Merge "Reset gSystemIcons when accessibility large icon settings has changed."
diff --git a/Android.mk b/Android.mk
index 137ef85..ad164e20 100644
--- a/Android.mk
+++ b/Android.mk
@@ -42,6 +42,7 @@
 
 # EventLogTags files.
 LOCAL_SRC_FILES += \
+       core/java/android/auditing/SecurityLogTags.logtags \
        core/java/android/content/EventLogTags.logtags \
        core/java/android/speech/tts/EventLogTags.logtags \
        core/java/android/webkit/EventLogTags.logtags \
@@ -96,6 +97,7 @@
 	core/java/android/app/trust/ITrustManager.aidl \
 	core/java/android/app/trust/ITrustListener.aidl \
 	core/java/android/app/backup/IBackupManager.aidl \
+	core/java/android/app/backup/IBackupObserver.aidl \
 	core/java/android/app/backup/IFullBackupRestoreObserver.aidl \
 	core/java/android/app/backup/IRestoreObserver.aidl \
 	core/java/android/app/backup/IRestoreSession.aidl \
@@ -185,6 +187,8 @@
 	core/java/android/hardware/location/IGeofenceHardware.aidl \
 	core/java/android/hardware/location/IGeofenceHardwareCallback.aidl \
 	core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl \
+	core/java/android/hardware/location/IContextHubCallback.aidl \
+	core/java/android/hardware/location/IContextHubService.aidl \
 	core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl \
 	core/java/android/hardware/usb/IUsbManager.aidl \
 	core/java/android/net/ICaptivePortal.aidl \
@@ -204,11 +208,13 @@
 	core/java/android/nfc/INfcAdapterExtras.aidl \
 	core/java/android/nfc/INfcTag.aidl \
 	core/java/android/nfc/INfcCardEmulation.aidl \
+	core/java/android/nfc/INfcFCardEmulation.aidl \
 	core/java/android/nfc/INfcUnlockHandler.aidl \
 	core/java/android/os/IBatteryPropertiesListener.aidl \
 	core/java/android/os/IBatteryPropertiesRegistrar.aidl \
 	core/java/android/os/ICancellationSignal.aidl \
 	core/java/android/os/IDeviceIdleController.aidl \
+	core/java/android/os/IMaintenanceActivityListener.aidl \
 	core/java/android/os/IMessenger.aidl \
 	core/java/android/os/INetworkActivityListener.aidl \
 	core/java/android/os/INetworkManagementService.aidl \
@@ -261,7 +267,7 @@
 	core/java/android/view/IApplicationToken.aidl \
 	core/java/android/view/IAppTransitionAnimationSpecsFuture.aidl \
 	core/java/android/view/IAssetAtlas.aidl \
-	core/java/android/view/IDockDividerVisibilityListener.aidl \
+	core/java/android/view/IDockedStackListener.aidl \
 	core/java/android/view/IGraphicsStats.aidl \
 	core/java/android/view/IInputFilter.aidl \
 	core/java/android/view/IInputFilterHost.aidl \
@@ -284,6 +290,7 @@
 	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 \
 	core/java/com/android/internal/app/IVoiceInteractor.aidl \
@@ -308,7 +315,7 @@
 	core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl \
 	core/java/com/android/internal/textservice/ITextServicesManager.aidl \
 	core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl \
-	core/java/com/android/internal/view/IDropPermissionHolder.aidl \
+	core/java/com/android/internal/view/IDropPermissions.aidl \
 	core/java/com/android/internal/view/IInputContext.aidl \
 	core/java/com/android/internal/view/IInputContextCallback.aidl \
 	core/java/com/android/internal/view/IInputMethod.aidl \
@@ -326,10 +333,10 @@
 	location/java/android/location/IFusedProvider.aidl \
 	location/java/android/location/IGeocodeProvider.aidl \
 	location/java/android/location/IGeofenceProvider.aidl \
+	location/java/android/location/IGnssStatusListener.aidl \
+	location/java/android/location/IGnssStatusProvider.aidl \
 	location/java/android/location/IGpsMeasurementsListener.aidl \
 	location/java/android/location/IGpsNavigationMessageListener.aidl \
-	location/java/android/location/IGpsStatusListener.aidl \
-	location/java/android/location/IGpsStatusProvider.aidl \
 	location/java/android/location/ILocationListener.aidl \
 	location/java/android/location/ILocationManager.aidl \
 	location/java/android/location/IFusedGeofenceHardware.aidl \
@@ -341,10 +348,12 @@
 	media/java/android/media/IAudioRoutesObserver.aidl \
 	media/java/android/media/IMediaHTTPConnection.aidl \
 	media/java/android/media/IMediaHTTPService.aidl \
+	media/java/android/media/IMediaResourceMonitor.aidl \
 	media/java/android/media/IMediaRouterClient.aidl \
 	media/java/android/media/IMediaRouterService.aidl \
 	media/java/android/media/IMediaScannerListener.aidl \
 	media/java/android/media/IMediaScannerService.aidl \
+	media/java/android/media/IRecordingConfigDispatcher.aidl \
 	media/java/android/media/IRemoteDisplayCallback.aidl \
 	media/java/android/media/IRemoteDisplayProvider.aidl \
 	media/java/android/media/IRemoteVolumeController.aidl \
@@ -378,6 +387,8 @@
 	media/java/android/media/tv/ITvInputSessionCallback.aidl \
 	media/java/android/service/media/IMediaBrowserService.aidl \
 	media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl \
+	telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl \
+	telecomm/java/com/android/internal/telecom/ICallScreeningService.aidl \
 	telecomm/java/com/android/internal/telecom/IVideoCallback.aidl \
 	telecomm/java/com/android/internal/telecom/IVideoProvider.aidl \
 	telecomm/java/com/android/internal/telecom/IConnectionService.aidl \
@@ -407,10 +418,14 @@
 	telephony/java/com/android/internal/telephony/ISms.aidl \
 	telephony/java/com/android/internal/telephony/ISub.aidl \
 	telephony/java/com/android/internal/telephony/ITelephony.aidl \
+	telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl \
+	telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl \
 	telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
 	telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
 	wifi/java/android/net/wifi/IWifiManager.aidl \
-	wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl \
+	wifi/java/android/net/wifi/nan/IWifiNanEventListener.aidl \
+	wifi/java/android/net/wifi/nan/IWifiNanManager.aidl \
+	wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl \
 	wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
 	wifi/java/android/net/wifi/IWifiScanner.aidl \
 	wifi/java/android/net/wifi/IRttManager.aidl \
@@ -420,8 +435,18 @@
 	core/java/android/service/quicksettings/IQSService.aidl \
 	core/java/android/service/quicksettings/IQSTileService.aidl \
 
+# The following are native binders that need to go with the native component
+# at system/update_engine/binder_bindings/. Use relative path to refer to them.
+LOCAL_SRC_FILES += \
+	../../system/update_engine/binder_bindings/android/os/IUpdateEngine.aidl \
+	../../system/update_engine/binder_bindings/android/os/IUpdateEngineCallback.aidl \
+
+LOCAL_AIDL_INCLUDES += system/update_engine/binder_bindings
+
 # FRAMEWORKS_BASE_JAVA_SRC_DIRS comes from build/core/pathmap.mk
-LOCAL_AIDL_INCLUDES += $(FRAMEWORKS_BASE_JAVA_SRC_DIRS)
+LOCAL_AIDL_INCLUDES += \
+      $(FRAMEWORKS_BASE_JAVA_SRC_DIRS) \
+      frameworks/native/aidl/binder
 
 LOCAL_INTERMEDIATE_SOURCES := \
 			$(framework_res_source_path)/android/R.java \
@@ -430,6 +455,7 @@
 
 LOCAL_NO_STANDARD_LIBRARIES := true
 LOCAL_JAVA_LIBRARIES := core-oj core-libart conscrypt okhttp core-junit bouncycastle ext
+LOCAL_STATIC_JAVA_LIBRARIES := framework-protos
 
 LOCAL_MODULE := framework
 
@@ -479,6 +505,11 @@
 	frameworks/base/media/java/android/media/tv/TvTrackInfo.aidl \
 	frameworks/base/media/java/android/media/browse/MediaBrowser.aidl \
 	frameworks/base/wifi/java/android/net/wifi/ScanSettings.aidl \
+	frameworks/base/wifi/java/android/net/wifi/nan/ConfigRequest.aidl \
+	frameworks/base/wifi/java/android/net/wifi/nan/PublishData.aidl \
+	frameworks/base/wifi/java/android/net/wifi/nan/SubscribeData.aidl \
+	frameworks/base/wifi/java/android/net/wifi/nan/PublishSettings.aidl \
+	frameworks/base/wifi/java/android/net/wifi/nan/SubscribeSettings.aidl \
 	frameworks/base/wifi/java/android/net/wifi/p2p/WifiP2pInfo.aidl \
 	frameworks/base/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.aidl \
 	frameworks/base/wifi/java/android/net/wifi/p2p/WifiP2pConfig.aidl \
@@ -498,6 +529,7 @@
 	frameworks/base/graphics/java/android/graphics/PointF.aidl \
 	frameworks/base/graphics/java/android/graphics/RectF.aidl \
 	frameworks/base/graphics/java/android/graphics/Rect.aidl \
+	frameworks/base/graphics/java/android/graphics/drawable/Icon.aidl \
 	frameworks/base/core/java/android/accounts/AuthenticatorDescription.aidl \
 	frameworks/base/core/java/android/accounts/Account.aidl \
 	frameworks/base/core/java/android/app/admin/SystemUpdatePolicy.aidl \
@@ -520,7 +552,6 @@
 	frameworks/base/core/java/android/os/ParcelUuid.aidl \
 	frameworks/base/core/java/android/os/ParcelFileDescriptor.aidl \
 	frameworks/base/core/java/android/os/ResultReceiver.aidl \
-	frameworks/base/core/java/android/os/PersistableBundle.aidl \
 	frameworks/base/core/java/android/os/WorkSource.aidl \
 	frameworks/base/core/java/android/os/DropBoxManager.aidl \
 	frameworks/base/core/java/android/os/Bundle.aidl \
@@ -628,6 +659,7 @@
 	frameworks/base/core/java/android/bluetooth/BluetoothDevice.aidl \
 	frameworks/base/core/java/android/database/CursorWindow.aidl \
 	frameworks/base/core/java/android/service/quicksettings/Tile.aidl \
+	frameworks/native/aidl/binder/android/os/PersistableBundle.aidl \
 
 gen := $(TARGET_OUT_COMMON_INTERMEDIATES)/framework.aidl
 $(gen): PRIVATE_SRC_FILES := $(aidl_files)
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 40908f1..2fe5cbe 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -238,6 +238,8 @@
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/DocumentsUI_intermediates)
 $(call add-clean-step, rm -f $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/media/java/android/media/IRemoteControlClient.*)
 $(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)
 
 # ******************************************************************
 # 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 b73214f..cabaad4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -33,6 +33,7 @@
     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";
+    field public static final java.lang.String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
     field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
     field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
     field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
@@ -67,8 +68,7 @@
     field public static final java.lang.String DUMP = "android.permission.DUMP";
     field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
     field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
-    field public static final java.lang.String FLASHLIGHT = "android.permission.FLASHLIGHT";
-    field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
+    field public static final deprecated 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 deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
@@ -335,6 +335,7 @@
     field public static final int calendarViewShown = 16843596; // 0x101034c
     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 canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
     field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9
     field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
@@ -505,6 +506,8 @@
     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
+    field public static final int endY = 16844052; // 0x1010514
     field public static final deprecated int endYear = 16843133; // 0x101017d
     field public static final int enterFadeDuration = 16843532; // 0x101030c
     field public static final int entries = 16842930; // 0x10100b2
@@ -524,6 +527,7 @@
     field public static final int expandableListViewStyle = 16842863; // 0x101006f
     field public static final int expandableListViewWhiteStyle = 16843446; // 0x10102b6
     field public static final int exported = 16842768; // 0x1010010
+    field public static final int externalService = 16844047; // 0x101050f
     field public static final int extraTension = 16843371; // 0x101026b
     field public static final int extractNativeLibs = 16844010; // 0x10104ea
     field public static final int factor = 16843219; // 0x10101d3
@@ -879,6 +883,7 @@
     field public static final int numbersTextColor = 16843937; // 0x10104a1
     field public static final deprecated int numeric = 16843109; // 0x1010165
     field public static final int numericShortcut = 16843236; // 0x10101e4
+    field public static final int offset = 16844053; // 0x1010515
     field public static final int onClick = 16843375; // 0x101026f
     field public static final int oneshot = 16843159; // 0x1010197
     field public static final int opacity = 16843550; // 0x101031e
@@ -1126,6 +1131,8 @@
     field public static final int startColor = 16843165; // 0x101019d
     field public static final int startDelay = 16843746; // 0x10103e2
     field public static final int startOffset = 16843198; // 0x10101be
+    field public static final int startX = 16844049; // 0x1010511
+    field public static final int startY = 16844050; // 0x1010512
     field public static final deprecated int startYear = 16843132; // 0x101017c
     field public static final int stateListAnimator = 16843848; // 0x1010448
     field public static final int stateNotNeeded = 16842774; // 0x1010016
@@ -1182,6 +1189,7 @@
     field public static final int summaryOn = 16843247; // 0x10101ef
     field public static final int supportsAssist = 16844016; // 0x10104f0
     field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
+    field public static final int supportsLocalInteraction = 16844048; // 0x1010510
     field public static final int supportsPictureInPicture = 16844024; // 0x10104f8
     field public static final int supportsRtl = 16843695; // 0x10103af
     field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
@@ -1289,6 +1297,9 @@
     field public static final int thumbTint = 16843889; // 0x1010471
     field public static final int thumbTintMode = 16843890; // 0x1010472
     field public static final int thumbnail = 16843429; // 0x10102a5
+    field public static final int tickMark = 16844043; // 0x101050b
+    field public static final int tickMarkTint = 16844044; // 0x101050c
+    field public static final int tickMarkTintMode = 16844045; // 0x101050d
     field public static final int tileMode = 16843265; // 0x1010201
     field public static final int tileModeX = 16843895; // 0x1010477
     field public static final int tileModeY = 16843896; // 0x1010478
@@ -2114,22 +2125,6 @@
     field public static final int Theme_Light_Panel = 16973914; // 0x103005a
     field public static final int Theme_Light_WallpaperSettings = 16973922; // 0x1030062
     field public static final int Theme_Material = 16974372; // 0x1030224
-    field public static final int Theme_Material_DayNight = 16974552; // 0x10302d8
-    field public static final int Theme_Material_DayNight_DarkActionBar = 16974553; // 0x10302d9
-    field public static final int Theme_Material_DayNight_Dialog = 16974554; // 0x10302da
-    field public static final int Theme_Material_DayNight_DialogWhenLarge = 16974560; // 0x10302e0
-    field public static final int Theme_Material_DayNight_DialogWhenLarge_DarkActionBar = 16974568; // 0x10302e8
-    field public static final int Theme_Material_DayNight_DialogWhenLarge_NoActionBar = 16974561; // 0x10302e1
-    field public static final int Theme_Material_DayNight_Dialog_Alert = 16974555; // 0x10302db
-    field public static final int Theme_Material_DayNight_Dialog_MinWidth = 16974556; // 0x10302dc
-    field public static final int Theme_Material_DayNight_Dialog_NoActionBar = 16974557; // 0x10302dd
-    field public static final int Theme_Material_DayNight_Dialog_NoActionBar_MinWidth = 16974558; // 0x10302de
-    field public static final int Theme_Material_DayNight_Dialog_Presentation = 16974559; // 0x10302df
-    field public static final int Theme_Material_DayNight_NoActionBar = 16974562; // 0x10302e2
-    field public static final int Theme_Material_DayNight_NoActionBar_Fullscreen = 16974563; // 0x10302e3
-    field public static final int Theme_Material_DayNight_NoActionBar_Overscan = 16974564; // 0x10302e4
-    field public static final int Theme_Material_DayNight_NoActionBar_TranslucentDecor = 16974565; // 0x10302e5
-    field public static final int Theme_Material_DayNight_Panel = 16974566; // 0x10302e6
     field public static final int Theme_Material_Dialog = 16974373; // 0x1030225
     field public static final int Theme_Material_DialogWhenLarge = 16974379; // 0x103022b
     field public static final int Theme_Material_DialogWhenLarge_NoActionBar = 16974380; // 0x103022c
@@ -2143,7 +2138,7 @@
     field public static final int Theme_Material_Light_DarkActionBar = 16974392; // 0x1030238
     field public static final int Theme_Material_Light_Dialog = 16974393; // 0x1030239
     field public static final int Theme_Material_Light_DialogWhenLarge = 16974399; // 0x103023f
-    field public static final int Theme_Material_Light_DialogWhenLarge_DarkActionBar = 16974567; // 0x10302e7
+    field public static final int Theme_Material_Light_DialogWhenLarge_DarkActionBar = 16974552; // 0x10302d8
     field public static final int Theme_Material_Light_DialogWhenLarge_NoActionBar = 16974400; // 0x1030240
     field public static final int Theme_Material_Light_Dialog_Alert = 16974394; // 0x103023a
     field public static final int Theme_Material_Light_Dialog_MinWidth = 16974395; // 0x103023b
@@ -2564,6 +2559,7 @@
     field public static final int Widget_Material_ScrollView = 16974462; // 0x103027e
     field public static final int Widget_Material_SearchView = 16974463; // 0x103027f
     field public static final int Widget_Material_SeekBar = 16974464; // 0x1030280
+    field public static final int Widget_Material_SeekBar_Discrete = 16974553; // 0x10302d9
     field public static final int Widget_Material_SegmentedButton = 16974465; // 0x1030281
     field public static final int Widget_Material_Spinner = 16974467; // 0x1030283
     field public static final int Widget_Material_Spinner_Underlined = 16974468; // 0x1030284
@@ -2623,6 +2619,8 @@
 
   public abstract class AccessibilityService extends android.app.Service {
     ctor public AccessibilityService();
+    method public final void disableSelf();
+    method public final boolean dispatchGesture(android.accessibilityservice.GestureDescription, android.accessibilityservice.AccessibilityService.GestureResultCallback, android.os.Handler);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
     method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
@@ -2662,6 +2660,12 @@
     field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice";
   }
 
+  public static abstract class AccessibilityService.GestureResultCallback {
+    ctor public AccessibilityService.GestureResultCallback();
+    method public void onCancelled(android.accessibilityservice.GestureDescription);
+    method public void onCompleted(android.accessibilityservice.GestureDescription);
+  }
+
   public static final class AccessibilityService.MagnificationController {
     method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener);
     method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener, android.os.Handler);
@@ -2694,6 +2698,7 @@
     method public java.lang.String loadDescription(android.content.pm.PackageManager);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10
+    field public static final int CAPABILITY_CAN_PERFORM_GESTURES = 32; // 0x20
     field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
     field public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 8; // 0x8
     field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
@@ -2720,6 +2725,30 @@
     field public java.lang.String[] packageNames;
   }
 
+  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 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 {
+    ctor public GestureDescription.Builder();
+    method public android.accessibilityservice.GestureDescription.Builder addStroke(android.accessibilityservice.GestureDescription.StrokeDescription);
+    method public android.accessibilityservice.GestureDescription build();
+  }
+
+  public static class GestureDescription.StrokeDescription {
+    ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long);
+    method public long getDuration();
+    method public android.graphics.Path getPath();
+    method public long getStartTime();
+  }
+
 }
 
 package android.accounts {
@@ -2730,15 +2759,12 @@
     method public android.os.Bundle addAccountFromCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle confirmCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle editProperties(android.accounts.AccountAuthenticatorResponse, java.lang.String);
-    method public android.os.Bundle finishSession(android.accounts.AccountAuthenticatorResponse, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public android.os.Bundle getAccountCredentialsForCloning(android.accounts.AccountAuthenticatorResponse, android.accounts.Account) throws android.accounts.NetworkErrorException;
     method public android.os.Bundle getAccountRemovalAllowed(android.accounts.AccountAuthenticatorResponse, android.accounts.Account) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle getAuthToken(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract java.lang.String getAuthTokenLabel(java.lang.String);
     method public final android.os.IBinder getIBinder();
     method public abstract android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;
-    method public android.os.Bundle startAddAccountSession(android.accounts.AccountAuthenticatorResponse, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle) throws android.accounts.NetworkErrorException;
-    method public android.os.Bundle startUpdateCredentialsSession(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
     field public static final java.lang.String KEY_CUSTOM_TOKEN_EXPIRY = "android.accounts.expiry";
   }
@@ -2776,7 +2802,6 @@
     method public void clearPassword(android.accounts.Account);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> confirmCredentials(android.accounts.Account, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> editProperties(java.lang.String, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
-    method public android.accounts.AccountManagerFuture<android.os.Bundle> finishSession(android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public static android.accounts.AccountManager get(android.content.Context);
     method public android.accounts.Account[] getAccounts();
     method public android.accounts.Account[] getAccountsByType(java.lang.String);
@@ -2804,8 +2829,6 @@
     method public void setAuthToken(android.accounts.Account, java.lang.String, java.lang.String);
     method public void setPassword(android.accounts.Account, java.lang.String);
     method public void setUserData(android.accounts.Account, java.lang.String, java.lang.String);
-    method public android.accounts.AccountManagerFuture<android.os.Bundle> startAddAccountSession(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
-    method public android.accounts.AccountManagerFuture<android.os.Bundle> startUpdateCredentialsSession(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> updateCredentials(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     field public static final java.lang.String ACTION_AUTHENTICATOR_INTENT = "android.accounts.AccountAuthenticator";
     field public static final java.lang.String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
@@ -2822,8 +2845,6 @@
     field public static final java.lang.String KEY_ACCOUNT_AUTHENTICATOR_RESPONSE = "accountAuthenticatorResponse";
     field public static final java.lang.String KEY_ACCOUNT_MANAGER_RESPONSE = "accountManagerResponse";
     field public static final java.lang.String KEY_ACCOUNT_NAME = "authAccount";
-    field public static final java.lang.String KEY_ACCOUNT_SESSION_BUNDLE = "accountSessionBundle";
-    field public static final java.lang.String KEY_ACCOUNT_STATUS_TOKEN = "accountStatusToken";
     field public static final java.lang.String KEY_ACCOUNT_TYPE = "accountType";
     field public static final java.lang.String KEY_ANDROID_PACKAGE_NAME = "androidPackageName";
     field public static final java.lang.String KEY_AUTHENTICATOR_TYPES = "authenticator_types";
@@ -3374,6 +3395,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 enterPictureInPictureMode();
     method public android.view.View findViewById(int);
     method public void finish();
     method public void finishActivity(int);
@@ -3421,6 +3443,7 @@
     method public boolean isDestroyed();
     method public boolean isFinishing();
     method public boolean isImmersive();
+    method public boolean isLocalVoiceInteractionSupported();
     method public boolean isTaskRoot();
     method public boolean isVoiceInteraction();
     method public boolean isVoiceInteractionRoot();
@@ -3462,6 +3485,8 @@
     method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
     method public boolean onKeyShortcut(int, android.view.KeyEvent);
     method public boolean onKeyUp(int, android.view.KeyEvent);
+    method public void onLocalVoiceInteractionStarted();
+    method public void onLocalVoiceInteractionStopped();
     method public void onLowMemory();
     method public boolean onMenuItemSelected(int, android.view.MenuItem);
     method public boolean onMenuOpened(int, android.view.Menu);
@@ -3484,6 +3509,7 @@
     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();
@@ -3519,6 +3545,7 @@
     method public boolean releaseInstance();
     method public final deprecated void removeDialog(int);
     method public void reportFullyDrawn();
+    method public android.view.DropPermissions requestDropPermissions(android.view.DragEvent);
     method public final void requestPermissions(java.lang.String[], int);
     method public boolean requestVisibleBehind(boolean);
     method public final boolean requestWindowFeature(int);
@@ -3553,6 +3580,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 boolean shouldShowRequestPermissionRationale(java.lang.String);
     method public boolean shouldUpRecreateTask(android.content.Intent);
     method public boolean showAssist(android.os.Bundle);
@@ -3573,12 +3601,14 @@
     method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
     method public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
     method public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+    method public void startLocalVoiceInteraction(android.os.Bundle);
     method public void startLockTask();
     method public deprecated void startManagingCursor(android.database.Cursor);
     method public boolean startNextMatchingActivity(android.content.Intent);
     method public boolean startNextMatchingActivity(android.content.Intent, android.os.Bundle);
     method public void startPostponedEnterTransition();
     method public void startSearch(java.lang.String, boolean, android.os.Bundle, boolean);
+    method public void stopLocalVoiceInteraction();
     method public void stopLockTask();
     method public deprecated void stopManagingCursor(android.database.Cursor);
     method public void takeKeyEvents(boolean);
@@ -4095,11 +4125,14 @@
   }
 
   public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
+    ctor public DatePickerDialog(android.content.Context);
+    ctor public DatePickerDialog(android.content.Context, int);
     ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
     ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
     method public android.widget.DatePicker getDatePicker();
     method public void onClick(android.content.DialogInterface, int);
     method public void onDateChanged(android.widget.DatePicker, int, int, int);
+    method public void setOnDateSetListener(android.app.DatePickerDialog.OnDateSetListener);
     method public void updateDate(int, int, int);
   }
 
@@ -4160,6 +4193,7 @@
     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);
@@ -4239,7 +4273,7 @@
     field public static final java.lang.String COLUMN_DESCRIPTION = "description";
     field public static final java.lang.String COLUMN_ID = "_id";
     field public static final java.lang.String COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp";
-    field public static final java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
+    field public static final deprecated java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
     field public static final java.lang.String COLUMN_LOCAL_URI = "local_uri";
     field public static final java.lang.String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri";
     field public static final java.lang.String COLUMN_MEDIA_TYPE = "media_type";
@@ -4851,6 +4885,7 @@
     field public static final java.lang.String EXTRA_PROGRESS = "android.progress";
     field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
     field public static final java.lang.String EXTRA_PROGRESS_MAX = "android.progressMax";
+    field public static final java.lang.String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
     field public static final java.lang.String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
     field public static final java.lang.String EXTRA_SHOW_WHEN = "android.showWhen";
     field public static final java.lang.String EXTRA_SMALL_ICON = "android.icon";
@@ -5017,6 +5052,7 @@
     method public android.app.Notification.Builder setPriority(int);
     method public android.app.Notification.Builder setProgress(int, int, boolean);
     method public android.app.Notification.Builder setPublicVersion(android.app.Notification);
+    method public android.app.Notification.Builder setRemoteInputHistory(java.lang.CharSequence[]);
     method public android.app.Notification.Builder setShowWhen(boolean);
     method public android.app.Notification.Builder setSmallIcon(int);
     method public android.app.Notification.Builder setSmallIcon(int, int);
@@ -5206,6 +5242,7 @@
     field public static final int SUPPRESSED_EFFECTS_UNSET = -1; // 0xffffffff
     field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
     field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+    field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
     field public final int priorityCallSenders;
     field public final int priorityCategories;
     field public final int priorityMessageSenders;
@@ -5658,10 +5695,13 @@
     method public android.graphics.drawable.Drawable peekFastDrawable();
     method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle);
     method public void setBitmap(android.graphics.Bitmap) throws java.io.IOException;
-    method public void setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean, int) throws java.io.IOException;
     method public void setResource(int) throws java.io.IOException;
+    method public int setResource(int, int) throws java.io.IOException;
     method public void setStream(java.io.InputStream) throws java.io.IOException;
-    method public void setStream(java.io.InputStream, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setStream(java.io.InputStream, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setStream(java.io.InputStream, android.graphics.Rect, boolean, int) throws java.io.IOException;
     method public void setWallpaperOffsetSteps(float, float);
     method public void setWallpaperOffsets(android.os.IBinder, float, float);
     method public void suggestDesiredDimensions(int, int);
@@ -5672,6 +5712,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 java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
   }
 
@@ -5710,6 +5752,9 @@
     ctor public DeviceAdminReceiver();
     method public android.app.admin.DevicePolicyManager getManager(android.content.Context);
     method public android.content.ComponentName getWho(android.content.Context);
+    method public void onBugreportFailed(android.content.Context, android.content.Intent, int);
+    method public void onBugreportShared(android.content.Context, android.content.Intent, java.lang.String);
+    method public void onBugreportSharingDeclined(android.content.Context, android.content.Intent);
     method public java.lang.String onChoosePrivateKeyAlias(android.content.Context, android.content.Intent, int, android.net.Uri, java.lang.String);
     method public java.lang.CharSequence onDisableRequested(android.content.Context, android.content.Intent);
     method public void onDisabled(android.content.Context, android.content.Intent);
@@ -5734,6 +5779,8 @@
     field public static final java.lang.String ACTION_PASSWORD_FAILED = "android.app.action.ACTION_PASSWORD_FAILED";
     field public static final java.lang.String ACTION_PASSWORD_SUCCEEDED = "android.app.action.ACTION_PASSWORD_SUCCEEDED";
     field public static final java.lang.String ACTION_PROFILE_PROVISIONING_COMPLETE = "android.app.action.PROFILE_PROVISIONING_COMPLETE";
+    field public static final int BUGREPORT_FAILURE_FAILED_COMPLETING = 0; // 0x0
+    field public static final int BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE = 1; // 0x1
     field public static final java.lang.String DEVICE_ADMIN_META_DATA = "android.app.device_admin";
     field public static final java.lang.String EXTRA_DISABLE_WARNING = "android.app.extra.DISABLE_WARNING";
     field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
@@ -5747,27 +5794,35 @@
     method public void clearCrossProfileIntentFilters(android.content.ComponentName);
     method public void clearDeviceOwnerApp(java.lang.String);
     method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
+    method public void clearProfileOwner(android.content.ComponentName);
     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();
     method public java.util.List<android.content.ComponentName> getActiveAdmins();
+    method public java.lang.String getAlwaysOnVpnPackage(android.content.ComponentName);
     method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
+    method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName);
     method public boolean getAutoTimeRequired();
     method public boolean getBluetoothContactSharingDisabled(android.content.ComponentName);
     method public boolean getCameraDisabled(android.content.ComponentName);
     method public java.lang.String getCertInstallerPackage(android.content.ComponentName) throws java.lang.SecurityException;
     method public boolean getCrossProfileCallerIdDisabled(android.content.ComponentName);
+    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 java.lang.String 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);
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
+    method public int getOrganizationColor(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);
     method public int getPasswordHistoryLength(android.content.ComponentName);
@@ -5785,6 +5840,7 @@
     method public java.util.List<java.lang.String> getPermittedAccessibilityServices(android.content.ComponentName);
     method public java.util.List<java.lang.String> getPermittedInputMethods(android.content.ComponentName);
     method public boolean getScreenCaptureDisabled(android.content.ComponentName);
+    method public java.lang.String getShortSupportMessage(android.content.ComponentName);
     method public boolean getStorageEncryption(android.content.ComponentName);
     method public int getStorageEncryptionStatus();
     method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
@@ -5798,6 +5854,7 @@
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
     method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
+    method public boolean isCallerApplicationRestrictionsManagingPackage();
     method public boolean isDeviceOwnerApp(java.lang.String);
     method public boolean isLockTaskPermitted(java.lang.String);
     method public boolean isMasterVolumeMuted(android.content.ComponentName);
@@ -5805,27 +5862,34 @@
     method public boolean isProvisioningAllowed(java.lang.String);
     method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String);
     method public void lockNow();
+    method public void reboot(android.content.ComponentName);
     method public void removeActiveAdmin(android.content.ComponentName);
     method public boolean removeCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
     method public boolean removeKeyPair(android.content.ComponentName, java.lang.String);
     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 void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
+    method public boolean setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String);
     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 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 boolean setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.String);
     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);
     method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
+    method public void setLongSupportMessage(android.content.ComponentName, java.lang.String);
     method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
+    method public void setOrganizationColor(android.content.ComponentName, int);
     method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
     method public void setPasswordHistoryLength(android.content.ComponentName, int);
@@ -5847,6 +5911,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 setShortSupportMessage(android.content.ComponentName, java.lang.String);
     method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
     method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
@@ -5862,6 +5927,7 @@
     field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
     field public static final java.lang.String ACTION_PROVISION_MANAGED_DEVICE = "android.app.action.PROVISION_MANAGED_DEVICE";
     field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
+    field public static final java.lang.String ACTION_SET_NEW_PARENT_PROFILE_PASSWORD = "android.app.action.SET_NEW_PARENT_PROFILE_PASSWORD";
     field public static final java.lang.String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
     field public static final java.lang.String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
     field public static final java.lang.String ACTION_SYSTEM_UPDATE_POLICY_CHANGED = "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED";
@@ -5924,6 +5990,7 @@
     field public static final int PERMISSION_POLICY_PROMPT = 0; // 0x0
     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 WIPE_EXTERNAL_STORAGE = 1; // 0x1
     field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
   }
@@ -6045,6 +6112,7 @@
     method public void onCreate();
     method public void onDestroy();
     method public void onFullBackup(android.app.backup.FullBackupDataOutput) throws java.io.IOException;
+    method public void onQuotaExceeded(long, long);
     method public abstract void onRestore(android.app.backup.BackupDataInput, int, android.os.ParcelFileDescriptor) throws java.io.IOException;
     method public void onRestoreFile(android.os.ParcelFileDescriptor, long, java.io.File, int, long, long) throws java.io.IOException;
     method public void onRestoreFinished();
@@ -6125,6 +6193,7 @@
     method public int describeContents();
     method public int getBackoffPolicy();
     method public android.os.PersistableBundle getExtras();
+    method public long getFlexMillis();
     method public int getId();
     method public long getInitialBackoffMillis();
     method public long getIntervalMillis();
@@ -6132,6 +6201,7 @@
     method public long getMinLatencyMillis();
     method public int getNetworkType();
     method public android.content.ComponentName getService();
+    method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
     method public boolean isPeriodic();
     method public boolean isPersisted();
     method public boolean isRequireCharging();
@@ -6142,6 +6212,8 @@
     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
@@ -6149,22 +6221,36 @@
 
   public static final class JobInfo.Builder {
     ctor public JobInfo.Builder(int, android.content.ComponentName);
+    method public android.app.job.JobInfo.Builder addTriggerContentUri(android.app.job.JobInfo.TriggerContentUri);
     method public android.app.job.JobInfo build();
     method public android.app.job.JobInfo.Builder setBackoffCriteria(long, int);
     method public android.app.job.JobInfo.Builder setExtras(android.os.PersistableBundle);
     method public android.app.job.JobInfo.Builder setMinimumLatency(long);
     method public android.app.job.JobInfo.Builder setOverrideDeadline(long);
     method public android.app.job.JobInfo.Builder setPeriodic(long);
+    method public android.app.job.JobInfo.Builder setPeriodic(long, long);
     method public android.app.job.JobInfo.Builder setPersisted(boolean);
     method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
     method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
     method public android.app.job.JobInfo.Builder setRequiresDeviceIdle(boolean);
   }
 
+  public static final class JobInfo.TriggerContentUri implements android.os.Parcelable {
+    ctor public JobInfo.TriggerContentUri(android.net.Uri, int);
+    method public int describeContents();
+    method public int getFlags();
+    method public android.net.Uri getUri();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.job.JobInfo.TriggerContentUri> CREATOR;
+    field public static final int FLAG_NOTIFY_FOR_DESCENDANTS = 1; // 0x1
+  }
+
   public class JobParameters implements android.os.Parcelable {
     method public int describeContents();
     method public android.os.PersistableBundle getExtras();
     method public int getJobId();
+    method public java.lang.String[] getTriggeredContentAuthorities();
+    method public android.net.Uri[] getTriggeredContentUris();
     method public boolean isOverrideDeadlineExpired();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.job.JobParameters> CREATOR;
@@ -6215,6 +6301,8 @@
   public static class NetworkStats.Bucket {
     ctor public NetworkStats.Bucket();
     method public long getEndTimeStamp();
+    method public int getMetering();
+    method public int getRoaming();
     method public long getRxBytes();
     method public long getRxPackets();
     method public long getStartTimeStamp();
@@ -6222,6 +6310,12 @@
     method public long getTxBytes();
     method public long getTxPackets();
     method public int getUid();
+    field public static final int METERING_ALL = -1; // 0xffffffff
+    field public static final int METERING_DEFAULT = 1; // 0x1
+    field public static final int METERING_METERED = 2; // 0x2
+    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 STATE_ALL = -1; // 0xffffffff
     field public static final int STATE_DEFAULT = 1; // 0x1
     field public static final int STATE_FOREGROUND = 2; // 0x2
@@ -6415,6 +6509,31 @@
 
 }
 
+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 {
@@ -7148,6 +7267,15 @@
     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 {
@@ -7572,11 +7700,12 @@
     method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
   }
 
-  public class ContentProviderClient {
+  public class ContentProviderClient implements java.lang.AutoCloseable {
     method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
     method public int bulkInsert(android.net.Uri, android.content.ContentValues[]) throws android.os.RemoteException;
     method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException;
     method public final android.net.Uri canonicalize(android.net.Uri) throws android.os.RemoteException;
+    method public void close();
     method public int delete(android.net.Uri, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
     method public android.content.ContentProvider getLocalContentProvider();
     method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String) throws android.os.RemoteException;
@@ -7590,7 +7719,7 @@
     method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
     method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) throws android.os.RemoteException;
     method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal) throws android.os.RemoteException;
-    method public boolean release();
+    method public deprecated boolean release();
     method public final android.net.Uri uncanonicalize(android.net.Uri) throws android.os.RemoteException;
     method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
   }
@@ -7916,6 +8045,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 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";
@@ -8269,7 +8399,6 @@
     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";
     field public static final java.lang.String ACTION_ATTACH_DATA = "android.intent.action.ATTACH_DATA";
-    field public static final java.lang.String ACTION_AVAILABILITY_CHANGED = "android.intent.action.AVAILABILITY_CHANGED";
     field public static final java.lang.String ACTION_BATTERY_CHANGED = "android.intent.action.BATTERY_CHANGED";
     field public static final java.lang.String ACTION_BATTERY_LOW = "android.intent.action.BATTERY_LOW";
     field public static final java.lang.String ACTION_BATTERY_OKAY = "android.intent.action.BATTERY_OKAY";
@@ -8330,6 +8459,9 @@
     field public static final java.lang.String ACTION_NEW_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL";
     field public static final java.lang.String ACTION_OPEN_DOCUMENT = "android.intent.action.OPEN_DOCUMENT";
     field public static final java.lang.String ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE";
+    field public static final java.lang.String ACTION_OPEN_EXTERNAL_DIRECTORY = "android.intent.action.OPEN_EXTERNAL_DIRECTORY";
+    field public static final java.lang.String ACTION_PACKAGES_SUSPENDED = "android.intent.action.PACKAGES_SUSPENDED";
+    field public static final java.lang.String ACTION_PACKAGES_UNSUSPENDED = "android.intent.action.PACKAGES_UNSUSPENDED";
     field public static final java.lang.String ACTION_PACKAGE_ADDED = "android.intent.action.PACKAGE_ADDED";
     field public static final java.lang.String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
     field public static final java.lang.String ACTION_PACKAGE_DATA_CLEARED = "android.intent.action.PACKAGE_DATA_CLEARED";
@@ -8350,6 +8482,7 @@
     field public static final java.lang.String ACTION_PROCESS_TEXT = "android.intent.action.PROCESS_TEXT";
     field public static final java.lang.String ACTION_PROVIDER_CHANGED = "android.intent.action.PROVIDER_CHANGED";
     field public static final java.lang.String ACTION_QUICK_CLOCK = "android.intent.action.QUICK_CLOCK";
+    field public static final java.lang.String ACTION_QUICK_VIEW = "android.intent.action.QUICK_VIEW";
     field public static final java.lang.String ACTION_REBOOT = "android.intent.action.REBOOT";
     field public static final java.lang.String ACTION_RUN = "android.intent.action.RUN";
     field public static final java.lang.String ACTION_SCREEN_OFF = "android.intent.action.SCREEN_OFF";
@@ -8443,6 +8576,7 @@
     field public static final java.lang.String EXTRA_DONT_KILL_APP = "android.intent.extra.DONT_KILL_APP";
     field public static final java.lang.String EXTRA_EMAIL = "android.intent.extra.EMAIL";
     field public static final java.lang.String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
+    field public static final java.lang.String EXTRA_INDEX = "android.intent.extra.INDEX";
     field public static final java.lang.String EXTRA_INITIAL_INTENTS = "android.intent.extra.INITIAL_INTENTS";
     field public static final java.lang.String EXTRA_INSTALLER_PACKAGE_NAME = "android.intent.extra.INSTALLER_PACKAGE_NAME";
     field public static final java.lang.String EXTRA_INTENT = "android.intent.extra.INTENT";
@@ -9004,6 +9138,7 @@
     field public static final int FLAG_ALWAYS_RETAIN_TASK_STATE = 8; // 0x8
     field public static final int FLAG_AUTO_REMOVE_FROM_RECENTS = 8192; // 0x2000
     field public static final int FLAG_CLEAR_TASK_ON_LAUNCH = 4; // 0x4
+    field public static final int FLAG_ENABLE_VR_MODE = 32768; // 0x8000
     field public static final int FLAG_EXCLUDE_FROM_RECENTS = 32; // 0x20
     field public static final int FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS = 256; // 0x100
     field public static final int FLAG_FINISH_ON_TASK_LAUNCH = 2; // 0x2
@@ -9235,6 +9370,7 @@
 
   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 boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
     method public boolean isPackageEnabled(java.lang.String, android.os.UserHandle);
     method public void registerCallback(android.content.pm.LauncherApps.Callback);
@@ -9251,7 +9387,9 @@
     method public abstract void onPackageChanged(java.lang.String, android.os.UserHandle);
     method public abstract void onPackageRemoved(java.lang.String, android.os.UserHandle);
     method public abstract void onPackagesAvailable(java.lang.String[], android.os.UserHandle, boolean);
+    method public 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);
   }
 
   public class PackageInfo implements android.os.Parcelable {
@@ -9433,8 +9571,6 @@
     method public abstract int getComponentEnabledSetting(android.content.ComponentName);
     method public abstract android.graphics.drawable.Drawable getDefaultActivityIcon();
     method public abstract android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
-    method public abstract byte[] getEphemeralCookie();
-    method public abstract int getEphemeralCookieMaxSizeBytes();
     method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
     method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
     method public abstract java.lang.String getInstallerPackageName(java.lang.String);
@@ -9444,8 +9580,10 @@
     method public abstract java.lang.String getNameForUid(int);
     method public android.content.pm.PackageInfo getPackageArchiveInfo(java.lang.String, int);
     method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.PackageInstaller getPackageInstaller();
+    method public abstract int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.lang.String[] getPackagesForUid(int);
     method public abstract java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int);
     method public abstract android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -9466,7 +9604,6 @@
     method public abstract java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle);
     method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
     method public abstract boolean hasSystemFeature(java.lang.String);
-    method public abstract boolean isEphemeralApplication();
     method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
     method public abstract boolean isSafeMode();
     method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
@@ -9484,7 +9621,6 @@
     method public abstract android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
     method public abstract void setApplicationEnabledSetting(java.lang.String, int, int);
     method public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int);
-    method public abstract boolean setEphemeralCookie(byte[]);
     method public abstract void setInstallerPackageName(java.lang.String, java.lang.String);
     method public abstract void verifyPendingInstall(int, int);
     field public static final int COMPONENT_ENABLED_STATE_DEFAULT = 0; // 0x0
@@ -9516,6 +9652,7 @@
     field public static final java.lang.String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
     field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
     field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
+    field public static final java.lang.String FEATURE_ETHERNET = "android.hardware.ethernet";
     field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch";
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
@@ -9536,6 +9673,7 @@
     field public static final java.lang.String FEATURE_MIDI = "android.software.midi";
     field public static final java.lang.String FEATURE_NFC = "android.hardware.nfc";
     field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION = "android.hardware.nfc.hce";
+    field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION_NFCF = "android.hardware.nfc.hcef";
     field public static final java.lang.String FEATURE_OPENGLES_EXTENSION_PACK = "android.hardware.opengles.aep";
     field public static final java.lang.String FEATURE_PICTURE_IN_PICTURE = "android.software.picture_in_picture";
     field public static final java.lang.String FEATURE_PRINTING = "android.software.print";
@@ -9567,15 +9705,15 @@
     field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
     field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host";
     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_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";
     field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
     field public static final int GET_ACTIVITIES = 1; // 0x1
     field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
-    field public static final int GET_DISABLED_COMPONENTS = 512; // 0x200
-    field public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
-    field public static final int GET_ENCRYPTION_UNAWARE_COMPONENTS = 262144; // 0x40000
+    field public static final deprecated int GET_DISABLED_COMPONENTS = 512; // 0x200
+    field public static final deprecated int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
     field public static final int GET_GIDS = 256; // 0x100
     field public static final int GET_INSTRUMENTATION = 16; // 0x10
     field public static final int GET_INTENT_FILTERS = 32; // 0x20
@@ -9587,10 +9725,17 @@
     field public static final int GET_SERVICES = 4; // 0x4
     field public static final int GET_SHARED_LIBRARY_FILES = 1024; // 0x400
     field public static final int GET_SIGNATURES = 64; // 0x40
-    field public static final int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
+    field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
     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_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
     field public static final int PERMISSION_DENIED = -1; // 0xffffffff
     field public static final int PERMISSION_GRANTED = 0; // 0x0
@@ -9810,7 +9955,7 @@
     method public final long skip(long) throws java.io.IOException;
   }
 
-  public class ColorStateList implements android.os.Parcelable {
+  public class ColorStateList extends android.content.res.ComplexColor 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;
@@ -9819,13 +9964,18 @@
     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);
@@ -9929,6 +10079,11 @@
     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);
@@ -9973,7 +10128,6 @@
     method public java.lang.String getQuantityString(int, int, java.lang.Object...) throws android.content.res.Resources.NotFoundException;
     method public java.lang.String getQuantityString(int, int) throws android.content.res.Resources.NotFoundException;
     method public java.lang.CharSequence getQuantityText(int, int) throws android.content.res.Resources.NotFoundException;
-    method public java.util.Locale getResolvedLocale();
     method public java.lang.String getResourceEntryName(int) throws android.content.res.Resources.NotFoundException;
     method public java.lang.String getResourceName(int) throws android.content.res.Resources.NotFoundException;
     method public java.lang.String getResourcePackageName(int) throws android.content.res.Resources.NotFoundException;
@@ -9989,6 +10143,7 @@
     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;
@@ -10024,6 +10179,7 @@
     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);
@@ -10605,6 +10761,7 @@
     method public void setVersion(int);
     method public int update(java.lang.String, android.content.ContentValues, java.lang.String, java.lang.String[]);
     method public int updateWithOnConflict(java.lang.String, android.content.ContentValues, java.lang.String, java.lang.String[], int);
+    method public void validateSql(java.lang.String, android.os.CancellationSignal);
     method public deprecated boolean yieldIfContended();
     method public boolean yieldIfContendedSafely();
     method public boolean yieldIfContendedSafely(long);
@@ -10839,7 +10996,7 @@
     field public final int statusCode;
   }
 
-  public class DrmManagerClient {
+  public class DrmManagerClient implements java.lang.AutoCloseable {
     ctor public DrmManagerClient(android.content.Context);
     method public android.drm.DrmInfo acquireDrmInfo(android.drm.DrmInfoRequest);
     method public int acquireRights(android.drm.DrmInfoRequest);
@@ -10849,6 +11006,7 @@
     method public int checkRightsStatus(android.net.Uri);
     method public int checkRightsStatus(java.lang.String, int);
     method public int checkRightsStatus(android.net.Uri, int);
+    method public void close();
     method public android.drm.DrmConvertedStatus closeConvertSession(int);
     method public android.drm.DrmConvertedStatus convertData(int, byte[]);
     method public java.lang.String[] getAvailableDrmEngines();
@@ -10862,7 +11020,7 @@
     method public java.lang.String getOriginalMimeType(android.net.Uri);
     method public int openConvertSession(java.lang.String);
     method public int processDrmInfo(android.drm.DrmInfo);
-    method public void release();
+    method public deprecated void release();
     method public int removeAllRights();
     method public int removeRights(java.lang.String);
     method public int removeRights(android.net.Uri);
@@ -11266,14 +11424,14 @@
 
   public static class BitmapFactory.Options {
     ctor public BitmapFactory.Options();
-    method public void requestCancelDecode();
+    method public deprecated void requestCancelDecode();
     field public android.graphics.Bitmap inBitmap;
     field public int inDensity;
-    field public boolean inDither;
+    field public deprecated boolean inDither;
     field public deprecated boolean inInputShareable;
     field public boolean inJustDecodeBounds;
     field public boolean inMutable;
-    field public boolean inPreferQualityOverSpeed;
+    field public deprecated boolean inPreferQualityOverSpeed;
     field public android.graphics.Bitmap.Config inPreferredConfig;
     field public boolean inPremultiplied;
     field public deprecated boolean inPurgeable;
@@ -11282,7 +11440,7 @@
     field public int inScreenDensity;
     field public int inTargetDensity;
     field public byte[] inTempStorage;
-    field public boolean mCancel;
+    field public deprecated boolean mCancel;
     field public int outHeight;
     field public java.lang.String outMimeType;
     field public int outWidth;
@@ -12721,6 +12879,7 @@
     method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
     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 {
@@ -13217,6 +13376,7 @@
     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 isWakeUpSensor();
@@ -13231,17 +13391,21 @@
     field public static final java.lang.String STRING_TYPE_GRAVITY = "android.sensor.gravity";
     field public static final java.lang.String STRING_TYPE_GYROSCOPE = "android.sensor.gyroscope";
     field public static final java.lang.String STRING_TYPE_GYROSCOPE_UNCALIBRATED = "android.sensor.gyroscope_uncalibrated";
+    field public static final java.lang.String STRING_TYPE_HEART_BEAT = "android.sensor.heart_beat";
     field public static final java.lang.String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
     field public static final java.lang.String STRING_TYPE_LIGHT = "android.sensor.light";
     field public static final java.lang.String STRING_TYPE_LINEAR_ACCELERATION = "android.sensor.linear_acceleration";
     field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD = "android.sensor.magnetic_field";
     field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED = "android.sensor.magnetic_field_uncalibrated";
+    field public static final java.lang.String STRING_TYPE_MOTION_DETECT = "android.sensor.motion_detect";
     field public static final deprecated java.lang.String STRING_TYPE_ORIENTATION = "android.sensor.orientation";
+    field public static final java.lang.String STRING_TYPE_POSE_6DOF = "android.sensor.pose_6dof";
     field public static final java.lang.String STRING_TYPE_PRESSURE = "android.sensor.pressure";
     field public static final java.lang.String STRING_TYPE_PROXIMITY = "android.sensor.proximity";
     field public static final java.lang.String STRING_TYPE_RELATIVE_HUMIDITY = "android.sensor.relative_humidity";
     field public static final java.lang.String STRING_TYPE_ROTATION_VECTOR = "android.sensor.rotation_vector";
     field public static final java.lang.String STRING_TYPE_SIGNIFICANT_MOTION = "android.sensor.significant_motion";
+    field public static final java.lang.String STRING_TYPE_STATIONARY_DETECT = "android.sensor.stationary_detect";
     field public static final java.lang.String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
     field public static final java.lang.String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
     field public static final deprecated java.lang.String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
@@ -13253,22 +13417,41 @@
     field public static final int TYPE_GRAVITY = 9; // 0x9
     field public static final int TYPE_GYROSCOPE = 4; // 0x4
     field public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16; // 0x10
+    field public static final int TYPE_HEART_BEAT = 31; // 0x1f
     field public static final int TYPE_HEART_RATE = 21; // 0x15
     field public static final int TYPE_LIGHT = 5; // 0x5
     field public static final int TYPE_LINEAR_ACCELERATION = 10; // 0xa
     field public static final int TYPE_MAGNETIC_FIELD = 2; // 0x2
     field public static final int TYPE_MAGNETIC_FIELD_UNCALIBRATED = 14; // 0xe
+    field public static final int TYPE_MOTION_DETECT = 30; // 0x1e
     field public static final deprecated int TYPE_ORIENTATION = 3; // 0x3
+    field public static final int TYPE_POSE_6DOF = 28; // 0x1c
     field public static final int TYPE_PRESSURE = 6; // 0x6
     field public static final int TYPE_PROXIMITY = 8; // 0x8
     field public static final int TYPE_RELATIVE_HUMIDITY = 12; // 0xc
     field public static final int TYPE_ROTATION_VECTOR = 11; // 0xb
     field public static final int TYPE_SIGNIFICANT_MOTION = 17; // 0x11
+    field public static final int TYPE_STATIONARY_DETECT = 29; // 0x1d
     field public static final int TYPE_STEP_COUNTER = 19; // 0x13
     field public static final int TYPE_STEP_DETECTOR = 18; // 0x12
     field public static final deprecated int TYPE_TEMPERATURE = 7; // 0x7
   }
 
+  public class SensorAdditionalInfo {
+    field public static final int TYPE_FRAME_BEGIN = 0; // 0x0
+    field public static final int TYPE_FRAME_END = 1; // 0x1
+    field public static final int TYPE_INTERNAL_TEMPERATURE = 65537; // 0x10001
+    field public static final int TYPE_SAMPLING = 65540; // 0x10004
+    field public static final int TYPE_SENSOR_PLACEMENT = 65539; // 0x10003
+    field public static final int TYPE_UNTRACKED_DELAY = 65536; // 0x10000
+    field public static final int TYPE_VEC3_CALIBRATION = 65538; // 0x10002
+    field public final float[] floatValues;
+    field public final int[] intValues;
+    field public final android.hardware.Sensor sensor;
+    field public final int serial;
+    field public final int type;
+  }
+
   public class SensorEvent {
     field public int accuracy;
     field public android.hardware.Sensor sensor;
@@ -13276,6 +13459,14 @@
     field public final float[] values;
   }
 
+  public abstract class SensorEventCallback implements android.hardware.SensorEventListener2 {
+    ctor public SensorEventCallback();
+    method public void onAccuracyChanged(android.hardware.Sensor, int);
+    method public void onFlushCompleted(android.hardware.Sensor);
+    method public void onSensorAdditionalInfo(android.hardware.SensorAdditionalInfo);
+    method public void onSensorChanged(android.hardware.SensorEvent);
+  }
+
   public abstract interface SensorEventListener {
     method public abstract void onAccuracyChanged(android.hardware.Sensor, int);
     method public abstract void onSensorChanged(android.hardware.SensorEvent);
@@ -13297,6 +13488,7 @@
     method public static void getAngleChange(float[], float[], float[]);
     method public android.hardware.Sensor getDefaultSensor(int);
     method public android.hardware.Sensor getDefaultSensor(int, boolean);
+    method public java.util.List<android.hardware.Sensor> getDynamicSensorList(int);
     method public static float getInclination(float[]);
     method public static float[] getOrientation(float[], float[]);
     method public static void getQuaternionFromVector(float[], float[]);
@@ -13304,6 +13496,8 @@
     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 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);
@@ -13312,6 +13506,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 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);
@@ -13376,6 +13571,12 @@
     field public static final float STANDARD_GRAVITY = 9.80665f;
   }
 
+  public static abstract class SensorManager.DynamicSensorConnectionCallback {
+    ctor public SensorManager.DynamicSensorConnectionCallback();
+    method public void onDynamicSensorConnected(android.hardware.Sensor);
+    method public void onDynamicSensorDisconnected(android.hardware.Sensor);
+  }
+
   public final class TriggerEvent {
     field public android.hardware.Sensor sensor;
     field public long timestamp;
@@ -13460,6 +13661,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AF;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AWB;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Integer>> CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> DEPTH_DEPTH_IS_EXCLUSIVE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> EDGE_AVAILABLE_EDGE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> FLASH_INFO_AVAILABLE;
@@ -13539,9 +13741,11 @@
     method public abstract void close();
     method public abstract android.hardware.camera2.CaptureRequest.Builder createCaptureRequest(int) throws android.hardware.camera2.CameraAccessException;
     method public abstract void createCaptureSession(java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method public abstract void createCaptureSessionByOutputConfiguration(java.util.List<android.hardware.camera2.params.OutputConfiguration>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract void createConstrainedHighSpeedCaptureSession(java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract android.hardware.camera2.CaptureRequest.Builder createReprocessCaptureRequest(android.hardware.camera2.TotalCaptureResult) throws android.hardware.camera2.CameraAccessException;
     method public abstract void createReprocessableCaptureSession(android.hardware.camera2.params.InputConfiguration, java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method public abstract void createReprocessableCaptureSessionWithConfigurations(android.hardware.camera2.params.InputConfiguration, java.util.List<android.hardware.camera2.params.OutputConfiguration>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract java.lang.String getId();
     field public static final int TEMPLATE_MANUAL = 6; // 0x6
     field public static final int TEMPLATE_PREVIEW = 1; // 0x1
@@ -13698,6 +13902,7 @@
     field public static final int HOT_PIXEL_MODE_FAST = 1; // 0x1
     field public static final int HOT_PIXEL_MODE_HIGH_QUALITY = 2; // 0x2
     field public static final int HOT_PIXEL_MODE_OFF = 0; // 0x0
+    field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_3 = 3; // 0x3
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1; // 0x1
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY = 2; // 0x2
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0; // 0x0
@@ -13819,6 +14024,7 @@
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_CAPTURE_INTENT;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_EFFECT_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_POST_RAW_SENSITIVITY_BOOST;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_SCENE_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_VIDEO_STABILIZATION_MODE;
     field public static final android.os.Parcelable.Creator<android.hardware.camera2.CaptureRequest> CREATOR;
@@ -13897,6 +14103,7 @@
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_CAPTURE_INTENT;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_EFFECT_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_POST_RAW_SENSITIVITY_BOOST;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_SCENE_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_VIDEO_STABILIZATION_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> EDGE_MODE;
@@ -14038,6 +14245,17 @@
     field public static final int METERING_WEIGHT_MIN = 0; // 0x0
   }
 
+  public final class OutputConfiguration implements android.os.Parcelable {
+    ctor public OutputConfiguration(android.view.Surface);
+    method public int describeContents();
+    method public android.view.Surface getSurface();
+    method public int getSurfaceSetId();
+    method public void setSurfaceSetId(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
+    field public static final int SURFACE_SET_ID_INVALID = -1; // 0xffffffff
+  }
+
   public final class RggbChannelVector {
     ctor public RggbChannelVector(float, float, float, float);
     method public void copyTo(float[], int);
@@ -18242,7 +18460,6 @@
     method public static java.lang.String getCanonicalID(java.lang.String, boolean[]);
     method public int getDSTSavings();
     method public static android.icu.util.TimeZone getDefault();
-    method public static int getDefaultTimeZoneType();
     method public final java.lang.String getDisplayName();
     method public final java.lang.String getDisplayName(java.util.Locale);
     method public final java.lang.String getDisplayName(android.icu.util.ULocale);
@@ -18266,8 +18483,6 @@
     method public abstract boolean inDaylightTime(java.util.Date);
     method public boolean isFrozen();
     method public boolean observesDaylightTime();
-    method public static synchronized void setDefault(android.icu.util.TimeZone);
-    method public static synchronized void setDefaultTimeZoneType(int);
     method public void setID(java.lang.String);
     method public abstract void setRawOffset(int);
     method public abstract boolean useDaylightTime();
@@ -18280,8 +18495,6 @@
     field public static final int SHORT_COMMONLY_USED = 6; // 0x6
     field public static final int SHORT_GENERIC = 2; // 0x2
     field public static final int SHORT_GMT = 4; // 0x4
-    field public static final int TIMEZONE_ICU = 0; // 0x0
-    field public static final int TIMEZONE_JDK = 1; // 0x1
     field public static final android.icu.util.TimeZone UNKNOWN_ZONE;
     field public static final java.lang.String UNKNOWN_ZONE_ID = "Etc/Unknown";
   }
@@ -18377,8 +18590,6 @@
     method public static java.lang.String getVariant(java.lang.String);
     method public boolean isRightToLeft();
     method public static android.icu.util.ULocale minimizeSubtags(android.icu.util.ULocale);
-    method public static synchronized void setDefault(android.icu.util.ULocale);
-    method public static synchronized void setDefault(android.icu.util.ULocale.Category, android.icu.util.ULocale);
     method public android.icu.util.ULocale setKeywordValue(java.lang.String, java.lang.String);
     method public static java.lang.String setKeywordValue(java.lang.String, java.lang.String, java.lang.String);
     method public java.lang.String toLanguageTag();
@@ -18866,6 +19077,288 @@
     method public static boolean isPresent();
   }
 
+  public abstract interface GnssNmeaListener {
+    method public abstract void onNmeaReceived(long, java.lang.String);
+  }
+
+  public final class GnssStatus {
+    method public float getAzimuth(int);
+    method public int getConstellationType(int);
+    method public float getElevation(int);
+    method public int getNumSatellites();
+    method public int getPrn(int);
+    method public float getSnr(int);
+    method public boolean hasAlmanac(int);
+    method public boolean hasEphemeris(int);
+    method public boolean usedInFix(int);
+    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 {
+    ctor public GnssStatusCallback();
+    method public void onFirstFix(int);
+    method public void onSatelliteStatusChanged(android.location.GnssStatus);
+    method public void onStarted();
+    method public void onStopped();
+  }
+
+  public final class GpsClock 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 short getLeapSecond();
+    method public long getTimeInNs();
+    method public long getTimeOfLastHwClockDiscontinuityInNs();
+    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 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.GpsClock);
+    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 setLeapSecond(short);
+    method public void setTimeInNs(long);
+    method public void setTimeOfLastHwClockDiscontinuityInNs(long);
+    method public void setTimeUncertaintyInNs(double);
+    method public void setType(byte);
+    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.GpsClock> CREATOR;
+  }
+
+  public static abstract class GpsClock.GpsClockType implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsMeasurement 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 long getCarrierCycles();
+    method public float getCarrierFrequencyInHz();
+    method public double getCarrierPhase();
+    method public double getCarrierPhaseUncertainty();
+    method public double getCn0InDbHz();
+    method public double getCodePhaseInChips();
+    method public double getCodePhaseUncertaintyInChips();
+    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 byte getPrn();
+    method public double getPseudorangeInMeters();
+    method public double getPseudorangeRateCarrierInMetersPerSec();
+    method public double getPseudorangeRateCarrierUncertaintyInMetersPerSec();
+    method public double getPseudorangeRateInMetersPerSec();
+    method public double getPseudorangeRateUncertaintyInMetersPerSec();
+    method public double getPseudorangeUncertaintyInMeters();
+    method public long getReceivedGpsTowInNs();
+    method public long getReceivedGpsTowUncertaintyInNs();
+    method public double getSnrInDb();
+    method public short getState();
+    method public short getTimeFromLastBitInMs();
+    method public double getTimeOffsetInNs();
+    method public boolean hasAzimuthInDeg();
+    method public boolean hasAzimuthUncertaintyInDeg();
+    method public boolean hasBitNumber();
+    method public boolean hasCarrierCycles();
+    method public boolean hasCarrierFrequencyInHz();
+    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.GpsMeasurement);
+    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 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 setPrn(byte);
+    method public void setPseudorangeInMeters(double);
+    method public void setPseudorangeRateCarrierInMetersPerSec(double);
+    method public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double);
+    method public void setPseudorangeRateInMetersPerSec(double);
+    method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
+    method public void setPseudorangeUncertaintyInMeters(double);
+    method public void setReceivedGpsTowInNs(long);
+    method public void setReceivedGpsTowUncertaintyInNs(long);
+    method public void setSnrInDb(double);
+    method public void setState(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 android.os.Parcelable.Creator<android.location.GpsMeasurement> 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 GpsMeasurement.LossOfLockStatus implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract class GpsMeasurement.MultipathIndicator implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsMeasurementsEvent implements android.os.Parcelable {
+    ctor public GpsMeasurementsEvent(android.location.GpsClock, android.location.GpsMeasurement[]);
+    method public int describeContents();
+    method public android.location.GpsClock getClock();
+    method public java.util.Collection<android.location.GpsMeasurement> getMeasurements();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.location.GpsMeasurementsEvent> CREATOR;
+    field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
+    field public static final int STATUS_READY = 1; // 0x1
+  }
+
+  public static abstract class GpsMeasurementsEvent.Callback {
+    ctor public GpsMeasurementsEvent.Callback();
+    method public void onGpsMeasurementsReceived(android.location.GpsMeasurementsEvent);
+    method public void onStatusChanged(int);
+  }
+
+  public static abstract class GpsMeasurementsEvent.GpsMeasurementsStatus implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsNavigationMessage implements android.os.Parcelable {
+    method public int describeContents();
+    method public byte[] getData();
+    method public short getMessageId();
+    method public byte getPrn();
+    method public short getStatus();
+    method public short getSubmessageId();
+    method public byte getType();
+    method public void reset();
+    method public void set(android.location.GpsNavigationMessage);
+    method public void setData(byte[]);
+    method public void setMessageId(short);
+    method public void setPrn(byte);
+    method public void setStatus(short);
+    method public void setSubmessageId(short);
+    method public void setType(byte);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessage> CREATOR;
+    field public static final byte MESSAGE_TYPE_CNAV2 = 4; // 0x4
+    field public static final byte MESSAGE_TYPE_L1CA = 1; // 0x1
+    field public static final byte MESSAGE_TYPE_L2CNAV = 2; // 0x2
+    field public static final byte MESSAGE_TYPE_L5CNAV = 3; // 0x3
+    field public static final byte 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 GpsNavigationMessage.GpsNavigationMessageType implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsNavigationMessageEvent implements android.os.Parcelable {
+    ctor public GpsNavigationMessageEvent(android.location.GpsNavigationMessage);
+    method public int describeContents();
+    method public android.location.GpsNavigationMessage getNavigationMessage();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessageEvent> CREATOR;
+    field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
+    field public static final int STATUS_READY = 1; // 0x1
+  }
+
+  public static abstract class GpsNavigationMessageEvent.Callback {
+    ctor public GpsNavigationMessageEvent.Callback();
+    method public void onGpsNavigationMessageReceived(android.location.GpsNavigationMessageEvent);
+    method public void onStatusChanged(int);
+  }
+
+  public static abstract class GpsNavigationMessageEvent.GpsNavigationMessageStatus implements java.lang.annotation.Annotation {
+  }
+
   public final class GpsSatellite {
     method public float getAzimuth();
     method public float getElevation();
@@ -18950,8 +19443,10 @@
   }
 
   public class LocationManager {
-    method public boolean addGpsStatusListener(android.location.GpsStatus.Listener);
-    method public boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public deprecated boolean addGpsStatusListener(android.location.GpsStatus.Listener);
+    method public deprecated boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public boolean addNmeaListener(android.location.GnssNmeaListener);
+    method public boolean addNmeaListener(android.location.GnssNmeaListener, android.os.Handler);
     method public void addProximityAlert(double, double, float, long, android.app.PendingIntent);
     method public void addTestProvider(java.lang.String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
     method public void clearTestProviderEnabled(java.lang.String);
@@ -18959,14 +19454,21 @@
     method public void clearTestProviderStatus(java.lang.String);
     method public java.util.List<java.lang.String> getAllProviders();
     method public java.lang.String getBestProvider(android.location.Criteria, boolean);
-    method public android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
+    method public deprecated android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
     method public android.location.Location getLastKnownLocation(java.lang.String);
     method public android.location.LocationProvider getProvider(java.lang.String);
     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 void removeGpsStatusListener(android.location.GpsStatus.Listener);
-    method public void removeNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback);
+    method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback, android.os.Handler);
+    method public boolean registerGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback);
+    method public boolean registerGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback, android.os.Handler);
+    method public boolean registerGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback);
+    method public boolean registerGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback, android.os.Handler);
+    method public deprecated void removeGpsStatusListener(android.location.GpsStatus.Listener);
+    method public deprecated void removeNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public void removeNmeaListener(android.location.GnssNmeaListener);
     method public void removeProximityAlert(android.app.PendingIntent);
     method public void removeTestProvider(java.lang.String);
     method public void removeUpdates(android.location.LocationListener);
@@ -18984,6 +19486,9 @@
     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 unregisterGnssStatusCallback(android.location.GnssStatusCallback);
+    method public void unregisterGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback);
+    method public void unregisterGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback);
     field public static final java.lang.String GPS_PROVIDER = "gps";
     field public static final java.lang.String KEY_LOCATION_CHANGED = "location";
     field public static final java.lang.String KEY_PROVIDER_ENABLED = "providerEnabled";
@@ -19050,6 +19555,7 @@
     field public static final android.os.Parcelable.Creator<android.media.AudioAttributes> CREATOR;
     field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
     field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
+    field public static final int FLAG_LOW_LATENCY = 256; // 0x100
     field public static final int USAGE_ALARM = 4; // 0x4
     field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
     field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc
@@ -19169,6 +19675,7 @@
     field public static final int ENCODING_DTS = 7; // 0x7
     field public static final int ENCODING_DTS_HD = 8; // 0x8
     field public static final int ENCODING_E_AC3 = 6; // 0x6
+    field public static final int ENCODING_IEC61937 = 13; // 0xd
     field public static final int ENCODING_INVALID = 0; // 0x0
     field public static final int ENCODING_PCM_16BIT = 2; // 0x2
     field public static final int ENCODING_PCM_8BIT = 3; // 0x3
@@ -19192,6 +19699,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.AudioDeviceInfo[] getDevices(int);
     method public int getMode();
     method public java.lang.String getParameters(java.lang.String);
@@ -19214,6 +19722,7 @@
     method public void playSoundEffect(int);
     method public void playSoundEffect(int, float);
     method public void registerAudioDeviceCallback(android.media.AudioDeviceCallback, android.os.Handler);
+    method public void registerAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback, android.os.Handler);
     method public deprecated void registerMediaButtonEventReceiver(android.content.ComponentName);
     method public deprecated void registerMediaButtonEventReceiver(android.app.PendingIntent);
     method public deprecated void registerRemoteControlClient(android.media.RemoteControlClient);
@@ -19237,6 +19746,7 @@
     method public void stopBluetoothSco();
     method public void unloadSoundEffects();
     method public void unregisterAudioDeviceCallback(android.media.AudioDeviceCallback);
+    method public void unregisterAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback);
     method public deprecated void unregisterMediaButtonEventReceiver(android.content.ComponentName);
     method public deprecated void unregisterMediaButtonEventReceiver(android.app.PendingIntent);
     method public deprecated void unregisterRemoteControlClient(android.media.RemoteControlClient);
@@ -19299,6 +19809,7 @@
     field public static final deprecated int NUM_STREAMS = 5; // 0x5
     field public static final java.lang.String PROPERTY_OUTPUT_FRAMES_PER_BUFFER = "android.media.property.OUTPUT_FRAMES_PER_BUFFER";
     field public static final java.lang.String PROPERTY_OUTPUT_SAMPLE_RATE = "android.media.property.OUTPUT_SAMPLE_RATE";
+    field public static final java.lang.String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED = "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED";
     field public static final java.lang.String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND = "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND";
     field public static final java.lang.String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND = "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND";
     field public static final java.lang.String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED";
@@ -19332,13 +19843,19 @@
     field public static final deprecated int VIBRATE_TYPE_RINGER = 0; // 0x0
   }
 
+  public static abstract class AudioManager.AudioRecordingCallback {
+    ctor public AudioManager.AudioRecordingCallback();
+    method public void onRecordConfigChanged();
+  }
+
   public static abstract interface AudioManager.OnAudioFocusChangeListener {
     method public abstract void onAudioFocusChange(int);
   }
 
-  public class AudioRecord {
+  public class AudioRecord implements android.media.AudioRouting {
     ctor public AudioRecord(int, int, int, int, int) throws java.lang.IllegalArgumentException;
-    method public void addOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener, android.os.Handler);
+    method public deprecated void addOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener, android.os.Handler);
+    method public void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
     method public int getAudioFormat();
     method public int getAudioSessionId();
     method public int getAudioSource();
@@ -19362,7 +19879,8 @@
     method public int read(java.nio.ByteBuffer, int);
     method public int read(java.nio.ByteBuffer, int, int);
     method public void release();
-    method public void removeOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener);
+    method public deprecated void removeOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener);
+    method public void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
     method public int setNotificationMarkerPosition(int);
     method public int setPositionNotificationPeriod(int);
     method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
@@ -19400,21 +19918,45 @@
     method public abstract void onRoutingChanged(android.media.AudioRecord);
   }
 
+  public class AudioRecordConfiguration implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.media.AudioDeviceInfo getAudioDevice();
+    method public int getClientAudioSessionId();
+    method public int getClientAudioSource();
+    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;
+  }
+
+  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 void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
+    method public abstract boolean setPreferredDevice(android.media.AudioDeviceInfo);
+  }
+
+  public static abstract interface AudioRouting.OnRoutingChangedListener {
+    method public abstract void onRoutingChanged(android.media.AudioRouting);
+  }
+
   public final class AudioTimestamp {
     ctor public AudioTimestamp();
     field public long framePosition;
     field public long nanoTime;
   }
 
-  public class AudioTrack {
+  public class AudioTrack implements android.media.AudioRouting {
     ctor public AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
     ctor public AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
     ctor public AudioTrack(android.media.AudioAttributes, android.media.AudioFormat, int, int, int) throws java.lang.IllegalArgumentException;
-    method public void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
+    method public deprecated void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
+    method public void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
     method public int attachAuxEffect(int);
     method public void flush();
     method public int getAudioFormat();
     method public int getAudioSessionId();
+    method public int getBufferCapacityInFrames();
     method public int getBufferSizeInFrames();
     method public int getChannelConfiguration();
     method public int getChannelCount();
@@ -19436,12 +19978,15 @@
     method public int getState();
     method public int getStreamType();
     method public boolean getTimestamp(android.media.AudioTimestamp);
+    method public int getUnderrunCount();
     method public void pause() throws java.lang.IllegalStateException;
     method public void play() throws java.lang.IllegalStateException;
     method public void release();
     method public int reloadStaticData();
-    method public void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
+    method public deprecated void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
+    method public void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
     method public int setAuxEffectSendLevel(float);
+    method public int setBufferSizeInFrames(int);
     method public int setLoopPoints(int, int, int);
     method public int setNotificationMarkerPosition(int);
     method public int setPlaybackHeadPosition(int);
@@ -19493,8 +20038,8 @@
     method public abstract void onPeriodicNotification(android.media.AudioTrack);
   }
 
-  public static abstract interface AudioTrack.OnRoutingChangedListener {
-    method public abstract void onRoutingChanged(android.media.AudioTrack);
+  public static abstract deprecated interface AudioTrack.OnRoutingChangedListener {
+    method public abstract deprecated void onRoutingChanged(android.media.AudioTrack);
   }
 
   public class CamcorderProfile {
@@ -19553,6 +20098,16 @@
     ctor public DeniedByServerException(java.lang.String);
   }
 
+  public abstract class DrmInitData {
+    ctor public DrmInitData();
+    method public abstract android.media.DrmInitData.SchemeInitData get(java.util.UUID);
+  }
+
+  public static final class DrmInitData.SchemeInitData {
+    field public final byte[] data;
+    field public final java.lang.String mimeType;
+  }
+
   public class ExifInterface {
     ctor public ExifInterface(java.lang.String) throws java.io.IOException;
     method public double getAltitude(double);
@@ -19900,6 +20455,7 @@
     field public static final deprecated int COLOR_QCOM_FormatYUV420SemiPlanar = 2141391872; // 0x7fa30c00
     field public static final deprecated int COLOR_TI_FormatYUV420PackedSemiPlanar = 2130706688; // 0x7f000100
     field public static final java.lang.String FEATURE_AdaptivePlayback = "adaptive-playback";
+    field public static final java.lang.String FEATURE_IntraRefresh = "intra-refresh";
     field public static final java.lang.String FEATURE_SecurePlayback = "secure-playback";
     field public static final java.lang.String FEATURE_TunneledPlayback = "tunneled-playback";
     field public int[] colorFormats;
@@ -19942,6 +20498,21 @@
     field public static final int AVCProfileHigh422 = 32; // 0x20
     field public static final int AVCProfileHigh444 = 64; // 0x40
     field public static final int AVCProfileMain = 2; // 0x2
+    field public static final int DolbyVisionLevelFhd24 = 4; // 0x4
+    field public static final int DolbyVisionLevelFhd30 = 8; // 0x8
+    field public static final int DolbyVisionLevelFhd60 = 16; // 0x10
+    field public static final int DolbyVisionLevelHd24 = 1; // 0x1
+    field public static final int DolbyVisionLevelHd30 = 2; // 0x2
+    field public static final int DolbyVisionLevelUhd24 = 32; // 0x20
+    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 H263Level10 = 1; // 0x1
     field public static final int H263Level20 = 2; // 0x2
     field public static final int H263Level30 = 4; // 0x4
@@ -20026,6 +20597,24 @@
     field public static final int VP8Level_Version2 = 4; // 0x4
     field public static final int VP8Level_Version3 = 8; // 0x8
     field public static final int VP8ProfileMain = 1; // 0x1
+    field public static final int VP9Level1 = 0; // 0x0
+    field public static final int VP9Level11 = 1; // 0x1
+    field public static final int VP9Level2 = 2; // 0x2
+    field public static final int VP9Level21 = 4; // 0x4
+    field public static final int VP9Level3 = 8; // 0x8
+    field public static final int VP9Level31 = 16; // 0x10
+    field public static final int VP9Level4 = 32; // 0x20
+    field public static final int VP9Level41 = 64; // 0x40
+    field public static final int VP9Level5 = 128; // 0x80
+    field public static final int VP9Level51 = 256; // 0x100
+    field public static final int VP9Level52 = 512; // 0x200
+    field public static final int VP9Level6 = 1024; // 0x400
+    field public static final int VP9Level61 = 2048; // 0x800
+    field public static final int VP9Level62 = 4096; // 0x1000
+    field public static final int VP9Profile0 = 0; // 0x0
+    field public static final int VP9Profile1 = 1; // 0x1
+    field public static final int VP9Profile2 = 2; // 0x2
+    field public static final int VP9Profile3 = 3; // 0x3
     field public int level;
     field public int profile;
   }
@@ -20209,6 +20798,7 @@
     ctor public MediaExtractor();
     method public boolean advance();
     method public long getCachedDuration();
+    method public android.media.DrmInitData getDrmInitData();
     method public java.util.Map<java.util.UUID, byte[]> getPsshInfo();
     method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo);
     method public int getSampleFlags();
@@ -20253,6 +20843,16 @@
     method public final void setInteger(java.lang.String, int);
     method public final void setLong(java.lang.String, long);
     method public final void setString(java.lang.String, java.lang.String);
+    field public static final int COLOR_RANGE_FULL = 1; // 0x1
+    field public static final int COLOR_RANGE_LIMITED = 2; // 0x2
+    field public static final int COLOR_STANDARD_BT2020 = 6; // 0x6
+    field public static final int COLOR_STANDARD_BT601_NTSC = 4; // 0x4
+    field public static final int COLOR_STANDARD_BT601_PAL = 2; // 0x2
+    field public static final int COLOR_STANDARD_BT709 = 1; // 0x1
+    field public static final int COLOR_TRANSFER_HLG = 7; // 0x7
+    field public static final int COLOR_TRANSFER_LINEAR = 1; // 0x1
+    field public static final int COLOR_TRANSFER_SDR_VIDEO = 3; // 0x3
+    field public static final int COLOR_TRANSFER_ST2084 = 6; // 0x6
     field public static final java.lang.String KEY_AAC_DRC_ATTENUATION_FACTOR = "aac-drc-cut-level";
     field public static final java.lang.String KEY_AAC_DRC_BOOST_FACTOR = "aac-drc-boost-level";
     field public static final java.lang.String KEY_AAC_DRC_HEAVY_COMPRESSION = "aac-drc-heavy-compression";
@@ -20268,11 +20868,15 @@
     field public static final java.lang.String KEY_CHANNEL_COUNT = "channel-count";
     field public static final java.lang.String KEY_CHANNEL_MASK = "channel-mask";
     field public static final java.lang.String KEY_COLOR_FORMAT = "color-format";
+    field public static final java.lang.String KEY_COLOR_RANGE = "color-range";
+    field public static final java.lang.String KEY_COLOR_STANDARD = "color-standard";
+    field public static final java.lang.String KEY_COLOR_TRANSFER = "color-transfer";
     field public static final java.lang.String KEY_COMPLEXITY = "complexity";
     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_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";
     field public static final java.lang.String KEY_IS_AUTOSELECT = "is-autoselect";
     field public static final java.lang.String KEY_IS_DEFAULT = "is-default";
@@ -20312,8 +20916,7 @@
     field public static final java.lang.String MIMETYPE_TEXT_CEA_608 = "text/cea-608";
     field public static final java.lang.String MIMETYPE_TEXT_VTT = "text/vtt";
     field public static final java.lang.String MIMETYPE_VIDEO_AVC = "video/avc";
-    field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_AVC = "video/dolby-avc";
-    field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_HEVC = "video/dolby-hevc";
+    field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision";
     field public static final java.lang.String MIMETYPE_VIDEO_H263 = "video/3gpp";
     field public static final java.lang.String MIMETYPE_VIDEO_HEVC = "video/hevc";
     field public static final java.lang.String MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
@@ -20595,9 +21198,11 @@
     method public static final int getAudioSourceMax();
     method public int getMaxAmplitude() throws java.lang.IllegalStateException;
     method public android.view.Surface getSurface();
+    method public void pause() throws java.lang.IllegalStateException;
     method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
     method public void release();
     method public void reset();
+    method public void resume() throws java.lang.IllegalStateException;
     method public void setAudioChannels(int);
     method public void setAudioEncoder(int) throws java.lang.IllegalStateException;
     method public void setAudioEncodingBitRate(int);
@@ -20646,6 +21251,7 @@
     field public static final int DEFAULT = 0; // 0x0
     field public static final int MIC = 1; // 0x1
     field public static final int REMOTE_SUBMIX = 8; // 0x8
+    field public static final int UNPROCESSED = 9; // 0x9
     field public static final int VOICE_CALL = 4; // 0x4
     field public static final int VOICE_COMMUNICATION = 7; // 0x7
     field public static final int VOICE_DOWNLINK = 3; // 0x3
@@ -20676,6 +21282,7 @@
     field public static final int DEFAULT = 0; // 0x0
     field public static final int H263 = 1; // 0x1
     field public static final int H264 = 2; // 0x2
+    field public static final int HEVC = 5; // 0x5
     field public static final int MPEG_4_SP = 3; // 0x3
     field public static final int VP8 = 4; // 0x4
   }
@@ -21564,7 +22171,11 @@
     method public android.media.session.MediaSession.Token getSessionToken();
     method public boolean isConnected();
     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);
+    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";
   }
 
   public static class MediaBrowser.ConnectionCallback {
@@ -21597,7 +22208,9 @@
   public static abstract class MediaBrowser.SubscriptionCallback {
     ctor public MediaBrowser.SubscriptionCallback();
     method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>);
+    method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>, android.os.Bundle);
     method public void onError(java.lang.String);
+    method public void onError(java.lang.String, android.os.Bundle);
   }
 
 }
@@ -21883,6 +22496,7 @@
     method public void setRatingType(int);
     method public void setSessionActivity(android.app.PendingIntent);
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+    field public static final int FLAG_HANDLES_PREPARE_ONLY = 4; // 0x4
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
   }
 
@@ -21961,6 +22575,7 @@
     field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
     field public static final long ACTION_STOP = 1L; // 0x1L
     field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR;
+    field public static final java.lang.String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
     field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
     field public static final int STATE_BUFFERING = 6; // 0x6
     field public static final int STATE_CONNECTING = 8; // 0x8
@@ -22035,6 +22650,7 @@
     method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri);
     method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
     method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
+    method public static final android.net.Uri buildRecordedProgramUri(long);
     field public static final java.lang.String AUTHORITY = "android.media.tv";
   }
 
@@ -22171,13 +22787,49 @@
     field public static final java.lang.String TRAVEL = "TRAVEL";
   }
 
+  public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseTvColumns {
+    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+    field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
+    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_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";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    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_RECORDING_DATA_BYTES = "recording_data_bytes";
+    field public static final java.lang.String COLUMN_RECORDING_DATA_URI = "recording_data_uri";
+    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_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";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
+    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/recorded_program";
+    field public static final android.net.Uri CONTENT_URI;
+  }
+
   public final class TvInputInfo implements android.os.Parcelable {
+    method public boolean canRecord();
     method public android.content.Intent createSettingsIntent();
     method public android.content.Intent createSetupIntent();
     method public int describeContents();
     method public java.lang.String getId();
     method public java.lang.String getParentId();
     method public android.content.pm.ServiceInfo getServiceInfo();
+    method public int getTunerCount();
     method public int getType();
     method public boolean isPassthroughInput();
     method public android.graphics.drawable.Drawable loadIcon(android.content.Context);
@@ -22197,6 +22849,13 @@
     field public static final int TYPE_VGA = 1005; // 0x3ed
   }
 
+  public static final class TvInputInfo.Builder {
+    ctor public TvInputInfo.Builder(android.content.Context, java.lang.Class<?>);
+    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);
+  }
+
   public final class TvInputManager {
     method public int getInputState(java.lang.String);
     method public android.media.tv.TvInputInfo getTvInputInfo(java.lang.String);
@@ -22212,6 +22871,10 @@
     field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
     field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
     field public static final java.lang.String META_DATA_CONTENT_RATING_SYSTEMS = "android.media.tv.metadata.CONTENT_RATING_SYSTEMS";
+    field public static final int RECORDING_ERROR_CONNECTION_FAILED = 1; // 0x1
+    field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 2; // 0x2
+    field public static final int RECORDING_ERROR_RESOURCE_BUSY = 3; // 0x3
+    field public static final int RECORDING_ERROR_UNKNOWN = 0; // 0x0
     field public static final long TIME_SHIFT_INVALID_TIME = -9223372036854775808L; // 0x8000000000000000L
     field public static final int TIME_SHIFT_STATUS_AVAILABLE = 3; // 0x3
     field public static final int TIME_SHIFT_STATUS_UNAVAILABLE = 2; // 0x2
@@ -22229,12 +22892,15 @@
     method public void onInputAdded(java.lang.String);
     method public void onInputRemoved(java.lang.String);
     method public void onInputStateChanged(java.lang.String, int);
+    method public void onTvInputInfoChanged(android.media.tv.TvInputInfo);
   }
 
   public abstract class TvInputService extends android.app.Service {
     ctor public TvInputService();
     method public final android.os.IBinder onBind(android.content.Intent);
+    method public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(java.lang.String);
     method public abstract android.media.tv.TvInputService.Session onCreateSession(java.lang.String);
+    method public static final void setTvInputInfo(android.content.Context, android.media.tv.TvInputInfo);
     field public static final java.lang.String SERVICE_INTERFACE = "android.media.tv.TvInputService";
     field public static final java.lang.String SERVICE_META_DATA = "android.media.tv.input";
   }
@@ -22247,6 +22913,18 @@
     method public final boolean onSetSurface(android.view.Surface);
   }
 
+  public static abstract class TvInputService.RecordingSession {
+    ctor public TvInputService.RecordingSession(android.content.Context);
+    method public void notifyConnected();
+    method public void notifyError(int);
+    method public void notifyRecordingStarted();
+    method public void notifyRecordingStopped(android.net.Uri);
+    method public abstract void onConnect(android.net.Uri);
+    method public abstract void onDisconnect();
+    method public abstract void onStartRecording();
+    method public abstract void onStopRecording();
+  }
+
   public static abstract class TvInputService.Session implements android.view.KeyEvent.Callback {
     ctor public TvInputService.Session(android.content.Context);
     method public void layoutSurface(int, int, int, int);
@@ -22274,6 +22952,7 @@
     method public long onTimeShiftGetCurrentPosition();
     method public long onTimeShiftGetStartPosition();
     method public void onTimeShiftPause();
+    method public void onTimeShiftPlay(android.net.Uri);
     method public void onTimeShiftResume();
     method public void onTimeShiftSeekTo(long);
     method public void onTimeShiftSetPlaybackParams(android.media.PlaybackParams);
@@ -22284,6 +22963,23 @@
     method public void setOverlayViewEnabled(boolean);
   }
 
+  public class TvRecordingClient {
+    ctor public TvRecordingClient(android.content.Context, java.lang.String, android.media.tv.TvRecordingClient.RecordingCallback, android.os.Handler);
+    method public void connect(java.lang.String, android.net.Uri);
+    method public void disconnect();
+    method public void startRecording();
+    method public void stopRecording();
+  }
+
+  public class TvRecordingClient.RecordingCallback {
+    ctor public TvRecordingClient.RecordingCallback();
+    method public void onConnected();
+    method public void onDisconnected();
+    method public void onError(int);
+    method public void onRecordingStarted();
+    method public void onRecordingStopped(android.net.Uri);
+  }
+
   public final class TvTrackInfo implements android.os.Parcelable {
     method public int describeContents();
     method public final int getAudioChannelCount();
@@ -22335,6 +23031,7 @@
     method public void setStreamVolume(float);
     method public void setTimeShiftPositionCallback(android.media.tv.TvView.TimeShiftPositionCallback);
     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);
@@ -22374,6 +23071,24 @@
     ctor public MtpConstants();
     method public static boolean isAbstractObject(int);
     field public static final int ASSOCIATION_TYPE_GENERIC_FOLDER = 1; // 0x1
+    field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001
+    field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d
+    field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008
+    field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006
+    field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b
+    field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002
+    field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007
+    field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801
+    field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802
+    field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803
+    field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003
+    field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009
+    field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c
+    field public static final int EVENT_STORE_ADDED = 16388; // 0x4004
+    field public static final int EVENT_STORE_FULL = 16394; // 0x400a
+    field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005
+    field public static final int EVENT_UNDEFINED = 16384; // 0x4000
+    field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e
     field public static final int FORMAT_3GP_CONTAINER = 47492; // 0xb984
     field public static final int FORMAT_AAC = 47363; // 0xb903
     field public static final int FORMAT_ABSTRACT_AUDIO_ALBUM = 47619; // 0xba03
@@ -22392,6 +23107,8 @@
     field public static final int FORMAT_AUDIBLE = 47364; // 0xb904
     field public static final int FORMAT_AVI = 12298; // 0x300a
     field public static final int FORMAT_BMP = 14340; // 0x3804
+    field public static final int FORMAT_DEFINED = 14336; // 0x3800
+    field public static final int FORMAT_DNG = 14353; // 0x3811
     field public static final int FORMAT_DPOF = 12294; // 0x3006
     field public static final int FORMAT_EXECUTABLE = 12291; // 0x3003
     field public static final int FORMAT_EXIF_JPEG = 14337; // 0x3801
@@ -22430,6 +23147,42 @@
     field public static final int FORMAT_WMV = 47489; // 0xb981
     field public static final int FORMAT_WPL_PLAYLIST = 47632; // 0xba10
     field public static final int FORMAT_XML_DOCUMENT = 47746; // 0xba82
+    field public static final int OPERATION_CLOSE_SESSION = 4099; // 0x1003
+    field public static final int OPERATION_COPY_OBJECT = 4122; // 0x101a
+    field public static final int OPERATION_DELETE_OBJECT = 4107; // 0x100b
+    field public static final int OPERATION_FORMAT_STORE = 4111; // 0x100f
+    field public static final int OPERATION_GET_DEVICE_INFO = 4097; // 0x1001
+    field public static final int OPERATION_GET_DEVICE_PROP_DESC = 4116; // 0x1014
+    field public static final int OPERATION_GET_DEVICE_PROP_VALUE = 4117; // 0x1015
+    field public static final int OPERATION_GET_NUM_OBJECTS = 4102; // 0x1006
+    field public static final int OPERATION_GET_OBJECT = 4105; // 0x1009
+    field public static final int OPERATION_GET_OBJECT_HANDLES = 4103; // 0x1007
+    field public static final int OPERATION_GET_OBJECT_INFO = 4104; // 0x1008
+    field public static final int OPERATION_GET_OBJECT_PROPS_SUPPORTED = 38913; // 0x9801
+    field public static final int OPERATION_GET_OBJECT_PROP_DESC = 38914; // 0x9802
+    field public static final int OPERATION_GET_OBJECT_PROP_VALUE = 38915; // 0x9803
+    field public static final int OPERATION_GET_OBJECT_REFERENCES = 38928; // 0x9810
+    field public static final int OPERATION_GET_PARTIAL_OBJECT = 4123; // 0x101b
+    field public static final int OPERATION_GET_PARTIAL_OBJECT_64 = 38337; // 0x95c1
+    field public static final int OPERATION_GET_STORAGE_INFO = 4101; // 0x1005
+    field public static final int OPERATION_GET_STORAGE_I_DS = 4100; // 0x1004
+    field public static final int OPERATION_GET_THUMB = 4106; // 0x100a
+    field public static final int OPERATION_INITIATE_CAPTURE = 4110; // 0x100e
+    field public static final int OPERATION_INITIATE_OPEN_CAPTURE = 4124; // 0x101c
+    field public static final int OPERATION_MOVE_OBJECT = 4121; // 0x1019
+    field public static final int OPERATION_OPEN_SESSION = 4098; // 0x1002
+    field public static final int OPERATION_POWER_DOWN = 4115; // 0x1013
+    field public static final int OPERATION_RESET_DEVICE = 4112; // 0x1010
+    field public static final int OPERATION_RESET_DEVICE_PROP_VALUE = 4119; // 0x1017
+    field public static final int OPERATION_SELF_TEST = 4113; // 0x1011
+    field public static final int OPERATION_SEND_OBJECT = 4109; // 0x100d
+    field public static final int OPERATION_SEND_OBJECT_INFO = 4108; // 0x100c
+    field public static final int OPERATION_SET_DEVICE_PROP_VALUE = 4118; // 0x1016
+    field public static final int OPERATION_SET_OBJECT_PROP_VALUE = 38916; // 0x9804
+    field public static final int OPERATION_SET_OBJECT_PROTECTION = 4114; // 0x1012
+    field public static final int OPERATION_SET_OBJECT_REFERENCES = 38929; // 0x9811
+    field public static final int OPERATION_SKIP = 38944; // 0x9820
+    field public static final int OPERATION_TERMINATE_OPEN_CAPTURE = 4120; // 0x1018
     field public static final int PROTECTION_STATUS_NONE = 0; // 0x0
     field public static final int PROTECTION_STATUS_NON_TRANSFERABLE_DATA = 32771; // 0x8003
     field public static final int PROTECTION_STATUS_READ_ONLY = 32769; // 0x8001
@@ -22447,6 +23200,8 @@
     method public int[] getObjectHandles(int, int, int);
     method public android.mtp.MtpObjectInfo getObjectInfo(int);
     method public long getParent(int);
+    method public long getPartialObject(int, long, long, byte[]) throws java.io.IOException;
+    method public long getPartialObject64(int, long, long, byte[]) throws java.io.IOException;
     method public long getStorageId(int);
     method public int[] getStorageIds();
     method public android.mtp.MtpStorageInfo getStorageInfo(int);
@@ -22455,61 +23210,62 @@
     method public boolean importFile(int, android.os.ParcelFileDescriptor);
     method public boolean open(android.hardware.usb.UsbDeviceConnection);
     method public android.mtp.MtpEvent readEvent(android.os.CancellationSignal);
-    method public boolean sendObject(int, int, android.os.ParcelFileDescriptor);
+    method public boolean sendObject(int, long, android.os.ParcelFileDescriptor);
     method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo);
   }
 
   public class MtpDeviceInfo {
+    method public final int[] getEventsSupported();
     method public final java.lang.String getManufacturer();
     method public final java.lang.String getModel();
+    method public final int[] getOperationsSupported();
     method public final java.lang.String getSerialNumber();
     method public final java.lang.String getVersion();
   }
 
   public class MtpEvent {
     ctor public MtpEvent();
+    method public int getDevicePropCode();
     method public int getEventCode();
-    field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001
-    field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d
-    field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008
-    field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006
-    field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b
-    field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002
-    field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007
-    field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801
-    field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802
-    field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803
-    field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003
-    field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009
-    field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c
-    field public static final int EVENT_STORE_ADDED = 16388; // 0x4004
-    field public static final int EVENT_STORE_FULL = 16394; // 0x400a
-    field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005
-    field public static final int EVENT_UNDEFINED = 16384; // 0x4000
-    field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e
+    method public int getObjectFormatCode();
+    method public int getObjectHandle();
+    method public int getObjectPropCode();
+    method public int getParameter1();
+    method public int getParameter2();
+    method public int getParameter3();
+    method public int getStorageId();
+    method public int getTransactionId();
   }
 
   public final class MtpObjectInfo {
     method public final int getAssociationDesc();
     method public final int getAssociationType();
     method public final int getCompressedSize();
+    method public final long getCompressedSizeLong();
     method public final long getDateCreated();
     method public final long getDateModified();
     method public final int getFormat();
     method public final int getImagePixDepth();
+    method public final long getImagePixDepthLong();
     method public final int getImagePixHeight();
+    method public final long getImagePixHeightLong();
     method public final int getImagePixWidth();
+    method public final long getImagePixWidthLong();
     method public final java.lang.String getKeywords();
     method public final java.lang.String getName();
     method public final int getObjectHandle();
     method public final int getParent();
     method public final int getProtectionStatus();
     method public final int getSequenceNumber();
+    method public final long getSequenceNumberLong();
     method public final int getStorageId();
     method public final int getThumbCompressedSize();
+    method public final long getThumbCompressedSizeLong();
     method public final int getThumbFormat();
     method public final int getThumbPixHeight();
+    method public final long getThumbPixHeightLong();
     method public final int getThumbPixWidth();
+    method public final long getThumbPixWidthLong();
   }
 
   public static class MtpObjectInfo.Builder {
@@ -22518,24 +23274,24 @@
     method public android.mtp.MtpObjectInfo build();
     method public android.mtp.MtpObjectInfo.Builder setAssociationDesc(int);
     method public android.mtp.MtpObjectInfo.Builder setAssociationType(int);
-    method public android.mtp.MtpObjectInfo.Builder setCompressedSize(int);
+    method public android.mtp.MtpObjectInfo.Builder setCompressedSize(long);
     method public android.mtp.MtpObjectInfo.Builder setDateCreated(long);
     method public android.mtp.MtpObjectInfo.Builder setDateModified(long);
     method public android.mtp.MtpObjectInfo.Builder setFormat(int);
-    method public android.mtp.MtpObjectInfo.Builder setImagePixDepth(int);
-    method public android.mtp.MtpObjectInfo.Builder setImagePixHeight(int);
-    method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(int);
+    method public android.mtp.MtpObjectInfo.Builder setImagePixDepth(long);
+    method public android.mtp.MtpObjectInfo.Builder setImagePixHeight(long);
+    method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(long);
     method public android.mtp.MtpObjectInfo.Builder setKeywords(java.lang.String);
     method public android.mtp.MtpObjectInfo.Builder setName(java.lang.String);
     method public android.mtp.MtpObjectInfo.Builder setObjectHandle(int);
     method public android.mtp.MtpObjectInfo.Builder setParent(int);
     method public android.mtp.MtpObjectInfo.Builder setProtectionStatus(int);
-    method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(int);
+    method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(long);
     method public android.mtp.MtpObjectInfo.Builder setStorageId(int);
-    method public android.mtp.MtpObjectInfo.Builder setThumbCompressedSize(int);
+    method public android.mtp.MtpObjectInfo.Builder setThumbCompressedSize(long);
     method public android.mtp.MtpObjectInfo.Builder setThumbFormat(int);
-    method public android.mtp.MtpObjectInfo.Builder setThumbPixHeight(int);
-    method public android.mtp.MtpObjectInfo.Builder setThumbPixWidth(int);
+    method public android.mtp.MtpObjectInfo.Builder setThumbPixHeight(long);
+    method public android.mtp.MtpObjectInfo.Builder setThumbPixWidth(long);
   }
 
   public final class MtpStorageInfo {
@@ -22574,6 +23330,7 @@
     method public android.net.NetworkInfo getNetworkInfo(android.net.Network);
     method public deprecated int getNetworkPreference();
     method public static deprecated android.net.Network getProcessDefaultNetwork();
+    method public int getRestrictBackgroundStatus();
     method public boolean isActiveNetworkMetered();
     method public boolean isDefaultNetworkActive();
     method public static deprecated boolean isNetworkTypeValid(int);
@@ -22608,6 +23365,9 @@
     field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity";
     field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
     field public static final java.lang.String EXTRA_REASON = "reason";
+    field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
+    field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
+    field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
     field public static final int TYPE_BLUETOOTH = 7; // 0x7
     field public static final int TYPE_DUMMY = 8; // 0x8
     field public static final int TYPE_ETHERNET = 9; // 0x9
@@ -23647,6 +24407,7 @@
     method public java.lang.String getAltSubjectMatch();
     method public java.lang.String getAnonymousIdentity();
     method public java.security.cert.X509Certificate getCaCertificate();
+    method public java.security.cert.X509Certificate[] getCaCertificates();
     method public java.security.cert.X509Certificate getClientCertificate();
     method public java.lang.String getDomainSuffixMatch();
     method public int getEapMethod();
@@ -23659,6 +24420,7 @@
     method public void setAltSubjectMatch(java.lang.String);
     method public void setAnonymousIdentity(java.lang.String);
     method public void setCaCertificate(java.security.cert.X509Certificate);
+    method public void setCaCertificates(java.security.cert.X509Certificate[]);
     method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
     method public void setDomainSuffixMatch(java.lang.String);
     method public void setEapMethod(int);
@@ -24137,6 +24899,7 @@
 
   public final class Tag implements android.os.Parcelable {
     method public int describeContents();
+    method public boolean done(int);
     method public byte[] getId();
     method public java.lang.String[] getTechList();
     method public void writeToParcel(android.os.Parcel, int);
@@ -24187,6 +24950,28 @@
     field public static final java.lang.String SERVICE_META_DATA = "android.nfc.cardemulation.host_apdu_service";
   }
 
+  public abstract class HostNfcFService extends android.app.Service {
+    ctor public HostNfcFService();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public abstract void onDeactivated(int);
+    method public abstract byte[] processNfcFPacket(byte[], android.os.Bundle);
+    method public final void sendResponsePacket(byte[]);
+    field public static final int DEACTIVATION_LINK_LOSS = 0; // 0x0
+    field public static final java.lang.String SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_NFCF_SERVICE";
+    field public static final java.lang.String SERVICE_META_DATA = "android.nfc.cardemulation.host_nfcf_service";
+  }
+
+  public final class NfcFCardEmulation {
+    method public boolean disableNfcFForegroundService(android.app.Activity);
+    method public boolean enableNfcFForegroundService(android.app.Activity, android.content.ComponentName);
+    method public static synchronized android.nfc.cardemulation.NfcFCardEmulation getInstance(android.nfc.NfcAdapter);
+    method public java.lang.String getNfcid2ForService(android.content.ComponentName);
+    method public java.lang.String getSystemCodeForService(android.content.ComponentName);
+    method public boolean registerSystemCodeForService(android.content.ComponentName, java.lang.String);
+    method public boolean removeSystemCodeForService(android.content.ComponentName);
+    method public boolean setNfcid2ForService(android.content.ComponentName, java.lang.String);
+  }
+
   public abstract class OffHostApduService extends android.app.Service {
     ctor public OffHostApduService();
     method public abstract android.os.IBinder onBind(android.content.Intent);
@@ -26859,12 +27644,285 @@
     method public abstract void onMessage(int, int, int, int, java.lang.String);
   }
 
+  public class GLES32 extends android.opengl.GLES31 {
+    method public static void glBlendBarrier();
+    method public static void glBlendEquationSeparatei(int, int, int);
+    method public static void glBlendEquationi(int, int);
+    method public static void glBlendFuncSeparatei(int, int, int, int, int);
+    method public static void glBlendFunci(int, int, int);
+    method public static void glColorMaski(int, boolean, boolean, boolean, boolean);
+    method public static void glCopyImageSubData(int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
+    method public static void glDebugMessageCallback(android.opengl.GLES32.DebugProc);
+    method public static void glDebugMessageControl(int, int, int, int, int[], int, boolean);
+    method public static void glDebugMessageControl(int, int, int, int, java.nio.IntBuffer, boolean);
+    method public static void glDebugMessageInsert(int, int, int, int, int, java.lang.String);
+    method public static void glDisablei(int, int);
+    method public static void glDrawElementsBaseVertex(int, int, int, java.nio.Buffer, int);
+    method public static void glDrawElementsInstancedBaseVertex(int, int, int, java.nio.Buffer, int, int);
+    method public static void glDrawElementsInstancedBaseVertex(int, int, int, int, int, int);
+    method public static void glDrawRangeElementsBaseVertex(int, int, int, int, int, java.nio.Buffer, int);
+    method public static void glEnablei(int, int);
+    method public static void glFramebufferTexture(int, int, int, int);
+    method public static int glGetDebugMessageLog(int, int, int[], int, int[], int, int[], int, int[], int, int[], int, byte[], int);
+    method public static int glGetDebugMessageLog(int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.ByteBuffer);
+    method public static java.lang.String[] glGetDebugMessageLog(int, int[], int, int[], int, int[], int, int[], int);
+    method public static java.lang.String[] glGetDebugMessageLog(int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer);
+    method public static int glGetGraphicsResetStatus();
+    method public static java.lang.String glGetObjectLabel(int, int);
+    method public static java.lang.String glGetObjectPtrLabel(long);
+    method public static long glGetPointerv(int);
+    method public static void glGetSamplerParameterIiv(int, int, int[], int);
+    method public static void glGetSamplerParameterIiv(int, int, java.nio.IntBuffer);
+    method public static void glGetSamplerParameterIuiv(int, int, int[], int);
+    method public static void glGetSamplerParameterIuiv(int, int, java.nio.IntBuffer);
+    method public static void glGetTexParameterIiv(int, int, int[], int);
+    method public static void glGetTexParameterIiv(int, int, java.nio.IntBuffer);
+    method public static void glGetTexParameterIuiv(int, int, int[], int);
+    method public static void glGetTexParameterIuiv(int, int, java.nio.IntBuffer);
+    method public static void glGetnUniformfv(int, int, int, float[], int);
+    method public static void glGetnUniformfv(int, int, int, java.nio.FloatBuffer);
+    method public static void glGetnUniformiv(int, int, int, int[], int);
+    method public static void glGetnUniformiv(int, int, int, java.nio.IntBuffer);
+    method public static void glGetnUniformuiv(int, int, int, int[], int);
+    method public static void glGetnUniformuiv(int, int, int, java.nio.IntBuffer);
+    method public static boolean glIsEnabledi(int, int);
+    method public static void glMinSampleShading(float);
+    method public static void glObjectLabel(int, int, int, java.lang.String);
+    method public static void glObjectPtrLabel(long, java.lang.String);
+    method public static void glPatchParameteri(int, int);
+    method public static void glPopDebugGroup();
+    method public static void glPrimitiveBoundingBox(float, float, float, float, float, float, float, float);
+    method public static void glPushDebugGroup(int, int, int, java.lang.String);
+    method public static void glReadnPixels(int, int, int, int, int, int, int, java.nio.Buffer);
+    method public static void glSamplerParameterIiv(int, int, int[], int);
+    method public static void glSamplerParameterIiv(int, int, java.nio.IntBuffer);
+    method public static void glSamplerParameterIuiv(int, int, int[], int);
+    method public static void glSamplerParameterIuiv(int, int, java.nio.IntBuffer);
+    method public static void glTexBuffer(int, int, int);
+    method public static void glTexBufferRange(int, int, int, int, int);
+    method public static void glTexParameterIiv(int, int, int[], int);
+    method public static void glTexParameterIiv(int, int, java.nio.IntBuffer);
+    method public static void glTexParameterIuiv(int, int, int[], int);
+    method public static void glTexParameterIuiv(int, int, java.nio.IntBuffer);
+    method public static void glTexStorage3DMultisample(int, int, int, int, int, int, boolean);
+    field public static final int GL_BUFFER = 33504; // 0x82e0
+    field public static final int GL_CLAMP_TO_BORDER = 33069; // 0x812d
+    field public static final int GL_COLORBURN = 37530; // 0x929a
+    field public static final int GL_COLORDODGE = 37529; // 0x9299
+    field public static final int GL_COMPRESSED_RGBA_ASTC_10x10 = 37819; // 0x93bb
+    field public static final int GL_COMPRESSED_RGBA_ASTC_10x5 = 37816; // 0x93b8
+    field public static final int GL_COMPRESSED_RGBA_ASTC_10x6 = 37817; // 0x93b9
+    field public static final int GL_COMPRESSED_RGBA_ASTC_10x8 = 37818; // 0x93ba
+    field public static final int GL_COMPRESSED_RGBA_ASTC_12x10 = 37820; // 0x93bc
+    field public static final int GL_COMPRESSED_RGBA_ASTC_12x12 = 37821; // 0x93bd
+    field public static final int GL_COMPRESSED_RGBA_ASTC_4x4 = 37808; // 0x93b0
+    field public static final int GL_COMPRESSED_RGBA_ASTC_5x4 = 37809; // 0x93b1
+    field public static final int GL_COMPRESSED_RGBA_ASTC_5x5 = 37810; // 0x93b2
+    field public static final int GL_COMPRESSED_RGBA_ASTC_6x5 = 37811; // 0x93b3
+    field public static final int GL_COMPRESSED_RGBA_ASTC_6x6 = 37812; // 0x93b4
+    field public static final int GL_COMPRESSED_RGBA_ASTC_8x5 = 37813; // 0x93b5
+    field public static final int GL_COMPRESSED_RGBA_ASTC_8x6 = 37814; // 0x93b6
+    field public static final int GL_COMPRESSED_RGBA_ASTC_8x8 = 37815; // 0x93b7
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10 = 37851; // 0x93db
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5 = 37848; // 0x93d8
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6 = 37849; // 0x93d9
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8 = 37850; // 0x93da
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10 = 37852; // 0x93dc
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12 = 37853; // 0x93dd
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4 = 37840; // 0x93d0
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4 = 37841; // 0x93d1
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5 = 37842; // 0x93d2
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5 = 37843; // 0x93d3
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6 = 37844; // 0x93d4
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5 = 37845; // 0x93d5
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6 = 37846; // 0x93d6
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8 = 37847; // 0x93d7
+    field public static final int GL_CONTEXT_FLAGS = 33310; // 0x821e
+    field public static final int GL_CONTEXT_FLAG_DEBUG_BIT = 2; // 0x2
+    field public static final int GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT = 4; // 0x4
+    field public static final int GL_CONTEXT_LOST = 1287; // 0x507
+    field public static final int GL_DARKEN = 37527; // 0x9297
+    field public static final int GL_DEBUG_CALLBACK_FUNCTION = 33348; // 0x8244
+    field public static final int GL_DEBUG_CALLBACK_USER_PARAM = 33349; // 0x8245
+    field public static final int GL_DEBUG_GROUP_STACK_DEPTH = 33389; // 0x826d
+    field public static final int GL_DEBUG_LOGGED_MESSAGES = 37189; // 0x9145
+    field public static final int GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH = 33347; // 0x8243
+    field public static final int GL_DEBUG_OUTPUT = 37600; // 0x92e0
+    field public static final int GL_DEBUG_OUTPUT_SYNCHRONOUS = 33346; // 0x8242
+    field public static final int GL_DEBUG_SEVERITY_HIGH = 37190; // 0x9146
+    field public static final int GL_DEBUG_SEVERITY_LOW = 37192; // 0x9148
+    field public static final int GL_DEBUG_SEVERITY_MEDIUM = 37191; // 0x9147
+    field public static final int GL_DEBUG_SEVERITY_NOTIFICATION = 33387; // 0x826b
+    field public static final int GL_DEBUG_SOURCE_API = 33350; // 0x8246
+    field public static final int GL_DEBUG_SOURCE_APPLICATION = 33354; // 0x824a
+    field public static final int GL_DEBUG_SOURCE_OTHER = 33355; // 0x824b
+    field public static final int GL_DEBUG_SOURCE_SHADER_COMPILER = 33352; // 0x8248
+    field public static final int GL_DEBUG_SOURCE_THIRD_PARTY = 33353; // 0x8249
+    field public static final int GL_DEBUG_SOURCE_WINDOW_SYSTEM = 33351; // 0x8247
+    field public static final int GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR = 33357; // 0x824d
+    field public static final int GL_DEBUG_TYPE_ERROR = 33356; // 0x824c
+    field public static final int GL_DEBUG_TYPE_MARKER = 33384; // 0x8268
+    field public static final int GL_DEBUG_TYPE_OTHER = 33361; // 0x8251
+    field public static final int GL_DEBUG_TYPE_PERFORMANCE = 33360; // 0x8250
+    field public static final int GL_DEBUG_TYPE_POP_GROUP = 33386; // 0x826a
+    field public static final int GL_DEBUG_TYPE_PORTABILITY = 33359; // 0x824f
+    field public static final int GL_DEBUG_TYPE_PUSH_GROUP = 33385; // 0x8269
+    field public static final int GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR = 33358; // 0x824e
+    field public static final int GL_DIFFERENCE = 37534; // 0x929e
+    field public static final int GL_EXCLUSION = 37536; // 0x92a0
+    field public static final int GL_FIRST_VERTEX_CONVENTION = 36429; // 0x8e4d
+    field public static final int GL_FRACTIONAL_EVEN = 36476; // 0x8e7c
+    field public static final int GL_FRACTIONAL_ODD = 36475; // 0x8e7b
+    field public static final int GL_FRAGMENT_INTERPOLATION_OFFSET_BITS = 36445; // 0x8e5d
+    field public static final int GL_FRAMEBUFFER_ATTACHMENT_LAYERED = 36263; // 0x8da7
+    field public static final int GL_FRAMEBUFFER_DEFAULT_LAYERS = 37650; // 0x9312
+    field public static final int GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS = 36264; // 0x8da8
+    field public static final int GL_GEOMETRY_INPUT_TYPE = 35095; // 0x8917
+    field public static final int GL_GEOMETRY_OUTPUT_TYPE = 35096; // 0x8918
+    field public static final int GL_GEOMETRY_SHADER = 36313; // 0x8dd9
+    field public static final int GL_GEOMETRY_SHADER_BIT = 4; // 0x4
+    field public static final int GL_GEOMETRY_SHADER_INVOCATIONS = 34943; // 0x887f
+    field public static final int GL_GEOMETRY_VERTICES_OUT = 35094; // 0x8916
+    field public static final int GL_GUILTY_CONTEXT_RESET = 33363; // 0x8253
+    field public static final int GL_HARDLIGHT = 37531; // 0x929b
+    field public static final int GL_HSL_COLOR = 37551; // 0x92af
+    field public static final int GL_HSL_HUE = 37549; // 0x92ad
+    field public static final int GL_HSL_LUMINOSITY = 37552; // 0x92b0
+    field public static final int GL_HSL_SATURATION = 37550; // 0x92ae
+    field public static final int GL_IMAGE_BUFFER = 36945; // 0x9051
+    field public static final int GL_IMAGE_CUBE_MAP_ARRAY = 36948; // 0x9054
+    field public static final int GL_INNOCENT_CONTEXT_RESET = 33364; // 0x8254
+    field public static final int GL_INT_IMAGE_BUFFER = 36956; // 0x905c
+    field public static final int GL_INT_IMAGE_CUBE_MAP_ARRAY = 36959; // 0x905f
+    field public static final int GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 37132; // 0x910c
+    field public static final int GL_INT_SAMPLER_BUFFER = 36304; // 0x8dd0
+    field public static final int GL_INT_SAMPLER_CUBE_MAP_ARRAY = 36878; // 0x900e
+    field public static final int GL_ISOLINES = 36474; // 0x8e7a
+    field public static final int GL_IS_PER_PATCH = 37607; // 0x92e7
+    field public static final int GL_LAST_VERTEX_CONVENTION = 36430; // 0x8e4e
+    field public static final int GL_LAYER_PROVOKING_VERTEX = 33374; // 0x825e
+    field public static final int GL_LIGHTEN = 37528; // 0x9298
+    field public static final int GL_LINES_ADJACENCY = 10; // 0xa
+    field public static final int GL_LINE_STRIP_ADJACENCY = 11; // 0xb
+    field public static final int GL_LOSE_CONTEXT_ON_RESET = 33362; // 0x8252
+    field public static final int GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS = 35378; // 0x8a32
+    field public static final int GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS = 36382; // 0x8e1e
+    field public static final int GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS = 36383; // 0x8e1f
+    field public static final int GL_MAX_DEBUG_GROUP_STACK_DEPTH = 33388; // 0x826c
+    field public static final int GL_MAX_DEBUG_LOGGED_MESSAGES = 37188; // 0x9144
+    field public static final int GL_MAX_DEBUG_MESSAGE_LENGTH = 37187; // 0x9143
+    field public static final int GL_MAX_FRAGMENT_INTERPOLATION_OFFSET = 36444; // 0x8e5c
+    field public static final int GL_MAX_FRAMEBUFFER_LAYERS = 37655; // 0x9317
+    field public static final int GL_MAX_GEOMETRY_ATOMIC_COUNTERS = 37589; // 0x92d5
+    field public static final int GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS = 37583; // 0x92cf
+    field public static final int GL_MAX_GEOMETRY_IMAGE_UNIFORMS = 37069; // 0x90cd
+    field public static final int GL_MAX_GEOMETRY_INPUT_COMPONENTS = 37155; // 0x9123
+    field public static final int GL_MAX_GEOMETRY_OUTPUT_COMPONENTS = 37156; // 0x9124
+    field public static final int GL_MAX_GEOMETRY_OUTPUT_VERTICES = 36320; // 0x8de0
+    field public static final int GL_MAX_GEOMETRY_SHADER_INVOCATIONS = 36442; // 0x8e5a
+    field public static final int GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS = 37079; // 0x90d7
+    field public static final int GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS = 35881; // 0x8c29
+    field public static final int GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = 36321; // 0x8de1
+    field public static final int GL_MAX_GEOMETRY_UNIFORM_BLOCKS = 35372; // 0x8a2c
+    field public static final int GL_MAX_GEOMETRY_UNIFORM_COMPONENTS = 36319; // 0x8ddf
+    field public static final int GL_MAX_LABEL_LENGTH = 33512; // 0x82e8
+    field public static final int GL_MAX_PATCH_VERTICES = 36477; // 0x8e7d
+    field public static final int GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS = 37587; // 0x92d3
+    field public static final int GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS = 37581; // 0x92cd
+    field public static final int GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS = 37067; // 0x90cb
+    field public static final int GL_MAX_TESS_CONTROL_INPUT_COMPONENTS = 34924; // 0x886c
+    field public static final int GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS = 36483; // 0x8e83
+    field public static final int GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS = 37080; // 0x90d8
+    field public static final int GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS = 36481; // 0x8e81
+    field public static final int GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS = 36485; // 0x8e85
+    field public static final int GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS = 36489; // 0x8e89
+    field public static final int GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS = 36479; // 0x8e7f
+    field public static final int GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS = 37588; // 0x92d4
+    field public static final int GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS = 37582; // 0x92ce
+    field public static final int GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS = 37068; // 0x90cc
+    field public static final int GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS = 34925; // 0x886d
+    field public static final int GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS = 36486; // 0x8e86
+    field public static final int GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS = 37081; // 0x90d9
+    field public static final int GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS = 36482; // 0x8e82
+    field public static final int GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS = 36490; // 0x8e8a
+    field public static final int GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS = 36480; // 0x8e80
+    field public static final int GL_MAX_TESS_GEN_LEVEL = 36478; // 0x8e7e
+    field public static final int GL_MAX_TESS_PATCH_COMPONENTS = 36484; // 0x8e84
+    field public static final int GL_MAX_TEXTURE_BUFFER_SIZE = 35883; // 0x8c2b
+    field public static final int GL_MIN_FRAGMENT_INTERPOLATION_OFFSET = 36443; // 0x8e5b
+    field public static final int GL_MIN_SAMPLE_SHADING_VALUE = 35895; // 0x8c37
+    field public static final int GL_MULTIPLY = 37524; // 0x9294
+    field public static final int GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY = 37762; // 0x9382
+    field public static final int GL_MULTISAMPLE_LINE_WIDTH_RANGE = 37761; // 0x9381
+    field public static final int GL_NO_RESET_NOTIFICATION = 33377; // 0x8261
+    field public static final int GL_OVERLAY = 37526; // 0x9296
+    field public static final int GL_PATCHES = 14; // 0xe
+    field public static final int GL_PATCH_VERTICES = 36466; // 0x8e72
+    field public static final int GL_PRIMITIVES_GENERATED = 35975; // 0x8c87
+    field public static final int GL_PRIMITIVE_BOUNDING_BOX = 37566; // 0x92be
+    field public static final int GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED = 33313; // 0x8221
+    field public static final int GL_PROGRAM = 33506; // 0x82e2
+    field public static final int GL_PROGRAM_PIPELINE = 33508; // 0x82e4
+    field public static final int GL_QUADS = 7; // 0x7
+    field public static final int GL_QUERY = 33507; // 0x82e3
+    field public static final int GL_REFERENCED_BY_GEOMETRY_SHADER = 37641; // 0x9309
+    field public static final int GL_REFERENCED_BY_TESS_CONTROL_SHADER = 37639; // 0x9307
+    field public static final int GL_REFERENCED_BY_TESS_EVALUATION_SHADER = 37640; // 0x9308
+    field public static final int GL_RESET_NOTIFICATION_STRATEGY = 33366; // 0x8256
+    field public static final int GL_SAMPLER = 33510; // 0x82e6
+    field public static final int GL_SAMPLER_2D_MULTISAMPLE_ARRAY = 37131; // 0x910b
+    field public static final int GL_SAMPLER_BUFFER = 36290; // 0x8dc2
+    field public static final int GL_SAMPLER_CUBE_MAP_ARRAY = 36876; // 0x900c
+    field public static final int GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW = 36877; // 0x900d
+    field public static final int GL_SAMPLE_SHADING = 35894; // 0x8c36
+    field public static final int GL_SCREEN = 37525; // 0x9295
+    field public static final int GL_SHADER = 33505; // 0x82e1
+    field public static final int GL_SOFTLIGHT = 37532; // 0x929c
+    field public static final int GL_STACK_OVERFLOW = 1283; // 0x503
+    field public static final int GL_STACK_UNDERFLOW = 1284; // 0x504
+    field public static final int GL_TESS_CONTROL_OUTPUT_VERTICES = 36469; // 0x8e75
+    field public static final int GL_TESS_CONTROL_SHADER = 36488; // 0x8e88
+    field public static final int GL_TESS_CONTROL_SHADER_BIT = 8; // 0x8
+    field public static final int GL_TESS_EVALUATION_SHADER = 36487; // 0x8e87
+    field public static final int GL_TESS_EVALUATION_SHADER_BIT = 16; // 0x10
+    field public static final int GL_TESS_GEN_MODE = 36470; // 0x8e76
+    field public static final int GL_TESS_GEN_POINT_MODE = 36473; // 0x8e79
+    field public static final int GL_TESS_GEN_SPACING = 36471; // 0x8e77
+    field public static final int GL_TESS_GEN_VERTEX_ORDER = 36472; // 0x8e78
+    field public static final int GL_TEXTURE_2D_MULTISAMPLE_ARRAY = 37122; // 0x9102
+    field public static final int GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY = 37125; // 0x9105
+    field public static final int GL_TEXTURE_BINDING_BUFFER = 35884; // 0x8c2c
+    field public static final int GL_TEXTURE_BINDING_CUBE_MAP_ARRAY = 36874; // 0x900a
+    field public static final int GL_TEXTURE_BORDER_COLOR = 4100; // 0x1004
+    field public static final int GL_TEXTURE_BUFFER = 35882; // 0x8c2a
+    field public static final int GL_TEXTURE_BUFFER_BINDING = 35882; // 0x8c2a
+    field public static final int GL_TEXTURE_BUFFER_DATA_STORE_BINDING = 35885; // 0x8c2d
+    field public static final int GL_TEXTURE_BUFFER_OFFSET = 37277; // 0x919d
+    field public static final int GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT = 37279; // 0x919f
+    field public static final int GL_TEXTURE_BUFFER_SIZE = 37278; // 0x919e
+    field public static final int GL_TEXTURE_CUBE_MAP_ARRAY = 36873; // 0x9009
+    field public static final int GL_TRIANGLES_ADJACENCY = 12; // 0xc
+    field public static final int GL_TRIANGLE_STRIP_ADJACENCY = 13; // 0xd
+    field public static final int GL_UNDEFINED_VERTEX = 33376; // 0x8260
+    field public static final int GL_UNKNOWN_CONTEXT_RESET = 33365; // 0x8255
+    field public static final int GL_UNSIGNED_INT_IMAGE_BUFFER = 36967; // 0x9067
+    field public static final int GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY = 36970; // 0x906a
+    field public static final int GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 37133; // 0x910d
+    field public static final int GL_UNSIGNED_INT_SAMPLER_BUFFER = 36312; // 0x8dd8
+    field public static final int GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY = 36879; // 0x900f
+    field public static final int GL_VERTEX_ARRAY = 32884; // 0x8074
+  }
+
+  public static abstract interface GLES32.DebugProc {
+    method public abstract void onMessage(int, int, int, int, java.lang.String);
+  }
+
   public class GLException extends java.lang.RuntimeException {
     ctor public GLException(int);
     ctor public GLException(int, java.lang.String);
   }
 
-  public class GLSurfaceView extends android.view.SurfaceView implements android.view.SurfaceHolder.Callback {
+  public class GLSurfaceView extends android.view.SurfaceView implements android.view.SurfaceHolder.Callback2 {
     ctor public GLSurfaceView(android.content.Context);
     ctor public GLSurfaceView(android.content.Context, android.util.AttributeSet);
     method public int getDebugFlags();
@@ -26888,6 +27946,7 @@
     method public void surfaceChanged(android.view.SurfaceHolder, int, int, int);
     method public void surfaceCreated(android.view.SurfaceHolder);
     method public void surfaceDestroyed(android.view.SurfaceHolder);
+    method public void surfaceRedrawNeeded(android.view.SurfaceHolder);
     field public static final int DEBUG_CHECK_GL_ERROR = 1; // 0x1
     field public static final int DEBUG_LOG_GL_CALLS = 2; // 0x2
     field public static final int RENDERMODE_CONTINUOUSLY = 1; // 0x1
@@ -27269,6 +28328,14 @@
     method public final synchronized android.os.CountDownTimer start();
   }
 
+  public final class CpuUsageInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getActive();
+    method public long getTotal();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.os.CpuUsageInfo> CREATOR;
+  }
+
   public class DeadObjectException extends android.os.RemoteException {
     ctor public DeadObjectException();
     ctor public DeadObjectException(java.lang.String);
@@ -27521,6 +28588,18 @@
     method public boolean quitSafely();
   }
 
+  public class HardwarePropertiesManager {
+    method public android.os.CpuUsageInfo[] getCpuUsages();
+    method public float[] getDeviceTemperatures(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 {
+  }
+
   public abstract interface IBinder {
     method public abstract void dump(java.io.FileDescriptor, java.lang.String[]) throws android.os.RemoteException;
     method public abstract void dumpAsync(java.io.FileDescriptor, java.lang.String[]) throws android.os.RemoteException;
@@ -27890,6 +28969,7 @@
     field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
     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
   }
 
   public final class PowerManager.WakeLock {
@@ -28095,6 +29175,7 @@
   }
 
   public class UserManager {
+    method public static android.content.Intent createUserCreationIntent(java.lang.String, java.lang.String, java.lang.String, android.os.PersistableBundle);
     method public android.os.Bundle getApplicationRestrictions(java.lang.String);
     method public long getSerialNumberForUser(android.os.UserHandle);
     method public int getUserCount();
@@ -28133,6 +29214,7 @@
     field public static final java.lang.String DISALLOW_CONFIG_WIFI = "no_config_wifi";
     field public static final java.lang.String DISALLOW_CREATE_WINDOWS = "no_create_windows";
     field public static final java.lang.String DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste";
+    field public static final java.lang.String DISALLOW_DATA_ROAMING = "no_data_roaming";
     field public static final java.lang.String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features";
     field public static final java.lang.String DISALLOW_FACTORY_RESET = "no_factory_reset";
     field public static final java.lang.String DISALLOW_FUN = "no_fun";
@@ -28145,6 +29227,7 @@
     field public static final java.lang.String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls";
     field public static final java.lang.String DISALLOW_REMOVE_USER = "no_remove_user";
     field public static final java.lang.String DISALLOW_SAFE_BOOT = "no_safe_boot";
+    field public static final java.lang.String DISALLOW_SET_USER_ICON = "no_set_user_icon";
     field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location";
     field public static final java.lang.String DISALLOW_SMS = "no_sms";
     field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
@@ -28152,6 +29235,8 @@
     field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
     field public static final java.lang.String ENSURE_VERIFY_APPS = "ensure_verify_apps";
     field public static final java.lang.String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
+    field public static final int USER_CREATION_FAILED_NOT_PERMITTED = 1; // 0x1
+    field public static final int USER_CREATION_FAILED_NO_MORE_USERS = 2; // 0x2
   }
 
   public abstract class Vibrator {
@@ -28509,6 +29594,8 @@
     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();
     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";
   }
@@ -28878,6 +29965,9 @@
     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 setIconResourceId(int);
+    method public android.print.PrinterInfo.Builder setInfoIntent(android.app.PendingIntent);
     method public android.print.PrinterInfo.Builder setName(java.lang.String);
     method public android.print.PrinterInfo.Builder setStatus(int);
   }
@@ -28898,6 +29988,10 @@
 
 package android.printservice {
 
+  public class CustomPrinterIconCallback {
+    method public boolean onCustomPrinterIconLoaded(android.graphics.drawable.Icon);
+  }
+
   public final class PrintDocument {
     method public android.os.ParcelFileDescriptor getData();
     method public android.print.PrintDocumentInfo getInfo();
@@ -28953,6 +30047,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 abstract void onStartPrinterDiscovery(java.util.List<android.print.PrinterId>);
     method public abstract void onStartPrinterStateTracking(android.print.PrinterId);
     method public abstract void onStopPrinterDiscovery();
@@ -28995,6 +30090,22 @@
     field public static final java.lang.String _ID = "_id";
   }
 
+  public class BlockedNumberContract {
+    method public static boolean isBlocked(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;
+  }
+
+  public static class BlockedNumberContract.BlockedNumbers {
+    field public static final java.lang.String COLUMN_E164_NUMBER = "e164_number";
+    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 COLUMN_STRIPPED_NUMBER = "stripped_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 android.net.Uri CONTENT_URI;
+  }
+
   public class Browser {
     ctor public Browser();
     method public static final void sendString(android.content.Context, java.lang.String);
@@ -29321,6 +30432,7 @@
     field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location";
     field public static final int INCOMING_TYPE = 1; // 0x1
     field public static final java.lang.String IS_READ = "is_read";
+    field public static final java.lang.String LAST_MODIFIED = "last_modified";
     field public static final java.lang.String LIMIT_PARAM_KEY = "limit";
     field public static final int MISSED_TYPE = 3; // 0x3
     field public static final java.lang.String NEW = "new";
@@ -30216,10 +31328,14 @@
 
   public static final class ContactsContract.Intents {
     ctor public ContactsContract.Intents();
+    field public static final java.lang.String ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS = "android.provider.action.VOICE_SEND_MESSAGE_TO_CONTACTS";
     field public static final java.lang.String ATTACH_IMAGE = "com.android.contacts.action.ATTACH_IMAGE";
     field public static final java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
     field public static final java.lang.String EXTRA_CREATE_DESCRIPTION = "com.android.contacts.action.CREATE_DESCRIPTION";
     field public static final java.lang.String EXTRA_FORCE_CREATE = "com.android.contacts.action.FORCE_CREATE";
+    field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_CHAT_ID = "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
+    field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_NAME = "android.provider.extra.RECIPIENT_CONTACT_NAME";
+    field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_URI = "android.provider.extra.RECIPIENT_CONTACT_URI";
     field public static final java.lang.String INVITE_CONTACT = "com.android.contacts.action.INVITE_CONTACT";
     field public static final java.lang.String SEARCH_SUGGESTION_CLICKED = "android.provider.Contacts.SEARCH_SUGGESTION_CLICKED";
     field public static final java.lang.String SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED = "android.provider.Contacts.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED";
@@ -30465,6 +31581,7 @@
     method public static android.net.Uri buildRootsUri(java.lang.String);
     method public static android.net.Uri buildSearchDocumentsUri(java.lang.String, java.lang.String, java.lang.String);
     method public static android.net.Uri buildTreeDocumentUri(java.lang.String, java.lang.String);
+    method public static android.net.Uri copyDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri);
     method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);
     method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri);
     method public static java.lang.String getDocumentId(android.net.Uri);
@@ -30473,6 +31590,9 @@
     method public static java.lang.String getSearchDocumentsQuery(android.net.Uri);
     method public static java.lang.String getTreeDocumentId(android.net.Uri);
     method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
+    method public static boolean isTreeUri(android.net.Uri);
+    method public static android.net.Uri moveDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri, android.net.Uri);
+    method public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri);
     method public static android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String);
     field public static final java.lang.String EXTRA_ERROR = "error";
     field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
@@ -30491,18 +31611,18 @@
     field public static final java.lang.String COLUMN_MIME_TYPE = "mime_type";
     field public static final java.lang.String COLUMN_SIZE = "_size";
     field public static final java.lang.String COLUMN_SUMMARY = "summary";
-    field public static final int FLAG_ARCHIVE = 2048; // 0x800
+    field public static final int FLAG_ARCHIVE = 1024; // 0x400
     field public static final int FLAG_DIR_PREFERS_GRID = 16; // 0x10
     field public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 32; // 0x20
     field public static final int FLAG_DIR_SUPPORTS_CREATE = 8; // 0x8
     field public static final int FLAG_SUPPORTS_COPY = 128; // 0x80
     field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4
     field public static final int FLAG_SUPPORTS_MOVE = 256; // 0x100
+    field public static final int FLAG_SUPPORTS_REMOVE = 2048; // 0x800
     field public static final int FLAG_SUPPORTS_RENAME = 64; // 0x40
     field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
-    field public static final int FLAG_SUPPORTS_TYPED_DOCUMENT = 512; // 0x200
     field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
-    field public static final int FLAG_VIRTUAL_DOCUMENT = 1024; // 0x400
+    field public static final int FLAG_VIRTUAL_DOCUMENT = 512; // 0x200
     field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory";
   }
 
@@ -30546,6 +31666,7 @@
     method public android.database.Cursor queryRecentDocuments(java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
     method public abstract android.database.Cursor queryRoots(java.lang.String[]) throws java.io.FileNotFoundException;
     method public android.database.Cursor querySearchDocuments(java.lang.String, java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
+    method public boolean removeDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public java.lang.String renameDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public final void revokeDocumentPermission(java.lang.String);
     method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
@@ -30925,10 +32046,12 @@
     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";
     field public static final java.lang.String ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS";
+    field public static final java.lang.String ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS";
     field public static final java.lang.String ACTION_MANAGE_OVERLAY_PERMISSION = "android.settings.action.MANAGE_OVERLAY_PERMISSION";
     field public static final java.lang.String ACTION_MANAGE_WRITE_SETTINGS = "android.settings.action.MANAGE_WRITE_SETTINGS";
     field public static final java.lang.String ACTION_MEMORY_CARD_SETTINGS = "android.settings.MEMORY_CARD_SETTINGS";
@@ -30945,6 +32068,7 @@
     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";
+    field public static final java.lang.String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
     field public static final java.lang.String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
     field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
     field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
@@ -30991,6 +32115,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 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";
     field public static final java.lang.String DEBUG_APP = "debug_app";
@@ -31583,6 +32708,7 @@
   public class VoicemailContract {
     field public static final java.lang.String ACTION_FETCH_VOICEMAIL = "android.intent.action.FETCH_VOICEMAIL";
     field public static final java.lang.String ACTION_NEW_VOICEMAIL = "android.intent.action.NEW_VOICEMAIL";
+    field public static final java.lang.String ACTION_SYNC_VOICEMAIL = "android.intent.action.SYNC_VOICEMAIL";
     field public static final java.lang.String AUTHORITY = "com.android.voicemail";
     field public static final java.lang.String EXTRA_SELF_CHANGE = "com.android.voicemail.extra.SELF_CHANGE";
     field public static final java.lang.String PARAM_KEY_SOURCE_PACKAGE = "source_package";
@@ -31590,14 +32716,20 @@
 
   public static final class VoicemailContract.Status implements android.provider.BaseColumns {
     method public static android.net.Uri buildSourceUri(java.lang.String);
+    method public static void setQuota(android.content.Context, android.telecom.PhoneAccountHandle, int, int);
     field public static final java.lang.String CONFIGURATION_STATE = "configuration_state";
     field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2
     field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1
     field public static final int CONFIGURATION_STATE_OK = 0; // 0x0
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String DATA_CHANNEL_STATE = "data_channel_state";
+    field public static final int DATA_CHANNEL_STATE_BAD_CONFIGURATION = 3; // 0x3
+    field public static final int DATA_CHANNEL_STATE_COMMUNICATION_ERROR = 4; // 0x4
     field public static final int DATA_CHANNEL_STATE_NO_CONNECTION = 1; // 0x1
+    field public static final int DATA_CHANNEL_STATE_NO_CONNECTION_CELLULAR_REQUIRED = 2; // 0x2
     field public static final int DATA_CHANNEL_STATE_OK = 0; // 0x0
+    field public static final int DATA_CHANNEL_STATE_SERVER_CONNECTION_ERROR = 6; // 0x6
+    field public static final int DATA_CHANNEL_STATE_SERVER_ERROR = 5; // 0x5
     field public static final java.lang.String DIR_TYPE = "vnd.android.cursor.dir/voicemail.source.status";
     field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail.source.status";
     field public static final java.lang.String NOTIFICATION_CHANNEL_STATE = "notification_channel_state";
@@ -31606,6 +32738,9 @@
     field public static final int NOTIFICATION_CHANNEL_STATE_OK = 0; // 0x0
     field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "phone_account_component_name";
     field public static final java.lang.String PHONE_ACCOUNT_ID = "phone_account_id";
+    field public static final java.lang.String QUOTA_OCCUPIED = "quota_occupied";
+    field public static final java.lang.String QUOTA_TOTAL = "quota_total";
+    field public static final int QUOTA_UNAVAILABLE = -1; // 0xffffffff
     field public static final java.lang.String SETTINGS_URI = "settings_uri";
     field public static final java.lang.String SOURCE_PACKAGE = "source_package";
     field public static final java.lang.String VOICEMAIL_ACCESS_URI = "voicemail_access_uri";
@@ -31622,6 +32757,7 @@
     field public static final java.lang.String HAS_CONTENT = "has_content";
     field public static final java.lang.String IS_READ = "is_read";
     field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail";
+    field public static final java.lang.String LAST_MODIFIED = "last_modified";
     field public static final java.lang.String MIME_TYPE = "mime_type";
     field public static final java.lang.String NUMBER = "number";
     field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
@@ -31691,6 +32827,7 @@
     method public void copyTo(short[]);
     method public void copyTo(int[]);
     method public void copyTo(float[]);
+    method public static android.renderscript.Allocation[] createAllocations(android.renderscript.RenderScript, android.renderscript.Type, int, int);
     method public static android.renderscript.Allocation createCubemapFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap, android.renderscript.Allocation.MipmapControl, int);
     method public static android.renderscript.Allocation createCubemapFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap);
     method public static android.renderscript.Allocation createCubemapFromCubeFaces(android.renderscript.RenderScript, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.renderscript.Allocation.MipmapControl, int);
@@ -31706,9 +32843,12 @@
     method public static android.renderscript.Allocation createTyped(android.renderscript.RenderScript, android.renderscript.Type, int);
     method public static android.renderscript.Allocation createTyped(android.renderscript.RenderScript, android.renderscript.Type);
     method public void generateMipmaps();
+    method public java.nio.ByteBuffer getByteBuffer();
     method public int getBytesSize();
     method public android.renderscript.Element getElement();
+    method public long getStride();
     method public android.view.Surface getSurface();
+    method public long getTimeStamp();
     method public android.renderscript.Type getType();
     method public int getUsage();
     method public void ioReceive();
@@ -32292,6 +33432,7 @@
     method public void getVarV(int, android.renderscript.FieldPacker);
     method protected void invoke(int);
     method protected void invoke(int, android.renderscript.FieldPacker);
+    method protected void reduce(int, android.renderscript.Allocation[], android.renderscript.Allocation, android.renderscript.Script.LaunchOptions);
     method public void setTimeZone(java.lang.String);
     method public void setVar(int, float);
     method public void setVar(int, double);
@@ -32813,6 +33954,7 @@
   public class NetworkSecurityPolicy {
     method public static android.security.NetworkSecurityPolicy getInstance();
     method public boolean isCleartextTrafficPermitted();
+    method public boolean isCleartextTrafficPermitted(java.lang.String);
   }
 
 }
@@ -33107,6 +34249,7 @@
     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();
@@ -33141,9 +34284,11 @@
     method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
     method public android.media.session.MediaSession.Token getSessionToken();
     method public void notifyChildrenChanged(java.lang.String);
+    method public void notifyChildrenChanged(java.lang.String, android.os.Bundle);
     method public android.os.IBinder onBind(android.content.Intent);
     method public abstract android.service.media.MediaBrowserService.BrowserRoot onGetRoot(java.lang.String, int, android.os.Bundle);
     method public abstract void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>);
+    method public void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>, android.os.Bundle);
     method public void onLoadItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>);
     method public void setSessionToken(android.media.session.MediaSession.Token);
     field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
@@ -33201,6 +34346,7 @@
     method public abstract void onUnsubscribe(android.net.Uri);
     field public static final java.lang.String EXTRA_RULE_ID = "android.content.automatic.ruleId";
     field public static final java.lang.String META_DATA_CONFIGURATION_ACTIVITY = "android.service.zen.automatic.configurationActivity";
+    field public static final java.lang.String META_DATA_RULE_INSTANCE_LIMIT = "android.service.zen.automatic.ruleInstanceLimit";
     field public static final java.lang.String META_DATA_RULE_TYPE = "android.service.zen.automatic.ruleType";
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
   }
@@ -33227,7 +34373,10 @@
     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 = 15; // 0xf
+    field public static final int REASON_TOPIC_BANNED = 14; // 0xe
     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 {
@@ -33256,7 +34405,10 @@
     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 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
@@ -33266,6 +34418,7 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
     field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
     field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+    field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
   }
 
   public static class NotificationListenerService.Ranking {
@@ -33322,25 +34475,37 @@
     method public java.lang.CharSequence getContentDescription();
     method public android.graphics.drawable.Icon getIcon();
     method public java.lang.CharSequence getLabel();
+    method public int getState();
     method public void setContentDescription(java.lang.CharSequence);
     method public void setIcon(android.graphics.drawable.Icon);
     method public void setLabel(java.lang.CharSequence);
+    method public void setState(int);
     method public void updateTile();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.quicksettings.Tile> CREATOR;
+    field public static final int STATE_ACTIVE = 2; // 0x2
+    field public static final int STATE_INACTIVE = 1; // 0x1
+    field public static final int STATE_UNAVAILABLE = 0; // 0x0
   }
 
   public class TileService extends android.app.Service {
     ctor public TileService();
     method public final android.service.quicksettings.Tile getQsTile();
+    method public final boolean isLocked();
+    method public final boolean isSecure();
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onClick();
     method public void onStartListening();
     method public void onStopListening();
-    method public void onTileAdded();
+    method public int onTileAdded();
     method public void onTileRemoved();
+    method public static final void requestListeningState(android.content.Context, android.content.ComponentName);
     method public final void showDialog(android.app.Dialog);
+    method public final void startActivityAndCollapse(android.content.Intent);
+    method public final void unlockAndRun(java.lang.Runnable);
     field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+    field public static final int TILE_MODE_ACTIVE = 2; // 0x2
+    field public static final int TILE_MODE_PASSIVE = 1; // 0x1
   }
 
 }
@@ -33472,6 +34637,7 @@
     method public void setTheme(int);
     method public void show(android.os.Bundle, int);
     method public void startVoiceActivity(android.content.Intent);
+    field public static final int SHOW_SOURCE_ACTIVITY = 16; // 0x10
     field public static final int SHOW_SOURCE_APPLICATION = 8; // 0x8
     field public static final int SHOW_SOURCE_ASSIST_GESTURE = 4; // 0x4
     field public static final int SHOW_WITH_ASSIST = 1; // 0x1
@@ -33833,6 +34999,8 @@
 
   public abstract class UtteranceProgressListener {
     ctor public UtteranceProgressListener();
+    method public void onAudioAvailable(java.lang.String, byte[]);
+    method public void onBeginSynthesis(java.lang.String, int, int, int);
     method public abstract void onDone(java.lang.String);
     method public abstract deprecated void onError(java.lang.String);
     method public void onError(java.lang.String, int);
@@ -34580,6 +35748,7 @@
     method public static boolean hasProperty(int, int);
     method public boolean hasProperty(int);
     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_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
     field public static final int CAPABILITY_HOLD = 1; // 0x1
@@ -34601,6 +35770,7 @@
     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_WIFI = 8; // 0x8
+    field public static final int PROPERTY_WORK_CALL = 32; // 0x20
   }
 
   public final class CallAudioState implements android.os.Parcelable {
@@ -34619,6 +35789,30 @@
     field public static final int ROUTE_WIRED_OR_EARPIECE = 5; // 0x5
   }
 
+  public abstract class CallScreeningService extends android.app.Service {
+    ctor public CallScreeningService();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public abstract void onScreenCall(android.telecom.Call.Details);
+    method public final void respondToCall(android.telecom.Call.Details, android.telecom.CallScreeningService.CallResponse);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.CallScreeningService";
+  }
+
+  public static class CallScreeningService.CallResponse {
+    method public boolean getDisallowCall();
+    method public boolean getRejectCall();
+    method public boolean getSkipCallLog();
+    method public boolean getSkipNotification();
+  }
+
+  public static class CallScreeningService.CallResponse.Builder {
+    ctor public CallScreeningService.CallResponse.Builder();
+    method public android.telecom.CallScreeningService.CallResponse build();
+    method public android.telecom.CallScreeningService.CallResponse.Builder setDisallowCall(boolean);
+    method public android.telecom.CallScreeningService.CallResponse.Builder setRejectCall(boolean);
+    method public android.telecom.CallScreeningService.CallResponse.Builder setSkipCallLog(boolean);
+    method public android.telecom.CallScreeningService.CallResponse.Builder setSkipNotification(boolean);
+  }
+
   public abstract class Conference extends android.telecom.Conferenceable {
     ctor public Conference(android.telecom.PhoneAccountHandle);
     method public final boolean addConnection(android.telecom.Connection);
@@ -34719,6 +35913,7 @@
     method public final void setVideoProvider(android.telecom.Connection.VideoProvider);
     method public final void setVideoState(int);
     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_UPGRADE_TO_VIDEO = 524288; // 0x80000
     field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
@@ -34857,6 +36052,7 @@
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
     method public void onCallRemoved(android.telecom.Call);
     method public void onCanAddCallChanged(boolean);
+    method public void onSilenceRinger();
     method public final void setAudioRoute(int);
     method public final void setMuted(boolean);
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.InCallService";
@@ -35098,6 +36294,7 @@
     field public static final java.lang.String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL";
     field public static final java.lang.String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS = "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS";
     field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
+    field public static final java.lang.String ACTION_SHOW_MISSED_CALLS_NOTIFICATION = "android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION";
     field public static final java.lang.String ACTION_SHOW_RESPOND_VIA_SMS_SETTINGS = "android.telecom.action.SHOW_RESPOND_VIA_SMS_SETTINGS";
     field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
     field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
@@ -35108,12 +36305,15 @@
     field public static final java.lang.String EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME = "android.telecom.extra.CHANGE_DEFAULT_DIALER_PACKAGE_NAME";
     field public static final java.lang.String EXTRA_INCOMING_CALL_ADDRESS = "android.telecom.extra.INCOMING_CALL_ADDRESS";
     field public static final java.lang.String EXTRA_INCOMING_CALL_EXTRAS = "android.telecom.extra.INCOMING_CALL_EXTRAS";
+    field public static final java.lang.String EXTRA_NOTIFICATION_COUNT = "android.telecom.extra.NOTIFICATION_COUNT";
+    field public static final java.lang.String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
     field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
     field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
     field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
     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_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
     field public static final int PRESENTATION_PAYPHONE = 4; // 0x4
@@ -35165,12 +36365,24 @@
     method public android.os.PersistableBundle getConfigForSubId(int);
     method public 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_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";
     field public static final java.lang.String KEY_APN_EXPAND_BOOL = "apn_expand_bool";
     field public static final java.lang.String KEY_AUTO_RETRY_ENABLED_BOOL = "auto_retry_enabled_bool";
     field public static final java.lang.String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL = "carrier_allow_turnoff_ims_bool";
+    field public static final java.lang.String KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL = "carrier_force_disable_etws_cmas_test_bool";
+    field public static final java.lang.String KEY_CARRIER_IMS_GBA_REQUIRED_BOOL = "carrier_ims_gba_required_bool";
+    field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL = "carrier_instant_lettering_available_bool";
+    field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_ENCODING_STRING = "carrier_instant_lettering_encoding_string";
+    field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_ESCAPED_CHARS_STRING = "carrier_instant_lettering_escaped_chars_string";
+    field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_INVALID_CHARS_STRING = "carrier_instant_lettering_invalid_chars_string";
+    field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_LENGTH_LIMIT_INT = "carrier_instant_lettering_length_limit_int";
     field public static final java.lang.String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
     field public static final java.lang.String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
@@ -35179,20 +36391,30 @@
     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_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";
+    field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_BOOL = "ci_action_on_sys_update_bool";
+    field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING = "ci_action_on_sys_update_extra_string";
+    field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING = "ci_action_on_sys_update_extra_val_string";
+    field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING = "ci_action_on_sys_update_intent_string";
     field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
     field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
     field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
     field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
+    field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
     field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
     field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
+    field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
     field public static final java.lang.String KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = "gsm_nonroaming_networks_string_array";
     field public static final java.lang.String KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY = "gsm_roaming_networks_string_array";
     field public static final java.lang.String KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL = "has_in_call_noise_suppression_bool";
     field public static final java.lang.String KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool";
+    field public static final java.lang.String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool";
+    field public static final java.lang.String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool";
     field public static final java.lang.String KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool";
     field public static final java.lang.String KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL = "ignore_sim_network_locked_events_bool";
+    field public static final java.lang.String KEY_IMS_DTMF_TONE_DELAY_INT = "ims_dtmf_tone_delay_int";
     field public static final java.lang.String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled";
     field public static final java.lang.String KEY_MMS_ALIAS_MAX_CHARS_INT = "aliasMaxChars";
     field public static final java.lang.String KEY_MMS_ALIAS_MIN_CHARS_INT = "aliasMinChars";
@@ -35226,20 +36448,24 @@
     field public static final java.lang.String KEY_MMS_USER_AGENT_STRING = "userAgent";
     field public static final java.lang.String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool";
     field public static final java.lang.String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
+    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_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";
     field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
     field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
     field public static final java.lang.String KEY_USE_HFA_FOR_PROVISIONING_BOOL = "use_hfa_for_provisioning_bool";
     field public static final java.lang.String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool";
+    field public static final java.lang.String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
     field public static final java.lang.String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool";
     field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
     field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
     field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN = "vvm_cellular_data_required";
     field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
     field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
+    field public static final java.lang.String KEY_VVM_PREFETCH_BOOLEAN = "vvm_prefetch";
     field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
     field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
   }
@@ -35257,6 +36483,8 @@
 
   public final class CellIdentityGsm implements android.os.Parcelable {
     method public int describeContents();
+    method public int getArfcn();
+    method public int getBsic();
     method public int getCid();
     method public int getLac();
     method public int getMcc();
@@ -35269,6 +36497,7 @@
   public final class CellIdentityLte implements android.os.Parcelable {
     method public int describeContents();
     method public int getCi();
+    method public int getEarfcn();
     method public int getMcc();
     method public int getMnc();
     method public int getPci();
@@ -35284,6 +36513,7 @@
     method public int getMcc();
     method public int getMnc();
     method public int getPsc();
+    method public int getUarfcn();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityWcdma> CREATOR;
   }
@@ -35705,10 +36935,15 @@
     method public int getActiveSubscriptionInfoCountMax();
     method public android.telephony.SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int);
     method public java.util.List<android.telephony.SubscriptionInfo> getActiveSubscriptionInfoList();
+    method public static int getDefaultDataSubscriptionId();
+    method public static int getDefaultSmsSubscriptionId();
+    method public static int getDefaultSubscriptionId();
+    method public static int getDefaultVoiceSubscriptionId();
     method public boolean isNetworkRoaming(int);
     method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
     field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
     field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
+    field public static final int INVALID_SUBSCRIPTION_ID = -1; // 0xffffffff
   }
 
   public static class SubscriptionManager.OnSubscriptionsChangedListener {
@@ -35720,31 +36955,50 @@
     method public boolean canChangeDtmfToneLength();
     method public java.util.List<android.telephony.CellInfo> getAllCellInfo();
     method public int getCallState();
+    method public int getCallState(int);
     method public android.telephony.CellLocation getCellLocation();
     method public int getDataActivity();
+    method public int getDataNetworkType(int);
     method public int getDataState();
     method public java.lang.String getDeviceId();
     method public java.lang.String getDeviceId(int);
     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 getLine1AlphaTag(int);
     method public java.lang.String getLine1Number();
+    method public java.lang.String getLine1Number(int);
     method public java.lang.String getMmsUAProfUrl();
     method public java.lang.String getMmsUserAgent();
     method public deprecated java.util.List<android.telephony.NeighboringCellInfo> getNeighboringCellInfo();
     method public java.lang.String getNetworkCountryIso();
+    method public java.lang.String getNetworkCountryIso(int);
     method public java.lang.String getNetworkOperator();
+    method public java.lang.String getNetworkOperator(int);
     method public java.lang.String getNetworkOperatorName();
+    method public java.lang.String getNetworkOperatorName(int);
     method public int getNetworkType();
+    method public int getNetworkType(int);
     method public int getPhoneCount();
     method public int getPhoneType();
     method public java.lang.String getSimCountryIso();
+    method public java.lang.String getSimCountryIso(int);
     method public java.lang.String getSimOperator();
+    method public java.lang.String getSimOperator(int);
     method public java.lang.String getSimOperatorName();
+    method public java.lang.String getSimOperatorName(int);
     method public java.lang.String getSimSerialNumber();
+    method public java.lang.String getSimSerialNumber(int);
     method public int getSimState();
     method public java.lang.String getSubscriberId();
+    method public java.lang.String getSubscriberId(int);
     method public java.lang.String getVoiceMailAlphaTag();
+    method public java.lang.String getVoiceMailAlphaTag(int);
     method public java.lang.String getVoiceMailNumber();
+    method public java.lang.String getVoiceMailNumber(int);
+    method public int getVoiceNetworkType(int);
+    method public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle);
     method public boolean hasCarrierPrivileges();
     method public boolean hasIccCard();
     method public boolean iccCloseLogicalChannel(int);
@@ -35754,16 +37008,20 @@
     method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
     method public boolean isHearingAidCompatibilitySupported();
     method public boolean isNetworkRoaming();
+    method public boolean isNetworkRoaming(int);
     method public boolean isSmsCapable();
     method public boolean isTtyModeSupported();
     method public boolean isVoiceCapable();
+    method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle);
     method public boolean isWorldPhone();
     method public void listen(android.telephony.PhoneStateListener, int);
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
     method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
+    method public boolean setLine1NumberForDisplay(int, java.lang.String, java.lang.String);
     method public boolean setOperatorBrandOverride(java.lang.String);
     method public boolean setPreferredNetworkTypeToGlobal();
     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";
@@ -35933,7 +37191,7 @@
     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public abstract class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
+  public abstract deprecated class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
     ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>);
     ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>);
     method public T getActivity();
@@ -35941,14 +37199,14 @@
     method public void setActivityIntent(android.content.Intent);
   }
 
-  public abstract class ActivityTestCase extends android.test.InstrumentationTestCase {
+  public abstract deprecated class ActivityTestCase extends android.test.InstrumentationTestCase {
     ctor public ActivityTestCase();
     method protected android.app.Activity getActivity();
     method protected void scrubClass(java.lang.Class<?>) throws java.lang.IllegalAccessException;
     method protected void setActivity(android.app.Activity);
   }
 
-  public abstract class ActivityUnitTestCase extends android.test.ActivityTestCase {
+  public abstract deprecated class ActivityUnitTestCase extends android.test.ActivityTestCase {
     ctor public ActivityUnitTestCase(java.lang.Class<T>);
     method public T getActivity();
     method public int getFinishedActivityRequest();
@@ -35961,7 +37219,7 @@
     method protected T startActivity(android.content.Intent, android.os.Bundle, java.lang.Object);
   }
 
-  public class AndroidTestCase extends junit.framework.TestCase {
+  public deprecated class AndroidTestCase extends junit.framework.TestCase {
     ctor public AndroidTestCase();
     method public void assertActivityRequiresPermission(java.lang.String, java.lang.String, java.lang.String);
     method public void assertReadingContentUriRequiresPermission(android.net.Uri, java.lang.String);
@@ -35973,7 +37231,7 @@
     field protected android.content.Context mContext;
   }
 
-  public class AndroidTestRunner extends junit.runner.BaseTestRunner {
+  public deprecated class AndroidTestRunner extends junit.runner.BaseTestRunner {
     ctor public AndroidTestRunner();
     method public void addTestListener(junit.framework.TestListener);
     method public void clearTestListeners();
@@ -35994,7 +37252,7 @@
     method public void testStarted(java.lang.String);
   }
 
-  public abstract class ApplicationTestCase extends android.test.AndroidTestCase {
+  public abstract deprecated class ApplicationTestCase extends android.test.AndroidTestCase {
     ctor public ApplicationTestCase(java.lang.Class<T>);
     method protected final void createApplication();
     method public T getApplication();
@@ -36012,10 +37270,10 @@
     ctor public ComparisonFailure(java.lang.String, java.lang.String, java.lang.String);
   }
 
-  public abstract class FlakyTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class FlakyTest implements java.lang.annotation.Annotation {
   }
 
-  public class InstrumentationTestCase extends junit.framework.TestCase {
+  public deprecated class InstrumentationTestCase extends junit.framework.TestCase {
     ctor public InstrumentationTestCase();
     method public android.app.Instrumentation getInstrumentation();
     method public deprecated void injectInsrumentation(android.app.Instrumentation);
@@ -36028,7 +37286,7 @@
     method public void sendRepeatedKeys(int...);
   }
 
-  public class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider {
+  public deprecated class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider {
     ctor public InstrumentationTestRunner();
     method public junit.framework.TestSuite getAllTests();
     method protected android.test.AndroidTestRunner getAndroidTestRunner();
@@ -36047,14 +37305,14 @@
     field public static final int REPORT_VALUE_RESULT_START = 1; // 0x1
   }
 
-  public class InstrumentationTestSuite extends junit.framework.TestSuite {
+  public deprecated class InstrumentationTestSuite extends junit.framework.TestSuite {
     ctor public InstrumentationTestSuite(android.app.Instrumentation);
     ctor public InstrumentationTestSuite(java.lang.String, android.app.Instrumentation);
     ctor public InstrumentationTestSuite(java.lang.Class, android.app.Instrumentation);
     method public void addTestSuite(java.lang.Class);
   }
 
-  public class IsolatedContext extends android.content.ContextWrapper {
+  public deprecated class IsolatedContext extends android.content.ContextWrapper {
     ctor public IsolatedContext(android.content.ContentResolver, android.content.Context);
     method public java.util.List<android.content.Intent> getAndClearBroadcastIntents();
   }
@@ -36064,7 +37322,7 @@
     method public T getLoaderResultSynchronously(android.content.Loader<T>);
   }
 
-  public final class MoreAsserts {
+  public final deprecated class MoreAsserts {
     method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Object);
     method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Class<?>);
     method public static java.util.regex.MatchResult assertContainsRegex(java.lang.String, java.lang.String, java.lang.String);
@@ -36103,7 +37361,7 @@
     method public static void checkEqualsAndHashCodeMethods(java.lang.Object, java.lang.Object, boolean);
   }
 
-  public abstract interface PerformanceTestCase {
+  public abstract deprecated interface PerformanceTestCase {
     method public abstract boolean isPerformanceOnly();
     method public abstract int startPerformance(android.test.PerformanceTestCase.Intermediates);
   }
@@ -36132,7 +37390,7 @@
     method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
-  public class RenamingDelegatingContext extends android.content.ContextWrapper {
+  public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper {
     ctor public RenamingDelegatingContext(android.content.Context, java.lang.String);
     ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String);
     method public java.lang.String getDatabasePrefix();
@@ -36141,7 +37399,7 @@
     method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
-  public abstract class ServiceTestCase extends android.test.AndroidTestCase {
+  public abstract deprecated class ServiceTestCase extends android.test.AndroidTestCase {
     ctor public ServiceTestCase(java.lang.Class<T>);
     method protected android.os.IBinder bindService(android.content.Intent);
     method public android.app.Application getApplication();
@@ -36154,23 +37412,23 @@
     method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public abstract class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
+  public abstract deprecated class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
     ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>);
     method public T getActivity();
     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public class SyncBaseInstrumentation extends android.test.InstrumentationTestCase {
+  public deprecated class SyncBaseInstrumentation extends android.test.InstrumentationTestCase {
     ctor public SyncBaseInstrumentation();
     method protected void cancelSyncsandDisableAutoSync();
     method protected void syncProvider(android.net.Uri, java.lang.String, java.lang.String) throws java.lang.Exception;
   }
 
-  public abstract interface TestSuiteProvider {
+  public abstract deprecated interface TestSuiteProvider {
     method public abstract junit.framework.TestSuite getTestSuite();
   }
 
-  public class TouchUtils {
+  public deprecated class TouchUtils {
     ctor public TouchUtils();
     method public static void clickView(android.test.InstrumentationTestCase, android.view.View);
     method public static deprecated void drag(android.test.ActivityInstrumentationTestCase, float, float, float, float, int);
@@ -36205,10 +37463,10 @@
     method public static void touchAndCancelView(android.test.InstrumentationTestCase, android.view.View);
   }
 
-  public abstract class UiThreadTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class UiThreadTest implements java.lang.annotation.Annotation {
   }
 
-  public class ViewAsserts {
+  public deprecated class ViewAsserts {
     method public static void assertBaselineAligned(android.view.View, android.view.View);
     method public static void assertBottomAligned(android.view.View, android.view.View);
     method public static void assertBottomAligned(android.view.View, android.view.View, int);
@@ -36233,11 +37491,11 @@
 
 package android.test.mock {
 
-  public class MockApplication extends android.app.Application {
+  public deprecated class MockApplication extends android.app.Application {
     ctor public MockApplication();
   }
 
-  public class MockContentProvider extends android.content.ContentProvider {
+  public deprecated class MockContentProvider extends android.content.ContentProvider {
     ctor protected MockContentProvider();
     ctor public MockContentProvider(android.content.Context);
     ctor public MockContentProvider(android.content.Context, java.lang.String, java.lang.String, android.content.pm.PathPermission[]);
@@ -36249,13 +37507,13 @@
     method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
   }
 
-  public class MockContentResolver extends android.content.ContentResolver {
+  public deprecated class MockContentResolver extends android.content.ContentResolver {
     ctor public MockContentResolver();
     ctor public MockContentResolver(android.content.Context);
     method public void addProvider(java.lang.String, android.content.ContentProvider);
   }
 
-  public class MockContext extends android.content.Context {
+  public deprecated class MockContext extends android.content.Context {
     ctor public MockContext();
     method public boolean bindService(android.content.Intent, android.content.ServiceConnection, int);
     method public int checkCallingOrSelfPermission(java.lang.String);
@@ -36355,7 +37613,7 @@
     method public void unregisterReceiver(android.content.BroadcastReceiver);
   }
 
-  public class MockCursor implements android.database.Cursor {
+  public deprecated class MockCursor implements android.database.Cursor {
     ctor public MockCursor();
     method public void close();
     method public void copyStringToBuffer(int, android.database.CharArrayBuffer);
@@ -36400,13 +37658,13 @@
     method public void unregisterDataSetObserver(android.database.DataSetObserver);
   }
 
-  public class MockDialogInterface implements android.content.DialogInterface {
+  public deprecated class MockDialogInterface implements android.content.DialogInterface {
     ctor public MockDialogInterface();
     method public void cancel();
     method public void dismiss();
   }
 
-  public class MockPackageManager extends android.content.pm.PackageManager {
+  public deprecated class MockPackageManager extends android.content.pm.PackageManager {
     ctor public MockPackageManager();
     method public void addPackageToPreferred(java.lang.String);
     method public boolean addPermission(android.content.pm.PermissionInfo);
@@ -36439,10 +37697,7 @@
     method public android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public int getComponentEnabledSetting(android.content.ComponentName);
     method public android.graphics.drawable.Drawable getDefaultActivityIcon();
-    method public java.lang.String getDefaultBrowserPackageName(int);
     method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
-    method public byte[] getEphemeralCookie();
-    method public int getEphemeralCookieMaxSizeBytes();
     method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
     method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
     method public java.lang.String getInstallerPackageName(java.lang.String);
@@ -36451,8 +37706,10 @@
     method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public java.lang.String getNameForUid(int);
     method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInstaller getPackageInstaller();
+    method public int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] getPackagesForUid(int);
     method public java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int);
     method public android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -36473,7 +37730,6 @@
     method public java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle);
     method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
     method public boolean hasSystemFeature(java.lang.String);
-    method public boolean isEphemeralApplication();
     method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
     method public boolean isSafeMode();
     method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
@@ -36491,13 +37747,11 @@
     method public android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
     method public void setApplicationEnabledSetting(java.lang.String, int, int);
     method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
-    method public boolean setDefaultBrowserPackageName(java.lang.String, int);
-    method public boolean setEphemeralCookie(byte[]);
     method public void setInstallerPackageName(java.lang.String, java.lang.String);
     method public void verifyPendingInstall(int, int);
   }
 
-  public class MockResources extends android.content.res.Resources {
+  public deprecated class MockResources extends android.content.res.Resources {
     ctor public MockResources();
   }
 
@@ -36538,19 +37792,19 @@
 
 package android.test.suitebuilder.annotation {
 
-  public abstract class LargeTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class LargeTest implements java.lang.annotation.Annotation {
   }
 
-  public abstract class MediumTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class MediumTest implements java.lang.annotation.Annotation {
   }
 
-  public abstract class SmallTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class SmallTest implements java.lang.annotation.Annotation {
   }
 
-  public abstract class Smoke implements java.lang.annotation.Annotation {
+  public abstract deprecated class Smoke implements java.lang.annotation.Annotation {
   }
 
-  public abstract class Suppress implements java.lang.annotation.Annotation {
+  public abstract deprecated class Suppress implements java.lang.annotation.Annotation {
   }
 
 }
@@ -36696,9 +37950,23 @@
 
   public class Html {
     method public static java.lang.String escapeHtml(java.lang.CharSequence);
-    method public static android.text.Spanned fromHtml(java.lang.String);
-    method public static android.text.Spanned fromHtml(java.lang.String, android.text.Html.ImageGetter, android.text.Html.TagHandler);
-    method public static java.lang.String toHtml(android.text.Spanned);
+    method public static deprecated android.text.Spanned fromHtml(java.lang.String);
+    method public static android.text.Spanned fromHtml(java.lang.String, int);
+    method public static deprecated android.text.Spanned fromHtml(java.lang.String, android.text.Html.ImageGetter, android.text.Html.TagHandler);
+    method public static android.text.Spanned fromHtml(java.lang.String, int, android.text.Html.ImageGetter, android.text.Html.TagHandler);
+    method public static deprecated java.lang.String toHtml(android.text.Spanned);
+    method public static java.lang.String toHtml(android.text.Spanned, int);
+    field public static final int FROM_HTML_MODE_COMPACT = 63; // 0x3f
+    field public static final int FROM_HTML_MODE_LEGACY = 0; // 0x0
+    field public static final int FROM_HTML_OPTION_USE_CSS_COLORS = 256; // 0x100
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_BLOCKQUOTE = 32; // 0x20
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_DIV = 16; // 0x10
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_HEADING = 2; // 0x2
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST = 8; // 0x8
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM = 4; // 0x4
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH = 1; // 0x1
+    field public static final int TO_HTML_PARAGRAPH_LINES_CONSECUTIVE = 0; // 0x0
+    field public static final int TO_HTML_PARAGRAPH_LINES_INDIVIDUAL = 1; // 0x1
   }
 
   public static abstract interface Html.ImageGetter {
@@ -37695,9 +38963,11 @@
 
   public class LocaleSpan extends android.text.style.MetricAffectingSpan implements android.text.ParcelableSpan {
     ctor public LocaleSpan(java.util.Locale);
+    ctor public LocaleSpan(android.util.LocaleList);
     ctor public LocaleSpan(android.os.Parcel);
     method public int describeContents();
     method public java.util.Locale getLocale();
+    method public android.util.LocaleList getLocales();
     method public int getSpanTypeId();
     method public void updateDrawState(android.text.TextPaint);
     method public void updateMeasureState(android.text.TextPaint);
@@ -37803,7 +39073,8 @@
     ctor public SuggestionSpan(android.os.Parcel);
     method public int describeContents();
     method public int getFlags();
-    method public java.lang.String getLocale();
+    method public deprecated java.lang.String getLocale();
+    method public java.util.Locale getLocaleObject();
     method public int getSpanTypeId();
     method public java.lang.String[] getSuggestions();
     method public void setFlags(int);
@@ -38723,7 +39994,9 @@
     method public static android.util.LocaleList getEmptyLocaleList();
     method public java.util.Locale getFirstMatch(java.lang.String[]);
     method public java.util.Locale getPrimary();
+    method public int indexOf(java.util.Locale);
     method public boolean isEmpty();
+    method public static void setDefault(android.util.LocaleList);
     method public int size();
     method public java.lang.String toLanguageTags();
     method public void writeToParcel(android.os.Parcel, int);
@@ -38881,7 +40154,7 @@
     method public static final java.lang.String digitsAndPlusOnly(java.util.regex.Matcher);
     field public static final java.util.regex.Pattern DOMAIN_NAME;
     field public static final java.util.regex.Pattern EMAIL_ADDRESS;
-    field public static final java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
+    field public static final deprecated java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
     field public static final java.util.regex.Pattern IP_ADDRESS;
     field public static final java.util.regex.Pattern PHONE;
     field public static final deprecated java.util.regex.Pattern TOP_LEVEL_DOMAIN;
@@ -39312,7 +40585,6 @@
     method public int getAction();
     method public android.content.ClipData getClipData();
     method public android.content.ClipDescription getClipDescription();
-    method public android.view.DropPermissionHolder getDropPermissionHolder();
     method public java.lang.Object getLocalState();
     method public boolean getResult();
     method public float getX();
@@ -39327,12 +40599,8 @@
     field public static final android.os.Parcelable.Creator<android.view.DragEvent> CREATOR;
   }
 
-  public class DropPermissionHolder implements android.os.Parcelable {
-    method public int describeContents();
-    method public void grant();
-    method public void revoke();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.view.DropPermissionHolder> CREATOR;
+  public final class DropPermissions {
+    method public void release();
   }
 
   public class FocusFinder {
@@ -39990,6 +41258,27 @@
     method public void startTracking(android.view.KeyEvent, java.lang.Object);
   }
 
+  public final class KeyboardShortcutGroup implements android.os.Parcelable {
+    ctor public KeyboardShortcutGroup(java.lang.CharSequence, java.util.List<android.view.KeyboardShortcutInfo>);
+    ctor public KeyboardShortcutGroup(java.lang.CharSequence);
+    method public void addItem(android.view.KeyboardShortcutInfo);
+    method public int describeContents();
+    method public java.util.List<android.view.KeyboardShortcutInfo> getItems();
+    method public java.lang.CharSequence getLabel();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.KeyboardShortcutGroup> CREATOR;
+  }
+
+  public final class KeyboardShortcutInfo implements android.os.Parcelable {
+    ctor public KeyboardShortcutInfo(java.lang.CharSequence, char, int);
+    method public int describeContents();
+    method public char getBaseCharacter();
+    method public java.lang.CharSequence getLabel();
+    method public int getModifiers();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.KeyboardShortcutInfo> CREATOR;
+  }
+
   public abstract class LayoutInflater {
     ctor protected LayoutInflater(android.content.Context);
     ctor protected LayoutInflater(android.view.LayoutInflater, android.content.Context);
@@ -40258,12 +41547,13 @@
     field public static final int AXIS_LTRIGGER = 17; // 0x11
     field public static final int AXIS_ORIENTATION = 8; // 0x8
     field public static final int AXIS_PRESSURE = 2; // 0x2
+    field public static final int AXIS_RELATIVE_X = 27; // 0x1b
+    field public static final int AXIS_RELATIVE_Y = 28; // 0x1c
     field public static final int AXIS_RTRIGGER = 18; // 0x12
     field public static final int AXIS_RUDDER = 20; // 0x14
     field public static final int AXIS_RX = 12; // 0xc
     field public static final int AXIS_RY = 13; // 0xd
     field public static final int AXIS_RZ = 14; // 0xe
-    field public static final int AXIS_SCROLL = 26; // 0x1a
     field public static final int AXIS_SIZE = 3; // 0x3
     field public static final int AXIS_THROTTLE = 19; // 0x13
     field public static final int AXIS_TILT = 25; // 0x19
@@ -40793,6 +42083,7 @@
     method public boolean hasNestedScrollingParent();
     method public boolean hasOnClickListeners();
     method public boolean hasOverlappingRendering();
+    method public boolean hasPointerCapture();
     method public boolean hasTransientState();
     method public boolean hasWindowFocus();
     method public static android.view.View inflate(android.content.Context, int, android.view.ViewGroup);
@@ -40919,6 +42210,7 @@
     method public void postOnAnimation(java.lang.Runnable);
     method public void postOnAnimationDelayed(java.lang.Runnable, long);
     method public void refreshDrawableState();
+    method public void releasePointerCapture();
     method public boolean removeCallbacks(java.lang.Runnable);
     method public void removeOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
     method public void removeOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
@@ -41019,6 +42311,7 @@
     method public void setPaddingRelative(int, int, int, int);
     method public void setPivotX(float);
     method public void setPivotY(float);
+    method public void setPointerCapture();
     method public void setPointerIcon(android.view.PointerIcon);
     method public void setPressed(boolean);
     method public final void setRight(int);
@@ -41987,6 +43280,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 abstract boolean onSearchRequested();
     method public abstract boolean onSearchRequested(android.view.SearchEvent);
     method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
@@ -42312,6 +43606,7 @@
     method public android.view.accessibility.AccessibilityNodeInfo.CollectionInfo getCollectionInfo();
     method public android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo getCollectionItemInfo();
     method public java.lang.CharSequence getContentDescription();
+    method public int getDrawingOrder();
     method public java.lang.CharSequence getError();
     method public android.os.Bundle getExtras();
     method public int getInputType();
@@ -42374,6 +43669,7 @@
     method public void setContentInvalid(boolean);
     method public void setContextClickable(boolean);
     method public void setDismissable(boolean);
+    method public void setDrawingOrder(int);
     method public void setEditable(boolean);
     method public void setEnabled(boolean);
     method public void setError(java.lang.CharSequence);
@@ -42930,6 +44226,7 @@
     method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public boolean commitText(java.lang.CharSequence, int);
     method public boolean deleteSurroundingText(int, int);
+    method public boolean deleteSurroundingTextInCodePoints(int, int);
     method public boolean endBatchEdit();
     method public boolean finishComposingText();
     method public static int getComposingSpanEnd(android.text.Spannable);
@@ -43037,6 +44334,7 @@
     field public android.os.Bundle extras;
     field public int fieldId;
     field public java.lang.String fieldName;
+    field public android.util.LocaleList hintLocales;
     field public java.lang.CharSequence hintText;
     field public int imeOptions;
     field public int initialCapsMode;
@@ -43044,7 +44342,6 @@
     field public int initialSelStart;
     field public int inputType;
     field public java.lang.CharSequence label;
-    field public android.util.LocaleList locales;
     field public java.lang.String packageName;
     field public java.lang.String privateImeOptions;
   }
@@ -43095,6 +44392,7 @@
     method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public abstract boolean commitText(java.lang.CharSequence, int);
     method public abstract boolean deleteSurroundingText(int, int);
+    method public abstract boolean deleteSurroundingTextInCodePoints(int, int);
     method public abstract boolean endBatchEdit();
     method public abstract boolean finishComposingText();
     method public abstract int getCursorCapsMode(int);
@@ -43125,6 +44423,7 @@
     method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public boolean commitText(java.lang.CharSequence, int);
     method public boolean deleteSurroundingText(int, int);
+    method public boolean deleteSurroundingTextInCodePoints(int, int);
     method public boolean endBatchEdit();
     method public boolean finishComposingText();
     method public int getCursorCapsMode(int);
@@ -43187,6 +44486,7 @@
   }
 
   public final class InputMethodManager {
+    method public void dispatchKeyEventFromInputMethod(android.view.View, android.view.KeyEvent);
     method public void displayCompletions(android.view.View, android.view.inputmethod.CompletionInfo[]);
     method public android.view.inputmethod.InputMethodSubtype getCurrentInputMethodSubtype();
     method public java.util.List<android.view.inputmethod.InputMethodInfo> getEnabledInputMethodList();
@@ -43518,6 +44818,30 @@
     method public abstract android.view.View getFullScreenView(int, android.content.Context);
   }
 
+  public class ServiceWorkerClient {
+    ctor public ServiceWorkerClient();
+    method public android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebResourceRequest);
+  }
+
+  public abstract class ServiceWorkerController {
+    ctor public ServiceWorkerController();
+    method public static android.webkit.ServiceWorkerController getInstance();
+    method public abstract android.webkit.ServiceWorkerWebSettings getServiceWorkerWebSettings();
+    method public abstract void setServiceWorkerClient(android.webkit.ServiceWorkerClient);
+  }
+
+  public abstract class ServiceWorkerWebSettings {
+    ctor public ServiceWorkerWebSettings();
+    method public abstract boolean getAllowContentAccess();
+    method public abstract boolean getAllowFileAccess();
+    method public abstract boolean getBlockNetworkLoads();
+    method public abstract int getCacheMode();
+    method public abstract void setAllowContentAccess(boolean);
+    method public abstract void setAllowFileAccess(boolean);
+    method public abstract void setBlockNetworkLoads(boolean);
+    method public abstract void setCacheMode(int);
+  }
+
   public class SslErrorHandler extends android.os.Handler {
     method public void cancel();
     method public void proceed();
@@ -43747,7 +45071,7 @@
     method public abstract deprecated void setEnableSmoothTransition(boolean);
     method public abstract void setFantasyFontFamily(java.lang.String);
     method public abstract void setFixedFontFamily(java.lang.String);
-    method public abstract void setGeolocationDatabasePath(java.lang.String);
+    method public abstract deprecated void setGeolocationDatabasePath(java.lang.String);
     method public abstract void setGeolocationEnabled(boolean);
     method public abstract void setJavaScriptCanOpenWindowsAutomatically(boolean);
     method public abstract void setJavaScriptEnabled(boolean);
@@ -44189,12 +45513,18 @@
     method public int getThumbOffset();
     method public android.content.res.ColorStateList getThumbTintList();
     method public android.graphics.PorterDuff.Mode getThumbTintMode();
+    method public android.graphics.drawable.Drawable getTickMark();
+    method public android.content.res.ColorStateList getTickMarkTintList();
+    method public android.graphics.PorterDuff.Mode getTickMarkTintMode();
     method public void setKeyProgressIncrement(int);
     method public void setSplitTrack(boolean);
     method public void setThumb(android.graphics.drawable.Drawable);
     method public void setThumbOffset(int);
     method public void setThumbTintList(android.content.res.ColorStateList);
     method public void setThumbTintMode(android.graphics.PorterDuff.Mode);
+    method public void setTickMark(android.graphics.drawable.Drawable);
+    method public void setTickMarkTintList(android.content.res.ColorStateList);
+    method public void setTickMarkTintMode(android.graphics.PorterDuff.Mode);
   }
 
   public abstract class AbsSpinner extends android.widget.AdapterView {
@@ -45151,6 +46481,7 @@
     method public int getBaselineAlignedChildIndex();
     method public android.graphics.drawable.Drawable getDividerDrawable();
     method public int getDividerPadding();
+    method public int getGravity();
     method public int getOrientation();
     method public int getShowDividers();
     method public float getWeightSum();
@@ -46281,6 +47612,7 @@
     method public int getHyphenationFrequency();
     method public int getImeActionId();
     method public java.lang.CharSequence getImeActionLabel();
+    method public android.util.LocaleList getImeHintLocales();
     method public int getImeOptions();
     method public boolean getIncludeFontPadding();
     method public android.os.Bundle getInputExtras(boolean);
@@ -46387,6 +47719,7 @@
     method public void setHorizontallyScrolling(boolean);
     method public void setHyphenationFrequency(int);
     method public void setImeActionLabel(java.lang.CharSequence, int);
+    method public void setImeHintLocales(android.util.LocaleList);
     method public void setImeOptions(int);
     method public void setIncludeFontPadding(boolean);
     method public void setInputExtras(int) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -47340,10 +48673,8 @@
   }
 
   public final class Console implements java.io.Flushable {
-    method public static java.io.Console console();
     method public void flush();
     method public java.io.Console format(java.lang.String, java.lang.Object...);
-    method public static synchronized java.io.Console getConsole();
     method public java.io.Console printf(java.lang.String, java.lang.Object...);
     method public java.lang.String readLine(java.lang.String, java.lang.Object...);
     method public java.lang.String readLine();
@@ -47486,7 +48817,6 @@
     method public boolean setReadable(boolean);
     method public boolean setWritable(boolean, boolean);
     method public boolean setWritable(boolean);
-    method public java.nio.file.Path toPath();
     method public java.net.URI toURI();
     method public deprecated java.net.URL toURL() throws java.net.MalformedURLException;
     field public static final java.lang.String pathSeparator;
@@ -47627,7 +48957,6 @@
   public class InterruptedIOException extends java.io.IOException {
     ctor public InterruptedIOException();
     ctor public InterruptedIOException(java.lang.String);
-    ctor public InterruptedIOException(java.lang.Throwable);
     field public int bytesTransferred;
   }
 
@@ -48298,7 +49627,6 @@
     method public long longValue();
     method public static byte parseByte(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static byte parseByte(java.lang.String) throws java.lang.NumberFormatException;
-    method public static java.lang.String toHexString(byte, boolean);
     method public static java.lang.String toString(byte);
     method public static java.lang.Byte valueOf(byte);
     method public static java.lang.Byte valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -49041,6 +50369,9 @@
     field public static final java.lang.Class<java.lang.Float> TYPE;
   }
 
+  public abstract class FunctionalInterface implements java.lang.annotation.Annotation {
+  }
+
   public class IllegalAccessError extends java.lang.IncompatibleClassChangeError {
     ctor public IllegalAccessError();
     ctor public IllegalAccessError(java.lang.String);
@@ -49142,6 +50473,8 @@
   public class InternalError extends java.lang.VirtualMachineError {
     ctor public InternalError();
     ctor public InternalError(java.lang.String);
+    ctor public InternalError(java.lang.String, java.lang.Throwable);
+    ctor public InternalError(java.lang.Throwable);
   }
 
   public class InterruptedException extends java.lang.Exception {
@@ -49914,6 +51247,8 @@
   public abstract class VirtualMachineError extends java.lang.Error {
     ctor public VirtualMachineError();
     ctor public VirtualMachineError(java.lang.String);
+    ctor public VirtualMachineError(java.lang.String, java.lang.Throwable);
+    ctor public VirtualMachineError(java.lang.Throwable);
   }
 
   public final class Void {
@@ -50166,6 +51501,7 @@
     method public java.lang.Object invoke(java.lang.Object, java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException;
     method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
     method public boolean isBridge();
+    method public boolean isDefault();
     method public boolean isSynthetic();
     method public boolean isVarArgs();
     method public java.lang.String toGenericString();
@@ -50446,7 +51782,6 @@
   public class BindException extends java.net.SocketException {
     ctor public BindException(java.lang.String);
     ctor public BindException();
-    ctor public BindException(java.lang.String, java.lang.Throwable);
   }
 
   public abstract class CacheRequest {
@@ -50464,7 +51799,6 @@
   public class ConnectException extends java.net.SocketException {
     ctor public ConnectException(java.lang.String);
     ctor public ConnectException();
-    ctor public ConnectException(java.lang.String, java.lang.Throwable);
   }
 
   public abstract class ContentHandler {
@@ -50544,7 +51878,6 @@
     method public void disconnect();
     method public synchronized boolean getBroadcast() throws java.net.SocketException;
     method public java.nio.channels.DatagramChannel getChannel();
-    method public final java.io.FileDescriptor getFileDescriptor$();
     method public java.net.InetAddress getInetAddress();
     method public java.net.InetAddress getLocalAddress();
     method public int getLocalPort();
@@ -50621,7 +51954,6 @@
     method public boolean hasExpired();
     method public boolean isHttpOnly();
     method public static java.util.List<java.net.HttpCookie> parse(java.lang.String);
-    method public static java.util.List<java.net.HttpCookie> parse(java.lang.String, boolean);
     method public void setComment(java.lang.String);
     method public void setCommentURL(java.lang.String);
     method public void setDiscard(boolean);
@@ -50714,9 +52046,6 @@
   }
 
   public final class Inet4Address extends java.net.InetAddress {
-    field public static final java.net.InetAddress ALL;
-    field public static final java.net.InetAddress ANY;
-    field public static final java.net.InetAddress LOOPBACK;
   }
 
   public final class Inet6Address extends java.net.InetAddress {
@@ -50725,8 +52054,6 @@
     method public int getScopeId();
     method public java.net.NetworkInterface getScopedInterface();
     method public boolean isIPv4CompatibleAddress();
-    field public static final java.net.InetAddress ANY;
-    field public static final java.net.InetAddress LOOPBACK;
   }
 
   public class InetAddress implements java.io.Serializable {
@@ -50854,13 +52181,11 @@
   public class PortUnreachableException extends java.net.SocketException {
     ctor public PortUnreachableException(java.lang.String);
     ctor public PortUnreachableException();
-    ctor public PortUnreachableException(java.lang.String, java.lang.Throwable);
   }
 
   public class ProtocolException extends java.io.IOException {
     ctor public ProtocolException(java.lang.String);
     ctor public ProtocolException();
-    ctor public ProtocolException(java.lang.String, java.lang.Throwable);
   }
 
   public abstract interface ProtocolFamily {
@@ -50995,8 +52320,6 @@
   public class SocketException extends java.io.IOException {
     ctor public SocketException(java.lang.String);
     ctor public SocketException();
-    ctor public SocketException(java.lang.Throwable);
-    ctor public SocketException(java.lang.String, java.lang.Throwable);
   }
 
   public abstract class SocketImpl implements java.net.SocketOptions {
@@ -51066,8 +52389,6 @@
   public class SocketTimeoutException extends java.io.InterruptedIOException {
     ctor public SocketTimeoutException(java.lang.String);
     ctor public SocketTimeoutException();
-    ctor public SocketTimeoutException(java.lang.Throwable);
-    ctor public SocketTimeoutException(java.lang.String, java.lang.Throwable);
   }
 
   public final class StandardProtocolFamily extends java.lang.Enum implements java.net.ProtocolFamily {
@@ -51594,25 +52915,6 @@
     ctor public AsynchronousCloseException();
   }
 
-  public abstract class AsynchronousFileChannel implements java.nio.channels.AsynchronousChannel {
-    ctor protected AsynchronousFileChannel();
-    method public abstract void force(boolean) throws java.io.IOException;
-    method public abstract void lock(long, long, boolean, A, java.nio.channels.CompletionHandler<java.nio.channels.FileLock, ? super A>);
-    method public final void lock(A, java.nio.channels.CompletionHandler<java.nio.channels.FileLock, ? super A>);
-    method public abstract java.util.concurrent.Future<java.nio.channels.FileLock> lock(long, long, boolean);
-    method public final java.util.concurrent.Future<java.nio.channels.FileLock> lock();
-    method public static java.nio.channels.AsynchronousFileChannel open(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.util.concurrent.ExecutorService, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.channels.AsynchronousFileChannel open(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public abstract void read(java.nio.ByteBuffer, long, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
-    method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer, long);
-    method public abstract long size() throws java.io.IOException;
-    method public abstract java.nio.channels.AsynchronousFileChannel truncate(long) throws java.io.IOException;
-    method public abstract java.nio.channels.FileLock tryLock(long, long, boolean) throws java.io.IOException;
-    method public final java.nio.channels.FileLock tryLock() throws java.io.IOException;
-    method public abstract void write(java.nio.ByteBuffer, long, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
-    method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer, long);
-  }
-
   public abstract class AsynchronousServerSocketChannel implements java.nio.channels.AsynchronousChannel java.nio.channels.NetworkChannel {
     ctor protected AsynchronousServerSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
     method public abstract void accept(A, java.nio.channels.CompletionHandler<java.nio.channels.AsynchronousSocketChannel, ? super A>);
@@ -51721,8 +53023,6 @@
     method public abstract java.nio.channels.FileLock lock(long, long, boolean) throws java.io.IOException;
     method public final java.nio.channels.FileLock lock() throws java.io.IOException;
     method public abstract java.nio.MappedByteBuffer map(java.nio.channels.FileChannel.MapMode, long, long) throws java.io.IOException;
-    method public static java.nio.channels.FileChannel open(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.channels.FileChannel open(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
     method public abstract long position() throws java.io.IOException;
     method public abstract java.nio.channels.FileChannel position(long) throws java.io.IOException;
     method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
@@ -51749,7 +53049,6 @@
 
   public abstract class FileLock implements java.lang.AutoCloseable {
     ctor protected FileLock(java.nio.channels.FileChannel, long, long, boolean);
-    ctor protected FileLock(java.nio.channels.AsynchronousFileChannel, long, long, boolean);
     method public java.nio.channels.Channel acquiredBy();
     method public final java.nio.channels.FileChannel channel();
     method public final void close() throws java.io.IOException;
@@ -52199,592 +53498,6 @@
 
 }
 
-package java.nio.file {
-
-  public class AccessDeniedException extends java.nio.file.FileSystemException {
-    ctor public AccessDeniedException(java.lang.String);
-    ctor public AccessDeniedException(java.lang.String, java.lang.String, java.lang.String);
-  }
-
-  public final class AccessMode extends java.lang.Enum {
-    method public static java.nio.file.AccessMode valueOf(java.lang.String);
-    method public static final java.nio.file.AccessMode[] values();
-    enum_constant public static final java.nio.file.AccessMode EXECUTE;
-    enum_constant public static final java.nio.file.AccessMode READ;
-    enum_constant public static final java.nio.file.AccessMode WRITE;
-  }
-
-  public class AtomicMoveNotSupportedException extends java.nio.file.FileSystemException {
-    ctor public AtomicMoveNotSupportedException(java.lang.String, java.lang.String, java.lang.String);
-  }
-
-  public class ClosedDirectoryStreamException extends java.lang.IllegalStateException {
-    ctor public ClosedDirectoryStreamException();
-  }
-
-  public class ClosedFileSystemException extends java.lang.IllegalStateException {
-    ctor public ClosedFileSystemException();
-  }
-
-  public class ClosedWatchServiceException extends java.lang.IllegalStateException {
-    ctor public ClosedWatchServiceException();
-  }
-
-  public abstract interface CopyOption {
-  }
-
-  public final class DirectoryIteratorException extends java.util.ConcurrentModificationException {
-    ctor public DirectoryIteratorException(java.io.IOException);
-  }
-
-  public class DirectoryNotEmptyException extends java.nio.file.FileSystemException {
-    ctor public DirectoryNotEmptyException(java.lang.String);
-  }
-
-  public abstract interface DirectoryStream implements java.io.Closeable java.lang.Iterable {
-    method public abstract java.util.Iterator<T> iterator();
-  }
-
-  public static abstract interface DirectoryStream.Filter {
-    method public abstract boolean accept(T) throws java.io.IOException;
-  }
-
-  public class FileAlreadyExistsException extends java.nio.file.FileSystemException {
-    ctor public FileAlreadyExistsException(java.lang.String);
-    ctor public FileAlreadyExistsException(java.lang.String, java.lang.String, java.lang.String);
-  }
-
-  public abstract class FileStore {
-    ctor protected FileStore();
-    method public abstract java.lang.Object getAttribute(java.lang.String) throws java.io.IOException;
-    method public abstract V getFileStoreAttributeView(java.lang.Class<V>);
-    method public abstract long getTotalSpace() throws java.io.IOException;
-    method public abstract long getUnallocatedSpace() throws java.io.IOException;
-    method public abstract long getUsableSpace() throws java.io.IOException;
-    method public abstract boolean isReadOnly();
-    method public abstract java.lang.String name();
-    method public abstract boolean supportsFileAttributeView(java.lang.Class<? extends java.nio.file.attribute.FileAttributeView>);
-    method public abstract boolean supportsFileAttributeView(java.lang.String);
-    method public abstract java.lang.String type();
-  }
-
-  public abstract class FileSystem implements java.io.Closeable {
-    ctor protected FileSystem();
-    method public abstract void close() throws java.io.IOException;
-    method public abstract java.lang.Iterable<java.nio.file.FileStore> getFileStores();
-    method public abstract java.nio.file.Path getPath(java.lang.String, java.lang.String...);
-    method public abstract java.nio.file.PathMatcher getPathMatcher(java.lang.String);
-    method public abstract java.lang.Iterable<java.nio.file.Path> getRootDirectories();
-    method public abstract java.lang.String getSeparator();
-    method public abstract java.nio.file.attribute.UserPrincipalLookupService getUserPrincipalLookupService();
-    method public abstract boolean isOpen();
-    method public abstract boolean isReadOnly();
-    method public abstract java.nio.file.WatchService newWatchService() throws java.io.IOException;
-    method public abstract java.nio.file.spi.FileSystemProvider provider();
-    method public abstract java.util.Set<java.lang.String> supportedFileAttributeViews();
-  }
-
-  public class FileSystemAlreadyExistsException extends java.lang.RuntimeException {
-    ctor public FileSystemAlreadyExistsException();
-    ctor public FileSystemAlreadyExistsException(java.lang.String);
-  }
-
-  public class FileSystemException extends java.io.IOException {
-    ctor public FileSystemException(java.lang.String);
-    ctor public FileSystemException(java.lang.String, java.lang.String, java.lang.String);
-    method public java.lang.String getFile();
-    method public java.lang.String getOtherFile();
-    method public java.lang.String getReason();
-  }
-
-  public class FileSystemLoopException extends java.nio.file.FileSystemException {
-    ctor public FileSystemLoopException(java.lang.String);
-  }
-
-  public class FileSystemNotFoundException extends java.lang.RuntimeException {
-    ctor public FileSystemNotFoundException();
-    ctor public FileSystemNotFoundException(java.lang.String);
-  }
-
-  public final class FileSystems {
-    method public static java.nio.file.FileSystem getDefault();
-    method public static java.nio.file.FileSystem getFileSystem(java.net.URI);
-    method public static java.nio.file.FileSystem newFileSystem(java.net.URI, java.util.Map<java.lang.String, ?>) throws java.io.IOException;
-    method public static java.nio.file.FileSystem newFileSystem(java.net.URI, java.util.Map<java.lang.String, ?>, java.lang.ClassLoader) throws java.io.IOException;
-    method public static java.nio.file.FileSystem newFileSystem(java.nio.file.Path, java.lang.ClassLoader) throws java.io.IOException;
-  }
-
-  public final class FileVisitOption extends java.lang.Enum {
-    method public static java.nio.file.FileVisitOption valueOf(java.lang.String);
-    method public static final java.nio.file.FileVisitOption[] values();
-    enum_constant public static final java.nio.file.FileVisitOption FOLLOW_LINKS;
-  }
-
-  public final class FileVisitResult extends java.lang.Enum {
-    method public static java.nio.file.FileVisitResult valueOf(java.lang.String);
-    method public static final java.nio.file.FileVisitResult[] values();
-    enum_constant public static final java.nio.file.FileVisitResult CONTINUE;
-    enum_constant public static final java.nio.file.FileVisitResult SKIP_SIBLINGS;
-    enum_constant public static final java.nio.file.FileVisitResult SKIP_SUBTREE;
-    enum_constant public static final java.nio.file.FileVisitResult TERMINATE;
-  }
-
-  public abstract interface FileVisitor {
-    method public abstract java.nio.file.FileVisitResult postVisitDirectory(T, java.io.IOException) throws java.io.IOException;
-    method public abstract java.nio.file.FileVisitResult preVisitDirectory(T, java.nio.file.attribute.BasicFileAttributes) throws java.io.IOException;
-    method public abstract java.nio.file.FileVisitResult visitFile(T, java.nio.file.attribute.BasicFileAttributes) throws java.io.IOException;
-    method public abstract java.nio.file.FileVisitResult visitFileFailed(T, java.io.IOException) throws java.io.IOException;
-  }
-
-  public final class Files {
-    method public static java.nio.file.Path copy(java.nio.file.Path, java.nio.file.Path, java.nio.file.CopyOption...) throws java.io.IOException;
-    method public static long copy(java.io.InputStream, java.nio.file.Path, java.nio.file.CopyOption...) throws java.io.IOException;
-    method public static long copy(java.nio.file.Path, java.io.OutputStream) throws java.io.IOException;
-    method public static java.nio.file.Path createDirectories(java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createDirectory(java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createFile(java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createLink(java.nio.file.Path, java.nio.file.Path) throws java.io.IOException;
-    method public static java.nio.file.Path createSymbolicLink(java.nio.file.Path, java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createTempDirectory(java.nio.file.Path, java.lang.String, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createTempDirectory(java.lang.String, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createTempFile(java.nio.file.Path, java.lang.String, java.lang.String, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createTempFile(java.lang.String, java.lang.String, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static void delete(java.nio.file.Path) throws java.io.IOException;
-    method public static boolean deleteIfExists(java.nio.file.Path) throws java.io.IOException;
-    method public static boolean exists(java.nio.file.Path, java.nio.file.LinkOption...);
-    method public static java.lang.Object getAttribute(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static V getFileAttributeView(java.nio.file.Path, java.lang.Class<V>, java.nio.file.LinkOption...);
-    method public static java.nio.file.FileStore getFileStore(java.nio.file.Path) throws java.io.IOException;
-    method public static java.nio.file.attribute.FileTime getLastModifiedTime(java.nio.file.Path, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static java.nio.file.attribute.UserPrincipal getOwner(java.nio.file.Path, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static java.util.Set<java.nio.file.attribute.PosixFilePermission> getPosixFilePermissions(java.nio.file.Path, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static boolean isDirectory(java.nio.file.Path, java.nio.file.LinkOption...);
-    method public static boolean isExecutable(java.nio.file.Path);
-    method public static boolean isHidden(java.nio.file.Path) throws java.io.IOException;
-    method public static boolean isReadable(java.nio.file.Path);
-    method public static boolean isRegularFile(java.nio.file.Path, java.nio.file.LinkOption...);
-    method public static boolean isSameFile(java.nio.file.Path, java.nio.file.Path) throws java.io.IOException;
-    method public static boolean isSymbolicLink(java.nio.file.Path);
-    method public static boolean isWritable(java.nio.file.Path);
-    method public static java.nio.file.Path move(java.nio.file.Path, java.nio.file.Path, java.nio.file.CopyOption...) throws java.io.IOException;
-    method public static java.io.BufferedReader newBufferedReader(java.nio.file.Path, java.nio.charset.Charset) throws java.io.IOException;
-    method public static java.io.BufferedWriter newBufferedWriter(java.nio.file.Path, java.nio.charset.Charset, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public static java.nio.channels.SeekableByteChannel newByteChannel(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.channels.SeekableByteChannel newByteChannel(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public static java.nio.file.DirectoryStream<java.nio.file.Path> newDirectoryStream(java.nio.file.Path) throws java.io.IOException;
-    method public static java.nio.file.DirectoryStream<java.nio.file.Path> newDirectoryStream(java.nio.file.Path, java.lang.String) throws java.io.IOException;
-    method public static java.nio.file.DirectoryStream<java.nio.file.Path> newDirectoryStream(java.nio.file.Path, java.nio.file.DirectoryStream.Filter<? super java.nio.file.Path>) throws java.io.IOException;
-    method public static java.io.InputStream newInputStream(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public static java.io.OutputStream newOutputStream(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public static boolean notExists(java.nio.file.Path, java.nio.file.LinkOption...);
-    method public static java.lang.String probeContentType(java.nio.file.Path) throws java.io.IOException;
-    method public static byte[] readAllBytes(java.nio.file.Path) throws java.io.IOException;
-    method public static java.util.List<java.lang.String> readAllLines(java.nio.file.Path, java.nio.charset.Charset) throws java.io.IOException;
-    method public static A readAttributes(java.nio.file.Path, java.lang.Class<A>, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static java.util.Map<java.lang.String, java.lang.Object> readAttributes(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static java.nio.file.Path readSymbolicLink(java.nio.file.Path) throws java.io.IOException;
-    method public static java.nio.file.Path setAttribute(java.nio.file.Path, java.lang.String, java.lang.Object, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static java.nio.file.Path setLastModifiedTime(java.nio.file.Path, java.nio.file.attribute.FileTime) throws java.io.IOException;
-    method public static java.nio.file.Path setOwner(java.nio.file.Path, java.nio.file.attribute.UserPrincipal) throws java.io.IOException;
-    method public static java.nio.file.Path setPosixFilePermissions(java.nio.file.Path, java.util.Set<java.nio.file.attribute.PosixFilePermission>) throws java.io.IOException;
-    method public static long size(java.nio.file.Path) throws java.io.IOException;
-    method public static java.nio.file.Path walkFileTree(java.nio.file.Path, java.util.Set<java.nio.file.FileVisitOption>, int, java.nio.file.FileVisitor<? super java.nio.file.Path>) throws java.io.IOException;
-    method public static java.nio.file.Path walkFileTree(java.nio.file.Path, java.nio.file.FileVisitor<? super java.nio.file.Path>) throws java.io.IOException;
-    method public static java.nio.file.Path write(java.nio.file.Path, byte[], java.nio.file.OpenOption...) throws java.io.IOException;
-    method public static java.nio.file.Path write(java.nio.file.Path, java.lang.Iterable<? extends java.lang.CharSequence>, java.nio.charset.Charset, java.nio.file.OpenOption...) throws java.io.IOException;
-  }
-
-  public class InvalidPathException extends java.lang.IllegalArgumentException {
-    ctor public InvalidPathException(java.lang.String, java.lang.String, int);
-    ctor public InvalidPathException(java.lang.String, java.lang.String);
-    method public int getIndex();
-    method public java.lang.String getInput();
-    method public java.lang.String getReason();
-  }
-
-  public final class LinkOption extends java.lang.Enum implements java.nio.file.CopyOption java.nio.file.OpenOption {
-    method public static java.nio.file.LinkOption valueOf(java.lang.String);
-    method public static final java.nio.file.LinkOption[] values();
-    enum_constant public static final java.nio.file.LinkOption NOFOLLOW_LINKS;
-  }
-
-  public final class LinkPermission extends java.security.BasicPermission {
-    ctor public LinkPermission(java.lang.String);
-    ctor public LinkPermission(java.lang.String, java.lang.String);
-  }
-
-  public class NoSuchFileException extends java.nio.file.FileSystemException {
-    ctor public NoSuchFileException(java.lang.String);
-    ctor public NoSuchFileException(java.lang.String, java.lang.String, java.lang.String);
-  }
-
-  public class NotDirectoryException extends java.nio.file.FileSystemException {
-    ctor public NotDirectoryException(java.lang.String);
-  }
-
-  public class NotLinkException extends java.nio.file.FileSystemException {
-    ctor public NotLinkException(java.lang.String);
-    ctor public NotLinkException(java.lang.String, java.lang.String, java.lang.String);
-  }
-
-  public abstract interface OpenOption {
-  }
-
-  public abstract interface Path implements java.lang.Comparable java.lang.Iterable java.nio.file.Watchable {
-    method public abstract int compareTo(java.nio.file.Path);
-    method public abstract boolean endsWith(java.nio.file.Path);
-    method public abstract boolean endsWith(java.lang.String);
-    method public abstract boolean equals(java.lang.Object);
-    method public abstract java.nio.file.Path getFileName();
-    method public abstract java.nio.file.FileSystem getFileSystem();
-    method public abstract java.nio.file.Path getName(int);
-    method public abstract int getNameCount();
-    method public abstract java.nio.file.Path getParent();
-    method public abstract java.nio.file.Path getRoot();
-    method public abstract int hashCode();
-    method public abstract boolean isAbsolute();
-    method public abstract java.util.Iterator<java.nio.file.Path> iterator();
-    method public abstract java.nio.file.Path normalize();
-    method public abstract java.nio.file.WatchKey register(java.nio.file.WatchService, java.nio.file.WatchEvent.Kind<?>[], java.nio.file.WatchEvent.Modifier...) throws java.io.IOException;
-    method public abstract java.nio.file.WatchKey register(java.nio.file.WatchService, java.nio.file.WatchEvent.Kind<?>...) throws java.io.IOException;
-    method public abstract java.nio.file.Path relativize(java.nio.file.Path);
-    method public abstract java.nio.file.Path resolve(java.nio.file.Path);
-    method public abstract java.nio.file.Path resolve(java.lang.String);
-    method public abstract java.nio.file.Path resolveSibling(java.nio.file.Path);
-    method public abstract java.nio.file.Path resolveSibling(java.lang.String);
-    method public abstract boolean startsWith(java.nio.file.Path);
-    method public abstract boolean startsWith(java.lang.String);
-    method public abstract java.nio.file.Path subpath(int, int);
-    method public abstract java.nio.file.Path toAbsolutePath();
-    method public abstract java.io.File toFile();
-    method public abstract java.nio.file.Path toRealPath(java.nio.file.LinkOption...) throws java.io.IOException;
-    method public abstract java.lang.String toString();
-    method public abstract java.net.URI toUri();
-  }
-
-  public abstract interface PathMatcher {
-    method public abstract boolean matches(java.nio.file.Path);
-  }
-
-  public final class Paths {
-    method public static java.nio.file.Path get(java.lang.String, java.lang.String...);
-    method public static java.nio.file.Path get(java.net.URI);
-  }
-
-  public class ProviderMismatchException extends java.lang.IllegalArgumentException {
-    ctor public ProviderMismatchException();
-    ctor public ProviderMismatchException(java.lang.String);
-  }
-
-  public class ProviderNotFoundException extends java.lang.RuntimeException {
-    ctor public ProviderNotFoundException();
-    ctor public ProviderNotFoundException(java.lang.String);
-  }
-
-  public class ReadOnlyFileSystemException extends java.lang.UnsupportedOperationException {
-    ctor public ReadOnlyFileSystemException();
-  }
-
-  public abstract interface SecureDirectoryStream implements java.nio.file.DirectoryStream {
-    method public abstract void deleteDirectory(T) throws java.io.IOException;
-    method public abstract void deleteFile(T) throws java.io.IOException;
-    method public abstract V getFileAttributeView(java.lang.Class<V>);
-    method public abstract V getFileAttributeView(T, java.lang.Class<V>, java.nio.file.LinkOption...);
-    method public abstract void move(T, java.nio.file.SecureDirectoryStream<T>, T) throws java.io.IOException;
-    method public abstract java.nio.channels.SeekableByteChannel newByteChannel(T, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public abstract java.nio.file.SecureDirectoryStream<T> newDirectoryStream(T, java.nio.file.LinkOption...) throws java.io.IOException;
-  }
-
-  public final class StandardCopyOption extends java.lang.Enum implements java.nio.file.CopyOption {
-    method public static java.nio.file.StandardCopyOption valueOf(java.lang.String);
-    method public static final java.nio.file.StandardCopyOption[] values();
-    enum_constant public static final java.nio.file.StandardCopyOption ATOMIC_MOVE;
-    enum_constant public static final java.nio.file.StandardCopyOption COPY_ATTRIBUTES;
-    enum_constant public static final java.nio.file.StandardCopyOption REPLACE_EXISTING;
-  }
-
-  public final class StandardOpenOption extends java.lang.Enum implements java.nio.file.OpenOption {
-    method public static java.nio.file.StandardOpenOption valueOf(java.lang.String);
-    method public static final java.nio.file.StandardOpenOption[] values();
-    enum_constant public static final java.nio.file.StandardOpenOption APPEND;
-    enum_constant public static final java.nio.file.StandardOpenOption CREATE;
-    enum_constant public static final java.nio.file.StandardOpenOption CREATE_NEW;
-    enum_constant public static final java.nio.file.StandardOpenOption DELETE_ON_CLOSE;
-    enum_constant public static final java.nio.file.StandardOpenOption DSYNC;
-    enum_constant public static final java.nio.file.StandardOpenOption READ;
-    enum_constant public static final java.nio.file.StandardOpenOption SPARSE;
-    enum_constant public static final java.nio.file.StandardOpenOption SYNC;
-    enum_constant public static final java.nio.file.StandardOpenOption TRUNCATE_EXISTING;
-    enum_constant public static final java.nio.file.StandardOpenOption WRITE;
-  }
-
-  public final class StandardWatchEventKinds {
-    field public static final java.nio.file.WatchEvent.Kind<java.nio.file.Path> ENTRY_CREATE;
-    field public static final java.nio.file.WatchEvent.Kind<java.nio.file.Path> ENTRY_DELETE;
-    field public static final java.nio.file.WatchEvent.Kind<java.nio.file.Path> ENTRY_MODIFY;
-    field public static final java.nio.file.WatchEvent.Kind<java.lang.Object> OVERFLOW;
-  }
-
-  public abstract interface WatchEvent {
-    method public abstract T context();
-    method public abstract int count();
-    method public abstract java.nio.file.WatchEvent.Kind<T> kind();
-  }
-
-  public static abstract interface WatchEvent.Kind {
-    method public abstract java.lang.String name();
-    method public abstract java.lang.Class<T> type();
-  }
-
-  public static abstract interface WatchEvent.Modifier {
-    method public abstract java.lang.String name();
-  }
-
-  public abstract interface WatchKey {
-    method public abstract void cancel();
-    method public abstract boolean isValid();
-    method public abstract java.util.List<java.nio.file.WatchEvent<?>> pollEvents();
-    method public abstract boolean reset();
-    method public abstract java.nio.file.Watchable watchable();
-  }
-
-  public abstract interface WatchService implements java.io.Closeable {
-    method public abstract void close() throws java.io.IOException;
-    method public abstract java.nio.file.WatchKey poll();
-    method public abstract java.nio.file.WatchKey poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public abstract java.nio.file.WatchKey take() throws java.lang.InterruptedException;
-  }
-
-  public abstract interface Watchable {
-    method public abstract java.nio.file.WatchKey register(java.nio.file.WatchService, java.nio.file.WatchEvent.Kind<?>[], java.nio.file.WatchEvent.Modifier...) throws java.io.IOException;
-    method public abstract java.nio.file.WatchKey register(java.nio.file.WatchService, java.nio.file.WatchEvent.Kind<?>...) throws java.io.IOException;
-  }
-
-}
-
-package java.nio.file.attribute {
-
-  public final class AclEntry {
-    method public java.util.Set<java.nio.file.attribute.AclEntryFlag> flags();
-    method public static java.nio.file.attribute.AclEntry.Builder newBuilder();
-    method public static java.nio.file.attribute.AclEntry.Builder newBuilder(java.nio.file.attribute.AclEntry);
-    method public java.util.Set<java.nio.file.attribute.AclEntryPermission> permissions();
-    method public java.nio.file.attribute.UserPrincipal principal();
-    method public java.nio.file.attribute.AclEntryType type();
-  }
-
-  public static final class AclEntry.Builder {
-    method public java.nio.file.attribute.AclEntry build();
-    method public java.nio.file.attribute.AclEntry.Builder setFlags(java.util.Set<java.nio.file.attribute.AclEntryFlag>);
-    method public java.nio.file.attribute.AclEntry.Builder setFlags(java.nio.file.attribute.AclEntryFlag...);
-    method public java.nio.file.attribute.AclEntry.Builder setPermissions(java.util.Set<java.nio.file.attribute.AclEntryPermission>);
-    method public java.nio.file.attribute.AclEntry.Builder setPermissions(java.nio.file.attribute.AclEntryPermission...);
-    method public java.nio.file.attribute.AclEntry.Builder setPrincipal(java.nio.file.attribute.UserPrincipal);
-    method public java.nio.file.attribute.AclEntry.Builder setType(java.nio.file.attribute.AclEntryType);
-  }
-
-  public final class AclEntryFlag extends java.lang.Enum {
-    method public static java.nio.file.attribute.AclEntryFlag valueOf(java.lang.String);
-    method public static final java.nio.file.attribute.AclEntryFlag[] values();
-    enum_constant public static final java.nio.file.attribute.AclEntryFlag DIRECTORY_INHERIT;
-    enum_constant public static final java.nio.file.attribute.AclEntryFlag FILE_INHERIT;
-    enum_constant public static final java.nio.file.attribute.AclEntryFlag INHERIT_ONLY;
-    enum_constant public static final java.nio.file.attribute.AclEntryFlag NO_PROPAGATE_INHERIT;
-  }
-
-  public final class AclEntryPermission extends java.lang.Enum {
-    method public static java.nio.file.attribute.AclEntryPermission valueOf(java.lang.String);
-    method public static final java.nio.file.attribute.AclEntryPermission[] values();
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission APPEND_DATA;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission DELETE;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission DELETE_CHILD;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission EXECUTE;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_ACL;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_ATTRIBUTES;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_DATA;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_NAMED_ATTRS;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission SYNCHRONIZE;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_ACL;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_ATTRIBUTES;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_DATA;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_NAMED_ATTRS;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_OWNER;
-    field public static final java.nio.file.attribute.AclEntryPermission ADD_FILE;
-    field public static final java.nio.file.attribute.AclEntryPermission ADD_SUBDIRECTORY;
-    field public static final java.nio.file.attribute.AclEntryPermission LIST_DIRECTORY;
-  }
-
-  public final class AclEntryType extends java.lang.Enum {
-    method public static java.nio.file.attribute.AclEntryType valueOf(java.lang.String);
-    method public static final java.nio.file.attribute.AclEntryType[] values();
-    enum_constant public static final java.nio.file.attribute.AclEntryType ALARM;
-    enum_constant public static final java.nio.file.attribute.AclEntryType ALLOW;
-    enum_constant public static final java.nio.file.attribute.AclEntryType AUDIT;
-    enum_constant public static final java.nio.file.attribute.AclEntryType DENY;
-  }
-
-  public abstract interface AclFileAttributeView implements java.nio.file.attribute.FileOwnerAttributeView {
-    method public abstract java.util.List<java.nio.file.attribute.AclEntry> getAcl() throws java.io.IOException;
-    method public abstract java.lang.String name();
-    method public abstract void setAcl(java.util.List<java.nio.file.attribute.AclEntry>) throws java.io.IOException;
-  }
-
-  public abstract interface AttributeView {
-    method public abstract java.lang.String name();
-  }
-
-  public abstract interface BasicFileAttributeView implements java.nio.file.attribute.FileAttributeView {
-    method public abstract java.lang.String name();
-    method public abstract java.nio.file.attribute.BasicFileAttributes readAttributes() throws java.io.IOException;
-    method public abstract void setTimes(java.nio.file.attribute.FileTime, java.nio.file.attribute.FileTime, java.nio.file.attribute.FileTime) throws java.io.IOException;
-  }
-
-  public abstract interface BasicFileAttributes {
-    method public abstract java.nio.file.attribute.FileTime creationTime();
-    method public abstract java.lang.Object fileKey();
-    method public abstract boolean isDirectory();
-    method public abstract boolean isOther();
-    method public abstract boolean isRegularFile();
-    method public abstract boolean isSymbolicLink();
-    method public abstract java.nio.file.attribute.FileTime lastAccessTime();
-    method public abstract java.nio.file.attribute.FileTime lastModifiedTime();
-    method public abstract long size();
-  }
-
-  public abstract interface DosFileAttributeView implements java.nio.file.attribute.BasicFileAttributeView {
-    method public abstract java.lang.String name();
-    method public abstract java.nio.file.attribute.DosFileAttributes readAttributes() throws java.io.IOException;
-    method public abstract void setArchive(boolean) throws java.io.IOException;
-    method public abstract void setHidden(boolean) throws java.io.IOException;
-    method public abstract void setReadOnly(boolean) throws java.io.IOException;
-    method public abstract void setSystem(boolean) throws java.io.IOException;
-  }
-
-  public abstract interface DosFileAttributes implements java.nio.file.attribute.BasicFileAttributes {
-    method public abstract boolean isArchive();
-    method public abstract boolean isHidden();
-    method public abstract boolean isReadOnly();
-    method public abstract boolean isSystem();
-  }
-
-  public abstract interface FileAttribute {
-    method public abstract java.lang.String name();
-    method public abstract T value();
-  }
-
-  public abstract interface FileAttributeView implements java.nio.file.attribute.AttributeView {
-  }
-
-  public abstract interface FileOwnerAttributeView implements java.nio.file.attribute.FileAttributeView {
-    method public abstract java.nio.file.attribute.UserPrincipal getOwner() throws java.io.IOException;
-    method public abstract java.lang.String name();
-    method public abstract void setOwner(java.nio.file.attribute.UserPrincipal) throws java.io.IOException;
-  }
-
-  public abstract interface FileStoreAttributeView implements java.nio.file.attribute.AttributeView {
-  }
-
-  public final class FileTime implements java.lang.Comparable {
-    method public int compareTo(java.nio.file.attribute.FileTime);
-    method public static java.nio.file.attribute.FileTime from(long, java.util.concurrent.TimeUnit);
-    method public static java.nio.file.attribute.FileTime fromMillis(long);
-    method public long to(java.util.concurrent.TimeUnit);
-    method public long toMillis();
-  }
-
-  public abstract interface GroupPrincipal implements java.nio.file.attribute.UserPrincipal {
-  }
-
-  public abstract interface PosixFileAttributeView implements java.nio.file.attribute.BasicFileAttributeView java.nio.file.attribute.FileOwnerAttributeView {
-    method public abstract java.lang.String name();
-    method public abstract java.nio.file.attribute.PosixFileAttributes readAttributes() throws java.io.IOException;
-    method public abstract void setGroup(java.nio.file.attribute.GroupPrincipal) throws java.io.IOException;
-    method public abstract void setPermissions(java.util.Set<java.nio.file.attribute.PosixFilePermission>) throws java.io.IOException;
-  }
-
-  public abstract interface PosixFileAttributes implements java.nio.file.attribute.BasicFileAttributes {
-    method public abstract java.nio.file.attribute.GroupPrincipal group();
-    method public abstract java.nio.file.attribute.UserPrincipal owner();
-    method public abstract java.util.Set<java.nio.file.attribute.PosixFilePermission> permissions();
-  }
-
-  public final class PosixFilePermission extends java.lang.Enum {
-    method public static java.nio.file.attribute.PosixFilePermission valueOf(java.lang.String);
-    method public static final java.nio.file.attribute.PosixFilePermission[] values();
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission GROUP_EXECUTE;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission GROUP_READ;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission GROUP_WRITE;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission OTHERS_EXECUTE;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission OTHERS_READ;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission OTHERS_WRITE;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission OWNER_EXECUTE;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission OWNER_READ;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission OWNER_WRITE;
-  }
-
-  public final class PosixFilePermissions {
-    method public static java.nio.file.attribute.FileAttribute<java.util.Set<java.nio.file.attribute.PosixFilePermission>> asFileAttribute(java.util.Set<java.nio.file.attribute.PosixFilePermission>);
-    method public static java.util.Set<java.nio.file.attribute.PosixFilePermission> fromString(java.lang.String);
-    method public static java.lang.String toString(java.util.Set<java.nio.file.attribute.PosixFilePermission>);
-  }
-
-  public abstract interface UserPrincipal implements java.security.Principal {
-  }
-
-  public abstract class UserPrincipalLookupService {
-    ctor protected UserPrincipalLookupService();
-    method public abstract java.nio.file.attribute.GroupPrincipal lookupPrincipalByGroupName(java.lang.String) throws java.io.IOException;
-    method public abstract java.nio.file.attribute.UserPrincipal lookupPrincipalByName(java.lang.String) throws java.io.IOException;
-  }
-
-  public class UserPrincipalNotFoundException extends java.io.IOException {
-    ctor public UserPrincipalNotFoundException(java.lang.String);
-    method public java.lang.String getName();
-  }
-
-}
-
-package java.nio.file.spi {
-
-  public abstract class FileSystemProvider {
-    ctor protected FileSystemProvider();
-    method public abstract void checkAccess(java.nio.file.Path, java.nio.file.AccessMode...) throws java.io.IOException;
-    method public abstract void copy(java.nio.file.Path, java.nio.file.Path, java.nio.file.CopyOption...) throws java.io.IOException;
-    method public abstract void createDirectory(java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public void createLink(java.nio.file.Path, java.nio.file.Path) throws java.io.IOException;
-    method public void createSymbolicLink(java.nio.file.Path, java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public abstract void delete(java.nio.file.Path) throws java.io.IOException;
-    method public boolean deleteIfExists(java.nio.file.Path) throws java.io.IOException;
-    method public abstract V getFileAttributeView(java.nio.file.Path, java.lang.Class<V>, java.nio.file.LinkOption...);
-    method public abstract java.nio.file.FileStore getFileStore(java.nio.file.Path) throws java.io.IOException;
-    method public abstract java.nio.file.FileSystem getFileSystem(java.net.URI);
-    method public abstract java.nio.file.Path getPath(java.net.URI);
-    method public abstract java.lang.String getScheme();
-    method public static java.util.List<java.nio.file.spi.FileSystemProvider> installedProviders();
-    method public abstract boolean isHidden(java.nio.file.Path) throws java.io.IOException;
-    method public abstract boolean isSameFile(java.nio.file.Path, java.nio.file.Path) throws java.io.IOException;
-    method public abstract void move(java.nio.file.Path, java.nio.file.Path, java.nio.file.CopyOption...) throws java.io.IOException;
-    method public java.nio.channels.AsynchronousFileChannel newAsynchronousFileChannel(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.util.concurrent.ExecutorService, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public abstract java.nio.channels.SeekableByteChannel newByteChannel(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public abstract java.nio.file.DirectoryStream<java.nio.file.Path> newDirectoryStream(java.nio.file.Path, java.nio.file.DirectoryStream.Filter<? super java.nio.file.Path>) throws java.io.IOException;
-    method public java.nio.channels.FileChannel newFileChannel(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public abstract java.nio.file.FileSystem newFileSystem(java.net.URI, java.util.Map<java.lang.String, ?>) throws java.io.IOException;
-    method public java.nio.file.FileSystem newFileSystem(java.nio.file.Path, java.util.Map<java.lang.String, ?>) throws java.io.IOException;
-    method public java.io.InputStream newInputStream(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public java.io.OutputStream newOutputStream(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public abstract A readAttributes(java.nio.file.Path, java.lang.Class<A>, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public abstract java.util.Map<java.lang.String, java.lang.Object> readAttributes(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public java.nio.file.Path readSymbolicLink(java.nio.file.Path) throws java.io.IOException;
-    method public abstract void setAttribute(java.nio.file.Path, java.lang.String, java.lang.Object, java.nio.file.LinkOption...) throws java.io.IOException;
-  }
-
-  public abstract class FileTypeDetector {
-    ctor protected FileTypeDetector();
-    method public abstract java.lang.String probeContentType(java.nio.file.Path) throws java.io.IOException;
-  }
-
-}
-
 package java.security {
 
   public final class AccessControlContext {
@@ -53656,6 +54369,7 @@
     method public static java.security.cert.CertPathBuilder getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
     method public static java.security.cert.CertPathBuilder getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
     method public final java.security.Provider getProvider();
+    method public final java.security.cert.CertPathChecker getRevocationChecker();
   }
 
   public class CertPathBuilderException extends java.security.GeneralSecurityException {
@@ -53673,6 +54387,13 @@
   public abstract class CertPathBuilderSpi {
     ctor public CertPathBuilderSpi();
     method public abstract java.security.cert.CertPathBuilderResult engineBuild(java.security.cert.CertPathParameters) throws java.security.cert.CertPathBuilderException, java.security.InvalidAlgorithmParameterException;
+    method public java.security.cert.CertPathChecker engineGetRevocationChecker();
+  }
+
+  public abstract interface CertPathChecker {
+    method public abstract void check(java.security.cert.Certificate) throws java.security.cert.CertPathValidatorException;
+    method public abstract void init(boolean) throws java.security.cert.CertPathValidatorException;
+    method public abstract boolean isForwardCheckingSupported();
   }
 
   public abstract interface CertPathParameters implements java.lang.Cloneable {
@@ -53687,6 +54408,7 @@
     method public static java.security.cert.CertPathValidator getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
     method public static java.security.cert.CertPathValidator getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
     method public final java.security.Provider getProvider();
+    method public final java.security.cert.CertPathChecker getRevocationChecker();
     method public final java.security.cert.CertPathValidatorResult validate(java.security.cert.CertPath, java.security.cert.CertPathParameters) throws java.security.cert.CertPathValidatorException, java.security.InvalidAlgorithmParameterException;
   }
 
@@ -53723,6 +54445,7 @@
 
   public abstract class CertPathValidatorSpi {
     ctor public CertPathValidatorSpi();
+    method public java.security.cert.CertPathChecker engineGetRevocationChecker();
     method public abstract java.security.cert.CertPathValidatorResult engineValidate(java.security.cert.CertPath, java.security.cert.CertPathParameters) throws java.security.cert.CertPathValidatorException, java.security.InvalidAlgorithmParameterException;
   }
 
@@ -53881,9 +54604,10 @@
     method public java.security.cert.CertPath getCertPath();
   }
 
-  public abstract class PKIXCertPathChecker implements java.lang.Cloneable {
+  public abstract class PKIXCertPathChecker implements java.security.cert.CertPathChecker java.lang.Cloneable {
     ctor protected PKIXCertPathChecker();
     method public abstract void check(java.security.cert.Certificate, java.util.Collection<java.lang.String>) throws java.security.cert.CertPathValidatorException;
+    method public void check(java.security.cert.Certificate) throws java.security.cert.CertPathValidatorException;
     method public java.lang.Object clone();
     method public abstract java.util.Set<java.lang.String> getSupportedExtensions();
     method public abstract void init(boolean) throws java.security.cert.CertPathValidatorException;
@@ -53943,6 +54667,30 @@
     enum_constant public static final java.security.cert.PKIXReason UNRECOGNIZED_CRIT_EXT;
   }
 
+  public abstract class PKIXRevocationChecker extends java.security.cert.PKIXCertPathChecker {
+    ctor protected PKIXRevocationChecker();
+    method public java.util.List<java.security.cert.Extension> getOcspExtensions();
+    method public java.net.URI getOcspResponder();
+    method public java.security.cert.X509Certificate getOcspResponderCert();
+    method public java.util.Map<java.security.cert.X509Certificate, byte[]> getOcspResponses();
+    method public java.util.Set<java.security.cert.PKIXRevocationChecker.Option> getOptions();
+    method public abstract java.util.List<java.security.cert.CertPathValidatorException> getSoftFailExceptions();
+    method public void setOcspExtensions(java.util.List<java.security.cert.Extension>);
+    method public void setOcspResponder(java.net.URI);
+    method public void setOcspResponderCert(java.security.cert.X509Certificate);
+    method public void setOcspResponses(java.util.Map<java.security.cert.X509Certificate, byte[]>);
+    method public void setOptions(java.util.Set<java.security.cert.PKIXRevocationChecker.Option>);
+  }
+
+  public static final class PKIXRevocationChecker.Option extends java.lang.Enum {
+    method public static java.security.cert.PKIXRevocationChecker.Option valueOf(java.lang.String);
+    method public static final java.security.cert.PKIXRevocationChecker.Option[] values();
+    enum_constant public static final java.security.cert.PKIXRevocationChecker.Option NO_FALLBACK;
+    enum_constant public static final java.security.cert.PKIXRevocationChecker.Option ONLY_END_ENTITY;
+    enum_constant public static final java.security.cert.PKIXRevocationChecker.Option PREFER_CRLS;
+    enum_constant public static final java.security.cert.PKIXRevocationChecker.Option SOFT_FAIL;
+  }
+
   public abstract interface PolicyNode {
     method public abstract java.util.Iterator<? extends java.security.cert.PolicyNode> getChildren();
     method public abstract int getDepth();
@@ -54102,6 +54850,7 @@
     method public javax.security.auth.x500.X500Principal getSubjectX500Principal();
     method public abstract byte[] getTBSCertificate() throws java.security.cert.CertificateEncodingException;
     method public abstract int getVersion();
+    method public void verify(java.security.PublicKey, java.security.Provider) throws java.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.SignatureException;
   }
 
   public abstract interface X509Extension {
@@ -57345,8 +58094,6 @@
     ctor public Scanner(java.io.InputStream, java.lang.String);
     ctor public Scanner(java.io.File) throws java.io.FileNotFoundException;
     ctor public Scanner(java.io.File, java.lang.String) throws java.io.FileNotFoundException;
-    ctor public Scanner(java.nio.file.Path) throws java.io.IOException;
-    ctor public Scanner(java.nio.file.Path, java.lang.String) throws java.io.IOException;
     ctor public Scanner(java.lang.String);
     ctor public Scanner(java.nio.channels.ReadableByteChannel);
     ctor public Scanner(java.nio.channels.ReadableByteChannel, java.lang.String);
@@ -58976,7 +59723,6 @@
     ctor public JarFile(java.io.File, boolean, int) throws java.io.IOException;
     method public java.util.jar.JarEntry getJarEntry(java.lang.String);
     method public java.util.jar.Manifest getManifest() throws java.io.IOException;
-    method public boolean hasClassPathAttribute() throws java.io.IOException;
     field public static final java.lang.String MANIFEST_NAME = "META-INF/MANIFEST.MF";
   }
 
@@ -59430,8 +60176,8 @@
     method public java.lang.StringBuffer appendTail(java.lang.StringBuffer);
     method public int end();
     method public int end(int);
-    method public boolean find(int);
     method public boolean find();
+    method public boolean find(int);
     method public java.lang.String group();
     method public java.lang.String group(int);
     method public int groupCount();
@@ -59459,8 +60205,8 @@
   }
 
   public final class Pattern implements java.io.Serializable {
-    method public static java.util.regex.Pattern compile(java.lang.String, int) throws java.util.regex.PatternSyntaxException;
     method public static java.util.regex.Pattern compile(java.lang.String);
+    method public static java.util.regex.Pattern compile(java.lang.String, int) throws java.util.regex.PatternSyntaxException;
     method public int flags();
     method public java.util.regex.Matcher matcher(java.lang.CharSequence);
     method public static boolean matches(java.lang.String, java.lang.CharSequence);
@@ -59475,6 +60221,7 @@
     field public static final int LITERAL = 16; // 0x10
     field public static final int MULTILINE = 8; // 0x8
     field public static final int UNICODE_CASE = 64; // 0x40
+    field public static final int UNICODE_CHARACTER_CLASS = 256; // 0x100
     field public static final int UNIX_LINES = 1; // 0x1
   }
 
diff --git a/api/removed.txt b/api/removed.txt
index f12e61e..2c6729d 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -199,6 +199,15 @@
 
 }
 
+package android.test.mock {
+
+  public deprecated class MockPackageManager extends android.content.pm.PackageManager {
+    method public deprecated java.lang.String getDefaultBrowserPackageName(int);
+    method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int);
+  }
+
+}
+
 package android.text.format {
 
   public class DateFormat {
diff --git a/api/system-current.txt b/api/system-current.txt
index 84dbe62..cfa3969 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -46,6 +46,7 @@
     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";
+    field public static final java.lang.String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
     field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
     field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
     field public static final java.lang.String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
@@ -93,10 +94,9 @@
     field public static final java.lang.String DUMP = "android.permission.DUMP";
     field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
     field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
-    field public static final java.lang.String FLASHLIGHT = "android.permission.FLASHLIGHT";
     field public static final java.lang.String FORCE_BACK = "android.permission.FORCE_BACK";
     field public static final java.lang.String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
-    field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
+    field public static final deprecated 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_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS";
     field public static final java.lang.String GET_PACKAGE_IMPORTANCE = "android.permission.GET_PACKAGE_IMPORTANCE";
@@ -215,6 +215,7 @@
     field public static final java.lang.String STATUS_BAR = "android.permission.STATUS_BAR";
     field public static final java.lang.String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES";
     field public static final java.lang.String SYSTEM_ALERT_WINDOW = "android.permission.SYSTEM_ALERT_WINDOW";
+    field public static final java.lang.String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
     field public static final java.lang.String TRANSMIT_IR = "android.permission.TRANSMIT_IR";
     field public static final java.lang.String TV_INPUT_HARDWARE = "android.permission.TV_INPUT_HARDWARE";
     field public static final java.lang.String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT";
@@ -429,6 +430,7 @@
     field public static final int calendarViewShown = 16843596; // 0x101034c
     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 canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
     field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9
     field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
@@ -599,6 +601,8 @@
     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
+    field public static final int endY = 16844052; // 0x1010514
     field public static final deprecated int endYear = 16843133; // 0x101017d
     field public static final int enterFadeDuration = 16843532; // 0x101030c
     field public static final int entries = 16842930; // 0x10100b2
@@ -618,6 +622,7 @@
     field public static final int expandableListViewStyle = 16842863; // 0x101006f
     field public static final int expandableListViewWhiteStyle = 16843446; // 0x10102b6
     field public static final int exported = 16842768; // 0x1010010
+    field public static final int externalService = 16844047; // 0x101050f
     field public static final int extraTension = 16843371; // 0x101026b
     field public static final int extractNativeLibs = 16844010; // 0x10104ea
     field public static final int factor = 16843219; // 0x10101d3
@@ -973,6 +978,7 @@
     field public static final int numbersTextColor = 16843937; // 0x10104a1
     field public static final deprecated int numeric = 16843109; // 0x1010165
     field public static final int numericShortcut = 16843236; // 0x10101e4
+    field public static final int offset = 16844053; // 0x1010515
     field public static final int onClick = 16843375; // 0x101026f
     field public static final int oneshot = 16843159; // 0x1010197
     field public static final int opacity = 16843550; // 0x101031e
@@ -1224,6 +1230,8 @@
     field public static final int startColor = 16843165; // 0x101019d
     field public static final int startDelay = 16843746; // 0x10103e2
     field public static final int startOffset = 16843198; // 0x10101be
+    field public static final int startX = 16844049; // 0x1010511
+    field public static final int startY = 16844050; // 0x1010512
     field public static final deprecated int startYear = 16843132; // 0x101017c
     field public static final int stateListAnimator = 16843848; // 0x1010448
     field public static final int stateNotNeeded = 16842774; // 0x1010016
@@ -1280,6 +1288,7 @@
     field public static final int summaryOn = 16843247; // 0x10101ef
     field public static final int supportsAssist = 16844016; // 0x10104f0
     field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
+    field public static final int supportsLocalInteraction = 16844048; // 0x1010510
     field public static final int supportsPictureInPicture = 16844024; // 0x10104f8
     field public static final int supportsRtl = 16843695; // 0x10103af
     field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
@@ -1387,6 +1396,9 @@
     field public static final int thumbTint = 16843889; // 0x1010471
     field public static final int thumbTintMode = 16843890; // 0x1010472
     field public static final int thumbnail = 16843429; // 0x10102a5
+    field public static final int tickMark = 16844043; // 0x101050b
+    field public static final int tickMarkTint = 16844044; // 0x101050c
+    field public static final int tickMarkTintMode = 16844045; // 0x101050d
     field public static final int tileMode = 16843265; // 0x1010201
     field public static final int tileModeX = 16843895; // 0x1010477
     field public static final int tileModeY = 16843896; // 0x1010478
@@ -2215,22 +2227,6 @@
     field public static final int Theme_Light_Panel = 16973914; // 0x103005a
     field public static final int Theme_Light_WallpaperSettings = 16973922; // 0x1030062
     field public static final int Theme_Material = 16974372; // 0x1030224
-    field public static final int Theme_Material_DayNight = 16974552; // 0x10302d8
-    field public static final int Theme_Material_DayNight_DarkActionBar = 16974553; // 0x10302d9
-    field public static final int Theme_Material_DayNight_Dialog = 16974554; // 0x10302da
-    field public static final int Theme_Material_DayNight_DialogWhenLarge = 16974560; // 0x10302e0
-    field public static final int Theme_Material_DayNight_DialogWhenLarge_DarkActionBar = 16974568; // 0x10302e8
-    field public static final int Theme_Material_DayNight_DialogWhenLarge_NoActionBar = 16974561; // 0x10302e1
-    field public static final int Theme_Material_DayNight_Dialog_Alert = 16974555; // 0x10302db
-    field public static final int Theme_Material_DayNight_Dialog_MinWidth = 16974556; // 0x10302dc
-    field public static final int Theme_Material_DayNight_Dialog_NoActionBar = 16974557; // 0x10302dd
-    field public static final int Theme_Material_DayNight_Dialog_NoActionBar_MinWidth = 16974558; // 0x10302de
-    field public static final int Theme_Material_DayNight_Dialog_Presentation = 16974559; // 0x10302df
-    field public static final int Theme_Material_DayNight_NoActionBar = 16974562; // 0x10302e2
-    field public static final int Theme_Material_DayNight_NoActionBar_Fullscreen = 16974563; // 0x10302e3
-    field public static final int Theme_Material_DayNight_NoActionBar_Overscan = 16974564; // 0x10302e4
-    field public static final int Theme_Material_DayNight_NoActionBar_TranslucentDecor = 16974565; // 0x10302e5
-    field public static final int Theme_Material_DayNight_Panel = 16974566; // 0x10302e6
     field public static final int Theme_Material_Dialog = 16974373; // 0x1030225
     field public static final int Theme_Material_DialogWhenLarge = 16974379; // 0x103022b
     field public static final int Theme_Material_DialogWhenLarge_NoActionBar = 16974380; // 0x103022c
@@ -2244,7 +2240,7 @@
     field public static final int Theme_Material_Light_DarkActionBar = 16974392; // 0x1030238
     field public static final int Theme_Material_Light_Dialog = 16974393; // 0x1030239
     field public static final int Theme_Material_Light_DialogWhenLarge = 16974399; // 0x103023f
-    field public static final int Theme_Material_Light_DialogWhenLarge_DarkActionBar = 16974567; // 0x10302e7
+    field public static final int Theme_Material_Light_DialogWhenLarge_DarkActionBar = 16974552; // 0x10302d8
     field public static final int Theme_Material_Light_DialogWhenLarge_NoActionBar = 16974400; // 0x1030240
     field public static final int Theme_Material_Light_Dialog_Alert = 16974394; // 0x103023a
     field public static final int Theme_Material_Light_Dialog_MinWidth = 16974395; // 0x103023b
@@ -2665,6 +2661,7 @@
     field public static final int Widget_Material_ScrollView = 16974462; // 0x103027e
     field public static final int Widget_Material_SearchView = 16974463; // 0x103027f
     field public static final int Widget_Material_SeekBar = 16974464; // 0x1030280
+    field public static final int Widget_Material_SeekBar_Discrete = 16974553; // 0x10302d9
     field public static final int Widget_Material_SegmentedButton = 16974465; // 0x1030281
     field public static final int Widget_Material_Spinner = 16974467; // 0x1030283
     field public static final int Widget_Material_Spinner_Underlined = 16974468; // 0x1030284
@@ -2724,6 +2721,8 @@
 
   public abstract class AccessibilityService extends android.app.Service {
     ctor public AccessibilityService();
+    method public final void disableSelf();
+    method public final boolean dispatchGesture(android.accessibilityservice.GestureDescription, android.accessibilityservice.AccessibilityService.GestureResultCallback, android.os.Handler);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
     method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
@@ -2763,6 +2762,12 @@
     field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice";
   }
 
+  public static abstract class AccessibilityService.GestureResultCallback {
+    ctor public AccessibilityService.GestureResultCallback();
+    method public void onCancelled(android.accessibilityservice.GestureDescription);
+    method public void onCompleted(android.accessibilityservice.GestureDescription);
+  }
+
   public static final class AccessibilityService.MagnificationController {
     method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener);
     method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener, android.os.Handler);
@@ -2795,6 +2800,7 @@
     method public java.lang.String loadDescription(android.content.pm.PackageManager);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10
+    field public static final int CAPABILITY_CAN_PERFORM_GESTURES = 32; // 0x20
     field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
     field public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 8; // 0x8
     field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
@@ -2821,6 +2827,30 @@
     field public java.lang.String[] packageNames;
   }
 
+  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 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 {
+    ctor public GestureDescription.Builder();
+    method public android.accessibilityservice.GestureDescription.Builder addStroke(android.accessibilityservice.GestureDescription.StrokeDescription);
+    method public android.accessibilityservice.GestureDescription build();
+  }
+
+  public static class GestureDescription.StrokeDescription {
+    ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long);
+    method public long getDuration();
+    method public android.graphics.Path getPath();
+    method public long getStartTime();
+  }
+
 }
 
 package android.accounts {
@@ -2838,6 +2868,7 @@
     method public abstract java.lang.String getAuthTokenLabel(java.lang.String);
     method public final android.os.IBinder getIBinder();
     method public abstract android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;
+    method public android.os.Bundle isCredentialsUpdateSuggested(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String) throws android.accounts.NetworkErrorException;
     method public android.os.Bundle startAddAccountSession(android.accounts.AccountAuthenticatorResponse, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public android.os.Bundle startUpdateCredentialsSession(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
@@ -2878,6 +2909,7 @@
     method public android.accounts.AccountManagerFuture<android.os.Bundle> confirmCredentials(android.accounts.Account, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> editProperties(java.lang.String, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> finishSession(android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
+    method public android.accounts.AccountManagerFuture<android.os.Bundle> finishSessionAsUser(android.os.Bundle, android.app.Activity, android.os.UserHandle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public static android.accounts.AccountManager get(android.content.Context);
     method public android.accounts.Account[] getAccounts();
     method public android.accounts.Account[] getAccountsByType(java.lang.String);
@@ -2893,6 +2925,7 @@
     method public java.lang.String getUserData(android.accounts.Account, java.lang.String);
     method public android.accounts.AccountManagerFuture<java.lang.Boolean> hasFeatures(android.accounts.Account, java.lang.String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public void invalidateAuthToken(java.lang.String, java.lang.String);
+    method public android.accounts.AccountManagerFuture<java.lang.Boolean> isCredentialsUpdateSuggested(android.accounts.Account, java.lang.String, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public static deprecated android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, java.lang.String[], boolean, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle);
     method public static android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.List<android.accounts.Account>, java.lang.String[], java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle);
     method public boolean notifyAccountAuthenticated(android.accounts.Account);
@@ -3477,6 +3510,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 enterPictureInPictureMode();
     method public android.view.View findViewById(int);
     method public void finish();
     method public void finishActivity(int);
@@ -3525,6 +3559,7 @@
     method public boolean isDestroyed();
     method public boolean isFinishing();
     method public boolean isImmersive();
+    method public boolean isLocalVoiceInteractionSupported();
     method public boolean isTaskRoot();
     method public boolean isVoiceInteraction();
     method public boolean isVoiceInteractionRoot();
@@ -3567,6 +3602,8 @@
     method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
     method public boolean onKeyShortcut(int, android.view.KeyEvent);
     method public boolean onKeyUp(int, android.view.KeyEvent);
+    method public void onLocalVoiceInteractionStarted();
+    method public void onLocalVoiceInteractionStopped();
     method public void onLowMemory();
     method public boolean onMenuItemSelected(int, android.view.MenuItem);
     method public boolean onMenuOpened(int, android.view.Menu);
@@ -3589,6 +3626,7 @@
     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();
@@ -3624,6 +3662,7 @@
     method public boolean releaseInstance();
     method public final deprecated void removeDialog(int);
     method public void reportFullyDrawn();
+    method public android.view.DropPermissions requestDropPermissions(android.view.DragEvent);
     method public final void requestPermissions(java.lang.String[], int);
     method public boolean requestVisibleBehind(boolean);
     method public final boolean requestWindowFeature(int);
@@ -3658,6 +3697,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 boolean shouldShowRequestPermissionRationale(java.lang.String);
     method public boolean shouldUpRecreateTask(android.content.Intent);
     method public boolean showAssist(android.os.Bundle);
@@ -3678,12 +3718,14 @@
     method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
     method public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
     method public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+    method public void startLocalVoiceInteraction(android.os.Bundle);
     method public void startLockTask();
     method public deprecated void startManagingCursor(android.database.Cursor);
     method public boolean startNextMatchingActivity(android.content.Intent);
     method public boolean startNextMatchingActivity(android.content.Intent, android.os.Bundle);
     method public void startPostponedEnterTransition();
     method public void startSearch(java.lang.String, boolean, android.os.Bundle, boolean);
+    method public void stopLocalVoiceInteraction();
     method public void stopLockTask();
     method public deprecated void stopManagingCursor(android.database.Cursor);
     method public void takeKeyEvents(boolean);
@@ -4215,11 +4257,14 @@
   }
 
   public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
+    ctor public DatePickerDialog(android.content.Context);
+    ctor public DatePickerDialog(android.content.Context, int);
     ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
     ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
     method public android.widget.DatePicker getDatePicker();
     method public void onClick(android.content.DialogInterface, int);
     method public void onDateChanged(android.widget.DatePicker, int, int, int);
+    method public void setOnDateSetListener(android.app.DatePickerDialog.OnDateSetListener);
     method public void updateDate(int, int, int);
   }
 
@@ -4280,6 +4325,7 @@
     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);
@@ -4359,7 +4405,7 @@
     field public static final java.lang.String COLUMN_DESCRIPTION = "description";
     field public static final java.lang.String COLUMN_ID = "_id";
     field public static final java.lang.String COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp";
-    field public static final java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
+    field public static final deprecated java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
     field public static final java.lang.String COLUMN_LOCAL_URI = "local_uri";
     field public static final java.lang.String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri";
     field public static final java.lang.String COLUMN_MEDIA_TYPE = "media_type";
@@ -4971,6 +5017,7 @@
     field public static final java.lang.String EXTRA_PROGRESS = "android.progress";
     field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
     field public static final java.lang.String EXTRA_PROGRESS_MAX = "android.progressMax";
+    field public static final java.lang.String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
     field public static final java.lang.String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
     field public static final java.lang.String EXTRA_SHOW_WHEN = "android.showWhen";
     field public static final java.lang.String EXTRA_SMALL_ICON = "android.icon";
@@ -5137,6 +5184,7 @@
     method public android.app.Notification.Builder setPriority(int);
     method public android.app.Notification.Builder setProgress(int, int, boolean);
     method public android.app.Notification.Builder setPublicVersion(android.app.Notification);
+    method public android.app.Notification.Builder setRemoteInputHistory(java.lang.CharSequence[]);
     method public android.app.Notification.Builder setShowWhen(boolean);
     method public android.app.Notification.Builder setSmallIcon(int);
     method public android.app.Notification.Builder setSmallIcon(int, int);
@@ -5326,6 +5374,7 @@
     field public static final int SUPPRESSED_EFFECTS_UNSET = -1; // 0xffffffff
     field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
     field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+    field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
     field public final int priorityCallSenders;
     field public final int priorityCategories;
     field public final int priorityMessageSenders;
@@ -5779,12 +5828,15 @@
     method public android.graphics.drawable.Drawable peekFastDrawable();
     method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle);
     method public void setBitmap(android.graphics.Bitmap) throws java.io.IOException;
-    method public void setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean, int) throws java.io.IOException;
     method public void setDisplayOffset(android.os.IBinder, int, int);
     method public void setDisplayPadding(android.graphics.Rect);
     method public void setResource(int) throws java.io.IOException;
+    method public int setResource(int, int) throws java.io.IOException;
     method public void setStream(java.io.InputStream) throws java.io.IOException;
-    method public void setStream(java.io.InputStream, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setStream(java.io.InputStream, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setStream(java.io.InputStream, android.graphics.Rect, boolean, int) throws java.io.IOException;
     method public boolean setWallpaperComponent(android.content.ComponentName);
     method public void setWallpaperOffsetSteps(float, float);
     method public void setWallpaperOffsets(android.os.IBinder, float, float);
@@ -5796,6 +5848,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 java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
   }
 
@@ -5834,6 +5888,9 @@
     ctor public DeviceAdminReceiver();
     method public android.app.admin.DevicePolicyManager getManager(android.content.Context);
     method public android.content.ComponentName getWho(android.content.Context);
+    method public void onBugreportFailed(android.content.Context, android.content.Intent, int);
+    method public void onBugreportShared(android.content.Context, android.content.Intent, java.lang.String);
+    method public void onBugreportSharingDeclined(android.content.Context, android.content.Intent);
     method public java.lang.String onChoosePrivateKeyAlias(android.content.Context, android.content.Intent, int, android.net.Uri, java.lang.String);
     method public java.lang.CharSequence onDisableRequested(android.content.Context, android.content.Intent);
     method public void onDisabled(android.content.Context, android.content.Intent);
@@ -5858,6 +5915,8 @@
     field public static final java.lang.String ACTION_PASSWORD_FAILED = "android.app.action.ACTION_PASSWORD_FAILED";
     field public static final java.lang.String ACTION_PASSWORD_SUCCEEDED = "android.app.action.ACTION_PASSWORD_SUCCEEDED";
     field public static final java.lang.String ACTION_PROFILE_PROVISIONING_COMPLETE = "android.app.action.PROFILE_PROVISIONING_COMPLETE";
+    field public static final int BUGREPORT_FAILURE_FAILED_COMPLETING = 0; // 0x0
+    field public static final int BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE = 1; // 0x1
     field public static final java.lang.String DEVICE_ADMIN_META_DATA = "android.app.device_admin";
     field public static final java.lang.String EXTRA_DISABLE_WARNING = "android.app.extra.DISABLE_WARNING";
     field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
@@ -5874,28 +5933,36 @@
     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();
     method public java.util.List<android.content.ComponentName> getActiveAdmins();
+    method public java.lang.String getAlwaysOnVpnPackage(android.content.ComponentName);
     method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
+    method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName);
     method public boolean getAutoTimeRequired();
     method public boolean getBluetoothContactSharingDisabled(android.content.ComponentName);
     method public boolean getCameraDisabled(android.content.ComponentName);
     method public java.lang.String getCertInstallerPackage(android.content.ComponentName) throws java.lang.SecurityException;
     method public boolean getCrossProfileCallerIdDisabled(android.content.ComponentName);
+    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 deprecated java.lang.String getDeviceInitializerApp();
     method public deprecated android.content.ComponentName getDeviceInitializerComponent();
     method public java.lang.String getDeviceOwner();
     method public java.lang.String getDeviceOwnerLockScreenInfo();
+    method public java.lang.String getDeviceOwnerNameOnAnyUser();
     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);
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
+    method public int getOrganizationColor(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);
     method public int getPasswordHistoryLength(android.content.ComponentName);
@@ -5917,6 +5984,7 @@
     method public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
     method public java.lang.String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
     method public boolean getScreenCaptureDisabled(android.content.ComponentName);
+    method public java.lang.String getShortSupportMessage(android.content.ComponentName);
     method public boolean getStorageEncryption(android.content.ComponentName);
     method public int getStorageEncryptionStatus();
     method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
@@ -5930,6 +5998,7 @@
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
     method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
+    method public boolean isCallerApplicationRestrictionsManagingPackage();
     method public boolean isDeviceOwnerApp(java.lang.String);
     method public boolean isLockTaskPermitted(java.lang.String);
     method public boolean isMasterVolumeMuted(android.content.ComponentName);
@@ -5938,28 +6007,35 @@
     method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String);
     method public void lockNow();
     method public void notifyPendingSystemUpdate(long);
+    method public void reboot(android.content.ComponentName);
     method public void removeActiveAdmin(android.content.ComponentName);
     method public boolean removeCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
     method public boolean removeKeyPair(android.content.ComponentName, java.lang.String);
     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 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 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 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 boolean setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.String);
     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);
     method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
+    method public void setLongSupportMessage(android.content.ComponentName, java.lang.String);
     method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
+    method public void setOrganizationColor(android.content.ComponentName, int);
     method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
     method public void setPasswordHistoryLength(android.content.ComponentName, int);
@@ -5981,6 +6057,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 setShortSupportMessage(android.content.ComponentName, java.lang.String);
     method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
     method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
@@ -5996,6 +6073,7 @@
     field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
     field public static final java.lang.String ACTION_PROVISION_MANAGED_DEVICE = "android.app.action.PROVISION_MANAGED_DEVICE";
     field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
+    field public static final java.lang.String ACTION_SET_NEW_PARENT_PROFILE_PASSWORD = "android.app.action.SET_NEW_PARENT_PROFILE_PASSWORD";
     field public static final java.lang.String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
     field public static final java.lang.String ACTION_SET_PROFILE_OWNER = "android.app.action.SET_PROFILE_OWNER";
     field public static final java.lang.String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
@@ -6060,6 +6138,7 @@
     field public static final int PERMISSION_POLICY_PROMPT = 0; // 0x0
     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 WIPE_EXTERNAL_STORAGE = 1; // 0x1
     field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
   }
@@ -6181,6 +6260,7 @@
     method public void onCreate();
     method public void onDestroy();
     method public void onFullBackup(android.app.backup.FullBackupDataOutput) throws java.io.IOException;
+    method public void onQuotaExceeded(long, long);
     method public abstract void onRestore(android.app.backup.BackupDataInput, int, android.os.ParcelFileDescriptor) throws java.io.IOException;
     method public void onRestoreFile(android.os.ParcelFileDescriptor, long, java.io.File, int, long, long) throws java.io.IOException;
     method public void onRestoreFinished();
@@ -6230,12 +6310,37 @@
     method public static void dataChanged(java.lang.String);
     method public long getAvailableRestoreToken(java.lang.String);
     method public java.lang.String getCurrentTransport();
+    method public boolean isAppEligibleForBackup(java.lang.String);
     method public boolean isBackupEnabled();
     method public java.lang.String[] listAllTransports();
+    method public int requestBackup(java.lang.String[], android.app.backup.BackupObserver);
     method public int requestRestore(android.app.backup.RestoreObserver);
     method public java.lang.String selectBackupTransport(java.lang.String);
     method public void setAutoRestore(boolean);
     method public void setBackupEnabled(boolean);
+    field public static final int ERROR_AGENT_FAILURE = -1003; // 0xfffffc15
+    field public static final int ERROR_BACKUP_NOT_ALLOWED = -2001; // 0xfffff82f
+    field public static final int ERROR_PACKAGE_NOT_FOUND = -2002; // 0xfffff82e
+    field public static final int ERROR_TRANSPORT_ABORTED = -1000; // 0xfffffc18
+    field public static final int ERROR_TRANSPORT_PACKAGE_REJECTED = -1002; // 0xfffffc16
+    field public static final int ERROR_TRANSPORT_QUOTA_EXCEEDED = -1005; // 0xfffffc13
+    field public static final int SUCCESS = 0; // 0x0
+  }
+
+  public abstract class BackupObserver {
+    ctor public BackupObserver();
+    method public void backupFinished(int);
+    method public void onResult(java.lang.String, int);
+    method public void onUpdate(java.lang.String, android.app.backup.BackupProgress);
+  }
+
+  public class BackupProgress implements android.os.Parcelable {
+    ctor public BackupProgress(long, long);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.backup.BackupProgress> CREATOR;
+    field public final long bytesExpected;
+    field public final long bytesTransferred;
   }
 
   public class BackupTransport {
@@ -6251,14 +6356,18 @@
     method public int finishBackup();
     method public void finishRestore();
     method public android.app.backup.RestoreSet[] getAvailableRestoreSets();
+    method public long getBackupQuota(java.lang.String, boolean);
     method public android.os.IBinder getBinder();
     method public long getCurrentRestoreSet();
     method public int getNextFullRestoreDataChunk(android.os.ParcelFileDescriptor);
     method public int getRestoreData(android.os.ParcelFileDescriptor);
     method public int initializeDevice();
+    method public boolean isAppEligibleForBackup(android.content.pm.PackageInfo, boolean);
     method public java.lang.String name();
     method public android.app.backup.RestoreDescription nextRestorePackage();
+    method public int performBackup(android.content.pm.PackageInfo, android.os.ParcelFileDescriptor, int);
     method public int performBackup(android.content.pm.PackageInfo, android.os.ParcelFileDescriptor);
+    method public int performFullBackup(android.content.pm.PackageInfo, android.os.ParcelFileDescriptor, int);
     method public int performFullBackup(android.content.pm.PackageInfo, android.os.ParcelFileDescriptor);
     method public long requestBackupTime();
     method public long requestFullBackupTime();
@@ -6267,11 +6376,13 @@
     method public java.lang.String transportDirName();
     field public static final int AGENT_ERROR = -1003; // 0xfffffc15
     field public static final int AGENT_UNKNOWN = -1004; // 0xfffffc14
+    field public static final int FLAG_USER_INITIATED = 1; // 0x1
     field public static final int NO_MORE_DATA = -1; // 0xffffffff
     field public static final int TRANSPORT_ERROR = -1000; // 0xfffffc18
     field public static final int TRANSPORT_NOT_INITIALIZED = -1001; // 0xfffffc17
     field public static final int TRANSPORT_OK = 0; // 0x0
     field public static final int TRANSPORT_PACKAGE_REJECTED = -1002; // 0xfffffc16
+    field public static final int TRANSPORT_QUOTA_EXCEEDED = -1005; // 0xfffffc13
   }
 
   public class FileBackupHelper extends android.app.backup.FileBackupHelperBase implements android.app.backup.BackupHelper {
@@ -6339,6 +6450,7 @@
     method public int describeContents();
     method public int getBackoffPolicy();
     method public android.os.PersistableBundle getExtras();
+    method public long getFlexMillis();
     method public int getId();
     method public long getInitialBackoffMillis();
     method public long getIntervalMillis();
@@ -6346,6 +6458,7 @@
     method public long getMinLatencyMillis();
     method public int getNetworkType();
     method public android.content.ComponentName getService();
+    method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
     method public boolean isPeriodic();
     method public boolean isPersisted();
     method public boolean isRequireCharging();
@@ -6356,6 +6469,8 @@
     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
@@ -6363,22 +6478,36 @@
 
   public static final class JobInfo.Builder {
     ctor public JobInfo.Builder(int, android.content.ComponentName);
+    method public android.app.job.JobInfo.Builder addTriggerContentUri(android.app.job.JobInfo.TriggerContentUri);
     method public android.app.job.JobInfo build();
     method public android.app.job.JobInfo.Builder setBackoffCriteria(long, int);
     method public android.app.job.JobInfo.Builder setExtras(android.os.PersistableBundle);
     method public android.app.job.JobInfo.Builder setMinimumLatency(long);
     method public android.app.job.JobInfo.Builder setOverrideDeadline(long);
     method public android.app.job.JobInfo.Builder setPeriodic(long);
+    method public android.app.job.JobInfo.Builder setPeriodic(long, long);
     method public android.app.job.JobInfo.Builder setPersisted(boolean);
     method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
     method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
     method public android.app.job.JobInfo.Builder setRequiresDeviceIdle(boolean);
   }
 
+  public static final class JobInfo.TriggerContentUri implements android.os.Parcelable {
+    ctor public JobInfo.TriggerContentUri(android.net.Uri, int);
+    method public int describeContents();
+    method public int getFlags();
+    method public android.net.Uri getUri();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.job.JobInfo.TriggerContentUri> CREATOR;
+    field public static final int FLAG_NOTIFY_FOR_DESCENDANTS = 1; // 0x1
+  }
+
   public class JobParameters implements android.os.Parcelable {
     method public int describeContents();
     method public android.os.PersistableBundle getExtras();
     method public int getJobId();
+    method public java.lang.String[] getTriggeredContentAuthorities();
+    method public android.net.Uri[] getTriggeredContentUris();
     method public boolean isOverrideDeadlineExpired();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.job.JobParameters> CREATOR;
@@ -6429,6 +6558,8 @@
   public static class NetworkStats.Bucket {
     ctor public NetworkStats.Bucket();
     method public long getEndTimeStamp();
+    method public int getMetering();
+    method public int getRoaming();
     method public long getRxBytes();
     method public long getRxPackets();
     method public long getStartTimeStamp();
@@ -6436,6 +6567,12 @@
     method public long getTxBytes();
     method public long getTxPackets();
     method public int getUid();
+    field public static final int METERING_ALL = -1; // 0xffffffff
+    field public static final int METERING_DEFAULT = 1; // 0x1
+    field public static final int METERING_METERED = 2; // 0x2
+    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 STATE_ALL = -1; // 0xffffffff
     field public static final int STATE_DEFAULT = 1; // 0x1
     field public static final int STATE_FOREGROUND = 2; // 0x2
@@ -6630,6 +6767,31 @@
 
 }
 
+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 {
@@ -7371,6 +7533,15 @@
     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 {
@@ -7443,6 +7614,8 @@
     method public void flushPendingScanResults(android.bluetooth.le.ScanCallback);
     method public void startScan(android.bluetooth.le.ScanCallback);
     method public void startScan(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
+    method public void startScanFromSource(android.os.WorkSource, android.bluetooth.le.ScanCallback);
+    method public void startScanFromSource(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.os.WorkSource, android.bluetooth.le.ScanCallback);
     method public void startTruncatedScan(java.util.List<android.bluetooth.le.TruncatedFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
     method public void stopScan(android.bluetooth.le.ScanCallback);
   }
@@ -7815,11 +7988,12 @@
     method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
   }
 
-  public class ContentProviderClient {
+  public class ContentProviderClient implements java.lang.AutoCloseable {
     method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
     method public int bulkInsert(android.net.Uri, android.content.ContentValues[]) throws android.os.RemoteException;
     method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException;
     method public final android.net.Uri canonicalize(android.net.Uri) throws android.os.RemoteException;
+    method public void close();
     method public int delete(android.net.Uri, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
     method public android.content.ContentProvider getLocalContentProvider();
     method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String) throws android.os.RemoteException;
@@ -7833,7 +8007,7 @@
     method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
     method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) throws android.os.RemoteException;
     method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal) throws android.os.RemoteException;
-    method public boolean release();
+    method public deprecated boolean release();
     method public final android.net.Uri uncanonicalize(android.net.Uri) throws android.os.RemoteException;
     method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
   }
@@ -8147,6 +8321,7 @@
     field public static final int BIND_ALLOW_OOM_MANAGEMENT = 16; // 0x10
     field public static final int BIND_AUTO_CREATE = 1; // 0x1
     field public static final int BIND_DEBUG_UNBIND = 2; // 0x2
+    field public static final int BIND_EXTERNAL_SERVICE = -2147483648; // 0x80000000
     field public static final int BIND_IMPORTANT = 64; // 0x40
     field public static final int BIND_NOT_FOREGROUND = 4; // 0x4
     field public static final int BIND_WAIVE_PRIORITY = 32; // 0x20
@@ -8165,6 +8340,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 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";
@@ -8527,7 +8703,6 @@
     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";
     field public static final java.lang.String ACTION_ATTACH_DATA = "android.intent.action.ATTACH_DATA";
-    field public static final java.lang.String ACTION_AVAILABILITY_CHANGED = "android.intent.action.AVAILABILITY_CHANGED";
     field public static final java.lang.String ACTION_BATTERY_CHANGED = "android.intent.action.BATTERY_CHANGED";
     field public static final java.lang.String ACTION_BATTERY_LOW = "android.intent.action.BATTERY_LOW";
     field public static final java.lang.String ACTION_BATTERY_OKAY = "android.intent.action.BATTERY_OKAY";
@@ -8590,6 +8765,9 @@
     field public static final java.lang.String ACTION_NEW_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL";
     field public static final java.lang.String ACTION_OPEN_DOCUMENT = "android.intent.action.OPEN_DOCUMENT";
     field public static final java.lang.String ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE";
+    field public static final java.lang.String ACTION_OPEN_EXTERNAL_DIRECTORY = "android.intent.action.OPEN_EXTERNAL_DIRECTORY";
+    field public static final java.lang.String ACTION_PACKAGES_SUSPENDED = "android.intent.action.PACKAGES_SUSPENDED";
+    field public static final java.lang.String ACTION_PACKAGES_UNSUSPENDED = "android.intent.action.PACKAGES_UNSUSPENDED";
     field public static final java.lang.String ACTION_PACKAGE_ADDED = "android.intent.action.PACKAGE_ADDED";
     field public static final java.lang.String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
     field public static final java.lang.String ACTION_PACKAGE_DATA_CLEARED = "android.intent.action.PACKAGE_DATA_CLEARED";
@@ -8611,6 +8789,7 @@
     field public static final java.lang.String ACTION_PROVIDER_CHANGED = "android.intent.action.PROVIDER_CHANGED";
     field public static final java.lang.String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
     field public static final java.lang.String ACTION_QUICK_CLOCK = "android.intent.action.QUICK_CLOCK";
+    field public static final java.lang.String ACTION_QUICK_VIEW = "android.intent.action.QUICK_VIEW";
     field public static final java.lang.String ACTION_REBOOT = "android.intent.action.REBOOT";
     field public static final java.lang.String ACTION_RESOLVE_EPHEMERAL_PACKAGE = "android.intent.action.RESOLVE_EPHEMERAL_PACKAGE";
     field public static final java.lang.String ACTION_RUN = "android.intent.action.RUN";
@@ -8708,6 +8887,7 @@
     field public static final java.lang.String EXTRA_EPHEMERAL_FAILURE = "android.intent.extra.EPHEMERAL_FAILURE";
     field public static final java.lang.String EXTRA_EPHEMERAL_SUCCESS = "android.intent.extra.EPHEMERAL_SUCCESS";
     field public static final java.lang.String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
+    field public static final java.lang.String EXTRA_INDEX = "android.intent.extra.INDEX";
     field public static final java.lang.String EXTRA_INITIAL_INTENTS = "android.intent.extra.INITIAL_INTENTS";
     field public static final java.lang.String EXTRA_INSTALLER_PACKAGE_NAME = "android.intent.extra.INSTALLER_PACKAGE_NAME";
     field public static final java.lang.String EXTRA_INTENT = "android.intent.extra.INTENT";
@@ -9272,6 +9452,7 @@
     field public static final int FLAG_ALWAYS_RETAIN_TASK_STATE = 8; // 0x8
     field public static final int FLAG_AUTO_REMOVE_FROM_RECENTS = 8192; // 0x2000
     field public static final int FLAG_CLEAR_TASK_ON_LAUNCH = 4; // 0x4
+    field public static final int FLAG_ENABLE_VR_MODE = 32768; // 0x8000
     field public static final int FLAG_EXCLUDE_FROM_RECENTS = 32; // 0x20
     field public static final int FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS = 256; // 0x100
     field public static final int FLAG_FINISH_ON_TASK_LAUNCH = 2; // 0x2
@@ -9534,6 +9715,7 @@
 
   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 boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
     method public boolean isPackageEnabled(java.lang.String, android.os.UserHandle);
     method public void registerCallback(android.content.pm.LauncherApps.Callback);
@@ -9550,13 +9732,9 @@
     method public abstract void onPackageChanged(java.lang.String, android.os.UserHandle);
     method public abstract void onPackageRemoved(java.lang.String, android.os.UserHandle);
     method public abstract void onPackagesAvailable(java.lang.String[], android.os.UserHandle, boolean);
+    method public void onPackagesSuspended(java.lang.String[], android.os.UserHandle);
     method public abstract void onPackagesUnavailable(java.lang.String[], android.os.UserHandle, boolean);
-  }
-
-  public class ManifestDigest 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.content.pm.ManifestDigest> CREATOR;
+    method public void onPackagesUnsuspended(java.lang.String[], android.os.UserHandle);
   }
 
   public class PackageInfo implements android.os.Parcelable {
@@ -9667,7 +9845,6 @@
     method public void setAppLabel(java.lang.CharSequence);
     method public void setAppPackageName(java.lang.String);
     method public void setGrantedRuntimePermissions(java.lang.String[]);
-    method public void setInstallFlagsQuick();
     method public void setInstallLocation(int);
     method public void setOriginatingUid(int);
     method public void setOriginatingUri(android.net.Uri);
@@ -9741,8 +9918,6 @@
     method public abstract int getComponentEnabledSetting(android.content.ComponentName);
     method public abstract android.graphics.drawable.Drawable getDefaultActivityIcon();
     method public abstract android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
-    method public abstract byte[] getEphemeralCookie();
-    method public abstract int getEphemeralCookieMaxSizeBytes();
     method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
     method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
     method public abstract java.lang.String getInstallerPackageName(java.lang.String);
@@ -9752,8 +9927,10 @@
     method public abstract java.lang.String getNameForUid(int);
     method public android.content.pm.PackageInfo getPackageArchiveInfo(java.lang.String, int);
     method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.PackageInstaller getPackageInstaller();
+    method public abstract int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.lang.String[] getPackagesForUid(int);
     method public abstract java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int);
     method public abstract int getPermissionFlags(java.lang.String, java.lang.String, android.os.UserHandle);
@@ -9776,10 +9953,10 @@
     method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
     method public abstract void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
     method public abstract boolean hasSystemFeature(java.lang.String);
-    method public abstract boolean isEphemeralApplication();
     method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
     method public abstract boolean isSafeMode();
     method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
+    method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceiversAsUser(android.content.Intent, int, android.os.UserHandle);
     method public abstract java.util.List<android.content.pm.ProviderInfo> queryContentProviders(java.lang.String, int, int);
     method public abstract java.util.List<android.content.pm.InstrumentationInfo> queryInstrumentation(java.lang.String, int);
     method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentActivities(android.content.Intent, int);
@@ -9796,7 +9973,6 @@
     method public abstract void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
     method public abstract void setApplicationEnabledSetting(java.lang.String, int, int);
     method public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int);
-    method public abstract boolean setEphemeralCookie(byte[]);
     method public abstract void setInstallerPackageName(java.lang.String, java.lang.String);
     method public abstract void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle);
     method public abstract void verifyIntentFilter(int, int, java.util.List<java.lang.String>);
@@ -9833,6 +10009,7 @@
     field public static final java.lang.String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
     field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
     field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
+    field public static final java.lang.String FEATURE_ETHERNET = "android.hardware.ethernet";
     field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch";
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
@@ -9853,6 +10030,7 @@
     field public static final java.lang.String FEATURE_MIDI = "android.software.midi";
     field public static final java.lang.String FEATURE_NFC = "android.hardware.nfc";
     field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION = "android.hardware.nfc.hce";
+    field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION_NFCF = "android.hardware.nfc.hcef";
     field public static final java.lang.String FEATURE_OPENGLES_EXTENSION_PACK = "android.hardware.opengles.aep";
     field public static final java.lang.String FEATURE_PICTURE_IN_PICTURE = "android.software.picture_in_picture";
     field public static final java.lang.String FEATURE_PRINTING = "android.software.print";
@@ -9884,15 +10062,15 @@
     field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
     field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host";
     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_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";
     field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
     field public static final int GET_ACTIVITIES = 1; // 0x1
     field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
-    field public static final int GET_DISABLED_COMPONENTS = 512; // 0x200
-    field public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
-    field public static final int GET_ENCRYPTION_UNAWARE_COMPONENTS = 262144; // 0x40000
+    field public static final deprecated int GET_DISABLED_COMPONENTS = 512; // 0x200
+    field public static final deprecated int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
     field public static final int GET_GIDS = 256; // 0x100
     field public static final int GET_INSTRUMENTATION = 16; // 0x10
     field public static final int GET_INTENT_FILTERS = 32; // 0x20
@@ -9904,7 +10082,7 @@
     field public static final int GET_SERVICES = 4; // 0x4
     field public static final int GET_SHARED_LIBRARY_FILES = 1024; // 0x400
     field public static final int GET_SIGNATURES = 64; // 0x40
-    field public static final int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
+    field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
     field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
     field public static final int INSTALL_FAILED_ALREADY_EXISTS = -1; // 0xffffffff
     field public static final int INSTALL_FAILED_CONFLICTING_PROVIDER = -13; // 0xfffffff3
@@ -9945,6 +10123,13 @@
     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_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
     field public static final int PERMISSION_DENIED = -1; // 0xffffffff
     field public static final int PERMISSION_GRANTED = 0; // 0x0
@@ -10171,7 +10356,7 @@
     method public final long skip(long) throws java.io.IOException;
   }
 
-  public class ColorStateList implements android.os.Parcelable {
+  public class ColorStateList extends android.content.res.ComplexColor 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;
@@ -10180,13 +10365,18 @@
     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);
@@ -10290,6 +10480,11 @@
     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);
@@ -10334,7 +10529,6 @@
     method public java.lang.String getQuantityString(int, int, java.lang.Object...) throws android.content.res.Resources.NotFoundException;
     method public java.lang.String getQuantityString(int, int) throws android.content.res.Resources.NotFoundException;
     method public java.lang.CharSequence getQuantityText(int, int) throws android.content.res.Resources.NotFoundException;
-    method public java.util.Locale getResolvedLocale();
     method public java.lang.String getResourceEntryName(int) throws android.content.res.Resources.NotFoundException;
     method public java.lang.String getResourceName(int) throws android.content.res.Resources.NotFoundException;
     method public java.lang.String getResourcePackageName(int) throws android.content.res.Resources.NotFoundException;
@@ -10350,6 +10544,7 @@
     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;
@@ -10385,6 +10580,7 @@
     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);
@@ -10966,6 +11162,7 @@
     method public void setVersion(int);
     method public int update(java.lang.String, android.content.ContentValues, java.lang.String, java.lang.String[]);
     method public int updateWithOnConflict(java.lang.String, android.content.ContentValues, java.lang.String, java.lang.String[], int);
+    method public void validateSql(java.lang.String, android.os.CancellationSignal);
     method public deprecated boolean yieldIfContended();
     method public boolean yieldIfContendedSafely();
     method public boolean yieldIfContendedSafely(long);
@@ -11200,7 +11397,7 @@
     field public final int statusCode;
   }
 
-  public class DrmManagerClient {
+  public class DrmManagerClient implements java.lang.AutoCloseable {
     ctor public DrmManagerClient(android.content.Context);
     method public android.drm.DrmInfo acquireDrmInfo(android.drm.DrmInfoRequest);
     method public int acquireRights(android.drm.DrmInfoRequest);
@@ -11210,6 +11407,7 @@
     method public int checkRightsStatus(android.net.Uri);
     method public int checkRightsStatus(java.lang.String, int);
     method public int checkRightsStatus(android.net.Uri, int);
+    method public void close();
     method public android.drm.DrmConvertedStatus closeConvertSession(int);
     method public android.drm.DrmConvertedStatus convertData(int, byte[]);
     method public java.lang.String[] getAvailableDrmEngines();
@@ -11223,7 +11421,7 @@
     method public java.lang.String getOriginalMimeType(android.net.Uri);
     method public int openConvertSession(java.lang.String);
     method public int processDrmInfo(android.drm.DrmInfo);
-    method public void release();
+    method public deprecated void release();
     method public int removeAllRights();
     method public int removeRights(java.lang.String);
     method public int removeRights(android.net.Uri);
@@ -11627,14 +11825,14 @@
 
   public static class BitmapFactory.Options {
     ctor public BitmapFactory.Options();
-    method public void requestCancelDecode();
+    method public deprecated void requestCancelDecode();
     field public android.graphics.Bitmap inBitmap;
     field public int inDensity;
-    field public boolean inDither;
+    field public deprecated boolean inDither;
     field public deprecated boolean inInputShareable;
     field public boolean inJustDecodeBounds;
     field public boolean inMutable;
-    field public boolean inPreferQualityOverSpeed;
+    field public deprecated boolean inPreferQualityOverSpeed;
     field public android.graphics.Bitmap.Config inPreferredConfig;
     field public boolean inPremultiplied;
     field public deprecated boolean inPurgeable;
@@ -11643,7 +11841,7 @@
     field public int inScreenDensity;
     field public int inTargetDensity;
     field public byte[] inTempStorage;
-    field public boolean mCancel;
+    field public deprecated boolean mCancel;
     field public int outHeight;
     field public java.lang.String outMimeType;
     field public int outWidth;
@@ -13082,6 +13280,7 @@
     method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
     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 {
@@ -13578,6 +13777,7 @@
     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 isDataInjectionSupported();
@@ -13588,22 +13788,27 @@
     field public static final int REPORTING_MODE_SPECIAL_TRIGGER = 3; // 0x3
     field public static final java.lang.String STRING_TYPE_ACCELEROMETER = "android.sensor.accelerometer";
     field public static final java.lang.String STRING_TYPE_AMBIENT_TEMPERATURE = "android.sensor.ambient_temperature";
+    field public static final java.lang.String STRING_TYPE_DYNAMIC_SENSOR_META = "android.sensor.dynamic_sensor_meta";
     field public static final java.lang.String STRING_TYPE_GAME_ROTATION_VECTOR = "android.sensor.game_rotation_vector";
     field public static final java.lang.String STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR = "android.sensor.geomagnetic_rotation_vector";
     field public static final java.lang.String STRING_TYPE_GRAVITY = "android.sensor.gravity";
     field public static final java.lang.String STRING_TYPE_GYROSCOPE = "android.sensor.gyroscope";
     field public static final java.lang.String STRING_TYPE_GYROSCOPE_UNCALIBRATED = "android.sensor.gyroscope_uncalibrated";
+    field public static final java.lang.String STRING_TYPE_HEART_BEAT = "android.sensor.heart_beat";
     field public static final java.lang.String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
     field public static final java.lang.String STRING_TYPE_LIGHT = "android.sensor.light";
     field public static final java.lang.String STRING_TYPE_LINEAR_ACCELERATION = "android.sensor.linear_acceleration";
     field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD = "android.sensor.magnetic_field";
     field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED = "android.sensor.magnetic_field_uncalibrated";
+    field public static final java.lang.String STRING_TYPE_MOTION_DETECT = "android.sensor.motion_detect";
     field public static final deprecated java.lang.String STRING_TYPE_ORIENTATION = "android.sensor.orientation";
+    field public static final java.lang.String STRING_TYPE_POSE_6DOF = "android.sensor.pose_6dof";
     field public static final java.lang.String STRING_TYPE_PRESSURE = "android.sensor.pressure";
     field public static final java.lang.String STRING_TYPE_PROXIMITY = "android.sensor.proximity";
     field public static final java.lang.String STRING_TYPE_RELATIVE_HUMIDITY = "android.sensor.relative_humidity";
     field public static final java.lang.String STRING_TYPE_ROTATION_VECTOR = "android.sensor.rotation_vector";
     field public static final java.lang.String STRING_TYPE_SIGNIFICANT_MOTION = "android.sensor.significant_motion";
+    field public static final java.lang.String STRING_TYPE_STATIONARY_DETECT = "android.sensor.stationary_detect";
     field public static final java.lang.String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
     field public static final java.lang.String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
     field public static final deprecated java.lang.String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
@@ -13611,28 +13816,48 @@
     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_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
     field public static final int TYPE_GRAVITY = 9; // 0x9
     field public static final int TYPE_GYROSCOPE = 4; // 0x4
     field public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16; // 0x10
+    field public static final int TYPE_HEART_BEAT = 31; // 0x1f
     field public static final int TYPE_HEART_RATE = 21; // 0x15
     field public static final int TYPE_LIGHT = 5; // 0x5
     field public static final int TYPE_LINEAR_ACCELERATION = 10; // 0xa
     field public static final int TYPE_MAGNETIC_FIELD = 2; // 0x2
     field public static final int TYPE_MAGNETIC_FIELD_UNCALIBRATED = 14; // 0xe
+    field public static final int TYPE_MOTION_DETECT = 30; // 0x1e
     field public static final deprecated int TYPE_ORIENTATION = 3; // 0x3
+    field public static final int TYPE_POSE_6DOF = 28; // 0x1c
     field public static final int TYPE_PRESSURE = 6; // 0x6
     field public static final int TYPE_PROXIMITY = 8; // 0x8
     field public static final int TYPE_RELATIVE_HUMIDITY = 12; // 0xc
     field public static final int TYPE_ROTATION_VECTOR = 11; // 0xb
     field public static final int TYPE_SIGNIFICANT_MOTION = 17; // 0x11
+    field public static final int TYPE_STATIONARY_DETECT = 29; // 0x1d
     field public static final int TYPE_STEP_COUNTER = 19; // 0x13
     field public static final int TYPE_STEP_DETECTOR = 18; // 0x12
     field public static final deprecated int TYPE_TEMPERATURE = 7; // 0x7
     field public static final int TYPE_WRIST_TILT_GESTURE = 26; // 0x1a
   }
 
+  public class SensorAdditionalInfo {
+    field public static final int TYPE_FRAME_BEGIN = 0; // 0x0
+    field public static final int TYPE_FRAME_END = 1; // 0x1
+    field public static final int TYPE_INTERNAL_TEMPERATURE = 65537; // 0x10001
+    field public static final int TYPE_SAMPLING = 65540; // 0x10004
+    field public static final int TYPE_SENSOR_PLACEMENT = 65539; // 0x10003
+    field public static final int TYPE_UNTRACKED_DELAY = 65536; // 0x10000
+    field public static final int TYPE_VEC3_CALIBRATION = 65538; // 0x10002
+    field public final float[] floatValues;
+    field public final int[] intValues;
+    field public final android.hardware.Sensor sensor;
+    field public final int serial;
+    field public final int type;
+  }
+
   public class SensorEvent {
     field public int accuracy;
     field public android.hardware.Sensor sensor;
@@ -13640,6 +13865,14 @@
     field public final float[] values;
   }
 
+  public abstract class SensorEventCallback implements android.hardware.SensorEventListener2 {
+    ctor public SensorEventCallback();
+    method public void onAccuracyChanged(android.hardware.Sensor, int);
+    method public void onFlushCompleted(android.hardware.Sensor);
+    method public void onSensorAdditionalInfo(android.hardware.SensorAdditionalInfo);
+    method public void onSensorChanged(android.hardware.SensorEvent);
+  }
+
   public abstract interface SensorEventListener {
     method public abstract void onAccuracyChanged(android.hardware.Sensor, int);
     method public abstract void onSensorChanged(android.hardware.SensorEvent);
@@ -13661,6 +13894,7 @@
     method public static void getAngleChange(float[], float[], float[]);
     method public android.hardware.Sensor getDefaultSensor(int);
     method public android.hardware.Sensor getDefaultSensor(int, boolean);
+    method public java.util.List<android.hardware.Sensor> getDynamicSensorList(int);
     method public static float getInclination(float[]);
     method public static float[] getOrientation(float[], float[]);
     method public static void getQuaternionFromVector(float[], float[]);
@@ -13670,6 +13904,8 @@
     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 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);
@@ -13678,6 +13914,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 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);
@@ -13742,6 +13979,12 @@
     field public static final float STANDARD_GRAVITY = 9.80665f;
   }
 
+  public static abstract class SensorManager.DynamicSensorConnectionCallback {
+    ctor public SensorManager.DynamicSensorConnectionCallback();
+    method public void onDynamicSensorConnected(android.hardware.Sensor);
+    method public void onDynamicSensorDisconnected(android.hardware.Sensor);
+  }
+
   public final class TriggerEvent {
     field public android.hardware.Sensor sensor;
     field public long timestamp;
@@ -13826,6 +14069,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AF;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AWB;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Integer>> CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> DEPTH_DEPTH_IS_EXCLUSIVE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> EDGE_AVAILABLE_EDGE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> FLASH_INFO_AVAILABLE;
@@ -13905,9 +14149,11 @@
     method public abstract void close();
     method public abstract android.hardware.camera2.CaptureRequest.Builder createCaptureRequest(int) throws android.hardware.camera2.CameraAccessException;
     method public abstract void createCaptureSession(java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method public abstract void createCaptureSessionByOutputConfiguration(java.util.List<android.hardware.camera2.params.OutputConfiguration>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract void createConstrainedHighSpeedCaptureSession(java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract android.hardware.camera2.CaptureRequest.Builder createReprocessCaptureRequest(android.hardware.camera2.TotalCaptureResult) throws android.hardware.camera2.CameraAccessException;
     method public abstract void createReprocessableCaptureSession(android.hardware.camera2.params.InputConfiguration, java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method public abstract void createReprocessableCaptureSessionWithConfigurations(android.hardware.camera2.params.InputConfiguration, java.util.List<android.hardware.camera2.params.OutputConfiguration>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract java.lang.String getId();
     field public static final int TEMPLATE_MANUAL = 6; // 0x6
     field public static final int TEMPLATE_PREVIEW = 1; // 0x1
@@ -14064,6 +14310,7 @@
     field public static final int HOT_PIXEL_MODE_FAST = 1; // 0x1
     field public static final int HOT_PIXEL_MODE_HIGH_QUALITY = 2; // 0x2
     field public static final int HOT_PIXEL_MODE_OFF = 0; // 0x0
+    field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_3 = 3; // 0x3
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1; // 0x1
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY = 2; // 0x2
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0; // 0x0
@@ -14185,6 +14432,7 @@
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_CAPTURE_INTENT;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_EFFECT_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_POST_RAW_SENSITIVITY_BOOST;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_SCENE_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_VIDEO_STABILIZATION_MODE;
     field public static final android.os.Parcelable.Creator<android.hardware.camera2.CaptureRequest> CREATOR;
@@ -14263,6 +14511,7 @@
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_CAPTURE_INTENT;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_EFFECT_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_POST_RAW_SENSITIVITY_BOOST;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_SCENE_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_VIDEO_STABILIZATION_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> EDGE_MODE;
@@ -14404,6 +14653,24 @@
     field public static final int METERING_WEIGHT_MIN = 0; // 0x0
   }
 
+  public final class OutputConfiguration implements android.os.Parcelable {
+    ctor public OutputConfiguration(android.view.Surface);
+    ctor public OutputConfiguration(android.view.Surface, int);
+    ctor public OutputConfiguration(android.hardware.camera2.params.OutputConfiguration);
+    method public int describeContents();
+    method public int getRotation();
+    method public android.view.Surface getSurface();
+    method public int getSurfaceSetId();
+    method public void setSurfaceSetId(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
+    field public static final int ROTATION_0 = 0; // 0x0
+    field public static final int ROTATION_180 = 2; // 0x2
+    field public static final int ROTATION_270 = 3; // 0x3
+    field public static final int ROTATION_90 = 1; // 0x1
+    field public static final int SURFACE_SET_ID_INVALID = -1; // 0xffffffff
+  }
+
   public final class RggbChannelVector {
     ctor public RggbChannelVector(float, float, float, float);
     method public void copyTo(float[], int);
@@ -14857,6 +15124,66 @@
 
 package android.hardware.location {
 
+  public class ContextHubInfo {
+    ctor public ContextHubInfo();
+    method public int describeContents();
+    method public int getId();
+    method public android.hardware.location.MemoryRegion[] getMemoryRegions();
+    method public java.lang.String getName();
+    method public float getPeakMips();
+    method public float getPeakPowerDrawMw();
+    method public int getPlatformVersion();
+    method public float getSleepPowerDrawMw();
+    method public int getStaticSwVersion();
+    method public float getStoppedPowerDrawMw();
+    method public int[] getSupportedSensors();
+    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 android.hardware.location.NanoAppInstanceInfo getNanoAppInstanceInfo(int);
+    method public int loadNanoApp(int, android.hardware.location.NanoApp);
+    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
+  }
+
+  public class ContextHubMessage {
+    ctor public ContextHubMessage(int, int, byte[]);
+    method public int describeContents();
+    method public byte[] getData();
+    method public int getMsgType();
+    method public int getVersion();
+    method public void setMsgData(byte[]);
+    method public void setMsgType(int);
+    method public void setVersion(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.hardware.location.ContextHubMessage> CREATOR;
+  }
+
   public final class GeofenceHardware {
     ctor public GeofenceHardware(android.hardware.location.IGeofenceHardware);
     method public boolean addGeofence(int, int, android.hardware.location.GeofenceHardwareRequest, android.hardware.location.GeofenceHardwareCallback);
@@ -14973,6 +15300,89 @@
     method public abstract void onMonitoringSystemChange(android.hardware.location.GeofenceHardwareMonitorEvent) throws android.os.RemoteException;
   }
 
+  public class MemoryRegion implements android.os.Parcelable {
+    ctor public MemoryRegion(android.os.Parcel);
+    method public int describeContents();
+    method public int getCapacityBytes();
+    method public int getFreeCapacityBytes();
+    method public boolean isExecutable();
+    method public boolean isReadable();
+    method public boolean isWritable();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.hardware.location.MemoryRegion> CREATOR;
+  }
+
+  public class NanoApp {
+    ctor public NanoApp();
+    method public int describeContents();
+    method public byte[] getAppBinary();
+    method public int getAppId();
+    method public int getAppVersion();
+    method public java.lang.String getName();
+    method public int getNeededExecMemBytes();
+    method public int getNeededReadMemBytes();
+    method public int[] getNeededSensors();
+    method public int getNeededWriteMemBytes();
+    method public int[] getOutputEvents();
+    method public java.lang.String getPublisher();
+    method public void setAppBinary(byte[]);
+    method public void setAppId(int);
+    method public void setAppVersion(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.NanoApp> CREATOR;
+  }
+
+  public class NanoAppFilter {
+    ctor public NanoAppFilter(long, int, int, long);
+    method public int describeContents();
+    method public boolean testMatch(android.hardware.location.NanoAppInstanceInfo);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int APP_ANY = -1; // 0xffffffff
+    field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppFilter> CREATOR;
+    field public static final int FLAGS_VERSION_ANY = -1; // 0xffffffff
+    field public static final int FLAGS_VERSION_GREAT_THAN = 2; // 0x2
+    field public static final int FLAGS_VERSION_LESS_THAN = 4; // 0x4
+    field public static final int FLAGS_VERSION_STRICTLY_EQUAL = 8; // 0x8
+    field public static final int HUB_ANY = -1; // 0xffffffff
+    field public static final int VENDOR_ANY = -1; // 0xffffffff
+  }
+
+  public class NanoAppInstanceInfo {
+    ctor public NanoAppInstanceInfo();
+    method public int describeContents();
+    method public int getAppId();
+    method public int getAppVersion();
+    method public int getContexthubId();
+    method public int getHandle();
+    method public java.lang.String getName();
+    method public int getNeededExecMemBytes();
+    method public int getNeededReadMemBytes();
+    method public int[] getNeededSensors();
+    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;
+  }
+
 }
 
 package android.hardware.radio {
@@ -19230,7 +19640,6 @@
     method public static java.lang.String getCanonicalID(java.lang.String, boolean[]);
     method public int getDSTSavings();
     method public static android.icu.util.TimeZone getDefault();
-    method public static int getDefaultTimeZoneType();
     method public final java.lang.String getDisplayName();
     method public final java.lang.String getDisplayName(java.util.Locale);
     method public final java.lang.String getDisplayName(android.icu.util.ULocale);
@@ -19254,8 +19663,6 @@
     method public abstract boolean inDaylightTime(java.util.Date);
     method public boolean isFrozen();
     method public boolean observesDaylightTime();
-    method public static synchronized void setDefault(android.icu.util.TimeZone);
-    method public static synchronized void setDefaultTimeZoneType(int);
     method public void setID(java.lang.String);
     method public abstract void setRawOffset(int);
     method public abstract boolean useDaylightTime();
@@ -19268,8 +19675,6 @@
     field public static final int SHORT_COMMONLY_USED = 6; // 0x6
     field public static final int SHORT_GENERIC = 2; // 0x2
     field public static final int SHORT_GMT = 4; // 0x4
-    field public static final int TIMEZONE_ICU = 0; // 0x0
-    field public static final int TIMEZONE_JDK = 1; // 0x1
     field public static final android.icu.util.TimeZone UNKNOWN_ZONE;
     field public static final java.lang.String UNKNOWN_ZONE_ID = "Etc/Unknown";
   }
@@ -19365,8 +19770,6 @@
     method public static java.lang.String getVariant(java.lang.String);
     method public boolean isRightToLeft();
     method public static android.icu.util.ULocale minimizeSubtags(android.icu.util.ULocale);
-    method public static synchronized void setDefault(android.icu.util.ULocale);
-    method public static synchronized void setDefault(android.icu.util.ULocale.Category, android.icu.util.ULocale);
     method public android.icu.util.ULocale setKeywordValue(java.lang.String, java.lang.String);
     method public static java.lang.String setKeywordValue(java.lang.String, java.lang.String, java.lang.String);
     method public java.lang.String toLanguageTag();
@@ -19854,7 +20257,38 @@
     method public static boolean isPresent();
   }
 
-  public class GpsClock implements android.os.Parcelable {
+  public abstract interface GnssNmeaListener {
+    method public abstract void onNmeaReceived(long, java.lang.String);
+  }
+
+  public final class GnssStatus {
+    method public float getAzimuth(int);
+    method public int getConstellationType(int);
+    method public float getElevation(int);
+    method public int getNumSatellites();
+    method public int getPrn(int);
+    method public float getSnr(int);
+    method public boolean hasAlmanac(int);
+    method public boolean hasEphemeris(int);
+    method public boolean usedInFix(int);
+    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 {
+    ctor public GnssStatusCallback();
+    method public void onFirstFix(int);
+    method public void onSatelliteStatusChanged(android.location.GnssStatus);
+    method public void onStarted();
+    method public void onStopped();
+  }
+
+  public final class GpsClock implements android.os.Parcelable {
     method public int describeContents();
     method public double getBiasInNs();
     method public double getBiasUncertaintyInNs();
@@ -19863,6 +20297,7 @@
     method public long getFullBiasInNs();
     method public short getLeapSecond();
     method public long getTimeInNs();
+    method public long getTimeOfLastHwClockDiscontinuityInNs();
     method public double getTimeUncertaintyInNs();
     method public byte getType();
     method public boolean hasBiasInNs();
@@ -19888,16 +20323,20 @@
     method public void setFullBiasInNs(long);
     method public void setLeapSecond(short);
     method public void setTimeInNs(long);
+    method public void setTimeOfLastHwClockDiscontinuityInNs(long);
     method public void setTimeUncertaintyInNs(double);
     method public void setType(byte);
     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.GpsClock> CREATOR;
-    field public static final byte TYPE_GPS_TIME = 2; // 0x2
-    field public static final byte TYPE_LOCAL_HW_TIME = 1; // 0x1
-    field public static final byte TYPE_UNKNOWN = 0; // 0x0
   }
 
-  public class GpsMeasurement implements android.os.Parcelable {
+  public static abstract class GpsClock.GpsClockType implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsMeasurement implements android.os.Parcelable {
     method public int describeContents();
     method public double getAccumulatedDeltaRangeInMeters();
     method public short getAccumulatedDeltaRangeState();
@@ -19920,6 +20359,8 @@
     method public byte getMultipathIndicator();
     method public byte getPrn();
     method public double getPseudorangeInMeters();
+    method public double getPseudorangeRateCarrierInMetersPerSec();
+    method public double getPseudorangeRateCarrierUncertaintyInMetersPerSec();
     method public double getPseudorangeRateInMetersPerSec();
     method public double getPseudorangeRateUncertaintyInMetersPerSec();
     method public double getPseudorangeUncertaintyInMeters();
@@ -19988,6 +20429,8 @@
     method public void setMultipathIndicator(byte);
     method public void setPrn(byte);
     method public void setPseudorangeInMeters(double);
+    method public void setPseudorangeRateCarrierInMetersPerSec(double);
+    method public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double);
     method public void setPseudorangeRateInMetersPerSec(double);
     method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
     method public void setPseudorangeUncertaintyInMeters(double);
@@ -20018,7 +20461,13 @@
     field public static final short STATE_UNKNOWN = 0; // 0x0
   }
 
-  public class GpsMeasurementsEvent implements android.os.Parcelable {
+  public static abstract class GpsMeasurement.LossOfLockStatus implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract class GpsMeasurement.MultipathIndicator implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsMeasurementsEvent implements android.os.Parcelable {
     ctor public GpsMeasurementsEvent(android.location.GpsClock, android.location.GpsMeasurement[]);
     method public int describeContents();
     method public android.location.GpsClock getClock();
@@ -20030,12 +20479,16 @@
     field public static final int STATUS_READY = 1; // 0x1
   }
 
-  public static abstract interface GpsMeasurementsEvent.Listener {
-    method public abstract void onGpsMeasurementsReceived(android.location.GpsMeasurementsEvent);
-    method public abstract void onStatusChanged(int);
+  public static abstract class GpsMeasurementsEvent.Callback {
+    ctor public GpsMeasurementsEvent.Callback();
+    method public void onGpsMeasurementsReceived(android.location.GpsMeasurementsEvent);
+    method public void onStatusChanged(int);
   }
 
-  public class GpsNavigationMessage implements android.os.Parcelable {
+  public static abstract class GpsMeasurementsEvent.GpsMeasurementsStatus implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsNavigationMessage implements android.os.Parcelable {
     method public int describeContents();
     method public byte[] getData();
     method public short getMessageId();
@@ -20053,30 +20506,37 @@
     method public void setType(byte);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessage> CREATOR;
+    field public static final byte MESSAGE_TYPE_CNAV2 = 4; // 0x4
+    field public static final byte MESSAGE_TYPE_L1CA = 1; // 0x1
+    field public static final byte MESSAGE_TYPE_L2CNAV = 2; // 0x2
+    field public static final byte MESSAGE_TYPE_L5CNAV = 3; // 0x3
+    field public static final byte 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
-    field public static final byte TYPE_CNAV2 = 4; // 0x4
-    field public static final byte TYPE_L1CA = 1; // 0x1
-    field public static final byte TYPE_L2CNAV = 2; // 0x2
-    field public static final byte TYPE_L5CNAV = 3; // 0x3
-    field public static final byte TYPE_UNKNOWN = 0; // 0x0
   }
 
-  public class GpsNavigationMessageEvent implements android.os.Parcelable {
+  public static abstract class GpsNavigationMessage.GpsNavigationMessageType implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsNavigationMessageEvent implements android.os.Parcelable {
     ctor public GpsNavigationMessageEvent(android.location.GpsNavigationMessage);
     method public int describeContents();
     method public android.location.GpsNavigationMessage getNavigationMessage();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessageEvent> CREATOR;
-    field public static int STATUS_GPS_LOCATION_DISABLED;
-    field public static int STATUS_NOT_SUPPORTED;
-    field public static int STATUS_READY;
+    field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
+    field public static final int STATUS_READY = 1; // 0x1
   }
 
-  public static abstract interface GpsNavigationMessageEvent.Listener {
-    method public abstract void onGpsNavigationMessageReceived(android.location.GpsNavigationMessageEvent);
-    method public abstract void onStatusChanged(int);
+  public static abstract class GpsNavigationMessageEvent.Callback {
+    ctor public GpsNavigationMessageEvent.Callback();
+    method public void onGpsNavigationMessageReceived(android.location.GpsNavigationMessageEvent);
+    method public void onStatusChanged(int);
+  }
+
+  public static abstract class GpsNavigationMessageEvent.GpsNavigationMessageStatus implements java.lang.annotation.Annotation {
   }
 
   public final class GpsSatellite {
@@ -20183,10 +20643,10 @@
   }
 
   public class LocationManager {
-    method public boolean addGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
-    method public boolean addGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
-    method public boolean addGpsStatusListener(android.location.GpsStatus.Listener);
-    method public boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public deprecated boolean addGpsStatusListener(android.location.GpsStatus.Listener);
+    method public deprecated boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public boolean addNmeaListener(android.location.GnssNmeaListener);
+    method public boolean addNmeaListener(android.location.GnssNmeaListener, android.os.Handler);
     method public void addProximityAlert(double, double, float, long, android.app.PendingIntent);
     method public void addTestProvider(java.lang.String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
     method public void clearTestProviderEnabled(java.lang.String);
@@ -20194,16 +20654,21 @@
     method public void clearTestProviderStatus(java.lang.String);
     method public java.util.List<java.lang.String> getAllProviders();
     method public java.lang.String getBestProvider(android.location.Criteria, boolean);
-    method public android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
+    method public deprecated android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
     method public android.location.Location getLastKnownLocation(java.lang.String);
     method public android.location.LocationProvider getProvider(java.lang.String);
     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 void removeGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
-    method public void removeGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
-    method public void removeGpsStatusListener(android.location.GpsStatus.Listener);
-    method public void removeNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback);
+    method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback, android.os.Handler);
+    method public boolean registerGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback);
+    method public boolean registerGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback, android.os.Handler);
+    method public boolean registerGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback);
+    method public boolean registerGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback, android.os.Handler);
+    method public deprecated void removeGpsStatusListener(android.location.GpsStatus.Listener);
+    method public deprecated void removeNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public void removeNmeaListener(android.location.GnssNmeaListener);
     method public void removeProximityAlert(android.app.PendingIntent);
     method public void removeTestProvider(java.lang.String);
     method public void removeUpdates(android.location.LocationListener);
@@ -20223,6 +20688,9 @@
     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 unregisterGnssStatusCallback(android.location.GnssStatusCallback);
+    method public void unregisterGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback);
+    method public void unregisterGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback);
     field public static final java.lang.String GPS_PROVIDER = "gps";
     field public static final java.lang.String KEY_LOCATION_CHANGED = "location";
     field public static final java.lang.String KEY_PROVIDER_ENABLED = "providerEnabled";
@@ -20329,6 +20797,7 @@
     field public static final int FLAG_BYPASS_MUTE = 128; // 0x80
     field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
     field public static final int FLAG_HW_HOTWORD = 32; // 0x20
+    field public static final int FLAG_LOW_LATENCY = 256; // 0x100
     field public static final int USAGE_ALARM = 4; // 0x4
     field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
     field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc
@@ -20462,6 +20931,7 @@
     field public static final int ENCODING_DTS = 7; // 0x7
     field public static final int ENCODING_DTS_HD = 8; // 0x8
     field public static final int ENCODING_E_AC3 = 6; // 0x6
+    field public static final int ENCODING_IEC61937 = 13; // 0xd
     field public static final int ENCODING_INVALID = 0; // 0x0
     field public static final int ENCODING_PCM_16BIT = 2; // 0x2
     field public static final int ENCODING_PCM_8BIT = 3; // 0x3
@@ -20486,6 +20956,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.AudioDeviceInfo[] getDevices(int);
     method public int getMode();
     method public java.lang.String getParameters(java.lang.String);
@@ -20510,6 +20981,7 @@
     method public void playSoundEffect(int, float);
     method public void registerAudioDeviceCallback(android.media.AudioDeviceCallback, android.os.Handler);
     method public int registerAudioPolicy(android.media.audiopolicy.AudioPolicy);
+    method public void registerAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback, android.os.Handler);
     method public deprecated void registerMediaButtonEventReceiver(android.content.ComponentName);
     method public deprecated void registerMediaButtonEventReceiver(android.app.PendingIntent);
     method public deprecated void registerRemoteControlClient(android.media.RemoteControlClient);
@@ -20536,6 +21008,7 @@
     method public void unloadSoundEffects();
     method public void unregisterAudioDeviceCallback(android.media.AudioDeviceCallback);
     method public void unregisterAudioPolicyAsync(android.media.audiopolicy.AudioPolicy);
+    method public void unregisterAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback);
     method public deprecated void unregisterMediaButtonEventReceiver(android.content.ComponentName);
     method public deprecated void unregisterMediaButtonEventReceiver(android.app.PendingIntent);
     method public deprecated void unregisterRemoteControlClient(android.media.RemoteControlClient);
@@ -20601,6 +21074,7 @@
     field public static final deprecated int NUM_STREAMS = 5; // 0x5
     field public static final java.lang.String PROPERTY_OUTPUT_FRAMES_PER_BUFFER = "android.media.property.OUTPUT_FRAMES_PER_BUFFER";
     field public static final java.lang.String PROPERTY_OUTPUT_SAMPLE_RATE = "android.media.property.OUTPUT_SAMPLE_RATE";
+    field public static final java.lang.String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED = "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED";
     field public static final java.lang.String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND = "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND";
     field public static final java.lang.String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND = "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND";
     field public static final java.lang.String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED";
@@ -20634,14 +21108,20 @@
     field public static final deprecated int VIBRATE_TYPE_RINGER = 0; // 0x0
   }
 
+  public static abstract class AudioManager.AudioRecordingCallback {
+    ctor public AudioManager.AudioRecordingCallback();
+    method public void onRecordConfigChanged();
+  }
+
   public static abstract interface AudioManager.OnAudioFocusChangeListener {
     method public abstract void onAudioFocusChange(int);
   }
 
-  public class AudioRecord {
+  public class AudioRecord implements android.media.AudioRouting {
     ctor public AudioRecord(int, int, int, int, int) throws java.lang.IllegalArgumentException;
     ctor public AudioRecord(android.media.AudioAttributes, android.media.AudioFormat, int, int) throws java.lang.IllegalArgumentException;
-    method public void addOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener, android.os.Handler);
+    method public deprecated void addOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener, android.os.Handler);
+    method public void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
     method public int getAudioFormat();
     method public int getAudioSessionId();
     method public int getAudioSource();
@@ -20665,7 +21145,8 @@
     method public int read(java.nio.ByteBuffer, int);
     method public int read(java.nio.ByteBuffer, int, int);
     method public void release();
-    method public void removeOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener);
+    method public deprecated void removeOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener);
+    method public void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
     method public int setNotificationMarkerPosition(int);
     method public int setPositionNotificationPeriod(int);
     method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
@@ -20705,21 +21186,45 @@
     method public abstract void onRoutingChanged(android.media.AudioRecord);
   }
 
+  public class AudioRecordConfiguration implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.media.AudioDeviceInfo getAudioDevice();
+    method public int getClientAudioSessionId();
+    method public int getClientAudioSource();
+    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;
+  }
+
+  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 void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
+    method public abstract boolean setPreferredDevice(android.media.AudioDeviceInfo);
+  }
+
+  public static abstract interface AudioRouting.OnRoutingChangedListener {
+    method public abstract void onRoutingChanged(android.media.AudioRouting);
+  }
+
   public final class AudioTimestamp {
     ctor public AudioTimestamp();
     field public long framePosition;
     field public long nanoTime;
   }
 
-  public class AudioTrack {
+  public class AudioTrack implements android.media.AudioRouting {
     ctor public AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
     ctor public AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
     ctor public AudioTrack(android.media.AudioAttributes, android.media.AudioFormat, int, int, int) throws java.lang.IllegalArgumentException;
-    method public void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
+    method public deprecated void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
+    method public void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
     method public int attachAuxEffect(int);
     method public void flush();
     method public int getAudioFormat();
     method public int getAudioSessionId();
+    method public int getBufferCapacityInFrames();
     method public int getBufferSizeInFrames();
     method public int getChannelConfiguration();
     method public int getChannelCount();
@@ -20741,12 +21246,15 @@
     method public int getState();
     method public int getStreamType();
     method public boolean getTimestamp(android.media.AudioTimestamp);
+    method public int getUnderrunCount();
     method public void pause() throws java.lang.IllegalStateException;
     method public void play() throws java.lang.IllegalStateException;
     method public void release();
     method public int reloadStaticData();
-    method public void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
+    method public deprecated void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
+    method public void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
     method public int setAuxEffectSendLevel(float);
+    method public int setBufferSizeInFrames(int);
     method public int setLoopPoints(int, int, int);
     method public int setNotificationMarkerPosition(int);
     method public int setPlaybackHeadPosition(int);
@@ -20798,8 +21306,8 @@
     method public abstract void onPeriodicNotification(android.media.AudioTrack);
   }
 
-  public static abstract interface AudioTrack.OnRoutingChangedListener {
-    method public abstract void onRoutingChanged(android.media.AudioTrack);
+  public static abstract deprecated interface AudioTrack.OnRoutingChangedListener {
+    method public abstract deprecated void onRoutingChanged(android.media.AudioTrack);
   }
 
   public class CamcorderProfile {
@@ -20858,6 +21366,16 @@
     ctor public DeniedByServerException(java.lang.String);
   }
 
+  public abstract class DrmInitData {
+    ctor public DrmInitData();
+    method public abstract android.media.DrmInitData.SchemeInitData get(java.util.UUID);
+  }
+
+  public static final class DrmInitData.SchemeInitData {
+    field public final byte[] data;
+    field public final java.lang.String mimeType;
+  }
+
   public class ExifInterface {
     ctor public ExifInterface(java.lang.String) throws java.io.IOException;
     method public double getAltitude(double);
@@ -21205,6 +21723,7 @@
     field public static final deprecated int COLOR_QCOM_FormatYUV420SemiPlanar = 2141391872; // 0x7fa30c00
     field public static final deprecated int COLOR_TI_FormatYUV420PackedSemiPlanar = 2130706688; // 0x7f000100
     field public static final java.lang.String FEATURE_AdaptivePlayback = "adaptive-playback";
+    field public static final java.lang.String FEATURE_IntraRefresh = "intra-refresh";
     field public static final java.lang.String FEATURE_SecurePlayback = "secure-playback";
     field public static final java.lang.String FEATURE_TunneledPlayback = "tunneled-playback";
     field public int[] colorFormats;
@@ -21247,6 +21766,21 @@
     field public static final int AVCProfileHigh422 = 32; // 0x20
     field public static final int AVCProfileHigh444 = 64; // 0x40
     field public static final int AVCProfileMain = 2; // 0x2
+    field public static final int DolbyVisionLevelFhd24 = 4; // 0x4
+    field public static final int DolbyVisionLevelFhd30 = 8; // 0x8
+    field public static final int DolbyVisionLevelFhd60 = 16; // 0x10
+    field public static final int DolbyVisionLevelHd24 = 1; // 0x1
+    field public static final int DolbyVisionLevelHd30 = 2; // 0x2
+    field public static final int DolbyVisionLevelUhd24 = 32; // 0x20
+    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 H263Level10 = 1; // 0x1
     field public static final int H263Level20 = 2; // 0x2
     field public static final int H263Level30 = 4; // 0x4
@@ -21331,6 +21865,24 @@
     field public static final int VP8Level_Version2 = 4; // 0x4
     field public static final int VP8Level_Version3 = 8; // 0x8
     field public static final int VP8ProfileMain = 1; // 0x1
+    field public static final int VP9Level1 = 0; // 0x0
+    field public static final int VP9Level11 = 1; // 0x1
+    field public static final int VP9Level2 = 2; // 0x2
+    field public static final int VP9Level21 = 4; // 0x4
+    field public static final int VP9Level3 = 8; // 0x8
+    field public static final int VP9Level31 = 16; // 0x10
+    field public static final int VP9Level4 = 32; // 0x20
+    field public static final int VP9Level41 = 64; // 0x40
+    field public static final int VP9Level5 = 128; // 0x80
+    field public static final int VP9Level51 = 256; // 0x100
+    field public static final int VP9Level52 = 512; // 0x200
+    field public static final int VP9Level6 = 1024; // 0x400
+    field public static final int VP9Level61 = 2048; // 0x800
+    field public static final int VP9Level62 = 4096; // 0x1000
+    field public static final int VP9Profile0 = 0; // 0x0
+    field public static final int VP9Profile1 = 1; // 0x1
+    field public static final int VP9Profile2 = 2; // 0x2
+    field public static final int VP9Profile3 = 3; // 0x3
     field public int level;
     field public int profile;
   }
@@ -21514,6 +22066,7 @@
     ctor public MediaExtractor();
     method public boolean advance();
     method public long getCachedDuration();
+    method public android.media.DrmInitData getDrmInitData();
     method public java.util.Map<java.util.UUID, byte[]> getPsshInfo();
     method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo);
     method public int getSampleFlags();
@@ -21558,6 +22111,16 @@
     method public final void setInteger(java.lang.String, int);
     method public final void setLong(java.lang.String, long);
     method public final void setString(java.lang.String, java.lang.String);
+    field public static final int COLOR_RANGE_FULL = 1; // 0x1
+    field public static final int COLOR_RANGE_LIMITED = 2; // 0x2
+    field public static final int COLOR_STANDARD_BT2020 = 6; // 0x6
+    field public static final int COLOR_STANDARD_BT601_NTSC = 4; // 0x4
+    field public static final int COLOR_STANDARD_BT601_PAL = 2; // 0x2
+    field public static final int COLOR_STANDARD_BT709 = 1; // 0x1
+    field public static final int COLOR_TRANSFER_HLG = 7; // 0x7
+    field public static final int COLOR_TRANSFER_LINEAR = 1; // 0x1
+    field public static final int COLOR_TRANSFER_SDR_VIDEO = 3; // 0x3
+    field public static final int COLOR_TRANSFER_ST2084 = 6; // 0x6
     field public static final java.lang.String KEY_AAC_DRC_ATTENUATION_FACTOR = "aac-drc-cut-level";
     field public static final java.lang.String KEY_AAC_DRC_BOOST_FACTOR = "aac-drc-boost-level";
     field public static final java.lang.String KEY_AAC_DRC_HEAVY_COMPRESSION = "aac-drc-heavy-compression";
@@ -21573,11 +22136,15 @@
     field public static final java.lang.String KEY_CHANNEL_COUNT = "channel-count";
     field public static final java.lang.String KEY_CHANNEL_MASK = "channel-mask";
     field public static final java.lang.String KEY_COLOR_FORMAT = "color-format";
+    field public static final java.lang.String KEY_COLOR_RANGE = "color-range";
+    field public static final java.lang.String KEY_COLOR_STANDARD = "color-standard";
+    field public static final java.lang.String KEY_COLOR_TRANSFER = "color-transfer";
     field public static final java.lang.String KEY_COMPLEXITY = "complexity";
     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_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";
     field public static final java.lang.String KEY_IS_AUTOSELECT = "is-autoselect";
     field public static final java.lang.String KEY_IS_DEFAULT = "is-default";
@@ -21617,8 +22184,7 @@
     field public static final java.lang.String MIMETYPE_TEXT_CEA_608 = "text/cea-608";
     field public static final java.lang.String MIMETYPE_TEXT_VTT = "text/vtt";
     field public static final java.lang.String MIMETYPE_VIDEO_AVC = "video/avc";
-    field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_AVC = "video/dolby-avc";
-    field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_HEVC = "video/dolby-hevc";
+    field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision";
     field public static final java.lang.String MIMETYPE_VIDEO_H263 = "video/3gpp";
     field public static final java.lang.String MIMETYPE_VIDEO_HEVC = "video/hevc";
     field public static final java.lang.String MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
@@ -21900,9 +22466,11 @@
     method public static final int getAudioSourceMax();
     method public int getMaxAmplitude() throws java.lang.IllegalStateException;
     method public android.view.Surface getSurface();
+    method public void pause() throws java.lang.IllegalStateException;
     method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
     method public void release();
     method public void reset();
+    method public void resume() throws java.lang.IllegalStateException;
     method public void setAudioChannels(int);
     method public void setAudioEncoder(int) throws java.lang.IllegalStateException;
     method public void setAudioEncodingBitRate(int);
@@ -21953,6 +22521,7 @@
     field public static final int MIC = 1; // 0x1
     field public static final int RADIO_TUNER = 1998; // 0x7ce
     field public static final int REMOTE_SUBMIX = 8; // 0x8
+    field public static final int UNPROCESSED = 9; // 0x9
     field public static final int VOICE_CALL = 4; // 0x4
     field public static final int VOICE_COMMUNICATION = 7; // 0x7
     field public static final int VOICE_DOWNLINK = 3; // 0x3
@@ -21983,6 +22552,7 @@
     field public static final int DEFAULT = 0; // 0x0
     field public static final int H263 = 1; // 0x1
     field public static final int H264 = 2; // 0x2
+    field public static final int HEVC = 5; // 0x5
     field public static final int MPEG_4_SP = 3; // 0x3
     field public static final int VP8 = 4; // 0x4
   }
@@ -22879,12 +23449,15 @@
   public class AudioMixingRule {
     field public static final int RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET = 2; // 0x2
     field public static final int RULE_MATCH_ATTRIBUTE_USAGE = 1; // 0x1
+    field public static final int RULE_MATCH_UID = 4; // 0x4
   }
 
   public static class AudioMixingRule.Builder {
     ctor public AudioMixingRule.Builder();
+    method public android.media.audiopolicy.AudioMixingRule.Builder addMixRule(int, java.lang.Object) throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioMixingRule.Builder addRule(android.media.AudioAttributes, int) throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioMixingRule build();
+    method public android.media.audiopolicy.AudioMixingRule.Builder excludeMixRule(int, java.lang.Object) throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioMixingRule.Builder excludeRule(android.media.AudioAttributes, int) throws java.lang.IllegalArgumentException;
   }
 
@@ -22939,7 +23512,11 @@
     method public android.media.session.MediaSession.Token getSessionToken();
     method public boolean isConnected();
     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);
+    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";
   }
 
   public static class MediaBrowser.ConnectionCallback {
@@ -22972,7 +23549,9 @@
   public static abstract class MediaBrowser.SubscriptionCallback {
     ctor public MediaBrowser.SubscriptionCallback();
     method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>);
+    method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>, android.os.Bundle);
     method public void onError(java.lang.String);
+    method public void onError(java.lang.String, android.os.Bundle);
   }
 
 }
@@ -23258,6 +23837,7 @@
     method public void setRatingType(int);
     method public void setSessionActivity(android.app.PendingIntent);
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+    field public static final int FLAG_HANDLES_PREPARE_ONLY = 4; // 0x4
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
   }
 
@@ -23336,6 +23916,7 @@
     field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
     field public static final long ACTION_STOP = 1L; // 0x1L
     field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR;
+    field public static final java.lang.String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
     field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
     field public static final int STATE_BUFFERING = 6; // 0x6
     field public static final int STATE_CONNECTING = 8; // 0x8
@@ -23384,6 +23965,38 @@
 
 }
 
+package android.media.soundtrigger {
+
+  public final class SoundTriggerDetector {
+    method public boolean startRecognition();
+    method public boolean stopRecognition();
+  }
+
+  public abstract class SoundTriggerDetector.Callback {
+    ctor public SoundTriggerDetector.Callback();
+    method public abstract void onAvailabilityChanged(int);
+    method public abstract void onDetected();
+    method public abstract void onError();
+    method public abstract void onRecognitionPaused();
+    method public abstract void onRecognitionResumed();
+  }
+
+  public final class SoundTriggerManager {
+    method public android.media.soundtrigger.SoundTriggerDetector createSoundTriggerDetector(java.util.UUID, android.media.soundtrigger.SoundTriggerDetector.Callback, android.os.Handler);
+    method public void deleteModel(java.util.UUID);
+    method public android.media.soundtrigger.SoundTriggerManager.Model getModel(java.util.UUID);
+    method public void updateModel(android.media.soundtrigger.SoundTriggerManager.Model);
+  }
+
+  public static class SoundTriggerManager.Model {
+    method public static android.media.soundtrigger.SoundTriggerManager.Model create(java.util.UUID, java.util.UUID, byte[]);
+    method public byte[] getModelData();
+    method public java.util.UUID getModelUuid();
+    method public java.util.UUID getVendorUuid();
+  }
+
+}
+
 package android.media.tv {
 
   public final class TvContentRating {
@@ -23420,6 +24033,7 @@
     method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri);
     method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
     method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
+    method public static final android.net.Uri buildRecordedProgramUri(long);
     method public static final boolean isChannelUriForPassthroughInput(android.net.Uri);
     field public static final java.lang.String AUTHORITY = "android.media.tv";
   }
@@ -23560,6 +24174,40 @@
     field public static final java.lang.String TRAVEL = "TRAVEL";
   }
 
+  public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseTvColumns {
+    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+    field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
+    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_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";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    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_RECORDING_DATA_BYTES = "recording_data_bytes";
+    field public static final java.lang.String COLUMN_RECORDING_DATA_URI = "recording_data_uri";
+    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_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";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
+    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/recorded_program";
+    field public static final android.net.Uri CONTENT_URI;
+  }
+
   public static final class TvContract.WatchedPrograms implements android.media.tv.TvContract.BaseTvColumns {
     field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
     field public static final java.lang.String COLUMN_DESCRIPTION = "description";
@@ -23608,17 +24256,19 @@
   }
 
   public final class TvInputInfo implements android.os.Parcelable {
+    method public boolean canRecord();
     method public android.content.Intent createSettingsIntent();
     method public android.content.Intent createSetupIntent();
-    method public static android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.hardware.hdmi.HdmiDeviceInfo, java.lang.String, java.lang.String, android.net.Uri) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.hardware.hdmi.HdmiDeviceInfo, java.lang.String, int, android.graphics.drawable.Icon) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.media.tv.TvInputHardwareInfo, java.lang.String, android.net.Uri) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.media.tv.TvInputHardwareInfo, int, android.graphics.drawable.Icon) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static deprecated android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.hardware.hdmi.HdmiDeviceInfo, java.lang.String, java.lang.String, android.net.Uri) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static deprecated android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.hardware.hdmi.HdmiDeviceInfo, java.lang.String, int, android.graphics.drawable.Icon) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static deprecated android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.media.tv.TvInputHardwareInfo, java.lang.String, android.net.Uri) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static deprecated android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.media.tv.TvInputHardwareInfo, int, android.graphics.drawable.Icon) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public int describeContents();
     method public android.hardware.hdmi.HdmiDeviceInfo getHdmiDeviceInfo();
     method public java.lang.String getId();
     method public java.lang.String getParentId();
     method public android.content.pm.ServiceInfo getServiceInfo();
+    method public int getTunerCount();
     method public int getType();
     method public boolean isConnectedToHdmiSwitch();
     method public boolean isHardwareInput();
@@ -23642,6 +24292,18 @@
     field public static final int TYPE_VGA = 1005; // 0x3ed
   }
 
+  public static final class TvInputInfo.Builder {
+    ctor public TvInputInfo.Builder(android.content.Context, java.lang.Class<?>);
+    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 setLabel(int);
+    method public android.media.tv.TvInputInfo.Builder setParentId(java.lang.String);
+    method public android.media.tv.TvInputInfo.Builder setTunerCount(int);
+    method public android.media.tv.TvInputInfo.Builder setTvInputHardwareInfo(android.media.tv.TvInputHardwareInfo);
+  }
+
   public static final class TvInputInfo.TvInputSettings {
     method public static java.util.Map<java.lang.String, java.lang.String> getCustomLabels(android.content.Context, int);
     method public static java.util.Set<java.lang.String> getHiddenTvInputIds(android.content.Context, int);
@@ -23653,6 +24315,7 @@
     method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
     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();
@@ -23676,6 +24339,10 @@
     field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
     field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
     field public static final java.lang.String META_DATA_CONTENT_RATING_SYSTEMS = "android.media.tv.metadata.CONTENT_RATING_SYSTEMS";
+    field public static final int RECORDING_ERROR_CONNECTION_FAILED = 1; // 0x1
+    field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 2; // 0x2
+    field public static final int RECORDING_ERROR_RESOURCE_BUSY = 3; // 0x3
+    field public static final int RECORDING_ERROR_UNKNOWN = 0; // 0x0
     field public static final long TIME_SHIFT_INVALID_TIME = -9223372036854775808L; // 0x8000000000000000L
     field public static final int TIME_SHIFT_STATUS_AVAILABLE = 3; // 0x3
     field public static final int TIME_SHIFT_STATUS_UNAVAILABLE = 2; // 0x2
@@ -23740,16 +24407,19 @@
     method public void onInputRemoved(java.lang.String);
     method public void onInputStateChanged(java.lang.String, int);
     method public void onInputUpdated(java.lang.String);
+    method public void onTvInputInfoChanged(android.media.tv.TvInputInfo);
   }
 
   public abstract class TvInputService extends android.app.Service {
     ctor public TvInputService();
     method public final android.os.IBinder onBind(android.content.Intent);
+    method public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(java.lang.String);
     method public abstract android.media.tv.TvInputService.Session onCreateSession(java.lang.String);
     method public android.media.tv.TvInputInfo onHardwareAdded(android.media.tv.TvInputHardwareInfo);
     method public java.lang.String onHardwareRemoved(android.media.tv.TvInputHardwareInfo);
     method public android.media.tv.TvInputInfo onHdmiDeviceAdded(android.hardware.hdmi.HdmiDeviceInfo);
     method public java.lang.String onHdmiDeviceRemoved(android.hardware.hdmi.HdmiDeviceInfo);
+    method public static final void setTvInputInfo(android.content.Context, android.media.tv.TvInputInfo);
     field public static final java.lang.String SERVICE_INTERFACE = "android.media.tv.TvInputService";
     field public static final java.lang.String SERVICE_META_DATA = "android.media.tv.input";
   }
@@ -23762,6 +24432,21 @@
     method public final boolean onSetSurface(android.view.Surface);
   }
 
+  public static abstract class TvInputService.RecordingSession {
+    ctor public TvInputService.RecordingSession(android.content.Context);
+    method public void notifyConnected();
+    method public void notifyError(int);
+    method public void notifyRecordingStarted();
+    method public void notifyRecordingStopped(android.net.Uri);
+    method public void notifySessionEvent(java.lang.String, android.os.Bundle);
+    method public void onAppPrivateCommand(java.lang.String, android.os.Bundle);
+    method public abstract void onConnect(android.net.Uri);
+    method public void onConnect(android.net.Uri, android.os.Bundle);
+    method public abstract void onDisconnect();
+    method public abstract void onStartRecording();
+    method public abstract void onStopRecording();
+  }
+
   public static abstract class TvInputService.Session implements android.view.KeyEvent.Callback {
     ctor public TvInputService.Session(android.content.Context);
     method public void layoutSurface(int, int, int, int);
@@ -23792,6 +24477,7 @@
     method public long onTimeShiftGetCurrentPosition();
     method public long onTimeShiftGetStartPosition();
     method public void onTimeShiftPause();
+    method public void onTimeShiftPlay(android.net.Uri);
     method public void onTimeShiftResume();
     method public void onTimeShiftSeekTo(long);
     method public void onTimeShiftSetPlaybackParams(android.media.PlaybackParams);
@@ -23803,8 +24489,29 @@
     method public void setOverlayViewEnabled(boolean);
   }
 
+  public class TvRecordingClient {
+    ctor public TvRecordingClient(android.content.Context, java.lang.String, android.media.tv.TvRecordingClient.RecordingCallback, android.os.Handler);
+    method public void connect(java.lang.String, android.net.Uri);
+    method public void connect(java.lang.String, android.net.Uri, android.os.Bundle);
+    method public void disconnect();
+    method public void sendAppPrivateCommand(java.lang.String, android.os.Bundle);
+    method public void startRecording();
+    method public void stopRecording();
+  }
+
+  public class TvRecordingClient.RecordingCallback {
+    ctor public TvRecordingClient.RecordingCallback();
+    method public void onConnected();
+    method public void onDisconnected();
+    method public void onError(int);
+    method public void onEvent(java.lang.String, java.lang.String, android.os.Bundle);
+    method public void onRecordingStarted();
+    method public void onRecordingStopped(android.net.Uri);
+  }
+
   public class TvStreamConfig implements android.os.Parcelable {
     method public int describeContents();
+    method public int getFlags();
     method public int getGeneration();
     method public int getMaxHeight();
     method public int getMaxWidth();
@@ -23812,6 +24519,7 @@
     method public int getType();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.media.tv.TvStreamConfig> CREATOR;
+    field public static final int FLAG_MASK_SIGNAL_DETECTION = 1; // 0x1
     field public static final int STREAM_TYPE_BUFFER_PRODUCER = 2; // 0x2
     field public static final int STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE = 1; // 0x1
   }
@@ -23819,6 +24527,7 @@
   public static final class TvStreamConfig.Builder {
     ctor public TvStreamConfig.Builder();
     method public android.media.tv.TvStreamConfig build();
+    method public android.media.tv.TvStreamConfig.Builder flags(int);
     method public android.media.tv.TvStreamConfig.Builder generation(int);
     method public android.media.tv.TvStreamConfig.Builder maxHeight(int);
     method public android.media.tv.TvStreamConfig.Builder maxWidth(int);
@@ -23882,6 +24591,7 @@
     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);
@@ -23924,6 +24634,24 @@
     ctor public MtpConstants();
     method public static boolean isAbstractObject(int);
     field public static final int ASSOCIATION_TYPE_GENERIC_FOLDER = 1; // 0x1
+    field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001
+    field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d
+    field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008
+    field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006
+    field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b
+    field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002
+    field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007
+    field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801
+    field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802
+    field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803
+    field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003
+    field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009
+    field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c
+    field public static final int EVENT_STORE_ADDED = 16388; // 0x4004
+    field public static final int EVENT_STORE_FULL = 16394; // 0x400a
+    field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005
+    field public static final int EVENT_UNDEFINED = 16384; // 0x4000
+    field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e
     field public static final int FORMAT_3GP_CONTAINER = 47492; // 0xb984
     field public static final int FORMAT_AAC = 47363; // 0xb903
     field public static final int FORMAT_ABSTRACT_AUDIO_ALBUM = 47619; // 0xba03
@@ -23942,6 +24670,8 @@
     field public static final int FORMAT_AUDIBLE = 47364; // 0xb904
     field public static final int FORMAT_AVI = 12298; // 0x300a
     field public static final int FORMAT_BMP = 14340; // 0x3804
+    field public static final int FORMAT_DEFINED = 14336; // 0x3800
+    field public static final int FORMAT_DNG = 14353; // 0x3811
     field public static final int FORMAT_DPOF = 12294; // 0x3006
     field public static final int FORMAT_EXECUTABLE = 12291; // 0x3003
     field public static final int FORMAT_EXIF_JPEG = 14337; // 0x3801
@@ -23980,6 +24710,42 @@
     field public static final int FORMAT_WMV = 47489; // 0xb981
     field public static final int FORMAT_WPL_PLAYLIST = 47632; // 0xba10
     field public static final int FORMAT_XML_DOCUMENT = 47746; // 0xba82
+    field public static final int OPERATION_CLOSE_SESSION = 4099; // 0x1003
+    field public static final int OPERATION_COPY_OBJECT = 4122; // 0x101a
+    field public static final int OPERATION_DELETE_OBJECT = 4107; // 0x100b
+    field public static final int OPERATION_FORMAT_STORE = 4111; // 0x100f
+    field public static final int OPERATION_GET_DEVICE_INFO = 4097; // 0x1001
+    field public static final int OPERATION_GET_DEVICE_PROP_DESC = 4116; // 0x1014
+    field public static final int OPERATION_GET_DEVICE_PROP_VALUE = 4117; // 0x1015
+    field public static final int OPERATION_GET_NUM_OBJECTS = 4102; // 0x1006
+    field public static final int OPERATION_GET_OBJECT = 4105; // 0x1009
+    field public static final int OPERATION_GET_OBJECT_HANDLES = 4103; // 0x1007
+    field public static final int OPERATION_GET_OBJECT_INFO = 4104; // 0x1008
+    field public static final int OPERATION_GET_OBJECT_PROPS_SUPPORTED = 38913; // 0x9801
+    field public static final int OPERATION_GET_OBJECT_PROP_DESC = 38914; // 0x9802
+    field public static final int OPERATION_GET_OBJECT_PROP_VALUE = 38915; // 0x9803
+    field public static final int OPERATION_GET_OBJECT_REFERENCES = 38928; // 0x9810
+    field public static final int OPERATION_GET_PARTIAL_OBJECT = 4123; // 0x101b
+    field public static final int OPERATION_GET_PARTIAL_OBJECT_64 = 38337; // 0x95c1
+    field public static final int OPERATION_GET_STORAGE_INFO = 4101; // 0x1005
+    field public static final int OPERATION_GET_STORAGE_I_DS = 4100; // 0x1004
+    field public static final int OPERATION_GET_THUMB = 4106; // 0x100a
+    field public static final int OPERATION_INITIATE_CAPTURE = 4110; // 0x100e
+    field public static final int OPERATION_INITIATE_OPEN_CAPTURE = 4124; // 0x101c
+    field public static final int OPERATION_MOVE_OBJECT = 4121; // 0x1019
+    field public static final int OPERATION_OPEN_SESSION = 4098; // 0x1002
+    field public static final int OPERATION_POWER_DOWN = 4115; // 0x1013
+    field public static final int OPERATION_RESET_DEVICE = 4112; // 0x1010
+    field public static final int OPERATION_RESET_DEVICE_PROP_VALUE = 4119; // 0x1017
+    field public static final int OPERATION_SELF_TEST = 4113; // 0x1011
+    field public static final int OPERATION_SEND_OBJECT = 4109; // 0x100d
+    field public static final int OPERATION_SEND_OBJECT_INFO = 4108; // 0x100c
+    field public static final int OPERATION_SET_DEVICE_PROP_VALUE = 4118; // 0x1016
+    field public static final int OPERATION_SET_OBJECT_PROP_VALUE = 38916; // 0x9804
+    field public static final int OPERATION_SET_OBJECT_PROTECTION = 4114; // 0x1012
+    field public static final int OPERATION_SET_OBJECT_REFERENCES = 38929; // 0x9811
+    field public static final int OPERATION_SKIP = 38944; // 0x9820
+    field public static final int OPERATION_TERMINATE_OPEN_CAPTURE = 4120; // 0x1018
     field public static final int PROTECTION_STATUS_NONE = 0; // 0x0
     field public static final int PROTECTION_STATUS_NON_TRANSFERABLE_DATA = 32771; // 0x8003
     field public static final int PROTECTION_STATUS_READ_ONLY = 32769; // 0x8001
@@ -23997,6 +24763,8 @@
     method public int[] getObjectHandles(int, int, int);
     method public android.mtp.MtpObjectInfo getObjectInfo(int);
     method public long getParent(int);
+    method public long getPartialObject(int, long, long, byte[]) throws java.io.IOException;
+    method public long getPartialObject64(int, long, long, byte[]) throws java.io.IOException;
     method public long getStorageId(int);
     method public int[] getStorageIds();
     method public android.mtp.MtpStorageInfo getStorageInfo(int);
@@ -24005,61 +24773,62 @@
     method public boolean importFile(int, android.os.ParcelFileDescriptor);
     method public boolean open(android.hardware.usb.UsbDeviceConnection);
     method public android.mtp.MtpEvent readEvent(android.os.CancellationSignal);
-    method public boolean sendObject(int, int, android.os.ParcelFileDescriptor);
+    method public boolean sendObject(int, long, android.os.ParcelFileDescriptor);
     method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo);
   }
 
   public class MtpDeviceInfo {
+    method public final int[] getEventsSupported();
     method public final java.lang.String getManufacturer();
     method public final java.lang.String getModel();
+    method public final int[] getOperationsSupported();
     method public final java.lang.String getSerialNumber();
     method public final java.lang.String getVersion();
   }
 
   public class MtpEvent {
     ctor public MtpEvent();
+    method public int getDevicePropCode();
     method public int getEventCode();
-    field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001
-    field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d
-    field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008
-    field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006
-    field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b
-    field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002
-    field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007
-    field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801
-    field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802
-    field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803
-    field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003
-    field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009
-    field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c
-    field public static final int EVENT_STORE_ADDED = 16388; // 0x4004
-    field public static final int EVENT_STORE_FULL = 16394; // 0x400a
-    field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005
-    field public static final int EVENT_UNDEFINED = 16384; // 0x4000
-    field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e
+    method public int getObjectFormatCode();
+    method public int getObjectHandle();
+    method public int getObjectPropCode();
+    method public int getParameter1();
+    method public int getParameter2();
+    method public int getParameter3();
+    method public int getStorageId();
+    method public int getTransactionId();
   }
 
   public final class MtpObjectInfo {
     method public final int getAssociationDesc();
     method public final int getAssociationType();
     method public final int getCompressedSize();
+    method public final long getCompressedSizeLong();
     method public final long getDateCreated();
     method public final long getDateModified();
     method public final int getFormat();
     method public final int getImagePixDepth();
+    method public final long getImagePixDepthLong();
     method public final int getImagePixHeight();
+    method public final long getImagePixHeightLong();
     method public final int getImagePixWidth();
+    method public final long getImagePixWidthLong();
     method public final java.lang.String getKeywords();
     method public final java.lang.String getName();
     method public final int getObjectHandle();
     method public final int getParent();
     method public final int getProtectionStatus();
     method public final int getSequenceNumber();
+    method public final long getSequenceNumberLong();
     method public final int getStorageId();
     method public final int getThumbCompressedSize();
+    method public final long getThumbCompressedSizeLong();
     method public final int getThumbFormat();
     method public final int getThumbPixHeight();
+    method public final long getThumbPixHeightLong();
     method public final int getThumbPixWidth();
+    method public final long getThumbPixWidthLong();
   }
 
   public static class MtpObjectInfo.Builder {
@@ -24068,24 +24837,24 @@
     method public android.mtp.MtpObjectInfo build();
     method public android.mtp.MtpObjectInfo.Builder setAssociationDesc(int);
     method public android.mtp.MtpObjectInfo.Builder setAssociationType(int);
-    method public android.mtp.MtpObjectInfo.Builder setCompressedSize(int);
+    method public android.mtp.MtpObjectInfo.Builder setCompressedSize(long);
     method public android.mtp.MtpObjectInfo.Builder setDateCreated(long);
     method public android.mtp.MtpObjectInfo.Builder setDateModified(long);
     method public android.mtp.MtpObjectInfo.Builder setFormat(int);
-    method public android.mtp.MtpObjectInfo.Builder setImagePixDepth(int);
-    method public android.mtp.MtpObjectInfo.Builder setImagePixHeight(int);
-    method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(int);
+    method public android.mtp.MtpObjectInfo.Builder setImagePixDepth(long);
+    method public android.mtp.MtpObjectInfo.Builder setImagePixHeight(long);
+    method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(long);
     method public android.mtp.MtpObjectInfo.Builder setKeywords(java.lang.String);
     method public android.mtp.MtpObjectInfo.Builder setName(java.lang.String);
     method public android.mtp.MtpObjectInfo.Builder setObjectHandle(int);
     method public android.mtp.MtpObjectInfo.Builder setParent(int);
     method public android.mtp.MtpObjectInfo.Builder setProtectionStatus(int);
-    method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(int);
+    method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(long);
     method public android.mtp.MtpObjectInfo.Builder setStorageId(int);
-    method public android.mtp.MtpObjectInfo.Builder setThumbCompressedSize(int);
+    method public android.mtp.MtpObjectInfo.Builder setThumbCompressedSize(long);
     method public android.mtp.MtpObjectInfo.Builder setThumbFormat(int);
-    method public android.mtp.MtpObjectInfo.Builder setThumbPixHeight(int);
-    method public android.mtp.MtpObjectInfo.Builder setThumbPixWidth(int);
+    method public android.mtp.MtpObjectInfo.Builder setThumbPixHeight(long);
+    method public android.mtp.MtpObjectInfo.Builder setThumbPixWidth(long);
   }
 
   public final class MtpStorageInfo {
@@ -24117,6 +24886,7 @@
     method public android.net.Network[] getAllNetworks();
     method public deprecated boolean getBackgroundDataSetting();
     method public android.net.Network getBoundNetworkForProcess();
+    method public java.lang.String getCaptivePortalServerUrl();
     method public android.net.ProxyInfo getDefaultProxy();
     method public android.net.LinkProperties getLinkProperties(android.net.Network);
     method public android.net.NetworkCapabilities getNetworkCapabilities(android.net.Network);
@@ -24124,9 +24894,11 @@
     method public android.net.NetworkInfo getNetworkInfo(android.net.Network);
     method public deprecated int getNetworkPreference();
     method public static deprecated android.net.Network getProcessDefaultNetwork();
+    method public int getRestrictBackgroundStatus();
     method public boolean isActiveNetworkMetered();
     method public boolean isDefaultNetworkActive();
     method public static deprecated boolean isNetworkTypeValid(int);
+    method public boolean isTetheringSupported();
     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);
@@ -24139,7 +24911,10 @@
     method public deprecated boolean requestRouteToHost(int, int);
     method public deprecated void setNetworkPreference(int);
     method public static deprecated boolean setProcessDefaultNetwork(android.net.Network);
+    method public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
+    method public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
     method public deprecated int startUsingNetworkFeature(int, java.lang.String);
+    method public void stopTethering(int);
     method public deprecated int stopUsingNetworkFeature(int, java.lang.String);
     method public void unregisterNetworkCallback(android.net.ConnectivityManager.NetworkCallback);
     method public void unregisterNetworkCallback(android.app.PendingIntent);
@@ -24158,6 +24933,12 @@
     field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity";
     field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
     field public static final java.lang.String EXTRA_REASON = "reason";
+    field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
+    field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
+    field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
+    field public static final int TETHERING_BLUETOOTH = 2; // 0x2
+    field public static final int TETHERING_USB = 1; // 0x1
+    field public static final int TETHERING_WIFI = 0; // 0x0
     field public static final int TYPE_BLUETOOTH = 7; // 0x7
     field public static final int TYPE_DUMMY = 8; // 0x8
     field public static final int TYPE_ETHERNET = 9; // 0x9
@@ -24184,6 +24965,12 @@
     method public abstract void onNetworkActive();
   }
 
+  public static abstract class ConnectivityManager.OnStartTetheringCallback {
+    ctor public ConnectivityManager.OnStartTetheringCallback();
+    method public void onTetheringFailed();
+    method public void onTetheringStarted();
+  }
+
   public class Credentials {
     ctor public Credentials(int, int, int);
     method public int getGid();
@@ -25412,6 +26199,7 @@
   public static class WifiConfiguration.KeyMgmt {
     field public static final int IEEE8021X = 3; // 0x3
     field public static final int NONE = 0; // 0x0
+    field public static final int WPA2_PSK = 4; // 0x4
     field public static final int WPA_EAP = 2; // 0x2
     field public static final int WPA_PSK = 1; // 0x1
     field public static final java.lang.String[] strings;
@@ -25462,6 +26250,7 @@
     method public java.lang.String getAltSubjectMatch();
     method public java.lang.String getAnonymousIdentity();
     method public java.security.cert.X509Certificate getCaCertificate();
+    method public java.security.cert.X509Certificate[] getCaCertificates();
     method public java.security.cert.X509Certificate getClientCertificate();
     method public java.lang.String getDomainSuffixMatch();
     method public int getEapMethod();
@@ -25474,6 +26263,7 @@
     method public void setAltSubjectMatch(java.lang.String);
     method public void setAnonymousIdentity(java.lang.String);
     method public void setCaCertificate(java.security.cert.X509Certificate);
+    method public void setCaCertificates(java.security.cert.X509Certificate[]);
     method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
     method public void setDomainSuffixMatch(java.lang.String);
     method public void setEapMethod(int);
@@ -25543,6 +26333,8 @@
     method public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
     method public java.util.List<android.net.wifi.ScanInfo> getScanInfos();
     method public java.util.List<android.net.wifi.ScanResult> getScanResults();
+    method public android.net.wifi.WifiConfiguration getWifiApConfiguration();
+    method public int getWifiApState();
     method public int getWifiState();
     method public boolean is5GHzBandSupported();
     method public deprecated boolean isBatchedScanSupported();
@@ -25554,6 +26346,7 @@
     method public boolean isPreferredNetworkOffloadSupported();
     method public boolean isScanAlwaysAvailable();
     method public boolean isTdlsSupported();
+    method public boolean isWifiApEnabled();
     method public boolean isWifiEnabled();
     method public boolean isWifiScannerSupported();
     method public boolean pingSupplicant();
@@ -25564,6 +26357,8 @@
     method public void setOsuSelection(int);
     method public void setTdlsEnabled(java.net.InetAddress, boolean);
     method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
+    method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
+    method public boolean setWifiApEnabled(android.net.wifi.WifiConfiguration, boolean);
     method public boolean setWifiEnabled(boolean);
     method public deprecated boolean startLocationRestrictedScan(android.os.WorkSource);
     method public boolean startScan();
@@ -25679,6 +26474,7 @@
     field public static final int REASON_UNSPECIFIED = -1; // 0xffffffff
     field public static final deprecated int REPORT_EVENT_AFTER_BUFFER_FULL = 0; // 0x0
     field public static final int REPORT_EVENT_AFTER_EACH_SCAN = 1; // 0x1
+    field public static final int REPORT_EVENT_CONTEXT_HUB = 8; // 0x8
     field public static final int REPORT_EVENT_FULL_SCAN_RESULT = 2; // 0x2
     field public static final int REPORT_EVENT_NO_BATCH = 4; // 0x4
     field public static final int WIFI_BAND_24_GHZ = 1; // 0x1
@@ -25759,7 +26555,6 @@
     method public void writeToParcel(android.os.Parcel, int);
     field public int band;
     field public android.net.wifi.WifiScanner.ChannelSpec[] channels;
-    field public int exponent;
     field public int maxPeriodInMs;
     field public int maxScansToCache;
     field public int numBssidsPerScan;
@@ -26132,6 +26927,7 @@
 
   public final class Tag implements android.os.Parcelable {
     method public int describeContents();
+    method public boolean done(int);
     method public byte[] getId();
     method public java.lang.String[] getTechList();
     method public void writeToParcel(android.os.Parcel, int);
@@ -26182,6 +26978,28 @@
     field public static final java.lang.String SERVICE_META_DATA = "android.nfc.cardemulation.host_apdu_service";
   }
 
+  public abstract class HostNfcFService extends android.app.Service {
+    ctor public HostNfcFService();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public abstract void onDeactivated(int);
+    method public abstract byte[] processNfcFPacket(byte[], android.os.Bundle);
+    method public final void sendResponsePacket(byte[]);
+    field public static final int DEACTIVATION_LINK_LOSS = 0; // 0x0
+    field public static final java.lang.String SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_NFCF_SERVICE";
+    field public static final java.lang.String SERVICE_META_DATA = "android.nfc.cardemulation.host_nfcf_service";
+  }
+
+  public final class NfcFCardEmulation {
+    method public boolean disableNfcFForegroundService(android.app.Activity);
+    method public boolean enableNfcFForegroundService(android.app.Activity, android.content.ComponentName);
+    method public static synchronized android.nfc.cardemulation.NfcFCardEmulation getInstance(android.nfc.NfcAdapter);
+    method public java.lang.String getNfcid2ForService(android.content.ComponentName);
+    method public java.lang.String getSystemCodeForService(android.content.ComponentName);
+    method public boolean registerSystemCodeForService(android.content.ComponentName, java.lang.String);
+    method public boolean removeSystemCodeForService(android.content.ComponentName);
+    method public boolean setNfcid2ForService(android.content.ComponentName, java.lang.String);
+  }
+
   public abstract class OffHostApduService extends android.app.Service {
     ctor public OffHostApduService();
     method public abstract android.os.IBinder onBind(android.content.Intent);
@@ -28854,12 +29672,285 @@
     method public abstract void onMessage(int, int, int, int, java.lang.String);
   }
 
+  public class GLES32 extends android.opengl.GLES31 {
+    method public static void glBlendBarrier();
+    method public static void glBlendEquationSeparatei(int, int, int);
+    method public static void glBlendEquationi(int, int);
+    method public static void glBlendFuncSeparatei(int, int, int, int, int);
+    method public static void glBlendFunci(int, int, int);
+    method public static void glColorMaski(int, boolean, boolean, boolean, boolean);
+    method public static void glCopyImageSubData(int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
+    method public static void glDebugMessageCallback(android.opengl.GLES32.DebugProc);
+    method public static void glDebugMessageControl(int, int, int, int, int[], int, boolean);
+    method public static void glDebugMessageControl(int, int, int, int, java.nio.IntBuffer, boolean);
+    method public static void glDebugMessageInsert(int, int, int, int, int, java.lang.String);
+    method public static void glDisablei(int, int);
+    method public static void glDrawElementsBaseVertex(int, int, int, java.nio.Buffer, int);
+    method public static void glDrawElementsInstancedBaseVertex(int, int, int, java.nio.Buffer, int, int);
+    method public static void glDrawElementsInstancedBaseVertex(int, int, int, int, int, int);
+    method public static void glDrawRangeElementsBaseVertex(int, int, int, int, int, java.nio.Buffer, int);
+    method public static void glEnablei(int, int);
+    method public static void glFramebufferTexture(int, int, int, int);
+    method public static int glGetDebugMessageLog(int, int, int[], int, int[], int, int[], int, int[], int, int[], int, byte[], int);
+    method public static int glGetDebugMessageLog(int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.ByteBuffer);
+    method public static java.lang.String[] glGetDebugMessageLog(int, int[], int, int[], int, int[], int, int[], int);
+    method public static java.lang.String[] glGetDebugMessageLog(int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer);
+    method public static int glGetGraphicsResetStatus();
+    method public static java.lang.String glGetObjectLabel(int, int);
+    method public static java.lang.String glGetObjectPtrLabel(long);
+    method public static long glGetPointerv(int);
+    method public static void glGetSamplerParameterIiv(int, int, int[], int);
+    method public static void glGetSamplerParameterIiv(int, int, java.nio.IntBuffer);
+    method public static void glGetSamplerParameterIuiv(int, int, int[], int);
+    method public static void glGetSamplerParameterIuiv(int, int, java.nio.IntBuffer);
+    method public static void glGetTexParameterIiv(int, int, int[], int);
+    method public static void glGetTexParameterIiv(int, int, java.nio.IntBuffer);
+    method public static void glGetTexParameterIuiv(int, int, int[], int);
+    method public static void glGetTexParameterIuiv(int, int, java.nio.IntBuffer);
+    method public static void glGetnUniformfv(int, int, int, float[], int);
+    method public static void glGetnUniformfv(int, int, int, java.nio.FloatBuffer);
+    method public static void glGetnUniformiv(int, int, int, int[], int);
+    method public static void glGetnUniformiv(int, int, int, java.nio.IntBuffer);
+    method public static void glGetnUniformuiv(int, int, int, int[], int);
+    method public static void glGetnUniformuiv(int, int, int, java.nio.IntBuffer);
+    method public static boolean glIsEnabledi(int, int);
+    method public static void glMinSampleShading(float);
+    method public static void glObjectLabel(int, int, int, java.lang.String);
+    method public static void glObjectPtrLabel(long, java.lang.String);
+    method public static void glPatchParameteri(int, int);
+    method public static void glPopDebugGroup();
+    method public static void glPrimitiveBoundingBox(float, float, float, float, float, float, float, float);
+    method public static void glPushDebugGroup(int, int, int, java.lang.String);
+    method public static void glReadnPixels(int, int, int, int, int, int, int, java.nio.Buffer);
+    method public static void glSamplerParameterIiv(int, int, int[], int);
+    method public static void glSamplerParameterIiv(int, int, java.nio.IntBuffer);
+    method public static void glSamplerParameterIuiv(int, int, int[], int);
+    method public static void glSamplerParameterIuiv(int, int, java.nio.IntBuffer);
+    method public static void glTexBuffer(int, int, int);
+    method public static void glTexBufferRange(int, int, int, int, int);
+    method public static void glTexParameterIiv(int, int, int[], int);
+    method public static void glTexParameterIiv(int, int, java.nio.IntBuffer);
+    method public static void glTexParameterIuiv(int, int, int[], int);
+    method public static void glTexParameterIuiv(int, int, java.nio.IntBuffer);
+    method public static void glTexStorage3DMultisample(int, int, int, int, int, int, boolean);
+    field public static final int GL_BUFFER = 33504; // 0x82e0
+    field public static final int GL_CLAMP_TO_BORDER = 33069; // 0x812d
+    field public static final int GL_COLORBURN = 37530; // 0x929a
+    field public static final int GL_COLORDODGE = 37529; // 0x9299
+    field public static final int GL_COMPRESSED_RGBA_ASTC_10x10 = 37819; // 0x93bb
+    field public static final int GL_COMPRESSED_RGBA_ASTC_10x5 = 37816; // 0x93b8
+    field public static final int GL_COMPRESSED_RGBA_ASTC_10x6 = 37817; // 0x93b9
+    field public static final int GL_COMPRESSED_RGBA_ASTC_10x8 = 37818; // 0x93ba
+    field public static final int GL_COMPRESSED_RGBA_ASTC_12x10 = 37820; // 0x93bc
+    field public static final int GL_COMPRESSED_RGBA_ASTC_12x12 = 37821; // 0x93bd
+    field public static final int GL_COMPRESSED_RGBA_ASTC_4x4 = 37808; // 0x93b0
+    field public static final int GL_COMPRESSED_RGBA_ASTC_5x4 = 37809; // 0x93b1
+    field public static final int GL_COMPRESSED_RGBA_ASTC_5x5 = 37810; // 0x93b2
+    field public static final int GL_COMPRESSED_RGBA_ASTC_6x5 = 37811; // 0x93b3
+    field public static final int GL_COMPRESSED_RGBA_ASTC_6x6 = 37812; // 0x93b4
+    field public static final int GL_COMPRESSED_RGBA_ASTC_8x5 = 37813; // 0x93b5
+    field public static final int GL_COMPRESSED_RGBA_ASTC_8x6 = 37814; // 0x93b6
+    field public static final int GL_COMPRESSED_RGBA_ASTC_8x8 = 37815; // 0x93b7
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10 = 37851; // 0x93db
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5 = 37848; // 0x93d8
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6 = 37849; // 0x93d9
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8 = 37850; // 0x93da
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10 = 37852; // 0x93dc
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12 = 37853; // 0x93dd
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4 = 37840; // 0x93d0
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4 = 37841; // 0x93d1
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5 = 37842; // 0x93d2
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5 = 37843; // 0x93d3
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6 = 37844; // 0x93d4
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5 = 37845; // 0x93d5
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6 = 37846; // 0x93d6
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8 = 37847; // 0x93d7
+    field public static final int GL_CONTEXT_FLAGS = 33310; // 0x821e
+    field public static final int GL_CONTEXT_FLAG_DEBUG_BIT = 2; // 0x2
+    field public static final int GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT = 4; // 0x4
+    field public static final int GL_CONTEXT_LOST = 1287; // 0x507
+    field public static final int GL_DARKEN = 37527; // 0x9297
+    field public static final int GL_DEBUG_CALLBACK_FUNCTION = 33348; // 0x8244
+    field public static final int GL_DEBUG_CALLBACK_USER_PARAM = 33349; // 0x8245
+    field public static final int GL_DEBUG_GROUP_STACK_DEPTH = 33389; // 0x826d
+    field public static final int GL_DEBUG_LOGGED_MESSAGES = 37189; // 0x9145
+    field public static final int GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH = 33347; // 0x8243
+    field public static final int GL_DEBUG_OUTPUT = 37600; // 0x92e0
+    field public static final int GL_DEBUG_OUTPUT_SYNCHRONOUS = 33346; // 0x8242
+    field public static final int GL_DEBUG_SEVERITY_HIGH = 37190; // 0x9146
+    field public static final int GL_DEBUG_SEVERITY_LOW = 37192; // 0x9148
+    field public static final int GL_DEBUG_SEVERITY_MEDIUM = 37191; // 0x9147
+    field public static final int GL_DEBUG_SEVERITY_NOTIFICATION = 33387; // 0x826b
+    field public static final int GL_DEBUG_SOURCE_API = 33350; // 0x8246
+    field public static final int GL_DEBUG_SOURCE_APPLICATION = 33354; // 0x824a
+    field public static final int GL_DEBUG_SOURCE_OTHER = 33355; // 0x824b
+    field public static final int GL_DEBUG_SOURCE_SHADER_COMPILER = 33352; // 0x8248
+    field public static final int GL_DEBUG_SOURCE_THIRD_PARTY = 33353; // 0x8249
+    field public static final int GL_DEBUG_SOURCE_WINDOW_SYSTEM = 33351; // 0x8247
+    field public static final int GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR = 33357; // 0x824d
+    field public static final int GL_DEBUG_TYPE_ERROR = 33356; // 0x824c
+    field public static final int GL_DEBUG_TYPE_MARKER = 33384; // 0x8268
+    field public static final int GL_DEBUG_TYPE_OTHER = 33361; // 0x8251
+    field public static final int GL_DEBUG_TYPE_PERFORMANCE = 33360; // 0x8250
+    field public static final int GL_DEBUG_TYPE_POP_GROUP = 33386; // 0x826a
+    field public static final int GL_DEBUG_TYPE_PORTABILITY = 33359; // 0x824f
+    field public static final int GL_DEBUG_TYPE_PUSH_GROUP = 33385; // 0x8269
+    field public static final int GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR = 33358; // 0x824e
+    field public static final int GL_DIFFERENCE = 37534; // 0x929e
+    field public static final int GL_EXCLUSION = 37536; // 0x92a0
+    field public static final int GL_FIRST_VERTEX_CONVENTION = 36429; // 0x8e4d
+    field public static final int GL_FRACTIONAL_EVEN = 36476; // 0x8e7c
+    field public static final int GL_FRACTIONAL_ODD = 36475; // 0x8e7b
+    field public static final int GL_FRAGMENT_INTERPOLATION_OFFSET_BITS = 36445; // 0x8e5d
+    field public static final int GL_FRAMEBUFFER_ATTACHMENT_LAYERED = 36263; // 0x8da7
+    field public static final int GL_FRAMEBUFFER_DEFAULT_LAYERS = 37650; // 0x9312
+    field public static final int GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS = 36264; // 0x8da8
+    field public static final int GL_GEOMETRY_INPUT_TYPE = 35095; // 0x8917
+    field public static final int GL_GEOMETRY_OUTPUT_TYPE = 35096; // 0x8918
+    field public static final int GL_GEOMETRY_SHADER = 36313; // 0x8dd9
+    field public static final int GL_GEOMETRY_SHADER_BIT = 4; // 0x4
+    field public static final int GL_GEOMETRY_SHADER_INVOCATIONS = 34943; // 0x887f
+    field public static final int GL_GEOMETRY_VERTICES_OUT = 35094; // 0x8916
+    field public static final int GL_GUILTY_CONTEXT_RESET = 33363; // 0x8253
+    field public static final int GL_HARDLIGHT = 37531; // 0x929b
+    field public static final int GL_HSL_COLOR = 37551; // 0x92af
+    field public static final int GL_HSL_HUE = 37549; // 0x92ad
+    field public static final int GL_HSL_LUMINOSITY = 37552; // 0x92b0
+    field public static final int GL_HSL_SATURATION = 37550; // 0x92ae
+    field public static final int GL_IMAGE_BUFFER = 36945; // 0x9051
+    field public static final int GL_IMAGE_CUBE_MAP_ARRAY = 36948; // 0x9054
+    field public static final int GL_INNOCENT_CONTEXT_RESET = 33364; // 0x8254
+    field public static final int GL_INT_IMAGE_BUFFER = 36956; // 0x905c
+    field public static final int GL_INT_IMAGE_CUBE_MAP_ARRAY = 36959; // 0x905f
+    field public static final int GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 37132; // 0x910c
+    field public static final int GL_INT_SAMPLER_BUFFER = 36304; // 0x8dd0
+    field public static final int GL_INT_SAMPLER_CUBE_MAP_ARRAY = 36878; // 0x900e
+    field public static final int GL_ISOLINES = 36474; // 0x8e7a
+    field public static final int GL_IS_PER_PATCH = 37607; // 0x92e7
+    field public static final int GL_LAST_VERTEX_CONVENTION = 36430; // 0x8e4e
+    field public static final int GL_LAYER_PROVOKING_VERTEX = 33374; // 0x825e
+    field public static final int GL_LIGHTEN = 37528; // 0x9298
+    field public static final int GL_LINES_ADJACENCY = 10; // 0xa
+    field public static final int GL_LINE_STRIP_ADJACENCY = 11; // 0xb
+    field public static final int GL_LOSE_CONTEXT_ON_RESET = 33362; // 0x8252
+    field public static final int GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS = 35378; // 0x8a32
+    field public static final int GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS = 36382; // 0x8e1e
+    field public static final int GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS = 36383; // 0x8e1f
+    field public static final int GL_MAX_DEBUG_GROUP_STACK_DEPTH = 33388; // 0x826c
+    field public static final int GL_MAX_DEBUG_LOGGED_MESSAGES = 37188; // 0x9144
+    field public static final int GL_MAX_DEBUG_MESSAGE_LENGTH = 37187; // 0x9143
+    field public static final int GL_MAX_FRAGMENT_INTERPOLATION_OFFSET = 36444; // 0x8e5c
+    field public static final int GL_MAX_FRAMEBUFFER_LAYERS = 37655; // 0x9317
+    field public static final int GL_MAX_GEOMETRY_ATOMIC_COUNTERS = 37589; // 0x92d5
+    field public static final int GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS = 37583; // 0x92cf
+    field public static final int GL_MAX_GEOMETRY_IMAGE_UNIFORMS = 37069; // 0x90cd
+    field public static final int GL_MAX_GEOMETRY_INPUT_COMPONENTS = 37155; // 0x9123
+    field public static final int GL_MAX_GEOMETRY_OUTPUT_COMPONENTS = 37156; // 0x9124
+    field public static final int GL_MAX_GEOMETRY_OUTPUT_VERTICES = 36320; // 0x8de0
+    field public static final int GL_MAX_GEOMETRY_SHADER_INVOCATIONS = 36442; // 0x8e5a
+    field public static final int GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS = 37079; // 0x90d7
+    field public static final int GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS = 35881; // 0x8c29
+    field public static final int GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = 36321; // 0x8de1
+    field public static final int GL_MAX_GEOMETRY_UNIFORM_BLOCKS = 35372; // 0x8a2c
+    field public static final int GL_MAX_GEOMETRY_UNIFORM_COMPONENTS = 36319; // 0x8ddf
+    field public static final int GL_MAX_LABEL_LENGTH = 33512; // 0x82e8
+    field public static final int GL_MAX_PATCH_VERTICES = 36477; // 0x8e7d
+    field public static final int GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS = 37587; // 0x92d3
+    field public static final int GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS = 37581; // 0x92cd
+    field public static final int GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS = 37067; // 0x90cb
+    field public static final int GL_MAX_TESS_CONTROL_INPUT_COMPONENTS = 34924; // 0x886c
+    field public static final int GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS = 36483; // 0x8e83
+    field public static final int GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS = 37080; // 0x90d8
+    field public static final int GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS = 36481; // 0x8e81
+    field public static final int GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS = 36485; // 0x8e85
+    field public static final int GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS = 36489; // 0x8e89
+    field public static final int GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS = 36479; // 0x8e7f
+    field public static final int GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS = 37588; // 0x92d4
+    field public static final int GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS = 37582; // 0x92ce
+    field public static final int GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS = 37068; // 0x90cc
+    field public static final int GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS = 34925; // 0x886d
+    field public static final int GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS = 36486; // 0x8e86
+    field public static final int GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS = 37081; // 0x90d9
+    field public static final int GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS = 36482; // 0x8e82
+    field public static final int GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS = 36490; // 0x8e8a
+    field public static final int GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS = 36480; // 0x8e80
+    field public static final int GL_MAX_TESS_GEN_LEVEL = 36478; // 0x8e7e
+    field public static final int GL_MAX_TESS_PATCH_COMPONENTS = 36484; // 0x8e84
+    field public static final int GL_MAX_TEXTURE_BUFFER_SIZE = 35883; // 0x8c2b
+    field public static final int GL_MIN_FRAGMENT_INTERPOLATION_OFFSET = 36443; // 0x8e5b
+    field public static final int GL_MIN_SAMPLE_SHADING_VALUE = 35895; // 0x8c37
+    field public static final int GL_MULTIPLY = 37524; // 0x9294
+    field public static final int GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY = 37762; // 0x9382
+    field public static final int GL_MULTISAMPLE_LINE_WIDTH_RANGE = 37761; // 0x9381
+    field public static final int GL_NO_RESET_NOTIFICATION = 33377; // 0x8261
+    field public static final int GL_OVERLAY = 37526; // 0x9296
+    field public static final int GL_PATCHES = 14; // 0xe
+    field public static final int GL_PATCH_VERTICES = 36466; // 0x8e72
+    field public static final int GL_PRIMITIVES_GENERATED = 35975; // 0x8c87
+    field public static final int GL_PRIMITIVE_BOUNDING_BOX = 37566; // 0x92be
+    field public static final int GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED = 33313; // 0x8221
+    field public static final int GL_PROGRAM = 33506; // 0x82e2
+    field public static final int GL_PROGRAM_PIPELINE = 33508; // 0x82e4
+    field public static final int GL_QUADS = 7; // 0x7
+    field public static final int GL_QUERY = 33507; // 0x82e3
+    field public static final int GL_REFERENCED_BY_GEOMETRY_SHADER = 37641; // 0x9309
+    field public static final int GL_REFERENCED_BY_TESS_CONTROL_SHADER = 37639; // 0x9307
+    field public static final int GL_REFERENCED_BY_TESS_EVALUATION_SHADER = 37640; // 0x9308
+    field public static final int GL_RESET_NOTIFICATION_STRATEGY = 33366; // 0x8256
+    field public static final int GL_SAMPLER = 33510; // 0x82e6
+    field public static final int GL_SAMPLER_2D_MULTISAMPLE_ARRAY = 37131; // 0x910b
+    field public static final int GL_SAMPLER_BUFFER = 36290; // 0x8dc2
+    field public static final int GL_SAMPLER_CUBE_MAP_ARRAY = 36876; // 0x900c
+    field public static final int GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW = 36877; // 0x900d
+    field public static final int GL_SAMPLE_SHADING = 35894; // 0x8c36
+    field public static final int GL_SCREEN = 37525; // 0x9295
+    field public static final int GL_SHADER = 33505; // 0x82e1
+    field public static final int GL_SOFTLIGHT = 37532; // 0x929c
+    field public static final int GL_STACK_OVERFLOW = 1283; // 0x503
+    field public static final int GL_STACK_UNDERFLOW = 1284; // 0x504
+    field public static final int GL_TESS_CONTROL_OUTPUT_VERTICES = 36469; // 0x8e75
+    field public static final int GL_TESS_CONTROL_SHADER = 36488; // 0x8e88
+    field public static final int GL_TESS_CONTROL_SHADER_BIT = 8; // 0x8
+    field public static final int GL_TESS_EVALUATION_SHADER = 36487; // 0x8e87
+    field public static final int GL_TESS_EVALUATION_SHADER_BIT = 16; // 0x10
+    field public static final int GL_TESS_GEN_MODE = 36470; // 0x8e76
+    field public static final int GL_TESS_GEN_POINT_MODE = 36473; // 0x8e79
+    field public static final int GL_TESS_GEN_SPACING = 36471; // 0x8e77
+    field public static final int GL_TESS_GEN_VERTEX_ORDER = 36472; // 0x8e78
+    field public static final int GL_TEXTURE_2D_MULTISAMPLE_ARRAY = 37122; // 0x9102
+    field public static final int GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY = 37125; // 0x9105
+    field public static final int GL_TEXTURE_BINDING_BUFFER = 35884; // 0x8c2c
+    field public static final int GL_TEXTURE_BINDING_CUBE_MAP_ARRAY = 36874; // 0x900a
+    field public static final int GL_TEXTURE_BORDER_COLOR = 4100; // 0x1004
+    field public static final int GL_TEXTURE_BUFFER = 35882; // 0x8c2a
+    field public static final int GL_TEXTURE_BUFFER_BINDING = 35882; // 0x8c2a
+    field public static final int GL_TEXTURE_BUFFER_DATA_STORE_BINDING = 35885; // 0x8c2d
+    field public static final int GL_TEXTURE_BUFFER_OFFSET = 37277; // 0x919d
+    field public static final int GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT = 37279; // 0x919f
+    field public static final int GL_TEXTURE_BUFFER_SIZE = 37278; // 0x919e
+    field public static final int GL_TEXTURE_CUBE_MAP_ARRAY = 36873; // 0x9009
+    field public static final int GL_TRIANGLES_ADJACENCY = 12; // 0xc
+    field public static final int GL_TRIANGLE_STRIP_ADJACENCY = 13; // 0xd
+    field public static final int GL_UNDEFINED_VERTEX = 33376; // 0x8260
+    field public static final int GL_UNKNOWN_CONTEXT_RESET = 33365; // 0x8255
+    field public static final int GL_UNSIGNED_INT_IMAGE_BUFFER = 36967; // 0x9067
+    field public static final int GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY = 36970; // 0x906a
+    field public static final int GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 37133; // 0x910d
+    field public static final int GL_UNSIGNED_INT_SAMPLER_BUFFER = 36312; // 0x8dd8
+    field public static final int GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY = 36879; // 0x900f
+    field public static final int GL_VERTEX_ARRAY = 32884; // 0x8074
+  }
+
+  public static abstract interface GLES32.DebugProc {
+    method public abstract void onMessage(int, int, int, int, java.lang.String);
+  }
+
   public class GLException extends java.lang.RuntimeException {
     ctor public GLException(int);
     ctor public GLException(int, java.lang.String);
   }
 
-  public class GLSurfaceView extends android.view.SurfaceView implements android.view.SurfaceHolder.Callback {
+  public class GLSurfaceView extends android.view.SurfaceView implements android.view.SurfaceHolder.Callback2 {
     ctor public GLSurfaceView(android.content.Context);
     ctor public GLSurfaceView(android.content.Context, android.util.AttributeSet);
     method public int getDebugFlags();
@@ -28883,6 +29974,7 @@
     method public void surfaceChanged(android.view.SurfaceHolder, int, int, int);
     method public void surfaceCreated(android.view.SurfaceHolder);
     method public void surfaceDestroyed(android.view.SurfaceHolder);
+    method public void surfaceRedrawNeeded(android.view.SurfaceHolder);
     field public static final int DEBUG_CHECK_GL_ERROR = 1; // 0x1
     field public static final int DEBUG_LOG_GL_CALLS = 2; // 0x2
     field public static final int RENDERMODE_CONTINUOUSLY = 1; // 0x1
@@ -29264,6 +30356,14 @@
     method public final synchronized android.os.CountDownTimer start();
   }
 
+  public final class CpuUsageInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getActive();
+    method public long getTotal();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.os.CpuUsageInfo> CREATOR;
+  }
+
   public class DeadObjectException extends android.os.RemoteException {
     ctor public DeadObjectException();
     ctor public DeadObjectException(java.lang.String);
@@ -29516,6 +30616,18 @@
     method public boolean quitSafely();
   }
 
+  public class HardwarePropertiesManager {
+    method public android.os.CpuUsageInfo[] getCpuUsages();
+    method public float[] getDeviceTemperatures(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 {
+  }
+
   public abstract interface IBinder {
     method public abstract void dump(java.io.FileDescriptor, java.lang.String[]) throws android.os.RemoteException;
     method public abstract void dumpAsync(java.io.FileDescriptor, java.lang.String[]) throws android.os.RemoteException;
@@ -29888,6 +31000,7 @@
     field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
     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_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
@@ -30095,6 +31208,7 @@
     method public deprecated boolean isOwner();
     method public boolean isSystem();
     method public static int myUserId();
+    method public static android.os.UserHandle of(int);
     method public static android.os.UserHandle readFromParcel(android.os.Parcel);
     method public void writeToParcel(android.os.Parcel, int);
     method public static void writeToParcel(android.os.UserHandle, android.os.Parcel);
@@ -30102,8 +31216,14 @@
   }
 
   public class UserManager {
+    method public void clearSeedAccountData();
+    method public static android.content.Intent createUserCreationIntent(java.lang.String, java.lang.String, java.lang.String, android.os.PersistableBundle);
     method public android.os.Bundle getApplicationRestrictions(java.lang.String);
+    method public java.lang.String getSeedAccountName();
+    method public android.os.PersistableBundle getSeedAccountOptions();
+    method public java.lang.String getSeedAccountType();
     method public long getSerialNumberForUser(android.os.UserHandle);
+    method public long[] getSerialNumbersOfUsers(boolean);
     method public int getUserCount();
     method public long getUserCreationTime(android.os.UserHandle);
     method public android.os.UserHandle getUserForSerialNumber(long);
@@ -30141,6 +31261,7 @@
     field public static final java.lang.String DISALLOW_CONFIG_WIFI = "no_config_wifi";
     field public static final java.lang.String DISALLOW_CREATE_WINDOWS = "no_create_windows";
     field public static final java.lang.String DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste";
+    field public static final java.lang.String DISALLOW_DATA_ROAMING = "no_data_roaming";
     field public static final java.lang.String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features";
     field public static final java.lang.String DISALLOW_FACTORY_RESET = "no_factory_reset";
     field public static final java.lang.String DISALLOW_FUN = "no_fun";
@@ -30153,6 +31274,7 @@
     field public static final java.lang.String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls";
     field public static final java.lang.String DISALLOW_REMOVE_USER = "no_remove_user";
     field public static final java.lang.String DISALLOW_SAFE_BOOT = "no_safe_boot";
+    field public static final java.lang.String DISALLOW_SET_USER_ICON = "no_set_user_icon";
     field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location";
     field public static final java.lang.String DISALLOW_SMS = "no_sms";
     field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
@@ -30160,6 +31282,8 @@
     field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
     field public static final java.lang.String ENSURE_VERIFY_APPS = "ensure_verify_apps";
     field public static final java.lang.String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
+    field public static final int USER_CREATION_FAILED_NOT_PERMITTED = 1; // 0x1
+    field public static final int USER_CREATION_FAILED_NO_MORE_USERS = 2; // 0x2
   }
 
   public abstract class Vibrator {
@@ -30517,6 +31641,9 @@
     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 setStorageDefault();
+    method public void setStorageDeviceEncrypted();
     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";
   }
@@ -30886,6 +32013,9 @@
     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 setIconResourceId(int);
+    method public android.print.PrinterInfo.Builder setInfoIntent(android.app.PendingIntent);
     method public android.print.PrinterInfo.Builder setName(java.lang.String);
     method public android.print.PrinterInfo.Builder setStatus(int);
   }
@@ -30906,6 +32036,10 @@
 
 package android.printservice {
 
+  public class CustomPrinterIconCallback {
+    method public boolean onCustomPrinterIconLoaded(android.graphics.drawable.Icon);
+  }
+
   public final class PrintDocument {
     method public android.os.ParcelFileDescriptor getData();
     method public android.print.PrintDocumentInfo getInfo();
@@ -30961,6 +32095,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 abstract void onStartPrinterDiscovery(java.util.List<android.print.PrinterId>);
     method public abstract void onStartPrinterStateTracking(android.print.PrinterId);
     method public abstract void onStopPrinterDiscovery();
@@ -31003,6 +32138,22 @@
     field public static final java.lang.String _ID = "_id";
   }
 
+  public class BlockedNumberContract {
+    method public static boolean isBlocked(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;
+  }
+
+  public static class BlockedNumberContract.BlockedNumbers {
+    field public static final java.lang.String COLUMN_E164_NUMBER = "e164_number";
+    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 COLUMN_STRIPPED_NUMBER = "stripped_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 android.net.Uri CONTENT_URI;
+  }
+
   public class Browser {
     ctor public Browser();
     method public static final void sendString(android.content.Context, java.lang.String);
@@ -31329,6 +32480,7 @@
     field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location";
     field public static final int INCOMING_TYPE = 1; // 0x1
     field public static final java.lang.String IS_READ = "is_read";
+    field public static final java.lang.String LAST_MODIFIED = "last_modified";
     field public static final java.lang.String LIMIT_PARAM_KEY = "limit";
     field public static final int MISSED_TYPE = 3; // 0x3
     field public static final java.lang.String NEW = "new";
@@ -32224,10 +33376,14 @@
 
   public static final class ContactsContract.Intents {
     ctor public ContactsContract.Intents();
+    field public static final java.lang.String ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS = "android.provider.action.VOICE_SEND_MESSAGE_TO_CONTACTS";
     field public static final java.lang.String ATTACH_IMAGE = "com.android.contacts.action.ATTACH_IMAGE";
     field public static final java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
     field public static final java.lang.String EXTRA_CREATE_DESCRIPTION = "com.android.contacts.action.CREATE_DESCRIPTION";
     field public static final java.lang.String EXTRA_FORCE_CREATE = "com.android.contacts.action.FORCE_CREATE";
+    field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_CHAT_ID = "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
+    field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_NAME = "android.provider.extra.RECIPIENT_CONTACT_NAME";
+    field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_URI = "android.provider.extra.RECIPIENT_CONTACT_URI";
     field public static final java.lang.String INVITE_CONTACT = "com.android.contacts.action.INVITE_CONTACT";
     field public static final java.lang.String SEARCH_SUGGESTION_CLICKED = "android.provider.Contacts.SEARCH_SUGGESTION_CLICKED";
     field public static final java.lang.String SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED = "android.provider.Contacts.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED";
@@ -32503,6 +33659,7 @@
     method public static android.net.Uri buildRootsUri(java.lang.String);
     method public static android.net.Uri buildSearchDocumentsUri(java.lang.String, java.lang.String, java.lang.String);
     method public static android.net.Uri buildTreeDocumentUri(java.lang.String, java.lang.String);
+    method public static android.net.Uri copyDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri);
     method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);
     method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri);
     method public static java.lang.String getDocumentId(android.net.Uri);
@@ -32511,6 +33668,9 @@
     method public static java.lang.String getSearchDocumentsQuery(android.net.Uri);
     method public static java.lang.String getTreeDocumentId(android.net.Uri);
     method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
+    method public static boolean isTreeUri(android.net.Uri);
+    method public static android.net.Uri moveDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri, android.net.Uri);
+    method public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri);
     method public static android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String);
     field public static final java.lang.String EXTRA_ERROR = "error";
     field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
@@ -32529,18 +33689,18 @@
     field public static final java.lang.String COLUMN_MIME_TYPE = "mime_type";
     field public static final java.lang.String COLUMN_SIZE = "_size";
     field public static final java.lang.String COLUMN_SUMMARY = "summary";
-    field public static final int FLAG_ARCHIVE = 2048; // 0x800
+    field public static final int FLAG_ARCHIVE = 1024; // 0x400
     field public static final int FLAG_DIR_PREFERS_GRID = 16; // 0x10
     field public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 32; // 0x20
     field public static final int FLAG_DIR_SUPPORTS_CREATE = 8; // 0x8
     field public static final int FLAG_SUPPORTS_COPY = 128; // 0x80
     field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4
     field public static final int FLAG_SUPPORTS_MOVE = 256; // 0x100
+    field public static final int FLAG_SUPPORTS_REMOVE = 2048; // 0x800
     field public static final int FLAG_SUPPORTS_RENAME = 64; // 0x40
     field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
-    field public static final int FLAG_SUPPORTS_TYPED_DOCUMENT = 512; // 0x200
     field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
-    field public static final int FLAG_VIRTUAL_DOCUMENT = 1024; // 0x400
+    field public static final int FLAG_VIRTUAL_DOCUMENT = 512; // 0x200
     field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory";
   }
 
@@ -32584,6 +33744,7 @@
     method public android.database.Cursor queryRecentDocuments(java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
     method public abstract android.database.Cursor queryRoots(java.lang.String[]) throws java.io.FileNotFoundException;
     method public android.database.Cursor querySearchDocuments(java.lang.String, java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
+    method public boolean removeDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public java.lang.String renameDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public final void revokeDocumentPermission(java.lang.String);
     method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
@@ -33065,10 +34226,12 @@
     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";
     field public static final java.lang.String ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS";
+    field public static final java.lang.String ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS";
     field public static final java.lang.String ACTION_MANAGE_OVERLAY_PERMISSION = "android.settings.action.MANAGE_OVERLAY_PERMISSION";
     field public static final java.lang.String ACTION_MANAGE_WRITE_SETTINGS = "android.settings.action.MANAGE_WRITE_SETTINGS";
     field public static final java.lang.String ACTION_MEMORY_CARD_SETTINGS = "android.settings.MEMORY_CARD_SETTINGS";
@@ -33085,6 +34248,7 @@
     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";
+    field public static final java.lang.String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
     field public static final java.lang.String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
     field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
     field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
@@ -33131,6 +34295,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 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";
     field public static final java.lang.String DEBUG_APP = "debug_app";
@@ -33724,6 +34889,7 @@
   public class VoicemailContract {
     field public static final java.lang.String ACTION_FETCH_VOICEMAIL = "android.intent.action.FETCH_VOICEMAIL";
     field public static final java.lang.String ACTION_NEW_VOICEMAIL = "android.intent.action.NEW_VOICEMAIL";
+    field public static final java.lang.String ACTION_SYNC_VOICEMAIL = "android.intent.action.SYNC_VOICEMAIL";
     field public static final java.lang.String AUTHORITY = "com.android.voicemail";
     field public static final java.lang.String EXTRA_SELF_CHANGE = "com.android.voicemail.extra.SELF_CHANGE";
     field public static final java.lang.String PARAM_KEY_SOURCE_PACKAGE = "source_package";
@@ -33731,14 +34897,20 @@
 
   public static final class VoicemailContract.Status implements android.provider.BaseColumns {
     method public static android.net.Uri buildSourceUri(java.lang.String);
+    method public static void setQuota(android.content.Context, android.telecom.PhoneAccountHandle, int, int);
     field public static final java.lang.String CONFIGURATION_STATE = "configuration_state";
     field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2
     field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1
     field public static final int CONFIGURATION_STATE_OK = 0; // 0x0
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String DATA_CHANNEL_STATE = "data_channel_state";
+    field public static final int DATA_CHANNEL_STATE_BAD_CONFIGURATION = 3; // 0x3
+    field public static final int DATA_CHANNEL_STATE_COMMUNICATION_ERROR = 4; // 0x4
     field public static final int DATA_CHANNEL_STATE_NO_CONNECTION = 1; // 0x1
+    field public static final int DATA_CHANNEL_STATE_NO_CONNECTION_CELLULAR_REQUIRED = 2; // 0x2
     field public static final int DATA_CHANNEL_STATE_OK = 0; // 0x0
+    field public static final int DATA_CHANNEL_STATE_SERVER_CONNECTION_ERROR = 6; // 0x6
+    field public static final int DATA_CHANNEL_STATE_SERVER_ERROR = 5; // 0x5
     field public static final java.lang.String DIR_TYPE = "vnd.android.cursor.dir/voicemail.source.status";
     field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail.source.status";
     field public static final java.lang.String NOTIFICATION_CHANNEL_STATE = "notification_channel_state";
@@ -33747,6 +34919,9 @@
     field public static final int NOTIFICATION_CHANNEL_STATE_OK = 0; // 0x0
     field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "phone_account_component_name";
     field public static final java.lang.String PHONE_ACCOUNT_ID = "phone_account_id";
+    field public static final java.lang.String QUOTA_OCCUPIED = "quota_occupied";
+    field public static final java.lang.String QUOTA_TOTAL = "quota_total";
+    field public static final int QUOTA_UNAVAILABLE = -1; // 0xffffffff
     field public static final java.lang.String SETTINGS_URI = "settings_uri";
     field public static final java.lang.String SOURCE_PACKAGE = "source_package";
     field public static final java.lang.String VOICEMAIL_ACCESS_URI = "voicemail_access_uri";
@@ -33763,6 +34938,7 @@
     field public static final java.lang.String HAS_CONTENT = "has_content";
     field public static final java.lang.String IS_READ = "is_read";
     field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail";
+    field public static final java.lang.String LAST_MODIFIED = "last_modified";
     field public static final java.lang.String MIME_TYPE = "mime_type";
     field public static final java.lang.String NUMBER = "number";
     field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
@@ -33832,6 +35008,7 @@
     method public void copyTo(short[]);
     method public void copyTo(int[]);
     method public void copyTo(float[]);
+    method public static android.renderscript.Allocation[] createAllocations(android.renderscript.RenderScript, android.renderscript.Type, int, int);
     method public static android.renderscript.Allocation createCubemapFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap, android.renderscript.Allocation.MipmapControl, int);
     method public static android.renderscript.Allocation createCubemapFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap);
     method public static android.renderscript.Allocation createCubemapFromCubeFaces(android.renderscript.RenderScript, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.renderscript.Allocation.MipmapControl, int);
@@ -33847,9 +35024,12 @@
     method public static android.renderscript.Allocation createTyped(android.renderscript.RenderScript, android.renderscript.Type, int);
     method public static android.renderscript.Allocation createTyped(android.renderscript.RenderScript, android.renderscript.Type);
     method public void generateMipmaps();
+    method public java.nio.ByteBuffer getByteBuffer();
     method public int getBytesSize();
     method public android.renderscript.Element getElement();
+    method public long getStride();
     method public android.view.Surface getSurface();
+    method public long getTimeStamp();
     method public android.renderscript.Type getType();
     method public int getUsage();
     method public void ioReceive();
@@ -34433,6 +35613,7 @@
     method public void getVarV(int, android.renderscript.FieldPacker);
     method protected void invoke(int);
     method protected void invoke(int, android.renderscript.FieldPacker);
+    method protected void reduce(int, android.renderscript.Allocation[], android.renderscript.Allocation, android.renderscript.Script.LaunchOptions);
     method public void setTimeZone(java.lang.String);
     method public void setVar(int, float);
     method public void setVar(int, double);
@@ -34954,6 +36135,7 @@
   public class NetworkSecurityPolicy {
     method public static android.security.NetworkSecurityPolicy getInstance();
     method public boolean isCleartextTrafficPermitted();
+    method public boolean isCleartextTrafficPermitted(java.lang.String);
   }
 
 }
@@ -35248,6 +36430,7 @@
     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();
@@ -35282,9 +36465,11 @@
     method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
     method public android.media.session.MediaSession.Token getSessionToken();
     method public void notifyChildrenChanged(java.lang.String);
+    method public void notifyChildrenChanged(java.lang.String, android.os.Bundle);
     method public android.os.IBinder onBind(android.content.Intent);
     method public abstract android.service.media.MediaBrowserService.BrowserRoot onGetRoot(java.lang.String, int, android.os.Bundle);
     method public abstract void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>);
+    method public void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>, android.os.Bundle);
     method public void onLoadItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>);
     method public void setSessionToken(android.media.session.MediaSession.Token);
     field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
@@ -35342,6 +36527,7 @@
     method public abstract void onUnsubscribe(android.net.Uri);
     field public static final java.lang.String EXTRA_RULE_ID = "android.content.automatic.ruleId";
     field public static final java.lang.String META_DATA_CONFIGURATION_ACTIVITY = "android.service.zen.automatic.configurationActivity";
+    field public static final java.lang.String META_DATA_RULE_INSTANCE_LIMIT = "android.service.zen.automatic.ruleInstanceLimit";
     field public static final java.lang.String META_DATA_RULE_TYPE = "android.service.zen.automatic.ruleType";
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
   }
@@ -35368,7 +36554,10 @@
     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 = 15; // 0xf
+    field public static final int REASON_TOPIC_BANNED = 14; // 0xe
     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 {
@@ -35400,9 +36589,12 @@
     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 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
@@ -35412,6 +36604,7 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
     field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
     field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+    field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
     field public static final int TRIM_FULL = 0; // 0x0
     field public static final int TRIM_LIGHT = 1; // 0x1
   }
@@ -35495,25 +36688,38 @@
     method public java.lang.CharSequence getContentDescription();
     method public android.graphics.drawable.Icon getIcon();
     method public java.lang.CharSequence getLabel();
+    method public int getState();
     method public void setContentDescription(java.lang.CharSequence);
     method public void setIcon(android.graphics.drawable.Icon);
     method public void setLabel(java.lang.CharSequence);
+    method public void setState(int);
     method public void updateTile();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.quicksettings.Tile> CREATOR;
+    field public static final int STATE_ACTIVE = 2; // 0x2
+    field public static final int STATE_INACTIVE = 1; // 0x1
+    field public static final int STATE_UNAVAILABLE = 0; // 0x0
   }
 
   public class TileService extends android.app.Service {
     ctor public TileService();
     method public final android.service.quicksettings.Tile getQsTile();
+    method public final boolean isLocked();
+    method public final boolean isSecure();
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onClick();
     method public void onStartListening();
     method public void onStopListening();
-    method public void onTileAdded();
+    method public int onTileAdded();
     method public void onTileRemoved();
+    method public static final void requestListeningState(android.content.Context, android.content.ComponentName);
+    method public final void setStatusIcon(android.graphics.drawable.Icon, java.lang.String);
     method public final void showDialog(android.app.Dialog);
+    method public final void startActivityAndCollapse(android.content.Intent);
+    method public final void unlockAndRun(java.lang.Runnable);
     field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+    field public static final int TILE_MODE_ACTIVE = 2; // 0x2
+    field public static final int TILE_MODE_PASSIVE = 1; // 0x1
   }
 
 }
@@ -35667,6 +36873,7 @@
     method public void setTheme(int);
     method public void show(android.os.Bundle, int);
     method public void startVoiceActivity(android.content.Intent);
+    field public static final int SHOW_SOURCE_ACTIVITY = 16; // 0x10
     field public static final int SHOW_SOURCE_APPLICATION = 8; // 0x8
     field public static final int SHOW_SOURCE_ASSIST_GESTURE = 4; // 0x4
     field public static final int SHOW_WITH_ASSIST = 1; // 0x1
@@ -36028,6 +37235,8 @@
 
   public abstract class UtteranceProgressListener {
     ctor public UtteranceProgressListener();
+    method public void onAudioAvailable(java.lang.String, byte[]);
+    method public void onBeginSynthesis(java.lang.String, int, int, int);
     method public abstract void onDone(java.lang.String);
     method public abstract deprecated void onError(java.lang.String);
     method public void onError(java.lang.String, int);
@@ -36796,6 +38005,7 @@
     method public static boolean hasProperty(int, int);
     method public boolean hasProperty(int);
     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_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
     field public static final int CAPABILITY_HOLD = 1; // 0x1
@@ -36817,6 +38027,7 @@
     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_WIFI = 8; // 0x8
+    field public static final int PROPERTY_WORK_CALL = 32; // 0x20
   }
 
   public static abstract deprecated class Call.Listener extends android.telecom.Call.Callback {
@@ -36839,6 +38050,30 @@
     field public static final int ROUTE_WIRED_OR_EARPIECE = 5; // 0x5
   }
 
+  public abstract class CallScreeningService extends android.app.Service {
+    ctor public CallScreeningService();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public abstract void onScreenCall(android.telecom.Call.Details);
+    method public final void respondToCall(android.telecom.Call.Details, android.telecom.CallScreeningService.CallResponse);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.CallScreeningService";
+  }
+
+  public static class CallScreeningService.CallResponse {
+    method public boolean getDisallowCall();
+    method public boolean getRejectCall();
+    method public boolean getSkipCallLog();
+    method public boolean getSkipNotification();
+  }
+
+  public static class CallScreeningService.CallResponse.Builder {
+    ctor public CallScreeningService.CallResponse.Builder();
+    method public android.telecom.CallScreeningService.CallResponse build();
+    method public android.telecom.CallScreeningService.CallResponse.Builder setDisallowCall(boolean);
+    method public android.telecom.CallScreeningService.CallResponse.Builder setRejectCall(boolean);
+    method public android.telecom.CallScreeningService.CallResponse.Builder setSkipCallLog(boolean);
+    method public android.telecom.CallScreeningService.CallResponse.Builder setSkipNotification(boolean);
+  }
+
   public abstract class Conference extends android.telecom.Conferenceable {
     ctor public Conference(android.telecom.PhoneAccountHandle);
     method public final boolean addConnection(android.telecom.Connection);
@@ -36946,6 +38181,7 @@
     method public final void setVideoProvider(android.telecom.Connection.VideoProvider);
     method public final void setVideoState(int);
     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_UPGRADE_TO_VIDEO = 524288; // 0x80000
     field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
@@ -37087,6 +38323,7 @@
     method public void onCanAddCallChanged(boolean);
     method public deprecated void onPhoneCreated(android.telecom.Phone);
     method public deprecated void onPhoneDestroyed(android.telecom.Phone);
+    method public void onSilenceRinger();
     method public final void setAudioRoute(int);
     method public final void setMuted(boolean);
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.InCallService";
@@ -37120,6 +38357,35 @@
     method public abstract void onVideoQualityChanged(int);
   }
 
+  public class ParcelableCallAnalytics implements android.os.Parcelable {
+    ctor public ParcelableCallAnalytics(long, long, int, boolean, boolean, int, int, boolean, java.lang.String, boolean);
+    ctor public ParcelableCallAnalytics(android.os.Parcel);
+    method public int describeContents();
+    method public long getCallDurationMillis();
+    method public int getCallTechnologies();
+    method public int getCallTerminationCode();
+    method public int getCallType();
+    method public java.lang.String getConnectionService();
+    method public long getStartTimeMillis();
+    method public boolean isAdditionalCall();
+    method public boolean isCreatedFromExistingConnection();
+    method public boolean isEmergencyCall();
+    method public boolean isInterrupted();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CALLTYPE_INCOMING = 1; // 0x1
+    field public static final int CALLTYPE_OUTGOING = 2; // 0x2
+    field public static final int CALLTYPE_UNKNOWN = 0; // 0x0
+    field public static final int CDMA_PHONE = 1; // 0x1
+    field public static final android.os.Parcelable.Creator<android.telecom.ParcelableCallAnalytics> CREATOR;
+    field public static final int GSM_PHONE = 2; // 0x2
+    field public static final int IMS_PHONE = 4; // 0x4
+    field public static final long MILLIS_IN_1_SECOND = 1000L; // 0x3e8L
+    field public static final long MILLIS_IN_5_MINUTES = 300000L; // 0x493e0L
+    field public static final int SIP_PHONE = 8; // 0x8
+    field public static final int STILL_CONNECTED = -1; // 0xffffffff
+    field public static final int THIRD_PARTY_PHONE = 16; // 0x10
+  }
+
   public final deprecated class Phone {
     method public final void addListener(android.telecom.Phone.Listener);
     method public final boolean canAddCall();
@@ -37139,6 +38405,7 @@
     method public void onCallAudioStateChanged(android.telecom.Phone, android.telecom.CallAudioState);
     method public void onCallRemoved(android.telecom.Phone, android.telecom.Call);
     method public void onCanAddCallChanged(android.telecom.Phone, boolean);
+    method public void onSilenceRinger(android.telecom.Phone);
   }
 
   public final class PhoneAccount implements android.os.Parcelable {
@@ -37337,6 +38604,7 @@
     method public void cancelMissedCallsNotification();
     method public deprecated void clearAccounts();
     method public void clearPhoneAccounts();
+    method public java.util.List<android.telecom.ParcelableCallAnalytics> dumpAnalytics();
     method public void enablePhoneAccount(android.telecom.PhoneAccountHandle, boolean);
     method public boolean endCall();
     method public android.net.Uri getAdnUriForPhoneAccount(android.telecom.PhoneAccountHandle);
@@ -37397,6 +38665,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_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
     field public static final int PRESENTATION_PAYPHONE = 4; // 0x4
@@ -37453,11 +38722,21 @@
     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_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";
     field public static final java.lang.String KEY_APN_EXPAND_BOOL = "apn_expand_bool";
     field public static final java.lang.String KEY_AUTO_RETRY_ENABLED_BOOL = "auto_retry_enabled_bool";
     field public static final java.lang.String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL = "carrier_allow_turnoff_ims_bool";
+    field public static final java.lang.String KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL = "carrier_force_disable_etws_cmas_test_bool";
+    field public static final java.lang.String KEY_CARRIER_IMS_GBA_REQUIRED_BOOL = "carrier_ims_gba_required_bool";
+    field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL = "carrier_instant_lettering_available_bool";
+    field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_ENCODING_STRING = "carrier_instant_lettering_encoding_string";
+    field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_ESCAPED_CHARS_STRING = "carrier_instant_lettering_escaped_chars_string";
+    field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_INVALID_CHARS_STRING = "carrier_instant_lettering_invalid_chars_string";
+    field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_LENGTH_LIMIT_INT = "carrier_instant_lettering_length_limit_int";
     field public static final java.lang.String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
     field public static final java.lang.String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
@@ -37466,20 +38745,30 @@
     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_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";
+    field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_BOOL = "ci_action_on_sys_update_bool";
+    field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING = "ci_action_on_sys_update_extra_string";
+    field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING = "ci_action_on_sys_update_extra_val_string";
+    field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING = "ci_action_on_sys_update_intent_string";
     field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
     field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
     field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
     field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
+    field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
     field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
     field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
+    field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
     field public static final java.lang.String KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = "gsm_nonroaming_networks_string_array";
     field public static final java.lang.String KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY = "gsm_roaming_networks_string_array";
     field public static final java.lang.String KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL = "has_in_call_noise_suppression_bool";
     field public static final java.lang.String KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool";
+    field public static final java.lang.String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool";
+    field public static final java.lang.String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool";
     field public static final java.lang.String KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool";
     field public static final java.lang.String KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL = "ignore_sim_network_locked_events_bool";
+    field public static final java.lang.String KEY_IMS_DTMF_TONE_DELAY_INT = "ims_dtmf_tone_delay_int";
     field public static final java.lang.String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled";
     field public static final java.lang.String KEY_MMS_ALIAS_MAX_CHARS_INT = "aliasMaxChars";
     field public static final java.lang.String KEY_MMS_ALIAS_MIN_CHARS_INT = "aliasMinChars";
@@ -37513,20 +38802,24 @@
     field public static final java.lang.String KEY_MMS_USER_AGENT_STRING = "userAgent";
     field public static final java.lang.String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool";
     field public static final java.lang.String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
+    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_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";
     field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
     field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
     field public static final java.lang.String KEY_USE_HFA_FOR_PROVISIONING_BOOL = "use_hfa_for_provisioning_bool";
     field public static final java.lang.String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool";
+    field public static final java.lang.String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
     field public static final java.lang.String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool";
     field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
     field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
     field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN = "vvm_cellular_data_required";
     field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
     field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
+    field public static final java.lang.String KEY_VVM_PREFETCH_BOOLEAN = "vvm_prefetch";
     field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
     field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
   }
@@ -37544,6 +38837,8 @@
 
   public final class CellIdentityGsm implements android.os.Parcelable {
     method public int describeContents();
+    method public int getArfcn();
+    method public int getBsic();
     method public int getCid();
     method public int getLac();
     method public int getMcc();
@@ -37556,6 +38851,7 @@
   public final class CellIdentityLte implements android.os.Parcelable {
     method public int describeContents();
     method public int getCi();
+    method public int getEarfcn();
     method public int getMcc();
     method public int getMnc();
     method public int getPci();
@@ -37571,6 +38867,7 @@
     method public int getMcc();
     method public int getMnc();
     method public int getPsc();
+    method public int getUarfcn();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityWcdma> CREATOR;
   }
@@ -37992,10 +39289,15 @@
     method public int getActiveSubscriptionInfoCountMax();
     method public android.telephony.SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int);
     method public java.util.List<android.telephony.SubscriptionInfo> getActiveSubscriptionInfoList();
+    method public static int getDefaultDataSubscriptionId();
+    method public static int getDefaultSmsSubscriptionId();
+    method public static int getDefaultSubscriptionId();
+    method public static int getDefaultVoiceSubscriptionId();
     method public boolean isNetworkRoaming(int);
     method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
     field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
     field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
+    field public static final int INVALID_SUBSCRIPTION_ID = -1; // 0xffffffff
   }
 
   public static class SubscriptionManager.OnSubscriptionsChangedListener {
@@ -38016,6 +39318,7 @@
     method public boolean endCall();
     method public java.util.List<android.telephony.CellInfo> getAllCellInfo();
     method public int getCallState();
+    method public int getCallState(int);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
     method public java.lang.String getCdmaMdn();
@@ -38028,29 +39331,47 @@
     method public int getDataActivity();
     method public boolean getDataEnabled();
     method public boolean getDataEnabled(int);
+    method public int getDataNetworkType(int);
     method public int getDataState();
     method public java.lang.String getDeviceId();
     method public java.lang.String getDeviceId(int);
     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 getLine1AlphaTag(int);
     method public java.lang.String getLine1Number();
+    method public java.lang.String getLine1Number(int);
     method public java.lang.String getMmsUAProfUrl();
     method public java.lang.String getMmsUserAgent();
     method public deprecated java.util.List<android.telephony.NeighboringCellInfo> getNeighboringCellInfo();
     method public java.lang.String getNetworkCountryIso();
+    method public java.lang.String getNetworkCountryIso(int);
     method public java.lang.String getNetworkOperator();
+    method public java.lang.String getNetworkOperator(int);
     method public java.lang.String getNetworkOperatorName();
+    method public java.lang.String getNetworkOperatorName(int);
     method public int getNetworkType();
+    method public int getNetworkType(int);
     method public int getPhoneCount();
     method public int getPhoneType();
     method public java.lang.String getSimCountryIso();
+    method public java.lang.String getSimCountryIso(int);
     method public java.lang.String getSimOperator();
+    method public java.lang.String getSimOperator(int);
     method public java.lang.String getSimOperatorName();
+    method public java.lang.String getSimOperatorName(int);
     method public java.lang.String getSimSerialNumber();
+    method public java.lang.String getSimSerialNumber(int);
     method public int getSimState();
     method public java.lang.String getSubscriberId();
+    method public java.lang.String getSubscriberId(int);
     method public java.lang.String getVoiceMailAlphaTag();
+    method public java.lang.String getVoiceMailAlphaTag(int);
     method public java.lang.String getVoiceMailNumber();
+    method public java.lang.String getVoiceMailNumber(int);
+    method public int getVoiceNetworkType(int);
+    method public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle);
     method public boolean handlePinMmi(java.lang.String);
     method public boolean handlePinMmiForSubscriber(int, java.lang.String);
     method public boolean hasCarrierPrivileges();
@@ -38064,14 +39385,15 @@
     method public boolean isHearingAidCompatibilitySupported();
     method public boolean isIdle();
     method public boolean isNetworkRoaming();
+    method public boolean isNetworkRoaming(int);
     method public boolean isOffhook();
     method public boolean isRadioOn();
     method public boolean isRinging();
-    method public boolean isSimPinEnabled();
     method public boolean isSmsCapable();
     method public boolean isTtyModeSupported();
     method public boolean isVideoCallingEnabled();
     method public boolean isVoiceCapable();
+    method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle);
     method public boolean isWorldPhone();
     method public void listen(android.telephony.PhoneStateListener, int);
     method public boolean needsOtaServiceProvisioning();
@@ -38079,11 +39401,13 @@
     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 setPreferredNetworkTypeToGlobal();
     method public boolean setRadio(boolean);
     method public boolean setRadioPower(boolean);
     method public boolean setVoiceMailNumber(java.lang.String, java.lang.String);
+    method public boolean setVoiceMailNumber(int, java.lang.String, java.lang.String);
     method public void silenceRinger();
     method public boolean supplyPin(java.lang.String);
     method public int[] supplyPinReportResult(java.lang.String);
@@ -38274,7 +39598,7 @@
     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public abstract class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
+  public abstract deprecated class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
     ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>);
     ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>);
     method public T getActivity();
@@ -38282,14 +39606,14 @@
     method public void setActivityIntent(android.content.Intent);
   }
 
-  public abstract class ActivityTestCase extends android.test.InstrumentationTestCase {
+  public abstract deprecated class ActivityTestCase extends android.test.InstrumentationTestCase {
     ctor public ActivityTestCase();
     method protected android.app.Activity getActivity();
     method protected void scrubClass(java.lang.Class<?>) throws java.lang.IllegalAccessException;
     method protected void setActivity(android.app.Activity);
   }
 
-  public abstract class ActivityUnitTestCase extends android.test.ActivityTestCase {
+  public abstract deprecated class ActivityUnitTestCase extends android.test.ActivityTestCase {
     ctor public ActivityUnitTestCase(java.lang.Class<T>);
     method public T getActivity();
     method public int getFinishedActivityRequest();
@@ -38302,7 +39626,7 @@
     method protected T startActivity(android.content.Intent, android.os.Bundle, java.lang.Object);
   }
 
-  public class AndroidTestCase extends junit.framework.TestCase {
+  public deprecated class AndroidTestCase extends junit.framework.TestCase {
     ctor public AndroidTestCase();
     method public void assertActivityRequiresPermission(java.lang.String, java.lang.String, java.lang.String);
     method public void assertReadingContentUriRequiresPermission(android.net.Uri, java.lang.String);
@@ -38314,7 +39638,7 @@
     field protected android.content.Context mContext;
   }
 
-  public class AndroidTestRunner extends junit.runner.BaseTestRunner {
+  public deprecated class AndroidTestRunner extends junit.runner.BaseTestRunner {
     ctor public AndroidTestRunner();
     method public void addTestListener(junit.framework.TestListener);
     method public void clearTestListeners();
@@ -38335,7 +39659,7 @@
     method public void testStarted(java.lang.String);
   }
 
-  public abstract class ApplicationTestCase extends android.test.AndroidTestCase {
+  public abstract deprecated class ApplicationTestCase extends android.test.AndroidTestCase {
     ctor public ApplicationTestCase(java.lang.Class<T>);
     method protected final void createApplication();
     method public T getApplication();
@@ -38353,10 +39677,10 @@
     ctor public ComparisonFailure(java.lang.String, java.lang.String, java.lang.String);
   }
 
-  public abstract class FlakyTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class FlakyTest implements java.lang.annotation.Annotation {
   }
 
-  public class InstrumentationTestCase extends junit.framework.TestCase {
+  public deprecated class InstrumentationTestCase extends junit.framework.TestCase {
     ctor public InstrumentationTestCase();
     method public android.app.Instrumentation getInstrumentation();
     method public deprecated void injectInsrumentation(android.app.Instrumentation);
@@ -38369,7 +39693,7 @@
     method public void sendRepeatedKeys(int...);
   }
 
-  public class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider {
+  public deprecated class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider {
     ctor public InstrumentationTestRunner();
     method public junit.framework.TestSuite getAllTests();
     method protected android.test.AndroidTestRunner getAndroidTestRunner();
@@ -38388,14 +39712,14 @@
     field public static final int REPORT_VALUE_RESULT_START = 1; // 0x1
   }
 
-  public class InstrumentationTestSuite extends junit.framework.TestSuite {
+  public deprecated class InstrumentationTestSuite extends junit.framework.TestSuite {
     ctor public InstrumentationTestSuite(android.app.Instrumentation);
     ctor public InstrumentationTestSuite(java.lang.String, android.app.Instrumentation);
     ctor public InstrumentationTestSuite(java.lang.Class, android.app.Instrumentation);
     method public void addTestSuite(java.lang.Class);
   }
 
-  public class IsolatedContext extends android.content.ContextWrapper {
+  public deprecated class IsolatedContext extends android.content.ContextWrapper {
     ctor public IsolatedContext(android.content.ContentResolver, android.content.Context);
     method public java.util.List<android.content.Intent> getAndClearBroadcastIntents();
   }
@@ -38405,7 +39729,7 @@
     method public T getLoaderResultSynchronously(android.content.Loader<T>);
   }
 
-  public final class MoreAsserts {
+  public final deprecated class MoreAsserts {
     method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Object);
     method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Class<?>);
     method public static java.util.regex.MatchResult assertContainsRegex(java.lang.String, java.lang.String, java.lang.String);
@@ -38444,7 +39768,7 @@
     method public static void checkEqualsAndHashCodeMethods(java.lang.Object, java.lang.Object, boolean);
   }
 
-  public abstract interface PerformanceTestCase {
+  public abstract deprecated interface PerformanceTestCase {
     method public abstract boolean isPerformanceOnly();
     method public abstract int startPerformance(android.test.PerformanceTestCase.Intermediates);
   }
@@ -38473,7 +39797,7 @@
     method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
-  public class RenamingDelegatingContext extends android.content.ContextWrapper {
+  public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper {
     ctor public RenamingDelegatingContext(android.content.Context, java.lang.String);
     ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String);
     method public java.lang.String getDatabasePrefix();
@@ -38482,7 +39806,7 @@
     method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
-  public abstract class ServiceTestCase extends android.test.AndroidTestCase {
+  public abstract deprecated class ServiceTestCase extends android.test.AndroidTestCase {
     ctor public ServiceTestCase(java.lang.Class<T>);
     method protected android.os.IBinder bindService(android.content.Intent);
     method public android.app.Application getApplication();
@@ -38495,23 +39819,23 @@
     method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public abstract class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
+  public abstract deprecated class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
     ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>);
     method public T getActivity();
     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public class SyncBaseInstrumentation extends android.test.InstrumentationTestCase {
+  public deprecated class SyncBaseInstrumentation extends android.test.InstrumentationTestCase {
     ctor public SyncBaseInstrumentation();
     method protected void cancelSyncsandDisableAutoSync();
     method protected void syncProvider(android.net.Uri, java.lang.String, java.lang.String) throws java.lang.Exception;
   }
 
-  public abstract interface TestSuiteProvider {
+  public abstract deprecated interface TestSuiteProvider {
     method public abstract junit.framework.TestSuite getTestSuite();
   }
 
-  public class TouchUtils {
+  public deprecated class TouchUtils {
     ctor public TouchUtils();
     method public static void clickView(android.test.InstrumentationTestCase, android.view.View);
     method public static deprecated void drag(android.test.ActivityInstrumentationTestCase, float, float, float, float, int);
@@ -38546,10 +39870,10 @@
     method public static void touchAndCancelView(android.test.InstrumentationTestCase, android.view.View);
   }
 
-  public abstract class UiThreadTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class UiThreadTest implements java.lang.annotation.Annotation {
   }
 
-  public class ViewAsserts {
+  public deprecated class ViewAsserts {
     method public static void assertBaselineAligned(android.view.View, android.view.View);
     method public static void assertBottomAligned(android.view.View, android.view.View);
     method public static void assertBottomAligned(android.view.View, android.view.View, int);
@@ -38574,11 +39898,11 @@
 
 package android.test.mock {
 
-  public class MockApplication extends android.app.Application {
+  public deprecated class MockApplication extends android.app.Application {
     ctor public MockApplication();
   }
 
-  public class MockContentProvider extends android.content.ContentProvider {
+  public deprecated class MockContentProvider extends android.content.ContentProvider {
     ctor protected MockContentProvider();
     ctor public MockContentProvider(android.content.Context);
     ctor public MockContentProvider(android.content.Context, java.lang.String, java.lang.String, android.content.pm.PathPermission[]);
@@ -38590,13 +39914,13 @@
     method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
   }
 
-  public class MockContentResolver extends android.content.ContentResolver {
+  public deprecated class MockContentResolver extends android.content.ContentResolver {
     ctor public MockContentResolver();
     ctor public MockContentResolver(android.content.Context);
     method public void addProvider(java.lang.String, android.content.ContentProvider);
   }
 
-  public class MockContext extends android.content.Context {
+  public deprecated class MockContext extends android.content.Context {
     ctor public MockContext();
     method public boolean bindService(android.content.Intent, android.content.ServiceConnection, int);
     method public int checkCallingOrSelfPermission(java.lang.String);
@@ -38700,7 +40024,7 @@
     method public void unregisterReceiver(android.content.BroadcastReceiver);
   }
 
-  public class MockCursor implements android.database.Cursor {
+  public deprecated class MockCursor implements android.database.Cursor {
     ctor public MockCursor();
     method public void close();
     method public void copyStringToBuffer(int, android.database.CharArrayBuffer);
@@ -38745,13 +40069,13 @@
     method public void unregisterDataSetObserver(android.database.DataSetObserver);
   }
 
-  public class MockDialogInterface implements android.content.DialogInterface {
+  public deprecated class MockDialogInterface implements android.content.DialogInterface {
     ctor public MockDialogInterface();
     method public void cancel();
     method public void dismiss();
   }
 
-  public class MockPackageManager extends android.content.pm.PackageManager {
+  public deprecated class MockPackageManager extends android.content.pm.PackageManager {
     ctor public MockPackageManager();
     method public void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
     method public void addPackageToPreferred(java.lang.String);
@@ -38785,10 +40109,7 @@
     method public android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public int getComponentEnabledSetting(android.content.ComponentName);
     method public android.graphics.drawable.Drawable getDefaultActivityIcon();
-    method public java.lang.String getDefaultBrowserPackageName(int);
     method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
-    method public byte[] getEphemeralCookie();
-    method public int getEphemeralCookieMaxSizeBytes();
     method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
     method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
     method public java.lang.String getInstallerPackageName(java.lang.String);
@@ -38797,8 +40118,10 @@
     method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public java.lang.String getNameForUid(int);
     method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInstaller getPackageInstaller();
+    method public int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] getPackagesForUid(int);
     method public java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int);
     method public int getPermissionFlags(java.lang.String, java.lang.String, android.os.UserHandle);
@@ -38821,7 +40144,6 @@
     method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
     method public void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
     method public boolean hasSystemFeature(java.lang.String);
-    method public boolean isEphemeralApplication();
     method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
     method public boolean isSafeMode();
     method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
@@ -38841,15 +40163,13 @@
     method public void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
     method public void setApplicationEnabledSetting(java.lang.String, int, int);
     method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
-    method public boolean setDefaultBrowserPackageName(java.lang.String, int);
-    method public boolean setEphemeralCookie(byte[]);
     method public void setInstallerPackageName(java.lang.String, java.lang.String);
     method public void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle);
     method public void verifyIntentFilter(int, int, java.util.List<java.lang.String>);
     method public void verifyPendingInstall(int, int);
   }
 
-  public class MockResources extends android.content.res.Resources {
+  public deprecated class MockResources extends android.content.res.Resources {
     ctor public MockResources();
   }
 
@@ -38890,19 +40210,19 @@
 
 package android.test.suitebuilder.annotation {
 
-  public abstract class LargeTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class LargeTest implements java.lang.annotation.Annotation {
   }
 
-  public abstract class MediumTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class MediumTest implements java.lang.annotation.Annotation {
   }
 
-  public abstract class SmallTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class SmallTest implements java.lang.annotation.Annotation {
   }
 
-  public abstract class Smoke implements java.lang.annotation.Annotation {
+  public abstract deprecated class Smoke implements java.lang.annotation.Annotation {
   }
 
-  public abstract class Suppress implements java.lang.annotation.Annotation {
+  public abstract deprecated class Suppress implements java.lang.annotation.Annotation {
   }
 
 }
@@ -39048,9 +40368,23 @@
 
   public class Html {
     method public static java.lang.String escapeHtml(java.lang.CharSequence);
-    method public static android.text.Spanned fromHtml(java.lang.String);
-    method public static android.text.Spanned fromHtml(java.lang.String, android.text.Html.ImageGetter, android.text.Html.TagHandler);
-    method public static java.lang.String toHtml(android.text.Spanned);
+    method public static deprecated android.text.Spanned fromHtml(java.lang.String);
+    method public static android.text.Spanned fromHtml(java.lang.String, int);
+    method public static deprecated android.text.Spanned fromHtml(java.lang.String, android.text.Html.ImageGetter, android.text.Html.TagHandler);
+    method public static android.text.Spanned fromHtml(java.lang.String, int, android.text.Html.ImageGetter, android.text.Html.TagHandler);
+    method public static deprecated java.lang.String toHtml(android.text.Spanned);
+    method public static java.lang.String toHtml(android.text.Spanned, int);
+    field public static final int FROM_HTML_MODE_COMPACT = 63; // 0x3f
+    field public static final int FROM_HTML_MODE_LEGACY = 0; // 0x0
+    field public static final int FROM_HTML_OPTION_USE_CSS_COLORS = 256; // 0x100
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_BLOCKQUOTE = 32; // 0x20
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_DIV = 16; // 0x10
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_HEADING = 2; // 0x2
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST = 8; // 0x8
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM = 4; // 0x4
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH = 1; // 0x1
+    field public static final int TO_HTML_PARAGRAPH_LINES_CONSECUTIVE = 0; // 0x0
+    field public static final int TO_HTML_PARAGRAPH_LINES_INDIVIDUAL = 1; // 0x1
   }
 
   public static abstract interface Html.ImageGetter {
@@ -40047,9 +41381,11 @@
 
   public class LocaleSpan extends android.text.style.MetricAffectingSpan implements android.text.ParcelableSpan {
     ctor public LocaleSpan(java.util.Locale);
+    ctor public LocaleSpan(android.util.LocaleList);
     ctor public LocaleSpan(android.os.Parcel);
     method public int describeContents();
     method public java.util.Locale getLocale();
+    method public android.util.LocaleList getLocales();
     method public int getSpanTypeId();
     method public void updateDrawState(android.text.TextPaint);
     method public void updateMeasureState(android.text.TextPaint);
@@ -40155,7 +41491,8 @@
     ctor public SuggestionSpan(android.os.Parcel);
     method public int describeContents();
     method public int getFlags();
-    method public java.lang.String getLocale();
+    method public deprecated java.lang.String getLocale();
+    method public java.util.Locale getLocaleObject();
     method public int getSpanTypeId();
     method public java.lang.String[] getSuggestions();
     method public void setFlags(int);
@@ -41075,7 +42412,9 @@
     method public static android.util.LocaleList getEmptyLocaleList();
     method public java.util.Locale getFirstMatch(java.lang.String[]);
     method public java.util.Locale getPrimary();
+    method public int indexOf(java.util.Locale);
     method public boolean isEmpty();
+    method public static void setDefault(android.util.LocaleList);
     method public int size();
     method public java.lang.String toLanguageTags();
     method public void writeToParcel(android.os.Parcel, int);
@@ -41233,7 +42572,7 @@
     method public static final java.lang.String digitsAndPlusOnly(java.util.regex.Matcher);
     field public static final java.util.regex.Pattern DOMAIN_NAME;
     field public static final java.util.regex.Pattern EMAIL_ADDRESS;
-    field public static final java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
+    field public static final deprecated java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
     field public static final java.util.regex.Pattern IP_ADDRESS;
     field public static final java.util.regex.Pattern PHONE;
     field public static final deprecated java.util.regex.Pattern TOP_LEVEL_DOMAIN;
@@ -41664,7 +43003,6 @@
     method public int getAction();
     method public android.content.ClipData getClipData();
     method public android.content.ClipDescription getClipDescription();
-    method public android.view.DropPermissionHolder getDropPermissionHolder();
     method public java.lang.Object getLocalState();
     method public boolean getResult();
     method public float getX();
@@ -41679,12 +43017,8 @@
     field public static final android.os.Parcelable.Creator<android.view.DragEvent> CREATOR;
   }
 
-  public class DropPermissionHolder implements android.os.Parcelable {
-    method public int describeContents();
-    method public void grant();
-    method public void revoke();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.view.DropPermissionHolder> CREATOR;
+  public final class DropPermissions {
+    method public void release();
   }
 
   public class FocusFinder {
@@ -42342,6 +43676,27 @@
     method public void startTracking(android.view.KeyEvent, java.lang.Object);
   }
 
+  public final class KeyboardShortcutGroup implements android.os.Parcelable {
+    ctor public KeyboardShortcutGroup(java.lang.CharSequence, java.util.List<android.view.KeyboardShortcutInfo>);
+    ctor public KeyboardShortcutGroup(java.lang.CharSequence);
+    method public void addItem(android.view.KeyboardShortcutInfo);
+    method public int describeContents();
+    method public java.util.List<android.view.KeyboardShortcutInfo> getItems();
+    method public java.lang.CharSequence getLabel();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.KeyboardShortcutGroup> CREATOR;
+  }
+
+  public final class KeyboardShortcutInfo implements android.os.Parcelable {
+    ctor public KeyboardShortcutInfo(java.lang.CharSequence, char, int);
+    method public int describeContents();
+    method public char getBaseCharacter();
+    method public java.lang.CharSequence getLabel();
+    method public int getModifiers();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.KeyboardShortcutInfo> CREATOR;
+  }
+
   public abstract class LayoutInflater {
     ctor protected LayoutInflater(android.content.Context);
     ctor protected LayoutInflater(android.view.LayoutInflater, android.content.Context);
@@ -42610,12 +43965,13 @@
     field public static final int AXIS_LTRIGGER = 17; // 0x11
     field public static final int AXIS_ORIENTATION = 8; // 0x8
     field public static final int AXIS_PRESSURE = 2; // 0x2
+    field public static final int AXIS_RELATIVE_X = 27; // 0x1b
+    field public static final int AXIS_RELATIVE_Y = 28; // 0x1c
     field public static final int AXIS_RTRIGGER = 18; // 0x12
     field public static final int AXIS_RUDDER = 20; // 0x14
     field public static final int AXIS_RX = 12; // 0xc
     field public static final int AXIS_RY = 13; // 0xd
     field public static final int AXIS_RZ = 14; // 0xe
-    field public static final int AXIS_SCROLL = 26; // 0x1a
     field public static final int AXIS_SIZE = 3; // 0x3
     field public static final int AXIS_THROTTLE = 19; // 0x13
     field public static final int AXIS_TILT = 25; // 0x19
@@ -43145,6 +44501,7 @@
     method public boolean hasNestedScrollingParent();
     method public boolean hasOnClickListeners();
     method public boolean hasOverlappingRendering();
+    method public boolean hasPointerCapture();
     method public boolean hasTransientState();
     method public boolean hasWindowFocus();
     method public static android.view.View inflate(android.content.Context, int, android.view.ViewGroup);
@@ -43271,6 +44628,7 @@
     method public void postOnAnimation(java.lang.Runnable);
     method public void postOnAnimationDelayed(java.lang.Runnable, long);
     method public void refreshDrawableState();
+    method public void releasePointerCapture();
     method public boolean removeCallbacks(java.lang.Runnable);
     method public void removeOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
     method public void removeOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
@@ -43371,6 +44729,7 @@
     method public void setPaddingRelative(int, int, int, int);
     method public void setPivotX(float);
     method public void setPivotY(float);
+    method public void setPointerCapture();
     method public void setPointerIcon(android.view.PointerIcon);
     method public void setPressed(boolean);
     method public final void setRight(int);
@@ -44340,6 +45699,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 abstract boolean onSearchRequested();
     method public abstract boolean onSearchRequested(android.view.SearchEvent);
     method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
@@ -44667,6 +46027,7 @@
     method public android.view.accessibility.AccessibilityNodeInfo.CollectionInfo getCollectionInfo();
     method public android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo getCollectionItemInfo();
     method public java.lang.CharSequence getContentDescription();
+    method public int getDrawingOrder();
     method public java.lang.CharSequence getError();
     method public android.os.Bundle getExtras();
     method public int getInputType();
@@ -44729,6 +46090,7 @@
     method public void setContentInvalid(boolean);
     method public void setContextClickable(boolean);
     method public void setDismissable(boolean);
+    method public void setDrawingOrder(int);
     method public void setEditable(boolean);
     method public void setEnabled(boolean);
     method public void setError(java.lang.CharSequence);
@@ -45285,6 +46647,7 @@
     method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public boolean commitText(java.lang.CharSequence, int);
     method public boolean deleteSurroundingText(int, int);
+    method public boolean deleteSurroundingTextInCodePoints(int, int);
     method public boolean endBatchEdit();
     method public boolean finishComposingText();
     method public static int getComposingSpanEnd(android.text.Spannable);
@@ -45392,6 +46755,7 @@
     field public android.os.Bundle extras;
     field public int fieldId;
     field public java.lang.String fieldName;
+    field public android.util.LocaleList hintLocales;
     field public java.lang.CharSequence hintText;
     field public int imeOptions;
     field public int initialCapsMode;
@@ -45399,7 +46763,6 @@
     field public int initialSelStart;
     field public int inputType;
     field public java.lang.CharSequence label;
-    field public android.util.LocaleList locales;
     field public java.lang.String packageName;
     field public java.lang.String privateImeOptions;
   }
@@ -45450,6 +46813,7 @@
     method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public abstract boolean commitText(java.lang.CharSequence, int);
     method public abstract boolean deleteSurroundingText(int, int);
+    method public abstract boolean deleteSurroundingTextInCodePoints(int, int);
     method public abstract boolean endBatchEdit();
     method public abstract boolean finishComposingText();
     method public abstract int getCursorCapsMode(int);
@@ -45480,6 +46844,7 @@
     method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public boolean commitText(java.lang.CharSequence, int);
     method public boolean deleteSurroundingText(int, int);
+    method public boolean deleteSurroundingTextInCodePoints(int, int);
     method public boolean endBatchEdit();
     method public boolean finishComposingText();
     method public int getCursorCapsMode(int);
@@ -45542,6 +46907,7 @@
   }
 
   public final class InputMethodManager {
+    method public void dispatchKeyEventFromInputMethod(android.view.View, android.view.KeyEvent);
     method public void displayCompletions(android.view.View, android.view.inputmethod.CompletionInfo[]);
     method public android.view.inputmethod.InputMethodSubtype getCurrentInputMethodSubtype();
     method public java.util.List<android.view.inputmethod.InputMethodInfo> getEnabledInputMethodList();
@@ -45927,12 +47293,54 @@
     method public abstract android.view.View getFullScreenView(int, android.content.Context);
   }
 
+  public class ServiceWorkerClient {
+    ctor public ServiceWorkerClient();
+    method public android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebResourceRequest);
+  }
+
+  public abstract class ServiceWorkerController {
+    ctor public ServiceWorkerController();
+    method public static android.webkit.ServiceWorkerController getInstance();
+    method public abstract android.webkit.ServiceWorkerWebSettings getServiceWorkerWebSettings();
+    method public abstract void setServiceWorkerClient(android.webkit.ServiceWorkerClient);
+  }
+
+  public abstract class ServiceWorkerWebSettings {
+    ctor public ServiceWorkerWebSettings();
+    method public abstract boolean getAllowContentAccess();
+    method public abstract boolean getAllowFileAccess();
+    method public abstract boolean getBlockNetworkLoads();
+    method public abstract int getCacheMode();
+    method public abstract void setAllowContentAccess(boolean);
+    method public abstract void setAllowFileAccess(boolean);
+    method public abstract void setBlockNetworkLoads(boolean);
+    method public abstract void setCacheMode(int);
+  }
+
   public class SslErrorHandler extends android.os.Handler {
     ctor public SslErrorHandler();
     method public void cancel();
     method public void proceed();
   }
 
+  public abstract class TokenBindingService {
+    ctor public TokenBindingService();
+    method public abstract void deleteAllKeys(android.webkit.ValueCallback<java.lang.Boolean>);
+    method public abstract void deleteKey(android.net.Uri, android.webkit.ValueCallback<java.lang.Boolean>);
+    method public abstract void enableTokenBinding();
+    method public static android.webkit.TokenBindingService getInstance();
+    method public abstract void getKey(android.net.Uri, java.lang.String[], android.webkit.ValueCallback<android.webkit.TokenBindingService.TokenBindingKey>);
+    field public static final java.lang.String KEY_ALGORITHM_ECDSAP256 = "ECDSAP256";
+    field public static final java.lang.String KEY_ALGORITHM_RSA2048_PKCS_1_5 = "RSA2048_PKCS_1.5";
+    field public static final java.lang.String KEY_ALGORITHM_RSA2048_PSS = "RSA2048PSS";
+  }
+
+  public static abstract class TokenBindingService.TokenBindingKey {
+    ctor public TokenBindingService.TokenBindingKey();
+    method public abstract java.lang.String getAlgorithm();
+    method public abstract java.security.KeyPair getKeyPair();
+  }
+
   public final class URLUtil {
     ctor public URLUtil();
     method public static java.lang.String composeSearchUrl(java.lang.String, java.lang.String, java.lang.String);
@@ -46170,7 +47578,7 @@
     method public abstract deprecated void setEnableSmoothTransition(boolean);
     method public abstract void setFantasyFontFamily(java.lang.String);
     method public abstract void setFixedFontFamily(java.lang.String);
-    method public abstract void setGeolocationDatabasePath(java.lang.String);
+    method public abstract deprecated void setGeolocationDatabasePath(java.lang.String);
     method public abstract void setGeolocationEnabled(boolean);
     method public abstract void setJavaScriptCanOpenWindowsAutomatically(boolean);
     method public abstract void setJavaScriptEnabled(boolean);
@@ -46554,7 +47962,9 @@
     method public abstract android.webkit.WebViewProvider createWebView(android.webkit.WebView, android.webkit.WebView.PrivateAccess);
     method public abstract android.webkit.CookieManager getCookieManager();
     method public abstract android.webkit.GeolocationPermissions getGeolocationPermissions();
+    method public abstract android.webkit.ServiceWorkerController getServiceWorkerController();
     method public abstract android.webkit.WebViewFactoryProvider.Statics getStatics();
+    method public abstract android.webkit.TokenBindingService getTokenBindingService();
     method public abstract android.webkit.WebIconDatabase getWebIconDatabase();
     method public abstract android.webkit.WebStorage getWebStorage();
     method public abstract android.webkit.WebViewDatabase getWebViewDatabase(android.content.Context);
@@ -46857,12 +48267,18 @@
     method public int getThumbOffset();
     method public android.content.res.ColorStateList getThumbTintList();
     method public android.graphics.PorterDuff.Mode getThumbTintMode();
+    method public android.graphics.drawable.Drawable getTickMark();
+    method public android.content.res.ColorStateList getTickMarkTintList();
+    method public android.graphics.PorterDuff.Mode getTickMarkTintMode();
     method public void setKeyProgressIncrement(int);
     method public void setSplitTrack(boolean);
     method public void setThumb(android.graphics.drawable.Drawable);
     method public void setThumbOffset(int);
     method public void setThumbTintList(android.content.res.ColorStateList);
     method public void setThumbTintMode(android.graphics.PorterDuff.Mode);
+    method public void setTickMark(android.graphics.drawable.Drawable);
+    method public void setTickMarkTintList(android.content.res.ColorStateList);
+    method public void setTickMarkTintMode(android.graphics.PorterDuff.Mode);
   }
 
   public abstract class AbsSpinner extends android.widget.AdapterView {
@@ -47819,6 +49235,7 @@
     method public int getBaselineAlignedChildIndex();
     method public android.graphics.drawable.Drawable getDividerDrawable();
     method public int getDividerPadding();
+    method public int getGravity();
     method public int getOrientation();
     method public int getShowDividers();
     method public float getWeightSum();
@@ -48949,6 +50366,7 @@
     method public int getHyphenationFrequency();
     method public int getImeActionId();
     method public java.lang.CharSequence getImeActionLabel();
+    method public android.util.LocaleList getImeHintLocales();
     method public int getImeOptions();
     method public boolean getIncludeFontPadding();
     method public android.os.Bundle getInputExtras(boolean);
@@ -49055,6 +50473,7 @@
     method public void setHorizontallyScrolling(boolean);
     method public void setHyphenationFrequency(int);
     method public void setImeActionLabel(java.lang.CharSequence, int);
+    method public void setImeHintLocales(android.util.LocaleList);
     method public void setImeOptions(int);
     method public void setIncludeFontPadding(boolean);
     method public void setInputExtras(int) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -50008,10 +51427,8 @@
   }
 
   public final class Console implements java.io.Flushable {
-    method public static java.io.Console console();
     method public void flush();
     method public java.io.Console format(java.lang.String, java.lang.Object...);
-    method public static synchronized java.io.Console getConsole();
     method public java.io.Console printf(java.lang.String, java.lang.Object...);
     method public java.lang.String readLine(java.lang.String, java.lang.Object...);
     method public java.lang.String readLine();
@@ -50154,7 +51571,6 @@
     method public boolean setReadable(boolean);
     method public boolean setWritable(boolean, boolean);
     method public boolean setWritable(boolean);
-    method public java.nio.file.Path toPath();
     method public java.net.URI toURI();
     method public deprecated java.net.URL toURL() throws java.net.MalformedURLException;
     field public static final java.lang.String pathSeparator;
@@ -50295,7 +51711,6 @@
   public class InterruptedIOException extends java.io.IOException {
     ctor public InterruptedIOException();
     ctor public InterruptedIOException(java.lang.String);
-    ctor public InterruptedIOException(java.lang.Throwable);
     field public int bytesTransferred;
   }
 
@@ -50966,7 +52381,6 @@
     method public long longValue();
     method public static byte parseByte(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static byte parseByte(java.lang.String) throws java.lang.NumberFormatException;
-    method public static java.lang.String toHexString(byte, boolean);
     method public static java.lang.String toString(byte);
     method public static java.lang.Byte valueOf(byte);
     method public static java.lang.Byte valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -51709,6 +53123,9 @@
     field public static final java.lang.Class<java.lang.Float> TYPE;
   }
 
+  public abstract class FunctionalInterface implements java.lang.annotation.Annotation {
+  }
+
   public class IllegalAccessError extends java.lang.IncompatibleClassChangeError {
     ctor public IllegalAccessError();
     ctor public IllegalAccessError(java.lang.String);
@@ -51810,6 +53227,8 @@
   public class InternalError extends java.lang.VirtualMachineError {
     ctor public InternalError();
     ctor public InternalError(java.lang.String);
+    ctor public InternalError(java.lang.String, java.lang.Throwable);
+    ctor public InternalError(java.lang.Throwable);
   }
 
   public class InterruptedException extends java.lang.Exception {
@@ -52582,6 +54001,8 @@
   public abstract class VirtualMachineError extends java.lang.Error {
     ctor public VirtualMachineError();
     ctor public VirtualMachineError(java.lang.String);
+    ctor public VirtualMachineError(java.lang.String, java.lang.Throwable);
+    ctor public VirtualMachineError(java.lang.Throwable);
   }
 
   public final class Void {
@@ -52834,6 +54255,7 @@
     method public java.lang.Object invoke(java.lang.Object, java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException;
     method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
     method public boolean isBridge();
+    method public boolean isDefault();
     method public boolean isSynthetic();
     method public boolean isVarArgs();
     method public java.lang.String toGenericString();
@@ -53114,7 +54536,6 @@
   public class BindException extends java.net.SocketException {
     ctor public BindException(java.lang.String);
     ctor public BindException();
-    ctor public BindException(java.lang.String, java.lang.Throwable);
   }
 
   public abstract class CacheRequest {
@@ -53132,7 +54553,6 @@
   public class ConnectException extends java.net.SocketException {
     ctor public ConnectException(java.lang.String);
     ctor public ConnectException();
-    ctor public ConnectException(java.lang.String, java.lang.Throwable);
   }
 
   public abstract class ContentHandler {
@@ -53212,7 +54632,6 @@
     method public void disconnect();
     method public synchronized boolean getBroadcast() throws java.net.SocketException;
     method public java.nio.channels.DatagramChannel getChannel();
-    method public final java.io.FileDescriptor getFileDescriptor$();
     method public java.net.InetAddress getInetAddress();
     method public java.net.InetAddress getLocalAddress();
     method public int getLocalPort();
@@ -53289,7 +54708,6 @@
     method public boolean hasExpired();
     method public boolean isHttpOnly();
     method public static java.util.List<java.net.HttpCookie> parse(java.lang.String);
-    method public static java.util.List<java.net.HttpCookie> parse(java.lang.String, boolean);
     method public void setComment(java.lang.String);
     method public void setCommentURL(java.lang.String);
     method public void setDiscard(boolean);
@@ -53382,9 +54800,6 @@
   }
 
   public final class Inet4Address extends java.net.InetAddress {
-    field public static final java.net.InetAddress ALL;
-    field public static final java.net.InetAddress ANY;
-    field public static final java.net.InetAddress LOOPBACK;
   }
 
   public final class Inet6Address extends java.net.InetAddress {
@@ -53393,8 +54808,6 @@
     method public int getScopeId();
     method public java.net.NetworkInterface getScopedInterface();
     method public boolean isIPv4CompatibleAddress();
-    field public static final java.net.InetAddress ANY;
-    field public static final java.net.InetAddress LOOPBACK;
   }
 
   public class InetAddress implements java.io.Serializable {
@@ -53522,13 +54935,11 @@
   public class PortUnreachableException extends java.net.SocketException {
     ctor public PortUnreachableException(java.lang.String);
     ctor public PortUnreachableException();
-    ctor public PortUnreachableException(java.lang.String, java.lang.Throwable);
   }
 
   public class ProtocolException extends java.io.IOException {
     ctor public ProtocolException(java.lang.String);
     ctor public ProtocolException();
-    ctor public ProtocolException(java.lang.String, java.lang.Throwable);
   }
 
   public abstract interface ProtocolFamily {
@@ -53663,8 +55074,6 @@
   public class SocketException extends java.io.IOException {
     ctor public SocketException(java.lang.String);
     ctor public SocketException();
-    ctor public SocketException(java.lang.Throwable);
-    ctor public SocketException(java.lang.String, java.lang.Throwable);
   }
 
   public abstract class SocketImpl implements java.net.SocketOptions {
@@ -53734,8 +55143,6 @@
   public class SocketTimeoutException extends java.io.InterruptedIOException {
     ctor public SocketTimeoutException(java.lang.String);
     ctor public SocketTimeoutException();
-    ctor public SocketTimeoutException(java.lang.Throwable);
-    ctor public SocketTimeoutException(java.lang.String, java.lang.Throwable);
   }
 
   public final class StandardProtocolFamily extends java.lang.Enum implements java.net.ProtocolFamily {
@@ -54262,25 +55669,6 @@
     ctor public AsynchronousCloseException();
   }
 
-  public abstract class AsynchronousFileChannel implements java.nio.channels.AsynchronousChannel {
-    ctor protected AsynchronousFileChannel();
-    method public abstract void force(boolean) throws java.io.IOException;
-    method public abstract void lock(long, long, boolean, A, java.nio.channels.CompletionHandler<java.nio.channels.FileLock, ? super A>);
-    method public final void lock(A, java.nio.channels.CompletionHandler<java.nio.channels.FileLock, ? super A>);
-    method public abstract java.util.concurrent.Future<java.nio.channels.FileLock> lock(long, long, boolean);
-    method public final java.util.concurrent.Future<java.nio.channels.FileLock> lock();
-    method public static java.nio.channels.AsynchronousFileChannel open(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.util.concurrent.ExecutorService, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.channels.AsynchronousFileChannel open(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public abstract void read(java.nio.ByteBuffer, long, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
-    method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer, long);
-    method public abstract long size() throws java.io.IOException;
-    method public abstract java.nio.channels.AsynchronousFileChannel truncate(long) throws java.io.IOException;
-    method public abstract java.nio.channels.FileLock tryLock(long, long, boolean) throws java.io.IOException;
-    method public final java.nio.channels.FileLock tryLock() throws java.io.IOException;
-    method public abstract void write(java.nio.ByteBuffer, long, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
-    method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer, long);
-  }
-
   public abstract class AsynchronousServerSocketChannel implements java.nio.channels.AsynchronousChannel java.nio.channels.NetworkChannel {
     ctor protected AsynchronousServerSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
     method public abstract void accept(A, java.nio.channels.CompletionHandler<java.nio.channels.AsynchronousSocketChannel, ? super A>);
@@ -54389,8 +55777,6 @@
     method public abstract java.nio.channels.FileLock lock(long, long, boolean) throws java.io.IOException;
     method public final java.nio.channels.FileLock lock() throws java.io.IOException;
     method public abstract java.nio.MappedByteBuffer map(java.nio.channels.FileChannel.MapMode, long, long) throws java.io.IOException;
-    method public static java.nio.channels.FileChannel open(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.channels.FileChannel open(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
     method public abstract long position() throws java.io.IOException;
     method public abstract java.nio.channels.FileChannel position(long) throws java.io.IOException;
     method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
@@ -54417,7 +55803,6 @@
 
   public abstract class FileLock implements java.lang.AutoCloseable {
     ctor protected FileLock(java.nio.channels.FileChannel, long, long, boolean);
-    ctor protected FileLock(java.nio.channels.AsynchronousFileChannel, long, long, boolean);
     method public java.nio.channels.Channel acquiredBy();
     method public final java.nio.channels.FileChannel channel();
     method public final void close() throws java.io.IOException;
@@ -54867,592 +56252,6 @@
 
 }
 
-package java.nio.file {
-
-  public class AccessDeniedException extends java.nio.file.FileSystemException {
-    ctor public AccessDeniedException(java.lang.String);
-    ctor public AccessDeniedException(java.lang.String, java.lang.String, java.lang.String);
-  }
-
-  public final class AccessMode extends java.lang.Enum {
-    method public static java.nio.file.AccessMode valueOf(java.lang.String);
-    method public static final java.nio.file.AccessMode[] values();
-    enum_constant public static final java.nio.file.AccessMode EXECUTE;
-    enum_constant public static final java.nio.file.AccessMode READ;
-    enum_constant public static final java.nio.file.AccessMode WRITE;
-  }
-
-  public class AtomicMoveNotSupportedException extends java.nio.file.FileSystemException {
-    ctor public AtomicMoveNotSupportedException(java.lang.String, java.lang.String, java.lang.String);
-  }
-
-  public class ClosedDirectoryStreamException extends java.lang.IllegalStateException {
-    ctor public ClosedDirectoryStreamException();
-  }
-
-  public class ClosedFileSystemException extends java.lang.IllegalStateException {
-    ctor public ClosedFileSystemException();
-  }
-
-  public class ClosedWatchServiceException extends java.lang.IllegalStateException {
-    ctor public ClosedWatchServiceException();
-  }
-
-  public abstract interface CopyOption {
-  }
-
-  public final class DirectoryIteratorException extends java.util.ConcurrentModificationException {
-    ctor public DirectoryIteratorException(java.io.IOException);
-  }
-
-  public class DirectoryNotEmptyException extends java.nio.file.FileSystemException {
-    ctor public DirectoryNotEmptyException(java.lang.String);
-  }
-
-  public abstract interface DirectoryStream implements java.io.Closeable java.lang.Iterable {
-    method public abstract java.util.Iterator<T> iterator();
-  }
-
-  public static abstract interface DirectoryStream.Filter {
-    method public abstract boolean accept(T) throws java.io.IOException;
-  }
-
-  public class FileAlreadyExistsException extends java.nio.file.FileSystemException {
-    ctor public FileAlreadyExistsException(java.lang.String);
-    ctor public FileAlreadyExistsException(java.lang.String, java.lang.String, java.lang.String);
-  }
-
-  public abstract class FileStore {
-    ctor protected FileStore();
-    method public abstract java.lang.Object getAttribute(java.lang.String) throws java.io.IOException;
-    method public abstract V getFileStoreAttributeView(java.lang.Class<V>);
-    method public abstract long getTotalSpace() throws java.io.IOException;
-    method public abstract long getUnallocatedSpace() throws java.io.IOException;
-    method public abstract long getUsableSpace() throws java.io.IOException;
-    method public abstract boolean isReadOnly();
-    method public abstract java.lang.String name();
-    method public abstract boolean supportsFileAttributeView(java.lang.Class<? extends java.nio.file.attribute.FileAttributeView>);
-    method public abstract boolean supportsFileAttributeView(java.lang.String);
-    method public abstract java.lang.String type();
-  }
-
-  public abstract class FileSystem implements java.io.Closeable {
-    ctor protected FileSystem();
-    method public abstract void close() throws java.io.IOException;
-    method public abstract java.lang.Iterable<java.nio.file.FileStore> getFileStores();
-    method public abstract java.nio.file.Path getPath(java.lang.String, java.lang.String...);
-    method public abstract java.nio.file.PathMatcher getPathMatcher(java.lang.String);
-    method public abstract java.lang.Iterable<java.nio.file.Path> getRootDirectories();
-    method public abstract java.lang.String getSeparator();
-    method public abstract java.nio.file.attribute.UserPrincipalLookupService getUserPrincipalLookupService();
-    method public abstract boolean isOpen();
-    method public abstract boolean isReadOnly();
-    method public abstract java.nio.file.WatchService newWatchService() throws java.io.IOException;
-    method public abstract java.nio.file.spi.FileSystemProvider provider();
-    method public abstract java.util.Set<java.lang.String> supportedFileAttributeViews();
-  }
-
-  public class FileSystemAlreadyExistsException extends java.lang.RuntimeException {
-    ctor public FileSystemAlreadyExistsException();
-    ctor public FileSystemAlreadyExistsException(java.lang.String);
-  }
-
-  public class FileSystemException extends java.io.IOException {
-    ctor public FileSystemException(java.lang.String);
-    ctor public FileSystemException(java.lang.String, java.lang.String, java.lang.String);
-    method public java.lang.String getFile();
-    method public java.lang.String getOtherFile();
-    method public java.lang.String getReason();
-  }
-
-  public class FileSystemLoopException extends java.nio.file.FileSystemException {
-    ctor public FileSystemLoopException(java.lang.String);
-  }
-
-  public class FileSystemNotFoundException extends java.lang.RuntimeException {
-    ctor public FileSystemNotFoundException();
-    ctor public FileSystemNotFoundException(java.lang.String);
-  }
-
-  public final class FileSystems {
-    method public static java.nio.file.FileSystem getDefault();
-    method public static java.nio.file.FileSystem getFileSystem(java.net.URI);
-    method public static java.nio.file.FileSystem newFileSystem(java.net.URI, java.util.Map<java.lang.String, ?>) throws java.io.IOException;
-    method public static java.nio.file.FileSystem newFileSystem(java.net.URI, java.util.Map<java.lang.String, ?>, java.lang.ClassLoader) throws java.io.IOException;
-    method public static java.nio.file.FileSystem newFileSystem(java.nio.file.Path, java.lang.ClassLoader) throws java.io.IOException;
-  }
-
-  public final class FileVisitOption extends java.lang.Enum {
-    method public static java.nio.file.FileVisitOption valueOf(java.lang.String);
-    method public static final java.nio.file.FileVisitOption[] values();
-    enum_constant public static final java.nio.file.FileVisitOption FOLLOW_LINKS;
-  }
-
-  public final class FileVisitResult extends java.lang.Enum {
-    method public static java.nio.file.FileVisitResult valueOf(java.lang.String);
-    method public static final java.nio.file.FileVisitResult[] values();
-    enum_constant public static final java.nio.file.FileVisitResult CONTINUE;
-    enum_constant public static final java.nio.file.FileVisitResult SKIP_SIBLINGS;
-    enum_constant public static final java.nio.file.FileVisitResult SKIP_SUBTREE;
-    enum_constant public static final java.nio.file.FileVisitResult TERMINATE;
-  }
-
-  public abstract interface FileVisitor {
-    method public abstract java.nio.file.FileVisitResult postVisitDirectory(T, java.io.IOException) throws java.io.IOException;
-    method public abstract java.nio.file.FileVisitResult preVisitDirectory(T, java.nio.file.attribute.BasicFileAttributes) throws java.io.IOException;
-    method public abstract java.nio.file.FileVisitResult visitFile(T, java.nio.file.attribute.BasicFileAttributes) throws java.io.IOException;
-    method public abstract java.nio.file.FileVisitResult visitFileFailed(T, java.io.IOException) throws java.io.IOException;
-  }
-
-  public final class Files {
-    method public static java.nio.file.Path copy(java.nio.file.Path, java.nio.file.Path, java.nio.file.CopyOption...) throws java.io.IOException;
-    method public static long copy(java.io.InputStream, java.nio.file.Path, java.nio.file.CopyOption...) throws java.io.IOException;
-    method public static long copy(java.nio.file.Path, java.io.OutputStream) throws java.io.IOException;
-    method public static java.nio.file.Path createDirectories(java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createDirectory(java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createFile(java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createLink(java.nio.file.Path, java.nio.file.Path) throws java.io.IOException;
-    method public static java.nio.file.Path createSymbolicLink(java.nio.file.Path, java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createTempDirectory(java.nio.file.Path, java.lang.String, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createTempDirectory(java.lang.String, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createTempFile(java.nio.file.Path, java.lang.String, java.lang.String, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createTempFile(java.lang.String, java.lang.String, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static void delete(java.nio.file.Path) throws java.io.IOException;
-    method public static boolean deleteIfExists(java.nio.file.Path) throws java.io.IOException;
-    method public static boolean exists(java.nio.file.Path, java.nio.file.LinkOption...);
-    method public static java.lang.Object getAttribute(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static V getFileAttributeView(java.nio.file.Path, java.lang.Class<V>, java.nio.file.LinkOption...);
-    method public static java.nio.file.FileStore getFileStore(java.nio.file.Path) throws java.io.IOException;
-    method public static java.nio.file.attribute.FileTime getLastModifiedTime(java.nio.file.Path, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static java.nio.file.attribute.UserPrincipal getOwner(java.nio.file.Path, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static java.util.Set<java.nio.file.attribute.PosixFilePermission> getPosixFilePermissions(java.nio.file.Path, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static boolean isDirectory(java.nio.file.Path, java.nio.file.LinkOption...);
-    method public static boolean isExecutable(java.nio.file.Path);
-    method public static boolean isHidden(java.nio.file.Path) throws java.io.IOException;
-    method public static boolean isReadable(java.nio.file.Path);
-    method public static boolean isRegularFile(java.nio.file.Path, java.nio.file.LinkOption...);
-    method public static boolean isSameFile(java.nio.file.Path, java.nio.file.Path) throws java.io.IOException;
-    method public static boolean isSymbolicLink(java.nio.file.Path);
-    method public static boolean isWritable(java.nio.file.Path);
-    method public static java.nio.file.Path move(java.nio.file.Path, java.nio.file.Path, java.nio.file.CopyOption...) throws java.io.IOException;
-    method public static java.io.BufferedReader newBufferedReader(java.nio.file.Path, java.nio.charset.Charset) throws java.io.IOException;
-    method public static java.io.BufferedWriter newBufferedWriter(java.nio.file.Path, java.nio.charset.Charset, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public static java.nio.channels.SeekableByteChannel newByteChannel(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.channels.SeekableByteChannel newByteChannel(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public static java.nio.file.DirectoryStream<java.nio.file.Path> newDirectoryStream(java.nio.file.Path) throws java.io.IOException;
-    method public static java.nio.file.DirectoryStream<java.nio.file.Path> newDirectoryStream(java.nio.file.Path, java.lang.String) throws java.io.IOException;
-    method public static java.nio.file.DirectoryStream<java.nio.file.Path> newDirectoryStream(java.nio.file.Path, java.nio.file.DirectoryStream.Filter<? super java.nio.file.Path>) throws java.io.IOException;
-    method public static java.io.InputStream newInputStream(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public static java.io.OutputStream newOutputStream(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public static boolean notExists(java.nio.file.Path, java.nio.file.LinkOption...);
-    method public static java.lang.String probeContentType(java.nio.file.Path) throws java.io.IOException;
-    method public static byte[] readAllBytes(java.nio.file.Path) throws java.io.IOException;
-    method public static java.util.List<java.lang.String> readAllLines(java.nio.file.Path, java.nio.charset.Charset) throws java.io.IOException;
-    method public static A readAttributes(java.nio.file.Path, java.lang.Class<A>, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static java.util.Map<java.lang.String, java.lang.Object> readAttributes(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static java.nio.file.Path readSymbolicLink(java.nio.file.Path) throws java.io.IOException;
-    method public static java.nio.file.Path setAttribute(java.nio.file.Path, java.lang.String, java.lang.Object, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static java.nio.file.Path setLastModifiedTime(java.nio.file.Path, java.nio.file.attribute.FileTime) throws java.io.IOException;
-    method public static java.nio.file.Path setOwner(java.nio.file.Path, java.nio.file.attribute.UserPrincipal) throws java.io.IOException;
-    method public static java.nio.file.Path setPosixFilePermissions(java.nio.file.Path, java.util.Set<java.nio.file.attribute.PosixFilePermission>) throws java.io.IOException;
-    method public static long size(java.nio.file.Path) throws java.io.IOException;
-    method public static java.nio.file.Path walkFileTree(java.nio.file.Path, java.util.Set<java.nio.file.FileVisitOption>, int, java.nio.file.FileVisitor<? super java.nio.file.Path>) throws java.io.IOException;
-    method public static java.nio.file.Path walkFileTree(java.nio.file.Path, java.nio.file.FileVisitor<? super java.nio.file.Path>) throws java.io.IOException;
-    method public static java.nio.file.Path write(java.nio.file.Path, byte[], java.nio.file.OpenOption...) throws java.io.IOException;
-    method public static java.nio.file.Path write(java.nio.file.Path, java.lang.Iterable<? extends java.lang.CharSequence>, java.nio.charset.Charset, java.nio.file.OpenOption...) throws java.io.IOException;
-  }
-
-  public class InvalidPathException extends java.lang.IllegalArgumentException {
-    ctor public InvalidPathException(java.lang.String, java.lang.String, int);
-    ctor public InvalidPathException(java.lang.String, java.lang.String);
-    method public int getIndex();
-    method public java.lang.String getInput();
-    method public java.lang.String getReason();
-  }
-
-  public final class LinkOption extends java.lang.Enum implements java.nio.file.CopyOption java.nio.file.OpenOption {
-    method public static java.nio.file.LinkOption valueOf(java.lang.String);
-    method public static final java.nio.file.LinkOption[] values();
-    enum_constant public static final java.nio.file.LinkOption NOFOLLOW_LINKS;
-  }
-
-  public final class LinkPermission extends java.security.BasicPermission {
-    ctor public LinkPermission(java.lang.String);
-    ctor public LinkPermission(java.lang.String, java.lang.String);
-  }
-
-  public class NoSuchFileException extends java.nio.file.FileSystemException {
-    ctor public NoSuchFileException(java.lang.String);
-    ctor public NoSuchFileException(java.lang.String, java.lang.String, java.lang.String);
-  }
-
-  public class NotDirectoryException extends java.nio.file.FileSystemException {
-    ctor public NotDirectoryException(java.lang.String);
-  }
-
-  public class NotLinkException extends java.nio.file.FileSystemException {
-    ctor public NotLinkException(java.lang.String);
-    ctor public NotLinkException(java.lang.String, java.lang.String, java.lang.String);
-  }
-
-  public abstract interface OpenOption {
-  }
-
-  public abstract interface Path implements java.lang.Comparable java.lang.Iterable java.nio.file.Watchable {
-    method public abstract int compareTo(java.nio.file.Path);
-    method public abstract boolean endsWith(java.nio.file.Path);
-    method public abstract boolean endsWith(java.lang.String);
-    method public abstract boolean equals(java.lang.Object);
-    method public abstract java.nio.file.Path getFileName();
-    method public abstract java.nio.file.FileSystem getFileSystem();
-    method public abstract java.nio.file.Path getName(int);
-    method public abstract int getNameCount();
-    method public abstract java.nio.file.Path getParent();
-    method public abstract java.nio.file.Path getRoot();
-    method public abstract int hashCode();
-    method public abstract boolean isAbsolute();
-    method public abstract java.util.Iterator<java.nio.file.Path> iterator();
-    method public abstract java.nio.file.Path normalize();
-    method public abstract java.nio.file.WatchKey register(java.nio.file.WatchService, java.nio.file.WatchEvent.Kind<?>[], java.nio.file.WatchEvent.Modifier...) throws java.io.IOException;
-    method public abstract java.nio.file.WatchKey register(java.nio.file.WatchService, java.nio.file.WatchEvent.Kind<?>...) throws java.io.IOException;
-    method public abstract java.nio.file.Path relativize(java.nio.file.Path);
-    method public abstract java.nio.file.Path resolve(java.nio.file.Path);
-    method public abstract java.nio.file.Path resolve(java.lang.String);
-    method public abstract java.nio.file.Path resolveSibling(java.nio.file.Path);
-    method public abstract java.nio.file.Path resolveSibling(java.lang.String);
-    method public abstract boolean startsWith(java.nio.file.Path);
-    method public abstract boolean startsWith(java.lang.String);
-    method public abstract java.nio.file.Path subpath(int, int);
-    method public abstract java.nio.file.Path toAbsolutePath();
-    method public abstract java.io.File toFile();
-    method public abstract java.nio.file.Path toRealPath(java.nio.file.LinkOption...) throws java.io.IOException;
-    method public abstract java.lang.String toString();
-    method public abstract java.net.URI toUri();
-  }
-
-  public abstract interface PathMatcher {
-    method public abstract boolean matches(java.nio.file.Path);
-  }
-
-  public final class Paths {
-    method public static java.nio.file.Path get(java.lang.String, java.lang.String...);
-    method public static java.nio.file.Path get(java.net.URI);
-  }
-
-  public class ProviderMismatchException extends java.lang.IllegalArgumentException {
-    ctor public ProviderMismatchException();
-    ctor public ProviderMismatchException(java.lang.String);
-  }
-
-  public class ProviderNotFoundException extends java.lang.RuntimeException {
-    ctor public ProviderNotFoundException();
-    ctor public ProviderNotFoundException(java.lang.String);
-  }
-
-  public class ReadOnlyFileSystemException extends java.lang.UnsupportedOperationException {
-    ctor public ReadOnlyFileSystemException();
-  }
-
-  public abstract interface SecureDirectoryStream implements java.nio.file.DirectoryStream {
-    method public abstract void deleteDirectory(T) throws java.io.IOException;
-    method public abstract void deleteFile(T) throws java.io.IOException;
-    method public abstract V getFileAttributeView(java.lang.Class<V>);
-    method public abstract V getFileAttributeView(T, java.lang.Class<V>, java.nio.file.LinkOption...);
-    method public abstract void move(T, java.nio.file.SecureDirectoryStream<T>, T) throws java.io.IOException;
-    method public abstract java.nio.channels.SeekableByteChannel newByteChannel(T, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public abstract java.nio.file.SecureDirectoryStream<T> newDirectoryStream(T, java.nio.file.LinkOption...) throws java.io.IOException;
-  }
-
-  public final class StandardCopyOption extends java.lang.Enum implements java.nio.file.CopyOption {
-    method public static java.nio.file.StandardCopyOption valueOf(java.lang.String);
-    method public static final java.nio.file.StandardCopyOption[] values();
-    enum_constant public static final java.nio.file.StandardCopyOption ATOMIC_MOVE;
-    enum_constant public static final java.nio.file.StandardCopyOption COPY_ATTRIBUTES;
-    enum_constant public static final java.nio.file.StandardCopyOption REPLACE_EXISTING;
-  }
-
-  public final class StandardOpenOption extends java.lang.Enum implements java.nio.file.OpenOption {
-    method public static java.nio.file.StandardOpenOption valueOf(java.lang.String);
-    method public static final java.nio.file.StandardOpenOption[] values();
-    enum_constant public static final java.nio.file.StandardOpenOption APPEND;
-    enum_constant public static final java.nio.file.StandardOpenOption CREATE;
-    enum_constant public static final java.nio.file.StandardOpenOption CREATE_NEW;
-    enum_constant public static final java.nio.file.StandardOpenOption DELETE_ON_CLOSE;
-    enum_constant public static final java.nio.file.StandardOpenOption DSYNC;
-    enum_constant public static final java.nio.file.StandardOpenOption READ;
-    enum_constant public static final java.nio.file.StandardOpenOption SPARSE;
-    enum_constant public static final java.nio.file.StandardOpenOption SYNC;
-    enum_constant public static final java.nio.file.StandardOpenOption TRUNCATE_EXISTING;
-    enum_constant public static final java.nio.file.StandardOpenOption WRITE;
-  }
-
-  public final class StandardWatchEventKinds {
-    field public static final java.nio.file.WatchEvent.Kind<java.nio.file.Path> ENTRY_CREATE;
-    field public static final java.nio.file.WatchEvent.Kind<java.nio.file.Path> ENTRY_DELETE;
-    field public static final java.nio.file.WatchEvent.Kind<java.nio.file.Path> ENTRY_MODIFY;
-    field public static final java.nio.file.WatchEvent.Kind<java.lang.Object> OVERFLOW;
-  }
-
-  public abstract interface WatchEvent {
-    method public abstract T context();
-    method public abstract int count();
-    method public abstract java.nio.file.WatchEvent.Kind<T> kind();
-  }
-
-  public static abstract interface WatchEvent.Kind {
-    method public abstract java.lang.String name();
-    method public abstract java.lang.Class<T> type();
-  }
-
-  public static abstract interface WatchEvent.Modifier {
-    method public abstract java.lang.String name();
-  }
-
-  public abstract interface WatchKey {
-    method public abstract void cancel();
-    method public abstract boolean isValid();
-    method public abstract java.util.List<java.nio.file.WatchEvent<?>> pollEvents();
-    method public abstract boolean reset();
-    method public abstract java.nio.file.Watchable watchable();
-  }
-
-  public abstract interface WatchService implements java.io.Closeable {
-    method public abstract void close() throws java.io.IOException;
-    method public abstract java.nio.file.WatchKey poll();
-    method public abstract java.nio.file.WatchKey poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public abstract java.nio.file.WatchKey take() throws java.lang.InterruptedException;
-  }
-
-  public abstract interface Watchable {
-    method public abstract java.nio.file.WatchKey register(java.nio.file.WatchService, java.nio.file.WatchEvent.Kind<?>[], java.nio.file.WatchEvent.Modifier...) throws java.io.IOException;
-    method public abstract java.nio.file.WatchKey register(java.nio.file.WatchService, java.nio.file.WatchEvent.Kind<?>...) throws java.io.IOException;
-  }
-
-}
-
-package java.nio.file.attribute {
-
-  public final class AclEntry {
-    method public java.util.Set<java.nio.file.attribute.AclEntryFlag> flags();
-    method public static java.nio.file.attribute.AclEntry.Builder newBuilder();
-    method public static java.nio.file.attribute.AclEntry.Builder newBuilder(java.nio.file.attribute.AclEntry);
-    method public java.util.Set<java.nio.file.attribute.AclEntryPermission> permissions();
-    method public java.nio.file.attribute.UserPrincipal principal();
-    method public java.nio.file.attribute.AclEntryType type();
-  }
-
-  public static final class AclEntry.Builder {
-    method public java.nio.file.attribute.AclEntry build();
-    method public java.nio.file.attribute.AclEntry.Builder setFlags(java.util.Set<java.nio.file.attribute.AclEntryFlag>);
-    method public java.nio.file.attribute.AclEntry.Builder setFlags(java.nio.file.attribute.AclEntryFlag...);
-    method public java.nio.file.attribute.AclEntry.Builder setPermissions(java.util.Set<java.nio.file.attribute.AclEntryPermission>);
-    method public java.nio.file.attribute.AclEntry.Builder setPermissions(java.nio.file.attribute.AclEntryPermission...);
-    method public java.nio.file.attribute.AclEntry.Builder setPrincipal(java.nio.file.attribute.UserPrincipal);
-    method public java.nio.file.attribute.AclEntry.Builder setType(java.nio.file.attribute.AclEntryType);
-  }
-
-  public final class AclEntryFlag extends java.lang.Enum {
-    method public static java.nio.file.attribute.AclEntryFlag valueOf(java.lang.String);
-    method public static final java.nio.file.attribute.AclEntryFlag[] values();
-    enum_constant public static final java.nio.file.attribute.AclEntryFlag DIRECTORY_INHERIT;
-    enum_constant public static final java.nio.file.attribute.AclEntryFlag FILE_INHERIT;
-    enum_constant public static final java.nio.file.attribute.AclEntryFlag INHERIT_ONLY;
-    enum_constant public static final java.nio.file.attribute.AclEntryFlag NO_PROPAGATE_INHERIT;
-  }
-
-  public final class AclEntryPermission extends java.lang.Enum {
-    method public static java.nio.file.attribute.AclEntryPermission valueOf(java.lang.String);
-    method public static final java.nio.file.attribute.AclEntryPermission[] values();
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission APPEND_DATA;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission DELETE;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission DELETE_CHILD;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission EXECUTE;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_ACL;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_ATTRIBUTES;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_DATA;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_NAMED_ATTRS;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission SYNCHRONIZE;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_ACL;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_ATTRIBUTES;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_DATA;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_NAMED_ATTRS;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_OWNER;
-    field public static final java.nio.file.attribute.AclEntryPermission ADD_FILE;
-    field public static final java.nio.file.attribute.AclEntryPermission ADD_SUBDIRECTORY;
-    field public static final java.nio.file.attribute.AclEntryPermission LIST_DIRECTORY;
-  }
-
-  public final class AclEntryType extends java.lang.Enum {
-    method public static java.nio.file.attribute.AclEntryType valueOf(java.lang.String);
-    method public static final java.nio.file.attribute.AclEntryType[] values();
-    enum_constant public static final java.nio.file.attribute.AclEntryType ALARM;
-    enum_constant public static final java.nio.file.attribute.AclEntryType ALLOW;
-    enum_constant public static final java.nio.file.attribute.AclEntryType AUDIT;
-    enum_constant public static final java.nio.file.attribute.AclEntryType DENY;
-  }
-
-  public abstract interface AclFileAttributeView implements java.nio.file.attribute.FileOwnerAttributeView {
-    method public abstract java.util.List<java.nio.file.attribute.AclEntry> getAcl() throws java.io.IOException;
-    method public abstract java.lang.String name();
-    method public abstract void setAcl(java.util.List<java.nio.file.attribute.AclEntry>) throws java.io.IOException;
-  }
-
-  public abstract interface AttributeView {
-    method public abstract java.lang.String name();
-  }
-
-  public abstract interface BasicFileAttributeView implements java.nio.file.attribute.FileAttributeView {
-    method public abstract java.lang.String name();
-    method public abstract java.nio.file.attribute.BasicFileAttributes readAttributes() throws java.io.IOException;
-    method public abstract void setTimes(java.nio.file.attribute.FileTime, java.nio.file.attribute.FileTime, java.nio.file.attribute.FileTime) throws java.io.IOException;
-  }
-
-  public abstract interface BasicFileAttributes {
-    method public abstract java.nio.file.attribute.FileTime creationTime();
-    method public abstract java.lang.Object fileKey();
-    method public abstract boolean isDirectory();
-    method public abstract boolean isOther();
-    method public abstract boolean isRegularFile();
-    method public abstract boolean isSymbolicLink();
-    method public abstract java.nio.file.attribute.FileTime lastAccessTime();
-    method public abstract java.nio.file.attribute.FileTime lastModifiedTime();
-    method public abstract long size();
-  }
-
-  public abstract interface DosFileAttributeView implements java.nio.file.attribute.BasicFileAttributeView {
-    method public abstract java.lang.String name();
-    method public abstract java.nio.file.attribute.DosFileAttributes readAttributes() throws java.io.IOException;
-    method public abstract void setArchive(boolean) throws java.io.IOException;
-    method public abstract void setHidden(boolean) throws java.io.IOException;
-    method public abstract void setReadOnly(boolean) throws java.io.IOException;
-    method public abstract void setSystem(boolean) throws java.io.IOException;
-  }
-
-  public abstract interface DosFileAttributes implements java.nio.file.attribute.BasicFileAttributes {
-    method public abstract boolean isArchive();
-    method public abstract boolean isHidden();
-    method public abstract boolean isReadOnly();
-    method public abstract boolean isSystem();
-  }
-
-  public abstract interface FileAttribute {
-    method public abstract java.lang.String name();
-    method public abstract T value();
-  }
-
-  public abstract interface FileAttributeView implements java.nio.file.attribute.AttributeView {
-  }
-
-  public abstract interface FileOwnerAttributeView implements java.nio.file.attribute.FileAttributeView {
-    method public abstract java.nio.file.attribute.UserPrincipal getOwner() throws java.io.IOException;
-    method public abstract java.lang.String name();
-    method public abstract void setOwner(java.nio.file.attribute.UserPrincipal) throws java.io.IOException;
-  }
-
-  public abstract interface FileStoreAttributeView implements java.nio.file.attribute.AttributeView {
-  }
-
-  public final class FileTime implements java.lang.Comparable {
-    method public int compareTo(java.nio.file.attribute.FileTime);
-    method public static java.nio.file.attribute.FileTime from(long, java.util.concurrent.TimeUnit);
-    method public static java.nio.file.attribute.FileTime fromMillis(long);
-    method public long to(java.util.concurrent.TimeUnit);
-    method public long toMillis();
-  }
-
-  public abstract interface GroupPrincipal implements java.nio.file.attribute.UserPrincipal {
-  }
-
-  public abstract interface PosixFileAttributeView implements java.nio.file.attribute.BasicFileAttributeView java.nio.file.attribute.FileOwnerAttributeView {
-    method public abstract java.lang.String name();
-    method public abstract java.nio.file.attribute.PosixFileAttributes readAttributes() throws java.io.IOException;
-    method public abstract void setGroup(java.nio.file.attribute.GroupPrincipal) throws java.io.IOException;
-    method public abstract void setPermissions(java.util.Set<java.nio.file.attribute.PosixFilePermission>) throws java.io.IOException;
-  }
-
-  public abstract interface PosixFileAttributes implements java.nio.file.attribute.BasicFileAttributes {
-    method public abstract java.nio.file.attribute.GroupPrincipal group();
-    method public abstract java.nio.file.attribute.UserPrincipal owner();
-    method public abstract java.util.Set<java.nio.file.attribute.PosixFilePermission> permissions();
-  }
-
-  public final class PosixFilePermission extends java.lang.Enum {
-    method public static java.nio.file.attribute.PosixFilePermission valueOf(java.lang.String);
-    method public static final java.nio.file.attribute.PosixFilePermission[] values();
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission GROUP_EXECUTE;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission GROUP_READ;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission GROUP_WRITE;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission OTHERS_EXECUTE;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission OTHERS_READ;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission OTHERS_WRITE;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission OWNER_EXECUTE;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission OWNER_READ;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission OWNER_WRITE;
-  }
-
-  public final class PosixFilePermissions {
-    method public static java.nio.file.attribute.FileAttribute<java.util.Set<java.nio.file.attribute.PosixFilePermission>> asFileAttribute(java.util.Set<java.nio.file.attribute.PosixFilePermission>);
-    method public static java.util.Set<java.nio.file.attribute.PosixFilePermission> fromString(java.lang.String);
-    method public static java.lang.String toString(java.util.Set<java.nio.file.attribute.PosixFilePermission>);
-  }
-
-  public abstract interface UserPrincipal implements java.security.Principal {
-  }
-
-  public abstract class UserPrincipalLookupService {
-    ctor protected UserPrincipalLookupService();
-    method public abstract java.nio.file.attribute.GroupPrincipal lookupPrincipalByGroupName(java.lang.String) throws java.io.IOException;
-    method public abstract java.nio.file.attribute.UserPrincipal lookupPrincipalByName(java.lang.String) throws java.io.IOException;
-  }
-
-  public class UserPrincipalNotFoundException extends java.io.IOException {
-    ctor public UserPrincipalNotFoundException(java.lang.String);
-    method public java.lang.String getName();
-  }
-
-}
-
-package java.nio.file.spi {
-
-  public abstract class FileSystemProvider {
-    ctor protected FileSystemProvider();
-    method public abstract void checkAccess(java.nio.file.Path, java.nio.file.AccessMode...) throws java.io.IOException;
-    method public abstract void copy(java.nio.file.Path, java.nio.file.Path, java.nio.file.CopyOption...) throws java.io.IOException;
-    method public abstract void createDirectory(java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public void createLink(java.nio.file.Path, java.nio.file.Path) throws java.io.IOException;
-    method public void createSymbolicLink(java.nio.file.Path, java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public abstract void delete(java.nio.file.Path) throws java.io.IOException;
-    method public boolean deleteIfExists(java.nio.file.Path) throws java.io.IOException;
-    method public abstract V getFileAttributeView(java.nio.file.Path, java.lang.Class<V>, java.nio.file.LinkOption...);
-    method public abstract java.nio.file.FileStore getFileStore(java.nio.file.Path) throws java.io.IOException;
-    method public abstract java.nio.file.FileSystem getFileSystem(java.net.URI);
-    method public abstract java.nio.file.Path getPath(java.net.URI);
-    method public abstract java.lang.String getScheme();
-    method public static java.util.List<java.nio.file.spi.FileSystemProvider> installedProviders();
-    method public abstract boolean isHidden(java.nio.file.Path) throws java.io.IOException;
-    method public abstract boolean isSameFile(java.nio.file.Path, java.nio.file.Path) throws java.io.IOException;
-    method public abstract void move(java.nio.file.Path, java.nio.file.Path, java.nio.file.CopyOption...) throws java.io.IOException;
-    method public java.nio.channels.AsynchronousFileChannel newAsynchronousFileChannel(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.util.concurrent.ExecutorService, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public abstract java.nio.channels.SeekableByteChannel newByteChannel(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public abstract java.nio.file.DirectoryStream<java.nio.file.Path> newDirectoryStream(java.nio.file.Path, java.nio.file.DirectoryStream.Filter<? super java.nio.file.Path>) throws java.io.IOException;
-    method public java.nio.channels.FileChannel newFileChannel(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public abstract java.nio.file.FileSystem newFileSystem(java.net.URI, java.util.Map<java.lang.String, ?>) throws java.io.IOException;
-    method public java.nio.file.FileSystem newFileSystem(java.nio.file.Path, java.util.Map<java.lang.String, ?>) throws java.io.IOException;
-    method public java.io.InputStream newInputStream(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public java.io.OutputStream newOutputStream(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public abstract A readAttributes(java.nio.file.Path, java.lang.Class<A>, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public abstract java.util.Map<java.lang.String, java.lang.Object> readAttributes(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public java.nio.file.Path readSymbolicLink(java.nio.file.Path) throws java.io.IOException;
-    method public abstract void setAttribute(java.nio.file.Path, java.lang.String, java.lang.Object, java.nio.file.LinkOption...) throws java.io.IOException;
-  }
-
-  public abstract class FileTypeDetector {
-    ctor protected FileTypeDetector();
-    method public abstract java.lang.String probeContentType(java.nio.file.Path) throws java.io.IOException;
-  }
-
-}
-
 package java.security {
 
   public final class AccessControlContext {
@@ -56324,6 +57123,7 @@
     method public static java.security.cert.CertPathBuilder getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
     method public static java.security.cert.CertPathBuilder getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
     method public final java.security.Provider getProvider();
+    method public final java.security.cert.CertPathChecker getRevocationChecker();
   }
 
   public class CertPathBuilderException extends java.security.GeneralSecurityException {
@@ -56341,6 +57141,13 @@
   public abstract class CertPathBuilderSpi {
     ctor public CertPathBuilderSpi();
     method public abstract java.security.cert.CertPathBuilderResult engineBuild(java.security.cert.CertPathParameters) throws java.security.cert.CertPathBuilderException, java.security.InvalidAlgorithmParameterException;
+    method public java.security.cert.CertPathChecker engineGetRevocationChecker();
+  }
+
+  public abstract interface CertPathChecker {
+    method public abstract void check(java.security.cert.Certificate) throws java.security.cert.CertPathValidatorException;
+    method public abstract void init(boolean) throws java.security.cert.CertPathValidatorException;
+    method public abstract boolean isForwardCheckingSupported();
   }
 
   public abstract interface CertPathParameters implements java.lang.Cloneable {
@@ -56355,6 +57162,7 @@
     method public static java.security.cert.CertPathValidator getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
     method public static java.security.cert.CertPathValidator getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
     method public final java.security.Provider getProvider();
+    method public final java.security.cert.CertPathChecker getRevocationChecker();
     method public final java.security.cert.CertPathValidatorResult validate(java.security.cert.CertPath, java.security.cert.CertPathParameters) throws java.security.cert.CertPathValidatorException, java.security.InvalidAlgorithmParameterException;
   }
 
@@ -56391,6 +57199,7 @@
 
   public abstract class CertPathValidatorSpi {
     ctor public CertPathValidatorSpi();
+    method public java.security.cert.CertPathChecker engineGetRevocationChecker();
     method public abstract java.security.cert.CertPathValidatorResult engineValidate(java.security.cert.CertPath, java.security.cert.CertPathParameters) throws java.security.cert.CertPathValidatorException, java.security.InvalidAlgorithmParameterException;
   }
 
@@ -56549,9 +57358,10 @@
     method public java.security.cert.CertPath getCertPath();
   }
 
-  public abstract class PKIXCertPathChecker implements java.lang.Cloneable {
+  public abstract class PKIXCertPathChecker implements java.security.cert.CertPathChecker java.lang.Cloneable {
     ctor protected PKIXCertPathChecker();
     method public abstract void check(java.security.cert.Certificate, java.util.Collection<java.lang.String>) throws java.security.cert.CertPathValidatorException;
+    method public void check(java.security.cert.Certificate) throws java.security.cert.CertPathValidatorException;
     method public java.lang.Object clone();
     method public abstract java.util.Set<java.lang.String> getSupportedExtensions();
     method public abstract void init(boolean) throws java.security.cert.CertPathValidatorException;
@@ -56611,6 +57421,30 @@
     enum_constant public static final java.security.cert.PKIXReason UNRECOGNIZED_CRIT_EXT;
   }
 
+  public abstract class PKIXRevocationChecker extends java.security.cert.PKIXCertPathChecker {
+    ctor protected PKIXRevocationChecker();
+    method public java.util.List<java.security.cert.Extension> getOcspExtensions();
+    method public java.net.URI getOcspResponder();
+    method public java.security.cert.X509Certificate getOcspResponderCert();
+    method public java.util.Map<java.security.cert.X509Certificate, byte[]> getOcspResponses();
+    method public java.util.Set<java.security.cert.PKIXRevocationChecker.Option> getOptions();
+    method public abstract java.util.List<java.security.cert.CertPathValidatorException> getSoftFailExceptions();
+    method public void setOcspExtensions(java.util.List<java.security.cert.Extension>);
+    method public void setOcspResponder(java.net.URI);
+    method public void setOcspResponderCert(java.security.cert.X509Certificate);
+    method public void setOcspResponses(java.util.Map<java.security.cert.X509Certificate, byte[]>);
+    method public void setOptions(java.util.Set<java.security.cert.PKIXRevocationChecker.Option>);
+  }
+
+  public static final class PKIXRevocationChecker.Option extends java.lang.Enum {
+    method public static java.security.cert.PKIXRevocationChecker.Option valueOf(java.lang.String);
+    method public static final java.security.cert.PKIXRevocationChecker.Option[] values();
+    enum_constant public static final java.security.cert.PKIXRevocationChecker.Option NO_FALLBACK;
+    enum_constant public static final java.security.cert.PKIXRevocationChecker.Option ONLY_END_ENTITY;
+    enum_constant public static final java.security.cert.PKIXRevocationChecker.Option PREFER_CRLS;
+    enum_constant public static final java.security.cert.PKIXRevocationChecker.Option SOFT_FAIL;
+  }
+
   public abstract interface PolicyNode {
     method public abstract java.util.Iterator<? extends java.security.cert.PolicyNode> getChildren();
     method public abstract int getDepth();
@@ -56770,6 +57604,7 @@
     method public javax.security.auth.x500.X500Principal getSubjectX500Principal();
     method public abstract byte[] getTBSCertificate() throws java.security.cert.CertificateEncodingException;
     method public abstract int getVersion();
+    method public void verify(java.security.PublicKey, java.security.Provider) throws java.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.SignatureException;
   }
 
   public abstract interface X509Extension {
@@ -60013,8 +60848,6 @@
     ctor public Scanner(java.io.InputStream, java.lang.String);
     ctor public Scanner(java.io.File) throws java.io.FileNotFoundException;
     ctor public Scanner(java.io.File, java.lang.String) throws java.io.FileNotFoundException;
-    ctor public Scanner(java.nio.file.Path) throws java.io.IOException;
-    ctor public Scanner(java.nio.file.Path, java.lang.String) throws java.io.IOException;
     ctor public Scanner(java.lang.String);
     ctor public Scanner(java.nio.channels.ReadableByteChannel);
     ctor public Scanner(java.nio.channels.ReadableByteChannel, java.lang.String);
@@ -61644,7 +62477,6 @@
     ctor public JarFile(java.io.File, boolean, int) throws java.io.IOException;
     method public java.util.jar.JarEntry getJarEntry(java.lang.String);
     method public java.util.jar.Manifest getManifest() throws java.io.IOException;
-    method public boolean hasClassPathAttribute() throws java.io.IOException;
     field public static final java.lang.String MANIFEST_NAME = "META-INF/MANIFEST.MF";
   }
 
@@ -62098,8 +62930,8 @@
     method public java.lang.StringBuffer appendTail(java.lang.StringBuffer);
     method public int end();
     method public int end(int);
-    method public boolean find(int);
     method public boolean find();
+    method public boolean find(int);
     method public java.lang.String group();
     method public java.lang.String group(int);
     method public int groupCount();
@@ -62127,8 +62959,8 @@
   }
 
   public final class Pattern implements java.io.Serializable {
-    method public static java.util.regex.Pattern compile(java.lang.String, int) throws java.util.regex.PatternSyntaxException;
     method public static java.util.regex.Pattern compile(java.lang.String);
+    method public static java.util.regex.Pattern compile(java.lang.String, int) throws java.util.regex.PatternSyntaxException;
     method public int flags();
     method public java.util.regex.Matcher matcher(java.lang.CharSequence);
     method public static boolean matches(java.lang.String, java.lang.CharSequence);
@@ -62143,6 +62975,7 @@
     field public static final int LITERAL = 16; // 0x10
     field public static final int MULTILINE = 8; // 0x8
     field public static final int UNICODE_CASE = 64; // 0x40
+    field public static final int UNICODE_CHARACTER_CLASS = 256; // 0x100
     field public static final int UNIX_LINES = 1; // 0x1
   }
 
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 642d2a8..27de913 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -190,6 +190,15 @@
 
 }
 
+package android.test.mock {
+
+  public deprecated class MockPackageManager extends android.content.pm.PackageManager {
+    method public deprecated java.lang.String getDefaultBrowserPackageName(int);
+    method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int);
+  }
+
+}
+
 package android.text.format {
 
   public class DateFormat {
diff --git a/api/test-current.txt b/api/test-current.txt
index 390a017..8f534a3 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -33,6 +33,7 @@
     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";
+    field public static final java.lang.String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
     field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
     field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
     field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
@@ -67,8 +68,7 @@
     field public static final java.lang.String DUMP = "android.permission.DUMP";
     field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
     field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
-    field public static final java.lang.String FLASHLIGHT = "android.permission.FLASHLIGHT";
-    field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
+    field public static final deprecated 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 deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
@@ -335,6 +335,7 @@
     field public static final int calendarViewShown = 16843596; // 0x101034c
     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 canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
     field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9
     field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
@@ -505,6 +506,8 @@
     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
+    field public static final int endY = 16844052; // 0x1010514
     field public static final deprecated int endYear = 16843133; // 0x101017d
     field public static final int enterFadeDuration = 16843532; // 0x101030c
     field public static final int entries = 16842930; // 0x10100b2
@@ -524,6 +527,7 @@
     field public static final int expandableListViewStyle = 16842863; // 0x101006f
     field public static final int expandableListViewWhiteStyle = 16843446; // 0x10102b6
     field public static final int exported = 16842768; // 0x1010010
+    field public static final int externalService = 16844047; // 0x101050f
     field public static final int extraTension = 16843371; // 0x101026b
     field public static final int extractNativeLibs = 16844010; // 0x10104ea
     field public static final int factor = 16843219; // 0x10101d3
@@ -879,6 +883,7 @@
     field public static final int numbersTextColor = 16843937; // 0x10104a1
     field public static final deprecated int numeric = 16843109; // 0x1010165
     field public static final int numericShortcut = 16843236; // 0x10101e4
+    field public static final int offset = 16844053; // 0x1010515
     field public static final int onClick = 16843375; // 0x101026f
     field public static final int oneshot = 16843159; // 0x1010197
     field public static final int opacity = 16843550; // 0x101031e
@@ -1126,6 +1131,8 @@
     field public static final int startColor = 16843165; // 0x101019d
     field public static final int startDelay = 16843746; // 0x10103e2
     field public static final int startOffset = 16843198; // 0x10101be
+    field public static final int startX = 16844049; // 0x1010511
+    field public static final int startY = 16844050; // 0x1010512
     field public static final deprecated int startYear = 16843132; // 0x101017c
     field public static final int stateListAnimator = 16843848; // 0x1010448
     field public static final int stateNotNeeded = 16842774; // 0x1010016
@@ -1182,6 +1189,7 @@
     field public static final int summaryOn = 16843247; // 0x10101ef
     field public static final int supportsAssist = 16844016; // 0x10104f0
     field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
+    field public static final int supportsLocalInteraction = 16844048; // 0x1010510
     field public static final int supportsPictureInPicture = 16844024; // 0x10104f8
     field public static final int supportsRtl = 16843695; // 0x10103af
     field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
@@ -1289,6 +1297,9 @@
     field public static final int thumbTint = 16843889; // 0x1010471
     field public static final int thumbTintMode = 16843890; // 0x1010472
     field public static final int thumbnail = 16843429; // 0x10102a5
+    field public static final int tickMark = 16844043; // 0x101050b
+    field public static final int tickMarkTint = 16844044; // 0x101050c
+    field public static final int tickMarkTintMode = 16844045; // 0x101050d
     field public static final int tileMode = 16843265; // 0x1010201
     field public static final int tileModeX = 16843895; // 0x1010477
     field public static final int tileModeY = 16843896; // 0x1010478
@@ -2114,22 +2125,6 @@
     field public static final int Theme_Light_Panel = 16973914; // 0x103005a
     field public static final int Theme_Light_WallpaperSettings = 16973922; // 0x1030062
     field public static final int Theme_Material = 16974372; // 0x1030224
-    field public static final int Theme_Material_DayNight = 16974552; // 0x10302d8
-    field public static final int Theme_Material_DayNight_DarkActionBar = 16974553; // 0x10302d9
-    field public static final int Theme_Material_DayNight_Dialog = 16974554; // 0x10302da
-    field public static final int Theme_Material_DayNight_DialogWhenLarge = 16974560; // 0x10302e0
-    field public static final int Theme_Material_DayNight_DialogWhenLarge_DarkActionBar = 16974568; // 0x10302e8
-    field public static final int Theme_Material_DayNight_DialogWhenLarge_NoActionBar = 16974561; // 0x10302e1
-    field public static final int Theme_Material_DayNight_Dialog_Alert = 16974555; // 0x10302db
-    field public static final int Theme_Material_DayNight_Dialog_MinWidth = 16974556; // 0x10302dc
-    field public static final int Theme_Material_DayNight_Dialog_NoActionBar = 16974557; // 0x10302dd
-    field public static final int Theme_Material_DayNight_Dialog_NoActionBar_MinWidth = 16974558; // 0x10302de
-    field public static final int Theme_Material_DayNight_Dialog_Presentation = 16974559; // 0x10302df
-    field public static final int Theme_Material_DayNight_NoActionBar = 16974562; // 0x10302e2
-    field public static final int Theme_Material_DayNight_NoActionBar_Fullscreen = 16974563; // 0x10302e3
-    field public static final int Theme_Material_DayNight_NoActionBar_Overscan = 16974564; // 0x10302e4
-    field public static final int Theme_Material_DayNight_NoActionBar_TranslucentDecor = 16974565; // 0x10302e5
-    field public static final int Theme_Material_DayNight_Panel = 16974566; // 0x10302e6
     field public static final int Theme_Material_Dialog = 16974373; // 0x1030225
     field public static final int Theme_Material_DialogWhenLarge = 16974379; // 0x103022b
     field public static final int Theme_Material_DialogWhenLarge_NoActionBar = 16974380; // 0x103022c
@@ -2143,7 +2138,7 @@
     field public static final int Theme_Material_Light_DarkActionBar = 16974392; // 0x1030238
     field public static final int Theme_Material_Light_Dialog = 16974393; // 0x1030239
     field public static final int Theme_Material_Light_DialogWhenLarge = 16974399; // 0x103023f
-    field public static final int Theme_Material_Light_DialogWhenLarge_DarkActionBar = 16974567; // 0x10302e7
+    field public static final int Theme_Material_Light_DialogWhenLarge_DarkActionBar = 16974552; // 0x10302d8
     field public static final int Theme_Material_Light_DialogWhenLarge_NoActionBar = 16974400; // 0x1030240
     field public static final int Theme_Material_Light_Dialog_Alert = 16974394; // 0x103023a
     field public static final int Theme_Material_Light_Dialog_MinWidth = 16974395; // 0x103023b
@@ -2564,6 +2559,7 @@
     field public static final int Widget_Material_ScrollView = 16974462; // 0x103027e
     field public static final int Widget_Material_SearchView = 16974463; // 0x103027f
     field public static final int Widget_Material_SeekBar = 16974464; // 0x1030280
+    field public static final int Widget_Material_SeekBar_Discrete = 16974553; // 0x10302d9
     field public static final int Widget_Material_SegmentedButton = 16974465; // 0x1030281
     field public static final int Widget_Material_Spinner = 16974467; // 0x1030283
     field public static final int Widget_Material_Spinner_Underlined = 16974468; // 0x1030284
@@ -2623,6 +2619,8 @@
 
   public abstract class AccessibilityService extends android.app.Service {
     ctor public AccessibilityService();
+    method public final void disableSelf();
+    method public final boolean dispatchGesture(android.accessibilityservice.GestureDescription, android.accessibilityservice.AccessibilityService.GestureResultCallback, android.os.Handler);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
     method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
@@ -2662,6 +2660,12 @@
     field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice";
   }
 
+  public static abstract class AccessibilityService.GestureResultCallback {
+    ctor public AccessibilityService.GestureResultCallback();
+    method public void onCancelled(android.accessibilityservice.GestureDescription);
+    method public void onCompleted(android.accessibilityservice.GestureDescription);
+  }
+
   public static final class AccessibilityService.MagnificationController {
     method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener);
     method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener, android.os.Handler);
@@ -2694,6 +2698,7 @@
     method public java.lang.String loadDescription(android.content.pm.PackageManager);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10
+    field public static final int CAPABILITY_CAN_PERFORM_GESTURES = 32; // 0x20
     field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
     field public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 8; // 0x8
     field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
@@ -2720,6 +2725,30 @@
     field public java.lang.String[] packageNames;
   }
 
+  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 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 {
+    ctor public GestureDescription.Builder();
+    method public android.accessibilityservice.GestureDescription.Builder addStroke(android.accessibilityservice.GestureDescription.StrokeDescription);
+    method public android.accessibilityservice.GestureDescription build();
+  }
+
+  public static class GestureDescription.StrokeDescription {
+    ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long);
+    method public long getDuration();
+    method public android.graphics.Path getPath();
+    method public long getStartTime();
+  }
+
 }
 
 package android.accounts {
@@ -2730,15 +2759,12 @@
     method public android.os.Bundle addAccountFromCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle confirmCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle editProperties(android.accounts.AccountAuthenticatorResponse, java.lang.String);
-    method public android.os.Bundle finishSession(android.accounts.AccountAuthenticatorResponse, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public android.os.Bundle getAccountCredentialsForCloning(android.accounts.AccountAuthenticatorResponse, android.accounts.Account) throws android.accounts.NetworkErrorException;
     method public android.os.Bundle getAccountRemovalAllowed(android.accounts.AccountAuthenticatorResponse, android.accounts.Account) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle getAuthToken(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract java.lang.String getAuthTokenLabel(java.lang.String);
     method public final android.os.IBinder getIBinder();
     method public abstract android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;
-    method public android.os.Bundle startAddAccountSession(android.accounts.AccountAuthenticatorResponse, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle) throws android.accounts.NetworkErrorException;
-    method public android.os.Bundle startUpdateCredentialsSession(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
     field public static final java.lang.String KEY_CUSTOM_TOKEN_EXPIRY = "android.accounts.expiry";
   }
@@ -2776,7 +2802,6 @@
     method public void clearPassword(android.accounts.Account);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> confirmCredentials(android.accounts.Account, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> editProperties(java.lang.String, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
-    method public android.accounts.AccountManagerFuture<android.os.Bundle> finishSession(android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public static android.accounts.AccountManager get(android.content.Context);
     method public android.accounts.Account[] getAccounts();
     method public android.accounts.Account[] getAccountsByType(java.lang.String);
@@ -2804,8 +2829,6 @@
     method public void setAuthToken(android.accounts.Account, java.lang.String, java.lang.String);
     method public void setPassword(android.accounts.Account, java.lang.String);
     method public void setUserData(android.accounts.Account, java.lang.String, java.lang.String);
-    method public android.accounts.AccountManagerFuture<android.os.Bundle> startAddAccountSession(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
-    method public android.accounts.AccountManagerFuture<android.os.Bundle> startUpdateCredentialsSession(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> updateCredentials(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     field public static final java.lang.String ACTION_AUTHENTICATOR_INTENT = "android.accounts.AccountAuthenticator";
     field public static final java.lang.String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
@@ -2822,8 +2845,6 @@
     field public static final java.lang.String KEY_ACCOUNT_AUTHENTICATOR_RESPONSE = "accountAuthenticatorResponse";
     field public static final java.lang.String KEY_ACCOUNT_MANAGER_RESPONSE = "accountManagerResponse";
     field public static final java.lang.String KEY_ACCOUNT_NAME = "authAccount";
-    field public static final java.lang.String KEY_ACCOUNT_SESSION_BUNDLE = "accountSessionBundle";
-    field public static final java.lang.String KEY_ACCOUNT_STATUS_TOKEN = "accountStatusToken";
     field public static final java.lang.String KEY_ACCOUNT_TYPE = "accountType";
     field public static final java.lang.String KEY_ANDROID_PACKAGE_NAME = "androidPackageName";
     field public static final java.lang.String KEY_AUTHENTICATOR_TYPES = "authenticator_types";
@@ -3374,6 +3395,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 enterPictureInPictureMode();
     method public android.view.View findViewById(int);
     method public void finish();
     method public void finishActivity(int);
@@ -3421,6 +3443,7 @@
     method public boolean isDestroyed();
     method public boolean isFinishing();
     method public boolean isImmersive();
+    method public boolean isLocalVoiceInteractionSupported();
     method public boolean isTaskRoot();
     method public boolean isVoiceInteraction();
     method public boolean isVoiceInteractionRoot();
@@ -3462,6 +3485,8 @@
     method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
     method public boolean onKeyShortcut(int, android.view.KeyEvent);
     method public boolean onKeyUp(int, android.view.KeyEvent);
+    method public void onLocalVoiceInteractionStarted();
+    method public void onLocalVoiceInteractionStopped();
     method public void onLowMemory();
     method public boolean onMenuItemSelected(int, android.view.MenuItem);
     method public boolean onMenuOpened(int, android.view.Menu);
@@ -3484,6 +3509,7 @@
     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();
@@ -3519,6 +3545,7 @@
     method public boolean releaseInstance();
     method public final deprecated void removeDialog(int);
     method public void reportFullyDrawn();
+    method public android.view.DropPermissions requestDropPermissions(android.view.DragEvent);
     method public final void requestPermissions(java.lang.String[], int);
     method public boolean requestVisibleBehind(boolean);
     method public final boolean requestWindowFeature(int);
@@ -3553,6 +3580,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 boolean shouldShowRequestPermissionRationale(java.lang.String);
     method public boolean shouldUpRecreateTask(android.content.Intent);
     method public boolean showAssist(android.os.Bundle);
@@ -3573,12 +3601,14 @@
     method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
     method public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
     method public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+    method public void startLocalVoiceInteraction(android.os.Bundle);
     method public void startLockTask();
     method public deprecated void startManagingCursor(android.database.Cursor);
     method public boolean startNextMatchingActivity(android.content.Intent);
     method public boolean startNextMatchingActivity(android.content.Intent, android.os.Bundle);
     method public void startPostponedEnterTransition();
     method public void startSearch(java.lang.String, boolean, android.os.Bundle, boolean);
+    method public void stopLocalVoiceInteraction();
     method public void stopLockTask();
     method public deprecated void stopManagingCursor(android.database.Cursor);
     method public void takeKeyEvents(boolean);
@@ -4095,11 +4125,14 @@
   }
 
   public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
+    ctor public DatePickerDialog(android.content.Context);
+    ctor public DatePickerDialog(android.content.Context, int);
     ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
     ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
     method public android.widget.DatePicker getDatePicker();
     method public void onClick(android.content.DialogInterface, int);
     method public void onDateChanged(android.widget.DatePicker, int, int, int);
+    method public void setOnDateSetListener(android.app.DatePickerDialog.OnDateSetListener);
     method public void updateDate(int, int, int);
   }
 
@@ -4160,6 +4193,7 @@
     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);
@@ -4239,7 +4273,7 @@
     field public static final java.lang.String COLUMN_DESCRIPTION = "description";
     field public static final java.lang.String COLUMN_ID = "_id";
     field public static final java.lang.String COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp";
-    field public static final java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
+    field public static final deprecated java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
     field public static final java.lang.String COLUMN_LOCAL_URI = "local_uri";
     field public static final java.lang.String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri";
     field public static final java.lang.String COLUMN_MEDIA_TYPE = "media_type";
@@ -4851,6 +4885,7 @@
     field public static final java.lang.String EXTRA_PROGRESS = "android.progress";
     field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
     field public static final java.lang.String EXTRA_PROGRESS_MAX = "android.progressMax";
+    field public static final java.lang.String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
     field public static final java.lang.String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
     field public static final java.lang.String EXTRA_SHOW_WHEN = "android.showWhen";
     field public static final java.lang.String EXTRA_SMALL_ICON = "android.icon";
@@ -5017,6 +5052,7 @@
     method public android.app.Notification.Builder setPriority(int);
     method public android.app.Notification.Builder setProgress(int, int, boolean);
     method public android.app.Notification.Builder setPublicVersion(android.app.Notification);
+    method public android.app.Notification.Builder setRemoteInputHistory(java.lang.CharSequence[]);
     method public android.app.Notification.Builder setShowWhen(boolean);
     method public android.app.Notification.Builder setSmallIcon(int);
     method public android.app.Notification.Builder setSmallIcon(int, int);
@@ -5206,6 +5242,7 @@
     field public static final int SUPPRESSED_EFFECTS_UNSET = -1; // 0xffffffff
     field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
     field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+    field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
     field public final int priorityCallSenders;
     field public final int priorityCategories;
     field public final int priorityMessageSenders;
@@ -5509,8 +5546,10 @@
     method public android.view.WindowAnimationFrameStats getWindowAnimationFrameStats();
     method public android.view.WindowContentFrameStats getWindowContentFrameStats(int);
     method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
+    method public boolean grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
     method public boolean injectInputEvent(android.view.InputEvent, boolean);
     method public final boolean performGlobalAction(int);
+    method public boolean revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
     method public void setOnAccessibilityEventListener(android.app.UiAutomation.OnAccessibilityEventListener);
     method public boolean setRotation(int);
     method public void setRunAsMonkey(boolean);
@@ -5658,10 +5697,13 @@
     method public android.graphics.drawable.Drawable peekFastDrawable();
     method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle);
     method public void setBitmap(android.graphics.Bitmap) throws java.io.IOException;
-    method public void setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean, int) throws java.io.IOException;
     method public void setResource(int) throws java.io.IOException;
+    method public int setResource(int, int) throws java.io.IOException;
     method public void setStream(java.io.InputStream) throws java.io.IOException;
-    method public void setStream(java.io.InputStream, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setStream(java.io.InputStream, android.graphics.Rect, boolean) throws java.io.IOException;
+    method public int setStream(java.io.InputStream, android.graphics.Rect, boolean, int) throws java.io.IOException;
     method public void setWallpaperOffsetSteps(float, float);
     method public void setWallpaperOffsets(android.os.IBinder, float, float);
     method public void suggestDesiredDimensions(int, int);
@@ -5672,6 +5714,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 java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
   }
 
@@ -5710,6 +5754,9 @@
     ctor public DeviceAdminReceiver();
     method public android.app.admin.DevicePolicyManager getManager(android.content.Context);
     method public android.content.ComponentName getWho(android.content.Context);
+    method public void onBugreportFailed(android.content.Context, android.content.Intent, int);
+    method public void onBugreportShared(android.content.Context, android.content.Intent, java.lang.String);
+    method public void onBugreportSharingDeclined(android.content.Context, android.content.Intent);
     method public java.lang.String onChoosePrivateKeyAlias(android.content.Context, android.content.Intent, int, android.net.Uri, java.lang.String);
     method public java.lang.CharSequence onDisableRequested(android.content.Context, android.content.Intent);
     method public void onDisabled(android.content.Context, android.content.Intent);
@@ -5734,6 +5781,8 @@
     field public static final java.lang.String ACTION_PASSWORD_FAILED = "android.app.action.ACTION_PASSWORD_FAILED";
     field public static final java.lang.String ACTION_PASSWORD_SUCCEEDED = "android.app.action.ACTION_PASSWORD_SUCCEEDED";
     field public static final java.lang.String ACTION_PROFILE_PROVISIONING_COMPLETE = "android.app.action.PROFILE_PROVISIONING_COMPLETE";
+    field public static final int BUGREPORT_FAILURE_FAILED_COMPLETING = 0; // 0x0
+    field public static final int BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE = 1; // 0x1
     field public static final java.lang.String DEVICE_ADMIN_META_DATA = "android.app.device_admin";
     field public static final java.lang.String EXTRA_DISABLE_WARNING = "android.app.extra.DISABLE_WARNING";
     field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
@@ -5747,27 +5796,35 @@
     method public void clearCrossProfileIntentFilters(android.content.ComponentName);
     method public void clearDeviceOwnerApp(java.lang.String);
     method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
+    method public void clearProfileOwner(android.content.ComponentName);
     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();
     method public java.util.List<android.content.ComponentName> getActiveAdmins();
+    method public java.lang.String getAlwaysOnVpnPackage(android.content.ComponentName);
     method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
+    method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName);
     method public boolean getAutoTimeRequired();
     method public boolean getBluetoothContactSharingDisabled(android.content.ComponentName);
     method public boolean getCameraDisabled(android.content.ComponentName);
     method public java.lang.String getCertInstallerPackage(android.content.ComponentName) throws java.lang.SecurityException;
     method public boolean getCrossProfileCallerIdDisabled(android.content.ComponentName);
+    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 java.lang.String 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);
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
+    method public int getOrganizationColor(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);
     method public int getPasswordHistoryLength(android.content.ComponentName);
@@ -5785,6 +5842,7 @@
     method public java.util.List<java.lang.String> getPermittedAccessibilityServices(android.content.ComponentName);
     method public java.util.List<java.lang.String> getPermittedInputMethods(android.content.ComponentName);
     method public boolean getScreenCaptureDisabled(android.content.ComponentName);
+    method public java.lang.String getShortSupportMessage(android.content.ComponentName);
     method public boolean getStorageEncryption(android.content.ComponentName);
     method public int getStorageEncryptionStatus();
     method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
@@ -5798,6 +5856,7 @@
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
     method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
+    method public boolean isCallerApplicationRestrictionsManagingPackage();
     method public boolean isDeviceOwnerApp(java.lang.String);
     method public boolean isLockTaskPermitted(java.lang.String);
     method public boolean isMasterVolumeMuted(android.content.ComponentName);
@@ -5805,27 +5864,34 @@
     method public boolean isProvisioningAllowed(java.lang.String);
     method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String);
     method public void lockNow();
+    method public void reboot(android.content.ComponentName);
     method public void removeActiveAdmin(android.content.ComponentName);
     method public boolean removeCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
     method public boolean removeKeyPair(android.content.ComponentName, java.lang.String);
     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 void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
+    method public boolean setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String);
     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 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 boolean setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.String);
     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);
     method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
+    method public void setLongSupportMessage(android.content.ComponentName, java.lang.String);
     method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
+    method public void setOrganizationColor(android.content.ComponentName, int);
     method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
     method public void setPasswordHistoryLength(android.content.ComponentName, int);
@@ -5847,6 +5913,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 setShortSupportMessage(android.content.ComponentName, java.lang.String);
     method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
     method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
@@ -5862,6 +5929,7 @@
     field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
     field public static final java.lang.String ACTION_PROVISION_MANAGED_DEVICE = "android.app.action.PROVISION_MANAGED_DEVICE";
     field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
+    field public static final java.lang.String ACTION_SET_NEW_PARENT_PROFILE_PASSWORD = "android.app.action.SET_NEW_PARENT_PROFILE_PASSWORD";
     field public static final java.lang.String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
     field public static final java.lang.String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
     field public static final java.lang.String ACTION_SYSTEM_UPDATE_POLICY_CHANGED = "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED";
@@ -5924,6 +5992,7 @@
     field public static final int PERMISSION_POLICY_PROMPT = 0; // 0x0
     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 WIPE_EXTERNAL_STORAGE = 1; // 0x1
     field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
   }
@@ -6045,6 +6114,7 @@
     method public void onCreate();
     method public void onDestroy();
     method public void onFullBackup(android.app.backup.FullBackupDataOutput) throws java.io.IOException;
+    method public void onQuotaExceeded(long, long);
     method public abstract void onRestore(android.app.backup.BackupDataInput, int, android.os.ParcelFileDescriptor) throws java.io.IOException;
     method public void onRestoreFile(android.os.ParcelFileDescriptor, long, java.io.File, int, long, long) throws java.io.IOException;
     method public void onRestoreFinished();
@@ -6125,6 +6195,7 @@
     method public int describeContents();
     method public int getBackoffPolicy();
     method public android.os.PersistableBundle getExtras();
+    method public long getFlexMillis();
     method public int getId();
     method public long getInitialBackoffMillis();
     method public long getIntervalMillis();
@@ -6132,6 +6203,7 @@
     method public long getMinLatencyMillis();
     method public int getNetworkType();
     method public android.content.ComponentName getService();
+    method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
     method public boolean isPeriodic();
     method public boolean isPersisted();
     method public boolean isRequireCharging();
@@ -6142,6 +6214,8 @@
     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
@@ -6149,22 +6223,36 @@
 
   public static final class JobInfo.Builder {
     ctor public JobInfo.Builder(int, android.content.ComponentName);
+    method public android.app.job.JobInfo.Builder addTriggerContentUri(android.app.job.JobInfo.TriggerContentUri);
     method public android.app.job.JobInfo build();
     method public android.app.job.JobInfo.Builder setBackoffCriteria(long, int);
     method public android.app.job.JobInfo.Builder setExtras(android.os.PersistableBundle);
     method public android.app.job.JobInfo.Builder setMinimumLatency(long);
     method public android.app.job.JobInfo.Builder setOverrideDeadline(long);
     method public android.app.job.JobInfo.Builder setPeriodic(long);
+    method public android.app.job.JobInfo.Builder setPeriodic(long, long);
     method public android.app.job.JobInfo.Builder setPersisted(boolean);
     method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
     method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
     method public android.app.job.JobInfo.Builder setRequiresDeviceIdle(boolean);
   }
 
+  public static final class JobInfo.TriggerContentUri implements android.os.Parcelable {
+    ctor public JobInfo.TriggerContentUri(android.net.Uri, int);
+    method public int describeContents();
+    method public int getFlags();
+    method public android.net.Uri getUri();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.job.JobInfo.TriggerContentUri> CREATOR;
+    field public static final int FLAG_NOTIFY_FOR_DESCENDANTS = 1; // 0x1
+  }
+
   public class JobParameters implements android.os.Parcelable {
     method public int describeContents();
     method public android.os.PersistableBundle getExtras();
     method public int getJobId();
+    method public java.lang.String[] getTriggeredContentAuthorities();
+    method public android.net.Uri[] getTriggeredContentUris();
     method public boolean isOverrideDeadlineExpired();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.job.JobParameters> CREATOR;
@@ -6215,6 +6303,8 @@
   public static class NetworkStats.Bucket {
     ctor public NetworkStats.Bucket();
     method public long getEndTimeStamp();
+    method public int getMetering();
+    method public int getRoaming();
     method public long getRxBytes();
     method public long getRxPackets();
     method public long getStartTimeStamp();
@@ -6222,6 +6312,12 @@
     method public long getTxBytes();
     method public long getTxPackets();
     method public int getUid();
+    field public static final int METERING_ALL = -1; // 0xffffffff
+    field public static final int METERING_DEFAULT = 1; // 0x1
+    field public static final int METERING_METERED = 2; // 0x2
+    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 STATE_ALL = -1; // 0xffffffff
     field public static final int STATE_DEFAULT = 1; // 0x1
     field public static final int STATE_FOREGROUND = 2; // 0x2
@@ -6415,6 +6511,31 @@
 
 }
 
+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 {
@@ -7148,6 +7269,15 @@
     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 {
@@ -7572,11 +7702,12 @@
     method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
   }
 
-  public class ContentProviderClient {
+  public class ContentProviderClient implements java.lang.AutoCloseable {
     method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
     method public int bulkInsert(android.net.Uri, android.content.ContentValues[]) throws android.os.RemoteException;
     method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException;
     method public final android.net.Uri canonicalize(android.net.Uri) throws android.os.RemoteException;
+    method public void close();
     method public int delete(android.net.Uri, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
     method public android.content.ContentProvider getLocalContentProvider();
     method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String) throws android.os.RemoteException;
@@ -7590,7 +7721,7 @@
     method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
     method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) throws android.os.RemoteException;
     method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal) throws android.os.RemoteException;
-    method public boolean release();
+    method public deprecated boolean release();
     method public final android.net.Uri uncanonicalize(android.net.Uri) throws android.os.RemoteException;
     method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
   }
@@ -7672,6 +7803,7 @@
     method public static java.util.List<android.content.PeriodicSync> getPeriodicSyncs(android.accounts.Account, java.lang.String);
     method public java.util.List<android.content.UriPermission> getPersistedUriPermissions();
     method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String);
+    method public static java.lang.String[] getSyncAdapterPackagesForAuthorityAsUser(java.lang.String, int);
     method public static android.content.SyncAdapterType[] getSyncAdapterTypes();
     method public static boolean getSyncAutomatically(android.accounts.Account, java.lang.String);
     method public final java.lang.String getType(android.net.Uri);
@@ -7838,6 +7970,7 @@
     method public abstract java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public final java.lang.CharSequence getText(int);
     method public abstract android.content.res.Resources.Theme getTheme();
+    method public abstract int getUserId();
     method public abstract deprecated android.graphics.drawable.Drawable getWallpaper();
     method public abstract deprecated int getWallpaperDesiredMinimumHeight();
     method public abstract deprecated int getWallpaperDesiredMinimumWidth();
@@ -7916,6 +8049,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 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";
@@ -8020,6 +8154,7 @@
     method public java.lang.Object getSystemService(java.lang.String);
     method public java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public android.content.res.Resources.Theme getTheme();
+    method public int getUserId();
     method public deprecated android.graphics.drawable.Drawable getWallpaper();
     method public deprecated int getWallpaperDesiredMinimumHeight();
     method public deprecated int getWallpaperDesiredMinimumWidth();
@@ -8269,7 +8404,6 @@
     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";
     field public static final java.lang.String ACTION_ATTACH_DATA = "android.intent.action.ATTACH_DATA";
-    field public static final java.lang.String ACTION_AVAILABILITY_CHANGED = "android.intent.action.AVAILABILITY_CHANGED";
     field public static final java.lang.String ACTION_BATTERY_CHANGED = "android.intent.action.BATTERY_CHANGED";
     field public static final java.lang.String ACTION_BATTERY_LOW = "android.intent.action.BATTERY_LOW";
     field public static final java.lang.String ACTION_BATTERY_OKAY = "android.intent.action.BATTERY_OKAY";
@@ -8330,6 +8464,9 @@
     field public static final java.lang.String ACTION_NEW_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL";
     field public static final java.lang.String ACTION_OPEN_DOCUMENT = "android.intent.action.OPEN_DOCUMENT";
     field public static final java.lang.String ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE";
+    field public static final java.lang.String ACTION_OPEN_EXTERNAL_DIRECTORY = "android.intent.action.OPEN_EXTERNAL_DIRECTORY";
+    field public static final java.lang.String ACTION_PACKAGES_SUSPENDED = "android.intent.action.PACKAGES_SUSPENDED";
+    field public static final java.lang.String ACTION_PACKAGES_UNSUSPENDED = "android.intent.action.PACKAGES_UNSUSPENDED";
     field public static final java.lang.String ACTION_PACKAGE_ADDED = "android.intent.action.PACKAGE_ADDED";
     field public static final java.lang.String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
     field public static final java.lang.String ACTION_PACKAGE_DATA_CLEARED = "android.intent.action.PACKAGE_DATA_CLEARED";
@@ -8350,6 +8487,7 @@
     field public static final java.lang.String ACTION_PROCESS_TEXT = "android.intent.action.PROCESS_TEXT";
     field public static final java.lang.String ACTION_PROVIDER_CHANGED = "android.intent.action.PROVIDER_CHANGED";
     field public static final java.lang.String ACTION_QUICK_CLOCK = "android.intent.action.QUICK_CLOCK";
+    field public static final java.lang.String ACTION_QUICK_VIEW = "android.intent.action.QUICK_VIEW";
     field public static final java.lang.String ACTION_REBOOT = "android.intent.action.REBOOT";
     field public static final java.lang.String ACTION_RUN = "android.intent.action.RUN";
     field public static final java.lang.String ACTION_SCREEN_OFF = "android.intent.action.SCREEN_OFF";
@@ -8443,6 +8581,7 @@
     field public static final java.lang.String EXTRA_DONT_KILL_APP = "android.intent.extra.DONT_KILL_APP";
     field public static final java.lang.String EXTRA_EMAIL = "android.intent.extra.EMAIL";
     field public static final java.lang.String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
+    field public static final java.lang.String EXTRA_INDEX = "android.intent.extra.INDEX";
     field public static final java.lang.String EXTRA_INITIAL_INTENTS = "android.intent.extra.INITIAL_INTENTS";
     field public static final java.lang.String EXTRA_INSTALLER_PACKAGE_NAME = "android.intent.extra.INSTALLER_PACKAGE_NAME";
     field public static final java.lang.String EXTRA_INTENT = "android.intent.extra.INTENT";
@@ -9004,6 +9143,7 @@
     field public static final int FLAG_ALWAYS_RETAIN_TASK_STATE = 8; // 0x8
     field public static final int FLAG_AUTO_REMOVE_FROM_RECENTS = 8192; // 0x2000
     field public static final int FLAG_CLEAR_TASK_ON_LAUNCH = 4; // 0x4
+    field public static final int FLAG_ENABLE_VR_MODE = 32768; // 0x8000
     field public static final int FLAG_EXCLUDE_FROM_RECENTS = 32; // 0x20
     field public static final int FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS = 256; // 0x100
     field public static final int FLAG_FINISH_ON_TASK_LAUNCH = 2; // 0x2
@@ -9071,6 +9211,8 @@
     ctor public ApplicationInfo(android.content.pm.ApplicationInfo);
     method public int describeContents();
     method public void dump(android.util.Printer, java.lang.String);
+    method public boolean isPrivilegedApp();
+    method public boolean isSystemApp();
     method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager);
     field public static final android.os.Parcelable.Creator<android.content.pm.ApplicationInfo> CREATOR;
     field public static final int FLAG_ALLOW_BACKUP = 32768; // 0x8000
@@ -9235,6 +9377,7 @@
 
   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 boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
     method public boolean isPackageEnabled(java.lang.String, android.os.UserHandle);
     method public void registerCallback(android.content.pm.LauncherApps.Callback);
@@ -9251,7 +9394,9 @@
     method public abstract void onPackageChanged(java.lang.String, android.os.UserHandle);
     method public abstract void onPackageRemoved(java.lang.String, android.os.UserHandle);
     method public abstract void onPackagesAvailable(java.lang.String[], android.os.UserHandle, boolean);
+    method public 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);
   }
 
   public class PackageInfo implements android.os.Parcelable {
@@ -9432,9 +9577,8 @@
     method public abstract android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract int getComponentEnabledSetting(android.content.ComponentName);
     method public abstract android.graphics.drawable.Drawable getDefaultActivityIcon();
+    method public abstract java.lang.String getDefaultBrowserPackageNameAsUser(int);
     method public abstract android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
-    method public abstract byte[] getEphemeralCookie();
-    method public abstract int getEphemeralCookieMaxSizeBytes();
     method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
     method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
     method public abstract java.lang.String getInstallerPackageName(java.lang.String);
@@ -9444,8 +9588,10 @@
     method public abstract java.lang.String getNameForUid(int);
     method public android.content.pm.PackageInfo getPackageArchiveInfo(java.lang.String, int);
     method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.PackageInstaller getPackageInstaller();
+    method public abstract int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.lang.String[] getPackagesForUid(int);
     method public abstract java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int);
     method public abstract android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -9466,7 +9612,6 @@
     method public abstract java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle);
     method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
     method public abstract boolean hasSystemFeature(java.lang.String);
-    method public abstract boolean isEphemeralApplication();
     method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
     method public abstract boolean isSafeMode();
     method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
@@ -9484,7 +9629,6 @@
     method public abstract android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
     method public abstract void setApplicationEnabledSetting(java.lang.String, int, int);
     method public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int);
-    method public abstract boolean setEphemeralCookie(byte[]);
     method public abstract void setInstallerPackageName(java.lang.String, java.lang.String);
     method public abstract void verifyPendingInstall(int, int);
     field public static final int COMPONENT_ENABLED_STATE_DEFAULT = 0; // 0x0
@@ -9516,6 +9660,7 @@
     field public static final java.lang.String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
     field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
     field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
+    field public static final java.lang.String FEATURE_ETHERNET = "android.hardware.ethernet";
     field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch";
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
@@ -9536,6 +9681,7 @@
     field public static final java.lang.String FEATURE_MIDI = "android.software.midi";
     field public static final java.lang.String FEATURE_NFC = "android.hardware.nfc";
     field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION = "android.hardware.nfc.hce";
+    field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION_NFCF = "android.hardware.nfc.hcef";
     field public static final java.lang.String FEATURE_OPENGLES_EXTENSION_PACK = "android.hardware.opengles.aep";
     field public static final java.lang.String FEATURE_PICTURE_IN_PICTURE = "android.software.picture_in_picture";
     field public static final java.lang.String FEATURE_PRINTING = "android.software.print";
@@ -9567,15 +9713,15 @@
     field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
     field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host";
     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_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";
     field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
     field public static final int GET_ACTIVITIES = 1; // 0x1
     field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
-    field public static final int GET_DISABLED_COMPONENTS = 512; // 0x200
-    field public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
-    field public static final int GET_ENCRYPTION_UNAWARE_COMPONENTS = 262144; // 0x40000
+    field public static final deprecated int GET_DISABLED_COMPONENTS = 512; // 0x200
+    field public static final deprecated int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
     field public static final int GET_GIDS = 256; // 0x100
     field public static final int GET_INSTRUMENTATION = 16; // 0x10
     field public static final int GET_INTENT_FILTERS = 32; // 0x20
@@ -9587,10 +9733,17 @@
     field public static final int GET_SERVICES = 4; // 0x4
     field public static final int GET_SHARED_LIBRARY_FILES = 1024; // 0x400
     field public static final int GET_SIGNATURES = 64; // 0x40
-    field public static final int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
+    field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
     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_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
     field public static final int PERMISSION_DENIED = -1; // 0xffffffff
     field public static final int PERMISSION_GRANTED = 0; // 0x0
@@ -9810,7 +9963,7 @@
     method public final long skip(long) throws java.io.IOException;
   }
 
-  public class ColorStateList implements android.os.Parcelable {
+  public class ColorStateList extends android.content.res.ComplexColor 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;
@@ -9819,13 +9972,18 @@
     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);
@@ -9929,6 +10087,11 @@
     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);
@@ -9973,7 +10136,6 @@
     method public java.lang.String getQuantityString(int, int, java.lang.Object...) throws android.content.res.Resources.NotFoundException;
     method public java.lang.String getQuantityString(int, int) throws android.content.res.Resources.NotFoundException;
     method public java.lang.CharSequence getQuantityText(int, int) throws android.content.res.Resources.NotFoundException;
-    method public java.util.Locale getResolvedLocale();
     method public java.lang.String getResourceEntryName(int) throws android.content.res.Resources.NotFoundException;
     method public java.lang.String getResourceName(int) throws android.content.res.Resources.NotFoundException;
     method public java.lang.String getResourcePackageName(int) throws android.content.res.Resources.NotFoundException;
@@ -9989,6 +10151,7 @@
     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;
@@ -10024,6 +10187,7 @@
     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);
@@ -10605,6 +10769,7 @@
     method public void setVersion(int);
     method public int update(java.lang.String, android.content.ContentValues, java.lang.String, java.lang.String[]);
     method public int updateWithOnConflict(java.lang.String, android.content.ContentValues, java.lang.String, java.lang.String[], int);
+    method public void validateSql(java.lang.String, android.os.CancellationSignal);
     method public deprecated boolean yieldIfContended();
     method public boolean yieldIfContendedSafely();
     method public boolean yieldIfContendedSafely(long);
@@ -10839,7 +11004,7 @@
     field public final int statusCode;
   }
 
-  public class DrmManagerClient {
+  public class DrmManagerClient implements java.lang.AutoCloseable {
     ctor public DrmManagerClient(android.content.Context);
     method public android.drm.DrmInfo acquireDrmInfo(android.drm.DrmInfoRequest);
     method public int acquireRights(android.drm.DrmInfoRequest);
@@ -10849,6 +11014,7 @@
     method public int checkRightsStatus(android.net.Uri);
     method public int checkRightsStatus(java.lang.String, int);
     method public int checkRightsStatus(android.net.Uri, int);
+    method public void close();
     method public android.drm.DrmConvertedStatus closeConvertSession(int);
     method public android.drm.DrmConvertedStatus convertData(int, byte[]);
     method public java.lang.String[] getAvailableDrmEngines();
@@ -10862,7 +11028,7 @@
     method public java.lang.String getOriginalMimeType(android.net.Uri);
     method public int openConvertSession(java.lang.String);
     method public int processDrmInfo(android.drm.DrmInfo);
-    method public void release();
+    method public deprecated void release();
     method public int removeAllRights();
     method public int removeRights(java.lang.String);
     method public int removeRights(android.net.Uri);
@@ -11266,14 +11432,14 @@
 
   public static class BitmapFactory.Options {
     ctor public BitmapFactory.Options();
-    method public void requestCancelDecode();
+    method public deprecated void requestCancelDecode();
     field public android.graphics.Bitmap inBitmap;
     field public int inDensity;
-    field public boolean inDither;
+    field public deprecated boolean inDither;
     field public deprecated boolean inInputShareable;
     field public boolean inJustDecodeBounds;
     field public boolean inMutable;
-    field public boolean inPreferQualityOverSpeed;
+    field public deprecated boolean inPreferQualityOverSpeed;
     field public android.graphics.Bitmap.Config inPreferredConfig;
     field public boolean inPremultiplied;
     field public deprecated boolean inPurgeable;
@@ -11282,7 +11448,7 @@
     field public int inScreenDensity;
     field public int inTargetDensity;
     field public byte[] inTempStorage;
-    field public boolean mCancel;
+    field public deprecated boolean mCancel;
     field public int outHeight;
     field public java.lang.String outMimeType;
     field public int outWidth;
@@ -12721,6 +12887,7 @@
     method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
     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 {
@@ -13217,6 +13384,7 @@
     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 isWakeUpSensor();
@@ -13231,17 +13399,21 @@
     field public static final java.lang.String STRING_TYPE_GRAVITY = "android.sensor.gravity";
     field public static final java.lang.String STRING_TYPE_GYROSCOPE = "android.sensor.gyroscope";
     field public static final java.lang.String STRING_TYPE_GYROSCOPE_UNCALIBRATED = "android.sensor.gyroscope_uncalibrated";
+    field public static final java.lang.String STRING_TYPE_HEART_BEAT = "android.sensor.heart_beat";
     field public static final java.lang.String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
     field public static final java.lang.String STRING_TYPE_LIGHT = "android.sensor.light";
     field public static final java.lang.String STRING_TYPE_LINEAR_ACCELERATION = "android.sensor.linear_acceleration";
     field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD = "android.sensor.magnetic_field";
     field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED = "android.sensor.magnetic_field_uncalibrated";
+    field public static final java.lang.String STRING_TYPE_MOTION_DETECT = "android.sensor.motion_detect";
     field public static final deprecated java.lang.String STRING_TYPE_ORIENTATION = "android.sensor.orientation";
+    field public static final java.lang.String STRING_TYPE_POSE_6DOF = "android.sensor.pose_6dof";
     field public static final java.lang.String STRING_TYPE_PRESSURE = "android.sensor.pressure";
     field public static final java.lang.String STRING_TYPE_PROXIMITY = "android.sensor.proximity";
     field public static final java.lang.String STRING_TYPE_RELATIVE_HUMIDITY = "android.sensor.relative_humidity";
     field public static final java.lang.String STRING_TYPE_ROTATION_VECTOR = "android.sensor.rotation_vector";
     field public static final java.lang.String STRING_TYPE_SIGNIFICANT_MOTION = "android.sensor.significant_motion";
+    field public static final java.lang.String STRING_TYPE_STATIONARY_DETECT = "android.sensor.stationary_detect";
     field public static final java.lang.String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
     field public static final java.lang.String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
     field public static final deprecated java.lang.String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
@@ -13253,22 +13425,41 @@
     field public static final int TYPE_GRAVITY = 9; // 0x9
     field public static final int TYPE_GYROSCOPE = 4; // 0x4
     field public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16; // 0x10
+    field public static final int TYPE_HEART_BEAT = 31; // 0x1f
     field public static final int TYPE_HEART_RATE = 21; // 0x15
     field public static final int TYPE_LIGHT = 5; // 0x5
     field public static final int TYPE_LINEAR_ACCELERATION = 10; // 0xa
     field public static final int TYPE_MAGNETIC_FIELD = 2; // 0x2
     field public static final int TYPE_MAGNETIC_FIELD_UNCALIBRATED = 14; // 0xe
+    field public static final int TYPE_MOTION_DETECT = 30; // 0x1e
     field public static final deprecated int TYPE_ORIENTATION = 3; // 0x3
+    field public static final int TYPE_POSE_6DOF = 28; // 0x1c
     field public static final int TYPE_PRESSURE = 6; // 0x6
     field public static final int TYPE_PROXIMITY = 8; // 0x8
     field public static final int TYPE_RELATIVE_HUMIDITY = 12; // 0xc
     field public static final int TYPE_ROTATION_VECTOR = 11; // 0xb
     field public static final int TYPE_SIGNIFICANT_MOTION = 17; // 0x11
+    field public static final int TYPE_STATIONARY_DETECT = 29; // 0x1d
     field public static final int TYPE_STEP_COUNTER = 19; // 0x13
     field public static final int TYPE_STEP_DETECTOR = 18; // 0x12
     field public static final deprecated int TYPE_TEMPERATURE = 7; // 0x7
   }
 
+  public class SensorAdditionalInfo {
+    field public static final int TYPE_FRAME_BEGIN = 0; // 0x0
+    field public static final int TYPE_FRAME_END = 1; // 0x1
+    field public static final int TYPE_INTERNAL_TEMPERATURE = 65537; // 0x10001
+    field public static final int TYPE_SAMPLING = 65540; // 0x10004
+    field public static final int TYPE_SENSOR_PLACEMENT = 65539; // 0x10003
+    field public static final int TYPE_UNTRACKED_DELAY = 65536; // 0x10000
+    field public static final int TYPE_VEC3_CALIBRATION = 65538; // 0x10002
+    field public final float[] floatValues;
+    field public final int[] intValues;
+    field public final android.hardware.Sensor sensor;
+    field public final int serial;
+    field public final int type;
+  }
+
   public class SensorEvent {
     field public int accuracy;
     field public android.hardware.Sensor sensor;
@@ -13276,6 +13467,14 @@
     field public final float[] values;
   }
 
+  public abstract class SensorEventCallback implements android.hardware.SensorEventListener2 {
+    ctor public SensorEventCallback();
+    method public void onAccuracyChanged(android.hardware.Sensor, int);
+    method public void onFlushCompleted(android.hardware.Sensor);
+    method public void onSensorAdditionalInfo(android.hardware.SensorAdditionalInfo);
+    method public void onSensorChanged(android.hardware.SensorEvent);
+  }
+
   public abstract interface SensorEventListener {
     method public abstract void onAccuracyChanged(android.hardware.Sensor, int);
     method public abstract void onSensorChanged(android.hardware.SensorEvent);
@@ -13297,6 +13496,7 @@
     method public static void getAngleChange(float[], float[], float[]);
     method public android.hardware.Sensor getDefaultSensor(int);
     method public android.hardware.Sensor getDefaultSensor(int, boolean);
+    method public java.util.List<android.hardware.Sensor> getDynamicSensorList(int);
     method public static float getInclination(float[]);
     method public static float[] getOrientation(float[], float[]);
     method public static void getQuaternionFromVector(float[], float[]);
@@ -13304,6 +13504,8 @@
     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 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);
@@ -13312,6 +13514,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 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);
@@ -13376,6 +13579,12 @@
     field public static final float STANDARD_GRAVITY = 9.80665f;
   }
 
+  public static abstract class SensorManager.DynamicSensorConnectionCallback {
+    ctor public SensorManager.DynamicSensorConnectionCallback();
+    method public void onDynamicSensorConnected(android.hardware.Sensor);
+    method public void onDynamicSensorDisconnected(android.hardware.Sensor);
+  }
+
   public final class TriggerEvent {
     field public android.hardware.Sensor sensor;
     field public long timestamp;
@@ -13460,6 +13669,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AF;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AWB;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Integer>> CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> DEPTH_DEPTH_IS_EXCLUSIVE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> EDGE_AVAILABLE_EDGE_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> FLASH_INFO_AVAILABLE;
@@ -13539,9 +13749,11 @@
     method public abstract void close();
     method public abstract android.hardware.camera2.CaptureRequest.Builder createCaptureRequest(int) throws android.hardware.camera2.CameraAccessException;
     method public abstract void createCaptureSession(java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method public abstract void createCaptureSessionByOutputConfiguration(java.util.List<android.hardware.camera2.params.OutputConfiguration>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract void createConstrainedHighSpeedCaptureSession(java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract android.hardware.camera2.CaptureRequest.Builder createReprocessCaptureRequest(android.hardware.camera2.TotalCaptureResult) throws android.hardware.camera2.CameraAccessException;
     method public abstract void createReprocessableCaptureSession(android.hardware.camera2.params.InputConfiguration, java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method public abstract void createReprocessableCaptureSessionWithConfigurations(android.hardware.camera2.params.InputConfiguration, java.util.List<android.hardware.camera2.params.OutputConfiguration>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract java.lang.String getId();
     field public static final int TEMPLATE_MANUAL = 6; // 0x6
     field public static final int TEMPLATE_PREVIEW = 1; // 0x1
@@ -13698,6 +13910,7 @@
     field public static final int HOT_PIXEL_MODE_FAST = 1; // 0x1
     field public static final int HOT_PIXEL_MODE_HIGH_QUALITY = 2; // 0x2
     field public static final int HOT_PIXEL_MODE_OFF = 0; // 0x0
+    field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_3 = 3; // 0x3
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1; // 0x1
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY = 2; // 0x2
     field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0; // 0x0
@@ -13819,6 +14032,7 @@
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_CAPTURE_INTENT;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_EFFECT_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_MODE;
+    field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_POST_RAW_SENSITIVITY_BOOST;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_SCENE_MODE;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_VIDEO_STABILIZATION_MODE;
     field public static final android.os.Parcelable.Creator<android.hardware.camera2.CaptureRequest> CREATOR;
@@ -13897,6 +14111,7 @@
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_CAPTURE_INTENT;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_EFFECT_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_POST_RAW_SENSITIVITY_BOOST;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_SCENE_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_VIDEO_STABILIZATION_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> EDGE_MODE;
@@ -14038,6 +14253,17 @@
     field public static final int METERING_WEIGHT_MIN = 0; // 0x0
   }
 
+  public final class OutputConfiguration implements android.os.Parcelable {
+    ctor public OutputConfiguration(android.view.Surface);
+    method public int describeContents();
+    method public android.view.Surface getSurface();
+    method public int getSurfaceSetId();
+    method public void setSurfaceSetId(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
+    field public static final int SURFACE_SET_ID_INVALID = -1; // 0xffffffff
+  }
+
   public final class RggbChannelVector {
     ctor public RggbChannelVector(float, float, float, float);
     method public void copyTo(float[], int);
@@ -18242,7 +18468,6 @@
     method public static java.lang.String getCanonicalID(java.lang.String, boolean[]);
     method public int getDSTSavings();
     method public static android.icu.util.TimeZone getDefault();
-    method public static int getDefaultTimeZoneType();
     method public final java.lang.String getDisplayName();
     method public final java.lang.String getDisplayName(java.util.Locale);
     method public final java.lang.String getDisplayName(android.icu.util.ULocale);
@@ -18266,8 +18491,6 @@
     method public abstract boolean inDaylightTime(java.util.Date);
     method public boolean isFrozen();
     method public boolean observesDaylightTime();
-    method public static synchronized void setDefault(android.icu.util.TimeZone);
-    method public static synchronized void setDefaultTimeZoneType(int);
     method public void setID(java.lang.String);
     method public abstract void setRawOffset(int);
     method public abstract boolean useDaylightTime();
@@ -18280,8 +18503,6 @@
     field public static final int SHORT_COMMONLY_USED = 6; // 0x6
     field public static final int SHORT_GENERIC = 2; // 0x2
     field public static final int SHORT_GMT = 4; // 0x4
-    field public static final int TIMEZONE_ICU = 0; // 0x0
-    field public static final int TIMEZONE_JDK = 1; // 0x1
     field public static final android.icu.util.TimeZone UNKNOWN_ZONE;
     field public static final java.lang.String UNKNOWN_ZONE_ID = "Etc/Unknown";
   }
@@ -18377,8 +18598,6 @@
     method public static java.lang.String getVariant(java.lang.String);
     method public boolean isRightToLeft();
     method public static android.icu.util.ULocale minimizeSubtags(android.icu.util.ULocale);
-    method public static synchronized void setDefault(android.icu.util.ULocale);
-    method public static synchronized void setDefault(android.icu.util.ULocale.Category, android.icu.util.ULocale);
     method public android.icu.util.ULocale setKeywordValue(java.lang.String, java.lang.String);
     method public static java.lang.String setKeywordValue(java.lang.String, java.lang.String, java.lang.String);
     method public java.lang.String toLanguageTag();
@@ -18866,6 +19085,288 @@
     method public static boolean isPresent();
   }
 
+  public abstract interface GnssNmeaListener {
+    method public abstract void onNmeaReceived(long, java.lang.String);
+  }
+
+  public final class GnssStatus {
+    method public float getAzimuth(int);
+    method public int getConstellationType(int);
+    method public float getElevation(int);
+    method public int getNumSatellites();
+    method public int getPrn(int);
+    method public float getSnr(int);
+    method public boolean hasAlmanac(int);
+    method public boolean hasEphemeris(int);
+    method public boolean usedInFix(int);
+    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 {
+    ctor public GnssStatusCallback();
+    method public void onFirstFix(int);
+    method public void onSatelliteStatusChanged(android.location.GnssStatus);
+    method public void onStarted();
+    method public void onStopped();
+  }
+
+  public final class GpsClock 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 short getLeapSecond();
+    method public long getTimeInNs();
+    method public long getTimeOfLastHwClockDiscontinuityInNs();
+    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 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.GpsClock);
+    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 setLeapSecond(short);
+    method public void setTimeInNs(long);
+    method public void setTimeOfLastHwClockDiscontinuityInNs(long);
+    method public void setTimeUncertaintyInNs(double);
+    method public void setType(byte);
+    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.GpsClock> CREATOR;
+  }
+
+  public static abstract class GpsClock.GpsClockType implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsMeasurement 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 long getCarrierCycles();
+    method public float getCarrierFrequencyInHz();
+    method public double getCarrierPhase();
+    method public double getCarrierPhaseUncertainty();
+    method public double getCn0InDbHz();
+    method public double getCodePhaseInChips();
+    method public double getCodePhaseUncertaintyInChips();
+    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 byte getPrn();
+    method public double getPseudorangeInMeters();
+    method public double getPseudorangeRateCarrierInMetersPerSec();
+    method public double getPseudorangeRateCarrierUncertaintyInMetersPerSec();
+    method public double getPseudorangeRateInMetersPerSec();
+    method public double getPseudorangeRateUncertaintyInMetersPerSec();
+    method public double getPseudorangeUncertaintyInMeters();
+    method public long getReceivedGpsTowInNs();
+    method public long getReceivedGpsTowUncertaintyInNs();
+    method public double getSnrInDb();
+    method public short getState();
+    method public short getTimeFromLastBitInMs();
+    method public double getTimeOffsetInNs();
+    method public boolean hasAzimuthInDeg();
+    method public boolean hasAzimuthUncertaintyInDeg();
+    method public boolean hasBitNumber();
+    method public boolean hasCarrierCycles();
+    method public boolean hasCarrierFrequencyInHz();
+    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.GpsMeasurement);
+    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 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 setPrn(byte);
+    method public void setPseudorangeInMeters(double);
+    method public void setPseudorangeRateCarrierInMetersPerSec(double);
+    method public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double);
+    method public void setPseudorangeRateInMetersPerSec(double);
+    method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
+    method public void setPseudorangeUncertaintyInMeters(double);
+    method public void setReceivedGpsTowInNs(long);
+    method public void setReceivedGpsTowUncertaintyInNs(long);
+    method public void setSnrInDb(double);
+    method public void setState(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 android.os.Parcelable.Creator<android.location.GpsMeasurement> 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 GpsMeasurement.LossOfLockStatus implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract class GpsMeasurement.MultipathIndicator implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsMeasurementsEvent implements android.os.Parcelable {
+    ctor public GpsMeasurementsEvent(android.location.GpsClock, android.location.GpsMeasurement[]);
+    method public int describeContents();
+    method public android.location.GpsClock getClock();
+    method public java.util.Collection<android.location.GpsMeasurement> getMeasurements();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.location.GpsMeasurementsEvent> CREATOR;
+    field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
+    field public static final int STATUS_READY = 1; // 0x1
+  }
+
+  public static abstract class GpsMeasurementsEvent.Callback {
+    ctor public GpsMeasurementsEvent.Callback();
+    method public void onGpsMeasurementsReceived(android.location.GpsMeasurementsEvent);
+    method public void onStatusChanged(int);
+  }
+
+  public static abstract class GpsMeasurementsEvent.GpsMeasurementsStatus implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsNavigationMessage implements android.os.Parcelable {
+    method public int describeContents();
+    method public byte[] getData();
+    method public short getMessageId();
+    method public byte getPrn();
+    method public short getStatus();
+    method public short getSubmessageId();
+    method public byte getType();
+    method public void reset();
+    method public void set(android.location.GpsNavigationMessage);
+    method public void setData(byte[]);
+    method public void setMessageId(short);
+    method public void setPrn(byte);
+    method public void setStatus(short);
+    method public void setSubmessageId(short);
+    method public void setType(byte);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessage> CREATOR;
+    field public static final byte MESSAGE_TYPE_CNAV2 = 4; // 0x4
+    field public static final byte MESSAGE_TYPE_L1CA = 1; // 0x1
+    field public static final byte MESSAGE_TYPE_L2CNAV = 2; // 0x2
+    field public static final byte MESSAGE_TYPE_L5CNAV = 3; // 0x3
+    field public static final byte 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 GpsNavigationMessage.GpsNavigationMessageType implements java.lang.annotation.Annotation {
+  }
+
+  public final class GpsNavigationMessageEvent implements android.os.Parcelable {
+    ctor public GpsNavigationMessageEvent(android.location.GpsNavigationMessage);
+    method public int describeContents();
+    method public android.location.GpsNavigationMessage getNavigationMessage();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessageEvent> CREATOR;
+    field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
+    field public static final int STATUS_READY = 1; // 0x1
+  }
+
+  public static abstract class GpsNavigationMessageEvent.Callback {
+    ctor public GpsNavigationMessageEvent.Callback();
+    method public void onGpsNavigationMessageReceived(android.location.GpsNavigationMessageEvent);
+    method public void onStatusChanged(int);
+  }
+
+  public static abstract class GpsNavigationMessageEvent.GpsNavigationMessageStatus implements java.lang.annotation.Annotation {
+  }
+
   public final class GpsSatellite {
     method public float getAzimuth();
     method public float getElevation();
@@ -18950,8 +19451,10 @@
   }
 
   public class LocationManager {
-    method public boolean addGpsStatusListener(android.location.GpsStatus.Listener);
-    method public boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public deprecated boolean addGpsStatusListener(android.location.GpsStatus.Listener);
+    method public deprecated boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public boolean addNmeaListener(android.location.GnssNmeaListener);
+    method public boolean addNmeaListener(android.location.GnssNmeaListener, android.os.Handler);
     method public void addProximityAlert(double, double, float, long, android.app.PendingIntent);
     method public void addTestProvider(java.lang.String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
     method public void clearTestProviderEnabled(java.lang.String);
@@ -18959,14 +19462,22 @@
     method public void clearTestProviderStatus(java.lang.String);
     method public java.util.List<java.lang.String> getAllProviders();
     method public java.lang.String getBestProvider(android.location.Criteria, boolean);
-    method public android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
+    method public deprecated android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
+    method public int getGpsYearOfHardware();
     method public android.location.Location getLastKnownLocation(java.lang.String);
     method public android.location.LocationProvider getProvider(java.lang.String);
     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 void removeGpsStatusListener(android.location.GpsStatus.Listener);
-    method public void removeNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback);
+    method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback, android.os.Handler);
+    method public boolean registerGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback);
+    method public boolean registerGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback, android.os.Handler);
+    method public boolean registerGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback);
+    method public boolean registerGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback, android.os.Handler);
+    method public deprecated void removeGpsStatusListener(android.location.GpsStatus.Listener);
+    method public deprecated void removeNmeaListener(android.location.GpsStatus.NmeaListener);
+    method public void removeNmeaListener(android.location.GnssNmeaListener);
     method public void removeProximityAlert(android.app.PendingIntent);
     method public void removeTestProvider(java.lang.String);
     method public void removeUpdates(android.location.LocationListener);
@@ -18984,6 +19495,9 @@
     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 unregisterGnssStatusCallback(android.location.GnssStatusCallback);
+    method public void unregisterGpsMeasurementCallback(android.location.GpsMeasurementsEvent.Callback);
+    method public void unregisterGpsNavigationMessageCallback(android.location.GpsNavigationMessageEvent.Callback);
     field public static final java.lang.String GPS_PROVIDER = "gps";
     field public static final java.lang.String KEY_LOCATION_CHANGED = "location";
     field public static final java.lang.String KEY_PROVIDER_ENABLED = "providerEnabled";
@@ -19050,6 +19564,7 @@
     field public static final android.os.Parcelable.Creator<android.media.AudioAttributes> CREATOR;
     field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
     field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
+    field public static final int FLAG_LOW_LATENCY = 256; // 0x100
     field public static final int USAGE_ALARM = 4; // 0x4
     field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
     field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc
@@ -19169,6 +19684,7 @@
     field public static final int ENCODING_DTS = 7; // 0x7
     field public static final int ENCODING_DTS_HD = 8; // 0x8
     field public static final int ENCODING_E_AC3 = 6; // 0x6
+    field public static final int ENCODING_IEC61937 = 13; // 0xd
     field public static final int ENCODING_INVALID = 0; // 0x0
     field public static final int ENCODING_PCM_16BIT = 2; // 0x2
     field public static final int ENCODING_PCM_8BIT = 3; // 0x3
@@ -19192,6 +19708,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.AudioDeviceInfo[] getDevices(int);
     method public int getMode();
     method public java.lang.String getParameters(java.lang.String);
@@ -19214,6 +19731,7 @@
     method public void playSoundEffect(int);
     method public void playSoundEffect(int, float);
     method public void registerAudioDeviceCallback(android.media.AudioDeviceCallback, android.os.Handler);
+    method public void registerAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback, android.os.Handler);
     method public deprecated void registerMediaButtonEventReceiver(android.content.ComponentName);
     method public deprecated void registerMediaButtonEventReceiver(android.app.PendingIntent);
     method public deprecated void registerRemoteControlClient(android.media.RemoteControlClient);
@@ -19237,6 +19755,7 @@
     method public void stopBluetoothSco();
     method public void unloadSoundEffects();
     method public void unregisterAudioDeviceCallback(android.media.AudioDeviceCallback);
+    method public void unregisterAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback);
     method public deprecated void unregisterMediaButtonEventReceiver(android.content.ComponentName);
     method public deprecated void unregisterMediaButtonEventReceiver(android.app.PendingIntent);
     method public deprecated void unregisterRemoteControlClient(android.media.RemoteControlClient);
@@ -19299,6 +19818,7 @@
     field public static final deprecated int NUM_STREAMS = 5; // 0x5
     field public static final java.lang.String PROPERTY_OUTPUT_FRAMES_PER_BUFFER = "android.media.property.OUTPUT_FRAMES_PER_BUFFER";
     field public static final java.lang.String PROPERTY_OUTPUT_SAMPLE_RATE = "android.media.property.OUTPUT_SAMPLE_RATE";
+    field public static final java.lang.String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED = "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED";
     field public static final java.lang.String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND = "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND";
     field public static final java.lang.String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND = "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND";
     field public static final java.lang.String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED";
@@ -19332,13 +19852,19 @@
     field public static final deprecated int VIBRATE_TYPE_RINGER = 0; // 0x0
   }
 
+  public static abstract class AudioManager.AudioRecordingCallback {
+    ctor public AudioManager.AudioRecordingCallback();
+    method public void onRecordConfigChanged();
+  }
+
   public static abstract interface AudioManager.OnAudioFocusChangeListener {
     method public abstract void onAudioFocusChange(int);
   }
 
-  public class AudioRecord {
+  public class AudioRecord implements android.media.AudioRouting {
     ctor public AudioRecord(int, int, int, int, int) throws java.lang.IllegalArgumentException;
-    method public void addOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener, android.os.Handler);
+    method public deprecated void addOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener, android.os.Handler);
+    method public void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
     method public int getAudioFormat();
     method public int getAudioSessionId();
     method public int getAudioSource();
@@ -19362,7 +19888,8 @@
     method public int read(java.nio.ByteBuffer, int);
     method public int read(java.nio.ByteBuffer, int, int);
     method public void release();
-    method public void removeOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener);
+    method public deprecated void removeOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener);
+    method public void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
     method public int setNotificationMarkerPosition(int);
     method public int setPositionNotificationPeriod(int);
     method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
@@ -19400,21 +19927,45 @@
     method public abstract void onRoutingChanged(android.media.AudioRecord);
   }
 
+  public class AudioRecordConfiguration implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.media.AudioDeviceInfo getAudioDevice();
+    method public int getClientAudioSessionId();
+    method public int getClientAudioSource();
+    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;
+  }
+
+  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 void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
+    method public abstract boolean setPreferredDevice(android.media.AudioDeviceInfo);
+  }
+
+  public static abstract interface AudioRouting.OnRoutingChangedListener {
+    method public abstract void onRoutingChanged(android.media.AudioRouting);
+  }
+
   public final class AudioTimestamp {
     ctor public AudioTimestamp();
     field public long framePosition;
     field public long nanoTime;
   }
 
-  public class AudioTrack {
+  public class AudioTrack implements android.media.AudioRouting {
     ctor public AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
     ctor public AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
     ctor public AudioTrack(android.media.AudioAttributes, android.media.AudioFormat, int, int, int) throws java.lang.IllegalArgumentException;
-    method public void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
+    method public deprecated void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
+    method public void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
     method public int attachAuxEffect(int);
     method public void flush();
     method public int getAudioFormat();
     method public int getAudioSessionId();
+    method public int getBufferCapacityInFrames();
     method public int getBufferSizeInFrames();
     method public int getChannelConfiguration();
     method public int getChannelCount();
@@ -19436,12 +19987,15 @@
     method public int getState();
     method public int getStreamType();
     method public boolean getTimestamp(android.media.AudioTimestamp);
+    method public int getUnderrunCount();
     method public void pause() throws java.lang.IllegalStateException;
     method public void play() throws java.lang.IllegalStateException;
     method public void release();
     method public int reloadStaticData();
-    method public void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
+    method public deprecated void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
+    method public void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
     method public int setAuxEffectSendLevel(float);
+    method public int setBufferSizeInFrames(int);
     method public int setLoopPoints(int, int, int);
     method public int setNotificationMarkerPosition(int);
     method public int setPlaybackHeadPosition(int);
@@ -19493,8 +20047,8 @@
     method public abstract void onPeriodicNotification(android.media.AudioTrack);
   }
 
-  public static abstract interface AudioTrack.OnRoutingChangedListener {
-    method public abstract void onRoutingChanged(android.media.AudioTrack);
+  public static abstract deprecated interface AudioTrack.OnRoutingChangedListener {
+    method public abstract deprecated void onRoutingChanged(android.media.AudioTrack);
   }
 
   public class CamcorderProfile {
@@ -19553,6 +20107,16 @@
     ctor public DeniedByServerException(java.lang.String);
   }
 
+  public abstract class DrmInitData {
+    ctor public DrmInitData();
+    method public abstract android.media.DrmInitData.SchemeInitData get(java.util.UUID);
+  }
+
+  public static final class DrmInitData.SchemeInitData {
+    field public final byte[] data;
+    field public final java.lang.String mimeType;
+  }
+
   public class ExifInterface {
     ctor public ExifInterface(java.lang.String) throws java.io.IOException;
     method public double getAltitude(double);
@@ -19900,6 +20464,7 @@
     field public static final deprecated int COLOR_QCOM_FormatYUV420SemiPlanar = 2141391872; // 0x7fa30c00
     field public static final deprecated int COLOR_TI_FormatYUV420PackedSemiPlanar = 2130706688; // 0x7f000100
     field public static final java.lang.String FEATURE_AdaptivePlayback = "adaptive-playback";
+    field public static final java.lang.String FEATURE_IntraRefresh = "intra-refresh";
     field public static final java.lang.String FEATURE_SecurePlayback = "secure-playback";
     field public static final java.lang.String FEATURE_TunneledPlayback = "tunneled-playback";
     field public int[] colorFormats;
@@ -19942,6 +20507,21 @@
     field public static final int AVCProfileHigh422 = 32; // 0x20
     field public static final int AVCProfileHigh444 = 64; // 0x40
     field public static final int AVCProfileMain = 2; // 0x2
+    field public static final int DolbyVisionLevelFhd24 = 4; // 0x4
+    field public static final int DolbyVisionLevelFhd30 = 8; // 0x8
+    field public static final int DolbyVisionLevelFhd60 = 16; // 0x10
+    field public static final int DolbyVisionLevelHd24 = 1; // 0x1
+    field public static final int DolbyVisionLevelHd30 = 2; // 0x2
+    field public static final int DolbyVisionLevelUhd24 = 32; // 0x20
+    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 H263Level10 = 1; // 0x1
     field public static final int H263Level20 = 2; // 0x2
     field public static final int H263Level30 = 4; // 0x4
@@ -20026,6 +20606,24 @@
     field public static final int VP8Level_Version2 = 4; // 0x4
     field public static final int VP8Level_Version3 = 8; // 0x8
     field public static final int VP8ProfileMain = 1; // 0x1
+    field public static final int VP9Level1 = 0; // 0x0
+    field public static final int VP9Level11 = 1; // 0x1
+    field public static final int VP9Level2 = 2; // 0x2
+    field public static final int VP9Level21 = 4; // 0x4
+    field public static final int VP9Level3 = 8; // 0x8
+    field public static final int VP9Level31 = 16; // 0x10
+    field public static final int VP9Level4 = 32; // 0x20
+    field public static final int VP9Level41 = 64; // 0x40
+    field public static final int VP9Level5 = 128; // 0x80
+    field public static final int VP9Level51 = 256; // 0x100
+    field public static final int VP9Level52 = 512; // 0x200
+    field public static final int VP9Level6 = 1024; // 0x400
+    field public static final int VP9Level61 = 2048; // 0x800
+    field public static final int VP9Level62 = 4096; // 0x1000
+    field public static final int VP9Profile0 = 0; // 0x0
+    field public static final int VP9Profile1 = 1; // 0x1
+    field public static final int VP9Profile2 = 2; // 0x2
+    field public static final int VP9Profile3 = 3; // 0x3
     field public int level;
     field public int profile;
   }
@@ -20209,6 +20807,7 @@
     ctor public MediaExtractor();
     method public boolean advance();
     method public long getCachedDuration();
+    method public android.media.DrmInitData getDrmInitData();
     method public java.util.Map<java.util.UUID, byte[]> getPsshInfo();
     method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo);
     method public int getSampleFlags();
@@ -20253,6 +20852,16 @@
     method public final void setInteger(java.lang.String, int);
     method public final void setLong(java.lang.String, long);
     method public final void setString(java.lang.String, java.lang.String);
+    field public static final int COLOR_RANGE_FULL = 1; // 0x1
+    field public static final int COLOR_RANGE_LIMITED = 2; // 0x2
+    field public static final int COLOR_STANDARD_BT2020 = 6; // 0x6
+    field public static final int COLOR_STANDARD_BT601_NTSC = 4; // 0x4
+    field public static final int COLOR_STANDARD_BT601_PAL = 2; // 0x2
+    field public static final int COLOR_STANDARD_BT709 = 1; // 0x1
+    field public static final int COLOR_TRANSFER_HLG = 7; // 0x7
+    field public static final int COLOR_TRANSFER_LINEAR = 1; // 0x1
+    field public static final int COLOR_TRANSFER_SDR_VIDEO = 3; // 0x3
+    field public static final int COLOR_TRANSFER_ST2084 = 6; // 0x6
     field public static final java.lang.String KEY_AAC_DRC_ATTENUATION_FACTOR = "aac-drc-cut-level";
     field public static final java.lang.String KEY_AAC_DRC_BOOST_FACTOR = "aac-drc-boost-level";
     field public static final java.lang.String KEY_AAC_DRC_HEAVY_COMPRESSION = "aac-drc-heavy-compression";
@@ -20268,11 +20877,15 @@
     field public static final java.lang.String KEY_CHANNEL_COUNT = "channel-count";
     field public static final java.lang.String KEY_CHANNEL_MASK = "channel-mask";
     field public static final java.lang.String KEY_COLOR_FORMAT = "color-format";
+    field public static final java.lang.String KEY_COLOR_RANGE = "color-range";
+    field public static final java.lang.String KEY_COLOR_STANDARD = "color-standard";
+    field public static final java.lang.String KEY_COLOR_TRANSFER = "color-transfer";
     field public static final java.lang.String KEY_COMPLEXITY = "complexity";
     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_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";
     field public static final java.lang.String KEY_IS_AUTOSELECT = "is-autoselect";
     field public static final java.lang.String KEY_IS_DEFAULT = "is-default";
@@ -20312,8 +20925,7 @@
     field public static final java.lang.String MIMETYPE_TEXT_CEA_608 = "text/cea-608";
     field public static final java.lang.String MIMETYPE_TEXT_VTT = "text/vtt";
     field public static final java.lang.String MIMETYPE_VIDEO_AVC = "video/avc";
-    field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_AVC = "video/dolby-avc";
-    field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_HEVC = "video/dolby-hevc";
+    field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision";
     field public static final java.lang.String MIMETYPE_VIDEO_H263 = "video/3gpp";
     field public static final java.lang.String MIMETYPE_VIDEO_HEVC = "video/hevc";
     field public static final java.lang.String MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
@@ -20595,9 +21207,11 @@
     method public static final int getAudioSourceMax();
     method public int getMaxAmplitude() throws java.lang.IllegalStateException;
     method public android.view.Surface getSurface();
+    method public void pause() throws java.lang.IllegalStateException;
     method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
     method public void release();
     method public void reset();
+    method public void resume() throws java.lang.IllegalStateException;
     method public void setAudioChannels(int);
     method public void setAudioEncoder(int) throws java.lang.IllegalStateException;
     method public void setAudioEncodingBitRate(int);
@@ -20646,6 +21260,7 @@
     field public static final int DEFAULT = 0; // 0x0
     field public static final int MIC = 1; // 0x1
     field public static final int REMOTE_SUBMIX = 8; // 0x8
+    field public static final int UNPROCESSED = 9; // 0x9
     field public static final int VOICE_CALL = 4; // 0x4
     field public static final int VOICE_COMMUNICATION = 7; // 0x7
     field public static final int VOICE_DOWNLINK = 3; // 0x3
@@ -20676,6 +21291,7 @@
     field public static final int DEFAULT = 0; // 0x0
     field public static final int H263 = 1; // 0x1
     field public static final int H264 = 2; // 0x2
+    field public static final int HEVC = 5; // 0x5
     field public static final int MPEG_4_SP = 3; // 0x3
     field public static final int VP8 = 4; // 0x4
   }
@@ -21564,7 +22180,11 @@
     method public android.media.session.MediaSession.Token getSessionToken();
     method public boolean isConnected();
     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);
+    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";
   }
 
   public static class MediaBrowser.ConnectionCallback {
@@ -21597,7 +22217,9 @@
   public static abstract class MediaBrowser.SubscriptionCallback {
     ctor public MediaBrowser.SubscriptionCallback();
     method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>);
+    method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>, android.os.Bundle);
     method public void onError(java.lang.String);
+    method public void onError(java.lang.String, android.os.Bundle);
   }
 
 }
@@ -21883,6 +22505,7 @@
     method public void setRatingType(int);
     method public void setSessionActivity(android.app.PendingIntent);
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+    field public static final int FLAG_HANDLES_PREPARE_ONLY = 4; // 0x4
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
   }
 
@@ -21961,6 +22584,7 @@
     field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
     field public static final long ACTION_STOP = 1L; // 0x1L
     field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR;
+    field public static final java.lang.String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
     field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
     field public static final int STATE_BUFFERING = 6; // 0x6
     field public static final int STATE_CONNECTING = 8; // 0x8
@@ -22035,6 +22659,7 @@
     method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri);
     method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
     method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
+    method public static final android.net.Uri buildRecordedProgramUri(long);
     field public static final java.lang.String AUTHORITY = "android.media.tv";
   }
 
@@ -22171,13 +22796,49 @@
     field public static final java.lang.String TRAVEL = "TRAVEL";
   }
 
+  public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseTvColumns {
+    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
+    field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
+    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_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";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    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_RECORDING_DATA_BYTES = "recording_data_bytes";
+    field public static final java.lang.String COLUMN_RECORDING_DATA_URI = "recording_data_uri";
+    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_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";
+    field public static final java.lang.String COLUMN_TITLE = "title";
+    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
+    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/recorded_program";
+    field public static final android.net.Uri CONTENT_URI;
+  }
+
   public final class TvInputInfo implements android.os.Parcelable {
+    method public boolean canRecord();
     method public android.content.Intent createSettingsIntent();
     method public android.content.Intent createSetupIntent();
     method public int describeContents();
     method public java.lang.String getId();
     method public java.lang.String getParentId();
     method public android.content.pm.ServiceInfo getServiceInfo();
+    method public int getTunerCount();
     method public int getType();
     method public boolean isPassthroughInput();
     method public android.graphics.drawable.Drawable loadIcon(android.content.Context);
@@ -22197,6 +22858,13 @@
     field public static final int TYPE_VGA = 1005; // 0x3ed
   }
 
+  public static final class TvInputInfo.Builder {
+    ctor public TvInputInfo.Builder(android.content.Context, java.lang.Class<?>);
+    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);
+  }
+
   public final class TvInputManager {
     method public int getInputState(java.lang.String);
     method public android.media.tv.TvInputInfo getTvInputInfo(java.lang.String);
@@ -22212,6 +22880,10 @@
     field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
     field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
     field public static final java.lang.String META_DATA_CONTENT_RATING_SYSTEMS = "android.media.tv.metadata.CONTENT_RATING_SYSTEMS";
+    field public static final int RECORDING_ERROR_CONNECTION_FAILED = 1; // 0x1
+    field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 2; // 0x2
+    field public static final int RECORDING_ERROR_RESOURCE_BUSY = 3; // 0x3
+    field public static final int RECORDING_ERROR_UNKNOWN = 0; // 0x0
     field public static final long TIME_SHIFT_INVALID_TIME = -9223372036854775808L; // 0x8000000000000000L
     field public static final int TIME_SHIFT_STATUS_AVAILABLE = 3; // 0x3
     field public static final int TIME_SHIFT_STATUS_UNAVAILABLE = 2; // 0x2
@@ -22229,12 +22901,15 @@
     method public void onInputAdded(java.lang.String);
     method public void onInputRemoved(java.lang.String);
     method public void onInputStateChanged(java.lang.String, int);
+    method public void onTvInputInfoChanged(android.media.tv.TvInputInfo);
   }
 
   public abstract class TvInputService extends android.app.Service {
     ctor public TvInputService();
     method public final android.os.IBinder onBind(android.content.Intent);
+    method public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(java.lang.String);
     method public abstract android.media.tv.TvInputService.Session onCreateSession(java.lang.String);
+    method public static final void setTvInputInfo(android.content.Context, android.media.tv.TvInputInfo);
     field public static final java.lang.String SERVICE_INTERFACE = "android.media.tv.TvInputService";
     field public static final java.lang.String SERVICE_META_DATA = "android.media.tv.input";
   }
@@ -22247,6 +22922,18 @@
     method public final boolean onSetSurface(android.view.Surface);
   }
 
+  public static abstract class TvInputService.RecordingSession {
+    ctor public TvInputService.RecordingSession(android.content.Context);
+    method public void notifyConnected();
+    method public void notifyError(int);
+    method public void notifyRecordingStarted();
+    method public void notifyRecordingStopped(android.net.Uri);
+    method public abstract void onConnect(android.net.Uri);
+    method public abstract void onDisconnect();
+    method public abstract void onStartRecording();
+    method public abstract void onStopRecording();
+  }
+
   public static abstract class TvInputService.Session implements android.view.KeyEvent.Callback {
     ctor public TvInputService.Session(android.content.Context);
     method public void layoutSurface(int, int, int, int);
@@ -22274,6 +22961,7 @@
     method public long onTimeShiftGetCurrentPosition();
     method public long onTimeShiftGetStartPosition();
     method public void onTimeShiftPause();
+    method public void onTimeShiftPlay(android.net.Uri);
     method public void onTimeShiftResume();
     method public void onTimeShiftSeekTo(long);
     method public void onTimeShiftSetPlaybackParams(android.media.PlaybackParams);
@@ -22284,6 +22972,23 @@
     method public void setOverlayViewEnabled(boolean);
   }
 
+  public class TvRecordingClient {
+    ctor public TvRecordingClient(android.content.Context, java.lang.String, android.media.tv.TvRecordingClient.RecordingCallback, android.os.Handler);
+    method public void connect(java.lang.String, android.net.Uri);
+    method public void disconnect();
+    method public void startRecording();
+    method public void stopRecording();
+  }
+
+  public class TvRecordingClient.RecordingCallback {
+    ctor public TvRecordingClient.RecordingCallback();
+    method public void onConnected();
+    method public void onDisconnected();
+    method public void onError(int);
+    method public void onRecordingStarted();
+    method public void onRecordingStopped(android.net.Uri);
+  }
+
   public final class TvTrackInfo implements android.os.Parcelable {
     method public int describeContents();
     method public final int getAudioChannelCount();
@@ -22335,6 +23040,7 @@
     method public void setStreamVolume(float);
     method public void setTimeShiftPositionCallback(android.media.tv.TvView.TimeShiftPositionCallback);
     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);
@@ -22374,6 +23080,24 @@
     ctor public MtpConstants();
     method public static boolean isAbstractObject(int);
     field public static final int ASSOCIATION_TYPE_GENERIC_FOLDER = 1; // 0x1
+    field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001
+    field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d
+    field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008
+    field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006
+    field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b
+    field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002
+    field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007
+    field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801
+    field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802
+    field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803
+    field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003
+    field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009
+    field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c
+    field public static final int EVENT_STORE_ADDED = 16388; // 0x4004
+    field public static final int EVENT_STORE_FULL = 16394; // 0x400a
+    field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005
+    field public static final int EVENT_UNDEFINED = 16384; // 0x4000
+    field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e
     field public static final int FORMAT_3GP_CONTAINER = 47492; // 0xb984
     field public static final int FORMAT_AAC = 47363; // 0xb903
     field public static final int FORMAT_ABSTRACT_AUDIO_ALBUM = 47619; // 0xba03
@@ -22392,6 +23116,8 @@
     field public static final int FORMAT_AUDIBLE = 47364; // 0xb904
     field public static final int FORMAT_AVI = 12298; // 0x300a
     field public static final int FORMAT_BMP = 14340; // 0x3804
+    field public static final int FORMAT_DEFINED = 14336; // 0x3800
+    field public static final int FORMAT_DNG = 14353; // 0x3811
     field public static final int FORMAT_DPOF = 12294; // 0x3006
     field public static final int FORMAT_EXECUTABLE = 12291; // 0x3003
     field public static final int FORMAT_EXIF_JPEG = 14337; // 0x3801
@@ -22430,6 +23156,42 @@
     field public static final int FORMAT_WMV = 47489; // 0xb981
     field public static final int FORMAT_WPL_PLAYLIST = 47632; // 0xba10
     field public static final int FORMAT_XML_DOCUMENT = 47746; // 0xba82
+    field public static final int OPERATION_CLOSE_SESSION = 4099; // 0x1003
+    field public static final int OPERATION_COPY_OBJECT = 4122; // 0x101a
+    field public static final int OPERATION_DELETE_OBJECT = 4107; // 0x100b
+    field public static final int OPERATION_FORMAT_STORE = 4111; // 0x100f
+    field public static final int OPERATION_GET_DEVICE_INFO = 4097; // 0x1001
+    field public static final int OPERATION_GET_DEVICE_PROP_DESC = 4116; // 0x1014
+    field public static final int OPERATION_GET_DEVICE_PROP_VALUE = 4117; // 0x1015
+    field public static final int OPERATION_GET_NUM_OBJECTS = 4102; // 0x1006
+    field public static final int OPERATION_GET_OBJECT = 4105; // 0x1009
+    field public static final int OPERATION_GET_OBJECT_HANDLES = 4103; // 0x1007
+    field public static final int OPERATION_GET_OBJECT_INFO = 4104; // 0x1008
+    field public static final int OPERATION_GET_OBJECT_PROPS_SUPPORTED = 38913; // 0x9801
+    field public static final int OPERATION_GET_OBJECT_PROP_DESC = 38914; // 0x9802
+    field public static final int OPERATION_GET_OBJECT_PROP_VALUE = 38915; // 0x9803
+    field public static final int OPERATION_GET_OBJECT_REFERENCES = 38928; // 0x9810
+    field public static final int OPERATION_GET_PARTIAL_OBJECT = 4123; // 0x101b
+    field public static final int OPERATION_GET_PARTIAL_OBJECT_64 = 38337; // 0x95c1
+    field public static final int OPERATION_GET_STORAGE_INFO = 4101; // 0x1005
+    field public static final int OPERATION_GET_STORAGE_I_DS = 4100; // 0x1004
+    field public static final int OPERATION_GET_THUMB = 4106; // 0x100a
+    field public static final int OPERATION_INITIATE_CAPTURE = 4110; // 0x100e
+    field public static final int OPERATION_INITIATE_OPEN_CAPTURE = 4124; // 0x101c
+    field public static final int OPERATION_MOVE_OBJECT = 4121; // 0x1019
+    field public static final int OPERATION_OPEN_SESSION = 4098; // 0x1002
+    field public static final int OPERATION_POWER_DOWN = 4115; // 0x1013
+    field public static final int OPERATION_RESET_DEVICE = 4112; // 0x1010
+    field public static final int OPERATION_RESET_DEVICE_PROP_VALUE = 4119; // 0x1017
+    field public static final int OPERATION_SELF_TEST = 4113; // 0x1011
+    field public static final int OPERATION_SEND_OBJECT = 4109; // 0x100d
+    field public static final int OPERATION_SEND_OBJECT_INFO = 4108; // 0x100c
+    field public static final int OPERATION_SET_DEVICE_PROP_VALUE = 4118; // 0x1016
+    field public static final int OPERATION_SET_OBJECT_PROP_VALUE = 38916; // 0x9804
+    field public static final int OPERATION_SET_OBJECT_PROTECTION = 4114; // 0x1012
+    field public static final int OPERATION_SET_OBJECT_REFERENCES = 38929; // 0x9811
+    field public static final int OPERATION_SKIP = 38944; // 0x9820
+    field public static final int OPERATION_TERMINATE_OPEN_CAPTURE = 4120; // 0x1018
     field public static final int PROTECTION_STATUS_NONE = 0; // 0x0
     field public static final int PROTECTION_STATUS_NON_TRANSFERABLE_DATA = 32771; // 0x8003
     field public static final int PROTECTION_STATUS_READ_ONLY = 32769; // 0x8001
@@ -22447,6 +23209,8 @@
     method public int[] getObjectHandles(int, int, int);
     method public android.mtp.MtpObjectInfo getObjectInfo(int);
     method public long getParent(int);
+    method public long getPartialObject(int, long, long, byte[]) throws java.io.IOException;
+    method public long getPartialObject64(int, long, long, byte[]) throws java.io.IOException;
     method public long getStorageId(int);
     method public int[] getStorageIds();
     method public android.mtp.MtpStorageInfo getStorageInfo(int);
@@ -22455,61 +23219,62 @@
     method public boolean importFile(int, android.os.ParcelFileDescriptor);
     method public boolean open(android.hardware.usb.UsbDeviceConnection);
     method public android.mtp.MtpEvent readEvent(android.os.CancellationSignal);
-    method public boolean sendObject(int, int, android.os.ParcelFileDescriptor);
+    method public boolean sendObject(int, long, android.os.ParcelFileDescriptor);
     method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo);
   }
 
   public class MtpDeviceInfo {
+    method public final int[] getEventsSupported();
     method public final java.lang.String getManufacturer();
     method public final java.lang.String getModel();
+    method public final int[] getOperationsSupported();
     method public final java.lang.String getSerialNumber();
     method public final java.lang.String getVersion();
   }
 
   public class MtpEvent {
     ctor public MtpEvent();
+    method public int getDevicePropCode();
     method public int getEventCode();
-    field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001
-    field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d
-    field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008
-    field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006
-    field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b
-    field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002
-    field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007
-    field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801
-    field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802
-    field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803
-    field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003
-    field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009
-    field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c
-    field public static final int EVENT_STORE_ADDED = 16388; // 0x4004
-    field public static final int EVENT_STORE_FULL = 16394; // 0x400a
-    field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005
-    field public static final int EVENT_UNDEFINED = 16384; // 0x4000
-    field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e
+    method public int getObjectFormatCode();
+    method public int getObjectHandle();
+    method public int getObjectPropCode();
+    method public int getParameter1();
+    method public int getParameter2();
+    method public int getParameter3();
+    method public int getStorageId();
+    method public int getTransactionId();
   }
 
   public final class MtpObjectInfo {
     method public final int getAssociationDesc();
     method public final int getAssociationType();
     method public final int getCompressedSize();
+    method public final long getCompressedSizeLong();
     method public final long getDateCreated();
     method public final long getDateModified();
     method public final int getFormat();
     method public final int getImagePixDepth();
+    method public final long getImagePixDepthLong();
     method public final int getImagePixHeight();
+    method public final long getImagePixHeightLong();
     method public final int getImagePixWidth();
+    method public final long getImagePixWidthLong();
     method public final java.lang.String getKeywords();
     method public final java.lang.String getName();
     method public final int getObjectHandle();
     method public final int getParent();
     method public final int getProtectionStatus();
     method public final int getSequenceNumber();
+    method public final long getSequenceNumberLong();
     method public final int getStorageId();
     method public final int getThumbCompressedSize();
+    method public final long getThumbCompressedSizeLong();
     method public final int getThumbFormat();
     method public final int getThumbPixHeight();
+    method public final long getThumbPixHeightLong();
     method public final int getThumbPixWidth();
+    method public final long getThumbPixWidthLong();
   }
 
   public static class MtpObjectInfo.Builder {
@@ -22518,24 +23283,24 @@
     method public android.mtp.MtpObjectInfo build();
     method public android.mtp.MtpObjectInfo.Builder setAssociationDesc(int);
     method public android.mtp.MtpObjectInfo.Builder setAssociationType(int);
-    method public android.mtp.MtpObjectInfo.Builder setCompressedSize(int);
+    method public android.mtp.MtpObjectInfo.Builder setCompressedSize(long);
     method public android.mtp.MtpObjectInfo.Builder setDateCreated(long);
     method public android.mtp.MtpObjectInfo.Builder setDateModified(long);
     method public android.mtp.MtpObjectInfo.Builder setFormat(int);
-    method public android.mtp.MtpObjectInfo.Builder setImagePixDepth(int);
-    method public android.mtp.MtpObjectInfo.Builder setImagePixHeight(int);
-    method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(int);
+    method public android.mtp.MtpObjectInfo.Builder setImagePixDepth(long);
+    method public android.mtp.MtpObjectInfo.Builder setImagePixHeight(long);
+    method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(long);
     method public android.mtp.MtpObjectInfo.Builder setKeywords(java.lang.String);
     method public android.mtp.MtpObjectInfo.Builder setName(java.lang.String);
     method public android.mtp.MtpObjectInfo.Builder setObjectHandle(int);
     method public android.mtp.MtpObjectInfo.Builder setParent(int);
     method public android.mtp.MtpObjectInfo.Builder setProtectionStatus(int);
-    method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(int);
+    method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(long);
     method public android.mtp.MtpObjectInfo.Builder setStorageId(int);
-    method public android.mtp.MtpObjectInfo.Builder setThumbCompressedSize(int);
+    method public android.mtp.MtpObjectInfo.Builder setThumbCompressedSize(long);
     method public android.mtp.MtpObjectInfo.Builder setThumbFormat(int);
-    method public android.mtp.MtpObjectInfo.Builder setThumbPixHeight(int);
-    method public android.mtp.MtpObjectInfo.Builder setThumbPixWidth(int);
+    method public android.mtp.MtpObjectInfo.Builder setThumbPixHeight(long);
+    method public android.mtp.MtpObjectInfo.Builder setThumbPixWidth(long);
   }
 
   public final class MtpStorageInfo {
@@ -22574,6 +23339,7 @@
     method public android.net.NetworkInfo getNetworkInfo(android.net.Network);
     method public deprecated int getNetworkPreference();
     method public static deprecated android.net.Network getProcessDefaultNetwork();
+    method public int getRestrictBackgroundStatus();
     method public boolean isActiveNetworkMetered();
     method public boolean isDefaultNetworkActive();
     method public static deprecated boolean isNetworkTypeValid(int);
@@ -22608,6 +23374,9 @@
     field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity";
     field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
     field public static final java.lang.String EXTRA_REASON = "reason";
+    field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
+    field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
+    field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
     field public static final int TYPE_BLUETOOTH = 7; // 0x7
     field public static final int TYPE_DUMMY = 8; // 0x8
     field public static final int TYPE_ETHERNET = 9; // 0x9
@@ -23647,6 +24416,7 @@
     method public java.lang.String getAltSubjectMatch();
     method public java.lang.String getAnonymousIdentity();
     method public java.security.cert.X509Certificate getCaCertificate();
+    method public java.security.cert.X509Certificate[] getCaCertificates();
     method public java.security.cert.X509Certificate getClientCertificate();
     method public java.lang.String getDomainSuffixMatch();
     method public int getEapMethod();
@@ -23659,6 +24429,7 @@
     method public void setAltSubjectMatch(java.lang.String);
     method public void setAnonymousIdentity(java.lang.String);
     method public void setCaCertificate(java.security.cert.X509Certificate);
+    method public void setCaCertificates(java.security.cert.X509Certificate[]);
     method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
     method public void setDomainSuffixMatch(java.lang.String);
     method public void setEapMethod(int);
@@ -24137,6 +24908,7 @@
 
   public final class Tag implements android.os.Parcelable {
     method public int describeContents();
+    method public boolean done(int);
     method public byte[] getId();
     method public java.lang.String[] getTechList();
     method public void writeToParcel(android.os.Parcel, int);
@@ -24187,6 +24959,28 @@
     field public static final java.lang.String SERVICE_META_DATA = "android.nfc.cardemulation.host_apdu_service";
   }
 
+  public abstract class HostNfcFService extends android.app.Service {
+    ctor public HostNfcFService();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public abstract void onDeactivated(int);
+    method public abstract byte[] processNfcFPacket(byte[], android.os.Bundle);
+    method public final void sendResponsePacket(byte[]);
+    field public static final int DEACTIVATION_LINK_LOSS = 0; // 0x0
+    field public static final java.lang.String SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_NFCF_SERVICE";
+    field public static final java.lang.String SERVICE_META_DATA = "android.nfc.cardemulation.host_nfcf_service";
+  }
+
+  public final class NfcFCardEmulation {
+    method public boolean disableNfcFForegroundService(android.app.Activity);
+    method public boolean enableNfcFForegroundService(android.app.Activity, android.content.ComponentName);
+    method public static synchronized android.nfc.cardemulation.NfcFCardEmulation getInstance(android.nfc.NfcAdapter);
+    method public java.lang.String getNfcid2ForService(android.content.ComponentName);
+    method public java.lang.String getSystemCodeForService(android.content.ComponentName);
+    method public boolean registerSystemCodeForService(android.content.ComponentName, java.lang.String);
+    method public boolean removeSystemCodeForService(android.content.ComponentName);
+    method public boolean setNfcid2ForService(android.content.ComponentName, java.lang.String);
+  }
+
   public abstract class OffHostApduService extends android.app.Service {
     ctor public OffHostApduService();
     method public abstract android.os.IBinder onBind(android.content.Intent);
@@ -26859,12 +27653,285 @@
     method public abstract void onMessage(int, int, int, int, java.lang.String);
   }
 
+  public class GLES32 extends android.opengl.GLES31 {
+    method public static void glBlendBarrier();
+    method public static void glBlendEquationSeparatei(int, int, int);
+    method public static void glBlendEquationi(int, int);
+    method public static void glBlendFuncSeparatei(int, int, int, int, int);
+    method public static void glBlendFunci(int, int, int);
+    method public static void glColorMaski(int, boolean, boolean, boolean, boolean);
+    method public static void glCopyImageSubData(int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
+    method public static void glDebugMessageCallback(android.opengl.GLES32.DebugProc);
+    method public static void glDebugMessageControl(int, int, int, int, int[], int, boolean);
+    method public static void glDebugMessageControl(int, int, int, int, java.nio.IntBuffer, boolean);
+    method public static void glDebugMessageInsert(int, int, int, int, int, java.lang.String);
+    method public static void glDisablei(int, int);
+    method public static void glDrawElementsBaseVertex(int, int, int, java.nio.Buffer, int);
+    method public static void glDrawElementsInstancedBaseVertex(int, int, int, java.nio.Buffer, int, int);
+    method public static void glDrawElementsInstancedBaseVertex(int, int, int, int, int, int);
+    method public static void glDrawRangeElementsBaseVertex(int, int, int, int, int, java.nio.Buffer, int);
+    method public static void glEnablei(int, int);
+    method public static void glFramebufferTexture(int, int, int, int);
+    method public static int glGetDebugMessageLog(int, int, int[], int, int[], int, int[], int, int[], int, int[], int, byte[], int);
+    method public static int glGetDebugMessageLog(int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.ByteBuffer);
+    method public static java.lang.String[] glGetDebugMessageLog(int, int[], int, int[], int, int[], int, int[], int);
+    method public static java.lang.String[] glGetDebugMessageLog(int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer);
+    method public static int glGetGraphicsResetStatus();
+    method public static java.lang.String glGetObjectLabel(int, int);
+    method public static java.lang.String glGetObjectPtrLabel(long);
+    method public static long glGetPointerv(int);
+    method public static void glGetSamplerParameterIiv(int, int, int[], int);
+    method public static void glGetSamplerParameterIiv(int, int, java.nio.IntBuffer);
+    method public static void glGetSamplerParameterIuiv(int, int, int[], int);
+    method public static void glGetSamplerParameterIuiv(int, int, java.nio.IntBuffer);
+    method public static void glGetTexParameterIiv(int, int, int[], int);
+    method public static void glGetTexParameterIiv(int, int, java.nio.IntBuffer);
+    method public static void glGetTexParameterIuiv(int, int, int[], int);
+    method public static void glGetTexParameterIuiv(int, int, java.nio.IntBuffer);
+    method public static void glGetnUniformfv(int, int, int, float[], int);
+    method public static void glGetnUniformfv(int, int, int, java.nio.FloatBuffer);
+    method public static void glGetnUniformiv(int, int, int, int[], int);
+    method public static void glGetnUniformiv(int, int, int, java.nio.IntBuffer);
+    method public static void glGetnUniformuiv(int, int, int, int[], int);
+    method public static void glGetnUniformuiv(int, int, int, java.nio.IntBuffer);
+    method public static boolean glIsEnabledi(int, int);
+    method public static void glMinSampleShading(float);
+    method public static void glObjectLabel(int, int, int, java.lang.String);
+    method public static void glObjectPtrLabel(long, java.lang.String);
+    method public static void glPatchParameteri(int, int);
+    method public static void glPopDebugGroup();
+    method public static void glPrimitiveBoundingBox(float, float, float, float, float, float, float, float);
+    method public static void glPushDebugGroup(int, int, int, java.lang.String);
+    method public static void glReadnPixels(int, int, int, int, int, int, int, java.nio.Buffer);
+    method public static void glSamplerParameterIiv(int, int, int[], int);
+    method public static void glSamplerParameterIiv(int, int, java.nio.IntBuffer);
+    method public static void glSamplerParameterIuiv(int, int, int[], int);
+    method public static void glSamplerParameterIuiv(int, int, java.nio.IntBuffer);
+    method public static void glTexBuffer(int, int, int);
+    method public static void glTexBufferRange(int, int, int, int, int);
+    method public static void glTexParameterIiv(int, int, int[], int);
+    method public static void glTexParameterIiv(int, int, java.nio.IntBuffer);
+    method public static void glTexParameterIuiv(int, int, int[], int);
+    method public static void glTexParameterIuiv(int, int, java.nio.IntBuffer);
+    method public static void glTexStorage3DMultisample(int, int, int, int, int, int, boolean);
+    field public static final int GL_BUFFER = 33504; // 0x82e0
+    field public static final int GL_CLAMP_TO_BORDER = 33069; // 0x812d
+    field public static final int GL_COLORBURN = 37530; // 0x929a
+    field public static final int GL_COLORDODGE = 37529; // 0x9299
+    field public static final int GL_COMPRESSED_RGBA_ASTC_10x10 = 37819; // 0x93bb
+    field public static final int GL_COMPRESSED_RGBA_ASTC_10x5 = 37816; // 0x93b8
+    field public static final int GL_COMPRESSED_RGBA_ASTC_10x6 = 37817; // 0x93b9
+    field public static final int GL_COMPRESSED_RGBA_ASTC_10x8 = 37818; // 0x93ba
+    field public static final int GL_COMPRESSED_RGBA_ASTC_12x10 = 37820; // 0x93bc
+    field public static final int GL_COMPRESSED_RGBA_ASTC_12x12 = 37821; // 0x93bd
+    field public static final int GL_COMPRESSED_RGBA_ASTC_4x4 = 37808; // 0x93b0
+    field public static final int GL_COMPRESSED_RGBA_ASTC_5x4 = 37809; // 0x93b1
+    field public static final int GL_COMPRESSED_RGBA_ASTC_5x5 = 37810; // 0x93b2
+    field public static final int GL_COMPRESSED_RGBA_ASTC_6x5 = 37811; // 0x93b3
+    field public static final int GL_COMPRESSED_RGBA_ASTC_6x6 = 37812; // 0x93b4
+    field public static final int GL_COMPRESSED_RGBA_ASTC_8x5 = 37813; // 0x93b5
+    field public static final int GL_COMPRESSED_RGBA_ASTC_8x6 = 37814; // 0x93b6
+    field public static final int GL_COMPRESSED_RGBA_ASTC_8x8 = 37815; // 0x93b7
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10 = 37851; // 0x93db
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5 = 37848; // 0x93d8
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6 = 37849; // 0x93d9
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8 = 37850; // 0x93da
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10 = 37852; // 0x93dc
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12 = 37853; // 0x93dd
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4 = 37840; // 0x93d0
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4 = 37841; // 0x93d1
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5 = 37842; // 0x93d2
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5 = 37843; // 0x93d3
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6 = 37844; // 0x93d4
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5 = 37845; // 0x93d5
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6 = 37846; // 0x93d6
+    field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8 = 37847; // 0x93d7
+    field public static final int GL_CONTEXT_FLAGS = 33310; // 0x821e
+    field public static final int GL_CONTEXT_FLAG_DEBUG_BIT = 2; // 0x2
+    field public static final int GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT = 4; // 0x4
+    field public static final int GL_CONTEXT_LOST = 1287; // 0x507
+    field public static final int GL_DARKEN = 37527; // 0x9297
+    field public static final int GL_DEBUG_CALLBACK_FUNCTION = 33348; // 0x8244
+    field public static final int GL_DEBUG_CALLBACK_USER_PARAM = 33349; // 0x8245
+    field public static final int GL_DEBUG_GROUP_STACK_DEPTH = 33389; // 0x826d
+    field public static final int GL_DEBUG_LOGGED_MESSAGES = 37189; // 0x9145
+    field public static final int GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH = 33347; // 0x8243
+    field public static final int GL_DEBUG_OUTPUT = 37600; // 0x92e0
+    field public static final int GL_DEBUG_OUTPUT_SYNCHRONOUS = 33346; // 0x8242
+    field public static final int GL_DEBUG_SEVERITY_HIGH = 37190; // 0x9146
+    field public static final int GL_DEBUG_SEVERITY_LOW = 37192; // 0x9148
+    field public static final int GL_DEBUG_SEVERITY_MEDIUM = 37191; // 0x9147
+    field public static final int GL_DEBUG_SEVERITY_NOTIFICATION = 33387; // 0x826b
+    field public static final int GL_DEBUG_SOURCE_API = 33350; // 0x8246
+    field public static final int GL_DEBUG_SOURCE_APPLICATION = 33354; // 0x824a
+    field public static final int GL_DEBUG_SOURCE_OTHER = 33355; // 0x824b
+    field public static final int GL_DEBUG_SOURCE_SHADER_COMPILER = 33352; // 0x8248
+    field public static final int GL_DEBUG_SOURCE_THIRD_PARTY = 33353; // 0x8249
+    field public static final int GL_DEBUG_SOURCE_WINDOW_SYSTEM = 33351; // 0x8247
+    field public static final int GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR = 33357; // 0x824d
+    field public static final int GL_DEBUG_TYPE_ERROR = 33356; // 0x824c
+    field public static final int GL_DEBUG_TYPE_MARKER = 33384; // 0x8268
+    field public static final int GL_DEBUG_TYPE_OTHER = 33361; // 0x8251
+    field public static final int GL_DEBUG_TYPE_PERFORMANCE = 33360; // 0x8250
+    field public static final int GL_DEBUG_TYPE_POP_GROUP = 33386; // 0x826a
+    field public static final int GL_DEBUG_TYPE_PORTABILITY = 33359; // 0x824f
+    field public static final int GL_DEBUG_TYPE_PUSH_GROUP = 33385; // 0x8269
+    field public static final int GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR = 33358; // 0x824e
+    field public static final int GL_DIFFERENCE = 37534; // 0x929e
+    field public static final int GL_EXCLUSION = 37536; // 0x92a0
+    field public static final int GL_FIRST_VERTEX_CONVENTION = 36429; // 0x8e4d
+    field public static final int GL_FRACTIONAL_EVEN = 36476; // 0x8e7c
+    field public static final int GL_FRACTIONAL_ODD = 36475; // 0x8e7b
+    field public static final int GL_FRAGMENT_INTERPOLATION_OFFSET_BITS = 36445; // 0x8e5d
+    field public static final int GL_FRAMEBUFFER_ATTACHMENT_LAYERED = 36263; // 0x8da7
+    field public static final int GL_FRAMEBUFFER_DEFAULT_LAYERS = 37650; // 0x9312
+    field public static final int GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS = 36264; // 0x8da8
+    field public static final int GL_GEOMETRY_INPUT_TYPE = 35095; // 0x8917
+    field public static final int GL_GEOMETRY_OUTPUT_TYPE = 35096; // 0x8918
+    field public static final int GL_GEOMETRY_SHADER = 36313; // 0x8dd9
+    field public static final int GL_GEOMETRY_SHADER_BIT = 4; // 0x4
+    field public static final int GL_GEOMETRY_SHADER_INVOCATIONS = 34943; // 0x887f
+    field public static final int GL_GEOMETRY_VERTICES_OUT = 35094; // 0x8916
+    field public static final int GL_GUILTY_CONTEXT_RESET = 33363; // 0x8253
+    field public static final int GL_HARDLIGHT = 37531; // 0x929b
+    field public static final int GL_HSL_COLOR = 37551; // 0x92af
+    field public static final int GL_HSL_HUE = 37549; // 0x92ad
+    field public static final int GL_HSL_LUMINOSITY = 37552; // 0x92b0
+    field public static final int GL_HSL_SATURATION = 37550; // 0x92ae
+    field public static final int GL_IMAGE_BUFFER = 36945; // 0x9051
+    field public static final int GL_IMAGE_CUBE_MAP_ARRAY = 36948; // 0x9054
+    field public static final int GL_INNOCENT_CONTEXT_RESET = 33364; // 0x8254
+    field public static final int GL_INT_IMAGE_BUFFER = 36956; // 0x905c
+    field public static final int GL_INT_IMAGE_CUBE_MAP_ARRAY = 36959; // 0x905f
+    field public static final int GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 37132; // 0x910c
+    field public static final int GL_INT_SAMPLER_BUFFER = 36304; // 0x8dd0
+    field public static final int GL_INT_SAMPLER_CUBE_MAP_ARRAY = 36878; // 0x900e
+    field public static final int GL_ISOLINES = 36474; // 0x8e7a
+    field public static final int GL_IS_PER_PATCH = 37607; // 0x92e7
+    field public static final int GL_LAST_VERTEX_CONVENTION = 36430; // 0x8e4e
+    field public static final int GL_LAYER_PROVOKING_VERTEX = 33374; // 0x825e
+    field public static final int GL_LIGHTEN = 37528; // 0x9298
+    field public static final int GL_LINES_ADJACENCY = 10; // 0xa
+    field public static final int GL_LINE_STRIP_ADJACENCY = 11; // 0xb
+    field public static final int GL_LOSE_CONTEXT_ON_RESET = 33362; // 0x8252
+    field public static final int GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS = 35378; // 0x8a32
+    field public static final int GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS = 36382; // 0x8e1e
+    field public static final int GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS = 36383; // 0x8e1f
+    field public static final int GL_MAX_DEBUG_GROUP_STACK_DEPTH = 33388; // 0x826c
+    field public static final int GL_MAX_DEBUG_LOGGED_MESSAGES = 37188; // 0x9144
+    field public static final int GL_MAX_DEBUG_MESSAGE_LENGTH = 37187; // 0x9143
+    field public static final int GL_MAX_FRAGMENT_INTERPOLATION_OFFSET = 36444; // 0x8e5c
+    field public static final int GL_MAX_FRAMEBUFFER_LAYERS = 37655; // 0x9317
+    field public static final int GL_MAX_GEOMETRY_ATOMIC_COUNTERS = 37589; // 0x92d5
+    field public static final int GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS = 37583; // 0x92cf
+    field public static final int GL_MAX_GEOMETRY_IMAGE_UNIFORMS = 37069; // 0x90cd
+    field public static final int GL_MAX_GEOMETRY_INPUT_COMPONENTS = 37155; // 0x9123
+    field public static final int GL_MAX_GEOMETRY_OUTPUT_COMPONENTS = 37156; // 0x9124
+    field public static final int GL_MAX_GEOMETRY_OUTPUT_VERTICES = 36320; // 0x8de0
+    field public static final int GL_MAX_GEOMETRY_SHADER_INVOCATIONS = 36442; // 0x8e5a
+    field public static final int GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS = 37079; // 0x90d7
+    field public static final int GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS = 35881; // 0x8c29
+    field public static final int GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = 36321; // 0x8de1
+    field public static final int GL_MAX_GEOMETRY_UNIFORM_BLOCKS = 35372; // 0x8a2c
+    field public static final int GL_MAX_GEOMETRY_UNIFORM_COMPONENTS = 36319; // 0x8ddf
+    field public static final int GL_MAX_LABEL_LENGTH = 33512; // 0x82e8
+    field public static final int GL_MAX_PATCH_VERTICES = 36477; // 0x8e7d
+    field public static final int GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS = 37587; // 0x92d3
+    field public static final int GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS = 37581; // 0x92cd
+    field public static final int GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS = 37067; // 0x90cb
+    field public static final int GL_MAX_TESS_CONTROL_INPUT_COMPONENTS = 34924; // 0x886c
+    field public static final int GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS = 36483; // 0x8e83
+    field public static final int GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS = 37080; // 0x90d8
+    field public static final int GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS = 36481; // 0x8e81
+    field public static final int GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS = 36485; // 0x8e85
+    field public static final int GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS = 36489; // 0x8e89
+    field public static final int GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS = 36479; // 0x8e7f
+    field public static final int GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS = 37588; // 0x92d4
+    field public static final int GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS = 37582; // 0x92ce
+    field public static final int GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS = 37068; // 0x90cc
+    field public static final int GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS = 34925; // 0x886d
+    field public static final int GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS = 36486; // 0x8e86
+    field public static final int GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS = 37081; // 0x90d9
+    field public static final int GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS = 36482; // 0x8e82
+    field public static final int GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS = 36490; // 0x8e8a
+    field public static final int GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS = 36480; // 0x8e80
+    field public static final int GL_MAX_TESS_GEN_LEVEL = 36478; // 0x8e7e
+    field public static final int GL_MAX_TESS_PATCH_COMPONENTS = 36484; // 0x8e84
+    field public static final int GL_MAX_TEXTURE_BUFFER_SIZE = 35883; // 0x8c2b
+    field public static final int GL_MIN_FRAGMENT_INTERPOLATION_OFFSET = 36443; // 0x8e5b
+    field public static final int GL_MIN_SAMPLE_SHADING_VALUE = 35895; // 0x8c37
+    field public static final int GL_MULTIPLY = 37524; // 0x9294
+    field public static final int GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY = 37762; // 0x9382
+    field public static final int GL_MULTISAMPLE_LINE_WIDTH_RANGE = 37761; // 0x9381
+    field public static final int GL_NO_RESET_NOTIFICATION = 33377; // 0x8261
+    field public static final int GL_OVERLAY = 37526; // 0x9296
+    field public static final int GL_PATCHES = 14; // 0xe
+    field public static final int GL_PATCH_VERTICES = 36466; // 0x8e72
+    field public static final int GL_PRIMITIVES_GENERATED = 35975; // 0x8c87
+    field public static final int GL_PRIMITIVE_BOUNDING_BOX = 37566; // 0x92be
+    field public static final int GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED = 33313; // 0x8221
+    field public static final int GL_PROGRAM = 33506; // 0x82e2
+    field public static final int GL_PROGRAM_PIPELINE = 33508; // 0x82e4
+    field public static final int GL_QUADS = 7; // 0x7
+    field public static final int GL_QUERY = 33507; // 0x82e3
+    field public static final int GL_REFERENCED_BY_GEOMETRY_SHADER = 37641; // 0x9309
+    field public static final int GL_REFERENCED_BY_TESS_CONTROL_SHADER = 37639; // 0x9307
+    field public static final int GL_REFERENCED_BY_TESS_EVALUATION_SHADER = 37640; // 0x9308
+    field public static final int GL_RESET_NOTIFICATION_STRATEGY = 33366; // 0x8256
+    field public static final int GL_SAMPLER = 33510; // 0x82e6
+    field public static final int GL_SAMPLER_2D_MULTISAMPLE_ARRAY = 37131; // 0x910b
+    field public static final int GL_SAMPLER_BUFFER = 36290; // 0x8dc2
+    field public static final int GL_SAMPLER_CUBE_MAP_ARRAY = 36876; // 0x900c
+    field public static final int GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW = 36877; // 0x900d
+    field public static final int GL_SAMPLE_SHADING = 35894; // 0x8c36
+    field public static final int GL_SCREEN = 37525; // 0x9295
+    field public static final int GL_SHADER = 33505; // 0x82e1
+    field public static final int GL_SOFTLIGHT = 37532; // 0x929c
+    field public static final int GL_STACK_OVERFLOW = 1283; // 0x503
+    field public static final int GL_STACK_UNDERFLOW = 1284; // 0x504
+    field public static final int GL_TESS_CONTROL_OUTPUT_VERTICES = 36469; // 0x8e75
+    field public static final int GL_TESS_CONTROL_SHADER = 36488; // 0x8e88
+    field public static final int GL_TESS_CONTROL_SHADER_BIT = 8; // 0x8
+    field public static final int GL_TESS_EVALUATION_SHADER = 36487; // 0x8e87
+    field public static final int GL_TESS_EVALUATION_SHADER_BIT = 16; // 0x10
+    field public static final int GL_TESS_GEN_MODE = 36470; // 0x8e76
+    field public static final int GL_TESS_GEN_POINT_MODE = 36473; // 0x8e79
+    field public static final int GL_TESS_GEN_SPACING = 36471; // 0x8e77
+    field public static final int GL_TESS_GEN_VERTEX_ORDER = 36472; // 0x8e78
+    field public static final int GL_TEXTURE_2D_MULTISAMPLE_ARRAY = 37122; // 0x9102
+    field public static final int GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY = 37125; // 0x9105
+    field public static final int GL_TEXTURE_BINDING_BUFFER = 35884; // 0x8c2c
+    field public static final int GL_TEXTURE_BINDING_CUBE_MAP_ARRAY = 36874; // 0x900a
+    field public static final int GL_TEXTURE_BORDER_COLOR = 4100; // 0x1004
+    field public static final int GL_TEXTURE_BUFFER = 35882; // 0x8c2a
+    field public static final int GL_TEXTURE_BUFFER_BINDING = 35882; // 0x8c2a
+    field public static final int GL_TEXTURE_BUFFER_DATA_STORE_BINDING = 35885; // 0x8c2d
+    field public static final int GL_TEXTURE_BUFFER_OFFSET = 37277; // 0x919d
+    field public static final int GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT = 37279; // 0x919f
+    field public static final int GL_TEXTURE_BUFFER_SIZE = 37278; // 0x919e
+    field public static final int GL_TEXTURE_CUBE_MAP_ARRAY = 36873; // 0x9009
+    field public static final int GL_TRIANGLES_ADJACENCY = 12; // 0xc
+    field public static final int GL_TRIANGLE_STRIP_ADJACENCY = 13; // 0xd
+    field public static final int GL_UNDEFINED_VERTEX = 33376; // 0x8260
+    field public static final int GL_UNKNOWN_CONTEXT_RESET = 33365; // 0x8255
+    field public static final int GL_UNSIGNED_INT_IMAGE_BUFFER = 36967; // 0x9067
+    field public static final int GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY = 36970; // 0x906a
+    field public static final int GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 37133; // 0x910d
+    field public static final int GL_UNSIGNED_INT_SAMPLER_BUFFER = 36312; // 0x8dd8
+    field public static final int GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY = 36879; // 0x900f
+    field public static final int GL_VERTEX_ARRAY = 32884; // 0x8074
+  }
+
+  public static abstract interface GLES32.DebugProc {
+    method public abstract void onMessage(int, int, int, int, java.lang.String);
+  }
+
   public class GLException extends java.lang.RuntimeException {
     ctor public GLException(int);
     ctor public GLException(int, java.lang.String);
   }
 
-  public class GLSurfaceView extends android.view.SurfaceView implements android.view.SurfaceHolder.Callback {
+  public class GLSurfaceView extends android.view.SurfaceView implements android.view.SurfaceHolder.Callback2 {
     ctor public GLSurfaceView(android.content.Context);
     ctor public GLSurfaceView(android.content.Context, android.util.AttributeSet);
     method public int getDebugFlags();
@@ -26888,6 +27955,7 @@
     method public void surfaceChanged(android.view.SurfaceHolder, int, int, int);
     method public void surfaceCreated(android.view.SurfaceHolder);
     method public void surfaceDestroyed(android.view.SurfaceHolder);
+    method public void surfaceRedrawNeeded(android.view.SurfaceHolder);
     field public static final int DEBUG_CHECK_GL_ERROR = 1; // 0x1
     field public static final int DEBUG_LOG_GL_CALLS = 2; // 0x2
     field public static final int RENDERMODE_CONTINUOUSLY = 1; // 0x1
@@ -27269,6 +28337,14 @@
     method public final synchronized android.os.CountDownTimer start();
   }
 
+  public final class CpuUsageInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getActive();
+    method public long getTotal();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.os.CpuUsageInfo> CREATOR;
+  }
+
   public class DeadObjectException extends android.os.RemoteException {
     ctor public DeadObjectException();
     ctor public DeadObjectException(java.lang.String);
@@ -27521,6 +28597,18 @@
     method public boolean quitSafely();
   }
 
+  public class HardwarePropertiesManager {
+    method public android.os.CpuUsageInfo[] getCpuUsages();
+    method public float[] getDeviceTemperatures(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 {
+  }
+
   public abstract interface IBinder {
     method public abstract void dump(java.io.FileDescriptor, java.lang.String[]) throws android.os.RemoteException;
     method public abstract void dumpAsync(java.io.FileDescriptor, java.lang.String[]) throws android.os.RemoteException;
@@ -27890,6 +28978,7 @@
     field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
     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
   }
 
   public final class PowerManager.WakeLock {
@@ -28088,6 +29177,7 @@
   public final class UserHandle implements android.os.Parcelable {
     ctor public UserHandle(android.os.Parcel);
     method public int describeContents();
+    method public static int getAppId(int);
     method public static android.os.UserHandle readFromParcel(android.os.Parcel);
     method public void writeToParcel(android.os.Parcel, int);
     method public static void writeToParcel(android.os.UserHandle, android.os.Parcel);
@@ -28095,6 +29185,7 @@
   }
 
   public class UserManager {
+    method public static android.content.Intent createUserCreationIntent(java.lang.String, java.lang.String, java.lang.String, android.os.PersistableBundle);
     method public android.os.Bundle getApplicationRestrictions(java.lang.String);
     method public long getSerialNumberForUser(android.os.UserHandle);
     method public int getUserCount();
@@ -28133,6 +29224,7 @@
     field public static final java.lang.String DISALLOW_CONFIG_WIFI = "no_config_wifi";
     field public static final java.lang.String DISALLOW_CREATE_WINDOWS = "no_create_windows";
     field public static final java.lang.String DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste";
+    field public static final java.lang.String DISALLOW_DATA_ROAMING = "no_data_roaming";
     field public static final java.lang.String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features";
     field public static final java.lang.String DISALLOW_FACTORY_RESET = "no_factory_reset";
     field public static final java.lang.String DISALLOW_FUN = "no_fun";
@@ -28145,6 +29237,7 @@
     field public static final java.lang.String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls";
     field public static final java.lang.String DISALLOW_REMOVE_USER = "no_remove_user";
     field public static final java.lang.String DISALLOW_SAFE_BOOT = "no_safe_boot";
+    field public static final java.lang.String DISALLOW_SET_USER_ICON = "no_set_user_icon";
     field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location";
     field public static final java.lang.String DISALLOW_SMS = "no_sms";
     field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
@@ -28152,6 +29245,8 @@
     field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
     field public static final java.lang.String ENSURE_VERIFY_APPS = "ensure_verify_apps";
     field public static final java.lang.String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
+    field public static final int USER_CREATION_FAILED_NOT_PERMITTED = 1; // 0x1
+    field public static final int USER_CREATION_FAILED_NO_MORE_USERS = 2; // 0x2
   }
 
   public abstract class Vibrator {
@@ -28509,6 +29604,8 @@
     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();
     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";
   }
@@ -28867,6 +29964,7 @@
     method public android.print.PrinterId getId();
     method public java.lang.String getName();
     method public int getStatus();
+    method public android.graphics.drawable.Drawable loadIcon(android.content.Context);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.print.PrinterInfo> CREATOR;
     field public static final int STATUS_BUSY = 2; // 0x2
@@ -28880,6 +29978,9 @@
     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 setIconResourceId(int);
+    method public android.print.PrinterInfo.Builder setInfoIntent(android.app.PendingIntent);
     method public android.print.PrinterInfo.Builder setName(java.lang.String);
     method public android.print.PrinterInfo.Builder setStatus(int);
   }
@@ -28900,6 +30001,10 @@
 
 package android.printservice {
 
+  public class CustomPrinterIconCallback {
+    method public boolean onCustomPrinterIconLoaded(android.graphics.drawable.Icon);
+  }
+
   public final class PrintDocument {
     method public android.os.ParcelFileDescriptor getData();
     method public android.print.PrintDocumentInfo getInfo();
@@ -28955,6 +30060,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 abstract void onStartPrinterDiscovery(java.util.List<android.print.PrinterId>);
     method public abstract void onStartPrinterStateTracking(android.print.PrinterId);
     method public abstract void onStopPrinterDiscovery();
@@ -28997,6 +30103,22 @@
     field public static final java.lang.String _ID = "_id";
   }
 
+  public class BlockedNumberContract {
+    method public static boolean isBlocked(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;
+  }
+
+  public static class BlockedNumberContract.BlockedNumbers {
+    field public static final java.lang.String COLUMN_E164_NUMBER = "e164_number";
+    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 COLUMN_STRIPPED_NUMBER = "stripped_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 android.net.Uri CONTENT_URI;
+  }
+
   public class Browser {
     ctor public Browser();
     method public static final void sendString(android.content.Context, java.lang.String);
@@ -29323,6 +30445,7 @@
     field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location";
     field public static final int INCOMING_TYPE = 1; // 0x1
     field public static final java.lang.String IS_READ = "is_read";
+    field public static final java.lang.String LAST_MODIFIED = "last_modified";
     field public static final java.lang.String LIMIT_PARAM_KEY = "limit";
     field public static final int MISSED_TYPE = 3; // 0x3
     field public static final java.lang.String NEW = "new";
@@ -30218,10 +31341,14 @@
 
   public static final class ContactsContract.Intents {
     ctor public ContactsContract.Intents();
+    field public static final java.lang.String ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS = "android.provider.action.VOICE_SEND_MESSAGE_TO_CONTACTS";
     field public static final java.lang.String ATTACH_IMAGE = "com.android.contacts.action.ATTACH_IMAGE";
     field public static final java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
     field public static final java.lang.String EXTRA_CREATE_DESCRIPTION = "com.android.contacts.action.CREATE_DESCRIPTION";
     field public static final java.lang.String EXTRA_FORCE_CREATE = "com.android.contacts.action.FORCE_CREATE";
+    field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_CHAT_ID = "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
+    field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_NAME = "android.provider.extra.RECIPIENT_CONTACT_NAME";
+    field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_URI = "android.provider.extra.RECIPIENT_CONTACT_URI";
     field public static final java.lang.String INVITE_CONTACT = "com.android.contacts.action.INVITE_CONTACT";
     field public static final java.lang.String SEARCH_SUGGESTION_CLICKED = "android.provider.Contacts.SEARCH_SUGGESTION_CLICKED";
     field public static final java.lang.String SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED = "android.provider.Contacts.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED";
@@ -30467,6 +31594,7 @@
     method public static android.net.Uri buildRootsUri(java.lang.String);
     method public static android.net.Uri buildSearchDocumentsUri(java.lang.String, java.lang.String, java.lang.String);
     method public static android.net.Uri buildTreeDocumentUri(java.lang.String, java.lang.String);
+    method public static android.net.Uri copyDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri);
     method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);
     method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri);
     method public static java.lang.String getDocumentId(android.net.Uri);
@@ -30475,6 +31603,9 @@
     method public static java.lang.String getSearchDocumentsQuery(android.net.Uri);
     method public static java.lang.String getTreeDocumentId(android.net.Uri);
     method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
+    method public static boolean isTreeUri(android.net.Uri);
+    method public static android.net.Uri moveDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri, android.net.Uri);
+    method public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri);
     method public static android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String);
     field public static final java.lang.String EXTRA_ERROR = "error";
     field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
@@ -30493,18 +31624,18 @@
     field public static final java.lang.String COLUMN_MIME_TYPE = "mime_type";
     field public static final java.lang.String COLUMN_SIZE = "_size";
     field public static final java.lang.String COLUMN_SUMMARY = "summary";
-    field public static final int FLAG_ARCHIVE = 2048; // 0x800
+    field public static final int FLAG_ARCHIVE = 1024; // 0x400
     field public static final int FLAG_DIR_PREFERS_GRID = 16; // 0x10
     field public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 32; // 0x20
     field public static final int FLAG_DIR_SUPPORTS_CREATE = 8; // 0x8
     field public static final int FLAG_SUPPORTS_COPY = 128; // 0x80
     field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4
     field public static final int FLAG_SUPPORTS_MOVE = 256; // 0x100
+    field public static final int FLAG_SUPPORTS_REMOVE = 2048; // 0x800
     field public static final int FLAG_SUPPORTS_RENAME = 64; // 0x40
     field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
-    field public static final int FLAG_SUPPORTS_TYPED_DOCUMENT = 512; // 0x200
     field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
-    field public static final int FLAG_VIRTUAL_DOCUMENT = 1024; // 0x400
+    field public static final int FLAG_VIRTUAL_DOCUMENT = 512; // 0x200
     field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory";
   }
 
@@ -30548,6 +31679,7 @@
     method public android.database.Cursor queryRecentDocuments(java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
     method public abstract android.database.Cursor queryRoots(java.lang.String[]) throws java.io.FileNotFoundException;
     method public android.database.Cursor querySearchDocuments(java.lang.String, java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
+    method public boolean removeDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public java.lang.String renameDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public final void revokeDocumentPermission(java.lang.String);
     method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
@@ -30927,10 +32059,12 @@
     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";
     field public static final java.lang.String ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS";
+    field public static final java.lang.String ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS";
     field public static final java.lang.String ACTION_MANAGE_OVERLAY_PERMISSION = "android.settings.action.MANAGE_OVERLAY_PERMISSION";
     field public static final java.lang.String ACTION_MANAGE_WRITE_SETTINGS = "android.settings.action.MANAGE_WRITE_SETTINGS";
     field public static final java.lang.String ACTION_MEMORY_CARD_SETTINGS = "android.settings.MEMORY_CARD_SETTINGS";
@@ -30947,6 +32081,7 @@
     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";
+    field public static final java.lang.String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
     field public static final java.lang.String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
     field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
     field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
@@ -30993,6 +32128,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 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";
     field public static final java.lang.String DEBUG_APP = "debug_app";
@@ -31101,6 +32237,7 @@
     field public static final deprecated java.lang.String TTS_USE_DEFAULTS = "tts_use_defaults";
     field public static final deprecated java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
     field public static final deprecated java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
+    field public static final java.lang.String VOICE_INTERACTION_SERVICE = "voice_interaction_service";
     field public static final deprecated java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
     field public static final deprecated java.lang.String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms";
     field public static final deprecated java.lang.String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = "wifi_networks_available_notification_on";
@@ -31484,6 +32621,7 @@
     field public static final int RESULT_SMS_OUT_OF_MEMORY = 3; // 0x3
     field public static final int RESULT_SMS_UNSUPPORTED = 4; // 0x4
     field public static final java.lang.String SIM_FULL_ACTION = "android.provider.Telephony.SIM_FULL";
+    field public static final java.lang.String SMS_CARRIER_PROVISION_ACTION = "android.provider.Telephony.SMS_CARRIER_PROVISION";
     field public static final java.lang.String SMS_CB_RECEIVED_ACTION = "android.provider.Telephony.SMS_CB_RECEIVED";
     field public static final java.lang.String SMS_DELIVER_ACTION = "android.provider.Telephony.SMS_DELIVER";
     field public static final java.lang.String SMS_EMERGENCY_CB_RECEIVED_ACTION = "android.provider.Telephony.SMS_EMERGENCY_CB_RECEIVED";
@@ -31585,6 +32723,7 @@
   public class VoicemailContract {
     field public static final java.lang.String ACTION_FETCH_VOICEMAIL = "android.intent.action.FETCH_VOICEMAIL";
     field public static final java.lang.String ACTION_NEW_VOICEMAIL = "android.intent.action.NEW_VOICEMAIL";
+    field public static final java.lang.String ACTION_SYNC_VOICEMAIL = "android.intent.action.SYNC_VOICEMAIL";
     field public static final java.lang.String AUTHORITY = "com.android.voicemail";
     field public static final java.lang.String EXTRA_SELF_CHANGE = "com.android.voicemail.extra.SELF_CHANGE";
     field public static final java.lang.String PARAM_KEY_SOURCE_PACKAGE = "source_package";
@@ -31592,14 +32731,20 @@
 
   public static final class VoicemailContract.Status implements android.provider.BaseColumns {
     method public static android.net.Uri buildSourceUri(java.lang.String);
+    method public static void setQuota(android.content.Context, android.telecom.PhoneAccountHandle, int, int);
     field public static final java.lang.String CONFIGURATION_STATE = "configuration_state";
     field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2
     field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1
     field public static final int CONFIGURATION_STATE_OK = 0; // 0x0
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String DATA_CHANNEL_STATE = "data_channel_state";
+    field public static final int DATA_CHANNEL_STATE_BAD_CONFIGURATION = 3; // 0x3
+    field public static final int DATA_CHANNEL_STATE_COMMUNICATION_ERROR = 4; // 0x4
     field public static final int DATA_CHANNEL_STATE_NO_CONNECTION = 1; // 0x1
+    field public static final int DATA_CHANNEL_STATE_NO_CONNECTION_CELLULAR_REQUIRED = 2; // 0x2
     field public static final int DATA_CHANNEL_STATE_OK = 0; // 0x0
+    field public static final int DATA_CHANNEL_STATE_SERVER_CONNECTION_ERROR = 6; // 0x6
+    field public static final int DATA_CHANNEL_STATE_SERVER_ERROR = 5; // 0x5
     field public static final java.lang.String DIR_TYPE = "vnd.android.cursor.dir/voicemail.source.status";
     field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail.source.status";
     field public static final java.lang.String NOTIFICATION_CHANNEL_STATE = "notification_channel_state";
@@ -31608,6 +32753,9 @@
     field public static final int NOTIFICATION_CHANNEL_STATE_OK = 0; // 0x0
     field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "phone_account_component_name";
     field public static final java.lang.String PHONE_ACCOUNT_ID = "phone_account_id";
+    field public static final java.lang.String QUOTA_OCCUPIED = "quota_occupied";
+    field public static final java.lang.String QUOTA_TOTAL = "quota_total";
+    field public static final int QUOTA_UNAVAILABLE = -1; // 0xffffffff
     field public static final java.lang.String SETTINGS_URI = "settings_uri";
     field public static final java.lang.String SOURCE_PACKAGE = "source_package";
     field public static final java.lang.String VOICEMAIL_ACCESS_URI = "voicemail_access_uri";
@@ -31624,6 +32772,7 @@
     field public static final java.lang.String HAS_CONTENT = "has_content";
     field public static final java.lang.String IS_READ = "is_read";
     field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail";
+    field public static final java.lang.String LAST_MODIFIED = "last_modified";
     field public static final java.lang.String MIME_TYPE = "mime_type";
     field public static final java.lang.String NUMBER = "number";
     field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
@@ -31693,6 +32842,7 @@
     method public void copyTo(short[]);
     method public void copyTo(int[]);
     method public void copyTo(float[]);
+    method public static android.renderscript.Allocation[] createAllocations(android.renderscript.RenderScript, android.renderscript.Type, int, int);
     method public static android.renderscript.Allocation createCubemapFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap, android.renderscript.Allocation.MipmapControl, int);
     method public static android.renderscript.Allocation createCubemapFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap);
     method public static android.renderscript.Allocation createCubemapFromCubeFaces(android.renderscript.RenderScript, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.renderscript.Allocation.MipmapControl, int);
@@ -31708,9 +32858,12 @@
     method public static android.renderscript.Allocation createTyped(android.renderscript.RenderScript, android.renderscript.Type, int);
     method public static android.renderscript.Allocation createTyped(android.renderscript.RenderScript, android.renderscript.Type);
     method public void generateMipmaps();
+    method public java.nio.ByteBuffer getByteBuffer();
     method public int getBytesSize();
     method public android.renderscript.Element getElement();
+    method public long getStride();
     method public android.view.Surface getSurface();
+    method public long getTimeStamp();
     method public android.renderscript.Type getType();
     method public int getUsage();
     method public void ioReceive();
@@ -32294,6 +33447,7 @@
     method public void getVarV(int, android.renderscript.FieldPacker);
     method protected void invoke(int);
     method protected void invoke(int, android.renderscript.FieldPacker);
+    method protected void reduce(int, android.renderscript.Allocation[], android.renderscript.Allocation, android.renderscript.Script.LaunchOptions);
     method public void setTimeZone(java.lang.String);
     method public void setVar(int, float);
     method public void setVar(int, double);
@@ -32815,6 +33969,7 @@
   public class NetworkSecurityPolicy {
     method public static android.security.NetworkSecurityPolicy getInstance();
     method public boolean isCleartextTrafficPermitted();
+    method public boolean isCleartextTrafficPermitted(java.lang.String);
   }
 
 }
@@ -33109,6 +34264,7 @@
     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();
@@ -33143,9 +34299,11 @@
     method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
     method public android.media.session.MediaSession.Token getSessionToken();
     method public void notifyChildrenChanged(java.lang.String);
+    method public void notifyChildrenChanged(java.lang.String, android.os.Bundle);
     method public android.os.IBinder onBind(android.content.Intent);
     method public abstract android.service.media.MediaBrowserService.BrowserRoot onGetRoot(java.lang.String, int, android.os.Bundle);
     method public abstract void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>);
+    method public void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>, android.os.Bundle);
     method public void onLoadItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>);
     method public void setSessionToken(android.media.session.MediaSession.Token);
     field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
@@ -33203,6 +34361,7 @@
     method public abstract void onUnsubscribe(android.net.Uri);
     field public static final java.lang.String EXTRA_RULE_ID = "android.content.automatic.ruleId";
     field public static final java.lang.String META_DATA_CONFIGURATION_ACTIVITY = "android.service.zen.automatic.configurationActivity";
+    field public static final java.lang.String META_DATA_RULE_INSTANCE_LIMIT = "android.service.zen.automatic.ruleInstanceLimit";
     field public static final java.lang.String META_DATA_RULE_TYPE = "android.service.zen.automatic.ruleType";
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
   }
@@ -33229,7 +34388,10 @@
     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 = 15; // 0xf
+    field public static final int REASON_TOPIC_BANNED = 14; // 0xe
     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 {
@@ -33258,7 +34420,10 @@
     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 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
@@ -33268,6 +34433,7 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
     field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
     field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+    field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
   }
 
   public static class NotificationListenerService.Ranking {
@@ -33324,25 +34490,37 @@
     method public java.lang.CharSequence getContentDescription();
     method public android.graphics.drawable.Icon getIcon();
     method public java.lang.CharSequence getLabel();
+    method public int getState();
     method public void setContentDescription(java.lang.CharSequence);
     method public void setIcon(android.graphics.drawable.Icon);
     method public void setLabel(java.lang.CharSequence);
+    method public void setState(int);
     method public void updateTile();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.quicksettings.Tile> CREATOR;
+    field public static final int STATE_ACTIVE = 2; // 0x2
+    field public static final int STATE_INACTIVE = 1; // 0x1
+    field public static final int STATE_UNAVAILABLE = 0; // 0x0
   }
 
   public class TileService extends android.app.Service {
     ctor public TileService();
     method public final android.service.quicksettings.Tile getQsTile();
+    method public final boolean isLocked();
+    method public final boolean isSecure();
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onClick();
     method public void onStartListening();
     method public void onStopListening();
-    method public void onTileAdded();
+    method public int onTileAdded();
     method public void onTileRemoved();
+    method public static final void requestListeningState(android.content.Context, android.content.ComponentName);
     method public final void showDialog(android.app.Dialog);
+    method public final void startActivityAndCollapse(android.content.Intent);
+    method public final void unlockAndRun(java.lang.Runnable);
     field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+    field public static final int TILE_MODE_ACTIVE = 2; // 0x2
+    field public static final int TILE_MODE_PASSIVE = 1; // 0x1
   }
 
 }
@@ -33474,6 +34652,7 @@
     method public void setTheme(int);
     method public void show(android.os.Bundle, int);
     method public void startVoiceActivity(android.content.Intent);
+    field public static final int SHOW_SOURCE_ACTIVITY = 16; // 0x10
     field public static final int SHOW_SOURCE_APPLICATION = 8; // 0x8
     field public static final int SHOW_SOURCE_ASSIST_GESTURE = 4; // 0x4
     field public static final int SHOW_WITH_ASSIST = 1; // 0x1
@@ -33835,6 +35014,8 @@
 
   public abstract class UtteranceProgressListener {
     ctor public UtteranceProgressListener();
+    method public void onAudioAvailable(java.lang.String, byte[]);
+    method public void onBeginSynthesis(java.lang.String, int, int, int);
     method public abstract void onDone(java.lang.String);
     method public abstract deprecated void onError(java.lang.String);
     method public void onError(java.lang.String, int);
@@ -34582,6 +35763,7 @@
     method public static boolean hasProperty(int, int);
     method public boolean hasProperty(int);
     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_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
     field public static final int CAPABILITY_HOLD = 1; // 0x1
@@ -34603,6 +35785,7 @@
     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_WIFI = 8; // 0x8
+    field public static final int PROPERTY_WORK_CALL = 32; // 0x20
   }
 
   public final class CallAudioState implements android.os.Parcelable {
@@ -34621,6 +35804,30 @@
     field public static final int ROUTE_WIRED_OR_EARPIECE = 5; // 0x5
   }
 
+  public abstract class CallScreeningService extends android.app.Service {
+    ctor public CallScreeningService();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public abstract void onScreenCall(android.telecom.Call.Details);
+    method public final void respondToCall(android.telecom.Call.Details, android.telecom.CallScreeningService.CallResponse);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.CallScreeningService";
+  }
+
+  public static class CallScreeningService.CallResponse {
+    method public boolean getDisallowCall();
+    method public boolean getRejectCall();
+    method public boolean getSkipCallLog();
+    method public boolean getSkipNotification();
+  }
+
+  public static class CallScreeningService.CallResponse.Builder {
+    ctor public CallScreeningService.CallResponse.Builder();
+    method public android.telecom.CallScreeningService.CallResponse build();
+    method public android.telecom.CallScreeningService.CallResponse.Builder setDisallowCall(boolean);
+    method public android.telecom.CallScreeningService.CallResponse.Builder setRejectCall(boolean);
+    method public android.telecom.CallScreeningService.CallResponse.Builder setSkipCallLog(boolean);
+    method public android.telecom.CallScreeningService.CallResponse.Builder setSkipNotification(boolean);
+  }
+
   public abstract class Conference extends android.telecom.Conferenceable {
     ctor public Conference(android.telecom.PhoneAccountHandle);
     method public final boolean addConnection(android.telecom.Connection);
@@ -34721,6 +35928,7 @@
     method public final void setVideoProvider(android.telecom.Connection.VideoProvider);
     method public final void setVideoState(int);
     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_UPGRADE_TO_VIDEO = 524288; // 0x80000
     field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
@@ -34859,6 +36067,7 @@
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
     method public void onCallRemoved(android.telecom.Call);
     method public void onCanAddCallChanged(boolean);
+    method public void onSilenceRinger();
     method public final void setAudioRoute(int);
     method public final void setMuted(boolean);
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.InCallService";
@@ -35100,6 +36309,7 @@
     field public static final java.lang.String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL";
     field public static final java.lang.String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS = "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS";
     field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
+    field public static final java.lang.String ACTION_SHOW_MISSED_CALLS_NOTIFICATION = "android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION";
     field public static final java.lang.String ACTION_SHOW_RESPOND_VIA_SMS_SETTINGS = "android.telecom.action.SHOW_RESPOND_VIA_SMS_SETTINGS";
     field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
     field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
@@ -35110,12 +36320,15 @@
     field public static final java.lang.String EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME = "android.telecom.extra.CHANGE_DEFAULT_DIALER_PACKAGE_NAME";
     field public static final java.lang.String EXTRA_INCOMING_CALL_ADDRESS = "android.telecom.extra.INCOMING_CALL_ADDRESS";
     field public static final java.lang.String EXTRA_INCOMING_CALL_EXTRAS = "android.telecom.extra.INCOMING_CALL_EXTRAS";
+    field public static final java.lang.String EXTRA_NOTIFICATION_COUNT = "android.telecom.extra.NOTIFICATION_COUNT";
+    field public static final java.lang.String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
     field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
     field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
     field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
     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_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
     field public static final int PRESENTATION_PAYPHONE = 4; // 0x4
@@ -35167,12 +36380,24 @@
     method public android.os.PersistableBundle getConfigForSubId(int);
     method public 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_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";
     field public static final java.lang.String KEY_APN_EXPAND_BOOL = "apn_expand_bool";
     field public static final java.lang.String KEY_AUTO_RETRY_ENABLED_BOOL = "auto_retry_enabled_bool";
     field public static final java.lang.String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL = "carrier_allow_turnoff_ims_bool";
+    field public static final java.lang.String KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL = "carrier_force_disable_etws_cmas_test_bool";
+    field public static final java.lang.String KEY_CARRIER_IMS_GBA_REQUIRED_BOOL = "carrier_ims_gba_required_bool";
+    field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL = "carrier_instant_lettering_available_bool";
+    field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_ENCODING_STRING = "carrier_instant_lettering_encoding_string";
+    field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_ESCAPED_CHARS_STRING = "carrier_instant_lettering_escaped_chars_string";
+    field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_INVALID_CHARS_STRING = "carrier_instant_lettering_invalid_chars_string";
+    field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_LENGTH_LIMIT_INT = "carrier_instant_lettering_length_limit_int";
     field public static final java.lang.String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
     field public static final java.lang.String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
@@ -35181,20 +36406,30 @@
     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_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";
+    field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_BOOL = "ci_action_on_sys_update_bool";
+    field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING = "ci_action_on_sys_update_extra_string";
+    field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING = "ci_action_on_sys_update_extra_val_string";
+    field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING = "ci_action_on_sys_update_intent_string";
     field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
     field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
     field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
     field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
+    field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
     field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
     field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
+    field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
     field public static final java.lang.String KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = "gsm_nonroaming_networks_string_array";
     field public static final java.lang.String KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY = "gsm_roaming_networks_string_array";
     field public static final java.lang.String KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL = "has_in_call_noise_suppression_bool";
     field public static final java.lang.String KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool";
+    field public static final java.lang.String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool";
+    field public static final java.lang.String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool";
     field public static final java.lang.String KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool";
     field public static final java.lang.String KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL = "ignore_sim_network_locked_events_bool";
+    field public static final java.lang.String KEY_IMS_DTMF_TONE_DELAY_INT = "ims_dtmf_tone_delay_int";
     field public static final java.lang.String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled";
     field public static final java.lang.String KEY_MMS_ALIAS_MAX_CHARS_INT = "aliasMaxChars";
     field public static final java.lang.String KEY_MMS_ALIAS_MIN_CHARS_INT = "aliasMinChars";
@@ -35228,20 +36463,24 @@
     field public static final java.lang.String KEY_MMS_USER_AGENT_STRING = "userAgent";
     field public static final java.lang.String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool";
     field public static final java.lang.String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
+    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_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";
     field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
     field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
     field public static final java.lang.String KEY_USE_HFA_FOR_PROVISIONING_BOOL = "use_hfa_for_provisioning_bool";
     field public static final java.lang.String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool";
+    field public static final java.lang.String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
     field public static final java.lang.String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool";
     field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
     field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
     field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN = "vvm_cellular_data_required";
     field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
     field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
+    field public static final java.lang.String KEY_VVM_PREFETCH_BOOLEAN = "vvm_prefetch";
     field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
     field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
   }
@@ -35259,6 +36498,8 @@
 
   public final class CellIdentityGsm implements android.os.Parcelable {
     method public int describeContents();
+    method public int getArfcn();
+    method public int getBsic();
     method public int getCid();
     method public int getLac();
     method public int getMcc();
@@ -35271,6 +36512,7 @@
   public final class CellIdentityLte implements android.os.Parcelable {
     method public int describeContents();
     method public int getCi();
+    method public int getEarfcn();
     method public int getMcc();
     method public int getMnc();
     method public int getPci();
@@ -35286,6 +36528,7 @@
     method public int getMcc();
     method public int getMnc();
     method public int getPsc();
+    method public int getUarfcn();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityWcdma> CREATOR;
   }
@@ -35707,10 +36950,15 @@
     method public int getActiveSubscriptionInfoCountMax();
     method public android.telephony.SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int);
     method public java.util.List<android.telephony.SubscriptionInfo> getActiveSubscriptionInfoList();
+    method public static int getDefaultDataSubscriptionId();
+    method public static int getDefaultSmsSubscriptionId();
+    method public static int getDefaultSubscriptionId();
+    method public static int getDefaultVoiceSubscriptionId();
     method public boolean isNetworkRoaming(int);
     method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
     field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
     field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
+    field public static final int INVALID_SUBSCRIPTION_ID = -1; // 0xffffffff
   }
 
   public static class SubscriptionManager.OnSubscriptionsChangedListener {
@@ -35722,31 +36970,50 @@
     method public boolean canChangeDtmfToneLength();
     method public java.util.List<android.telephony.CellInfo> getAllCellInfo();
     method public int getCallState();
+    method public int getCallState(int);
     method public android.telephony.CellLocation getCellLocation();
     method public int getDataActivity();
+    method public int getDataNetworkType(int);
     method public int getDataState();
     method public java.lang.String getDeviceId();
     method public java.lang.String getDeviceId(int);
     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 getLine1AlphaTag(int);
     method public java.lang.String getLine1Number();
+    method public java.lang.String getLine1Number(int);
     method public java.lang.String getMmsUAProfUrl();
     method public java.lang.String getMmsUserAgent();
     method public deprecated java.util.List<android.telephony.NeighboringCellInfo> getNeighboringCellInfo();
     method public java.lang.String getNetworkCountryIso();
+    method public java.lang.String getNetworkCountryIso(int);
     method public java.lang.String getNetworkOperator();
+    method public java.lang.String getNetworkOperator(int);
     method public java.lang.String getNetworkOperatorName();
+    method public java.lang.String getNetworkOperatorName(int);
     method public int getNetworkType();
+    method public int getNetworkType(int);
     method public int getPhoneCount();
     method public int getPhoneType();
     method public java.lang.String getSimCountryIso();
+    method public java.lang.String getSimCountryIso(int);
     method public java.lang.String getSimOperator();
+    method public java.lang.String getSimOperator(int);
     method public java.lang.String getSimOperatorName();
+    method public java.lang.String getSimOperatorName(int);
     method public java.lang.String getSimSerialNumber();
+    method public java.lang.String getSimSerialNumber(int);
     method public int getSimState();
     method public java.lang.String getSubscriberId();
+    method public java.lang.String getSubscriberId(int);
     method public java.lang.String getVoiceMailAlphaTag();
+    method public java.lang.String getVoiceMailAlphaTag(int);
     method public java.lang.String getVoiceMailNumber();
+    method public java.lang.String getVoiceMailNumber(int);
+    method public int getVoiceNetworkType(int);
+    method public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle);
     method public boolean hasCarrierPrivileges();
     method public boolean hasIccCard();
     method public boolean iccCloseLogicalChannel(int);
@@ -35756,16 +37023,20 @@
     method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
     method public boolean isHearingAidCompatibilitySupported();
     method public boolean isNetworkRoaming();
+    method public boolean isNetworkRoaming(int);
     method public boolean isSmsCapable();
     method public boolean isTtyModeSupported();
     method public boolean isVoiceCapable();
+    method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle);
     method public boolean isWorldPhone();
     method public void listen(android.telephony.PhoneStateListener, int);
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
     method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
+    method public boolean setLine1NumberForDisplay(int, java.lang.String, java.lang.String);
     method public boolean setOperatorBrandOverride(java.lang.String);
     method public boolean setPreferredNetworkTypeToGlobal();
     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";
@@ -35935,7 +37206,7 @@
     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public abstract class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
+  public abstract deprecated class ActivityInstrumentationTestCase2 extends android.test.ActivityTestCase {
     ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>);
     ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>);
     method public T getActivity();
@@ -35943,14 +37214,14 @@
     method public void setActivityIntent(android.content.Intent);
   }
 
-  public abstract class ActivityTestCase extends android.test.InstrumentationTestCase {
+  public abstract deprecated class ActivityTestCase extends android.test.InstrumentationTestCase {
     ctor public ActivityTestCase();
     method protected android.app.Activity getActivity();
     method protected void scrubClass(java.lang.Class<?>) throws java.lang.IllegalAccessException;
     method protected void setActivity(android.app.Activity);
   }
 
-  public abstract class ActivityUnitTestCase extends android.test.ActivityTestCase {
+  public abstract deprecated class ActivityUnitTestCase extends android.test.ActivityTestCase {
     ctor public ActivityUnitTestCase(java.lang.Class<T>);
     method public T getActivity();
     method public int getFinishedActivityRequest();
@@ -35963,7 +37234,7 @@
     method protected T startActivity(android.content.Intent, android.os.Bundle, java.lang.Object);
   }
 
-  public class AndroidTestCase extends junit.framework.TestCase {
+  public deprecated class AndroidTestCase extends junit.framework.TestCase {
     ctor public AndroidTestCase();
     method public void assertActivityRequiresPermission(java.lang.String, java.lang.String, java.lang.String);
     method public void assertReadingContentUriRequiresPermission(android.net.Uri, java.lang.String);
@@ -35975,7 +37246,7 @@
     field protected android.content.Context mContext;
   }
 
-  public class AndroidTestRunner extends junit.runner.BaseTestRunner {
+  public deprecated class AndroidTestRunner extends junit.runner.BaseTestRunner {
     ctor public AndroidTestRunner();
     method public void addTestListener(junit.framework.TestListener);
     method public void clearTestListeners();
@@ -35996,7 +37267,7 @@
     method public void testStarted(java.lang.String);
   }
 
-  public abstract class ApplicationTestCase extends android.test.AndroidTestCase {
+  public abstract deprecated class ApplicationTestCase extends android.test.AndroidTestCase {
     ctor public ApplicationTestCase(java.lang.Class<T>);
     method protected final void createApplication();
     method public T getApplication();
@@ -36014,10 +37285,10 @@
     ctor public ComparisonFailure(java.lang.String, java.lang.String, java.lang.String);
   }
 
-  public abstract class FlakyTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class FlakyTest implements java.lang.annotation.Annotation {
   }
 
-  public class InstrumentationTestCase extends junit.framework.TestCase {
+  public deprecated class InstrumentationTestCase extends junit.framework.TestCase {
     ctor public InstrumentationTestCase();
     method public android.app.Instrumentation getInstrumentation();
     method public deprecated void injectInsrumentation(android.app.Instrumentation);
@@ -36030,7 +37301,7 @@
     method public void sendRepeatedKeys(int...);
   }
 
-  public class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider {
+  public deprecated class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider {
     ctor public InstrumentationTestRunner();
     method public junit.framework.TestSuite getAllTests();
     method protected android.test.AndroidTestRunner getAndroidTestRunner();
@@ -36049,14 +37320,14 @@
     field public static final int REPORT_VALUE_RESULT_START = 1; // 0x1
   }
 
-  public class InstrumentationTestSuite extends junit.framework.TestSuite {
+  public deprecated class InstrumentationTestSuite extends junit.framework.TestSuite {
     ctor public InstrumentationTestSuite(android.app.Instrumentation);
     ctor public InstrumentationTestSuite(java.lang.String, android.app.Instrumentation);
     ctor public InstrumentationTestSuite(java.lang.Class, android.app.Instrumentation);
     method public void addTestSuite(java.lang.Class);
   }
 
-  public class IsolatedContext extends android.content.ContextWrapper {
+  public deprecated class IsolatedContext extends android.content.ContextWrapper {
     ctor public IsolatedContext(android.content.ContentResolver, android.content.Context);
     method public java.util.List<android.content.Intent> getAndClearBroadcastIntents();
   }
@@ -36066,7 +37337,7 @@
     method public T getLoaderResultSynchronously(android.content.Loader<T>);
   }
 
-  public final class MoreAsserts {
+  public final deprecated class MoreAsserts {
     method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Object);
     method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Class<?>);
     method public static java.util.regex.MatchResult assertContainsRegex(java.lang.String, java.lang.String, java.lang.String);
@@ -36105,7 +37376,7 @@
     method public static void checkEqualsAndHashCodeMethods(java.lang.Object, java.lang.Object, boolean);
   }
 
-  public abstract interface PerformanceTestCase {
+  public abstract deprecated interface PerformanceTestCase {
     method public abstract boolean isPerformanceOnly();
     method public abstract int startPerformance(android.test.PerformanceTestCase.Intermediates);
   }
@@ -36134,7 +37405,7 @@
     method public static android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
-  public class RenamingDelegatingContext extends android.content.ContextWrapper {
+  public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper {
     ctor public RenamingDelegatingContext(android.content.Context, java.lang.String);
     ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String);
     method public java.lang.String getDatabasePrefix();
@@ -36143,7 +37414,7 @@
     method public static T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
-  public abstract class ServiceTestCase extends android.test.AndroidTestCase {
+  public abstract deprecated class ServiceTestCase extends android.test.AndroidTestCase {
     ctor public ServiceTestCase(java.lang.Class<T>);
     method protected android.os.IBinder bindService(android.content.Intent);
     method public android.app.Application getApplication();
@@ -36156,23 +37427,23 @@
     method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public abstract class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
+  public abstract deprecated class SingleLaunchActivityTestCase extends android.test.InstrumentationTestCase {
     ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>);
     method public T getActivity();
     method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public class SyncBaseInstrumentation extends android.test.InstrumentationTestCase {
+  public deprecated class SyncBaseInstrumentation extends android.test.InstrumentationTestCase {
     ctor public SyncBaseInstrumentation();
     method protected void cancelSyncsandDisableAutoSync();
     method protected void syncProvider(android.net.Uri, java.lang.String, java.lang.String) throws java.lang.Exception;
   }
 
-  public abstract interface TestSuiteProvider {
+  public abstract deprecated interface TestSuiteProvider {
     method public abstract junit.framework.TestSuite getTestSuite();
   }
 
-  public class TouchUtils {
+  public deprecated class TouchUtils {
     ctor public TouchUtils();
     method public static void clickView(android.test.InstrumentationTestCase, android.view.View);
     method public static deprecated void drag(android.test.ActivityInstrumentationTestCase, float, float, float, float, int);
@@ -36207,10 +37478,10 @@
     method public static void touchAndCancelView(android.test.InstrumentationTestCase, android.view.View);
   }
 
-  public abstract class UiThreadTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class UiThreadTest implements java.lang.annotation.Annotation {
   }
 
-  public class ViewAsserts {
+  public deprecated class ViewAsserts {
     method public static void assertBaselineAligned(android.view.View, android.view.View);
     method public static void assertBottomAligned(android.view.View, android.view.View);
     method public static void assertBottomAligned(android.view.View, android.view.View, int);
@@ -36235,11 +37506,11 @@
 
 package android.test.mock {
 
-  public class MockApplication extends android.app.Application {
+  public deprecated class MockApplication extends android.app.Application {
     ctor public MockApplication();
   }
 
-  public class MockContentProvider extends android.content.ContentProvider {
+  public deprecated class MockContentProvider extends android.content.ContentProvider {
     ctor protected MockContentProvider();
     ctor public MockContentProvider(android.content.Context);
     ctor public MockContentProvider(android.content.Context, java.lang.String, java.lang.String, android.content.pm.PathPermission[]);
@@ -36251,13 +37522,13 @@
     method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
   }
 
-  public class MockContentResolver extends android.content.ContentResolver {
+  public deprecated class MockContentResolver extends android.content.ContentResolver {
     ctor public MockContentResolver();
     ctor public MockContentResolver(android.content.Context);
     method public void addProvider(java.lang.String, android.content.ContentProvider);
   }
 
-  public class MockContext extends android.content.Context {
+  public deprecated class MockContext extends android.content.Context {
     ctor public MockContext();
     method public boolean bindService(android.content.Intent, android.content.ServiceConnection, int);
     method public int checkCallingOrSelfPermission(java.lang.String);
@@ -36315,6 +37586,7 @@
     method public java.lang.Object getSystemService(java.lang.String);
     method public java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public android.content.res.Resources.Theme getTheme();
+    method public int getUserId();
     method public android.graphics.drawable.Drawable getWallpaper();
     method public int getWallpaperDesiredMinimumHeight();
     method public int getWallpaperDesiredMinimumWidth();
@@ -36357,7 +37629,7 @@
     method public void unregisterReceiver(android.content.BroadcastReceiver);
   }
 
-  public class MockCursor implements android.database.Cursor {
+  public deprecated class MockCursor implements android.database.Cursor {
     ctor public MockCursor();
     method public void close();
     method public void copyStringToBuffer(int, android.database.CharArrayBuffer);
@@ -36402,13 +37674,13 @@
     method public void unregisterDataSetObserver(android.database.DataSetObserver);
   }
 
-  public class MockDialogInterface implements android.content.DialogInterface {
+  public deprecated class MockDialogInterface implements android.content.DialogInterface {
     ctor public MockDialogInterface();
     method public void cancel();
     method public void dismiss();
   }
 
-  public class MockPackageManager extends android.content.pm.PackageManager {
+  public deprecated class MockPackageManager extends android.content.pm.PackageManager {
     ctor public MockPackageManager();
     method public void addPackageToPreferred(java.lang.String);
     method public boolean addPermission(android.content.pm.PermissionInfo);
@@ -36441,10 +37713,8 @@
     method public android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public int getComponentEnabledSetting(android.content.ComponentName);
     method public android.graphics.drawable.Drawable getDefaultActivityIcon();
-    method public java.lang.String getDefaultBrowserPackageName(int);
+    method public java.lang.String getDefaultBrowserPackageNameAsUser(int);
     method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
-    method public byte[] getEphemeralCookie();
-    method public int getEphemeralCookieMaxSizeBytes();
     method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
     method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
     method public java.lang.String getInstallerPackageName(java.lang.String);
@@ -36453,8 +37723,10 @@
     method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public java.lang.String getNameForUid(int);
     method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInstaller getPackageInstaller();
+    method public int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] getPackagesForUid(int);
     method public java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int);
     method public android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -36475,7 +37747,6 @@
     method public java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle);
     method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
     method public boolean hasSystemFeature(java.lang.String);
-    method public boolean isEphemeralApplication();
     method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
     method public boolean isSafeMode();
     method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
@@ -36493,13 +37764,11 @@
     method public android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
     method public void setApplicationEnabledSetting(java.lang.String, int, int);
     method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
-    method public boolean setDefaultBrowserPackageName(java.lang.String, int);
-    method public boolean setEphemeralCookie(byte[]);
     method public void setInstallerPackageName(java.lang.String, java.lang.String);
     method public void verifyPendingInstall(int, int);
   }
 
-  public class MockResources extends android.content.res.Resources {
+  public deprecated class MockResources extends android.content.res.Resources {
     ctor public MockResources();
   }
 
@@ -36540,19 +37809,19 @@
 
 package android.test.suitebuilder.annotation {
 
-  public abstract class LargeTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class LargeTest implements java.lang.annotation.Annotation {
   }
 
-  public abstract class MediumTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class MediumTest implements java.lang.annotation.Annotation {
   }
 
-  public abstract class SmallTest implements java.lang.annotation.Annotation {
+  public abstract deprecated class SmallTest implements java.lang.annotation.Annotation {
   }
 
-  public abstract class Smoke implements java.lang.annotation.Annotation {
+  public abstract deprecated class Smoke implements java.lang.annotation.Annotation {
   }
 
-  public abstract class Suppress implements java.lang.annotation.Annotation {
+  public abstract deprecated class Suppress implements java.lang.annotation.Annotation {
   }
 
 }
@@ -36698,9 +37967,23 @@
 
   public class Html {
     method public static java.lang.String escapeHtml(java.lang.CharSequence);
-    method public static android.text.Spanned fromHtml(java.lang.String);
-    method public static android.text.Spanned fromHtml(java.lang.String, android.text.Html.ImageGetter, android.text.Html.TagHandler);
-    method public static java.lang.String toHtml(android.text.Spanned);
+    method public static deprecated android.text.Spanned fromHtml(java.lang.String);
+    method public static android.text.Spanned fromHtml(java.lang.String, int);
+    method public static deprecated android.text.Spanned fromHtml(java.lang.String, android.text.Html.ImageGetter, android.text.Html.TagHandler);
+    method public static android.text.Spanned fromHtml(java.lang.String, int, android.text.Html.ImageGetter, android.text.Html.TagHandler);
+    method public static deprecated java.lang.String toHtml(android.text.Spanned);
+    method public static java.lang.String toHtml(android.text.Spanned, int);
+    field public static final int FROM_HTML_MODE_COMPACT = 63; // 0x3f
+    field public static final int FROM_HTML_MODE_LEGACY = 0; // 0x0
+    field public static final int FROM_HTML_OPTION_USE_CSS_COLORS = 256; // 0x100
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_BLOCKQUOTE = 32; // 0x20
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_DIV = 16; // 0x10
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_HEADING = 2; // 0x2
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST = 8; // 0x8
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM = 4; // 0x4
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH = 1; // 0x1
+    field public static final int TO_HTML_PARAGRAPH_LINES_CONSECUTIVE = 0; // 0x0
+    field public static final int TO_HTML_PARAGRAPH_LINES_INDIVIDUAL = 1; // 0x1
   }
 
   public static abstract interface Html.ImageGetter {
@@ -37697,9 +38980,11 @@
 
   public class LocaleSpan extends android.text.style.MetricAffectingSpan implements android.text.ParcelableSpan {
     ctor public LocaleSpan(java.util.Locale);
+    ctor public LocaleSpan(android.util.LocaleList);
     ctor public LocaleSpan(android.os.Parcel);
     method public int describeContents();
     method public java.util.Locale getLocale();
+    method public android.util.LocaleList getLocales();
     method public int getSpanTypeId();
     method public void updateDrawState(android.text.TextPaint);
     method public void updateMeasureState(android.text.TextPaint);
@@ -37805,7 +39090,8 @@
     ctor public SuggestionSpan(android.os.Parcel);
     method public int describeContents();
     method public int getFlags();
-    method public java.lang.String getLocale();
+    method public deprecated java.lang.String getLocale();
+    method public java.util.Locale getLocaleObject();
     method public int getSpanTypeId();
     method public java.lang.String[] getSuggestions();
     method public void setFlags(int);
@@ -38725,7 +40011,9 @@
     method public static android.util.LocaleList getEmptyLocaleList();
     method public java.util.Locale getFirstMatch(java.lang.String[]);
     method public java.util.Locale getPrimary();
+    method public int indexOf(java.util.Locale);
     method public boolean isEmpty();
+    method public static void setDefault(android.util.LocaleList);
     method public int size();
     method public java.lang.String toLanguageTags();
     method public void writeToParcel(android.os.Parcel, int);
@@ -38883,7 +40171,7 @@
     method public static final java.lang.String digitsAndPlusOnly(java.util.regex.Matcher);
     field public static final java.util.regex.Pattern DOMAIN_NAME;
     field public static final java.util.regex.Pattern EMAIL_ADDRESS;
-    field public static final java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
+    field public static final deprecated java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
     field public static final java.util.regex.Pattern IP_ADDRESS;
     field public static final java.util.regex.Pattern PHONE;
     field public static final deprecated java.util.regex.Pattern TOP_LEVEL_DOMAIN;
@@ -39314,7 +40602,6 @@
     method public int getAction();
     method public android.content.ClipData getClipData();
     method public android.content.ClipDescription getClipDescription();
-    method public android.view.DropPermissionHolder getDropPermissionHolder();
     method public java.lang.Object getLocalState();
     method public boolean getResult();
     method public float getX();
@@ -39329,12 +40616,8 @@
     field public static final android.os.Parcelable.Creator<android.view.DragEvent> CREATOR;
   }
 
-  public class DropPermissionHolder implements android.os.Parcelable {
-    method public int describeContents();
-    method public void grant();
-    method public void revoke();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.view.DropPermissionHolder> CREATOR;
+  public final class DropPermissions {
+    method public void release();
   }
 
   public class FocusFinder {
@@ -39992,6 +41275,27 @@
     method public void startTracking(android.view.KeyEvent, java.lang.Object);
   }
 
+  public final class KeyboardShortcutGroup implements android.os.Parcelable {
+    ctor public KeyboardShortcutGroup(java.lang.CharSequence, java.util.List<android.view.KeyboardShortcutInfo>);
+    ctor public KeyboardShortcutGroup(java.lang.CharSequence);
+    method public void addItem(android.view.KeyboardShortcutInfo);
+    method public int describeContents();
+    method public java.util.List<android.view.KeyboardShortcutInfo> getItems();
+    method public java.lang.CharSequence getLabel();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.KeyboardShortcutGroup> CREATOR;
+  }
+
+  public final class KeyboardShortcutInfo implements android.os.Parcelable {
+    ctor public KeyboardShortcutInfo(java.lang.CharSequence, char, int);
+    method public int describeContents();
+    method public char getBaseCharacter();
+    method public java.lang.CharSequence getLabel();
+    method public int getModifiers();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.KeyboardShortcutInfo> CREATOR;
+  }
+
   public abstract class LayoutInflater {
     ctor protected LayoutInflater(android.content.Context);
     ctor protected LayoutInflater(android.view.LayoutInflater, android.content.Context);
@@ -40260,12 +41564,13 @@
     field public static final int AXIS_LTRIGGER = 17; // 0x11
     field public static final int AXIS_ORIENTATION = 8; // 0x8
     field public static final int AXIS_PRESSURE = 2; // 0x2
+    field public static final int AXIS_RELATIVE_X = 27; // 0x1b
+    field public static final int AXIS_RELATIVE_Y = 28; // 0x1c
     field public static final int AXIS_RTRIGGER = 18; // 0x12
     field public static final int AXIS_RUDDER = 20; // 0x14
     field public static final int AXIS_RX = 12; // 0xc
     field public static final int AXIS_RY = 13; // 0xd
     field public static final int AXIS_RZ = 14; // 0xe
-    field public static final int AXIS_SCROLL = 26; // 0x1a
     field public static final int AXIS_SIZE = 3; // 0x3
     field public static final int AXIS_THROTTLE = 19; // 0x13
     field public static final int AXIS_TILT = 25; // 0x19
@@ -40795,6 +42100,7 @@
     method public boolean hasNestedScrollingParent();
     method public boolean hasOnClickListeners();
     method public boolean hasOverlappingRendering();
+    method public boolean hasPointerCapture();
     method public boolean hasTransientState();
     method public boolean hasWindowFocus();
     method public static android.view.View inflate(android.content.Context, int, android.view.ViewGroup);
@@ -40921,6 +42227,7 @@
     method public void postOnAnimation(java.lang.Runnable);
     method public void postOnAnimationDelayed(java.lang.Runnable, long);
     method public void refreshDrawableState();
+    method public void releasePointerCapture();
     method public boolean removeCallbacks(java.lang.Runnable);
     method public void removeOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
     method public void removeOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
@@ -41021,6 +42328,7 @@
     method public void setPaddingRelative(int, int, int, int);
     method public void setPivotX(float);
     method public void setPivotY(float);
+    method public void setPointerCapture();
     method public void setPointerIcon(android.view.PointerIcon);
     method public void setPressed(boolean);
     method public final void setRight(int);
@@ -41989,6 +43297,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 abstract boolean onSearchRequested();
     method public abstract boolean onSearchRequested(android.view.SearchEvent);
     method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
@@ -42314,6 +43623,7 @@
     method public android.view.accessibility.AccessibilityNodeInfo.CollectionInfo getCollectionInfo();
     method public android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo getCollectionItemInfo();
     method public java.lang.CharSequence getContentDescription();
+    method public int getDrawingOrder();
     method public java.lang.CharSequence getError();
     method public android.os.Bundle getExtras();
     method public int getInputType();
@@ -42376,6 +43686,7 @@
     method public void setContentInvalid(boolean);
     method public void setContextClickable(boolean);
     method public void setDismissable(boolean);
+    method public void setDrawingOrder(int);
     method public void setEditable(boolean);
     method public void setEnabled(boolean);
     method public void setError(java.lang.CharSequence);
@@ -42932,6 +44243,7 @@
     method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public boolean commitText(java.lang.CharSequence, int);
     method public boolean deleteSurroundingText(int, int);
+    method public boolean deleteSurroundingTextInCodePoints(int, int);
     method public boolean endBatchEdit();
     method public boolean finishComposingText();
     method public static int getComposingSpanEnd(android.text.Spannable);
@@ -43039,6 +44351,7 @@
     field public android.os.Bundle extras;
     field public int fieldId;
     field public java.lang.String fieldName;
+    field public android.util.LocaleList hintLocales;
     field public java.lang.CharSequence hintText;
     field public int imeOptions;
     field public int initialCapsMode;
@@ -43046,7 +44359,6 @@
     field public int initialSelStart;
     field public int inputType;
     field public java.lang.CharSequence label;
-    field public android.util.LocaleList locales;
     field public java.lang.String packageName;
     field public java.lang.String privateImeOptions;
   }
@@ -43097,6 +44409,7 @@
     method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public abstract boolean commitText(java.lang.CharSequence, int);
     method public abstract boolean deleteSurroundingText(int, int);
+    method public abstract boolean deleteSurroundingTextInCodePoints(int, int);
     method public abstract boolean endBatchEdit();
     method public abstract boolean finishComposingText();
     method public abstract int getCursorCapsMode(int);
@@ -43127,6 +44440,7 @@
     method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
     method public boolean commitText(java.lang.CharSequence, int);
     method public boolean deleteSurroundingText(int, int);
+    method public boolean deleteSurroundingTextInCodePoints(int, int);
     method public boolean endBatchEdit();
     method public boolean finishComposingText();
     method public int getCursorCapsMode(int);
@@ -43189,6 +44503,7 @@
   }
 
   public final class InputMethodManager {
+    method public void dispatchKeyEventFromInputMethod(android.view.View, android.view.KeyEvent);
     method public void displayCompletions(android.view.View, android.view.inputmethod.CompletionInfo[]);
     method public android.view.inputmethod.InputMethodSubtype getCurrentInputMethodSubtype();
     method public java.util.List<android.view.inputmethod.InputMethodInfo> getEnabledInputMethodList();
@@ -43520,6 +44835,30 @@
     method public abstract android.view.View getFullScreenView(int, android.content.Context);
   }
 
+  public class ServiceWorkerClient {
+    ctor public ServiceWorkerClient();
+    method public android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebResourceRequest);
+  }
+
+  public abstract class ServiceWorkerController {
+    ctor public ServiceWorkerController();
+    method public static android.webkit.ServiceWorkerController getInstance();
+    method public abstract android.webkit.ServiceWorkerWebSettings getServiceWorkerWebSettings();
+    method public abstract void setServiceWorkerClient(android.webkit.ServiceWorkerClient);
+  }
+
+  public abstract class ServiceWorkerWebSettings {
+    ctor public ServiceWorkerWebSettings();
+    method public abstract boolean getAllowContentAccess();
+    method public abstract boolean getAllowFileAccess();
+    method public abstract boolean getBlockNetworkLoads();
+    method public abstract int getCacheMode();
+    method public abstract void setAllowContentAccess(boolean);
+    method public abstract void setAllowFileAccess(boolean);
+    method public abstract void setBlockNetworkLoads(boolean);
+    method public abstract void setCacheMode(int);
+  }
+
   public class SslErrorHandler extends android.os.Handler {
     method public void cancel();
     method public void proceed();
@@ -43749,7 +45088,7 @@
     method public abstract deprecated void setEnableSmoothTransition(boolean);
     method public abstract void setFantasyFontFamily(java.lang.String);
     method public abstract void setFixedFontFamily(java.lang.String);
-    method public abstract void setGeolocationDatabasePath(java.lang.String);
+    method public abstract deprecated void setGeolocationDatabasePath(java.lang.String);
     method public abstract void setGeolocationEnabled(boolean);
     method public abstract void setJavaScriptCanOpenWindowsAutomatically(boolean);
     method public abstract void setJavaScriptEnabled(boolean);
@@ -44191,12 +45530,18 @@
     method public int getThumbOffset();
     method public android.content.res.ColorStateList getThumbTintList();
     method public android.graphics.PorterDuff.Mode getThumbTintMode();
+    method public android.graphics.drawable.Drawable getTickMark();
+    method public android.content.res.ColorStateList getTickMarkTintList();
+    method public android.graphics.PorterDuff.Mode getTickMarkTintMode();
     method public void setKeyProgressIncrement(int);
     method public void setSplitTrack(boolean);
     method public void setThumb(android.graphics.drawable.Drawable);
     method public void setThumbOffset(int);
     method public void setThumbTintList(android.content.res.ColorStateList);
     method public void setThumbTintMode(android.graphics.PorterDuff.Mode);
+    method public void setTickMark(android.graphics.drawable.Drawable);
+    method public void setTickMarkTintList(android.content.res.ColorStateList);
+    method public void setTickMarkTintMode(android.graphics.PorterDuff.Mode);
   }
 
   public abstract class AbsSpinner extends android.widget.AdapterView {
@@ -45153,6 +46498,7 @@
     method public int getBaselineAlignedChildIndex();
     method public android.graphics.drawable.Drawable getDividerDrawable();
     method public int getDividerPadding();
+    method public int getGravity();
     method public int getOrientation();
     method public int getShowDividers();
     method public float getWeightSum();
@@ -46283,6 +47629,7 @@
     method public int getHyphenationFrequency();
     method public int getImeActionId();
     method public java.lang.CharSequence getImeActionLabel();
+    method public android.util.LocaleList getImeHintLocales();
     method public int getImeOptions();
     method public boolean getIncludeFontPadding();
     method public android.os.Bundle getInputExtras(boolean);
@@ -46389,6 +47736,7 @@
     method public void setHorizontallyScrolling(boolean);
     method public void setHyphenationFrequency(int);
     method public void setImeActionLabel(java.lang.CharSequence, int);
+    method public void setImeHintLocales(android.util.LocaleList);
     method public void setImeOptions(int);
     method public void setIncludeFontPadding(boolean);
     method public void setInputExtras(int) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -47342,10 +48690,8 @@
   }
 
   public final class Console implements java.io.Flushable {
-    method public static java.io.Console console();
     method public void flush();
     method public java.io.Console format(java.lang.String, java.lang.Object...);
-    method public static synchronized java.io.Console getConsole();
     method public java.io.Console printf(java.lang.String, java.lang.Object...);
     method public java.lang.String readLine(java.lang.String, java.lang.Object...);
     method public java.lang.String readLine();
@@ -47488,7 +48834,6 @@
     method public boolean setReadable(boolean);
     method public boolean setWritable(boolean, boolean);
     method public boolean setWritable(boolean);
-    method public java.nio.file.Path toPath();
     method public java.net.URI toURI();
     method public deprecated java.net.URL toURL() throws java.net.MalformedURLException;
     field public static final java.lang.String pathSeparator;
@@ -47629,7 +48974,6 @@
   public class InterruptedIOException extends java.io.IOException {
     ctor public InterruptedIOException();
     ctor public InterruptedIOException(java.lang.String);
-    ctor public InterruptedIOException(java.lang.Throwable);
     field public int bytesTransferred;
   }
 
@@ -48300,7 +49644,6 @@
     method public long longValue();
     method public static byte parseByte(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static byte parseByte(java.lang.String) throws java.lang.NumberFormatException;
-    method public static java.lang.String toHexString(byte, boolean);
     method public static java.lang.String toString(byte);
     method public static java.lang.Byte valueOf(byte);
     method public static java.lang.Byte valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -49043,6 +50386,9 @@
     field public static final java.lang.Class<java.lang.Float> TYPE;
   }
 
+  public abstract class FunctionalInterface implements java.lang.annotation.Annotation {
+  }
+
   public class IllegalAccessError extends java.lang.IncompatibleClassChangeError {
     ctor public IllegalAccessError();
     ctor public IllegalAccessError(java.lang.String);
@@ -49144,6 +50490,8 @@
   public class InternalError extends java.lang.VirtualMachineError {
     ctor public InternalError();
     ctor public InternalError(java.lang.String);
+    ctor public InternalError(java.lang.String, java.lang.Throwable);
+    ctor public InternalError(java.lang.Throwable);
   }
 
   public class InterruptedException extends java.lang.Exception {
@@ -49916,6 +51264,8 @@
   public abstract class VirtualMachineError extends java.lang.Error {
     ctor public VirtualMachineError();
     ctor public VirtualMachineError(java.lang.String);
+    ctor public VirtualMachineError(java.lang.String, java.lang.Throwable);
+    ctor public VirtualMachineError(java.lang.Throwable);
   }
 
   public final class Void {
@@ -50168,6 +51518,7 @@
     method public java.lang.Object invoke(java.lang.Object, java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException;
     method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
     method public boolean isBridge();
+    method public boolean isDefault();
     method public boolean isSynthetic();
     method public boolean isVarArgs();
     method public java.lang.String toGenericString();
@@ -50448,7 +51799,6 @@
   public class BindException extends java.net.SocketException {
     ctor public BindException(java.lang.String);
     ctor public BindException();
-    ctor public BindException(java.lang.String, java.lang.Throwable);
   }
 
   public abstract class CacheRequest {
@@ -50466,7 +51816,6 @@
   public class ConnectException extends java.net.SocketException {
     ctor public ConnectException(java.lang.String);
     ctor public ConnectException();
-    ctor public ConnectException(java.lang.String, java.lang.Throwable);
   }
 
   public abstract class ContentHandler {
@@ -50546,7 +51895,6 @@
     method public void disconnect();
     method public synchronized boolean getBroadcast() throws java.net.SocketException;
     method public java.nio.channels.DatagramChannel getChannel();
-    method public final java.io.FileDescriptor getFileDescriptor$();
     method public java.net.InetAddress getInetAddress();
     method public java.net.InetAddress getLocalAddress();
     method public int getLocalPort();
@@ -50623,7 +51971,6 @@
     method public boolean hasExpired();
     method public boolean isHttpOnly();
     method public static java.util.List<java.net.HttpCookie> parse(java.lang.String);
-    method public static java.util.List<java.net.HttpCookie> parse(java.lang.String, boolean);
     method public void setComment(java.lang.String);
     method public void setCommentURL(java.lang.String);
     method public void setDiscard(boolean);
@@ -50716,9 +52063,6 @@
   }
 
   public final class Inet4Address extends java.net.InetAddress {
-    field public static final java.net.InetAddress ALL;
-    field public static final java.net.InetAddress ANY;
-    field public static final java.net.InetAddress LOOPBACK;
   }
 
   public final class Inet6Address extends java.net.InetAddress {
@@ -50727,8 +52071,6 @@
     method public int getScopeId();
     method public java.net.NetworkInterface getScopedInterface();
     method public boolean isIPv4CompatibleAddress();
-    field public static final java.net.InetAddress ANY;
-    field public static final java.net.InetAddress LOOPBACK;
   }
 
   public class InetAddress implements java.io.Serializable {
@@ -50856,13 +52198,11 @@
   public class PortUnreachableException extends java.net.SocketException {
     ctor public PortUnreachableException(java.lang.String);
     ctor public PortUnreachableException();
-    ctor public PortUnreachableException(java.lang.String, java.lang.Throwable);
   }
 
   public class ProtocolException extends java.io.IOException {
     ctor public ProtocolException(java.lang.String);
     ctor public ProtocolException();
-    ctor public ProtocolException(java.lang.String, java.lang.Throwable);
   }
 
   public abstract interface ProtocolFamily {
@@ -50997,8 +52337,6 @@
   public class SocketException extends java.io.IOException {
     ctor public SocketException(java.lang.String);
     ctor public SocketException();
-    ctor public SocketException(java.lang.Throwable);
-    ctor public SocketException(java.lang.String, java.lang.Throwable);
   }
 
   public abstract class SocketImpl implements java.net.SocketOptions {
@@ -51068,8 +52406,6 @@
   public class SocketTimeoutException extends java.io.InterruptedIOException {
     ctor public SocketTimeoutException(java.lang.String);
     ctor public SocketTimeoutException();
-    ctor public SocketTimeoutException(java.lang.Throwable);
-    ctor public SocketTimeoutException(java.lang.String, java.lang.Throwable);
   }
 
   public final class StandardProtocolFamily extends java.lang.Enum implements java.net.ProtocolFamily {
@@ -51596,25 +52932,6 @@
     ctor public AsynchronousCloseException();
   }
 
-  public abstract class AsynchronousFileChannel implements java.nio.channels.AsynchronousChannel {
-    ctor protected AsynchronousFileChannel();
-    method public abstract void force(boolean) throws java.io.IOException;
-    method public abstract void lock(long, long, boolean, A, java.nio.channels.CompletionHandler<java.nio.channels.FileLock, ? super A>);
-    method public final void lock(A, java.nio.channels.CompletionHandler<java.nio.channels.FileLock, ? super A>);
-    method public abstract java.util.concurrent.Future<java.nio.channels.FileLock> lock(long, long, boolean);
-    method public final java.util.concurrent.Future<java.nio.channels.FileLock> lock();
-    method public static java.nio.channels.AsynchronousFileChannel open(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.util.concurrent.ExecutorService, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.channels.AsynchronousFileChannel open(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public abstract void read(java.nio.ByteBuffer, long, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
-    method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer, long);
-    method public abstract long size() throws java.io.IOException;
-    method public abstract java.nio.channels.AsynchronousFileChannel truncate(long) throws java.io.IOException;
-    method public abstract java.nio.channels.FileLock tryLock(long, long, boolean) throws java.io.IOException;
-    method public final java.nio.channels.FileLock tryLock() throws java.io.IOException;
-    method public abstract void write(java.nio.ByteBuffer, long, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
-    method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer, long);
-  }
-
   public abstract class AsynchronousServerSocketChannel implements java.nio.channels.AsynchronousChannel java.nio.channels.NetworkChannel {
     ctor protected AsynchronousServerSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
     method public abstract void accept(A, java.nio.channels.CompletionHandler<java.nio.channels.AsynchronousSocketChannel, ? super A>);
@@ -51723,8 +53040,6 @@
     method public abstract java.nio.channels.FileLock lock(long, long, boolean) throws java.io.IOException;
     method public final java.nio.channels.FileLock lock() throws java.io.IOException;
     method public abstract java.nio.MappedByteBuffer map(java.nio.channels.FileChannel.MapMode, long, long) throws java.io.IOException;
-    method public static java.nio.channels.FileChannel open(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.channels.FileChannel open(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
     method public abstract long position() throws java.io.IOException;
     method public abstract java.nio.channels.FileChannel position(long) throws java.io.IOException;
     method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
@@ -51751,7 +53066,6 @@
 
   public abstract class FileLock implements java.lang.AutoCloseable {
     ctor protected FileLock(java.nio.channels.FileChannel, long, long, boolean);
-    ctor protected FileLock(java.nio.channels.AsynchronousFileChannel, long, long, boolean);
     method public java.nio.channels.Channel acquiredBy();
     method public final java.nio.channels.FileChannel channel();
     method public final void close() throws java.io.IOException;
@@ -52201,592 +53515,6 @@
 
 }
 
-package java.nio.file {
-
-  public class AccessDeniedException extends java.nio.file.FileSystemException {
-    ctor public AccessDeniedException(java.lang.String);
-    ctor public AccessDeniedException(java.lang.String, java.lang.String, java.lang.String);
-  }
-
-  public final class AccessMode extends java.lang.Enum {
-    method public static java.nio.file.AccessMode valueOf(java.lang.String);
-    method public static final java.nio.file.AccessMode[] values();
-    enum_constant public static final java.nio.file.AccessMode EXECUTE;
-    enum_constant public static final java.nio.file.AccessMode READ;
-    enum_constant public static final java.nio.file.AccessMode WRITE;
-  }
-
-  public class AtomicMoveNotSupportedException extends java.nio.file.FileSystemException {
-    ctor public AtomicMoveNotSupportedException(java.lang.String, java.lang.String, java.lang.String);
-  }
-
-  public class ClosedDirectoryStreamException extends java.lang.IllegalStateException {
-    ctor public ClosedDirectoryStreamException();
-  }
-
-  public class ClosedFileSystemException extends java.lang.IllegalStateException {
-    ctor public ClosedFileSystemException();
-  }
-
-  public class ClosedWatchServiceException extends java.lang.IllegalStateException {
-    ctor public ClosedWatchServiceException();
-  }
-
-  public abstract interface CopyOption {
-  }
-
-  public final class DirectoryIteratorException extends java.util.ConcurrentModificationException {
-    ctor public DirectoryIteratorException(java.io.IOException);
-  }
-
-  public class DirectoryNotEmptyException extends java.nio.file.FileSystemException {
-    ctor public DirectoryNotEmptyException(java.lang.String);
-  }
-
-  public abstract interface DirectoryStream implements java.io.Closeable java.lang.Iterable {
-    method public abstract java.util.Iterator<T> iterator();
-  }
-
-  public static abstract interface DirectoryStream.Filter {
-    method public abstract boolean accept(T) throws java.io.IOException;
-  }
-
-  public class FileAlreadyExistsException extends java.nio.file.FileSystemException {
-    ctor public FileAlreadyExistsException(java.lang.String);
-    ctor public FileAlreadyExistsException(java.lang.String, java.lang.String, java.lang.String);
-  }
-
-  public abstract class FileStore {
-    ctor protected FileStore();
-    method public abstract java.lang.Object getAttribute(java.lang.String) throws java.io.IOException;
-    method public abstract V getFileStoreAttributeView(java.lang.Class<V>);
-    method public abstract long getTotalSpace() throws java.io.IOException;
-    method public abstract long getUnallocatedSpace() throws java.io.IOException;
-    method public abstract long getUsableSpace() throws java.io.IOException;
-    method public abstract boolean isReadOnly();
-    method public abstract java.lang.String name();
-    method public abstract boolean supportsFileAttributeView(java.lang.Class<? extends java.nio.file.attribute.FileAttributeView>);
-    method public abstract boolean supportsFileAttributeView(java.lang.String);
-    method public abstract java.lang.String type();
-  }
-
-  public abstract class FileSystem implements java.io.Closeable {
-    ctor protected FileSystem();
-    method public abstract void close() throws java.io.IOException;
-    method public abstract java.lang.Iterable<java.nio.file.FileStore> getFileStores();
-    method public abstract java.nio.file.Path getPath(java.lang.String, java.lang.String...);
-    method public abstract java.nio.file.PathMatcher getPathMatcher(java.lang.String);
-    method public abstract java.lang.Iterable<java.nio.file.Path> getRootDirectories();
-    method public abstract java.lang.String getSeparator();
-    method public abstract java.nio.file.attribute.UserPrincipalLookupService getUserPrincipalLookupService();
-    method public abstract boolean isOpen();
-    method public abstract boolean isReadOnly();
-    method public abstract java.nio.file.WatchService newWatchService() throws java.io.IOException;
-    method public abstract java.nio.file.spi.FileSystemProvider provider();
-    method public abstract java.util.Set<java.lang.String> supportedFileAttributeViews();
-  }
-
-  public class FileSystemAlreadyExistsException extends java.lang.RuntimeException {
-    ctor public FileSystemAlreadyExistsException();
-    ctor public FileSystemAlreadyExistsException(java.lang.String);
-  }
-
-  public class FileSystemException extends java.io.IOException {
-    ctor public FileSystemException(java.lang.String);
-    ctor public FileSystemException(java.lang.String, java.lang.String, java.lang.String);
-    method public java.lang.String getFile();
-    method public java.lang.String getOtherFile();
-    method public java.lang.String getReason();
-  }
-
-  public class FileSystemLoopException extends java.nio.file.FileSystemException {
-    ctor public FileSystemLoopException(java.lang.String);
-  }
-
-  public class FileSystemNotFoundException extends java.lang.RuntimeException {
-    ctor public FileSystemNotFoundException();
-    ctor public FileSystemNotFoundException(java.lang.String);
-  }
-
-  public final class FileSystems {
-    method public static java.nio.file.FileSystem getDefault();
-    method public static java.nio.file.FileSystem getFileSystem(java.net.URI);
-    method public static java.nio.file.FileSystem newFileSystem(java.net.URI, java.util.Map<java.lang.String, ?>) throws java.io.IOException;
-    method public static java.nio.file.FileSystem newFileSystem(java.net.URI, java.util.Map<java.lang.String, ?>, java.lang.ClassLoader) throws java.io.IOException;
-    method public static java.nio.file.FileSystem newFileSystem(java.nio.file.Path, java.lang.ClassLoader) throws java.io.IOException;
-  }
-
-  public final class FileVisitOption extends java.lang.Enum {
-    method public static java.nio.file.FileVisitOption valueOf(java.lang.String);
-    method public static final java.nio.file.FileVisitOption[] values();
-    enum_constant public static final java.nio.file.FileVisitOption FOLLOW_LINKS;
-  }
-
-  public final class FileVisitResult extends java.lang.Enum {
-    method public static java.nio.file.FileVisitResult valueOf(java.lang.String);
-    method public static final java.nio.file.FileVisitResult[] values();
-    enum_constant public static final java.nio.file.FileVisitResult CONTINUE;
-    enum_constant public static final java.nio.file.FileVisitResult SKIP_SIBLINGS;
-    enum_constant public static final java.nio.file.FileVisitResult SKIP_SUBTREE;
-    enum_constant public static final java.nio.file.FileVisitResult TERMINATE;
-  }
-
-  public abstract interface FileVisitor {
-    method public abstract java.nio.file.FileVisitResult postVisitDirectory(T, java.io.IOException) throws java.io.IOException;
-    method public abstract java.nio.file.FileVisitResult preVisitDirectory(T, java.nio.file.attribute.BasicFileAttributes) throws java.io.IOException;
-    method public abstract java.nio.file.FileVisitResult visitFile(T, java.nio.file.attribute.BasicFileAttributes) throws java.io.IOException;
-    method public abstract java.nio.file.FileVisitResult visitFileFailed(T, java.io.IOException) throws java.io.IOException;
-  }
-
-  public final class Files {
-    method public static java.nio.file.Path copy(java.nio.file.Path, java.nio.file.Path, java.nio.file.CopyOption...) throws java.io.IOException;
-    method public static long copy(java.io.InputStream, java.nio.file.Path, java.nio.file.CopyOption...) throws java.io.IOException;
-    method public static long copy(java.nio.file.Path, java.io.OutputStream) throws java.io.IOException;
-    method public static java.nio.file.Path createDirectories(java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createDirectory(java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createFile(java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createLink(java.nio.file.Path, java.nio.file.Path) throws java.io.IOException;
-    method public static java.nio.file.Path createSymbolicLink(java.nio.file.Path, java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createTempDirectory(java.nio.file.Path, java.lang.String, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createTempDirectory(java.lang.String, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createTempFile(java.nio.file.Path, java.lang.String, java.lang.String, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createTempFile(java.lang.String, java.lang.String, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static void delete(java.nio.file.Path) throws java.io.IOException;
-    method public static boolean deleteIfExists(java.nio.file.Path) throws java.io.IOException;
-    method public static boolean exists(java.nio.file.Path, java.nio.file.LinkOption...);
-    method public static java.lang.Object getAttribute(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static V getFileAttributeView(java.nio.file.Path, java.lang.Class<V>, java.nio.file.LinkOption...);
-    method public static java.nio.file.FileStore getFileStore(java.nio.file.Path) throws java.io.IOException;
-    method public static java.nio.file.attribute.FileTime getLastModifiedTime(java.nio.file.Path, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static java.nio.file.attribute.UserPrincipal getOwner(java.nio.file.Path, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static java.util.Set<java.nio.file.attribute.PosixFilePermission> getPosixFilePermissions(java.nio.file.Path, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static boolean isDirectory(java.nio.file.Path, java.nio.file.LinkOption...);
-    method public static boolean isExecutable(java.nio.file.Path);
-    method public static boolean isHidden(java.nio.file.Path) throws java.io.IOException;
-    method public static boolean isReadable(java.nio.file.Path);
-    method public static boolean isRegularFile(java.nio.file.Path, java.nio.file.LinkOption...);
-    method public static boolean isSameFile(java.nio.file.Path, java.nio.file.Path) throws java.io.IOException;
-    method public static boolean isSymbolicLink(java.nio.file.Path);
-    method public static boolean isWritable(java.nio.file.Path);
-    method public static java.nio.file.Path move(java.nio.file.Path, java.nio.file.Path, java.nio.file.CopyOption...) throws java.io.IOException;
-    method public static java.io.BufferedReader newBufferedReader(java.nio.file.Path, java.nio.charset.Charset) throws java.io.IOException;
-    method public static java.io.BufferedWriter newBufferedWriter(java.nio.file.Path, java.nio.charset.Charset, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public static java.nio.channels.SeekableByteChannel newByteChannel(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.channels.SeekableByteChannel newByteChannel(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public static java.nio.file.DirectoryStream<java.nio.file.Path> newDirectoryStream(java.nio.file.Path) throws java.io.IOException;
-    method public static java.nio.file.DirectoryStream<java.nio.file.Path> newDirectoryStream(java.nio.file.Path, java.lang.String) throws java.io.IOException;
-    method public static java.nio.file.DirectoryStream<java.nio.file.Path> newDirectoryStream(java.nio.file.Path, java.nio.file.DirectoryStream.Filter<? super java.nio.file.Path>) throws java.io.IOException;
-    method public static java.io.InputStream newInputStream(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public static java.io.OutputStream newOutputStream(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public static boolean notExists(java.nio.file.Path, java.nio.file.LinkOption...);
-    method public static java.lang.String probeContentType(java.nio.file.Path) throws java.io.IOException;
-    method public static byte[] readAllBytes(java.nio.file.Path) throws java.io.IOException;
-    method public static java.util.List<java.lang.String> readAllLines(java.nio.file.Path, java.nio.charset.Charset) throws java.io.IOException;
-    method public static A readAttributes(java.nio.file.Path, java.lang.Class<A>, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static java.util.Map<java.lang.String, java.lang.Object> readAttributes(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static java.nio.file.Path readSymbolicLink(java.nio.file.Path) throws java.io.IOException;
-    method public static java.nio.file.Path setAttribute(java.nio.file.Path, java.lang.String, java.lang.Object, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static java.nio.file.Path setLastModifiedTime(java.nio.file.Path, java.nio.file.attribute.FileTime) throws java.io.IOException;
-    method public static java.nio.file.Path setOwner(java.nio.file.Path, java.nio.file.attribute.UserPrincipal) throws java.io.IOException;
-    method public static java.nio.file.Path setPosixFilePermissions(java.nio.file.Path, java.util.Set<java.nio.file.attribute.PosixFilePermission>) throws java.io.IOException;
-    method public static long size(java.nio.file.Path) throws java.io.IOException;
-    method public static java.nio.file.Path walkFileTree(java.nio.file.Path, java.util.Set<java.nio.file.FileVisitOption>, int, java.nio.file.FileVisitor<? super java.nio.file.Path>) throws java.io.IOException;
-    method public static java.nio.file.Path walkFileTree(java.nio.file.Path, java.nio.file.FileVisitor<? super java.nio.file.Path>) throws java.io.IOException;
-    method public static java.nio.file.Path write(java.nio.file.Path, byte[], java.nio.file.OpenOption...) throws java.io.IOException;
-    method public static java.nio.file.Path write(java.nio.file.Path, java.lang.Iterable<? extends java.lang.CharSequence>, java.nio.charset.Charset, java.nio.file.OpenOption...) throws java.io.IOException;
-  }
-
-  public class InvalidPathException extends java.lang.IllegalArgumentException {
-    ctor public InvalidPathException(java.lang.String, java.lang.String, int);
-    ctor public InvalidPathException(java.lang.String, java.lang.String);
-    method public int getIndex();
-    method public java.lang.String getInput();
-    method public java.lang.String getReason();
-  }
-
-  public final class LinkOption extends java.lang.Enum implements java.nio.file.CopyOption java.nio.file.OpenOption {
-    method public static java.nio.file.LinkOption valueOf(java.lang.String);
-    method public static final java.nio.file.LinkOption[] values();
-    enum_constant public static final java.nio.file.LinkOption NOFOLLOW_LINKS;
-  }
-
-  public final class LinkPermission extends java.security.BasicPermission {
-    ctor public LinkPermission(java.lang.String);
-    ctor public LinkPermission(java.lang.String, java.lang.String);
-  }
-
-  public class NoSuchFileException extends java.nio.file.FileSystemException {
-    ctor public NoSuchFileException(java.lang.String);
-    ctor public NoSuchFileException(java.lang.String, java.lang.String, java.lang.String);
-  }
-
-  public class NotDirectoryException extends java.nio.file.FileSystemException {
-    ctor public NotDirectoryException(java.lang.String);
-  }
-
-  public class NotLinkException extends java.nio.file.FileSystemException {
-    ctor public NotLinkException(java.lang.String);
-    ctor public NotLinkException(java.lang.String, java.lang.String, java.lang.String);
-  }
-
-  public abstract interface OpenOption {
-  }
-
-  public abstract interface Path implements java.lang.Comparable java.lang.Iterable java.nio.file.Watchable {
-    method public abstract int compareTo(java.nio.file.Path);
-    method public abstract boolean endsWith(java.nio.file.Path);
-    method public abstract boolean endsWith(java.lang.String);
-    method public abstract boolean equals(java.lang.Object);
-    method public abstract java.nio.file.Path getFileName();
-    method public abstract java.nio.file.FileSystem getFileSystem();
-    method public abstract java.nio.file.Path getName(int);
-    method public abstract int getNameCount();
-    method public abstract java.nio.file.Path getParent();
-    method public abstract java.nio.file.Path getRoot();
-    method public abstract int hashCode();
-    method public abstract boolean isAbsolute();
-    method public abstract java.util.Iterator<java.nio.file.Path> iterator();
-    method public abstract java.nio.file.Path normalize();
-    method public abstract java.nio.file.WatchKey register(java.nio.file.WatchService, java.nio.file.WatchEvent.Kind<?>[], java.nio.file.WatchEvent.Modifier...) throws java.io.IOException;
-    method public abstract java.nio.file.WatchKey register(java.nio.file.WatchService, java.nio.file.WatchEvent.Kind<?>...) throws java.io.IOException;
-    method public abstract java.nio.file.Path relativize(java.nio.file.Path);
-    method public abstract java.nio.file.Path resolve(java.nio.file.Path);
-    method public abstract java.nio.file.Path resolve(java.lang.String);
-    method public abstract java.nio.file.Path resolveSibling(java.nio.file.Path);
-    method public abstract java.nio.file.Path resolveSibling(java.lang.String);
-    method public abstract boolean startsWith(java.nio.file.Path);
-    method public abstract boolean startsWith(java.lang.String);
-    method public abstract java.nio.file.Path subpath(int, int);
-    method public abstract java.nio.file.Path toAbsolutePath();
-    method public abstract java.io.File toFile();
-    method public abstract java.nio.file.Path toRealPath(java.nio.file.LinkOption...) throws java.io.IOException;
-    method public abstract java.lang.String toString();
-    method public abstract java.net.URI toUri();
-  }
-
-  public abstract interface PathMatcher {
-    method public abstract boolean matches(java.nio.file.Path);
-  }
-
-  public final class Paths {
-    method public static java.nio.file.Path get(java.lang.String, java.lang.String...);
-    method public static java.nio.file.Path get(java.net.URI);
-  }
-
-  public class ProviderMismatchException extends java.lang.IllegalArgumentException {
-    ctor public ProviderMismatchException();
-    ctor public ProviderMismatchException(java.lang.String);
-  }
-
-  public class ProviderNotFoundException extends java.lang.RuntimeException {
-    ctor public ProviderNotFoundException();
-    ctor public ProviderNotFoundException(java.lang.String);
-  }
-
-  public class ReadOnlyFileSystemException extends java.lang.UnsupportedOperationException {
-    ctor public ReadOnlyFileSystemException();
-  }
-
-  public abstract interface SecureDirectoryStream implements java.nio.file.DirectoryStream {
-    method public abstract void deleteDirectory(T) throws java.io.IOException;
-    method public abstract void deleteFile(T) throws java.io.IOException;
-    method public abstract V getFileAttributeView(java.lang.Class<V>);
-    method public abstract V getFileAttributeView(T, java.lang.Class<V>, java.nio.file.LinkOption...);
-    method public abstract void move(T, java.nio.file.SecureDirectoryStream<T>, T) throws java.io.IOException;
-    method public abstract java.nio.channels.SeekableByteChannel newByteChannel(T, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public abstract java.nio.file.SecureDirectoryStream<T> newDirectoryStream(T, java.nio.file.LinkOption...) throws java.io.IOException;
-  }
-
-  public final class StandardCopyOption extends java.lang.Enum implements java.nio.file.CopyOption {
-    method public static java.nio.file.StandardCopyOption valueOf(java.lang.String);
-    method public static final java.nio.file.StandardCopyOption[] values();
-    enum_constant public static final java.nio.file.StandardCopyOption ATOMIC_MOVE;
-    enum_constant public static final java.nio.file.StandardCopyOption COPY_ATTRIBUTES;
-    enum_constant public static final java.nio.file.StandardCopyOption REPLACE_EXISTING;
-  }
-
-  public final class StandardOpenOption extends java.lang.Enum implements java.nio.file.OpenOption {
-    method public static java.nio.file.StandardOpenOption valueOf(java.lang.String);
-    method public static final java.nio.file.StandardOpenOption[] values();
-    enum_constant public static final java.nio.file.StandardOpenOption APPEND;
-    enum_constant public static final java.nio.file.StandardOpenOption CREATE;
-    enum_constant public static final java.nio.file.StandardOpenOption CREATE_NEW;
-    enum_constant public static final java.nio.file.StandardOpenOption DELETE_ON_CLOSE;
-    enum_constant public static final java.nio.file.StandardOpenOption DSYNC;
-    enum_constant public static final java.nio.file.StandardOpenOption READ;
-    enum_constant public static final java.nio.file.StandardOpenOption SPARSE;
-    enum_constant public static final java.nio.file.StandardOpenOption SYNC;
-    enum_constant public static final java.nio.file.StandardOpenOption TRUNCATE_EXISTING;
-    enum_constant public static final java.nio.file.StandardOpenOption WRITE;
-  }
-
-  public final class StandardWatchEventKinds {
-    field public static final java.nio.file.WatchEvent.Kind<java.nio.file.Path> ENTRY_CREATE;
-    field public static final java.nio.file.WatchEvent.Kind<java.nio.file.Path> ENTRY_DELETE;
-    field public static final java.nio.file.WatchEvent.Kind<java.nio.file.Path> ENTRY_MODIFY;
-    field public static final java.nio.file.WatchEvent.Kind<java.lang.Object> OVERFLOW;
-  }
-
-  public abstract interface WatchEvent {
-    method public abstract T context();
-    method public abstract int count();
-    method public abstract java.nio.file.WatchEvent.Kind<T> kind();
-  }
-
-  public static abstract interface WatchEvent.Kind {
-    method public abstract java.lang.String name();
-    method public abstract java.lang.Class<T> type();
-  }
-
-  public static abstract interface WatchEvent.Modifier {
-    method public abstract java.lang.String name();
-  }
-
-  public abstract interface WatchKey {
-    method public abstract void cancel();
-    method public abstract boolean isValid();
-    method public abstract java.util.List<java.nio.file.WatchEvent<?>> pollEvents();
-    method public abstract boolean reset();
-    method public abstract java.nio.file.Watchable watchable();
-  }
-
-  public abstract interface WatchService implements java.io.Closeable {
-    method public abstract void close() throws java.io.IOException;
-    method public abstract java.nio.file.WatchKey poll();
-    method public abstract java.nio.file.WatchKey poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public abstract java.nio.file.WatchKey take() throws java.lang.InterruptedException;
-  }
-
-  public abstract interface Watchable {
-    method public abstract java.nio.file.WatchKey register(java.nio.file.WatchService, java.nio.file.WatchEvent.Kind<?>[], java.nio.file.WatchEvent.Modifier...) throws java.io.IOException;
-    method public abstract java.nio.file.WatchKey register(java.nio.file.WatchService, java.nio.file.WatchEvent.Kind<?>...) throws java.io.IOException;
-  }
-
-}
-
-package java.nio.file.attribute {
-
-  public final class AclEntry {
-    method public java.util.Set<java.nio.file.attribute.AclEntryFlag> flags();
-    method public static java.nio.file.attribute.AclEntry.Builder newBuilder();
-    method public static java.nio.file.attribute.AclEntry.Builder newBuilder(java.nio.file.attribute.AclEntry);
-    method public java.util.Set<java.nio.file.attribute.AclEntryPermission> permissions();
-    method public java.nio.file.attribute.UserPrincipal principal();
-    method public java.nio.file.attribute.AclEntryType type();
-  }
-
-  public static final class AclEntry.Builder {
-    method public java.nio.file.attribute.AclEntry build();
-    method public java.nio.file.attribute.AclEntry.Builder setFlags(java.util.Set<java.nio.file.attribute.AclEntryFlag>);
-    method public java.nio.file.attribute.AclEntry.Builder setFlags(java.nio.file.attribute.AclEntryFlag...);
-    method public java.nio.file.attribute.AclEntry.Builder setPermissions(java.util.Set<java.nio.file.attribute.AclEntryPermission>);
-    method public java.nio.file.attribute.AclEntry.Builder setPermissions(java.nio.file.attribute.AclEntryPermission...);
-    method public java.nio.file.attribute.AclEntry.Builder setPrincipal(java.nio.file.attribute.UserPrincipal);
-    method public java.nio.file.attribute.AclEntry.Builder setType(java.nio.file.attribute.AclEntryType);
-  }
-
-  public final class AclEntryFlag extends java.lang.Enum {
-    method public static java.nio.file.attribute.AclEntryFlag valueOf(java.lang.String);
-    method public static final java.nio.file.attribute.AclEntryFlag[] values();
-    enum_constant public static final java.nio.file.attribute.AclEntryFlag DIRECTORY_INHERIT;
-    enum_constant public static final java.nio.file.attribute.AclEntryFlag FILE_INHERIT;
-    enum_constant public static final java.nio.file.attribute.AclEntryFlag INHERIT_ONLY;
-    enum_constant public static final java.nio.file.attribute.AclEntryFlag NO_PROPAGATE_INHERIT;
-  }
-
-  public final class AclEntryPermission extends java.lang.Enum {
-    method public static java.nio.file.attribute.AclEntryPermission valueOf(java.lang.String);
-    method public static final java.nio.file.attribute.AclEntryPermission[] values();
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission APPEND_DATA;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission DELETE;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission DELETE_CHILD;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission EXECUTE;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_ACL;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_ATTRIBUTES;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_DATA;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_NAMED_ATTRS;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission SYNCHRONIZE;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_ACL;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_ATTRIBUTES;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_DATA;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_NAMED_ATTRS;
-    enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_OWNER;
-    field public static final java.nio.file.attribute.AclEntryPermission ADD_FILE;
-    field public static final java.nio.file.attribute.AclEntryPermission ADD_SUBDIRECTORY;
-    field public static final java.nio.file.attribute.AclEntryPermission LIST_DIRECTORY;
-  }
-
-  public final class AclEntryType extends java.lang.Enum {
-    method public static java.nio.file.attribute.AclEntryType valueOf(java.lang.String);
-    method public static final java.nio.file.attribute.AclEntryType[] values();
-    enum_constant public static final java.nio.file.attribute.AclEntryType ALARM;
-    enum_constant public static final java.nio.file.attribute.AclEntryType ALLOW;
-    enum_constant public static final java.nio.file.attribute.AclEntryType AUDIT;
-    enum_constant public static final java.nio.file.attribute.AclEntryType DENY;
-  }
-
-  public abstract interface AclFileAttributeView implements java.nio.file.attribute.FileOwnerAttributeView {
-    method public abstract java.util.List<java.nio.file.attribute.AclEntry> getAcl() throws java.io.IOException;
-    method public abstract java.lang.String name();
-    method public abstract void setAcl(java.util.List<java.nio.file.attribute.AclEntry>) throws java.io.IOException;
-  }
-
-  public abstract interface AttributeView {
-    method public abstract java.lang.String name();
-  }
-
-  public abstract interface BasicFileAttributeView implements java.nio.file.attribute.FileAttributeView {
-    method public abstract java.lang.String name();
-    method public abstract java.nio.file.attribute.BasicFileAttributes readAttributes() throws java.io.IOException;
-    method public abstract void setTimes(java.nio.file.attribute.FileTime, java.nio.file.attribute.FileTime, java.nio.file.attribute.FileTime) throws java.io.IOException;
-  }
-
-  public abstract interface BasicFileAttributes {
-    method public abstract java.nio.file.attribute.FileTime creationTime();
-    method public abstract java.lang.Object fileKey();
-    method public abstract boolean isDirectory();
-    method public abstract boolean isOther();
-    method public abstract boolean isRegularFile();
-    method public abstract boolean isSymbolicLink();
-    method public abstract java.nio.file.attribute.FileTime lastAccessTime();
-    method public abstract java.nio.file.attribute.FileTime lastModifiedTime();
-    method public abstract long size();
-  }
-
-  public abstract interface DosFileAttributeView implements java.nio.file.attribute.BasicFileAttributeView {
-    method public abstract java.lang.String name();
-    method public abstract java.nio.file.attribute.DosFileAttributes readAttributes() throws java.io.IOException;
-    method public abstract void setArchive(boolean) throws java.io.IOException;
-    method public abstract void setHidden(boolean) throws java.io.IOException;
-    method public abstract void setReadOnly(boolean) throws java.io.IOException;
-    method public abstract void setSystem(boolean) throws java.io.IOException;
-  }
-
-  public abstract interface DosFileAttributes implements java.nio.file.attribute.BasicFileAttributes {
-    method public abstract boolean isArchive();
-    method public abstract boolean isHidden();
-    method public abstract boolean isReadOnly();
-    method public abstract boolean isSystem();
-  }
-
-  public abstract interface FileAttribute {
-    method public abstract java.lang.String name();
-    method public abstract T value();
-  }
-
-  public abstract interface FileAttributeView implements java.nio.file.attribute.AttributeView {
-  }
-
-  public abstract interface FileOwnerAttributeView implements java.nio.file.attribute.FileAttributeView {
-    method public abstract java.nio.file.attribute.UserPrincipal getOwner() throws java.io.IOException;
-    method public abstract java.lang.String name();
-    method public abstract void setOwner(java.nio.file.attribute.UserPrincipal) throws java.io.IOException;
-  }
-
-  public abstract interface FileStoreAttributeView implements java.nio.file.attribute.AttributeView {
-  }
-
-  public final class FileTime implements java.lang.Comparable {
-    method public int compareTo(java.nio.file.attribute.FileTime);
-    method public static java.nio.file.attribute.FileTime from(long, java.util.concurrent.TimeUnit);
-    method public static java.nio.file.attribute.FileTime fromMillis(long);
-    method public long to(java.util.concurrent.TimeUnit);
-    method public long toMillis();
-  }
-
-  public abstract interface GroupPrincipal implements java.nio.file.attribute.UserPrincipal {
-  }
-
-  public abstract interface PosixFileAttributeView implements java.nio.file.attribute.BasicFileAttributeView java.nio.file.attribute.FileOwnerAttributeView {
-    method public abstract java.lang.String name();
-    method public abstract java.nio.file.attribute.PosixFileAttributes readAttributes() throws java.io.IOException;
-    method public abstract void setGroup(java.nio.file.attribute.GroupPrincipal) throws java.io.IOException;
-    method public abstract void setPermissions(java.util.Set<java.nio.file.attribute.PosixFilePermission>) throws java.io.IOException;
-  }
-
-  public abstract interface PosixFileAttributes implements java.nio.file.attribute.BasicFileAttributes {
-    method public abstract java.nio.file.attribute.GroupPrincipal group();
-    method public abstract java.nio.file.attribute.UserPrincipal owner();
-    method public abstract java.util.Set<java.nio.file.attribute.PosixFilePermission> permissions();
-  }
-
-  public final class PosixFilePermission extends java.lang.Enum {
-    method public static java.nio.file.attribute.PosixFilePermission valueOf(java.lang.String);
-    method public static final java.nio.file.attribute.PosixFilePermission[] values();
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission GROUP_EXECUTE;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission GROUP_READ;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission GROUP_WRITE;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission OTHERS_EXECUTE;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission OTHERS_READ;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission OTHERS_WRITE;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission OWNER_EXECUTE;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission OWNER_READ;
-    enum_constant public static final java.nio.file.attribute.PosixFilePermission OWNER_WRITE;
-  }
-
-  public final class PosixFilePermissions {
-    method public static java.nio.file.attribute.FileAttribute<java.util.Set<java.nio.file.attribute.PosixFilePermission>> asFileAttribute(java.util.Set<java.nio.file.attribute.PosixFilePermission>);
-    method public static java.util.Set<java.nio.file.attribute.PosixFilePermission> fromString(java.lang.String);
-    method public static java.lang.String toString(java.util.Set<java.nio.file.attribute.PosixFilePermission>);
-  }
-
-  public abstract interface UserPrincipal implements java.security.Principal {
-  }
-
-  public abstract class UserPrincipalLookupService {
-    ctor protected UserPrincipalLookupService();
-    method public abstract java.nio.file.attribute.GroupPrincipal lookupPrincipalByGroupName(java.lang.String) throws java.io.IOException;
-    method public abstract java.nio.file.attribute.UserPrincipal lookupPrincipalByName(java.lang.String) throws java.io.IOException;
-  }
-
-  public class UserPrincipalNotFoundException extends java.io.IOException {
-    ctor public UserPrincipalNotFoundException(java.lang.String);
-    method public java.lang.String getName();
-  }
-
-}
-
-package java.nio.file.spi {
-
-  public abstract class FileSystemProvider {
-    ctor protected FileSystemProvider();
-    method public abstract void checkAccess(java.nio.file.Path, java.nio.file.AccessMode...) throws java.io.IOException;
-    method public abstract void copy(java.nio.file.Path, java.nio.file.Path, java.nio.file.CopyOption...) throws java.io.IOException;
-    method public abstract void createDirectory(java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public void createLink(java.nio.file.Path, java.nio.file.Path) throws java.io.IOException;
-    method public void createSymbolicLink(java.nio.file.Path, java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public abstract void delete(java.nio.file.Path) throws java.io.IOException;
-    method public boolean deleteIfExists(java.nio.file.Path) throws java.io.IOException;
-    method public abstract V getFileAttributeView(java.nio.file.Path, java.lang.Class<V>, java.nio.file.LinkOption...);
-    method public abstract java.nio.file.FileStore getFileStore(java.nio.file.Path) throws java.io.IOException;
-    method public abstract java.nio.file.FileSystem getFileSystem(java.net.URI);
-    method public abstract java.nio.file.Path getPath(java.net.URI);
-    method public abstract java.lang.String getScheme();
-    method public static java.util.List<java.nio.file.spi.FileSystemProvider> installedProviders();
-    method public abstract boolean isHidden(java.nio.file.Path) throws java.io.IOException;
-    method public abstract boolean isSameFile(java.nio.file.Path, java.nio.file.Path) throws java.io.IOException;
-    method public abstract void move(java.nio.file.Path, java.nio.file.Path, java.nio.file.CopyOption...) throws java.io.IOException;
-    method public java.nio.channels.AsynchronousFileChannel newAsynchronousFileChannel(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.util.concurrent.ExecutorService, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public abstract java.nio.channels.SeekableByteChannel newByteChannel(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public abstract java.nio.file.DirectoryStream<java.nio.file.Path> newDirectoryStream(java.nio.file.Path, java.nio.file.DirectoryStream.Filter<? super java.nio.file.Path>) throws java.io.IOException;
-    method public java.nio.channels.FileChannel newFileChannel(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public abstract java.nio.file.FileSystem newFileSystem(java.net.URI, java.util.Map<java.lang.String, ?>) throws java.io.IOException;
-    method public java.nio.file.FileSystem newFileSystem(java.nio.file.Path, java.util.Map<java.lang.String, ?>) throws java.io.IOException;
-    method public java.io.InputStream newInputStream(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public java.io.OutputStream newOutputStream(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public abstract A readAttributes(java.nio.file.Path, java.lang.Class<A>, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public abstract java.util.Map<java.lang.String, java.lang.Object> readAttributes(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public java.nio.file.Path readSymbolicLink(java.nio.file.Path) throws java.io.IOException;
-    method public abstract void setAttribute(java.nio.file.Path, java.lang.String, java.lang.Object, java.nio.file.LinkOption...) throws java.io.IOException;
-  }
-
-  public abstract class FileTypeDetector {
-    ctor protected FileTypeDetector();
-    method public abstract java.lang.String probeContentType(java.nio.file.Path) throws java.io.IOException;
-  }
-
-}
-
 package java.security {
 
   public final class AccessControlContext {
@@ -53658,6 +54386,7 @@
     method public static java.security.cert.CertPathBuilder getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
     method public static java.security.cert.CertPathBuilder getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
     method public final java.security.Provider getProvider();
+    method public final java.security.cert.CertPathChecker getRevocationChecker();
   }
 
   public class CertPathBuilderException extends java.security.GeneralSecurityException {
@@ -53675,6 +54404,13 @@
   public abstract class CertPathBuilderSpi {
     ctor public CertPathBuilderSpi();
     method public abstract java.security.cert.CertPathBuilderResult engineBuild(java.security.cert.CertPathParameters) throws java.security.cert.CertPathBuilderException, java.security.InvalidAlgorithmParameterException;
+    method public java.security.cert.CertPathChecker engineGetRevocationChecker();
+  }
+
+  public abstract interface CertPathChecker {
+    method public abstract void check(java.security.cert.Certificate) throws java.security.cert.CertPathValidatorException;
+    method public abstract void init(boolean) throws java.security.cert.CertPathValidatorException;
+    method public abstract boolean isForwardCheckingSupported();
   }
 
   public abstract interface CertPathParameters implements java.lang.Cloneable {
@@ -53689,6 +54425,7 @@
     method public static java.security.cert.CertPathValidator getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
     method public static java.security.cert.CertPathValidator getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
     method public final java.security.Provider getProvider();
+    method public final java.security.cert.CertPathChecker getRevocationChecker();
     method public final java.security.cert.CertPathValidatorResult validate(java.security.cert.CertPath, java.security.cert.CertPathParameters) throws java.security.cert.CertPathValidatorException, java.security.InvalidAlgorithmParameterException;
   }
 
@@ -53725,6 +54462,7 @@
 
   public abstract class CertPathValidatorSpi {
     ctor public CertPathValidatorSpi();
+    method public java.security.cert.CertPathChecker engineGetRevocationChecker();
     method public abstract java.security.cert.CertPathValidatorResult engineValidate(java.security.cert.CertPath, java.security.cert.CertPathParameters) throws java.security.cert.CertPathValidatorException, java.security.InvalidAlgorithmParameterException;
   }
 
@@ -53883,9 +54621,10 @@
     method public java.security.cert.CertPath getCertPath();
   }
 
-  public abstract class PKIXCertPathChecker implements java.lang.Cloneable {
+  public abstract class PKIXCertPathChecker implements java.security.cert.CertPathChecker java.lang.Cloneable {
     ctor protected PKIXCertPathChecker();
     method public abstract void check(java.security.cert.Certificate, java.util.Collection<java.lang.String>) throws java.security.cert.CertPathValidatorException;
+    method public void check(java.security.cert.Certificate) throws java.security.cert.CertPathValidatorException;
     method public java.lang.Object clone();
     method public abstract java.util.Set<java.lang.String> getSupportedExtensions();
     method public abstract void init(boolean) throws java.security.cert.CertPathValidatorException;
@@ -53945,6 +54684,30 @@
     enum_constant public static final java.security.cert.PKIXReason UNRECOGNIZED_CRIT_EXT;
   }
 
+  public abstract class PKIXRevocationChecker extends java.security.cert.PKIXCertPathChecker {
+    ctor protected PKIXRevocationChecker();
+    method public java.util.List<java.security.cert.Extension> getOcspExtensions();
+    method public java.net.URI getOcspResponder();
+    method public java.security.cert.X509Certificate getOcspResponderCert();
+    method public java.util.Map<java.security.cert.X509Certificate, byte[]> getOcspResponses();
+    method public java.util.Set<java.security.cert.PKIXRevocationChecker.Option> getOptions();
+    method public abstract java.util.List<java.security.cert.CertPathValidatorException> getSoftFailExceptions();
+    method public void setOcspExtensions(java.util.List<java.security.cert.Extension>);
+    method public void setOcspResponder(java.net.URI);
+    method public void setOcspResponderCert(java.security.cert.X509Certificate);
+    method public void setOcspResponses(java.util.Map<java.security.cert.X509Certificate, byte[]>);
+    method public void setOptions(java.util.Set<java.security.cert.PKIXRevocationChecker.Option>);
+  }
+
+  public static final class PKIXRevocationChecker.Option extends java.lang.Enum {
+    method public static java.security.cert.PKIXRevocationChecker.Option valueOf(java.lang.String);
+    method public static final java.security.cert.PKIXRevocationChecker.Option[] values();
+    enum_constant public static final java.security.cert.PKIXRevocationChecker.Option NO_FALLBACK;
+    enum_constant public static final java.security.cert.PKIXRevocationChecker.Option ONLY_END_ENTITY;
+    enum_constant public static final java.security.cert.PKIXRevocationChecker.Option PREFER_CRLS;
+    enum_constant public static final java.security.cert.PKIXRevocationChecker.Option SOFT_FAIL;
+  }
+
   public abstract interface PolicyNode {
     method public abstract java.util.Iterator<? extends java.security.cert.PolicyNode> getChildren();
     method public abstract int getDepth();
@@ -54104,6 +54867,7 @@
     method public javax.security.auth.x500.X500Principal getSubjectX500Principal();
     method public abstract byte[] getTBSCertificate() throws java.security.cert.CertificateEncodingException;
     method public abstract int getVersion();
+    method public void verify(java.security.PublicKey, java.security.Provider) throws java.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.SignatureException;
   }
 
   public abstract interface X509Extension {
@@ -57347,8 +58111,6 @@
     ctor public Scanner(java.io.InputStream, java.lang.String);
     ctor public Scanner(java.io.File) throws java.io.FileNotFoundException;
     ctor public Scanner(java.io.File, java.lang.String) throws java.io.FileNotFoundException;
-    ctor public Scanner(java.nio.file.Path) throws java.io.IOException;
-    ctor public Scanner(java.nio.file.Path, java.lang.String) throws java.io.IOException;
     ctor public Scanner(java.lang.String);
     ctor public Scanner(java.nio.channels.ReadableByteChannel);
     ctor public Scanner(java.nio.channels.ReadableByteChannel, java.lang.String);
@@ -58978,7 +59740,6 @@
     ctor public JarFile(java.io.File, boolean, int) throws java.io.IOException;
     method public java.util.jar.JarEntry getJarEntry(java.lang.String);
     method public java.util.jar.Manifest getManifest() throws java.io.IOException;
-    method public boolean hasClassPathAttribute() throws java.io.IOException;
     field public static final java.lang.String MANIFEST_NAME = "META-INF/MANIFEST.MF";
   }
 
@@ -59432,8 +60193,8 @@
     method public java.lang.StringBuffer appendTail(java.lang.StringBuffer);
     method public int end();
     method public int end(int);
-    method public boolean find(int);
     method public boolean find();
+    method public boolean find(int);
     method public java.lang.String group();
     method public java.lang.String group(int);
     method public int groupCount();
@@ -59461,8 +60222,8 @@
   }
 
   public final class Pattern implements java.io.Serializable {
-    method public static java.util.regex.Pattern compile(java.lang.String, int) throws java.util.regex.PatternSyntaxException;
     method public static java.util.regex.Pattern compile(java.lang.String);
+    method public static java.util.regex.Pattern compile(java.lang.String, int) throws java.util.regex.PatternSyntaxException;
     method public int flags();
     method public java.util.regex.Matcher matcher(java.lang.CharSequence);
     method public static boolean matches(java.lang.String, java.lang.CharSequence);
@@ -59477,6 +60238,7 @@
     field public static final int LITERAL = 16; // 0x10
     field public static final int MULTILINE = 8; // 0x8
     field public static final int UNICODE_CASE = 64; // 0x40
+    field public static final int UNICODE_CHARACTER_CLASS = 256; // 0x100
     field public static final int UNIX_LINES = 1; // 0x1
   }
 
diff --git a/api/test-removed.txt b/api/test-removed.txt
index f12e61e..2c6729d 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -199,6 +199,15 @@
 
 }
 
+package android.test.mock {
+
+  public deprecated class MockPackageManager extends android.content.pm.PackageManager {
+    method public deprecated java.lang.String getDefaultBrowserPackageName(int);
+    method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int);
+  }
+
+}
+
 package android.text.format {
 
   public class DateFormat {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 4f7a109..d45bc5d 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -47,7 +47,6 @@
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
-import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -79,7 +78,6 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.HashSet;
 import java.util.List;
 
 public class Am extends BaseCommand {
@@ -159,6 +157,8 @@
                 "       am stack start <DISPLAY_ID> <INTENT>\n" +
                 "       am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
                 "       am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
+                "       am stack resize-animated <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
+                "       am stack resize-docked-stack <LEFT,TOP,RIGHT,BOTTOM> [<TASK_LEFT,TASK_TOP,TASK_RIGHT,TASK_BOTTOM>]\n" +
                 "       am stack size-docked-stack-test: <STEP_SIZE> <l|t|r|b> [DELAY_MS]\n" +
                 "       am stack move-top-activity-to-pinned-stack: <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
                 "       am stack positiontask <TASK_ID> <STACK_ID> <POSITION>\n" +
@@ -299,7 +299,11 @@
                 "am stack movetask: move <TASK_ID> from its current stack to the top (true) or" +
                 "   bottom (false) of <STACK_ID>.\n" +
                 "\n" +
-                "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>." +
+                "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>.\n" +
+                "\n" +
+                "am stack resize-docked-stack: change docked stack to <LEFT,TOP,RIGHT,BOTTOM>\n" +
+                "   and supplying temporary different task bounds indicated by\n" +
+                "   <TASK_LEFT,TOP,RIGHT,BOTTOM>\n" +
                 "\n" +
                 "am stack size-docked-stack-test: test command for sizing docked stack by\n" +
                 "   <STEP_SIZE> increments from the side <l>eft, <t>op, <r>ight, or <b>ottom\n" +
@@ -1075,16 +1079,16 @@
 
     private void runBugReport() throws Exception {
         String opt;
-        boolean progress = false;
+        int bugreportType = ActivityManager.BUGREPORT_OPTION_FULL;
         while ((opt=nextOption()) != null) {
             if (opt.equals("--progress")) {
-                progress = true;
+                bugreportType = ActivityManager.BUGREPORT_OPTION_INTERACTIVE;
             } else {
                 System.err.println("Error: Unknown option: " + opt);
                 return;
             }
         }
-        mAm.requestBugReport(progress);
+        mAm.requestBugReport(bugreportType);
         System.out.println("Your lovely bug report is being created; please be patient.");
     }
 
@@ -1683,6 +1687,12 @@
             case "resize":
                 runStackResize();
                 break;
+            case "resize-animated":
+                runStackResizeAnimated();
+                break;
+            case "resize-docked-stack":
+                runStackResizeDocked();
+                break;
             case "positiontask":
                 runStackPositionTask();
                 break;
@@ -1748,17 +1758,43 @@
             System.err.println("Error: invalid input bounds");
             return;
         }
-        resizeStack(stackId, bounds, 0);
+        resizeStack(stackId, bounds, 0, false);
     }
 
-    private void resizeStack(int stackId, Rect bounds, int delayMs) throws Exception {
+    private void runStackResizeAnimated() throws Exception {
+        String stackIdStr = nextArgRequired();
+        int stackId = Integer.valueOf(stackIdStr);
+        final Rect bounds = getBounds();
+        if (bounds == null) {
+            System.err.println("Error: invalid input bounds");
+            return;
+        }
+        resizeStack(stackId, bounds, 0, true);
+    }
+
+    private void runStackResizeDocked() throws Exception {
+        final Rect bounds = getBounds();
+        final Rect taskBounds = getBounds();
+        if (bounds == null || taskBounds == null) {
+            System.err.println("Error: invalid input bounds");
+            return;
+        }
+        try {
+            mAm.resizeDockedStack(bounds, taskBounds, null, null, null);
+        } catch (RemoteException e) {
+            showError("Error: resizing docked stack " + e);
+        }
+    }
+
+    private void resizeStack(int stackId, Rect bounds, int delayMs, boolean animate)
+            throws Exception {
         if (bounds == null) {
             showError("Error: invalid input bounds");
             return;
         }
 
         try {
-            mAm.resizeStack(stackId, bounds, false);
+            mAm.resizeStack(stackId, bounds, false, false, animate);
             Thread.sleep(delayMs);
         } catch (RemoteException e) {
             showError("Error: resizing stack " + e);
@@ -1872,7 +1908,7 @@
             maxChange = Math.min(stepSize, currentPoint - minPoint);
             currentPoint -= maxChange;
             setBoundsSide(bounds, side, currentPoint);
-            resizeStack(DOCKED_STACK_ID, bounds, delayMs);
+            resizeStack(DOCKED_STACK_ID, bounds, delayMs, false);
         }
 
         System.out.println("Growing docked stack side=" + side);
@@ -1880,7 +1916,7 @@
             maxChange = Math.min(stepSize, maxPoint - currentPoint);
             currentPoint += maxChange;
             setBoundsSide(bounds, side, currentPoint);
-            resizeStack(DOCKED_STACK_ID, bounds, delayMs);
+            resizeStack(DOCKED_STACK_ID, bounds, delayMs, false);
         }
 
         System.out.println("Back to Original size side=" + side);
@@ -1888,7 +1924,7 @@
             maxChange = Math.min(stepSize, currentPoint - startPoint);
             currentPoint -= maxChange;
             setBoundsSide(bounds, side, currentPoint);
-            resizeStack(DOCKED_STACK_ID, bounds, delayMs);
+            resizeStack(DOCKED_STACK_ID, bounds, delayMs, false);
         }
     }
 
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 9728e38..67d63a4 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -16,8 +16,11 @@
 
 package com.android.commands.bmgr;
 
+import android.app.backup.BackupManager;
+import android.app.backup.BackupProgress;
 import android.app.backup.RestoreSet;
 import android.app.backup.IBackupManager;
+import android.app.backup.IBackupObserver;
 import android.app.backup.IRestoreObserver;
 import android.app.backup.IRestoreSession;
 import android.os.RemoteException;
@@ -108,6 +111,11 @@
             return;
         }
 
+        if ("backupnow".equals(op)) {
+            doBackupNow();
+            return;
+        }
+
         System.err.println("Unknown command");
         showUsage();
     }
@@ -189,6 +197,88 @@
         }
     }
 
+    class BackupObserver extends IBackupObserver.Stub {
+        boolean done = false;
+
+        @Override
+        public void onUpdate(String currentPackage, BackupProgress backupProgress) {
+            System.out.println(
+                "onUpdate: " + currentPackage + " with progress: " + backupProgress.bytesTransferred
+                    + "/" + backupProgress.bytesExpected);
+        }
+
+        @Override
+        public void onResult(String currentPackage, int status) {
+            System.out.println("onResult: " + currentPackage + " with result: "
+                    + convertBackupStatusToString(status));
+        }
+
+        @Override
+        public void backupFinished(int status) {
+            System.out.println("backupFinished: " + convertBackupStatusToString(status));
+            synchronized (this) {
+                done = true;
+                this.notify();
+            }
+        }
+
+        public void waitForCompletion() {
+            // The backupFinished() callback will throw the 'done' flag; we
+            // just sit and wait on that notification.
+            synchronized (this) {
+                while (!this.done) {
+                    try {
+                        this.wait();
+                    } catch (InterruptedException ex) {
+                    }
+                }
+            }
+        }
+
+    }
+
+    private static String convertBackupStatusToString(int errorCode) {
+        switch (errorCode) {
+            case BackupManager.SUCCESS:
+                return "Success";
+            case BackupManager.ERROR_BACKUP_NOT_ALLOWED:
+                return "Backup is not allowed";
+            case BackupManager.ERROR_PACKAGE_NOT_FOUND:
+                return "Package not found";
+            case BackupManager.ERROR_TRANSPORT_ABORTED:
+                return "Transport error";
+            case BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED:
+                return "Transport rejected package";
+            case BackupManager.ERROR_AGENT_FAILURE:
+                return "Agent error";
+            default:
+                return "Unknown error";
+        }
+    }
+
+    private void doBackupNow() {
+        String pkg;
+        ArrayList<String> allPkgs = new ArrayList<String>();
+        while ((pkg = nextArg()) != null) {
+            allPkgs.add(pkg);
+        }
+        if (allPkgs.size() > 0) {
+            try {
+                BackupObserver observer = new BackupObserver();
+                int err = mBmgr.requestBackup(allPkgs.toArray(new String[allPkgs.size()]), observer);
+                if (err == 0) {
+                    // Off and running -- wait for the backup to complete
+                    observer.waitForCompletion();
+                } else {
+                    System.err.println("Unable to run backup");
+                }
+            } catch (RemoteException e) {
+                System.err.println(e.toString());
+                System.err.println(BMGR_NOT_RUNNING_ERR);
+            }
+        }
+    }
+
     private void doTransport() {
         try {
             String which = nextArg();
@@ -528,5 +618,10 @@
         System.err.println("");
         System.err.println("The 'fullbackup' command induces a full-data stream backup for one or more");
         System.err.println("packages.  The data is sent via the currently active transport.");
+        System.err.println("");
+        System.err.println("The 'backupnow' command runs an immediate backup for one or more packages.");
+        System.err.println("For each package it will run key/value or full data backup ");
+        System.err.println("depending on the package's manifest declarations.");
+        System.err.println("The data is sent via the currently active transport.");
     }
 }
diff --git a/cmds/dpm/src/com/android/commands/dpm/Dpm.java b/cmds/dpm/src/com/android/commands/dpm/Dpm.java
index 6dc3cd1..b83484d 100644
--- a/cmds/dpm/src/com/android/commands/dpm/Dpm.java
+++ b/cmds/dpm/src/com/android/commands/dpm/Dpm.java
@@ -18,6 +18,7 @@
 
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
+import android.app.admin.DevicePolicyManager;
 import android.app.admin.IDevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -143,6 +144,10 @@
             mDevicePolicyManager.removeActiveAdmin(mComponent, UserHandle.USER_SYSTEM);
             throw e;
         }
+
+        mDevicePolicyManager.setUserProvisioningState(
+                DevicePolicyManager.STATE_USER_SETUP_FINALIZED, mUserId);
+
         System.out.println("Success: Device owner set to package " + mComponent);
         System.out.println("Active admin set to component " + mComponent.toShortString());
     }
@@ -161,6 +166,10 @@
             mDevicePolicyManager.removeActiveAdmin(mComponent, mUserId);
             throw e;
         }
+
+        mDevicePolicyManager.setUserProvisioningState(
+                DevicePolicyManager.STATE_USER_SETUP_FINALIZED, mUserId);
+
         System.out.println("Success: Active admin and profile owner set to "
                 + mComponent.toShortString() + " for user " + mUserId);
     }
@@ -180,4 +189,4 @@
             throw new IllegalArgumentException ("Invalid integer argument '" + argument + "'", e);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index ad1b3b5..24449d4 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -376,6 +376,7 @@
                     != PackageInstaller.STATUS_SUCCESS) {
                 return 1;
             }
+            System.out.println("Success");
             return 0;
         } finally {
             try {
@@ -591,7 +592,6 @@
             } else {
                 System.err.println("Failure ["
                         + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
-                System.err.println("Failure details: " + result.getExtras());
             }
             return status;
         } finally {
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index b7c729b..63f6c92 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -19,11 +19,13 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.net.Uri;
+import android.os.IUserManager;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
-import android.text.TextUtils;
 
 import com.android.internal.os.BaseCommand;
 import com.android.internal.telecom.ITelecomService;
@@ -53,16 +55,17 @@
     private ComponentName mComponent;
     private String mAccountId;
     private ITelecomService mTelecomService;
+    private IUserManager mUserManager;
 
     @Override
     public void onShowUsage(PrintStream out) {
         out.println(
                 "usage: telecom [subcommand] [options]\n" +
-                "usage: telecom set-phone-account-enabled <COMPONENT> <ID>\n" +
-                "usage: telecom set-phone-account-disabled <COMPONENT> <ID>\n" +
-                "usage: telecom register-phone-account <COMPONENT> <ID> <LABEL>\n" +
-                "usage: telecom register-sim-phone-account <COMPONENT> <ID> <LABEL> <ADDRESS>\n" +
-                "usage: telecom unregister-phone-account <COMPONENT> <ID>\n" +
+                "usage: telecom set-phone-account-enabled <COMPONENT> <ID> <USER_SN>\n" +
+                "usage: telecom set-phone-account-disabled <COMPONENT> <ID> <USER_SN>\n" +
+                "usage: telecom register-phone-account <COMPONENT> <ID> <USER_SN> <LABEL>\n" +
+                "usage: telecom register-sim-phone-account <COMPONENT> <ID> <USER_SN> <LABEL> <ADDRESS>\n" +
+                "usage: telecom unregister-phone-account <COMPONENT> <ID> <USER_SN>\n" +
                 "usage: telecom set-default-dialer <PACKAGE>\n" +
                 "usage: telecom get-default-dialer\n" +
                 "usage: telecom get-system-dialer\n" +
@@ -89,6 +92,12 @@
             showError("Error: Could not access the Telecom Manager. Is the system running?");
             return;
         }
+        mUserManager = IUserManager.Stub
+                .asInterface(ServiceManager.getService(Context.USER_SERVICE));
+        if (mUserManager == null) {
+            showError("Error: Could not access the User Manager. Is the system running?");
+            return;
+        }
 
         String command = nextArgRequired();
         switch (command) {
@@ -183,10 +192,18 @@
         System.out.println(mTelecomService.getSystemDialerPackage());
     }
 
-    private PhoneAccountHandle getPhoneAccountHandleFromArgs() {
+    private PhoneAccountHandle getPhoneAccountHandleFromArgs() throws RemoteException{
         final ComponentName component = parseComponentName(nextArgRequired());
         final String accountId = nextArgRequired();
-        return new PhoneAccountHandle(component, accountId);
+        final String userSnInStr = nextArgRequired();
+        UserHandle userHandle;
+        try {
+            final int userSn = Integer.parseInt(userSnInStr);
+            userHandle = UserHandle.of(mUserManager.getUserHandle(userSn));
+        } catch (NumberFormatException ex) {
+            throw new IllegalArgumentException ("Invalid user serial number " + userSnInStr);
+        }
+        return new PhoneAccountHandle(component, accountId, userHandle);
     }
 
     private ComponentName parseComponentName(String component) {
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 468c145..be93926 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -16,11 +16,13 @@
 
 package android.accessibilityservice;
 
+import android.accessibilityservice.GestureDescription.MotionEventGenerator;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ParceledListSlice;
 import android.graphics.Region;
 import android.os.Handler;
 import android.os.IBinder;
@@ -29,8 +31,11 @@
 import android.os.RemoteException;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.view.KeyEvent;
+import android.view.MotionEvent;
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
 import android.view.accessibility.AccessibilityEvent;
@@ -41,13 +46,11 @@
 import com.android.internal.os.HandlerCaller;
 import com.android.internal.os.SomeArgs;
 
-import java.util.ArrayList;
 import java.util.List;
-import java.util.Map.Entry;
-import java.util.Set;
 
 /**
- * An accessibility service runs in the background and receives callbacks by the system
+ * Accessibility services are intended to assist users with disabilities in using
+ * Android devices and apps. They run in the background and receive callbacks by the system
  * when {@link AccessibilityEvent}s are fired. Such events denote some state transition
  * in the user interface, for example, the focus has changed, a button has been clicked,
  * etc. Such a service can optionally request the capability for querying the content
@@ -64,22 +67,31 @@
  * <h3>Lifecycle</h3>
  * <p>
  * The lifecycle of an accessibility service is managed exclusively by the system and
- * follows the established service life cycle. Additionally, starting or stopping an
- * accessibility service is triggered exclusively by an explicit user action through
- * enabling or disabling it in the device settings. After the system binds to a service it
- * calls {@link AccessibilityService#onServiceConnected()}. This method can be
- * overriden by clients that want to perform post binding setup.
+ * follows the established service life cycle. Starting an accessibility service is triggered
+ * exclusively by the user explicitly turning the service on in device settings. After the system
+ * binds to a service, it calls {@link AccessibilityService#onServiceConnected()}. This method can
+ * be overriden by clients that want to perform post binding setup.
+ * </p>
+ * <p>
+ * An accessibility service stops either when the user turns it off in device settings or when
+ * it calls {@link AccessibilityService#disableSelf()}.
  * </p>
  * <h3>Declaration</h3>
  * <p>
- * An accessibility is declared as any other service in an AndroidManifest.xml but it
- * must also specify that it handles the "android.accessibilityservice.AccessibilityService"
- * {@link android.content.Intent}. Failure to declare this intent will cause the system to
- * ignore the accessibility service. Additionally an accessibility service must request the
- * {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission to ensure
- * that only the system
- * can bind to it. Failure to declare this intent will cause the system to ignore the
- * accessibility service. Following is an example declaration:
+ * An accessibility is declared as any other service in an AndroidManifest.xml, but it
+ * must do two things:
+ * <ul>
+ *     <ol>
+ *         Specify that it handles the "android.accessibilityservice.AccessibilityService"
+ *         {@link android.content.Intent}.
+ *     </ol>
+ *     <ol>
+ *         Request the {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission to
+ *         ensure that only the system can bind to it.
+ *     </ol>
+ * </ul>
+ * If either of these items is missing, the system will ignore the accessibility service.
+ * Following is an example declaration:
  * </p>
  * <pre> &lt;service android:name=".MyAccessibilityService"
  *         android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"&gt;
@@ -133,48 +145,24 @@
  * </ul>
  * <h3>Retrieving window content</h3>
  * <p>
- * A service can specify in its declaration that it can retrieve the active window
- * content which is represented as a tree of {@link AccessibilityNodeInfo}. Note that
+ * A service can specify in its declaration that it can retrieve window
+ * content which is represented as a tree of {@link AccessibilityWindowInfo} and
+ * {@link AccessibilityNodeInfo} objects. Note that
  * declaring this capability requires that the service declares its configuration via
  * an XML resource referenced by {@link #SERVICE_META_DATA}.
  * </p>
  * <p>
- * For security purposes an accessibility service can retrieve only the content of the
- * currently active window. The currently active window is defined as the window from
- * which was fired the last event of the following types:
- * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED},
- * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
- * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT},
- * In other words, the last window that was shown or the last window that the user has touched
- * during touch exploration.
- * </p>
- * <p>
- * The entry point for retrieving window content is through calling
- * {@link AccessibilityEvent#getSource() AccessibilityEvent.getSource()} of the last received
- * event of the above types or a previous event from the same window
- * (see {@link AccessibilityEvent#getWindowId() AccessibilityEvent.getWindowId()}). Invoking
- * this method will return an {@link AccessibilityNodeInfo} that can be used to traverse the
- * window content which represented as a tree of such objects.
+ * Window content may be retrieved with
+ * {@link AccessibilityEvent#getSource() AccessibilityEvent.getSource()},
+ * {@link AccessibilityService#findFocus(int)},
+ * {@link AccessibilityService#getWindows()}, or
+ * {@link AccessibilityService#getRootInActiveWindow()}.
  * </p>
  * <p class="note">
  * <strong>Note</strong> An accessibility service may have requested to be notified for
- * a subset of the event types, thus be unaware that the active window has changed. Therefore
- * accessibility service that would like to retrieve window content should:
- * <ul>
- * <li>
- * Register for all event types with no notification timeout and keep track for the active
- * window by calling {@link AccessibilityEvent#getWindowId()} of the last received event and
- * compare this with the {@link AccessibilityNodeInfo#getWindowId()} before calling retrieval
- * methods on the latter.
- * </li>
- * <li>
- * Prepare that a retrieval method on {@link AccessibilityNodeInfo} may fail since the
- * active window has changed and the service did not get the accessibility event yet. Note
- * that it is possible to have a retrieval method failing even adopting the strategy
- * specified in the previous bullet because the accessibility event dispatch is asynchronous
- * and crosses process boundaries.
- * </li>
- * </ul>
+ * a subset of the event types, and thus be unaware when the node hierarchy has changed. It is also
+ * possible for a node to contain outdated information because the window content may change at any
+ * time.
  * </p>
  * <h3>Notification strategy</h3>
  * <p>
@@ -326,7 +314,6 @@
      *     android:settingsActivity="foo.bar.TestBackActivity"
      *     android:canRetrieveWindowContent="true"
      *     android:canRequestTouchExplorationMode="true"
-     *     android:canRequestEnhancedWebAccessibility="true"
      *     . . .
      * /&gt;</pre>
      */
@@ -376,6 +363,7 @@
         public boolean onKeyEvent(KeyEvent event);
         public void onMagnificationChanged(@NonNull Region region,
                 float scale, float centerX, float centerY);
+        public void onPerformGestureResult(int sequence, boolean completedSuccessfully);
     }
 
     private int mConnectionId;
@@ -388,6 +376,12 @@
 
     private MagnificationController mMagnificationController;
 
+    private int mGestureStatusCallbackSequence;
+
+    private SparseArray<GestureResultCallbackInfo> mGestureStatusCallbackInfos;
+
+    private final Object mLock = new Object();
+
     /**
      * Callback for {@link android.view.accessibility.AccessibilityEvent}s.
      *
@@ -519,6 +513,14 @@
      * is currently touching or the window with input focus, if the user is not
      * touching any window.
      * <p>
+     * The currently active window is defined as the window that most recently fired one
+     * of the following events:
+     * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED},
+     * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
+     * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}.
+     * In other words, the last window shown that also has input focus.
+     * </p>
+     * <p>
      * <strong>Note:</strong> In order to access the root node your service has
      * to declare the capability to retrieve window content by setting the
      * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
@@ -532,6 +534,22 @@
     }
 
     /**
+     * Disables the service. After calling this method, the service will be disabled and settings
+     * will show that it is turned off.
+     */
+    public final void disableSelf() {
+        final IAccessibilityServiceConnection connection =
+                AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
+        if (connection != null) {
+            try {
+                connection.disableSelf();
+            } catch (RemoteException re) {
+                throw new RuntimeException(re);
+            }
+        }
+    }
+
+    /**
      * Returns the magnification controller, which may be used to query and
      * modify the state of display magnification.
      * <p>
@@ -551,6 +569,88 @@
         return mMagnificationController;
     }
 
+    /**
+     * Dispatch a gesture to the touch screen. Any gestures currently in progress, whether from
+     * the user, this service, or another service, will be cancelled.
+     * <p>
+     * <strong>Note:</strong> In order to dispatch gestures, your service
+     * must declare the capability by setting the
+     * {@link android.R.styleable#AccessibilityService_canPerformGestures}
+     * property in its meta-data. For more information, see
+     * {@link #SERVICE_META_DATA}.
+     *
+     * @param gesture The gesture to dispatch
+     * @param callback The object to call back when the status of the gesture is known. If
+     * {@code null}, no status is reported.
+     * @param handler The handler on which to call back the {@code callback} object. If
+     * {@code null}, the object is called back on the service's main thread.
+     *
+     * @return {@code true} if the gesture is dispatched, {@code false} if not.
+     */
+    public final boolean dispatchGesture(@NonNull GestureDescription gesture,
+            @Nullable GestureResultCallback callback,
+            @Nullable Handler handler) {
+        final IAccessibilityServiceConnection connection =
+                AccessibilityInteractionClient.getInstance().getConnection(
+                        mConnectionId);
+        if (connection == null) {
+            return false;
+        }
+        List<MotionEvent> events = MotionEventGenerator.getMotionEventsFromGestureDescription(
+                gesture, 100);
+        try {
+            synchronized (mLock) {
+                connection.sendMotionEvents(++mGestureStatusCallbackSequence,
+                        new ParceledListSlice<>(events));
+                if (callback != null) {
+                    if (mGestureStatusCallbackInfos == null) {
+                        mGestureStatusCallbackInfos = new SparseArray<>();
+                    }
+                    GestureResultCallbackInfo callbackInfo = new GestureResultCallbackInfo(gesture,
+                            callback, handler);
+                    mGestureStatusCallbackInfos.put(mGestureStatusCallbackSequence, callbackInfo);
+                }
+            }
+        } catch (RemoteException re) {
+            throw new RuntimeException(re);
+        }
+        return true;
+    }
+
+    void onPerformGestureResult(int sequence, final boolean completedSuccessfully) {
+        if (mGestureStatusCallbackInfos == null) {
+            return;
+        }
+        GestureResultCallbackInfo callbackInfo;
+        synchronized (mLock) {
+            callbackInfo = mGestureStatusCallbackInfos.get(sequence);
+        }
+        final GestureResultCallbackInfo finalCallbackInfo = callbackInfo;
+        if ((callbackInfo != null) && (callbackInfo.gestureDescription != null)
+                && (callbackInfo.callback != null)) {
+            if (callbackInfo.handler != null) {
+                callbackInfo.handler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        if (completedSuccessfully) {
+                            finalCallbackInfo.callback
+                                    .onCompleted(finalCallbackInfo.gestureDescription);
+                        } else {
+                            finalCallbackInfo.callback
+                                    .onCancelled(finalCallbackInfo.gestureDescription);
+                        }
+                    }
+                });
+                return;
+            }
+            if (completedSuccessfully) {
+                callbackInfo.callback.onCompleted(callbackInfo.gestureDescription);
+            } else {
+                callbackInfo.callback.onCancelled(callbackInfo.gestureDescription);
+            }
+        }
+    }
+
     private void onMagnificationChanged(@NonNull Region region, float scale,
             float centerX, float centerY) {
         if (mMagnificationController != null) {
@@ -947,7 +1047,7 @@
      * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
      * Also the service has to opt-in to retrieve the interactive windows by
      * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
-     * flag.Otherwise, the search will be performed only in the active window.
+     * flag. Otherwise, the search will be performed only in the active window.
      * </p>
      *
      * @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
@@ -1082,6 +1182,11 @@
                     float scale, float centerX, float centerY) {
                 AccessibilityService.this.onMagnificationChanged(region, scale, centerX, centerY);
             }
+
+            @Override
+            public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
+                AccessibilityService.this.onPerformGestureResult(sequence, completedSuccessfully);
+            }
         });
     }
 
@@ -1100,6 +1205,7 @@
         private static final int DO_CLEAR_ACCESSIBILITY_CACHE = 5;
         private static final int DO_ON_KEY_EVENT = 6;
         private static final int DO_ON_MAGNIFICATION_CHANGED = 7;
+        private static final int DO_GESTURE_COMPLETE = 8;
 
         private final HandlerCaller mCaller;
 
@@ -1158,6 +1264,12 @@
             mCaller.sendMessage(message);
         }
 
+        public void onPerformGestureResult(int sequence, boolean successfully) {
+            Message message = mCaller.obtainMessageII(DO_GESTURE_COMPLETE, sequence,
+                    successfully ? 1 : 0);
+            mCaller.sendMessage(message);
+        }
+
         @Override
         public void executeMessage(Message message) {
             switch (message.what) {
@@ -1242,9 +1354,47 @@
                     mCallback.onMagnificationChanged(region, scale, centerX, centerY);
                 } return;
 
+                case DO_GESTURE_COMPLETE: {
+                    final boolean successfully = message.arg2 == 1;
+                    mCallback.onPerformGestureResult(message.arg1, successfully);
+                } return;
+
                 default :
                     Log.w(LOG_TAG, "Unknown message type " + message.what);
             }
         }
     }
+
+    /**
+     * Class used to report status of dispatched gestures
+     */
+    public static abstract class GestureResultCallback {
+        /** Called when the gesture has completed successfully
+         *
+         * @param gestureDescription The description of the gesture that completed.
+         */
+        public void onCompleted(GestureDescription gestureDescription) {
+        }
+
+        /** Called when the gesture was cancelled
+         *
+         * @param gestureDescription The description of the gesture that was cancelled.
+         */
+        public void onCancelled(GestureDescription gestureDescription) {
+        }
+    }
+
+    /* Object to keep track of gesture result callbacks */
+    private static class GestureResultCallbackInfo {
+        GestureDescription gestureDescription;
+        GestureResultCallback callback;
+        Handler handler;
+
+        GestureResultCallbackInfo(GestureDescription gestureDescription,
+                GestureResultCallback callback, Handler handler) {
+            this.gestureDescription = gestureDescription;
+            this.callback = callback;
+            this.handler = handler;
+        }
+    }
 }
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 2c98fef..079bdfc 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -110,6 +110,12 @@
      */
     public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 0x00000010;
 
+    /**
+     * Capability: This accessibility service can perform gestures.
+     * @see android.R.styleable#AccessibilityService_canPerformGestures
+     */
+    public static final int CAPABILITY_CAN_PERFORM_GESTURES = 0x00000020;
+
     private static final SparseArray<CapabilityInfo> sAvailableCapabilityInfos =
             new SparseArray<CapabilityInfo>();
     static {
@@ -133,6 +139,10 @@
                 new CapabilityInfo(CAPABILITY_CAN_CONTROL_MAGNIFICATION,
                         R.string.capability_title_canControlMagnification,
                         R.string.capability_desc_canControlMagnification));
+        sAvailableCapabilityInfos.put(CAPABILITY_CAN_PERFORM_GESTURES,
+                new CapabilityInfo(CAPABILITY_CAN_PERFORM_GESTURES,
+                        R.string.capability_title_canPerformGestures,
+                        R.string.capability_desc_canPerformGestures));
     }
 
     /**
@@ -276,12 +286,7 @@
     /**
      * This flag requests from the system to filter key events. If this flag
      * is set the accessibility service will receive the key events before
-     * applications allowing it implement global shortcuts. Setting this flag
-     * does not guarantee that this service will filter key events since only
-     * one service can do so at any given time. This avoids user confusion due
-     * to behavior change in case different key filtering services are enabled.
-     * If there is already another key filtering service enabled, this one will
-     * not receive key events.
+     * applications allowing it implement global shortcuts.
      * <p>
      * Services that want to set this flag have to declare this capability
      * in their meta-data by setting the attribute {@link android.R.attr
@@ -516,6 +521,10 @@
                     .AccessibilityService_canControlMagnification, false)) {
                 mCapabilities |= CAPABILITY_CAN_CONTROL_MAGNIFICATION;
             }
+            if (asAttributes.getBoolean(com.android.internal.R.styleable
+                    .AccessibilityService_canPerformGestures, false)) {
+                mCapabilities |= CAPABILITY_CAN_PERFORM_GESTURES;
+            }
             TypedValue peekedValue = asAttributes.peekValue(
                     com.android.internal.R.styleable.AccessibilityService_description);
             if (peekedValue != null) {
@@ -616,6 +625,8 @@
      * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
      * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
      * @see #CAPABILITY_FILTER_KEY_EVENTS
+     * @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION
+     * @see #CAPABILITY_CAN_PERFORM_GESTURES
      */
     public int getCapabilities() {
         return mCapabilities;
@@ -631,6 +642,8 @@
      * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
      * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
      * @see #CAPABILITY_FILTER_KEY_EVENTS
+     * @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION
+     * @see #CAPABILITY_CAN_PERFORM_GESTURES
      *
      * @hide
      */
@@ -933,6 +946,8 @@
                 return "CAPABILITY_CAN_FILTER_KEY_EVENTS";
             case CAPABILITY_CAN_CONTROL_MAGNIFICATION:
                 return "CAPABILITY_CAN_CONTROL_MAGNIFICATION";
+            case CAPABILITY_CAN_PERFORM_GESTURES:
+                return "CAPABILITY_CAN_PERFORM_GESTURES";
             default:
                 return "UNKNOWN";
         }
diff --git a/core/java/android/accessibilityservice/GestureDescription.java b/core/java/android/accessibilityservice/GestureDescription.java
new file mode 100644
index 0000000..14aabcf
--- /dev/null
+++ b/core/java/android/accessibilityservice/GestureDescription.java
@@ -0,0 +1,612 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accessibilityservice;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.graphics.Matrix;
+import android.graphics.Path;
+import android.graphics.PathMeasure;
+import android.graphics.RectF;
+import android.view.InputDevice;
+import android.view.MotionEvent;
+import android.view.MotionEvent.PointerCoords;
+import android.view.MotionEvent.PointerProperties;
+import android.view.ViewConfiguration;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 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.
+ * <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;
+
+    /**
+     * Upper bound on total gesture duration. Nearly all gestures will be much shorter.
+     */
+    public 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
+     *
+     * @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)
+     */
+    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()));
+    }
+
+    /**
+     * Create a description of a long click gesture
+     *
+     * @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)
+     */
+    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)));
+    }
+
+    private GestureDescription() {}
+
+    private GestureDescription(List<StrokeDescription> strokes) {
+        mStrokes.addAll(strokes);
+    }
+
+    private GestureDescription(StrokeDescription stroke) {
+        mStrokes.add(stroke);
+    }
+
+    /**
+     * Get the number of stroke in the gesture.
+     *
+     * @return the number of strokes in this gesture
+     */
+    public int getStrokeCount() {
+        return mStrokes.size();
+    }
+
+    /**
+     * Read a stroke from the gesture
+     *
+     * @param index the index of the stroke
+     *
+     * @return A description of the stroke.
+     */
+    public StrokeDescription getStroke(@IntRange(from = 0) int index) {
+        return mStrokes.get(index);
+    }
+
+    /**
+     * Return the smallest key point (where a path starts or ends) that is at least a specified
+     * offset
+     * @param offset the minimum start time
+     * @return The next key time that is at least the offset or -1 if one can't be found
+     */
+    private long getNextKeyPointAtLeast(long offset) {
+        long nextKeyPoint = Long.MAX_VALUE;
+        for (int i = 0; i < mStrokes.size(); i++) {
+            long thisStartTime = mStrokes.get(i).mStartTime;
+            if ((thisStartTime < nextKeyPoint) && (thisStartTime >= offset)) {
+                nextKeyPoint = thisStartTime;
+            }
+            long thisEndTime = mStrokes.get(i).mEndTime;
+            if ((thisEndTime < nextKeyPoint) && (thisEndTime >= offset)) {
+                nextKeyPoint = thisEndTime;
+            }
+        }
+        return (nextKeyPoint == Long.MAX_VALUE) ? -1L : nextKeyPoint;
+    }
+
+    /**
+     * Get the points that correspond to a particular moment in time.
+     * @param time The time of interest
+     * @param touchPoints An array to hold the current touch points. Must be preallocated to at
+     * least the number of paths in the gesture to prevent going out of bounds
+     * @return The number of points found, and thus the number of elements set in each array
+     */
+    private int getPointsForTime(long time, TouchPoint[] touchPoints) {
+        int numPointsFound = 0;
+        for (int i = 0; i < mStrokes.size(); i++) {
+            StrokeDescription strokeDescription = mStrokes.get(i);
+            if (strokeDescription.hasPointForTime(time)) {
+                touchPoints[numPointsFound].mPathIndex = i;
+                touchPoints[numPointsFound].mIsStartOfPath = (time == strokeDescription.mStartTime);
+                touchPoints[numPointsFound].mIsEndOfPath = (time == strokeDescription.mEndTime);
+                strokeDescription.getPosForTime(time, mTempPos);
+                touchPoints[numPointsFound].mX = Math.round(mTempPos[0]);
+                touchPoints[numPointsFound].mY = Math.round(mTempPos[1]);
+                numPointsFound++;
+            }
+        }
+        return numPointsFound;
+    }
+
+    // Total duration assumes that the gesture starts at 0; waiting around to start a gesture
+    // counts against total duration
+    private static long getTotalDuration(List<StrokeDescription> paths) {
+        long latestEnd = Long.MIN_VALUE;
+        for (int i = 0; i < paths.size(); i++) {
+            StrokeDescription path = paths.get(i);
+            latestEnd = Math.max(latestEnd, path.mEndTime);
+        }
+        return Math.max(latestEnd, 0);
+    }
+
+    /**
+     * Builder for a {@code GestureDescription}
+     */
+    public static class Builder {
+
+        private final List<StrokeDescription> mStrokes = new ArrayList<>();
+
+        /**
+         * Add a stroke to the gesture description. Up to {@code MAX_STROKE_COUNT} paths may be
+         * added to a gesture, and the total gesture duration (earliest path start time to latest path
+         * end time) may not exceed {@code MAX_GESTURE_DURATION_MS}.
+         *
+         * @param strokeDescription the stroke to add.
+         *
+         * @return this
+         */
+        public Builder addStroke(@NonNull StrokeDescription strokeDescription) {
+            if (mStrokes.size() >= MAX_STROKE_COUNT) {
+                throw new RuntimeException("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");
+            }
+            return this;
+        }
+
+        public GestureDescription build() {
+            if (mStrokes.size() == 0) {
+                throw new RuntimeException("Gestures must have at least one stroke");
+            }
+            return new GestureDescription(mStrokes);
+        }
+    }
+
+    /**
+     * Immutable description of stroke that can be part of a gesture.
+     */
+    public static class StrokeDescription {
+        Path mPath;
+        long mStartTime;
+        long mEndTime;
+        private float mTimeToLengthConversion;
+        private PathMeasure mPathMeasure;
+
+        /**
+         * @param path The path to follow. Must have exactly one contour, and that contour must
+         * have nonzero length. The bounds of the path must not be negative.
+         * @param startTime The time, in milliseconds, from the time the gesture starts to the
+         * time the stroke should start. Must not be negative.
+         * @param duration The duration, in milliseconds, the stroke takes to traverse the path.
+         * 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) {
+            if (duration <= 0) {
+                throw new IllegalArgumentException("Duration must be positive");
+            }
+            if (startTime < 0) {
+                throw new IllegalArgumentException("Start time must not be negative");
+            }
+            RectF bounds = new RectF();
+            path.computeBounds(bounds, false /* unused */);
+            if ((bounds.bottom < 0) || (bounds.top < 0) || (bounds.right < 0)
+                    || (bounds.left < 0)) {
+                throw new IllegalArgumentException("Path bounds must not be negative");
+            }
+            mPath = new Path(path);
+            mPathMeasure = new PathMeasure(path, false);
+            if (mPathMeasure.getLength() == 0) {
+                throw new IllegalArgumentException("Path has zero length");
+            }
+            if (mPathMeasure.nextContour()) {
+                throw new IllegalArgumentException("Path has more than one contour");
+            }
+            /*
+             * Calling nextContour has moved mPathMeasure off the first contour, which is the only
+             * one we care about. Set the path again to go back to the first contour.
+             */
+            mPathMeasure.setPath(path, false);
+            mStartTime = startTime;
+            mEndTime = startTime + duration;
+            if (duration > 0) {
+                mTimeToLengthConversion = getLength() / duration;
+            }
+        }
+
+        /**
+         * Retrieve a copy of the path for this stroke
+         *
+         * @return A copy of the path
+         */
+        public Path getPath() {
+            return new Path(mPath);
+        }
+
+        /**
+         * Get the stroke's start time
+         *
+         * @return the start time for this stroke.
+         */
+        public long getStartTime() {
+            return mStartTime;
+        }
+
+        /**
+         * Get the stroke's duration
+         *
+         * @return the duration for this stroke
+         */
+        public long getDuration() {
+            return mEndTime - mStartTime;
+        }
+
+        float getLength() {
+            return mPathMeasure.getLength();
+        }
+
+        /* Assumes hasPointForTime returns true */
+        boolean getPosForTime(long time, float[] pos) {
+            if (time == mEndTime) {
+                // Close to the end time, roundoff can be a problem
+                return mPathMeasure.getPosTan(getLength(), pos, null);
+            }
+            float length = mTimeToLengthConversion * ((float) (time - mStartTime));
+            return mPathMeasure.getPosTan(length, pos, null);
+        }
+
+        boolean hasPointForTime(long time) {
+            return ((time >= mStartTime) && (time <= mEndTime));
+        }
+    }
+
+    private static class TouchPoint {
+        int mPathIndex;
+        boolean mIsStartOfPath;
+        boolean mIsEndOfPath;
+        float mX;
+        float mY;
+
+        void copyFrom(TouchPoint other) {
+            mPathIndex = other.mPathIndex;
+            mIsStartOfPath = other.mIsStartOfPath;
+            mIsEndOfPath = other.mIsEndOfPath;
+            mX = other.mX;
+            mY = other.mY;
+        }
+    }
+
+    /**
+     * Class to convert a GestureDescription to a series of MotionEvents.
+     */
+    static class MotionEventGenerator {
+        /**
+         * Constants used to initialize all MotionEvents
+         */
+        private static final int EVENT_META_STATE = 0;
+        private static final int EVENT_BUTTON_STATE = 0;
+        private static final int EVENT_DEVICE_ID = 0;
+        private static final int EVENT_EDGE_FLAGS = 0;
+        private static final int EVENT_SOURCE = InputDevice.SOURCE_TOUCHSCREEN;
+        private static final int EVENT_FLAGS = 0;
+        private static final float EVENT_X_PRECISION = 1;
+        private static final float EVENT_Y_PRECISION = 1;
+
+        /* Lazily-created scratch memory for processing touches */
+        private static TouchPoint[] sCurrentTouchPoints;
+        private static TouchPoint[] sLastTouchPoints;
+        private static PointerCoords[] sPointerCoords;
+        private static PointerProperties[] sPointerProps;
+
+        static List<MotionEvent> getMotionEventsFromGestureDescription(
+                GestureDescription description, int sampleTimeMs) {
+            final List<MotionEvent> motionEvents = new ArrayList<>();
+
+            // Point data at each time we generate an event for
+            final TouchPoint[] currentTouchPoints =
+                    getCurrentTouchPoints(description.getStrokeCount());
+            // Point data sent in last touch event
+            int lastTouchPointSize = 0;
+            final TouchPoint[] lastTouchPoints =
+                    getLastTouchPoints(description.getStrokeCount());
+
+            /* Loop through each time slice where there are touch points */
+            long timeSinceGestureStart = 0;
+            long nextKeyPointTime = description.getNextKeyPointAtLeast(timeSinceGestureStart);
+            while (nextKeyPointTime >= 0) {
+                timeSinceGestureStart = (lastTouchPointSize == 0) ? nextKeyPointTime
+                        : Math.min(nextKeyPointTime, timeSinceGestureStart + sampleTimeMs);
+                int currentTouchPointSize = description.getPointsForTime(timeSinceGestureStart,
+                        currentTouchPoints);
+
+                appendMoveEventIfNeeded(motionEvents, lastTouchPoints, lastTouchPointSize,
+                        currentTouchPoints, currentTouchPointSize, timeSinceGestureStart);
+                lastTouchPointSize = appendUpEvents(motionEvents, lastTouchPoints,
+                        lastTouchPointSize, currentTouchPoints, currentTouchPointSize,
+                        timeSinceGestureStart);
+                lastTouchPointSize = appendDownEvents(motionEvents, lastTouchPoints,
+                        lastTouchPointSize, currentTouchPoints, currentTouchPointSize,
+                        timeSinceGestureStart);
+
+                /* Move to next time slice */
+                nextKeyPointTime = description.getNextKeyPointAtLeast(timeSinceGestureStart + 1);
+            }
+            return motionEvents;
+        }
+
+        private static TouchPoint[] getCurrentTouchPoints(int requiredCapacity) {
+            if ((sCurrentTouchPoints == null) || (sCurrentTouchPoints.length < requiredCapacity)) {
+                sCurrentTouchPoints = new TouchPoint[requiredCapacity];
+                for (int i = 0; i < requiredCapacity; i++) {
+                    sCurrentTouchPoints[i] = new TouchPoint();
+                }
+            }
+            return sCurrentTouchPoints;
+        }
+
+        private static TouchPoint[] getLastTouchPoints(int requiredCapacity) {
+            if ((sLastTouchPoints == null) || (sLastTouchPoints.length < requiredCapacity)) {
+                sLastTouchPoints = new TouchPoint[requiredCapacity];
+                for (int i = 0; i < requiredCapacity; i++) {
+                    sLastTouchPoints[i] = new TouchPoint();
+                }
+            }
+            return sLastTouchPoints;
+        }
+
+        private static PointerCoords[] getPointerCoords(int requiredCapacity) {
+            if ((sPointerCoords == null) || (sPointerCoords.length < requiredCapacity)) {
+                sPointerCoords = new PointerCoords[requiredCapacity];
+                for (int i = 0; i < requiredCapacity; i++) {
+                    sPointerCoords[i] = new PointerCoords();
+                }
+            }
+            return sPointerCoords;
+        }
+
+        private static PointerProperties[] getPointerProps(int requiredCapacity) {
+            if ((sPointerProps == null) || (sPointerProps.length < requiredCapacity)) {
+                sPointerProps = new PointerProperties[requiredCapacity];
+                for (int i = 0; i < requiredCapacity; i++) {
+                    sPointerProps[i] = new PointerProperties();
+                }
+            }
+            return sPointerProps;
+        }
+
+        private static void appendMoveEventIfNeeded(List<MotionEvent> motionEvents,
+                TouchPoint[] lastTouchPoints, int lastTouchPointsSize,
+                TouchPoint[] currentTouchPoints, int currentTouchPointsSize, long currentTime) {
+            /* Look for pointers that have moved */
+            boolean moveFound = false;
+            for (int i = 0; i < currentTouchPointsSize; i++) {
+                int lastPointsIndex = findPointByPathIndex(lastTouchPoints, lastTouchPointsSize,
+                        currentTouchPoints[i].mPathIndex);
+                if (lastPointsIndex >= 0) {
+                    moveFound |= (lastTouchPoints[lastPointsIndex].mX != currentTouchPoints[i].mX)
+                            || (lastTouchPoints[lastPointsIndex].mY != currentTouchPoints[i].mY);
+                    lastTouchPoints[lastPointsIndex].copyFrom(currentTouchPoints[i]);
+                }
+            }
+
+            if (moveFound) {
+                long downTime = motionEvents.get(motionEvents.size() - 1).getDownTime();
+                motionEvents.add(obtainMotionEvent(downTime, currentTime, MotionEvent.ACTION_MOVE,
+                        lastTouchPoints, lastTouchPointsSize));
+            }
+        }
+
+        private static int appendUpEvents(List<MotionEvent> motionEvents,
+                TouchPoint[] lastTouchPoints, int lastTouchPointsSize,
+                TouchPoint[] currentTouchPoints, int currentTouchPointsSize, long currentTime) {
+            /* Look for a pointer at the end of its path */
+            for (int i = 0; i < currentTouchPointsSize; i++) {
+                if (currentTouchPoints[i].mIsEndOfPath) {
+                    int indexOfUpEvent = findPointByPathIndex(lastTouchPoints, lastTouchPointsSize,
+                            currentTouchPoints[i].mPathIndex);
+                    if (indexOfUpEvent < 0) {
+                        continue; // Should not happen
+                    }
+                    long downTime = motionEvents.get(motionEvents.size() - 1).getDownTime();
+                    int action = (lastTouchPointsSize == 1) ? MotionEvent.ACTION_UP
+                            : MotionEvent.ACTION_POINTER_UP;
+                    action |= indexOfUpEvent << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+                    motionEvents.add(obtainMotionEvent(downTime, currentTime, action,
+                            lastTouchPoints, lastTouchPointsSize));
+                    /* Remove this point from lastTouchPoints */
+                    for (int j = indexOfUpEvent; j < lastTouchPointsSize - 1; j++) {
+                        lastTouchPoints[j].copyFrom(lastTouchPoints[j+1]);
+                    }
+                    lastTouchPointsSize--;
+                }
+            }
+            return lastTouchPointsSize;
+        }
+
+        private static int appendDownEvents(List<MotionEvent> motionEvents,
+                TouchPoint[] lastTouchPoints, int lastTouchPointsSize,
+                TouchPoint[] currentTouchPoints, int currentTouchPointsSize, long currentTime) {
+            /* Look for a pointer that is just starting */
+            for (int i = 0; i < currentTouchPointsSize; i++) {
+                if (currentTouchPoints[i].mIsStartOfPath) {
+                    /* Add the point to last coords and use the new array to generate the event */
+                    lastTouchPoints[lastTouchPointsSize++].copyFrom(currentTouchPoints[i]);
+                    int action = (lastTouchPointsSize == 1) ? MotionEvent.ACTION_DOWN
+                            : MotionEvent.ACTION_POINTER_DOWN;
+                    long downTime = (action == MotionEvent.ACTION_DOWN) ? currentTime :
+                            motionEvents.get(motionEvents.size() - 1).getDownTime();
+                    action |= i << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+                    motionEvents.add(obtainMotionEvent(downTime, currentTime, action,
+                            lastTouchPoints, lastTouchPointsSize));
+                }
+            }
+            return lastTouchPointsSize;
+        }
+
+        private static MotionEvent obtainMotionEvent(long downTime, long eventTime, int action,
+                TouchPoint[] touchPoints, int touchPointsSize) {
+            PointerCoords[] pointerCoords = getPointerCoords(touchPointsSize);
+            PointerProperties[] pointerProperties = getPointerProps(touchPointsSize);
+            for (int i = 0; i < touchPointsSize; i++) {
+                pointerProperties[i].id = touchPoints[i].mPathIndex;
+                pointerProperties[i].toolType = MotionEvent.TOOL_TYPE_UNKNOWN;
+                pointerCoords[i].clear();
+                pointerCoords[i].pressure = 1.0f;
+                pointerCoords[i].size = 1.0f;
+                pointerCoords[i].x = touchPoints[i].mX;
+                pointerCoords[i].y = touchPoints[i].mY;
+            }
+            return MotionEvent.obtain(downTime, eventTime, action, touchPointsSize,
+                    pointerProperties, pointerCoords, EVENT_META_STATE, EVENT_BUTTON_STATE,
+                    EVENT_X_PRECISION, EVENT_Y_PRECISION, EVENT_DEVICE_ID, EVENT_EDGE_FLAGS,
+                    EVENT_SOURCE, EVENT_FLAGS);
+        }
+
+        private static int findPointByPathIndex(TouchPoint[] touchPoints, int touchPointsSize,
+                int pathIndex) {
+            for (int i = 0; i < touchPointsSize; i++) {
+                if (touchPoints[i].mPathIndex == pathIndex) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+    }
+}
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
index 15666bf..6280542 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
@@ -42,4 +42,6 @@
     void onKeyEvent(in KeyEvent event, int sequence);
 
     void onMagnificationChanged(in Region region, float scale, float centerX, float centerY);
+
+    void onPerformGestureResult(int sequence, boolean completedSuccessfully);
 }
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 6ac50bd..e58ef2f 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -16,10 +16,12 @@
 
 package android.accessibilityservice;
 
-import android.os.Bundle;
 import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.pm.ParceledListSlice;
 import android.graphics.Region;
+import android.os.Bundle;
 import android.view.MagnificationSpec;
+import android.view.MotionEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
 import android.view.accessibility.AccessibilityWindowInfo;
@@ -63,6 +65,8 @@
 
     boolean performGlobalAction(int action);
 
+    oneway void disableSelf();
+
     oneway void setOnKeyEventResult(boolean handled, int sequence);
 
     float getMagnificationScale();
@@ -79,4 +83,6 @@
         boolean animate);
 
     void setMagnificationCallbackEnabled(boolean enabled);
+
+    void sendMotionEvents(int sequence, in ParceledListSlice events);
 }
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index a312e3f..4dca8e2 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -16,15 +16,16 @@
 
 package android.accounts;
 
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.text.TextUtils;
-import android.os.Binder;
-import android.os.IBinder;
-import android.content.pm.PackageManager;
+import android.Manifest;
+import android.annotation.SystemApi;
 import android.content.Context;
 import android.content.Intent;
-import android.Manifest;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.text.TextUtils;
 import android.util.Log;
 
 import java.util.Arrays;
@@ -435,6 +436,7 @@
             }
         }
 
+        @Override
         public void finishSession(
                 IAccountAuthenticatorResponse response,
                 String accountType,
@@ -460,6 +462,24 @@
 
             }
         }
+
+        @Override
+        public void isCredentialsUpdateSuggested(
+                IAccountAuthenticatorResponse response,
+                Account account,
+                String statusToken) throws RemoteException {
+            checkBinderPermission();
+            try {
+                final Bundle result = AbstractAccountAuthenticator.this
+                        .isCredentialsUpdateSuggested(
+                                new AccountAuthenticatorResponse(response), account, statusToken);
+                if (result != null) {
+                    response.onResult(result);
+                }
+            } catch (Exception e) {
+                handleException(response, "isCredentialsUpdateSuggested", account.toString(), e);
+            }
+        }
     }
 
     private void handleException(IAccountAuthenticatorResponse response, String method,
@@ -762,7 +782,9 @@
      * @throws NetworkErrorException if the authenticator could not honor the
      *             request due to a network error
      * @see #finishSession(AccountAuthenticatorResponse, String, Bundle)
+     * @hide
      */
+    @SystemApi
     public Bundle startAddAccountSession(
             final AccountAuthenticatorResponse response,
             final String accountType,
@@ -818,7 +840,9 @@
      * @throws NetworkErrorException if the authenticator could not honor the
      *             request due to a network error
      * @see #finishSession(AccountAuthenticatorResponse, String, Bundle)
+     * @hide
      */
+    @SystemApi
     public Bundle startUpdateCredentialsSession(
             final AccountAuthenticatorResponse response,
             final Account account,
@@ -868,9 +892,12 @@
      *         <li>{@link AccountManager#KEY_ERROR_CODE} and
      *         {@link AccountManager#KEY_ERROR_MESSAGE} to indicate an error
      *         </ul>
-     * @throws NetworkErrorException
+     * @throws NetworkErrorException if the authenticator could not honor the request due to a
+     *             network error
      * @see #startAddAccountSession and #startUpdateCredentialsSession
+     * @hide
      */
+    @SystemApi
     public Bundle finishSession(
             final AccountAuthenticatorResponse response,
             final String accountType,
@@ -937,4 +964,32 @@
         // Otherwise, session bundle was created by startAddAccountSession default implementation.
         return addAccount(response, accountType, authTokenType, requiredFeatures, sessionOptions);
     }
+
+    /**
+     * Checks if update of the account credentials is suggested.
+     *
+     * @param response to send the result back to the AccountManager, will never be null.
+     * @param account the account to check, will never be null
+     * @param statusToken a String of token to check if update of credentials is suggested.
+     * @return a Bundle result or null if the result is to be returned via the response. The result
+     *         will contain either:
+     *         <ul>
+     *         <li>{@link AccountManager#KEY_BOOLEAN_RESULT}, true if update of account's
+     *         credentials is suggested, false otherwise
+     *         <li>{@link AccountManager#KEY_ERROR_CODE} and
+     *         {@link AccountManager#KEY_ERROR_MESSAGE} to indicate an error
+     *         </ul>
+     * @throws NetworkErrorException if the authenticator could not honor the request due to a
+     *             network error
+     * @hide
+     */
+    @SystemApi
+    public Bundle isCredentialsUpdateSuggested(
+            final AccountAuthenticatorResponse response,
+            Account account,
+            String statusToken) throws NetworkErrorException {
+        Bundle result = new Bundle();
+        result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
+        return result;
+    }
 }
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index ada1ac2..35695c4 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -16,9 +16,12 @@
 
 package android.accounts;
 
+import static android.Manifest.permission.GET_ACCOUNTS;
+
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.Size;
+import android.annotation.SystemApi;
 import android.app.Activity;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -53,8 +56,6 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
-import static android.Manifest.permission.GET_ACCOUNTS;
-
 /**
  * This class provides access to a centralized registry of the user's
  * online accounts.  The user enters credentials (username and password) once
@@ -244,14 +245,18 @@
      * Bundle key used for a {@link Bundle} in result from
      * {@link #startAddAccountSession} and friends which returns session data
      * for installing an account later.
+     * @hide
      */
+    @SystemApi
     public static final String KEY_ACCOUNT_SESSION_BUNDLE = "accountSessionBundle";
 
     /**
      * Bundle key used for the {@link String} account status token in result
      * from {@link #startAddAccountSession} and friends which returns
      * information about a particular account.
+     * @hide
      */
+    @SystemApi
     public static final String KEY_ACCOUNT_STATUS_TOKEN = "accountStatusToken";
 
     public static final String ACTION_AUTHENTICATOR_INTENT =
@@ -425,47 +430,46 @@
     }
 
     /**
-     * Lists all accounts of any type registered on the device.
-     * Equivalent to getAccountsByType(null).
+     * List every {@link Account} registered on the device that are managed by
+     * applications whose signatures match the caller.
      *
-     * <p>It is safe to call this method from the main thread.
+     * <p>This method can be called safely from the main thread. It is
+     * equivalent to calling <code>getAccountsByType(null)</code>.
      *
-     * <p>Clients of this method that have not been granted the
-     * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
-     * will only see those accounts managed by AbstractAccountAuthenticators whose
-     * signature matches the client.
+     * <p><b>NOTE:</b> Apps declaring a {@code targetSdkVersion<=23} in their
+     * manifests will continue to behave as they did on devices that support
+     * API level 23. In particular the GET_ACCOUNTS permission is required to
+     * see all the Accounts registered with the AccountManager. See docs for
+     * this function in API level 23 for more information.
      *
-     * @return An array of {@link Account}, one for each account.  Empty
-     *     (never null) if no accounts have been added.
+     * @return Array of Accounts. The array may be empty if no accounts are
+     *     available to the caller.
      */
     @NonNull
-    @RequiresPermission(GET_ACCOUNTS)
     public Account[] getAccounts() {
-        try {
-            return mService.getAccounts(null, mContext.getOpPackageName());
-        } catch (RemoteException e) {
-            // won't ever happen
-            throw new RuntimeException(e);
-        }
+        return getAccountsByType(null);
     }
 
     /**
      * @hide
-     * Lists all accounts of any type registered on the device for a given
-     * user id. Equivalent to getAccountsByType(null).
+     * List every {@link Account} registered on the device for a specific User
+     * that are managed by applications whose signatures match the caller.
      *
-     * <p>It is safe to call this method from the main thread.
+     * <p><b>NOTE:</b> Apps declaring a {@code targetSdkVersion<=23} in their
+     * manifests will continue to behave as they did on devices that support
+     * API level 23. In particular the GET_ACCOUNTS permission is required to
+     * see all the Accounts registered with the AccountManager for the
+     * specified userId. See docs for this function in API level 23 for more
+     * information.
      *
-     * <p>Clients of this method that have not been granted the
-     * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
-     * will only see those accounts managed by AbstractAccountAuthenticators whose
-     * signature matches the client.
+     * <p>This method can be called safely from the main thread.
      *
-     * @return An array of {@link Account}, one for each account.  Empty
-     *     (never null) if no accounts have been added.
+     * @param int userId associated with the User whose accounts should be
+     *     queried.
+     * @return Array of Accounts. The array may be empty if no accounts are
+     *     available to the caller.
      */
     @NonNull
-    @RequiresPermission(GET_ACCOUNTS)
     public Account[] getAccountsAsUser(int userId) {
         try {
             return mService.getAccountsAsUser(null, userId, mContext.getOpPackageName());
@@ -496,10 +500,11 @@
     /**
      * Returns the accounts visible to the specified package, in an environment where some apps
      * are not authorized to view all accounts. This method can only be called by system apps.
+     *
      * @param type The type of accounts to return, null to retrieve all accounts
      * @param packageName The package name of the app for which the accounts are to be returned
-     * @return An array of {@link Account}, one per matching account.  Empty
-     *     (never null) if no accounts of the specified type have been added.
+     * @return Array of Accounts. The array may be empty if no accounts of th
+     *     specified type are visible to the caller.
      */
     @NonNull
     public Account[] getAccountsByTypeForPackage(String type, String packageName) {
@@ -513,29 +518,22 @@
     }
 
     /**
-     * Lists all accounts of a particular type.  The account type is a
-     * string token corresponding to the authenticator and useful domain
-     * of the account.  For example, there are types corresponding to Google
-     * and Facebook.  The exact string token to use will be published somewhere
-     * associated with the authenticator in question.
+     * List every {@link Account} of a specified type managed by applications
+     * whose signatures match the caller.
      *
-     * <p>It is safe to call this method from the main thread.
+     * <p><b>NOTE:</b> Apps declaring a {@code targetSdkVersion<=23} in their
+     * manifests will continue to behave as they did on devices that support
+     * API level 23. See docs for this function in API level 23 for more
+     * information.
      *
-     * <p>Clients of this method that have not been granted the
-     * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
-     * will only see those accounts managed by AbstractAccountAuthenticators whose
-     * signature matches the client.
+     * <p>This method can be called safely from the main thread.
      *
-     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
-     * GET_ACCOUNTS permission is needed for those platforms, irrespective of uid
-     * or signature match. See docs for this function in API level 22.
-     *
-     * @param type The type of accounts to return, null to retrieve all accounts
-     * @return An array of {@link Account}, one per matching account.  Empty
-     *     (never null) if no accounts of the specified type have been added.
+     * @param type String denoting the type of the accounts to return,
+     *        {@code null} to retrieve all accounts visible to the caller.
+     * @return An array of Accounts.  Empty (never null) if no accounts
+     *         are available to the caller.
      */
     @NonNull
-    @RequiresPermission(GET_ACCOUNTS)
     public Account[] getAccountsByType(String type) {
         return getAccountsByTypeAsUser(type, Process.myUserHandle());
     }
@@ -581,12 +579,14 @@
      * @return a future containing the label string
      * @hide
      */
+    @NonNull
     public AccountManagerFuture<String> getAuthTokenLabel(
             final String accountType, final String authTokenType,
             AccountManagerCallback<String> callback, Handler handler) {
         if (accountType == null) throw new IllegalArgumentException("accountType is null");
         if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
         return new Future2Task<String>(handler, callback) {
+            @Override
             public void doWork() throws RemoteException {
                 mService.getAuthTokenLabel(mResponse, accountType, authTokenType);
             }
@@ -612,9 +612,13 @@
      * <p>This method may be called from any thread, but the returned
      * {@link AccountManagerFuture} must not be used on the main thread.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#GET_ACCOUNTS} or be a signature
-     * match with the AbstractAccountAuthenticator that manages the account.
+     * <p><b>Note:</b>The specified account must be managed by an application
+     * whose signature matches the caller.
+     *
+     * <p><b>Further note:</b>Apps targeting API level 23 or earlier will continue to
+     * behave as they did on devices that support API level 23. In particular
+     * they may still require the GET_ACCOUNTS permission. See docs for this
+     * function in API level 23.
      *
      * @param account The {@link Account} to test
      * @param features An array of the account features to check
@@ -623,18 +627,22 @@
      * @param handler {@link Handler} identifying the callback thread,
      *     null for the main thread
      * @return An {@link AccountManagerFuture} which resolves to a Boolean,
-     * true if the account exists and has all of the specified features.
+     *     true if the account exists and has all of the specified features.
+     * @throws SecurityException if the specified account is managed by an
+     *     application whose signature doesn't match the caller's signature.
      */
-    @RequiresPermission(GET_ACCOUNTS)
+    @NonNull
     public AccountManagerFuture<Boolean> hasFeatures(final Account account,
             final String[] features,
             AccountManagerCallback<Boolean> callback, Handler handler) {
         if (account == null) throw new IllegalArgumentException("account is null");
         if (features == null) throw new IllegalArgumentException("features is null");
         return new Future2Task<Boolean>(handler, callback) {
+            @Override
             public void doWork() throws RemoteException {
                 mService.hasFeatures(mResponse, account, features, mContext.getOpPackageName());
             }
+            @Override
             public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
                 if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
                     throw new AuthenticatorException("no result in response");
@@ -646,9 +654,10 @@
 
     /**
      * Lists all accounts of a type which have certain features.  The account
-     * type identifies the authenticator (see {@link #getAccountsByType}).
-     * Account features are authenticator-specific string tokens identifying
-     * boolean account properties (see {@link #hasFeatures}).
+     * type identifies the authenticator (see {@link #getAccountsByType}). Said
+     * authenticator must be in a package whose signature matches the callers
+     * package signature. Account features are authenticator-specific string tokens
+     * identifying boolean account properties (see {@link #hasFeatures}).
      *
      * <p>Unlike {@link #getAccountsByType}, this method calls the authenticator,
      * which may contact the server or do other work to check account features,
@@ -657,19 +666,14 @@
      * <p>This method may be called from any thread, but the returned
      * {@link AccountManagerFuture} must not be used on the main thread.
      *
-     * <p>Clients of this method that have not been granted the
-     * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
-     * will only see those accounts managed by AbstractAccountAuthenticators whose
-     * signature matches the client.
+     * <p><b>NOTE:</b> Apps targeting API level 23 or earlier will continue to
+     * behave as they did on devices that support API level 23. In particular
+     * they may still require the GET_ACCOUNTS permission. See docs for this
+     * function in API level 23.
      *
      * @param type The type of accounts to return, must not be null
      * @param features An array of the account features to require,
      *     may be null or empty
-     *
-     * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
-     * GET_ACCOUNTS permission is needed for those platforms, irrespective of uid
-     * or signature match. See docs for this function in API level 22.
-     *
      * @param callback Callback to invoke when the request completes,
      *     null for no callback
      * @param handler {@link Handler} identifying the callback thread,
@@ -678,16 +682,18 @@
      *     {@link Account}, one per account of the specified type which
      *     matches the requested features.
      */
-    @RequiresPermission(GET_ACCOUNTS)
+    @NonNull
     public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures(
             final String type, final String[] features,
             AccountManagerCallback<Account[]> callback, Handler handler) {
         if (type == null) throw new IllegalArgumentException("type is null");
         return new Future2Task<Account[]>(handler, callback) {
+            @Override
             public void doWork() throws RemoteException {
                 mService.getAccountsByFeatures(mResponse, type, features,
                         mContext.getOpPackageName());
             }
+            @Override
             public Account[] bundleToResult(Bundle bundle) throws AuthenticatorException {
                 if (!bundle.containsKey(KEY_ACCOUNTS)) {
                     throw new AuthenticatorException("no result in response");
@@ -966,6 +972,7 @@
         if (userHandle == null)
             throw new IllegalArgumentException("userHandle is null");
         return new AmsTask(activity, handler, callback) {
+            @Override
             public void doWork() throws RemoteException {
                 mService.removeAccountAsUser(mResponse, account, activity != null,
                         userHandle.getIdentifier());
@@ -1046,7 +1053,7 @@
      * is needed for those platforms. See docs for this function in API level 22.
      *
      * @param account The account for which an auth token is to be fetched. Cannot be {@code null}.
-     * @param authTokenType The type of auth token to fetch. Cannot be {@code null}. 
+     * @param authTokenType The type of auth token to fetch. Cannot be {@code null}.
      * @return The cached auth token for this account and type, or null if
      *     no auth token is cached or the account does not exist.
      * @see #getAuthToken
@@ -1240,7 +1247,7 @@
      * tokens to access Gmail and Google Calendar for the same account.
      *
      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
-     * USE_CREDENTIALS permission is needed for those platforms. See docs for 
+     * USE_CREDENTIALS permission is needed for those platforms. See docs for
      * this function in API level 22.
      *
      * <p>This method may be called from any thread, but the returned
@@ -1290,6 +1297,7 @@
         }
         optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
         return new AmsTask(activity, handler, callback) {
+            @Override
             public void doWork() throws RemoteException {
                 mService.getAuthToken(mResponse, account, authTokenType,
                         false /* notifyOnAuthFailure */, true /* expectActivityLaunch */,
@@ -1407,7 +1415,7 @@
      * {@link AccountManagerFuture} must not be used on the main thread.
      *
      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
-     * USE_CREDENTIALS permission is needed for those platforms. See docs for 
+     * USE_CREDENTIALS permission is needed for those platforms. See docs for
      * this function in API level 22.
      *
      * @param account The account to fetch an auth token for
@@ -1458,6 +1466,7 @@
         }
         optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
         return new AmsTask(null, handler, callback) {
+            @Override
             public void doWork() throws RemoteException {
                 mService.getAuthToken(mResponse, account, authTokenType,
                         notifyAuthFailure, false /* expectActivityLaunch */, optionsIn);
@@ -1473,7 +1482,7 @@
      *
      * <p>This method may be called from any thread, but the returned
      * {@link AccountManagerFuture} must not be used on the main thread.
-     * 
+     *
      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
      * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
      * this function in API level 22.
@@ -1527,6 +1536,7 @@
         optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
 
         return new AmsTask(activity, handler, callback) {
+            @Override
             public void doWork() throws RemoteException {
                 mService.addAccount(mResponse, accountType, authTokenType,
                         requiredFeatures, activity != null, optionsIn);
@@ -1551,6 +1561,7 @@
         optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
 
         return new AmsTask(activity, handler, callback) {
+            @Override
             public void doWork() throws RemoteException {
                 mService.addAccountAsUser(mResponse, accountType, authTokenType,
                         requiredFeatures, activity != null, optionsIn, userHandle.getIdentifier());
@@ -1727,6 +1738,7 @@
         if (account == null) throw new IllegalArgumentException("account is null");
         final int userId = userHandle.getIdentifier();
         return new AmsTask(activity, handler, callback) {
+            @Override
             public void doWork() throws RemoteException {
                 mService.confirmCredentialsAsUser(mResponse, account, options, activity != null,
                         userId);
@@ -1789,6 +1801,7 @@
             final Handler handler) {
         if (account == null) throw new IllegalArgumentException("account is null");
         return new AmsTask(activity, handler, callback) {
+            @Override
             public void doWork() throws RemoteException {
                 mService.updateCredentials(mResponse, account, authTokenType, activity != null,
                         options);
@@ -1842,12 +1855,29 @@
             final Handler handler) {
         if (accountType == null) throw new IllegalArgumentException("accountType is null");
         return new AmsTask(activity, handler, callback) {
+            @Override
             public void doWork() throws RemoteException {
                 mService.editProperties(mResponse, accountType, activity != null);
             }
         }.start();
     }
 
+    /**
+     * @hide
+     * Checks if the given account exists on any of the users on the device.
+     * Only the system process can call this method.
+     *
+     * @param account The account to check for existence.
+     * @return whether any user has this account
+     */
+    public boolean someUserHasAccount(@NonNull final Account account) {
+        try {
+            return mService.someUserHasAccount(account);
+        } catch (RemoteException re) {
+            throw new RuntimeException(re);
+        }
+    }
+
     private void ensureNotOnMainThread() {
         final Looper looper = Looper.myLooper();
         if (looper != null && looper == mContext.getMainLooper()) {
@@ -1865,6 +1895,7 @@
             final AccountManagerFuture<Bundle> future) {
         handler = handler == null ? mMainHandler : handler;
         handler.post(new Runnable() {
+            @Override
             public void run() {
                 callback.run(future);
             }
@@ -1879,6 +1910,7 @@
         System.arraycopy(accounts, 0, accountsCopy, 0, accountsCopy.length);
         handler = (handler == null) ? mMainHandler : handler;
         handler.post(new Runnable() {
+            @Override
             public void run() {
                 try {
                     listener.onAccountsUpdated(accountsCopy);
@@ -1898,6 +1930,7 @@
         final Activity mActivity;
         public AmsTask(Activity activity, Handler handler, AccountManagerCallback<Bundle> callback) {
             super(new Callable<Bundle>() {
+                @Override
                 public Bundle call() throws Exception {
                     throw new IllegalStateException("this should never be called");
                 }
@@ -1918,6 +1951,7 @@
             return this;
         }
 
+        @Override
         protected void set(Bundle bundle) {
             // TODO: somehow a null is being set as the result of the Future. Log this
             // case to help debug where this is occurring. When this bug is fixed this
@@ -1968,16 +2002,19 @@
             throw new OperationCanceledException();
         }
 
+        @Override
         public Bundle getResult()
                 throws OperationCanceledException, IOException, AuthenticatorException {
             return internalGetResult(null, null);
         }
 
+        @Override
         public Bundle getResult(long timeout, TimeUnit unit)
                 throws OperationCanceledException, IOException, AuthenticatorException {
             return internalGetResult(timeout, unit);
         }
 
+        @Override
         protected void done() {
             if (mCallback != null) {
                 postToHandler(mHandler, mCallback, this);
@@ -1986,6 +2023,7 @@
 
         /** Handles the responses from the AccountManager */
         private class Response extends IAccountManagerResponse.Stub {
+            @Override
             public void onResult(Bundle bundle) {
                 Intent intent = bundle.getParcelable(KEY_INTENT);
                 if (intent != null && mActivity != null) {
@@ -2005,6 +2043,7 @@
                 }
             }
 
+            @Override
             public void onError(int code, String message) {
                 if (code == ERROR_CODE_CANCELED || code == ERROR_CODE_USER_RESTRICTED
                         || code == ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
@@ -2025,6 +2064,7 @@
 
         public BaseFutureTask(Handler handler) {
             super(new Callable<T>() {
+                @Override
                 public T call() throws Exception {
                     throw new IllegalStateException("this should never be called");
                 }
@@ -2051,6 +2091,7 @@
         }
 
         protected class Response extends IAccountManagerResponse.Stub {
+            @Override
             public void onResult(Bundle bundle) {
                 try {
                     T result = bundleToResult(bundle);
@@ -2067,6 +2108,7 @@
                 onError(ERROR_CODE_INVALID_RESPONSE, "no result in response");
             }
 
+            @Override
             public void onError(int code, String message) {
                 if (code == ERROR_CODE_CANCELED || code == ERROR_CODE_USER_RESTRICTED
                         || code == ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
@@ -2088,9 +2130,11 @@
             mCallback = callback;
         }
 
+        @Override
         protected void done() {
             if (mCallback != null) {
                 postRunnableToHandler(new Runnable() {
+                    @Override
                     public void run() {
                         mCallback.run(Future2Task.this);
                     }
@@ -2141,11 +2185,13 @@
             throw new OperationCanceledException();
         }
 
+        @Override
         public T getResult()
                 throws OperationCanceledException, IOException, AuthenticatorException {
             return internalGetResult(null, null);
         }
 
+        @Override
         public T getResult(long timeout, TimeUnit unit)
                 throws OperationCanceledException, IOException, AuthenticatorException {
             return internalGetResult(timeout, unit);
@@ -2197,9 +2243,11 @@
         final AccountManagerCallback<Bundle> mMyCallback;
         private volatile int mNumAccounts = 0;
 
+        @Override
         public void doWork() throws RemoteException {
             getAccountsByTypeAndFeatures(mAccountType, mFeatures,
                     new AccountManagerCallback<Account[]>() {
+                        @Override
                         public void run(AccountManagerFuture<Account[]> future) {
                             Account[] accounts;
                             try {
@@ -2250,6 +2298,7 @@
                                 if (mActivity != null) {
                                     IAccountManagerResponse chooseResponse =
                                             new IAccountManagerResponse.Stub() {
+                                        @Override
                                         public void onResult(Bundle value) throws RemoteException {
                                             Account account = new Account(
                                                     value.getString(KEY_ACCOUNT_NAME),
@@ -2258,6 +2307,7 @@
                                                     mActivity, mMyCallback, mHandler);
                                         }
 
+                                        @Override
                                         public void onError(int errorCode, String errorMessage)
                                                 throws RemoteException {
                                             mResponse.onError(errorCode, errorMessage);
@@ -2290,6 +2340,7 @@
                         }}, mHandler);
         }
 
+        @Override
         public void run(AccountManagerFuture<Bundle> future) {
             try {
                 final Bundle result = future.getResult();
@@ -2510,6 +2561,7 @@
      * in mAccountsUpdatedListeners.
      */
     private final BroadcastReceiver mAccountsChangedBroadcastReceiver = new BroadcastReceiver() {
+        @Override
         public void onReceive(final Context context, final Intent intent) {
             final Account[] accounts = getAccounts();
             // send the result to the listeners
@@ -2667,7 +2719,9 @@
      *         trouble
      *         </ul>
      * @see #finishSession
+     * @hide
      */
+    @SystemApi
     public AccountManagerFuture<Bundle> startAddAccountSession(
             final String accountType,
             final String authTokenType,
@@ -2749,7 +2803,9 @@
      *         trouble
      *         </ul>
      * @see #finishSession
+     * @hide
      */
+    @SystemApi
     public AccountManagerFuture<Bundle> startUpdateCredentialsSession(
             final Account account,
             final String authTokenType,
@@ -2818,12 +2874,33 @@
      *         trouble
      *         </ul>
      * @see #startAddAccountSession and #startUpdateCredentialsSession
+     * @hide
      */
+    @SystemApi
     public AccountManagerFuture<Bundle> finishSession(
             final Bundle sessionBundle,
             final Activity activity,
             AccountManagerCallback<Bundle> callback,
             Handler handler) {
+        return finishSessionAsUser(
+                sessionBundle,
+                activity,
+                Process.myUserHandle(),
+                callback,
+                handler);
+    }
+
+    /**
+     * @see #finishSession
+     * @hide
+     */
+    @SystemApi
+    public AccountManagerFuture<Bundle> finishSessionAsUser(
+            final Bundle sessionBundle,
+            final Activity activity,
+            final UserHandle userHandle,
+            AccountManagerCallback<Bundle> callback,
+            Handler handler) {
         if (sessionBundle == null) {
             throw new IllegalArgumentException("sessionBundle is null");
         }
@@ -2835,7 +2912,60 @@
         return new AmsTask(activity, handler, callback) {
             @Override
             public void doWork() throws RemoteException {
-                mService.finishSession(mResponse, sessionBundle, activity != null, appInfo);
+                mService.finishSessionAsUser(
+                        mResponse,
+                        sessionBundle,
+                        activity != null,
+                        appInfo,
+                        userHandle.getIdentifier());
+            }
+        }.start();
+    }
+
+    /**
+     * Checks whether {@link #updateCredentials} or {@link #startUpdateCredentialsSession} should be
+     * called with respect to the specified account.
+     * <p>
+     * This method may be called from any thread, but the returned {@link AccountManagerFuture} must
+     * not be used on the main thread.
+     *
+     * @param account The {@link Account} to be checked whether {@link #updateCredentials} or
+     * {@link #startUpdateCredentialsSession} should be called
+     * @param statusToken a String of token to check account staus
+     * @param callback Callback to invoke when the request completes, null for no callback
+     * @param handler {@link Handler} identifying the callback thread, null for the main thread
+     * @return An {@link AccountManagerFuture} which resolves to a Boolean, true if the credentials
+     *         of the account should be updated.
+     * @hide
+     */
+    @SystemApi
+    public AccountManagerFuture<Boolean> isCredentialsUpdateSuggested(
+            final Account account,
+            final String statusToken,
+            AccountManagerCallback<Boolean> callback,
+            Handler handler) {
+        if (account == null) {
+            throw new IllegalArgumentException("account is null");
+        }
+
+        if (TextUtils.isEmpty(statusToken)) {
+            throw new IllegalArgumentException("status token is empty");
+        }
+
+        return new Future2Task<Boolean>(handler, callback) {
+            @Override
+            public void doWork() throws RemoteException {
+                mService.isCredentialsUpdateSuggested(
+                        mResponse,
+                        account,
+                        statusToken);
+            }
+            @Override
+            public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
+                if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
+                    throw new AuthenticatorException("no result in response");
+                }
+                return bundle.getBoolean(KEY_BOOLEAN_RESULT);
             }
         }.start();
     }
diff --git a/core/java/android/accounts/IAccountAuthenticator.aidl b/core/java/android/accounts/IAccountAuthenticator.aidl
index 6bda800..8b98ca2 100644
--- a/core/java/android/accounts/IAccountAuthenticator.aidl
+++ b/core/java/android/accounts/IAccountAuthenticator.aidl
@@ -104,4 +104,10 @@
      */
     void finishSession(in IAccountAuthenticatorResponse response, String accountType,
         in Bundle sessionBundle);
+
+    /**
+     * Checks if the credentials of the provided account should be updated.
+     */
+    void isCredentialsUpdateSuggested(in IAccountAuthenticatorResponse response, in Account account,
+        String statusToken);
 }
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 4af9f33..7199288 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -92,7 +92,14 @@
     void startUpdateCredentialsSession(in IAccountManagerResponse response, in Account account,
         String authTokenType, boolean expectActivityLaunch, in Bundle options);
 
-    /* Finish session started by startAddAccountSession(...) or startUpdateCredentialsSession(...) */
-    void finishSession(in IAccountManagerResponse response, in Bundle sessionBundle,
-        boolean expectActivityLaunch, in Bundle appInfo);
+    /* Finish session started by startAddAccountSession(...) or startUpdateCredentialsSession(...) for user */
+    void finishSessionAsUser(in IAccountManagerResponse response, in Bundle sessionBundle,
+        boolean expectActivityLaunch, in Bundle appInfo, int userId);
+
+    /* Check if an account exists on any user on the device. */
+    boolean someUserHasAccount(in Account account);
+
+    /* Check if credentials update is suggested */
+    void isCredentialsUpdateSuggested(in IAccountManagerResponse response, in Account account,
+        String statusToken);
 }
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
index 8928e99..e993cca 100644
--- a/core/java/android/animation/PropertyValuesHolder.java
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -861,22 +861,23 @@
         if (mProperty != null) {
             Object value = convertBack(mProperty.get(target));
             kf.setValue(value);
-        }
-        try {
-            if (mGetter == null) {
-                Class targetClass = target.getClass();
-                setupGetter(targetClass);
+        } else {
+            try {
                 if (mGetter == null) {
-                    // Already logged the error - just return to avoid NPE
-                    return;
+                    Class targetClass = target.getClass();
+                    setupGetter(targetClass);
+                    if (mGetter == null) {
+                        // Already logged the error - just return to avoid NPE
+                        return;
+                    }
                 }
+                Object value = convertBack(mGetter.invoke(target));
+                kf.setValue(value);
+            } catch (InvocationTargetException e) {
+                Log.e("PropertyValuesHolder", e.toString());
+            } catch (IllegalAccessException e) {
+                Log.e("PropertyValuesHolder", e.toString());
             }
-            Object value = convertBack(mGetter.invoke(target));
-            kf.setValue(value);
-        } catch (InvocationTargetException e) {
-            Log.e("PropertyValuesHolder", e.toString());
-        } catch (IllegalAccessException e) {
-            Log.e("PropertyValuesHolder", e.toString());
         }
     }
 
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 7f9a5d3..e721de9 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -17,6 +17,7 @@
 package android.animation;
 
 import android.annotation.CallSuper;
+import android.annotation.IntDef;
 import android.os.Looper;
 import android.os.Trace;
 import android.util.AndroidRuntimeException;
@@ -25,6 +26,8 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.LinearInterpolator;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.HashMap;
 
@@ -234,6 +237,11 @@
      * Public constants
      */
 
+    /** @hide */
+    @IntDef({RESTART, REVERSE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RepeatMode {}
+
     /**
      * When the animation reaches the end and <code>repeatCount</code> is INFINITE
      * or a positive value, the animation restarts from the beginning.
@@ -807,7 +815,7 @@
      *
      * @param value {@link #RESTART} or {@link #REVERSE}
      */
-    public void setRepeatMode(int value) {
+    public void setRepeatMode(@RepeatMode int value) {
         mRepeatMode = value;
     }
 
@@ -816,6 +824,7 @@
      *
      * @return either one of {@link #REVERSE} or {@link #RESTART}
      */
+    @RepeatMode
     public int getRepeatMode() {
         return mRepeatMode;
     }
diff --git a/core/java/android/annotation/AppIdInt.java b/core/java/android/annotation/AppIdInt.java
new file mode 100644
index 0000000..29838dd
--- /dev/null
+++ b/core/java/android/annotation/AppIdInt.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 android.annotation;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Denotes that the annotated element is a multi-user application ID. This is
+ * <em>not</em> the same as a UID.
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD, PARAMETER, FIELD})
+public @interface AppIdInt {
+}
diff --git a/core/java/android/annotation/IntDef.java b/core/java/android/annotation/IntDef.java
index a18bfa5..434a9c7 100644
--- a/core/java/android/annotation/IntDef.java
+++ b/core/java/android/annotation/IntDef.java
@@ -42,7 +42,7 @@
  * For a flag, set the flag attribute:
  * <pre><code>
  *  &#64;IntDef(
- *      flag = true
+ *      flag = true,
  *      value = {NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
  * </code></pre>
  *
diff --git a/core/java/android/annotation/UserIdInt.java b/core/java/android/annotation/UserIdInt.java
new file mode 100644
index 0000000..7b9ce25
--- /dev/null
+++ b/core/java/android/annotation/UserIdInt.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 android.annotation;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Denotes that the annotated element is a multi-user user ID. This is
+ * <em>not</em> the same as a UID.
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD, PARAMETER, FIELD})
+public @interface UserIdInt {
+}
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 72f8c77..6fc0d74 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -31,9 +31,11 @@
 import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.View;
+import android.view.View.OnFocusChangeListener;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
 import android.view.ViewHierarchyEncoder;
+import android.view.ViewParent;
 import android.view.Window;
 import android.widget.SpinnerAdapter;
 import java.lang.annotation.Retention;
@@ -1071,6 +1073,66 @@
     }
 
     /**
+     * Attempts to move focus to the ActionBar if it does not already contain the focus.
+     *
+     * @return {@code true} if focus changes or {@code false} if focus doesn't change.
+     * @hide
+     */
+    public boolean requestFocus() {
+        return false;
+    }
+
+    /** @hide */
+    public void onDestroy() {
+    }
+
+    /**
+     * Common implementation for requestFocus that takes in the Toolbar and moves focus
+     * to the contents. This makes the ViewGroups containing the toolbar allow focus while it stays
+     * in the ActionBar and then prevents it again once it leaves.
+     *
+     * @param viewGroup The toolbar ViewGroup
+     * @return {@code true} if focus changes or {@code false} if focus doesn't change.
+     * @hide
+     */
+    protected boolean requestFocus(ViewGroup viewGroup) {
+        if (viewGroup != null && !viewGroup.hasFocus()) {
+            final ViewGroup toolbar = viewGroup.getTouchscreenBlocksFocus() ? viewGroup : null;
+            ViewParent parent = viewGroup.getParent();
+            ViewGroup container = null;
+            while (parent != null && parent instanceof ViewGroup) {
+                final ViewGroup vgParent = (ViewGroup) parent;
+                if (vgParent.getTouchscreenBlocksFocus()) {
+                    container = vgParent;
+                    break;
+                }
+                parent = vgParent.getParent();
+            }
+            if (container != null) {
+                container.setTouchscreenBlocksFocus(false);
+            }
+            if (toolbar != null) {
+                toolbar.setTouchscreenBlocksFocus(false);
+            }
+            viewGroup.requestFocus();
+            final View focused = viewGroup.findFocus();
+            if (focused != null) {
+                focused.setOnFocusChangeListener(new FollowOutOfActionBar(viewGroup,
+                        container, toolbar));
+            } else {
+                if (container != null) {
+                    container.setTouchscreenBlocksFocus(true);
+                }
+                if (toolbar != null) {
+                    toolbar.setTouchscreenBlocksFocus(true);
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
      * Listener interface for ActionBar navigation events.
      *
      * @deprecated Action bar navigation modes are deprecated and not supported by inline
@@ -1388,4 +1450,43 @@
             encoder.addProperty("gravity", gravity);
         }
     }
+
+    /**
+     * Tracks the focused View until it leaves the ActionBar, then it resets the
+     * touchscreenBlocksFocus value.
+     */
+    private static class FollowOutOfActionBar implements OnFocusChangeListener, Runnable {
+        private final ViewGroup mFocusRoot;
+        private final ViewGroup mContainer;
+        private final ViewGroup mToolbar;
+
+        public FollowOutOfActionBar(ViewGroup focusRoot, ViewGroup container, ViewGroup toolbar) {
+            mContainer = container;
+            mToolbar = toolbar;
+            mFocusRoot = focusRoot;
+        }
+
+        @Override
+        public void onFocusChange(View v, boolean hasFocus) {
+            if (!hasFocus) {
+                v.setOnFocusChangeListener(null);
+                final View focused = mFocusRoot.findFocus();
+                if (focused != null) {
+                    focused.setOnFocusChangeListener(this);
+                } else {
+                    mFocusRoot.post(this);
+                }
+            }
+        }
+
+        @Override
+        public void run() {
+            if (mContainer != null) {
+                mContainer.setTouchscreenBlocksFocus(true);
+            }
+            if (mToolbar != null) {
+                mToolbar.setTouchscreenBlocksFocus(true);
+            }
+        }
+    }
 }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ef84ab0..11154f2 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -31,6 +31,8 @@
 import android.transition.TransitionManager;
 import android.util.ArrayMap;
 import android.util.SuperNotCalledException;
+import android.view.DragEvent;
+import android.view.DropPermissions;
 import android.view.Window.WindowControllerCallback;
 import android.widget.Toolbar;
 
@@ -60,7 +62,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
-import android.graphics.Rect;
+import android.graphics.drawable.Icon;
 import android.media.AudioManager;
 import android.media.session.MediaController;
 import android.net.Uri;
@@ -70,6 +72,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Parcelable;
+import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.StrictMode;
 import android.os.UserHandle;
@@ -77,23 +80,28 @@
 import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
 import android.text.method.TextKeyListener;
+import android.transition.Scene;
+import android.transition.TransitionManager;
+import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SuperNotCalledException;
 import android.view.ActionMode;
 import android.view.ContextMenu;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.ContextThemeWrapper;
 import android.view.KeyEvent;
+import android.view.KeyboardShortcutGroup;
+import android.view.KeyboardShortcutInfo;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.MotionEvent;
-import com.android.internal.policy.PhoneWindow;
 import android.view.SearchEvent;
 import android.view.View;
 import android.view.View.OnCreateContextMenuListener;
@@ -102,10 +110,17 @@
 import android.view.ViewManager;
 import android.view.ViewRootImpl;
 import android.view.Window;
+import android.view.Window.WindowControllerCallback;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.AdapterView;
+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.PhoneWindow;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -115,6 +130,8 @@
 import java.util.HashMap;
 import java.util.List;
 
+import static java.lang.Character.MIN_VALUE;
+
 /**
  * An activity is a single, focused thing that the user can do.  Almost all
  * activities interact with the user, so the Activity class takes care of
@@ -816,6 +833,7 @@
     SharedElementCallback mExitTransitionListener = SharedElementCallback.NULL_CALLBACK;
 
     private boolean mHasCurrentPermissionsRequest;
+    private boolean mEatKeyUpEvent;
 
     /** Return the intent that started this activity. */
     public Intent getIntent() {
@@ -1249,6 +1267,15 @@
         mCalled = true;
     }
 
+    void setVoiceInteractor(IVoiceInteractor voiceInteractor) {
+        if (voiceInteractor == null) {
+            mVoiceInteractor = null;
+        } else {
+            mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
+                    Looper.myLooper());
+        }
+    }
+
     /**
      * Check whether this activity is running as part of a voice interaction with the user.
      * If true, it should perform its interaction with the user through the
@@ -1283,6 +1310,62 @@
     }
 
     /**
+     * Queries whether the currently enabled voice interaction service supports returning
+     * a voice interactor for use by the activity. This is valid only for the duration of the
+     * activity.
+     *
+     * @return whether the current voice interaction service supports local voice interaction
+     */
+    public boolean isLocalVoiceInteractionSupported() {
+        try {
+            return ActivityManagerNative.getDefault().supportsLocalVoiceInteraction();
+        } catch (RemoteException re) {
+        }
+        return false;
+    }
+
+    /**
+     * Starts a local voice interaction session. When ready,
+     * {@link #onLocalVoiceInteractionStarted()} is called. You can pass a bundle of private options
+     * to the registered voice interaction service.
+     * @param privateOptions a Bundle of private arguments to the current voice interaction service
+     */
+    public void startLocalVoiceInteraction(Bundle privateOptions) {
+        try {
+            ActivityManagerNative.getDefault().startLocalVoiceInteraction(mToken, privateOptions);
+        } catch (RemoteException re) {
+        }
+    }
+
+    /**
+     * Callback to indicate that {@link #startLocalVoiceInteraction(Bundle)} has resulted in a
+     * voice interaction session being started. You can now retrieve a voice interactor using
+     * {@link #getVoiceInteractor()}.
+     */
+    public void onLocalVoiceInteractionStarted() {
+        Log.i(TAG, "onLocalVoiceInteractionStarted! " + getVoiceInteractor());
+    }
+
+    /**
+     * Callback to indicate that the local voice interaction has stopped for some
+     * reason.
+     */
+    public void onLocalVoiceInteractionStopped() {
+        Log.i(TAG, "onLocalVoiceInteractionStopped :( " + getVoiceInteractor());
+    }
+
+    /**
+     * Request to terminate the current voice interaction that was previously started
+     * using {@link #startLocalVoiceInteraction(Bundle)}.
+     */
+    public void stopLocalVoiceInteraction() {
+        try {
+            ActivityManagerNative.getDefault().stopLocalVoiceInteraction(mToken);
+        } catch (RemoteException re) {
+        }
+    }
+
+    /**
      * This is called for activities that set launchMode to "singleTop" in
      * their package, or if a client used the {@link Intent#FLAG_ACTIVITY_SINGLE_TOP}
      * flag when calling {@link #startActivity}.  In either case, when the
@@ -1592,6 +1675,30 @@
     public void onProvideAssistContent(AssistContent outContent) {
     }
 
+    @Override
+    public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {
+        if (menu == null) {
+          return;
+        }
+        KeyboardShortcutGroup group = null;
+        int menuSize = menu.size();
+        for (int i = 0; i < menuSize; ++i) {
+            final MenuItem item = menu.getItem(i);
+            final CharSequence title = item.getTitle();
+            final char alphaShortcut = item.getAlphabeticShortcut();
+            if (title != null && alphaShortcut != MIN_VALUE) {
+                if (group == null) {
+                    group = new KeyboardShortcutGroup(null /* no label */);
+                }
+                group.addItem(new KeyboardShortcutInfo(
+                    title, alphaShortcut, KeyEvent.META_CTRL_ON));
+            }
+        }
+        if (group != null) {
+            data.add(group);
+        }
+    }
+
     /**
      * Ask to have the current assistant shown to the user.  This only works if the calling
      * activity is the current foreground activity.  It is the same as calling
@@ -1700,6 +1807,10 @@
             mSearchManager.stopSearch();
         }
 
+        if (mActionBar != null) {
+            mActionBar.onDestroy();
+        }
+
         getApplication().dispatchActivityDestroyed(this);
     }
 
@@ -1782,6 +1893,17 @@
     }
 
     /**
+     * Puts the activity in picture-in-picture mode.
+     * @see android.R.attr#supportsPictureInPicture
+     */
+    public void enterPictureInPictureMode() {
+        try {
+            ActivityManagerNative.getDefault().enterPictureInPictureMode(mToken);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Called by the system when the device configuration changes while your
      * activity is running.  Note that this will <em>only</em> be called if
      * you have selected configurations you would like to handle with the
@@ -2191,21 +2313,36 @@
      * <p>In order to use a Toolbar within the Activity's window content the application
      * must not request the window feature {@link Window#FEATURE_ACTION_BAR FEATURE_ACTION_BAR}.</p>
      *
-     * @param toolbar Toolbar to set as the Activity's action bar
+     * @param toolbar Toolbar to set as the Activity's action bar, or {@code null} to clear it
      */
     public void setActionBar(@Nullable Toolbar toolbar) {
-        if (getActionBar() instanceof WindowDecorActionBar) {
+        final ActionBar ab = getActionBar();
+        if (ab instanceof WindowDecorActionBar) {
             throw new IllegalStateException("This Activity already has an action bar supplied " +
                     "by the window decor. Do not request Window.FEATURE_ACTION_BAR and set " +
                     "android:windowActionBar to false in your theme to use a Toolbar instead.");
         }
-        // Clear out the MenuInflater to make sure that it is valid for the new Action Bar
+
+        // If we reach here then we're setting a new action bar
+        // First clear out the MenuInflater to make sure that it is valid for the new Action Bar
         mMenuInflater = null;
 
-        ToolbarActionBar tbab = new ToolbarActionBar(toolbar, getTitle(), this);
-        mActionBar = tbab;
-        mWindow.setCallback(tbab.getWrappedWindowCallback());
-        mActionBar.invalidateOptionsMenu();
+        // If we have an action bar currently, destroy it
+        if (ab != null) {
+            ab.onDestroy();
+        }
+
+        if (toolbar != null) {
+            final ToolbarActionBar tbab = new ToolbarActionBar(toolbar, getTitle(), this);
+            mActionBar = tbab;
+            mWindow.setCallback(tbab.getWrappedWindowCallback());
+        } else {
+            mActionBar = null;
+            // Re-set the original window callback since we may have already set a Toolbar wrapper
+            mWindow.setCallback(this);
+        }
+
+        invalidateOptionsMenu();
     }
 
     /**
@@ -2781,17 +2918,15 @@
 
 
     /**
-     * Called to move the window and its activity/task to a different stack container.
-     * For example, a window can move between
-     * {@link android.app.ActivityManager.StackId#FULLSCREEN_WORKSPACE_STACK_ID} stack and
-     * {@link android.app.ActivityManager.StackId#FREEFORM_WORKSPACE_STACK_ID} stack.
+     * Moves the activity from
+     * {@link android.app.ActivityManager.StackId#FREEFORM_WORKSPACE_STACK_ID} to
+     * {@link android.app.ActivityManager.StackId#FULLSCREEN_WORKSPACE_STACK_ID} stack.
      *
-     * @param stackId stack Id to change to.
      * @hide
      */
     @Override
-    public void changeWindowStack(int stackId) throws RemoteException {
-        ActivityManagerNative.getDefault().moveActivityToStack(mToken, stackId);
+    public void exitFreeformMode() throws RemoteException {
+        ActivityManagerNative.getDefault().exitFreeformMode(mToken);
     }
 
     /** Returns the current stack Id for the window.
@@ -2816,9 +2951,24 @@
 
         // Let action bars open menus in response to the menu key prioritized over
         // the window handling it
-        if (event.getKeyCode() == KeyEvent.KEYCODE_MENU &&
+        final int keyCode = event.getKeyCode();
+        if (keyCode == KeyEvent.KEYCODE_MENU &&
                 mActionBar != null && mActionBar.onMenuKeyEvent(event)) {
             return true;
+        } else if (event.isCtrlPressed() &&
+                event.getUnicodeChar(event.getMetaState() & ~KeyEvent.META_CTRL_MASK) == '<') {
+            // Capture the Control-< and send focus to the ActionBar
+            final int action = event.getAction();
+            if (action == KeyEvent.ACTION_DOWN) {
+                final ActionBar actionBar = getActionBar();
+                if (actionBar != null && actionBar.isShowing() && actionBar.requestFocus()) {
+                    mEatKeyUpEvent = true;
+                    return true;
+                }
+            } else if (action == KeyEvent.ACTION_UP && mEatKeyUpEvent) {
+                mEatKeyUpEvent = false;
+                return true;
+            }
         }
 
         Window win = getWindow();
@@ -5289,8 +5439,7 @@
      */
     public boolean isTaskRoot() {
         try {
-            return ActivityManagerNative.getDefault()
-                .getTaskForActivity(mToken, true) >= 0;
+            return ActivityManagerNative.getDefault().getTaskForActivity(mToken, true) >= 0;
         } catch (RemoteException e) {
             return false;
         }
@@ -6011,6 +6160,22 @@
     }
 
     /**
+     * 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>
+     *
+     * @param enabled {@code true} to enable this mode.
+     */
+    public void setVrMode(boolean enabled) {
+        try {
+            ActivityManagerNative.getDefault().setVrMode(mToken, enabled);
+        } catch (RemoteException e) {
+            // pass
+        }
+    }
+
+    /**
      * Start an action mode of the default type {@link ActionMode#TYPE_PRIMARY}.
      *
      * @param callback Callback that will manage lifecycle events for this action mode
@@ -6293,6 +6458,21 @@
         mActivityTransitionState.startPostponedEnterTransition();
     }
 
+    /**
+     * Create {@link DropPermissions} object bound to this activity and controlling the access
+     * permissions for content URIs associated with the {@link DragEvent}.
+     * @param event Drag event
+     * @return The DropPermissions object used to control access to the content URIs. Null if
+     * no content URIs are associated with the event or if permissions could not be granted.
+     */
+    public DropPermissions requestDropPermissions(DragEvent event) {
+        DropPermissions dropPermissions = DropPermissions.obtain(event);
+        if (dropPermissions != null && dropPermissions.take(getActivityToken())) {
+            return dropPermissions;
+        }
+        return null;
+    }
+
     // ------------------ Internal API ------------------
 
     final void setParent(Activity parent) {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index c39ee75..90feab4 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.Manifest;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -36,10 +37,12 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.UriPermission;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -59,12 +62,15 @@
 import android.util.DisplayMetrics;
 import android.util.Size;
 import android.util.Slog;
+
 import org.xmlpull.v1.XmlSerializer;
 
 import java.io.FileDescriptor;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -80,6 +86,36 @@
     private final Handler mHandler;
 
     /**
+     * Defines acceptable types of bugreports.
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            BUGREPORT_OPTION_FULL,
+            BUGREPORT_OPTION_INTERACTIVE,
+            BUGREPORT_OPTION_REMOTE
+    })
+    public @interface BugreportMode {}
+    /**
+     * Takes a bugreport without user interference (and hence causing less
+     * interference to the system), but includes all sections.
+     * @hide
+     */
+    public static final int BUGREPORT_OPTION_FULL = 0;
+    /**
+     * Allows user to monitor progress and enter additional data; might not include all
+     * sections.
+     * @hide
+     */
+    public static final int BUGREPORT_OPTION_INTERACTIVE = 1;
+    /**
+     * Takes a bugreport requested remotely by administrator of the Device Owner app,
+     * not the device's user.
+     * @hide
+     */
+    public static final int BUGREPORT_OPTION_REMOTE = 2;
+
+    /**
      * <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code
      * <meta-data>}</a> name for a 'home' Activity that declares a package that is to be
      * uninstalled in lieu of the declaring one.  The package named here must be
@@ -528,8 +564,7 @@
          * there isn't a display gap.
          */
         public static boolean preserveWindowOnTaskMove(int stackId) {
-            return stackId == FULLSCREEN_WORKSPACE_STACK_ID
-                    || stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID;
+            return stackId == FULLSCREEN_WORKSPACE_STACK_ID || stackId == DOCKED_STACK_ID;
         }
 
         /**
@@ -558,11 +593,35 @@
         }
 
         /**
-         * Returns true if the application windows in this stack should be displayed above all
-         * other application windows, including during the animation.
+         * Returns true if the top task in the task is allowed to return home when finished and
+         * there are other tasks in the stack.
          */
-        public static boolean shouldIncreaseApplicationWindowLayer(int stackId) {
-            return stackId == PINNED_STACK_ID || stackId == DOCKED_STACK_ID;
+        public static boolean allowTopTaskToReturnHome(int stackId) {
+            return stackId != PINNED_STACK_ID;
+        }
+
+        /**
+         * Returns true if the stack should be resized to match the bounds specified by
+         * {@link ActivityOptions#setLaunchBounds} when launching an activity into the stack.
+         */
+        public static boolean resizeStackWithLaunchBounds(int stackId) {
+            return stackId == PINNED_STACK_ID;
+        }
+
+        /**
+         * Returns true if any visible windows belonging to apps in this stack should be kept on
+         * screen when the app is killed due to something like the low memory killer.
+         */
+        public static boolean keepVisibleDeadAppWindowOnScreen(int stackId) {
+            return stackId != PINNED_STACK_ID;
+        }
+
+        /**
+         * Returns true if the backdrop on the client side should match the frame of the window.
+         * Returns false, if the backdrop should be fullscreen.
+         */
+        public static boolean useWindowFrameForBackdrop(int stackId) {
+            return stackId == FREEFORM_WORKSPACE_STACK_ID || stackId == PINNED_STACK_ID;
         }
     }
 
@@ -1245,6 +1304,18 @@
     public static final int RECENT_IGNORE_HOME_STACK_TASKS = 0x0008;
 
     /**
+     * Ignores all tasks that are on the docked stack.
+     * @hide
+     */
+    public static final int RECENT_INGORE_DOCKED_STACK_TASKS = 0x0010;
+
+    /**
+     * Ignores all tasks that are on the pinned stack.
+     * @hide
+     */
+    public static final int RECENT_INGORE_PINNED_STACK_TASKS = 0x0020;
+
+    /**
      * <p></p>Return a list of the tasks that the user has recently launched, with
      * the most recent being first and older ones after in order.
      *
@@ -2252,6 +2323,45 @@
         return clearApplicationUserData(mContext.getPackageName(), null);
     }
 
+
+    /**
+     * Permits an application to get the persistent URI permissions granted to another.
+     *
+     * <p>Typically called by Settings.
+     *
+     * @param packageName application to look for the granted permissions
+     * @return list of granted URI permissions
+     *
+     * @hide
+     */
+    public ParceledListSlice<UriPermission> getGrantedUriPermissions(String packageName) {
+        try {
+            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();
+        }
+    }
+
+    /**
+     * Permits an application to clear the persistent URI permissions granted to another.
+     *
+     * <p>Typically called by Settings.
+     *
+     * @param packageName application to clear its granted permissions
+     *
+     * @hide
+     */
+    public void clearGrantedUriPermissions(String packageName) {
+        try {
+            ActivityManagerNative.getDefault().clearGrantedUriPermissions(packageName,
+                    UserHandle.myUserId());
+        } catch (RemoteException e) {
+            Log.e(TAG, "Couldn't clear granted URI permissions for :" + packageName, e);
+        }
+    }
+
     /**
      * Information you can retrieve about any processes that are in an error condition.
      */
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 373a23f..4fa654f 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -18,6 +18,10 @@
 
 import android.annotation.NonNull;
 import android.content.ComponentName;
+import android.os.IBinder;
+import android.service.voice.IVoiceInteractionSession;
+
+import com.android.internal.app.IVoiceInteractor;
 
 /**
  * Activity manager local system service interface.
@@ -64,4 +68,8 @@
      * @param userId The user being cleaned up.
      */
     public abstract void onUserRemoved(int userId);
+
+    public abstract void onLocalVoiceInteractionStarted(IBinder callingActivity,
+            IVoiceInteractionSession mSession,
+            IVoiceInteractor mInteractor);
 }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index f11bf742..cd5797e 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -315,6 +315,34 @@
             return true;
         }
 
+        case START_LOCAL_VOICE_INTERACTION_TRANSACTION:
+        {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder token = data.readStrongBinder();
+            Bundle options = data.readBundle();
+            startLocalVoiceInteraction(token, options);
+            reply.writeNoException();
+            return true;
+        }
+
+        case STOP_LOCAL_VOICE_INTERACTION_TRANSACTION:
+        {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder token = data.readStrongBinder();
+            stopLocalVoiceInteraction(token);
+            reply.writeNoException();
+            return true;
+        }
+
+        case SUPPORTS_LOCAL_VOICE_INTERACTION_TRANSACTION:
+        {
+            data.enforceInterface(IActivityManager.descriptor);
+            boolean result = supportsLocalVoiceInteraction();
+            reply.writeNoException();
+            reply.writeInt(result? 1 : 0);
+            return true;
+        }
+
         case START_NEXT_MATCHING_ACTIVITY_TRANSACTION:
         {
             data.enforceInterface(IActivityManager.descriptor);
@@ -332,10 +360,9 @@
         {
             data.enforceInterface(IActivityManager.descriptor);
             final int taskId = data.readInt();
-            final int launchStackId = data.readInt();
             final Bundle options =
                     data.readInt() == 0 ? null : Bundle.CREATOR.createFromParcel(data);
-            final int result = startActivityFromRecents(taskId, launchStackId, options);
+            final int result = startActivityFromRecents(taskId, options);
             reply.writeNoException();
             reply.writeInt(result);
             return true;
@@ -571,6 +598,14 @@
             return true;
         }
 
+        case ACTIVITY_RELAUNCHED_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder token = data.readStrongBinder();
+            activityRelaunched(token);
+            reply.writeNoException();
+            return true;
+        }
+
         case GET_CALLING_PACKAGE_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
@@ -781,7 +816,42 @@
                 r = Rect.CREATOR.createFromParcel(data);
             }
             final boolean allowResizeInDockedMode = data.readInt() == 1;
-            resizeStack(stackId, r, allowResizeInDockedMode);
+            final boolean preserveWindows = data.readInt() == 1;
+            final boolean animate = data.readInt() == 1;
+            resizeStack(stackId, r, allowResizeInDockedMode, preserveWindows, animate);
+            reply.writeNoException();
+            return true;
+        }
+
+        case RESIZE_DOCKED_STACK_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            final boolean hasBounds = data.readInt() != 0;
+            Rect bounds = null;
+            if (hasBounds) {
+                bounds = Rect.CREATOR.createFromParcel(data);
+            }
+            final boolean hasTempDockedTaskBounds = data.readInt() != 0;
+            Rect tempDockedTaskBounds = null;
+            if (hasTempDockedTaskBounds) {
+                tempDockedTaskBounds = Rect.CREATOR.createFromParcel(data);
+            }
+            final boolean hasTempDockedTaskInsetBounds = data.readInt() != 0;
+            Rect tempDockedTaskInsetBounds = null;
+            if (hasTempDockedTaskInsetBounds) {
+                tempDockedTaskInsetBounds = Rect.CREATOR.createFromParcel(data);
+            }
+            final boolean hasTempOtherTaskBounds = data.readInt() != 0;
+            Rect tempOtherTaskBounds = null;
+            if (hasTempOtherTaskBounds) {
+                tempOtherTaskBounds = Rect.CREATOR.createFromParcel(data);
+            }
+            final boolean hasTempOtherTaskInsetBounds = data.readInt() != 0;
+            Rect tempOtherTaskInsetBounds = null;
+            if (hasTempOtherTaskInsetBounds) {
+                tempOtherTaskInsetBounds = Rect.CREATOR.createFromParcel(data);
+            }
+            resizeDockedStack(bounds, tempDockedTaskBounds, tempDockedTaskInsetBounds,
+                    tempOtherTaskBounds, tempOtherTaskInsetBounds);
             reply.writeNoException();
             return true;
         }
@@ -1368,6 +1438,26 @@
             return true;
         }
 
+        case GET_GRANTED_URI_PERMISSIONS_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            final String packageName = data.readString();
+            final int userId = data.readInt();
+            final ParceledListSlice<UriPermission> perms = getGrantedUriPermissions(packageName,
+                    userId);
+            reply.writeNoException();
+            perms.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+            return true;
+        }
+
+        case CLEAR_GRANTED_URI_PERMISSIONS_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            final String packageName = data.readString();
+            final int userId = data.readInt();
+            clearGrantedUriPermissions(packageName, userId);
+            reply.writeNoException();
+            return true;
+        }
+
         case SHOW_WAITING_FOR_DEBUGGER_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder b = data.readStrongBinder();
@@ -1845,6 +1935,15 @@
             return true;
         }
 
+        case GET_URI_PERMISSION_OWNER_FOR_ACTIVITY_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder activityToken = data.readStrongBinder();
+            IBinder perm = getUriPermissionOwnerForActivity(activityToken);
+            reply.writeNoException();
+            reply.writeStrongBinder(perm);
+            return true;
+        }
+
         case GRANT_URI_PERMISSION_FROM_OWNER_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder owner = data.readStrongBinder();
@@ -2237,8 +2336,8 @@
 
         case REQUEST_BUG_REPORT_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
-            boolean progress = data.readInt() != 0;
-            requestBugReport(progress);
+            int bugreportType = data.readInt();
+            requestBugReport(bugreportType);
             reply.writeNoException();
             return true;
         }
@@ -2703,11 +2802,10 @@
             reply.writeInt(stackId);
             return true;
         }
-        case MOVE_ACTIVITY_TO_STACK_TRANSACTION: {
+        case EXIT_FREEFORM_MODE_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
-            int stackId = data.readInt();
-            moveActivityToStack(token, stackId);
+            exitFreeformMode(token);
             reply.writeNoException();
             return true;
         }
@@ -2730,7 +2828,8 @@
         case MOVE_TASKS_TO_FULLSCREEN_STACK_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             final int stackId = data.readInt();
-            moveTasksToFullscreenStack(stackId);
+            final boolean onTop = data.readInt() == 1;
+            moveTasksToFullscreenStack(stackId, onTop);
             reply.writeNoException();
             return true;
         }
@@ -2759,6 +2858,29 @@
             reply.writeInt(pipMode ? 1 : 0);
             return true;
         }
+        case ENTER_PICTURE_IN_PICTURE_MODE_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            final IBinder token = data.readStrongBinder();
+            enterPictureInPictureMode(token);
+            reply.writeNoException();
+            return true;
+        }
+        case SET_VR_MODE_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            final IBinder token = data.readStrongBinder();
+            final boolean enable = data.readInt() == 1;
+            setVrMode(token, enable);
+            reply.writeNoException();
+            return true;
+        }
+        case IS_APP_FOREGROUND_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            final int userHandle = data.readInt();
+            final boolean isForeground = isAppForeground(userHandle);
+            reply.writeNoException();
+            reply.writeInt(isForeground ? 1 : 0);
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -3044,6 +3166,43 @@
         data.recycle();
         return result;
     }
+
+    public void startLocalVoiceInteraction(IBinder callingActivity, Bundle options)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(callingActivity);
+        data.writeBundle(options);
+        mRemote.transact(START_LOCAL_VOICE_INTERACTION_TRANSACTION, data, reply, 0);
+        reply.readException();
+        reply.recycle();
+        data.recycle();
+    }
+
+    public void stopLocalVoiceInteraction(IBinder callingActivity) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(callingActivity);
+        mRemote.transact(STOP_LOCAL_VOICE_INTERACTION_TRANSACTION, data, reply, 0);
+        reply.readException();
+        reply.recycle();
+        data.recycle();
+    }
+
+    public boolean supportsLocalVoiceInteraction() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(SUPPORTS_LOCAL_VOICE_INTERACTION_TRANSACTION, data, reply, 0);
+        reply.readException();
+        int result = reply.readInt();
+        reply.recycle();
+        data.recycle();
+        return result != 0;
+    }
+
     public boolean startNextMatchingActivity(IBinder callingActivity,
             Intent intent, Bundle options) throws RemoteException {
         Parcel data = Parcel.obtain();
@@ -3064,13 +3223,12 @@
         data.recycle();
         return result != 0;
     }
-    public int startActivityFromRecents(int taskId, int launchStackId, Bundle options)
+    public int startActivityFromRecents(int taskId, Bundle options)
             throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeInt(taskId);
-        data.writeInt(launchStackId);
         if (options == null) {
             data.writeInt(0);
         } else {
@@ -3358,6 +3516,17 @@
         data.recycle();
         reply.recycle();
     }
+    public void activityRelaunched(IBinder token) throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(token);
+        mRemote.transact(ACTIVITY_RELAUNCHED_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
     public String getCallingPackage(IBinder token) throws RemoteException
     {
         Parcel data = Parcel.obtain();
@@ -3648,9 +3817,8 @@
         return res;
     }
     @Override
-    public void resizeStack(int stackId, Rect r, boolean allowResizeInDockedMode)
-            throws RemoteException
-    {
+    public void resizeStack(int stackId, Rect r, boolean allowResizeInDockedMode,
+            boolean preserveWindows, boolean animate) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
@@ -3662,12 +3830,58 @@
             data.writeInt(0);
         }
         data.writeInt(allowResizeInDockedMode ? 1 : 0);
+        data.writeInt(preserveWindows ? 1 : 0);
+        data.writeInt(animate ? 1 : 0);
         mRemote.transact(RESIZE_STACK_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
     }
     @Override
+    public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
+            Rect tempDockedTaskInsetBounds,
+            Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds)
+            throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        if (dockedBounds != null) {
+            data.writeInt(1);
+            dockedBounds.writeToParcel(data, 0);
+        } else {
+            data.writeInt(0);
+        }
+        if (tempDockedTaskBounds != null) {
+            data.writeInt(1);
+            tempDockedTaskBounds.writeToParcel(data, 0);
+        } else {
+            data.writeInt(0);
+        }
+        if (tempDockedTaskInsetBounds != null) {
+            data.writeInt(1);
+            tempDockedTaskInsetBounds.writeToParcel(data, 0);
+        } else {
+            data.writeInt(0);
+        }
+        if (tempOtherTaskBounds != null) {
+            data.writeInt(1);
+            tempOtherTaskBounds.writeToParcel(data, 0);
+        } else {
+            data.writeInt(0);
+        }
+        if (tempOtherTaskInsetBounds != null) {
+            data.writeInt(1);
+            tempOtherTaskInsetBounds.writeToParcel(data, 0);
+        } else {
+            data.writeInt(0);
+        }
+        mRemote.transact(RESIZE_DOCKED_STACK_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+    @Override
     public void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException
     {
         Parcel data = Parcel.obtain();
@@ -4494,6 +4708,7 @@
         data.writeInt(incoming ? 1 : 0);
         mRemote.transact(GET_PERSISTED_URI_PERMISSIONS_TRANSACTION, data, reply, 0);
         reply.readException();
+        @SuppressWarnings("unchecked")
         final ParceledListSlice<UriPermission> perms = ParceledListSlice.CREATOR.createFromParcel(
                 reply);
         data.recycle();
@@ -4501,6 +4716,37 @@
         return perms;
     }
 
+    @Override
+    public ParceledListSlice<UriPermission> getGrantedUriPermissions(String packageName, int userId)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeString(packageName);
+        data.writeInt(userId);
+        mRemote.transact(GET_GRANTED_URI_PERMISSIONS_TRANSACTION, data, reply, 0);
+        reply.readException();
+        @SuppressWarnings("unchecked")
+        final ParceledListSlice<UriPermission> perms = ParceledListSlice.CREATOR.createFromParcel(
+                reply);
+        data.recycle();
+        reply.recycle();
+        return perms;
+    }
+
+    @Override
+    public void clearGrantedUriPermissions(String packageName, int userId) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeString(packageName);
+        data.writeInt(userId);
+        mRemote.transact(CLEAR_GRANTED_URI_PERMISSIONS_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     public void showWaitingForDebugger(IApplicationThread who, boolean waiting)
             throws RemoteException {
         Parcel data = Parcel.obtain();
@@ -5106,6 +5352,19 @@
         return res;
     }
 
+    public IBinder getUriPermissionOwnerForActivity(IBinder activityToken) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(activityToken);
+        mRemote.transact(GET_URI_PERMISSION_OWNER_FOR_ACTIVITY_TRANSACTION, data, reply, 0);
+        reply.readException();
+        IBinder res = reply.readStrongBinder();
+        data.recycle();
+        reply.recycle();
+        return res;
+    }
+
     public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
             Uri uri, int mode, int sourceUserId, int targetUserId) throws RemoteException {
         Parcel data = Parcel.obtain();
@@ -5638,11 +5897,12 @@
         reply.recycle();
     }
 
-    public void requestBugReport(boolean progress) throws RemoteException {
+    public void requestBugReport(@ActivityManager.BugreportMode int bugreportType)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(progress ? 1 : 0);
+        data.writeInt(bugreportType);
         mRemote.transact(REQUEST_BUG_REPORT_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
@@ -5889,6 +6149,18 @@
         return res;
     }
 
+    public void setVrMode(IBinder token, boolean enabled) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(token);
+        data.writeInt(enabled ? 1 : 0);
+        mRemote.transact(SET_VR_MODE_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     @Override
     public IActivityContainer createStackOnDisplay(int displayId) throws RemoteException {
         Parcel data = Parcel.obtain();
@@ -6314,13 +6586,12 @@
     }
 
     @Override
-    public void moveActivityToStack(IBinder token, int stackId) throws RemoteException {
+    public void exitFreeformMode(IBinder token) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(token);
-        data.writeInt(stackId);
-        mRemote.transact(MOVE_ACTIVITY_TO_STACK_TRANSACTION, data, reply, 0);
+        mRemote.transact(EXIT_FREEFORM_MODE_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
@@ -6379,11 +6650,12 @@
     }
 
     @Override
-    public void moveTasksToFullscreenStack(int fromStackId) throws RemoteException {
+    public void moveTasksToFullscreenStack(int fromStackId, boolean onTop) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeInt(fromStackId);
+        data.writeInt(onTop ? 1 : 0);
         mRemote.transact(MOVE_TASKS_TO_FULLSCREEN_STACK_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
@@ -6433,5 +6705,30 @@
         return pipMode;
     }
 
+    @Override
+    public void enterPictureInPictureMode(IBinder token) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(token);
+        mRemote.transact(ENTER_PICTURE_IN_PICTURE_MODE_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
+    @Override
+    public boolean isAppForeground(int uid) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(uid);
+        mRemote.transact(IS_APP_FOREGROUND_TRANSACTION, data, reply, 0);
+        final boolean isForeground = reply.readInt() == 1 ? true : false;
+        data.recycle();
+        reply.recycle();
+        return isForeground;
+    };
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index cee1aa5..b42cf68 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 
 import android.content.Context;
 import android.content.Intent;
@@ -67,7 +68,8 @@
      * The bounds (window size) that the activity should be launched in. Set to null explicitly for
      * full screen. If the key is not found, previous bounds will be preserved.
      * NOTE: This value is ignored on devices that don't have
-     * {@link android.content.pm.PackageManager#FEATURE_FREEFORM_WINDOW_MANAGEMENT} enabled.
+     * {@link android.content.pm.PackageManager#FEATURE_FREEFORM_WINDOW_MANAGEMENT} or
+     * {@link android.content.pm.PackageManager#FEATURE_PICTURE_IN_PICTURE} enabled.
      * @hide
      */
     public static final String KEY_LAUNCH_BOUNDS = "android:activity.launchBounds";
@@ -145,6 +147,12 @@
     private static final String KEY_ANIM_SPECS = "android:activity.animSpecs";
 
     /**
+     * The stack id the activity should be launched into.
+     * @hide
+     */
+    private static final String KEY_LAUNCH_STACK_ID = "android.activity.launchStackId";
+
+    /**
      * Where the docked stack should be positioned.
      * @hide
      */
@@ -215,6 +223,7 @@
     private int mResultCode;
     private int mExitCoordinatorIndex;
     private PendingIntent mUsageTimeReport;
+    private int mLaunchStackId = INVALID_STACK_ID;
     private int mDockCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
     private AppTransitionAnimationSpec mAnimSpecs[];
 
@@ -754,6 +763,7 @@
                 mExitCoordinatorIndex = opts.getInt(KEY_EXIT_COORDINATOR_INDEX);
                 break;
         }
+        mLaunchStackId = opts.getInt(KEY_LAUNCH_STACK_ID, INVALID_STACK_ID);
         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);
@@ -901,7 +911,19 @@
     }
 
     /** @hide */
-    public int getDockCreateMode() { return mDockCreateMode; }
+    public int getLaunchStackId() {
+        return mLaunchStackId;
+    }
+
+    /** @hide */
+    public void setLaunchStackId(int launchStackId) {
+        mLaunchStackId = launchStackId;
+    }
+
+    /** @hide */
+    public int getDockCreateMode() {
+        return mDockCreateMode;
+    }
 
     /** @hide */
     public void setDockCreateMode(int dockCreateMode) {
@@ -1049,6 +1071,7 @@
                 b.putInt(KEY_EXIT_COORDINATOR_INDEX, mExitCoordinatorIndex);
                 break;
         }
+        b.putInt(KEY_LAUNCH_STACK_ID, mLaunchStackId);
         b.putInt(KEY_DOCK_CREATE_MODE, mDockCreateMode);
         if (mAnimSpecs != null) {
             b.putParcelableArray(KEY_ANIM_SPECS, mAnimSpecs);
@@ -1102,4 +1125,11 @@
         return null;
     }
 
+    /** @hide */
+    @Override
+    public String toString() {
+        return "ActivityOptions(" + hashCode() + "), mPackageName=" + mPackageName
+                + ", mAnimationType=" + mAnimationType + ", mStartX=" + mStartX + ", mStartY="
+                + mStartY + ", mWidth=" + mWidth + ", mHeight=" + mHeight;
+    }
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 3962abd..1e7457c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -83,6 +83,7 @@
 import android.util.ArrayMap;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
+import android.util.LocaleList;
 import android.util.Log;
 import android.util.LogPrinter;
 import android.util.Pair;
@@ -101,6 +102,9 @@
 import android.view.WindowManagerGlobal;
 import android.renderscript.RenderScriptCacheDir;
 import android.security.keystore.AndroidKeyStoreProvider;
+import android.system.Os;
+import android.system.OsConstants;
+import android.system.ErrnoException;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IVoiceInteractor;
@@ -123,8 +127,8 @@
 import java.net.InetAddress;
 import java.text.DateFormat;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
-import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.TimeZone;
@@ -819,43 +823,6 @@
 
             setCoreSettings(coreSettings);
 
-            /*
-             * Two possible indications that this package could be
-             * sharing its runtime with other packages:
-             *
-             * 1.) the sharedUserId attribute is set in the manifest,
-             *     indicating a request to share a VM with other
-             *     packages with the same sharedUserId.
-             *
-             * 2.) the application element of the manifest has an
-             *     attribute specifying a non-default process name,
-             *     indicating the desire to run in another packages VM.
-             *
-             * If sharing is enabled we do not have a unique application
-             * in a process and therefore cannot rely on the package
-             * name inside the runtime.
-             */
-            IPackageManager pm = getPackageManager();
-            android.content.pm.PackageInfo pi = null;
-            try {
-                pi = pm.getPackageInfo(appInfo.packageName, 0, UserHandle.myUserId());
-            } catch (RemoteException e) {
-            }
-            if (pi != null) {
-                boolean sharedUserIdSet = (pi.sharedUserId != null);
-                boolean processNameNotDefault =
-                (pi.applicationInfo != null &&
-                 !appInfo.packageName.equals(pi.applicationInfo.processName));
-                boolean sharable = (sharedUserIdSet || processNameNotDefault);
-
-                // Tell the VMRuntime about the application, unless it is shared
-                // inside a process.
-                if (!sharable) {
-                    VMRuntime.registerAppInfo(appInfo.packageName, appInfo.dataDir,
-                                            appInfo.processName);
-                }
-            }
-
             AppBindData data = new AppBindData();
             data.processName = processName;
             data.appInfo = appInfo;
@@ -1287,6 +1254,15 @@
                 throws RemoteException {
             sendMessage(H.PICTURE_IN_PICTURE_MODE_CHANGED, token, pipMode ? 1 : 0);
         }
+
+        @Override
+        public void scheduleLocalVoiceInteractionStarted(IBinder token,
+                IVoiceInteractor voiceInteractor) throws RemoteException {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = token;
+            args.arg2 = voiceInteractor;
+            sendMessage(H.LOCAL_VOICE_INTERACTION_STARTED, args);
+        }
     }
 
     private int getLifecycleSeq() {
@@ -1350,6 +1326,7 @@
         public static final int STOP_BINDER_TRACKING_AND_DUMP = 151;
         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) {
             if (DEBUG_MESSAGES) {
@@ -1405,6 +1382,7 @@
                     case ENTER_ANIMATION_COMPLETE: return "ENTER_ANIMATION_COMPLETE";
                     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";
                 }
             }
             return Integer.toString(code);
@@ -1654,6 +1632,10 @@
                 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,
+                            (IVoiceInteractor) ((SomeArgs) msg.obj).arg2);
+                    break;
             }
             Object obj = msg.obj;
             if (obj instanceof SomeArgs) {
@@ -1848,7 +1830,9 @@
         ApplicationInfo ai = null;
         try {
             ai = getPackageManager().getApplicationInfo(packageName,
-                    PackageManager.GET_SHARED_LIBRARY_FILES, userId);
+                    PackageManager.GET_SHARED_LIBRARY_FILES
+                            | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
+                    userId);
         } catch (RemoteException e) {
             // Ignore
         }
@@ -2046,7 +2030,7 @@
     private static final String ONE_COUNT_COLUMN_HEADER = "%21s %8s";
 
     // Formatting for checkin service - update version if row format changes
-    private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 3;
+    private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 4;
 
     static void printRow(PrintWriter pw, String format, Object...objs) {
         pw.println(String.format(format, objs));
@@ -2122,6 +2106,25 @@
             pw.print(memInfo.otherPrivateClean); pw.print(',');
             pw.print(memInfo.getTotalPrivateClean()); pw.print(',');
 
+            // Heap info - swapped out
+            pw.print(memInfo.nativeSwappedOut); pw.print(',');
+            pw.print(memInfo.dalvikSwappedOut); pw.print(',');
+            pw.print(memInfo.otherSwappedOut); pw.print(',');
+            pw.print(memInfo.getTotalSwappedOut()); pw.print(',');
+
+            // Heap info - swapped out pss
+            if (memInfo.hasSwappedOutPss) {
+                pw.print(memInfo.nativeSwappedOutPss); pw.print(',');
+                pw.print(memInfo.dalvikSwappedOutPss); pw.print(',');
+                pw.print(memInfo.otherSwappedOutPss); pw.print(',');
+                pw.print(memInfo.getTotalSwappedOutPss()); pw.print(',');
+            } else {
+                pw.print("N/A,");
+                pw.print("N/A,");
+                pw.print("N/A,");
+                pw.print("N/A,");
+            }
+
             // Heap info - other areas
             for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
                 pw.print(Debug.MemoryInfo.getOtherLabel(i)); pw.print(',');
@@ -2131,6 +2134,12 @@
                 pw.print(memInfo.getOtherSharedClean(i)); pw.print(',');
                 pw.print(memInfo.getOtherPrivateDirty(i)); pw.print(',');
                 pw.print(memInfo.getOtherPrivateClean(i)); pw.print(',');
+                pw.print(memInfo.getOtherSwappedOut(i)); pw.print(',');
+                if (memInfo.hasSwappedOutPss) {
+                    pw.print(memInfo.getOtherSwappedOutPss(i)); pw.print(',');
+                } else {
+                    pw.print("N/A,");
+                }
             }
             return;
         }
@@ -2138,35 +2147,44 @@
         if (!dumpSummaryOnly) {
             if (dumpFullInfo) {
                 printRow(pw, HEAP_FULL_COLUMN, "", "Pss", "Pss", "Shared", "Private",
-                        "Shared", "Private", "Swapped", "Heap", "Heap", "Heap");
+                        "Shared", "Private", memInfo.hasSwappedOutPss ? "SwapPss" : "Swap",
+                        "Heap", "Heap", "Heap");
                 printRow(pw, HEAP_FULL_COLUMN, "", "Total", "Clean", "Dirty", "Dirty",
-                        "Clean", "Clean", "Dirty", "Size", "Alloc", "Free");
+                        "Clean", "Clean", "Dirty",
+                        "Size", "Alloc", "Free");
                 printRow(pw, HEAP_FULL_COLUMN, "", "------", "------", "------", "------",
                         "------", "------", "------", "------", "------", "------");
                 printRow(pw, HEAP_FULL_COLUMN, "Native Heap", memInfo.nativePss,
                         memInfo.nativeSwappablePss, memInfo.nativeSharedDirty,
                         memInfo.nativePrivateDirty, memInfo.nativeSharedClean,
-                        memInfo.nativePrivateClean, memInfo.nativeSwappedOut,
+                        memInfo.nativePrivateClean, memInfo.hasSwappedOutPss ?
+                        memInfo.nativeSwappedOut : memInfo.nativeSwappedOutPss,
                         nativeMax, nativeAllocated, nativeFree);
                 printRow(pw, HEAP_FULL_COLUMN, "Dalvik Heap", memInfo.dalvikPss,
                         memInfo.dalvikSwappablePss, memInfo.dalvikSharedDirty,
                         memInfo.dalvikPrivateDirty, memInfo.dalvikSharedClean,
-                        memInfo.dalvikPrivateClean, memInfo.dalvikSwappedOut,
+                        memInfo.dalvikPrivateClean, memInfo.hasSwappedOutPss ?
+                        memInfo.dalvikSwappedOut : memInfo.dalvikSwappedOutPss,
                         dalvikMax, dalvikAllocated, dalvikFree);
             } else {
                 printRow(pw, HEAP_COLUMN, "", "Pss", "Private",
-                        "Private", "Swapped", "Heap", "Heap", "Heap");
+                        "Private", memInfo.hasSwappedOutPss ? "SwapPss" : "Swap",
+                        "Heap", "Heap", "Heap");
                 printRow(pw, HEAP_COLUMN, "", "Total", "Dirty",
                         "Clean", "Dirty", "Size", "Alloc", "Free");
                 printRow(pw, HEAP_COLUMN, "", "------", "------", "------",
                         "------", "------", "------", "------", "------");
                 printRow(pw, HEAP_COLUMN, "Native Heap", memInfo.nativePss,
                         memInfo.nativePrivateDirty,
-                        memInfo.nativePrivateClean, memInfo.nativeSwappedOut,
+                        memInfo.nativePrivateClean,
+                        memInfo.hasSwappedOutPss ? memInfo.nativeSwappedOutPss :
+                        memInfo.nativeSwappedOut,
                         nativeMax, nativeAllocated, nativeFree);
                 printRow(pw, HEAP_COLUMN, "Dalvik Heap", memInfo.dalvikPss,
                         memInfo.dalvikPrivateDirty,
-                        memInfo.dalvikPrivateClean, memInfo.dalvikSwappedOut,
+                        memInfo.dalvikPrivateClean,
+                        memInfo.hasSwappedOutPss ? memInfo.dalvikSwappedOutPss :
+                        memInfo.dalvikSwappedOut,
                         dalvikMax, dalvikAllocated, dalvikFree);
             }
 
@@ -2177,6 +2195,7 @@
             int otherSharedClean = memInfo.otherSharedClean;
             int otherPrivateClean = memInfo.otherPrivateClean;
             int otherSwappedOut = memInfo.otherSwappedOut;
+            int otherSwappedOutPss = memInfo.otherSwappedOutPss;
 
             for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
                 final int myPss = memInfo.getOtherPss(i);
@@ -2186,16 +2205,22 @@
                 final int mySharedClean = memInfo.getOtherSharedClean(i);
                 final int myPrivateClean = memInfo.getOtherPrivateClean(i);
                 final int mySwappedOut = memInfo.getOtherSwappedOut(i);
+                final int mySwappedOutPss = memInfo.getOtherSwappedOutPss(i);
                 if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
-                        || mySharedClean != 0 || myPrivateClean != 0 || mySwappedOut != 0) {
+                        || mySharedClean != 0 || myPrivateClean != 0
+                        || (memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut) != 0) {
                     if (dumpFullInfo) {
                         printRow(pw, HEAP_FULL_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
                                 myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
-                                mySharedClean, myPrivateClean, mySwappedOut, "", "", "");
+                                mySharedClean, myPrivateClean,
+                                memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut,
+                                "", "", "");
                     } else {
                         printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
                                 myPss, myPrivateDirty,
-                                myPrivateClean, mySwappedOut, "", "", "");
+                                myPrivateClean,
+                                memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut,
+                                "", "", "");
                     }
                     otherPss -= myPss;
                     otherSwappablePss -= mySwappablePss;
@@ -2204,26 +2229,32 @@
                     otherSharedClean -= mySharedClean;
                     otherPrivateClean -= myPrivateClean;
                     otherSwappedOut -= mySwappedOut;
+                    otherSwappedOutPss -= mySwappedOutPss;
                 }
             }
 
             if (dumpFullInfo) {
                 printRow(pw, HEAP_FULL_COLUMN, "Unknown", otherPss, otherSwappablePss,
                         otherSharedDirty, otherPrivateDirty, otherSharedClean, otherPrivateClean,
-                        otherSwappedOut, "", "", "");
+                        memInfo.hasSwappedOutPss ? otherSwappedOutPss : otherSwappedOut,
+                        "", "", "");
                 printRow(pw, HEAP_FULL_COLUMN, "TOTAL", memInfo.getTotalPss(),
                         memInfo.getTotalSwappablePss(),
                         memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(),
                         memInfo.getTotalSharedClean(), memInfo.getTotalPrivateClean(),
-                        memInfo.getTotalSwappedOut(), nativeMax+dalvikMax,
-                        nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
+                        memInfo.hasSwappedOutPss ? memInfo.getTotalSwappedOut() :
+                        memInfo.getTotalSwappedOutPss(),
+                        nativeMax+dalvikMax, nativeAllocated+dalvikAllocated,
+                        nativeFree+dalvikFree);
             } else {
                 printRow(pw, HEAP_COLUMN, "Unknown", otherPss,
-                        otherPrivateDirty, otherPrivateClean, otherSwappedOut,
+                        otherPrivateDirty, otherPrivateClean,
+                        memInfo.hasSwappedOutPss ? otherSwappedOutPss : otherSwappedOut,
                         "", "", "");
                 printRow(pw, HEAP_COLUMN, "TOTAL", memInfo.getTotalPss(),
                         memInfo.getTotalPrivateDirty(),
                         memInfo.getTotalPrivateClean(),
+                        memInfo.hasSwappedOutPss ? memInfo.getTotalSwappedOutPss() :
                         memInfo.getTotalSwappedOut(),
                         nativeMax+dalvikMax,
                         nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
@@ -2242,16 +2273,22 @@
                     final int mySharedClean = memInfo.getOtherSharedClean(i);
                     final int myPrivateClean = memInfo.getOtherPrivateClean(i);
                     final int mySwappedOut = memInfo.getOtherSwappedOut(i);
+                    final int mySwappedOutPss = memInfo.getOtherSwappedOutPss(i);
                     if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
-                            || mySharedClean != 0 || myPrivateClean != 0) {
+                            || mySharedClean != 0 || myPrivateClean != 0
+                            || (memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut) != 0) {
                         if (dumpFullInfo) {
                             printRow(pw, HEAP_FULL_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
                                     myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
-                                    mySharedClean, myPrivateClean, mySwappedOut, "", "", "");
+                                    mySharedClean, myPrivateClean,
+                                    memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut,
+                                    "", "", "");
                         } else {
                             printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
                                     myPss, myPrivateDirty,
-                                    myPrivateClean, mySwappedOut, "", "", "");
+                                    myPrivateClean,
+                                    memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut,
+                                    "", "", "");
                         }
                     }
                 }
@@ -2277,9 +2314,15 @@
         printRow(pw, ONE_COUNT_COLUMN,
             "System:", memInfo.getSummarySystem());
         pw.println(" ");
-        printRow(pw, TWO_COUNT_COLUMNS,
-            "TOTAL:", memInfo.getSummaryTotalPss(),
-            "TOTAL SWAP (KB):", memInfo.getSummaryTotalSwap());
+        if (memInfo.hasSwappedOutPss) {
+            printRow(pw, TWO_COUNT_COLUMNS,
+                "TOTAL:", memInfo.getSummaryTotalPss(),
+                "TOTAL SWAP PSS:", memInfo.getSummaryTotalSwapPss());
+        } else {
+            printRow(pw, TWO_COUNT_COLUMNS,
+                "TOTAL:", memInfo.getSummaryTotalPss(),
+                "TOTAL SWAP (KB):", memInfo.getSummaryTotalSwap());
+        }
     }
 
     public void registerOnActivityPausedListener(Activity activity,
@@ -2850,6 +2893,19 @@
         }
     }
 
+    private void handleLocalVoiceInteractionStarted(IBinder token, IVoiceInteractor interactor) {
+        final ActivityClientRecord r = mActivities.get(token);
+        if (r != null) {
+            r.voiceInteractor = interactor;
+            r.activity.setVoiceInteractor(interactor);
+            if (interactor == null) {
+                r.activity.onLocalVoiceInteractionStopped();
+            } else {
+                r.activity.onLocalVoiceInteractionStarted();
+            }
+        }
+    }
+
     private static final ThreadLocal<Intent> sCurrentBroadcastIntent = new ThreadLocal<Intent>();
 
     /**
@@ -4155,6 +4211,15 @@
                             r.pendingIntents = pendingNewIntents;
                         }
                     }
+
+                    // For each relaunch request, activity manager expects an answer
+                    if (!r.onlyLocalRequest && fromServer) {
+                        try {
+                            ActivityManagerNative.getDefault().activityRelaunched(token);
+                        } catch (RemoteException e) {
+                            e.printStackTrace();
+                        }
+                    }
                     break;
                 }
             }
@@ -4269,6 +4334,13 @@
         ActivityClientRecord r = mActivities.get(tmp.token);
         if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handling relaunch of " + r);
         if (r == null) {
+            if (!tmp.onlyLocalRequest) {
+                try {
+                    ActivityManagerNative.getDefault().activityRelaunched(tmp.token);
+                } catch (RemoteException e) {
+                    // If the system process has died, it's game over for everyone.
+                }
+            }
             return;
         }
 
@@ -4281,6 +4353,21 @@
 
         r.activity.mChangingConfigurations = true;
 
+        // If we are preserving the main window across relaunches we would also like to preserve
+        // the children. However the client side view system does not support preserving
+        // the child views so we notify the window manager to expect these windows to
+        // be replaced and defer requests to destroy or hide them. This way we can achieve
+        // visual continuity. It's important that we do this here prior to pause and destroy
+        // as that is when we may hide or remove the child views.
+        try {
+            if (r.mPreserveWindow) {
+                WindowManagerGlobal.getWindowSession().prepareToReplaceChildren(r.token);
+            }
+        } catch (RemoteException e) {
+            // If the system process has died, it's game over for everyone.
+        }
+
+
         // Need to ensure state is saved.
         if (!r.paused) {
             performPauseActivity(r.token, false, r.isPreHoneycomb());
@@ -4314,6 +4401,17 @@
         r.overrideConfig = tmp.overrideConfig;
 
         handleLaunchActivity(r, currentIntent);
+
+        if (!tmp.onlyLocalRequest) {
+            try {
+                ActivityManagerNative.getDefault().activityRelaunched(r.token);
+                if (r.window != null) {
+                    r.window.reportActivityRelaunched();
+                }
+            } catch (RemoteException e) {
+                // If the system process has died, it's game over for everyone.
+            }
+        }
     }
 
     private void callCallActivityOnSaveInstanceState(ActivityClientRecord r) {
@@ -4667,6 +4765,90 @@
         }
     }
 
+    private static void setupJitProfileSupport(LoadedApk loadedApk, File cacheDir) {
+        if (!SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false)) {
+            return;
+        }
+        final ApplicationInfo appInfo = loadedApk.getApplicationInfo();
+        if (isSharingRuntime(appInfo)) {
+            // If sharing is enabled we do not have a unique application
+            // in a process and therefore cannot rely on the package
+            // name inside the runtime.
+            return;
+        }
+        final List<String> codePaths = new ArrayList<>();
+        if ((appInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
+            codePaths.add(appInfo.sourceDir);
+        }
+        if (appInfo.splitSourceDirs != null) {
+            Collections.addAll(codePaths, appInfo.splitSourceDirs);
+        }
+
+        if (codePaths.isEmpty()) {
+            // If there are no code paths there's no need to setup a profile file and register with
+            // the runtime,
+            return;
+        }
+
+        // Add an extension to the file name to better reveal its intended use.
+        // Keep in sync with BackgroundDexOptService.
+        final String profileExtension = ".prof";
+        final File profileFile = new File(cacheDir, loadedApk.mPackageName + profileExtension);
+        if (!profileFile.exists()) {
+            FileDescriptor fd = null;
+            try {
+                final int permissions = 0600;  // read-write for user.
+                fd = Os.open(profileFile.getAbsolutePath(), OsConstants.O_CREAT, permissions);
+                Os.fchmod(fd, permissions);
+                Os.fchown(fd, appInfo.uid, appInfo.uid);
+            } catch (ErrnoException e) {
+                Log.w(TAG, "Unable to create jit profile file " + profileFile, e);
+                try {
+                    Os.unlink(profileFile.getAbsolutePath());
+                } catch (ErrnoException unlinkErr) {
+                    Log.v(TAG, "Unable to unlink jit profile file " + profileFile, unlinkErr);
+                }
+                return;
+            } finally {
+                IoUtils.closeQuietly(fd);
+            }
+        }
+
+        VMRuntime.registerAppInfo(profileFile.getAbsolutePath(), appInfo.dataDir,
+                codePaths.toArray(new String[codePaths.size()]));
+    }
+
+    /*
+     * Two possible indications that this package could be
+     * sharing its runtime with other packages:
+     *
+     * 1) the sharedUserId attribute is set in the manifest,
+     *    indicating a request to share a VM with other
+     *    packages with the same sharedUserId.
+     *
+     * 2) the application element of the manifest has an
+     *    attribute specifying a non-default process name,
+     *    indicating the desire to run in another packages VM.
+     */
+    private static boolean isSharingRuntime(ApplicationInfo appInfo) {
+        IPackageManager pm = getPackageManager();
+        android.content.pm.PackageInfo pi = null;
+        try {
+            pi = pm.getPackageInfo(appInfo.packageName, 0, UserHandle.myUserId());
+        } catch (RemoteException e) {
+        }
+        if (pi != null) {
+            boolean sharedUserIdSet = (pi.sharedUserId != null);
+            boolean processNameNotDefault = (pi.applicationInfo != null) &&
+                    !appInfo.packageName.equals(pi.applicationInfo.processName);
+            boolean sharable = sharedUserIdSet || processNameNotDefault;
+            return sharable;
+        }
+        // We couldn't get information for the package. Be pessimistic and assume
+        // it's sharing the runtime.
+        return true;
+    }
+
     private void updateDefaultDensity() {
         if (mCurDefaultDisplayDpi != Configuration.DENSITY_DPI_UNDEFINED
                 && mCurDefaultDisplayDpi != DisplayMetrics.DENSITY_DEVICE
@@ -4733,9 +4915,11 @@
         TimeZone.setDefault(null);
 
         /*
-         * Initialize the default locale in this process for the reasons we set the time zone.
+         * 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.
          */
-        Locale.setDefault(data.config.locale);
+        mResourcesManager.setDefaultLocalesLocked(data.config.getLocales());
 
         /*
          * Update the system configuration since its preloaded and might not
@@ -4870,12 +5054,14 @@
                         + "due to missing cache directory");
             }
 
-            // Use codeCacheDir to store generated/compiled graphics code
+            // Use codeCacheDir to store generated/compiled graphics code and jit profiling data.
             final File codeCacheDir = appContext.getCodeCacheDir();
             if (codeCacheDir != null) {
                 setupGraphicsSupport(data.info, codeCacheDir);
+                setupJitProfileSupport(data.info, codeCacheDir);
             } else {
-                Log.e(TAG, "Unable to setupGraphicsSupport due to missing code-cache directory");
+                Log.e(TAG, "Unable to setupGraphicsSupport and setupJitProfileSupport " +
+                        "due to missing code-cache directory");
             }
         }
 
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index e28fb20..af840d0 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -894,7 +894,9 @@
             final View decor = getDecor();
             if (decor != null) {
                 final ViewRootImpl viewRoot = decor.getViewRootImpl();
-                viewRoot.setPausedForTransition(false);
+                if (viewRoot != null) {
+                    viewRoot.setPausedForTransition(false);
+                }
             }
             onTransitionsComplete();
         }
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index 38562da..bf0bd79 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -206,7 +206,7 @@
     }
 
     private void startEnter() {
-        if (mEnterActivityOptions.isReturning()) {
+        if (mEnterTransitionCoordinator.isReturning()) {
             if (mExitingToView != null) {
                 mEnterTransitionCoordinator.viewInstancesReady(mExitingFrom, mExitingTo,
                         mExitingToView);
@@ -238,6 +238,7 @@
 
     public void onResume() {
         restoreExitedViews();
+        restoreReenteringViews();
     }
 
     public void clear() {
@@ -258,6 +259,15 @@
         }
     }
 
+    private void restoreReenteringViews() {
+        if (mEnterTransitionCoordinator != null && mEnterTransitionCoordinator.isReturning()) {
+            mEnterTransitionCoordinator.forceViewsToAppear();
+            mExitingFrom = null;
+            mExitingTo = null;
+            mExitingToView = null;
+        }
+    }
+
     public boolean startExitBackTransition(final Activity activity) {
         if (mEnteringNames == null) {
             return false;
diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java
index ddb2d46..7d0d1b4 100644
--- a/core/java/android/app/ApplicationLoaders.java
+++ b/core/java/android/app/ApplicationLoaders.java
@@ -27,7 +27,7 @@
         return gApplicationLoaders;
     }
 
-    public ClassLoader getClassLoader(String zip, String librarySearchPath,
+    public ClassLoader getClassLoader(String zip, boolean isBundled, String librarySearchPath,
                                       String libraryPermittedPath, ClassLoader parent)
     {
         /*
@@ -56,7 +56,8 @@
     
                 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
                 PathClassLoader pathClassloader =
-                    new PathClassLoader(zip, librarySearchPath, libraryPermittedPath, parent);
+                    new PathClassLoader(zip, isBundled, librarySearchPath,
+                                        libraryPermittedPath, parent);
                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
 
                 mLoaders.put(zip, pathClassloader);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 77721e6..220fb607 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -42,7 +42,6 @@
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.KeySet;
-import android.content.pm.ManifestDigest;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageItemInfo;
@@ -214,10 +213,15 @@
     }
 
     @Override
-    public int[] getPackageGids(String packageName)
+    public int[] getPackageGids(String packageName) throws NameNotFoundException {
+        return getPackageGids(packageName, 0);
+    }
+
+    @Override
+    public int[] getPackageGids(String packageName, int flags)
             throws NameNotFoundException {
         try {
-            int[] gids = mPM.getPackageGids(packageName, mContext.getUserId());
+            int[] gids = mPM.getPackageGids(packageName, flags, mContext.getUserId());
             if (gids != null) {
                 return gids;
             }
@@ -229,10 +233,20 @@
     }
 
     @Override
-    public int getPackageUid(String packageName, int userHandle)
+    public int getPackageUid(String packageName, int flags) throws NameNotFoundException {
+        return getPackageUidAsUser(packageName, flags, mContext.getUserId());
+    }
+
+    @Override
+    public int getPackageUidAsUser(String packageName, int userId) throws NameNotFoundException {
+        return getPackageUidAsUser(packageName, 0, userId);
+    }
+
+    @Override
+    public int getPackageUidAsUser(String packageName, int flags, int userId)
             throws NameNotFoundException {
         try {
-            int uid = mPM.getPackageUid(packageName, userHandle);
+            int uid = mPM.getPackageUid(packageName, flags, userId);
             if (uid >= 0) {
                 return uid;
             }
@@ -300,8 +314,14 @@
     @Override
     public ApplicationInfo getApplicationInfo(String packageName, int flags)
             throws NameNotFoundException {
+        return getApplicationInfoAsUser(packageName, flags, mContext.getUserId());
+    }
+
+    @Override
+    public ApplicationInfo getApplicationInfoAsUser(String packageName, int flags, int userId)
+            throws NameNotFoundException {
         try {
-            ApplicationInfo ai = mPM.getApplicationInfo(packageName, flags, mContext.getUserId());
+            ApplicationInfo ai = mPM.getApplicationInfo(packageName, flags, userId);
             if (ai != null) {
                 // This is a temporary hack. Callers must use
                 // createPackageContext(packageName).getApplicationInfo() to
@@ -338,7 +358,6 @@
         }
     }
 
-
     @Override
     public ActivityInfo getActivityInfo(ComponentName className, int flags)
             throws NameNotFoundException {
@@ -591,12 +610,12 @@
     @SuppressWarnings("unchecked")
     @Override
     public List<PackageInfo> getInstalledPackages(int flags) {
-        return getInstalledPackages(flags, mContext.getUserId());
+        return getInstalledPackagesAsUser(flags, mContext.getUserId());
     }
 
     /** @hide */
     @Override
-    public List<PackageInfo> getInstalledPackages(int flags, int userId) {
+    public List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {
         try {
             ParceledListSlice<PackageInfo> slice = mPM.getInstalledPackages(flags, userId);
             return slice.getList();
@@ -780,7 +799,7 @@
      * @hide
      */
     @Override
-    public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags, int userId) {
+    public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent, int flags, int userId) {
         try {
             return mPM.queryIntentReceivers(
                 intent,
@@ -794,7 +813,7 @@
 
     @Override
     public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) {
-        return queryBroadcastReceivers(intent, flags, mContext.getUserId());
+        return queryBroadcastReceiversAsUser(intent, flags, mContext.getUserId());
     }
 
     @Override
@@ -1080,13 +1099,24 @@
 
     @Override
     public Drawable getUserBadgeForDensity(UserHandle user, int density) {
+        return getManagedProfileIconForDensity(user, density,
+                com.android.internal.R.drawable.ic_corp_badge);
+    }
+
+    @Override
+    public Drawable getUserBadgeForDensityNoBackground(UserHandle user, int density) {
+        return getManagedProfileIconForDensity(user, density,
+                com.android.internal.R.drawable.ic_corp_badge_no_background);
+    }
+
+    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(
-                    com.android.internal.R.drawable.ic_corp_badge, density);
+            return Resources.getSystem().getDrawableForDensity(drawableId, density);
         }
         return null;
     }
@@ -1155,8 +1185,10 @@
         throw new NameNotFoundException("Package " + appPackageName + " doesn't exist");
     }
 
-    int mCachedSafeMode = -1;
-    @Override public boolean isSafeMode() {
+    volatile int mCachedSafeMode = -1;
+
+    @Override
+    public boolean isSafeMode() {
         try {
             if (mCachedSafeMode < 0) {
                 mCachedSafeMode = mPM.isSafeMode() ? 1 : 0;
@@ -1421,7 +1453,7 @@
     public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
                                String installerPackageName) {
         final VerificationParams verificationParams = new VerificationParams(null, null,
-                null, VerificationParams.NO_UID, null);
+                null, VerificationParams.NO_UID);
         installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
                 installerPackageName, verificationParams, null, mContext.getUserId());
     }
@@ -1429,9 +1461,9 @@
     @Override
     public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
             int flags, String installerPackageName, Uri verificationURI,
-            ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
+            ContainerEncryptionParams encryptionParams) {
         final VerificationParams verificationParams = new VerificationParams(verificationURI, null,
-                null, VerificationParams.NO_UID, manifestDigest);
+                null, VerificationParams.NO_UID);
         installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
                 installerPackageName, verificationParams, encryptionParams, mContext.getUserId());
     }
@@ -1455,7 +1487,7 @@
     public void installPackageAsUser(Uri packageURI, PackageInstallObserver observer, int flags,
                String installerPackageName, int userId) {
         final VerificationParams verificationParams = new VerificationParams(null, null,
-                null, VerificationParams.NO_UID, null);
+                null, VerificationParams.NO_UID);
         installCommon(packageURI, observer, flags, installerPackageName, verificationParams, null,
                 userId);
     }
@@ -1463,10 +1495,10 @@
     @Override
     public void installPackageWithVerification(Uri packageURI,
             PackageInstallObserver observer, int flags, String installerPackageName,
-            Uri verificationURI, ManifestDigest manifestDigest,
+            Uri verificationURI,
             ContainerEncryptionParams encryptionParams) {
         final VerificationParams verificationParams = new VerificationParams(verificationURI, null,
-                null, VerificationParams.NO_UID, manifestDigest);
+                null, VerificationParams.NO_UID);
         installCommon(packageURI, observer, flags, installerPackageName, verificationParams,
                 encryptionParams, mContext.getUserId());
     }
@@ -1547,7 +1579,7 @@
     }
 
     @Override
-    public int getIntentVerificationStatus(String packageName, int userId) {
+    public int getIntentVerificationStatusAsUser(String packageName, int userId) {
         try {
             return mPM.getIntentVerificationStatus(packageName, userId);
         } catch (RemoteException e) {
@@ -1557,7 +1589,7 @@
     }
 
     @Override
-    public boolean updateIntentVerificationStatus(String packageName, int status, int userId) {
+    public boolean updateIntentVerificationStatusAsUser(String packageName, int status, int userId) {
         try {
             return mPM.updateIntentVerificationStatus(packageName, status, userId);
         } catch (RemoteException e) {
@@ -1587,7 +1619,7 @@
     }
 
     @Override
-    public String getDefaultBrowserPackageName(int userId) {
+    public String getDefaultBrowserPackageNameAsUser(int userId) {
         try {
             return mPM.getDefaultBrowserPackageName(userId);
         } catch (RemoteException e) {
@@ -1597,7 +1629,7 @@
     }
 
     @Override
-    public boolean setDefaultBrowserPackageName(String packageName, int userId) {
+    public boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId) {
         try {
             return mPM.setDefaultBrowserPackageName(packageName, userId);
         } catch (RemoteException e) {
@@ -1868,7 +1900,7 @@
     }
 
     @Override
-    public void getPackageSizeInfo(String packageName, int userHandle,
+    public void getPackageSizeInfoAsUser(String packageName, int userHandle,
             IPackageStatsObserver observer) {
         try {
             mPM.getPackageSizeInfo(packageName, userHandle, observer);
@@ -1915,7 +1947,7 @@
     }
 
     @Override
-    public void addPreferredActivity(IntentFilter filter, int match,
+    public void addPreferredActivityAsUser(IntentFilter filter, int match,
             ComponentName[] set, ComponentName activity, int userId) {
         try {
             mPM.addPreferredActivity(filter, match, set, activity, userId);
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 5951c8d..9be7f23 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -425,6 +425,16 @@
             return true;
         }
 
+        case SCHEDULE_LOCAL_VOICE_INTERACTION_STARTED_TRANSACTION:
+        {
+            data.enforceInterface(IApplicationThread.descriptor);
+            IBinder token = data.readStrongBinder();
+            IVoiceInteractor voiceInteractor = IVoiceInteractor.Stub.asInterface(
+                    data.readStrongBinder());
+            scheduleLocalVoiceInteractionStarted(token, voiceInteractor);
+            return true;
+        }
+
         case PROFILER_CONTROL_TRANSACTION:
         {
             data.enforceInterface(IApplicationThread.descriptor);
@@ -1101,6 +1111,17 @@
         data.recycle();
     }
 
+    public final void scheduleLocalVoiceInteractionStarted(IBinder token,
+            IVoiceInteractor voiceInteractor) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        data.writeInterfaceToken(IApplicationThread.descriptor);
+        data.writeStrongBinder(token);
+        data.writeStrongBinder(voiceInteractor != null ? voiceInteractor.asBinder() : null);
+        mRemote.transact(SCHEDULE_LOCAL_VOICE_INTERACTION_STARTED_TRANSACTION, data, null,
+                IBinder.FLAG_ONEWAY);
+        data.recycle();
+    }
+
     public void updateTimeZone() throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 984a186..a147cc8 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -719,7 +719,7 @@
                     Fragment f = op.fragment;
                     int containerId = f.mContainerId;
                     if (mManager.mAdded != null) {
-                        for (int i = 0; i < mManager.mAdded.size(); i++) {
+                        for (int i = mManager.mAdded.size() - 1; i >= 0; i--) {
                             Fragment old = mManager.mAdded.get(i);
                             if (FragmentManagerImpl.DEBUG) {
                                 Log.v(TAG,
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 569ab11..fab3740 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1762,10 +1762,6 @@
 
     @Override
     public Context createDeviceEncryptedStorageContext() {
-        if (!StorageManager.isFileBasedEncryptionEnabled()) {
-            return null;
-        }
-
         final int flags = (mFlags & ~Context.CONTEXT_CREDENTIAL_ENCRYPTED_STORAGE)
                 | Context.CONTEXT_DEVICE_ENCRYPTED_STORAGE;
         return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index 3fbbdff..bbf1607 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -16,11 +16,13 @@
 
 package android.app;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StyleRes;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnClickListener;
 import android.os.Bundle;
-import android.text.format.DateUtils;
 import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -35,99 +37,125 @@
 
 /**
  * A simple dialog containing an {@link android.widget.DatePicker}.
- *
- * <p>See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
- * guide.</p>
+ * <p>
+ * See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
+ * guide.
  */
 public class DatePickerDialog extends AlertDialog implements OnClickListener,
         OnDateChangedListener {
-
     private static final String YEAR = "year";
     private static final String MONTH = "month";
     private static final String DAY = "day";
 
     private final DatePicker mDatePicker;
-    private final OnDateSetListener mDateSetListener;
-    private final Calendar mCalendar;
 
-    private boolean mTitleNeedsUpdate = true;
+    private OnDateSetListener mDateSetListener;
 
     /**
-     * The callback used to indicate the user is done filling in the date.
+     * Creates a new date picker dialog for the current date using the parent
+     * context's default date picker dialog theme.
+     *
+     * @param context the parent context
      */
-    public interface OnDateSetListener {
-
-        /**
-         * @param view The view associated with this listener.
-         * @param year The year that was set.
-         * @param monthOfYear The month that was set (0-11) for compatibility
-         *  with {@link java.util.Calendar}.
-         * @param dayOfMonth The day of the month that was set.
-         */
-        void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth);
+    public DatePickerDialog(@NonNull Context context) {
+        this(context, 0);
     }
 
     /**
-     * @param context The context the dialog is to run in.
-     * @param callBack How the parent is notified that the date is set.
-     * @param year The initial year of the dialog.
-     * @param monthOfYear The initial month of the dialog.
-     * @param dayOfMonth The initial day of the dialog.
+     * Creates a new date picker dialog for the current date.
+     *
+     * @param context the parent context
+     * @param themeResId the resource ID of the theme against which to inflate
+     *                   this dialog, or {@code 0} to use the parent
+     *                   {@code context}'s default alert dialog theme
      */
-    public DatePickerDialog(Context context,
-            OnDateSetListener callBack,
-            int year,
-            int monthOfYear,
-            int dayOfMonth) {
-        this(context, 0, callBack, year, monthOfYear, dayOfMonth);
-    }
-
-    static int resolveDialogTheme(Context context, int resid) {
-        if (resid == 0) {
-            final TypedValue outValue = new TypedValue();
-            context.getTheme().resolveAttribute(R.attr.datePickerDialogTheme, outValue, true);
-            return outValue.resourceId;
-        } else {
-            return resid;
-        }
-    }
-
-    /**
-     * @param context The context the dialog is to run in.
-     * @param theme the theme to apply to this dialog
-     * @param listener How the parent is notified that the date is set.
-     * @param year The initial year of the dialog.
-     * @param monthOfYear The initial month of the dialog.
-     * @param dayOfMonth The initial day of the dialog.
-     */
-    public DatePickerDialog(Context context, int theme, OnDateSetListener listener, int year,
-            int monthOfYear, int dayOfMonth) {
-        super(context, resolveDialogTheme(context, theme));
-
-        mDateSetListener = listener;
-        mCalendar = Calendar.getInstance();
+    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);
     }
 
-    @Override
-    public void onDateChanged(DatePicker view, int year, int month, int day) {
-        mDatePicker.init(year, month, day, this);
-        updateTitle(year, month, day);
+    /**
+     * Creates a new date picker dialog for the specified date using the parent
+     * context's default date picker dialog theme.
+     *
+     * @param context the parent context
+     * @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 dayOfMonth the initially selected day of month (1-31, depending
+     *                   on month)
+     */
+    public DatePickerDialog(@NonNull Context context, @Nullable OnDateSetListener listener,
+            int year, int month, int dayOfMonth) {
+        this(context, 0, listener, year, month, dayOfMonth);
+    }
+
+    /**
+     * Creates a new date picker dialog for the specified date.
+     *
+     * @param context the parent context
+     * @param themeResId the resource ID of the theme against which to inflate
+     *                   this dialog, or {@code 0} to use the parent
+     *                   {@code context}'s default alert dialog theme
+     * @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 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);
+
+        mDateSetListener = listener;
+
+        mDatePicker.updateDate(year, month, dayOfMonth);
+    }
+
+    static @StyleRes int resolveDialogTheme(@NonNull Context context, @StyleRes int themeResId) {
+        if (themeResId == 0) {
+            final TypedValue outValue = new TypedValue();
+            context.getTheme().resolveAttribute(R.attr.datePickerDialogTheme, outValue, true);
+            return outValue.resourceId;
+        } else {
+            return themeResId;
+        }
     }
 
     @Override
-    public void onClick(DialogInterface dialog, int which) {
+    public void onDateChanged(@NonNull DatePicker view, int year, int month, int dayOfMonth) {
+        mDatePicker.init(year, month, dayOfMonth, this);
+    }
+
+    /**
+     * Sets the listener to call when the user sets the date.
+     *
+     * @param listener the listener to call when the user sets the date
+     */
+    public void setOnDateSetListener(@Nullable OnDateSetListener listener) {
+        mDateSetListener = listener;
+    }
+
+    @Override
+    public void onClick(@NonNull DialogInterface dialog, int which) {
         switch (which) {
             case BUTTON_POSITIVE:
                 if (mDateSetListener != null) {
@@ -145,10 +173,11 @@
     }
 
     /**
-     * Gets the {@link DatePicker} contained in this dialog.
+     * Returns the {@link DatePicker} contained in this dialog.
      *
-     * @return The calendar view.
+     * @return the date picker
      */
+    @NonNull
     public DatePicker getDatePicker() {
         return mDatePicker;
     }
@@ -156,34 +185,13 @@
     /**
      * Sets the current date.
      *
-     * @param year The date year.
-     * @param monthOfYear The date month.
-     * @param dayOfMonth The date day of month.
+     * @param year the year
+     * @param month the month (0-11 for compatibility with
+     *              {@link Calendar#MONTH})
+     * @param dayOfMonth the day of month (1-31, depending on month)
      */
-    public void updateDate(int year, int monthOfYear, int dayOfMonth) {
-        mDatePicker.updateDate(year, monthOfYear, dayOfMonth);
-    }
-
-    private void updateTitle(int year, int month, int day) {
-        if (!mDatePicker.getCalendarViewShown()) {
-            mCalendar.set(Calendar.YEAR, year);
-            mCalendar.set(Calendar.MONTH, month);
-            mCalendar.set(Calendar.DAY_OF_MONTH, day);
-            String title = DateUtils.formatDateTime(mContext,
-                    mCalendar.getTimeInMillis(),
-                    DateUtils.FORMAT_SHOW_DATE
-                    | DateUtils.FORMAT_SHOW_WEEKDAY
-                    | DateUtils.FORMAT_SHOW_YEAR
-                    | DateUtils.FORMAT_ABBREV_MONTH
-                    | DateUtils.FORMAT_ABBREV_WEEKDAY);
-            setTitle(title);
-            mTitleNeedsUpdate = true;
-        } else {
-            if (mTitleNeedsUpdate) {
-                mTitleNeedsUpdate = false;
-                setTitle(R.string.date_picker_dialog_title);
-            }
-        }
+    public void updateDate(int year, int month, int dayOfMonth) {
+        mDatePicker.updateDate(year, month, dayOfMonth);
     }
 
     @Override
@@ -213,4 +221,19 @@
             }
         }
     };
+
+    /**
+     * The listener used to indicate the user has finished selecting a date.
+     */
+    public interface OnDateSetListener {
+        /**
+         * @param view the picker associated with the dialog
+         * @param year the selected year
+         * @param month the selected month (0-11 for compatibility with
+         *              {@link Calendar#MONTH})
+         * @param dayOfMonth th selected day of the month (1-31, depending on
+         *                   month)
+         */
+        void onDateSet(DatePicker view, int year, int month, int dayOfMonth);
+    }
 }
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 6e8e2c4..79461b4 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -21,9 +21,8 @@
 import android.annotation.IdRes;
 import android.annotation.LayoutRes;
 import android.annotation.NonNull;
-import android.annotation.StringRes;
-
 import android.annotation.Nullable;
+import android.annotation.StringRes;
 import android.annotation.StyleRes;
 import android.content.ComponentName;
 import android.content.Context;
@@ -44,11 +43,11 @@
 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;
 import android.view.MotionEvent;
-import com.android.internal.policy.PhoneWindow;
 import android.view.SearchEvent;
 import android.view.View;
 import android.view.View.OnCreateContextMenuListener;
@@ -60,8 +59,10 @@
 
 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.
@@ -1081,6 +1082,13 @@
     }
 
     /**
+     * {@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() {
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index fb0e79b..ed4bb28 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -27,6 +27,7 @@
 import android.net.ConnectivityManager;
 import android.net.NetworkPolicyManager;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.provider.Downloads;
@@ -105,8 +106,17 @@
     public final static String COLUMN_LOCAL_URI = "local_uri";
 
     /**
-     * The pathname of the file where the download is stored.
+     * Path to the downloaded file on disk.
+     * <p>
+     * Note that apps may not have filesystem permissions to directly access
+     * this path. Instead of trying to open this path directly, apps should use
+     * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain access.
+     *
+     * @deprecated apps should transition to using
+     *             {@link ContentResolver#openFileDescriptor(Uri, String)}
+     *             instead.
      */
+    @Deprecated
     public final static String COLUMN_LOCAL_FILENAME = "local_filename";
 
     /**
@@ -908,16 +918,22 @@
         }
     }
 
-    private ContentResolver mResolver;
-    private String mPackageName;
+    private final ContentResolver mResolver;
+    private final String mPackageName;
+
     private Uri mBaseUri = Downloads.Impl.CONTENT_URI;
+    private boolean mAccessFilename;
 
     /**
      * @hide
      */
-    public DownloadManager(ContentResolver resolver, String packageName) {
-        mResolver = resolver;
-        mPackageName = packageName;
+    public DownloadManager(Context context) {
+        mResolver = context.getContentResolver();
+        mPackageName = context.getPackageName();
+
+        // Callers can access filename columns when targeting old platform
+        // versions; otherwise we throw telling them it's deprecated.
+        mAccessFilename = context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N;
     }
 
     /**
@@ -933,6 +949,11 @@
         }
     }
 
+    /** {@hide} */
+    public void setAccessFilename(boolean accessFilename) {
+        mAccessFilename = accessFilename;
+    }
+
     /**
      * Enqueue a new download.  The download will start automatically once the download manager is
      * ready to execute it and connectivity is available.
@@ -997,7 +1018,7 @@
         if (underlyingCursor == null) {
             return null;
         }
-        return new CursorTranslator(underlyingCursor, mBaseUri);
+        return new CursorTranslator(underlyingCursor, mBaseUri, mAccessFilename);
     }
 
     /**
@@ -1265,11 +1286,13 @@
      * underlying data.
      */
     private static class CursorTranslator extends CursorWrapper {
-        private Uri mBaseUri;
+        private final Uri mBaseUri;
+        private final boolean mAccessFilename;
 
-        public CursorTranslator(Cursor cursor, Uri baseUri) {
+        public CursorTranslator(Cursor cursor, Uri baseUri, boolean accessFilename) {
             super(cursor);
             mBaseUri = baseUri;
+            mAccessFilename = accessFilename;
         }
 
         @Override
@@ -1290,8 +1313,19 @@
 
         @Override
         public String getString(int columnIndex) {
-            return (getColumnName(columnIndex).equals(COLUMN_LOCAL_URI)) ? getLocalUri() :
-                    super.getString(columnIndex);
+            final String columnName = getColumnName(columnIndex);
+            switch (columnName) {
+                case COLUMN_LOCAL_URI:
+                    return getLocalUri();
+                case COLUMN_LOCAL_FILENAME:
+                    if (!mAccessFilename) {
+                        throw new IllegalArgumentException(
+                                "COLUMN_LOCAL_FILENAME is deprecated;"
+                                        + " use ContentResolver.openFileDescriptor() instead");
+                    }
+                default:
+                    return super.getString(columnIndex);
+            }
         }
 
         private String getLocalUri() {
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 20f3495..fe9cc80 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -30,7 +30,9 @@
 import android.view.ViewGroup;
 import android.view.ViewGroupOverlay;
 import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnPreDrawListener;
 import android.view.Window;
+import android.view.accessibility.AccessibilityEvent;
 
 import java.util.ArrayList;
 
@@ -56,6 +58,7 @@
     private boolean mAreViewsReady;
     private boolean mIsViewsTransitionStarted;
     private Transition mEnterViewsTransition;
+    private OnPreDrawListener mViewsReadyListener;
 
     public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver,
             ArrayList<String> sharedElementNames, boolean isReturning) {
@@ -137,15 +140,16 @@
                 (sharedElements.isEmpty() || !sharedElements.valueAt(0).isLayoutRequested()))) {
             viewsReady(sharedElements);
         } else {
-            decor.getViewTreeObserver()
-                    .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
-                        @Override
-                        public boolean onPreDraw() {
-                            decor.getViewTreeObserver().removeOnPreDrawListener(this);
-                            viewsReady(sharedElements);
-                            return true;
-                        }
-                    });
+            mViewsReadyListener = new ViewTreeObserver.OnPreDrawListener() {
+                @Override
+                public boolean onPreDraw() {
+                    mViewsReadyListener = null;
+                    decor.getViewTreeObserver().removeOnPreDrawListener(this);
+                    viewsReady(sharedElements);
+                    return true;
+                }
+            };
+            decor.getViewTreeObserver().addOnPreDrawListener(mViewsReadyListener);
         }
     }
 
@@ -240,6 +244,50 @@
         }
     }
 
+    /**
+     * 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
+     * caused by the top Activity finishing before the transitions started.
+     * In that case, we can finish any transition that was started, but we
+     * should cancel any pending transition and just bring those Views visible.
+     */
+    public void forceViewsToAppear() {
+        if (!mIsReturning) {
+            return;
+        }
+        if (!mIsReadyForTransition) {
+            mIsReadyForTransition = true;
+            final ViewGroup decor = getDecor();
+            if (decor != null && mViewsReadyListener != null) {
+                decor.getViewTreeObserver().removeOnPreDrawListener(mViewsReadyListener);
+                mViewsReadyListener = null;
+            }
+            showViews(mTransitioningViews, true);
+            mSharedElements.clear();
+            mAllSharedElementNames.clear();
+            mTransitioningViews.clear();
+            mIsReadyForTransition = true;
+            viewsTransitionComplete();
+            sharedElementTransitionComplete();
+        } else {
+            if (!mSharedElementTransitionStarted) {
+                moveSharedElementsFromOverlay();
+                mSharedElementTransitionStarted = true;
+                showViews(mSharedElements, true);
+                mSharedElements.clear();
+                sharedElementTransitionComplete();
+            }
+            if (!mIsViewsTransitionStarted) {
+                mIsViewsTransitionStarted = true;
+                showViews(mTransitioningViews, true);
+                mTransitioningViews.clear();
+                viewsTransitionComplete();
+            }
+            cancelPendingTransitions();
+        }
+        mAreViewsReady = true;
+    }
+
     private void cancel() {
         if (!mIsCanceled) {
             mIsCanceled = true;
@@ -500,6 +548,10 @@
     @Override
     protected void onTransitionsComplete() {
         moveSharedElementsFromOverlay();
+        final ViewGroup decorView = getDecor();
+        if (decorView != null) {
+            decorView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+        }
     }
 
     private void sharedElementTransitionStarted() {
@@ -654,5 +706,4 @@
             }
         });
     }
-
 }
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index a73ad09..20eaf0b 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -26,6 +26,7 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -409,9 +410,6 @@
     // If set this fragment is being removed from its activity.
     boolean mRemoving;
 
-    // True if the fragment is in the resumed state.
-    boolean mResumed;
-
     // Set to true if this fragment was instantiated from a layout file.
     boolean mFromLayout;
 
@@ -928,7 +926,7 @@
      * for the duration of {@link #onResume()} and {@link #onPause()} as well.
      */
     final public boolean isResumed() {
-        return mResumed;
+        return mState >= RESUMED;
     }
 
     /**
@@ -1419,11 +1417,30 @@
      * at this point.  If you want to do work once the activity itself is
      * created, see {@link #onActivityCreated(Bundle)}.
      *
+     * <p>If your app's <code>targetSdkVersion</code> is 23 or lower, child fragments
+     * being restored from the savedInstanceState are restored after <code>onCreate</code>
+     * returns. When targeting N or above and running on an N or newer platform version
+     * they are restored by <code>Fragment.onCreate</code>.</p>
+     *
      * @param savedInstanceState If the fragment is being re-created from
      * a previous saved state, this is the state.
      */
     public void onCreate(@Nullable Bundle savedInstanceState) {
         mCalled = true;
+        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();
+                }
+            }
+        }
     }
 
     /**
@@ -1630,7 +1647,6 @@
         mWho = null;
         mAdded = false;
         mRemoving = false;
-        mResumed = false;
         mFromLayout = false;
         mInLayout = false;
         mRestored = false;
@@ -2113,7 +2129,6 @@
         writer.print(" mBackStackNesting="); writer.println(mBackStackNesting);
         writer.print(prefix); writer.print("mAdded="); writer.print(mAdded);
         writer.print(" mRemoving="); writer.print(mRemoving);
-        writer.print(" mResumed="); writer.print(mResumed);
         writer.print(" mFromLayout="); writer.print(mFromLayout);
         writer.print(" mInLayout="); writer.println(mInLayout);
         writer.print(prefix); writer.print("mHidden="); writer.print(mHidden);
@@ -2208,20 +2223,25 @@
         if (mChildFragmentManager != null) {
             mChildFragmentManager.noteStateNotSaved();
         }
+        mState = CREATED;
         mCalled = false;
         onCreate(savedInstanceState);
         if (!mCalled) {
             throw new SuperNotCalledException("Fragment " + this
                     + " did not call through to super.onCreate()");
         }
-        if (savedInstanceState != null) {
-            Parcelable p = savedInstanceState.getParcelable(Activity.FRAGMENTS_TAG);
-            if (p != null) {
-                if (mChildFragmentManager == null) {
-                    instantiateChildFragmentManager();
+        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();
                 }
-                mChildFragmentManager.restoreAllState(p, null);
-                mChildFragmentManager.dispatchCreate();
             }
         }
     }
@@ -2238,6 +2258,7 @@
         if (mChildFragmentManager != null) {
             mChildFragmentManager.noteStateNotSaved();
         }
+        mState = ACTIVITY_CREATED;
         mCalled = false;
         onActivityCreated(savedInstanceState);
         if (!mCalled) {
@@ -2254,6 +2275,7 @@
             mChildFragmentManager.noteStateNotSaved();
             mChildFragmentManager.execPendingActions();
         }
+        mState = STARTED;
         mCalled = false;
         onStart();
         if (!mCalled) {
@@ -2273,6 +2295,7 @@
             mChildFragmentManager.noteStateNotSaved();
             mChildFragmentManager.execPendingActions();
         }
+        mState = RESUMED;
         mCalled = false;
         onResume();
         if (!mCalled) {
@@ -2389,6 +2412,7 @@
         if (mChildFragmentManager != null) {
             mChildFragmentManager.dispatchPause();
         }
+        mState = STARTED;
         mCalled = false;
         onPause();
         if (!mCalled) {
@@ -2401,6 +2425,7 @@
         if (mChildFragmentManager != null) {
             mChildFragmentManager.dispatchStop();
         }
+        mState = STOPPED;
         mCalled = false;
         onStop();
         if (!mCalled) {
@@ -2428,6 +2453,7 @@
         if (mChildFragmentManager != null) {
             mChildFragmentManager.dispatchDestroyView();
         }
+        mState = CREATED;
         mCalled = false;
         onDestroyView();
         if (!mCalled) {
@@ -2443,6 +2469,7 @@
         if (mChildFragmentManager != null) {
             mChildFragmentManager.dispatchDestroy();
         }
+        mState = INITIALIZING;
         mCalled = false;
         onDestroy();
         if (!mCalled) {
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 696ccdb..84ae09d 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1004,7 +1004,6 @@
                 case Fragment.STARTED:
                     if (newState > Fragment.STARTED) {
                         if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
-                        f.mResumed = true;
                         f.performResume();
                         // Get rid of this in case we saved it and never needed it.
                         f.mSavedFragmentState = null;
@@ -1017,7 +1016,6 @@
                     if (newState < Fragment.RESUMED) {
                         if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
                         f.performPause();
-                        f.mResumed = false;
                     }
                 case Fragment.STARTED:
                     if (newState < Fragment.STARTED) {
@@ -1096,6 +1094,8 @@
                             if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
                             if (!f.mRetaining) {
                                 f.performDestroy();
+                            } else {
+                                f.mState = Fragment.INITIALIZING;
                             }
 
                             f.mCalled = false;
@@ -1119,7 +1119,11 @@
             }
         }
         
-        f.mState = newState;
+        if (f.mState != newState) {
+            Log.w(TAG, "moveToState: Fragment state for " + f + " not updated inline; "
+                    + "expected state " + newState + " found " + f.mState);
+            f.mState = newState;
+        }
     }
     
     void moveToState(Fragment f) {
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 64c69af..5b3ffe0 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -92,7 +92,7 @@
             int userId) throws RemoteException;
     public boolean startNextMatchingActivity(IBinder callingActivity,
             Intent intent, Bundle options) throws RemoteException;
-    public int startActivityFromRecents(int taskId, int launchStackId, Bundle options)
+    public int startActivityFromRecents(int taskId, Bundle options)
             throws RemoteException;
     public boolean finishActivity(IBinder token, int code, Intent data, int finishTask)
             throws RemoteException;
@@ -122,6 +122,7 @@
             PersistableBundle persistentState, CharSequence description) throws RemoteException;
     public void activitySlept(IBinder token) throws RemoteException;
     public void activityDestroyed(IBinder token) throws RemoteException;
+    public void activityRelaunched(IBinder token) throws RemoteException;
     public void reportSizeConfigurations(IBinder token, int[] horizontalSizeConfiguration,
             int[] verticalSizeConfigurations, int[] smallestWidthConfigurations)
             throws RemoteException;
@@ -145,7 +146,31 @@
     public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
             Rect initialBounds) throws RemoteException;
     public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) throws RemoteException;
-    public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode) throws RemoteException;
+    public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode,
+            boolean preserveWindows, boolean animate) throws RemoteException;
+
+    /**
+     * Resizes the docked stack, and all other stacks as the result of the dock stack bounds change.
+     *
+     * @param dockedBounds The bounds for the docked stack.
+     * @param tempDockedTaskBounds The temporary bounds for the tasks in the docked 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.
+     * @param tempDockedTaskInsetBounds The temporary bounds for the tasks to calculate the insets.
+     *                                  When resizing, we usually "freeze" the layout of a task. To
+     *                                  achieve that, we also need to "freeze" the insets, which
+     *                                  gets achieved by changing task bounds but not bounds used
+     *                                  to calculate the insets in this transient state
+     * @param tempOtherTaskBounds The temporary bounds for the tasks in all other stacks, or
+     *                            {@code null} if they should be the same as the stack bounds.
+     * @param tempOtherTaskInsetBounds Like {@code tempDockedTaskInsetBounds}, but for the other
+     *                                 stacks.
+     * @throws RemoteException
+     */
+    public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
+            Rect tempDockedTaskInsetBounds,
+            Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds) 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;
@@ -251,6 +276,15 @@
     public ParceledListSlice<UriPermission> getPersistedUriPermissions(
             String packageName, boolean incoming) throws RemoteException;
 
+    // Gets the URI permissions granted to an arbitrary package.
+    // NOTE: this is different from getPersistedUriPermissions(), which returns the URIs the package
+    // granted to another packages (instead of those granted to it).
+    public ParceledListSlice<UriPermission> getGrantedUriPermissions(String packageName, int userId)
+            throws RemoteException;
+
+    // Clears the URI permissions granted to an arbitrary package.
+    public void clearGrantedUriPermissions(String packageName, int userId) throws RemoteException;
+
     public void showWaitingForDebugger(IApplicationThread who, boolean waiting)
             throws RemoteException;
 
@@ -363,6 +397,7 @@
     public String getProviderMimeType(Uri uri, int userId) throws RemoteException;
 
     public IBinder newUriPermissionOwner(String name) throws RemoteException;
+    public IBinder getUriPermissionOwnerForActivity(IBinder activityToken) throws RemoteException;
     public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
             Uri uri, int mode, int sourceUserId, int targetUserId) throws RemoteException;
     public void revokeUriPermissionFromOwner(IBinder owner, Uri uri,
@@ -438,7 +473,7 @@
     public void registerUserSwitchObserver(IUserSwitchObserver observer) throws RemoteException;
     public void unregisterUserSwitchObserver(IUserSwitchObserver observer) throws RemoteException;
 
-    public void requestBugReport(boolean progress) throws RemoteException;
+    public void requestBugReport(int bugreportType) throws RemoteException;
 
     public long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason)
             throws RemoteException;
@@ -538,11 +573,11 @@
     public boolean stopBinderTrackingAndDump(ParcelFileDescriptor fd) throws RemoteException;
 
     public int getActivityStackId(IBinder token) throws RemoteException;
-    public void moveActivityToStack(IBinder token, int stackId) throws RemoteException;
+    public void exitFreeformMode(IBinder token) throws RemoteException;
 
     public void suppressResizeConfigChanges(boolean suppress) throws RemoteException;
 
-    public void moveTasksToFullscreenStack(int fromStackId) throws RemoteException;
+    public void moveTasksToFullscreenStack(int fromStackId, boolean onTop) throws RemoteException;
 
     public int getAppStartMode(int uid, String packageName) throws RemoteException;
 
@@ -550,6 +585,18 @@
 
     public boolean inPictureInPictureMode(IBinder token) throws RemoteException;
 
+    public void enterPictureInPictureMode(IBinder token) throws RemoteException;
+
+    public void setVrMode(IBinder token, boolean enabled) throws RemoteException;
+
+    public boolean isAppForeground(int uid) throws RemoteException;
+
+    public void startLocalVoiceInteraction(IBinder token, Bundle options) throws RemoteException;
+
+    public void stopLocalVoiceInteraction(IBinder token) throws RemoteException;
+
+    public boolean supportsLocalVoiceInteraction() throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -903,7 +950,7 @@
     int STOP_BINDER_TRACKING_AND_DUMP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 341;
     int POSITION_TASK_IN_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 342;
     int GET_ACTIVITY_STACK_ID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 343;
-    int MOVE_ACTIVITY_TO_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 344;
+    int EXIT_FREEFORM_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 344;
     int REPORT_SIZE_CONFIGURATIONS = IBinder.FIRST_CALL_TRANSACTION + 345;
     int MOVE_TASK_TO_DOCKED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 346;
     int SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 347;
@@ -914,4 +961,15 @@
     int IN_MULTI_WINDOW_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 352;
     int IN_PICTURE_IN_PICTURE_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 353;
     int KILL_PACKAGE_DEPENDENTS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 354;
+    int ENTER_PICTURE_IN_PICTURE_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 355;
+    int ACTIVITY_RELAUNCHED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 356;
+    int GET_URI_PERMISSION_OWNER_FOR_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 357;
+    int RESIZE_DOCKED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 358;
+    int SET_VR_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 359;
+    int GET_GRANTED_URI_PERMISSIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 360;
+    int CLEAR_GRANTED_URI_PERMISSIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 361;
+    int IS_APP_FOREGROUND_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 362;
+    int START_LOCAL_VOICE_INTERACTION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 363;
+    int STOP_LOCAL_VOICE_INTERACTION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 364;
+    int SUPPORTS_LOCAL_VOICE_INTERACTION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 365;
 }
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index dc67026..6d64bd0 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -154,6 +154,7 @@
     void stopBinderTrackingAndDump(FileDescriptor fd) throws RemoteException;
     void scheduleMultiWindowModeChanged(IBinder token, boolean multiWindowMode) throws RemoteException;
     void schedulePictureInPictureModeChanged(IBinder token, boolean multiWindowMode) throws RemoteException;
+    void scheduleLocalVoiceInteractionStarted(IBinder token, IVoiceInteractor voiceInteractor) throws RemoteException;
 
     String descriptor = "android.app.IApplicationThread";
 
@@ -216,4 +217,5 @@
     int STOP_BINDER_TRACKING_AND_DUMP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+57;
     int SCHEDULE_MULTI_WINDOW_MODE_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+58;
     int SCHEDULE_PICTURE_IN_PICTURE_MODE_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+59;
+    int SCHEDULE_LOCAL_VOICE_INTERACTION_STARTED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+60;
 }
diff --git a/core/java/android/app/IBackupAgent.aidl b/core/java/android/app/IBackupAgent.aidl
index fe8e228..eda9603 100644
--- a/core/java/android/app/IBackupAgent.aidl
+++ b/core/java/android/app/IBackupAgent.aidl
@@ -105,6 +105,27 @@
     void doMeasureFullBackup(int token, IBackupManager callbackBinder);
 
     /**
+     * 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.
+     *
+     * @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.
+     */
+    void doQuotaExceeded(long backupDataBytes, long quotaBytes);
+
+    /**
      * Restore a single "file" to the application.  The file was typically obtained from
      * a full-backup dataset.  The agent reads 'size' bytes of file content
      * from the provided file descriptor.
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 136b810..3288cd9 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -48,12 +48,13 @@
     boolean areNotificationsEnabledForPackage(String pkg, int uid);
 
     ParceledListSlice getTopics(String pkg, int uid);
-    void setTopicVisibilityOverride(String pkg, int uid, in Notification.Topic topic, int visibility);
-    int getTopicVisibilityOverride(String pkg, int uid, in Notification.Topic topic);
-    void setTopicPriority(String pkg, int uid, in Notification.Topic topic, int priority);
-    int getTopicPriority(String pkg, int uid, in Notification.Topic topic);
-    void setTopicImportance(String pkg, int uid, in Notification.Topic topic, int importance);
-    int getTopicImportance(String pkg, int uid, in Notification.Topic topic);
+    void setVisibilityOverride(String pkg, int uid, in Notification.Topic topic, int visibility);
+    int getVisibilityOverride(String pkg, int uid, in Notification.Topic topic);
+    void setPriority(String pkg, int uid, in Notification.Topic topic, int priority);
+    int getPriority(String pkg, int uid, in Notification.Topic topic);
+    void setImportance(String pkg, int uid, in Notification.Topic topic, int importance);
+    int getImportance(String pkg, int uid, in Notification.Topic topic);
+    boolean doesAppUseTopics(String pkg, int uid);
 
     // TODO: Remove this when callers have been migrated to the equivalent
     // INotificationListener method.
@@ -66,6 +67,9 @@
     void cancelNotificationFromListener(in INotificationListener token, String pkg, String tag, int id);
     void cancelNotificationsFromListener(in INotificationListener token, in String[] keys);
 
+    void requestBindListener(in ComponentName component);
+    void requestUnbindListener(in INotificationListener token);
+
     void setNotificationsShownFromListener(in INotificationListener token, in String[] keys);
 
     ParceledListSlice getActiveNotificationsFromListener(in INotificationListener token, in String[] keys, int trim);
@@ -76,6 +80,8 @@
     void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim);
     void setInterruptionFilter(String pkg, int interruptionFilter);
 
+    void setImportanceFromAssistant(in INotificationListener token, String key, int importance, CharSequence explanation);
+
     ComponentName getEffectsSuppressor();
     boolean matchesCallFilter(in Bundle extras);
     boolean isSystemConditionProviderEnabled(String path);
@@ -96,6 +102,7 @@
     boolean updateAutomaticZenRule(in AutomaticZenRule automaticZenRule);
     boolean removeAutomaticZenRule(String id);
     boolean removeAutomaticZenRules(String packageName);
+    int getRuleInstanceCount(in ComponentName owner);
 
     byte[] getBackupPayload(int user);
     void applyRestore(in byte[] payload, int user);
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 4b0935c..fa11234 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -18,5 +18,16 @@
 
 /** @hide */
 oneway interface ITaskStackListener {
+    /** Called whenever there are changes to the state of tasks in a stack. */
     void onTaskStackChanged();
+
+    /** Called whenever an Activity is moved to the pinned stack from another stack. */
+    void onActivityPinned();
+
+    /**
+     * Called whenever IActivityManager.startActivity is called on an activity that is already
+     * running in the pinned stack and the activity is not actually started, but the task is either
+     * brought to the front or a new Intent is delivered to it.
+     */
+    void onPinnedActivityRestartAttempt();
 }
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index ccba250..fa0fbd1 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -28,37 +28,53 @@
 
     /**
      * Set the wallpaper.
+     *
+     * If 'extras' is non-null, on successful return it will contain:
+     *   EXTRA_SET_WALLPAPER_ID : integer ID that the new wallpaper will have
+     *
+     * 'which' is some combination of:
+     *   FLAG_SET_SYSTEM
+     *   FLAG_SET_LOCK
+     *
+     * A 'null' cropHint rectangle is explicitly permitted as a sentinel for "whatever
+     * the source image's bounding rect is."
+     *
+     * The completion callback's "onWallpaperChanged()" method is invoked when the
+     * new wallpaper content is ready to display.
      */
-    ParcelFileDescriptor setWallpaper(String name, in String callingPackage);
-    
+    ParcelFileDescriptor setWallpaper(String name, in String callingPackage,
+            in Rect cropHint, out Bundle extras, int which, IWallpaperManagerCallback completion);
+
     /**
-     * Set the live wallpaper.
+     * Set the live wallpaper. This only affects the system wallpaper.
      */
     void setWallpaperComponentChecked(in ComponentName name, in String callingPackage);
 
     /**
-     * Set the live wallpaper.
+     * Set the live wallpaper. This only affects the system wallpaper.
      */
     void setWallpaperComponent(in ComponentName name);
 
     /**
-     * Get the wallpaper.
+     * Get the system wallpaper.
      */
     ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
             out Bundle outParams);
-    
+
     /**
-     * Get information about a live wallpaper.
+     * 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.
      */
     WallpaperInfo getWallpaperInfo();
-    
+
     /**
-     * Clear the wallpaper.
+     * Clear the system wallpaper.
      */
     void clearWallpaper(in String callingPackage);
 
     /**
-     * Return whether there is a wallpaper set with the given name.
+     * Return whether the current system wallpaper has the given name.
      */
     boolean hasNamedWallpaper(String name);
 
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 7184337..24a3470 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -545,7 +545,7 @@
          * returning the resulting activity or till the timeOut period expires.
          * If the timeOut expires before the activity is started, return null. 
          * 
-         * @param timeOut Time to wait before the activity is created.
+         * @param timeOut Time to wait in milliseconds before the activity is created.
          * 
          * @return Activity
          */
diff --git a/core/java/android/app/IntentService.java b/core/java/android/app/IntentService.java
index 3cda973..f33af39 100644
--- a/core/java/android/app/IntentService.java
+++ b/core/java/android/app/IntentService.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.annotation.WorkerThread;
+import android.annotation.Nullable;
 import android.content.Intent;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -113,7 +114,7 @@
     }
 
     @Override
-    public void onStart(Intent intent, int startId) {
+    public void onStart(@Nullable Intent intent, int startId) {
         Message msg = mServiceHandler.obtainMessage();
         msg.arg1 = startId;
         msg.obj = intent;
@@ -127,7 +128,7 @@
      * @see android.app.Service#onStartCommand
      */
     @Override
-    public int onStartCommand(Intent intent, int flags, int startId) {
+    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
         onStart(intent, startId);
         return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
     }
@@ -139,10 +140,11 @@
 
     /**
      * Unless you provide binding for your service, you don't need to implement this
-     * method, because the default implementation returns null. 
+     * method, because the default implementation returns null.
      * @see android.app.Service#onBind
      */
     @Override
+    @Nullable
     public IBinder onBind(Intent intent) {
         return null;
     }
@@ -158,7 +160,11 @@
      *
      * @param intent The value passed to {@link
      *               android.content.Context#startService(Intent)}.
+     *               This may be null if the service is being restarted after
+     *               its process has gone away; see
+     *               {@link android.app.Service#onStartCommand}
+     *               for details.
      */
     @WorkerThread
-    protected abstract void onHandleIntent(Intent intent);
+    protected abstract void onHandleIntent(@Nullable Intent intent);
 }
diff --git a/core/java/android/app/JobSchedulerImpl.java b/core/java/android/app/JobSchedulerImpl.java
index 09038d5..dacf4ea 100644
--- a/core/java/android/app/JobSchedulerImpl.java
+++ b/core/java/android/app/JobSchedulerImpl.java
@@ -46,6 +46,15 @@
     }
 
     @Override
+    public int scheduleAsPackage(JobInfo job, String packageName, int userId) {
+        try {
+            return mBinder.scheduleAsPackage(job, packageName, userId);
+        } catch (RemoteException e) {
+            return JobScheduler.RESULT_FAILURE;
+        }
+    }
+
+    @Override
     public void cancel(int jobId) {
         try {
             mBinder.cancel(jobId);
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 7313fd1..1e22bef 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -366,12 +366,21 @@
                     }
                 }
 
+                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");
                 }
 
                 final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
@@ -389,10 +398,8 @@
                 // as this is early and necessary.
                 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
 
-                String libraryPermittedPath = mAppDir + File.pathSeparator + mDataDir;
-
-                mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, librarySearchPath,
-                        libraryPermittedPath, mBaseClassLoader);
+                mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, isBundledApp,
+                        librarySearchPath, libraryPermittedPath, mBaseClassLoader);
 
                 StrictMode.setThreadPolicy(oldPolicy);
             } else {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 620ab50..0f3aad9 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -145,6 +145,11 @@
     private static final int MAX_CHARSEQUENCE_LENGTH = 5 * 1024;
 
     /**
+     * Maximum entries of reply text that are accepted by Builder and friends.
+     */
+    private static final int MAX_REPLY_HISTORY = 5;
+
+    /**
      * A timestamp related to this notification, in milliseconds since the epoch.
      *
      * Default value: {@link System#currentTimeMillis() Now}.
@@ -745,6 +750,12 @@
     public static final String EXTRA_SUB_TEXT = "android.subText";
 
     /**
+     * {@link #extras} key: this is the remote input history, as supplied to
+     * {@link Builder#setRemoteInputHistory(CharSequence[])}.
+     */
+    public static final String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
+
+    /**
      * {@link #extras} key: this is a small piece of additional text as supplied to
      * {@link Builder#setContentInfo(CharSequence)}.
      */
@@ -2324,6 +2335,34 @@
         }
 
         /**
+         * Set the remote input history.
+         *
+         * This should be set to the most recent inputs that have been sent
+         * through a {@link RemoteInput} of this Notification and cleared once the it is no
+         * longer relevant (e.g. for chat notifications once the other party has responded).
+         *
+         * The most recent input must be stored at the 0 index, the second most recent at the
+         * 1 index, etc. Note that the system will limit both how far back the inputs will be shown
+         * and how much of each individual input is shown.
+         *
+         * <p>Note: The reply text will only be shown on notifications that have least one action
+         * with a {@code RemoteInput}.</p>
+         */
+        public Builder setRemoteInputHistory(CharSequence[] text) {
+            if (text == null) {
+                mN.extras.putCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY, null);
+            } else {
+                final int N = Math.min(MAX_REPLY_HISTORY, text.length);
+                CharSequence[] safe = new CharSequence[N];
+                for (int i = 0; i < N; i++) {
+                    safe[i] = safeCharSequence(text[i]);
+                }
+                mN.extras.putCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY, safe);
+            }
+            return this;
+        }
+
+        /**
          * Set the large number at the right-hand side of the notification.  This is
          * equivalent to setContentInfo, although it might show the number in a different
          * font size for readability.
@@ -2959,7 +2998,7 @@
         private Drawable getProfileBadgeDrawable() {
             // Note: This assumes that the current user can read the profile badge of the
             // originating user.
-            return mContext.getPackageManager().getUserBadgeForDensity(
+            return mContext.getPackageManager().getUserBadgeForDensityNoBackground(
                     new UserHandle(mContext.getUserId()), 0);
         }
 
@@ -2977,34 +3016,25 @@
             return bitmap;
         }
 
-        private boolean addProfileBadge(RemoteViews contentView, int resId) {
+        private void bindProfileBadge(RemoteViews contentView) {
             Bitmap profileBadge = getProfileBadge();
 
-            contentView.setViewVisibility(R.id.profile_badge_large_template, View.GONE);
-            contentView.setViewVisibility(R.id.profile_badge_line3, View.GONE);
-
             if (profileBadge != null) {
-                contentView.setImageViewBitmap(resId, profileBadge);
-                contentView.setViewVisibility(resId, View.VISIBLE);
-
-                // Make sure Line 3 is visible. As badge will be here if there
-                // is no text to display.
-                if (resId == R.id.profile_badge_line3) {
-                    contentView.setViewVisibility(R.id.line3, View.VISIBLE);
-                }
-                return true;
+                contentView.setImageViewBitmap(R.id.profile_badge, profileBadge);
+                contentView.setViewVisibility(R.id.profile_badge, View.VISIBLE);
             }
-            return false;
         }
 
         private void resetStandardTemplate(RemoteViews contentView) {
             resetNotificationHeader(contentView);
             resetContentMargins(contentView);
             contentView.setViewVisibility(R.id.right_icon, View.GONE);
+            contentView.setViewVisibility(R.id.title, View.GONE);
             contentView.setTextViewText(R.id.title, null);
+            contentView.setViewVisibility(R.id.text, View.GONE);
             contentView.setTextViewText(R.id.text, null);
-            contentView.setViewVisibility(R.id.line3, View.GONE);
             contentView.setViewVisibility(R.id.text_line_1, View.GONE);
+            contentView.setTextViewText(R.id.text_line_1, null);
             contentView.setViewVisibility(R.id.progress, View.GONE);
         }
 
@@ -3022,11 +3052,13 @@
             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);
+            contentView.setImageViewIcon(R.id.profile_badge, null);
+            contentView.setViewVisibility(R.id.profile_badge, View.GONE);
         }
 
         private void resetContentMargins(RemoteViews contentView) {
             contentView.setViewLayoutMarginEnd(R.id.line1, 0);
-            contentView.setViewLayoutMarginEnd(R.id.line3, 0);
+            contentView.setViewLayoutMarginEnd(R.id.text, 0);
         }
 
         private RemoteViews applyStandardTemplate(int resId) {
@@ -3041,34 +3073,44 @@
 
             resetStandardTemplate(contentView);
 
-            boolean showLine3 = false;
             final Bundle ex = mN.extras;
 
             bindNotificationHeader(contentView);
             bindLargeIcon(contentView);
             if (ex.getCharSequence(EXTRA_TITLE) != null) {
+                contentView.setViewVisibility(R.id.title, View.VISIBLE);
                 contentView.setTextViewText(R.id.title,
                         processLegacyText(ex.getCharSequence(EXTRA_TITLE)));
             }
             boolean showProgress = handleProgressBar(hasProgress, contentView, ex);
             if (ex.getCharSequence(EXTRA_TEXT) != null) {
-                contentView.setTextViewText(showProgress ? R.id.text_line_1 : R.id.text,
-                        processLegacyText(ex.getCharSequence(EXTRA_TEXT)));
-                if (showProgress) {
-                    contentView.setViewVisibility(R.id.text_line_1, View.VISIBLE);
-                }
-                showLine3 = !showProgress;
+                int textId = showProgress ? com.android.internal.R.id.text_line_1
+                        : com.android.internal.R.id.text;
+                contentView.setTextViewText(textId, processLegacyText(
+                        ex.getCharSequence(EXTRA_TEXT)));
+                contentView.setViewVisibility(textId, View.VISIBLE);
             }
-            // We want to add badge to first line of text.
-            if (addProfileBadge(contentView, R.id.profile_badge_line3)) {
-                showLine3 = true;
-            }
-            // Note getStandardView may hide line 3 again.
-            contentView.setViewVisibility(R.id.line3, showLine3 ? View.VISIBLE : View.GONE);
+
+            setContentMinHeight(contentView, showProgress || mN.mLargeIcon != null);
 
             return contentView;
         }
 
+        /**
+         * @param remoteView the remote view to update the minheight in
+         * @param hasMinHeight does it have a mimHeight
+         * @hide
+         */
+        void setContentMinHeight(RemoteViews remoteView, boolean hasMinHeight) {
+            int minHeight = 0;
+            if (hasMinHeight) {
+                // we need to set the minHeight of the notification
+                minHeight = mContext.getResources().getDimensionPixelSize(
+                        com.android.internal.R.dimen.notification_min_content_height);
+            }
+            remoteView.setInt(R.id.notification_main_column, "setMinimumHeight", minHeight);
+        }
+
         private boolean handleProgressBar(boolean hasProgress, RemoteViews contentView, Bundle ex) {
             final int max = ex.getInt(EXTRA_PROGRESS_MAX, 0);
             final int progress = ex.getInt(EXTRA_PROGRESS, 0);
@@ -3100,7 +3142,7 @@
                 int endMargin = mContext.getResources().getDimensionPixelSize(
                         R.dimen.notification_content_picture_margin);
                 contentView.setViewLayoutMarginEnd(R.id.line1, endMargin);
-                contentView.setViewLayoutMarginEnd(R.id.line3, endMargin);
+                contentView.setViewLayoutMarginEnd(R.id.text, endMargin);
                 contentView.setViewLayoutMarginEnd(R.id.progress, endMargin);
             }
         }
@@ -3113,6 +3155,7 @@
             bindContentInfo(contentView);
             bindHeaderChronometerAndTime(contentView);
             bindExpandButton(contentView);
+            bindProfileBadge(contentView);
         }
 
         private void bindChildCountColor(RemoteViews contentView) {
@@ -3214,6 +3257,14 @@
         private void resetStandardTemplateWithActions(RemoteViews big) {
             big.setViewVisibility(R.id.actions, View.GONE);
             big.removeAllViews(R.id.actions);
+
+            big.setViewVisibility(R.id.notification_material_reply_container, View.GONE);
+            big.setTextViewText(R.id.notification_material_reply_text_1, null);
+
+            big.setViewVisibility(R.id.notification_material_reply_text_2, View.GONE);
+            big.setTextViewText(R.id.notification_material_reply_text_2, null);
+            big.setViewVisibility(R.id.notification_material_reply_text_3, View.GONE);
+            big.setTextViewText(R.id.notification_material_reply_text_3, null);
         }
 
         private RemoteViews applyStandardTemplateWithActions(int layoutId) {
@@ -3221,18 +3272,62 @@
 
             resetStandardTemplateWithActions(big);
 
+            boolean validRemoteInput = false;
+
             int N = mActions.size();
             if (N > 0) {
                 big.setViewVisibility(R.id.actions, View.VISIBLE);
                 if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS;
                 for (int i=0; i<N; i++) {
-                    final RemoteViews button = generateActionButton(mActions.get(i));
+                    Action action = mActions.get(i);
+                    validRemoteInput |= hasValidRemoteInput(action);
+
+                    final RemoteViews button = generateActionButton(action);
                     big.addView(R.id.actions, button);
                 }
             }
+
+            CharSequence[] replyText = mN.extras.getCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY);
+            if (validRemoteInput && replyText != null
+                    && replyText.length > 0 && !TextUtils.isEmpty(replyText[0])) {
+                big.setViewVisibility(R.id.notification_material_reply_container, View.VISIBLE);
+                big.setTextViewText(R.id.notification_material_reply_text_1, replyText[0]);
+
+                if (replyText.length > 1 && !TextUtils.isEmpty(replyText[1])) {
+                    big.setViewVisibility(R.id.notification_material_reply_text_2, View.VISIBLE);
+                    big.setTextViewText(R.id.notification_material_reply_text_2, replyText[1]);
+
+                    if (replyText.length > 2 && !TextUtils.isEmpty(replyText[2])) {
+                        big.setViewVisibility(
+                                R.id.notification_material_reply_text_3, View.VISIBLE);
+                        big.setTextViewText(R.id.notification_material_reply_text_3, replyText[2]);
+                    }
+                }
+            }
+
             return big;
         }
 
+        private boolean hasValidRemoteInput(Action action) {
+            if (TextUtils.isEmpty(action.title) || action.actionIntent == null) {
+                // Weird actions
+                return false;
+            }
+
+            RemoteInput[] remoteInputs = action.getRemoteInputs();
+            if (remoteInputs == null) {
+                return false;
+            }
+
+            for (RemoteInput r : remoteInputs) {
+                CharSequence[] choices = r.getChoices();
+                if (r.getAllowFreeFormInput() || (choices != null && choices.length != 0)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
         /**
          * Construct a RemoteViews for the final 1U notification layout. In order:
          *   1. Custom contentView from the caller
@@ -3312,6 +3407,37 @@
             return applyStandardTemplateWithActions(getBigBaseLayoutResource());
         }
 
+        /**
+         * Construct a RemoteViews for the display in public contexts like on the lockscreen.
+         *
+         * @hide
+         */
+        public RemoteViews makePublicContentView() {
+            if (mN.publicVersion != null) {
+                final Builder builder = recoverBuilder(mContext, mN.publicVersion);
+                return builder.makeContentView();
+            }
+            Bundle savedBundle = mN.extras;
+            Style style = mStyle;
+            mStyle = null;
+            Icon largeIcon = mN.mLargeIcon;
+            mN.mLargeIcon = null;
+            Bundle publicExtras = new Bundle();
+            publicExtras.putBoolean(EXTRA_SHOW_WHEN,
+                    savedBundle.getBoolean(EXTRA_SHOW_WHEN));
+            publicExtras.putBoolean(EXTRA_SHOW_CHRONOMETER,
+                    savedBundle.getBoolean(EXTRA_SHOW_CHRONOMETER));
+            publicExtras.putCharSequence(EXTRA_TITLE,
+                    mContext.getString(R.string.notification_hidden_text));
+            mN.extras = publicExtras;
+            final RemoteViews publicView = applyStandardTemplate(getBaseLayoutResource());
+            mN.extras = savedBundle;
+            mN.mLargeIcon = largeIcon;
+            mStyle = style;
+            return publicView;
+        }
+
+
 
         private RemoteViews generateActionButton(Action action) {
             final boolean tombstone = (action.actionIntent == null);
@@ -3589,10 +3715,6 @@
                 contentView.setViewVisibility(R.id.line1, View.VISIBLE);
             }
 
-            // Clear text in case we use the line to show the profile badge.
-            contentView.setTextViewText(com.android.internal.R.id.text, "");
-            contentView.setViewVisibility(com.android.internal.R.id.line3, View.GONE);
-
             return contentView;
         }
 
@@ -3799,22 +3921,15 @@
             RemoteViews contentView = getStandardView(mBuilder.getBigPictureLayoutResource());
             if (mSummaryTextSet) {
                 contentView.setTextViewText(R.id.text, mBuilder.processLegacyText(mSummaryText));
-                contentView.setViewVisibility(R.id.line3, View.VISIBLE);
+                contentView.setViewVisibility(R.id.text, View.VISIBLE);
             }
-            int imageMinHeight = mBuilder.mContext.getResources().getDimensionPixelSize(
-                    R.dimen.notification_big_picture_content_min_height_with_picture);
-            // We need to make space for the right image, so we're enforcing a minheight if there
-            // is a picture.
-            int minHeight = (mBuilder.mN.mLargeIcon == null) ? 0 : imageMinHeight;
-            contentView.setInt(R.id.notification_main_column, "setMinimumHeight", minHeight);
+            mBuilder.setContentMinHeight(contentView, mBuilder.mN.mLargeIcon != null);
 
             if (mBigLargeIconSet) {
                 mBuilder.mN.mLargeIcon = oldLargeIcon;
             }
 
             contentView.setImageViewBitmap(R.id.big_picture, mPicture);
-
-            mBuilder.addProfileBadge(contentView, R.id.profile_badge_line3);
             return contentView;
         }
 
@@ -3873,8 +3988,7 @@
     public static class BigTextStyle extends Style {
 
         private static final int MAX_LINES = 13;
-        private static final int LINES_CONSUMED_BY_ACTIONS = 3;
-        private static final int LINES_CONSUMED_BY_SUMMARY = 2;
+        private static final int LINES_CONSUMED_BY_ACTIONS = 4;
 
         private CharSequence mBigText;
 
@@ -3944,12 +4058,11 @@
 
             mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, oldBuilderContentText);
 
-            contentView.setTextViewText(R.id.big_text, mBuilder.processLegacyText(mBigText));
-            contentView.setViewVisibility(R.id.big_text, View.VISIBLE);
+            CharSequence bigTextText = mBuilder.processLegacyText(mBigText);
+            contentView.setTextViewText(R.id.big_text, bigTextText);
+            contentView.setViewVisibility(R.id.big_text,
+                    TextUtils.isEmpty(bigTextText) ? View.GONE : View.VISIBLE);
             contentView.setInt(R.id.big_text, "setMaxLines", calculateMaxLines());
-
-            mBuilder.addProfileBadge(contentView, R.id.profile_badge_large_template);
-
             contentView.setBoolean(R.id.big_text, "setHasImage", mBuilder.mN.mLargeIcon != null);
 
             return contentView;
@@ -3958,14 +4071,9 @@
         private int calculateMaxLines() {
             int lineCount = MAX_LINES;
             boolean hasActions = mBuilder.mActions.size() > 0;
-            boolean hasSummary = (mSummaryTextSet ? mSummaryText
-                    : mBuilder.getAllExtras().getCharSequence(EXTRA_SUB_TEXT)) != null;
             if (hasActions) {
                 lineCount -= LINES_CONSUMED_BY_ACTIONS;
             }
-            if (hasSummary) {
-                lineCount -= LINES_CONSUMED_BY_SUMMARY;
-            }
             return lineCount;
         }
     }
@@ -4052,7 +4160,7 @@
          * @hide
          */
         public RemoteViews makeBigContentView() {
-            // Remove the content text so line3 disappears unless you have a summary
+            // Remove the content text so it disappears unless you have a summary
             // Nasty
             CharSequence oldBuilderContentText = mBuilder.mN.extras.getCharSequence(EXTRA_TEXT);
             mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, null);
@@ -4091,7 +4199,6 @@
                 }
                 i++;
             }
-            mBuilder.addProfileBadge(contentView, R.id.profile_badge_large_template);
 
             handleInboxImageMargin(contentView, rowIds[0]);
 
@@ -4302,7 +4409,7 @@
         private void handleImage(RemoteViews contentView) {
             if (mBuilder.mN.mLargeIcon != null) {
                 contentView.setViewLayoutMarginEnd(R.id.line1, 0);
-                contentView.setViewLayoutMarginEnd(R.id.line3, 0);
+                contentView.setViewLayoutMarginEnd(R.id.text, 0);
             }
         }
 
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 85d9831..faf5b11 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -380,6 +380,18 @@
     }
 
     /**
+     * @hide
+     */
+    public int getRuleInstanceCount(ComponentName owner) {
+        INotificationManager service = getService();
+        try {
+            return service.getRuleInstanceCount(owner);
+        } catch (RemoteException e) {
+        }
+        return 0;
+    }
+
+    /**
      * Returns AutomaticZenRules owned by the caller.
      *
      * <p>
@@ -637,10 +649,12 @@
         public static final int SUPPRESSED_EFFECTS_UNSET = -1;
         public static final int SUPPRESSED_EFFECT_LIGHTS = 1 << 0;
         public static final int SUPPRESSED_EFFECT_PEEK = 1 << 1;
+        public static final int SUPPRESSED_EFFECT_SCREEN_ON = 1 << 2;
 
         private static final int[] ALL_SUPPRESSED_EFFECTS = {
                 SUPPRESSED_EFFECT_LIGHTS,
                 SUPPRESSED_EFFECT_PEEK,
+                SUPPRESSED_EFFECT_SCREEN_ON,
         };
 
         /**
@@ -750,6 +764,7 @@
             switch (effect) {
                 case SUPPRESSED_EFFECT_LIGHTS: return "SUPPRESSED_EFFECT_LIGHTS";
                 case SUPPRESSED_EFFECT_PEEK: return "SUPPRESSED_EFFECT_PEEK";
+                case SUPPRESSED_EFFECT_SCREEN_ON: return "SUPPRESSED_EFFECT_SCREEN_ON";
                 case SUPPRESSED_EFFECTS_UNSET: return "SUPPRESSED_EFFECTS_UNSET";
                 default: return "UNKNOWN_" + effect;
             }
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 3187984..94e584e 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -27,6 +27,7 @@
 import android.hardware.display.DisplayManagerGlobal;
 import android.util.ArrayMap;
 import android.util.DisplayMetrics;
+import android.util.LocaleList;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
@@ -34,7 +35,9 @@
 import android.view.DisplayAdjustments;
 
 import java.lang.ref.WeakReference;
-import java.util.Locale;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
 
 /** @hide */
 public class ResourcesManager {
@@ -42,11 +45,15 @@
     private static final boolean DEBUG = false;
 
     private static ResourcesManager sResourcesManager;
-    private final ArrayMap<ResourcesKey, WeakReference<Resources> > mActiveResources =
+    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>();
+    private boolean mHasNonSystemLocales = false;
+
     CompatibilityInfo mResCompatibilityInfo;
 
     Configuration mResConfiguration;
@@ -165,6 +172,8 @@
                 ? 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);
@@ -178,6 +187,8 @@
                         + " key=" + key + " overrideConfig=" + overrideConfiguration);
                 return r;
             }
+            findSystemLocales = (mSystemLocales.length == 0);
+            hasNonSystemLocales = mHasNonSystemLocales;
         }
 
         //if (r != null) {
@@ -243,6 +254,18 @@
         if (DEBUG) Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "
                 + r.getConfiguration() + " appScale=" + r.getCompatibilityInfo().applicationScale);
 
+        final String[] systemLocales = (
+                findSystemLocales ?
+                AssetManager.getSystem().getLocales() :
+                null);
+        final String[] nonSystemLocales = assets.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
+        // able to affect mHasNonSystemLocales.
+        final boolean isPseudoLocalesOnly = hasNonSystemLocales ||
+                LocaleList.isPseudoLocalesOnly(nonSystemLocales);
+
         synchronized (this) {
             WeakReference<Resources> wr = mActiveResources.get(key);
             Resources existing = wr != null ? wr.get() : null;
@@ -255,11 +278,30 @@
 
             // XXX need to remove entries when weak references go away
             mActiveResources.put(key, new WeakReference<>(r));
+            if (mSystemLocales.length == 0) {
+                mSystemLocales = systemLocales;
+            }
+            mNonSystemLocales.addAll(Arrays.asList(nonSystemLocales));
+            mHasNonSystemLocales = mHasNonSystemLocales || !isPseudoLocalesOnly;
             if (DEBUG) Slog.v(TAG, "mActiveResources.size()=" + mActiveResources.size());
             return r;
         }
     }
 
+    /* package */ void setDefaultLocalesLocked(LocaleList locales) {
+        final int bestLocale;
+        if (mHasNonSystemLocales) {
+            bestLocale = locales.getFirstMatchIndexWithEnglishSupported(mNonSystemLocales);
+        } else {
+            // We fallback to system locales if there was no locale specifically supported by the
+            // assets. This is to properly support apps that only rely on the shared system assets
+            // and don't need assets of their own.
+            bestLocale = locales.getFirstMatchIndexWithEnglishSupported(mSystemLocales);
+        }
+        // set it for Java, this also affects newly created Resources
+        LocaleList.setDefault(locales, bestLocale);
+    }
+
     final boolean applyConfigurationToResourcesLocked(Configuration config,
             CompatibilityInfo compat) {
         if (mResConfiguration == null) {
@@ -283,12 +325,28 @@
                     | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
         }
 
-        // set it for java, this also affects newly created Resources
-        if (config.locale != null) {
-            Locale.setDefault(config.locale);
+        Configuration localeAdjustedConfig = config;
+        final LocaleList configLocales = config.getLocales();
+        if (!configLocales.isEmpty()) {
+            setDefaultLocalesLocked(configLocales);
+            final LocaleList adjustedLocales = LocaleList.getAdjustedDefault();
+            if (adjustedLocales != configLocales) { // has the same result as .equals() in this case
+                // The first locale in the list was not chosen. So we create a modified
+                // configuration with the adjusted locales (which moves the chosen locale to the
+                // front).
+                localeAdjustedConfig = new Configuration();
+                localeAdjustedConfig.setTo(config);
+                localeAdjustedConfig.setLocales(adjustedLocales);
+                // Also adjust the locale list in mResConfiguration, so that the Resources created
+                // later would have the same locale list.
+                if (!mResConfiguration.getLocales().equals(adjustedLocales)) {
+                    mResConfiguration.setLocales(adjustedLocales);
+                    changes |= ActivityInfo.CONFIG_LOCALE;
+                }
+            }
         }
 
-        Resources.updateSystemConfiguration(config, defaultDisplayMetrics, compat);
+        Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics, compat);
 
         ApplicationPackageManager.configurationChanged();
         //Slog.i(TAG, "Configuration changed in " + currentPackageName());
@@ -300,7 +358,7 @@
             Resources r = mActiveResources.valueAt(i).get();
             if (r != null) {
                 if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
-                        + r + " config to: " + config);
+                        + r + " config to: " + localeAdjustedConfig);
                 int displayId = key.mDisplayId;
                 boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
                 DisplayMetrics dm = defaultDisplayMetrics;
@@ -309,7 +367,7 @@
                     if (tmpConfig == null) {
                         tmpConfig = new Configuration();
                     }
-                    tmpConfig.setTo(config);
+                    tmpConfig.setTo(localeAdjustedConfig);
                     if (!isDefaultDisplay) {
                         dm = getDisplayMetricsLocked(displayId);
                         applyNonDefaultDisplayMetricsToConfigurationLocked(dm, tmpConfig);
@@ -319,7 +377,7 @@
                     }
                     r.updateConfiguration(tmpConfig, dm, compat);
                 } else {
-                    r.updateConfiguration(config, dm, compat);
+                    r.updateConfiguration(localeAdjustedConfig, dm, compat);
                 }
                 //Slog.i(TAG, "Updated app resources " + v.getKey()
                 //        + " " + r + ": " + r.getConfiguration());
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 288a2cb..5eed781 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import com.android.internal.app.IAppOpsService;
+import com.android.internal.app.ISoundTriggerService;
 import com.android.internal.appwidget.IAppWidgetService;
 import com.android.internal.os.IDropBoxManagerService;
 
@@ -61,6 +62,7 @@
 import android.media.midi.MidiManager;
 import android.media.projection.MediaProjectionManager;
 import android.media.session.MediaSessionManager;
+import android.media.soundtrigger.SoundTriggerManager;
 import android.media.tv.ITvInputManager;
 import android.media.tv.TvInputManager;
 import android.net.ConnectivityManager;
@@ -78,13 +80,14 @@
 import android.net.wifi.RttManager;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiScanner;
+import android.net.wifi.nan.IWifiNanManager;
+import android.net.wifi.nan.WifiNanManager;
 import android.net.wifi.p2p.IWifiP2pManager;
 import android.net.wifi.p2p.WifiP2pManager;
-import android.net.wifi.passpoint.IWifiPasspointManager;
-import android.net.wifi.passpoint.WifiPasspointManager;
 import android.nfc.NfcManager;
 import android.os.BatteryManager;
 import android.os.DropBoxManager;
+import android.os.HardwarePropertiesManager;
 import android.os.IBinder;
 import android.os.IPowerManager;
 import android.os.IUserManager;
@@ -247,7 +250,7 @@
                 new CachedServiceFetcher<DownloadManager>() {
             @Override
             public DownloadManager createService(ContextImpl ctx) {
-                return new DownloadManager(ctx.getContentResolver(), ctx.getPackageName());
+                return new DownloadManager(ctx);
             }});
 
         registerService(Context.BATTERY_SERVICE, BatteryManager.class,
@@ -481,15 +484,6 @@
                 return new WifiManager(ctx.getOuterContext(), service);
             }});
 
-        registerService(Context.WIFI_PASSPOINT_SERVICE, WifiPasspointManager.class,
-                new CachedServiceFetcher<WifiPasspointManager>() {
-            @Override
-            public WifiPasspointManager createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(Context.WIFI_PASSPOINT_SERVICE);
-                IWifiPasspointManager service = IWifiPasspointManager.Stub.asInterface(b);
-                return new WifiPasspointManager(ctx.getOuterContext(), service);
-            }});
-
         registerService(Context.WIFI_P2P_SERVICE, WifiP2pManager.class,
                 new StaticServiceFetcher<WifiP2pManager>() {
             @Override
@@ -499,6 +493,18 @@
                 return new WifiP2pManager(service);
             }});
 
+        registerService(Context.WIFI_NAN_SERVICE, WifiNanManager.class,
+                new StaticServiceFetcher<WifiNanManager>() {
+            @Override
+            public WifiNanManager createService() {
+                IBinder b = ServiceManager.getService(Context.WIFI_NAN_SERVICE);
+                IWifiNanManager service = IWifiNanManager.Stub.asInterface(b);
+                if (service == null) {
+                    return null;
+                }
+                return new WifiNanManager(service);
+            }});
+
         registerService(Context.WIFI_SCANNING_SERVICE, WifiScanner.class,
                 new CachedServiceFetcher<WifiScanner>() {
             @Override
@@ -704,6 +710,22 @@
             public RadioManager createService(ContextImpl ctx) {
                 return new RadioManager(ctx);
             }});
+
+        registerService(Context.HARDWARE_PROPERTIES_SERVICE, HardwarePropertiesManager.class,
+                new CachedServiceFetcher<HardwarePropertiesManager>() {
+            @Override
+            public HardwarePropertiesManager createService(ContextImpl ctx) {
+                return new HardwarePropertiesManager();
+            }});
+
+        registerService(Context.SOUND_TRIGGER_SERVICE, SoundTriggerManager.class,
+                new CachedServiceFetcher<SoundTriggerManager>() {
+            @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));
+            }});
     }
 
     /**
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index f7848f9..dce2e51 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -22,6 +22,7 @@
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.accessibilityservice.IAccessibilityServiceConnection;
 import android.annotation.NonNull;
+import android.annotation.TestApi;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Point;
@@ -856,6 +857,7 @@
      *
      * @hide
      */
+    @TestApi
     public boolean grantRuntimePermission(String packageName, String permission,
             UserHandle userHandle) {
         synchronized (mLock) {
@@ -884,6 +886,7 @@
      *
      * @hide
      */
+    @TestApi
     public boolean revokeRuntimePermission(String packageName, String permission,
             UserHandle userHandle) {
         synchronized (mLock) {
@@ -1028,6 +1031,11 @@
                         float scale, float centerX, float centerY) {
                     /* do nothing */
                 }
+
+                @Override
+                public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
+                    /* do nothing */
+                }
             });
         }
     }
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 13e27e2..bd10267 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -28,6 +28,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.view.IWindowManager;
 import android.view.InputEvent;
 import android.view.SurfaceControl;
@@ -167,9 +168,10 @@
             throwIfShutdownLocked();
             throwIfNotConnectedLocked();
         }
+        int callingUserId = UserHandle.getCallingUserId();
         final long identity = Binder.clearCallingIdentity();
         try {
-            IBinder token = mAccessibilityManager.getWindowToken(windowId);
+            IBinder token = mAccessibilityManager.getWindowToken(windowId, callingUserId);
             if (token == null) {
                 return false;
             }
@@ -186,9 +188,10 @@
             throwIfShutdownLocked();
             throwIfNotConnectedLocked();
         }
+        int callingUserId = UserHandle.getCallingUserId();
         final long identity = Binder.clearCallingIdentity();
         try {
-            IBinder token = mAccessibilityManager.getWindowToken(windowId);
+            IBinder token = mAccessibilityManager.getWindowToken(windowId, callingUserId);
             if (token == null) {
                 return null;
             }
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 4416415..56b4249 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -16,12 +16,16 @@
 
 package android.app;
 
+import android.annotation.IntDef;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * This class provides access to the system uimode services.  These services
  * allow applications to control UI modes of the device.
@@ -92,18 +96,26 @@
      * when the user exits desk mode.
      */
     public static String ACTION_EXIT_DESK_MODE = "android.app.action.EXIT_DESK_MODE";
-    
-    /** Constant for {@link #setNightMode(int)} and {@link #getNightMode()}:
+
+    /** @hide */
+    @IntDef({MODE_NIGHT_AUTO, MODE_NIGHT_NO, MODE_NIGHT_YES})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface NightMode {}
+
+    /**
+     * Constant for {@link #setNightMode(int)} and {@link #getNightMode()}:
      * automatically switch night mode on and off based on the time.
      */
     public static final int MODE_NIGHT_AUTO = Configuration.UI_MODE_NIGHT_UNDEFINED >> 4;
     
-    /** Constant for {@link #setNightMode(int)} and {@link #getNightMode()}:
+    /**
+     * Constant for {@link #setNightMode(int)} and {@link #getNightMode()}:
      * never run in night mode.
      */
     public static final int MODE_NIGHT_NO = Configuration.UI_MODE_NIGHT_NO >> 4;
     
-    /** Constant for {@link #setNightMode(int)} and {@link #getNightMode()}:
+    /**
+     * Constant for {@link #setNightMode(int)} and {@link #getNightMode()}:
      * always run in night mode.
      */
     public static final int MODE_NIGHT_YES = Configuration.UI_MODE_NIGHT_YES >> 4;
@@ -195,20 +207,28 @@
     }
 
     /**
-     * Sets the night mode.  Changes to the night mode are only effective when
-     * the car or desk mode is enabled on a device.
-     *
-     * <p>The mode can be one of:
+     * Sets the night mode.
+     * <p>
+     * The mode can be one of:
      * <ul>
-     *   <li><em>{@link #MODE_NIGHT_NO}<em> - sets the device into notnight
-     *       mode.</li>
-     *   <li><em>{@link #MODE_NIGHT_YES}</em> - sets the device into night mode.
-     *   </li>
-     *   <li><em>{@link #MODE_NIGHT_AUTO}</em> - automatic night/notnight switching
-     *       depending on the location and certain other sensors.</li>
+     *   <li><em>{@link #MODE_NIGHT_NO}<em> sets the device into
+     *       {@code notnight} mode</li>
+     *   <li><em>{@link #MODE_NIGHT_YES}</em> sets the device into
+     *       {@code night} mode</li>
+     *   <li><em>{@link #MODE_NIGHT_AUTO}</em> automatically switches between
+     *       {@code night} and {@code notnight} based on the device's current
+     *       location and certain other sensors</li>
      * </ul>
+     * <p>
+     * <strong>Note:</strong> On API 22 and below, changes to the night mode
+     * are only effective when the {@link Configuration#UI_MODE_TYPE_CAR car}
+     * or {@link Configuration#UI_MODE_TYPE_DESK desk} mode is enabled on a
+     * device. Starting in API 23, changes to night mode are always effective.
+     *
+     * @param mode the night mode to set
+     * @see #getNightMode()
      */
-    public void setNightMode(int mode) {
+    public void setNightMode(@NightMode int mode) {
         if (mService != null) {
             try {
                 mService.setNightMode(mode);
@@ -219,11 +239,20 @@
     }
 
     /**
-     * @return the currently configured night mode. May be one of
-     *         {@link #MODE_NIGHT_NO}, {@link #MODE_NIGHT_YES},
-     *         {@link #MODE_NIGHT_AUTO}, or -1 on error.
+     * Returns the currently configured night mode.
+     * <p>
+     * May be one of:
+     * <ul>
+     *   <li>{@link #MODE_NIGHT_NO}</li>
+     *   <li>{@link #MODE_NIGHT_YES}</li>
+     *   <li>{@link #MODE_NIGHT_AUTO}</li>
+     *   <li>{@code -1} on error</li>
+     * </ul>
+     *
+     * @return the current night mode, or {@code -1} on error
+     * @see #setNightMode(int)
      */
-    public int getNightMode() {
+    public @NightMode int getNightMode() {
         if (mService != null) {
             try {
                 return mService.getNightMode();
@@ -250,9 +279,13 @@
     }
 
     /**
-     * @return If Night mode is locked or not. When Night mode is locked, changing Night mode
-     *         is only allowed to privileged system components and normal application's call
-     *         to change Night mode using {@link #setNightMode(int)} will silently fail.
+     * Returns whether night mode is locked or not.
+     * <p>
+     * When night mode is locked, only privileged system components may change
+     * night mode and calls from non-privileged applications to change night
+     * mode will fail silently.
+     *
+     * @return {@code true} if night mode is locked or {@code false} otherwise
      */
     public boolean isNightModeLocked() {
         if (mService != null) {
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 5b5bba4..b0ffd21 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.annotation.IntDef;
 import android.annotation.RawRes;
 import android.annotation.SystemApi;
 import android.content.ComponentName;
@@ -60,7 +61,11 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Provides access to the system wallpaper. With WallpaperManager, you can
@@ -144,7 +149,33 @@
      * and y arguments are the location of the drop.
      */
     public static final String COMMAND_DROP = "android.home.drop";
-    
+
+    /**
+     * Extra passed back from setWallpaper() giving the new wallpaper's assigned ID.
+     * @hide
+     */
+    public static final String EXTRA_NEW_WALLPAPER_ID = "android.service.wallpaper.extra.ID";
+
+    // flags for which kind of wallpaper to set
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            FLAG_SET_SYSTEM,
+            FLAG_SET_LOCK
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SetWallpaperFlags {}
+
+    /**
+     * Flag: use the supplied imagery as the general system wallpaper.
+     */
+    public static final int FLAG_SET_SYSTEM = 1 << 0;
+
+    /**
+     * Flag: use the supplied imagery as the lock-screen wallpaper.
+     */
+    public static final int FLAG_SET_LOCK = 1 << 1;
+
     private final Context mContext;
     
     /**
@@ -717,27 +748,57 @@
      * wallpaper.
      */
     public void setResource(@RawRes int resid) throws IOException {
+        setResource(resid, FLAG_SET_SYSTEM);
+    }
+
+    /**
+     * Version of {@link #setResource(int)} that takes an optional Bundle for returning
+     * metadata about the operation to the caller.
+     *
+     * @param resid
+     * @param which Flags indicating which wallpaper(s) to configure with the new imagery.
+     *
+     * @see #FLAG_SET_LOCK
+     * @see #FLAG_SET_SYSTEM
+     *
+     * @return An integer ID assigned to the newly active wallpaper; or zero on failure.
+     *
+     * @throws IOException
+     */
+    public int setResource(@RawRes int resid, @SetWallpaperFlags int which)
+            throws IOException {
         if (sGlobals.mService == null) {
             Log.w(TAG, "WallpaperService not running");
-            return;
+            return 0;
         }
+        final Bundle result = new Bundle();
+        final WallpaperSetCompletion completion = new WallpaperSetCompletion();
         try {
             Resources resources = mContext.getResources();
             /* Set the wallpaper to the default values */
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(
-                    "res:" + resources.getResourceName(resid), mContext.getOpPackageName());
+                    "res:" + resources.getResourceName(resid),
+                    mContext.getOpPackageName(), null, result, which, completion);
             if (fd != null) {
                 FileOutputStream fos = null;
+                boolean ok = false;
                 try {
                     fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
-                    setWallpaper(resources.openRawResource(resid), fos);
+                    copyStreamToWallpaperFile(resources.openRawResource(resid), fos);
+                    // The 'close()' is the trigger for any server-side image manipulation,
+                    // so we must do that before waiting for completion.
+                    fos.close();
+                    completion.waitForCompletion();
                 } finally {
+                    // Might be redundant but completion shouldn't wait unless the write
+                    // succeeded; this is a fallback if it threw past the close+wait.
                     IoUtils.closeQuietly(fos);
                 }
             }
         } catch (RemoteException e) {
             // Ignore
         }
+        return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
     }
 
     /**
@@ -753,7 +814,7 @@
      * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#SET_WALLPAPER}.
      *
-     * @param bitmap The bitmap to save.
+     * @param bitmap The bitmap to be used as the new system wallpaper.
      *
      * @throws IOException If an error occurs when attempting to set the wallpaper
      *     to the provided image.
@@ -775,42 +836,75 @@
      * <p>This method requires the caller to hold the permission
      * {@link android.Manifest.permission#SET_WALLPAPER}.
      *
-     * @param fullImage A bitmap that will supply the wallpaper imagery. 
+     * @param fullImage A bitmap that will supply the wallpaper imagery.
      * @param visibleCropHint The rectangular subregion of {@code fullImage} that should be
      *     displayed as wallpaper.  Passing {@code null} for this parameter means that
      *     the full image should be displayed if possible given the image's and device's
-     *     aspect ratios, etc. 
+     *     aspect ratios, etc.
      * @param allowBackup {@code true} if the OS is permitted to back up this wallpaper
      *     image for restore to a future device; {@code false} otherwise.
      *
+     * @return An integer ID assigned to the newly active wallpaper; or zero on failure.
+     *
      * @throws IOException If an error occurs when attempting to set the wallpaper
      *     to the provided image.
      * @throws IllegalArgumentException If the {@code visibleCropHint} rectangle is
      *     empty or invalid.
      */
-    public void setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup)
+    public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup)
+            throws IOException {
+        return setBitmap(fullImage, visibleCropHint, allowBackup, FLAG_SET_SYSTEM);
+    }
+
+    /**
+    /**
+     * Version of {@link #setBitmap(Bitmap, Rect, boolean)} that allows the caller
+     * to specify which of the supported wallpaper categories to set.
+     *
+     * @param fullImage A bitmap that will supply the wallpaper imagery.
+     * @param visibleCropHint The rectangular subregion of {@code fullImage} that should be
+     *     displayed as wallpaper.  Passing {@code null} for this parameter means that
+     *     the full image should be displayed if possible given the image's and device's
+     *     aspect ratios, etc.
+     * @param allowBackup {@code true} if the OS is permitted to back up this wallpaper
+     *     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
+     *
+     * @return An integer ID assigned to the newly active wallpaper; or zero on failure.
+     *
+     * @throws IOException
+     */
+    public int setBitmap(Bitmap fullImage, Rect visibleCropHint,
+            boolean allowBackup, @SetWallpaperFlags int which)
             throws IOException {
         validateRect(visibleCropHint);
         if (sGlobals.mService == null) {
             Log.w(TAG, "WallpaperService not running");
-            return;
+            return 0;
         }
+        final Bundle result = new Bundle();
+        final WallpaperSetCompletion completion = new WallpaperSetCompletion();
         try {
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
-                    mContext.getOpPackageName());
-            if (fd == null) {
-                return;
-            }
-            FileOutputStream fos = null;
-            try {
-                fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
-                fullImage.compress(Bitmap.CompressFormat.PNG, 90, fos);
-            } finally {
-                IoUtils.closeQuietly(fos);
+                    mContext.getOpPackageName(), visibleCropHint, result, which, completion);
+            if (fd != null) {
+                FileOutputStream fos = null;
+                try {
+                    fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
+                    fullImage.compress(Bitmap.CompressFormat.PNG, 90, fos);
+                    fos.close();
+                    completion.waitForCompletion();
+                } finally {
+                    IoUtils.closeQuietly(fos);
+                }
             }
         } catch (RemoteException e) {
             // Ignore
         }
+        return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
     }
 
     private final void validateRect(Rect rect) {
@@ -843,7 +937,7 @@
         setStream(bitmapData, null, true);
     }
 
-    private void setWallpaper(InputStream data, FileOutputStream fos)
+    private void copyStreamToWallpaperFile(InputStream data, FileOutputStream fos)
             throws IOException {
         byte[] buffer = new byte[32768];
         int amt;
@@ -877,29 +971,58 @@
      * @throws IllegalArgumentException If the {@code visibleCropHint} rectangle is
      *     empty or invalid.
      */
-    public void setStream(InputStream bitmapData, Rect visibleCropHint, boolean allowBackup)
+    public int setStream(InputStream bitmapData, Rect visibleCropHint, boolean allowBackup)
             throws IOException {
+        return setStream(bitmapData, visibleCropHint, allowBackup, FLAG_SET_SYSTEM);
+    }
+
+    /**
+     * Version of {@link #setStream(InputStream, Rect, boolean)} that allows the caller
+     * to specify which of the supported wallpaper categories to set.
+     *
+     * @param bitmapData A stream containing the raw data to install as a wallpaper.
+     * @param visibleCropHint The rectangular subregion of the streamed image that should be
+     *     displayed as wallpaper.  Passing {@code null} for this parameter means that
+     *     the full image should be displayed if possible given the image's and device's
+     *     aspect ratios, etc.
+     * @param allowBackup {@code true} if the OS is permitted to back up this wallpaper
+     *     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
+     *
+     * @throws IOException
+     */
+    public int setStream(InputStream bitmapData, Rect visibleCropHint,
+            boolean allowBackup, @SetWallpaperFlags int which)
+                    throws IOException {
         validateRect(visibleCropHint);
         if (sGlobals.mService == null) {
             Log.w(TAG, "WallpaperService not running");
-            return;
+            return 0;
         }
+        final Bundle result = new Bundle();
+        final WallpaperSetCompletion completion = new WallpaperSetCompletion();
         try {
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
-                    mContext.getOpPackageName());
-            if (fd == null) {
-                return;
-            }
-            FileOutputStream fos = null;
-            try {
-                fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
-                setWallpaper(bitmapData, fos);
-            } finally {
-                IoUtils.closeQuietly(fos);
+                    mContext.getOpPackageName(), visibleCropHint, result, which, completion);
+            if (fd != null) {
+                FileOutputStream fos = null;
+                try {
+                    fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
+                    copyStreamToWallpaperFile(bitmapData, fos);
+                    fos.close();
+                    completion.waitForCompletion();
+                } finally {
+                    IoUtils.closeQuietly(fos);
+                }
             }
         } catch (RemoteException e) {
             // Ignore
         }
+
+        return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
     }
 
     /**
@@ -1278,4 +1401,28 @@
 
         return null;
     }
+
+    // Private completion callback for setWallpaper() synchronization
+    private class WallpaperSetCompletion extends IWallpaperManagerCallback.Stub {
+        final CountDownLatch mLatch;
+
+        public WallpaperSetCompletion() {
+            mLatch = new CountDownLatch(1);
+        }
+
+        public void waitForCompletion() {
+            try {
+                mLatch.await(30, TimeUnit.SECONDS);
+            } catch (InterruptedException e) {
+                // This might be legit: the crop may take a very long time. Don't sweat
+                // it in that case; we are okay with display lagging behind in order to
+                // keep the caller from locking up indeterminately.
+            }
+        }
+
+        @Override
+        public void onWallpaperChanged() throws RemoteException {
+            mLatch.countDown();
+        }
+    }
 }
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 84b6d39..3c1ecc7 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -17,6 +17,7 @@
 package android.app.admin;
 
 import android.accounts.AccountManager;
+import android.annotation.IntDef;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
@@ -29,6 +30,9 @@
 import android.os.Bundle;
 import android.security.KeyChain;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Base class for implementing a device administration component.  This
  * class provides a convenience for interpreting the raw intent actions
@@ -227,6 +231,75 @@
     public static final String ACTION_PROFILE_PROVISIONING_COMPLETE =
             "android.app.action.PROFILE_PROVISIONING_COMPLETE";
 
+    /**
+     * Action sent to a device administrator to notify that the device user
+     * has declined sharing a bugreport.
+     *
+     * <p>The calling device admin must be the device owner to receive this broadcast.
+     * @see DevicePolicyManager#requestBugreport
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_BUGREPORT_SHARING_DECLINED =
+            "android.app.action.BUGREPORT_SHARING_DECLINED";
+
+    /**
+     * Action sent to a device administrator to notify that the collection of a bugreport
+     * has failed.
+     *
+     * <p>The calling device admin must be the device owner to receive this broadcast.
+     * @see DevicePolicyManager#requestBugreport
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_BUGREPORT_FAILED = "android.app.action.BUGREPORT_FAILED";
+
+    /**
+     * Action sent to a device administrator to share the bugreport.
+     *
+     * <p>The calling device admin must be the device owner to receive this broadcast.
+     * @see DevicePolicyManager#requestBugreport
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_BUGREPORT_SHARE =
+            "android.app.action.BUGREPORT_SHARE";
+
+    /**
+     * A string containing the SHA-256 hash of the bugreport file.
+     *
+     * @see #ACTION_BUGREPORT_SHARE
+     * @hide
+     */
+    public static final String EXTRA_BUGREPORT_HASH = "android.app.extra.BUGREPORT_HASH";
+
+    /**
+     * An {@code int} failure code representing the reason of the bugreport failure.
+     *
+     * @see #ACTION_BUGREPORT_FAILED
+     * @see #BUGREPORT_FAILURE_FAILED_COMPLETING, #BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE
+     * @hide
+     */
+    public static final String EXTRA_BUGREPORT_FAILURE_REASON =
+            "android.app.extra.BUGREPORT_FAILURE_REASON";
+
+    /**
+     * An interface representing reason of bugreport failure.
+     *
+     * @see #EXTRA_BUGREPORT_FAILURE_REASON
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+        BUGREPORT_FAILURE_FAILED_COMPLETING,
+        BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE
+    })
+    public @interface BugreportFailureCode {}
+    /** Bugreport completion process failed. */
+    public static final int BUGREPORT_FAILURE_FAILED_COMPLETING = 0;
+    /** Bugreport is no longer available for collection. */
+    public static final int BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE = 1;
+
     /** @hide */
     public static final String ACTION_CHOOSE_PRIVATE_KEY_ALIAS = "android.app.action.CHOOSE_PRIVATE_KEY_ALIAS";
 
@@ -338,8 +411,7 @@
     /**
      * Called after the user has changed their password, as a result of
      * receiving {@link #ACTION_PASSWORD_CHANGED}.  At this point you
-     * can use {@link DevicePolicyManager#getCurrentFailedPasswordAttempts()
-     * DevicePolicyManager.getCurrentFailedPasswordAttempts()}
+     * can use {@link DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
      * to retrieve the active password characteristics.
      * @param context The running context as per {@link #onReceive}.
      * @param intent The received intent as per {@link #onReceive}.
@@ -482,6 +554,48 @@
     }
 
     /**
+     * Called when sharing a bugreport has been cancelled by the user of the device.
+     *
+     * <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#requestBugreport
+     */
+    public void onBugreportSharingDeclined(Context context, Intent intent) {
+    }
+
+    /**
+     * Called when the bugreport has been shared with the device administrator app.
+     *
+     * <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}. Contains the URI of
+     * the bugreport file (with MIME type "application/vnd.android.bugreport"), that can be accessed
+     * by calling {@link Intent#getData()}
+     * @param bugreportHash SHA-256 hash of the bugreport file.
+     * @see DevicePolicyManager#requestBugreport
+     */
+    public void onBugreportShared(Context context, Intent intent, String bugreportHash) {
+    }
+
+    /**
+     * Called when the bugreport collection flow has failed.
+     *
+     * <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}.
+     * @param failureCode int containing failure code. One of
+     * #BUGREPORT_FAILURE_FAILED_COMPLETING or #BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE
+     * @see DevicePolicyManager#requestBugreport
+     */
+    public void onBugreportFailed(Context context, Intent intent,
+            @BugreportFailureCode int failureCode) {
+    }
+
+    /**
      * Intercept standard device administrator broadcasts.  Implementations
      * should not override this method; it is better to implement the
      * convenience callbacks for each action.
@@ -524,6 +638,15 @@
         } else if (ACTION_NOTIFY_PENDING_SYSTEM_UPDATE.equals(action)) {
             long receivedTime = intent.getLongExtra(EXTRA_SYSTEM_UPDATE_RECEIVED_TIME, -1);
             onSystemUpdatePending(context, intent, receivedTime);
+        } else if (ACTION_BUGREPORT_SHARING_DECLINED.equals(action)) {
+            onBugreportSharingDeclined(context, intent);
+        } else if (ACTION_BUGREPORT_SHARE.equals(action)) {
+            String bugreportFileHash = intent.getStringExtra(EXTRA_BUGREPORT_HASH);
+            onBugreportShared(context, intent, bugreportFileHash);
+        } else if (ACTION_BUGREPORT_FAILED.equals(action)) {
+            int failureCode = intent.getIntExtra(EXTRA_BUGREPORT_FAILURE_REASON,
+                    BUGREPORT_FAILURE_FAILED_COMPLETING);
+            onBugreportFailed(context, intent, failureCode);
         }
     }
 }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 660ce3b..e4e97a1 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -16,6 +16,7 @@
 
 package android.app.admin;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
@@ -29,6 +30,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
 import android.graphics.Bitmap;
 import android.net.ProxyInfo;
 import android.net.Uri;
@@ -40,8 +42,8 @@
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.provider.Settings;
 import android.provider.ContactsContract.Directory;
+import android.provider.Settings;
 import android.security.Credentials;
 import android.service.restrictions.RestrictionsReceiver;
 import android.util.Log;
@@ -53,20 +55,23 @@
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.net.InetSocketAddress;
 import java.net.Proxy;
 import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
-import java.security.spec.PKCS8EncodedKeySpec;
 import java.security.spec.InvalidKeySpecException;
-import java.security.NoSuchAlgorithmException;
+import java.security.spec.PKCS8EncodedKeySpec;
 import java.util.ArrayList;
 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
@@ -88,25 +93,30 @@
 
     private final Context mContext;
     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) {
-        this(context, IDevicePolicyManager.Stub.asInterface(
-                        ServiceManager.getService(Context.DEVICE_POLICY_SERVICE)));
+    private DevicePolicyManager(Context context, boolean parentInstance) {
+        this(context,
+                IDevicePolicyManager.Stub.asInterface(
+                        ServiceManager.getService(Context.DEVICE_POLICY_SERVICE)),
+                parentInstance);
     }
 
     /** @hide */
     @VisibleForTesting
-    protected DevicePolicyManager(Context context, IDevicePolicyManager service) {
+    protected DevicePolicyManager(
+            Context context, IDevicePolicyManager service, boolean parentInstance) {
         mContext = context;
         mService = service;
+        mParentInstance = parentInstance;
     }
 
     /** @hide */
     public static DevicePolicyManager create(Context context) {
-        DevicePolicyManager me = new DevicePolicyManager(context);
+        DevicePolicyManager me = new DevicePolicyManager(context, false);
         return me.mService != null ? me : null;
     }
 
@@ -274,6 +284,21 @@
         = "android.app.action.PROVISION_MANAGED_SHAREABLE_DEVICE";
 
     /**
+     * Activity action: Finalizes management provisioning, should be used after user-setup
+     * has been completed and {@link #getUserProvisioningState()} returns one of:
+     * <ul>
+     * <li>{@link #STATE_USER_SETUP_INCOMPLETE}</li>
+     * <li>{@link #STATE_USER_SETUP_COMPLETE}</li>
+     * <li>{@link #STATE_USER_PROFILE_COMPLETE}</li>
+     * </ul>
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_PROVISION_FINALIZATION
+            = "android.app.action.PROVISION_FINALIZATION";
+
+    /**
      * 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.
@@ -618,6 +643,21 @@
             "android.app.extra.PROVISIONING_LOGO_URI";
 
     /**
+     * A boolean extra indicating if user setup should be skipped, for when provisioning is started
+     * during setup-wizard.
+     *
+     * <p>If unspecified, defaults to {@code true} to match the behavior in
+     * {@link android.os.Build.VERSION_CODES#M} and earlier.
+     *
+     * <p>Use in an intent with action {@link #ACTION_PROVISION_MANAGED_DEVICE} or
+     * {@link #ACTION_PROVISION_MANAGED_USER}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_PROVISIONING_SKIP_USER_SETUP =
+            "android.app.extra.PROVISIONING_SKIP_USER_SETUP";
+
+    /**
      * 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.
@@ -756,12 +796,28 @@
      * have the user select a new password in order to meet the current
      * constraints. Upon being resumed from this activity, you can check the new
      * password characteristics to see if they are sufficient.
+     *
+     * If the intent is launched from within a managed profile with a profile
+     * owner built against {@link android.os.Build.VERSION_CODES#M} or before,
+     * this will trigger entering a new password for the parent of the profile.
+     * For all other cases it will trigger entering a new password for the user
+     * or profile it is launched from.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_SET_NEW_PASSWORD
             = "android.app.action.SET_NEW_PASSWORD";
 
     /**
+     * Activity action: have the user enter a new password for the parent profile.
+     * If the intent is launched from within a managed profile, this will trigger
+     * entering a new password for the parent of the profile. In all other cases
+     * the behaviour is identical to {@link #ACTION_SET_NEW_PASSWORD}.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_SET_NEW_PARENT_PROFILE_PASSWORD
+            = "android.app.action.SET_NEW_PARENT_PROFILE_PASSWORD";
+
+    /**
      * Flag used by {@link #addCrossProfileIntentFilter} to allow activities in
      * the parent profile to access intents sent from the managed profile.
      * That is, when an app in the managed profile calls
@@ -824,6 +880,44 @@
     public static final int PERMISSION_GRANT_STATE_DENIED = 2;
 
     /**
+     * No management for current user in-effect. This is the default.
+     * @hide
+     */
+    public static final int STATE_USER_UNMANAGED = 0;
+
+    /**
+     * Management partially setup, user setup needs to be completed.
+     * @hide
+     */
+    public static final int STATE_USER_SETUP_INCOMPLETE = 1;
+
+    /**
+     * Management partially setup, user setup completed.
+     * @hide
+     */
+    public static final int STATE_USER_SETUP_COMPLETE = 2;
+
+    /**
+     * Management setup and active on current user.
+     * @hide
+     */
+    public static final int STATE_USER_SETUP_FINALIZED = 3;
+
+    /**
+     * Management partially setup on a managed profile.
+     * @hide
+     */
+    public static final int STATE_USER_PROFILE_COMPLETE = 4;
+
+    /**
+     * @hide
+     */
+    @IntDef({STATE_USER_UNMANAGED, STATE_USER_SETUP_INCOMPLETE, STATE_USER_SETUP_COMPLETE,
+            STATE_USER_SETUP_FINALIZED, STATE_USER_PROFILE_COMPLETE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface UserProvisioningState {}
+
+    /**
      * Return true if the given administrator component is currently
      * active (enabled) in the system.
      */
@@ -939,6 +1033,22 @@
     }
 
     /**
+     * Returns true if the Profile Challenge is available to use for the given profile user.
+     *
+     * @hide
+     */
+    public boolean isSeparateProfileChallengeAllowed(int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.isSeparateProfileChallengeAllowed(userHandle);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+        return false;
+    }
+
+    /**
      * Constant for {@link #setPasswordQuality}: the policy has no requirements
      * for the password.  Note that quality constants are ordered so that higher
      * values are more restrictive.
@@ -1004,6 +1114,18 @@
     public static final int PASSWORD_QUALITY_COMPLEX = 0x60000;
 
     /**
+     * Constant for {@link #setPasswordQuality}: the user is not allowed to
+     * modify password. In case this password quality is set, the password is
+     * managed by a profile owner. The profile owner can set any password,
+     * as if {@link #PASSWORD_QUALITY_UNSPECIFIED} is used. Note
+     * that quality constants are ordered so that higher values are more
+     * restrictive. The value of {@link #PASSWORD_QUALITY_MANAGED} is
+     * the highest.
+     * @hide
+     */
+    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
@@ -1031,7 +1153,7 @@
     public void setPasswordQuality(@NonNull ComponentName admin, int quality) {
         if (mService != null) {
             try {
-                mService.setPasswordQuality(admin, quality);
+                mService.setPasswordQuality(admin, quality, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1052,7 +1174,7 @@
     public int getPasswordQuality(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordQuality(admin, userHandle);
+                return mService.getPasswordQuality(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1084,7 +1206,7 @@
     public void setPasswordMinimumLength(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumLength(admin, length);
+                mService.setPasswordMinimumLength(admin, length, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1105,7 +1227,7 @@
     public int getPasswordMinimumLength(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordMinimumLength(admin, userHandle);
+                return mService.getPasswordMinimumLength(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1138,7 +1260,7 @@
     public void setPasswordMinimumUpperCase(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumUpperCase(admin, length);
+                mService.setPasswordMinimumUpperCase(admin, length, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1166,7 +1288,7 @@
     public int getPasswordMinimumUpperCase(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordMinimumUpperCase(admin, userHandle);
+                return mService.getPasswordMinimumUpperCase(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1199,7 +1321,7 @@
     public void setPasswordMinimumLowerCase(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumLowerCase(admin, length);
+                mService.setPasswordMinimumLowerCase(admin, length, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1227,7 +1349,7 @@
     public int getPasswordMinimumLowerCase(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordMinimumLowerCase(admin, userHandle);
+                return mService.getPasswordMinimumLowerCase(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1259,7 +1381,7 @@
     public void setPasswordMinimumLetters(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumLetters(admin, length);
+                mService.setPasswordMinimumLetters(admin, length, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1285,7 +1407,7 @@
     public int getPasswordMinimumLetters(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordMinimumLetters(admin, userHandle);
+                return mService.getPasswordMinimumLetters(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1317,7 +1439,7 @@
     public void setPasswordMinimumNumeric(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumNumeric(admin, length);
+                mService.setPasswordMinimumNumeric(admin, length, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1344,7 +1466,7 @@
     public int getPasswordMinimumNumeric(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordMinimumNumeric(admin, userHandle);
+                return mService.getPasswordMinimumNumeric(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1376,7 +1498,7 @@
     public void setPasswordMinimumSymbols(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumSymbols(admin, length);
+                mService.setPasswordMinimumSymbols(admin, length, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1402,7 +1524,7 @@
     public int getPasswordMinimumSymbols(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordMinimumSymbols(admin, userHandle);
+                return mService.getPasswordMinimumSymbols(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1434,7 +1556,7 @@
     public void setPasswordMinimumNonLetter(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumNonLetter(admin, length);
+                mService.setPasswordMinimumNonLetter(admin, length, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1461,7 +1583,7 @@
     public int getPasswordMinimumNonLetter(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordMinimumNonLetter(admin, userHandle);
+                return mService.getPasswordMinimumNonLetter(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1494,7 +1616,7 @@
     public void setPasswordHistoryLength(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordHistoryLength(admin, length);
+                mService.setPasswordHistoryLength(admin, length, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1526,7 +1648,7 @@
     public void setPasswordExpirationTimeout(@NonNull ComponentName admin, long timeout) {
         if (mService != null) {
             try {
-                mService.setPasswordExpirationTimeout(admin, timeout);
+                mService.setPasswordExpirationTimeout(admin, timeout, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1545,7 +1667,7 @@
     public long getPasswordExpirationTimeout(@Nullable ComponentName admin) {
         if (mService != null) {
             try {
-                return mService.getPasswordExpirationTimeout(admin, myUserId());
+                return mService.getPasswordExpirationTimeout(admin, myUserId(), mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1566,7 +1688,7 @@
     public long getPasswordExpiration(@Nullable ComponentName admin) {
         if (mService != null) {
             try {
-                return mService.getPasswordExpiration(admin, myUserId());
+                return mService.getPasswordExpiration(admin, myUserId(), mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1589,7 +1711,7 @@
     public int getPasswordHistoryLength(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordHistoryLength(admin, userHandle);
+                return mService.getPasswordHistoryLength(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1611,7 +1733,7 @@
     /**
      * Determine whether the current password the user has set is sufficient
      * to meet the policy requirements (quality, minimum length) that have been
-     * requested by the admins of this user and its profiles.
+     * requested by the admins of this user and its profiles that don't have a separate challenge.
      *
      * <p>The calling device admin must have requested
      * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
@@ -1622,7 +1744,27 @@
     public boolean isActivePasswordSufficient() {
         if (mService != null) {
             try {
-                return mService.isActivePasswordSufficient(myUserId());
+                return mService.isActivePasswordSufficient(myUserId(), mParentInstance);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Determine whether the current profile password the user has set is sufficient
+     * to meet the policy requirements (quality, minimum length) that have been
+     * requested by the admins of the parent user and its profiles.
+     *
+     * @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.
+     * @hide
+     */
+    public boolean isProfileActivePasswordSufficientForParent(int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.isProfileActivePasswordSufficientForParent(userHandle);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1641,7 +1783,7 @@
     public int getCurrentFailedPasswordAttempts() {
         if (mService != null) {
             try {
-                return mService.getCurrentFailedPasswordAttempts(myUserId());
+                return mService.getCurrentFailedPasswordAttempts(myUserId(), mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1688,7 +1830,7 @@
     public void setMaximumFailedPasswordsForWipe(@NonNull ComponentName admin, int num) {
         if (mService != null) {
             try {
-                mService.setMaximumFailedPasswordsForWipe(admin, num);
+                mService.setMaximumFailedPasswordsForWipe(admin, num, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1710,7 +1852,8 @@
     public int getMaximumFailedPasswordsForWipe(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getMaximumFailedPasswordsForWipe(admin, userHandle);
+                return mService.getMaximumFailedPasswordsForWipe(
+                        admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1728,7 +1871,8 @@
     public int getProfileWithMinimumFailedPasswordsForWipe(int userHandle) {
         if (mService != null) {
             try {
-                return mService.getProfileWithMinimumFailedPasswordsForWipe(userHandle);
+                return mService.getProfileWithMinimumFailedPasswordsForWipe(
+                        userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1791,6 +1935,9 @@
      * not acceptable for the current constraints or if the user has not been decrypted yet.
      */
     public boolean resetPassword(String password, int flags) {
+        if (mParentInstance) {
+            throw new SecurityException("Reset password does not work across profiles.");
+        }
         if (mService != null) {
             try {
                 return mService.resetPassword(password, flags);
@@ -1817,7 +1964,7 @@
     public void setMaximumTimeToLock(@NonNull ComponentName admin, long timeMs) {
         if (mService != null) {
             try {
-                mService.setMaximumTimeToLock(admin, timeMs);
+                mService.setMaximumTimeToLock(admin, timeMs, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1840,7 +1987,7 @@
     public long getMaximumTimeToLock(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getMaximumTimeToLock(admin, userHandle);
+                return mService.getMaximumTimeToLock(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1859,7 +2006,7 @@
     public void lockNow() {
         if (mService != null) {
             try {
-                mService.lockNow();
+                mService.lockNow(mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -2415,6 +2562,53 @@
     }
 
     /**
+     * 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.
+     *
+     * <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.
+     */
+    public boolean setAlwaysOnVpnPackage(@NonNull ComponentName admin,
+            @Nullable String vpnPackage) {
+        if (mService != null) {
+            try {
+                return mService.setAlwaysOnVpnPackage(admin, vpnPackage);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+        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.
+     *
+     * @return Package name of VPN controller responsible for always-on VPN,
+     *         or {@code null} if none is set.
+     */
+    public String getAlwaysOnVpnPackage(@NonNull ComponentName admin) {
+        if (mService != null) {
+            try {
+                return mService.getAlwaysOnVpnPackage(admin);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+        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.
@@ -2461,6 +2655,28 @@
     }
 
     /**
+     * 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.
+     *
+     * @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)
+     */
+    public boolean requestBugreport(@NonNull ComponentName admin) {
+        if (mService != null) {
+            try {
+                return mService.requestBugreport(admin);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+        return false;
+    }
+
+    /**
      * Determine whether or not creating a guest user has been disabled for the device
      *
      * @hide
@@ -2555,6 +2771,45 @@
     }
 
     /**
+     * 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.
+     *
+     * @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.
+     * @hide
+     */
+    public void setForceEphemeralUsers(
+            @NonNull ComponentName admin, boolean forceEphemeralUsers) {
+        if (mService != null) {
+            try {
+                mService.setForceEphemeralUsers(admin, forceEphemeralUsers);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+    }
+
+    /**
+     * @return true if all users are created ephemeral.
+     * @hide
+     */
+    public boolean getForceEphemeralUsers(@NonNull ComponentName admin) {
+        if (mService != null) {
+            try {
+                return mService.getForceEphemeralUsers(admin);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+        return false;
+    }
+
+    /**
      * 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.
@@ -2587,7 +2842,7 @@
     public void setKeyguardDisabledFeatures(@NonNull ComponentName admin, int which) {
         if (mService != null) {
             try {
-                mService.setKeyguardDisabledFeatures(admin, which);
+                mService.setKeyguardDisabledFeatures(admin, which, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -2597,8 +2852,8 @@
     /**
      * Determine whether or not features have been disabled in keyguard either by the calling
      * admin, if specified, or all admins.
-     * @param admin The name of the admin component to check, or {@code null} to check whether any admins
-     * have disabled features in keyguard.
+     * @param admin The name of the admin component to check, or {@code null} to check whether any
+     * admins have disabled features in keyguard.
      * @return bitfield of flags. See {@link #setKeyguardDisabledFeatures(ComponentName, int)}
      * for a list.
      */
@@ -2610,7 +2865,7 @@
     public int getKeyguardDisabledFeatures(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getKeyguardDisabledFeatures(admin, userHandle);
+                return mService.getKeyguardDisabledFeatures(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -2719,6 +2974,34 @@
     }
 
     /**
+     * Should be called when keyguard has been dismissed.
+     * @hide
+     */
+    public void reportKeyguardDismissed() {
+        if (mService != null) {
+            try {
+                mService.reportKeyguardDismissed();
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+    }
+
+    /**
+     * Should be called when keyguard view has been shown to the user.
+     * @hide
+     */
+    public void reportKeyguardSecured() {
+        if (mService != null) {
+            try {
+                mService.reportKeyguardSecured();
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+    }
+
+    /**
      * @hide
      * Sets the given package as the device owner.
      * Same as {@link #setDeviceOwner(ComponentName, String)} but without setting a device owner name.
@@ -2924,6 +3207,7 @@
      *
      * @hide
      */
+    @SystemApi
     public String getDeviceOwnerNameOnAnyUser() {
         if (mService != null) {
             try {
@@ -2989,15 +3273,14 @@
     }
 
     /**
-     * @hide
      * 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.
-     * @return
      */
-    @SystemApi
     public void clearProfileOwner(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
@@ -3060,6 +3343,8 @@
      *
      * <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.
      *
      * @param admin The name of the admin component to check.
      * @param info Device owner information which will be displayed instead of the user
@@ -3312,8 +3597,69 @@
     }
 
     /**
-     * Called by a profile or device owner to set the application restrictions for a given target
-     * application running in the profile.
+     * Called by a profile owner or device owner to grant permission to a package to manage
+     * application restrictions for the calling user via {@link #setApplicationRestrictions} and
+     * {@link #getApplicationRestrictions}.
+     * <p>
+     * This permission is persistent until it is later cleared by calling this method with a
+     * {@code null} value or uninstalling the managing package.
+     *
+     * @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.
+     */
+    public void setApplicationRestrictionsManagingPackage(@NonNull ComponentName admin,
+            @Nullable String packageName) {
+        if (mService != null) {
+            try {
+                mService.setApplicationRestrictionsManagingPackage(admin, packageName);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+    }
+
+    /**
+     * Called by a profile owner or device owner to retrieve the application restrictions managing
+     * package for the current user, or {@code null} if none is set.
+     *
+     * @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.
+     */
+    public String getApplicationRestrictionsManagingPackage(@NonNull ComponentName admin) {
+        if (mService != null) {
+            try {
+                return mService.getApplicationRestrictionsManagingPackage(admin);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns {@code true} if the calling package has been granted permission via
+     * {@link #setApplicationRestrictionsManagingPackage} to manage application
+     * restrictions for the calling user.
+     */
+    public boolean isCallerApplicationRestrictionsManagingPackage() {
+        if (mService != null) {
+            try {
+                return mService.isCallerApplicationRestrictionsManagingPackage();
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 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:
      * <ul>
@@ -3323,24 +3669,25 @@
      * <li>From {@link android.os.Build.VERSION_CODES#M}, {@code Bundle} or {@code Bundle[]}
      * </ul>
      *
-     * <p>The application restrictions are only made visible to the target application and the
-     * profile or device owner.
-     *
      * <p>If the restrictions are not available yet, but may be applied in the near future,
-     * the admin can notify the target application of that by adding
+     * the caller can notify the target application of that by adding
      * {@link UserManager#KEY_RESTRICTIONS_PENDING} to the settings parameter.
      *
-     * <p>The calling device admin must be a profile or device owner; if it is not, a security
-     * exception will be thrown.
+     * <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.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+     * {@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.
      *
+     * @see #setApplicationRestrictionsManagingPackage
      * @see UserManager#KEY_RESTRICTIONS_PENDING
      */
-    public void setApplicationRestrictions(@NonNull ComponentName admin, String packageName,
+    public void setApplicationRestrictions(@Nullable ComponentName admin, String packageName,
             Bundle settings) {
         if (mService != null) {
             try {
@@ -3471,15 +3818,76 @@
     }
 
     /**
+     * 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.
+     */
+    public void setCrossProfileContactsSearchDisabled(@NonNull ComponentName admin,
+            boolean disabled) {
+        if (mService != null) {
+            try {
+                mService.setCrossProfileContactsSearchDisabled(admin, disabled);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+    }
+
+    /**
+     * 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.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     */
+    public boolean getCrossProfileContactsSearchDisabled(@NonNull ComponentName admin) {
+        if (mService != null) {
+            try {
+                return mService.getCrossProfileContactsSearchDisabled(admin);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+        return false;
+    }
+
+
+    /**
+     * Determine whether or not contacts search has been disabled.
+     *
+     * @param userHandle The user for whom to check the contacts search permission
+     * @hide
+     */
+    public boolean getCrossProfileContactsSearchDisabled(@NonNull UserHandle userHandle) {
+        if (mService != null) {
+            try {
+                return mService
+                        .getCrossProfileContactsSearchDisabledForUser(userHandle.getIdentifier());
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+        return false;
+    }
+
+    /**
      * Start Quick Contact on the managed profile for the user, if the policy allows.
+     *
      * @hide
      */
     public void startManagedQuickContact(String actualLookupKey, long actualContactId,
-            long directoryId, Intent originalIntent) {
+            boolean isContactIdIgnored, long directoryId, Intent originalIntent) {
         if (mService != null) {
             try {
-                mService.startManagedQuickContact(
-                        actualLookupKey, actualContactId, directoryId, originalIntent);
+                mService.startManagedQuickContact(actualLookupKey, actualContactId,
+                        isContactIdIgnored, directoryId, originalIntent);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -3492,7 +3900,7 @@
      */
     public void startManagedQuickContact(String actualLookupKey, long actualContactId,
             Intent originalIntent) {
-        startManagedQuickContact(actualLookupKey, actualContactId, Directory.DEFAULT,
+        startManagedQuickContact(actualLookupKey, actualContactId, false, Directory.DEFAULT,
                 originalIntent);
     }
 
@@ -3861,6 +4269,57 @@
     }
 
     /**
+      * Flag used by {@link #createAndManageUser} to skip setup wizard after creating a new user.
+      */
+    public static final int SKIP_SETUP_WIZARD = 0x0001;
+
+    /**
+     * Flag used by {@link #createAndManageUser} to specify that the user should be created
+     * ephemeral.
+     * @hide
+     */
+    public static final int MAKE_USER_EPHEMERAL = 0x0002;
+
+    /**
+     * Called by a device owner to create a user with the specified name and a given component of
+     * the calling package as profile owner. The UserHandle returned by this method should not be
+     * persisted as user handles are recycled as users are removed and created. If you need to
+     * persist an identifier for this user, use {@link UserManager#getSerialNumberForUser}. The new
+     * user will 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.
+     *
+     * @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.
+     * @param adminExtras Extras that will be passed to onEnable of the admin receiver on the new
+     *      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.
+     */
+    public UserHandle createAndManageUser(@NonNull ComponentName admin, @NonNull String name,
+            @NonNull ComponentName profileOwner, @Nullable PersistableBundle adminExtras,
+            int flags) {
+        try {
+            return mService.createAndManageUser(admin, name, profileOwner, adminExtras, flags);
+        } catch (RemoteException re) {
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+        }
+        return null;
+    }
+
+    /**
      * Called by a device owner to remove a user and all associated data. The primary user can
      * not be removed.
      *
@@ -3896,19 +4355,23 @@
     }
 
     /**
-     * Called by a profile or device owner to get the application restrictions for a given target
-     * application running in the profile.
+     * Retrieves the application restrictions for a given target application running in the calling
+     * user.
      *
-     * <p>The calling device admin must be a profile or device owner; if it is not, 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.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+     * {@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.
+     *
+     * @see {@link #setApplicationRestrictionsManagingPackage}
      */
-    public Bundle getApplicationRestrictions(@NonNull ComponentName admin, String packageName) {
+    public Bundle getApplicationRestrictions(@Nullable ComponentName admin, String packageName) {
         if (mService != null) {
             try {
                 return mService.getApplicationRestrictions(admin, packageName);
@@ -4076,6 +4539,10 @@
      * <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
@@ -4400,7 +4867,8 @@
      * @see #addCrossProfileWidgetProvider(android.content.ComponentName, String)
      * @see #getCrossProfileWidgetProviders(android.content.ComponentName)
      */
-    public boolean removeCrossProfileWidgetProvider(@NonNull ComponentName admin, String packageName) {
+    public boolean removeCrossProfileWidgetProvider(
+            @NonNull ComponentName admin, String packageName) {
         if (mService != null) {
             try {
                 return mService.removeCrossProfileWidgetProvider(admin, packageName);
@@ -4721,4 +5189,303 @@
             return null;
         }
     }
+
+    /**
+     * Called by device owner to reboot the device.
+     */
+    public void reboot(@NonNull ComponentName admin) {
+        try {
+            mService.reboot(admin);
+        } catch (RemoteException re) {
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+        }
+    }
+
+    /**
+     * 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.
+     *
+     * @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.
+     */
+    public void setShortSupportMessage(@NonNull ComponentName admin,
+            @Nullable String message) {
+        if (mService != null) {
+            try {
+                mService.setShortSupportMessage(admin, message);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+    }
+
+    /**
+     * 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.
+     */
+    public String getShortSupportMessage(@NonNull ComponentName admin) {
+        if (mService != null) {
+            try {
+                return mService.getShortSupportMessage(admin);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+        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.
+     *
+     * @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.
+     */
+    public void setLongSupportMessage(@NonNull ComponentName admin,
+            @Nullable String message) {
+        if (mService != null) {
+            try {
+                mService.setLongSupportMessage(admin, message);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+    }
+
+    /**
+     * 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.
+     */
+    public String getLongSupportMessage(@NonNull ComponentName admin) {
+        if (mService != null) {
+            try {
+                return mService.getLongSupportMessage(admin);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Called by the system to get the short support message.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param userHandle user id the admin is running as.
+     * @return The message set by {@link #setShortSupportMessage(ComponentName, String)}
+     *
+     * @hide
+     */
+    public String getShortSupportMessageForUser(@NonNull ComponentName admin, int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.getShortSupportMessageForUser(admin, userHandle);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+        return null;
+    }
+
+
+    /**
+     * Called by the system to get the long support message.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param userHandle user id the admin is running as.
+     * @return The message set by {@link #setLongSupportMessage(ComponentName, String)}
+     *
+     * @hide
+     */
+    public String getLongSupportMessageForUser(@NonNull ComponentName admin, int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.getLongSupportMessageForUser(admin, userHandle);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 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.
+     *
+     * @return a new instance of {@link DevicePolicyManager} that acts on the parent profile.
+     */
+    public DevicePolicyManager getParentProfileInstance(@NonNull ComponentName admin) {
+        try {
+            if (!mService.isManagedProfile(admin)) {
+                throw new SecurityException("The current user does not have a parent profile.");
+            }
+            return new DevicePolicyManager(mContext, true);
+        } catch (RemoteException re) {
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+            return null;
+        }
+    }
+
+    /**
+     * Called by the system to obtain a {@link DevicePolicyManager} whose calls act on the parent
+     * profile.
+     *
+     * @hide
+     */
+    public DevicePolicyManager getParentProfileInstance(UserInfo uInfo) {
+        mContext.checkSelfPermission(
+                android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        if (!uInfo.isManagedProfile()) {
+            throw new SecurityException("The user " + uInfo.id
+                    + " does not have a parent profile.");
+        }
+        return new DevicePolicyManager(mContext, true);
+    }
+
+    /**
+     * 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
+     * {@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.
+     */
+    public void setOrganizationColor(@NonNull ComponentName admin, int color) {
+        try {
+            mService.setOrganizationColor(admin, color);
+        } catch (RemoteException re) {
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+        }
+    }
+
+    /**
+     * Called by a profile owner of a managed profile to retrieve the color used for customization.
+     * This color is used as background color of the confirm credentials screen for that user.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @return The 32bit representation of the color to be used.
+     */
+    public int getOrganizationColor(@NonNull ComponentName admin) {
+        try {
+            return mService.getOrganizationColor(admin);
+        } catch (RemoteException re) {
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+            return 0;
+        }
+    }
+
+    /**
+     * @hide
+     * Retrieve the customization color for a given user.
+     *
+     * @param userHandle The user id of the user we're interested in.
+     * @return The 32bit representation of the color to be used.
+     */
+    public int getOrganizationColorForUser(int userHandle) {
+        try {
+            return mService.getOrganizationColorForUser(userHandle);
+        } catch (RemoteException re) {
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+            return 0;
+        }
+    }
+
+    /**
+     * @return the {@link UserProvisioningState} for the current user - for unmanaged users will
+     *         return {@link #STATE_USER_UNMANAGED}
+     * @hide
+     */
+    @UserProvisioningState
+    public int getUserProvisioningState() {
+        if (mService != null) {
+            try {
+                return mService.getUserProvisioningState();
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+        return STATE_USER_UNMANAGED;
+    }
+
+    /**
+     * Set the {@link UserProvisioningState} for the supplied user, if they are managed.
+     *
+     * @param state to store
+     * @param userHandle for user
+     * @hide
+     */
+    public void setUserProvisioningState(@UserProvisioningState int state, int userHandle) {
+        if (mService != null) {
+            try {
+                mService.setUserProvisioningState(state, userHandle);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+    }
+
+    /**
+     * @hide
+     * Indicates the entity that controls the device or profile owner. A user/profile is considered
+     * affiliated if it is managed by the same entity as the device.
+     *
+     * <p> By definition, the user that the device owner runs on is always affiliated. Any other
+     * user/profile is considered affiliated if the following conditions are both met:
+     * <ul>
+     * <li>The device owner and the user's/profile's profile owner have called this method,
+     *   specifying a set of opaque affiliation ids each. If the sets specified by the device owner
+     *   and a profile owner intersect, they must have come from the same source, which means that
+     *   the device owner and profile owner are controlled by the same entity.</li>
+     * <li>The device owner's and profile owner's package names are the same.</li>
+     * </ul>
+     *
+     * @param admin Which profile or device owner this request is associated with.
+     * @param ids A set of opaque affiliation ids.
+     */
+    public void setAffiliationIds(@NonNull ComponentName admin, Set<String> ids) {
+        try {
+            mService.setAffiliationIds(admin, new ArrayList<String>(ids));
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed talking with device policy service", e);
+        }
+    }
+
+    /**
+     * @hide
+     * Returns whether this user/profile is affiliated with the device. See
+     * {@link #setAffiliationIds} for the definition of affiliation.
+     *
+     * @return whether this user/profile is affiliated with the device.
+     */
+    public boolean isAffiliatedUser() {
+        try {
+            return mService != null && mService.isAffiliatedUser();
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed talking with device policy service", e);
+            return false;
+        }
+    }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index d8cc2ea..6333013 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -35,51 +35,52 @@
  * {@hide}
  */
 interface IDevicePolicyManager {
-    void setPasswordQuality(in ComponentName who, int quality);
-    int getPasswordQuality(in ComponentName who, int userHandle);
+    void setPasswordQuality(in ComponentName who, int quality, boolean parent);
+    int getPasswordQuality(in ComponentName who, int userHandle, boolean parent);
 
-    void setPasswordMinimumLength(in ComponentName who, int length);
-    int getPasswordMinimumLength(in ComponentName who, int userHandle);
+    void setPasswordMinimumLength(in ComponentName who, int length, boolean parent);
+    int getPasswordMinimumLength(in ComponentName who, int userHandle, boolean parent);
 
-    void setPasswordMinimumUpperCase(in ComponentName who, int length);
-    int getPasswordMinimumUpperCase(in ComponentName who, int userHandle);
+    void setPasswordMinimumUpperCase(in ComponentName who, int length, boolean parent);
+    int getPasswordMinimumUpperCase(in ComponentName who, int userHandle, boolean parent);
 
-    void setPasswordMinimumLowerCase(in ComponentName who, int length);
-    int getPasswordMinimumLowerCase(in ComponentName who, int userHandle);
+    void setPasswordMinimumLowerCase(in ComponentName who, int length, boolean parent);
+    int getPasswordMinimumLowerCase(in ComponentName who, int userHandle, boolean parent);
 
-    void setPasswordMinimumLetters(in ComponentName who, int length);
-    int getPasswordMinimumLetters(in ComponentName who, int userHandle);
+    void setPasswordMinimumLetters(in ComponentName who, int length, boolean parent);
+    int getPasswordMinimumLetters(in ComponentName who, int userHandle, boolean parent);
 
-    void setPasswordMinimumNumeric(in ComponentName who, int length);
-    int getPasswordMinimumNumeric(in ComponentName who, int userHandle);
+    void setPasswordMinimumNumeric(in ComponentName who, int length, boolean parent);
+    int getPasswordMinimumNumeric(in ComponentName who, int userHandle, boolean parent);
 
-    void setPasswordMinimumSymbols(in ComponentName who, int length);
-    int getPasswordMinimumSymbols(in ComponentName who, int userHandle);
+    void setPasswordMinimumSymbols(in ComponentName who, int length, boolean parent);
+    int getPasswordMinimumSymbols(in ComponentName who, int userHandle, boolean parent);
 
-    void setPasswordMinimumNonLetter(in ComponentName who, int length);
-    int getPasswordMinimumNonLetter(in ComponentName who, int userHandle);
+    void setPasswordMinimumNonLetter(in ComponentName who, int length, boolean parent);
+    int getPasswordMinimumNonLetter(in ComponentName who, int userHandle, boolean parent);
 
-    void setPasswordHistoryLength(in ComponentName who, int length);
-    int getPasswordHistoryLength(in ComponentName who, int userHandle);
+    void setPasswordHistoryLength(in ComponentName who, int length, boolean parent);
+    int getPasswordHistoryLength(in ComponentName who, int userHandle, boolean parent);
 
-    void setPasswordExpirationTimeout(in ComponentName who, long expiration);
-    long getPasswordExpirationTimeout(in ComponentName who, int userHandle);
+    void setPasswordExpirationTimeout(in ComponentName who, long expiration, boolean parent);
+    long getPasswordExpirationTimeout(in ComponentName who, int userHandle, boolean parent);
 
-    long getPasswordExpiration(in ComponentName who, int userHandle);
+    long getPasswordExpiration(in ComponentName who, int userHandle, boolean parent);
 
-    boolean isActivePasswordSufficient(int userHandle);
-    int getCurrentFailedPasswordAttempts(int userHandle);
-    int getProfileWithMinimumFailedPasswordsForWipe(int userHandle);
+    boolean isActivePasswordSufficient(int userHandle, boolean parent);
+    boolean isProfileActivePasswordSufficientForParent(int userHandle);
+    int getCurrentFailedPasswordAttempts(int userHandle, boolean parent);
+    int getProfileWithMinimumFailedPasswordsForWipe(int userHandle, boolean parent);
 
-    void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num);
-    int getMaximumFailedPasswordsForWipe(in ComponentName admin, int userHandle);
+    void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num, boolean parent);
+    int getMaximumFailedPasswordsForWipe(in ComponentName admin, int userHandle, boolean parent);
 
     boolean resetPassword(String password, int flags);
 
-    void setMaximumTimeToLock(in ComponentName who, long timeMs);
-    long getMaximumTimeToLock(in ComponentName who, int userHandle);
+    void setMaximumTimeToLock(in ComponentName who, long timeMs, boolean parent);
+    long getMaximumTimeToLock(in ComponentName who, int userHandle, boolean parent);
 
-    void lockNow();
+    void lockNow(boolean parent);
 
     void wipeData(int flags);
 
@@ -91,14 +92,16 @@
     boolean getStorageEncryption(in ComponentName who, int userHandle);
     int getStorageEncryptionStatus(int userHandle);
 
+    boolean requestBugreport(in ComponentName who);
+
     void setCameraDisabled(in ComponentName who, boolean disabled);
     boolean getCameraDisabled(in ComponentName who, int userHandle);
 
     void setScreenCaptureDisabled(in ComponentName who, boolean disabled);
     boolean getScreenCaptureDisabled(in ComponentName who, int userHandle);
 
-    void setKeyguardDisabledFeatures(in ComponentName who, int which);
-    int getKeyguardDisabledFeatures(in ComponentName who, int userHandle);
+    void setKeyguardDisabledFeatures(in ComponentName who, int which, boolean parent);
+    int getKeyguardDisabledFeatures(in ComponentName who, int userHandle, boolean parent);
 
     void setActiveAdmin(in ComponentName policyReceiver, boolean refreshing, int userHandle);
     boolean isAdminActive(in ComponentName policyReceiver, int userHandle);
@@ -113,6 +116,9 @@
     void reportFailedPasswordAttempt(int userHandle);
     void reportSuccessfulPasswordAttempt(int userHandle);
 
+    void reportKeyguardDismissed();
+    void reportKeyguardSecured();
+
     boolean setDeviceOwner(in ComponentName who, String ownerName, int userId);
     ComponentName getDeviceOwnerComponent(boolean callingUserOnly);
     String getDeviceOwnerName();
@@ -144,11 +150,17 @@
     void setCertInstallerPackage(in ComponentName who, String installerPackage);
     String getCertInstallerPackage(in ComponentName who);
 
+    boolean setAlwaysOnVpnPackage(in ComponentName who, String vpnPackage);
+    String getAlwaysOnVpnPackage(in ComponentName who);
+
     void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity);
     void clearPackagePersistentPreferredActivities(in ComponentName admin, String packageName);
 
     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);
+    String getApplicationRestrictionsManagingPackage(in ComponentName admin);
+    boolean isCallerApplicationRestrictionsManagingPackage();
 
     void setRestrictionsProvider(in ComponentName who, in ComponentName provider);
     ComponentName getRestrictionsProvider(int userHandle);
@@ -171,6 +183,7 @@
 
     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);
 
@@ -199,7 +212,10 @@
     void setCrossProfileCallerIdDisabled(in ComponentName who, boolean disabled);
     boolean getCrossProfileCallerIdDisabled(in ComponentName who);
     boolean getCrossProfileCallerIdDisabledForUser(int userId);
-    void startManagedQuickContact(String lookupKey, long contactId, long directoryId, in Intent originalIntent);
+    void setCrossProfileContactsSearchDisabled(in ComponentName who, boolean disabled);
+    boolean getCrossProfileContactsSearchDisabled(in ComponentName who);
+    boolean getCrossProfileContactsSearchDisabledForUser(int userId);
+    void startManagedQuickContact(String lookupKey, long contactId, boolean isContactIdIgnored, long directoryId, in Intent originalIntent);
 
     void setBluetoothContactSharingDisabled(in ComponentName who, boolean disabled);
     boolean getBluetoothContactSharingDisabled(in ComponentName who);
@@ -217,6 +233,9 @@
     void setAutoTimeRequired(in ComponentName who, boolean required);
     boolean getAutoTimeRequired();
 
+    void setForceEphemeralUsers(in ComponentName who, boolean forceEpehemeralUsers);
+    boolean getForceEphemeralUsers(in ComponentName who);
+
     boolean isRemovingAdmin(in ComponentName adminReceiver, int userHandle);
 
     void setUserIcon(in ComponentName admin, in Bitmap icon);
@@ -241,4 +260,25 @@
     boolean isManagedProfile(in ComponentName admin);
     boolean isSystemOnlyUser(in ComponentName admin);
     String getWifiMacAddress();
+    void reboot(in ComponentName admin);
+
+    void setShortSupportMessage(in ComponentName admin, in String message);
+    String getShortSupportMessage(in ComponentName admin);
+    void setLongSupportMessage(in ComponentName admin, in String message);
+    String getLongSupportMessage(in ComponentName admin);
+
+    String getShortSupportMessageForUser(in ComponentName admin, int userHandle);
+    String getLongSupportMessageForUser(in ComponentName admin, int userHandle);
+
+    boolean isSeparateProfileChallengeAllowed(int userHandle);
+
+    void setOrganizationColor(in ComponentName admin, in int color);
+    int getOrganizationColor(in ComponentName admin);
+    int getOrganizationColorForUser(int userHandle);
+
+    int getUserProvisioningState();
+    void setUserProvisioningState(int state, int userHandle);
+
+    void setAffiliationIds(in ComponentName admin, in List<String> ids);
+    boolean isAffiliatedUser();
 }
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index aa4a631..63f1425 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -382,6 +382,28 @@
     }
 
     /**
+     * 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.
+     *
+     * @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.
+     */
+    public void onQuotaExceeded(long backupDataBytes, long quotaBytes) {
+    }
+
+    /**
      * Check whether the xml yielded any <include/> tag for the provided <code>domainToken</code>.
      * If so, perform a {@link #fullBackupFileTree} which backs up the file or recurses if the path
      * is a directory.
@@ -955,6 +977,21 @@
         public void fail(String message) {
             getHandler().post(new FailRunnable(message));
         }
+
+        @Override
+        public void doQuotaExceeded(long backupDataBytes, long quotaBytes) {
+            long ident = Binder.clearCallingIdentity();
+            try {
+                BackupAgent.this.onQuotaExceeded(backupDataBytes, quotaBytes);
+            } catch (Exception e) {
+                Log.d(TAG, "onQuotaExceeded(" + BackupAgent.this.getClass().getName() + ") threw",
+                        e);
+                throw e;
+            } finally {
+                waitForSharedPrefs();
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
     }
 
     static class FailRunnable implements Runnable {
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 8b79305..ff62b7c 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -17,13 +17,13 @@
 package android.app.backup;
 
 import android.annotation.SystemApi;
-import android.app.backup.RestoreSession;
-import android.app.backup.IBackupManager;
-import android.app.backup.IRestoreSession;
 import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
+import android.util.Pair;
 
 /**
  * The interface through which an application interacts with the Android backup service to
@@ -59,6 +59,75 @@
 public class BackupManager {
     private static final String TAG = "BackupManager";
 
+    // BackupObserver status codes
+    /**
+     * Indicates that backup succeeded.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int SUCCESS = 0;
+
+    /**
+     * Indicates that backup is either not enabled at all or
+     * backup for the package was rejected by backup service
+     * or backup transport,
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_BACKUP_NOT_ALLOWED = -2001;
+
+    /**
+     * The requested app is not installed on the device.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_PACKAGE_NOT_FOUND = -2002;
+
+    /**
+     * The transport for some reason was not in a good state and
+     * aborted the entire backup request. This is a transient
+     * failure and should not be retried immediately.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_TRANSPORT_ABORTED = BackupTransport.TRANSPORT_ERROR;
+
+    /**
+     * Returned when the transport was unable to process the
+     * backup request for a given package, for example if the
+     * transport hit a transient network failure. The remaining
+     * packages provided to {@link #requestBackup(String[], BackupObserver)}
+     * will still be attempted.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_TRANSPORT_PACKAGE_REJECTED =
+            BackupTransport.TRANSPORT_PACKAGE_REJECTED;
+
+    /**
+     * Returned when the transport reject the attempt to backup because
+     * backup data size exceeded current quota limit for this package.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_TRANSPORT_QUOTA_EXCEEDED =
+            BackupTransport.TRANSPORT_QUOTA_EXCEEDED;
+
+    /**
+     * The {@link BackupAgent} for the requested package failed for some reason
+     * and didn't provide appropriate backup data.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ERROR_AGENT_FAILURE = BackupTransport.AGENT_ERROR;
+
     private Context mContext;
     private static IBackupManager sService;
 
@@ -365,4 +434,117 @@
         }
         return 0;
     }
+
+    /**
+     * Ask the framework whether this app is eligible for backup.
+     *
+     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+     *
+     * @param packageName The name of the package.
+     * @return Whether this app is eligible for backup.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean isAppEligibleForBackup(String packageName) {
+        checkServiceBinder();
+        if (sService != null) {
+            try {
+                return sService.isAppEligibleForBackup(packageName);
+            } catch (RemoteException e) {
+                Log.e(TAG, "isAppEligibleForBackup(pkg) couldn't connect");
+            }
+        }
+        return false;
+    }
+    
+    /**
+     * Request an immediate backup, providing an observer to which results of the backup operation
+     * will be published. The Android backup system will decide for each package whether it will
+     * be full app data backup or key/value-pair-based backup.
+     *
+     * <p>If this method returns {@link BackupManager#SUCCESS}, the OS will attempt to backup all
+     * provided packages using the remote transport.
+     *
+     * @param packages List of package names to backup.
+     * @param observer The {@link BackupObserver} to receive callbacks during the backup
+     * operation.
+     * @return {@link BackupManager#SUCCESS} on success; nonzero on error.
+     * @exception  IllegalArgumentException on null or empty {@code packages} param.
+     *
+     * @hide
+     */
+    @SystemApi
+    public int requestBackup(String[] packages, BackupObserver observer) {
+        checkServiceBinder();
+        if (sService != null) {
+            try {
+                BackupObserverWrapper observerWrapper =
+                    new BackupObserverWrapper(mContext, observer);
+                return sService.requestBackup(packages, observerWrapper);
+            } catch (RemoteException e) {
+                Log.e(TAG, "requestBackup() couldn't connect");
+            }
+        }
+        return -1;
+    }
+
+    /*
+     * We wrap incoming binder calls with a private class implementation that
+     * redirects them into main-thread actions.  This serializes the backup
+     * progress callbacks nicely within the usual main-thread lifecycle pattern.
+     */
+    @SystemApi
+    private class BackupObserverWrapper extends IBackupObserver.Stub {
+        final Handler mHandler;
+        final BackupObserver mObserver;
+
+        static final int MSG_UPDATE = 1;
+        static final int MSG_RESULT = 2;
+        static final int MSG_FINISHED = 3;
+
+        BackupObserverWrapper(Context context, BackupObserver observer) {
+            mHandler = new Handler(context.getMainLooper()) {
+                @Override
+                public void handleMessage(Message msg) {
+                    switch (msg.what) {
+                        case MSG_UPDATE:
+                            Pair<String, BackupProgress> obj =
+                                (Pair<String, BackupProgress>) msg.obj;
+                            mObserver.onUpdate(obj.first, obj.second);
+                            break;
+                        case MSG_RESULT:
+                            mObserver.onResult((String)msg.obj, msg.arg1);
+                            break;
+                        case MSG_FINISHED:
+                            mObserver.backupFinished(msg.arg1);
+                            break;
+                        default:
+                            Log.w(TAG, "Unknown message: " + msg);
+                            break;
+                    }
+                }
+            };
+            mObserver = observer;
+        }
+
+        // Binder calls into this object just enqueue on the main-thread handler
+        @Override
+        public void onUpdate(String currentPackage, BackupProgress backupProgress) {
+            mHandler.sendMessage(
+                mHandler.obtainMessage(MSG_UPDATE, Pair.create(currentPackage, backupProgress)));
+        }
+
+        @Override
+        public void onResult(String currentPackage, int status) {
+            mHandler.sendMessage(
+                mHandler.obtainMessage(MSG_FINISHED, status, 0, currentPackage));
+        }
+
+        @Override
+        public void backupFinished(int status) {
+            mHandler.sendMessage(
+                mHandler.obtainMessage(MSG_FINISHED, status, 0));
+        }
+    }
 }
diff --git a/core/java/android/app/backup/BackupObserver.java b/core/java/android/app/backup/BackupObserver.java
new file mode 100644
index 0000000..0dd071e
--- /dev/null
+++ b/core/java/android/app/backup/BackupObserver.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.app.backup;
+
+import android.annotation.SystemApi;
+
+/**
+ * Callback class for receiving progress reports during a backup operation.  These
+ * methods will all be called on your application's main thread.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class BackupObserver {
+    /**
+     * This method could be called several times for packages with full data backup.
+     * It will tell how much of backup data is already saved and how much is expected.
+     *
+     * @param currentBackupPackage The name of the package that now being backuped.
+     * @param backupProgress Current progress of backup for the package.
+     */
+    public void onUpdate(String currentBackupPackage, BackupProgress backupProgress) {
+    }
+
+    /**
+     * The backup of single package has completed.  This method will be called at most one time
+     * for each package and could be not called if backup is failed before and
+     * backupFinished() is called.
+     *
+     * @param currentBackupPackage The name of the package that was backuped.
+     * @param status Zero on success; a nonzero error code if the backup operation failed.
+     */
+    public void onResult(String currentBackupPackage, int status) {
+    }
+
+    /**
+     * The backup process has completed.  This method will always be called,
+     * even if no individual package backup operations were attempted.
+     *
+     * @param status Zero on success; a nonzero error code if the backup operation
+     *   as a whole failed.
+     */
+    public void backupFinished(int status) {
+    }
+}
diff --git a/core/java/android/app/backup/BackupProgress.aidl b/core/java/android/app/backup/BackupProgress.aidl
new file mode 100644
index 0000000..c10b9a2
--- /dev/null
+++ b/core/java/android/app/backup/BackupProgress.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.app.backup;
+
+parcelable BackupProgress;
\ No newline at end of file
diff --git a/core/java/android/app/backup/BackupProgress.java b/core/java/android/app/backup/BackupProgress.java
new file mode 100644
index 0000000..32e6212
--- /dev/null
+++ b/core/java/android/app/backup/BackupProgress.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.app.backup;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Information about current progress of full data backup
+ * Used in {@link BackupObserver#onUpdate(String, BackupProgress)}
+ *
+ * @hide
+ */
+@SystemApi
+public class BackupProgress implements Parcelable {
+
+    /**
+     * Expected size of data in full backup.
+     */
+    public final long bytesExpected;
+    /**
+     * Amount of backup data that is already saved in backup.
+     */
+    public final long bytesTransferred;
+
+    public BackupProgress(long _bytesExpected, long _bytesTransferred) {
+        bytesExpected = _bytesExpected;
+        bytesTransferred = _bytesTransferred;
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeLong(bytesExpected);
+        out.writeLong(bytesTransferred);
+    }
+
+    public static final Creator<BackupProgress> CREATOR = new Creator<BackupProgress>() {
+        public BackupProgress createFromParcel(Parcel in) {
+            return new BackupProgress(in);
+        }
+
+        public BackupProgress[] newArray(int size) {
+            return new BackupProgress[size];
+        }
+    };
+
+    private BackupProgress(Parcel in) {
+        bytesExpected = in.readLong();
+        bytesTransferred = in.readLong();
+    }
+}
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index 954ccef..ac23b68 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -49,6 +49,11 @@
     public static final int TRANSPORT_PACKAGE_REJECTED = -1002;
     public static final int AGENT_ERROR = -1003;
     public static final int AGENT_UNKNOWN = -1004;
+    public static final int TRANSPORT_QUOTA_EXCEEDED = -1005;
+
+    // Indicates that operation was initiated by user, not a scheduled one.
+    // Transport should ignore its own moratoriums for call with this flag set.
+    public static final int FLAG_USER_INITIATED = 1;
 
     IBackupTransport mBinderImpl = new TransportImpl();
 
@@ -228,13 +233,10 @@
      *
      * @param packageInfo The identity of the application whose data is being backed up.
      *   This specifically includes the signature list for the package.
-     * @param data The data stream that resulted from invoking the application's
+     * @param inFd Descriptor of file with data that resulted from invoking the application's
      *   BackupService.doBackup() method.  This may be a pipe rather than a file on
      *   persistent media, so it may not be seekable.
-     * @param wipeAllFirst When true, <i>all</i> backed-up data for the current device/account
-     *   must be erased prior to the storage of the data provided here.  The purpose of this
-     *   is to provide a guarantee that no stale data exists in the restore set when the
-     *   device begins providing incremental backups.
+     * @param flags {@link BackupTransport#FLAG_USER_INITIATED} or 0.
      * @return one of {@link BackupTransport#TRANSPORT_OK} (OK so far),
      *  {@link BackupTransport#TRANSPORT_PACKAGE_REJECTED} (to suppress backup of this
      *  specific package, but allow others to proceed),
@@ -242,6 +244,14 @@
      *  {@link BackupTransport#TRANSPORT_NOT_INITIALIZED} (if the backend dataset has
      *  become lost due to inactivity purge or some other reason and needs re-initializing)
      */
+    public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd, int flags) {
+        return performBackup(packageInfo, inFd);
+    }
+
+    /**
+     * Legacy version of {@link #performBackup(PackageInfo, ParcelFileDescriptor, int)} that
+     * doesn't use flags parameter.
+     */
     public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd) {
         return BackupTransport.TRANSPORT_ERROR;
     }
@@ -392,11 +402,21 @@
      *    close this file descriptor now; otherwise it should be cached for use during
      *    succeeding calls to {@link #sendBackupData(int)}, and closed in response to
      *    {@link #finishBackup()}.
+     * @param flags {@link BackupTransport#FLAG_USER_INITIATED} or 0.
      * @return TRANSPORT_PACKAGE_REJECTED to indicate that the stated application is not
      *    to be backed up; TRANSPORT_OK to indicate that the OS may proceed with delivering
      *    backup data; TRANSPORT_ERROR to indicate a fatal error condition that precludes
      *    performing a backup at this time.
      */
+    public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket,
+            int flags) {
+        return performFullBackup(targetPackage, socket);
+    }
+
+    /**
+     * Legacy version of {@link #performFullBackup(PackageInfo, ParcelFileDescriptor, int)} that
+     * doesn't use flags parameter.
+     */
     public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket) {
         return BackupTransport.TRANSPORT_PACKAGE_REJECTED;
     }
@@ -463,6 +483,30 @@
                 "Transport cancelFullBackup() not implemented");
     }
 
+    /**
+     * Ask the transport whether this app is eligible for backup.
+     *
+     * @param targetPackage The identity of the application.
+     * @param isFullBackup If set, transport should check if app is eligible for full data backup,
+     *   otherwise to check if eligible for key-value backup.
+     * @return Whether this app is eligible for backup.
+     */
+    public boolean isAppEligibleForBackup(PackageInfo targetPackage, boolean isFullBackup) {
+        return true;
+    }
+
+    /**
+     * Ask the transport about current quota for backup size of the package.
+     *
+     * @param packageName ID of package to provide the quota.
+     * @param isFullBackup If set, transport should return limit for full data backup, otherwise
+     *                     for key-value backup.
+     * @return Current limit on full data backup size in bytes.
+     */
+    public long getBackupQuota(String packageName, boolean isFullBackup) {
+        return Long.MAX_VALUE;
+    }
+
     // ------------------------------------------------------------------------------------
     // Full restore interfaces
 
@@ -568,9 +612,9 @@
         }
 
         @Override
-        public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd)
+        public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd, int flags)
                 throws RemoteException {
-            return BackupTransport.this.performBackup(packageInfo, inFd);
+            return BackupTransport.this.performBackup(packageInfo, inFd, flags);
         }
 
         @Override
@@ -619,8 +663,9 @@
         }
 
         @Override
-        public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket) throws RemoteException {
-            return BackupTransport.this.performFullBackup(targetPackage, socket);
+        public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket,
+                int flags) throws RemoteException {
+            return BackupTransport.this.performFullBackup(targetPackage, socket, flags);
         }
 
         @Override
@@ -639,6 +684,17 @@
         }
 
         @Override
+        public boolean isAppEligibleForBackup(PackageInfo targetPackage, boolean isFullBackup)
+                throws RemoteException {
+            return BackupTransport.this.isAppEligibleForBackup(targetPackage, isFullBackup);
+        }
+
+        @Override
+        public long getBackupQuota(String packageName, boolean isFullBackup) {
+            return BackupTransport.this.getBackupQuota(packageName, isFullBackup);
+        }
+
+        @Override
         public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) {
             return BackupTransport.this.getNextFullRestoreDataChunk(socket);
         }
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index 87e4ef1..5d4cc6f 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -16,6 +16,7 @@
 
 package android.app.backup;
 
+import android.app.backup.IBackupObserver;
 import android.app.backup.IFullBackupRestoreObserver;
 import android.app.backup.IRestoreSession;
 import android.os.ParcelFileDescriptor;
@@ -326,4 +327,29 @@
      *     no suitable data is available.
      */
     long getAvailableRestoreToken(String packageName);
+
+    /**
+     * Ask the framework whether this app is eligible for backup.
+     *
+     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+     *
+     * @param packageName The name of the package.
+     * @return Whether this app is eligible for backup.
+     */
+    boolean isAppEligibleForBackup(String packageName);
+
+    /**
+     * Request an immediate backup, providing an observer to which results of the backup operation
+     * will be published. The Android backup system will decide for each package whether it will
+     * be full app data backup or key/value-pair-based backup.
+     *
+     * <p>If this method returns zero (meaning success), the OS will attempt to backup all provided
+     * packages using the remote transport.
+     *
+     * @param observer The {@link BackupObserver} to receive callbacks during the backup
+     * operation.
+     *
+     * @return Zero on success; nonzero on error.
+     */
+    int requestBackup(in String[] packages, IBackupObserver observer);
 }
diff --git a/core/java/android/app/backup/IBackupObserver.aidl b/core/java/android/app/backup/IBackupObserver.aidl
new file mode 100644
index 0000000..821a589
--- /dev/null
+++ b/core/java/android/app/backup/IBackupObserver.aidl
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.backup;
+
+import android.app.backup.BackupProgress;
+
+/**
+ * Callback class for receiving progress reports during a backup operation.  These
+ * methods will all be called on your application's main thread.
+ *
+ * @hide
+ */
+oneway interface IBackupObserver {
+    /**
+     * This method could be called several times for packages with full data backup.
+     * It will tell how much of backup data is already saved and how much is expected.
+     *
+     * @param currentBackupPackage The name of the package that now being backuped.
+     * @param backupProgress Current progress of backup for the package.
+     */
+    void onUpdate(String currentPackage, in BackupProgress backupProgress);
+
+    /**
+     * The backup of single package has completed.  This method will be called at most one time
+     * for each package and could be not called if backup is failed before and
+     * backupFinished() is called.
+     *
+     * @param currentBackupPackage The name of the package that was backuped.
+     * @param status Zero on success; a nonzero error code if the backup operation failed.
+     */
+    void onResult(String currentPackage, int status);
+
+    /**
+     * The backup process has completed.  This method will always be called,
+     * even if no individual package backup operations were attempted.
+     *
+     * @param status Zero on success; a nonzero error code if the backup operation
+     *   as a whole failed.
+     */
+    void backupFinished(int status);
+}
diff --git a/core/java/android/app/backup/RestoreSet.java b/core/java/android/app/backup/RestoreSet.java
index aacaf7c..4a6316c 100644
--- a/core/java/android/app/backup/RestoreSet.java
+++ b/core/java/android/app/backup/RestoreSet.java
@@ -58,7 +58,6 @@
         token = _token;
     }
 
-
     // Parcelable implementation
     public int describeContents() {
         return 0;
diff --git a/core/java/android/app/job/IJobScheduler.aidl b/core/java/android/app/job/IJobScheduler.aidl
index f1258ae..f0c3302 100644
--- a/core/java/android/app/job/IJobScheduler.aidl
+++ b/core/java/android/app/job/IJobScheduler.aidl
@@ -24,6 +24,7 @@
   */
 interface IJobScheduler {
     int schedule(in JobInfo job);
+    int scheduleAsPackage(in JobInfo job, String packageName, int userId);
     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 0d9e778..0143797 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -16,11 +16,16 @@
 
 package android.app.job;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.ComponentName;
+import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.PersistableBundle;
 
+import java.util.ArrayList;
+
 /**
  * Container of data passed to the {@link android.app.job.JobScheduler} fully encapsulating the
  * parameters required to schedule work against the calling application. These are constructed
@@ -64,6 +69,11 @@
      */
     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
+    /* Minimum flex for a periodic job, in milliseconds. */
+    public static final long MIN_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes
+
     /**
      * Default type of backoff.
      * @hide
@@ -75,6 +85,7 @@
     private final ComponentName service;
     private final boolean requireCharging;
     private final boolean requireDeviceIdle;
+    private final TriggerContentUri[] triggerContentUris;
     private final boolean hasEarlyConstraint;
     private final boolean hasLateConstraint;
     private final int networkType;
@@ -83,8 +94,10 @@
     private final boolean isPeriodic;
     private final boolean isPersisted;
     private final long intervalMillis;
+    private final long flexMillis;
     private final long initialBackoffMillis;
     private final int backoffPolicy;
+    private final int priority;
 
     /**
      * Unique job id associated with this class. This is assigned to your job by the scheduler.
@@ -107,6 +120,11 @@
         return service;
     }
 
+    /** @hide */
+    public int getPriority() {
+        return priority;
+    }
+
     /**
      * Whether this job needs the device to be plugged in.
      */
@@ -122,6 +140,15 @@
     }
 
     /**
+     * Which content: URIs must change for the job to be scheduled.  Returns null
+     * if there are none required.
+     */
+    @Nullable
+    public TriggerContentUri[] getTriggerContentUris() {
+        return triggerContentUris;
+    }
+
+    /**
      * One of {@link android.app.job.JobInfo#NETWORK_TYPE_ANY},
      * {@link android.app.job.JobInfo#NETWORK_TYPE_NONE}, or
      * {@link android.app.job.JobInfo#NETWORK_TYPE_UNMETERED}.
@@ -165,7 +192,17 @@
      * job does not recur periodically.
      */
     public long getIntervalMillis() {
-        return intervalMillis;
+        return intervalMillis >= MIN_PERIOD_MILLIS ? intervalMillis : MIN_PERIOD_MILLIS;
+    }
+
+    /**
+     * Flex time for this job. Only valid if this is a periodic job.
+     */
+    public long getFlexMillis() {
+        long interval = getIntervalMillis();
+        long percentClamp = 5 * interval / 100;
+        long clampedFlex = Math.max(flexMillis, Math.max(percentClamp, MIN_FLEX_MILLIS));
+        return clampedFlex <= interval ? clampedFlex : interval;
     }
 
     /**
@@ -210,16 +247,19 @@
         service = in.readParcelable(null);
         requireCharging = in.readInt() == 1;
         requireDeviceIdle = in.readInt() == 1;
+        triggerContentUris = in.createTypedArray(TriggerContentUri.CREATOR);
         networkType = in.readInt();
         minLatencyMillis = in.readLong();
         maxExecutionDelayMillis = in.readLong();
         isPeriodic = in.readInt() == 1;
         isPersisted = in.readInt() == 1;
         intervalMillis = in.readLong();
+        flexMillis = in.readLong();
         initialBackoffMillis = in.readLong();
         backoffPolicy = in.readInt();
         hasEarlyConstraint = in.readInt() == 1;
         hasLateConstraint = in.readInt() == 1;
+        priority = in.readInt();
     }
 
     private JobInfo(JobInfo.Builder b) {
@@ -228,16 +268,21 @@
         service = b.mJobService;
         requireCharging = b.mRequiresCharging;
         requireDeviceIdle = b.mRequiresDeviceIdle;
+        triggerContentUris = b.mTriggerContentUris != null
+                ? b.mTriggerContentUris.toArray(new TriggerContentUri[b.mTriggerContentUris.size()])
+                : null;
         networkType = b.mNetworkType;
         minLatencyMillis = b.mMinLatencyMillis;
         maxExecutionDelayMillis = b.mMaxExecutionDelayMillis;
         isPeriodic = b.mIsPeriodic;
         isPersisted = b.mIsPersisted;
         intervalMillis = b.mIntervalMillis;
+        flexMillis = b.mFlexMillis;
         initialBackoffMillis = b.mInitialBackoffMillis;
         backoffPolicy = b.mBackoffPolicy;
         hasEarlyConstraint = b.mHasEarlyConstraint;
         hasLateConstraint = b.mHasLateConstraint;
+        priority = b.mPriority;
     }
 
     @Override
@@ -252,16 +297,19 @@
         out.writeParcelable(service, flags);
         out.writeInt(requireCharging ? 1 : 0);
         out.writeInt(requireDeviceIdle ? 1 : 0);
+        out.writeTypedArray(triggerContentUris, flags);
         out.writeInt(networkType);
         out.writeLong(minLatencyMillis);
         out.writeLong(maxExecutionDelayMillis);
         out.writeInt(isPeriodic ? 1 : 0);
         out.writeInt(isPersisted ? 1 : 0);
         out.writeLong(intervalMillis);
+        out.writeLong(flexMillis);
         out.writeLong(initialBackoffMillis);
         out.writeInt(backoffPolicy);
         out.writeInt(hasEarlyConstraint ? 1 : 0);
         out.writeInt(hasLateConstraint ? 1 : 0);
+        out.writeInt(priority);
     }
 
     public static final Creator<JobInfo> CREATOR = new Creator<JobInfo>() {
@@ -281,15 +329,86 @@
         return "(job:" + jobId + "/" + service.flattenToShortString() + ")";
     }
 
+    /**
+     * Information about a content URI modification that a job would like to
+     * trigger on.
+     */
+    public static final class TriggerContentUri implements Parcelable {
+        private final Uri mUri;
+        private final int mFlags;
+
+        /**
+         * Flag for trigger: also trigger if any descendants of the given URI change.
+         * Corresponds to the <var>notifyForDescendants</var> of
+         * {@link android.content.ContentResolver#registerContentObserver}.
+         */
+        public static final int FLAG_NOTIFY_FOR_DESCENDANTS = 1<<0;
+
+        /**
+         * Create a new trigger description.
+         * @param uri The URI to observe.  Must be non-null.
+         * @param flags Optional flags for the observer, either 0 or
+         * {@link #FLAG_NOTIFY_FOR_DESCENDANTS}.
+         */
+        public TriggerContentUri(@NonNull Uri uri, int flags) {
+            mUri = uri;
+            mFlags = flags;
+        }
+
+        /**
+         * Return the Uri this trigger was created for.
+         */
+        public Uri getUri() {
+            return mUri;
+        }
+
+        /**
+         * Return the flags supplied for the trigger.
+         */
+        public int getFlags() {
+            return mFlags;
+        }
+
+        private TriggerContentUri(Parcel in) {
+            mUri = Uri.CREATOR.createFromParcel(in);
+            mFlags = in.readInt();
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            mUri.writeToParcel(out, flags);
+            out.writeInt(mFlags);
+        }
+
+        public static final Creator<TriggerContentUri> CREATOR = new Creator<TriggerContentUri>() {
+            @Override
+            public TriggerContentUri createFromParcel(Parcel in) {
+                return new TriggerContentUri(in);
+            }
+
+            @Override
+            public TriggerContentUri[] newArray(int size) {
+                return new TriggerContentUri[size];
+            }
+        };
+    }
+
     /** Builder class for constructing {@link JobInfo} objects. */
     public static final class Builder {
         private int mJobId;
         private PersistableBundle mExtras = PersistableBundle.EMPTY;
         private ComponentName mJobService;
+        private int mPriority;
         // Requirements.
         private boolean mRequiresCharging;
         private boolean mRequiresDeviceIdle;
         private int mNetworkType;
+        private ArrayList<TriggerContentUri> mTriggerContentUris;
         private boolean mIsPersisted;
         // One-off parameters.
         private long mMinLatencyMillis;
@@ -299,6 +418,7 @@
         private boolean mHasEarlyConstraint;
         private boolean mHasLateConstraint;
         private long mIntervalMillis;
+        private long mFlexMillis;
         // Back-off parameters.
         private long mInitialBackoffMillis = DEFAULT_INITIAL_BACKOFF_MILLIS;
         private int mBackoffPolicy = DEFAULT_BACKOFF_POLICY;
@@ -318,6 +438,14 @@
         }
 
         /**
+         * @hide
+         */
+        public Builder setPriority(int priority) {
+            mPriority = priority;
+            return this;
+        }
+
+        /**
          * Set optional extras. This is persisted, so we only allow primitive types.
          * @param extras Bundle containing extras you want the scheduler to hold on to for you.
          */
@@ -365,6 +493,25 @@
         }
 
         /**
+         * Add a new content: URI that will be monitored with a
+         * {@link android.database.ContentObserver}, and will cause the job to execute if changed.
+         * If you have any trigger content URIs associated with a job, it will not execute until
+         * there has been a change report for one or more of them.
+         * <p>Note that trigger URIs can not be used in combination with
+         * {@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>
+         * @param uri The content: URI to monitor.
+         */
+        public Builder addTriggerContentUri(@NonNull TriggerContentUri uri) {
+            if (mTriggerContentUris == null) {
+                mTriggerContentUris = new ArrayList<>();
+            }
+            mTriggerContentUris.add(uri);
+            return this;
+        }
+
+        /**
          * Specify that this job should recur with the provided interval, not more than once per
          * period. You have no control over when within this interval this job will be executed,
          * only the guarantee that it will be executed at most once within this interval.
@@ -373,8 +520,21 @@
          * @param intervalMillis Millisecond interval for which this job will repeat.
          */
         public Builder setPeriodic(long intervalMillis) {
+            return setPeriodic(intervalMillis, intervalMillis);
+        }
+
+        /**
+         * 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.
+         * @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
+         *                   higher.
+         */
+        public Builder setPeriodic(long intervalMillis, long flexMillis) {
             mIsPeriodic = true;
             mIntervalMillis = intervalMillis;
+            mFlexMillis = flexMillis;
             mHasEarlyConstraint = mHasLateConstraint = true;
             return this;
         }
@@ -447,7 +607,8 @@
         public JobInfo build() {
             // Allow jobs with no constraints - What am I, a database?
             if (!mHasEarlyConstraint && !mHasLateConstraint && !mRequiresCharging &&
-                    !mRequiresDeviceIdle && mNetworkType == NETWORK_TYPE_NONE) {
+                    !mRequiresDeviceIdle && mNetworkType == NETWORK_TYPE_NONE &&
+                    mTriggerContentUris == null) {
                 throw new IllegalArgumentException("You're trying to build a job with no " +
                         "constraints, this is not allowed.");
             }
@@ -461,6 +622,14 @@
                 throw new IllegalArgumentException("Can't call setMinimumLatency() on a " +
                         "periodic job");
             }
+            if (mIsPeriodic && (mTriggerContentUris != null)) {
+                throw new IllegalArgumentException("Can't call addTriggerContentUri() on a " +
+                        "periodic job");
+            }
+            if (mIsPersisted && (mTriggerContentUris != null)) {
+                throw new IllegalArgumentException("Can't call addTriggerContentUri() on a " +
+                        "persisted job");
+            }
             if (mBackoffPolicySet && mRequiresDeviceIdle) {
                 throw new IllegalArgumentException("An idle mode job will not respect any" +
                         " back-off policy, so calling setBackoffCriteria with" +
diff --git a/core/java/android/app/job/JobParameters.java b/core/java/android/app/job/JobParameters.java
index 7ee39f5..8b309e11 100644
--- a/core/java/android/app/job/JobParameters.java
+++ b/core/java/android/app/job/JobParameters.java
@@ -17,6 +17,7 @@
 package android.app.job;
 
 import android.app.job.IJobCallback;
+import android.net.Uri;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -28,18 +29,36 @@
  */
 public class JobParameters implements Parcelable {
 
+    /** @hide */
+    public static final int REASON_CANCELED = 0;
+    /** @hide */
+    public static final int REASON_CONSTRAINTS_NOT_SATISFIED = 1;
+    /** @hide */
+    public static final int REASON_PREEMPT = 2;
+    /** @hide */
+    public static final int REASON_TIMEOUT = 3;
+    /** @hide */
+    public static final int REASON_DEVICE_IDLE = 4;
+
     private final int jobId;
     private final PersistableBundle extras;
     private final IBinder callback;
     private final boolean overrideDeadlineExpired;
+    private final Uri[] mTriggeredContentUris;
+    private final String[] mTriggeredContentAuthorities;
+
+    private int stopReason; // Default value of stopReason is REASON_CANCELED
 
     /** @hide */
     public JobParameters(IBinder callback, int jobId, PersistableBundle extras,
-                         boolean overrideDeadlineExpired) {
+                boolean overrideDeadlineExpired, Uri[] triggeredContentUris,
+            String[] triggeredContentAuthorities) {
         this.jobId = jobId;
         this.extras = extras;
         this.callback = callback;
         this.overrideDeadlineExpired = overrideDeadlineExpired;
+        this.mTriggeredContentUris = triggeredContentUris;
+        this.mTriggeredContentAuthorities = triggeredContentAuthorities;
     }
 
     /**
@@ -50,6 +69,14 @@
     }
 
     /**
+     * Reason onStopJob() was called on this job.
+     * @hide
+     */
+    public int getStopReason() {
+        return stopReason;
+    }
+
+    /**
      * @return The extras you passed in when constructing this job with
      * {@link android.app.job.JobInfo.Builder#setExtras(android.os.PersistableBundle)}. This will
      * never be null. If you did not set any extras this will be an empty bundle.
@@ -68,6 +95,30 @@
         return overrideDeadlineExpired;
     }
 
+    /**
+     * For jobs with {@link android.app.job.JobInfo.Builder#addTriggerContentUri} set, this
+     * reports which URIs have triggered the job.  This will be null if either no URIs have
+     * triggered it (it went off due to a deadline or other reason), or the number of changed
+     * URIs is too large to report.  Whether or not the number of URIs is too large, you can
+     * always use {@link #getTriggeredContentAuthorities()} to determine whether the job was
+     * triggered due to any content changes and the authorities they are associated with.
+     */
+    public Uri[] getTriggeredContentUris() {
+        return mTriggeredContentUris;
+    }
+
+    /**
+     * For jobs with {@link android.app.job.JobInfo.Builder#addTriggerContentUri} set, this
+     * reports which content authorities have triggered the job.  It will only be null if no
+     * authorities have triggered it -- that is, the job executed for some other reason, such
+     * as a deadline expiring.  If this is non-null, you can use {@link #getTriggeredContentUris()}
+     * to retrieve the details of which URIs changed (as long as that has not exceeded the maximum
+     * number it can reported).
+     */
+    public String[] getTriggeredContentAuthorities() {
+        return mTriggeredContentAuthorities;
+    }
+
     /** @hide */
     public IJobCallback getCallback() {
         return IJobCallback.Stub.asInterface(callback);
@@ -78,6 +129,14 @@
         extras = in.readPersistableBundle();
         callback = in.readStrongBinder();
         overrideDeadlineExpired = in.readInt() == 1;
+        mTriggeredContentUris = in.createTypedArray(Uri.CREATOR);
+        mTriggeredContentAuthorities = in.createStringArray();
+        stopReason = in.readInt();
+    }
+
+    /** @hide */
+    public void setStopReason(int reason) {
+        stopReason = reason;
     }
 
     @Override
@@ -91,6 +150,9 @@
         dest.writePersistableBundle(extras);
         dest.writeStrongBinder(callback);
         dest.writeInt(overrideDeadlineExpired ? 1 : 0);
+        dest.writeTypedArray(mTriggeredContentUris, flags);
+        dest.writeStringArray(mTriggeredContentAuthorities);
+        dest.writeInt(stopReason);
     }
 
     public static final Creator<JobParameters> CREATOR = new Creator<JobParameters>() {
diff --git a/core/java/android/app/job/JobScheduler.java b/core/java/android/app/job/JobScheduler.java
index a1c11f3..5e1a4256 100644
--- a/core/java/android/app/job/JobScheduler.java
+++ b/core/java/android/app/job/JobScheduler.java
@@ -50,22 +50,30 @@
      */
     public static final int RESULT_FAILURE = 0;
     /**
-     * Returned from {@link #schedule(JobInfo)} if this application has made too many requests for
-     * work over too short a time.
+     * Returned from {@link #schedule(JobInfo)} if this job has been successfully scheduled.
      */
-    // TODO: Determine if this is necessary.
     public static final int RESULT_SUCCESS = 1;
 
     /**
      * @param job The job you wish scheduled. See
      * {@link android.app.job.JobInfo.Builder JobInfo.Builder} for more detail on the sorts of jobs
      * you can schedule.
-     * @return If >0, this int returns the jobId of the successfully scheduled job.
-     * Otherwise you have to compare the return value to the error codes defined in this class.
+     * @return An int representing ({@link #RESULT_SUCCESS} or {@link #RESULT_FAILURE}).
      */
     public abstract int schedule(JobInfo job);
 
     /**
+     *
+     * @param job The job to be scheduled.
+     * @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.
+     * @return {@link #RESULT_SUCCESS} or {@link #RESULT_FAILURE}
+     * @hide
+     */
+    public abstract int scheduleAsPackage(JobInfo job, String packageName, int userId);
+
+    /**
      * Cancel a job that is pending in the JobScheduler.
      * @param jobId unique identifier for this job. Obtain this value from the jobs returned by
      * {@link #getAllPendingJobs()}.
diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl
index a3fe6ab..d3d02e5 100644
--- a/core/java/android/app/trust/ITrustManager.aidl
+++ b/core/java/android/app/trust/ITrustManager.aidl
@@ -32,4 +32,5 @@
     void setDeviceLockedForUser(int userId, boolean locked);
     boolean isDeviceLocked(int userId);
     boolean isDeviceSecure(int userId);
+    boolean isTrustUsuallyManaged(int userId);
 }
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index ee591d3..999d826 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -16,19 +16,17 @@
 
 package android.app.trust;
 
-import android.annotation.IntDef;
+import com.android.internal.widget.LockPatternUtils;
+
+import android.Manifest;
+import android.annotation.RequiresPermission;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
-import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.Log;
-import android.util.SparseIntArray;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 
 /**
  * See {@link com.android.server.trust.TrustManagerService}
@@ -54,9 +52,12 @@
      * Changes the lock status for the given user. This is only applicable to Managed Profiles,
      * other users should be handled by Keyguard.
      *
+     * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
+     *
      * @param userId The id for the user to be locked/unlocked.
      * @param locked The value for that user's locked state.
      */
+    @RequiresPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE)
     public void setDeviceLockedForUser(int userId, boolean locked) {
         try {
             mService.setDeviceLockedForUser(userId, locked);
@@ -153,6 +154,21 @@
         }
     }
 
+    /**
+     * @return whether {@param userId} has enabled and configured trust agents. Ignores short-term
+     * unavailability of trust due to {@link LockPatternUtils.StrongAuthTracker}.
+     */
+    @RequiresPermission(android.Manifest.permission.TRUST_LISTENER)
+    public boolean isTrustUsuallyManaged(int userId) {
+        try {
+            return mService.isTrustUsuallyManaged(userId);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+
+
     private void onError(Exception e) {
         Log.e(TAG, "Error while calling TrustManagerService", e);
     }
diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java
index ef08eb9..d263646 100644
--- a/core/java/android/app/usage/NetworkStats.java
+++ b/core/java/android/app/usage/NetworkStats.java
@@ -121,12 +121,12 @@
      */
     public static class Bucket {
         /**
-         * Combined usage across all other states.
+         * Combined usage across all states.
          */
         public static final int STATE_ALL = -1;
 
         /**
-         * Usage not accounted in any other states.
+         * Usage not accounted for in any other state.
          */
         public static final int STATE_DEFAULT = 0x1;
 
@@ -150,8 +150,40 @@
          */
         public static final int UID_TETHERING = TrafficStats.UID_TETHERING;
 
+        /**
+         * Combined usage across all metering states.
+         */
+        public static final int METERING_ALL = -1;
+
+        /**
+         * Usage not accounted for in any other metering state.
+         */
+        public static final int METERING_DEFAULT = 0x1;
+
+        /**
+         * Metered usage.
+         */
+        public static final int METERING_METERED = 0x2;
+
+        /**
+         * Combined usage across all roaming states.
+         */
+        public static final int ROAMING_ALL = -1;
+
+        /**
+         * Usage not accounted for in any other roaming state.
+         */
+        public static final int ROAMING_DEFAULT = 0x1;
+
+        /**
+         * Roaming usage.
+         */
+        public static final int ROAMING_ROAMING = 0x2;
+
         private int mUid;
         private int mState;
+        private int mMetering;
+        private int mRoaming;
         private long mBeginTimeStamp;
         private long mEndTimeStamp;
         private long mRxBytes;
@@ -176,6 +208,15 @@
             return uid;
         }
 
+        private static 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;
+            }
+            return 0;
+        }
+
         public Bucket() {
         }
 
@@ -206,6 +247,30 @@
         }
 
         /**
+         * Metering state. One of the following values:<p/>
+         * <ul>
+         * <li>{@link #METERING_ALL}</li>
+         * <li>{@link #METERING_DEFAULT}</li>
+         * <li>{@link #METERING_METERED}</li>
+         * </ul>
+         */
+        public int getMetering() {
+            return mMetering;
+        }
+
+        /**
+         * Roaming state. One of the following values:<p/>
+         * <ul>
+         * <li>{@link #ROAMING_ALL}</li>
+         * <li>{@link #ROAMING_DEFAULT}</li>
+         * <li>{@link #ROAMING_ROAMING}</li>
+         * </ul>
+         */
+        public int getRoaming() {
+            return mRoaming;
+        }
+
+        /**
          * Start timestamp of the bucket's time interval. Defined in terms of "Unix time", see
          * {@link java.lang.System#currentTimeMillis}.
          * @return Start of interval.
@@ -398,6 +463,9 @@
     private void fillBucketFromSummaryEntry(Bucket bucketOut) {
         bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid);
         bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set);
+        // TODO: Implement metering tracking.
+        bucketOut.mMetering = Bucket.METERING_ALL;
+        bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming);
         bucketOut.mBeginTimeStamp = mStartTimeStamp;
         bucketOut.mEndTimeStamp = mEndTimeStamp;
         bucketOut.mRxBytes = mRecycledSummaryEntry.rxBytes;
@@ -444,6 +512,8 @@
                         mRecycledHistoryEntry);
                 bucketOut.mUid = Bucket.convertUid(getUid());
                 bucketOut.mState = Bucket.STATE_ALL;
+                bucketOut.mMetering = Bucket.METERING_ALL;
+                bucketOut.mRoaming = Bucket.ROAMING_ALL;
                 bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart;
                 bucketOut.mEndTimeStamp = mRecycledHistoryEntry.bucketStart +
                         mRecycledHistoryEntry.bucketDuration;
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 0fce7a9..1a9bf4e 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -40,21 +40,24 @@
  * {@link #querySummaryForUser} <p />
  * {@link #querySummary} <p />
  * These queries aggregate network usage across the whole interval. Therefore there will be only one
- * bucket for a particular key and state combination. In case of the user-wide and device-wide
- * summaries a single bucket containing the totalised network usage is returned.
+ * bucket for a particular key and state and roaming combination. In case of the user-wide and
+ * device-wide summaries a single bucket containing the totalised network usage is returned.
  * <h3>
  * History queries
  * </h3>
  * {@link #queryDetailsForUid} <p />
  * {@link #queryDetails} <p />
- * These queries do not aggregate over time but do aggregate over state. Therefore there can be
- * multiple buckets for a particular key but all Bucket's state is going to be
- * {@link NetworkStats.Bucket#STATE_ALL}.
+ * These queries do not aggregate over time but do aggregate over state and roaming. Therefore there
+ * can be multiple buckets for a particular key but all Bucket's state is going to be
+ * {@link NetworkStats.Bucket#STATE_ALL} and all Bucket's roaming is going to be
+ * {@link NetworkStats.Bucket#ROAMING_ALL}.
  * <p />
- * <b>NOTE:</b> Accessing stats for apps other than the calling app requires the permission
- * {@link android.Manifest.permission#PACKAGE_USAGE_STATS}, which is a system-level permission and
- * will not be granted to third-party apps. However, declaring the permission implies intention to
- * use the API and the user of the device can grant permission through the Settings application.
+ * <b>NOTE:</b> Calling {@link #querySummaryForDevice} or accessing stats for apps other than the
+ * calling app requires the permission {@link android.Manifest.permission#PACKAGE_USAGE_STATS},
+ * which is a system-level permission and will not be granted to third-party apps. However,
+ * declaring the permission implies intention to use the API and the user of the device can grant
+ * permission through the Settings application.
+ * <p />
  * Profile owner apps are automatically granted permission to query data on the profile they manage
  * (that is, for any query except {@link #querySummaryForDevice}). Device owner apps and carrier-
  * privileged apps likewise get access to usage data for all users on the device.
@@ -81,8 +84,8 @@
      * Query network usage statistics summaries. Result is summarised data usage for the whole
      * device. Result is a single Bucket aggregated over time, state and uid. This means the
      * bucket's start and end timestamp are going to be the same as the 'startTime' and 'endTime'
-     * parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid
-     * {@link NetworkStats.Bucket#UID_ALL}.
+     * parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid
+     * {@link NetworkStats.Bucket#UID_ALL}, and roaming {@link NetworkStats.Bucket#ROAMING_ALL}.
      *
      * @param networkType As defined in {@link ConnectivityManager}, e.g.
      *            {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
@@ -114,8 +117,8 @@
      * Query network usage statistics summaries. Result is summarised data usage for all uids
      * belonging to calling user. Result is a single Bucket aggregated over time, state and uid.
      * This means the bucket's start and end timestamp are going to be the same as the 'startTime'
-     * and 'endTime' parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid
-     * {@link NetworkStats.Bucket#UID_ALL}.
+     * and 'endTime' parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid
+     * {@link NetworkStats.Bucket#UID_ALL}, and roaming {@link NetworkStats.Bucket#ROAMING_ALL}.
      *
      * @param networkType As defined in {@link ConnectivityManager}, e.g.
      *            {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
@@ -146,7 +149,7 @@
     /**
      * Query network usage statistics summaries. Result filtered to include only uids belonging to
      * calling user. Result is aggregated over time, hence all buckets will have the same start and
-     * end timestamps. Not aggregated over state or uid. This means buckets' start and end
+     * end timestamps. Not aggregated over state, uid, or roaming. This means buckets' start and end
      * timestamps are going to be the same as the 'startTime' and 'endTime' parameters, state and
      * uid are going to vary.
      *
@@ -179,7 +182,8 @@
      * Query network usage statistics details. Only usable for uids belonging to calling user.
      * Result is aggregated over state but not aggregated over time. This means buckets' start and
      * end timestamps are going to be between 'startTime' and 'endTime' parameters, state is going
-     * to be {@link NetworkStats.Bucket#STATE_ALL} and uid the same as the 'uid' parameter.
+     * to be {@link NetworkStats.Bucket#STATE_ALL} and uid the same as the 'uid' parameter. roaming
+     * is going to be {@link NetworkStats.Bucket#ROAMING_ALL}.
      * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
      * interpolate across partial buckets. Since bucket length is in the order of hours, this
      * method cannot be used to measure data usage on a fine grained time scale.
@@ -215,6 +219,7 @@
      * calling user. Result is aggregated over state but not aggregated over time or uid. This means
      * buckets' start and end timestamps are going to be between 'startTime' and 'endTime'
      * parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid will vary.
+     * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}.
      * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
      * interpolate across partial buckets. Since bucket length is in the order of hours, this
      * method cannot be used to measure data usage on a fine grained time scale.
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index 0fce4e2..a88aa3125 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -165,14 +165,18 @@
                     mPackageName + "' with UsageStats for package '" + right.mPackageName + "'.");
         }
 
-        if (right.mEndTimeStamp > mEndTimeStamp) {
+        if (right.mBeginTimeStamp > mBeginTimeStamp) {
+            // The incoming UsageStat begins after this one, so use its last time used fields
+            // as the source of truth.
+            // We use the mBeginTimeStamp due to a bug where UsageStats files can overlap with
+            // regards to their mEndTimeStamp.
             mLastEvent = right.mLastEvent;
-            mEndTimeStamp = right.mEndTimeStamp;
             mLastTimeUsed = right.mLastTimeUsed;
             mBeginIdleTime = right.mBeginIdleTime;
             mLastTimeSystemUsed = right.mLastTimeSystemUsed;
         }
         mBeginTimeStamp = Math.min(mBeginTimeStamp, right.mBeginTimeStamp);
+        mEndTimeStamp = Math.max(mEndTimeStamp, right.mEndTimeStamp);
         mTotalTimeInForeground += right.mTotalTimeInForeground;
         mLaunchCount += right.mLaunchCount;
     }
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index 498ff81..b6f1567 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -19,6 +19,8 @@
 import android.content.ComponentName;
 import android.content.res.Configuration;
 
+import java.io.IOException;
+
 /**
  * UsageStatsManager local system service interface.
  *
@@ -109,4 +111,9 @@
         public abstract void onParoleStateChanged(boolean isParoleOn);
     }
 
+    /*  Backup/Restore API */
+    public abstract byte[] getBackupPayload(int user, String key);
+
+    public abstract void applyRestoredPayload(int user, String key, byte[] payload);
+
 }
diff --git a/core/java/android/auditing/SecurityLog.java b/core/java/android/auditing/SecurityLog.java
new file mode 100644
index 0000000..8d8d2f5
--- /dev/null
+++ b/core/java/android/auditing/SecurityLog.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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 attempt result (integer, 1 for successful, 0 for unsuccessful), accessible via
+     * {@link SecurityEvent#getData()}}
+     */
+    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
new file mode 100644
index 0000000..cf85894
--- /dev/null
+++ b/core/java/android/auditing/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.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)
+210008 security_keyguard_secured
diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java
old mode 100644
new mode 100755
index 2e27345..74302f2
--- a/core/java/android/bluetooth/BluetoothA2dpSink.java
+++ b/core/java/android/bluetooth/BluetoothA2dpSink.java
@@ -371,6 +371,89 @@
     }
 
     /**
+     * Set priority of the profile
+     *
+     * <p> The device should already be paired.
+     *  Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager
+     * {@link #PRIORITY_OFF},
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+     * permission.
+     *
+     * @param device Paired bluetooth device
+     * @param priority
+     * @return true if priority is set, false on error
+     * @hide
+     */
+    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, "Stack:" + 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}
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param device Bluetooth device
+     * @return priority of the device
+     * @hide
+     */
+    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, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return BluetoothProfile.PRIORITY_OFF;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return BluetoothProfile.PRIORITY_OFF;
+    }
+
+    /**
+     * Check if A2DP profile is streaming music.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param device BluetoothDevice device
+     */
+    public boolean isA2dpPlaying(BluetoothDevice device) {
+        if (mService != null && isEnabled()
+            && isValidDevice(device)) {
+            try {
+                return mService.isA2dpPlaying(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+                return false;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /**
      * Helper for converting a state to a string.
      *
      * For debug use only - strings are not internationalized.
diff --git a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java
index 834a587..e32a470 100644
--- a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java
+++ b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.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 bt stack state.Timestamp the record with system
@@ -27,11 +29,12 @@
  */
 public final class BluetoothActivityEnergyInfo implements Parcelable {
     private final long mTimestamp;
-    private final int mBluetoothStackState;
-    private final long mControllerTxTimeMs;
-    private final long mControllerRxTimeMs;
-    private final long mControllerIdleTimeMs;
-    private final long mControllerEnergyUsed;
+    private int mBluetoothStackState;
+    private long mControllerTxTimeMs;
+    private long mControllerRxTimeMs;
+    private long mControllerIdleTimeMs;
+    private long mControllerEnergyUsed;
+    private UidTraffic[] mUidTraffic;
 
     public static final int BT_STACK_STATE_INVALID = 0;
     public static final int BT_STACK_STATE_STATE_ACTIVE = 1;
@@ -48,6 +51,17 @@
         mControllerEnergyUsed = energyUsed;
     }
 
+    @SuppressWarnings("unchecked")
+    BluetoothActivityEnergyInfo(Parcel in) {
+        mTimestamp = in.readLong();
+        mBluetoothStackState = in.readInt();
+        mControllerTxTimeMs = in.readLong();
+        mControllerRxTimeMs = in.readLong();
+        mControllerIdleTimeMs = in.readLong();
+        mControllerEnergyUsed = in.readLong();
+        mUidTraffic = in.createTypedArray(UidTraffic.CREATOR);
+    }
+
     @Override
     public String toString() {
         return "BluetoothActivityEnergyInfo{"
@@ -57,26 +71,22 @@
             + " mControllerRxTimeMs=" + mControllerRxTimeMs
             + " mControllerIdleTimeMs=" + mControllerIdleTimeMs
             + " mControllerEnergyUsed=" + mControllerEnergyUsed
+            + " mUidTraffic=" + Arrays.toString(mUidTraffic)
             + " }";
     }
 
     public static final Parcelable.Creator<BluetoothActivityEnergyInfo> CREATOR =
             new Parcelable.Creator<BluetoothActivityEnergyInfo>() {
         public BluetoothActivityEnergyInfo createFromParcel(Parcel in) {
-            long timestamp = in.readLong();
-            int stackState = in.readInt();
-            long txTime = in.readLong();
-            long rxTime = in.readLong();
-            long idleTime = in.readLong();
-            long energyUsed = in.readLong();
-            return new BluetoothActivityEnergyInfo(timestamp, stackState,
-                    txTime, rxTime, idleTime, energyUsed);
+            return new BluetoothActivityEnergyInfo(in);
         }
+
         public BluetoothActivityEnergyInfo[] newArray(int size) {
             return new BluetoothActivityEnergyInfo[size];
         }
     };
 
+    @SuppressWarnings("unchecked")
     public void writeToParcel(Parcel out, int flags) {
         out.writeLong(mTimestamp);
         out.writeInt(mBluetoothStackState);
@@ -84,6 +94,7 @@
         out.writeLong(mControllerRxTimeMs);
         out.writeLong(mControllerIdleTimeMs);
         out.writeLong(mControllerEnergyUsed);
+        out.writeTypedArray(mUidTraffic, flags);
     }
 
     public int describeContents() {
@@ -133,6 +144,14 @@
         return mTimestamp;
     }
 
+    public UidTraffic[] getUidTraffic() {
+        return mUidTraffic;
+    }
+
+    public void setUidTraffic(UidTraffic[] traffic) {
+        mUidTraffic = traffic;
+    }
+
     /**
      * @return if the record is valid
      */
diff --git a/core/java/android/bluetooth/BluetoothAvrcpController.java b/core/java/android/bluetooth/BluetoothAvrcpController.java
index b53a8fc..444e429 100644
--- a/core/java/android/bluetooth/BluetoothAvrcpController.java
+++ b/core/java/android/bluetooth/BluetoothAvrcpController.java
@@ -20,6 +20,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.media.MediaMetadata;
+import android.media.session.PlaybackState;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
@@ -28,8 +30,8 @@
 import java.util.List;
 
 /**
- * This class provides the public APIs to control the Bluetooth AVRCP Controller
- * profile.
+ * This class provides the public APIs to control the Bluetooth AVRCP Controller. It currently
+ * supports player information, playback support and track metadata.
  *
  *<p>BluetoothAvrcpController is a proxy object for controlling the Bluetooth AVRCP
  * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
@@ -39,7 +41,7 @@
  */
 public final class BluetoothAvrcpController implements BluetoothProfile {
     private static final String TAG = "BluetoothAvrcpController";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final boolean VDBG = false;
 
     /**
@@ -61,7 +63,63 @@
      * receive.
      */
     public static final String ACTION_CONNECTION_STATE_CHANGED =
-        "android.bluetooth.acrcp-controller.profile.action.CONNECTION_STATE_CHANGED";
+        "android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED";
+
+    /**
+     * Intent used to broadcast the change in metadata state of playing track on the AVRCP
+     * AG.
+     *
+     * <p>This intent will have the two extras:
+     * <ul>
+     *    <li> {@link #EXTRA_METADATA} - {@link MediaMetadata} containing the current metadata.</li>
+     *    <li> {@link #EXTRA_PLAYBACK} - {@link PlaybackState} containing the current playback
+     *    state. </li>
+     * </ul>
+     */
+    public static final String ACTION_TRACK_EVENT =
+        "android.bluetooth.avrcp-controller.profile.action.TRACK_EVENT";
+
+
+    /**
+     * Intent used to broadcast the change in player application setting state on AVRCP AG.
+     *
+     * <p>This intent will have the following extras:
+     * <ul>
+     *    <li> {@link #EXTRA_PLAYER_SETTING} - {@link BluetoothAvrcpPlayerSettings} containing the
+     *    most recent player setting. </li>
+     * </ul>
+     */
+    public static final String ACTION_PLAYER_SETTING =
+        "android.bluetooth.avrcp-controller.profile.action.PLAYER_SETTING";
+
+    public static final String EXTRA_METADATA =
+            "android.bluetooth.avrcp-controller.profile.extra.METADATA";
+
+    public static final String EXTRA_PLAYBACK =
+            "android.bluetooth.avrcp-controller.profile.extra.PLAYBACK";
+
+    public static final String EXTRA_PLAYER_SETTING =
+            "android.bluetooth.avrcp-controller.profile.extra.PLAYER_SETTING";
+
+    /*
+     * KeyCoded for Pass Through Commands
+     */
+    public static final int PASS_THRU_CMD_ID_PLAY = 0x44;
+    public static final int PASS_THRU_CMD_ID_PAUSE = 0x46;
+    public static final int PASS_THRU_CMD_ID_VOL_UP = 0x41;
+    public static final int PASS_THRU_CMD_ID_VOL_DOWN = 0x42;
+    public static final int PASS_THRU_CMD_ID_STOP = 0x45;
+    public static final int PASS_THRU_CMD_ID_FF = 0x49;
+    public static final int PASS_THRU_CMD_ID_REWIND = 0x48;
+    public static final int PASS_THRU_CMD_ID_FORWARD = 0x4B;
+    public static final int PASS_THRU_CMD_ID_BACKWARD = 0x4C;
+    /* Key State Variables */
+    public static final int KEY_STATE_PRESSED = 0;
+    public static final int KEY_STATE_RELEASED = 1;
+    /* Group Navigation Key Codes */
+    public static final int PASS_THRU_CMD_ID_NEXT_GRP = 0x00;
+    public static final int PASS_THRU_CMD_ID_PREV_GRP = 0x01;
+
 
     private Context mContext;
     private ServiceListener mServiceListener;
@@ -69,33 +127,33 @@
     private BluetoothAdapter mAdapter;
 
     final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
-            new IBluetoothStateChangeCallback.Stub() {
-                public void onBluetoothStateChange(boolean up) {
-                    if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
-                    if (!up) {
-                        if (VDBG) Log.d(TAG,"Unbinding service...");
-                        synchronized (mConnection) {
-                            try {
-                                mService = null;
-                                mContext.unbindService(mConnection);
-                            } catch (Exception re) {
-                                Log.e(TAG,"",re);
-                            }
+        new IBluetoothStateChangeCallback.Stub() {
+            public void onBluetoothStateChange(boolean up) {
+                if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+                if (!up) {
+                    if (VDBG) Log.d(TAG,"Unbinding service...");
+                    synchronized (mConnection) {
+                        try {
+                            mService = null;
+                            mContext.unbindService(mConnection);
+                        } catch (Exception re) {
+                            Log.e(TAG,"",re);
                         }
-                    } else {
-                        synchronized (mConnection) {
-                            try {
-                                if (mService == null) {
-                                    if (VDBG) Log.d(TAG,"Binding service...");
-                                    doBind();
-                                }
-                            } catch (Exception re) {
-                                Log.e(TAG,"",re);
+                    }
+                } else {
+                    synchronized (mConnection) {
+                        try {
+                            if (mService == null) {
+                                if (VDBG) Log.d(TAG,"Binding service...");
+                                doBind();
                             }
+                        } catch (Exception re) {
+                            Log.e(TAG,"",re);
                         }
                     }
                 }
-        };
+            }
+      };
 
     /**
      * Create a BluetoothAvrcpController proxy object for interacting with the local
@@ -223,6 +281,104 @@
         if (mService == null) Log.w(TAG, "Proxy not attached to service");
     }
 
+    /**
+     * Gets the player application settings.
+     *
+     * @return the {@link BluetoothAvrcpPlayerSettings} or {@link null} if there is an error.
+     */
+    public BluetoothAvrcpPlayerSettings getPlayerSettings(BluetoothDevice device) {
+        if (DBG) Log.d(TAG, "getPlayerSettings");
+        BluetoothAvrcpPlayerSettings settings = null;
+        if (mService != null && isEnabled()) {
+            try {
+                settings = mService.getPlayerSettings(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error talking to BT service in getMetadata() " + e);
+                return null;
+            }
+        }
+        return settings;
+    }
+
+    /**
+     * Gets the metadata for the current track.
+     *
+     * This should be usually called when application UI needs to be updated, eg. when the track
+     * changes or immediately after connecting and getting the current state.
+     * @return the {@link MediaMetadata} or {@link null} if there is an error.
+     */
+    public MediaMetadata getMetadata(BluetoothDevice device) {
+        if (DBG) Log.d(TAG, "getMetadata");
+        MediaMetadata metadata = null;
+        if (mService != null && isEnabled()) {
+            try {
+                metadata = mService.getMetadata(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error talking to BT service in getMetadata() " + e);
+                return null;
+            }
+        }
+        return metadata;
+    }
+
+    /**
+     * Gets the playback state for current track.
+     *
+     * When the application is first connecting it can use current track state to get playback info.
+     * For all further updates it should listen to notifications.
+     * @return the {@link PlaybackState} or {@link null} if there is an error.
+     */
+    public PlaybackState getPlaybackState(BluetoothDevice device) {
+        if (DBG) Log.d(TAG, "getPlaybackState");
+        PlaybackState playbackState = null;
+        if (mService != null && isEnabled()) {
+            try {
+                playbackState = mService.getPlaybackState(device);
+            } catch (RemoteException e) {
+                Log.e(TAG,
+                    "Error talking to BT service in getPlaybackState() " + e);
+                return null;
+            }
+        }
+        return playbackState;
+    }
+
+    /**
+     * Sets the player app setting for current player.
+     * returns true in case setting is supported by remote, false otherwise
+     */
+    public boolean setPlayerApplicationSetting(BluetoothAvrcpPlayerSettings plAppSetting) {
+        if (DBG) Log.d(TAG, "setPlayerApplicationSetting");
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.setPlayerApplicationSetting(plAppSetting);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error talking to BT service in setPlayerApplicationSetting() " + e);
+                return false;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+        return false;
+    }
+
+    /*
+     * Send Group Navigation Command to Remote.
+     * possible keycode values: next_grp, previous_grp defined above
+     */
+    public void sendGroupNavigationCmd(BluetoothDevice device, int keyCode, int keyState) {
+        Log.d(TAG, "sendGroupNavigationCmd dev = " + device + " key " + keyCode + " State = " + keyState);
+        if (mService != null && isEnabled()) {
+            try {
+                mService.sendGroupNavigationCmd(device, keyCode, keyState);
+                return;
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error talking to BT service in sendGroupNavigationCmd()", e);
+                return;
+            }
+        }
+        if (mService == null) Log.w(TAG, "Proxy not attached to service");
+    }
+
     private final ServiceConnection mConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) Log.d(TAG, "Proxy object connected");
diff --git a/core/java/android/bluetooth/BluetoothAvrcpPlayerSettings.aidl b/core/java/android/bluetooth/BluetoothAvrcpPlayerSettings.aidl
new file mode 100644
index 0000000..590fd63
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAvrcpPlayerSettings.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothAvrcpPlayerSettings;
diff --git a/core/java/android/bluetooth/BluetoothAvrcpPlayerSettings.java b/core/java/android/bluetooth/BluetoothAvrcpPlayerSettings.java
new file mode 100644
index 0000000..927cb56
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAvrcpPlayerSettings.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Class used to identify settings associated with the player on AG.
+ *
+ * {@hide}
+ */
+public final class BluetoothAvrcpPlayerSettings implements Parcelable {
+    public static final String TAG = "BluetoothAvrcpPlayerSettings";
+
+    /**
+     * Equalizer setting.
+     */
+    public static final int SETTING_EQUALIZER    = 0x01;
+
+    /**
+     * Repeat setting.
+     */
+    public static final int SETTING_REPEAT       = 0x02;
+
+    /**
+     * Shuffle setting.
+     */
+    public static final int SETTING_SHUFFLE      = 0x04;
+
+    /**
+     * Scan mode setting.
+     */
+    public static final int SETTING_SCAN         = 0x08;
+
+    /**
+     * Invalid state.
+     *
+     * Used for returning error codes.
+     */
+    public static final int STATE_INVALID = -1;
+
+    /**
+     * OFF state.
+     *
+     * Denotes a general OFF state. Applies to all settings.
+     */
+    public static final int STATE_OFF = 0x00;
+
+    /**
+     * ON state.
+     *
+     * Applies to {@link SETTING_EQUALIZER}.
+     */
+    public static final int STATE_ON = 0x01;
+
+    /**
+     * Single track repeat.
+     *
+     * Applies only to {@link SETTING_REPEAT}.
+     */
+    public static final int STATE_SINGLE_TRACK = 0x02;
+
+    /**
+     * All track repeat/shuffle.
+     *
+     * Applies to {@link SETTING_REPEAT}, {@link SETTING_SHUFFLE} and {@link SETTING_SCAN}.
+     */
+    public static final int STATE_ALL_TRACK    = 0x03;
+
+    /**
+     * Group repeat/shuffle.
+     *
+     * Applies to {@link SETTING_REPEAT}, {@link SETTING_SHUFFLE} and {@link SETTING_SCAN}.
+     */
+    public static final int STATE_GROUP        = 0x04;
+
+    /**
+     * List of supported settings ORed.
+     */
+    private int mSettings;
+
+    /**
+     * Hash map of current capability values.
+     */
+    private Map<Integer, Integer> mSettingsValue = new HashMap<Integer, Integer>();
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mSettings);
+        out.writeInt(mSettingsValue.size());
+        for (int k : mSettingsValue.keySet()) {
+            out.writeInt(k);
+            out.writeInt(mSettingsValue.get(k));
+        }
+    }
+
+    public static final Parcelable.Creator<BluetoothAvrcpPlayerSettings> CREATOR
+            = new Parcelable.Creator<BluetoothAvrcpPlayerSettings>() {
+        public BluetoothAvrcpPlayerSettings createFromParcel(Parcel in) {
+            return new BluetoothAvrcpPlayerSettings(in);
+        }
+
+        public BluetoothAvrcpPlayerSettings[] newArray(int size) {
+            return new BluetoothAvrcpPlayerSettings[size];
+        }
+    };
+
+    private BluetoothAvrcpPlayerSettings(Parcel in) {
+        mSettings = in.readInt();
+        int numSettings = in.readInt();
+        for (int i = 0; i < numSettings; i++) {
+            mSettingsValue.put(in.readInt(), in.readInt());
+        }
+    }
+
+    /**
+     * Create a new player settings object.
+     *
+     * @param settings a ORed value of SETTINGS_* defined above.
+     */
+    public BluetoothAvrcpPlayerSettings(int settings) {
+        mSettings = settings;
+    }
+
+    /**
+     * Get the supported settings.
+     *
+     * @return int ORed value of supported settings.
+     */
+    public int getSettings() {
+        return mSettings;
+    }
+
+    /**
+     * Add a setting value.
+     *
+     * The setting must be part of possible settings in {@link getSettings()}.
+     * @param setting setting config.
+     * @param value value for the setting.
+     * @throws IllegalStateException if the setting is not supported.
+     */
+    public void addSettingValue(int setting, int value) {
+        if ((setting & mSettings) == 0) {
+            Log.e(TAG, "Setting not supported: " + setting + " " + mSettings);
+            throw new IllegalStateException("Setting not supported: " + setting);
+        }
+        mSettingsValue.put(setting, value);
+    }
+
+    /**
+     * Get a setting value.
+     *
+     * The setting must be part of possible settings in {@link getSettings()}.
+     * @param setting setting config.
+     * @return value value for the setting.
+     * @throws IllegalStateException if the setting is not supported.
+     */
+    public int getSettingValue(int setting) {
+        if ((setting & mSettings) == 0) {
+            Log.e(TAG, "Setting not supported: " + setting + " " + mSettings);
+            throw new IllegalStateException("Setting not supported: " + setting);
+        }
+        Integer i = mSettingsValue.get(setting);
+        if (i == null) return -1;
+        return i;
+    }
+}
diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java
old mode 100644
new mode 100755
index 54bf4af..4a38287
--- a/core/java/android/bluetooth/BluetoothClass.java
+++ b/core/java/android/bluetooth/BluetoothClass.java
@@ -283,6 +283,8 @@
     public static final int PROFILE_PANU = 4;
     /** @hide */
     public static final int PROFILE_NAP = 5;
+    /** @hide */
+    public static final int PROFILE_A2DP_SINK = 6;
 
     /**
      * Check class bits for possible bluetooth profile support.
@@ -310,6 +312,21 @@
                 default:
                     return false;
             }
+        } else if (profile == PROFILE_A2DP_SINK) {
+            if (hasService(Service.CAPTURE)) {
+                return true;
+            }
+            // By the A2DP spec, srcs must indicate the CAPTURE service.
+            // However if some device that do not, we try to
+            // match on some other class bits.
+            switch (getDeviceClass()) {
+                case Device.AUDIO_VIDEO_HIFI_AUDIO:
+                case Device.AUDIO_VIDEO_SET_TOP_BOX:
+                case Device.AUDIO_VIDEO_VCR :
+                    return true;
+                default:
+                    return false;
+            }
         } else if (profile == PROFILE_HEADSET) {
             // The render service class is required by the spec for HFP, so is a
             // pretty good signal
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index cd5c205..f43fb30 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -879,18 +879,16 @@
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
      *
-     * @param hash - Simple Secure pairing hash
-     * @param randomizer - The random key obtained using OOB
+     * @param transport - Transport to use
+     * @param oobData - Out Of Band data
      * @return false on immediate error, true if bonding will begin
      *
      * @hide
      */
-    public boolean createBondOutOfBand(byte[] hash, byte[] randomizer) {
-        //TODO(BT)
-        /*
+    public boolean createBondOutOfBand(int transport, OobData oobData) {
         try {
-            return sService.createBondOutOfBand(this, hash, randomizer);
-        } catch (RemoteException e) {Log.e(TAG, "", e);}*/
+            return sService.createBondOutOfBand(this, transport, oobData);
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
         return false;
     }
 
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
index 1fb7825..c73bc3c 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
@@ -19,6 +19,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.UUID;
+
 /**
  * This class represents a single call, its state and properties.
  * It implements {@link Parcelable} for inter-process message passing.
@@ -67,14 +69,21 @@
     private String mNumber;
     private boolean mMultiParty;
     private final boolean mOutgoing;
+    private final UUID mUUID;
 
     /**
      * Creates BluetoothHeadsetClientCall instance.
      */
     public BluetoothHeadsetClientCall(BluetoothDevice device, int id, int state, String number,
             boolean multiParty, boolean outgoing) {
+        this(device, id, UUID.randomUUID(), state, number, multiParty, outgoing);
+    }
+
+    public BluetoothHeadsetClientCall(BluetoothDevice device, int id, UUID uuid, int state,
+            String number, boolean multiParty, boolean outgoing) {
         mDevice = device;
         mId = id;
+        mUUID = uuid;
         mState = state;
         mNumber = number != null ? number : "";
         mMultiParty = multiParty;
@@ -134,6 +143,16 @@
     }
 
     /**
+     * Gets call's UUID.
+     *
+     * @return call uuid
+     * @hide
+     */
+    public UUID getUUID() {
+        return mUUID;
+    }
+
+    /**
      * Gets call's current state.
      *
      * @return state of this particular phone call.
@@ -177,9 +196,11 @@
 
     public String toString(boolean loggable) {
         StringBuilder builder = new StringBuilder("BluetoothHeadsetClientCall{mDevice: ");
-        builder.append(loggable ? mDevice.hashCode() : mDevice);
+        builder.append(loggable ? mDevice : mDevice.hashCode());
         builder.append(", mId: ");
         builder.append(mId);
+        builder.append(", mUUID: ");
+        builder.append(mUUID);
         builder.append(", mState: ");
         switch (mState) {
             case CALL_STATE_ACTIVE: builder.append("ACTIVE"); break;
@@ -193,7 +214,7 @@
             default: builder.append(mState); break;
         }
         builder.append(", mNumber: ");
-        builder.append(loggable ? mNumber.hashCode() : mNumber);
+        builder.append(loggable ? mNumber : mNumber.hashCode());
         builder.append(", mMultiParty: ");
         builder.append(mMultiParty);
         builder.append(", mOutgoing: ");
@@ -210,8 +231,8 @@
                 @Override
                 public BluetoothHeadsetClientCall createFromParcel(Parcel in) {
                     return new BluetoothHeadsetClientCall((BluetoothDevice)in.readParcelable(null),
-                            in.readInt(), in.readInt(), in.readString(),
-                            in.readInt() == 1, in.readInt() == 1);
+                            in.readInt(), UUID.fromString(in.readString()), in.readInt(),
+                            in.readString(), in.readInt() == 1, in.readInt() == 1);
                 }
 
                 @Override
@@ -224,6 +245,7 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeParcelable(mDevice, 0);
         out.writeInt(mId);
+        out.writeString(mUUID.toString());
         out.writeInt(mState);
         out.writeString(mNumber);
         out.writeInt(mMultiParty ? 1 : 0);
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 66f3418..9cd7d05 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -20,6 +20,7 @@
 import android.bluetooth.IBluetoothStateChangeCallback;
 import android.bluetooth.BluetoothActivityEnergyInfo;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.OobData;
 import android.os.ParcelUuid;
 import android.os.ParcelFileDescriptor;
 
@@ -56,6 +57,7 @@
 
     BluetoothDevice[] getBondedDevices();
     boolean createBond(in BluetoothDevice device, in int transport);
+    boolean createBondOutOfBand(in BluetoothDevice device, in int transport, in OobData oobData);
     boolean cancelBondProcess(in BluetoothDevice device);
     boolean removeBond(in BluetoothDevice device);
     int getBondState(in BluetoothDevice device);
@@ -102,8 +104,6 @@
     void getActivityEnergyInfoFromController();
     BluetoothActivityEnergyInfo reportActivityInfo();
 
-    // For dumpsys support
-    void dump(in ParcelFileDescriptor fd);
     void onLeServiceUp();
     void onBrEdrDown();
 }
diff --git a/core/java/android/bluetooth/IBluetoothA2dpSink.aidl b/core/java/android/bluetooth/IBluetoothA2dpSink.aidl
old mode 100644
new mode 100755
index b7c6476..d1458246
--- a/core/java/android/bluetooth/IBluetoothA2dpSink.aidl
+++ b/core/java/android/bluetooth/IBluetoothA2dpSink.aidl
@@ -31,4 +31,7 @@
     List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
     int getConnectionState(in BluetoothDevice device);
     BluetoothAudioConfig getAudioConfig(in BluetoothDevice device);
+    boolean setPriority(in BluetoothDevice device, int priority);
+    int getPriority(in BluetoothDevice device);
+    boolean isA2dpPlaying(in BluetoothDevice device);
 }
diff --git a/core/java/android/bluetooth/IBluetoothAvrcpController.aidl b/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
index f917a50..f1288d0 100644
--- a/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
+++ b/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
@@ -16,7 +16,10 @@
 
 package android.bluetooth;
 
+import android.bluetooth.BluetoothAvrcpPlayerSettings;
 import android.bluetooth.BluetoothDevice;
+import android.media.MediaMetadata;
+import android.media.session.PlaybackState;
 
 /**
  * APIs for Bluetooth AVRCP controller service
@@ -28,4 +31,9 @@
     List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
     int getConnectionState(in BluetoothDevice device);
     void sendPassThroughCmd(in BluetoothDevice device, int keyCode, int keyState);
+    BluetoothAvrcpPlayerSettings getPlayerSettings(in BluetoothDevice device);
+    MediaMetadata getMetadata(in BluetoothDevice device);
+    PlaybackState getPlaybackState(in BluetoothDevice device);
+    boolean setPlayerApplicationSetting(in BluetoothAvrcpPlayerSettings plAppSetting);
+    void sendGroupNavigationCmd(in BluetoothDevice device, int keyCode, int keyState);
 }
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 3660be7..6b5f77f 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -23,6 +23,7 @@
 import android.bluetooth.le.ScanSettings;
 import android.bluetooth.le.ResultStorageDescriptor;
 import android.os.ParcelUuid;
+import android.os.WorkSource;
 
 import android.bluetooth.IBluetoothGattCallback;
 import android.bluetooth.IBluetoothGattServerCallback;
@@ -35,8 +36,8 @@
     List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
 
     void startScan(in int appIf, in boolean isServer, in ScanSettings settings,
-                   in List<ScanFilter> filters,
-                   in List scanStorages, in String callingPackage);
+                   in List<ScanFilter> filters, in WorkSource workSource, in List scanStorages,
+                   in String callingPackage);
     void stopScan(in int appIf, in boolean isServer);
     void flushPendingBatchResults(in int appIf, in boolean isServer);
     void startMultiAdvertising(in int appIf,
diff --git a/core/java/android/bluetooth/OobData.aidl b/core/java/android/bluetooth/OobData.aidl
new file mode 100644
index 0000000..d831c64
--- /dev/null
+++ b/core/java/android/bluetooth/OobData.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 OobData;
diff --git a/core/java/android/bluetooth/OobData.java b/core/java/android/bluetooth/OobData.java
new file mode 100644
index 0000000..01f72ef
--- /dev/null
+++ b/core/java/android/bluetooth/OobData.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 android.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import android.util.Log;
+
+/**
+ * Out Of Band Data for Bluetooth device.
+ */
+public class OobData implements Parcelable {
+    private byte[] securityManagerTk;
+
+    public byte[] getSecurityManagerTk() {
+        return securityManagerTk;
+    }
+
+    public void setSecurityManagerTk(byte[] securityManagerTk) {
+        this.securityManagerTk = securityManagerTk;
+    }
+
+    public OobData() { }
+
+    private OobData(Parcel in) {
+        securityManagerTk = in.createByteArray();
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeByteArray(securityManagerTk);
+    }
+
+    public static final Parcelable.Creator<OobData> CREATOR
+            = new Parcelable.Creator<OobData>() {
+        public OobData createFromParcel(Parcel in) {
+            return new OobData(in);
+        }
+
+        public OobData[] newArray(int size) {
+            return new OobData[size];
+        }
+    };
+}
\ No newline at end of file
diff --git a/core/java/android/bluetooth/UidTraffic.java b/core/java/android/bluetooth/UidTraffic.java
new file mode 100644
index 0000000..78013cc
--- /dev/null
+++ b/core/java/android/bluetooth/UidTraffic.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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;
+
+/**
+ * Record of data traffic (in bytes) by an application identified by its UID.
+ * @hide
+ */
+public class UidTraffic implements Cloneable, Parcelable {
+    private final int mAppUid;
+    private long mRxBytes;
+    private long mTxBytes;
+
+    public UidTraffic(int appUid) {
+        mAppUid = appUid;
+    }
+
+    public UidTraffic(int appUid, long rx, long tx) {
+        mAppUid = appUid;
+        mRxBytes = rx;
+        mTxBytes = tx;
+    }
+
+    UidTraffic(Parcel in) {
+        mAppUid = in.readInt();
+        mRxBytes = in.readLong();
+        mTxBytes = in.readLong();
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mAppUid);
+        dest.writeLong(mRxBytes);
+        dest.writeLong(mTxBytes);
+    }
+
+    public void setRxBytes(long bytes) {
+        mRxBytes = bytes;
+    }
+
+    public void setTxBytes(long bytes) {
+        mTxBytes = bytes;
+    }
+
+    public void addRxBytes(long bytes) {
+        mRxBytes += bytes;
+    }
+
+    public void addTxBytes(long bytes) {
+        mTxBytes += bytes;
+    }
+
+    public int getUid() {
+        return mAppUid;
+    }
+
+    public long getRxBytes() {
+        return mRxBytes;
+    }
+
+    public long getTxBytes() {
+        return mTxBytes;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public UidTraffic clone() {
+        return new UidTraffic(mAppUid, mRxBytes, mTxBytes);
+    }
+
+    @Override
+    public String toString() {
+        return "UidTraffic{" +
+                "mAppUid=" + mAppUid +
+                ", mRxBytes=" + mRxBytes +
+                ", mTxBytes=" + mTxBytes +
+                '}';
+    }
+
+    public static final Creator<UidTraffic> CREATOR = new Creator<UidTraffic>() {
+        @Override
+        public UidTraffic createFromParcel(Parcel source) {
+            return new UidTraffic(source);
+        }
+
+        @Override
+        public UidTraffic[] newArray(int size) {
+            return new UidTraffic[size];
+        }
+    };
+}
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index 2ba87744..03449cc 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -29,6 +29,7 @@
 import android.os.Looper;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
+import android.os.WorkSource;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -89,9 +90,6 @@
      */
     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     public void startScan(final ScanCallback callback) {
-        if (callback == null) {
-            throw new IllegalArgumentException("callback is null");
-        }
         startScan(null, new ScanSettings.Builder().build(), callback);
     }
 
@@ -112,14 +110,53 @@
     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     public void startScan(List<ScanFilter> filters, ScanSettings settings,
             final ScanCallback callback) {
-        startScan(filters, settings, callback, null);
+        startScan(filters, settings, null, callback, null);
+    }
+
+    /**
+     * Start Bluetooth LE scan. Same as {@link #startScan(ScanCallback)} but allows the caller to
+     * specify on behalf of which application(s) the work is being done.
+     *
+     * @param workSource {@link WorkSource} identifying the application(s) for which to blame for
+     *                   the scan.
+     * @param callback Callback used to deliver scan results.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(allOf = {
+            Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.UPDATE_DEVICE_STATS })
+    public void startScanFromSource(final WorkSource workSource, final ScanCallback callback) {
+        startScanFromSource(null, new ScanSettings.Builder().build(), workSource, callback);
+    }
+
+    /**
+     * Start Bluetooth LE scan. Same as {@link #startScan(List, ScanSettings, ScanCallback)} but
+     * allows the caller to specify on behalf of which application(s) the work is being done.
+     *
+     * @param filters {@link ScanFilter}s for finding exact BLE devices.
+     * @param settings Settings for the scan.
+     * @param workSource {@link WorkSource} identifying the application(s) for which to blame for
+     *                   the scan.
+     * @param callback Callback used to deliver scan results.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(allOf = {
+            Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.UPDATE_DEVICE_STATS })
+    public void startScanFromSource(List<ScanFilter> filters, ScanSettings settings,
+                                    final WorkSource workSource, final ScanCallback callback) {
+        startScan(filters, settings, workSource, callback, null);
     }
 
     private void startScan(List<ScanFilter> filters, ScanSettings settings,
-            final ScanCallback callback, List<List<ResultStorageDescriptor>> resultStorages) {
+                           final WorkSource workSource, final ScanCallback callback,
+                           List<List<ResultStorageDescriptor>> resultStorages) {
         BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
-        if (settings == null || callback == null) {
-            throw new IllegalArgumentException("settings or callback is null");
+        if (callback == null) {
+            throw new IllegalArgumentException("callback is null");
+        }
+        if (settings == null) {
+            throw new IllegalArgumentException("settings is null");
         }
         synchronized (mLeScanClients) {
             if (mLeScanClients.containsKey(callback)) {
@@ -152,7 +189,7 @@
                 return;
             }
             BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(gatt, filters,
-                    settings, callback, resultStorages);
+                    settings, workSource, callback, resultStorages);
             wrapper.startRegisteration();
         }
     }
@@ -215,7 +252,7 @@
             scanFilters.add(filter.getFilter());
             scanStorages.add(filter.getStorageDescriptors());
         }
-        startScan(scanFilters, settings, callback, scanStorages);
+        startScan(scanFilters, settings, null, callback, scanStorages);
     }
 
     /**
@@ -235,6 +272,7 @@
 
         private final ScanCallback mScanCallback;
         private final List<ScanFilter> mFilters;
+        private final WorkSource mWorkSource;
         private ScanSettings mSettings;
         private IBluetoothGatt mBluetoothGatt;
         private List<List<ResultStorageDescriptor>> mResultStorages;
@@ -246,10 +284,12 @@
 
         public BleScanCallbackWrapper(IBluetoothGatt bluetoothGatt,
                 List<ScanFilter> filters, ScanSettings settings,
-                ScanCallback scanCallback, List<List<ResultStorageDescriptor>> resultStorages) {
+                WorkSource workSource, ScanCallback scanCallback,
+                List<List<ResultStorageDescriptor>> resultStorages) {
             mBluetoothGatt = bluetoothGatt;
             mFilters = filters;
             mSettings = settings;
+            mWorkSource = workSource;
             mScanCallback = scanCallback;
             mClientIf = 0;
             mResultStorages = resultStorages;
@@ -322,7 +362,9 @@
                     mClientIf = clientIf;
                     try {
                         mBluetoothGatt.startScan(mClientIf, false, mSettings, mFilters,
-                                mResultStorages, ActivityThread.currentOpPackageName());
+                                mWorkSource, mResultStorages,
+                                ActivityThread.currentOpPackageName());
+
                     } catch (RemoteException e) {
                         Log.e(TAG, "fail to start le scan: " + e);
                         mClientIf = -1;
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index c934e8d..6dfefac 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -17,11 +17,14 @@
 package android.content;
 
 import static android.content.ContentProvider.maybeAddUserId;
+
+import android.content.pm.PackageManager;
 import android.content.res.AssetFileDescriptor;
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.Process;
 import android.os.StrictMode;
 import android.text.Html;
 import android.text.Spannable;
@@ -36,6 +39,7 @@
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Representation of a clipped data on the clipboard.
@@ -461,7 +465,12 @@
                 // Check to see what data representations the content
                 // provider supports.  We would like HTML text, but if that
                 // is not possible we'll live with plan text.
-                String[] types = context.getContentResolver().getStreamTypes(mUri, "text/*");
+                String[] types = null;
+                try {
+                    types = context.getContentResolver().getStreamTypes(mUri, "text/*");
+                } catch (SecurityException e) {
+                    // No read permission for mUri, assume empty stream types list.
+                }
                 boolean hasHtml = false;
                 boolean hasText = false;
                 if (types != null) {
@@ -914,6 +923,27 @@
         }
     }
 
+    /** @hide */
+    public void collectUris(List<Uri> out) {
+        for (int i = 0; i < mItems.size(); ++i) {
+            ClipData.Item item = getItemAt(i);
+
+            if (item.getUri() != null) {
+                out.add(item.getUri());
+            }
+
+            Intent intent = item.getIntent();
+            if (intent != null) {
+                if (intent.getData() != null) {
+                    out.add(intent.getData());
+                }
+                if (intent.getClipData() != null) {
+                    intent.getClipData().collectUris(out);
+                }
+            }
+        }
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index d12595f..4135487 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.res.AssetFileDescriptor;
+import android.database.CrossProcessCursorWrapper;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
@@ -32,27 +33,34 @@
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
 import dalvik.system.CloseGuard;
 
 import java.io.FileNotFoundException;
 import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
- * The public interface object used to interact with a {@link ContentProvider}. This is obtained by
- * calling {@link ContentResolver#acquireContentProviderClient}. This object must be released
- * using {@link #release} in order to indicate to the system that the {@link ContentProvider} is
- * no longer needed and can be killed to free up resources.
- *
- * <p>Note that you should generally create a new ContentProviderClient instance
- * for each thread that will be performing operations.  Unlike
+ * The public interface object used to interact with a specific
+ * {@link ContentProvider}.
+ * <p>
+ * Instances can be obtained by calling
+ * {@link ContentResolver#acquireContentProviderClient} or
+ * {@link ContentResolver#acquireUnstableContentProviderClient}. Instances must
+ * be released using {@link #close()} in order to indicate to the system that
+ * the underlying {@link ContentProvider} is no longer needed and can be killed
+ * to free up resources.
+ * <p>
+ * Note that you should generally create a new ContentProviderClient instance
+ * for each thread that will be performing operations. Unlike
  * {@link ContentResolver}, the methods here such as {@link #query} and
- * {@link #openFile} are not thread safe -- you must not call
- * {@link #release()} on the ContentProviderClient those calls are made from
- * until you are finished with the data they have returned.
+ * {@link #openFile} are not thread safe -- you must not call {@link #close()}
+ * on the ContentProviderClient those calls are made from until you are finished
+ * with the data they have returned.
  */
-public class ContentProviderClient {
+public class ContentProviderClient implements AutoCloseable {
     private static final String TAG = "ContentProviderClient";
 
     @GuardedBy("ContentProviderClient.class")
@@ -63,22 +71,23 @@
     private final String mPackageName;
     private final boolean mStable;
 
-    private final CloseGuard mGuard = CloseGuard.get();
+    private final AtomicBoolean mClosed = new AtomicBoolean();
+    private final CloseGuard mCloseGuard = CloseGuard.get();
 
     private long mAnrTimeout;
     private NotRespondingRunnable mAnrRunnable;
 
-    private boolean mReleased;
-
     /** {@hide} */
-    ContentProviderClient(
+    @VisibleForTesting
+    public ContentProviderClient(
             ContentResolver contentResolver, IContentProvider contentProvider, boolean stable) {
         mContentResolver = contentResolver;
         mContentProvider = contentProvider;
         mPackageName = contentResolver.mPackageName;
+
         mStable = stable;
 
-        mGuard.open("release");
+        mCloseGuard.open("close");
     }
 
     /** {@hide} */
@@ -133,8 +142,19 @@
                 remoteCancellationSignal = mContentProvider.createCancellationSignal();
                 cancellationSignal.setRemote(remoteCancellationSignal);
             }
-            return mContentProvider.query(mPackageName, url, projection, selection, selectionArgs,
-                    sortOrder, remoteCancellationSignal);
+            final Cursor cursor = mContentProvider.query(mPackageName, url, projection, selection,
+                    selectionArgs, sortOrder, remoteCancellationSignal);
+            if (cursor == null) {
+                return null;
+            }
+
+            if ("com.google.android.gms".equals(mPackageName)
+                    || "com.google.android.syncadapters.contacts".equals(mPackageName)) {
+                // They're casting to a concrete subclass, sigh
+                return cursor;
+            } else {
+                return new CursorWrapperInner(cursor);
+            }
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -446,29 +466,42 @@
     }
 
     /**
-     * Call this to indicate to the system that the associated {@link ContentProvider} is no
-     * longer needed by this {@link ContentProviderClient}.
-     * @return true if this was release, false if it was already released
+     * Closes this client connection, indicating to the system that the
+     * underlying {@link ContentProvider} is no longer needed.
      */
+    @Override
+    public void close() {
+        closeInternal();
+    }
+
+    /**
+     * @deprecated replaced by {@link #close()}.
+     */
+    @Deprecated
     public boolean release() {
-        synchronized (this) {
-            if (mReleased) {
-                throw new IllegalStateException("Already released");
-            }
-            mReleased = true;
-            mGuard.close();
+        return closeInternal();
+    }
+
+    private boolean closeInternal() {
+        mCloseGuard.close();
+        if (mClosed.compareAndSet(false, true)) {
             if (mStable) {
                 return mContentResolver.releaseProvider(mContentProvider);
             } else {
                 return mContentResolver.releaseUnstableProvider(mContentProvider);
             }
+        } else {
+            return false;
         }
     }
 
     @Override
     protected void finalize() throws Throwable {
-        if (mGuard != null) {
-            mGuard.warnIfOpen();
+        try {
+            mCloseGuard.warnIfOpen();
+            close();
+        } finally {
+            super.finalize();
         }
     }
 
@@ -502,4 +535,29 @@
             mContentResolver.appNotRespondingViaProvider(mContentProvider);
         }
     }
+
+    private final class CursorWrapperInner extends CrossProcessCursorWrapper {
+        private final CloseGuard mCloseGuard = CloseGuard.get();
+
+        CursorWrapperInner(Cursor cursor) {
+            super(cursor);
+            mCloseGuard.open("close");
+        }
+
+        @Override
+        public void close() {
+            mCloseGuard.close();
+            super.close();
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
+            try {
+                mCloseGuard.warnIfOpen();
+                close();
+            } finally {
+                super.finalize();
+            }
+        }
+    }
 }
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 9d0ebc2..3461c11 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -20,6 +20,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.TestApi;
+import android.annotation.UserIdInt;
 import android.app.ActivityManagerNative;
 import android.app.ActivityThread;
 import android.app.AppGlobals;
@@ -47,11 +49,11 @@
 import android.util.EventLog;
 import android.util.Log;
 
-import dalvik.system.CloseGuard;
-
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 
+import dalvik.system.CloseGuard;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -59,9 +61,9 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.Random;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * This class provides applications access to the content model.
@@ -514,8 +516,9 @@
             maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder);
 
             // Wrap the cursor object into CursorWrapperInner object.
-            CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
-                    stableProvider != null ? stableProvider : acquireProvider(uri));
+            final IContentProvider provider = (stableProvider != null) ? stableProvider
+                    : acquireProvider(uri);
+            final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);
             stableProvider = null;
             qCursor = null;
             return wrapper;
@@ -1589,27 +1592,27 @@
      *
      * @param uri The URI to watch for changes. This can be a specific row URI, or a base URI
      * for a whole class of content.
-     * @param notifyForDescendents When false, the observer will be notified whenever a
+     * @param notifyForDescendants When false, the observer will be notified whenever a
      * change occurs to the exact URI specified by <code>uri</code> or to one of the
      * URI's ancestors in the path hierarchy.  When true, the observer will also be notified
      * whenever a change occurs to the URI's descendants in the path hierarchy.
      * @param observer The object that receives callbacks when changes occur.
      * @see #unregisterContentObserver
      */
-    public final void registerContentObserver(@NonNull Uri uri, boolean notifyForDescendents,
+    public final void registerContentObserver(@NonNull Uri uri, boolean notifyForDescendants,
             @NonNull ContentObserver observer) {
         Preconditions.checkNotNull(uri, "uri");
         Preconditions.checkNotNull(observer, "observer");
         registerContentObserver(
                 ContentProvider.getUriWithoutUserId(uri),
-                notifyForDescendents,
+                notifyForDescendants,
                 observer,
                 ContentProvider.getUserIdFromUri(uri, UserHandle.myUserId()));
     }
 
     /** @hide - designated user version */
     public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
-            ContentObserver observer, int userHandle) {
+            ContentObserver observer, @UserIdInt int userHandle) {
         try {
             getContentService().registerContentObserver(uri, notifyForDescendents,
                     observer.getContentObserver(), userHandle);
@@ -1683,7 +1686,7 @@
      * @hide
      */
     public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork,
-            int userHandle) {
+            @UserIdInt int userHandle) {
         try {
             getContentService().notifyChange(
                     uri, observer == null ? null : observer.getContentObserver(),
@@ -1824,7 +1827,7 @@
      * @see #requestSync(Account, String, Bundle)
      * @hide
      */
-    public static void requestSyncAsUser(Account account, String authority, int userId,
+    public static void requestSyncAsUser(Account account, String authority, @UserIdInt int userId,
             Bundle extras) {
         if (extras == null) {
             throw new IllegalArgumentException("Must specify extras.");
@@ -1921,7 +1924,7 @@
      * @see #cancelSync(Account, String)
      * @hide
      */
-    public static void cancelSyncAsUser(Account account, String authority, int userId) {
+    public static void cancelSyncAsUser(Account account, String authority, @UserIdInt int userId) {
         try {
             getContentService().cancelSyncAsUser(account, authority, null, userId);
         } catch (RemoteException e) {
@@ -1944,7 +1947,7 @@
      * @see #getSyncAdapterTypes()
      * @hide
      */
-    public static SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) {
+    public static SyncAdapterType[] getSyncAdapterTypesAsUser(@UserIdInt int userId) {
         try {
             return getContentService().getSyncAdapterTypesAsUser(userId);
         } catch (RemoteException e) {
@@ -1956,8 +1959,9 @@
      * @hide
      * Returns the package names of syncadapters that match a given user and authority.
      */
+    @TestApi
     public static String[] getSyncAdapterPackagesForAuthorityAsUser(String authority,
-            int userId) {
+            @UserIdInt int userId) {
         try {
             return getContentService().getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
         } catch (RemoteException e) {
@@ -1987,7 +1991,7 @@
      * @hide
      */
     public static boolean getSyncAutomaticallyAsUser(Account account, String authority,
-            int userId) {
+            @UserIdInt int userId) {
         try {
             return getContentService().getSyncAutomaticallyAsUser(account, authority, userId);
         } catch (RemoteException e) {
@@ -2013,7 +2017,7 @@
      * @hide
      */
     public static void setSyncAutomaticallyAsUser(Account account, String authority, boolean sync,
-            int userId) {
+            @UserIdInt int userId) {
         try {
             getContentService().setSyncAutomaticallyAsUser(account, authority, sync, userId);
         } catch (RemoteException e) {
@@ -2172,7 +2176,8 @@
      * @see #getIsSyncable(Account, String)
      * @hide
      */
-    public static int getIsSyncableAsUser(Account account, String authority, int userId) {
+    public static int getIsSyncableAsUser(Account account, String authority,
+            @UserIdInt int userId) {
         try {
             return getContentService().getIsSyncableAsUser(account, authority, userId);
         } catch (RemoteException e) {
@@ -2215,7 +2220,7 @@
      * @see #getMasterSyncAutomatically()
      * @hide
      */
-    public static boolean getMasterSyncAutomaticallyAsUser(int userId) {
+    public static boolean getMasterSyncAutomaticallyAsUser(@UserIdInt int userId) {
         try {
             return getContentService().getMasterSyncAutomaticallyAsUser(userId);
         } catch (RemoteException e) {
@@ -2239,7 +2244,7 @@
      * @see #setMasterSyncAutomatically(boolean)
      * @hide
      */
-    public static void setMasterSyncAutomaticallyAsUser(boolean sync, int userId) {
+    public static void setMasterSyncAutomaticallyAsUser(boolean sync, @UserIdInt int userId) {
         try {
             getContentService().setMasterSyncAutomaticallyAsUser(sync, userId);
         } catch (RemoteException e) {
@@ -2319,7 +2324,7 @@
      * @see #getCurrentSyncs()
      * @hide
      */
-    public static List<SyncInfo> getCurrentSyncsAsUser(int userId) {
+    public static List<SyncInfo> getCurrentSyncsAsUser(@UserIdInt int userId) {
         try {
             return getContentService().getCurrentSyncsAsUser(userId);
         } catch (RemoteException e) {
@@ -2347,7 +2352,7 @@
      * @hide
      */
     public static SyncStatusInfo getSyncStatusAsUser(Account account, String authority,
-            int userId) {
+            @UserIdInt int userId) {
         try {
             return getContentService().getSyncStatusAsUser(account, authority, null, userId);
         } catch (RemoteException e) {
@@ -2371,7 +2376,8 @@
      * @see #requestSync(Account, String, Bundle)
      * @hide
      */
-    public static boolean isSyncPendingAsUser(Account account, String authority, int userId) {
+    public static boolean isSyncPendingAsUser(Account account, String authority,
+            @UserIdInt int userId) {
         try {
             return getContentService().isSyncPendingAsUser(account, authority, null, userId);
         } catch (RemoteException e) {
@@ -2503,41 +2509,31 @@
 
     private final class CursorWrapperInner extends CrossProcessCursorWrapper {
         private final IContentProvider mContentProvider;
-        public static final String TAG="CursorWrapperInner";
+        private final AtomicBoolean mProviderReleased = new AtomicBoolean();
 
         private final CloseGuard mCloseGuard = CloseGuard.get();
-        private boolean mProviderReleased;
 
-        CursorWrapperInner(Cursor cursor, IContentProvider icp) {
+        CursorWrapperInner(Cursor cursor, IContentProvider contentProvider) {
             super(cursor);
-            mContentProvider = icp;
+            mContentProvider = contentProvider;
             mCloseGuard.open("close");
         }
 
         @Override
         public void close() {
+            mCloseGuard.close();
             super.close();
-            ContentResolver.this.releaseProvider(mContentProvider);
-            mProviderReleased = true;
 
-            if (mCloseGuard != null) {
-                mCloseGuard.close();
+            if (mProviderReleased.compareAndSet(false, true)) {
+                ContentResolver.this.releaseProvider(mContentProvider);
             }
         }
 
         @Override
         protected void finalize() throws Throwable {
             try {
-                if (mCloseGuard != null) {
-                    mCloseGuard.warnIfOpen();
-                }
-
-                if (!mProviderReleased && mContentProvider != null) {
-                    // Even though we are using CloseGuard, log this anyway so that
-                    // application developers always see the message in the log.
-                    Log.w(TAG, "Cursor finalized without prior close()");
-                    ContentResolver.this.releaseProvider(mContentProvider);
-                }
+                mCloseGuard.warnIfOpen();
+                close();
             } finally {
                 super.finalize();
             }
@@ -2546,7 +2542,7 @@
 
     private final class ParcelFileDescriptorInner extends ParcelFileDescriptor {
         private final IContentProvider mContentProvider;
-        private boolean mProviderReleased;
+        private final AtomicBoolean mProviderReleased = new AtomicBoolean();
 
         ParcelFileDescriptorInner(ParcelFileDescriptor pfd, IContentProvider icp) {
             super(pfd);
@@ -2555,9 +2551,8 @@
 
         @Override
         public void releaseResources() {
-            if (!mProviderReleased) {
+            if (mProviderReleased.compareAndSet(false, true)) {
                 ContentResolver.this.releaseProvider(mContentProvider);
-                mProviderReleased = true;
             }
         }
     }
@@ -2584,7 +2579,9 @@
 
     private static IContentService sContentService;
     private final Context mContext;
+
     final String mPackageName;
+
     private static final String TAG = "ContentResolver";
 
     /** @hide */
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 38a4475..3142b40 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -30,6 +30,8 @@
 import android.annotation.StyleRes;
 import android.annotation.StyleableRes;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.annotation.UserIdInt;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
@@ -46,6 +48,7 @@
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
+import android.os.HardwarePropertiesManager;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.StatFs;
@@ -326,10 +329,40 @@
      */
     public static final int BIND_NOT_VISIBLE = 0x40000000;
 
-    /** Return an AssetManager instance for your application's package. */
+    /**
+     * Flag for {@link #bindService}: The service being bound is an
+     * {@link android.R.attr#isolatedProcess isolated},
+     * {@link android.R.attr#externalService external} service.  This binds the service into the
+     * calling application's package, rather than the package in which the service is declared.
+     * @hide
+     */
+    @SystemApi
+    public static final int BIND_EXTERNAL_SERVICE = 0x80000000;
+
+    /**
+     * Returns an AssetManager instance for the application's package.
+     * <p>
+     * <strong>Note:</strong> Implementations of this method should return
+     * an AssetManager instance that is consistent with the Resources instance
+     * returned by {@link #getResources()}. For example, they should share the
+     * same {@link Configuration} object.
+     *
+     * @return an AssetManager instance for the application's package
+     * @see #getResources()
+     */
     public abstract AssetManager getAssets();
 
-    /** Return a Resources instance for your application's package. */
+    /**
+     * Returns a Resources instance for the application's package.
+     * <p>
+     * <strong>Note:</strong> Implementations of this method should return
+     * a Resources instance that is consistent with the AssetManager instance
+     * returned by {@link #getAssets()}. For example, they should share the
+     * same {@link Configuration} object.
+     *
+     * @return a Resources instance for the application's package
+     * @see #getAssets()
+     */
     public abstract Resources getResources();
 
     /** Return PackageManager instance to find global package information. */
@@ -2528,7 +2561,7 @@
             NETWORK_STATS_SERVICE,
             //@hide: NETWORK_POLICY_SERVICE,
             WIFI_SERVICE,
-            WIFI_PASSPOINT_SERVICE,
+            WIFI_NAN_SERVICE,
             WIFI_P2P_SERVICE,
             WIFI_SCANNING_SERVICE,
             //@hide: WIFI_RTT_SERVICE,
@@ -2579,6 +2612,8 @@
             MEDIA_PROJECTION_SERVICE,
             MIDI_SERVICE,
             RADIO_SERVICE,
+            HARDWARE_PROPERTIES_SERVICE,
+            //@hide: SOUND_TRIGGER_SERVICE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ServiceName {}
@@ -2640,6 +2675,8 @@
      * <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")
+     * <dd> A {@link android.os.HardwarePropertiesManager} for accessing hardware properties.
      * </dl>
      *
      * <p>Note:  System services obtained via this API may be closely associated with
@@ -2701,6 +2738,8 @@
      * @see android.app.job.JobScheduler
      * @see #NETWORK_STATS_SERVICE
      * @see android.app.usage.NetworkStatsManager
+     * @see android.os.HardwarePropertiesManager
+     * @see #HARDWARE_PROPERTIES_SERVICE
      */
     public abstract Object getSystemService(@ServiceName @NonNull String name);
 
@@ -2970,17 +3009,6 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
-     * android.net.wifi.passpoint.WifiPasspointManager} for handling management of
-     * Wi-Fi passpoint access.
-     *
-     * @see #getSystemService
-     * @see android.net.wifi.passpoint.WifiPasspointManager
-     * @hide
-     */
-    public static final String WIFI_PASSPOINT_SERVICE = "wifipasspoint";
-
-    /**
-     * Use with {@link #getSystemService} to retrieve a {@link
      * android.net.wifi.p2p.WifiP2pManager} for handling management of
      * Wi-Fi peer-to-peer connections.
      *
@@ -2990,6 +3018,17 @@
     public static final String WIFI_P2P_SERVICE = "wifip2p";
 
     /**
+     * Use with {@link #getSystemService} to retrieve a
+     * {@link android.net.wifi.nan.WifiNanManager} for handling management of
+     * Wi-Fi NAN discovery and connections.
+     *
+     * @see #getSystemService
+     * @see android.net.wifi.nan.WifiNanManager
+     * @hide PROPOSED_NAN_API
+     */
+    public static final String WIFI_NAN_SERVICE = "wifinan";
+
+    /**
      * Use with {@link #getSystemService} to retrieve a {@link
      * android.net.wifi.WifiScanner} for scanning the wifi universe
      *
@@ -3157,6 +3196,16 @@
     public static final String VOICE_INTERACTION_MANAGER_SERVICE = "voiceinteraction";
 
     /**
+     * Use with {@link #getSystemService} to access the
+     * {@link com.android.server.voiceinteraction.SoundTriggerService}.
+     *
+     * @hide
+     * @see #getSystemService
+     */
+    public static final String SOUND_TRIGGER_SERVICE = "soundtrigger";
+
+
+    /**
      * Use with {@link #getSystemService} to retrieve an
      * {@link android.app.backup.IBackupManager IBackupManager} for communicating
      * with the backup mechanism.
@@ -3443,6 +3492,14 @@
     public static final String RADIO_SERVICE = "radio";
 
     /**
+     * Use with {@link #getSystemService} to retrieve a
+     * {@link android.os.HardwarePropertiesManager} for accessing the hardware properties service.
+     *
+     * @see #getSystemService
+     */
+    public static final String HARDWARE_PROPERTIES_SERVICE = "hardwareproperties";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
@@ -3947,7 +4004,8 @@
      *
      * @hide
      */
-    public abstract int getUserId();
+    @TestApi
+    public abstract @UserIdInt int getUserId();
 
     /**
      * Return a new Context object for the current Context but whose resources
@@ -3998,13 +4056,16 @@
      * Because device-encrypted data is available before user authentication,
      * you should carefully consider what data you store using this Context.
      * <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.
+     * <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.
      *
-     * @return new Context or {@code null} if device-encrypted storage is not
-     *         supported or available on this device.
      * @see #isDeviceEncryptedStorage()
      */
     public abstract Context createDeviceEncryptedStorageContext();
@@ -4018,6 +4079,11 @@
      * <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.
+     * <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
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 1a3d262..c99ddc8 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -82,8 +82,7 @@
     }
 
     @Override
-    public Resources getResources()
-    {
+    public Resources getResources() {
         return mBase.getResources();
     }
 
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9973faf..49b8363 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -41,6 +41,7 @@
 import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Environment;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -541,6 +542,8 @@
  *     <li> {@link #ACTION_PACKAGE_REMOVED}
  *     <li> {@link #ACTION_PACKAGE_RESTARTED}
  *     <li> {@link #ACTION_PACKAGE_DATA_CLEARED}
+ *     <li> {@link #ACTION_PACKAGES_SUSPENDED}
+ *     <li> {@link #ACTION_PACKAGES_UNSUSPENDED}
  *     <li> {@link #ACTION_UID_REMOVED}
  *     <li> {@link #ACTION_BATTERY_CHANGED}
  *     <li> {@link #ACTION_POWER_CONNECTED}
@@ -661,10 +664,13 @@
     public static final String ACTION_DEFAULT = ACTION_VIEW;
 
     /**
-     * Activity Action: Quick view the data.
-     * <p>Input: {@link #getData} is URI from which to retrieve data.
+     * Activity Action: Quick view the data. Launches a quick viewer for
+     * a URI or a list of URIs.
+     * <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
+     * optional index of the URI in the clip data to show first.
      * <p>Output: nothing.
-     * @hide
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_QUICK_VIEW = "android.intent.action.QUICK_VIEW";
@@ -1569,6 +1575,14 @@
             = "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
@@ -2118,6 +2132,30 @@
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_PACKAGE_DATA_CLEARED = "android.intent.action.PACKAGE_DATA_CLEARED";
     /**
+     * Broadcast Action: Packages have been suspended.
+     * <p>Includes the following extras:
+     * <ul>
+     * <li> {@link #EXTRA_CHANGED_PACKAGE_LIST} is the set of packages which have been suspended
+     * </ul>
+     *
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system. It is only sent to registered receivers.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_PACKAGES_SUSPENDED = "android.intent.action.PACKAGES_SUSPENDED";
+    /**
+     * Broadcast Action: Packages have been unsuspended.
+     * <p>Includes the following extras:
+     * <ul>
+     * <li> {@link #EXTRA_CHANGED_PACKAGE_LIST} is the set of packages which have been unsuspended
+     * </ul>
+     *
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system. It is only sent to registered receivers.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_PACKAGES_UNSUSPENDED = "android.intent.action.PACKAGES_UNSUSPENDED";
+    /**
      * Broadcast Action: A user ID has been removed from the system.  The user
      * ID number is stored in the extra data under {@link #EXTRA_UID}.
      *
@@ -2537,6 +2575,16 @@
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_MEDIA_BUTTON = "android.intent.action.MEDIA_BUTTON";
 
+   /**
+     * Broadcast Action:  The "Picture-in-picture (PIP) Button" was pressed.
+     * Includes a single extra field, {@link #EXTRA_KEY_EVENT}, containing the key event that
+     * caused the broadcast.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_PICTURE_IN_PICTURE_BUTTON =
+            "android.intent.action.PICTURE_IN_PICTURE_BUTTON";
+
     /**
      * Broadcast Action:  The "Camera Button" was pressed.  Includes a single
      * extra field, {@link #EXTRA_KEY_EVENT}, containing the key event that
@@ -2578,8 +2626,7 @@
      *   turned off</li>
      * </ul>
      *
-     * <p class="note">This is a protected intent that can only be sent
-     * by the system.
+     * <p class="note">This is a protected intent that can only be sent by the system.</p>
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_AIRPLANE_MODE_CHANGED = "android.intent.action.AIRPLANE_MODE";
@@ -2992,27 +3039,15 @@
 
     /**
      * 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, or when the profile
-     * owner suspends 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.
+     * changed. This includes when the user toggles the profile's quiet mode. 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";
 
     /**
-     * Broadcast sent to the managed profile when its availability has changed. This includes when
-     * the user toggles the profile's quiet mode, or when the profile owner suspends 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. See also
-     * {@link #ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED}
-     */
-    public static final String ACTION_AVAILABILITY_CHANGED =
-            "android.intent.action.AVAILABILITY_CHANGED";
-
-    /**
      * Sent when the user taps on the clock widget in the system's "quick settings" area.
      */
     public static final String ACTION_QUICK_CLOCK =
@@ -3034,6 +3069,24 @@
     public static final String ACTION_GLOBAL_BUTTON = "android.intent.action.GLOBAL_BUTTON";
 
     /**
+     * Broadcast Action: Sent when media resource is granted.
+     * <p>
+     * {@link #EXTRA_PACKAGES} specifies the packages on the process holding the media resource
+     * granted.
+     * </p>
+     * <p class="note">
+     * This is a protected intent that can only be sent by the system.
+     * </p>
+     * <p class="note">
+     * This requires {@link android.Manifest.permission#RECEIVE_MEDIA_RESOURCE_USAGE} permission.
+     * </p>
+     *
+     * @hide
+     */
+    public static final String ACTION_MEDIA_RESOURCE_GRANTED =
+            "android.intent.action.MEDIA_RESOURCE_GRANTED";
+
+    /**
      * Activity Action: Allow the user to select and return one or more existing
      * documents. When invoked, the system will display the various
      * {@link DocumentsProvider} instances installed on the device, letting the
@@ -3132,6 +3185,50 @@
     public static final String
             ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE";
 
+    /**
+     * Activity Action: Give access to a standard storage directory 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).
+     * <p>
+     * To gain access to descendant (child, grandchild, etc) documents, use
+     * {@link DocumentsContract#buildDocumentUriUsingTree(Uri, String)} and
+     * {@link DocumentsContract#buildChildDocumentsUriUsingTree(Uri, String)} with the returned URI.
+     * <p>
+     * Input: full path to a standard directory, in the form of
+     * {@code STORAGE_ROOT + STANDARD_DIRECTORY}, where {@code STORAGE_ROOT} is the physical path of
+     * a storage container, and {@code STANDARD_DIRECTORY} is 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}
+     * <p>
+     * For example, to open the "Pictures" folder in the default external storage, the intent's data
+     * would be: {@code Uri.fromFile(new File(Environment.getExternalStorageDirectory(),
+     * Environment.DIRECTORY_PICTURES))}.
+     * <p>
+     * Output: The URI representing the requested directory tree.
+     *
+     * @see DocumentsContract
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String
+            ACTION_OPEN_EXTERNAL_DIRECTORY = "android.intent.action.OPEN_EXTERNAL_DIRECTORY";
+
+    /**
+     * Broadcast Action: List of dynamic sensor is changed due to new sensor being connected or
+     * exisiting sensor being disconnected.
+     *
+     * <p class="note">This is a protected intent that can only be sent by the system.</p>
+     *
+     * {@hide}
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String
+            ACTION_DYNAMIC_SENSOR_CHANGED = "android.intent.action.DYNAMIC_SENSOR_CHANGED";
+
     /** {@hide} */
     public static final String ACTION_MASTER_CLEAR = "android.intent.action.MASTER_CLEAR";
 
@@ -3604,6 +3701,15 @@
     public static final String EXTRA_USER_ID = "android.intent.extra.USER_ID";
 
     /**
+     * An int representing the task id to be retrieved. This is used when a launch from recents is
+     * intercepted by another action such as credentials confirmation to remember which task should
+     * be resumed when complete.
+     *
+     * @hide
+     */
+    public static final String EXTRA_TASK_ID = "android.intent.extra.TASK_ID";
+
+    /**
      * An Intent[] describing additional, alternate choices you would like shown with
      * {@link #ACTION_CHOOSER}.
      *
@@ -3913,7 +4019,9 @@
     /**
      * This field is part of
      * {@link android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_AVAILABLE},
-     * {@link android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE}
+     * {@link android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE},
+     * {@link android.content.Intent#ACTION_PACKAGES_SUSPENDED},
+     * {@link android.content.Intent#ACTION_PACKAGES_UNSUSPENDED}
      * and contains a string array of all of the components that have changed.
      */
     public static final String EXTRA_CHANGED_PACKAGE_LIST =
@@ -4061,13 +4169,44 @@
     public static final String EXTRA_SIM_ACTIVATION_RESPONSE =
             "android.intent.extra.SIM_ACTIVATION_RESPONSE";
 
-    /** {@hide} */
+    /**
+     * Optional index with semantics depending on the intent action.
+     * @see #ACTION_QUICK_VIEW
+     */
     public static final String EXTRA_INDEX = "android.intent.extra.INDEX";
 
     /**
      * Optional boolean extra indicating whether quiet mode has been switched on or off.
      */
     public static final String EXTRA_QUIET_MODE = "android.intent.extra.QUIET_MODE";
+
+    /**
+     * Used as an int extra field in {@link #ACTION_MEDIA_RESOURCE_GRANTED}
+     * intents to specify the resource type granted. Possible values are
+     * {@link #EXTRA_MEDIA_RESOURCE_TYPE_VIDEO_CODEC} or
+     * {@link #EXTRA_MEDIA_RESOURCE_TYPE_AUDIO_CODEC}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_MEDIA_RESOURCE_TYPE =
+            "android.intent.extra.MEDIA_RESOURCE_TYPE";
+
+    /**
+     * Used as an int value for {@link #EXTRA_MEDIA_RESOURCE_TYPE}
+     * to represent that a video codec is allowed to use.
+     *
+     * @hide
+     */
+    public static final int EXTRA_MEDIA_RESOURCE_TYPE_VIDEO_CODEC = 0;
+
+    /**
+     * Used as an int value for {@link #EXTRA_MEDIA_RESOURCE_TYPE}
+     * to represent that a audio codec is allowed to use.
+     *
+     * @hide
+     */
+    public static final int EXTRA_MEDIA_RESOURCE_TYPE_AUDIO_CODEC = 1;
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Intent flags (see mFlags variable).
@@ -4168,6 +4307,21 @@
     public static final int FLAG_GRANT_PREFIX_URI_PERMISSION = 0x00000080;
 
     /**
+     * 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:
+     * <ul>
+     * <li>Apps installed on external storage, which will appear to be
+     * uninstalled while the the device is ejected.
+     * <li>Apps with encryption unaware components, which will appear to not
+     * exist while the device is locked.
+     * </ul>
+     *
+     * @hide
+     */
+    public static final int FLAG_DEBUG_TRIAGED_MISSING = 0x00000100;
+
+    /**
      * If set, the new activity is not kept in the history stack.  As soon as
      * the user navigates away from it, the activity is finished.  This may also
      * be set with the {@link android.R.styleable#AndroidManifestActivity_noHistory
@@ -5563,6 +5717,9 @@
                 case "--receiver-replace-pending":
                     intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
                     break;
+                case "--receiver-foreground":
+                    intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+                    break;
                 case "--selector":
                     intent.setDataAndType(data, type);
                     intent = new Intent();
@@ -5672,6 +5829,7 @@
                 "    [--esal <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]",
                 "        (mutiple extras passed as List<String>; to embed a comma into a string,",
                 "         escape it using \"\\,\")",
+                "    [--f <FLAG>]",
                 "    [--grant-read-uri-permission] [--grant-write-uri-permission]",
                 "    [--grant-persistable-uri-permission] [--grant-prefix-uri-permission]",
                 "    [--debug-log-resolution] [--exclude-stopped-packages]",
@@ -5685,6 +5843,7 @@
                 "    [--activity-single-top] [--activity-clear-task]",
                 "    [--activity-task-on-home]",
                 "    [--receiver-registered-only] [--receiver-replace-pending]",
+                "    [--receiver-foreground]",
                 "    [--selector]",
                 "    [<URI> | <PACKAGE> | <COMPONENT>]"
         };
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index 1d16516..7f9e176 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -30,8 +30,7 @@
  * when they are committed to storage.  Objects that are returned from the
  * various <code>get</code> methods must be treated as immutable by the application.
  *
- * <p><em>Note: currently this class does not support use across multiple
- * processes.  This will be added later.</em>
+ * <p><em>Note: This class does not support use across multiple processes.</em>
  *
  * <div class="special reference">
  * <h3>Developer Guides</h3>
diff --git a/core/java/android/content/SyncInfo.java b/core/java/android/content/SyncInfo.java
index a586d6f..ab3c30b 100644
--- a/core/java/android/content/SyncInfo.java
+++ b/core/java/android/content/SyncInfo.java
@@ -24,6 +24,13 @@
  * Information about the sync operation that is currently underway.
  */
 public class SyncInfo implements Parcelable {
+    /**
+     * Used when the caller receiving this object doesn't have permission to access the accounts
+     * on device.
+     * @See Manifest.permission.GET_ACCOUNTS
+     */
+    private static final Account REDACTED_ACCOUNT = new Account("*****", "*****");
+
     /** @hide */
     public final int authorityId;
 
@@ -44,6 +51,17 @@
      */
     public final long startTime;
 
+    /**
+     * Creates a SyncInfo object with an unusable Account. Used when the caller receiving this
+     * object doesn't have access to the accounts on the device.
+     * @See Manifest.permission.GET_ACCOUNTS
+     * @hide
+     */
+    public static SyncInfo createAccountRedacted(
+        int authorityId, String authority, long startTime) {
+            return new SyncInfo(authorityId, REDACTED_ACCOUNT, authority, startTime);
+    }
+
     /** @hide */
     public SyncInfo(int authorityId, Account account, String authority, long startTime) {
         this.authorityId = authorityId;
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 0cb0e9f..91a8e0a 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -156,6 +156,35 @@
     public String targetActivity;
 
     /**
+     * Activity can not be resized and always occupies the fullscreen area with all windows fully
+     * visible.
+     * @hide
+     */
+    public static final int RESIZE_MODE_UNRESIZEABLE = 0;
+    /**
+     * Activity can not be resized and always occupies the fullscreen area with all windows cropped
+     * to either the task or stack bounds.
+     * @hide
+     */
+    public static final int RESIZE_MODE_CROP_WINDOWS = 1;
+    /**
+     * Activity is resizeable.
+     * @hide
+     */
+    public static final int RESIZE_MODE_RESIZEABLE = 2;
+    /**
+     * Activity is resizeable and supported picture-in-picture mode.
+     * @hide
+     */
+    public static final int RESIZE_MODE_RESIZEABLE_AND_PIPABLE = 3;
+    /**
+     * Value indicating if the resizing mode the activity supports.
+     * See {@link android.R.attr#resizeableActivity}.
+     * @hide
+     */
+    public int resizeMode;
+
+    /**
      * Bit in {@link #flags} indicating whether this activity is able to
      * run in multiple processes.  If
      * true, the system may instantiate it in the some process as the
@@ -276,6 +305,21 @@
      */
     public static final int FLAG_RESUME_WHILE_PAUSING = 0x4000;
     /**
+     * Bit in {@link #flags} indicating that this activity should be run with VR mode enabled.
+     *
+     * {@see android.app.Activity#setVrMode(boolean)}.
+     */
+    public static final int FLAG_ENABLE_VR_MODE = 0x8000;
+
+    /**
+     * Bit in {@link #flags} indicating if the activity is always focusable regardless of if it is
+     * in a task/stack whose activities are normally not focusable.
+     * See android.R.attr#alwaysFocusable.
+     * @hide
+     */
+    public static final int FLAG_ALWAYS_FOCUSABLE = 0x40000;
+
+    /**
      * @hide Bit in {@link #flags}: If set, this component will only be seen
      * by the system user.  Only works with broadcast receivers.  Set from the
      * android.R.attr#systemUserOnly attribute.
@@ -664,20 +708,6 @@
      */
     public String parentActivityName;
 
-    /**
-     * Value indicating if the activity is resizeable to any dimension.
-     * See {@link android.R.attr#resizeableActivity}.
-     * @hide
-     */
-    public boolean resizeable;
-
-    /**
-     * Value indicating if the activity is supports picture-in-picture form of multi-window mode.
-     * See {@link android.R.attr#supportsPictureInPicture}.
-     * @hide
-     */
-    public boolean supportsPip;
-
     /** @hide */
     public static final int LOCK_TASK_LAUNCH_MODE_DEFAULT = 0;
     /** @hide */
@@ -729,10 +759,9 @@
         uiOptions = orig.uiOptions;
         parentActivityName = orig.parentActivityName;
         maxRecents = orig.maxRecents;
-        resizeable = orig.resizeable;
-        supportsPip = orig.supportsPip;
         lockTaskLaunchMode = orig.lockTaskLaunchMode;
         layout = orig.layout;
+        resizeMode = orig.resizeMode;
     }
 
     /**
@@ -755,6 +784,22 @@
         }
     }
 
+    /** @hide */
+    public static final String resizeModeToString(int mode) {
+        switch (mode) {
+            case RESIZE_MODE_UNRESIZEABLE:
+                return "RESIZE_MODE_UNRESIZEABLE";
+            case RESIZE_MODE_CROP_WINDOWS:
+                return "RESIZE_MODE_CROP_WINDOWS";
+            case RESIZE_MODE_RESIZEABLE:
+                return "RESIZE_MODE_RESIZEABLE";
+            case RESIZE_MODE_RESIZEABLE_AND_PIPABLE:
+                return "RESIZE_MODE_RESIZEABLE_AND_PIPABLE";
+            default:
+                return "unknown=" + mode;
+        }
+    }
+
     public void dump(Printer pw, String prefix) {
         dump(pw, prefix, DUMP_FLAG_ALL);
     }
@@ -785,7 +830,6 @@
             pw.println(prefix + " uiOptions=0x" + Integer.toHexString(uiOptions));
         }
         if ((flags&DUMP_FLAG_DETAILS) != 0) {
-            pw.println(prefix + "resizeable=" + resizeable + " supportsPip=" + supportsPip);
             pw.println(prefix + "lockTaskLaunchMode="
                     + lockTaskLaunchModeToString(lockTaskLaunchMode));
         }
@@ -794,6 +838,7 @@
                     + layout.widthFraction + ", " + layout.height + "|"
                     + layout.heightFraction + ", " + layout.gravity);
         }
+        pw.println(prefix + "resizeMode=" + resizeModeToString(resizeMode));
         super.dumpBack(pw, prefix, flags);
     }
 
@@ -823,8 +868,6 @@
         dest.writeString(parentActivityName);
         dest.writeInt(persistableMode);
         dest.writeInt(maxRecents);
-        dest.writeInt(resizeable ? 1 : 0);
-        dest.writeInt(supportsPip ? 1 : 0);
         dest.writeInt(lockTaskLaunchMode);
         if (layout != null) {
             dest.writeInt(1);
@@ -837,6 +880,7 @@
         } else {
             dest.writeInt(0);
         }
+        dest.writeInt(resizeMode);
     }
 
     public static final Parcelable.Creator<ActivityInfo> CREATOR
@@ -865,12 +909,11 @@
         parentActivityName = source.readString();
         persistableMode = source.readInt();
         maxRecents = source.readInt();
-        resizeable = (source.readInt() == 1);
-        supportsPip = (source.readInt() == 1);
         lockTaskLaunchMode = source.readInt();
         if (source.readInt() == 1) {
             layout = new Layout(source);
         }
+        resizeMode = source.readInt();
     }
 
     public static final class Layout {
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 807c0a2..654396b 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import android.annotation.TestApi;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
@@ -175,7 +176,7 @@
     
     /**
      * Value for {@link #flags}: this is set if this application has been
-     * install as an update to a built-in system application.
+     * installed as an update to a built-in system application.
      */
     public static final int FLAG_UPDATED_SYSTEM_APP = 1<<7;
     
@@ -506,6 +507,14 @@
     public static final int PRIVATE_FLAG_EPHEMERAL = 1 << 9;
 
     /**
+     * When set, signals that the application is required for the system user and should not be
+     * uninstalled.
+     *
+     * @hide
+     */
+    public static final int PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER = 1 << 10;
+
+    /**
      * Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
      * {@hide}
      */
@@ -795,7 +804,12 @@
     public boolean hasRtlSupport() {
         return (flags & FLAG_SUPPORTS_RTL) == FLAG_SUPPORTS_RTL;
     }
-    
+
+    /** {@hide} */
+    public boolean hasCode() {
+        return (flags & FLAG_HAS_CODE) != 0;
+    }
+
     public static class DisplayNameComparator
             implements Comparator<ApplicationInfo> {
         public DisplayNameComparator(PackageManager pm) {
@@ -1061,6 +1075,7 @@
     /**
      * @hide
      */
+    @TestApi
     public boolean isSystemApp() {
         return (flags & ApplicationInfo.FLAG_SYSTEM) != 0;
     }
@@ -1068,6 +1083,7 @@
     /**
      * @hide
      */
+    @TestApi
     public boolean isPrivilegedApp() {
         return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
     }
@@ -1117,6 +1133,13 @@
     /**
      * @hide
      */
+    public boolean isRequiredForSystemUser() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER) != 0;
+    }
+
+    /**
+     * @hide
+     */
     @Override protected ApplicationInfo getApplicationInfo() {
         return this;
     }
diff --git a/core/java/android/content/pm/AppsQueryHelper.java b/core/java/android/content/pm/AppsQueryHelper.java
index 084bc18..e542589 100644
--- a/core/java/android/content/pm/AppsQueryHelper.java
+++ b/core/java/android/content/pm/AppsQueryHelper.java
@@ -51,6 +51,11 @@
      */
     public static int GET_IMES = 1 << 2;
 
+    /**
+     * Return all apps that are flagged as required for the system user.
+     */
+    public static int GET_REQUIRED_FOR_SYSTEM_USER = 1 << 3;
+
     private final IPackageManager mPackageManager;
     private List<ApplicationInfo> mAllApps;
 
@@ -73,6 +78,7 @@
         boolean nonLaunchableApps = (flags & GET_NON_LAUNCHABLE_APPS) > 0;
         boolean interactAcrossUsers = (flags & GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM) > 0;
         boolean imes = (flags & GET_IMES) > 0;
+        boolean requiredForSystemUser = (flags & GET_REQUIRED_FOR_SYSTEM_USER) > 0;
         if (mAllApps == null) {
             mAllApps = getAllApps(user.getIdentifier());
         }
@@ -143,6 +149,18 @@
             }
         }
 
+        if (requiredForSystemUser) {
+            final int allAppsSize = mAllApps.size();
+            for (int i = 0; i < allAppsSize; i++) {
+                final ApplicationInfo appInfo = mAllApps.get(i);
+                if (systemAppsOnly && !appInfo.isSystemApp()) {
+                    continue;
+                }
+                if (appInfo.isRequiredForSystemUser()) {
+                    result.add(appInfo.packageName);
+                }
+            }
+        }
         return result;
     }
 
diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java
index a295cc5..63a163d 100644
--- a/core/java/android/content/pm/ComponentInfo.java
+++ b/core/java/android/content/pm/ComponentInfo.java
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import android.content.ComponentName;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -148,6 +149,11 @@
         return banner != 0 ? banner : applicationInfo.banner;
     }
 
+    /** {@hide} */
+    public ComponentName getComponentName() {
+        return new ComponentName(packageName, name);
+    }
+
     protected void dumpFront(Printer pw, String prefix) {
         super.dumpFront(pw, prefix);
         if (processName != null && !packageName.equals(processName)) {
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index 6586426..cc266c5 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -18,6 +18,7 @@
 
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.IOnAppsChangedListener;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
@@ -40,4 +41,5 @@
             in Bundle opts, in UserHandle user);
     boolean isPackageEnabled(String packageName, in UserHandle user);
     boolean isActivityEnabled(in ComponentName component, in UserHandle user);
+    ApplicationInfo getApplicationInfo(String packageName, int flags, in UserHandle user);
 }
diff --git a/core/java/android/content/pm/IOnAppsChangedListener.aidl b/core/java/android/content/pm/IOnAppsChangedListener.aidl
index 796b58d..1303696 100644
--- a/core/java/android/content/pm/IOnAppsChangedListener.aidl
+++ b/core/java/android/content/pm/IOnAppsChangedListener.aidl
@@ -27,4 +27,6 @@
     void onPackageChanged(in UserHandle user, String packageName);
     void onPackagesAvailable(in UserHandle user, in String[] packageNames, boolean replacing);
     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);
 }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 4d0d146..2c6b604 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -64,10 +64,8 @@
     void checkPackageStartable(String packageName, int userId);
     boolean isPackageAvailable(String packageName, int userId);
     PackageInfo getPackageInfo(String packageName, int flags, int userId);
-    int getPackageUid(String packageName, int userId);
-    int getPackageUidEtc(String packageName, int flags, int userId);
-    int[] getPackageGids(String packageName, int userId);
-    int[] getPackageGidsEtc(String packageName, int flags, int userId);
+    int getPackageUid(String packageName, int flags, int userId);
+    int[] getPackageGids(String packageName, int flags, int userId);
 
     String[] currentToCanonicalPackageNames(in String[] names);
     String[] canonicalToCurrentPackageNames(in String[] names);
@@ -296,6 +294,8 @@
     void restoreDefaultApps(in byte[] backup, int userId);
     byte[] getIntentFilterVerificationBackup(int userId);
     void restoreIntentFilterVerification(in byte[] backup, int userId);
+    byte[] getPermissionGrantBackup(int userId);
+    void restorePermissionGrants(in byte[] backup, int userId);
 
     /**
      * Report the set of 'Home' activity candidates, plus (if any) which of them
@@ -429,6 +429,12 @@
     void performFstrimIfNeeded();
 
     /**
+     * Ask the package manager to extract packages if needed, to save
+     * the VM unzipping the APK in memory during launch.
+     */
+    void extractPackagesIfNeeded();
+
+    /**
      * Notify the package manager that a package is going to be used.
      */
     void notifyPackageUse(String packageName);
@@ -523,4 +529,6 @@
     boolean setEphemeralApplicationCookie(String packageName, in byte[] cookie, int userId);
     Bitmap getEphemeralApplicationIcon(String packageName, int userId);
     boolean isEphemeralApplication(String packageName, int userId);
+
+    boolean setRequiredForSystemUser(String packageName, boolean systemUserApp);
 }
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 6e67af4..8c7d327 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -21,6 +21,7 @@
 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;
@@ -123,6 +124,30 @@
          */
         abstract public void onPackagesUnavailable(String[] packageNames, UserHandle user,
                 boolean replacing);
+
+        /**
+         * Indicates that one or more packages have been suspended. For
+         * example, this can happen when a Device Administrator suspends
+         * an applicaton.
+         *
+         * @param packageNames The names of the packages that have just been
+         *            suspended.
+         * @param user The UserHandle of the profile that generated the change.
+         */
+        public void onPackagesSuspended(String[] packageNames, UserHandle user) {
+        }
+
+        /**
+         * Indicates that one or more packages have been unsuspended. For
+         * example, this can happen when a Device Administrator unsuspends
+         * an applicaton.
+         *
+         * @param packageNames The names of the packages that have just been
+         *            unsuspended.
+         * @param user The UserHandle of the profile that generated the change.
+         */
+        public void onPackagesUnsuspended(String[] packageNames, UserHandle user) {
+        }
     }
 
     /** @hide */
@@ -243,6 +268,25 @@
     }
 
     /**
+     * Retrieve all of the information we know about a particular package / application.
+     *
+     * @param packageName The package of the application
+     * @param flags Additional option flags {@link PackageManager#getApplicationInfo}
+     * @param user The UserHandle of the profile.
+     *
+     * @return An {@link ApplicationInfo} containing information about the package or
+     *         null of the package isn't found.
+     */
+    public ApplicationInfo getApplicationInfo(String packageName, @ApplicationInfoFlags int flags,
+            UserHandle user) {
+        try {
+            return mService.getApplicationInfo(packageName, flags, user);
+        } catch (RemoteException re) {
+            throw new RuntimeException("Failed to call LauncherAppsService", re);
+        }
+    }
+
+    /**
      * Checks if the activity exists and it enabled for a profile.
      *
      * @param component The activity to check.
@@ -400,7 +444,33 @@
                 for (CallbackMessageHandler callback : mCallbacks) {
                     callback.postOnPackagesUnavailable(packageNames, user, replacing);
                 }
-           }
+            }
+        }
+
+        @Override
+        public void onPackagesSuspended(UserHandle user, String[] packageNames)
+                throws RemoteException {
+            if (DEBUG) {
+                Log.d(TAG, "onPackagesSuspended " + user.getIdentifier() + "," + packageNames);
+            }
+            synchronized (LauncherApps.this) {
+                for (CallbackMessageHandler callback : mCallbacks) {
+                    callback.postOnPackagesSuspended(packageNames, user);
+                }
+            }
+        }
+
+        @Override
+        public void onPackagesUnsuspended(UserHandle user, String[] packageNames)
+                throws RemoteException {
+            if (DEBUG) {
+                Log.d(TAG, "onPackagesUnsuspended " + user.getIdentifier() + "," + packageNames);
+            }
+            synchronized (LauncherApps.this) {
+                for (CallbackMessageHandler callback : mCallbacks) {
+                    callback.postOnPackagesUnsuspended(packageNames, user);
+                }
+            }
         }
     };
 
@@ -410,6 +480,8 @@
         private static final int MSG_CHANGED = 3;
         private static final int MSG_AVAILABLE = 4;
         private static final int MSG_UNAVAILABLE = 5;
+        private static final int MSG_SUSPENDED = 6;
+        private static final int MSG_UNSUSPENDED = 7;
 
         private LauncherApps.Callback mCallback;
 
@@ -447,6 +519,12 @@
                 case MSG_UNAVAILABLE:
                     mCallback.onPackagesUnavailable(info.packageNames, info.user, info.replacing);
                     break;
+                case MSG_SUSPENDED:
+                    mCallback.onPackagesSuspended(info.packageNames, info.user);
+                    break;
+                case MSG_UNSUSPENDED:
+                    mCallback.onPackagesUnsuspended(info.packageNames, info.user);
+                    break;
             }
         }
 
@@ -488,5 +566,19 @@
             info.user = user;
             obtainMessage(MSG_UNAVAILABLE, info).sendToTarget();
         }
+
+        public void postOnPackagesSuspended(String[] packageNames, UserHandle user) {
+            CallbackInfo info = new CallbackInfo();
+            info.packageNames = packageNames;
+            info.user = user;
+            obtainMessage(MSG_SUSPENDED, info).sendToTarget();
+        }
+
+        public void postOnPackagesUnsuspended(String[] packageNames, UserHandle user) {
+            CallbackInfo info = new CallbackInfo();
+            info.packageNames = packageNames;
+            info.user = user;
+            obtainMessage(MSG_UNSUSPENDED, info).sendToTarget();
+        }
     }
 }
diff --git a/core/java/android/content/pm/ManifestDigest.java b/core/java/android/content/pm/ManifestDigest.java
deleted file mode 100644
index e7dc764..0000000
--- a/core/java/android/content/pm/ManifestDigest.java
+++ /dev/null
@@ -1,147 +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 com.android.internal.util.HexDump;
-
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Slog;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.DigestInputStream;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.Arrays;
-
-import libcore.io.IoUtils;
-
-/**
- * Represents the manifest digest for a package. This is suitable for comparison
- * of two packages to know whether the manifests are identical.
- *
- * @hide
- */
-@SystemApi
-public class ManifestDigest implements Parcelable {
-    private static final String TAG = "ManifestDigest";
-
-    /** The digest of the manifest in our preferred order. */
-    private final byte[] mDigest;
-
-    /** What we print out first when toString() is called. */
-    private static final String TO_STRING_PREFIX = "ManifestDigest {mDigest=";
-
-    /** Digest algorithm to use. */
-    private static final String DIGEST_ALGORITHM = "SHA-256";
-
-    ManifestDigest(byte[] digest) {
-        mDigest = digest;
-    }
-
-    private ManifestDigest(Parcel source) {
-        mDigest = source.createByteArray();
-    }
-
-    static ManifestDigest fromInputStream(InputStream fileIs) {
-        if (fileIs == null) {
-            return null;
-        }
-
-        final MessageDigest md;
-        try {
-            md = MessageDigest.getInstance(DIGEST_ALGORITHM);
-        } catch (NoSuchAlgorithmException e) {
-            throw new RuntimeException(DIGEST_ALGORITHM + " must be available", e);
-        }
-
-        final DigestInputStream dis = new DigestInputStream(new BufferedInputStream(fileIs), md);
-        try {
-            byte[] readBuffer = new byte[8192];
-            while (dis.read(readBuffer, 0, readBuffer.length) != -1) {
-                // not using
-            }
-        } catch (IOException e) {
-            Slog.w(TAG, "Could not read manifest");
-            return null;
-        } finally {
-            IoUtils.closeQuietly(dis);
-        }
-
-        final byte[] digest = md.digest();
-        return new ManifestDigest(digest);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (!(o instanceof ManifestDigest)) {
-            return false;
-        }
-
-        final ManifestDigest other = (ManifestDigest) o;
-
-        return this == other || Arrays.equals(mDigest, other.mDigest);
-    }
-
-    @Override
-    public int hashCode() {
-        return Arrays.hashCode(mDigest);
-    }
-
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder(TO_STRING_PREFIX.length()
-                + (mDigest.length * 3) + 1);
-
-        sb.append(TO_STRING_PREFIX);
-
-        final int N = mDigest.length;
-        for (int i = 0; i < N; i++) {
-            final byte b = mDigest[i];
-            HexDump.appendByteAsHex(sb, b, false);
-            sb.append(',');
-        }
-        sb.append('}');
-
-        return sb.toString();
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeByteArray(mDigest);
-    }
-
-    public static final Parcelable.Creator<ManifestDigest> CREATOR
-            = new Parcelable.Creator<ManifestDigest>() {
-        public ManifestDigest createFromParcel(Parcel source) {
-            return new ManifestDigest(source);
-        }
-
-        public ManifestDigest[] newArray(int size) {
-            return new ManifestDigest[size];
-        }
-    };
-
-}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index d6d395b..3283005 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1042,12 +1042,6 @@
         }
 
         /** {@hide} */
-        @SystemApi
-        public void setInstallFlagsQuick() {
-            installFlags |= PackageManager.INSTALL_QUICK;
-        }
-
-        /** {@hide} */
         public void dump(IndentingPrintWriter pw) {
             pw.printPair("mode", mode);
             pw.printHexPair("installFlags", installFlags);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 3e7deb9..3a94bf7 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -27,6 +27,8 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.StringRes;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.annotation.UserIdInt;
 import android.annotation.XmlRes;
 import android.app.PackageDeleteObserver;
 import android.app.PackageInstallObserver;
@@ -47,10 +49,9 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.storage.VolumeInfo;
-import android.provider.Settings;
 import android.util.AndroidException;
-
 import android.util.Log;
+
 import com.android.internal.util.ArrayUtils;
 
 import java.io.File;
@@ -65,6 +66,7 @@
  * You can find this class through {@link Context#getPackageManager}.
  */
 public abstract class PackageManager {
+    private static final String TAG = "PackageManager";
 
     /**
      * This exception is thrown when a given package, application, or component
@@ -95,6 +97,110 @@
     }
 
     /**
+     * As a guiding principle:
+     * <p>
+     * {@code GET_} flags are used to request additional data that may have been
+     * elided to save wire space.
+     * <p>
+     * {@code MATCH_} flags are used to include components or packages that
+     * would have otherwise been omitted from a result set by current system
+     * state.
+     */
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            GET_ACTIVITIES,
+            GET_CONFIGURATIONS,
+            GET_GIDS,
+            GET_INSTRUMENTATION,
+            GET_INTENT_FILTERS,
+            GET_META_DATA,
+            GET_PERMISSIONS,
+            GET_PROVIDERS,
+            GET_RECEIVERS,
+            GET_SERVICES,
+            GET_SHARED_LIBRARY_FILES,
+            GET_SIGNATURES,
+            GET_URI_PERMISSION_PATTERNS,
+            MATCH_UNINSTALLED_PACKAGES,
+            MATCH_DISABLED_COMPONENTS,
+            MATCH_DISABLED_UNTIL_USED_COMPONENTS,
+            MATCH_SYSTEM_ONLY,
+            MATCH_DEBUG_TRIAGED_MISSING,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PackageInfoFlags {}
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            GET_META_DATA,
+            GET_SHARED_LIBRARY_FILES,
+            MATCH_UNINSTALLED_PACKAGES,
+            MATCH_SYSTEM_ONLY,
+            MATCH_DEBUG_TRIAGED_MISSING,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ApplicationInfoFlags {}
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            GET_META_DATA,
+            GET_SHARED_LIBRARY_FILES,
+            MATCH_ALL,
+            MATCH_DEBUG_TRIAGED_MISSING,
+            MATCH_DEFAULT_ONLY,
+            MATCH_DISABLED_COMPONENTS,
+            MATCH_DISABLED_UNTIL_USED_COMPONENTS,
+            MATCH_ENCRYPTION_AWARE,
+            MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
+            MATCH_ENCRYPTION_UNAWARE,
+            MATCH_SYSTEM_ONLY,
+            MATCH_UNINSTALLED_PACKAGES,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ComponentInfoFlags {}
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            GET_META_DATA,
+            GET_RESOLVED_FILTER,
+            GET_SHARED_LIBRARY_FILES,
+            MATCH_ALL,
+            MATCH_DEBUG_TRIAGED_MISSING,
+            MATCH_DISABLED_COMPONENTS,
+            MATCH_DISABLED_UNTIL_USED_COMPONENTS,
+            MATCH_DEFAULT_ONLY,
+            MATCH_ENCRYPTION_AWARE,
+            MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
+            MATCH_ENCRYPTION_UNAWARE,
+            MATCH_SYSTEM_ONLY,
+            MATCH_UNINSTALLED_PACKAGES,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ResolveInfoFlags {}
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            GET_META_DATA,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PermissionInfoFlags {}
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            GET_META_DATA,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PermissionGroupInfoFlags {}
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            GET_META_DATA,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface InstrumentationInfoFlags {}
+
+    /**
      * {@link PackageInfo} flag: return information about
      * activities in the package in {@link PackageInfo#activities}.
      */
@@ -163,9 +269,15 @@
     public static final int GET_GIDS                    = 0x00000100;
 
     /**
+     * @deprecated replaced with {@link #MATCH_DISABLED_COMPONENTS}
+     */
+    @Deprecated
+    public static final int GET_DISABLED_COMPONENTS = 0x00000200;
+
+    /**
      * {@link PackageInfo} flag: include disabled components in the returned info.
      */
-    public static final int GET_DISABLED_COMPONENTS     = 0x00000200;
+    public static final int MATCH_DISABLED_COMPONENTS = 0x00000200;
 
     /**
      * {@link ApplicationInfo} flag: return the
@@ -192,6 +304,12 @@
     public static final int GET_PERMISSIONS               = 0x00001000;
 
     /**
+     * @deprecated replaced with {@link #MATCH_UNINSTALLED_PACKAGES}
+     */
+    @Deprecated
+    public static final int GET_UNINSTALLED_PACKAGES = 0x00002000;
+
+    /**
      * Flag parameter to retrieve some information about all applications (even
      * uninstalled ones) which have data directories. This state could have
      * resulted if applications have been deleted with flag
@@ -201,7 +319,7 @@
      * Note: this flag may cause less information about currently installed
      * applications to be returned.
      */
-    public static final int GET_UNINSTALLED_PACKAGES = 0x00002000;
+    public static final int MATCH_UNINSTALLED_PACKAGES = 0x00002000;
 
     /**
      * {@link PackageInfo} flag: return information about
@@ -213,12 +331,18 @@
     public static final int GET_CONFIGURATIONS = 0x00004000;
 
     /**
+     * @deprecated replaced with {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}.
+     */
+    @Deprecated
+    public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 0x00008000;
+
+    /**
      * {@link PackageInfo} flag: include disabled components which are in
      * that state only because of {@link #COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED}
      * in the returned info.  Note that if you set this flag, applications
      * that are in this disabled state will be reported as enabled.
      */
-    public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 0x00008000;
+    public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 0x00008000;
 
     /**
      * Resolution and querying flag: if set, only filters that support the
@@ -229,40 +353,68 @@
     public static final int MATCH_DEFAULT_ONLY  = 0x00010000;
 
     /**
-     * Querying flag: if set and if the platform is doing any filtering of the results, then
-     * the filtering will not happen. This is a synonym for saying that all results should
-     * be returned.
+     * Querying flag: if set and if the platform is doing any filtering of the
+     * results, then the filtering will not happen. This is a synonym for saying
+     * that all results should be returned.
+     * <p>
+     * <em>This flag should be used with extreme care.</em>
      */
     public static final int MATCH_ALL = 0x00020000;
 
     /**
-     * {@link PackageInfo} flag: include components which aren't encryption
-     * aware in the returned info, regardless of the current user state.
+     * Querying flag: include only components which are encryption unaware in
+     * the returned info, regardless of the current user state.
      */
-    public static final int GET_ENCRYPTION_UNAWARE_COMPONENTS = 0x00040000;
+    public static final int MATCH_ENCRYPTION_UNAWARE = 0x00040000;
 
     /**
-     * {@link PackageInfo} flag: return components that are marked as
-     * {@link ComponentInfo#encryptionAware}, unless
-     * {@link #GET_ENCRYPTION_UNAWARE_COMPONENTS} is also specified.
-     * <p>
-     * This flag is for internal use only.
+     * Querying flag: include only components which are encryption aware in the
+     * returned info, regardless of the current user state.
+     */
+    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.
+     */
+    public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = MATCH_ENCRYPTION_AWARE
+            | MATCH_ENCRYPTION_UNAWARE;
+
+    /**
+     * Querying flag: include only components from applications that are marked
+     * with {@link ApplicationInfo#FLAG_SYSTEM}.
+     */
+    public static final int MATCH_SYSTEM_ONLY = 0x00100000;
+
+    /**
+     * 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:
+     * <ul>
+     * <li>Apps installed on external storage, which will appear to be
+     * uninstalled while the the device is ejected.
+     * <li>Apps with encryption unaware components, which will appear to not
+     * exist while the device is locked.
+     * </ul>
      *
+     * @see #MATCH_UNINSTALLED_PACKAGES
+     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
      * @hide
      */
-    public static final int MATCH_ENCRYPTION_AWARE_ONLY = 0x00080000;
+    public static final int MATCH_DEBUG_TRIAGED_MISSING = 0x10000000;
 
     /**
-     * Flag for {@link addCrossProfileIntentFilter}: if this flag is set:
-     * when resolving an intent that matches the {@link CrossProfileIntentFilter}, the current
-     * profile will be skipped.
-     * Only activities in the target user can respond to the intent.
+     * Flag for {@link #addCrossProfileIntentFilter}: if this flag is set: when
+     * resolving an intent that matches the {@code CrossProfileIntentFilter},
+     * the current profile will be skipped. Only activities in the target user
+     * can respond to the intent.
+     *
      * @hide
      */
     public static final int SKIP_CURRENT_PROFILE = 0x00000002;
 
     /**
-     * Flag for {@link addCrossProfileIntentFilter}: if this flag is set:
+     * Flag for {@link #addCrossProfileIntentFilter}: if this flag is set:
      * activities in the other profiles can respond to the intent only if no activity with
      * non-negative priority in current profile can respond to the intent.
      * @hide
@@ -369,17 +521,37 @@
      */
     public static final int COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED = 4;
 
+    /** @hide */
+    @IntDef(flag = true, value = {
+            INSTALL_FORWARD_LOCK,
+            INSTALL_REPLACE_EXISTING,
+            INSTALL_ALLOW_TEST,
+            INSTALL_EXTERNAL,
+            INSTALL_INTERNAL,
+            INSTALL_FROM_ADB,
+            INSTALL_ALL_USERS,
+            INSTALL_ALLOW_DOWNGRADE,
+            INSTALL_GRANT_RUNTIME_PERMISSIONS,
+            INSTALL_FORCE_VOLUME_UUID,
+            INSTALL_FORCE_PERMISSION_PROMPT,
+            INSTALL_EPHEMERAL,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface InstallFlags {}
+
     /**
-     * Flag parameter for {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} to
-     * indicate that this package should be installed as forward locked, i.e. only the app itself
-     * should have access to its code and non-resource assets.
+     * Flag parameter for {@link #installPackage} to indicate that this package
+     * should be installed as forward locked, i.e. only the app itself should
+     * have access to its code and non-resource assets.
+     *
      * @hide
      */
     public static final int INSTALL_FORWARD_LOCK = 0x00000001;
 
     /**
-     * Flag parameter for {@link #installPackage} to indicate that you want to replace an already
-     * installed package, if one exists.
+     * Flag parameter for {@link #installPackage} to indicate that you want to
+     * replace an already installed package, if one exists.
+     *
      * @hide
      */
     public static final int INSTALL_REPLACE_EXISTING = 0x00000002;
@@ -457,19 +629,11 @@
 
     /**
      * Flag parameter for {@link #installPackage} to indicate that this package is
-     * to be installed quickly.
-     *
-     * @hide
-     */
-    public static final int INSTALL_QUICK = 0x00000800;
-
-    /**
-     * Flag parameter for {@link #installPackage} to indicate that this package is
      * to be installed as a lightweight "ephemeral" app.
      *
      * @hide
      */
-    public static final int INSTALL_EPHEMERAL = 0x00001000;
+    public static final int INSTALL_EPHEMERAL = 0x00000800;
 
     /**
      * Flag parameter for
@@ -480,170 +644,181 @@
     public static final int DONT_KILL_APP = 0x00000001;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} on success.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} on success.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_SUCCEEDED = 1;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if the package is
-     * already installed.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the package is already installed.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_ALREADY_EXISTS = -1;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if the package archive
-     * file is invalid.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the package archive file is invalid.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_INVALID_APK = -2;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if the URI passed in
-     * is invalid.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the URI passed in is invalid.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_INVALID_URI = -3;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if the package manager
-     * service found that the device didn't have enough storage space to install the app.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the package manager service found that
+     * the device didn't have enough storage space to install the app.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_INSUFFICIENT_STORAGE = -4;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if a
-     * package is already installed with the same name.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if a package is already installed with
+     * the same name.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_DUPLICATE_PACKAGE = -5;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the requested shared user does not exist.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the requested shared user does not
+     * exist.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_NO_SHARED_USER = -6;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * a previously installed package of the same name has a different signature
-     * than the new package (and the old package's data was not removed).
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if a previously installed package of the
+     * same name has a different signature than the new package (and the old
+     * package's data was not removed).
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_UPDATE_INCOMPATIBLE = -7;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the new package is requested a shared user which is already installed on the
-     * device and does not have matching signature.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the new package is requested a shared
+     * user which is already installed on the device and does not have matching
+     * signature.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_SHARED_USER_INCOMPATIBLE = -8;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the new package uses a shared library that is not available.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the new package uses a shared library
+     * that is not available.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_MISSING_SHARED_LIBRARY = -9;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the new package uses a shared library that is not available.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the new package uses a shared library
+     * that is not available.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_REPLACE_COULDNT_DELETE = -10;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the new package failed while optimizing and validating its dex files,
-     * either because there was not enough storage or the validation failed.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the new package failed while
+     * optimizing and validating its dex files, either because there was not
+     * enough storage or the validation failed.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_DEXOPT = -11;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the new package failed because the current SDK version is older than
-     * that required by the package.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the new package failed because the
+     * current SDK version is older than that required by the package.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_OLDER_SDK = -12;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the new package failed because it contains a content provider with the
-     * same authority as a provider already installed in the system.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the new package failed because it
+     * contains a content provider with the same authority as a provider already
+     * installed in the system.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_CONFLICTING_PROVIDER = -13;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the new package failed because the current SDK version is newer than
-     * that required by the package.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the new package failed because the
+     * current SDK version is newer than that required by the package.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_NEWER_SDK = -14;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the new package failed because it has specified that it is a test-only
-     * package and the caller has not supplied the {@link #INSTALL_ALLOW_TEST}
-     * flag.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the new package failed because it has
+     * specified that it is a test-only package and the caller has not supplied
+     * the {@link #INSTALL_ALLOW_TEST} flag.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_TEST_ONLY = -15;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the package being installed contains native code, but none that is
-     * compatible with the device's CPU_ABI.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the package being installed contains
+     * native code, but none that is compatible with the device's CPU_ABI.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_CPU_ABI_INCOMPATIBLE = -16;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the new package uses a feature that is not available.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the new package uses a feature that is
+     * not available.
+     *
      * @hide
      */
     @SystemApi
@@ -651,217 +826,234 @@
 
     // ------ Errors related to sdcard
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * a secure container mount point couldn't be accessed on external media.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if a secure container mount point
+     * couldn't be accessed on external media.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_CONTAINER_ERROR = -18;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the new package couldn't be installed in the specified install
-     * location.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the new package couldn't be installed
+     * in the specified install location.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_INVALID_INSTALL_LOCATION = -19;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the new package couldn't be installed in the specified install
-     * location because the media is not available.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the new package couldn't be installed
+     * in the specified install location because the media is not available.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_MEDIA_UNAVAILABLE = -20;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the new package couldn't be installed because the verification timed out.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the new package couldn't be installed
+     * because the verification timed out.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_VERIFICATION_TIMEOUT = -21;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the new package couldn't be installed because the verification did not succeed.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the new package couldn't be installed
+     * because the verification did not succeed.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_VERIFICATION_FAILURE = -22;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the package changed from what the calling program expected.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the package changed from what the
+     * calling program expected.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_PACKAGE_CHANGED = -23;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the new package is assigned a different UID than it previously held.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the new package is assigned a
+     * different UID than it previously held.
+     *
      * @hide
      */
     public static final int INSTALL_FAILED_UID_CHANGED = -24;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the new package has an older version code than the currently installed package.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the new package has an older version
+     * code than the currently installed package.
+     *
      * @hide
      */
     public static final int INSTALL_FAILED_VERSION_DOWNGRADE = -25;
 
     /**
-     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
-     * the old package has target SDK high enough to support runtime permission and
-     * the new package has target SDK low enough to not support runtime permissions.
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the old package has target SDK high
+     * enough to support runtime permission and the new package has target SDK
+     * low enough to not support runtime permissions.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE = -26;
 
     /**
-     * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
-     * if the parser was given a path that is not a file, or does not end with the expected
-     * '.apk' extension.
+     * Installation parse return code: this is passed to the
+     * {@link IPackageInstallObserver} if the parser was given a path that is
+     * not a file, or does not end with the expected '.apk' extension.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_PARSE_FAILED_NOT_APK = -100;
 
     /**
-     * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
-     * if the parser was unable to retrieve the AndroidManifest.xml file.
+     * Installation parse return code: this is passed to the
+     * {@link IPackageInstallObserver} if the parser was unable to retrieve the
+     * AndroidManifest.xml file.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_PARSE_FAILED_BAD_MANIFEST = -101;
 
     /**
-     * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
-     * if the parser encountered an unexpected exception.
+     * Installation parse return code: this is passed to the
+     * {@link IPackageInstallObserver} if the parser encountered an unexpected
+     * exception.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102;
 
     /**
-     * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
-     * if the parser did not find any certificates in the .apk.
+     * Installation parse return code: this is passed to the
+     * {@link IPackageInstallObserver} if the parser did not find any
+     * certificates in the .apk.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_PARSE_FAILED_NO_CERTIFICATES = -103;
 
     /**
-     * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
-     * if the parser found inconsistent certificates on the files in the .apk.
+     * Installation parse return code: this is passed to the
+     * {@link IPackageInstallObserver} if the parser found inconsistent
+     * certificates on the files in the .apk.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES = -104;
 
     /**
-     * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
-     * if the parser encountered a CertificateEncodingException in one of the
-     * files in the .apk.
+     * Installation parse return code: this is passed to the
+     * {@link IPackageInstallObserver} if the parser encountered a
+     * CertificateEncodingException in one of the files in the .apk.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING = -105;
 
     /**
-     * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
-     * if the parser encountered a bad or missing package name in the manifest.
+     * Installation parse return code: this is passed to the
+     * {@link IPackageInstallObserver} if the parser encountered a bad or
+     * missing package name in the manifest.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME = -106;
 
     /**
-     * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
-     * if the parser encountered a bad shared user id name in the manifest.
+     * Installation parse return code: this is passed to the
+     * {@link IPackageInstallObserver} if the parser encountered a bad shared
+     * user id name in the manifest.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID = -107;
 
     /**
-     * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
-     * if the parser encountered some structural problem in the manifest.
+     * Installation parse return code: this is passed to the
+     * {@link IPackageInstallObserver} if the parser encountered some structural
+     * problem in the manifest.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_PARSE_FAILED_MANIFEST_MALFORMED = -108;
 
     /**
-     * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
-     * if the parser did not find any actionable tags (instrumentation or application)
-     * in the manifest.
+     * Installation parse return code: this is passed to the
+     * {@link IPackageInstallObserver} if the parser did not find any actionable
+     * tags (instrumentation or application) in the manifest.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_PARSE_FAILED_MANIFEST_EMPTY = -109;
 
     /**
-     * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
-     * if the system failed to install the package because of system issues.
+     * Installation failed return code: this is passed to the
+     * {@link IPackageInstallObserver} if the system failed to install the
+     * package because of system issues.
+     *
      * @hide
      */
     @SystemApi
     public static final int INSTALL_FAILED_INTERNAL_ERROR = -110;
 
     /**
-     * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
-     * if the system failed to install the package because the user is restricted from installing
-     * apps.
+     * Installation failed return code: this is passed to the
+     * {@link IPackageInstallObserver} if the system failed to install the
+     * package because the user is restricted from installing apps.
+     *
      * @hide
      */
     public static final int INSTALL_FAILED_USER_RESTRICTED = -111;
 
     /**
-     * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
-     * if the system failed to install the package because it is attempting to define a
-     * permission that is already defined by some existing package.
+     * Installation failed return code: this is passed to the
+     * {@link IPackageInstallObserver} if the system failed to install the
+     * package because it is attempting to define a permission that is already
+     * defined by some existing package.
+     * <p>
+     * The package name of the app which has already defined the permission is
+     * passed to a {@link PackageInstallObserver}, if any, as the
+     * {@link #EXTRA_FAILURE_EXISTING_PACKAGE} string extra; and the name of the
+     * permission being redefined is passed in the
+     * {@link #EXTRA_FAILURE_EXISTING_PERMISSION} string extra.
      *
-     * <p>The package name of the app which has already defined the permission is passed to
-     * a {@link PackageInstallObserver}, if any, as the {@link #EXTRA_EXISTING_PACKAGE}
-     * string extra; and the name of the permission being redefined is passed in the
-     * {@link #EXTRA_EXISTING_PERMISSION} string extra.
      * @hide
      */
     public static final int INSTALL_FAILED_DUPLICATE_PERMISSION = -112;
 
     /**
-     * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by
-     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
-     * if the system failed to install the package because its packaged native code did not
-     * match any of the ABIs supported by the system.
+     * Installation failed return code: this is passed to the
+     * {@link IPackageInstallObserver} if the system failed to install the
+     * package because its packaged native code did not match any of the ABIs
+     * supported by the system.
      *
      * @hide
      */
@@ -887,6 +1079,15 @@
      */
     public static final int INSTALL_FAILED_EPHEMERAL_INVALID = -116;
 
+    /** @hide */
+    @IntDef(flag = true, value = {
+            DELETE_KEEP_DATA,
+            DELETE_ALL_USERS,
+            DELETE_SYSTEM_APP,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DeleteFlags {}
+
     /**
      * Flag parameter for {@link #deletePackage} to indicate that you don't want to delete the
      * package's data directory.
@@ -916,8 +1117,8 @@
 
     /**
      * Return code for when package deletion succeeds. This is passed to the
-     * {@link IPackageDeleteObserver} by {@link #deletePackage()} if the system
-     * succeeded in deleting the package.
+     * {@link IPackageDeleteObserver} if the system succeeded in deleting the
+     * package.
      *
      * @hide
      */
@@ -925,8 +1126,8 @@
 
     /**
      * Deletion failed return code: this is passed to the
-     * {@link IPackageDeleteObserver} by {@link #deletePackage()} if the system
-     * failed to delete the package for an unspecified reason.
+     * {@link IPackageDeleteObserver} if the system failed to delete the package
+     * for an unspecified reason.
      *
      * @hide
      */
@@ -934,9 +1135,8 @@
 
     /**
      * Deletion failed return code: this is passed to the
-     * {@link IPackageDeleteObserver} by {@link #deletePackage()} if the system
-     * failed to delete the package because it is the active DevicePolicy
-     * manager.
+     * {@link IPackageDeleteObserver} if the system failed to delete the package
+     * because it is the active DevicePolicy manager.
      *
      * @hide
      */
@@ -944,8 +1144,8 @@
 
     /**
      * Deletion failed return code: this is passed to the
-     * {@link IPackageDeleteObserver} by {@link #deletePackage()} if the system
-     * failed to delete the package since the user is restricted.
+     * {@link IPackageDeleteObserver} if the system failed to delete the package
+     * since the user is restricted.
      *
      * @hide
      */
@@ -953,9 +1153,9 @@
 
     /**
      * Deletion failed return code: this is passed to the
-     * {@link IPackageDeleteObserver} by {@link #deletePackage()} if the system
-     * failed to delete the package because a profile
-     * or device owner has marked the package as uninstallable.
+     * {@link IPackageDeleteObserver} if the system failed to delete the package
+     * because a profile or device owner has marked the package as
+     * uninstallable.
      *
      * @hide
      */
@@ -965,8 +1165,7 @@
     public static final int DELETE_FAILED_ABORTED = -5;
 
     /**
-     * Return code that is passed to the {@link IPackageMoveObserver} by
-     * {@link #movePackage(android.net.Uri, IPackageMoveObserver)} when the
+     * Return code that is passed to the {@link IPackageMoveObserver} when the
      * package has been successfully moved by the system.
      *
      * @hide
@@ -974,59 +1173,57 @@
     public static final int MOVE_SUCCEEDED = -100;
 
     /**
-     * Error code that is passed to the {@link IPackageMoveObserver} by
-     * {@link #movePackage(android.net.Uri, IPackageMoveObserver)}
-     * when the package hasn't been successfully moved by the system
-     * because of insufficient memory on specified media.
+     * Error code that is passed to the {@link IPackageMoveObserver} when the
+     * package hasn't been successfully moved by the system because of
+     * insufficient memory on specified media.
+     *
      * @hide
      */
     public static final int MOVE_FAILED_INSUFFICIENT_STORAGE = -1;
 
     /**
-     * Error code that is passed to the {@link IPackageMoveObserver} by
-     * {@link #movePackage(android.net.Uri, IPackageMoveObserver)}
-     * if the specified package doesn't exist.
+     * Error code that is passed to the {@link IPackageMoveObserver} if the
+     * specified package doesn't exist.
+     *
      * @hide
      */
     public static final int MOVE_FAILED_DOESNT_EXIST = -2;
 
     /**
-     * Error code that is passed to the {@link IPackageMoveObserver} by
-     * {@link #movePackage(android.net.Uri, IPackageMoveObserver)}
-     * if the specified package cannot be moved since its a system package.
+     * Error code that is passed to the {@link IPackageMoveObserver} if the
+     * specified package cannot be moved since its a system package.
+     *
      * @hide
      */
     public static final int MOVE_FAILED_SYSTEM_PACKAGE = -3;
 
     /**
-     * Error code that is passed to the {@link IPackageMoveObserver} by
-     * {@link #movePackage(android.net.Uri, IPackageMoveObserver)}
-     * if the specified package cannot be moved since its forward locked.
+     * Error code that is passed to the {@link IPackageMoveObserver} if the
+     * specified package cannot be moved since its forward locked.
+     *
      * @hide
      */
     public static final int MOVE_FAILED_FORWARD_LOCKED = -4;
 
     /**
-     * Error code that is passed to the {@link IPackageMoveObserver} by
-     * {@link #movePackage(android.net.Uri, IPackageMoveObserver)}
-     * if the specified package cannot be moved to the specified location.
+     * Error code that is passed to the {@link IPackageMoveObserver} if the
+     * specified package cannot be moved to the specified location.
+     *
      * @hide
      */
     public static final int MOVE_FAILED_INVALID_LOCATION = -5;
 
     /**
-     * Error code that is passed to the {@link IPackageMoveObserver} by
-     * {@link #movePackage(android.net.Uri, IPackageMoveObserver)}
-     * if the specified package cannot be moved to the specified location.
+     * Error code that is passed to the {@link IPackageMoveObserver} if the
+     * specified package cannot be moved to the specified location.
+     *
      * @hide
      */
     public static final int MOVE_FAILED_INTERNAL_ERROR = -6;
 
     /**
-     * Error code that is passed to the {@link IPackageMoveObserver} by
-     * {@link #movePackage(android.net.Uri, IPackageMoveObserver)} if the
-     * specified package already has an operation pending in the
-     * {@link PackageHandler} queue.
+     * Error code that is passed to the {@link IPackageMoveObserver} if the
+     * specified package already has an operation pending in the queue.
      *
      * @hide
      */
@@ -1102,28 +1299,31 @@
     public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED = 0;
 
     /**
-     * Used as the {@code status} argument for {@link PackageManager#updateIntentVerificationStatus}
-     * to indicate that the User will always be prompted the Intent Disambiguation Dialog if there
-     * are two or more Intent resolved for the IntentFilter's domain(s).
+     * Used as the {@code status} argument for
+     * {@link #updateIntentVerificationStatusAsUser} to indicate that the User
+     * will always be prompted the Intent Disambiguation Dialog if there are two
+     * or more Intent resolved for the IntentFilter's domain(s).
      *
      * @hide
      */
     public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK = 1;
 
     /**
-     * Used as the {@code status} argument for {@link PackageManager#updateIntentVerificationStatus}
-     * to indicate that the User will never be prompted the Intent Disambiguation Dialog if there
-     * are two or more resolution of the Intent. The default App for the domain(s) specified in the
-     * IntentFilter will also ALWAYS be used.
+     * Used as the {@code status} argument for
+     * {@link #updateIntentVerificationStatusAsUser} to indicate that the User
+     * will never be prompted the Intent Disambiguation Dialog if there are two
+     * or more resolution of the Intent. The default App for the domain(s)
+     * specified in the IntentFilter will also ALWAYS be used.
      *
      * @hide
      */
     public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS = 2;
 
     /**
-     * Used as the {@code status} argument for {@link PackageManager#updateIntentVerificationStatus}
-     * to indicate that the User may be prompted the Intent Disambiguation Dialog if there
-     * are two or more Intent resolved. The default App for the domain(s) specified in the
+     * Used as the {@code status} argument for
+     * {@link #updateIntentVerificationStatusAsUser} to indicate that the User
+     * may be prompted the Intent Disambiguation Dialog if there are two or more
+     * Intent resolved. The default App for the domain(s) specified in the
      * IntentFilter will also NEVER be presented to the User.
      *
      * @hide
@@ -1131,12 +1331,13 @@
     public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER = 3;
 
     /**
-     * Used as the {@code status} argument for {@link PackageManager#updateIntentVerificationStatus}
-     * to indicate that this app should always be considered as an ambiguous candidate for
-     * handling the matching Intent even if there are other candidate apps in the "always"
-     * state.  Put another way: if there are any 'always ask' apps in a set of more than
-     * one candidate app, then a disambiguation is *always* presented even if there is
-     * another candidate app with the 'always' state.
+     * Used as the {@code status} argument for
+     * {@link #updateIntentVerificationStatusAsUser} to indicate that this app
+     * should always be considered as an ambiguous candidate for handling the
+     * matching Intent even if there are other candidate apps in the "always"
+     * state. Put another way: if there are any 'always ask' apps in a set of
+     * more than one candidate app, then a disambiguation is *always* presented
+     * even if there is another candidate app with the 'always' state.
      *
      * @hide
      */
@@ -1344,6 +1545,14 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports host-
+     * based NFC-F card emulation.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_NFC_HOST_CARD_EMULATION_NFCF = "android.hardware.nfc.hcef";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device supports the OpenGL ES
      * <a href="http://www.khronos.org/registry/gles/extensions/ANDROID/ANDROID_extension_pack_es31a.txt">
      * Android Extension Pack</a>.
@@ -1701,6 +1910,16 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports Wi-Fi Aware (NAN)
+     * networking.
+     *
+     * @hide PROPOSED_NAN_API
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_WIFI_NAN = "android.hardware.wifi.nan";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: This is a device dedicated to showing UI
      * on a vehicle headunit. A headunit here is defined to be inside a
      * vehicle that may or may not be moving. A headunit uses either a
@@ -1798,6 +2017,11 @@
     public static final String FEATURE_SECURELY_REMOVES_USERS
             = "android.software.securely_removes_users";
 
+    /** {@hide} */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_FILE_BASED_ENCRYPTION
+            = "android.software.file_based_encryption";
+
     /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
      * The device has a full implementation of the android.webkit.* APIs. Devices
@@ -1809,7 +2033,6 @@
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: This device supports ethernet.
-     * @hide
      */
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_ETHERNET = "android.hardware.ethernet";
@@ -1838,6 +2061,16 @@
     public static final String FEATURE_MIDI = "android.software.midi";
 
     /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+     * The device implements a an optimized mode for virtual reality (VR) applications that handles
+     * stereoscopic rendering of notifications, and may potentially also include optimizations to
+     * reduce latency in the graphics, display, and sensor stacks.  Presence of this feature
+     * also indicates that the VrCore library is included on this device.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_VR_MODE = "android.software.vr.mode";
+
+    /**
      * Action to external storage service to clean out removed apps.
      * @hide
      */
@@ -1910,9 +2143,9 @@
             = "android.content.pm.extra.VERIFICATION_VERSION_CODE";
 
     /**
-     * Extra field name for the ID of a intent filter pending verification. Passed to
-     * an intent filter verifier and is used to call back to
-     * {@link PackageManager#verifyIntentFilter(int, int)}
+     * Extra field name for the ID of a intent filter pending verification.
+     * Passed to an intent filter verifier and is used to call back to
+     * {@link #verifyIntentFilter}
      *
      * @hide
      */
@@ -2080,79 +2313,99 @@
     /**
      * Retrieve overall information about an application package that is
      * installed on the system.
-     * <p>
-     * Throws {@link NameNotFoundException} if a package with the given name can
-     * not be found on the system.
      *
      * @param packageName The full name (i.e. com.google.apps.contacts) of the
-     *            desired package.
+     *         desired package.
      * @param flags Additional option flags. Use any combination of
-     *            {@link #GET_ACTIVITIES}, {@link #GET_GIDS},
-     *            {@link #GET_CONFIGURATIONS}, {@link #GET_INSTRUMENTATION},
-     *            {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS},
-     *            {@link #GET_RECEIVERS}, {@link #GET_SERVICES},
-     *            {@link #GET_SIGNATURES}, {@link #GET_UNINSTALLED_PACKAGES} to
-     *            modify the data returned.
+     *         {@link #GET_ACTIVITIES}, {@link #GET_CONFIGURATIONS},
+     *         {@link #GET_GIDS}, {@link #GET_INSTRUMENTATION},
+     *         {@link #GET_INTENT_FILTERS}, {@link #GET_META_DATA},
+     *         {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS},
+     *         {@link #GET_RECEIVERS}, {@link #GET_SERVICES},
+     *         {@link #GET_SHARED_LIBRARY_FILES}, {@link #GET_SIGNATURES},
+     *         {@link #GET_URI_PERMISSION_PATTERNS}, {@link #GET_UNINSTALLED_PACKAGES},
+     *         {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *         {@link #MATCH_UNINSTALLED_PACKAGES}
+     *         to modify the data returned.
+     *
      * @return A PackageInfo object containing information about the
-     *         package. If flag GET_UNINSTALLED_PACKAGES is set and if the
+     *         package. If flag {@code MATCH_UNINSTALLED_PACKAGES} is set and if the
      *         package is not found in the list of installed applications, the
      *         package information is retrieved from the list of uninstalled
      *         applications (which includes installed applications as well as
      *         applications with data directory i.e. applications which had been
      *         deleted with {@code DONT_DELETE_DATA} flag set).
+     * @throws NameNotFoundException if a package with the given name cannot be
+     *             found on the system.
      * @see #GET_ACTIVITIES
-     * @see #GET_GIDS
      * @see #GET_CONFIGURATIONS
+     * @see #GET_GIDS
      * @see #GET_INSTRUMENTATION
+     * @see #GET_INTENT_FILTERS
+     * @see #GET_META_DATA
      * @see #GET_PERMISSIONS
      * @see #GET_PROVIDERS
      * @see #GET_RECEIVERS
      * @see #GET_SERVICES
+     * @see #GET_SHARED_LIBRARY_FILES
      * @see #GET_SIGNATURES
-     * @see #GET_UNINSTALLED_PACKAGES
+     * @see #GET_URI_PERMISSION_PATTERNS
+     * @see #MATCH_DISABLED_COMPONENTS
+     * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
+     * @see #MATCH_UNINSTALLED_PACKAGES
      */
-    public abstract PackageInfo getPackageInfo(String packageName, int flags)
+    public abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags)
             throws NameNotFoundException;
 
     /**
      * @hide
      * Retrieve overall information about an application package that is
      * installed on the system.
-     * <p>
-     * Throws {@link NameNotFoundException} if a package with the given name can
-     * not be found on the system.
      *
      * @param packageName The full name (i.e. com.google.apps.contacts) of the
-     *            desired package.
+     *         desired package.
      * @param flags Additional option flags. Use any combination of
-     *            {@link #GET_ACTIVITIES}, {@link #GET_GIDS},
-     *            {@link #GET_CONFIGURATIONS}, {@link #GET_INSTRUMENTATION},
-     *            {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS},
-     *            {@link #GET_RECEIVERS}, {@link #GET_SERVICES},
-     *            {@link #GET_SIGNATURES}, {@link #GET_UNINSTALLED_PACKAGES} to
-     *            modify the data returned.
+     *         {@link #GET_ACTIVITIES}, {@link #GET_CONFIGURATIONS},
+     *         {@link #GET_GIDS}, {@link #GET_INSTRUMENTATION},
+     *         {@link #GET_INTENT_FILTERS}, {@link #GET_META_DATA},
+     *         {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS},
+     *         {@link #GET_RECEIVERS}, {@link #GET_SERVICES},
+     *         {@link #GET_SHARED_LIBRARY_FILES}, {@link #GET_SIGNATURES},
+     *         {@link #GET_URI_PERMISSION_PATTERNS}, {@link #GET_UNINSTALLED_PACKAGES},
+     *         {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *         {@link #MATCH_UNINSTALLED_PACKAGES}
+     *         to modify the data returned.
      * @param userId The user id.
+     *
      * @return A PackageInfo object containing information about the
-     *         package. If flag GET_UNINSTALLED_PACKAGES is set and if the
+     *         package. If flag {@code MATCH_UNINSTALLED_PACKAGES} is set and if the
      *         package is not found in the list of installed applications, the
      *         package information is retrieved from the list of uninstalled
      *         applications (which includes installed applications as well as
      *         applications with data directory i.e. applications which had been
      *         deleted with {@code DONT_DELETE_DATA} flag set).
+     * @throws NameNotFoundException if a package with the given name cannot be
+     *             found on the system.
      * @see #GET_ACTIVITIES
-     * @see #GET_GIDS
      * @see #GET_CONFIGURATIONS
+     * @see #GET_GIDS
      * @see #GET_INSTRUMENTATION
+     * @see #GET_INTENT_FILTERS
+     * @see #GET_META_DATA
      * @see #GET_PERMISSIONS
      * @see #GET_PROVIDERS
      * @see #GET_RECEIVERS
      * @see #GET_SERVICES
+     * @see #GET_SHARED_LIBRARY_FILES
      * @see #GET_SIGNATURES
-     * @see #GET_UNINSTALLED_PACKAGES
+     * @see #GET_URI_PERMISSION_PATTERNS
+     * @see #MATCH_DISABLED_COMPONENTS
+     * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
+     * @see #MATCH_UNINSTALLED_PACKAGES
      */
     @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
-    public abstract PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
-            throws NameNotFoundException;
+    public abstract PackageInfo getPackageInfoAsUser(String packageName,
+            @PackageInfoFlags int flags, @UserIdInt int userId) throws NameNotFoundException;
 
     /**
      * Map from the current package names in use on the device to whatever
@@ -2194,9 +2447,6 @@
      * through packages. The current implementation will look for a main
      * activity in the category {@link Intent#CATEGORY_LEANBACK_LAUNCHER}, or
      * return null if no main leanback activities are found.
-     * <p>
-     * Throws {@link NameNotFoundException} if a package with the given name
-     * cannot be found on the system.
      *
      * @param packageName The name of the package to inspect.
      * @return Returns either a fully-qualified Intent that can be used to launch
@@ -2208,325 +2458,456 @@
     /**
      * Return an array of all of the secondary group-ids that have been assigned
      * to a package.
-     * <p>
-     * Throws {@link NameNotFoundException} if a package with the given name
-     * cannot be found on the system.
      *
      * @param packageName The full name (i.e. com.google.apps.contacts) of the
-     *            desired package.
+     *         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.
      */
     public abstract int[] getPackageGids(String packageName)
             throws NameNotFoundException;
 
     /**
-     * @hide Return the uid associated with the given package name for the
-     * given user.
-     *
-     * <p>Throws {@link NameNotFoundException} if a package with the given
-     * name can not be found on the system.
+     * Return an array of all of the secondary group-ids that have been assigned
+     * to a package.
      *
      * @param packageName The full name (i.e. com.google.apps.contacts) of the
-     *                    desired package.
-     * @param userHandle The user handle identifier to look up the package under.
-     *
-     * @return Returns an integer uid who owns the given package name.
+     *            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.
      */
-    public abstract int getPackageUid(String packageName, int userHandle)
+    public abstract int[] getPackageGids(String packageName, @PackageInfoFlags int flags)
             throws NameNotFoundException;
 
     /**
+     * Return the UID associated with the given package name.
+     *
+     * @param packageName The full name (i.e. com.google.apps.contacts) of the
+     *            desired package.
+     * @return Returns an integer UID who owns the given package name.
+     * @throws NameNotFoundException if a package with the given name can not be
+     *             found on the system.
+     */
+    public abstract int getPackageUid(String packageName, @PackageInfoFlags int flags)
+            throws NameNotFoundException;
+
+    /**
+     * Return the UID associated with the given package name.
+     *
+     * @param packageName The full name (i.e. com.google.apps.contacts) of the
+     *            desired package.
+     * @param userId The user handle identifier to look up the package under.
+     * @return Returns an integer UID who owns the given package name.
+     * @throws NameNotFoundException if a package with the given name can not be
+     *             found on the system.
+     * @hide
+     */
+    public abstract int getPackageUidAsUser(String packageName, @UserIdInt int userId)
+            throws NameNotFoundException;
+
+    /**
+     * Return the UID associated with the given package name.
+     *
+     * @param packageName The full name (i.e. com.google.apps.contacts) of the
+     *            desired package.
+     * @param userId The user handle identifier to look up the package under.
+     * @return Returns an integer UID who owns the given package name.
+     * @throws NameNotFoundException if a package with the given name can not be
+     *             found on the system.
+     * @hide
+     */
+    public abstract int getPackageUidAsUser(String packageName, @PackageInfoFlags int flags,
+            @UserIdInt int userId) throws NameNotFoundException;
+
+    /**
      * Retrieve all of the information we know about a particular permission.
      *
-     * <p>Throws {@link NameNotFoundException} if a permission with the given
-     * name cannot be found on the system.
-     *
      * @param name The fully qualified name (i.e. com.google.permission.LOGIN)
-     *             of the permission you are interested in.
+     *         of the permission you are interested in.
      * @param flags Additional option flags.  Use {@link #GET_META_DATA} to
-     * retrieve any meta-data associated with the permission.
+     *         retrieve any meta-data associated with the permission.
      *
      * @return Returns a {@link PermissionInfo} containing information about the
      *         permission.
+     * @throws NameNotFoundException if a package with the given name cannot be
+     *             found on the system.
+     *
+     * @see #GET_META_DATA
      */
-    public abstract PermissionInfo getPermissionInfo(String name, int flags)
+    public abstract PermissionInfo getPermissionInfo(String name, @PermissionInfoFlags int flags)
             throws NameNotFoundException;
 
     /**
      * Query for all of the permissions associated with a particular group.
      *
-     * <p>Throws {@link NameNotFoundException} if the given group does not
-     * exist.
-     *
      * @param group The fully qualified name (i.e. com.google.permission.LOGIN)
-     *             of the permission group you are interested in.  Use null to
-     *             find all of the permissions not associated with a group.
+     *         of the permission group you are interested in.  Use null to
+     *         find all of the permissions not associated with a group.
      * @param flags Additional option flags.  Use {@link #GET_META_DATA} to
-     * retrieve any meta-data associated with the permissions.
+     *         retrieve any meta-data associated with the permissions.
      *
      * @return Returns a list of {@link PermissionInfo} containing information
-     * about all of the permissions in the given group.
+     *             about all of the permissions in the given group.
+     * @throws NameNotFoundException if a package with the given name cannot be
+     *             found on the system.
+     *
+     * @see #GET_META_DATA
      */
     public abstract List<PermissionInfo> queryPermissionsByGroup(String group,
-            int flags) throws NameNotFoundException;
+            @PermissionInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Retrieve all of the information we know about a particular group of
      * permissions.
      *
-     * <p>Throws {@link NameNotFoundException} if a permission group with the given
-     * name cannot be found on the system.
-     *
      * @param name The fully qualified name (i.e. com.google.permission_group.APPS)
-     *             of the permission you are interested in.
+     *         of the permission you are interested in.
      * @param flags Additional option flags.  Use {@link #GET_META_DATA} to
-     * retrieve any meta-data associated with the permission group.
+     *         retrieve any meta-data associated with the permission group.
      *
      * @return Returns a {@link PermissionGroupInfo} containing information
-     * about the permission.
+     *         about the permission.
+     * @throws NameNotFoundException if a package with the given name cannot be
+     *             found on the system.
+     *
+     * @see #GET_META_DATA
      */
     public abstract PermissionGroupInfo getPermissionGroupInfo(String name,
-            int flags) throws NameNotFoundException;
+            @PermissionGroupInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Retrieve all of the known permission groups in the system.
      *
      * @param flags Additional option flags.  Use {@link #GET_META_DATA} to
-     * retrieve any meta-data associated with the permission group.
+     *         retrieve any meta-data associated with the permission group.
      *
      * @return Returns a list of {@link PermissionGroupInfo} containing
-     * information about all of the known permission groups.
+     *         information about all of the known permission groups.
+     *
+     * @see #GET_META_DATA
      */
-    public abstract List<PermissionGroupInfo> getAllPermissionGroups(int flags);
+    public abstract List<PermissionGroupInfo> getAllPermissionGroups(
+            @PermissionGroupInfoFlags int flags);
 
     /**
      * Retrieve all of the information we know about a particular
      * package/application.
      *
-     * <p>Throws {@link NameNotFoundException} if an application with the given
-     * package name cannot be found on the system.
-     *
      * @param packageName The full name (i.e. com.google.apps.contacts) of an
-     *                    application.
+     *         application.
      * @param flags Additional option flags. Use any combination of
-     * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
-     * {@link #GET_UNINSTALLED_PACKAGES} to modify the data returned.
+     *         {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
+     *         {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES}
+     *         to modify the data returned.
      *
-     * @return  {@link ApplicationInfo} Returns ApplicationInfo object containing
-     *         information about the package.
-     *         If flag GET_UNINSTALLED_PACKAGES is set and  if the package is not
-     *         found in the list of installed applications,
-     *         the application information is retrieved from the
-     *         list of uninstalled applications(which includes
-     *         installed applications as well as applications
-     *         with data directory ie applications which had been
+     * @return An {@link ApplicationInfo} containing information about the
+     *         package. If flag {@code MATCH_UNINSTALLED_PACKAGES} is set and if the
+     *         package is not found in the list of installed applications, the
+     *         application information is retrieved from the list of uninstalled
+     *         applications (which includes installed applications as well as
+     *         applications with data directory i.e. applications which had been
      *         deleted with {@code DONT_DELETE_DATA} flag set).
+     * @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 #GET_UNINSTALLED_PACKAGES
+     * @see #MATCH_SYSTEM_ONLY
+     * @see #MATCH_UNINSTALLED_PACKAGES
      */
     public abstract ApplicationInfo getApplicationInfo(String packageName,
-            int flags) throws NameNotFoundException;
+            @ApplicationInfoFlags int flags) throws NameNotFoundException;
+
+    /** {@hide} */
+    public abstract ApplicationInfo getApplicationInfoAsUser(String packageName,
+            @ApplicationInfoFlags int flags, @UserIdInt int userId) throws NameNotFoundException;
 
     /**
      * Retrieve all of the information we know about a particular activity
      * class.
      *
-     * <p>Throws {@link NameNotFoundException} if an activity with the given
-     * class name cannot be found on the system.
-     *
      * @param component The full component name (i.e.
      * 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},
-     * to modify the data (in ApplicationInfo) 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_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 {@link ActivityInfo} containing information about the activity.
+     * @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_INTENT_FILTERS
      * @see #GET_META_DATA
      * @see #GET_SHARED_LIBRARY_FILES
+     * @see #MATCH_ALL
+     * @see #MATCH_DEBUG_TRIAGED_MISSING
+     * @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_SYSTEM_ONLY
+     * @see #MATCH_UNINSTALLED_PACKAGES
      */
     public abstract ActivityInfo getActivityInfo(ComponentName component,
-            int flags) throws NameNotFoundException;
+            @ComponentInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Retrieve all of the information we know about a particular receiver
      * class.
      *
-     * <p>Throws {@link NameNotFoundException} if a receiver with the given
-     * class name cannot be found on the system.
-     *
      * @param component The full component name (i.e.
      * 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},
-     * to modify the data returned.
+     * @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 {@link ActivityInfo} containing information about the receiver.
+     * @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_INTENT_FILTERS
      * @see #GET_META_DATA
      * @see #GET_SHARED_LIBRARY_FILES
+     * @see #MATCH_ALL
+     * @see #MATCH_DEBUG_TRIAGED_MISSING
+     * @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_SYSTEM_ONLY
+     * @see #MATCH_UNINSTALLED_PACKAGES
      */
     public abstract ActivityInfo getReceiverInfo(ComponentName component,
-            int flags) throws NameNotFoundException;
+            @ComponentInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Retrieve all of the information we know about a particular service
      * class.
      *
-     * <p>Throws {@link NameNotFoundException} if a service with the given
-     * class name cannot be found on the system.
-     *
      * @param component The full component name (i.e.
      * 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},
-     * to modify the data returned.
+     * @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 ServiceInfo containing information about the service.
+     * @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
+     * @see #MATCH_DEBUG_TRIAGED_MISSING
+     * @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_SYSTEM_ONLY
+     * @see #MATCH_UNINSTALLED_PACKAGES
      */
     public abstract ServiceInfo getServiceInfo(ComponentName component,
-            int flags) throws NameNotFoundException;
+            @ComponentInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Retrieve all of the information we know about a particular content
      * provider class.
      *
-     * <p>Throws {@link NameNotFoundException} if a provider with the given
-     * class name cannot be found on the system.
-     *
      * @param component The full component name (i.e.
      * 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},
-     * to modify the data returned.
+     * @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 ProviderInfo containing information about the service.
+     * @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
+     * @see #MATCH_DEBUG_TRIAGED_MISSING
+     * @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_SYSTEM_ONLY
+     * @see #MATCH_UNINSTALLED_PACKAGES
      */
     public abstract ProviderInfo getProviderInfo(ComponentName component,
-            int flags) throws NameNotFoundException;
+            @ComponentInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Return a List of all packages that are installed
      * on the device.
      *
      * @param flags Additional option flags. Use any combination of
-     * {@link #GET_ACTIVITIES},
-     * {@link #GET_GIDS},
-     * {@link #GET_CONFIGURATIONS},
-     * {@link #GET_INSTRUMENTATION},
-     * {@link #GET_PERMISSIONS},
-     * {@link #GET_PROVIDERS},
-     * {@link #GET_RECEIVERS},
-     * {@link #GET_SERVICES},
-     * {@link #GET_SIGNATURES},
-     * {@link #GET_UNINSTALLED_PACKAGES} to modify the data returned.
+     *         {@link #GET_ACTIVITIES}, {@link #GET_CONFIGURATIONS},
+     *         {@link #GET_GIDS}, {@link #GET_INSTRUMENTATION},
+     *         {@link #GET_INTENT_FILTERS}, {@link #GET_META_DATA},
+     *         {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS},
+     *         {@link #GET_RECEIVERS}, {@link #GET_SERVICES},
+     *         {@link #GET_SHARED_LIBRARY_FILES}, {@link #GET_SIGNATURES},
+     *         {@link #GET_URI_PERMISSION_PATTERNS}, {@link #GET_UNINSTALLED_PACKAGES},
+     *         {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *         {@link #MATCH_UNINSTALLED_PACKAGES}
+     *         to modify the data returned.
      *
-     * @return A List of PackageInfo objects, one for each package that is
-     *         installed on the device.  In the unlikely case of there being no
-     *         installed packages, an empty list is returned.
-     *         If flag GET_UNINSTALLED_PACKAGES is set, a list of all
-     *         applications including those deleted with {@code DONT_DELETE_DATA}
-     *         (partially installed apps with data directory) will be returned.
+     * @return A List of PackageInfo objects, one for each installed package,
+     *         containing information about the package.  In the unlikely case
+     *         there are no installed packages, an empty list is returned. If
+     *         flag {@code MATCH_UNINSTALLED_PACKAGES} is set, the package
+     *         information is retrieved from the list of uninstalled
+     *         applications (which includes installed applications as well as
+     *         applications with data directory i.e. applications which had been
+     *         deleted with {@code DONT_DELETE_DATA} flag set).
      *
      * @see #GET_ACTIVITIES
-     * @see #GET_GIDS
      * @see #GET_CONFIGURATIONS
+     * @see #GET_GIDS
      * @see #GET_INSTRUMENTATION
+     * @see #GET_INTENT_FILTERS
+     * @see #GET_META_DATA
      * @see #GET_PERMISSIONS
      * @see #GET_PROVIDERS
      * @see #GET_RECEIVERS
      * @see #GET_SERVICES
+     * @see #GET_SHARED_LIBRARY_FILES
      * @see #GET_SIGNATURES
-     * @see #GET_UNINSTALLED_PACKAGES
+     * @see #GET_URI_PERMISSION_PATTERNS
+     * @see #MATCH_DISABLED_COMPONENTS
+     * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
+     * @see #MATCH_UNINSTALLED_PACKAGES
      */
-    public abstract List<PackageInfo> getInstalledPackages(int flags);
+    public abstract List<PackageInfo> getInstalledPackages(@PackageInfoFlags int flags);
 
     /**
      * Return a List of all installed packages that are currently
      * holding any of the given permissions.
      *
      * @param flags Additional option flags. Use any combination of
-     * {@link #GET_ACTIVITIES},
-     * {@link #GET_GIDS},
-     * {@link #GET_CONFIGURATIONS},
-     * {@link #GET_INSTRUMENTATION},
-     * {@link #GET_PERMISSIONS},
-     * {@link #GET_PROVIDERS},
-     * {@link #GET_RECEIVERS},
-     * {@link #GET_SERVICES},
-     * {@link #GET_SIGNATURES},
-     * {@link #GET_UNINSTALLED_PACKAGES} to modify the data returned.
+     *         {@link #GET_ACTIVITIES}, {@link #GET_CONFIGURATIONS},
+     *         {@link #GET_GIDS}, {@link #GET_INSTRUMENTATION},
+     *         {@link #GET_INTENT_FILTERS}, {@link #GET_META_DATA},
+     *         {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS},
+     *         {@link #GET_RECEIVERS}, {@link #GET_SERVICES},
+     *         {@link #GET_SHARED_LIBRARY_FILES}, {@link #GET_SIGNATURES},
+     *         {@link #GET_URI_PERMISSION_PATTERNS}, {@link #GET_UNINSTALLED_PACKAGES},
+     *         {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *         {@link #MATCH_UNINSTALLED_PACKAGES}
+     *         to modify the data returned.
      *
-     * @return Returns a List of PackageInfo objects, one for each installed
-     * application that is holding any of the permissions that were provided.
+     * @return A List of PackageInfo objects, one for each installed package
+     *         that holds any of the permissions that were provided, containing
+     *         information about the package. If no installed packages hold any
+     *         of the permissions, an empty list is returned. If flag
+     *         {@code MATCH_UNINSTALLED_PACKAGES} is set, the package information
+     *         is retrieved from the list of uninstalled applications (which
+     *         includes installed applications as well as applications with data
+     *         directory i.e. applications which had been deleted with
+     *         {@code DONT_DELETE_DATA} flag set).
      *
      * @see #GET_ACTIVITIES
-     * @see #GET_GIDS
      * @see #GET_CONFIGURATIONS
+     * @see #GET_GIDS
      * @see #GET_INSTRUMENTATION
+     * @see #GET_INTENT_FILTERS
+     * @see #GET_META_DATA
      * @see #GET_PERMISSIONS
      * @see #GET_PROVIDERS
      * @see #GET_RECEIVERS
      * @see #GET_SERVICES
+     * @see #GET_SHARED_LIBRARY_FILES
      * @see #GET_SIGNATURES
-     * @see #GET_UNINSTALLED_PACKAGES
+     * @see #GET_URI_PERMISSION_PATTERNS
+     * @see #MATCH_DISABLED_COMPONENTS
+     * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
+     * @see #MATCH_UNINSTALLED_PACKAGES
      */
     public abstract List<PackageInfo> getPackagesHoldingPermissions(
-            String[] permissions, int flags);
+            String[] permissions, @PackageInfoFlags int flags);
 
     /**
      * Return a List of all packages that are installed on the device, for a specific user.
      * Requesting a list of installed packages for another user
      * will require the permission INTERACT_ACROSS_USERS_FULL.
+     *
      * @param flags Additional option flags. Use any combination of
-     * {@link #GET_ACTIVITIES},
-     * {@link #GET_GIDS},
-     * {@link #GET_CONFIGURATIONS},
-     * {@link #GET_INSTRUMENTATION},
-     * {@link #GET_PERMISSIONS},
-     * {@link #GET_PROVIDERS},
-     * {@link #GET_RECEIVERS},
-     * {@link #GET_SERVICES},
-     * {@link #GET_SIGNATURES},
-     * {@link #GET_UNINSTALLED_PACKAGES} to modify the data returned.
+     *         {@link #GET_ACTIVITIES}, {@link #GET_CONFIGURATIONS},
+     *         {@link #GET_GIDS}, {@link #GET_INSTRUMENTATION},
+     *         {@link #GET_INTENT_FILTERS}, {@link #GET_META_DATA},
+     *         {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS},
+     *         {@link #GET_RECEIVERS}, {@link #GET_SERVICES},
+     *         {@link #GET_SHARED_LIBRARY_FILES}, {@link #GET_SIGNATURES},
+     *         {@link #GET_URI_PERMISSION_PATTERNS}, {@link #GET_UNINSTALLED_PACKAGES},
+     *         {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *         {@link #MATCH_UNINSTALLED_PACKAGES}
+     *         to modify the data returned.
      * @param userId The user for whom the installed packages are to be listed
      *
-     * @return A List of PackageInfo objects, one for each package that is
-     *         installed on the device.  In the unlikely case of there being no
-     *         installed packages, an empty list is returned.
-     *         If flag GET_UNINSTALLED_PACKAGES is set, a list of all
-     *         applications including those deleted with {@code DONT_DELETE_DATA}
-     *         (partially installed apps with data directory) will be returned.
+     * @return A List of PackageInfo objects, one for each installed package,
+     *         containing information about the package.  In the unlikely case
+     *         there are no installed packages, an empty list is returned. If
+     *         flag {@code MATCH_UNINSTALLED_PACKAGES} is set, the package
+     *         information is retrieved from the list of uninstalled
+     *         applications (which includes installed applications as well as
+     *         applications with data directory i.e. applications which had been
+     *         deleted with {@code DONT_DELETE_DATA} flag set).
      *
      * @see #GET_ACTIVITIES
-     * @see #GET_GIDS
      * @see #GET_CONFIGURATIONS
+     * @see #GET_GIDS
      * @see #GET_INSTRUMENTATION
+     * @see #GET_INTENT_FILTERS
+     * @see #GET_META_DATA
      * @see #GET_PERMISSIONS
      * @see #GET_PROVIDERS
      * @see #GET_RECEIVERS
      * @see #GET_SERVICES
+     * @see #GET_SHARED_LIBRARY_FILES
      * @see #GET_SIGNATURES
-     * @see #GET_UNINSTALLED_PACKAGES
+     * @see #GET_URI_PERMISSION_PATTERNS
+     * @see #MATCH_DISABLED_COMPONENTS
+     * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
+     * @see #MATCH_UNINSTALLED_PACKAGES
      *
      * @hide
      */
-    public abstract List<PackageInfo> getInstalledPackages(int flags, int userId);
+    public abstract List<PackageInfo> getInstalledPackagesAsUser(@PackageInfoFlags int flags,
+            @UserIdInt int userId);
 
     /**
      * Check whether a particular package has been granted a particular
@@ -2815,7 +3196,7 @@
      * @return Returns an array of one or more packages assigned to the user
      * id, or null if there are no known packages with the given id.
      */
-    public abstract String[] getPackagesForUid(int uid);
+    public abstract @Nullable String[] getPackagesForUid(int uid);
 
     /**
      * Retrieve the official name associated with a user id.  This name is
@@ -2828,7 +3209,7 @@
      * @return Returns a unique name for the given user id, or null if the
      * user id is not currently assigned.
      */
-    public abstract String getNameForUid(int uid);
+    public abstract @Nullable String getNameForUid(int uid);
 
     /**
      * Return the user id associated with a shared user name. Multiple
@@ -2838,8 +3219,9 @@
      * shared user.
      *
      * @param sharedUserName The shared user name whose uid is to be retrieved.
-     * @return Returns the uid associated with the shared user, or  NameNotFoundException
-     * if the shared user name is not being used by any installed packages
+     * @return Returns the UID associated with the shared user.
+     * @throws NameNotFoundException if a package with the given name cannot be
+     *             found on the system.
      * @hide
      */
     public abstract int getUidForSharedUser(String sharedUserName)
@@ -2853,20 +3235,23 @@
      *
      * @param flags Additional option flags. Use any combination of
      * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
-     * {@link #GET_UNINSTALLED_PACKAGES} to modify the data returned.
+     * {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES}
+     * to modify the data returned.
      *
-     * @return Returns a List of ApplicationInfo objects, one for each application that
-     *         is installed on the device.  In the unlikely case of there being
-     *         no installed applications, an empty list is returned.
-     *         If flag GET_UNINSTALLED_PACKAGES is set, a list of all
-     *         applications including those deleted with {@code DONT_DELETE_DATA}
-     *         (partially installed apps with data directory) will be returned.
+     * @return A List of ApplicationInfo objects, one for each installed application.
+     *         In the unlikely case there are no installed packages, an empty list
+     *         is returned. If flag {@code MATCH_UNINSTALLED_PACKAGES} is set, the
+     *         application information is retrieved from the list of uninstalled
+     *         applications (which includes installed applications as well as
+     *         applications with data directory i.e. applications which had been
+     *         deleted with {@code DONT_DELETE_DATA} flag set).
      *
      * @see #GET_META_DATA
      * @see #GET_SHARED_LIBRARY_FILES
-     * @see #GET_UNINSTALLED_PACKAGES
+     * @see #MATCH_SYSTEM_ONLY
+     * @see #MATCH_UNINSTALLED_PACKAGES
      */
-    public abstract List<ApplicationInfo> getInstalledApplications(int flags);
+    public abstract List<ApplicationInfo> getInstalledApplications(@ApplicationInfoFlags int flags);
 
     /**
      * Gets the ephemeral applications the user recently used. Requires
@@ -2896,6 +3281,8 @@
      * @see #setEphemeralCookie(byte[])
      * @see #getEphemeralCookie()
      * @see #getEphemeralCookieMaxSizeBytes()
+     *
+     * @hide
      */
     public abstract boolean isEphemeralApplication();
 
@@ -2908,6 +3295,8 @@
      * @see #isEphemeralApplication()
      * @see #setEphemeralCookie(byte[])
      * @see #getEphemeralCookie()
+     *
+     * @hide
      */
     public abstract int getEphemeralCookieMaxSizeBytes();
 
@@ -2924,6 +3313,8 @@
      * @see #isEphemeralApplication()
      * @see #setEphemeralCookie(byte[])
      * @see #getEphemeralCookieMaxSizeBytes()
+     *
+     * @hide
      */
     public abstract @NonNull byte[] getEphemeralCookie();
 
@@ -2941,7 +3332,9 @@
      *
      * @see #isEphemeralApplication()
      * @see #getEphemeralCookieMaxSizeBytes()
-     * @see #getEphemeralCookie();
+     * @see #getEphemeralCookie()
+     *
+     * @hide
      */
     public abstract boolean setEphemeralCookie(@NonNull  byte[] cookie);
 
@@ -2987,21 +3380,37 @@
      *
      * @param intent An intent containing all of the desired specification
      *               (action, data, type, category, and/or component).
-     * @param flags Additional option flags.  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 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 ResolveInfo containing the final activity intent that
-     *         was determined to be the best action.  Returns null if no
+     * @return Returns a ResolveInfo object containing the final activity intent
+     *         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
+     *         found and there is no default set, returns a ResolveInfo object
      *         containing something else, such as the activity resolver.
      *
-     * @see #MATCH_DEFAULT_ONLY
-     * @see #GET_INTENT_FILTERS
+     * @see #GET_META_DATA
      * @see #GET_RESOLVED_FILTER
+     * @see #GET_SHARED_LIBRARY_FILES
+     * @see #MATCH_ALL
+     * @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_SYSTEM_ONLY
+     * @see #MATCH_UNINSTALLED_PACKAGES
      */
-    public abstract ResolveInfo resolveActivity(Intent intent, int flags);
+    public abstract ResolveInfo resolveActivity(Intent intent, @ResolveInfoFlags int flags);
 
     /**
      * Determine the best action to perform for a given Intent for a given user. This
@@ -3017,72 +3426,117 @@
      *
      * @param intent An intent containing all of the desired specification
      *               (action, data, type, category, and/or component).
-     * @param flags Additional option flags.  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 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}.
      * @param userId The user id.
      *
-     * @return Returns a ResolveInfo containing the final activity intent that
-     *         was determined to be the best action.  Returns null if no
+     * @return Returns a ResolveInfo object containing the final activity intent
+     *         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
+     *         found and there is no default set, returns a ResolveInfo object
      *         containing something else, such as the activity resolver.
      *
-     * @see #MATCH_DEFAULT_ONLY
-     * @see #GET_INTENT_FILTERS
+     * @see #GET_META_DATA
      * @see #GET_RESOLVED_FILTER
+     * @see #GET_SHARED_LIBRARY_FILES
+     * @see #MATCH_ALL
+     * @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_SYSTEM_ONLY
+     * @see #MATCH_UNINSTALLED_PACKAGES
      *
      * @hide
      */
-    public abstract ResolveInfo resolveActivityAsUser(Intent intent, int flags, int userId);
+    public abstract ResolveInfo resolveActivityAsUser(Intent intent, @ResolveInfoFlags int flags,
+            @UserIdInt int userId);
 
     /**
      * Retrieve all activities that can be performed for the given intent.
      *
      * @param intent The desired intent as per resolveActivity().
-     * @param flags Additional option flags.  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 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.
      *
-     * You can also set {@link #MATCH_ALL} for preventing the 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.
      *
-     * @return A List&lt;ResolveInfo&gt; containing one entry for each matching
-     *         Activity. These are ordered from best to worst match -- that
-     *         is, the first item in the list is what is returned by
-     *         {@link #resolveActivity}.  If there are no matching activities, an empty
-     *         list is returned.
-     *
-     * @see #MATCH_DEFAULT_ONLY
-     * @see #GET_INTENT_FILTERS
+     * @see #GET_META_DATA
      * @see #GET_RESOLVED_FILTER
+     * @see #GET_SHARED_LIBRARY_FILES
+     * @see #MATCH_ALL
+     * @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_SYSTEM_ONLY
+     * @see #MATCH_UNINSTALLED_PACKAGES
      */
     public abstract List<ResolveInfo> queryIntentActivities(Intent intent,
-            int flags);
+            @ResolveInfoFlags int flags);
 
     /**
      * 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.  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 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.
      *
-     * You can also set {@link #MATCH_ALL} for preventing the 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.
      *
-     * @return A List&lt;ResolveInfo&gt; containing one entry for each matching
-     *         Activity. These are ordered from best to worst match -- that
-     *         is, the first item in the list is what is returned by
-     *         {@link #resolveActivity}.  If there are no matching activities, an empty
-     *         list is returned.
-     *
-     * @see #MATCH_DEFAULT_ONLY
-     * @see #GET_INTENT_FILTERS
+     * @see #GET_META_DATA
      * @see #GET_RESOLVED_FILTER
+     * @see #GET_SHARED_LIBRARY_FILES
+     * @see #MATCH_ALL
+     * @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_SYSTEM_ONLY
+     * @see #MATCH_UNINSTALLED_PACKAGES
+     *
      * @hide
      */
     public abstract List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
-            int flags, int userId);
-
+            @ResolveInfoFlags int flags, @UserIdInt int userId);
 
     /**
      * Retrieve a set of activities that should be presented to the user as
@@ -3098,158 +3552,369 @@
      * @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.  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 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 A List&lt;ResolveInfo&gt; containing one entry for each matching
-     *         Activity. These are ordered first by all of the intents resolved
+     * @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 #MATCH_DEFAULT_ONLY
-     * @see #GET_INTENT_FILTERS
+     * @see #GET_META_DATA
      * @see #GET_RESOLVED_FILTER
+     * @see #GET_SHARED_LIBRARY_FILES
+     * @see #MATCH_ALL
+     * @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_SYSTEM_ONLY
+     * @see #MATCH_UNINSTALLED_PACKAGES
      */
     public abstract List<ResolveInfo> queryIntentActivityOptions(
-            ComponentName caller, Intent[] specifics, Intent intent, int flags);
+            ComponentName caller, Intent[] specifics, Intent intent, @ResolveInfoFlags int flags);
 
     /**
      * Retrieve all receivers that can handle a broadcast of the given intent.
      *
      * @param intent The desired intent as per resolveActivity().
-     * @param flags Additional option flags.
+     * @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 A List&lt;ResolveInfo&gt; containing one entry for each matching
-     *         Receiver. These are ordered from first to last in priority.  If
-     *         there are no matching receivers, an empty list 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 #MATCH_DEFAULT_ONLY
-     * @see #GET_INTENT_FILTERS
+     * @see #GET_META_DATA
      * @see #GET_RESOLVED_FILTER
+     * @see #GET_SHARED_LIBRARY_FILES
+     * @see #MATCH_ALL
+     * @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_SYSTEM_ONLY
+     * @see #MATCH_UNINSTALLED_PACKAGES
      */
     public abstract List<ResolveInfo> queryBroadcastReceivers(Intent intent,
-            int flags);
+            @ResolveInfoFlags int flags);
 
     /**
      * 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.
-     * @param userId The userId of the user being queried.
+     * @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.
+     * @param userHandle UserHandle of the user being queried.
      *
-     * @return A List&lt;ResolveInfo&gt; containing one entry for each matching
-     *         Receiver. These are ordered from first to last in priority.  If
-     *         there are no matching receivers, an empty list or {@code 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 #MATCH_DEFAULT_ONLY
-     * @see #GET_INTENT_FILTERS
+     * @see #GET_META_DATA
      * @see #GET_RESOLVED_FILTER
+     * @see #GET_SHARED_LIBRARY_FILES
+     * @see #MATCH_ALL
+     * @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_SYSTEM_ONLY
+     * @see #MATCH_UNINSTALLED_PACKAGES
+     *
      * @hide
      */
-    public abstract List<ResolveInfo> queryBroadcastReceivers(Intent intent,
-            int flags, int userId);
+    @SystemApi
+    public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent,
+            @ResolveInfoFlags int flags, UserHandle userHandle) {
+        return queryBroadcastReceiversAsUser(intent, flags, userHandle.getIdentifier());
+    }
+
+    /**
+     * @hide
+     */
+    public abstract List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent,
+            @ResolveInfoFlags int flags, @UserIdInt int userId);
+
+
+    /** {@hide} */
+    @Deprecated
+    public List<ResolveInfo> queryBroadcastReceivers(Intent intent,
+            @ResolveInfoFlags int flags, @UserIdInt int userId) {
+        Log.w(TAG, "STAHP USING HIDDEN APIS KTHX");
+        return queryBroadcastReceiversAsUser(intent, flags, userId);
+    }
 
     /**
      * 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).
-     * @param flags Additional option flags.
+     * @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 ResolveInfo containing the final service intent that
-     *         was determined to be the best action.  Returns null if no
+     * @return Returns a ResolveInfo object containing the final service intent
+     *         that was determined to be the best action.  Returns null if no
      *         matching service was found.
      *
-     * @see #GET_INTENT_FILTERS
+     * @see #GET_META_DATA
      * @see #GET_RESOLVED_FILTER
+     * @see #GET_SHARED_LIBRARY_FILES
+     * @see #MATCH_ALL
+     * @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_SYSTEM_ONLY
+     * @see #MATCH_UNINSTALLED_PACKAGES
      */
-    public abstract ResolveInfo resolveService(Intent intent, int flags);
+    public abstract ResolveInfo resolveService(Intent intent, @ResolveInfoFlags int flags);
 
     /**
      * Retrieve all services that can match the given intent.
      *
      * @param intent The desired intent as per resolveService().
-     * @param flags Additional option flags.
+     * @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 A List&lt;ResolveInfo&gt; containing one entry for each matching
-     *         ServiceInfo. These are ordered from best to worst match -- that
-     *         is, the first item in the list is what is returned by
-     *         resolveService().  If there are no matching services, an empty
-     *         list or {@code 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_INTENT_FILTERS
+     * @see #GET_META_DATA
      * @see #GET_RESOLVED_FILTER
+     * @see #GET_SHARED_LIBRARY_FILES
+     * @see #MATCH_ALL
+     * @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_SYSTEM_ONLY
+     * @see #MATCH_UNINSTALLED_PACKAGES
      */
     public abstract List<ResolveInfo> queryIntentServices(Intent intent,
-            int flags);
+            @ResolveInfoFlags int flags);
 
     /**
      * Retrieve all services that can match the given intent for a given user.
      *
      * @param intent The desired intent as per resolveService().
-     * @param flags Additional option flags.
+     * @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.
      * @param userId The user id.
      *
-     * @return A List&lt;ResolveInfo&gt; containing one entry for each matching
-     *         ServiceInfo. These are ordered from best to worst match -- that
-     *         is, the first item in the list is what is returned by
-     *         resolveService().  If there are no matching services, an empty
-     *         list or {@code 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_INTENT_FILTERS
+     * @see #GET_META_DATA
      * @see #GET_RESOLVED_FILTER
+     * @see #GET_SHARED_LIBRARY_FILES
+     * @see #MATCH_ALL
+     * @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_SYSTEM_ONLY
+     * @see #MATCH_UNINSTALLED_PACKAGES
      *
      * @hide
      */
     public abstract List<ResolveInfo> queryIntentServicesAsUser(Intent intent,
-            int flags, int userId);
-
-    /** {@hide} */
-    public abstract List<ResolveInfo> queryIntentContentProvidersAsUser(
-            Intent intent, int flags, int userId);
+            @ResolveInfoFlags int flags, @UserIdInt int userId);
 
     /**
      * Retrieve all providers that can match the given intent.
      *
      * @param intent An intent containing all of the desired specification
      *            (action, data, type, category, and/or component).
-     * @param flags Additional option flags.
-     * @return A List&lt;ResolveInfo&gt; containing one entry for each matching
-     *         ProviderInfo. These are ordered from best to worst match. If
-     *         there are no matching providers, an empty list or {@code null} is returned.
-     * @see #GET_INTENT_FILTERS
-     * @see #GET_RESOLVED_FILTER
-     */
-    public abstract List<ResolveInfo> queryIntentContentProviders(Intent intent, int flags);
-
-    /**
-     * Find a single content provider by its base path name.
-     *
-     * @param name The name of the provider to find.
-     * @param flags Additional option flags.  Currently should always be 0.
-     *
-     * @return ContentProviderInfo Information about the provider, if found,
-     *         else null.
-     */
-    public abstract ProviderInfo resolveContentProvider(String name,
-            int flags);
-
-    /**
-     * Find a single content provider by its base path name.
-     *
-     * @param name The name of the provider to find.
-     * @param flags Additional option flags.  Currently should always be 0.
+     * @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.
      * @param userId The user id.
      *
-     * @return ContentProviderInfo Information about the provider, if found,
-     *         else null.
+     * @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
+     * @see #MATCH_ALL
+     * @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_SYSTEM_ONLY
+     * @see #MATCH_UNINSTALLED_PACKAGES
+     *
      * @hide
      */
-    public abstract ProviderInfo resolveContentProviderAsUser(String name, int flags, int userId);
+    public abstract List<ResolveInfo> queryIntentContentProvidersAsUser(
+            Intent intent, @ResolveInfoFlags int flags, @UserIdInt int userId);
+
+    /**
+     * Retrieve all providers that can match the given intent.
+     *
+     * @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.
+     *
+     * @see #GET_META_DATA
+     * @see #GET_RESOLVED_FILTER
+     * @see #GET_SHARED_LIBRARY_FILES
+     * @see #MATCH_ALL
+     * @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_SYSTEM_ONLY
+     * @see #MATCH_UNINSTALLED_PACKAGES
+     */
+    public abstract List<ResolveInfo> queryIntentContentProviders(Intent intent,
+            @ResolveInfoFlags int flags);
+
+    /**
+     * Find a single content provider by its base path name.
+     *
+     * @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.
+     *
+     * @see #GET_META_DATA
+     * @see #GET_SHARED_LIBRARY_FILES
+     * @see #MATCH_ALL
+     * @see #MATCH_DEBUG_TRIAGED_MISSING
+     * @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_SYSTEM_ONLY
+     * @see #MATCH_UNINSTALLED_PACKAGES
+     */
+    public abstract ProviderInfo resolveContentProvider(String name,
+            @ComponentInfoFlags int flags);
+
+    /**
+     * Find a single content provider by its base path name.
+     *
+     * @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.
+     * @param userId The user id.
+     *
+     * @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
+     * @see #MATCH_DEBUG_TRIAGED_MISSING
+     * @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_SYSTEM_ONLY
+     * @see #MATCH_UNINSTALLED_PACKAGES
+     *
+     * @hide
+     */
+    public abstract ProviderInfo resolveContentProviderAsUser(String name,
+            @ComponentInfoFlags int flags, @UserIdInt int userId);
 
     /**
      * Retrieve content provider information.
@@ -3262,33 +3927,56 @@
      *                    all content providers are returned.
      * @param uid If <var>processName</var> is non-null, this is the required
      *        uid owning the requested content providers.
-     * @param flags Additional option flags.  Currently should always be 0.
+     * @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 List&lt;ContentProviderInfo&gt; containing one entry for each
-     *         content provider either patching <var>processName</var> or, if
+     * @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
+     * @see #MATCH_DEBUG_TRIAGED_MISSING
+     * @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_SYSTEM_ONLY
+     * @see #MATCH_UNINSTALLED_PACKAGES
      */
     public abstract List<ProviderInfo> queryContentProviders(
-            String processName, int uid, int flags);
+            String processName, int uid, @ComponentInfoFlags int flags);
 
     /**
      * Retrieve all of the information we know about a particular
      * instrumentation class.
      *
-     * <p>Throws {@link NameNotFoundException} if instrumentation with the
-     * given class name cannot be found on the system.
-     *
      * @param className The full name (i.e.
      *                  com.google.apps.contacts.InstrumentList) of an
      *                  Instrumentation class.
-     * @param flags Additional option flags.  Currently should always be 0.
+     * @param flags Additional option flags. Use any combination of
+     *         {@link #GET_META_DATA}
+     *         to modify the data returned.
      *
-     * @return InstrumentationInfo containing information about the
+     * @return An {@link InstrumentationInfo} object containing information about the
      *         instrumentation.
+     * @throws NameNotFoundException if a package with the given name cannot be
+     *             found on the system.
+     *
+     * @see #GET_META_DATA
      */
-    public abstract InstrumentationInfo getInstrumentationInfo(
-            ComponentName className, int flags) throws NameNotFoundException;
+    public abstract InstrumentationInfo getInstrumentationInfo(ComponentName className,
+            @InstrumentationInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Retrieve information about available instrumentation code.  May be used
@@ -3298,14 +3986,18 @@
      * @param targetPackage If null, all instrumentation is returned; only the
      *                      instrumentation targeting this package name is
      *                      returned.
-     * @param flags Additional option flags.  Currently should always be 0.
+     * @param flags Additional option flags. Use any combination of
+     *         {@link #GET_META_DATA}
+     *         to modify the data returned.
      *
-     * @return A List&lt;InstrumentationInfo&gt; containing one entry for each
-     *         matching available Instrumentation.  Returns an empty list if
-     *         there is no instrumentation available for the given package.
+     * @return A list of {@link InstrumentationInfo} objects containing one
+     *         entry for each matching instrumentation. If there are no
+     *         instrumentation available, returns and empty list. 
+     *
+     * @see #GET_META_DATA
      */
-    public abstract List<InstrumentationInfo> queryInstrumentation(
-            String targetPackage, int flags);
+    public abstract List<InstrumentationInfo> queryInstrumentation(String targetPackage,
+            @InstrumentationInfoFlags int flags);
 
     /**
      * Retrieve an image from a package.  This is a low-level API used by
@@ -3599,6 +4291,22 @@
 
     /**
      * If the target user is a managed profile of the calling user or the caller
+     * is itself a managed profile, then this returns a drawable to use as a small
+     * icon to include in a view to distinguish it from the original icon. This version
+     * doesn't have background protection and should be used over a light background instead of
+     * a badge.
+     *
+     * @param user The target user.
+     * @param density The optional desired density for the badge as per
+     *         {@link android.util.DisplayMetrics#densityDpi}. If not provided
+     *         the density of the current display is used.
+     * @return the drawable or null if no drawable is required.
+     * @hide
+     */
+    public abstract Drawable getUserBadgeForDensityNoBackground(UserHandle user, int density);
+
+    /**
+     * If the target user is a managed profile of the calling user or the caller
      * is itself a managed profile, then this returns a copy of the label with
      * badging for accessibility services like talkback. E.g. passing in "Email"
      * and it might return "Work Email" for Email in the work profile.
@@ -3708,8 +4416,8 @@
             throws NameNotFoundException;
 
     /** @hide */
-    public abstract Resources getResourcesForApplicationAsUser(String appPackageName, int userId)
-            throws NameNotFoundException;
+    public abstract Resources getResourcesForApplicationAsUser(String appPackageName,
+            @UserIdInt int userId) throws NameNotFoundException;
 
     /**
      * Retrieve overall information about an application package defined
@@ -3717,38 +4425,55 @@
      *
      * @param archiveFilePath The path to the archive file
      * @param flags Additional option flags. Use any combination of
-     * {@link #GET_ACTIVITIES},
-     * {@link #GET_GIDS},
-     * {@link #GET_CONFIGURATIONS},
-     * {@link #GET_INSTRUMENTATION},
-     * {@link #GET_PERMISSIONS},
-     * {@link #GET_PROVIDERS},
-     * {@link #GET_RECEIVERS},
-     * {@link #GET_SERVICES},
-     * {@link #GET_SIGNATURES}, to modify the data returned.
+     *         {@link #GET_ACTIVITIES}, {@link #GET_CONFIGURATIONS},
+     *         {@link #GET_GIDS}, {@link #GET_INSTRUMENTATION},
+     *         {@link #GET_INTENT_FILTERS}, {@link #GET_META_DATA},
+     *         {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS},
+     *         {@link #GET_RECEIVERS}, {@link #GET_SERVICES},
+     *         {@link #GET_SHARED_LIBRARY_FILES}, {@link #GET_SIGNATURES},
+     *         {@link #GET_URI_PERMISSION_PATTERNS}, {@link #GET_UNINSTALLED_PACKAGES},
+     *         {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *         {@link #MATCH_UNINSTALLED_PACKAGES}
+     *         to modify the data returned.
      *
-     * @return Returns the information about the package. Returns
-     * null if the package could not be successfully parsed.
+     * @return A PackageInfo object containing information about the
+     *         package archive. If the package could not be parsed,
+     *         returns null.
      *
      * @see #GET_ACTIVITIES
-     * @see #GET_GIDS
      * @see #GET_CONFIGURATIONS
+     * @see #GET_GIDS
      * @see #GET_INSTRUMENTATION
+     * @see #GET_INTENT_FILTERS
+     * @see #GET_META_DATA
      * @see #GET_PERMISSIONS
      * @see #GET_PROVIDERS
      * @see #GET_RECEIVERS
      * @see #GET_SERVICES
+     * @see #GET_SHARED_LIBRARY_FILES
      * @see #GET_SIGNATURES
+     * @see #GET_URI_PERMISSION_PATTERNS
+     * @see #MATCH_DISABLED_COMPONENTS
+     * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
+     * @see #MATCH_UNINSTALLED_PACKAGES
      *
      */
-    public PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags) {
+    public PackageInfo getPackageArchiveInfo(String archiveFilePath, @PackageInfoFlags int flags) {
         final PackageParser parser = new PackageParser();
         final File apkFile = new File(archiveFilePath);
         try {
+            if ((flags & (MATCH_ENCRYPTION_UNAWARE | MATCH_ENCRYPTION_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;
+            }
+
             PackageParser.Package pkg = parser.parseMonolithicPackage(apkFile, 0);
             if ((flags & GET_SIGNATURES) != 0) {
                 parser.collectCertificates(pkg, 0);
-                parser.collectManifestDigest(pkg);
             }
             PackageUserState state = new PackageUserState();
             return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state);
@@ -3758,217 +4483,64 @@
     }
 
     /**
-     * @hide Install a package. Since this may take a little while, the result
-     *       will be posted back to the given observer. An installation will
-     *       fail if the calling context lacks the
-     *       {@link android.Manifest.permission#INSTALL_PACKAGES} permission, if
-     *       the package named in the package file's manifest is already
-     *       installed, or if there's no space available on the device.
-     * @param packageURI The location of the package file to install. This can
-     *            be a 'file:' or a 'content:' URI.
-     * @param observer An observer callback to get notified when the package
-     *            installation is complete.
-     *            {@link IPackageInstallObserver#packageInstalled(String, int)}
-     *            will be called when that happens. This parameter must not be
-     *            null.
-     * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
-     *            {@link #INSTALL_REPLACE_EXISTING},
-     *            {@link #INSTALL_ALLOW_TEST}.
-     * @param installerPackageName Optional package name of the application that
-     *            is performing the installation. This identifies which market
-     *            the package came from.
-     * @deprecated Use {@link #installPackage(Uri, PackageInstallObserver, int,
-     *             String)} instead. This method will continue to be supported
-     *             but the older observer interface will not get additional
-     *             failure details.
+     * @deprecated replaced by {@link PackageInstaller}
+     * @hide
      */
-    // @SystemApi
+    @Deprecated
     public abstract void installPackage(
-            Uri packageURI, IPackageInstallObserver observer, int flags,
+            Uri packageURI, IPackageInstallObserver observer, @InstallFlags int flags,
             String installerPackageName);
 
     /**
-     * Similar to
-     * {@link #installPackage(Uri, IPackageInstallObserver, int, String)} but
-     * with an extra verification file provided.
-     *
-     * @param packageURI The location of the package file to install. This can
-     *            be a 'file:' or a 'content:' URI.
-     * @param observer An observer callback to get notified when the package
-     *            installation is complete.
-     *            {@link IPackageInstallObserver#packageInstalled(String, int)}
-     *            will be called when that happens. This parameter must not be
-     *            null.
-     * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
-     *            {@link #INSTALL_REPLACE_EXISTING},
-     *            {@link #INSTALL_ALLOW_TEST}.
-     * @param installerPackageName Optional package name of the application that
-     *            is performing the installation. This identifies which market
-     *            the package came from.
-     * @param verificationURI The location of the supplementary verification
-     *            file. This can be a 'file:' or a 'content:' URI. May be
-     *            {@code null}.
-     * @param manifestDigest an object that holds the digest of the package
-     *            which can be used to verify ownership. May be {@code null}.
-     * @param encryptionParams if the package to be installed is encrypted,
-     *            these parameters describing the encryption and authentication
-     *            used. May be {@code null}.
+     * @deprecated replaced by {@link PackageInstaller}
      * @hide
-     * @deprecated Use {@link #installPackageWithVerification(Uri,
-     *             PackageInstallObserver, int, String, Uri, ManifestDigest,
-     *             ContainerEncryptionParams)} instead. This method will
-     *             continue to be supported but the older observer interface
-     *             will not get additional failure details.
      */
-    // @SystemApi
+    @Deprecated
     public abstract void installPackageWithVerification(Uri packageURI,
-            IPackageInstallObserver observer, int flags, String installerPackageName,
-            Uri verificationURI, ManifestDigest manifestDigest,
-            ContainerEncryptionParams encryptionParams);
+            IPackageInstallObserver observer, @InstallFlags int flags, String installerPackageName,
+            Uri verificationURI, ContainerEncryptionParams encryptionParams);
 
     /**
-     * Similar to
-     * {@link #installPackage(Uri, IPackageInstallObserver, int, String)} but
-     * with an extra verification information provided.
-     *
-     * @param packageURI The location of the package file to install. This can
-     *            be a 'file:' or a 'content:' URI.
-     * @param observer An observer callback to get notified when the package
-     *            installation is complete.
-     *            {@link IPackageInstallObserver#packageInstalled(String, int)}
-     *            will be called when that happens. This parameter must not be
-     *            null.
-     * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
-     *            {@link #INSTALL_REPLACE_EXISTING},
-     *            {@link #INSTALL_ALLOW_TEST}.
-     * @param installerPackageName Optional package name of the application that
-     *            is performing the installation. This identifies which market
-     *            the package came from.
-     * @param verificationParams an object that holds signal information to
-     *            assist verification. May be {@code null}.
-     * @param encryptionParams if the package to be installed is encrypted,
-     *            these parameters describing the encryption and authentication
-     *            used. May be {@code null}.
+     * @deprecated replaced by {@link PackageInstaller}
      * @hide
-     * @deprecated Use {@link #installPackageWithVerificationAndEncryption(Uri,
-     *             PackageInstallObserver, int, String, VerificationParams,
-     *             ContainerEncryptionParams)} instead. This method will
-     *             continue to be supported but the older observer interface
-     *             will not get additional failure details.
      */
     @Deprecated
     public abstract void installPackageWithVerificationAndEncryption(Uri packageURI,
-            IPackageInstallObserver observer, int flags, String installerPackageName,
-            VerificationParams verificationParams,
-            ContainerEncryptionParams encryptionParams);
-
-    // Package-install variants that take the new, expanded form of observer interface.
-    // Note that these *also* take the original observer type and will redundantly
-    // report the same information to that observer if supplied; but it is not required.
+            IPackageInstallObserver observer, @InstallFlags int flags, String installerPackageName,
+            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams);
 
     /**
+     * @deprecated replaced by {@link PackageInstaller}
      * @hide
-     *
-     * Install a package. Since this may take a little while, the result will
-     * be posted back to the given observer.  An installation will fail if the calling context
-     * lacks the {@link android.Manifest.permission#INSTALL_PACKAGES} permission, if the
-     * package named in the package file's manifest is already installed, or if there's no space
-     * available on the device.
-     *
-     * @param packageURI The location of the package file to install.  This can be a 'file:' or a
-     * 'content:' URI.
-     * @param observer An observer callback to get notified when the package installation is
-     * complete. {@link PackageInstallObserver#packageInstalled(String, Bundle, int)} will be
-     * called when that happens. This parameter must not be null.
-     * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
-     * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.
-     * @param installerPackageName Optional package name of the application that is performing the
-     * installation. This identifies which market the package came from.
      */
-    public abstract void installPackage(
-            Uri packageURI, PackageInstallObserver observer,
-            int flags, String installerPackageName);
-
+    @Deprecated
+    public abstract void installPackage(Uri packageURI, PackageInstallObserver observer,
+            @InstallFlags int flags, String installerPackageName);
 
     /**
+     * @deprecated replaced by {@link PackageInstaller}
      * @hide
-     * Install a package. Since this may take a little while, the result will be
-     * posted back to the given observer. An installation will fail if the package named
-     * in the package file's manifest is already installed, or if there's no space
-     * available on the device.
-     * @param packageURI The location of the package file to install. This can be a 'file:' or a
-     * 'content:' URI.
-     * @param observer An observer callback to get notified when the package installation is
-     * complete. {@link PackageInstallObserver#packageInstalled(String, Bundle, int)} will be
-     * called when that happens. This parameter must not be null.
-     * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
-     * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.
-     * @param installerPackageName Optional package name of the application that is performing the
-     * installation. This identifies which market the package came from.
-     * @param userId The user id.
      */
-     @RequiresPermission(anyOf = {
-            Manifest.permission.INSTALL_PACKAGES,
-            Manifest.permission.INTERACT_ACROSS_USERS_FULL})
-    public abstract void installPackageAsUser(
-            Uri packageURI, PackageInstallObserver observer, int flags,
-            String installerPackageName, int userId);
+    @Deprecated
+    public abstract void installPackageAsUser(Uri packageURI, PackageInstallObserver observer,
+            @InstallFlags int flags, String installerPackageName, @UserIdInt int userId);
 
     /**
-     * Similar to
-     * {@link #installPackage(Uri, IPackageInstallObserver, int, String)} but
-     * with an extra verification file provided.
-     *
-     * @param packageURI The location of the package file to install. This can
-     *            be a 'file:' or a 'content:' URI.
-     * @param observer An observer callback to get notified when the package installation is
-     * complete. {@link PackageInstallObserver#packageInstalled(String, Bundle, int)} will be
-     * called when that happens. This parameter must not be null.
-     * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
-     *            {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.
-     * @param installerPackageName Optional package name of the application that
-     *            is performing the installation. This identifies which market
-     *            the package came from.
-     * @param verificationURI The location of the supplementary verification
-     *            file. This can be a 'file:' or a 'content:' URI. May be
-     *            {@code null}.
-     * @param manifestDigest an object that holds the digest of the package
-     *            which can be used to verify ownership. May be {@code null}.
-     * @param encryptionParams if the package to be installed is encrypted,
-     *            these parameters describing the encryption and authentication
-     *            used. May be {@code null}.
+     * @deprecated replaced by {@link PackageInstaller}
      * @hide
      */
+    @Deprecated
     public abstract void installPackageWithVerification(Uri packageURI,
-            PackageInstallObserver observer, int flags, String installerPackageName,
-            Uri verificationURI, ManifestDigest manifestDigest,
-            ContainerEncryptionParams encryptionParams);
+            PackageInstallObserver observer, @InstallFlags int flags, String installerPackageName,
+            Uri verificationURI, ContainerEncryptionParams encryptionParams);
 
     /**
-     * Similar to
-     * {@link #installPackage(Uri, IPackageInstallObserver, int, String)} but
-     * with an extra verification information provided.
-     *
-     * @param packageURI The location of the package file to install. This can
-     *            be a 'file:' or a 'content:' URI.
-     * @param observer An observer callback to get notified when the package installation is
-     * complete. {@link PackageInstallObserver#packageInstalled(String, Bundle, int)} will be
-     * called when that happens. This parameter must not be null.
-     * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
-     *            {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.
-     * @param installerPackageName Optional package name of the application that
-     *            is performing the installation. This identifies which market
-     *            the package came from.
-     * @param verificationParams an object that holds signal information to
-     *            assist verification. May be {@code null}.
-     * @param encryptionParams if the package to be installed is encrypted,
-     *            these parameters describing the encryption and authentication
-     *            used. May be {@code null}.
-     *
+     * @deprecated replaced by {@link PackageInstaller}
      * @hide
      */
+    @Deprecated
     public abstract void installPackageWithVerificationAndEncryption(Uri packageURI,
-            PackageInstallObserver observer, int flags, String installerPackageName,
+            PackageInstallObserver observer, @InstallFlags int flags, String installerPackageName,
             VerificationParams verificationParams, ContainerEncryptionParams encryptionParams);
 
     /**
@@ -3976,7 +4548,6 @@
      * on the system for other users, also install it for the calling user.
      * @hide
      */
-    // @SystemApi
     public abstract int installExistingPackage(String packageName) throws NameNotFoundException;
 
     /**
@@ -3987,7 +4558,7 @@
      @RequiresPermission(anyOf = {
             Manifest.permission.INSTALL_PACKAGES,
             Manifest.permission.INTERACT_ACROSS_USERS_FULL})
-    public abstract int installExistingPackageAsUser(String packageName, int userId)
+    public abstract int installExistingPackageAsUser(String packageName, @UserIdInt int userId)
             throws NameNotFoundException;
 
     /**
@@ -4085,7 +4656,7 @@
      *
      * @hide
      */
-    public abstract int getIntentVerificationStatus(String packageName, int userId);
+    public abstract int getIntentVerificationStatusAsUser(String packageName, @UserIdInt int userId);
 
     /**
      * Allow to change the status of a Intent Verification status for all IntentFilter of an App.
@@ -4107,8 +4678,8 @@
      *
      * @hide
      */
-    public abstract boolean updateIntentVerificationStatus(String packageName, int status,
-            int userId);
+    public abstract boolean updateIntentVerificationStatusAsUser(String packageName, int status,
+            @UserIdInt int userId);
 
     /**
      * Get the list of IntentFilterVerificationInfo for a specific package and User.
@@ -4148,7 +4719,8 @@
      *
      * @hide
      */
-    public abstract String getDefaultBrowserPackageName(int userId);
+    @TestApi
+    public abstract String getDefaultBrowserPackageNameAsUser(@UserIdInt int userId);
 
     /**
      * Set the default Browser package name for a specific user.
@@ -4162,7 +4734,8 @@
      *
      * @hide
      */
-    public abstract boolean setDefaultBrowserPackageName(String packageName, int userId);
+    public abstract boolean setDefaultBrowserPackageNameAsUser(String packageName,
+            @UserIdInt int userId);
 
     /**
      * Change the installer associated with a given package.  There are limitations
@@ -4183,45 +4756,44 @@
             String installerPackageName);
 
     /**
-     * Attempts to delete a package.  Since this may take a little while, the result will
-     * be posted back to the given observer.  A deletion will fail if the calling context
-     * lacks the {@link android.Manifest.permission#DELETE_PACKAGES} permission, if the
-     * named package cannot be found, or if the named package is a "system package".
-     * (TODO: include pointer to documentation on "system packages")
+     * Attempts to delete a package. Since this may take a little while, the
+     * result will be posted back to the given observer. A deletion will fail if
+     * the calling context lacks the
+     * {@link android.Manifest.permission#DELETE_PACKAGES} permission, if the
+     * named package cannot be found, or if the named package is a system
+     * package.
      *
      * @param packageName The name of the package to delete
-     * @param observer An observer callback to get notified when the package deletion is
-     * complete. {@link android.content.pm.IPackageDeleteObserver#packageDeleted(boolean)} will be
-     * called when that happens.  observer may be null to indicate that no callback is desired.
-     * @param flags Possible values: {@link #DELETE_KEEP_DATA},
-     * {@link #DELETE_ALL_USERS}.
-     *
+     * @param observer An observer callback to get notified when the package
+     *            deletion is complete.
+     *            {@link android.content.pm.IPackageDeleteObserver#packageDeleted}
+     *            will be called when that happens. observer may be null to
+     *            indicate that no callback is desired.
      * @hide
      */
-    // @SystemApi
-    public abstract void deletePackage(
-            String packageName, IPackageDeleteObserver observer, int flags);
+    public abstract void deletePackage(String packageName, IPackageDeleteObserver observer,
+            @DeleteFlags int flags);
 
     /**
-     * Attempts to delete a package.  Since this may take a little while, the result will
-     * be posted back to the given observer. A deletion will fail if the named package cannot be
-     * found, or if the named package is a "system package".
-     * (TODO: include pointer to documentation on "system packages")
+     * Attempts to delete a package. Since this may take a little while, the
+     * result will be posted back to the given observer. A deletion will fail if
+     * the named package cannot be found, or if the named package is a system
+     * package.
      *
      * @param packageName The name of the package to delete
-     * @param observer An observer callback to get notified when the package deletion is
-     * complete. {@link android.content.pm.IPackageDeleteObserver#packageDeleted(boolean)} will be
-     * called when that happens.  observer may be null to indicate that no callback is desired.
-     * @param flags Possible values: {@link #DELETE_KEEP_DATA}, {@link #DELETE_ALL_USERS}.
+     * @param observer An observer callback to get notified when the package
+     *            deletion is complete.
+     *            {@link android.content.pm.IPackageDeleteObserver#packageDeleted}
+     *            will be called when that happens. observer may be null to
+     *            indicate that no callback is desired.
      * @param userId The user Id
-     *
      * @hide
      */
      @RequiresPermission(anyOf = {
             Manifest.permission.DELETE_PACKAGES,
             Manifest.permission.INTERACT_ACROSS_USERS_FULL})
-    public abstract void deletePackageAsUser(
-            String packageName, IPackageDeleteObserver observer, int flags, int userId);
+    public abstract void deletePackageAsUser(String packageName, IPackageDeleteObserver observer,
+            @DeleteFlags int flags, @UserIdInt int userId);
 
     /**
      * Retrieve the package name of the application that installed a package. This identifies
@@ -4288,7 +4860,6 @@
      *
      * @hide
      */
-    // @SystemApi
     public void freeStorageAndNotify(long freeStorageSize, IPackageDataObserver observer) {
         freeStorageAndNotify(null, freeStorageSize, observer);
     }
@@ -4334,7 +4905,7 @@
      * should have the {@link android.Manifest.permission#GET_PACKAGE_SIZE} permission.
      *
      * @param packageName The name of the package whose size information is to be retrieved
-     * @param userHandle The user whose size information should be retrieved.
+     * @param userId The user whose size information should be retrieved.
      * @param observer An observer callback to get notified when the operation
      * is complete.
      * {@link android.content.pm.IPackageStatsObserver#onGetStatsCompleted(PackageStats, boolean)}
@@ -4345,17 +4916,17 @@
      *
      * @hide
      */
-    public abstract void getPackageSizeInfo(String packageName, int userHandle,
+    public abstract void getPackageSizeInfoAsUser(String packageName, @UserIdInt int userId,
             IPackageStatsObserver observer);
 
     /**
-     * Like {@link #getPackageSizeInfo(String, int, IPackageStatsObserver)}, but
+     * Like {@link #getPackageSizeInfoAsUser(String, int, IPackageStatsObserver)}, but
      * returns the size for the calling user.
      *
      * @hide
      */
     public void getPackageSizeInfo(String packageName, IPackageStatsObserver observer) {
-        getPackageSizeInfo(packageName, UserHandle.myUserId(), observer);
+        getPackageSizeInfoAsUser(packageName, UserHandle.myUserId(), observer);
     }
 
     /**
@@ -4380,30 +4951,38 @@
      * least preferred.
      *
      * @param flags Additional option flags. Use any combination of
-     * {@link #GET_ACTIVITIES},
-     * {@link #GET_GIDS},
-     * {@link #GET_CONFIGURATIONS},
-     * {@link #GET_INSTRUMENTATION},
-     * {@link #GET_PERMISSIONS},
-     * {@link #GET_PROVIDERS},
-     * {@link #GET_RECEIVERS},
-     * {@link #GET_SERVICES},
-     * {@link #GET_SIGNATURES}, to modify the data returned.
+     *         {@link #GET_ACTIVITIES}, {@link #GET_CONFIGURATIONS},
+     *         {@link #GET_GIDS}, {@link #GET_INSTRUMENTATION},
+     *         {@link #GET_INTENT_FILTERS}, {@link #GET_META_DATA},
+     *         {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS},
+     *         {@link #GET_RECEIVERS}, {@link #GET_SERVICES},
+     *         {@link #GET_SHARED_LIBRARY_FILES}, {@link #GET_SIGNATURES},
+     *         {@link #GET_URI_PERMISSION_PATTERNS}, {@link #GET_UNINSTALLED_PACKAGES},
+     *         {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *         {@link #MATCH_UNINSTALLED_PACKAGES}
+     *         to modify the data returned.
      *
-     * @return Returns a list of PackageInfo objects describing each
-     * preferred application, in order of preference.
+     * @return A List of PackageInfo objects, one for each preferred application,
+     *         in order of preference.
      *
      * @see #GET_ACTIVITIES
-     * @see #GET_GIDS
      * @see #GET_CONFIGURATIONS
+     * @see #GET_GIDS
      * @see #GET_INSTRUMENTATION
+     * @see #GET_INTENT_FILTERS
+     * @see #GET_META_DATA
      * @see #GET_PERMISSIONS
      * @see #GET_PROVIDERS
      * @see #GET_RECEIVERS
      * @see #GET_SERVICES
+     * @see #GET_SHARED_LIBRARY_FILES
      * @see #GET_SIGNATURES
+     * @see #GET_URI_PERMISSION_PATTERNS
+     * @see #MATCH_DISABLED_COMPONENTS
+     * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
+     * @see #MATCH_UNINSTALLED_PACKAGES
      */
-    public abstract List<PackageInfo> getPreferredPackages(int flags);
+    public abstract List<PackageInfo> getPreferredPackages(@PackageInfoFlags int flags);
 
     /**
      * @deprecated This is a protected API that should not have been available
@@ -4434,8 +5013,8 @@
             to.
      * @hide
      */
-    public void addPreferredActivity(IntentFilter filter, int match,
-            ComponentName[] set, ComponentName activity, int userId) {
+    public void addPreferredActivityAsUser(IntentFilter filter, int match,
+            ComponentName[] set, ComponentName activity, @UserIdInt int userId) {
         throw new RuntimeException("Not implemented. Must override in a subclass.");
     }
 
@@ -4469,7 +5048,7 @@
      */
     @Deprecated
     public void replacePreferredActivityAsUser(IntentFilter filter, int match,
-           ComponentName[] set, ComponentName activity, int userId) {
+           ComponentName[] set, ComponentName activity, @UserIdInt int userId) {
         throw new RuntimeException("Not implemented. Must override in a subclass.");
     }
 
@@ -4664,27 +5243,6 @@
     public abstract boolean isSignedByExactly(String packageName, KeySet ks);
 
     /**
-     * Attempts to move package resources from internal to external media or vice versa.
-     * Since this may take a little while, the result will
-     * be posted back to the given observer.   This call may fail if the calling context
-     * lacks the {@link android.Manifest.permission#MOVE_PACKAGE} permission, if the
-     * named package cannot be found, or if the named package is a "system package".
-     *
-     * @param packageName The name of the package to delete
-     * @param observer An observer callback to get notified when the package move is
-     * complete. {@link android.content.pm.IPackageMoveObserver#packageMoved(boolean)} will be
-     * called when that happens.  observer may be null to indicate that no callback is desired.
-     * @param flags To indicate install location {@link #MOVE_INTERNAL} or
-     * {@link #MOVE_EXTERNAL_MEDIA}
-     *
-     * @hide
-     */
-    @Deprecated
-    public void movePackage(String packageName, IPackageMoveObserver observer, int flags) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
      * Puts the package in a suspended state, making the package un-runnable,
      * but it doesn't remove the data or the actual package file. The application notifications
      * will be hidden and also the application will not show up in recents.
@@ -4697,7 +5255,7 @@
      * @hide
      */
     public abstract boolean setPackageSuspendedAsUser(
-            String packageName, boolean suspended, int userId);
+            String packageName, boolean suspended, @UserIdInt int userId);
 
     /** {@hide} */
     public static boolean isMoveStatusFinished(int status) {
@@ -4755,22 +5313,25 @@
     public abstract @NonNull PackageInstaller getPackageInstaller();
 
     /**
-     * Adds a {@link CrossProfileIntentFilter}. After calling this method all intents sent from the
-     * user with id sourceUserId can also be be resolved by activities in the user with id
-     * targetUserId if they match the specified intent filter.
+     * Adds a {@code CrossProfileIntentFilter}. After calling this method all
+     * intents sent from the user with id sourceUserId can also be be resolved
+     * by activities in the user with id targetUserId if they match the
+     * specified intent filter.
+     *
      * @param filter The {@link IntentFilter} the intent has to match
      * @param sourceUserId The source user id.
      * @param targetUserId The target user id.
-     * @param flags The possible values are {@link SKIP_CURRENT_PROFILE} and
-     *        {@link ONLY_IF_NO_MATCH_FOUND}.
+     * @param flags The possible values are {@link #SKIP_CURRENT_PROFILE} and
+     *            {@link #ONLY_IF_NO_MATCH_FOUND}.
      * @hide
      */
     public abstract void addCrossProfileIntentFilter(IntentFilter filter, int sourceUserId,
             int targetUserId, int flags);
 
     /**
-     * Clearing {@link CrossProfileIntentFilter}s which have the specified user as their
-     * source, and have been set by the app calling this method.
+     * Clearing {@code CrossProfileIntentFilter}s which have the specified user
+     * as their source, and have been set by the app calling this method.
+     *
      * @param sourceUserId The source user id.
      * @hide
      */
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 019ed2b..44cd003 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -16,15 +16,12 @@
 
 package android.content.pm;
 
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
-import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import com.android.internal.R;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
 
 import android.app.ActivityManager;
 import android.content.ComponentName;
@@ -37,7 +34,6 @@
 import android.content.res.XmlResourceParser;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.Environment;
 import android.os.FileUtils;
 import android.os.PatternMatcher;
 import android.os.Trace;
@@ -52,17 +48,10 @@
 import android.util.Pair;
 import android.util.Slog;
 import android.util.TypedValue;
+import android.util.apk.ApkSignatureSchemeV2Verifier;
+import android.util.jar.StrictJarFile;
 import android.view.Gravity;
 
-import com.android.internal.R;
-import com.android.internal.util.ArrayUtils;
-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.IOException;
 import java.io.InputStream;
@@ -86,7 +75,24 @@
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.zip.ZipEntry;
 
-import android.util.jar.StrictJarFile;
+import libcore.io.IoUtils;
+
+import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 
 /**
  * Parser for package files (APKs) on disk. This supports apps packaged either
@@ -421,8 +427,7 @@
     public static PackageInfo generatePackageInfo(PackageParser.Package p,
             int gids[], int flags, long firstInstallTime, long lastUpdateTime,
             Set<String> grantedPermissions, PackageUserState state, int userId) {
-
-        if (!checkUseInstalledOrHidden(flags, state)) {
+        if (!checkUseInstalledOrHidden(flags, state) || !p.isMatch(flags)) {
             return null;
         }
         PackageInfo pi = new PackageInfo();
@@ -466,92 +471,60 @@
                 p.featureGroups.toArray(pi.featureGroups);
             }
         }
-        if ((flags&PackageManager.GET_ACTIVITIES) != 0) {
-            int N = p.activities.size();
+        if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
+            final int N = p.activities.size();
             if (N > 0) {
-                if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
-                    pi.activities = new ActivityInfo[N];
-                } else {
-                    int num = 0;
-                    for (int i=0; i<N; i++) {
-                        if (p.activities.get(i).info.enabled) num++;
-                    }
-                    pi.activities = new ActivityInfo[num];
-                }
-                for (int i=0, j=0; i<N; i++) {
-                    final Activity activity = p.activities.get(i);
-                    if (activity.info.enabled
-                        || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
-                        pi.activities[j++] = generateActivityInfo(p.activities.get(i), flags,
-                                state, userId);
+                int num = 0;
+                final ActivityInfo[] res = new ActivityInfo[N];
+                for (int i = 0; i < N; i++) {
+                    final Activity a = p.activities.get(i);
+                    if (state.isMatch(a.info, flags)) {
+                        res[num++] = generateActivityInfo(a, flags, state, userId);
                     }
                 }
+                pi.activities = ArrayUtils.trimToSize(res, num);
             }
         }
-        if ((flags&PackageManager.GET_RECEIVERS) != 0) {
-            int N = p.receivers.size();
+        if ((flags & PackageManager.GET_RECEIVERS) != 0) {
+            final int N = p.receivers.size();
             if (N > 0) {
-                if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
-                    pi.receivers = new ActivityInfo[N];
-                } else {
-                    int num = 0;
-                    for (int i=0; i<N; i++) {
-                        if (p.receivers.get(i).info.enabled) num++;
-                    }
-                    pi.receivers = new ActivityInfo[num];
-                }
-                for (int i=0, j=0; i<N; i++) {
-                    final Activity activity = p.receivers.get(i);
-                    if (activity.info.enabled
-                        || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
-                        pi.receivers[j++] = generateActivityInfo(p.receivers.get(i), flags,
-                                state, userId);
+                int num = 0;
+                final ActivityInfo[] res = new ActivityInfo[N];
+                for (int i = 0; i < N; i++) {
+                    final Activity a = p.receivers.get(i);
+                    if (state.isMatch(a.info, flags)) {
+                        res[num++] = generateActivityInfo(a, flags, state, userId);
                     }
                 }
+                pi.receivers = ArrayUtils.trimToSize(res, num);
             }
         }
-        if ((flags&PackageManager.GET_SERVICES) != 0) {
-            int N = p.services.size();
+        if ((flags & PackageManager.GET_SERVICES) != 0) {
+            final int N = p.services.size();
             if (N > 0) {
-                if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
-                    pi.services = new ServiceInfo[N];
-                } else {
-                    int num = 0;
-                    for (int i=0; i<N; i++) {
-                        if (p.services.get(i).info.enabled) num++;
-                    }
-                    pi.services = new ServiceInfo[num];
-                }
-                for (int i=0, j=0; i<N; i++) {
-                    final Service service = p.services.get(i);
-                    if (service.info.enabled
-                        || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
-                        pi.services[j++] = generateServiceInfo(p.services.get(i), flags,
-                                state, userId);
+                int num = 0;
+                final ServiceInfo[] res = new ServiceInfo[N];
+                for (int i = 0; i < N; i++) {
+                    final Service s = p.services.get(i);
+                    if (state.isMatch(s.info, flags)) {
+                        res[num++] = generateServiceInfo(s, flags, state, userId);
                     }
                 }
+                pi.services = ArrayUtils.trimToSize(res, num);
             }
         }
-        if ((flags&PackageManager.GET_PROVIDERS) != 0) {
-            int N = p.providers.size();
+        if ((flags & PackageManager.GET_PROVIDERS) != 0) {
+            final int N = p.providers.size();
             if (N > 0) {
-                if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
-                    pi.providers = new ProviderInfo[N];
-                } else {
-                    int num = 0;
-                    for (int i=0; i<N; i++) {
-                        if (p.providers.get(i).info.enabled) num++;
-                    }
-                    pi.providers = new ProviderInfo[num];
-                }
-                for (int i=0, j=0; i<N; i++) {
-                    final Provider provider = p.providers.get(i);
-                    if (provider.info.enabled
-                        || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
-                        pi.providers[j++] = generateProviderInfo(p.providers.get(i), flags,
-                                state, userId);
+                int num = 0;
+                final ProviderInfo[] res = new ProviderInfo[N];
+                for (int i = 0; i < N; i++) {
+                    final Provider pr = p.providers.get(i);
+                    if (state.isMatch(pr.info, flags)) {
+                        res[num++] = generateProviderInfo(pr, flags, state, userId);
                     }
                 }
+                pi.providers = ArrayUtils.trimToSize(res, num);
             }
         }
         if ((flags&PackageManager.GET_INSTRUMENTATION) != 0) {
@@ -625,9 +598,7 @@
     public final static int PARSE_COLLECT_CERTIFICATES = 1<<8;
     public final static int PARSE_TRUSTED_OVERLAY = 1<<9;
     public final static int PARSE_ENFORCE_CODE = 1<<10;
-    // TODO: fix b/25118622; remove this entirely once signature processing is quick
-    public final static int PARSE_SKIP_VERIFICATION = 1<<11;
-    public final static int PARSE_IS_EPHEMERAL = 1<<12;
+    public final static int PARSE_IS_EPHEMERAL = 1<<11;
 
     private static final Comparator<String> sSplitNameComparator = new SplitNameComparator();
 
@@ -1034,34 +1005,8 @@
     }
 
     /**
-     * Gathers the {@link ManifestDigest} for {@code pkg} if it exists in the
-     * APK. If it successfully scanned the package and found the
-     * {@code AndroidManifest.xml}, {@code true} is returned.
-     */
-    public void collectManifestDigest(Package pkg) throws PackageParserException {
-        pkg.manifestDigest = null;
-
-        // TODO: extend to gather digest for split APKs
-        try {
-            final StrictJarFile jarFile = new StrictJarFile(pkg.baseCodePath);
-            try {
-                final ZipEntry je = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
-                if (je != null) {
-                    pkg.manifestDigest = ManifestDigest.fromInputStream(jarFile.getInputStream(je));
-                }
-            } finally {
-                jarFile.close();
-            }
-        } catch (IOException | RuntimeException e) {
-            throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                    "Failed to collect manifest digest");
-        }
-    }
-
-    /**
      * Collect certificates from all the APKs described in the given package,
-     * populating {@link Package#mSignatures}.
-     * <p>Depending upon the parser flags, this may also asserts that all APK
+     * populating {@link Package#mSignatures}. Also asserts that all APK
      * contents are signed correctly and consistently.
      */
     public void collectCertificates(Package pkg, int parseFlags) throws PackageParserException {
@@ -1084,14 +1029,57 @@
         final boolean hasCode = (apkFlags & ApplicationInfo.FLAG_HAS_CODE) != 0;
         final boolean requireCode = ((parseFlags & PARSE_ENFORCE_CODE) != 0) && hasCode;
         final String apkPath = apkFile.getAbsolutePath();
-        final boolean skipVerification = Build.IS_DEBUGGABLE
-                && ((parseFlags & PARSE_SKIP_VERIFICATION) != 0);
 
-        boolean codeFound = skipVerification;
+        // Try to verify the APK using APK Signature Scheme v2.
+        boolean verified = false;
+        {
+            Certificate[][] allSignersCerts = null;
+            Signature[] signatures = null;
+            try {
+                allSignersCerts = ApkSignatureSchemeV2Verifier.verify(apkPath);
+                signatures = convertToSignatures(allSignersCerts);
+                // APK verified using APK Signature Scheme v2.
+                verified = true;
+            } catch (ApkSignatureSchemeV2Verifier.SignatureNotFoundException e) {
+                // No APK Signature Scheme v2 signature found
+            } catch (Exception e) {
+                // APK Signature Scheme v2 signature was found but did not verify
+                throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+                        "Failed to collect certificates from " + apkPath
+                                + " using APK Signature Scheme v2",
+                        e);
+            }
+
+            if (verified) {
+                if (pkg.mCertificates == null) {
+                    pkg.mCertificates = allSignersCerts;
+                    pkg.mSignatures = signatures;
+                    pkg.mSigningKeys = new ArraySet<>(allSignersCerts.length);
+                    for (int i = 0; i < allSignersCerts.length; i++) {
+                        Certificate[] signerCerts = allSignersCerts[i];
+                        Certificate signerCert = signerCerts[0];
+                        pkg.mSigningKeys.add(signerCert.getPublicKey());
+                    }
+                } else {
+                    if (!Signature.areExactMatch(pkg.mSignatures, signatures)) {
+                        throw new PackageParserException(
+                                INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
+                                apkPath + " has mismatched certificates");
+                    }
+                }
+                // Not yet done, because we need to confirm that AndroidManifest.xml exists and,
+                // if requested, that classes.dex exists.
+            }
+        }
+
+        boolean codeFound = false;
         StrictJarFile jarFile = null;
         try {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "strictJarFileCtor");
-            jarFile = new StrictJarFile(apkPath);
+            jarFile = new StrictJarFile(
+                    apkPath,
+                    !verified // whether to verify JAR signature
+                    );
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
 
             // Always verify manifest, regardless of source
@@ -1101,12 +1089,22 @@
                         "Package " + apkPath + " has no manifest");
             }
 
+            // Optimization: early termination when APK already verified
+            if (verified) {
+                if ((requireCode) && (jarFile.findEntry(BYTECODE_FILENAME) == null)) {
+                    throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            "Package " + apkPath + " code is missing");
+                }
+                return;
+            }
+
+            // APK's integrity needs to be verified using JAR signature scheme.
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "buildVerifyList");
             final List<ZipEntry> toVerify = new ArrayList<>();
             toVerify.add(manifestEntry);
 
             // If we're parsing an untrusted package, verify all contents
-            if (!skipVerification && (parseFlags & PARSE_IS_SYSTEM) == 0) {
+            if ((parseFlags & PARSE_IS_SYSTEM) == 0) {
                 final Iterator<ZipEntry> i = jarFile.iterator();
                 while (i.hasNext()) {
                     final ZipEntry entry = i.next();
@@ -1150,9 +1148,6 @@
                     for (int i=0; i < entryCerts.length; i++) {
                         pkg.mSigningKeys.add(entryCerts[i][0].getPublicKey());
                     }
-                    if (skipVerification) {
-                        break;
-                    }
                 } else {
                     if (!Signature.areExactMatch(pkg.mSignatures, entrySignatures)) {
                         throw new PackageParserException(
@@ -1218,9 +1213,7 @@
             if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
                 // TODO: factor signature related items out of Package object
                 final Package tempPkg = new Package(null);
-                // TODO: fix b/25118622; pass in '0' for parse flags
-                collectCertificates(tempPkg, apkFile, 0 /*apkFlags*/,
-                        flags & PARSE_SKIP_VERIFICATION);
+                collectCertificates(tempPkg, apkFile, 0 /*apkFlags*/, 0 /*flags*/);
                 signatures = tempPkg.mSignatures;
             } else {
                 signatures = null;
@@ -3233,16 +3226,28 @@
                 a.info.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
             }
 
-            a.info.resizeable = sa.getBoolean(
-                    R.styleable.AndroidManifestActivity_resizeableActivity,
-                    owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N);
-
-            a.info.supportsPip = a.info.resizeable ? sa.getBoolean(
-                    R.styleable.AndroidManifestActivity_supportsPictureInPicture, false) : false;
-
             a.info.screenOrientation = sa.getInt(
                     R.styleable.AndroidManifestActivity_screenOrientation,
-                    ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+                    SCREEN_ORIENTATION_UNSPECIFIED);
+
+            a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+            if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity, true)) {
+                    if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture,
+                            false)) {
+                        a.info.resizeMode = RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
+                    } else {
+                        a.info.resizeMode = RESIZE_MODE_RESIZEABLE;
+                    }
+                }
+            } else if (a.info.screenOrientation == SCREEN_ORIENTATION_UNSPECIFIED
+                    && (a.info.flags & FLAG_IMMERSIVE) == 0) {
+                a.info.resizeMode = RESIZE_MODE_CROP_WINDOWS;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) {
+                a.info.flags |= FLAG_ALWAYS_FOCUSABLE;
+            }
 
             a.info.lockTaskLaunchMode =
                     sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
@@ -3485,6 +3490,8 @@
         info.parentActivityName = target.info.parentActivityName;
         info.maxRecents = target.info.maxRecents;
         info.layout = target.info.layout;
+        info.resizeMode = target.info.resizeMode;
+        info.encryptionAware = target.info.encryptionAware;
 
         Activity a = new Activity(mParseActivityAliasArgs, info);
         if (outError[0] != null) {
@@ -3949,6 +3956,11 @@
             s.info.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS;
         }
         if (sa.getBoolean(
+                com.android.internal.R.styleable.AndroidManifestService_externalService,
+                false)) {
+            s.info.flags |= ServiceInfo.FLAG_EXTERNAL_SERVICE;
+        }
+        if (sa.getBoolean(
                 com.android.internal.R.styleable.AndroidManifestService_singleUser,
                 false)) {
             s.info.flags |= ServiceInfo.FLAG_SINGLE_USER;
@@ -4502,12 +4514,6 @@
         /* The required account type without which this application will not function */
         public String mRequiredAccountType;
 
-        /**
-         * Digest suitable for comparing whether this package's manifest is the
-         * same as another.
-         */
-        public ManifestDigest manifestDigest;
-
         public String mOverlayTarget;
         public int mOverlayPriority;
         public boolean mTrustedOverlay;
@@ -4657,6 +4663,13 @@
                     && !isForwardLocked() && !applicationInfo.isExternalAsec();
         }
 
+        public boolean isMatch(int flags) {
+            if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
+                return isSystemApp();
+            }
+            return true;
+        }
+
         public String toString() {
             return "Package{"
                 + Integer.toHexString(System.identityHashCode(this))
@@ -4907,7 +4920,7 @@
     public static ApplicationInfo generateApplicationInfo(Package p, int flags,
             PackageUserState state, int userId) {
         if (p == null) return null;
-        if (!checkUseInstalledOrHidden(flags, state)) {
+        if (!checkUseInstalledOrHidden(flags, state) || !p.isMatch(flags)) {
             return null;
         }
         if (!copyNeeded(flags, p, state, null, userId)
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 91fdf7f..38e0044 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -17,9 +17,20 @@
 package android.content.pm;
 
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import static android.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_SYSTEM_ONLY;
 
 import android.util.ArraySet;
 
+import com.android.internal.util.ArrayUtils;
+
 /**
  * Per-user state information about a package.
  * @hide
@@ -58,12 +69,77 @@
         hidden = o.hidden;
         suspended = o.suspended;
         lastDisableAppCaller = o.lastDisableAppCaller;
-        disabledComponents = o.disabledComponents != null
-                ? new ArraySet<>(o.disabledComponents) : null;
-        enabledComponents = o.enabledComponents != null
-                ? new ArraySet<>(o.enabledComponents) : null;
+        disabledComponents = ArrayUtils.cloneOrNull(o.disabledComponents);
+        enabledComponents = ArrayUtils.cloneOrNull(o.enabledComponents);
         blockUninstall = o.blockUninstall;
         domainVerificationStatus = o.domainVerificationStatus;
         appLinkGeneration = o.appLinkGeneration;
     }
+
+    /**
+     * Test if this package is installed.
+     */
+    public boolean isInstalled(int flags) {
+        return (this.installed && !this.hidden)
+                || (flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0;
+    }
+
+    /**
+     * Test if the given component is considered installed, enabled and a match
+     * for the given flags.
+     */
+    public boolean isMatch(ComponentInfo componentInfo, int flags) {
+        if (!isInstalled(flags)) return false;
+        if (!isEnabled(componentInfo, flags)) return false;
+
+        if ((flags & MATCH_SYSTEM_ONLY) != 0) {
+            if (!componentInfo.applicationInfo.isSystemApp()) {
+                return false;
+            }
+        }
+
+        final boolean matchesUnaware = ((flags & MATCH_ENCRYPTION_UNAWARE) != 0)
+                && !componentInfo.encryptionAware;
+        final boolean matchesAware = ((flags & MATCH_ENCRYPTION_AWARE) != 0)
+                && componentInfo.encryptionAware;
+        return matchesUnaware || matchesAware;
+    }
+
+    /**
+     * Test if the given component is considered enabled.
+     */
+    public boolean isEnabled(ComponentInfo componentInfo, int flags) {
+        if ((flags & MATCH_DISABLED_COMPONENTS) != 0) {
+            return true;
+        }
+
+        // First check if the overall package is disabled; if the package is
+        // enabled then fall through to check specific component
+        switch (this.enabled) {
+            case COMPONENT_ENABLED_STATE_DISABLED:
+            case COMPONENT_ENABLED_STATE_DISABLED_USER:
+                return false;
+            case COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:
+                if ((flags & MATCH_DISABLED_UNTIL_USED_COMPONENTS) == 0) {
+                    return false;
+                }
+            case COMPONENT_ENABLED_STATE_DEFAULT:
+                if (!componentInfo.applicationInfo.enabled) {
+                    return false;
+                }
+            case COMPONENT_ENABLED_STATE_ENABLED:
+                break;
+        }
+
+        // Check if component has explicit state before falling through to
+        // the manifest default
+        if (ArrayUtils.contains(this.enabledComponents, componentInfo.name)) {
+            return true;
+        }
+        if (ArrayUtils.contains(this.disabledComponents, componentInfo.name)) {
+            return false;
+        }
+
+        return componentInfo.enabled;
+    }
 }
diff --git a/core/java/android/content/pm/ParceledListSlice.java b/core/java/android/content/pm/ParceledListSlice.java
index cfb4473..945858e6 100644
--- a/core/java/android/content/pm/ParceledListSlice.java
+++ b/core/java/android/content/pm/ParceledListSlice.java
@@ -24,6 +24,7 @@
 import android.util.Log;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -50,6 +51,10 @@
 
     private final List<T> mList;
 
+    public static <T extends Parcelable> ParceledListSlice<T> emptyList() {
+        return new ParceledListSlice<T>(Collections.<T> emptyList());
+    }
+
     public ParceledListSlice(List<T> list) {
         mList = list;
     }
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index a413f36..bb28bde 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -365,7 +365,7 @@
     protected List<ResolveInfo> queryIntentServices(int userId) {
         final PackageManager pm = mContext.getPackageManager();
         return pm.queryIntentServicesAsUser(new Intent(mInterfaceName),
-                PackageManager.GET_META_DATA | PackageManager.GET_ENCRYPTION_UNAWARE_COMPONENTS,
+                PackageManager.GET_META_DATA | PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
                 userId);
     }
 
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index d5d3007..c9be6ed 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -172,7 +172,8 @@
      */
     public boolean handleAllWebDataURI;
 
-    private ComponentInfo getComponentInfo() {
+    /** {@hide} */
+    public ComponentInfo getComponentInfo() {
         if (activityInfo != null) return activityInfo;
         if (serviceInfo != null) return serviceInfo;
         if (providerInfo != null) return providerInfo;
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 74e5c2a..eecf0de 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -49,6 +49,14 @@
     public static final int FLAG_ISOLATED_PROCESS = 0x0002;
 
     /**
+     * Bit in {@link #flags}: If set, the service can be bound and run in the
+     * calling application's package, rather than the package in which it is
+     * declared.  Set from {@link android.R.attr#externalService} attribute.
+     * @hide
+     */
+    public static final int FLAG_EXTERNAL_SERVICE = 0x0004;
+
+    /**
      * Bit in {@link #flags}: If set, a single instance of the service will
      * run for all users on the device.  Set from the
      * {@link android.R.attr#singleUser} attribute.
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index e3050fe..9cf4675 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -145,6 +145,10 @@
         return (flags & FLAG_EPHEMERAL) == FLAG_EPHEMERAL;
     }
 
+    public boolean isInitialized() {
+        return (flags & FLAG_INITIALIZED) == FLAG_INITIALIZED;
+    }
+
     /**
      * Returns true if the user is a split system user.
      * <p>If {@link UserManager#isSplitSystemUser split system user mode} is not enabled,
diff --git a/core/java/android/content/pm/VerificationParams.java b/core/java/android/content/pm/VerificationParams.java
index e5119b6..f90d295 100644
--- a/core/java/android/content/pm/VerificationParams.java
+++ b/core/java/android/content/pm/VerificationParams.java
@@ -16,7 +16,6 @@
 
 package android.content.pm;
 
-import android.content.pm.ManifestDigest;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -51,12 +50,6 @@
     private int mInstallerUid;
 
     /**
-     * An object that holds the digest of the package which can be used to
-     * verify ownership.
-     */
-    private final ManifestDigest mManifestDigest;
-
-    /**
      * Creates verification specifications for installing with application verification.
      *
      * @param verificationURI The location of the supplementary verification
@@ -67,16 +60,13 @@
      *            May be {@code null}.
      * @param originatingUid UID of the application that the install request originated
      *            from, or NO_UID if not present
-     * @param manifestDigest an object that holds the digest of the package
-     *            which can be used to verify ownership. May be {@code null}.
      */
     public VerificationParams(Uri verificationURI, Uri originatingURI, Uri referrer,
-            int originatingUid, ManifestDigest manifestDigest) {
+            int originatingUid) {
         mVerificationURI = verificationURI;
         mOriginatingURI = originatingURI;
         mReferrer = referrer;
         mOriginatingUid = originatingUid;
-        mManifestDigest = manifestDigest;
         mInstallerUid = NO_UID;
     }
 
@@ -97,10 +87,6 @@
         return mOriginatingUid;
     }
 
-    public ManifestDigest getManifestDigest() {
-        return mManifestDigest;
-    }
-
     /** @return NO_UID when not set */
     public int getInstallerUid() {
         return mInstallerUid;
@@ -155,14 +141,6 @@
             return false;
         }
 
-        if (mManifestDigest == null) {
-            if (other.mManifestDigest != null) {
-                return false;
-            }
-        } else if (!mManifestDigest.equals(other.mManifestDigest)) {
-            return false;
-        }
-
         if (mInstallerUid != other.mInstallerUid) {
             return false;
         }
@@ -178,8 +156,7 @@
         hash += 7 * (mOriginatingURI == null ? 1 : mOriginatingURI.hashCode());
         hash += 11 * (mReferrer == null ? 1 : mReferrer.hashCode());
         hash += 13 * mOriginatingUid;
-        hash += 17 * (mManifestDigest == null ? 1 : mManifestDigest.hashCode());
-        hash += 19 * mInstallerUid;
+        hash += 17 * mInstallerUid;
 
         return hash;
     }
@@ -196,8 +173,6 @@
         sb.append(mReferrer.toString());
         sb.append(",mOriginatingUid=");
         sb.append(mOriginatingUid);
-        sb.append(",mManifestDigest=");
-        sb.append(mManifestDigest.toString());
         sb.append(",mInstallerUid=");
         sb.append(mInstallerUid);
         sb.append('}');
@@ -211,7 +186,6 @@
         dest.writeParcelable(mOriginatingURI, 0);
         dest.writeParcelable(mReferrer, 0);
         dest.writeInt(mOriginatingUid);
-        dest.writeParcelable(mManifestDigest, 0);
         dest.writeInt(mInstallerUid);
     }
 
@@ -221,7 +195,6 @@
         mOriginatingURI = source.readParcelable(Uri.class.getClassLoader());
         mReferrer = source.readParcelable(Uri.class.getClassLoader());
         mOriginatingUid = source.readInt();
-        mManifestDigest = source.readParcelable(ManifestDigest.class.getClassLoader());
         mInstallerUid = source.readInt();
     }
 
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 7669053..7b0b98d 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -16,6 +16,11 @@
 
 package android.content.res;
 
+import android.annotation.AnyRes;
+import android.annotation.ArrayRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringRes;
 import android.os.ParcelFileDescriptor;
 import android.util.Log;
 import android.util.SparseArray;
@@ -142,80 +147,95 @@
     }
 
     /**
-     * Retrieve the string value associated with a particular resource
-     * identifier for the current configuration / skin.
+     * Retrieves the string value associated with a particular resource
+     * identifier for the current configuration.
+     *
+     * @param resId the resource identifier to load
+     * @return the string value, or {@code null}
      */
-    /*package*/ final CharSequence getResourceText(int ident) {
+    @Nullable
+    final CharSequence getResourceText(@StringRes int resId) {
         synchronized (this) {
-            TypedValue tmpValue = mValue;
-            int block = loadResourceValue(ident, (short) 0, tmpValue, true);
-            if (block >= 0) {
-                if (tmpValue.type == TypedValue.TYPE_STRING) {
-                    return mStringBlocks[block].get(tmpValue.data);
-                }
-                return tmpValue.coerceToString();
+            final TypedValue outValue = mValue;
+            if (getResourceValue(resId, 0, outValue, true)) {
+                return outValue.coerceToString();
             }
+            return null;
         }
-        return null;
     }
 
     /**
-     * Retrieve the string value associated with a particular resource
-     * identifier for the current configuration / skin.
+     * Retrieves the string value associated with a particular resource
+     * identifier for the current configuration.
+     *
+     * @param resId the resource identifier to load
+     * @param bagEntryId
+     * @return the string value, or {@code null}
      */
-    /*package*/ final CharSequence getResourceBagText(int ident, int bagEntryId) {
+    @Nullable
+    final CharSequence getResourceBagText(@StringRes int resId, int bagEntryId) {
         synchronized (this) {
-            TypedValue tmpValue = mValue;
-            int block = loadResourceBagValue(ident, bagEntryId, tmpValue, true);
-            if (block >= 0) {
-                if (tmpValue.type == TypedValue.TYPE_STRING) {
-                    return mStringBlocks[block].get(tmpValue.data);
-                }
-                return tmpValue.coerceToString();
+            final TypedValue outValue = mValue;
+            final int block = loadResourceBagValue(resId, bagEntryId, outValue, true);
+            if (block < 0) {
+                return null;
             }
+            if (outValue.type == TypedValue.TYPE_STRING) {
+                return mStringBlocks[block].get(outValue.data);
+            }
+            return outValue.coerceToString();
         }
-        return null;
     }
 
     /**
-     * Retrieve the string array associated with a particular resource
-     * identifier.
-     * @param id Resource id of the string array
+     * Retrieves the string array associated with a particular resource
+     * identifier for the current configuration.
+     *
+     * @param resId the resource identifier of the string array
+     * @return the string array, or {@code null}
      */
-    /*package*/ final String[] getResourceStringArray(final int id) {
-        String[] retArray = getArrayStringResource(id);
-        return retArray;
+    @Nullable
+    final String[] getResourceStringArray(@ArrayRes int resId) {
+        return getArrayStringResource(resId);
     }
 
-
-    /*package*/ final boolean getResourceValue(int ident,
-                                               int density,
-                                               TypedValue outValue,
-                                               boolean resolveRefs)
-    {
-        int block = loadResourceValue(ident, (short) density, outValue, resolveRefs);
-        if (block >= 0) {
-            if (outValue.type != TypedValue.TYPE_STRING) {
-                return true;
-            }
+    /**
+     * Populates {@code outValue} with the data associated a particular
+     * resource identifier for the current configuration.
+     *
+     * @param resId the resource identifier to load
+     * @param densityDpi the density bucket for which to load the resource
+     * @param outValue the typed value in which to put the data
+     * @param resolveRefs {@code true} to resolve references, {@code false}
+     *                    to leave them unresolved
+     * @return {@code true} if the data was loaded into {@code outValue},
+     *         {@code false} otherwise
+     */
+    final boolean getResourceValue(@AnyRes int resId, int densityDpi, @NonNull TypedValue outValue,
+            boolean resolveRefs) {
+        final int block = loadResourceValue(resId, (short) densityDpi, outValue, resolveRefs);
+        if (block < 0) {
+            return false;
+        }
+        if (outValue.type == TypedValue.TYPE_STRING) {
             outValue.string = mStringBlocks[block].get(outValue.data);
-            return true;
         }
-        return false;
+        return true;
     }
 
     /**
      * Retrieve the text array associated with a particular resource
      * identifier.
-     * @param id Resource id of the string array
+     *
+     * @param resId the resource id of the string array
      */
-    /*package*/ final CharSequence[] getResourceTextArray(final int id) {
-        int[] rawInfoArray = getArrayStringInfo(id);
-        int rawInfoArrayLen = rawInfoArray.length;
+    final CharSequence[] getResourceTextArray(@ArrayRes int resId) {
+        final int[] rawInfoArray = getArrayStringInfo(resId);
+        final int rawInfoArrayLen = rawInfoArray.length;
         final int infoArrayLen = rawInfoArrayLen / 2;
         int block;
         int index;
-        CharSequence[] retArray = new CharSequence[infoArrayLen];
+        final CharSequence[] retArray = new CharSequence[infoArrayLen];
         for (int i = 0, j = 0; i < rawInfoArrayLen; i = i + 2, j++) {
             block = rawInfoArray[i];
             index = rawInfoArray[i + 1];
@@ -223,32 +243,45 @@
         }
         return retArray;
     }
-    
-    /*package*/ final boolean getThemeValue(long theme, int ident,
-            TypedValue outValue, boolean resolveRefs) {
-        int block = loadThemeAttributeValue(theme, ident, outValue, resolveRefs);
-        if (block >= 0) {
-            if (outValue.type != TypedValue.TYPE_STRING) {
-                return true;
-            }
-            StringBlock[] blocks = mStringBlocks;
-            if (blocks == null) {
-                ensureStringBlocks();
-                blocks = mStringBlocks;
-            }
-            outValue.string = blocks[block].get(outValue.data);
-            return true;
+
+    /**
+     * Populates {@code outValue} with the data associated with a particular
+     * resource identifier for the current configuration. Resolves theme
+     * attributes against the specified theme.
+     *
+     * @param theme the native pointer of the theme
+     * @param resId the resource identifier to load
+     * @param outValue the typed value in which to put the data
+     * @param resolveRefs {@code true} to resolve references, {@code false}
+     *                    to leave them unresolved
+     * @return {@code true} if the data was loaded into {@code outValue},
+     *         {@code false} otherwise
+     */
+    final boolean getThemeValue(long theme, @AnyRes int resId, @NonNull TypedValue outValue,
+            boolean resolveRefs) {
+        final int block = loadThemeAttributeValue(theme, resId, outValue, resolveRefs);
+        if (block < 0) {
+            return false;
         }
-        return false;
+        if (outValue.type == TypedValue.TYPE_STRING) {
+            final StringBlock[] blocks = ensureStringBlocks();
+            outValue.string = blocks[block].get(outValue.data);
+        }
+        return true;
     }
 
-    /*package*/ final void ensureStringBlocks() {
-        if (mStringBlocks == null) {
-            synchronized (this) {
-                if (mStringBlocks == null) {
-                    makeStringBlocks(sSystem.mStringBlocks);
-                }
+    /**
+     * Ensures the string blocks are loaded.
+     *
+     * @return the string blocks
+     */
+    @NonNull
+    final StringBlock[] ensureStringBlocks() {
+        synchronized (this) {
+            if (mStringBlocks == null) {
+                makeStringBlocks(sSystem.mStringBlocks);
             }
+            return mStringBlocks;
         }
     }
 
@@ -698,6 +731,18 @@
      */
     public native final String[] getLocales();
 
+    /**
+     * Same as getLocales(), except that locales that are only provided by the system (i.e. those
+     * present in framework-res.apk or its overlays) will not be listed.
+     *
+     * For example, if the "system" assets support English, French, and German, and the additional
+     * assets support Cherokee and French, getLocales() would return
+     * [Cherokee, English, French, German], while getNonSystemLocales() would return
+     * [Cherokee, French].
+     * {@hide}
+     */
+    public native final String[] getNonSystemLocales();
+
     /** {@hide} */
     public native final Configuration[] getSizeConfigurations();
 
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index 19921b5..9e1b312 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -69,7 +69,7 @@
  * href="{@docRoot}guide/topics/resources/color-list-resource.html">Color State
  * List Resource</a>.</p>
  */
-public class ColorStateList implements Parcelable {
+public class ColorStateList extends ComplexColor implements Parcelable {
     private static final String TAG = "ColorStateList";
 
     private static final int DEFAULT_COLOR = Color.RED;
@@ -209,7 +209,7 @@
      * @return A new color state list for the current tag.
      */
     @NonNull
-    private static ColorStateList createFromXmlInner(@NonNull Resources r,
+    static ColorStateList createFromXmlInner(@NonNull Resources r,
             @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
         final String name = parser.getName();
@@ -340,6 +340,7 @@
      * @return whether a theme can be applied to this color state list
      * @hide only for resource preloading
      */
+    @Override
     public boolean canApplyTheme() {
         return mThemeAttrs != null;
     }
@@ -419,6 +420,7 @@
      *         attributes
      * @hide only for resource preloading
      */
+    @Override
     public ColorStateList obtainForTheme(Theme t) {
         if (t == null || !canApplyTheme()) {
             return this;
@@ -460,6 +462,7 @@
      *         otherwise.
      * @see #getColorForState(int[], int)
      */
+    @Override
     public boolean isStateful() {
         return mStateSpecs.length > 1;
     }
@@ -602,14 +605,14 @@
      * @return a factory that can create new instances of this ColorStateList
      * @hide only for resource preloading
      */
-    public ConstantState<ColorStateList> getConstantState() {
+    public ConstantState<ComplexColor> getConstantState() {
         if (mFactory == null) {
             mFactory = new ColorStateListFactory(this);
         }
         return mFactory;
     }
 
-    private static class ColorStateListFactory extends ConstantState<ColorStateList> {
+    private static class ColorStateListFactory extends ConstantState<ComplexColor> {
         private final ColorStateList mSrc;
 
         public ColorStateListFactory(ColorStateList src) {
@@ -628,7 +631,7 @@
 
         @Override
         public ColorStateList newInstance(Resources res, Theme theme) {
-            return mSrc.obtainForTheme(theme);
+            return (ColorStateList) mSrc.obtainForTheme(theme);
         }
     }
 
diff --git a/core/java/android/content/res/ComplexColor.java b/core/java/android/content/res/ComplexColor.java
new file mode 100644
index 0000000..d96ec62
--- /dev/null
+++ b/core/java/android/content/res/ComplexColor.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.ColorInt;
+import android.content.res.Resources.Theme;
+import android.graphics.Color;
+
+/**
+ * Defines an abstract class for the complex color information, like
+ * {@link android.content.res.ColorStateList} or {@link android.content.res.GradientColor}
+ */
+public abstract class ComplexColor {
+    /**
+     * @return {@code true}  if this ComplexColor changes color based on state, {@code false}
+     * otherwise.
+     */
+    public boolean isStateful() { return false; }
+
+    /**
+     * @return the default color.
+     */
+    @ColorInt
+    public abstract int getDefaultColor();
+
+    /**
+     * @hide only for resource preloading
+     *
+     */
+    public abstract ConstantState<ComplexColor> getConstantState();
+
+    /**
+     * @hide only for resource preloading
+     */
+    public abstract boolean canApplyTheme();
+
+    /**
+     * @hide only for resource preloading
+     */
+    public abstract ComplexColor obtainForTheme(Theme t);
+}
diff --git a/core/java/android/content/res/GradientColor.java b/core/java/android/content/res/GradientColor.java
new file mode 100644
index 0000000..98ef2ea
--- /dev/null
+++ b/core/java/android/content/res/GradientColor.java
@@ -0,0 +1,523 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.ColorInt;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.Resources.Theme;
+
+import com.android.internal.R;
+import com.android.internal.util.GrowingArrayUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.graphics.LinearGradient;
+import android.graphics.RadialGradient;
+import android.graphics.Shader;
+import android.graphics.SweepGradient;
+import android.graphics.drawable.GradientDrawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Xml;
+
+import java.io.IOException;
+
+
+public class GradientColor extends ComplexColor {
+    private static final String TAG = "GradientColor";
+
+    private static final boolean DBG_GRADIENT = false;
+
+    /** Lazily-created factory for this GradientColor. */
+    private GradientColorFactory mFactory;
+
+    private 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>
+    private int mGradientType = GradientDrawable.LINEAR_GRADIENT;
+
+    private float mCenterX = 0f;
+    private float mCenterY = 0f;
+
+    private float mStartX = 0f;
+    private float mStartY = 0f;
+    private float mEndX = 0f;
+    private float mEndY = 0f;
+
+    private int mStartColor = 0;
+    private int mCenterColor = 0;
+    private int mEndColor = 0;
+    private boolean mHasCenterColor = false;
+
+    private float mGradientRadius = 0f;
+
+    // Below are the attributes for the <item> element.
+    private int[] mItemColors;
+    private float[] mItemOffsets;
+
+    // Theme attributes for the root and item elements.
+    private int[] mThemeAttrs;
+    private int[][] mItemsThemeAttrs;
+
+    private GradientColor() {
+    }
+
+    private GradientColor(GradientColor copy) {
+        if (copy != null) {
+            mChangingConfigurations = copy.mChangingConfigurations;
+            mDefaultColor = copy.mDefaultColor;
+            mShader = copy.mShader;
+            mGradientType = copy.mGradientType;
+            mCenterX = copy.mCenterX;
+            mCenterY = copy.mCenterY;
+            mStartX = copy.mStartX;
+            mStartY = copy.mStartY;
+            mEndX = copy.mEndX;
+            mEndY = copy.mEndY;
+            mStartColor = copy.mStartColor;
+            mCenterColor = copy.mCenterColor;
+            mEndColor = copy.mEndColor;
+            mHasCenterColor = copy.mHasCenterColor;
+            mGradientRadius = copy.mGradientRadius;
+
+            if (copy.mItemColors != null) {
+                mItemColors = copy.mItemColors.clone();
+            }
+            if (copy.mItemOffsets != null) {
+                mItemOffsets = copy.mItemOffsets.clone();
+            }
+
+            if (copy.mThemeAttrs != null) {
+                mThemeAttrs = copy.mThemeAttrs.clone();
+            }
+            if (copy.mItemsThemeAttrs != null) {
+                mItemsThemeAttrs = copy.mItemsThemeAttrs.clone();
+            }
+        }
+    }
+
+    /**
+     * Update the root level's attributes, either for inflate or applyTheme.
+     */
+    private void updateRootElementState(TypedArray a) {
+        // Extract the theme attributes, if any.
+        mThemeAttrs = a.extractThemeAttrs();
+
+        mStartX = a.getFloat(
+                R.styleable.GradientColor_startX, mStartX);
+        mStartY = a.getFloat(
+                R.styleable.GradientColor_startY, mStartY);
+        mEndX = a.getFloat(
+                R.styleable.GradientColor_endX, mEndX);
+        mEndY = a.getFloat(
+                R.styleable.GradientColor_endY, mEndY);
+
+        mCenterX = a.getFloat(
+                R.styleable.GradientColor_centerX, mCenterX);
+        mCenterY = a.getFloat(
+                R.styleable.GradientColor_centerY, mCenterY);
+
+        mGradientType = a.getInt(
+                R.styleable.GradientColor_type, mGradientType);
+
+        mStartColor = a.getColor(
+                R.styleable.GradientColor_startColor, mStartColor);
+        mHasCenterColor |= a.hasValue(
+                R.styleable.GradientColor_centerColor);
+        mCenterColor = a.getColor(
+                R.styleable.GradientColor_centerColor, mCenterColor);
+        mEndColor = a.getColor(
+                R.styleable.GradientColor_endColor, mEndColor);
+
+        if (DBG_GRADIENT) {
+            Log.v(TAG, "hasCenterColor is " + mHasCenterColor);
+            if (mHasCenterColor) {
+                Log.v(TAG, "centerColor:" + mCenterColor);
+            }
+            Log.v(TAG, "startColor: " + mStartColor);
+            Log.v(TAG, "endColor: " + mEndColor);
+        }
+
+        mGradientRadius = a.getFloat(R.styleable.GradientColor_gradientRadius,
+                mGradientRadius);
+    }
+
+    /**
+     * Check if the XML content is valid.
+     *
+     * @throws XmlPullParserException if errors were found.
+     */
+    private void validateXmlContent() throws XmlPullParserException {
+        if (mGradientRadius <= 0
+                && mGradientType == GradientDrawable.RADIAL_GRADIENT) {
+            throw new XmlPullParserException(
+                    "<gradient> tag requires 'gradientRadius' "
+                            + "attribute with radial type");
+        }
+    }
+
+    /**
+     * The shader information will be applied to the native VectorDrawable's path.
+     * @hide
+     */
+    public Shader getShader() {
+        return mShader;
+    }
+
+    /**
+     * A public method to create GradientColor from a XML resource.
+     */
+    public static GradientColor createFromXml(Resources r, XmlResourceParser parser, Theme theme)
+            throws XmlPullParserException, IOException {
+        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");
+        }
+
+        return createFromXmlInner(r, parser, attrs, theme);
+    }
+
+    /**
+     * Create from inside an XML document. Called on a parser positioned at a
+     * tag in an XML document, tries to create a GradientColor from that tag.
+     *
+     * @return A new GradientColor for the current tag.
+     * @throws XmlPullParserException if the current tag is not &lt;gradient>
+     */
+    @NonNull
+    static GradientColor createFromXmlInner(@NonNull Resources r,
+            @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)
+            throws XmlPullParserException, IOException {
+        final String name = parser.getName();
+        if (!name.equals("gradient")) {
+            throw new XmlPullParserException(
+                    parser.getPositionDescription() + ": invalid gradient color tag " + name);
+        }
+
+        final GradientColor gradientColor = new GradientColor();
+        gradientColor.inflate(r, parser, attrs, theme);
+        return gradientColor;
+    }
+
+    /**
+     * Fill in this object based on the contents of an XML "gradient" element.
+     */
+    private void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
+            throws XmlPullParserException, IOException {
+        final TypedArray a = Resources.obtainAttributes(r, theme, attrs, R.styleable.GradientColor);
+        updateRootElementState(a);
+        mChangingConfigurations |= a.getChangingConfigurations();
+        a.recycle();
+
+        // Check correctness and throw exception if errors found.
+        validateXmlContent();
+
+        inflateChildElements(r, parser, attrs, theme);
+
+        onColorsChange();
+    }
+
+    /**
+     * Inflates child elements "item"s for each color stop.
+     *
+     * Note that at root level, we need to save ThemeAttrs for theme applied later.
+     * Here similarly, at each child item, we need to save the theme's attributes, and apply theme
+     * later as applyItemsAttrsTheme().
+     */
+    private void inflateChildElements(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @NonNull Theme theme)
+            throws XmlPullParserException, IOException {
+        final int innerDepth = parser.getDepth() + 1;
+        int type;
+        int depth;
+
+        // Pre-allocate the array with some size, for better performance.
+        float[] offsetList = new float[20];
+        int[] colorList = new int[offsetList.length];
+        int[][] themeAttrsList = new int[offsetList.length][];
+
+        int listSize = 0;
+        boolean hasUnresolvedAttrs = false;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && ((depth = parser.getDepth()) >= innerDepth
+                || type != XmlPullParser.END_TAG)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+            if (depth > innerDepth || !parser.getName().equals("item")) {
+                continue;
+            }
+
+            final TypedArray a = Resources.obtainAttributes(r, theme, attrs,
+                    R.styleable.GradientColorItem);
+            boolean hasColor = a.hasValue(R.styleable.GradientColorItem_color);
+            boolean hasOffset = a.hasValue(R.styleable.GradientColorItem_offset);
+            if (!hasColor || !hasOffset) {
+                throw new XmlPullParserException(
+                        parser.getPositionDescription()
+                                + ": <item> tag requires a 'color' attribute and a 'offset' "
+                                + "attribute!");
+            }
+
+            final int[] themeAttrs = a.extractThemeAttrs();
+            int color = a.getColor(R.styleable.GradientColorItem_color, 0);
+            float offset = a.getFloat(R.styleable.GradientColorItem_offset, 0);
+
+            if (DBG_GRADIENT) {
+                Log.v(TAG, "new item color " + color + " " + Integer.toHexString(color));
+                Log.v(TAG, "offset" + offset);
+            }
+            mChangingConfigurations |= a.getChangingConfigurations();
+            a.recycle();
+
+            if (themeAttrs != null) {
+                hasUnresolvedAttrs = true;
+            }
+
+            colorList = GrowingArrayUtils.append(colorList, listSize, color);
+            offsetList = GrowingArrayUtils.append(offsetList, listSize, offset);
+            themeAttrsList = GrowingArrayUtils.append(themeAttrsList, listSize, themeAttrs);
+            listSize++;
+        }
+        if (listSize > 0) {
+            if (hasUnresolvedAttrs) {
+                mItemsThemeAttrs = new int[listSize][];
+                System.arraycopy(themeAttrsList, 0, mItemsThemeAttrs, 0, listSize);
+            } else {
+                mItemsThemeAttrs = null;
+            }
+
+            mItemColors = new int[listSize];
+            mItemOffsets = new float[listSize];
+            System.arraycopy(colorList, 0, mItemColors, 0, listSize);
+            System.arraycopy(offsetList, 0, mItemOffsets, 0, listSize);
+        }
+    }
+
+    /**
+     * Apply theme to all the items.
+     */
+    private void applyItemsAttrsTheme(Theme t) {
+        if (mItemsThemeAttrs == null) {
+            return;
+        }
+
+        boolean hasUnresolvedAttrs = false;
+
+        final int[][] themeAttrsList = mItemsThemeAttrs;
+        final int N = themeAttrsList.length;
+        for (int i = 0; i < N; i++) {
+            if (themeAttrsList[i] != null) {
+                final TypedArray a = t.resolveAttributes(themeAttrsList[i],
+                        R.styleable.GradientColorItem);
+
+                // Extract the theme attributes, if any, before attempting to
+                // read from the typed array. This prevents a crash if we have
+                // unresolved attrs.
+                themeAttrsList[i] = a.extractThemeAttrs(themeAttrsList[i]);
+                if (themeAttrsList[i] != null) {
+                    hasUnresolvedAttrs = true;
+                }
+
+                mItemColors[i] = a.getColor(R.styleable.GradientColorItem_color, mItemColors[i]);
+                mItemOffsets[i] = a.getFloat(R.styleable.GradientColorItem_offset, mItemOffsets[i]);
+                if (DBG_GRADIENT) {
+                    Log.v(TAG, "applyItemsAttrsTheme Colors[i] " + i + " " +
+                            Integer.toHexString(mItemColors[i]));
+                    Log.v(TAG, "Offsets[i] " + i + " " + mItemOffsets[i]);
+                }
+
+                // Account for any configuration changes.
+                mChangingConfigurations |= a.getChangingConfigurations();
+
+                a.recycle();
+            }
+        }
+
+        if (!hasUnresolvedAttrs) {
+            mItemsThemeAttrs = null;
+        }
+    }
+
+    private void onColorsChange() {
+        int[] tempColors = null;
+        float[] tempOffsets = null;
+
+        if (mItemColors != null) {
+            int length = mItemColors.length;
+            tempColors = new int[length];
+            tempOffsets = new float[length];
+
+            for (int i = 0; i < length; i++) {
+                tempColors[i] = mItemColors[i];
+                tempOffsets[i] = mItemOffsets[i];
+            }
+        } else {
+            if (mHasCenterColor) {
+                tempColors = new int[3];
+                tempColors[0] = mStartColor;
+                tempColors[1] = mCenterColor;
+                tempColors[2] = mEndColor;
+
+                tempOffsets = new float[3];
+                tempOffsets[0] = 0.0f;
+                // Since 0.5f is default value, try to take the one that isn't 0.5f
+                tempOffsets[1] = 0.5f;
+                tempOffsets[2] = 1f;
+            } else {
+                tempColors = new int[2];
+                tempColors[0] = mStartColor;
+                tempColors[1] = mEndColor;
+            }
+        }
+        if (tempColors.length < 2) {
+            Log.w(TAG, "<gradient> tag requires 2 color values specified!" + tempColors.length
+                    + " " + tempColors);
+        }
+
+        if (mGradientType == GradientDrawable.LINEAR_GRADIENT) {
+            mShader = new LinearGradient(mStartX, mStartY, mEndX, mEndY, tempColors, tempOffsets,
+                    Shader.TileMode.CLAMP);
+        } else {
+            if (mGradientType == GradientDrawable.RADIAL_GRADIENT) {
+                mShader = new RadialGradient(mCenterX, mCenterY, mGradientRadius, tempColors,
+                        tempOffsets, Shader.TileMode.CLAMP);
+            } else {
+                mShader = new SweepGradient(mCenterX, mCenterY, tempColors, tempOffsets);
+            }
+        }
+        mDefaultColor = tempColors[0];
+    }
+
+    /**
+     * For Gradient color, the default color is not very useful, since the gradient will override
+     * the color information anyway.
+     */
+    @Override
+    @ColorInt
+    public int getDefaultColor() {
+        return mDefaultColor;
+    }
+
+    /**
+     * Similar to ColorStateList, setup constant state and its factory.
+     * @hide only for resource preloading
+     */
+    @Override
+    public ConstantState<ComplexColor> getConstantState() {
+        if (mFactory == null) {
+            mFactory = new GradientColorFactory(this);
+        }
+        return mFactory;
+    }
+
+    private static class GradientColorFactory extends ConstantState<ComplexColor> {
+        private final GradientColor mSrc;
+
+        public GradientColorFactory(GradientColor src) {
+            mSrc = src;
+        }
+
+        @Override
+        public int getChangingConfigurations() {
+            return mSrc.mChangingConfigurations;
+        }
+
+        @Override
+        public GradientColor newInstance() {
+            return mSrc;
+        }
+
+        @Override
+        public GradientColor newInstance(Resources res, Theme theme) {
+            return mSrc.obtainForTheme(theme);
+        }
+    }
+
+    /**
+     * Returns an appropriately themed gradient color.
+     *
+     * @param t the theme to apply
+     * @return a copy of the gradient color the theme applied, or the
+     * gradient itself if there were no unresolved theme
+     * attributes
+     * @hide only for resource preloading
+     */
+    @Override
+    public GradientColor obtainForTheme(Theme t) {
+        if (t == null || !canApplyTheme()) {
+            return this;
+        }
+
+        final GradientColor clone = new GradientColor(this);
+        clone.applyTheme(t);
+        return clone;
+    }
+
+    private void applyTheme(Theme t) {
+        if (mThemeAttrs != null) {
+            applyRootAttrsTheme(t);
+        }
+        if (mItemsThemeAttrs != null) {
+            applyItemsAttrsTheme(t);
+        }
+        onColorsChange();
+    }
+
+    private void applyRootAttrsTheme(Theme t) {
+        final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.GradientColor);
+        // mThemeAttrs will be set to null if if there are no theme attributes in the
+        // typed array.
+        mThemeAttrs = a.extractThemeAttrs(mThemeAttrs);
+        // merging the attributes update inside the updateRootElementState().
+        updateRootElementState(a);
+
+        // Account for any configuration changes.
+        mChangingConfigurations |= a.getChangingConfigurations();
+        a.recycle();
+    }
+
+
+    /**
+     * Returns whether a theme can be applied to this gradient color, which
+     * usually indicates that the gradient color has unresolved theme
+     * attributes.
+     *
+     * @return whether a theme can be applied to this gradient color.
+     * @hide only for resource preloading
+     */
+    @Override
+    public boolean canApplyTheme() {
+        return mThemeAttrs != null || mItemsThemeAttrs != null;
+    }
+
+}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 60c6e82..4967d05 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -56,6 +56,7 @@
 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;
 
@@ -115,8 +116,8 @@
     private static final LongSparseArray<ConstantState>[] sPreloadedDrawables;
     private static final LongSparseArray<ConstantState> sPreloadedColorDrawables
             = new LongSparseArray<>();
-    private static final LongSparseArray<android.content.res.ConstantState<ColorStateList>>
-            sPreloadedColorStateLists = 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);
@@ -133,7 +134,7 @@
     private final Configuration mTmpConfig = new Configuration();
     private final DrawableCache mDrawableCache = new DrawableCache(this);
     private final DrawableCache mColorDrawableCache = new DrawableCache(this);
-    private final ConfigurationBoundResourceCache<ColorStateList> mColorStateListCache =
+    private final ConfigurationBoundResourceCache<ComplexColor> mComplexColorCache =
             new ConfigurationBoundResourceCache<>(this);
     private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
             new ConfigurationBoundResourceCache<>(this);
@@ -151,8 +152,9 @@
 
     private boolean mPreloading;
 
+    // Cyclical cache used for recently-accessed XML files.
     private int mLastCachedXmlBlockIndex = -1;
-    private final int[] mCachedXmlBlockIds = { 0, 0, 0, 0 };
+    private final String[] mCachedXmlBlockFiles = new String[4];
     private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[4];
 
     final AssetManager mAssets;
@@ -160,7 +162,7 @@
     final DisplayMetrics mMetrics = new DisplayMetrics();
 
     private final Configuration mConfiguration = new Configuration();
-    private Locale mResolvedLocale = null;
+
     private PluralRules mPluralRule;
 
     private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
@@ -316,16 +318,6 @@
     }
 
     /**
-     * Return the Locale resulting from locale negotiation between the Resources and the
-     * Configuration objects used to construct the Resources. The locale is used for retrieving
-     * resources as well as for determining plural rules.
-     */
-    @NonNull
-    public Locale getResolvedLocale() {
-        return mResolvedLocale;
-    }
-
-    /**
      * Return the string value associated with a particular resource ID.  The
      * returned object will be a String if this is a plain string; it will be
      * some other type of CharSequence if it is styled.
@@ -389,7 +381,7 @@
     private PluralRules getPluralRule() {
         synchronized (sSync) {
             if (mPluralRule == null) {
-                mPluralRule = PluralRules.forLocale(mResolvedLocale);
+                mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().getPrimary());
             }
             return mPluralRule;
         }
@@ -452,7 +444,7 @@
     @NonNull
     public String getString(@StringRes int id, Object... formatArgs) throws NotFoundException {
         final String raw = getString(id);
-        return String.format(mResolvedLocale, raw, formatArgs);
+        return String.format(mConfiguration.getLocales().getPrimary(), raw, formatArgs);
     }
 
     /**
@@ -483,7 +475,7 @@
     public String getQuantityString(@PluralsRes int id, int quantity, Object... formatArgs)
             throws NotFoundException {
         String raw = getQuantityText(id, quantity).toString();
-        return String.format(mResolvedLocale, raw, formatArgs);
+        return String.format(mConfiguration.getLocales().getPrimary(), raw, formatArgs);
     }
 
     /**
@@ -866,6 +858,11 @@
         try {
             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;
+
             /*
              * Pretend the requested density is actually the display density. If
              * the drawable returned is not the requested density, then force it
@@ -881,7 +878,7 @@
                 }
             }
 
-            return loadDrawable(value, id, theme);
+            return loadDrawable(value, id, theme, useCache);
         } finally {
             releaseTempTypedValue(value);
         }
@@ -1944,9 +1941,8 @@
             final int configChanges = calcConfigChanges(config);
 
             LocaleList locales = mConfiguration.getLocales();
-            final boolean setLocalesToDefault = locales.isEmpty();
-            if (setLocalesToDefault) {
-                locales = LocaleList.getDefault();
+            if (locales.isEmpty()) {
+                locales = LocaleList.getAdjustedDefault();
                 mConfiguration.setLocales(locales);
             }
             if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
@@ -1974,12 +1970,8 @@
                 keyboardHidden = mConfiguration.keyboardHidden;
             }
 
-            if (setLocalesToDefault || mResolvedLocale == null
-                    || (configChanges & Configuration.NATIVE_CONFIG_LOCALE) != 0) {
-                mResolvedLocale = locales.getFirstMatch(mAssets.getLocales());
-            }
             mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
-                    adjustLanguageTag(mResolvedLocale.toLanguageTag()),
+                    adjustLanguageTag(locales.getPrimary().toLanguageTag()),
                     mConfiguration.orientation,
                     mConfiguration.touchscreen,
                     mConfiguration.densityDpi, mConfiguration.keyboard,
@@ -1996,7 +1988,7 @@
 
             mDrawableCache.onConfigurationChange(configChanges);
             mColorDrawableCache.onConfigurationChange(configChanges);
-            mColorStateListCache.onConfigurationChange(configChanges);
+            mComplexColorCache.onConfigurationChange(configChanges);
             mAnimatorCache.onConfigurationChange(configChanges);
             mStateListAnimatorCache.onConfigurationChange(configChanges);
 
@@ -2004,7 +1996,7 @@
         }
         synchronized (sSync) {
             if (mPluralRule != null) {
-                mPluralRule = PluralRules.forLocale(mResolvedLocale);
+                mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().getPrimary());
             }
         }
     }
@@ -2351,16 +2343,17 @@
      * tools.
      */
     public final void flushLayoutCache() {
-        synchronized (mCachedXmlBlockIds) {
-            // First see if this block is in our cache.
-            final int num = mCachedXmlBlockIds.length;
-            for (int i=0; i<num; i++) {
-                mCachedXmlBlockIds[i] = -0;
-                XmlBlock oldBlock = mCachedXmlBlocks[i];
+        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();
                 }
-                mCachedXmlBlocks[i] = null;
+                cachedXmlBlockFiles[i] = null;
+                cachedXmlBlocks[i] = null;
             }
         }
     }
@@ -2437,6 +2430,12 @@
 
     @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
@@ -2463,16 +2462,17 @@
             }
 
             // First, check whether we have a cached version of this drawable
-            // that was inflated against the specified theme.
-            if (!mPreloading) {
+            // 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. These may contain unresolved theme
-            // attributes.
+            // Next, check preloaded drawables. Preloaded drawables may contain
+            // unresolved theme attributes.
             final ConstantState cs;
             if (isColorDrawable) {
                 cs = sPreloadedColorDrawables.get(key);
@@ -2500,8 +2500,9 @@
             }
 
             // If we were able to obtain a drawable, store it in the appropriate
-            // cache: preload, not themed, null theme, or theme-specific.
-            if (dr != null) {
+            // 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);
             }
@@ -2613,6 +2614,82 @@
         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 {
@@ -2626,63 +2703,57 @@
 
         final long key = (((long) value.assetCookie) << 32) | value.data;
 
-        ColorStateList csl;
-
         // Handle inline color definitions.
         if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
                 && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
-            final android.content.res.ConstantState<ColorStateList> factory =
-                    sPreloadedColorStateLists.get(key);
-            if (factory != null) {
-                return factory.newInstance();
-            }
-
-            csl = ColorStateList.valueOf(value.data);
-
-            if (mPreloading) {
-                if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
-                        "color")) {
-                    sPreloadedColorStateLists.put(key, csl.getConstantState());
-                }
-            }
-
-            return csl;
+            return getColorStateListFromInt(value, key);
         }
 
-        final ConfigurationBoundResourceCache<ColorStateList> cache = mColorStateListCache;
-        csl = cache.getInstance(key, theme);
-        if (csl != null) {
-            return csl;
+        ComplexColor complexColor = loadComplexColorFromName(theme, value, id);
+        if (complexColor != null && complexColor instanceof ColorStateList) {
+            return (ColorStateList) complexColor;
         }
 
-        final android.content.res.ConstantState<ColorStateList> factory =
-                sPreloadedColorStateLists.get(key);
+        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) {
-            csl = factory.newInstance(this, theme);
+            return (ColorStateList) factory.newInstance();
         }
 
-        if (csl == null) {
-            csl = loadColorStateListForCookie(value, id, theme);
-        }
+        csl = ColorStateList.valueOf(value.data);
 
-        if (csl != null) {
-            if (mPreloading) {
-                if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
-                        "color")) {
-                    sPreloadedColorStateLists.put(key, csl.getConstantState());
-                }
-            } else {
-                cache.put(key, theme, csl.getConstantState());
+        if (mPreloading) {
+            if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
+                    "color")) {
+                sPreloadedComplexColors.put(key, csl.getConstantState());
             }
         }
 
         return csl;
     }
 
-    private ColorStateList loadColorStateListForCookie(TypedValue value, int id, Theme theme) {
+    /**
+     * 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 color state list: type=0x" + value.type);
+                    "Can't convert to ComplexColor: type=0x" + value.type);
         }
 
         final String file = value.string.toString();
@@ -2692,29 +2763,45 @@
             if ((id >>> 24) == 0x1) {
                 final String name = getResourceName(id);
                 if (name != null) {
-                    Log.d(TAG, "Loading framework color state list #" + Integer.toHexString(id)
+                    Log.d(TAG, "Loading framework ComplexColor #" + Integer.toHexString(id)
                             + ": " + name + " at " + file);
                 }
             }
         }
 
         if (DEBUG_LOAD) {
-            Log.v(TAG, "Loading color state list for cookie " + value.assetCookie + ": " + file);
+            Log.v(TAG, "Loading ComplexColor for cookie " + value.assetCookie + ": " + file);
         }
 
-        final ColorStateList csl;
+        ComplexColor complexColor = null;
 
         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
         if (file.endsWith(".xml")) {
             try {
-                final XmlResourceParser rp = loadXmlResourceParser(
-                        file, id, value.assetCookie, "colorstatelist");
-                csl = ColorStateList.createFromXml(this, rp, theme);
-                rp.close();
+                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 color state list resource ID #0x"
+                        "File " + file + " from ComplexColor resource ID #0x"
                                 + Integer.toHexString(id));
                 rnf.initCause(e);
                 throw rnf;
@@ -2727,10 +2814,19 @@
         }
         Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
 
-        return csl;
+        return complexColor;
     }
 
-    /*package*/ XmlResourceParser loadXmlResourceParser(int id, String type)
+    /**
+     * Loads an XML parser for the specified file.
+     *
+     * @param id the resource identifier 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(@AnyRes int id, @NonNull String type)
             throws NotFoundException {
         final TypedValue value = obtainTempTypedValue(id);
         try {
@@ -2744,53 +2840,58 @@
             releaseTempTypedValue(value);
         }
     }
-    
-    /*package*/ XmlResourceParser loadXmlResourceParser(String file, int id,
-            int assetCookie, String type) throws NotFoundException {
+
+    /**
+     * 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 {
-                // These may be compiled...
-                synchronized (mCachedXmlBlockIds) {
+                final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
+                final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
+                synchronized (cachedXmlBlockFiles) {
                     // First see if this block is in our cache.
-                    final int num = mCachedXmlBlockIds.length;
-                    for (int i=0; i<num; i++) {
-                        if (mCachedXmlBlockIds[i] == id) {
-                            //System.out.println("**** REUSING XML BLOCK!  id="
-                            //                   + id + ", index=" + i);
-                            return mCachedXmlBlocks[i].newParser();
+                    final int num = cachedXmlBlockFiles.length;
+                    for (int i = 0; i < num; i++) {
+                        if (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.
-                    XmlBlock block = mAssets.openXmlBlockAsset(
-                            assetCookie, file);
+                    final XmlBlock block = mAssets.openXmlBlockAsset(assetCookie, file);
                     if (block != null) {
-                        int pos = mLastCachedXmlBlockIndex+1;
-                        if (pos >= num) pos = 0;
+                        final int pos = (mLastCachedXmlBlockIndex + 1) % num;
                         mLastCachedXmlBlockIndex = pos;
-                        XmlBlock oldBlock = mCachedXmlBlocks[pos];
+                        final XmlBlock oldBlock = cachedXmlBlocks[pos];
                         if (oldBlock != null) {
                             oldBlock.close();
                         }
-                        mCachedXmlBlockIds[pos] = id;
-                        mCachedXmlBlocks[pos] = block;
-                        //System.out.println("**** CACHING NEW XML BLOCK!  id="
-                        //                   + id + ", index=" + pos);
+                        cachedXmlBlockFiles[pos] = file;
+                        cachedXmlBlocks[pos] = block;
                         return block.newParser();
                     }
                 }
             } catch (Exception e) {
-                NotFoundException rnf = new NotFoundException(
-                        "File " + file + " from xml type " + type + " resource ID #0x"
-                        + Integer.toHexString(id));
+                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"
+        throw new NotFoundException("File " + file + " from xml type " + type + " resource ID #0x"
                 + Integer.toHexString(id));
     }
 
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index cc65e1e..6067577 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -454,6 +454,39 @@
     }
 
     /**
+     * Retrieve the ComplexColor for the attribute at <var>index</var>.
+     * The value may be either a {@link android.content.res.ColorStateList} which can wrap a simple
+     * color value or a {@link android.content.res.GradientColor}
+     * <p>
+     * This method will return {@code null} if the attribute is not defined or
+     * is not an integer color, color state list or GradientColor.
+     *
+     * @param index Index of attribute to retrieve.
+     *
+     * @return ComplexColor for the attribute, or {@code null} if not defined.
+     * @throws RuntimeException if the attribute if the TypedArray has already
+     *         been recycled.
+     * @throws UnsupportedOperationException if the attribute is defined but is
+     *         not an integer color, color state list or GradientColor.
+     */
+    @Nullable
+    public ComplexColor getComplexColor(@StyleableRes int index) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
+        final TypedValue value = mValue;
+        if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
+            if (value.type == TypedValue.TYPE_ATTRIBUTE) {
+                throw new UnsupportedOperationException(
+                        "Failed to resolve attribute at index " + index + ": " + value);
+            }
+            return mResources.loadComplexColor(value, value.resourceId, mTheme);
+        }
+        return null;
+    }
+
+    /**
      * 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}
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 433d5d1c..50e7356 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -16,6 +16,8 @@
 
 package android.database.sqlite;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.database.DatabaseErrorHandler;
@@ -1683,6 +1685,21 @@
     }
 
     /**
+     * Verifies that a SQL SELECT statement is valid by compiling it.
+     * If the SQL statement is not valid, this method will throw a {@link SQLiteException}.
+     *
+     * @param sql SQL to be validated
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
+     * If the operation is canceled, then {@link OperationCanceledException} will be thrown
+     * when the query is executed.
+     * @throws SQLiteException if {@code sql} is invalid
+     */
+    public void validateSql(@NonNull String sql, @Nullable CancellationSignal cancellationSignal) {
+        getThreadSession().prepare(sql,
+                getThreadDefaultConnectionFlags(/* readOnly =*/ true), cancellationSignal, null);
+    }
+
+    /**
      * Returns true if the database is opened as read only.
      *
      * @return True if database is opened as read only.
diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
index 91884ab..56cba79 100644
--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
+++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
@@ -386,8 +386,7 @@
             // in both the wrapped and original forms.
             String sqlForValidation = buildQuery(projectionIn, "(" + selection + ")", groupBy,
                     having, sortOrder, limit);
-            validateQuerySql(db, sqlForValidation,
-                    cancellationSignal); // will throw if query is invalid
+            db.validateSql(sqlForValidation, cancellationSignal); // will throw if query is invalid
         }
 
         String sql = buildQuery(
@@ -404,16 +403,6 @@
     }
 
     /**
-     * Verifies that a SQL SELECT statement is valid by compiling it.
-     * If the SQL statement is not valid, this method will throw a {@link SQLiteException}.
-     */
-    private void validateQuerySql(SQLiteDatabase db, String sql,
-            CancellationSignal cancellationSignal) {
-        db.getThreadSession().prepare(sql,
-                db.getThreadDefaultConnectionFlags(true /*readOnly*/), cancellationSignal, null);
-    }
-
-    /**
      * Construct a SELECT statement suitable for use in a group of
      * SELECT statements that will be joined through UNION operators
      * in buildUnionQuery.
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index e875864..841e5b0 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -17,8 +17,10 @@
 
 package android.hardware;
 
-import android.os.Build;
 import android.annotation.SystemApi;
+import android.os.Build;
+
+import java.util.UUID;
 
 /**
  * Class representing a sensor. Use {@link SensorManager#getSensorList} to get
@@ -534,8 +536,120 @@
     public static final String STRING_TYPE_WRIST_TILT_GESTURE = "android.sensor.wrist_tilt_gesture";
 
     /**
+     * The current orientation of the device.
+     * <p>
+     * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
+     *
+     * @hide Expected to be used internally for auto-rotate and speaker rotation.
+     *
+     */
+    public static final int TYPE_DEVICE_ORIENTATION = 27;
+
+    /**
+     * A constant string describing a device orientation sensor type.
+     *
+     * @hide
+     * @see #TYPE_DEVICE_ORIENTATION
+     */
+    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
+     * translation from an arbitrary reference point.
+     *
+     * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
+     *
+     * Can use camera, depth sensor etc to compute output value.
+     *
+     * This is expected to be a high power sensor and expected only to be
+     * used when the screen is on.
+     *
+     * Expected to be more accurate than the rotation vector alone.
+     *
+     */
+    public static final int TYPE_POSE_6DOF = 28;
+
+    /**
+     * A constant string describing a pose sensor with 6 degrees of freedom.
+     *
+     * @see #TYPE_POSE_6DOF
+     */
+    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.
+     *
+     */
+    public static final int TYPE_STATIONARY_DETECT = 29;
+
+    /**
+     * A constant string describing a stationary detection sensor.
+     *
+     * @see #TYPE_STATIONARY_DETECT
+     */
+    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.
+     *
+     */
+    public static final int TYPE_MOTION_DETECT = 30;
+
+    /**
+     * A constant string describing a motion detection sensor.
+     *
+     * @see #TYPE_MOTION_DETECT
+     */
+    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.
+     *
+     */
+    public static final int TYPE_HEART_BEAT = 31;
+
+    /**
+     * A constant string describing a heart beat sensor.
+     *
+     * @see #TYPE_HEART_BEAT
+     */
+
+    public static final String STRING_TYPE_HEART_BEAT = "android.sensor.heart_beat";
+    /**
+     * A constant describing a dynamic sensor meta event sensor.
+     *
+     * A sensor event of this type is received when a dynamic sensor is added to or removed from
+     * the system. This sensor type should always use special trigger report mode ({@code
+     * SensorManager.REPORTING_MODE_SPECIAL_TRIGGER}).
+     *
+     * @hide This sensor is expected to be used only by system services.
+     */
+    @SystemApi
+    public static final int TYPE_DYNAMIC_SENSOR_META = 32;
+
+    /**
+     * A constant string describing a dynamic sensor meta event sensor.
+     *
+     * @see #TYPE_DYNAMIC_SENSOR_META
+     *
+     * @hide This sensor is expected to only be used by the system service
+     */
+    @SystemApi
+    public static final String STRING_TYPE_DYNAMIC_SENSOR_META =
+            "android.sensor.dynamic_sensor_meta";
+
+    /**
      * A constant describing all sensor types.
      */
+
     public static final int TYPE_ALL = -1;
 
     // If this flag is set, the sensor defined as a wake up sensor. This field and REPORTING_MODE_*
@@ -618,6 +732,12 @@
             1, // SENSOR_TYPE_GLANCE_GESTURE
             1, // SENSOR_TYPE_PICK_UP_GESTURE
             1, // SENSOR_TYPE_WRIST_TILT_GESTURE
+            1, // SENSOR_TYPE_DEVICE_ORIENTATION
+            16,// SENSOR_TYPE_POSE_6DOF
+            1, // SENSOR_TYPE_STATIONARY_DETECT
+            1, // SENSOR_TYPE_MOTION_DETECT
+            1, // SENSOR_TYPE_HEART_BEAT
+            2, // SENSOR_TYPE_DYNAMIC_SENSOR_META
     };
 
     /**
@@ -643,12 +763,10 @@
         }
         int offset = sensor.mType;
         if (offset >= sSensorReportingModes.length) {
-            // we don't know about this sensor, so this is probably a
-            // vendor-defined sensor, in that case, we don't know how many value
-            // it has
-            // so we return the maximum and assume the app will know.
-            // FIXME: sensor HAL should advertise how much data is returned per
-            // sensor
+            // we don't know about this sensor, so this is probably a vendor-defined sensor, in that
+            // case, we don't know how many value it has so we return the maximum and assume the app
+            // will know.
+            // FIXME: sensor HAL should advertise how much data is returned per sensor
             return 16;
         }
         return sSensorReportingModes[offset];
@@ -672,6 +790,7 @@
     private String  mRequiredPermission;
     private int     mMaxDelay;
     private int     mFlags;
+    private UUID    mUuid;
 
     Sensor() {
     }
@@ -760,6 +879,13 @@
     }
 
     /**
+     * @return The type of this sensor as a string.
+     */
+    public UUID getUuid() {
+        return mUuid;
+    }
+
+    /**
      * @hide
      * @return The permission required to access this sensor. If empty, no permission is required.
      */
@@ -939,6 +1065,12 @@
             case TYPE_TEMPERATURE:
                 mStringType = STRING_TYPE_TEMPERATURE;
                 return true;
+            case TYPE_DEVICE_ORIENTATION:
+                mStringType = STRING_TYPE_DEVICE_ORIENTATION;
+                return true;
+            case TYPE_DYNAMIC_SENSOR_META:
+                mStringType = STRING_TYPE_DYNAMIC_SENSOR_META;
+                return true;
             default:
                 return false;
         }
diff --git a/core/java/android/hardware/SensorAdditionalInfo.java b/core/java/android/hardware/SensorAdditionalInfo.java
new file mode 100644
index 0000000..8e5b8a3
--- /dev/null
+++ b/core/java/android/hardware/SensorAdditionalInfo.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This class represents a {@link android.hardware.Sensor Sensor} additional information frame,
+ * which is reported through listener callback {@link
+ * android.hardware.SensorEventCallback#onSensorAdditionalInfo onSensorAdditionalInfo}.
+ *
+ * @see SensorManager
+ * @see SensorEventListener3
+ * @see Sensor
+ *
+ */
+
+public class SensorAdditionalInfo {
+
+    /**
+     * The sensor that generated this event. See
+     * {@link android.hardware.SensorManager SensorManager} for details.
+     */
+    public final Sensor sensor;
+
+    /**
+     * Type of this additional info frame.
+     */
+    public final int type;
+
+    /**
+     * Sequence number of frame for a certain type.
+     */
+    public final int serial;
+
+    /**
+     * Additional info payload data represented in float values. Depending on the type of
+     * information, this may be null.
+     */
+    public final float[] floatValues;
+
+    /**
+     * Additional info payload data represented in int values. Depending on the type of information,
+     * this may be null.
+     */
+    public final int[] intValues;
+
+    /**
+     * Typical values of additional infomation type. The set of values is subject to extension in
+     * newer versions and vendors have the freedom of define their own custom values.
+     *
+     * @hide
+     */
+    @IntDef({TYPE_FRAME_BEGIN, TYPE_FRAME_END, TYPE_UNTRACKED_DELAY, TYPE_INTERNAL_TEMPERATURE,
+             TYPE_VEC3_CALIBRATION, TYPE_SENSOR_PLACEMENT, TYPE_SAMPLING})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AdditionalInfoType {}
+
+    /**
+     * Mark the beginning of a set of additional info frames.
+     */
+    public static final int TYPE_FRAME_BEGIN = 0;
+
+    /**
+     * Mark the end of a set of additional info frames.
+     */
+    public static final int TYPE_FRAME_END = 1;
+
+    /**
+     * Untracked delay. Delays that are introduced by data processing, such as filtering, which is
+     * not taken into account by sensor timestamps.
+     *
+     * Payload:
+     *     floatValues[0]: delay estimation in seconds
+     *     floatValues[1]: delay estimation standard deviation
+     */
+    public static final int TYPE_UNTRACKED_DELAY = 0x10000;
+
+    /**
+     * Internal temperature. Sensor hardware device internal temperature.
+     *
+     * Payload:
+     *     floatValues[0]: internal temperature in Celsius.
+     */
+    public static final int TYPE_INTERNAL_TEMPERATURE = 0x10001;
+
+    /**
+     * Vector calibration parameter. Calibration applied to a sensor with 3 elements vector output,
+     * such as accelerometer, gyro, etc.
+     *
+     * Payload:
+     *     floatValues[0..11]: First 3 rows of a homogenous matrix in row major order that captures
+     *     any linear transformation, including rotation, scaling, shear, shift.
+     */
+    public static final int TYPE_VEC3_CALIBRATION = 0x10002;
+
+    /**
+     * Sensor placement. Describes location and installation angle of the sensor device.
+     *
+     * Payload:
+     *     floatValues[0..11]: First 3 rows of homogeneous matrix in row major order that describes
+     *     the location and orientation of the sensor. Origin of reference will be the mobile device
+     *     geometric sensor. Reference frame is defined as the same as Android sensor frame.
+     */
+    public static final int TYPE_SENSOR_PLACEMENT = 0x10003;
+
+    /**
+     * Sampling parameter. Describes the raw sample period and estimated jitter of sample time in
+     * terms of standard deviation.
+     *
+     * Payload:
+     *     floatValues[0]: raw sample period in seconds.
+     *     floatValues[1]: standard deviation of sampling period.
+     */
+    public static final int TYPE_SAMPLING = 0x10004;
+
+    SensorAdditionalInfo(
+            Sensor aSensor, int aType, int aSerial, int [] aIntValues, float [] aFloatValues) {
+        sensor = aSensor;
+        type = aType;
+        serial = aSerial;
+        intValues = aIntValues;
+        floatValues = aFloatValues;
+    }
+}
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 906c2a19..35c96f7 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -396,7 +396,7 @@
      * dv = 216.7 *
      * (rh / 100.0 * 6.112 * Math.exp(17.62 * t / (243.12 + t)) / (273.15 + t));
      * </pre>
-     * 
+     *
      * <h4>{@link android.hardware.Sensor#TYPE_AMBIENT_TEMPERATURE Sensor.TYPE_AMBIENT_TEMPERATURE}:
      * </h4>
      *
@@ -483,6 +483,101 @@
      * on it. In earlier versions, this used to be always 3 which has changed now. </p>
      *
      * @see GeomagneticField
+     *
+     * <h4> {@link android.hardware.Sensor#TYPE_DEVICE_ORIENTATION
+     * Sensor.TYPE_DEVICE_ORIENTATION}:</h4>
+     * The current device orientation will be available in values[0]. The only
+     * available values are:
+     * <ul>
+     * <li> 0: device is in default orientation (Y axis is vertical and points up)
+     * <li> 1: device is rotated 90 degrees counter-clockwise from default
+     *         orientation (X axis is vertical and points up)
+     * <li> 2: device is rotated 180 degrees from default orientation (Y axis is
+     *         vertical and points down)
+     * <li> 3: device is rotated 90 degrees clockwise from default orientation (X axis
+     *         is vertical and points down)
+     * </ul>
+     *
+     *   <h4>{@link android.hardware.Sensor#TYPE_POSE_6DOF
+     * Sensor.TYPE_POSE_6DOF}:</h4>
+     *
+     * A TYPE_POSE_6DOF event consists of a rotation expressed as a quaternion and a translation
+     * expressed in SI units. The event also contains a delta rotation and translation that show
+     * how the device?s pose has changed since the previous sequence numbered pose.
+     * The event uses the cannonical Android Sensor axes.
+     *
+     *
+     * <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[4]: Translation along x 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>
+     * <li> values[8]:  Delta quaternion rotation y*sin(&#952/2) </li>
+     * <li> values[9]:  Delta quaternion rotation z*sin(&#952/2) </li>
+     * <li> values[10]: Delta quaternion rotation cos(&#952/2) </li>
+     *
+     * <li> values[11]: Delta translation along x axis. </li>
+     * <li> values[12]: Delta translation along y axis. </li>
+     * <li> values[13]: Delta translation along z axis. </li>
+     *
+     * <li> values[14]: Sequence number </li>
+     *
+     * </ul>
+     *
+     *   <h4>{@link android.hardware.Sensor#TYPE_STATIONARY_DETECT
+     * Sensor.TYPE_STATIONARY_DETECT}:</h4>
+     *
+     * A TYPE_STATIONARY_DETECT event is produced if the device has been
+     * stationary for at least 5 seconds with a maximal latency of 5
+     * additional seconds. ie: it may take up anywhere from 5 to 10 seconds
+     * afte the device has been at rest to trigger this event.
+     *
+     * The only allowed value is 1.0.
+     *
+     * <ul>
+     *  <li> values[0]: 1.0 </li>
+     * </ul>
+     *
+     *   <h4>{@link android.hardware.Sensor#TYPE_MOTION_DETECT
+     * Sensor.TYPE_MOTION_DETECT}:</h4>
+     *
+     * A TYPE_MOTION_DETECT event is produced if the device has been in
+     * motion  for at least 5 seconds with a maximal latency of 5
+     * additional seconds. ie: it may take up anywhere from 5 to 10 seconds
+     * afte the device has been at rest to trigger this event.
+     *
+     * The only allowed value is 1.0.
+     *
+     * <ul>
+     *  <li> values[0]: 1.0 </li>
+     * </ul>
+     *
+     *   <h4>{@link android.hardware.Sensor#TYPE_HEART_BEAT
+     * Sensor.TYPE_HEART_BEAT}:</h4>
+     *
+     * A sensor of this type returns an event everytime a hear beat peak is
+     * detected.
+     *
+     * Peak here ideally corresponds to the positive peak in the QRS complex of
+     * an ECG signal.
+     *
+     * <ul>
+     *  <li> values[0]: confidence</li>
+     * </ul>
+     *
+     * <p>
+     * A confidence value of 0.0 indicates complete uncertainty - that a peak
+     * is as likely to be at the indicated timestamp as anywhere else.
+     * A confidence value of 1.0 indicates complete certainly - that a peak is
+     * completely unlikely to be anywhere else on the QRS complex.
+     * </p>
      */
     public final float[] values;
 
diff --git a/core/java/android/hardware/SensorEventCallback.java b/core/java/android/hardware/SensorEventCallback.java
new file mode 100644
index 0000000..bac212a
--- /dev/null
+++ b/core/java/android/hardware/SensorEventCallback.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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;
+
+/**
+ * Used for receiving sensor additional information frames.
+ */
+public abstract class SensorEventCallback implements SensorEventListener2 {
+
+    /**
+     * Called when sensor values have changed.
+     *
+     * @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent)
+     */
+    @Override
+    public void onSensorChanged(SensorEvent event) {}
+
+    /**
+     * Called when the accuracy of the registered sensor has changed.
+     *
+     * @see android.hardware.SensorEventListener#onAccuracyChanged(Sensor, int)
+     */
+    @Override
+    public void onAccuracyChanged(Sensor sensor, int accuracy) {}
+
+    /**
+     * Called after flush() is completed.
+     *
+     * @see android.hardware.SensorEventListener2#onFlushCompleted(Sensor)
+     */
+    @Override
+    public void onFlushCompleted(Sensor sensor) {}
+
+    /**
+     * Called when a sensor additional information frame is available.
+     *
+     * @param info A {@link android.hardware.SensorAdditionalInfo SensorAdditionalInfo} frame
+     * reported from sensor hardware.
+     */
+    public void onSensorAdditionalInfo(SensorAdditionalInfo info) {}
+}
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 5d405f9..f0b17c30 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -377,6 +377,12 @@
     protected abstract List<Sensor> getFullSensorList();
 
     /**
+     * Gets the full list of dynamic sensors that are available.
+     * @hide
+     */
+    protected abstract List<Sensor> getFullDynamicSensorList();
+
+    /**
      * @return available sensors.
      * @deprecated This method is deprecated, use
      *             {@link SensorManager#getSensorList(int)} instead
@@ -430,6 +436,38 @@
     }
 
     /**
+     * Use this method to get a list of available dynamic sensors of a certain type.
+     * Make multiple calls to get sensors of different types or use
+     * {@link android.hardware.Sensor#TYPE_ALL Sensor.TYPE_ALL} to get all dynamic sensors.
+     *
+     * <p class="note">
+     * NOTE: Both wake-up and non wake-up sensors matching the given type are
+     * returned. Check {@link Sensor#isWakeUpSensor()} to know the wake-up properties
+     * of the returned {@link Sensor}.
+     * </p>
+     *
+     * @param type of sensors requested
+     *
+     * @return a list of dynamic sensors matching the requested type.
+     *
+     * @see Sensor
+     */
+    public List<Sensor> getDynamicSensorList(int type) {
+        // cache the returned lists the first time
+        final List<Sensor> fullList = getFullDynamicSensorList();
+        if (type == Sensor.TYPE_ALL) {
+            return Collections.unmodifiableList(fullList);
+        } else {
+            List<Sensor> list = new ArrayList();
+            for (Sensor i : fullList) {
+                if (i.getType() == type)
+                    list.add(i);
+            }
+            return Collections.unmodifiableList(list);
+        }
+    }
+
+    /**
      * Use this method to get the default sensor for a given type. Note that the
      * returned sensor could be a composite sensor, and its data could be
      * averaged or filtered. If you need to access the raw sensors use
@@ -841,6 +879,86 @@
     /** @hide */
     protected abstract boolean flushImpl(SensorEventListener listener);
 
+
+    /**
+     * Used for receiving notifications from the SensorManager when dynamic sensors are connected or
+     * disconnected.
+     */
+    public static abstract class DynamicSensorConnectionCallback {
+        /**
+         * Called when there is a dynamic sensor being connected to the system.
+         *
+         * @param sensor the newly connected sensor. See {@link android.hardware.Sensor Sensor}.
+         */
+        public void onDynamicSensorConnected(Sensor sensor) {}
+
+        /**
+         * Called when there is a dynamic sensor being disconnected from the system.
+         *
+         * @param sensor the disconnected sensor. See {@link android.hardware.Sensor Sensor}.
+         */
+        public void onDynamicSensorDisconnected(Sensor sensor) {}
+    }
+
+
+    /**
+     * Add a {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
+     * DynamicSensorConnectionCallback} 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.
+     * @see #addDynamicSensorCallback(DynamicSensorConnectionCallback, Handler)
+     *
+     * @throws IllegalArgumentException when callback is null.
+     */
+    public void registerDynamicSensorCallback(DynamicSensorConnectionCallback callback) {
+        registerDynamicSensorCallback(callback, null);
+    }
+
+    /**
+     * Add a {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
+     * DynamicSensorConnectionCallback} 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.
+     * @param handler The {@link android.os.Handler Handler} the {@link
+     *        android.hardware.SensorManager.DynamicSensorConnectionCallback
+     *        sensor connection events} will be delivered to.
+     *
+     * @throws IllegalArgumentException when callback is null.
+     */
+    public void registerDynamicSensorCallback(
+            DynamicSensorConnectionCallback callback, Handler handler) {
+        registerDynamicSensorCallbackImpl(callback, handler);
+    }
+
+    /**
+     * Remove a {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
+     * DynamicSensorConnectionCallback} to stop sending dynamic sensor connection events to that
+     * callback.
+     *
+     * @param callback An object that implements the
+     *        {@link android.hardware.SensorManager.DynamicSensorConnectionCallback
+     *        DynamicSensorConnectionCallback}
+     *        interface for receiving callbacks.
+     */
+    public void unregisterDynamicSensorCallback(DynamicSensorConnectionCallback callback) {
+        unregisterDynamicSensorCallbackImpl(callback);
+    }
+
+    /** @hide */
+    protected abstract void registerDynamicSensorCallbackImpl(
+            DynamicSensorConnectionCallback callback, Handler handler);
+
+    /** @hide */
+    protected abstract void unregisterDynamicSensorCallbackImpl(
+            DynamicSensorConnectionCallback callback);
+
     /**
      * <p>
      * Computes the inclination matrix <b>I</b> as well as the rotation matrix
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 2fe8fb6..c4afbfb 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -17,7 +17,10 @@
 package android.hardware;
 
 import android.Manifest;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.os.Handler;
 import android.os.Looper;
@@ -32,6 +35,7 @@
 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
@@ -40,10 +44,14 @@
  * @hide
  */
 public class SystemSensorManager extends SensorManager {
+    //TODO: disable extra logging before release
+    private static boolean DEBUG_DYNAMIC_SENSOR = true;
+
     private static native void nativeClassInit();
     private static native long nativeCreate(String opPackageName);
     private static native boolean nativeGetSensorAtIndex(long nativeInstance,
             Sensor sensor, int index);
+    private static native void nativeGetDynamicSensors(long nativeInstance, List<Sensor> list);
     private static native boolean nativeIsDataInjectionEnabled(long nativeInstance);
 
     private static boolean sSensorModuleInitialized = false;
@@ -52,7 +60,10 @@
     private final Object mLock = new Object();
 
     private final ArrayList<Sensor> mFullSensorsList = new ArrayList<>();
-    private final SparseArray<Sensor> mHandleToSensor = new SparseArray<>();
+    private List<Sensor> mFullDynamicSensorsList = new ArrayList<>();
+    private boolean mDynamicSensorListDirty = true;
+
+    private final HashMap<Integer, Sensor> mHandleToSensor = new HashMap<>();
 
     // Listener list
     private final HashMap<SensorEventListener, SensorEventQueue> mSensorListeners =
@@ -60,6 +71,11 @@
     private final HashMap<TriggerEventListener, TriggerEventQueue> mTriggerListeners =
             new HashMap<TriggerEventListener, TriggerEventQueue>();
 
+    // Dynamic Sensor callbacks
+    private HashMap<DynamicSensorConnectionCallback, Handler>
+            mDynamicSensorCallbacks = new HashMap<>();
+    private BroadcastReceiver mDynamicSensorBroadcastReceiver;
+
     // Looper associated with the context in which this instance was created.
     private final Looper mMainLooper;
     private final int mTargetSdkLevel;
@@ -84,7 +100,7 @@
                 Sensor sensor = new Sensor();
                 if (!nativeGetSensorAtIndex(mNativeInstance, sensor, index)) break;
                 mFullSensorsList.add(sensor);
-                mHandleToSensor.append(sensor.getHandle(), sensor);
+                mHandleToSensor.put(sensor.getHandle(), sensor);
             }
         }
     }
@@ -96,6 +112,15 @@
         return mFullSensorsList;
     }
 
+    /** @hide */
+    @Override
+    protected List<Sensor> getFullDynamicSensorList() {
+        // only set up broadcast receiver if the application tries to find dynamic sensors or
+        // explicitly register a DynamicSensorConnectionCallback
+        setupDynamicSensorBroadcastReceiver();
+        updateDynamicSensorList();
+        return mFullDynamicSensorsList;
+    }
 
     /** @hide */
     @Override
@@ -274,6 +299,187 @@
         }
     }
 
+    private void cleanupSensorConnection(Sensor sensor) {
+        mHandleToSensor.remove(sensor.getHandle());
+
+        if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
+            synchronized(mTriggerListeners) {
+                for (TriggerEventListener l: mTriggerListeners.keySet()) {
+                    if (DEBUG_DYNAMIC_SENSOR){
+                        Log.i(TAG, "removed trigger listener" + l.toString() +
+                                   " due to sensor disconnection");
+                    }
+                    cancelTriggerSensorImpl(l, sensor, true);
+                }
+            }
+        } else {
+            synchronized(mSensorListeners) {
+                for (SensorEventListener l: mSensorListeners.keySet()) {
+                    if (DEBUG_DYNAMIC_SENSOR){
+                        Log.i(TAG, "removed event listener" + l.toString() +
+                                   " due to sensor disconnection");
+                    }
+                    unregisterListenerImpl(l, sensor);
+                }
+            }
+        }
+    }
+
+    private void updateDynamicSensorList() {
+        synchronized(mFullDynamicSensorsList) {
+            if (mDynamicSensorListDirty) {
+                List<Sensor> list = new ArrayList<>();
+                nativeGetDynamicSensors(mNativeInstance, list);
+
+                final List<Sensor> updatedList = new ArrayList<>();
+                final List<Sensor> addedList = new ArrayList<>();
+                final List<Sensor> removedList = new ArrayList<>();
+
+                boolean changed = diffSortedSensorList(
+                        mFullDynamicSensorsList, list, updatedList, addedList, removedList);
+
+                if (changed) {
+                    if (DEBUG_DYNAMIC_SENSOR) {
+                        Log.i(TAG, "DYNS dynamic sensor list cached should be updated");
+                    }
+                    mFullDynamicSensorsList = updatedList;
+
+                    for (Sensor s: addedList) {
+                        mHandleToSensor.put(s.getHandle(), s);
+                    }
+
+                    Handler mainHandler = new Handler(mContext.getMainLooper());
+
+                    for (Map.Entry<DynamicSensorConnectionCallback, Handler> entry :
+                            mDynamicSensorCallbacks.entrySet()) {
+                        final DynamicSensorConnectionCallback callback = entry.getKey();
+                        Handler handler =
+                                entry.getValue() == null ? mainHandler : entry.getValue();
+
+                        handler.post(new Runnable() {
+                            @Override
+                            public void run() {
+                                for (Sensor s: addedList) {
+                                    callback.onDynamicSensorConnected(s);
+                                }
+                                for (Sensor s: removedList) {
+                                    callback.onDynamicSensorDisconnected(s);
+                                }
+                            }
+                        });
+                    }
+
+                    for (Sensor s: removedList) {
+                        cleanupSensorConnection(s);
+                    }
+                }
+
+                mDynamicSensorListDirty = false;
+            }
+        }
+    }
+
+    private void setupDynamicSensorBroadcastReceiver() {
+        if (mDynamicSensorBroadcastReceiver == null) {
+            mDynamicSensorBroadcastReceiver = new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    if (intent.getAction() == Intent.ACTION_DYNAMIC_SENSOR_CHANGED) {
+                        if (DEBUG_DYNAMIC_SENSOR) {
+                            Log.i(TAG, "DYNS received DYNAMIC_SENSOR_CHANED broadcast");
+                        }
+                        // Dynamic sensors probably changed
+                        mDynamicSensorListDirty = true;
+                        updateDynamicSensorList();
+                    }
+                }
+            };
+
+            IntentFilter filter = new IntentFilter("dynamic_sensor_change");
+            filter.addAction(Intent.ACTION_DYNAMIC_SENSOR_CHANGED);
+            mContext.registerReceiver(mDynamicSensorBroadcastReceiver, filter);
+        }
+    }
+
+    private void teardownDynamicSensorBroadcastReceiver() {
+        mDynamicSensorCallbacks.clear();
+        mContext.unregisterReceiver(mDynamicSensorBroadcastReceiver);
+        mDynamicSensorBroadcastReceiver = null;
+    }
+
+    /** @hide */
+    protected void registerDynamicSensorCallbackImpl(
+            DynamicSensorConnectionCallback callback, Handler handler) {
+        if (DEBUG_DYNAMIC_SENSOR) {
+            Log.i(TAG, "DYNS Register dynamic sensor callback");
+        }
+
+        if (callback == null) {
+            throw new IllegalArgumentException("callback cannot be null");
+        }
+        if (mDynamicSensorCallbacks.containsKey(callback)) {
+            // has been already registered, ignore
+            return;
+        }
+
+        setupDynamicSensorBroadcastReceiver();
+        mDynamicSensorCallbacks.put(callback, handler);
+    }
+
+    /** @hide */
+    protected void unregisterDynamicSensorCallbackImpl(
+            DynamicSensorConnectionCallback callback) {
+        if (DEBUG_DYNAMIC_SENSOR) {
+            Log.i(TAG, "Removing dynamic sensor listerner");
+        }
+        mDynamicSensorCallbacks.remove(callback);
+    }
+
+    /*
+     * Find the difference of two List<Sensor> assuming List are sorted by handle of sensor,
+     * assuming the input list is already sorted by handle. Inputs are ol and nl; outputs are
+     * updated, added and removed. Any of the output lists can be null in case the result is not
+     * interested.
+     */
+    private static boolean diffSortedSensorList(
+            List<Sensor> oldList, List<Sensor> newList, List<Sensor> updated,
+            List<Sensor> added, List<Sensor> removed) {
+
+        boolean changed = false;
+
+        int i = 0, j = 0;
+        while (true) {
+            if (j < oldList.size() && ( i >= newList.size() ||
+                    newList.get(i).getHandle() > oldList.get(j).getHandle()) ) {
+                changed = true;
+                if (removed != null) {
+                    removed.add(oldList.get(j));
+                }
+                ++j;
+            } else if (i < newList.size() && ( j >= oldList.size() ||
+                    newList.get(i).getHandle() < oldList.get(j).getHandle())) {
+                changed = true;
+                if (added != null) {
+                    added.add(newList.get(i));
+                }
+                if (updated != null) {
+                    updated.add(newList.get(i));
+                }
+                ++i;
+            } else if (i < newList.size() && j < oldList.size() &&
+                    newList.get(i).getHandle() == oldList.get(j).getHandle()) {
+                if (updated != null) {
+                    updated.add(oldList.get(j));
+                }
+                ++i;
+                ++j;
+            } else {
+                break;
+            }
+        }
+        return changed;
+    }
+
     /*
      * BaseEventQueue is the communication channel with the sensor service,
      * SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between
@@ -284,7 +490,7 @@
      */
     private static abstract class BaseEventQueue {
         private static native long nativeInitBaseEventQueue(long nativeManager,
-                WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ, float[] scratch,
+                WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ,
                 String packageName, int mode, String opPackageName);
         private static native int nativeEnableSensor(long eventQ, int handle, int rateUs,
                 int maxBatchReportLatencyUs);
@@ -297,9 +503,7 @@
         private long nSensorEventQueue;
         private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
         protected final SparseIntArray mSensorAccuracies = new SparseIntArray();
-        protected final SparseBooleanArray mFirstEvent = new SparseBooleanArray();
         private final CloseGuard mCloseGuard = CloseGuard.get();
-        private final float[] mScratch = new float[16];
         protected final SystemSensorManager mManager;
 
         protected static final int OPERATING_MODE_NORMAL = 0;
@@ -308,7 +512,7 @@
         BaseEventQueue(Looper looper, SystemSensorManager manager, int mode, String packageName) {
             if (packageName == null) packageName = "";
             nSensorEventQueue = nativeInitBaseEventQueue(manager.mNativeInstance,
-                    new WeakReference<>(this), looper.getQueue(), mScratch,
+                    new WeakReference<>(this), looper.getQueue(),
                     packageName, mode, manager.mContext.getOpPackageName());
             mCloseGuard.open("dispose");
             mManager = manager;
@@ -348,7 +552,7 @@
                         mActiveSensors.put(handle, false);
                         removeSensorEvent(sensor);
                     } else {
-                        // it should never happen -- just ignore.
+                        // sensor just disconnected -- just ignore.
                     }
                 }
             }
@@ -420,6 +624,11 @@
                 long timestamp);
         protected abstract void dispatchFlushCompleteEvent(int handle);
 
+        protected void dispatchAdditionalInfoEvent(
+                int handle, int type, int serial, float[] floatValues, int[] intValues) {
+            // default implementation is do nothing
+        }
+
         protected abstract void addSensorEvent(Sensor sensor);
         protected abstract void removeSensorEvent(Sensor sensor);
     }
@@ -456,6 +665,11 @@
         protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy,
                 long timestamp) {
             final Sensor sensor = mManager.mHandleToSensor.get(handle);
+            if (sensor == null) {
+                // sensor disconnected
+                return;
+            }
+
             SensorEvent t = null;
             synchronized (mSensorsEvents) {
                 t = mSensorsEvents.get(handle);
@@ -481,14 +695,37 @@
             mListener.onSensorChanged(t);
         }
 
+        // Called from native code.
         @SuppressWarnings("unused")
+        @Override
         protected void dispatchFlushCompleteEvent(int handle) {
             if (mListener instanceof SensorEventListener2) {
                 final Sensor sensor = mManager.mHandleToSensor.get(handle);
+                if (sensor == null) {
+                    // sensor disconnected
+                    return;
+                }
                 ((SensorEventListener2)mListener).onFlushCompleted(sensor);
             }
             return;
         }
+
+        // Called from native code.
+        @SuppressWarnings("unused")
+        @Override
+        protected void dispatchAdditionalInfoEvent(
+                int handle, int type, int serial, float[] floatValues, int[] intValues) {
+            if (mListener instanceof SensorEventCallback) {
+                final Sensor sensor = mManager.mHandleToSensor.get(handle);
+                if (sensor == null) {
+                    // sensor disconnected
+                    return;
+                }
+                SensorAdditionalInfo info =
+                        new SensorAdditionalInfo(sensor, type, serial, intValues, floatValues);
+                ((SensorEventCallback)mListener).onSensorAdditionalInfo(info);
+            }
+        }
     }
 
     static final class TriggerEventQueue extends BaseEventQueue {
@@ -523,6 +760,10 @@
         protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
                 long timestamp) {
             final Sensor sensor = mManager.mHandleToSensor.get(handle);
+            if (sensor == null) {
+                // sensor disconnected
+                return;
+            }
             TriggerEvent t = null;
             synchronized (mTriggerEvents) {
                 t = mTriggerEvents.get(handle);
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index bb0a04f..2aa6af6 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -743,6 +743,26 @@
             new Key<int[]>("android.control.availableModes", int[].class);
 
     /**
+     * <p>Range of boosts for {@link CaptureRequest#CONTROL_POST_RAW_SENSITIVITY_BOOST android.control.postRawSensitivityBoost} supported
+     * by this camera device.</p>
+     * <p>Devices support post RAW sensitivity boost  will advertise
+     * {@link CaptureRequest#CONTROL_POST_RAW_SENSITIVITY_BOOST android.control.postRawSensitivityBoost} key for controling
+     * post RAW sensitivity boost.</p>
+     * <p>This key will be <code>null</code> for devices that do not support any RAW format
+     * outputs. For devices that do support RAW format outputs, this key will always
+     * present, and if a device does not support post RAW sensitivity boost, it will
+     * list <code>(100, 100)</code> in this key.</p>
+     * <p><b>Units</b>: ISO arithmetic units, the same as {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#CONTROL_POST_RAW_SENSITIVITY_BOOST
+     * @see CaptureRequest#SENSOR_SENSITIVITY
+     */
+    @PublicKey
+    public static final Key<android.util.Range<Integer>> CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE =
+            new Key<android.util.Range<Integer>>("android.control.postRawSensitivityBoostRange", new TypeReference<android.util.Range<Integer>>() {{ }});
+
+    /**
      * <p>List of edge enhancement modes for {@link CaptureRequest#EDGE_MODE android.edge.mode} that are supported by this camera
      * device.</p>
      * <p>Full-capability camera devices must always support OFF; camera devices that support
@@ -2767,22 +2787,39 @@
 
     /**
      * <p>Generally classifies the overall set of the camera device functionality.</p>
-     * <p>Camera devices will come in three flavors: LEGACY, LIMITED and FULL.</p>
-     * <p>A FULL device will support below capabilities:</p>
+     * <p>The supported hardware level is a high-level description of the camera device's
+     * capabilities, summarizing several capabilities into one field.  Each level adds additional
+     * features to the previous one, and is always a strict superset of the previous level.
+     * The ordering is <code>LEGACY &lt; LIMITED &lt; FULL &lt; LEVEL_3</code>.</p>
+     * <p>Starting from <code>LEVEL_3</code>, the level enumerations are guaranteed to be in increasing
+     * numerical value as well. To check if a given device is at least at a given hardware level,
+     * the following code snippet can be used:</p>
+     * <pre><code>// Returns true if the device supports the required hardware level, or better.
+     * boolean isHardwareLevelSupported(CameraCharacteristics c, int requiredLevel) {
+     *     int deviceLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
+     *     if (deviceLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
+     *         return requiredLevel == deviceLevel;
+     *     }
+     *     // deviceLevel is not LEGACY, can use numerical sort
+     *     return requiredLevel &lt;= deviceLevel;
+     * }
+     * </code></pre>
+     * <p>At a high level, the levels are:</p>
      * <ul>
-     * <li>BURST_CAPTURE capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains BURST_CAPTURE)</li>
-     * <li>Per frame control ({@link CameraCharacteristics#SYNC_MAX_LATENCY android.sync.maxLatency} <code>==</code> PER_FRAME_CONTROL)</li>
-     * <li>Manual sensor control ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains MANUAL_SENSOR)</li>
-     * <li>Manual post-processing control ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
-     *   MANUAL_POST_PROCESSING)</li>
-     * <li>At least 3 processed (but not stalling) format output streams
-     *   ({@link CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_PROC android.request.maxNumOutputProc} <code>&gt;=</code> 3)</li>
-     * <li>The required stream configurations defined in android.scaler.availableStreamConfigurations</li>
-     * <li>The required exposure time range defined in {@link CameraCharacteristics#SENSOR_INFO_EXPOSURE_TIME_RANGE android.sensor.info.exposureTimeRange}</li>
-     * <li>The required maxFrameDuration defined in {@link CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION android.sensor.info.maxFrameDuration}</li>
+     * <li><code>LEGACY</code> devices operate in a backwards-compatibility mode for older
+     *   Android devices, and have very limited capabilities.</li>
+     * <li><code>LIMITED</code> devices represent the
+     *   baseline feature set, and may also include additional capabilities that are
+     *   subsets of <code>FULL</code>.</li>
+     * <li><code>FULL</code> devices additionally support per-frame manual control of sensor, flash, lens and
+     *   post-processing settings, and image capture at a high rate.</li>
+     * <li><code>LEVEL_3</code> devices additionally support YUV reprocessing and RAW image capture, along
+     *   with additional output stream configurations.</li>
      * </ul>
-     * <p>A LIMITED device may have some or none of the above characteristics.
-     * To find out more refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}.</p>
+     * <p>See the individual level enums for full descriptions of the supported capabilities.  The
+     * {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} entry describes the device's capabilities at a
+     * finer-grain level, if needed. In addition, many controls have their available settings or
+     * ranges defined in individual {@link android.hardware.camera2.CameraCharacteristics } entries.</p>
      * <p>Some features are not part of any particular hardware level or capability and must be
      * queried separately. These include:</p>
      * <ul>
@@ -2793,19 +2830,12 @@
      *   ({@link CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION android.lens.info.availableOpticalStabilization},
      *    {@link CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES android.control.availableVideoStabilizationModes})</li>
      * </ul>
-     * <p>A LEGACY device does not support per-frame control, manual sensor control, manual
-     * post-processing, arbitrary cropping regions, and has relaxed performance constraints.</p>
-     * <p>Each higher level supports everything the lower level supports
-     * in this order: FULL <code>&gt;</code> LIMITED <code>&gt;</code> LEGACY.</p>
-     * <p>Note:
-     * Pre-API level 23, FULL devices also supported arbitrary cropping region
-     * ({@link CameraCharacteristics#SCALER_CROPPING_TYPE android.scaler.croppingType} <code>==</code> FREEFORM); this requirement was relaxed in API level 23,
-     * and FULL devices may only support CENTERED cropping.</p>
      * <p><b>Possible values:</b>
      * <ul>
      *   <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED}</li>
      *   <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}</li>
      *   <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY}</li>
+     *   <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_3 3}</li>
      * </ul></p>
      * <p>This key is available on all devices.</p>
      *
@@ -2813,16 +2843,12 @@
      * @see CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION
      * @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
-     * @see CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_PROC
-     * @see CameraCharacteristics#SCALER_CROPPING_TYPE
-     * @see CameraCharacteristics#SENSOR_INFO_EXPOSURE_TIME_RANGE
-     * @see CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION
      * @see CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE
      * @see CameraCharacteristics#STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES
-     * @see CameraCharacteristics#SYNC_MAX_LATENCY
      * @see #INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED
      * @see #INFO_SUPPORTED_HARDWARE_LEVEL_FULL
      * @see #INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY
+     * @see #INFO_SUPPORTED_HARDWARE_LEVEL_3
      */
     @PublicKey
     public static final Key<Integer> INFO_SUPPORTED_HARDWARE_LEVEL =
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 8f45f72..6aacc9c 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -168,7 +168,7 @@
      * <p>The active capture session determines the set of potential output Surfaces for
      * the camera device for each capture request. A given request may use all
      * or only some of the outputs. Once the CameraCaptureSession is created, requests can be
-     * can be submitted with {@link CameraCaptureSession#capture capture},
+     * submitted with {@link CameraCaptureSession#capture capture},
      * {@link CameraCaptureSession#captureBurst captureBurst},
      * {@link CameraCaptureSession#setRepeatingRequest setRepeatingRequest}, or
      * {@link CameraCaptureSession#setRepeatingBurst setRepeatingBurst}.</p>
@@ -314,7 +314,7 @@
      * </table><br>
      * </p>
      *
-     * <p>Limited-capability ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
+     * <p>Limited-level ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
      * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED}) devices
      * support at least the following stream combinations in addition to those for
      * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY} devices:
@@ -332,13 +332,13 @@
      * </table><br>
      * </p>
      *
-     * <p>FULL-capability ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
+     * <p>FULL-level ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
      * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}) devices
      * support at least the following stream combinations in addition to those for
      * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices:
      *
      * <table>
-     * <tr><th colspan="7">FULL-capability additional guaranteed configurations</th></tr>
+     * <tr><th colspan="7">FULL-level additional guaranteed configurations</th></tr>
      * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
      * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td colspan="2" id="rb"></td> <td>Maximum-resolution GPU processing with preview.</td> </tr>
@@ -389,6 +389,22 @@
      * </table><br>
      * </p>
      *
+     * <p>LEVEL-3 ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
+     * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_3 LEVEL_3})
+     * support at least the following stream combinations in addition to the combinations for
+     * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL} and for
+     * RAW capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes
+     * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_RAW RAW}):
+     *
+     * <table>
+     * <tr><th colspan="11">LEVEL-3 additional guaranteed configurations</th></tr>
+     * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th rowspan="2">Sample use case(s)</th> </tr>
+     * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
+     * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code 640x480}</td> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td> <td>In-app viewfinder analysis with dynamic selection of output format.</td> </tr>
+     * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code 640x480}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td> <td>In-app viewfinder analysis with dynamic selection of output format.</td> </tr>
+     * </table><br>
+     * </p>
+     *
      * <p>Since the capabilities of camera devices vary greatly, a given camera device may support
      * target combinations with sizes outside of these guarantees, but this can only be tested for
      * by attempting to create a session with such targets.</p>
@@ -421,8 +437,6 @@
      *
      * @see #createCaptureSession
      * @see OutputConfiguration
-     *
-     * @hide
      */
     public abstract void createCaptureSessionByOutputConfiguration(
             List<OutputConfiguration> outputConfigurations,
@@ -503,7 +517,7 @@
      *  #rb { border-right-width: thick; }
      * </style>
      *
-     * <p>Limited-capability ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
+     * <p>LIMITED-level ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
      * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED}) devices
      * support at least the following stream combinations for creating a reprocessable capture
      * session in addition to those listed in {@link #createCaptureSession createCaptureSession} for
@@ -520,14 +534,14 @@
      * </table><br>
      * </p>
      *
-     * <p>FULL-capability ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
+     * <p>FULL-level ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
      * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}) devices
      * support at least the following stream combinations for creating a reprocessable capture
      * session in addition to those for
      * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices:
      *
      * <table>
-     * <tr><th colspan="11">FULL-capability additional guaranteed configurations for creating a reprocessable capture session<br>({@code PRIV} input is guaranteed only if PRIVATE reprocessing is supported. {@code YUV} input is guaranteed only if YUV reprocessing is supported)</th></tr>
+     * <tr><th colspan="11">FULL-level additional guaranteed configurations for creating a reprocessable capture session<br>({@code PRIV} input is guaranteed only if PRIVATE reprocessing is supported. {@code YUV} input is guaranteed only if YUV reprocessing is supported)</th></tr>
      * <tr><th colspan="2" id="rb">Input</th><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
      * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td></td><td id="rb"></td> <td></td><td id="rb"></td> <td>Maximum-resolution multi-frame image fusion in-app processing with regular preview.</td> </tr>
@@ -557,6 +571,24 @@
      * </table><br>
      * </p>
      *
+     * <p>LEVEL-3 ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
+     * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_3 LEVEL_3}) devices
+     * support at least the following stream combinations for creating a reprocessable capture
+     * session in addition to those for
+     * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL} devices. Note that while
+     * the second configuration allows for configuring {@code MAXIMUM} {@code YUV} and {@code JPEG}
+     * outputs at the same time, that configuration is not listed for regular capture sessions, and
+     * therefore simultaneous output to both targets is not allowed.
+     *
+     * <table>
+     * <tr><th colspan="13">LEVEL-3 additional guaranteed configurations for creating a reprocessable capture session<br>({@code PRIV} input is guaranteed only if PRIVATE reprocessing is supported. {@code YUV} input is always guaranteed.</th></tr>
+     * <tr><th colspan="2" id="rb">Input</th><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th colspan="2" id="rb">Target 5</th><th rowspan="2">Sample use case(s)</th> </tr>
+     * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
+     * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code 640x480}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td> <td></td><td id="rb"></td> <td>In-app viewfinder analysis with ZSL and RAW.</td> </tr>
+     * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Same as input</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code 640x480}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td><td>In-app viewfinder analysis with ZSL, RAW, and JPEG reprocessing output.</td> </tr>
+     * </table><br>
+     * </p>
+     *
      * @param inputConfig The configuration for the input {@link Surface}
      * @param outputs The new set of Surfaces that should be made available as
      *                targets for captured image data.
@@ -587,6 +619,22 @@
             throws CameraAccessException;
 
     /**
+     * Create a new reprocessable camera capture session by providing the desired reprocessing
+     * input configuration and output {@link OutputConfiguration}
+     * to the camera device.
+     *
+     * @see #createReprocessableCaptureSession
+     * @see OutputConfiguration
+     *
+     */
+    public abstract void createReprocessableCaptureSessionWithConfigurations(
+            @NonNull InputConfiguration inputConfig,
+            @NonNull List<OutputConfiguration> outputs,
+            @NonNull CameraCaptureSession.StateCallback callback,
+            @Nullable Handler handler)
+            throws CameraAccessException;
+
+    /**
      * <p>Create a new constrained high speed capture session.</p>
      *
      * <p>The application can use normal capture session (created via {@link #createCaptureSession})
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index f61892e..d58ad22 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -964,23 +964,102 @@
     //
 
     /**
-     * <p>This camera device has only limited capabilities.</p>
+     * <p>This camera device does not have enough capabilities to qualify as a <code>FULL</code> device or
+     * better.</p>
+     * <p>Only the stream configurations listed in the <code>LEGACY</code> and <code>LIMITED</code> tables in the
+     * {@link android.hardware.camera2.CameraDevice#createCaptureSession createCaptureSession} documentation are guaranteed to be supported.</p>
+     * <p>All <code>LIMITED</code> devices support the <code>BACKWARDS_COMPATIBLE</code> capability, indicating basic
+     * support for color image capture. The only exception is that the device may
+     * alternatively support only the <code>DEPTH_OUTPUT</code> capability, if it can only output depth
+     * measurements and not color images.</p>
+     * <p><code>LIMITED</code> devices and above require the use of {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}
+     * to lock exposure metering (and calculate flash power, for cameras with flash) before
+     * capturing a high-quality still image.</p>
+     * <p>A <code>LIMITED</code> device that only lists the <code>BACKWARDS_COMPATIBLE</code> capability is only
+     * required to support full-automatic operation and post-processing (<code>OFF</code> is not
+     * supported for {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode}, {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}, or
+     * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode})</p>
+     * <p>Additional capabilities may optionally be supported by a <code>LIMITED</code>-level device, and
+     * can be checked for in {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}.</p>
+     *
+     * @see CaptureRequest#CONTROL_AE_MODE
+     * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
+     * @see CaptureRequest#CONTROL_AF_MODE
+     * @see CaptureRequest#CONTROL_AWB_MODE
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      */
     public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0;
 
     /**
      * <p>This camera device is capable of supporting advanced imaging applications.</p>
+     * <p>The stream configurations listed in the <code>FULL</code>, <code>LEGACY</code> and <code>LIMITED</code> tables in the
+     * {@link android.hardware.camera2.CameraDevice#createCaptureSession createCaptureSession} documentation are guaranteed to be supported.</p>
+     * <p>A <code>FULL</code> device will support below capabilities:</p>
+     * <ul>
+     * <li><code>BURST_CAPTURE</code> capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
+     *   <code>BURST_CAPTURE</code>)</li>
+     * <li>Per frame control ({@link CameraCharacteristics#SYNC_MAX_LATENCY android.sync.maxLatency} <code>==</code> PER_FRAME_CONTROL)</li>
+     * <li>Manual sensor control ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains <code>MANUAL_SENSOR</code>)</li>
+     * <li>Manual post-processing control ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
+     *   <code>MANUAL_POST_PROCESSING</code>)</li>
+     * <li>The required exposure time range defined in {@link CameraCharacteristics#SENSOR_INFO_EXPOSURE_TIME_RANGE android.sensor.info.exposureTimeRange}</li>
+     * <li>The required maxFrameDuration defined in {@link CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION android.sensor.info.maxFrameDuration}</li>
+     * </ul>
+     * <p>Note:
+     * Pre-API level 23, FULL devices also supported arbitrary cropping region
+     * ({@link CameraCharacteristics#SCALER_CROPPING_TYPE android.scaler.croppingType} <code>== FREEFORM</code>); this requirement was relaxed in API level
+     * 23, and <code>FULL</code> devices may only support <code>CENTERED</code> cropping.</p>
+     *
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     * @see CameraCharacteristics#SCALER_CROPPING_TYPE
+     * @see CameraCharacteristics#SENSOR_INFO_EXPOSURE_TIME_RANGE
+     * @see CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION
+     * @see CameraCharacteristics#SYNC_MAX_LATENCY
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      */
     public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1;
 
     /**
      * <p>This camera device is running in backward compatibility mode.</p>
+     * <p>Only the stream configurations listed in the <code>LEGACY</code> table in the {@link android.hardware.camera2.CameraDevice#createCaptureSession createCaptureSession}
+     * documentation are supported.</p>
+     * <p>A <code>LEGACY</code> device does not support per-frame control, manual sensor control, manual
+     * post-processing, arbitrary cropping regions, and has relaxed performance constraints.
+     * No additional capabilities beyond <code>BACKWARD_COMPATIBLE</code> will ever be listed by a
+     * <code>LEGACY</code> device in {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}.</p>
+     * <p>In addition, the {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is not functional on <code>LEGACY</code>
+     * devices. Instead, every request that includes a JPEG-format output target is treated
+     * as triggering a still capture, internally executing a precapture trigger.  This may
+     * fire the flash for flash power metering during precapture, and then fire the flash
+     * for the final capture, if a flash is available on the device and the AE mode is set to
+     * enable the flash.</p>
+     *
+     * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      */
     public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY = 2;
 
+    /**
+     * <p>This camera device is capable of YUV reprocessing and RAW data capture, in addition to
+     * FULL-level capabilities.</p>
+     * <p>The stream configurations listed in the <code>LEVEL_3</code>, <code>RAW</code>, <code>FULL</code>, <code>LEGACY</code> and
+     * <code>LIMITED</code> tables in the {@link android.hardware.camera2.CameraDevice#createCaptureSession createCaptureSession}
+     * documentation are guaranteed to be supported.</p>
+     * <p>The following additional capabilities are guaranteed to be supported:</p>
+     * <ul>
+     * <li><code>YUV_REPROCESSING</code> capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
+     *   <code>YUV_REPROCESSING</code>)</li>
+     * <li><code>RAW</code> capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
+     *   <code>RAW</code>)</li>
+     * </ul>
+     *
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     */
+    public static final int INFO_SUPPORTED_HARDWARE_LEVEL_3 = 3;
+
     //
     // Enumeration values for CameraCharacteristics#SYNC_MAX_LATENCY
     //
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 67835a0..79eff4f 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1590,6 +1590,41 @@
             new Key<Integer>("android.control.videoStabilizationMode", int.class);
 
     /**
+     * <p>The amount of additional sesnsitivity boost applied to output images
+     * after RAW sensor data is captured.</p>
+     * <p>Some camera devices support additional digital sensitivity boosting in the
+     * camera processing pipeline after sensor RAW image is captured.
+     * Such a boost will be applied to YUV/JPEG format output images but will not
+     * have effect on RAW output formats like RAW_SENSOR, RAW10, RAW12 or RAW_OPAQUE.</p>
+     * <p>This key is optional. Applications can assume there is no boost applied
+     * after RAW is captured if this key is not available.
+     * When this key is available, the sensitivity boost value must be within
+     * {@link CameraCharacteristics#CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE android.control.postRawSensitivityBoostRange}.</p>
+     * <p>If the camera device cannot apply the exact boost requested, it will reduce the
+     * boost to the nearest supported value.
+     * The final boost value used will be available in the output capture result.</p>
+     * <p>For devices that support post RAW sensitivity boost, the YUV/JPEG output images
+     * of such device will have the total sensitivity of
+     * <code>{@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} * {@link CaptureRequest#CONTROL_POST_RAW_SENSITIVITY_BOOST android.control.postRawSensitivityBoost} / 100</code>
+     * The sensitivity of RAW format images will always be <code>{@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}</code></p>
+     * <p>This control is only effective if {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} or {@link CaptureRequest#CONTROL_MODE android.control.mode} is set to
+     * OFF; otherwise the auto-exposure algorithm will override this value.</p>
+     * <p><b>Units</b>: ISO arithmetic units, the same as {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}</p>
+     * <p><b>Range of valid values:</b><br>
+     * {@link CameraCharacteristics#CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE android.control.postRawSensitivityBoostRange}</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#CONTROL_AE_MODE
+     * @see CaptureRequest#CONTROL_MODE
+     * @see CaptureRequest#CONTROL_POST_RAW_SENSITIVITY_BOOST
+     * @see CameraCharacteristics#CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE
+     * @see CaptureRequest#SENSOR_SENSITIVITY
+     */
+    @PublicKey
+    public static final Key<Integer> CONTROL_POST_RAW_SENSITIVITY_BOOST =
+            new Key<Integer>("android.control.postRawSensitivityBoost", int.class);
+
+    /**
      * <p>Operation mode for edge
      * enhancement.</p>
      * <p>Edge enhancement improves sharpness and details in the captured image. OFF means
@@ -2244,6 +2279,8 @@
      * requested, it will reduce the gain to the nearest supported
      * value. The final sensitivity used will be available in the
      * output capture result.</p>
+     * <p>This control is only effective if {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} or {@link CaptureRequest#CONTROL_MODE android.control.mode} is set to
+     * OFF; otherwise the auto-exposure algorithm will override this value.</p>
      * <p><b>Units</b>: ISO arithmetic units</p>
      * <p><b>Range of valid values:</b><br>
      * {@link CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE android.sensor.info.sensitivityRange}</p>
@@ -2252,6 +2289,8 @@
      * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
      * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
      *
+     * @see CaptureRequest#CONTROL_AE_MODE
+     * @see CaptureRequest#CONTROL_MODE
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      * @see CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE
      * @see CameraCharacteristics#SENSOR_MAX_ANALOG_SENSITIVITY
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 3c2d503..5748726 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2097,6 +2097,41 @@
             new Key<Integer>("android.control.videoStabilizationMode", int.class);
 
     /**
+     * <p>The amount of additional sesnsitivity boost applied to output images
+     * after RAW sensor data is captured.</p>
+     * <p>Some camera devices support additional digital sensitivity boosting in the
+     * camera processing pipeline after sensor RAW image is captured.
+     * Such a boost will be applied to YUV/JPEG format output images but will not
+     * have effect on RAW output formats like RAW_SENSOR, RAW10, RAW12 or RAW_OPAQUE.</p>
+     * <p>This key is optional. Applications can assume there is no boost applied
+     * after RAW is captured if this key is not available.
+     * When this key is available, the sensitivity boost value must be within
+     * {@link CameraCharacteristics#CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE android.control.postRawSensitivityBoostRange}.</p>
+     * <p>If the camera device cannot apply the exact boost requested, it will reduce the
+     * boost to the nearest supported value.
+     * The final boost value used will be available in the output capture result.</p>
+     * <p>For devices that support post RAW sensitivity boost, the YUV/JPEG output images
+     * of such device will have the total sensitivity of
+     * <code>{@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} * {@link CaptureRequest#CONTROL_POST_RAW_SENSITIVITY_BOOST android.control.postRawSensitivityBoost} / 100</code>
+     * The sensitivity of RAW format images will always be <code>{@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}</code></p>
+     * <p>This control is only effective if {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} or {@link CaptureRequest#CONTROL_MODE android.control.mode} is set to
+     * OFF; otherwise the auto-exposure algorithm will override this value.</p>
+     * <p><b>Units</b>: ISO arithmetic units, the same as {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}</p>
+     * <p><b>Range of valid values:</b><br>
+     * {@link CameraCharacteristics#CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE android.control.postRawSensitivityBoostRange}</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CaptureRequest#CONTROL_AE_MODE
+     * @see CaptureRequest#CONTROL_MODE
+     * @see CaptureRequest#CONTROL_POST_RAW_SENSITIVITY_BOOST
+     * @see CameraCharacteristics#CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE
+     * @see CaptureRequest#SENSOR_SENSITIVITY
+     */
+    @PublicKey
+    public static final Key<Integer> CONTROL_POST_RAW_SENSITIVITY_BOOST =
+            new Key<Integer>("android.control.postRawSensitivityBoost", int.class);
+
+    /**
      * <p>Operation mode for edge
      * enhancement.</p>
      * <p>Edge enhancement improves sharpness and details in the captured image. OFF means
@@ -3086,6 +3121,8 @@
      * requested, it will reduce the gain to the nearest supported
      * value. The final sensitivity used will be available in the
      * output capture result.</p>
+     * <p>This control is only effective if {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} or {@link CaptureRequest#CONTROL_MODE android.control.mode} is set to
+     * OFF; otherwise the auto-exposure algorithm will override this value.</p>
      * <p><b>Units</b>: ISO arithmetic units</p>
      * <p><b>Range of valid values:</b><br>
      * {@link CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE android.sensor.info.sensitivityRange}</p>
@@ -3094,6 +3131,8 @@
      * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
      * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
      *
+     * @see CaptureRequest#CONTROL_AE_MODE
+     * @see CaptureRequest#CONTROL_MODE
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
      * @see CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE
      * @see CameraCharacteristics#SENSOR_MAX_ANALOG_SENSITIVITY
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 6e02df1..3aba0d1 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -89,7 +89,6 @@
             new SparseArray<CaptureCallbackHolder>();
 
     private int mRepeatingRequestId = REQUEST_ID_NONE;
-    private final ArrayList<Integer> mRepeatingRequestIdDeletedList = new ArrayList<Integer>();
     // Map stream IDs to input/output configurations
     private SimpleEntry<Integer, InputConfiguration> mConfiguredInput =
             new SimpleEntry<>(REQUEST_ID_NONE, null);
@@ -486,7 +485,13 @@
             Log.d(TAG, "createCaptureSessionByOutputConfiguration");
         }
 
-        createCaptureSessionInternal(null, outputConfigurations, callback, handler,
+        // OutputConfiguration objects aren't immutable, make a copy before using.
+        List<OutputConfiguration> currentOutputs = new ArrayList<OutputConfiguration>();
+        for (OutputConfiguration output : outputConfigurations) {
+            currentOutputs.add(new OutputConfiguration(output));
+        }
+
+        createCaptureSessionInternal(null, currentOutputs, callback, handler,
                 /*isConstrainedHighSpeed*/false);
     }
 
@@ -511,6 +516,34 @@
     }
 
     @Override
+    public void createReprocessableCaptureSessionWithConfigurations(InputConfiguration inputConfig,
+            List<OutputConfiguration> outputs,
+            android.hardware.camera2.CameraCaptureSession.StateCallback callback, Handler handler)
+                    throws CameraAccessException {
+        if (DEBUG) {
+            Log.d(TAG, "createReprocessableCaptureSessionWithConfigurations");
+        }
+
+        if (inputConfig == null) {
+            throw new IllegalArgumentException("inputConfig cannot be null when creating a " +
+                    "reprocessable capture session");
+        }
+
+        if (outputs == null) {
+            throw new IllegalArgumentException("Output configurations cannot be null when " +
+                    "creating a reprocessable capture session");
+        }
+
+        // OutputConfiguration objects aren't immutable, make a copy before using.
+        List<OutputConfiguration> currentOutputs = new ArrayList<OutputConfiguration>();
+        for (OutputConfiguration output : outputs) {
+            currentOutputs.add(new OutputConfiguration(output));
+        }
+        createCaptureSessionInternal(inputConfig, currentOutputs,
+                callback, handler, /*isConstrainedHighSpeed*/false);
+    }
+
+    @Override
     public void createConstrainedHighSpeedCaptureSession(List<Surface> outputs,
             android.hardware.camera2.CameraCaptureSession.StateCallback callback, Handler handler)
             throws CameraAccessException {
@@ -916,11 +949,6 @@
                 int requestId = mRepeatingRequestId;
                 mRepeatingRequestId = REQUEST_ID_NONE;
 
-                // Queue for deletion after in-flight requests finish
-                if (mCaptureCallbackMap.get(requestId) != null) {
-                    mRepeatingRequestIdDeletedList.add(requestId);
-                }
-
                 try {
                     LongParcelable lastFrameNumberRef = new LongParcelable();
                     mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index a04cdce..4407e55 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -17,6 +17,7 @@
 
 package android.hardware.camera2.params;
 
+import android.annotation.SystemApi;
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.utils.HashCodeHelpers;
 import android.hardware.camera2.utils.SurfaceUtils;
@@ -32,39 +33,58 @@
  * A class for describing camera output, which contains a {@link Surface} and its specific
  * configuration for creating capture session.
  *
- * @see CameraDevice#createCaptureSession
+ * @see CameraDevice#createCaptureSessionByOutputConfiguration
  *
- * @hide
  */
 public final class OutputConfiguration implements Parcelable {
 
     /**
      * Rotation constant: 0 degree rotation (no rotation)
+     *
+     * @hide
      */
+    @SystemApi
     public static final int ROTATION_0 = 0;
 
     /**
      * Rotation constant: 90 degree counterclockwise rotation.
+     *
+     * @hide
      */
+    @SystemApi
     public static final int ROTATION_90 = 1;
 
     /**
      * Rotation constant: 180 degree counterclockwise rotation.
+     *
+     * @hide
      */
+    @SystemApi
     public static final int ROTATION_180 = 2;
 
     /**
      * Rotation constant: 270 degree counterclockwise rotation.
+     *
+     * @hide
      */
+    @SystemApi
     public static final int ROTATION_270 = 3;
 
     /**
-     * Create a new immutable SurfaceConfiguration instance.
+     * Invalid surface set ID.
+     *
+     *<p>An {@link OutputConfiguration} with this value indicates that the included surface
+     *doesn't belong to any surface set.</p>
+     */
+    public static final int SURFACE_SET_ID_INVALID = -1;
+
+    /**
+     * Create a new {@link OutputConfiguration} instance with a {@link Surface}.
      *
      * @param surface
      *          A Surface for camera to output to.
      *
-     * <p>This constructor creates a default configuration</p>
+     * <p>This constructor creates a default configuration.</p>
      *
      */
     public OutputConfiguration(Surface surface) {
@@ -72,7 +92,7 @@
     }
 
     /**
-     * Create a new immutable SurfaceConfiguration instance.
+     * Create a new {@link OutputConfiguration} instance.
      *
      * <p>This constructor takes an argument for desired camera rotation</p>
      *
@@ -87,11 +107,13 @@
      *          application should set rotation to {@code ROTATION_90} and make sure the
      *          corresponding Surface size is 720x1280. Note that {@link CameraDevice} might
      *          throw {@code IllegalArgumentException} if device cannot perform such rotation.
-     *
+     * @hide
      */
+    @SystemApi
     public OutputConfiguration(Surface surface, int rotation) {
         checkNotNull(surface, "Surface must not be null");
         checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
+        mSurfaceSetId = SURFACE_SET_ID_INVALID;
         mSurface = surface;
         mRotation = rotation;
         mConfiguredSize = SurfaceUtils.getSurfaceSize(surface);
@@ -100,13 +122,37 @@
     }
 
     /**
+     * Create a new {@link OutputConfiguration} instance with another {@link OutputConfiguration}
+     * instance.
+     *
+     * @param other Another {@link OutputConfiguration} instance to be copied.
+     *
+     * @hide
+     */
+    @SystemApi
+    public OutputConfiguration(OutputConfiguration other) {
+        if (other == null) {
+            throw new IllegalArgumentException("OutputConfiguration shouldn't be null");
+        }
+
+        this.mSurface = other.mSurface;
+        this.mRotation = other.mRotation;
+        this.mSurfaceSetId = other.mSurfaceSetId;
+        this.mConfiguredDataspace = other.mConfiguredDataspace;
+        this.mConfiguredFormat = other.mConfiguredFormat;
+        this.mConfiguredSize = other.mConfiguredSize;
+    }
+
+    /**
      * Create an OutputConfiguration from Parcel.
      */
     private OutputConfiguration(Parcel source) {
         int rotation = source.readInt();
+        int surfaceSetId = source.readInt();
         Surface surface = Surface.CREATOR.createFromParcel(source);
         checkNotNull(surface, "Surface must not be null");
         checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
+        mSurfaceSetId = surfaceSetId;
         mSurface = surface;
         mRotation = rotation;
         mConfiguredSize = SurfaceUtils.getSurfaceSize(mSurface);
@@ -128,11 +174,46 @@
      *
      * @return the rotation associated with this {@link OutputConfiguration}.
      *         Value will be one of ROTATION_[0, 90, 180, 270]
+     *
+     * @hide
      */
+    @SystemApi
     public int getRotation() {
         return mRotation;
     }
 
+    /**
+     * Set the surface set ID to this {@link OutputConfiguration}.
+     *
+     * <p>
+     * A surface set ID is used to identify which surface set this output surface belongs to. A
+     * surface set is a group of output surfaces that are not intended to receive camera output
+     * buffer streams simultaneously. The {@link CameraDevice} may be able to share the buffers used
+     * by all the surfaces from the same surface set, therefore may save the overall memory
+     * footprint. The application should only set the same set ID for the streams that are not
+     * simultaneously streaming. A negative ID indicates that this surface doesn't belong to any
+     * surface set. The default value will be {@value #SURFACE_SET_ID_INVALID}.
+     * </p>
+     *
+     * @param setId
+     */
+    public void setSurfaceSetId(int setId) {
+        if (setId < 0) {
+            setId = SURFACE_SET_ID_INVALID;
+        }
+        mSurfaceSetId = setId;
+    }
+
+    /**
+     * Get the surface set Id associated with this {@link OutputConfiguration}.
+     *
+     * @return the surface set Id associated with this {@link OutputConfiguration}.
+     *         Value will be one of ROTATION_[0, 90, 180, 270]
+     */
+    public int getSurfaceSetId() {
+        return mSurfaceSetId;
+    }
+
     public static final Parcelable.Creator<OutputConfiguration> CREATOR =
             new Parcelable.Creator<OutputConfiguration>() {
         @Override
@@ -163,6 +244,7 @@
             throw new IllegalArgumentException("dest must not be null");
         }
         dest.writeInt(mRotation);
+        dest.writeInt(mSurfaceSetId);
         mSurface.writeToParcel(dest, flags);
     }
 
@@ -187,7 +269,8 @@
                    mRotation == other.mRotation &&
                    mConfiguredSize.equals(other.mConfiguredSize) &&
                    mConfiguredFormat == other.mConfiguredFormat &&
-                   mConfiguredDataspace == other.mConfiguredDataspace;
+                   mConfiguredDataspace == other.mConfiguredDataspace &&
+                   mSurfaceSetId == other.mSurfaceSetId;
         }
         return false;
     }
@@ -203,6 +286,7 @@
     private static final String TAG = "OutputConfiguration";
     private final Surface mSurface;
     private final int mRotation;
+    private int mSurfaceSetId;
 
     // The size, format, and dataspace of the surface when OutputConfiguration is created.
     private final Size mConfiguredSize;
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 04caa8f..9f8c28e 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -491,12 +491,16 @@
      * credentials (e.g. pin, pattern or password).
      * @param cancel an object that can be used to cancel enrollment
      * @param flags optional flags
+     * @param userId the user to whom this fingerprint will belong to
      * @param callback an object to receive enrollment events
      * @hide
      */
     @RequiresPermission(MANAGE_FINGERPRINT)
     public void enroll(byte [] token, CancellationSignal cancel, int flags,
-            EnrollmentCallback callback) {
+            int userId, EnrollmentCallback callback) {
+        if (userId == UserHandle.USER_CURRENT) {
+            userId = getCurrentUserId();
+        }
         if (callback == null) {
             throw new IllegalArgumentException("Must supply an enrollment callback");
         }
@@ -512,7 +516,7 @@
 
         if (mService != null) try {
             mEnrollmentCallback = callback;
-            mService.enroll(mToken, token, getCurrentUserId(), mServiceReceiver, flags);
+            mService.enroll(mToken, token, userId, mServiceReceiver, flags);
         } catch (RemoteException e) {
             Log.w(TAG, "Remote exception in enroll: ", e);
             if (callback != null) {
@@ -556,19 +560,35 @@
     }
 
     /**
+     * Sets the active user. This is meant to be used to select the current profile for enrollment
+     * to allow separate enrolled fingers for a work profile
+     * @param userId
+     * @hide
+     */
+    @RequiresPermission(MANAGE_FINGERPRINT)
+    public void setActiveUser(int userId) {
+        if (mService != null) try {
+            mService.setActiveUser(userId);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Remote exception in setActiveUser: ", e);
+        }
+    }
+
+    /**
      * Remove given fingerprint template from fingerprint hardware and/or protected storage.
      * @param fp the fingerprint item to remove
+     * @param userId the user who this fingerprint belongs to
      * @param callback an optional callback to verify that fingerprint templates have been
      * successfully removed. May be null of no callback is required.
      *
      * @hide
      */
     @RequiresPermission(MANAGE_FINGERPRINT)
-    public void remove(Fingerprint fp, RemovalCallback callback) {
+    public void remove(Fingerprint fp, int userId, RemovalCallback callback) {
         if (mService != null) try {
             mRemovalCallback = callback;
             mRemovalFingerprint = fp;
-            mService.remove(mToken, fp.getFingerId(), getCurrentUserId(), mServiceReceiver);
+            mService.remove(mToken, fp.getFingerId(), userId, mServiceReceiver);
         } catch (RemoteException e) {
             Log.w(TAG, "Remote exception in remove: ", e);
             if (callback != null) {
@@ -581,16 +601,17 @@
     /**
      * Renames the given fingerprint template
      * @param fpId the fingerprint id
+     * @param userId the user who this fingerprint belongs to
      * @param newName the new name
      *
      * @hide
      */
     @RequiresPermission(MANAGE_FINGERPRINT)
-    public void rename(int fpId, String newName) {
+    public void rename(int fpId, int userId, String newName) {
         // Renames the given fpId
         if (mService != null) {
             try {
-                mService.rename(fpId, getCurrentUserId(), newName);
+                mService.rename(fpId, userId, newName);
             } catch (RemoteException e) {
                 Log.v(TAG, "Remote exception in rename(): ", e);
             }
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 690a751..43d5577 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -75,4 +75,7 @@
 
     // Add a callback which gets notified when the fingerprint lockout period expired.
     void addLockoutResetCallback(IFingerprintServiceLockoutResetCallback callback);
+
+    // Explicitly set the active user (for enrolling work profile)
+    void setActiveUser(int uid);
 }
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index ff33bd9..c4ee347 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -25,6 +25,8 @@
 import android.view.InputDevice;
 import android.view.InputEvent;
 import android.view.PointerIcon;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
 
 /** @hide */
 interface IInputManager {
@@ -49,15 +51,21 @@
 
     // Keyboard layouts configuration.
     KeyboardLayout[] getKeyboardLayouts();
+    KeyboardLayout[] getKeyboardLayoutsForInputDevice(in InputDeviceIdentifier identifier);
     KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor);
     String getCurrentKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier);
     void setCurrentKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
             String keyboardLayoutDescriptor);
-    String[] getKeyboardLayoutsForInputDevice(in InputDeviceIdentifier identifier);
+    String[] getEnabledKeyboardLayoutsForInputDevice(in InputDeviceIdentifier identifier);
     void addKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
             String keyboardLayoutDescriptor);
     void removeKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
             String keyboardLayoutDescriptor);
+    KeyboardLayout getKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
+            in InputMethodInfo imeInfo, in InputMethodSubtype imeSubtype);
+    void setKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
+            in InputMethodInfo imeInfo, in InputMethodSubtype imeSubtype,
+            String keyboardLayoutDescriptor);
 
     // Registers an input devices changed listener.
     void registerInputDevicesChangedListener(IInputDevicesChangedListener listener);
@@ -73,4 +81,6 @@
 
     void setPointerIconShape(int shapeId);
     void setCustomPointerIcon(in PointerIcon icon);
+
+    void setPointerIconDetached(boolean detached);
 }
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index fab4718..cbe3412 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -16,7 +16,7 @@
 
 package android.hardware.input;
 
-import android.view.PointerIcon;
+import com.android.internal.inputmethod.InputMethodSubtypeHandle;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.ArrayUtils;
 
@@ -40,6 +40,9 @@
 import android.util.SparseArray;
 import android.view.InputDevice;
 import android.view.InputEvent;
+import android.view.PointerIcon;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -474,6 +477,29 @@
     }
 
     /**
+     * Gets information about all supported keyboard layouts appropriate
+     * for a specific input device.
+     * <p>
+     * The input manager consults the built-in keyboard layouts as well
+     * as all keyboard layouts advertised by applications using a
+     * {@link #ACTION_QUERY_KEYBOARD_LAYOUTS} broadcast receiver.
+     * </p>
+     *
+     * @return A list of all supported keyboard layouts for a specific
+     * input device.
+     *
+     * @hide
+     */
+    public KeyboardLayout[] getKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
+        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];
+        }
+    }
+
+    /**
      * Gets the keyboard layout with the specified descriptor.
      *
      * @param keyboardLayoutDescriptor The keyboard layout descriptor, as returned by
@@ -551,13 +577,13 @@
      * @return The keyboard layout descriptors.
      * @hide
      */
-    public String[] getKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
+    public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
         if (identifier == null) {
             throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
         }
 
         try {
-            return mIm.getKeyboardLayoutsForInputDevice(identifier);
+            return mIm.getEnabledKeyboardLayoutsForInputDevice(identifier);
         } catch (RemoteException ex) {
             Log.w(TAG, "Could not get keyboard layouts for input device.", ex);
             return ArrayUtils.emptyArray(String.class);
@@ -620,6 +646,51 @@
         }
     }
 
+
+    /**
+     * Gets the keyboard layout for the specified input device and IME subtype.
+     *
+     * @param identifier The identifier for the input device.
+     * @param inputMethodInfo The input method.
+     * @param inputMethodSubtype The input method subtype.
+     *
+     * @return The associated {@link KeyboardLayout}, or null if one has not been set.
+     *
+     * @hide
+     */
+    public KeyboardLayout getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
+            InputMethodInfo inputMethodInfo, InputMethodSubtype inputMethodSubtype) {
+        try {
+            return mIm.getKeyboardLayoutForInputDevice(
+                    identifier, inputMethodInfo, inputMethodSubtype);
+        } catch (RemoteException ex) {
+            Log.w(TAG, "Could not set keyboard layout.", ex);
+            return null;
+        }
+    }
+
+    /**
+     * Sets the keyboard layout for the specified input device and IME subtype pair.
+     *
+     * @param identifier The identifier for the input device.
+     * @param inputMethodInfo The input method with which to associate the keyboard layout.
+     * @param inputMethodSubtype The input method subtype which which to associate the keyboard
+     *                           layout.
+     * @param keyboardLayoutDescriptor The descriptor of the keyboard layout to set
+     *
+     * @hide
+     */
+    public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
+            InputMethodInfo inputMethodInfo, InputMethodSubtype inputMethodSubtype,
+            String keyboardLayoutDescriptor) {
+        try {
+            mIm.setKeyboardLayoutForInputDevice(identifier, inputMethodInfo,
+                    inputMethodSubtype, keyboardLayoutDescriptor);
+        } catch (RemoteException ex) {
+            Log.w(TAG, "Could not set keyboard layout.", ex);
+        }
+    }
+
     /**
      * Gets the TouchCalibration applied to the specified input device's coordinates.
      *
@@ -829,6 +900,24 @@
         }
     }
 
+    /**
+     * Update the pointer icon status. When detached, the pointer icon disappears, and further
+     * mouse location will be stuck at the current point. Mouse movement events will still arrive,
+     * and movement should be handled through {@link MotionEvent.AXIS_RELATIVE_X} and
+     * {@link MotionEvent.AXIS_RELATIVE_Y}.
+     *
+     * @param detached true if the icon will be detached from the actual mouse movement.
+     *
+     * @hide
+     */
+    public void setPointerIconDetached(boolean detached) {
+        try {
+            mIm.setPointerIconDetached(detached);
+        } catch (RemoteException ex) {
+            // Do nothing.
+        }
+    }
+
     private void populateInputDevicesLocked() {
         if (mInputDevicesChangedListener == null) {
             final InputDevicesChangedListener listener = new InputDevicesChangedListener();
diff --git a/core/java/android/hardware/input/KeyboardLayout.java b/core/java/android/hardware/input/KeyboardLayout.java
index ed51402..2cafa08 100644
--- a/core/java/android/hardware/input/KeyboardLayout.java
+++ b/core/java/android/hardware/input/KeyboardLayout.java
@@ -16,8 +16,12 @@
 
 package android.hardware.input;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.LocaleList;
+
+import java.util.Locale;
 
 /**
  * Describes a keyboard layout.
@@ -30,6 +34,10 @@
     private final String mLabel;
     private final String mCollection;
     private final int mPriority;
+    @NonNull
+    private final LocaleList mLocales;
+    private final int mVendorId;
+    private final int mProductId;
 
     public static final Parcelable.Creator<KeyboardLayout> CREATOR =
             new Parcelable.Creator<KeyboardLayout>() {
@@ -41,11 +49,15 @@
         }
     };
 
-    public KeyboardLayout(String descriptor, String label, String collection, int priority) {
+    public KeyboardLayout(String descriptor, String label, String collection, int priority,
+            LocaleList locales, int vid, int pid) {
         mDescriptor = descriptor;
         mLabel = label;
         mCollection = collection;
         mPriority = priority;
+        mLocales = locales;
+        mVendorId = vid;
+        mProductId = pid;
     }
 
     private KeyboardLayout(Parcel source) {
@@ -53,6 +65,9 @@
         mLabel = source.readString();
         mCollection = source.readString();
         mPriority = source.readInt();
+        mLocales = LocaleList.CREATOR.createFromParcel(source);
+        mVendorId = source.readInt();
+        mProductId = source.readInt();
     }
 
     /**
@@ -83,6 +98,33 @@
         return mCollection;
     }
 
+    /**
+     * Gets the locales that this keyboard layout is intended for.
+     * This may be empty if a locale has not been assigned to this keyboard layout.
+     * @return The keyboard layout's intended locale.
+     */
+    public LocaleList getLocales() {
+        return mLocales;
+    }
+
+    /**
+     * Gets the vendor ID of the hardware device this keyboard layout is intended for.
+     * Returns -1 if this is not specific to any piece of hardware.
+     * @return The hardware vendor ID of the keyboard layout's intended device.
+     */
+    public int getVendorId() {
+        return mVendorId;
+    }
+
+    /**
+     * Gets the product ID of the hardware device this keyboard layout is intended for.
+     * Returns -1 if this is not specific to any piece of hardware.
+     * @return The hardware product ID of the keyboard layout's intended device.
+     */
+    public int getProductId() {
+        return mProductId;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -94,6 +136,9 @@
         dest.writeString(mLabel);
         dest.writeString(mCollection);
         dest.writeInt(mPriority);
+        mLocales.writeToParcel(dest, 0);
+        dest.writeInt(mVendorId);
+        dest.writeInt(mProductId);
     }
 
     @Override
diff --git a/core/java/android/hardware/input/TouchCalibration.java b/core/java/android/hardware/input/TouchCalibration.java
index 025fad0..15503ed 100644
--- a/core/java/android/hardware/input/TouchCalibration.java
+++ b/core/java/android/hardware/input/TouchCalibration.java
@@ -123,4 +123,10 @@
                Float.floatToIntBits(mYScale)  ^
                Float.floatToIntBits(mYOffset);
     }
+
+    @Override
+    public String toString() {
+        return String.format("[%f, %f, %f, %f, %f, %f]",
+                mXScale, mXYMix, mXOffset, mYXMix, mYScale, mYOffset);
+    }
 }
diff --git a/core/java/android/hardware/location/ContextHubInfo.aidl b/core/java/android/hardware/location/ContextHubInfo.aidl
new file mode 100644
index 0000000..1a9221a
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubInfo.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.location;
+/*
+@hide
+*/
+parcelable ContextHubInfo;
diff --git a/core/java/android/hardware/location/ContextHubInfo.java b/core/java/android/hardware/location/ContextHubInfo.java
new file mode 100644
index 0000000..e47c541
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubInfo.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.location;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * @hide
+  */
+@SystemApi
+public class ContextHubInfo {
+    private int mId;
+    private String mName;
+    private String mVendor;
+    private String mToolchain;
+    private int mPlatformVersion;
+    private int mStaticSwVersion;
+    private int mToolchainVersion;
+    private float mPeakMips;
+    private float mStoppedPowerDrawMw;
+    private float mSleepPowerDrawMw;
+    private float mPeakPowerDrawMw;
+
+    private int[] mSupportedSensors;
+
+    private MemoryRegion[] mMemoryRegions;
+
+    public ContextHubInfo() {
+    }
+
+    /**
+     * get the context hub unique identifer
+     *
+     * @return int - unique system wide identifier
+     */
+    public int getId() {
+        return mId;
+    }
+
+    /**
+     * set the context hub unique identifer
+     *
+     * @param id - unique system wide identifier for the hub
+     */
+    public void setId(int id) {
+        mId = id;
+    }
+
+    /**
+     * get a string as a hub name
+     *
+     * @return String - a name for the hub
+     */
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * set a string as the hub name
+     *
+     * @param String - the name for the hub
+     */
+    public void setName(String name) {
+        mName = name;
+    }
+
+    /**
+     * get a string as the vendor name
+     *
+     * @return String - a name for the vendor
+     */
+    public String getVendor() {
+        return mVendor;
+    }
+
+    /**
+     * set a string as the vendor name
+     *
+     * @param String - a name for the vendor
+     */
+    public void setVendor(String vendor) {
+        mVendor = vendor;
+    }
+
+    /**
+     * get tool chain string
+     *
+     * @return String - description of the tool chain
+     */
+    public String getToolchain() {
+        return mToolchain;
+    }
+
+    /**
+     * set tool chain string
+     *
+     * @param String - description of the tool chain
+     */
+    public void setToolchain(String toolchain) {
+        mToolchain = toolchain;
+    }
+
+    /**
+     * get platform version
+     *
+     * @return int - platform version number
+     */
+    public int getPlatformVersion() {
+        return mPlatformVersion;
+    }
+
+    /**
+     * set platform version
+     *
+     * @param platformVersion - platform version number
+     */
+    public void setPlatformVersion(int platformVersion) {
+        mPlatformVersion = platformVersion;
+    }
+
+    /**
+     * get static platform version number
+     *
+     * @return int - platform version number
+     */
+    public int getStaticSwVersion() {
+        return mStaticSwVersion;
+    }
+
+    /**
+     * set platform software version
+     *
+     * @param staticSwVersion - platform static s/w version number
+     */
+    public void setStaticSwVersion(int staticSwVersion) {
+        mStaticSwVersion = staticSwVersion;
+    }
+
+    /**
+     * get the tool chain version
+     *
+     * @return int - the tool chain version
+     */
+    public int getToolchainVersion() {
+        return mToolchainVersion;
+    }
+
+    /**
+     * set the tool chain version number
+     *
+     * @param toolchainVersion - tool chain version number
+     */
+    public void setToolchainVersion(int toolchainVersion) {
+        mToolchainVersion = toolchainVersion;
+    }
+
+    /**
+     * get the peak processing mips the hub can support
+     *
+     * @return float - peak MIPS that this hub can deliver
+     */
+    public float getPeakMips() {
+        return mPeakMips;
+    }
+
+    /**
+     * set the peak mips that this hub can support
+     *
+     * @param peakMips - peak mips this hub can deliver
+     */
+    public void setPeakMips(float peakMips) {
+        mPeakMips = peakMips;
+    }
+
+    /**
+     * get the stopped power draw in milliwatts
+     * This assumes that the hub enter a stopped state - which is
+     * different from the sleep state. Latencies on exiting the
+     * sleep state are typically higher and expect to be in multiple
+     * milliseconds.
+     *
+     * @return float - power draw by the hub in stopped state
+     */
+    public float getStoppedPowerDrawMw() {
+        return mStoppedPowerDrawMw;
+    }
+
+    /**
+     * Set the power consumed by the hub in stopped state
+     *
+     * @param stoppedPowerDrawMw - stopped power in milli watts
+     */
+    public void setStoppedPowerDrawMw(float stoppedPowerDrawMw) {
+        mStoppedPowerDrawMw = stoppedPowerDrawMw;
+    }
+
+    /**
+     * get the power draw of the hub in sleep mode. This assumes
+     * that the hub supports a sleep mode in which the power draw is
+     * lower than the power consumed when the hub is actively
+     * processing. As a guideline, assume that the hub should be
+     * able to enter sleep mode if it knows reliably on completion
+     * of some task that the next interrupt/scheduled work item is
+     * at least 250 milliseconds later.
+     *
+     * @return float - sleep power draw in milli watts
+     */
+    public float getSleepPowerDrawMw() {
+        return mSleepPowerDrawMw;
+    }
+
+    /**
+     * Set the sleep power draw in milliwatts
+     *
+     * @param sleepPowerDrawMw - sleep power draw in milliwatts.
+     */
+    public void setSleepPowerDrawMw(float sleepPowerDrawMw) {
+        mSleepPowerDrawMw = sleepPowerDrawMw;
+    }
+
+    /**
+     * get the peak powe draw of the hub. This is the power consumed
+     * by the hub at maximum load.
+     *
+     * @return float - peak power draw
+     */
+    public float getPeakPowerDrawMw() {
+        return mPeakPowerDrawMw;
+    }
+
+    /**
+     * set the peak power draw of the hub
+     *
+     * @param peakPowerDrawMw - peak power draw of the hub in
+     *                        milliwatts.
+     */
+    public void setPeakPowerDrawMw(float peakPowerDrawMw) {
+        mPeakPowerDrawMw = peakPowerDrawMw;
+    }
+
+    /**
+     * get the sensors supported by this hub
+     *
+     * @return int[] - all the supported sensors on this hub
+     *
+     * @see ContextHubManager
+     */
+    public int[] getSupportedSensors() {
+        return Arrays.copyOf(mSupportedSensors, mSupportedSensors.length);
+    }
+
+    /**
+     * get the various memory regions on this hub
+     *
+     * @return MemoryRegion[] - all the memory regions on this hub
+     *
+     * @see MemoryRegion
+     */
+    public MemoryRegion[] getMemoryRegions() {
+        return Arrays.copyOf(mMemoryRegions, mMemoryRegions.length);
+    }
+
+    /**
+     * set the supported sensors on this hub
+     *
+     * @param supportedSensors - supported sensors on this hub
+     */
+    public void setSupportedSensors(int[] supportedSensors) {
+        mSupportedSensors = Arrays.copyOf(supportedSensors, supportedSensors.length);
+    }
+
+    /**
+     * set memory regions for this hub
+     *
+     * @param memoryRegions - memory regions information
+     *
+     * @see MemoryRegion
+     */
+    public void setMemoryRegions(MemoryRegion[] memoryRegions) {
+        mMemoryRegions = Arrays.copyOf(memoryRegions, memoryRegions.length);
+    }
+
+    private ContextHubInfo(Parcel in) {
+        mId = in.readInt();
+        mName = in.readString();
+        mVendor = in.readString();
+        mToolchain = in.readString();
+        mPlatformVersion = in.readInt();
+        mToolchainVersion = in.readInt();
+        mStaticSwVersion = in.readInt();
+        mPeakMips = in.readFloat();
+        mStoppedPowerDrawMw = in.readFloat();
+        mSleepPowerDrawMw = in.readFloat();
+        mPeakPowerDrawMw = in.readFloat();
+
+        int numSupportedSensors = in.readInt();
+        mSupportedSensors = new int[numSupportedSensors];
+        in.readIntArray(mSupportedSensors);
+        mMemoryRegions = in.createTypedArray(MemoryRegion.CREATOR);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mId);
+        out.writeString(mName);
+        out.writeString(mVendor);
+        out.writeString(mToolchain);
+        out.writeInt(mPlatformVersion);
+        out.writeInt(mToolchainVersion);
+        out.writeInt(mStaticSwVersion);
+        out.writeFloat(mPeakMips);
+        out.writeFloat(mStoppedPowerDrawMw);
+        out.writeFloat(mSleepPowerDrawMw);
+        out.writeFloat(mPeakPowerDrawMw);
+
+        out.writeInt(mSupportedSensors.length);
+        out.writeIntArray(mSupportedSensors);
+        out.writeTypedArray(mMemoryRegions, flags);
+    }
+
+    public static final Parcelable.Creator<ContextHubInfo> CREATOR
+            = new Parcelable.Creator<ContextHubInfo>() {
+        public ContextHubInfo createFromParcel(Parcel in) {
+            return new ContextHubInfo(in);
+        }
+
+        public ContextHubInfo[] newArray(int size) {
+            return new ContextHubInfo[size];
+        }
+    };
+}
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
new file mode 100644
index 0000000..301b2e4
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.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.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * A class that exposes the Context hubs on a device to
+ * applicaions.
+ *
+ * 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.
+ *
+ * @hide
+ */
+@SystemApi
+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 IContextHubService mContextHubService;
+    private boolean mContextHubConnected;
+
+    /**
+     * A special context hub identifer meaning any possible hub on
+     * the system.
+     */
+    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;
+
+
+    /**
+     * Get a handle to all the context hubs in the system
+     * @return array of context hub handles
+     */
+    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());
+            }
+        }
+        return retVal;
+    }
+
+    /**
+     * Get more information about a specific hub.
+     *
+     * @param contexthubHandle Handle of context hub
+     *
+     * @return ContextHubInfo  returned information about the hub
+     *
+     * @see ContextHubInfo
+     */
+    public ContextHubInfo getContexthubInfo(int contexthubHandle) {
+        ContextHubInfo retVal = null;
+        if(mContextHubConnected) {
+            try {
+                retVal = mContextHubService.getContextHubInfo(contexthubHandle);
+            }catch (RemoteException e) {
+                Log.e (TAG, "Could not fetch context hub info :" + e.toString());
+            }
+        }
+
+        return(retVal);
+    }
+
+    /**
+     * Load a nanoapp 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
+     *
+     * @return int nanoAppInstance of the loaded nanoApp on success,
+     *         -1 otherwise
+     *
+     * @see NanoApp
+     */
+    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());
+            }
+        }
+
+        return retVal;
+    }
+
+    /**
+     * Unload a specified nanoApp
+     *
+     * @param nanoAppInstanceHandle handle of the nanoApp to load
+     *
+     * @return int  0 on success, -1 otherewise
+     */
+    public int unloadNanoApp(int nanoAppInstanceHandle) {
+        int retVal = -1;
+
+        if(mContextHubConnected) {
+            try {
+                retVal = mContextHubService.unloadNanoApp(nanoAppInstanceHandle);
+            }catch (RemoteException e) {
+                Log.e (TAG, "Could not fetch unload nanoApp :" + e.toString());
+            }
+        }
+
+        return retVal;
+    }
+
+    /**
+     * get information about the nano app instance
+     *
+     * @param nanoAppInstanceHandle handle of the nanoAppInstance
+     *
+     * @return NanoAppInstanceInfo Inforamtion about the nano app
+     *         instance.
+     *
+     * @see NanoAppInstanceInfo
+     */
+    public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle) {
+        NanoAppInstanceInfo retVal = null;
+
+        if(mContextHubConnected) {
+            try {
+                retVal = mContextHubService.getNanoAppInstanceInfo(nanoAppInstanceHandle);
+            }catch (RemoteException e) {
+                Log.e (TAG, "Could not fetch nanoApp info :" + e.toString());
+            }
+        }
+
+        return retVal;
+    }
+
+    /**
+     * Find a specified nano app on the system
+     *
+     * @param hubHandle handle of hub to search for nano app
+     * @param filter filter specifying the search criteria for app
+     *
+     * @see NanoAppFilter
+     *
+     * @return Integer[] Array of handles to any found nano apps
+     */
+    public Integer[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) {
+        int[] temp;
+        Integer[] retVal = null;
+
+        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());
+            }
+        }
+
+        return retVal;
+    }
+
+    /**
+     * Send a message to a spcific 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 msg Message to be sent
+     *
+     * @see ContextHubMessage
+     *
+     * @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;
+    }
+
+    private void checkPermissions() {
+        mContext.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE);
+    }
+
+    private IContextHubCallback.Stub mClientCallback = new IContextHubCallback.Stub() {
+        @Override
+        public void onMessageReceipt(int hubId, int nanoAppId, ContextHubMessage msg) throws RemoteException {
+
+        }
+    };
+
+    private ContextHubManager(Context context) {
+        checkPermissions();
+        mContext = context;
+        mContextHubConnected = false;
+    }
+
+    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());
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            mContextHubService = null;
+            mContextHubConnected = false;
+            Log.d(TAG, "contexthub manager disconnected from " + name.toString());
+        }
+    };
+
+}
diff --git a/core/java/android/hardware/location/ContextHubMessage.aidl b/core/java/android/hardware/location/ContextHubMessage.aidl
new file mode 100644
index 0000000..915f1ec
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubMessage.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.hardware.location;
+/*
+@hide
+*/
+parcelable ContextHubMessage;
+
diff --git a/core/java/android/hardware/location/ContextHubMessage.java b/core/java/android/hardware/location/ContextHubMessage.java
new file mode 100644
index 0000000..954e97d
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubMessage.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.hardware.location;
+
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * @hide
+ */
+@SystemApi
+public class ContextHubMessage {
+    private int mType;
+    private int mVersion;
+    private byte[]mData;
+
+    /**
+     * Get the message type
+     *
+     * @return int - message type
+     */
+    public int getMsgType() {
+        return mType;
+    }
+
+    /**
+     * get message version
+     *
+     * @return int - message version
+     */
+    public int getVersion() {
+        return mVersion;
+    }
+
+    /**
+     * get message data
+     *
+     * @return byte[] - message data buffer
+     */
+    public byte[] getData() {
+        return Arrays.copyOf(mData, mData.length);
+    }
+
+    /**
+     * set message type
+     *
+     * @param msgType - message type
+     */
+    public void setMsgType(int msgType) {
+        mType = msgType;
+    }
+
+    /**
+     * Set message version
+     *
+     * @param version - message version
+     */
+    public void setVersion(int version) {
+        mVersion = version;
+    }
+
+    /**
+     * set message data
+     *
+     * @param data - message buffer
+     */
+    public void setMsgData(byte[] data) {
+        mData = Arrays.copyOf(data, data.length);
+    }
+
+    /**
+     * Constructor for a context hub message
+     *
+     * @param msgType - message type
+     * @param version - version
+     * @param data    - message buffer
+     */
+    public ContextHubMessage(int msgType, int version, byte[] data) {
+        mType = msgType;
+        mVersion = version;
+        mData = Arrays.copyOf(data, data.length);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    private ContextHubMessage(Parcel in) {
+        mType = in.readInt();
+        mVersion = in.readInt();
+        byte[] byteBuffer = new byte[in.readInt()];
+        in.readByteArray(byteBuffer);
+    }
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mType);
+        out.writeInt(mVersion);
+        out.writeInt(mData.length);
+        out.writeByteArray(mData);
+    }
+
+    public static final Parcelable.Creator<ContextHubMessage> CREATOR
+            = new Parcelable.Creator<ContextHubMessage>() {
+        public ContextHubMessage createFromParcel(Parcel in) {
+            return new ContextHubMessage(in);
+        }
+
+        public ContextHubMessage[] newArray(int size) {
+            return new ContextHubMessage[size];
+        }
+    };
+}
diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java
new file mode 100644
index 0000000..a2a13c6
--- /dev/null
+++ b/core/java/android/hardware/location/ContextHubService.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.location;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * @hide
+ */
+public class ContextHubService extends Service {
+
+    private static final String TAG = "ContextHubService";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private static ContextHubService sSingletonInstance;
+    private static final Object sSingletonInstanceLock = new Object();
+
+    private HashMap<Integer, ContextHubInfo> mHubHash;
+    private HashMap<Integer, NanoAppInstanceInfo> mNanoAppHash;
+    private ContextHubInfo[] mContexthubInfo;
+
+
+    private native int nativeSendMessage(int[] header, byte[] data);
+    private native ContextHubInfo[] nativeInitialize();
+
+    private int onMessageReceipt(int[] header, byte[] data) {
+        return 0;
+    }
+    private void initialize() {
+        mContexthubInfo = nativeInitialize();
+
+        mHubHash = new HashMap<Integer, ContextHubInfo>();
+
+        for (int i = 0; i < mContexthubInfo.length; i++) {
+            mHubHash.put(i + 1, mContexthubInfo[i]); // Avoiding zero
+        }
+    }
+
+    private ContextHubService(Context context) {
+        initialize();
+        Log.d(TAG, "Created from " + context.toString());
+    }
+
+    public static ContextHubService getInstance(Context context) {
+        synchronized (sSingletonInstanceLock) {
+            if (sSingletonInstance == null) {
+                sSingletonInstance = new ContextHubService(context);
+            }
+            return sSingletonInstance;
+        }
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    private final IContextHubService.Stub mBinder = new IContextHubService.Stub() {
+
+        private  IContextHubCallback callback;
+
+        @Override
+        public int registerCallBack(IContextHubCallback callback) throws RemoteException{
+            this.callback = callback;
+            return 0;
+        }
+
+        @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;
+        }
+
+        @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 {
+
+                    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);
+            }
+        }
+
+        @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;
+            }
+        }
+
+        @Override
+        public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) throws RemoteException {
+            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 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()));
+        }
+    };
+}
diff --git a/core/java/android/hardware/location/IContextHubCallback.aidl b/core/java/android/hardware/location/IContextHubCallback.aidl
new file mode 100644
index 0000000..45b1ef4
--- /dev/null
+++ b/core/java/android/hardware/location/IContextHubCallback.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.hardware.location;
+
+import android.hardware.location.ContextHubMessage;
+
+/** @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
new file mode 100644
index 0000000..b2db0b2
--- /dev/null
+++ b/core/java/android/hardware/location/IContextHubService.aidl
@@ -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 android.hardware.location;
+
+// Declare any non-default types here with import statements
+import android.hardware.location.ContextHubMessage;
+import android.hardware.location.ContextHubInfo;
+import android.hardware.location.NanoApp;
+import android.hardware.location.NanoAppInstanceInfo;
+import android.hardware.location.NanoAppFilter;
+import android.hardware.location.IContextHubCallback;
+
+/** @hide */
+interface IContextHubService {
+
+    // register a callback to receive messages
+    int registerCallBack(in IContextHubCallback callback);
+
+    // Gets a list of available context hub handles
+    int[] getContextHubHandles();
+
+    // Get the properties of a hub
+    ContextHubInfo getContextHubInfo(int contextHubHandle);
+
+    // Load a nanoapp on a specified context hub
+    int loadNanoApp(int hubHandle, in NanoApp app);
+
+    // Unload a nanoapp instance
+    int unloadNanoApp(int nanoAppInstanceHandle);
+
+    // get information about a nanoAppInstance
+    NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle);
+
+    // find all nanoApp instances matching some filter
+    int[] findNanoAppOnHub(int hubHandle, in NanoAppFilter filter);
+
+    // send a message to a nanoApp
+    int sendMessage(int hubHandle, int nanoAppHandle, in ContextHubMessage msg);
+}
diff --git a/core/java/android/hardware/location/MemoryRegion.java b/core/java/android/hardware/location/MemoryRegion.java
new file mode 100644
index 0000000..e8c7615
--- /dev/null
+++ b/core/java/android/hardware/location/MemoryRegion.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.location;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+
+@SystemApi
+public class MemoryRegion implements Parcelable{
+
+    private int mSizeBytes;
+    private int mSizeBytesFree;
+    private boolean mIsReadable;
+    private boolean mIsWritable;
+    private boolean mIsExecutable;
+
+    /**
+     * get the capacity of the memory region in bytes
+     *
+     * @return int - the memory capacity in bytes
+     */
+    public int getCapacityBytes() {
+        return mSizeBytes;
+    }
+
+    /**
+     * get the free capacity of the memory region in bytes
+     *
+     * @return int - free bytes
+     */
+    public int getFreeCapacityBytes() {
+        return mSizeBytesFree;
+    }
+
+    /**
+     * Is the memory readable
+     *
+     * @return boolean - true if memory is readable, false otherwise
+     */
+    public boolean isReadable() {
+        return mIsReadable;
+    }
+
+    /**
+     * Is the memory writable
+     *
+     * @return boolean - true if memory is writable, false otherwise
+     */
+    public boolean isWritable() {
+        return mIsWritable;
+    }
+
+    /**
+     * Is the memory executable
+     *
+     * @return boolean - true if memory is executable, false
+     *         otherwise
+     */
+    public boolean isExecutable() {
+        return mIsExecutable;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mSizeBytes);
+        dest.writeInt(mSizeBytesFree);
+        dest.writeInt(mIsReadable ? 1 : 0);
+        dest.writeInt(mIsWritable ? 1 : 0);
+        dest.writeInt(mIsExecutable ? 1 : 0);
+    }
+
+    public MemoryRegion(Parcel source) {
+        mSizeBytes = source.readInt();
+        mSizeBytesFree = source.readInt();
+        mIsReadable = source.readInt() != 0;
+        mIsWritable = source.readInt() != 0;
+        mIsExecutable = source.readInt() != 0;
+    }
+
+    public static final Parcelable.Creator<MemoryRegion> CREATOR
+            = new Parcelable.Creator<MemoryRegion>() {
+        public MemoryRegion createFromParcel(Parcel in) {
+            return new MemoryRegion(in);
+        }
+
+        public MemoryRegion[] newArray(int size) {
+            return new MemoryRegion[size];
+        }
+    };
+
+}
diff --git a/core/java/android/hardware/location/NanoApp.aidl b/core/java/android/hardware/location/NanoApp.aidl
new file mode 100644
index 0000000..d32c44a
--- /dev/null
+++ b/core/java/android/hardware/location/NanoApp.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.location;
+/*
+@hide
+*/
+parcelable NanoApp;
diff --git a/core/java/android/hardware/location/NanoApp.java b/core/java/android/hardware/location/NanoApp.java
new file mode 100644
index 0000000..36d181f
--- /dev/null
+++ b/core/java/android/hardware/location/NanoApp.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.location;
+
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * 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.
+ *
+ * Nano apps are expected to be used only by bundled apps only
+ * at this time.
+ *
+ * @hide
+ */
+@SystemApi
+public class NanoApp {
+    private String mPublisher;
+    private String mName;
+
+    private int mAppId;
+    private int mAppVersion;
+
+    private int mNeededReadMemBytes;
+    private int mNeededWriteMemBytes;
+    private int mNeededExecMemBytes;
+
+    private int[] mNeededSensors;
+    private int[] mOutputEvents;
+    private byte[] mAppBinary;
+
+    public NanoApp() {
+    }
+
+    /**
+     * Set the publisher name
+     *
+     * @param publisher name of the publisher of this nano app
+     */
+    public void setPublisher(String publisher) {
+        mPublisher = publisher;
+    }
+
+    /**
+     * set the name of the app
+     *
+     * @param name   name of the app
+     */
+    public void setName(String name) {
+        mName = name;
+    }
+
+    /**
+     * set the app identifier
+     *
+     * @param appId  add identifier
+     */
+    public void setAppId(int appId) {
+        mAppId = appId;
+    }
+
+    /**
+     * Set the app version
+     *
+     * @param appVersion app version
+     */
+    public void setAppVersion(int appVersion) {
+        mAppVersion = appVersion;
+    }
+
+    /**
+     * set memory needed as read only
+     *
+     * @param neededReadMemBytes
+     *               read only memory needed in bytes
+     */
+    public void setNeededReadMemBytes(int neededReadMemBytes) {
+        mNeededReadMemBytes = neededReadMemBytes;
+    }
+
+    /**
+     * set writable memory needed in bytes
+     *
+     * @param neededWriteMemBytes
+     *               writable memory needed in bytes
+     */
+    public void setNeededWriteMemBytes(int neededWriteMemBytes) {
+        mNeededWriteMemBytes = neededWriteMemBytes;
+    }
+
+    /**
+     * set executable memory needed
+     *
+     * @param neededExecMemBytes
+     *               executable memory needed in bytes
+     */
+    public void setNeededExecMemBytes(int neededExecMemBytes) {
+        mNeededExecMemBytes = neededExecMemBytes;
+    }
+
+    /**
+     * set the sensors needed for this app
+     *
+     * @param neededSensors
+     *               needed Sensors
+     */
+    public void setNeededSensors(int[] neededSensors) {
+        mNeededSensors = neededSensors;
+    }
+
+    public void setOutputEvents(int[] outputEvents) {
+        mOutputEvents = outputEvents;
+    }
+
+    /**
+     * set output events returned by the nano app
+     *
+     * @param appBinary generated events
+     */
+    public void setAppBinary(byte[] appBinary) {
+        mAppBinary = appBinary;
+    }
+
+
+    /**
+     * get the publisher name
+     *
+     * @return publisher name
+     */
+    public String getPublisher() {
+      return mPublisher;
+    }
+
+    /**
+     * get the name of the app
+     *
+     * @return app name
+     */
+    public String getName() {
+    return mName;
+    }
+
+    /**
+     * get the identifier of the app
+     *
+     * @return identifier for this app
+     */
+    public int getAppId() {
+      return mAppId;
+    }
+
+    /**
+     * get the app version
+     *
+     * @return app version
+     */
+    public int getAppVersion() {
+      return mAppVersion;
+    }
+
+    /**
+     * get the ammount of readable memory needed by this app
+     *
+     * @return readable memory needed in bytes
+     */
+    public int getNeededReadMemBytes() {
+      return mNeededReadMemBytes;
+    }
+
+    /**
+     * get the ammount og writable memory needed in bytes
+     *
+     * @return writable memory needed in bytes
+     */
+    public int getNeededWriteMemBytes() {
+      return mNeededWriteMemBytes;
+    }
+
+    /**
+     * executable memory needed in bytes
+     *
+     * @return executable memory needed in bytes
+     */
+    public int getNeededExecMemBytes() {
+      return mNeededExecMemBytes;
+    }
+
+    /**
+     * get the sensors needed by this app
+     *
+     * @return sensors needed
+     */
+    public int[] getNeededSensors() {
+      return mNeededSensors;
+    }
+
+    /**
+     * get the events generated by this app
+     *
+     * @return generated events
+     */
+    public int[] getOutputEvents() {
+      return mOutputEvents;
+    }
+
+    /**
+     * get the binary for this app
+     *
+     * @return app binary
+     */
+    public byte[] getAppBinary() {
+      return mAppBinary;
+    }
+
+    private NanoApp(Parcel in) {
+        mPublisher = in.readString();
+        mName = in.readString();
+
+        mAppId = in.readInt();
+        mAppVersion = in.readInt();
+        mNeededReadMemBytes = in.readInt();
+        mNeededWriteMemBytes = in.readInt();
+        mNeededExecMemBytes = in.readInt();
+
+        int mNeededSensorsLength = in.readInt();
+        mNeededSensors = new int[mNeededSensorsLength];
+        in.readIntArray(mNeededSensors);
+
+        int mOutputEventsLength = in.readInt();
+        mOutputEvents = new int[mOutputEventsLength];
+        in.readIntArray(mOutputEvents);
+
+        int binaryLength = in.readInt();
+        mAppBinary = new byte[binaryLength];
+        in.readByteArray(mAppBinary);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mPublisher);
+        out.writeString(mName);
+        out.writeInt(mAppId);
+        out.writeInt(mAppVersion);
+        out.writeInt(mNeededReadMemBytes);
+        out.writeInt(mNeededWriteMemBytes);
+        out.writeInt(mNeededExecMemBytes);
+
+        out.writeInt(mNeededSensors.length);
+        out.writeIntArray(mNeededSensors);
+
+        out.writeInt(mOutputEvents.length);
+        out.writeIntArray(mOutputEvents);
+
+        out.writeInt(mAppBinary.length);
+        out.writeByteArray(mAppBinary);
+    }
+
+    public static final Parcelable.Creator<NanoApp> CREATOR
+            = new Parcelable.Creator<NanoApp>() {
+        public NanoApp createFromParcel(Parcel in) {
+            return new NanoApp(in);
+        }
+
+        public NanoApp[] newArray(int size) {
+            return new NanoApp[size];
+        }
+    };
+}
diff --git a/core/java/android/hardware/location/NanoAppFilter.aidl b/core/java/android/hardware/location/NanoAppFilter.aidl
new file mode 100644
index 0000000..cc6d475
--- /dev/null
+++ b/core/java/android/hardware/location/NanoAppFilter.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.location;
+/*
+@hide
+*/
+parcelable NanoAppFilter;
diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
new file mode 100644
index 0000000..ac341e4
--- /dev/null
+++ b/core/java/android/hardware/location/NanoAppFilter.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 android.hardware.location;
+
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public class NanoAppFilter {
+
+    // The appId, can be set to APP_ID_ANY
+    private long mAppId;
+
+    // Version to filter apps
+    private int mAppVersion;
+
+    // filtering spec for version
+    private int mVersionRestrictionMask;
+
+    // If APP_ID is any, then a match is performef with the vendor mask
+    private long mAppIdVendorMask;
+
+    // Id of the context hub this instance is expected on
+    private int mContextHubId;
+
+    /**
+     * Flag indicating any version. With this flag set, all versions shall match provided version.
+     */
+    public static final int FLAGS_VERSION_ANY = -1;
+    /**
+     * If this flag is set, only versions strictly greater than the version specified shall match.
+     */
+    public static final int FLAGS_VERSION_GREAT_THAN  = 2;
+    /**
+     * If this flag is set, only versions strictly less than the version specified shall match.
+     */
+    public static final int FLAGS_VERSION_LESS_THAN   = 4;
+    public static final int FLAGS_VERSION_STRICTLY_EQUAL = 8;
+
+    /**
+     * If this flag is set, only versions strictly equal to the version specified shall match.
+     */
+    public static final int APP_ANY = -1;
+
+    /**
+     * If this flag is set, all vendors shall match.
+     */
+    public static final int VENDOR_ANY = -1;
+
+    /**
+     * If this flag is set, any hub shall match.
+     */
+    public static final int HUB_ANY = -1;
+
+    private NanoAppFilter(Parcel in) {
+        mAppId = in.readLong();
+        mAppVersion = in.readInt();
+        mVersionRestrictionMask = in.readInt();
+        mAppIdVendorMask = in.readInt();
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+
+        out.writeLong(mAppId);
+        out.writeInt(mAppVersion);
+        out.writeInt(mVersionRestrictionMask);
+        out.writeLong(mAppIdVendorMask);
+    }
+
+    /**
+     * Create a filter
+     *
+     * @param appId       application id
+     * @param appVersion  application version
+     * @param versionMask version
+     * @param vendorMask  vendor
+     */
+    public NanoAppFilter(long appId, int appVersion, int versionMask, long vendorMask) {
+        mAppId = appId;
+        mAppVersion = appVersion;
+        mVersionRestrictionMask = versionMask;
+        mAppIdVendorMask = vendorMask;
+    }
+
+    private boolean versionsMatch(int versionRestrictionMask, int expected, int actual){
+        // some refactoring of version restriction mask is needed, until then, return all
+        return true;
+    }
+    /**
+     *
+     * @param 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) &&
+                (mAppId == APP_ANY || info.getAppId() == mAppId) &&
+               // (mAppIdVendorMask == VENDOR_ANY) TODO : Expose Vendor mask cleanly
+                (versionsMatch(mVersionRestrictionMask, mAppVersion, info.getAppVersion()))) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public static final Parcelable.Creator<NanoAppFilter> CREATOR
+            = new Parcelable.Creator<NanoAppFilter>() {
+        public NanoAppFilter createFromParcel(Parcel in) {
+            return new NanoAppFilter(in);
+        }
+
+        public NanoAppFilter[] newArray(int size) {
+            return new NanoAppFilter[size];
+        }
+    };
+}
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.aidl b/core/java/android/hardware/location/NanoAppInstanceInfo.aidl
new file mode 100644
index 0000000..c8c40d7
--- /dev/null
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.location;
+/*
+@hide
+*/
+parcelable NanoAppInstanceInfo;
\ No newline at end of file
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
new file mode 100644
index 0000000..ac62919
--- /dev/null
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.location;
+
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public class NanoAppInstanceInfo {
+    private String mPublisher;
+    private String mName;
+
+    private int mAppId;
+    private int mAppVersion;
+
+    private int mNeededReadMemBytes;
+    private int mNeededWriteMemBytes;
+    private int mNeededExecMemBytes;
+
+    private int[] mNeededSensors;
+    private int[] mOutputEvents;
+
+    private int mContexthubId;
+    private int mHandle;
+
+    public NanoAppInstanceInfo() {
+    }
+
+    /**
+     * get the publisher of this app
+     *
+     * @return String - name of the publisher
+     */
+    public String getPublisher() {
+        return mPublisher;
+    }
+
+
+    /**
+     * set the publisher name for the app
+     *
+     * @param publisher - name of the publisher
+     */
+    public void setPublisher(String publisher) {
+        mPublisher = publisher;
+    }
+
+    /**
+     * get the name of the app
+     *
+     * @return String - name of the app
+     */
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * set the name of the app
+     *
+     * @param name - name of the app
+     */
+    public void setName(String name) {
+        mName = name;
+    }
+
+    /**
+     * Get the application identifier
+     *
+     * @return int - application identifier
+     */
+    public int getAppId() {
+        return mAppId;
+    }
+
+    /**
+     * Set the application identifier
+     *
+     * @param appId - application identifier
+     */
+    public void setAppId(int appId) {
+        mAppId = appId;
+    }
+
+    /**
+     * Set the application version
+     *
+     * @return int - version of the app
+     */
+    public int getAppVersion() {
+        return mAppVersion;
+    }
+
+    /**
+     * Set the application version
+     *
+     * @param appVersion - version of the app
+     */
+    public void setAppVersion(int appVersion) {
+        mAppVersion = appVersion;
+    }
+
+    /**
+     * Get the read memory needed by the app
+     *
+     * @return int - readable memory needed in bytes
+     */
+    public int getNeededReadMemBytes() {
+        return mNeededReadMemBytes;
+    }
+
+    /**
+     * Set the read memory needed by the app
+     *
+     * @param neededReadMemBytes - readable Memory needed in bytes
+     */
+    public void setNeededReadMemBytes(int neededReadMemBytes) {
+        mNeededReadMemBytes = neededReadMemBytes;
+    }
+
+    /**
+     *  get writable memory needed by the app
+     *
+     * @return int - writable memory needed by the app
+     */
+    public int getNeededWriteMemBytes() {
+        return mNeededWriteMemBytes;
+    }
+
+    /**
+     * set writable memory needed by the app
+     *
+     * @param neededWriteMemBytes - writable memory needed by the
+     *                            app
+     */
+    public void setNeededWriteMemBytes(int neededWriteMemBytes) {
+        mNeededWriteMemBytes = neededWriteMemBytes;
+    }
+
+    /**
+     * get executable memory needed by the app
+     *
+     * @return int - executable memory needed by the app
+     */
+    public int getNeededExecMemBytes() {
+        return mNeededExecMemBytes;
+    }
+
+    /**
+     * set executable memory needed by the app
+     *
+     * @param neededExecMemBytes - executable memory needed by the
+     *                           app
+     */
+    public void setNeededExecMemBytes(int neededExecMemBytes) {
+        mNeededExecMemBytes = neededExecMemBytes;
+    }
+
+    /**
+     * Get the sensors needed by this app
+     *
+     * @return int[] all the required sensors needed by this app
+     */
+    public int[] getNeededSensors() {
+        return mNeededSensors;
+    }
+
+    /**
+     * set the sensors needed by this app
+     *
+     * @param neededSensors - all the sensors needed by this app
+     */
+    public void setNeededSensors(int[] neededSensors) {
+        mNeededSensors = neededSensors;
+    }
+
+    /**
+     * get the events generated by this app
+     *
+     * @return all the events that can be generated by this app
+     */
+    public int[] getOutputEvents() {
+        return mOutputEvents;
+    }
+
+    /**
+     * set the output events that can be generated by this app
+     *
+     * @param outputEvents - the events that may be generated by
+     *                     this app
+     */
+    public void setOutputEvents(int[] outputEvents) {
+        mOutputEvents = outputEvents;
+    }
+
+    /**
+     * get the context hub identifier
+     *
+     * @return int - system unique hub identifier
+     */
+    public int getContexthubId() {
+        return mContexthubId;
+    }
+
+    /**
+     * set the context hub identifier
+     *
+     * @param contexthubId - system wide unique identifier
+     */
+    public void setContexthubId(int contexthubId) {
+        mContexthubId = contexthubId;
+    }
+
+    /**
+     * get a handle to the nano app instance
+     *
+     * @return int - handle to this instance
+     */
+    public int getHandle() {
+        return mHandle;
+    }
+
+    /**
+     * set the handle for an app instance
+     *
+     * @param handle - handle to this instance
+     */
+    public void setHandle(int handle) {
+        mHandle = handle;
+    }
+
+
+    private NanoAppInstanceInfo(Parcel in) {
+        mPublisher = in.readString();
+        mName = in.readString();
+
+        mAppId = in.readInt();
+        mAppVersion = in.readInt();
+        mNeededReadMemBytes = in.readInt();
+        mNeededWriteMemBytes = in.readInt();
+        mNeededExecMemBytes = in.readInt();
+
+        int mNeededSensorsLength = in.readInt();
+        mNeededSensors = new int[mNeededSensorsLength];
+        in.readIntArray(mNeededSensors);
+
+        int mOutputEventsLength = in.readInt();
+        mOutputEvents = new int[mOutputEventsLength];
+        in.readIntArray(mOutputEvents);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mPublisher);
+        out.writeString(mName);
+        out.writeInt(mAppId);
+        out.writeInt(mAppVersion);
+        out.writeInt(mContexthubId);
+        out.writeInt(mNeededReadMemBytes);
+        out.writeInt(mNeededWriteMemBytes);
+        out.writeInt(mNeededExecMemBytes);
+
+        out.writeInt(mNeededSensors.length);
+        out.writeIntArray(mNeededSensors);
+
+        out.writeInt(mOutputEvents.length);
+        out.writeIntArray(mOutputEvents);
+
+    }
+
+    public static final Parcelable.Creator<NanoAppInstanceInfo> CREATOR
+            = new Parcelable.Creator<NanoAppInstanceInfo>() {
+        public NanoAppInstanceInfo createFromParcel(Parcel in) {
+            return new NanoAppInstanceInfo(in);
+        }
+
+        public NanoAppInstanceInfo[] newArray(int size) {
+            return new NanoAppInstanceInfo[size];
+        }
+    };
+}
diff --git a/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl b/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
index 2f6dbe7..597efa5 100644
--- a/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
+++ b/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
@@ -25,9 +25,12 @@
     /**
      * Called when the keyphrase is spoken.
      *
-     * @param data Optional trigger audio data, if it was requested and is available.
+     * @param recognitionEvent Object containing data relating to the
+     *                         recognition event such as trigger audio data, if it was requested
+     *                         and is available.
      */
-    void onDetected(in SoundTrigger.KeyphraseRecognitionEvent recognitionEvent);
+    void onDetected(in SoundTrigger.RecognitionEvent recognitionEvent);
+
     /**
      * Called when the detection fails due to an error.
      *
@@ -42,4 +45,4 @@
      * Called when the recognition is resumed after it was temporarily paused.
      */
     void onRecognitionResumed();
-}
\ No newline at end of file
+}
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.aidl b/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
index e16ea71..fec64ea 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.aidl
@@ -18,8 +18,11 @@
 
 parcelable SoundTrigger.ConfidenceLevel;
 parcelable SoundTrigger.Keyphrase;
+parcelable SoundTrigger.RecognitionEvent;
 parcelable SoundTrigger.KeyphraseRecognitionEvent;
+parcelable SoundTrigger.GenericSoundRecognitionEvent;
 parcelable SoundTrigger.KeyphraseRecognitionExtra;
 parcelable SoundTrigger.KeyphraseSoundModel;
+parcelable SoundTrigger.GenericSoundModel;
 parcelable SoundTrigger.ModuleProperties;
 parcelable SoundTrigger.RecognitionConfig;
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index d490409..882908a 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -195,6 +195,12 @@
         /** Keyphrase sound model */
         public static final int TYPE_KEYPHRASE = 0;
 
+        /**
+         * A generic sound model. Use this type only for non-keyphrase sound models such as
+         * ones that match a particular sound pattern.
+         */
+        public static final int TYPE_GENERIC_SOUND = 1;
+
         /** Unique sound model identifier */
         public final UUID uuid;
 
@@ -458,6 +464,63 @@
         }
     }
 
+
+    /*****************************************************************************
+     * A GenericSoundModel is a specialized {@link SoundModel} for non-voice sound
+     * patterns.
+     ****************************************************************************/
+    public static class GenericSoundModel extends SoundModel implements Parcelable {
+
+        public static final Parcelable.Creator<GenericSoundModel> CREATOR
+                = new Parcelable.Creator<GenericSoundModel>() {
+            public GenericSoundModel createFromParcel(Parcel in) {
+                return GenericSoundModel.fromParcel(in);
+            }
+
+            public GenericSoundModel[] newArray(int size) {
+                return new GenericSoundModel[size];
+            }
+        };
+
+        public GenericSoundModel(UUID uuid, UUID vendorUuid, byte[] data) {
+            super(uuid, vendorUuid, TYPE_GENERIC_SOUND, data);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        private static GenericSoundModel fromParcel(Parcel in) {
+            UUID uuid = UUID.fromString(in.readString());
+            UUID vendorUuid = null;
+            int length = in.readInt();
+            if (length >= 0) {
+                vendorUuid = UUID.fromString(in.readString());
+            }
+            byte[] data = in.readBlob();
+            return new GenericSoundModel(uuid, vendorUuid, data);
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(uuid.toString());
+            if (vendorUuid == null) {
+                dest.writeInt(-1);
+            } else {
+                dest.writeInt(vendorUuid.toString().length());
+                dest.writeString(vendorUuid.toString());
+            }
+            dest.writeBlob(data);
+        }
+
+        @Override
+        public String toString() {
+            return "GenericSoundModel [uuid=" + uuid + ", vendorUuid=" + vendorUuid
+                    + ", type=" + type + ", data=" + (data == null ? 0 : data.length) + "]";
+        }
+    }
+
     /**
      *  Modes for key phrase recognition
      */
@@ -1019,6 +1082,21 @@
     }
 
     /**
+     * Sub-class of RecognitionEvent specifically for sound-trigger based sound
+     * models(non-keyphrase). Currently does not contain any additional fields.
+     */
+    public static class GenericRecognitionEvent extends RecognitionEvent {
+        public GenericRecognitionEvent(int status, int soundModelHandle,
+                boolean captureAvailable, int captureSession, int captureDelayMs,
+                int capturePreambleMs, boolean triggerInData, AudioFormat captureFormat,
+                byte[] data) {
+            super(status, soundModelHandle, captureAvailable, captureSession,
+                    captureDelayMs, capturePreambleMs, triggerInData, captureFormat,
+                    data);
+        }
+    }
+
+    /**
      *  Status codes for {@link SoundModelEvent}
      */
     /** Sound Model was updated */
@@ -1118,7 +1196,7 @@
     public static final int SERVICE_STATE_DISABLED = 1;
 
     /**
-     * Returns a list of descriptors for all harware modules loaded.
+     * Returns a list of descriptors for all hardware modules loaded.
      * @param modules A ModuleProperties array where the list will be returned.
      * @return - {@link #STATUS_OK} in case of success
      *         - {@link #STATUS_ERROR} in case of unspecified error
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 8ab8991..2826882 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -19,16 +19,22 @@
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
+import android.annotation.CallSuper;
 import android.annotation.DrawableRes;
+import android.annotation.IntDef;
+import android.annotation.MainThread;
 import android.app.ActivityManager;
 import android.app.Dialog;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.database.ContentObserver;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.ResultReceiver;
 import android.os.SystemClock;
@@ -68,6 +74,8 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 /**
  * InputMethodService provides a standard implementation of an InputMethod,
@@ -634,6 +642,97 @@
     }
 
     /**
+     * A {@link ContentObserver} to monitor {@link Settings.Secure#SHOW_IME_WITH_HARD_KEYBOARD}.
+     *
+     * <p>Note that {@link Settings.Secure#SHOW_IME_WITH_HARD_KEYBOARD} is not a public API.
+     * Basically this functionality still needs to be considered as implementation details.</p>
+     */
+    @MainThread
+    private static final class SettingsObserver extends ContentObserver {
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef({
+                ShowImeWithHardKeyboardType.UNKNOWN,
+                ShowImeWithHardKeyboardType.FALSE,
+                ShowImeWithHardKeyboardType.TRUE,
+        })
+        private @interface ShowImeWithHardKeyboardType {
+            int UNKNOWN = 0;
+            int FALSE = 1;
+            int TRUE = 2;
+        }
+        @ShowImeWithHardKeyboardType
+        private int mShowImeWithHardKeyboard = ShowImeWithHardKeyboardType.UNKNOWN;
+
+        private final InputMethodService mService;
+
+        private SettingsObserver(InputMethodService service) {
+            super(new Handler(service.getMainLooper()));
+            mService = service;
+        }
+
+        /**
+         * A factory method that internally enforces two-phase initialization to make sure that the
+         * object reference will not be escaped until the object is properly constructed.
+         *
+         * <p>NOTE: Currently {@link SettingsObserver} is accessed only from main thread.  Hence
+         * this enforcement of two-phase initialization may be unnecessary at the moment.</p>
+         *
+         * @param service {@link InputMethodService} that needs to receive the callback.
+         * @return {@link SettingsObserver} that is already registered to
+         * {@link android.content.ContentResolver}. The caller must call
+         * {@link SettingsObserver#unregister()}.
+         */
+        public static SettingsObserver createAndRegister(InputMethodService service) {
+            final SettingsObserver observer = new SettingsObserver(service);
+            // The observer is properly constructed. Let's start accepting the event.
+            service.getContentResolver().registerContentObserver(
+                    Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD),
+                    false, observer);
+            return observer;
+        }
+
+        void unregister() {
+            mService.getContentResolver().unregisterContentObserver(this);
+        }
+
+        private boolean shouldShowImeWithHardKeyboard() {
+            // Lazily initialize as needed.
+            if (mShowImeWithHardKeyboard == ShowImeWithHardKeyboardType.UNKNOWN) {
+                mShowImeWithHardKeyboard = Settings.Secure.getInt(mService.getContentResolver(),
+                        Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0 ?
+                        ShowImeWithHardKeyboardType.TRUE : ShowImeWithHardKeyboardType.FALSE;
+            }
+            switch (mShowImeWithHardKeyboard) {
+                case ShowImeWithHardKeyboardType.TRUE:
+                    return true;
+                case ShowImeWithHardKeyboardType.FALSE:
+                    return false;
+                default:
+                    Log.e(TAG, "Unexpected mShowImeWithHardKeyboard=" + mShowImeWithHardKeyboard);
+                    return false;
+            }
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            final Uri showImeWithHardKeyboardUri =
+                    Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
+            if (showImeWithHardKeyboardUri.equals(uri)) {
+                mShowImeWithHardKeyboard = Settings.Secure.getInt(mService.getContentResolver(),
+                        Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0 ?
+                        ShowImeWithHardKeyboardType.TRUE : ShowImeWithHardKeyboardType.FALSE;
+                mService.updateInputViewShown();
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "SettingsObserver{mShowImeWithHardKeyboard=" + mShowImeWithHardKeyboard  + "}";
+        }
+    }
+    private SettingsObserver mSettingsObserver;
+
+    /**
      * You can call this to customize the theme used by your IME's window.
      * This theme should typically be one that derives from
      * {@link android.R.style#Theme_InputMethod}, which is the default theme
@@ -682,6 +781,7 @@
         super.setTheme(mTheme);
         super.onCreate();
         mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
+        mSettingsObserver = SettingsObserver.createAndRegister(this);
         // If the previous IME has occupied non-empty inset in the screen, we need to decide whether
         // we continue to use the same size of the inset or update it
         mShouldClearInsetOfPreviousIme = (mImm.getInputMethodWindowVisibleHeight() > 0);
@@ -764,6 +864,10 @@
             mWindow.getWindow().setWindowAnimations(0);
             mWindow.dismiss();
         }
+        if (mSettingsObserver != null) {
+            mSettingsObserver.unregister();
+            mSettingsObserver = null;
+        }
     }
 
     /**
@@ -1140,21 +1244,32 @@
     public boolean isInputViewShown() {
         return mIsInputViewShown && mWindowVisible;
     }
-    
+
     /**
-     * Override this to control when the soft input area should be shown to
-     * the user.  The default implementation only shows the input view when
-     * there is no hard keyboard or the keyboard is hidden.  If you change what
-     * this returns, you will need to call {@link #updateInputViewShown()}
-     * yourself whenever the returned value may have changed to have it
-     * re-evaluated and applied.
+     * Override this to control when the soft input area should be shown to the user.  The default
+     * implementation returns {@code false} when there is no hard keyboard or the keyboard is hidden
+     * unless the user shows an intention to use software keyboard.  If you change what this
+     * returns, you will need to call {@link #updateInputViewShown()} yourself whenever the returned
+     * value may have changed to have it re-evaluated and applied.
+     *
+     * <p>When you override this method, it is recommended to call
+     * {@code super.onEvaluateInputViewShown()} and return {@code true} when {@code true} is
+     * returned.</p>
      */
+    @CallSuper
     public boolean onEvaluateInputViewShown() {
+        if (mSettingsObserver == null) {
+            Log.w(TAG, "onEvaluateInputViewShown: mSettingsObserver must not be null here.");
+            return false;
+        }
+        if (mSettingsObserver.shouldShowImeWithHardKeyboard()) {
+            return true;
+        }
         Configuration config = getResources().getConfiguration();
         return config.keyboard == Configuration.KEYBOARD_NOKEYS
                 || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES;
     }
-    
+
     /**
      * Controls the visibility of the candidates display area.  By default
      * it is hidden.
@@ -2483,5 +2598,6 @@
                 + " touchableInsets=" + mTmpInsets.touchableInsets
                 + " touchableRegion=" + mTmpInsets.touchableRegion);
         p.println(" mShouldClearInsetOfPreviousIme=" + mShouldClearInsetOfPreviousIme);
+        p.println(" mSettingsObserver=" + mSettingsObserver);
     }
 }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 515e9a2..25b38c0 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -17,15 +17,18 @@
 
 import static com.android.internal.util.Preconditions.checkNotNull;
 
+import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.net.NetworkUtils;
 import android.os.Binder;
 import android.os.Build.VERSION_CODES;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -36,6 +39,7 @@
 import android.os.Messenger;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
 import android.os.ServiceManager;
 import android.provider.Settings;
 import android.telephony.SubscriptionManager;
@@ -46,12 +50,14 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.util.Protocol;
 
-import java.net.InetAddress;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.HashMap;
-
 import libcore.net.event.NetworkEventDispatcher;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.net.InetAddress;
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
 /**
  * Class that answers queries about the state of network connectivity. It also
  * notifies applications when network connectivity changes. Get an instance
@@ -335,6 +341,71 @@
     public static final String ACTION_PROMPT_UNVALIDATED = "android.net.conn.PROMPT_UNVALIDATED";
 
     /**
+     * Invalid tethering type.
+     * @see #startTethering(int, OnStartTetheringCallback, boolean)
+     * @hide
+     */
+    public static final int TETHERING_INVALID   = -1;
+
+    /**
+     * Wifi tethering type.
+     * @see #startTethering(int, OnStartTetheringCallback, boolean)
+     * @hide
+     */
+    @SystemApi
+    public static final int TETHERING_WIFI      = 0;
+
+    /**
+     * USB tethering type.
+     * @see #startTethering(int, OnStartTetheringCallback, boolean)
+     * @hide
+     */
+    @SystemApi
+    public static final int TETHERING_USB       = 1;
+
+    /**
+     * Bluetooth tethering type.
+     * @see #startTethering(int, OnStartTetheringCallback, boolean)
+     * @hide
+     */
+    @SystemApi
+    public static final int TETHERING_BLUETOOTH = 2;
+
+    /**
+     * Extra used for communicating with the TetherService. Includes the type of tethering to
+     * enable if any.
+     * @hide
+     */
+    public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
+
+    /**
+     * Extra used for communicating with the TetherService. Includes the type of tethering for
+     * which to cancel provisioning.
+     * @hide
+     */
+    public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
+
+    /**
+     * Extra used for communicating with the TetherService. True to schedule a recheck of tether
+     * provisioning.
+     * @hide
+     */
+    public static final String EXTRA_SET_ALARM = "extraSetAlarm";
+
+    /**
+     * Tells the TetherService to run a provision check now.
+     * @hide
+     */
+    public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
+
+    /**
+     * Extra used for communicating with the TetherService. Contains the {@link ResultReceiver}
+     * which will receive provisioning results. Can be left empty.
+     * @hide
+     */
+    public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
+
+    /**
      * The absence of a connection type.
      * @hide
      */
@@ -511,6 +582,7 @@
     private final Context mContext;
 
     private INetworkManagementService mNMService;
+    private INetworkPolicyManager mNPManager;
 
     /**
      * Tests if a given integer represents a valid network type.
@@ -686,6 +758,47 @@
     }
 
     /**
+     * Configures an always-on VPN connection through a specific application.
+     * This connection is automatically granted and persisted after a reboot.
+     *
+     * <p>The designated package should declare a {@link VpnService} in its
+     *    manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE},
+     *    otherwise the call will fail.
+     *
+     * @param userId The identifier of the user to set an always-on VPN for.
+     * @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.
+     * @hide
+     */
+    public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage) {
+        try {
+            return mService.setAlwaysOnVpnPackage(userId, vpnPackage);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Returns the package name of the currently set always-on VPN application.
+     * If there is no always-on VPN set, or the VPN is provided by the system instead
+     * of by an app, {@code null} will be returned.
+     *
+     * @return Package name of VPN controller responsible for always-on VPN,
+     *         or {@code null} if none is set.
+     * @hide
+     */
+    public String getAlwaysOnVpnPackageForUser(int userId) {
+        try {
+            return mService.getAlwaysOnVpnPackage(userId);
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
      * Returns details about the currently active default data network
      * for a given uid.  This is for internal use only to avoid spying
      * other apps.
@@ -898,6 +1011,24 @@
     }
 
     /**
+     * Gets the URL that should be used for resolving whether a captive portal is present.
+     * 1. This URL should respond with a 204 response to a GET request to indicate no captive
+     *    portal is present.
+     * 2. This URL must be HTTP as redirect responses are used to find captive portal
+     *    sign-in pages. Captive portals cannot respond to HTTPS requests with redirects.
+     *
+     * @hide
+     */
+    @SystemApi
+    public String getCaptivePortalServerUrl() {
+        try {
+            return mService.getCaptivePortalServerUrl();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
      * Tells the underlying networking system that the caller wants to
      * begin using the named feature. The interpretation of {@code feature}
      * is completely up to each networking implementation.
@@ -1058,7 +1189,7 @@
             return TYPE_NONE;
         }
 
-        // Do this only for SUPL, until GpsLocationProvider is fixed. http://b/25876485 .
+        // Do this only for SUPL, until GnssLocationProvider is fixed. http://b/25876485 .
         if (!netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) {
             // NOTE: if this causes app breakage, we should not just comment out this early return;
             // instead, we should make this early return conditional on the requesting app's target
@@ -1480,7 +1611,7 @@
         if (b != null) {
             try {
                 ITelephony it = ITelephony.Stub.asInterface(b);
-                int subId = SubscriptionManager.getDefaultDataSubId();
+                int subId = SubscriptionManager.getDefaultDataSubscriptionId();
                 Log.d("ConnectivityManager", "getMobileDataEnabled()+ subId=" + subId);
                 boolean retVal = it.getDataEnabled(subId);
                 Log.d("ConnectivityManager", "getMobileDataEnabled()- subId=" + subId
@@ -1611,7 +1742,7 @@
             // Have a provisioning app - must only let system apps (which check this app)
             // turn on tethering
             context.enforceCallingOrSelfPermission(
-                    android.Manifest.permission.CONNECTIVITY_INTERNAL, "ConnectivityService");
+                    android.Manifest.permission.TETHER_PRIVILEGED, "ConnectivityService");
         } else {
             int uid = Binder.getCallingUid();
             Settings.checkAndNoteWriteSettingsOperation(context, uid, Settings
@@ -1726,6 +1857,11 @@
      * or the ability to modify system settings as determined by
      * {@link android.provider.Settings.System#canWrite}.</p>
      *
+     * <p>WARNING: New clients should not use this function. The only usages should be in PanService
+     * and WifiStateMachine which need direct access. All other clients should use
+     * {@link #startTethering} and {@link #stopTethering} which encapsulate proper provisioning
+     * logic.</p>
+     *
      * @param iface the interface name to tether.
      * @return error a {@code TETHER_ERROR} value indicating success or failure type
      *
@@ -1747,6 +1883,11 @@
      * or the ability to modify system settings as determined by
      * {@link android.provider.Settings.System#canWrite}.</p>
      *
+     * <p>WARNING: New clients should not use this function. The only usages should be in PanService
+     * and WifiStateMachine which need direct access. All other clients should use
+     * {@link #startTethering} and {@link #stopTethering} which encapsulate proper provisioning
+     * logic.</p>
+     *
      * @param iface the interface name to untether.
      * @return error a {@code TETHER_ERROR} value indicating success or failure type
      *
@@ -1771,6 +1912,7 @@
      *
      * {@hide}
      */
+    @SystemApi
     public boolean isTetheringSupported() {
         try {
             return mService.isTetheringSupported();
@@ -1780,6 +1922,94 @@
     }
 
     /**
+     * Callback for use with {@link #startTethering} to find out whether tethering succeeded.
+     * @hide
+     */
+    @SystemApi
+    public static abstract class OnStartTetheringCallback {
+        /**
+         * Called when tethering has been successfully started.
+         */
+        public void onTetheringStarted() {};
+
+        /**
+         * Called when starting tethering failed.
+         */
+        public void onTetheringFailed() {};
+    }
+
+    /**
+     * Convenient overload for
+     * {@link #startTethering(int, boolean, OnStartTetheringCallback, Handler)} which passes a null
+     * handler to run on the current thread's {@link Looper}.
+     * @hide
+     */
+    @SystemApi
+    public void startTethering(int type, boolean showProvisioningUi,
+            final OnStartTetheringCallback callback) {
+        startTethering(type, showProvisioningUi, callback, null);
+    }
+
+    /**
+     * Runs tether provisioning for the given type if needed and then starts tethering if
+     * the check succeeds. If no carrier provisioning is required for tethering, tethering is
+     * enabled immediately. If provisioning fails, tethering will not be enabled. It also
+     * schedules tether provisioning re-checks if appropriate.
+     *
+     * @param type The type of tethering to start. Must be one of
+     *         {@link ConnectivityManager.TETHERING_WIFI},
+     *         {@link ConnectivityManager.TETHERING_USB}, or
+     *         {@link ConnectivityManager.TETHERING_BLUETOOTH}.
+     * @param showProvisioningUi a boolean indicating to show the provisioning app UI if there
+     *         is one. This should be true the first time this function is called and also any time
+     *         the user can see this UI. It gives users information from their carrier about the
+     *         check failing and how they can sign up for tethering if possible.
+     * @param callback an {@link OnStartTetheringCallback} which will be called to notify the caller
+     *         of the result of trying to tether.
+     * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+     * @hide
+     */
+    @SystemApi
+    public void startTethering(int type, boolean showProvisioningUi,
+            final OnStartTetheringCallback callback, Handler handler) {
+        ResultReceiver wrappedCallback = new ResultReceiver(handler) {
+            @Override
+            protected void onReceiveResult(int resultCode, Bundle resultData) {
+                if (resultCode == TETHER_ERROR_NO_ERROR) {
+                    callback.onTetheringStarted();
+                } else {
+                    callback.onTetheringFailed();
+                }
+            }
+        };
+        try {
+            mService.startTethering(type, wrappedCallback, showProvisioningUi);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Exception trying to start tethering.", e);
+            wrappedCallback.send(TETHER_ERROR_SERVICE_UNAVAIL, null);
+        }
+    }
+
+    /**
+     * Stops tethering for the given type. Also cancels any provisioning rechecks for that type if
+     * applicable.
+     *
+     * @param type The type of tethering to stop. Must be one of
+     *         {@link ConnectivityManager.TETHERING_WIFI},
+     *         {@link ConnectivityManager.TETHERING_USB}, or
+     *         {@link ConnectivityManager.TETHERING_BLUETOOTH}.
+     * @hide
+     */
+    @SystemApi
+    public void stopTethering(int type) {
+        try {
+            mService.stopTethering(type);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Exception trying to stop tethering.", e);
+        }
+    }
+
+    /**
      * Get the list of regular expressions that define any tetherable
      * USB network interfaces.  If USB tethering is not supported by the
      * device, this list should be empty.
@@ -1886,6 +2116,8 @@
     public static final int TETHER_ERROR_DISABLE_NAT_ERROR    = 9;
     /** {@hide} */
     public static final int TETHER_ERROR_IFACE_CFG_ERROR      = 10;
+    /** {@hide} */
+    public static final int TETHER_ERROR_PROVISION_FAILED     = 11;
 
     /**
      * Get a more detailed error code after a Tethering or Untethering
@@ -2938,7 +3170,7 @@
 
     // Checks whether the calling app can use the legacy routing API (startUsingNetworkFeature,
     // stopUsingNetworkFeature, requestRouteToHost), and if not throw UnsupportedOperationException.
-    // TODO: convert the existing system users (Tethering, GpsLocationProvider) to the new APIs and
+    // TODO: convert the existing system users (Tethering, GnssLocationProvider) to the new APIs and
     // remove these exemptions. Note that this check is not secure, and apps can still access these
     // functions by accessing ConnectivityService directly. However, it should be clear that doing
     // so is unsupported and may break in the future. http://b/22728205
@@ -2965,4 +3197,59 @@
         return NetworkUtils.bindProcessToNetworkForHostResolution(
                 network == null ? NETID_UNSET : network.netId);
     }
+
+    /**
+     * Device is not restricting metered network activity while application is running on
+     * background.
+     */
+    public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1;
+
+    /**
+     * Device is restricting metered network activity while application is running on background,
+     * but application is allowed to bypass it.
+     * <p>
+     * In this state, application should take action to mitigate metered network access.
+     * For example, a music streaming application should switch to a low-bandwidth bitrate.
+     */
+    public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2;
+
+    /**
+     * Device is restricting metered network activity while application is running on background.
+     * In this state, application should not try to use the network while running on background,
+     * because it would be denied.
+     */
+    public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = false, value = {
+            RESTRICT_BACKGROUND_STATUS_DISABLED,
+            RESTRICT_BACKGROUND_STATUS_WHITELISTED,
+            RESTRICT_BACKGROUND_STATUS_ENABLED,
+    })
+    public @interface RestrictBackgroundStatus {
+    }
+
+    private INetworkPolicyManager getNetworkPolicyManager() {
+        synchronized (this) {
+            if (mNPManager != null) {
+                return mNPManager;
+            }
+            mNPManager = INetworkPolicyManager.Stub.asInterface(ServiceManager
+                    .getService(Context.NETWORK_POLICY_SERVICE));
+            return mNPManager;
+        }
+    }
+
+    /**
+     * Determines if the calling application is subject to metered network restrictions while
+     * running on background.
+     */
+    public @RestrictBackgroundStatus int getRestrictBackgroundStatus() {
+        try {
+            return getNetworkPolicyManager().getRestrictBackgroundByCaller();
+        } catch (RemoteException e) {
+            return RESTRICT_BACKGROUND_STATUS_DISABLED;
+        }
+    }
 }
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index d4dd669..1a9c9ea 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -76,6 +76,10 @@
 
     boolean isTetheringSupported();
 
+    void startTethering(int type, in ResultReceiver receiver, boolean showProvisioningUi);
+
+    void stopTethering(int type);
+
     String[] getTetherableIfaces();
 
     String[] getTetheredIfaces();
@@ -117,6 +121,8 @@
     VpnInfo[] getAllVpnInfo();
 
     boolean updateLockdownVpn();
+    boolean setAlwaysOnVpnPackage(int userId, String packageName);
+    String getAlwaysOnVpnPackage(int userId);
 
     int checkMobileProvisioning(int suggestedTimeOutMs);
 
@@ -165,4 +171,6 @@
             in IBinder binder, String srcAddr, int srcPort, String dstAddr);
 
     void stopKeepalive(in Network network, int slot);
+
+    String getCaptivePortalServerUrl();
 }
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 7f5f377..a57fac3 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -52,6 +52,17 @@
     void setRestrictBackground(boolean restrictBackground);
     boolean getRestrictBackground();
 
+    /** Control which applications can be exempt from background data restrictions */
+    void addRestrictBackgroundWhitelistedUid(int uid);
+    void removeRestrictBackgroundWhitelistedUid(int uid);
+    int[] getRestrictBackgroundWhitelistedUids();
+    /** Gets the restrict background status based on the caller's UID:
+        1 - disabled
+        2 - whitelisted
+        3 - enabled
+    */
+    int getRestrictBackgroundByCaller();
+
     void setDeviceIdleMode(boolean enabled);
 
     NetworkQuotaInfo getNetworkQuotaInfo(in NetworkState state);
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 3bd12c0..e27c0fb 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -197,6 +197,19 @@
             (1 << NET_CAPABILITY_CAPTIVE_PORTAL);
 
     /**
+     * Network specifier for factories which want to match any network specifier
+     * (NS) in a request. Behavior:
+     * <li>Empty NS in request matches any network factory NS</li>
+     * <li>Empty NS in the network factory NS only matches a request with an
+     * empty NS</li>
+     * <li>"*" (this constant) NS in the network factory matches requests with
+     * any NS</li>
+     *
+     * @hide
+     */
+    public static final String MATCH_ALL_REQUESTS_NETWORK_SPECIFIER = "*";
+
+    /**
      * Network capabilities that are not allowed in NetworkRequests. This exists because the
      * NetworkFactory / NetworkAgent model does not deal well with the situation where a
      * capability's presence cannot be known in advance. If such a capability is requested, then we
@@ -596,7 +609,8 @@
     }
     private boolean satisfiedBySpecifier(NetworkCapabilities nc) {
         return (TextUtils.isEmpty(mNetworkSpecifier) ||
-                mNetworkSpecifier.equals(nc.mNetworkSpecifier));
+                mNetworkSpecifier.equals(nc.mNetworkSpecifier) ||
+                MATCH_ALL_REQUESTS_NETWORK_SPECIFIER.equals(nc.mNetworkSpecifier));
     }
     private boolean equalsSpecifier(NetworkCapabilities nc) {
         if (TextUtils.isEmpty(mNetworkSpecifier)) {
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 7da4818..f1edcbe 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -188,6 +188,10 @@
          *                         networks.
          */
         public Builder setNetworkSpecifier(String networkSpecifier) {
+            if (NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER.equals(networkSpecifier)) {
+                throw new IllegalArgumentException("Invalid network specifier - must not be '"
+                        + NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER + "'");
+            }
             mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
             return this;
         }
diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java
index ec76b8a..e555fa4 100644
--- a/core/java/android/net/NetworkScorerAppManager.java
+++ b/core/java/android/net/NetworkScorerAppManager.java
@@ -33,6 +33,7 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -90,13 +91,18 @@
      * @return the list of scorers, or the empty list if there are no valid scorers.
      */
     public static Collection<NetworkScorerAppData> getAllValidScorers(Context context) {
-        List<NetworkScorerAppData> scorers = new ArrayList<>();
+        // Network scorer apps can only run as the primary user so exit early if we're not the
+        // primary user.
+        if (UserHandle.getCallingUserId() != UserHandle.USER_SYSTEM) {
+            return Collections.emptyList();
+        }
 
+        List<NetworkScorerAppData> scorers = new ArrayList<>();
         PackageManager pm = context.getPackageManager();
         // Only apps installed under the primary user of the device can be scorers.
         // TODO: http://b/23422763
         List<ResolveInfo> receivers =
-                pm.queryBroadcastReceivers(SCORE_INTENT, 0 /* flags */, UserHandle.USER_SYSTEM);
+                pm.queryBroadcastReceiversAsUser(SCORE_INTENT, 0 /* flags */, UserHandle.USER_SYSTEM);
         for (ResolveInfo receiver : receivers) {
             // This field is a misnomer, see android.content.pm.ResolveInfo#activityInfo
             final ActivityInfo receiverInfo = receiver.activityInfo;
@@ -105,8 +111,9 @@
                 continue;
             }
             if (!permission.BROADCAST_NETWORK_PRIVILEGED.equals(receiverInfo.permission)) {
-                // Receiver doesn't require the BROADCAST_NETWORK_PRIVILEGED permission, which means
-                // anyone could trigger network scoring and flood the framework with score requests.
+                // Receiver doesn't require the BROADCAST_NETWORK_PRIVILEGED permission, which
+                // means anyone could trigger network scoring and flood the framework with score
+                // requests.
                 continue;
             }
             if (pm.checkPermission(permission.SCORE_NETWORKS, receiverInfo.packageName) !=
@@ -128,8 +135,8 @@
                 }
             }
 
-            // NOTE: loadLabel will attempt to load the receiver's label and fall back to the app
-            // label if none is present.
+            // 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));
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 77d7e0c..8919d51 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -50,7 +50,7 @@
     public static final int UID_ALL = -1;
     /** {@link #tag} value matching any tag. */
     public static final int TAG_ALL = -1;
-    /** {@link #set} value when all sets combined, not including debug sets. */
+    /** {@link #set} value for all sets combined, not including debug sets. */
     public static final int SET_ALL = -1;
     /** {@link #set} value where background data is accounted. */
     public static final int SET_DEFAULT = 0;
@@ -66,6 +66,13 @@
     /** {@link #tag} value for total data across all tags. */
     public static final int TAG_NONE = 0;
 
+    /** {@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;
+    /** {@link #set} value where roaming data is accounted. */
+    public static final int ROAMING_ROAMING = 1;
+
     // TODO: move fields to "mVariable" notation
 
     /**
@@ -79,6 +86,7 @@
     private int[] uid;
     private int[] set;
     private int[] tag;
+    private int[] roaming;
     private long[] rxBytes;
     private long[] rxPackets;
     private long[] txBytes;
@@ -90,6 +98,12 @@
         public int uid;
         public int set;
         public int tag;
+        /**
+         * Note that this is only populated w/ the default value when read from /proc or written
+         * to disk. We merge in the correct value when reporting this value to clients of
+         * getSummary().
+         */
+        public int roaming;
         public long rxBytes;
         public long rxPackets;
         public long txBytes;
@@ -107,10 +121,17 @@
 
         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,
+                    operations);
+        }
+
+        public Entry(String iface, int uid, int set, int tag, int roaming, long rxBytes,
+                long rxPackets, long txBytes, long txPackets, long operations) {
             this.iface = iface;
             this.uid = uid;
             this.set = set;
             this.tag = tag;
+            this.roaming = roaming;
             this.rxBytes = rxBytes;
             this.rxPackets = rxPackets;
             this.txBytes = txBytes;
@@ -142,6 +163,7 @@
             builder.append(" uid=").append(uid);
             builder.append(" set=").append(setToString(set));
             builder.append(" tag=").append(tagToString(tag));
+            builder.append(" roaming=").append(roamingToString(roaming));
             builder.append(" rxBytes=").append(rxBytes);
             builder.append(" rxPackets=").append(rxPackets);
             builder.append(" txBytes=").append(txBytes);
@@ -154,8 +176,8 @@
         public boolean equals(Object o) {
             if (o instanceof Entry) {
                 final Entry e = (Entry) o;
-                return uid == e.uid && set == e.set && tag == e.tag && rxBytes == e.rxBytes
-                        && rxPackets == e.rxPackets && txBytes == e.txBytes
+                return uid == e.uid && set == e.set && tag == e.tag && roaming == e.roaming
+                        && rxBytes == e.rxBytes && rxPackets == e.rxPackets && txBytes == e.txBytes
                         && txPackets == e.txPackets && operations == e.operations
                         && iface.equals(e.iface);
             }
@@ -172,6 +194,7 @@
             this.uid = new int[initialSize];
             this.set = new int[initialSize];
             this.tag = new int[initialSize];
+            this.roaming = new int[initialSize];
             this.rxBytes = new long[initialSize];
             this.rxPackets = new long[initialSize];
             this.txBytes = new long[initialSize];
@@ -184,6 +207,7 @@
             this.uid = EmptyArray.INT;
             this.set = EmptyArray.INT;
             this.tag = EmptyArray.INT;
+            this.roaming = EmptyArray.INT;
             this.rxBytes = EmptyArray.LONG;
             this.rxPackets = EmptyArray.LONG;
             this.txBytes = EmptyArray.LONG;
@@ -200,6 +224,7 @@
         uid = parcel.createIntArray();
         set = parcel.createIntArray();
         tag = parcel.createIntArray();
+        roaming = parcel.createIntArray();
         rxBytes = parcel.createLongArray();
         rxPackets = parcel.createLongArray();
         txBytes = parcel.createLongArray();
@@ -216,6 +241,7 @@
         dest.writeIntArray(uid);
         dest.writeIntArray(set);
         dest.writeIntArray(tag);
+        dest.writeIntArray(roaming);
         dest.writeLongArray(rxBytes);
         dest.writeLongArray(rxPackets);
         dest.writeLongArray(txBytes);
@@ -248,6 +274,13 @@
                 iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
     }
 
+    @VisibleForTesting
+    public NetworkStats addValues(String iface, int uid, int set, int tag, int roaming,
+            long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
+        return addValues(new Entry(
+                iface, uid, set, tag, roaming, rxBytes, rxPackets, txBytes, txPackets, operations));
+    }
+
     /**
      * Add new stats entry, copying from given {@link Entry}. The {@link Entry}
      * object can be recycled across multiple calls.
@@ -259,6 +292,7 @@
             uid = Arrays.copyOf(uid, newLength);
             set = Arrays.copyOf(set, newLength);
             tag = Arrays.copyOf(tag, newLength);
+            roaming = Arrays.copyOf(roaming, newLength);
             rxBytes = Arrays.copyOf(rxBytes, newLength);
             rxPackets = Arrays.copyOf(rxPackets, newLength);
             txBytes = Arrays.copyOf(txBytes, newLength);
@@ -271,6 +305,7 @@
         uid[size] = entry.uid;
         set[size] = entry.set;
         tag[size] = entry.tag;
+        roaming[size] = entry.roaming;
         rxBytes[size] = entry.rxBytes;
         rxPackets[size] = entry.rxPackets;
         txBytes[size] = entry.txBytes;
@@ -290,6 +325,7 @@
         entry.uid = uid[i];
         entry.set = set[i];
         entry.tag = tag[i];
+        entry.roaming = roaming[i];
         entry.rxBytes = rxBytes[i];
         entry.rxPackets = rxPackets[i];
         entry.txBytes = txBytes[i];
@@ -327,22 +363,23 @@
     public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
             long txBytes, long txPackets, long operations) {
         return combineValues(
-                iface, uid, SET_DEFAULT, tag, rxBytes, rxPackets, txBytes, txPackets, operations);
+                iface, uid, SET_DEFAULT, tag, rxBytes, rxPackets, txBytes,
+                txPackets, operations);
     }
 
-    public NetworkStats combineValues(String iface, int uid, int set, int tag, long rxBytes,
-            long rxPackets, long txBytes, long txPackets, long operations) {
+    public NetworkStats combineValues(String iface, int uid, int set, int tag,
+            long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
         return combineValues(new Entry(
                 iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
     }
 
     /**
      * Combine given values with an existing row, or create a new row if
-     * {@link #findIndex(String, int, int, int)} is unable to find match. Can
+     * {@link #findIndex(String, int, int, int, int)} is unable to find match. Can
      * also be used to subtract values from existing rows.
      */
     public NetworkStats combineValues(Entry entry) {
-        final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag);
+        final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.roaming);
         if (i == -1) {
             // only create new entry when positive contribution
             addValues(entry);
@@ -370,10 +407,10 @@
     /**
      * Find first stats index that matches the requested parameters.
      */
-    public int findIndex(String iface, int uid, int set, int tag) {
+    public int findIndex(String iface, int uid, int set, int tag, int roaming) {
         for (int i = 0; i < size; i++) {
             if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
-                    && Objects.equals(iface, this.iface[i])) {
+                    && roaming == this.roaming[i] && Objects.equals(iface, this.iface[i])) {
                 return i;
             }
         }
@@ -385,7 +422,8 @@
      * search around the hinted index as an optimization.
      */
     @VisibleForTesting
-    public int findIndexHinted(String iface, int uid, int set, int tag, int hintIndex) {
+    public int findIndexHinted(String iface, int uid, int set, int tag, int roaming,
+            int hintIndex) {
         for (int offset = 0; offset < size; offset++) {
             final int halfOffset = offset / 2;
 
@@ -398,7 +436,7 @@
             }
 
             if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
-                    && Objects.equals(iface, this.iface[i])) {
+                    && roaming == this.roaming[i] && Objects.equals(iface, this.iface[i])) {
                 return i;
             }
         }
@@ -412,7 +450,7 @@
      */
     public void spliceOperationsFrom(NetworkStats stats) {
         for (int i = 0; i < size; i++) {
-            final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i]);
+            final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], roaming[i]);
             if (j == -1) {
                 operations[i] = 0;
             } else {
@@ -502,6 +540,7 @@
         entry.uid = limitUid;
         entry.set = SET_ALL;
         entry.tag = TAG_NONE;
+        entry.roaming = ROAMING_ALL;
         entry.rxBytes = 0;
         entry.rxPackets = 0;
         entry.txBytes = 0;
@@ -596,9 +635,11 @@
             entry.uid = left.uid[i];
             entry.set = left.set[i];
             entry.tag = left.tag[i];
+            entry.roaming = left.roaming[i];
 
             // find remote row that matches, and subtract
-            final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, i);
+            final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag,
+                    entry.roaming, i);
             if (j == -1) {
                 // newly appearing row, return entire value
                 entry.rxBytes = left.rxBytes[i];
@@ -644,6 +685,7 @@
         entry.uid = UID_ALL;
         entry.set = SET_ALL;
         entry.tag = TAG_NONE;
+        entry.roaming = ROAMING_ALL;
         entry.operations = 0L;
 
         for (int i = 0; i < size; i++) {
@@ -672,6 +714,7 @@
         entry.iface = IFACE_ALL;
         entry.set = SET_ALL;
         entry.tag = TAG_NONE;
+        entry.roaming = ROAMING_ALL;
 
         for (int i = 0; i < size; i++) {
             // skip specific tags, since already counted in TAG_NONE
@@ -717,6 +760,7 @@
             pw.print(" uid="); pw.print(uid[i]);
             pw.print(" set="); pw.print(setToString(set[i]));
             pw.print(" tag="); pw.print(tagToString(tag[i]));
+            pw.print(" roaming="); pw.print(roamingToString(roaming[i]));
             pw.print(" rxBytes="); pw.print(rxBytes[i]);
             pw.print(" rxPackets="); pw.print(rxPackets[i]);
             pw.print(" txBytes="); pw.print(txBytes[i]);
@@ -783,6 +827,22 @@
         return "0x" + Integer.toHexString(tag);
     }
 
+    /**
+     * Return text description of {@link #roaming} value.
+     */
+    public static String roamingToString(int roaming) {
+        switch (roaming) {
+            case ROAMING_ALL:
+                return "ALL";
+            case ROAMING_DEFAULT:
+                return "DEFAULT";
+            case ROAMING_ROAMING:
+                return "ROAMING";
+            default:
+                return "UNKNOWN";
+        }
+    }
+
     @Override
     public String toString() {
         final CharArrayWriter writer = new CharArrayWriter();
@@ -932,6 +992,7 @@
                 tmpEntry.uid = uid[i];
                 tmpEntry.tag = tag[i];
                 tmpEntry.set = set[i];
+                tmpEntry.roaming = roaming[i];
                 combineValues(tmpEntry);
                 if (tag[i] == TAG_NONE) {
                     moved.add(tmpEntry);
@@ -950,16 +1011,24 @@
         moved.set = SET_DBG_VPN_OUT;
         moved.tag = TAG_NONE;
         moved.iface = underlyingIface;
+        moved.roaming = ROAMING_ALL;
         combineValues(moved);
 
         // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than
         // the TAG_NONE traffic.
-        int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE);
+        //
+        // Relies on the fact that the underlying traffic only has state ROAMING_DEFAULT, 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);
         if (idxVpnBackground != -1) {
             tunSubtract(idxVpnBackground, this, moved);
         }
 
-        int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE);
+        int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE,
+                ROAMING_DEFAULT);
         if (idxVpnForeground != -1) {
             tunSubtract(idxVpnForeground, this, moved);
         }
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 961a3f4..940565f 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -26,6 +26,7 @@
 import android.nfc.INfcAdapterExtras;
 import android.nfc.INfcTag;
 import android.nfc.INfcCardEmulation;
+import android.nfc.INfcFCardEmulation;
 import android.nfc.INfcUnlockHandler;
 import android.os.Bundle;
 
@@ -36,6 +37,7 @@
 {
     INfcTag getNfcTagInterface();
     INfcCardEmulation getNfcCardEmulationInterface();
+    INfcFCardEmulation getNfcFCardEmulationInterface();
     INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg);
 
     int getState();
diff --git a/core/java/android/nfc/INfcFCardEmulation.aidl b/core/java/android/nfc/INfcFCardEmulation.aidl
new file mode 100644
index 0000000..124bfac
--- /dev/null
+++ b/core/java/android/nfc/INfcFCardEmulation.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc;
+
+import android.content.ComponentName;
+import android.nfc.cardemulation.NfcFServiceInfo;
+
+/**
+ * @hide
+ */
+interface INfcFCardEmulation
+{
+    String getSystemCodeForService(int userHandle, in ComponentName service);
+    boolean registerSystemCodeForService(int userHandle, in ComponentName service, String systemCode);
+    boolean removeSystemCodeForService(int userHandle, in ComponentName service);
+    String getNfcid2ForService(int userHandle, in ComponentName service);
+    boolean setNfcid2ForService(int userHandle, in ComponentName service, String nfcid2);
+    boolean enableNfcFForegroundService(in ComponentName service);
+    boolean disableNfcFForegroundService();
+    List<NfcFServiceInfo> getNfcFServices(int userHandle);
+    int getMaxNumOfRegisterableSystemCodes();
+}
diff --git a/core/java/android/nfc/INfcTag.aidl b/core/java/android/nfc/INfcTag.aidl
index 3ac1dcc..26d2bec 100644
--- a/core/java/android/nfc/INfcTag.aidl
+++ b/core/java/android/nfc/INfcTag.aidl
@@ -25,13 +25,13 @@
  */
 interface INfcTag
 {
-    int close(int nativeHandle);
     int connect(int nativeHandle, int technology);
     int reconnect(int nativeHandle);
     int[] getTechList(int nativeHandle);
     boolean isNdef(int nativeHandle);
     boolean isPresent(int nativeHandle);
     TransceiveResult transceive(int nativeHandle, in byte[] data, boolean raw);
+    boolean done(int nativeHandle, int debounceMs);
 
     NdefMessage ndefRead(int nativeHandle);
     int ndefWrite(int nativeHandle, in NdefMessage msg);
diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java
index d619c0a..c7d4c65 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/core/java/android/nfc/NfcActivityManager.java
@@ -371,40 +371,44 @@
             flags = state.flags;
             activity = state.activity;
         }
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            // Make callbacks without lock
+            if (ndefCallback != null) {
+                message = ndefCallback.createNdefMessage(event);
+            }
+            if (urisCallback != null) {
+                uris = urisCallback.createBeamUris(event);
+                if (uris != null) {
+                    ArrayList<Uri> validUris = new ArrayList<Uri>();
+                    for (Uri uri : uris) {
+                        if (uri == null) {
+                            Log.e(TAG, "Uri not allowed to be null.");
+                            continue;
+                        }
+                        String scheme = uri.getScheme();
+                        if (scheme == null || (!scheme.equalsIgnoreCase("file") &&
+                                !scheme.equalsIgnoreCase("content"))) {
+                            Log.e(TAG, "Uri needs to have " +
+                                    "either scheme file or scheme content");
+                            continue;
+                        }
+                        uri = ContentProvider.maybeAddUserId(uri, UserHandle.myUserId());
+                        validUris.add(uri);
+                    }
 
-        // Make callbacks without lock
-        if (ndefCallback != null) {
-            message  = ndefCallback.createNdefMessage(event);
-        }
-        if (urisCallback != null) {
-            uris = urisCallback.createBeamUris(event);
-            if (uris != null) {
-                ArrayList<Uri> validUris = new ArrayList<Uri>();
-                for (Uri uri : uris) {
-                    if (uri == null) {
-                        Log.e(TAG, "Uri not allowed to be null.");
-                        continue;
-                    }
-                    String scheme = uri.getScheme();
-                    if (scheme == null || (!scheme.equalsIgnoreCase("file") &&
-                            !scheme.equalsIgnoreCase("content"))) {
-                        Log.e(TAG, "Uri needs to have " +
-                                "either scheme file or scheme content");
-                        continue;
-                    }
-                    uri = ContentProvider.maybeAddUserId(uri, UserHandle.myUserId());
-                    validUris.add(uri);
+                    uris = validUris.toArray(new Uri[validUris.size()]);
                 }
-
-                uris = validUris.toArray(new Uri[validUris.size()]);
             }
-        }
-        if (uris != null && uris.length > 0) {
-            for (Uri uri : uris) {
-                // Grant the NFC process permission to read these URIs
-                activity.grantUriPermission("com.android.nfc", uri,
-                        Intent.FLAG_GRANT_READ_URI_PERMISSION);
+            if (uris != null && uris.length > 0) {
+                for (Uri uri : uris) {
+                    // Grant the NFC process permission to read these URIs
+                    activity.grantUriPermission("com.android.nfc", uri,
+                            Intent.FLAG_GRANT_READ_URI_PERMISSION);
+                }
             }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
         return new BeamShareData(message, uris, new UserHandle(UserHandle.myUserId()), flags);
     }
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index ff6eb40..acd780d 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -294,6 +294,7 @@
     static INfcAdapter sService;
     static INfcTag sTagService;
     static INfcCardEmulation sCardEmulationService;
+    static INfcFCardEmulation sNfcFCardEmulationService;
 
     /**
      * The NfcAdapter object for each application context.
@@ -452,6 +453,13 @@
                 throw new UnsupportedOperationException();
             }
 
+            try {
+                sNfcFCardEmulationService = sService.getNfcFCardEmulationInterface();
+            } catch (RemoteException e) {
+                Log.e(TAG, "could not retrieve NFC-F card emulation service");
+                throw new UnsupportedOperationException();
+            }
+
             sIsInitialized = true;
         }
         if (context == null) {
@@ -571,6 +579,15 @@
     }
 
     /**
+     * Returns the binder interface to the NFC-F card emulation service.
+     * @hide
+     */
+    public INfcFCardEmulation getNfcFCardEmulationService() {
+        isEnabled();
+        return sNfcFCardEmulationService;
+    }
+
+    /**
      * NFC service dead - attempt best effort recovery
      * @hide
      */
@@ -601,6 +618,12 @@
             Log.e(TAG, "could not retrieve NFC card emulation service during service recovery");
         }
 
+        try {
+            sNfcFCardEmulationService = service.getNfcFCardEmulationInterface();
+        } catch (RemoteException ee) {
+            Log.e(TAG, "could not retrieve NFC-F card emulation service during service recovery");
+        }
+
         return;
     }
 
diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java
index 154d5a1..40d5a8db 100644
--- a/core/java/android/nfc/Tag.java
+++ b/core/java/android/nfc/Tag.java
@@ -214,6 +214,42 @@
         return techIntList;
     }
 
+    /**
+     * Signals that you are no longer interested in communicating with this tag
+     * for as long as it remains in range.
+     *
+     * All future attempted communication to this tag will fail with {@link IOException}.
+     * The NFC controller will be put in a low-power polling mode, allowing the device
+     * to save power in cases where it's "attached" to a tag all the time (eg a tag in
+     * car dock).
+     *
+     * Additionally the debounceMs parameter allows you to specify for how long the tag needs
+     * to have gone out of range, before it will be dispatched again.
+     *
+     * Note: the NFC controller typically polls at a pretty slow interval (100 - 500 ms).
+     * This means that if the tag repeatedly goes in and out of range (for example, in
+     * case of a flaky connection), and the controller happens to poll every time the
+     * tag is out of range, it *will* re-dispatch the tag after debounceMs, despite the tag
+     * having been "in range" during the interval.
+     *
+     * Note 2: if a tag with another UID is detected after this API is called, its effect
+     * will be cancelled; if this tag shows up before the amount of time specified in
+     * debounceMs, it will be dispatched again.
+     *
+     * Note 3: some tags have a random UID, in which case this API won't work.
+     *
+     * @param debounceMs minimum amount of time the tag needs to be out of range before being
+     *                   dispatched again.
+     * @return false if the Tag couldn't be found (or has gone out of range), true otherwise
+     */
+    public boolean done(int debounceMs) {
+        try {
+            return mTagService.done(getServiceHandle(), debounceMs);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
     private static HashMap<String, Integer> getTechStringToCodeMap() {
         HashMap<String, Integer> techStringToCodeMap = new HashMap<String, Integer>();
 
diff --git a/core/java/android/nfc/cardemulation/HostNfcFService.java b/core/java/android/nfc/cardemulation/HostNfcFService.java
new file mode 100644
index 0000000..273ddeb
--- /dev/null
+++ b/core/java/android/nfc/cardemulation/HostNfcFService.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc.cardemulation;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * <p>HostNfcFService is a convenience {@link Service} class that can be
+ * extended to emulate an NFC-F card inside an Android service component.
+ */
+public abstract class HostNfcFService extends Service {
+    /**
+     * The {@link Intent} action that must be declared as handled by the service.
+     */
+    @SdkConstant(SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE =
+            "android.nfc.cardemulation.action.HOST_NFCF_SERVICE";
+
+    /**
+     * The name of the meta-data element that contains
+     * more information about this service.
+     */
+    public static final String SERVICE_META_DATA =
+            "android.nfc.cardemulation.host_nfcf_service";
+
+    /**
+     * Reason for {@link #onDeactivated(int)}.
+     * Indicates deactivation was due to the NFC link
+     * being lost.
+     */
+    public static final int DEACTIVATION_LINK_LOSS = 0;
+
+    static final String TAG = "NfcFService";
+
+    /**
+     * MSG_COMMAND_PACKET is sent by NfcService when
+     * a NFC-F command packet has been received.
+     *
+     * @hide
+     */
+    public static final int MSG_COMMAND_PACKET = 0;
+
+    /**
+     * MSG_RESPONSE_PACKET is sent to NfcService to send
+     * a response packet back to the remote device.
+     *
+     * @hide
+     */
+    public static final int MSG_RESPONSE_PACKET = 1;
+
+    /**
+     * MSG_DEACTIVATED is sent by NfcService when
+     * the current session is finished; because
+     * the NFC link was deactivated.
+     *
+     * @hide
+     */
+    public static final int MSG_DEACTIVATED = 2;
+
+   /**
+     * @hide
+     */
+    public static final String KEY_DATA = "data";
+
+    /**
+     * @hide
+     */
+    public static final String KEY_MESSENGER = "messenger";
+
+    /**
+     * Messenger interface to NfcService for sending responses.
+     * Only accessed on main thread by the message handler.
+     *
+     * @hide
+     */
+    Messenger mNfcService = null;
+
+    final Messenger mMessenger = new Messenger(new MsgHandler());
+
+    final class MsgHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+            case MSG_COMMAND_PACKET:
+                Bundle dataBundle = msg.getData();
+                if (dataBundle == null) {
+                    return;
+                }
+                if (mNfcService == null) mNfcService = msg.replyTo;
+
+                byte[] packet = dataBundle.getByteArray(KEY_DATA);
+                if (packet != null) {
+                    byte[] responsePacket = processNfcFPacket(packet, null);
+                    if (responsePacket != null) {
+                        if (mNfcService == null) {
+                            Log.e(TAG, "Response not sent; service was deactivated.");
+                            return;
+                        }
+                        Message responseMsg = Message.obtain(null, MSG_RESPONSE_PACKET);
+                        Bundle responseBundle = new Bundle();
+                        responseBundle.putByteArray(KEY_DATA, responsePacket);
+                        responseMsg.setData(responseBundle);
+                        responseMsg.replyTo = mMessenger;
+                        try {
+                            mNfcService.send(responseMsg);
+                        } catch (RemoteException e) {
+                            Log.e("TAG", "Response not sent; RemoteException calling into " +
+                                    "NfcService.");
+                        }
+                    }
+                } else {
+                    Log.e(TAG, "Received MSG_COMMAND_PACKET without data.");
+                }
+                break;
+            case MSG_RESPONSE_PACKET:
+                if (mNfcService == null) {
+                    Log.e(TAG, "Response not sent; service was deactivated.");
+                    return;
+                }
+                try {
+                    msg.replyTo = mMessenger;
+                    mNfcService.send(msg);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "RemoteException calling into NfcService.");
+                }
+                break;
+            case MSG_DEACTIVATED:
+                // Make sure we won't call into NfcService again
+                mNfcService = null;
+                onDeactivated(msg.arg1);
+                break;
+            default:
+                super.handleMessage(msg);
+            }
+        }
+    }
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        return mMessenger.getBinder();
+    }
+
+    /**
+     * Sends a response packet back to the remote device.
+     *
+     * <p>Note: this method may be called from any thread and will not block.
+     * @param responsePacket A byte-array containing the response packet.
+     */
+    public final void sendResponsePacket(byte[] responsePacket) {
+        Message responseMsg = Message.obtain(null, MSG_RESPONSE_PACKET);
+        Bundle dataBundle = new Bundle();
+        dataBundle.putByteArray(KEY_DATA, responsePacket);
+        responseMsg.setData(dataBundle);
+        try {
+            mMessenger.send(responseMsg);
+        } catch (RemoteException e) {
+            Log.e("TAG", "Local messenger has died.");
+        }
+    }
+
+    /**
+     * <p>This method will be called when a NFC-F packet has been received
+     * from a remote device. A response packet can be provided directly
+     * by returning a byte-array in this method. Note that in general
+     * response packets must be sent as quickly as possible, given the fact
+     * that the user is likely holding his device over an NFC reader
+     * when this method is called.
+     *
+     * <p class="note">This method is running on the main thread of your application.
+     * If you cannot return a response packet immediately, return null
+     * and use the {@link #sendResponsePacket(byte[])} method later.
+     *
+     * @param commandPacket The NFC-F packet that was received from the remote device
+     * @param extras A bundle containing extra data. May be null.
+     * @return a byte-array containing the response packet, or null if no
+     *         response packet can be sent at this point.
+     */
+    public abstract byte[] processNfcFPacket(byte[] commandPacket, Bundle extras);
+
+    /**
+     * This method will be called in following possible scenarios:
+     * <li>The NFC link has been lost
+     * @param reason {@link #DEACTIVATION_LINK_LOSS}
+     */
+    public abstract void onDeactivated(int reason);
+}
diff --git a/core/java/android/nfc/cardemulation/NfcFCardEmulation.java b/core/java/android/nfc/cardemulation/NfcFCardEmulation.java
new file mode 100644
index 0000000..d61ac02
--- /dev/null
+++ b/core/java/android/nfc/cardemulation/NfcFCardEmulation.java
@@ -0,0 +1,470 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc.cardemulation;
+
+import android.app.Activity;
+import android.app.ActivityThread;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.nfc.INfcFCardEmulation;
+import android.nfc.NfcAdapter;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * This class can be used to query the state of
+ * NFC-F card emulation services.
+ *
+ * For a general introduction into NFC card emulation,
+ * please read the <a href="{@docRoot}guide/topics/connectivity/nfc/hce.html">
+ * NFC card emulation developer guide</a>.</p>
+ *
+ * <p class="note">Use of this class requires the
+ * {@link PackageManager#FEATURE_NFC_HOST_CARD_EMULATION_NFCF}
+ * to be present on the device.
+ */
+public final class NfcFCardEmulation {
+    static final String TAG = "NfcFCardEmulation";
+
+    static boolean sIsInitialized = false;
+    static HashMap<Context, NfcFCardEmulation> sCardEmus = new HashMap<Context, NfcFCardEmulation>();
+    static INfcFCardEmulation sService;
+
+    final Context mContext;
+
+    private NfcFCardEmulation(Context context, INfcFCardEmulation service) {
+        mContext = context.getApplicationContext();
+        sService = service;
+    }
+
+    /**
+     * Helper to get an instance of this class.
+     *
+     * @param adapter A reference to an NfcAdapter object.
+     * @return
+     */
+    public static synchronized NfcFCardEmulation getInstance(NfcAdapter adapter) {
+        if (adapter == null) throw new NullPointerException("NfcAdapter is null");
+        Context context = adapter.getContext();
+        if (context == null) {
+            Log.e(TAG, "NfcAdapter context is null.");
+            throw new UnsupportedOperationException();
+        }
+        if (!sIsInitialized) {
+            IPackageManager pm = ActivityThread.getPackageManager();
+            if (pm == null) {
+                Log.e(TAG, "Cannot get PackageManager");
+                throw new UnsupportedOperationException();
+            }
+            try {
+                if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF)) {
+                    Log.e(TAG, "This device does not support NFC-F card emulation");
+                    throw new UnsupportedOperationException();
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "PackageManager query failed.");
+                throw new UnsupportedOperationException();
+            }
+            sIsInitialized = true;
+        }
+        NfcFCardEmulation manager = sCardEmus.get(context);
+        if (manager == null) {
+            // Get card emu service
+            INfcFCardEmulation service = adapter.getNfcFCardEmulationService();
+            if (service == null) {
+                Log.e(TAG, "This device does not implement the INfcFCardEmulation interface.");
+                throw new UnsupportedOperationException();
+            }
+            manager = new NfcFCardEmulation(context, service);
+            sCardEmus.put(context, manager);
+        }
+        return manager;
+    }
+
+    /**
+     * Retrieves the current System Code for the specified service.
+     *
+     * <p>Before calling {@link #registerSystemCodeForService(ComponentName, String)},
+     * the System Code contained in the Manifest file is returned. After calling
+     * {@link #registerSystemCodeForService(ComponentName, String)}, the System Code
+     * registered there is returned. After calling
+     * {@link #removeSystemCodeForService(ComponentName)}, "null" is returned.
+     *
+     * @param service The component name of the service
+     * @return the current System Code
+     */
+    public String getSystemCodeForService(ComponentName service) {
+        if (service == null) {
+            throw new NullPointerException("service is null");
+        }
+        try {
+            return sService.getSystemCodeForService(UserHandle.myUserId(), service);
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return null;
+            }
+            try {
+                return sService.getSystemCodeForService(UserHandle.myUserId(), service);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return null;
+            }
+        }
+    }
+
+    /**
+     * Registers a System Code for the specified service.
+     *
+     * <p>The System Code must be in range from "4000" to "4FFF" (excluding "4*FF").
+     *
+     * <p>If a System Code was previously registered for this service
+     * (either statically through the manifest, or dynamically by using this API),
+     * it will be replaced with this one.
+     *
+     * <p>Even if the same System Code is already registered for another service,
+     * this method succeeds in registering the System Code.
+     *
+     * <p>Note that you can only register a System Code for a service that
+     * is running under the same UID as the caller of this API. Typically
+     * this means you need to call this from the same
+     * package as the service itself, though UIDs can also
+     * be shared between packages using shared UIDs.
+     *
+     * @param service The component name of the service
+     * @param systemCode The System Code to be registered
+     * @return whether the registration was successful.
+     */
+    public boolean registerSystemCodeForService(ComponentName service, String systemCode) {
+        if (service == null || systemCode == null) {
+            throw new NullPointerException("service or systemCode is null");
+        }
+        try {
+            return sService.registerSystemCodeForService(UserHandle.myUserId(),
+                    service, systemCode);
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return false;
+            }
+            try {
+                return sService.registerSystemCodeForService(UserHandle.myUserId(),
+                        service, systemCode);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Removes a registered System Code for the specified service.
+     *
+     * @param service The component name of the service
+     * @return whether the System Code was successfully removed.
+     */
+    public boolean removeSystemCodeForService(ComponentName service) {
+        if (service == null) {
+            throw new NullPointerException("service is null");
+        }
+        try {
+            return sService.removeSystemCodeForService(UserHandle.myUserId(), service);
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return false;
+            }
+            try {
+                return sService.removeSystemCodeForService(UserHandle.myUserId(), service);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Retrieves the current NFCID2 for the specified service.
+     *
+     * <p>Before calling {@link #setNfcid2ForService(ComponentName, String)},
+     * the NFCID2 contained in the Manifest file is returned. If "random" is specified
+     * in the Manifest file, a random number assigned by the system at installation time
+     * is returned. After setting an NFCID2
+     * with {@link #setNfcid2ForService(ComponentName, String)}, this NFCID2 is returned.
+     *
+     * @param service The component name of the service
+     * @return the current NFCID2
+     */
+    public String getNfcid2ForService(ComponentName service) {
+        if (service == null) {
+            throw new NullPointerException("service is null");
+        }
+        try {
+            return sService.getNfcid2ForService(UserHandle.myUserId(), service);
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return null;
+            }
+            try {
+                return sService.getNfcid2ForService(UserHandle.myUserId(), service);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return null;
+            }
+        }
+    }
+
+    /**
+     * Set a NFCID2 for the specified service.
+     *
+     * <p>The NFCID2 must be in range from "02FE000000000000" to "02FEFFFFFFFFFFFF".
+     *
+     * <p>If a NFCID2 was previously set for this service
+     * (either statically through the manifest, or dynamically by using this API),
+     * it will be replaced.
+     *
+     * <p>Note that you can only set the NFCID2 for a service that
+     * is running under the same UID as the caller of this API. Typically
+     * this means you need to call this from the same
+     * package as the service itself, though UIDs can also
+     * be shared between packages using shared UIDs.
+     *
+     * @param service The component name of the service
+     * @param nfcid2 The NFCID2 to be registered
+     * @return whether the setting was successful.
+     */
+    public boolean setNfcid2ForService(ComponentName service, String nfcid2) {
+        if (service == null || nfcid2 == null) {
+            throw new NullPointerException("service or nfcid2 is null");
+        }
+        try {
+            return sService.setNfcid2ForService(UserHandle.myUserId(),
+                    service, nfcid2);
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return false;
+            }
+            try {
+                return sService.setNfcid2ForService(UserHandle.myUserId(),
+                        service, nfcid2);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Allows a foreground application to specify which card emulation service
+     * should be enabled while a specific Activity is in the foreground.
+     *
+     * <p>The specified HCE-F service is only enabled when the corresponding application is
+     * in the foreground and this method has been called. When the application is moved to
+     * the background, {@link #disableNfcFForegroundService(Activity)} is called, or
+     * NFCID2 or System Code is replaced, the HCE-F service is disabled.
+     *
+     * <p>The specified Activity must currently be in resumed state. A good
+     * paradigm is to call this method in your {@link Activity#onResume}, and to call
+     * {@link #disableNfcFForegroundService(Activity)} in your {@link Activity#onPause}.
+     *
+     * <p>Note that this preference is not persisted by the OS, and hence must be
+     * called every time the Activity is resumed.
+     *
+     * @param activity The activity which prefers this service to be invoked
+     * @param service The service to be preferred while this activity is in the foreground
+     * @return whether the registration was successful
+     */
+    public boolean enableNfcFForegroundService(Activity activity, ComponentName service) {
+        if (activity == null || service == null) {
+            throw new NullPointerException("activity or service is null");
+        }
+        // Verify the activity is in the foreground before calling into NfcService
+        if (!activity.isResumed()) {
+            throw new IllegalArgumentException("Activity must be resumed.");
+        }
+        try {
+            return sService.enableNfcFForegroundService(service);
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return false;
+            }
+            try {
+                return sService.enableNfcFForegroundService(service);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Disables the service for the specified Activity.
+     *
+     * <p>Note that the specified Activity must still be in resumed
+     * state at the time of this call. A good place to call this method
+     * is in your {@link Activity#onPause} implementation.
+     *
+     * @param activity The activity which the service was registered for
+     * @return true when successful
+     */
+    public boolean disableNfcFForegroundService(Activity activity) {
+        if (activity == null) {
+            throw new NullPointerException("activity is null");
+        }
+        if (!activity.isResumed()) {
+            throw new IllegalArgumentException("Activity must be resumed.");
+        }
+        try {
+            return sService.disableNfcFForegroundService();
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return false;
+            }
+            try {
+                return sService.disableNfcFForegroundService();
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return false;
+            }
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public List<NfcFServiceInfo> getNfcFServices() {
+        try {
+            return sService.getNfcFServices(UserHandle.myUserId());
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return null;
+            }
+            try {
+                return sService.getNfcFServices(UserHandle.myUserId());
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return null;
+            }
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public int getMaxNumOfRegisterableSystemCodes() {
+        try {
+            return sService.getMaxNumOfRegisterableSystemCodes();
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return -1;
+            }
+            try {
+                return sService.getMaxNumOfRegisterableSystemCodes();
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return -1;
+            }
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public static boolean isValidSystemCode(String systemCode) {
+        if (systemCode == null) {
+            return false;
+        }
+        if (systemCode.length() != 4) {
+            Log.e(TAG, "System Code " + systemCode + " is not a valid System Code.");
+            return false;
+        }
+        // check if the value is between "4000" and "4FFF" (excluding "4*FF")
+        if (!systemCode.startsWith("4") || systemCode.toUpperCase().endsWith("FF")) {
+            Log.e(TAG, "System Code " + systemCode + " is not a valid System Code.");
+            return false;
+        }
+        try {
+            Integer.valueOf(systemCode, 16);
+        } catch (NumberFormatException e) {
+            Log.e(TAG, "System Code " + systemCode + " is not a valid System Code.");
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * @hide
+     */
+    public static boolean isValidNfcid2(String nfcid2) {
+        if (nfcid2 == null) {
+            return false;
+        }
+        if (nfcid2.length() != 16) {
+            Log.e(TAG, "NFCID2 " + nfcid2 + " is not a valid NFCID2.");
+            return false;
+        }
+        // check if the the value starts with "02FE"
+        if (!nfcid2.toUpperCase().startsWith("02FE")) {
+            Log.e(TAG, "NFCID2 " + nfcid2 + " is not a valid NFCID2.");
+            return false;
+        }
+        try {
+            Long.valueOf(nfcid2, 16);
+        } catch (NumberFormatException e) {
+            Log.e(TAG, "NFCID2 " + nfcid2 + " is not a valid NFCID2.");
+            return false;
+        }
+        return true;
+    }
+
+    void recoverService() {
+        NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
+        sService = adapter.getNfcFCardEmulationService();
+    }
+
+}
+
diff --git a/core/java/android/nfc/cardemulation/NfcFServiceInfo.aidl b/core/java/android/nfc/cardemulation/NfcFServiceInfo.aidl
new file mode 100644
index 0000000..56b98eb
--- /dev/null
+++ b/core/java/android/nfc/cardemulation/NfcFServiceInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc.cardemulation;
+
+parcelable NfcFServiceInfo;
diff --git a/core/java/android/nfc/cardemulation/NfcFServiceInfo.java b/core/java/android/nfc/cardemulation/NfcFServiceInfo.java
new file mode 100644
index 0000000..b93eec1
--- /dev/null
+++ b/core/java/android/nfc/cardemulation/NfcFServiceInfo.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc.cardemulation;
+
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * @hide
+ */
+public final class NfcFServiceInfo implements Parcelable {
+    static final String TAG = "NfcFServiceInfo";
+
+    /**
+     * The service that implements this
+     */
+    final ResolveInfo mService;
+
+    /**
+     * Description of the service
+     */
+    final String mDescription;
+
+    /**
+     * System Code of the service
+     */
+    final String mSystemCode;
+
+    /**
+     * System Code of the service registered by API
+     */
+    String mDynamicSystemCode;
+
+    /**
+     * NFCID2 of the service
+     */
+    final String mNfcid2;
+
+    /**
+     * NFCID2 of the service registered by API
+     */
+    String mDynamicNfcid2;
+
+    /**
+     * The uid of the package the service belongs to
+     */
+    final int mUid;
+
+    /**
+     * @hide
+     */
+    public NfcFServiceInfo(ResolveInfo info, String description,
+            String systemCode, String dynamicSystemCode, String nfcid2, String dynamicNfcid2,
+            int uid) {
+        this.mService = info;
+        this.mDescription = description;
+        this.mSystemCode = systemCode;
+        this.mDynamicSystemCode = dynamicSystemCode;
+        this.mNfcid2 = nfcid2;
+        this.mDynamicNfcid2 = dynamicNfcid2;
+        this.mUid = uid;
+    }
+
+    public NfcFServiceInfo(PackageManager pm, ResolveInfo info)
+            throws XmlPullParserException, IOException {
+        ServiceInfo si = info.serviceInfo;
+        XmlResourceParser parser = null;
+        try {
+            parser = si.loadXmlMetaData(pm, HostNfcFService.SERVICE_META_DATA);
+            if (parser == null) {
+                throw new XmlPullParserException("No " + HostNfcFService.SERVICE_META_DATA +
+                        " meta-data");
+            }
+
+            int eventType = parser.getEventType();
+            while (eventType != XmlPullParser.START_TAG &&
+                    eventType != XmlPullParser.END_DOCUMENT) {
+                eventType = parser.next();
+            }
+
+            String tagName = parser.getName();
+            if (!"host-nfcf-service".equals(tagName)) {
+                throw new XmlPullParserException(
+                        "Meta-data does not start with <host-nfcf-service> tag");
+            }
+
+            Resources res = pm.getResourcesForApplication(si.applicationInfo);
+            AttributeSet attrs = Xml.asAttributeSet(parser);
+            TypedArray sa = res.obtainAttributes(attrs,
+                    com.android.internal.R.styleable.HostNfcFService);
+            mService = info;
+            mDescription = sa.getString(
+                    com.android.internal.R.styleable.HostNfcFService_description);
+            mDynamicSystemCode = null;
+            mDynamicNfcid2 = null;
+            sa.recycle();
+
+            String systemCode = null;
+            String nfcid2 = null;
+            final int depth = parser.getDepth();
+
+            while (((eventType = parser.next()) != XmlPullParser.END_TAG ||
+                    parser.getDepth() > depth) && eventType != XmlPullParser.END_DOCUMENT) {
+                tagName = parser.getName();
+                if (eventType == XmlPullParser.START_TAG &&
+                        "system-code-filter".equals(tagName) && systemCode == null) {
+                    final TypedArray a = res.obtainAttributes(attrs,
+                            com.android.internal.R.styleable.SystemCodeFilter);
+                    systemCode = a.getString(
+                            com.android.internal.R.styleable.SystemCodeFilter_name).toUpperCase();
+                    if (!NfcFCardEmulation.isValidSystemCode(systemCode) &&
+                            !systemCode.equalsIgnoreCase("NULL")) {
+                        Log.e(TAG, "Invalid System Code: " + systemCode);
+                        systemCode = null;
+                    }
+                    a.recycle();
+                } else if (eventType == XmlPullParser.START_TAG &&
+                        "nfcid2-filter".equals(tagName) && nfcid2 == null) {
+                    final TypedArray a = res.obtainAttributes(attrs,
+                            com.android.internal.R.styleable.Nfcid2Filter);
+                    nfcid2 = a.getString(
+                            com.android.internal.R.styleable.Nfcid2Filter_name).toUpperCase();
+                    if (!nfcid2.equalsIgnoreCase("RANDOM") &&
+                            !nfcid2.equalsIgnoreCase("NULL") &&
+                            !NfcFCardEmulation.isValidNfcid2(nfcid2)) {
+                        Log.e(TAG, "Invalid NFCID2: " + nfcid2);
+                        nfcid2 = null;
+                    }
+                    a.recycle();
+                }
+            }
+            mSystemCode = (systemCode == null ? "NULL" : systemCode);
+            mNfcid2 = (nfcid2 == null ? "NULL" : nfcid2);
+        } catch (NameNotFoundException e) {
+            throw new XmlPullParserException("Unable to create context for: " + si.packageName);
+        } finally {
+            if (parser != null) parser.close();
+        }
+        // Set uid
+        mUid = si.applicationInfo.uid;
+    }
+
+    public ComponentName getComponent() {
+        return new ComponentName(mService.serviceInfo.packageName,
+                mService.serviceInfo.name);
+    }
+
+    public String getSystemCode() {
+        return (mDynamicSystemCode == null ? mSystemCode : mDynamicSystemCode);
+    }
+
+    public void setOrReplaceDynamicSystemCode(String systemCode) {
+        mDynamicSystemCode = systemCode;
+    }
+
+    public String getNfcid2() {
+        return (mDynamicNfcid2 == null ? mNfcid2 : mDynamicNfcid2);
+    }
+
+    public void setOrReplaceDynamicNfcid2(String nfcid2) {
+        mDynamicNfcid2 = nfcid2;
+    }
+
+    public String getDescription() {
+        return mDescription;
+    }
+
+    public int getUid() {
+        return mUid;
+    }
+
+    public CharSequence loadLabel(PackageManager pm) {
+        return mService.loadLabel(pm);
+    }
+
+    public Drawable loadIcon(PackageManager pm) {
+        return mService.loadIcon(pm);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder out = new StringBuilder("NfcFService: ");
+        out.append(getComponent());
+        out.append(", description: " + mDescription);
+        out.append(", System Code: " + mSystemCode);
+        if (mDynamicSystemCode != null) {
+            out.append(", dynamic System Code: " + mDynamicSystemCode);
+        }
+        out.append(", NFCID2: " + mNfcid2);
+        if (mDynamicNfcid2 != null) {
+            out.append(", dynamic NFCID2: " + mDynamicNfcid2);
+        }
+        return out.toString();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof NfcFServiceInfo)) return false;
+        NfcFServiceInfo thatService = (NfcFServiceInfo) o;
+
+        if (!thatService.getComponent().equals(this.getComponent())) return false;
+        if (!thatService.mSystemCode.equalsIgnoreCase(this.mSystemCode)) return false;
+        if (!thatService.mNfcid2.equalsIgnoreCase(this.mNfcid2)) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return getComponent().hashCode();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        mService.writeToParcel(dest, flags);
+        dest.writeString(mDescription);
+        dest.writeString(mSystemCode);
+        dest.writeInt(mDynamicSystemCode != null ? 1 : 0);
+        if (mDynamicSystemCode != null) {
+            dest.writeString(mDynamicSystemCode);
+        }
+        dest.writeString(mNfcid2);
+        dest.writeInt(mDynamicNfcid2 != null ? 1 : 0);
+        if (mDynamicNfcid2 != null) {
+            dest.writeString(mDynamicNfcid2);
+        }
+        dest.writeInt(mUid);
+    };
+
+    public static final Parcelable.Creator<NfcFServiceInfo> CREATOR =
+            new Parcelable.Creator<NfcFServiceInfo>() {
+        @Override
+        public NfcFServiceInfo createFromParcel(Parcel source) {
+            ResolveInfo info = ResolveInfo.CREATOR.createFromParcel(source);
+            String description = source.readString();
+            String systemCode = source.readString();
+            String dynamicSystemCode = null;
+            if (source.readInt() != 0) {
+                dynamicSystemCode = source.readString();
+            }
+            String nfcid2 = source.readString();
+            String dynamicNfcid2 = null;
+            if (source.readInt() != 0) {
+                dynamicNfcid2 = source.readString();
+            }
+            int uid = source.readInt();
+            NfcFServiceInfo service = new NfcFServiceInfo(info, description,
+                    systemCode, dynamicSystemCode, nfcid2, dynamicNfcid2, uid);
+            return service;
+        }
+
+        @Override
+        public NfcFServiceInfo[] newArray(int size) {
+            return new NfcFServiceInfo[size];
+        }
+    };
+
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("    " + getComponent() +
+                " (Description: " + getDescription() + ")");
+        pw.println("    System Code: " + getSystemCode());
+        pw.println("    NFCID2: " + getNfcid2());
+    }
+}
+
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index cd483b1..ee7bd9a 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -32,7 +32,9 @@
     private static final String TAG = "Bundle";
     static final boolean DEBUG = false;
 
+    // Keep in sync with frameworks/native/libs/binder/PersistableBundle.cpp.
     static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L'
+
     static final Parcel EMPTY_PARCEL;
 
     static {
@@ -1308,6 +1310,8 @@
      * @param parcel The parcel to copy this bundle to.
      */
     void writeToParcelInner(Parcel parcel, int flags) {
+        // Keep implementation in sync with writeToParcel() in
+        // frameworks/native/libs/binder/PersistableBundle.cpp.
         if (mParcelledData != null) {
             if (mParcelledData == EMPTY_PARCEL) {
                 parcel.writeInt(0);
@@ -1345,6 +1349,8 @@
      * @param parcel The parcel to overwrite this bundle from.
      */
     void readFromParcelInner(Parcel parcel) {
+        // Keep implementation in sync with readFromParcel() in
+        // frameworks/native/libs/binder/PersistableBundle.cpp.
         int length = parcel.readInt();
         readFromParcelInner(parcel, length);
     }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index bce38f4..52fa2ed 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -201,9 +201,14 @@
     private static final String BATTERY_LEVEL_DATA = "lv";
     private static final String GLOBAL_WIFI_DATA = "gwfl";
     private static final String WIFI_DATA = "wfl";
-    private static final String GLOBAL_BLUETOOTH_DATA = "gble";
+    private static final String GLOBAL_WIFI_CONTROLLER_DATA = "gwfcd";
+    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 MISC_DATA = "m";
     private static final String GLOBAL_NETWORK_DATA = "gn";
+    private static final String GLOBAL_MODEM_CONTROLLER_DATA = "gmcd";
+    private static final String MODEM_CONTROLLER_DATA = "mcd";
     private static final String HISTORY_STRING_POOL = "hsp";
     private static final String HISTORY_DATA = "h";
     private static final String SCREEN_BRIGHTNESS_DATA = "br";
@@ -271,6 +276,39 @@
     }
 
     /**
+     * Container class that aggregates counters for transmit, receive, and idle state of a
+     * radio controller.
+     */
+    public static abstract class ControllerActivityCounter {
+        /**
+         * @return a non-null {@link LongCounter} representing time spent (milliseconds) in the
+         * idle state.
+         */
+        public abstract LongCounter getIdleTimeCounter();
+
+        /**
+         * @return a non-null {@link LongCounter} representing time spent (milliseconds) in the
+         * receive state.
+         */
+        public abstract LongCounter getRxTimeCounter();
+
+        /**
+         * An array of {@link LongCounter}, representing various transmit levels, where each level
+         * may draw a different amount of power. The levels themselves are controller-specific.
+         * @return non-null array of {@link LongCounter}s representing time spent (milliseconds) in
+         * various transmit level states.
+         */
+        public abstract LongCounter[] getTxTimeCounters();
+
+        /**
+         * @return a non-null {@link LongCounter} representing the power consumed by the controller
+         * in all states, measured in milli-ampere-milliseconds (mAms). The counter may always
+         * yield a value of 0 if the device doesn't support power calculations.
+         */
+        public abstract LongCounter getPowerCounter();
+    }
+
+    /**
      * State for keeping track of timing information.
      */
     public static abstract class Timer {
@@ -367,15 +405,9 @@
          */
         public abstract ArrayMap<String, ? extends Pkg> getPackageStats();
 
-        /**
-         * Returns the time in milliseconds that this app kept the WiFi controller in the
-         * specified state <code>type</code>.
-         * @param type one of {@link #CONTROLLER_IDLE_TIME}, {@link #CONTROLLER_RX_TIME}, or
-         *             {@link #CONTROLLER_TX_TIME}.
-         * @param which one of {@link #STATS_CURRENT}, {@link #STATS_SINCE_CHARGED}, or
-         *              {@link #STATS_SINCE_UNPLUGGED}.
-         */
-        public abstract long getWifiControllerActivity(int type, int which);
+        public abstract ControllerActivityCounter getWifiControllerActivity();
+        public abstract ControllerActivityCounter getBluetoothControllerActivity();
+        public abstract ControllerActivityCounter getModemControllerActivity();
 
         /**
          * {@hide}
@@ -2014,48 +2046,54 @@
     public static final int NETWORK_MOBILE_TX_DATA = 1;
     public static final int NETWORK_WIFI_RX_DATA = 2;
     public static final int NETWORK_WIFI_TX_DATA = 3;
-    public static final int NUM_NETWORK_ACTIVITY_TYPES = NETWORK_WIFI_TX_DATA + 1;
+    public static final int NETWORK_BT_RX_DATA = 4;
+    public static final int NETWORK_BT_TX_DATA = 5;
+    public static final int NUM_NETWORK_ACTIVITY_TYPES = NETWORK_BT_TX_DATA + 1;
 
     public abstract long getNetworkActivityBytes(int type, int which);
     public abstract long getNetworkActivityPackets(int type, int which);
 
-    public static final int CONTROLLER_IDLE_TIME = 0;
-    public static final int CONTROLLER_RX_TIME = 1;
-    public static final int CONTROLLER_TX_TIME = 2;
-    public static final int CONTROLLER_POWER_DRAIN = 3;
-    public static final int NUM_CONTROLLER_ACTIVITY_TYPES = CONTROLLER_POWER_DRAIN + 1;
-
-    /**
-     * Returns true if the BatteryStats object has detailed bluetooth power reports.
-     * When true, calling {@link #getBluetoothControllerActivity(int, int)} will yield the
-     * actual power data.
-     */
-    public abstract boolean hasBluetoothActivityReporting();
-
-    /**
-     * For {@link #CONTROLLER_IDLE_TIME}, {@link #CONTROLLER_RX_TIME}, and
-     * {@link #CONTROLLER_TX_TIME}, returns the time spent (in milliseconds) in the
-     * respective state.
-     * For {@link #CONTROLLER_POWER_DRAIN}, returns the power used by the controller in
-     * milli-ampere-milliseconds (mAms).
-     */
-    public abstract long getBluetoothControllerActivity(int type, int which);
-
     /**
      * Returns true if the BatteryStats object has detailed WiFi power reports.
-     * When true, calling {@link #getWifiControllerActivity(int, int)} will yield the
+     * When true, calling {@link #getWifiControllerActivity()} will yield the
      * actual power data.
      */
     public abstract boolean hasWifiActivityReporting();
 
     /**
-     * For {@link #CONTROLLER_IDLE_TIME}, {@link #CONTROLLER_RX_TIME}, and
-     * {@link #CONTROLLER_TX_TIME}, returns the time spent (in milliseconds) in the
-     * respective state.
-     * For {@link #CONTROLLER_POWER_DRAIN}, returns the power used by the controller in
-     * milli-ampere-milliseconds (mAms).
+     * Returns a {@link ControllerActivityCounter} which is an aggregate of the times spent
+     * in various radio controller states, such as transmit, receive, and idle.
+     * @return non-null {@link ControllerActivityCounter}
      */
-    public abstract long getWifiControllerActivity(int type, int which);
+    public abstract ControllerActivityCounter getWifiControllerActivity();
+
+    /**
+     * Returns true if the BatteryStats object has detailed bluetooth power reports.
+     * When true, calling {@link #getBluetoothControllerActivity()} will yield the
+     * actual power data.
+     */
+    public abstract boolean hasBluetoothActivityReporting();
+
+    /**
+     * Returns a {@link ControllerActivityCounter} which is an aggregate of the times spent
+     * in various radio controller states, such as transmit, receive, and idle.
+     * @return non-null {@link ControllerActivityCounter}
+     */
+    public abstract ControllerActivityCounter getBluetoothControllerActivity();
+
+    /**
+     * Returns true if the BatteryStats object has detailed modem power reports.
+     * When true, calling {@link #getModemControllerActivity()} will yield the
+     * actual power data.
+     */
+    public abstract boolean hasModemActivityReporting();
+
+    /**
+     * Returns a {@link ControllerActivityCounter} which is an aggregate of the times spent
+     * in various radio controller states, such as transmit, receive, and idle.
+     * @return non-null {@link ControllerActivityCounter}
+     */
+    public abstract ControllerActivityCounter getModemControllerActivity();
 
     /**
      * Return the wall clock time when battery stats data collection started.
@@ -2484,6 +2522,17 @@
         return ",";
     }
     
+    private static final void dumpLineHeader(PrintWriter pw, int uid, String category,
+                                             String type) {
+        pw.print(BATTERY_STATS_CHECKIN_VERSION);
+        pw.print(',');
+        pw.print(uid);
+        pw.print(',');
+        pw.print(category);
+        pw.print(',');
+        pw.print(type);
+    }
+
     /**
      * Dump a comma-separated line of values for terse checkin mode.
      * 
@@ -2494,14 +2543,7 @@
      */
     private static final void dumpLine(PrintWriter pw, int uid, String category, String type, 
            Object... args ) {
-        pw.print(BATTERY_STATS_CHECKIN_VERSION);
-        pw.print(',');
-        pw.print(uid);
-        pw.print(',');
-        pw.print(category);
-        pw.print(',');
-        pw.print(type);
-
+        dumpLineHeader(pw, uid, category, type);
         for (Object arg : args) {
             pw.print(',');
             pw.print(arg);
@@ -2534,6 +2576,140 @@
     }
 
     /**
+     * Checks if the ControllerActivityCounter has any data worth dumping.
+     */
+    private static boolean controllerActivityHasData(ControllerActivityCounter counter, int which) {
+        if (counter == null) {
+            return false;
+        }
+
+        if (counter.getIdleTimeCounter().getCountLocked(which) != 0
+                || counter.getRxTimeCounter().getCountLocked(which) != 0
+                || counter.getPowerCounter().getCountLocked(which) != 0) {
+            return true;
+        }
+
+        for (LongCounter c : counter.getTxTimeCounters()) {
+            if (c.getCountLocked(which) != 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Dumps the ControllerActivityCounter if it has any data worth dumping.
+     * The order of the arguments in the final check in line is:
+     *
+     * idle, rx, power, tx...
+     *
+     * where tx... is one or more transmit level times.
+     */
+    private static final void dumpControllerActivityLine(PrintWriter pw, int uid, String category,
+                                                         String type,
+                                                         ControllerActivityCounter counter,
+                                                         int which) {
+        if (!controllerActivityHasData(counter, which)) {
+            return;
+        }
+
+        dumpLineHeader(pw, uid, category, type);
+        pw.print(",");
+        pw.print(counter.getIdleTimeCounter().getCountLocked(which));
+        pw.print(",");
+        pw.print(counter.getRxTimeCounter().getCountLocked(which));
+        pw.print(",");
+        pw.print(counter.getPowerCounter().getCountLocked(which) / (1000 * 60 * 60));
+        for (LongCounter c : counter.getTxTimeCounters()) {
+            pw.print(",");
+            pw.print(c.getCountLocked(which));
+        }
+        pw.println();
+    }
+
+    private final void printControllerActivityIfInteresting(PrintWriter pw, StringBuilder sb,
+                                                            String prefix, String controllerName,
+                                                            ControllerActivityCounter counter,
+                                                            int which) {
+        if (controllerActivityHasData(counter, which)) {
+            printControllerActivity(pw, sb, prefix, controllerName, counter, which);
+        }
+    }
+
+    private final void printControllerActivity(PrintWriter pw, StringBuilder sb, String prefix,
+                                               String controllerName,
+                                               ControllerActivityCounter counter, int which) {
+        final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(which);
+        final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(which);
+        final long powerDrainMaMs = counter.getPowerCounter().getCountLocked(which);
+        long totalTxTimeMs = 0;
+        for (LongCounter txState : counter.getTxTimeCounters()) {
+            totalTxTimeMs += txState.getCountLocked(which);
+        }
+
+        final long totalTimeMs = idleTimeMs + rxTimeMs + totalTxTimeMs;
+
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  ");
+        sb.append(controllerName);
+        sb.append(" Idle time:   ");
+        formatTimeMs(sb, idleTimeMs);
+        sb.append("(");
+        sb.append(formatRatioLocked(idleTimeMs, totalTimeMs));
+        sb.append(")");
+        pw.println(sb.toString());
+
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  ");
+        sb.append(controllerName);
+        sb.append(" Rx time:     ");
+        formatTimeMs(sb, rxTimeMs);
+        sb.append("(");
+        sb.append(formatRatioLocked(rxTimeMs, totalTimeMs));
+        sb.append(")");
+        pw.println(sb.toString());
+
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  ");
+        sb.append(controllerName);
+        sb.append(" Tx time:     ");
+        formatTimeMs(sb, totalTxTimeMs);
+        sb.append("(");
+        sb.append(formatRatioLocked(totalTxTimeMs, totalTimeMs));
+        sb.append(")");
+        pw.println(sb.toString());
+
+        final int numTxLvls = counter.getTxTimeCounters().length;
+        if (numTxLvls > 1) {
+            for (int lvl = 0; lvl < numTxLvls; lvl++) {
+                final long txLvlTimeMs = counter.getTxTimeCounters()[lvl].getCountLocked(which);
+                sb.setLength(0);
+                sb.append(prefix);
+                sb.append("    [");
+                sb.append(lvl);
+                sb.append("] ");
+                formatTimeMs(sb, txLvlTimeMs);
+                sb.append("(");
+                sb.append(formatRatioLocked(txLvlTimeMs, totalTxTimeMs));
+                sb.append(")");
+                pw.println(sb.toString());
+            }
+        }
+
+        sb.setLength(0);
+        sb.append(prefix);
+        sb.append("  ");
+        sb.append(controllerName);
+        sb.append(" Power drain: ").append(
+                BatteryStatsHelper.makemAh(powerDrainMaMs / (double) (1000*60*60)));
+        sb.append("mAh");
+        pw.println(sb.toString());
+    }
+
+    /**
      * Temporary for settings.
      */
     public final void dumpCheckinLocked(Context context, PrintWriter pw, int which, int reqUid) {
@@ -2625,24 +2801,22 @@
                 mobileRxTotalBytes, mobileTxTotalBytes, wifiRxTotalBytes, wifiTxTotalBytes,
                 mobileRxTotalPackets, mobileTxTotalPackets, wifiRxTotalPackets, wifiTxTotalPackets);
 
+        // Dump Modem controller stats
+        dumpControllerActivityLine(pw, 0 /* uid */, category, GLOBAL_MODEM_CONTROLLER_DATA,
+                getModemControllerActivity(), which);
+
         // Dump Wifi controller stats
         final long wifiOnTime = getWifiOnTime(rawRealtime, which);
         final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
-        final long wifiIdleTimeMs = getWifiControllerActivity(CONTROLLER_IDLE_TIME, which);
-        final long wifiRxTimeMs = getWifiControllerActivity(CONTROLLER_RX_TIME, which);
-        final long wifiTxTimeMs = getWifiControllerActivity(CONTROLLER_TX_TIME, which);
-        final long wifiPowerMaMs = getWifiControllerActivity(CONTROLLER_POWER_DRAIN, which);
-        dumpLine(pw, 0 /* uid */, category, GLOBAL_WIFI_DATA,
-                wifiOnTime / 1000, wifiRunningTime / 1000,
-                wifiIdleTimeMs, wifiRxTimeMs, wifiTxTimeMs, wifiPowerMaMs / (1000*60*60));
+        dumpLine(pw, 0 /* uid */, category, GLOBAL_WIFI_DATA, wifiOnTime / 1000,
+                wifiRunningTime / 1000, /* legacy fields follow, keep at 0 */ 0, 0, 0, 0);
+
+        dumpControllerActivityLine(pw, 0 /* uid */, category, GLOBAL_WIFI_CONTROLLER_DATA,
+                getWifiControllerActivity(), which);
 
         // Dump Bluetooth controller stats
-        final long btIdleTimeMs = getBluetoothControllerActivity(CONTROLLER_IDLE_TIME, which);
-        final long btRxTimeMs = getBluetoothControllerActivity(CONTROLLER_RX_TIME, which);
-        final long btTxTimeMs = getBluetoothControllerActivity(CONTROLLER_TX_TIME, which);
-        final long btPowerMaMs = getBluetoothControllerActivity(CONTROLLER_POWER_DRAIN, which);
-        dumpLine(pw, 0 /* uid */, category, GLOBAL_BLUETOOTH_DATA,
-                btIdleTimeMs, btRxTimeMs, btTxTimeMs, btPowerMaMs / (1000*60*60));
+        dumpControllerActivityLine(pw, 0 /* uid */, category, GLOBAL_BLUETOOTH_CONTROLLER_DATA,
+                getBluetoothControllerActivity(), which);
 
         // Dump misc stats
         dumpLine(pw, 0 /* uid */, category, MISC_DATA,
@@ -2853,21 +3027,25 @@
                         mobileActiveTime, mobileActiveCount);
             }
 
+            // Dump modem controller data, per UID.
+            dumpControllerActivityLine(pw, uid, category, MODEM_CONTROLLER_DATA,
+                    u.getModemControllerActivity(), which);
+
+            // Dump Wifi controller data, per UID.
             final long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
             final long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
             final int wifiScanCount = u.getWifiScanCount(which);
             final long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
-            final long uidWifiIdleTimeMs = u.getWifiControllerActivity(CONTROLLER_IDLE_TIME, which);
-            final long uidWifiRxTimeMs = u.getWifiControllerActivity(CONTROLLER_RX_TIME, which);
-            final long uidWifiTxTimeMs = u.getWifiControllerActivity(CONTROLLER_TX_TIME, which);
             if (fullWifiLockOnTime != 0 || wifiScanTime != 0 || wifiScanCount != 0
-                    || uidWifiRunningTime != 0 || uidWifiIdleTimeMs != 0 || uidWifiRxTimeMs != 0
-                    || uidWifiTxTimeMs != 0) {
-                dumpLine(pw, uid, category, WIFI_DATA,
-                        fullWifiLockOnTime, wifiScanTime, uidWifiRunningTime, wifiScanCount,
-                        uidWifiIdleTimeMs, uidWifiRxTimeMs, uidWifiTxTimeMs);
+                    || uidWifiRunningTime != 0) {
+                dumpLine(pw, uid, category, WIFI_DATA, fullWifiLockOnTime, wifiScanTime,
+                        uidWifiRunningTime, wifiScanCount,
+                        /* legacy fields follow, keep at 0 */ 0, 0, 0, 0);
             }
 
+            dumpControllerActivityLine(pw, uid, category, WIFI_CONTROLLER_DATA,
+                    u.getWifiControllerActivity(), which);
+
             if (u.hasUserActivity()) {
                 args = new Object[Uid.NUM_USER_ACTIVITY_TYPES];
                 boolean hasData = false;
@@ -3284,6 +3462,8 @@
         final long mobileTxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
         final long wifiRxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
         final long wifiTxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
+        final long btRxTotalBytes = getNetworkActivityBytes(NETWORK_BT_RX_DATA, which);
+        final long btTxTotalBytes = getNetworkActivityBytes(NETWORK_BT_TX_DATA, which);
 
         if (fullWakeLockTimeTotalMicros != 0) {
             sb.setLength(0);
@@ -3395,6 +3575,8 @@
             pw.println(sb.toString());
         }
 
+        printControllerActivity(pw, sb, prefix, "Radio", getModemControllerActivity(), which);
+
         pw.print(prefix);
                 pw.print("  Wi-Fi total received: "); pw.print(formatBytesLocked(wifiRxTotalBytes));
                 pw.print(", sent: "); pw.print(formatBytesLocked(wifiTxTotalBytes));
@@ -3480,81 +3662,14 @@
         if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
 
-        final long wifiIdleTimeMs = getWifiControllerActivity(CONTROLLER_IDLE_TIME, which);
-        final long wifiRxTimeMs = getWifiControllerActivity(CONTROLLER_RX_TIME, which);
-        final long wifiTxTimeMs = getWifiControllerActivity(CONTROLLER_TX_TIME, which);
-        final long wifiPowerDrainMaMs = getWifiControllerActivity(CONTROLLER_POWER_DRAIN, which);
-        final long wifiTotalTimeMs = wifiIdleTimeMs + wifiRxTimeMs + wifiTxTimeMs;
+        printControllerActivity(pw, sb, prefix, "WiFi", getWifiControllerActivity(), which);
 
-        sb.setLength(0);
-        sb.append(prefix);
-        sb.append("  WiFi Idle time: "); formatTimeMs(sb, wifiIdleTimeMs);
-        sb.append("(");
-        sb.append(formatRatioLocked(wifiIdleTimeMs, wifiTotalTimeMs));
-        sb.append(")");
-        pw.println(sb.toString());
+        pw.print(prefix);
+        pw.print("  Bluetooth total received: "); pw.print(formatBytesLocked(btRxTotalBytes));
+        pw.print(", sent: "); pw.println(formatBytesLocked(btTxTotalBytes));
 
-        sb.setLength(0);
-        sb.append(prefix);
-        sb.append("  WiFi Rx time:   "); formatTimeMs(sb, wifiRxTimeMs);
-        sb.append("(");
-        sb.append(formatRatioLocked(wifiRxTimeMs, wifiTotalTimeMs));
-        sb.append(")");
-        pw.println(sb.toString());
-
-        sb.setLength(0);
-        sb.append(prefix);
-        sb.append("  WiFi Tx time:   "); formatTimeMs(sb, wifiTxTimeMs);
-        sb.append("(");
-        sb.append(formatRatioLocked(wifiTxTimeMs, wifiTotalTimeMs));
-        sb.append(")");
-        pw.println(sb.toString());
-
-        sb.setLength(0);
-        sb.append(prefix);
-        sb.append("  WiFi Power drain: ").append(
-                BatteryStatsHelper.makemAh(wifiPowerDrainMaMs / (double) (1000*60*60)));
-        sb.append("mAh");
-        pw.println(sb.toString());
-
-        final long bluetoothIdleTimeMs =
-                getBluetoothControllerActivity(CONTROLLER_IDLE_TIME, which);
-        final long bluetoothRxTimeMs = getBluetoothControllerActivity(CONTROLLER_RX_TIME, which);
-        final long bluetoothTxTimeMs = getBluetoothControllerActivity(CONTROLLER_TX_TIME, which);
-        final long bluetoothTotalTimeMs = bluetoothIdleTimeMs + bluetoothRxTimeMs +
-                bluetoothTxTimeMs;
-
-        sb.setLength(0);
-        sb.append(prefix);
-        sb.append("  Bluetooth Idle time: "); formatTimeMs(sb, bluetoothIdleTimeMs);
-        sb.append("(");
-        sb.append(formatRatioLocked(bluetoothIdleTimeMs, bluetoothTotalTimeMs));
-        sb.append(")");
-        pw.println(sb.toString());
-
-        sb.setLength(0);
-        sb.append(prefix);
-        sb.append("  Bluetooth Rx time:   "); formatTimeMs(sb, bluetoothRxTimeMs);
-        sb.append("(");
-        sb.append(formatRatioLocked(bluetoothRxTimeMs, bluetoothTotalTimeMs));
-        sb.append(")");
-        pw.println(sb.toString());
-
-        sb.setLength(0);
-        sb.append(prefix);
-        sb.append("  Bluetooth Tx time:   "); formatTimeMs(sb, bluetoothTxTimeMs);
-        sb.append("(");
-        sb.append(formatRatioLocked(bluetoothTxTimeMs, bluetoothTotalTimeMs));
-        sb.append(")");
-        pw.println(sb.toString());
-
-        sb.setLength(0);
-        sb.append(prefix);
-        sb.append("  Bluetooth Power drain: ").append(BatteryStatsHelper.makemAh(
-                getBluetoothControllerActivity(CONTROLLER_POWER_DRAIN, which) /
-                        (double)(1000*60*60)));
-        sb.append("mAh");
-        pw.println(sb.toString());
+        printControllerActivity(pw, sb, prefix, "Bluetooth", getBluetoothControllerActivity(),
+                which);
 
         pw.println();
 
@@ -3838,12 +3953,17 @@
             final long mobileTxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
             final long wifiRxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
             final long wifiTxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
+            final long btRxBytes = u.getNetworkActivityBytes(NETWORK_BT_RX_DATA, which);
+            final long btTxBytes = u.getNetworkActivityBytes(NETWORK_BT_TX_DATA, which);
+
             final long mobileRxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
             final long mobileTxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
-            final long uidMobileActiveTime = u.getMobileRadioActiveTime(which);
-            final int uidMobileActiveCount = u.getMobileRadioActiveCount(which);
             final long wifiRxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
             final long wifiTxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
+
+            final long uidMobileActiveTime = u.getMobileRadioActiveTime(which);
+            final int uidMobileActiveCount = u.getMobileRadioActiveCount(which);
+
             final long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
             final long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
             final int wifiScanCount = u.getWifiScanCount(which);
@@ -3874,6 +3994,9 @@
                 pw.println(sb.toString());
             }
 
+            printControllerActivityIfInteresting(pw, sb, prefix + "  ", "Modem",
+                    u.getModemControllerActivity(), which);
+
             if (wifiRxBytes > 0 || wifiTxBytes > 0 || wifiRxPackets > 0 || wifiTxPackets > 0) {
                 pw.print(prefix); pw.print("    Wi-Fi network: ");
                         pw.print(formatBytesLocked(wifiRxBytes)); pw.print(" received, ");
@@ -3902,25 +4025,14 @@
                 pw.println(sb.toString());
             }
 
-            final long uidWifiIdleTimeMs = u.getWifiControllerActivity(CONTROLLER_IDLE_TIME, which);
-            final long uidWifiRxTimeMs = u.getWifiControllerActivity(CONTROLLER_RX_TIME, which);
-            final long uidWifiTxTimeMs = u.getWifiControllerActivity(CONTROLLER_TX_TIME, which);
-            final long uidWifiTotalTimeMs = uidWifiIdleTimeMs + uidWifiRxTimeMs + uidWifiTxTimeMs;
-            if (uidWifiTotalTimeMs > 0) {
-                sb.setLength(0);
-                sb.append(prefix).append("    WiFi Idle time: ");
-                formatTimeMs(sb, uidWifiIdleTimeMs);
-                sb.append("(").append(formatRatioLocked(uidWifiIdleTimeMs, uidWifiTotalTimeMs))
-                        .append(")\n");
+            printControllerActivityIfInteresting(pw, sb, prefix + "  ", "WiFi",
+                    u.getWifiControllerActivity(), which);
 
-                sb.append(prefix).append("    WiFi Rx time:   "); formatTimeMs(sb, uidWifiRxTimeMs);
-                sb.append("(").append(formatRatioLocked(uidWifiRxTimeMs, uidWifiTotalTimeMs))
-                        .append(")\n");
-
-                sb.append(prefix).append("    WiFi Tx time:   "); formatTimeMs(sb, uidWifiTxTimeMs);
-                sb.append("(").append(formatRatioLocked(uidWifiTxTimeMs, uidWifiTotalTimeMs))
-                        .append(")");
-                pw.println(sb.toString());
+            if (btRxBytes > 0 || btTxBytes > 0) {
+                pw.print(prefix); pw.print("    Bluetooth network: ");
+                pw.print(formatBytesLocked(btRxBytes)); pw.print(" received, ");
+                pw.print(formatBytesLocked(btTxBytes));
+                pw.println(" sent");
             }
 
             if (u.hasUserActivity()) {
diff --git a/core/java/android/os/CpuUsageInfo.java b/core/java/android/os/CpuUsageInfo.java
new file mode 100644
index 0000000..54caa15
--- /dev/null
+++ b/core/java/android/os/CpuUsageInfo.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * CPU usage information per core.
+ */
+public final class CpuUsageInfo implements Parcelable {
+    private long mActive;
+    private long mTotal;
+
+    public static final Parcelable.Creator<CpuUsageInfo> CREATOR = new
+            Parcelable.Creator<CpuUsageInfo>() {
+                    public CpuUsageInfo createFromParcel(Parcel in) {
+                        return new CpuUsageInfo(in);
+                    }
+
+                    public CpuUsageInfo[] newArray(int size) {
+                        return new CpuUsageInfo[size];
+                    }
+                };
+
+    /** @hide */
+    public CpuUsageInfo(long activeTime, long totalTime) {
+        mActive = activeTime;
+        mTotal = totalTime;
+    }
+
+    private CpuUsageInfo(Parcel in) {
+        readFromParcel(in);
+    }
+
+    /**
+     * Gets the active time in milliseconds since the system last booted.
+     *
+     * @return Active time in milliseconds.
+     */
+    public long getActive() {
+        return mActive;
+    }
+
+    /**
+     * Gets the total time in milliseconds that the CPU has been enabled since the system last
+     * booted. This includes time the CPU spent idle.
+     *
+     * @return Total time in milliseconds.
+     */
+    public long getTotal() {
+        return mTotal;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeLong(mActive);
+        out.writeLong(mTotal);
+    }
+
+    private void readFromParcel(Parcel in) {
+        mActive = in.readLong();
+        mTotal = in.readLong();
+    }
+}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index fdd34f5..e58744b 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -130,6 +130,9 @@
         /** The dirty dalvik pages that have been swapped out. */
         /** @hide We may want to expose this, eventually. */
         public int dalvikSwappedOut;
+        /** The dirty dalvik pages that have been swapped out, proportional. */
+        /** @hide We may want to expose this, eventually. */
+        public int dalvikSwappedOutPss;
 
         /** The proportional set size for the native heap. */
         public int nativePss;
@@ -149,6 +152,9 @@
         /** The dirty native pages that have been swapped out. */
         /** @hide We may want to expose this, eventually. */
         public int nativeSwappedOut;
+        /** The dirty native pages that have been swapped out, proportional. */
+        /** @hide We may want to expose this, eventually. */
+        public int nativeSwappedOutPss;
 
         /** The proportional set size for everything else. */
         public int otherPss;
@@ -168,6 +174,13 @@
         /** The dirty pages used by anyting else that have been swapped out. */
         /** @hide We may want to expose this, eventually. */
         public int otherSwappedOut;
+        /** The dirty pages used by anyting else that have been swapped out, proportional. */
+        /** @hide We may want to expose this, eventually. */
+        public int otherSwappedOutPss;
+
+        /** Whether the kernel reports proportional swap usage */
+        /** @hide */
+        public boolean hasSwappedOutPss;
 
         /** @hide */
         public static final int HEAP_UNKNOWN = 0;
@@ -235,7 +248,7 @@
         public static final int NUM_DVK_STATS = 8;
 
         /** @hide */
-        public static final int NUM_CATEGORIES = 7;
+        public static final int NUM_CATEGORIES = 8;
 
         /** @hide */
         public static final int offsetPss = 0;
@@ -251,6 +264,8 @@
         public static final int offsetSharedClean = 5;
         /** @hide */
         public static final int offsetSwappedOut = 6;
+        /** @hide */
+        public static final int offsetSwappedOutPss = 7;
 
         private int[] otherStats = new int[(NUM_OTHER_STATS+NUM_DVK_STATS)*NUM_CATEGORIES];
 
@@ -261,7 +276,7 @@
          * Return total PSS memory usage in kB.
          */
         public int getTotalPss() {
-            return dalvikPss + nativePss + otherPss;
+            return dalvikPss + nativePss + otherPss + getTotalSwappedOutPss();
         }
 
         /**
@@ -274,7 +289,8 @@
         }
 
         /**
-         * Return total PSS memory usage in kB.
+         * Return total PSS memory usage in kB mapping a file of one of the following extension:
+         * .so, .jar, .apk, .ttf, .dex, .odex, .oat, .art .
          */
         public int getTotalSwappablePss() {
             return dalvikSwappablePss + nativeSwappablePss + otherSwappablePss;
@@ -316,6 +332,14 @@
             return dalvikSwappedOut + nativeSwappedOut + otherSwappedOut;
         }
 
+        /**
+         * Return total swapped out memory in kB, proportional.
+         * @hide
+         */
+        public int getTotalSwappedOutPss() {
+            return dalvikSwappedOutPss + nativeSwappedOutPss + otherSwappedOutPss;
+        }
+
         /** @hide */
         public int getOtherPss(int which) {
             return otherStats[which*NUM_CATEGORIES + offsetPss];
@@ -359,6 +383,11 @@
         }
 
         /** @hide */
+        public int getOtherSwappedOutPss(int which) {
+            return otherStats[which*NUM_CATEGORIES + offsetSwappedOutPss];
+        }
+
+        /** @hide */
         public static String getOtherLabel(int which) {
             switch (which) {
                 case OTHER_DALVIK_OTHER: return "Dalvik Other";
@@ -632,12 +661,24 @@
          *    know if the Swap memory is shared or private, so we don't know
          *    what to blame on the application and what on the system.
          *    For now, just lump all the Swap in one place.
+         *    For kernels reporting SwapPss {@link #getSummaryTotalSwapPss()}
+         *    will report the application proportional Swap.
          * @hide
          */
         public int getSummaryTotalSwap() {
             return getTotalSwappedOut();
         }
 
+        /**
+         * Total proportional Swap in KB.
+         * Notes:
+         *  * Always 0 if {@link #hasSwappedOutPss} is false.
+         * @hide
+         */
+        public int getSummaryTotalSwapPss() {
+            return getTotalSwappedOutPss();
+        }
+
         public int describeContents() {
             return 0;
         }
@@ -664,6 +705,8 @@
             dest.writeInt(otherPrivateClean);
             dest.writeInt(otherSharedClean);
             dest.writeInt(otherSwappedOut);
+            dest.writeInt(hasSwappedOutPss ? 1 : 0);
+            dest.writeInt(otherSwappedOutPss);
             dest.writeIntArray(otherStats);
         }
 
@@ -689,6 +732,8 @@
             otherPrivateClean = source.readInt();
             otherSharedClean = source.readInt();
             otherSwappedOut = source.readInt();
+            hasSwappedOutPss = source.readInt() != 0;
+            otherSwappedOutPss = source.readInt();
             otherStats = source.createIntArray();
         }
 
@@ -1563,11 +1608,12 @@
 
     /**
      * Retrieves the PSS memory used by the process as given by the
-     * smaps.  Optionally supply a long array of 1 entry to also
-     * receive the uss of the process, and another array to also
-     * retrieve the separate memtrack size.  @hide
+     * smaps.  Optionally supply a long array of 2 entries to also
+     * receive the Uss and SwapPss of the process, and another array to also
+     * retrieve the separate memtrack size.
+     * @hide
      */
-    public static native long getPss(int pid, long[] outUss, long[] outMemtrack);
+    public static native long getPss(int pid, long[] outUssSwapPss, long[] outMemtrack);
 
     /** @hide */
     public static final int MEMINFO_TOTAL = 0;
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index a01d34a..c776ef8 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -37,6 +37,7 @@
     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";
+    private static final String ENV_ODM_ROOT = "ODM_ROOT";
     private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT";
 
     /** {@hide} */
@@ -56,6 +57,7 @@
     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");
+    private static final File DIR_ODM_ROOT = getDirectory(ENV_ODM_ROOT, "/odm");
     private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor");
 
     private static UserEnvironment sCurrentUser;
@@ -156,6 +158,16 @@
     }
 
     /**
+     * Return root directory of the "odm" partition holding ODM customizations,
+     * if any. If present, the partition is mounted read-only.
+     *
+     * @hide
+     */
+    public static File getOdmDirectory() {
+        return DIR_ODM_ROOT;
+    }
+
+    /**
      * Return root directory of the "vendor" partition that holds vendor-provided
      * software that should persist across simple reflashing of the "system" partition.
      * @hide
@@ -378,7 +390,7 @@
      * type.
      */
     public static String DIRECTORY_MUSIC = "Music";
-    
+
     /**
      * Standard directory in which to place any audio files that should be
      * in the list of podcasts that the user can select (not as regular
@@ -390,7 +402,7 @@
      * type.
      */
     public static String DIRECTORY_PODCASTS = "Podcasts";
-    
+
     /**
      * Standard directory in which to place any audio files that should be
      * in the list of ringtones that the user can select (not as regular
@@ -402,7 +414,7 @@
      * type.
      */
     public static String DIRECTORY_RINGTONES = "Ringtones";
-    
+
     /**
      * Standard directory in which to place any audio files that should be
      * in the list of alarms that the user can select (not as regular
@@ -414,7 +426,7 @@
      * type.
      */
     public static String DIRECTORY_ALARMS = "Alarms";
-    
+
     /**
      * Standard directory in which to place any audio files that should be
      * in the list of notifications that the user can select (not as regular
@@ -426,7 +438,7 @@
      * type.
      */
     public static String DIRECTORY_NOTIFICATIONS = "Notifications";
-    
+
     /**
      * Standard directory in which to place pictures that are available to
      * the user.  Note that this is primarily a convention for the top-level
@@ -434,7 +446,7 @@
      * in any directory.
      */
     public static String DIRECTORY_PICTURES = "Pictures";
-    
+
     /**
      * Standard directory in which to place movies that are available to
      * the user.  Note that this is primarily a convention for the top-level
@@ -442,7 +454,7 @@
      * in any directory.
      */
     public static String DIRECTORY_MOVIES = "Movies";
-    
+
     /**
      * Standard directory in which to place files that have been downloaded by
      * the user.  Note that this is primarily a convention for the top-level
@@ -452,7 +464,7 @@
      * backwards compatibility reasons.
      */
     public static String DIRECTORY_DOWNLOADS = "Download";
-    
+
     /**
      * The traditional location for pictures and videos when mounting the
      * device as a camera.  Note that this is primarily a convention for the
@@ -467,6 +479,49 @@
     public static String DIRECTORY_DOCUMENTS = "Documents";
 
     /**
+     * List of standard storage directories.
+     * <p>
+     * Each of its values have its own constant:
+     * <ul>
+     *   <li>{@link #DIRECTORY_MUSIC}
+     *   <li>{@link #DIRECTORY_PODCASTS}
+     *   <li>{@link #DIRECTORY_ALARMS}
+     *   <li>{@link #DIRECTORY_RINGTONES}
+     *   <li>{@link #DIRECTORY_NOTIFICATIONS}
+     *   <li>{@link #DIRECTORY_PICTURES}
+     *   <li>{@link #DIRECTORY_MOVIES}
+     *   <li>{@link #DIRECTORY_DOWNLOADS}
+     *   <li>{@link #DIRECTORY_DCIM}
+     *   <li>{@link #DIRECTORY_DOCUMENTS}
+     * </ul>
+     * @hide
+     */
+    private static final String[] STANDARD_DIRECTORIES = {
+            DIRECTORY_MUSIC,
+            DIRECTORY_PODCASTS,
+            DIRECTORY_RINGTONES,
+            DIRECTORY_ALARMS,
+            DIRECTORY_NOTIFICATIONS,
+            DIRECTORY_PICTURES,
+            DIRECTORY_MOVIES,
+            DIRECTORY_DOWNLOADS,
+            DIRECTORY_DCIM,
+            DIRECTORY_DOCUMENTS
+    };
+
+    /**
+     * @hide
+     */
+    public static boolean isStandardDirectory(String dir) {
+        for (String valid : STANDARD_DIRECTORIES) {
+            if (valid.equals(dir)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
      * Get a top-level shared/external storage directory for placing files of a
      * particular type. This is where the user will typically place and manage
      * their own files, so you should be careful about what you put here to
@@ -483,13 +538,13 @@
      * </p>
      * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
      * public_picture}
-     * 
+     *
      * @param type The type of storage directory to return. Should be one of
      *            {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS},
      *            {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS},
      *            {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES},
-     *            {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS}, or
-     *            {@link #DIRECTORY_DCIM}. May not be null.
+     *            {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS},
+     *            {@link #DIRECTORY_DCIM}, or {@link #DIRECTORY_DOCUMENTS}. May not be null.
      * @return Returns the File path for the directory. Note that this directory
      *         may not yet exist, so you must make sure it exists before using
      *         it such as with {@link File#mkdirs File.mkdirs()}.
@@ -516,7 +571,7 @@
         throwIfUserRequired();
         return sCurrentUser.buildExternalStorageAppDataDirs(packageName);
     }
-    
+
     /**
      * Generates the raw path to an application's media
      * @hide
@@ -525,7 +580,7 @@
         throwIfUserRequired();
         return sCurrentUser.buildExternalStorageAppMediaDirs(packageName);
     }
-    
+
     /**
      * Generates the raw path to an application's OBB files
      * @hide
@@ -534,7 +589,7 @@
         throwIfUserRequired();
         return sCurrentUser.buildExternalStorageAppObbDirs(packageName);
     }
-    
+
     /**
      * Generates the path to an application's files.
      * @hide
@@ -552,7 +607,7 @@
         throwIfUserRequired();
         return sCurrentUser.buildExternalStorageAppCacheDirs(packageName);
     }
-    
+
     /**
      * Return the download/cache content directory.
      */
@@ -645,7 +700,7 @@
 
     /**
      * Returns the current state of the primary shared/external storage media.
-     * 
+     *
      * @see #getExternalStorageDirectory()
      * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED},
      *         {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING},
diff --git a/core/java/android/os/HardwarePropertiesManager.java b/core/java/android/os/HardwarePropertiesManager.java
new file mode 100644
index 0000000..bc317b6
--- /dev/null
+++ b/core/java/android/os/HardwarePropertiesManager.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.annotation.IntDef;
+import android.annotation.NonNull;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+
+/**
+ * The HardwarePropertiesManager class provides a mechanism of accessing hardware state of a
+ * device: CPU, GPU and battery temperatures, CPU usage per core, fan speed, etc.
+ */
+public class HardwarePropertiesManager {
+
+    private static final String TAG = HardwarePropertiesManager.class.getSimpleName();
+
+    private static native void nativeInit();
+
+    private static native float[] nativeGetFanSpeeds();
+    private static native float[] nativeGetDeviceTemperatures(int type);
+    private static native CpuUsageInfo[] nativeGetCpuUsages();
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+        DEVICE_TEMPERATURE_CPU, DEVICE_TEMPERATURE_GPU, DEVICE_TEMPERATURE_BATTERY
+    })
+    public @interface DeviceTemperatureType {}
+
+    /**
+     * Device temperature types. These must match the values in
+     * frameworks/native/include/hardwareproperties/HardwarePropertiesManager.h
+     */
+    /** Temperature of CPUs in Celsius. */
+    public static final int DEVICE_TEMPERATURE_CPU = 0;
+
+    /** Temperature of GPUs in Celsius. */
+    public static final int DEVICE_TEMPERATURE_GPU = 1;
+
+    /** Temperature of battery in Celsius. */
+    public static final int DEVICE_TEMPERATURE_BATTERY = 2;
+
+    /** @hide */
+    public HardwarePropertiesManager() {
+        nativeInit();
+    }
+
+    /**
+     * 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.
+     *         Empty if platform doesn't provide the queried temperature.
+     *
+     * @throws IllegalArgumentException if an incorrect temperature type is queried.
+    */
+    public @NonNull float[] getDeviceTemperatures(@DeviceTemperatureType int type) {
+        switch (type) {
+        case DEVICE_TEMPERATURE_CPU:
+        case DEVICE_TEMPERATURE_GPU:
+        case DEVICE_TEMPERATURE_BATTERY:
+            return nativeGetDeviceTemperatures(type);
+        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.
+     *         Empty if CPU usage is not supported on this system.
+     */
+    public @NonNull CpuUsageInfo[] getCpuUsages() {
+        return nativeGetCpuUsages();
+    }
+
+    /**
+     * Return an array of fan speeds in RPM.
+     *
+     * @return an arrat of float fan speeds. Empty if there is no fans or fan speed
+     *         not supported on this system.
+     */
+    public @NonNull float[] getFanSpeeds() {
+        return nativeGetFanSpeeds();
+    }
+}
diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl
index 7a1a6a2..838279b 100644
--- a/core/java/android/os/IDeviceIdleController.aidl
+++ b/core/java/android/os/IDeviceIdleController.aidl
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.os.IMaintenanceActivityListener;
 import android.os.UserHandle;
 
 /** @hide */
@@ -37,4 +38,6 @@
     void exitIdle(String reason);
     void downloadServiceActive(IBinder token);
     void downloadServiceInactive();
+    boolean registerMaintenanceActivityListener(IMaintenanceActivityListener listener);
+    void unregisterMaintenanceActivityListener(IMaintenanceActivityListener listener);
 }
diff --git a/core/java/android/os/IMaintenanceActivityListener.aidl b/core/java/android/os/IMaintenanceActivityListener.aidl
new file mode 100644
index 0000000..6a2581f
--- /dev/null
+++ b/core/java/android/os/IMaintenanceActivityListener.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.os;
+
+/** @hide */
+oneway interface IMaintenanceActivityListener {
+    void onMaintenanceActivityChanged(boolean active);
+}
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 9ee6228..bc2566b 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -18,6 +18,7 @@
 package android.os;
 
 import android.os.Bundle;
+import android.os.PersistableBundle;
 import android.content.pm.UserInfo;
 import android.content.RestrictionEntry;
 import android.graphics.Bitmap;
@@ -35,7 +36,7 @@
 
     UserInfo createUser(in String name, int flags);
     UserInfo createProfileForUser(in String name, int flags, int userHandle);
-    UserInfo createRestrictedProfile(String name, int parentUserId);
+    UserInfo createRestrictedProfile(String name, int parentUserHandle);
     void setUserEnabled(int userHandle);
     boolean removeUser(int userHandle);
     void setUserName(int userHandle, String name);
@@ -44,21 +45,21 @@
     UserInfo getPrimaryUser();
     List<UserInfo> getUsers(boolean excludeDying);
     List<UserInfo> getProfiles(int userHandle, boolean enabledOnly);
-    boolean canAddMoreManagedProfiles(int userId, boolean allowedToRemoveOne);
+    boolean canAddMoreManagedProfiles(int userHandle, boolean allowedToRemoveOne);
     UserInfo getProfileParent(int userHandle);
-    boolean isSameProfileGroup(int userId, int otherUserId);
+    boolean isSameProfileGroup(int userHandle, int otherUserHandle);
     UserInfo getUserInfo(int userHandle);
-    String getUserAccount(int userId);
-    void setUserAccount(int userId, String accountName);
+    String getUserAccount(int userHandle);
+    void setUserAccount(int userHandle, String accountName);
     long getUserCreationTime(int userHandle);
     boolean isRestricted();
-    boolean canHaveRestrictedProfile(int userId);
+    boolean canHaveRestrictedProfile(int userHandle);
     int getUserSerialNumber(int userHandle);
     int getUserHandle(int userSerialNumber);
     Bundle getUserRestrictions(int userHandle);
     boolean hasBaseUserRestriction(String restrictionKey, int userHandle);
     boolean hasUserRestriction(in String restrictionKey, int userHandle);
-    void setUserRestriction(String key, boolean value, int userId);
+    void setUserRestriction(String key, boolean value, int userHandle);
     void setApplicationRestrictions(in String packageName, in Bundle restrictions,
             int userHandle);
     Bundle getApplicationRestrictions(in String packageName);
@@ -68,4 +69,11 @@
     boolean markGuestForDeletion(int userHandle);
     void setQuietModeEnabled(int userHandle, boolean enableQuietMode);
     boolean isQuietModeEnabled(int userHandle);
+    void setSeedAccountData(int userHandle, in String accountName,
+            in String accountType, in PersistableBundle accountOptions, boolean persist);
+    String getSeedAccountName();
+    String getSeedAccountType();
+    PersistableBundle getSeedAccountOptions();
+    void clearSeedAccountData();
+    boolean someUserHasSeedAccount(in String accountName, in String accountType);
 }
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 9b68f90..2631247 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -204,6 +204,7 @@
     private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];
     private static final Parcel[] sHolderPool = new Parcel[POOL_SIZE];
 
+    // Keep in sync with frameworks/native/libs/binder/PersistableBundle.cpp.
     private static final int VAL_NULL = -1;
     private static final int VAL_STRING = 0;
     private static final int VAL_INTEGER = 1;
@@ -704,6 +705,8 @@
             writeInt(-1);
             return;
         }
+        // Keep the format of this Parcel in sync with writeToParcelInner() in
+        // frameworks/native/libs/binder/PersistableBundle.cpp.
         final int N = val.size();
         writeInt(N);
         if (DEBUG_ARRAY_MAP) {
@@ -1370,7 +1373,13 @@
             // Must be before Parcelable
             writeInt(VAL_BUNDLE);
             writeBundle((Bundle) v);
+        } else if (v instanceof PersistableBundle) {
+            writeInt(VAL_PERSISTABLEBUNDLE);
+            writePersistableBundle((PersistableBundle) v);
         } else if (v instanceof Parcelable) {
+            // IMPOTANT: cases for classes that implement Parcelable must
+            // come before the Parcelable case, so that their specific VAL_*
+            // types will be written.
             writeInt(VAL_PARCELABLE);
             writeParcelable((Parcelable) v, 0);
         } else if (v instanceof Short) {
@@ -1426,9 +1435,6 @@
         } else if (v instanceof Byte) {
             writeInt(VAL_BYTE);
             writeInt((Byte) v);
-        } else if (v instanceof PersistableBundle) {
-            writeInt(VAL_PERSISTABLEBUNDLE);
-            writePersistableBundle((PersistableBundle) v);
         } else if (v instanceof Size) {
             writeInt(VAL_SIZE);
             writeSize((Size) v);
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 135f369..d5491d3 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -233,6 +233,19 @@
         final FileDescriptor fd = openInternal(file, mode);
         if (fd == null) return null;
 
+        return fromFd(fd, handler, listener);
+    }
+
+    /** {@hide} */
+    public static ParcelFileDescriptor fromFd(
+            FileDescriptor fd, Handler handler, final OnCloseListener listener) throws IOException {
+        if (handler == null) {
+            throw new IllegalArgumentException("Handler must not be null");
+        }
+        if (listener == null) {
+            throw new IllegalArgumentException("Listener must not be null");
+        }
+
         final FileDescriptor[] comm = createCommSocketPair();
         final ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd, comm[0]);
         final MessageQueue queue = handler.getLooper().getQueue();
diff --git a/core/java/android/os/PersistableBundle.aidl b/core/java/android/os/PersistableBundle.aidl
deleted file mode 100644
index 5b05873..0000000
--- a/core/java/android/os/PersistableBundle.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
-**
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
-
-package android.os;
-
-parcelable PersistableBundle;
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index a0a0060..314b7d5 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -219,6 +219,15 @@
     public static final int DRAW_WAKE_LOCK = 0x00000080;
 
     /**
+     * Wake lock level: Enables Sustained Performance Mode.
+     * <p>
+     * This is used by Gaming and VR applications to ensure the device provides
+     * will provide consistent performance over a large amount of time.
+     * </p>
+     */
+    public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 0x00000100;
+
+    /**
      * Mask for the wake lock level component of a combined wake lock level and flags integer.
      *
      * @hide
@@ -389,6 +398,13 @@
     public static final String REBOOT_RECOVERY = "recovery";
 
     /**
+     * The value to pass as the 'reason' argument to reboot() when device owner requests a reboot on
+     * the device.
+     * @hide
+     */
+    public static final String REBOOT_REQUESTED_BY_DEVICE_OWNER = "deviceowner";
+
+    /**
      * The value to pass as the 'reason' argument to android_reboot().
      * @hide
      */
@@ -518,6 +534,7 @@
             case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
             case DOZE_WAKE_LOCK:
             case DRAW_WAKE_LOCK:
+            case SUSTAINED_PERFORMANCE_WAKE_LOCK:
                 break;
             default:
                 throw new IllegalArgumentException("Must specify a valid wake lock level.");
@@ -973,6 +990,14 @@
             = "android.os.action.POWER_SAVE_MODE_CHANGED";
 
     /**
+     * Intent that is broadcast when the state of {@link #isPowerSaveMode()} changes.
+     * @hide
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL
+            = "android.os.action.POWER_SAVE_MODE_CHANGED_INTERNAL";
+
+    /**
      * Intent that is broadcast when the state of {@link #isDeviceIdleMode()} changes.
      * This broadcast is only sent to registered receivers.
      */
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index eca2c3b..1552a3c 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -150,6 +150,12 @@
     public static final int AUDIOSERVER_UID = 1041;
 
     /**
+     * Defines the UID/GID for the cameraserver process
+     * @hide
+     */
+    public static final int CAMERASERVER_UID = 1046;
+
+    /**
      * Defines the start of a range of UIDs (and GIDs), going from this
      * number to {@link #LAST_APPLICATION_UID} that are reserved for assigning
      * to applications.
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index 13b8b66..2ba4aa4 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -112,8 +112,10 @@
 
     /**
      * Return a list of all currently running services.
+     * @return an array of all currently running services, or <code>null</code> in
+     * case of an exception
      */
-    public static String[] listServices() throws RemoteException {
+    public static String[] listServices() {
         try {
             return getIServiceManager().listServices();
         } catch (RemoteException e) {
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index f946ca7..344d06e 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -16,7 +16,10 @@
 
 package android.os;
 
+import android.annotation.AppIdInt;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.annotation.UserIdInt;
 
 import java.io.PrintWriter;
 
@@ -30,13 +33,13 @@
     public static final int PER_USER_RANGE = 100000;
 
     /** @hide A user id to indicate all users on the device */
-    public static final int USER_ALL = -1;
+    public static final @UserIdInt int USER_ALL = -1;
 
     /** @hide A user handle to indicate all users on the device */
     public static final UserHandle ALL = new UserHandle(USER_ALL);
 
     /** @hide A user id to indicate the currently active user */
-    public static final int USER_CURRENT = -2;
+    public static final @UserIdInt int USER_CURRENT = -2;
 
     /** @hide A user handle to indicate the current user of the device */
     public static final UserHandle CURRENT = new UserHandle(USER_CURRENT);
@@ -44,7 +47,7 @@
     /** @hide A user id to indicate that we would like to send to the current
      *  user, but if this is calling from a user process then we will send it
      *  to the caller's user instead of failing with a security exception */
-    public static final int USER_CURRENT_OR_SELF = -3;
+    public static final @UserIdInt int USER_CURRENT_OR_SELF = -3;
 
     /** @hide A user handle to indicate that we would like to send to the current
      *  user, but if this is calling from a user process then we will send it
@@ -52,14 +55,14 @@
     public static final UserHandle CURRENT_OR_SELF = new UserHandle(USER_CURRENT_OR_SELF);
 
     /** @hide An undefined user id */
-    public static final int USER_NULL = -10000;
+    public static final @UserIdInt int USER_NULL = -10000;
 
     /**
      * @hide A user id constant to indicate the "owner" user of the device
      * @deprecated Consider using either {@link UserHandle#USER_SYSTEM} constant or
      * check the target user's flag {@link android.content.pm.UserInfo#isAdmin}.
      */
-    public static final int USER_OWNER = 0;
+    public static final @UserIdInt int USER_OWNER = 0;
 
     /**
      * @hide A user handle to indicate the primary/owner user of the device
@@ -69,7 +72,7 @@
     public static final UserHandle OWNER = new UserHandle(USER_OWNER);
 
     /** @hide A user id constant to indicate the "system" user of the device */
-    public static final int USER_SYSTEM = 0;
+    public static final @UserIdInt int USER_SYSTEM = 0;
 
     /** @hide A user handle to indicate the "system" user of the device */
     public static final UserHandle SYSTEM = new UserHandle(USER_SYSTEM);
@@ -127,7 +130,7 @@
      * Returns the user id for a given uid.
      * @hide
      */
-    public static int getUserId(int uid) {
+    public static @UserIdInt int getUserId(int uid) {
         if (MU_ENABLED) {
             return uid / PER_USER_RANGE;
         } else {
@@ -136,12 +139,13 @@
     }
 
     /** @hide */
-    public static int getCallingUserId() {
+    public static @UserIdInt int getCallingUserId() {
         return getUserId(Binder.getCallingUid());
     }
 
     /** @hide */
-    public static UserHandle of(int userId) {
+    @SystemApi
+    public static UserHandle of(@UserIdInt int userId) {
         return userId == USER_SYSTEM ? SYSTEM : new UserHandle(userId);
     }
 
@@ -149,7 +153,7 @@
      * Returns the uid that is composed from the userId and the appId.
      * @hide
      */
-    public static int getUid(int userId, int appId) {
+    public static int getUid(@UserIdInt int userId, @AppIdInt int appId) {
         if (MU_ENABLED) {
             return userId * PER_USER_RANGE + (appId % PER_USER_RANGE);
         } else {
@@ -161,7 +165,8 @@
      * Returns the app id (or base uid) for a given uid, stripping out the user id from it.
      * @hide
      */
-    public static int getAppId(int uid) {
+    @TestApi
+    public static @AppIdInt int getAppId(int uid) {
         return uid % PER_USER_RANGE;
     }
 
@@ -169,7 +174,7 @@
      * Returns the gid shared between all apps with this userId.
      * @hide
      */
-    public static int getUserGid(int userId) {
+    public static int getUserGid(@UserIdInt int userId) {
         return getUid(userId, Process.SHARED_USER_GID);
     }
 
@@ -186,7 +191,7 @@
      * Returns the app id for a given shared app gid. Returns -1 if the ID is invalid.
      * @hide
      */
-    public static int getAppIdFromSharedAppGid(int gid) {
+    public static @AppIdInt int getAppIdFromSharedAppGid(int gid) {
         final int appId = getAppId(gid) + Process.FIRST_APPLICATION_UID
                 - Process.FIRST_SHARED_APPLICATION_GID;
         if (appId < 0 || appId >= Process.FIRST_SHARED_APPLICATION_GID) {
@@ -257,7 +262,7 @@
     }
 
     /** @hide */
-    public static int parseUserArg(String arg) {
+    public static @UserIdInt int parseUserArg(String arg) {
         int userId;
         if ("all".equals(arg)) {
             userId = UserHandle.USER_ALL;
@@ -279,7 +284,7 @@
      * @hide
      */
     @SystemApi
-    public static int myUserId() {
+    public static @UserIdInt int myUserId() {
         return getUserId(Process.myUid());
     }
 
@@ -315,7 +320,7 @@
      * @hide
      */
     @SystemApi
-    public int getIdentifier() {
+    public @UserIdInt int getIdentifier() {
         return mHandle;
     }
 
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index c5adafe..1ac798b 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -20,17 +20,21 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.annotation.UserIdInt;
+import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.storage.StorageManager;
 import android.provider.Settings;
 import android.util.Log;
 import android.view.WindowManager.LayoutParams;
@@ -56,6 +60,10 @@
      * Authenticator.
      * The default value is <code>false</code>.
      *
+     * <p>From {@link android.os.Build.VERSION_CODES#N} a profile or device owner app can still
+     * use {@link android.accounts.AccountManager} APIs to add or remove accounts when account
+     * management is disallowed.
+     *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
      * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
@@ -512,6 +520,31 @@
     public static final String DISALLOW_CAMERA = "no_camera";
 
     /**
+     * Specifies if a user is not allowed to use cellular data when roaming. This can only be set by
+     * device owners. The default value is <code>false</code>.
+     *
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_DATA_ROAMING = "no_data_roaming";
+
+    /**
+     * Specifies if a user is not allowed to change their icon. Device owner and profile owner
+     * can set this restriction. When it is set by device owner, only the target user will be
+     * affected. The default value is <code>false</code>.
+     *
+     * <p>Key for user restrictions.
+     *
+     * <p>Type: Boolean
+     *
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_SET_USER_ICON = "no_set_user_icon";
+
+    /**
      * Allows apps in the parent profile to handle web links from the managed profile.
      *
      * This user restriction has an effect only in a managed profile.
@@ -551,6 +584,37 @@
      */
     public static final String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
 
+    private static final String ACTION_CREATE_USER = "android.os.action.CREATE_USER";
+
+    /**
+     * Extra containing a name for the user being created. Optional parameter passed to
+     * ACTION_CREATE_USER activity.
+     * @hide
+     */
+    public static final String EXTRA_USER_NAME = "android.os.extra.USER_NAME";
+
+    /**
+     * Extra containing account name for the user being created. Optional parameter passed to
+     * ACTION_CREATE_USER activity.
+     * @hide
+     */
+    public static final String EXTRA_USER_ACCOUNT_NAME = "android.os.extra.USER_ACCOUNT_NAME";
+
+    /**
+     * Extra containing account type for the user being created. Optional parameter passed to
+     * ACTION_CREATE_USER activity.
+     * @hide
+     */
+    public static final String EXTRA_USER_ACCOUNT_TYPE = "android.os.extra.USER_ACCOUNT_TYPE";
+
+    /**
+     * Extra containing account-specific data for the user being created. Optional parameter passed
+     * to ACTION_CREATE_USER activity.
+     * @hide
+     */
+    public static final String EXTRA_USER_ACCOUNT_OPTIONS
+            = "android.os.extra.USER_ACCOUNT_OPTIONS";
+
     /** @hide */
     public static final int PIN_VERIFICATION_FAILED_INCORRECT = -3;
     /** @hide */
@@ -558,6 +622,20 @@
     /** @hide */
     public static final int PIN_VERIFICATION_SUCCESS = -1;
 
+    /**
+     * Error result indicating that this user is not allowed to add other users on this device.
+     * This is a result code returned from the activity created by the intent
+     * {@link #createUserCreationIntent(String, String, String, PersistableBundle)}.
+     */
+    public static final int USER_CREATION_FAILED_NOT_PERMITTED = Activity.RESULT_FIRST_USER;
+
+    /**
+     * Error result indicating that no more users can be created on this device.
+     * This is a result code returned from the activity created by the intent
+     * {@link #createUserCreationIntent(String, String, String, PersistableBundle)}.
+     */
+    public static final int USER_CREATION_FAILED_NO_MORE_USERS = Activity.RESULT_FIRST_USER + 1;
+
     /** @hide */
     public static UserManager get(Context context) {
         return (UserManager) context.getSystemService(Context.USER_SERVICE);
@@ -596,7 +674,7 @@
      * @return the user handle of this process.
      * @hide
      */
-    public int getUserHandle() {
+    public @UserIdInt int getUserHandle() {
         return UserHandle.myUserId();
     }
 
@@ -666,7 +744,7 @@
      * Returns whether the provided user is an admin user. There can be more than one admin
      * user.
      */
-    public boolean isUserAdmin(int userId) {
+    public boolean isUserAdmin(@UserIdInt int userId) {
         UserInfo user = getUserInfo(userId);
         return user != null && user.isAdmin();
     }
@@ -690,7 +768,7 @@
      * Checks if specified user can have restricted profile.
      * @hide
      */
-    public boolean canHaveRestrictedProfile(int userId) {
+    public boolean canHaveRestrictedProfile(@UserIdInt int userId) {
         try {
             return mService.canHaveRestrictedProfile(userId);
         } catch (RemoteException re) {
@@ -736,7 +814,7 @@
      * Returns whether the specified user is ephemeral.
      * @hide
      */
-    public boolean isUserEphemeral(int userId) {
+    public boolean isUserEphemeral(@UserIdInt int userId) {
         final UserInfo user = getUserInfo(userId);
         return user != null && user.isEphemeral();
     }
@@ -750,9 +828,13 @@
      * @param user The user to retrieve the running state for.
      */
     public boolean isUserRunning(UserHandle user) {
+        return isUserRunning(user.getIdentifier());
+    }
+
+    /** {@hide} */
+    public boolean isUserRunning(int userId) {
         try {
-            return ActivityManagerNative.getDefault().isUserRunning(
-                    user.getIdentifier(), 0);
+            return ActivityManagerNative.getDefault().isUserRunning(userId, 0);
         } catch (RemoteException e) {
             return false;
         }
@@ -852,12 +934,15 @@
      * @param user to retrieve the unlocked state for.
      */
     public boolean isUserUnlocked(UserHandle user) {
-        try {
-            return ActivityManagerNative.getDefault().isUserRunning(
-                    user.getIdentifier(), ActivityManager.FLAG_AND_UNLOCKED);
-        } catch (RemoteException e) {
-            return false;
-        }
+        return isUserUnlocked(user.getIdentifier());
+    }
+
+    /** {@hide} */
+    public boolean isUserUnlocked(@UserIdInt int userId) {
+        // TODO: eventually pivot this back to look at ActivityManager state,
+        // but there is race where we can start a non-encryption-aware launcher
+        // before that lifecycle has entered the running unlocked state.
+        return mContext.getSystemService(StorageManager.class).isUserKeyUnlocked(userId);
     }
 
     /**
@@ -867,7 +952,7 @@
      * @return the UserInfo object for a specific user.
      * @hide
      */
-    public UserInfo getUserInfo(int userHandle) {
+    public UserInfo getUserInfo(@UserIdInt int userHandle) {
         try {
             return mService.getUserInfo(userHandle);
         } catch (RemoteException re) {
@@ -1085,7 +1170,7 @@
      * @return the UserInfo object for the created user, or null if the user could not be created.
      * @hide
      */
-    public UserInfo createProfileForUser(String name, int flags, int userHandle) {
+    public UserInfo createProfileForUser(String name, int flags, @UserIdInt int userHandle) {
         try {
             return mService.createProfileForUser(name, flags, userHandle);
         } catch (RemoteException re) {
@@ -1119,13 +1204,149 @@
     }
 
     /**
+     * Returns an intent to create a user for the provided name and email address. The name
+     * and email address will be used when the setup process for the new user is started.
+     * If this device does not support multiple users, null is returned.
+     * <p/>
+     * The intent should be launched using startActivityForResult and the return result will
+     * indicate if the user consented to adding a new user and if the operation succeeded. Any
+     * errors in creating the user will be returned in the result code. If the user cancels the
+     * request, the return result will be {@link Activity#RESULT_CANCELED}. On success, the
+     * result code will be {@link Activity#RESULT_OK}.
+     * <p/>
+     * The new user is created but not initialized. After switching into the user for the first
+     * time, the preferred user name and account information are used by the setup process for that
+     * user.
+     *
+     * @param userName Optional name to assign to the user.
+     * @param accountName Optional email address that will be used by the setup wizard to initialize
+     *                    the user.
+     * @param accountType Optional account type for the account to be created. This is required
+     *                    if the account name is specified.
+     * @param accountOptions Optional bundle of data to be passed in during account creation in the
+     *                       new user via {@link AccountManager#addAccount(String, String, String[],
+     *                       Bundle, android.app.Activity, android.accounts.AccountManagerCallback,
+     *                       Handler)}.
+     * @return An Intent that can be launched from an Activity or null if creating users is not
+     *         supported on this device.
+     * @see #USER_CREATION_FAILED_NOT_PERMITTED
+     * @see #USER_CREATION_FAILED_NO_MORE_USERS
+     */
+    public static Intent createUserCreationIntent(@Nullable String userName,
+            @Nullable String accountName,
+            @Nullable String accountType, @Nullable PersistableBundle accountOptions) {
+        if (!supportsMultipleUsers() || getMaxSupportedUsers() < 2) {
+            return null;
+        }
+        Intent intent = new Intent(ACTION_CREATE_USER);
+        if (userName != null) {
+            intent.putExtra(EXTRA_USER_NAME, userName);
+        }
+        if (accountName != null && accountType == null) {
+            throw new IllegalArgumentException("accountType must be specified if accountName is "
+                    + "specified");
+        }
+        if (accountName != null) {
+            intent.putExtra(EXTRA_USER_ACCOUNT_NAME, accountName);
+        }
+        if (accountType != null) {
+            intent.putExtra(EXTRA_USER_ACCOUNT_TYPE, accountType);
+        }
+        if (accountOptions != null) {
+            intent.putExtra(EXTRA_USER_ACCOUNT_OPTIONS, accountOptions);
+        }
+        return intent;
+    }
+
+    /**
+     * @hide
+     *
+     * Returns the preferred account name for user creation. Requires MANAGE_USERS permission.
+     */
+    @SystemApi
+    public String getSeedAccountName() {
+        try {
+            return mService.getSeedAccountName();
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not get the seed account name", re);
+            return null;
+        }
+    }
+
+    /**
+     * @hide
+     *
+     * Returns the preferred account type for user creation. Requires MANAGE_USERS permission.
+     */
+    @SystemApi
+    public String getSeedAccountType() {
+        try {
+            return mService.getSeedAccountType();
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not get the seed account type", re);
+            return null;
+        }
+    }
+
+    /**
+     * @hide
+     *
+     * Returns the preferred account's options bundle for user creation. Requires MANAGE_USERS
+     * permission.
+     * @return Any options set by the requestor that created the user.
+     */
+    @SystemApi
+    public PersistableBundle getSeedAccountOptions() {
+        try {
+            return mService.getSeedAccountOptions();
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not get the seed account options", re);
+            return null;
+        }
+    }
+
+    /**
+     * @hide
+     *
+     * Called by a system activity to set the seed account information of a user created
+     * through the user creation intent.
+     * @param userId
+     * @param accountName
+     * @param accountType
+     * @param accountOptions
+     * @see #createUserCreationIntent(String, String, String, PersistableBundle)
+     */
+    public void setSeedAccountData(int userId, String accountName, String accountType,
+            PersistableBundle accountOptions) {
+        try {
+            mService.setSeedAccountData(userId, accountName, accountType, accountOptions,
+                    /* persist= */ true);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not set the seed account data", re);
+        }
+    }
+
+    /**
+     * @hide
+     * Clears the seed information used to create this user. Requires MANAGE_USERS permission.
+     */
+    @SystemApi
+    public void clearSeedAccountData() {
+        try {
+            mService.clearSeedAccountData();
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not clear the seed account data", re);
+        }
+    }
+
+    /**
      * @hide
      * Marks the guest user for deletion to allow a new guest to be created before deleting
      * the current user who is a guest.
      * @param userHandle
      * @return
      */
-    public boolean markGuestForDeletion(int userHandle) {
+    public boolean markGuestForDeletion(@UserIdInt int userHandle) {
         try {
             return mService.markGuestForDeletion(userHandle);
         } catch (RemoteException re) {
@@ -1142,7 +1363,7 @@
      * @param userHandle the id of the profile to enable
      * @hide
      */
-    public void setUserEnabled(int userHandle) {
+    public void setUserEnabled(@UserIdInt int userHandle) {
         try {
             mService.setUserEnabled(userHandle);
         } catch (RemoteException e) {
@@ -1161,7 +1382,7 @@
     /**
      * Returns information for all users on this device.
      * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
-     * @return the list of users that were created.
+     * @return the list of users that exist on the device.
      * @hide
      */
     public List<UserInfo> getUsers() {
@@ -1174,6 +1395,29 @@
     }
 
     /**
+     * Returns serial numbers of all users on this device.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+     *
+     * @param excludeDying specify if the list should exclude users being removed.
+     * @return the list of serial numbers of users that exist on the device.
+     * @hide
+     */
+    @SystemApi
+    public long[] getSerialNumbersOfUsers(boolean excludeDying) {
+        try {
+            List<UserInfo> users = mService.getUsers(excludeDying);
+            long[] result = new long[users.size()];
+            for (int i = 0; i < result.length; i++) {
+                result[i] = users.get(i).serialNumber;
+            }
+            return result;
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not get users list", re);
+            return null;
+        }
+    }
+
+    /**
      * @return the user's account name, null if not found.
      * @hide
      */
@@ -1181,7 +1425,7 @@
             Manifest.permission.INTERACT_ACROSS_USERS_FULL,
             Manifest.permission.MANAGE_USERS
     })
-    public @Nullable String getUserAccount(int userHandle) {
+    public @Nullable String getUserAccount(@UserIdInt int userHandle) {
         try {
             return mService.getUserAccount(userHandle);
         } catch (RemoteException re) {
@@ -1198,7 +1442,7 @@
             Manifest.permission.INTERACT_ACROSS_USERS_FULL,
             Manifest.permission.MANAGE_USERS
     })
-    public void setUserAccount(int userHandle, @Nullable String accountName) {
+    public void setUserAccount(@UserIdInt int userHandle, @Nullable String accountName) {
         try {
             mService.setUserAccount(userHandle, accountName);
         } catch (RemoteException re) {
@@ -1251,7 +1495,7 @@
      * @return true if more managed profiles can be added, false if limit has been reached.
      * @hide
      */
-    public boolean canAddMoreManagedProfiles(int userId, boolean allowedToRemoveOne) {
+    public boolean canAddMoreManagedProfiles(@UserIdInt int userId, boolean allowedToRemoveOne) {
         try {
             return mService.canAddMoreManagedProfiles(userId, allowedToRemoveOne);
         } catch (RemoteException re) {
@@ -1271,7 +1515,7 @@
      * @return the list of profiles.
      * @hide
      */
-    public List<UserInfo> getProfiles(int userHandle) {
+    public List<UserInfo> getProfiles(@UserIdInt int userHandle) {
         try {
             return mService.getProfiles(userHandle, false /* enabledOnly */);
         } catch (RemoteException re) {
@@ -1287,7 +1531,7 @@
      * @return true if the two user ids are in the same profile group.
      * @hide
      */
-    public boolean isSameProfileGroup(int userId, int otherUserId) {
+    public boolean isSameProfileGroup(@UserIdInt int userId, int otherUserId) {
         try {
             return mService.isSameProfileGroup(userId, otherUserId);
         } catch (RemoteException re) {
@@ -1306,7 +1550,7 @@
      * @return the list of profiles.
      * @hide
      */
-    public List<UserInfo> getEnabledProfiles(int userHandle) {
+    public List<UserInfo> getEnabledProfiles(@UserIdInt int userHandle) {
         try {
             return mService.getProfiles(userHandle, true /* enabledOnly */);
         } catch (RemoteException re) {
@@ -1344,7 +1588,7 @@
      *
      * @hide
      */
-    public int getCredentialOwnerProfile(int userHandle) {
+    public int getCredentialOwnerProfile(@UserIdInt int userHandle) {
         try {
             return mService.getCredentialOwnerProfile(userHandle);
         } catch (RemoteException re) {
@@ -1359,7 +1603,7 @@
      *
      * @hide
      */
-    public UserInfo getProfileParent(int userHandle) {
+    public UserInfo getProfileParent(@UserIdInt int userHandle) {
         try {
             return mService.getProfileParent(userHandle);
         } catch (RemoteException re) {
@@ -1375,7 +1619,7 @@
      * @param enableQuietMode Whether quiet mode should be enabled or disabled.
      * @hide
      */
-    public void setQuietModeEnabled(int userHandle, boolean enableQuietMode) {
+    public void setQuietModeEnabled(@UserIdInt int userHandle, boolean enableQuietMode) {
         try {
             mService.setQuietModeEnabled(userHandle, enableQuietMode);
         } catch (RemoteException e) {
@@ -1491,7 +1735,7 @@
      * @param userHandle the integer handle of the user, where 0 is the primary user.
      * @hide
      */
-    public boolean removeUser(int userHandle) {
+    public boolean removeUser(@UserIdInt int userHandle) {
         try {
             return mService.removeUser(userHandle);
         } catch (RemoteException re) {
@@ -1508,7 +1752,7 @@
      * @param name the new name for the user
      * @hide
      */
-    public void setUserName(int userHandle, String name) {
+    public void setUserName(@UserIdInt int userHandle, String name) {
         try {
             mService.setUserName(userHandle, name);
         } catch (RemoteException re) {
@@ -1522,7 +1766,7 @@
      * @param icon the bitmap to set as the photo.
      * @hide
      */
-    public void setUserIcon(int userHandle, Bitmap icon) {
+    public void setUserIcon(@UserIdInt int userHandle, Bitmap icon) {
         try {
             mService.setUserIcon(userHandle, icon);
         } catch (RemoteException re) {
@@ -1537,7 +1781,7 @@
      * @see com.android.internal.util.UserIcons#getDefaultUserIcon for a default.
      * @hide
      */
-    public Bitmap getUserIcon(int userHandle) {
+    public Bitmap getUserIcon(@UserIdInt int userHandle) {
         try {
             ParcelFileDescriptor fd = mService.getUserIcon(userHandle);
             if (fd != null) {
@@ -1603,7 +1847,7 @@
      * @return a serial number associated with that user, or -1 if the userHandle is not valid.
      * @hide
      */
-    public int getUserSerialNumber(int userHandle) {
+    public int getUserSerialNumber(@UserIdInt int userHandle) {
         try {
             return mService.getUserSerialNumber(userHandle);
         } catch (RemoteException re) {
@@ -1621,7 +1865,7 @@
      * is not valid.
      * @hide
      */
-    public int getUserHandle(int userSerialNumber) {
+    public @UserIdInt int getUserHandle(int userSerialNumber) {
         try {
             return mService.getUserHandle(userSerialNumber);
         } catch (RemoteException re) {
@@ -1733,4 +1977,21 @@
             return 0;
         }
     }
+
+    /**
+     * @hide
+     * Checks if any uninitialized user has the specific seed account name and type.
+     *
+     * @param mAccountName The account name to check for
+     * @param mAccountType The account type of the account to check for
+     * @return whether the seed account was found
+     */
+    public boolean someUserHasSeedAccount(String accountName, String accountType) {
+        try {
+            return mService.someUserHasSeedAccount(accountName, accountType);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not check seed accounts", re);
+            return false;
+        }
+    }
 }
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java
index 898b6cf..58a0269 100644
--- a/core/java/android/os/UserManagerInternal.java
+++ b/core/java/android/os/UserManagerInternal.java
@@ -17,6 +17,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.graphics.Bitmap;
 
 /**
  * @hide Only for use within the system server.
@@ -81,4 +82,28 @@
      * whether the user is managed by profile owner.
      */
     public abstract void setUserManaged(int userId, boolean isManaged);
+
+    /**
+     * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to omit
+     * restriction check, because DevicePolicyManager must always be able to set user icon
+     * regardless of any restriction.
+     * Also called by {@link com.android.server.pm.UserManagerService} because the logic of setting
+     * the icon is in this method.
+     */
+    public abstract void setUserIcon(int userId, Bitmap bitmap);
+
+    /**
+     * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to inform the
+     * user manager whether all users should be created ephemeral.
+     */
+    public abstract void setForceEphemeralUsers(boolean forceEphemeralUsers);
+
+    /**
+     * Switches to the system user and deletes all other users.
+     *
+     * <p>Called by the {@link com.android.server.devicepolicy.DevicePolicyManagerService} when
+     * the force-ephemeral-users policy is toggled on to make sure there are no pre-existing
+     * non-ephemeral users left.
+     */
+    public abstract void removeAllUsers();
 }
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index beda169..c8b942b 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -882,7 +882,8 @@
                 }
                 packageName = packageNames[0];
             }
-            final int uid = ActivityThread.getPackageManager().getPackageUid(packageName, userId);
+            final int uid = ActivityThread.getPackageManager().getPackageUid(packageName,
+                    PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
             if (uid <= 0) {
                 return new StorageVolume[0];
             }
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index fda6326..ebb12fd 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -16,6 +16,7 @@
 
 package android.preference;
 
+import android.annotation.SystemApi;
 import android.annotation.XmlRes;
 import android.app.Activity;
 import android.content.Context;
@@ -24,8 +25,8 @@
 import android.content.SharedPreferences;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
 import android.content.res.XmlResourceParser;
 import android.os.Bundle;
 import android.util.Log;
@@ -110,7 +111,13 @@
      * managed by this instance.
      */
     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 int mStorage = STORAGE_DEFAULT;
+
     /**
      * The {@link PreferenceScreen} at the root of the preference hierarchy.
      */
@@ -343,6 +350,46 @@
     }
 
     /**
+     * Sets the storage location used internally by this class to be the default
+     * provided by the hosting {@link Context}.
+     */
+    public void setStorageDefault() {
+        mStorage = STORAGE_DEFAULT;
+        mSharedPreferences = null;
+    }
+
+    /**
+     * Explicitly set the storage location used internally by this class to be
+     * device-encrypted 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.
+     *
+     * @see Context#createDeviceEncryptedStorageContext()
+     */
+    public void setStorageDeviceEncrypted() {
+        mStorage = STORAGE_DEVICE_ENCRYPTED;
+        mSharedPreferences = null;
+    }
+
+    /**
+     * Explicitly set the storage location used internally by this class to be
+     * credential-encrypted storage.
+     *
+     * @see Context#createCredentialEncryptedStorageContext()
+     * @hide
+     */
+    @SystemApi
+    public void setStorageCredentialEncrypted() {
+        mStorage = STORAGE_CREDENTIAL_ENCRYPTED;
+        mSharedPreferences = null;
+    }
+
+    /**
      * Gets a SharedPreferences instance that preferences managed by this will
      * use.
      * 
@@ -351,7 +398,20 @@
      */
     public SharedPreferences getSharedPreferences() {
         if (mSharedPreferences == null) {
-            mSharedPreferences = mContext.getSharedPreferences(mSharedPreferencesName,
+            final Context storageContext;
+            switch (mStorage) {
+                case STORAGE_DEVICE_ENCRYPTED:
+                    storageContext = mContext.createDeviceEncryptedStorageContext();
+                    break;
+                case STORAGE_CREDENTIAL_ENCRYPTED:
+                    storageContext = mContext.createCredentialEncryptedStorageContext();
+                    break;
+                default:
+                    storageContext = mContext;
+                    break;
+            }
+
+            mSharedPreferences = storageContext.getSharedPreferences(mSharedPreferencesName,
                     mSharedPreferencesMode);
         }
         
diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl
index 8fa7ab9..9a80e37 100644
--- a/core/java/android/print/IPrintManager.aidl
+++ b/core/java/android/print/IPrintManager.aidl
@@ -16,6 +16,7 @@
 
 package android.print;
 
+import android.graphics.drawable.Icon;
 import android.os.Bundle;
 import android.print.IPrinterDiscoveryObserver;
 import android.print.IPrintDocumentAdapter;
@@ -53,6 +54,19 @@
     void stopPrinterDiscovery(in IPrinterDiscoveryObserver observer, int userId);
     void validatePrinters(in List<PrinterId> printerIds, int userId);
     void startPrinterStateTracking(in PrinterId printerId, int userId);
+
+    /**
+     * Get the custom icon for a printer. If the icon is not cached, the icon is
+     * requested asynchronously. Once it is available the printer is updated.
+     *
+     * @param printerId the id of the printer the icon should be loaded for
+     * @param userId the id of the user requesting the printer
+     * @return the custom icon to be used for the printer or null if the icon is
+     *         not yet available
+     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+     */
+    Icon getCustomPrinterIcon(in PrinterId printerId, int userId);
+
     void stopPrinterStateTracking(in PrinterId printerId, int userId);
     void destroyPrinterDiscoverySession(in IPrinterDiscoveryObserver observer,
             int userId);
diff --git a/core/java/android/print/IPrintSpooler.aidl b/core/java/android/print/IPrintSpooler.aidl
index b7cfbea..469a4ea 100644
--- a/core/java/android/print/IPrintSpooler.aidl
+++ b/core/java/android/print/IPrintSpooler.aidl
@@ -17,9 +17,11 @@
 package android.print;
 
 import android.content.ComponentName;
+import android.graphics.drawable.Icon;
 import android.os.ParcelFileDescriptor;
 import android.print.IPrintSpoolerClient;
 import android.print.IPrintSpoolerCallbacks;
+import android.print.PrinterId;
 import android.print.PrinterInfo;
 import android.print.PrintAttributes;
 import android.print.PrintJobId;
@@ -58,10 +60,49 @@
      */
     void setStatus(in PrintJobId printJobId, in CharSequence status);
 
+    /**
+     * Handle that a custom icon for a printer was loaded.
+     *
+     * @param printerId the id of the printer the icon belongs to
+     * @param icon the icon that was loaded
+     * @param callbacks the callback to call once icon is stored in case
+     * @param sequence the sequence number of the call
+     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+     */
+    void onCustomPrinterIconLoaded(in PrinterId printerId, in Icon icon,
+            in IPrintSpoolerCallbacks callbacks, in int sequence);
+
+    /**
+     * Get the custom icon for a printer. If the icon is not cached, the icon is
+     * requested asynchronously. Once it is available the printer is updated.
+     *
+     * @param printerId the id of the printer the icon should be loaded for
+     * @param callbacks the callback to call once icon is retrieved
+     * @param sequence the sequence number of the call
+     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+     */
+    void getCustomPrinterIcon(in PrinterId printerId,
+            in IPrintSpoolerCallbacks callbacks, in int sequence);
+
+    /**
+     * Clear all state from the custom printer icon cache.
+     *
+     * @param callbacks the callback to call once cache is cleared
+     * @param sequence the sequence number of the call
+     */
+    void clearCustomPrinterIconCache(in IPrintSpoolerCallbacks callbacks,
+            in int sequence);
+
     void setPrintJobTag(in PrintJobId printJobId, String tag, IPrintSpoolerCallbacks callback,
             int sequence);
     void writePrintJobData(in ParcelFileDescriptor fd, in PrintJobId printJobId);
     void setClient(IPrintSpoolerClient client);
     void setPrintJobCancelling(in PrintJobId printJobId, boolean cancelling);
-    void removeApprovedPrintService(in ComponentName serviceToRemove);
+
+    /**
+     * Remove all approved print services that are not in the given set.
+     *
+     * @param servicesToKeep The names of the services to keep
+     */
+    void pruneApprovedPrintServices(in List<ComponentName> servicesToKeep);
 }
diff --git a/core/java/android/print/IPrintSpoolerCallbacks.aidl b/core/java/android/print/IPrintSpoolerCallbacks.aidl
index 45c5332..23d706a 100644
--- a/core/java/android/print/IPrintSpoolerCallbacks.aidl
+++ b/core/java/android/print/IPrintSpoolerCallbacks.aidl
@@ -16,7 +16,9 @@
 
 package android.print;
 
+import android.graphics.drawable.Icon;
 import android.print.PrintJobInfo;
+import android.print.PrinterId;
 import java.util.List;
 
 /**
@@ -32,4 +34,27 @@
     void onSetPrintJobStateResult(boolean success, int sequence);
     void onSetPrintJobTagResult(boolean success, int sequence);
     void onGetPrintJobInfoResult(in PrintJobInfo printJob, int sequence);
+
+    /**
+     * Deliver the result of a request of a custom printer icon.
+     *
+     * @param icon the icon that was retrieved, or null if no icon could be
+     *             found
+     * @param sequence the sequence number of the call to get the icon
+     */
+    void onGetCustomPrinterIconResult(in Icon icon, int sequence);
+
+    /**
+     * Declare that the print spooler cached a custom printer icon.
+     *
+     * @param sequence the sequence number of the call to cache the icon
+     */
+    void onCustomPrinterIconCached(int sequence);
+
+    /**
+     * Declare that the custom printer icon cache was cleared.
+     *
+     * @param sequence the sequence number of the call to clear the cache
+     */
+    void customPrinterIconCacheCleared(int sequence);
 }
diff --git a/core/java/android/print/PageRange.java b/core/java/android/print/PageRange.java
index 8bc157a..57c7718 100644
--- a/core/java/android/print/PageRange.java
+++ b/core/java/android/print/PageRange.java
@@ -16,6 +16,8 @@
 
 package android.print;
 
+import android.annotation.IntRange;
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -42,7 +44,7 @@
      * @throws IllegalArgumentException If start is less than zero or end
      * is less than zero or start greater than end.
      */
-    public PageRange(int start, int end) {
+    public PageRange(@IntRange(from = 0) int start, @IntRange(from = 0) int end) {
         if (start < 0) {
             throw new IllegalArgumentException("start cannot be less than zero.");
         }
@@ -56,7 +58,7 @@
         mEnd = end;
     }
 
-    private PageRange (Parcel parcel) {
+    private PageRange(@NonNull Parcel parcel) {
         this(parcel.readInt(), parcel.readInt());
     }
 
@@ -65,7 +67,7 @@
      *
      * @return The start page index.
      */
-    public int getStart() {
+    public @IntRange(from = 0) int getStart() {
         return mStart;
     }
 
@@ -74,7 +76,7 @@
      *
      * @return The end page index.
      */
-    public int getEnd() {
+    public @IntRange(from = 0) int getEnd() {
         return mEnd;
     }
 
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index 2afbb99..8892e34 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -16,6 +16,10 @@
 
 package android.print;
 
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources.NotFoundException;
@@ -27,6 +31,8 @@
 
 import com.android.internal.R;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Map;
 
 /**
@@ -37,6 +43,13 @@
  * 10 mills (thousand of an inch) on all sides, and be black and white.
  */
 public final class PrintAttributes implements Parcelable {
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, value = {
+            COLOR_MODE_MONOCHROME, COLOR_MODE_COLOR
+    })
+    public @interface ColorMode {
+    }
     /** Color mode: Monochrome color scheme, for example one color is used. */
     public static final int COLOR_MODE_MONOCHROME = 1 << 0;
     /** Color mode: Color color scheme, for example many colors are used. */
@@ -45,6 +58,13 @@
     private static final int VALID_COLOR_MODES =
             COLOR_MODE_MONOCHROME | COLOR_MODE_COLOR;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, value = {
+            DUPLEX_MODE_NONE, DUPLEX_MODE_LONG_EDGE, DUPLEX_MODE_SHORT_EDGE
+    })
+    public @interface DuplexMode {
+    }
     /** Duplex mode: No duplexing. */
     public static final int DUPLEX_MODE_NONE = 1 << 0;
     /** Duplex mode: Pages are turned sideways along the long edge - like a book. */
@@ -66,7 +86,7 @@
         /* hide constructor */
     }
 
-    private PrintAttributes(Parcel parcel) {
+    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;
@@ -79,7 +99,7 @@
      *
      * @return The media size or <code>null</code> if not set.
      */
-    public MediaSize getMediaSize() {
+    public @Nullable MediaSize getMediaSize() {
         return mMediaSize;
     }
 
@@ -99,7 +119,7 @@
      *
      * @return The resolution or <code>null</code> if not set.
      */
-    public Resolution getResolution() {
+    public @Nullable Resolution getResolution() {
         return mResolution;
     }
 
@@ -127,7 +147,7 @@
      *
      * @return The margins or <code>null</code> if not set.
      */
-    public Margins getMinMargins() {
+    public @Nullable Margins getMinMargins() {
         return mMinMargins;
     }
 
@@ -158,7 +178,7 @@
      * @see #COLOR_MODE_COLOR
      * @see #COLOR_MODE_MONOCHROME
      */
-    public int getColorMode() {
+    public @ColorMode int getColorMode() {
         return mColorMode;
     }
 
@@ -199,7 +219,7 @@
      * @see #DUPLEX_MODE_LONG_EDGE
      * @see #DUPLEX_MODE_SHORT_EDGE
      */
-    public int getDuplexMode() {
+    public @DuplexMode int getDuplexMode() {
         return mDuplexMode;
     }
 
@@ -828,7 +848,8 @@
          * or the widthMils is less than or equal to zero or the heightMils is less
          * than or equal to zero.
          */
-        public MediaSize(String id, String label, int widthMils, int heightMils) {
+        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.");
             }
@@ -872,7 +893,7 @@
          *
          * @return The unique media size id.
          */
-        public String getId() {
+        public @NonNull String getId() {
             return mId;
         }
 
@@ -882,7 +903,7 @@
          * @param packageManager The package manager for loading the label.
          * @return The human readable label.
          */
-        public String getLabel(PackageManager packageManager) {
+        public @NonNull String getLabel(@NonNull PackageManager packageManager) {
             if (!TextUtils.isEmpty(mPackageName) && mLabelResId > 0) {
                 try {
                     return packageManager.getResourcesForApplication(
@@ -903,7 +924,7 @@
          *
          * @return The media width.
          */
-        public int getWidthMils() {
+        public @IntRange(from = 1) int getWidthMils() {
             return mWidthMils;
         }
 
@@ -912,7 +933,7 @@
          *
          * @return The media height.
          */
-        public int getHeightMils() {
+        public @IntRange(from = 1) int getHeightMils() {
             return mHeightMils;
         }
 
@@ -934,7 +955,7 @@
          * @return New instance in landscape orientation if this one
          * is in landscape, otherwise this instance.
          */
-        public MediaSize asPortrait() {
+        public @NonNull MediaSize asPortrait() {
             if (isPortrait()) {
                 return this;
             }
@@ -951,7 +972,7 @@
          * @return New instance in landscape orientation if this one
          * is in portrait, otherwise this instance.
          */
-        public MediaSize asLandscape() {
+        public @NonNull MediaSize asLandscape() {
             if (!isPortrait()) {
                 return this;
             }
@@ -1063,7 +1084,8 @@
          * or the horizontalDpi is less than or equal to zero or the verticalDpi is
          * less than or equal to zero.
          */
-        public Resolution(String id, String label, int horizontalDpi, int verticalDpi) {
+        public Resolution(@NonNull String id, @NonNull String label,
+                @IntRange(from = 1) int horizontalDpi, @IntRange(from = 1) int verticalDpi) {
             if (TextUtils.isEmpty(id)) {
                 throw new IllegalArgumentException("id cannot be empty.");
             }
@@ -1094,7 +1116,7 @@
          *
          * @return The unique resolution id.
          */
-        public String getId() {
+        public @NonNull String getId() {
             return mId;
         }
 
@@ -1103,7 +1125,7 @@
          *
          * @return The human readable label.
          */
-        public String getLabel() {
+        public @NonNull String getLabel() {
             return mLabel;
         }
 
@@ -1112,7 +1134,7 @@
          *
          * @return The horizontal resolution.
          */
-        public int getHorizontalDpi() {
+        public @IntRange(from = 1) int getHorizontalDpi() {
             return mHorizontalDpi;
         }
 
@@ -1121,7 +1143,7 @@
          *
          * @return The vertical resolution.
          */
-        public int getVerticalDpi() {
+        public @IntRange(from = 1) int getVerticalDpi() {
             return mVerticalDpi;
         }
 
@@ -1204,7 +1226,8 @@
          * @param rightMils The right margin in mils (thousands of an inch).
          * @param bottomMils The bottom margin in mils (thousands of an inch).
          */
-        public Margins(int leftMils, int topMils, int rightMils, int bottomMils) {
+        public Margins(@IntRange(from = 0) int leftMils, @IntRange(from = 0) int topMils,
+                @IntRange(from = 0) int rightMils, @IntRange(from = 0) int bottomMils) {
             mTopMils = topMils;
             mLeftMils = leftMils;
             mRightMils = rightMils;
@@ -1216,7 +1239,7 @@
          *
          * @return The left margin.
          */
-        public int getLeftMils() {
+        public @IntRange(from = 0) int getLeftMils() {
             return mLeftMils;
         }
 
@@ -1225,7 +1248,7 @@
          *
          * @return The top margin.
          */
-        public int getTopMils() {
+        public @IntRange(from = 0) int getTopMils() {
             return mTopMils;
         }
 
@@ -1234,7 +1257,7 @@
          *
          * @return The right margin.
          */
-        public int getRightMils() {
+        public @IntRange(from = 0) int getRightMils() {
             return mRightMils;
         }
 
@@ -1243,7 +1266,7 @@
          *
          * @return The bottom margin.
          */
-        public int getBottomMils() {
+        public @IntRange(from = 0) int getBottomMils() {
             return mBottomMils;
         }
 
@@ -1368,7 +1391,7 @@
          * @param mediaSize The media size.
          * @return This builder.
          */
-        public Builder setMediaSize(MediaSize mediaSize) {
+        public @NonNull Builder setMediaSize(@NonNull MediaSize mediaSize) {
             mAttributes.setMediaSize(mediaSize);
             return this;
         }
@@ -1379,7 +1402,7 @@
          * @param resolution The resolution.
          * @return This builder.
          */
-        public Builder setResolution(Resolution resolution) {
+        public @NonNull Builder setResolution(@NonNull Resolution resolution) {
             mAttributes.setResolution(resolution);
             return this;
         }
@@ -1391,7 +1414,7 @@
          * @param margins The margins.
          * @return This builder.
          */
-        public Builder setMinMargins(Margins margins) {
+        public @NonNull Builder setMinMargins(@NonNull Margins margins) {
             mAttributes.setMinMargins(margins);
             return this;
         }
@@ -1405,7 +1428,7 @@
          * @see PrintAttributes#COLOR_MODE_MONOCHROME
          * @see PrintAttributes#COLOR_MODE_COLOR
          */
-        public Builder setColorMode(int colorMode) {
+        public @NonNull Builder setColorMode(@ColorMode int colorMode) {
             mAttributes.setColorMode(colorMode);
             return this;
         }
@@ -1420,7 +1443,7 @@
          * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE
          * @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE
          */
-        public Builder setDuplexMode(int duplexMode) {
+        public @NonNull Builder setDuplexMode(@DuplexMode int duplexMode) {
             mAttributes.setDuplexMode(duplexMode);
             return this;
         }
@@ -1430,7 +1453,7 @@
          *
          * @return The new instance.
          */
-        public PrintAttributes build() {
+        public @NonNull PrintAttributes build() {
             return mAttributes;
         }
     }
diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java
index 44e6410..db3b6f4 100644
--- a/core/java/android/print/PrintDocumentInfo.java
+++ b/core/java/android/print/PrintDocumentInfo.java
@@ -16,10 +16,16 @@
 
 package android.print;
 
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * This class encapsulates information about a document for printing
  * purposes. This meta-data is used by the platform and print services,
@@ -74,6 +80,13 @@
      */
     public static final int PAGE_COUNT_UNKNOWN = -1;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            CONTENT_TYPE_UNKNOWN, CONTENT_TYPE_DOCUMENT, CONTENT_TYPE_PHOTO
+    })
+    public @interface ContentType {
+    }
     /**
      * Content type: unknown.
      */
@@ -116,9 +129,9 @@
     /**
      * Creates a new instance.
      *
-     * @param Prototype from which to clone.
+     * @param prototype from which to clone.
      */
-    private PrintDocumentInfo(PrintDocumentInfo prototype) {
+    private PrintDocumentInfo(@NonNull PrintDocumentInfo prototype) {
         mName = prototype.mName;
         mPageCount = prototype.mPageCount;
         mContentType = prototype.mContentType;
@@ -143,7 +156,7 @@
      *
      * @return The document name.
      */
-    public String getName() {
+    public @NonNull String getName() {
         return mName;
     }
 
@@ -154,7 +167,7 @@
      *
      * @see #PAGE_COUNT_UNKNOWN
      */
-    public int getPageCount() {
+    public @IntRange(from = -1) int getPageCount() {
         return mPageCount;
     }
 
@@ -167,7 +180,7 @@
      * @see #CONTENT_TYPE_DOCUMENT
      * @see #CONTENT_TYPE_PHOTO
      */
-    public int getContentType() {
+    public @ContentType int getContentType() {
         return mContentType;
     }
 
@@ -176,7 +189,7 @@
      *
      * @return The data size.
      */
-    public long getDataSize() {
+    public @IntRange(from = 0) long getDataSize() {
         return mDataSize;
     }
 
@@ -187,7 +200,7 @@
      *
      * @hide
      */
-    public void setDataSize(long dataSize) {
+    public void setDataSize(@IntRange(from = 0) long dataSize) {
         mDataSize = dataSize;
     }
 
@@ -288,7 +301,7 @@
          * is the file name if the content it describes is saved as a PDF.
          * Cannot be empty. 
          */
-        public Builder(String name) {
+        public Builder(@NonNull String name) {
             if (TextUtils.isEmpty(name)) {
                 throw new IllegalArgumentException("name cannot be empty");
             }
@@ -302,10 +315,11 @@
          * <strong>Default: </strong> {@link #PAGE_COUNT_UNKNOWN}
          * </p>
          *
-         * @param pageCount The number of pages. Must be greater than
-         * or equal to zero or {@link PrintDocumentInfo#PAGE_COUNT_UNKNOWN}.
+         * @param pageCount The number of pages. Must be greater than or equal to zero or
+         *            {@link PrintDocumentInfo#PAGE_COUNT_UNKNOWN}.
+         * @return This builder.
          */
-        public Builder setPageCount(int pageCount) {
+        public @NonNull Builder setPageCount(@IntRange(from = -1) int pageCount) {
             if (pageCount < 0 && pageCount != PAGE_COUNT_UNKNOWN) {
                 throw new IllegalArgumentException("pageCount"
                         + " must be greater than or equal to zero or"
@@ -322,12 +336,12 @@
          * </p>
          *
          * @param type The content type.
-         *
+         * @return This builder.
          * @see #CONTENT_TYPE_UNKNOWN
          * @see #CONTENT_TYPE_DOCUMENT
          * @see #CONTENT_TYPE_PHOTO
          */
-        public Builder setContentType(int type) {
+        public @NonNull Builder setContentType(@ContentType int type) {
             mPrototype.mContentType = type;
             return this;
         }
@@ -337,7 +351,7 @@
          *
          * @return The new instance.
          */
-        public PrintDocumentInfo build() {
+        public @NonNull PrintDocumentInfo build() {
             // Zero pages is the same as unknown as in this case
             // we will have to ask for all pages and look a the
             // wiritten PDF file for the page count.
diff --git a/core/java/android/print/PrintFileDocumentAdapter.java b/core/java/android/print/PrintFileDocumentAdapter.java
index 5d655bf..747400d 100644
--- a/core/java/android/print/PrintFileDocumentAdapter.java
+++ b/core/java/android/print/PrintFileDocumentAdapter.java
@@ -46,7 +46,7 @@
  */
 public class PrintFileDocumentAdapter extends PrintDocumentAdapter {
 
-    private static final String LOG_TAG = "PrintedFileDocumentAdapter";
+    private static final String LOG_TAG = "PrintedFileDocAdapter";
 
     private final Context mContext;
 
diff --git a/core/java/android/print/PrintJob.java b/core/java/android/print/PrintJob.java
index 0abe219..66181e0 100644
--- a/core/java/android/print/PrintJob.java
+++ b/core/java/android/print/PrintJob.java
@@ -16,6 +16,11 @@
 
 package android.print;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.util.Objects;
+
 /**
  * This class represents a print job from the perspective of an
  * application. It contains behavior methods for performing operations
@@ -27,11 +32,11 @@
  */
 public final class PrintJob {
 
-    private final PrintManager mPrintManager;
+    private final @NonNull PrintManager mPrintManager;
 
-    private PrintJobInfo mCachedInfo;
+    private @NonNull PrintJobInfo mCachedInfo;
 
-    PrintJob(PrintJobInfo info, PrintManager printManager) {
+    PrintJob(@NonNull PrintJobInfo info, @NonNull PrintManager printManager) {
         mCachedInfo = info;
         mPrintManager = printManager;
     }
@@ -41,7 +46,7 @@
      *
      * @return The id.
      */
-    public PrintJobId getId() {
+    public @Nullable PrintJobId getId() {
         return mCachedInfo.getId();
     }
 
@@ -55,7 +60,7 @@
      *
      * @return The print job info.
      */
-    public PrintJobInfo getInfo() {
+    public @NonNull PrintJobInfo getInfo() {
         if (isInImmutableState()) {
             return mCachedInfo;
         }
@@ -190,11 +195,17 @@
             return false;
         }
         PrintJob other = (PrintJob) obj;
-        return mCachedInfo.getId().equals(other.mCachedInfo.getId());
+        return Objects.equals(mCachedInfo.getId(), other.mCachedInfo.getId());
     }
 
     @Override
     public int hashCode() {
-        return mCachedInfo.getId().hashCode();
+        PrintJobId printJobId = mCachedInfo.getId();
+
+        if (printJobId == null) {
+            return 0;
+        } else {
+            return printJobId.hashCode();
+        }
     }
 }
diff --git a/core/java/android/print/PrintJobId.java b/core/java/android/print/PrintJobId.java
index 01550e2..186ae9b 100644
--- a/core/java/android/print/PrintJobId.java
+++ b/core/java/android/print/PrintJobId.java
@@ -16,9 +16,11 @@
 
 package android.print;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.text.TextUtils;
+
+import com.android.internal.util.Preconditions;
 
 import java.util.UUID;
 
@@ -26,7 +28,7 @@
  * This class represents the id of a print job.
  */
 public final class PrintJobId implements Parcelable {
-    private final String mValue;
+    private final @NonNull String mValue;
 
     /**
      * Creates a new instance.
@@ -44,7 +46,7 @@
      *
      * @hide
      */
-    public PrintJobId(String value) {
+    public PrintJobId(@NonNull String value) {
         mValue = value;
     }
 
@@ -52,7 +54,7 @@
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = prime * result + ((mValue != null) ? mValue.hashCode() : 0);
+        result = prime * result + mValue.hashCode();
         return result;
     }
 
@@ -68,7 +70,7 @@
             return false;
         }
         PrintJobId other = (PrintJobId) obj;
-        if (!TextUtils.equals(mValue, other.mValue)) {
+        if (!mValue.equals(other.mValue)) {
             return false;
         }
         return true;
@@ -91,19 +93,19 @@
      *
      * @hide
      */
-    public String flattenToString() {
+    public @NonNull String flattenToString() {
         return mValue;
     }
 
     /**
      * Unflattens a print job id from a string.
      *
-     * @string The string.
+     * @param string The string.
      * @return The unflattened id, or null if the string is malformed.
      *
      * @hide
      */
-    public static PrintJobId unflattenFromString(String string) {
+    public static @NonNull PrintJobId unflattenFromString(@NonNull String string) {
         return new PrintJobId(string);
     }
 
@@ -111,7 +113,7 @@
             new Parcelable.Creator<PrintJobId>() {
         @Override
         public PrintJobId createFromParcel(Parcel parcel) {
-            return new PrintJobId(parcel.readString());
+            return new PrintJobId(Preconditions.checkNotNull(parcel.readString()));
         }
 
         @Override
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index 7148c87..7e3a72f 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -17,6 +17,9 @@
 package android.print;
 
 import android.annotation.FloatRange;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.os.Bundle;
@@ -25,6 +28,8 @@
 
 import com.android.internal.util.Preconditions;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
 
 /**
@@ -35,6 +40,15 @@
  */
 public final class PrintJobInfo implements Parcelable {
 
+    /** @hide */
+    @IntDef({
+            STATE_CREATED, STATE_QUEUED, STATE_STARTED, STATE_BLOCKED, STATE_COMPLETED,
+            STATE_FAILED, STATE_CANCELED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface State {
+    }
+
     /**
      * Constant for matching any print job state.
      *
@@ -200,7 +214,7 @@
         mAdvancedOptions = other.mAdvancedOptions;
     }
 
-    private PrintJobInfo(Parcel parcel) {
+    private PrintJobInfo(@NonNull Parcel parcel) {
         mId = parcel.readParcelable(null);
         mLabel = parcel.readString();
         mPrinterId = parcel.readParcelable(null);
@@ -230,7 +244,7 @@
      *
      * @return The id.
      */
-    public PrintJobId getId() {
+    public @Nullable PrintJobId getId() {
         return mId;
     }
 
@@ -241,7 +255,7 @@
      *
      * @hide
      */
-    public void setId(PrintJobId id) {
+    public void setId(@NonNull PrintJobId id) {
         this.mId = id;
     }
 
@@ -250,7 +264,7 @@
      *
      * @return The label.
      */
-    public String getLabel() {
+    public @NonNull String getLabel() {
         return mLabel;
     }
 
@@ -261,7 +275,7 @@
      *
      * @hide
      */
-    public void setLabel(String label) {
+    public void setLabel(@NonNull String label) {
         mLabel = label;
     }
 
@@ -270,7 +284,7 @@
      *
      * @return The target printer id.
      */
-    public PrinterId getPrinterId() {
+    public @Nullable PrinterId getPrinterId() {
         return mPrinterId;
     }
 
@@ -281,7 +295,7 @@
      *
      * @hide
      */
-    public void setPrinterId(PrinterId printerId) {
+    public void setPrinterId(@NonNull PrinterId printerId) {
         mPrinterId = printerId;
     }
 
@@ -292,7 +306,7 @@
      *
      * @hide
      */
-    public String getPrinterName() {
+    public @Nullable String getPrinterName() {
         return mPrinterName;
     }
 
@@ -303,7 +317,7 @@
      *
      * @hide
      */
-    public void setPrinterName(String printerName) {
+    public void setPrinterName(@NonNull String printerName) {
         mPrinterName = printerName;
     }
 
@@ -320,7 +334,7 @@
      * @see #STATE_FAILED
      * @see #STATE_CANCELED
      */
-    public int getState() {
+    public @State int getState() {
         return mState;
     }
 
@@ -431,7 +445,7 @@
      *
      * @return The number of copies or zero if not set.
      */
-    public int getCopies() {
+    public @IntRange(from = 0) int getCopies() {
         return mCopies;
     }
 
@@ -454,7 +468,7 @@
      *
      * @return The included pages or <code>null</code> if not set.
      */
-    public PageRange[] getPages() {
+    public @Nullable PageRange[] getPages() {
         return mPageRanges;
     }
 
@@ -474,7 +488,7 @@
      *
      * @return The attributes.
      */
-    public PrintAttributes getAttributes() {
+    public @NonNull PrintAttributes getAttributes() {
         return mAttributes;
     }
 
@@ -713,7 +727,7 @@
          * @param prototype Prototype to use as a starting point.
          * Can be <code>null</code>.
          */
-        public Builder(PrintJobInfo prototype) {
+        public Builder(@Nullable PrintJobInfo prototype) {
             mPrototype = (prototype != null)
                     ? new PrintJobInfo(prototype)
                     : new PrintJobInfo();
@@ -724,7 +738,7 @@
          *
          * @param copies The number of copies.
          */
-        public void setCopies(int copies) {
+        public void setCopies(@IntRange(from = 1) int copies) {
             mPrototype.mCopies = copies;
         }
 
@@ -733,7 +747,7 @@
          *
          * @param attributes The attributes.
          */
-        public void setAttributes(PrintAttributes attributes) {
+        public void setAttributes(@NonNull PrintAttributes attributes) {
             mPrototype.mAttributes = attributes;
         }
 
@@ -742,7 +756,7 @@
          *
          * @param pages The included pages.
          */
-        public void setPages(PageRange[] pages) {
+        public void setPages(@NonNull PageRange[] pages) {
             mPrototype.mPageRanges = pages;
         }
 
@@ -774,7 +788,7 @@
          * @param key The option key.
          * @param value The option value.
          */
-        public void putAdvancedOption(String key, String value) {
+        public void putAdvancedOption(@NonNull String key, @Nullable String value) {
             if (mPrototype.mAdvancedOptions == null) {
                 mPrototype.mAdvancedOptions = new Bundle();
             }
@@ -787,7 +801,7 @@
          * @param key The option key.
          * @param value The option value.
          */
-        public void putAdvancedOption(String key, int value) {
+        public void putAdvancedOption(@NonNull String key, int value) {
             if (mPrototype.mAdvancedOptions == null) {
                 mPrototype.mAdvancedOptions = new Bundle();
             }
@@ -799,7 +813,7 @@
          *
          * @return The new instance.
          */
-        public PrintJobInfo build() {
+        public @NonNull PrintJobInfo build() {
             return mPrototype;
         }
     }
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 3fb812e..58f260c 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -16,11 +16,14 @@
 
 package android.print;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.Application.ActivityLifecycleCallbacks;
 import android.content.Context;
 import android.content.IntentSender;
 import android.content.IntentSender.SendIntentException;
+import android.graphics.drawable.Icon;
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.Handler;
@@ -180,6 +183,8 @@
      *
      * @param context The current context in which to operate.
      * @param service The backing system service.
+     * @param userId The user id in which to operate.
+     * @param appId The application id in which to operate.
      * @hide
      */
     public PrintManager(Context context, IPrintManager service, int userId, int appId) {
@@ -290,6 +295,7 @@
     /**
      * Gets a print job given its id.
      *
+     * @param printJobId The id of the print job.
      * @return The print job list.
      * @see PrintJob
      * @hide
@@ -311,12 +317,35 @@
     }
 
     /**
+     * Get the custom icon for a printer. If the icon is not cached, the icon is
+     * requested asynchronously. Once it is available the printer is updated.
+     *
+     * @param printerId the id of the printer the icon should be loaded for
+     * @return the custom icon to be used for the printer or null if the icon is
+     *         not yet available
+     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+     * @hide
+     */
+    public Icon getCustomPrinterIcon(PrinterId printerId) {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return null;
+        }
+        try {
+            return mService.getCustomPrinterIcon(printerId, mUserId);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error getting custom printer icon", re);
+        }
+        return null;
+    }
+
+    /**
      * Gets the print jobs for this application.
      *
      * @return The print job list.
      * @see PrintJob
      */
-    public List<PrintJob> getPrintJobs() {
+    public @NonNull List<PrintJob> getPrintJobs() {
         if (mService == null) {
             Log.w(LOG_TAG, "Feature android.software.print not available");
             return Collections.emptyList();
@@ -411,8 +440,9 @@
      *
      * @see PrintJob
      */
-    public PrintJob print(String printJobName, PrintDocumentAdapter documentAdapter,
-            PrintAttributes attributes) {
+    public @NonNull PrintJob print(@NonNull String printJobName,
+            @NonNull PrintDocumentAdapter documentAdapter,
+            @Nullable PrintAttributes attributes) {
         if (mService == null) {
             Log.w(LOG_TAG, "Feature android.software.print not available");
             return null;
@@ -505,7 +535,10 @@
         return new PrinterDiscoverySession(mService, mContext, mUserId);
     }
 
-    private static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub
+    /**
+     * @hide
+     */
+    public static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub
             implements ActivityLifecycleCallbacks {
         private final Object mLock = new Object();
 
@@ -1031,7 +1064,10 @@
         }
     }
 
-    private static final class PrintJobStateChangeListenerWrapper extends
+    /**
+     * @hide
+     */
+    public static final class PrintJobStateChangeListenerWrapper extends
             IPrintJobStateChangeListener.Stub {
         private final WeakReference<PrintJobStateChangeListener> mWeakListener;
         private final WeakReference<Handler> mWeakHandler;
diff --git a/core/java/android/print/PrinterCapabilitiesInfo.java b/core/java/android/print/PrinterCapabilitiesInfo.java
index 96f3185..d13879b 100644
--- a/core/java/android/print/PrinterCapabilitiesInfo.java
+++ b/core/java/android/print/PrinterCapabilitiesInfo.java
@@ -16,8 +16,11 @@
 
 package android.print;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.print.PrintAttributes.ColorMode;
+import android.print.PrintAttributes.DuplexMode;
 import android.print.PrintAttributes.Margins;
 import android.print.PrintAttributes.MediaSize;
 import android.print.PrintAttributes.Resolution;
@@ -121,7 +124,7 @@
      *
      * @return The media sizes.
      */
-    public List<MediaSize> getMediaSizes() {
+    public @NonNull List<MediaSize> getMediaSizes() {
         return Collections.unmodifiableList(mMediaSizes);
     }
 
@@ -130,7 +133,7 @@
      *
      * @return The resolutions.
      */
-    public List<Resolution> getResolutions() {
+    public @NonNull List<Resolution> getResolutions() {
         return Collections.unmodifiableList(mResolutions);
     }
 
@@ -140,7 +143,7 @@
      *
      * @return The minimal margins.
      */
-    public Margins getMinMargins() {
+    public @NonNull Margins getMinMargins() {
         return mMinMargins;
     }
 
@@ -152,7 +155,7 @@
      * @see PrintAttributes#COLOR_MODE_COLOR
      * @see PrintAttributes#COLOR_MODE_MONOCHROME
      */
-    public int getColorModes() {
+    public @ColorMode int getColorModes() {
         return mColorModes;
     }
 
@@ -165,7 +168,7 @@
      * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE
      * @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE
      */
-    public int getDuplexModes() {
+    public @DuplexMode int getDuplexModes() {
         return mDuplexModes;
     }
 
@@ -174,7 +177,7 @@
      *
      * @return The default attributes.
      */
-    public PrintAttributes getDefaults() {
+    public @NonNull PrintAttributes getDefaults() {
         PrintAttributes.Builder builder = new PrintAttributes.Builder();
 
         builder.setMinMargins(mMinMargins);
@@ -425,7 +428,7 @@
          *
          * @throws IllegalArgumentException If the printer id is <code>null</code>.
          */
-        public Builder(PrinterId printerId) {
+        public Builder(@NonNull PrinterId printerId) {
             if (printerId == null) {
                 throw new IllegalArgumentException("printerId cannot be null.");
             }
@@ -446,7 +449,7 @@
          *
          * @see PrintAttributes.MediaSize
          */
-        public Builder addMediaSize(MediaSize mediaSize, boolean isDefault) {
+        public @NonNull Builder addMediaSize(@NonNull MediaSize mediaSize, boolean isDefault) {
             if (mPrototype.mMediaSizes == null) {
                 mPrototype.mMediaSizes = new ArrayList<MediaSize>();
             }
@@ -474,7 +477,7 @@
          *
          * @see PrintAttributes.Resolution
          */
-        public Builder addResolution(Resolution resolution, boolean isDefault) {
+        public @NonNull Builder addResolution(@NonNull Resolution resolution, boolean isDefault) {
             if (mPrototype.mResolutions == null) {
                 mPrototype.mResolutions = new ArrayList<Resolution>();
             }
@@ -502,7 +505,7 @@
          *
          * @see PrintAttributes.Margins
          */
-        public Builder setMinMargins(Margins margins) {
+        public @NonNull Builder setMinMargins(@NonNull Margins margins) {
             if (margins == null) {
                 throw new IllegalArgumentException("margins cannot be null");
             }
@@ -532,7 +535,8 @@
          * @see PrintAttributes#COLOR_MODE_COLOR
          * @see PrintAttributes#COLOR_MODE_MONOCHROME
          */
-        public Builder setColorModes(int colorModes, int defaultColorMode) {
+        public @NonNull Builder setColorModes(@ColorMode int colorModes,
+                @ColorMode int defaultColorMode) {
             int currentModes = colorModes;
             while (currentModes > 0) {
                 final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes));
@@ -562,7 +566,8 @@
          * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE
          * @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE
          */
-        public Builder setDuplexModes(int duplexModes, int defaultDuplexMode) {
+        public @NonNull Builder setDuplexModes(@DuplexMode int duplexModes,
+                @DuplexMode int defaultDuplexMode) {
             int currentModes = duplexModes;
             while (currentModes > 0) {
                 final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes));
@@ -589,7 +594,7 @@
          *
          * @throws IllegalStateException If a required attribute was not specified.
          */
-        public PrinterCapabilitiesInfo build() {
+        public @NonNull PrinterCapabilitiesInfo build() {
             if (mPrototype.mMediaSizes == null || mPrototype.mMediaSizes.isEmpty()) {
                 throw new IllegalStateException("No media size specified.");
             }
diff --git a/core/java/android/print/PrinterDiscoverySession.java b/core/java/android/print/PrinterDiscoverySession.java
index abb441b..c587edd 100644
--- a/core/java/android/print/PrinterDiscoverySession.java
+++ b/core/java/android/print/PrinterDiscoverySession.java
@@ -16,6 +16,8 @@
 
 package android.print;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
 import android.os.Handler;
@@ -72,7 +74,7 @@
         }
     }
 
-    public final void startPrinterDiscovery(List<PrinterId> priorityList) {
+    public final void startPrinterDiscovery(@Nullable List<PrinterId> priorityList) {
         if (isDestroyed()) {
             Log.w(LOG_TAG, "Ignoring start printers discovery - session destroyed");
             return;
@@ -102,7 +104,7 @@
         }
     }
 
-    public final void startPrinterStateTracking(PrinterId printerId) {
+    public final void startPrinterStateTracking(@NonNull PrinterId printerId) {
         if (isDestroyed()) {
             Log.w(LOG_TAG, "Ignoring start printer state tracking - session destroyed");
             return;
@@ -114,7 +116,7 @@
         }
     }
 
-    public final void stopPrinterStateTracking(PrinterId printerId) {
+    public final void stopPrinterStateTracking(@NonNull PrinterId printerId) {
         if (isDestroyed()) {
             Log.w(LOG_TAG, "Ignoring stop printer state tracking - session destroyed");
             return;
@@ -285,7 +287,7 @@
         }
     }
 
-    private static final class PrinterDiscoveryObserver extends IPrinterDiscoveryObserver.Stub {
+    public static final class PrinterDiscoveryObserver extends IPrinterDiscoveryObserver.Stub {
 
         private final WeakReference<PrinterDiscoverySession> mWeakSession;
 
diff --git a/core/java/android/print/PrinterId.java b/core/java/android/print/PrinterId.java
index a3f3b2bf..ff9c0df 100644
--- a/core/java/android/print/PrinterId.java
+++ b/core/java/android/print/PrinterId.java
@@ -16,19 +16,21 @@
 
 package android.print;
 
+import android.annotation.NonNull;
 import android.content.ComponentName;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.text.TextUtils;
+
+import com.android.internal.util.Preconditions;
 
 /**
  * This class represents the unique id of a printer.
  */
 public final class PrinterId implements Parcelable {
 
-    private final ComponentName mServiceName;
+    private final @NonNull ComponentName mServiceName;
 
-    private final String mLocalId;
+    private final @NonNull String mLocalId;
 
     /**
      * Creates a new instance.
@@ -38,14 +40,14 @@
      *
      * @hide
      */
-    public PrinterId(ComponentName serviceName, String localId) {
+    public PrinterId(@NonNull ComponentName serviceName, @NonNull String localId) {
         mServiceName = serviceName;
         mLocalId = localId;
     }
 
-    private PrinterId(Parcel parcel) {
-        mServiceName = parcel.readParcelable(null);
-        mLocalId = parcel.readString();
+    private PrinterId(@NonNull Parcel parcel) {
+        mServiceName = Preconditions.checkNotNull((ComponentName) parcel.readParcelable(null));
+        mLocalId = Preconditions.checkNotNull(parcel.readString());
     }
 
     /**
@@ -55,7 +57,7 @@
      *
      * @hide
      */
-    public ComponentName getServiceName() {
+    public @NonNull ComponentName getServiceName() {
         return mServiceName;
     }
 
@@ -65,7 +67,7 @@
      *
      * @return The printer name.
      */
-    public String getLocalId() {
+    public @NonNull String getLocalId() {
         return mLocalId;
     }
 
@@ -92,14 +94,10 @@
             return false;
         }
         PrinterId other = (PrinterId) object;
-        if (mServiceName == null) {
-            if (other.mServiceName != null) {
-                return false;
-            }
-        } else if (!mServiceName.equals(other.mServiceName)) {
+        if (!mServiceName.equals(other.mServiceName)) {
             return false;
         }
-        if (!TextUtils.equals(mLocalId, other.mLocalId)) {
+        if (!mLocalId.equals(other.mLocalId)) {
             return false;
         }
         return true;
@@ -109,8 +107,7 @@
     public int hashCode() {
         final int prime = 31;
         int hashCode = 1;
-        hashCode = prime * hashCode + ((mServiceName != null)
-                ? mServiceName.hashCode() : 1);
+        hashCode = prime * hashCode + mServiceName.hashCode();
         hashCode = prime * hashCode + mLocalId.hashCode();
         return hashCode;
     }
diff --git a/core/java/android/print/PrinterInfo.java b/core/java/android/print/PrinterInfo.java
index 7fcc81f..0d2d9f4 100644
--- a/core/java/android/print/PrinterInfo.java
+++ b/core/java/android/print/PrinterInfo.java
@@ -16,10 +16,28 @@
 
 package android.print;
 
+import android.annotation.DrawableRes;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.TestApi;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
 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;
+
 /**
  * This class represents the description of a printer. Instances of
  * this class are created by print services to report to the system
@@ -27,9 +45,19 @@
  * major components, printer properties such as name, id, status,
  * description and printer capabilities which describe the various
  * print modes a printer supports such as media sizes, margins, etc.
+ * <p>
+ * Once {@link PrinterInfo.Builder#build() built} the objects are immutable.
+ * </p>
  */
 public final class PrinterInfo implements Parcelable {
 
+    /** @hide */
+    @IntDef({
+            STATUS_IDLE, STATUS_BUSY, STATUS_UNAVAILABLE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Status {
+    }
     /** Printer status: the printer is idle and ready to print. */
     public static final int STATUS_IDLE = 1;
 
@@ -39,44 +67,41 @@
     /** Printer status: the printer is not available. */
     public static final int STATUS_UNAVAILABLE = 3;
 
-    private PrinterId mId;
+    private final @NonNull PrinterId mId;
 
-    private String mName;
+    /** Resource inside the printer's services's package to be used as an icon */
+    private final int mIconResourceId;
 
-    private int mStatus;
+    /** If a custom icon can be loaded for the printer */
+    private final boolean mHasCustomPrinterIcon;
 
-    private String mDescription;
+    /** The generation of the icon in the cache. */
+    private final int mCustomPrinterIconGen;
 
-    private PrinterCapabilitiesInfo mCapabilities;
+    /** Intent that launches the activity showing more information about the printer. */
+    private final @Nullable PendingIntent mInfoIntent;
 
-    private PrinterInfo() {
-        /* do nothing */
-    }
+    private final @NonNull String mName;
 
-    private PrinterInfo(PrinterInfo prototype) {
-        copyFrom(prototype);
-    }
+    private final @Status int mStatus;
 
-    /**
-     * @hide
-     */
-    public void copyFrom(PrinterInfo other) {
-        if (this == other) {
-            return;
-        }
-        mId = other.mId;
-        mName = other.mName;
-        mStatus = other.mStatus;
-        mDescription = other.mDescription;
-        if (other.mCapabilities != null) {
-            if (mCapabilities != null) {
-                mCapabilities.copyFrom(other.mCapabilities);
-            } else {
-                mCapabilities = new PrinterCapabilitiesInfo(other.mCapabilities);
-            }
-        } else {
-            mCapabilities = null;
-        }
+    private final @Nullable String mDescription;
+
+    private final @Nullable PrinterCapabilitiesInfo mCapabilities;
+
+    private PrinterInfo(@NonNull PrinterId printerId, @NonNull String name, @Status int status,
+            int iconResourceId, boolean hasCustomPrinterIcon, String description,
+            PendingIntent infoIntent, PrinterCapabilitiesInfo capabilities,
+            int customPrinterIconGen) {
+        mId = printerId;
+        mName = name;
+        mStatus = status;
+        mIconResourceId = iconResourceId;
+        mHasCustomPrinterIcon = hasCustomPrinterIcon;
+        mDescription = description;
+        mInfoIntent = infoIntent;
+        mCapabilities = capabilities;
+        mCustomPrinterIconGen = customPrinterIconGen;
     }
 
     /**
@@ -84,16 +109,64 @@
      *
      * @return The printer id.
      */
-    public PrinterId getId() {
+    public @NonNull PrinterId getId() {
         return mId;
     }
 
     /**
+     * Get the icon to be used for this printer. If no per printer icon is available, the printer's
+     * service's icon is returned. If the printer has a custom icon this icon might get requested
+     * asynchronously. Once the icon is loaded the discovery sessions will be notified that the
+     * printer changed.
+     *
+     * @param context The context that will be using the icons
+     * @return The icon to be used for the printer or null if no icon could be found.
+     * @hide
+     */
+    @TestApi
+    public @Nullable Drawable loadIcon(@NonNull Context context) {
+        Drawable drawable = null;
+        PackageManager packageManager = context.getPackageManager();
+
+        if (mHasCustomPrinterIcon) {
+            PrintManager printManager = (PrintManager) context
+                    .getSystemService(Context.PRINT_SERVICE);
+
+            Icon icon = printManager.getCustomPrinterIcon(mId);
+
+            if (icon != null) {
+                drawable = icon.loadDrawable(context);
+            }
+        }
+
+        if (drawable == null) {
+            try {
+                String packageName = mId.getServiceName().getPackageName();
+                PackageInfo packageInfo = packageManager.getPackageInfo(packageName, 0);
+                ApplicationInfo appInfo = packageInfo.applicationInfo;
+
+                // If no custom icon is available, try the icon from the resources
+                if (mIconResourceId != 0) {
+                    drawable = packageManager.getDrawable(packageName, mIconResourceId, appInfo);
+                }
+
+                // Fall back to the printer's service's icon if no per printer icon could be found
+                if (drawable == null) {
+                    drawable = appInfo.loadIcon(packageManager);
+                }
+            } catch (NameNotFoundException e) {
+            }
+        }
+
+        return drawable;
+    }
+
+    /**
      * Get the printer name.
      *
      * @return The printer name.
      */
-    public String getName() {
+    public @NonNull String getName() {
         return mName;
     }
 
@@ -106,7 +179,7 @@
      * @see #STATUS_IDLE
      * @see #STATUS_UNAVAILABLE
      */
-    public int getStatus() {
+    public @Status int getStatus() {
         return mStatus;
     }
 
@@ -115,25 +188,82 @@
      *
      * @return The description.
      */
-    public String getDescription() {
+    public @Nullable String getDescription() {
         return mDescription;
     }
 
     /**
+     * Get the {@link PendingIntent} that launches the activity showing more information about the
+     * printer.
+     *
+     * @return the {@link PendingIntent} that launches the activity showing more information about
+     *         the printer or null if it is not configured
+     * @hide
+     */
+    public @Nullable PendingIntent getInfoIntent() {
+        return mInfoIntent;
+    }
+
+    /**
      * Gets the printer capabilities.
      *
      * @return The capabilities.
      */
-    public PrinterCapabilitiesInfo getCapabilities() {
+    public @Nullable PrinterCapabilitiesInfo getCapabilities() {
         return mCapabilities;
     }
 
+    /**
+     * Check if printerId is valid.
+     *
+     * @param printerId The printerId that might be valid
+     * @return The valid printerId
+     * @throws IllegalArgumentException if printerId is not valid.
+     */
+    private static @NonNull PrinterId checkPrinterId(PrinterId printerId) {
+        return Preconditions.checkNotNull(printerId, "printerId cannot be null.");
+    }
+
+    /**
+     * Check if status is valid.
+     *
+     * @param status The status that might be valid
+     * @return The valid status
+     * @throws IllegalArgumentException if status is not valid.
+     */
+    private static @Status int checkStatus(int status) {
+        if (!(status == STATUS_IDLE
+                || status == STATUS_BUSY
+                || status == STATUS_UNAVAILABLE)) {
+            throw new IllegalArgumentException("status is invalid.");
+        }
+
+        return status;
+    }
+
+    /**
+     * Check if name is valid.
+     *
+     * @param name The name that might be valid
+     * @return The valid name
+     * @throws IllegalArgumentException if name is not valid.
+     */
+    private static @NonNull String checkName(String name) {
+        return Preconditions.checkStringNotEmpty(name, "name cannot be empty.");
+    }
+
     private PrinterInfo(Parcel parcel) {
-        mId = parcel.readParcelable(null);
-        mName = parcel.readString();
-        mStatus = parcel.readInt();
+        // mName can be null due to unchecked set in Builder.setName and status can be invalid
+        // due to unchecked set in Builder.setStatus, hence we can only check mId for a valid state
+        mId = checkPrinterId((PrinterId) parcel.readParcelable(null));
+        mName = checkName(parcel.readString());
+        mStatus = checkStatus(parcel.readInt());
         mDescription = parcel.readString();
         mCapabilities = parcel.readParcelable(null);
+        mIconResourceId = parcel.readInt();
+        mHasCustomPrinterIcon = parcel.readByte() != 0;
+        mCustomPrinterIconGen = parcel.readInt();
+        mInfoIntent = parcel.readParcelable(null);
     }
 
     @Override
@@ -148,20 +278,72 @@
         parcel.writeInt(mStatus);
         parcel.writeString(mDescription);
         parcel.writeParcelable(mCapabilities, flags);
+        parcel.writeInt(mIconResourceId);
+        parcel.writeByte((byte) (mHasCustomPrinterIcon ? 1 : 0));
+        parcel.writeInt(mCustomPrinterIconGen);
+        parcel.writeParcelable(mInfoIntent, flags);
     }
 
     @Override
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = prime * result + ((mId != null) ? mId.hashCode() : 0);
-        result = prime * result + ((mName != null) ? mName.hashCode() : 0);
+        result = prime * result + mId.hashCode();
+        result = prime * result + mName.hashCode();
         result = prime * result + mStatus;
         result = prime * result + ((mDescription != null) ? mDescription.hashCode() : 0);
         result = prime * result + ((mCapabilities != null) ? mCapabilities.hashCode() : 0);
+        result = prime * result + mIconResourceId;
+        result = prime * result + (mHasCustomPrinterIcon ? 1 : 0);
+        result = prime * result + mCustomPrinterIconGen;
+        result = prime * result + ((mInfoIntent != null) ? mInfoIntent.hashCode() : 0);
         return result;
     }
 
+    /**
+     * Compare two {@link PrinterInfo printerInfos} in all aspects beside being null and the
+     * {@link #mStatus}.
+     *
+     * @param other the other {@link PrinterInfo}
+     * @return true iff the infos are equivalent
+     * @hide
+     */
+    public boolean equalsIgnoringStatus(PrinterInfo other) {
+        if (!mId.equals(other.mId)) {
+            return false;
+        }
+        if (!mName.equals(other.mName)) {
+           return false;
+        }
+        if (!TextUtils.equals(mDescription, other.mDescription)) {
+            return false;
+        }
+        if (mCapabilities == null) {
+            if (other.mCapabilities != null) {
+                return false;
+            }
+        } else if (!mCapabilities.equals(other.mCapabilities)) {
+            return false;
+        }
+        if (mIconResourceId != other.mIconResourceId) {
+            return false;
+        }
+        if (mHasCustomPrinterIcon != other.mHasCustomPrinterIcon) {
+            return false;
+        }
+        if (mCustomPrinterIconGen != other.mCustomPrinterIconGen) {
+            return false;
+        }
+        if (mInfoIntent == null) {
+            if (other.mInfoIntent != null) {
+                return false;
+            }
+        } else if (!mInfoIntent.equals(other.mInfoIntent)) {
+            return false;
+        }
+        return true;
+    }
+
     @Override
     public boolean equals(Object obj) {
         if (this == obj) {
@@ -174,29 +356,12 @@
             return false;
         }
         PrinterInfo other = (PrinterInfo) obj;
-        if (mId == null) {
-            if (other.mId != null) {
-                return false;
-            }
-        } else if (!mId.equals(other.mId)) {
-            return false;
-        }
-        if (!TextUtils.equals(mName, other.mName)) {
+        if (!equalsIgnoringStatus(other)) {
             return false;
         }
         if (mStatus != other.mStatus) {
             return false;
         }
-        if (!TextUtils.equals(mDescription, other.mDescription)) {
-            return false;
-        }
-        if (mCapabilities == null) {
-            if (other.mCapabilities != null) {
-                return false;
-            }
-        } else if (!mCapabilities.equals(other.mCapabilities)) {
-            return false;
-        }
         return true;
     }
 
@@ -209,6 +374,10 @@
         builder.append(", status=").append(mStatus);
         builder.append(", description=").append(mDescription);
         builder.append(", capabilities=").append(mCapabilities);
+        builder.append(", iconResId=").append(mIconResourceId);
+        builder.append(", hasCustomPrinterIcon=").append(mHasCustomPrinterIcon);
+        builder.append(", customPrinterIconGen=").append(mCustomPrinterIconGen);
+        builder.append(", infoIntent=").append(mInfoIntent);
         builder.append("\"}");
         return builder.toString();
     }
@@ -217,7 +386,15 @@
      * Builder for creating of a {@link PrinterInfo}.
      */
     public static final class Builder {
-        private final PrinterInfo mPrototype;
+        private @NonNull PrinterId mPrinterId;
+        private @NonNull String mName;
+        private @Status int mStatus;
+        private int mIconResourceId;
+        private boolean mHasCustomPrinterIcon;
+        private String mDescription;
+        private PendingIntent mInfoIntent;
+        private PrinterCapabilitiesInfo mCapabilities;
+        private int mCustomPrinterIconGen;
 
         /**
          * Constructor.
@@ -228,20 +405,10 @@
          * @throws IllegalArgumentException If the printer id is null, or the
          * printer name is empty or the status is not a valid one.
          */
-        public Builder(PrinterId printerId, String name, int status) {
-            if (printerId == null) {
-                throw new IllegalArgumentException("printerId cannot be null.");
-            }
-            if (TextUtils.isEmpty(name)) {
-                throw new IllegalArgumentException("name cannot be empty.");
-            }
-            if (!isValidStatus(status)) {
-                throw new IllegalArgumentException("status is invalid.");
-            }
-            mPrototype = new PrinterInfo();
-            mPrototype.mId = printerId;
-            mPrototype.mName = name;
-            mPrototype.mStatus = status;
+        public Builder(@NonNull PrinterId printerId, @NonNull String name, @Status int status) {
+            mPrinterId = checkPrinterId(printerId);
+            mName = checkName(name);
+            mStatus = checkStatus(status);
         }
 
         /**
@@ -249,9 +416,16 @@
          *
          * @param other Other info from which to start building.
          */
-        public Builder(PrinterInfo other) {
-            mPrototype = new PrinterInfo();
-            mPrototype.copyFrom(other);
+        public Builder(@NonNull PrinterInfo other) {
+            mPrinterId = other.mId;
+            mName = other.mName;
+            mStatus = other.mStatus;
+            mIconResourceId = other.mIconResourceId;
+            mHasCustomPrinterIcon = other.mHasCustomPrinterIcon;
+            mDescription = other.mDescription;
+            mInfoIntent = other.mInfoIntent;
+            mCapabilities = other.mCapabilities;
+            mCustomPrinterIconGen = other.mCustomPrinterIconGen;
         }
 
         /**
@@ -259,13 +433,44 @@
          *
          * @param status The status.
          * @return This builder.
-         *
          * @see PrinterInfo#STATUS_IDLE
          * @see PrinterInfo#STATUS_BUSY
          * @see PrinterInfo#STATUS_UNAVAILABLE
          */
-        public Builder setStatus(int status) {
-            mPrototype.mStatus = status;
+        public @NonNull Builder setStatus(@Status int status) {
+            mStatus = checkStatus(status);
+            return this;
+        }
+
+        /**
+         * Set a drawable resource as icon for this printer. If no icon is set the printer's
+         * service's icon is used for the printer.
+         *
+         * @param iconResourceId The resource ID of the icon.
+         * @return This builder.
+         * @see PrinterInfo.Builder#setHasCustomPrinterIcon
+         */
+        public @NonNull Builder setIconResourceId(@DrawableRes int iconResourceId) {
+            mIconResourceId = Preconditions.checkArgumentNonnegative(iconResourceId,
+                    "iconResourceId can't be negative");
+            return this;
+        }
+
+        /**
+         * Declares that the print service can load a custom per printer's icon. If both
+         * {@link PrinterInfo.Builder#setIconResourceId} and a custom icon are set the resource icon
+         * is shown while the custom icon loads but then the custom icon is used. If
+         * {@link PrinterInfo.Builder#setIconResourceId} is not set the printer's service's icon is
+         * shown while loading.
+         * <p>
+         * The icon is requested asynchronously and only when needed via
+         * {@link android.printservice.PrinterDiscoverySession#onRequestCustomPrinterIcon}.
+         * </p>
+         *
+         * @return This builder.
+         */
+        public @NonNull Builder setHasCustomPrinterIcon() {
+            mHasCustomPrinterIcon = true;
             return this;
         }
 
@@ -276,8 +481,8 @@
          * @param name The name.
          * @return This builder.
          */
-        public Builder setName(String name) {
-            mPrototype.mName = name;
+        public @NonNull Builder setName(@NonNull String name) {
+            mName = checkName(name);
             return this;
         }
 
@@ -288,8 +493,20 @@
          * @param description The description.
          * @return This builder.
          */
-        public Builder setDescription(String description) {
-            mPrototype.mDescription = description;
+        public @NonNull Builder setDescription(@NonNull String description) {
+            mDescription = description;
+            return this;
+        }
+
+        /**
+         * Sets the {@link PendingIntent} that launches an activity showing more information about
+         * the printer.
+         *
+         * @param infoIntent The {@link PendingIntent intent}.
+         * @return This builder.
+         */
+        public @NonNull Builder setInfoIntent(@NonNull PendingIntent infoIntent) {
+            mInfoIntent = infoIntent;
             return this;
         }
 
@@ -299,8 +516,8 @@
          * @param capabilities The capabilities.
          * @return This builder.
          */
-        public Builder setCapabilities(PrinterCapabilitiesInfo capabilities) {
-            mPrototype.mCapabilities = capabilities;
+        public @NonNull Builder setCapabilities(@NonNull PrinterCapabilitiesInfo capabilities) {
+            mCapabilities = capabilities;
             return this;
         }
 
@@ -309,14 +526,23 @@
          *
          * @return A new {@link PrinterInfo}.
          */
-        public PrinterInfo build() {
-            return mPrototype;
+        public @NonNull PrinterInfo build() {
+            return new PrinterInfo(mPrinterId, mName, mStatus, mIconResourceId,
+                    mHasCustomPrinterIcon, mDescription, mInfoIntent, mCapabilities,
+                    mCustomPrinterIconGen);
         }
 
-        private boolean isValidStatus(int status) {
-            return (status == STATUS_IDLE
-                    || status == STATUS_BUSY
-                    || status == STATUS_UNAVAILABLE);
+        /**
+         * Increments the generation number of the custom printer icon. As the {@link PrinterInfo}
+         * does not match the previous one anymore, users of the {@link PrinterInfo} will reload the
+         * icon if needed.
+         *
+         * @return This builder.
+         * @hide
+         */
+        public @NonNull Builder incCustomPrinterIconGen() {
+            mCustomPrinterIconGen++;
+            return this;
         }
     }
 
diff --git a/core/java/android/print/pdf/PrintedPdfDocument.java b/core/java/android/print/pdf/PrintedPdfDocument.java
index 2d8aafa..df7c054 100644
--- a/core/java/android/print/pdf/PrintedPdfDocument.java
+++ b/core/java/android/print/pdf/PrintedPdfDocument.java
@@ -16,26 +16,25 @@
 
 package android.print.pdf;
 
+import android.annotation.IntRange;
+import android.annotation.NonNull;
 import android.content.Context;
 import android.graphics.Rect;
 import android.graphics.pdf.PdfDocument;
-import android.graphics.pdf.PdfDocument.Page;
-import android.graphics.pdf.PdfDocument.PageInfo;
 import android.print.PrintAttributes;
 import android.print.PrintAttributes.Margins;
 import android.print.PrintAttributes.MediaSize;
 
 /**
- * This class is a helper for creating a PDF file for given print
- * attributes. It is useful for implementing printing via the native
- * Android graphics APIs.
+ * This class is a helper for creating a PDF file for given print attributes. It is useful for
+ * implementing printing via the native Android graphics APIs.
  * <p>
- * This class computes the page width, page height, and content rectangle
- * from the provided print attributes and these precomputed values can be
- * accessed via {@link #getPageWidth()}, {@link #getPageHeight()}, and
- * {@link #getPageContentRect()}, respectively. The {@link #startPage(int)}
- * methods creates pages whose {@link PageInfo} is initialized with the
- * precomputed values for width, height, and content rectangle.
+ * This class computes the page width, page height, and content rectangle from the provided print
+ * attributes and these precomputed values can be accessed via {@link #getPageWidth()},
+ * {@link #getPageHeight()}, and {@link #getPageContentRect()}, respectively. The
+ * {@link #startPage(int)} methods creates pages whose
+ * {@link android.graphics.pdf.PdfDocument.PageInfo PageInfo} is initialized with the precomputed
+ * values for width, height, and content rectangle.
  * <p>
  * A typical use of the APIs looks like this:
  * </p>
@@ -81,7 +80,7 @@
      * @param context Context instance for accessing resources.
      * @param attributes The print attributes.
      */
-    public PrintedPdfDocument(Context context, PrintAttributes attributes) {
+    public PrintedPdfDocument(@NonNull Context context, @NonNull PrintAttributes attributes) {
         MediaSize mediaSize = attributes.getMediaSize();
 
         // Compute the size of the target canvas from the attributes.
@@ -105,28 +104,28 @@
     }
 
     /**
-     * Starts a new page. The page is created using width, height  and content
-     * rectangle computed from the print attributes passed in the constructor
-     * and the given page number to create an appropriate {@link PageInfo}.
+     * Starts a new page. The page is created using width, height and content rectangle computed
+     * from the print attributes passed in the constructor and the given page number to create an
+     * appropriate {@link android.graphics.pdf.PdfDocument.PageInfo PageInfo}.
      * <p>
-     * After the page is created you can draw arbitrary content on the page's
-     * canvas which you can get by calling {@link Page#getCanvas() Page.getCanvas()}.
+     * After the page is created you can draw arbitrary content on the page's canvas which you can
+     * get by calling {@link android.graphics.pdf.PdfDocument.Page#getCanvas() Page.getCanvas()}.
      * After you are done drawing the content you should finish the page by calling
-     * {@link #finishPage(Page)}. After the page is finished you should no longer
-     * access the page or its canvas.
+     * {@link #finishPage(Page)}. After the page is finished you should no longer access the page or
+     * its canvas.
      * </p>
      * <p>
-     * <strong>Note:</strong> Do not call this method after {@link #close()}.
-     * Also do not call this method if the last page returned by this method
-     * is not finished by calling {@link #finishPage(Page)}.
+     * <strong>Note:</strong> Do not call this method after {@link #close()}. Also do not call this
+     * method if the last page returned by this method is not finished by calling
+     * {@link #finishPage(Page)}.
      * </p>
      *
-     * @param pageNumber The page number. Must be a positive value.
+     * @param pageNumber The page number. Must be a non negative.
      * @return A blank page.
      *
      * @see #finishPage(Page)
      */
-    public Page startPage(int pageNumber) {
+    public @NonNull Page startPage(@IntRange(from = 0) int pageNumber) {
         PageInfo pageInfo = new PageInfo
                 .Builder(mPageWidth, mPageHeight, pageNumber)
                 .setContentRect(mContentRect)
@@ -139,7 +138,7 @@
      *
      * @return The page width in PostScript points (1/72th of an inch).
      */
-    public int getPageWidth() {
+    public @IntRange(from = 0) int getPageWidth() {
         return mPageWidth;
     }
 
@@ -148,7 +147,7 @@
      *
      * @return The page height in PostScript points (1/72th of an inch).
      */
-    public int getPageHeight() {
+    public @IntRange(from = 0) int getPageHeight() {
         return mPageHeight;
     }
 
@@ -158,7 +157,7 @@
      *
      * @return The content rectangle.
      */
-    public Rect getPageContentRect() {
+    public @NonNull Rect getPageContentRect() {
         return mContentRect;
     }
 }
diff --git a/core/java/android/printservice/CustomPrinterIconCallback.java b/core/java/android/printservice/CustomPrinterIconCallback.java
new file mode 100644
index 0000000..6b9d0d8
--- /dev/null
+++ b/core/java/android/printservice/CustomPrinterIconCallback.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.drawable.Icon;
+import android.os.RemoteException;
+import android.print.PrinterId;
+import android.util.Log;
+
+
+/**
+ * Callback for {@link PrinterDiscoverySession#onRequestCustomPrinterIcon}.
+ */
+public class CustomPrinterIconCallback {
+    /** The printer the call back is for */
+    private final @NonNull PrinterId mPrinterId;
+    private final @NonNull IPrintServiceClient mObserver;
+    private static final String LOG_TAG = "CustomPrinterIconCB";
+
+    /**
+     * Create a callback class to be used once a icon is loaded
+     *
+     * @param printerId The printer the icon should be loaded for
+     * @param observer The observer that needs to be notified about the update.
+     */
+    CustomPrinterIconCallback(@NonNull PrinterId printerId, @NonNull IPrintServiceClient observer) {
+        mPrinterId = printerId;
+        mObserver = observer;
+    }
+
+    /**
+     * Provide a new icon for a printer. Can be called more than once to update the icon.
+     *
+     * @param icon The new icon for the printer or null to unset the current icon
+     * @return true iff the icon could be updated
+     */
+    public boolean onCustomPrinterIconLoaded(@Nullable Icon icon) {
+        try {
+            mObserver.onCustomPrinterIconLoaded(mPrinterId, icon);
+        } catch (RemoteException e) {
+            Log.e(LOG_TAG , "Could not update icon", e);
+            return false;
+        }
+
+        return true;
+    }
+}
diff --git a/core/java/android/printservice/IPrintService.aidl b/core/java/android/printservice/IPrintService.aidl
index ee36619..3750d7a 100644
--- a/core/java/android/printservice/IPrintService.aidl
+++ b/core/java/android/printservice/IPrintService.aidl
@@ -10,7 +10,7 @@
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific languagÿe governing permissions and
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
@@ -35,6 +35,15 @@
     void stopPrinterDiscovery();
     void validatePrinters(in List<PrinterId> printerIds);
     void startPrinterStateTracking(in PrinterId printerId);
+
+    /**
+     * Request the custom icon for a printer.
+     *
+     * @param printerId the id of the printer the icon should be loaded for
+     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+     */
+    void requestCustomPrinterIcon(in PrinterId printerId);
+
     void stopPrinterStateTracking(in PrinterId printerId);
     void destroyPrinterDiscoverySession();
 }
diff --git a/core/java/android/printservice/IPrintServiceClient.aidl b/core/java/android/printservice/IPrintServiceClient.aidl
index b4baa48..0ae1e18 100644
--- a/core/java/android/printservice/IPrintServiceClient.aidl
+++ b/core/java/android/printservice/IPrintServiceClient.aidl
@@ -16,6 +16,7 @@
 
 package android.printservice;
 
+import android.graphics.drawable.Icon;
 import android.os.ParcelFileDescriptor;
 import android.print.PrintJobInfo;
 import android.print.PrinterId;
@@ -53,4 +54,13 @@
 
     void onPrintersAdded(in ParceledListSlice printers);
     void onPrintersRemoved(in ParceledListSlice printerIds);
+
+    /**
+     * Handle that a custom icon for a printer was loaded.
+     *
+     * @param printerId the id of the printer the icon belongs to
+     * @param icon the icon that was loaded
+     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+     */
+    void onCustomPrinterIconLoaded(in PrinterId printerId, in Icon icon);
 }
diff --git a/core/java/android/printservice/PrintDocument.java b/core/java/android/printservice/PrintDocument.java
index e43f2a8..0121ae1 100644
--- a/core/java/android/printservice/PrintDocument.java
+++ b/core/java/android/printservice/PrintDocument.java
@@ -16,6 +16,8 @@
 
 package android.printservice;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.print.PrintDocumentInfo;
@@ -54,7 +56,7 @@
      *
      * @return The document info.
      */
-    public PrintDocumentInfo getInfo() {
+    public @NonNull PrintDocumentInfo getInfo() {
         PrintService.throwIfNotCalledOnMainThread();
         return mInfo;
     }
@@ -69,7 +71,7 @@
      *
      * @return A file descriptor for reading the data.
      */
-    public ParcelFileDescriptor getData() {
+    public @Nullable ParcelFileDescriptor getData() {
         PrintService.throwIfNotCalledOnMainThread();
         ParcelFileDescriptor source = null;
         ParcelFileDescriptor sink = null;
diff --git a/core/java/android/printservice/PrintJob.java b/core/java/android/printservice/PrintJob.java
index 86fc292..6414b6a 100644
--- a/core/java/android/printservice/PrintJob.java
+++ b/core/java/android/printservice/PrintJob.java
@@ -344,7 +344,7 @@
      * @return True if the tag was set, false otherwise.
      */
     @MainThread
-    public boolean setTag(String tag) {
+    public boolean setTag(@NonNull String tag) {
         PrintService.throwIfNotCalledOnMainThread();
         if (isInImmutableState()) {
             return false;
@@ -364,7 +364,8 @@
      *
      * @see #setTag(String)
      */
-    public String getTag() {
+    @MainThread
+    public @Nullable String getTag() {
         PrintService.throwIfNotCalledOnMainThread();
         return getInfo().getTag();
     }
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index 6295822..62d214e 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -16,6 +16,8 @@
 
 package android.printservice;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.Service;
 import android.content.ComponentName;
 import android.content.Context;
@@ -29,6 +31,8 @@
 import android.print.PrinterId;
 import android.util.Log;
 
+import com.android.internal.util.Preconditions;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -191,30 +195,29 @@
 
     /**
      * If you declared an optional activity with advanced print options via the
-     * {@link android.R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
-     * attribute, this extra is used to pass in the currently constructed {@link
-     * PrintJobInfo} to your activity allowing you to modify it. After you are
-     * done, you must return the modified {@link PrintJobInfo} via the same extra.
+     * {@link android.R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity} attribute,
+     * this extra is used to pass in the currently constructed {@link PrintJobInfo} to your activity
+     * allowing you to modify it. After you are done, you must return the modified
+     * {@link PrintJobInfo} via the same extra.
      * <p>
-     * You cannot modify the passed in {@link PrintJobInfo} directly, rather you
-     * should build another one using the {@link PrintJobInfo.Builder} class. You
-     * can specify any standard properties and add advanced, printer specific,
-     * ones via {@link PrintJobInfo.Builder#putAdvancedOption(String, String)
-     * PrintJobInfo.Builder.putAdvancedOption(String, String)} and {@link
-     * PrintJobInfo.Builder#putAdvancedOption(String, int)
-     * PrintJobInfo.Builder.putAdvancedOption(String, int)}. The advanced options
-     * are not interpreted by the system, they will not be visible to applications,
-     * and can only be accessed by your print service via {@link
-     * PrintJob#getAdvancedStringOption(String) PrintJob.getAdvancedStringOption(String)}
-     * and {@link PrintJob#getAdvancedIntOption(String) PrintJob.getAdvancedIntOption(String)}.
+     * You cannot modify the passed in {@link PrintJobInfo} directly, rather you should build
+     * another one using the {@link android.print.PrintJobInfo.Builder PrintJobInfo.Builder} class.
+     * You can specify any standard properties and add advanced, printer specific, ones via
+     * {@link android.print.PrintJobInfo.Builder#putAdvancedOption(String, String)
+     * PrintJobInfo.Builder.putAdvancedOption(String, String)} and
+     * {@link android.print.PrintJobInfo.Builder#putAdvancedOption(String, int)
+     * PrintJobInfo.Builder.putAdvancedOption(String, int)}. The advanced options are not
+     * interpreted by the system, they will not be visible to applications, and can only be accessed
+     * by your print service via {@link PrintJob#getAdvancedStringOption(String)
+     * PrintJob.getAdvancedStringOption(String)} and {@link PrintJob#getAdvancedIntOption(String)
+     * PrintJob.getAdvancedIntOption(String)}.
      * </p>
      * <p>
-     * If the advanced print options activity offers changes to the standard print
-     * options, you can get the current {@link android.print.PrinterInfo} using the
-     * {@link #EXTRA_PRINTER_INFO} extra which will allow you to present the user
-     * with UI options supported by the current printer. For example, if the current
-     * printer does not support a given media size, you should not offer it in the
-     * advanced print options UI.
+     * If the advanced print options activity offers changes to the standard print options, you can
+     * get the current {@link android.print.PrinterInfo PrinterInfo} using the
+     * {@link #EXTRA_PRINTER_INFO} extra which will allow you to present the user with UI options
+     * supported by the current printer. For example, if the current printer does not support a
+     * given media size, you should not offer it in the advanced print options UI.
      * </p>
      *
      * @see #EXTRA_PRINTER_INFO
@@ -275,9 +278,10 @@
     /**
      * Callback asking you to create a new {@link PrinterDiscoverySession}.
      *
+     * @return The created session.
      * @see PrinterDiscoverySession
      */
-    protected abstract PrinterDiscoverySession onCreatePrinterDiscoverySession();
+    protected abstract @Nullable PrinterDiscoverySession onCreatePrinterDiscoverySession();
 
     /**
      * Called when cancellation of a print job is requested. The service
@@ -343,8 +347,9 @@
      * @param localId A locally unique id in the context of your print service.
      * @return Global printer id.
      */
-    public final PrinterId generatePrinterId(String localId) {
+    public @NonNull final PrinterId generatePrinterId(String localId) {
         throwIfNotCalledOnMainThread();
+        localId = Preconditions.checkNotNull(localId, "localId cannot be null");
         return new PrinterId(new ComponentName(getPackageName(),
                 getClass().getName()), localId);
     }
@@ -368,6 +373,7 @@
                 mHandler.sendEmptyMessage(ServiceHandler.MSG_DESTROY_PRINTER_DISCOVERY_SESSION);
             }
 
+            @Override
             public void startPrinterDiscovery(List<PrinterId> priorityList) {
                 mHandler.obtainMessage(ServiceHandler.MSG_START_PRINTER_DISCOVERY,
                         priorityList).sendToTarget();
@@ -391,6 +397,12 @@
             }
 
             @Override
+            public void requestCustomPrinterIcon(PrinterId printerId) {
+                mHandler.obtainMessage(ServiceHandler.MSG_REQUEST_CUSTOM_PRINTER_ICON,
+                        printerId).sendToTarget();
+            }
+
+            @Override
             public void stopPrinterStateTracking(PrinterId printerId) {
                 mHandler.obtainMessage(ServiceHandler.MSG_STOP_PRINTER_STATE_TRACKING,
                         printerId).sendToTarget();
@@ -423,10 +435,11 @@
         public static final int MSG_STOP_PRINTER_DISCOVERY = 4;
         public static final int MSG_VALIDATE_PRINTERS = 5;
         public static final int MSG_START_PRINTER_STATE_TRACKING = 6;
-        public static final int MSG_STOP_PRINTER_STATE_TRACKING = 7;
-        public static final int MSG_ON_PRINTJOB_QUEUED = 8;
-        public static final int MSG_ON_REQUEST_CANCEL_PRINTJOB = 9;
-        public static final int MSG_SET_CLIENT = 10;
+        public static final int MSG_REQUEST_CUSTOM_PRINTER_ICON = 7;
+        public static final int MSG_STOP_PRINTER_STATE_TRACKING = 8;
+        public static final int MSG_ON_PRINTJOB_QUEUED = 9;
+        public static final int MSG_ON_REQUEST_CANCEL_PRINTJOB = 10;
+        public static final int MSG_SET_CLIENT = 11;
 
         public ServiceHandler(Looper looper) {
             super(looper, null, true);
@@ -508,6 +521,17 @@
                     }
                 } break;
 
+                case MSG_REQUEST_CUSTOM_PRINTER_ICON: {
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "MSG_REQUEST_CUSTOM_PRINTER_ICON "
+                                + getPackageName());
+                    }
+                    if (mDiscoverySession != null) {
+                        PrinterId printerId = (PrinterId) message.obj;
+                        mDiscoverySession.requestCustomPrinterIcon(printerId);
+                    }
+                } break;
+
                 case MSG_STOP_PRINTER_STATE_TRACKING: {
                     if (DEBUG) {
                         Log.i(LOG_TAG, "MSG_STOP_PRINTER_STATE_TRACKING "
diff --git a/core/java/android/printservice/PrintServiceInfo.java b/core/java/android/printservice/PrintServiceInfo.java
index a2c6c09..91e01f2 100644
--- a/core/java/android/printservice/PrintServiceInfo.java
+++ b/core/java/android/printservice/PrintServiceInfo.java
@@ -16,6 +16,7 @@
 
 package android.printservice;
 
+import android.annotation.NonNull;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -94,12 +95,21 @@
     }
 
     /**
+     * Return the component name for this print service.
+     *
+     * @return The component name for this print service.
+     */
+    public @NonNull ComponentName getComponentName() {
+        return new ComponentName(mResolveInfo.serviceInfo.packageName,
+                mResolveInfo.serviceInfo.name);
+    }
+
+    /**
      * Creates a new instance.
      *
      * @param resolveInfo The service resolve info.
      * @param context Context for accessing resources.
-     * @throws XmlPullParserException If a XML parsing error occurs.
-     * @throws IOException If a I/O error occurs.
+     * @return The created instance.
      */
     public static PrintServiceInfo create(ResolveInfo resolveInfo, Context context) {
         String settingsActivityName = null;
@@ -220,10 +230,12 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public int describeContents() {
         return 0;
     }
 
+    @Override
     public void writeToParcel(Parcel parcel, int flagz) {
         parcel.writeString(mId);
         parcel.writeParcelable(mResolveInfo, 0);
@@ -275,10 +287,12 @@
 
     public static final Parcelable.Creator<PrintServiceInfo> CREATOR =
             new Parcelable.Creator<PrintServiceInfo>() {
+        @Override
         public PrintServiceInfo createFromParcel(Parcel parcel) {
             return new PrintServiceInfo(parcel);
         }
 
+        @Override
         public PrintServiceInfo[] newArray(int size) {
             return new PrintServiceInfo[size];
         }
diff --git a/core/java/android/printservice/PrinterDiscoverySession.java b/core/java/android/printservice/PrinterDiscoverySession.java
index 17cb68f..cd5a903 100644
--- a/core/java/android/printservice/PrinterDiscoverySession.java
+++ b/core/java/android/printservice/PrinterDiscoverySession.java
@@ -16,6 +16,7 @@
 
 package android.printservice;
 
+import android.annotation.NonNull;
 import android.content.pm.ParceledListSlice;
 import android.os.RemoteException;
 import android.print.PrinterCapabilitiesInfo;
@@ -138,7 +139,7 @@
      * @see #removePrinters(List)
      * @see #isDestroyed()
      */
-    public final List<PrinterInfo> getPrinters() {
+    public final @NonNull List<PrinterInfo> getPrinters() {
         PrintService.throwIfNotCalledOnMainThread();
         if (mIsDestroyed) {
             return Collections.emptyList();
@@ -161,7 +162,7 @@
      * @see #getPrinters()
      * @see #isDestroyed()
      */
-    public final void addPrinters(List<PrinterInfo> printers) {
+    public final void addPrinters(@NonNull List<PrinterInfo> printers) {
         PrintService.throwIfNotCalledOnMainThread();
 
         // If the session is destroyed - nothing do to.
@@ -225,7 +226,7 @@
      * @see #getPrinters()
      * @see #isDestroyed()
      */
-    public final void removePrinters(List<PrinterId> printerIds) {
+    public final void removePrinters(@NonNull List<PrinterId> printerIds) {
         PrintService.throwIfNotCalledOnMainThread();
 
         // If the session is destroyed - nothing do to.
@@ -350,7 +351,7 @@
      * @see #removePrinters(List)
      * @see #isPrinterDiscoveryStarted()
      */
-    public abstract void onStartPrinterDiscovery(List<PrinterId> priorityList);
+    public abstract void onStartPrinterDiscovery(@NonNull List<PrinterId> priorityList);
 
     /**
      * Callback notifying you that you should stop printer discovery.
@@ -372,10 +373,10 @@
      *
      * @param printerIds The printers to validate.
      *
-     * @see PrinterInfo.Builder#setCapabilities(PrinterCapabilitiesInfo)
+     * @see android.print.PrinterInfo.Builder#setCapabilities(PrinterCapabilitiesInfo)
      *      PrinterInfo.Builder.setCapabilities(PrinterCapabilitiesInfo)
      */
-    public abstract void onValidatePrinters(List<PrinterId> printerIds);
+    public abstract void onValidatePrinters(@NonNull List<PrinterId> printerIds);
 
     /**
      * Callback asking you to start tracking the state of a printer. Tracking
@@ -400,10 +401,24 @@
      * @param printerId The printer to start tracking.
      *
      * @see #onStopPrinterStateTracking(PrinterId)
-     * @see PrinterInfo.Builder#setCapabilities(PrinterCapabilitiesInfo)
+     * @see android.print.PrinterInfo.Builder#setCapabilities(PrinterCapabilitiesInfo)
      *      PrinterInfo.Builder.setCapabilities(PrinterCapabilitiesInfo)
      */
-    public abstract void onStartPrinterStateTracking(PrinterId printerId);
+    public abstract void onStartPrinterStateTracking(@NonNull PrinterId printerId);
+
+    /**
+     * Request the custom icon for a printer. Once the icon is available use
+     * {@link CustomPrinterIconCallback#onCustomPrinterIconLoaded} to send the data to the print
+     * service.
+     *
+     * @param printerId The printer to icon belongs to.
+     * @param callback Callback for returning the icon to the print spooler.
+     *
+     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+     */
+    public void onRequestCustomPrinterIcon(@NonNull PrinterId printerId,
+            @NonNull CustomPrinterIconCallback callback) {
+    }
 
     /**
      * Callback asking you to stop tracking the state of a printer. The passed
@@ -414,7 +429,7 @@
      *
      * @see #onStartPrinterStateTracking(PrinterId)
      */
-    public abstract void onStopPrinterStateTracking(PrinterId printerId);
+    public abstract void onStopPrinterStateTracking(@NonNull PrinterId printerId);
 
     /**
      * Gets the printers that should be tracked. These are printers that are
@@ -434,7 +449,7 @@
      * @see #onStopPrinterStateTracking(PrinterId)
      * @see #isDestroyed()
      */
-    public final List<PrinterId> getTrackedPrinters() {
+    public final @NonNull List<PrinterId> getTrackedPrinters() {
         PrintService.throwIfNotCalledOnMainThread();
         if (mIsDestroyed) {
             return Collections.emptyList();
@@ -476,7 +491,7 @@
         return mIsDiscoveryStarted;
     }
 
-    void startPrinterDiscovery(List<PrinterId> priorityList) {
+    void startPrinterDiscovery(@NonNull List<PrinterId> priorityList) {
         if (!mIsDestroyed) {
             mIsDiscoveryStarted = true;
             sendOutOfDiscoveryPeriodPrinterChanges();
@@ -494,13 +509,13 @@
         }
     }
 
-    void validatePrinters(List<PrinterId> printerIds) {
+    void validatePrinters(@NonNull List<PrinterId> printerIds) {
         if (!mIsDestroyed && mObserver != null) {
             onValidatePrinters(printerIds);
         }
     }
 
-    void startPrinterStateTracking(PrinterId printerId) {
+    void startPrinterStateTracking(@NonNull PrinterId printerId) {
         if (!mIsDestroyed && mObserver != null
                 && !mTrackedPrinters.contains(printerId)) {
             mTrackedPrinters.add(printerId);
@@ -508,7 +523,21 @@
         }
     }
 
-    void stopPrinterStateTracking(PrinterId printerId) {
+    /**
+     * Request the custom icon for a printer.
+     *
+     * @param printerId The printer to icon belongs to.
+     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+     */
+    void requestCustomPrinterIcon(@NonNull PrinterId printerId) {
+        if (!mIsDestroyed && mObserver != null) {
+            CustomPrinterIconCallback callback = new CustomPrinterIconCallback(printerId,
+                    mObserver);
+            onRequestCustomPrinterIcon(printerId, callback);
+        }
+    }
+
+    void stopPrinterStateTracking(@NonNull PrinterId printerId) {
         if (!mIsDestroyed && mObserver != null
                 && mTrackedPrinters.remove(printerId)) {
             onStopPrinterStateTracking(printerId);
diff --git a/core/java/android/provider/BlockedNumberContract.java b/core/java/android/provider/BlockedNumberContract.java
new file mode 100644
index 0000000..2a9d4ae
--- /dev/null
+++ b/core/java/android/provider/BlockedNumberContract.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 android.provider;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+
+/**
+ * Constants and methods to access blocked phone numbers for incoming calls and texts.
+ *
+ * TODO javadoc
+ * - Proper javadoc tagging.
+ * - Code sample?
+ * - Describe who can access it.
+ */
+public class BlockedNumberContract {
+    private BlockedNumberContract() {
+    }
+
+    /** The authority for the contacts provider */
+    public static final String AUTHORITY = "com.android.blockednumber";
+
+    /** A content:// style uri to the authority for the contacts provider */
+    public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
+
+    /**
+     * TODO javadoc
+     *
+     * Constants to interact with the blocked phone number list.
+     */
+    public static class BlockedNumbers {
+        private BlockedNumbers() {
+        }
+
+        /**
+         * TODO javadoc
+         *
+         * Content URI for the blocked numbers.
+         *
+         * Supported operations
+         * blocked
+         * - query
+         * - delete
+         * - insert
+         *
+         * blocked/ID
+         * - query (selection is not supported)
+         * - delete (selection is not supported)
+         */
+        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";
+
+        /**
+         * The MIME type of a blocked phone number under {@link #CONTENT_URI}.
+         */
+        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/blocked_number";
+
+        /**
+         * Auto-generated ID field which monotonically increases.
+         * <p>TYPE: long</p>
+         */
+        public static final String COLUMN_ID = "_id";
+
+        /**
+         * Phone number to block.
+         * <p>Must be specified in {@code insert}.
+         * <p>TYPE: String</p>
+         */
+        public static final String COLUMN_ORIGINAL_NUMBER = "original_number";
+
+        /**
+         * Phone number to block.  The system generates it from {@link #COLUMN_ORIGINAL_NUMBER}
+         * by removing all formatting characters.
+         * <p>Must NOT be specified in {@code insert}.
+         * <p>TYPE: String</p>
+         */
+        public static final String COLUMN_STRIPPED_NUMBER = "stripped_number";
+
+        /**
+         * Phone number to block.  The system generates it from {@link #COLUMN_ORIGINAL_NUMBER}
+         * by removing all formatting characters.
+         * <p>Optional in {@code insert}.  When not specified, the system tries to generate it
+         * assuming the current country. (Which will still be null if the number is not valid.)
+         * <p>TYPE: String</p>
+         */
+        public static final String COLUMN_E164_NUMBER = "e164_number";
+    }
+
+    /** @hide */
+    public static final String METHOD_IS_BLOCKED = "is_blocked";
+
+    /** @hide */
+    public static final String RES_NUMBER_IS_BLOCKED = "blocked";
+
+    /**
+     * Returns whether a given number is in the blocked list.
+     *
+     * TODO This should probably catch IllegalArgumentException to guard against the case where
+     * the provider is encrypted or the user is not running.
+     * (See addEntryAndRemoveExpiredEntries() in
+     * http://ag/#/c/844426/3/core/java/android/provider/CallLog.java)
+     */
+    public static boolean isBlocked(Context context, String phoneNumber) {
+        final Bundle res = context.getContentResolver().call(AUTHORITY_URI,
+                METHOD_IS_BLOCKED, phoneNumber, null);
+        return res != null && res.getBoolean(RES_NUMBER_IS_BLOCKED, false);
+    }
+}
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 1d4d572..e7c4a07 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -38,6 +38,7 @@
 import android.telecom.TelecomManager;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
+import android.util.Log;
 
 import com.android.internal.telephony.CallerInfo;
 import com.android.internal.telephony.PhoneConstants;
@@ -49,6 +50,7 @@
  */
 public class CallLog {
     private static final String LOG_TAG = "CallLog";
+    private static final boolean VERBOSE_LOG = false; // DON'T SUBMIT WITH TRUE.
 
     public static final String AUTHORITY = "call_log";
 
@@ -58,6 +60,17 @@
     public static final Uri CONTENT_URI =
         Uri.parse("content://" + AUTHORITY);
 
+
+    /**
+     * The "shadow" provider stores calllog when the real calllog provider is encrypted.  The
+     * real provider will alter copy from it when it starts, and remove the entries in the shadow.
+     *
+     * <p>See the comment in {@link Calls#addCall} for the details.
+     *
+     * @hide
+     */
+    public static final String SHADOW_AUTHORITY = "call_log_shadow";
+
     /**
      * Contains the recent calls.
      */
@@ -68,6 +81,10 @@
         public static final Uri CONTENT_URI =
                 Uri.parse("content://call_log/calls");
 
+        /** @hide */
+        public static final Uri SHADOW_CONTENT_URI =
+                Uri.parse("content://call_log_shadow/calls");
+
         /**
          * The content:// style URL for filtering this table on phone numbers
          */
@@ -421,6 +438,13 @@
         public static final String ADD_FOR_ALL_USERS = "add_for_all_users";
 
         /**
+         * The date the row is last inserted, updated, or marked as deleted, in milliseconds
+         * since the epoch. Read only.
+         * <P>Type: INTEGER (long)</P>
+         */
+        public static final String LAST_MODIFIED = "last_modified";
+
+        /**
          * If a successful call is made that is longer than this duration, update the phone number
          * in the ContactsProvider with the normalized version of the number, based on the user's
          * current country code.
@@ -451,8 +475,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, "", presentation, callType, features, accountHandle,
-                    start, duration, dataUsage, false, null, false);
+            return addCall(ci, context, number, /* postDialDigits =*/ "", presentation,
+                    callType, features, accountHandle,
+                    start, duration, dataUsage, /* addForAllUsers =*/ false,
+                    /* userToBeInsertedTo =*/ null, /* is_read =*/ false);
         }
 
 
@@ -488,7 +514,7 @@
                 boolean addForAllUsers, UserHandle userToBeInsertedTo) {
             return addCall(ci, context, number, postDialDigits, presentation, callType, features,
                     accountHandle, start, duration, dataUsage, addForAllUsers, userToBeInsertedTo,
-                    false);
+                    /* is_read =*/ false);
         }
 
         /**
@@ -519,13 +545,18 @@
          *                Used for call log restore of missed calls.
          *
          * @result The URI of the call log entry belonging to the user that made or received this
-         *        call.
+         *        call.  This could be of the shadow provider.  Do not return it to non-system apps,
+         *        as they don't have permissions.
          * {@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) {
+            if (VERBOSE_LOG) {
+                Log.v(LOG_TAG, String.format("Add call: number=%s, user=%s, for all=%s",
+                        number, userToBeInsertedTo, addForAllUsers));
+            }
             final ContentResolver resolver = context.getContentResolver();
             int numberPresentation = PRESENTATION_ALLOWED;
 
@@ -640,41 +671,104 @@
                 }
             }
 
+            /*
+                Writing the calllog works in the following way:
+                - All user entries
+                    - if user-0 is encrypted, insert to user-0's shadow only.
+                      (other users should also be encrypted, so nothing to do for other users.)
+                    - if user-0 is decrypted, insert to user-0's real provider, as well as
+                      all other users that are running and decrypted and should have calllog.
+
+                - Single user entry.
+                    - If the target user is encryted, insert to its shadow.
+                    - Otherwise insert to its real provider.
+
+                When the (real) calllog provider starts, it copies entries that it missed from
+                elsewhere.
+                - When user-0's (real) provider starts, it copies from user-0's shadow, and clears
+                  the shadow.
+
+                - When other users (real) providers start, unless it shouldn't have calllog entries,
+                     - Copy from the user's shadow, and clears the shadow.
+                     - Copy from user-0's entries that are FOR_ALL_USERS = 1.  (and don't clear it.)
+             */
+
             Uri result = null;
 
+            final UserManager userManager = context.getSystemService(UserManager.class);
+            final int currentUserId = userManager.getUserHandle();
+
             if (addForAllUsers) {
-                // Insert the entry for all currently running users, in order to trigger any
-                // ContentObservers currently set on the call log.
-                final UserManager userManager = (UserManager) context.getSystemService(
-                        Context.USER_SERVICE);
-                List<UserInfo> users = userManager.getUsers(true);
-                final int currentUserId = userManager.getUserHandle();
+                // First, insert to the system user.
+                final Uri uriForSystem = addEntryAndRemoveExpiredEntries(
+                        context, userManager, UserHandle.SYSTEM, values);
+                if (uriForSystem == null
+                        || SHADOW_AUTHORITY.equals(uriForSystem.getAuthority())) {
+                    // This means the system user is still encrypted and the entry has inserted
+                    // into the shadow.  This means other users are still all encrypted.
+                    // Nothing further to do; just return null.
+                    return null;
+                }
+                if (UserHandle.USER_SYSTEM == currentUserId) {
+                    result = uriForSystem;
+                }
+
+                // Otherwise, insert to all other users that are running and unlocked.
+
+                final List<UserInfo> users = userManager.getUsers(true);
+
                 final int count = users.size();
                 for (int i = 0; i < count; i++) {
-                    final UserInfo user = users.get(i);
-                    final UserHandle userHandle = user.getUserHandle();
+                    final UserInfo userInfo = users.get(i);
+                    final UserHandle userHandle = userInfo.getUserHandle();
+                    final int userId = userHandle.getIdentifier();
+
+                    if (userHandle.isSystem()) {
+                        // Already written.
+                        continue;
+                    }
+
+                    if (!shouldHaveSharedCallLogEntries(context, userManager, userId)) {
+                        // Shouldn't have calllog entries.
+                        continue;
+                    }
+
+                    // For other users, we write only when they're running *and* decrypted.
+                    // Other providers will copy from the system user's real provider, when they
+                    // start.
                     if (userManager.isUserRunning(userHandle)
-                            && !userManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS,
-                                    userHandle)
-                            && !user.isManagedProfile()) {
-                        Uri uri = addEntryAndRemoveExpiredEntries(context,
-                                ContentProvider.maybeAddUserId(CONTENT_URI, user.id), values);
-                        if (user.id == currentUserId) {
+                            && userManager.isUserUnlocked(userHandle)) {
+                        final Uri uri = addEntryAndRemoveExpiredEntries(context, userManager,
+                                userHandle, values);
+                        if (userId == currentUserId) {
                             result = uri;
                         }
                     }
                 }
             } else {
-                Uri uri = CONTENT_URI;
-                if (userToBeInsertedTo != null) {
-                    uri = ContentProvider
-                            .maybeAddUserId(CONTENT_URI, userToBeInsertedTo.getIdentifier());
-                }
-                result = addEntryAndRemoveExpiredEntries(context, uri, values);
+                // Single-user entry. Just write to that user, assuming it's running.  If the
+                // user is encrypted, we write to the shadow calllog.
+
+                final UserHandle targetUserHandle = userToBeInsertedTo != null
+                        ? userToBeInsertedTo
+                        : UserHandle.of(currentUserId);
+                result = addEntryAndRemoveExpiredEntries(context, userManager, targetUserHandle,
+                        values);
             }
             return result;
         }
 
+        /** @hide */
+        public static boolean shouldHaveSharedCallLogEntries(Context context,
+                UserManager userManager, int userId) {
+            if (userManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS,
+                    UserHandle.of(userId))) {
+                return false;
+            }
+            final UserInfo userInfo = userManager.getUserInfo(userId);
+            return userInfo != null && !userInfo.isManagedProfile();
+        }
+
         /**
          * Query the call log database for the last dialed number.
          * @param context Used to get the content resolver.
@@ -700,14 +794,31 @@
             }
         }
 
-        private static Uri addEntryAndRemoveExpiredEntries(Context context, Uri uri,
-                ContentValues values) {
+        private static Uri addEntryAndRemoveExpiredEntries(Context context, UserManager userManager,
+                UserHandle user, ContentValues values) {
             final ContentResolver resolver = context.getContentResolver();
-            Uri result = resolver.insert(uri, values);
-            resolver.delete(uri, "_id IN " +
-                    "(SELECT _id FROM calls ORDER BY " + DEFAULT_SORT_ORDER
-                    + " LIMIT -1 OFFSET 500)", null);
-            return result;
+
+            final Uri uri = ContentProvider.maybeAddUserId(
+                    userManager.isUserUnlocked(user) ? CONTENT_URI : SHADOW_CONTENT_URI,
+                    user.getIdentifier());
+
+            if (VERBOSE_LOG) {
+                Log.v(LOG_TAG, String.format("Inserting to %s", uri));
+            }
+
+            try {
+                final Uri result = resolver.insert(uri, values);
+                resolver.delete(uri, "_id IN " +
+                        "(SELECT _id FROM calls ORDER BY " + DEFAULT_SORT_ORDER
+                        + " LIMIT -1 OFFSET 500)", null);
+                return result;
+            } catch (IllegalArgumentException e) {
+                Log.w(LOG_TAG, "Failed to insert calllog", e);
+                // Even though we make sure the target user is running and decrypted before calling
+                // this method, there's a chance that the user just got shut down, in which case
+                // we'll still get "IllegalArgumentException: Unknown URL content://call_log/calls".
+                return null;
+            }
         }
 
         private static void updateDataUsageStatForData(ContentResolver resolver, String dataId) {
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 10432b5..330fcf6 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -409,6 +409,20 @@
                 "directories_enterprise");
 
         /**
+         * Access file provided by remote directory. It allows both personal and work remote
+         * directory, but not local and invisible diretory.
+         *
+         * It's supported only by a few specific places for referring to contact pictures in the
+         * remote directory. Contact picture URIs, e.g.
+         * {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}, may contain this kind of URI.
+         *
+         * @hide
+         */
+        public static final Uri ENTERPRISE_FILE_URI = Uri.withAppendedPath(AUTHORITY_URI,
+                "directory_file_enterprise");
+
+
+        /**
          * The MIME-type of {@link #CONTENT_URI} providing a directory of
          * contact directories.
          */
@@ -8387,10 +8401,15 @@
          * @hide
          */
         public static Intent rebuildManagedQuickContactsIntent(String lookupKey, long contactId,
-                long directoryId, Intent originalIntent) {
+                boolean isContactIdIgnored, long directoryId, Intent originalIntent) {
             final Intent intent = new Intent(ACTION_QUICK_CONTACT);
             // Rebuild the URI from a lookup key and a contact ID.
-            Uri uri = Contacts.getLookupUri(contactId, lookupKey);
+            Uri uri = null;
+            if (!TextUtils.isEmpty(lookupKey)) {
+                uri = isContactIdIgnored
+                        ? Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey)
+                        : Contacts.getLookupUri(contactId, lookupKey);
+            }
             if (uri != null && directoryId != Directory.DEFAULT) {
                 uri = uri.buildUpon().appendQueryParameter(
                         ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId)).build();
@@ -8685,6 +8704,120 @@
                 "com.android.contacts.action.SHOW_OR_CREATE_CONTACT";
 
         /**
+         * Activity Action: Initiate a message to someone by voice. The message could be text,
+         * audio, video or image(photo). This action supports messaging with a specific contact
+         * regardless of the underlying messaging protocol used.
+         * <p>
+         * The action could be originated from the Voice Assistant as a voice interaction. In such
+         * case, a receiving activity that supports {@link android.content.Intent#CATEGORY_VOICE}
+         * could check return value of {@link android.app.Activity#isVoiceInteractionRoot} before
+         * proceeding. By doing this check the activity verifies that the action indeed was
+         * initiated by Voice Assistant and could send a message right away, without any further
+         * input from the user. This allows for a smooth user experience when sending a message by
+         * voice. Note: this activity must also support the {@link
+         * android.content.Intent#CATEGORY_DEFAULT} so it can be found by {@link
+         * android.service.voice.VoiceInteractionSession#startVoiceActivity}.
+         * <p>
+         * When the action was not initiated by Voice Assistant or when the receiving activity does
+         * not support {@link android.content.Intent#CATEGORY_VOICE}, the activity should confirm
+         * with the user before sending the message (because in this case it is unknown which app
+         * sent the intent, it could be malicious).
+         * <p>
+         * To allow the Voice Assistant to help users with contacts disambiguation, the messaging
+         * app may choose to integrate with the Contacts Provider. The following convention should
+         * be met when creating Data table for such integration:
+         * <ul>
+         * <li>Column {@link DataColumns#DATA1} should store the unique contact ID as understood by
+         * the app. This value will be used in the {@link #EXTRA_RECIPIENT_CONTACT_CHAT_ID}.</li>
+         * <li>Optionally, column {@link DataColumns#DATA3} could store a human readable label for
+         * the ID. For example it could be phone number or human readable username/user_id like
+         * "a_super_cool_user_name". This label may be shown below the Contact Name by the Voice
+         * Assistant as the user completes the voice action. If DATA3 is empty, the ID in DATA1 may
+         * be shown instead.</li>
+         * <li><em>Note: Do not use DATA3 to store the Contact Name. The Voice Assistant will
+         * already get the Contact Name from the RawContact’s display_name.</em></li>
+         * <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>
+         * </ul>
+         * <p>
+         * Input: {@link android.content.Intent#getType} is the MIME type of the data being sent.
+         * The intent sender will always put the concrete mime type in the intent type, like
+         * "text/plain" or "audio/wav" for example. If the MIME type is "text/plain", message to
+         * sent will be provided via {@link android.content.Intent#EXTRA_TEXT} as a styled
+         * CharSequence. Otherwise, the message content will be supplied through {@link
+         * android.content.Intent#setClipData(ClipData)} as a content provider URI(s). In the latter
+         * case, EXTRA_TEXT could still be supplied optionally; for example, for audio messages
+         * ClipData will contain URI of a recording and EXTRA_TEXT could contain the text
+         * transcription of this recording.
+         * <p>
+         * The message can have n recipients. The n-th recipient of the message will be provided as
+         * n-th elements of {@link #EXTRA_RECIPIENT_CONTACT_URI}, {@link
+         * #EXTRA_RECIPIENT_CONTACT_CHAT_ID} and {@link #EXTRA_RECIPIENT_CONTACT_NAME} (as a
+         * consequence, EXTRA_RECIPIENT_CONTACT_URI, EXTRA_RECIPIENT_CONTACT_CHAT_ID and
+         * EXTRA_RECIPIENT_CONTACT_NAME should all be of length n). If neither of these 3 elements
+         * is provided (e.g. all 3 are null) for the recipient or if the information provided is
+         * ambiguous then the activity should prompt the user for the recipient to send the message
+         * to.
+         * <p>
+         * Output: nothing
+         *
+         * @see #EXTRA_RECIPIENT_CONTACT_URI
+         * @see #EXTRA_RECIPIENT_CONTACT_CHAT_ID
+         * @see #EXTRA_RECIPIENT_CONTACT_NAME
+         */
+        public static final String ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS =
+                "android.provider.action.VOICE_SEND_MESSAGE_TO_CONTACTS";
+
+        /**
+         * This extra specifies a content provider uri(s) for the contact(s) (if the contacts were
+         * located in the Contacts Provider), used with {@link
+         * #ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS} to supply the recipient(s). The value of this
+         * extra is a {@code String[]}. The number of elements in the array should be equal to
+         * number of recipients (and consistent with {@link #EXTRA_RECIPIENT_CONTACT_CHAT_ID} and
+         * {@link #EXTRA_RECIPIENT_CONTACT_NAME}). When the value of the element for the particular
+         * recipient is absent, it will be set to null.
+         * <p>
+         * <em>Note: one contact may have multiple accounts (e.g. Chat IDs) on a specific messaging
+         * platform, so this may be ambiguous. E.g., one contact “John Smith” could have two
+         * accounts on the same messaging app.</em>
+         * <p>
+         * <em>Example value: {"content://com.android.contacts/contacts/16"}</em>
+         */
+        public static final String EXTRA_RECIPIENT_CONTACT_URI =
+                "android.provider.extra.RECIPIENT_CONTACT_URI";
+
+        /**
+         * This extra specifies a messaging app’s unique ID(s) for the contact(s), used with {@link
+         * #ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS} to supply the recipient(s). The value of this
+         * extra is a {@code String[]}. The number of elements in the array should be equal to
+         * number of recipients (and consistent with {@link #EXTRA_RECIPIENT_CONTACT_URI} and {@link
+         * #EXTRA_RECIPIENT_CONTACT_NAME}). When the value of the element for the particular
+         * recipient is absent, it will be set to null.
+         * <p>
+         * The value of the elements comes from the {@link DataColumns#DATA1} column in Contacts
+         * Provider, and should be the unambiguous contact endpoint. This value is app-specific, it
+         * could be a phone number or some proprietary ID.
+         */
+        public static final String EXTRA_RECIPIENT_CONTACT_CHAT_ID =
+                "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
+
+        /**
+         * This extra specifies the contact name (full name from the Contacts Provider), used with
+         * {@link #ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS} to supply the recipient. The value of this
+         * extra is a {@code String[]}. The number of elements in the array should be equal to
+         * number of recipients (and consistent with {@link #EXTRA_RECIPIENT_CONTACT_URI} and {@link
+         * #EXTRA_RECIPIENT_CONTACT_CHAT_ID}). When the value of the element for the particular
+         * recipient is absent, it will be set to null.
+         * <p>
+         * The value of the elements comes from RawContact's display_name column.
+         * <p>
+         * <em>Example value: {"Jane Doe"}</em>
+         */
+        public static final String EXTRA_RECIPIENT_CONTACT_NAME =
+                "android.provider.extra.RECIPIENT_CONTACT_NAME";
+
+        /**
          * Starts an Activity that lets the user select the multiple phones from a
          * list of phone numbers which come from the contacts or
          * {@link #EXTRA_PHONE_URIS}.
diff --git a/core/java/android/provider/ContactsInternal.java b/core/java/android/provider/ContactsInternal.java
index 36ef52d..2cd1d48 100644
--- a/core/java/android/provider/ContactsInternal.java
+++ b/core/java/android/provider/ContactsInternal.java
@@ -42,10 +42,12 @@
     private static final UriMatcher sContactsUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
 
     private static final int CONTACTS_URI_LOOKUP_ID = 1000;
+    private static final int CONTACTS_URI_LOOKUP = 1001;
 
     static {
         // Contacts URI matching table
         final UriMatcher matcher = sContactsUriMatcher;
+        matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*", CONTACTS_URI_LOOKUP);
         matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_URI_LOOKUP_ID);
     }
 
@@ -57,6 +59,7 @@
 
         final int match = sContactsUriMatcher.match(uri);
         switch (match) {
+            case CONTACTS_URI_LOOKUP:
             case CONTACTS_URI_LOOKUP_ID: {
                 if (maybeStartManagedQuickContact(context, intent)) {
                     return; // Request handled by DPM.  Just return here.
@@ -89,7 +92,10 @@
 
         // Decompose into an ID and a lookup key.
         final List<String> pathSegments = uri.getPathSegments();
-        final long contactId = ContentUris.parseId(uri);
+        final boolean isContactIdIgnored = pathSegments.size() < 4;
+        final long contactId = isContactIdIgnored
+                ? ContactsContract.Contacts.ENTERPRISE_CONTACT_ID_BASE //contact id will be ignored
+                : ContentUris.parseId(uri);
         final String lookupKey = pathSegments.get(2);
         final String directoryIdStr = uri.getQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY);
         final long directoryId = (directoryIdStr == null)
@@ -119,8 +125,8 @@
         final long actualDirectoryId = (directoryId
                 - ContactsContract.Directory.ENTERPRISE_DIRECTORY_ID_BASE);
 
-        dpm.startManagedQuickContact(actualLookupKey, actualContactId, actualDirectoryId,
-                originalIntent);
+        dpm.startManagedQuickContact(actualLookupKey, actualContactId, isContactIdIgnored,
+                actualDirectoryId, originalIntent);
         return true;
     }
 }
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 084ff77..032d83d 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -62,7 +62,7 @@
  * All client apps must hold a valid URI permission grant to access documents,
  * typically issued when a user makes a selection through
  * {@link Intent#ACTION_OPEN_DOCUMENT}, {@link Intent#ACTION_CREATE_DOCUMENT},
- * or {@link Intent#ACTION_OPEN_DOCUMENT_TREE}.
+ * {@link Intent#ACTION_OPEN_DOCUMENT_TREE}, or {@link Intent#ACTION_OPEN_EXTERNAL_DIRECTORY}.
  *
  * @see DocumentsProvider
  */
@@ -230,11 +230,13 @@
          * @see #FLAG_SUPPORTS_WRITE
          * @see #FLAG_SUPPORTS_DELETE
          * @see #FLAG_SUPPORTS_THUMBNAIL
-         * @see #FLAG_SUPPORTS_TYPED_DOCUMENT
          * @see #FLAG_DIR_PREFERS_GRID
          * @see #FLAG_DIR_PREFERS_LAST_MODIFIED
          * @see #FLAG_VIRTUAL_DOCUMENT
          * @see #FLAG_ARCHIVE
+         * @see #FLAG_SUPPORTS_COPY
+         * @see #FLAG_SUPPORTS_MOVE
+         * @see #FLAG_SUPPORTS_REMOVE
          */
         public static final String COLUMN_FLAGS = "flags";
 
@@ -343,21 +345,12 @@
          * within the same document provider.
          *
          * @see #COLUMN_FLAGS
-         * @see DocumentsContract#moveDocument(ContentProviderClient, Uri, Uri)
-         * @see DocumentsProvider#moveDocument(String, String)
+         * @see DocumentsContract#moveDocument(ContentProviderClient, Uri, Uri, Uri)
+         * @see DocumentsProvider#moveDocument(String, String, String)
          */
         public static final int FLAG_SUPPORTS_MOVE = 1 << 8;
 
         /**
-         * Flag indicating that a document can be converted to alternative types.
-         *
-         * @see #COLUMN_FLAGS
-         * @see DocumentsProvider#openTypedDocument(String, String, Bundle,
-         *      android.os.CancellationSignal)
-         */
-        public static final int FLAG_SUPPORTS_TYPED_DOCUMENT = 1 << 9;
-
-        /**
          * Flag indicating that a document is virtual, and doesn't have byte
          * representation in the MIME type specified as {@link #COLUMN_MIME_TYPE}.
          *
@@ -366,7 +359,7 @@
          * @see DocumentsProvider#openTypedDocument(String, String, Bundle,
          *      android.os.CancellationSignal)
          */
-        public static final int FLAG_VIRTUAL_DOCUMENT = 1 << 10;
+        public static final int FLAG_VIRTUAL_DOCUMENT = 1 << 9;
 
         /**
          * Flag indicating that a document is an archive, and it's contents can be
@@ -378,7 +371,16 @@
          * @see #COLUMN_FLAGS
          * @see DocumentsProvider#queryChildDocuments(String, String[], String)
          */
-        public static final int FLAG_ARCHIVE = 1 << 11;
+        public static final int FLAG_ARCHIVE = 1 << 10;
+
+        /**
+         * Flag indicating that a document can be removed from a parent.
+         *
+         * @see #COLUMN_FLAGS
+         * @see DocumentsContract#removeDocument(ContentProviderClient, Uri, Uri)
+         * @see DocumentsProvider#removeDocument(String, String)
+         */
+        public static final int FLAG_SUPPORTS_REMOVE = 1 << 11;
 
         /**
          * Flag indicating that document titles should be hidden when viewing
@@ -622,8 +624,12 @@
     public static final String METHOD_MOVE_DOCUMENT = "android:moveDocument";
     /** {@hide} */
     public static final String METHOD_IS_CHILD_DOCUMENT = "android:isChildDocument";
+    /** {@hide} */
+    public static final String METHOD_REMOVE_DOCUMENT = "android:removeDocument";
 
     /** {@hide} */
+    public static final String EXTRA_PARENT_URI = "parentUri";
+    /** {@hide} */
     public static final String EXTRA_URI = "uri";
 
     private static final String PATH_ROOT = "root";
@@ -843,7 +849,12 @@
         return uri != null && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme());
     }
 
-    /** {@hide} */
+    /**
+     * Test if the given URI represents a {@link Document} tree.
+     *
+     * @see #buildTreeDocumentUri(String, String)
+     * @see #getTreeDocumentId(Uri, String)
+     */
     public static boolean isTreeUri(Uri uri) {
         final List<String> paths = uri.getPathSegments();
         return (paths.size() >= 2 && PATH_TREE.equals(paths.get(0)));
@@ -1149,7 +1160,6 @@
      * @param targetParentDocumentUri document which will become a parent of the source
      *         document's copy.
      * @return the copied document, or {@code null} if failed.
-     * @hide
      */
     public static Uri copyDocument(ContentResolver resolver, Uri sourceDocumentUri,
             Uri targetParentDocumentUri) {
@@ -1180,17 +1190,18 @@
      * Moves the given document under a new parent.
      *
      * @param sourceDocumentUri document with {@link Document#FLAG_SUPPORTS_MOVE}
+     * @param sourceParentDocumentUri parent document of the document to move.
      * @param targetParentDocumentUri document which will become a new parent of the source
      *         document.
      * @return the moved document, or {@code null} if failed.
-     * @hide
      */
     public static Uri moveDocument(ContentResolver resolver, Uri sourceDocumentUri,
-            Uri targetParentDocumentUri) {
+            Uri sourceParentDocumentUri, Uri targetParentDocumentUri) {
         final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
                 sourceDocumentUri.getAuthority());
         try {
-            return moveDocument(client, sourceDocumentUri, targetParentDocumentUri);
+            return moveDocument(client, sourceParentDocumentUri, sourceDocumentUri,
+                    targetParentDocumentUri);
         } catch (Exception e) {
             Log.w(TAG, "Failed to move document", e);
             return null;
@@ -1201,9 +1212,10 @@
 
     /** {@hide} */
     public static Uri moveDocument(ContentProviderClient client, Uri sourceDocumentUri,
-            Uri targetParentDocumentUri) throws RemoteException {
+            Uri sourceParentDocumentUri, Uri targetParentDocumentUri) throws RemoteException {
         final Bundle in = new Bundle();
         in.putParcelable(DocumentsContract.EXTRA_URI, sourceDocumentUri);
+        in.putParcelable(DocumentsContract.EXTRA_PARENT_URI, sourceParentDocumentUri);
         in.putParcelable(DocumentsContract.EXTRA_TARGET_URI, targetParentDocumentUri);
 
         final Bundle out = client.call(METHOD_MOVE_DOCUMENT, null, in);
@@ -1211,6 +1223,41 @@
     }
 
     /**
+     * Removes the given document from a parent directory.
+     *
+     * <p>In contrast to {@link #deleteDocument} it requires specifying the parent.
+     * This method is especially useful if the document can be in multiple parents.
+     *
+     * @param documentUri document with {@link Document#FLAG_SUPPORTS_REMOVE}
+     * @param parentDocumentUri parent document of the document to remove.
+     * @return true if the document was removed successfully.
+     */
+    public static boolean removeDocument(ContentResolver resolver, Uri documentUri,
+            Uri parentDocumentUri) {
+        final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
+                documentUri.getAuthority());
+        try {
+            removeDocument(client, documentUri, parentDocumentUri);
+            return true;
+        } catch (Exception e) {
+            Log.w(TAG, "Failed to remove document", e);
+            return false;
+        } finally {
+            ContentProviderClient.releaseQuietly(client);
+        }
+    }
+
+    /** {@hide} */
+    public static void removeDocument(ContentProviderClient client, Uri documentUri,
+            Uri parentDocumentUri) throws RemoteException {
+        final Bundle in = new Bundle();
+        in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
+        in.putParcelable(DocumentsContract.EXTRA_PARENT_URI, parentDocumentUri);
+
+        client.call(METHOD_REMOVE_DOCUMENT, null, in);
+    }
+
+    /**
      * Open the given image for thumbnail purposes, using any embedded EXIF
      * thumbnail if available, and providing orientation hints from the parent
      * image.
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index e25ba35..7a82cd1e 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -21,6 +21,7 @@
 import static android.provider.DocumentsContract.METHOD_DELETE_DOCUMENT;
 import static android.provider.DocumentsContract.METHOD_IS_CHILD_DOCUMENT;
 import static android.provider.DocumentsContract.METHOD_MOVE_DOCUMENT;
+import static android.provider.DocumentsContract.METHOD_REMOVE_DOCUMENT;
 import static android.provider.DocumentsContract.METHOD_RENAME_DOCUMENT;
 import static android.provider.DocumentsContract.buildDocumentUri;
 import static android.provider.DocumentsContract.buildDocumentUriMaybeUsingTree;
@@ -289,15 +290,36 @@
      * be returned.
      *
      * @param sourceDocumentId the document to move.
+     * @param sourceParentDocumentId the parent of the document to move.
      * @param targetParentDocumentId the target document to be a new parent of the
      *     source document.
      * @hide
      */
     @SuppressWarnings("unused")
-    public String moveDocument(String sourceDocumentId, String targetParentDocumentId)
+    public String moveDocument(String sourceDocumentId, String sourceParentDocumentId,
+            String targetParentDocumentId)
             throws FileNotFoundException {
         throw new UnsupportedOperationException("Move not supported");
     }
+
+    /**
+     * Removes the requested document or a document tree.
+     *
+     * <p>In contrast to {@link #deleteDocument} it requires specifying the parent.
+     * This method is especially useful if the document can be in multiple parents.
+     *
+     * <p>It's the responsibility of the provider to revoke grants if the document is
+     * removed from the last parent, and effectively the document is deleted.
+     *
+     * @param documentId the document to remove.
+     * @param parentDocumentId the parent of the document to move.
+     */
+    @SuppressWarnings("unused")
+    public boolean removeDocument(String documentId, String parentDocumentId)
+            throws FileNotFoundException {
+        throw new UnsupportedOperationException("Remove not supported");
+    }
+
     /**
      * Return all roots currently provided. To display to users, you must define
      * at least one root. You should avoid making network requests to keep this
@@ -517,13 +539,12 @@
      *            provider.
      * @param signal used by the caller to signal if the request should be
      *            cancelled. May be null.
-     * @see Document#FLAG_SUPPORTS_TYPED_DOCUMENT
      */
     @SuppressWarnings("unused")
     public AssetFileDescriptor openTypedDocument(
             String documentId, String mimeTypeFilter, Bundle opts, CancellationSignal signal)
             throws FileNotFoundException {
-        throw new UnsupportedOperationException("Typed documents not supported");
+        throw new FileNotFoundException("The requested MIME type is not supported.");
     }
 
     /**
@@ -760,7 +781,7 @@
 
                 out.putParcelable(DocumentsContract.EXTRA_URI, newDocumentUri);
 
-                // Original document no longer exists, clean up any grants
+                // Original document no longer exists, clean up any grants.
                 revokeDocumentPermission(documentId);
             }
 
@@ -768,7 +789,7 @@
             enforceWritePermissionInner(documentUri, getCallingPackage(), null);
             deleteDocument(documentId);
 
-            // Document no longer exists, clean up any grants
+            // Document no longer exists, clean up any grants.
             revokeDocumentPermission(documentId);
 
         } else if (METHOD_COPY_DOCUMENT.equals(method)) {
@@ -794,13 +815,16 @@
             }
 
         } else if (METHOD_MOVE_DOCUMENT.equals(method)) {
+            final Uri parentSourceUri = extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI);
+            final String parentSourceId = DocumentsContract.getDocumentId(parentSourceUri);
             final Uri targetUri = extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI);
             final String targetId = DocumentsContract.getDocumentId(targetUri);
 
-            enforceReadPermissionInner(documentUri, getCallingPackage(), null);
+            enforceWritePermissionInner(documentUri, getCallingPackage(), null);
+            enforceReadPermissionInner(parentSourceUri, getCallingPackage(), null);
             enforceWritePermissionInner(targetUri, getCallingPackage(), null);
 
-            final String newDocumentId = moveDocument(documentId, targetId);
+            final String newDocumentId = moveDocument(documentId, parentSourceId, targetId);
 
             if (newDocumentId != null) {
                 final Uri newDocumentUri = buildDocumentUriMaybeUsingTree(documentUri,
@@ -815,9 +839,20 @@
                 out.putParcelable(DocumentsContract.EXTRA_URI, newDocumentUri);
             }
 
-            // Original document no longer exists, clean up any grants
+            // Original document no longer exists, clean up any grants.
             revokeDocumentPermission(documentId);
 
+        } else if (METHOD_REMOVE_DOCUMENT.equals(method)) {
+            final Uri parentSourceUri = extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI);
+            final String parentSourceId = DocumentsContract.getDocumentId(parentSourceUri);
+
+            enforceReadPermissionInner(parentSourceUri, getCallingPackage(), null);
+            enforceWritePermissionInner(documentUri, getCallingPackage(), null);
+            removeDocument(documentId, parentSourceId);
+
+            // It's responsibility of the provider to revoke any grants, as the document may be
+            // still attached to another parents.
+
         } else {
             throw new UnsupportedOperationException("Method not supported " + method);
         }
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index b2d9b934..8472f78 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -609,7 +609,7 @@
          * This download has successfully completed.
          * Warning: there might be other status values that indicate success
          * in the future.
-         * Use isSucccess() to capture the entire category.
+         * Use isStatusSuccess() to capture the entire category.
          */
         public static final int STATUS_SUCCESS = 200;
 
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 48b3c1a..89ac27c9a 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -384,8 +384,14 @@
 
     public interface MediaColumns extends BaseColumns {
         /**
-         * The data stream for the file
-         * <P>Type: DATA STREAM</P>
+         * Path to the file on disk.
+         * <p>
+         * Note that apps may not have filesystem permissions to directly access
+         * this path. Instead of trying to open this path directly, apps should
+         * use {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
+         * access.
+         * <p>
+         * Type: TEXT
          */
         public static final String DATA = "_data";
 
@@ -1149,8 +1155,15 @@
             public static final String DEFAULT_SORT_ORDER = "image_id ASC";
 
             /**
-             * The data stream for the thumbnail
-             * <P>Type: DATA STREAM</P>
+             * Path to the thumbnail file on disk.
+             * <p>
+             * Note that apps may not have filesystem permissions to directly
+             * access this path. Instead of trying to open this path directly,
+             * apps should use
+             * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
+             * access.
+             * <p>
+             * Type: TEXT
              */
             public static final String DATA = "_data";
 
@@ -1596,8 +1609,15 @@
             public static final String NAME = "name";
 
             /**
-             * The data stream for the playlist file
-             * <P>Type: DATA STREAM</P>
+             * Path to the playlist file on disk.
+             * <p>
+             * Note that apps may not have filesystem permissions to directly
+             * access this path. Instead of trying to open this path directly,
+             * apps should use
+             * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
+             * access.
+             * <p>
+             * Type: TEXT
              */
             public static final String DATA = "_data";
 
@@ -2192,8 +2212,15 @@
             public static final String DEFAULT_SORT_ORDER = "video_id ASC";
 
             /**
-             * The data stream for the thumbnail
-             * <P>Type: DATA STREAM</P>
+             * Path to the thumbnail file on disk.
+             * <p>
+             * Note that apps may not have filesystem permissions to directly
+             * access this path. Instead of trying to open this path directly,
+             * apps should use
+             * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
+             * access.
+             * <p>
+             * Type: TEXT
              */
             public static final String DATA = "_data";
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
old mode 100644
new mode 100755
index a1e5510..c9c0cde
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -19,6 +19,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.app.ActivityThread;
 import android.app.AppOpsManager;
 import android.app.Application;
@@ -128,6 +129,27 @@
             "android.settings.WIRELESS_SETTINGS";
 
     /**
+     * Activity Action: Show tether provisioning activity.
+     *
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: {@link ConnectivityManager.EXTRA_TETHER_TYPE} should be included to specify which type
+     * of tethering should be checked. {@link ConnectivityManager.EXTRA_PROVISION_CALLBACK} should
+     * contain a {@link ResultReceiver} which will be called back with a tether result code.
+     * <p>
+     * Output: The result of the provisioning check.
+     * {@link ConnectivityManager.TETHER_ERROR_NO_ERROR} if successful,
+     * {@link ConnectivityManager.TETHER_ERROR_PROVISION_FAILED} for failure.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_TETHER_PROVISIONING =
+            "android.settings.TETHER_PROVISIONING_UI";
+
+    /**
      * Activity Action: Show settings to allow entering/exiting airplane mode.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
@@ -479,6 +501,23 @@
             "android.settings.USER_DICTIONARY_SETTINGS";
 
     /**
+     * Activity Action: Show settings to configure the hardware keyboard layout.
+     * <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";
+
+    /**
      * Activity Action: Adds a word to the user dictionary.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
@@ -640,7 +679,7 @@
      * provided by the platform for applications to operate correctly in the various power
      * saving mode.  This is only for unusual applications that need to deeply control their own
      * execution, at the potential expense of the user's battery life.  Note that these applications
-     * greatly run the risk of showing to the user has how power consumers on their device.</p>
+     * greatly run the risk of showing to the user as high power consumers on their device.</p>
      * <p>
      * Input: The Intent's data URI must specify the application package name
      * to be shown, with the "package" scheme.  That is "package:com.my.app".
@@ -1092,6 +1131,22 @@
     public static final String ACTION_HOME_SETTINGS
             = "android.settings.HOME_SETTINGS";
 
+
+
+    /**
+     * Activity Action: Show Default apps settings.
+     * <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_MANAGE_DEFAULT_APPS_SETTINGS
+            = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS";
+
     /**
      * Activity Action: Show notification settings.
      *
@@ -1122,6 +1177,19 @@
     /** @hide */ public static final String EXTRA_APP_UID = "app_uid";
     /** @hide */ public static final String EXTRA_APP_PACKAGE = "app_package";
 
+    /**
+     * Activity Action: Show a dialog with disabled by policy message.
+     * <p> If an user action is disabled by policy, this dialog can be triggered to let
+     * the user know about this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS
+            = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
+
     // End of Intent actions for Settings
 
     /**
@@ -2576,6 +2644,15 @@
         private static final Validator MICROPHONE_MUTE_VALIDATOR = sBooleanValidator;
 
         /**
+         * Master mono (int 1 = mono, 0 = normal).
+         *
+         * @hide
+         */
+        public static final String MASTER_MONO = "master_mono";
+
+        private static final Validator MASTER_MONO_VALIDATOR = sBooleanValidator;
+
+        /**
          * Whether the notifications should use the ring volume (value of 1) or
          * a separate notification volume (value of 0). In most cases, users
          * will have this enabled so the notification and ringer volumes will be
@@ -3239,6 +3316,7 @@
             WIFI_STATIC_DNS2,
             BLUETOOTH_DISCOVERABILITY,
             BLUETOOTH_DISCOVERABILITY_TIMEOUT,
+            FONT_SCALE,
             DIM_SCREEN,
             SCREEN_OFF_TIMEOUT,
             SCREEN_BRIGHTNESS,
@@ -3270,7 +3348,8 @@
             VIBRATE_WHEN_RINGING,
             RINGTONE,
             LOCK_TO_APP_ENABLED,
-            NOTIFICATION_SOUND
+            NOTIFICATION_SOUND,
+            ACCELEROMETER_ROTATION
         };
 
         /**
@@ -3341,6 +3420,7 @@
             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);
             PRIVATE_SETTINGS.add(MEDIA_BUTTON_RECEIVER);
@@ -3419,6 +3499,7 @@
             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);
             VALIDATORS.put(MEDIA_BUTTON_RECEIVER, MEDIA_BUTTON_RECEIVER_VALIDATOR);
@@ -4333,6 +4414,7 @@
          * The currently selected voice interaction service flattened ComponentName.
          * @hide
          */
+        @TestApi
         public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service";
 
         /**
@@ -4386,6 +4468,13 @@
         public static final String HTTP_PROXY = Global.HTTP_PROXY;
 
         /**
+         * Package designated as always-on VPN provider.
+         *
+         * @hide
+         */
+        public static final String ALWAYS_ON_VPN_APP = "always_on_vpn_app";
+
+        /**
          * Whether applications can be installed for this user via the system's
          * {@link Intent#ACTION_INSTALL_PACKAGE} mechanism.
          *
@@ -4956,19 +5045,22 @@
 
         /**
          * List of the enabled print services.
+         *
+         * N and beyond uses {@link #DISABLED_PRINT_SERVICES}. But this might be used in an upgrade
+         * from pre-N.
+         *
          * @hide
          */
         public static final String ENABLED_PRINT_SERVICES =
             "enabled_print_services";
 
         /**
-         * List of the system print services we enabled on first boot. On
-         * first boot we enable all system, i.e. bundled print services,
-         * once, so they work out-of-the-box.
+         * List of the disabled print services.
+         *
          * @hide
          */
-        public static final String ENABLED_ON_FIRST_BOOT_SYSTEM_PRINT_SERVICES =
-            "enabled_on_first_boot_system_print_services";
+        public static final String DISABLED_PRINT_SERVICES =
+            "disabled_print_services";
 
         /**
          * Setting to always use the default text-to-speech settings regardless
@@ -4998,6 +5090,14 @@
         public static final String TTS_DEFAULT_SYNTH = "tts_default_synth";
 
         /**
+         * Whether text-to-speech higher speech rate is enabled.
+         * 0 = disabled.
+         * 1 = enabled.
+         * @hide
+         */
+        public static final String TTS_DEFAULT_HIGHER_SPEECH_RATE_ENABLED =
+            "tts_default_higher_speech_rate_enabled";
+        /**
          * Default text-to-speech language.
          *
          * @deprecated this setting is no longer in use, as of the Ice Cream
@@ -5617,6 +5717,15 @@
         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 ':'.
          *
@@ -5770,10 +5879,15 @@
             PARENTAL_CONTROL_ENABLED,
             PARENTAL_CONTROL_REDIRECT_URL,
             USB_MASS_STORAGE_ENABLED,                           // moved to global
+            ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
+            ACCESSIBILITY_DISPLAY_DALTONIZER,
+            ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
+            ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
             ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
             ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
             ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE,
             ACCESSIBILITY_SCRIPT_INJECTION,
+            ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS,
             BACKUP_AUTO_RESTORE,
             ENABLED_ACCESSIBILITY_SERVICES,
             ENABLED_NOTIFICATION_LISTENERS,
@@ -5783,6 +5897,7 @@
             ACCESSIBILITY_ENABLED,
             ACCESSIBILITY_SPEAK_PASSWORD,
             ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
+            ACCESSIBILITY_CAPTIONING_PRESET,
             ACCESSIBILITY_CAPTIONING_ENABLED,
             ACCESSIBILITY_CAPTIONING_LOCALE,
             ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR,
@@ -5791,14 +5906,17 @@
             ACCESSIBILITY_CAPTIONING_EDGE_COLOR,
             ACCESSIBILITY_CAPTIONING_TYPEFACE,
             ACCESSIBILITY_CAPTIONING_FONT_SCALE,
+            ACCESSIBILITY_CAPTIONING_WINDOW_COLOR,
             TTS_USE_DEFAULTS,
             TTS_DEFAULT_RATE,
+            TTS_DEFAULT_HIGHER_SPEECH_RATE_ENABLED,
             TTS_DEFAULT_PITCH,
             TTS_DEFAULT_SYNTH,
             TTS_DEFAULT_LANG,
             TTS_DEFAULT_COUNTRY,
             TTS_ENABLED_PLUGINS,
             TTS_DEFAULT_LOCALE,
+            SHOW_IME_WITH_HARD_KEYBOARD,
             WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,            // moved to global
             WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,               // moved to global
             WIFI_NUM_OPEN_NETWORKS_KEPT,                        // moved to global
@@ -5812,9 +5930,16 @@
             UI_NIGHT_MODE,
             SLEEP_TIMEOUT,
             DOUBLE_TAP_TO_WAKE,
+            WAKE_GESTURE_ENABLED,
+            LONG_PRESS_TIMEOUT,
             CAMERA_GESTURE_DISABLED,
             ACCESSIBILITY_AUTOCLICK_ENABLED,
-            ACCESSIBILITY_AUTOCLICK_DELAY
+            ACCESSIBILITY_AUTOCLICK_DELAY,
+            ACCESSIBILITY_LARGE_POINTER_ICON,
+            PREFERRED_TTY_MODE,
+            ENHANCED_VOICE_PRIVACY_ENABLED,
+            TTY_MODE_ENABLED,
+            INCALL_POWER_BUTTON_BEHAVIOR
         };
 
         /**
@@ -6108,6 +6233,13 @@
         public static final String AIRPLANE_MODE_TOGGLEABLE_RADIOS = "airplane_mode_toggleable_radios";
 
         /**
+         * A Long representing a bitmap of profiles that should be disabled when bluetooth starts.
+         * See {@link android.bluetooth.BluetoothProfile}.
+         * {@hide}
+         */
+        public static final String BLUETOOTH_DISABLED_PROFILES = "bluetooth_disabled_profiles";
+
+        /**
          * The policy for deciding when Wi-Fi should go to sleep (which will in
          * turn switch to using the mobile data as an Internet connection).
          * <p>
@@ -6342,6 +6474,13 @@
         public static final String DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES
                 = "force_resizable_activities";
 
+        /**
+         * Whether to enable experimental freeform support for windows.
+         * @hide
+         */
+        public static final String DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT
+                = "enable_freeform_support";
+
        /**
         * Whether user has enabled development settings.
         */
@@ -7325,6 +7464,9 @@
                 BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX = "bluetooth_a2dp_sink_priority_";
         /** {@hide} */
         public static final String
+                BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX = "bluetooth_a2dp_src_priority_";
+        /** {@hide} */
+        public static final String
                 BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX = "bluetooth_input_device_priority_";
         /** {@hide} */
         public static final String
@@ -7372,10 +7514,12 @@
          * The following keys are supported:
          *
          * <pre>
-         * idle_duration        (long)
+         * idle_duration2       (long)
          * wallclock_threshold  (long)
          * parole_interval      (long)
          * parole_duration      (long)
+         *
+         * idle_duration        (long) // This is deprecated and used to circumvent b/26355386.
          * </pre>
          *
          * <p>
@@ -7425,6 +7569,14 @@
         }
 
         /**
+         * Get the key that retrieves a bluetooth a2dp src's priority.
+         * @hide
+         */
+        public static final String getBluetoothA2dpSrcPriorityKey(String address) {
+            return BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
+        }
+
+        /**
          * Get the key that retrieves a bluetooth Input Device's priority.
          * @hide
          */
@@ -8204,7 +8356,6 @@
         /**
          * Whether to enable contacts metadata syncing or not
          * The value 1 - enable, 0 - disable
-         * @hide
          */
         public static final String CONTACT_METADATA_SYNC = "contact_metadata_sync";
 
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index 76eaea9..8ee9d1e 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -101,6 +101,12 @@
     public static final String ACTION_FETCH_VOICEMAIL = "android.intent.action.FETCH_VOICEMAIL";
 
     /**
+     * Broadcast intent to request all voicemail sources to perform a sync with the remote server.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_SYNC_VOICEMAIL = "android.intent.action.SYNC_VOICEMAIL";
+
+    /**
      * Extra included in {@link Intent#ACTION_PROVIDER_CHANGED} broadcast intents to indicate if the
      * receiving package made this change.
      */
@@ -245,6 +251,13 @@
         public static final String DELETED = "deleted";
 
         /**
+         * The date the row is last inserted, updated, or marked as deleted, in milliseconds
+         * since the epoch. Read only.
+         * <P>Type: INTEGER (long)</P>
+         */
+        public static final String LAST_MODIFIED = "last_modified";
+
+        /**
          * A convenience method to build voicemail URI specific to a source package by appending
          * {@link VoicemailContract#PARAM_KEY_SOURCE_PACKAGE} param to the base URI.
          */
@@ -386,6 +399,14 @@
          * <P>Type: INTEGER</P>
          */
         public static final String CONFIGURATION_STATE = "configuration_state";
+        /**
+         * Value of {@link #CONFIGURATION_STATE} passed into
+         * {@link #setStatus(Context, PhoneAccountHandle, int, int, int)} to indicate that the
+         * {@link #CONFIGURATION_STATE} field is not to be changed
+         *
+         * @hide
+         */
+        public static final int CONFIGURATION_STATE_IGNORE = -1;
         /** Value of {@link #CONFIGURATION_STATE} to indicate an all OK configuration status. */
         public static final int CONFIGURATION_STATE_OK = 0;
         /**
@@ -411,15 +432,50 @@
          */
         public static final String DATA_CHANNEL_STATE = "data_channel_state";
         /**
+         * Value of {@link #DATA_CHANNEL_STATE} passed into
+         * {@link #setStatus(Context, PhoneAccountHandle, int, int, int)} to indicate that the
+         * {@link #DATA_CHANNEL_STATE} field is not to be changed
+         *
+         * @hide
+         */
+        public static final int DATA_CHANNEL_STATE_IGNORE = -1;
+        /**
          *  Value of {@link #DATA_CHANNEL_STATE} to indicate that data channel is working fine.
          */
         public static final int DATA_CHANNEL_STATE_OK = 0;
         /**
-         * Value of {@link #DATA_CHANNEL_STATE} to indicate that data channel connection is not
-         * working.
+         *  Value of {@link #DATA_CHANNEL_STATE} to indicate that data channel failed to find a
+         *  suitable network to connect to the server.
          */
         public static final int DATA_CHANNEL_STATE_NO_CONNECTION = 1;
         /**
+         *  Value of {@link #DATA_CHANNEL_STATE} to indicate that data channel failed to find a
+         *  suitable network to connect to the server, and the carrier requires using cellular
+         *  data network to connect to the server.
+         */
+        public static final int DATA_CHANNEL_STATE_NO_CONNECTION_CELLULAR_REQUIRED = 2;
+        /**
+         *  Value of {@link #DATA_CHANNEL_STATE} to indicate that data channel received incorrect
+         *  settings or credentials to connect to the server
+         */
+        public static final int DATA_CHANNEL_STATE_BAD_CONFIGURATION = 3;
+        /**
+         *  Value of {@link #DATA_CHANNEL_STATE} to indicate that a error has occurred in the data
+         *  channel while communicating with the server
+         */
+        public static final int DATA_CHANNEL_STATE_COMMUNICATION_ERROR = 4;
+        /**
+         *  Value of {@link #DATA_CHANNEL_STATE} to indicate that the server reported an internal
+         *  error to the data channel.
+         */
+        public static final int DATA_CHANNEL_STATE_SERVER_ERROR = 5;
+        /**
+         *  Value of {@link #DATA_CHANNEL_STATE} to indicate that while there is a suitable network,
+         *  the data channel is unable to establish a connection with the server.
+         */
+        public static final int DATA_CHANNEL_STATE_SERVER_CONNECTION_ERROR = 6;
+
+        /**
          * The notification channel state of the voicemail source. This is the channel through which
          * the source gets notified of new voicemails on the remote server.
          * <P> Possible values:
@@ -431,6 +487,14 @@
          */
         public static final String NOTIFICATION_CHANNEL_STATE = "notification_channel_state";
         /**
+         * Value of {@link #NOTIFICATION_CHANNEL_STATE} passed into
+         * {@link #setStatus(Context, PhoneAccountHandle, int, int, int)} to indicate that the
+         * {@link #NOTIFICATION_CHANNEL_STATE} field is not to be changed
+         *
+         * @hide
+         */
+        public static final int NOTIFICATION_CHANNEL_STATE_IGNORE = -1;
+        /**
          * Value of {@link #NOTIFICATION_CHANNEL_STATE} to indicate that the notification channel is
          * working fine.
          */
@@ -449,6 +513,26 @@
         public static final int NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING = 2;
 
         /**
+         * Amount of resource that is used by existing voicemail in the visual voicemail inbox,
+         * or {@link #QUOTA_UNAVAILABLE}. Unit is not specified.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String QUOTA_OCCUPIED = "quota_occupied";
+
+        /**
+         * Total resource in the visual voicemail inbox that can be used, or
+         * {@link #QUOTA_UNAVAILABLE}. Unit is not specified.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String QUOTA_TOTAL = "quota_total";
+
+        /**
+         * Value for {@link #QUOTA_OCCUPIED} and {@link #QUOTA_TOTAL} to indicate that no
+         * information is available.
+         */
+        public static final int QUOTA_UNAVAILABLE = -1;
+
+        /**
          * A convenience method to build status URI specific to a source package by appending
          * {@link VoicemailContract#PARAM_KEY_SOURCE_PACKAGE} param to the base URI.
          */
@@ -470,38 +554,51 @@
          */
         public static void setStatus(Context context, PhoneAccountHandle accountHandle,
                 int configurationState, int dataChannelState, int notificationChannelState) {
-            ContentResolver contentResolver = context.getContentResolver();
-            Uri statusUri = buildSourceUri(context.getPackageName());
             ContentValues values = new ContentValues();
             values.put(Status.PHONE_ACCOUNT_COMPONENT_NAME,
                     accountHandle.getComponentName().flattenToString());
             values.put(Status.PHONE_ACCOUNT_ID, accountHandle.getId());
-            values.put(Status.CONFIGURATION_STATE, configurationState);
-            values.put(Status.DATA_CHANNEL_STATE, dataChannelState);
-            values.put(Status.NOTIFICATION_CHANNEL_STATE, notificationChannelState);
-
-            if (isStatusPresent(contentResolver, statusUri)) {
-                contentResolver.update(statusUri, values, null, null);
-            } else {
-                contentResolver.insert(statusUri, values);
+            if(configurationState != CONFIGURATION_STATE_IGNORE) {
+                values.put(Status.CONFIGURATION_STATE, configurationState);
             }
+            if(dataChannelState != DATA_CHANNEL_STATE_IGNORE) {
+                values.put(Status.DATA_CHANNEL_STATE, dataChannelState);
+            }
+            if(notificationChannelState != NOTIFICATION_CHANNEL_STATE_IGNORE) {
+                values.put(Status.NOTIFICATION_CHANNEL_STATE, notificationChannelState);
+            }
+            ContentResolver contentResolver = context.getContentResolver();
+            Uri statusUri = buildSourceUri(context.getPackageName());
+            contentResolver.insert(statusUri, values);
         }
 
         /**
-         * Determines if a voicemail source exists in the status table.
+         * A helper method to set the quota of a voicemail source. Unit is unspecified.
          *
-         * @param contentResolver A content resolver constructed from the appropriate context.
-         * @param statusUri The content uri for the source.
-         * @return {@code true} if a status entry for this source exists
+         * @param context The context from the package calling the method. This will be the source.
+         * @param accountHandle The handle for the account the source is associated with.
+         * @param occupied See {@link Status#QUOTA_OCCUPIED}
+         * @param total See {@link Status#QUOTA_TOTAL}
          */
-        private static boolean isStatusPresent(ContentResolver contentResolver, Uri statusUri) {
-            Cursor cursor = null;
-            try {
-                cursor = contentResolver.query(statusUri, null, null, null, null);
-                return cursor != null && cursor.getCount() != 0;
-            } finally {
-                if (cursor != null) cursor.close();
+        public static void setQuota(Context context, PhoneAccountHandle accountHandle, int occupied,
+                int total) {
+            if (occupied == QUOTA_UNAVAILABLE && total == QUOTA_UNAVAILABLE) {
+                return;
             }
+            ContentValues values = new ContentValues();
+            values.put(Status.PHONE_ACCOUNT_COMPONENT_NAME,
+                    accountHandle.getComponentName().flattenToString());
+            values.put(Status.PHONE_ACCOUNT_ID, accountHandle.getId());
+            if (occupied != QUOTA_UNAVAILABLE) {
+                values.put(Status.QUOTA_OCCUPIED,occupied);
+            }
+            if (total != QUOTA_UNAVAILABLE) {
+                values.put(Status.QUOTA_TOTAL,total);
+            }
+
+            ContentResolver contentResolver = context.getContentResolver();
+            Uri statusUri = buildSourceUri(context.getPackageName());
+            contentResolver.insert(statusUri, values);
         }
     }
 }
diff --git a/core/java/android/security/FrameworkNetworkSecurityPolicy.java b/core/java/android/security/FrameworkNetworkSecurityPolicy.java
index e3dac5e..83f173ec 100644
--- a/core/java/android/security/FrameworkNetworkSecurityPolicy.java
+++ b/core/java/android/security/FrameworkNetworkSecurityPolicy.java
@@ -32,4 +32,9 @@
     public boolean isCleartextTrafficPermitted() {
         return mCleartextTrafficPermitted;
     }
+
+    @Override
+    public boolean isCleartextTrafficPermitted(String hostname) {
+        return isCleartextTrafficPermitted();
+    }
 }
diff --git a/core/java/android/security/NetworkSecurityPolicy.java b/core/java/android/security/NetworkSecurityPolicy.java
index 7991d37..733a092 100644
--- a/core/java/android/security/NetworkSecurityPolicy.java
+++ b/core/java/android/security/NetworkSecurityPolicy.java
@@ -16,6 +16,11 @@
 
 package android.security;
 
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.security.net.config.ApplicationConfig;
+import android.security.net.config.ManifestConfigSource;
+
 /**
  * Network security policy.
  *
@@ -43,7 +48,7 @@
 
     /**
      * Returns whether cleartext network traffic (e.g. HTTP, FTP, WebSockets, XMPP, IMAP, SMTP --
-     * without TLS or STARTTLS) is permitted for this process.
+     * without TLS or STARTTLS) is permitted for all network communication from this process.
      *
      * <p>When cleartext network traffic is not permitted, the platform's components (e.g. HTTP and
      * FTP stacks, {@link android.app.DownloadManager}, {@link android.media.MediaPlayer}) will
@@ -64,6 +69,17 @@
     }
 
     /**
+     * Returns whether cleartext network traffic (e.g. HTTP, FTP, XMPP, IMAP, SMTP -- without
+     * TLS or STARTTLS) is permitted for communicating with {@code hostname} for this process.
+     *
+     * @see #isCleartextTrafficPermitted()
+     */
+    public boolean isCleartextTrafficPermitted(String hostname) {
+        return libcore.net.NetworkSecurityPolicy.getInstance()
+                .isCleartextTrafficPermitted(hostname);
+    }
+
+    /**
      * Sets whether cleartext network traffic is permitted for this process.
      *
      * <p>This method is used by the platform early on in the application's initialization to set
@@ -75,4 +91,17 @@
         FrameworkNetworkSecurityPolicy policy = new FrameworkNetworkSecurityPolicy(permitted);
         libcore.net.NetworkSecurityPolicy.setInstance(policy);
     }
+
+
+    /**
+     * Returns an {@link ApplicationConfig} based on the configuration for {@code packageName}.
+     *
+     * @hide
+     */
+    public static ApplicationConfig getApplicationConfigForPackage(Context context,
+            String packageName) throws PackageManager.NameNotFoundException {
+        Context appContext = context.createPackageContext(packageName, 0);
+        ManifestConfigSource source = new ManifestConfigSource(appContext);
+        return new ApplicationConfig(source);
+    }
 }
diff --git a/core/java/android/security/net/config/ApplicationConfig.java b/core/java/android/security/net/config/ApplicationConfig.java
index 71d9d5d..4de36cd 100644
--- a/core/java/android/security/net/config/ApplicationConfig.java
+++ b/core/java/android/security/net/config/ApplicationConfig.java
@@ -120,6 +120,32 @@
         return mTrustManager;
     }
 
+    /**
+     * Returns {@code true} if cleartext traffic is permitted for this application, which is the
+     * case only if all configurations permit cleartext traffic. For finer-grained policy use
+     * {@link #isCleartextTrafficPermitted(String)}.
+     */
+    public boolean isCleartextTrafficPermitted() {
+        ensureInitialized();
+        if (mConfigs != null) {
+            for (Pair<Domain, NetworkSecurityConfig> entry : mConfigs) {
+                if (!entry.second.isCleartextTrafficPermitted()) {
+                    return false;
+                }
+            }
+        }
+
+        return mDefaultConfig.isCleartextTrafficPermitted();
+    }
+
+    /**
+     * Returns {@code true} if cleartext traffic is permitted for this application when connecting
+     * to {@code hostname}.
+     */
+    public boolean isCleartextTrafficPermitted(String hostname) {
+        return getConfigForHostname(hostname).isCleartextTrafficPermitted();
+    }
+
     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 7e3601e..f3272e4 100644
--- a/core/java/android/security/net/config/CertificateSource.java
+++ b/core/java/android/security/net/config/CertificateSource.java
@@ -16,12 +16,13 @@
 
 package android.security.net.config;
 
-import java.util.Set;
 import java.security.cert.X509Certificate;
+import java.util.Set;
 
 /** @hide */
 public interface CertificateSource {
     Set<X509Certificate> getCertificates();
     X509Certificate findBySubjectAndPublicKey(X509Certificate cert);
     X509Certificate findByIssuerAndSignature(X509Certificate cert);
+    Set<X509Certificate> findAllByIssuerAndSignature(X509Certificate cert);
 }
diff --git a/core/java/android/security/net/config/CertificatesEntryRef.java b/core/java/android/security/net/config/CertificatesEntryRef.java
index ff728ef..742d430 100644
--- a/core/java/android/security/net/config/CertificatesEntryRef.java
+++ b/core/java/android/security/net/config/CertificatesEntryRef.java
@@ -17,8 +17,8 @@
 package android.security.net.config;
 
 import android.util.ArraySet;
-import java.util.Set;
 import java.security.cert.X509Certificate;
+import java.util.Set;
 
 /** @hide */
 public final class CertificatesEntryRef {
@@ -60,4 +60,8 @@
 
         return new TrustAnchor(foundCert, mOverridesPins);
     }
+
+    public Set<X509Certificate> findAllCertificatesByIssuerAndSignature(X509Certificate cert) {
+        return mSource.findAllByIssuerAndSignature(cert);
+    }
 }
diff --git a/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java b/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java
new file mode 100644
index 0000000..e7d17c2
--- /dev/null
+++ b/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.net.config;
+
+/**
+ * {@link libcore.net.NetworkSecurityPolicy} based on an {@link ApplicationConfig}.
+ *
+ * @hide
+ */
+public class ConfigNetworkSecurityPolicy extends libcore.net.NetworkSecurityPolicy {
+    private final ApplicationConfig mConfig;
+
+    public ConfigNetworkSecurityPolicy(ApplicationConfig config) {
+        mConfig = config;
+    }
+
+    @Override
+    public boolean isCleartextTrafficPermitted() {
+        return mConfig.isCleartextTrafficPermitted();
+    }
+
+    @Override
+    public boolean isCleartextTrafficPermitted(String hostname) {
+        return mConfig.isCleartextTrafficPermitted(hostname);
+    }
+}
diff --git a/core/java/android/security/net/config/DirectoryCertificateSource.java b/core/java/android/security/net/config/DirectoryCertificateSource.java
index bf29efa..b2c068c 100644
--- a/core/java/android/security/net/config/DirectoryCertificateSource.java
+++ b/core/java/android/security/net/config/DirectoryCertificateSource.java
@@ -29,6 +29,7 @@
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
+import java.util.Collections;
 import java.util.Set;
 import libcore.io.IoUtils;
 
@@ -110,10 +111,50 @@
         });
     }
 
+    @Override
+    public Set<X509Certificate> findAllByIssuerAndSignature(final X509Certificate cert) {
+        return findCerts(cert.getIssuerX500Principal(), new CertSelector() {
+            @Override
+            public boolean match(X509Certificate ca) {
+                try {
+                    cert.verify(ca.getPublicKey());
+                    return true;
+                } catch (Exception e) {
+                    return false;
+                }
+            }
+        });
+    }
+
     private static interface CertSelector {
         boolean match(X509Certificate cert);
     }
 
+    private Set<X509Certificate> findCerts(X500Principal subj, CertSelector selector) {
+        String hash = getHash(subj);
+        Set<X509Certificate> certs = null;
+        for (int index = 0; index >= 0; index++) {
+            String fileName = hash + "." + index;
+            if (!new File(mDir, fileName).exists()) {
+                break;
+            }
+            if (isCertMarkedAsRemoved(fileName)) {
+                continue;
+            }
+            X509Certificate cert = readCertificate(fileName);
+            if (!subj.equals(cert.getSubjectX500Principal())) {
+                continue;
+            }
+            if (selector.match(cert)) {
+                if (certs == null) {
+                    certs = new ArraySet<X509Certificate>();
+                }
+                certs.add(cert);
+            }
+        }
+        return certs != null ? certs : Collections.<X509Certificate>emptySet();
+    }
+
     private X509Certificate findCert(X500Principal subj, CertSelector selector) {
         String hash = getHash(subj);
         for (int index = 0; index >= 0; index++) {
diff --git a/core/java/android/security/net/config/KeyStoreCertificateSource.java b/core/java/android/security/net/config/KeyStoreCertificateSource.java
index b6105cd..ba5dd83 100644
--- a/core/java/android/security/net/config/KeyStoreCertificateSource.java
+++ b/core/java/android/security/net/config/KeyStoreCertificateSource.java
@@ -21,6 +21,7 @@
 import java.security.KeyStoreException;
 import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
+import java.util.Collections;
 import java.util.Enumeration;
 import java.util.Set;
 
@@ -90,4 +91,18 @@
         }
         return anchor.getTrustedCert();
     }
+
+    @Override
+    public Set<X509Certificate> findAllByIssuerAndSignature(X509Certificate cert) {
+        ensureInitialized();
+        Set<java.security.cert.TrustAnchor> anchors = mIndex.findAllByIssuerAndSignature(cert);
+        if (anchors.isEmpty()) {
+            return Collections.<X509Certificate>emptySet();
+        }
+        Set<X509Certificate> certs = new ArraySet<X509Certificate>(anchors.size());
+        for (java.security.cert.TrustAnchor anchor : anchors) {
+            certs.add(anchor.getTrustedCert());
+        }
+        return certs;
+    }
 }
diff --git a/core/java/android/security/net/config/NetworkSecurityConfig.java b/core/java/android/security/net/config/NetworkSecurityConfig.java
index 0a2edff..ebe14691 100644
--- a/core/java/android/security/net/config/NetworkSecurityConfig.java
+++ b/core/java/android/security/net/config/NetworkSecurityConfig.java
@@ -145,6 +145,15 @@
         return null;
     }
 
+    /** @hide */
+    public Set<X509Certificate> findAllCertificatesByIssuerAndSignature(X509Certificate cert) {
+        Set<X509Certificate> certs = new ArraySet<X509Certificate>();
+        for (CertificatesEntryRef ref : mCertificatesEntryRefs) {
+            certs.addAll(ref.findAllCertificatesByIssuerAndSignature(cert));
+        }
+        return certs;
+    }
+
     /**
      * Return a {@link Builder} for the default {@code NetworkSecurityConfig}.
      *
diff --git a/core/java/android/security/net/config/NetworkSecurityConfigProvider.java b/core/java/android/security/net/config/NetworkSecurityConfigProvider.java
index 5ebc7ac..0f66873 100644
--- a/core/java/android/security/net/config/NetworkSecurityConfigProvider.java
+++ b/core/java/android/security/net/config/NetworkSecurityConfigProvider.java
@@ -40,5 +40,6 @@
             throw new RuntimeException("Failed to install provider as highest priority provider."
                     + " Provider was installed at position " + pos);
         }
+        libcore.net.NetworkSecurityPolicy.setInstance(new ConfigNetworkSecurityPolicy(config));
     }
 }
diff --git a/core/java/android/security/net/config/ResourceCertificateSource.java b/core/java/android/security/net/config/ResourceCertificateSource.java
index e489c2c..8803c4b 100644
--- a/core/java/android/security/net/config/ResourceCertificateSource.java
+++ b/core/java/android/security/net/config/ResourceCertificateSource.java
@@ -25,6 +25,7 @@
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Set;
 
 import com.android.org.conscrypt.TrustedCertificateIndex;
@@ -100,4 +101,18 @@
         }
         return anchor.getTrustedCert();
     }
+
+    @Override
+    public Set<X509Certificate> findAllByIssuerAndSignature(X509Certificate cert) {
+        ensureInitialized();
+        Set<java.security.cert.TrustAnchor> anchors = mIndex.findAllByIssuerAndSignature(cert);
+        if (anchors.isEmpty()) {
+            return Collections.<X509Certificate>emptySet();
+        }
+        Set<X509Certificate> certs = new ArraySet<X509Certificate>(anchors.size());
+        for (java.security.cert.TrustAnchor anchor : anchors) {
+            certs.add(anchor.getTrustedCert());
+        }
+        return certs;
+    }
 }
diff --git a/core/java/android/security/net/config/TrustedCertificateStoreAdapter.java b/core/java/android/security/net/config/TrustedCertificateStoreAdapter.java
index 4a90f82..c2f29be 100644
--- a/core/java/android/security/net/config/TrustedCertificateStoreAdapter.java
+++ b/core/java/android/security/net/config/TrustedCertificateStoreAdapter.java
@@ -42,6 +42,11 @@
     }
 
     @Override
+    public Set<X509Certificate> findAllIssuers(X509Certificate cert) {
+        return mConfig.findAllCertificatesByIssuerAndSignature(cert);
+    }
+
+    @Override
     public X509Certificate getTrustAnchor(X509Certificate cert) {
         TrustAnchor anchor = mConfig.findTrustAnchorBySubjectAndPublicKey(cert);
         if (anchor == null) {
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index bb46e83..816ecde 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -15,9 +15,6 @@
  */
 package android.service.dreams;
 
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
 import android.annotation.IdRes;
 import android.annotation.LayoutRes;
 import android.annotation.Nullable;
@@ -33,27 +30,32 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.util.MathUtils;
 import android.util.Slog;
 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;
-import com.android.internal.policy.PhoneWindow;
 import android.view.SearchEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
 import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
 import android.view.WindowManager.LayoutParams;
+import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityEvent;
-import android.util.MathUtils;
 
+import com.android.internal.policy.PhoneWindow;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.DumpUtils.Dump;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+
 /**
  * Extend this class to implement a custom dream (available to the user as a "Daydream").
  *
@@ -365,6 +367,11 @@
     @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/ConditionProviderService.java b/core/java/android/service/notification/ConditionProviderService.java
index 88bd283..eff09d6 100644
--- a/core/java/android/service/notification/ConditionProviderService.java
+++ b/core/java/android/service/notification/ConditionProviderService.java
@@ -85,6 +85,13 @@
             "android.service.zen.automatic.configurationActivity";
 
     /**
+     * The name of the {@code meta-data} tag containing the maximum number of rule instances that
+     * can be created for this rule type. Omit or enter a value <= 0 to allow unlimited instances.
+     */
+    public static final String META_DATA_RULE_INSTANCE_LIMIT =
+            "android.service.zen.automatic.ruleInstanceLimit";
+
+    /**
      * A String rule id extra passed to {@link #META_DATA_CONFIGURATION_ACTIVITY}.
      */
     public static final String EXTRA_RULE_ID = "android.content.automatic.ruleId";
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index e6bf6ba..a0de17f 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -23,6 +23,7 @@
 /** @hide */
 oneway interface INotificationListener
 {
+    // listeners and assistants
     void onListenerConnected(in NotificationRankingUpdate update);
     void onNotificationPosted(in IStatusBarNotificationHolder notificationHolder,
             in NotificationRankingUpdate update);
@@ -31,4 +32,11 @@
     void onNotificationRankingUpdate(in NotificationRankingUpdate update);
     void onListenerHintsChanged(int hints);
     void onInterruptionFilterChanged(int interruptionFilter);
+
+    // assistants only
+    void onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder, int importance, boolean user);
+    void onNotificationVisibilityChanged(String key, long time, boolean visible);
+    void onNotificationClick(String key, long time);
+    void onNotificationActionClick(String key, long time, int actionIndex);
+    void onNotificationRemovedReason(String key, long time, int reason);
 }
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index 5d1317c..bd41fb5 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -16,8 +16,20 @@
 
 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
@@ -35,6 +47,15 @@
  * &lt;/service></pre>
  */
 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;
 
@@ -74,6 +95,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 user banning the topic. */
+    public static final int REASON_TOPIC_BANNED = 14;
+
+    /** Notification was canceled by the device administrator suspending the package. */
+    public static final int REASON_PACKAGE_SUSPENDED = 15;
+
     public class Adjustment {
         int mImportance;
         CharSequence mExplanation;
@@ -96,6 +123,14 @@
         }
     }
 
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (mWrapper == null) {
+            mWrapper = new NotificationAssistantWrapper();
+        }
+        return mWrapper;
+    }
+
     /**
      * A notification was posted by an app. Called before alert.
      *
@@ -163,7 +198,13 @@
      */
     public final void adjustImportance(String key, Adjustment adjustment)
     {
-        // TODO: pack up the adjustment and send it to the NotificationManager.
+        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);
+        }
     }
 
     /**
@@ -171,7 +212,7 @@
      * be fired when the host notification is deleted, or when this annotation
      * is removed or replaced.
      *
-     * @param key the notification key
+     * @param key the key of the notification to be annotated
      * @param annotation the new annotation object
      */
     public final void setAnnotation(String key, Notification annotation)
@@ -182,10 +223,74 @@
     /**
      * Remove the annotation from a notification.
      *
-     * @param key the notification key
+     * @param key the key of the notification to be cleansed of annotatons
      */
     public final void clearAnnotation(String key)
     {
         // TODO: ask the NotificationManager to clear the annotation.
     }
+
+    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 232d4fe..ed90e79 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -15,6 +15,7 @@
  */
 
 package android.service.notification;
+import android.service.notification.IStatusBarNotificationHolder;
 
 import android.annotation.SystemApi;
 import android.annotation.SdkConstant;
@@ -60,6 +61,16 @@
  *         &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]"
@@ -112,6 +123,8 @@
             NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
     public static final int SUPPRESSED_EFFECT_PEEK =
             NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+    public static final int SUPPRESSED_EFFECT_SCREEN_ON =
+            NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
 
     /**
      * The full trim of the StatusBarNotification including all its features.
@@ -141,7 +154,8 @@
     @SystemApi
     public static final int TRIM_LIGHT = 1;
 
-    private INotificationListenerWrapper mWrapper = null;
+    /** @hide */
+    protected NotificationListenerWrapper mWrapper = null;
     private RankingMap mRankingMap;
 
     private INotificationManager mNoMan;
@@ -162,6 +176,17 @@
             = "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";
+
+    /**
      * Implement this method to learn about new notifications as they are posted by apps.
      *
      * @param sbn A data structure encapsulating the original {@link android.app.Notification}
@@ -270,7 +295,8 @@
         // optional
     }
 
-    private final INotificationManager getNotificationInterface() {
+    /** @hide */
+    protected final INotificationManager getNotificationInterface() {
         if (mNoMan == null) {
             mNoMan = INotificationManager.Stub.asInterface(
                     ServiceManager.getService(Context.NOTIFICATION_SERVICE));
@@ -613,12 +639,13 @@
     @Override
     public IBinder onBind(Intent intent) {
         if (mWrapper == null) {
-            mWrapper = new INotificationListenerWrapper();
+            mWrapper = new NotificationListenerWrapper();
         }
         return mWrapper;
     }
 
-    private boolean isBound() {
+    /** @hide */
+    protected boolean isBound() {
         if (mWrapper == null) {
             Log.w(TAG, "Notification listener service not yet bound.");
             return false;
@@ -643,7 +670,7 @@
             int currentUser) throws RemoteException {
         mSystemContext = context;
         if (mWrapper == null) {
-            mWrapper = new INotificationListenerWrapper();
+            mWrapper = new NotificationListenerWrapper();
         }
         INotificationManager noMan = getNotificationInterface();
         noMan.registerListener(mWrapper, componentName, currentUser);
@@ -665,6 +692,36 @@
         }
     }
 
+    /**
+     * Request that the listener be rebound, after a previous call to (@link requestUnbind).
+     *
+     * <P>This method will fail for assistants that have
+     * not been granted the permission by the user.
+     *
+     * <P>The service should wait for the {@link #onListenerConnected()} event
+     * before performing any operations.
+     */
+    public static final void requestRebind(ComponentName componentName)
+            throws RemoteException {
+        INotificationManager noMan = INotificationManager.Stub.asInterface(
+                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+        noMan.requestBindListener(componentName);
+    }
+
+    /**
+     * Request that the service be unbound.
+     *
+     * <P>This will no longer receive updates until
+     * {@link #requestRebind(ComponentName)} is called.
+     * The service will likely be kiled by the system after this call.
+     */
+    public final void requestUnbind() throws RemoteException {
+        if (mWrapper != null) {
+            INotificationManager noMan = getNotificationInterface();
+            noMan.requestUnbindListener(mWrapper);
+        }
+    }
+
     /** Convert new-style Icons to legacy representations for pre-M clients. */
     private void createLegacyIconExtras(Notification n) {
         Icon smallIcon = n.getSmallIcon();
@@ -695,7 +752,8 @@
         }
     }
 
-    private class INotificationListenerWrapper extends INotificationListener.Stub {
+    /** @hide */
+    protected class NotificationListenerWrapper extends INotificationListener.Stub {
         @Override
         public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder,
                 NotificationRankingUpdate update) {
@@ -796,6 +854,35 @@
                 Log.w(TAG, "Error running onInterruptionFilterChanged", t);
             }
         }
+
+        @Override
+        public void onNotificationEnqueued(IStatusBarNotificationHolder notificationHolder,
+                                           int importance, boolean user) throws RemoteException {
+            // no-op in the listener
+        }
+
+        @Override
+        public void onNotificationVisibilityChanged(String key, long time, boolean visible)
+                throws RemoteException {
+            // no-op in the listener
+        }
+
+        @Override
+        public void onNotificationClick(String key, long time) throws RemoteException {
+            // no-op in the listener
+        }
+
+        @Override
+        public void onNotificationActionClick(String key, long time, int actionIndex)
+                throws RemoteException {
+            // no-op in the listener
+        }
+
+        @Override
+        public void onNotificationRemovedReason(String key, long time, int reason)
+                throws RemoteException {
+            // no-op in the listener
+        }
     }
 
     private void applyUpdate(NotificationRankingUpdate update) {
@@ -906,7 +993,8 @@
 
         /**
          * Returns the type(s) of visual effects that should be suppressed for this notification.
-         * See {@link #SUPPRESSED_EFFECT_LIGHTS}, {@link #SUPPRESSED_EFFECT_PEEK}}.
+         * See {@link #SUPPRESSED_EFFECT_LIGHTS}, {@link #SUPPRESSED_EFFECT_PEEK},
+         * {@link #SUPPRESSED_EFFECT_SCREEN_ON}.
          */
         public int getSuppressedVisualEffects() {
             return mSuppressedVisualEffects;
@@ -944,13 +1032,12 @@
             return mImportanceExplanation;
         }
 
-        private void populate(String key, int rank, boolean isAmbient,
-                boolean matchesInterruptionFilter, int visibilityOverride,
-                int suppressedVisualEffects, int importance,
+        private void populate(String key, int rank, boolean matchesInterruptionFilter,
+                int visibilityOverride, int suppressedVisualEffects, int importance,
                 CharSequence explanation) {
             mKey = key;
             mRank = rank;
-            mIsAmbient = isAmbient;
+            mIsAmbient = importance < IMPORTANCE_DEFAULT;
             mMatchesInterruptionFilter = matchesInterruptionFilter;
             mVisibilityOverride = visibilityOverride;
             mSuppressedVisualEffects = suppressedVisualEffects;
@@ -1021,7 +1108,7 @@
          */
         public boolean getRanking(String key, Ranking outRanking) {
             int rank = getRank(key);
-            outRanking.populate(key, rank, isAmbient(key), !isIntercepted(key),
+            outRanking.populate(key, rank, !isIntercepted(key),
                     getVisibilityOverride(key), getSuppressedVisualEffects(key),
                     getImportance(key), getImportanceExplanation(key));
             return rank >= 0;
@@ -1037,15 +1124,6 @@
             return rank != null ? rank : -1;
         }
 
-        private boolean isAmbient(String key) {
-            int firstAmbientIndex = mRankingUpdate.getFirstAmbientIndex();
-            if (firstAmbientIndex < 0) {
-                return false;
-            }
-            int rank = getRank(key);
-            return rank >= 0 && rank >= firstAmbientIndex;
-        }
-
         private boolean isIntercepted(String key) {
             synchronized (this) {
                 if (mIntercepted == null) {
diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java
index 0d42ffb..79f6fc4 100644
--- a/core/java/android/service/notification/NotificationRankingUpdate.java
+++ b/core/java/android/service/notification/NotificationRankingUpdate.java
@@ -26,17 +26,15 @@
     // TODO: Support incremental updates.
     private final String[] mKeys;
     private final String[] mInterceptedKeys;
-    private final int mFirstAmbientIndex;
     private final Bundle mVisibilityOverrides;
     private final Bundle mSuppressedVisualEffects;
     private final int[] mImportance;
     private final Bundle mImportanceExplanation;
 
     public NotificationRankingUpdate(String[] keys, String[] interceptedKeys,
-            Bundle visibilityOverrides, int firstAmbientIndex, Bundle suppressedVisualEffects,
+            Bundle visibilityOverrides, Bundle suppressedVisualEffects,
             int[] importance, Bundle explanation) {
         mKeys = keys;
-        mFirstAmbientIndex = firstAmbientIndex;
         mInterceptedKeys = interceptedKeys;
         mVisibilityOverrides = visibilityOverrides;
         mSuppressedVisualEffects = suppressedVisualEffects;
@@ -46,7 +44,6 @@
 
     public NotificationRankingUpdate(Parcel in) {
         mKeys = in.readStringArray();
-        mFirstAmbientIndex = in.readInt();
         mInterceptedKeys = in.readStringArray();
         mVisibilityOverrides = in.readBundle();
         mSuppressedVisualEffects = in.readBundle();
@@ -63,7 +60,6 @@
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeStringArray(mKeys);
-        out.writeInt(mFirstAmbientIndex);
         out.writeStringArray(mInterceptedKeys);
         out.writeBundle(mVisibilityOverrides);
         out.writeBundle(mSuppressedVisualEffects);
@@ -86,10 +82,6 @@
         return mKeys;
     }
 
-    public int getFirstAmbientIndex() {
-        return mFirstAmbientIndex;
-    }
-
     public String[] getInterceptedKeys() {
         return mInterceptedKeys;
     }
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 541623d..4688843 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -79,6 +79,7 @@
     private static final boolean DEFAULT_ALLOW_REPEAT_CALLERS = false;
     private static final boolean DEFAULT_ALLOW_PEEK = true;
     private static final boolean DEFAULT_ALLOW_LIGHTS = true;
+    private static final boolean DEFAULT_ALLOW_SCREEN_ON = true;
 
     private static final int XML_VERSION = 2;
     private static final String ZEN_TAG = "zen";
@@ -95,6 +96,7 @@
     private static final String ALLOW_ATT_EVENTS = "events";
     private static final String ALLOW_ATT_PEEK = "peek";
     private static final String ALLOW_ATT_LIGHTS = "lights";
+    private static final String ALLOW_ATT_SCREEN_ON = "screen_on";
 
     private static final String CONDITION_TAG = "condition";
     private static final String CONDITION_ATT_COMPONENT = "component";
@@ -128,6 +130,7 @@
     public int user = UserHandle.USER_SYSTEM;
     public boolean allowPeek = DEFAULT_ALLOW_PEEK;
     public boolean allowLights = DEFAULT_ALLOW_LIGHTS;
+    public boolean allowScreenOn = DEFAULT_ALLOW_SCREEN_ON;
 
     public ZenRule manualRule;
     public ArrayMap<String, ZenRule> automaticRules = new ArrayMap<>();
@@ -156,6 +159,7 @@
         }
         allowPeek = source.readInt() == 1;
         allowLights = source.readInt() == 1;
+        allowScreenOn = source.readInt() == 1;
     }
 
     @Override
@@ -185,6 +189,7 @@
         }
         dest.writeInt(allowPeek ? 1 : 0);
         dest.writeInt(allowLights ? 1 : 0);
+        dest.writeInt(allowScreenOn ? 1 : 0);
     }
 
     @Override
@@ -200,6 +205,7 @@
                 .append(",allowEvents=").append(allowEvents)
                 .append(",allowPeek=").append(allowPeek)
                 .append(",allowLights=").append(allowLights)
+                .append(",allowScreenOn=").append(allowScreenOn)
                 .append(",automaticRules=").append(automaticRules)
                 .append(",manualRule=").append(manualRule)
                 .append(']').toString();
@@ -240,6 +246,9 @@
         if (allowLights != to.allowLights) {
             d.addLine("allowLights", allowLights, to.allowLights);
         }
+        if (allowScreenOn != to.allowScreenOn) {
+            d.addLine("allowScreenOn", allowScreenOn, to.allowScreenOn);
+        }
         final ArraySet<String> allRules = new ArraySet<>();
         addKeys(allRules, automaticRules);
         addKeys(allRules, to.automaticRules);
@@ -339,6 +348,7 @@
                 && other.allowEvents == allowEvents
                 && other.allowPeek == allowPeek
                 && other.allowLights == allowLights
+                && other.allowScreenOn == allowScreenOn
                 && other.user == user
                 && Objects.equals(other.automaticRules, automaticRules)
                 && Objects.equals(other.manualRule, manualRule);
@@ -348,7 +358,7 @@
     public int hashCode() {
         return Objects.hash(allowCalls, allowRepeatCallers, allowMessages, allowCallsFrom,
                 allowMessagesFrom, allowReminders, allowEvents, allowPeek, allowLights,
-                user, automaticRules, manualRule);
+                allowScreenOn, user, automaticRules, manualRule);
     }
 
     private static String toDayList(int[] days) {
@@ -435,6 +445,8 @@
                     }
                     rt.allowPeek = safeBoolean(parser, ALLOW_ATT_PEEK, DEFAULT_ALLOW_PEEK);
                     rt.allowLights = safeBoolean(parser, ALLOW_ATT_LIGHTS, DEFAULT_ALLOW_LIGHTS);
+                    rt.allowScreenOn =
+                            safeBoolean(parser, ALLOW_ATT_SCREEN_ON, DEFAULT_ALLOW_SCREEN_ON);
                 } else if (MANUAL_TAG.equals(tag)) {
                     rt.manualRule = readRuleXml(parser);
                 } else if (AUTOMATIC_TAG.equals(tag)) {
@@ -465,6 +477,7 @@
         out.attribute(null, ALLOW_ATT_MESSAGES_FROM, Integer.toString(allowMessagesFrom));
         out.attribute(null, ALLOW_ATT_PEEK, Boolean.toString(allowPeek));
         out.attribute(null, ALLOW_ATT_LIGHTS, Boolean.toString(allowLights));
+        out.attribute(null, ALLOW_ATT_SCREEN_ON, Boolean.toString(allowScreenOn));
         out.endTag(null, ALLOW_TAG);
 
         if (manualRule != null) {
@@ -643,6 +656,9 @@
         if (!allowLights) {
             suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS;
         }
+        if (!allowScreenOn) {
+            suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_SCREEN_ON;
+        }
         priorityCallSenders = sourceToPrioritySenders(allowCallsFrom, priorityCallSenders);
         priorityMessageSenders = sourceToPrioritySenders(allowMessagesFrom, priorityMessageSenders);
         return new Policy(priorityCategories, priorityCallSenders, priorityMessageSenders,
@@ -681,6 +697,8 @@
         if (policy.suppressedVisualEffects != Policy.SUPPRESSED_EFFECTS_UNSET) {
             allowPeek = (policy.suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) == 0;
             allowLights = (policy.suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) == 0;
+            allowScreenOn =
+                    (policy.suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_SCREEN_ON) == 0;
         }
     }
 
diff --git a/core/java/android/service/quicksettings/IQSService.aidl b/core/java/android/service/quicksettings/IQSService.aidl
index 7e70501..4bfc948 100644
--- a/core/java/android/service/quicksettings/IQSService.aidl
+++ b/core/java/android/service/quicksettings/IQSService.aidl
@@ -16,6 +16,7 @@
 package android.service.quicksettings;
 
 import android.content.ComponentName;
+import android.graphics.drawable.Icon;
 import android.service.quicksettings.Tile;
 
 /**
@@ -23,5 +24,12 @@
  */
 interface IQSService {
     void updateQsTile(in Tile tile);
+    void updateStatusIcon(in Tile tile, in Icon icon,
+            String contentDescription);
     void onShowDialog(in Tile tile);
+    void onStartActivity(in Tile tile);
+    void setTileMode(in ComponentName component, int mode);
+    boolean isLocked();
+    boolean isSecure();
+    void startUnlockAndRun(in Tile tile);
 }
diff --git a/core/java/android/service/quicksettings/IQSTileService.aidl b/core/java/android/service/quicksettings/IQSTileService.aidl
index 63a4c5e..bfde870 100644
--- a/core/java/android/service/quicksettings/IQSTileService.aidl
+++ b/core/java/android/service/quicksettings/IQSTileService.aidl
@@ -22,10 +22,12 @@
  * @hide
  */
 oneway interface IQSTileService {
+    void setQSService(in IQSService service);
     void setQSTile(in Tile tile);
     void onTileAdded();
     void onTileRemoved();
     void onStartListening();
     void onStopListening();
     void onClick(IBinder wtoken);
+    void onUnlockComplete();
 }
diff --git a/core/java/android/service/quicksettings/Tile.java b/core/java/android/service/quicksettings/Tile.java
index a53fc59..85f1955 100644
--- a/core/java/android/service/quicksettings/Tile.java
+++ b/core/java/android/service/quicksettings/Tile.java
@@ -36,11 +36,39 @@
 
     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.
+     */
+    public static final int STATE_UNAVAILABLE = 0;
+
+    /**
+     * This represents a tile that is currently in a disabled state but is still interactable.
+     *
+     * A disabled state indicates that the tile is not currently active (e.g. wifi disconnected or
+     * bluetooth disabled), but is still interactable by the user to modify this state.  Tiles
+     * that have boolean states should use this to represent one of their states.  The tile's
+     * icon will be tinted differently to reflect this state, but still be distinct from unavailable.
+     */
+    public static final int STATE_INACTIVE = 1;
+
+    /**
+     * This represents a tile that is currently active. (e.g. wifi is connected, bluetooth is on,
+     * cast is casting).
+     */
+    public static final int STATE_ACTIVE = 2;
+
     private ComponentName mComponentName;
-    private IQSService mService;
     private Icon mIcon;
     private CharSequence mLabel;
     private CharSequence mContentDescription;
+    // Default to active until clients of the new API can update.
+    private int mState = STATE_ACTIVE;
+
+    private IQSService mService;
 
     /**
      * @hide
@@ -52,8 +80,14 @@
     /**
      * @hide
      */
-    public Tile(ComponentName componentName, IQSService service) {
+    public Tile(ComponentName componentName) {
         mComponentName = componentName;
+    }
+
+    /**
+     * @hide
+     */
+    public void setService(IQSService service) {
         mService = service;
     }
 
@@ -65,6 +99,36 @@
     }
 
     /**
+     * @hide
+     */
+    public IQSService getQsService() {
+        return mService;
+    }
+
+    /**
+     * The current state of the tile.
+     *
+     * @see #STATE_UNAVAILABLE
+     * @see #STATE_INACTIVE
+     * @see #STATE_ACTIVE
+     */
+    public int getState() {
+        return mState;
+    }
+
+    /**
+     * Sets the current state for the tile.
+     *
+     * Does not take effect until {@link #updateTile()} is called.
+     *
+     * @param state One of {@link #STATE_UNAVAILABLE}, {@link #STATE_INACTIVE},
+     * {@link #STATE_ACTIVE}
+     */
+    public void setState(int state) {
+        mState = state;
+    }
+
+    /**
      * Gets the current icon for the tile.
      */
     public Icon getIcon() {
@@ -137,21 +201,8 @@
         }
     }
 
-    /**
-     * @hide
-     * Notifies the IQSService that this tile is showing a dialog.
-     */
-    void onShowDialog() {
-        try {
-            mService.onShowDialog(this);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Couldn't onShowDialog");
-        }
-    }
-
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeStrongInterface(mService);
         if (mComponentName != null) {
             dest.writeByte((byte) 1);
             mComponentName.writeToParcel(dest, flags);
@@ -164,12 +215,12 @@
         } else {
             dest.writeByte((byte) 0);
         }
+        dest.writeInt(mState);
         TextUtils.writeToParcel(mLabel, dest, flags);
         TextUtils.writeToParcel(mContentDescription, dest, flags);
     }
 
     private void readFromParcel(Parcel source) {
-        mService = IQSService.Stub.asInterface(source.readStrongBinder());
         if (source.readByte() != 0) {
             mComponentName = ComponentName.CREATOR.createFromParcel(source);
         } else {
@@ -180,6 +231,7 @@
         } else {
             mIcon = null;
         }
+        mState = source.readInt();
         mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
         mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
     }
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index fd2d5b0..c02465b 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -15,9 +15,14 @@
  */
 package android.service.quicksettings;
 
+import android.Manifest;
+import android.annotation.SystemApi;
 import android.app.Dialog;
 import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
+import android.graphics.drawable.Icon;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -26,29 +31,29 @@
 import android.view.WindowManager;
 
 /**
- * A QSTileService provides the user a tile that can be added to Quick Settings.
+ * A TileService provides the user a tile that can be added to Quick Settings.
  * Quick Settings is a space provided that allows the user to change settings and
  * take quick actions without leaving the context of their current app.
  *
- * <p>The lifecycle of a QSTileService is different from some other services in
+ * <p>The lifecycle of a TileService is different from some other services in
  * that it may be unbound during parts of its lifecycle.  Any of the following
  * lifecycle events can happen indepently in a separate binding/creation of the
  * service.</p>
  *
  * <ul>
- * <li>When a tile is added by the user its QSTileService will be bound to and
+ * <li>When a tile is added by the user its TileService will be bound to and
  * {@link #onTileAdded()} will be called.</li>
  *
  * <li>When a tile should be up to date and listing will be indicated by
  * {@link #onStartListening()} and {@link #onStopListening()}.</li>
  *
- * <li>When the user removes a tile from Quick Settings {@link #onStopListening()}
+ * <li>When the user removes a tile from Quick Settings {@link #onTileRemoved()}
  * will be called.</li>
  * </ul>
- * <p>QSTileService will be detected by tiles that match the {@value #ACTION_QS_TILE}
+ * <p>TileService will be detected by tiles that match the {@value #ACTION_QS_TILE}
  * and require the permission "android.permission.BIND_QUICK_SETTINGS_TILE".
  * The label and icon for the service will be used as the default label and
- * icon for the tile. Here is an example QSTileService declaration.</p>
+ * icon for the tile. Here is an example TileService declaration.</p>
  * <pre class="prettyprint">
  * {@literal
  * <service
@@ -67,15 +72,62 @@
 public class TileService extends Service {
 
     /**
-     * Action that identifies a Service as being a QSTileService.
+     * Action that identifies a Service as being a TileService.
      */
     public static final String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
 
+    /**
+     * The tile mode hasn't been set yet.
+     * @hide
+     */
+    public static final int TILE_MODE_UNSET = 0;
+
+    /**
+     * Constant to be returned by {@link #onTileAdded}.
+     * <p>
+     * Passive mode is the default mode for tiles.  The System will tell the tile
+     * when it is most important to update by putting it in the listening state.
+     */
+    public static final int TILE_MODE_PASSIVE = 1;
+
+    /**
+     * Constant to be returned by {@link #onTileAdded}.
+     * <p>
+     * Active mode is for tiles which already listen and keep track of their state in their
+     * own process.  These tiles may request to send an update to the System while their process
+     * is alive using {@link #requestListeningState}.  The System will only bind these tiles
+     * on its own when a click needs to occur.
+     */
+    public static final int TILE_MODE_ACTIVE = 2;
+
+    /**
+     * Used to notify SysUI that Listening has be requested.
+     * @hide
+     */
+    public static final String ACTION_REQUEST_LISTENING
+            = "android.service.quicksettings.action.REQUEST_LISTENING";
+
+    /**
+     * @hide
+     */
+    public static final String EXTRA_COMPONENT = "android.service.quicksettings.extra.COMPONENT";
+
     private final H mHandler = new H(Looper.getMainLooper());
 
     private boolean mListening = false;
     private Tile mTile;
     private IBinder mToken;
+    private IQSService mService;
+    private Runnable mUnlockRunnable;
+
+    @Override
+    public void onDestroy() {
+        if (mListening) {
+            onStopListening();
+            mListening = false;
+        }
+        super.onDestroy();
+    }
 
     /**
      * Called when the user adds this tile to Quick Settings.
@@ -83,8 +135,12 @@
      * Note that this is not guaranteed to be called between {@link #onCreate()}
      * and {@link #onStartListening()}, it will only be called when the tile is added
      * and not on subsequent binds.
+     *
+     * @see #TILE_MODE_PASSIVE
+     * @see #TILE_MODE_ACTIVE
      */
-    public void onTileAdded() {
+    public int onTileAdded() {
+        return TILE_MODE_PASSIVE;
     }
 
     /**
@@ -119,17 +175,103 @@
     }
 
     /**
+     * Sets an icon to be shown in the status bar.
+     * <p>
+     * The icon will be displayed before all other icons.  Can only be called between
+     * {@link #onStartListening} and {@link #onStopListening}.  Can only be called by system apps.
+     *
+     * @param icon The icon to be displayed, null to hide
+     * @param contentDescription Content description of the icon to be displayed
+     * @hide
+     */
+    @SystemApi
+    public final void setStatusIcon(Icon icon, String contentDescription) {
+        if (mService != null) {
+            try {
+                mService.updateStatusIcon(mTile, icon, contentDescription);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /**
      * Used to show a dialog.
      *
      * This will collapse the Quick Settings panel and show the dialog.
      *
      * @param dialog Dialog to show.
+     *
+     * @see #isLocked()
      */
     public final void showDialog(Dialog dialog) {
         dialog.getWindow().getAttributes().token = mToken;
         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_QS_DIALOG);
         dialog.show();
-        getQsTile().onShowDialog();
+        try {
+            mService.onShowDialog(mTile);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Prompts the user to unlock the device before executing the Runnable.
+     * <p>
+     * The user will be prompted for their current security method if applicable
+     * and if successful, runnable will be executed.  The Runnable will not be
+     * executed if the user fails to unlock the device or cancels the operation.
+     */
+    public final void unlockAndRun(Runnable runnable) {
+        mUnlockRunnable = runnable;
+        try {
+            mService.startUnlockAndRun(mTile);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Checks if the device is in a secure state.
+     *
+     * TileServices should detect when the device is secure and change their behavior
+     * accordingly.
+     *
+     * @return true if the device is secure.
+     */
+    public final boolean isSecure() {
+        try {
+            return mService.isSecure();
+        } catch (RemoteException e) {
+            return true;
+        }
+    }
+
+    /**
+     * Checks if the lock screen is showing.
+     *
+     * When a device is locked, then {@link #showDialog} will not present a dialog, as it will
+     * be under the lock screen. If the behavior of the Tile is safe to do while locked,
+     * then the user should use {@link #startActivity} to launch an activity on top of the lock
+     * screen, otherwise the tile should use {@link #unlockAndRun(Runnable)} to give the
+     * user their security challenge.
+     *
+     * @return true if the device is locked.
+     */
+    public final boolean isLocked() {
+        try {
+            return mService.isLocked();
+        } catch (RemoteException e) {
+            return true;
+        }
+    }
+
+    /**
+     * Start an activity while collapsing the panel.
+     */
+    public final void startActivityAndCollapse(Intent intent) {
+        startActivity(intent);
+        try {
+            mService.onStartActivity(mTile);
+        } catch (RemoteException e) {
+        }
     }
 
     /**
@@ -147,6 +289,11 @@
     public IBinder onBind(Intent intent) {
         return new IQSTileService.Stub() {
             @Override
+            public void setQSService(IQSService service) throws RemoteException {
+                mHandler.obtainMessage(H.MSG_SET_SERVICE, service).sendToTarget();
+            }
+
+            @Override
             public void setQSTile(Tile tile) throws RemoteException {
                 mHandler.obtainMessage(H.MSG_SET_TILE, tile).sendToTarget();
             }
@@ -175,6 +322,11 @@
             public void onClick(IBinder wtoken) throws RemoteException {
                 mHandler.obtainMessage(H.MSG_TILE_CLICKED, wtoken).sendToTarget();
             }
+
+            @Override
+            public void onUnlockComplete() throws RemoteException{
+                mHandler.sendEmptyMessage(H.MSG_UNLOCK_COMPLETE);
+            }
         };
     }
 
@@ -185,6 +337,8 @@
         private static final int MSG_TILE_ADDED = 4;
         private static final int MSG_TILE_REMOVED = 5;
         private static final int MSG_TILE_CLICKED = 6;
+        private static final int MSG_SET_SERVICE = 7;
+        private static final int MSG_UNLOCK_COMPLETE = 8;
 
         public H(Looper looper) {
             super(looper);
@@ -193,14 +347,35 @@
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
+                case MSG_SET_SERVICE:
+                    mService = (IQSService) msg.obj;
+                    if (mTile != null) {
+                        mTile.setService(mService);
+                    }
+                    break;
                 case MSG_SET_TILE:
                     mTile = (Tile) msg.obj;
+                    if (mService != null && mTile != null) {
+                        mTile.setService(mService);
+                    }
                     break;
                 case MSG_TILE_ADDED:
-                    TileService.this.onTileRemoved();
+                    int mode = TileService.this.onTileAdded();
+                    if (mService == null) {
+                        return;
+                    }
+                    try {
+                        mService.setTileMode(new ComponentName(TileService.this,
+                                TileService.this.getClass()), mode);
+                    } catch (RemoteException e) {
+                    }
                     break;
                 case MSG_TILE_REMOVED:
-                    TileService.this.onTileAdded();
+                    if (mListening) {
+                        mListening = false;
+                        TileService.this.onStopListening();
+                    }
+                    TileService.this.onTileRemoved();
                     break;
                 case MSG_STOP_LISTENING:
                     if (mListening) {
@@ -218,7 +393,24 @@
                     mToken = (IBinder) msg.obj;
                     TileService.this.onClick();
                     break;
+                case MSG_UNLOCK_COMPLETE:
+                    if (mUnlockRunnable != null) {
+                        mUnlockRunnable.run();
+                    }
+                    break;
             }
         }
     }
+
+    /**
+     * Requests that a tile be put in the listening state so it can send an update.
+     *
+     * This method is only applicable to tiles that return {@link #TILE_MODE_ACTIVE} from
+     * {@link #onTileAdded()}, and will do nothing otherwise.
+     */
+    public static final void requestListeningState(Context context, ComponentName component) {
+        Intent intent = new Intent(ACTION_REQUEST_LISTENING);
+        intent.putExtra(EXTRA_COMPONENT, component);
+        context.sendBroadcast(intent, Manifest.permission.BIND_QUICK_SETTINGS_TILE);
+    }
 }
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index ac7d539..76a401d 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -31,6 +31,7 @@
 import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
 import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
 import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
+import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
 import android.media.AudioFormat;
 import android.os.AsyncTask;
 import android.os.Handler;
@@ -616,7 +617,11 @@
         }
 
         @Override
-        public void onDetected(KeyphraseRecognitionEvent event) {
+        public void onDetected(RecognitionEvent event) {
+            if (! (event instanceof KeyphraseRecognitionEvent)) {
+                Slog.e(TAG, "onDetected() called for a soundtrigger event.");
+                return;
+            }
             if (DBG) {
                 Slog.d(TAG, "onDetected(" + event + ")");
             } else {
diff --git a/core/java/android/service/voice/VoiceInteractionManagerInternal.java b/core/java/android/service/voice/VoiceInteractionManagerInternal.java
new file mode 100644
index 0000000..b38067b
--- /dev/null
+++ b/core/java/android/service/voice/VoiceInteractionManagerInternal.java
@@ -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.
+ */
+
+package android.service.voice;
+
+import android.os.Bundle;
+import android.os.IBinder;
+
+
+/**
+ * @hide
+ * Private interface to the VoiceInteractionManagerService for use by ActivityManagerService.
+ */
+public abstract class VoiceInteractionManagerInternal {
+
+    /**
+     * Start a new voice interaction session when requested from within an activity
+     * by Activity.startLocalVoiceInteraction()
+     * @param callingActivity The binder token representing the calling activity.
+     * @param options 
+     */
+    public abstract void startLocalVoiceInteraction(IBinder callingActivity, Bundle options);
+
+    /**
+     * Returns whether the currently selected voice interaction service supports local voice
+     * interaction for launching from an Activity.
+     */
+    public abstract boolean supportsLocalVoiceInteraction();
+
+    public abstract void stopLocalVoiceInteraction(IBinder callingActivity);
+}
\ No newline at end of file
diff --git a/core/java/android/service/voice/VoiceInteractionServiceInfo.java b/core/java/android/service/voice/VoiceInteractionServiceInfo.java
index ebe3f47..a9db32b 100644
--- a/core/java/android/service/voice/VoiceInteractionServiceInfo.java
+++ b/core/java/android/service/voice/VoiceInteractionServiceInfo.java
@@ -45,6 +45,7 @@
     private String mSettingsActivity;
     private boolean mSupportsAssist;
     private boolean mSupportsLaunchFromKeyguard;
+    private boolean mSupportsLocalInteraction;
 
     public VoiceInteractionServiceInfo(PackageManager pm, ComponentName comp)
             throws PackageManager.NameNotFoundException {
@@ -70,6 +71,10 @@
     }
 
     public VoiceInteractionServiceInfo(PackageManager pm, ServiceInfo si) {
+        if (si == null) {
+            mParseError = "Service not available";
+            return;
+        }
         if (!Manifest.permission.BIND_VOICE_INTERACTION.equals(si.permission)) {
             mParseError = "Service does not require permission "
                     + Manifest.permission.BIND_VOICE_INTERACTION;
@@ -114,6 +119,8 @@
             mSupportsLaunchFromKeyguard = array.getBoolean(com.android.internal.
                     R.styleable.VoiceInteractionService_supportsLaunchVoiceAssistFromKeyguard,
                     false);
+            mSupportsLocalInteraction = array.getBoolean(com.android.internal.
+                    R.styleable.VoiceInteractionService_supportsLocalInteraction, false);
             array.recycle();
             if (mSessionService == null) {
                 mParseError = "No sessionService specified";
@@ -168,4 +175,8 @@
     public boolean getSupportsLaunchFromKeyguard() {
         return mSupportsLaunchFromKeyguard;
     }
+
+    public boolean getSupportsLocalInteraction() {
+        return mSupportsLocalInteraction;
+    }
 }
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index ec14740..0c6a0c6 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -17,6 +17,7 @@
 package android.service.voice;
 
 import android.annotation.Nullable;
+import android.app.Activity;
 import android.app.Dialog;
 import android.app.Instrumentation;
 import android.app.VoiceInteractor;
@@ -49,6 +50,7 @@
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 import android.widget.FrameLayout;
+
 import com.android.internal.app.IVoiceInteractionManagerService;
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractor;
@@ -75,7 +77,7 @@
  */
 public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCallbacks2 {
     static final String TAG = "VoiceInteractionSession";
-    static final boolean DEBUG = false;
+    static final boolean DEBUG = true;
 
     /**
      * Flag received in {@link #onShow}: originator requested that the session be started with
@@ -101,6 +103,13 @@
      */
     public static final int SHOW_SOURCE_APPLICATION = 1<<3;
 
+    /**
+     * Flag for use with {@link #onShow}: indicates that an Activity has invoked the voice
+     * interaction service for a local interaction using
+     * {@link Activity#startLocalVoiceInteraction(Bundle)}.
+     */
+    public static final int SHOW_SOURCE_ACTIVITY = 1<<4;
+
     final Context mContext;
     final HandlerCaller mHandlerCaller;
 
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index d146e5e..a985517 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -167,6 +167,7 @@
         final Rect mDispatchedOutsets = new Rect();
         final Rect mFinalSystemInsets = new Rect();
         final Rect mFinalStableInsets = new Rect();
+        final Rect mBackdropFrame = new Rect();
         final Configuration mConfiguration = new Configuration();
 
         final WindowManager.LayoutParams mLayout
@@ -270,7 +271,7 @@
             @Override
             public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
                     Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
-                    Configuration newConfig, Rect backDropRect) {
+                    Configuration newConfig, Rect backDropRect, boolean forceLayout) {
                 Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED,
                         reportDraw ? 1 : 0, outsets);
                 mCaller.sendMessage(msg);
@@ -675,8 +676,8 @@
                     final int relayoutResult = mSession.relayout(
                         mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
                             View.VISIBLE, 0, mWinFrame, mOverscanInsets, mContentInsets,
-                            mVisibleInsets, mStableInsets, mOutsets, mConfiguration,
-                            mSurfaceHolder.mSurface);
+                            mVisibleInsets, mStableInsets, mOutsets, mBackdropFrame,
+                            mConfiguration, mSurfaceHolder.mSurface);
 
                     if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface
                             + ", frame=" + mWinFrame);
diff --git a/core/java/android/speech/tts/FileSynthesisCallback.java b/core/java/android/speech/tts/FileSynthesisCallback.java
index dea766b..ca9931a 100644
--- a/core/java/android/speech/tts/FileSynthesisCallback.java
+++ b/core/java/android/speech/tts/FileSynthesisCallback.java
@@ -111,6 +111,7 @@
                        "of AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT or " +
                        "AudioFormat.ENCODING_PCM_FLOAT");
         }
+        mDispatcher.dispatchOnBeginSynthesis(sampleRateInHz, audioFormat, channelCount);
 
         FileChannel fileChannel = null;
         synchronized (mStateLock) {
@@ -176,6 +177,10 @@
             fileChannel = mFileChannel;
         }
 
+        final byte[] bufferCopy = new byte[length];
+        System.arraycopy(buffer, offset, bufferCopy, 0, length);
+        mDispatcher.dispatchOnAudioAvailable(bufferCopy);
+
         try {
             fileChannel.write(ByteBuffer.wrap(buffer,  offset,  length));
             return TextToSpeech.SUCCESS;
diff --git a/core/java/android/speech/tts/ITextToSpeechCallback.aidl b/core/java/android/speech/tts/ITextToSpeechCallback.aidl
index d785c3f..4e3acf6 100644
--- a/core/java/android/speech/tts/ITextToSpeechCallback.aidl
+++ b/core/java/android/speech/tts/ITextToSpeechCallback.aidl
@@ -22,33 +22,65 @@
  */
 oneway interface ITextToSpeechCallback {
     /**
-     * Tells the client that the synthesis has started.
+     * Tells the client that the synthesis has started playing.
      *
-     * @param utteranceId Unique id identifying synthesis request.
+     * @param utteranceId Unique id identifying the synthesis request.
      */
     void onStart(String utteranceId);
 
     /**
-     * Tells the client that the synthesis has finished.
+     * Tells the client that the synthesis has finished playing.
      *
-     * @param utteranceId Unique id identifying synthesis request.
+     * @param utteranceId Unique id identifying the synthesis request.
      */
     void onSuccess(String utteranceId);
 
     /**
      * Tells the client that the synthesis was stopped.
      *
-     * @param utteranceId Unique id identifying synthesis request.
+     * @param utteranceId Unique id identifying the synthesis request.
      */
     void onStop(String utteranceId, boolean isStarted);
 
     /**
      * Tells the client that the synthesis has failed.
      *
-     * @param utteranceId Unique id identifying synthesis request.
+     * @param utteranceId Unique id identifying the synthesis request.
      * @param errorCode One of the values from
      *        {@link android.speech.tts.v2.TextToSpeech}.
      */
     void onError(String utteranceId, int errorCode);
 
+    /**
+     * Tells the client that the TTS engine has started synthesizing the audio for a request.
+     *
+     * <p>
+     * This doesn't mean the synthesis request has already started playing (for example when there
+     * are synthesis requests ahead of it in the queue), but after receiving this callback you can
+     * expect onAudioAvailable to be called.
+     * </p>
+     *
+     * @param utteranceId Unique id identifying the synthesis request.
+     * @param sampleRateInHz Sample rate in HZ of the generated audio.
+     * @param audioFormat The audio format of the generated audio in the {@link #onAudioAvailable}
+     *        call. Should be one of {@link android.media.AudioFormat.ENCODING_PCM_8BIT},
+     *        {@link android.media.AudioFormat.ENCODING_PCM_16BIT} or
+     *        {@link android.media.AudioFormat.ENCODING_PCM_FLOAT}.
+     * @param channelCount The number of channels.
+     */
+    void onBeginSynthesis(String utteranceId, int sampleRateInHz, int audioFormat, int channelCount);
+
+    /**
+     * Tells the client about a chunk of the synthesized audio.
+     *
+     * <p>
+     * Called when a chunk of the synthesized audio is ready. This may be called more than once for
+     * every synthesis request, thereby streaming the audio to the client.
+     * </p>
+     *
+     * @param utteranceId Unique id identifying the synthesis request.
+     * @param audio The raw audio bytes. Its format is specified by the {@link #onStartAudio}
+     * callback.
+     */
+    void onAudioAvailable(String utteranceId, in byte[] audio);
 }
diff --git a/core/java/android/speech/tts/PlaybackSynthesisCallback.java b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
index dcc0095..778aa86 100644
--- a/core/java/android/speech/tts/PlaybackSynthesisCallback.java
+++ b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
@@ -15,6 +15,7 @@
  */
 package android.speech.tts;
 
+import android.annotation.NonNull;
 import android.media.AudioFormat;
 import android.speech.tts.TextToSpeechService.AudioOutputParams;
 import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
@@ -51,9 +52,10 @@
     private final Object mCallerIdentity;
     private final AbstractEventLogger mLogger;
 
-    PlaybackSynthesisCallback(AudioOutputParams audioParams, AudioPlaybackHandler audioTrackHandler,
-            UtteranceProgressDispatcher dispatcher, Object callerIdentity,
-            AbstractEventLogger logger, boolean clientIsUsingV2) {
+    PlaybackSynthesisCallback(@NonNull AudioOutputParams audioParams,
+            @NonNull AudioPlaybackHandler audioTrackHandler,
+            @NonNull UtteranceProgressDispatcher dispatcher, @NonNull Object callerIdentity,
+            @NonNull AbstractEventLogger logger, boolean clientIsUsingV2) {
         super(clientIsUsingV2);
         mAudioParams = audioParams;
         mAudioTrackHandler = audioTrackHandler;
@@ -130,6 +132,7 @@
                        "of AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT or " +
                        "AudioFormat.ENCODING_PCM_FLOAT");
         }
+        mDispatcher.dispatchOnBeginSynthesis(sampleRateInHz, audioFormat, channelCount);
 
         int channelConfig = BlockingAudioTrack.getChannelConfig(channelCount);
 
@@ -190,6 +193,7 @@
         // Sigh, another copy.
         final byte[] bufferCopy = new byte[length];
         System.arraycopy(buffer, offset, bufferCopy, 0, length);
+        mDispatcher.dispatchOnAudioAvailable(bufferCopy);
 
         // Might block on mItem.this, if there are too many buffers waiting to
         // be consumed.
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 61c33ff..d55c7bd 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -16,6 +16,7 @@
 package android.speech.tts;
 
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.annotation.RawRes;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
@@ -665,7 +666,7 @@
     private OnInitListener mInitListener;
     // Written from an unspecified application thread, read from
     // a binder thread.
-    private volatile UtteranceProgressListener mUtteranceProgressListener;
+    @Nullable private volatile UtteranceProgressListener mUtteranceProgressListener;
     private final Object mStartLock = new Object();
 
     private String mRequestedEngine;
@@ -2133,6 +2134,23 @@
                     listener.onStart(utteranceId);
                 }
             }
+
+            @Override
+            public void onBeginSynthesis(String utteranceId, int sampleRateInHz, int audioFormat,
+                                     int channelCount) {
+                UtteranceProgressListener listener = mUtteranceProgressListener;
+                if (listener != null) {
+                    listener.onBeginSynthesis(utteranceId, sampleRateInHz, audioFormat, channelCount);
+                }
+            }
+
+            @Override
+            public void onAudioAvailable(String utteranceId, byte[] audio) {
+                UtteranceProgressListener listener = mUtteranceProgressListener;
+                if (listener != null) {
+                    listener.onAudioAvailable(utteranceId, audio);
+                }
+            }
         };
 
         private class SetupConnectionAsyncTask extends AsyncTask<Void, Void, Integer> {
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 8c355d8..fc075de 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -15,6 +15,7 @@
  */
 package android.speech.tts;
 
+import android.annotation.NonNull;
 import android.app.Service;
 import android.content.Intent;
 import android.media.AudioAttributes;
@@ -111,7 +112,7 @@
     // A thread and it's associated handler for playing back any audio
     // associated with this TTS engine. Will handle all requests except synthesis
     // to file requests, which occur on the synthesis thread.
-    private AudioPlaybackHandler mAudioPlaybackHandler;
+    @NonNull private AudioPlaybackHandler mAudioPlaybackHandler;
     private TtsEngines mEngineHelper;
 
     private CallbackMap mCallbacks;
@@ -649,6 +650,8 @@
         public void dispatchOnSuccess();
         public void dispatchOnStart();
         public void dispatchOnError(int errorCode);
+        public void dispatchOnBeginSynthesis(int sampleRateInHz, int audioFormat, int channelCount);
+        public void dispatchOnAudioAvailable(byte[] audio);
     }
 
     /** Set of parameters affecting audio output. */
@@ -853,6 +856,22 @@
             }
         }
 
+        @Override
+        public void dispatchOnBeginSynthesis(int sampleRateInHz, int audioFormat, int channelCount) {
+            final String utteranceId = getUtteranceId();
+            if (utteranceId != null) {
+                mCallbacks.dispatchOnBeginSynthesis(getCallerIdentity(), utteranceId, sampleRateInHz, audioFormat, channelCount);
+            }
+        }
+
+        @Override
+        public void dispatchOnAudioAvailable(byte[] audio) {
+            final String utteranceId = getUtteranceId();
+            if (utteranceId != null) {
+                mCallbacks.dispatchOnAudioAvailable(getCallerIdentity(), utteranceId, audio);
+            }
+        }
+
         abstract public String getUtteranceId();
 
         String getStringParam(Bundle params, String key, String defaultValue) {
@@ -1430,7 +1449,6 @@
             } catch (RemoteException e) {
                 Log.e(TAG, "Callback onStart failed: " + e);
             }
-
         }
 
         public void dispatchOnError(Object callerIdentity, String utteranceId,
@@ -1444,6 +1462,26 @@
             }
         }
 
+        public void dispatchOnBeginSynthesis(Object callerIdentity, String utteranceId, int sampleRateInHz, int audioFormat, int channelCount) {
+            ITextToSpeechCallback cb = getCallbackFor(callerIdentity);
+            if (cb == null) return;
+            try {
+                cb.onBeginSynthesis(utteranceId, sampleRateInHz, audioFormat, channelCount);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Callback dispatchOnBeginSynthesis(String, int, int, int) failed: " + e);
+            }
+        }
+
+        public void dispatchOnAudioAvailable(Object callerIdentity, String utteranceId, byte[] buffer) {
+            ITextToSpeechCallback cb = getCallbackFor(callerIdentity);
+            if (cb == null) return;
+            try {
+                cb.onAudioAvailable(utteranceId, buffer);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Callback dispatchOnAudioAvailable(String, byte[]) failed: " + e);
+            }
+        }
+
         @Override
         public void onCallbackDied(ITextToSpeechCallback callback, Object cookie) {
             IBinder caller = (IBinder) cookie;
diff --git a/core/java/android/speech/tts/UtteranceProgressListener.java b/core/java/android/speech/tts/UtteranceProgressListener.java
index 890ea3d..72a5228 100644
--- a/core/java/android/speech/tts/UtteranceProgressListener.java
+++ b/core/java/android/speech/tts/UtteranceProgressListener.java
@@ -2,6 +2,8 @@
 
 package android.speech.tts;
 
+import android.media.AudioFormat;
+
 /**
  * Listener for events relating to the progress of an utterance through
  * the synthesis queue. Each utterance is associated with a call to
@@ -14,10 +16,10 @@
     /**
      * Called when an utterance "starts" as perceived by the caller. This will
      * be soon before audio is played back in the case of a {@link TextToSpeech#speak}
-     * or before the first bytes of a file are written to storage in the case
+     * or before the first bytes of a file are written to the file system in the case
      * of {@link TextToSpeech#synthesizeToFile}.
      *
-     * @param utteranceId the utterance ID of the utterance.
+     * @param utteranceId The utterance ID of the utterance.
      */
     public abstract void onStart(String utteranceId);
 
@@ -28,7 +30,7 @@
      *
      * This request is guaranteed to be called after {@link #onStart(String)}.
      *
-     * @param utteranceId the utterance ID of the utterance.
+     * @param utteranceId The utterance ID of the utterance.
      */
     public abstract void onDone(String utteranceId);
 
@@ -39,7 +41,7 @@
      * be a call to both {@link #onDone(String)} and {@link #onError(String)} for
      * the same utterance.
      *
-     * @param utteranceId the utterance ID of the utterance.
+     * @param utteranceId The utterance ID of the utterance.
      * @deprecated Use {@link #onError(String,int)} instead
      */
     @Deprecated
@@ -52,7 +54,7 @@
      * be a call to both {@link #onDone(String)} and {@link #onError(String,int)} for
      * the same utterance. The default implementation calls {@link #onError(String)}.
      *
-     * @param utteranceId the utterance ID of the utterance.
+     * @param utteranceId The utterance ID of the utterance.
      * @param errorCode one of the ERROR_* codes from {@link TextToSpeech}
      */
     public void onError(String utteranceId, int errorCode) {
@@ -65,7 +67,7 @@
      * or uses {@link TextToSpeech#QUEUE_FLUSH} as an argument with the
      * {@link TextToSpeech#speak} or {@link TextToSpeech#synthesizeToFile} methods.
      *
-     * @param utteranceId the utterance ID of the utterance.
+     * @param utteranceId The utterance ID of the utterance.
      * @param interrupted If true, then the utterance was interrupted while being synthesized
      *        and its output is incomplete. If false, then the utterance was flushed
      *        before the synthesis started.
@@ -74,6 +76,52 @@
     }
 
     /**
+     * Called when the TTS engine begins to synthesize the audio for a request.
+     *
+     * <p>
+     * It provides information about the format of the byte array for subsequent
+     * {@link #onAudioAvailable} calls.
+     * </p>
+     *
+     * <p>
+     * This is called when the TTS engine starts synthesizing audio for the request. If an
+     * application wishes to know when the audio is about to start playing, {#onStart(String)}
+     * should be used instead.
+     * </p>
+     *
+     * @param utteranceId The utterance ID of the utterance.
+     * @param sampleRateInHz Sample rate in hertz of the generated audio.
+     * @param audioFormat Audio format of the generated audio. Should be one of
+     *        {@link AudioFormat#ENCODING_PCM_8BIT}, {@link AudioFormat#ENCODING_PCM_16BIT} or
+     *        {@link AudioFormat#ENCODING_PCM_FLOAT}.
+     * @param channelCount The number of channels.
+     */
+    public void onBeginSynthesis(String utteranceId, int sampleRateInHz, int audioFormat, int channelCount) {
+    }
+
+    /**
+     * This is called when a chunk of audio is ready for consumption.
+     *
+     * <p>
+     * The audio parameter is a copy of what will be synthesized to the speakers (when synthesis was
+     * initiated with a {@link TextToSpeech#speak} call) or written to the file system (for
+     * {@link TextToSpeech#synthesizeToFile}). The audio bytes are delivered in one or more chunks;
+     * if {@link #onDone} or {@link #onError} is called all chunks have been received.
+     * </p>
+     *
+     * <p>
+     * The audio received here may not be played for some time depending on buffer sizes and the
+     * amount of items on the synthesis queue.
+     * </p>
+     *
+     * @param utteranceId The utterance ID of the utterance.
+     * @param audio A chunk of audio; the format can be known by listening to
+     *        {@link #onBeginSynthesis(String, int, int, int)}.
+     */
+    public void onAudioAvailable(String utteranceId, byte[] audio) {
+    }
+
+    /**
      * Wraps an old deprecated OnUtteranceCompletedListener with a shiny new
      * progress listener.
      *
diff --git a/core/java/android/test/AndroidTestCase.java b/core/java/android/test/AndroidTestCase.java
index 2ecbfae..1e6bd9c 100644
--- a/core/java/android/test/AndroidTestCase.java
+++ b/core/java/android/test/AndroidTestCase.java
@@ -29,7 +29,13 @@
 
 /**
  * Extend this if you need to access Resources or other things that depend on Activity Context.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html">
+ * InstrumentationRegistry</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class AndroidTestCase extends TestCase {
 
     protected Context mContext;
diff --git a/core/java/android/test/FlakyTest.java b/core/java/android/test/FlakyTest.java
index 919767f..4e5c4e3 100644
--- a/core/java/android/test/FlakyTest.java
+++ b/core/java/android/test/FlakyTest.java
@@ -26,7 +26,13 @@
  * test methods. When the annotation is present, the test method is re-executed if
  * the test fails. The total number of executions is specified by the tolerance and
  * defaults to 1.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/filters/FlakyTest.html">
+ * FlakyTest</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 @Target(ElementType.METHOD)
 @Retention(RetentionPolicy.RUNTIME)
 public @interface FlakyTest {
diff --git a/core/java/android/test/InstrumentationTestCase.java b/core/java/android/test/InstrumentationTestCase.java
index ca427ea..6b79314 100644
--- a/core/java/android/test/InstrumentationTestCase.java
+++ b/core/java/android/test/InstrumentationTestCase.java
@@ -32,7 +32,13 @@
 
 /**
  * A test case that has access to {@link Instrumentation}.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html">
+ * InstrumentationRegistry</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class InstrumentationTestCase extends TestCase {
 
     private Instrumentation mInstrumentation;
@@ -40,7 +46,7 @@
     /**
      * Injects instrumentation into this test case. This method is
      * called by the test runner during test setup.
-     * 
+     *
      * @param instrumentation the instrumentation to use with this instance
      */
     public void injectInstrumentation(Instrumentation instrumentation) {
diff --git a/core/java/android/test/InstrumentationTestSuite.java b/core/java/android/test/InstrumentationTestSuite.java
index 7a78ffb..a53fa26 100644
--- a/core/java/android/test/InstrumentationTestSuite.java
+++ b/core/java/android/test/InstrumentationTestSuite.java
@@ -25,7 +25,13 @@
 /**
  * A {@link junit.framework.TestSuite} that injects {@link android.app.Instrumentation} into
  * {@link InstrumentationTestCase} before running them.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html">
+ * InstrumentationRegistry</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class InstrumentationTestSuite extends TestSuite {
 
     private final Instrumentation mInstrumentation;
diff --git a/core/java/android/test/PerformanceTestCase.java b/core/java/android/test/PerformanceTestCase.java
index 679ad40..65bd4a4 100644
--- a/core/java/android/test/PerformanceTestCase.java
+++ b/core/java/android/test/PerformanceTestCase.java
@@ -18,10 +18,11 @@
 
 /**
  * More complex interface performance for test cases.
- * 
+ *
  * If you want your test to be used as a performance test, you must
  * implement this interface.
  */
+@Deprecated
 public interface PerformanceTestCase
 {
     /**
@@ -37,27 +38,27 @@
     }
 
     /**
-     * Set up to begin performance tests.  The 'intermediates' is a
+     * Set up to begin performance tests. The 'intermediates' is a
      * communication channel to send back intermediate performance numbers --
      * if you use it, you will probably want to ensure your test is only
      * executed once by returning 1.  Otherwise, return 0 to allow the test
      * harness to decide the number of iterations.
-     * 
+     *
      * <p>If you return a non-zero iteration count, you should call
      * {@link Intermediates#startTiming intermediates.startTiming} and
      * {@link Intermediates#finishTiming intermediates.endTiming} to report the
      * duration of the test whose performance should actually be measured.
-     * 
+     *
      * @param intermediates Callback for sending intermediate results.
-     * 
+     *
      * @return int Maximum number of iterations to run, or 0 to let the caller
-     *         decide.
+     * decide.
      */
     int startPerformance(Intermediates intermediates);
-    
+
     /**
      * This method is used to determine what modes this test case can run in.
-     * 
+     *
      * @return true if this test case can only be run in performance mode.
      */
     boolean isPerformanceOnly();
diff --git a/core/java/android/test/UiThreadTest.java b/core/java/android/test/UiThreadTest.java
index cd92231..cd06ab8 100644
--- a/core/java/android/test/UiThreadTest.java
+++ b/core/java/android/test/UiThreadTest.java
@@ -26,7 +26,13 @@
  * When the annotation is present, the test method is executed on the application's
  * main thread (or UI thread.) Note that instrumentation methods may not be used
  * when this annotation is present.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/annotation/UiThreadTest.html">
+ * UiThreadTest</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 @Target(ElementType.METHOD)
 @Retention(RetentionPolicy.RUNTIME)
 public @interface UiThreadTest {
diff --git a/core/java/android/test/suitebuilder/annotation/LargeTest.java b/core/java/android/test/suitebuilder/annotation/LargeTest.java
index a6269e7..dc77ee6 100644
--- a/core/java/android/test/suitebuilder/annotation/LargeTest.java
+++ b/core/java/android/test/suitebuilder/annotation/LargeTest.java
@@ -23,7 +23,13 @@
 
 /**
  * Marks a test that should run as part of the large tests.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/filters/LargeTest.html">
+ * LargeTest</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.METHOD, ElementType.TYPE})
 public @interface LargeTest {
diff --git a/core/java/android/test/suitebuilder/annotation/MediumTest.java b/core/java/android/test/suitebuilder/annotation/MediumTest.java
index 8afeb91..b941da0 100644
--- a/core/java/android/test/suitebuilder/annotation/MediumTest.java
+++ b/core/java/android/test/suitebuilder/annotation/MediumTest.java
@@ -24,7 +24,12 @@
 /**
  * Marks a test that should run as part of the medium tests.
  *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/filters/MediumTest.html">
+ * MediumTest</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.METHOD, ElementType.TYPE})
 public @interface MediumTest {
diff --git a/core/java/android/test/suitebuilder/annotation/SmallTest.java b/core/java/android/test/suitebuilder/annotation/SmallTest.java
index ad530e2..d3c74f0 100644
--- a/core/java/android/test/suitebuilder/annotation/SmallTest.java
+++ b/core/java/android/test/suitebuilder/annotation/SmallTest.java
@@ -23,7 +23,13 @@
 
 /**
  * Marks a test that should run as part of the small tests.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/filters/SmallTest.html">
+ * SmallTest</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.METHOD, ElementType.TYPE})
 public @interface SmallTest {
diff --git a/core/java/android/test/suitebuilder/annotation/Smoke.java b/core/java/android/test/suitebuilder/annotation/Smoke.java
index 237e033..aac2937 100644
--- a/core/java/android/test/suitebuilder/annotation/Smoke.java
+++ b/core/java/android/test/suitebuilder/annotation/Smoke.java
@@ -27,7 +27,11 @@
  * will run all tests with this annotation.
  *
  * @see android.test.suitebuilder.SmokeTestSuiteBuilder
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.METHOD, ElementType.TYPE})
 public @interface Smoke {
diff --git a/core/java/android/test/suitebuilder/annotation/Suppress.java b/core/java/android/test/suitebuilder/annotation/Suppress.java
index f16c8fa..629a3cf 100644
--- a/core/java/android/test/suitebuilder/annotation/Suppress.java
+++ b/core/java/android/test/suitebuilder/annotation/Suppress.java
@@ -26,7 +26,12 @@
  * suite. If the annotation appears on the class then no tests in that class will be included. If
  * the annotation appears only on a test method then only that method will be excluded.
  *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/filters/Suppress.html">
+ * Suppress</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.METHOD, ElementType.TYPE})
 public @interface Suppress {
diff --git a/core/java/android/text/Editable.java b/core/java/android/text/Editable.java
index a284a00..b3f2c2a 100644
--- a/core/java/android/text/Editable.java
+++ b/core/java/android/text/Editable.java
@@ -40,10 +40,14 @@
      * is Spanned, the spans from it are preserved into the Editable.
      * Existing spans within the Editable that entirely cover the replaced
      * range are retained, but any that were strictly within the range
-     * that was replaced are removed.  As a special case, the cursor
-     * position is preserved even when the entire range where it is
-     * located is replaced.
+     * that was replaced are removed. If the <code>source</code> contains a span
+     * with {@link Spanned#SPAN_PARAGRAPH} flag, and it does not satisfy the
+     * paragraph boundary constraint, it is not retained. As a special case, the
+     * cursor position is preserved even when the entire range where it is located
+     * is replaced.
      * @return  a reference to this object.
+     *
+     * @see Spanned#SPAN_PARAGRAPH
      */
     public Editable replace(int st, int en, CharSequence source, int start, int end);
 
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index 3d8ab1e..ed91239c 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -16,7 +16,6 @@
 
 package android.text;
 
-import android.graphics.Color;
 import com.android.internal.util.ArrayUtils;
 import org.ccil.cowan.tagsoup.HTMLSchema;
 import org.ccil.cowan.tagsoup.Parser;
@@ -27,12 +26,17 @@
 import org.xml.sax.SAXException;
 import org.xml.sax.XMLReader;
 
+import android.app.ActivityThread;
+import android.app.Application;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
+import android.graphics.Color;
 import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.text.style.AbsoluteSizeSpan;
 import android.text.style.AlignmentSpan;
+import android.text.style.BackgroundColorSpan;
+import android.text.style.BulletSpan;
 import android.text.style.CharacterStyle;
 import android.text.style.ForegroundColorSpan;
 import android.text.style.ImageSpan;
@@ -85,18 +89,109 @@
                                  Editable output, XMLReader xmlReader);
     }
 
+    /**
+     * Option for {@link #toHtml(Spanned, int)}: Wrap consecutive lines of text delimited by '\n'
+     * inside &lt;p&gt; elements. {@link BulletSpan}s are ignored.
+     */
+    public static final int TO_HTML_PARAGRAPH_LINES_CONSECUTIVE = 0x00000000;
+
+    /**
+     * Option for {@link #toHtml(Spanned, int)}: Wrap each line of text delimited by '\n' inside a
+     * &lt;p&gt; or a &lt;li&gt; element. This allows {@link ParagraphStyle}s attached to be
+     * encoded as CSS styles within the corresponding &lt;p&gt; or &lt;li&gt; element.
+     */
+    public static final int TO_HTML_PARAGRAPH_LINES_INDIVIDUAL = 0x00000001;
+
+    /**
+     * Flag indicating that texts inside &lt;p&gt; elements will be separated from other texts with
+     * one newline character by default.
+     */
+    public static final int FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH = 0x00000001;
+
+    /**
+     * Flag indicating that texts inside &lt;h1&gt;~&lt;h6&gt; elements will be separated from
+     * other texts with one newline character by default.
+     */
+    public static final int FROM_HTML_SEPARATOR_LINE_BREAK_HEADING = 0x00000002;
+
+    /**
+     * Flag indicating that texts inside &lt;li&gt; elements will be separated from other texts
+     * with one newline character by default.
+     */
+    public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM = 0x00000004;
+
+    /**
+     * Flag indicating that texts inside &lt;ul&gt; elements will be separated from other texts
+     * with one newline character by default.
+     */
+    public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST = 0x00000008;
+
+    /**
+     * Flag indicating that texts inside &lt;div&gt; elements will be separated from other texts
+     * with one newline character by default.
+     */
+    public static final int FROM_HTML_SEPARATOR_LINE_BREAK_DIV = 0x00000010;
+
+    /**
+     * Flag indicating that texts inside &lt;blockquote&gt; elements will be separated from other
+     * texts with one newline character by default.
+     */
+    public static final int FROM_HTML_SEPARATOR_LINE_BREAK_BLOCKQUOTE = 0x00000020;
+
+    /**
+     * Flag indicating that CSS color values should be used instead of those defined in
+     * {@link Color}.
+     */
+    public static final int FROM_HTML_OPTION_USE_CSS_COLORS = 0x00000100;
+
+    /**
+     * Flags for {@link #fromHtml(String, int, ImageGetter, TagHandler)}: Separate block-level
+     * elements with blank lines (two newline characters) in between. This is the legacy behavior
+     * prior to N.
+     */
+    public static final int FROM_HTML_MODE_LEGACY = 0x00000000;
+
+    /**
+     * Flags for {@link #fromHtml(String, int, ImageGetter, TagHandler)}: Separate block-level
+     * elements with line breaks (single newline character) in between. This inverts the
+     * {@link Spanned} to HTML string conversion done with the option
+     * {@link #TO_HTML_PARAGRAPH_LINES_INDIVIDUAL}.
+     */
+    public static final int FROM_HTML_MODE_COMPACT =
+            FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH
+            | FROM_HTML_SEPARATOR_LINE_BREAK_HEADING
+            | FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM
+            | FROM_HTML_SEPARATOR_LINE_BREAK_LIST
+            | FROM_HTML_SEPARATOR_LINE_BREAK_DIV
+            | FROM_HTML_SEPARATOR_LINE_BREAK_BLOCKQUOTE;
+
+    /**
+     * The bit which indicates if lines delimited by '\n' will be grouped into &lt;p&gt; elements.
+     */
+    private static final int TO_HTML_PARAGRAPH_FLAG = 0x00000001;
+
     private Html() { }
 
     /**
-     * Returns displayable styled text from the provided HTML string.
-     * Any &lt;img&gt; tags in the HTML will display as a generic
-     * replacement image which your program can then go through and
+     * Returns displayable styled text from the provided HTML string with the legacy flags
+     * {@link #FROM_HTML_MODE_LEGACY}.
+     *
+     * @deprecated use {@link #fromHtml(String, int)} instead.
+     */
+    @Deprecated
+    public static Spanned fromHtml(String source) {
+        return fromHtml(source, FROM_HTML_MODE_LEGACY, null, null);
+    }
+
+    /**
+     * Returns displayable styled text from the provided HTML string. Any &lt;img&gt; tags in the
+     * HTML will display as a generic replacement image which your program can then go through and
      * replace with real images.
      *
      * <p>This uses TagSoup to handle real HTML, including all of the brokenness found in the wild.
      */
-    public static Spanned fromHtml(String source) {
-        return fromHtml(source, null, null);
+    public static Spanned fromHtml(String source, int flags) {
+        return fromHtml(source, flags, null, null);
     }
 
     /**
@@ -109,16 +204,26 @@
     }
 
     /**
-     * Returns displayable styled text from the provided HTML string.
-     * Any &lt;img&gt; tags in the HTML will use the specified ImageGetter
-     * to request a representation of the image (use null if you don't
-     * want this) and the specified TagHandler to handle unknown tags
-     * (specify null if you don't want this).
+     * Returns displayable styled text from the provided HTML string with the legacy flags
+     * {@link #FROM_HTML_MODE_LEGACY}.
+     *
+     * @deprecated use {@link #fromHtml(String, int, ImageGetter, TagHandler)} instead.
+     */
+    @Deprecated
+    public static Spanned fromHtml(String source, ImageGetter imageGetter, TagHandler tagHandler) {
+        return fromHtml(source, FROM_HTML_MODE_LEGACY, imageGetter, tagHandler);
+    }
+
+    /**
+     * Returns displayable styled text from the provided HTML string. Any &lt;img&gt; tags in the
+     * HTML will use the specified ImageGetter to request a representation of the image (use null
+     * if you don't want this) and the specified TagHandler to handle unknown tags (specify null if
+     * you don't want this).
      *
      * <p>This uses TagSoup to handle real HTML, including all of the brokenness found in the wild.
      */
-    public static Spanned fromHtml(String source, ImageGetter imageGetter,
-                                   TagHandler tagHandler) {
+    public static Spanned fromHtml(String source, int flags, ImageGetter imageGetter,
+            TagHandler tagHandler) {
         Parser parser = new Parser();
         try {
             parser.setProperty(Parser.schemaProperty, HtmlParser.schema);
@@ -131,22 +236,31 @@
         }
 
         HtmlToSpannedConverter converter =
-                new HtmlToSpannedConverter(source, imageGetter, tagHandler,
-                        parser);
+                new HtmlToSpannedConverter(source, imageGetter, tagHandler, parser, flags);
         return converter.convert();
     }
 
     /**
+     * @deprecated use {@link #toHtml(Spanned, int)} instead.
+     */
+    @Deprecated
+    public static String toHtml(Spanned text) {
+        return toHtml(text, TO_HTML_PARAGRAPH_LINES_CONSECUTIVE);
+    }
+
+    /**
      * Returns an HTML representation of the provided Spanned text. A best effort is
      * made to add HTML tags corresponding to spans. Also note that HTML metacharacters
      * (such as "&lt;" and "&amp;") within the input text are escaped.
      *
      * @param text input text to convert
+     * @param option one of {@link #TO_HTML_PARAGRAPH_LINES_CONSECUTIVE} or
+     *     {@link #TO_HTML_PARAGRAPH_LINES_INDIVIDUAL}
      * @return string containing input converted to HTML
      */
-    public static String toHtml(Spanned text) {
+    public static String toHtml(Spanned text, int option) {
         StringBuilder out = new StringBuilder();
-        withinHtml(out, text);
+        withinHtml(out, text, option);
         return out.toString();
     }
 
@@ -159,11 +273,20 @@
         return out.toString();
     }
 
-    private static void withinHtml(StringBuilder out, Spanned text) {
+    private static void withinHtml(StringBuilder out, Spanned text, int option) {
+        if ((option & TO_HTML_PARAGRAPH_FLAG) == TO_HTML_PARAGRAPH_LINES_CONSECUTIVE) {
+            encodeTextAlignmentByDiv(out, text, option);
+            return;
+        }
+
+        withinDiv(out, text, 0, text.length(), option);
+    }
+
+    private static void encodeTextAlignmentByDiv(StringBuilder out, Spanned text, int option) {
         int len = text.length();
 
         int next;
-        for (int i = 0; i < text.length(); i = next) {
+        for (int i = 0; i < len; i = next) {
             next = text.nextSpanTransition(i, len, ParagraphStyle.class);
             ParagraphStyle[] style = text.getSpans(i, next, ParagraphStyle.class);
             String elements = " ";
@@ -187,7 +310,7 @@
                 out.append("<div ").append(elements).append(">");
             }
 
-            withinDiv(out, text, i, next);
+            withinDiv(out, text, i, next, option);
 
             if (needDiv) {
                 out.append("</div>");
@@ -195,8 +318,8 @@
         }
     }
 
-    private static void withinDiv(StringBuilder out, Spanned text,
-            int start, int end) {
+    private static void withinDiv(StringBuilder out, Spanned text, int start, int end,
+            int option) {
         int next;
         for (int i = start; i < end; i = next) {
             next = text.nextSpanTransition(i, end, QuoteSpan.class);
@@ -206,7 +329,7 @@
                 out.append("<blockquote>");
             }
 
-            withinBlockquote(out, text, i, next);
+            withinBlockquote(out, text, i, next, option);
 
             for (QuoteSpan quote : quotes) {
                 out.append("</blockquote>\n");
@@ -214,7 +337,7 @@
         }
     }
 
-    private static String getOpenParaTagWithDirection(Spanned text, int start, int end) {
+    private static String getTextDirection(Spanned text, int start, int end) {
         final int len = end - start;
         final byte[] levels = ArrayUtils.newUnpaddedByteArray(len);
         final char[] buffer = TextUtils.obtain(len);
@@ -224,16 +347,101 @@
                 false /* no info */);
         switch(paraDir) {
             case Layout.DIR_RIGHT_TO_LEFT:
-                return "<p dir=\"rtl\">";
+                return " dir=\"rtl\"";
             case Layout.DIR_LEFT_TO_RIGHT:
             default:
-                return "<p dir=\"ltr\">";
+                return " dir=\"ltr\"";
         }
     }
 
-    private static void withinBlockquote(StringBuilder out, Spanned text,
-                                         int start, int end) {
-        out.append(getOpenParaTagWithDirection(text, start, end));
+    private static String getTextStyles(Spanned text, int start, int end) {
+        final StringBuilder style = new StringBuilder(" style=\"margin-top:0; margin-bottom:0;");
+
+        final AlignmentSpan[] alignmentSpans = text.getSpans(start, end, AlignmentSpan.class);
+        final int len = alignmentSpans.length;
+        if (len > 0) {
+            final Layout.Alignment alignment = alignmentSpans[len - 1].getAlignment();
+            if (alignment == Layout.Alignment.ALIGN_NORMAL) {
+                style.append(" text-align:start;");
+            } else if (alignment == Layout.Alignment.ALIGN_CENTER) {
+                style.append(" text-align:center;");
+            } else if (alignment == Layout.Alignment.ALIGN_OPPOSITE) {
+                style.append(" text-align:end;");
+            }
+        }
+
+        style.append("\"");
+        return style.toString();
+    }
+
+    private static void withinBlockquote(StringBuilder out, Spanned text, int start, int end,
+            int option) {
+        if ((option & TO_HTML_PARAGRAPH_FLAG) == TO_HTML_PARAGRAPH_LINES_CONSECUTIVE) {
+            withinBlockquoteConsecutive(out, text, start, end);
+        } else {
+            withinBlockquoteIndividual(out, text, start, end);
+        }
+    }
+
+    private static void withinBlockquoteIndividual(StringBuilder out, Spanned text, int start,
+            int end) {
+        boolean isInList = false;
+        int next;
+        for (int i = start; i <= end; i = next) {
+            next = TextUtils.indexOf(text, '\n', i, end);
+            if (next < 0) {
+                next = end;
+            }
+
+            boolean isListItem = false;
+            ParagraphStyle[] paragraphStyles = text.getSpans(i, next, ParagraphStyle.class);
+            for (ParagraphStyle paragraphStyle : paragraphStyles) {
+                final int spanFlags = text.getSpanFlags(paragraphStyle);
+                if ((spanFlags & Spanned.SPAN_PARAGRAPH) == Spanned.SPAN_PARAGRAPH
+                        && paragraphStyle instanceof BulletSpan) {
+                    isListItem = true;
+                    break;
+                }
+            }
+
+            if (isListItem && !isInList) {
+                // Current paragraph is the first item in a list
+                isInList = true;
+                out.append("<ul>\n");
+            }
+
+            if (isInList && !isListItem) {
+                // Current paragraph is no longer a list item; close the previously opened list
+                isInList = false;
+                out.append("</ul>\n");
+            }
+
+            String tagType = isListItem ? "li" : "p";
+            out.append("<").append(tagType).append(getTextDirection(text, start, next))
+                    .append(getTextStyles(text, start, next)).append(">");
+
+            if (next - i == 0) {
+                out.append("<br>");
+            } else {
+                withinParagraph(out, text, i, next);
+            }
+
+            out.append("</");
+            out.append(tagType);
+            out.append(">\n");
+
+            if (next == end && isInList) {
+                isInList = false;
+                out.append("</ul>\n");
+            }
+
+            next++;
+        }
+    }
+
+    private static void withinBlockquoteConsecutive(StringBuilder out, Spanned text, int start,
+            int end) {
+        out.append("<p").append(getTextDirection(text, start, end)).append(">");
 
         int next;
         for (int i = start; i < end; i = next) {
@@ -249,25 +457,30 @@
                 next++;
             }
 
-            if (withinParagraph(out, text, i, next - nl, nl, next == end)) {
-                /* Paragraph should be closed */
-                out.append("</p>\n");
-                out.append(getOpenParaTagWithDirection(text, next, end));
+            withinParagraph(out, text, i, next - nl);
+
+            if (nl == 1) {
+                out.append("<br>\n");
+            } else {
+                for (int j = 2; j < nl; j++) {
+                    out.append("<br>");
+                }
+                if (next != end) {
+                    /* Paragraph should be closed and reopened */
+                    out.append("</p>\n");
+                    out.append("<p").append(getTextDirection(text, start, end)).append(">");
+                }
             }
         }
 
         out.append("</p>\n");
     }
 
-    /* Returns true if the caller should close and reopen the paragraph. */
-    private static boolean withinParagraph(StringBuilder out, Spanned text,
-                                        int start, int end, int nl,
-                                        boolean last) {
+    private static void withinParagraph(StringBuilder out, Spanned text, int start, int end) {
         int next;
         for (int i = start; i < end; i = next) {
             next = text.nextSpanTransition(i, end, CharacterStyle.class);
-            CharacterStyle[] style = text.getSpans(i, next,
-                                                   CharacterStyle.class);
+            CharacterStyle[] style = text.getSpans(i, next, CharacterStyle.class);
 
             for (int j = 0; j < style.length; j++) {
                 if (style[j] instanceof StyleSpan) {
@@ -297,7 +510,7 @@
                     out.append("<u>");
                 }
                 if (style[j] instanceof StrikethroughSpan) {
-                    out.append("<strike>");
+                    out.append("<span style=\"text-decoration:line-through;\">");
                 }
                 if (style[j] instanceof URLSpan) {
                     out.append("<a href=\"");
@@ -313,36 +526,51 @@
                     i = next;
                 }
                 if (style[j] instanceof AbsoluteSizeSpan) {
-                    out.append("<font size =\"");
-                    out.append(((AbsoluteSizeSpan) style[j]).getSize() / 6);
-                    out.append("\">");
+                    AbsoluteSizeSpan s = ((AbsoluteSizeSpan) style[j]);
+                    float sizeDip = s.getSize();
+                    if (!s.getDip()) {
+                        Application application = ActivityThread.currentApplication();
+                        sizeDip /= application.getResources().getDisplayMetrics().density;
+                    }
+
+                    // px in CSS is the equivalance of dip in Android
+                    out.append(String.format("<span style=\"font-size:%.0fpx\";>", sizeDip));
+                }
+                if (style[j] instanceof RelativeSizeSpan) {
+                    float sizeEm = ((RelativeSizeSpan) style[j]).getSizeChange();
+                    out.append(String.format("<span style=\"font-size:%.2fem;\">", sizeEm));
                 }
                 if (style[j] instanceof ForegroundColorSpan) {
-                    out.append("<font color =\"#");
-                    String color = Integer.toHexString(((ForegroundColorSpan)
-                            style[j]).getForegroundColor() + 0x01000000);
-                    while (color.length() < 6) {
-                        color = "0" + color;
-                    }
-                    out.append(color);
-                    out.append("\">");
+                    int color = ((ForegroundColorSpan) style[j]).getForegroundColor();
+                    out.append(String.format("<span style=\"color:#%06X;\">", 0xFFFFFF & color));
+                }
+                if (style[j] instanceof BackgroundColorSpan) {
+                    int color = ((BackgroundColorSpan) style[j]).getBackgroundColor();
+                    out.append(String.format("<span style=\"background-color:#%06X;\">",
+                            0xFFFFFF & color));
                 }
             }
 
             withinStyle(out, text, i, next);
 
             for (int j = style.length - 1; j >= 0; j--) {
+                if (style[j] instanceof BackgroundColorSpan) {
+                    out.append("</span>");
+                }
                 if (style[j] instanceof ForegroundColorSpan) {
-                    out.append("</font>");
+                    out.append("</span>");
+                }
+                if (style[j] instanceof RelativeSizeSpan) {
+                    out.append("</span>");
                 }
                 if (style[j] instanceof AbsoluteSizeSpan) {
-                    out.append("</font>");
+                    out.append("</span>");
                 }
                 if (style[j] instanceof URLSpan) {
                     out.append("</a>");
                 }
                 if (style[j] instanceof StrikethroughSpan) {
-                    out.append("</strike>");
+                    out.append("</span>");
                 }
                 if (style[j] instanceof UnderlineSpan) {
                     out.append("</u>");
@@ -372,16 +600,6 @@
                 }
             }
         }
-
-        if (nl == 1) {
-            out.append("<br>\n");
-            return false;
-        } else {
-            for (int i = 2; i < nl; i++) {
-                out.append("<br>");
-            }
-            return !last;
-        }
     }
 
     private static void withinStyle(StringBuilder out, CharSequence text,
@@ -431,15 +649,16 @@
     private SpannableStringBuilder mSpannableStringBuilder;
     private Html.ImageGetter mImageGetter;
     private Html.TagHandler mTagHandler;
+    private int mFlags;
 
-    public HtmlToSpannedConverter(
-            String source, Html.ImageGetter imageGetter, Html.TagHandler tagHandler,
-            Parser parser) {
+    public HtmlToSpannedConverter( String source, Html.ImageGetter imageGetter,
+            Html.TagHandler tagHandler, Parser parser, int flags) {
         mSource = source;
         mSpannableStringBuilder = new SpannableStringBuilder();
         mImageGetter = imageGetter;
         mTagHandler = tagHandler;
         mReader = parser;
+        mFlags = flags;
     }
 
     public Spanned convert() {
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index f9387b3..692d848 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1116,24 +1116,30 @@
     public int getOffsetForHorizontal(int line, float horiz) {
         // TODO: use Paint.getOffsetForAdvance to avoid binary search
         final int lineEndOffset = getLineEnd(line);
+        final int lineStartOffset = getLineStart(line);
+
+        Directions dirs = getLineDirections(line);
+
+        TextLine tl = TextLine.obtain();
+        // XXX: we don't care about tabs as we just use TextLine#getOffsetToLeftRightOf here.
+        tl.set(mPaint, mText, lineStartOffset, lineEndOffset, getParagraphDirection(line), dirs,
+                false, null);
+
         final int max;
         if (line == getLineCount() - 1) {
             max = lineEndOffset;
         } else {
-            max = mPaint.getTextRunCursor(mText, 0, mText.length(),
-                    isRtlCharAt(lineEndOffset) ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR,
-                    lineEndOffset, Paint.CURSOR_BEFORE);
+            max = tl.getOffsetToLeftRightOf(lineEndOffset - lineStartOffset,
+                    !isRtlCharAt(lineEndOffset - 1)) + lineStartOffset;
         }
-        final int min = getLineStart(line);
-        Directions dirs = getLineDirections(line);
-
-        int best = min;
+        int best = lineStartOffset;
         float bestdist = Math.abs(getPrimaryHorizontal(best) - horiz);
 
         for (int i = 0; i < dirs.mDirections.length; i += 2) {
-            int here = min + dirs.mDirections[i];
+            int here = lineStartOffset + dirs.mDirections[i];
             int there = here + (dirs.mDirections[i+1] & RUN_LENGTH_MASK);
-            int swap = (dirs.mDirections[i+1] & RUN_RTL_FLAG) != 0 ? -1 : 1;
+            boolean isRtl = (dirs.mDirections[i+1] & RUN_RTL_FLAG) != 0;
+            int swap = isRtl ? -1 : 1;
 
             if (there > max)
                 there = max;
@@ -1153,23 +1159,23 @@
                 low = here + 1;
 
             if (low < there) {
-                low = getOffsetAtStartOf(low);
+                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);
+                    if (aft < there) {
+                        float other = Math.abs(getPrimaryHorizontal(aft) - horiz);
 
-                float dist = Math.abs(getPrimaryHorizontal(low) - horiz);
-
-                int aft = TextUtils.getOffsetAfter(mText, low);
-                if (aft < there) {
-                    float other = Math.abs(getPrimaryHorizontal(aft) - horiz);
-
-                    if (other < dist) {
-                        dist = other;
-                        low = aft;
+                        if (other < dist) {
+                            dist = other;
+                            low = aft;
+                        }
                     }
-                }
 
-                if (dist < bestdist) {
-                    bestdist = dist;
-                    best = low;
+                    if (dist < bestdist) {
+                        bestdist = dist;
+                        best = low;
+                    }
                 }
             }
 
@@ -1188,6 +1194,7 @@
             best = max;
         }
 
+        TextLine.recycle(tl);
         return best;
     }
 
@@ -1819,7 +1826,11 @@
             return ArrayUtils.emptyArray(type);
         }
 
-        return text.getSpans(start, end, type);
+        if(text instanceof SpannableStringBuilder) {
+            return ((SpannableStringBuilder) text).getSpans(start, end, type, false);
+        } else {
+            return text.getSpans(start, end, type);
+        }
     }
 
     private char getEllipsisChar(TextUtils.TruncateAt method) {
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index 40315ad..787202e 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -19,6 +19,7 @@
 import android.annotation.Nullable;
 import android.graphics.Canvas;
 import android.graphics.Paint;
+import android.text.style.ParagraphStyle;
 import android.util.Log;
 
 import com.android.internal.util.ArrayUtils;
@@ -66,11 +67,15 @@
         TextUtils.getChars(text, start, end, mText, 0);
 
         mSpanCount = 0;
+        mSpanInsertCount = 0;
         mSpans = EmptyArray.OBJECT;
         mSpanStarts = EmptyArray.INT;
         mSpanEnds = EmptyArray.INT;
         mSpanFlags = EmptyArray.INT;
         mSpanMax = EmptyArray.INT;
+        mSpanOrder = EmptyArray.INT;
+        mPrioSortBuffer = EmptyArray.INT;
+        mOrderSortBuffer = EmptyArray.INT;
 
         if (text instanceof Spanned) {
             Spanned sp = (Spanned) text;
@@ -234,6 +239,7 @@
     // Documentation from interface
     public void clear() {
         replace(0, length(), "", 0, 0);
+        mSpanInsertCount = 0;
     }
 
     // Documentation from interface
@@ -256,6 +262,7 @@
         if (mIndexOfSpan != null) {
             mIndexOfSpan.clear();
         }
+        mSpanInsertCount = 0;
     }
 
     // Documentation from interface
@@ -421,8 +428,17 @@
 
                 // Add span only if this object is not yet used as a span in this string
                 if (getSpanStart(spans[i]) < 0) {
-                    setSpan(false, spans[i], st - csStart + start, en - csStart + start,
-                            sp.getSpanFlags(spans[i]) | SPAN_ADDED);
+                    int copySpanStart = st - csStart + start;
+                    int copySpanEnd = en - csStart + start;
+                    int copySpanFlags = sp.getSpanFlags(spans[i]) | SPAN_ADDED;
+
+                    int flagsStart = (copySpanFlags & START_MASK) >> START_SHIFT;
+                    int flagsEnd = copySpanFlags & END_MASK;
+
+                    if(!isInvalidParagraphStart(copySpanStart, flagsStart) &&
+                            !isInvalidParagraphEnd(copySpanEnd, flagsEnd)) {
+                        setSpan(false, spans[i], copySpanStart, copySpanEnd, copySpanFlags);
+                    }
                 }
             }
             restoreInvariants();
@@ -476,6 +492,7 @@
         System.arraycopy(mSpanStarts, i + 1, mSpanStarts, i, count);
         System.arraycopy(mSpanEnds, i + 1, mSpanEnds, i, count);
         System.arraycopy(mSpanFlags, i + 1, mSpanFlags, i, count);
+        System.arraycopy(mSpanOrder, i + 1, mSpanOrder, i, count);
 
         mSpanCount--;
 
@@ -666,23 +683,13 @@
         checkRange("setSpan", start, end);
 
         int flagsStart = (flags & START_MASK) >> START_SHIFT;
-        if (flagsStart == PARAGRAPH) {
-            if (start != 0 && start != length()) {
-                char c = charAt(start - 1);
-
-                if (c != '\n')
-                    throw new RuntimeException("PARAGRAPH span must start at paragraph boundary");
-            }
+        if(isInvalidParagraphStart(start, flagsStart)) {
+            throw new RuntimeException("PARAGRAPH span must start at paragraph boundary");
         }
 
         int flagsEnd = flags & END_MASK;
-        if (flagsEnd == PARAGRAPH) {
-            if (end != 0 && end != length()) {
-                char c = charAt(end - 1);
-
-                if (c != '\n')
-                    throw new RuntimeException("PARAGRAPH span must end at paragraph boundary");
-            }
+        if(isInvalidParagraphEnd(end, flagsEnd)) {
+            throw new RuntimeException("PARAGRAPH span must end at paragraph boundary");
         }
 
         // 0-length Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
@@ -713,9 +720,6 @@
                 end += mGapLength;
         }
 
-        int count = mSpanCount;
-        Object[] spans = mSpans;
-
         if (mIndexOfSpan != null) {
             Integer index = mIndexOfSpan.get(what);
             if (index != null) {
@@ -745,8 +749,10 @@
         mSpanStarts = GrowingArrayUtils.append(mSpanStarts, mSpanCount, start);
         mSpanEnds = GrowingArrayUtils.append(mSpanEnds, mSpanCount, end);
         mSpanFlags = GrowingArrayUtils.append(mSpanFlags, mSpanCount, flags);
+        mSpanOrder = GrowingArrayUtils.append(mSpanOrder, mSpanCount, mSpanInsertCount);
         invalidateIndex(mSpanCount);
         mSpanCount++;
+        mSpanInsertCount++;
         // Make sure there is enough room for empty interior nodes.
         // This magic formula computes the size of the smallest perfect binary
         // tree no smaller than mSpanCount.
@@ -761,6 +767,28 @@
         }
     }
 
+    private final boolean isInvalidParagraphStart(int start, int flagsStart) {
+        if (flagsStart == PARAGRAPH) {
+            if (start != 0 && start != length()) {
+                char c = charAt(start - 1);
+
+                if (c != '\n') return true;
+            }
+        }
+        return false;
+    }
+
+    private final boolean isInvalidParagraphEnd(int end, int flagsEnd) {
+        if (flagsEnd == PARAGRAPH) {
+            if (end != 0 && end != length()) {
+                char c = charAt(end - 1);
+
+                if (c != '\n') return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Remove the specified markup object from the buffer.
      */
@@ -816,6 +844,25 @@
      */
     @SuppressWarnings("unchecked")
     public <T> T[] getSpans(int queryStart, int queryEnd, @Nullable Class<T> kind) {
+        return getSpans(queryStart, queryEnd, kind, true);
+    }
+
+    /**
+     * Return an array of the spans of the specified type that overlap
+     * the specified range of the buffer.  The kind may be Object.class to get
+     * a list of all the spans regardless of type.
+     *
+     * @param queryStart Start index.
+     * @param queryEnd End index.
+     * @param kind Class type to search for.
+     * @param sort If true the results are sorted by the insertion order.
+     * @param <T>
+     * @return Array of the spans. Empty array if no results are found.
+     *
+     * @hide
+     */
+    public <T> T[] getSpans(int queryStart, int queryEnd, @Nullable Class<T> kind,
+                                 boolean sort) {
         if (kind == null) return (T[]) ArrayUtils.emptyArray(Object.class);
         if (mSpanCount == 0) return ArrayUtils.emptyArray(kind);
         int count = countSpans(queryStart, queryEnd, kind, treeRoot());
@@ -825,7 +872,13 @@
 
         // Safe conversion, but requires a suppressWarning
         T[] ret = (T[]) Array.newInstance(kind, count);
-        getSpansRec(queryStart, queryEnd, kind, treeRoot(), ret, 0);
+        if (sort) {
+            mPrioSortBuffer = checkSortBuffer(mPrioSortBuffer, count);
+            mOrderSortBuffer = checkSortBuffer(mOrderSortBuffer, count);
+        }
+        getSpansRec(queryStart, queryEnd, kind, treeRoot(), ret, mPrioSortBuffer,
+                mOrderSortBuffer, 0, sort);
+        if (sort) sort(ret, mPrioSortBuffer, mOrderSortBuffer);
         return ret;
     }
 
@@ -855,7 +908,7 @@
                 if (spanEnd >= queryStart &&
                     (spanStart == spanEnd || queryStart == queryEnd ||
                         (spanStart != queryEnd && spanEnd != queryStart)) &&
-                        kind.isInstance(mSpans[i])) {
+                        (Object.class == kind || kind.isInstance(mSpans[i]))) {
                     count++;
                 }
                 if ((i & 1) != 0) {
@@ -866,9 +919,25 @@
         return count;
     }
 
+    /**
+     * Fills the result array with the spans found under the current interval tree node.
+     *
+     * @param queryStart Start index for the interval query.
+     * @param queryEnd End index for the interval query.
+     * @param kind Class type to search for.
+     * @param i Index of the current tree node.
+     * @param ret Array to be filled with results.
+     * @param priority Buffer to keep record of the priorities of spans found.
+     * @param insertionOrder Buffer to keep record of the insertion orders of spans found.
+     * @param count The number of found spans.
+     * @param sort Flag to fill the priority and insertion order buffers. If false then
+     *             the spans with priority flag will be sorted in the result array.
+     * @param <T>
+     * @return The total number of spans found.
+     */
     @SuppressWarnings("unchecked")
     private <T> int getSpansRec(int queryStart, int queryEnd, Class<T> kind,
-            int i, T[] ret, int count) {
+            int i, T[] ret, int[] priority, int[] insertionOrder, int count, boolean sort) {
         if ((i & 1) != 0) {
             // internal tree node
             int left = leftChild(i);
@@ -877,7 +946,8 @@
                 spanMax -= mGapLength;
             }
             if (spanMax >= queryStart) {
-                count = getSpansRec(queryStart, queryEnd, kind, left, ret, count);
+                count = getSpansRec(queryStart, queryEnd, kind, left, ret, priority,
+                        insertionOrder, count, sort);
             }
         }
         if (i >= mSpanCount) return count;
@@ -893,36 +963,138 @@
             if (spanEnd >= queryStart &&
                     (spanStart == spanEnd || queryStart == queryEnd ||
                         (spanStart != queryEnd && spanEnd != queryStart)) &&
-                        kind.isInstance(mSpans[i])) {
-                int prio = mSpanFlags[i] & SPAN_PRIORITY;
-                if (prio != 0) {
-                    int j;
-
-                    for (j = 0; j < count; j++) {
+                        (Object.class == kind || kind.isInstance(mSpans[i]))) {
+                int spanPriority = mSpanFlags[i] & SPAN_PRIORITY;
+                int target = count;
+                if (sort) {
+                    priority[target] = spanPriority;
+                    insertionOrder[target] = mSpanOrder[i];
+                } else if (spanPriority != 0) {
+                    //insertion sort for elements with priority
+                    int j = 0;
+                    for (; j < count; j++) {
                         int p = getSpanFlags(ret[j]) & SPAN_PRIORITY;
-
-                        if (prio > p) {
-                            break;
-                        }
+                        if (spanPriority > p) break;
                     }
-
                     System.arraycopy(ret, j, ret, j + 1, count - j);
-                    // Safe conversion thanks to the isInstance test above
-                    ret[j] = (T) mSpans[i];
-                } else {
-                    // Safe conversion thanks to the isInstance test above
-                    ret[count] = (T) mSpans[i];
+                    target = j;
                 }
+                ret[target] = (T) mSpans[i];
                 count++;
             }
             if (count < ret.length && (i & 1) != 0) {
-                count = getSpansRec(queryStart, queryEnd, kind, rightChild(i), ret, count);
+                count = getSpansRec(queryStart, queryEnd, kind, rightChild(i), ret, priority,
+                        insertionOrder, count, sort);
             }
         }
         return count;
     }
 
     /**
+     * Check the size of the buffer and grow if required.
+     *
+     * @param buffer Buffer to be checked.
+     * @param size Required size.
+     * @return Same buffer instance if the current size is greater than required size. Otherwise a
+     * new instance is created and returned.
+     */
+    private final int[] checkSortBuffer(int[] buffer, int size) {
+        if(size > buffer.length) {
+            return ArrayUtils.newUnpaddedIntArray(GrowingArrayUtils.growSize(size));
+        }
+        return buffer;
+    }
+
+    /**
+     * An iterative heap sort implementation. It will sort the spans using first their priority
+     * then insertion order. A span with higher priority will be before a span with lower
+     * priority. If priorities are the same, the spans will be sorted with insertion order. A
+     * span with a lower insertion order will be before a span with a higher insertion order.
+     *
+     * @param array Span array to be sorted.
+     * @param priority Priorities of the spans
+     * @param insertionOrder Insertion orders of the spans
+     * @param <T> Span object type.
+     * @param <T>
+     */
+    private final <T> void sort(T[] array, int[] priority, int[] insertionOrder) {
+        int size = array.length;
+        for (int i = size / 2 - 1; i >= 0; i--) {
+            siftDown(i, array, size, priority, insertionOrder);
+        }
+
+        for (int i = size - 1; i > 0; i--) {
+            T v = array[0];
+            int prio = priority[0];
+            int insertOrder = insertionOrder[0];
+            array[0] = array[i];
+            priority[0] = priority[i];
+            insertionOrder[0] = insertionOrder[i];
+            siftDown(0, array, i, priority, insertionOrder);
+            array[i] = v;
+            priority[i] = prio;
+            insertionOrder[i] = insertOrder;
+        }
+    }
+
+    /**
+     * Helper function for heap sort.
+     *
+     * @param index Index of the element to sift down.
+     * @param array Span array to be sorted.
+     * @param size Current heap size.
+     * @param priority Priorities of the spans
+     * @param insertionOrder Insertion orders of the spans
+     * @param <T> Span object type.
+     */
+    private final <T> void siftDown(int index, T[] array, int size, int[] priority,
+                                    int[] insertionOrder) {
+        T v = array[index];
+        int prio = priority[index];
+        int insertOrder = insertionOrder[index];
+
+        int left = 2 * index + 1;
+        while (left < size) {
+            if (left < size - 1 && compareSpans(left, left + 1, priority, insertionOrder) < 0) {
+                left++;
+            }
+            if (compareSpans(index, left, priority, insertionOrder) >= 0) {
+                break;
+            }
+            array[index] = array[left];
+            priority[index] = priority[left];
+            insertionOrder[index] = insertionOrder[left];
+            index = left;
+            left = 2 * index + 1;
+        }
+        array[index] = v;
+        priority[index] = prio;
+        insertionOrder[index] = insertOrder;
+    }
+
+    /**
+     * Compare two span elements in an array. Comparison is based first on the priority flag of
+     * the span, and then the insertion order of the span.
+     *
+     * @param left Index of the element to compare.
+     * @param right Index of the other element to compare.
+     * @param priority Priorities of the spans
+     * @param insertionOrder Insertion orders of the spans
+     * @return
+     */
+    private final int compareSpans(int left, int right, int[] priority,
+                                       int[] insertionOrder) {
+        int priority1 = priority[left];
+        int priority2 = priority[right];
+        if (priority1 == priority2) {
+            return Integer.compare(insertionOrder[left], insertionOrder[right]);
+        }
+        // since high priority has to be before a lower priority, the arguments to compare are
+        // opposite of the insertion order check.
+        return Integer.compare(priority2, priority1);
+    }
+
+    /**
      * Return the next offset after <code>start</code> but less than or
      * equal to <code>limit</code> where a span of the specified type
      * begins or ends.
@@ -1488,18 +1660,21 @@
                 int start = mSpanStarts[i];
                 int end = mSpanEnds[i];
                 int flags = mSpanFlags[i];
+                int insertionOrder = mSpanOrder[i];
                 int j = i;
                 do {
                     mSpans[j] = mSpans[j - 1];
                     mSpanStarts[j] = mSpanStarts[j - 1];
                     mSpanEnds[j] = mSpanEnds[j - 1];
                     mSpanFlags[j] = mSpanFlags[j - 1];
+                    mSpanOrder[j] = mSpanOrder[j - 1];
                     j--;
                 } while (j > 0 && start < mSpanStarts[j - 1]);
                 mSpans[j] = span;
                 mSpanStarts[j] = start;
                 mSpanEnds[j] = end;
                 mSpanFlags[j] = flags;
+                mSpanOrder[j] = insertionOrder;
                 invalidateIndex(j);
             }
         }
@@ -1537,6 +1712,11 @@
     private int[] mSpanEnds;
     private int[] mSpanMax;  // see calcMax() for an explanation of what this array stores
     private int[] mSpanFlags;
+    private int[] mSpanOrder;  // store the order of span insertion
+    private int mSpanInsertCount;  // counter for the span insertion
+    private int[] mPrioSortBuffer;  // buffer used to sort getSpans result
+    private int[] mOrderSortBuffer;  // buffer used to sort getSpans result
+
     private int mSpanCount;
     private IdentityHashMap<Object, Integer> mIndexOfSpan;
     private int mLowWaterMark;  // indices below this have not been touched
diff --git a/core/java/android/text/SpannableStringInternal.java b/core/java/android/text/SpannableStringInternal.java
index 5c5deb4..47e71be 100644
--- a/core/java/android/text/SpannableStringInternal.java
+++ b/core/java/android/text/SpannableStringInternal.java
@@ -36,24 +36,99 @@
         mSpanData = EmptyArray.INT;
 
         if (source instanceof Spanned) {
-            Spanned sp = (Spanned) source;
-            Object[] spans = sp.getSpans(start, end, Object.class);
-
-            for (int i = 0; i < spans.length; i++) {
-                int st = sp.getSpanStart(spans[i]);
-                int en = sp.getSpanEnd(spans[i]);
-                int fl = sp.getSpanFlags(spans[i]);
-
-                if (st < start)
-                    st = start;
-                if (en > end)
-                    en = end;
-
-                setSpan(spans[i], st - start, en - start, fl);
+            if (source instanceof SpannableStringInternal) {
+                copySpans((SpannableStringInternal) source, start, end);
+            } else {
+                copySpans((Spanned) source, start, end);
             }
         }
     }
 
+    /**
+     * Copies another {@link Spanned} object's spans between [start, end] into this object.
+     *
+     * @param src Source object to copy from.
+     * @param start Start index in the source object.
+     * @param end End index in the source object.
+     */
+    private final void copySpans(Spanned src, int start, int end) {
+        Object[] spans = src.getSpans(start, end, Object.class);
+
+        for (int i = 0; i < spans.length; i++) {
+            int st = src.getSpanStart(spans[i]);
+            int en = src.getSpanEnd(spans[i]);
+            int fl = src.getSpanFlags(spans[i]);
+
+            if (st < start)
+                st = start;
+            if (en > end)
+                en = end;
+
+            setSpan(spans[i], st - start, en - start, fl);
+        }
+    }
+
+    /**
+     * Copies a {@link SpannableStringInternal} object's spans between [start, end] into this
+     * object.
+     *
+     * @param src Source object to copy from.
+     * @param start Start index in the source object.
+     * @param end End index in the source object.
+     */
+    private final void copySpans(SpannableStringInternal src, int start, int end) {
+        if (start == 0 && end == src.length()) {
+            mSpans = ArrayUtils.newUnpaddedObjectArray(src.mSpans.length);
+            mSpanData = new int[src.mSpanData.length];
+            mSpanCount = src.mSpanCount;
+            System.arraycopy(src.mSpans, 0, mSpans, 0, src.mSpans.length);
+            System.arraycopy(src.mSpanData, 0, mSpanData, 0, mSpanData.length);
+        } else {
+            int count = 0;
+            int[] srcData = src.mSpanData;
+            int limit = src.mSpanCount;
+            for (int i = 0; i < limit; i++) {
+                int spanStart = srcData[i * COLUMNS + START];
+                int spanEnd = srcData[i * COLUMNS + END];
+                if (isOutOfCopyRange(start, end, spanStart, spanEnd)) continue;
+                count++;
+            }
+
+            if (count == 0) return;
+
+            Object[] srcSpans = src.mSpans;
+            mSpanCount = count;
+            mSpans = ArrayUtils.newUnpaddedObjectArray(mSpanCount);
+            mSpanData = new int[mSpanCount * COLUMNS];
+            for (int i = 0, j = 0; i < limit; i++) {
+                int spanStart = srcData[i * COLUMNS + START];
+                int spanEnd = srcData[i * COLUMNS + END];
+                if (isOutOfCopyRange(start, end, spanStart, spanEnd)) continue;
+                if (spanStart < start) spanStart = start;
+                if (spanEnd > end) spanEnd = end;
+
+                mSpans[j] = srcSpans[i];
+                mSpanData[j * COLUMNS + START] = spanStart - start;
+                mSpanData[j * COLUMNS + END] = spanEnd - start;
+                mSpanData[j * COLUMNS + FLAGS] = srcData[i * COLUMNS + FLAGS];
+                j++;
+            }
+        }
+    }
+
+    /**
+     * Checks if [spanStart, spanEnd] interval is excluded from [start, end].
+     *
+     * @return True if excluded, false if included.
+     */
+    private final boolean isOutOfCopyRange(int start, int end, int spanStart, int spanEnd) {
+        if (spanStart > end || spanEnd < start) return true;
+        if (spanStart != spanEnd && start != end) {
+            if (spanStart == end || spanEnd == start) return true;
+        }
+        return false;
+    }
+
     public final int length() {
         return mText.length();
     }
@@ -234,7 +309,7 @@
             }
 
             // verify span class as late as possible, since it is expensive
-            if (kind != null && !kind.isInstance(spans[i])) {
+            if (kind != null && kind != Object.class && !kind.isInstance(spans[i])) {
                 continue;
             }
 
diff --git a/core/java/android/text/Spanned.java b/core/java/android/text/Spanned.java
index a785d1b..a0d54c2 100644
--- a/core/java/android/text/Spanned.java
+++ b/core/java/android/text/Spanned.java
@@ -81,7 +81,9 @@
      * immediately after a \n character, and if the \n
      * that anchors it is deleted, the endpoint is pulled to the
      * next \n that follows in the buffer (or to the end of
-     * the buffer).
+     * the buffer). If a span with SPAN_PARAGRAPH flag is pasted
+     * into another text and the paragraph boundary constraint
+     * is not satisfied, the span is discarded.
      */
     public static final int SPAN_PARAGRAPH =   0x33;
 
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index c42c791..2a52961 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -688,13 +688,14 @@
      * @param bottom the bottom of the line
      * @param fmi receives metrics information, can be null
      * @param needWidth true if the width of the run is needed
+     * @param offset the offset for the purpose of measuring
      * @return the signed width of the run based on the run direction; only
      * valid if needWidth is true
      */
     private float handleText(TextPaint wp, int start, int end,
             int contextStart, int contextEnd, boolean runIsRtl,
             Canvas c, float x, int top, int y, int bottom,
-            FontMetricsInt fmi, boolean needWidth) {
+            FontMetricsInt fmi, boolean needWidth, int offset) {
 
         // Get metrics first (even for empty strings or "0" width runs)
         if (fmi != null) {
@@ -712,11 +713,11 @@
         if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) {
             if (mCharsValid) {
                 ret = wp.getRunAdvance(mChars, start, end, contextStart, contextEnd,
-                        runIsRtl, end);
+                        runIsRtl, offset);
             } else {
                 int delta = mStart;
                 ret = wp.getRunAdvance(mText, delta + start, delta + end,
-                        delta + contextStart, delta + contextEnd, runIsRtl, delta + end);
+                        delta + contextStart, delta + contextEnd, runIsRtl, delta + offset);
             }
         }
 
@@ -865,8 +866,8 @@
             TextPaint wp = mWorkPaint;
             wp.set(mPaint);
             final int mlimit = measureLimit;
-            return handleText(wp, start, mlimit, start, limit, runIsRtl, c, x, top,
-                    y, bottom, fmi, needWidth || mlimit < measureLimit);
+            return handleText(wp, start, limit, start, limit, runIsRtl, c, x, top,
+                    y, bottom, fmi, needWidth || mlimit < measureLimit, mlimit);
         }
 
         mMetricAffectingSpanSpanSet.init(mSpanned, mStart + start, mStart + limit);
@@ -910,13 +911,14 @@
             }
 
             for (int j = i, jnext; j < mlimit; j = jnext) {
-                jnext = mCharacterStyleSpanSet.getNextTransition(mStart + j, mStart + mlimit) -
+                jnext = mCharacterStyleSpanSet.getNextTransition(mStart + j, mStart + inext) -
                         mStart;
+                int offset = Math.min(jnext, mlimit);
 
                 wp.set(mPaint);
                 for (int k = 0; k < mCharacterStyleSpanSet.numberOfSpans; k++) {
                     // Intentionally using >= and <= as explained above
-                    if ((mCharacterStyleSpanSet.spanStarts[k] >= mStart + jnext) ||
+                    if ((mCharacterStyleSpanSet.spanStarts[k] >= mStart + offset) ||
                             (mCharacterStyleSpanSet.spanEnds[k] <= mStart + j)) continue;
 
                     CharacterStyle span = mCharacterStyleSpanSet.spans[k];
@@ -928,7 +930,7 @@
                     wp.setHyphenEdit(0);
                 }
                 x += handleText(wp, j, jnext, i, inext, runIsRtl, c, x,
-                        top, y, bottom, fmi, needWidth || jnext < measureLimit);
+                        top, y, bottom, fmi, needWidth || jnext < measureLimit, offset);
             }
         }
 
diff --git a/core/java/android/text/method/Touch.java b/core/java/android/text/method/Touch.java
index d9068dc..44811cb 100644
--- a/core/java/android/text/method/Touch.java
+++ b/core/java/android/text/method/Touch.java
@@ -150,6 +150,7 @@
                     ds[0].mX = event.getX();
                     ds[0].mY = event.getY();
 
+                    int nx = widget.getScrollX() + (int) dx;
                     int ny = widget.getScrollY() + (int) dy;
 
                     int padding = widget.getTotalPaddingTop() + widget.getTotalPaddingBottom();
@@ -161,6 +162,8 @@
                     int oldX = widget.getScrollX();
                     int oldY = widget.getScrollY();
 
+                    scrollTo(widget, layout, nx, ny);
+
                     // If we actually scrolled, then cancel the up action.
                     if (oldX != widget.getScrollX() || oldY != widget.getScrollY()) {
                         widget.cancelLongPress();
diff --git a/core/java/android/text/style/LocaleSpan.java b/core/java/android/text/style/LocaleSpan.java
index d286231..117de774 100644
--- a/core/java/android/text/style/LocaleSpan.java
+++ b/core/java/android/text/style/LocaleSpan.java
@@ -16,30 +16,56 @@
 
 package android.text.style;
 
+import com.android.internal.util.Preconditions;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.graphics.Paint;
 import android.os.Parcel;
 import android.text.ParcelableSpan;
 import android.text.TextPaint;
 import android.text.TextUtils;
+import android.util.LocaleList;
+
 import java.util.Locale;
 
 /**
  * Changes the {@link Locale} of the text to which the span is attached.
  */
 public class LocaleSpan extends MetricAffectingSpan implements ParcelableSpan {
-    private final Locale mLocale;
+    @NonNull
+    private final LocaleList mLocales;
 
     /**
-     * Creates a LocaleSpan.
-     * @param locale The {@link Locale} of the text to which the span is
-     * attached.
+     * Creates a {@link LocaleSpan} from a well-formed {@link Locale}.  Note that only
+     * {@link Locale} objects that can be created by {@link Locale#forLanguageTag(String)} are
+     * supported.
+     *
+     * <p><b>Caveat:</b> Do not specify any {@link Locale} object that cannot be created by
+     * {@link Locale#forLanguageTag(String)}.  {@code new Locale(" a ", " b c", " d")} is an
+     * example of such a malformed {@link Locale} object.</p>
+     *
+     * @param locale The {@link Locale} of the text to which the span is attached.
+     *
+     * @see #LocaleSpan(LocaleList)
      */
-    public LocaleSpan(Locale locale) {
-        mLocale = locale;
+    public LocaleSpan(@Nullable Locale locale) {
+        mLocales = new LocaleList(locale);
     }
 
-    public LocaleSpan(Parcel src) {
-        mLocale = new Locale(src.readString(), src.readString(), src.readString());
+    /**
+     * Creates a {@link LocaleSpan} from {@link LocaleList}.
+     *
+     * @param locales The {@link LocaleList} of the text to which the span is attached.
+     * @throws NullPointerException if {@code locales} is null
+     */
+    public LocaleSpan(@NonNull LocaleList locales) {
+        Preconditions.checkNotNull(locales, "locales cannot be null");
+        mLocales = locales;
+    }
+
+    public LocaleSpan(Parcel source) {
+        mLocales = LocaleList.CREATOR.createFromParcel(source);
     }
 
     @Override
@@ -64,31 +90,40 @@
 
     /** @hide */
     public void writeToParcelInternal(Parcel dest, int flags) {
-        dest.writeString(mLocale.getLanguage());
-        dest.writeString(mLocale.getCountry());
-        dest.writeString(mLocale.getVariant());
+        mLocales.writeToParcel(dest, flags);
     }
 
     /**
-     * Returns the {@link Locale}.
+     * @return The {@link Locale} for this span.  If multiple locales are associated with this
+     * span, only the first locale is returned.  {@code null} if no {@link Locale} is specified.
      *
-     * @return The {@link Locale} for this span.
+     * @see LocaleList#getPrimary()
+     * @see #getLocales()
      */
+    @Nullable
     public Locale getLocale() {
-        return mLocale;
+        return mLocales.getPrimary();
+    }
+
+    /**
+     * @return The entire list of locales that are associated with this span.
+     */
+    @NonNull
+    public LocaleList getLocales() {
+        return mLocales;
     }
 
     @Override
     public void updateDrawState(TextPaint ds) {
-        apply(ds, mLocale);
+        apply(ds, mLocales);
     }
 
     @Override
     public void updateMeasureState(TextPaint paint) {
-        apply(paint, mLocale);
+        apply(paint, mLocales);
     }
 
-    private static void apply(Paint paint, Locale locale) {
-        paint.setTextLocale(locale);
+    private static void apply(@NonNull Paint paint, @NonNull LocaleList locales) {
+        paint.setTextLocales(locales);
     }
 }
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 6b449f9..1b00db2 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -16,6 +16,8 @@
 
 package android.text.style;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.TypedArray;
@@ -84,7 +86,15 @@
 
     private int mFlags;
     private final String[] mSuggestions;
-    private final String mLocaleString;
+    /**
+     * Kept for compatibility for apps that rely on invalid locale strings e.g.
+     * {@code new Locale(" an ", " i n v a l i d ", "data")}, which cannot be handled by
+     * {@link #mLanguageTag}.
+     */
+    @NonNull
+    private final String mLocaleStringForCompatibility;
+    @NonNull
+    private final String mLanguageTag;
     private final String mNotificationTargetClassName;
     private final String mNotificationTargetPackageName;
     private final int mHashCode;
@@ -130,14 +140,18 @@
         final int N = Math.min(SUGGESTIONS_MAX_SIZE, suggestions.length);
         mSuggestions = Arrays.copyOf(suggestions, N);
         mFlags = flags;
+        final Locale sourceLocale;
         if (locale != null) {
-            mLocaleString = locale.toString();
+            sourceLocale = locale;
         } else if (context != null) {
-            mLocaleString = context.getResources().getConfiguration().locale.toString();
+            // TODO: Consider to context.getResources().getResolvedLocale() instead.
+            sourceLocale = context.getResources().getConfiguration().locale;
         } else {
             Log.e("SuggestionSpan", "No locale or context specified in SuggestionSpan constructor");
-            mLocaleString = "";
+            sourceLocale = null;
         }
+        mLocaleStringForCompatibility = sourceLocale == null ? "" : sourceLocale.toString();
+        mLanguageTag = sourceLocale == null ? "" : sourceLocale.toLanguageTag();
 
         if (context != null) {
             mNotificationTargetPackageName = context.getPackageName();
@@ -150,7 +164,8 @@
         } else {
             mNotificationTargetClassName = "";
         }
-        mHashCode = hashCodeInternal(mSuggestions, mLocaleString, mNotificationTargetClassName);
+        mHashCode = hashCodeInternal(mSuggestions, mLanguageTag, mLocaleStringForCompatibility,
+                mNotificationTargetClassName);
 
         initStyle(context);
     }
@@ -194,7 +209,8 @@
     public SuggestionSpan(Parcel src) {
         mSuggestions = src.readStringArray();
         mFlags = src.readInt();
-        mLocaleString = src.readString();
+        mLocaleStringForCompatibility = src.readString();
+        mLanguageTag = src.readString();
         mNotificationTargetClassName = src.readString();
         mNotificationTargetPackageName = src.readString();
         mHashCode = src.readInt();
@@ -214,10 +230,29 @@
     }
 
     /**
-     * @return the locale of the suggestions
+     * @deprecated use {@link #getLocaleObject()} instead.
+     * @return the locale of the suggestions. An empty string is returned if no locale is specified.
      */
+    @NonNull
+    @Deprecated
     public String getLocale() {
-        return mLocaleString;
+        return mLocaleStringForCompatibility;
+    }
+
+    /**
+     * Returns a well-formed BCP 47 language tag representation of the suggestions, as a
+     * {@link Locale} object.
+     *
+     * <p><b>Caveat</b>: The returned object is guaranteed to be a  a well-formed BCP 47 language tag
+     * representation.  For example, this method can return an empty locale rather than returning a
+     * malformed data when this object is initialized with an malformed {@link Locale} object, e.g.
+     * {@code new Locale(" a ", " b c d ", " "}.</p>
+     *
+     * @return the locale of the suggestions. {@code null} is returned if no locale is specified.
+     */
+    @Nullable
+    public Locale getLocaleObject() {
+        return mLanguageTag.isEmpty() ? null : Locale.forLanguageTag(mLanguageTag);
     }
 
     /**
@@ -255,7 +290,8 @@
     public void writeToParcelInternal(Parcel dest, int flags) {
         dest.writeStringArray(mSuggestions);
         dest.writeInt(mFlags);
-        dest.writeString(mLocaleString);
+        dest.writeString(mLocaleStringForCompatibility);
+        dest.writeString(mLanguageTag);
         dest.writeString(mNotificationTargetClassName);
         dest.writeString(mNotificationTargetPackageName);
         dest.writeInt(mHashCode);
@@ -290,10 +326,10 @@
         return mHashCode;
     }
 
-    private static int hashCodeInternal(String[] suggestions, String locale,
-            String notificationTargetClassName) {
+    private static int hashCodeInternal(String[] suggestions, @NonNull String languageTag,
+            @NonNull String localeStringForCompatibility, String notificationTargetClassName) {
         return Arrays.hashCode(new Object[] {Long.valueOf(SystemClock.uptimeMillis()), suggestions,
-                locale, notificationTargetClassName});
+                languageTag, localeStringForCompatibility, notificationTargetClassName});
     }
 
     public static final Parcelable.Creator<SuggestionSpan> CREATOR =
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index c119277..fbd9924 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -218,7 +218,7 @@
         ArrayList<LinkSpec> links = new ArrayList<LinkSpec>();
 
         if ((mask & WEB_URLS) != 0) {
-            gatherLinks(links, text, Patterns.WEB_URL,
+            gatherLinks(links, text, Patterns.AUTOLINK_WEB_URL,
                 new String[] { "http://", "https://", "rtsp://" },
                 sUrlMatchFilter, null);
         }
diff --git a/core/java/android/transition/SidePropagation.java b/core/java/android/transition/SidePropagation.java
index b10f6a0..817541c 100644
--- a/core/java/android/transition/SidePropagation.java
+++ b/core/java/android/transition/SidePropagation.java
@@ -16,6 +16,7 @@
 package android.transition;
 
 import android.graphics.Rect;
+import android.transition.Slide.GravityFlag;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
@@ -45,7 +46,7 @@
      *             {@link Gravity#LEFT}, {@link Gravity#TOP}, {@link Gravity#RIGHT},
      *             {@link Gravity#BOTTOM}, {@link Gravity#START}, or {@link Gravity#END}.
      */
-    public void setSide(int side) {
+    public void setSide(@GravityFlag int side) {
         mSide = side;
     }
 
diff --git a/core/java/android/transition/Slide.java b/core/java/android/transition/Slide.java
index 9063b43..9af65e4 100644
--- a/core/java/android/transition/Slide.java
+++ b/core/java/android/transition/Slide.java
@@ -17,6 +17,7 @@
 
 import android.animation.Animator;
 import android.animation.TimeInterpolator;
+import android.annotation.IntDef;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
@@ -27,6 +28,9 @@
 import android.view.animation.DecelerateInterpolator;
 import com.android.internal.R;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * This transition tracks changes to the visibility of target views in the
  * start and end scenes and moves views in or out from one of the edges of the
@@ -42,7 +46,12 @@
     private static final TimeInterpolator sAccelerate = new AccelerateInterpolator();
     private static final String PROPNAME_SCREEN_POSITION = "android:slide:screenPosition";
     private CalculateSlide mSlideCalculator = sCalculateBottom;
-    private int mSlideEdge = Gravity.BOTTOM;
+    private @GravityFlag int mSlideEdge = Gravity.BOTTOM;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({Gravity.LEFT, Gravity.TOP, Gravity.RIGHT, Gravity.BOTTOM, Gravity.START, Gravity.END})
+    public @interface GravityFlag {}
 
     private interface CalculateSlide {
 
@@ -176,7 +185,7 @@
      *                  {@link android.view.Gravity#START}, {@link android.view.Gravity#END}.
      * @attr ref android.R.styleable#Slide_slideEdge
      */
-    public void setSlideEdge(int slideEdge) {
+    public void setSlideEdge(@GravityFlag int slideEdge) {
         switch (slideEdge) {
             case Gravity.LEFT:
                 mSlideCalculator = sCalculateLeft;
@@ -214,6 +223,7 @@
      *         {@link android.view.Gravity#START}, {@link android.view.Gravity#END}.
      * @attr ref android.R.styleable#Slide_slideEdge
      */
+    @GravityFlag
     public int getSlideEdge() {
         return mSlideEdge;
     }
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index e711812..eb95a02 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -16,17 +16,21 @@
 
 package android.transition;
 
-import com.android.internal.R;
-
 import android.animation.Animator;
 import android.animation.Animator.AnimatorListener;
 import android.animation.Animator.AnimatorPauseListener;
+import android.annotation.IntDef;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.android.internal.R;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * This transition tracks changes to the visibility of target views in the
  * start and end scenes. Visibility is determined not just by the
@@ -46,6 +50,11 @@
     private static final String PROPNAME_PARENT = "android:visibility:parent";
     private static final String PROPNAME_SCREEN_LOCATION = "android:visibility:screenLocation";
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag=true, value={MODE_IN, MODE_OUT})
+    @interface VisibilityMode {}
+
     /**
      * Mode used in {@link #setMode(int)} to make the transition
      * operate on targets that are appearing. Maybe be combined with
@@ -99,7 +108,7 @@
      *             {@link #MODE_IN} and {@link #MODE_OUT}.
      * @attr ref android.R.styleable#VisibilityTransition_transitionVisibilityMode
      */
-    public void setMode(int mode) {
+    public void setMode(@VisibilityMode int mode) {
         if ((mode & ~(MODE_IN | MODE_OUT)) != 0) {
             throw new IllegalArgumentException("Only MODE_IN and MODE_OUT flags are allowed");
         }
@@ -113,6 +122,7 @@
      *         {@link #MODE_IN} and {@link #MODE_OUT}.
      * @attr ref android.R.styleable#VisibilityTransition_transitionVisibilityMode
      */
+    @VisibilityMode
     public int getMode() {
         return mMode;
     }
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index 6bda83d2..6196a97 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -23,6 +23,7 @@
 import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.regex.Matcher;
@@ -161,6 +162,17 @@
                 throw new IllegalArgumentException("Unknown entry type: " + type);
             }
         }
+
+        /** @hide */
+        public static Event fromBytes(byte[] data) {
+            return new Event(data);
+        }
+
+        /** @hide */
+        public byte[] getBytes() {
+            byte[] bytes = mBuffer.array();
+            return Arrays.copyOf(bytes, bytes.length);
+        }
     }
 
     // We assume that the native methods deal with any concurrency issues.
diff --git a/core/java/android/util/LocaleList.java b/core/java/android/util/LocaleList.java
index 1becfb4..90a20bc 100644
--- a/core/java/android/util/LocaleList.java
+++ b/core/java/android/util/LocaleList.java
@@ -16,6 +16,7 @@
 
 package android.util;
 
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.Size;
@@ -25,15 +26,11 @@
 
 import com.android.internal.annotations.GuardedBy;
 
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.Locale;
 
-// TODO: We don't except too many LocaleLists to exist at the same time, and
-// we need access to the data at native level, so we should pass the data
-// down to the native level, create a map of every list seen there, take a
-// pointer back, and just keep that pointer in the Java-level object, so
-// things could be copied very quickly.
-
 /**
  * LocaleList is an immutable list of Locales, typically used to keep an
  * ordered user preferences for locales.
@@ -62,10 +59,21 @@
         return mList.length == 0;
     }
 
+    @IntRange(from=0)
     public int size() {
         return mList.length;
     }
 
+    @IntRange(from=-1)
+    public int indexOf(Locale locale) {
+        for (int i = 0; i < mList.length; i++) {
+            if (mList[i].equals(locale)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
     @Override
     public boolean equals(Object other) {
         if (other == this)
@@ -75,7 +83,7 @@
         final Locale[] otherList = ((LocaleList) other).mList;
         if (mList.length != otherList.length)
             return false;
-        for (int i = 0; i < mList.length; ++i) {
+        for (int i = 0; i < mList.length; i++) {
             if (!mList[i].equals(otherList[i]))
                 return false;
         }
@@ -85,7 +93,7 @@
     @Override
     public int hashCode() {
         int result = 1;
-        for (int i = 0; i < mList.length; ++i) {
+        for (int i = 0; i < mList.length; i++) {
             result = 31 * result + mList[i].hashCode();
         }
         return result;
@@ -95,7 +103,7 @@
     public String toString() {
         StringBuilder sb = new StringBuilder();
         sb.append("[");
-        for (int i = 0; i < mList.length; ++i) {
+        for (int i = 0; i < mList.length; i++) {
             sb.append(mList[i]);
             if (i < mList.length - 1) {
                 sb.append(',');
@@ -156,12 +164,12 @@
             final Locale[] localeList = new Locale[list.length];
             final HashSet<Locale> seenLocales = new HashSet<Locale>();
             final StringBuilder sb = new StringBuilder();
-            for (int i = 0; i < list.length; ++i) {
+            for (int i = 0; i < list.length; i++) {
                 final Locale l = list[i];
                 if (l == null) {
-                    throw new NullPointerException();
+                    throw new NullPointerException("list[" + i + "] is null");
                 } else if (seenLocales.contains(l)) {
-                    throw new IllegalArgumentException();
+                    throw new IllegalArgumentException("list[" + i + "] is a repetition");
                 } else {
                     final Locale localeClone = (Locale) l.clone();
                     localeList[i] = localeClone;
@@ -177,6 +185,55 @@
         }
     }
 
+    /**
+     * Constructs a locale list, with the topLocale moved to the front if it already is
+     * in otherLocales, or added to the front if it isn't.
+     *
+     * {@hide}
+     */
+    public LocaleList(@NonNull Locale topLocale, LocaleList otherLocales) {
+        if (topLocale == null) {
+            throw new NullPointerException("topLocale is null");
+        }
+
+        final int inputLength = (otherLocales == null) ? 0 : otherLocales.mList.length;
+        int topLocaleIndex = -1;
+        for (int i = 0; i < inputLength; i++) {
+            if (topLocale.equals(otherLocales.mList[i])) {
+                topLocaleIndex = i;
+                break;
+            }
+        }
+
+        final int outputLength = inputLength + (topLocaleIndex == -1 ? 1 : 0);
+        final Locale[] localeList = new Locale[outputLength];
+        localeList[0] = (Locale) topLocale.clone();
+        if (topLocaleIndex == -1) {
+            // topLocale was not in otherLocales
+            for (int i = 0; i < inputLength; i++) {
+                localeList[i + 1] = (Locale) otherLocales.mList[i].clone();
+            }
+        } else {
+            for (int i = 0; i < topLocaleIndex; i++) {
+                localeList[i + 1] = (Locale) otherLocales.mList[i].clone();
+            }
+            for (int i = topLocaleIndex + 1; i < inputLength; i++) {
+                localeList[i] = (Locale) otherLocales.mList[i].clone();
+            }
+        }
+
+        final StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < outputLength; i++) {
+            sb.append(localeList[i].toLanguageTag());
+            if (i < outputLength - 1) {
+                sb.append(',');
+            }
+        }
+
+        mList = localeList;
+        mStringRepresentation = sb.toString();
+    }
+
     public static final Parcelable.Creator<LocaleList> CREATOR
             = new Parcelable.Creator<LocaleList>() {
         @Override
@@ -202,7 +259,7 @@
         } else {
             final String[] tags = list.split(",");
             final Locale[] localeArray = new Locale[tags.length];
-            for (int i = 0; i < localeArray.length; ++i) {
+            for (int i = 0; i < localeArray.length; i++) {
                 localeArray[i] = Locale.forLanguageTag(tags[i]);
             }
             return new LocaleList(localeArray);
@@ -219,6 +276,21 @@
         }
     }
 
+    private static final String STRING_EN_XA = "en-XA";
+    private static final String STRING_AR_XB = "ar-XB";
+    private static final Locale LOCALE_EN_XA = new Locale("en", "XA");
+    private static final Locale LOCALE_AR_XB = new Locale("ar", "XB");
+    private static final int NUM_PSEUDO_LOCALES = 2;
+
+    private static boolean isPseudoLocale(String locale) {
+        return STRING_EN_XA.equals(locale) || STRING_AR_XB.equals(locale);
+    }
+
+    private static boolean isPseudoLocale(Locale locale) {
+        return LOCALE_EN_XA.equals(locale) || LOCALE_AR_XB.equals(locale);
+    }
+
+    @IntRange(from=0, to=1)
     private static int matchScore(Locale supported, Locale desired) {
         if (supported.equals(desired)) {
             return 1;  // return early so we don't do unnecessary computation
@@ -226,66 +298,239 @@
         if (!supported.getLanguage().equals(desired.getLanguage())) {
             return 0;
         }
+        if (isPseudoLocale(supported) || isPseudoLocale(desired)) {
+            // The locales are not the same, but the languages are the same, and one of the locales
+            // is a pseudo-locale. So this is not a match.
+            return 0;
+        }
+        final String supportedScr = getLikelyScript(supported);
+        if (supportedScr.isEmpty()) {
+            // If we can't guess a script, we don't know enough about the locales' language to find
+            // if the locales match. So we fall back to old behavior of matching, which considered
+            // locales with different regions different.
+            final String supportedRegion = supported.getCountry();
+            return (supportedRegion.isEmpty() ||
+                    supportedRegion.equals(desired.getCountry()))
+                    ? 1 : 0;
+        }
+        final String desiredScr = getLikelyScript(desired);
         // There is no match if the two locales use different scripts. This will most imporantly
         // take care of traditional vs simplified Chinese.
-        final String supportedScr = getLikelyScript(supported);
-        final String desiredScr = getLikelyScript(desired);
         return supportedScr.equals(desiredScr) ? 1 : 0;
     }
 
+    private int findFirstMatchIndex(Locale supportedLocale) {
+        for (int idx = 0; idx < mList.length; idx++) {
+            final int score = matchScore(supportedLocale, mList[idx]);
+            if (score > 0) {
+                return idx;
+            }
+        }
+        return Integer.MAX_VALUE;
+    }
+
+    private static final Locale EN_LATN = Locale.forLanguageTag("en-Latn");
+
+    private int computeFirstMatchIndex(Collection<String> supportedLocales,
+            boolean assumeEnglishIsSupported) {
+        if (mList.length == 1) {  // just one locale, perhaps the most common scenario
+            return 0;
+        }
+        if (mList.length == 0) {  // empty locale list
+            return -1;
+        }
+
+        int bestIndex = Integer.MAX_VALUE;
+        // Try English first, so we can return early if it's in the LocaleList
+        if (assumeEnglishIsSupported) {
+            final int idx = findFirstMatchIndex(EN_LATN);
+            if (idx == 0) { // We have a match on the first locale, which is good enough
+                return 0;
+            } else if (idx < bestIndex) {
+                bestIndex = idx;
+            }
+        }
+        for (String languageTag : supportedLocales) {
+            final Locale supportedLocale = Locale.forLanguageTag(languageTag);
+            // We expect the average length of locale lists used for locale resolution to be
+            // smaller than three, so it's OK to do this as an O(mn) algorithm.
+            final int idx = findFirstMatchIndex(supportedLocale);
+            if (idx == 0) { // We have a match on the first locale, which is good enough
+                return 0;
+            } else if (idx < bestIndex) {
+                bestIndex = idx;
+            }
+        }
+        if (bestIndex == Integer.MAX_VALUE) {
+            // no match was found, so we fall back to the first locale in the locale list
+            return 0;
+        } else {
+            return bestIndex;
+        }
+    }
+
+    private Locale computeFirstMatch(Collection<String> supportedLocales,
+            boolean assumeEnglishIsSupported) {
+        int bestIndex = computeFirstMatchIndex(supportedLocales, assumeEnglishIsSupported);
+        return bestIndex == -1 ? null : mList[bestIndex];
+    }
+
     /**
      * Returns the first match in the locale list given an unordered array of supported locales
-     * in BCP47 format.
+     * in BCP 47 format.
      *
      * If the locale list is empty, null would be returned.
      */
     @Nullable
     public Locale getFirstMatch(String[] supportedLocales) {
-        if (mList.length == 1) {  // just one locale, perhaps the most common scenario
-            return mList[0];
+        return computeFirstMatch(Arrays.asList(supportedLocales),
+                false /* assume English is not supported */);
+    }
+
+    /**
+     * Same as getFirstMatch(), but with English assumed to be supported, even if it's not.
+     * {@hide}
+     */
+    @Nullable
+    public Locale getFirstMatchWithEnglishSupported(String[] supportedLocales) {
+        return computeFirstMatch(Arrays.asList(supportedLocales),
+                true /* assume English is supported */);
+    }
+
+    /**
+     * {@hide}
+     */
+    public int getFirstMatchIndexWithEnglishSupported(Collection<String> supportedLocales) {
+        return computeFirstMatchIndex(supportedLocales, true /* assume English is supported */);
+    }
+
+    /**
+     * {@hide}
+     */
+    public int getFirstMatchIndexWithEnglishSupported(String[] supportedLocales) {
+        return getFirstMatchIndexWithEnglishSupported(Arrays.asList(supportedLocales));
+    }
+
+    /**
+     * Returns true if the collection of locale tags only contains empty locales and pseudolocales.
+     * Assumes that there is no repetition in the input.
+     * {@hide}
+     */
+    public static boolean isPseudoLocalesOnly(String[] supportedLocales) {
+        if (supportedLocales.length > NUM_PSEUDO_LOCALES + 1) {
+            // This is for optimization. Since there's no repetition in the input, if we have more
+            // than the number of pseudo-locales plus one for the empty string, it's guaranteed
+            // that we have some meaninful locale in the collection, so the list is not "practically
+            // empty".
+            return false;
         }
-        if (mList.length == 0) {  // empty locale list
-            return null;
-        }
-        // TODO: Figure out what to if en-XA or ar-XB are in the locale list
-        int bestIndex = Integer.MAX_VALUE;
-        for (String tag : supportedLocales) {
-            final Locale supportedLocale = Locale.forLanguageTag(tag);
-            // We expect the average length of locale lists used for locale resolution to be
-            // smaller than three, so it's OK to do this as an O(mn) algorithm.
-            for (int idx = 0; idx < mList.length; idx++) {
-                final int score = matchScore(supportedLocale, mList[idx]);
-                if (score > 0) {
-                    if (idx == 0) {  // We have a match on the first locale, which is good enough
-                        return mList[0];
-                    } else if (idx < bestIndex) {
-                        bestIndex = idx;
-                    }
-                }
+        for (String locale : supportedLocales) {
+            if (!locale.isEmpty() && !isPseudoLocale(locale)) {
+                return false;
             }
         }
-        if (bestIndex == Integer.MAX_VALUE) {  // no match was found
-            return mList[0];
-        } else {
-            return mList[bestIndex];
-        }
+        return true;
     }
 
     private final static Object sLock = new Object();
 
     @GuardedBy("sLock")
-    private static LocaleList sDefaultLocaleList;
+    private static LocaleList sLastExplicitlySetLocaleList = null;
+    @GuardedBy("sLock")
+    private static LocaleList sDefaultLocaleList = null;
+    @GuardedBy("sLock")
+    private static LocaleList sDefaultAdjustedLocaleList = null;
+    @GuardedBy("sLock")
+    private static Locale sLastDefaultLocale = null;
 
-    // TODO: fix this to return the default system locale list once we have that
+    /**
+     * The result is guaranteed to include the default Locale returned by Locale.getDefault(), but
+     * not necessarily at the top of the list. The default locale not being at the top of the list
+     * is an indication that the system has set the default locale to one of the user's other
+     * preferred locales, having concluded that the primary preference is not supported but a
+     * secondary preference is.
+     *
+     * Note that the default LocaleList would change if Locale.setDefault() is called. This method
+     * takes that into account by always checking the output of Locale.getDefault() and
+     * recalculating the default LocaleList if needed.
+     */
     @NonNull @Size(min=1)
     public static LocaleList getDefault() {
-        Locale defaultLocale = Locale.getDefault();
+        final Locale defaultLocale = Locale.getDefault();
         synchronized (sLock) {
-            if (sDefaultLocaleList == null || sDefaultLocaleList.size() != 1
-                    || !defaultLocale.equals(sDefaultLocaleList.getPrimary())) {
-                sDefaultLocaleList = new LocaleList(defaultLocale);
+            if (!defaultLocale.equals(sLastDefaultLocale)) {
+                sLastDefaultLocale = defaultLocale;
+                // It's either the first time someone has asked for the default locale list, or
+                // someone has called Locale.setDefault() since we last set or adjusted the default
+                // locale list. So let's recalculate the locale list.
+                if (sDefaultLocaleList != null
+                        && defaultLocale.equals(sDefaultLocaleList.getPrimary())) {
+                    // The default Locale has changed, but it happens to be the first locale in the
+                    // default locale list, so we don't need to construct a new locale list.
+                    return sDefaultLocaleList;
+                }
+                sDefaultLocaleList = new LocaleList(defaultLocale, sLastExplicitlySetLocaleList);
+                sDefaultAdjustedLocaleList = sDefaultLocaleList;
+            }
+            // sDefaultLocaleList can't be null, since it can't be set to null by
+            // LocaleList.setDefault(), and if getDefault() is called before a call to
+            // setDefault(), sLastDefaultLocale would be null and the check above would set
+            // sDefaultLocaleList.
+            return sDefaultLocaleList;
+        }
+    }
+
+    /**
+     * Returns the default locale list, adjusted by moving the default locale to its first
+     * position.
+     *
+     * {@hide}
+     */
+    @NonNull @Size(min=1)
+    public static LocaleList getAdjustedDefault() {
+        getDefault(); // to recalculate the default locale list, if necessary
+        synchronized (sLock) {
+            return sDefaultAdjustedLocaleList;
+        }
+    }
+
+    /**
+     * Also sets the default locale by calling Locale.setDefault() with the first locale in the
+     * list.
+     *
+     * @throws NullPointerException if the input is <code>null</code>.
+     * @throws IllegalArgumentException if the input is empty.
+     */
+    public static void setDefault(@NonNull @Size(min=1) LocaleList locales) {
+        setDefault(locales, 0);
+    }
+
+    /**
+     * This may be used directly by system processes to set the default locale list for apps. For
+     * such uses, the default locale list would always come from the user preferences, but the
+     * default locale may have been chosen to be a locale other than the first locale in the locale
+     * list (based on the locales the app supports).
+     *
+     * {@hide}
+     */
+    public static void setDefault(@NonNull @Size(min=1) LocaleList locales, int localeIndex) {
+        if (locales == null) {
+            throw new NullPointerException("locales is null");
+        }
+        if (locales.isEmpty()) {
+            throw new IllegalArgumentException("locales is empty");
+        }
+        synchronized (sLock) {
+            sLastDefaultLocale = locales.get(localeIndex);
+            Locale.setDefault(sLastDefaultLocale);
+            sLastExplicitlySetLocaleList = locales;
+            sDefaultLocaleList = locales;
+            if (localeIndex == 0) {
+                sDefaultAdjustedLocaleList = sDefaultLocaleList;
+            } else {
+                sDefaultAdjustedLocaleList = new LocaleList(
+                        sLastDefaultLocale, sDefaultLocaleList);
             }
         }
-        return sDefaultLocaleList;
     }
 }
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index fe41932..544444d 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -18,9 +18,11 @@
 
 import com.android.internal.os.RuntimeInit;
 import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.LineBreakBufferedWriter;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.io.Writer;
 import java.net.UnknownHostException;
 
 /**
@@ -126,7 +128,7 @@
      * @param tr An exception to log
      */
     public static int v(String tag, String msg, Throwable tr) {
-        return println_native(LOG_ID_MAIN, VERBOSE, tag, msg + '\n' + getStackTraceString(tr));
+        return printlns(LOG_ID_MAIN, VERBOSE, tag, msg, tr);
     }
 
     /**
@@ -147,7 +149,7 @@
      * @param tr An exception to log
      */
     public static int d(String tag, String msg, Throwable tr) {
-        return println_native(LOG_ID_MAIN, DEBUG, tag, msg + '\n' + getStackTraceString(tr));
+        return printlns(LOG_ID_MAIN, DEBUG, tag, msg, tr);
     }
 
     /**
@@ -168,7 +170,7 @@
      * @param tr An exception to log
      */
     public static int i(String tag, String msg, Throwable tr) {
-        return println_native(LOG_ID_MAIN, INFO, tag, msg + '\n' + getStackTraceString(tr));
+        return printlns(LOG_ID_MAIN, INFO, tag, msg, tr);
     }
 
     /**
@@ -189,7 +191,7 @@
      * @param tr An exception to log
      */
     public static int w(String tag, String msg, Throwable tr) {
-        return println_native(LOG_ID_MAIN, WARN, tag, msg + '\n' + getStackTraceString(tr));
+        return printlns(LOG_ID_MAIN, WARN, tag, msg, tr);
     }
 
     /**
@@ -219,7 +221,7 @@
      * @param tr An exception to log
      */
     public static int w(String tag, Throwable tr) {
-        return println_native(LOG_ID_MAIN, WARN, tag, getStackTraceString(tr));
+        return printlns(LOG_ID_MAIN, WARN, tag, "", tr);
     }
 
     /**
@@ -240,7 +242,7 @@
      * @param tr An exception to log
      */
     public static int e(String tag, String msg, Throwable tr) {
-        return println_native(LOG_ID_MAIN, ERROR, tag, msg + '\n' + getStackTraceString(tr));
+        return printlns(LOG_ID_MAIN, ERROR, tag, msg, tr);
     }
 
     /**
@@ -292,8 +294,7 @@
         // Only mark this as ERROR, do not use ASSERT since that should be
         // reserved for cases where the system is guaranteed to abort.
         // The onTerribleFailure call does not always cause a crash.
-        int bytes = println_native(logId, ERROR, tag, msg + '\n'
-                + getStackTraceString(localStack ? what : tr));
+        int bytes = printlns(logId, ERROR, tag, msg, localStack ? what : tr);
         sWtfHandler.onTerribleFailure(tag, what, system);
         return bytes;
     }
@@ -365,4 +366,107 @@
 
     /** @hide */ public static native int println_native(int bufID,
             int priority, String tag, String msg);
+
+    /**
+     * Return the maximum payload the log daemon accepts without truncation.
+     * @return LOGGER_ENTRY_MAX_PAYLOAD.
+     */
+    private static native int logger_entry_max_payload_native();
+
+    /**
+     * Helper function for long messages. Uses the LineBreakBufferedWriter to break
+     * up long messages and stacktraces along newlines, but tries to write in large
+     * chunks. This is to avoid truncation.
+     */
+    private static int printlns(int bufID, int priority, String tag, String msg,
+            Throwable tr) {
+        ImmediateLogWriter logWriter = new ImmediateLogWriter(bufID, priority, tag);
+        // Acceptable buffer size. Get the native buffer size, subtract two zero terminators,
+        // and the length of the tag.
+        // Note: we implicitly accept possible truncation for Modified-UTF8 differences. It
+        //       is too expensive to compute that ahead of time.
+        int bufferSize = NoPreloadHolder.LOGGER_ENTRY_MAX_PAYLOAD  // Base.
+                - 2                                                // Two terminators.
+                - (tag != null ? tag.length() : 0)                 // Tag length.
+                - 32;                                              // Some slack.
+        // At least assume you can print *some* characters (tag is not too large).
+        bufferSize = Math.max(bufferSize, 100);
+
+        LineBreakBufferedWriter lbbw = new LineBreakBufferedWriter(logWriter, bufferSize);
+
+        lbbw.println(msg);
+
+        if (tr != null) {
+            // This is to reduce the amount of log spew that apps do in the non-error
+            // condition of the network being unavailable.
+            Throwable t = tr;
+            while (t != null) {
+                if (t instanceof UnknownHostException) {
+                    break;
+                }
+                t = t.getCause();
+            }
+            if (t == null) {
+                tr.printStackTrace(lbbw);
+            }
+        }
+
+        lbbw.flush();
+
+        return logWriter.getWritten();
+    }
+
+    /**
+     * NoPreloadHelper class. Caches the LOGGER_ENTRY_MAX_PAYLOAD value to avoid
+     * a JNI call during logging.
+     */
+    static class NoPreloadHolder {
+        public final static int LOGGER_ENTRY_MAX_PAYLOAD =
+                logger_entry_max_payload_native();
+    }
+
+    /**
+     * Helper class to write to the logcat. Different from LogWriter, this writes
+     * the whole given buffer and does not break along newlines.
+     */
+    private static class ImmediateLogWriter extends Writer {
+
+        private int bufID;
+        private int priority;
+        private String tag;
+
+        private int written = 0;
+
+        /**
+         * Create a writer that immediately writes to the log, using the given
+         * parameters.
+         */
+        public ImmediateLogWriter(int bufID, int priority, String tag) {
+            this.bufID = bufID;
+            this.priority = priority;
+            this.tag = tag;
+        }
+
+        public int getWritten() {
+            return written;
+        }
+
+        @Override
+        public void write(char[] cbuf, int off, int len) {
+            // Note: using String here has a bit of overhead as a Java object is created,
+            //       but using the char[] directly is not easier, as it needs to be translated
+            //       to a C char[] for logging.
+            written += println_native(bufID, priority, tag, new String(cbuf, off, len));
+        }
+
+        @Override
+        public void flush() {
+            // Ignored.
+        }
+
+        @Override
+        public void close() {
+            // Ignored.
+        }
+    }
 }
diff --git a/core/java/android/util/PathParser.java b/core/java/android/util/PathParser.java
index f17a16c..78d5bcd 100644
--- a/core/java/android/util/PathParser.java
+++ b/core/java/android/util/PathParser.java
@@ -82,6 +82,10 @@
             }
         }
 
+        public long getNativePtr() {
+            return mNativePathData;
+        }
+
         /**
          * Update the path data to match the source.
          * Before calling this, make sure canMorph(target, source) is true.
diff --git a/core/java/android/util/Patterns.java b/core/java/android/util/Patterns.java
index 2cc91b9..9f2bcfd 100644
--- a/core/java/android/util/Patterns.java
+++ b/core/java/android/util/Patterns.java
@@ -109,11 +109,137 @@
         + "|z[amw]))";
 
     /**
-     * Good characters for Internationalized Resource Identifiers (IRI).
-     * This comprises most common used Unicode characters allowed in IRI
-     * as detailed in RFC 3987.
-     * Specifically, those two byte Unicode characters are not included.
+     *  Regular expression to match all IANA top-level domains.
+     *
+     *  List accurate as of 2015/11/24.  List taken from:
+     *  http://data.iana.org/TLD/tlds-alpha-by-domain.txt
+     *  This pattern is auto-generated by frameworks/ex/common/tools/make-iana-tld-pattern.py
+     *
+     *  @hide
      */
+    static final String IANA_TOP_LEVEL_DOMAINS =
+        "(?:"
+        + "(?:aaa|aarp|abb|abbott|abogado|academy|accenture|accountant|accountants|aco|active"
+        + "|actor|ads|adult|aeg|aero|afl|agency|aig|airforce|airtel|allfinanz|alsace|amica|amsterdam"
+        + "|android|apartments|app|apple|aquarelle|aramco|archi|army|arpa|arte|asia|associates"
+        + "|attorney|auction|audio|auto|autos|axa|azure|a[cdefgilmoqrstuwxz])"
+        + "|(?:band|bank|bar|barcelona|barclaycard|barclays|bargains|bauhaus|bayern|bbc|bbva"
+        + "|bcn|beats|beer|bentley|berlin|best|bet|bharti|bible|bid|bike|bing|bingo|bio|biz|black"
+        + "|blackfriday|bloomberg|blue|bms|bmw|bnl|bnpparibas|boats|bom|bond|boo|boots|boutique"
+        + "|bradesco|bridgestone|broadway|broker|brother|brussels|budapest|build|builders|business"
+        + "|buzz|bzh|b[abdefghijmnorstvwyz])"
+        + "|(?:cab|cafe|cal|camera|camp|cancerresearch|canon|capetown|capital|car|caravan|cards"
+        + "|care|career|careers|cars|cartier|casa|cash|casino|cat|catering|cba|cbn|ceb|center|ceo"
+        + "|cern|cfa|cfd|chanel|channel|chat|cheap|chloe|christmas|chrome|church|cipriani|cisco"
+        + "|citic|city|cityeats|claims|cleaning|click|clinic|clothing|cloud|club|clubmed|coach"
+        + "|codes|coffee|college|cologne|com|commbank|community|company|computer|comsec|condos"
+        + "|construction|consulting|contractors|cooking|cool|coop|corsica|country|coupons|courses"
+        + "|credit|creditcard|creditunion|cricket|crown|crs|cruises|csc|cuisinella|cymru|cyou|c[acdfghiklmnoruvwxyz])"
+        + "|(?:dabur|dad|dance|date|dating|datsun|day|dclk|deals|degree|delivery|dell|delta"
+        + "|democrat|dental|dentist|desi|design|dev|diamonds|diet|digital|direct|directory|discount"
+        + "|dnp|docs|dog|doha|domains|doosan|download|drive|durban|dvag|d[ejkmoz])"
+        + "|(?:earth|eat|edu|education|email|emerck|energy|engineer|engineering|enterprises"
+        + "|epson|equipment|erni|esq|estate|eurovision|eus|events|everbank|exchange|expert|exposed"
+        + "|express|e[cegrstu])"
+        + "|(?:fage|fail|fairwinds|faith|family|fan|fans|farm|fashion|feedback|ferrero|film"
+        + "|final|finance|financial|firmdale|fish|fishing|fit|fitness|flights|florist|flowers|flsmidth"
+        + "|fly|foo|football|forex|forsale|forum|foundation|frl|frogans|fund|furniture|futbol|fyi"
+        + "|f[ijkmor])"
+        + "|(?:gal|gallery|game|garden|gbiz|gdn|gea|gent|genting|ggee|gift|gifts|gives|giving"
+        + "|glass|gle|global|globo|gmail|gmo|gmx|gold|goldpoint|golf|goo|goog|google|gop|gov|grainger"
+        + "|graphics|gratis|green|gripe|group|gucci|guge|guide|guitars|guru|g[abdefghilmnpqrstuwy])"
+        + "|(?:hamburg|hangout|haus|healthcare|help|here|hermes|hiphop|hitachi|hiv|hockey|holdings"
+        + "|holiday|homedepot|homes|honda|horse|host|hosting|hoteles|hotmail|house|how|hsbc|hyundai"
+        + "|h[kmnrtu])"
+        + "|(?:ibm|icbc|ice|icu|ifm|iinet|immo|immobilien|industries|infiniti|info|ing|ink|institute"
+        + "|insure|int|international|investments|ipiranga|irish|ist|istanbul|itau|iwc|i[delmnoqrst])"
+        + "|(?:jaguar|java|jcb|jetzt|jewelry|jlc|jll|jobs|joburg|jprs|juegos|j[emop])"
+        + "|(?:kaufen|kddi|kia|kim|kinder|kitchen|kiwi|koeln|komatsu|krd|kred|kyoto|k[eghimnprwyz])"
+        + "|(?:lacaixa|lancaster|land|landrover|lasalle|lat|latrobe|law|lawyer|lds|lease|leclerc"
+        + "|legal|lexus|lgbt|liaison|lidl|life|lifestyle|lighting|limited|limo|linde|link|live"
+        + "|lixil|loan|loans|lol|london|lotte|lotto|love|ltd|ltda|lupin|luxe|luxury|l[abcikrstuvy])"
+        + "|(?:madrid|maif|maison|man|management|mango|market|marketing|markets|marriott|mba"
+        + "|media|meet|melbourne|meme|memorial|men|menu|meo|miami|microsoft|mil|mini|mma|mobi|moda"
+        + "|moe|moi|mom|monash|money|montblanc|mormon|mortgage|moscow|motorcycles|mov|movie|movistar"
+        + "|mtn|mtpc|mtr|museum|mutuelle|m[acdeghklmnopqrstuvwxyz])"
+        + "|(?:nadex|nagoya|name|navy|nec|net|netbank|network|neustar|new|news|nexus|ngo|nhk"
+        + "|nico|ninja|nissan|nokia|nra|nrw|ntt|nyc|n[acefgilopruz])"
+        + "|(?:obi|office|okinawa|omega|one|ong|onl|online|ooo|oracle|orange|org|organic|osaka"
+        + "|otsuka|ovh|om)"
+        + "|(?:page|panerai|paris|partners|parts|party|pet|pharmacy|philips|photo|photography"
+        + "|photos|physio|piaget|pics|pictet|pictures|ping|pink|pizza|place|play|playstation|plumbing"
+        + "|plus|pohl|poker|porn|post|praxi|press|pro|prod|productions|prof|properties|property"
+        + "|protection|pub|p[aefghklmnrstwy])"
+        + "|(?:qpon|quebec|qa)"
+        + "|(?:racing|realtor|realty|recipes|red|redstone|rehab|reise|reisen|reit|ren|rent|rentals"
+        + "|repair|report|republican|rest|restaurant|review|reviews|rich|ricoh|rio|rip|rocher|rocks"
+        + "|rodeo|rsvp|ruhr|run|rwe|ryukyu|r[eosuw])"
+        + "|(?:saarland|sakura|sale|samsung|sandvik|sandvikcoromant|sanofi|sap|sapo|sarl|saxo"
+        + "|sbs|sca|scb|schmidt|scholarships|school|schule|schwarz|science|scor|scot|seat|security"
+        + "|seek|sener|services|seven|sew|sex|sexy|shiksha|shoes|show|shriram|singles|site|ski"
+        + "|sky|skype|sncf|soccer|social|software|sohu|solar|solutions|sony|soy|space|spiegel|spreadbetting"
+        + "|srl|stada|starhub|statoil|stc|stcgroup|stockholm|studio|study|style|sucks|supplies"
+        + "|supply|support|surf|surgery|suzuki|swatch|swiss|sydney|systems|s[abcdeghijklmnortuvxyz])"
+        + "|(?:tab|taipei|tatamotors|tatar|tattoo|tax|taxi|team|tech|technology|tel|telefonica"
+        + "|temasek|tennis|thd|theater|theatre|tickets|tienda|tips|tires|tirol|today|tokyo|tools"
+        + "|top|toray|toshiba|tours|town|toyota|toys|trade|trading|training|travel|trust|tui|t[cdfghjklmnortvwz])"
+        + "|(?:ubs|university|uno|uol|u[agksyz])"
+        + "|(?:vacations|vana|vegas|ventures|versicherung|vet|viajes|video|villas|vin|virgin"
+        + "|vision|vista|vistaprint|viva|vlaanderen|vodka|vote|voting|voto|voyage|v[aceginu])"
+        + "|(?:wales|walter|wang|watch|webcam|website|wed|wedding|weir|whoswho|wien|wiki|williamhill"
+        + "|win|windows|wine|wme|work|works|world|wtc|wtf|w[fs])"
+        + "|(?:\u03b5\u03bb|\u0431\u0435\u043b|\u0434\u0435\u0442\u0438|\u043a\u043e\u043c|\u043c\u043a\u0434"
+        + "|\u043c\u043e\u043d|\u043c\u043e\u0441\u043a\u0432\u0430|\u043e\u043d\u043b\u0430\u0439\u043d"
+        + "|\u043e\u0440\u0433|\u0440\u0443\u0441|\u0440\u0444|\u0441\u0430\u0439\u0442|\u0441\u0440\u0431"
+        + "|\u0443\u043a\u0440|\u049b\u0430\u0437|\u0570\u0561\u0575|\u05e7\u05d5\u05dd|\u0627\u0631\u0627\u0645\u0643\u0648"
+        + "|\u0627\u0644\u0627\u0631\u062f\u0646|\u0627\u0644\u062c\u0632\u0627\u0626\u0631|\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629"
+        + "|\u0627\u0644\u0645\u063a\u0631\u0628|\u0627\u0645\u0627\u0631\u0627\u062a|\u0627\u06cc\u0631\u0627\u0646"
+        + "|\u0628\u0627\u0632\u0627\u0631|\u0628\u06be\u0627\u0631\u062a|\u062a\u0648\u0646\u0633"
+        + "|\u0633\u0648\u062f\u0627\u0646|\u0633\u0648\u0631\u064a\u0629|\u0634\u0628\u0643\u0629"
+        + "|\u0639\u0631\u0627\u0642|\u0639\u0645\u0627\u0646|\u0641\u0644\u0633\u0637\u064a\u0646"
+        + "|\u0642\u0637\u0631|\u0643\u0648\u0645|\u0645\u0635\u0631|\u0645\u0644\u064a\u0633\u064a\u0627"
+        + "|\u0645\u0648\u0642\u0639|\u0915\u0949\u092e|\u0928\u0947\u091f|\u092d\u093e\u0930\u0924"
+        + "|\u0938\u0902\u0917\u0920\u0928|\u09ad\u09be\u09b0\u09a4|\u0a2d\u0a3e\u0a30\u0a24|\u0aad\u0abe\u0ab0\u0aa4"
+        + "|\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe|\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8|\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd"
+        + "|\u0c2d\u0c3e\u0c30\u0c24\u0c4d|\u0dbd\u0d82\u0d9a\u0dcf|\u0e04\u0e2d\u0e21|\u0e44\u0e17\u0e22"
+        + "|\u10d2\u10d4|\u307f\u3093\u306a|\u30b0\u30fc\u30b0\u30eb|\u30b3\u30e0|\u4e16\u754c"
+        + "|\u4e2d\u4fe1|\u4e2d\u56fd|\u4e2d\u570b|\u4e2d\u6587\u7f51|\u4f01\u4e1a|\u4f5b\u5c71"
+        + "|\u4fe1\u606f|\u5065\u5eb7|\u516b\u5366|\u516c\u53f8|\u516c\u76ca|\u53f0\u6e7e|\u53f0\u7063"
+        + "|\u5546\u57ce|\u5546\u5e97|\u5546\u6807|\u5728\u7ebf|\u5927\u62ff|\u5a31\u4e50|\u5de5\u884c"
+        + "|\u5e7f\u4e1c|\u6148\u5584|\u6211\u7231\u4f60|\u624b\u673a|\u653f\u52a1|\u653f\u5e9c"
+        + "|\u65b0\u52a0\u5761|\u65b0\u95fb|\u65f6\u5c1a|\u673a\u6784|\u6de1\u9a6c\u9521|\u6e38\u620f"
+        + "|\u70b9\u770b|\u79fb\u52a8|\u7ec4\u7ec7\u673a\u6784|\u7f51\u5740|\u7f51\u5e97|\u7f51\u7edc"
+        + "|\u8c37\u6b4c|\u96c6\u56e2|\u98de\u5229\u6d66|\u9910\u5385|\u9999\u6e2f|\ub2f7\ub137"
+        + "|\ub2f7\ucef4|\uc0bc\uc131|\ud55c\uad6d|xbox"
+        + "|xerox|xin|xn\\-\\-11b4c3d|xn\\-\\-1qqw23a|xn\\-\\-30rr7y|xn\\-\\-3bst00m|xn\\-\\-3ds443g"
+        + "|xn\\-\\-3e0b707e|xn\\-\\-3pxu8k|xn\\-\\-42c2d9a|xn\\-\\-45brj9c|xn\\-\\-45q11c|xn\\-\\-4gbrim"
+        + "|xn\\-\\-55qw42g|xn\\-\\-55qx5d|xn\\-\\-6frz82g|xn\\-\\-6qq986b3xl|xn\\-\\-80adxhks"
+        + "|xn\\-\\-80ao21a|xn\\-\\-80asehdb|xn\\-\\-80aswg|xn\\-\\-90a3ac|xn\\-\\-90ais|xn\\-\\-9dbq2a"
+        + "|xn\\-\\-9et52u|xn\\-\\-b4w605ferd|xn\\-\\-c1avg|xn\\-\\-c2br7g|xn\\-\\-cg4bki|xn\\-\\-clchc0ea0b2g2a9gcd"
+        + "|xn\\-\\-czr694b|xn\\-\\-czrs0t|xn\\-\\-czru2d|xn\\-\\-d1acj3b|xn\\-\\-d1alf|xn\\-\\-efvy88h"
+        + "|xn\\-\\-estv75g|xn\\-\\-fhbei|xn\\-\\-fiq228c5hs|xn\\-\\-fiq64b|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s"
+        + "|xn\\-\\-fjq720a|xn\\-\\-flw351e|xn\\-\\-fpcrj9c3d|xn\\-\\-fzc2c9e2c|xn\\-\\-gecrj9c"
+        + "|xn\\-\\-h2brj9c|xn\\-\\-hxt814e|xn\\-\\-i1b6b1a6a2e|xn\\-\\-imr513n|xn\\-\\-io0a7i"
+        + "|xn\\-\\-j1aef|xn\\-\\-j1amh|xn\\-\\-j6w193g|xn\\-\\-kcrx77d1x4a|xn\\-\\-kprw13d|xn\\-\\-kpry57d"
+        + "|xn\\-\\-kput3i|xn\\-\\-l1acc|xn\\-\\-lgbbat1ad8j|xn\\-\\-mgb9awbf|xn\\-\\-mgba3a3ejt"
+        + "|xn\\-\\-mgba3a4f16a|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbab2bd|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a71e"
+        + "|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgberp4a5d4ar|xn\\-\\-mgbpl2fh|xn\\-\\-mgbtx2b|xn\\-\\-mgbx4cd0ab"
+        + "|xn\\-\\-mk1bu44c|xn\\-\\-mxtq1m|xn\\-\\-ngbc5azd|xn\\-\\-node|xn\\-\\-nqv7f|xn\\-\\-nqv7fs00ema"
+        + "|xn\\-\\-nyqy26a|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl|xn\\-\\-p1acf|xn\\-\\-p1ai|xn\\-\\-pgbs0dh"
+        + "|xn\\-\\-pssy2u|xn\\-\\-q9jyb4c|xn\\-\\-qcka1pmc|xn\\-\\-qxam|xn\\-\\-rhqv96g|xn\\-\\-s9brj9c"
+        + "|xn\\-\\-ses554g|xn\\-\\-t60b56a|xn\\-\\-tckwe|xn\\-\\-unup4y|xn\\-\\-vermgensberater\\-ctb"
+        + "|xn\\-\\-vermgensberatung\\-pwb|xn\\-\\-vhquv|xn\\-\\-vuq861b|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a"
+        + "|xn\\-\\-xhq521b|xn\\-\\-xkc2al3hye2a|xn\\-\\-xkc2dl3a5ee0h|xn\\-\\-y9a3aq|xn\\-\\-yfro4i67o"
+        + "|xn\\-\\-ygbi2ammx|xn\\-\\-zfr164b|xperia|xxx|xyz)"
+        + "|(?:yachts|yamaxun|yandex|yodobashi|yoga|yokohama|youtube|y[et])"
+        + "|(?:zara|zip|zone|zuerich|z[amw]))";
+
+    /**
+     * Kept for backward compatibility reasons.
+     *
+     * @deprecated Deprecated since it does not include all IRI characters defined in RFC 3987
+     */
+    @Deprecated
     public static final String GOOD_IRI_CHAR =
         "a-zA-Z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF";
 
@@ -125,35 +251,148 @@
             + "|[1-9][0-9]|[0-9]))");
 
     /**
+     * Valid UCS characters defined in RFC 3987.
+     */
+    private static final String UCS_CHAR =
+            "\u00A0-\uD7FF" +
+            "\uF900-\uFDCF" +
+            "\uFDF0-\uFFEF" +
+            "\uD800\uDC00-\uD83F\uDFFD" +
+            "\uD840\uDC00-\uD87F\uDFFD" +
+            "\uD880\uDC00-\uD8BF\uDFFD" +
+            "\uD8C0\uDC00-\uD8FF\uDFFD" +
+            "\uD900\uDC00-\uD93F\uDFFD" +
+            "\uD940\uDC00-\uD97F\uDFFD" +
+            "\uD980\uDC00-\uD9BF\uDFFD" +
+            "\uD9C0\uDC00-\uD9FF\uDFFD" +
+            "\uDA00\uDC00-\uDA3F\uDFFD" +
+            "\uDA40\uDC00-\uDA7F\uDFFD" +
+            "\uDA80\uDC00-\uDABF\uDFFD" +
+            "\uDAC0\uDC00-\uDAFF\uDFFD" +
+            "\uDB00\uDC00-\uDB3F\uDFFD" +
+            "\uDB44\uDC00-\uDB7F\uDFFD";
+
+    /**
+     * Valid characters for IRI label defined in RFC 3987.
+     */
+    private static final String LABEL_CHAR = "a-zA-Z0-9" + UCS_CHAR;
+
+    /**
+     * Valid characters for IRI TLD defined in RFC 3987.
+     */
+    private static final String TLD_CHAR = "a-zA-Z" + UCS_CHAR;
+
+    /**
      * RFC 1035 Section 2.3.4 limits the labels to a maximum 63 octets.
      */
-    private static final String IRI
-        = "[" + GOOD_IRI_CHAR + "]([" + GOOD_IRI_CHAR + "\\-]{0,61}[" + GOOD_IRI_CHAR + "]){0,1}";
+    private static final String IRI_LABEL =
+            "[" + LABEL_CHAR + "](?:[" + LABEL_CHAR + "\\-]{0,61}[" + LABEL_CHAR + "]){0,1}";
 
-    private static final String GOOD_GTLD_CHAR =
-        "a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF";
-    private static final String GTLD = "[" + GOOD_GTLD_CHAR + "]{2,63}";
-    private static final String HOST_NAME = "(" + IRI + "\\.)+" + GTLD;
+    /**
+     * RFC 3492 references RFC 1034 and limits Punycode algorithm output to 63 characters.
+     */
+    private static final String PUNYCODE_TLD = "xn\\-\\-[\\w\\-]{0,58}\\w";
+
+    private static final String TLD = "(" + PUNYCODE_TLD + "|" + "[" + TLD_CHAR + "]{2,63}" +")";
+
+    private static final String HOST_NAME = "(" + IRI_LABEL + "\\.)+" + TLD;
 
     public static final Pattern DOMAIN_NAME
         = Pattern.compile("(" + HOST_NAME + "|" + IP_ADDRESS + ")");
 
+    private static final String PROTOCOL = "(?i:http|https|rtsp):\\/\\/";
+
+    /* A word boundary or end of input.  This is to stop foo.sure from matching as foo.su */
+    private static final String WORD_BOUNDARY = "(?:\\b|$|^)";
+
+    private static final String USER_INFO = "(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
+            + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
+            + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@";
+
+    private static final String PORT_NUMBER = "\\:\\d{1,5}";
+
+    private static final String PATH_AND_QUERY = "\\/(?:(?:[" + LABEL_CHAR
+            + "\\;\\/\\?\\:\\@\\&\\=\\#\\~"  // plus optional query params
+            + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*";
+
     /**
      *  Regular expression pattern to match most part of RFC 3987
-     *  Internationalized URLs, aka IRIs.  Commonly used Unicode characters are
-     *  added.
+     *  Internationalized URLs, aka IRIs.
      */
-    public static final Pattern WEB_URL = Pattern.compile(
-        "((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
-        + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
-        + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
-        + "(?:" + DOMAIN_NAME + ")"
-        + "(?:\\:\\d{1,5})?)" // plus option port number
-        + "(\\/(?:(?:[" + GOOD_IRI_CHAR + "\\;\\/\\?\\:\\@\\&\\=\\#\\~"  // plus option query params
-        + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?"
-        + "(?:\\b|$)"); // and finally, a word boundary or end of
-                        // input.  This is to stop foo.sure from
-                        // matching as foo.su
+    public static final Pattern WEB_URL = Pattern.compile("("
+            + "("
+            + "(?:" + PROTOCOL + "(?:" + USER_INFO + ")?" + ")?"
+            + "(?:" + DOMAIN_NAME + ")"
+            + "(?:" + PORT_NUMBER + ")?"
+            + ")"
+            + "(" + PATH_AND_QUERY + ")?"
+            + WORD_BOUNDARY
+            + ")");
+
+    /**
+     * Regular expression that matches known TLDs and punycode TLDs
+     */
+    private static final String STRICT_TLD = "(?:" +
+            IANA_TOP_LEVEL_DOMAINS + "|" + PUNYCODE_TLD + ")";
+
+    /**
+     * Regular expression that matches host names using {@link #STRICT_TLD}
+     */
+    private static final String STRICT_HOST_NAME = "(?:(?:" + IRI_LABEL + "\\.)+"
+            + STRICT_TLD + ")";
+
+    /**
+     * Regular expression that matches domain names using either {@link #STRICT_HOST_NAME} or
+     * {@link #IP_ADDRESS}
+     */
+    private static final Pattern STRICT_DOMAIN_NAME
+            = Pattern.compile("(?:" + STRICT_HOST_NAME + "|" + IP_ADDRESS + ")");
+
+    /**
+     * Regular expression that matches domain names without a TLD
+     */
+    private static final String RELAXED_DOMAIN_NAME =
+            "(?:" + "(?:" + IRI_LABEL + "(?:\\.(?=\\S))" +"?)+" + "|" + IP_ADDRESS + ")";
+
+    /**
+     * Regular expression to match strings that do not start with a supported protocol. The TLDs
+     * are expected to be one of the known TLDs.
+     */
+    private static final String WEB_URL_WITHOUT_PROTOCOL = "("
+            + WORD_BOUNDARY
+            + "(?<!:\\/\\/)"
+            + "("
+            + "(?:" + STRICT_DOMAIN_NAME + ")"
+            + "(?:" + PORT_NUMBER + ")?"
+            + ")"
+            + "(?:" + PATH_AND_QUERY + ")?"
+            + WORD_BOUNDARY
+            + ")";
+
+    /**
+     * Regular expression to match strings that start with a supported protocol. Rules for domain
+     * names and TLDs are more relaxed. TLDs are optional.
+     */
+    private static final String WEB_URL_WITH_PROTOCOL = "("
+            + WORD_BOUNDARY
+            + "(?:"
+            + "(?:" + PROTOCOL + "(?:" + USER_INFO + ")?" + ")"
+            + "(?:" + RELAXED_DOMAIN_NAME + ")?"
+            + "(?:" + PORT_NUMBER + ")?"
+            + ")"
+            + "(?:" + PATH_AND_QUERY + ")?"
+            + WORD_BOUNDARY
+            + ")";
+
+    /**
+     * Regular expression pattern to match IRIs. If a string starts with http(s):// the expression
+     * tries to match the URL structure with a relaxed rule for TLDs. If the string does not start
+     * with http(s):// the TLDs are expected to be one of the known TLDs.
+     *
+     * @hide
+     */
+    public static final Pattern AUTOLINK_WEB_URL = Pattern.compile(
+            "(" + WEB_URL_WITH_PROTOCOL + "|" + WEB_URL_WITHOUT_PROTOCOL + ")");
 
     public static final Pattern EMAIL_ADDRESS
         = Pattern.compile(
diff --git a/core/java/android/util/StateSet.java b/core/java/android/util/StateSet.java
index c2a6a7a..051de8a 100644
--- a/core/java/android/util/StateSet.java
+++ b/core/java/android/util/StateSet.java
@@ -260,6 +260,12 @@
             case R.attr.state_enabled:
                 sb.append("E ");
                 break;
+            case R.attr.state_checked:
+                sb.append("C ");
+                break;
+            case R.attr.state_activated:
+                sb.append("A ");
+                break;
             }
         }
 
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
new file mode 100644
index 0000000..81c8c45
--- /dev/null
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -0,0 +1,1033 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.apk;
+
+import android.util.Pair;
+
+import java.io.ByteArrayInputStream;
+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.security.DigestException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Certificate;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.MGF1ParameterSpec;
+import java.security.spec.PSSParameterSpec;
+import java.security.spec.X509EncodedKeySpec;
+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;
+
+/**
+ * APK Signature Scheme v2 verifier.
+ *
+ * @hide for internal use only.
+ */
+public class ApkSignatureSchemeV2Verifier {
+
+    /**
+     * {@code .SF} file header section attribute indicating that the APK is signed not just with
+     * JAR signature scheme but also with APK Signature Scheme v2 or newer. This attribute
+     * facilitates v2 signature stripping detection.
+     *
+     * <p>The attribute contains a comma-separated set of signature scheme IDs.
+     */
+    public static final String SF_ATTRIBUTE_ANDROID_APK_SIGNED_NAME = "X-Android-APK-Signed";
+    // TODO: Change the value when signing scheme finalized.
+    public static final int SF_ATTRIBUTE_ANDROID_APK_SIGNED_ID = 1234567890;
+
+    /**
+     * Verifies APK Signature Scheme v2 signatures of the provided APK and returns the certificates
+     * 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 IOException if an I/O error occurs while reading the APK file.
+     */
+    public static X509Certificate[][] verify(String apkFile)
+            throws SignatureNotFoundException, SecurityException, IOException {
+        try (RandomAccessFile apk = new RandomAccessFile(apkFile, "r")) {
+            return verify(apk);
+        }
+    }
+
+    /**
+     * Verifies APK Signature Scheme v2 signatures of the provided APK and returns the certificates
+     * 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 IOException if an I/O error occurs while reading the APK file.
+     */
+    public 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);
+    }
+
+    /**
+     * 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.
+     *
+     * @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.
+     */
+    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)) {
+            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 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,
+                apkSignatureSchemeV2Block,
+                apkSigningBlockOffset,
+                centralDirOffset,
+                eocdOffset);
+    }
+
+    /**
+     * Verifies the contents outside of the APK Signing Block using the provided APK Signature
+     * Scheme v2 Block.
+     */
+    private static X509Certificate[][] verify(
+            ByteBuffer apkContents,
+            ByteBuffer v2Block,
+            int apkSigningBlockOffset,
+            int centralDirOffset,
+            int eocdOffset) throws SecurityException {
+        int signerCount = 0;
+        Map<Integer, byte[]> contentDigests = new HashMap<>();
+        List<X509Certificate[]> signerCerts = new ArrayList<>();
+        CertificateFactory certFactory;
+        try {
+            certFactory = CertificateFactory.getInstance("X.509");
+        } catch (CertificateException e) {
+            throw new RuntimeException("Failed to obtain X.509 CertificateFactory", e);
+        }
+        ByteBuffer signers;
+        try {
+            signers = getLengthPrefixedSlice(v2Block);
+        } catch (IOException e) {
+            throw new SecurityException("Failed to read list of signers", e);
+        }
+        while (signers.hasRemaining()) {
+            signerCount++;
+            try {
+                ByteBuffer signer = getLengthPrefixedSlice(signers);
+                X509Certificate[] certs = verifySigner(signer, contentDigests, certFactory);
+                signerCerts.add(certs);
+            } catch (IOException | BufferUnderflowException | SecurityException e) {
+                throw new SecurityException(
+                        "Failed to parse/verify signer #" + signerCount + " block",
+                        e);
+            }
+        }
+
+        if (signerCount < 1) {
+            throw new SecurityException("No signers found");
+        }
+
+        if (contentDigests.isEmpty()) {
+            throw new SecurityException("No content digests found");
+        }
+
+        verifyIntegrity(
+                contentDigests,
+                apkContents,
+                apkSigningBlockOffset,
+                centralDirOffset,
+                eocdOffset);
+
+        return signerCerts.toArray(new X509Certificate[signerCerts.size()][]);
+    }
+
+    private static X509Certificate[] verifySigner(
+            ByteBuffer signerBlock,
+            Map<Integer, byte[]> contentDigests,
+            CertificateFactory certFactory) throws SecurityException, IOException {
+        ByteBuffer signedData = getLengthPrefixedSlice(signerBlock);
+        ByteBuffer signatures = getLengthPrefixedSlice(signerBlock);
+        byte[] publicKeyBytes = readLengthPrefixedByteArray(signerBlock);
+
+        int signatureCount = 0;
+        int bestSigAlgorithm = -1;
+        byte[] bestSigAlgorithmSignatureBytes = null;
+        List<Integer> signaturesSigAlgorithms = new ArrayList<>();
+        while (signatures.hasRemaining()) {
+            signatureCount++;
+            try {
+                ByteBuffer signature = getLengthPrefixedSlice(signatures);
+                if (signature.remaining() < 8) {
+                    throw new SecurityException("Signature record too short");
+                }
+                int sigAlgorithm = signature.getInt();
+                signaturesSigAlgorithms.add(sigAlgorithm);
+                if (!isSupportedSignatureAlgorithm(sigAlgorithm)) {
+                    continue;
+                }
+                if ((bestSigAlgorithm == -1)
+                        || (compareSignatureAlgorithm(sigAlgorithm, bestSigAlgorithm) > 0)) {
+                    bestSigAlgorithm = sigAlgorithm;
+                    bestSigAlgorithmSignatureBytes = readLengthPrefixedByteArray(signature);
+                }
+            } catch (IOException | BufferUnderflowException e) {
+                throw new SecurityException(
+                        "Failed to parse signature record #" + signatureCount,
+                        e);
+            }
+        }
+        if (bestSigAlgorithm == -1) {
+            if (signatureCount == 0) {
+                throw new SecurityException("No signatures found");
+            } else {
+                throw new SecurityException("No supported signatures found");
+            }
+        }
+
+        String keyAlgorithm = getSignatureAlgorithmJcaKeyAlgorithm(bestSigAlgorithm);
+        Pair<String, ? extends AlgorithmParameterSpec> signatureAlgorithmParams =
+                getSignatureAlgorithmJcaSignatureAlgorithm(bestSigAlgorithm);
+        String jcaSignatureAlgorithm = signatureAlgorithmParams.first;
+        AlgorithmParameterSpec jcaSignatureAlgorithmParams = signatureAlgorithmParams.second;
+        boolean sigVerified;
+        try {
+            PublicKey publicKey =
+                    KeyFactory.getInstance(keyAlgorithm)
+                            .generatePublic(new X509EncodedKeySpec(publicKeyBytes));
+            Signature sig = Signature.getInstance(jcaSignatureAlgorithm);
+            sig.initVerify(publicKey);
+            if (jcaSignatureAlgorithmParams != null) {
+                sig.setParameter(jcaSignatureAlgorithmParams);
+            }
+            sig.update(signedData);
+            sigVerified = sig.verify(bestSigAlgorithmSignatureBytes);
+        } catch (NoSuchAlgorithmException | InvalidKeySpecException | InvalidKeyException
+                | InvalidAlgorithmParameterException | SignatureException e) {
+            throw new SecurityException(
+                    "Failed to verify " + jcaSignatureAlgorithm + " signature", e);
+        }
+        if (!sigVerified) {
+            throw new SecurityException(jcaSignatureAlgorithm + " signature did not verify");
+        }
+
+        // Signature over signedData has verified.
+
+        byte[] contentDigest = null;
+        signedData.clear();
+        ByteBuffer digests = getLengthPrefixedSlice(signedData);
+        List<Integer> digestsSigAlgorithms = new ArrayList<>();
+        int digestCount = 0;
+        while (digests.hasRemaining()) {
+            digestCount++;
+            try {
+                ByteBuffer digest = getLengthPrefixedSlice(digests);
+                if (digest.remaining() < 8) {
+                    throw new IOException("Record too short");
+                }
+                int sigAlgorithm = digest.getInt();
+                digestsSigAlgorithms.add(sigAlgorithm);
+                if (sigAlgorithm == bestSigAlgorithm) {
+                    contentDigest = readLengthPrefixedByteArray(digest);
+                }
+            } catch (IOException | BufferUnderflowException e) {
+                throw new IOException("Failed to parse digest record #" + digestCount, e);
+            }
+        }
+
+        if (!signaturesSigAlgorithms.equals(digestsSigAlgorithms)) {
+            throw new SecurityException(
+                    "Signature algorithms don't match between digests and signatures records");
+        }
+        int digestAlgorithm = getSignatureAlgorithmContentDigestAlgorithm(bestSigAlgorithm);
+        byte[] previousSignerDigest = contentDigests.put(digestAlgorithm, contentDigest);
+        if ((previousSignerDigest != null)
+                && (!MessageDigest.isEqual(previousSignerDigest, contentDigest))) {
+            throw new SecurityException(
+                    getContentDigestAlgorithmJcaDigestAlgorithm(digestAlgorithm)
+                    + " contents digest does not match the digest specified by a preceding signer");
+        }
+
+        ByteBuffer certificates = getLengthPrefixedSlice(signedData);
+        List<X509Certificate> certs = new ArrayList<>();
+        int certificateCount = 0;
+        while (certificates.hasRemaining()) {
+            certificateCount++;
+            byte[] encodedCert = readLengthPrefixedByteArray(certificates);
+            X509Certificate certificate;
+            try {
+                certificate = (X509Certificate)
+                        certFactory.generateCertificate(new ByteArrayInputStream(encodedCert));
+            } catch (CertificateException e) {
+                throw new SecurityException("Failed to decode certificate #" + certificateCount, e);
+            }
+            certificate = new VerbatimX509Certificate(certificate, encodedCert);
+            certs.add(certificate);
+        }
+
+        if (certs.isEmpty()) {
+            throw new SecurityException("No certificates listed");
+        }
+        X509Certificate mainCertificate = certs.get(0);
+        byte[] certificatePublicKeyBytes = mainCertificate.getPublicKey().getEncoded();
+        if (!Arrays.equals(publicKeyBytes, certificatePublicKeyBytes)) {
+            throw new SecurityException(
+                    "Public key mismatch between certificate and signature record");
+        }
+
+        return certs.toArray(new X509Certificate[certs.size()]);
+    }
+
+    private static void verifyIntegrity(
+            Map<Integer, byte[]> expectedDigests,
+            ByteBuffer apkContents,
+            int apkSigningBlockOffset,
+            int centralDirOffset,
+            int eocdOffset) throws SecurityException {
+
+        if (expectedDigests.isEmpty()) {
+            throw new SecurityException("No digests provided");
+        }
+
+        ByteBuffer beforeApkSigningBlock = sliceFromTo(apkContents, 0, apkSigningBlockOffset);
+        ByteBuffer centralDir = sliceFromTo(apkContents, centralDirOffset, eocdOffset);
+        // 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);
+
+        int[] digestAlgorithms = new int[expectedDigests.size()];
+        int digestAlgorithmCount = 0;
+        for (int digestAlgorithm : expectedDigests.keySet()) {
+            digestAlgorithms[digestAlgorithmCount] = digestAlgorithm;
+            digestAlgorithmCount++;
+        }
+        Map<Integer, byte[]> actualDigests;
+        try {
+            actualDigests =
+                    computeContentDigests(
+                            digestAlgorithms,
+                            new ByteBuffer[] {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);
+            if (!MessageDigest.isEqual(expectedDigest, actualDigest)) {
+                throw new SecurityException(
+                        getContentDigestAlgorithmJcaDigestAlgorithm(digestAlgorithm)
+                        + " digest of contents did not verify");
+            }
+        }
+    }
+
+    private static Map<Integer, byte[]> computeContentDigests(
+            int[] digestAlgorithms,
+            ByteBuffer[] 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.
+        //    No chunks are produced for empty (zero length) segments.
+        // 2. The digest of each chunk is computed over the concatenation of byte 0xa5, the chunk's
+        //    length in bytes (uint32 little-endian) and the chunk's contents.
+        // 3. The output digest is computed over the concatenation of the byte 0x5a, the number of
+        //    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());
+        }
+
+        Map<Integer, byte[]> digestsOfChunks = new HashMap<>(totalChunkCount);
+        for (int digestAlgorithm : digestAlgorithms) {
+            int digestOutputSizeBytes = getContentDigestAlgorithmOutputSizeBytes(digestAlgorithm);
+            byte[] concatenationOfChunkCountAndChunkDigests =
+                    new byte[5 + totalChunkCount * digestOutputSizeBytes];
+            concatenationOfChunkCountAndChunkDigests[0] = 0x5a;
+            setUnsignedInt32LittleEndian(
+                    totalChunkCount,
+                    concatenationOfChunkCountAndChunkDigests,
+                    1);
+            digestsOfChunks.put(digestAlgorithm, 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);
+                    int expectedDigestSizeBytes =
+                            getContentDigestAlgorithmOutputSizeBytes(digestAlgorithm);
+                    int actualDigestSizeBytes = md.digest(concatenationOfChunkCountAndChunkDigests,
+                            5 + chunkIndex * expectedDigestSizeBytes, expectedDigestSizeBytes);
+                    if (actualDigestSizeBytes != expectedDigestSizeBytes) {
+                        throw new RuntimeException(
+                                "Unexpected output size of " + md.getAlgorithm() + " digest: "
+                                        + actualDigestSizeBytes);
+                    }
+                }
+                chunkIndex++;
+            }
+        }
+
+        Map<Integer, byte[]> result = new HashMap<>(digestAlgorithms.length);
+        for (Map.Entry<Integer, byte[]> entry : digestsOfChunks.entrySet()) {
+            int digestAlgorithm = entry.getKey();
+            byte[] input = entry.getValue();
+            String jcaAlgorithmName = getContentDigestAlgorithmJcaDigestAlgorithm(digestAlgorithm);
+            MessageDigest md;
+            try {
+                md = MessageDigest.getInstance(jcaAlgorithmName);
+            } catch (NoSuchAlgorithmException e) {
+                throw new RuntimeException(jcaAlgorithmName + " digest not supported", e);
+            }
+            byte[] output = md.digest(input);
+            result.put(digestAlgorithm, output);
+        }
+        return result;
+    }
+
+    private static final int getChunkCount(int inputSizeBytes) {
+        return (inputSizeBytes + CHUNK_SIZE_BYTES - 1) / CHUNK_SIZE_BYTES;
+    }
+
+    private static final int CHUNK_SIZE_BYTES = 1024 * 1024;
+
+    private static final int SIGNATURE_RSA_PSS_WITH_SHA256 = 0x0101;
+    private static final int SIGNATURE_RSA_PSS_WITH_SHA512 = 0x0102;
+    private static final int SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256 = 0x0103;
+    private static final int SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512 = 0x0104;
+    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;
+
+    private static boolean isSupportedSignatureAlgorithm(int sigAlgorithm) {
+        switch (sigAlgorithm) {
+            case SIGNATURE_RSA_PSS_WITH_SHA256:
+            case SIGNATURE_RSA_PSS_WITH_SHA512:
+            case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256:
+            case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512:
+            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;
+        }
+    }
+
+    private static int compareSignatureAlgorithm(int sigAlgorithm1, int sigAlgorithm2) {
+        int digestAlgorithm1 = getSignatureAlgorithmContentDigestAlgorithm(sigAlgorithm1);
+        int digestAlgorithm2 = getSignatureAlgorithmContentDigestAlgorithm(sigAlgorithm2);
+        return compareContentDigestAlgorithm(digestAlgorithm1, digestAlgorithm2);
+    }
+
+    private static int compareContentDigestAlgorithm(int digestAlgorithm1, int digestAlgorithm2) {
+        switch (digestAlgorithm1) {
+            case CONTENT_DIGEST_CHUNKED_SHA256:
+                switch (digestAlgorithm2) {
+                    case CONTENT_DIGEST_CHUNKED_SHA256:
+                        return 0;
+                    case CONTENT_DIGEST_CHUNKED_SHA512:
+                        return -1;
+                    default:
+                        throw new IllegalArgumentException(
+                                "Unknown digestAlgorithm2: " + digestAlgorithm2);
+                }
+            case CONTENT_DIGEST_CHUNKED_SHA512:
+                switch (digestAlgorithm2) {
+                    case CONTENT_DIGEST_CHUNKED_SHA256:
+                        return 1;
+                    case CONTENT_DIGEST_CHUNKED_SHA512:
+                        return 0;
+                    default:
+                        throw new IllegalArgumentException(
+                                "Unknown digestAlgorithm2: " + digestAlgorithm2);
+                }
+            default:
+                throw new IllegalArgumentException("Unknown digestAlgorithm1: " + digestAlgorithm1);
+        }
+    }
+
+    private static int getSignatureAlgorithmContentDigestAlgorithm(int sigAlgorithm) {
+        switch (sigAlgorithm) {
+            case SIGNATURE_RSA_PSS_WITH_SHA256:
+            case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256:
+            case SIGNATURE_ECDSA_WITH_SHA256:
+            case SIGNATURE_DSA_WITH_SHA256:
+                return CONTENT_DIGEST_CHUNKED_SHA256;
+            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(
+                        "Unknown signature algorithm: 0x"
+                                + Long.toHexString(sigAlgorithm & 0xffffffff));
+        }
+    }
+
+    private static String getContentDigestAlgorithmJcaDigestAlgorithm(int digestAlgorithm) {
+        switch (digestAlgorithm) {
+            case CONTENT_DIGEST_CHUNKED_SHA256:
+                return "SHA-256";
+            case CONTENT_DIGEST_CHUNKED_SHA512:
+                return "SHA-512";
+            default:
+                throw new IllegalArgumentException(
+                        "Unknown content digest algorthm: " + digestAlgorithm);
+        }
+    }
+
+    private static int getContentDigestAlgorithmOutputSizeBytes(int digestAlgorithm) {
+        switch (digestAlgorithm) {
+            case CONTENT_DIGEST_CHUNKED_SHA256:
+                return 256 / 8;
+            case CONTENT_DIGEST_CHUNKED_SHA512:
+                return 512 / 8;
+            default:
+                throw new IllegalArgumentException(
+                        "Unknown content digest algorthm: " + digestAlgorithm);
+        }
+    }
+
+    private static String getSignatureAlgorithmJcaKeyAlgorithm(int sigAlgorithm) {
+        switch (sigAlgorithm) {
+            case SIGNATURE_RSA_PSS_WITH_SHA256:
+            case SIGNATURE_RSA_PSS_WITH_SHA512:
+            case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256:
+            case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512:
+                return "RSA";
+            case SIGNATURE_ECDSA_WITH_SHA256:
+            case SIGNATURE_ECDSA_WITH_SHA512:
+                return "EC";
+            case SIGNATURE_DSA_WITH_SHA256:
+            case SIGNATURE_DSA_WITH_SHA512:
+                return "DSA";
+            default:
+                throw new IllegalArgumentException(
+                        "Unknown signature algorithm: 0x"
+                                + Long.toHexString(sigAlgorithm & 0xffffffff));
+        }
+    }
+
+    private static Pair<String, ? extends AlgorithmParameterSpec>
+            getSignatureAlgorithmJcaSignatureAlgorithm(int sigAlgorithm) {
+        switch (sigAlgorithm) {
+            case SIGNATURE_RSA_PSS_WITH_SHA256:
+                return Pair.create(
+                        "SHA256withRSA/PSS",
+                        new PSSParameterSpec(
+                                "SHA-256", "MGF1", MGF1ParameterSpec.SHA256, 256 / 8, 1));
+            case SIGNATURE_RSA_PSS_WITH_SHA512:
+                return Pair.create(
+                        "SHA512withRSA/PSS",
+                        new PSSParameterSpec(
+                                "SHA-512", "MGF1", MGF1ParameterSpec.SHA512, 512 / 8, 1));
+            case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256:
+                return Pair.create("SHA256withRSA", null);
+            case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512:
+                return Pair.create("SHA512withRSA", null);
+            case SIGNATURE_ECDSA_WITH_SHA256:
+                return Pair.create("SHA256withECDSA", null);
+            case SIGNATURE_ECDSA_WITH_SHA512:
+                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"
+                                + Long.toHexString(sigAlgorithm & 0xffffffff));
+        }
+    }
+
+    /**
+     * Returns new byte buffer whose content is a shared subsequence of this buffer's content
+     * between the specified start (inclusive) and end (exclusive) positions. As opposed to
+     * {@link ByteBuffer#slice()}, the returned buffer's byte order is the same as the source
+     * buffer's byte order.
+     */
+    private static ByteBuffer sliceFromTo(ByteBuffer source, int start, int end) {
+        if (start < 0) {
+            throw new IllegalArgumentException("start: " + start);
+        }
+        if (end < start) {
+            throw new IllegalArgumentException("end < start: " + end + " < " + start);
+        }
+        int capacity = source.capacity();
+        if (end > source.capacity()) {
+            throw new IllegalArgumentException("end > capacity: " + end + " > " + capacity);
+        }
+        int originalLimit = source.limit();
+        int originalPosition = source.position();
+        try {
+            source.position(0);
+            source.limit(end);
+            source.position(start);
+            ByteBuffer result = source.slice();
+            result.order(source.order());
+            return result;
+        } finally {
+            source.position(0);
+            source.limit(originalLimit);
+            source.position(originalPosition);
+        }
+    }
+
+    /**
+     * Relative <em>get</em> method for reading {@code size} number of bytes from the current
+     * position of this buffer.
+     *
+     * <p>This method reads the next {@code size} bytes at this buffer's current position,
+     * returning them as a {@code ByteBuffer} with start set to 0, limit and capacity set to
+     * {@code size}, byte order set to this buffer's byte order; and then increments the position by
+     * {@code size}.
+     */
+    private static ByteBuffer getByteBuffer(ByteBuffer source, int size)
+            throws BufferUnderflowException {
+        if (size < 0) {
+            throw new IllegalArgumentException("size: " + size);
+        }
+        int originalLimit = source.limit();
+        int position = source.position();
+        int limit = position + size;
+        if ((limit < position) || (limit > originalLimit)) {
+            throw new BufferUnderflowException();
+        }
+        source.limit(limit);
+        try {
+            ByteBuffer result = source.slice();
+            result.order(source.order());
+            source.position(limit);
+            return result;
+        } finally {
+            source.limit(originalLimit);
+        }
+    }
+
+    private static ByteBuffer getLengthPrefixedSlice(ByteBuffer source) throws IOException {
+        if (source.remaining() < 4) {
+            throw new IOException(
+                    "Remaining buffer too short to contain length of length-prefixed field."
+                            + " Remaining: " + source.remaining());
+        }
+        int len = source.getInt();
+        if (len < 0) {
+            throw new IllegalArgumentException("Negative length");
+        } else if (len > source.remaining()) {
+            throw new IOException("Length-prefixed field longer than remaining buffer."
+                    + " Field length: " + len + ", remaining: " + source.remaining());
+        }
+        return getByteBuffer(source, len);
+    }
+
+    private static byte[] readLengthPrefixedByteArray(ByteBuffer buf) throws IOException {
+        int len = buf.getInt();
+        if (len < 0) {
+            throw new IOException("Negative length");
+        } else if (len > buf.remaining()) {
+            throw new IOException("Underflow while reading length-prefixed value. Length: " + len
+                    + ", available: " + buf.remaining());
+        }
+        byte[] result = new byte[len];
+        buf.get(result);
+        return result;
+    }
+
+    private static void setUnsignedInt32LittleEndian(int value, byte[] result, int offset) {
+        result[offset] = (byte) (value & 0xff);
+        result[offset + 1] = (byte) ((value >>> 8) & 0xff);
+        result[offset + 2] = (byte) ((value >>> 16) & 0xff);
+        result[offset + 3] = (byte) ((value >>> 24) & 0xff);
+    }
+
+    private static final long APK_SIG_BLOCK_MAGIC_HI = 0x3234206b636f6c42L;
+    private static final long APK_SIG_BLOCK_MAGIC_LO = 0x20676953204b5041L;
+    private static final int APK_SIG_BLOCK_MIN_SIZE = 32;
+
+    private static final int APK_SIGNATURE_SCHEME_V2_BLOCK_ID = 0x7109871a;
+
+    private static int findApkSigningBlock(ByteBuffer apkContents, int centralDirOffset)
+            throws SignatureNotFoundException {
+        checkByteOrderLittleEndian(apkContents);
+
+        // FORMAT:
+        // OFFSET       DATA TYPE  DESCRIPTION
+        // * @+0  bytes uint64:    size in bytes (excluding this field)
+        // * @+8  bytes payload
+        // * @-24 bytes uint64:    size in bytes (same as the one above)
+        // * @-16 bytes uint128:   magic
+
+        if (centralDirOffset < APK_SIG_BLOCK_MIN_SIZE) {
+            throw new SignatureNotFoundException(
+                    "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)) {
+            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)) {
+            throw new SignatureNotFoundException(
+                    "APK Signing Block size out of range: " + apkSigBlockSizeLong);
+        }
+        int apkSigBlockSizeFromFooter = (int) apkSigBlockSizeLong;
+        int totalSize = apkSigBlockSizeFromFooter + 8;
+        int 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) {
+            throw new SignatureNotFoundException(
+                    "APK Signing Block sizes in header and footer do not match: "
+                            + apkSigBlockSizeFromHeader + " vs " + apkSigBlockSizeFromFooter);
+        }
+        return apkSigBlockOffset;
+    }
+
+    private static ByteBuffer findApkSignatureSchemeV2Block(ByteBuffer apkSigningBlock)
+            throws SignatureNotFoundException {
+        checkByteOrderLittleEndian(apkSigningBlock);
+        // FORMAT:
+        // OFFSET       DATA TYPE  DESCRIPTION
+        // * @+0  bytes uint64:    size in bytes (excluding this field)
+        // * @+8  bytes pairs
+        // * @-24 bytes uint64:    size in bytes (same as the one above)
+        // * @-16 bytes uint128:   magic
+        ByteBuffer pairs = sliceFromTo(apkSigningBlock, 8, apkSigningBlock.capacity() - 24);
+
+        int entryCount = 0;
+        while (pairs.hasRemaining()) {
+            entryCount++;
+            if (pairs.remaining() < 8) {
+                throw new SignatureNotFoundException(
+                        "Insufficient data to read size of APK Signing Block entry #" + entryCount);
+            }
+            long lenLong = pairs.getLong();
+            if ((lenLong < 4) || (lenLong > Integer.MAX_VALUE)) {
+                throw new SignatureNotFoundException(
+                        "APK Signing Block entry #" + entryCount
+                                + " size out of range: " + lenLong);
+            }
+            int len = (int) lenLong;
+            int nextEntryPos = pairs.position() + len;
+            if (len > pairs.remaining()) {
+                throw new SignatureNotFoundException(
+                        "APK Signing Block entry #" + entryCount + " size out of range: " + len
+                                + ", available: " + pairs.remaining());
+            }
+            int id = pairs.getInt();
+            if (id == APK_SIGNATURE_SCHEME_V2_BLOCK_ID) {
+                return getByteBuffer(pairs, len - 4);
+            }
+            pairs.position(nextEntryPos);
+        }
+
+        throw new SignatureNotFoundException(
+                "No APK Signature Scheme v2 block in APK Signing Block");
+    }
+
+    private static void checkByteOrderLittleEndian(ByteBuffer buffer) {
+        if (buffer.order() != ByteOrder.LITTLE_ENDIAN) {
+            throw new IllegalArgumentException("ByteBuffer byte order must be little endian");
+        }
+    }
+
+    public static class SignatureNotFoundException extends Exception {
+        public SignatureNotFoundException(String message) {
+            super(message);
+        }
+
+        public SignatureNotFoundException(String message, Throwable cause) {
+            super(message, cause);
+        }
+    }
+
+    /**
+     * 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.
+     */
+    private static class VerbatimX509Certificate extends WrappedX509Certificate {
+        private byte[] encodedVerbatim;
+
+        public VerbatimX509Certificate(X509Certificate wrapped, byte[] encodedVerbatim) {
+            super(wrapped);
+            this.encodedVerbatim = encodedVerbatim;
+        }
+
+        @Override
+        public byte[] getEncoded() throws CertificateEncodingException {
+            return encodedVerbatim;
+        }
+    }
+
+    private static class WrappedX509Certificate extends X509Certificate {
+        private final X509Certificate wrapped;
+
+        public WrappedX509Certificate(X509Certificate wrapped) {
+            this.wrapped = wrapped;
+        }
+
+        @Override
+        public Set<String> getCriticalExtensionOIDs() {
+            return wrapped.getCriticalExtensionOIDs();
+        }
+
+        @Override
+        public byte[] getExtensionValue(String oid) {
+            return wrapped.getExtensionValue(oid);
+        }
+
+        @Override
+        public Set<String> getNonCriticalExtensionOIDs() {
+            return wrapped.getNonCriticalExtensionOIDs();
+        }
+
+        @Override
+        public boolean hasUnsupportedCriticalExtension() {
+            return wrapped.hasUnsupportedCriticalExtension();
+        }
+
+        @Override
+        public void checkValidity()
+                throws CertificateExpiredException, CertificateNotYetValidException {
+            wrapped.checkValidity();
+        }
+
+        @Override
+        public void checkValidity(Date date)
+                throws CertificateExpiredException, CertificateNotYetValidException {
+            wrapped.checkValidity(date);
+        }
+
+        @Override
+        public int getVersion() {
+            return wrapped.getVersion();
+        }
+
+        @Override
+        public BigInteger getSerialNumber() {
+            return wrapped.getSerialNumber();
+        }
+
+        @Override
+        public Principal getIssuerDN() {
+            return wrapped.getIssuerDN();
+        }
+
+        @Override
+        public Principal getSubjectDN() {
+            return wrapped.getSubjectDN();
+        }
+
+        @Override
+        public Date getNotBefore() {
+            return wrapped.getNotBefore();
+        }
+
+        @Override
+        public Date getNotAfter() {
+            return wrapped.getNotAfter();
+        }
+
+        @Override
+        public byte[] getTBSCertificate() throws CertificateEncodingException {
+            return wrapped.getTBSCertificate();
+        }
+
+        @Override
+        public byte[] getSignature() {
+            return wrapped.getSignature();
+        }
+
+        @Override
+        public String getSigAlgName() {
+            return wrapped.getSigAlgName();
+        }
+
+        @Override
+        public String getSigAlgOID() {
+            return wrapped.getSigAlgOID();
+        }
+
+        @Override
+        public byte[] getSigAlgParams() {
+            return wrapped.getSigAlgParams();
+        }
+
+        @Override
+        public boolean[] getIssuerUniqueID() {
+            return wrapped.getIssuerUniqueID();
+        }
+
+        @Override
+        public boolean[] getSubjectUniqueID() {
+            return wrapped.getSubjectUniqueID();
+        }
+
+        @Override
+        public boolean[] getKeyUsage() {
+            return wrapped.getKeyUsage();
+        }
+
+        @Override
+        public int getBasicConstraints() {
+            return wrapped.getBasicConstraints();
+        }
+
+        @Override
+        public byte[] getEncoded() throws CertificateEncodingException {
+            return wrapped.getEncoded();
+        }
+
+        @Override
+        public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException,
+                InvalidKeyException, NoSuchProviderException, SignatureException {
+            wrapped.verify(key);
+        }
+
+        @Override
+        public void verify(PublicKey key, String sigProvider)
+                throws CertificateException, NoSuchAlgorithmException, InvalidKeyException,
+                NoSuchProviderException, SignatureException {
+            wrapped.verify(key, sigProvider);
+        }
+
+        @Override
+        public String toString() {
+            return wrapped.toString();
+        }
+
+        @Override
+        public PublicKey getPublicKey() {
+            return wrapped.getPublicKey();
+        }
+    }
+}
diff --git a/core/java/android/util/apk/ZipUtils.java b/core/java/android/util/apk/ZipUtils.java
new file mode 100644
index 0000000..a383d5c
--- /dev/null
+++ b/core/java/android/util/apk/ZipUtils.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.apk;
+
+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
+ * order of these buffers is little-endian.
+ */
+abstract class ZipUtils {
+    private ZipUtils() {}
+
+    private static final int ZIP_EOCD_REC_MIN_SIZE = 22;
+    private static final int ZIP_EOCD_REC_SIG = 0x06054b50;
+    private static final int ZIP_EOCD_CENTRAL_DIR_SIZE_FIELD_OFFSET = 12;
+    private static final int ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_OFFSET = 16;
+    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 UINT32_MAX_VALUE = 0xffff;
+
+    /**
+     * Returns the position at which ZIP End of Central Directory record starts in the provided
+     * buffer or {@code -1} if the record is not present.
+     *
+     * <p>NOTE: Byte order of {@code zipContents} must be little-endian.
+     */
+    public static int findZipEndOfCentralDirectoryRecord(ByteBuffer zipContents) {
+        assertByteOrderLittleEndian(zipContents);
+
+        // 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 32-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 eocdWithEmptyCommentStartPosition = archiveSize - ZIP_EOCD_REC_MIN_SIZE;
+        for (int expectedCommentLength = 0; expectedCommentLength < maxCommentLength;
+                expectedCommentLength++) {
+            int eocdStartPos = eocdWithEmptyCommentStartPosition - expectedCommentLength;
+            if (zipContents.getInt(eocdStartPos) == ZIP_EOCD_REC_SIG) {
+                int actualCommentLength =
+                        getUnsignedInt16(
+                                zipContents, eocdStartPos + ZIP_EOCD_COMMENT_LENGTH_FIELD_OFFSET);
+                if (actualCommentLength == expectedCommentLength) {
+                    return eocdStartPos;
+                }
+            }
+        }
+
+        return -1;
+    }
+
+    /**
+     * Returns {@code true} if the provided buffer contains a ZIP64 End of Central Directory
+     * Locator.
+     *
+     * <p>NOTE: Byte order of {@code zipContents} must be little-endian.
+     */
+    public static final boolean isZip64EndOfCentralDirectoryLocatorPresent(
+            ByteBuffer zipContents, int zipEndOfCentralDirectoryPosition) {
+        assertByteOrderLittleEndian(zipContents);
+
+        // ZIP64 End of Central Directory Locator immediately precedes the ZIP End of Central
+        // Directory Record.
+
+        int locatorPosition = zipEndOfCentralDirectoryPosition - ZIP64_EOCD_LOCATOR_SIZE;
+        if (locatorPosition < 0) {
+            return false;
+        }
+
+        return zipContents.getInt(locatorPosition) == ZIP64_EOCD_LOCATOR_SIG;
+    }
+
+    /**
+     * Returns the offset of the start of the ZIP Central Directory in the archive.
+     *
+     * <p>NOTE: Byte order of {@code zipEndOfCentralDirectory} must be little-endian.
+     */
+    public static long getZipEocdCentralDirectoryOffset(ByteBuffer zipEndOfCentralDirectory) {
+        assertByteOrderLittleEndian(zipEndOfCentralDirectory);
+        return getUnsignedInt32(
+                zipEndOfCentralDirectory,
+                zipEndOfCentralDirectory.position() + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_OFFSET);
+    }
+
+    /**
+     * Sets the offset of the start of the ZIP Central Directory in the archive.
+     *
+     * <p>NOTE: Byte order of {@code zipEndOfCentralDirectory} must be little-endian.
+     */
+    public static void setZipEocdCentralDirectoryOffset(
+            ByteBuffer zipEndOfCentralDirectory, long offset) {
+        assertByteOrderLittleEndian(zipEndOfCentralDirectory);
+        setUnsignedInt32(
+                zipEndOfCentralDirectory,
+                zipEndOfCentralDirectory.position() + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_OFFSET,
+                offset);
+    }
+
+    /**
+     * Returns the size (in bytes) of the ZIP Central Directory.
+     *
+     * <p>NOTE: Byte order of {@code zipEndOfCentralDirectory} must be little-endian.
+     */
+    public static long getZipEocdCentralDirectorySizeBytes(ByteBuffer zipEndOfCentralDirectory) {
+        assertByteOrderLittleEndian(zipEndOfCentralDirectory);
+        return getUnsignedInt32(
+                zipEndOfCentralDirectory,
+                zipEndOfCentralDirectory.position() + ZIP_EOCD_CENTRAL_DIR_SIZE_FIELD_OFFSET);
+    }
+
+    private static void assertByteOrderLittleEndian(ByteBuffer buffer) {
+        if (buffer.order() != ByteOrder.LITTLE_ENDIAN) {
+            throw new IllegalArgumentException("ByteBuffer byte order must be little endian");
+        }
+    }
+
+    private static int getUnsignedInt16(ByteBuffer buffer, int offset) {
+        return buffer.getShort(offset) & 0xffff;
+    }
+
+    private static long getUnsignedInt32(ByteBuffer buffer, int offset) {
+        return buffer.getInt(offset) & 0xffffffffL;
+    }
+
+    private static void setUnsignedInt32(ByteBuffer buffer, int offset, long value) {
+        if ((value < 0) || (value > 0xffffffffL)) {
+            throw new IllegalArgumentException("uint32 value of out range: " + value);
+        }
+        buffer.putInt(buffer.position() + offset, (int) value);
+    }
+}
diff --git a/core/java/android/util/jar/StrictJarFile.java b/core/java/android/util/jar/StrictJarFile.java
index fd57806..302a08d 100644
--- a/core/java/android/util/jar/StrictJarFile.java
+++ b/core/java/android/util/jar/StrictJarFile.java
@@ -18,7 +18,6 @@
 package android.util.jar;
 
 import dalvik.system.CloseGuard;
-import java.io.ByteArrayInputStream;
 import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -30,9 +29,7 @@
 import java.util.zip.Inflater;
 import java.util.zip.InflaterInputStream;
 import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
 import java.util.jar.JarFile;
-import java.util.jar.Manifest;
 import libcore.io.IoUtils;
 import libcore.io.Streams;
 
@@ -59,7 +56,13 @@
     private final CloseGuard guard = CloseGuard.get();
     private boolean closed;
 
-    public StrictJarFile(String fileName) throws IOException, SecurityException {
+    public StrictJarFile(String fileName)
+            throws IOException, SecurityException {
+        this(fileName, true);
+    }
+
+    public StrictJarFile(String fileName, boolean verify)
+            throws IOException, SecurityException {
         this.nativeHandle = nativeOpenJarFile(fileName);
         this.raf = new RandomAccessFile(fileName, "r");
 
@@ -67,17 +70,23 @@
             // Read the MANIFEST and signature files up front and try to
             // parse them. We never want to accept a JAR File with broken signatures
             // or manifests, so it's best to throw as early as possible.
-            HashMap<String, byte[]> metaEntries = getMetaEntries();
-            this.manifest = new StrictJarManifest(metaEntries.get(JarFile.MANIFEST_NAME), true);
-            this.verifier = new StrictJarVerifier(fileName, manifest, metaEntries);
-            Set<String> files = manifest.getEntries().keySet();
-            for (String file : files) {
-                if (findEntry(file) == null) {
-                    throw new SecurityException(fileName + ": File " + file + " in manifest does not exist");
+            if (verify) {
+                HashMap<String, byte[]> metaEntries = getMetaEntries();
+                this.manifest = new StrictJarManifest(metaEntries.get(JarFile.MANIFEST_NAME), true);
+                this.verifier = new StrictJarVerifier(fileName, manifest, metaEntries);
+                Set<String> files = manifest.getEntries().keySet();
+                for (String file : files) {
+                    if (findEntry(file) == null) {
+                        throw new SecurityException(fileName + ": File " + file + " in manifest does not exist");
+                    }
                 }
-            }
 
-            isSigned = verifier.readCertificates() && verifier.isSignedJar();
+                isSigned = verifier.readCertificates() && verifier.isSignedJar();
+            } else {
+                isSigned = false;
+                this.manifest = null;
+                this.verifier = null;
+            }
         } catch (IOException | SecurityException e) {
             nativeClose(this.nativeHandle);
             IoUtils.closeQuietly(this.raf);
diff --git a/core/java/android/util/jar/StrictJarVerifier.java b/core/java/android/util/jar/StrictJarVerifier.java
index ca2aec1..0546a5f 100644
--- a/core/java/android/util/jar/StrictJarVerifier.java
+++ b/core/java/android/util/jar/StrictJarVerifier.java
@@ -32,8 +32,12 @@
 import java.util.Iterator;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
 import java.util.jar.Attributes;
 import java.util.jar.JarFile;
+import android.util.ArraySet;
+import android.util.apk.ApkSignatureSchemeV2Verifier;
 import libcore.io.Base64;
 import sun.security.jca.Providers;
 import sun.security.pkcs.PKCS7;
@@ -353,6 +357,43 @@
             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;
+                }
+                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?");
+            }
+        }
+
         // Do we actually have any signatures to look at?
         if (attributes.get(Attributes.Name.SIGNATURE_VERSION) == null) {
             return;
diff --git a/core/java/android/view/ContextThemeWrapper.java b/core/java/android/view/ContextThemeWrapper.java
index ea0873d..4888877 100644
--- a/core/java/android/view/ContextThemeWrapper.java
+++ b/core/java/android/view/ContextThemeWrapper.java
@@ -104,11 +104,15 @@
     @Override
     public AssetManager getAssets() {
         // Ensure we're returning assets with the correct configuration.
-        return getResources().getAssets();
+        return getResourcesInternal().getAssets();
     }
 
     @Override
     public Resources getResources() {
+        return getResourcesInternal();
+    }
+
+    private Resources getResourcesInternal() {
         if (mResources == null) {
             if (mOverrideConfiguration == null) {
                 mResources = super.getResources();
@@ -117,7 +121,6 @@
                 mResources = resContext.getResources();
             }
         }
-
         return mResources;
     }
 
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index 34835f4..71db0b5 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -21,6 +21,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.internal.view.IDropPermissions;
+
 //TODO: Improve Javadoc
 /**
  * Represents an event that is sent out by the system at various times during a drag and drop
@@ -128,7 +130,7 @@
     float mX, mY;
     ClipDescription mClipDescription;
     ClipData mClipData;
-    DropPermissionHolder mDropPermissionHolder;
+    IDropPermissions mDropPermissions;
 
     Object mLocalState;
     boolean mDragResult;
@@ -146,7 +148,7 @@
      * Action constant returned by {@link #getAction()}: Signals the start of a
      * drag and drop operation. The View should return {@code true} from its
      * {@link View#onDragEvent(DragEvent) onDragEvent()} handler method or
-     * {@link View.View.OnDragListener#onDrag(View,DragEvent) OnDragListener.onDrag()} listener
+     * {@link View.OnDragListener#onDrag(View,DragEvent) OnDragListener.onDrag()} listener
      * if it can accept a drop. The onDragEvent() or onDrag() methods usually inspect the metadata
      * from {@link #getClipDescription()} to determine if they can accept the data contained in
      * this drag. For an operation that doesn't represent data transfer, these methods may
@@ -190,7 +192,7 @@
      * within the View object's bounding box.
      * <p>
      * The View should return {@code true} from its {@link View#onDragEvent(DragEvent)}
-     * handler or {@link View.View.OnDragListener#onDrag(View,DragEvent) OnDragListener.onDrag()}
+     * handler or {@link View.OnDragListener#onDrag(View,DragEvent) OnDragListener.onDrag()}
      * listener if it accepted the drop, and {@code false} if it ignored the drop.
      * </p>
      * <p>
@@ -255,13 +257,13 @@
     }
 
     private void init(int action, float x, float y, ClipDescription description, ClipData data,
-            DropPermissionHolder dropPermissionHolder, Object localState, boolean result) {
+            IDropPermissions dropPermissions, Object localState, boolean result) {
         mAction = action;
         mX = x;
         mY = y;
         mClipDescription = description;
         mClipData = data;
-        mDropPermissionHolder = dropPermissionHolder;
+        mDropPermissions = dropPermissions;
         mLocalState = localState;
         mDragResult = result;
     }
@@ -272,13 +274,13 @@
 
     /** @hide */
     public static DragEvent obtain(int action, float x, float y, Object localState,
-            ClipDescription description, ClipData data, DropPermissionHolder dropPermissionHolder,
+            ClipDescription description, ClipData data, IDropPermissions dropPermissions,
             boolean result) {
         final DragEvent ev;
         synchronized (gRecyclerLock) {
             if (gRecyclerTop == null) {
                 ev = new DragEvent();
-                ev.init(action, x, y, description, data, dropPermissionHolder, localState, result);
+                ev.init(action, x, y, description, data, dropPermissions, localState, result);
                 return ev;
             }
             ev = gRecyclerTop;
@@ -289,7 +291,7 @@
         ev.mRecycled = false;
         ev.mNext = null;
 
-        ev.init(action, x, y, description, data, dropPermissionHolder, localState, result);
+        ev.init(action, x, y, description, data, dropPermissions, localState, result);
 
         return ev;
     }
@@ -297,7 +299,7 @@
     /** @hide */
     public static DragEvent obtain(DragEvent source) {
         return obtain(source.mAction, source.mX, source.mY, source.mLocalState,
-                source.mClipDescription, source.mClipData, source.mDropPermissionHolder,
+                source.mClipDescription, source.mClipData, source.mDropPermissions,
                 source.mDragResult);
     }
 
@@ -362,15 +364,9 @@
         return mClipDescription;
     }
 
-    /**
-     * Returns the {@link android.view.DropPermissionHolder} object that can be used by the drag
-     * listener to request and release the permissions for the content URIs contained in the
-     * {@link android.content.ClipData} object associated with this event.
-     * This method only returns valid data if the event action is {@link #ACTION_DROP}.
-     * @return The DropPermissionHolder object used to handle content URI permissions.
-     */
-    public DropPermissionHolder getDropPermissionHolder() {
-        return mDropPermissionHolder;
+    /** @hide */
+    public IDropPermissions getDropPermissions() {
+        return mDropPermissions;
     }
 
     /**
@@ -493,11 +489,11 @@
             dest.writeInt(1);
             mClipDescription.writeToParcel(dest, flags);
         }
-        if (mDropPermissionHolder == null) {
+        if (mDropPermissions == null) {
             dest.writeInt(0);
         } else {
             dest.writeInt(1);
-            mDropPermissionHolder.writeToParcel(dest, flags);
+            dest.writeStrongBinder(mDropPermissions.asBinder());
         }
     }
 
@@ -519,7 +515,7 @@
                 event.mClipDescription = ClipDescription.CREATOR.createFromParcel(in);
             }
             if (in.readInt() != 0) {
-                event.mDropPermissionHolder = DropPermissionHolder.CREATOR.createFromParcel(in);
+                event.mDropPermissions = IDropPermissions.Stub.asInterface(in.readStrongBinder());;
             }
             return event;
         }
diff --git a/core/java/android/view/DropPermissionHolder.java b/core/java/android/view/DropPermissionHolder.java
deleted file mode 100644
index 993e67a..0000000
--- a/core/java/android/view/DropPermissionHolder.java
+++ /dev/null
@@ -1,161 +0,0 @@
-package android.view;
-
-import android.app.IActivityManager;
-import android.content.ClipData;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import com.android.internal.view.IDropPermissionHolder;
-
-import java.util.ArrayList;
-
-public class DropPermissionHolder implements Parcelable {
-
-    IDropPermissionHolder mDropPermissionHolder;
-
-    /**
-     * Create a new DropPermissionHolder to be passed to the client with a DragEvent.
-     *
-     * @hide
-     */
-    public DropPermissionHolder(ClipData clipData, IActivityManager activityManager,
-            int sourceUid, String targetPackage, int mode, int sourceUserId, int targetUserId) {
-        mDropPermissionHolder = new LocalDropPermissionHolder(clipData, activityManager,
-                sourceUid, targetPackage, mode, sourceUserId, targetUserId);
-    }
-
-    private class LocalDropPermissionHolder extends IDropPermissionHolder.Stub {
-
-        private final IActivityManager mActivityManager;
-        private final int mSourceUid;
-        private final String mTargetPackage;
-        private final int mMode;
-        private final int mSourceUserId;
-        private final int mTargetUserId;
-
-        IBinder mPermissionOwner = null;
-
-        final private ArrayList<Uri> mUris = new ArrayList<Uri>();
-
-        LocalDropPermissionHolder(ClipData clipData, IActivityManager activityManager,
-                int sourceUid, String targetPackage, int mode, int sourceUserId, int targetUserId) {
-            mActivityManager = activityManager;
-            mSourceUid = sourceUid;
-            mTargetPackage = targetPackage;
-            mMode = mode;
-            mSourceUserId = sourceUserId;
-            mTargetUserId = targetUserId;
-
-            int N = clipData.getItemCount();
-            for (int i = 0; i != N; ++i) {
-                ClipData.Item item = clipData.getItemAt(i);
-
-                if (item.getUri() != null) {
-                    mUris.add(item.getUri());
-                }
-
-                Intent intent = item.getIntent();
-                if (intent != null && intent.getData() != null) {
-                    mUris.add(intent.getData());
-                }
-            }
-        }
-
-        @Override
-        public void grant() throws RemoteException {
-            if (mPermissionOwner != null) {
-                return;
-            }
-
-            mPermissionOwner = mActivityManager.newUriPermissionOwner("drop");
-
-            long origId = Binder.clearCallingIdentity();
-            try {
-                for (Uri mUri : mUris) {
-                    mActivityManager.grantUriPermissionFromOwner(
-                            mPermissionOwner, mSourceUid, mTargetPackage, mUri, mMode,
-                            mSourceUserId, mTargetUserId);
-                }
-            } finally {
-                Binder.restoreCallingIdentity(origId);
-            }
-
-        }
-
-        @Override
-        public void revoke() throws RemoteException {
-            if (mPermissionOwner == null) {
-                return;
-            }
-
-            for (Uri mUri : mUris) {
-                mActivityManager.revokeUriPermissionFromOwner(
-                        mPermissionOwner, mUri, mMode, mSourceUserId);
-            }
-
-            mPermissionOwner = null;
-        }
-    }
-
-    /**
-     * Request permissions granted by the activity which started the drag.
-     */
-    public void grant() {
-        try {
-            mDropPermissionHolder.grant();
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Revoke permissions granted by the {@link #grant()} call.
-     */
-    public void revoke() {
-        try {
-            mDropPermissionHolder.revoke();
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Returns information about the {@link android.os.Parcel} representation of this
-     * DropPermissionHolder object.
-     * @return Information about the {@link android.os.Parcel} representation.
-     */
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    /**
-     * Creates a {@link android.os.Parcel} object from this DropPermissionHolder object.
-     * @param dest A {@link android.os.Parcel} object in which to put the DropPermissionHolder
-     *             object.
-     * @param flags Flags to store in the Parcel.
-     */
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeStrongBinder(mDropPermissionHolder.asBinder());
-    }
-
-    DropPermissionHolder(Parcel in) {
-        mDropPermissionHolder = IDropPermissionHolder.Stub.asInterface(in.readStrongBinder());
-    }
-
-    /**
-     * A container for creating a DropPermissionHolder from a Parcel.
-     */
-    public static final Parcelable.Creator<DropPermissionHolder> CREATOR
-            = new Parcelable.Creator<DropPermissionHolder>() {
-        public DropPermissionHolder createFromParcel(Parcel in) {
-            return new DropPermissionHolder(in);
-        }
-        public DropPermissionHolder[] newArray(int size) {
-            return new DropPermissionHolder[size];
-        }
-    };
-}
diff --git a/core/java/android/view/DropPermissions.java b/core/java/android/view/DropPermissions.java
new file mode 100644
index 0000000..5411dad
--- /dev/null
+++ b/core/java/android/view/DropPermissions.java
@@ -0,0 +1,125 @@
+/*
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.view;
+
+import android.app.ActivityManagerNative;
+import android.os.IBinder;
+import android.os.RemoteException;
+import com.android.internal.view.IDropPermissions;
+import dalvik.system.CloseGuard;
+
+
+/**
+ * {@link DropPermissions} controls the access permissions for the content URIs associated with a
+ * {@link DragEvent}.
+ * <p>
+ * Permission are granted when this object is created by {@link
+ * android.app.Activity#requestDropPermissions(DragEvent) Activity.requestDropPermissions}.
+ * Which permissions are granted is defined by the set of flags passed to {@link
+ * View#startDragAndDrop(android.content.ClipData, View.DragShadowBuilder, Object, int)
+ * View.startDragAndDrop} by the app that started the drag operation.
+ * <p>
+ * The life cycle of the permissions is bound to the activity used to call {@link
+ * android.app.Activity#requestDropPermissions(DragEvent) requestDropPermissions}. The
+ * permissions are revoked when this activity is destroyed, or when {@link #release()} is called,
+ * whichever occurs first.
+ */
+public final class DropPermissions {
+
+    private final IDropPermissions mDropPermissions;
+
+    private IBinder mPermissionOwnerToken;
+
+    private final CloseGuard mCloseGuard = CloseGuard.get();
+
+    /**
+     * Create a new {@link DropPermissions} object to control the access permissions for content
+     * URIs associated with {@link DragEvent}.
+     * @param dragEvent Drag event
+     * @return {@link DropPermissions} object or null if there are no content URIs associated with
+     * the {@link DragEvent}.
+     * @hide
+     */
+    public static DropPermissions obtain(DragEvent dragEvent) {
+        if (dragEvent.getDropPermissions() == null) {
+            return null;
+        }
+        return new DropPermissions(dragEvent.getDropPermissions());
+    }
+
+    /** @hide */
+    private DropPermissions(IDropPermissions dropPermissions) {
+        mDropPermissions = dropPermissions;
+    }
+
+    /**
+     * Take the permissions and bind their lifetime to the activity.
+     * @param activityToken Binder pointing to an Activity instance to bind the lifetime to.
+     * @return True if permissions are successfully taken.
+     * @hide
+     */
+    public boolean take(IBinder activityToken) {
+        try {
+            mDropPermissions.take(activityToken);
+        } catch (RemoteException e) {
+            return false;
+        }
+        mCloseGuard.open("release");
+        return true;
+    }
+
+    /**
+     * Take the permissions. Must call {@link #release} explicitly.
+     * @return True if permissions are successfully taken.
+     * @hide
+     */
+    public boolean takeTransient() {
+        try {
+            mPermissionOwnerToken = ActivityManagerNative.getDefault().
+                    newUriPermissionOwner("drop");
+            mDropPermissions.takeTransient(mPermissionOwnerToken);
+        } catch (RemoteException e) {
+            return false;
+        }
+        mCloseGuard.open("release");
+        return true;
+    }
+
+    /**
+     * Revoke permissions explicitly.
+     */
+    public void release() {
+        try {
+            mDropPermissions.release();
+            mPermissionOwnerToken = null;
+        } catch (RemoteException e) {
+        }
+        mCloseGuard.close();
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            if (mCloseGuard != null) {
+                mCloseGuard.warnIfOpen();
+            }
+            release();
+        } finally {
+            super.finalize();
+        }
+    }
+}
diff --git a/core/java/android/view/FrameStatsObserver.java b/core/java/android/view/FrameStatsObserver.java
new file mode 100644
index 0000000..0add607
--- /dev/null
+++ b/core/java/android/view/FrameStatsObserver.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.annotation.NonNull;
+import android.util.Log;
+import android.os.Looper;
+import android.os.MessageQueue;
+
+import com.android.internal.util.VirtualRefBasePtr;
+
+import java.lang.NullPointerException;
+import java.lang.ref.WeakReference;
+import java.lang.SuppressWarnings;
+
+/**
+ * Provides streaming access to frame stats information from the rendering
+ * subsystem to apps.
+ *
+ * @hide
+ */
+public abstract class FrameStatsObserver {
+    private static final String TAG = "FrameStatsObserver";
+
+    private MessageQueue mMessageQueue;
+    private long[] mBuffer;
+
+    private FrameStats mFrameStats;
+
+    /* package */ ThreadedRenderer mRenderer;
+    /* package */ VirtualRefBasePtr mNative;
+
+    /**
+     * Containing class for frame statistics reported
+     * by the rendering subsystem.
+     */
+    public static class FrameStats {
+        /**
+         * Precise timing data for various milestones in a frame
+         * lifecycle.
+         *
+         * This data is exactly the same as what is returned by
+         * `adb shell dumpsys gfxinfo <PACKAGE_NAME> framestats`
+         *
+         * The fields reported may change from release to release.
+         *
+         * @see {@link http://developer.android.com/training/testing/performance.html}
+         * for a description of the fields present.
+         */
+        public long[] mTimingData;
+    }
+
+    /**
+     * Creates a FrameStatsObserver
+     *
+     * @param looper the looper to use when invoking callbacks
+     */
+    public FrameStatsObserver(@NonNull Looper looper) {
+        if (looper == null) {
+            throw new NullPointerException("looper cannot be null");
+        }
+
+        mMessageQueue = looper.getQueue();
+        if (mMessageQueue == null) {
+            throw new IllegalStateException("invalid looper, null message queue\n");
+        }
+
+        mFrameStats = new FrameStats();
+    }
+
+    /**
+     * Called on provided looper when frame stats data is available
+     * for the previous frame.
+     *
+     * Clients of this class must do as little work as possible within
+     * this callback, as the buffer is shared between the producer and consumer.
+     *
+     * If the consumer is still executing within this method when there is new
+     * data available that data will be dropped. The producer cannot
+     * wait on the consumer.
+     *
+     * @param data the newly available data
+     */
+    public abstract void onDataAvailable(FrameStats data);
+
+    /**
+     * Returns the number of reports dropped as a result of a slow
+     * consumer.
+     */
+    public long getDroppedReportCount() {
+        if (mRenderer == null) {
+            return 0;
+        }
+
+        return mRenderer.getDroppedFrameReportCount();
+    }
+
+    public boolean isRegistered() {
+        return mRenderer != null && mNative != null;
+    }
+
+    // === called by native === //
+    @SuppressWarnings("unused")
+    private void notifyDataAvailable() {
+        mFrameStats.mTimingData = mBuffer;
+        onDataAvailable(mFrameStats);
+    }
+}
diff --git a/core/java/android/view/IDockDividerVisibilityListener.aidl b/core/java/android/view/IDockDividerVisibilityListener.aidl
deleted file mode 100644
index a7d5cda..0000000
--- a/core/java/android/view/IDockDividerVisibilityListener.aidl
+++ /dev/null
@@ -1,27 +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.view;
-
-/**
-  * Listener for showing/hiding of the dock divider. Will fire when an app is shown in side by side
-  * mode and a divider should be shown.
-  *
-  * @hide
-  */
-oneway interface IDockDividerVisibilityListener {
-    void onDockDividerVisibilityChanged(boolean visible);
-}
diff --git a/core/java/android/view/IDockedStackListener.aidl b/core/java/android/view/IDockedStackListener.aidl
new file mode 100644
index 0000000..77fa7e2
--- /dev/null
+++ b/core/java/android/view/IDockedStackListener.aidl
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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;
+
+/**
+  * Listener for showing/hiding of the dock divider. Will fire when an app is shown in side by side
+  * mode and a divider should be shown.
+  *
+  * @hide
+  */
+oneway interface IDockedStackListener {
+
+    /**
+     * Will fire when an app is shown in side by side mode and a divider should be shown.
+     */
+    void onDividerVisibilityChanged(boolean visible);
+
+    /**
+     * Called when the docked stack gets created or removed.
+     */
+    void onDockedStackExistsChanged(boolean exists);
+}
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 9e478c1..3688d50 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -25,6 +25,8 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 
+import com.android.internal.os.IResultReceiver;
+
 /**
  * API back to a client window that the Window Manager uses to inform it of
  * interesting things happening.
@@ -47,7 +49,7 @@
 
     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);
+            in Configuration newConfig, in Rect backDropFrame, boolean forceLayout);
     void moved(int newX, int newY);
     void dispatchAppVisibility(boolean visible);
     void dispatchGetNewSurface();
@@ -74,6 +76,11 @@
     void dispatchDragEvent(in DragEvent event);
 
     /**
+     * Pointer icon events
+     */
+    void updatePointerIcon(float x, float y);
+
+    /**
      * System chrome visibility changes
      */
     void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
@@ -83,4 +90,9 @@
      * Called for non-application windows when the enter animation has completed.
      */
     void dispatchWindowShown();
+
+    /**
+     * Called when Keyboard Shortcuts are requested for the window.
+     */
+    void requestAppKeyboardShortcuts(IResultReceiver receiver);
 }
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 7a379d50..b045c17 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -17,6 +17,7 @@
 package android.view;
 
 import com.android.internal.app.IAssistScreenshotReceiver;
+import com.android.internal.os.IResultReceiver;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
 
@@ -29,7 +30,7 @@
 import android.os.IRemoteCallback;
 import android.view.IApplicationToken;
 import android.view.IAppTransitionAnimationSpecsFuture;
-import android.view.IDockDividerVisibilityListener;
+import android.view.IDockedStackListener;
 import android.view.IOnKeyguardExitResult;
 import android.view.IRotationWatcher;
 import android.view.IWindowSession;
@@ -101,11 +102,14 @@
      *                   the task doesn't exist yet.
      * @param configuration Configuration that is being used with this task.
      * @param cropWindowsToStack True if the app windows should be cropped to the stack bounds.
+     * @param alwaysFocusable True if the app windows are always focusable regardless of the stack
+     *                        they are in.
      */
     void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
             int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
             int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
-            in Rect taskBounds, in Configuration configuration, boolean cropWindowsToStack);
+            in Rect taskBounds, in Configuration configuration, boolean cropWindowsToStack,
+            boolean alwaysFocusable);
     /**
      *
      * @param token The token we are adding to the input task Id.
@@ -354,7 +358,24 @@
     void setDockedStackResizing(boolean resizing);
 
     /**
-     * Registers a listener that will be called when the dock divider changes its visibility.
+     * Registers a listener that will be called when the dock divider changes its visibility or when
+     * the docked stack gets added/removed.
      */
-    void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener);
+    void registerDockedStackListener(IDockedStackListener listener);
+
+    /**
+     * Updates the dim layer used while resizing.
+     *
+     * @param visible Whether the dim layer should be visible.
+     * @param targetStackId The id of the task stack the dim layer should be placed on.
+     * @param alpha The translucency of the dim layer, between 0 and 1.
+     */
+    void setResizeDimLayer(boolean visible, int targetStackId, float alpha);
+
+    /**
+     * Requests Keyboard Shortcuts from the displayed window.
+     *
+     * @param receiver The receiver to deliver the results to.
+     */
+    void requestAppKeyboardShortcuts(IResultReceiver receiver);
 }
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index b3cd8c11..1703ed1 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -81,6 +81,8 @@
      * so complex relayout of the window should not happen based on them.
      * @param outOutsets Rect in which is placed the dead area of the screen that we would like to
      * treat as real display. Example of such area is a chin in some models of wearable devices.
+     * @param outBackdropFrame Rect which is used draw the resizing background during a resize
+     * operation.
      * @param outConfiguration New configuration of window, if it is now
      * becoming visible and the global configuration has changed since it
      * was last displayed.
@@ -93,7 +95,8 @@
             int requestedWidth, int requestedHeight, int viewVisibility,
             int flags, out Rect outFrame, out Rect outOverscanInsets,
             out Rect outContentInsets, out Rect outVisibleInsets, out Rect outStableInsets,
-            out Rect outOutsets, out Configuration outConfig, out Surface outSurface);
+            out Rect outOutsets, out Rect outBackdropFrame, out Configuration outConfig,
+            out Surface outSurface);
 
     /**
      *  Position a window relative to it's parent (attached) window without triggering
@@ -120,6 +123,14 @@
     void repositionChild(IWindow childWindow, int left, int top, int right, int bottom,
             long deferTransactionUntilFrame, out Rect outFrame);
 
+    /*
+     * Notify the window manager that an application is relaunching and
+     * child windows should be prepared for replacement.
+     *
+     * @param appToken The application
+     */
+    void prepareToReplaceChildren(IBinder appToken);
+
     /**
      * If a call to relayout() asked to have the surface destroy deferred,
      * it must call this once it is okay to destroy that surface.
@@ -175,8 +186,8 @@
     /**
      * Initiate the drag operation itself
      */
-    boolean performDrag(IWindow window, IBinder dragToken, float touchX, float touchY,
-            float thumbCenterX, float thumbCenterY, in ClipData data);
+    boolean performDrag(IWindow window, IBinder dragToken, int touchSource,
+            float touchX, float touchY, float thumbCenterX, float thumbCenterY, in ClipData data);
 
    /**
      * Report the result of a drop action targeted to the given window.
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index f037958..51e1f4b 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1856,6 +1856,9 @@
             case KeyEvent.KEYCODE_MENU:
             case KeyEvent.KEYCODE_WAKEUP:
             case KeyEvent.KEYCODE_PAIRING:
+            case KeyEvent.KEYCODE_STEM_1:
+            case KeyEvent.KEYCODE_STEM_2:
+            case KeyEvent.KEYCODE_STEM_3:
                 return true;
         }
         return false;
diff --git a/core/java/android/view/KeyboardShortcutGroup.java b/core/java/android/view/KeyboardShortcutGroup.java
new file mode 100644
index 0000000..57d07c0
--- /dev/null
+++ b/core/java/android/view/KeyboardShortcutGroup.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.view;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+/**
+ * A group of {@link KeyboardShortcutInfo}.
+ */
+public final class KeyboardShortcutGroup implements Parcelable {
+    private final CharSequence mLabel;
+    private final List<KeyboardShortcutInfo> mItems;
+    // The system group looks different UI wise.
+    private boolean mSystemGroup;
+
+    /**
+     * @param label The title to be used for this group, or null if there is none.
+     * @param items The set of items to be included.
+     */
+    public KeyboardShortcutGroup(@Nullable CharSequence label,
+            @NonNull List<KeyboardShortcutInfo> items) {
+        mLabel = label;
+        mItems = new ArrayList<>(checkNotNull(items));
+    }
+
+    /**
+     * @param label The title to be used for this group, or null if there is none.
+     */
+    public KeyboardShortcutGroup(@Nullable CharSequence label) {
+        this(label, Collections.<KeyboardShortcutInfo>emptyList());
+    }
+
+    /**
+     * @param label The title to be used for this group, or null if there is none.
+     * @param items The set of items to be included.
+     * @param isSystemGroup Set this to {@code true} if this is s system group.
+     * @hide
+     */
+    public KeyboardShortcutGroup(@Nullable CharSequence label,
+            @NonNull List<KeyboardShortcutInfo> items, boolean isSystemGroup) {
+        mLabel = label;
+        mItems = new ArrayList<>(checkNotNull(items));
+        mSystemGroup = isSystemGroup;
+    }
+
+    /**
+     * @param label The title to be used for this group, or null if there is none.
+     * @param isSystemGroup Set this to {@code true} if this is s system group.
+     * @hide
+     */
+    public KeyboardShortcutGroup(@Nullable CharSequence label, boolean isSystemGroup) {
+        this(label, Collections.<KeyboardShortcutInfo>emptyList(), isSystemGroup);
+    }
+
+    private KeyboardShortcutGroup(Parcel source) {
+        mItems = new ArrayList<>();
+        mLabel = source.readCharSequence();
+        source.readTypedList(mItems, KeyboardShortcutInfo.CREATOR);
+        mSystemGroup = source.readInt() == 1;
+    }
+
+    /**
+     * Returns the label to be used to describe this group.
+     */
+    public CharSequence getLabel() {
+        return mLabel;
+    }
+
+    /**
+     * Returns the list of items included in this group.
+     */
+    public List<KeyboardShortcutInfo> getItems() {
+        return mItems;
+    }
+
+    /** @hide **/
+    public boolean isSystemGroup() {
+        return mSystemGroup;
+    }
+
+    /**
+     * Adds an item to the existing list.
+     *
+     * @param item The item to be added.
+     */
+    public void addItem(KeyboardShortcutInfo item) {
+        mItems.add(item);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeCharSequence(mLabel);
+        dest.writeTypedList(mItems);
+        dest.writeInt(mSystemGroup ? 1 : 0);
+    }
+
+    public static final Creator<KeyboardShortcutGroup> CREATOR =
+            new Creator<KeyboardShortcutGroup>() {
+        public KeyboardShortcutGroup createFromParcel(Parcel source) {
+            return new KeyboardShortcutGroup(source);
+        }
+        public KeyboardShortcutGroup[] newArray(int size) {
+            return new KeyboardShortcutGroup[size];
+        }
+    };
+}
diff --git a/core/java/android/view/KeyboardShortcutInfo.java b/core/java/android/view/KeyboardShortcutInfo.java
new file mode 100644
index 0000000..2c9006d
--- /dev/null
+++ b/core/java/android/view/KeyboardShortcutInfo.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.graphics.drawable.Icon;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import static com.android.internal.util.Preconditions.checkArgument;
+import static java.lang.Character.MIN_VALUE;
+
+/**
+ * Information about a Keyboard Shortcut.
+ */
+public final class KeyboardShortcutInfo implements Parcelable {
+    private final CharSequence mLabel;
+    private final Icon mIcon;
+    private final char mBaseCharacter;
+    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 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}.
+     *
+     * @hide
+     */
+    public KeyboardShortcutInfo(
+            @Nullable CharSequence label, @Nullable Icon icon, char baseCharacter, int modifiers) {
+        mLabel = label;
+        mIcon = icon;
+        checkArgument(baseCharacter != MIN_VALUE);
+        mBaseCharacter = baseCharacter;
+        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 baseCharacter The character that triggers the shortcut.
+     * @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, char baseCharacter, int modifiers) {
+        mLabel = label;
+        checkArgument(baseCharacter != MIN_VALUE);
+        mBaseCharacter = baseCharacter;
+        mModifiers = modifiers;
+        mIcon = null;
+    }
+
+    private KeyboardShortcutInfo(Parcel source) {
+        mLabel = source.readCharSequence();
+        mIcon = (Icon) source.readParcelable(null);
+        mBaseCharacter = (char) source.readInt();
+        mModifiers = source.readInt();
+    }
+
+    /**
+     * Returns the label to be used to describe this shortcut.
+     */
+    @Nullable
+    public CharSequence getLabel() {
+        return mLabel;
+    }
+
+    /**
+     * Returns the icon to be used to describe this shortcut.
+     *
+     * @hide
+     */
+    @Nullable
+    public Icon getIcon() {
+        return mIcon;
+    }
+
+    /**
+     * Returns the base character that, combined with the modifiers, triggers this shortcut.
+     */
+    public char getBaseCharacter() {
+        return mBaseCharacter;
+    }
+
+    /**
+     * Returns the set of modifiers that, combined with the key, trigger this shortcut.
+     */
+    public int getModifiers() {
+        return mModifiers;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeCharSequence(mLabel);
+        dest.writeParcelable(mIcon, 0);
+        dest.writeInt(mBaseCharacter);
+        dest.writeInt(mModifiers);
+    }
+
+    public static final Creator<KeyboardShortcutInfo> CREATOR =
+            new Creator<KeyboardShortcutInfo>() {
+        public KeyboardShortcutInfo createFromParcel(Parcel source) {
+            return new KeyboardShortcutInfo(source);
+        }
+        public KeyboardShortcutInfo[] newArray(int size) {
+            return new KeyboardShortcutInfo[size];
+        }
+    };
+}
\ No newline at end of file
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index aa29636..914bd56 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -555,6 +555,26 @@
         }
     }
 
+    private static final ClassLoader BOOT_CLASS_LOADER = LayoutInflater.class.getClassLoader();
+
+    private final boolean verifyClassLoader(Constructor<? extends View> constructor) {
+        final ClassLoader constructorLoader = constructor.getDeclaringClass().getClassLoader();
+        if (constructorLoader == BOOT_CLASS_LOADER) {
+            // fast path for boot class loader (most common case?) - always ok
+            return true;
+        }
+        // in all normal cases (no dynamic code loading), we will exit the following loop on the
+        // first iteration (i.e. when the declaring classloader is the contexts class loader).
+        ClassLoader cl = mContext.getClassLoader();
+        do {
+            if (constructorLoader == cl) {
+                return true;
+            }
+            cl = cl.getParent();
+        } while (cl != null);
+        return false;
+    }
+
     /**
      * Low-level function for instantiating a view by name. This attempts to
      * instantiate a view class of the given <var>name</var> found in this
@@ -575,6 +595,10 @@
     public final View createView(String name, String prefix, AttributeSet attrs)
             throws ClassNotFoundException, InflateException {
         Constructor<? extends View> constructor = sConstructorMap.get(name);
+        if (constructor != null && !verifyClassLoader(constructor)) {
+            constructor = null;
+            sConstructorMap.remove(name);
+        }
         Class<? extends View> clazz = null;
 
         try {
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 0195dec..a0f5142 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -973,10 +973,42 @@
      * </p>
      *
      * @see #getAxisValue(int, int)
+     * {@hide}
      */
     public static final int AXIS_SCROLL = 26;
 
     /**
+     * Axis constant: The movement of x position of a motion event.
+     * <p>
+     * <ul>
+     * <li>For a mouse, reports a difference of x position between the previous position.
+     * This is useful when pointer is captured, in that case the mouse pointer doesn't change
+     * the location but this axis reports the difference which allows the app to see
+     * how the mouse is moved.
+     * </ul>
+     * </p>
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int, int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_RELATIVE_X = 27;
+
+    /**
+     * Axis constant: The movement of y position of a motion event.
+     * <p>
+     * This is similar to {@link #AXIS_RELATIVE_X} but for y-axis.
+     * </p>
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int, int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_RELATIVE_Y = 28;
+
+    /**
      * Axis constant: Generic 1 axis of a motion event.
      * The interpretation of a generic axis is device-specific.
      *
@@ -1187,6 +1219,8 @@
         names.append(AXIS_DISTANCE, "AXIS_DISTANCE");
         names.append(AXIS_TILT, "AXIS_TILT");
         names.append(AXIS_SCROLL, "AXIS_SCROLL");
+        names.append(AXIS_RELATIVE_X, "AXIS_REALTIVE_X");
+        names.append(AXIS_RELATIVE_Y, "AXIS_REALTIVE_Y");
         names.append(AXIS_GENERIC_1, "AXIS_GENERIC_1");
         names.append(AXIS_GENERIC_2, "AXIS_GENERIC_2");
         names.append(AXIS_GENERIC_3, "AXIS_GENERIC_3");
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 54fa764..1c0ea0f 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -25,6 +25,8 @@
 import android.widget.RemoteViews;
 import android.widget.TextView;
 
+import com.android.internal.R;
+
 import java.util.ArrayList;
 
 /**
@@ -44,6 +46,7 @@
     private ImageView mExpandButton;
     private View mIcon;
     private TextView mChildCount;
+    private View mProfileBadge;
     private int mIconColor;
     private int mOriginalNotificationColor;
     private boolean mGroupHeader;
@@ -76,6 +79,7 @@
         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);
     }
 
     @Override
@@ -120,12 +124,29 @@
             }
             totalWidth = givenWidth;
         }
+        if (mProfileBadge.getVisibility() != View.GONE) {
+            totalWidth = givenWidth;
+        }
         setMeasuredDimension(totalWidth, givenHeight);
     }
 
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
+        if (mProfileBadge.getVisibility() != View.GONE) {
+            int paddingEnd = getPaddingEnd();
+            if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
+                mProfileBadge.layout(paddingEnd,
+                        mProfileBadge.getTop(),
+                        paddingEnd + mProfileBadge.getMeasuredWidth(),
+                        mProfileBadge.getBottom());
+            } else {
+                mProfileBadge.layout(getWidth() - paddingEnd - mProfileBadge.getMeasuredWidth(),
+                        mProfileBadge.getTop(),
+                        getWidth() - paddingEnd,
+                        mProfileBadge.getBottom());
+            }
+        }
         updateTouchListener();
     }
 
@@ -305,4 +326,20 @@
         }
         return this;
     }
+
+    public ImageView getExpandButton() {
+        return mExpandButton;
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+
+    public boolean isInTouchRect(float x, float y) {
+        if (mExpandClickListener == null) {
+            return false;
+        }
+        return mTouchListener.isInside(x, y);
+    }
 }
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 394660f..ef50fdc 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -57,6 +57,7 @@
     private static native int nativeGetHeight(long nativeObject);
 
     private static native long nativeGetNextFrameNumber(long nativeObject);
+    private static native int nativeSetScalingMode(long nativeObject, int scalingMode);
 
     public static final Parcelable.Creator<Surface> CREATOR =
             new Parcelable.Creator<Surface>() {
@@ -95,6 +96,21 @@
     private HwuiContext mHwuiContext;
 
     /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({SCALING_MODE_FREEZE, SCALING_MODE_SCALE_TO_WINDOW,
+                    SCALING_MODE_SCALE_CROP, SCALING_MODE_NO_SCALE_CROP})
+    public @interface ScalingMode {}
+    // From system/window.h
+    /** @hide */
+    static final int SCALING_MODE_FREEZE = 0;
+    /** @hide */
+    static final int SCALING_MODE_SCALE_TO_WINDOW = 1;
+    /** @hide */
+    static final int SCALING_MODE_SCALE_CROP = 2;
+    /** @hide */
+    static final int SCALING_MODE_NO_SCALE_CROP = 3;
+
+    /** @hide */
     @IntDef({ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270})
     @Retention(RetentionPolicy.SOURCE)
     public @interface Rotation {}
@@ -500,6 +516,20 @@
     }
 
     /**
+     * Set the scaling mode to be used for this surfaces buffers
+     * @hide
+     */
+    void setScalingMode(@ScalingMode int scalingMode) {
+        synchronized (mLock) {
+            checkNotReleasedLocked();
+            int err = nativeSetScalingMode(mNativeObject, scalingMode);
+            if (err != 0) {
+                throw new IllegalArgumentException("Invalid scaling mode: " + scalingMode);
+            }
+        }
+    }
+
+    /**
      * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or
      * when a SurfaceTexture could not successfully be allocated.
      */
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 589c0dc..5b48e28 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -107,6 +107,7 @@
     final Rect mContentInsets = new Rect();
     final Rect mStableInsets = new Rect();
     final Rect mOutsets = new Rect();
+    final Rect mBackdropFrame = new Rect();
     final Configuration mConfiguration = new Configuration();
 
     static final int KEEP_SCREEN_ON_MSG = 1;
@@ -498,7 +499,8 @@
                     mLayout.privateFlags |=
                             WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
                 }
-                mLayout.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+                mLayout.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION
+                    | WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
 
                 if (mWindow == null) {
                     Display display = getDisplay();
@@ -529,8 +531,8 @@
                             visible ? VISIBLE : GONE,
                             WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY,
                             mWinFrame, mOverscanInsets, mContentInsets,
-                            mVisibleInsets, mStableInsets, mOutsets, mConfiguration,
-                            mNewSurface);
+                            mVisibleInsets, mStableInsets, mOutsets, mBackdropFrame,
+                            mConfiguration, mNewSurface);
                     if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
                         reportDrawNeeded = true;
                     }
@@ -578,8 +580,19 @@
                     }
 
                     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;
@@ -685,7 +698,7 @@
         @Override
         public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
                 Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
-                Configuration newConfig, Rect backDropRect) {
+                Configuration newConfig, Rect backDropRect, boolean forceLayout) {
             SurfaceView surfaceView = mSurfaceView.get();
             if (surfaceView != null) {
                 if (DEBUG) Log.v(
@@ -698,7 +711,8 @@
                         surfaceView.mReportDrawNeeded = true;
                         surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
                     } else if (surfaceView.mWinFrame.width() != frame.width()
-                            || surfaceView.mWinFrame.height() != frame.height()) {
+                            || surfaceView.mWinFrame.height() != frame.height()
+                            || forceLayout) {
                         surfaceView.mUpdateWindowNeeded = true;
                         surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
                     }
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 6b60be9..1be4810 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -297,7 +297,7 @@
 
     @Override
     public void setForeground(Drawable foreground) {
-        if (foreground != null) {
+        if (foreground != null && !sTextureViewIgnoresDrawableSetters) {
             throw new UnsupportedOperationException(
                     "TextureView doesn't support displaying a foreground drawable");
         }
@@ -305,7 +305,7 @@
 
     @Override
     public void setBackgroundDrawable(Drawable background) {
-        if (background != null) {
+        if (background != null && !sTextureViewIgnoresDrawableSetters) {
             throw new UnsupportedOperationException(
                     "TextureView doesn't support displaying a background drawable");
         }
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index f2a4d7b..78a63a6 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -24,7 +24,9 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Binder;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Message;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -34,12 +36,14 @@
 import android.view.View.AttachInfo;
 
 import com.android.internal.R;
+import com.android.internal.util.VirtualRefBasePtr;
 
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.HashSet;
 
 /**
  * Hardware renderer that proxies the rendering to a render thread. Most calls
@@ -339,6 +343,8 @@
     private boolean mEnabled;
     private boolean mRequested = true;
 
+    private HashSet<FrameStatsObserver> mFrameStatsObservers;
+
     ThreadedRenderer(Context context, boolean translucent) {
         final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0);
         mLightY = a.getDimension(R.styleable.Lighting_lightY, 0);
@@ -422,9 +428,10 @@
      * @return True if the initialization was successful, false otherwise.
      */
     boolean initialize(Surface surface) throws OutOfResourcesException {
+        boolean status = !mInitialized;
         mInitialized = true;
         updateEnabledState(surface);
-        boolean status = nInitialize(mNativeProxy, surface);
+        nInitialize(mNativeProxy, surface);
         return status;
     }
 
@@ -946,6 +953,31 @@
         }
     }
 
+    void addFrameStatsObserver(FrameStatsObserver fso) {
+        if (mFrameStatsObservers == null) {
+            mFrameStatsObservers = new HashSet<>();
+        }
+
+        long nativeFso = nAddFrameStatsObserver(mNativeProxy, fso);
+        fso.mRenderer = this;
+        fso.mNative = new VirtualRefBasePtr(nativeFso);
+        mFrameStatsObservers.add(fso);
+    }
+
+    void removeFrameStatsObserver(FrameStatsObserver fso) {
+        if (!mFrameStatsObservers.remove(fso)) {
+            throw new IllegalArgumentException("attempt to remove FrameStatsObserver that was never added");
+        }
+
+        nRemoveFrameStatsObserver(mNativeProxy, fso.mNative.get());
+        fso.mRenderer = null;
+        fso.mNative = null;
+    }
+
+    long getDroppedFrameReportCount() {
+        return nGetDroppedFrameReportCount(mNativeProxy);
+    }
+
     static native void setupShadersDiskCache(String cacheFile);
 
     private static native void nSetAtlas(long nativeProxy, GraphicBuffer buffer, long[] map);
@@ -958,7 +990,7 @@
     private static native boolean nLoadSystemProperties(long nativeProxy);
     private static native void nSetName(long nativeProxy, String name);
 
-    private static native boolean nInitialize(long nativeProxy, Surface window);
+    private static native void nInitialize(long nativeProxy, Surface window);
     private static native void nUpdateSurface(long nativeProxy, Surface window);
     private static native boolean nPauseSurface(long nativeProxy, Surface window);
     private static native void nSetup(long nativeProxy, int width, int height,
@@ -999,4 +1031,8 @@
     private static native void nDrawRenderNode(long nativeProxy, long rootRenderNode);
     private static native void nSetContentDrawBounds(long nativeProxy, int left,
              int top, int right, int bottom);
+
+    private static native long nAddFrameStatsObserver(long nativeProxy, FrameStatsObserver fso);
+    private static native void nRemoveFrameStatsObserver(long nativeProxy, long nativeFso);
+    private static native long nGetDroppedFrameReportCount(long nativeProxy);
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index afa6c78..dd0887f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -24,6 +24,7 @@
 import android.annotation.FloatRange;
 import android.annotation.IdRes;
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.LayoutRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -79,10 +80,11 @@
 import android.util.SuperNotCalledException;
 import android.util.TypedValue;
 import android.view.ContextMenu.ContextMenuInfo;
-import android.view.AccessibilityIterators.TextSegmentIterator;
 import android.view.AccessibilityIterators.CharacterTextSegmentIterator;
-import android.view.AccessibilityIterators.WordTextSegmentIterator;
 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;
@@ -98,16 +100,17 @@
 import android.widget.Checkable;
 import android.widget.FrameLayout;
 import android.widget.ScrollBarDrawable;
-
 import static android.os.Build.VERSION_CODES.*;
 import static java.lang.Math.max;
 
 import com.android.internal.R;
 import com.android.internal.util.Predicate;
 import com.android.internal.view.menu.MenuBuilder;
+import com.android.internal.widget.ScrollBarUtils;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 
+import java.lang.NullPointerException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
@@ -812,6 +815,12 @@
     private static boolean sLayoutParamsAlwaysChanged = false;
 
     /**
+     * Allow setForeground/setBackground to be called (and ignored) on a textureview,
+     * without throwing
+     */
+    static boolean sTextureViewIgnoresDrawableSetters = false;
+
+    /**
      * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when
      * calling setFlags.
      */
@@ -3694,6 +3703,11 @@
     private ViewPropertyAnimator mAnimator = null;
 
     /**
+     * List of FrameStatsObservers pending registration when mAttachInfo is null.
+     */
+    private ArrayList<FrameStatsObserver> mPendingFrameStatsObservers;
+
+    /**
      * Flag indicating that a drag can cross window boundaries.  When
      * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called
      * with this flag set, all visible applications will be able to participate
@@ -3984,6 +3998,10 @@
             // work. Partial layout breaks this assumption.
             sLayoutParamsAlwaysChanged = targetSdkVersion <= M;
 
+            // Prior to N, TextureView would silently ignore calls to setBackground/setForeground.
+            // On N+, we throw, but that breaks compatibility with apps that use these methods.
+            sTextureViewIgnoresDrawableSetters = targetSdkVersion <= M;
+
             sCompatibilityDone = true;
         }
     }
@@ -5110,6 +5128,88 @@
         return mVerticalScrollbarPosition;
     }
 
+    boolean isOnScrollbar(float x, float y) {
+        if (mScrollCache == null) {
+            return false;
+        }
+        x += getScrollX();
+        y += getScrollY();
+        if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) {
+            final Rect bounds = mScrollCache.mScrollBarBounds;
+            getVerticalScrollBarBounds(bounds);
+            if (bounds.contains((int)x, (int)y)) {
+                return true;
+            }
+        }
+        if (isHorizontalScrollBarEnabled()) {
+            final Rect bounds = mScrollCache.mScrollBarBounds;
+            getHorizontalScrollBarBounds(bounds);
+            if (bounds.contains((int)x, (int)y)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    boolean isOnScrollbarThumb(float x, float y) {
+        return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y);
+    }
+
+    private boolean isOnVerticalScrollbarThumb(float x, float y) {
+        if (mScrollCache == null) {
+            return false;
+        }
+        if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) {
+            x += getScrollX();
+            y += getScrollY();
+            final Rect bounds = mScrollCache.mScrollBarBounds;
+            getVerticalScrollBarBounds(bounds);
+            final int range = computeVerticalScrollRange();
+            final int offset = computeVerticalScrollOffset();
+            final int extent = computeVerticalScrollExtent();
+            final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(),
+                    extent, range);
+            final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength,
+                    extent, range, offset);
+            final int thumbTop = bounds.top + thumbOffset;
+            if (x >= bounds.left && x <= bounds.right && y >= thumbTop
+                    && y <= thumbTop + thumbLength) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isOnHorizontalScrollbarThumb(float x, float y) {
+        if (mScrollCache == null) {
+            return false;
+        }
+        if (isHorizontalScrollBarEnabled()) {
+            x += getScrollX();
+            y += getScrollY();
+            final Rect bounds = mScrollCache.mScrollBarBounds;
+            getHorizontalScrollBarBounds(bounds);
+            final int range = computeHorizontalScrollRange();
+            final int offset = computeHorizontalScrollOffset();
+            final int extent = computeHorizontalScrollExtent();
+            final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(),
+                    extent, range);
+            final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength,
+                    extent, range, offset);
+            final int thumbLeft = bounds.left + thumbOffset;
+            if (x >= thumbLeft && x <= thumbLeft + thumbLength && y >= bounds.top
+                    && y <= bounds.bottom) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    boolean isDraggingScrollBar() {
+        return mScrollCache != null
+                && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING;
+    }
+
     /**
      * Sets the state of all scroll indicators.
      * <p>
@@ -5369,6 +5469,58 @@
     }
 
     /**
+     * Set an observer to collect stats for each frame rendered for this view.
+     *
+     * @hide
+     */
+    public void addFrameStatsObserver(FrameStatsObserver fso) {
+        if (mAttachInfo != null) {
+            if (mAttachInfo.mHardwareRenderer != null) {
+                mAttachInfo.mHardwareRenderer.addFrameStatsObserver(fso);
+            } else {
+                Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats");
+            }
+        } else {
+            if (mPendingFrameStatsObservers == null) {
+                mPendingFrameStatsObservers = new ArrayList<>();
+            }
+
+            mPendingFrameStatsObservers.add(fso);
+        }
+    }
+
+    /**
+     * Remove observer configured to collect frame stats for this view.
+     *
+     * @hide
+     */
+    public void removeFrameStatsObserver(FrameStatsObserver fso) {
+        ThreadedRenderer renderer = getHardwareRenderer();
+
+        if (mPendingFrameStatsObservers != null) {
+            mPendingFrameStatsObservers.remove(fso);
+        }
+
+        if (renderer != null) {
+            renderer.removeFrameStatsObserver(fso);
+        }
+    }
+
+    private void registerPendingFrameStatsObservers() {
+        if (mPendingFrameStatsObservers != null) {
+            ThreadedRenderer renderer = getHardwareRenderer();
+            if (renderer != null) {
+                for (FrameStatsObserver fso : mPendingFrameStatsObservers) {
+                    renderer.addFrameStatsObserver(fso);
+                }
+            } else {
+                Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats");
+            }
+            mPendingFrameStatsObservers = null;
+        }
+    }
+
+    /**
      * Call this view's OnClickListener, if it is defined.  Performs all normal
      * actions associated with clicking: reporting accessibility event, playing
      * a sound, etc.
@@ -5725,8 +5877,11 @@
      * <p>A View should call this if it maintains some notion of which part
      * of its content is interesting.  For example, a text editing view
      * should call this when its cursor moves.
+     * <p>The Rectangle passed into this method should be in the View's content coordinate space.
+     * It should not be affected by which part of the View is currently visible or its scroll
+     * position.
      *
-     * @param rectangle The rectangle.
+     * @param rectangle The rectangle in the View's content coordinate space
      * @return Whether any parent scrolled.
      */
     public boolean requestRectangleOnScreen(Rect rectangle) {
@@ -5740,11 +5895,13 @@
      * <p>A View should call this if it maintains some notion of which part
      * of its content is interesting.  For example, a text editing view
      * should call this when its cursor moves.
-     *
+     * <p>The Rectangle passed into this method should be in the View's content coordinate space.
+     * It should not be affected by which part of the View is currently visible or its scroll
+     * position.
      * <p>When <code>immediate</code> is set to true, scrolling will not be
      * animated.
      *
-     * @param rectangle The rectangle.
+     * @param rectangle The rectangle in the View's content coordinate space
      * @param immediate True to forbid animated scrolling, false otherwise
      * @return Whether any parent scrolled.
      */
@@ -5764,24 +5921,16 @@
             rectangle.set((int) position.left, (int) position.top,
                     (int) position.right, (int) position.bottom);
 
-            scrolled |= parent.requestChildRectangleOnScreen(child,
-                    rectangle, immediate);
-
-            if (!child.hasIdentityMatrix()) {
-                child.getMatrix().mapRect(position);
-            }
-
-            position.offset(child.mLeft, child.mTop);
+            scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate);
 
             if (!(parent instanceof View)) {
                 break;
             }
 
-            View parentView = (View) parent;
+            // move it from child's content coordinate space to parent's content coordinate space
+            position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY());
 
-            position.offset(-parentView.getScrollX(), -parentView.getScrollY());
-
-            child = parentView;
+            child = (View) parent;
             parent = child.getParent();
         }
 
@@ -6680,6 +6829,68 @@
         }
 
         info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN);
+        populateAccessibilityNodeInfoDrawingOrderInParent(info);
+    }
+
+    /**
+     * Determine the order in which this view will be drawn relative to its siblings for a11y
+     *
+     * @param info The info whose drawing order should be populated
+     */
+    private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) {
+        int drawingOrderInParent = 1;
+        // Iterate up the hierarchy if parents are not important for a11y
+        View viewAtDrawingLevel = this;
+        final ViewParent parent = getParentForAccessibility();
+        while (viewAtDrawingLevel != parent) {
+            final ViewParent currentParent = viewAtDrawingLevel.getParent();
+            if (!(currentParent instanceof ViewGroup)) {
+                // Should only happen for the Decor
+                drawingOrderInParent = 0;
+                break;
+            } else {
+                final ViewGroup parentGroup = (ViewGroup) currentParent;
+                final int childCount = parentGroup.getChildCount();
+                if (childCount > 1) {
+                    List<View> preorderedList = parentGroup.buildOrderedChildList();
+                    if (preorderedList != null) {
+                        final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel);
+                        for (int i = 0; i < childDrawIndex; i++) {
+                            drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i));
+                        }
+                    } else {
+                        final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel);
+                        final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled();
+                        final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup
+                                .getChildDrawingOrder(childCount, childIndex) : childIndex;
+                        final int numChildrenToIterate = customOrder ? childCount : childDrawIndex;
+                        if (childDrawIndex != 0) {
+                            for (int i = 0; i < numChildrenToIterate; i++) {
+                                final int otherDrawIndex = (customOrder ?
+                                        parentGroup.getChildDrawingOrder(childCount, i) : i);
+                                if (otherDrawIndex < childDrawIndex) {
+                                    drawingOrderInParent +=
+                                            numViewsForAccessibility(parentGroup.getChildAt(i));
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            viewAtDrawingLevel = (View) currentParent;
+        }
+        info.setDrawingOrder(drawingOrderInParent);
+    }
+
+    private static int numViewsForAccessibility(View view) {
+        if (view != null) {
+            if (view.includeForAccessibility()) {
+                return 1;
+            } else if (view instanceof ViewGroup) {
+                return ((ViewGroup) view).getNumChildrenForAccessibility();
+            }
+        }
+        return 0;
     }
 
     private View findLabelForView(View view, int labeledId) {
@@ -9586,6 +9797,9 @@
         }
 
         if (onFilterTouchEventForSecurity(event)) {
+            if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
+                result = true;
+            }
             //noinspection SimplifiableIfStatement
             ListenerInfo li = mListenerInfo;
             if (li != null && li.mOnTouchListener != null
@@ -10450,6 +10664,11 @@
             }
         }
 
+        if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE)
+                && event.isFromSource(InputDevice.SOURCE_MOUSE)
+                && isOnScrollbar(event.getX(), event.getY())) {
+            awakenScrollBars();
+        }
         if (isHoverable()) {
             switch (action) {
                 case MotionEvent.ACTION_HOVER_ENTER:
@@ -10553,6 +10772,110 @@
     }
 
     /**
+     * Handles scroll bar dragging by mouse input.
+     *
+     * @hide
+     * @param event The motion event.
+     *
+     * @return true if the event was handled as a scroll bar dragging, false otherwise.
+     */
+    protected boolean handleScrollBarDragging(MotionEvent event) {
+        if (mScrollCache == null) {
+            return false;
+        }
+        final float x = event.getX();
+        final float y = event.getY();
+        final int action = event.getAction();
+        if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING
+                && action != MotionEvent.ACTION_DOWN)
+                    || !event.isFromSource(InputDevice.SOURCE_MOUSE)
+                    || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) {
+            mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING;
+            return false;
+        }
+
+        switch (action) {
+            case MotionEvent.ACTION_MOVE:
+                if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) {
+                    return false;
+                }
+                if (mScrollCache.mScrollBarDraggingState
+                        == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) {
+                    final Rect bounds = mScrollCache.mScrollBarBounds;
+                    getVerticalScrollBarBounds(bounds);
+                    final int range = computeVerticalScrollRange();
+                    final int offset = computeVerticalScrollOffset();
+                    final int extent = computeVerticalScrollExtent();
+
+                    final int thumbLength = ScrollBarUtils.getThumbLength(
+                            bounds.height(), bounds.width(), extent, range);
+                    final int thumbOffset = ScrollBarUtils.getThumbOffset(
+                            bounds.height(), thumbLength, extent, range, offset);
+
+                    final float diff = y - mScrollCache.mScrollBarDraggingPos;
+                    final float maxThumbOffset = bounds.height() - thumbLength;
+                    final float newThumbOffset =
+                            Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset);
+                    final int height = getHeight();
+                    if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0
+                            && height > 0 && extent > 0) {
+                        final int newY = Math.round((range - extent)
+                                / ((float)extent / height) * (newThumbOffset / maxThumbOffset));
+                        if (newY != getScrollY()) {
+                            mScrollCache.mScrollBarDraggingPos = y;
+                            setScrollY(newY);
+                        }
+                    }
+                    return true;
+                }
+                if (mScrollCache.mScrollBarDraggingState
+                        == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) {
+                    final Rect bounds = mScrollCache.mScrollBarBounds;
+                    getHorizontalScrollBarBounds(bounds);
+                    final int range = computeHorizontalScrollRange();
+                    final int offset = computeHorizontalScrollOffset();
+                    final int extent = computeHorizontalScrollExtent();
+
+                    final int thumbLength = ScrollBarUtils.getThumbLength(
+                            bounds.width(), bounds.height(), extent, range);
+                    final int thumbOffset = ScrollBarUtils.getThumbOffset(
+                            bounds.width(), thumbLength, extent, range, offset);
+
+                    final float diff = x - mScrollCache.mScrollBarDraggingPos;
+                    final float maxThumbOffset = bounds.width() - thumbLength;
+                    final float newThumbOffset =
+                            Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset);
+                    final int width = getWidth();
+                    if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0
+                            && width > 0 && extent > 0) {
+                        final int newX = Math.round((range - extent)
+                                / ((float)extent / width) * (newThumbOffset / maxThumbOffset));
+                        if (newX != getScrollX()) {
+                            mScrollCache.mScrollBarDraggingPos = x;
+                            setScrollX(newX);
+                        }
+                    }
+                    return true;
+                }
+            case MotionEvent.ACTION_DOWN:
+                if (isOnVerticalScrollbarThumb(x, y)) {
+                    mScrollCache.mScrollBarDraggingState =
+                            ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR;
+                    mScrollCache.mScrollBarDraggingPos = y;
+                    return true;
+                }
+                if (isOnHorizontalScrollbarThumb(x, y)) {
+                    mScrollCache.mScrollBarDraggingState =
+                            ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR;
+                    mScrollCache.mScrollBarDraggingPos = x;
+                    return true;
+                }
+        }
+        mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING;
+        return false;
+    }
+
+    /**
      * Implement this method to handle touch screen motion events.
      * <p>
      * If this method is used to detect click actions, it is recommended that
@@ -10585,7 +10908,6 @@
                     || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
                     || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE);
         }
-
         if (mTouchDelegate != null) {
             if (mTouchDelegate.onTouchEvent(event)) {
                 return true;
@@ -12482,8 +12804,7 @@
      * Determines whether the given point, in local coordinates is inside the view.
      */
     /*package*/ final boolean pointInView(float localX, float localY) {
-        return localX >= 0 && localX < (mRight - mLeft)
-                && localY >= 0 && localY < (mBottom - mTop);
+        return pointInView(localX, localY, 0);
     }
 
     /**
@@ -14147,6 +14468,45 @@
         }
     }
 
+    private void getHorizontalScrollBarBounds(Rect bounds) {
+        final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0;
+        final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled()
+                && !isVerticalScrollBarHidden();
+        final int size = getHorizontalScrollbarHeight();
+        final int verticalScrollBarGap = drawVerticalScrollBar ?
+                getVerticalScrollbarWidth() : 0;
+        final int width = mRight - mLeft;
+        final int height = mBottom - mTop;
+        bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside);
+        bounds.left = mScrollX + (mPaddingLeft & inside);
+        bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap;
+        bounds.bottom = bounds.top + size;
+    }
+
+    private void getVerticalScrollBarBounds(Rect bounds) {
+        final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0;
+        final int size = getVerticalScrollbarWidth();
+        int verticalScrollbarPosition = mVerticalScrollbarPosition;
+        if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) {
+            verticalScrollbarPosition = isLayoutRtl() ?
+                    SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT;
+        }
+        final int width = mRight - mLeft;
+        final int height = mBottom - mTop;
+        switch (verticalScrollbarPosition) {
+            default:
+            case SCROLLBAR_POSITION_RIGHT:
+                bounds.left = mScrollX + width - size - (mUserPaddingRight & inside);
+                break;
+            case SCROLLBAR_POSITION_LEFT:
+                bounds.left = mScrollX + (mUserPaddingLeft & inside);
+                break;
+        }
+        bounds.top = mScrollY + (mPaddingTop & inside);
+        bounds.right = bounds.left + size;
+        bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside);
+    }
+
     /**
      * <p>Request the drawing of the horizontal and the vertical scrollbar. The
      * scrollbars are painted only if they have been awakened first.</p>
@@ -14194,80 +14554,36 @@
                 cache.scrollBar.mutate().setAlpha(255);
             }
 
-
-            final int viewFlags = mViewFlags;
-
-            final boolean drawHorizontalScrollBar =
-                (viewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL;
-            final boolean drawVerticalScrollBar =
-                (viewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL
-                && !isVerticalScrollBarHidden();
+            final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled();
+            final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled()
+                    && !isVerticalScrollBarHidden();
 
             if (drawVerticalScrollBar || drawHorizontalScrollBar) {
-                final int width = mRight - mLeft;
-                final int height = mBottom - mTop;
-
                 final ScrollBarDrawable scrollBar = cache.scrollBar;
 
-                final int scrollX = mScrollX;
-                final int scrollY = mScrollY;
-                final int inside = (viewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0;
-
-                int left;
-                int top;
-                int right;
-                int bottom;
-
                 if (drawHorizontalScrollBar) {
-                    int size = scrollBar.getSize(false);
-                    if (size <= 0) {
-                        size = cache.scrollBarSize;
-                    }
-
                     scrollBar.setParameters(computeHorizontalScrollRange(),
                                             computeHorizontalScrollOffset(),
                                             computeHorizontalScrollExtent(), false);
-                    final int verticalScrollBarGap = drawVerticalScrollBar ?
-                            getVerticalScrollbarWidth() : 0;
-                    top = scrollY + height - size - (mUserPaddingBottom & inside);
-                    left = scrollX + (mPaddingLeft & inside);
-                    right = scrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap;
-                    bottom = top + size;
-                    onDrawHorizontalScrollBar(canvas, scrollBar, left, top, right, bottom);
+                    final Rect bounds = cache.mScrollBarBounds;
+                    getHorizontalScrollBarBounds(bounds);
+                    onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top,
+                            bounds.right, bounds.bottom);
                     if (invalidate) {
-                        invalidate(left, top, right, bottom);
+                        invalidate(bounds);
                     }
                 }
 
                 if (drawVerticalScrollBar) {
-                    int size = scrollBar.getSize(true);
-                    if (size <= 0) {
-                        size = cache.scrollBarSize;
-                    }
-
                     scrollBar.setParameters(computeVerticalScrollRange(),
                                             computeVerticalScrollOffset(),
                                             computeVerticalScrollExtent(), true);
-                    int verticalScrollbarPosition = mVerticalScrollbarPosition;
-                    if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) {
-                        verticalScrollbarPosition = isLayoutRtl() ?
-                                SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT;
-                    }
-                    switch (verticalScrollbarPosition) {
-                        default:
-                        case SCROLLBAR_POSITION_RIGHT:
-                            left = scrollX + width - size - (mUserPaddingRight & inside);
-                            break;
-                        case SCROLLBAR_POSITION_LEFT:
-                            left = scrollX + (mUserPaddingLeft & inside);
-                            break;
-                    }
-                    top = scrollY + (mPaddingTop & inside);
-                    right = left + size;
-                    bottom = scrollY + height - (mUserPaddingBottom & inside);
-                    onDrawVerticalScrollBar(canvas, scrollBar, left, top, right, bottom);
+                    final Rect bounds = cache.mScrollBarBounds;
+                    getVerticalScrollBarBounds(bounds);
+                    onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top,
+                            bounds.right, bounds.bottom);
                     if (invalidate) {
-                        invalidate(left, top, right, bottom);
+                        invalidate(bounds);
                     }
                 }
             }
@@ -14716,6 +15032,7 @@
         destroyDrawingCache();
 
         cleanupDraw();
+        releasePointerCapture();
         mCurrentAnimation = null;
     }
 
@@ -14829,6 +15146,9 @@
             info.mTreeObserver.merge(mFloatingTreeObserver);
             mFloatingTreeObserver = null;
         }
+
+        registerPendingFrameStatsObservers();
+
         if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) {
             mAttachInfo.mScrollContainers.add(this);
             mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED;
@@ -17248,8 +17568,10 @@
      */
     @CallSuper
     protected boolean verifyDrawable(Drawable who) {
-        return who == mBackground || (mScrollCache != null && mScrollCache.scrollBar == who)
-                || (mForegroundInfo != null && mForegroundInfo.mDrawable == 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.
+        return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who);
     }
 
     /**
@@ -19983,7 +20305,7 @@
                 root.getLastTouchPoint(shadowSize);
 
                 okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, mAttachInfo.mDragToken,
-                        shadowSize.x, shadowSize.y,
+                        root.getLastTouchSource(), shadowSize.x, shadowSize.y,
                         shadowTouchPoint.x, shadowTouchPoint.y, data);
                 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay);
             }
@@ -21201,6 +21523,9 @@
      * @see PointerIcon
      */
     public PointerIcon getPointerIcon(MotionEvent event, float x, float y) {
+        if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) {
+            return PointerIcon.getSystemIcon(mContext, PointerIcon.STYLE_ARROW);
+        }
         return mPointerIcon;
     }
 
@@ -21212,6 +21537,56 @@
         mPointerIcon = pointerIcon;
     }
 
+    /**
+     * Request capturing further mouse events.
+     *
+     * When the view captures, the mouse pointer icon will disappear and will not change its
+     * position. Further mouse events will come to the capturing view, and the mouse movements
+     * will can be detected through {@link MotionEvent#AXIS_RELATIVE_X} and
+     * {@link MotionEvent#AXIS_RELATIVE_Y}. Non-mouse events (touchscreens, or stylus) will not
+     * be affected.
+     *
+     * The capture will be released through {@link #releasePointerCapture()}, or will be lost
+     * automatically when the view or containing window disappear.
+     *
+     * @return true when succeeds.
+     * @see #releasePointerCapture()
+     * @see #hasPointerCapture()
+     */
+    public void setPointerCapture() {
+        final ViewRootImpl viewRootImpl = getViewRootImpl();
+        if (viewRootImpl != null) {
+            viewRootImpl.setPointerCapture(this);
+        }
+    }
+
+
+    /**
+     * Release the current capture of mouse events.
+     *
+     * If the view does not have the capture, it will do nothing.
+     * @see #setPointerCapture()
+     * @see #hasPointerCapture()
+     */
+    public void releasePointerCapture() {
+        final ViewRootImpl viewRootImpl = getViewRootImpl();
+        if (viewRootImpl != null) {
+            viewRootImpl.releasePointerCapture(this);
+        }
+    }
+
+    /**
+     * Checks the capture status of mouse events.
+     *
+     * @return true if the view has the capture.
+     * @see #setPointerCapture()
+     * @see #hasPointerCapture()
+     */
+    public boolean hasPointerCapture() {
+        final ViewRootImpl viewRootImpl = getViewRootImpl();
+        return (viewRootImpl != null) && viewRootImpl.hasPointerCapture(this);
+    }
+
     //
     // Properties
     //
@@ -21438,6 +21813,11 @@
         private static final int MODE_SHIFT = 30;
         private static final int MODE_MASK  = 0x3 << MODE_SHIFT;
 
+        /** @hide */
+        @IntDef({UNSPECIFIED, EXACTLY, AT_MOST})
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface MeasureSpecMode {}
+
         /**
          * Measure specification mode: The parent has not imposed any constraint
          * on the child. It can be whatever size it wants.
@@ -21478,7 +21858,8 @@
          * @param mode the mode of the measure specification
          * @return the measure specification based on size and mode
          */
-        public static int makeMeasureSpec(int size, int mode) {
+        public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size,
+                                          @MeasureSpecMode int mode) {
             if (sUseBrokenMakeMeasureSpec) {
                 return size + mode;
             } else {
@@ -21507,7 +21888,9 @@
          *         {@link android.view.View.MeasureSpec#AT_MOST} or
          *         {@link android.view.View.MeasureSpec#EXACTLY}
          */
+        @MeasureSpecMode
         public static int getMode(int measureSpec) {
+            //noinspection ResourceType
             return (measureSpec & MODE_MASK);
         }
 
@@ -21646,6 +22029,13 @@
     }
 
     /**
+     * @hide
+     */
+    public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data) {
+        // Do nothing.
+    }
+
+    /**
      * Interface definition for a callback to be invoked when a hardware key event is
      * dispatched to this view. The callback will be invoked before the key event is
      * given to the view. This is only useful for hardware keyboards; a software input
@@ -22407,6 +22797,15 @@
 
         private int mLastColor;
 
+        public final Rect mScrollBarBounds = new Rect();
+
+        public static final int NOT_DRAGGING = 0;
+        public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1;
+        public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2;
+        public int mScrollBarDraggingState = NOT_DRAGGING;
+
+        public float mScrollBarDraggingPos = 0;
+
         public ScrollabilityCache(ViewConfiguration configuration, View host) {
             fadingEdgeLength = configuration.getScaledFadingEdgeLength();
             scrollBarSize = configuration.getScaledScrollBarSize();
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index cd93dab..3fe6b8e 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -59,6 +59,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+
 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
 
 /**
@@ -700,9 +701,6 @@
         mGroupFlags |= (focusability & FLAG_MASK_FOCUSABILITY);
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     void handleFocusGainInternal(int direction, Rect previouslyFocusedRect) {
         if (mFocused != null) {
@@ -712,9 +710,7 @@
         super.handleFocusGainInternal(direction, previouslyFocusedRect);
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    @Override
     public void requestChildFocus(View child, View focused) {
         if (DBG) {
             System.out.println(this + " requestChildFocus()");
@@ -739,9 +735,7 @@
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    @Override
     public void focusableViewAvailable(View v) {
         if (mParent != null
                 // shortcut: don't report a new focusable view if we block our descendants from
@@ -760,9 +754,7 @@
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    @Override
     public boolean showContextMenuForChild(View originalView) {
         return mParent != null && mParent.showContextMenuForChild(originalView);
     }
@@ -772,9 +764,6 @@
         return mParent != null && mParent.showContextMenuForChild(originalView, x, y);
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
         if ((mGroupFlags & FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED) == 0) {
@@ -791,9 +780,6 @@
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public ActionMode startActionModeForChild(
             View originalView, ActionMode.Callback callback, int type) {
@@ -848,6 +834,7 @@
      * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and
      *        FOCUS_RIGHT, or 0 for not applicable.
      */
+    @Override
     public View focusSearch(View focused, int direction) {
         if (isRootNamespace()) {
             // root namespace means we should consider ourselves the top of the
@@ -860,16 +847,11 @@
         return null;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    @Override
     public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
         return false;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
         ViewParent parent = mParent;
@@ -921,6 +903,7 @@
     /**
      * Called when a child view has changed whether or not it is tracking transient state.
      */
+    @Override
     public void childHasTransientStateChanged(View child, boolean childHasTransientState) {
         final boolean oldHasTransientState = hasTransientState();
         if (childHasTransientState) {
@@ -945,18 +928,13 @@
         return mChildCountWithTransientState > 0 || super.hasTransientState();
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public boolean dispatchUnhandledMove(View focused, int direction) {
         return mFocused != null &&
                 mFocused.dispatchUnhandledMove(focused, direction);
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    @Override
     public void clearChildFocus(View child) {
         if (DBG) {
             System.out.println(this + " clearChildFocus()");
@@ -968,9 +946,6 @@
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public void clearFocus() {
         if (DBG) {
@@ -985,9 +960,6 @@
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     void unFocus(View focused) {
         if (DBG) {
@@ -1054,9 +1026,6 @@
         return null;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public boolean hasFocusable() {
         if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
@@ -1083,9 +1052,6 @@
         return false;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
         final int focusableCount = views.size();
@@ -1195,9 +1161,6 @@
         return null;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public void dispatchWindowFocusChanged(boolean hasFocus) {
         super.dispatchWindowFocusChanged(hasFocus);
@@ -1208,9 +1171,6 @@
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public void addTouchables(ArrayList<View> views) {
         super.addTouchables(views);
@@ -1239,9 +1199,6 @@
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public void dispatchDisplayHint(int hint) {
         super.dispatchDisplayHint(hint);
@@ -1287,9 +1244,6 @@
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     protected void dispatchVisibilityChanged(View changedView, int visibility) {
         super.dispatchVisibilityChanged(changedView, visibility);
@@ -1300,9 +1254,6 @@
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public void dispatchWindowVisibilityChanged(int visibility) {
         super.dispatchWindowVisibilityChanged(visibility);
@@ -1313,9 +1264,6 @@
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public void dispatchConfigurationChanged(Configuration newConfig) {
         super.dispatchConfigurationChanged(newConfig);
@@ -1326,9 +1274,7 @@
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    @Override
     public void recomputeViewAttributes(View child) {
         if (mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
             ViewParent parent = mParent;
@@ -1350,9 +1296,7 @@
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    @Override
     public void bringChildToFront(View child) {
         final int index = indexOfChild(child);
         if (index >= 0) {
@@ -1369,9 +1313,6 @@
         return mLocalPoint;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     // TODO: Write real docs
     @Override
     public boolean dispatchDragEvent(DragEvent event) {
@@ -1419,8 +1360,9 @@
 
         case DragEvent.ACTION_DRAG_ENDED: {
             // Release the bookkeeping now that the drag lifecycle has ended
-            if (mChildrenInterestedInDrag != null) {
-                for (View child : mChildrenInterestedInDrag) {
+            final HashSet<View> childrenInterestedInDrag = mChildrenInterestedInDrag;
+            if (childrenInterestedInDrag != null) {
+                for (View child : childrenInterestedInDrag) {
                     // If a child was interested in the ongoing drag, it's told that it's over
                     if (child.dispatchDragEvent(event)) {
                         retval = true;
@@ -1428,12 +1370,11 @@
                     child.mPrivateFlags2 &= ~View.DRAG_MASK;
                     child.refreshDrawableState();
                 }
-
-                mChildrenInterestedInDrag.clear();
-                if (mCurrentDragStartEvent != null) {
-                    mCurrentDragStartEvent.recycle();
-                    mCurrentDragStartEvent = null;
-                }
+                childrenInterestedInDrag.clear();
+            }
+            if (mCurrentDragStartEvent != null) {
+                mCurrentDragStartEvent.recycle();
+                mCurrentDragStartEvent = null;
             }
 
             if (mIsInterestedInDrag) {
@@ -1461,6 +1402,10 @@
                 root.setDragFocus(target);
 
                 final int action = event.mAction;
+                // Position should not be available for ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED.
+                event.mX = 0;
+                event.mY = 0;
+
                 // If we've dragged off of a child view or this window, send it the EXITED message
                 if (mCurrentDragView != null) {
                     final View view = mCurrentDragView;
@@ -1489,6 +1434,8 @@
                     }
                 }
                 event.mAction = action;  // restore the event's original state
+                event.mX = tx;
+                event.mY = ty;
             }
 
             // Dispatch the actual drag location notice, localized into its coordinates
@@ -1631,9 +1578,6 @@
         return changed;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public boolean dispatchKeyEventPreIme(KeyEvent event) {
         if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
@@ -1646,9 +1590,6 @@
         return false;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
         if (mInputEventConsistencyVerifier != null) {
@@ -1673,9 +1614,6 @@
         return false;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public boolean dispatchKeyShortcutEvent(KeyEvent event) {
         if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
@@ -1688,9 +1626,6 @@
         return false;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public boolean dispatchTrackballEvent(MotionEvent event) {
         if (mInputEventConsistencyVerifier != null) {
@@ -1717,6 +1652,9 @@
 
     @Override
     public PointerIcon getPointerIcon(MotionEvent event, float x, float y) {
+        if (isOnScrollbarThumb(x, y) || isDraggingScrollBar()) {
+            return PointerIcon.getSystemIcon(mContext, PointerIcon.STYLE_ARROW);
+        }
         // Check what the child under the pointer says about the pointer.
         final int childrenCount = mChildrenCount;
         if (childrenCount != 0) {
@@ -1725,10 +1663,9 @@
                     && isChildrenDrawingOrderEnabled();
             final View[] children = mChildren;
             for (int i = childrenCount - 1; i >= 0; i--) {
-                final int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
-                final View child = (preorderedList == null)
-                        ? children[childIndex] : preorderedList.get(childIndex);
-                PointF point = getLocalPoint();
+                final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
+                final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
+                final PointF point = getLocalPoint();
                 if (isTransformedTouchPointInView(x, y, child, point)) {
                     final PointerIcon pointerIcon = child.getPointerIcon(event, point.x, point.y);
                     if (pointerIcon != null) {
@@ -1744,9 +1681,22 @@
         return super.getPointerIcon(event, x, y);
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    private int getAndVerifyPreorderedIndex(int childrenCount, int i, boolean customOrder) {
+        final int childIndex;
+        if (customOrder) {
+            final int childIndex1 = getChildDrawingOrder(childrenCount, i);
+            if (childIndex1 >= childrenCount) {
+                throw new IndexOutOfBoundsException("getChildDrawingOrder() "
+                        + "returned invalid index " + childIndex1
+                        + " (child count is " + childrenCount + ")");
+            }
+            childIndex = childIndex1;
+        } else {
+            childIndex = i;
+        }
+        return childIndex;
+    }
+
     @SuppressWarnings({"ConstantConditions"})
     @Override
     protected boolean dispatchHoverEvent(MotionEvent event) {
@@ -1774,9 +1724,10 @@
                 final View[] children = mChildren;
                 HoverTarget lastHoverTarget = null;
                 for (int i = childrenCount - 1; i >= 0; i--) {
-                    int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
-                    final View child = (preorderedList == null)
-                            ? children[childIndex] : preorderedList.get(childIndex);
+                    final int childIndex = getAndVerifyPreorderedIndex(
+                            childrenCount, i, customOrder);
+                    final View child = getAndVerifyPreorderedView(
+                            preorderedList, children, childIndex);
                     if (!canViewReceivePointerEvents(child)
                             || !isTransformedTouchPointInView(x, y, child, null)) {
                         continue;
@@ -2027,7 +1978,7 @@
      * hover exit event in {@link #onHoverEvent} and then the hovered child will
      * receive a hover enter event.
      * </p><p>
-     * The default implementation always returns false.
+     * The default implementation handles mouse hover on the scroll bars.
      * </p>
      *
      * @param event The motion event that describes the hover.
@@ -2035,6 +1986,15 @@
      * and prevent its children from receiving it.
      */
     public boolean onInterceptHoverEvent(MotionEvent event) {
+        if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
+            final int action = event.getAction();
+            final float x = event.getX();
+            final float y = event.getY();
+            if ((action == MotionEvent.ACTION_HOVER_MOVE
+                    || action == MotionEvent.ACTION_HOVER_ENTER) && isOnScrollbar(x, y)) {
+                return true;
+            }
+        }
         return false;
     }
 
@@ -2045,9 +2005,6 @@
         return MotionEvent.obtainNoHistory(event);
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     protected boolean dispatchGenericPointerEvent(MotionEvent event) {
         // Send the event to the child under the pointer.
@@ -2061,9 +2018,8 @@
                     && isChildrenDrawingOrderEnabled();
             final View[] children = mChildren;
             for (int i = childrenCount - 1; i >= 0; i--) {
-                int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
-                final View child = (preorderedList == null)
-                        ? children[childIndex] : preorderedList.get(childIndex);
+                final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
+                final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
                 if (!canViewReceivePointerEvents(child)
                         || !isTransformedTouchPointInView(x, y, child, null)) {
                     continue;
@@ -2081,9 +2037,6 @@
         return super.dispatchGenericPointerEvent(event);
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     protected boolean dispatchGenericFocusedEvent(MotionEvent event) {
         // Send the event to the focused child or to this view group if it has focus.
@@ -2124,9 +2077,6 @@
         return handled;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
         if (mInputEventConsistencyVerifier != null) {
@@ -2216,10 +2166,10 @@
                                 && isChildrenDrawingOrderEnabled();
                         final View[] children = mChildren;
                         for (int i = childrenCount - 1; i >= 0; i--) {
-                            final int childIndex = customOrder
-                                    ? getChildDrawingOrder(childrenCount, i) : i;
-                            final View child = (preorderedList == null)
-                                    ? children[childIndex] : preorderedList.get(childIndex);
+                            final int childIndex = getAndVerifyPreorderedIndex(
+                                    childrenCount, i, customOrder);
+                            final View child = getAndVerifyPreorderedView(
+                                    preorderedList, children, childIndex);
 
                             // If there is a view that has accessibility focus we want it
                             // to get the event first and if not handled we will perform a
@@ -2397,7 +2347,7 @@
      * Resets the cancel next up flag.
      * Returns true if the flag was previously set.
      */
-    private static boolean resetCancelNextUpFlag(View view) {
+    private static boolean resetCancelNextUpFlag(@NonNull View view) {
         if ((view.mPrivateFlags & PFLAG_CANCEL_NEXT_UP_EVENT) != 0) {
             view.mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
             return true;
@@ -2450,7 +2400,7 @@
      * Gets the touch target for specified child view.
      * Returns null if not found.
      */
-    private TouchTarget getTouchTarget(View child) {
+    private TouchTarget getTouchTarget(@NonNull View child) {
         for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
             if (target.child == child) {
                 return target;
@@ -2463,8 +2413,8 @@
      * Adds a touch target for specified child to the beginning of the list.
      * Assumes the target child is not already present.
      */
-    private TouchTarget addTouchTarget(View child, int pointerIdBits) {
-        TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
+    private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) {
+        final TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
         target.next = mFirstTouchTarget;
         mFirstTouchTarget = target;
         return target;
@@ -2526,7 +2476,7 @@
      * Returns true if a child view can receive pointer events.
      * @hide
      */
-    private static boolean canViewReceivePointerEvents(View child) {
+    private static boolean canViewReceivePointerEvents(@NonNull View child) {
         return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
                 || child.getAnimation() != null;
     }
@@ -2721,9 +2671,7 @@
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    @Override
     public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
 
         if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
@@ -2781,6 +2729,12 @@
      * messages will be delivered here.
      */
     public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (ev.isFromSource(InputDevice.SOURCE_MOUSE)
+                && ev.getAction() == MotionEvent.ACTION_DOWN
+                && ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY)
+                && isOnScrollbarThumb(ev.getX(), ev.getY())) {
+            return true;
+        }
         return false;
     }
 
@@ -2893,9 +2847,6 @@
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     void dispatchAttachedToWindow(AttachInfo info, int visibility) {
         mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
@@ -2962,6 +2913,7 @@
      * adds in all child views of the view group, in addition to calling the default View
      * implementation.
      */
+    @Override
     public void dispatchProvideStructure(ViewStructure structure) {
         super.dispatchProvideStructure(structure);
         if (!isAssistBlocked()) {
@@ -2976,7 +2928,7 @@
                     for (int i=0; i<childrenCount; i++) {
                         int childIndex;
                         try {
-                            childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
+                            childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
                         } catch (IndexOutOfBoundsException e) {
                             childIndex = i;
                             if (mContext.getApplicationInfo().targetSdkVersion
@@ -3021,9 +2973,10 @@
                                 throw e;
                             }
                         }
-                        final View child = (preorderedList == null)
-                                ? children[childIndex] : preorderedList.get(childIndex);
-                        ViewStructure cstructure = structure.newChild(i);
+
+                        final View child = getAndVerifyPreorderedView(
+                                preorderedList, children, childIndex);
+                        final ViewStructure cstructure = structure.newChild(i);
                         child.dispatchProvideStructure(cstructure);
                     }
                 }
@@ -3031,6 +2984,21 @@
         }
     }
 
+    private static View getAndVerifyPreorderedView(ArrayList<View> preorderedList, View[] children,
+            int childIndex) {
+        final View child;
+        if (preorderedList != null) {
+            child = preorderedList.get(childIndex);
+            if (child == null) {
+                throw new RuntimeException("Invalid preorderedList contained null child at index "
+                        + childIndex);
+            }
+        } else {
+            child = children[childIndex];
+        }
+        return child;
+    }
+
     /** @hide */
     @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
@@ -3083,6 +3051,26 @@
     }
 
     /**
+     * Counts the number of children of this View that will be sent to an accessibility service.
+     *
+     * @return The number of children an {@code AccessibilityNodeInfo} rooted at this View
+     * would have.
+     */
+    int getNumChildrenForAccessibility() {
+        int numChildrenForAccessibility = 0;
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+            if (child.includeForAccessibility()) {
+                numChildrenForAccessibility++;
+            } else if (child instanceof ViewGroup) {
+                numChildrenForAccessibility += ((ViewGroup) child)
+                        .getNumChildrenForAccessibility();
+            }
+        }
+        return numChildrenForAccessibility;
+    }
+
+    /**
      * {@inheritDoc}
      *
      * <p>Subclasses should always call <code>super.onNestedPrePerformAccessibilityAction</code></p>
@@ -3098,9 +3086,6 @@
         return false;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     void dispatchDetachedFromWindow() {
         // If we still have a touch target, we are still in the process of
@@ -3152,9 +3137,6 @@
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
         super.dispatchSaveInstanceState(container);
@@ -3180,9 +3162,6 @@
         super.dispatchSaveInstanceState(container);
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
         super.dispatchRestoreInstanceState(container);
@@ -3255,6 +3234,7 @@
         return mLayoutMode == LAYOUT_MODE_OPTICAL_BOUNDS;
     }
 
+    @Override
     Insets computeOpticalInsets() {
         if (isLayoutModeOptical()) {
             int left = 0;
@@ -3386,9 +3366,6 @@
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     protected void dispatchDraw(Canvas canvas) {
         boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode);
@@ -3459,9 +3436,9 @@
                     transientIndex = -1;
                 }
             }
-            int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
-            final View child = (preorderedList == null)
-                    ? children[childIndex] : preorderedList.get(childIndex);
+
+            final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
+            final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
             if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
                 more |= drawChild(canvas, child, drawingTime);
             }
@@ -3514,6 +3491,7 @@
             // drawChild() after the animation is over
             mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;
             final Runnable end = new Runnable() {
+               @Override
                public void run() {
                    notifyAnimationListener();
                }
@@ -3580,21 +3558,21 @@
      * children.
      */
     ArrayList<View> buildOrderedChildList() {
-        final int count = mChildrenCount;
-        if (count <= 1 || !hasChildWithZ()) return null;
+        final int childrenCount = mChildrenCount;
+        if (childrenCount <= 1 || !hasChildWithZ()) return null;
 
         if (mPreSortedChildren == null) {
-            mPreSortedChildren = new ArrayList<View>(count);
+            mPreSortedChildren = new ArrayList<>(childrenCount);
         } else {
-            mPreSortedChildren.ensureCapacity(count);
+            mPreSortedChildren.ensureCapacity(childrenCount);
         }
 
-        final boolean useCustomOrder = isChildrenDrawingOrderEnabled();
-        for (int i = 0; i < mChildrenCount; i++) {
+        final boolean customOrder = isChildrenDrawingOrderEnabled();
+        for (int i = 0; i < childrenCount; i++) {
             // add next child (in child order) to end of list
-            int childIndex = useCustomOrder ? getChildDrawingOrder(mChildrenCount, i) : i;
-            View nextChild = mChildren[childIndex];
-            float currentZ = nextChild.getZ();
+            final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
+            final View nextChild = mChildren[childIndex];
+            final float currentZ = nextChild.getZ();
 
             // insert ahead of any Views with greater Z
             int insertIndex = i;
@@ -3612,6 +3590,7 @@
 
         if (mAnimationListener != null) {
            final Runnable end = new Runnable() {
+               @Override
                public void run() {
                    mAnimationListener.onAnimationEnd(mLayoutAnimationController.getAnimation());
                }
@@ -3761,9 +3740,6 @@
         return hasBooleanFlag(FLAG_CLIP_TO_PADDING);
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public void dispatchSetSelected(boolean selected) {
         final View[] children = mChildren;
@@ -3773,9 +3749,6 @@
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public void dispatchSetActivated(boolean activated) {
         final View[] children = mChildren;
@@ -4180,6 +4153,7 @@
      * @param child the child view to add
      * @param params the layout parameters to set on the child
      */
+    @Override
     public void addView(View child, LayoutParams params) {
         addView(child, -1, params);
     }
@@ -4212,9 +4186,7 @@
         addViewInner(child, index, params, false);
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    @Override
     public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
         if (!checkLayoutParams(params)) {
             throw new IllegalArgumentException("Invalid LayoutParams supplied to " + this);
@@ -4225,9 +4197,6 @@
         view.setLayoutParams(params);
     }
 
-    /**
-     * {@inheritDoc}
-     */
     protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
         return  p != null;
     }
@@ -4574,6 +4543,7 @@
      * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
      * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
      */
+    @Override
     public void removeView(View view) {
         if (removeViewInternal(view)) {
             requestLayout();
@@ -5075,6 +5045,7 @@
      * Don't call or override this method. It is used for the implementation of
      * the view hierarchy.
      */
+    @Override
     public final void invalidateChild(View child, final Rect dirty) {
         ViewParent parent = this;
 
@@ -5183,6 +5154,7 @@
      * if this ViewGroup is already fully invalidated or if the dirty rectangle
      * does not intersect with this ViewGroup's bounds.
      */
+    @Override
     public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
         if ((mPrivateFlags & PFLAG_DRAWN) == PFLAG_DRAWN ||
                 (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) {
@@ -5359,6 +5331,9 @@
     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;
@@ -5372,8 +5347,16 @@
                 && (theParent != this)) {
 
             if (offsetFromChildToParent) {
-                rect.offset(descendant.mLeft - descendant.mScrollX,
-                        descendant.mTop - descendant.mScrollY);
+                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);
+
                 if (clipToBounds) {
                     View p = (View) theParent;
                     boolean intersected = rect.intersect(0, 0, p.mRight - p.mLeft,
@@ -5391,8 +5374,16 @@
                         rect.setEmpty();
                     }
                 }
-                rect.offset(descendant.mScrollX - descendant.mLeft,
-                        descendant.mScrollY - descendant.mTop);
+                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);
             }
 
             descendant = (View) theParent;
@@ -5403,11 +5394,26 @@
         // to get into our coordinate space
         if (theParent == this) {
             if (offsetFromChildToParent) {
-                rect.offset(descendant.mLeft - descendant.mScrollX,
-                        descendant.mTop - descendant.mScrollY);
+                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);
             } else {
-                rect.offset(descendant.mScrollX - descendant.mLeft,
-                        descendant.mScrollY - descendant.mTop);
+                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);
             }
         } else {
             throw new IllegalArgumentException("parameter must be a descendant of this view");
@@ -5442,9 +5448,7 @@
         notifySubtreeAccessibilityStateChangedIfNeeded();
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    @Override
     public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
         // It doesn't make a whole lot of sense to call this on a view that isn't attached,
         // but for some simple tests it can be useful. If we don't have attach info this
@@ -5504,9 +5508,6 @@
         return rectIsVisible;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public final void layout(int l, int t, int r, int b) {
         if (!mSuppressLayout && (mTransition == null || !mTransition.isChangingLayout())) {
@@ -5520,9 +5521,6 @@
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     protected abstract void onLayout(boolean changed,
             int l, int t, int r, int b);
@@ -5887,9 +5885,6 @@
         return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     protected void debug(int depth) {
         super.debug(depth);
@@ -6114,6 +6109,7 @@
             }
             break;
         }
+        //noinspection ResourceType
         return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
     }
 
@@ -6306,9 +6302,6 @@
         return mSuppressLayout;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public boolean gatherTransparentRegion(Region region) {
         // If no transparent regions requested, we are always opaque.
@@ -6332,9 +6325,7 @@
         return meOpaque || noneOfTheChildrenAreTransparent;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    @Override
     public void requestTransparentRegion(View child) {
         if (child != null) {
             child.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
@@ -6460,6 +6451,7 @@
      * If {@link #addStatesFromChildren} is true, refreshes this group's
      * drawable state (to include the states from its children).
      */
+    @Override
     public void childDrawableStateChanged(View child) {
         if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
             refreshDrawableState();
@@ -7205,9 +7197,6 @@
             a.recycle();
         }
 
-        /**
-         * {@inheritDoc}
-         */
         public MarginLayoutParams(int width, int height) {
             super(width, height);
 
@@ -7237,9 +7226,6 @@
             this.mMarginFlags = source.mMarginFlags;
         }
 
-        /**
-         * {@inheritDoc}
-         */
         public MarginLayoutParams(LayoutParams source) {
             super(source);
 
@@ -7546,7 +7532,11 @@
         private TouchTarget() {
         }
 
-        public static TouchTarget obtain(View child, int pointerIdBits) {
+        public static TouchTarget obtain(@NonNull View child, int pointerIdBits) {
+            if (child == null) {
+                throw new IllegalArgumentException("child must be non-null");
+            }
+
             final TouchTarget target;
             synchronized (sRecycleLock) {
                 if (sRecycleBin == null) {
@@ -7564,6 +7554,10 @@
         }
 
         public void recycle() {
+            if (child == null) {
+                throw new IllegalStateException("already recycled once");
+            }
+
             synchronized (sRecycleLock) {
                 if (sRecycledCount < MAX_RECYCLED) {
                     next = sRecycleBin;
@@ -7593,7 +7587,11 @@
         private HoverTarget() {
         }
 
-        public static HoverTarget obtain(View child) {
+        public static HoverTarget obtain(@NonNull View child) {
+            if (child == null) {
+                throw new IllegalArgumentException("child must be non-null");
+            }
+
             final HoverTarget target;
             synchronized (sRecycleLock) {
                 if (sRecycleBin == null) {
@@ -7601,7 +7599,7 @@
                 } else {
                     target = sRecycleBin;
                     sRecycleBin = target.next;
-                     sRecycledCount--;
+                    sRecycledCount--;
                     target.next = null;
                 }
             }
@@ -7610,6 +7608,10 @@
         }
 
         public void recycle() {
+            if (child == null) {
+                throw new IllegalStateException("already recycled once");
+            }
+
             synchronized (sRecycleLock) {
                 if (sRecycledCount < MAX_RECYCLED) {
                     next = sRecycleBin;
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index e9b123b5..1962be8 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -266,14 +266,14 @@
      *            intercept touch events.
      */
     public void requestDisallowInterceptTouchEvent(boolean disallowIntercept);
-    
+
     /**
      * Called when a child of this group wants a particular rectangle to be
      * positioned onto the screen.  {@link ViewGroup}s overriding this can trust
      * that:
      * <ul>
      *   <li>child will be a direct child of this group</li>
-     *   <li>rectangle will be in the child's coordinates</li>
+     *   <li>rectangle will be in the child's content coordinates</li>
      * </ul>
      *
      * <p>{@link ViewGroup}s overriding this should uphold the contract:</p>
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index faf2640..98e3289 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -16,7 +16,12 @@
 
 package android.view;
 
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 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;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
 
 import android.Manifest;
 import android.animation.LayoutTransition;
@@ -39,6 +44,7 @@
 import android.graphics.drawable.Drawable;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManager.DisplayListener;
+import android.hardware.input.InputManager;
 import android.media.AudioManager;
 import android.os.Binder;
 import android.os.Build;
@@ -78,6 +84,7 @@
 import android.widget.Scroller;
 
 import com.android.internal.R;
+import com.android.internal.os.IResultReceiver;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.policy.PhoneFallbackEventHandler;
 import com.android.internal.view.BaseSurfaceHolder;
@@ -139,6 +146,9 @@
      */
     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();
@@ -174,6 +184,9 @@
     View mAccessibilityFocusedHost;
     AccessibilityNodeInfo mAccessibilityFocusedVirtualView;
 
+    // The view which captures mouse input, or null when no one is capturing.
+    View mCapturingView;
+
     int mViewVisibility;
     boolean mAppVisible = true;
     // For recents to freeform transition we need to keep drawing after the app receives information
@@ -197,6 +210,10 @@
     // so the window should no longer be active.
     boolean mStopped = false;
 
+    // Set to true if the owner of this window is in ambient mode,
+    // which means it won't receive input events.
+    boolean mIsAmbientMode = false;
+
     // Set to true to stop input during an Activity Transition.
     boolean mPausedForTransition = false;
 
@@ -216,8 +233,10 @@
     boolean mIsAnimating;
 
     private boolean mDragResizing;
+    private int mResizeMode;
     private int mCanvasOffsetX;
     private int mCanvasOffsetY;
+    private boolean mActivityRelaunched;
 
     CompatibilityInfo.Translator mTranslator;
 
@@ -245,6 +264,7 @@
     boolean mNewSurfaceNeeded;
     boolean mHasHadWindowFocus;
     boolean mLastWasImTarget;
+    boolean mForceNextWindowRelayout;
     CountDownLatch mWindowDrawCountDown;
 
     boolean mIsDrawing;
@@ -321,6 +341,7 @@
     volatile Object mLocalDragState;
     final PointF mDragPoint = new PointF();
     final PointF mLastTouchPoint = new PointF();
+    int mLastTouchSource;
 
     private boolean mProfileRendering;
     private Choreographer.FrameCallback mRenderProfiler;
@@ -376,6 +397,8 @@
         int localChanges;
     }
 
+    private String mTag = TAG;
+
     public ViewRootImpl(Context context, Display display) {
         mContext = context;
         mWindowSession = WindowManagerGlobal.getWindowSession();
@@ -502,6 +525,7 @@
                     mWindowAttributes.packageName = mBasePackageName;
                 }
                 attrs = mWindowAttributes;
+                setTag();
                 // Keep track of the actual window flags supplied by the client.
                 mClientWindowLayoutFlags = attrs.flags;
 
@@ -538,7 +562,7 @@
                     attrs.backup();
                     mTranslator.translateWindowLayout(attrs);
                 }
-                if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
+                if (DEBUG_LAYOUT) Log.d(mTag, "WindowLayout in setView:" + attrs);
 
                 if (!compatibilityInfo.supportsScreen()) {
                     attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
@@ -599,7 +623,7 @@
                 mPendingContentInsets.set(mAttachInfo.mContentInsets);
                 mPendingStableInsets.set(mAttachInfo.mStableInsets);
                 mPendingVisibleInsets.set(0, 0, 0, 0);
-                if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
+                if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
                 if (res < WindowManagerGlobal.ADD_OKAY) {
                     mAttachInfo.mRootView = null;
                     mAdded = false;
@@ -693,6 +717,13 @@
         }
     }
 
+    private void setTag() {
+        final String[] split = mWindowAttributes.getTitle().toString().split("\\.");
+        if (split.length > 0) {
+            mTag = TAG + "[" + split[split.length - 1] + "]";
+        }
+    }
+
     /** Whether the window is in local focus mode or not */
     private boolean isInLocalFocusMode() {
         return (mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0;
@@ -982,7 +1013,7 @@
     @Override
     public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
         checkThread();
-        if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
+        if (DEBUG_DRAW) Log.v(mTag, "Invalidate child: " + dirty);
 
         if (dirty == null) {
             invalidate();
@@ -1032,6 +1063,10 @@
         }
     }
 
+    public void setIsAmbientMode(boolean ambient) {
+        mIsAmbientMode = ambient;
+    }
+
     void setWindowStopped(boolean stopped) {
         if (mStopped != stopped) {
             mStopped = stopped;
@@ -1162,7 +1197,7 @@
 
     private boolean collectViewAttributes() {
         if (mAttachInfo.mRecomputeGlobalAttributes) {
-            //Log.i(TAG, "Computing view hierarchy attributes!");
+            //Log.i(mTag, "Computing view hierarchy attributes!");
             mAttachInfo.mRecomputeGlobalAttributes = false;
             boolean oldScreenOn = mAttachInfo.mKeepScreenOn;
             mAttachInfo.mKeepScreenOn = false;
@@ -1203,7 +1238,7 @@
         int childHeightMeasureSpec;
         boolean windowSizeMayChange = false;
 
-        if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,
+        if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(mTag,
                 "Measuring " + host + " in display " + desiredWindowWidth
                 + "x" + desiredWindowHeight + "...");
 
@@ -1219,26 +1254,29 @@
             if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
                 baseSize = (int)mTmpValue.getDimension(packageMetrics);
             }
-            if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize);
+            if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": baseSize=" + baseSize
+                    + ", desiredWindowWidth=" + desiredWindowWidth);
             if (baseSize != 0 && desiredWindowWidth > baseSize) {
                 childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
                 childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
                 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
-                if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
-                        + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
+                if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
+                        + host.getMeasuredWidth() + "," + host.getMeasuredHeight()
+                        + ") from width spec: " + MeasureSpec.toString(childWidthMeasureSpec)
+                        + " and height spec: " + MeasureSpec.toString(childHeightMeasureSpec));
                 if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
                     goodMeasure = true;
                 } else {
                     // Didn't fit in that size... try expanding a bit.
                     baseSize = (baseSize+desiredWindowWidth)/2;
-                    if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
+                    if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": next baseSize="
                             + baseSize);
                     childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
                     performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
-                    if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
+                    if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
                             + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
                     if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
-                        if (DEBUG_DIALOG) Log.v(TAG, "Good!");
+                        if (DEBUG_DIALOG) Log.v(mTag, "Good!");
                         goodMeasure = true;
                     }
                 }
@@ -1314,6 +1352,17 @@
         host.dispatchApplyWindowInsets(getWindowInsets(true /* forceConstruct */));
     }
 
+    private static boolean shouldUseDisplaySize(final WindowManager.LayoutParams lp) {
+        return lp.type == TYPE_STATUS_BAR_PANEL
+                || lp.type == TYPE_INPUT_METHOD
+                || lp.type == TYPE_VOLUME_OVERLAY;
+    }
+
+    private int dipToPx(int dip) {
+        final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
+        return (int) (displayMetrics.density * dip + 0.5f);
+    }
+
     private void performTraversals() {
         // cache mView since it is used so much below...
         final View host = mView;
@@ -1338,8 +1387,8 @@
         int desiredWindowHeight;
 
         final int viewVisibility = getHostVisibility();
-        boolean viewVisibilityChanged = mViewVisibility != viewVisibility
-                || mNewSurfaceNeeded;
+        final boolean viewVisibilityChanged = !mFirst
+                && (mViewVisibility != viewVisibility || mNewSurfaceNeeded);
 
         WindowManager.LayoutParams params = null;
         if (mWindowAttributesChanged) {
@@ -1368,18 +1417,16 @@
             mFullRedrawNeeded = true;
             mLayoutRequested = true;
 
-            if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL
-                    || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
+            if (shouldUseDisplaySize(lp)) {
                 // NOTE -- system code, won't try to do compat mode.
                 Point size = new Point();
                 mDisplay.getRealSize(size);
                 desiredWindowWidth = size.x;
                 desiredWindowHeight = size.y;
             } else {
-                DisplayMetrics packageMetrics =
-                    mView.getContext().getResources().getDisplayMetrics();
-                desiredWindowWidth = packageMetrics.widthPixels;
-                desiredWindowHeight = packageMetrics.heightPixels;
+                Configuration config = mContext.getResources().getConfiguration();
+                desiredWindowWidth = dipToPx(config.screenWidthDp);
+                desiredWindowHeight = dipToPx(config.screenHeightDp);
             }
 
             // We used to use the following condition to choose 32 bits drawing caches:
@@ -1389,7 +1436,6 @@
             mAttachInfo.mHasWindowFocus = false;
             mAttachInfo.mWindowVisibility = viewVisibility;
             mAttachInfo.mRecomputeGlobalAttributes = false;
-            viewVisibilityChanged = false;
             mLastConfiguration.setTo(host.getResources().getConfiguration());
             mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
             // Set the layout direction if it has not been set before (inherit is the default)
@@ -1399,14 +1445,13 @@
             host.dispatchAttachedToWindow(mAttachInfo, 0);
             mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
             dispatchApplyInsets(host);
-            //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
+            //Log.i(mTag, "Screen on initialized: " + attachInfo.mKeepScreenOn);
 
         } else {
             desiredWindowWidth = frame.width();
             desiredWindowHeight = frame.height();
             if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
-                if (DEBUG_ORIENTATION) Log.v(TAG,
-                        "View " + host + " resized to: " + frame);
+                if (DEBUG_ORIENTATION) Log.v(mTag, "View " + host + " resized to: " + frame);
                 mFullRedrawNeeded = true;
                 mLayoutRequested = true;
                 windowSizeMayChange = true;
@@ -1459,7 +1504,7 @@
                 }
                 if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
                     mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
-                    if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
+                    if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
                             + mAttachInfo.mVisibleInsets);
                 }
                 if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) {
@@ -1469,17 +1514,16 @@
                         || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
                     windowSizeMayChange = true;
 
-                    if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL
-                            || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
+                    if (shouldUseDisplaySize(lp)) {
                         // NOTE -- system code, won't try to do compat mode.
                         Point size = new Point();
                         mDisplay.getRealSize(size);
                         desiredWindowWidth = size.x;
                         desiredWindowHeight = size.y;
                     } else {
-                        DisplayMetrics packageMetrics = res.getDisplayMetrics();
-                        desiredWindowWidth = packageMetrics.widthPixels;
-                        desiredWindowHeight = packageMetrics.heightPixels;
+                        Configuration config = res.getConfiguration();
+                        desiredWindowWidth = dipToPx(config.screenWidthDp);
+                        desiredWindowHeight = dipToPx(config.screenHeightDp);
                     }
                 }
             }
@@ -1560,12 +1604,17 @@
                         frame.width() < desiredWindowWidth && frame.width() != mWidth)
                 || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
                         frame.height() < desiredWindowHeight && frame.height() != mHeight));
-        windowShouldResize |= mDragResizing;
+        windowShouldResize |= mDragResizing && mResizeMode == RESIZE_MODE_FREEFORM;
 
         // If the backdrop frame doesn't equal to a frame, we are starting a resize operation, so
         // force it to be resized.
         windowShouldResize |= !mPendingBackDropFrame.equals(mWinFrame);
 
+        // If the activity was just relaunched, it might have unfrozen the task bounds (while
+        // relaunching), so we need to force a call into window manager to pick up the latest
+        // bounds.
+        windowShouldResize |= mActivityRelaunched;
+
         // Determine whether to compute insets.
         // If there are no inset listeners remaining then we may still need to compute
         // insets in case the old insets were non-empty and must be reset.
@@ -1578,7 +1627,8 @@
 
         final boolean isViewVisible = viewVisibility == View.VISIBLE;
         if (mFirst || windowShouldResize || insetsChanged ||
-                viewVisibilityChanged || params != null) {
+                viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
+            mForceNextWindowRelayout = false;
 
             if (isViewVisible) {
                 // If this window is giving internal insets to the window
@@ -1604,7 +1654,7 @@
 
             try {
                 if (DEBUG_LAYOUT) {
-                    Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" +
+                    Log.i(mTag, "host=w:" + host.getMeasuredWidth() + ", h:" +
                             host.getMeasuredHeight() + ", params=" + params);
                 }
 
@@ -1622,7 +1672,7 @@
                 final int surfaceGenerationId = mSurface.getGenerationId();
                 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
 
-                if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString()
+                if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
                         + " overscan=" + mPendingOverscanInsets.toShortString()
                         + " content=" + mPendingContentInsets.toShortString()
                         + " visible=" + mPendingVisibleInsets.toShortString()
@@ -1631,7 +1681,7 @@
                         + " surface=" + mSurface);
 
                 if (mPendingConfiguration.seq != 0) {
-                    if (DEBUG_CONFIGURATION) Log.v(TAG, "Visible with new config: "
+                    if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: "
                             + mPendingConfiguration);
                     updateConfiguration(new Configuration(mPendingConfiguration), !mFirst);
                     mPendingConfiguration.seq = 0;
@@ -1650,19 +1700,19 @@
                         & WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
                 if (contentInsetsChanged) {
                     mAttachInfo.mContentInsets.set(mPendingContentInsets);
-                    if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
+                    if (DEBUG_LAYOUT) Log.v(mTag, "Content insets changing to: "
                             + mAttachInfo.mContentInsets);
                 }
                 if (overscanInsetsChanged) {
                     mAttachInfo.mOverscanInsets.set(mPendingOverscanInsets);
-                    if (DEBUG_LAYOUT) Log.v(TAG, "Overscan insets changing to: "
+                    if (DEBUG_LAYOUT) Log.v(mTag, "Overscan insets changing to: "
                             + mAttachInfo.mOverscanInsets);
                     // Need to relayout with content insets.
                     contentInsetsChanged = true;
                 }
                 if (stableInsetsChanged) {
                     mAttachInfo.mStableInsets.set(mPendingStableInsets);
-                    if (DEBUG_LAYOUT) Log.v(TAG, "Decor insets changing to: "
+                    if (DEBUG_LAYOUT) Log.v(mTag, "Decor insets changing to: "
                             + mAttachInfo.mStableInsets);
                     // Need to relayout with content insets.
                     contentInsetsChanged = true;
@@ -1679,7 +1729,7 @@
                 }
                 if (visibleInsetsChanged) {
                     mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
-                    if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
+                    if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
                             + mAttachInfo.mVisibleInsets);
                 }
 
@@ -1754,11 +1804,17 @@
                     }
                 }
 
-                final boolean dragResizing = (relayoutResult
-                        & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING) != 0;
+                final boolean freeformResizing = (relayoutResult
+                        & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_FREEFORM) != 0;
+                final boolean dockedResizing = (relayoutResult
+                        & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_DOCKED) != 0;
+                final boolean dragResizing = freeformResizing || dockedResizing;
                 if (mDragResizing != dragResizing) {
                     if (dragResizing) {
                         startDragResizing(mPendingBackDropFrame);
+                        mResizeMode = freeformResizing
+                                ? RESIZE_MODE_FREEFORM
+                                : RESIZE_MODE_DOCKED_DIVIDER;
                     } else {
                         // We shouldn't come here, but if we come we should end the resize.
                         endDragResizing();
@@ -1860,7 +1916,7 @@
                     int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
                     int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
 
-                    if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed!  mWidth="
+                    if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed!  mWidth="
                             + mWidth + " measuredWidth=" + host.getMeasuredWidth()
                             + " mHeight=" + mHeight
                             + " measuredHeight=" + host.getMeasuredHeight()
@@ -1890,7 +1946,7 @@
                     }
 
                     if (measureAgain) {
-                        if (DEBUG_LAYOUT) Log.v(TAG,
+                        if (DEBUG_LAYOUT) Log.v(mTag,
                                 "And hey let's measure once more: width=" + width
                                 + " height=" + height);
                         performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
@@ -1905,29 +1961,7 @@
             // in the attach info. We translate only the window frame since on window move
             // the window manager tells us only for the new frame but the insets are the
             // same and we do not want to translate them more than once.
-
-            // TODO: Well, we are checking whether the frame has changed similarly
-            // to how this is done for the insets. This is however incorrect since
-            // the insets and the frame are translated. For example, the old frame
-            // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new
-            // reported frame is (2, 2 - 2, 2) which implies no change but this is not
-            // true since we are comparing a not translated value to a translated one.
-            // This scenario is rare but we may want to fix that.
-
-            final boolean windowMoved = (mAttachInfo.mWindowLeft != frame.left
-                    || mAttachInfo.mWindowTop != frame.top);
-            if (windowMoved) {
-                if (mTranslator != null) {
-                    mTranslator.translateRectInScreenToAppWinFrame(frame);
-                }
-                mAttachInfo.mWindowLeft = frame.left;
-                mAttachInfo.mWindowTop = frame.top;
-
-                // Update the light position for the new window offsets.
-                if (mAttachInfo.mHardwareRenderer != null) {
-                    mAttachInfo.mHardwareRenderer.setLightCenter(mAttachInfo);
-                }
-            }
+            maybeHandleWindowMove(frame);
         }
 
         final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
@@ -2012,15 +2046,15 @@
 
         if (mFirst) {
             // handle first focus request
-            if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()="
+            if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: mView.hasFocus()="
                     + mView.hasFocus());
             if (mView != null) {
                 if (!mView.hasFocus()) {
                     mView.requestFocus(View.FOCUS_FORWARD);
-                    if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: requested focused view="
+                    if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: requested focused view="
                             + mView.findFocus());
                 } else {
-                    if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: existing focused view="
+                    if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: existing focused view="
                             + mView.findFocus());
                 }
             }
@@ -2042,6 +2076,7 @@
         mFirst = false;
         mWillDrawSoon = false;
         mNewSurfaceNeeded = false;
+        mActivityRelaunched = false;
         mViewVisibility = viewVisibility;
         mHadWindowFocus = hasWindowFocus;
 
@@ -2067,7 +2102,7 @@
 
         boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
 
-        if (!cancelDraw && !newSurface) {
+        if (!cancelDraw) {
             if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
                 for (int i = 0; i < mPendingTransitions.size(); ++i) {
                     mPendingTransitions.get(i).startChangingAnimations();
@@ -2091,12 +2126,38 @@
         mIsInTraversal = false;
     }
 
+    private void maybeHandleWindowMove(Rect frame) {
+
+        // TODO: Well, we are checking whether the frame has changed similarly
+        // to how this is done for the insets. This is however incorrect since
+        // the insets and the frame are translated. For example, the old frame
+        // was (1, 1 - 1, 1) and was translated to say (2, 2 - 2, 2), now the new
+        // reported frame is (2, 2 - 2, 2) which implies no change but this is not
+        // true since we are comparing a not translated value to a translated one.
+        // This scenario is rare but we may want to fix that.
+
+        final boolean windowMoved = mAttachInfo.mWindowLeft != frame.left
+                || mAttachInfo.mWindowTop != frame.top;
+        if (windowMoved) {
+            if (mTranslator != null) {
+                mTranslator.translateRectInScreenToAppWinFrame(frame);
+            }
+            mAttachInfo.mWindowLeft = frame.left;
+            mAttachInfo.mWindowTop = frame.top;
+
+            // Update the light position for the new window offsets.
+            if (mAttachInfo.mHardwareRenderer != null) {
+                mAttachInfo.mHardwareRenderer.setLightCenter(mAttachInfo);
+            }
+        }
+    }
+
     private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
-        Log.e(TAG, "OutOfResourcesException initializing HW surface", e);
+        Log.e(mTag, "OutOfResourcesException initializing HW surface", e);
         try {
             if (!mWindowSession.outOfMemory(mWindow) &&
                     Process.myUid() != Process.SYSTEM_UID) {
-                Slog.w(TAG, "No processes killed for memory; killing self");
+                Slog.w(mTag, "No processes killed for memory; killing self");
                 Process.killProcess(Process.myPid());
             }
         } catch (RemoteException ex) {
@@ -2172,7 +2233,7 @@
 
         final View host = mView;
         if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
-            Log.v(TAG, "Laying out " + host + " to (" +
+            Log.v(mTag, "Laying out " + host + " to (" +
                     host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
         }
 
@@ -2415,11 +2476,11 @@
             String thisHash = Integer.toHexString(System.identityHashCode(this));
             long frameTime = nowTime - mFpsPrevTime;
             long totalTime = nowTime - mFpsStartTime;
-            Log.v(TAG, "0x" + thisHash + "\tFrame time:\t" + frameTime);
+            Log.v(mTag, "0x" + thisHash + "\tFrame time:\t" + frameTime);
             mFpsPrevTime = nowTime;
             if (totalTime > 1000) {
                 float fps = (float) mFpsNumFrames * 1000 / totalTime;
-                Log.v(TAG, "0x" + thisHash + "\tFPS:\t" + fps);
+                Log.v(mTag, "0x" + thisHash + "\tFPS:\t" + fps);
                 mFpsStartTime = nowTime;
                 mFpsNumFrames = 0;
             }
@@ -2461,7 +2522,7 @@
                 try {
                     mWindowDrawCountDown.await();
                 } catch (InterruptedException e) {
-                    Log.e(TAG, "Window redraw count down interruped!");
+                    Log.e(mTag, "Window redraw count down interruped!");
                 }
                 mWindowDrawCountDown = null;
             }
@@ -2471,7 +2532,7 @@
             }
 
             if (LOCAL_LOGV) {
-                Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
+                Log.v(mTag, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
             }
             if (mSurfaceHolder != null && mSurface.isValid()) {
                 mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
@@ -2554,7 +2615,7 @@
         }
 
         if (DEBUG_ORIENTATION || DEBUG_DRAW) {
-            Log.v(TAG, "Draw " + mView + "/"
+            Log.v(mTag, "Draw " + mView + "/"
                     + mWindowAttributes.getTitle()
                     + ": dirty={" + dirty.left + "," + dirty.top
                     + "," + dirty.right + "," + dirty.bottom + "} surface="
@@ -2688,7 +2749,7 @@
             handleOutOfResourcesException(e);
             return false;
         } catch (IllegalArgumentException e) {
-            Log.e(TAG, "Could not lock surface", e);
+            Log.e(mTag, "Could not lock surface", e);
             // Don't assume this is due to out of memory, it could be
             // something else, and if it is something else then we could
             // kill stuff (or ourself) for no reason.
@@ -2698,7 +2759,7 @@
 
         try {
             if (DEBUG_ORIENTATION || DEBUG_DRAW) {
-                Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
+                Log.v(mTag, "Surface " + surface + " drawing to bitmap w="
                         + canvas.getWidth() + ", h=" + canvas.getHeight());
                 //canvas.drawARGB(255, 255, 0, 0);
             }
@@ -2721,7 +2782,7 @@
 
             if (DEBUG_DRAW) {
                 Context cxt = mView.getContext();
-                Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
+                Log.i(mTag, "Drawing: package:" + cxt.getPackageName() +
                         ", metrics=" + cxt.getResources().getDisplayMetrics() +
                         ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
             }
@@ -2746,14 +2807,14 @@
             try {
                 surface.unlockCanvasAndPost(canvas);
             } catch (IllegalArgumentException e) {
-                Log.e(TAG, "Could not unlock surface", e);
+                Log.e(mTag, "Could not unlock surface", e);
                 mLayoutRequested = true;    // ask wm for a new surface next time.
                 //noinspection ReturnInsideFinallyBlock
                 return false;
             }
 
             if (LOCAL_LOGV) {
-                Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
+                Log.v(mTag, "Surface " + surface + " unlockCanvasAndPost");
             }
         }
         return true;
@@ -2858,14 +2919,14 @@
                 // view is visible.
                 rectangle = null;
             }
-            if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Eval scroll: focus=" + focus
+            if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Eval scroll: focus=" + focus
                     + " rectangle=" + rectangle + " ci=" + ci
                     + " vi=" + vi);
             if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) {
                 // Optimization: if the focus hasn't changed since last
                 // time, and no layout has happened, then just leave things
                 // as they are.
-                if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y="
+                if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Keeping scroll y="
                         + mScrollY + " vi=" + vi.toShortString());
             } else {
                 // We need to determine if the currently focused view is
@@ -2873,51 +2934,51 @@
                 // a pan so it can be seen.
                 mLastScrolledFocus = new WeakReference<View>(focus);
                 mScrollMayChange = false;
-                if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Need to scroll?");
+                if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Need to scroll?");
                 // Try to find the rectangle from the focus view.
                 if (focus.getGlobalVisibleRect(mVisRect, null)) {
-                    if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w="
+                    if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Root w="
                             + mView.getWidth() + " h=" + mView.getHeight()
                             + " ci=" + ci.toShortString()
                             + " vi=" + vi.toShortString());
                     if (rectangle == null) {
                         focus.getFocusedRect(mTempRect);
-                        if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus
+                        if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Focus " + focus
                                 + ": focusRect=" + mTempRect.toShortString());
                         if (mView instanceof ViewGroup) {
                             ((ViewGroup) mView).offsetDescendantRectToMyCoords(
                                     focus, mTempRect);
                         }
-                        if (DEBUG_INPUT_RESIZE) Log.v(TAG,
+                        if (DEBUG_INPUT_RESIZE) Log.v(mTag,
                                 "Focus in window: focusRect="
                                 + mTempRect.toShortString()
                                 + " visRect=" + mVisRect.toShortString());
                     } else {
                         mTempRect.set(rectangle);
-                        if (DEBUG_INPUT_RESIZE) Log.v(TAG,
+                        if (DEBUG_INPUT_RESIZE) Log.v(mTag,
                                 "Request scroll to rect: "
                                 + mTempRect.toShortString()
                                 + " visRect=" + mVisRect.toShortString());
                     }
                     if (mTempRect.intersect(mVisRect)) {
-                        if (DEBUG_INPUT_RESIZE) Log.v(TAG,
+                        if (DEBUG_INPUT_RESIZE) Log.v(mTag,
                                 "Focus window visible rect: "
                                 + mTempRect.toShortString());
                         if (mTempRect.height() >
                                 (mView.getHeight()-vi.top-vi.bottom)) {
                             // If the focus simply is not going to fit, then
                             // best is probably just to leave things as-is.
-                            if (DEBUG_INPUT_RESIZE) Log.v(TAG,
+                            if (DEBUG_INPUT_RESIZE) Log.v(mTag,
                                     "Too tall; leaving scrollY=" + scrollY);
                         } else if ((mTempRect.top-scrollY) < vi.top) {
                             scrollY -= vi.top - (mTempRect.top-scrollY);
-                            if (DEBUG_INPUT_RESIZE) Log.v(TAG,
+                            if (DEBUG_INPUT_RESIZE) Log.v(mTag,
                                     "Top covered; scrollY=" + scrollY);
                         } else if ((mTempRect.bottom-scrollY)
                                 > (mView.getHeight()-vi.bottom)) {
                             scrollY += (mTempRect.bottom-scrollY)
                                     - (mView.getHeight()-vi.bottom);
-                            if (DEBUG_INPUT_RESIZE) Log.v(TAG,
+                            if (DEBUG_INPUT_RESIZE) Log.v(mTag,
                                     "Bottom covered; scrollY=" + scrollY);
                         }
                         handled = true;
@@ -2927,7 +2988,7 @@
         }
 
         if (scrollY != mScrollY) {
-            if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old="
+            if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Pan scroll changed: old="
                     + mScrollY + " , new=" + scrollY);
             if (!immediate) {
                 if (mScroller == null) {
@@ -3004,10 +3065,35 @@
         }
     }
 
+    void setPointerCapture(View view) {
+        if (!mAttachInfo.mHasWindowFocus) {
+            Log.w(mTag, "Can't set capture if it's not focused.");
+            return;
+        }
+        if (mCapturingView == view) {
+            return;
+        }
+        mCapturingView = view;
+        InputManager.getInstance().setPointerIconDetached(true);
+    }
+
+    void releasePointerCapture(View view) {
+        if (mCapturingView != view || mCapturingView == null) {
+            return;
+        }
+
+        mCapturingView = null;
+        InputManager.getInstance().setPointerIconDetached(false);
+    }
+
+    boolean hasPointerCapture(View view) {
+        return view != null && mCapturingView == view;
+    }
+
     @Override
     public void requestChildFocus(View child, View focused) {
         if (DEBUG_INPUT_RESIZE) {
-            Log.v(TAG, "Request child focus: focus now " + focused);
+            Log.v(mTag, "Request child focus: focus now " + focused);
         }
         checkThread();
         scheduleTraversals();
@@ -3016,7 +3102,7 @@
     @Override
     public void clearChildFocus(View child) {
         if (DEBUG_INPUT_RESIZE) {
-            Log.v(TAG, "Clearing child focus");
+            Log.v(mTag, "Clearing child focus");
         }
         checkThread();
         scheduleTraversals();
@@ -3081,6 +3167,10 @@
         mView = null;
         mAttachInfo.mRootView = null;
 
+        if (mCapturingView != null) {
+            releasePointerCapture(mCapturingView);
+        }
+
         mSurface.release();
 
         if (mInputQueueCallback != null && mInputQueue != null) {
@@ -3111,7 +3201,7 @@
     }
 
     void updateConfiguration(Configuration config, boolean force) {
-        if (DEBUG_CONFIGURATION) Log.v(TAG,
+        if (DEBUG_CONFIGURATION) Log.v(mTag,
                 "Applying new config to window "
                 + mWindowAttributes.getTitle()
                 + ": " + config);
@@ -3191,6 +3281,8 @@
     private final static int MSG_WINDOW_MOVED = 23;
     private final static int MSG_SYNTHESIZE_INPUT_EVENT = 24;
     private final static int MSG_DISPATCH_WINDOW_SHOWN = 25;
+    private final static int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26;
+    private final static int MSG_UPDATE_POINTER_ICON = 27;
 
     final class ViewRootHandler extends Handler {
         @Override
@@ -3240,6 +3332,8 @@
                     return "MSG_SYNTHESIZE_INPUT_EVENT";
                 case MSG_DISPATCH_WINDOW_SHOWN:
                     return "MSG_DISPATCH_WINDOW_SHOWN";
+                case MSG_UPDATE_POINTER_ICON:
+                    return "MSG_UPDATE_POINTER_ICON";
             }
             return super.getMessageName(message);
         }
@@ -3274,7 +3368,9 @@
                         && mPendingStableInsets.equals(args.arg6)
                         && mPendingVisibleInsets.equals(args.arg3)
                         && mPendingOutsets.equals(args.arg7)
-                        && args.arg4 == null) {
+                        && mPendingBackDropFrame.equals(args.arg8)
+                        && args.arg4 == null
+                        && args.argi1 == 0) {
                     break;
                 }
                 } // fall through...
@@ -3294,6 +3390,7 @@
                     mPendingVisibleInsets.set((Rect) args.arg3);
                     mPendingOutsets.set((Rect) args.arg7);
                     mPendingBackDropFrame.set((Rect) args.arg8);
+                    mForceNextWindowRelayout = args.argi1 != 0;
 
                     args.recycle();
 
@@ -3321,10 +3418,19 @@
 
                     mPendingBackDropFrame.set(mWinFrame);
 
-                    if (mView != null) {
-                        forceLayout(mView);
+                    // Suppress layouts during resizing - a correct layout will happen when resizing
+                    // is done, and this just increases system load.
+                    boolean isDockedDivider = mWindowAttributes.type == TYPE_DOCK_DIVIDER;
+                    boolean suppress = (mDragResizing && mResizeMode == RESIZE_MODE_DOCKED_DIVIDER)
+                            || isDockedDivider;
+                    if (!suppress) {
+                        if (mView != null) {
+                            forceLayout(mView);
+                        }
+                        requestLayout();
+                    } else {
+                        maybeHandleWindowMove(mWinFrame);
                     }
-                    requestLayout();
                 }
                 break;
             case MSG_WINDOW_FOCUS_CHANGED: {
@@ -3346,10 +3452,10 @@
                                 mAttachInfo.mHardwareRenderer.initializeIfNeeded(
                                         mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
                             } catch (OutOfResourcesException e) {
-                                Log.e(TAG, "OutOfResourcesException locking surface", e);
+                                Log.e(mTag, "OutOfResourcesException locking surface", e);
                                 try {
                                     if (!mWindowSession.outOfMemory(mWindow)) {
-                                        Slog.w(TAG, "No processes killed for memory; killing self");
+                                        Slog.w(mTag, "No processes killed for memory; killing self");
                                         Process.killProcess(Process.myPid());
                                     }
                                 } catch (RemoteException ex) {
@@ -3390,6 +3496,8 @@
                                 .softInputMode &=
                                     ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
                         mHasHadWindowFocus = true;
+                    } else if (mCapturingView != null) {
+                        releasePointerCapture(mCapturingView);
                     }
                 }
             } break;
@@ -3464,7 +3572,15 @@
             } break;
             case MSG_DISPATCH_WINDOW_SHOWN: {
                 handleDispatchWindowShown();
-            }
+            } break;
+            case MSG_REQUEST_KEYBOARD_SHORTCUTS: {
+                IResultReceiver receiver = (IResultReceiver) msg.obj;
+                handleRequestKeyboardShortcuts(receiver);
+            } break;
+            case MSG_UPDATE_POINTER_ICON: {
+                MotionEvent event = (MotionEvent) msg.obj;
+                resetPointerIcon(event);
+            } break;
             }
         }
     }
@@ -3487,9 +3603,7 @@
 
         // tell the window manager
         try {
-            if (!isInLocalFocusMode()) {
-                mWindowSession.setInTouchMode(inTouchMode);
-            }
+            mWindowSession.setInTouchMode(inTouchMode);
         } catch (RemoteException e) {
             throw new RuntimeException(e);
         }
@@ -3670,7 +3784,7 @@
          */
         protected void onDeliverToNext(QueuedInputEvent q) {
             if (DEBUG_INPUT_STAGES) {
-                Log.v(TAG, "Done with " + getClass().getSimpleName() + ". " + q);
+                Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);
             }
             if (mNext != null) {
                 mNext.deliver(q);
@@ -3681,23 +3795,23 @@
 
         protected boolean shouldDropInputEvent(QueuedInputEvent q) {
             if (mView == null || !mAdded) {
-                Slog.w(TAG, "Dropping event due to root view being removed: " + q.mEvent);
+                Slog.w(mTag, "Dropping event due to root view being removed: " + q.mEvent);
                 return true;
             } else if ((!mAttachInfo.mHasWindowFocus
                     && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) || mStopped
-                    || (mPausedForTransition && !isBack(q.mEvent))) {
+                    || mIsAmbientMode || (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.
                 if (isTerminalInputEvent(q.mEvent)) {
                     // Don't drop terminal input events, however mark them as canceled.
                     q.mEvent.cancel();
-                    Slog.w(TAG, "Cancelling event due to no window focus: " + q.mEvent);
+                    Slog.w(mTag, "Cancelling event due to no window focus: " + q.mEvent);
                     return false;
                 }
 
                 // Drop non-terminal input events.
-                Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent);
+                Slog.w(mTag, "Dropping event due to no window focus: " + q.mEvent);
                 return true;
             }
             return false;
@@ -3937,7 +4051,7 @@
                 InputMethodManager imm = InputMethodManager.peekInstance();
                 if (imm != null) {
                     final InputEvent event = q.mEvent;
-                    if (DEBUG_IMF) Log.v(TAG, "Sending input event to IME: " + event);
+                    if (DEBUG_IMF) Log.v(mTag, "Sending input event to IME: " + event);
                     int result = imm.dispatchInputEvent(event, q, this, mHandler);
                     if (result == InputMethodManager.DISPATCH_HANDLED) {
                         return FINISH_HANDLED;
@@ -4022,6 +4136,7 @@
             if (event.isTouchEvent()) {
                 mLastTouchPoint.x = event.getRawX();
                 mLastTouchPoint.y = event.getRawY();
+                mLastTouchSource = event.getSource();
             }
             return FORWARD;
         }
@@ -4207,36 +4322,19 @@
                     mPointerIconShape = PointerIcon.STYLE_NOT_SPECIFIED;
                 }
 
-                final float x = event.getX();
-                final float y = event.getY();
-                if (event.getActionMasked() != MotionEvent.ACTION_HOVER_EXIT
-                        && x >= 0 && x < mView.getWidth() && y >= 0 && y < mView.getHeight()) {
-                    PointerIcon pointerIcon = mView.getPointerIcon(event, x, y);
-                    int pointerShape = (pointerIcon != null) ?
-                            pointerIcon.getStyle() : PointerIcon.STYLE_DEFAULT;
-
-                    final InputDevice inputDevice = event.getDevice();
-                    if (inputDevice != null) {
-                        if (mPointerIconShape != pointerShape) {
-                            mPointerIconShape = pointerShape;
-                            if (mPointerIconShape != PointerIcon.STYLE_CUSTOM) {
-                                mCustomPointerIcon = null;
-                                inputDevice.setPointerShape(pointerShape);
-                            }
-                        }
-                        if (mPointerIconShape == PointerIcon.STYLE_CUSTOM &&
-                                !pointerIcon.equals(mCustomPointerIcon)) {
-                            mCustomPointerIcon = pointerIcon;
-                            inputDevice.setCustomPointerIcon(mCustomPointerIcon);
-                        }
+                if (event.getActionMasked() != MotionEvent.ACTION_HOVER_EXIT) {
+                    if (!updatePointerIcon(event) &&
+                            event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) {
+                        mPointerIconShape = PointerIcon.STYLE_NOT_SPECIFIED;
                     }
-                } else if (event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) {
-                    mPointerIconShape = PointerIcon.STYLE_NOT_SPECIFIED;
                 }
             }
 
             mAttachInfo.mUnbufferedDispatchRequested = false;
-            boolean handled = mView.dispatchPointerEvent(event);
+            final View eventTarget =
+                    (event.isFromSource(InputDevice.SOURCE_MOUSE) && mCapturingView != null) ?
+                            mCapturingView : mView;
+            boolean handled = eventTarget.dispatchPointerEvent(event);
             if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
                 mUnbufferedInputDispatch = true;
                 if (mConsumeBatchedInputScheduled) {
@@ -4266,6 +4364,38 @@
         }
     }
 
+    private void resetPointerIcon(MotionEvent event) {
+        mPointerIconShape = PointerIcon.STYLE_NOT_SPECIFIED;
+        updatePointerIcon(event);
+    }
+
+    private boolean updatePointerIcon(MotionEvent event) {
+        final float x = event.getX();
+        final float y = event.getY();
+        if (x < 0 || x >= mView.getWidth() || y < 0 || y >= mView.getHeight()) {
+            Slog.e(mTag, "updatePointerIcon called with position out of bounds");
+            return false;
+        }
+        final PointerIcon pointerIcon = mView.getPointerIcon(event, x, y);
+        final int pointerShape = (pointerIcon != null) ?
+                pointerIcon.getStyle() : PointerIcon.STYLE_DEFAULT;
+
+        if (mPointerIconShape != pointerShape) {
+            mPointerIconShape = pointerShape;
+            if (mPointerIconShape != PointerIcon.STYLE_CUSTOM) {
+                mCustomPointerIcon = null;
+                InputManager.getInstance().setPointerIconShape(pointerShape);
+                return true;
+            }
+        }
+        if (mPointerIconShape == PointerIcon.STYLE_CUSTOM &&
+                !pointerIcon.equals(mCustomPointerIcon)) {
+            mCustomPointerIcon = pointerIcon;
+            InputManager.getInstance().setCustomPointerIcon(mCustomPointerIcon);
+        }
+        return true;
+    }
+
     /**
      * Performs synthesis of new input events from unhandled input events.
      */
@@ -4366,7 +4496,7 @@
                     break;
             }
 
-            if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + mX.position + " step="
+            if (DEBUG_TRACKBALL) Log.v(mTag, "TB X=" + mX.position + " step="
                     + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration
                     + " move=" + event.getX()
                     + " / Y=" + mY.position + " step="
@@ -4405,11 +4535,11 @@
             if (keycode != 0) {
                 if (movement < 0) movement = -movement;
                 int accelMovement = (int)(movement * accel);
-                if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
+                if (DEBUG_TRACKBALL) Log.v(mTag, "Move: movement=" + movement
                         + " accelMovement=" + accelMovement
                         + " accel=" + accel);
                 if (accelMovement > movement) {
-                    if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: "
+                    if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
                             + keycode);
                     movement--;
                     int repeatCount = accelMovement - movement;
@@ -4419,7 +4549,7 @@
                             InputDevice.SOURCE_KEYBOARD));
                 }
                 while (movement > 0) {
-                    if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: "
+                    if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
                             + keycode);
                     movement--;
                     curTime = SystemClock.uptimeMillis();
@@ -4661,7 +4791,7 @@
                 update(event, true);
                 break;
             default:
-                Log.w(TAG, "Unexpected action: " + event.getActionMasked());
+                Log.w(mTag, "Unexpected action: " + event.getActionMasked());
             }
         }
 
@@ -5300,7 +5430,7 @@
                             mWindowSession.dragRecipientEntered(mWindow);
                         }
                     } catch (RemoteException e) {
-                        Slog.e(TAG, "Unable to note drag target change");
+                        Slog.e(mTag, "Unable to note drag target change");
                     }
                 }
 
@@ -5308,10 +5438,10 @@
                 if (what == DragEvent.ACTION_DROP) {
                     mDragDescription = null;
                     try {
-                        Log.i(TAG, "Reporting drop result: " + result);
+                        Log.i(mTag, "Reporting drop result: " + result);
                         mWindowSession.reportDropResult(mWindow, result);
                     } catch (RemoteException e) {
-                        Log.e(TAG, "Unable to report drop result");
+                        Log.e(mTag, "Unable to report drop result");
                     }
                 }
 
@@ -5354,11 +5484,28 @@
         mAttachInfo.mTreeObserver.dispatchOnWindowShown();
     }
 
+    public void handleRequestKeyboardShortcuts(IResultReceiver receiver) {
+        Bundle data = new Bundle();
+        ArrayList<KeyboardShortcutGroup> list = new ArrayList<>();
+        if (mView != null) {
+            mView.requestKeyboardShortcuts(list);
+        }
+        data.putParcelableArrayList(WindowManager.PARCEL_KEY_SHORTCUTS_ARRAY, list);
+        try {
+            receiver.send(0, data);
+        } catch (RemoteException e) {
+        }
+    }
+
     public void getLastTouchPoint(Point outLocation) {
         outLocation.x = (int) mLastTouchPoint.x;
         outLocation.y = (int) mLastTouchPoint.y;
     }
 
+    public int getLastTouchSource() {
+        return mLastTouchSource;
+    }
+
     public void setDragFocus(View newDragTarget) {
         if (mCurrentDragView != newDragTarget) {
             mCurrentDragView = newDragTarget;
@@ -5397,14 +5544,14 @@
             mTranslator.translateWindowLayout(params);
         }
         if (params != null) {
-            if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params);
+            if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);
         }
         mPendingConfiguration.seq = 0;
-        //Log.d(TAG, ">>>>>> CALLING relayout");
+        //Log.d(mTag, ">>>>>> CALLING relayout");
         if (params != null && mOrigWindowType != params.type) {
             // For compatibility with old apps, don't crash here.
             if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
-                Slog.w(TAG, "Window type can not be changed after "
+                Slog.w(mTag, "Window type can not be changed after "
                         + "the window is added; ignoring change of " + mView);
                 params.type = mOrigWindowType;
             }
@@ -5415,8 +5562,9 @@
                 (int) (mView.getMeasuredHeight() * appScale + 0.5f),
                 viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
                 mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
-                mPendingStableInsets, mPendingOutsets, mPendingConfiguration, mSurface);
-        //Log.d(TAG, "<<<<<< BACK FROM relayout");
+                mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingConfiguration,
+                mSurface);
+        //Log.d(mTag, "<<<<<< BACK FROM relayout");
         if (restore) {
             params.restore();
         }
@@ -5463,7 +5611,7 @@
             }
         } catch (IllegalStateException e) {
             // Exception thrown by getAudioManager() when mView is null
-            Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e);
+            Log.e(mTag, "FATAL EXCEPTION when attempting to play sound effect: " + e);
             e.printStackTrace();
         }
     }
@@ -5511,6 +5659,8 @@
                 writer.println(mProcessInputEventsScheduled);
         writer.print(innerPrefix); writer.print("mTraversalScheduled=");
                 writer.print(mTraversalScheduled);
+        writer.print(innerPrefix); writer.print("mIsAmbientMode=");
+                writer.print(mIsAmbientMode);
         if (mTraversalScheduled) {
             writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
         } else {
@@ -5584,7 +5734,7 @@
         if (!mIsDrawing) {
             destroyHardwareRenderer();
         } else {
-            Log.e(TAG, "Attempting to destroy the window while drawing!\n" +
+            Log.e(mTag, "Attempting to destroy the window while drawing!\n" +
                     "  window=" + this + ", title=" + mWindowAttributes.getTitle());
         }
         mHandler.sendEmptyMessage(MSG_DIE);
@@ -5593,7 +5743,7 @@
 
     void doDie() {
         checkThread();
-        if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
+        if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
         synchronized (this) {
             if (mRemoved) {
                 return;
@@ -5685,8 +5835,8 @@
 
     public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
             Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
-            Configuration newConfig, Rect backDropFrame) {
-        if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": frame=" + frame.toShortString()
+            Configuration newConfig, Rect backDropFrame, boolean forceLayout) {
+        if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString()
                 + " contentInsets=" + contentInsets.toShortString()
                 + " visibleInsets=" + visibleInsets.toShortString()
                 + " reportDraw=" + reportDraw
@@ -5719,12 +5869,13 @@
         args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets;
         args.arg7 = sameProcessCall ? new Rect(outsets) : outsets;
         args.arg8 = sameProcessCall ? new Rect(backDropFrame) : backDropFrame;
+        args.argi1 = forceLayout ? 1 : 0;
         msg.obj = args;
         mHandler.sendMessage(msg);
     }
 
     public void dispatchMoved(int newX, int newY) {
-        if (DEBUG_LAYOUT) Log.v(TAG, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
+        if (DEBUG_LAYOUT) Log.v(mTag, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
         if (mTranslator != null) {
             PointF point = new PointF(newX, newY);
             mTranslator.translatePointInScreenToAppWindow(point);
@@ -6264,6 +6415,16 @@
         mHandler.sendMessage(msg);
     }
 
+    public void updatePointerIcon(float x, float y) {
+        final int what = MSG_UPDATE_POINTER_ICON;
+        mHandler.removeMessages(what);
+        final long now = SystemClock.uptimeMillis();
+        final MotionEvent event = MotionEvent.obtain(
+                0, now, MotionEvent.ACTION_HOVER_MOVE, x, y, 0);
+        Message msg = mHandler.obtainMessage(what, event);
+        mHandler.sendMessage(msg);
+    }
+
     public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
             int localValue, int localChanges) {
         SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
@@ -6281,6 +6442,10 @@
         }
     }
 
+    public void dispatchRequestKeyboardShortcuts(IResultReceiver receiver) {
+        mHandler.obtainMessage(MSG_REQUEST_KEYBOARD_SHORTCUTS, receiver).sendToTarget();
+    }
+
     /**
      * Post a callback to send a
      * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
@@ -6571,16 +6736,19 @@
 
     @Override
     public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
+        if (rectangle == null) {
+            return scrollToRectOrFocus(null, immediate);
+        }
+        rectangle.offset(child.getLeft() - child.getScrollX(),
+                child.getTop() - child.getScrollY());
         final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
-        if (rectangle != null) {
-            mTempRect.set(rectangle);
-            mTempRect.offset(0, -mCurScrollY);
-            mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
-            try {
-                mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect);
-            } catch (RemoteException re) {
-                /* ignore */
-            }
+        mTempRect.set(rectangle);
+        mTempRect.offset(0, -mCurScrollY);
+        mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
+        try {
+            mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect);
+        } catch (RemoteException re) {
+            /* ignore */
         }
         return scrolled;
     }
@@ -6641,7 +6809,7 @@
     }
 
     void changeCanvasOpacity(boolean opaque) {
-        Log.d(TAG, "changeCanvasOpacity: opaque=" + opaque);
+        Log.d(mTag, "changeCanvasOpacity: opaque=" + opaque);
         if (mAttachInfo.mHardwareRenderer != null) {
             mAttachInfo.mHardwareRenderer.setOpaque(opaque);
         }
@@ -6717,11 +6885,12 @@
         @Override
         public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
                 Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
-                Configuration newConfig, Rect backDropFrame) {
+                Configuration newConfig, Rect backDropFrame, boolean forceLayout) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
                 viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
-                        visibleInsets, stableInsets, outsets, reportDraw, newConfig, backDropFrame);
+                        visibleInsets, stableInsets, outsets, reportDraw, newConfig, backDropFrame,
+                        forceLayout);
             }
         }
 
@@ -6838,6 +7007,14 @@
         }
 
         @Override
+        public void updatePointerIcon(float x, float y) {
+            final ViewRootImpl viewAncestor = mViewAncestor.get();
+            if (viewAncestor != null) {
+                viewAncestor.updatePointerIcon(x, y);
+            }
+        }
+
+        @Override
         public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
                 int localValue, int localChanges) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
@@ -6854,6 +7031,14 @@
                 viewAncestor.dispatchWindowShown();
             }
         }
+
+        @Override
+        public void requestAppKeyboardShortcuts(IResultReceiver receiver) {
+          ViewRootImpl viewAncestor = mViewAncestor.get();
+          if (viewAncestor != null) {
+            viewAncestor.dispatchRequestKeyboardShortcuts(receiver);
+          }
+        }
     }
 
     public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
@@ -6927,6 +7112,15 @@
     }
 
     /**
+     * Tells this instance that its corresponding activity has just relaunched. In this case, we
+     * need to force a relayout of the window to make sure we get the correct bounds from window
+     * manager.
+     */
+    public void reportActivityRelaunched() {
+        mActivityRelaunched = true;
+    }
+
+    /**
      * Class for managing the accessibility interaction connection
      * based on the global accessibility state.
      */
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index d7a98ab..ee70891 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -34,6 +34,7 @@
 import android.media.session.MediaController;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemProperties;
@@ -42,6 +43,8 @@
 import android.transition.TransitionManager;
 import android.view.accessibility.AccessibilityEvent;
 
+import java.util.List;
+
 /**
  * Abstract base class for a top-level window look and behavior policy.  An
  * instance of this class should be used as the top-level view added to the
@@ -556,6 +559,15 @@
          * @param mode The mode that was just finished.
          */
         public void onActionModeFinished(ActionMode mode);
+
+        /**
+         * Called when Keyboard Shortcuts are requested for the current window.
+         *
+         * @param data The data list to populate with shortcuts.
+         * @param menu The current menu, which may be null.
+         */
+        public void onProvideKeyboardShortcuts(
+                List<KeyboardShortcutGroup> data, @Nullable Menu menu);
     }
 
     /** @hide */
@@ -571,14 +583,11 @@
     /** @hide */
     public interface WindowControllerCallback {
         /**
-         * Called to move the window and its activity/task to a different stack container.
-         * For example, a window can move between
-         * {@link android.app.ActivityManager.StackId#FULLSCREEN_WORKSPACE_STACK_ID} stack and
-         * {@link android.app.ActivityManager.StackId#FREEFORM_WORKSPACE_STACK_ID} stack.
-         *
-         * @param stackId stack Id to change to.
+         * Moves the activity from
+         * {@link android.app.ActivityManager.StackId#FREEFORM_WORKSPACE_STACK_ID} to
+         * {@link android.app.ActivityManager.StackId#FULLSCREEN_WORKSPACE_STACK_ID} stack.
          */
-        void changeWindowStack(int stackId) throws RemoteException;
+        void exitFreeformMode() throws RemoteException;
 
         /** Returns the current stack Id for the window. */
         int getWindowStackId() throws RemoteException;
@@ -786,6 +795,40 @@
         return mCallback;
     }
 
+    /**
+     * Set an observer to collect frame stats for each frame rendererd in this window.
+     *
+     * Must be in hardware rendering mode.
+     * @hide
+     */
+    public final void addFrameStatsObserver(@NonNull FrameStatsObserver fso) {
+        final View decorView = getDecorView();
+        if (decorView == null) {
+            throw new IllegalStateException("can't observe a Window without an attached view");
+        }
+
+        if (fso == null) {
+            throw new NullPointerException("FrameStatsObserver cannot be null");
+        }
+
+        if (fso.isRegistered()) {
+            throw new IllegalStateException("FrameStatsObserver already registered on a Window.");
+        }
+
+        decorView.addFrameStatsObserver(fso);
+    }
+
+    /**
+     * Remove observer and stop listening to frame stats for this window.
+     * @hide
+     */
+    public final void removeFrameStatsObserver(FrameStatsObserver fso) {
+        final View decorView = getDecorView();
+        if (decorView != null) {
+            getDecorView().removeFrameStatsObserver(fso);
+        }
+    }
+
     /** @hide */
     public final void setOnWindowDismissedCallback(OnWindowDismissedCallback dcb) {
         mOnWindowDismissedCallback = dcb;
@@ -2112,4 +2155,10 @@
      * @hide
      */
     public abstract void onMultiWindowModeChanged();
+
+    /**
+     * Called when the activity just relaunched.
+     * @hide
+     */
+    public abstract void reportActivityRelaunched();
 }
diff --git a/core/java/android/view/WindowCallbackWrapper.java b/core/java/android/view/WindowCallbackWrapper.java
index 8ce1f8c..bed74e9 100644
--- a/core/java/android/view/WindowCallbackWrapper.java
+++ b/core/java/android/view/WindowCallbackWrapper.java
@@ -19,6 +19,8 @@
 
 import android.view.accessibility.AccessibilityEvent;
 
+import java.util.List;
+
 /**
  * A simple decorator stub for Window.Callback that passes through any calls
  * to the wrapped instance as a base implementation. Call super.foo() to call into
@@ -150,5 +152,10 @@
     public void onActionModeFinished(ActionMode mode) {
         mWrapped.onActionModeFinished(mode);
     }
+
+    @Override
+    public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, Menu menu) {
+        mWrapped.onProvideKeyboardShortcuts(data, menu);
+    }
 }
 
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 2e884cc..0c5a5fc 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -29,6 +29,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import java.util.List;
+
 
 /**
  * The interface that apps use to talk to the window manager.
@@ -118,6 +120,34 @@
      */
     public void removeViewImmediate(View view);
 
+    /**
+     * Used to asynchronously request Keyboard Shortcuts from the focused window.
+     *
+     * @hide
+     */
+    public interface KeyboardShortcutsReceiver {
+        /**
+         * Callback used when the focused window keyboard shortcuts are ready to be displayed.
+         *
+         * @param result The keyboard shortcuts to be displayed.
+         */
+        void onKeyboardShortcutsReceived(List<KeyboardShortcutGroup> result);
+    }
+
+    /**
+     * @hide
+     */
+    public static final String PARCEL_KEY_SHORTCUTS_ARRAY = "shortcuts_array";
+
+    /**
+     * Request for keyboard shortcuts to be retrieved asynchronously.
+     *
+     * @param receiver The callback to be triggered when the result is ready.
+     *
+     * @hide
+     */
+    public void requestAppKeyboardShortcuts(final KeyboardShortcutsReceiver receiver);
+
     public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
         /**
          * X position for this window.  With the default gravity it is ignored.
@@ -559,14 +589,14 @@
         public static final int TYPE_VOICE_INTERACTION = FIRST_SYSTEM_WINDOW+31;
 
         /**
-         * Window type: Windows that are overlaid <em>only</em> by an {@link
+         * Window type: Windows that are overlaid <em>only</em> by a connected {@link
          * android.accessibilityservice.AccessibilityService} for interception of
          * user interactions without changing the windows an accessibility service
          * can introspect. In particular, an accessibility service can introspect
          * only windows that a sighted user can interact with which is they can touch
          * these windows or can type into these windows. For example, if there
          * is a full screen accessibility overlay that is touchable, the windows
-         * below it will be introspectable by an accessibility service regardless
+         * below it will be introspectable by an accessibility service even though
          * they are covered by a touchable window.
          */
         public static final int TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32;
@@ -1183,6 +1213,13 @@
         public static final int PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH = 0x00008000;
 
         /**
+         * Flag to indicate that this child window should always be laid-out in the parent
+         * frame regardless of the current windowing mode configuration.
+         * @hide
+         */
+        public static final int PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME = 0x00010000;
+
+        /**
          * Control flags that are private to the platform.
          * @hide
          */
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 8c68e92..1530b47 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -30,6 +30,7 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.view.inputmethod.InputMethodManager;
+
 import com.android.internal.util.FastPrintWriter;
 
 import java.io.FileDescriptor;
@@ -70,16 +71,23 @@
     public static final int RELAYOUT_RES_SURFACE_CHANGED = 0x4;
 
     /**
+     * The window is being resized by dragging on the docked divider. The client should render
+     * at (0, 0) and extend its background to the background frame passed into
+     * {@link IWindow#resized}.
+     */
+    public static final int RELAYOUT_RES_DRAG_RESIZING_DOCKED = 0x8;
+
+    /**
      * The window is being resized by dragging one of the window corners,
      * in this case the surface would be fullscreen-sized. The client should
      * render to the actual frame location (instead of (0,curScrollY)).
      */
-    public static final int RELAYOUT_RES_DRAG_RESIZING = 0x8;
+    public static final int RELAYOUT_RES_DRAG_RESIZING_FREEFORM = 0x10;
 
     /**
      * The window manager has changed the size of the surface from the last call.
      */
-    public static final int RELAYOUT_RES_SURFACE_RESIZED = 0x10;
+    public static final int RELAYOUT_RES_SURFACE_RESIZED = 0x20;
 
     /**
      * Flag for relayout: the client will be later giving
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 98e9f54..6e11671 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -17,7 +17,15 @@
 package android.view;
 
 import android.annotation.NonNull;
+import android.content.Context;
+import android.os.Bundle;
 import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.internal.os.IResultReceiver;
+import com.android.internal.R;
+
+import java.util.List;
 
 /**
  * Provides low-level communication with the system window manager for
@@ -117,6 +125,23 @@
     }
 
     @Override
+    public void requestAppKeyboardShortcuts(final KeyboardShortcutsReceiver receiver) {
+        IResultReceiver resultReceiver = new IResultReceiver.Stub() {
+            @Override
+            public void send(int resultCode, Bundle resultData) throws RemoteException {
+                List<KeyboardShortcutGroup> result =
+                        resultData.getParcelableArrayList(PARCEL_KEY_SHORTCUTS_ARRAY);
+                receiver.onKeyboardShortcutsReceived(result);
+            }
+        };
+        try {
+            WindowManagerGlobal.getWindowManagerService()
+                .requestAppKeyboardShortcuts(resultReceiver);
+        } catch (RemoteException e) {
+        }
+    }
+
+    @Override
     public Display getDefaultDisplay() {
         return mDisplay;
     }
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 01bfbb5..6e38b32 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -441,12 +441,6 @@
         public int getCameraLensCoverState();
 
         /**
-         * Switch the keyboard layout for the given device.
-         * Direction should be +1 or -1 to go to the next or previous keyboard layout.
-         */
-        public void switchKeyboardLayout(int deviceId, int direction);
-
-        /**
          * Switch the input method, to be precise, input method subtype.
          *
          * @param forwardDirection {@code true} to rotate in a forward direction.
@@ -623,14 +617,16 @@
      * decorations that can never be removed.  That is, system bar or
      * button bar.
      */
-    public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation);
+    public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation,
+            int uiMode);
 
     /**
      * Return the display height available after excluding any screen
      * decorations that can never be removed.  That is, system bar or
      * button bar.
      */
-    public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation);
+    public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation,
+            int uiMode);
 
     /**
      * Return the available screen width that we should report for the
@@ -638,7 +634,8 @@
      * {@link #getNonDecorDisplayWidth(int, int, int)}; it may be smaller than
      * that to account for more transient decoration like a status bar.
      */
-    public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation);
+    public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation,
+            int uiMode);
 
     /**
      * Return the available screen height that we should report for the
@@ -646,7 +643,8 @@
      * {@link #getNonDecorDisplayHeight(int, int, int)}; it may be smaller than
      * that to account for more transient decoration like a status bar.
      */
-    public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation);
+    public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation,
+            int uiMode);
 
     /**
      * Return whether the given window is forcibly hiding all windows except windows with
@@ -861,11 +859,11 @@
      * @param isDefaultDisplay true if window is on {@link Display#DEFAULT_DISPLAY}.
      * @param displayWidth The current full width of the screen.
      * @param displayHeight The current full height of the screen.
-     * @param displayRotation The current rotation being applied to the base
-     * window.
+     * @param displayRotation The current rotation being applied to the base window.
+     * @param uiMode The current uiMode in configuration.
      */
     public void beginLayoutLw(boolean isDefaultDisplay, int displayWidth, int displayHeight,
-                              int displayRotation);
+                              int displayRotation, int uiMode);
 
     /**
      * Returns the bottom-most layer of the system decor, above which no policy decor should
@@ -1324,4 +1322,15 @@
      * @param fadeoutDuration the duration of the exit animation, in milliseconds
      */
     public void startKeyguardExitAnimation(long startTime, long fadeoutDuration);
+
+    /**
+     * Calculates the stable insets without running a layout.
+     *
+     * @param displayRotation the current display rotation
+     * @param displayWidth the current display width
+     * @param displayHeight the current display height
+     * @param outInsets the insets to return
+     */
+    public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
+            Rect outInsets);
 }
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 1735e1b..b673386 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -38,8 +38,8 @@
 /**
  * This class represents a node of the window content as well as actions that
  * can be requested from its source. From the point of view of an
- * {@link android.accessibilityservice.AccessibilityService} a window content is
- * presented as tree of accessibility node info which may or may not map one-to-one
+ * {@link android.accessibilityservice.AccessibilityService} a window's content is
+ * presented as a tree of accessibility node infos, which may or may not map one-to-one
  * to the view hierarchy. In other words, a custom view is free to report itself as
  * a tree of accessibility node info.
  * </p>
@@ -50,7 +50,7 @@
  * <p>
  * Please refer to {@link android.accessibilityservice.AccessibilityService} for
  * details about how to obtain a handle to window content as a tree of accessibility
- * node info as well as familiarizing with the security model.
+ * node info as well as details about the security model.
  * </p>
  * <div class="special reference">
  * <h3>Developer Guides</h3>
@@ -647,6 +647,7 @@
     private int mBooleanProperties;
     private final Rect mBoundsInParent = new Rect();
     private final Rect mBoundsInScreen = new Rect();
+    private int mDrawingOrderInParent;
 
     private CharSequence mPackageName;
     private CharSequence mClassName;
@@ -1892,6 +1893,37 @@
     }
 
     /**
+     * Get the drawing order of the view corresponding it this node.
+     * <p>
+     * Drawing order is determined only within the node's parent, so this index is only relative
+     * to its siblings.
+     * <p>
+     * In some cases, the drawing order is essentially simultaneous, so it is possible for two
+     * siblings to return the same value. It is also possible that values will be skipped.
+     *
+     * @return The drawing position of the view corresponding to this node relative to its siblings.
+     */
+    public int getDrawingOrder() {
+        return mDrawingOrderInParent;
+    }
+
+    /**
+     * Set the drawing order of the view corresponding it this node.
+     *
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     * @param drawingOrderInParent
+     * @throws IllegalStateException If called from an AccessibilityService.
+     */
+    public void setDrawingOrder(int drawingOrderInParent) {
+        enforceNotSealed();
+        mDrawingOrderInParent = drawingOrderInParent;
+    }
+
+    /**
      * Gets the collection info if the node is a collection. A collection
      * child is always a collection item.
      *
@@ -2390,18 +2422,30 @@
     }
 
     /**
-     * Gets the text selection start.
+     * Gets the text selection start or the cursor position.
+     * <p>
+     * If no text is selected, both this method and
+     * {@link AccessibilityNodeInfo#getTextSelectionEnd()} return the same value:
+     * the current location of the cursor.
+     * </p>
      *
-     * @return The text selection start if there is selection or -1.
+     * @return The text selection start, the cursor location if there is no selection, or -1 if
+     *         there is no text selection and no cursor.
      */
     public int getTextSelectionStart() {
         return mTextSelectionStart;
     }
 
     /**
-     * Gets the text selection end.
+     * Gets the text selection end if text is selected.
+     * <p>
+     * If no text is selected, both this method and
+     * {@link AccessibilityNodeInfo#getTextSelectionStart()} return the same value:
+     * the current location of the cursor.
+     * </p>
      *
-     * @return The text selection end if there is selection or -1.
+     * @return The text selection end, the cursor location if there is no selection, or -1 if
+     *         there is no text selection and no cursor.
      */
     public int getTextSelectionEnd() {
         return mTextSelectionEnd;
@@ -2753,6 +2797,7 @@
         parcel.writeInt(mTextSelectionEnd);
         parcel.writeInt(mInputType);
         parcel.writeInt(mLiveRegion);
+        parcel.writeInt(mDrawingOrderInParent);
 
         if (mExtras != null) {
             parcel.writeInt(1);
@@ -2850,6 +2895,7 @@
         mTextSelectionEnd = other.mTextSelectionEnd;
         mInputType = other.mInputType;
         mLiveRegion = other.mLiveRegion;
+        mDrawingOrderInParent = other.mDrawingOrderInParent;
         if (other.mExtras != null && !other.mExtras.isEmpty()) {
             getExtras().putAll(other.mExtras);
         }
@@ -2927,6 +2973,7 @@
 
         mInputType = parcel.readInt();
         mLiveRegion = parcel.readInt();
+        mDrawingOrderInParent = parcel.readInt();
 
         if (parcel.readInt() == 1) {
             getExtras().putAll(parcel.readBundle());
@@ -2982,6 +3029,7 @@
         mBoundsInParent.set(0, 0, 0, 0);
         mBoundsInScreen.set(0, 0, 0, 0);
         mBooleanProperties = 0;
+        mDrawingOrderInParent = 0;
         mPackageName = null;
         mClassName = null;
         mText = null;
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index b6570cc..9e79057 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -58,5 +58,5 @@
     void temporaryEnableAccessibilityStateUntilKeyguardRemoved(in ComponentName service,
             boolean touchExplorationEnabled);
 
-    IBinder getWindowToken(int windowId);
+    IBinder getWindowToken(int windowId, int userId);
 }
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index e0dbe2f..1536c29 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -850,7 +850,7 @@
             normalizedTime = currentTime < mStartTime ? 0.0f : 1.0f;
         }
 
-        final boolean expired = normalizedTime >= 1.0f;
+        final boolean expired = normalizedTime >= 1.0f || isCanceled();
         mMore = !expired;
 
         if (!mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);
@@ -875,7 +875,7 @@
         }
 
         if (expired) {
-            if (mRepeatCount == mRepeated) {
+            if (mRepeatCount == mRepeated || isCanceled()) {
                 if (!mEnded) {
                     mEnded = true;
                     guard.close();
@@ -905,6 +905,10 @@
         return mMore;
     }
 
+    private boolean isCanceled() {
+        return mStartTime == Long.MIN_VALUE;
+    }
+
     private void fireAnimationStart() {
         if (mListener != null) {
             if (mListenerHandler == null) mListener.onAnimationStart(this);
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index ba5d6c2..a10f792 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -195,16 +195,22 @@
     public boolean commitText(CharSequence text, int newCursorPosition) {
         if (DEBUG) Log.v(TAG, "commitText " + text);
         replaceText(text, newCursorPosition, false);
-        mIMM.notifyUserAction();
         sendCurrentText();
         return true;
     }
 
     /**
-     * The default implementation performs the deletion around the current
-     * selection position of the editable text.
-     * @param beforeLength
-     * @param afterLength
+     * The default implementation performs the deletion around the current selection position of the
+     * editable text.
+     *
+     * @param beforeLength The number of characters before the cursor to be deleted, in code unit.
+     *        If this is greater than the number of existing characters between the beginning of the
+     *        text and the cursor, then this method does not fail but deletes all the characters in
+     *        that range.
+     * @param afterLength The number of characters after the cursor to be deleted, in code unit.
+     *        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.
      */
     public boolean deleteSurroundingText(int beforeLength, int afterLength) {
         if (DEBUG) Log.v(TAG, "deleteSurroundingText " + beforeLength
@@ -213,7 +219,7 @@
         if (content == null) return false;
 
         beginBatchEdit();
-        
+
         int a = Selection.getSelectionStart(content);
         int b = Selection.getSelectionEnd(content);
 
@@ -223,7 +229,7 @@
             b = tmp;
         }
 
-        // ignore the composing text.
+        // Ignore the composing text.
         int ca = getComposingSpanStart(content);
         int cb = getComposingSpanEnd(content);
         if (cb < ca) {
@@ -253,9 +259,170 @@
 
             content.delete(b, end);
         }
-        
+
         endBatchEdit();
-        
+
+        return true;
+    }
+
+    private static int INVALID_INDEX = -1;
+    private static int findIndexBackward(final CharSequence cs, final int from,
+            final int numCodePoints) {
+        int currentIndex = from;
+        boolean waitingHighSurrogate = false;
+        final int N = cs.length();
+        if (currentIndex < 0 || N < currentIndex) {
+            return INVALID_INDEX;  // The starting point is out of range.
+        }
+        if (numCodePoints < 0) {
+            return INVALID_INDEX;  // Basically this should not happen.
+        }
+        int remainingCodePoints = numCodePoints;
+        while (true) {
+            if (remainingCodePoints == 0) {
+                return currentIndex;  // Reached to the requested length in code points.
+            }
+
+            --currentIndex;
+            if (currentIndex < 0) {
+                if (waitingHighSurrogate) {
+                    return INVALID_INDEX;  // An invalid surrogate pair is found.
+                }
+                return 0;  // Reached to the beginning of the text w/o any invalid surrogate pair.
+            }
+            final char c = cs.charAt(currentIndex);
+            if (waitingHighSurrogate) {
+                if (!java.lang.Character.isHighSurrogate(c)) {
+                    return INVALID_INDEX;  // An invalid surrogate pair is found.
+                }
+                waitingHighSurrogate = false;
+                --remainingCodePoints;
+                continue;
+            }
+            if (!java.lang.Character.isSurrogate(c)) {
+                --remainingCodePoints;
+                continue;
+            }
+            if (java.lang.Character.isHighSurrogate(c)) {
+                return INVALID_INDEX;  // A invalid surrogate pair is found.
+            }
+            waitingHighSurrogate = true;
+        }
+    }
+
+    private static int findIndexForward(final CharSequence cs, final int from,
+            final int numCodePoints) {
+        int currentIndex = from;
+        boolean waitingLowSurrogate = false;
+        final int N = cs.length();
+        if (currentIndex < 0 || N < currentIndex) {
+            return INVALID_INDEX;  // The starting point is out of range.
+        }
+        if (numCodePoints < 0) {
+            return INVALID_INDEX;  // Basically this should not happen.
+        }
+        int remainingCodePoints = numCodePoints;
+
+        while (true) {
+            if (remainingCodePoints == 0) {
+                return currentIndex;  // Reached to the requested length in code points.
+            }
+
+            if (currentIndex >= N) {
+                if (waitingLowSurrogate) {
+                    return INVALID_INDEX;  // An invalid surrogate pair is found.
+                }
+                return N;  // Reached to the end of the text w/o any invalid surrogate pair.
+            }
+            final char c = cs.charAt(currentIndex);
+            if (waitingLowSurrogate) {
+                if (!java.lang.Character.isLowSurrogate(c)) {
+                    return INVALID_INDEX;  // An invalid surrogate pair is found.
+                }
+                --remainingCodePoints;
+                waitingLowSurrogate = false;
+                ++currentIndex;
+                continue;
+            }
+            if (!java.lang.Character.isSurrogate(c)) {
+                --remainingCodePoints;
+                ++currentIndex;
+                continue;
+            }
+            if (java.lang.Character.isLowSurrogate(c)) {
+                return INVALID_INDEX;  // A invalid surrogate pair is found.
+            }
+            waitingLowSurrogate = true;
+            ++currentIndex;
+        }
+    }
+
+    /**
+     * The default implementation performs the deletion around the current selection position of the
+     * editable text.
+     * @param beforeLength The number of characters before the cursor to be deleted, in code points.
+     *        If this is greater than the number of existing characters between the beginning of the
+     *        text and the cursor, then this method does not fail but deletes all the characters in
+     *        that range.
+     * @param afterLength The number of characters after the cursor to be deleted, in code points.
+     *        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.
+     */
+    public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
+        if (DEBUG) Log.v(TAG, "deleteSurroundingText " + beforeLength
+                + " / " + afterLength);
+        final Editable content = getEditable();
+        if (content == null) return false;
+
+        beginBatchEdit();
+
+        int a = Selection.getSelectionStart(content);
+        int b = Selection.getSelectionEnd(content);
+
+        if (a > b) {
+            int tmp = a;
+            a = b;
+            b = tmp;
+        }
+
+        // Ignore the composing text.
+        int ca = getComposingSpanStart(content);
+        int cb = getComposingSpanEnd(content);
+        if (cb < ca) {
+            int tmp = ca;
+            ca = cb;
+            cb = tmp;
+        }
+        if (ca != -1 && cb != -1) {
+            if (ca < a) a = ca;
+            if (cb > b) b = cb;
+        }
+
+        if (a >= 0 && b >= 0) {
+            final int start = findIndexBackward(content, a, Math.max(beforeLength, 0));
+            if (start != INVALID_INDEX) {
+                final int end = findIndexForward(content, b, Math.max(afterLength, 0));
+                if (end != INVALID_INDEX) {
+                    final int numDeleteBefore = a - start;
+                    if (numDeleteBefore > 0) {
+                        content.delete(start, a);
+                    }
+                    final int numDeleteAfter = end - b;
+                    if (numDeleteAfter > 0) {
+                        content.delete(b - numDeleteBefore, end - numDeleteBefore);
+                    }
+                }
+            }
+            // NOTE: You may think we should return false here if start and/or end is INVALID_INDEX,
+            // but the truth is that IInputConnectionWrapper running in the middle of IPC calls
+            // always returns true to the IME without waiting for the completion of this method as
+            // IInputConnectionWrapper#isAtive() returns true.  This is actually why some methods
+            // including this method look like asynchronous calls from the IME.
+        }
+
+        endBatchEdit();
+
         return true;
     }
 
@@ -443,7 +610,6 @@
     public boolean setComposingText(CharSequence text, int newCursorPosition) {
         if (DEBUG) Log.v(TAG, "setComposingText " + text);
         replaceText(text, newCursorPosition, true);
-        mIMM.notifyUserAction();
         return true;
     }
 
@@ -516,29 +682,17 @@
      * attached to the input connection's view.
      */
     public boolean sendKeyEvent(KeyEvent event) {
-        synchronized (mIMM.mH) {
-            ViewRootImpl viewRootImpl = mTargetView != null ? mTargetView.getViewRootImpl() : null;
-            if (viewRootImpl == null) {
-                if (mIMM.mServedView != null) {
-                    viewRootImpl = mIMM.mServedView.getViewRootImpl();
-                }
-            }
-            if (viewRootImpl != null) {
-                viewRootImpl.dispatchKeyFromIme(event);
-            }
-        }
-        mIMM.notifyUserAction();
+        mIMM.dispatchKeyEventFromInputMethod(mTargetView, event);
         return false;
     }
-    
+
     /**
      * Updates InputMethodManager with the current fullscreen mode.
      */
     public boolean reportFullscreenMode(boolean enabled) {
-        mIMM.setFullscreenMode(enabled);
         return true;
     }
-    
+
     private void sendCurrentText() {
         if (!mDummyMode) {
             return;
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index 3ff9522..85893b0 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -16,6 +16,7 @@
 
 package android.view.inputmethod;
 
+import android.annotation.Nullable;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -341,20 +342,26 @@
     public Bundle extras;
 
     /**
-     * Additional context information that tells what languages are expected by the user.
+     * List of the languages that the user is supposed to switch to no matter what input method
+     * subtype is currently used.  This special "hint" can be used mainly for, but not limited to,
+     * multilingual users who want IMEs to switch language context automatically.
      *
-     * <p><strong>IME authors:</strong> Possible use cases for IME developers would be:</p>
-     * <ul>
-     *     <li>Automatically switching keyboard layout.</li>
-     *     <li>Changing language model for better typing experience.</li>
-     * </ul>
+     * <p>{@code null} means that no special language "hint" is needed.</p>
      *
-     * <p><strong>Editor authors:</strong> Providing this context information can help IMEs to
-     * improve text input experience.  For example, chat applications can remember what language is
-     * used in the last conversation for each chat session, and put the last used language at the
-     * top of {@link #locales}.</p>
+     * <p><strong>Editor authors:</strong> Specify this only when you are confident that the user
+     * will switch to certain languages in this context no matter what input method subtype is
+     * currently selected.  Otherwise, keep this {@code null}.  Explicit user actions and/or
+     * preferences would be good signals to specify this special "hint",  For example, a chat
+     * application may be able to put the last used language at the top of {@link #hintLocales}
+     * based on whom the user is going to talk, by remembering what language is used in the last
+     * conversation.  Do not specify {@link android.widget.TextView#getTextLocales()} only because
+     * it is used for text rendering.</p>
+     *
+     * @see android.widget.TextView#setImeHintLocales(LocaleList)
+     * @see android.widget.TextView#getImeHintLocales()
      */
-    public LocaleList locales = LocaleList.getEmptyLocaleList();
+    @Nullable
+    public LocaleList hintLocales = null;
 
     /**
      * Ensure that the data in this EditorInfo is compatible with an application
@@ -410,7 +417,7 @@
                 + " fieldId=" + fieldId
                 + " fieldName=" + fieldName);
         pw.println(prefix + "extras=" + extras);
-        pw.println(prefix + "locales=" + locales);
+        pw.println(prefix + "hintLocales=" + hintLocales);
     }
 
     /**
@@ -434,7 +441,11 @@
         dest.writeInt(fieldId);
         dest.writeString(fieldName);
         dest.writeBundle(extras);
-        locales.writeToParcel(dest, flags);
+        if (hintLocales != null) {
+            hintLocales.writeToParcel(dest, flags);
+        } else {
+            LocaleList.getEmptyLocaleList().writeToParcel(dest, flags);
+        }
     }
 
     /**
@@ -458,7 +469,8 @@
                     res.fieldId = source.readInt();
                     res.fieldName = source.readString();
                     res.extras = source.readBundle();
-                    res.locales = LocaleList.CREATOR.createFromParcel(source);
+                    LocaleList hintLocales = LocaleList.CREATOR.createFromParcel(source);
+                    res.hintLocales = hintLocales.isEmpty() ? null : hintLocales;
                     return res;
                 }
 
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index ff992d3..eb773e2 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -335,16 +335,46 @@
      * but be careful to wait until the batch edit is over if one is
      * in progress.</p>
      *
-     * @param beforeLength The number of characters to be deleted before the
-     *        current cursor position.
-     * @param afterLength The number of characters to be deleted after the
-     *        current cursor position.
-     * @return true on success, false if the input connection is no longer
-     * valid.
+     * @param beforeLength The number of characters before the cursor to be deleted, in code unit.
+     *        If this is greater than the number of existing characters between the beginning of the
+     *        text and the cursor, then this method does not fail but deletes all the characters in
+     *        that range.
+     * @param afterLength The number of characters after the cursor to be deleted, in code unit.
+     *        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.
      */
     public boolean deleteSurroundingText(int beforeLength, int afterLength);
 
     /**
+     * A variant of {@link #deleteSurroundingText(int, int)}. Major differences are:
+     *
+     * <ul>
+     *     <li>The lengths are supplied in code points, not in Java chars or in glyphs.</>
+     *     <li>This method does nothing if there are one or more invalid surrogate pairs in the
+     *     requested range.</li>
+     * </ul>
+     *
+     * <p><strong>Editor authors:</strong> In addition to the requirement in
+     * {@link #deleteSurroundingText(int, int)}, make sure to do nothing when one ore more invalid
+     * surrogate pairs are found in the requested range.</p>
+     *
+     * @see #deleteSurroundingText(int, int)
+     *
+     * @param beforeLength The number of characters before the cursor to be deleted, in code points.
+     *        If this is greater than the number of existing characters between the beginning of the
+     *        text and the cursor, then this method does not fail but deletes all the characters in
+     *        that range.
+     * @param afterLength The number of characters after the cursor to be deleted, in code points.
+     *        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.
+     */
+    public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength);
+
+    /**
      * Replace the currently composing text with the given text, and
      * set the new cursor position. Any composing text set previously
      * will be removed automatically.
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index 231aa07..e5ae422 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -62,6 +62,10 @@
         return mTarget.getExtractedText(request, flags);
     }
 
+    public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
+        return mTarget.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
+    }
+
     public boolean deleteSurroundingText(int beforeLength, int afterLength) {
         return mTarget.deleteSurroundingText(beforeLength, afterLength);
     }
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 4fc6665..43306d0 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -191,6 +191,8 @@
                                     .InputMethod_Subtype_label, 0))
                             .setSubtypeIconResId(a.getResourceId(com.android.internal.R.styleable
                                     .InputMethod_Subtype_icon, 0))
+                            .setLanguageTag(a.getString(com.android.internal.R.styleable
+                                    .InputMethod_Subtype_languageTag))
                             .setSubtypeLocale(a.getString(com.android.internal.R.styleable
                                     .InputMethod_Subtype_imeSubtypeLocale))
                             .setSubtypeMode(a.getString(com.android.internal.R.styleable
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 5e07347..0ed2299 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -25,6 +25,8 @@
 import com.android.internal.view.InputBindResult;
 import com.android.internal.view.InputMethodClient;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.content.Context;
 import android.graphics.Rect;
@@ -527,7 +529,7 @@
             }
         }
     }
-    
+
     private static class ControlledInputConnectionWrapper extends IInputConnectionWrapper {
         private final InputMethodManager mParentInputMethodManager;
         private boolean mActive;
@@ -549,13 +551,23 @@
         }
 
         @Override
+        protected void onUserAction() {
+            mParentInputMethodManager.notifyUserAction();
+        }
+
+        @Override
+        protected void onReportFullscreenMode(boolean enabled) {
+            mParentInputMethodManager.setFullscreenMode(enabled);
+        }
+
+        @Override
         public String toString() {
             return "ControlledInputConnectionWrapper{mActive=" + mActive
                     + " mParentInputMethodManager.mActive=" + mParentInputMethodManager.mActive
                     + "}";
         }
     }
-    
+
     final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() {
         @Override
         protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
@@ -1813,6 +1825,34 @@
         return DISPATCH_NOT_HANDLED;
     }
 
+    /**
+     * Provides the default implementation of {@link InputConnection#sendKeyEvent(KeyEvent)}, which
+     * is expected to dispatch an keyboard event sent from the IME to an appropriate event target
+     * depending on the given {@link View} and the current focus state.
+     *
+     * <p>CAUTION: This method is provided only for the situation where
+     * {@link InputConnection#sendKeyEvent(KeyEvent)} needs to be implemented without relying on
+     * {@link BaseInputConnection}. Do not use this API for anything else.</p>
+     *
+     * @param targetView the default target view. If {@code null} is specified, then this method
+     * tries to find a good event target based on the current focus state.
+     * @param event the key event to be dispatched.
+     */
+    public void dispatchKeyEventFromInputMethod(@Nullable View targetView,
+            @NonNull KeyEvent event) {
+        synchronized (mH) {
+            ViewRootImpl viewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
+            if (viewRootImpl == null) {
+                if (mServedView != null) {
+                    viewRootImpl = mServedView.getViewRootImpl();
+                }
+            }
+            if (viewRootImpl != null) {
+                viewRootImpl.dispatchKeyFromIme(event);
+            }
+        }
+    }
+
     // Must be called on the main looper
     void sendInputEventAndReportResultOnMainLooper(PendingEvent p) {
         final boolean handled;
@@ -2163,6 +2203,17 @@
      * by changing its extra value. The different subtype won't get affected by the stored past
      * status. (You may want to take a look at {@link InputMethodSubtype#hashCode()} to refer
      * to the current implementation.)
+     *
+     * <p>NOTE: If the same subtype exists in both the manifest XML file and additional subtypes
+     * specified by {@code subtypes}, those multiple instances are automatically merged into one
+     * instance.</p>
+     *
+     * <p>CAVEAT: In API Level 23 and prior, the system may do nothing if an empty
+     * {@link InputMethodSubtype} is specified in {@code subtypes}, which prevents you from removing
+     * the last one entry of additional subtypes. If your IME statically defines one or more
+     * subtypes in the manifest XML file, you may be able to work around this limitation by
+     * specifying one of those statically defined subtypes in {@code subtypes}.</p>
+     *
      * @param imiId Id of InputMethodInfo which additional input method subtypes will be added to.
      * @param subtypes subtypes will be added as additional subtypes of the current input method.
      */
diff --git a/core/java/android/webkit/ServiceWorkerClient.java b/core/java/android/webkit/ServiceWorkerClient.java
new file mode 100644
index 0000000..85de698
--- /dev/null
+++ b/core/java/android/webkit/ServiceWorkerClient.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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;
+
+
+public class ServiceWorkerClient {
+
+    /**
+     * Notify the host application of a resource request and allow the
+     * application to return the data. If the return value is null, the
+     * Service Worker will continue to load the resource as usual.
+     * Otherwise, the return response and data will be used.
+     * NOTE: This method is called on a thread other than the UI thread
+     * so clients should exercise caution when accessing private data
+     * or the view system.
+     *
+     * @param request Object containing the details of the request.
+     * @return A {@link android.webkit.WebResourceResponse} containing the
+     *         response information or null if the WebView should load the
+     *         resource itself.
+     * @see {@link WebViewClient#shouldInterceptRequest()}
+     */
+    public WebResourceResponse shouldInterceptRequest(WebResourceRequest request) {
+        return null;
+    }
+}
+
diff --git a/core/java/android/webkit/ServiceWorkerController.java b/core/java/android/webkit/ServiceWorkerController.java
new file mode 100644
index 0000000..9115558
--- /dev/null
+++ b/core/java/android/webkit/ServiceWorkerController.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.webkit;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/**
+ * Manages Service Workers used by WebView.
+ */
+public abstract class ServiceWorkerController {
+
+    /**
+     * Returns the default ServiceWorkerController instance. At present there is
+     * only one ServiceWorkerController instance for all WebView instances,
+     * however this restriction may be relaxed in the future.
+     *
+     * @return The default ServiceWorkerController instance.
+     */
+     @NonNull
+     public static ServiceWorkerController getInstance() {
+         return WebViewFactory.getProvider().getServiceWorkerController();
+     }
+
+    /**
+     * Gets the settings for all service workers.
+     *
+     * @return The current ServiceWorkerWebSettings
+     */
+    @NonNull
+    public abstract ServiceWorkerWebSettings getServiceWorkerWebSettings();
+
+    /**
+     * Sets the client to capture service worker related callbacks.
+     */
+    public abstract void setServiceWorkerClient(@Nullable ServiceWorkerClient client);
+}
+
diff --git a/core/java/android/webkit/ServiceWorkerWebSettings.java b/core/java/android/webkit/ServiceWorkerWebSettings.java
new file mode 100644
index 0000000..8b104d1c
--- /dev/null
+++ b/core/java/android/webkit/ServiceWorkerWebSettings.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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;
+
+/**
+ * Manages settings state for all Service Workers. These settings are not tied to
+ * the lifetime of any WebView because service workers can outlive WebView instances.
+ * The settings are similar to {@link WebSettings} but only settings relevant to
+ * Service Workers are supported.
+ */
+// This is an abstract base class: concrete ServiceWorkerControllers must
+// create a class derived from this, and return an instance of it in the
+// ServiceWorkerController.getServiceWorkerWebSettings() method implementation.
+public abstract class ServiceWorkerWebSettings {
+
+    /**
+     * Overrides the way the cache is used, see {@link WebSettings#setCacheMode}.
+     *
+     * @param mode the mode to use
+     */
+    public abstract void setCacheMode(int mode);
+
+    /**
+     * Gets the current setting for overriding the cache mode.
+     *
+     * @return the current setting for overriding the cache mode
+     * @see #setCacheMode
+     */
+    public abstract int getCacheMode();
+
+    /**
+     * Enables or disables content URL access from Service Workers, see
+     * {@link WebSettings#setAllowContentAccess}.
+     */
+    public abstract void setAllowContentAccess(boolean allow);
+
+    /**
+     * Gets whether Service Workers support content URL access.
+     *
+     * @see #setAllowContentAccess
+     */
+    public abstract boolean getAllowContentAccess();
+
+    /**
+     * Enables or disables file access within Service Workers, see
+     * {@link WebSettings#setAllowFileAccess}.
+     */
+    public abstract void setAllowFileAccess(boolean allow);
+
+    /**
+     * Gets whether Service Workers support file access.
+     *
+     * @see #setAllowFileAccess
+     */
+    public abstract boolean getAllowFileAccess();
+
+    /**
+     * Sets whether the Service Workers should not load resources from the network,
+     * see {@link WebSettings#setBlockNetworkLoads}.
+     *
+     * @param flag whether the Service Workers should not load any resources from the
+     *             network
+     */
+    public abstract void setBlockNetworkLoads(boolean flag);
+
+    /**
+     * Gets whether Service Workers are prohibited from loading any resources from the network.
+     *
+     * @return true if the Service Workers are not allowed to load any resources from the network
+     * @see #setBlockNetworkLoads
+     */
+    public abstract boolean getBlockNetworkLoads();
+}
+
diff --git a/core/java/android/webkit/TokenBindingService.java b/core/java/android/webkit/TokenBindingService.java
new file mode 100644
index 0000000..f7caac7
--- /dev/null
+++ b/core/java/android/webkit/TokenBindingService.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.net.Uri;
+
+import java.security.KeyPair;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * Enables the token binding procotol, and provides access to the keys. See
+ * https://tools.ietf.org/html/draft-ietf-tokbind-protocol-03
+ *
+ * All methods are required to be called on the UI thread where WebView is
+ * attached to the View hierarchy.
+ * @hide
+ */
+@SystemApi
+public abstract class TokenBindingService {
+
+    public static final String KEY_ALGORITHM_RSA2048_PKCS_1_5 = "RSA2048_PKCS_1.5";
+    public static final String KEY_ALGORITHM_RSA2048_PSS = "RSA2048PSS";
+    public static final String KEY_ALGORITHM_ECDSAP256 = "ECDSAP256";
+
+    /**
+     * Provides the KeyPair information.
+     */
+    public static abstract class TokenBindingKey {
+        /**
+         * The public, private key pair.
+         */
+        public abstract KeyPair getKeyPair();
+
+        /**
+         * The algorithm that is used to generate the key pair.
+         */
+        public abstract String getAlgorithm();
+    }
+
+    /**
+     * Returns the default TokenBinding service instance. At present there is
+     * only one token binding service instance for all WebView instances,
+     * however this restriction may be relaxed in the future.
+     *
+     * @return The default TokenBindingService instance.
+     */
+    public static TokenBindingService getInstance() {
+        return WebViewFactory.getProvider().getTokenBindingService();
+    }
+
+    /**
+     * Enables the token binding protocol. The token binding protocol
+     * has to be enabled before creating any WebViews.
+     *
+     * @throws IllegalStateException if a WebView was already created.
+     */
+    public abstract void enableTokenBinding();
+
+    /**
+     * Retrieves the key pair for a given origin from the internal
+     * TokenBinding key store asynchronously.
+     *
+     * The user can provide a list of acceptable algorithms for the retrieved
+     * key pair. If a key pair exists and it is in the list of algorithms, then
+     * the key is returned. If it is not in the list, no key is returned.
+     *
+     * If no key pair exists, WebView chooses an algorithm from the list, in
+     * the order given, to generate a key.
+     *
+     * The user can pass a null if any algorithm is acceptable.
+     *
+     * @param origin The origin for the server.
+     * @param algorithm The list of algorithms. Can be null. An
+     *        IllegalArgumentException is thrown if array is empty.
+     * @param callback The callback that will be called when key is available.
+     *        Cannot be null.
+     */
+    public abstract void getKey(Uri origin,
+                                String[] algorithm,
+                                ValueCallback<TokenBindingKey> callback);
+    /**
+     * Deletes specified key (for use when associated cookie is cleared).
+     *
+     * @param origin The origin of the server.
+     * @param callback The callback that will be called when key is deleted. The
+     *        callback parameter (Boolean) will indicate if operation is
+     *        successful or if failed. The callback can be null.
+     */
+    public abstract void deleteKey(Uri origin,
+                                   ValueCallback<Boolean> callback);
+
+     /**
+      * Deletes all the keys (for use when cookies are cleared).
+      *
+      * @param callback The callback that will be called when keys are deleted.
+      *        The callback parameter (Boolean) will indicate if operation is
+      *        successful or if failed. The callback can be null.
+      */
+    public abstract void deleteAllKeys(ValueCallback<Boolean> callback);
+}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 9442226..9595db2 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -987,9 +987,6 @@
      * @deprecated Database paths are managed by the implementation and calling this method
      *             will have no effect.
      */
-    // This will update WebCore when the Sync runs in the C++ side.
-    // Note that the WebCore Database Tracker only allows the path to be set
-    // once.
     @Deprecated
     public abstract void setDatabasePath(String databasePath);
 
@@ -1000,8 +997,10 @@
      *
      * @param databasePath a path to the directory where databases should be
      *                     saved.
+     * @deprecated Geolocation database are managed by the implementation and calling this method
+     *             will have no effect.
      */
-    // This will update WebCore when the Sync runs in the C++ side.
+    @Deprecated
     public abstract void setGeolocationDatabasePath(String databasePath);
 
     /**
@@ -1102,8 +1101,6 @@
      *   via the JavaScript Geolocation API.
      * </ul>
      * <p>
-     * As an option, it is possible to store previous locations and web origin
-     * permissions in a database. See {@link #setGeolocationDatabasePath}.
      *
      * @param flag whether Geolocation should be enabled
      */
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 7443bce..0f58ba3 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -280,6 +280,23 @@
  * instead.
  * </p>
  *
+ * <h3>Metrics</h3>
+ *
+ * <p>
+ * WebView may upload anonymous diagnostic data to Google when the user has consented. This data
+ * 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" />
+ * </pre>
+ * <p>
+ * Data will only be uploaded for a given app if the user has consented AND the app has not opted
+ * out.
+ * </p>
+ *
  */
 // Implementation notes.
 // The WebView is a thin API class that delegates its public API to a backend WebViewProvider
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 01d1566..b04b4c0 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -131,9 +131,30 @@
     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
      * */
@@ -161,9 +182,13 @@
                         throw new MissingWebViewPackageException(
                                 "WebView provider in framework resources missing description");
                     }
-                    String signature = parser.getAttributeValue(null, TAG_SIGNATURE);
+                    String availableByDefault = parser.getAttributeValue(null, TAG_AVAILABILITY);
+                    if (availableByDefault == null) {
+                        availableByDefault = "false";
+                    }
                     webViewProviders.add(
-                            new WebViewProviderInfo(packageName, description, signature));
+                            new WebViewProviderInfo(packageName, description, availableByDefault,
+                                readSignatures(parser)));
                 }
                 else {
                     Log.e(LOGTAG, "Found an element that is not a webview provider");
@@ -252,28 +277,49 @@
 
     private static Class<WebViewFactoryProvider> getProviderClass() {
         try {
-            // First fetch the package info so we can log the webview package version.
-            int res = waitForProviderAndSetPackageInfo();
-            if (res != LIBLOAD_SUCCESS) {
-                throw new MissingWebViewPackageException(
-                        "Failed to load WebView provider, error: "
-                        + getWebViewPreparationErrorReason(res));
+            Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
+                    "WebViewFactory.waitForProviderAndSetPackageInfo()");
+            try {
+                // First fetch the package info so we can log the webview package version.
+                int res = waitForProviderAndSetPackageInfo();
+                if (res != LIBLOAD_SUCCESS) {
+                    throw new MissingWebViewPackageException(
+                            "Failed to load WebView provider, error: "
+                            + getWebViewPreparationErrorReason(res));
+                }
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
             }
             Log.i(LOGTAG, "Loading " + sPackageInfo.packageName + " version " +
                 sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")");
 
             Application initialApplication = AppGlobals.getInitialApplication();
             Context webViewContext = null;
+            Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "PackageManager.getApplicationInfo()");
             try {
                 // Construct a package context to load the Java code into the current app.
                 // This is done as early as possible since by constructing a package context we
                 // register the WebView package as a dependency for the current application so that
                 // when the WebView package is updated this application will be killed.
-                webViewContext = initialApplication.createPackageContext(
-                        sPackageInfo.packageName,
-                        Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+                ApplicationInfo applicationInfo =
+                    initialApplication.getPackageManager().getApplicationInfo(
+                        sPackageInfo.packageName, PackageManager.GET_SHARED_LIBRARY_FILES
+                        | PackageManager.MATCH_DEBUG_TRIAGED_MISSING
+                        // make sure that we fetch the current provider even if its not installed
+                        // for the current user
+                        | PackageManager.MATCH_UNINSTALLED_PACKAGES);
+                Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
+                        "initialApplication.createApplicationContext");
+                try {
+                    webViewContext = initialApplication.createApplicationContext(applicationInfo,
+                            Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
+                }
             } catch (PackageManager.NameNotFoundException e) {
                 throw new MissingWebViewPackageException(e);
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
             }
 
             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index 9105394..8359a10 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -103,6 +103,22 @@
     CookieManager getCookieManager();
 
     /**
+     * Gets the TokenBindingService instance for this WebView implementation. The
+     * implementation must return the same instance on subsequent calls.
+     *
+     * @return the TokenBindingService instance
+     */
+    TokenBindingService getTokenBindingService();
+
+    /**
+     * Gets the ServiceWorkerController instance for this WebView implementation. The
+     * implementation must return the same instance on subsequent calls.
+     *
+     * @return the ServiceWorkerController instance
+     */
+    ServiceWorkerController getServiceWorkerController();
+
+    /**
      * Gets the singleton WebIconDatabase instance for this WebView implementation. The
      * implementation must return the same instance on subsequent calls.
      *
diff --git a/core/java/android/webkit/WebViewProviderInfo.java b/core/java/android/webkit/WebViewProviderInfo.java
index d5e3a230..3f50fe2 100644
--- a/core/java/android/webkit/WebViewProviderInfo.java
+++ b/core/java/android/webkit/WebViewProviderInfo.java
@@ -40,10 +40,12 @@
         public WebViewPackageNotFoundException(Exception e) { super(e); }
     }
 
-    public WebViewProviderInfo(String packageName, String description, String signature) {
+    public WebViewProviderInfo(String packageName, String description, String availableByDefault,
+            String[] signatures) {
         this.packageName = packageName;
         this.description = description;
-        this.signature = signature;
+        this.availableByDefault = availableByDefault.equals("true");
+        this.signatures = signatures;
     }
 
     private boolean hasValidSignature() {
@@ -53,7 +55,7 @@
         try {
             // If no signature is declared, instead check whether the package is included in the
             // system.
-            if (signature == null)
+            if (signatures == null || signatures.length == 0)
                 return getPackageInfo().applicationInfo.isSystemApp();
 
             packageSignatures = getPackageInfo().signatures;
@@ -62,8 +64,15 @@
         }
         if (packageSignatures.length != 1)
             return false;
-        final byte[] releaseSignature = Base64.decode(signature, Base64.DEFAULT);
-        return Arrays.equals(releaseSignature, packageSignatures[0].toByteArray());
+
+        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;
     }
 
     /**
@@ -82,6 +91,39 @@
         return false;
     }
 
+    /**
+     * Returns whether this package is enabled.
+     * This state can be changed by the user from Settings->Apps
+     */
+    public boolean isEnabled() {
+        try {
+            PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
+            int enabled_state = pm.getApplicationEnabledSetting(packageName);
+            switch (enabled_state) {
+                case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:
+                    return true;
+                case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:
+                    ApplicationInfo applicationInfo = getPackageInfo().applicationInfo;
+                    return applicationInfo.enabled;
+                default:
+                    return false;
+            }
+        } catch (WebViewPackageNotFoundException e) {
+            return false;
+        } catch (IllegalArgumentException e) {
+            // Thrown by PackageManager.getApplicationEnabledSetting if the package does not exist
+            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;
+    }
+
     public PackageInfo getPackageInfo() {
         if (packageInfo == null) {
             try {
@@ -109,7 +151,7 @@
     private WebViewProviderInfo(Parcel in) {
         packageName = in.readString();
         description = in.readString();
-        signature = in.readString();
+        signatures = in.createStringArray();
         packageInfo = null;
     }
 
@@ -122,19 +164,19 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeString(packageName);
         out.writeString(description);
-        out.writeString(signature);
+        out.writeStringArray(signatures);
     }
 
     // fields read from framework resource
     public String packageName;
     public String description;
+    private boolean availableByDefault;
 
-    private String signature;
+    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;
-}
 
+    // 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;
+}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index e1ce9fe..df84970 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -1036,6 +1036,7 @@
             mChoiceActionMode = startActionMode(mMultiChoiceModeCallback);
         }
 
+        final boolean itemCheckChanged;
         if (mChoiceMode == CHOICE_MODE_MULTIPLE || mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL) {
             boolean oldValue = mCheckStates.get(position);
             mCheckStates.put(position, value);
@@ -1046,7 +1047,8 @@
                     mCheckedIdStates.delete(mAdapter.getItemId(position));
                 }
             }
-            if (oldValue != value) {
+            itemCheckChanged = oldValue != value;
+            if (itemCheckChanged) {
                 if (value) {
                     mCheckedItemCount++;
                 } else {
@@ -1062,6 +1064,7 @@
             boolean updateIds = mCheckedIdStates != null && mAdapter.hasStableIds();
             // Clear all values if we're checking something, or unchecking the currently
             // selected item
+            itemCheckChanged = isItemChecked(position) != value;
             if (value || isItemChecked(position)) {
                 mCheckStates.clear();
                 if (updateIds) {
@@ -1081,8 +1084,8 @@
             }
         }
 
-        // Do not generate a data change while we are in the layout phase
-        if (!mInLayout && !mBlockLayoutRequests) {
+        // Do not generate a data change while we are in the layout phase or data has not changed
+        if (!mInLayout && !mBlockLayoutRequests && itemCheckChanged) {
             mDataChanged = true;
             rememberSyncState();
             requestLayout();
@@ -3203,42 +3206,74 @@
         return mContextMenuInfo;
     }
 
-    /** @hide */
+    @Override
+    public boolean showContextMenu() {
+        return showContextMenuInternal(0, 0, false);
+    }
+
     @Override
     public boolean showContextMenu(float x, float y) {
+        return showContextMenuInternal(x, y, true);
+    }
+
+    private boolean showContextMenuInternal(float x, float y, boolean useOffsets) {
         final int position = pointToPosition((int)x, (int)y);
         if (position != INVALID_POSITION) {
             final long id = mAdapter.getItemId(position);
             View child = getChildAt(position - mFirstPosition);
             if (child != null) {
                 mContextMenuInfo = createContextMenuInfo(child, position, id);
-                return super.showContextMenuForChild(AbsListView.this, x, y);
+                if (useOffsets) {
+                    return super.showContextMenuForChild(this, x, y);
+                } else {
+                    return super.showContextMenuForChild(this);
+                }
             }
         }
-        return super.showContextMenu(x, y);
+        if (useOffsets) {
+            return super.showContextMenu(x, y);
+        } else {
+            return super.showContextMenu();
+        }
     }
 
     @Override
     public boolean showContextMenuForChild(View originalView) {
-        final int longPressPosition = getPositionForView(originalView);
-        if (longPressPosition >= 0) {
-            final long longPressId = mAdapter.getItemId(longPressPosition);
-            boolean handled = false;
+        return showContextMenuForChildInternal(originalView, 0, 0, false);
+    }
 
-            if (mOnItemLongClickListener != null) {
-                handled = mOnItemLongClickListener.onItemLongClick(AbsListView.this, originalView,
-                        longPressPosition, longPressId);
-            }
-            if (!handled) {
-                mContextMenuInfo = createContextMenuInfo(
-                        getChildAt(longPressPosition - mFirstPosition),
-                        longPressPosition, longPressId);
+    @Override
+    public boolean showContextMenuForChild(View originalView, float x, float y) {
+        return showContextMenuForChildInternal(originalView,x, y, true);
+    }
+
+    private boolean showContextMenuForChildInternal(View originalView, float x, float y,
+            boolean useOffsets) {
+        final int longPressPosition = getPositionForView(originalView);
+        if (longPressPosition < 0) {
+            return false;
+        }
+
+        final long longPressId = mAdapter.getItemId(longPressPosition);
+        boolean handled = false;
+
+        if (mOnItemLongClickListener != null) {
+            handled = mOnItemLongClickListener.onItemLongClick(this, originalView,
+                    longPressPosition, longPressId);
+        }
+
+        if (!handled) {
+            final View child = getChildAt(longPressPosition - mFirstPosition);
+            mContextMenuInfo = createContextMenuInfo(child, longPressPosition, longPressId);
+
+            if (useOffsets) {
+                handled = super.showContextMenuForChild(originalView, x, y);
+            } else {
                 handled = super.showContextMenuForChild(originalView);
             }
-
-            return handled;
         }
-        return false;
+
+        return handled;
     }
 
     @Override
@@ -3669,6 +3704,13 @@
         }
     }
 
+    /** @hide */
+    @Override
+    protected boolean handleScrollBarDragging(MotionEvent event) {
+        // Doesn't support normal scroll bar dragging. Use FastScroller.
+        return false;
+    }
+
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
         if (!isEnabled()) {
@@ -5803,6 +5845,11 @@
         }
 
         @Override
+        public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
+            return getTarget().deleteSurroundingTextInCodePoints(beforeLength, afterLength);
+        }
+
+        @Override
         public boolean setComposingText(CharSequence text, int newCursorPosition) {
             return getTarget().setComposingText(text, newCursorPosition);
         }
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index cf4587d..4ca8971 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -44,6 +44,12 @@
     private boolean mHasThumbTint = false;
     private boolean mHasThumbTintMode = false;
 
+    private Drawable mTickMark;
+    private ColorStateList mTickMarkTintList = null;
+    private PorterDuff.Mode mTickMarkTintMode = null;
+    private boolean mHasTickMarkTint = false;
+    private boolean mHasTickMarkTintMode = false;
+
     private int mThumbOffset;
     private boolean mSplitTrack;
 
@@ -103,10 +109,25 @@
             mHasThumbTint = true;
         }
 
+        final Drawable tickMark = a.getDrawable(R.styleable.SeekBar_tickMark);
+        setTickMark(tickMark);
+
+        if (a.hasValue(R.styleable.SeekBar_tickMarkTintMode)) {
+            mTickMarkTintMode = Drawable.parseTintMode(a.getInt(
+                    R.styleable.SeekBar_tickMarkTintMode, -1), mTickMarkTintMode);
+            mHasTickMarkTintMode = true;
+        }
+
+        if (a.hasValue(R.styleable.SeekBar_tickMarkTint)) {
+            mTickMarkTintList = a.getColorStateList(R.styleable.SeekBar_tickMarkTint);
+            mHasTickMarkTint = true;
+        }
+
         mSplitTrack = a.getBoolean(R.styleable.SeekBar_splitTrack, false);
 
         // Guess thumb offset if thumb != null, but allow layout to override.
-        final int thumbOffset = a.getDimensionPixelOffset(R.styleable.SeekBar_thumbOffset, getThumbOffset());
+        final int thumbOffset = a.getDimensionPixelOffset(
+                R.styleable.SeekBar_thumbOffset, getThumbOffset());
         setThumbOffset(thumbOffset);
 
         final boolean useDisabledAlpha = a.getBoolean(R.styleable.SeekBar_useDisabledAlpha, true);
@@ -121,6 +142,7 @@
         }
 
         applyThumbTint();
+        applyTickMarkTint();
 
         mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
     }
@@ -313,6 +335,123 @@
     }
 
     /**
+     * Sets the drawable displayed at each progress position, e.g. at each
+     * possible thumb position.
+     *
+     * @param tickMark the drawable to display at each progress position
+     */
+    public void setTickMark(Drawable tickMark) {
+        if (mTickMark != null) {
+            mTickMark.setCallback(null);
+        }
+
+        mTickMark = tickMark;
+
+        if (tickMark != null) {
+            tickMark.setCallback(this);
+            tickMark.setLayoutDirection(getLayoutDirection());
+            if (tickMark.isStateful()) {
+                tickMark.setState(getDrawableState());
+            }
+            applyTickMarkTint();
+        }
+
+        invalidate();
+    }
+
+    /**
+     * @return the drawable displayed at each progress position
+     */
+    public Drawable getTickMark() {
+        return mTickMark;
+    }
+
+    /**
+     * Applies a tint to the tick mark drawable. Does not modify the current tint
+     * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
+     * <p>
+     * Subsequent calls to {@link #setTickMark(Drawable)} will automatically
+     * mutate the drawable and apply the specified tint and tint mode using
+     * {@link Drawable#setTintList(ColorStateList)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#SeekBar_tickMarkTint
+     * @see #getTickMarkTintList()
+     * @see Drawable#setTintList(ColorStateList)
+     */
+    public void setTickMarkTintList(@Nullable ColorStateList tint) {
+        mTickMarkTintList = tint;
+        mHasTickMarkTint = true;
+
+        applyTickMarkTint();
+    }
+
+    /**
+     * Returns the tint applied to the tick mark drawable, if specified.
+     *
+     * @return the tint applied to the tick mark drawable
+     * @attr ref android.R.styleable#SeekBar_tickMarkTint
+     * @see #setTickMarkTintList(ColorStateList)
+     */
+    @Nullable
+    public ColorStateList getTickMarkTintList() {
+        return mTickMarkTintList;
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by
+     * {@link #setTickMarkTintList(ColorStateList)}} to the tick mark drawable. The
+     * default mode is {@link PorterDuff.Mode#SRC_IN}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#SeekBar_tickMarkTintMode
+     * @see #getTickMarkTintMode()
+     * @see Drawable#setTintMode(PorterDuff.Mode)
+     */
+    public void setTickMarkTintMode(@Nullable PorterDuff.Mode tintMode) {
+        mTickMarkTintMode = tintMode;
+        mHasTickMarkTintMode = true;
+
+        applyTickMarkTint();
+    }
+
+    /**
+     * Returns the blending mode used to apply the tint to the tick mark drawable,
+     * if specified.
+     *
+     * @return the blending mode used to apply the tint to the tick mark drawable
+     * @attr ref android.R.styleable#SeekBar_tickMarkTintMode
+     * @see #setTickMarkTintMode(PorterDuff.Mode)
+     */
+    @Nullable
+    public PorterDuff.Mode getTickMarkTintMode() {
+        return mTickMarkTintMode;
+    }
+
+    private void applyTickMarkTint() {
+        if (mTickMark != null && (mHasTickMarkTint || mHasTickMarkTintMode)) {
+            mTickMark = mTickMark.mutate();
+
+            if (mHasTickMarkTint) {
+                mTickMark.setTintList(mTickMarkTintList);
+            }
+
+            if (mHasTickMarkTintMode) {
+                mTickMark.setTintMode(mTickMarkTintMode);
+            }
+
+            // The drawable (or one of its children) may not have been
+            // stateful before applying the tint, so let's try again.
+            if (mTickMark.isStateful()) {
+                mTickMark.setState(getDrawableState());
+            }
+        }
+    }
+
+    /**
      * Sets the amount of progress changed via the arrow keys.
      *
      * @param increment The amount to increment or decrement when the user
@@ -347,7 +486,7 @@
 
     @Override
     protected boolean verifyDrawable(Drawable who) {
-        return who == mThumb || super.verifyDrawable(who);
+        return who == mThumb || who == mTickMark || super.verifyDrawable(who);
     }
 
     @Override
@@ -357,6 +496,10 @@
         if (mThumb != null) {
             mThumb.jumpToCurrentState();
         }
+
+        if (mTickMark != null) {
+            mTickMark.jumpToCurrentState();
+        }
     }
 
     @Override
@@ -373,6 +516,12 @@
                 && thumb.setState(getDrawableState())) {
             invalidateDrawable(thumb);
         }
+
+        final Drawable tickMark = mTickMark;
+        if (tickMark != null && tickMark.isStateful()
+                && tickMark.setState(getDrawableState())) {
+            invalidateDrawable(tickMark);
+        }
     }
 
     @Override
@@ -524,9 +673,36 @@
             final int saveCount = canvas.save();
             canvas.clipRect(tempRect, Op.DIFFERENCE);
             super.drawTrack(canvas);
+            drawTickMarks(canvas);
             canvas.restoreToCount(saveCount);
         } else {
             super.drawTrack(canvas);
+            drawTickMarks(canvas);
+        }
+    }
+
+    /**
+     * Draw the tick marks.
+     */
+    void drawTickMarks(Canvas canvas) {
+        if (mTickMark != null) {
+            final int count = getMax();
+            if (count > 1) {
+                final int w = mTickMark.getIntrinsicWidth();
+                final int h = mTickMark.getIntrinsicHeight();
+                final int halfW = w >= 0 ? w / 2 : 1;
+                final int halfH = h >= 0 ? h / 2 : 1;
+                mTickMark.setBounds(-halfW, -halfH, halfW, halfH);
+
+                final int spacing = (getWidth() - mPaddingLeft - mPaddingRight) / count;
+                final int saveCount = canvas.save();
+                canvas.translate(mPaddingLeft, getHeight() / 2);
+                for (int i = 0; i <= count; i++) {
+                    mTickMark.draw(canvas);
+                    canvas.translate(spacing, 0);
+                }
+                canvas.restoreToCount(saveCount);
+            }
         }
     }
 
@@ -535,12 +711,12 @@
      */
     void drawThumb(Canvas canvas) {
         if (mThumb != null) {
-            canvas.save();
+            final int saveCount = canvas.save();
             // Translate the padding. For the x, we need to allow the thumb to
             // draw in its extra space
             canvas.translate(mPaddingLeft - mThumbOffset, mPaddingTop);
             mThumb.draw(canvas);
-            canvas.restore();
+            canvas.restoreToCount(saveCount);
         }
     }
 
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index 0032f17..ac8d578 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -20,6 +20,8 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -57,7 +59,6 @@
  */
 public class ActionMenuPresenter extends BaseMenuPresenter
         implements ActionProvider.SubUiVisibilityListener {
-    private static final String TAG = "ActionMenuPresenter";
     private static final int ITEM_ANIMATION_DURATION = 150;
     private static final boolean ACTIONBAR_ANIMATIONS_ENABLED = false;
 
@@ -85,20 +86,16 @@
     private OpenOverflowRunnable mPostedOpenRunnable;
     private ActionMenuPopupCallback mPopupCallback;
 
-    private final boolean mShowCascadingMenus;
-
     final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback();
     int mOpenSubMenuId;
 
     // These collections are used to store pre- and post-layout information for menu items,
     // which is used to determine appropriate animations to run for changed items.
-    private SparseArray<MenuItemLayoutInfo> mPreLayoutItems =
-            new SparseArray<MenuItemLayoutInfo>();
-    private SparseArray<MenuItemLayoutInfo> mPostLayoutItems =
-            new SparseArray<MenuItemLayoutInfo>();
+    private SparseArray<MenuItemLayoutInfo> mPreLayoutItems = new SparseArray<>();
+    private SparseArray<MenuItemLayoutInfo> mPostLayoutItems = new SparseArray<>();
 
     // The list of currently running animations on menu items.
-    private List<ItemAnimationInfo> mRunningItemAnimations = new ArrayList<ItemAnimationInfo>();
+    private List<ItemAnimationInfo> mRunningItemAnimations = new ArrayList<>();
     private ViewTreeObserver.OnPreDrawListener mItemAnimationPreDrawListener =
             new ViewTreeObserver.OnPreDrawListener() {
         @Override
@@ -128,13 +125,10 @@
     public ActionMenuPresenter(Context context) {
         super(context, com.android.internal.R.layout.action_menu_layout,
                 com.android.internal.R.layout.action_menu_item_layout);
-
-        mShowCascadingMenus = context.getResources().getBoolean(
-                com.android.internal.R.bool.config_enableCascadingSubmenus);
     }
 
     @Override
-    public void initForMenu(Context context, MenuBuilder menu) {
+    public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) {
         super.initForMenu(context, menu);
 
         final Resources res = context.getResources();
@@ -629,8 +623,16 @@
     }
 
     public boolean flagActionItems() {
-        final ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems();
-        final int itemsSize = visibleItems.size();
+        final ArrayList<MenuItemImpl> visibleItems;
+        final int itemsSize;
+        if (mMenu != null) {
+            visibleItems = mMenu.getVisibleItems();
+            itemsSize = visibleItems.size();
+        } else {
+            visibleItems = null;
+            itemsSize = 0;
+        }
+
         int maxActions = mMaxItems;
         int widthLimit = mActionItemWidthLimit;
         final int querySpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
@@ -786,7 +788,7 @@
         if (isVisible) {
             // Not a submenu, but treat it like one.
             super.onSubMenuSelected(null);
-        } else {
+        } else if (mMenu != null) {
             mMenu.close(false /* closeAllMenus */);
         }
     }
@@ -835,8 +837,6 @@
     }
 
     private class OverflowMenuButton extends ImageButton implements ActionMenuView.ActionMenuChildView {
-        private final float[] mTempPts = new float[2];
-
         public OverflowMenuButton(Context context) {
             super(context, null, com.android.internal.R.attr.actionOverflowButtonStyle);
 
@@ -938,7 +938,9 @@
 
         @Override
         protected void onDismiss() {
-            mMenu.close();
+            if (mMenu != null) {
+                mMenu.close();
+            }
             mOverflowPopup = null;
 
             super.onDismiss();
@@ -999,7 +1001,9 @@
         }
 
         public void run() {
-            mMenu.changeMenuMode();
+            if (mMenu != null) {
+                mMenu.changeMenuMode();
+            }
             final View menuView = (View) mMenuView;
             if (menuView != null && menuView.getWindowToken() != null && mPopup.tryShow()) {
                 mOverflowPopup = mPopup;
diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java
index 1f02c3b..4d0a1c8 100644
--- a/core/java/android/widget/ActionMenuView.java
+++ b/core/java/android/widget/ActionMenuView.java
@@ -622,7 +622,7 @@
     }
 
     /** @hide */
-    public void initialize(MenuBuilder menu) {
+    public void initialize(@Nullable MenuBuilder menu) {
         mMenu = menu;
     }
 
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index 2aaa356..cde7604 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -16,8 +16,11 @@
 
 package android.widget;
 
+import android.annotation.AttrRes;
 import android.annotation.ColorInt;
 import android.annotation.DrawableRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.StyleRes;
 import android.annotation.Widget;
 import android.content.Context;
@@ -37,9 +40,13 @@
 import java.util.TimeZone;
 
 /**
- * This class is a calendar widget for displaying and selecting dates. The range
- * of dates supported by this calendar is configurable. A user can select a date
- * by taping on it and can scroll and fling the calendar to a desired date.
+ * This class is a calendar widget for displaying and selecting dates. The
+ * range of dates supported by this calendar is configurable.
+ * <p>
+ * The exact appearance and interaction model of this widget may vary between
+ * OS versions and themes (e.g. Holo versus Material), but in general a user
+ * can select a date by tapping on it and can scroll or fling the calendar to a
+ * desired date.
  *
  * @attr ref android.R.styleable#CalendarView_showWeekNumber
  * @attr ref android.R.styleable#CalendarView_firstDayOfWeek
@@ -77,22 +84,24 @@
          * @param month The month that was set [0-11].
          * @param dayOfMonth The day of the month that was set.
          */
-        public void onSelectedDayChange(CalendarView view, int year, int month, int dayOfMonth);
+        void onSelectedDayChange(@NonNull CalendarView view, int year, int month, int dayOfMonth);
     }
 
-    public CalendarView(Context context) {
+    public CalendarView(@NonNull Context context) {
         this(context, null);
     }
 
-    public CalendarView(Context context, AttributeSet attrs) {
+    public CalendarView(@NonNull Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, R.attr.calendarViewStyle);
     }
 
-    public CalendarView(Context context, AttributeSet attrs, int defStyleAttr) {
+    public CalendarView(@NonNull Context context, @Nullable AttributeSet attrs,
+            @AttrRes int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
-    public CalendarView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public CalendarView(@NonNull Context context, @Nullable AttributeSet attrs,
+            @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
 
         final TypedArray a = context.obtainStyledAttributes(
@@ -322,7 +331,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_weekDayTextAppearance
      */
-    public void setWeekDayTextAppearance(int resourceId) {
+    public void setWeekDayTextAppearance(@StyleRes int resourceId) {
         mDelegate.setWeekDayTextAppearance(resourceId);
     }
 
@@ -333,7 +342,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_weekDayTextAppearance
      */
-    public int getWeekDayTextAppearance() {
+    public @StyleRes int getWeekDayTextAppearance() {
         return mDelegate.getWeekDayTextAppearance();
     }
 
@@ -344,7 +353,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_dateTextAppearance
      */
-    public void setDateTextAppearance(int resourceId) {
+    public void setDateTextAppearance(@StyleRes int resourceId) {
         mDelegate.setDateTextAppearance(resourceId);
     }
 
@@ -355,7 +364,7 @@
      *
      * @attr ref android.R.styleable#CalendarView_dateTextAppearance
      */
-    public int getDateTextAppearance() {
+    public @StyleRes int getDateTextAppearance() {
         return mDelegate.getDateTextAppearance();
     }
 
@@ -552,36 +561,29 @@
         int getShownWeekCount();
 
         void setSelectedWeekBackgroundColor(@ColorInt int color);
-        @ColorInt
-        int getSelectedWeekBackgroundColor();
+        @ColorInt int getSelectedWeekBackgroundColor();
 
         void setFocusedMonthDateColor(@ColorInt int color);
-        @ColorInt
-        int getFocusedMonthDateColor();
+        @ColorInt int getFocusedMonthDateColor();
 
         void setUnfocusedMonthDateColor(@ColorInt int color);
-        @ColorInt
-        int getUnfocusedMonthDateColor();
+        @ColorInt int getUnfocusedMonthDateColor();
 
         void setWeekNumberColor(@ColorInt int color);
-        @ColorInt
-        int getWeekNumberColor();
+        @ColorInt int getWeekNumberColor();
 
         void setWeekSeparatorLineColor(@ColorInt int color);
-        @ColorInt
-        int getWeekSeparatorLineColor();
+        @ColorInt int getWeekSeparatorLineColor();
 
         void setSelectedDateVerticalBar(@DrawableRes int resourceId);
         void setSelectedDateVerticalBar(Drawable drawable);
         Drawable getSelectedDateVerticalBar();
 
         void setWeekDayTextAppearance(@StyleRes int resourceId);
-        @StyleRes
-        int getWeekDayTextAppearance();
+        @StyleRes int getWeekDayTextAppearance();
 
         void setDateTextAppearance(@StyleRes int resourceId);
-        @StyleRes
-        int getDateTextAppearance();
+        @StyleRes int getDateTextAppearance();
 
         void setMinDate(long minDate);
         long getMinDate();
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 5f5943f..87bee44 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -999,8 +999,8 @@
 
         private boolean isNewDate(int year, int month, int dayOfMonth) {
             return (mCurrentDate.get(Calendar.YEAR) != year
-                    || mCurrentDate.get(Calendar.MONTH) != dayOfMonth
-                    || mCurrentDate.get(Calendar.DAY_OF_MONTH) != month);
+                    || mCurrentDate.get(Calendar.MONTH) != month
+                    || mCurrentDate.get(Calendar.DAY_OF_MONTH) != dayOfMonth);
         }
 
         private void setDate(int year, int month, int dayOfMonth) {
diff --git a/core/java/android/widget/DropDownListView.java b/core/java/android/widget/DropDownListView.java
index 2fb2101..69e4218 100644
--- a/core/java/android/widget/DropDownListView.java
+++ b/core/java/android/widget/DropDownListView.java
@@ -19,18 +19,10 @@
 
 import com.android.internal.widget.AutoScrollHelper.AbsListViewAutoScroller;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
+import android.annotation.NonNull;
 import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.util.IntProperty;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.widget.TextView;
-import android.widget.ListView;
-
 
 /**
  * Wrapper class for a ListView. This wrapper can hijack the focus to
@@ -41,26 +33,6 @@
  * @hide
  */
 public class DropDownListView extends ListView {
-    /** Duration in milliseconds of the drag-to-open click animation. */
-    private static final long CLICK_ANIM_DURATION = 150;
-
-    /** Target alpha value for drag-to-open click animation. */
-    private static final int CLICK_ANIM_ALPHA = 0x80;
-
-    /** Wrapper around Drawable's <code>alpha</code> property. */
-    private static final IntProperty<Drawable> DRAWABLE_ALPHA =
-            new IntProperty<Drawable>("alpha") {
-                @Override
-                public void setValue(Drawable object, int value) {
-                    object.setAlpha(value);
-                }
-
-                @Override
-                public Integer get(Drawable object) {
-                    return object.getAlpha();
-                }
-            };
-
     /*
      * WARNING: This is a workaround for a touch mode issue.
      *
@@ -99,18 +71,21 @@
     /** Whether to force drawing of the pressed state selector. */
     private boolean mDrawsInPressedState;
 
-    /** Current drag-to-open click animation, if any. */
-    private Animator mClickAnimation;
-
     /** Helper for drag-to-open auto scrolling. */
     private AbsListViewAutoScroller mScrollHelper;
 
     /**
+     * Runnable posted when we are awaiting hover event resolution. When set,
+     * drawable state changes are postponed.
+     */
+    private ResolveHoverRunnable mResolveHoverRunnable;
+
+    /**
      * Creates a new list view wrapper.
      *
      * @param context this view's context
      */
-    public DropDownListView(Context context, boolean hijackFocus) {
+    public DropDownListView(@NonNull Context context, boolean hijackFocus) {
         this(context, hijackFocus, com.android.internal.R.attr.dropDownListViewStyle);
     }
 
@@ -119,7 +94,7 @@
      *
      * @param context this view's context
      */
-    public DropDownListView(Context context, boolean hijackFocus, int defStyleAttr) {
+    public DropDownListView(@NonNull Context context, boolean hijackFocus, int defStyleAttr) {
         super(context, null, defStyleAttr);
         mHijackFocus = hijackFocus;
         // TODO: Add an API to control this
@@ -132,18 +107,36 @@
     }
 
     @Override
-    public boolean onHoverEvent(MotionEvent ev) {
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (mResolveHoverRunnable != null) {
+            // Resolved hover event as hover => touch transition.
+            mResolveHoverRunnable.cancel();
+        }
+
+        return super.onTouchEvent(ev);
+    }
+
+    @Override
+    public boolean onHoverEvent(@NonNull MotionEvent ev) {
+        final int action = ev.getActionMasked();
+        if (action == MotionEvent.ACTION_HOVER_EXIT && mResolveHoverRunnable == null) {
+            // This may be transitioning to TOUCH_DOWN. Postpone drawable state
+            // updates until either the next frame or the next touch event.
+            mResolveHoverRunnable = new ResolveHoverRunnable();
+            mResolveHoverRunnable.post();
+        }
+
         // Allow the super class to handle hover state management first.
         final boolean handled = super.onHoverEvent(ev);
 
-        final int action = ev.getActionMasked();
         if (action == MotionEvent.ACTION_HOVER_ENTER
                 || action == MotionEvent.ACTION_HOVER_MOVE) {
             final int position = pointToPosition((int) ev.getX(), (int) ev.getY());
             if (position != INVALID_POSITION && position != mSelectedPosition) {
                 final View hoveredItem = getChildAt(position - getFirstVisiblePosition());
                 if (hoveredItem.isEnabled()) {
-                    // Force a focus so that the proper selector state gets used when we update.
+                    // Force a focus so that the proper selector state gets
+                    // used when we update.
                     requestFocus();
 
                     positionSelector(position, hoveredItem);
@@ -153,7 +146,8 @@
                 updateSelectorState();
             }
         } else {
-            // Do not cancel the selected position if the selection is visible by other reasons.
+            // Do not cancel the selected position if the selection is visible
+            // by other means.
             if (!super.shouldShowSelector()) {
                 setSelectedPositionInt(INVALID_POSITION);
                 setNextSelectedPositionInt(INVALID_POSITION);
@@ -163,13 +157,20 @@
         return handled;
     }
 
+    @Override
+    protected void drawableStateChanged() {
+        if (mResolveHoverRunnable == null) {
+            super.drawableStateChanged();
+        }
+    }
+
     /**
      * Handles forwarded events.
      *
      * @param activePointerId id of the pointer that activated forwarding
      * @return whether the event was handled
      */
-    public boolean onForwardedEvent(MotionEvent event, int activePointerId) {
+    public boolean onForwardedEvent(@NonNull MotionEvent event, int activePointerId) {
         boolean handledEvent = true;
         boolean clearPressedItem = false;
 
@@ -201,7 +202,8 @@
                 handledEvent = true;
 
                 if (actionMasked == MotionEvent.ACTION_UP) {
-                    clickPressedItem(child, position);
+                    final long id = getItemIdAtPosition(position);
+                    performItemClick(child, position, id);
                 }
                 break;
         }
@@ -226,36 +228,14 @@
     }
 
     /**
-     * Sets whether the list selection is hidden, as part of a workaround for a touch mode issue
-     * (see the declaration for mListSelectionHidden).
-     * @param listSelectionHidden
+     * Sets whether the list selection is hidden, as part of a workaround for a
+     * touch mode issue (see the declaration for mListSelectionHidden).
+     *
+     * @param hideListSelection {@code true} to hide list selection,
+     *                          {@code false} to show
      */
-    public void setListSelectionHidden(boolean listSelectionHidden) {
-        this.mListSelectionHidden = listSelectionHidden;
-    }
-
-    /**
-     * Starts an alpha animation on the selector. When the animation ends,
-     * the list performs a click on the item.
-     */
-    private void clickPressedItem(final View child, final int position) {
-        final long id = getItemIdAtPosition(position);
-        final Animator anim = ObjectAnimator.ofInt(
-                mSelector, DRAWABLE_ALPHA, 0xFF, CLICK_ANIM_ALPHA, 0xFF);
-        anim.setDuration(CLICK_ANIM_DURATION);
-        anim.setInterpolator(new AccelerateDecelerateInterpolator());
-        anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-            public void onAnimationEnd(Animator animation) {
-                performItemClick(child, position, id);
-            }
-        });
-        anim.start();
-
-        if (mClickAnimation != null) {
-            mClickAnimation.cancel();
-        }
-        mClickAnimation = anim;
+    public void setListSelectionHidden(boolean hideListSelection) {
+        mListSelectionHidden = hideListSelection;
     }
 
     private void clearPressedItem() {
@@ -267,14 +247,9 @@
         if (motionView != null) {
             motionView.setPressed(false);
         }
-
-        if (mClickAnimation != null) {
-            mClickAnimation.cancel();
-            mClickAnimation = null;
-        }
     }
 
-    private void setPressedItem(View child, int position, float x, float y) {
+    private void setPressedItem(@NonNull View child, int position, float x, float y) {
         mDrawsInPressedState = true;
 
         // Ordering is essential. First, update the container's pressed state.
@@ -311,11 +286,6 @@
         // Refresh the drawable state to reflect the new pressed state,
         // which will also update the selector state.
         refreshDrawableState();
-
-        if (mClickAnimation != null) {
-            mClickAnimation.cancel();
-            mClickAnimation = null;
-        }
     }
 
     @Override
@@ -376,4 +346,25 @@
     public boolean hasFocus() {
         return mHijackFocus || super.hasFocus();
     }
+
+    /**
+     * Runnable that forces hover event resolution and updates drawable state.
+     */
+    private class ResolveHoverRunnable implements Runnable {
+        @Override
+        public void run() {
+            // Resolved hover event as standard hover exit.
+            mResolveHoverRunnable = null;
+            drawableStateChanged();
+        }
+
+        public void cancel() {
+            mResolveHoverRunnable = null;
+            removeCallbacks(this);
+        }
+
+        public void post() {
+            DropDownListView.this.post(this);
+        }
+    }
 }
\ No newline at end of file
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 2d1f855..617d3dd 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -38,6 +38,7 @@
 import android.graphics.Path;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -68,12 +69,15 @@
 import android.text.style.TextAppearanceSpan;
 import android.text.style.URLSpan;
 import android.util.DisplayMetrics;
+import android.util.LocaleList;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.ActionMode;
 import android.view.ActionMode.Callback;
+import android.view.ContextMenu;
 import android.view.DisplayListCanvas;
 import android.view.DragEvent;
+import android.view.DropPermissions;
 import android.view.Gravity;
 import android.view.InputDevice;
 import android.view.LayoutInflater;
@@ -81,6 +85,7 @@
 import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.RenderNode;
+import android.view.SubMenu;
 import android.view.View;
 import android.view.View.DragShadowBuilder;
 import android.view.View.OnClickListener;
@@ -135,13 +140,16 @@
     // Tag used when the Editor maintains its own separate UndoManager.
     private static final String UNDO_OWNER_TAG = "Editor";
 
-    // Ordering constants used to place the Action Mode items in their menu.
-    private static final int MENU_ITEM_ORDER_CUT = 1;
-    private static final int MENU_ITEM_ORDER_COPY = 2;
-    private static final int MENU_ITEM_ORDER_PASTE = 3;
-    private static final int MENU_ITEM_ORDER_SHARE = 4;
-    private static final int MENU_ITEM_ORDER_SELECT_ALL = 5;
-    private static final int MENU_ITEM_ORDER_REPLACE = 6;
+    // Ordering constants used to place the Action Mode or context menu items in their menu.
+    private static final int MENU_ITEM_ORDER_UNDO = 1;
+    private static final int MENU_ITEM_ORDER_REDO = 2;
+    private static final int MENU_ITEM_ORDER_CUT = 3;
+    private static final int MENU_ITEM_ORDER_COPY = 4;
+    private static final int MENU_ITEM_ORDER_PASTE = 5;
+    private static final int MENU_ITEM_ORDER_PASTE_AS_PLAIN_TEXT = 6;
+    private static final int MENU_ITEM_ORDER_SHARE = 7;
+    private static final int MENU_ITEM_ORDER_SELECT_ALL = 8;
+    private static final int MENU_ITEM_ORDER_REPLACE = 9;
     private static final int MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START = 10;
 
     // Each Editor manages its own undo stack.
@@ -184,6 +192,7 @@
 
     boolean mDiscardNextActionUp;
     boolean mIgnoreActionUpEvent;
+    private boolean mIgnoreNextMouseActionUpOrDown;
 
     long mShowCursor;
     Blink mBlink;
@@ -209,6 +218,8 @@
     boolean mPreserveDetachedSelection;
     boolean mTemporaryDetach;
 
+    boolean mIsBeingLongClicked;
+
     SuggestionsPopupWindow mSuggestionsPopupWindow;
     SuggestionRangeSpan mSuggestionRangeSpan;
     Runnable mShowSuggestionRunnable;
@@ -224,6 +235,7 @@
     private PositionListener mPositionListener;
 
     float mLastDownPositionX, mLastDownPositionY;
+    private float mContextMenuAnchorX, mContextMenuAnchorY;
     Callback mCustomSelectionActionModeCallback;
     Callback mCustomInsertionActionModeCallback;
 
@@ -239,6 +251,9 @@
     // Only for mouse input.
     private static final int TAP_STATE_TRIPLE_CLICK = 3;
 
+    // The button state as of the last time #onTouchEvent is called.
+    private int mLastButtonState;
+
     private Runnable mInsertionActionModeRunnable;
 
     // The span controller helps monitoring the changes to which the Editor needs to react:
@@ -274,6 +289,9 @@
 
     boolean mIsInsertionActionModeStartPending = false;
 
+    private final SuggestionHelper mSuggestionHelper = new SuggestionHelper();
+    private SuggestionInfo[] mSuggestionInfosInContextMenu;
+
     Editor(TextView textView) {
         mTextView = textView;
         // Synchronize the filter list, which places the undo input filter at the end.
@@ -1065,6 +1083,20 @@
         return true;
     }
 
+    private void startDragAndDrop() {
+        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,
+                View.DRAG_FLAG_GLOBAL);
+        stopTextActionMode();
+        if (hasSelectionController()) {
+            getSelectionController().resetTouchOffsets();
+        }
+    }
+
     public boolean performLongClick(boolean handled) {
         // Long press in empty space moves cursor and starts the insertion action mode.
         if (!handled && !isPositionOnText(mLastDownPositionX, mLastDownPositionY) &&
@@ -1080,15 +1112,7 @@
 
         if (!handled && mTextActionMode != null) {
             if (touchPositionIsInSelection()) {
-                // Start a drag
-                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.startDrag(data, getTextThumbnailBuilder(selectedText), localState,
-                        View.DRAG_FLAG_GLOBAL);
-                stopTextActionMode();
+                startDragAndDrop();
             } else {
                 stopTextActionMode();
                 selectCurrentWordAndStartDrag();
@@ -1314,7 +1338,33 @@
         }
     }
 
+    private boolean shouldFilterOutTouchEvent(MotionEvent event) {
+        if (!event.isFromSource(InputDevice.SOURCE_MOUSE)) {
+            return false;
+        }
+        final boolean primaryButtonStateChanged =
+                ((mLastButtonState ^ event.getButtonState()) & MotionEvent.BUTTON_PRIMARY) != 0;
+        final int action = event.getActionMasked();
+        if ((action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_UP)
+                && !primaryButtonStateChanged) {
+            return true;
+        }
+        if (action == MotionEvent.ACTION_MOVE
+                && !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) {
+            return true;
+        }
+        return false;
+    }
+
     void onTouchEvent(MotionEvent event) {
+        final boolean filterOutEvent = shouldFilterOutTouchEvent(event);
+        mLastButtonState = event.getButtonState();
+        if (filterOutEvent) {
+            if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+                mDiscardNextActionUp = true;
+            }
+            return;
+        }
         updateTapState(event);
         updateFloatingToolbarVisibility(event);
 
@@ -2249,11 +2299,24 @@
 
     void onDrop(DragEvent event) {
         StringBuilder content = new StringBuilder("");
-        ClipData clipData = event.getClipData();
-        final int itemCount = clipData.getItemCount();
-        for (int i=0; i < itemCount; i++) {
-            Item item = clipData.getItemAt(i);
-            content.append(item.coerceToStyledText(mTextView.getContext()));
+
+        final DropPermissions dropPermissions = DropPermissions.obtain(event);
+        if (dropPermissions != null) {
+            dropPermissions.takeTransient();
+        }
+
+        try {
+            ClipData clipData = event.getClipData();
+            final int itemCount = clipData.getItemCount();
+            for (int i=0; i < itemCount; i++) {
+                Item item = clipData.getItemAt(i);
+                content.append(item.coerceToStyledText(mTextView.getContext()));
+            }
+        }
+        finally {
+            if (dropPermissions != null) {
+                dropPermissions.release();
+            }
         }
 
         final int offset = mTextView.getOffsetForPosition(event.getX(), event.getY());
@@ -2318,6 +2381,184 @@
         text.setSpan(mSpanController, 0, textLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
     }
 
+    void setContextMenuAnchor(float x, float y) {
+        mContextMenuAnchorX = x;
+        mContextMenuAnchorY = y;
+    }
+
+    void onCreateContextMenu(ContextMenu menu) {
+        if (mIsBeingLongClicked || Float.isNaN(mContextMenuAnchorX)
+                || Float.isNaN(mContextMenuAnchorY)) {
+            return;
+        }
+        final int offset = mTextView.getOffsetForPosition(mContextMenuAnchorX, mContextMenuAnchorY);
+        if (offset == -1) {
+            return;
+        }
+        mPreserveDetachedSelection = true;
+        stopTextActionMode();
+        mPreserveDetachedSelection = false;
+        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);
+        }
+
+        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 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);
+            }
+        }
+
+        menu.add(Menu.NONE, TextView.ID_UNDO, MENU_ITEM_ORDER_UNDO,
+                com.android.internal.R.string.undo)
+                .setAlphabeticShortcut('z')
+                .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
+                .setEnabled(mTextView.canUndo());
+        menu.add(Menu.NONE, TextView.ID_REDO, MENU_ITEM_ORDER_REDO,
+                com.android.internal.R.string.redo)
+                .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
+                .setEnabled(mTextView.canRedo());
+
+        menu.add(Menu.NONE, TextView.ID_CUT, MENU_ITEM_ORDER_CUT,
+                com.android.internal.R.string.cut)
+                .setAlphabeticShortcut('x')
+                .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
+                .setEnabled(mTextView.canCut());
+        menu.add(Menu.NONE, TextView.ID_COPY, MENU_ITEM_ORDER_COPY,
+                com.android.internal.R.string.copy)
+                .setAlphabeticShortcut('c')
+                .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
+                .setEnabled(mTextView.canCopy());
+        menu.add(Menu.NONE, TextView.ID_PASTE, MENU_ITEM_ORDER_PASTE,
+                com.android.internal.R.string.paste)
+                .setAlphabeticShortcut('v')
+                .setEnabled(mTextView.canPaste())
+                .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
+        menu.add(Menu.NONE, TextView.ID_PASTE, MENU_ITEM_ORDER_PASTE_AS_PLAIN_TEXT,
+                com.android.internal.R.string.paste_as_plain_text)
+                .setEnabled(mTextView.canPaste())
+                .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
+        menu.add(Menu.NONE, TextView.ID_SHARE, MENU_ITEM_ORDER_SHARE,
+                com.android.internal.R.string.share)
+                .setEnabled(mTextView.canShare())
+                .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
+        menu.add(Menu.NONE, TextView.ID_SELECT_ALL, MENU_ITEM_ORDER_SELECT_ALL,
+                com.android.internal.R.string.selectAll)
+                .setAlphabeticShortcut('a')
+                .setEnabled(mTextView.canSelectAllText())
+                .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
+
+        mPreserveDetachedSelection = true;
+    }
+
+    private void replaceWithSuggestion(SuggestionInfo suggestionInfo, int spanStart, int spanEnd) {
+        final Editable editable = (Editable) mTextView.getText();
+        final String originalText = TextUtils.substring(editable, spanStart, spanEnd);
+        // SuggestionSpans are removed by replace: save them before
+        SuggestionSpan[] suggestionSpans = editable.getSpans(spanStart, spanEnd,
+                SuggestionSpan.class);
+        final int length = suggestionSpans.length;
+        int[] suggestionSpansStarts = new int[length];
+        int[] suggestionSpansEnds = new int[length];
+        int[] suggestionSpansFlags = new int[length];
+        for (int i = 0; i < length; i++) {
+            final SuggestionSpan suggestionSpan = suggestionSpans[i];
+            suggestionSpansStarts[i] = editable.getSpanStart(suggestionSpan);
+            suggestionSpansEnds[i] = editable.getSpanEnd(suggestionSpan);
+            suggestionSpansFlags[i] = editable.getSpanFlags(suggestionSpan);
+
+            // Remove potential misspelled flags
+            int suggestionSpanFlags = suggestionSpan.getFlags();
+            if ((suggestionSpanFlags & SuggestionSpan.FLAG_MISSPELLED) != 0) {
+                suggestionSpanFlags &= ~SuggestionSpan.FLAG_MISSPELLED;
+                suggestionSpanFlags &= ~SuggestionSpan.FLAG_EASY_CORRECT;
+                suggestionSpan.setFlags(suggestionSpanFlags);
+            }
+        }
+
+        // Notify source IME of the suggestion pick. Do this before swapping texts.
+        suggestionInfo.mSuggestionSpan.notifySelection(
+                mTextView.getContext(), originalText, suggestionInfo.mSuggestionIndex);
+
+        // Swap text content between actual text and Suggestion span
+        final int suggestionStart = suggestionInfo.mSuggestionStart;
+        final int suggestionEnd = suggestionInfo.mSuggestionEnd;
+        final String suggestion = suggestionInfo.mText.subSequence(
+                suggestionStart, suggestionEnd).toString();
+        mTextView.replaceText_internal(spanStart, spanEnd, suggestion);
+
+        String[] suggestions = suggestionInfo.mSuggestionSpan.getSuggestions();
+        suggestions[suggestionInfo.mSuggestionIndex] = originalText;
+
+        // Restore previous SuggestionSpans
+        final int lengthDelta = suggestion.length() - (spanEnd - spanStart);
+        for (int i = 0; i < length; i++) {
+            // Only spans that include the modified region make sense after replacement
+            // Spans partially included in the replaced region are removed, there is no
+            // way to assign them a valid range after replacement
+            if (suggestionSpansStarts[i] <= spanStart && suggestionSpansEnds[i] >= spanEnd) {
+                mTextView.setSpan_internal(suggestionSpans[i], suggestionSpansStarts[i],
+                        suggestionSpansEnds[i] + lengthDelta, suggestionSpansFlags[i]);
+            }
+        }
+        // Move cursor at the end of the replaced word
+        final int newCursorPosition = spanEnd + lengthDelta;
+        mTextView.setCursorPosition_internal(newCursorPosition, newCursorPosition);
+    }
+
+    private final MenuItem.OnMenuItemClickListener mOnContextMenuItemClickListener =
+            new MenuItem.OnMenuItemClickListener() {
+        @Override
+        public boolean onMenuItemClick(MenuItem item) {
+            if (mProcessTextIntentActionsHandler.performMenuItemAction(item)) {
+                return true;
+            }
+            return mTextView.onTextContextMenuItem(item.getItemId());
+        }
+    };
+
+    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.
@@ -2710,6 +2951,9 @@
         }
 
         public void hide() {
+            if (!isShowing()) {
+                return;
+            }
             mPopupWindow.dismiss();
             getPositionListener().removeSubscriber(this);
         }
@@ -2731,6 +2975,131 @@
         }
     }
 
+    private static class SuggestionInfo {
+        // Range of actual suggestion within text
+        int mSuggestionStart, mSuggestionEnd;
+
+        // The SuggestionSpan that this TextView represents
+        @Nullable
+        SuggestionSpan mSuggestionSpan;
+
+        // The index of this suggestion inside suggestionSpan
+        int mSuggestionIndex;
+
+        final SpannableStringBuilder mText = new SpannableStringBuilder();
+
+        void clear() {
+            mSuggestionSpan = null;
+            mText.clear();
+        }
+    }
+
+    private class SuggestionHelper {
+        private final Comparator<SuggestionSpan> mSuggestionSpanComparator =
+                new SuggestionSpanComparator();
+        private final HashMap<SuggestionSpan, Integer> mSpansLengths =
+                new HashMap<SuggestionSpan, Integer>();
+
+        private class SuggestionSpanComparator implements Comparator<SuggestionSpan> {
+            public int compare(SuggestionSpan span1, SuggestionSpan span2) {
+                final int flag1 = span1.getFlags();
+                final int flag2 = span2.getFlags();
+                if (flag1 != flag2) {
+                    // The order here should match what is used in updateDrawState
+                    final boolean easy1 = (flag1 & SuggestionSpan.FLAG_EASY_CORRECT) != 0;
+                    final boolean easy2 = (flag2 & SuggestionSpan.FLAG_EASY_CORRECT) != 0;
+                    final boolean misspelled1 = (flag1 & SuggestionSpan.FLAG_MISSPELLED) != 0;
+                    final boolean misspelled2 = (flag2 & SuggestionSpan.FLAG_MISSPELLED) != 0;
+                    if (easy1 && !misspelled1) return -1;
+                    if (easy2 && !misspelled2) return 1;
+                    if (misspelled1) return -1;
+                    if (misspelled2) return 1;
+                }
+
+                return mSpansLengths.get(span1).intValue() - mSpansLengths.get(span2).intValue();
+            }
+        }
+
+        /**
+         * Returns the suggestion spans that cover the current cursor position. The suggestion
+         * spans are sorted according to the length of text that they are attached to.
+         */
+        private SuggestionSpan[] getSortedSuggestionSpans() {
+            int pos = mTextView.getSelectionStart();
+            Spannable spannable = (Spannable) mTextView.getText();
+            SuggestionSpan[] suggestionSpans = spannable.getSpans(pos, pos, SuggestionSpan.class);
+
+            mSpansLengths.clear();
+            for (SuggestionSpan suggestionSpan : suggestionSpans) {
+                int start = spannable.getSpanStart(suggestionSpan);
+                int end = spannable.getSpanEnd(suggestionSpan);
+                mSpansLengths.put(suggestionSpan, Integer.valueOf(end - start));
+            }
+
+            // The suggestions are sorted according to their types (easy correction first, then
+            // misspelled) and to the length of the text that they cover (shorter first).
+            Arrays.sort(suggestionSpans, mSuggestionSpanComparator);
+            mSpansLengths.clear();
+
+            return suggestionSpans;
+        }
+
+        /**
+         * Gets the SuggestionInfo list that contains suggestion information at the current cursor
+         * position.
+         *
+         * @param suggestionInfos SuggestionInfo array the results will be set.
+         * @return the number of suggestions actually fetched.
+         */
+        public int getSuggestionInfo(SuggestionInfo[] suggestionInfos) {
+            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];
+                final int spanStart = spannable.getSpanStart(suggestionSpan);
+                final int spanEnd = spannable.getSpanEnd(suggestionSpan);
+
+                final String[] suggestions = suggestionSpan.getSuggestions();
+                final int nbSuggestions = suggestions.length;
+                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);
+                            if (spanStart == otherSpanStart && spanEnd == otherSpanEnd) {
+                                suggestionIsDuplicate = true;
+                                break;
+                            }
+                        }
+                    }
+
+                    if (suggestionIsDuplicate) {
+                        continue;
+                    }
+                    SuggestionInfo suggestionInfo = suggestionInfos[numberOfSuggestions];
+                    suggestionInfo.mSuggestionSpan = suggestionSpan;
+                    suggestionInfo.mSuggestionIndex = suggestionIndex;
+                    suggestionInfo.mSuggestionStart = 0;
+                    suggestionInfo.mSuggestionEnd = suggestion.length();
+                    suggestionInfo.mText.replace(0, suggestionInfo.mText.length(), suggestion);
+                    numberOfSuggestions++;
+                    if (numberOfSuggestions >= suggestionInfos.length) {
+                        return numberOfSuggestions;
+                    }
+                }
+            }
+            return numberOfSuggestions;
+        }
+    }
+
     @VisibleForTesting
     public class SuggestionsPopupWindow extends PinnedPopupWindow implements OnItemClickListener {
         private static final int MAX_NUMBER_SUGGESTIONS = SuggestionSpan.SUGGESTIONS_MAX_SIZE;
@@ -2744,8 +3113,6 @@
         private boolean mCursorWasVisibleBeforeSuggestions;
         private boolean mIsShowingUp = false;
         private SuggestionAdapter mSuggestionsAdapter;
-        private final Comparator<SuggestionSpan> mSuggestionSpanComparator;
-        private final HashMap<SuggestionSpan, Integer> mSpansLengths;
         private final TextAppearanceSpan mHighlightSpan = new TextAppearanceSpan(
                 mTextView.getContext(), mTextView.mTextEditSuggestionHighlightStyle);
         private TextView mAddToDictionaryButton;
@@ -2753,14 +3120,12 @@
         private SuggestionSpan mMisspelledSpan;
 
         private class CustomPopupWindow extends PopupWindow {
-            public CustomPopupWindow(Context context, int defStyleAttr) {
-                super(context, null, defStyleAttr);
-            }
-
             @Override
             public void dismiss() {
+                if (!isShowing()) {
+                    return;
+                }
                 super.dismiss();
-
                 getPositionListener().removeSubscriber(SuggestionsPopupWindow.this);
 
                 // Safe cast since show() checks that mTextView.getText() is an Editable
@@ -2775,15 +3140,13 @@
 
         public SuggestionsPopupWindow() {
             mCursorWasVisibleBeforeSuggestions = mCursorVisible;
-            mSuggestionSpanComparator = new SuggestionSpanComparator();
-            mSpansLengths = new HashMap<SuggestionSpan, Integer>();
         }
 
         @Override
         protected void createPopupWindow() {
-            mPopupWindow = new CustomPopupWindow(mTextView.getContext(),
-                com.android.internal.R.attr.textSuggestionsWindowStyle);
+            mPopupWindow = new CustomPopupWindow();
             mPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
+            mPopupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
             mPopupWindow.setFocusable(true);
             mPopupWindow.setClippingEnabled(false);
         }
@@ -2867,24 +3230,6 @@
             mIsShowingUp = false;
         }
 
-        private final class SuggestionInfo {
-            int suggestionStart, suggestionEnd; // range of actual suggestion within text
-
-            // the SuggestionSpan that this TextView represents
-            @Nullable
-            SuggestionSpan suggestionSpan;
-
-            int suggestionIndex; // the index of this suggestion inside suggestionSpan
-
-            @Nullable
-            final SpannableStringBuilder text = new SpannableStringBuilder();
-
-            void clear() {
-                suggestionSpan = null;
-                text.clear();
-            }
-        }
-
         private class SuggestionAdapter extends BaseAdapter {
             private LayoutInflater mInflater = (LayoutInflater) mTextView.getContext().
                     getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -2914,55 +3259,11 @@
                 }
 
                 final SuggestionInfo suggestionInfo = mSuggestionInfos[position];
-                textView.setText(suggestionInfo.text);
+                textView.setText(suggestionInfo.mText);
                 return textView;
             }
         }
 
-        private class SuggestionSpanComparator implements Comparator<SuggestionSpan> {
-            public int compare(SuggestionSpan span1, SuggestionSpan span2) {
-                final int flag1 = span1.getFlags();
-                final int flag2 = span2.getFlags();
-                if (flag1 != flag2) {
-                    // The order here should match what is used in updateDrawState
-                    final boolean easy1 = (flag1 & SuggestionSpan.FLAG_EASY_CORRECT) != 0;
-                    final boolean easy2 = (flag2 & SuggestionSpan.FLAG_EASY_CORRECT) != 0;
-                    final boolean misspelled1 = (flag1 & SuggestionSpan.FLAG_MISSPELLED) != 0;
-                    final boolean misspelled2 = (flag2 & SuggestionSpan.FLAG_MISSPELLED) != 0;
-                    if (easy1 && !misspelled1) return -1;
-                    if (easy2 && !misspelled2) return 1;
-                    if (misspelled1) return -1;
-                    if (misspelled2) return 1;
-                }
-
-                return mSpansLengths.get(span1).intValue() - mSpansLengths.get(span2).intValue();
-            }
-        }
-
-        /**
-         * Returns the suggestion spans that cover the current cursor position. The suggestion
-         * spans are sorted according to the length of text that they are attached to.
-         */
-        private SuggestionSpan[] getSuggestionSpans() {
-            int pos = mTextView.getSelectionStart();
-            Spannable spannable = (Spannable) mTextView.getText();
-            SuggestionSpan[] suggestionSpans = spannable.getSpans(pos, pos, SuggestionSpan.class);
-
-            mSpansLengths.clear();
-            for (SuggestionSpan suggestionSpan : suggestionSpans) {
-                int start = spannable.getSpanStart(suggestionSpan);
-                int end = spannable.getSpanEnd(suggestionSpan);
-                mSpansLengths.put(suggestionSpan, Integer.valueOf(end - start));
-            }
-
-            // The suggestions are sorted according to their types (easy correction first, then
-            // misspelled) and to the length of the text that they cover (shorter first).
-            Arrays.sort(suggestionSpans, mSuggestionSpanComparator);
-            mSpansLengths.clear();
-
-            return suggestionSpans;
-        }
-
         @VisibleForTesting
         public ViewGroup getContentViewForTesting() {
             return mContentView;
@@ -3046,66 +3347,26 @@
 
         private boolean updateSuggestions() {
             Spannable spannable = (Spannable) mTextView.getText();
-            SuggestionSpan[] suggestionSpans = getSuggestionSpans();
+            mNumberOfSuggestions =
+                    mSuggestionHelper.getSuggestionInfo(mSuggestionInfos);
+            if (mNumberOfSuggestions == 0) {
+                return false;
+            }
 
-            final int nbSpans = suggestionSpans.length;
-            // Suggestions are shown after a delay: the underlying spans may have been removed
-            if (nbSpans == 0) return false;
-
-            mNumberOfSuggestions = 0;
             int spanUnionStart = mTextView.getText().length();
             int spanUnionEnd = 0;
 
             mMisspelledSpan = null;
-            int underlineColor = 0;
-
-            for (int spanIndex = 0; spanIndex < nbSpans; spanIndex++) {
-                SuggestionSpan suggestionSpan = suggestionSpans[spanIndex];
-                final int spanStart = spannable.getSpanStart(suggestionSpan);
-                final int spanEnd = spannable.getSpanEnd(suggestionSpan);
-                spanUnionStart = Math.min(spanStart, spanUnionStart);
-                spanUnionEnd = Math.max(spanEnd, spanUnionEnd);
-
+            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;
                 }
-
-                // The first span dictates the background color of the highlighted text
-                if (spanIndex == 0) underlineColor = suggestionSpan.getUnderlineColor();
-
-                String[] suggestions = suggestionSpan.getSuggestions();
-                int nbSuggestions = suggestions.length;
-                for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) {
-                    String suggestion = suggestions[suggestionIndex];
-
-                    boolean suggestionIsDuplicate = false;
-                    for (int i = 0; i < mNumberOfSuggestions; i++) {
-                        if (mSuggestionInfos[i].text.toString().equals(suggestion)) {
-                            SuggestionSpan otherSuggestionSpan = mSuggestionInfos[i].suggestionSpan;
-                            final int otherSpanStart = spannable.getSpanStart(otherSuggestionSpan);
-                            final int otherSpanEnd = spannable.getSpanEnd(otherSuggestionSpan);
-                            if (spanStart == otherSpanStart && spanEnd == otherSpanEnd) {
-                                suggestionIsDuplicate = true;
-                                break;
-                            }
-                        }
-                    }
-
-                    if (!suggestionIsDuplicate) {
-                        SuggestionInfo suggestionInfo = mSuggestionInfos[mNumberOfSuggestions];
-                        suggestionInfo.suggestionSpan = suggestionSpan;
-                        suggestionInfo.suggestionIndex = suggestionIndex;
-                        suggestionInfo.text.replace(0, suggestionInfo.text.length(), suggestion);
-
-                        mNumberOfSuggestions++;
-
-                        if (mNumberOfSuggestions == MAX_NUMBER_SUGGESTIONS) {
-                            // Also end outer for loop
-                            spanIndex = nbSpans;
-                            break;
-                        }
-                    }
-                }
+                final int spanStart = spannable.getSpanStart(suggestionSpan);
+                final int spanEnd = spannable.getSpanEnd(suggestionSpan);
+                spanUnionStart = Math.min(spanUnionStart, spanStart);
+                spanUnionEnd = Math.max(spanUnionEnd, spanEnd);
             }
 
             for (int i = 0; i < mNumberOfSuggestions; i++) {
@@ -3124,6 +3385,7 @@
             mAddToDictionaryButton.setVisibility(addToDictionaryButtonVisibility);
 
             if (mSuggestionRangeSpan == null) mSuggestionRangeSpan = new SuggestionRangeSpan();
+            final int underlineColor = mSuggestionInfos[0].mSuggestionSpan.getUnderlineColor();
             if (underlineColor == 0) {
                 // Fallback on the default highlight color when the first span does not provide one
                 mSuggestionRangeSpan.setBackgroundColor(mTextView.mHighlightColor);
@@ -3143,21 +3405,21 @@
         private void highlightTextDifferences(SuggestionInfo suggestionInfo, int unionStart,
                 int unionEnd) {
             final Spannable text = (Spannable) mTextView.getText();
-            final int spanStart = text.getSpanStart(suggestionInfo.suggestionSpan);
-            final int spanEnd = text.getSpanEnd(suggestionInfo.suggestionSpan);
+            final int spanStart = text.getSpanStart(suggestionInfo.mSuggestionSpan);
+            final int spanEnd = text.getSpanEnd(suggestionInfo.mSuggestionSpan);
 
             // Adjust the start/end of the suggestion span
-            suggestionInfo.suggestionStart = spanStart - unionStart;
-            suggestionInfo.suggestionEnd = suggestionInfo.suggestionStart
-                    + suggestionInfo.text.length();
+            suggestionInfo.mSuggestionStart = spanStart - unionStart;
+            suggestionInfo.mSuggestionEnd = suggestionInfo.mSuggestionStart
+                    + suggestionInfo.mText.length();
 
-            suggestionInfo.text.setSpan(mHighlightSpan, 0, suggestionInfo.text.length(),
+            suggestionInfo.mText.setSpan(mHighlightSpan, 0, suggestionInfo.mText.length(),
                     Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
 
             // Add the text before and after the span.
             final String textAsString = text.toString();
-            suggestionInfo.text.insert(0, textAsString.substring(unionStart, spanStart));
-            suggestionInfo.text.append(textAsString.substring(spanEnd, unionEnd));
+            suggestionInfo.mText.insert(0, textAsString.substring(unionStart, spanStart));
+            suggestionInfo.mText.append(textAsString.substring(spanEnd, unionEnd));
         }
 
         @Override
@@ -3165,69 +3427,14 @@
             Editable editable = (Editable) mTextView.getText();
             SuggestionInfo suggestionInfo = mSuggestionInfos[position];
 
-            final int spanStart = editable.getSpanStart(suggestionInfo.suggestionSpan);
-            final int spanEnd = editable.getSpanEnd(suggestionInfo.suggestionSpan);
+            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;
             }
-
-            final String originalText = TextUtils.substring(editable, spanStart, spanEnd);
-
-            // SuggestionSpans are removed by replace: save them before
-            final SuggestionSpan[] suggestionSpans = editable.getSpans(spanStart, spanEnd,
-                    SuggestionSpan.class);
-            final int length = suggestionSpans.length;
-            final int[] suggestionSpansStarts = new int[length];
-            final int[] suggestionSpansEnds = new int[length];
-            final int[] suggestionSpansFlags = new int[length];
-            for (int i = 0; i < length; i++) {
-                final SuggestionSpan suggestionSpan = suggestionSpans[i];
-                suggestionSpansStarts[i] = editable.getSpanStart(suggestionSpan);
-                suggestionSpansEnds[i] = editable.getSpanEnd(suggestionSpan);
-                suggestionSpansFlags[i] = editable.getSpanFlags(suggestionSpan);
-
-                // Remove potential misspelled flags
-                int suggestionSpanFlags = suggestionSpan.getFlags();
-                if ((suggestionSpanFlags & SuggestionSpan.FLAG_MISSPELLED) > 0) {
-                    suggestionSpanFlags &= ~SuggestionSpan.FLAG_MISSPELLED;
-                    suggestionSpanFlags &= ~SuggestionSpan.FLAG_EASY_CORRECT;
-                    suggestionSpan.setFlags(suggestionSpanFlags);
-                }
-            }
-
-            final int suggestionStart = suggestionInfo.suggestionStart;
-            final int suggestionEnd = suggestionInfo.suggestionEnd;
-            final String suggestion = suggestionInfo.text.subSequence(
-                    suggestionStart, suggestionEnd).toString();
-            mTextView.replaceText_internal(spanStart, spanEnd, suggestion);
-
-            // Notify source IME of the suggestion pick. Do this before
-            // swaping texts.
-            suggestionInfo.suggestionSpan.notifySelection(
-                    mTextView.getContext(), originalText, suggestionInfo.suggestionIndex);
-
-            // Swap text content between actual text and Suggestion span
-            final String[] suggestions = suggestionInfo.suggestionSpan.getSuggestions();
-            suggestions[suggestionInfo.suggestionIndex] = originalText;
-
-            // Restore previous SuggestionSpans
-            final int lengthDifference = suggestion.length() - (spanEnd - spanStart);
-            for (int i = 0; i < length; i++) {
-                // Only spans that include the modified region make sense after replacement
-                // Spans partially included in the replaced region are removed, there is no
-                // way to assign them a valid range after replacement
-                if (suggestionSpansStarts[i] <= spanStart &&
-                        suggestionSpansEnds[i] >= spanEnd) {
-                    mTextView.setSpan_internal(suggestionSpans[i], suggestionSpansStarts[i],
-                            suggestionSpansEnds[i] + lengthDifference, suggestionSpansFlags[i]);
-                }
-            }
-
-            // Move cursor at the end of the replaced word
-            final int newCursorPosition = spanEnd + lengthDifference;
-            mTextView.setCursorPosition_internal(newCursorPosition, newCursorPosition);
+            replaceWithSuggestion(suggestionInfo, spanStart, spanEnd);
             hideWithCleanUp();
         }
     }
@@ -4738,6 +4945,14 @@
 
                     if (isMouse && !isDragAcceleratorActive()) {
                         final int offset = mTextView.getOffsetForPosition(eventX, eventY);
+                        if (mTextView.hasSelection()
+                                && (!mHaventMovedEnoughToStartDrag || mStartOffset != offset)
+                                && offset >= mTextView.getSelectionStart()
+                                && offset <= mTextView.getSelectionEnd()) {
+                            startDragAndDrop();
+                            break;
+                        }
+
                         if (mStartOffset != offset) {
                             // Start character based drag accelerator.
                             if (mTextActionMode != null) {
@@ -5113,6 +5328,7 @@
         Bundle extras;
         OnEditorActionListener onEditorActionListener;
         boolean enterDown;
+        LocaleList imeHintLocales;
     }
 
     static class InputMethodState {
diff --git a/core/java/android/widget/ForwardingListener.java b/core/java/android/widget/ForwardingListener.java
index 7ddeff9..b383e1c 100644
--- a/core/java/android/widget/ForwardingListener.java
+++ b/core/java/android/widget/ForwardingListener.java
@@ -53,12 +53,6 @@
     /** Whether this listener is currently forwarding touch events. */
     private boolean mForwarding;
 
-    /**
-     * Whether forwarding was initiated by a long-press. If so, we won't
-     * force the window to dismiss when the touch stream ends.
-     */
-    private boolean mWasLongPress;
-
     /** The id of the first pointer down in the current event stream. */
     private int mActivePointerId;
 
@@ -172,7 +166,6 @@
         switch (actionMasked) {
             case MotionEvent.ACTION_DOWN:
                 mActivePointerId = srcEvent.getPointerId(0);
-                mWasLongPress = false;
 
                 if (mDisallowIntercept == null) {
                     mDisallowIntercept = new DisallowIntercept();
@@ -243,7 +236,6 @@
         e.recycle();
 
         mForwarding = true;
-        mWasLongPress = true;
     }
 
     /**
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index 9ebbe36..a6ef572 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import android.annotation.NonNull;
 import android.annotation.Widget;
 import android.content.Context;
 import android.content.res.TypedArray;
@@ -1097,15 +1098,15 @@
     }
     
     @Override
-    public void onLongPress(MotionEvent e) {
-        
+    public void onLongPress(@NonNull MotionEvent e) {
         if (mDownTouchPosition < 0) {
             return;
         }
         
         performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
-        long id = getItemIdAtPosition(mDownTouchPosition);
-        dispatchLongPress(mDownTouchView, mDownTouchPosition, id);
+
+        final long id = getItemIdAtPosition(mDownTouchPosition);
+        dispatchLongPress(mDownTouchView, mDownTouchPosition, id, e.getX(), e.getY(), true);
     }
 
     // Unused methods from GestureDetector.OnGestureListener below
@@ -1159,29 +1160,47 @@
 
     @Override
     public boolean showContextMenuForChild(View originalView) {
+        return showContextMenuForChildInternal(originalView, 0, 0, false);
+    }
 
+    @Override
+    public boolean showContextMenuForChild(View originalView, float x, float y) {
+        return showContextMenuForChildInternal(originalView, x, y, true);
+    }
+
+    private boolean showContextMenuForChildInternal(View originalView, float x, float y,
+            boolean useOffsets) {
         final int longPressPosition = getPositionForView(originalView);
         if (longPressPosition < 0) {
             return false;
         }
         
         final long longPressId = mAdapter.getItemId(longPressPosition);
-        return dispatchLongPress(originalView, longPressPosition, longPressId);
+        return dispatchLongPress(originalView, longPressPosition, longPressId, x, y, useOffsets);
     }
 
     @Override
     public boolean showContextMenu() {
-        
+        return showContextMenuInternal(0, 0, false);
+    }
+
+    @Override
+    public boolean showContextMenu(float x, float y) {
+        return showContextMenuInternal(x, y, true);
+    }
+
+    private boolean showContextMenuInternal(float x, float y, boolean useOffsets) {
         if (isPressed() && mSelectedPosition >= 0) {
-            int index = mSelectedPosition - mFirstPosition;
-            View v = getChildAt(index);
-            return dispatchLongPress(v, mSelectedPosition, mSelectedRowId);
+            final int index = mSelectedPosition - mFirstPosition;
+            final View v = getChildAt(index);
+            return dispatchLongPress(v, mSelectedPosition, mSelectedRowId, x, y, useOffsets);
         }        
         
         return false;
     }
 
-    private boolean dispatchLongPress(View view, int position, long id) {
+    private boolean dispatchLongPress(View view, int position, long id, float x, float y,
+            boolean useOffsets) {
         boolean handled = false;
         
         if (mOnItemLongClickListener != null) {
@@ -1191,7 +1210,12 @@
 
         if (!handled) {
             mContextMenuInfo = new AdapterContextMenuInfo(view, position, id);
-            handled = super.showContextMenuForChild(this);
+
+            if (useOffsets) {
+                handled = super.showContextMenuForChild(view, x, y);
+            } else {
+                handled = super.showContextMenuForChild(this);
+            }
         }
 
         if (handled) {
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 258424a..ef6628a 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -1752,7 +1752,8 @@
             boolean validSolution = true;
             // do a binary search to find the max delta that won't conflict with constraints
             while(deltaMin < deltaMax) {
-                final int delta = (deltaMin + deltaMax) / 2;
+                // cast to long to prevent overflow.
+                final int delta = (int) (((long) deltaMin + deltaMax) / 2);
                 invalidateValues();
                 shareOutDelta(delta, totalWeight);
                 validSolution = solve(getArcs(), a, false);
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index ebc7eb3..f16fdd6 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -454,6 +454,10 @@
             return true;
         }
 
+        if (super.onInterceptTouchEvent(ev)) {
+            return true;
+        }
+
         switch (action & MotionEvent.ACTION_MASK) {
             case MotionEvent.ACTION_MOVE: {
                 /*
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index ad939be..e0ef86c 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -359,7 +359,6 @@
         final int count = getVirtualChildCount();
         for (int i = 0; i < count; i++) {
             final View child = getVirtualChildAt(i);
-
             if (child != null && child.getVisibility() != GONE) {
                 if (hasDividerBeforeChildAt(i)) {
                     final LayoutParams lp = (LayoutParams) child.getLayoutParams();
@@ -388,7 +387,7 @@
      */
     private View getLastNonGoneChild() {
         for (int i = getVirtualChildCount() - 1; i >= 0; i--) {
-            View child = getVirtualChildAt(i);
+            final View child = getVirtualChildAt(i);
             if (child != null && child.getVisibility() != GONE) {
                 return child;
             }
@@ -401,7 +400,6 @@
         final boolean isLayoutRtl = isLayoutRtl();
         for (int i = 0; i < count; i++) {
             final View child = getVirtualChildAt(i);
-
             if (child != null && child.getVisibility() != GONE) {
                 if (hasDividerBeforeChildAt(i)) {
                     final LayoutParams lp = (LayoutParams) child.getLayoutParams();
@@ -588,8 +586,9 @@
      * for an example.</p>
      *
      * @param index the child's index
-     * @return the child at the specified index
+     * @return the child at the specified index, may be {@code null}
      */
+    @Nullable
     View getVirtualChildAt(int index) {
         return getChildAt(index);
     }
@@ -670,7 +669,7 @@
      */
     private boolean allViewsAreGoneBefore(int childIndex) {
         for (int i = childIndex - 1; i >= 0; i--) {
-            View child = getVirtualChildAt(i);
+            final View child = getVirtualChildAt(i);
             if (child != null && child.getVisibility() != GONE) {
                 return false;
             }
@@ -715,7 +714,6 @@
         // See how tall everyone is. Also remember max width.
         for (int i = 0; i < count; ++i) {
             final View child = getVirtualChildAt(i);
-
             if (child == null) {
                 mTotalLength += measureNullChild(i);
                 continue;
@@ -837,7 +835,6 @@
 
             for (int i = 0; i < count; ++i) {
                 final View child = getVirtualChildAt(i);
-
                 if (child == null) {
                     mTotalLength += measureNullChild(i);
                     continue;
@@ -943,7 +940,6 @@
             if (useLargestChild && heightMode != MeasureSpec.EXACTLY) {
                 for (int i = 0; i < count; i++) {
                     final View child = getVirtualChildAt(i);
-
                     if (child == null || child.getVisibility() == View.GONE) {
                         continue;
                     }
@@ -986,7 +982,7 @@
                 MeasureSpec.EXACTLY);
         for (int i = 0; i< count; ++i) {
            final View child = getVirtualChildAt(i);
-           if (child.getVisibility() != GONE) { 
+           if (child != null && child.getVisibility() != GONE) {
                LinearLayout.LayoutParams lp = ((LinearLayout.LayoutParams)child.getLayoutParams());
                
                if (lp.width == LayoutParams.MATCH_PARENT) {
@@ -1053,7 +1049,6 @@
         // See how wide everyone is. Also remember max height.
         for (int i = 0; i < count; ++i) {
             final View child = getVirtualChildAt(i);
-
             if (child == null) {
                 mTotalLength += measureNullChild(i);
                 continue;
@@ -1211,7 +1206,6 @@
 
             for (int i = 0; i < count; ++i) {
                 final View child = getVirtualChildAt(i);
-
                 if (child == null) {
                     mTotalLength += measureNullChild(i);
                     continue;
@@ -1357,7 +1351,6 @@
             if (useLargestChild && widthMode != MeasureSpec.EXACTLY) {
                 for (int i = 0; i < count; i++) {
                     final View child = getVirtualChildAt(i);
-
                     if (child == null || child.getVisibility() == View.GONE) {
                         continue;
                     }
@@ -1402,7 +1395,7 @@
                 MeasureSpec.EXACTLY);
         for (int i = 0; i < count; ++i) {
            final View child = getVirtualChildAt(i);
-           if (child.getVisibility() != GONE) { 
+           if (child != null && child.getVisibility() != GONE) {
                LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
                
                if (lp.height == LayoutParams.MATCH_PARENT) {
@@ -1662,9 +1655,8 @@
         }
 
         for (int i = 0; i < count; i++) {
-            int childIndex = start + dir * i;
+            final int childIndex = start + dir * i;
             final View child = getVirtualChildAt(childIndex);
-
             if (child == null) {
                 childLeft += measureNullChild(childIndex);
             } else if (child.getVisibility() != GONE) {
@@ -1789,6 +1781,16 @@
         }
     }
 
+    /**
+     * Returns the current gravity. See {@link android.view.Gravity}
+     *
+     * @return the current gravity.
+     * @see #setGravity
+     */
+    public int getGravity() {
+        return mGravity;
+    }
+
     @android.view.RemotableViewMethod
     public void setHorizontalGravity(int horizontalGravity) {
         final int gravity = horizontalGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index b95bc28..dcadb6a 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -16,18 +16,20 @@
 
 package android.widget;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
+import com.android.internal.R;
+import com.android.internal.view.menu.ShowableListMenu;
+
+import android.annotation.AttrRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StyleRes;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.database.DataSetObserver;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
-import android.text.TextUtils;
 import android.util.AttributeSet;
-import android.util.IntProperty;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.KeyEvent;
@@ -38,13 +40,7 @@
 import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.view.WindowManager;
-import android.view.animation.AccelerateDecelerateInterpolator;
-
-import com.android.internal.R;
-import com.android.internal.view.menu.ShowableListMenu;
-import com.android.internal.widget.AutoScrollHelper.AbsListViewAutoScroller;
-
-import java.util.Locale;
+import android.widget.AdapterView.OnItemSelectedListener;
 
 /**
  * A ListPopupWindow anchors itself to a host view and displays a
@@ -78,6 +74,7 @@
     private int mDropDownVerticalOffset;
     private int mDropDownWindowLayoutType = WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
     private boolean mDropDownVerticalOffsetSet;
+    private boolean mIsAnimatedFromAnchor = true;
 
     private int mDropDownGravity = Gravity.NO_GRAVITY;
 
@@ -105,12 +102,16 @@
 
     private final Handler mHandler;
 
-    private Rect mTempRect = new Rect();
+    private final Rect mTempRect = new Rect();
+
+    /**
+     * Optional anchor-relative bounds to be used as the transition epicenter.
+     * When {@code null}, the anchor bounds are used as the epicenter.
+     */
+    private Rect mEpicenterBounds;
 
     private boolean mModal;
 
-    private int mLayoutDirection;
-
     PopupWindow mPopup;
 
     /**
@@ -174,7 +175,7 @@
      * 
      * @param context Context used for contained views.
      */
-    public ListPopupWindow(Context context) {
+    public ListPopupWindow(@NonNull Context context) {
         this(context, null, com.android.internal.R.attr.listPopupWindowStyle, 0);
     }
 
@@ -185,7 +186,7 @@
      * @param context Context used for contained views.
      * @param attrs Attributes from inflating parent views used to style the popup.
      */
-    public ListPopupWindow(Context context, AttributeSet attrs) {
+    public ListPopupWindow(@NonNull Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, com.android.internal.R.attr.listPopupWindowStyle, 0);
     }
 
@@ -197,7 +198,8 @@
      * @param attrs Attributes from inflating parent views used to style the popup.
      * @param defStyleAttr Default style attribute to use for popup content.
      */
-    public ListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr) {
+    public ListPopupWindow(@NonNull Context context, @Nullable AttributeSet attrs,
+            @AttrRes int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
@@ -210,7 +212,8 @@
      * @param defStyleAttr Style attribute to read for default styling of popup content.
      * @param defStyleRes Style resource ID to use for default styling of popup content.
      */
-    public ListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public ListPopupWindow(@NonNull Context context, @Nullable AttributeSet attrs,
+            @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
         mContext = context;
         mHandler = new Handler(context.getMainLooper());
 
@@ -227,9 +230,6 @@
 
         mPopup = new PopupWindow(context, attrs, defStyleAttr, defStyleRes);
         mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
-        // Set the default layout direction to match the default locale one
-        final Locale locale = mContext.getResources().getConfiguration().locale;
-        mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(locale);
     }
 
     /**
@@ -238,7 +238,7 @@
      *
      * @param adapter The adapter to use to create this window's content.
      */
-    public void setAdapter(ListAdapter adapter) {
+    public void setAdapter(@Nullable ListAdapter adapter) {
         if (mObserver == null) {
             mObserver = new PopupDataSetObserver();
         } else if (mAdapter != null) {
@@ -371,7 +371,7 @@
     /**
      * @return The background drawable for the popup window.
      */
-    public Drawable getBackground() {
+    public @Nullable Drawable getBackground() {
         return mPopup.getBackground();
     }
 
@@ -380,7 +380,7 @@
      * 
      * @param d A drawable to set as the background.
      */
-    public void setBackgroundDrawable(Drawable d) {
+    public void setBackgroundDrawable(@Nullable Drawable d) {
         mPopup.setBackgroundDrawable(d);
     }
 
@@ -389,7 +389,7 @@
      * 
      * @param animationStyle Animation style to use.
      */
-    public void setAnimationStyle(int animationStyle) {
+    public void setAnimationStyle(@StyleRes int animationStyle) {
         mPopup.setAnimationStyle(animationStyle);
     }
 
@@ -399,7 +399,7 @@
      * 
      * @return Animation style that will be used.
      */
-    public int getAnimationStyle() {
+    public @StyleRes int getAnimationStyle() {
         return mPopup.getAnimationStyle();
     }
 
@@ -408,7 +408,7 @@
      * 
      * @return The popup's anchor view
      */
-    public View getAnchorView() {
+    public @Nullable View getAnchorView() {
         return mDropDownAnchorView;
     }
 
@@ -418,7 +418,7 @@
      * 
      * @param anchor The view to use as an anchor.
      */
-    public void setAnchorView(View anchor) {
+    public void setAnchorView(@Nullable View anchor) {
         mDropDownAnchorView = anchor;
     }
 
@@ -459,6 +459,17 @@
     }
 
     /**
+     * Specifies the anchor-relative bounds of the popup's transition
+     * epicenter.
+     *
+     * @param bounds anchor-relative bounds
+     * @hide
+     */
+    public void setEpicenterBounds(Rect bounds) {
+        mEpicenterBounds = bounds;
+    }
+
+    /**
      * Set the gravity of the dropdown list. This is commonly used to
      * set gravity to START or END for alignment with the anchor.
      *
@@ -537,7 +548,7 @@
      * 
      * @see ListView#setOnItemClickListener(android.widget.AdapterView.OnItemClickListener)
      */
-    public void setOnItemClickListener(AdapterView.OnItemClickListener clickListener) {
+    public void setOnItemClickListener(@Nullable AdapterView.OnItemClickListener clickListener) {
         mItemClickListener = clickListener;
     }
 
@@ -546,9 +557,9 @@
      * 
      * @param selectedListener Listener to register.
      * 
-     * @see ListView#setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener)
+     * @see ListView#setOnItemSelectedListener(OnItemSelectedListener)
      */
-    public void setOnItemSelectedListener(AdapterView.OnItemSelectedListener selectedListener) {
+    public void setOnItemSelectedListener(@Nullable OnItemSelectedListener selectedListener) {
         mItemSelectedListener = selectedListener;
     }
 
@@ -558,7 +569,7 @@
      * 
      * @param prompt View to use as an informational prompt.
      */
-    public void setPromptView(View prompt) {
+    public void setPromptView(@Nullable View prompt) {
         boolean showing = isShowing();
         if (showing) {
             removePromptView();
@@ -656,6 +667,7 @@
             // only set this if the dropdown is not always visible
             mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible);
             mPopup.setTouchInterceptor(mTouchInterceptor);
+            mPopup.setEpicenterBounds(mEpicenterBounds);
             mPopup.showAsDropDown(getAnchorView(), mDropDownHorizontalOffset,
                     mDropDownVerticalOffset, mDropDownGravity);
             mDropDownList.setSelection(ListView.INVALID_POSITION);
@@ -686,7 +698,7 @@
      *
      * @param listener Listener that will be notified when the popup is dismissed.
      */
-    public void setOnDismissListener(PopupWindow.OnDismissListener listener) {
+    public void setOnDismissListener(@Nullable PopupWindow.OnDismissListener listener) {
         mPopup.setOnDismissListener(listener);
     }
 
@@ -795,7 +807,7 @@
     /**
      * @return The currently selected item or null if the popup is not showing.
      */
-    public Object getSelectedItem() {
+    public @Nullable Object getSelectedItem() {
         if (!isShowing()) {
             return null;
         }
@@ -834,7 +846,7 @@
      * 
      * @see ListView#getSelectedView()
      */
-    public View getSelectedView() {
+    public @Nullable View getSelectedView() {
         if (!isShowing()) {
             return null;
         }
@@ -846,11 +858,11 @@
      * Only valid when {@link #isShowing()} == {@code true}.
      */
     @Override
-    public ListView getListView() {
+    public @Nullable ListView getListView() {
         return mDropDownList;
     }
 
-    DropDownListView createDropDownListView(Context context, boolean hijackFocus) {
+    @NonNull DropDownListView createDropDownListView(Context context, boolean hijackFocus) {
         return new DropDownListView(context, hijackFocus);
     }
 
@@ -874,7 +886,7 @@
      * 
      * @see #setModal(boolean)
      */
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
+    public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
         // when the drop down is shown, we drive it directly
         if (isShowing()) {
             // the key events are forwarded to the list in the drop down view
@@ -969,7 +981,7 @@
      * 
      * @see #setModal(boolean)
      */
-    public boolean onKeyUp(int keyCode, KeyEvent event) {
+    public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
         if (isShowing() && mDropDownList.getSelectedItemPosition() >= 0) {
             boolean consumed = mDropDownList.onKeyUp(keyCode, event);
             if (consumed && KeyEvent.isConfirmKey(keyCode)) {
@@ -993,7 +1005,7 @@
      * 
      * @see #setModal(boolean)
      */
-    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+    public boolean onKeyPreIme(int keyCode, @NonNull KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_BACK && isShowing()) {
             // special case for the back key, we do not even try to send it
             // to the drop down list but instead, consume it immediately
@@ -1159,7 +1171,6 @@
 
             mPopup.setContentView(dropDownView);
         } else {
-            dropDownView = (ViewGroup) mPopup.getContentView();
             final View view = mPromptView;
             if (view != null) {
                 LinearLayout.LayoutParams hintParams =
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 064808b..a11897d 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -2181,7 +2181,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/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index f4c343a..584df08 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -16,6 +16,7 @@
 
 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;
@@ -149,6 +150,7 @@
 
     private Transition mEnterTransition;
     private Transition mExitTransition;
+    private Rect mEpicenterBounds;
 
     private boolean mAboveAnchor;
     private int mWindowLayoutType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
@@ -344,6 +346,25 @@
         mExitTransition = exitTransition;
     }
 
+    /**
+     * 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
+     * the direction of travel. For popup windows, the anchor view bounds are
+     * used as the default epicenter.
+     * <p>
+     * See {@link Transition#setEpicenterCallback(EpicenterCallback)} for more
+     * information about how transition epicenters.
+     *
+     * @param bounds the epicenter bounds relative to the anchor view, or
+     *               {@code null} to use the default epicenter
+     * @see #getTransitionEpicenter()
+     * @hide
+     */
+    public void setEpicenterBounds(Rect bounds) {
+        mEpicenterBounds = bounds;
+    }
+
     private Transition getTransition(int resId) {
         if (resId != 0 && resId != R.transition.no_transition) {
             final TransitionInflater inflater = TransitionInflater.from(mContext);
@@ -1313,7 +1334,8 @@
             p.width = mLastWidth = mWidth;
         }
 
-        p.privateFlags = PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
+        p.privateFlags = PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH
+                | PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
 
         // Used for debugging.
         p.setTitle("PopupWindow:" + Integer.toHexString(hashCode()));
@@ -1465,10 +1487,14 @@
         }
 
         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 > displayFrameWidth) {
-                p.x -= right - displayFrameWidth;
+            if (right > displayFrame.right) {
+                p.x -= right - displayFrame.right;
             }
 
             if (p.x < displayFrame.left) {
@@ -1477,10 +1503,9 @@
             }
 
             if (mOverlapAnchor) {
-                final int displayFrameHeight = displayFrame.bottom - displayFrame.top;
                 final int bottom = p.y + p.height;
                 if (bottom > displayFrame.bottom) {
-                    p.y -= bottom - displayFrameHeight;
+                    p.y -= bottom - displayFrame.bottom;
                 }
             } else {
                 if (onTop) {
@@ -1492,6 +1517,8 @@
                     p.y = Math.max(p.y, displayFrame.top);
                 }
             }
+            p.x -= winOffsetX;
+            p.y -= winOffsetY;
         }
 
         p.gravity |= Gravity.DISPLAY_CLIP_VERTICAL;
@@ -1614,7 +1641,7 @@
             p.flags |= LayoutParams.FLAG_NOT_FOCUSABLE;
             mWindowManager.updateViewLayout(decorView, p);
 
-            final Rect epicenter = getRelativeAnchorBounds();
+            final Rect epicenter = getTransitionEpicenter();
             exitTransition.setEpicenterCallback(new EpicenterCallback() {
                 @Override
                 public Rect onGetEpicenter(Transition transition) {
@@ -1639,7 +1666,17 @@
         }
     }
 
-    private Rect getRelativeAnchorBounds() {
+    /**
+     * Returns the window-relative epicenter bounds to be used by enter and
+     * exit transitions.
+     * <p>
+     * <strong>Note:</strong> This is distinct from the rect passed to
+     * {@link #setEpicenterBounds(Rect)}, which is anchor-relative.
+     *
+     * @return the window-relative epicenter bounds to be used by enter and
+     *         exit transitions
+     */
+    private Rect getTransitionEpicenter() {
         final View anchor = mAnchor != null ? mAnchor.get() : null;
         final View decor = mDecorView;
         if (anchor == null || decor == null) {
@@ -1652,6 +1689,15 @@
         // Compute the position of the anchor relative to the popup.
         final Rect bounds = new Rect(0, 0, anchor.getWidth(), anchor.getHeight());
         bounds.offset(anchorLocation[0] - popupLocation[0], anchorLocation[1] - popupLocation[1]);
+
+        // Use anchor-relative epicenter, if specified.
+        if (mEpicenterBounds != null) {
+            final int offsetX = bounds.left;
+            final int offsetY = bounds.top;
+            bounds.set(mEpicenterBounds);
+            bounds.offset(offsetX, offsetY);
+        }
+
         return bounds;
     }
 
@@ -2024,7 +2070,7 @@
                             observer.removeOnGlobalLayoutListener(this);
                         }
 
-                        final Rect epicenter = getRelativeAnchorBounds();
+                        final Rect epicenter = getTransitionEpicenter();
                         enterTransition.setEpicenterCallback(new EpicenterCallback() {
                             @Override
                             public Rect onGetEpicenter(Transition transition) {
diff --git a/core/java/android/widget/ScrollBarDrawable.java b/core/java/android/widget/ScrollBarDrawable.java
index 91d6232..8880217 100644
--- a/core/java/android/widget/ScrollBarDrawable.java
+++ b/core/java/android/widget/ScrollBarDrawable.java
@@ -16,6 +16,8 @@
 
 package android.widget;
 
+import com.android.internal.widget.ScrollBarUtils;
+
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.PixelFormat;
@@ -135,23 +137,15 @@
         }
 
         if (drawThumb) {
-            final int size = vertical ? r.height() : r.width();
+            final int scrollBarLength = vertical ? r.height() : r.width();
             final int thickness = vertical ? r.width() : r.height();
-            final int minLength = thickness * 2;
+            final int thumbLength =
+                    ScrollBarUtils.getThumbLength(scrollBarLength, thickness, extent, range);
+            final int thumbOffset =
+                    ScrollBarUtils.getThumbOffset(scrollBarLength, thumbLength, extent, range,
+                            mOffset);
 
-            // Avoid the tiny thumb.
-            int length = Math.round((float) size * extent / range);
-            if (length < minLength) {
-                length = minLength;
-            }
-
-            // Avoid the too-big thumb.
-            int offset = Math.round((float) (size - length) * mOffset / (range - extent));
-            if (offset > size - length) {
-                offset = size - length;
-            }
-
-            drawThumb(canvas, r, offset, length, vertical);
+            drawThumb(canvas, r, thumbOffset, thumbLength, vertical);
         }
     }
 
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 78b931d..3f7a07b 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -489,6 +489,10 @@
             return true;
         }
 
+        if (super.onInterceptTouchEvent(ev)) {
+            return true;
+        }
+
         /*
          * Don't try to intercept touch if we can't scroll anyway.
          */
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index c79e184..09cf704 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -271,6 +271,10 @@
                         attrs, R.styleable.Spinner, defStyleAttr, defStyleRes);
                 mDropDownWidth = pa.getLayoutDimension(R.styleable.Spinner_dropDownWidth,
                         ViewGroup.LayoutParams.WRAP_CONTENT);
+                if (pa.hasValueOrEmpty(R.styleable.Spinner_dropDownSelector)) {
+                    popup.setListSelector(pa.getDrawable(
+                            R.styleable.Spinner_dropDownSelector));
+                }
                 popup.setBackgroundDrawable(pa.getDrawable(R.styleable.Spinner_popupBackground));
                 popup.setPromptText(a.getString(R.styleable.Spinner_prompt));
                 pa.recycle();
diff --git a/core/java/android/widget/TableRow.java b/core/java/android/widget/TableRow.java
index f7f9c91..22931fc 100644
--- a/core/java/android/widget/TableRow.java
+++ b/core/java/android/widget/TableRow.java
@@ -98,7 +98,7 @@
      * {@hide}
      */
     void setColumnCollapsed(int columnIndex, boolean collapsed) {
-        View child = getVirtualChildAt(columnIndex);
+        final View child = getVirtualChildAt(columnIndex);
         if (child != null) {
             child.setVisibility(collapsed ? GONE : VISIBLE);
         }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 17c803f..c626af6 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -111,6 +111,7 @@
 import android.view.AccessibilityIterators.TextSegmentIterator;
 import android.view.ActionMode;
 import android.view.Choreographer;
+import android.view.ContextMenu;
 import android.view.DragEvent;
 import android.view.Gravity;
 import android.view.HapticFeedbackConstants;
@@ -393,7 +394,17 @@
             mOverride = false;
         }
 
-        public void resolveWithLayoutDirection(int layoutDirection) {
+        /**
+         * Updates the list of displayed drawables to account for the current
+         * layout direction.
+         *
+         * @param layoutDirection the current layout direction
+         * @return {@code true} if the displayed drawables changed
+         */
+        public boolean resolveWithLayoutDirection(int layoutDirection) {
+            final Drawable previousLeft = mShowing[Drawables.LEFT];
+            final Drawable previousRight = mShowing[Drawables.RIGHT];
+
             // First reset "left" and "right" drawables to their initial values
             mShowing[Drawables.LEFT] = mDrawableLeftInitial;
             mShowing[Drawables.RIGHT] = mDrawableRightInitial;
@@ -441,16 +452,11 @@
                         break;
                 }
             }
-            applyErrorDrawableIfNeeded(layoutDirection);
-            updateDrawablesLayoutDirection(layoutDirection);
-        }
 
-        private void updateDrawablesLayoutDirection(int layoutDirection) {
-            for (Drawable dr : mShowing) {
-                if (dr != null) {
-                    dr.setLayoutDirection(layoutDirection);
-                }
-            }
+            applyErrorDrawableIfNeeded(layoutDirection);
+
+            return mShowing[Drawables.LEFT] != previousLeft
+                    || mShowing[Drawables.RIGHT] != previousRight;
         }
 
         public void setErrorDrawable(Drawable dr, TextView tv) {
@@ -639,6 +645,16 @@
      */
     private Editor mEditor;
 
+    private static final int DEVICE_PROVISIONED_UNKNOWN = 0;
+    private static final int DEVICE_PROVISIONED_NO = 1;
+    private static final int DEVICE_PROVISIONED_YES = 2;
+
+    /**
+     * Some special options such as sharing selected text should only be shown if the device
+     * is provisioned. Only check the provisioned state once for a given view instance.
+     */
+    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).
@@ -4986,6 +5002,35 @@
     }
 
     /**
+     * Change "hint" locales associated with the text view, which will be reported to an IME with
+     * {@link EditorInfo#hintLocales} when it has focus.
+     *
+     * <p><strong>Note:</strong> If you want new "hint" to take effect immediately you need to
+     * call {@link InputMethodManager#restartInput(View)}.</p>
+     * @param hintLocales List of the languages that the user is supposed to switch to no matter
+     * what input method subtype is currently used. Set {@code null} to clear the current "hint".
+     * @see #getImeHIntLocales()
+     * @see android.view.inputmethod.EditorInfo#hintLocales
+     */
+    public void setImeHintLocales(@Nullable LocaleList hintLocales) {
+        createEditorIfNeeded();
+        mEditor.createInputContentTypeIfNeeded();
+        mEditor.mInputContentType.imeHintLocales = hintLocales;
+    }
+
+    /**
+     * @return The current languages list "hint". {@code null} when no "hint" is available.
+     * @see #setImeHintLocales(LocaleList)
+     * @see android.view.inputmethod.EditorInfo#hintLocales
+     */
+    @Nullable
+    public LocaleList getImeHintLocales() {
+        if (mEditor == null) { return null; }
+        if (mEditor.mInputContentType == null) { return null; }
+        return mEditor.mInputContentType.imeHintLocales;
+    }
+
+    /**
      * Returns the error message that was set to be displayed with
      * {@link #setError}, or <code>null</code> if no error was set
      * or if it the error was cleared by the widget after user input.
@@ -5957,6 +6002,14 @@
 
     @Override
     public PointerIcon getPointerIcon(MotionEvent event, float x, float y) {
+        if (mText instanceof Spannable && mLinksClickable) {
+            final int offset = getOffsetForPosition(x, y);
+            final ClickableSpan[] clickables = ((Spannable) mText).getSpans(offset, offset,
+                    ClickableSpan.class);
+            if (clickables.length > 0) {
+                return PointerIcon.getSystemIcon(mContext, PointerIcon.STYLE_HAND);
+            }
+        }
         if (isTextSelectable() || isTextEditable()) {
             return PointerIcon.getSystemIcon(mContext, PointerIcon.STYLE_TEXT);
         }
@@ -6397,8 +6450,10 @@
                 outAttrs.actionLabel = mEditor.mInputContentType.imeActionLabel;
                 outAttrs.actionId = mEditor.mInputContentType.imeActionId;
                 outAttrs.extras = mEditor.mInputContentType.extras;
+                outAttrs.hintLocales = mEditor.mInputContentType.imeHintLocales;
             } else {
                 outAttrs.imeOptions = EditorInfo.IME_NULL;
+                outAttrs.hintLocales = null;
             }
             if (focusSearch(FOCUS_DOWN) != null) {
                 outAttrs.imeOptions |= EditorInfo.IME_FLAG_NAVIGATE_NEXT;
@@ -6433,9 +6488,6 @@
                 outAttrs.initialCapsMode = ic.getCursorCapsMode(getInputType());
                 return ic;
             }
-            // LocaleList is designed to be immutable.  This is theoretically equivalent to copy
-            // the snapshot of the current text locales.
-            outAttrs.locales = getTextLocales();
         }
         return null;
     }
@@ -8489,6 +8541,29 @@
         return super.onGenericMotionEvent(event);
     }
 
+    @Override
+    protected void onCreateContextMenu(ContextMenu menu) {
+        if (mEditor != null) {
+            mEditor.onCreateContextMenu(menu);
+        }
+    }
+
+    @Override
+    public boolean showContextMenu() {
+        if (mEditor != null) {
+            mEditor.setContextMenuAnchor(Float.NaN, Float.NaN);
+        }
+        return super.showContextMenu();
+    }
+
+    @Override
+    public boolean showContextMenu(float x, float y) {
+        if (mEditor != null) {
+            mEditor.setContextMenuAnchor(x, y);
+        }
+        return super.showContextMenu(x, y);
+    }
+
     /**
      * @return True iff this TextView contains a text that can be edited, or if this is
      * a selectable TextView.
@@ -9390,12 +9465,17 @@
     public boolean performLongClick() {
         boolean handled = false;
 
+        if (mEditor != null) {
+            mEditor.mIsBeingLongClicked = true;
+        }
+
         if (super.performLongClick()) {
             handled = true;
         }
 
         if (mEditor != null) {
             handled |= mEditor.performLongClick(handled);
+            mEditor.mIsBeingLongClicked = false;
         }
 
         if (handled) {
@@ -9571,7 +9651,17 @@
     }
 
     boolean canShare() {
-        return canCopy();
+        return canCopy() && isDeviceProvisioned();
+    }
+
+    boolean isDeviceProvisioned() {
+        if (mDeviceProvisionedState == DEVICE_PROVISIONED_UNKNOWN) {
+            mDeviceProvisionedState = Settings.Global.getInt(
+                    mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0
+                    ? DEVICE_PROVISIONED_YES
+                    : DEVICE_PROVISIONED_NO;
+        }
+        return mDeviceProvisionedState == DEVICE_PROVISIONED_YES;
     }
 
     boolean canPaste() {
@@ -9809,7 +9899,30 @@
 
         // Resolve drawables
         if (mDrawables != null) {
-            mDrawables.resolveWithLayoutDirection(layoutDirection);
+            if (mDrawables.resolveWithLayoutDirection(layoutDirection)) {
+                prepareDrawableForDisplay(mDrawables.mShowing[Drawables.LEFT]);
+                prepareDrawableForDisplay(mDrawables.mShowing[Drawables.RIGHT]);
+                applyCompoundDrawableTint();
+            }
+        }
+    }
+
+    /**
+     * Prepares a drawable for display by propagating layout direction and
+     * drawable state.
+     *
+     * @param dr the drawable to prepare
+     */
+    private void prepareDrawableForDisplay(@Nullable Drawable dr) {
+        if (dr == null) {
+            return;
+        }
+
+        dr.setLayoutDirection(getLayoutDirection());
+
+        if (dr.isStateful()) {
+            dr.setState(getDrawableState());
+            dr.jumpToCurrentState();
         }
     }
 
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index acbf5eb..06daf61 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -1946,6 +1946,9 @@
     public void setMenuCallbacks(MenuPresenter.Callback pcb, MenuBuilder.Callback mcb) {
         mActionMenuPresenterCallback = pcb;
         mMenuBuilderCallback = mcb;
+        if (mMenuView != null) {
+            mMenuView.setMenuCallbacks(pcb, mcb);
+        }
     }
 
     /**
@@ -2070,7 +2073,7 @@
         MenuItemImpl mCurrentExpandedItem;
 
         @Override
-        public void initForMenu(Context context, MenuBuilder menu) {
+        public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) {
             // Clear the expanded action view when menus change.
             if (mMenu != null && mCurrentExpandedItem != null) {
                 mMenu.collapseItemActionView(mCurrentExpandedItem);
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 2671739..f084db2 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -22,6 +22,7 @@
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.media.AudioManager;
+import android.media.Cea708CaptionRenderer;
 import android.media.ClosedCaptionRenderer;
 import android.media.MediaFormat;
 import android.media.MediaPlayer;
@@ -328,6 +329,7 @@
                     context, mMediaPlayer.getMediaTimeProvider(), mMediaPlayer);
             controller.registerRenderer(new WebVttRenderer(context));
             controller.registerRenderer(new TtmlRenderer(context));
+            controller.registerRenderer(new Cea708CaptionRenderer(context));
             controller.registerRenderer(new ClosedCaptionRenderer(context));
             mMediaPlayer.setSubtitleAnchor(controller, this);
 
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 66374a6..27c3b72 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -378,6 +378,7 @@
 
         if (mIconView != null) {
             if (icon != null) {
+                mIconView.setVisibility(View.VISIBLE);
                 mIconView.setImageDrawable(icon);
             } else {
                 mIconView.setVisibility(View.GONE);
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index b7b7400..2733391 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -66,6 +66,7 @@
 import android.widget.ListView;
 import com.android.internal.R;
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -209,7 +210,7 @@
         super.onCreate(savedInstanceState, target, title, defaultTitleRes, initialIntents,
                 null, false);
 
-        MetricsLogger.action(this, MetricsLogger.ACTION_ACTIVITY_CHOOSER_SHOWN);
+        MetricsLogger.action(this, MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN);
     }
 
     @Override
@@ -349,14 +350,14 @@
             int value = which;
             switch (mChooserListAdapter.getPositionTargetType(which)) {
                 case ChooserListAdapter.TARGET_CALLER:
-                    cat = MetricsLogger.ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET;
+                    cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET;
                     break;
                 case ChooserListAdapter.TARGET_SERVICE:
-                    cat = MetricsLogger.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET;
+                    cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET;
                     value -= mChooserListAdapter.getCallerTargetCount();
                     break;
                 case ChooserListAdapter.TARGET_STANDARD:
-                    cat = MetricsLogger.ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET;
+                    cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET;
                     value -= mChooserListAdapter.getCallerTargetCount()
                             + mChooserListAdapter.getServiceTargetCount();
                     break;
diff --git a/core/java/com/android/internal/app/ConfirmUserCreationActivity.java b/core/java/com/android/internal/app/ConfirmUserCreationActivity.java
new file mode 100644
index 0000000..03da9bc
--- /dev/null
+++ b/core/java/com/android/internal/app/ConfirmUserCreationActivity.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.accounts.Account;
+import android.accounts.AccountManager;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
+import android.os.Bundle;
+import android.os.PersistableBundle;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+
+import com.android.internal.R;
+
+/**
+ * Activity to confirm with the user that it is ok to create a new user, as requested by
+ * an app. It has to do some checks to decide what kind of prompt the user should be shown.
+ * Particularly, it needs to check if the account requested already exists on another user.
+ */
+public class ConfirmUserCreationActivity extends AlertActivity
+        implements DialogInterface.OnClickListener {
+
+    private static final String TAG = "CreateUser";
+
+    private String mUserName;
+    private String mAccountName;
+    private String mAccountType;
+    private PersistableBundle mAccountOptions;
+    private boolean mCanProceed;
+    private UserManager mUserManager;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        Intent intent = getIntent();
+        mUserName = intent.getStringExtra(UserManager.EXTRA_USER_NAME);
+        mAccountName = intent.getStringExtra(UserManager.EXTRA_USER_ACCOUNT_NAME);
+        mAccountType = intent.getStringExtra(UserManager.EXTRA_USER_ACCOUNT_TYPE);
+        mAccountOptions = (PersistableBundle)
+                intent.getParcelableExtra(UserManager.EXTRA_USER_ACCOUNT_OPTIONS);
+
+        mUserManager = getSystemService(UserManager.class);
+
+        String message = checkUserCreationRequirements();
+
+        if (message == null) {
+            finish();
+            return;
+        }
+        final AlertController.AlertParams ap = mAlertParams;
+        ap.mMessage = message;
+        ap.mPositiveButtonText = getString(android.R.string.ok);
+        ap.mPositiveButtonListener = this;
+
+        // Show the negative button if the user actually has a choice
+        if (mCanProceed) {
+            ap.mNegativeButtonText = getString(android.R.string.cancel);
+            ap.mNegativeButtonListener = this;
+        }
+        setupAlert();
+    }
+
+    private String checkUserCreationRequirements() {
+        final String callingPackage = getCallingPackage();
+        if (callingPackage == null) {
+            throw new SecurityException(
+                    "User Creation intent must be launched with startActivityForResult");
+        }
+        final ApplicationInfo appInfo;
+        try {
+            appInfo = getPackageManager().getApplicationInfo(callingPackage, 0);
+        } catch (NameNotFoundException nnfe) {
+            throw new SecurityException(
+                    "Cannot find the calling package");
+        }
+        final String message;
+        // Check the user restrictions
+        boolean cantCreateUser = mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER)
+                || !mUserManager.isAdminUser();
+        // Check the system state and user count
+        boolean cantCreateAnyMoreUsers = !mUserManager.canAddMoreUsers();
+        // Check the account existence
+        final Account account = new Account(mAccountName, mAccountType);
+        boolean accountExists = mAccountName != null && mAccountType != null
+                && (AccountManager.get(this).someUserHasAccount(account)
+                    | mUserManager.someUserHasSeedAccount(mAccountName, mAccountType));
+        mCanProceed = true;
+        final String appName = appInfo.loadLabel(getPackageManager()).toString();
+        if (cantCreateUser) {
+            setResult(UserManager.USER_CREATION_FAILED_NOT_PERMITTED);
+            return null;
+        } else if (cantCreateAnyMoreUsers) {
+            setResult(UserManager.USER_CREATION_FAILED_NO_MORE_USERS);
+            return null;
+        } else if (accountExists) {
+            message = getString(R.string.user_creation_account_exists, appName, mAccountName);
+        } else {
+            message = getString(R.string.user_creation_adding, appName, mAccountName);
+        }
+        return message;
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        setResult(RESULT_CANCELED);
+        if (which == BUTTON_POSITIVE && mCanProceed) {
+            Log.i(TAG, "Ok, creating user");
+            UserInfo user = mUserManager.createUser(mUserName, 0);
+            if (user == null) {
+                Log.e(TAG, "Couldn't create user");
+                finish();
+                return;
+            }
+            mUserManager.setSeedAccountData(user.id, mAccountName, mAccountType, mAccountOptions);
+            setResult(RESULT_OK);
+        }
+        finish();
+    }
+}
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 3b9b8db..ec53a2e 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -121,4 +121,7 @@
     void setBatteryState(int status, int health, int plugType, int level, int temp, int volt);
     long getAwakeTimeBattery();
     long getAwakeTimePlugged();
+
+    void noteBleScanStarted(in WorkSource ws);
+    void noteBleScanStopped(in WorkSource ws);
 }
diff --git a/core/java/com/android/internal/app/ISoundTriggerService.aidl b/core/java/com/android/internal/app/ISoundTriggerService.aidl
new file mode 100644
index 0000000..9de4a6c
--- /dev/null
+++ b/core/java/com/android/internal/app/ISoundTriggerService.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.SoundTrigger;
+import android.os.ParcelUuid;
+
+/**
+ * Service interface for a generic sound recognition model.
+ * @hide
+ */
+interface ISoundTriggerService {
+
+
+    SoundTrigger.GenericSoundModel getSoundModel(in ParcelUuid soundModelId);
+
+    void updateSoundModel(in SoundTrigger.GenericSoundModel soundModel);
+
+    void deleteSoundModel(in ParcelUuid soundModelId);
+
+    void startRecognition(in ParcelUuid soundModelId, in IRecognitionStatusCallback callback);
+
+    /**
+     * Stops recognition.
+     */
+    void stopRecognition(in ParcelUuid soundModelId, in IRecognitionStatusCallback callback);
+}
diff --git a/core/java/com/android/internal/app/LocaleHelper.java b/core/java/com/android/internal/app/LocaleHelper.java
new file mode 100644
index 0000000..71c2c21
--- /dev/null
+++ b/core/java/com/android/internal/app/LocaleHelper.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.icu.util.ULocale;
+import android.util.LocaleList;
+
+import java.text.Collator;
+import java.util.Comparator;
+import java.util.Locale;
+
+/**
+ * This class implements some handy methods to process with locales.
+ */
+public class LocaleHelper {
+
+    /**
+     * Sentence-case (first character uppercased).
+     *
+     * <p>There is no good API available for this, not even in ICU.
+     * We can revisit this if we get some ICU support later.</p>
+     *
+     * <p>There are currently several tickets requesting this feature:</p>
+     * <ul>
+     * <li>ICU needs to provide an easy way to titlecase only one first letter
+     *   http://bugs.icu-project.org/trac/ticket/11729</li>
+     * <li>Add "initial case"
+     *    http://bugs.icu-project.org/trac/ticket/8394</li>
+     * <li>Add code for initialCase, toTitlecase don't modify after Lt,
+     *   avoid 49Ers, low-level language-specific casing
+     *   http://bugs.icu-project.org/trac/ticket/10410</li>
+     * <li>BreakIterator.getFirstInstance: Often you need to titlecase just the first
+     *   word, and leave the rest of the string alone.  (closed as duplicate)
+     *   http://bugs.icu-project.org/trac/ticket/8946</li>
+     * </ul>
+     *
+     * <p>A (clunky) option with the current ICU API is:</p>
+     * {{
+     *   BreakIterator breakIterator = BreakIterator.getSentenceInstance(locale);
+     *   String result = UCharacter.toTitleCase(locale,
+     *       source, breakIterator, UCharacter.TITLECASE_NO_LOWERCASE);
+     * }}
+     *
+     * <p>That also means creating a BreakIterator for each locale. Expensive...</p>
+     *
+     * @param str the string to sentence-case.
+     * @param locale the locale used for the case conversion.
+     * @return the string converted to sentence-case.
+     */
+    public static String toSentenceCase(String str, Locale locale) {
+        if (str.isEmpty()) {
+            return str;
+        }
+        final int firstCodePointLen = str.offsetByCodePoints(0, 1);
+        return str.substring(0, firstCodePointLen).toUpperCase(locale)
+                + str.substring(firstCodePointLen);
+    }
+
+    /**
+     * Normalizes a string for locale name search. Does case conversion for now,
+     * but might do more in the future.
+     *
+     * <p>Warning: it is only intended to be used in searches by the locale picker.
+     * Don't use it for other things, it is very limited.</p>
+     *
+     * @param str the string to normalize
+     * @param locale the locale that might be used for certain operations (i.e. case conversion)
+     * @return the string normalized for search
+     */
+    public static String normalizeForSearch(String str, Locale locale) {
+        // TODO: tbd if it needs to be smarter (real normalization, remove accents, etc.)
+        // If needed we might use case folding and ICU/CLDR's collation-based loose searching.
+        // TODO: decide what should the locale be, the default locale, or the locale of the string.
+        // Uppercase is better than lowercase because of things like sharp S, Greek sigma, ...
+        return str.toUpperCase();
+    }
+
+    /**
+     * Returns the locale localized for display in the provided locale.
+     *
+     * @param locale the locale whose name is to be displayed.
+     * @param displayLocale the locale in which to display the name.
+     * @param sentenceCase true if the result should be sentence-cased
+     * @return the localized name of the locale.
+     */
+    public static String getDisplayName(Locale locale, Locale displayLocale, boolean sentenceCase) {
+        String result = ULocale.getDisplayName(locale.toLanguageTag(),
+                ULocale.forLocale(displayLocale));
+        return sentenceCase ? toSentenceCase(result, displayLocale) : result;
+    }
+
+    /**
+     * Returns the locale localized for display in the default locale.
+     *
+     * @param locale the locale whose name is to be displayed.
+     * @param sentenceCase true if the result should be sentence-cased
+     * @return the localized name of the locale.
+     */
+    public static String getDisplayName(Locale locale, boolean sentenceCase) {
+        String result = ULocale.getDisplayName(locale.toLanguageTag(), ULocale.getDefault());
+        return sentenceCase ? toSentenceCase(result, Locale.getDefault()) : result;
+    }
+
+    /**
+     * Returns a locale's country localized for display in the provided locale.
+     *
+     * @param locale the locale whose country will be displayed.
+     * @param displayLocale the locale in which to display the name.
+     * @return the localized country name.
+     */
+    public static String getDisplayCountry(Locale locale, Locale displayLocale) {
+        return ULocale.getDisplayCountry(locale.toLanguageTag(), ULocale.forLocale(displayLocale));
+    }
+
+    /**
+     * Returns a locale's country localized for display in the default locale.
+     *
+     * @param locale the locale whose country will be displayed.
+     * @return the localized country name.
+     */
+    public static String getDisplayCountry(Locale locale) {
+        return ULocale.getDisplayCountry(locale.toLanguageTag(), ULocale.getDefault());
+    }
+
+    /**
+     * Returns the locale list localized for display in the provided locale.
+     *
+     * @param locales the list of locales whose names is to be displayed.
+     * @param displayLocale the locale in which to display the names.
+     *                      If this is null, it will use the default locale.
+     * @return the locale aware list of locale names
+     */
+    public static String getDisplayLocaleList(LocaleList locales, Locale displayLocale) {
+        final StringBuilder result = new StringBuilder();
+
+        final Locale dispLocale = displayLocale == null ? Locale.getDefault() : displayLocale;
+        int localeCount = locales.size();
+        for (int i = 0; i < localeCount; i++) {
+            Locale locale = locales.get(i);
+            result.append(LocaleHelper.getDisplayName(locale, dispLocale, false));
+            // TODO: language aware list formatter. ICU has one.
+            if (i < localeCount - 1) {
+                result.append(", ");
+            }
+        }
+
+        return result.toString();
+    }
+
+    /**
+     * Adds the likely subtags for a provided locale ID.
+     *
+     * @param locale the locale to maximize.
+     * @return the maximized Locale instance.
+     */
+    public static Locale addLikelySubtags(Locale locale) {
+        return libcore.icu.ICU.addLikelySubtags(locale);
+    }
+
+    /**
+     * Locale-sensitive comparison for LocaleInfo.
+     *
+     * <p>It uses the label, leaving the decision on what to put there to the LocaleInfo.
+     * For instance fr-CA can be shown as "français" as a generic label in the language selection,
+     * or "français (Canada)" if it is a suggestion, or "Canada" in the country selection.</p>
+     *
+     * <p>Gives priority to suggested locales (to sort them at the top).</p>
+     */
+    public static final class LocaleInfoComparator implements Comparator<LocaleStore.LocaleInfo> {
+        private final Collator mCollator;
+
+        /**
+         * Constructor.
+         *
+         * @param sortLocale the locale to be used for sorting.
+         */
+        public LocaleInfoComparator(Locale sortLocale) {
+            mCollator = Collator.getInstance(sortLocale);
+        }
+
+        /**
+         * Compares its two arguments for order.
+         *
+         * @param lhs   the first object to be compared
+         * @param rhs   the second object to be compared
+         * @return  a negative integer, zero, or a positive integer as the first
+         *          argument is less than, equal to, or greater than the second.
+         */
+        @Override
+        public int compare(LocaleStore.LocaleInfo lhs, LocaleStore.LocaleInfo rhs) {
+            // We don't care about the various suggestion types, just "suggested" (!= 0)
+            // 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());
+            } 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 4efefa9..6a365e0 100644
--- a/core/java/com/android/internal/app/LocalePicker.java
+++ b/core/java/com/android/internal/app/LocalePicker.java
@@ -28,6 +28,7 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.provider.Settings;
+import android.util.LocaleList;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -45,6 +46,7 @@
 public class LocalePicker extends ListFragment {
     private static final String TAG = "LocalePicker";
     private static final boolean DEBUG = false;
+    private static final String[] pseudoLocales = { "en-XA", "ar-XB" };
 
     public static interface LocaleSelectionListener {
         // You can add any argument if you really need it...
@@ -57,7 +59,7 @@
         static final Collator sCollator = Collator.getInstance();
 
         String label;
-        Locale locale;
+        final Locale locale;
 
         public LocaleInfo(String label, Locale locale) {
             this.label = label;
@@ -83,17 +85,30 @@
         }
     }
 
+    public static String[] getSystemAssetLocales() {
+        return Resources.getSystem().getAssets().getLocales();
+    }
+
+    public static String[] getSupportedLocales(Context context) {
+        return context.getResources().getStringArray(R.array.supported_locales);
+    }
+
+    public static String[] getPseudoLocales() {
+        return pseudoLocales;
+    }
+
     public static List<LocaleInfo> getAllAssetLocales(Context context, boolean isInDeveloperMode) {
         final Resources resources = context.getResources();
 
-        final String[] locales = Resources.getSystem().getAssets().getLocales();
+        final String[] locales = getSystemAssetLocales();
         List<String> localeList = new ArrayList<String>(locales.length);
         Collections.addAll(localeList, locales);
 
         // Don't show the pseudolocales unless we're in developer mode. http://b/17190407.
         if (!isInDeveloperMode) {
-            localeList.remove("ar-XB");
-            localeList.remove("en-XA");
+            for (String locale : pseudoLocales) {
+                localeList.remove(locale);
+            }
         }
 
         Collections.sort(localeList);
@@ -240,13 +255,24 @@
     /**
      * Requests the system to update the system locale. Note that the system looks halted
      * for a while during the Locale migration, so the caller need to take care of it.
+     *
+     * @see #updateLocales(LocaleList)
      */
     public static void updateLocale(Locale locale) {
-        try {
-            IActivityManager am = ActivityManagerNative.getDefault();
-            Configuration config = am.getConfiguration();
+        updateLocales(new LocaleList(locale));
+    }
 
-            config.setLocale(locale);
+    /**
+     * Requests the system to update the list of system locales.
+     * Note that the system looks halted for a while during the Locale migration,
+     * so the caller need to take care of it.
+     */
+    public static void updateLocales(LocaleList locales) {
+        try {
+            final IActivityManager am = ActivityManagerNative.getDefault();
+            final Configuration config = am.getConfiguration();
+
+            config.setLocales(locales);
             config.userSetLocale = true;
 
             am.updateConfiguration(config);
@@ -256,4 +282,19 @@
             // Intentionally left blank
         }
     }
+
+    /**
+     * Get the locale list.
+     *
+     * @return The locale list.
+     */
+    public static LocaleList getLocales() {
+        try {
+            return ActivityManagerNative.getDefault()
+                    .getConfiguration().getLocales();
+        } catch (RemoteException e) {
+            // If something went wrong
+            return LocaleList.getDefault();
+        }
+    }
 }
diff --git a/core/java/com/android/internal/app/LocalePickerWithRegion.java b/core/java/com/android/internal/app/LocalePickerWithRegion.java
new file mode 100644
index 0000000..9a17883
--- /dev/null
+++ b/core/java/com/android/internal/app/LocalePickerWithRegion.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.internal.app;
+
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.app.ListFragment;
+import android.content.Context;
+import android.os.Bundle;
+import android.util.LocaleList;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.SearchView;
+
+import com.android.internal.R;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Set;
+
+/**
+ * A two-step locale picker. It shows a language, then a country.
+ *
+ * <p>It shows suggestions at the top, then the rest of the locales.
+ * Allows the user to search for locales using both their native name and their name in the
+ * default locale.</p>
+ */
+public class LocalePickerWithRegion extends ListFragment implements SearchView.OnQueryTextListener {
+
+    private SuggestedLocaleAdapter mAdapter;
+    private LocaleSelectedListener mListener;
+    private Set<LocaleStore.LocaleInfo> mLocaleList;
+    private LocaleStore.LocaleInfo mParentLocale;
+    private boolean mTranslatedOnly = false;
+    private boolean mCountryMode = false;
+
+    /**
+     * Other classes can register to be notified when a locale was selected.
+     *
+     * <p>This is the mechanism to "return" the result of the selection.</p>
+     */
+    public interface LocaleSelectedListener {
+        /**
+         * The classes that want to retrieve the locale picked should implement this method.
+         * @param locale    the locale picked.
+         */
+        void onLocaleSelected(LocaleStore.LocaleInfo locale);
+    }
+
+    private static LocalePickerWithRegion createCountryPicker(Context context,
+            LocaleSelectedListener listener, LocaleStore.LocaleInfo parent,
+            boolean translatedOnly) {
+        LocalePickerWithRegion localePicker = new LocalePickerWithRegion();
+        boolean shouldShowTheList = localePicker.setListener(context, listener, parent,
+                true /* country mode */, 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);
+        return localePicker;
+    }
+
+    /**
+     * Sets the listener and initializes the locale list.
+     *
+     * <p>Returns true if we need to show the list, false if not.</p>
+     *
+     * <p>Can return false because of an error, trying to show a list of countries,
+     * but no parent locale was provided.</p>
+     *
+     * <p>It can also return false if the caller tries to show the list in country mode and
+     * there is only one country available (i.e. Japanese => Japan).
+     * In this case we don't even show the list, we call the listener with that locale,
+     * "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;
+        this.mParentLocale = parent;
+        this.mListener = listener;
+        this.mTranslatedOnly = translatedOnly;
+        setRetainInstance(true);
+
+        final HashSet<String> langTagsToIgnore = new HashSet<>();
+        if (!translatedOnly) {
+            final LocaleList userLocales = LocalePicker.getLocales();
+            final String[] langTags = userLocales.toLanguageTags().split(",");
+            Collections.addAll(langTagsToIgnore, langTags);
+        }
+
+        if (countryMode) {
+            mLocaleList = LocaleStore.getLevelLocales(context,
+                    langTagsToIgnore, parent, translatedOnly);
+            if (mLocaleList.size() <= 1) {
+                if (listener != null && (mLocaleList.size() == 1)) {
+                    listener.onLocaleSelected(mLocaleList.iterator().next());
+                }
+                return false;
+            }
+        } else {
+            mLocaleList = LocaleStore.getLevelLocales(context, langTagsToIgnore,
+                    null /* no parent */, translatedOnly);
+        }
+
+        return true;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setHasOptionsMenu(true);
+
+        Locale sortingLocale;
+        if (mCountryMode) {
+            if (mParentLocale == null) {
+                sortingLocale = Locale.getDefault();
+                this.getActivity().setTitle(R.string.country_selection_title);
+            } else {
+                sortingLocale = mParentLocale.getLocale();
+                this.getActivity().setTitle(mParentLocale.getFullNameNative());
+            }
+        } else {
+            sortingLocale = Locale.getDefault();
+            this.getActivity().setTitle(R.string.language_selection_title);
+        }
+
+        mAdapter = new SuggestedLocaleAdapter(mLocaleList, mCountryMode);
+        LocaleHelper.LocaleInfoComparator comp =
+                new LocaleHelper.LocaleInfoComparator(sortingLocale);
+        mAdapter.sort(comp);
+        setListAdapter(mAdapter);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem menuItem) {
+        int id = menuItem.getItemId();
+        switch (id) {
+            case android.R.id.home:
+                getFragmentManager().popBackStack();
+                return true;
+        }
+        return super.onOptionsItemSelected(menuItem);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        getListView().requestFocus();
+    }
+
+    @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 (mListener != null) {
+                mListener.onLocaleSelected(locale);
+            }
+            getFragmentManager().popBackStack("localeListEditor",
+                    FragmentManager.POP_BACK_STACK_INCLUSIVE);
+        } else {
+            LocalePickerWithRegion selector = LocalePickerWithRegion.createCountryPicker(
+                    getContext(), mListener, locale, mTranslatedOnly /* translate only */);
+            if (selector != null) {
+                getFragmentManager().beginTransaction()
+                        .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
+                        .replace(getId(), selector).addToBackStack(null)
+                        .commit();
+            } else {
+                getFragmentManager().popBackStack("localeListEditor",
+                        FragmentManager.POP_BACK_STACK_INCLUSIVE);
+            }
+        }
+    }
+
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        if (!mCountryMode) {
+            inflater.inflate(R.menu.language_selection_list, menu);
+
+            MenuItem mSearchMenuItem = menu.findItem(R.id.locale_search_menu);
+            SearchView mSearchView = (SearchView) mSearchMenuItem.getActionView();
+
+            mSearchView.setQueryHint(getText(R.string.search_language_hint));
+            mSearchView.setOnQueryTextListener(this);
+            mSearchView.setQuery("", false /* submit */);
+        }
+    }
+
+    @Override
+    public boolean onQueryTextSubmit(String query) {
+        return false;
+    }
+
+    @Override
+    public boolean onQueryTextChange(String newText) {
+        if (mAdapter != null) {
+            mAdapter.getFilter().filter(newText);
+        }
+        return false;
+    }
+}
diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java
new file mode 100644
index 0000000..210adce
--- /dev/null
+++ b/core/java/com/android/internal/app/LocaleStore.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.Context;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IllformedLocaleException;
+import java.util.Locale;
+import java.util.Set;
+
+public class LocaleStore {
+    private static final HashMap<String, LocaleInfo> sLocaleCache = new HashMap<>();
+    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 final Locale mLocale;
+        private final Locale mParent;
+        private final String mId;
+        private boolean mIsTranslated;
+        private boolean mIsPseudo;
+        private boolean mIsChecked; // Used by the LocaleListEditor to mark entries for deletion
+        // Combination of flags for various reasons to show a locale as a suggestion.
+        // Can be SIM, location, etc.
+        private int mSuggestionFlags;
+
+        private String mFullNameNative;
+        private String mFullCountryNameNative;
+        private String mLangScriptKey;
+
+        private LocaleInfo(Locale locale) {
+            this.mLocale = locale;
+            this.mId = locale.toLanguageTag();
+            this.mParent = getParent(locale);
+            this.mIsChecked = false;
+            this.mSuggestionFlags = SUGGESTION_TYPE_NONE;
+            this.mIsTranslated = false;
+            this.mIsPseudo = false;
+        }
+
+        private LocaleInfo(String localeId) {
+            this(Locale.forLanguageTag(localeId));
+        }
+
+        private static Locale getParent(Locale locale) {
+            if (locale.getCountry().isEmpty()) {
+                return null;
+            }
+            return new Locale.Builder()
+                    .setLocale(locale).setRegion("")
+                    .build();
+        }
+
+        @Override
+        public String toString() {
+            return mId;
+        }
+
+        public Locale getLocale() {
+            return mLocale;
+        }
+
+        public Locale getParent() {
+            return mParent;
+        }
+
+        public String getId() {
+            return mId;
+        }
+
+        public boolean isTranslated() {
+            return mIsTranslated;
+        }
+
+        public void setTranslated(boolean isTranslated) {
+            mIsTranslated = isTranslated;
+        }
+
+        /* package */ boolean isSuggested() {
+            if (!mIsTranslated) { // Never suggest an untranslated locale
+                return false;
+            }
+            return mSuggestionFlags != SUGGESTION_TYPE_NONE;
+        }
+
+        private boolean isSuggestionOfType(int suggestionMask) {
+            return (mSuggestionFlags & suggestionMask) == suggestionMask;
+        }
+
+        public String getFullNameNative() {
+            if (mFullNameNative == null) {
+                mFullNameNative =
+                        LocaleHelper.getDisplayName(mLocale, mLocale, true /* sentence case */);
+            }
+            return mFullNameNative;
+        }
+
+        String getFullCountryNameNative() {
+            if (mFullCountryNameNative == null) {
+                mFullCountryNameNative = LocaleHelper.getDisplayCountry(mLocale, mLocale);
+            }
+            return mFullCountryNameNative;
+        }
+
+        /** Returns the name of the locale in the language of the UI.
+         * It is used for search, but never shown.
+         * For instance German will show as "Deutsch" in the list, but we will also search for
+         * "allemand" if the system UI is in French.
+         */
+        public String getFullNameInUiLanguage() {
+            return LocaleHelper.getDisplayName(mLocale, true /* sentence case */);
+        }
+
+        private String getLangScriptKey() {
+            if (mLangScriptKey == null) {
+                Locale parentWithScript = getParent(LocaleHelper.addLikelySubtags(mLocale));
+                mLangScriptKey =
+                        (parentWithScript == null)
+                        ? mLocale.toLanguageTag()
+                        : parentWithScript.toLanguageTag();
+            }
+            return mLangScriptKey;
+        }
+
+        String getLabel() {
+            if (getParent() == null || this.isSuggestionOfType(SUGGESTION_TYPE_SIM)) {
+                return getFullNameNative();
+            } else {
+                return getFullCountryNameNative();
+            }
+        }
+
+        public boolean getChecked() {
+            return mIsChecked;
+        }
+
+        public void setChecked(boolean checked) {
+            mIsChecked = checked;
+        }
+    }
+
+    private static Set<String> getSimCountries(Context context) {
+        Set<String> result = new HashSet<>();
+
+        TelephonyManager tm = TelephonyManager.from(context);
+
+        if (tm != null) {
+            String iso = tm.getSimCountryIso().toUpperCase(Locale.US);
+            if (!iso.isEmpty()) {
+                result.add(iso);
+            }
+
+            iso = tm.getNetworkCountryIso().toUpperCase(Locale.US);
+            if (!iso.isEmpty()) {
+                result.add(iso);
+            }
+        }
+
+        return result;
+    }
+
+    /*
+     * This method is added for SetupWizard, to force an update of the suggested locales
+     * when the SIM is initialized.
+     *
+     * <p>When the device is freshly started, it sometimes gets to the language selection
+     * before the SIM is properly initialized.
+     * So at the time the cache is filled, the info from the SIM might not be available.
+     * The SetupWizard has a SimLocaleMonitor class to detect onSubscriptionsChanged events.
+     * SetupWizard will call this function when that happens.</p>
+     *
+     * <p>TODO: decide if it is worth moving such kind of monitoring in this shared code.
+     * The user might change the SIM or might cross border and connect to a network
+     * in a different country, without restarting the Settings application or the phone.</p>
+     */
+    public static void updateSimCountries(Context context) {
+        Set<String> simCountries = getSimCountries(context);
+
+        for (LocaleInfo li : sLocaleCache.values()) {
+            // This method sets the suggestion flags for the (new) SIM locales, but it does not
+            // try to clean up the old flags. After all, if the user replaces a German SIM
+            // with a French one, it is still possible that they are speaking German.
+            // So both French and German are reasonable suggestions.
+            if (simCountries.contains(li.getLocale().getCountry())) {
+                li.mSuggestionFlags |= LocaleInfo.SUGGESTION_TYPE_SIM;
+            }
+        }
+    }
+
+    public static void fillCache(Context context) {
+        if (sFullyInitialized) {
+            return;
+        }
+
+        Set<String> simCountries = getSimCountries(context);
+
+        for (String localeId : LocalePicker.getSupportedLocales(context)) {
+            if (localeId.isEmpty()) {
+                throw new IllformedLocaleException("Bad locale entry in locale_config.xml");
+            }
+            LocaleInfo li = new LocaleInfo(localeId);
+            if (simCountries.contains(li.getLocale().getCountry())) {
+                li.mSuggestionFlags |= LocaleInfo.SUGGESTION_TYPE_SIM;
+            }
+            sLocaleCache.put(li.getId(), li);
+            final Locale parent = li.getParent();
+            if (parent != null) {
+                String parentId = parent.toLanguageTag();
+                if (!sLocaleCache.containsKey(parentId)) {
+                    sLocaleCache.put(parentId, new LocaleInfo(parent));
+                }
+            }
+        }
+
+        boolean isInDeveloperMode = Settings.Global.getInt(context.getContentResolver(),
+                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
+        for (String localeId : LocalePicker.getPseudoLocales()) {
+            LocaleInfo li = getLocaleInfo(Locale.forLanguageTag(localeId));
+            if (isInDeveloperMode) {
+                li.setTranslated(true);
+                li.mIsPseudo = true;
+                li.mSuggestionFlags |= LocaleInfo.SUGGESTION_TYPE_SIM;
+            } else {
+                sLocaleCache.remove(li.getId());
+            }
+        }
+
+        // TODO: See if we can reuse what LocaleList.matchScore does
+        final HashSet<String> localizedLocales = new HashSet<>();
+        for (String localeId : LocalePicker.getSystemAssetLocales()) {
+            LocaleInfo li = new LocaleInfo(localeId);
+            localizedLocales.add(li.getLangScriptKey());
+        }
+
+        for (LocaleInfo li : sLocaleCache.values()) {
+            li.setTranslated(localizedLocales.contains(li.getLangScriptKey()));
+        }
+
+        sFullyInitialized = true;
+    }
+
+    private static int getLevel(Set<String> ignorables, LocaleInfo li, boolean translatedOnly) {
+        if (ignorables.contains(li.getId())) return 0;
+        if (li.mIsPseudo) return 2;
+        if (translatedOnly && !li.isTranslated()) return 0;
+        if (li.getParent() != null) return 2;
+        return 0;
+    }
+
+    /**
+     * Returns a list of locales for language or region selection.
+     * If the parent is null, then it is the language list.
+     * If it is not null, then the list will contain all the locales that belong to that parent.
+     * Example: if the parent is "ar", then the region list will contain all Arabic locales.
+     * (this is not language based, but language-script, so that it works for zh-Hant and so on.
+     */
+    public static Set<LocaleInfo> getLevelLocales(Context context, Set<String> ignorables,
+            LocaleInfo parent, boolean translatedOnly) {
+        fillCache(context);
+        String parentId = parent == null ? null : parent.getId();
+
+        HashSet<LocaleInfo> result = new HashSet<>();
+        for (LocaleStore.LocaleInfo li : sLocaleCache.values()) {
+            int level = getLevel(ignorables, li, translatedOnly);
+            if (level == 2) {
+                if (parent != null) { // region selection
+                    if (parentId.equals(li.getParent().toLanguageTag())) {
+                        if (!li.isSuggestionOfType(LocaleInfo.SUGGESTION_TYPE_SIM)) {
+                            result.add(li);
+                        }
+                    }
+                } else { // language selection
+                    if (li.isSuggestionOfType(LocaleInfo.SUGGESTION_TYPE_SIM)) {
+                        result.add(li);
+                    } else {
+                        result.add(getLocaleInfo(li.getParent()));
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    public static LocaleInfo getLocaleInfo(Locale locale) {
+        String id = locale.toLanguageTag();
+        LocaleInfo result;
+        if (!sLocaleCache.containsKey(id)) {
+            result = new LocaleInfo(locale);
+            sLocaleCache.put(id, result);
+        } else {
+            result = sLocaleCache.get(id);
+        }
+        return result;
+    }
+}
diff --git a/core/java/com/android/internal/app/NetInitiatedActivity.java b/core/java/com/android/internal/app/NetInitiatedActivity.java
index b951f50e..d3bae16 100644
--- a/core/java/com/android/internal/app/NetInitiatedActivity.java
+++ b/core/java/com/android/internal/app/NetInitiatedActivity.java
@@ -133,7 +133,7 @@
         notificationId = -1;
     }
 
-    // Respond to NI Handler under GpsLocationProvider, 1 = accept, 2 = deny
+    // Respond to NI Handler under GnssLocationProvider, 1 = accept, 2 = deny
     private void sendUserResponse(int response) {
         if (DEBUG) Log.d(TAG, "sendUserResponse, response: " + response);
         LocationManager locationManager = (LocationManager)
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index ba0912a..ec148c55 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -718,9 +718,9 @@
 
                     if (ri.handleAllWebDataURI) {
                         // Set default Browser if needed
-                        final String packageName = pm.getDefaultBrowserPackageName(userId);
+                        final String packageName = pm.getDefaultBrowserPackageNameAsUser(userId);
                         if (TextUtils.isEmpty(packageName)) {
-                            pm.setDefaultBrowserPackageName(ri.activityInfo.packageName, userId);
+                            pm.setDefaultBrowserPackageNameAsUser(ri.activityInfo.packageName, userId);
                         }
                     } else {
                         // Update Domain Verification status
@@ -737,7 +737,7 @@
                                 categories.contains(Intent.CATEGORY_BROWSABLE);
 
                         if (isHttpOrHttps && isViewAction && hasCategoryBrowsable) {
-                            pm.updateIntentVerificationStatus(packageName,
+                            pm.updateIntentVerificationStatusAsUser(packageName,
                                     PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS,
                                     userId);
                         }
@@ -1231,7 +1231,9 @@
                 }
 
                 // Filter out any activities that the launched uid does not
-                // have permission for.  We don't do this when we have an explicit
+                // have permission for.
+                // Also filter out those that are suspended because they couldn't
+                // be started. We don't do this when we have an explicit
                 // list of resolved activities, because that only happens when
                 // we are being subclassed, so we can safely launch whatever
                 // they gave us.
@@ -1242,7 +1244,9 @@
                         int granted = ActivityManager.checkComponentPermission(
                                 ai.permission, mLaunchedFromUid,
                                 ai.applicationInfo.uid, ai.exported);
-                        if (granted != PackageManager.PERMISSION_GRANTED) {
+                        boolean suspended = (ai.applicationInfo.flags
+                                & ApplicationInfo.FLAG_SUSPENDED) != 0;
+                        if (granted != PackageManager.PERMISSION_GRANTED || suspended) {
                             // Access not allowed!
                             if (mOrigResolveList == currentResolveList) {
                                 mOrigResolveList = new ArrayList<>(mOrigResolveList);
diff --git a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
new file mode 100644
index 0000000..c4ec714
--- /dev/null
+++ b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+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;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Locale;
+import java.util.Set;
+
+
+/**
+ * This adapter wraps around a regular ListAdapter for LocaleInfo, and creates 2 sections.
+ *
+ * <p>The first section contains "suggested" languages (usually including a region),
+ * the second section contains all the languages within the original adapter.
+ * The "others" might still include languages that appear in the "suggested" section.</p>
+ *
+ * <p>Example: if we show "German Switzerland" as "suggested" (based on SIM, let's say),
+ * then "German" will still show in the "others" section, clicking on it will only show the
+ * countries for all the other German locales, but not Switzerland
+ * (Austria, Belgium, Germany, Liechtenstein, Luxembourg)</p>
+ */
+public class SuggestedLocaleAdapter extends BaseAdapter implements Filterable {
+    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 ArrayList<LocaleStore.LocaleInfo> mLocaleOptions;
+    private ArrayList<LocaleStore.LocaleInfo> mOriginalLocaleOptions;
+    private int mSuggestionCount;
+    private final boolean mCountryMode;
+    private LayoutInflater mInflater;
+
+    public SuggestedLocaleAdapter(Set<LocaleStore.LocaleInfo> localeOptions, boolean countryMode) {
+        mCountryMode = countryMode;
+        mLocaleOptions = new ArrayList<>(localeOptions.size());
+        for (LocaleStore.LocaleInfo li : localeOptions) {
+            if (li.isSuggested()) {
+                mSuggestionCount++;
+            }
+            mLocaleOptions.add(li);
+        }
+    }
+
+    @Override
+    public boolean areAllItemsEnabled() {
+        return false;
+    }
+
+    @Override
+    public boolean isEnabled(int position) {
+        return getItemViewType(position) == TYPE_LOCALE;
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        if (!showHeaders()) {
+            return TYPE_LOCALE;
+        } else {
+            if (position == 0) {
+                return TYPE_HEADER_SUGGESTED;
+            }
+            if (position == mSuggestionCount + 1) {
+                return TYPE_HEADER_ALL_OTHERS;
+            }
+            return TYPE_LOCALE;
+        }
+    }
+
+    @Override
+    public int getViewTypeCount() {
+        if (showHeaders()) {
+            return 3; // Two headers in addition to the locales
+        } else {
+            return 1; // Locales items only
+        }
+    }
+
+    @Override
+    public int getCount() {
+        if (showHeaders()) {
+            return mLocaleOptions.size() + 2; // 2 extra for the headers
+        } else {
+            return mLocaleOptions.size();
+        }
+    }
+
+    @Override
+    public Object getItem(int position) {
+        int offset = 0;
+        if (showHeaders()) {
+            offset = position > mSuggestionCount ? -2 : -1;
+        }
+
+        return mLocaleOptions.get(position + offset);
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return position;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        if (convertView == null && mInflater == null) {
+            mInflater = LayoutInflater.from(parent.getContext());
+        }
+
+        int itemType = getItemViewType(position);
+        switch (itemType) {
+            case TYPE_HEADER_SUGGESTED: // intentional fallthrough
+            case TYPE_HEADER_ALL_OTHERS:
+                // Covers both null, and "reusing" a wrong kind of view
+                if (!(convertView instanceof TextView)) {
+                    convertView = mInflater.inflate(R.layout.language_picker_section_header,
+                            parent, false);
+                }
+                TextView textView = (TextView) convertView;
+                if (itemType == TYPE_HEADER_SUGGESTED) {
+                    textView.setText(R.string.language_picker_section_suggested);
+                } else {
+                    textView.setText(R.string.language_picker_section_all);
+                }
+                textView.setTextLocale(Locale.getDefault());
+                break;
+            default:
+                // Covers both null, and "reusing" a wrong kind of view
+                if (!(convertView instanceof ViewGroup)) {
+                    convertView = mInflater.inflate(R.layout.language_picker_item, parent, false);
+                }
+
+                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());
+                }
+        }
+        return convertView;
+    }
+
+    private boolean showHeaders() {
+        return mSuggestionCount != 0 && mSuggestionCount != mLocaleOptions.size();
+    }
+
+    /**
+     * Sorts the items in the adapter using a locale-aware comparator.
+     * @param comp The locale-aware comparator to use.
+     */
+    public void sort(LocaleHelper.LocaleInfoComparator comp) {
+        Collections.sort(mLocaleOptions, comp);
+    }
+
+    class FilterByNativeAndUiNames extends Filter {
+
+        @Override
+        protected FilterResults performFiltering(CharSequence prefix) {
+            FilterResults results = new FilterResults();
+
+            if (mOriginalLocaleOptions == null) {
+                mOriginalLocaleOptions = new ArrayList<>(mLocaleOptions);
+            }
+
+            ArrayList<LocaleStore.LocaleInfo> values;
+            values = new ArrayList<>(mOriginalLocaleOptions);
+            if (prefix == null || prefix.length() == 0) {
+                results.values = values;
+                results.count = values.size();
+            } else {
+                // TODO: decide if we should use the string's locale
+                Locale locale = Locale.getDefault();
+                String prefixString = LocaleHelper.normalizeForSearch(prefix.toString(), locale);
+
+                final int count = values.size();
+                final ArrayList<LocaleStore.LocaleInfo> newValues = new ArrayList<>();
+
+                for (int i = 0; i < count; i++) {
+                    final LocaleStore.LocaleInfo value = values.get(i);
+                    final String nameToCheck = LocaleHelper.normalizeForSearch(
+                            value.getFullNameInUiLanguage(), locale);
+                    final String nativeNameToCheck = LocaleHelper.normalizeForSearch(
+                            value.getFullNameNative(), locale);
+                    if (wordMatches(nativeNameToCheck, prefixString)
+                            || wordMatches(nameToCheck, prefixString)) {
+                        newValues.add(value);
+                    }
+                }
+
+                results.values = newValues;
+                results.count = newValues.size();
+            }
+
+            return results;
+        }
+
+        // TODO: decide if this is enough, or we want to use a BreakIterator...
+        boolean wordMatches(String valueText, String prefixString) {
+            // First match against the whole, non-split value
+            if (valueText.startsWith(prefixString)) {
+                return true;
+            }
+
+            final String[] words = valueText.split(" ");
+            // Start at index 0, in case valueText starts with space(s)
+            for (String word : words) {
+                if (word.startsWith(prefixString)) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        @Override
+        protected void publishResults(CharSequence constraint, FilterResults results) {
+            mLocaleOptions = (ArrayList<LocaleStore.LocaleInfo>) results.values;
+
+            mSuggestionCount = 0;
+            for (LocaleStore.LocaleInfo li : mLocaleOptions) {
+                if (li.isSuggested()) {
+                    mSuggestionCount++;
+                }
+            }
+
+            if (results.count > 0) {
+                notifyDataSetChanged();
+            } else {
+                notifyDataSetInvalidated();
+            }
+        }
+    }
+
+    @Override
+    public Filter getFilter() {
+        return new FilterByNativeAndUiNames();
+    }
+}
diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java
index 9d12803..575ef02 100644
--- a/core/java/com/android/internal/app/ToolbarActionBar.java
+++ b/core/java/com/android/internal/app/ToolbarActionBar.java
@@ -29,10 +29,14 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
+import android.view.View.OnFocusChangeListener;
+import android.view.ViewGroup;
+import android.view.ViewParent;
 import android.view.Window;
 import android.view.WindowCallbackWrapper;
 import android.widget.SpinnerAdapter;
 import android.widget.Toolbar;
+
 import com.android.internal.view.menu.MenuBuilder;
 import com.android.internal.view.menu.MenuPresenter;
 import com.android.internal.widget.DecorToolbar;
@@ -479,6 +483,12 @@
         return true;
     }
 
+    @Override
+    public void onDestroy() {
+        // Remove any invalidation callbacks
+        mDecorToolbar.getViewGroup().removeCallbacks(mMenuInvalidator);
+    }
+
     public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
         mMenuVisibilityListeners.add(listener);
     }
@@ -499,6 +509,12 @@
         }
     }
 
+    /** @hide */
+    @Override
+    public boolean requestFocus() {
+        return requestFocus(mDecorToolbar.getViewGroup());
+    }
+
     private class ToolbarCallbackWrapper extends WindowCallbackWrapper {
         public ToolbarCallbackWrapper(Window.Callback wrapped) {
             super(wrapped);
diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
new file mode 100644
index 0000000..aada6e3
--- /dev/null
+++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.internal.R;
+
+/**
+ * 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.
+ */
+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;
+    private int mReason;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Intent intent = getIntent();
+        mReason = intent.getIntExtra(EXTRA_UNLAUNCHABLE_REASON, -1);
+        mUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+
+        if (mUserId == UserHandle.USER_NULL) {
+            Log.wtf(TAG, "Invalid user id: " + mUserId + ". Stopping.");
+            finish();
+            return;
+        }
+
+        String dialogTitle;
+        String dialogMessage;
+        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) {
+            PackageManager pm = getPackageManager();
+            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);
+            dialogMessage = dpm.getShortSupportMessageForUser(dpm.getProfileOwnerAsUser(mUserId),
+                    mUserId);
+            if (dialogMessage == null) {
+                dialogMessage = String.format(
+                        getResources().getString(R.string.suspended_package_message),
+                        dpm.getProfileOwnerNameAsUser(mUserId));
+            }
+        } else {
+            Log.wtf(TAG, "Invalid unlaunchable type: " + mReason);
+            finish();
+            return;
+        }
+
+        View rootView = LayoutInflater.from(this).inflate(R.layout.unlaunchable_app_activity, null);
+        TextView titleView = (TextView)rootView.findViewById(R.id.unlaunchable_app_title);
+        TextView messageView = (TextView)rootView.findViewById(R.id.unlaunchable_app_message);
+        titleView.setText(dialogTitle);
+        messageView.setText(dialogMessage);
+
+        AlertDialog.Builder builder = new AlertDialog.Builder(this)
+                .setView(rootView)
+                .setOnDismissListener(this);
+        if (mReason == UNLAUNCHABLE_REASON_QUIET_MODE) {
+            builder.setPositiveButton(R.string.work_mode_turn_on, this)
+                    .setNegativeButton(R.string.cancel, null);
+        } else {
+            builder.setPositiveButton(R.string.ok, null);
+        }
+        builder.show();
+    }
+
+    @Override
+    public void onDismiss(DialogInterface dialog) {
+        finish();
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        if (mReason == UNLAUNCHABLE_REASON_QUIET_MODE && which == DialogInterface.BUTTON_POSITIVE) {
+            UserManager.get(this).setQuietModeEnabled(mUserId, false);
+        }
+    }
+
+    private static final Intent createBaseIntent() {
+        Intent intent = new Intent();
+        intent.setComponent(new ComponentName("android", UnlaunchableAppActivity.class.getName()));
+        intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+        return intent;
+    }
+
+    public static Intent createInQuietModeDialogIntent(int userId) {
+        Intent intent = createBaseIntent();
+        intent.putExtra(EXTRA_UNLAUNCHABLE_REASON, UNLAUNCHABLE_REASON_QUIET_MODE);
+        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/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java
index 05cfd81..c6bf1b4 100644
--- a/core/java/com/android/internal/app/WindowDecorActionBar.java
+++ b/core/java/com/android/internal/app/WindowDecorActionBar.java
@@ -18,6 +18,8 @@
 
 import android.animation.ValueAnimator;
 import android.content.res.TypedArray;
+import android.view.View.OnFocusChangeListener;
+import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.widget.Toolbar;
 
@@ -950,6 +952,12 @@
         return false;
     }
 
+    /** @hide */
+    @Override
+    public boolean requestFocus() {
+        return requestFocus(mDecorToolbar.getViewGroup());
+    }
+
     /**
      * @hide
      */
diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl
index 083d6c7..98f5bea 100644
--- a/core/java/com/android/internal/backup/IBackupTransport.aidl
+++ b/core/java/com/android/internal/backup/IBackupTransport.aidl
@@ -133,19 +133,16 @@
      *
      * @param packageInfo The identity of the application whose data is being backed up.
      *   This specifically includes the signature list for the package.
-     * @param data The data stream that resulted from invoking the application's
+     * @param inFd Descriptor of file with data that resulted from invoking the application's
      *   BackupService.doBackup() method.  This may be a pipe rather than a file on
      *   persistent media, so it may not be seekable.
-     * @param wipeAllFirst When true, <i>all</i> backed-up data for the current device/account
-     *   will be erased prior to the storage of the data provided here.  The purpose of this
-     *   is to provide a guarantee that no stale data exists in the restore set when the
-     *   device begins providing backups.
+     * @param flags Some of {@link BackupTransport#FLAG_USER_INITIATED}.
      * @return one of {@link BackupConstants#TRANSPORT_OK} (OK so far),
      *  {@link BackupConstants#TRANSPORT_ERROR} (on network error or other failure), or
      *  {@link BackupConstants#TRANSPORT_NOT_INITIALIZED} (if the backend dataset has
      *  become lost due to inactive expiry or some other reason and needs re-initializing)
      */
-    int performBackup(in PackageInfo packageInfo, in ParcelFileDescriptor inFd);
+    int performBackup(in PackageInfo packageInfo, in ParcelFileDescriptor inFd, int flags);
 
     /**
      * Erase the give application's data from the backup destination.  This clears
@@ -237,11 +234,31 @@
     // full backup stuff
 
     long requestFullBackupTime();
-    int performFullBackup(in PackageInfo targetPackage, in ParcelFileDescriptor socket);
+    int performFullBackup(in PackageInfo targetPackage, in ParcelFileDescriptor socket, int flags);
     int checkFullBackupSize(long size);
     int sendBackupData(int numBytes);
     void cancelFullBackup();
 
+    /**
+     * Ask the transport whether this app is eligible for backup.
+     *
+     * @param targetPackage The identity of the application.
+     * @param isFullBackup If set, transport should check if app is eligible for full data backup,
+     *   otherwise to check if eligible for key-value backup.
+     * @return Whether this app is eligible for backup.
+     */
+    boolean isAppEligibleForBackup(in PackageInfo targetPackage, boolean isFullBackup);
+
+    /**
+     * Ask the transport about current quota for backup size of the package.
+     *
+     * @param packageName ID of package to provide the quota.
+     * @param isFullBackup If set, transport should return limit for full data backup, otherwise
+     *                     for key-value backup.
+     * @return Current limit on full data backup size in bytes.
+     */
+    long getBackupQuota(String packageName, boolean isFullBackup);
+
     // full restore stuff
 
     /**
@@ -289,5 +306,4 @@
      *    operation will immediately be finished with no further attempts to restore app data.
      */
     int abortFullRestore();
-
 }
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 22d35f2..8cdfc64 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -71,6 +71,9 @@
     // The currently-active restore set always has the same (nonzero!) token
     private static final long CURRENT_SET_TOKEN = 1;
 
+    // Full backup size quota is set to reasonable value.
+    private static final long FULL_BACKUP_SIZE_QUOTA = 25 * 1024 * 1024;
+
     private Context mContext;
     private File mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup");
     private File mCurrentSetDir = new File(mDataDir, Long.toString(CURRENT_SET_TOKEN));
@@ -90,6 +93,7 @@
     private FileInputStream mSocketInputStream;
     private BufferedOutputStream mFullBackupOutputStream;
     private byte[] mFullBackupBuffer;
+    private long mFullBackupSize;
 
     private FileInputStream mCurFullRestoreStream;
     private FileOutputStream mFullRestoreSocketStream;
@@ -314,8 +318,13 @@
 
     @Override
     public int checkFullBackupSize(long size) {
+        int result = TRANSPORT_OK;
         // Decline zero-size "backups"
-        final int result = (size > 0) ? TRANSPORT_OK : TRANSPORT_PACKAGE_REJECTED;
+        if (size <= 0) {
+            result = TRANSPORT_PACKAGE_REJECTED;
+        } else if (size > FULL_BACKUP_SIZE_QUOTA) {
+            result = TRANSPORT_QUOTA_EXCEEDED;
+        }
         if (result != TRANSPORT_OK) {
             if (DEBUG) {
                 Log.v(TAG, "Declining backup of size " + size);
@@ -339,6 +348,7 @@
         // sure to dup() our own copy of the socket fd.  Transports which run in
         // their own processes must not do this.
         try {
+            mFullBackupSize = 0;
             mSocket = ParcelFileDescriptor.dup(socket.getFileDescriptor());
             mSocketInputStream = new FileInputStream(mSocket.getFileDescriptor());
         } catch (IOException e) {
@@ -359,6 +369,11 @@
             return TRANSPORT_ERROR;
         }
 
+        mFullBackupSize += numBytes;
+        if (mFullBackupSize > FULL_BACKUP_SIZE_QUOTA) {
+            return TRANSPORT_QUOTA_EXCEEDED;
+        }
+
         if (numBytes > mFullBackupBuffer.length) {
             mFullBackupBuffer = new byte[numBytes];
         }
@@ -699,4 +714,8 @@
         return TRANSPORT_OK;
     }
 
+    @Override
+    public long getBackupQuota(String packageName, boolean isFullBackup) {
+        return isFullBackup ? FULL_BACKUP_SIZE_QUOTA : Long.MAX_VALUE;
+    }
 }
diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java
index 481ab0e..c0dce22 100644
--- a/core/java/com/android/internal/content/PackageMonitor.java
+++ b/core/java/com/android/internal/content/PackageMonitor.java
@@ -47,6 +47,8 @@
         sPackageFilt.addDataScheme("package");
         sNonDataFilt.addAction(Intent.ACTION_UID_REMOVED);
         sNonDataFilt.addAction(Intent.ACTION_USER_STOPPED);
+        sNonDataFilt.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
+        sNonDataFilt.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
         sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
         sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
     }
@@ -185,7 +187,13 @@
     
     public void onPackagesUnavailable(String[] packages) {
     }
-    
+
+    public void onPackagesSuspended(String[] packages) {
+    }
+
+    public void onPackagesUnsuspended(String[] packages) {
+    }
+
     public static final int PACKAGE_UNCHANGED = 0;
     public static final int PACKAGE_UPDATING = 1;
     public static final int PACKAGE_TEMPORARY_CHANGE = 2;
@@ -396,8 +404,16 @@
                     onPackageDisappeared(pkgList[i], mChangeType);
                 }
             }
+        } else if (Intent.ACTION_PACKAGES_SUSPENDED.equals(action)) {
+            String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+            mSomePackagesChanged = true;
+            onPackagesSuspended(pkgList);
+        } else if (Intent.ACTION_PACKAGES_UNSUSPENDED.equals(action)) {
+            String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+            mSomePackagesChanged = true;
+            onPackagesUnsuspended(pkgList);
         }
-        
+
         if (mSomePackagesChanged) {
             onSomePackagesChanged();
         }
diff --git a/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java b/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java
new file mode 100644
index 0000000..975021e8
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.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 com.android.internal.inputmethod;
+
+import android.text.TextUtils;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
+
+import java.util.Objects;
+
+public class InputMethodSubtypeHandle {
+    private final String mInputMethodId;
+    private final int mSubtypeId;
+
+    public InputMethodSubtypeHandle(InputMethodInfo info, InputMethodSubtype subtype) {
+        mInputMethodId = info.getId();
+        if (subtype != null) {
+            mSubtypeId = subtype.hashCode();
+        } else {
+            mSubtypeId = 0;
+        }
+    }
+
+    public InputMethodSubtypeHandle(String inputMethodId, int subtypeId) {
+        mInputMethodId = inputMethodId;
+        mSubtypeId = subtypeId;
+    }
+
+    public String getInputMethodId() {
+        return mInputMethodId;
+    }
+
+    public int getSubtypeId() {
+        return mSubtypeId;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof InputMethodSubtypeHandle)) {
+            return false;
+        }
+        InputMethodSubtypeHandle other = (InputMethodSubtypeHandle) o;
+        return TextUtils.equals(mInputMethodId, other.getInputMethodId())
+                && mSubtypeId == other.getSubtypeId();
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(mInputMethodId) * 31 + mSubtypeId;
+    }
+
+    @Override
+    public String toString() {
+        return "InputMethodSubtypeHandle{mInputMethodId=" + mInputMethodId
+            + ", mSubtypeId=" + mSubtypeId + "}";
+    }
+}
diff --git a/core/java/com/android/internal/logging/MetricsConstants.java b/core/java/com/android/internal/logging/MetricsConstants.java
deleted file mode 100644
index 37bf71c..0000000
--- a/core/java/com/android/internal/logging/MetricsConstants.java
+++ /dev/null
@@ -1,291 +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.internal.logging;
-
-/**
- * Constants for mestrics logs.
- *
- * @hide
- */
-public interface MetricsConstants {
-    // These constants must match those in the analytic pipeline, do not edit.
-    // Add temporary values to the top of MetricsLogger instead.
-    public static final int VIEW_UNKNOWN = 0;
-    public static final int MAIN_SETTINGS = 1;
-    public static final int ACCESSIBILITY = 2;
-    public static final int ACCESSIBILITY_CAPTION_PROPERTIES = 3;
-    public static final int ACCESSIBILITY_SERVICE = 4;
-    public static final int ACCESSIBILITY_TOGGLE_DALTONIZER = 5;
-    public static final int ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE = 6;
-    public static final int ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION = 7;
-    public static final int ACCOUNT = 8;
-    public static final int ACCOUNTS_ACCOUNT_SYNC = 9;
-    public static final int ACCOUNTS_CHOOSE_ACCOUNT_ACTIVITY = 10;
-    public static final int ACCOUNTS_MANAGE_ACCOUNTS = 11;
-    public static final int APN = 12;
-    public static final int APN_EDITOR = 13;
-    public static final int APP_OPS_DETAILS = 14;
-    public static final int APP_OPS_SUMMARY = 15;
-    public static final int APPLICATION = 16;
-    public static final int APPLICATIONS_APP_LAUNCH = 17;
-    public static final int APPLICATIONS_APP_PERMISSION = 18;
-    public static final int APPLICATIONS_APP_STORAGE = 19;
-    public static final int APPLICATIONS_INSTALLED_APP_DETAILS = 20;
-    public static final int APPLICATIONS_PROCESS_STATS_DETAIL = 21;
-    public static final int APPLICATIONS_PROCESS_STATS_MEM_DETAIL = 22;
-    public static final int APPLICATIONS_PROCESS_STATS_UI = 23;
-    public static final int BLUETOOTH = 24;
-    public static final int BLUETOOTH_DEVICE_PICKER = 25;
-    public static final int BLUETOOTH_DEVICE_PROFILES = 26;
-    public static final int CHOOSE_LOCK_GENERIC = 27;
-    public static final int CHOOSE_LOCK_PASSWORD = 28;
-    public static final int CHOOSE_LOCK_PATTERN = 29;
-    public static final int CONFIRM_LOCK_PASSWORD = 30;
-    public static final int CONFIRM_LOCK_PATTERN = 31;
-    public static final int CRYPT_KEEPER = 32;
-    public static final int CRYPT_KEEPER_CONFIRM = 33;
-    public static final int DASHBOARD_SEARCH_RESULTS = 34;
-    public static final int DASHBOARD_SUMMARY = 35;
-    public static final int DATA_USAGE = 36;
-    public static final int DATA_USAGE_SUMMARY = 37;
-    public static final int DATE_TIME = 38;
-    public static final int DEVELOPMENT = 39;
-    public static final int DEVICEINFO = 40;
-    public static final int DEVICEINFO_IMEI_INFORMATION = 41;
-    public static final int DEVICEINFO_MEMORY = 42;
-    public static final int DEVICEINFO_SIM_STATUS = 43;
-    public static final int DEVICEINFO_STATUS = 44;
-    public static final int DEVICEINFO_USB = 45;
-    public static final int DISPLAY = 46;
-    public static final int DREAM = 47;
-    public static final int ENCRYPTION = 48;
-    public static final int FINGERPRINT = 49;
-    public static final int FINGERPRINT_ENROLL = 50;
-    public static final int FUELGAUGE_BATTERY_HISTORY_DETAIL = 51;
-    public static final int FUELGAUGE_BATTERY_SAVER = 52;
-    public static final int FUELGAUGE_POWER_USAGE_DETAIL = 53;
-    public static final int FUELGAUGE_POWER_USAGE_SUMMARY = 54;
-    public static final int HOME = 55;
-    public static final int ICC_LOCK = 56;
-    public static final int INPUTMETHOD_LANGUAGE = 57;
-    public static final int INPUTMETHOD_KEYBOARD = 58;
-    public static final int INPUTMETHOD_SPELL_CHECKERS = 59;
-    public static final int INPUTMETHOD_SUBTYPE_ENABLER = 60;
-    public static final int INPUTMETHOD_USER_DICTIONARY = 61;
-    public static final int INPUTMETHOD_USER_DICTIONARY_ADD_WORD = 62;
-    public static final int LOCATION = 63;
-    public static final int LOCATION_MODE = 64;
-    public static final int MANAGE_APPLICATIONS = 65;
-    public static final int MASTER_CLEAR = 66;
-    public static final int MASTER_CLEAR_CONFIRM = 67;
-    public static final int NET_DATA_USAGE_METERED = 68;
-    public static final int NFC_BEAM = 69;
-    public static final int NFC_PAYMENT = 70;
-    public static final int NOTIFICATION = 71;
-    public static final int NOTIFICATION_APP_NOTIFICATION = 72;
-    public static final int NOTIFICATION_OTHER_SOUND = 73;
-    public static final int NOTIFICATION_REDACTION = 74;
-    public static final int NOTIFICATION_STATION = 75;
-    public static final int NOTIFICATION_ZEN_MODE = 76;
-    public static final int OWNER_INFO = 77;
-    public static final int PRINT_JOB_SETTINGS = 78;
-    public static final int PRINT_SERVICE_SETTINGS = 79;
-    public static final int PRINT_SETTINGS = 80;
-    public static final int PRIVACY = 81;
-    public static final int PROXY_SELECTOR = 82;
-    public static final int RESET_NETWORK = 83;
-    public static final int RESET_NETWORK_CONFIRM = 84;
-    public static final int RUNNING_SERVICE_DETAILS = 85;
-    public static final int SCREEN_PINNING = 86;
-    public static final int SECURITY = 87;
-    public static final int SIM = 88;
-    public static final int TESTING = 89;
-    public static final int TETHER = 90;
-    public static final int TRUST_AGENT = 91;
-    public static final int TRUSTED_CREDENTIALS = 92;
-    public static final int TTS_ENGINE_SETTINGS = 93;
-    public static final int TTS_TEXT_TO_SPEECH = 94;
-    public static final int USAGE_ACCESS = 95;
-    public static final int USER = 96;
-    public static final int USERS_APP_RESTRICTIONS = 97;
-    public static final int USER_DETAILS = 98;
-    public static final int VOICE_INPUT = 99;
-    public static final int VPN = 100;
-    public static final int WALLPAPER_TYPE = 101;
-    public static final int WFD_WIFI_DISPLAY = 102;
-    public static final int WIFI = 103;
-    public static final int WIFI_ADVANCED = 104;
-    public static final int WIFI_CALLING = 105;
-    public static final int WIFI_SAVED_ACCESS_POINTS = 106;
-    public static final int WIFI_APITEST = 107;
-    public static final int WIFI_INFO = 108;
-    public static final int WIFI_P2P = 109;
-    public static final int WIRELESS = 110;
-    public static final int QS_PANEL = 111;
-    public static final int QS_AIRPLANEMODE = 112;
-    public static final int QS_BLUETOOTH = 113;
-    public static final int QS_CAST = 114;
-    public static final int QS_CELLULAR = 115;
-    public static final int QS_COLORINVERSION = 116;
-    public static final int QS_DATAUSAGEDETAIL = 117;
-    public static final int QS_DND = 118;
-    public static final int QS_FLASHLIGHT = 119;
-    public static final int QS_HOTSPOT = 120;
-    public static final int QS_INTENT = 121;
-    public static final int QS_LOCATION = 122;
-    public static final int QS_ROTATIONLOCK = 123;
-    public static final int QS_USERDETAILITE = 124;
-    public static final int QS_USERDETAIL = 125;
-    public static final int QS_WIFI = 126;
-    public static final int NOTIFICATION_PANEL = 127;
-    public static final int NOTIFICATION_ITEM = 128;
-    public static final int NOTIFICATION_ITEM_ACTION = 129;
-    public static final int APPLICATIONS_ADVANCED = 130;
-    public static final int LOCATION_SCANNING = 131;
-    public static final int MANAGE_APPLICATIONS_ALL = 132;
-    public static final int MANAGE_APPLICATIONS_NOTIFICATIONS = 133;
-    public static final int ACTION_WIFI_ADD_NETWORK = 134;
-    public static final int ACTION_WIFI_CONNECT = 135;
-    public static final int ACTION_WIFI_FORCE_SCAN = 136;
-    public static final int ACTION_WIFI_FORGET = 137;
-    public static final int ACTION_WIFI_OFF = 138;
-    public static final int ACTION_WIFI_ON = 139;
-    public static final int MANAGE_PERMISSIONS = 140;
-    public static final int NOTIFICATION_ZEN_MODE_PRIORITY = 141;
-    public static final int NOTIFICATION_ZEN_MODE_AUTOMATION = 142;
-    public static final int MANAGE_DOMAIN_URLS = 143;
-    public static final int NOTIFICATION_ZEN_MODE_SCHEDULE_RULE = 144;
-    public static final int NOTIFICATION_ZEN_MODE_EXTERNAL_RULE = 145;
-    public static final int NOTIFICATION_ZEN_MODE_EVENT_RULE = 146;
-    public static final int ACTION_BAN_APP_NOTES = 147;
-    public static final int ACTION_DISMISS_ALL_NOTES = 148;
-    public static final int QS_DND_DETAILS = 149;
-    public static final int QS_BLUETOOTH_DETAILS = 150;
-    public static final int QS_CAST_DETAILS = 151;
-    public static final int QS_WIFI_DETAILS = 152;
-    public static final int QS_WIFI_TOGGLE = 153;
-    public static final int QS_BLUETOOTH_TOGGLE = 154;
-    public static final int QS_CELLULAR_TOGGLE = 155;
-    public static final int QS_SWITCH_USER = 156;
-    public static final int QS_CAST_SELECT = 157;
-    public static final int QS_CAST_DISCONNECT = 158;
-    public static final int ACTION_BLUETOOTH_TOGGLE = 159;
-    public static final int ACTION_BLUETOOTH_SCAN = 160;
-    public static final int ACTION_BLUETOOTH_RENAME = 161;
-    public static final int ACTION_BLUETOOTH_FILES = 162;
-    public static final int QS_DND_TIME = 163;
-    public static final int QS_DND_CONDITION_SELECT = 164;
-    public static final int QS_DND_ZEN_SELECT = 165;
-    public static final int QS_DND_TOGGLE = 166;
-    public static final int ACTION_ZEN_ALLOW_REMINDERS = 167;
-    public static final int ACTION_ZEN_ALLOW_EVENTS = 168;
-    public static final int ACTION_ZEN_ALLOW_MESSAGES = 169;
-    public static final int ACTION_ZEN_ALLOW_CALLS = 170;
-    public static final int ACTION_ZEN_ALLOW_REPEAT_CALLS = 171;
-    public static final int ACTION_ZEN_ADD_RULE = 172;
-    public static final int ACTION_ZEN_ADD_RULE_OK = 173;
-    public static final int ACTION_ZEN_DELETE_RULE = 174;
-    public static final int ACTION_ZEN_DELETE_RULE_OK = 175;
-    public static final int ACTION_ZEN_ENABLE_RULE = 176;
-    public static final int ACTION_AIRPLANE_TOGGLE = 177;
-    public static final int ACTION_CELL_DATA_TOGGLE = 178;
-    public static final int NOTIFICATION_ACCESS = 179;
-    public static final int NOTIFICATION_ZEN_MODE_ACCESS = 180;
-    public static final int APPLICATIONS_DEFAULT_APPS = 181;
-    public static final int APPLICATIONS_STORAGE_APPS = 182;
-    public static final int APPLICATIONS_USAGE_ACCESS_DETAIL = 183;
-    public static final int APPLICATIONS_HIGH_POWER_APPS = 184;
-    public static final int FUELGAUGE_HIGH_POWER_DETAILS = 185;
-    public static final int ACTION_LS_UNLOCK = 186;
-    public static final int ACTION_LS_SHADE = 187;
-    public static final int ACTION_LS_HINT = 188;
-    public static final int ACTION_LS_CAMERA = 189;
-    public static final int ACTION_LS_DIALER = 190;
-    public static final int ACTION_LS_LOCK = 191;
-    public static final int ACTION_LS_NOTE = 192;
-    public static final int ACTION_LS_QS = 193;
-    public static final int ACTION_SHADE_QS_PULL = 194;
-    public static final int ACTION_SHADE_QS_TAP = 195;
-    public static final int LOCKSCREEN = 196;
-    public static final int BOUNCER = 197;
-    public static final int SCREEN = 198;
-    public static final int NOTIFICATION_ALERT = 199;
-    public static final int ACTION_EMERGENCY_CALL = 200;
-    public static final int APPLICATIONS_MANAGE_ASSIST = 201;
-    public static final int PROCESS_STATS_SUMMARY = 202;
-    public static final int ACTION_ROTATION_LOCK = 203;
-    public static final int ACTION_NOTE_CONTROLS = 204;
-    public static final int ACTION_NOTE_INFO = 205;
-    public static final int ACTION_APP_NOTE_SETTINGS = 206;
-    public static final int VOLUME_DIALOG = 207;
-    public static final int VOLUME_DIALOG_DETAILS = 208;
-    public static final int ACTION_VOLUME_SLIDER = 209;
-    public static final int ACTION_VOLUME_STREAM = 210;
-    public static final int ACTION_VOLUME_KEY = 211;
-    public static final int ACTION_VOLUME_ICON = 212;
-    public static final int ACTION_RINGER_MODE = 213;
-    public static final int ACTION_ACTIVITY_CHOOSER_SHOWN = 214;
-    public static final int ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET = 215;
-    public static final int ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET = 216;
-    public static final int ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET = 217;
-    public static final int ACTION_BRIGHTNESS = 218;
-    public static final int ACTION_BRIGHTNESS_AUTO = 219;
-    public static final int BRIGHTNESS_DIALOG = 220;
-    public static final int SYSTEM_ALERT_WINDOW_APPS = 221;
-    public static final int DREAMING = 222;
-    public static final int DOZING = 223;
-    public static final int OVERVIEW_ACTIVITY = 224;
-    public static final int ABOUT_LEGAL_SETTINGS = 225;
-    public static final int ACTION_SEARCH_RESULTS = 226;
-    public static final int TUNER = 227;
-    public static final int TUNER_QS = 228;
-    public static final int TUNER_DEMO_MODE = 229;
-    public static final int TUNER_QS_REORDER = 230;
-    public static final int TUNER_QS_ADD = 231;
-    public static final int TUNER_QS_REMOVE = 232;
-    public static final int TUNER_STATUS_BAR_ENABLE = 233;
-    public static final int TUNER_STATUS_BAR_DISABLE = 234;
-    public static final int TUNER_DEMO_MODE_ENABLED = 235;
-    public static final int TUNER_DEMO_MODE_ON = 236;
-    public static final int TUNER_BATTERY_PERCENTAGE = 237;
-    public static final int FUELGAUGE_INACTIVE_APPS = 238;
-    public static final int ACTION_ASSIST_LONG_PRESS = 239;
-    public static final int FINGERPRINT_ENROLLING = 240;
-    public static final int FINGERPRINT_FIND_SENSOR = 241;
-    public static final int FINGERPRINT_ENROLL_FINISH = 242;
-    public static final int FINGERPRINT_ENROLL_INTRO = 243;
-    public static final int FINGERPRINT_ENROLL_ONBOARD = 244;
-    public static final int FINGERPRINT_ENROLL_SIDECAR = 245;
-    public static final int FINGERPRINT_ENROLLING_SETUP = 246;
-    public static final int FINGERPRINT_FIND_SENSOR_SETUP = 247;
-    public static final int FINGERPRINT_ENROLL_FINISH_SETUP = 248;
-    public static final int FINGERPRINT_ENROLL_INTRO_SETUP = 249;
-    public static final int FINGERPRINT_ENROLL_ONBOARD_SETUP = 250;
-    public static final int ACTION_FINGERPRINT_ENROLL = 251;
-    public static final int ACTION_FINGERPRINT_AUTH = 252;
-    public static final int ACTION_FINGERPRINT_DELETE = 253;
-    public static final int ACTION_FINGERPRINT_RENAME = 254;
-    public static final int ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE = 255;
-    public static final int ACTION_WIGGLE_CAMERA_GESTURE = 256;
-    public static final int QS_WORKMODE = 257;
-    public static final int BACKGROUND_CHECK_SUMMARY = 258;
-
-    // These constants must match those in the analytic pipeline, do not edit.
-    // Add temporary values to the top of MetricsLogger instead.
-
-    //aliases
-    public static final int DEVICEINFO_STORAGE = DEVICEINFO_MEMORY;
-}
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index e276bc6..ef725da 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -15,44 +15,21 @@
  */
 package com.android.internal.logging;
 
-
 import android.content.Context;
 import android.os.Build;
 import android.view.View;
 
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+
 /**
  * Log all the things.
  *
  * @hide
  */
-public class MetricsLogger implements MetricsConstants {
-    // Temporary constants go here, to await migration to MetricsConstants.
-    public static final int QS_LOCK_TILE = 257;
-    public static final int QS_USER_TILE = 258;
-    public static final int QS_BATTERY_TILE = 259;
-    public static final int NOTIFICATION_ZEN_MODE_VISUAL_INTERRUPTIONS = 260;
-    public static final int ACTION_ZEN_ALLOW_PEEK = 261;
-    public static final int ACTION_ZEN_ALLOW_LIGHTS = 262;
-    public static final int NOTIFICATION_TOPIC_NOTIFICATION = 263;
-    public static final int ACTION_DEFAULT_SMS_APP_CHANGED = 264;
+public class MetricsLogger {
+    // define metric categories in frameworks/base/proto/src/metrics_constants.proto.
 
-    /**
-     * Logged when the user docks a window from recents by longpressing a task and dragging it to
-     * the dock area.
-     */
-    public static final int ACTION_WINDOW_DOCK_DRAG_DROP = 265;
-
-    /**
-     * Logged when the user docks a fullscreen window by long pressing recents which also opens
-     * recents on the lower/right side.
-     */
-    public static final int ACTION_WINDOW_DOCK_LONGPRESS = 266;
-
-    /**
-     * Logged when the user docks a window by dragging from the navbar which also opens recents on
-     * the lower/right side.
-     */
-    public static final int ACTION_WINDOW_DOCK_SWIPE = 267;
+    public static final int VIEW_UNKNOWN = MetricsEvent.VIEW_UNKNOWN;
 
     public static void visible(Context context, int category) throws IllegalArgumentException {
         if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index cc815c4..c71c131 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -19,6 +19,7 @@
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.bluetooth.BluetoothActivityEnergyInfo;
+import android.bluetooth.UidTraffic;
 import android.content.Context;
 import android.content.Intent;
 import android.net.ConnectivityManager;
@@ -40,6 +41,7 @@
 import android.os.SystemProperties;
 import android.os.WorkSource;
 import android.telephony.DataConnectionRealTimeInfo;
+import android.telephony.ModemActivityInfo;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyManager;
@@ -95,7 +97,7 @@
     private static final String TAG = "BatteryStatsImpl";
     private static final boolean DEBUG = false;
     public static final boolean DEBUG_ENERGY = false;
-    private static final boolean DEBUG_ENERGY_CPU = DEBUG_ENERGY || false;
+    private static final boolean DEBUG_ENERGY_CPU = DEBUG_ENERGY;
     private static final boolean DEBUG_HISTORY = false;
     private static final boolean USE_OLD_HISTORY = false;   // for debugging.
 
@@ -105,7 +107,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 138 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 140 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -118,6 +120,12 @@
     // in to one common name.
     private static final int MAX_WAKELOCKS_PER_UID = 100;
 
+    // Number of transmit power states the Wifi controller can be in.
+    private static final int NUM_WIFI_TX_LEVELS = 1;
+
+    // Number of transmit power states the Bluetooth controller can be in.
+    private static final int NUM_BT_TX_LEVELS = 1;
+
     private final JournaledFile mFile;
     public final AtomicFile mCheckinFile;
     public final AtomicFile mDailyFile;
@@ -196,8 +204,7 @@
     /**
      * The statistics we have collected organized by uids.
      */
-    final SparseArray<BatteryStatsImpl.Uid> mUidStats =
-        new SparseArray<BatteryStatsImpl.Uid>();
+    final SparseArray<BatteryStatsImpl.Uid> mUidStats = new SparseArray<>();
 
     // A set of pools of currently active timers.  When a timer is queried, we will divide the
     // elapsed time by the number of active timers to arrive at that timer's share of the time.
@@ -379,11 +386,38 @@
     final LongSamplingCounter[] mNetworkPacketActivityCounters =
             new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
 
-    final LongSamplingCounter[] mBluetoothActivityCounters =
-            new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES];
+    /**
+     * The WiFi controller activity (time in tx, rx, idle, and power consumed) for the device.
+     */
+    ControllerActivityCounterImpl mWifiActivity;
 
-    final LongSamplingCounter[] mWifiActivityCounters =
-            new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES];
+    /**
+     * The Bluetooth controller activity (time in tx, rx, idle, and power consumed) for the device.
+     */
+    ControllerActivityCounterImpl mBluetoothActivity;
+
+    /**
+     * The Modem controller activity (time in tx, rx, idle, and power consumed) for the device.
+     */
+    ControllerActivityCounterImpl mModemActivity;
+
+    /**
+     * Whether the device supports WiFi controller energy reporting. This is set to true on
+     * the first WiFi energy report. See {@link #mWifiActivity}.
+     */
+    boolean mHasWifiReporting = false;
+
+    /**
+     * Whether the device supports Bluetooth controller energy reporting. This is set to true on
+     * the first Bluetooth energy report. See {@link #mBluetoothActivity}.
+     */
+    boolean mHasBluetoothReporting = false;
+
+    /**
+     * Whether the device supports Modem controller energy reporting. This is set to true on
+     * the first Modem energy report. See {@link #mModemActivity}.
+     */
+    boolean mHasModemReporting = false;
 
     boolean mWifiOn;
     StopwatchTimer mWifiOnTimer;
@@ -479,8 +513,6 @@
     private final NetworkStats.Entry mTmpNetworkStatsEntry = new NetworkStats.Entry();
 
     private PowerProfile mPowerProfile;
-    private boolean mHasWifiEnergyReporting = false;
-    private boolean mHasBluetoothEnergyReporting = false;
 
     /*
      * Holds a SamplingTimer associated with each kernel wakelock name being tracked.
@@ -1770,6 +1802,131 @@
         public abstract T instantiateObject();
     }
 
+    public static class ControllerActivityCounterImpl extends ControllerActivityCounter
+            implements Parcelable {
+        private final LongSamplingCounter mIdleTimeMillis;
+        private final LongSamplingCounter mRxTimeMillis;
+        private final LongSamplingCounter[] mTxTimeMillis;
+        private final LongSamplingCounter mPowerDrainMaMs;
+
+        public ControllerActivityCounterImpl(TimeBase timeBase, int numTxStates) {
+            mIdleTimeMillis = new LongSamplingCounter(timeBase);
+            mRxTimeMillis = new LongSamplingCounter(timeBase);
+            mTxTimeMillis = new LongSamplingCounter[numTxStates];
+            for (int i = 0; i < numTxStates; i++) {
+                mTxTimeMillis[i] = new LongSamplingCounter(timeBase);
+            }
+            mPowerDrainMaMs = new LongSamplingCounter(timeBase);
+        }
+
+        public ControllerActivityCounterImpl(TimeBase timeBase, int numTxStates, Parcel in) {
+            mIdleTimeMillis = new LongSamplingCounter(timeBase, in);
+            mRxTimeMillis = new LongSamplingCounter(timeBase, in);
+            final int recordedTxStates = in.readInt();
+            if (recordedTxStates != numTxStates) {
+                throw new ParcelFormatException("inconsistent tx state lengths");
+            }
+
+            mTxTimeMillis = new LongSamplingCounter[numTxStates];
+            for (int i = 0; i < numTxStates; i++) {
+                mTxTimeMillis[i] = new LongSamplingCounter(timeBase, in);
+            }
+            mPowerDrainMaMs = new LongSamplingCounter(timeBase, in);
+        }
+
+        public void readSummaryFromParcel(Parcel in) {
+            mIdleTimeMillis.readSummaryFromParcelLocked(in);
+            mRxTimeMillis.readSummaryFromParcelLocked(in);
+            final int recordedTxStates = in.readInt();
+            if (recordedTxStates != mTxTimeMillis.length) {
+                throw new ParcelFormatException("inconsistent tx state lengths");
+            }
+            for (LongSamplingCounter counter : mTxTimeMillis) {
+                counter.readSummaryFromParcelLocked(in);
+            }
+            mPowerDrainMaMs.readSummaryFromParcelLocked(in);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeSummaryToParcel(Parcel dest) {
+            mIdleTimeMillis.writeSummaryFromParcelLocked(dest);
+            mRxTimeMillis.writeSummaryFromParcelLocked(dest);
+            dest.writeInt(mTxTimeMillis.length);
+            for (LongSamplingCounter counter : mTxTimeMillis) {
+                counter.writeSummaryFromParcelLocked(dest);
+            }
+            mPowerDrainMaMs.writeSummaryFromParcelLocked(dest);
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            mIdleTimeMillis.writeToParcel(dest);
+            mRxTimeMillis.writeToParcel(dest);
+            dest.writeInt(mTxTimeMillis.length);
+            for (LongSamplingCounter counter : mTxTimeMillis) {
+                counter.writeToParcel(dest);
+            }
+            mPowerDrainMaMs.writeToParcel(dest);
+        }
+
+        public void reset(boolean detachIfReset) {
+            mIdleTimeMillis.reset(detachIfReset);
+            mRxTimeMillis.reset(detachIfReset);
+            for (LongSamplingCounter counter : mTxTimeMillis) {
+                counter.reset(detachIfReset);
+            }
+            mPowerDrainMaMs.reset(detachIfReset);
+        }
+
+        public void detach() {
+            mIdleTimeMillis.detach();
+            mRxTimeMillis.detach();
+            for (LongSamplingCounter counter : mTxTimeMillis) {
+                counter.detach();
+            }
+            mPowerDrainMaMs.detach();
+        }
+
+        /**
+         * @return a LongSamplingCounter, measuring time spent in the idle state in
+         * milliseconds.
+         */
+        @Override
+        public LongSamplingCounter getIdleTimeCounter() {
+            return mRxTimeMillis;
+        }
+
+        /**
+         * @return a LongSamplingCounter, measuring time spent in the receive state in
+         * milliseconds.
+         */
+        @Override
+        public LongSamplingCounter getRxTimeCounter() {
+            return mRxTimeMillis;
+        }
+
+        /**
+         * @return a LongSamplingCounter[], measuring time spent in various transmit states in
+         * milliseconds.
+         */
+        @Override
+        public LongSamplingCounter[] getTxTimeCounters() {
+            return mTxTimeMillis;
+        }
+
+        /**
+         * @return a LongSamplingCounter, measuring power use in milli-ampere milliseconds (mAmS).
+         */
+        @Override
+        public LongSamplingCounter getPowerCounter() {
+            return mPowerDrainMaMs;
+        }
+    }
+
     /*
      * Get the wakeup reason counter, and create a new one if one
      * doesn't already exist.
@@ -3198,7 +3355,7 @@
                 mMobileRadioActivePerAppTimer.startRunningLocked(elapsedRealtime);
             } else {
                 mMobileRadioActiveTimer.stopRunningLocked(realElapsedRealtimeMs);
-                updateMobileRadioStateLocked(realElapsedRealtimeMs);
+                updateMobileRadioStateLocked(realElapsedRealtimeMs, null);
                 mMobileRadioActivePerAppTimer.stopRunningLocked(realElapsedRealtimeMs);
             }
         }
@@ -4144,8 +4301,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.
-        final long elapsedRealtimeMs = SystemClock.elapsedRealtime();
-        updateMobileRadioStateLocked(elapsedRealtimeMs);
+        updateMobileRadioStateLocked(SystemClock.elapsedRealtime(), null);
         updateWifiStateLocked(null);
     }
 
@@ -4328,26 +4484,34 @@
         return mWifiSignalStrengthsTimer[strengthBin].getCountLocked(which);
     }
 
-    @Override public boolean hasBluetoothActivityReporting() {
-        return mHasBluetoothEnergyReporting;
+    @Override
+    public ControllerActivityCounter getBluetoothControllerActivity() {
+        return mBluetoothActivity;
     }
 
-    @Override public long getBluetoothControllerActivity(int type, int which) {
-        if (type >= 0 && type < mBluetoothActivityCounters.length) {
-            return mBluetoothActivityCounters[type].getCountLocked(which);
-        }
-        return 0;
+    @Override
+    public ControllerActivityCounter getWifiControllerActivity() {
+        return mWifiActivity;
     }
 
-    @Override public boolean hasWifiActivityReporting() {
-        return mHasWifiEnergyReporting;
+    @Override
+    public ControllerActivityCounter getModemControllerActivity() {
+        return mModemActivity;
     }
 
-    @Override public long getWifiControllerActivity(int type, int which) {
-        if (type >= 0 && type < mWifiActivityCounters.length) {
-            return mWifiActivityCounters[type].getCountLocked(which);
-        }
-        return 0;
+    @Override
+    public boolean hasBluetoothActivityReporting() {
+        return mHasBluetoothReporting;
+    }
+
+    @Override
+    public boolean hasWifiActivityReporting() {
+        return mHasWifiReporting;
+    }
+
+    @Override
+    public boolean hasModemActivityReporting() {
+        return mHasModemReporting;
     }
 
     @Override
@@ -4457,15 +4621,21 @@
 
         /**
          * The amount of time this uid has kept the WiFi controller in idle, tx, and rx mode.
+         * Can be null if the UID has had no such activity.
          */
-        LongSamplingCounter[] mWifiControllerTime =
-                new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES];
+        private ControllerActivityCounterImpl mWifiControllerActivity;
 
         /**
          * The amount of time this uid has kept the Bluetooth controller in idle, tx, and rx mode.
+         * Can be null if the UID has had no such activity.
          */
-        LongSamplingCounter[] mBluetoothControllerTime =
-                new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES];
+        private ControllerActivityCounterImpl mBluetoothControllerActivity;
+
+        /**
+         * The amount of time this uid has kept the Modem controller in idle, tx, and rx mode.
+         * Can be null if the UID has had no such activity.
+         */
+        private ControllerActivityCounterImpl mModemControllerActivity;
 
         /**
          * The CPU times we had at the last history details update.
@@ -4684,11 +4854,43 @@
             }
         }
 
-        public void noteWifiControllerActivityLocked(int type, long timeMs) {
-            if (mWifiControllerTime[type] == null) {
-                mWifiControllerTime[type] = new LongSamplingCounter(mOnBatteryTimeBase);
+        @Override
+        public ControllerActivityCounter getWifiControllerActivity() {
+            return mWifiControllerActivity;
+        }
+
+        @Override
+        public ControllerActivityCounter getBluetoothControllerActivity() {
+            return mBluetoothControllerActivity;
+        }
+
+        @Override
+        public ControllerActivityCounter getModemControllerActivity() {
+            return mModemControllerActivity;
+        }
+
+        public ControllerActivityCounterImpl getOrCreateWifiControllerActivityLocked() {
+            if (mWifiControllerActivity == null) {
+                mWifiControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+                        NUM_BT_TX_LEVELS);
             }
-            mWifiControllerTime[type].addCountLocked(timeMs);
+            return mWifiControllerActivity;
+        }
+
+        public ControllerActivityCounterImpl getOrCreateBluetoothControllerActivityLocked() {
+            if (mBluetoothControllerActivity == null) {
+                mBluetoothControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+                        NUM_BT_TX_LEVELS);
+            }
+            return mBluetoothControllerActivity;
+        }
+
+        public ControllerActivityCounterImpl getOrCreateModemControllerActivityLocked() {
+            if (mModemControllerActivity == null) {
+                mModemControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+                        ModemActivityInfo.TX_POWER_LEVELS);
+            }
+            return mModemControllerActivity;
         }
 
         public StopwatchTimer createAudioTurnedOnTimerLocked() {
@@ -5076,15 +5278,6 @@
             return 0;
         }
 
-        @Override
-        public long getWifiControllerActivity(int type, int which) {
-            if (type >= 0 && type < NUM_CONTROLLER_ACTIVITY_TYPES &&
-                    mWifiControllerTime[type] != null) {
-                return mWifiControllerTime[type].getCountLocked(which);
-            }
-            return 0;
-        }
-
         void initNetworkActivityLocked() {
             mNetworkByteActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
             mNetworkPacketActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
@@ -5174,14 +5367,16 @@
                 mMobileRadioActiveCount.reset(false);
             }
 
-            for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
-                if (mWifiControllerTime[i] != null) {
-                    mWifiControllerTime[i].reset(false);
-                }
+            if (mWifiControllerActivity != null) {
+                mWifiControllerActivity.reset(false);
+            }
 
-                if (mBluetoothControllerTime[i] != null) {
-                    mBluetoothControllerTime[i].reset(false);
-                }
+            if (mBluetoothActivity != null) {
+                mBluetoothActivity.reset(false);
+            }
+
+            if (mModemActivity != null) {
+                mModemActivity.reset(false);
             }
 
             mUserCpuTime.reset(false);
@@ -5326,15 +5521,18 @@
                     }
                 }
 
-                for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
-                    if (mWifiControllerTime[i] != null) {
-                        mWifiControllerTime[i].detach();
-                    }
-
-                    if (mBluetoothControllerTime[i] != null) {
-                        mBluetoothControllerTime[i].detach();
-                    }
+                if (mWifiControllerActivity != null) {
+                    mWifiControllerActivity.detach();
                 }
+
+                if (mBluetoothControllerActivity != null) {
+                    mBluetoothControllerActivity.detach();
+                }
+
+                if (mModemControllerActivity != null) {
+                    mModemControllerActivity.detach();
+                }
+
                 mPids.clear();
 
                 mUserCpuTime.detach();
@@ -5505,22 +5703,25 @@
                 out.writeInt(0);
             }
 
-            for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
-                if (mWifiControllerTime[i] != null) {
-                    out.writeInt(1);
-                    mWifiControllerTime[i].writeToParcel(out);
-                } else {
-                    out.writeInt(0);
-                }
+            if (mWifiControllerActivity != null) {
+                out.writeInt(1);
+                mWifiControllerActivity.writeToParcel(out, 0);
+            } else {
+                out.writeInt(0);
             }
 
-            for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
-                if (mBluetoothControllerTime[i] != null) {
-                    out.writeInt(1);
-                    mBluetoothControllerTime[i].writeToParcel(out);
-                } else {
-                    out.writeInt(0);
-                }
+            if (mBluetoothControllerActivity != null) {
+                out.writeInt(1);
+                mBluetoothControllerActivity.writeToParcel(out, 0);
+            } else {
+                out.writeInt(0);
+            }
+
+            if (mModemControllerActivity != null) {
+                out.writeInt(1);
+                mModemControllerActivity.writeToParcel(out, 0);
+            } else {
+                out.writeInt(0);
             }
 
             mUserCpuTime.writeToParcel(out);
@@ -5711,20 +5912,25 @@
                 mNetworkPacketActivityCounters = null;
             }
 
-            for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
-                if (in.readInt() != 0) {
-                    mWifiControllerTime[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
-                } else {
-                    mWifiControllerTime[i] = null;
-                }
+            if (in.readInt() != 0) {
+                mWifiControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+                        NUM_WIFI_TX_LEVELS, in);
+            } else {
+                mWifiControllerActivity = null;
             }
 
-            for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
-                if (in.readInt() != 0) {
-                    mBluetoothControllerTime[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
-                } else {
-                    mBluetoothControllerTime[i] = null;
-                }
+            if (in.readInt() != 0) {
+                mBluetoothControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+                        NUM_BT_TX_LEVELS, in);
+            } else {
+                mBluetoothControllerActivity = null;
+            }
+
+            if (in.readInt() != 0) {
+                mModemControllerActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+                        ModemActivityInfo.TX_POWER_LEVELS, in);
+            } else {
+                mModemControllerActivity = null;
             }
 
             mUserCpuTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
@@ -6900,10 +7106,12 @@
             mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
             mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
         }
-        for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
-            mBluetoothActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
-            mWifiActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
-        }
+        mWifiActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase, NUM_WIFI_TX_LEVELS);
+        mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+                NUM_BT_TX_LEVELS);
+        mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+                ModemActivityInfo.TX_POWER_LEVELS);
+
         mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mOnBatteryTimeBase);
         mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mOnBatteryTimeBase);
         mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase);
@@ -7551,10 +7759,9 @@
         for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
             mWifiSignalStrengthsTimer[i].reset(false);
         }
-        for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
-            mBluetoothActivityCounters[i].reset(false);
-            mWifiActivityCounters[i].reset(false);
-        }
+        mWifiActivity.reset(false);
+        mBluetoothActivity.reset(false);
+        mModemActivity.reset(false);
         mNumConnectivityChange = mLoadedNumConnectivityChange = mUnpluggedNumConnectivityChange = 0;
 
         for (int i=0; i<mUidStats.size(); i++) {
@@ -7765,7 +7972,7 @@
         }
 
         if (info != null) {
-            mHasWifiEnergyReporting = true;
+            mHasWifiReporting = true;
 
             // Measured in mAms
             final long txTimeMs = info.getControllerTxTimeMillis();
@@ -7845,8 +8052,11 @@
                                 + scanRxTimeSinceMarkMs + " ms  Tx:"
                                 + scanTxTimeSinceMarkMs + " ms)");
                     }
-                    uid.noteWifiControllerActivityLocked(CONTROLLER_RX_TIME, scanRxTimeSinceMarkMs);
-                    uid.noteWifiControllerActivityLocked(CONTROLLER_TX_TIME, scanTxTimeSinceMarkMs);
+
+                    ControllerActivityCounterImpl activityCounter =
+                            uid.getOrCreateWifiControllerActivityLocked();
+                    activityCounter.getRxTimeCounter().addCountLocked(scanRxTimeSinceMarkMs);
+                    activityCounter.getTxTimeCounters()[0].addCountLocked(scanTxTimeSinceMarkMs);
                     leftOverRxTimeMs -= scanRxTimeSinceMarkMs;
                     leftOverTxTimeMs -= scanTxTimeSinceMarkMs;
                 }
@@ -7865,7 +8075,8 @@
                         Slog.d(TAG, "  IdleTime for UID " + uid.getUid() + ": "
                                 + myIdleTimeMs + " ms");
                     }
-                    uid.noteWifiControllerActivityLocked(CONTROLLER_IDLE_TIME, myIdleTimeMs);
+                    uid.getOrCreateWifiControllerActivityLocked().getIdleTimeCounter()
+                            .addCountLocked(myIdleTimeMs);
                 }
             }
 
@@ -7882,7 +8093,8 @@
                 if (DEBUG_ENERGY) {
                     Slog.d(TAG, "  TxTime for UID " + uid.getUid() + ": " + myTxTimeMs + " ms");
                 }
-                uid.noteWifiControllerActivityLocked(CONTROLLER_TX_TIME, myTxTimeMs);
+                uid.getOrCreateWifiControllerActivityLocked().getTxTimeCounters()[0]
+                        .addCountLocked(myTxTimeMs);
             }
 
             // Distribute the remaining Rx power appropriately between all apps that received
@@ -7893,25 +8105,23 @@
                 if (DEBUG_ENERGY) {
                     Slog.d(TAG, "  RxTime for UID " + uid.getUid() + ": " + myRxTimeMs + " ms");
                 }
-                uid.noteWifiControllerActivityLocked(CONTROLLER_RX_TIME, myRxTimeMs);
+                uid.getOrCreateWifiControllerActivityLocked().getRxTimeCounter()
+                        .addCountLocked(myRxTimeMs);
             }
 
             // Any left over power use will be picked up by the WiFi category in BatteryStatsHelper.
 
             // Update WiFi controller stats.
-            mWifiActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
-                    info.getControllerRxTimeMillis());
-            mWifiActivityCounters[CONTROLLER_TX_TIME].addCountLocked(
-                    info.getControllerTxTimeMillis());
-            mWifiActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
-                    info.getControllerIdleTimeMillis());
+            mWifiActivity.getRxTimeCounter().addCountLocked(info.getControllerRxTimeMillis());
+            mWifiActivity.getTxTimeCounters()[0].addCountLocked(info.getControllerTxTimeMillis());
+            mWifiActivity.getIdleTimeCounter().addCountLocked(info.getControllerIdleTimeMillis());
 
             // POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
             final double opVolt = mPowerProfile.getAveragePower(
                     PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
             if (opVolt != 0) {
                 // We store the power drain as mAms.
-                mWifiActivityCounters[CONTROLLER_POWER_DRAIN].addCountLocked(
+                mWifiActivity.getPowerCounter().addCountLocked(
                         (long)(info.getControllerEnergyUsed() / opVolt));
             }
         }
@@ -7920,9 +8130,10 @@
     /**
      * Distribute Cell radio energy info and network traffic to apps.
      */
-    public void updateMobileRadioStateLocked(final long elapsedRealtimeMs) {
+    public void updateMobileRadioStateLocked(final long elapsedRealtimeMs,
+                                             final ModemActivityInfo activityInfo) {
         if (DEBUG_ENERGY) {
-            Slog.d(TAG, "Updating mobile radio stats");
+            Slog.d(TAG, "Updating mobile radio stats with " + activityInfo);
         }
 
         NetworkStats delta = null;
@@ -7935,60 +8146,112 @@
             return;
         }
 
-        if (delta == null || !mOnBatteryInternal) {
+        if (!mOnBatteryInternal) {
             return;
         }
 
         long radioTime = mMobileRadioActivePerAppTimer.getTimeSinceMarkLocked(
                 elapsedRealtimeMs * 1000);
         mMobileRadioActivePerAppTimer.setMark(elapsedRealtimeMs);
-        long totalPackets = delta.getTotalPackets();
 
-        final int size = delta.size();
-        for (int i = 0; i < size; i++) {
-            final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
+        long totalRxPackets = 0;
+        long totalTxPackets = 0;
+        if (delta != null) {
+            final int size = delta.size();
+            for (int i = 0; i < size; i++) {
+                final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
+                if (entry.rxPackets == 0 || entry.txPackets == 0) {
+                    continue;
+                }
 
-            if (entry.rxBytes == 0 || entry.txBytes == 0) {
-                continue;
+                if (DEBUG_ENERGY) {
+                    Slog.d(TAG, "Mobile uid " + entry.uid + ": delta rx=" + entry.rxBytes
+                            + " tx=" + entry.txBytes + " rxPackets=" + entry.rxPackets
+                            + " txPackets=" + entry.txPackets);
+                }
+
+                totalRxPackets += entry.rxPackets;
+                totalTxPackets += entry.txPackets;
+
+                final Uid u = getUidStatsLocked(mapUid(entry.uid));
+                u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.rxBytes, entry.rxPackets);
+                u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_DATA, entry.txBytes, entry.txPackets);
+
+                mNetworkByteActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
+                        entry.rxBytes);
+                mNetworkByteActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
+                        entry.txBytes);
+                mNetworkPacketActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
+                        entry.rxPackets);
+                mNetworkPacketActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
+                        entry.txPackets);
             }
 
-            if (DEBUG_ENERGY) {
-                Slog.d(TAG, "Mobile uid " + entry.uid + ": delta rx=" + entry.rxBytes
-                        + " tx=" + entry.txBytes + " rxPackets=" + entry.rxPackets
-                        + " txPackets=" + entry.txPackets);
-            }
+            // Now distribute proportional blame to the apps that did networking.
+            long totalPackets = totalRxPackets + totalTxPackets;
+            if (totalPackets > 0) {
+                for (int i = 0; i < size; i++) {
+                    final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
+                    if (entry.rxPackets == 0 && entry.txPackets == 0) {
+                        continue;
+                    }
 
-            final Uid u = getUidStatsLocked(mapUid(entry.uid));
-            u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.rxBytes,
-                    entry.rxPackets);
-            u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_DATA, entry.txBytes,
-                    entry.txPackets);
+                    final Uid u = getUidStatsLocked(mapUid(entry.uid));
+
+                    // Distribute total radio active time in to this app.
+                    final long appPackets = entry.rxPackets + entry.txPackets;
+                    final long appRadioTime = (radioTime * appPackets) / totalPackets;
+                    u.noteMobileRadioActiveTimeLocked(appRadioTime);
+
+                    // Remove this app from the totals, so that we don't lose any time
+                    // due to rounding.
+                    radioTime -= appRadioTime;
+                    totalPackets -= appPackets;
+
+                    if (activityInfo != null) {
+                        ControllerActivityCounterImpl activityCounter =
+                                u.getOrCreateModemControllerActivityLocked();
+                        if (entry.rxPackets != 0) {
+                            final long rxMs = (entry.rxPackets * activityInfo.getRxTimeMillis())
+                                    / totalRxPackets;
+                            activityCounter.getRxTimeCounter().addCountLocked(rxMs);
+                        }
+
+                        if (entry.txPackets != 0) {
+                            for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
+                                long txMs = entry.txPackets * activityInfo.getTxTimeMillis()[lvl];
+                                txMs /= totalTxPackets;
+                                activityCounter.getTxTimeCounters()[lvl].addCountLocked(txMs);
+                            }
+                        }
+                    }
+                }
+            }
 
             if (radioTime > 0) {
-                // Distribute total radio active time in to this app.
-                long appPackets = entry.rxPackets + entry.txPackets;
-                long appRadioTime = (radioTime*appPackets)/totalPackets;
-                u.noteMobileRadioActiveTimeLocked(appRadioTime);
-                // Remove this app from the totals, so that we don't lose any time
-                // due to rounding.
-                radioTime -= appRadioTime;
-                totalPackets -= appPackets;
+                // Whoops, there is some radio time we can't blame on an app!
+                mMobileRadioActiveUnknownTime.addCountLocked(radioTime);
+                mMobileRadioActiveUnknownCount.addCountLocked(1);
             }
-
-            mNetworkByteActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
-                    entry.rxBytes);
-            mNetworkByteActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
-                    entry.txBytes);
-            mNetworkPacketActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
-                    entry.rxPackets);
-            mNetworkPacketActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
-                    entry.txPackets);
         }
 
-        if (radioTime > 0) {
-            // Whoops, there is some radio time we can't blame on an app!
-            mMobileRadioActiveUnknownTime.addCountLocked(radioTime);
-            mMobileRadioActiveUnknownCount.addCountLocked(1);
+        if (activityInfo != null) {
+            mHasModemReporting = true;
+            mModemActivity.getIdleTimeCounter().addCountLocked(activityInfo.getIdleTimeMillis());
+            mModemActivity.getRxTimeCounter().addCountLocked(activityInfo.getRxTimeMillis());
+            for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
+                mModemActivity.getTxTimeCounters()[lvl]
+                        .addCountLocked(activityInfo.getTxTimeMillis()[lvl]);
+            }
+
+            // POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
+            final double opVolt = mPowerProfile.getAveragePower(
+                    PowerProfile.POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
+            if (opVolt != 0) {
+                // We store the power drain as mAms.
+                mModemActivity.getPowerCounter().addCountLocked(
+                        (long) (activityInfo.getEnergyUsed() / opVolt));
+            }
         }
     }
 
@@ -7998,16 +8261,16 @@
      */
     public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info) {
         if (DEBUG_ENERGY) {
-            Slog.d(TAG, "Updating bluetooth stats");
+            Slog.d(TAG, "Updating bluetooth stats: " + info);
         }
 
         if (info != null && mOnBatteryInternal) {
-            mHasBluetoothEnergyReporting = true;
-            mBluetoothActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
+            mHasBluetoothReporting = true;
+            mBluetoothActivity.getRxTimeCounter().addCountLocked(
                     info.getControllerRxTimeMillis());
-            mBluetoothActivityCounters[CONTROLLER_TX_TIME].addCountLocked(
+            mBluetoothActivity.getTxTimeCounters()[0].addCountLocked(
                     info.getControllerTxTimeMillis());
-            mBluetoothActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
+            mBluetoothActivity.getIdleTimeCounter().addCountLocked(
                     info.getControllerIdleTimeMillis());
 
             // POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
@@ -8015,9 +8278,26 @@
                     PowerProfile.POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
             if (opVolt != 0) {
                 // We store the power drain as mAms.
-                mBluetoothActivityCounters[CONTROLLER_POWER_DRAIN].addCountLocked(
+                mBluetoothActivity.getPowerCounter().addCountLocked(
                         (long) (info.getControllerEnergyUsed() / opVolt));
             }
+
+            final UidTraffic[] uidTraffic = info.getUidTraffic();
+            final int numUids = uidTraffic != null ? uidTraffic.length : 0;
+            for (int i = 0; i < numUids; i++) {
+                final UidTraffic traffic = uidTraffic[i];
+
+                // Add to the global counters.
+                mNetworkByteActivityCounters[NETWORK_BT_RX_DATA].addCountLocked(
+                        traffic.getRxBytes());
+                mNetworkByteActivityCounters[NETWORK_BT_TX_DATA].addCountLocked(
+                        traffic.getTxBytes());
+
+                // Add to the UID counters.
+                final Uid u = getUidStatsLocked(mapUid(traffic.getUid()));
+                u.noteNetworkActivityLocked(NETWORK_BT_RX_DATA, traffic.getRxBytes(), 0);
+                u.noteNetworkActivityLocked(NETWORK_BT_TX_DATA, traffic.getTxBytes(), 0);
+            }
         }
     }
 
@@ -9304,12 +9584,12 @@
         for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
             mWifiSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
         }
-        for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
-            mBluetoothActivityCounters[i].readSummaryFromParcelLocked(in);
-        }
-        for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
-            mWifiActivityCounters[i].readSummaryFromParcelLocked(in);
-        }
+        mWifiActivity.readSummaryFromParcel(in);
+        mBluetoothActivity.readSummaryFromParcel(in);
+        mModemActivity.readSummaryFromParcel(in);
+        mHasWifiReporting = in.readInt() != 0;
+        mHasBluetoothReporting = in.readInt() != 0;
+        mHasModemReporting = in.readInt() != 0;
 
         mNumConnectivityChange = mLoadedNumConnectivityChange = in.readInt();
         mFlashlightOnNesting = 0;
@@ -9638,12 +9918,13 @@
         for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
             mWifiSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         }
-        for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
-            mBluetoothActivityCounters[i].writeSummaryFromParcelLocked(out);
-        }
-        for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
-            mWifiActivityCounters[i].writeSummaryFromParcelLocked(out);
-        }
+        mWifiActivity.writeSummaryToParcel(out);
+        mBluetoothActivity.writeSummaryToParcel(out);
+        mModemActivity.writeSummaryToParcel(out);
+        out.writeInt(mHasWifiReporting ? 1 : 0);
+        out.writeInt(mHasBluetoothReporting ? 1 : 0);
+        out.writeInt(mHasModemReporting ? 1 : 0);
+
         out.writeInt(mNumConnectivityChange);
         mFlashlightOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         mCameraOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
@@ -9986,15 +10267,17 @@
             mWifiSignalStrengthsTimer[i] = new StopwatchTimer(null, -800-i,
                     null, mOnBatteryTimeBase, in);
         }
-        for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
-            mBluetoothActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
-        }
-        for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
-            mWifiActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
-        }
 
-        mHasWifiEnergyReporting = in.readInt() != 0;
-        mHasBluetoothEnergyReporting = in.readInt() != 0;
+        mWifiActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+                NUM_WIFI_TX_LEVELS, in);
+        mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+                NUM_BT_TX_LEVELS, in);
+        mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+                ModemActivityInfo.TX_POWER_LEVELS, in);
+        mHasWifiReporting = in.readInt() != 0;
+        mHasBluetoothReporting = in.readInt() != 0;
+        mHasModemReporting = in.readInt() != 0;
+
         mNumConnectivityChange = in.readInt();
         mLoadedNumConnectivityChange = in.readInt();
         mUnpluggedNumConnectivityChange = in.readInt();
@@ -10141,14 +10424,13 @@
         for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
             mWifiSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
         }
-        for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
-            mBluetoothActivityCounters[i].writeToParcel(out);
-        }
-        for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
-            mWifiActivityCounters[i].writeToParcel(out);
-        }
-        out.writeInt(mHasWifiEnergyReporting ? 1 : 0);
-        out.writeInt(mHasBluetoothEnergyReporting ? 1 : 0);
+        mWifiActivity.writeToParcel(out, 0);
+        mBluetoothActivity.writeToParcel(out, 0);
+        mModemActivity.writeToParcel(out, 0);
+        out.writeInt(mHasWifiReporting ? 1 : 0);
+        out.writeInt(mHasBluetoothReporting ? 1 : 0);
+        out.writeInt(mHasModemReporting ? 1 : 0);
+
         out.writeInt(mNumConnectivityChange);
         out.writeInt(mLoadedNumConnectivityChange);
         out.writeInt(mUnpluggedNumConnectivityChange);
diff --git a/core/java/com/android/internal/os/BluetoothPowerCalculator.java b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
index 1f59672..531d1fa 100644
--- a/core/java/com/android/internal/os/BluetoothPowerCalculator.java
+++ b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
@@ -40,15 +40,15 @@
     @Override
     public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
                                    long rawUptimeUs, int statsType) {
-        final long idleTimeMs = stats.getBluetoothControllerActivity(
-                BatteryStats.CONTROLLER_IDLE_TIME, statsType);
-        final long txTimeMs = stats.getBluetoothControllerActivity(
-                BatteryStats.CONTROLLER_TX_TIME, statsType);
-        final long rxTimeMs = stats.getBluetoothControllerActivity(
-                BatteryStats.CONTROLLER_RX_TIME, statsType);
+        final BatteryStats.ControllerActivityCounter counter =
+                stats.getBluetoothControllerActivity();
+
+        final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(statsType);
+        final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(statsType);
+        final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(statsType);
         final long totalTimeMs = idleTimeMs + txTimeMs + rxTimeMs;
-        double powerMah = stats.getBluetoothControllerActivity(
-                BatteryStats.CONTROLLER_POWER_DRAIN, statsType) / (double)(1000*60*60);
+        double powerMah = counter.getPowerCounter().getCountLocked(statsType)
+                 / (double)(1000*60*60);
 
         if (powerMah == 0) {
             // Some devices do not report the power, so calculate it.
diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java
index 830da79..ed4722d 100644
--- a/core/java/com/android/internal/os/InstallerConnection.java
+++ b/core/java/com/android/internal/os/InstallerConnection.java
@@ -19,7 +19,9 @@
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
 import android.os.SystemClock;
+import android.text.TextUtils;
 import android.util.Slog;
+import android.text.TextUtils;
 
 import com.android.internal.util.Preconditions;
 
@@ -29,6 +31,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.Arrays;
 
 /**
  * Represents a connection to {@code installd}. Allows multiple connect and
@@ -61,6 +64,11 @@
     }
 
     public synchronized String transact(String cmd) {
+        if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
+            Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
+                    + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
+        }
+
         if (!connect()) {
             Slog.e(TAG, "connection failed");
             return "-1";
@@ -96,44 +104,60 @@
         }
     }
 
-    public int execute(String cmd) {
-        if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
-            Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
-                    + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
-        }
-
-        String res = transact(cmd);
+    public void execute(String cmd, Object... args) throws InstallerException {
+        final String resRaw = executeForResult(cmd, args);
+        int res = -1;
         try {
-            return Integer.parseInt(res);
-        } catch (NumberFormatException ex) {
-            return -1;
+            res = Integer.parseInt(resRaw);
+        } catch (NumberFormatException ignored) {
+        }
+        if (res != 0) {
+            throw new InstallerException(
+                    "Failed to execute " + cmd + " " + Arrays.toString(args) + ": " + res);
         }
     }
 
-    public int dexopt(String apkPath, int uid, String instructionSet,
-            int dexoptNeeded, int dexFlags) {
-        return dexopt(apkPath, uid, "*", instructionSet, dexoptNeeded,
-                null /*outputPath*/, dexFlags);
+    public String executeForResult(String cmd, Object... args)
+            throws InstallerException {
+        final StringBuilder builder = new StringBuilder(cmd);
+        for (Object arg : args) {
+            String escaped;
+            if (arg == null) {
+                escaped = "";
+            } else {
+                escaped = String.valueOf(arg);
+            }
+            if (escaped.indexOf('\0') != -1 || escaped.indexOf(' ') != -1 || "!".equals(escaped)) {
+                throw new InstallerException(
+                        "Invalid argument while executing " + cmd + " " + Arrays.toString(args));
+            }
+            if (TextUtils.isEmpty(escaped)) {
+                escaped = "!";
+            }
+            builder.append(' ').append(escaped);
+        }
+        return transact(builder.toString());
     }
 
-    public int dexopt(String apkPath, int uid, String pkgName, String instructionSet,
-            int dexoptNeeded, String outputPath, int dexFlags) {
-        StringBuilder builder = new StringBuilder("dexopt");
-        builder.append(' ');
-        builder.append(apkPath);
-        builder.append(' ');
-        builder.append(uid);
-        builder.append(' ');
-        builder.append(pkgName);
-        builder.append(' ');
-        builder.append(instructionSet);
-        builder.append(' ');
-        builder.append(dexoptNeeded);
-        builder.append(' ');
-        builder.append(outputPath != null ? outputPath : "!");
-        builder.append(' ');
-        builder.append(dexFlags);
-        return execute(builder.toString());
+    public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded,
+            int dexFlags, String volumeUuid, boolean useProfiles) throws InstallerException {
+        dexopt(apkPath, uid, "*", instructionSet, dexoptNeeded,
+                null /*outputPath*/, dexFlags, volumeUuid, useProfiles);
+    }
+
+    public void dexopt(String apkPath, int uid, String pkgName, String instructionSet,
+            int dexoptNeeded, String outputPath, int dexFlags, String volumeUuid,
+            boolean useProfiles) throws InstallerException {
+        execute("dexopt",
+                apkPath,
+                uid,
+                pkgName,
+                instructionSet,
+                dexoptNeeded,
+                outputPath,
+                dexFlags,
+                volumeUuid,
+                useProfiles ? '1' : '0');
     }
 
     private boolean connect() {
@@ -227,11 +251,19 @@
 
     public void waitForConnection() {
         for (;;) {
-            if (execute("ping") >= 0) {
+            try {
+                execute("ping");
                 return;
+            } catch (InstallerException ignored) {
             }
             Slog.w(TAG, "installd not ready");
             SystemClock.sleep(1000);
         }
     }
+
+    public static class InstallerException extends Exception {
+        public InstallerException(String detailMessage) {
+            super(detailMessage);
+        }
+    }
 }
diff --git a/core/java/com/android/internal/os/KernelCpuSpeedReader.java b/core/java/com/android/internal/os/KernelCpuSpeedReader.java
index 5b776ac..3f6ebb9 100644
--- a/core/java/com/android/internal/os/KernelCpuSpeedReader.java
+++ b/core/java/com/android/internal/os/KernelCpuSpeedReader.java
@@ -16,8 +16,11 @@
 package com.android.internal.os;
 
 import android.text.TextUtils;
+import android.system.OsConstants;
 import android.util.Slog;
 
+import libcore.io.Libcore;
+
 import java.io.BufferedReader;
 import java.io.FileReader;
 import java.io.IOException;
@@ -29,7 +32,7 @@
  *
  * freq time
  *
- * where time is measured in 1/100 seconds.
+ * where time is measured in jiffies.
  */
 public class KernelCpuSpeedReader {
     private static final String TAG = "KernelCpuSpeedReader";
@@ -38,6 +41,9 @@
     private final long[] mLastSpeedTimes;
     private final long[] mDeltaSpeedTimes;
 
+    // How long a CPU jiffy is in milliseconds.
+    private final long mJiffyMillis;
+
     /**
      * @param cpuNumber The cpu (cpu0, cpu1, etc) whose state to read.
      */
@@ -46,6 +52,8 @@
                 cpuNumber);
         mLastSpeedTimes = new long[numSpeedSteps];
         mDeltaSpeedTimes = new long[numSpeedSteps];
+        long jiffyHz = Libcore.os.sysconf(OsConstants._SC_CLK_TCK);
+        mJiffyMillis = 1000/jiffyHz;
     }
 
     /**
@@ -62,8 +70,7 @@
                 splitter.setString(line);
                 Long.parseLong(splitter.next());
 
-                // The proc file reports time in 1/100 sec, so convert to milliseconds.
-                long time = Long.parseLong(splitter.next()) * 10;
+                long time = Long.parseLong(splitter.next()) * mJiffyMillis;
                 if (time < mLastSpeedTimes[speedIndex]) {
                     // The stats reset when the cpu hotplugged. That means that the time
                     // we read is offset from 0, so the time is the delta.
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index aaa9f73..14ebe22 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -93,6 +93,12 @@
     public static final String POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE =
             "bluetooth.controller.voltage";
 
+    public static final String POWER_MODEM_CONTROLLER_IDLE = "modem.controller.idle";
+    public static final String POWER_MODEM_CONTROLLER_RX = "modem.controller.rx";
+    public static final String POWER_MODEM_CONTROLLER_TX = "modem.controller.tx";
+    public static final String POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE =
+            "modem.controller.voltage";
+
     /**
      * Power consumption when GPS is on.
      */
@@ -100,17 +106,23 @@
 
     /**
      * Power consumption when Bluetooth driver is on.
+     * @deprecated
      */
+    @Deprecated
     public static final String POWER_BLUETOOTH_ON = "bluetooth.on";
 
     /**
      * Power consumption when Bluetooth driver is transmitting/receiving.
+     * @deprecated
      */
+    @Deprecated
     public static final String POWER_BLUETOOTH_ACTIVE = "bluetooth.active";
 
     /**
      * Power consumption when Bluetooth driver gets an AT command.
+     * @deprecated
      */
+    @Deprecated
     public static final String POWER_BLUETOOTH_AT_CMD = "bluetooth.at";
 
 
diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
index bf97f1f..d831902 100644
--- a/core/java/com/android/internal/os/ProcessCpuTracker.java
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -67,10 +67,10 @@
     static final int PROCESS_STAT_UTIME = 2;
     static final int PROCESS_STAT_STIME = 3;
 
-    /** Stores user time and system time in 100ths of a second. */
+    /** Stores user time and system time in jiffies. */
     private final long[] mProcessStatsData = new long[4];
 
-    /** Stores user time and system time in 100ths of a second.  Used for
+    /** Stores user time and system time in jiffies.  Used for
      * public API to retrieve CPU use for a process.  Must lock while in use. */
     private final long[] mSinglePidStatsData = new long[4];
 
diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java
index 146c0f8..2a27f70 100644
--- a/core/java/com/android/internal/os/WifiPowerCalculator.java
+++ b/core/java/com/android/internal/os/WifiPowerCalculator.java
@@ -39,10 +39,14 @@
     @Override
     public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
                              long rawUptimeUs, int statsType) {
-        final long idleTime = u.getWifiControllerActivity(BatteryStats.CONTROLLER_IDLE_TIME,
-                statsType);
-        final long txTime = u.getWifiControllerActivity(BatteryStats.CONTROLLER_TX_TIME, statsType);
-        final long rxTime = u.getWifiControllerActivity(BatteryStats.CONTROLLER_RX_TIME, statsType);
+        final BatteryStats.ControllerActivityCounter counter = u.getWifiControllerActivity();
+        if (counter == null) {
+            return;
+        }
+
+        final long idleTime = counter.getIdleTimeCounter().getCountLocked(statsType);
+        final long txTime = counter.getTxTimeCounters()[0].getCountLocked(statsType);
+        final long rxTime = counter.getRxTimeCounter().getCountLocked(statsType);
         app.wifiRunningTimeMs = idleTime + rxTime + txTime;
         app.wifiPowerMah =
                 ((idleTime * mIdleCurrentMa) + (txTime * mTxCurrentMa) + (rxTime * mRxCurrentMa))
@@ -67,16 +71,15 @@
     @Override
     public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
                                    long rawUptimeUs, int statsType) {
-        final long idleTimeMs = stats.getWifiControllerActivity(BatteryStats.CONTROLLER_IDLE_TIME,
-                statsType);
-        final long rxTimeMs = stats.getWifiControllerActivity(BatteryStats.CONTROLLER_RX_TIME,
-                statsType);
-        final long txTimeMs = stats.getWifiControllerActivity(BatteryStats.CONTROLLER_TX_TIME,
-                statsType);
+        final BatteryStats.ControllerActivityCounter counter = stats.getWifiControllerActivity();
+
+        final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(statsType);
+        final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(statsType);
+        final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(statsType);
         app.wifiRunningTimeMs = idleTimeMs + rxTimeMs + txTimeMs;
 
-        double powerDrainMah = stats.getWifiControllerActivity(BatteryStats.CONTROLLER_POWER_DRAIN,
-                statsType) / (double)(1000*60*60);
+        double powerDrainMah = counter.getPowerCounter().getCountLocked(statsType)
+                / (double)(1000*60*60);
         if (powerDrainMah == 0) {
             // Some controllers do not report power drain, so we can calculate it here.
             powerDrainMah = ((idleTimeMs * mIdleCurrentMa) + (txTimeMs * mTxCurrentMa)
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 8e318a2..6ad9e20 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -37,6 +37,8 @@
 import android.util.Log;
 import android.webkit.WebViewFactory;
 
+import com.android.internal.os.InstallerConnection.InstallerException;
+
 import dalvik.system.DexFile;
 import dalvik.system.PathClassLoader;
 import dalvik.system.VMRuntime;
@@ -498,12 +500,15 @@
                 final int dexoptNeeded = DexFile.getDexOptNeeded(
                         classPathElement, "*", instructionSet, false /* defer */);
                 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*/);
+                            dexoptNeeded, 0 /*dexFlags*/, null /*volumeUuid*/,
+                            false /*useProfiles*/);
                 }
             }
-        } catch (IOException ioe) {
-            throw new RuntimeException("Error starting system_server", ioe);
+        } catch (IOException | InstallerException e) {
+            throw new RuntimeException("Error starting system_server", e);
         } finally {
             installer.disconnect();
         }
@@ -534,7 +539,7 @@
         String args[] = {
             "--setuid=1000",
             "--setgid=1000",
-            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007,3009",
+            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007,3009,3010",
             "--capabilities=" + capabilities + "," + capabilities,
             "--nice-name=system_server",
             "--runtime-args",
diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
index 1b44ff3..de54d96 100644
--- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java
+++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
@@ -99,6 +99,9 @@
         mResizingBackgroundDrawable = resizingBackgroundDrawable;
         mCaptionBackgroundDrawable = captionBackgroundDrawableDrawable;
         mUserCaptionBackgroundDrawable = userCaptionBackgroundDrawable;
+        if (mCaptionBackgroundDrawable == null) {
+            mCaptionBackgroundDrawable = mResizingBackgroundDrawable;
+        }
         if (statusBarColor != 0) {
             mStatusBarColor = new ColorDrawable(statusBarColor);
             addSystemBarNodeIfNeeded();
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 6a1e07b..36009dc 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -17,22 +17,25 @@
 package com.android.internal.policy;
 
 import com.android.internal.R;
+import com.android.internal.policy.PhoneWindow.PanelFeatureState;
 import com.android.internal.policy.PhoneWindow.PhoneWindowMenuCallback;
 import com.android.internal.view.FloatingActionMode;
 import com.android.internal.view.RootViewSurfaceTaker;
 import com.android.internal.view.StandaloneActionMode;
 import com.android.internal.view.menu.ContextMenuBuilder;
 import com.android.internal.view.menu.MenuHelper;
-import com.android.internal.view.menu.MenuPresenter;
 import com.android.internal.widget.ActionBarContextView;
 import com.android.internal.widget.BackgroundFallback;
 import com.android.internal.widget.DecorCaptionView;
 import com.android.internal.widget.FloatingToolbar;
 
+import java.util.List;
+
 import android.animation.Animator;
 import android.animation.ObjectAnimator;
 import android.app.ActivityManager;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -49,6 +52,7 @@
 import android.view.Gravity;
 import android.view.InputQueue;
 import android.view.KeyEvent;
+import android.view.KeyboardShortcutGroup;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -72,6 +76,7 @@
 import static android.app.ActivityManager.StackId;
 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.view.View.MeasureSpec.AT_MOST;
 import static android.view.View.MeasureSpec.EXACTLY;
 import static android.view.View.MeasureSpec.getMode;
@@ -85,11 +90,14 @@
 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static com.android.internal.policy.PhoneWindow.FEATURE_OPTIONS_PANEL;
 
 /** @hide */
 public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
     private static final String TAG = "DecorView";
 
+    private static final boolean DEBUG_MEASURE = false;
+
     private static final boolean SWEEP_OPEN_MENU = false;
 
     // The height of a window which has focus in DIP.
@@ -194,7 +202,12 @@
     private Drawable mCaptionBackgroundDrawable;
     private Drawable mUserCaptionBackgroundDrawable;
 
-    DecorView(Context context, int featureId, PhoneWindow window) {
+    private float mAvailableWidth;
+
+    String mLogTag = TAG;
+
+    DecorView(Context context, int featureId, PhoneWindow window,
+            WindowManager.LayoutParams params) {
         super(context);
         mFeatureId = featureId;
 
@@ -210,7 +223,11 @@
         mSemiTransparentStatusBarColor = context.getResources().getColor(
                 R.color.system_bar_background_semi_transparent, null /* theme */);
 
+        updateAvailableWidth();
+
         setWindow(window);
+
+        updateLogTag(params);
     }
 
     void setBackgroundFallback(int resId) {
@@ -408,7 +425,7 @@
 
         if (mFeatureId >= 0) {
             if (action == MotionEvent.ACTION_DOWN) {
-                Log.i(TAG, "Watchiing!");
+                Log.i(mLogTag, "Watchiing!");
                 mWatchingForMenu = true;
                 mDownY = (int) event.getY();
                 return false;
@@ -421,7 +438,7 @@
             int y = (int)event.getY();
             if (action == MotionEvent.ACTION_MOVE) {
                 if (y > (mDownY+30)) {
-                    Log.i(TAG, "Closing!");
+                    Log.i(mLogTag, "Closing!");
                     mWindow.closePanel(mFeatureId);
                     mWatchingForMenu = false;
                     return true;
@@ -433,13 +450,13 @@
             return false;
         }
 
-        //Log.i(TAG, "Intercept: action=" + action + " y=" + event.getY()
+        //Log.i(mLogTag, "Intercept: action=" + action + " y=" + event.getY()
         //        + " (in " + getHeight() + ")");
 
         if (action == MotionEvent.ACTION_DOWN) {
             int y = (int)event.getY();
             if (y >= (getHeight()-5) && !mWindow.hasChildren()) {
-                Log.i(TAG, "Watching!");
+                Log.i(mLogTag, "Watching!");
                 mWatchingForMenu = true;
             }
             return false;
@@ -452,7 +469,7 @@
         int y = (int)event.getY();
         if (action == MotionEvent.ACTION_MOVE) {
             if (y < (getHeight()-30)) {
-                Log.i(TAG, "Opening!");
+                Log.i(mLogTag, "Opening!");
                 mWindow.openPanel(Window.FEATURE_OPTIONS_PANEL, new KeyEvent(
                         KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU));
                 mWatchingForMenu = false;
@@ -543,15 +560,15 @@
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
-        final boolean isPortrait = metrics.widthPixels < metrics.heightPixels;
+        final boolean isPortrait =
+                getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT;
 
         final int widthMode = getMode(widthMeasureSpec);
         final int heightMode = getMode(heightMeasureSpec);
 
         boolean fixedWidth = false;
         if (widthMode == AT_MOST) {
-            final TypedValue tvw = isPortrait ? mWindow.mFixedWidthMinor
-                    : mWindow.mFixedWidthMajor;
+            final TypedValue tvw = isPortrait ? mWindow.mFixedWidthMinor : mWindow.mFixedWidthMajor;
             if (tvw != null && tvw.type != TypedValue.TYPE_NULL) {
                 final int w;
                 if (tvw.type == TypedValue.TYPE_DIMENSION) {
@@ -561,7 +578,7 @@
                 } else {
                     w = 0;
                 }
-
+                if (DEBUG_MEASURE) Log.d(mLogTag, "Fixed width: " + w);
                 if (w > 0) {
                     final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
                     widthMeasureSpec = MeasureSpec.makeMeasureSpec(
@@ -583,6 +600,7 @@
                 } else {
                     h = 0;
                 }
+                if (DEBUG_MEASURE) Log.d(mLogTag, "Fixed height: " + h);
                 if (h > 0) {
                     final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
                     heightMeasureSpec = MeasureSpec.makeMeasureSpec(
@@ -623,10 +641,12 @@
                 if (tv.type == TypedValue.TYPE_DIMENSION) {
                     min = (int)tv.getDimension(metrics);
                 } else if (tv.type == TypedValue.TYPE_FRACTION) {
-                    min = (int)tv.getFraction(metrics.widthPixels, metrics.widthPixels);
+                    min = (int)tv.getFraction(mAvailableWidth, mAvailableWidth);
                 } else {
                     min = 0;
                 }
+                if (DEBUG_MEASURE) Log.d(mLogTag, "Adjust for min width: " + min + ", value::"
+                        + tv.coerceToString() + ", mAvailableWidth=" + mAvailableWidth);
 
                 if (width < min) {
                     widthMeasureSpec = MeasureSpec.makeMeasureSpec(min, EXACTLY);
@@ -702,11 +722,13 @@
             helper = mWindow.mContextMenu.showDialog(originalView, originalView.getWindowToken());
         }
 
-        // If it's a dialog, the callback needs to handle showing sub-menus.
-        // Either way, the callback is required for propagating selection to
-        // Context.onContextMenuItemSelected().
-        callback.setShowDialogForSubmenu(!isPopup);
-        helper.setPresenterCallback(callback);
+        if (helper != null) {
+            // If it's a dialog, the callback needs to handle showing
+            // sub-menus. Either way, the callback is required for propagating
+            // selection to Context.onContextMenuItemSelected().
+            callback.setShowDialogForSubmenu(!isPopup);
+            helper.setPresenterCallback(callback);
+        }
 
         mWindow.mContextMenuHelper = helper;
         return helper != null;
@@ -1215,7 +1237,7 @@
                     int fop = fg.getOpacity();
                     int bop = bg.getOpacity();
                     if (false)
-                        Log.v(TAG, "Background opacity: " + bop + ", Frame opacity: " + fop);
+                        Log.v(mLogTag, "Background opacity: " + bop + ", Frame opacity: " + fop);
                     if (fop == PixelFormat.OPAQUE || bop == PixelFormat.OPAQUE) {
                         opacity = PixelFormat.OPAQUE;
                     } else if (fop == PixelFormat.UNKNOWN) {
@@ -1230,16 +1252,16 @@
                     // frame with padding... there is no way to tell if the
                     // frame and background together will draw all pixels.
                     if (false)
-                        Log.v(TAG, "Padding: " + mFramePadding);
+                        Log.v(mLogTag, "Padding: " + mFramePadding);
                     opacity = PixelFormat.TRANSLUCENT;
                 }
             }
             if (false)
-                Log.v(TAG, "Background: " + bg + ", Frame: " + fg);
+                Log.v(mLogTag, "Background: " + bg + ", Frame: " + fg);
         }
 
         if (false)
-            Log.v(TAG, "Selected default opacity: " + opacity);
+            Log.v(mLogTag, "Selected default opacity: " + opacity);
 
         mDefaultOpacity = opacity;
         if (mFeatureId < 0) {
@@ -1575,7 +1597,9 @@
         }
     }
 
-    void onConfigurationChanged() {
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
         int workspaceId = getStackId();
         if (mStackId != workspaceId) {
             mStackId = workspaceId;
@@ -1598,20 +1622,15 @@
                 enableCaption(StackId.hasWindowDecor(workspaceId));
             }
         }
+        updateAvailableWidth();
         initializeElevation();
     }
 
     void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
         mStackId = getStackId();
 
-        mResizingBackgroundDrawable = getResizingBackgroundDrawable(
-                mWindow.mBackgroundResource, mWindow.mBackgroundFallbackResource);
-        if (mCaptionBackgroundDrawable == null) {
-            mCaptionBackgroundDrawable = getContext().getDrawable(
-                    R.drawable.decor_caption_title_focused);
-        }
-
         if (mBackdropFrameRenderer != null) {
+            loadBackgroundDrawablesIfNeeded();
             mBackdropFrameRenderer.onResourcesLoaded(
                     this, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
                     mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState));
@@ -1633,6 +1652,17 @@
         initializeElevation();
     }
 
+    private void loadBackgroundDrawablesIfNeeded() {
+        if (mResizingBackgroundDrawable == null) {
+            mResizingBackgroundDrawable = getResizingBackgroundDrawable(
+                    mWindow.mBackgroundResource, mWindow.mBackgroundFallbackResource);
+        }
+        if (mCaptionBackgroundDrawable == null) {
+            mCaptionBackgroundDrawable = getContext().getDrawable(
+                    R.drawable.decor_caption_title_focused);
+        }
+    }
+
     // Free floating overlapping windows require a caption.
     private DecorCaptionView createDecorCaptionView(LayoutInflater inflater) {
         DecorCaptionView decorCaptionView = null;
@@ -1742,7 +1772,7 @@
 
         // We shouldn't really get here as the background fallback should be always available since
         // it is defaulted by the system.
-        Log.w(TAG, "Failed to find background drawable for PhoneWindow=" + mWindow);
+        Log.w(mLogTag, "Failed to find background drawable for PhoneWindow=" + mWindow);
         return null;
     }
 
@@ -1759,7 +1789,7 @@
             try {
                 workspaceId = callback.getWindowStackId();
             } catch (RemoteException ex) {
-                Log.e(TAG, "Failed to get the workspace ID of a PhoneWindow.");
+                Log.e(mLogTag, "Failed to get the workspace ID of a PhoneWindow.");
             }
         }
         if (workspaceId == INVALID_STACK_ID) {
@@ -1803,6 +1833,7 @@
         }
         final ThreadedRenderer renderer = getHardwareRenderer();
         if (renderer != null) {
+            loadBackgroundDrawablesIfNeeded();
             mBackdropFrameRenderer = new BackdropFrameRenderer(this, renderer,
                     initialBounds, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
                     mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState));
@@ -1925,6 +1956,49 @@
         }
     }
 
+    private static String getTitleSuffix(WindowManager.LayoutParams params) {
+        if (params == null) {
+            return "";
+        }
+        final String[] split = params.getTitle().toString().split("\\.");
+        if (split.length > 0) {
+            return split[split.length - 1];
+        } else {
+            return "";
+        }
+    }
+
+    void updateLogTag(WindowManager.LayoutParams params) {
+        mLogTag = TAG + "[" + getTitleSuffix(params) + "]";
+    }
+
+    private void updateAvailableWidth() {
+        Resources res = getResources();
+        mAvailableWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                res.getConfiguration().screenWidthDp, res.getDisplayMetrics());
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> list) {
+        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.
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "DecorView@" + Integer.toHexString(this.hashCode()) + "["
+                + getTitleSuffix(mWindow.getAttributes()) + "]";
+    }
+
     private static class ColorViewState {
         View view = null;
         int targetVisibility = View.INVISIBLE;
@@ -1986,12 +2060,12 @@
                 isPrimary = mode == mPrimaryActionMode;
                 isFloating = mode == mFloatingActionMode;
                 if (!isPrimary && mode.getType() == ActionMode.TYPE_PRIMARY) {
-                    Log.e(TAG, "Destroying unexpected ActionMode instance of TYPE_PRIMARY; "
+                    Log.e(mLogTag, "Destroying unexpected ActionMode instance of TYPE_PRIMARY; "
                             + mode + " was not the current primary action mode! Expected "
                             + mPrimaryActionMode);
                 }
                 if (!isFloating && mode.getType() == ActionMode.TYPE_FLOATING) {
-                    Log.e(TAG, "Destroying unexpected ActionMode instance of TYPE_FLOATING; "
+                    Log.e(mLogTag, "Destroying unexpected ActionMode instance of TYPE_FLOATING; "
                             + mode + " was not the current floating action mode! Expected "
                             + mFloatingActionMode);
                 }
diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
new file mode 100644
index 0000000..a38139f
--- /dev/null
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.policy;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+/**
+ * Calculates the snap targets and the snap position given a position and a velocity. All positions
+ * here are to be interpreted as the left/top edge of the divider rectangle.
+ *
+ * @hide
+ */
+public class DividerSnapAlgorithm {
+
+    private static final int MIN_FLING_VELOCITY_DP_PER_SECOND = 400;
+    private static final int MIN_DISMISS_VELOCITY_DP_PER_SECOND = 600;
+
+    /**
+     * 3 snap targets: left/top has 16:9 ratio (for videos), 1:1, and right/bottom has 16:9 ratio
+     */
+    private static final int SNAP_MODE_16_9 = 0;
+
+    /**
+     * 3 snap targets: fixed ratio, 1:1, (1 - fixed ratio)
+     */
+    private static final int SNAP_FIXED_RATIO = 1;
+
+    /**
+     * 1 snap target: 1:1
+     */
+    private static final int SNAP_ONLY_1_1 = 2;
+
+    private final float mMinFlingVelocityPxPerSecond;
+    private final float mMinDismissVelocityPxPerSecond;
+    private final int mDisplayWidth;
+    private final int mDisplayHeight;
+    private final int mDividerSize;
+    private final ArrayList<SnapTarget> mTargets = new ArrayList<>();
+    private final Rect mInsets = new Rect();
+    private final int mSnapMode;
+    private final float mFixedRatio;
+
+    /** The first target which is still splitting the screen */
+    private final SnapTarget mFirstSplitTarget;
+
+    /** The last target which is still splitting the screen */
+    private final SnapTarget mLastSplitTarget;
+
+    private final SnapTarget mDismissStartTarget;
+    private final SnapTarget mDismissEndTarget;
+    private final SnapTarget mMiddleTarget;
+
+    public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
+            boolean isHorizontalDivision, Rect insets) {
+        mMinFlingVelocityPxPerSecond =
+                MIN_FLING_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density;
+        mMinDismissVelocityPxPerSecond =
+                MIN_DISMISS_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density;
+        mDividerSize = dividerSize;
+        mDisplayWidth = displayWidth;
+        mDisplayHeight = displayHeight;
+        mInsets.set(insets);
+        mSnapMode = res.getInteger(
+                com.android.internal.R.integer.config_dockedStackDividerSnapMode);
+        mFixedRatio = res.getFraction(
+                com.android.internal.R.fraction.docked_stack_divider_fixed_ratio, 1, 1);
+        calculateTargets(isHorizontalDivision);
+        mFirstSplitTarget = mTargets.get(1);
+        mLastSplitTarget = mTargets.get(mTargets.size() - 2);
+        mDismissStartTarget = mTargets.get(0);
+        mDismissEndTarget = mTargets.get(mTargets.size() - 1);
+        mMiddleTarget = mTargets.get(mTargets.size() / 2);
+    }
+
+    public SnapTarget calculateSnapTarget(int position, float velocity) {
+        return calculateSnapTarget(position, velocity, true /* hardDismiss */);
+    }
+
+    /**
+     * @param position the top/left position of the divider
+     * @param velocity current dragging velocity
+     * @param hardDismiss if set, make it a bit harder to get reach the dismiss targets
+     */
+    public SnapTarget calculateSnapTarget(int position, float velocity, boolean hardDismiss) {
+        if (position < mFirstSplitTarget.position && velocity < -mMinDismissVelocityPxPerSecond) {
+            return mDismissStartTarget;
+        }
+        if (position > mLastSplitTarget.position && velocity > mMinDismissVelocityPxPerSecond) {
+            return mDismissEndTarget;
+        }
+        if (Math.abs(velocity) < mMinFlingVelocityPxPerSecond) {
+            return snap(position, hardDismiss);
+        }
+        if (velocity < 0) {
+            return mFirstSplitTarget;
+        } else {
+            return mLastSplitTarget;
+        }
+    }
+
+    public SnapTarget calculateNonDismissingSnapTarget(int position) {
+        SnapTarget target = snap(position, false /* hardDismiss */);
+        if (target == mDismissStartTarget) {
+            return mFirstSplitTarget;
+        } else if (target == mDismissEndTarget) {
+            return mLastSplitTarget;
+        } else {
+            return target;
+        }
+    }
+
+    public float calculateDismissingFraction(int position) {
+        if (position < mFirstSplitTarget.position) {
+            return 1f - (float) position / mFirstSplitTarget.position;
+        } else if (position > mLastSplitTarget.position) {
+            return (float) (position - mLastSplitTarget.position)
+                    / (mDismissEndTarget.position - mLastSplitTarget.position);
+        }
+        return 0f;
+    }
+
+    public SnapTarget getClosestDismissTarget(int position) {
+        if (position < mFirstSplitTarget.position) {
+            return mDismissStartTarget;
+        } else if (position > mLastSplitTarget.position) {
+            return mDismissEndTarget;
+        } else if (position - mDismissStartTarget.position
+                < mDismissEndTarget.position - position) {
+            return mDismissStartTarget;
+        } else {
+            return mDismissEndTarget;
+        }
+    }
+
+    public SnapTarget getFirstSplitTarget() {
+        return mFirstSplitTarget;
+    }
+
+    public SnapTarget getLastSplitTarget() {
+        return mLastSplitTarget;
+    }
+
+    public SnapTarget getDismissStartTarget() {
+        return mDismissStartTarget;
+    }
+
+    public SnapTarget getDismissEndTarget() {
+        return mDismissEndTarget;
+    }
+
+    private SnapTarget snap(int position, boolean hardDismiss) {
+        int minIndex = -1;
+        float minDistance = Float.MAX_VALUE;
+        int size = mTargets.size();
+        for (int i = 0; i < size; i++) {
+            SnapTarget target = mTargets.get(i);
+            float distance = Math.abs(position - target.position);
+            if (hardDismiss) {
+                distance /= target.distanceMultiplier;
+            }
+            if (distance < minDistance) {
+                minIndex = i;
+                minDistance = distance;
+            }
+        }
+        return mTargets.get(minIndex);
+    }
+
+    private void calculateTargets(boolean isHorizontalDivision) {
+        mTargets.clear();
+        int dividerMax = isHorizontalDivision
+                ? mDisplayHeight
+                : mDisplayWidth;
+        mTargets.add(new SnapTarget(-mDividerSize, SnapTarget.FLAG_DISMISS_START, 0.35f));
+        switch (mSnapMode) {
+            case SNAP_MODE_16_9:
+                addRatio16_9Targets(isHorizontalDivision);
+                break;
+            case SNAP_FIXED_RATIO:
+                addFixedDivisionTargets(isHorizontalDivision);
+                break;
+            case SNAP_ONLY_1_1:
+                addMiddleTarget(isHorizontalDivision);
+                break;
+        }
+        mTargets.add(new SnapTarget(dividerMax, SnapTarget.FLAG_DISMISS_END, 0.35f));
+    }
+
+    private void addFixedDivisionTargets(boolean isHorizontalDivision) {
+        int start = isHorizontalDivision ? mInsets.top : mInsets.left;
+        int end = isHorizontalDivision
+                ? mDisplayHeight - mInsets.bottom
+                : mDisplayWidth - mInsets.right;
+        mTargets.add(new SnapTarget((int) (start + mFixedRatio * (end - start)) - mDividerSize / 2,
+                SnapTarget.FLAG_NONE));
+        addMiddleTarget(isHorizontalDivision);
+        mTargets.add(new SnapTarget((int) (start + (1 - mFixedRatio) * (end - start))
+                - mDividerSize / 2, SnapTarget.FLAG_NONE));
+    }
+
+    private void addRatio16_9Targets(boolean isHorizontalDivision) {
+        int start = isHorizontalDivision ? mInsets.top : mInsets.left;
+        int end = isHorizontalDivision
+                ? mDisplayHeight - mInsets.bottom
+                : mDisplayWidth - mInsets.right;
+        int startOther = isHorizontalDivision ? mInsets.left : mInsets.top;
+        int endOther = isHorizontalDivision
+                ? mDisplayWidth - mInsets.right
+                : mDisplayHeight - mInsets.bottom;
+        float size = 9.0f / 16.0f * (endOther - startOther);
+        int sizeInt = (int) Math.floor(size);
+        mTargets.add(new SnapTarget(start + sizeInt, SnapTarget.FLAG_NONE));
+        addMiddleTarget(isHorizontalDivision);
+        mTargets.add(new SnapTarget(end - sizeInt - mDividerSize, SnapTarget.FLAG_NONE));
+    }
+
+    private void addMiddleTarget(boolean isHorizontalDivision) {
+        mTargets.add(new SnapTarget(DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision,
+                mInsets, mDisplayWidth, mDisplayHeight, mDividerSize), SnapTarget.FLAG_NONE));
+    }
+
+    public SnapTarget getMiddleTarget() {
+        return mMiddleTarget;
+    }
+
+    public SnapTarget getNextTarget(SnapTarget snapTarget) {
+        int index = mTargets.indexOf(snapTarget);
+        if (index != -1 && index < mTargets.size() - 1) {
+            return mTargets.get(index + 1);
+        }
+        return snapTarget;
+    }
+
+    public SnapTarget getPreviousTarget(SnapTarget snapTarget) {
+        int index = mTargets.indexOf(snapTarget);
+        if (index != -1 && index > 0) {
+            return mTargets.get(index - 1);
+        }
+        return snapTarget;
+    }
+
+    /**
+     * Represents a snap target for the divider.
+     */
+    public static class SnapTarget {
+        public static final int FLAG_NONE = 0;
+
+        /** If the divider reaches this value, the left/top task should be dismissed. */
+        public static final int FLAG_DISMISS_START = 1;
+
+        /** If the divider reaches this value, the right/bottom task should be dismissed */
+        public static final int FLAG_DISMISS_END = 2;
+
+        public final int position;
+        public final int flag;
+
+        /**
+         * Multiplier used to calculate distance to snap position. The lower this value, the harder
+         * it's to snap on this target
+         */
+        private final float distanceMultiplier;
+
+        public SnapTarget(int position, int flag) {
+            this(position, flag, 1f);
+        }
+
+        public SnapTarget(int position, int flag, float distanceMultiplier) {
+            this.position = position;
+            this.flag = flag;
+            this.distanceMultiplier = distanceMultiplier;
+        }
+    }
+}
diff --git a/core/java/com/android/internal/policy/DockedDividerUtils.java b/core/java/com/android/internal/policy/DockedDividerUtils.java
new file mode 100644
index 0000000..00c65bd
--- /dev/null
+++ b/core/java/com/android/internal/policy/DockedDividerUtils.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.policy;
+
+import android.graphics.Rect;
+import android.view.WindowManager;
+
+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;
+
+/**
+ * Utility functions for docked stack divider used by both window manager and System UI.
+ *
+ * @hide
+ */
+public class DockedDividerUtils {
+
+    public static void calculateBoundsForPosition(int position, int dockSide, Rect outRect,
+            int displayWidth, int displayHeight, int dividerSize) {
+        outRect.set(0, 0, displayWidth, displayHeight);
+        switch (dockSide) {
+            case WindowManager.DOCKED_LEFT:
+                outRect.right = position;
+                break;
+            case WindowManager.DOCKED_TOP:
+                outRect.bottom = position;
+                break;
+            case WindowManager.DOCKED_RIGHT:
+                outRect.left = position + dividerSize;
+                break;
+            case WindowManager.DOCKED_BOTTOM:
+                outRect.top = position + dividerSize;
+                break;
+        }
+        sanitizeStackBounds(outRect);
+    }
+
+    public static void sanitizeStackBounds(Rect bounds) {
+        if (bounds.left >= bounds.right) {
+            bounds.left = bounds.right - 1;
+        }
+        if (bounds.top >= bounds.bottom) {
+            bounds.top = bounds.bottom - 1;
+        }
+        if (bounds.right <= bounds.left) {
+            bounds.right = bounds.left + 1;
+        }
+        if (bounds.bottom <= bounds.top) {
+            bounds.bottom = bounds.top + 1;
+        }
+    }
+
+    public static int calculatePositionForBounds(Rect bounds, int dockSide, int dividerSize) {
+        switch (dockSide) {
+            case WindowManager.DOCKED_LEFT:
+                return bounds.right;
+            case WindowManager.DOCKED_TOP:
+                return bounds.bottom;
+            case WindowManager.DOCKED_RIGHT:
+                return bounds.left - dividerSize;
+            case WindowManager.DOCKED_BOTTOM:
+                return bounds.top - dividerSize;
+            default:
+                return 0;
+        }
+    }
+
+    public static int calculateMiddlePosition(boolean isHorizontalDivision, Rect insets,
+            int displayWidth, int displayHeight, int dividerSize) {
+        int start = isHorizontalDivision ? insets.top : insets.left;
+        int end = isHorizontalDivision
+                ? displayHeight - insets.bottom
+                : displayWidth - insets.right;
+        return start + (end - start) / 2 - dividerSize / 2;
+    }
+
+    public static int getDockSideFromCreatedMode(boolean dockOnTopOrLeft,
+            boolean isHorizontalDivision) {
+        if (dockOnTopOrLeft) {
+            if (isHorizontalDivision) {
+                return DOCKED_TOP;
+            } else {
+                return DOCKED_LEFT;
+            }
+        } else {
+            if (isHorizontalDivision) {
+                return DOCKED_BOTTOM;
+            } else {
+                return DOCKED_RIGHT;
+            }
+        }
+    }
+
+    public static int invertDockSide(int dockSide) {
+        switch (dockSide) {
+            case WindowManager.DOCKED_LEFT:
+                return WindowManager.DOCKED_RIGHT;
+            case WindowManager.DOCKED_TOP:
+                return WindowManager.DOCKED_BOTTOM;
+            case WindowManager.DOCKED_RIGHT:
+                return WindowManager.DOCKED_LEFT;
+            case WindowManager.DOCKED_BOTTOM:
+                return WindowManager.DOCKED_TOP;
+            default:
+                return WindowManager.DOCKED_INVALID;
+        }
+    }
+}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 2d8bfd4..19ed11a 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -113,6 +113,8 @@
 
     private final static String TAG = "PhoneWindow";
 
+    private static final boolean DEBUG = false;
+
     private final static int DEFAULT_BACKGROUND_FADE_DURATION_MS = 300;
 
     private static final int CUSTOM_TITLE_COMPATIBLE_FEATURES = DEFAULT_FEATURES |
@@ -146,6 +148,9 @@
     // This is the view in which the window contents are placed. It is either
     // mDecor itself, or a child of mDecor where the contents go.
     ViewGroup mContentParent;
+    // Whether the client has explicitly set the content view. If false and mContentParent is not
+    // null, then the content parent was set due to window preservation.
+    private boolean mContentParentExplicitlySet = false;
 
     Callback2 mTakeSurfaceCallback;
 
@@ -274,6 +279,8 @@
 
     private int mDecorCaptionShade = DECOR_CAPTION_SHADE_AUTO;
 
+    private boolean mUseDecorContext = false;
+
     static class WindowManagerHolder {
         static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
                 ServiceManager.getService("window"));
@@ -286,8 +293,14 @@
         mLayoutInflater = LayoutInflater.from(context);
     }
 
+    /**
+     * Constructor for main window of an activity.
+     */
     public PhoneWindow(Context context, Window preservedWindow) {
         this(context);
+        // Only main activity windows use decor context, all the other windows depend on whatever
+        // context that was given to them.
+        mUseDecorContext = true;
         if (preservedWindow != null) {
             mDecor = (DecorView) preservedWindow.getDecorView();
             mElevation = preservedWindow.getElevation();
@@ -307,7 +320,7 @@
 
     @Override
     public boolean requestFeature(int featureId) {
-        if (mContentParent != null) {
+        if (mContentParentExplicitlySet) {
             throw new AndroidRuntimeException("requestFeature() must be called before adding content");
         }
         final int features = getFeatures();
@@ -391,6 +404,7 @@
         if (cb != null && !isDestroyed()) {
             cb.onContentChanged();
         }
+        mContentParentExplicitlySet = true;
     }
 
     @Override
@@ -421,6 +435,7 @@
         if (cb != null && !isDestroyed()) {
             cb.onContentChanged();
         }
+        mContentParentExplicitlySet = true;
     }
 
     @Override
@@ -657,15 +672,19 @@
                 }
             }
         }
-        if (mDecor != null) {
-            mDecor.onConfigurationChanged();
-        }
     }
 
     @Override
     public void onMultiWindowModeChanged() {
         if (mDecor != null) {
-            mDecor.onConfigurationChanged();
+            mDecor.onConfigurationChanged(getContext().getResources().getConfiguration());
+        }
+    }
+
+    @Override
+    public void reportActivityRelaunched() {
+        if (mDecor != null && mDecor.getViewRootImpl() != null) {
+            mDecor.getViewRootImpl().reportActivityRelaunched();
         }
     }
 
@@ -2259,17 +2278,21 @@
         // System process doesn't have application context and in that case we need to directly use
         // the context we have. Otherwise we want the application context, so we don't cling to the
         // activity.
-        Context applicationContext = getContext().getApplicationContext();
         Context context;
-        if (applicationContext == null) {
-            context = getContext();
-        } else {
-            context = new DecorContext(applicationContext);
-            if (mTheme != -1) {
-                context.setTheme(mTheme);
+        if (mUseDecorContext) {
+            Context applicationContext = getContext().getApplicationContext();
+            if (applicationContext == null) {
+                context = getContext();
+            } else {
+                context = new DecorContext(applicationContext);
+                if (mTheme != -1) {
+                    context.setTheme(mTheme);
+                }
             }
+        } else {
+            context = getContext();
         }
-        return new DecorView(context, featureId, this);
+        return new DecorView(context, featureId, this, getAttributes());
     }
 
     protected ViewGroup generateLayout(DecorView decor) {
@@ -2348,6 +2371,8 @@
 
         a.getValue(R.styleable.Window_windowMinWidthMajor, mMinWidthMajor);
         a.getValue(R.styleable.Window_windowMinWidthMinor, mMinWidthMinor);
+        if (DEBUG) Log.d(TAG, "Min width minor: " + mMinWidthMinor.coerceToString()
+                + ", major: " + mMinWidthMajor.coerceToString());
         if (a.hasValue(R.styleable.Window_windowFixedWidthMajor)) {
             if (mFixedWidthMajor == null) mFixedWidthMajor = new TypedValue();
             a.getValue(R.styleable.Window_windowFixedWidthMajor,
@@ -2656,20 +2681,16 @@
                     invalidatePanelMenu(FEATURE_ACTION_BAR);
                 }
             } else {
-                mTitleView = (TextView)findViewById(R.id.title);
+                mTitleView = (TextView) findViewById(R.id.title);
                 if (mTitleView != null) {
-                    mTitleView.setLayoutDirection(mDecor.getLayoutDirection());
                     if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
-                        View titleContainer = findViewById(
-                                R.id.title_container);
+                        final View titleContainer = findViewById(R.id.title_container);
                         if (titleContainer != null) {
                             titleContainer.setVisibility(View.GONE);
                         } else {
                             mTitleView.setVisibility(View.GONE);
                         }
-                        if (mContentParent instanceof FrameLayout) {
-                            ((FrameLayout)mContentParent).setForeground(null);
-                        }
+                        mContentParent.setForeground(null);
                     } else {
                         mTitleView.setText(mTitle);
                     }
@@ -3764,4 +3785,12 @@
     int getDecorCaptionShade() {
         return mDecorCaptionShade;
     }
+
+    @Override
+    public void setAttributes(WindowManager.LayoutParams params) {
+        super.setAttributes(params);
+        if (mDecor != null) {
+            mDecor.updateLogTag(params);
+        }
+    }
 }
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 849d314..632285c 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -24,8 +24,8 @@
 /** @hide */
 oneway interface IStatusBar
 {
-    void setIcon(int index, in StatusBarIcon icon);
-    void removeIcon(int index);
+    void setIcon(String slot, in StatusBarIcon icon);
+    void removeIcon(String slot);
     void disable(int state1, int state2);
     void animateExpandNotificationsPanel();
     void animateExpandSettingsPanel(String subPanel);
@@ -46,7 +46,7 @@
     void cancelPreloadRecentApps();
     void showScreenPinningRequest();
 
-    void showKeyboardShortcutsMenu();
+    void toggleKeyboardShortcutsMenu();
 
     /**
      * Notifies the status bar that an app transition is pending to delay applying some flags with
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 0a4ad06..32de45c 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -44,7 +44,8 @@
 
     // ---- Methods below are for use by the status bar policy services ----
     // You need the STATUS_BAR_SERVICE permission
-    void registerStatusBar(IStatusBar callbacks, out StatusBarIconList iconList,
+    void registerStatusBar(IStatusBar callbacks, out List<String> iconSlots,
+            out List<StatusBarIcon> iconList,
             out int[] switches, out List<IBinder> binders);
     void onPanelRevealed(boolean clearNotificationEffects, int numItems);
     void onPanelHidden();
@@ -68,7 +69,7 @@
     void preloadRecentApps();
     void cancelPreloadRecentApps();
 
-    void showKeyboardShortcutsMenu();
+    void toggleKeyboardShortcutsMenu();
 
     /**
      * Notifies the status bar that an app transition is pending to delay applying some flags with
diff --git a/core/java/com/android/internal/statusbar/StatusBarIconList.java b/core/java/com/android/internal/statusbar/StatusBarIconList.java
deleted file mode 100644
index 478d245..0000000
--- a/core/java/com/android/internal/statusbar/StatusBarIconList.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.statusbar;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.io.PrintWriter;
-
-public class StatusBarIconList implements Parcelable {
-    private String[] mSlots;
-    private StatusBarIcon[] mIcons;
-
-    public StatusBarIconList() {
-    }
-
-    public StatusBarIconList(Parcel in) {
-        readFromParcel(in);
-    }
-    
-    public void readFromParcel(Parcel in) {
-        this.mSlots = in.readStringArray();
-        final int N = in.readInt();
-        if (N < 0) {
-            mIcons = null;
-        } else {
-            mIcons = new StatusBarIcon[N];
-            for (int i=0; i<N; i++) {
-                if (in.readInt() != 0) {
-                    mIcons[i] = new StatusBarIcon(in);
-                }
-            }
-        }
-    }
-
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeStringArray(mSlots);
-        if (mIcons == null) {
-            out.writeInt(-1);
-        } else {
-            final int N = mIcons.length;
-            out.writeInt(N);
-            for (int i=0; i<N; i++) {
-                StatusBarIcon ic = mIcons[i];
-                if (ic == null) {
-                    out.writeInt(0);
-                } else {
-                    out.writeInt(1);
-                    ic.writeToParcel(out, flags);
-                }
-            }
-        }
-    }
-
-    public int describeContents() {
-        return 0;
-    }
-
-    /**
-     * Parcelable.Creator that instantiates StatusBarIconList objects
-     */
-    public static final Parcelable.Creator<StatusBarIconList> CREATOR
-            = new Parcelable.Creator<StatusBarIconList>()
-    {
-        public StatusBarIconList createFromParcel(Parcel parcel)
-        {
-            return new StatusBarIconList(parcel);
-        }
-
-        public StatusBarIconList[] newArray(int size)
-        {
-            return new StatusBarIconList[size];
-        }
-    };
-
-    public void defineSlots(String[] slots) {
-        final int N = slots.length;
-        String[] s = mSlots = new String[N];
-        for (int i=0; i<N; i++) {
-            s[i] = slots[i];
-        }
-        mIcons = new StatusBarIcon[N];
-    }
-
-    public int getSlotIndex(String slot) {
-        final int N = mSlots.length;
-        for (int i=0; i<N; i++) {
-            if (slot.equals(mSlots[i])) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    public int size() {
-        return mSlots.length;
-    }
-
-    public void setIcon(int index, StatusBarIcon icon) {
-        mIcons[index] = icon.clone();
-    }
-
-    public void removeIcon(int index) {
-        mIcons[index] = null;
-    }
-
-    public String getSlot(int index) {
-        return mSlots[index];
-    }
-
-    public StatusBarIcon getIcon(int index) {
-        return mIcons[index];
-    }
-
-    public int getViewIndex(int index) {
-        int count = 0;
-        for (int i=0; i<index; i++) {
-            if (mIcons[i] != null) {
-                count++;
-            }
-        }
-        return count;
-    }
-
-    public void copyFrom(StatusBarIconList that) {
-        if (that.mSlots == null) {
-            this.mSlots = null;
-            this.mIcons = null;
-        } else {
-            final int N = that.mSlots.length;
-            this.mSlots = new String[N];
-            this.mIcons = new StatusBarIcon[N];
-            for (int i=0; i<N; i++) {
-                this.mSlots[i] = that.mSlots[i];
-                this.mIcons[i] = that.mIcons[i] != null ? that.mIcons[i].clone() : null;
-            }
-        }
-    }
-
-    public void dump(PrintWriter pw) {
-        final int N = mSlots.length;
-        pw.println("Icon list:");
-        for (int i=0; i<N; i++) {
-            pw.printf("  %2d: (%s) %s\n", i, mSlots[i], mIcons[i]);
-        }
-    }
-}
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index e8970bc..ca1334c 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -26,6 +26,7 @@
 
 import java.lang.reflect.Array;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Objects;
 
 /**
@@ -125,28 +126,28 @@
     /**
      * Checks if given array is null or has zero elements.
      */
-    public static <T> boolean isEmpty(T[] array) {
+    public static <T> boolean isEmpty(@Nullable T[] array) {
         return array == null || array.length == 0;
     }
 
     /**
      * Checks if given array is null or has zero elements.
      */
-    public static boolean isEmpty(int[] array) {
+    public static boolean isEmpty(@Nullable int[] array) {
         return array == null || array.length == 0;
     }
 
     /**
      * Checks if given array is null or has zero elements.
      */
-    public static boolean isEmpty(long[] array) {
+    public static boolean isEmpty(@Nullable long[] array) {
         return array == null || array.length == 0;
     }
 
     /**
      * Checks if given array is null or has zero elements.
      */
-    public static boolean isEmpty(byte[] array) {
+    public static boolean isEmpty(@Nullable byte[] array) {
         return array == null || array.length == 0;
     }
 
@@ -156,7 +157,7 @@
      * @param value the value to check for
      * @return true if the value is present in the array
      */
-    public static <T> boolean contains(T[] array, T value) {
+    public static <T> boolean contains(@Nullable T[] array, T value) {
         return indexOf(array, value) != -1;
     }
 
@@ -164,7 +165,7 @@
      * Return first index of {@code value} in {@code array}, or {@code -1} if
      * not found.
      */
-    public static <T> int indexOf(T[] array, T value) {
+    public static <T> int indexOf(@Nullable T[] array, T value) {
         if (array == null) return -1;
         for (int i = 0; i < array.length; i++) {
             if (Objects.equals(array[i], value)) return i;
@@ -175,7 +176,7 @@
     /**
      * Test if all {@code check} items are contained in {@code array}.
      */
-    public static <T> boolean containsAll(T[] array, T[] check) {
+    public static <T> boolean containsAll(@Nullable T[] array, T[] check) {
         if (check == null) return true;
         for (T checkItem : check) {
             if (!contains(array, checkItem)) {
@@ -185,7 +186,7 @@
         return true;
     }
 
-    public static boolean contains(int[] array, int value) {
+    public static boolean contains(@Nullable int[] array, int value) {
         if (array == null) return false;
         for (int element : array) {
             if (element == value) {
@@ -195,7 +196,7 @@
         return false;
     }
 
-    public static boolean contains(long[] array, long value) {
+    public static boolean contains(@Nullable long[] array, long value) {
         if (array == null) return false;
         for (long element : array) {
             if (element == value) {
@@ -205,10 +206,12 @@
         return false;
     }
 
-    public static long total(long[] array) {
+    public static long total(@Nullable long[] array) {
         long total = 0;
-        for (long value : array) {
-            total += value;
+        if (array != null) {
+            for (long value : array) {
+                total += value;
+            }
         }
         return total;
     }
@@ -366,11 +369,15 @@
         return cur;
     }
 
-    public static long[] cloneOrNull(long[] array) {
+    public static @Nullable long[] cloneOrNull(@Nullable long[] array) {
         return (array != null) ? array.clone() : null;
     }
 
-    public static <T> ArraySet<T> add(ArraySet<T> cur, T val) {
+    public static @Nullable <T> ArraySet<T> cloneOrNull(@Nullable ArraySet<T> array) {
+        return (array != null) ? new ArraySet<T>(array) : null;
+    }
+
+    public static @NonNull <T> ArraySet<T> add(@Nullable ArraySet<T> cur, T val) {
         if (cur == null) {
             cur = new ArraySet<>();
         }
@@ -378,7 +385,7 @@
         return cur;
     }
 
-    public static <T> ArraySet<T> remove(ArraySet<T> cur, T val) {
+    public static @Nullable <T> ArraySet<T> remove(@Nullable ArraySet<T> cur, T val) {
         if (cur == null) {
             return null;
         }
@@ -390,11 +397,11 @@
         }
     }
 
-    public static <T> boolean contains(ArraySet<T> cur, T val) {
+    public static <T> boolean contains(@Nullable ArraySet<T> cur, T val) {
         return (cur != null) ? cur.contains(val) : false;
     }
 
-    public static <T> ArrayList<T> add(ArrayList<T> cur, T val) {
+    public static @NonNull <T> ArrayList<T> add(@Nullable ArrayList<T> cur, T val) {
         if (cur == null) {
             cur = new ArrayList<>();
         }
@@ -402,7 +409,7 @@
         return cur;
     }
 
-    public static <T> ArrayList<T> remove(ArrayList<T> cur, T val) {
+    public static @Nullable <T> ArrayList<T> remove(@Nullable ArrayList<T> cur, T val) {
         if (cur == null) {
             return null;
         }
@@ -414,10 +421,20 @@
         }
     }
 
-    public static <T> boolean contains(ArrayList<T> cur, T val) {
+    public static <T> boolean contains(@Nullable ArrayList<T> cur, T val) {
         return (cur != null) ? cur.contains(val) : false;
     }
 
+    public static @Nullable <T> T[] trimToSize(@Nullable T[] array, int size) {
+        if (array == null || size == 0) {
+            return null;
+        } else if (array.length == size) {
+            return array;
+        } else {
+            return Arrays.copyOf(array, size);
+        }
+    }
+
     /**
      * Returns true if the two ArrayLists are equal with respect to the objects they contain.
      * The objects must be in the same order and be reference equal (== not .equals()).
diff --git a/core/java/com/android/internal/util/GrowingArrayUtils.java b/core/java/com/android/internal/util/GrowingArrayUtils.java
index b4d2d730..968d920 100644
--- a/core/java/com/android/internal/util/GrowingArrayUtils.java
+++ b/core/java/com/android/internal/util/GrowingArrayUtils.java
@@ -97,6 +97,21 @@
     }
 
     /**
+     * Primitive float version of {@link #append(Object[], int, Object)}.
+     */
+    public static float[] append(float[] array, int currentSize, float element) {
+        assert currentSize <= array.length;
+
+        if (currentSize + 1 > array.length) {
+            float[] newArray = ArrayUtils.newUnpaddedFloatArray(growSize(currentSize));
+            System.arraycopy(array, 0, newArray, 0, currentSize);
+            array = newArray;
+        }
+        array[currentSize] = element;
+        return array;
+    }
+
+    /**
      * Inserts an element into the array at the specified index, growing the array if there is no
      * more room.
      *
diff --git a/core/java/com/android/internal/util/IndentingPrintWriter.java b/core/java/com/android/internal/util/IndentingPrintWriter.java
index f1add27..696667c 100644
--- a/core/java/com/android/internal/util/IndentingPrintWriter.java
+++ b/core/java/com/android/internal/util/IndentingPrintWriter.java
@@ -45,6 +45,8 @@
      */
     private boolean mEmptyLine = true;
 
+    private char[] mSingleChar = new char[1];
+
     public IndentingPrintWriter(Writer writer, String singleIndent) {
         this(writer, singleIndent, -1);
     }
@@ -78,6 +80,24 @@
     }
 
     @Override
+    public void println() {
+        write('\n');
+    }
+
+    @Override
+    public void write(int c) {
+        mSingleChar[0] = (char) c;
+        write(mSingleChar, 0, 1);
+    }
+
+    @Override
+    public void write(String s, int off, int len) {
+        final char[] buf = new char[len];
+        s.getChars(off, len - off, buf, 0);
+        write(buf, 0, len);
+    }
+
+    @Override
     public void write(char[] buf, int offset, int count) {
         final int indentLength = mIndentBuilder.length();
         final int bufferEnd = offset + count;
diff --git a/core/java/com/android/internal/util/LineBreakBufferedWriter.java b/core/java/com/android/internal/util/LineBreakBufferedWriter.java
new file mode 100644
index 0000000..f831e7a
--- /dev/null
+++ b/core/java/com/android/internal/util/LineBreakBufferedWriter.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 java.io.PrintWriter;
+import java.io.Writer;
+import java.util.Arrays;
+
+/**
+ * A writer that breaks up its output into chunks before writing to its out writer,
+ * and which is linebreak aware, i.e., chunks will created along line breaks, if
+ * possible.
+ *
+ * Note: this class is not thread-safe.
+ */
+public class LineBreakBufferedWriter extends PrintWriter {
+
+    /**
+     * A buffer to collect data until the buffer size is reached.
+     *
+     * Note: we manage a char[] ourselves to avoid an allocation when printing to the
+     *       out writer. Otherwise a StringBuilder would have been simpler to use.
+     */
+    private char[] buffer;
+
+    /**
+     * The index of the first free element in the buffer.
+     */
+    private int bufferIndex;
+
+    /**
+     * The chunk size (=maximum buffer size) to use for this writer.
+     */
+    private final int bufferSize;
+
+
+    /**
+     * Index of the last newline character discovered in the buffer. The writer will try
+     * to split there.
+     */
+    private int lastNewline = -1;
+
+    /**
+     * The line separator for println().
+     */
+    private final String lineSeparator;
+
+    /**
+     * Create a new linebreak-aware buffered writer with the given output and buffer
+     * size. The initial capacity will be a default value.
+     * @param out The writer to write to.
+     * @param bufferSize The maximum buffer size.
+     */
+    public LineBreakBufferedWriter(Writer out, int bufferSize) {
+        this(out, bufferSize, 16);  // 16 is the default size of a StringBuilder buffer.
+    }
+
+    /**
+     * Create a new linebreak-aware buffered writer with the given output, buffer
+     * size and initial capacity.
+     * @param out The writer to write to.
+     * @param bufferSize The maximum buffer size.
+     * @param initialCapacity The initial capacity of the internal buffer.
+     */
+    public LineBreakBufferedWriter(Writer out, int bufferSize, int initialCapacity) {
+        super(out);
+        this.buffer = new char[Math.min(initialCapacity, bufferSize)];
+        this.bufferIndex = 0;
+        this.bufferSize = bufferSize;
+        this.lineSeparator = System.getProperty("line.separator");
+    }
+
+    /**
+     * Flush the current buffer. This will ignore line breaks.
+     */
+    @Override
+    public void flush() {
+        writeBuffer(bufferIndex);
+        bufferIndex = 0;
+        super.flush();
+    }
+
+    @Override
+    public void write(int c) {
+        if (bufferIndex < bufferSize) {
+            buffer[bufferIndex] = (char)c;
+            bufferIndex++;
+            if ((char)c == '\n') {
+                lastNewline = bufferIndex;
+            }
+        } else {
+            // This should be an uncommon case, we mostly expect char[] and String. So
+            // let the chunking be handled by the char[] case.
+            write(new char[] { (char)c }, 0 ,1);
+        }
+    }
+
+    @Override
+    public void println() {
+        write(lineSeparator);
+    }
+
+    @Override
+    public void write(char[] buf, int off, int len) {
+        while (bufferIndex + len > bufferSize) {
+            // Find the next newline in the buffer, see if that's below the limit.
+            // Repeat.
+            int nextNewLine = -1;
+            int maxLength = bufferSize - bufferIndex;
+            for (int i = 0; i < maxLength; i++) {
+                if (buf[off + i] == '\n') {
+                    if (bufferIndex + i < bufferSize) {
+                        nextNewLine = i;
+                    } else {
+                        break;
+                    }
+                }
+            }
+
+            if (nextNewLine != -1) {
+                // We can add some more data.
+                appendToBuffer(buf, off, nextNewLine);
+                writeBuffer(bufferIndex);
+                bufferIndex = 0;
+                lastNewline = -1;
+                off += nextNewLine + 1;
+                len -= nextNewLine + 1;
+            } else if (lastNewline != -1) {
+                // Use the last newline.
+                writeBuffer(lastNewline);
+                removeFromBuffer(lastNewline + 1);
+                lastNewline = -1;
+            } else {
+                // OK, there was no newline, break at a full buffer.
+                int rest = bufferSize - bufferIndex;
+                appendToBuffer(buf, off, rest);
+                writeBuffer(bufferIndex);
+                bufferIndex = 0;
+                off += rest;
+                len -= rest;
+            }
+        }
+
+        // Add to the buffer, this will fit.
+        if (len > 0) {
+            // Add the chars, find the last newline.
+            appendToBuffer(buf, off, len);
+            for (int i = len - 1; i >= 0; i--) {
+                if (buf[off + i] == '\n') {
+                    lastNewline = bufferIndex - len + i;
+                    break;
+                }
+            }
+        }
+    }
+
+    @Override
+    public void write(String s, int off, int len) {
+        while (bufferIndex + len > bufferSize) {
+            // Find the next newline in the buffer, see if that's below the limit.
+            // Repeat.
+            int nextNewLine = -1;
+            int maxLength = bufferSize - bufferIndex;
+            for (int i = 0; i < maxLength; i++) {
+                if (s.charAt(off + i) == '\n') {
+                    if (bufferIndex + i < bufferSize) {
+                        nextNewLine = i;
+                    } else {
+                        break;
+                    }
+                }
+            }
+
+            if (nextNewLine != -1) {
+                // We can add some more data.
+                appendToBuffer(s, off, nextNewLine);
+                writeBuffer(bufferIndex);
+                bufferIndex = 0;
+                lastNewline = -1;
+                off += nextNewLine + 1;
+                len -= nextNewLine + 1;
+            } else if (lastNewline != -1) {
+                // Use the last newline.
+                writeBuffer(lastNewline);
+                removeFromBuffer(lastNewline + 1);
+                lastNewline = -1;
+            } else {
+                // OK, there was no newline, break at a full buffer.
+                int rest = bufferSize - bufferIndex;
+                appendToBuffer(s, off, rest);
+                writeBuffer(bufferIndex);
+                bufferIndex = 0;
+                off += rest;
+                len -= rest;
+            }
+        }
+
+        // Add to the buffer, this will fit.
+        if (len > 0) {
+            // Add the chars, find the last newline.
+            appendToBuffer(s, off, len);
+            for (int i = len - 1; i >= 0; i--) {
+                if (s.charAt(off + i) == '\n') {
+                    lastNewline = bufferIndex - len + i;
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Append the characters to the buffer. This will potentially resize the buffer,
+     * and move the index along.
+     * @param buf The char[] containing the data.
+     * @param off The start index to copy from.
+     * @param len The number of characters to copy.
+     */
+    private void appendToBuffer(char[] buf, int off, int len) {
+        if (bufferIndex + len > buffer.length) {
+            ensureCapacity(bufferIndex + len);
+        }
+        System.arraycopy(buf, off, buffer, bufferIndex, len);
+        bufferIndex += len;
+    }
+
+    /**
+     * Append the characters from the given string to the buffer. This will potentially
+     * resize the buffer, and move the index along.
+     * @param s The string supplying the characters.
+     * @param off The start index to copy from.
+     * @param len The number of characters to copy.
+     */
+    private void appendToBuffer(String s, int off, int len) {
+        if (bufferIndex + len > buffer.length) {
+            ensureCapacity(bufferIndex + len);
+        }
+        s.getChars(off, off + len, buffer, bufferIndex);
+        bufferIndex += len;
+    }
+
+    /**
+     * Resize the buffer. We use the usual double-the-size plus constant scheme for
+     * amortized O(1) insert. Note: we expect small buffers, so this won't check for
+     * overflow.
+     * @param capacity The size to be ensured.
+     */
+    private void ensureCapacity(int capacity) {
+        int newSize = buffer.length * 2 + 2;
+        if (newSize < capacity) {
+            newSize = capacity;
+        }
+        buffer = Arrays.copyOf(buffer, newSize);
+    }
+
+    /**
+     * Remove the characters up to (and excluding) index i from the buffer. This will
+     * not resize the buffer, but will update bufferIndex.
+     * @param i The number of characters to remove from the front.
+     */
+    private void removeFromBuffer(int i) {
+        int rest = bufferIndex - i;
+        if (rest > 0) {
+            System.arraycopy(buffer, bufferIndex - rest, buffer, 0, rest);
+            bufferIndex = rest;
+        } else {
+            bufferIndex = 0;
+        }
+    }
+
+    /**
+     * Helper method, write the given part of the buffer, [start,length), to the output.
+     * @param length The number of characters to flush.
+     */
+    private void writeBuffer(int length) {
+        if (length > 0) {
+            super.write(buffer, 0, length);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index b692a18..2f26e92 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -16,6 +16,10 @@
 
 package com.android.internal.util;
 
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.text.TextUtils;
+
 import java.util.Collection;
 
 /**
@@ -31,6 +35,39 @@
     }
 
     /**
+     * Ensures that an string reference passed as a parameter to the calling
+     * method is not empty.
+     *
+     * @param string an string reference
+     * @return the string reference that was validated
+     * @throws IllegalArgumentException if {@code string} is empty
+     */
+    public static @NonNull String checkStringNotEmpty(final String string) {
+        if (TextUtils.isEmpty(string)) {
+            throw new IllegalArgumentException();
+        }
+        return string;
+    }
+
+    /**
+     * Ensures that an string reference passed as a parameter to the calling
+     * method is not empty.
+     *
+     * @param string an string reference
+     * @param errorMessage the exception message to use if the check fails; will
+     *     be converted to a string using {@link String#valueOf(Object)}
+     * @return the string reference that was validated
+     * @throws IllegalArgumentException if {@code string} is empty
+     */
+    public static @NonNull String checkStringNotEmpty(final String string,
+            final Object errorMessage) {
+        if (TextUtils.isEmpty(string)) {
+            throw new IllegalArgumentException(String.valueOf(errorMessage));
+        }
+        return string;
+    }
+
+    /**
      * Ensures that an object reference passed as a parameter to the calling
      * method is not null.
      *
@@ -38,7 +75,7 @@
      * @return the non-null reference that was validated
      * @throws NullPointerException if {@code reference} is null
      */
-    public static <T> T checkNotNull(final T reference) {
+    public static @NonNull <T> T checkNotNull(final T reference) {
         if (reference == null) {
             throw new NullPointerException();
         }
@@ -55,7 +92,7 @@
      * @return the non-null reference that was validated
      * @throws NullPointerException if {@code reference} is null
      */
-    public static <T> T checkNotNull(final T reference, final Object errorMessage) {
+    public static @NonNull <T> T checkNotNull(final T reference, final Object errorMessage) {
         if (reference == null) {
             throw new NullPointerException(String.valueOf(errorMessage));
         }
@@ -95,7 +132,8 @@
      * @return the validated numeric value
      * @throws IllegalArgumentException if {@code value} was negative
      */
-    public static int checkArgumentNonnegative(final int value, final String errorMessage) {
+    public static @IntRange(from = 0) int checkArgumentNonnegative(final int value,
+            final String errorMessage) {
         if (value < 0) {
             throw new IllegalArgumentException(errorMessage);
         }
@@ -218,6 +256,33 @@
     }
 
     /**
+     * Ensures that the argument long value is within the inclusive range.
+     *
+     * @param value a long value
+     * @param lower the lower endpoint of the inclusive range
+     * @param upper the upper endpoint of the inclusive range
+     * @param valueName the name of the argument to use if the check fails
+     *
+     * @return the validated long value
+     *
+     * @throws IllegalArgumentException if {@code value} was not within the range
+     */
+    public static long checkArgumentInRange(long value, long lower, long upper,
+            String valueName) {
+        if (value < lower) {
+            throw new IllegalArgumentException(
+                    String.format(
+                            "%s is out of range of [%d, %d] (too low)", valueName, lower, upper));
+        } else if (value > upper) {
+            throw new IllegalArgumentException(
+                    String.format(
+                            "%s is out of range of [%d, %d] (too high)", valueName, lower, upper));
+        }
+
+        return value;
+    }
+
+    /**
      * Ensures that the array is not {@code null}, and none of its elements are {@code null}.
      *
      * @param value an array of boxed objects
@@ -253,8 +318,8 @@
      *
      * @throws NullPointerException if the {@code value} or any of its elements were {@code null}
      */
-    public static <T> Collection<T> checkCollectionElementsNotNull(final Collection<T> value,
-            final String valueName) {
+    public static @NonNull <C extends Collection<T>, T> C checkCollectionElementsNotNull(
+            final C value, final String valueName) {
         if (value == null) {
             throw new NullPointerException(valueName + " must not be null");
         }
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 406b487..dc66818 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -779,7 +779,7 @@
         @Override
         public final void handleMessage(Message msg) {
             if (!mHasQuit) {
-                if (mSm != null) {
+                if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {
                     mSm.onPreHandleMessage(msg);
                 }
 
@@ -807,7 +807,7 @@
                 // We need to check if mSm == null here as we could be quitting.
                 if (mDbg && mSm != null) mSm.log("handleMessage: X");
 
-                if (mSm != null) {
+                if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {
                     mSm.onPostHandleMessage(msg);
                 }
             }
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 8699843..bcc310f 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -25,6 +25,8 @@
 import android.view.IWindow;
 import android.view.IWindowSession;
 
+import com.android.internal.os.IResultReceiver;
+
 public class BaseIWindow extends IWindow.Stub {
     private IWindowSession mSession;
     public int mSeq;
@@ -36,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) {
+            Rect backDropFrame, boolean forceLayout) {
         if (reportDraw) {
             try {
                 mSession.finishDrawing(this);
@@ -84,6 +86,10 @@
     }
 
     @Override
+    public void updatePointerIcon(float x, float y) {
+    }
+
+    @Override
     public void dispatchSystemUiVisibilityChanged(int seq, int globalUi,
             int localValue, int localChanges) {
         mSeq = seq;
@@ -103,4 +109,8 @@
     @Override
     public void dispatchWindowShown() {
     }
+
+    @Override
+    public void requestAppKeyboardShortcuts(IResultReceiver receiver) {
+    }
 }
diff --git a/core/java/com/android/internal/view/IDropPermissionHolder.aidl b/core/java/com/android/internal/view/IDropPermissionHolder.aidl
deleted file mode 100644
index e60ab0e..0000000
--- a/core/java/com/android/internal/view/IDropPermissionHolder.aidl
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
-** Copyright 2015, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package com.android.internal.view;
-
-/**
- * Interface to allow a drop receiver to request permissions for URIs passed along with ClipData
- * contained in DragEvent.
- */
-interface IDropPermissionHolder {
-    void grant();
-    void revoke();
-}
diff --git a/core/java/com/android/internal/view/IDropPermissions.aidl b/core/java/com/android/internal/view/IDropPermissions.aidl
new file mode 100644
index 0000000..74ff4b4
--- /dev/null
+++ b/core/java/com/android/internal/view/IDropPermissions.aidl
@@ -0,0 +1,29 @@
+/*
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package com.android.internal.view;
+
+import android.os.IBinder;
+
+/**
+ * Interface to allow a drop receiver to request permissions for URIs passed along with ClipData
+ * contained in DragEvent.
+ */
+interface IDropPermissions {
+    void take(IBinder activityToken);
+    void takeTransient(IBinder permissionOwnerToken);
+    void release();
+}
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 85ec29c..3be15f3 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -30,7 +30,7 @@
 
 import java.lang.ref.WeakReference;
 
-public class IInputConnectionWrapper extends IInputContext.Stub {
+public abstract class IInputConnectionWrapper extends IInputContext.Stub {
     static final String TAG = "IInputConnectionWrapper";
 
     private static final int DO_GET_TEXT_AFTER_CURSOR = 10;
@@ -49,6 +49,7 @@
     private static final int DO_FINISH_COMPOSING_TEXT = 65;
     private static final int DO_SEND_KEY_EVENT = 70;
     private static final int DO_DELETE_SURROUNDING_TEXT = 80;
+    private static final int DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS = 81;
     private static final int DO_BEGIN_BATCH_EDIT = 90;
     private static final int DO_END_BATCH_EDIT = 95;
     private static final int DO_REPORT_FULLSCREEN_MODE = 100;
@@ -80,15 +81,25 @@
     }
     
     public IInputConnectionWrapper(Looper mainLooper, InputConnection conn) {
-        mInputConnection = new WeakReference<InputConnection>(conn);
+        mInputConnection = new WeakReference<>(conn);
         mMainLooper = mainLooper;
         mH = new MyHandler(mMainLooper);
     }
 
-    public boolean isActive() {
-        return true;
-    }
-    
+    abstract protected boolean isActive();
+
+    /**
+     * Called when the user took some actions that should be taken into consideration to update the
+     * LRU list for input method rotation.
+     */
+    abstract protected void onUserAction();
+
+    /**
+     * Called when the input method started or stopped full-screen mode.
+     *
+     */
+    abstract protected void onReportFullscreenMode(boolean enabled);
+
     public void getTextAfterCursor(int length, int flags, int seq, IInputContextCallback callback) {
         dispatchMessage(obtainMessageIISC(DO_GET_TEXT_AFTER_CURSOR, length, flags, seq, callback));
     }
@@ -155,9 +166,14 @@
         dispatchMessage(obtainMessageII(DO_CLEAR_META_KEY_STATES, states, 0));
     }
 
-    public void deleteSurroundingText(int leftLength, int rightLength) {
+    public void deleteSurroundingText(int beforeLength, int afterLength) {
         dispatchMessage(obtainMessageII(DO_DELETE_SURROUNDING_TEXT,
-            leftLength, rightLength));
+                beforeLength, afterLength));
+    }
+
+    public void deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
+        dispatchMessage(obtainMessageII(DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS,
+                beforeLength, afterLength));
     }
 
     public void beginBatchEdit() {
@@ -284,6 +300,7 @@
                     return;
                 }
                 ic.commitText((CharSequence)msg.obj, msg.arg1);
+                onUserAction();
                 return;
             }
             case DO_SET_SELECTION: {
@@ -338,6 +355,7 @@
                     return;
                 }
                 ic.setComposingText((CharSequence)msg.obj, msg.arg1);
+                onUserAction();
                 return;
             }
             case DO_SET_COMPOSING_REGION: {
@@ -369,6 +387,7 @@
                     return;
                 }
                 ic.sendKeyEvent((KeyEvent)msg.obj);
+                onUserAction();
                 return;
             }
             case DO_CLEAR_META_KEY_STATES: {
@@ -389,6 +408,15 @@
                 ic.deleteSurroundingText(msg.arg1, msg.arg2);
                 return;
             }
+            case DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS: {
+                InputConnection ic = mInputConnection.get();
+                if (ic == null || !isActive()) {
+                    Log.w(TAG, "deleteSurroundingTextInCodePoints on inactive InputConnection");
+                    return;
+                }
+                ic.deleteSurroundingTextInCodePoints(msg.arg1, msg.arg2);
+                return;
+            }
             case DO_BEGIN_BATCH_EDIT: {
                 InputConnection ic = mInputConnection.get();
                 if (ic == null || !isActive()) {
@@ -413,7 +441,9 @@
                     Log.w(TAG, "reportFullscreenMode on inexistent InputConnection");
                     return;
                 }
-                ic.reportFullscreenMode(msg.arg1 == 1);
+                final boolean enabled = msg.arg1 == 1;
+                ic.reportFullscreenMode(enabled);
+                onReportFullscreenMode(enabled);
                 return;
             }
             case DO_PERFORM_PRIVATE_COMMAND: {
@@ -454,7 +484,7 @@
     Message obtainMessageII(int what, int arg1, int arg2) {
         return mH.obtainMessage(what, arg1, arg2);
     }
-    
+
     Message obtainMessageO(int what, Object arg1) {
         return mH.obtainMessage(what, 0, 0, arg1);
     }
diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl
index fd2b513..f7ec420 100644
--- a/core/java/com/android/internal/view/IInputContext.aidl
+++ b/core/java/com/android/internal/view/IInputContext.aidl
@@ -38,8 +38,9 @@
     
     void getExtractedText(in ExtractedTextRequest request, int flags, int seq,
             IInputContextCallback callback);
-    
-    void deleteSurroundingText(int leftLength, int rightLength);
+
+    void deleteSurroundingText(int beforeLength, int afterLength);
+    void deleteSurroundingTextInCodePoints(int beforeLength, int afterLength);
 
     void setComposingText(CharSequence text, int newCursorPosition);
 
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index 7dc927f..94790c1 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -400,7 +400,7 @@
             return false;
         }
     }
-    
+
     public boolean deleteSurroundingText(int beforeLength, int afterLength) {
         try {
             mIInputContext.deleteSurroundingText(beforeLength, afterLength);
@@ -410,6 +410,15 @@
         }
     }
 
+    public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
+        try {
+            mIInputContext.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
+            return true;
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
     public boolean reportFullscreenMode(boolean enabled) {
         try {
             mIInputContext.reportFullscreenMode(enabled);
diff --git a/core/java/com/android/internal/view/menu/BaseMenuPresenter.java b/core/java/com/android/internal/view/menu/BaseMenuPresenter.java
index 92e9ea6..7ac0ac3 100644
--- a/core/java/com/android/internal/view/menu/BaseMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/BaseMenuPresenter.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.view.menu;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -58,7 +60,7 @@
     }
 
     @Override
-    public void initForMenu(Context context, MenuBuilder menu) {
+    public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) {
         mContext = context;
         mInflater = LayoutInflater.from(mContext);
         mMenu = menu;
diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
index 320de90..a502fcc 100644
--- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
@@ -362,6 +362,7 @@
 
         final int x;
         final int y;
+        final Rect epicenterBounds;
         if (parentView != null) {
             // This menu is a cascading submenu anchored to a parent view.
             popupWindow.setTouchModal(false);
@@ -396,13 +397,16 @@
             }
 
             y = parentOffsetTop;
+            epicenterBounds = null;
         } else {
             x = mInitXOffset;
             y = mInitYOffset;
+            epicenterBounds = getEpicenterBounds();
         }
 
         popupWindow.setHorizontalOffset(x);
         popupWindow.setVerticalOffset(y);
+        popupWindow.setEpicenterBounds(epicenterBounds);
 
         final CascadingMenuInfo menuInfo = new CascadingMenuInfo(popupWindow, menu, mLastPosition);
         mShowingMenus.add(menuInfo);
diff --git a/core/java/com/android/internal/view/menu/IconMenuPresenter.java b/core/java/com/android/internal/view/menu/IconMenuPresenter.java
index 2439b5d..5223a7b 100644
--- a/core/java/com/android/internal/view/menu/IconMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/IconMenuPresenter.java
@@ -17,6 +17,8 @@
 
 import com.android.internal.view.menu.MenuView.ItemView;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.Parcelable;
@@ -49,7 +51,7 @@
     }
 
     @Override
-    public void initForMenu(Context context, MenuBuilder menu) {
+    public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) {
         super.initForMenu(context, menu);
         mMaxItems = -1;
     }
diff --git a/core/java/com/android/internal/view/menu/ListMenuPresenter.java b/core/java/com/android/internal/view/menu/ListMenuPresenter.java
index c476354..2fff3ba 100644
--- a/core/java/com/android/internal/view/menu/ListMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ListMenuPresenter.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.view.menu;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.Parcelable;
@@ -76,7 +78,7 @@
     }
 
     @Override
-    public void initForMenu(Context context, MenuBuilder menu) {
+    public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) {
         if (mThemeRes != 0) {
             mContext = new ContextThemeWrapper(context, mThemeRes);
             mInflater = LayoutInflater.from(mContext);
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 465d775..31b2f96 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -17,6 +17,7 @@
 package com.android.internal.view.menu;
 
 
+import android.annotation.NonNull;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -1027,23 +1028,24 @@
         mIsActionItemsStale = true;
         onItemsChanged(true);
     }
-    
+
+    @NonNull
     public ArrayList<MenuItemImpl> getVisibleItems() {
         if (!mIsVisibleItemsStale) return mVisibleItems;
-        
+
         // Refresh the visible items
         mVisibleItems.clear();
-        
+
         final int itemsSize = mItems.size(); 
         MenuItemImpl item;
         for (int i = 0; i < itemsSize; i++) {
             item = mItems.get(i);
             if (item.isVisible()) mVisibleItems.add(item);
         }
-        
+
         mIsVisibleItemsStale = false;
         mIsActionItemsStale = true;
-        
+
         return mVisibleItems;
     }
 
diff --git a/core/java/com/android/internal/view/menu/MenuPopup.java b/core/java/com/android/internal/view/menu/MenuPopup.java
index 98f5d90..42b1a56 100644
--- a/core/java/com/android/internal/view/menu/MenuPopup.java
+++ b/core/java/com/android/internal/view/menu/MenuPopup.java
@@ -16,7 +16,10 @@
 
 package com.android.internal.view.menu;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
+import android.graphics.Rect;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.View.MeasureSpec;
@@ -35,6 +38,7 @@
  */
 public abstract class MenuPopup implements ShowableListMenu, MenuPresenter,
         AdapterView.OnItemClickListener {
+    private Rect mEpicenterBounds;
 
     public abstract void setForceShowIcon(boolean forceShow);
 
@@ -58,6 +62,23 @@
     public abstract void setVerticalOffset(int y);
 
     /**
+     * Specifies the anchor-relative bounds of the popup's transition
+     * epicenter.
+     *
+     * @param bounds anchor-relative bounds
+     */
+    public void setEpicenterBounds(Rect bounds) {
+        mEpicenterBounds = bounds;
+    }
+
+    /**
+     * @return anchor-relative bounds of the popup's transition epicenter
+     */
+    public Rect getEpicenterBounds() {
+        return mEpicenterBounds;
+    }
+
+    /**
      * Set whether a title entry should be shown in the popup menu (if a title exists for the
      * menu).
      *
@@ -73,7 +94,7 @@
     public abstract void setOnDismissListener(PopupWindow.OnDismissListener listener);
 
     @Override
-    public void initForMenu(Context context, MenuBuilder menu) {
+    public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) {
         // Don't need to do anything; we added as a presenter in the constructor.
     }
 
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index 044ee6e..1f1e594 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -23,6 +23,8 @@
 import android.annotation.Nullable;
 import android.annotation.StyleRes;
 import android.content.Context;
+import android.graphics.Rect;
+import android.util.DisplayMetrics;
 import android.view.Gravity;
 import android.view.View;
 import android.widget.PopupWindow.OnDismissListener;
@@ -31,6 +33,8 @@
  * Presents a menu as a small, simple popup anchored to another view.
  */
 public class MenuPopupHelper implements MenuHelper {
+    private static final int TOUCH_EPICENTER_SIZE_DP = 48;
+
     private final Context mContext;
 
     // Immutable cached popup menu properties.
@@ -163,6 +167,11 @@
      * Shows the popup menu and makes a best-effort to anchor it to the
      * specified (x,y) coordinate relative to the anchor view.
      * <p>
+     * Additionally, the popup's transition epicenter (see
+     * {@link android.widget.PopupWindow#setEpicenterBounds(Rect)} will be
+     * centered on the specified coordinate, rather than using the bounds of
+     * the anchor view.
+     * <p>
      * If the popup's resolved gravity is {@link Gravity#LEFT}, this will
      * display the popup with its top-left corner at (x,y) relative to the
      * anchor view. If the resolved gravity is {@link Gravity#RIGHT}, the
@@ -222,8 +231,11 @@
         return popup;
     }
 
-    private void showPopup(int xOffset, int yOffset, boolean resolveOffsets, boolean showTitle) {
-        if (resolveOffsets) {
+    private void showPopup(int xOffset, int yOffset, boolean useOffsets, boolean showTitle) {
+        final MenuPopup popup = getPopup();
+        popup.setShowTitle(showTitle);
+
+        if (useOffsets) {
             // If the resolved drop-down gravity is RIGHT, the popup's right
             // edge will be aligned with the anchor view. Adjust by the anchor
             // width such that the top-right corner is at the X offset.
@@ -232,12 +244,21 @@
             if (hgrav == Gravity.RIGHT) {
                 xOffset -= mAnchorView.getWidth();
             }
+
+            popup.setHorizontalOffset(xOffset);
+            popup.setVerticalOffset(yOffset);
+
+            // Set the transition epicenter to be roughly finger (or mouse
+            // cursor) sized and centered around the offset position. This
+            // will give the appearance that the window is emerging from
+            // the touch point.
+            final float density = mContext.getResources().getDisplayMetrics().density;
+            final int halfSize = (int) (TOUCH_EPICENTER_SIZE_DP * density / 2);
+            final Rect epicenter = new Rect(xOffset - halfSize, yOffset - halfSize,
+                    xOffset + halfSize, yOffset + halfSize);
+            popup.setEpicenterBounds(epicenter);
         }
 
-        final MenuPopup popup = getPopup();
-        popup.setHorizontalOffset(xOffset);
-        popup.setVerticalOffset(yOffset);
-        popup.setShowTitle(showTitle);
         popup.show();
     }
 
diff --git a/core/java/com/android/internal/view/menu/MenuPresenter.java b/core/java/com/android/internal/view/menu/MenuPresenter.java
index c847c15..65bdc09 100644
--- a/core/java/com/android/internal/view/menu/MenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/MenuPresenter.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.view.menu;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.os.Parcelable;
 import android.view.ViewGroup;
@@ -49,14 +51,16 @@
     }
 
     /**
-     * Initialize this presenter for the given context and menu.
-     * This method is called by MenuBuilder when a presenter is
-     * added. See {@link MenuBuilder#addMenuPresenter(MenuPresenter)}
+     * Initializes this presenter for the given context and menu.
+     * <p>
+     * This method is called by MenuBuilder when a presenter is added. See
+     * {@link MenuBuilder#addMenuPresenter(MenuPresenter)}.
      *
-     * @param context Context for this presenter; used for view creation and resource management
-     * @param menu Menu to host
+     * @param context the context for this presenter; used for view creation
+     *                and resource management, must be non-{@code null}
+     * @param menu the menu to host, or {@code null} to clear the hosted menu
      */
-    public void initForMenu(Context context, MenuBuilder menu);
+    public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu);
 
     /**
      * Retrieve a MenuView to display the menu specified in
diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
index c2adc42..2d4baa2 100644
--- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package com.android.internal.view.menu;
 
 import android.content.Context;
@@ -7,7 +23,6 @@
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.View.OnAttachStateChangeListener;
 import android.view.View.OnKeyListener;
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
@@ -30,7 +45,7 @@
         MenuPresenter, OnKeyListener {
 
     private final Context mContext;
-    private final LayoutInflater mInflater;
+
     private final MenuBuilder mMenu;
     private final MenuAdapter mAdapter;
     private final boolean mOverflowOnly;
@@ -79,8 +94,6 @@
     private Callback mPresenterCallback;
     private ViewTreeObserver mTreeObserver;
 
-    private ViewGroup mMeasureParent;
-
     /** Whether the popup has been dismissed. Once dismissed, it cannot be opened again. */
     private boolean mWasDismissed;
 
@@ -99,10 +112,10 @@
     public StandardMenuPopup(Context context, MenuBuilder menu, View anchorView, int popupStyleAttr,
             int popupStyleRes, boolean overflowOnly) {
         mContext = Preconditions.checkNotNull(context);
-        mInflater = LayoutInflater.from(context);
         mMenu = menu;
         mOverflowOnly = overflowOnly;
-        mAdapter = new MenuAdapter(menu, mInflater, mOverflowOnly);
+        final LayoutInflater inflater = LayoutInflater.from(context);
+        mAdapter = new MenuAdapter(menu, inflater, mOverflowOnly);
         mPopupStyleAttr = popupStyleAttr;
         mPopupStyleRes = popupStyleRes;
 
@@ -155,8 +168,7 @@
         mPopup.setDropDownGravity(mDropDownGravity);
 
         if (!mHasContentWidth) {
-            mContentWidth = measureIndividualMenuWidth(
-                    mAdapter, mMeasureParent, mContext, mPopupMaxWidth);
+            mContentWidth = measureIndividualMenuWidth(mAdapter, null, mContext, mPopupMaxWidth);
             mHasContentWidth = true;
         }
 
@@ -164,6 +176,7 @@
         mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
         mPopup.setHorizontalOffset(mXOffset);
         mPopup.setVerticalOffset(mYOffset);
+        mPopup.setEpicenterBounds(getEpicenterBounds());
         mPopup.show();
 
         ListView listView = mPopup.getListView();
@@ -177,7 +190,9 @@
                             false);
             TextView titleView = (TextView) titleItemView.findViewById(
                     com.android.internal.R.id.title);
-            titleView.setText(mMenu.getHeaderTitle());
+            if (titleView != null) {
+                titleView.setText(mMenu.getHeaderTitle());
+            }
             titleItemView.setEnabled(false);
             listView.addHeaderView(titleItemView, null, false);
 
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 825e336..f90b59d 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -17,6 +17,8 @@
 package com.android.internal.widget;
 
 import android.animation.LayoutTransition;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActionBar;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -1593,7 +1595,7 @@
         MenuItemImpl mCurrentExpandedItem;
 
         @Override
-        public void initForMenu(Context context, MenuBuilder menu) {
+        public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) {
             // Clear the expanded action view when menus change.
             if (mMenu != null && mCurrentExpandedItem != null) {
                 mMenu.collapseItemActionView(mCurrentExpandedItem);
diff --git a/core/java/com/android/internal/widget/DecorCaptionView.java b/core/java/com/android/internal/widget/DecorCaptionView.java
index c3fe9e7..409a17f 100644
--- a/core/java/com/android/internal/widget/DecorCaptionView.java
+++ b/core/java/com/android/internal/widget/DecorCaptionView.java
@@ -16,8 +16,6 @@
 
 package com.android.internal.widget;
 
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
-
 import android.content.Context;
 import android.graphics.Color;
 import android.graphics.Rect;
@@ -351,7 +349,7 @@
         Window.WindowControllerCallback callback = mOwner.getWindowControllerCallback();
         if (callback != null) {
             try {
-                callback.changeWindowStack(FULLSCREEN_WORKSPACE_STACK_ID);
+                callback.exitFreeformMode();
             } catch (RemoteException ex) {
                 Log.e(TAG, "Cannot change task workspace.");
             }
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index 3a00469..976ef4b 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -1264,7 +1264,7 @@
         }
 
         private void maybeComputeTransitionDurationScale() {
-            if (mMainPanelSize == null || mOverflowPanel == null) {
+            if (mMainPanelSize != null && mOverflowPanelSize != null) {
                 int w = mMainPanelSize.getWidth() - mOverflowPanelSize.getWidth();
                 int h = mOverflowPanelSize.getHeight() - mMainPanelSize.getHeight();
                 mTransitionDurationScale = (int) (Math.sqrt(w * w + h * h) /
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 4e4552d..b07e36a 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -39,4 +39,5 @@
     void registerStrongAuthTracker(in IStrongAuthTracker tracker);
     void unregisterStrongAuthTracker(in IStrongAuthTracker tracker);
     void requireStrongAuth(int strongAuthReason, int userId);
+    void systemReady();
 }
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index e38d82f..3f468ac 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -24,6 +24,7 @@
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.pm.UserInfo;
 import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.IBinder;
@@ -34,6 +35,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.os.storage.IMountService;
 import android.os.storage.StorageManager;
 import android.provider.Settings;
@@ -134,6 +136,9 @@
     private static final String LOCK_SCREEN_DEVICE_OWNER_INFO = "lockscreen.device_owner_info";
 
     private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents";
+    private static final String IS_TRUST_USUALLY_MANAGED = "lockscreen.istrustusuallymanaged";
+
+    private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge";
 
     // Maximum allowed number of repeated or ordered characters in a sequence before we'll
     // consider it a complex PIN/password.
@@ -143,7 +148,32 @@
     private final ContentResolver mContentResolver;
     private DevicePolicyManager mDevicePolicyManager;
     private ILockSettings mLockSettingsService;
+    private UserManager mUserManager;
 
+    /**
+     * Use {@link TrustManager#isTrustUsuallyManaged(int)}.
+     *
+     * This returns the lazily-peristed value and should only be used by TrustManagerService.
+     */
+    public boolean isTrustUsuallyManaged(int userId) {
+        if (!(mLockSettingsService instanceof ILockSettings.Stub)) {
+            throw new IllegalStateException("May only be called by TrustManagerService. "
+                    + "Use TrustManager.isTrustUsuallyManaged()");
+        }
+        try {
+            return getLockSettings().getBoolean(IS_TRUST_USUALLY_MANAGED, false, userId);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    public void setTrustUsuallyManaged(boolean managed, int userId) {
+        try {
+            getLockSettings().setBoolean(IS_TRUST_USUALLY_MANAGED, managed, userId);
+        } catch (RemoteException e) {
+            // System dead.
+        }
+    }
 
     public static final class RequestThrottledException extends Exception {
         private int mTimeoutMs;
@@ -173,6 +203,13 @@
         return mDevicePolicyManager;
     }
 
+    private UserManager getUserManager() {
+        if (mUserManager == null) {
+            mUserManager = UserManager.get(mContext);
+        }
+        return mUserManager;
+    }
+
     private TrustManager getTrustManager() {
         TrustManager trust = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
         if (trust == null) {
@@ -866,6 +903,46 @@
     }
 
     /**
+     * Enables/disables the Separate Profile Challenge for this {@param userHandle}. This is a no-op
+     * for user handles that do not belong to a managed profile.
+     */
+    public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled) {
+        UserInfo info = getUserManager().getUserInfo(userHandle);
+        if (info.isManagedProfile()) {
+            setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userHandle);
+        }
+    }
+
+    /**
+     * Retrieves whether the Separate Profile Challenge is enabled for this {@param userHandle}.
+     */
+    public boolean isSeparateProfileChallengeEnabled(int userHandle) {
+        UserInfo info = getUserManager().getUserInfo(userHandle);
+        if (info == null || !info.isManagedProfile()) {
+            return false;
+        }
+        return getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userHandle);
+    }
+
+    /**
+     * Retrieves whether the current DPM allows use of the Profile Challenge.
+     */
+    public boolean isSeparateProfileChallengeAllowed(int userHandle) {
+        UserInfo info = getUserManager().getUserInfo(userHandle);
+        if (info == null || !info.isManagedProfile()) {
+            return false;
+        }
+        return getDevicePolicyManager().isSeparateProfileChallengeAllowed(userHandle);
+    }
+
+    /**
+     * Retrieves whether the current profile and device locks can be unified.
+     */
+    public boolean isSeparateProfileChallengeAllowedToUnify(int userHandle) {
+        return getDevicePolicyManager().isProfileActivePasswordSufficientForParent(userHandle);
+    }
+
+    /**
      * Deserialize a pattern.
      * @param string The pattern serialized with {@link #patternToString}
      * @return The pattern.
@@ -1288,10 +1365,6 @@
         }
     }
 
-    public static boolean isSeparateWorkChallengeEnabled() {
-        return StorageManager.isFileBasedEncryptionEnabled();
-    }
-
     public void registerStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
         try {
             getLockSettings().registerStrongAuthTracker(strongAuthTracker.mStub);
@@ -1352,25 +1425,32 @@
          */
         public static final int SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL = 0x10;
 
-        public static final int DEFAULT = STRONG_AUTH_REQUIRED_AFTER_BOOT;
-
         private static final int ALLOWING_FINGERPRINT = STRONG_AUTH_NOT_REQUIRED
                 | SOME_AUTH_REQUIRED_AFTER_USER_REQUEST
                 | SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL;
 
         private final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
         private final H mHandler;
+        private final int mDefaultStrongAuthFlags;
 
-        public StrongAuthTracker() {
-            this(Looper.myLooper());
+        public StrongAuthTracker(Context context) {
+            this(context, Looper.myLooper());
         }
 
         /**
          * @param looper the looper on whose thread calls to {@link #onStrongAuthRequiredChanged}
          *               will be scheduled.
+         * @param context the current {@link Context}
          */
-        public StrongAuthTracker(Looper looper) {
+        public StrongAuthTracker(Context context, Looper looper) {
             mHandler = new H(looper);
+            mDefaultStrongAuthFlags = getDefaultFlags(context);
+        }
+
+        public static @StrongAuthFlags int getDefaultFlags(Context context) {
+            boolean strongAuthRequired = context.getResources().getBoolean(
+                    com.android.internal.R.bool.config_strongAuthRequiredOnBoot);
+            return strongAuthRequired ? STRONG_AUTH_REQUIRED_AFTER_BOOT : STRONG_AUTH_NOT_REQUIRED;
         }
 
         /**
@@ -1381,7 +1461,7 @@
          * @param userId the user for whom the state is queried.
          */
         public @StrongAuthFlags int getStrongAuthForUser(int userId) {
-            return mStrongAuthRequiredForUser.get(userId, DEFAULT);
+            return mStrongAuthRequiredForUser.get(userId, mDefaultStrongAuthFlags);
         }
 
         /**
@@ -1411,7 +1491,7 @@
 
             int oldValue = getStrongAuthForUser(userId);
             if (strongAuthFlags != oldValue) {
-                if (strongAuthFlags == DEFAULT) {
+                if (strongAuthFlags == mDefaultStrongAuthFlags) {
                     mStrongAuthRequiredForUser.delete(userId);
                 } else {
                     mStrongAuthRequiredForUser.put(userId, strongAuthFlags);
diff --git a/core/java/com/android/internal/widget/ScrollBarUtils.java b/core/java/com/android/internal/widget/ScrollBarUtils.java
new file mode 100644
index 0000000..0ae9f74
--- /dev/null
+++ b/core/java/com/android/internal/widget/ScrollBarUtils.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.internal.widget;
+
+public class ScrollBarUtils {
+
+    public static int getThumbLength(int size, int thickness, int extent, int range) {
+        // Avoid the tiny thumb.
+        final int minLength = thickness * 2;
+        int length = Math.round((float) size * extent / range);
+        if (length < minLength) {
+            length = minLength;
+        }
+        return length;
+    }
+
+    public static int getThumbOffset(int size, int thumbLength, int extent, int range, int offset) {
+        // Avoid the too-big thumb.
+        int thumbOffset = Math.round((float) (size - thumbLength) * offset / (range - extent));
+        if (thumbOffset > size - thumbLength) {
+            thumbOffset = size - thumbLength;
+        }
+        return thumbOffset;
+    }
+}
diff --git a/core/java/com/android/internal/widget/SubtitleView.java b/core/java/com/android/internal/widget/SubtitleView.java
index 8c395ec..3230185 100644
--- a/core/java/com/android/internal/widget/SubtitleView.java
+++ b/core/java/com/android/internal/widget/SubtitleView.java
@@ -28,6 +28,7 @@
 import android.graphics.RectF;
 import android.graphics.Typeface;
 import android.text.Layout.Alignment;
+import android.text.SpannableStringBuilder;
 import android.text.StaticLayout;
 import android.text.TextPaint;
 import android.util.AttributeSet;
@@ -54,8 +55,8 @@
     /** Temporary rectangle used for computing line bounds. */
     private final RectF mLineBounds = new RectF();
 
-    /** Reusable string builder used for holding text. */
-    private final StringBuilder mText = new StringBuilder();
+    /** Reusable spannable string builder used for holding text. */
+    private final SpannableStringBuilder mText = new SpannableStringBuilder();
 
     private Alignment mAlignment;
     private TextPaint mTextPaint;
@@ -141,7 +142,7 @@
     }
 
     public void setText(CharSequence text) {
-        mText.setLength(0);
+        mText.clear();
         mText.append(text);
 
         mHasMeasurements = false;
diff --git a/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java b/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
index c0215a8..0449340 100644
--- a/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
+++ b/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
@@ -203,9 +203,8 @@
             }
         } catch (EOFException eof) {
             // Initial state may be empty.
-        } finally {
-            dataInput.close();
         }
+        // We explicitly don't close 'dataInput' because we must not close the backing fd.
         return oldMd5Checksum;
     }
 
@@ -219,7 +218,10 @@
 
         dataOutput.writeInt(STATE_VERSION);
         dataOutput.write(md5Checksum);
-        dataOutput.close();
+
+        // We explicitly don't close 'dataOutput' because we must not close the backing fd.
+        // The FileOutputStream will not close it implicitly.
+
     }
 
     private byte[] generateMd5Checksum(byte[] data) throws NoSuchAlgorithmException {
diff --git a/core/java/com/android/server/backup/PermissionBackupHelper.java b/core/java/com/android/server/backup/PermissionBackupHelper.java
new file mode 100644
index 0000000..ff0e63d
--- /dev/null
+++ b/core/java/com/android/server/backup/PermissionBackupHelper.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.AppGlobals;
+import android.app.backup.BlobBackupHelper;
+import android.content.pm.IPackageManager;
+import android.os.UserHandle;
+import android.util.Slog;
+
+public class PermissionBackupHelper extends BlobBackupHelper {
+    private static final String TAG = "PermissionBackup";
+    private static final boolean DEBUG = false;
+
+    // current schema of the backup state blob
+    private static final int STATE_VERSION = 1;
+
+    // key under which the permission-grant state blob is committed to backup
+    private static final String KEY_PERMISSIONS = "permissions";
+
+    public PermissionBackupHelper() {
+        super(STATE_VERSION, KEY_PERMISSIONS);
+    }
+
+    @Override
+    protected byte[] getBackupPayload(String key) {
+        IPackageManager pm = AppGlobals.getPackageManager();
+        if (DEBUG) {
+            Slog.d(TAG, "Handling backup of " + key);
+        }
+        try {
+            switch (key) {
+                case KEY_PERMISSIONS:
+                    return pm.getPermissionGrantBackup(UserHandle.USER_SYSTEM);
+
+                default:
+                    Slog.w(TAG, "Unexpected backup key " + key);
+            }
+        } catch (Exception e) {
+            Slog.e(TAG, "Unable to store payload " + key);
+        }
+        return null;
+    }
+
+    @Override
+    protected void applyRestoredPayload(String key, byte[] payload) {
+        IPackageManager pm = AppGlobals.getPackageManager();
+        if (DEBUG) {
+            Slog.d(TAG, "Handling restore of " + key);
+        }
+        try {
+            switch (key) {
+                case KEY_PERMISSIONS:
+                    pm.restorePermissionGrants(payload, UserHandle.USER_SYSTEM);
+                    break;
+
+                default:
+                    Slog.w(TAG, "Unexpected restore key " + key);
+            }
+        } catch (Exception e) {
+            Slog.w(TAG, "Unable to restore key " + key);
+        }
+    }
+}
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index 234815f..cee98b8 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -46,6 +46,8 @@
     private static final String SYNC_SETTINGS_HELPER = "account_sync_settings";
     private static final String PREFERRED_HELPER = "preferred_activities";
     private static final String NOTIFICATION_HELPER = "notifications";
+    private static final String PERMISSION_HELPER = "permissions";
+    private static final String USAGE_STATS_HELPER = "usage_stats";
 
     // 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
@@ -94,7 +96,8 @@
         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));
         super.onBackup(oldState, data, newState);
     }
 
@@ -128,6 +131,8 @@
         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));
 
         try {
             super.onRestore(data, appVersionCode, newState);
@@ -180,7 +185,7 @@
             if (restoredWallpaper) {
                 IWallpaperManager wallpaper =
                         (IWallpaperManager)ServiceManager.getService(
-                        Context.WALLPAPER_SERVICE);
+                                Context.WALLPAPER_SERVICE);
                 if (wallpaper != null) {
                     try {
                         wallpaper.settingsRestored();
diff --git a/core/java/com/android/server/backup/UsageStatsBackupHelper.java b/core/java/com/android/server/backup/UsageStatsBackupHelper.java
new file mode 100644
index 0000000..bde2396
--- /dev/null
+++ b/core/java/com/android/server/backup/UsageStatsBackupHelper.java
@@ -0,0 +1,70 @@
+package com.android.server.backup;
+
+
+import android.app.backup.BlobBackupHelper;
+import android.app.usage.IUsageStatsManager;
+import android.app.usage.UsageStatsManagerInternal;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Log;
+
+import com.android.server.LocalServices;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class UsageStatsBackupHelper extends BlobBackupHelper {
+    static final String TAG = "UsgStatsBackupHelper";   // must be < 23 chars
+    static final boolean DEBUG = false;
+
+    // Current version of the blob schema
+    static final int BLOB_VERSION = 1;
+
+    // Key under which the payload blob is stored
+    // same as UsageStatsBackupHelperAssistant.KEY_USAGE_STATS
+    static final String KEY_USAGE_STATS = "usage_stats";
+
+    public UsageStatsBackupHelper(Context context) {
+        super(BLOB_VERSION, KEY_USAGE_STATS);
+    }
+
+    @Override
+    protected byte[] getBackupPayload(String key) {
+        if(KEY_USAGE_STATS.equals(key)) {
+            UsageStatsManagerInternal localUsageStatsManager = LocalServices.getService(UsageStatsManagerInternal.class);
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            DataOutputStream out  = new DataOutputStream(baos);
+            try{
+                out.writeInt(UserHandle.USER_SYSTEM);
+                out.write(localUsageStatsManager.getBackupPayload(UserHandle.USER_SYSTEM, key));
+            } catch (IOException ioe){
+                if (DEBUG) Log.e(TAG, "Failed to backup Usage Stats", ioe);
+                baos.reset();
+            }
+            return baos.toByteArray();
+        }
+        return null;
+    }
+
+
+    @Override
+    protected void applyRestoredPayload(String key, byte[] payload)  {
+        if (KEY_USAGE_STATS.equals(key)) {
+            UsageStatsManagerInternal localUsageStatsManager = LocalServices.getService(UsageStatsManagerInternal.class);
+            DataInputStream in = new DataInputStream(new ByteArrayInputStream(payload));
+            try{
+                int user = in.readInt();
+                byte[] restoreData = new byte[payload.length - 4];
+                in.read(restoreData, 0, payload.length-4);
+                localUsageStatsManager.applyRestoredPayload(user, key, restoreData);
+            } catch (IOException ioe){
+                if (DEBUG) Log.e(TAG, "Failed to restore Usage Stats", ioe);
+            }
+        }
+    }
+}
diff --git a/core/java/org/apache/http/conn/ssl/AbstractVerifier.java b/core/java/org/apache/http/conn/ssl/AbstractVerifier.java
index 66a5121..b9349b39 100644
--- a/core/java/org/apache/http/conn/ssl/AbstractVerifier.java
+++ b/core/java/org/apache/http/conn/ssl/AbstractVerifier.java
@@ -208,8 +208,8 @@
     }
 
     public static String[] getCNs(X509Certificate cert) {
-        DistinguishedNameParser dnParser =
-                new DistinguishedNameParser(cert.getSubjectX500Principal());
+        AndroidDistinguishedNameParser dnParser =
+                new AndroidDistinguishedNameParser(cert.getSubjectX500Principal());
         List<String> cnList = dnParser.getAllMostSpecificFirst("cn");
 
         if(!cnList.isEmpty()) {
diff --git a/core/java/org/apache/http/conn/ssl/AndroidDistinguishedNameParser.java b/core/java/org/apache/http/conn/ssl/AndroidDistinguishedNameParser.java
new file mode 100644
index 0000000..4f0b726
--- /dev/null
+++ b/core/java/org/apache/http/conn/ssl/AndroidDistinguishedNameParser.java
@@ -0,0 +1,480 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.http.conn.ssl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * A distinguished name (DN) parser. This parser only supports extracting a
+ * string value from a DN. It doesn't support values in the hex-string style.
+ *
+ * @hide
+ */
+@Deprecated
+final class AndroidDistinguishedNameParser {
+    private final String dn;
+    private final int length;
+    private int pos;
+    private int beg;
+    private int end;
+
+    /** tmp vars to store positions of the currently parsed item */
+    private int cur;
+
+    /** distinguished name chars */
+    private char[] chars;
+
+    public AndroidDistinguishedNameParser(X500Principal principal) {
+        // RFC2253 is used to ensure we get attributes in the reverse
+        // order of the underlying ASN.1 encoding, so that the most
+        // significant values of repeated attributes occur first.
+        this.dn = principal.getName(X500Principal.RFC2253);
+        this.length = this.dn.length();
+    }
+
+    // gets next attribute type: (ALPHA 1*keychar) / oid
+    private String nextAT() {
+        // skip preceding space chars, they can present after
+        // comma or semicolon (compatibility with RFC 1779)
+        for (; pos < length && chars[pos] == ' '; pos++) {
+        }
+        if (pos == length) {
+            return null; // reached the end of DN
+        }
+
+        // mark the beginning of attribute type
+        beg = pos;
+
+        // attribute type chars
+        pos++;
+        for (; pos < length && chars[pos] != '=' && chars[pos] != ' '; pos++) {
+            // we don't follow exact BNF syntax here:
+            // accept any char except space and '='
+        }
+        if (pos >= length) {
+            throw new IllegalStateException("Unexpected end of DN: " + dn);
+        }
+
+        // mark the end of attribute type
+        end = pos;
+
+        // skip trailing space chars between attribute type and '='
+        // (compatibility with RFC 1779)
+        if (chars[pos] == ' ') {
+            for (; pos < length && chars[pos] != '=' && chars[pos] == ' '; pos++) {
+            }
+
+            if (chars[pos] != '=' || pos == length) {
+                throw new IllegalStateException("Unexpected end of DN: " + dn);
+            }
+        }
+
+        pos++; //skip '=' char
+
+        // skip space chars between '=' and attribute value
+        // (compatibility with RFC 1779)
+        for (; pos < length && chars[pos] == ' '; pos++) {
+        }
+
+        // in case of oid attribute type skip its prefix: "oid." or "OID."
+        // (compatibility with RFC 1779)
+        if ((end - beg > 4) && (chars[beg + 3] == '.')
+                && (chars[beg] == 'O' || chars[beg] == 'o')
+                && (chars[beg + 1] == 'I' || chars[beg + 1] == 'i')
+                && (chars[beg + 2] == 'D' || chars[beg + 2] == 'd')) {
+            beg += 4;
+        }
+
+        return new String(chars, beg, end - beg);
+    }
+
+    // gets quoted attribute value: QUOTATION *( quotechar / pair ) QUOTATION
+    private String quotedAV() {
+        pos++;
+        beg = pos;
+        end = beg;
+        while (true) {
+
+            if (pos == length) {
+                throw new IllegalStateException("Unexpected end of DN: " + dn);
+            }
+
+            if (chars[pos] == '"') {
+                // enclosing quotation was found
+                pos++;
+                break;
+            } else if (chars[pos] == '\\') {
+                chars[end] = getEscaped();
+            } else {
+                // shift char: required for string with escaped chars
+                chars[end] = chars[pos];
+            }
+            pos++;
+            end++;
+        }
+
+        // skip trailing space chars before comma or semicolon.
+        // (compatibility with RFC 1779)
+        for (; pos < length && chars[pos] == ' '; pos++) {
+        }
+
+        return new String(chars, beg, end - beg);
+    }
+
+    // gets hex string attribute value: "#" hexstring
+    private String hexAV() {
+        if (pos + 4 >= length) {
+            // encoded byte array  must be not less then 4 c
+            throw new IllegalStateException("Unexpected end of DN: " + dn);
+        }
+
+        beg = pos; // store '#' position
+        pos++;
+        while (true) {
+
+            // check for end of attribute value
+            // looks for space and component separators
+            if (pos == length || chars[pos] == '+' || chars[pos] == ','
+                    || chars[pos] == ';') {
+                end = pos;
+                break;
+            }
+
+            if (chars[pos] == ' ') {
+                end = pos;
+                pos++;
+                // skip trailing space chars before comma or semicolon.
+                // (compatibility with RFC 1779)
+                for (; pos < length && chars[pos] == ' '; pos++) {
+                }
+                break;
+            } else if (chars[pos] >= 'A' && chars[pos] <= 'F') {
+                chars[pos] += 32; //to low case
+            }
+
+            pos++;
+        }
+
+        // verify length of hex string
+        // encoded byte array  must be not less then 4 and must be even number
+        int hexLen = end - beg; // skip first '#' char
+        if (hexLen < 5 || (hexLen & 1) == 0) {
+            throw new IllegalStateException("Unexpected end of DN: " + dn);
+        }
+
+        // get byte encoding from string representation
+        byte[] encoded = new byte[hexLen / 2];
+        for (int i = 0, p = beg + 1; i < encoded.length; p += 2, i++) {
+            encoded[i] = (byte) getByte(p);
+        }
+
+        return new String(chars, beg, hexLen);
+    }
+
+    // gets string attribute value: *( stringchar / pair )
+    private String escapedAV() {
+        beg = pos;
+        end = pos;
+        while (true) {
+            if (pos >= length) {
+                // the end of DN has been found
+                return new String(chars, beg, end - beg);
+            }
+
+            switch (chars[pos]) {
+            case '+':
+            case ',':
+            case ';':
+                // separator char has been found
+                return new String(chars, beg, end - beg);
+            case '\\':
+                // escaped char
+                chars[end++] = getEscaped();
+                pos++;
+                break;
+            case ' ':
+                // need to figure out whether space defines
+                // the end of attribute value or not
+                cur = end;
+
+                pos++;
+                chars[end++] = ' ';
+
+                for (; pos < length && chars[pos] == ' '; pos++) {
+                    chars[end++] = ' ';
+                }
+                if (pos == length || chars[pos] == ',' || chars[pos] == '+'
+                        || chars[pos] == ';') {
+                    // separator char or the end of DN has been found
+                    return new String(chars, beg, cur - beg);
+                }
+                break;
+            default:
+                chars[end++] = chars[pos];
+                pos++;
+            }
+        }
+    }
+
+    // returns escaped char
+    private char getEscaped() {
+        pos++;
+        if (pos == length) {
+            throw new IllegalStateException("Unexpected end of DN: " + dn);
+        }
+
+        switch (chars[pos]) {
+        case '"':
+        case '\\':
+        case ',':
+        case '=':
+        case '+':
+        case '<':
+        case '>':
+        case '#':
+        case ';':
+        case ' ':
+        case '*':
+        case '%':
+        case '_':
+            //FIXME: escaping is allowed only for leading or trailing space char
+            return chars[pos];
+        default:
+            // RFC doesn't explicitly say that escaped hex pair is
+            // interpreted as UTF-8 char. It only contains an example of such DN.
+            return getUTF8();
+        }
+    }
+
+    // decodes UTF-8 char
+    // see http://www.unicode.org for UTF-8 bit distribution table
+    private char getUTF8() {
+        int res = getByte(pos);
+        pos++; //FIXME tmp
+
+        if (res < 128) { // one byte: 0-7F
+            return (char) res;
+        } else if (res >= 192 && res <= 247) {
+
+            int count;
+            if (res <= 223) { // two bytes: C0-DF
+                count = 1;
+                res = res & 0x1F;
+            } else if (res <= 239) { // three bytes: E0-EF
+                count = 2;
+                res = res & 0x0F;
+            } else { // four bytes: F0-F7
+                count = 3;
+                res = res & 0x07;
+            }
+
+            int b;
+            for (int i = 0; i < count; i++) {
+                pos++;
+                if (pos == length || chars[pos] != '\\') {
+                    return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
+                }
+                pos++;
+
+                b = getByte(pos);
+                pos++; //FIXME tmp
+                if ((b & 0xC0) != 0x80) {
+                    return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
+                }
+
+                res = (res << 6) + (b & 0x3F);
+            }
+            return (char) res;
+        } else {
+            return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
+        }
+    }
+
+    // Returns byte representation of a char pair
+    // The char pair is composed of DN char in
+    // specified 'position' and the next char
+    // According to BNF syntax:
+    // hexchar    = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
+    //                    / "a" / "b" / "c" / "d" / "e" / "f"
+    private int getByte(int position) {
+        if (position + 1 >= length) {
+            throw new IllegalStateException("Malformed DN: " + dn);
+        }
+
+        int b1, b2;
+
+        b1 = chars[position];
+        if (b1 >= '0' && b1 <= '9') {
+            b1 = b1 - '0';
+        } else if (b1 >= 'a' && b1 <= 'f') {
+            b1 = b1 - 87; // 87 = 'a' - 10
+        } else if (b1 >= 'A' && b1 <= 'F') {
+            b1 = b1 - 55; // 55 = 'A' - 10
+        } else {
+            throw new IllegalStateException("Malformed DN: " + dn);
+        }
+
+        b2 = chars[position + 1];
+        if (b2 >= '0' && b2 <= '9') {
+            b2 = b2 - '0';
+        } else if (b2 >= 'a' && b2 <= 'f') {
+            b2 = b2 - 87; // 87 = 'a' - 10
+        } else if (b2 >= 'A' && b2 <= 'F') {
+            b2 = b2 - 55; // 55 = 'A' - 10
+        } else {
+            throw new IllegalStateException("Malformed DN: " + dn);
+        }
+
+        return (b1 << 4) + b2;
+    }
+
+    /**
+     * Parses the DN and returns the most significant attribute value
+     * for an attribute type, or null if none found.
+     *
+     * @param attributeType attribute type to look for (e.g. "ca")
+     */
+    public String findMostSpecific(String attributeType) {
+        // Initialize internal state.
+        pos = 0;
+        beg = 0;
+        end = 0;
+        cur = 0;
+        chars = dn.toCharArray();
+
+        String attType = nextAT();
+        if (attType == null) {
+            return null;
+        }
+        while (true) {
+            String attValue = "";
+
+            if (pos == length) {
+                return null;
+            }
+
+            switch (chars[pos]) {
+            case '"':
+                attValue = quotedAV();
+                break;
+            case '#':
+                attValue = hexAV();
+                break;
+            case '+':
+            case ',':
+            case ';': // compatibility with RFC 1779: semicolon can separate RDNs
+                //empty attribute value
+                break;
+            default:
+                attValue = escapedAV();
+            }
+
+            // Values are ordered from most specific to least specific
+            // due to the RFC2253 formatting. So take the first match
+            // we see.
+            if (attributeType.equalsIgnoreCase(attType)) {
+                return attValue;
+            }
+
+            if (pos >= length) {
+                return null;
+            }
+
+            if (chars[pos] == ',' || chars[pos] == ';') {
+            } else if (chars[pos] != '+') {
+                throw new IllegalStateException("Malformed DN: " + dn);
+            }
+
+            pos++;
+            attType = nextAT();
+            if (attType == null) {
+                throw new IllegalStateException("Malformed DN: " + dn);
+            }
+        }
+    }
+
+    /**
+     * Parses the DN and returns all values for an attribute type, in
+     * the order of decreasing significance (most significant first).
+     *
+     * @param attributeType attribute type to look for (e.g. "ca")
+     */
+    public List<String> getAllMostSpecificFirst(String attributeType) {
+        // Initialize internal state.
+        pos = 0;
+        beg = 0;
+        end = 0;
+        cur = 0;
+        chars = dn.toCharArray();
+        List<String> result = Collections.emptyList();
+
+        String attType = nextAT();
+        if (attType == null) {
+            return result;
+        }
+        while (pos < length) {
+            String attValue = "";
+
+            switch (chars[pos]) {
+            case '"':
+                attValue = quotedAV();
+                break;
+            case '#':
+                attValue = hexAV();
+                break;
+            case '+':
+            case ',':
+            case ';': // compatibility with RFC 1779: semicolon can separate RDNs
+                //empty attribute value
+                break;
+            default:
+                attValue = escapedAV();
+            }
+
+            // Values are ordered from most specific to least specific
+            // due to the RFC2253 formatting. So take the first match
+            // we see.
+            if (attributeType.equalsIgnoreCase(attType)) {
+                if (result.isEmpty()) {
+                    result = new ArrayList<String>();
+                }
+                result.add(attValue);
+            }
+
+            if (pos >= length) {
+                break;
+            }
+
+            if (chars[pos] == ',' || chars[pos] == ';') {
+            } else if (chars[pos] != '+') {
+                throw new IllegalStateException("Malformed DN: " + dn);
+            }
+
+            pos++;
+            attType = nextAT();
+            if (attType == null) {
+                throw new IllegalStateException("Malformed DN: " + dn);
+            }
+        }
+
+        return result;
+    }
+}
diff --git a/core/java/org/apache/http/conn/ssl/DistinguishedNameParser.java b/core/java/org/apache/http/conn/ssl/DistinguishedNameParser.java
deleted file mode 100644
index b2d0e3e..0000000
--- a/core/java/org/apache/http/conn/ssl/DistinguishedNameParser.java
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package org.apache.http.conn.ssl;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import javax.security.auth.x500.X500Principal;
-
-/**
- * A distinguished name (DN) parser. This parser only supports extracting a
- * string value from a DN. It doesn't support values in the hex-string style.
- *
- * @hide
- */
-@Deprecated
-final class DistinguishedNameParser {
-    private final String dn;
-    private final int length;
-    private int pos;
-    private int beg;
-    private int end;
-
-    /** tmp vars to store positions of the currently parsed item */
-    private int cur;
-
-    /** distinguished name chars */
-    private char[] chars;
-
-    public DistinguishedNameParser(X500Principal principal) {
-        // RFC2253 is used to ensure we get attributes in the reverse
-        // order of the underlying ASN.1 encoding, so that the most
-        // significant values of repeated attributes occur first.
-        this.dn = principal.getName(X500Principal.RFC2253);
-        this.length = this.dn.length();
-    }
-
-    // gets next attribute type: (ALPHA 1*keychar) / oid
-    private String nextAT() {
-        // skip preceding space chars, they can present after
-        // comma or semicolon (compatibility with RFC 1779)
-        for (; pos < length && chars[pos] == ' '; pos++) {
-        }
-        if (pos == length) {
-            return null; // reached the end of DN
-        }
-
-        // mark the beginning of attribute type
-        beg = pos;
-
-        // attribute type chars
-        pos++;
-        for (; pos < length && chars[pos] != '=' && chars[pos] != ' '; pos++) {
-            // we don't follow exact BNF syntax here:
-            // accept any char except space and '='
-        }
-        if (pos >= length) {
-            throw new IllegalStateException("Unexpected end of DN: " + dn);
-        }
-
-        // mark the end of attribute type
-        end = pos;
-
-        // skip trailing space chars between attribute type and '='
-        // (compatibility with RFC 1779)
-        if (chars[pos] == ' ') {
-            for (; pos < length && chars[pos] != '=' && chars[pos] == ' '; pos++) {
-            }
-
-            if (chars[pos] != '=' || pos == length) {
-                throw new IllegalStateException("Unexpected end of DN: " + dn);
-            }
-        }
-
-        pos++; //skip '=' char
-
-        // skip space chars between '=' and attribute value
-        // (compatibility with RFC 1779)
-        for (; pos < length && chars[pos] == ' '; pos++) {
-        }
-
-        // in case of oid attribute type skip its prefix: "oid." or "OID."
-        // (compatibility with RFC 1779)
-        if ((end - beg > 4) && (chars[beg + 3] == '.')
-                && (chars[beg] == 'O' || chars[beg] == 'o')
-                && (chars[beg + 1] == 'I' || chars[beg + 1] == 'i')
-                && (chars[beg + 2] == 'D' || chars[beg + 2] == 'd')) {
-            beg += 4;
-        }
-
-        return new String(chars, beg, end - beg);
-    }
-
-    // gets quoted attribute value: QUOTATION *( quotechar / pair ) QUOTATION
-    private String quotedAV() {
-        pos++;
-        beg = pos;
-        end = beg;
-        while (true) {
-
-            if (pos == length) {
-                throw new IllegalStateException("Unexpected end of DN: " + dn);
-            }
-
-            if (chars[pos] == '"') {
-                // enclosing quotation was found
-                pos++;
-                break;
-            } else if (chars[pos] == '\\') {
-                chars[end] = getEscaped();
-            } else {
-                // shift char: required for string with escaped chars
-                chars[end] = chars[pos];
-            }
-            pos++;
-            end++;
-        }
-
-        // skip trailing space chars before comma or semicolon.
-        // (compatibility with RFC 1779)
-        for (; pos < length && chars[pos] == ' '; pos++) {
-        }
-
-        return new String(chars, beg, end - beg);
-    }
-
-    // gets hex string attribute value: "#" hexstring
-    private String hexAV() {
-        if (pos + 4 >= length) {
-            // encoded byte array  must be not less then 4 c
-            throw new IllegalStateException("Unexpected end of DN: " + dn);
-        }
-
-        beg = pos; // store '#' position
-        pos++;
-        while (true) {
-
-            // check for end of attribute value
-            // looks for space and component separators
-            if (pos == length || chars[pos] == '+' || chars[pos] == ','
-                    || chars[pos] == ';') {
-                end = pos;
-                break;
-            }
-
-            if (chars[pos] == ' ') {
-                end = pos;
-                pos++;
-                // skip trailing space chars before comma or semicolon.
-                // (compatibility with RFC 1779)
-                for (; pos < length && chars[pos] == ' '; pos++) {
-                }
-                break;
-            } else if (chars[pos] >= 'A' && chars[pos] <= 'F') {
-                chars[pos] += 32; //to low case
-            }
-
-            pos++;
-        }
-
-        // verify length of hex string
-        // encoded byte array  must be not less then 4 and must be even number
-        int hexLen = end - beg; // skip first '#' char
-        if (hexLen < 5 || (hexLen & 1) == 0) {
-            throw new IllegalStateException("Unexpected end of DN: " + dn);
-        }
-
-        // get byte encoding from string representation
-        byte[] encoded = new byte[hexLen / 2];
-        for (int i = 0, p = beg + 1; i < encoded.length; p += 2, i++) {
-            encoded[i] = (byte) getByte(p);
-        }
-
-        return new String(chars, beg, hexLen);
-    }
-
-    // gets string attribute value: *( stringchar / pair )
-    private String escapedAV() {
-        beg = pos;
-        end = pos;
-        while (true) {
-            if (pos >= length) {
-                // the end of DN has been found
-                return new String(chars, beg, end - beg);
-            }
-
-            switch (chars[pos]) {
-            case '+':
-            case ',':
-            case ';':
-                // separator char has been found
-                return new String(chars, beg, end - beg);
-            case '\\':
-                // escaped char
-                chars[end++] = getEscaped();
-                pos++;
-                break;
-            case ' ':
-                // need to figure out whether space defines
-                // the end of attribute value or not
-                cur = end;
-
-                pos++;
-                chars[end++] = ' ';
-
-                for (; pos < length && chars[pos] == ' '; pos++) {
-                    chars[end++] = ' ';
-                }
-                if (pos == length || chars[pos] == ',' || chars[pos] == '+'
-                        || chars[pos] == ';') {
-                    // separator char or the end of DN has been found
-                    return new String(chars, beg, cur - beg);
-                }
-                break;
-            default:
-                chars[end++] = chars[pos];
-                pos++;
-            }
-        }
-    }
-
-    // returns escaped char
-    private char getEscaped() {
-        pos++;
-        if (pos == length) {
-            throw new IllegalStateException("Unexpected end of DN: " + dn);
-        }
-
-        switch (chars[pos]) {
-        case '"':
-        case '\\':
-        case ',':
-        case '=':
-        case '+':
-        case '<':
-        case '>':
-        case '#':
-        case ';':
-        case ' ':
-        case '*':
-        case '%':
-        case '_':
-            //FIXME: escaping is allowed only for leading or trailing space char
-            return chars[pos];
-        default:
-            // RFC doesn't explicitly say that escaped hex pair is
-            // interpreted as UTF-8 char. It only contains an example of such DN.
-            return getUTF8();
-        }
-    }
-
-    // decodes UTF-8 char
-    // see http://www.unicode.org for UTF-8 bit distribution table
-    private char getUTF8() {
-        int res = getByte(pos);
-        pos++; //FIXME tmp
-
-        if (res < 128) { // one byte: 0-7F
-            return (char) res;
-        } else if (res >= 192 && res <= 247) {
-
-            int count;
-            if (res <= 223) { // two bytes: C0-DF
-                count = 1;
-                res = res & 0x1F;
-            } else if (res <= 239) { // three bytes: E0-EF
-                count = 2;
-                res = res & 0x0F;
-            } else { // four bytes: F0-F7
-                count = 3;
-                res = res & 0x07;
-            }
-
-            int b;
-            for (int i = 0; i < count; i++) {
-                pos++;
-                if (pos == length || chars[pos] != '\\') {
-                    return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
-                }
-                pos++;
-
-                b = getByte(pos);
-                pos++; //FIXME tmp
-                if ((b & 0xC0) != 0x80) {
-                    return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
-                }
-
-                res = (res << 6) + (b & 0x3F);
-            }
-            return (char) res;
-        } else {
-            return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
-        }
-    }
-
-    // Returns byte representation of a char pair
-    // The char pair is composed of DN char in
-    // specified 'position' and the next char
-    // According to BNF syntax:
-    // hexchar    = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
-    //                    / "a" / "b" / "c" / "d" / "e" / "f"
-    private int getByte(int position) {
-        if (position + 1 >= length) {
-            throw new IllegalStateException("Malformed DN: " + dn);
-        }
-
-        int b1, b2;
-
-        b1 = chars[position];
-        if (b1 >= '0' && b1 <= '9') {
-            b1 = b1 - '0';
-        } else if (b1 >= 'a' && b1 <= 'f') {
-            b1 = b1 - 87; // 87 = 'a' - 10
-        } else if (b1 >= 'A' && b1 <= 'F') {
-            b1 = b1 - 55; // 55 = 'A' - 10
-        } else {
-            throw new IllegalStateException("Malformed DN: " + dn);
-        }
-
-        b2 = chars[position + 1];
-        if (b2 >= '0' && b2 <= '9') {
-            b2 = b2 - '0';
-        } else if (b2 >= 'a' && b2 <= 'f') {
-            b2 = b2 - 87; // 87 = 'a' - 10
-        } else if (b2 >= 'A' && b2 <= 'F') {
-            b2 = b2 - 55; // 55 = 'A' - 10
-        } else {
-            throw new IllegalStateException("Malformed DN: " + dn);
-        }
-
-        return (b1 << 4) + b2;
-    }
-
-    /**
-     * Parses the DN and returns the most significant attribute value
-     * for an attribute type, or null if none found.
-     *
-     * @param attributeType attribute type to look for (e.g. "ca")
-     */
-    public String findMostSpecific(String attributeType) {
-        // Initialize internal state.
-        pos = 0;
-        beg = 0;
-        end = 0;
-        cur = 0;
-        chars = dn.toCharArray();
-
-        String attType = nextAT();
-        if (attType == null) {
-            return null;
-        }
-        while (true) {
-            String attValue = "";
-
-            if (pos == length) {
-                return null;
-            }
-
-            switch (chars[pos]) {
-            case '"':
-                attValue = quotedAV();
-                break;
-            case '#':
-                attValue = hexAV();
-                break;
-            case '+':
-            case ',':
-            case ';': // compatibility with RFC 1779: semicolon can separate RDNs
-                //empty attribute value
-                break;
-            default:
-                attValue = escapedAV();
-            }
-
-            // Values are ordered from most specific to least specific
-            // due to the RFC2253 formatting. So take the first match
-            // we see.
-            if (attributeType.equalsIgnoreCase(attType)) {
-                return attValue;
-            }
-
-            if (pos >= length) {
-                return null;
-            }
-
-            if (chars[pos] == ',' || chars[pos] == ';') {
-            } else if (chars[pos] != '+') {
-                throw new IllegalStateException("Malformed DN: " + dn);
-            }
-
-            pos++;
-            attType = nextAT();
-            if (attType == null) {
-                throw new IllegalStateException("Malformed DN: " + dn);
-            }
-        }
-    }
-
-    /**
-     * Parses the DN and returns all values for an attribute type, in
-     * the order of decreasing significance (most significant first).
-     *
-     * @param attributeType attribute type to look for (e.g. "ca")
-     */
-    public List<String> getAllMostSpecificFirst(String attributeType) {
-        // Initialize internal state.
-        pos = 0;
-        beg = 0;
-        end = 0;
-        cur = 0;
-        chars = dn.toCharArray();
-        List<String> result = Collections.emptyList();
-
-        String attType = nextAT();
-        if (attType == null) {
-            return result;
-        }
-        while (pos < length) {
-            String attValue = "";
-
-            switch (chars[pos]) {
-            case '"':
-                attValue = quotedAV();
-                break;
-            case '#':
-                attValue = hexAV();
-                break;
-            case '+':
-            case ',':
-            case ';': // compatibility with RFC 1779: semicolon can separate RDNs
-                //empty attribute value
-                break;
-            default:
-                attValue = escapedAV();
-            }
-
-            // Values are ordered from most specific to least specific
-            // due to the RFC2253 formatting. So take the first match
-            // we see.
-            if (attributeType.equalsIgnoreCase(attType)) {
-                if (result.isEmpty()) {
-                    result = new ArrayList<String>();
-                }
-                result.add(attValue);
-            }
-
-            if (pos >= length) {
-                break;
-            }
-
-            if (chars[pos] == ',' || chars[pos] == ';') {
-            } else if (chars[pos] != '+') {
-                throw new IllegalStateException("Malformed DN: " + dn);
-            }
-
-            pos++;
-            attType = nextAT();
-            if (attType == null) {
-                throw new IllegalStateException("Malformed DN: " + dn);
-            }
-        }
-
-        return result;
-    }
-}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index a9a198b..8c4683d 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -7,6 +7,7 @@
 LOCAL_CFLAGS += -Wno-unused-parameter
 LOCAL_CFLAGS += -Wno-non-virtual-dtor
 LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses
+LOCAL_CFLAGS += -DHWUI_NEW_OPS
 LOCAL_CPPFLAGS += -Wno-conversion-null
 
 ifeq ($(TARGET_ARCH), arm)
@@ -33,6 +34,7 @@
     com_google_android_gles_jni_EGLImpl.cpp \
     com_google_android_gles_jni_GLImpl.cpp.arm \
     android_app_NativeActivity.cpp \
+    android_auditing_SecurityLog.cpp \
     android_opengl_EGL14.cpp \
     android_opengl_EGLExt.cpp \
     android_opengl_GLES10.cpp \
@@ -43,11 +45,13 @@
     android_opengl_GLES30.cpp \
     android_opengl_GLES31.cpp \
     android_opengl_GLES31Ext.cpp \
+    android_opengl_GLES32.cpp \
     android_database_CursorWindow.cpp \
     android_database_SQLiteCommon.cpp \
     android_database_SQLiteConnection.cpp \
     android_database_SQLiteGlobal.cpp \
     android_database_SQLiteDebug.cpp \
+    android_graphics_drawable_VectorDrawable.cpp \
     android_view_DisplayEventReceiver.cpp \
     android_view_DisplayListCanvas.cpp \
     android_view_GraphicBuffer.cpp \
@@ -172,7 +176,8 @@
     com_android_internal_net_NetworkStatsFactory.cpp \
     com_android_internal_os_Zygote.cpp \
     com_android_internal_util_VirtualRefBasePtr.cpp \
-    com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
+    com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp \
+    android_os_HardwarePropertiesManager.cpp
 
 LOCAL_C_INCLUDES += \
     $(JNI_H_INCLUDE) \
@@ -184,6 +189,8 @@
     $(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 \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f6f45b5..2e45f8c 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -80,6 +80,7 @@
 extern int register_android_opengl_jni_GLES30(JNIEnv* env);
 extern int register_android_opengl_jni_GLES31(JNIEnv* env);
 extern int register_android_opengl_jni_GLES31Ext(JNIEnv* env);
+extern int register_android_opengl_jni_GLES32(JNIEnv* env);
 
 extern int register_android_hardware_Camera(JNIEnv *env);
 extern int register_android_hardware_camera2_CameraMetadata(JNIEnv *env);
@@ -107,6 +108,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_content_AssetManager(JNIEnv* env);
 extern int register_android_util_EventLog(JNIEnv* env);
 extern int register_android_util_Log(JNIEnv* env);
@@ -129,6 +131,7 @@
 extern int register_android_graphics_Region(JNIEnv* env);
 extern int register_android_graphics_SurfaceTexture(JNIEnv* env);
 extern int register_android_graphics_Xfermode(JNIEnv* env);
+extern int register_android_graphics_drawable_VectorDrawable(JNIEnv* env);
 extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env);
 extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env);
 extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
@@ -194,6 +197,7 @@
 extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env);
 extern int register_com_android_internal_os_Zygote(JNIEnv *env);
 extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
+extern int register_android_os_HardwarePropertiesManager(JNIEnv *env);
 
 static AndroidRuntime* gCurRuntime = NULL;
 
@@ -584,6 +588,7 @@
     char jitmaxsizeOptsBuf[sizeof("-Xjitmaxsize:")-1 + PROPERTY_VALUE_MAX];
     char jitinitialsizeOptsBuf[sizeof("-Xjitinitialsize:")-1 + PROPERTY_VALUE_MAX];
     char jitthresholdOptsBuf[sizeof("-Xjitthreshold:")-1 + PROPERTY_VALUE_MAX];
+    char useJitProfilesOptsBuf[sizeof("-Xjitsaveprofilinginfo:")-1 + PROPERTY_VALUE_MAX];
     char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
     char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
     char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
@@ -689,6 +694,10 @@
     parseRuntimeOption("dalvik.vm.jitmaxsize", jitmaxsizeOptsBuf, "-Xjitmaxsize:");
     parseRuntimeOption("dalvik.vm.jitinitialsize", jitinitialsizeOptsBuf, "-Xjitinitialsize:");
     parseRuntimeOption("dalvik.vm.jitthreshold", jitthresholdOptsBuf, "-Xjitthreshold:");
+    property_get("dalvik.vm.usejitprofiles", useJitProfilesOptsBuf, "");
+    if (strcmp(useJitProfilesOptsBuf, "true") == 0) {
+        addOption("-Xjitsaveprofilinginfo");
+    }
 
     property_get("ro.config.low_ram", propBuf, "");
     if (strcmp(propBuf, "true") == 0) {
@@ -1242,6 +1251,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_content_AssetManager),
     REG_JNI(register_android_content_StringBlock),
     REG_JNI(register_android_content_XmlBlock),
@@ -1255,6 +1265,7 @@
     REG_JNI(register_android_os_Binder),
     REG_JNI(register_android_os_Parcel),
     REG_JNI(register_android_nio_utils),
+    REG_JNI(register_android_graphics_Canvas),
     REG_JNI(register_android_graphics_Graphics),
     REG_JNI(register_android_view_DisplayEventReceiver),
     REG_JNI(register_android_view_RenderNode),
@@ -1280,13 +1291,13 @@
     REG_JNI(register_android_opengl_jni_GLES30),
     REG_JNI(register_android_opengl_jni_GLES31),
     REG_JNI(register_android_opengl_jni_GLES31Ext),
+    REG_JNI(register_android_opengl_jni_GLES32),
 
     REG_JNI(register_android_graphics_Bitmap),
     REG_JNI(register_android_graphics_BitmapFactory),
     REG_JNI(register_android_graphics_BitmapRegionDecoder),
     REG_JNI(register_android_graphics_Camera),
     REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor),
-    REG_JNI(register_android_graphics_Canvas),
     REG_JNI(register_android_graphics_CanvasProperty),
     REG_JNI(register_android_graphics_ColorFilter),
     REG_JNI(register_android_graphics_DrawFilter),
@@ -1310,6 +1321,7 @@
     REG_JNI(register_android_graphics_Typeface),
     REG_JNI(register_android_graphics_Xfermode),
     REG_JNI(register_android_graphics_YuvImage),
+    REG_JNI(register_android_graphics_drawable_VectorDrawable),
     REG_JNI(register_android_graphics_pdf_PdfDocument),
     REG_JNI(register_android_graphics_pdf_PdfEditor),
     REG_JNI(register_android_graphics_pdf_PdfRenderer),
@@ -1376,7 +1388,7 @@
     REG_JNI(register_android_animation_PropertyValuesHolder),
     REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
     REG_JNI(register_com_android_internal_net_NetworkStatsFactory),
-
+    REG_JNI(register_android_os_HardwarePropertiesManager),
 
 };
 
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index a805b6d..80ccb61 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -774,11 +774,14 @@
     return ret;
 }
 
-static void Bitmap_destructor(JNIEnv* env, jobject, jlong bitmapHandle) {
-    LocalScopedBitmap bitmap(bitmapHandle);
+static void Bitmap_destruct(Bitmap* bitmap) {
     bitmap->detachFromJava();
 }
 
+static jlong Bitmap_getNativeFinalizer(JNIEnv*, jobject) {
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Bitmap_destruct));
+}
+
 static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
     LocalScopedBitmap bitmap(bitmapHandle);
     bitmap->freePixels();
@@ -1357,7 +1360,7 @@
         (void*)Bitmap_copy },
     {   "nativeCopyAshmem",         "(J)Landroid/graphics/Bitmap;",
         (void*)Bitmap_copyAshmem },
-    {   "nativeDestructor",         "(J)V", (void*)Bitmap_destructor },
+    {   "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer },
     {   "nativeRecycle",            "(J)Z", (void*)Bitmap_recycle },
     {   "nativeReconfigure",        "(JIIIIZ)V", (void*)Bitmap_reconfigure },
     {   "nativeCompress",           "(JIILjava/io/OutputStream;[B)Z",
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 88b3769..92f7812 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -260,12 +260,21 @@
         return nullObjectReturn("SkAndroidCodec::NewFromStream returned null");
     }
 
+    // Do not allow ninepatch decodes to 565.  In the past, decodes to 565
+    // would dither, and we do not want to pre-dither ninepatches, since we
+    // know that they will be stretched.  We no longer dither 565 decodes,
+    // but we continue to prevent ninepatches from decoding to 565, in order
+    // to maintain the old behavior.
+    if (peeker.mPatch && kRGB_565_SkColorType == prefColorType) {
+        prefColorType = kN32_SkColorType;
+    }
+
     // Determine the output size and return if the client only wants the size.
     SkISize size = codec->getSampledDimensions(sampleSize);
     if (options != NULL) {
         jstring mimeType = encodedFormatToString(env, codec->getEncodedFormat());
         if (env->ExceptionCheck()) {
-            return nullObjectReturn("OOM in getEncodedFormat()");
+            return nullObjectReturn("OOM in encodedFormatToString()");
         }
         env->SetIntField(options, gOptions_widthFieldID, size.width());
         env->SetIntField(options, gOptions_heightFieldID, size.height());
@@ -369,15 +378,7 @@
         case SkCodec::kIncompleteInput:
             break;
         default:
-            return nullObjectReturn("codec->getAndoridPixels() failed.");
-    }
-
-    // Some images may initially report that they have alpha due to the format
-    // of the encoded data, but then never use any colors which have alpha
-    // less than 100%.  Here we check if the image really had alpha, and
-    // mark it as opaque if it is actually opaque.
-    if (kOpaque_SkAlphaType != alphaType && !codec->reallyHasAlpha()) {
-        decodingBitmap.setAlphaType(kOpaque_SkAlphaType);
+            return nullObjectReturn("codec->getAndroidPixels() failed.");
     }
 
     int scaledWidth = size.width();
@@ -587,10 +588,6 @@
     return doDecode(env, stream.release(), NULL, options);
 }
 
-static void nativeRequestCancel(JNIEnv*, jobject joptions) {
-    // Deprecated
-}
-
 static jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) {
     jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
     return ::lseek64(descriptor, 0, SEEK_CUR) != -1 ? JNI_TRUE : JNI_FALSE;
@@ -630,10 +627,6 @@
     },
 };
 
-static const JNINativeMethod gOptionsMethods[] = {
-    {   "requestCancel", "()V", (void*)nativeRequestCancel }
-};
-
 int register_android_graphics_BitmapFactory(JNIEnv* env) {
     jclass options_class = FindClassOrDie(env, "android/graphics/BitmapFactory$Options");
     gOptions_bitmapFieldID = GetFieldIDOrDie(env, options_class, "inBitmap",
@@ -665,8 +658,6 @@
     gInsetStruct_constructorMethodID = GetMethodIDOrDie(env, gInsetStruct_class, "<init>",
                                                         "(IIIIIIIIFIF)V");
 
-    android::RegisterMethodsOrDie(env, "android/graphics/BitmapFactory$Options",
-                                  gOptionsMethods, NELEM(gOptionsMethods));
     return android::RegisterMethodsOrDie(env, "android/graphics/BitmapFactory",
                                          gMethods, NELEM(gMethods));
 }
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index 492d766..a1ba42e 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -136,9 +136,6 @@
         sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
         jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
         colorType = GraphicsJNI::getNativeBitmapColorType(env, jconfig);
-        if (kAlpha_8_SkColorType == colorType) {
-            colorType = kGray_8_SkColorType;
-        }
         requireUnpremul = !env->GetBooleanField(options, gOptions_premultipliedFieldID);
         javaBitmap = env->GetObjectField(options, gOptions_bitmapFieldID);
         // The Java options of ditherMode and preferQualityOverSpeed are deprecated.  We will
@@ -189,6 +186,9 @@
         env->SetIntField(options, gOptions_heightFieldID, bitmap.height());
         env->SetObjectField(options, gOptions_mimeFieldID,
                 encodedFormatToString(env, brd->getEncodedFormat()));
+        if (env->ExceptionCheck()) {
+            return nullObjectReturn("OOM in encodedFormatToString()");
+        }
     }
 
     // If we may have reused a bitmap, we need to indicate that the pixels have changed.
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
index 83fd073..1a86e5f 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -42,7 +42,7 @@
     }
 
     static jlong CreateLightingFilter(JNIEnv* env, jobject, jint mul, jint add) {
-        return reinterpret_cast<jlong>(SkColorFilter::CreateLightingFilter(mul, add));
+        return reinterpret_cast<jlong>(SkColorMatrixFilter::CreateLightingFilter(mul, add));
     }
 
     static jlong CreateColorMatrixFilter(JNIEnv* env, jobject, jfloatArray jarray) {
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index ab0df55..7c8dbe8 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -36,12 +36,12 @@
 namespace android {
 
 static jlong FontFamily_create(JNIEnv* env, jobject clazz, jstring lang, jint variant) {
-    FontLanguage fontLanguage;
-    if (lang != NULL) {
-        ScopedUtfChars str(env, lang);
-        fontLanguage = FontLanguage(str.c_str(), str.size());
+    if (lang == NULL) {
+        return (jlong)new FontFamily(variant);
     }
-    return (jlong)new FontFamily(fontLanguage, variant);
+    ScopedUtfChars str(env, lang);
+    uint32_t langId = FontStyle::registerLanguageList(str.c_str());
+    return (jlong)new FontFamily(langId, variant);
 }
 
 static void FontFamily_unref(JNIEnv* env, jobject clazz, jlong familyPtr) {
diff --git a/core/jni/android/graphics/MinikinUtils.cpp b/core/jni/android/graphics/MinikinUtils.cpp
index 0597d3f..309d35b 100644
--- a/core/jni/android/graphics/MinikinUtils.cpp
+++ b/core/jni/android/graphics/MinikinUtils.cpp
@@ -62,6 +62,15 @@
     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);
diff --git a/core/jni/android/graphics/MinikinUtils.h b/core/jni/android/graphics/MinikinUtils.h
index 5bf1eec..9152539 100644
--- a/core/jni/android/graphics/MinikinUtils.h
+++ b/core/jni/android/graphics/MinikinUtils.h
@@ -40,6 +40,9 @@
             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);
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 654d148..a3214eb 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -76,9 +76,12 @@
         AFTER, AT_OR_AFTER, BEFORE, AT_OR_BEFORE, AT
     };
 
-    static void finalizer(JNIEnv* env, jobject clazz, jlong objHandle) {
-        Paint* obj = reinterpret_cast<Paint*>(objHandle);
-        delete obj;
+    static void deletePaint(Paint* paint) {
+        delete paint;
+    }
+
+    static jlong getNativeFinalizer(JNIEnv*, jobject) {
+        return static_cast<jlong>(reinterpret_cast<uintptr_t>(&deletePaint));
     }
 
     static jlong init(JNIEnv* env, jobject) {
@@ -313,94 +316,10 @@
         obj->setTextAlign(align);
     }
 
-    // generate bcp47 identifier for the supplied locale
-    static void toLanguageTag(char* output, size_t outSize,
-            const char* locale) {
-        if (output == NULL || outSize <= 0) {
-            return;
-        }
-        if (locale == NULL) {
-            output[0] = '\0';
-            return;
-        }
-        char canonicalChars[ULOC_FULLNAME_CAPACITY];
-        UErrorCode uErr = U_ZERO_ERROR;
-        uloc_canonicalize(locale, canonicalChars, ULOC_FULLNAME_CAPACITY,
-                &uErr);
-        if (U_SUCCESS(uErr)) {
-            char likelyChars[ULOC_FULLNAME_CAPACITY];
-            uErr = U_ZERO_ERROR;
-            uloc_addLikelySubtags(canonicalChars, likelyChars,
-                    ULOC_FULLNAME_CAPACITY, &uErr);
-            if (U_SUCCESS(uErr)) {
-                uErr = U_ZERO_ERROR;
-                uloc_toLanguageTag(likelyChars, output, outSize, FALSE, &uErr);
-                if (U_SUCCESS(uErr)) {
-                    return;
-                } else {
-                    ALOGD("uloc_toLanguageTag(\"%s\") failed: %s", likelyChars,
-                            u_errorName(uErr));
-                }
-            } else {
-                ALOGD("uloc_addLikelySubtags(\"%s\") failed: %s",
-                        canonicalChars, u_errorName(uErr));
-            }
-        } else {
-            ALOGD("uloc_canonicalize(\"%s\") failed: %s", locale,
-                    u_errorName(uErr));
-        }
-        // unable to build a proper language identifier
-        output[0] = '\0';
-    }
-
-    static void toLanguageTags(std::string* output, const char* locales) {
-        if (output == NULL) {
-            return;
-        }
-        if (locales == NULL) {
-            output->clear();
-            return;
-        }
-
-        char langTag[ULOC_FULLNAME_CAPACITY];
-        const char* commaLoc = strchr(locales, ',');
-        if (commaLoc == NULL) {
-            assert(locales[0] != '\0');  // the string should not be empty
-            toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, locales);
-            *output = langTag;
-            return;
-        }
-
-        size_t len = strlen(locales);
-        char locale[len];
-        output->clear();
-        output->reserve(len);
-        const char* lastStart = locales;
-        do {
-            assert(lastStart > commaLoc);  // the substring should not be empty
-            strncpy(locale, lastStart, commaLoc - lastStart);
-            locale[commaLoc - lastStart] = '\0';
-            toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, locale);
-            if (langTag[0] != '\0') {
-                output->append(langTag);
-                output->push_back(',');
-            }
-            lastStart = commaLoc + 1;
-            commaLoc = strchr(lastStart, ',');
-        } while (commaLoc != NULL);
-        assert(lastStart[0] != '\0');  // the final substring should not be empty
-        toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, lastStart);
-        if (langTag[0] != '\0') {
-            output->append(langTag);
-        }
-    }
-
     static jint setTextLocales(JNIEnv* env, jobject clazz, jlong objHandle, jstring locales) {
         Paint* obj = reinterpret_cast<Paint*>(objHandle);
         ScopedUtfChars localesChars(env, locales);
-        std::string buf;
-        toLanguageTags(&buf, localesChars.c_str());
-        jint minikinLangListId = FontStyle::registerLanguageList(buf);
+        jint minikinLangListId = FontStyle::registerLanguageList(localesChars.c_str());
         obj->setMinikinLangListId(minikinLangListId);
         return minikinLangListId;
     }
@@ -574,16 +493,16 @@
                 return 0;
             }
         }
-
-        Layout layout;
-        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, start, count,
-                contextCount);
-        if (advances != NULL) {
-            std::unique_ptr<jfloat> advancesArray(new jfloat[count]);
-            layout.getAdvances(advancesArray.get());
+        std::unique_ptr<jfloat[]> advancesArray;
+        if (advances) {
+            advancesArray.reset(new jfloat[count]);
+        }
+        const float advance = MinikinUtils::measureText(paint, bidiFlags, typeface, text,
+                start, count, contextCount, advancesArray.get());
+        if (advances) {
             env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray.get());
         }
-        return layout.getAdvance();
+        return advance;
     }
 
     static jfloat getTextAdvances___CIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
@@ -947,7 +866,7 @@
 }; // namespace PaintGlue
 
 static const JNINativeMethod methods[] = {
-    {"nFinalizer", "(J)V", (void*) PaintGlue::finalizer},
+    {"nGetNativeFinalizer", "()J", (void*) PaintGlue::getNativeFinalizer},
     {"nInit","()J", (void*) PaintGlue::init},
     {"nInitWithPaint","(J)J", (void*) PaintGlue::initWithPaint},
 
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 799ed83..2507e4d 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -61,18 +61,27 @@
     SkASSERT(shaderHandle);
     SkAutoTUnref<SkShader> currentShader(reinterpret_cast<SkShader*>(shaderHandle));
 
-    SkMatrix currentMatrix;
-    SkAutoTUnref<SkShader> baseShader(currentShader->refAsALocalMatrixShader(&currentMatrix));
+    // Attempt to peel off an existing proxy shader and get the proxy's matrix. If
+    // the proxy existed and it's matrix equals the desired matrix then just return
+    // the proxy, otherwise replace it with a new proxy containing the desired matrix.
+    //
+    // refAsALocalMatrixShader(): if the shader contains a proxy then it unwraps the proxy
+    //                            returning both the underlying shader and the proxy's matrix.
+    // newWithLocalMatrix(): will return a proxy shader that wraps the provided shader and
+    //                       concats the provided local matrix with the shader's matrix.
+    //
+    // WARNING: This proxy replacement only behaves like a setter because the Java
+    //          API enforces that all local matrices are set using this call and
+    //          not passed to the constructor of the Shader.
+    SkMatrix proxyMatrix;
+    SkAutoTUnref<SkShader> baseShader(currentShader->refAsALocalMatrixShader(&proxyMatrix));
     if (baseShader.get()) {
-        // if the matrices are same then there is no need to allocate a new
-        // shader that is identical to the existing one.
-        if (currentMatrix == *matrix) {
+        if (proxyMatrix == *matrix) {
             return reinterpret_cast<jlong>(currentShader.detach());
         }
-        return reinterpret_cast<jlong>(SkShader::CreateLocalMatrixShader(baseShader, *matrix));
+        return reinterpret_cast<jlong>(baseShader->newWithLocalMatrix(*matrix));
     }
-
-    return reinterpret_cast<jlong>(SkShader::CreateLocalMatrixShader(currentShader, *matrix));
+    return reinterpret_cast<jlong>(currentShader->newWithLocalMatrix(*matrix));
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 61dc6e4..2018e76 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -18,6 +18,8 @@
 
 #include <stdio.h>
 
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
@@ -34,6 +36,8 @@
 
 // ----------------------------------------------------------------------------
 
+#define EGL_QCOM_PROTECTED_CONTENT 0x32E0
+
 namespace android {
 
 static const char* const OutOfResourcesException =
@@ -55,6 +59,28 @@
     return android_atomic_inc(&globalCounter);
 }
 
+// Check whether the current EGL context is protected.
+static bool isProtectedContext() {
+    EGLDisplay dpy = eglGetCurrentDisplay();
+    EGLContext ctx = eglGetCurrentContext();
+
+    if (dpy == EGL_NO_DISPLAY) {
+        ALOGE("isProtectedSurface: invalid current EGLDisplay");
+        return false;
+    }
+
+    if (ctx == EGL_NO_CONTEXT) {
+        ALOGE("isProtectedSurface: invalid current EGLContext");
+        return false;
+    }
+
+    EGLint isProtected = EGL_FALSE;
+    // TODO: Change the enum value below when an extension is ratified.
+    eglQueryContext(dpy, ctx, EGL_QCOM_PROTECTED_CONTENT, &isProtected);
+
+    return isProtected;
+}
+
 // ----------------------------------------------------------------------------
 
 static void SurfaceTexture_setSurfaceTexture(JNIEnv* env, jobject thiz,
@@ -263,6 +289,11 @@
             getpid(),
             createProcessUniqueId()));
 
+    // If the current context is protected, inform the producer.
+    if (isProtectedContext()) {
+        consumer->setConsumerUsageBits(GRALLOC_USAGE_PROTECTED);
+    }
+
     SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture);
     SurfaceTexture_setProducer(env, thiz, producer);
 
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 6ecb3fb..88a56d2 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -270,7 +270,7 @@
     bool needNativeBridge = false;
 
     void* handle = OpenNativeLibrary(env, sdkVersion, pathStr, classLoader,
-                                     libraryPath, isolationPath);
+                                     false, libraryPath, isolationPath);
     if (handle == NULL) {
         if (NativeBridgeIsSupported(pathStr)) {
             handle = NativeBridgeLoadLibrary(pathStr, RTLD_LAZY);
diff --git a/core/jni/android_auditing_SecurityLog.cpp b/core/jni/android_auditing_SecurityLog.cpp
new file mode 100644
index 0000000..78f04cd
--- /dev/null
+++ b/core/jni/android_auditing_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_auditing_SecurityLog_isLoggingEnabled(JNIEnv* env,
+                                                    jobject /* clazz */) {
+    return (bool)__android_log_security();
+}
+
+static jint android_auditing_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_auditing_SecurityLog_writeEvent_Array(JNIEnv* env, jobject clazz,
+                                                   jint tag, jobjectArray value) {
+    if (value == NULL) {
+        return android_auditing_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_auditing_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_auditing_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_auditing_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_auditing_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_auditing_SecurityLog_isLoggingEnabled
+    },
+    { "writeEvent",
+      "(ILjava/lang/String;)I",
+      (void*) android_auditing_SecurityLog_writeEvent_String
+    },
+    { "writeEvent",
+      "(I[Ljava/lang/Object;)I",
+      (void*) android_auditing_SecurityLog_writeEvent_Array
+    },
+    { "readEvents",
+      "(Ljava/util/Collection;)V",
+      (void*) android_auditing_SecurityLog_readEvents
+    },
+    { "readEventsSince",
+      "(JLjava/util/Collection;)V",
+      (void*) android_auditing_SecurityLog_readEventsSince
+    },
+    { "readPreviousEvents",
+      "(Ljava/util/Collection;)V",
+      (void*) android_auditing_SecurityLog_readPreviousEvents
+    },
+    { "readEventsOnWrapping",
+      "(JLjava/util/Collection;)V",
+      (void*) android_auditing_SecurityLog_readEventsOnWrapping
+    },
+};
+
+static struct { const char *name; jclass *clazz; } gClasses[] = {
+    { "android/auditing/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_auditing_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/auditing/SecurityLog",
+            gRegisterMethods, NELEM(gRegisterMethods));
+}
+
+}; // namespace android
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index e4e73a4..35b5016 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -37,8 +37,12 @@
     return reinterpret_cast<Canvas*>(canvasHandle);
 }
 
-static void finalizer(JNIEnv* env, jobject clazz, jlong canvasHandle) {
-    delete get_canvas(canvasHandle);
+static void delete_canvas(Canvas* canvas) {
+    delete canvas;
+}
+
+static jlong getNativeFinalizer(JNIEnv* env, jobject clazz) {
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&delete_canvas));
 }
 
 // Native wrapper constructor used by Canvas(Bitmap)
@@ -82,20 +86,20 @@
 }
 
 static jint save(JNIEnv*, jobject, jlong canvasHandle, jint flagsHandle) {
-    SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle);
+    SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);
     return static_cast<jint>(get_canvas(canvasHandle)->save(flags));
 }
 
 static jint saveLayer(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t,
                       jfloat r, jfloat b, jlong paintHandle, jint flagsHandle) {
     Paint* paint  = reinterpret_cast<Paint*>(paintHandle);
-    SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle);
+    SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);
     return static_cast<jint>(get_canvas(canvasHandle)->saveLayer(l, t, r, b, paint, flags));
 }
 
 static jint saveLayerAlpha(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t,
                            jfloat r, jfloat b, jint alpha, jint flagsHandle) {
-    SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle);
+    SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);
     return static_cast<jint>(get_canvas(canvasHandle)->saveLayerAlpha(l, t, r, b, alpha, flags));
 }
 
@@ -347,7 +351,7 @@
     if (CC_LIKELY(dstDensity == srcDensity || dstDensity == 0 || srcDensity == 0)) {
         canvas->drawNinePatch(skiaBitmap, *chunk, left, top, right, bottom, paint);
     } else {
-        canvas->save(SkCanvas::kMatrixClip_SaveFlag);
+        canvas->save(SaveFlags::MatrixClip);
 
         SkScalar scale = dstDensity / (float)srcDensity;
         canvas->translate(left, top);
@@ -386,7 +390,7 @@
             canvas->drawBitmap(bitmap, left, top, paint);
         }
     } else {
-        canvas->save(SkCanvas::kMatrixClip_SaveFlag);
+        canvas->save(SaveFlags::MatrixClip);
         SkScalar scale = canvasDensity / (float)bitmapDensity;
         canvas->translate(left, top);
         canvas->scale(scale, scale);
@@ -710,7 +714,7 @@
 }; // namespace CanvasJNI
 
 static const JNINativeMethod gMethods[] = {
-    {"finalizer", "(J)V", (void*) CanvasJNI::finalizer},
+    {"getNativeFinalizer", "()J", (void*) CanvasJNI::getNativeFinalizer},
     {"initRaster", "(Landroid/graphics/Bitmap;)J", (void*) CanvasJNI::initRaster},
     {"native_setBitmap", "!(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap},
     {"native_isOpaque","!(J)Z", (void*) CanvasJNI::isOpaque},
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp
new file mode 100644
index 0000000..563ec8b
--- /dev/null
+++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni.h"
+#include "GraphicsJNI.h"
+#include "core_jni_helpers.h"
+#include "log/log.h"
+
+#include "Paint.h"
+#include "VectorDrawable.h"
+
+namespace android {
+using namespace uirenderer;
+using namespace uirenderer::VectorDrawable;
+
+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 deleteTree(JNIEnv*, jobject, jlong treePtr) {
+    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+    delete 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);
+}
+
+static jlong createFullPath(JNIEnv*, jobject, jlong srcFullPathPtr) {
+    VectorDrawable::FullPath* srcFullPath =
+            reinterpret_cast<VectorDrawable::FullPath*>(srcFullPathPtr);
+    VectorDrawable::FullPath* newPath = new VectorDrawable::FullPath(*srcFullPath);
+    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);
+}
+
+static jlong createClipPath(JNIEnv*, jobject, jlong srcClipPathPtr) {
+    VectorDrawable::ClipPath* srcClipPath =
+            reinterpret_cast<VectorDrawable::ClipPath*>(srcClipPathPtr);
+    VectorDrawable::ClipPath* newPath = new VectorDrawable::ClipPath(*srcClipPath);
+    return reinterpret_cast<jlong>(newPath);
+}
+
+static jlong createEmptyGroup(JNIEnv*, jobject) {
+    VectorDrawable::Group* newGroup = new VectorDrawable::Group();
+    return reinterpret_cast<jlong>(newGroup);
+}
+
+static jlong createGroup(JNIEnv*, jobject, jlong srcGroupPtr) {
+    VectorDrawable::Group* srcGroup = reinterpret_cast<VectorDrawable::Group*>(srcGroupPtr);
+    VectorDrawable::Group* newGroup = new VectorDrawable::Group(*srcGroup);
+    return reinterpret_cast<jlong>(newGroup);
+}
+
+static void deleteNode(JNIEnv*, jobject, jlong nodePtr) {
+    VectorDrawable::Node* node = reinterpret_cast<VectorDrawable::Node*>(nodePtr);
+    delete node;
+}
+
+static void setNodeName(JNIEnv* env, jobject, jlong nodePtr, jstring nameStr) {
+    VectorDrawable::Node* node = reinterpret_cast<VectorDrawable::Node*>(nodePtr);
+    const char* nodeName = env->GetStringUTFChars(nameStr, NULL);
+    node->setName(nodeName);
+    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 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);
+    env->ReleaseStringUTFChars(inputStr, pathString);
+}
+
+static jfloat getRotation(JNIEnv*, jobject, jlong groupPtr) {
+    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+    return group->getRotation();
+}
+
+static void setRotation(JNIEnv*, jobject, jlong groupPtr, jfloat rotation) {
+    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+    group->setRotation(rotation);
+}
+
+static jfloat getPivotX(JNIEnv*, jobject, jlong groupPtr) {
+    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+    return group->getPivotX();
+}
+
+static void setPivotX(JNIEnv*, jobject, jlong groupPtr, jfloat pivotX) {
+    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+    group->setPivotX(pivotX);
+}
+
+static jfloat getPivotY(JNIEnv*, jobject, jlong groupPtr) {
+    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+    return group->getPivotY();
+}
+
+static void setPivotY(JNIEnv*, jobject, jlong groupPtr, jfloat pivotY) {
+    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+    group->setPivotY(pivotY);
+}
+
+static jfloat getScaleX(JNIEnv*, jobject, jlong groupPtr) {
+    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+    return group->getScaleX();
+}
+
+static void setScaleX(JNIEnv*, jobject, jlong groupPtr, jfloat scaleX) {
+    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+    group->setScaleX(scaleX);
+}
+
+static jfloat getScaleY(JNIEnv*, jobject, jlong groupPtr) {
+    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+    return group->getScaleY();
+}
+
+static void setScaleY(JNIEnv*, jobject, jlong groupPtr, jfloat scaleY) {
+    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+    group->setScaleY(scaleY);
+}
+
+static jfloat getTranslateX(JNIEnv*, jobject, jlong groupPtr) {
+    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+    return group->getTranslateX();
+}
+
+static void setTranslateX(JNIEnv*, jobject, jlong groupPtr, jfloat translateX) {
+    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+    group->setTranslateX(translateX);
+}
+
+static jfloat getTranslateY(JNIEnv*, jobject, jlong groupPtr) {
+    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+    return group->getTranslateY();
+}
+
+static void setTranslateY(JNIEnv*, jobject, jlong groupPtr, jfloat translateY) {
+    VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+    group->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);
+}
+
+static jfloat getStrokeWidth(JNIEnv*, jobject, jlong fullPathPtr) {
+    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+    return fullPath->getStrokeWidth();
+}
+
+static void setStrokeWidth(JNIEnv*, jobject, jlong fullPathPtr, jfloat strokeWidth) {
+    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+    fullPath->setStrokeWidth(strokeWidth);
+}
+
+static jint getStrokeColor(JNIEnv*, jobject, jlong fullPathPtr) {
+    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+    return fullPath->getStrokeColor();
+}
+
+static void setStrokeColor(JNIEnv*, jobject, jlong fullPathPtr, jint strokeColor) {
+    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+    fullPath->setStrokeColor(strokeColor);
+}
+
+static jfloat getStrokeAlpha(JNIEnv*, jobject, jlong fullPathPtr) {
+    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+    return fullPath->getStrokeAlpha();
+}
+
+static void setStrokeAlpha(JNIEnv*, jobject, jlong fullPathPtr, jfloat strokeAlpha) {
+    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+    fullPath->setStrokeAlpha(strokeAlpha);
+}
+
+static jint getFillColor(JNIEnv*, jobject, jlong fullPathPtr) {
+    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+    return fullPath->getFillColor();
+}
+
+static void setFillColor(JNIEnv*, jobject, jlong fullPathPtr, jint fillColor) {
+    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+    fullPath->setFillColor(fillColor);
+}
+
+static jfloat getFillAlpha(JNIEnv*, jobject, jlong fullPathPtr) {
+    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+    return fullPath->getFillAlpha();
+}
+
+static void setFillAlpha(JNIEnv*, jobject, jlong fullPathPtr, jfloat fillAlpha) {
+    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+    fullPath->setFillAlpha(fillAlpha);
+}
+
+static jfloat getTrimPathStart(JNIEnv*, jobject, jlong fullPathPtr) {
+    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+    return fullPath->getTrimPathStart();
+}
+
+static void setTrimPathStart(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathStart) {
+    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+    fullPath->setTrimPathStart(trimPathStart);
+}
+
+static jfloat getTrimPathEnd(JNIEnv*, jobject, jlong fullPathPtr) {
+    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+    return fullPath->getTrimPathEnd();
+}
+
+static void setTrimPathEnd(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathEnd) {
+    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+    fullPath->setTrimPathEnd(trimPathEnd);
+}
+
+static jfloat getTrimPathOffset(JNIEnv*, jobject, jlong fullPathPtr) {
+    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+    return fullPath->getTrimPathOffset();
+}
+
+static void setTrimPathOffset(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathOffset) {
+    VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+    fullPath->setTrimPathOffset(trimPathOffset);
+}
+
+static const JNINativeMethod gMethods[] = {
+        {"nCreateRenderer", "!(J)J", (void*)createTree},
+        {"nDestroyRenderer", "!(J)V", (void*)deleteTree},
+        {"nSetRendererViewportSize", "!(JFF)V", (void*)setTreeViewportSize},
+        {"nSetRootAlpha", "!(JF)Z", (void*)setRootAlpha},
+        {"nGetRootAlpha", "!(J)F", (void*)getRootAlpha},
+        {"nSetAllowCaching", "!(JZ)V", (void*)setAllowCaching},
+
+        {"nDraw", "(JJJLandroid/graphics/Rect;ZZ)V", (void*)draw},
+        {"nCreateFullPath", "!()J", (void*)createEmptyFullPath},
+        {"nCreateFullPath", "!(J)J", (void*)createFullPath},
+        {"nUpdateFullPathProperties", "!(JFIFIFFFFFII)V", (void*)updateFullPathPropertiesAndStrokeStyles},
+        {"nUpdateFullPathFillGradient", "!(JJ)V", (void*)updateFullPathFillGradient},
+        {"nUpdateFullPathStrokeGradient", "!(JJ)V", (void*)updateFullPathStrokeGradient},
+        {"nGetFullPathProperties", "(J[BI)Z", (void*)getFullPathProperties},
+        {"nGetGroupProperties", "(J[FI)Z", (void*)getGroupProperties},
+
+        {"nCreateClipPath", "!()J", (void*)createEmptyClipPath},
+        {"nCreateClipPath", "!(J)J", (void*)createClipPath},
+        {"nCreateGroup", "!()J", (void*)createEmptyGroup},
+        {"nCreateGroup", "!(J)J", (void*)createGroup},
+        {"nDestroy", "!(J)V", (void*)deleteNode},
+        {"nSetName", "(JLjava/lang/String;)V", (void*)setNodeName},
+        {"nUpdateGroupProperties", "!(JFFFFFFF)V", (void*)updateGroupProperties},
+
+        {"nAddChild", "!(JJ)V", (void*)addChild},
+        {"nSetPathString", "(JLjava/lang/String;I)V", (void*)setPathString},
+
+        {"nGetRotation", "!(J)F", (void*)getRotation},
+        {"nSetRotation", "!(JF)V", (void*)setRotation},
+        {"nGetPivotX", "!(J)F", (void*)getPivotX},
+        {"nSetPivotX", "!(JF)V", (void*)setPivotX},
+        {"nGetPivotY", "!(J)F", (void*)getPivotY},
+        {"nSetPivotY", "!(JF)V", (void*)setPivotY},
+        {"nGetScaleX", "!(J)F", (void*)getScaleX},
+        {"nSetScaleX", "!(JF)V", (void*)setScaleX},
+        {"nGetScaleY", "!(J)F", (void*)getScaleY},
+        {"nSetScaleY", "!(JF)V", (void*)setScaleY},
+        {"nGetTranslateX", "!(J)F", (void*)getTranslateX},
+        {"nSetTranslateX", "!(JF)V", (void*)setTranslateX},
+        {"nGetTranslateY", "!(J)F", (void*)getTranslateY},
+        {"nSetTranslateY", "!(JF)V", (void*)setTranslateY},
+
+        {"nSetPathData", "!(JJ)V", (void*)setPathData},
+        {"nGetStrokeWidth", "!(J)F", (void*)getStrokeWidth},
+        {"nSetStrokeWidth", "!(JF)V", (void*)setStrokeWidth},
+        {"nGetStrokeColor", "!(J)I", (void*)getStrokeColor},
+        {"nSetStrokeColor", "!(JI)V", (void*)setStrokeColor},
+        {"nGetStrokeAlpha", "!(J)F", (void*)getStrokeAlpha},
+        {"nSetStrokeAlpha", "!(JF)V", (void*)setStrokeAlpha},
+        {"nGetFillColor", "!(J)I", (void*)getFillColor},
+        {"nSetFillColor", "!(JI)V", (void*)setFillColor},
+        {"nGetFillAlpha", "!(J)F", (void*)getFillAlpha},
+        {"nSetFillAlpha", "!(JF)V", (void*)setFillAlpha},
+        {"nGetTrimPathStart", "!(J)F", (void*)getTrimPathStart},
+        {"nSetTrimPathStart", "!(JF)V", (void*)setTrimPathStart},
+        {"nGetTrimPathEnd", "!(J)F", (void*)getTrimPathEnd},
+        {"nSetTrimPathEnd", "!(JF)V", (void*)setTrimPathEnd},
+        {"nGetTrimPathOffset", "!(J)F", (void*)getTrimPathOffset},
+        {"nSetTrimPathOffset", "!(JF)V", (void*)setTrimPathOffset},
+};
+
+int register_android_graphics_drawable_VectorDrawable(JNIEnv* env) {
+    return RegisterMethodsOrDie(env, "android/graphics/drawable/VectorDrawable", gMethods, NELEM(gMethods));
+}
+
+}; // namespace android
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 414eba7..806fcc3 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -534,7 +534,7 @@
     if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {
         // Default path: hal version is don't care, do normal camera connect.
         camera = Camera::connect(cameraId, clientName,
-                Camera::USE_CALLING_UID);
+                Camera::USE_CALLING_UID, Camera::USE_CALLING_PID);
     } else {
         jint status = Camera::connectLegacy(cameraId, halVersion, clientName,
                 Camera::USE_CALLING_UID, camera);
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 2e5cda0..4842e1b 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -23,6 +23,7 @@
 
 #include <utils/Log.h>
 #include <utils/Looper.h>
+#include <utils/Vector.h>
 
 #include <gui/Sensor.h>
 #include <gui/SensorManager.h>
@@ -39,12 +40,14 @@
     jclass clazz;
     jmethodID dispatchSensorEvent;
     jmethodID dispatchFlushCompleteEvent;
+    jmethodID dispatchAdditionalInfoEvent;
 } gBaseEventQueueClassInfo;
 
 namespace android {
 
 struct SensorOffsets
 {
+    jclass      clazz;
     jfieldID    name;
     jfieldID    vendor;
     jfieldID    version;
@@ -60,8 +63,13 @@
     jfieldID    maxDelay;
     jfieldID    flags;
     jmethodID   setType;
+    jmethodID   init;
 } gSensorOffsets;
 
+struct ListOffsets {
+    jclass      clazz;
+    jmethodID   add;
+} gListOffsets;
 
 /*
  * The method below are not thread-safe and not intended to be
@@ -70,8 +78,10 @@
 static void
 nativeClassInit (JNIEnv *_env, jclass _this)
 {
-    jclass sensorClass = _env->FindClass("android/hardware/Sensor");
+    //android.hardware.Sensor
     SensorOffsets& sensorOffsets = gSensorOffsets;
+    jclass sensorClass = (jclass) _env->NewGlobalRef(_env->FindClass("android/hardware/Sensor"));
+    sensorOffsets.clazz       = sensorClass;
     sensorOffsets.name        = _env->GetFieldID(sensorClass, "mName",      "Ljava/lang/String;");
     sensorOffsets.vendor      = _env->GetFieldID(sensorClass, "mVendor",    "Ljava/lang/String;");
     sensorOffsets.version     = _env->GetFieldID(sensorClass, "mVersion",   "I");
@@ -88,7 +98,15 @@
                                                         "Ljava/lang/String;");
     sensorOffsets.maxDelay    = _env->GetFieldID(sensorClass, "mMaxDelay",  "I");
     sensorOffsets.flags = _env->GetFieldID(sensorClass, "mFlags",  "I");
+
     sensorOffsets.setType = _env->GetMethodID(sensorClass, "setType", "(I)Z");
+    sensorOffsets.init = _env->GetMethodID(sensorClass, "<init>", "()V");
+
+    // java.util.List;
+    ListOffsets& listOffsets = gListOffsets;
+    jclass listClass = (jclass) _env->NewGlobalRef(_env->FindClass("java/util/List"));
+    listOffsets.clazz = listClass;
+    listOffsets.add = _env->GetMethodID(listClass, "add", "(Ljava/lang/Object;)Z");
 }
 
 /**
@@ -141,6 +159,46 @@
     return (jlong) &SensorManager::getInstanceForPackage(String16(opPackageNameUtf.c_str()));
 }
 
+static jobject
+translateNativeSensorToJavaSensor(JNIEnv *env, jobject sensor, const Sensor& nativeSensor) {
+    const SensorOffsets& sensorOffsets(gSensorOffsets);
+
+    if (sensor == NULL) {
+        // Sensor sensor = new Sensor();
+        sensor = env->NewObject(sensorOffsets.clazz, sensorOffsets.init, "");
+    }
+
+    if (sensor != NULL) {
+        jstring name = env->NewStringUTF(nativeSensor.getName().string());
+        jstring vendor = env->NewStringUTF(nativeSensor.getVendor().string());
+        jstring requiredPermission =
+                env->NewStringUTF(nativeSensor.getRequiredPermission().string());
+
+        env->SetObjectField(sensor, sensorOffsets.name,      name);
+        env->SetObjectField(sensor, sensorOffsets.vendor,    vendor);
+        env->SetIntField(sensor, sensorOffsets.version,      nativeSensor.getVersion());
+        env->SetIntField(sensor, sensorOffsets.handle,       nativeSensor.getHandle());
+        env->SetFloatField(sensor, sensorOffsets.range,      nativeSensor.getMaxValue());
+        env->SetFloatField(sensor, sensorOffsets.resolution, nativeSensor.getResolution());
+        env->SetFloatField(sensor, sensorOffsets.power,      nativeSensor.getPowerUsage());
+        env->SetIntField(sensor, sensorOffsets.minDelay,     nativeSensor.getMinDelay());
+        env->SetIntField(sensor, sensorOffsets.fifoReservedEventCount,
+                         nativeSensor.getFifoReservedEventCount());
+        env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount,
+                         nativeSensor.getFifoMaxEventCount());
+        env->SetObjectField(sensor, sensorOffsets.requiredPermission,
+                            requiredPermission);
+        env->SetIntField(sensor, sensorOffsets.maxDelay, nativeSensor.getMaxDelay());
+        env->SetIntField(sensor, sensorOffsets.flags, nativeSensor.getFlags());
+        if (env->CallBooleanMethod(sensor, sensorOffsets.setType, nativeSensor.getType())
+                == JNI_FALSE) {
+            jstring stringType = getInternedString(env, &nativeSensor.getStringType());
+            env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
+        }
+    }
+    return sensor;
+}
+
 static jboolean
 nativeGetSensorAtIndex(JNIEnv *env, jclass clazz, jlong sensorManager, jobject sensor, jint index)
 {
@@ -180,6 +238,24 @@
     return true;
 }
 
+static void
+nativeGetDynamicSensors(JNIEnv *env, jclass clazz, jlong sensorManager, jobject sensorList) {
+
+    SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
+    const ListOffsets& listOffsets(gListOffsets);
+
+    Vector<Sensor> nativeList;
+
+    mgr->getDynamicSensorList(nativeList);
+
+    ALOGI("DYNS native SensorManager.getDynamicSensorList return %d sensors", nativeList.size());
+    for (size_t i = 0; i < nativeList.size(); ++i) {
+        jobject sensor = translateNativeSensorToJavaSensor(env, NULL, nativeList[i]);
+        // add to list
+        env->CallBooleanMethod(sensorList, listOffsets.add, sensor);
+    }
+}
+
 static jboolean nativeIsDataInjectionEnabled(JNIEnv *_env, jclass _this, jlong sensorManager) {
     SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
     return mgr->isDataInjectionEnabled();
@@ -191,21 +267,25 @@
     sp<SensorEventQueue> mSensorQueue;
     sp<MessageQueue> mMessageQueue;
     jobject mReceiverWeakGlobal;
-    jfloatArray mScratch;
+    jfloatArray mFloatScratch;
+    jintArray   mIntScratch;
 public:
     Receiver(const sp<SensorEventQueue>& sensorQueue,
             const sp<MessageQueue>& messageQueue,
-            jobject receiverWeak, jfloatArray scratch) {
+            jobject receiverWeak) {
         JNIEnv* env = AndroidRuntime::getJNIEnv();
         mSensorQueue = sensorQueue;
         mMessageQueue = messageQueue;
         mReceiverWeakGlobal = env->NewGlobalRef(receiverWeak);
-        mScratch = (jfloatArray)env->NewGlobalRef(scratch);
+
+        mIntScratch = (jintArray) env->NewGlobalRef(env->NewIntArray(16));
+        mFloatScratch = (jfloatArray) env->NewGlobalRef(env->NewFloatArray(16));
     }
     ~Receiver() {
         JNIEnv* env = AndroidRuntime::getJNIEnv();
         env->DeleteGlobalRef(mReceiverWeakGlobal);
-        env->DeleteGlobalRef(mScratch);
+        env->DeleteGlobalRef(mFloatScratch);
+        env->DeleteGlobalRef(mIntScratch);
     }
     sp<SensorEventQueue> getSensorEventQueue() const {
         return mSensorQueue;
@@ -234,9 +314,19 @@
                 if (buffer[i].type == SENSOR_TYPE_STEP_COUNTER) {
                     // step-counter returns a uint64, but the java API only deals with floats
                     float value = float(buffer[i].u64.step_counter);
-                    env->SetFloatArrayRegion(mScratch, 0, 1, &value);
+                    env->SetFloatArrayRegion(mFloatScratch, 0, 1, &value);
+                } else if (buffer[i].type == SENSOR_TYPE_DYNAMIC_SENSOR_META) {
+                    float value[2];
+                    value[0] = buffer[i].dynamic_sensor_meta.connected ? 1.f: 0.f;
+                    value[1] = float(buffer[i].dynamic_sensor_meta.handle);
+                    env->SetFloatArrayRegion(mFloatScratch, 0, 2, value);
+                } else if (buffer[i].type == SENSOR_TYPE_ADDITIONAL_INFO) {
+                    env->SetIntArrayRegion(mIntScratch, 0, 14,
+                                           buffer[i].additional_info.data_int32);
+                    env->SetFloatArrayRegion(mFloatScratch, 0, 14,
+                                             buffer[i].additional_info.data_float);
                 } else {
-                    env->SetFloatArrayRegion(mScratch, 0, 16, buffer[i].data);
+                    env->SetFloatArrayRegion(mFloatScratch, 0, 16, buffer[i].data);
                 }
 
                 if (buffer[i].type == SENSOR_TYPE_META_DATA) {
@@ -247,7 +337,21 @@
                                             gBaseEventQueueClassInfo.dispatchFlushCompleteEvent,
                                             buffer[i].meta_data.sensor);
                     }
-                } else {
+                } else if (buffer[i].type == SENSOR_TYPE_ADDITIONAL_INFO) {
+                    // This is a flush complete sensor event. Call dispatchAdditionalInfoEvent
+                    // method.
+                    if (receiverObj.get()) {
+                        int type = buffer[i].additional_info.type;
+                        int serial = buffer[i].additional_info.serial;
+                        env->CallVoidMethod(receiverObj.get(),
+                                            gBaseEventQueueClassInfo.dispatchAdditionalInfoEvent,
+                                            buffer[i].sensor,
+                                            type, serial,
+                                            mFloatScratch,
+                                            mIntScratch,
+                                            buffer[i].timestamp);
+                    }
+                }else {
                     int8_t status;
                     switch (buffer[i].type) {
                     case SENSOR_TYPE_ORIENTATION:
@@ -269,7 +373,7 @@
                         env->CallVoidMethod(receiverObj.get(),
                                             gBaseEventQueueClassInfo.dispatchSensorEvent,
                                             buffer[i].sensor,
-                                            mScratch,
+                                            mFloatScratch,
                                             status,
                                             buffer[i].timestamp);
                     }
@@ -290,7 +394,7 @@
 };
 
 static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jlong sensorManager,
-        jobject eventQWeak, jobject msgQ, jfloatArray scratch, jstring packageName, jint mode) {
+        jobject eventQWeak, jobject msgQ, jstring packageName, jint mode) {
     SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
     ScopedUtfChars packageUtf(env, packageName);
     String8 clientName(packageUtf.c_str());
@@ -302,7 +406,7 @@
         return 0;
     }
 
-    sp<Receiver> receiver = new Receiver(queue, messageQueue, eventQWeak, scratch);
+    sp<Receiver> receiver = new Receiver(queue, messageQueue, eventQWeak);
     receiver->incStrong((void*)nativeInitSensorEventQueue);
     return jlong(receiver.get());
 }
@@ -355,6 +459,10 @@
             "(JLandroid/hardware/Sensor;I)Z",
             (void*)nativeGetSensorAtIndex },
 
+    {"nativeGetDynamicSensors",
+            "(JLjava/util/List;)V",
+            (void*)nativeGetDynamicSensors },
+
     {"nativeIsDataInjectionEnabled",
             "(J)Z",
             (void*)nativeIsDataInjectionEnabled},
@@ -362,7 +470,7 @@
 
 static const JNINativeMethod gBaseEventQueueMethods[] = {
     {"nativeInitBaseEventQueue",
-             "(JLjava/lang/ref/WeakReference;Landroid/os/MessageQueue;[FLjava/lang/String;ILjava/lang/String;)J",
+             "(JLjava/lang/ref/WeakReference;Landroid/os/MessageQueue;Ljava/lang/String;ILjava/lang/String;)J",
              (void*)nativeInitSensorEventQueue },
 
     {"nativeEnableSensor",
@@ -407,5 +515,8 @@
     gBaseEventQueueClassInfo.dispatchFlushCompleteEvent = GetMethodIDOrDie(env,
             gBaseEventQueueClassInfo.clazz, "dispatchFlushCompleteEvent", "(I)V");
 
+    gBaseEventQueueClassInfo.dispatchAdditionalInfoEvent = GetMethodIDOrDie(env,
+            gBaseEventQueueClassInfo.clazz, "dispatchAdditionalInfoEvent", "(III[F[I)V");
+
     return 0;
 }
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 6d3c7d7..8e8f6c3 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -152,7 +152,8 @@
 
 static struct {
     jmethodID postDynPolicyEventFromNative;
-} gDynPolicyEventHandlerMethods;
+    jmethodID postRecordConfigEventFromNative;
+} gAudioPolicyEventHandlerMethods;
 
 static Mutex gLock;
 
@@ -378,12 +379,26 @@
     const char* zechars = regId.string();
     jstring zestring = env->NewStringUTF(zechars);
 
-    env->CallStaticVoidMethod(clazz, gDynPolicyEventHandlerMethods.postDynPolicyEventFromNative,
+    env->CallStaticVoidMethod(clazz, gAudioPolicyEventHandlerMethods.postDynPolicyEventFromNative,
             event, zestring, val);
 
     env->ReleaseStringUTFChars(zestring, zechars);
     env->DeleteLocalRef(clazz);
+}
 
+static void
+android_media_AudioSystem_recording_callback(int event, int session, int source)
+{
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    if (env == NULL) {
+        return;
+    }
+
+    jclass clazz = env->FindClass(kClassPathName);
+    env->CallStaticVoidMethod(clazz,
+            gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative,
+            event, session, source);
+    env->DeleteLocalRef(clazz);
 }
 
 static jint
@@ -498,6 +513,22 @@
 }
 
 static jint
+android_media_AudioSystem_setMasterMono(JNIEnv *env, jobject thiz, jboolean mono)
+{
+    return (jint) check_AudioSystem_Command(AudioSystem::setMasterMono(mono));
+}
+
+static jboolean
+android_media_AudioSystem_getMasterMono(JNIEnv *env, jobject thiz)
+{
+    bool mono;
+    if (AudioSystem::getMasterMono(&mono) != NO_ERROR) {
+        mono = false;
+    }
+    return mono;
+}
+
+static jint
 android_media_AudioSystem_getDevicesForStream(JNIEnv *env, jobject thiz, jint stream)
 {
     return (jint) AudioSystem::getDevicesForStream(static_cast <audio_stream_type_t>(stream));
@@ -1487,6 +1518,12 @@
     AudioSystem::setDynPolicyCallback(android_media_AudioSystem_dyn_policy_callback);
 }
 
+static void
+android_media_AudioSystem_registerRecordingCallback(JNIEnv *env, jobject thiz)
+{
+    AudioSystem::setRecordConfigCallback(android_media_AudioSystem_recording_callback);
+}
+
 
 static jint convertAudioMixToNative(JNIEnv *env,
                                     AudioMix *nAudioMix,
@@ -1637,6 +1674,8 @@
     {"getMasterVolume",     "()F",      (void *)android_media_AudioSystem_getMasterVolume},
     {"setMasterMute",       "(Z)I",     (void *)android_media_AudioSystem_setMasterMute},
     {"getMasterMute",       "()Z",      (void *)android_media_AudioSystem_getMasterMute},
+    {"setMasterMono",       "(Z)I",     (void *)android_media_AudioSystem_setMasterMono},
+    {"getMasterMono",       "()Z",      (void *)android_media_AudioSystem_getMasterMono},
     {"getDevicesForStream", "(I)I",     (void *)android_media_AudioSystem_getDevicesForStream},
     {"getPrimaryOutputSamplingRate", "()I", (void *)android_media_AudioSystem_getPrimaryOutputSamplingRate},
     {"getPrimaryOutputFrameCount",   "()I", (void *)android_media_AudioSystem_getPrimaryOutputFrameCount},
@@ -1659,6 +1698,8 @@
                                             (void *)android_media_AudioSystem_registerPolicyMixes},
     {"native_register_dynamic_policy_callback", "()V",
                                     (void *)android_media_AudioSystem_registerDynPolicyCallback},
+    {"native_register_recording_callback", "()V",
+                                    (void *)android_media_AudioSystem_registerRecordingCallback},
     {"systemReady", "()I", (void *)android_media_AudioSystem_systemReady},
 };
 
@@ -1762,9 +1803,12 @@
     gEventHandlerFields.mJniCallback = GetFieldIDOrDie(env,
                                                     eventHandlerClass, "mJniCallback", "J");
 
-    gDynPolicyEventHandlerMethods.postDynPolicyEventFromNative =
+    gAudioPolicyEventHandlerMethods.postDynPolicyEventFromNative =
             GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName),
                     "dynamicPolicyCallbackFromNative", "(ILjava/lang/String;I)V");
+    gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative =
+            GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName),
+                    "recordingCallbackFromNative", "(III)V");
 
     jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix");
     gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass);
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 7860b74..61f185e 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -656,18 +656,59 @@
 }
 
 // ----------------------------------------------------------------------------
-static jint android_media_AudioTrack_get_native_frame_count(JNIEnv *env,  jobject thiz) {
+static jint android_media_AudioTrack_get_buffer_size_frames(JNIEnv *env,  jobject thiz) {
     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
-            "Unable to retrieve AudioTrack pointer for frameCount()");
+            "Unable to retrieve AudioTrack pointer for getBufferSizeInFrames()");
+        return (jint)AUDIO_JAVA_ERROR;
+    }
+
+    ssize_t result = lpTrack->getBufferSizeInFrames();
+    if (result < 0) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Internal error detected in getBufferSizeInFrames() = " + result);
+        return (jint)AUDIO_JAVA_ERROR;
+    }
+    return (jint)result;
+}
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_set_buffer_size_frames(JNIEnv *env,
+        jobject thiz, jint bufferSizeInFrames) {
+    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+    if (lpTrack == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for setBufferSizeInFrames()");
+        return (jint)AUDIO_JAVA_ERROR;
+    }
+    // Value will be coerced into the valid range.
+    // But internal values are unsigned, size_t, so we need to clip
+    // against zero here where it is signed.
+    if (bufferSizeInFrames < 0) {
+        bufferSizeInFrames = 0;
+    }
+    ssize_t result = lpTrack->setBufferSizeInFrames(bufferSizeInFrames);
+    if (result < 0) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Internal error detected in setBufferSizeInFrames() = " + result);
+        return (jint)AUDIO_JAVA_ERROR;
+    }
+    return (jint)result;
+}
+
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_get_buffer_capacity_frames(JNIEnv *env,  jobject thiz) {
+    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+    if (lpTrack == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for getBufferCapacityInFrames()");
         return (jint)AUDIO_JAVA_ERROR;
     }
 
     return lpTrack->frameCount();
 }
 
-
 // ----------------------------------------------------------------------------
 static jint android_media_AudioTrack_set_playback_rate(JNIEnv *env,  jobject thiz,
         jint sampleRateInHz) {
@@ -857,6 +898,17 @@
     return (jint)lpTrack->latency();
 }
 
+// ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_get_underrun_count(JNIEnv *env,  jobject thiz) {
+    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+
+    if (lpTrack == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for getUnderrunCount()");
+        return (jint)AUDIO_JAVA_ERROR;
+    }
+    return (jint)lpTrack->getUnderrunCount();
+}
 
 // ----------------------------------------------------------------------------
 static jint android_media_AudioTrack_get_timestamp(JNIEnv *env,  jobject thiz, jlongArray jTimestamp) {
@@ -1049,6 +1101,10 @@
     pJniStorage->mDeviceCallback.clear();
 }
 
+static jint android_media_AudioTrack_get_FCC_8(JNIEnv *env, jobject thiz) {
+    return FCC_8;
+}
+
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
@@ -1069,8 +1125,12 @@
     {"native_write_short",   "([SIIIZ)I",(void *)android_media_AudioTrack_writeArray<jshortArray>},
     {"native_write_float",   "([FIIIZ)I",(void *)android_media_AudioTrack_writeArray<jfloatArray>},
     {"native_setVolume",     "(FF)V",    (void *)android_media_AudioTrack_set_volume},
-    {"native_get_native_frame_count",
-                             "()I",      (void *)android_media_AudioTrack_get_native_frame_count},
+    {"native_get_buffer_size_frames",
+                             "()I",      (void *)android_media_AudioTrack_get_buffer_size_frames},
+    {"native_set_buffer_size_frames",
+                             "(I)I",     (void *)android_media_AudioTrack_set_buffer_size_frames},
+    {"native_get_buffer_capacity_frames",
+                             "()I",      (void *)android_media_AudioTrack_get_buffer_capacity_frames},
     {"native_set_playback_rate",
                              "(I)I",     (void *)android_media_AudioTrack_set_playback_rate},
     {"native_get_playback_rate",
@@ -1090,6 +1150,7 @@
     {"native_set_position",  "(I)I",     (void *)android_media_AudioTrack_set_position},
     {"native_get_position",  "()I",      (void *)android_media_AudioTrack_get_position},
     {"native_get_latency",   "()I",      (void *)android_media_AudioTrack_get_latency},
+    {"native_get_underrun_count", "()I",      (void *)android_media_AudioTrack_get_underrun_count},
     {"native_get_timestamp", "([J)I",    (void *)android_media_AudioTrack_get_timestamp},
     {"native_set_loop",      "(III)I",   (void *)android_media_AudioTrack_set_loop},
     {"native_reload_static", "()I",      (void *)android_media_AudioTrack_reload},
@@ -1106,6 +1167,7 @@
     {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioTrack_getRoutedDeviceId},
     {"native_enableDeviceCallback", "()V", (void *)android_media_AudioTrack_enableDeviceCallback},
     {"native_disableDeviceCallback", "()V", (void *)android_media_AudioTrack_disableDeviceCallback},
+    {"native_get_FCC_8",     "()I",      (void *)android_media_AudioTrack_get_FCC_8},
 };
 
 
@@ -1135,6 +1197,9 @@
 // ----------------------------------------------------------------------------
 int register_android_media_AudioTrack(JNIEnv *env)
 {
+    // must be first
+    int res = RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
+
     javaAudioTrackFields.nativeTrackInJavaObj = NULL;
     javaAudioTrackFields.postNativeEventInJava = NULL;
 
@@ -1173,7 +1238,7 @@
     // initialize PlaybackParams field info
     gPlaybackParamsFields.init(env);
 
-    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
+    return res;
 }
 
 
diff --git a/core/jni/android_opengl_GLES32.cpp b/core/jni/android_opengl_GLES32.cpp
new file mode 100644
index 0000000..f9a1a8e
--- /dev/null
+++ b/core/jni/android_opengl_GLES32.cpp
@@ -0,0 +1,1999 @@
+/*
+ * 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.
+ */
+
+// This source file is automatically generated
+
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#pragma GCC diagnostic ignored "-Wunused-function"
+
+#include <stdint.h>
+#include <GLES3/gl32.h>
+#include <jni.h>
+#include <JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/misc.h>
+#include <assert.h>
+
+static int initialized = 0;
+
+static jclass nioAccessClass;
+static jclass bufferClass;
+static jmethodID getBasePointerID;
+static jmethodID getBaseArrayID;
+static jmethodID getBaseArrayOffsetID;
+static jfieldID positionID;
+static jfieldID limitID;
+static jfieldID elementSizeShiftID;
+
+
+/* special calls implemented in Android's GLES wrapper used to more
+ * efficiently bound-check passed arrays */
+extern "C" {
+#ifdef GL_VERSION_ES_CM_1_1
+GL_API void GL_APIENTRY glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
+        const GLvoid *ptr, GLsizei count);
+GL_API void GL_APIENTRY glNormalPointerBounds(GLenum type, GLsizei stride,
+        const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glTexCoordPointerBounds(GLint size, GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glVertexPointerBounds(GLint size, GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glPointSizePointerOESBounds(GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glMatrixIndexPointerOESBounds(GLint size, GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count);
+#endif
+#ifdef GL_ES_VERSION_2_0
+static void glVertexAttribPointerBounds(GLuint indx, GLint size, GLenum type,
+        GLboolean normalized, GLsizei stride, const GLvoid *pointer, GLsizei count) {
+    glVertexAttribPointer(indx, size, type, normalized, stride, pointer);
+}
+#endif
+#ifdef GL_ES_VERSION_3_0
+static void glVertexAttribIPointerBounds(GLuint indx, GLint size, GLenum type,
+        GLsizei stride, const GLvoid *pointer, GLsizei count) {
+    glVertexAttribIPointer(indx, size, type, stride, pointer);
+}
+#endif
+}
+
+/* Cache method IDs each time the class is loaded. */
+
+static void
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
+{
+    jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
+    nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
+
+    jclass bufferClassLocal = _env->FindClass("java/nio/Buffer");
+    bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal);
+
+    getBasePointerID = _env->GetStaticMethodID(nioAccessClass,
+            "getBasePointer", "(Ljava/nio/Buffer;)J");
+    getBaseArrayID = _env->GetStaticMethodID(nioAccessClass,
+            "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
+    getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass,
+            "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
+
+    positionID = _env->GetFieldID(bufferClass, "position", "I");
+    limitID = _env->GetFieldID(bufferClass, "limit", "I");
+    elementSizeShiftID =
+        _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
+}
+
+static void *
+getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *offset)
+{
+    jint position;
+    jint limit;
+    jint elementSizeShift;
+    jlong pointer;
+
+    position = _env->GetIntField(buffer, positionID);
+    limit = _env->GetIntField(buffer, limitID);
+    elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
+    *remaining = (limit - position) << elementSizeShift;
+    pointer = _env->CallStaticLongMethod(nioAccessClass,
+            getBasePointerID, buffer);
+    if (pointer != 0L) {
+        *array = NULL;
+        return reinterpret_cast<void*>(pointer);
+    }
+
+    *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
+            getBaseArrayID, buffer);
+    *offset = _env->CallStaticIntMethod(nioAccessClass,
+            getBaseArrayOffsetID, buffer);
+
+    return NULL;
+}
+
+class ByteArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jbyteArray array, jboolean* is_copy) {
+        return _env->GetByteArrayElements(array, is_copy);
+    }
+};
+class BooleanArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jbooleanArray array, jboolean* is_copy) {
+        return _env->GetBooleanArrayElements(array, is_copy);
+    }
+};
+class CharArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jcharArray array, jboolean* is_copy) {
+        return _env->GetCharArrayElements(array, is_copy);
+    }
+};
+class ShortArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jshortArray array, jboolean* is_copy) {
+        return _env->GetShortArrayElements(array, is_copy);
+    }
+};
+class IntArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jintArray array, jboolean* is_copy) {
+        return _env->GetIntArrayElements(array, is_copy);
+    }
+};
+class LongArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jlongArray array, jboolean* is_copy) {
+        return _env->GetLongArrayElements(array, is_copy);
+    }
+};
+class FloatArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jfloatArray array, jboolean* is_copy) {
+        return _env->GetFloatArrayElements(array, is_copy);
+    }
+};
+class DoubleArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jdoubleArray array, jboolean* is_copy) {
+        return _env->GetDoubleArrayElements(array, is_copy);
+    }
+};
+
+template<typename JTYPEARRAY, typename ARRAYGETTER>
+static void*
+getArrayPointer(JNIEnv *_env, JTYPEARRAY array, jboolean* is_copy) {
+    return ARRAYGETTER::Get(_env, array, is_copy);
+}
+
+class ByteArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jbyteArray array, jbyte* data, jboolean commit) {
+        _env->ReleaseByteArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+class BooleanArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jbooleanArray array, jboolean* data, jboolean commit) {
+        _env->ReleaseBooleanArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+class CharArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jcharArray array, jchar* data, jboolean commit) {
+        _env->ReleaseCharArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+class ShortArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jshortArray array, jshort* data, jboolean commit) {
+        _env->ReleaseShortArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+class IntArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jintArray array, jint* data, jboolean commit) {
+        _env->ReleaseIntArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+class LongArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jlongArray array, jlong* data, jboolean commit) {
+        _env->ReleaseLongArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+class FloatArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jfloatArray array, jfloat* data, jboolean commit) {
+        _env->ReleaseFloatArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+class DoubleArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jdoubleArray array, jdouble* data, jboolean commit) {
+        _env->ReleaseDoubleArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+
+template<typename JTYPEARRAY, typename NTYPEARRAY, typename ARRAYRELEASER>
+static void
+releaseArrayPointer(JNIEnv *_env, JTYPEARRAY array, NTYPEARRAY data, jboolean commit) {
+    ARRAYRELEASER::Release(_env, array, data, commit);
+}
+
+static void
+releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit)
+{
+    _env->ReleasePrimitiveArrayCritical(array, data,
+                       commit ? 0 : JNI_ABORT);
+}
+
+static void *
+getDirectBufferPointer(JNIEnv *_env, jobject buffer) {
+    char* buf = (char*) _env->GetDirectBufferAddress(buffer);
+    if (buf) {
+        jint position = _env->GetIntField(buffer, positionID);
+        jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
+        buf += position << elementSizeShift;
+    } else {
+        jniThrowException(_env, "java/lang/IllegalArgumentException",
+                          "Must use a native order direct Buffer");
+    }
+    return (void*) buf;
+}
+
+// --------------------------------------------------------------------------
+
+/*
+ * returns the number of values glGet returns for a given pname.
+ *
+ * The code below is written such that pnames requiring only one values
+ * are the default (and are not explicitely tested for). This makes the
+ * checking code much shorter/readable/efficient.
+ *
+ * This means that unknown pnames (e.g.: extensions) will default to 1. If
+ * that unknown pname needs more than 1 value, then the validation check
+ * is incomplete and the app may crash if it passed the wrong number params.
+ */
+static int getNeededCount(GLint pname) {
+    int needed = 1;
+#ifdef GL_ES_VERSION_2_0
+    // GLES 2.x pnames
+    switch (pname) {
+        case GL_ALIASED_LINE_WIDTH_RANGE:
+        case GL_ALIASED_POINT_SIZE_RANGE:
+            needed = 2;
+            break;
+
+        case GL_BLEND_COLOR:
+        case GL_COLOR_CLEAR_VALUE:
+        case GL_COLOR_WRITEMASK:
+        case GL_SCISSOR_BOX:
+        case GL_VIEWPORT:
+            needed = 4;
+            break;
+
+        case GL_COMPRESSED_TEXTURE_FORMATS:
+            glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &needed);
+            break;
+
+        case GL_SHADER_BINARY_FORMATS:
+            glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &needed);
+            break;
+    }
+#endif
+
+#ifdef GL_VERSION_ES_CM_1_1
+    // GLES 1.x pnames
+    switch (pname) {
+        case GL_ALIASED_LINE_WIDTH_RANGE:
+        case GL_ALIASED_POINT_SIZE_RANGE:
+        case GL_DEPTH_RANGE:
+        case GL_SMOOTH_LINE_WIDTH_RANGE:
+        case GL_SMOOTH_POINT_SIZE_RANGE:
+            needed = 2;
+            break;
+
+        case GL_CURRENT_NORMAL:
+        case GL_POINT_DISTANCE_ATTENUATION:
+            needed = 3;
+            break;
+
+        case GL_COLOR_CLEAR_VALUE:
+        case GL_COLOR_WRITEMASK:
+        case GL_CURRENT_COLOR:
+        case GL_CURRENT_TEXTURE_COORDS:
+        case GL_FOG_COLOR:
+        case GL_LIGHT_MODEL_AMBIENT:
+        case GL_SCISSOR_BOX:
+        case GL_VIEWPORT:
+            needed = 4;
+            break;
+
+        case GL_MODELVIEW_MATRIX:
+        case GL_PROJECTION_MATRIX:
+        case GL_TEXTURE_MATRIX:
+            needed = 16;
+            break;
+
+        case GL_COMPRESSED_TEXTURE_FORMATS:
+            glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &needed);
+            break;
+    }
+#endif
+    return needed;
+}
+
+template <typename JTYPEARRAY, typename ARRAYGETTER, typename NTYPEARRAY,
+          typename ARRAYRELEASER, typename CTYPE, void GET(GLenum, CTYPE*)>
+static void
+get
+  (JNIEnv *_env, jobject _this, jint pname, JTYPEARRAY params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType;
+    const char * _exceptionMessage;
+    CTYPE *params_base = (CTYPE *) 0;
+    jint _remaining;
+    CTYPE *params = (CTYPE *) 0;
+    int _needed = 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(params_ref) - offset;
+    _needed = getNeededCount(pname);
+    // if we didn't find this pname, we just assume the user passed
+    // an array of the right size -- this might happen with extensions
+    // or if we forget an enum here.
+    if (_remaining < _needed) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "length - offset < needed";
+        goto exit;
+    }
+    params_base = (CTYPE *) getArrayPointer<JTYPEARRAY, ARRAYGETTER>(
+        _env, params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    GET(
+        (GLenum)pname,
+        (CTYPE *)params
+    );
+
+exit:
+    if (params_base) {
+        releaseArrayPointer<JTYPEARRAY, NTYPEARRAY, ARRAYRELEASER>(
+            _env, params_ref, params_base, !_exception);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+
+template <typename CTYPE, typename JTYPEARRAY, typename ARRAYGETTER, typename NTYPEARRAY,
+          typename ARRAYRELEASER, void GET(GLenum, CTYPE*)>
+static void
+getarray
+  (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType;
+    const char * _exceptionMessage;
+    JTYPEARRAY _array = (JTYPEARRAY) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    CTYPE *params = (CTYPE *) 0;
+    int _needed = 0;
+
+    params = (CTYPE *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+    _remaining /= sizeof(CTYPE);    // convert from bytes to item count
+    _needed = getNeededCount(pname);
+    // if we didn't find this pname, we just assume the user passed
+    // an array of the right size -- this might happen with extensions
+    // or if we forget an enum here.
+    if (_needed>0 && _remaining < _needed) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "remaining() < needed";
+        goto exit;
+    }
+    if (params == NULL) {
+        char * _paramsBase = (char *) getArrayPointer<JTYPEARRAY, ARRAYGETTER>(
+            _env, _array, (jboolean *) 0);
+        params = (CTYPE *) (_paramsBase + _bufferOffset);
+    }
+    GET(
+        (GLenum)pname,
+        (CTYPE *)params
+    );
+
+exit:
+    if (_array) {
+        releaseArrayPointer<JTYPEARRAY, NTYPEARRAY, ARRAYRELEASER>(
+            _env, _array, (NTYPEARRAY)params, _exception ? JNI_FALSE : JNI_TRUE);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+// --------------------------------------------------------------------------
+/* void glBlendBarrier ( void ) */
+static void
+android_glBlendBarrier__
+  (JNIEnv *_env, jobject _this) {
+    glBlendBarrier();
+}
+
+/* void glCopyImageSubData ( GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth ) */
+static void
+android_glCopyImageSubData__IIIIIIIIIIIIIII
+  (JNIEnv *_env, jobject _this, jint srcName, jint srcTarget, jint srcLevel, jint srcX, jint srcY, jint srcZ, jint dstName, jint dstTarget, jint dstLevel, jint dstX, jint dstY, jint dstZ, jint srcWidth, jint srcHeight, jint srcDepth) {
+    glCopyImageSubData(
+        (GLuint)srcName,
+        (GLenum)srcTarget,
+        (GLint)srcLevel,
+        (GLint)srcX,
+        (GLint)srcY,
+        (GLint)srcZ,
+        (GLuint)dstName,
+        (GLenum)dstTarget,
+        (GLint)dstLevel,
+        (GLint)dstX,
+        (GLint)dstY,
+        (GLint)dstZ,
+        (GLsizei)srcWidth,
+        (GLsizei)srcHeight,
+        (GLsizei)srcDepth
+    );
+}
+
+/* void glDebugMessageControl ( GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled ) */
+static void
+android_glDebugMessageControl__IIII_3IIZ
+  (JNIEnv *_env, jobject _this, jint source, jint type, jint severity, jint count, jintArray ids_ref, jint offset, jboolean enabled) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *ids_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *ids = (GLuint *) 0;
+
+    if (!ids_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "ids == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(ids_ref) - offset;
+    if (_remaining < count) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "length - offset < count < needed";
+        goto exit;
+    }
+    ids_base = (GLuint *)
+        _env->GetIntArrayElements(ids_ref, (jboolean *)0);
+    ids = ids_base + offset;
+
+    glDebugMessageControl(
+        (GLenum)source,
+        (GLenum)type,
+        (GLenum)severity,
+        (GLsizei)count,
+        (GLuint *)ids,
+        (GLboolean)enabled
+    );
+
+exit:
+    if (ids_base) {
+        _env->ReleaseIntArrayElements(ids_ref, (jint*)ids_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glDebugMessageControl ( GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled ) */
+static void
+android_glDebugMessageControl__IIIILjava_nio_IntBuffer_2Z
+  (JNIEnv *_env, jobject _this, jint source, jint type, jint severity, jint count, jobject ids_buf, jboolean enabled) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    jintArray _array = (jintArray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *ids = (GLuint *) 0;
+
+    ids = (GLuint *)getPointer(_env, ids_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+    if (_remaining < count) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "remaining() < count < needed";
+        goto exit;
+    }
+    if (ids == NULL) {
+        char * _idsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
+        ids = (GLuint *) (_idsBase + _bufferOffset);
+    }
+    glDebugMessageControl(
+        (GLenum)source,
+        (GLenum)type,
+        (GLenum)severity,
+        (GLsizei)count,
+        (GLuint *)ids,
+        (GLboolean)enabled
+    );
+
+exit:
+    if (_array) {
+        _env->ReleaseIntArrayElements(_array, (jint*)ids, JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glDebugMessageInsert ( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf ) */
+static void
+android_glDebugMessageInsert__IIIIILjava_lang_String_2
+  (JNIEnv *_env, jobject _this, jint source, jint type, jint id, jint severity, jint length, jstring buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    const char* _nativebuf = 0;
+
+    if (!buf) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "buf == null";
+        goto exit;
+    }
+    _nativebuf = _env->GetStringUTFChars(buf, 0);
+
+    glDebugMessageInsert(
+        (GLenum)source,
+        (GLenum)type,
+        (GLuint)id,
+        (GLenum)severity,
+        (GLsizei)length,
+        (GLchar *)_nativebuf
+    );
+
+exit:
+    if (_nativebuf) {
+        _env->ReleaseStringUTFChars(buf, _nativebuf);
+    }
+
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glDebugMessageCallback ( GLDEBUGPROC callback, const void *userParam ) */
+static void
+android_glDebugMessageCallback(JNIEnv *_env, jobject _this, jobject callback) {
+    jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented");
+}
+/* GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) */
+static jint
+android_glGetDebugMessageLog__II_3II_3II_3II_3II_3II_3BI
+  (JNIEnv *_env, jobject _this, jint count, jint bufSize, jintArray sources_ref, jint sourcesOffset, jintArray types_ref, jint typesOffset, jintArray ids_ref, jint idsOffset, jintArray severities_ref, jint severitiesOffset, jintArray lengths_ref, jint lengthsOffset, jbyteArray messageLog_ref, jint messageLogOffset) {
+    jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented");
+    return 0;
+}
+
+/* GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) */
+static uint
+android_glGetDebugMessageLog__ILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_ByteBuffer_2
+  (JNIEnv *_env, jobject _this, jint count, jobject sources_ref, jobject types_ref, jobject ids_ref, jobject severities_ref, jobject lengths_ref, jobject messageLog_ref) {
+    jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented");
+    return 0;
+}
+
+/* GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) */
+static jobjectArray
+android_glGetDebugMessageLog__I_3II_3II_3II_3II
+  (JNIEnv *_env, jobject _this, jint count, jintArray sources_ref, jint sourcesOffset, jintArray types_ref, jint typesOffset, jintArray ids_ref, jint idsOffset, jintArray severities_ref, jint severitiesOffset) {
+    jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented");
+    return 0;
+}
+
+/* GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) */
+static jobjectArray
+android_glGetDebugMessageLog__ILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint count, jobject sources_ref, jobject types_ref, jobject ids_ref, jobject severities_ref) {
+    jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented");
+    return 0;
+}
+/* void glPushDebugGroup ( GLenum source, GLuint id, GLsizei length, const GLchar *message ) */
+static void
+android_glPushDebugGroup__IIILjava_lang_String_2
+  (JNIEnv *_env, jobject _this, jint source, jint id, jint length, jstring message) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    const char* _nativemessage = 0;
+    jsize _stringlen = 0;
+
+    if (!message) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "message == null";
+        goto exit;
+    }
+    _nativemessage = _env->GetStringUTFChars(message, 0);
+    _stringlen = _env->GetStringUTFLength(message);
+    if (length > _stringlen) {
+        _exception = 1;
+        _exceptionType = "java/lang/ArrayIndexOutOfBoundsException";
+        _exceptionMessage = "length of message is shorter than length argument";
+        goto exit;
+    }
+
+    glPushDebugGroup(
+        (GLenum)source,
+        (GLuint)id,
+        (GLsizei)length,
+        (GLchar *)_nativemessage
+    );
+
+exit:
+    if (_nativemessage) {
+        _env->ReleaseStringUTFChars(message, _nativemessage);
+    }
+
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glPopDebugGroup ( void ) */
+static void
+android_glPopDebugGroup__
+  (JNIEnv *_env, jobject _this) {
+    glPopDebugGroup();
+}
+
+/* void glObjectLabel ( GLenum identifier, GLuint name, GLsizei length, const GLchar *label ) */
+static void
+android_glObjectLabel__IIILjava_lang_String_2
+  (JNIEnv *_env, jobject _this, jint identifier, jint name, jint length, jstring label) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    const char* _nativelabel = 0;
+    jsize _stringlen = 0;
+
+    if (label) {
+        _nativelabel = _env->GetStringUTFChars(label, 0);
+        _stringlen = _env->GetStringUTFLength(label);
+        if (length > _stringlen) {
+            _exception = 1;
+            _exceptionType = "java/lang/ArrayIndexOutOfBoundsException";
+            _exceptionMessage = "length of label is shorter than length argument";
+            goto exit;
+        }
+    }
+
+    glObjectLabel(
+        (GLenum)identifier,
+        (GLuint)name,
+        (GLsizei)length,
+        (GLchar *)_nativelabel
+    );
+
+exit:
+    if (_nativelabel) {
+        _env->ReleaseStringUTFChars(label, _nativelabel);
+    }
+
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetObjectLabel ( GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label ) */
+static jstring
+android_glGetObjectLabel(JNIEnv *_env, jobject _this, jint identifier, jint name) {
+    jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented");
+    return NULL;
+}
+
+/* void glObjectPtrLabel ( const void *ptr, GLsizei length, const GLchar *label ) */
+static void
+android_glObjectPtrLabel(JNIEnv *_env, jobject _this, jlong ptr, jstring label) {
+    jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented");
+}
+
+/* void glGetObjectPtrLabel ( const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label ) */
+static jstring
+android_glGetObjectPtrLabel(JNIEnv *_env, jobject _this, jlong ptr) {
+    jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented");
+    return NULL;
+}
+
+/* void glGetPointerv ( GLenum pname, void **params ) */
+static jlong
+android_glGetPointerv(JNIEnv *_env, jobject _this, jint pname) {
+    jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented");
+    return NULL;
+}
+
+/* void glEnablei ( GLenum target, GLuint index ) */
+static void
+android_glEnablei__II
+  (JNIEnv *_env, jobject _this, jint target, jint index) {
+    glEnablei(
+        (GLenum)target,
+        (GLuint)index
+    );
+}
+
+/* void glDisablei ( GLenum target, GLuint index ) */
+static void
+android_glDisablei__II
+  (JNIEnv *_env, jobject _this, jint target, jint index) {
+    glDisablei(
+        (GLenum)target,
+        (GLuint)index
+    );
+}
+
+/* void glBlendEquationi ( GLuint buf, GLenum mode ) */
+static void
+android_glBlendEquationi__II
+  (JNIEnv *_env, jobject _this, jint buf, jint mode) {
+    glBlendEquationi(
+        (GLuint)buf,
+        (GLenum)mode
+    );
+}
+
+/* void glBlendEquationSeparatei ( GLuint buf, GLenum modeRGB, GLenum modeAlpha ) */
+static void
+android_glBlendEquationSeparatei__III
+  (JNIEnv *_env, jobject _this, jint buf, jint modeRGB, jint modeAlpha) {
+    glBlendEquationSeparatei(
+        (GLuint)buf,
+        (GLenum)modeRGB,
+        (GLenum)modeAlpha
+    );
+}
+
+/* void glBlendFunci ( GLuint buf, GLenum src, GLenum dst ) */
+static void
+android_glBlendFunci__III
+  (JNIEnv *_env, jobject _this, jint buf, jint src, jint dst) {
+    glBlendFunci(
+        (GLuint)buf,
+        (GLenum)src,
+        (GLenum)dst
+    );
+}
+
+/* void glBlendFuncSeparatei ( GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha ) */
+static void
+android_glBlendFuncSeparatei__IIIII
+  (JNIEnv *_env, jobject _this, jint buf, jint srcRGB, jint dstRGB, jint srcAlpha, jint dstAlpha) {
+    glBlendFuncSeparatei(
+        (GLuint)buf,
+        (GLenum)srcRGB,
+        (GLenum)dstRGB,
+        (GLenum)srcAlpha,
+        (GLenum)dstAlpha
+    );
+}
+
+/* void glColorMaski ( GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a ) */
+static void
+android_glColorMaski__IZZZZ
+  (JNIEnv *_env, jobject _this, jint index, jboolean r, jboolean g, jboolean b, jboolean a) {
+    glColorMaski(
+        (GLuint)index,
+        (GLboolean)r,
+        (GLboolean)g,
+        (GLboolean)b,
+        (GLboolean)a
+    );
+}
+
+/* GLboolean glIsEnabledi ( GLenum target, GLuint index ) */
+static jboolean
+android_glIsEnabledi__II
+  (JNIEnv *_env, jobject _this, jint target, jint index) {
+    GLboolean _returnValue;
+    _returnValue = glIsEnabledi(
+        (GLenum)target,
+        (GLuint)index
+    );
+    return (jboolean)_returnValue;
+}
+
+/* void glDrawElementsBaseVertex ( GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex ) */
+static void
+android_glDrawElementsBaseVertex__IIILjava_nio_Buffer_2I
+  (JNIEnv *_env, jobject _this, jint mode, jint count, jint type, jobject indices_buf, jint basevertex) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    void *indices = (void *) 0;
+
+    indices = (void *)getPointer(_env, indices_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+    if (_remaining < count-basevertex) {
+        _exception = 1;
+        _exceptionType = "java/lang/ArrayIndexOutOfBoundsException";
+        _exceptionMessage = "remaining() < count-basevertex < needed";
+        goto exit;
+    }
+    if (indices == NULL) {
+        char * _indicesBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        indices = (void *) (_indicesBase + _bufferOffset);
+    }
+    glDrawElementsBaseVertex(
+        (GLenum)mode,
+        (GLsizei)count,
+        (GLenum)type,
+        (void *)indices,
+        (GLint)basevertex
+    );
+
+exit:
+    if (_array) {
+        releasePointer(_env, _array, indices, JNI_FALSE);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glDrawRangeElementsBaseVertex ( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex ) */
+static void
+android_glDrawRangeElementsBaseVertex__IIIIILjava_nio_Buffer_2I
+  (JNIEnv *_env, jobject _this, jint mode, jint start, jint end, jint count, jint type, jobject indices_buf, jint basevertex) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    void *indices = (void *) 0;
+
+    indices = (void *)getPointer(_env, indices_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+    if (_remaining < count-basevertex) {
+        _exception = 1;
+        _exceptionType = "java/lang/ArrayIndexOutOfBoundsException";
+        _exceptionMessage = "remaining() < count-basevertex < needed";
+        goto exit;
+    }
+    if (indices == NULL) {
+        char * _indicesBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        indices = (void *) (_indicesBase + _bufferOffset);
+    }
+    glDrawRangeElementsBaseVertex(
+        (GLenum)mode,
+        (GLuint)start,
+        (GLuint)end,
+        (GLsizei)count,
+        (GLenum)type,
+        (void *)indices,
+        (GLint)basevertex
+    );
+
+exit:
+    if (_array) {
+        releasePointer(_env, _array, indices, JNI_FALSE);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glDrawElementsInstancedBaseVertex ( GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount, GLint basevertex ) */
+static void
+android_glDrawElementsInstancedBaseVertex__IIILjava_nio_Buffer_2II
+  (JNIEnv *_env, jobject _this, jint mode, jint count, jint type, jobject indices_buf, jint instanceCount, jint basevertex) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    void *indices = (void *) 0;
+
+    indices = (void *)getPointer(_env, indices_buf, &_array, &_remaining, &_bufferOffset);
+    if (_remaining < count-basevertex) {
+        _exception = 1;
+        _exceptionType = "java/lang/ArrayIndexOutOfBoundsException";
+        _exceptionMessage = "remaining() < count-basevertex < needed";
+        goto exit;
+    }
+    if (indices == NULL) {
+        char * _indicesBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        indices = (void *) (_indicesBase + _bufferOffset);
+    }
+    glDrawElementsInstancedBaseVertex(
+        (GLenum)mode,
+        (GLsizei)count,
+        (GLenum)type,
+        (void *)indices,
+        (GLsizei)instanceCount,
+        (GLint) basevertex
+    );
+
+exit:
+    if (_array) {
+        releasePointer(_env, _array, indices, JNI_FALSE);
+    }
+}
+
+/* void glDrawElementsInstancedBaseVertex ( GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount, GLint basevertex ) */
+static void
+android_glDrawElementsInstancedBaseVertex__IIIIII
+  (JNIEnv *_env, jobject _this, jint mode, jint count, jint type, jint indicesOffset, jint instanceCount, jint basevertex) {
+    glDrawElementsInstancedBaseVertex(
+        (GLenum)mode,
+        (GLsizei)count,
+        (GLenum)type,
+        (void *)static_cast<uintptr_t>(indicesOffset),
+        (GLsizei)instanceCount,
+        (GLint)basevertex
+    );
+}
+/* void glFramebufferTexture ( GLenum target, GLenum attachment, GLuint texture, GLint level ) */
+static void
+android_glFramebufferTexture__IIII
+  (JNIEnv *_env, jobject _this, jint target, jint attachment, jint texture, jint level) {
+    glFramebufferTexture(
+        (GLenum)target,
+        (GLenum)attachment,
+        (GLuint)texture,
+        (GLint)level
+    );
+}
+
+/* void glPrimitiveBoundingBox ( GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW ) */
+static void
+android_glPrimitiveBoundingBox__FFFFFFFF
+  (JNIEnv *_env, jobject _this, jfloat minX, jfloat minY, jfloat minZ, jfloat minW, jfloat maxX, jfloat maxY, jfloat maxZ, jfloat maxW) {
+    glPrimitiveBoundingBox(
+        (GLfloat)minX,
+        (GLfloat)minY,
+        (GLfloat)minZ,
+        (GLfloat)minW,
+        (GLfloat)maxX,
+        (GLfloat)maxY,
+        (GLfloat)maxZ,
+        (GLfloat)maxW
+    );
+}
+
+/* GLenum glGetGraphicsResetStatus ( void ) */
+static jint
+android_glGetGraphicsResetStatus__
+  (JNIEnv *_env, jobject _this) {
+    GLenum _returnValue;
+    _returnValue = glGetGraphicsResetStatus();
+    return (jint)_returnValue;
+}
+
+/* void glReadnPixels ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data ) */
+static void
+android_glReadnPixels__IIIIIIILjava_nio_Buffer_2
+  (JNIEnv *_env, jobject _this, jint x, jint y, jint width, jint height, jint format, jint type, jint bufSize, jobject data_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    jarray _array = (jarray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    void *data = (void *) 0;
+
+    data = (void *)getPointer(_env, data_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+    if (_remaining < bufSize) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "remaining() < bufSize < needed";
+        goto exit;
+    }
+    if (data == NULL) {
+        char * _dataBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        data = (void *) (_dataBase + _bufferOffset);
+    }
+    glReadnPixels(
+        (GLint)x,
+        (GLint)y,
+        (GLsizei)width,
+        (GLsizei)height,
+        (GLenum)format,
+        (GLenum)type,
+        (GLsizei)bufSize,
+        (void *)data
+    );
+
+exit:
+    if (_array) {
+        releasePointer(_env, _array, data, _exception ? JNI_FALSE : JNI_TRUE);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetnUniformfv ( GLuint program, GLint location, GLsizei bufSize, GLfloat *params ) */
+static void
+android_glGetnUniformfv__III_3FI
+  (JNIEnv *_env, jobject _this, jint program, jint location, jint bufSize, jfloatArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLfloat *params_base = (GLfloat *) 0;
+    jint _remaining;
+    GLfloat *params = (GLfloat *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(params_ref) - offset;
+    if (_remaining < bufSize) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "length - offset < bufSize < needed";
+        goto exit;
+    }
+    params_base = (GLfloat *)
+        _env->GetFloatArrayElements(params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glGetnUniformfv(
+        (GLuint)program,
+        (GLint)location,
+        (GLsizei)bufSize,
+        (GLfloat *)params
+    );
+
+exit:
+    if (params_base) {
+        _env->ReleaseFloatArrayElements(params_ref, (jfloat*)params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetnUniformfv ( GLuint program, GLint location, GLsizei bufSize, GLfloat *params ) */
+static void
+android_glGetnUniformfv__IIILjava_nio_FloatBuffer_2
+  (JNIEnv *_env, jobject _this, jint program, jint location, jint bufSize, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    jfloatArray _array = (jfloatArray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLfloat *params = (GLfloat *) 0;
+
+    params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+    if (_remaining < bufSize) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "remaining() < bufSize < needed";
+        goto exit;
+    }
+    if (params == NULL) {
+        char * _paramsBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
+        params = (GLfloat *) (_paramsBase + _bufferOffset);
+    }
+    glGetnUniformfv(
+        (GLuint)program,
+        (GLint)location,
+        (GLsizei)bufSize,
+        (GLfloat *)params
+    );
+
+exit:
+    if (_array) {
+        _env->ReleaseFloatArrayElements(_array, (jfloat*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetnUniformiv ( GLuint program, GLint location, GLsizei bufSize, GLint *params ) */
+static void
+android_glGetnUniformiv__III_3II
+  (JNIEnv *_env, jobject _this, jint program, jint location, jint bufSize, jintArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint *params_base = (GLint *) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(params_ref) - offset;
+    if (_remaining < bufSize) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "length - offset < bufSize < needed";
+        goto exit;
+    }
+    params_base = (GLint *)
+        _env->GetIntArrayElements(params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glGetnUniformiv(
+        (GLuint)program,
+        (GLint)location,
+        (GLsizei)bufSize,
+        (GLint *)params
+    );
+
+exit:
+    if (params_base) {
+        _env->ReleaseIntArrayElements(params_ref, (jint*)params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetnUniformiv ( GLuint program, GLint location, GLsizei bufSize, GLint *params ) */
+static void
+android_glGetnUniformiv__IIILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint program, jint location, jint bufSize, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    jintArray _array = (jintArray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+
+    params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+    if (_remaining < bufSize) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "remaining() < bufSize < needed";
+        goto exit;
+    }
+    if (params == NULL) {
+        char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
+        params = (GLint *) (_paramsBase + _bufferOffset);
+    }
+    glGetnUniformiv(
+        (GLuint)program,
+        (GLint)location,
+        (GLsizei)bufSize,
+        (GLint *)params
+    );
+
+exit:
+    if (_array) {
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetnUniformuiv ( GLuint program, GLint location, GLsizei bufSize, GLuint *params ) */
+static void
+android_glGetnUniformuiv__III_3II
+  (JNIEnv *_env, jobject _this, jint program, jint location, jint bufSize, jintArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *params_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *params = (GLuint *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(params_ref) - offset;
+    if (_remaining < bufSize) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "length - offset < bufSize < needed";
+        goto exit;
+    }
+    params_base = (GLuint *)
+        _env->GetIntArrayElements(params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glGetnUniformuiv(
+        (GLuint)program,
+        (GLint)location,
+        (GLsizei)bufSize,
+        (GLuint *)params
+    );
+
+exit:
+    if (params_base) {
+        _env->ReleaseIntArrayElements(params_ref, (jint*)params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetnUniformuiv ( GLuint program, GLint location, GLsizei bufSize, GLuint *params ) */
+static void
+android_glGetnUniformuiv__IIILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint program, jint location, jint bufSize, jobject params_buf) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    jintArray _array = (jintArray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *params = (GLuint *) 0;
+
+    params = (GLuint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+    if (_remaining < bufSize) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "remaining() < bufSize < needed";
+        goto exit;
+    }
+    if (params == NULL) {
+        char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
+        params = (GLuint *) (_paramsBase + _bufferOffset);
+    }
+    glGetnUniformuiv(
+        (GLuint)program,
+        (GLint)location,
+        (GLsizei)bufSize,
+        (GLuint *)params
+    );
+
+exit:
+    if (_array) {
+        _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glMinSampleShading ( GLfloat value ) */
+static void
+android_glMinSampleShading__F
+  (JNIEnv *_env, jobject _this, jfloat value) {
+    glMinSampleShading(
+        (GLfloat)value
+    );
+}
+
+/* void glPatchParameteri ( GLenum pname, GLint value ) */
+static void
+android_glPatchParameteri__II
+  (JNIEnv *_env, jobject _this, jint pname, jint value) {
+    glPatchParameteri(
+        (GLenum)pname,
+        (GLint)value
+    );
+}
+
+/* void glTexParameterIiv ( GLenum target, GLenum pname, const GLint *params ) */
+static void
+android_glTexParameterIiv__II_3II
+  (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint *params_base = (GLint *) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(params_ref) - offset;
+    params_base = (GLint *)
+        _env->GetIntArrayElements(params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glTexParameterIiv(
+        (GLenum)target,
+        (GLenum)pname,
+        (GLint *)params
+    );
+
+exit:
+    if (params_base) {
+        _env->ReleaseIntArrayElements(params_ref, (jint*)params_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glTexParameterIiv ( GLenum target, GLenum pname, const GLint *params ) */
+static void
+android_glTexParameterIiv__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+    jintArray _array = (jintArray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+
+    params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+    if (params == NULL) {
+        char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
+        params = (GLint *) (_paramsBase + _bufferOffset);
+    }
+    glTexParameterIiv(
+        (GLenum)target,
+        (GLenum)pname,
+        (GLint *)params
+    );
+    if (_array) {
+        _env->ReleaseIntArrayElements(_array, (jint*)params, JNI_ABORT);
+    }
+}
+
+/* void glTexParameterIuiv ( GLenum target, GLenum pname, const GLuint *params ) */
+static void
+android_glTexParameterIuiv__II_3II
+  (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *params_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *params = (GLuint *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(params_ref) - offset;
+    params_base = (GLuint *)
+        _env->GetIntArrayElements(params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glTexParameterIuiv(
+        (GLenum)target,
+        (GLenum)pname,
+        (GLuint *)params
+    );
+
+exit:
+    if (params_base) {
+        _env->ReleaseIntArrayElements(params_ref, (jint*)params_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glTexParameterIuiv ( GLenum target, GLenum pname, const GLuint *params ) */
+static void
+android_glTexParameterIuiv__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+    jintArray _array = (jintArray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *params = (GLuint *) 0;
+
+    params = (GLuint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+    if (params == NULL) {
+        char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
+        params = (GLuint *) (_paramsBase + _bufferOffset);
+    }
+    glTexParameterIuiv(
+        (GLenum)target,
+        (GLenum)pname,
+        (GLuint *)params
+    );
+    if (_array) {
+        _env->ReleaseIntArrayElements(_array, (jint*)params, JNI_ABORT);
+    }
+}
+
+/* void glGetTexParameterIiv ( GLenum target, GLenum pname, GLint *params ) */
+static void
+android_glGetTexParameterIiv__II_3II
+  (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint *params_base = (GLint *) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(params_ref) - offset;
+    params_base = (GLint *)
+        _env->GetIntArrayElements(params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glGetTexParameterIiv(
+        (GLenum)target,
+        (GLenum)pname,
+        (GLint *)params
+    );
+
+exit:
+    if (params_base) {
+        _env->ReleaseIntArrayElements(params_ref, (jint*)params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetTexParameterIiv ( GLenum target, GLenum pname, GLint *params ) */
+static void
+android_glGetTexParameterIiv__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+    jintArray _array = (jintArray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+
+    params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+    if (params == NULL) {
+        char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
+        params = (GLint *) (_paramsBase + _bufferOffset);
+    }
+    glGetTexParameterIiv(
+        (GLenum)target,
+        (GLenum)pname,
+        (GLint *)params
+    );
+    if (_array) {
+        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+    }
+}
+
+/* void glGetTexParameterIuiv ( GLenum target, GLenum pname, GLuint *params ) */
+static void
+android_glGetTexParameterIuiv__II_3II
+  (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *params_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *params = (GLuint *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(params_ref) - offset;
+    params_base = (GLuint *)
+        _env->GetIntArrayElements(params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glGetTexParameterIuiv(
+        (GLenum)target,
+        (GLenum)pname,
+        (GLuint *)params
+    );
+
+exit:
+    if (params_base) {
+        _env->ReleaseIntArrayElements(params_ref, (jint*)params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetTexParameterIuiv ( GLenum target, GLenum pname, GLuint *params ) */
+static void
+android_glGetTexParameterIuiv__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+    jintArray _array = (jintArray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *params = (GLuint *) 0;
+
+    params = (GLuint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+    if (params == NULL) {
+        char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
+        params = (GLuint *) (_paramsBase + _bufferOffset);
+    }
+    glGetTexParameterIuiv(
+        (GLenum)target,
+        (GLenum)pname,
+        (GLuint *)params
+    );
+    if (_array) {
+        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+    }
+}
+
+/* void glSamplerParameterIiv ( GLuint sampler, GLenum pname, const GLint *param ) */
+static void
+android_glSamplerParameterIiv__II_3II
+  (JNIEnv *_env, jobject _this, jint sampler, jint pname, jintArray param_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint *param_base = (GLint *) 0;
+    jint _remaining;
+    GLint *param = (GLint *) 0;
+
+    if (!param_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "param == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(param_ref) - offset;
+    param_base = (GLint *)
+        _env->GetIntArrayElements(param_ref, (jboolean *)0);
+    param = param_base + offset;
+
+    glSamplerParameterIiv(
+        (GLuint)sampler,
+        (GLenum)pname,
+        (GLint *)param
+    );
+
+exit:
+    if (param_base) {
+        _env->ReleaseIntArrayElements(param_ref, (jint*)param_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glSamplerParameterIiv ( GLuint sampler, GLenum pname, const GLint *param ) */
+static void
+android_glSamplerParameterIiv__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject param_buf) {
+    jintArray _array = (jintArray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLint *param = (GLint *) 0;
+
+    param = (GLint *)getPointer(_env, param_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+    if (param == NULL) {
+        char * _paramBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
+        param = (GLint *) (_paramBase + _bufferOffset);
+    }
+    glSamplerParameterIiv(
+        (GLuint)sampler,
+        (GLenum)pname,
+        (GLint *)param
+    );
+    if (_array) {
+        _env->ReleaseIntArrayElements(_array, (jint*)param, JNI_ABORT);
+    }
+}
+
+/* void glSamplerParameterIuiv ( GLuint sampler, GLenum pname, const GLuint *param ) */
+static void
+android_glSamplerParameterIuiv__II_3II
+  (JNIEnv *_env, jobject _this, jint sampler, jint pname, jintArray param_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *param_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *param = (GLuint *) 0;
+
+    if (!param_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "param == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(param_ref) - offset;
+    param_base = (GLuint *)
+        _env->GetIntArrayElements(param_ref, (jboolean *)0);
+    param = param_base + offset;
+
+    glSamplerParameterIuiv(
+        (GLuint)sampler,
+        (GLenum)pname,
+        (GLuint *)param
+    );
+
+exit:
+    if (param_base) {
+        _env->ReleaseIntArrayElements(param_ref, (jint*)param_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glSamplerParameterIuiv ( GLuint sampler, GLenum pname, const GLuint *param ) */
+static void
+android_glSamplerParameterIuiv__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject param_buf) {
+    jintArray _array = (jintArray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *param = (GLuint *) 0;
+
+    param = (GLuint *)getPointer(_env, param_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+    if (param == NULL) {
+        char * _paramBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
+        param = (GLuint *) (_paramBase + _bufferOffset);
+    }
+    glSamplerParameterIuiv(
+        (GLuint)sampler,
+        (GLenum)pname,
+        (GLuint *)param
+    );
+    if (_array) {
+        _env->ReleaseIntArrayElements(_array, (jint*)param, JNI_ABORT);
+    }
+}
+
+/* void glGetSamplerParameterIiv ( GLuint sampler, GLenum pname, GLint *params ) */
+static void
+android_glGetSamplerParameterIiv__II_3II
+  (JNIEnv *_env, jobject _this, jint sampler, jint pname, jintArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLint *params_base = (GLint *) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(params_ref) - offset;
+    params_base = (GLint *)
+        _env->GetIntArrayElements(params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glGetSamplerParameterIiv(
+        (GLuint)sampler,
+        (GLenum)pname,
+        (GLint *)params
+    );
+
+exit:
+    if (params_base) {
+        _env->ReleaseIntArrayElements(params_ref, (jint*)params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetSamplerParameterIiv ( GLuint sampler, GLenum pname, GLint *params ) */
+static void
+android_glGetSamplerParameterIiv__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject params_buf) {
+    jintArray _array = (jintArray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLint *params = (GLint *) 0;
+
+    params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+    if (params == NULL) {
+        char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
+        params = (GLint *) (_paramsBase + _bufferOffset);
+    }
+    glGetSamplerParameterIiv(
+        (GLuint)sampler,
+        (GLenum)pname,
+        (GLint *)params
+    );
+    if (_array) {
+        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+    }
+}
+
+/* void glGetSamplerParameterIuiv ( GLuint sampler, GLenum pname, GLuint *params ) */
+static void
+android_glGetSamplerParameterIuiv__II_3II
+  (JNIEnv *_env, jobject _this, jint sampler, jint pname, jintArray params_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLuint *params_base = (GLuint *) 0;
+    jint _remaining;
+    GLuint *params = (GLuint *) 0;
+
+    if (!params_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "params == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(params_ref) - offset;
+    params_base = (GLuint *)
+        _env->GetIntArrayElements(params_ref, (jboolean *)0);
+    params = params_base + offset;
+
+    glGetSamplerParameterIuiv(
+        (GLuint)sampler,
+        (GLenum)pname,
+        (GLuint *)params
+    );
+
+exit:
+    if (params_base) {
+        _env->ReleaseIntArrayElements(params_ref, (jint*)params_base,
+            _exception ? JNI_ABORT: 0);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+}
+
+/* void glGetSamplerParameterIuiv ( GLuint sampler, GLenum pname, GLuint *params ) */
+static void
+android_glGetSamplerParameterIuiv__IILjava_nio_IntBuffer_2
+  (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject params_buf) {
+    jintArray _array = (jintArray) 0;
+    jint _bufferOffset = (jint) 0;
+    jint _remaining;
+    GLuint *params = (GLuint *) 0;
+
+    params = (GLuint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+    if (params == NULL) {
+        char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
+        params = (GLuint *) (_paramsBase + _bufferOffset);
+    }
+    glGetSamplerParameterIuiv(
+        (GLuint)sampler,
+        (GLenum)pname,
+        (GLuint *)params
+    );
+    if (_array) {
+        _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+    }
+}
+
+/* void glTexBuffer ( GLenum target, GLenum internalformat, GLuint buffer ) */
+static void
+android_glTexBuffer__III
+  (JNIEnv *_env, jobject _this, jint target, jint internalformat, jint buffer) {
+    glTexBuffer(
+        (GLenum)target,
+        (GLenum)internalformat,
+        (GLuint)buffer
+    );
+}
+
+/* void glTexBufferRange ( GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size ) */
+static void
+android_glTexBufferRange__IIIII
+  (JNIEnv *_env, jobject _this, jint target, jint internalformat, jint buffer, jint offset, jint size) {
+    glTexBufferRange(
+        (GLenum)target,
+        (GLenum)internalformat,
+        (GLuint)buffer,
+        (GLintptr)offset,
+        (GLsizeiptr)size
+    );
+}
+
+/* void glTexStorage3DMultisample ( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations ) */
+static void
+android_glTexStorage3DMultisample__IIIIIIZ
+  (JNIEnv *_env, jobject _this, jint target, jint samples, jint internalformat, jint width, jint height, jint depth, jboolean fixedsamplelocations) {
+    glTexStorage3DMultisample(
+        (GLenum)target,
+        (GLsizei)samples,
+        (GLenum)internalformat,
+        (GLsizei)width,
+        (GLsizei)height,
+        (GLsizei)depth,
+        (GLboolean)fixedsamplelocations
+    );
+}
+
+static const char *classPathName = "android/opengl/GLES32";
+
+static const JNINativeMethod methods[] = {
+{"_nativeClassInit", "()V", (void*)nativeClassInit },
+{"glBlendBarrier", "()V", (void *) android_glBlendBarrier__ },
+{"glCopyImageSubData", "(IIIIIIIIIIIIIII)V", (void *) android_glCopyImageSubData__IIIIIIIIIIIIIII },
+{"glDebugMessageControl", "(IIII[IIZ)V", (void *) android_glDebugMessageControl__IIII_3IIZ },
+{"glDebugMessageControl", "(IIIILjava/nio/IntBuffer;Z)V", (void *) android_glDebugMessageControl__IIIILjava_nio_IntBuffer_2Z },
+{"glDebugMessageInsert", "(IIIIILjava/lang/String;)V", (void *) android_glDebugMessageInsert__IIIIILjava_lang_String_2 },
+{"glDebugMessageCallback", "(Landroid/opengl/GLES32$DebugProc;)V", (void *) android_glDebugMessageCallback },
+{"glGetDebugMessageLog", "(II[II[II[II[II[II[BI)I", (void *) android_glGetDebugMessageLog__II_3II_3II_3II_3II_3II_3BI },
+{"glGetDebugMessageLog", "(ILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/ByteBuffer;)I", (void *) android_glGetDebugMessageLog__ILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_ByteBuffer_2 },
+{"glGetDebugMessageLog", "(I[II[II[II[II)[Ljava/lang/String;", (void *) android_glGetDebugMessageLog__I_3II_3II_3II_3II },
+{"glGetDebugMessageLog", "(ILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;)[Ljava/lang/String;", (void *) android_glGetDebugMessageLog__ILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2 },
+{"glPushDebugGroup", "(IIILjava/lang/String;)V", (void *) android_glPushDebugGroup__IIILjava_lang_String_2 },
+{"glPopDebugGroup", "()V", (void *) android_glPopDebugGroup__ },
+{"glObjectLabel", "(IIILjava/lang/String;)V", (void *) android_glObjectLabel__IIILjava_lang_String_2 },
+{"glGetObjectLabel", "(II)Ljava/lang/String;", (void *) android_glGetObjectLabel },
+{"glObjectPtrLabel", "(JLjava/lang/String;)V", (void *) android_glObjectPtrLabel },
+{"glGetObjectPtrLabel", "(J)Ljava/lang/String;", (void *) android_glGetObjectPtrLabel },
+{"glGetPointerv", "(I)J", (void *) android_glGetPointerv },
+{"glEnablei", "(II)V", (void *) android_glEnablei__II },
+{"glDisablei", "(II)V", (void *) android_glDisablei__II },
+{"glBlendEquationi", "(II)V", (void *) android_glBlendEquationi__II },
+{"glBlendEquationSeparatei", "(III)V", (void *) android_glBlendEquationSeparatei__III },
+{"glBlendFunci", "(III)V", (void *) android_glBlendFunci__III },
+{"glBlendFuncSeparatei", "(IIIII)V", (void *) android_glBlendFuncSeparatei__IIIII },
+{"glColorMaski", "(IZZZZ)V", (void *) android_glColorMaski__IZZZZ },
+{"glIsEnabledi", "(II)Z", (void *) android_glIsEnabledi__II },
+{"glDrawElementsBaseVertex", "(IIILjava/nio/Buffer;I)V", (void *) android_glDrawElementsBaseVertex__IIILjava_nio_Buffer_2I },
+{"glDrawRangeElementsBaseVertex", "(IIIIILjava/nio/Buffer;I)V", (void *) android_glDrawRangeElementsBaseVertex__IIIIILjava_nio_Buffer_2I },
+{"glDrawElementsInstancedBaseVertex", "(IIILjava/nio/Buffer;II)V", (void *) android_glDrawElementsInstancedBaseVertex__IIILjava_nio_Buffer_2II },
+{"glDrawElementsInstancedBaseVertex", "(IIIIII)V", (void *) android_glDrawElementsInstancedBaseVertex__IIIIII },
+{"glFramebufferTexture", "(IIII)V", (void *) android_glFramebufferTexture__IIII },
+{"glPrimitiveBoundingBox", "(FFFFFFFF)V", (void *) android_glPrimitiveBoundingBox__FFFFFFFF },
+{"glGetGraphicsResetStatus", "()I", (void *) android_glGetGraphicsResetStatus__ },
+{"glReadnPixels", "(IIIIIIILjava/nio/Buffer;)V", (void *) android_glReadnPixels__IIIIIIILjava_nio_Buffer_2 },
+{"glGetnUniformfv", "(III[FI)V", (void *) android_glGetnUniformfv__III_3FI },
+{"glGetnUniformfv", "(IIILjava/nio/FloatBuffer;)V", (void *) android_glGetnUniformfv__IIILjava_nio_FloatBuffer_2 },
+{"glGetnUniformiv", "(III[II)V", (void *) android_glGetnUniformiv__III_3II },
+{"glGetnUniformiv", "(IIILjava/nio/IntBuffer;)V", (void *) android_glGetnUniformiv__IIILjava_nio_IntBuffer_2 },
+{"glGetnUniformuiv", "(III[II)V", (void *) android_glGetnUniformuiv__III_3II },
+{"glGetnUniformuiv", "(IIILjava/nio/IntBuffer;)V", (void *) android_glGetnUniformuiv__IIILjava_nio_IntBuffer_2 },
+{"glMinSampleShading", "(F)V", (void *) android_glMinSampleShading__F },
+{"glPatchParameteri", "(II)V", (void *) android_glPatchParameteri__II },
+{"glTexParameterIiv", "(II[II)V", (void *) android_glTexParameterIiv__II_3II },
+{"glTexParameterIiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glTexParameterIiv__IILjava_nio_IntBuffer_2 },
+{"glTexParameterIuiv", "(II[II)V", (void *) android_glTexParameterIuiv__II_3II },
+{"glTexParameterIuiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glTexParameterIuiv__IILjava_nio_IntBuffer_2 },
+{"glGetTexParameterIiv", "(II[II)V", (void *) android_glGetTexParameterIiv__II_3II },
+{"glGetTexParameterIiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetTexParameterIiv__IILjava_nio_IntBuffer_2 },
+{"glGetTexParameterIuiv", "(II[II)V", (void *) android_glGetTexParameterIuiv__II_3II },
+{"glGetTexParameterIuiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetTexParameterIuiv__IILjava_nio_IntBuffer_2 },
+{"glSamplerParameterIiv", "(II[II)V", (void *) android_glSamplerParameterIiv__II_3II },
+{"glSamplerParameterIiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glSamplerParameterIiv__IILjava_nio_IntBuffer_2 },
+{"glSamplerParameterIuiv", "(II[II)V", (void *) android_glSamplerParameterIuiv__II_3II },
+{"glSamplerParameterIuiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glSamplerParameterIuiv__IILjava_nio_IntBuffer_2 },
+{"glGetSamplerParameterIiv", "(II[II)V", (void *) android_glGetSamplerParameterIiv__II_3II },
+{"glGetSamplerParameterIiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetSamplerParameterIiv__IILjava_nio_IntBuffer_2 },
+{"glGetSamplerParameterIuiv", "(II[II)V", (void *) android_glGetSamplerParameterIuiv__II_3II },
+{"glGetSamplerParameterIuiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetSamplerParameterIuiv__IILjava_nio_IntBuffer_2 },
+{"glTexBuffer", "(III)V", (void *) android_glTexBuffer__III },
+{"glTexBufferRange", "(IIIII)V", (void *) android_glTexBufferRange__IIIII },
+{"glTexStorage3DMultisample", "(IIIIIIZ)V", (void *) android_glTexStorage3DMultisample__IIIIIIZ },
+};
+
+int register_android_opengl_jni_GLES32(JNIEnv *_env)
+{
+    int err;
+    err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));
+    return err;
+}
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 2488111..03a1e71 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -84,6 +84,7 @@
     jfieldID privateClean_field;
     jfieldID sharedClean_field;
     jfieldID swappedOut_field;
+    jfieldID swappedOutPss_field;
 };
 
 struct stat_field_names {
@@ -94,20 +95,22 @@
     const char* privateClean_name;
     const char* sharedClean_name;
     const char* swappedOut_name;
+    const char* swappedOutPss_name;
 };
 
 static stat_fields stat_fields[_NUM_CORE_HEAP];
 
 static stat_field_names stat_field_names[_NUM_CORE_HEAP] = {
     { "otherPss", "otherSwappablePss", "otherPrivateDirty", "otherSharedDirty",
-        "otherPrivateClean", "otherSharedClean", "otherSwappedOut" },
+        "otherPrivateClean", "otherSharedClean", "otherSwappedOut", "otherSwappedOutPss" },
     { "dalvikPss", "dalvikSwappablePss", "dalvikPrivateDirty", "dalvikSharedDirty",
-        "dalvikPrivateClean", "dalvikSharedClean", "dalvikSwappedOut" },
+        "dalvikPrivateClean", "dalvikSharedClean", "dalvikSwappedOut", "dalvikSwappedOutPss" },
     { "nativePss", "nativeSwappablePss", "nativePrivateDirty", "nativeSharedDirty",
-        "nativePrivateClean", "nativeSharedClean", "nativeSwappedOut" }
+        "nativePrivateClean", "nativeSharedClean", "nativeSwappedOut", "nativeSwappedOutPss" }
 };
 
 jfieldID otherStats_field;
+jfieldID hasSwappedOutPss_field;
 
 static bool memtrackLoaded;
 
@@ -119,6 +122,7 @@
     int privateClean;
     int sharedClean;
     int swappedOut;
+    int swappedOutPss;
 };
 
 #define BINDER_STATS "/proc/binder/stats"
@@ -206,7 +210,7 @@
     return err;
 }
 
-static void read_mapinfo(FILE *fp, stats_t* stats)
+static void read_mapinfo(FILE *fp, stats_t* stats, bool* foundSwapPss)
 {
     char line[1024];
     int len, nameLen;
@@ -216,7 +220,7 @@
     float sharing_proportion = 0.0;
     unsigned shared_clean = 0, shared_dirty = 0;
     unsigned private_clean = 0, private_dirty = 0;
-    unsigned swapped_out = 0;
+    unsigned swapped_out = 0, swapped_out_pss = 0;
     bool is_swappable = false;
     unsigned temp;
 
@@ -230,6 +234,8 @@
     int subHeap = HEAP_UNKNOWN;
     int prevHeap = HEAP_UNKNOWN;
 
+    *foundSwapPss = false;
+
     if(fgets(line, sizeof(line), fp) == 0) return;
 
     while (!done) {
@@ -340,6 +346,7 @@
         private_clean = 0;
         private_dirty = 0;
         swapped_out = 0;
+        swapped_out_pss = 0;
 
         while (true) {
             if (fgets(line, 1024, fp) == 0) {
@@ -365,6 +372,9 @@
                 /* referenced = temp; */
             } else if (line[0] == 'S' && sscanf(line, "Swap: %d kB", &temp) == 1) {
                 swapped_out = temp;
+            } else if (line[0] == 'S' && sscanf(line, "SwapPss: %d kB", &temp) == 1) {
+                *foundSwapPss = true;
+                swapped_out_pss = temp;
             } else if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %*s %*x %*x:%*x %*d", &start, &end) == 2) {
                 // looks like a new mapping
                 // example: "10000000-10001000 ---p 10000000 00:00 0"
@@ -390,6 +400,7 @@
             stats[whichHeap].privateClean += private_clean;
             stats[whichHeap].sharedClean += shared_clean;
             stats[whichHeap].swappedOut += swapped_out;
+            stats[whichHeap].swappedOutPss += swapped_out_pss;
             if (whichHeap == HEAP_DALVIK || whichHeap == HEAP_DALVIK_OTHER) {
                 stats[subHeap].pss += pss;
                 stats[subHeap].swappablePss += swappable_pss;
@@ -398,12 +409,13 @@
                 stats[subHeap].privateClean += private_clean;
                 stats[subHeap].sharedClean += shared_clean;
                 stats[subHeap].swappedOut += swapped_out;
+                stats[subHeap].swappedOutPss += swapped_out_pss;
             }
         }
     }
 }
 
-static void load_maps(int pid, stats_t* stats)
+static void load_maps(int pid, stats_t* stats, bool* foundSwapPss)
 {
     char tmp[128];
     FILE *fp;
@@ -412,17 +424,18 @@
     fp = fopen(tmp, "r");
     if (fp == 0) return;
 
-    read_mapinfo(fp, stats);
+    read_mapinfo(fp, stats, foundSwapPss);
     fclose(fp);
 }
 
 static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
         jint pid, jobject object)
 {
+    bool foundSwapPss;
     stats_t stats[_NUM_HEAP];
     memset(&stats, 0, sizeof(stats));
 
-    load_maps(pid, stats);
+    load_maps(pid, stats, &foundSwapPss);
 
     struct graphics_memory_pss graphics_mem;
     if (read_memtrack_memory(pid, &graphics_mem) == 0) {
@@ -442,6 +455,7 @@
         stats[HEAP_UNKNOWN].privateClean += stats[i].privateClean;
         stats[HEAP_UNKNOWN].sharedClean += stats[i].sharedClean;
         stats[HEAP_UNKNOWN].swappedOut += stats[i].swappedOut;
+        stats[HEAP_UNKNOWN].swappedOutPss += stats[i].swappedOutPss;
     }
 
     for (int i=0; i<_NUM_CORE_HEAP; i++) {
@@ -452,9 +466,11 @@
         env->SetIntField(object, stat_fields[i].privateClean_field, stats[i].privateClean);
         env->SetIntField(object, stat_fields[i].sharedClean_field, stats[i].sharedClean);
         env->SetIntField(object, stat_fields[i].swappedOut_field, stats[i].swappedOut);
+        env->SetIntField(object, stat_fields[i].swappedOutPss_field, stats[i].swappedOutPss);
     }
 
 
+    env->SetBooleanField(object, hasSwappedOutPss_field, foundSwapPss);
     jintArray otherIntArray = (jintArray)env->GetObjectField(object, otherStats_field);
 
     jint* otherArray = (jint*)env->GetPrimitiveArrayCritical(otherIntArray, 0);
@@ -471,6 +487,7 @@
         otherArray[j++] = stats[i].privateClean;
         otherArray[j++] = stats[i].sharedClean;
         otherArray[j++] = stats[i].swappedOut;
+        otherArray[j++] = stats[i].swappedOutPss;
     }
 
     env->ReleasePrimitiveArrayCritical(otherIntArray, otherArray, 0);
@@ -481,11 +498,12 @@
     android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object);
 }
 
-static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid, jlongArray outUss,
-        jlongArray outMemtrack)
+static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid,
+        jlongArray outUssSwapPss, jlongArray outMemtrack)
 {
     char line[1024];
     jlong pss = 0;
+    jlong swapPss = 0;
     jlong uss = 0;
     jlong memtrack = 0;
 
@@ -521,19 +539,31 @@
                     }
                     uss += atoi(c);
                 }
+            } else if (line[0] == 'S' && strncmp(line, "SwapPss:", 8) == 0) {
+                char* c = line + 8;
+                jlong lSwapPss;
+                while (*c != 0 && (*c < '0' || *c > '9')) {
+                    c++;
+                }
+                lSwapPss = atoi(c);
+                swapPss += lSwapPss;
+                pss += lSwapPss; // Also in swap, those pages would be accounted as Pss without SWAP
             }
         }
 
         fclose(fp);
     }
 
-    if (outUss != NULL) {
-        if (env->GetArrayLength(outUss) >= 1) {
-            jlong* outUssArray = env->GetLongArrayElements(outUss, 0);
-            if (outUssArray != NULL) {
-                outUssArray[0] = uss;
+    if (outUssSwapPss != NULL) {
+        if (env->GetArrayLength(outUssSwapPss) >= 1) {
+            jlong* outUssSwapPssArray = env->GetLongArrayElements(outUssSwapPss, 0);
+            if (outUssSwapPssArray != NULL) {
+                outUssSwapPssArray[0] = uss;
+                if (env->GetArrayLength(outUssSwapPss) >= 2) {
+                    outUssSwapPssArray[1] = swapPss;
+                }
             }
-            env->ReleaseLongArrayElements(outUss, outUssArray, 0);
+            env->ReleaseLongArrayElements(outUssSwapPss, outUssSwapPssArray, 0);
         }
     }
 
@@ -1056,6 +1086,7 @@
     }
 
     otherStats_field = env->GetFieldID(clazz, "otherStats", "[I");
+    hasSwappedOutPss_field = env->GetFieldID(clazz, "hasSwappedOutPss", "Z");
 
     for (int i=0; i<_NUM_CORE_HEAP; i++) {
         stat_fields[i].pss_field =
@@ -1072,6 +1103,8 @@
                 env->GetFieldID(clazz, stat_field_names[i].sharedClean_name, "I");
         stat_fields[i].swappedOut_field =
                 env->GetFieldID(clazz, stat_field_names[i].swappedOut_name, "I");
+        stat_fields[i].swappedOutPss_field =
+                env->GetFieldID(clazz, stat_field_names[i].swappedOutPss_name, "I");
     }
 
     return jniRegisterNativeMethods(env, "android/os/Debug", gMethods, NELEM(gMethods));
diff --git a/core/jni/android_os_HardwarePropertiesManager.cpp b/core/jni/android_os_HardwarePropertiesManager.cpp
new file mode 100644
index 0000000..dc1ba48
--- /dev/null
+++ b/core/jni/android_os_HardwarePropertiesManager.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "HardwarePropertiesManager-JNI"
+
+#include "JNIHelp.h"
+#include "jni.h"
+
+#include <stdlib.h>
+
+#include <hardware/hardware_properties.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include <hardware_properties/HardwarePropertiesManager.h>
+
+#include "core_jni_helpers.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+static struct {
+    jclass clazz;
+    jmethodID initMethod;
+} gCpuUsageInfoClassInfo;
+
+static struct hardware_properties_module* gHardwarePropertiesModule;
+
+// ----------------------------------------------------------------------------
+
+static void nativeInit(JNIEnv* env, jobject obj) {
+    status_t err = hw_get_module(HARDWARE_PROPERTIES_HARDWARE_MODULE_ID,
+            (hw_module_t const**)&gHardwarePropertiesModule);
+    if (err) {
+        ALOGE("Couldn't load %s module (%s)", HARDWARE_PROPERTIES_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 (speeds && size > 0) {
+            jfloatArray fanSpeeds = env->NewFloatArray(size);
+            env->SetFloatArrayRegion(fanSpeeds, 0, size, speeds);
+            free(speeds);
+            return fanSpeeds;
+        }
+
+        if (size < 0) {
+            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);
+            }
+            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;
+        }
+        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);
+        }
+    }
+    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);
+            }
+            free(active_times);
+            free(total_times);
+            return cpuUsages;
+        }
+
+        if (size < 0) {
+            ALOGE("Couldn't get CPU usages because of HAL error");
+        }
+    }
+    return env->NewObjectArray(0, gCpuUsageInfoClassInfo.clazz, nullptr);
+}
+
+// ----------------------------------------------------------------------------
+
+static const JNINativeMethod gHardwarePropertiesManagerMethods[] = {
+    /* name, signature, funcPtr */
+    { "nativeInit", "()V",
+            (void*) nativeInit },
+    { "nativeGetFanSpeeds", "()[F",
+            (void*) nativeGetFanSpeeds },
+    { "nativeGetDeviceTemperatures", "(I)[F",
+            (void*) nativeGetDeviceTemperatures },
+    { "nativeGetCpuUsages", "()[Landroid/os/CpuUsageInfo;",
+            (void*) nativeGetCpuUsages }
+};
+
+int register_android_os_HardwarePropertiesManager(JNIEnv* env) {
+    gHardwarePropertiesModule = nullptr;
+    int res = jniRegisterNativeMethods(env, "android/os/HardwarePropertiesManager",
+                                       gHardwarePropertiesManagerMethods,
+                                       NELEM(gHardwarePropertiesManagerMethods));
+    jclass clazz = env->FindClass("android/os/CpuUsageInfo");
+    gCpuUsageInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
+    gCpuUsageInfoClassInfo.initMethod = GetMethodIDOrDie(env, gCpuUsageInfoClassInfo.clazz,
+                                                         "<init>", "(JJ)V");
+    return res;
+}
+
+} /* namespace android */
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 90606a35..3473d9d 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -578,7 +578,7 @@
     return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
 }
 
-static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
+static jobjectArray getLocales(JNIEnv* env, jobject clazz, bool includeSystemLocales)
 {
     Vector<String8> locales;
 
@@ -587,7 +587,7 @@
         return NULL;
     }
 
-    am->getLocales(&locales);
+    am->getLocales(&locales, includeSystemLocales);
 
     const int N = locales.size();
 
@@ -608,6 +608,16 @@
     return result;
 }
 
+static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
+{
+    return getLocales(env, clazz, true /* include system locales */);
+}
+
+static jobjectArray android_content_AssetManager_getNonSystemLocales(JNIEnv* env, jobject clazz)
+{
+    return getLocales(env, clazz, false /* don't include system locales */);
+}
+
 static jobject constructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
     jobject result = env->NewObject(gConfigurationOffsets.classObject,
             gConfigurationOffsets.constructor);
@@ -2154,6 +2164,8 @@
     // Resources.
     { "getLocales",      "()[Ljava/lang/String;",
         (void*) android_content_AssetManager_getLocales },
+    { "getNonSystemLocales", "()[Ljava/lang/String;",
+        (void*) android_content_AssetManager_getNonSystemLocales },
     { "getSizeConfigurations", "()[Landroid/content/res/Configuration;",
         (void*) android_content_AssetManager_getSizeConfigurations },
     { "setConfiguration", "!(IILjava/lang/String;IIIIIIIIIIIIII)V",
diff --git a/core/jni/android_util_Log.cpp b/core/jni/android_util_Log.cpp
index 2d23cda..7719e31 100644
--- a/core/jni/android_util_Log.cpp
+++ b/core/jni/android_util_Log.cpp
@@ -18,8 +18,10 @@
 #define LOG_NAMESPACE "log.tag."
 #define LOG_TAG "Log_println"
 
+#include <android-base/macros.h>
 #include <assert.h>
 #include <cutils/properties.h>
+#include <log/logger.h>               // For LOGGER_ENTRY_MAX_PAYLOAD.
 #include <utils/Log.h>
 #include <utils/String8.h>
 
@@ -109,12 +111,23 @@
 }
 
 /*
+ * In class android.util.Log:
+ *  private static native int logger_entry_max_payload_native()
+ */
+static jint android_util_Log_logger_entry_max_payload_native(JNIEnv* env ATTRIBUTE_UNUSED,
+                                                             jobject clazz ATTRIBUTE_UNUSED)
+{
+    return static_cast<jint>(LOGGER_ENTRY_MAX_PAYLOAD);
+}
+
+/*
  * JNI registration.
  */
 static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "isLoggable",      "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable },
     { "println_native",  "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native },
+    { "logger_entry_max_payload_native",  "()I", (void*) android_util_Log_logger_entry_max_payload_native },
 };
 
 int register_android_util_Log(JNIEnv* env)
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 24eb961..f9936ae 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -23,6 +23,7 @@
 #include <inttypes.h>
 
 #include <android_runtime/AndroidRuntime.h>
+#include <androidfw/DisplayEventDispatcher.h>
 #include <utils/Log.h>
 #include <utils/Looper.h>
 #include <utils/threads.h>
@@ -48,14 +49,12 @@
 } gDisplayEventReceiverClassInfo;
 
 
-class NativeDisplayEventReceiver : public LooperCallback {
+class NativeDisplayEventReceiver : public DisplayEventDispatcher {
 public:
     NativeDisplayEventReceiver(JNIEnv* env,
             jobject receiverWeak, const sp<MessageQueue>& messageQueue);
 
-    status_t initialize();
     void dispose();
-    status_t scheduleVsync();
 
 protected:
     virtual ~NativeDisplayEventReceiver();
@@ -66,15 +65,14 @@
     DisplayEventReceiver mReceiver;
     bool mWaitingForVsync;
 
-    virtual int handleEvent(int receiveFd, int events, void* data);
-    bool processPendingEvents(nsecs_t* outTimestamp, int32_t* id, uint32_t* outCount);
-    void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count);
-    void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected);
+    virtual void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count);
+    virtual void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected);
 };
 
 
 NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
         jobject receiverWeak, const sp<MessageQueue>& messageQueue) :
+        DisplayEventDispatcher(messageQueue->getLooper()),
         mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
         mMessageQueue(messageQueue), mWaitingForVsync(false) {
     ALOGV("receiver %p ~ Initializing display event receiver.", this);
@@ -85,21 +83,6 @@
     env->DeleteGlobalRef(mReceiverWeakGlobal);
 }
 
-status_t NativeDisplayEventReceiver::initialize() {
-    status_t result = mReceiver.initCheck();
-    if (result) {
-        ALOGW("Failed to initialize display event receiver, status=%d", result);
-        return result;
-    }
-
-    int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT,
-            this, NULL);
-    if (rc < 0) {
-        return UNKNOWN_ERROR;
-    }
-    return OK;
-}
-
 void NativeDisplayEventReceiver::dispose() {
     ALOGV("receiver %p ~ Disposing display event receiver.", this);
 
@@ -108,87 +91,6 @@
     }
 }
 
-status_t NativeDisplayEventReceiver::scheduleVsync() {
-    if (!mWaitingForVsync) {
-        ALOGV("receiver %p ~ Scheduling vsync.", this);
-
-        // Drain all pending events.
-        nsecs_t vsyncTimestamp;
-        int32_t vsyncDisplayId;
-        uint32_t vsyncCount;
-        processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount);
-
-        status_t status = mReceiver.requestNextVsync();
-        if (status) {
-            ALOGW("Failed to request next vsync, status=%d", status);
-            return status;
-        }
-
-        mWaitingForVsync = true;
-    }
-    return OK;
-}
-
-int NativeDisplayEventReceiver::handleEvent(int receiveFd, int events, void* data) {
-    if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
-        ALOGE("Display event receiver pipe was closed or an error occurred.  "
-                "events=0x%x", events);
-        return 0; // remove the callback
-    }
-
-    if (!(events & Looper::EVENT_INPUT)) {
-        ALOGW("Received spurious callback for unhandled poll event.  "
-                "events=0x%x", events);
-        return 1; // keep the callback
-    }
-
-    // Drain all pending events, keep the last vsync.
-    nsecs_t vsyncTimestamp;
-    int32_t vsyncDisplayId;
-    uint32_t vsyncCount;
-    if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
-        ALOGV("receiver %p ~ Vsync pulse: timestamp=%" PRId64 ", id=%d, count=%d",
-                this, vsyncTimestamp, vsyncDisplayId, vsyncCount);
-        mWaitingForVsync = false;
-        dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
-    }
-
-    return 1; // keep the callback
-}
-
-bool NativeDisplayEventReceiver::processPendingEvents(
-        nsecs_t* outTimestamp, int32_t* outId, uint32_t* outCount) {
-    bool gotVsync = false;
-    DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
-    ssize_t n;
-    while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
-        ALOGV("receiver %p ~ Read %d events.", this, int(n));
-        for (ssize_t i = 0; i < n; i++) {
-            const DisplayEventReceiver::Event& ev = buf[i];
-            switch (ev.header.type) {
-            case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
-                // Later vsync events will just overwrite the info from earlier
-                // ones. That's fine, we only care about the most recent.
-                gotVsync = true;
-                *outTimestamp = ev.header.timestamp;
-                *outId = ev.header.id;
-                *outCount = ev.vsync.count;
-                break;
-            case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
-                dispatchHotplug(ev.header.timestamp, ev.header.id, ev.hotplug.connected);
-                break;
-            default:
-                ALOGW("receiver %p ~ ignoring unknown event type %#x", this, ev.header.type);
-                break;
-            }
-        }
-    }
-    if (n < 0) {
-        ALOGW("Failed to get events from display event receiver, status=%d", status_t(n));
-    }
-    return gotVsync;
-}
-
 void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
 
diff --git a/core/jni/android_view_DisplayListCanvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp
index 9b41eb3..a6c61de 100644
--- a/core/jni/android_view_DisplayListCanvas.cpp
+++ b/core/jni/android_view_DisplayListCanvas.cpp
@@ -27,7 +27,13 @@
 #include <SkBitmap.h>
 #include <SkRegion.h>
 
+#if HWUI_NEW_OPS
+#include <RecordingCanvas.h>
+typedef android::uirenderer::RecordingCanvas canvas_t;
+#else
 #include <DisplayListCanvas.h>
+typedef android::uirenderer::DisplayListCanvas canvas_t;
+#endif
 #include <Rect.h>
 #include <RenderNode.h>
 #include <CanvasProperty.h>
@@ -46,7 +52,7 @@
 
 static void android_view_DisplayListCanvas_insertReorderBarrier(JNIEnv* env, jobject clazz,
         jlong canvasPtr, jboolean reorderEnable) {
-    DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
+    canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
     canvas->insertReorderBarrier(reorderEnable);
 }
 
@@ -56,7 +62,7 @@
 
 static void android_view_DisplayListCanvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
         jlong canvasPtr, jlong functorPtr) {
-    DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
+    canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
     Functor* functor = reinterpret_cast<Functor*>(functorPtr);
     canvas->callDrawGLFunction(functor);
 }
@@ -66,10 +72,16 @@
 // ----------------------------------------------------------------------------
 
 static jint android_view_DisplayListCanvas_getMaxTextureWidth(JNIEnv* env, jobject clazz) {
+    if (!Caches::hasInstance()) {
+        android::uirenderer::renderthread::RenderProxy::staticFence();
+    }
     return Caches::getInstance().maxTextureSize;
 }
 
 static jint android_view_DisplayListCanvas_getMaxTextureHeight(JNIEnv* env, jobject clazz) {
+    if (!Caches::hasInstance()) {
+        android::uirenderer::renderthread::RenderProxy::staticFence();
+    }
     return Caches::getInstance().maxTextureSize;
 }
 
@@ -80,7 +92,7 @@
 static void android_view_DisplayListCanvas_drawRoundRectProps(JNIEnv* env, jobject clazz,
         jlong canvasPtr, jlong leftPropPtr, jlong topPropPtr, jlong rightPropPtr,
         jlong bottomPropPtr, jlong rxPropPtr, jlong ryPropPtr, jlong paintPropPtr) {
-    DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
+    canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
     CanvasPropertyPrimitive* leftProp = reinterpret_cast<CanvasPropertyPrimitive*>(leftPropPtr);
     CanvasPropertyPrimitive* topProp = reinterpret_cast<CanvasPropertyPrimitive*>(topPropPtr);
     CanvasPropertyPrimitive* rightProp = reinterpret_cast<CanvasPropertyPrimitive*>(rightPropPtr);
@@ -93,7 +105,7 @@
 
 static void android_view_DisplayListCanvas_drawCircleProps(JNIEnv* env, jobject clazz,
         jlong canvasPtr, jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) {
-    DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
+    canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
     CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
     CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
     CanvasPropertyPrimitive* radiusProp = reinterpret_cast<CanvasPropertyPrimitive*>(radiusPropPtr);
@@ -107,25 +119,25 @@
 
 static jlong android_view_DisplayListCanvas_finishRecording(JNIEnv* env,
         jobject clazz, jlong canvasPtr) {
-    DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
+    canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
     return reinterpret_cast<jlong>(canvas->finishRecording());
 }
 
 static jlong android_view_DisplayListCanvas_createDisplayListCanvas(JNIEnv* env, jobject clazz,
         jint width, jint height) {
-    return reinterpret_cast<jlong>(new DisplayListCanvas(width, height));
+    return reinterpret_cast<jlong>(new canvas_t(width, height));
 }
 
 static void android_view_DisplayListCanvas_resetDisplayListCanvas(JNIEnv* env, jobject clazz,
         jlong canvasPtr, jint width, jint height) {
-    DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
+    canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
     canvas->reset(width, height);
 }
 
 
 static void android_view_DisplayListCanvas_drawRenderNode(JNIEnv* env,
         jobject clazz, jlong canvasPtr, jlong renderNodePtr) {
-    DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
+    canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     canvas->drawRenderNode(renderNode);
 }
@@ -136,7 +148,7 @@
 
 static void android_view_DisplayListCanvas_drawLayer(JNIEnv* env, jobject clazz,
         jlong canvasPtr, jlong layerPtr) {
-    DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
+    canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
     canvas->drawLayer(layer);
 }
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index f6e68c4..cf68449 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -465,11 +465,17 @@
     anw->query(anw, NATIVE_WINDOW_HEIGHT, &value);
     return value;
 }
+
 static jlong nativeGetNextFrameNumber(JNIEnv *env, jclass clazz, jlong nativeObject) {
     Surface* surface = reinterpret_cast<Surface*>(nativeObject);
     return surface->getNextFrameNumber();
 }
 
+static jint nativeSetScalingMode(JNIEnv *env, jclass clazz, jlong nativeObject, jint scalingMode) {
+    Surface* surface = reinterpret_cast<Surface*>(nativeObject);
+    return surface->setScalingMode(scalingMode);
+}
+
 namespace uirenderer {
 
 using namespace android::uirenderer::renderthread;
@@ -546,6 +552,7 @@
     {"nativeGetWidth", "(J)I", (void*)nativeGetWidth },
     {"nativeGetHeight", "(J)I", (void*)nativeGetHeight },
     {"nativeGetNextFrameNumber", "(J)J", (void*)nativeGetNextFrameNumber },
+    {"nativeSetScalingMode", "(JI)I", (void*)nativeSetScalingMode },
 
     // HWUI context
     {"nHwuiCreate", "(JJ)J", (void*) hwui::create },
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 17eb876..edced56 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -28,14 +28,18 @@
 #include <EGL/eglext.h>
 #include <EGL/egl_cache.h>
 
+#include <utils/Looper.h>
+#include <utils/RefBase.h>
 #include <utils/StrongPointer.h>
 #include <android_runtime/android_view_Surface.h>
 #include <system/window.h>
 
 #include "android_view_GraphicBuffer.h"
+#include "android_os_MessageQueue.h"
 
 #include <Animator.h>
 #include <AnimationContext.h>
+#include <FrameInfo.h>
 #include <IContextFactory.h>
 #include <JankTracker.h>
 #include <RenderNode.h>
@@ -50,6 +54,12 @@
 using namespace android::uirenderer;
 using namespace android::uirenderer::renderthread;
 
+struct {
+    jfieldID buffer;
+    jfieldID messageQueue;
+    jmethodID notifyData;
+} gFrameStatsObserverClassInfo;
+
 static JNIEnv* getenv(JavaVM* vm) {
     JNIEnv* env;
     if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
@@ -207,6 +217,99 @@
     RootRenderNode* mRootNode;
 };
 
+class ObserverProxy;
+
+class NotifyHandler : public MessageHandler {
+public:
+    NotifyHandler(JavaVM* vm) : mVm(vm) {}
+
+    void setObserver(ObserverProxy* observer) {
+        mObserver = observer;
+    }
+
+    void setBuffer(BufferPool::Buffer* buffer) {
+        mBuffer = buffer;
+    }
+
+    virtual void handleMessage(const Message& message);
+
+private:
+    JavaVM* mVm;
+
+    sp<ObserverProxy> mObserver;
+    BufferPool::Buffer* mBuffer;
+};
+
+class ObserverProxy : public FrameStatsObserver {
+public:
+    ObserverProxy(JavaVM *vm, jobject fso) : mVm(vm) {
+        JNIEnv* env = getenv(mVm);
+
+        jlongArray longArrayLocal = env->NewLongArray(kBufferSize);
+        LOG_ALWAYS_FATAL_IF(longArrayLocal == nullptr,
+                "OOM: can't allocate frame stats buffer");
+        env->SetObjectField(fso, gFrameStatsObserverClassInfo.buffer, longArrayLocal);
+
+        mFsoWeak = env->NewWeakGlobalRef(fso);
+        LOG_ALWAYS_FATAL_IF(mFsoWeak == nullptr,
+                "unable to create frame stats observer reference");
+
+        jobject messageQueueLocal =
+                env->GetObjectField(fso, gFrameStatsObserverClassInfo.messageQueue);
+        mMessageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueLocal);
+        LOG_ALWAYS_FATAL_IF(mMessageQueue == nullptr, "message queue not available");
+
+        mMessageHandler = new NotifyHandler(mVm);
+        LOG_ALWAYS_FATAL_IF(mMessageHandler == nullptr,
+                "OOM: unable to allocate NotifyHandler");
+    }
+
+    ~ObserverProxy() {
+        JNIEnv* env = getenv(mVm);
+        env->DeleteWeakGlobalRef(mFsoWeak);
+    }
+
+    jweak getJavaObjectRef() {
+        return mFsoWeak;
+    }
+
+    virtual void notify(BufferPool::Buffer* buffer) {
+        buffer->incRef();
+        mMessageHandler->setBuffer(buffer);
+        mMessageHandler->setObserver(this);
+        mMessageQueue->getLooper()->sendMessage(mMessageHandler, mMessage);
+    }
+
+private:
+    static const int kBufferSize = static_cast<int>(FrameInfoIndex::NumIndexes);
+
+    JavaVM* mVm;
+    jweak mFsoWeak;
+
+    sp<MessageQueue> mMessageQueue;
+    sp<NotifyHandler> mMessageHandler;
+    Message mMessage;
+};
+
+void NotifyHandler::handleMessage(const Message& message) {
+    JNIEnv* env = getenv(mVm);
+
+    jobject target = env->NewLocalRef(mObserver->getJavaObjectRef());
+
+    if (target != nullptr) {
+        jobject javaBuffer = env->GetObjectField(target, gFrameStatsObserverClassInfo.buffer);
+        if (javaBuffer != nullptr) {
+            env->SetLongArrayRegion(reinterpret_cast<jlongArray>(javaBuffer),
+                    0, mBuffer->getSize(), mBuffer->getBuffer());
+            env->CallVoidMethod(target, gFrameStatsObserverClassInfo.notifyData);
+            env->DeleteLocalRef(target);
+        }
+    }
+
+    mBuffer->release();
+    mObserver.clear();
+}
+
 static void android_view_ThreadedRenderer_setAtlas(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jobject graphicBuffer, jlongArray atlasMapArray) {
     sp<GraphicBuffer> buffer = graphicBufferForJavaObject(env, graphicBuffer);
@@ -262,11 +365,11 @@
     env->ReleaseStringUTFChars(jname, name);
 }
 
-static jboolean android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
+static void android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jobject jsurface) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     sp<ANativeWindow> window = android_view_Surface_getNativeWindow(env, jsurface);
-    return proxy->initialize(window);
+    proxy->initialize(window);
 }
 
 static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz,
@@ -468,6 +571,42 @@
 }
 
 // ----------------------------------------------------------------------------
+// FrameStatsObserver
+// ----------------------------------------------------------------------------
+
+static jlong android_view_ThreadedRenderer_addFrameStatsObserver(JNIEnv* env,
+        jclass clazz, jlong proxyPtr, jobject fso) {
+    JavaVM* vm = nullptr;
+    if (env->GetJavaVM(&vm) != JNI_OK) {
+        LOG_ALWAYS_FATAL("Unable to get Java VM");
+        return 0;
+    }
+
+    renderthread::RenderProxy* renderProxy =
+            reinterpret_cast<renderthread::RenderProxy*>(proxyPtr);
+
+    FrameStatsObserver* observer = new ObserverProxy(vm, fso);
+    renderProxy->addFrameStatsObserver(observer);
+    return reinterpret_cast<jlong>(observer);
+}
+
+static void android_view_ThreadedRenderer_removeFrameStatsObserver(JNIEnv* env, jclass clazz,
+        jlong proxyPtr, jlong observerPtr) {
+    FrameStatsObserver* observer = reinterpret_cast<FrameStatsObserver*>(observerPtr);
+    renderthread::RenderProxy* renderProxy =
+            reinterpret_cast<renderthread::RenderProxy*>(proxyPtr);
+
+    renderProxy->removeFrameStatsObserver(observer);
+}
+
+static jint android_view_ThreadedRenderer_getDroppedFrameReportCount(JNIEnv* env, jclass clazz,
+        jlong proxyPtr) {
+    renderthread::RenderProxy* renderProxy =
+            reinterpret_cast<renderthread::RenderProxy*>(proxyPtr);
+    return renderProxy->getDroppedFrameReportCount();
+}
+
+// ----------------------------------------------------------------------------
 // Shaders
 // ----------------------------------------------------------------------------
 
@@ -492,7 +631,7 @@
     { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
     { "nLoadSystemProperties", "(J)Z", (void*) android_view_ThreadedRenderer_loadSystemProperties },
     { "nSetName", "(JLjava/lang/String;)V", (void*) android_view_ThreadedRenderer_setName },
-    { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize },
+    { "nInitialize", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_initialize },
     { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
     { "nPauseSurface", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_pauseSurface },
     { "nSetup", "(JIIFII)V", (void*) android_view_ThreadedRenderer_setup },
@@ -523,9 +662,26 @@
     { "nRemoveRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_removeRenderNode},
     { "nDrawRenderNode", "(JJ)V", (void*) android_view_ThreadedRendererd_drawRenderNode},
     { "nSetContentDrawBounds", "(JIIII)V", (void*)android_view_ThreadedRenderer_setContentDrawBounds},
+    { "nAddFrameStatsObserver",
+            "(JLandroid/view/FrameStatsObserver;)J",
+            (void*)android_view_ThreadedRenderer_addFrameStatsObserver },
+    { "nRemoveFrameStatsObserver",
+            "(JJ)V",
+            (void*)android_view_ThreadedRenderer_removeFrameStatsObserver },
+    { "nGetDroppedFrameReportCount",
+            "(J)J",
+            (void*)android_view_ThreadedRenderer_getDroppedFrameReportCount },
 };
 
 int register_android_view_ThreadedRenderer(JNIEnv* env) {
+    jclass clazz = FindClassOrDie(env, "android/view/FrameStatsObserver");
+    gFrameStatsObserverClassInfo.messageQueue  =
+            GetFieldIDOrDie(env, clazz, "mMessageQueue", "Landroid/os/MessageQueue;");
+    gFrameStatsObserverClassInfo.buffer =
+            GetFieldIDOrDie(env, clazz, "mBuffer", "[J");
+    gFrameStatsObserverClassInfo.notifyData =
+            GetMethodIDOrDie(env, clazz, "notifyDataAvailable", "()V");
+
     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
index 70134ab..9fa90ac 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -43,6 +43,7 @@
     jfieldID uid;
     jfieldID set;
     jfieldID tag;
+    jfieldID roaming;
     jfieldID rxBytes;
     jfieldID rxPackets;
     jfieldID txBytes;
@@ -238,6 +239,9 @@
     ScopedIntArrayRW tag(env, get_int_array(env, stats,
             gNetworkStatsClassInfo.tag, size, grow));
     if (tag.get() == NULL) return -1;
+    ScopedIntArrayRW roaming(env, get_int_array(env, stats,
+            gNetworkStatsClassInfo.roaming, size, grow));
+    if (roaming.get() == NULL) return -1;
     ScopedLongArrayRW rxBytes(env, get_long_array(env, stats,
             gNetworkStatsClassInfo.rxBytes, size, grow));
     if (rxBytes.get() == NULL) return -1;
@@ -261,6 +265,7 @@
         uid[i] = lines[i].uid;
         set[i] = lines[i].set;
         tag[i] = lines[i].tag;
+        // Roaming is populated in Java-land by inspecting the iface properties.
         rxBytes[i] = lines[i].rxBytes;
         rxPackets[i] = lines[i].rxPackets;
         txBytes[i] = lines[i].txBytes;
@@ -274,6 +279,7 @@
         env->SetObjectField(stats, gNetworkStatsClassInfo.uid, uid.getJavaArray());
         env->SetObjectField(stats, gNetworkStatsClassInfo.set, set.getJavaArray());
         env->SetObjectField(stats, gNetworkStatsClassInfo.tag, tag.getJavaArray());
+        env->SetObjectField(stats, gNetworkStatsClassInfo.roaming, roaming.getJavaArray());
         env->SetObjectField(stats, gNetworkStatsClassInfo.rxBytes, rxBytes.getJavaArray());
         env->SetObjectField(stats, gNetworkStatsClassInfo.rxPackets, rxPackets.getJavaArray());
         env->SetObjectField(stats, gNetworkStatsClassInfo.txBytes, txBytes.getJavaArray());
@@ -305,6 +311,7 @@
     gNetworkStatsClassInfo.uid = GetFieldIDOrDie(env, clazz, "uid", "[I");
     gNetworkStatsClassInfo.set = GetFieldIDOrDie(env, clazz, "set", "[I");
     gNetworkStatsClassInfo.tag = GetFieldIDOrDie(env, clazz, "tag", "[I");
+    gNetworkStatsClassInfo.roaming = GetFieldIDOrDie(env, clazz, "roaming", "[I");
     gNetworkStatsClassInfo.rxBytes = GetFieldIDOrDie(env, clazz, "rxBytes", "[J");
     gNetworkStatsClassInfo.rxPackets = GetFieldIDOrDie(env, clazz, "rxPackets", "[J");
     gNetworkStatsClassInfo.txBytes = GetFieldIDOrDie(env, clazz, "txBytes", "[J");
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 96d150b..4194aa4 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -605,10 +605,32 @@
         jint debug_flags, jobjectArray rlimits,
         jint mount_external, jstring se_info, jstring se_name,
         jintArray fdsToClose, jstring instructionSet, jstring appDataDir) {
-    // Grant CAP_WAKE_ALARM to the Bluetooth process.
     jlong capabilities = 0;
-    if (uid == AID_BLUETOOTH) {
-        capabilities |= (1LL << CAP_WAKE_ALARM);
+
+    // Grant CAP_WAKE_ALARM to the Bluetooth process.
+    if (multiuser_get_app_id(uid) == AID_BLUETOOTH) {
+      capabilities |= (1LL << CAP_WAKE_ALARM);
+    }
+
+    // Grant CAP_BLOCK_SUSPEND to processes that belong to GID "wakelock"
+    bool gid_wakelock_found = false;
+    if (gid == AID_WAKELOCK) {
+      gid_wakelock_found = true;
+    } else if (gids != NULL) {
+      jsize gids_num = env->GetArrayLength(gids);
+      ScopedIntArrayRO ar(env, gids);
+      if (ar.get() == NULL) {
+        RuntimeAbort(env, __LINE__, "Bad gids array");
+      }
+      for (int i = 0; i < gids_num; i++) {
+        if (ar[i] == AID_WAKELOCK) {
+          gid_wakelock_found = true;
+          break;
+        }
+      }
+    }
+    if (gid_wakelock_found) {
+      capabilities |= (1LL << CAP_BLOCK_SUSPEND);
     }
 
     return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1090f90..1c3db10 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -47,6 +47,8 @@
     <protected-broadcast android:name="android.intent.action.PACKAGE_FIRST_LAUNCH" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_NEEDS_VERIFICATION" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_VERIFIED" />
+    <protected-broadcast android:name="android.intent.action.PACKAGES_SUSPENDED" />
+    <protected-broadcast android:name="android.intent.action.PACKAGES_UNSUSPENDED" />
     <protected-broadcast android:name="android.intent.action.UID_REMOVED" />
     <protected-broadcast android:name="android.intent.action.QUERY_PACKAGE_RESTART" />
     <protected-broadcast android:name="android.intent.action.CONFIGURATION_CHANGED" />
@@ -94,6 +96,10 @@
     <protected-broadcast android:name="android.app.action.EXIT_DESK_MODE" />
     <protected-broadcast android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
 
+    <protected-broadcast android:name="android.app.action.BUGREPORT_SHARING_DECLINED" />
+    <protected-broadcast android:name="android.app.action.BUGREPORT_FAILED" />
+    <protected-broadcast android:name="android.app.action.BUGREPORT_SHARE" />
+
     <protected-broadcast android:name="android.appwidget.action.APPWIDGET_UPDATE_OPTIONS" />
     <protected-broadcast android:name="android.appwidget.action.APPWIDGET_DELETED" />
     <protected-broadcast android:name="android.appwidget.action.APPWIDGET_DISABLED" />
@@ -103,10 +109,11 @@
 
     <protected-broadcast android:name="android.os.action.SETTING_RESTORED" />
 
-    <protected-broadcast android:name="android.backup.intent.RUN" />
-    <protected-broadcast android:name="android.backup.intent.CLEAR" />
-    <protected-broadcast android:name="android.backup.intent.INIT" />
+    <protected-broadcast android:name="android.app.backup.intent.RUN" />
+    <protected-broadcast android:name="android.app.backup.intent.CLEAR" />
+    <protected-broadcast android:name="android.app.backup.intent.INIT" />
 
+    <protected-broadcast android:name="android.bluetooth.intent.DISCOVERABLE_TIMEOUT" />
     <protected-broadcast android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.adapter.action.SCAN_MODE_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_STARTED" />
@@ -204,6 +211,7 @@
     <protected-broadcast android:name="android.media.VOLUME_CHANGED_ACTION" />
     <protected-broadcast android:name="android.media.MASTER_VOLUME_CHANGED_ACTION" />
     <protected-broadcast android:name="android.media.MASTER_MUTE_CHANGED_ACTION" />
+    <protected-broadcast android:name="android.media.MASTER_MONO_CHANGED_ACTION" />
     <protected-broadcast android:name="android.media.SCO_AUDIO_STATE_CHANGED" />
     <protected-broadcast android:name="android.media.ACTION_SCO_AUDIO_STATE_UPDATED" />
 
@@ -218,6 +226,8 @@
     <protected-broadcast android:name="android.intent.action.MEDIA_UNMOUNTABLE" />
     <protected-broadcast android:name="android.intent.action.MEDIA_EJECT" />
 
+    <protected-broadcast android:name="android.intent.action.PICTURE_IN_PICTURE_BUTTON" />
+
     <protected-broadcast android:name="android.net.conn.CAPTIVE_PORTAL" />
     <protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE" />
     <!-- @deprecated.  Only {@link android.net.ConnectivityManager.CONNECTIVITY_ACTION} is sent. -->
@@ -247,6 +257,8 @@
     <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.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" />
     <protected-broadcast android:name="android.net.wifi.WIFI_AP_STATE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.WIFI_CREDENTIAL_CHANGED" />
@@ -276,8 +288,10 @@
     <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_FINISHED" />
     <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" />
 
     <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_START" />
     <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_END" />
@@ -325,7 +339,6 @@
     <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.AVAILABILITY_CHANGED" />
 
     <!-- Added in N -->
     <protected-broadcast android:name="android.intent.action.ANR" />
@@ -342,6 +355,20 @@
     <protected-broadcast android:name="android.intent.action.WALLPAPER_CHANGED" />
 
     <protected-broadcast android:name="android.app.action.DEVICE_POLICY_MANAGER_STATE_CHANGED" />
+    <protected-broadcast android:name="android.app.action.CHOOSE_PRIVATE_KEY_ALIAS" />
+    <protected-broadcast android:name="android.app.action.DEVICE_ADMIN_DISABLED" />
+    <protected-broadcast android:name="android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED" />
+    <protected-broadcast android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+    <protected-broadcast android:name="android.app.action.LOCK_TASK_ENTERING" />
+    <protected-broadcast android:name="android.app.action.LOCK_TASK_EXITING" />
+    <protected-broadcast android:name="android.app.action.NOTIFY_PENDING_SYSTEM_UPDATE" />
+    <protected-broadcast android:name="android.app.action.ACTION_PASSWORD_CHANGED" />
+    <protected-broadcast android:name="android.app.action.ACTION_PASSWORD_EXPIRING" />
+    <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.bluetooth.adapter.action.BLE_STATE_CHANGED" />
     <protected-broadcast android:name="android.content.jobscheduler.JOB_DELAY_EXPIRED" />
     <protected-broadcast android:name="android.content.syncmanager.SYNC_ALARM" />
@@ -356,6 +383,7 @@
     <protected-broadcast android:name="android.security.STORAGE_CHANGED" />
     <protected-broadcast android:name="android.telecom.action.PHONE_ACCOUNT_REGISTERED" />
     <protected-broadcast android:name="android.telecom.action.PHONE_ACCOUNT_UNREGISTERED" />
+    <protected-broadcast android:name="android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION" />
     <protected-broadcast android:name="android.telephony.action.CARRIER_CONFIG_CHANGED" />
 
     <protected-broadcast android:name="com.android.bluetooth.btservice.action.ALARM_WAKEUP" />
@@ -381,6 +409,18 @@
     <protected-broadcast android:name="com.android.server.device_idle.STEP_LIGHT_IDLE_STATE" />
     <protected-broadcast android:name="com.android.server.Wifi.action.TOGGLE_PNO" />
     <protected-broadcast android:name="intent.action.ACTION_RF_BAND_INFO" />
+    <protected-broadcast android:name="android.intent.action.MEDIA_RESOURCE_GRANTED" />
+
+    <protected-broadcast android:name="android.app.action.INTERRUPTION_FILTER_CHANGED" />
+    <protected-broadcast android:name="android.app.action.INTERRUPTION_FILTER_CHANGED_INTERNAL" />
+    <protected-broadcast android:name="android.app.action.NOTIFICATION_POLICY_CHANGED" />
+    <protected-broadcast android:name="android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED" />
+    <protected-broadcast android:name="android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED" />
+
+    <protected-broadcast android:name="android.permission.GET_APP_GRANTED_URI_PERMISSIONS" />
+    <protected-broadcast android:name="android.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS" />
+
+    <protected-broadcast android:name="android.intent.action.DYNAMIC_SENSOR_CHANGED" />
 
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
@@ -888,6 +928,11 @@
         android:protectionLevel="normal"
         android:permissionFlags="hidden"/>
 
+    <!-- @hide We need to keep this around for backwards compatibility -->
+    <permission android:name="android.permission.FLASHLIGHT"
+        android:protectionLevel="normal"
+        android:permissionFlags="hidden"/>
+
     <!-- ====================================================================== -->
     <!-- INSTALL PERMISSIONS                                                    -->
     <!-- ====================================================================== -->
@@ -1052,6 +1097,12 @@
     <permission android:name="android.permission.READ_WIFI_CREDENTIAL"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi @hide Allows applications to change tether state and run
+         tether carrier provisioning.
+         <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.TETHER_PRIVILEGED"
+        android:protectionLevel="signature|privileged" />
+
     <!-- @SystemApi @hide Allow system apps to receive broadcast
          when a wifi network credential is changed.
          <p>Not for use by third-party applications. -->
@@ -1159,7 +1210,8 @@
     <eat-comment />
 
     <!-- Allows access to the list of accounts in the Accounts Service.
-        <p>Protection level: normal
+         <p>Protection level: dangerous
+         @deprecated Not operative for apps apps with targetSdkVersion >= 24.
     -->
     <permission android:name="android.permission.GET_ACCOUNTS"
         android:permissionGroup="android.permission-group.CONTACTS"
@@ -1193,14 +1245,6 @@
         android:description="@string/permdesc_vibrate"
         android:protectionLevel="normal" />
 
-    <!-- Allows access to the flashlight.
-         <p>Protection level: normal
-    -->
-    <permission android:name="android.permission.FLASHLIGHT"
-        android:label="@string/permlab_flashlight"
-        android:description="@string/permdesc_flashlight"
-        android:protectionLevel="normal" />
-
     <!-- Allows using PowerManager WakeLocks to keep processor from sleeping or screen
          from dimming.
          <p>Protection level: normal
@@ -1365,6 +1409,13 @@
     <permission android:name="android.permission.BIND_INCALL_SERVICE"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Must be required by a {@link android.telecom.CallScreeningService},
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature|privileged
+    -->
+    <permission android:name="android.permission.BIND_SCREENING_SERVICE"
+        android:protectionLevel="signature|privileged" />
+
     <!-- Must be required by a {@link android.telecom.ConnectionService},
          to ensure that only the system can bind to it.
          @deprecated {@link android.telecom.ConnectionService}s should require
@@ -1901,7 +1952,7 @@
 
     <!-- Allows an application to bind to third party quick settings tiles.
          <p>Should only be requested by the System, should be required by
-         QSTileService declarations.-->
+         TileService declarations.-->
     <permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE"
         android:protectionLevel="signature" />
 
@@ -2186,6 +2237,21 @@
     <permission android:name="android.permission.CLEAR_APP_USER_DATA"
         android:protectionLevel="signature|installer" />
 
+    <!-- @hide Allows an application to get the URI permissions
+         granted to another application.
+         <p>Not for use by third-party applications
+    -->
+    <permission android:name="android.permission.GET_APP_GRANTED_URI_PERMISSIONS"
+        android:protectionLevel="signature" />
+
+    <!-- @hide Allows an application to clear the URI permissions
+         granted to another application.
+         <p>Not for use by third-party applications
+    -->
+    <permission
+        android:name="android.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS"
+        android:protectionLevel="signature" />
+
     <!-- @SystemApi Allows an application to delete cache files.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.DELETE_CACHE_FILES"
@@ -2797,6 +2863,18 @@
     <permission android:name="android.permission.ACCESS_EPHEMERAL_APPS"
             android:protectionLevel="signature" />
 
+    <!-- Allows receiving the usage of media resource e.g. video/audio codec and
+         graphic memory.
+         @hide -->
+    <permission android:name="android.permission.RECEIVE_MEDIA_RESOURCE_USAGE"
+                android:protectionLevel="signature|privileged" />
+
+    <!-- Must be required by system/priv apps when accessing the sound trigger
+         APIs given by {@link SoundTriggerManager}.
+         @hide <p>Not for use by third-party applications.</p> -->
+    <permission android:name="android.permission.MANAGE_SOUND_TRIGGER"
+        android:protectionLevel="signature|privileged" />
+
     <application android:process="system"
                  android:persistent="true"
                  android:hasCode="false"
@@ -2946,6 +3024,24 @@
             </intent-filter>
         </activity>
 
+        <!-- Activity to prompt user if it's ok to create a new user sandbox for a
+             specified account. -->
+        <activity android:name="com.android.internal.app.ConfirmUserCreationActivity"
+                android:excludeFromRecents="true"
+                android:process=":ui"
+                android:theme="@style/Theme.Material.DayNight.Dialog.Alert">
+            <intent-filter android:priority="1000">
+                <action android:name="android.os.action.CREATE_USER" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="com.android.internal.app.UnlaunchableAppActivity"
+                android:theme="@style/Theme.Material.DayNight.Dialog.Alert"
+                android:excludeFromRecents="true"
+                android:process=":ui">
+        </activity>
+
         <receiver android:name="com.android.server.BootReceiver"
                 android:systemUserOnly="true">
             <intent-filter android:priority="1000">
diff --git a/core/res/res/drawable-xhdpi/pointer_alias_large.png b/core/res/res/drawable-xhdpi/pointer_alias_large.png
new file mode 100644
index 0000000..813cd2a
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_alias_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_all_scroll_large.png b/core/res/res/drawable-xhdpi/pointer_all_scroll_large.png
new file mode 100644
index 0000000..f101077
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_all_scroll_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_arrow_large.png b/core/res/res/drawable-xhdpi/pointer_arrow_large.png
new file mode 100644
index 0000000..0f9165b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_arrow_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_cell_large.png b/core/res/res/drawable-xhdpi/pointer_cell_large.png
new file mode 100644
index 0000000..b41f855
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_cell_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_context_menu_large.png b/core/res/res/drawable-xhdpi/pointer_context_menu_large.png
new file mode 100644
index 0000000..6264e0b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_context_menu_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_copy_large.png b/core/res/res/drawable-xhdpi/pointer_copy_large.png
new file mode 100644
index 0000000..5e7f375
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_copy_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_crosshair_large.png b/core/res/res/drawable-xhdpi/pointer_crosshair_large.png
new file mode 100644
index 0000000..d5f4502
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_crosshair_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_grab_large.png b/core/res/res/drawable-xhdpi/pointer_grab_large.png
new file mode 100644
index 0000000..bf99b79
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_grab_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_grabbing_large.png b/core/res/res/drawable-xhdpi/pointer_grabbing_large.png
new file mode 100644
index 0000000..e576bcd
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_grabbing_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_hand_large.png b/core/res/res/drawable-xhdpi/pointer_hand_large.png
new file mode 100644
index 0000000..76fa09b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_hand_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_help_large.png b/core/res/res/drawable-xhdpi/pointer_help_large.png
new file mode 100644
index 0000000..a45f039
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_help_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow_large.png b/core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow_large.png
new file mode 100644
index 0000000..9b2a312
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_horizontal_double_arrow_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_nodrop_large.png b/core/res/res/drawable-xhdpi/pointer_nodrop_large.png
new file mode 100644
index 0000000..f140532
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_nodrop_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_text_large.png b/core/res/res/drawable-xhdpi/pointer_text_large.png
new file mode 100644
index 0000000..56be154
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_text_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow_large.png b/core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow_large.png
new file mode 100644
index 0000000..9e6a8b6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_top_left_diagonal_double_arrow_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow_large.png b/core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow_large.png
new file mode 100644
index 0000000..2631094
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_top_right_diagonal_double_arrow_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_vertical_double_arrow_large.png b/core/res/res/drawable-xhdpi/pointer_vertical_double_arrow_large.png
new file mode 100644
index 0000000..5ec65e0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_vertical_double_arrow_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_vertical_text_large.png b/core/res/res/drawable-xhdpi/pointer_vertical_text_large.png
new file mode 100644
index 0000000..26c46de
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_vertical_text_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_zoom_in_large.png b/core/res/res/drawable-xhdpi/pointer_zoom_in_large.png
new file mode 100644
index 0000000..c2b845f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_zoom_in_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_zoom_out_large.png b/core/res/res/drawable-xhdpi/pointer_zoom_out_large.png
new file mode 100644
index 0000000..148ed25
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_zoom_out_large.png
Binary files differ
diff --git a/core/res/res/drawable/ic_corp_badge_no_background.xml b/core/res/res/drawable/ic_corp_badge_no_background.xml
new file mode 100644
index 0000000..b1bddfc
--- /dev/null
+++ b/core/res/res/drawable/ic_corp_badge_no_background.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="24.0dp"
+    android:height="24.0dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:pathData="M20.801,5.981L17.13,5.98l0.001,-1.471l-2.053,-2.055L8.969,2.453L6.915,4.506L6.914,5.977L3.203,5.976c-1.216,0.0 -2.189,0.983 -2.189,2.199L1.0,12.406c0.0,1.216 0.983,2.2 2.199,2.2L10.0,14.608l0.0,-1.644l0.291,0.0l3.351,0.0l0.291,0.0l0.0,1.645l6.863,0.002c1.216,0.0 2.2,-0.983 2.2,-2.199L23.0,8.181C23.0,6.965 22.017,5.981 20.801,5.981zM15.076,5.979L8.968,5.978l0.001,-1.471l6.108,0.001L15.076,5.979z"
+        android:fillColor="#FF5722"/>
+    <path
+        android:pathData="M13.911,16.646L9.978,16.646L9.978,15.48L1.673,15.48l0.0,4.105c0.0,1.216 0.959,2.2 2.175,2.2l16.13,0.004c1.216,0.0 2.203,-0.983 2.203,-2.199l0.0,-4.11l-8.27,0.0L13.910999,16.646z"
+        android:fillColor="#FF5722"/>
+    <path
+        android:pathData="M23.657,6.55 h4.72 v1.137 h-4.72z"
+        android:fillColor="#00000000"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_notification_alert.xml b/core/res/res/drawable/ic_notification_alert.xml
new file mode 100644
index 0000000..c8514ac
--- /dev/null
+++ b/core/res/res/drawable/ic_notification_alert.xml
@@ -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.
+-->
+<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="M18.4,2.2L17.0,3.6c2.0,1.4 3.3,3.7 3.5,6.4l2.0,0.0C22.3,6.8 20.8,4.0 18.4,2.2z"
+        android:fillColor="#FFFFFFFF"/>
+    <path
+        android:pathData="M7.1,3.6L5.7,2.2C3.3,4.0 1.7,6.8 1.5,10.0l2.0,0.0C3.7,7.3 5.0,5.0 7.1,3.6z"
+        android:fillColor="#FFFFFFFF"/>
+    <path
+        android:pathData="M18.5,10.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.5,3.5C13.5,2.7 12.8,2.0 12.0,2.0s-1.5,0.7 -1.5,1.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.5,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0l-2.0,-2.0L18.5,10.5zM13.0,16.5l-2.0,0.0l0.0,-2.0l2.0,0.0L13.0,16.5zM13.0,12.5l-2.0,0.0l0.0,-6.0l2.0,0.0L13.0,12.5z"
+        android:fillColor="#FFFFFFFF"/>
+    <path
+        android:pathData="M12.0,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0L10.0,20.0C10.0,21.1 10.9,22.0 12.0,22.0z"
+        android:fillColor="#FFFFFFFF"/>
+</vector>
diff --git a/core/res/res/drawable/ic_notification_block.xml b/core/res/res/drawable/ic_notification_block.xml
new file mode 100644
index 0000000..572e97b
--- /dev/null
+++ b/core/res/res/drawable/ic_notification_block.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="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M12.0,2.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.0zM4.0,12.0c0.0,-4.42 3.58,-8.0 8.0,-8.0 1.85,0.0 3.5,0.63 4.9,1.69L5.69,16.9C4.63,15.55 4.0,13.85 4.0,12.0zm8.0,8.0c-1.85,0.0 -3.55,-0.63 -4.9,-1.69L18.31,7.1C19.37,8.45 20.0,10.15 20.0,12.0c0.0,4.42 -3.58,8.0 -8.0,8.0z"/>
+</vector>
diff --git a/core/res/res/drawable/seekbar_tick_mark_material.xml b/core/res/res/drawable/seekbar_tick_mark_material.xml
new file mode 100644
index 0000000..d2c38a2
--- /dev/null
+++ b/core/res/res/drawable/seekbar_tick_mark_material.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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="oval"
+       android:tint="?attr/colorControlNormal">
+    <size android:width="@dimen/progress_bar_height_material"
+          android:height="@dimen/progress_bar_height_material" />
+    <solid android:color="@color/white" />
+</shape>
diff --git a/core/res/res/layout-sw600dp/date_picker_dialog.xml b/core/res/res/layout-sw600dp/date_picker_dialog.xml
index f9b247f..f18485f 100644
--- a/core/res/res/layout-sw600dp/date_picker_dialog.xml
+++ b/core/res/res/layout-sw600dp/date_picker_dialog.xml
@@ -1,20 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+     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.
 -->
 
 <DatePicker xmlns:android="http://schemas.android.com/apk/res/android"
@@ -23,5 +21,4 @@
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:spinnersShown="true"
-    android:calendarViewShown="true"
-    />
+    android:calendarViewShown="true" />
diff --git a/core/res/res/layout/app_error_dialog.xml b/core/res/res/layout/app_error_dialog.xml
new file mode 100644
index 0000000..46a2b2a
--- /dev/null
+++ b/core/res/res/layout/app_error_dialog.xml
@@ -0,0 +1,70 @@
+<?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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:paddingTop="@dimen/dialog_list_padding_vertical_material"
+        android:paddingBottom="@dimen/dialog_list_padding_vertical_material"
+>
+
+
+    <Button
+            android:id="@+id/aerr_restart"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/aerr_restart"
+            style="@style/aerr_list_item"
+    />
+
+    <Button
+            android:id="@+id/aerr_reset"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/aerr_reset"
+            style="@style/aerr_list_item"
+    />
+
+    <Button
+            android:id="@+id/aerr_report"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/aerr_report"
+            style="@style/aerr_list_item"
+    />
+
+    <Button
+            android:id="@+id/aerr_close"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/aerr_close"
+            style="@style/aerr_list_item"
+    />
+
+    <Button
+            android:id="@+id/aerr_mute"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/aerr_mute"
+            style="@style/aerr_list_item"
+    />
+
+
+</LinearLayout>
diff --git a/core/res/res/layout/app_error_dialog_dont_show_again.xml b/core/res/res/layout/app_error_dialog_dont_show_again.xml
deleted file mode 100644
index ba79ecd..0000000
--- a/core/res/res/layout/app_error_dialog_dont_show_again.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?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.
-*/
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:paddingStart="14dp"
-        android:paddingEnd="10dp"
-        android:gravity="center_vertical"
-        >
-    <CheckBox
-            android:id="@+id/checkbox"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            />
-    <TextView
-            android:id="@+id/text"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="8dp"
-            android:layout_marginBottom="8dp"
-            />
-
-</LinearLayout>
diff --git a/core/res/res/layout/date_picker_dialog.xml b/core/res/res/layout/date_picker_dialog.xml
index db8f311..64ac1b9 100644
--- a/core/res/res/layout/date_picker_dialog.xml
+++ b/core/res/res/layout/date_picker_dialog.xml
@@ -1,20 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+     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.
 -->
 
 <DatePicker xmlns:android="http://schemas.android.com/apk/res/android"
@@ -23,5 +21,4 @@
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:spinnersShown="true"
-    android:calendarViewShown="false"
-    />
+    android:calendarViewShown="false" />
diff --git a/core/res/res/layout/date_picker_header_material.xml b/core/res/res/layout/date_picker_header_material.xml
index 821b588..cfc6d0d 100644
--- a/core/res/res/layout/date_picker_header_material.xml
+++ b/core/res/res/layout/date_picker_header_material.xml
@@ -19,35 +19,46 @@
               android:id="@+id/date_picker_header"
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
-              android:paddingStart="?attr/dialogPreferredPadding"
-              android:paddingEnd="?attr/dialogPreferredPadding"
-              android:paddingTop="16dp"
-              android:paddingBottom="18dp"
-              android:orientation="vertical"
-              android:clipToPadding="false"
-              android:clipChildren="false">
+              android:orientation="vertical">
 
-    <TextView
-        android:id="@+id/date_picker_header_year"
-        android:layout_width="wrap_content"
+    <ViewStub
+        android:id="@id/topPanel"
+        android:layout="@layout/alert_dialog_title_material"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:focusable="true"
-        android:layout_marginStart="-8dp"
-        android:layout_marginEnd="-8dp"
-        android:layout_marginTop="-8dp"
-        android:layout_marginBottom="-8dp"
-        android:padding="8dp"
-        android:background="?attr/selectableItemBackground"
-        android:textAppearance="@style/TextAppearance.Material.DatePicker.YearLabel"
-        android:nextFocusForward="@+id/prev" />
+        android:paddingStart="?attr/dialogPreferredPadding"
+        android:paddingEnd="?attr/dialogPreferredPadding"
+        android:paddingTop="16dp"
+        android:paddingBottom="18dp"
+        android:orientation="vertical"
+        android:clipToPadding="false"
+        android:clipChildren="false">
 
-    <TextView
-        android:id="@+id/date_picker_header_date"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:textAppearance="@style/TextAppearance.Material.DatePicker.DateLabel"
-        android:gravity="start"
-        android:maxLines="2"
-        android:ellipsize="none" />
+        <TextView
+            android:id="@+id/date_picker_header_year"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:focusable="true"
+            android:layout_marginStart="-8dp"
+            android:layout_marginEnd="-8dp"
+            android:layout_marginTop="-8dp"
+            android:layout_marginBottom="-8dp"
+            android:padding="8dp"
+            android:background="?attr/selectableItemBackground"
+            android:textAppearance="@style/TextAppearance.Material.DatePicker.YearLabel"
+            android:nextFocusForward="@+id/prev" />
 
+        <TextView
+            android:id="@+id/date_picker_header_date"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="@style/TextAppearance.Material.DatePicker.DateLabel"
+            android:gravity="start"
+            android:maxLines="2"
+            android:ellipsize="none" />
+    </LinearLayout>
 </LinearLayout>
diff --git a/core/res/res/layout/input_method_switch_dialog_title.xml b/core/res/res/layout/input_method_switch_dialog_title.xml
index 856a7af..48fd5e6 100644
--- a/core/res/res/layout/input_method_switch_dialog_title.xml
+++ b/core/res/res/layout/input_method_switch_dialog_title.xml
@@ -70,24 +70,24 @@
                 android:orientation="vertical"
                 android:paddingBottom="5dp"
                 android:paddingStart="?attr/listPreferredItemPaddingStart"
-                android:paddingEnd="0dp"
-                android:paddingTop="5dp" >
+                android:paddingEnd="16dp"
+                android:paddingTop="16dp" >
 
                 <TextView
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:singleLine="true"
                     android:text="@string/hardware"
-                    android:textAppearance="?attr/textAppearanceMedium"
-                    android:textColor="?attr/textColorAlertDialogListItem" />
+                    android:textAppearance="?attr/textAppearanceListItem"
+                    android:ellipsize="marquee" />
 
                 <TextView
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:singleLine="true"
+                    android:maxLines="10"
                     android:text="@string/show_ime"
-                    android:textAppearance="?attr/textAppearanceSmall"
-                    android:textColor="?attr/textColorAlertDialogListItem" />
+                    android:textAppearance="?attr/textAppearanceListItemSecondary"
+                    android:textColor="?attr/textColorSecondary" />
             </LinearLayout>
 
             <Switch
diff --git a/core/res/res/layout/language_picker_item.xml b/core/res/res/layout/language_picker_item.xml
new file mode 100644
index 0000000..22cb514
--- /dev/null
+++ b/core/res/res/layout/language_picker_item.xml
@@ -0,0 +1,50 @@
+<?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: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>
diff --git a/core/res/res/layout/language_picker_section_header.xml b/core/res/res/layout/language_picker_section_header.xml
new file mode 100644
index 0000000..c4d3069
--- /dev/null
+++ b/core/res/res/layout/language_picker_section_header.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.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
+          style="?android:attr/preferenceCategoryStyle"
+          android:layout_width="match_parent"
+          android:layout_height="36dp"
+          android:paddingStart="12dp"
+          android:paddingEnd="12dp"
+          android:textColor="?android:attr/colorAccent"
+          tools:text="@string/language_picker_section_all"/>
diff --git a/core/res/res/layout/notification_material_action_list.xml b/core/res/res/layout/notification_material_action_list.xml
index 2a89faa..2a4aa96 100644
--- a/core/res/res/layout/notification_material_action_list.xml
+++ b/core/res/res/layout/notification_material_action_list.xml
@@ -26,6 +26,7 @@
             android:layout_height="56dp"
             android:paddingEnd="4dp"
             android:orientation="horizontal"
+            android:gravity="center_vertical"
             android:visibility="gone"
             android:background="#ffeeeeee"
             >
diff --git a/core/res/res/layout/notification_material_reply_text.xml b/core/res/res/layout/notification_material_reply_text.xml
new file mode 100644
index 0000000..bc22eb4
--- /dev/null
+++ b/core/res/res/layout/notification_material_reply_text.xml
@@ -0,0 +1,61 @@
+<?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
+  -->
+
+<!-- Note: this layout is included from a view stub; layout attributes will be overridden. -->
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/notification_material_reply_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:paddingStart="@dimen/notification_content_margin_start">
+
+    <ImageView
+            android:layout_width="match_parent"
+            android:layout_height="1dip"
+            android:id="@+id/action_divider"
+            android:layout_marginBottom="15dp"
+            android:background="@drawable/notification_template_divider" />
+
+    <TextView
+            android:id="@+id/notification_material_reply_text_3"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
+            android:visibility="gone"
+            android:textAppearance="@style/TextAppearance.Material.Notification.Reply"
+            android:singleLine="true" />
+
+    <TextView
+            android:id="@+id/notification_material_reply_text_2"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
+            android:visibility="gone"
+            android:textAppearance="@style/TextAppearance.Material.Notification.Reply"
+            android:singleLine="true" />
+
+    <TextView
+            android:id="@+id/notification_material_reply_text_1"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="15dp"
+            android:layout_marginEnd="@dimen/notification_content_margin_end"
+            android:textAppearance="@style/TextAppearance.Material.Notification.Reply"
+            android:singleLine="true" />
+
+</LinearLayout>
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index e45f52b..163db30 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -127,5 +127,15 @@
         android:paddingTop="1dp"
         android:visibility="gone"
         />
+    <ImageView android:id="@+id/profile_badge"
+        android:layout_width="@dimen/notification_badge_size"
+        android:layout_height="@dimen/notification_badge_size"
+        android:layout_gravity="center"
+        android:layout_marginStart="4dp"
+        android:paddingTop="1dp"
+        android:scaleType="fitCenter"
+        android:visibility="gone"
+        android:contentDescription="@string/notification_work_profile_content_description"
+        />
 </NotificationHeaderView>
 
diff --git a/core/res/res/layout/notification_template_material_base.xml b/core/res/res/layout/notification_template_material_base.xml
index b69eb24..a37bfa9 100644
--- a/core/res/res/layout/notification_template_material_base.xml
+++ b/core/res/res/layout/notification_template_material_base.xml
@@ -25,16 +25,16 @@
     <LinearLayout
         android:id="@+id/notification_main_column"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_height="wrap_content"
         android:layout_gravity="top"
         android:layout_marginStart="@dimen/notification_content_margin_start"
         android:layout_marginEnd="@dimen/notification_content_margin_end"
         android:layout_marginTop="@dimen/notification_content_margin_top"
-        android:minHeight="@dimen/notification_min_content_height"
+        android:layout_marginBottom="@dimen/notification_content_margin_bottom"
         android:orientation="vertical"
         >
         <include layout="@layout/notification_template_part_line1" />
-        <include layout="@layout/notification_template_part_line3" />
+        <include layout="@layout/notification_template_text" />
     </LinearLayout>
     <FrameLayout
         android:layout_width="match_parent"
@@ -42,7 +42,7 @@
         android:layout_gravity="bottom"
         android:layout_marginStart="@dimen/notification_content_margin_start"
         android:layout_marginBottom="11dp"
-        android:layout_marginEnd="@dimen/notification_content_margin_end">
+        android:layout_marginEnd="@dimen/notification_content_margin_end" >
         <include layout="@layout/notification_template_progress" />
     </FrameLayout>
     <include layout="@layout/notification_template_right_icon" />
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 eb02e8b..f302087 100644
--- a/core/res/res/layout/notification_template_material_big_base.xml
+++ b/core/res/res/layout/notification_template_material_big_base.xml
@@ -25,7 +25,7 @@
     <FrameLayout
         android:id="@+id/status_bar_latest_event_content"
         android:layout_width="match_parent"
-        android:layout_height="@dimen/notification_min_height"
+        android:layout_height="wrap_content"
         android:layout_gravity="top"
         android:tag="base"
         >
@@ -38,11 +38,11 @@
             android:layout_marginStart="@dimen/notification_content_margin_start"
             android:layout_marginEnd="@dimen/notification_content_margin_end"
             android:layout_marginTop="@dimen/notification_content_margin_top"
-            android:minHeight="@dimen/notification_min_content_height"
+            android:layout_marginBottom="@dimen/notification_content_margin_bottom"
             android:orientation="vertical"
             >
             <include layout="@layout/notification_template_part_line1" />
-            <include layout="@layout/notification_template_part_line3" />
+            <include layout="@layout/notification_template_text" />
         </LinearLayout>
         <FrameLayout
             android:layout_width="match_parent"
@@ -55,6 +55,11 @@
         </FrameLayout>
         <include layout="@layout/notification_template_right_icon" />
     </FrameLayout>
+    <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"
         android:layout_width="match_parent"
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 0427c8a..e8ff186 100644
--- a/core/res/res/layout/notification_template_material_big_media.xml
+++ b/core/res/res/layout/notification_template_material_big_media.xml
@@ -33,13 +33,14 @@
         android:layout_height="wrap_content"
         android:layout_marginTop="@dimen/notification_content_margin_top"
         android:layout_marginStart="@dimen/notification_content_margin_start"
+        android:layout_marginBottom="@dimen/notification_content_margin_bottom"
         android:layout_marginEnd="24dp"
         android:layout_toStartOf="@id/right_icon"
         android:minHeight="@dimen/notification_min_content_height"
         android:orientation="vertical"
         >
         <include layout="@layout/notification_template_part_line1" />
-        <include layout="@layout/notification_template_part_line3" />
+        <include layout="@layout/notification_template_text" />
     </LinearLayout>
     <LinearLayout
         android:id="@+id/media_actions"
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 58e3d1b..50aec6b 100644
--- a/core/res/res/layout/notification_template_material_big_picture.xml
+++ b/core/res/res/layout/notification_template_material_big_picture.xml
@@ -40,7 +40,7 @@
             android:orientation="vertical">
             <include layout="@layout/notification_template_part_line1"/>
             <include layout="@layout/notification_template_progress"/>
-            <include layout="@layout/notification_template_part_line3"/>
+            <include layout="@layout/notification_template_text"/>
         </LinearLayout>
         <ImageView
                 android:id="@+id/big_picture"
@@ -52,6 +52,13 @@
                 android:layout_marginBottom="16dp"
                 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>
 </FrameLayout>
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 9e010f2..9a4b28c 100644
--- a/core/res/res/layout/notification_template_material_big_text.xml
+++ b/core/res/res/layout/notification_template_material_big_text.xml
@@ -36,32 +36,24 @@
         >
         <include layout="@layout/notification_template_part_line1" />
         <include layout="@layout/notification_template_progress" />
-        <LinearLayout
+        <com.android.internal.widget.ImageFloatingTextView android:id="@+id/big_text"
             android:layout_width="match_parent"
             android:layout_height="0dp"
-            android:paddingBottom="13dp"
-            android:orientation="horizontal"
-            android:gravity="top"
+            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"
-            >
-            <com.android.internal.widget.ImageFloatingTextView android:id="@+id/big_text"
-                android:textAppearance="@style/TextAppearance.Material.Notification"
-                android:layout_width="0dp"
+            android:gravity="top"
+            android:visibility="gone"
+            />
+        <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_weight="1"
-                android:singleLine="false"
-                android:visibility="gone"
-                />
-            <ImageView android:id="@+id/profile_badge_large_template"
-                android:layout_width="@dimen/notification_badge_size"
-                android:layout_height="@dimen/notification_badge_size"
-                android:layout_weight="0"
-                android:layout_marginStart="4dp"
-                android:scaleType="fitCenter"
-                android:visibility="gone"
-                android:contentDescription="@string/notification_work_profile_content_description"
-                />
-        </LinearLayout>
+                android:layout_marginStart="-16dp"
+                android:layout_marginEnd="-16dp"
+        />
         <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 8c0abc9..86902db 100644
--- a/core/res/res/layout/notification_template_material_inbox.xml
+++ b/core/res/res/layout/notification_template_material_inbox.xml
@@ -41,34 +41,15 @@
             android:layout_width="match_parent"
             android:layout_height="15dp"
             android:layout_marginTop="4dp"/>
-
-        <!-- We can't have another vertical linear layout here with weight != 0 so this forces us to
-             put the badge on the first line. -->
-        <LinearLayout
+        <TextView android:id="@+id/inbox_text0"
+            android:textAppearance="@style/TextAppearance.Material.Notification"
             android:layout_width="match_parent"
-            android:layout_weight="1"
             android:layout_height="0dp"
-            android:orientation="horizontal"
-            >
-            <TextView android:id="@+id/inbox_text0"
-                android:textAppearance="@style/TextAppearance.Material.Notification"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:visibility="gone"
-                android:layout_weight="1"
-                />
-            <ImageView android:id="@+id/profile_badge_large_template"
-                android:layout_width="@dimen/notification_badge_size"
-                android:layout_height="@dimen/notification_badge_size"
-                android:layout_weight="0"
-                android:layout_marginStart="4dp"
-                android:scaleType="fitCenter"
-                android:visibility="gone"
-                android:contentDescription="@string/notification_work_profile_content_description"
-                />
-        </LinearLayout>
+            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"
@@ -123,13 +104,6 @@
             android:visibility="gone"
             android:layout_weight="1"
             />
-        <FrameLayout
-            android:id="@+id/inbox_end_pad"
-            android:layout_width="match_parent"
-            android:layout_height="13dp"
-            android:visibility="gone"
-            android:layout_weight="0"
-        />
         <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 dc4afb8..9fcd356 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -29,7 +29,7 @@
     <LinearLayout
         android:id="@+id/notification_main_column"
         android:layout_width="match_parent"
-        android:layout_height="@dimen/notification_min_content_height"
+        android:layout_height="wrap_content"
         android:background="#00000000"
         android:orientation="horizontal"
         android:layout_marginStart="@dimen/notification_content_margin_start"
@@ -43,11 +43,12 @@
             android:layout_gravity="fill_vertical"
             android:layout_weight="1"
             android:minHeight="@dimen/notification_min_content_height"
+            android:paddingBottom="@dimen/notification_content_margin_bottom"
             android:orientation="vertical"
             >
             <include layout="@layout/notification_template_part_line1"/>
             <include layout="@layout/notification_template_progress"/>
-            <include layout="@layout/notification_template_part_line3"/>
+            <include layout="@layout/notification_template_text"/>
         </LinearLayout>
         <LinearLayout
             android:id="@+id/media_actions"
diff --git a/core/res/res/layout/notification_template_part_line1.xml b/core/res/res/layout/notification_template_part_line1.xml
index e7ac408..308b30f 100644
--- a/core/res/res/layout/notification_template_part_line1.xml
+++ b/core/res/res/layout/notification_template_part_line1.xml
@@ -20,7 +20,6 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:orientation="horizontal"
-    android:layout_marginBottom="1dp"
     >
     <TextView android:id="@+id/title"
         android:textAppearance="@style/TextAppearance.Material.Notification.Title"
diff --git a/core/res/res/layout/notification_template_part_line3.xml b/core/res/res/layout/notification_template_part_line3.xml
deleted file mode 100644
index 76337ac..0000000
--- a/core/res/res/layout/notification_template_part_line3.xml
+++ /dev/null
@@ -1,45 +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
-  -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/line3"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="horizontal"
-    android:gravity="center_vertical"
-    >
-    <TextView android:id="@+id/text"
-        android:textAppearance="@style/TextAppearance.Material.Notification"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:layout_gravity="center"
-        android:singleLine="true"
-        android:ellipsize="marquee"
-        android:fadingEdge="horizontal"
-        />
-    <ImageView android:id="@+id/profile_badge_line3"
-        android:layout_width="@dimen/notification_badge_size"
-        android:layout_height="@dimen/notification_badge_size"
-        android:layout_gravity="center"
-        android:layout_weight="0"
-        android:layout_marginStart="4dp"
-        android:scaleType="fitCenter"
-        android:visibility="gone"
-        android:contentDescription="@string/notification_work_profile_content_description"
-        />
-</LinearLayout>
diff --git a/core/res/res/layout/notification_template_text.xml b/core/res/res/layout/notification_template_text.xml
new file mode 100644
index 0000000..38470cd
--- /dev/null
+++ b/core/res/res/layout/notification_template_text.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
+  -->
+<TextView 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:ellipsize="marquee"
+    android:fadingEdge="horizontal"
+    android:gravity="top"
+    android:singleLine="true"
+    android:textAppearance="@style/TextAppearance.Material.Notification"
+    />
diff --git a/core/res/res/layout/text_drag_thumbnail.xml b/core/res/res/layout/text_drag_thumbnail.xml
index 63d2c05..b1a58cd 100644
--- a/core/res/res/layout/text_drag_thumbnail.xml
+++ b/core/res/res/layout/text_drag_thumbnail.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
 **
 ** Copyright 2010, The Android Open Source Project
 **
diff --git a/core/res/res/layout/text_edit_suggestion_container.xml b/core/res/res/layout/text_edit_suggestion_container.xml
index 04eca8f..fe02d4e 100644
--- a/core/res/res/layout/text_edit_suggestion_container.xml
+++ b/core/res/res/layout/text_edit_suggestion_container.xml
@@ -16,6 +16,8 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
+    android:background="@drawable/text_edit_suggestions_window"
+    android:dropDownSelector="@drawable/list_selector_background"
     android:divider="@null">
     <ListView
         android:id="@+id/suggestionContainer"
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 d0e2467..62e315b4 100644
--- a/core/res/res/layout/text_edit_suggestion_container_material.xml
+++ b/core/res/res/layout/text_edit_suggestion_container_material.xml
@@ -14,17 +14,19 @@
      limitations under the License.
 -->
 
+<!-- Background of the popup window is the same as the one of the floating toolbar.
+     Use floating toolbar background style. -->
 <LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
-    android:divider="?android:attr/dividerHorizontal"
+    android:background="?android:attr/floatingToolbarPopupBackgroundDrawable"
+    android:divider="?android:attr/listDivider"
     android:showDividers="middle" >
     <ListView
         android:id="@+id/suggestionContainer"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:background="@color/white"
         android:paddingTop="8dip"
-        android:paddingBottom="8dip"
+        android:paddingBottom="0dip"
         android:divider="@null" />
     <LinearLayout
         android:layout_width="match_parent"
diff --git a/core/res/res/layout/unlaunchable_app_activity.xml b/core/res/res/layout/unlaunchable_app_activity.xml
new file mode 100644
index 0000000..429d5ed
--- /dev/null
+++ b/core/res/res/layout/unlaunchable_app_activity.xml
@@ -0,0 +1,35 @@
+<?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:padding="@dimen/dialog_padding"
+        android:orientation="vertical">
+        <TextView android:id="@+id/unlaunchable_app_title"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingStart="@dimen/dialog_padding"
+                android:paddingBottom="@dimen/dialog_padding"
+                android:textAppearance="@android:style/TextAppearance.Material.Title" />
+
+        <TextView android:id="@+id/unlaunchable_app_message"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingStart="@dimen/dialog_padding"
+                android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+                android:textColor="?android:attr/textColorSecondary" />
+</LinearLayout>
+
diff --git a/core/res/res/menu/language_selection_list.xml b/core/res/res/menu/language_selection_list.xml
new file mode 100644
index 0000000..63b9627
--- /dev/null
+++ b/core/res/res/menu/language_selection_list.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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+      xmlns:app="http://schemas.android.com/apk/res-auto">
+    <item
+        android:id="@+id/locale_search_menu"
+        android:title="@string/locale_search_menu"
+        app:showAsAction="always"
+        app:actionViewClass="android.widget.SearchView" />
+
+</menu>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 1ac7e98..eae2c44 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Foutverslag"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Neem foutverslag"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Dit sal inligting oor die huidige toestand van jou toestel insamel om as \'n e-posboodskap te stuur. Dit sal \'n tydjie neem vandat die foutverslag begin is totdat dit reg is om gestuur te word; wees asseblief geduldig."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktiewe verslag"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Gebruik dit in die meeste omstandighede. Maak dit vir jou moontlik om die vordering van die verslag na te spoor en meer besonderhede oor die probleem in te voer. Dit sal dalk sommige afdelings weglaat wat minder gebruik word en waarvoor verslagdoening lank duur."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Volle verslag"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Neem skermkiekie vir foutverslag oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes.</item>
+      <item quantity="one">Neem skermkiekie vir foutverslag oor <xliff:g id="NUMBER_0">%d</xliff:g> sekonde.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Stilmodus"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Klank is AF"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Klank is AAN"</string>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"Veiligmodus"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-stelsel"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"Persoonlik"</string>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Sluit persoonlike data soos kredietkaartnommers en wagwoorde in."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Beheer vertoonskermvergroting"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Beheer die vertoonskerm se zoemvlak en posisionering."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Voer gebare uit"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Kan tik, swiep, knyp en ander gebare uitvoer."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"deaktiveer of verander statusbalk"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Laat die program toe om die statusbalk te deaktiveer en stelselikone by te voeg of te verwyder."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"wees die statusbalk"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Laat die program toe om foto\'s en video\'s met die kamera te neem. Hierdie toestemming laat die program toe om die kamera te eniger tyd sonder jou bevestiging te gebruik."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"beheer vibrasie"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Laat die program toe om die vibrator te beheer."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"beheer flitslig"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Laat die program toe om die flitslig te beheer."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"skakel foonnommers direk"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Laat die program toe om telefoonnommers sonder jou tussentrede te bel. Dit kan tot onverwagte heffings of oproepe lei. Let daarop dat dit nie die program toelaat om noodnommers te bel nie. Kwaadwillige programme kan jou geld kos deur oproepe sonder jou bevestiging te maak."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"toegang tot kitsboodskapoproepdiens"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Sny"</string>
     <string name="copy" msgid="2681946229533511987">"Kopieer"</string>
     <string name="paste" msgid="5629880836805036433">"Plak"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Plak as skoonteks"</string>
     <string name="replace" msgid="5781686059063148930">"Vervang..."</string>
     <string name="delete" msgid="6098684844021697789">"Vee uit"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Kopieer URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Kies teks"</string>
+    <string name="undo" msgid="7905788502491742328">"Ontdoen"</string>
+    <string name="redo" msgid="7759464876566803888">"Herdoen"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Tekskeuse"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Voeg by woordeboek"</string>
     <string name="deleteText" msgid="6979668428458199034">"Vee uit"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Deel foutverslag met administrateur?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Jou IT-administrateur het \'n foutverslag versoek om met foutsporing te help"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"AANVAAR"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"WEIER"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Neem tans foutverslag …"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Raak om te kanselleer"</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="9157568568695230830">"Wys invoermetode"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardeware"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Verander muurpapier"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Kennisgewingluisteraar"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Toestandverskaffer"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Kennisgewingassistent"</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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Opgedateer deur jou administrateur"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Deur jou administrateur uitgevee"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Om batterylewe te help verbeter, verminder batterybespaarder jou toestel se werkverrigting en beperk vibrasie, liggingdienste en die meeste agtergronddata. E-pos, boodskappe en ander programme wat op sinkronisering staatmaak, sal dalk nie opdateer tensy jy hulle oopmaak nie.\n\nBatterybespaarder skakel outomaties af wanneer jou toestel besig is om te laai."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Belangrikheid"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Geblokkeer: Moet nooit hierdie kennisgewings wys nie"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Laag: Wys sonder klank aan die onderkant van die kennisgewinglys"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normaal: Wys hierdie kennisgewings sonder klank"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Hoog: Wys aan die bokant van die kennisgewingslys en maak \'n geluid"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Dringend: Verskyn vlugtig op die skerm en maak \'n geluid"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">%1$d minute lank (tot <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">Een minuut lank (tot <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"Dit is belangrik as gevolg van die mense wat betrokke is."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" probeer om \'n nuwe gebruiker by te voeg, maar word tans verbied."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" probeer tans om \'n nuwe gebruiker by te voeg, maar die gebruikerlimiet is bereik."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" probeer tans om \'n nuwe gebruiker by te voeg, maar die rekening "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" bestaan reeds op hierdie toestel. Gaan in elk geval voort?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" probeer tans om \'n nuwe gebruiker vir die rekening "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" by te voeg. Gaan voort?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Taalvoorkeur"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Alle tale"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Soek"</string>
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index d7b08eb..85ef3c5 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"የሳንካ ሪፖርት"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"የሳንካ ሪፖርት ውሰድ"</string>
     <string name="bugreport_message" msgid="398447048750350456">"ይሄ እንደ የኢሜይል መልዕክት አድርጎ የሚልከውን ስለመሣሪያዎ የአሁኑ ሁኔታ መረጃ ይሰበስባል። የሳንካ ሪፖርቱን ከመጀመር ጀምሮ እስኪላክ ድረስ ትንሽ ጊዜ ይወስዳል፤ እባክዎ ይታገሱ።"</string>
+    <string name="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 />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">በ<xliff:g id="NUMBER_1">%d</xliff:g> ሰከንዶች ውስጥ ለሳንካ ሪፖርት ቅጽበታዊ ገጽ ዕይታን በማንሳት ላይ።</item>
+      <item quantity="other">በ<xliff:g id="NUMBER_1">%d</xliff:g> ሰከንዶች ውስጥ ለሳንካ ሪፖርት ቅጽበታዊ ገጽ ዕይታን በማንሳት ላይ።</item>
+    </plurals>
     <string name="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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"የሚያስተማምን ሁነታ"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android ስርዓት"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"የግል"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"መተግበሪያው በካሜራው ፎቶዎችንና ቪዲዮዎችን እንዲያነሳ ይፈቅድለታል። ይህ ፈቃድ መተግበሪያው ካሜራውን በማንኛውም ጊዜ ያላንተ ማረጋገጫ እንዲጠቀም ይፈቅድለታል።"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"ነዛሪ ተቆጣጠር"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"ነዛሪውን ለመቆጣጠር ለመተግበሪያው ይፈቅዳሉ።"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"የብርሃንብልጭታ ተቆጣጠር"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"የብልጭታ ብርሃኑን ለመቆጣጠር ለመተግበሪያው ይፈቅዳሉ።"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"በቀጥታ ስልክ ቁጥሮች ደውል"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"መተግበሪያው ያላንተ ጣልቃ ገብነት የስልክ ቁጥሮች ላይ እንዲደውል ይፈቅድለታል። ይህ ያልተጠበቁ ክፍያዎችን ወይም ጥሪዎችን ሊያስከትል ይችላል። ይህ መተግበሪያው የድንገተኛ ስልክ ቁጥሮችን እንዲደውል እንደማይፈቅድለት ልብ በል። ተንኮል አዘል መተግበሪያዎች ያላንተ ማረጋገጫ ጥሪዎችን በማድረግ ገንዘብ ሊያስወጡህ ይችላሉ።"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"የአይኤምኤስ ጥሪ አገልግሎትን ይደርሳል"</string>
@@ -858,10 +868,13 @@
     <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">"ሰርዝ"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"የሳንካ ሪፖርት ለአስተዳዳሪ ይጋራ?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"የእርስዎ የአይቲ አስተዳዳሪ መላ መፈለግ ላይ እንዲያግዝ የሳንካ ሪፖርት ጠይቀዋል"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ተቀበል"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ውድቅ አድርግ"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"የሳንካ ሪፖርትን በመውሰድ ላይ…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"ለመሰረዝ ይንኩ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"ቁልፍ ሰሌዳ ይቀይሩ"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"ቁልፍ ሰሌዳዎችን ምረጥ"</string>
-    <string name="show_ime" msgid="9157568568695230830">"የግቤት ስልት አሳይ"</string>
-    <string name="hardware" msgid="7517821086888990278">"ሃርድዌር"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"ልጣፍ ለውጥ"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"ማሳወቂያ አዳማጭ"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"የሁኔታ አቅራቢ"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"የማሳወቂያ ረዳት"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"አስፈላጊነት"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"የታገደ፦ እነኝህን ማሳወቂያዎች ፈፅሞ አታሳይ"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"ዝቅተኛ፦ በጸጥታ የማሳወቂያ ዝርዝር የታችኛውን ክፍል አሳይ"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"መደበኛ፦ በጸጥታ እነኝህን ማሳወቂያዎች አሳይ"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"ከፍተኛ፦ የማሳወቂያዎችን ዝርዝር የላይኛውን ክፍል አሳይ እና ድምፅ አሰማ"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"አስቸኳይ፦ ወደ ገጸ ማያው አንሳ እና ድምፅ ቅዳ"</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="other">ለ%1$d ደቂቃዎች (እስከ <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> ድረስ)</item>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"የተለያዩ"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"የእነዚህን ማሳወቂያዎች አስፈላጊነት አዘጋጅተዋል።"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ይሄ በሚሳተፉ ሰዎች ምክንያት አስፈላጊ ነው።"</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" አዲስ ተጠቃሚ ለማከል እየሞከረ ነው፣ ነገር ግን አሁን ላይ ተከልክሏል።"</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" አዲስ ተጠቃሚ ለማከል እየሞከረ ነው፣ ሆኖም ግን የተጠቃሚ ብዛት ገደብ ላይ ተደርሷል።"</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" አዲስ ተጠቃሚ ለማከል እየሞከረ ነው፣ ነገር ግን መለያ "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" አስቀድሞ በዚህ መሣሪያ ላይ አለ። የሆነው ሆኖ ይቀጥል?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ለ"<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" መለያ አዲስ ተጠቃሚ ለማከል እየሞከረ ነው። ይቀጥል?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"የቋንቋ ምርጫ"</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>
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index c18fc4a..bcab357 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -215,6 +215,19 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"تقرير الأخطاء"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"إعداد تقرير بالأخطاء"</string>
     <string name="bugreport_message" msgid="398447048750350456">"سيجمع هذا معلومات حول حالة جهازك الحالي لإرسالها كرسالة إلكترونية، ولكنه سيستغرق وقتًا قليلاً من بدء عرض تقرير بالأخطاء. وحتى يكون جاهزًا للإرسال، الرجاء الانتظار."</string>
+    <string name="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 />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="zero">سيتم التقاط لقطة شاشة لتقرير الخطأ خلال <xliff:g id="NUMBER_1">%d</xliff:g> ثانية.</item>
+      <item quantity="two">سيتم التقاط لقطة شاشة لتقرير الخطأ خلال ثانيتين (<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>
+      <item quantity="one">سيتم التقاط لقطة شاشة لتقرير الخطأ خلال <xliff:g id="NUMBER_0">%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>
@@ -227,6 +240,7 @@
     <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="safeMode" msgid="2788228061547930246">"الوضع الآمن"</string>
     <string name="android_system_label" msgid="6577375335728551336">"‏نظام Android"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"شخصي"</string>
@@ -259,6 +273,8 @@
     <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>
@@ -357,8 +373,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"للسماح للتطبيق بالتقاط صور ومقاطع فيديو من خلال الكاميرا. ويتيح هذا الإذن للتطبيق استخدام الكاميرا في أي وقت وبدون موافقة منك."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"التحكم في الاهتزاز"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"للسماح للتطبيق بالتحكم في الهزّاز."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"التحكم في الضوء الوامض"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"للسماح للتطبيق بالتحكم في الضوء الوامض."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"اتصال مباشر بأرقام الهواتف"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"للسماح للتطبيق بطلب أرقام هاتفية بدون تدخل منك. وقد يؤدي ذلك إلى تحمل رسوم غير متوقعة أو إجراء مكالمات غير متوقعة. ومن الجدير بالذكر أن ذلك لا يتيح للتطبيق الاتصال بأرقام الطوارئ. وقد تؤدي التطبيقات الضارة إلى تحملك تكاليف مالية من خلال إجراء مكالمات بدون موافقة منك."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"الوصول إلى خدمة الاتصال عبر الرسائل الفورية"</string>
@@ -878,10 +892,13 @@
     <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">"حذف"</string>
@@ -1056,10 +1073,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"هل تريد مشاركة تقرير الأخطاء مع المشرف؟"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"طلب مشرف تكنولوجيا المعلومات الحصول على تقرير بالأخطاء للمساعدة في تحري الخلل وإصلاحه"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"قبول"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"رفض"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"جارٍ الحصول على تقرير بالأخطاء…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"المس للإلغاء"</string>
     <string name="select_input_method" msgid="8547250819326693584">"تغيير لوحة المفاتيح"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"اختيار لوحات المفاتيح"</string>
-    <string name="show_ime" msgid="9157568568695230830">"إظهار طريقة الإدخال"</string>
-    <string name="hardware" msgid="7517821086888990278">"أجهزة"</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="fast_scroll_alphabet" msgid="5433275485499039199">" أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
@@ -1135,6 +1158,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"تغيير الخلفية"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"برنامج تلقّي الإشعارات الصوتية"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"موفر الحالة"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"مساعد الإشعار"</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>
@@ -1476,12 +1500,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"الأهمية"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"محظور: عدم عرض هذه الإشعارات مطلقًا"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"منخفض الأهمية: عرض بأسفل قائمة الإشعارات وبدون تنبيه صوتي"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"عادي: عرض هذه الإشعارات بدون تنبيه صوتي"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"عالي الأهمية: عرض بأعلى قائمة الإشعارات مع إصدار تنبيه صوتي"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"عاجل: الظهور سريعًا على الشاشة مع إصدار تنبيه صوتي"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="zero">‏لمدة أقل من دقيقة (%1$d) (حتى <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="two">‏لمدة دقيقتين (%1$d) (حتى <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1585,4 +1603,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"متنوعة"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"لقد عيَّنت أهمية هذه الإشعارات."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"هذه الرسالة مهمة نظرًا لأهمية الأشخاص المعنيين."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315">"هناك محاولة من "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" لإضافة مستخدم جديد لكنه محظور حاليًا."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266">"هناك محاولة من "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" لإضافة مستخدم جديد إلا أنه قد تم الوصول إلى الحد الأقصى للمستخدمين."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789">"هناك محاولة من "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" لإضافة مستخدم جديد إلا أن الحساب "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" موجود مسبقًا على هذا الجهاز، فهل تريد المتابعة على أي حال؟"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392">"هناك محاولة من "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" لإضافة مستخدم جديد إلى الحساب "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>"، فهل تريد المتابعة؟"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"تفضيل اللغة"</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>
 </resources>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 5de0b59..05ce1c0 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Baq hesabatı"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Baqı xəbər verin"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Bu, sizin hazırkı cihaz durumu haqqında məlumat toplayacaq ki, elektron məktub şəklində göndərsin. Baq raportuna başlamaq üçün bir az vaxt lazım ola bilər, bir az səbr edin."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"İnteraktiv hesabat"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Bir çox hallarda bundan istifadə edin. Bu hesabatın gedişatını izləməyə və problem haqqında daha ətraflı məlumat daxil etməyə imkan verir. Bu, çox vaxt tələb edən bəzi az istifadə olunan bölmələri ixtisar edə bilər."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Tam hesabat"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Baq hesabatı üçün <xliff:g id="NUMBER_1">%d</xliff:g> saniyədə sktinşot çəkilir.</item>
+      <item quantity="one">Baq hesabatı üçün <xliff:g id="NUMBER_0">%d</xliff:g> saniyədə skrinşot çəkilir.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Səssiz rejim"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Səs qapalıdır"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Səs Aktivdir"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Kredit kartı nömrələri və parollar kimi şəxsi məlumatlar daxildir."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Ekran böyütməsinə nəzarət edin"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ekran yaxınlaşdırma səviyyəsi və yerləşdirməsinə nəzarət edin."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Jestlər ilə əməliyyat aparın"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Digər jestlərə tıklaya, sürüşdürə və əməliyyat apara bilərsiniz."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"status panelini deaktivləşdir və ya dəyişdir"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Tətbiqə status panelini deaktiv etməyə və ya sistem ikonalarını əlavə etmək və ya silmək imkanı verir."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"status paneli edin"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Tətbiqə kamera ilə şəkil və video çəkməyə imkan yaradır. Bu icazə tətbiqə sizin təsdiqiniz olmadan kameradan istifadə icazəsi verir."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"vibrasiyaya nəzarət edir"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Tətbiqə vibratoru idarə etmə icazəsi verir."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"Flash işığını idarə edir"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Tətbiqə siqnal işığı na nəzarət etməyə imkan verir."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"telefon nömrələrinə birbaşa zəng edir"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Tətbiqə Sizin müdaxiləniz olmadan telefon zəngləri etməyə imkan verir. Zərərli tətbiqlər Sizdən xəbərsiz şəkildə müxtəlif zənglər edərək, Sizə maddi ziyan vura bilər. Qeyd: Bu, tətbiqlərə təcili nömrələrə zəng etməyə icazə vermir."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS zəng xidmətinə giriş"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Kəs"</string>
     <string name="copy" msgid="2681946229533511987">"Kopyala"</string>
     <string name="paste" msgid="5629880836805036433">"Yerləşdir"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Adi mətn kimi köçürün"</string>
     <string name="replace" msgid="5781686059063148930">"Əvəz et..."</string>
     <string name="delete" msgid="6098684844021697789">"Sil"</string>
     <string name="copyUrl" msgid="2538211579596067402">"URL kopyala"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Mətn seçin"</string>
+    <string name="undo" msgid="7905788502491742328">"Ləğv edin"</string>
+    <string name="redo" msgid="7759464876566803888">"Yenidən edin"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Mətn seçimi"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Lüğətə əlavə et"</string>
     <string name="deleteText" msgid="6979668428458199034">"Sil"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Baq hesabatı admin ilə paylaşılsın?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"IT admininiz nasazlıqların aşkarlanması üçün baq hesabatı sorğusu göndərdi"</string>
+    <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="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Baq xəbər verilir..."</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Ləğv etmək üçün toxunun"</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="9157568568695230830">"Daxiletmə metodunu göstərin"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardware"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCÇDEƏFGĞHXIİJKQLMNOÖPRSŞTUÜVYZ"</string>
@@ -1107,6 +1126,7 @@
     <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="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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Sizin administrator tərəfindən yeniləndi"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Administratorunuz tərəfindən silinib"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Batareyanın istismar müddətini təkmilləşdirmək üçün batareya qənaəti cihazınızın məhsuldarlığını azaldır və titrətmə, məkan xidmətləri və ən son fon məlumatlarını məhdudlaşdırır. Sinxronlaşmaya arxayın olan e-poçt, mesajlaşma və digər proqramlar siz onları açmayana kimi yenilənməyə bilər.\n\nCihazınız doldurulan zaman batareya qənaəti avtomatik olaraq sönür."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Əhəmiyyət"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Blok edildi: Bu bildirişləri heç vaxt göstərməyin"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Alçaq: Bildirişlər siyahısının aşağısında səssiz göstərin"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Bu bildişləri səssiz göstərin"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Yüksək: Bildirişlər siyahısında yuxarıda göstərin və səsli edin"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Təcili: Ekranda nəzər salın və səsli edin"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other"> %1$d dəqiqəlik (saat <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> radəsinə qədər)</item>
       <item quantity="one">Bir dəqiqəlik (saat <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> radəsinə qədər)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"İnsanlar cəlb olunduğu üçün bu vacibdir."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" yeni istifadəçi əlavə etməyə çalışır, lakin hal-hazırda qadağandır."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" yeni istifadəçi əlavə etməyə çalışır, lakin istifadəçi limitinə çatılıb."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" yeni istifadəçi əlavə etməyə çalışır, lakin "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" hesabı bu cihazda artıq mövcuddur. Hər bir halda davam edilsin?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" hesabı üçün yeni istifadəçi əlavə etməyə çalışır. Davam edilsin?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Dil seçimi"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Bütün dillər"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Axtarın"</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 8871bbc..7e5106a 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -212,6 +212,16 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Izveštaj o grešci"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Napravi izveštaj o grešci"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Ovim će se prikupiti informacije o trenutnom stanju uređaja kako bi bile poslate u poruci e-pošte. Od započinjanja izveštaja o grešci do trenutka za njegovo slanje proći će neko vreme; budite strpljivi."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktiv. izveštaj"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Koristite ovo u većini slučajeva. To vam omogućava da pratite napredak izveštaja i da unosite dodatne detalje o problemu. Verovatno će izostaviti neke manje korišćene odeljke za koje pravljenje izveštaja dugo traje."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Kompletan izveštaj"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">Napravićemo snimak ekrana radi izveštaja o grešci za <xliff:g id="NUMBER_1">%d</xliff:g> sekundu.</item>
+      <item quantity="few">Napravićemo snimak ekrana radi izveštaja o grešci za <xliff:g id="NUMBER_1">%d</xliff:g> sekunde.</item>
+      <item quantity="other">Napravićemo snimak ekrana radi izveštaja o grešci za <xliff:g id="NUMBER_1">%d</xliff:g> sekundi.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Nečujni režim"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Zvuk je ISKLJUČEN"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Zvuk je UKLJUČEN"</string>
@@ -224,6 +234,7 @@
     <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="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>
@@ -256,6 +267,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Obuhvata lične podatke kao što su brojevi kreditnih kartica i lozinke."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Upravljaj uvećanjem prikaza"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Upravlja nivoom zumiranja prikaza i određivanjem položaja."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Obavljanje pokreta"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Može da dodiruje, lista, skuplja prikaz i obavlja druge pokrete."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"onemogućavanje ili izmena statusne trake"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Dozvoljava aplikaciji da onemogući statusnu traku ili da dodaje i uklanja sistemske ikone."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"funkcionisanje kao statusna traka"</string>
@@ -354,8 +367,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Dozvoljava aplikaciji da snima slike i video snimke kamerom. Ova dozvola omogućava aplikaciji da u bilo kom trenutku koristi kameru bez vaše potvrde."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"kontrola vibracije"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Dozvoljava aplikaciji da kontroliše vibraciju."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"kontrola osvetljenja"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Dozvoljava aplikaciji da kontroliše blic."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"direktno pozivanje brojeva telefona"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Dozvoljava aplikaciji da poziva brojeve telefona bez vaše dozvole. Ovo može da dovede do neočekivanih troškova ili poziva. Imajte na umu da ovo ne dozvoljava aplikaciji da poziva brojeve za hitne slučajeve. Zlonamerne aplikacije mogu da pozivaju bez vaše potvrde, što može da dovede do troškova."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"pristup usluzi poziva pomoću razmene trenutnih poruka"</string>
@@ -863,10 +874,13 @@
     <string name="cut" msgid="3092569408438626261">"Iseci"</string>
     <string name="copy" msgid="2681946229533511987">"Kopiraj"</string>
     <string name="paste" msgid="5629880836805036433">"Nalepi"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Nalepi kao običan tekst"</string>
     <string name="replace" msgid="5781686059063148930">"Zameni..."</string>
     <string name="delete" msgid="6098684844021697789">"Izbriši"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Kopiraj URL adresu"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Izaberi tekst"</string>
+    <string name="undo" msgid="7905788502491742328">"Opozovi"</string>
+    <string name="redo" msgid="7759464876566803888">"Ponovi"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Izbor teksta"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Dodaj u rečnik"</string>
     <string name="deleteText" msgid="6979668428458199034">"Izbriši"</string>
@@ -1035,10 +1049,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Želite li da delite izveštaj o grešci sa administratorom?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"IT administrator je zatražio izveštaj o grešci radi lakšeg rešavanja problema"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"PRIHVATI"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ODBIJ"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Izveštaj o grešci se generiše…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Dodirnite da biste otkazali"</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="9157568568695230830">"Prikazivanje metoda unosa"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardver"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1114,6 +1134,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Promena pozadine"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Monitor obaveštenja"</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="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>
@@ -1449,12 +1470,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Ažurirao je administrator"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Izbrisao je vaš admiistrator"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Da bi produžila vreme trajanja baterije, ušteda baterije smanjuje performanse uređaja i ograničava vibraciju, usluge lokacije i većinu pozadinskih podataka. Imejl, razmena poruka i druge aplikacije koje se oslanjaju na sinhronizaciju možda neće da se ažuriraju ako ih ne otvorite.\n\nUšteda baterije se automatski isključuje kada se uređaj puni."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Važnost"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokirana: Ova obaveštenja se nikada ne prikazuju"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Niska: Prikazuju se u dnu liste obaveštenja bez zvuka"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Uobičajena: Ova obaveštenja se prikazuju bez zvuka"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Visoka: Prikazuju se u vrhu liste obaveštenja i aktivira se zvučni signal"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Hitna: Nakratko se prikazuju na ekranu i aktivira se zvučni signal"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="one">%1$d minut (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="few">%1$d minuta (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1531,4 +1546,14 @@
     <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_person" msgid="9160133597262938296">"Ovo je važno zbog ljudi koji učestvuju."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" pokušava da doda novog korisnika, ali to je trenutno zabranjeno."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" pokušava da doda novog korisnika, ali je ograničenje za broj korisnika dostignuto."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" pokušava da doda novog korisnika, ali nalog "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" već postoji na ovom uređaju. Želite li ipak da nastavite?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" pokušava da doda novog korisnika za nalog "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Želite li da nastavite?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Podešavanje jezika"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Svi jezici"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Pretraži"</string>
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index fc0317a..297d50b 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Сигнал за програмна грешка"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Сигнал за програмна грешка"</string>
     <string name="bugreport_message" msgid="398447048750350456">"По този начин ще се събере информация за текущото състояние на устройството ви, която да се изпрати като имейл съобщение. След стартирането на процеса ще мине известно време, докато сигналът за програмна грешка бъде готов за подаване. Моля, имайте търпение."</string>
+    <string name="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 />
+    <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>
+    </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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"Безопасен режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Системно от Android"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"Личен"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Разрешава на приложението да прави снимки и видеоклипове с камерата. Това разрешение му позволява да я използва по всяко време без потвърждение от ваша страна."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"контролиране на вибрирането"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Разрешава на приложението да контролира устройството за вибрация."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"контролиране на фенерчето"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Разрешава на приложението да контролира фенерчето."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"директно обаждане до телефонни номера"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Разрешава на приложението да се обажда без ваша намеса до телефонни номера, което може да доведе до неочаквано таксуване или обаждания. Обърнете внимание, че това не му позволява да извършва обаждания до спешните служби. Злонамерените приложения могат да ви въвлекат в разходи, като извършват обаждания без потвърждение от ваша страна."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"достъп до услугата за незабавни съобщения за обаждания"</string>
@@ -858,10 +868,13 @@
     <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">"Изтриване"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Да се сподели ли сигналът за програмна грешка с администратора?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Системният ви администратор заяви сигнал за програмна грешка с цел отстраняване на неизправностите"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ПРИЕМАМ"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ОТХВЪРЛЯМ"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Сигналът за програмна грешка се извлича…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Докоснете, за да анулирате"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Промяна на клавиатурата"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"Избиране на клавиатури"</string>
-    <string name="show_ime" msgid="9157568568695230830">"Метод на въвежд.: Показв."</string>
-    <string name="hardware" msgid="7517821086888990278">"Хардуер"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Промяна на тапета"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Слушател на известия"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Доставчик на условия"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Помощник за известия"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"Важност"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Блокирано: Тези известия никога да не се показват"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Маловажно: Показване без звуков сигнал в долната част на списъка с известия"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Нормално: Тези известия да се показват без звуков сигнал"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Важно: Показване в горната част на списъка с известия и издаване на звуков сигнал"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Спешно: Показване на екрана и издаване на звуков сигнал"</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">За една минута (до <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"Други"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"Зададохте важността на тези известия."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Това е важно заради участващите хора."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" опитва да добави нов потребител, но понастоящем това е забранено."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" опитва да добави нов потребител, но ограничението за брой потребители е достигнато."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" опитва да добави нов потребител, но профилът "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" вече съществува на устройството. Да се продължи ли въпреки това?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" опитва да добави нов потребител за профила "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Да се продължи ли?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Езиково предпочитание"</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>
 </resources>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index de10c61..b9a1cd8 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"ত্রুটির প্রতিবেদন"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"ত্রুটির প্রতিবেদন করুন"</string>
     <string name="bugreport_message" msgid="398447048750350456">"এটি একটি ই-মেল বার্তা পাঠানোর জন্য আপনার ডিভাইসের বর্তমান অবস্থা সম্পর্কে তথ্য সংগ্রহ করবে৷ ত্রুটির প্রতিবেদন শুরুর সময় থেকে এটি পাঠানোর জন্য প্রস্তুত হতে কিছুটা সময় নেবে; দয়া করে ধৈর্য রাখুন৷"</string>
+    <string name="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 />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one"><xliff:g id="NUMBER_1">%d</xliff:g> সেকেন্ডের মধ্যে ত্রুটির প্রতিবেদনের জন্য স্ক্রীনশট নেওয়া হচ্ছে৷</item>
+      <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> সেকেন্ডের মধ্যে ত্রুটির প্রতিবেদনের জন্য স্ক্রীনশট নেওয়া হচ্ছে৷</item>
+    </plurals>
     <string name="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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"নিরাপদ মোড"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android সিস্টেম"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"ব্যক্তিগত"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ক্যামেরার সাহায্যে ছবি তুলতে ও ভিডিও তৈরি করতে অ্যাপ্লিকেশানটিকে মঞ্জুর করে৷ এই অনুমতিটি অ্যাপ্লিকেশানটিকে আপনার নিশ্চয়তা ছাড়াই যেকোনো সময় ক্যামেরা ব্যবহার করতে মঞ্জুর করে৷"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"কম্পন নিয়ন্ত্রণ করুন"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"অ্যাপ্লিকেশানকে কম্পক নিয়ন্ত্রণ করতে দেয়৷"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ফ্ল্যাশলাইট নিয়ন্ত্রণ করে"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"অ্যাপ্লিকেশানকে টর্চলাইট নিয়ন্ত্রণ করতে দেয়৷"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"সরাসরি ফোন নম্বরগুলিতে কল করে"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"অ্যাপ্লিকেশানটিকে আপনার হস্তক্ষেপ ছাড়াই ফোন নম্বরগুলিতে কল করতে মঞ্জুর করে৷ এটি অপ্রত্যাশিত পরিমাণ খরচা বা কলের কারণ হতে পারে৷ মনে রাখবেন, এটি অ্যাপ্লিকেশানটির দ্বারা জরুরি নম্বরগুলিতে কল করাকে অনুমতি দেয় না৷ ক্ষতিকারক অ্যাপ্লিকেশানগুলি আপনার সম্মতি ছাড়াই কল করার ফলে আপনাকে অহেতুক অর্থ প্রদান করতে হতে পারে৷"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS পরিষেবাতে অ্যাক্সেস"</string>
@@ -858,10 +868,13 @@
     <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">"মুছুন"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"প্রশাসকের সাথে ত্রুটির প্রতিবেদন ভাগ করবেন?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"আপনার IT প্রশাসক সমস্যা নিবারণে সহায়তা করতে একটি ত্রুটির প্রতিবেদন চেয়েছেন"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"স্বীকার করুন"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"অস্বীকার করুন"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"ত্রুটির প্রতিবেদন নেওয়া হচ্ছে..."</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"বাতিল করতে স্পর্শ করুন"</string>
     <string name="select_input_method" msgid="8547250819326693584">"কীবোর্ড পরিবর্তন করুন"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"কীবোর্ড চয়ন করুন"</string>
-    <string name="show_ime" msgid="9157568568695230830">"ইনপুট পদ্ধতি দেখান"</string>
-    <string name="hardware" msgid="7517821086888990278">"হার্ডওয়্যার"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"ওয়ালপেপার পরিবর্তন করুন"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"বিজ্ঞপ্তির শ্রোতা"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"শর্ত প্রদানকারী"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"বিজ্ঞপ্তি সহায়ক"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"গুরুত্ব"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"অবরুদ্ধ: এই বিজ্ঞপ্তিগুলি কখনই দেখানো হবে না"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"নিম্ন: বিজ্ঞপ্তি তালিকার নীচের অংশে নিঃশব্দে প্রদর্শন করা হয়"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"সাধারন: এই বিজ্ঞপ্তিগুলি নিঃশব্দে প্রদর্শন করা হয়"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"উচ্চ: বিজ্ঞপ্তি তালিকার শীর্ষে দেখানো হয় এবং শব্দ করে"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"জরুরী: স্ক্রীনের উপরে প্রদর্শিত হয় এবং শব্দ করে"</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="other">%1$d মিনিটের জন্য (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> পর্যন্ত)</item>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"বিবিধ"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"আপনি এই বিজ্ঞপ্তিগুলির গুরুত্ব সেট করেছেন।"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"লোকজন জড়িত থাকার কারণে এটি গুরুত্বপূর্ণ।"</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" একজন নতুন ব্যবহারকারীকে যোগ করার চেষ্টা করছে, তবে বর্তমানে তা নিষিদ্ধ।"</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" একজন নতুন ব্যবহারকারী যোগ করার চেষ্টা করছে, তবে ব্যবহারকারীর সীমা অতিক্রান্ত হয়েছে।"</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" একজন নতুন ব্যবহারকারীকে যোগ করার চেষ্টা করছে, তবে "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" অ্যাকাউন্ট আগে থেকেই এই ডিভাইসটিতে বিদ্যমান আছে। তবুও এগোতে চান?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" অ্যাকাউন্টের জন্য একজন নতুন ব্যবহারকারীকে যোগ করার চেষ্টা করছে। এগোতে চান?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"পছন্দের ভাষা"</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>
 </resources>
diff --git a/core/res/res/values-bs-rBA/strings.xml b/core/res/res/values-bs-rBA/strings.xml
new file mode 100644
index 0000000..6a5ef12
--- /dev/null
+++ b/core/res/res/values-bs-rBA/strings.xml
@@ -0,0 +1,2858 @@
+<?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">
+    <!-- no translation found for byteShort (8340973892742019101) -->
+    <skip />
+    <!-- no translation found for kilobyteShort (5973789783504771878) -->
+    <skip />
+    <!-- no translation found for megabyteShort (6355851576770428922) -->
+    <skip />
+    <!-- no translation found for gigabyteShort (3259882455212193214) -->
+    <skip />
+    <!-- no translation found for terabyteShort (231613018159186962) -->
+    <skip />
+    <!-- no translation found for petabyteShort (5637816680144990219) -->
+    <skip />
+    <!-- no translation found for fileSizeSuffix (8897567456150907538) -->
+    <skip />
+    <!-- no translation found for durationDays (6652371460511178259) -->
+    <skip />
+    <!-- no translation found for durationDayHours (2713107458736744435) -->
+    <skip />
+    <!-- no translation found for durationDayHour (7293789639090958917) -->
+    <skip />
+    <!-- no translation found for durationHours (4266858287167358988) -->
+    <skip />
+    <!-- no translation found for durationHourMinutes (9029176248692041549) -->
+    <skip />
+    <!-- no translation found for durationHourMinute (2741677355177402539) -->
+    <skip />
+    <!-- no translation found for durationMinutes (3134226679883579347) -->
+    <skip />
+    <!-- no translation found for durationMinute (7155301744174623818) -->
+    <skip />
+    <!-- no translation found for durationMinuteSeconds (1424656185379003751) -->
+    <skip />
+    <!-- no translation found for durationMinuteSecond (3989228718067466680) -->
+    <skip />
+    <!-- no translation found for durationSeconds (8050088505238241405) -->
+    <skip />
+    <!-- no translation found for durationSecond (985669622276420331) -->
+    <skip />
+    <!-- no translation found for untitled (4638956954852782576) -->
+    <skip />
+    <!-- no translation found for emptyPhoneNumber (7694063042079676517) -->
+    <skip />
+    <!-- no translation found for unknownName (6867811765370350269) -->
+    <skip />
+    <!-- no translation found for defaultVoiceMailAlphaTag (2660020990097733077) -->
+    <skip />
+    <!-- no translation found for defaultMsisdnAlphaTag (2850889754919584674) -->
+    <skip />
+    <!-- no translation found for mmiError (5154499457739052907) -->
+    <skip />
+    <!-- no translation found for mmiFdnError (5224398216385316471) -->
+    <skip />
+    <!-- no translation found for serviceEnabled (8147278346414714315) -->
+    <skip />
+    <!-- no translation found for serviceEnabledFor (6856228140453471041) -->
+    <skip />
+    <!-- no translation found for serviceDisabled (1937553226592516411) -->
+    <skip />
+    <!-- no translation found for serviceRegistered (6275019082598102493) -->
+    <skip />
+    <!-- no translation found for serviceErased (1288584695297200972) -->
+    <skip />
+    <!-- no translation found for passwordIncorrect (7612208839450128715) -->
+    <skip />
+    <!-- no translation found for mmiComplete (8232527495411698359) -->
+    <skip />
+    <!-- no translation found for badPin (9015277645546710014) -->
+    <skip />
+    <!-- no translation found for badPuk (5487257647081132201) -->
+    <skip />
+    <!-- no translation found for mismatchPin (609379054496863419) -->
+    <skip />
+    <!-- no translation found for invalidPin (3850018445187475377) -->
+    <skip />
+    <!-- no translation found for invalidPuk (8761456210898036513) -->
+    <skip />
+    <!-- no translation found for needPuk (919668385956251611) -->
+    <skip />
+    <!-- no translation found for needPuk2 (4526033371987193070) -->
+    <skip />
+    <!-- no translation found for enablePin (209412020907207950) -->
+    <skip />
+    <!-- no translation found for pinpuk_attempts (1251012001539225582) -->
+    <!-- no translation found for imei (2625429890869005782) -->
+    <skip />
+    <!-- no translation found for meid (4841221237681254195) -->
+    <skip />
+    <!-- no translation found for ClipMmi (6952821216480289285) -->
+    <skip />
+    <!-- no translation found for ClirMmi (7784673673446833091) -->
+    <skip />
+    <!-- no translation found for ColpMmi (3065121483740183974) -->
+    <skip />
+    <!-- no translation found for ColrMmi (4996540314421889589) -->
+    <skip />
+    <!-- no translation found for CfMmi (5123218989141573515) -->
+    <skip />
+    <!-- no translation found for CwMmi (9129678056795016867) -->
+    <skip />
+    <!-- no translation found for BaMmi (455193067926770581) -->
+    <skip />
+    <!-- no translation found for PwdMmi (7043715687905254199) -->
+    <skip />
+    <!-- no translation found for PinMmi (3113117780361190304) -->
+    <skip />
+    <!-- no translation found for CnipMmi (3110534680557857162) -->
+    <skip />
+    <!-- no translation found for CnirMmi (3062102121430548731) -->
+    <skip />
+    <!-- no translation found for ThreeWCMmi (9051047170321190368) -->
+    <skip />
+    <!-- no translation found for RuacMmi (7827887459138308886) -->
+    <skip />
+    <!-- no translation found for CndMmi (3116446237081575808) -->
+    <skip />
+    <!-- no translation found for DndMmi (1265478932418334331) -->
+    <skip />
+    <!-- no translation found for CLIRDefaultOnNextCallOn (429415409145781923) -->
+    <skip />
+    <!-- no translation found for CLIRDefaultOnNextCallOff (3092918006077864624) -->
+    <skip />
+    <!-- no translation found for CLIRDefaultOffNextCallOn (6179425182856418465) -->
+    <skip />
+    <!-- no translation found for CLIRDefaultOffNextCallOff (2567998633124408552) -->
+    <skip />
+    <!-- no translation found for serviceNotProvisioned (8614830180508686666) -->
+    <skip />
+    <!-- no translation found for CLIRPermanent (3377371145926835671) -->
+    <skip />
+    <!-- no translation found for RestrictedChangedTitle (5592189398956187498) -->
+    <skip />
+    <!-- no translation found for RestrictedOnData (8653794784690065540) -->
+    <skip />
+    <!-- no translation found for RestrictedOnEmergency (6581163779072833665) -->
+    <skip />
+    <!-- no translation found for RestrictedOnNormal (4953867011389750673) -->
+    <skip />
+    <!-- no translation found for RestrictedOnAllVoice (3396963652108151260) -->
+    <skip />
+    <!-- no translation found for RestrictedOnSms (8314352327461638897) -->
+    <skip />
+    <!-- no translation found for RestrictedOnVoiceData (996636487106171320) -->
+    <skip />
+    <!-- no translation found for RestrictedOnVoiceSms (1888588152792023873) -->
+    <skip />
+    <!-- no translation found for RestrictedOnAll (5643028264466092821) -->
+    <skip />
+    <!-- no translation found for peerTtyModeFull (6165351790010341421) -->
+    <skip />
+    <!-- no translation found for peerTtyModeHco (5728602160669216784) -->
+    <skip />
+    <!-- no translation found for peerTtyModeVco (1742404978686538049) -->
+    <skip />
+    <!-- no translation found for peerTtyModeOff (3280819717850602205) -->
+    <skip />
+    <!-- no translation found for serviceClassVoice (1258393812335258019) -->
+    <skip />
+    <!-- no translation found for serviceClassData (872456782077937893) -->
+    <skip />
+    <!-- no translation found for serviceClassFAX (5566624998840486475) -->
+    <skip />
+    <!-- no translation found for serviceClassSMS (2015460373701527489) -->
+    <skip />
+    <!-- no translation found for serviceClassDataAsync (4523454783498551468) -->
+    <skip />
+    <!-- no translation found for serviceClassDataSync (7530000519646054776) -->
+    <skip />
+    <!-- no translation found for serviceClassPacket (6991006557993423453) -->
+    <skip />
+    <!-- no translation found for serviceClassPAD (3235259085648271037) -->
+    <skip />
+    <!-- no translation found for roamingText0 (7170335472198694945) -->
+    <skip />
+    <!-- no translation found for roamingText1 (5314861519752538922) -->
+    <skip />
+    <!-- no translation found for roamingText2 (8969929049081268115) -->
+    <skip />
+    <!-- no translation found for roamingText3 (5148255027043943317) -->
+    <skip />
+    <!-- no translation found for roamingText4 (8808456682550796530) -->
+    <skip />
+    <!-- no translation found for roamingText5 (7604063252850354350) -->
+    <skip />
+    <!-- no translation found for roamingText6 (2059440825782871513) -->
+    <skip />
+    <!-- no translation found for roamingText7 (7112078724097233605) -->
+    <skip />
+    <!-- no translation found for roamingText8 (5989569778604089291) -->
+    <skip />
+    <!-- no translation found for roamingText9 (7969296811355152491) -->
+    <skip />
+    <!-- no translation found for roamingText10 (3992906999815316417) -->
+    <skip />
+    <!-- no translation found for roamingText11 (4154476854426920970) -->
+    <skip />
+    <!-- no translation found for roamingText12 (1189071119992726320) -->
+    <skip />
+    <!-- no translation found for roamingTextSearching (8360141885972279963) -->
+    <skip />
+    <!-- no translation found for wfcRegErrorTitle (2301376280632110664) -->
+    <skip />
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+  </string-array>
+    <!-- no translation found for wfcSpnFormat (8211621332478306568) -->
+    <skip />
+    <!-- no translation found for wfcDataSpnFormat (1118052028767666883) -->
+    <skip />
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
+    <!-- no translation found for cfTemplateNotForwarded (1683685883841272560) -->
+    <skip />
+    <!-- no translation found for cfTemplateForwarded (1302922117498590521) -->
+    <skip />
+    <!-- no translation found for cfTemplateForwardedTime (9206251736527085256) -->
+    <skip />
+    <!-- no translation found for cfTemplateRegistered (5073237827620166285) -->
+    <skip />
+    <!-- no translation found for cfTemplateRegisteredTime (6781621964320635172) -->
+    <skip />
+    <!-- no translation found for fcComplete (3118848230966886575) -->
+    <skip />
+    <!-- no translation found for fcError (3327560126588500777) -->
+    <skip />
+    <!-- no translation found for httpErrorOk (1191919378083472204) -->
+    <skip />
+    <!-- no translation found for httpError (7956392511146698522) -->
+    <skip />
+    <!-- no translation found for httpErrorLookup (4711687456111963163) -->
+    <skip />
+    <!-- no translation found for httpErrorUnsupportedAuthScheme (6299980280442076799) -->
+    <skip />
+    <!-- no translation found for httpErrorAuth (1435065629438044534) -->
+    <skip />
+    <!-- no translation found for httpErrorProxyAuth (1788207010559081331) -->
+    <skip />
+    <!-- no translation found for httpErrorConnect (8714273236364640549) -->
+    <skip />
+    <!-- no translation found for httpErrorIO (2340558197489302188) -->
+    <skip />
+    <!-- no translation found for httpErrorTimeout (4743403703762883954) -->
+    <skip />
+    <!-- no translation found for httpErrorRedirectLoop (8679596090392779516) -->
+    <skip />
+    <!-- no translation found for httpErrorUnsupportedScheme (5015730812906192208) -->
+    <skip />
+    <!-- no translation found for httpErrorFailedSslHandshake (96549606000658641) -->
+    <skip />
+    <!-- no translation found for httpErrorBadUrl (3636929722728881972) -->
+    <skip />
+    <!-- no translation found for httpErrorFile (2170788515052558676) -->
+    <skip />
+    <!-- no translation found for httpErrorFileNotFound (6203856612042655084) -->
+    <skip />
+    <!-- no translation found for httpErrorTooManyRequests (1235396927087188253) -->
+    <skip />
+    <!-- no translation found for notification_title (8967710025036163822) -->
+    <skip />
+    <!-- no translation found for contentServiceSync (8353523060269335667) -->
+    <skip />
+    <!-- no translation found for contentServiceSyncNotificationTitle (397743349191901458) -->
+    <skip />
+    <!-- no translation found for contentServiceTooManyDeletesNotificationDesc (8100981435080696431) -->
+    <skip />
+    <!-- no translation found for low_memory (6494019234102154896) -->
+    <skip />
+    <!-- no translation found for low_memory (4415914910770005166) -->
+    <skip />
+    <!-- no translation found for low_memory (516619861191025923) -->
+    <skip />
+    <!-- no translation found for low_memory (3475999286680000541) -->
+    <skip />
+    <!-- no translation found for ssl_ca_cert_warning (5848402127455021714) -->
+    <skip />
+    <!-- no translation found for ssl_ca_cert_noti_by_unknown (4475437862189850602) -->
+    <skip />
+    <!-- no translation found for ssl_ca_cert_noti_by_administrator (550758088185764312) -->
+    <skip />
+    <!-- no translation found for ssl_ca_cert_noti_managed (4030263497686867141) -->
+    <skip />
+    <!-- no translation found for work_profile_deleted (5005572078641980632) -->
+    <skip />
+    <!-- no translation found for work_profile_deleted_description (6305147513054341102) -->
+    <skip />
+    <!-- no translation found for work_profile_deleted_details (226615743462361248) -->
+    <skip />
+    <!-- no translation found for work_profile_deleted_description_dpm_wipe (6019770344820507579) -->
+    <skip />
+    <!-- no translation found for factory_reset_warning (5423253125642394387) -->
+    <skip />
+    <!-- no translation found for factory_reset_message (4905025204141900666) -->
+    <skip />
+    <!-- no translation found for me (6545696007631404292) -->
+    <skip />
+    <!-- no translation found for power_dialog (8545351420865202853) -->
+    <skip />
+    <!-- no translation found for power_dialog (6153888706430556356) -->
+    <skip />
+    <!-- no translation found for power_dialog (1319919075463988638) -->
+    <skip />
+    <!-- no translation found for silent_mode (7167703389802618663) -->
+    <skip />
+    <!-- no translation found for turn_on_radio (3912793092339962371) -->
+    <skip />
+    <!-- no translation found for turn_off_radio (8198784949987062346) -->
+    <skip />
+    <!-- no translation found for screen_lock (799094655496098153) -->
+    <skip />
+    <!-- no translation found for power_off (4266614107412865048) -->
+    <skip />
+    <!-- no translation found for silent_mode_silent (319298163018473078) -->
+    <skip />
+    <!-- no translation found for silent_mode_vibrate (7072043388581551395) -->
+    <skip />
+    <!-- no translation found for silent_mode_ring (8592241816194074353) -->
+    <skip />
+    <!-- no translation found for reboot_to_update_title (6212636802536823850) -->
+    <skip />
+    <!-- no translation found for reboot_to_update_prepare (6305853831955310890) -->
+    <skip />
+    <!-- no translation found for reboot_to_update_package (3871302324500927291) -->
+    <skip />
+    <!-- no translation found for reboot_to_update_reboot (6428441000951565185) -->
+    <skip />
+    <!-- no translation found for reboot_to_reset_title (4142355915340627490) -->
+    <skip />
+    <!-- no translation found for reboot_to_reset_message (2432077491101416345) -->
+    <skip />
+    <!-- no translation found for shutdown_progress (2281079257329981203) -->
+    <skip />
+    <!-- no translation found for shutdown_confirm (3385745179555731470) -->
+    <skip />
+    <!-- no translation found for shutdown_confirm (476672373995075359) -->
+    <skip />
+    <!-- no translation found for shutdown_confirm (3490275567476369184) -->
+    <skip />
+    <!-- no translation found for shutdown_confirm (649792175242821353) -->
+    <skip />
+    <!-- no translation found for shutdown_confirm_question (2906544768881136183) -->
+    <skip />
+    <!-- no translation found for reboot_safemode_title (7054509914500140361) -->
+    <skip />
+    <!-- no translation found for reboot_safemode_confirm (55293944502784668) -->
+    <skip />
+    <!-- no translation found for recent_tasks_title (3691764623638127888) -->
+    <skip />
+    <!-- no translation found for no_recent_tasks (8794906658732193473) -->
+    <skip />
+    <!-- no translation found for global_actions (408477140088053665) -->
+    <skip />
+    <!-- no translation found for global_actions (7240386462508182976) -->
+    <skip />
+    <!-- no translation found for global_actions (2406416831541615258) -->
+    <skip />
+    <!-- no translation found for global_action_lock (2844945191792119712) -->
+    <skip />
+    <!-- no translation found for global_action_power_off (4471879440839879722) -->
+    <skip />
+    <!-- no translation found for global_action_bug_report (7934010578922304799) -->
+    <skip />
+    <!-- no translation found for bugreport_title (2667494803742548533) -->
+    <skip />
+    <!-- no translation found for bugreport_message (398447048750350456) -->
+    <skip />
+    <!-- no translation found for bugreport_option_interactive_title (8635056131768862479) -->
+    <skip />
+    <!-- no translation found for bugreport_option_interactive_summary (8180152634022797629) -->
+    <skip />
+    <!-- no translation found for bugreport_option_full_title (6354382025840076439) -->
+    <skip />
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <!-- no translation found for bugreport_countdown (6878900193900090368) -->
+    <!-- no translation found for global_action_toggle_silent_mode (8219525344246810925) -->
+    <skip />
+    <!-- no translation found for global_action_silent_mode_on_status (3289841937003758806) -->
+    <skip />
+    <!-- no translation found for global_action_silent_mode_off_status (1506046579177066419) -->
+    <skip />
+    <!-- no translation found for global_actions_toggle_airplane_mode (5884330306926307456) -->
+    <skip />
+    <!-- no translation found for global_actions_airplane_mode_on_status (2719557982608919750) -->
+    <skip />
+    <!-- no translation found for global_actions_airplane_mode_off_status (5075070442854490296) -->
+    <skip />
+    <!-- no translation found for global_action_settings (1756531602592545966) -->
+    <skip />
+    <!-- no translation found for global_action_assist (3892832961594295030) -->
+    <skip />
+    <!-- no translation found for global_action_voice_assist (7751191495200504480) -->
+    <skip />
+    <!-- no translation found for global_action_lockdown (8751542514724332873) -->
+    <skip />
+    <!-- no translation found for status_bar_notification_info_overflow (5301981741705354993) -->
+    <skip />
+    <!-- no translation found for notification_children_count_bracketed (1769425473168347839) -->
+    <skip />
+    <!-- no translation found for notification_hidden_text (1135169301897151909) -->
+    <skip />
+    <!-- no translation found for safeMode (2788228061547930246) -->
+    <skip />
+    <!-- no translation found for android_system_label (6577375335728551336) -->
+    <skip />
+    <!-- no translation found for user_owner_label (2804351898001038951) -->
+    <skip />
+    <!-- no translation found for managed_profile_label (6260850669674791528) -->
+    <skip />
+    <!-- no translation found for permgrouplab_contacts (3657758145679177612) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_contacts (6951499528303668046) -->
+    <skip />
+    <!-- no translation found for permgrouplab_location (7275582855722310164) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_location (1346617465127855033) -->
+    <skip />
+    <!-- no translation found for permgrouplab_calendar (5863508437783683902) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_calendar (3889615280211184106) -->
+    <skip />
+    <!-- no translation found for permgrouplab_sms (228308803364967808) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_sms (4656988620100940350) -->
+    <skip />
+    <!-- no translation found for permgrouplab_storage (1971118770546336966) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_storage (637758554581589203) -->
+    <skip />
+    <!-- no translation found for permgrouplab_microphone (171539900250043464) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_microphone (4988812113943554584) -->
+    <skip />
+    <!-- no translation found for permgrouplab_camera (4820372495894586615) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_camera (3250611594678347720) -->
+    <skip />
+    <!-- no translation found for permgrouplab_phone (5229115638567440675) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_phone (6234224354060641055) -->
+    <skip />
+    <!-- no translation found for permgrouplab_sensors (416037179223226722) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_sensors (7147968539346634043) -->
+    <skip />
+    <!-- no translation found for capability_title_canRetrieveWindowContent (3901717936930170320) -->
+    <skip />
+    <!-- no translation found for capability_desc_canRetrieveWindowContent (3772225008605310672) -->
+    <skip />
+    <!-- no translation found for capability_title_canRequestTouchExploration (3108723364676667320) -->
+    <skip />
+    <!-- no translation found for capability_desc_canRequestTouchExploration (5800552516779249356) -->
+    <skip />
+    <!-- no translation found for capability_title_canRequestEnhancedWebAccessibility (1739881766522594073) -->
+    <skip />
+    <!-- no translation found for capability_desc_canRequestEnhancedWebAccessibility (7881063961507511765) -->
+    <skip />
+    <!-- no translation found for capability_title_canRequestFilterKeyEvents (2103440391902412174) -->
+    <skip />
+    <!-- no translation found for capability_desc_canRequestFilterKeyEvents (7463135292204152818) -->
+    <skip />
+    <!-- no translation found for capability_title_canControlMagnification (3593493281059424855) -->
+    <skip />
+    <!-- no translation found for capability_desc_canControlMagnification (4791858203568383773) -->
+    <skip />
+    <!-- no translation found for capability_title_canPerformGestures (7418984730362576862) -->
+    <skip />
+    <!-- no translation found for capability_desc_canPerformGestures (8296373021636981249) -->
+    <skip />
+    <!-- no translation found for permlab_statusBar (7417192629601890791) -->
+    <skip />
+    <!-- no translation found for permdesc_statusBar (8434669549504290975) -->
+    <skip />
+    <!-- no translation found for permlab_statusBarService (4826835508226139688) -->
+    <skip />
+    <!-- no translation found for permdesc_statusBarService (716113660795976060) -->
+    <skip />
+    <!-- no translation found for permlab_expandStatusBar (1148198785937489264) -->
+    <skip />
+    <!-- no translation found for permdesc_expandStatusBar (6917549437129401132) -->
+    <skip />
+    <!-- no translation found for permlab_install_shortcut (4279070216371564234) -->
+    <skip />
+    <!-- no translation found for permdesc_install_shortcut (8341295916286736996) -->
+    <skip />
+    <!-- no translation found for permlab_uninstall_shortcut (4729634524044003699) -->
+    <skip />
+    <!-- no translation found for permdesc_uninstall_shortcut (6745743474265057975) -->
+    <skip />
+    <!-- no translation found for permlab_processOutgoingCalls (3906007831192990946) -->
+    <skip />
+    <!-- no translation found for permdesc_processOutgoingCalls (5156385005547315876) -->
+    <skip />
+    <!-- no translation found for permlab_receiveSms (8673471768947895082) -->
+    <skip />
+    <!-- no translation found for permdesc_receiveSms (6424387754228766939) -->
+    <skip />
+    <!-- no translation found for permlab_receiveMms (1821317344668257098) -->
+    <skip />
+    <!-- no translation found for permdesc_receiveMms (533019437263212260) -->
+    <skip />
+    <!-- no translation found for permlab_readCellBroadcasts (1598328843619646166) -->
+    <skip />
+    <!-- no translation found for permdesc_readCellBroadcasts (6361972776080458979) -->
+    <skip />
+    <!-- no translation found for permlab_subscribedFeedsRead (4756609637053353318) -->
+    <skip />
+    <!-- no translation found for permdesc_subscribedFeedsRead (5557058907906144505) -->
+    <skip />
+    <!-- no translation found for permlab_sendSms (7544599214260982981) -->
+    <skip />
+    <!-- no translation found for permdesc_sendSms (7094729298204937667) -->
+    <skip />
+    <!-- no translation found for permlab_readSms (8745086572213270480) -->
+    <skip />
+    <!-- no translation found for permdesc_readSms (2467981548684735522) -->
+    <skip />
+    <!-- no translation found for permdesc_readSms (5102425513647038535) -->
+    <skip />
+    <!-- no translation found for permdesc_readSms (3695967533457240550) -->
+    <skip />
+    <!-- no translation found for permlab_receiveWapPush (5991398711936590410) -->
+    <skip />
+    <!-- no translation found for permdesc_receiveWapPush (748232190220583385) -->
+    <skip />
+    <!-- no translation found for permlab_getTasks (6466095396623933906) -->
+    <skip />
+    <!-- no translation found for permdesc_getTasks (7454215995847658102) -->
+    <skip />
+    <!-- no translation found for permlab_manageProfileAndDeviceOwners (7918181259098220004) -->
+    <skip />
+    <!-- no translation found for permdesc_manageProfileAndDeviceOwners (106894851498657169) -->
+    <skip />
+    <!-- no translation found for permlab_reorderTasks (2018575526934422779) -->
+    <skip />
+    <!-- no translation found for permdesc_reorderTasks (7734217754877439351) -->
+    <skip />
+    <!-- no translation found for permlab_enableCarMode (5684504058192921098) -->
+    <skip />
+    <!-- no translation found for permdesc_enableCarMode (4853187425751419467) -->
+    <skip />
+    <!-- no translation found for permlab_killBackgroundProcesses (3914026687420177202) -->
+    <skip />
+    <!-- no translation found for permdesc_killBackgroundProcesses (4593353235959733119) -->
+    <skip />
+    <!-- no translation found for permlab_systemAlertWindow (3543347980839518613) -->
+    <skip />
+    <!-- no translation found for permdesc_systemAlertWindow (8584678381972820118) -->
+    <skip />
+    <!-- no translation found for permlab_persistentActivity (8841113627955563938) -->
+    <skip />
+    <!-- no translation found for permdesc_persistentActivity (8525189272329086137) -->
+    <skip />
+    <!-- no translation found for permdesc_persistentActivity (5086862529499103587) -->
+    <skip />
+    <!-- no translation found for permdesc_persistentActivity (4384760047508278272) -->
+    <skip />
+    <!-- no translation found for permlab_getPackageSize (7472921768357981986) -->
+    <skip />
+    <!-- no translation found for permdesc_getPackageSize (3921068154420738296) -->
+    <skip />
+    <!-- no translation found for permlab_writeSettings (2226195290955224730) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSettings (7775723441558907181) -->
+    <skip />
+    <!-- no translation found for permlab_receiveBootCompleted (5312965565987800025) -->
+    <skip />
+    <!-- no translation found for permdesc_receiveBootCompleted (7390304664116880704) -->
+    <skip />
+    <!-- no translation found for permdesc_receiveBootCompleted (4525890122209673621) -->
+    <skip />
+    <!-- no translation found for permdesc_receiveBootCompleted (513950589102617504) -->
+    <skip />
+    <!-- no translation found for permlab_broadcastSticky (7919126372606881614) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastSticky (7749760494399915651) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastSticky (6839285697565389467) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastSticky (2825803764232445091) -->
+    <skip />
+    <!-- no translation found for permlab_readContacts (8348481131899886131) -->
+    <skip />
+    <!-- no translation found for permdesc_readContacts (5294866856941149639) -->
+    <skip />
+    <!-- no translation found for permdesc_readContacts (1839238344654834087) -->
+    <skip />
+    <!-- no translation found for permdesc_readContacts (8440654152457300662) -->
+    <skip />
+    <!-- no translation found for permlab_writeContacts (5107492086416793544) -->
+    <skip />
+    <!-- no translation found for permdesc_writeContacts (897243932521953602) -->
+    <skip />
+    <!-- no translation found for permdesc_writeContacts (5438230957000018959) -->
+    <skip />
+    <!-- no translation found for permdesc_writeContacts (589869224625163558) -->
+    <skip />
+    <!-- no translation found for permlab_readCallLog (3478133184624102739) -->
+    <skip />
+    <!-- no translation found for permdesc_readCallLog (3700645184870760285) -->
+    <skip />
+    <!-- no translation found for permdesc_readCallLog (5611770887047387926) -->
+    <skip />
+    <!-- no translation found for permdesc_readCallLog (5777725796813217244) -->
+    <skip />
+    <!-- no translation found for permlab_writeCallLog (8552045664743499354) -->
+    <skip />
+    <!-- no translation found for permdesc_writeCallLog (6661806062274119245) -->
+    <skip />
+    <!-- no translation found for permdesc_writeCallLog (4225034892248398019) -->
+    <skip />
+    <!-- no translation found for permdesc_writeCallLog (683941736352787842) -->
+    <skip />
+    <!-- no translation found for permlab_bodySensors (4683341291818520277) -->
+    <skip />
+    <!-- no translation found for permdesc_bodySensors (4380015021754180431) -->
+    <skip />
+    <!-- no translation found for permlab_readCalendar (5972727560257612398) -->
+    <skip />
+    <!-- no translation found for permdesc_readCalendar (4216462049057658723) -->
+    <skip />
+    <!-- no translation found for permdesc_readCalendar (3191352452242394196) -->
+    <skip />
+    <!-- no translation found for permdesc_readCalendar (7434548682470851583) -->
+    <skip />
+    <!-- no translation found for permlab_writeCalendar (8438874755193825647) -->
+    <skip />
+    <!-- no translation found for permdesc_writeCalendar (6679035520113668528) -->
+    <skip />
+    <!-- no translation found for permdesc_writeCalendar (1273290605500902507) -->
+    <skip />
+    <!-- no translation found for permdesc_writeCalendar (2324469496327249376) -->
+    <skip />
+    <!-- no translation found for permlab_accessLocationExtraCommands (2836308076720553837) -->
+    <skip />
+    <!-- no translation found for permdesc_accessLocationExtraCommands (6078307221056649927) -->
+    <skip />
+    <!-- no translation found for permlab_accessFineLocation (251034415460950944) -->
+    <skip />
+    <!-- no translation found for permdesc_accessFineLocation (5295047563564981250) -->
+    <skip />
+    <!-- no translation found for permlab_accessCoarseLocation (7715277613928539434) -->
+    <skip />
+    <!-- no translation found for permdesc_accessCoarseLocation (2538200184373302295) -->
+    <skip />
+    <!-- no translation found for permlab_modifyAudioSettings (6095859937069146086) -->
+    <skip />
+    <!-- no translation found for permdesc_modifyAudioSettings (3522565366806248517) -->
+    <skip />
+    <!-- no translation found for permlab_recordAudio (3876049771427466323) -->
+    <skip />
+    <!-- no translation found for permdesc_recordAudio (4906839301087980680) -->
+    <skip />
+    <!-- no translation found for permlab_sim_communication (2935852302216852065) -->
+    <skip />
+    <!-- no translation found for permdesc_sim_communication (5725159654279639498) -->
+    <skip />
+    <!-- no translation found for permlab_camera (3616391919559751192) -->
+    <skip />
+    <!-- no translation found for permdesc_camera (8497216524735535009) -->
+    <skip />
+    <!-- no translation found for permlab_vibrate (7696427026057705834) -->
+    <skip />
+    <!-- no translation found for permdesc_vibrate (6284989245902300945) -->
+    <skip />
+    <!-- no translation found for permlab_callPhone (3925836347681847954) -->
+    <skip />
+    <!-- no translation found for permdesc_callPhone (3740797576113760827) -->
+    <skip />
+    <!-- no translation found for permlab_accessImsCallService (3574943847181793918) -->
+    <skip />
+    <!-- no translation found for permdesc_accessImsCallService (8992884015198298775) -->
+    <skip />
+    <!-- no translation found for permlab_readPhoneState (9178228524507610486) -->
+    <skip />
+    <!-- no translation found for permdesc_readPhoneState (1639212771826125528) -->
+    <skip />
+    <!-- no translation found for permlab_wakeLock (1531731435011495015) -->
+    <skip />
+    <!-- no translation found for permlab_wakeLock (2601193288949154131) -->
+    <skip />
+    <!-- no translation found for permlab_wakeLock (573480187941496130) -->
+    <skip />
+    <!-- no translation found for permdesc_wakeLock (7311319824400447868) -->
+    <skip />
+    <!-- no translation found for permdesc_wakeLock (3208534859208996974) -->
+    <skip />
+    <!-- no translation found for permdesc_wakeLock (8559100677372928754) -->
+    <skip />
+    <!-- no translation found for permlab_transmitIr (7545858504238530105) -->
+    <skip />
+    <!-- no translation found for permdesc_transmitIr (5358308854306529170) -->
+    <skip />
+    <!-- no translation found for permdesc_transmitIr (3926790828514867101) -->
+    <skip />
+    <!-- no translation found for permdesc_transmitIr (7957763745020300725) -->
+    <skip />
+    <!-- no translation found for permlab_setWallpaper (6627192333373465143) -->
+    <skip />
+    <!-- no translation found for permdesc_setWallpaper (7373447920977624745) -->
+    <skip />
+    <!-- no translation found for permlab_setWallpaperHints (3278608165977736538) -->
+    <skip />
+    <!-- no translation found for permdesc_setWallpaperHints (8235784384223730091) -->
+    <skip />
+    <!-- no translation found for permlab_setTimeZone (2945079801013077340) -->
+    <skip />
+    <!-- no translation found for permdesc_setTimeZone (1676983712315827645) -->
+    <skip />
+    <!-- no translation found for permdesc_setTimeZone (888864653946175955) -->
+    <skip />
+    <!-- no translation found for permdesc_setTimeZone (4499943488436633398) -->
+    <skip />
+    <!-- no translation found for permlab_getAccounts (1086795467760122114) -->
+    <skip />
+    <!-- no translation found for permdesc_getAccounts (2741496534769660027) -->
+    <skip />
+    <!-- no translation found for permdesc_getAccounts (4190633395633907543) -->
+    <skip />
+    <!-- no translation found for permdesc_getAccounts (3448316822451807382) -->
+    <skip />
+    <!-- no translation found for permlab_accessNetworkState (4951027964348974773) -->
+    <skip />
+    <!-- no translation found for permdesc_accessNetworkState (8318964424675960975) -->
+    <skip />
+    <!-- no translation found for permlab_createNetworkSockets (7934516631384168107) -->
+    <skip />
+    <!-- no translation found for permdesc_createNetworkSockets (3403062187779724185) -->
+    <skip />
+    <!-- no translation found for permlab_changeNetworkState (958884291454327309) -->
+    <skip />
+    <!-- no translation found for permdesc_changeNetworkState (6789123912476416214) -->
+    <skip />
+    <!-- no translation found for permlab_changeTetherState (5952584964373017960) -->
+    <skip />
+    <!-- no translation found for permdesc_changeTetherState (1524441344412319780) -->
+    <skip />
+    <!-- no translation found for permlab_accessWifiState (5202012949247040011) -->
+    <skip />
+    <!-- no translation found for permdesc_accessWifiState (5002798077387803726) -->
+    <skip />
+    <!-- no translation found for permlab_changeWifiState (6550641188749128035) -->
+    <skip />
+    <!-- no translation found for permdesc_changeWifiState (7137950297386127533) -->
+    <skip />
+    <!-- no translation found for permlab_changeWifiMulticastState (1368253871483254784) -->
+    <skip />
+    <!-- no translation found for permdesc_changeWifiMulticastState (7969774021256336548) -->
+    <skip />
+    <!-- no translation found for permdesc_changeWifiMulticastState (9031975661145014160) -->
+    <skip />
+    <!-- no translation found for permdesc_changeWifiMulticastState (6851949706025349926) -->
+    <skip />
+    <!-- no translation found for permlab_bluetoothAdmin (6006967373935926659) -->
+    <skip />
+    <!-- no translation found for permdesc_bluetoothAdmin (6921177471748882137) -->
+    <skip />
+    <!-- no translation found for permdesc_bluetoothAdmin (3373125682645601429) -->
+    <skip />
+    <!-- no translation found for permdesc_bluetoothAdmin (8931682159331542137) -->
+    <skip />
+    <!-- no translation found for permlab_accessWimaxState (4195907010610205703) -->
+    <skip />
+    <!-- no translation found for permdesc_accessWimaxState (6360102877261978887) -->
+    <skip />
+    <!-- no translation found for permlab_changeWimaxState (340465839241528618) -->
+    <skip />
+    <!-- no translation found for permdesc_changeWimaxState (3156456504084201805) -->
+    <skip />
+    <!-- no translation found for permdesc_changeWimaxState (6022307083934827718) -->
+    <skip />
+    <!-- no translation found for permdesc_changeWimaxState (697025043004923798) -->
+    <skip />
+    <!-- no translation found for permlab_bluetooth (6127769336339276828) -->
+    <skip />
+    <!-- no translation found for permdesc_bluetooth (3480722181852438628) -->
+    <skip />
+    <!-- no translation found for permdesc_bluetooth (3974124940101104206) -->
+    <skip />
+    <!-- no translation found for permdesc_bluetooth (3207106324452312739) -->
+    <skip />
+    <!-- no translation found for permlab_nfc (4423351274757876953) -->
+    <skip />
+    <!-- no translation found for permdesc_nfc (7120611819401789907) -->
+    <skip />
+    <!-- no translation found for permlab_disableKeyguard (3598496301486439258) -->
+    <skip />
+    <!-- no translation found for permdesc_disableKeyguard (6034203065077122992) -->
+    <skip />
+    <!-- no translation found for permlab_manageFingerprint (5640858826254575638) -->
+    <skip />
+    <!-- no translation found for permdesc_manageFingerprint (178208705828055464) -->
+    <skip />
+    <!-- no translation found for permlab_useFingerprint (3150478619915124905) -->
+    <skip />
+    <!-- no translation found for permdesc_useFingerprint (9165097460730684114) -->
+    <skip />
+    <!-- no translation found for fingerprint_acquired_partial (735082772341716043) -->
+    <skip />
+    <!-- no translation found for fingerprint_acquired_insufficient (4596546021310923214) -->
+    <skip />
+    <!-- no translation found for fingerprint_acquired_imager_dirty (1087209702421076105) -->
+    <skip />
+    <!-- no translation found for fingerprint_acquired_too_fast (6470642383109155969) -->
+    <skip />
+    <!-- no translation found for fingerprint_acquired_too_slow (59250885689661653) -->
+    <skip />
+  <string-array name="fingerprint_acquired_vendor">
+  </string-array>
+    <!-- no translation found for fingerprint_error_hw_not_available (7955921658939936596) -->
+    <skip />
+    <!-- no translation found for fingerprint_error_no_space (1055819001126053318) -->
+    <skip />
+    <!-- no translation found for fingerprint_error_timeout (3927186043737732875) -->
+    <skip />
+    <!-- no translation found for fingerprint_error_canceled (4402024612660774395) -->
+    <skip />
+    <!-- no translation found for fingerprint_error_lockout (5536934748136933450) -->
+    <skip />
+    <!-- no translation found for fingerprint_error_unable_to_process (6107816084103552441) -->
+    <skip />
+    <!-- no translation found for fingerprint_name_template (5870957565512716938) -->
+    <skip />
+  <string-array name="fingerprint_error_vendor">
+  </string-array>
+    <!-- no translation found for fingerprint_icon_content_description (2340202869968465936) -->
+    <skip />
+    <!-- no translation found for permlab_readSyncSettings (6201810008230503052) -->
+    <skip />
+    <!-- no translation found for permdesc_readSyncSettings (2706745674569678644) -->
+    <skip />
+    <!-- no translation found for permlab_writeSyncSettings (5408694875793945314) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSyncSettings (8956262591306369868) -->
+    <skip />
+    <!-- no translation found for permlab_readSyncStats (7396577451360202448) -->
+    <skip />
+    <!-- no translation found for permdesc_readSyncStats (1510143761757606156) -->
+    <skip />
+    <!-- no translation found for permlab_sdcardRead (367275095159405468) -->
+    <skip />
+    <!-- no translation found for permlab_sdcardRead (2188156462934977940) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardRead (3446988712598386079) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardRead (2607362473654975411) -->
+    <skip />
+    <!-- no translation found for permlab_sdcardWrite (8485979062254666748) -->
+    <skip />
+    <!-- no translation found for permlab_sdcardWrite (8805693630050458763) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardWrite (6175406299445710888) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardWrite (4337417790936632090) -->
+    <skip />
+    <!-- no translation found for permlab_use_sip (2052499390128979920) -->
+    <skip />
+    <!-- no translation found for permdesc_use_sip (2297804849860225257) -->
+    <skip />
+    <!-- no translation found for permlab_register_sim_subscription (3166535485877549177) -->
+    <skip />
+    <!-- no translation found for permdesc_register_sim_subscription (2138909035926222911) -->
+    <skip />
+    <!-- no translation found for permlab_register_call_provider (108102120289029841) -->
+    <skip />
+    <!-- no translation found for permdesc_register_call_provider (7034310263521081388) -->
+    <skip />
+    <!-- no translation found for permlab_connection_manager (1116193254522105375) -->
+    <skip />
+    <!-- no translation found for permdesc_connection_manager (5925480810356483565) -->
+    <skip />
+    <!-- no translation found for permlab_bind_incall_service (6773648341975287125) -->
+    <skip />
+    <!-- no translation found for permdesc_bind_incall_service (8343471381323215005) -->
+    <skip />
+    <!-- no translation found for permlab_bind_connection_service (3557341439297014940) -->
+    <skip />
+    <!-- no translation found for permdesc_bind_connection_service (4008754499822478114) -->
+    <skip />
+    <!-- no translation found for permlab_control_incall_experience (9061024437607777619) -->
+    <skip />
+    <!-- no translation found for permdesc_control_incall_experience (915159066039828124) -->
+    <skip />
+    <!-- no translation found for permlab_readNetworkUsageHistory (7862593283611493232) -->
+    <skip />
+    <!-- no translation found for permdesc_readNetworkUsageHistory (7689060749819126472) -->
+    <skip />
+    <!-- no translation found for permlab_manageNetworkPolicy (2562053592339859990) -->
+    <skip />
+    <!-- no translation found for permdesc_manageNetworkPolicy (7537586771559370668) -->
+    <skip />
+    <!-- no translation found for permlab_modifyNetworkAccounting (5088217309088729650) -->
+    <skip />
+    <!-- no translation found for permdesc_modifyNetworkAccounting (5443412866746198123) -->
+    <skip />
+    <!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
+    <skip />
+    <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
+    <skip />
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
+    <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
+    <skip />
+    <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
+    <skip />
+    <!-- no translation found for permlab_bindDreamService (4153646965978563462) -->
+    <skip />
+    <!-- no translation found for permdesc_bindDreamService (7325825272223347863) -->
+    <skip />
+    <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
+    <skip />
+    <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
+    <skip />
+    <!-- no translation found for permlab_accessNetworkConditions (8206077447838909516) -->
+    <skip />
+    <!-- no translation found for permdesc_accessNetworkConditions (6899102075825272211) -->
+    <skip />
+    <!-- no translation found for permlab_setInputCalibration (4902620118878467615) -->
+    <skip />
+    <!-- no translation found for permdesc_setInputCalibration (4527511047549456929) -->
+    <skip />
+    <!-- no translation found for permlab_accessDrmCertificates (7436886640723203615) -->
+    <skip />
+    <!-- no translation found for permdesc_accessDrmCertificates (8073288354426159089) -->
+    <skip />
+    <!-- no translation found for permlab_handoverStatus (7820353257219300883) -->
+    <skip />
+    <!-- no translation found for permdesc_handoverStatus (4788144087245714948) -->
+    <skip />
+    <!-- no translation found for permlab_removeDrmCertificates (7044888287209892751) -->
+    <skip />
+    <!-- no translation found for permdesc_removeDrmCertificates (7272999075113400993) -->
+    <skip />
+    <!-- no translation found for permlab_bindCarrierMessagingService (1490229371796969158) -->
+    <skip />
+    <!-- no translation found for permdesc_bindCarrierMessagingService (2762882888502113944) -->
+    <skip />
+    <!-- no translation found for permlab_bindCarrierServices (3233108656245526783) -->
+    <skip />
+    <!-- no translation found for permdesc_bindCarrierServices (1391552602551084192) -->
+    <skip />
+    <!-- no translation found for permlab_access_notification_policy (4247510821662059671) -->
+    <skip />
+    <!-- no translation found for permdesc_access_notification_policy (3296832375218749580) -->
+    <skip />
+    <!-- no translation found for policylab_limitPassword (4497420728857585791) -->
+    <skip />
+    <!-- no translation found for policydesc_limitPassword (2502021457917874968) -->
+    <skip />
+    <!-- no translation found for policylab_watchLogin (914130646942199503) -->
+    <skip />
+    <!-- no translation found for policydesc_watchLogin (3215729294215070072) -->
+    <skip />
+    <!-- no translation found for policydesc_watchLogin (2707817988309890256) -->
+    <skip />
+    <!-- no translation found for policydesc_watchLogin (5712323091846761073) -->
+    <skip />
+    <!-- no translation found for policydesc_watchLogin_secondaryUser (4280246270601044505) -->
+    <skip />
+    <!-- no translation found for policydesc_watchLogin_secondaryUser (3484832653564483250) -->
+    <skip />
+    <!-- no translation found for policydesc_watchLogin_secondaryUser (2185480427217127147) -->
+    <skip />
+    <!-- no translation found for policylab_resetPassword (4934707632423915395) -->
+    <skip />
+    <!-- no translation found for policydesc_resetPassword (1278323891710619128) -->
+    <skip />
+    <!-- no translation found for policylab_forceLock (2274085384704248431) -->
+    <skip />
+    <!-- no translation found for policydesc_forceLock (1141797588403827138) -->
+    <skip />
+    <!-- no translation found for policylab_wipeData (3910545446758639713) -->
+    <skip />
+    <!-- no translation found for policydesc_wipeData (4306184096067756876) -->
+    <skip />
+    <!-- no translation found for policydesc_wipeData (5816221315214527028) -->
+    <skip />
+    <!-- no translation found for policydesc_wipeData (5096895604574188391) -->
+    <skip />
+    <!-- no translation found for policylab_wipeData_secondaryUser (8362863289455531813) -->
+    <skip />
+    <!-- no translation found for policydesc_wipeData_secondaryUser (6336255514635308054) -->
+    <skip />
+    <!-- no translation found for policydesc_wipeData_secondaryUser (2086473496848351810) -->
+    <skip />
+    <!-- no translation found for policydesc_wipeData_secondaryUser (6787904546711590238) -->
+    <skip />
+    <!-- no translation found for policylab_setGlobalProxy (2784828293747791446) -->
+    <skip />
+    <!-- no translation found for policydesc_setGlobalProxy (8459859731153370499) -->
+    <skip />
+    <!-- no translation found for policylab_expirePassword (5610055012328825874) -->
+    <skip />
+    <!-- no translation found for policydesc_expirePassword (5367525762204416046) -->
+    <skip />
+    <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
+    <skip />
+    <!-- no translation found for policydesc_encryptedStorage (2637732115325316992) -->
+    <skip />
+    <!-- no translation found for policylab_disableCamera (6395301023152297826) -->
+    <skip />
+    <!-- no translation found for policydesc_disableCamera (2306349042834754597) -->
+    <skip />
+    <!-- no translation found for policylab_disableKeyguardFeatures (8552277871075367771) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardFeatures (2044755691354158439) -->
+    <skip />
+    <!-- no translation found for phoneTypes:0 (8901098336658710359) -->
+    <!-- no translation found for phoneTypes:1 (869923650527136615) -->
+    <!-- no translation found for phoneTypes:2 (7897544654242874543) -->
+    <!-- no translation found for phoneTypes:3 (1103601433382158155) -->
+    <!-- no translation found for phoneTypes:4 (1735177144948329370) -->
+    <!-- no translation found for phoneTypes:5 (603878674477207394) -->
+    <!-- no translation found for phoneTypes:6 (1650824275177931637) -->
+    <!-- no translation found for phoneTypes:7 (9192514806975898961) -->
+    <!-- no translation found for emailAddressTypes:0 (8073994352956129127) -->
+    <!-- no translation found for emailAddressTypes:1 (7084237356602625604) -->
+    <!-- no translation found for emailAddressTypes:2 (1112044410659011023) -->
+    <!-- no translation found for emailAddressTypes:3 (2374913952870110618) -->
+    <!-- no translation found for postalAddressTypes:0 (6880257626740047286) -->
+    <!-- no translation found for postalAddressTypes:1 (5629153956045109251) -->
+    <!-- no translation found for postalAddressTypes:2 (4966604264500343469) -->
+    <!-- no translation found for postalAddressTypes:3 (4932682847595299369) -->
+    <!-- no translation found for imAddressTypes:0 (1738585194601476694) -->
+    <!-- no translation found for imAddressTypes:1 (1359644565647383708) -->
+    <!-- no translation found for imAddressTypes:2 (7868549401053615677) -->
+    <!-- no translation found for imAddressTypes:3 (3145118944639869809) -->
+    <!-- no translation found for organizationTypes:0 (7546335612189115615) -->
+    <!-- no translation found for organizationTypes:1 (4378074129049520373) -->
+    <!-- no translation found for organizationTypes:2 (3455047468583965104) -->
+    <!-- no translation found for imProtocols:0 (8595261363518459565) -->
+    <!-- no translation found for imProtocols:1 (7390473628275490700) -->
+    <!-- no translation found for imProtocols:2 (7882877134931458217) -->
+    <!-- no translation found for imProtocols:3 (5035376313200585242) -->
+    <!-- no translation found for imProtocols:4 (7532363178459444943) -->
+    <!-- no translation found for imProtocols:5 (3713441034299660749) -->
+    <!-- no translation found for imProtocols:6 (2506857312718630823) -->
+    <!-- no translation found for imProtocols:7 (1648797903785279353) -->
+    <!-- no translation found for phoneTypeCustom (1644738059053355820) -->
+    <skip />
+    <!-- no translation found for phoneTypeHome (2570923463033985887) -->
+    <skip />
+    <!-- no translation found for phoneTypeMobile (6501463557754751037) -->
+    <skip />
+    <!-- no translation found for phoneTypeWork (8863939667059911633) -->
+    <skip />
+    <!-- no translation found for phoneTypeFaxWork (3517792160008890912) -->
+    <skip />
+    <!-- no translation found for phoneTypeFaxHome (2067265972322971467) -->
+    <skip />
+    <!-- no translation found for phoneTypePager (7582359955394921732) -->
+    <skip />
+    <!-- no translation found for phoneTypeOther (1544425847868765990) -->
+    <skip />
+    <!-- no translation found for phoneTypeCallback (2712175203065678206) -->
+    <skip />
+    <!-- no translation found for phoneTypeCar (8738360689616716982) -->
+    <skip />
+    <!-- no translation found for phoneTypeCompanyMain (540434356461478916) -->
+    <skip />
+    <!-- no translation found for phoneTypeIsdn (8022453193171370337) -->
+    <skip />
+    <!-- no translation found for phoneTypeMain (6766137010628326916) -->
+    <skip />
+    <!-- no translation found for phoneTypeOtherFax (8587657145072446565) -->
+    <skip />
+    <!-- no translation found for phoneTypeRadio (4093738079908667513) -->
+    <skip />
+    <!-- no translation found for phoneTypeTelex (3367879952476250512) -->
+    <skip />
+    <!-- no translation found for phoneTypeTtyTdd (8606514378585000044) -->
+    <skip />
+    <!-- no translation found for phoneTypeWorkMobile (1311426989184065709) -->
+    <skip />
+    <!-- no translation found for phoneTypeWorkPager (649938731231157056) -->
+    <skip />
+    <!-- no translation found for phoneTypeAssistant (5596772636128562884) -->
+    <skip />
+    <!-- no translation found for phoneTypeMms (7254492275502768992) -->
+    <skip />
+    <!-- no translation found for eventTypeCustom (7837586198458073404) -->
+    <skip />
+    <!-- no translation found for eventTypeBirthday (2813379844211390740) -->
+    <skip />
+    <!-- no translation found for eventTypeAnniversary (3876779744518284000) -->
+    <skip />
+    <!-- no translation found for eventTypeOther (7388178939010143077) -->
+    <skip />
+    <!-- no translation found for emailTypeCustom (8525960257804213846) -->
+    <skip />
+    <!-- no translation found for emailTypeHome (449227236140433919) -->
+    <skip />
+    <!-- no translation found for emailTypeWork (3548058059601149973) -->
+    <skip />
+    <!-- no translation found for emailTypeOther (2923008695272639549) -->
+    <skip />
+    <!-- no translation found for emailTypeMobile (119919005321166205) -->
+    <skip />
+    <!-- no translation found for postalTypeCustom (8903206903060479902) -->
+    <skip />
+    <!-- no translation found for postalTypeHome (8165756977184483097) -->
+    <skip />
+    <!-- no translation found for postalTypeWork (5268172772387694495) -->
+    <skip />
+    <!-- no translation found for postalTypeOther (2726111966623584341) -->
+    <skip />
+    <!-- no translation found for imTypeCustom (2074028755527826046) -->
+    <skip />
+    <!-- no translation found for imTypeHome (6241181032954263892) -->
+    <skip />
+    <!-- no translation found for imTypeWork (1371489290242433090) -->
+    <skip />
+    <!-- no translation found for imTypeOther (5377007495735915478) -->
+    <skip />
+    <!-- no translation found for imProtocolCustom (6919453836618749992) -->
+    <skip />
+    <!-- no translation found for imProtocolAim (7050360612368383417) -->
+    <skip />
+    <!-- no translation found for imProtocolMsn (144556545420769442) -->
+    <skip />
+    <!-- no translation found for imProtocolYahoo (8271439408469021273) -->
+    <skip />
+    <!-- no translation found for imProtocolSkype (9019296744622832951) -->
+    <skip />
+    <!-- no translation found for imProtocolQq (8887484379494111884) -->
+    <skip />
+    <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
+    <skip />
+    <!-- no translation found for imProtocolIcq (1574870433606517315) -->
+    <skip />
+    <!-- no translation found for imProtocolJabber (2279917630875771722) -->
+    <skip />
+    <!-- no translation found for imProtocolNetMeeting (8287625655986827971) -->
+    <skip />
+    <!-- no translation found for orgTypeWork (29268870505363872) -->
+    <skip />
+    <!-- no translation found for orgTypeOther (3951781131570124082) -->
+    <skip />
+    <!-- no translation found for orgTypeCustom (225523415372088322) -->
+    <skip />
+    <!-- no translation found for relationTypeCustom (3542403679827297300) -->
+    <skip />
+    <!-- no translation found for relationTypeAssistant (6274334825195379076) -->
+    <skip />
+    <!-- no translation found for relationTypeBrother (8757913506784067713) -->
+    <skip />
+    <!-- no translation found for relationTypeChild (1890746277276881626) -->
+    <skip />
+    <!-- no translation found for relationTypeDomesticPartner (6904807112121122133) -->
+    <skip />
+    <!-- no translation found for relationTypeFather (5228034687082050725) -->
+    <skip />
+    <!-- no translation found for relationTypeFriend (7313106762483391262) -->
+    <skip />
+    <!-- no translation found for relationTypeManager (6365677861610137895) -->
+    <skip />
+    <!-- no translation found for relationTypeMother (4578571352962758304) -->
+    <skip />
+    <!-- no translation found for relationTypeParent (4755635567562925226) -->
+    <skip />
+    <!-- no translation found for relationTypePartner (7266490285120262781) -->
+    <skip />
+    <!-- no translation found for relationTypeReferredBy (101573059844135524) -->
+    <skip />
+    <!-- no translation found for relationTypeRelative (1799819930085610271) -->
+    <skip />
+    <!-- no translation found for relationTypeSister (1735983554479076481) -->
+    <skip />
+    <!-- no translation found for relationTypeSpouse (394136939428698117) -->
+    <skip />
+    <!-- no translation found for sipAddressTypeCustom (2473580593111590945) -->
+    <skip />
+    <!-- no translation found for sipAddressTypeHome (6093598181069359295) -->
+    <skip />
+    <!-- no translation found for sipAddressTypeWork (6920725730797099047) -->
+    <skip />
+    <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
+    <skip />
+    <!-- no translation found for quick_contacts_not_available (746098007828579688) -->
+    <skip />
+    <!-- no translation found for keyguard_password_enter_pin_code (3037685796058495017) -->
+    <skip />
+    <!-- no translation found for keyguard_password_enter_puk_code (4800725266925845333) -->
+    <skip />
+    <!-- no translation found for keyguard_password_enter_puk_prompt (1341112146710087048) -->
+    <skip />
+    <!-- no translation found for keyguard_password_enter_pin_prompt (8027680321614196258) -->
+    <skip />
+    <!-- no translation found for keyguard_password_entry_touch_hint (7858547464982981384) -->
+    <skip />
+    <!-- no translation found for keyguard_password_enter_password_code (1054721668279049780) -->
+    <skip />
+    <!-- no translation found for keyguard_password_enter_pin_password_code (6391755146112503443) -->
+    <skip />
+    <!-- no translation found for keyguard_password_wrong_pin_code (2422225591006134936) -->
+    <skip />
+    <!-- no translation found for keyguard_label_text (861796461028298424) -->
+    <skip />
+    <!-- no translation found for emergency_call_dialog_number_for_display (696192103195090970) -->
+    <skip />
+    <!-- no translation found for lockscreen_carrier_default (6169005837238288522) -->
+    <skip />
+    <!-- no translation found for lockscreen_screen_locked (7288443074806832904) -->
+    <skip />
+    <!-- no translation found for lockscreen_instructions_when_pattern_enabled (46154051614126049) -->
+    <skip />
+    <!-- no translation found for lockscreen_instructions_when_pattern_disabled (686260028797158364) -->
+    <skip />
+    <!-- no translation found for lockscreen_pattern_instructions (7478703254964810302) -->
+    <skip />
+    <!-- no translation found for lockscreen_emergency_call (5298642613417801888) -->
+    <skip />
+    <!-- no translation found for lockscreen_return_to_call (5244259785500040021) -->
+    <skip />
+    <!-- no translation found for lockscreen_pattern_correct (9039008650362261237) -->
+    <skip />
+    <!-- no translation found for lockscreen_pattern_wrong (4317955014948108794) -->
+    <skip />
+    <!-- no translation found for lockscreen_password_wrong (5737815393253165301) -->
+    <skip />
+    <!-- no translation found for faceunlock_multiple_failures (754137583022792429) -->
+    <skip />
+    <!-- no translation found for lockscreen_missing_sim_message_short (5099439277819215399) -->
+    <skip />
+    <!-- no translation found for lockscreen_missing_sim_message (151659196095791474) -->
+    <skip />
+    <!-- no translation found for lockscreen_missing_sim_message (1943633865476989599) -->
+    <skip />
+    <!-- no translation found for lockscreen_missing_sim_message (2186920585695169078) -->
+    <skip />
+    <!-- no translation found for lockscreen_missing_sim_instructions (5372787138023272615) -->
+    <skip />
+    <!-- no translation found for lockscreen_missing_sim_instructions_long (3526573099019319472) -->
+    <skip />
+    <!-- no translation found for lockscreen_permanent_disabled_sim_message_short (5096149665138916184) -->
+    <skip />
+    <!-- no translation found for lockscreen_permanent_disabled_sim_instructions (910904643433151371) -->
+    <skip />
+    <!-- no translation found for lockscreen_transport_prev_description (6300840251218161534) -->
+    <skip />
+    <!-- no translation found for lockscreen_transport_next_description (573285210424377338) -->
+    <skip />
+    <!-- no translation found for lockscreen_transport_pause_description (3980308465056173363) -->
+    <skip />
+    <!-- no translation found for lockscreen_transport_play_description (1901258823643886401) -->
+    <skip />
+    <!-- no translation found for lockscreen_transport_stop_description (5907083260651210034) -->
+    <skip />
+    <!-- no translation found for lockscreen_transport_rew_description (6944412838651990410) -->
+    <skip />
+    <!-- no translation found for lockscreen_transport_ffw_description (42987149870928985) -->
+    <skip />
+    <!-- no translation found for emergency_calls_only (6733978304386365407) -->
+    <!-- no translation found for emergency_calls_only (2485604591272668370) -->
+    <skip />
+    <!-- no translation found for lockscreen_network_locked_message (143389224986028501) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_puk_locked_message (7441797339976230) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_puk_locked_instructions (8127916255245181063) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_locked_message (8066660129206001039) -->
+    <skip />
+    <!-- no translation found for lockscreen_sim_unlock_progress_dialog_message (595323214052881264) -->
+    <skip />
+    <!-- no translation found for lockscreen_too_many_failed_attempts_dialog_message (6481623830344107222) -->
+    <skip />
+    <!-- no translation found for lockscreen_too_many_failed_password_attempts_dialog_message (2725973286239344555) -->
+    <skip />
+    <!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6216672706545696955) -->
+    <skip />
+    <!-- no translation found for lockscreen_failed_attempts_almost_glogin (9191611984625460820) -->
+    <skip />
+    <!-- no translation found for lockscreen_failed_attempts_almost_glogin (5316664559603394684) -->
+    <skip />
+    <!-- no translation found for lockscreen_failed_attempts_almost_glogin (2590227559763762751) -->
+    <skip />
+    <!-- no translation found for lockscreen_failed_attempts_almost_at_wipe (6128106399745755604) -->
+    <skip />
+    <!-- no translation found for lockscreen_failed_attempts_almost_at_wipe (950408382418270260) -->
+    <skip />
+    <!-- no translation found for lockscreen_failed_attempts_almost_at_wipe (8603565142156826565) -->
+    <skip />
+    <!-- no translation found for lockscreen_failed_attempts_now_wiping (280873516493934365) -->
+    <skip />
+    <!-- no translation found for lockscreen_failed_attempts_now_wiping (3195755534096192191) -->
+    <skip />
+    <!-- no translation found for lockscreen_failed_attempts_now_wiping (3025504721764922246) -->
+    <skip />
+    <!-- no translation found for lockscreen_too_many_failed_attempts_countdown (6251480343394389665) -->
+    <skip />
+    <!-- no translation found for lockscreen_forgot_pattern_button_text (2626999449610695930) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_forgot_pattern (2588521501166032747) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_too_many_attempts (2751368605287288808) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_instructions (3931816256100707784) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_username_hint (8846881424106484447) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_password_hint (5958028383954738528) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_submit_button (7130893694795786300) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_invalid_input (1364051473347485908) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_account_recovery_hint (1696924763690379073) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_checking_password (7114627351286933867) -->
+    <skip />
+    <!-- no translation found for lockscreen_unlock_label (737440483220667054) -->
+    <skip />
+    <!-- no translation found for lockscreen_sound_on_label (9068877576513425970) -->
+    <skip />
+    <!-- no translation found for lockscreen_sound_off_label (996822825154319026) -->
+    <skip />
+    <!-- no translation found for lockscreen_access_pattern_start (3941045502933142847) -->
+    <skip />
+    <!-- no translation found for lockscreen_access_pattern_cleared (5583479721001639579) -->
+    <skip />
+    <!-- no translation found for lockscreen_access_pattern_cell_added (6756031208359292487) -->
+    <skip />
+    <!-- no translation found for lockscreen_access_pattern_cell_added_verbose (7264580781744026939) -->
+    <skip />
+    <!-- no translation found for lockscreen_access_pattern_detected (4988730895554057058) -->
+    <skip />
+    <!-- no translation found for lockscreen_access_pattern_area (400813207572953209) -->
+    <!-- no translation found for lockscreen_access_pattern_area () -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_widget_changed (5678624624681400191) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_add_widget (8273277058724924654) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_widget_empty_slot (1281505703307930757) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_unlock_area_expanded (2278106022311170299) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_unlock_area_collapsed (6366992066936076396) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_widget (6527131039741808240) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_user_selector (1226798370913698896) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_status (8008264603935930611) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_camera (8904231194181114603) -->
+    <skip />
+    <!-- no translation found for keygaurd_accessibility_media_controls (262209654292161806) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_widget_reorder_start (8736853615588828197) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_widget_reorder_end (7170190950870468320) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_widget_deleted (4426204263929224434) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_expand_lock_area (519859720934178024) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_slide_unlock (2959928478764697254) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_pattern_unlock (1490840706075246612) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_face_unlock (4817282543351718535) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_pin_unlock (2469687111784035046) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_password_unlock (7675777623912155089) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_pattern_area (7679891324509597904) -->
+    <skip />
+    <!-- no translation found for keyguard_accessibility_slide_area (6736064494019979544) -->
+    <skip />
+    <!-- no translation found for password_keyboard_label_symbol_key (992280756256536042) -->
+    <skip />
+    <!-- no translation found for password_keyboard_label_alpha_key (8001096175167485649) -->
+    <skip />
+    <!-- no translation found for password_keyboard_label_alt_key (1284820942620288678) -->
+    <skip />
+    <!-- no translation found for granularity_label_character (7336470535385009523) -->
+    <skip />
+    <!-- no translation found for granularity_label_word (7075570328374918660) -->
+    <skip />
+    <!-- no translation found for granularity_label_link (5815508880782488267) -->
+    <skip />
+    <!-- no translation found for granularity_label_line (5764267235026120888) -->
+    <skip />
+    <!-- no translation found for factorytest_failed (5410270329114212041) -->
+    <skip />
+    <!-- no translation found for factorytest_not_system (4435201656767276723) -->
+    <skip />
+    <!-- no translation found for factorytest_no_action (872991874799998561) -->
+    <skip />
+    <!-- no translation found for factorytest_reboot (6320168203050791643) -->
+    <skip />
+    <!-- no translation found for js_dialog_title (1987483977834603872) -->
+    <skip />
+    <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
+    <!-- no translation found for save_password_label (6860261758665825069) -->
+    <skip />
+    <!-- no translation found for double_tap_toast (4595046515400268881) -->
+    <skip />
+    <!-- no translation found for autofill_this_form (4616758841157816676) -->
+    <skip />
+    <!-- no translation found for setup_autofill (7103495070180590814) -->
+    <skip />
+    <!-- no translation found for autofill_address_name_separator (6350145154779706772) -->
+    <skip />
+    <!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
+    <skip />
+    <!-- no translation found for autofill_address_summary_separator (7483307893170324129) -->
+    <skip />
+    <!-- no translation found for autofill_address_summary_format (4874459455786827344) -->
+    <skip />
+    <!-- no translation found for autofill_province (2231806553863422300) -->
+    <skip />
+    <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+    <skip />
+    <!-- no translation found for autofill_state (6988894195520044613) -->
+    <skip />
+    <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+    <skip />
+    <!-- no translation found for autofill_county (237073771020362891) -->
+    <skip />
+    <!-- no translation found for autofill_island (4020100875984667025) -->
+    <skip />
+    <!-- no translation found for autofill_district (8400735073392267672) -->
+    <skip />
+    <!-- no translation found for autofill_department (5343279462564453309) -->
+    <skip />
+    <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+    <skip />
+    <!-- no translation found for autofill_parish (8202206105468820057) -->
+    <skip />
+    <!-- no translation found for autofill_area (3547409050889952423) -->
+    <skip />
+    <!-- no translation found for autofill_emirate (2893880978835698818) -->
+    <skip />
+    <!-- no translation found for permlab_readHistoryBookmarks (3775265775405106983) -->
+    <skip />
+    <!-- no translation found for permdesc_readHistoryBookmarks (8462378226600439658) -->
+    <skip />
+    <!-- no translation found for permlab_writeHistoryBookmarks (3714785165273314490) -->
+    <skip />
+    <!-- no translation found for permdesc_writeHistoryBookmarks (6825527469145760922) -->
+    <skip />
+    <!-- no translation found for permdesc_writeHistoryBookmarks (7007393823197766548) -->
+    <skip />
+    <!-- no translation found for permdesc_writeHistoryBookmarks (8497389531014185509) -->
+    <skip />
+    <!-- no translation found for permlab_setAlarm (1379294556362091814) -->
+    <skip />
+    <!-- no translation found for permdesc_setAlarm (316392039157473848) -->
+    <skip />
+    <!-- no translation found for permlab_addVoicemail (5525660026090959044) -->
+    <skip />
+    <!-- no translation found for permdesc_addVoicemail (6604508651428252437) -->
+    <skip />
+    <!-- no translation found for permlab_writeGeolocationPermissions (5962224158955273932) -->
+    <skip />
+    <!-- no translation found for permdesc_writeGeolocationPermissions (1083743234522638747) -->
+    <skip />
+    <!-- no translation found for save_password_message (767344687139195790) -->
+    <skip />
+    <!-- no translation found for save_password_notnow (6389675316706699758) -->
+    <skip />
+    <!-- no translation found for save_password_remember (6491879678996749466) -->
+    <skip />
+    <!-- no translation found for save_password_never (8274330296785855105) -->
+    <skip />
+    <!-- no translation found for open_permission_deny (7374036708316629800) -->
+    <skip />
+    <!-- no translation found for text_copied (4985729524670131385) -->
+    <skip />
+    <!-- no translation found for more_item_label (4650918923083320495) -->
+    <skip />
+    <!-- no translation found for prepend_shortcut_label (2572214461676015642) -->
+    <skip />
+    <!-- no translation found for menu_space_shortcut_label (2410328639272162537) -->
+    <skip />
+    <!-- no translation found for menu_enter_shortcut_label (2743362785111309668) -->
+    <skip />
+    <!-- no translation found for menu_delete_shortcut_label (3658178007202748164) -->
+    <skip />
+    <!-- no translation found for search_go (8298016669822141719) -->
+    <skip />
+    <!-- no translation found for search_hint (1733947260773056054) -->
+    <skip />
+    <!-- no translation found for searchview_description_search (6749826639098512120) -->
+    <skip />
+    <!-- no translation found for searchview_description_query (5911778593125355124) -->
+    <skip />
+    <!-- no translation found for searchview_description_clear (1330281990951833033) -->
+    <skip />
+    <!-- no translation found for searchview_description_submit (2688450133297983542) -->
+    <skip />
+    <!-- no translation found for searchview_description_voice (2453203695674994440) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_title (7460694070309730149) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (8655887539089910577) -->
+    <skip />
+    <!-- no translation found for enable_explore_by_touch_warning_message (2708199672852373195) -->
+    <skip />
+    <!-- no translation found for oneMonthDurationPast (7396384508953779925) -->
+    <skip />
+    <!-- no translation found for beforeOneMonthDurationPast (909134546836499826) -->
+    <skip />
+    <!-- no translation found for last_num_days (5104533550723932025) -->
+    <!-- no translation found for last_month (3959346739979055432) -->
+    <skip />
+    <!-- no translation found for older (5211975022815554840) -->
+    <skip />
+    <!-- no translation found for preposition_for_date (9093949757757445117) -->
+    <skip />
+    <!-- no translation found for preposition_for_time (5506831244263083793) -->
+    <skip />
+    <!-- no translation found for preposition_for_year (5040395640711867177) -->
+    <skip />
+    <!-- no translation found for day (8144195776058119424) -->
+    <skip />
+    <!-- no translation found for days (4774547661021344602) -->
+    <skip />
+    <!-- no translation found for hour (2126771916426189481) -->
+    <skip />
+    <!-- no translation found for hours (894424005266852993) -->
+    <skip />
+    <!-- no translation found for minute (9148878657703769868) -->
+    <skip />
+    <!-- no translation found for minutes (5646001005827034509) -->
+    <skip />
+    <!-- no translation found for second (3184235808021478) -->
+    <skip />
+    <!-- no translation found for seconds (3161515347216589235) -->
+    <skip />
+    <!-- no translation found for week (5617961537173061583) -->
+    <skip />
+    <!-- no translation found for weeks (6509623834583944518) -->
+    <skip />
+    <!-- no translation found for year (4001118221013892076) -->
+    <skip />
+    <!-- no translation found for years (6881577717993213522) -->
+    <skip />
+    <!-- no translation found for duration_seconds (4527986939729687805) -->
+    <!-- no translation found for duration_minutes (643786953939956125) -->
+    <!-- no translation found for duration_hours (6826233369186668274) -->
+    <!-- no translation found for VideoView_error_title (3534509135438353077) -->
+    <skip />
+    <!-- no translation found for VideoView_error_text_invalid_progressive_playback (3186670335938670444) -->
+    <skip />
+    <!-- no translation found for VideoView_error_text_unknown (3450439155187810085) -->
+    <skip />
+    <!-- no translation found for VideoView_error_button (2822238215100679592) -->
+    <skip />
+    <!-- no translation found for relative_time (1818557177829411417) -->
+    <skip />
+    <!-- no translation found for noon (7245353528818587908) -->
+    <skip />
+    <!-- no translation found for Noon (3342127745230013127) -->
+    <skip />
+    <!-- no translation found for midnight (7166259508850457595) -->
+    <skip />
+    <!-- no translation found for Midnight (5630806906897892201) -->
+    <skip />
+    <!-- no translation found for elapsed_time_short_format_mm_ss (4431555943828711473) -->
+    <skip />
+    <!-- no translation found for elapsed_time_short_format_h_mm_ss (1846071997616654124) -->
+    <skip />
+    <!-- no translation found for selectAll (6876518925844129331) -->
+    <skip />
+    <!-- no translation found for cut (3092569408438626261) -->
+    <skip />
+    <!-- no translation found for copy (2681946229533511987) -->
+    <skip />
+    <!-- no translation found for paste (5629880836805036433) -->
+    <skip />
+    <!-- no translation found for paste_as_plain_text (5427792741908010675) -->
+    <skip />
+    <!-- no translation found for replace (5781686059063148930) -->
+    <skip />
+    <!-- no translation found for delete (6098684844021697789) -->
+    <skip />
+    <!-- no translation found for copyUrl (2538211579596067402) -->
+    <skip />
+    <!-- no translation found for selectTextMode (1018691815143165326) -->
+    <skip />
+    <!-- no translation found for undo (7905788502491742328) -->
+    <skip />
+    <!-- no translation found for redo (7759464876566803888) -->
+    <skip />
+    <!-- no translation found for textSelectionCABTitle (5236850394370820357) -->
+    <skip />
+    <!-- no translation found for addToDictionary (4352161534510057874) -->
+    <skip />
+    <!-- no translation found for deleteText (6979668428458199034) -->
+    <skip />
+    <!-- no translation found for inputMethod (1653630062304567879) -->
+    <skip />
+    <!-- no translation found for editTextMenuTitle (4909135564941815494) -->
+    <skip />
+    <!-- no translation found for low_internal_storage_view_title (5576272496365684834) -->
+    <skip />
+    <!-- no translation found for low_internal_storage_view_text (6640505817617414371) -->
+    <skip />
+    <!-- no translation found for low_internal_storage_view_text_no_boot (6935190099204693424) -->
+    <skip />
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
+    <!-- no translation found for ok (5970060430562524910) -->
+    <skip />
+    <!-- no translation found for cancel (6442560571259935130) -->
+    <skip />
+    <!-- no translation found for yes (5362982303337969312) -->
+    <skip />
+    <!-- no translation found for no (5141531044935541497) -->
+    <skip />
+    <!-- no translation found for dialog_alert_title (2049658708609043103) -->
+    <skip />
+    <!-- no translation found for loading (7933681260296021180) -->
+    <skip />
+    <!-- no translation found for capital_on (1544682755514494298) -->
+    <skip />
+    <!-- no translation found for capital_off (6815870386972805832) -->
+    <skip />
+    <!-- no translation found for whichApplication (4533185947064773386) -->
+    <skip />
+    <!-- no translation found for whichApplicationNamed (8260158865936942783) -->
+    <skip />
+    <!-- no translation found for whichViewApplication (3272778576700572102) -->
+    <skip />
+    <!-- no translation found for whichViewApplicationNamed (2286418824011249620) -->
+    <skip />
+    <!-- no translation found for whichEditApplication (144727838241402655) -->
+    <skip />
+    <!-- no translation found for whichEditApplicationNamed (1775815530156447790) -->
+    <skip />
+    <!-- no translation found for whichSendApplication (6902512414057341668) -->
+    <skip />
+    <!-- no translation found for whichSendApplicationNamed (2799370240005424391) -->
+    <skip />
+    <!-- no translation found for whichHomeApplication (4307587691506919691) -->
+    <skip />
+    <!-- no translation found for whichHomeApplicationNamed (4493438593214760979) -->
+    <skip />
+    <!-- no translation found for alwaysUse (4583018368000610438) -->
+    <skip />
+    <!-- no translation found for use_a_different_app (8134926230585710243) -->
+    <skip />
+    <!-- no translation found for clearDefaultHintMsg (3252584689512077257) -->
+    <skip />
+    <!-- no translation found for chooseActivity (7486876147751803333) -->
+    <skip />
+    <!-- no translation found for chooseUsbActivity (6894748416073583509) -->
+    <skip />
+    <!-- no translation found for noApplications (2991814273936504689) -->
+    <skip />
+    <string name="aerr_title" msgid="1905800560317137752"></string>
+    <!-- no translation found for aerr_application (932628488013092776) -->
+    <skip />
+    <!-- no translation found for aerr_process (4507058997035697579) -->
+    <skip />
+    <!-- no translation found for aerr_process_silence (4226685530196000222) -->
+    <skip />
+    <string name="anr_title" msgid="4351948481459135709"></string>
+    <!-- no translation found for anr_activity_application (1904477189057199066) -->
+    <skip />
+    <!-- no translation found for anr_activity_process (5776209883299089767) -->
+    <skip />
+    <!-- no translation found for anr_application_process (8941757607340481057) -->
+    <skip />
+    <!-- no translation found for anr_process (6513209874880517125) -->
+    <skip />
+    <!-- no translation found for force_close (8346072094521265605) -->
+    <skip />
+    <!-- no translation found for report (4060218260984795706) -->
+    <skip />
+    <!-- no translation found for wait (7147118217226317732) -->
+    <skip />
+    <!-- no translation found for webpage_unresponsive (3272758351138122503) -->
+    <skip />
+    <!-- no translation found for launch_warning_title (1547997780506713581) -->
+    <skip />
+    <!-- no translation found for launch_warning_replace (6202498949970281412) -->
+    <skip />
+    <!-- no translation found for launch_warning_original (188102023021668683) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_scale (3202955667675944499) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_show (4013878876486655892) -->
+    <skip />
+    <!-- no translation found for screen_compat_mode_hint (1064524084543304459) -->
+    <skip />
+    <!-- no translation found for smv_application (3307209192155442829) -->
+    <skip />
+    <!-- no translation found for smv_process (5120397012047462446) -->
+    <skip />
+    <!-- no translation found for android_upgrading_title (1584192285441405746) -->
+    <skip />
+    <!-- no translation found for android_start_title (8418054686415318207) -->
+    <skip />
+    <!-- no translation found for android_upgrading_fstrim (8036718871534640010) -->
+    <skip />
+    <!-- no translation found for android_upgrading_apk (7904042682111526169) -->
+    <skip />
+    <!-- no translation found for android_preparing_apk (8162599310274079154) -->
+    <skip />
+    <!-- no translation found for android_upgrading_starting_apps (451464516346926713) -->
+    <skip />
+    <!-- no translation found for android_upgrading_complete (1405954754112999229) -->
+    <skip />
+    <!-- no translation found for heavy_weight_notification (9087063985776626166) -->
+    <skip />
+    <!-- no translation found for heavy_weight_notification_detail (1721681741617898865) -->
+    <skip />
+    <!-- no translation found for heavy_weight_switcher_title (7153167085403298169) -->
+    <skip />
+    <!-- no translation found for heavy_weight_switcher_text (7022631924534406403) -->
+    <skip />
+    <!-- no translation found for old_app_action (493129172238566282) -->
+    <skip />
+    <!-- no translation found for old_app_description (2082094275580358049) -->
+    <skip />
+    <!-- no translation found for new_app_action (5472756926945440706) -->
+    <skip />
+    <!-- no translation found for new_app_description (1932143598371537340) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification (2618183274836056542) -->
+    <skip />
+    <!-- no translation found for dump_heap_notification_detail (2075673362317481664) -->
+    <skip />
+    <!-- no translation found for dump_heap_title (5864292264307651673) -->
+    <skip />
+    <!-- no translation found for dump_heap_text (4809417337240334941) -->
+    <skip />
+    <!-- no translation found for sendText (5209874571959469142) -->
+    <skip />
+    <!-- no translation found for volume_ringtone (6885421406845734650) -->
+    <skip />
+    <!-- no translation found for volume_music (5421651157138628171) -->
+    <skip />
+    <!-- no translation found for volume_music_hint_playing_through_bluetooth (9165984379394601533) -->
+    <skip />
+    <!-- no translation found for volume_music_hint_silent_ringtone_selected (8310739960973156272) -->
+    <skip />
+    <!-- no translation found for volume_call (3941680041282788711) -->
+    <skip />
+    <!-- no translation found for volume_bluetooth_call (2002891926351151534) -->
+    <skip />
+    <!-- no translation found for volume_alarm (1985191616042689100) -->
+    <skip />
+    <!-- no translation found for volume_notification (2422265656744276715) -->
+    <skip />
+    <!-- no translation found for volume_unknown (1400219669770445902) -->
+    <skip />
+    <!-- no translation found for volume_icon_description_bluetooth (6538894177255964340) -->
+    <skip />
+    <!-- no translation found for volume_icon_description_ringer (3326003847006162496) -->
+    <skip />
+    <!-- no translation found for volume_icon_description_incall (8890073218154543397) -->
+    <skip />
+    <!-- no translation found for volume_icon_description_media (4217311719665194215) -->
+    <skip />
+    <!-- no translation found for volume_icon_description_notification (7044986546477282274) -->
+    <skip />
+    <!-- no translation found for ringtone_default (3789758980357696936) -->
+    <skip />
+    <!-- no translation found for ringtone_default_with_actual (8129563480895990372) -->
+    <skip />
+    <!-- no translation found for ringtone_silent (7937634392408977062) -->
+    <skip />
+    <!-- no translation found for ringtone_picker_title (3515143939175119094) -->
+    <skip />
+    <!-- no translation found for ringtone_unknown (5477919988701784788) -->
+    <skip />
+    <!-- no translation found for wifi_available (7900333017752027322) -->
+    <!-- no translation found for wifi_available_detailed (1140699367193975606) -->
+    <!-- no translation found for wifi_available_sign_in (9157196203958866662) -->
+    <skip />
+    <!-- no translation found for network_available_sign_in (1848877297365446605) -->
+    <skip />
+    <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
+    <skip />
+    <!-- no translation found for wifi_no_internet (8451173622563841546) -->
+    <skip />
+    <!-- no translation found for wifi_no_internet_detailed (7593858887662270131) -->
+    <skip />
+    <!-- no translation found for wifi_watchdog_network_disabled (7904214231651546347) -->
+    <skip />
+    <!-- no translation found for wifi_watchdog_network_disabled_detailed (5548780776418332675) -->
+    <skip />
+    <!-- no translation found for wifi_connect_alert_title (8455846016001810172) -->
+    <skip />
+    <!-- no translation found for wifi_connect_alert_message (6451273376815958922) -->
+    <skip />
+    <!-- no translation found for wifi_connect_default_application (7143109390475484319) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_dialog_title (97611782659324517) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_turnon_message (2909250942299627244) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_failed_message (3763669677935623084) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_enabled_notification_title (2068321881673734886) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_enabled_notification_message (1638949953993894335) -->
+    <skip />
+    <!-- no translation found for accept (1645267259272829559) -->
+    <skip />
+    <!-- no translation found for decline (2112225451706137894) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_invitation_sent_title (1318975185112070734) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_invitation_to_connect_title (4958803948658533637) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_from_message (570389174731951769) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_to_message (248968974522044099) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_enter_pin_message (5920929550367828970) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_show_pin_message (8530563323880921094) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_frequency_conflict_message (8012981257742232475) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_frequency_conflict_message (3087858235069421128) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_frequency_conflict_message (7363907213787469151) -->
+    <skip />
+    <!-- no translation found for select_character (3365550120617701745) -->
+    <skip />
+    <!-- no translation found for sms_control_title (7296612781128917719) -->
+    <skip />
+    <!-- no translation found for sms_control_message (3867899169651496433) -->
+    <skip />
+    <!-- no translation found for sms_control_yes (3663725993855816807) -->
+    <skip />
+    <!-- no translation found for sms_control_no (625438561395534982) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_message (1645436466285310855) -->
+    <skip />
+    <!-- no translation found for sms_short_code_details (5873295990846059400) -->
+    <skip />
+    <!-- no translation found for sms_premium_short_code_details (7869234868023975) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_allow (4458878637111023413) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_deny (2927389840209170706) -->
+    <skip />
+    <!-- no translation found for sms_short_code_remember_choice (5289538592272218136) -->
+    <skip />
+    <!-- no translation found for sms_short_code_remember_undo_instruction (4960944133052287484) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_always_allow (3241181154869493368) -->
+    <skip />
+    <!-- no translation found for sms_short_code_confirm_never_allow (446992765774269673) -->
+    <skip />
+    <!-- no translation found for sim_removed_title (6227712319223226185) -->
+    <skip />
+    <!-- no translation found for sim_removed_message (5450336489923274918) -->
+    <skip />
+    <!-- no translation found for sim_done_button (827949989369963775) -->
+    <skip />
+    <!-- no translation found for sim_added_title (3719670512889674693) -->
+    <skip />
+    <!-- no translation found for sim_added_message (7797975656153714319) -->
+    <skip />
+    <!-- no translation found for sim_restart_button (4722407842815232347) -->
+    <skip />
+    <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+    <skip />
+    <!-- no translation found for date_picker_dialog_title (5879450659453782278) -->
+    <skip />
+    <!-- no translation found for date_time_set (5777075614321087758) -->
+    <skip />
+    <!-- no translation found for date_time_done (2507683751759308828) -->
+    <skip />
+    <!-- no translation found for perms_new_perm_prefix (8257740710754301407) -->
+    <skip />
+    <!-- no translation found for perms_description_app (5139836143293299417) -->
+    <skip />
+    <!-- no translation found for no_permissions (7283357728219338112) -->
+    <skip />
+    <!-- no translation found for perm_costs_money (4902470324142151116) -->
+    <skip />
+    <!-- no translation found for dlg_ok (7376953167039865701) -->
+    <skip />
+    <!-- no translation found for usb_charging_notification_title (4004114449249406402) -->
+    <skip />
+    <!-- no translation found for usb_mtp_notification_title (8396264943589760855) -->
+    <skip />
+    <!-- no translation found for usb_ptp_notification_title (1347328437083192112) -->
+    <skip />
+    <!-- no translation found for usb_midi_notification_title (4850904915889144654) -->
+    <skip />
+    <!-- no translation found for usb_accessory_notification_title (7848236974087653666) -->
+    <skip />
+    <!-- no translation found for usb_notification_message (7347368030849048437) -->
+    <skip />
+    <!-- no translation found for adb_active_notification_title (6729044778949189918) -->
+    <skip />
+    <!-- no translation found for adb_active_notification_message (1016654627626476142) -->
+    <skip />
+    <!-- no translation found for share_remote_bugreport_notification_title (3116061729914615290) -->
+    <skip />
+    <!-- no translation found for share_remote_bugreport_notification_message (1310517845557771773) -->
+    <skip />
+    <!-- no translation found for share_remote_bugreport_notification_accept (8203856129078669677) -->
+    <skip />
+    <!-- no translation found for share_remote_bugreport_notification_decline (6337969352057443969) -->
+    <skip />
+    <!-- no translation found for remote_bugreport_progress_notification_title (2785600634417078622) -->
+    <skip />
+    <!-- no translation found for remote_bugreport_progress_notification_message_can_cancel (5743435483005099451) -->
+    <skip />
+    <!-- no translation found for select_input_method (8547250819326693584) -->
+    <skip />
+    <!-- no translation found for configure_input_methods (4769971288371946846) -->
+    <skip />
+    <!-- no translation found for show_ime (2506087537466597099) -->
+    <skip />
+    <!-- no translation found for hardware (194658061510127999) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_title (1407367017263030773) -->
+    <skip />
+    <!-- no translation found for select_keyboard_layout_notification_message (4465907700449257063) -->
+    <skip />
+    <!-- no translation found for fast_scroll_alphabet (5433275485499039199) -->
+    <skip />
+    <!-- no translation found for fast_scroll_numeric_alphabet (4030170524595123610) -->
+    <skip />
+    <!-- no translation found for candidates_style (4333913089637062257) -->
+    <skip />
+    <!-- no translation found for ext_media_checking_notification_title (5734005953288045806) -->
+    <skip />
+    <!-- no translation found for ext_media_checking_notification_message (4747432538578886744) -->
+    <skip />
+    <!-- no translation found for ext_media_new_notification_message (7589986898808506239) -->
+    <skip />
+    <!-- no translation found for ext_media_ready_notification_message (4083398150380114462) -->
+    <skip />
+    <!-- no translation found for ext_media_unmountable_notification_title (8295123366236989588) -->
+    <skip />
+    <!-- no translation found for ext_media_unmountable_notification_message (1586311304430052169) -->
+    <skip />
+    <!-- no translation found for ext_media_unsupported_notification_title (3797642322958803257) -->
+    <skip />
+    <!-- no translation found for ext_media_unsupported_notification_message (8789610369456474891) -->
+    <skip />
+    <!-- no translation found for ext_media_badremoval_notification_title (3206248947375505416) -->
+    <skip />
+    <!-- no translation found for ext_media_badremoval_notification_message (380176703346946313) -->
+    <skip />
+    <!-- no translation found for ext_media_nomedia_notification_title (1704840188641749091) -->
+    <skip />
+    <!-- no translation found for ext_media_nomedia_notification_message (6471542972147056586) -->
+    <skip />
+    <!-- no translation found for ext_media_unmounting_notification_title (640674168454809372) -->
+    <skip />
+    <!-- no translation found for ext_media_unmounting_notification_message (4182843895023357756) -->
+    <skip />
+    <!-- no translation found for ext_media_init_action (7952885510091978278) -->
+    <skip />
+    <!-- no translation found for ext_media_unmount_action (1121883233103278199) -->
+    <skip />
+    <!-- no translation found for ext_media_browse_action (8322172381028546087) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_title (620980315821543904) -->
+    <skip />
+    <!-- no translation found for ext_media_missing_message (5761133583368750174) -->
+    <skip />
+    <!-- no translation found for ext_media_move_specific_title (1471100343872375842) -->
+    <skip />
+    <!-- no translation found for ext_media_move_title (1022809140035962662) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_title (8575300932957954671) -->
+    <skip />
+    <!-- no translation found for ext_media_move_success_message (4199002148206265426) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_title (7613189040358789908) -->
+    <skip />
+    <!-- no translation found for ext_media_move_failure_message (1978096440816403360) -->
+    <skip />
+    <!-- no translation found for ext_media_status_removed (6576172423185918739) -->
+    <skip />
+    <!-- no translation found for ext_media_status_unmounted (2551560878416417752) -->
+    <skip />
+    <!-- no translation found for ext_media_status_checking (6193921557423194949) -->
+    <skip />
+    <!-- no translation found for ext_media_status_mounted (7253821726503179202) -->
+    <skip />
+    <!-- no translation found for ext_media_status_mounted_ro (8020978752406021015) -->
+    <skip />
+    <!-- no translation found for ext_media_status_bad_removal (8395398567890329422) -->
+    <skip />
+    <!-- no translation found for ext_media_status_unmountable (805594039236667894) -->
+    <skip />
+    <!-- no translation found for ext_media_status_unsupported (4691436711745681828) -->
+    <skip />
+    <!-- no translation found for ext_media_status_ejecting (5463887263101234174) -->
+    <skip />
+    <!-- no translation found for ext_media_status_formatting (1085079556538644861) -->
+    <skip />
+    <!-- no translation found for ext_media_status_missing (5638633895221670766) -->
+    <skip />
+    <!-- no translation found for activity_list_empty (1675388330786841066) -->
+    <skip />
+    <!-- no translation found for permlab_route_media_output (6243022988998972085) -->
+    <skip />
+    <!-- no translation found for permdesc_route_media_output (4932818749547244346) -->
+    <skip />
+    <!-- no translation found for permlab_readInstallSessions (3713753067455750349) -->
+    <skip />
+    <!-- no translation found for permdesc_readInstallSessions (2049771699626019849) -->
+    <skip />
+    <!-- no translation found for permlab_requestInstallPackages (5782013576218172577) -->
+    <skip />
+    <!-- no translation found for permdesc_requestInstallPackages (5740101072486783082) -->
+    <skip />
+    <!-- no translation found for tutorial_double_tap_to_zoom_message_short (4070433208160063538) -->
+    <skip />
+    <!-- no translation found for gadget_host_error_inflating (4882004314906466162) -->
+    <skip />
+    <!-- no translation found for ime_action_go (8320845651737369027) -->
+    <skip />
+    <!-- no translation found for ime_action_search (658110271822807811) -->
+    <skip />
+    <!-- no translation found for ime_action_send (2316166556349314424) -->
+    <skip />
+    <!-- no translation found for ime_action_next (3138843904009813834) -->
+    <skip />
+    <!-- no translation found for ime_action_done (8971516117910934605) -->
+    <skip />
+    <!-- no translation found for ime_action_previous (1443550039250105948) -->
+    <skip />
+    <!-- no translation found for ime_action_default (2840921885558045721) -->
+    <skip />
+    <!-- no translation found for dial_number_using (5789176425167573586) -->
+    <skip />
+    <!-- no translation found for create_contact_using (4947405226788104538) -->
+    <skip />
+    <!-- no translation found for grant_credentials_permission_message_header (2106103817937859662) -->
+    <skip />
+    <!-- no translation found for grant_credentials_permission_message_footer (3125211343379376561) -->
+    <skip />
+    <!-- no translation found for grant_permissions_header_text (6874497408201826708) -->
+    <skip />
+    <!-- no translation found for allow (7225948811296386551) -->
+    <skip />
+    <!-- no translation found for deny (2081879885755434506) -->
+    <skip />
+    <!-- no translation found for permission_request_notification_title (6486759795926237907) -->
+    <skip />
+    <!-- no translation found for permission_request_notification_with_subtitle (8530393139639560189) -->
+    <skip />
+    <!-- no translation found for forward_intent_to_owner (1207197447013960896) -->
+    <skip />
+    <!-- no translation found for forward_intent_to_work (621480743856004612) -->
+    <skip />
+    <!-- no translation found for input_method_binding_label (1283557179944992649) -->
+    <skip />
+    <!-- no translation found for sync_binding_label (3687969138375092423) -->
+    <skip />
+    <!-- no translation found for accessibility_binding_label (4148120742096474641) -->
+    <skip />
+    <!-- no translation found for wallpaper_binding_label (1240087844304687662) -->
+    <skip />
+    <!-- no translation found for chooser_wallpaper (7873476199295190279) -->
+    <skip />
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
+    <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
+    <skip />
+    <!-- no translation found for notification_assistant_binding_label (909456055569102952) -->
+    <skip />
+    <!-- no translation found for vpn_title (19615213552042827) -->
+    <skip />
+    <!-- no translation found for vpn_title_long (6400714798049252294) -->
+    <skip />
+    <!-- no translation found for vpn_text (3011306607126450322) -->
+    <skip />
+    <!-- no translation found for vpn_text_long (6407351006249174473) -->
+    <skip />
+    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
+    <skip />
+    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
+    <skip />
+    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
+    <skip />
+    <!-- no translation found for vpn_lockdown_config (6415899150671537970) -->
+    <skip />
+    <!-- no translation found for upload_file (2897957172366730416) -->
+    <skip />
+    <!-- no translation found for no_file_chosen (6363648562170759465) -->
+    <skip />
+    <!-- no translation found for reset (2448168080964209908) -->
+    <skip />
+    <!-- no translation found for submit (1602335572089911941) -->
+    <skip />
+    <!-- no translation found for car_mode_disable_notification_title (3164768212003864316) -->
+    <skip />
+    <!-- no translation found for car_mode_disable_notification_message (8035230537563503262) -->
+    <skip />
+    <!-- no translation found for tethered_notification_title (3146694234398202601) -->
+    <skip />
+    <!-- no translation found for tethered_notification_message (6857031760103062982) -->
+    <skip />
+    <!-- no translation found for back_button_label (2300470004503343439) -->
+    <skip />
+    <!-- no translation found for next_button_label (1080555104677992408) -->
+    <skip />
+    <!-- no translation found for skip_button_label (1275362299471631819) -->
+    <skip />
+    <!-- no translation found for no_matches (8129421908915840737) -->
+    <skip />
+    <!-- no translation found for find_on_page (1946799233822820384) -->
+    <skip />
+    <!-- no translation found for matches_found (1210884353962081884) -->
+    <!-- no translation found for action_mode_done (7217581640461922289) -->
+    <skip />
+    <!-- no translation found for progress_erasing (4521573321524340058) -->
+    <skip />
+    <!-- no translation found for progress_erasing (6596988875507043042) -->
+    <skip />
+    <!-- no translation found for share (1778686618230011964) -->
+    <skip />
+    <!-- no translation found for find (4808270900322985960) -->
+    <skip />
+    <!-- no translation found for websearch (4337157977400211589) -->
+    <skip />
+    <!-- no translation found for find_next (5742124618942193978) -->
+    <skip />
+    <!-- no translation found for find_previous (2196723669388360506) -->
+    <skip />
+    <!-- no translation found for gpsNotifTicker (5622683912616496172) -->
+    <skip />
+    <!-- no translation found for gpsNotifTitle (5446858717157416839) -->
+    <skip />
+    <!-- no translation found for gpsNotifMessage (1374718023224000702) -->
+    <skip />
+    <!-- no translation found for gpsVerifYes (2346566072867213563) -->
+    <skip />
+    <!-- no translation found for gpsVerifNo (1146564937346454865) -->
+    <skip />
+    <!-- no translation found for sync_too_many_deletes (5296321850662746890) -->
+    <skip />
+    <!-- no translation found for sync_too_many_deletes_desc (496551671008694245) -->
+    <skip />
+    <!-- no translation found for sync_really_delete (2572600103122596243) -->
+    <skip />
+    <!-- no translation found for sync_undo_deletes (2941317360600338602) -->
+    <skip />
+    <!-- no translation found for sync_do_nothing (3743764740430821845) -->
+    <skip />
+    <!-- no translation found for choose_account_label (5655203089746423927) -->
+    <skip />
+    <!-- no translation found for add_account_label (2935267344849993553) -->
+    <skip />
+    <!-- no translation found for add_account_button_label (3611982894853435874) -->
+    <skip />
+    <!-- no translation found for number_picker_increment_button (2412072272832284313) -->
+    <skip />
+    <!-- no translation found for number_picker_decrement_button (476050778386779067) -->
+    <skip />
+    <!-- no translation found for number_picker_increment_scroll_mode (3073101067441638428) -->
+    <skip />
+    <!-- no translation found for number_picker_increment_scroll_action (9101473045891835490) -->
+    <skip />
+    <!-- no translation found for time_picker_increment_minute_button (8865885114028614321) -->
+    <skip />
+    <!-- no translation found for time_picker_decrement_minute_button (6246834937080684791) -->
+    <skip />
+    <!-- no translation found for time_picker_increment_hour_button (3652056055810223139) -->
+    <skip />
+    <!-- no translation found for time_picker_decrement_hour_button (1377479863429214792) -->
+    <skip />
+    <!-- no translation found for time_picker_increment_set_pm_button (4147590696151230863) -->
+    <skip />
+    <!-- no translation found for time_picker_decrement_set_am_button (8302140353539486752) -->
+    <skip />
+    <!-- no translation found for date_picker_increment_month_button (5369998479067934110) -->
+    <skip />
+    <!-- no translation found for date_picker_decrement_month_button (1832698995541726019) -->
+    <skip />
+    <!-- no translation found for date_picker_increment_day_button (7130465412308173903) -->
+    <skip />
+    <!-- no translation found for date_picker_decrement_day_button (4131881521818750031) -->
+    <skip />
+    <!-- no translation found for date_picker_increment_year_button (6318697384310808899) -->
+    <skip />
+    <!-- no translation found for date_picker_decrement_year_button (4482021813491121717) -->
+    <skip />
+    <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+    <skip />
+    <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+    <skip />
+    <!-- no translation found for keyboardview_keycode_alt (4856868820040051939) -->
+    <skip />
+    <!-- no translation found for keyboardview_keycode_cancel (1203984017245783244) -->
+    <skip />
+    <!-- no translation found for keyboardview_keycode_delete (3337914833206635744) -->
+    <skip />
+    <!-- no translation found for keyboardview_keycode_done (1992571118466679775) -->
+    <skip />
+    <!-- no translation found for keyboardview_keycode_mode_change (4547387741906537519) -->
+    <skip />
+    <!-- no translation found for keyboardview_keycode_shift (2270748814315147690) -->
+    <skip />
+    <!-- no translation found for keyboardview_keycode_enter (2985864015076059467) -->
+    <skip />
+    <!-- no translation found for activitychooserview_choose_application (2125168057199941199) -->
+    <skip />
+    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
+    <skip />
+    <!-- no translation found for shareactionprovider_share_with (806688056141131819) -->
+    <skip />
+    <!-- no translation found for shareactionprovider_share_with_application (5627411384638389738) -->
+    <skip />
+    <!-- no translation found for content_description_sliding_handle (415975056159262248) -->
+    <skip />
+    <!-- no translation found for description_target_unlock_tablet (3833195335629795055) -->
+    <skip />
+    <!-- no translation found for keyboard_headset_required_to_hear_password (7011927352267668657) -->
+    <skip />
+    <!-- no translation found for keyboard_password_character_no_headset (2859873770886153678) -->
+    <skip />
+    <!-- no translation found for action_bar_home_description (5293600496601490216) -->
+    <skip />
+    <!-- no translation found for action_bar_up_description (2237496562952152589) -->
+    <skip />
+    <!-- no translation found for action_menu_overflow_description (2295659037509008453) -->
+    <skip />
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
+    <!-- no translation found for storage_internal (4891916833657929263) -->
+    <skip />
+    <!-- no translation found for storage_sd_card (3282948861378286745) -->
+    <skip />
+    <!-- no translation found for storage_sd_card_label (6347111320774379257) -->
+    <skip />
+    <!-- no translation found for storage_usb_drive (6261899683292244209) -->
+    <skip />
+    <!-- no translation found for storage_usb_drive_label (4501418548927759953) -->
+    <skip />
+    <!-- no translation found for storage_usb (3017954059538517278) -->
+    <skip />
+    <!-- no translation found for extract_edit_menu_button (8940478730496610137) -->
+    <skip />
+    <!-- no translation found for data_usage_warning_title (1955638862122232342) -->
+    <skip />
+    <!-- no translation found for data_usage_warning_body (2814673551471969954) -->
+    <skip />
+    <!-- no translation found for data_usage_3g_limit_title (4361523876818447683) -->
+    <skip />
+    <!-- no translation found for data_usage_4g_limit_title (4609566827219442376) -->
+    <skip />
+    <!-- no translation found for data_usage_mobile_limit_title (557158376602636112) -->
+    <skip />
+    <!-- no translation found for data_usage_wifi_limit_title (5803363779034792676) -->
+    <skip />
+    <!-- no translation found for data_usage_limit_body (291731708279614081) -->
+    <skip />
+    <!-- no translation found for data_usage_3g_limit_snoozed_title (7026739121138005231) -->
+    <skip />
+    <!-- no translation found for data_usage_4g_limit_snoozed_title (1106562779311209039) -->
+    <skip />
+    <!-- no translation found for data_usage_mobile_limit_snoozed_title (4941346653729943789) -->
+    <skip />
+    <!-- no translation found for data_usage_wifi_limit_snoozed_title (8743856006384825974) -->
+    <skip />
+    <!-- no translation found for data_usage_limit_snoozed_body (7035490278298441767) -->
+    <skip />
+    <!-- no translation found for data_usage_restricted_title (5965157361036321914) -->
+    <skip />
+    <!-- no translation found for data_usage_restricted_body (6741521330997452990) -->
+    <skip />
+    <!-- no translation found for ssl_certificate (6510040486049237639) -->
+    <skip />
+    <!-- no translation found for ssl_certificate_is_valid (6825263250774569373) -->
+    <skip />
+    <!-- no translation found for issued_to (454239480274921032) -->
+    <skip />
+    <!-- no translation found for common_name (2233209299434172646) -->
+    <skip />
+    <!-- no translation found for org_name (6973561190762085236) -->
+    <skip />
+    <!-- no translation found for org_unit (7265981890422070383) -->
+    <skip />
+    <!-- no translation found for issued_by (2647584988057481566) -->
+    <skip />
+    <!-- no translation found for validity_period (8818886137545983110) -->
+    <skip />
+    <!-- no translation found for issued_on (5895017404361397232) -->
+    <skip />
+    <!-- no translation found for expires_on (3676242949915959821) -->
+    <skip />
+    <!-- no translation found for serial_number (758814067660862493) -->
+    <skip />
+    <!-- no translation found for fingerprints (4516019619850763049) -->
+    <skip />
+    <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
+    <skip />
+    <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
+    <skip />
+    <!-- no translation found for activity_chooser_view_see_all (4292569383976636200) -->
+    <skip />
+    <!-- no translation found for activity_chooser_view_dialog_title_default (4710013864974040615) -->
+    <skip />
+    <!-- no translation found for share_action_provider_share_with (5247684435979149216) -->
+    <skip />
+    <!-- no translation found for sending (3245653681008218030) -->
+    <skip />
+    <!-- no translation found for launchBrowserDefault (2057951947297614725) -->
+    <skip />
+    <!-- no translation found for SetupCallDefault (5834948469253758575) -->
+    <skip />
+    <!-- no translation found for activity_resolver_use_always (8017770747801494933) -->
+    <skip />
+    <!-- no translation found for activity_resolver_use_once (2404644797149173758) -->
+    <skip />
+    <!-- no translation found for activity_resolver_work_profiles_support (185598180676883455) -->
+    <skip />
+    <!-- no translation found for default_audio_route_name (4617053898167127471) -->
+    <skip />
+    <!-- no translation found for default_audio_route_name (9158088547603019321) -->
+    <skip />
+    <!-- no translation found for default_audio_route_name (4239291273420140123) -->
+    <skip />
+    <!-- no translation found for default_audio_route_name_headphones (8119971843803439110) -->
+    <skip />
+    <!-- no translation found for default_audio_route_name_dock_speakers (6240602982276591864) -->
+    <skip />
+    <!-- no translation found for default_media_route_name_hdmi (2450970399023478055) -->
+    <skip />
+    <!-- no translation found for default_audio_route_category_name (3722811174003886946) -->
+    <skip />
+    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
+    <skip />
+    <!-- no translation found for wireless_display_route_description (9070346425023979651) -->
+    <skip />
+    <!-- no translation found for media_route_button_content_description (591703006349356016) -->
+    <skip />
+    <!-- no translation found for media_route_chooser_title (1751618554539087622) -->
+    <skip />
+    <!-- no translation found for media_route_chooser_title_for_remote_display (3395541745872017583) -->
+    <skip />
+    <!-- no translation found for media_route_chooser_searching (4776236202610828706) -->
+    <skip />
+    <!-- no translation found for media_route_chooser_extended_settings (87015534236701604) -->
+    <skip />
+    <!-- no translation found for media_route_controller_disconnect (8966120286374158649) -->
+    <skip />
+    <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
+    <skip />
+    <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
+    <skip />
+    <!-- no translation found for media_route_status_available (6983258067194649391) -->
+    <skip />
+    <!-- no translation found for media_route_status_not_available (6739899962681886401) -->
+    <skip />
+    <!-- no translation found for media_route_status_in_use (4533786031090198063) -->
+    <skip />
+    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <skip />
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
+    <skip />
+    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <skip />
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
+    <skip />
+    <!-- no translation found for display_manager_overlay_display_secure_suffix (6022119702628572080) -->
+    <skip />
+    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
+    <skip />
+    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
+    <skip />
+    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
+    <skip />
+    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
+    <skip />
+    <!-- no translation found for kg_too_many_failed_attempts_countdown (6358110221603297548) -->
+    <skip />
+    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
+    <skip />
+    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
+    <skip />
+    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
+    <skip />
+    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
+    <skip />
+    <!-- no translation found for kg_puk_enter_puk_hint (453227143861735537) -->
+    <skip />
+    <!-- no translation found for kg_puk_enter_pin_hint (7871604527429602024) -->
+    <skip />
+    <!-- no translation found for kg_enter_confirm_pin_hint (325676184762529976) -->
+    <skip />
+    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
+    <skip />
+    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
+    <skip />
+    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
+    <skip />
+    <!-- no translation found for kg_invalid_sim_puk_hint (6025069204539532000) -->
+    <skip />
+    <!-- no translation found for kg_invalid_puk (3638289409676051243) -->
+    <skip />
+    <!-- no translation found for kg_invalid_confirm_pin_hint (7003469261464593516) -->
+    <skip />
+    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
+    <skip />
+    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
+    <skip />
+    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
+    <skip />
+    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
+    <skip />
+    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
+    <skip />
+    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
+    <skip />
+    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
+    <skip />
+    <!-- no translation found for kg_login_checking_password (1052685197710252395) -->
+    <skip />
+    <!-- no translation found for kg_too_many_failed_pin_attempts_dialog_message (8276745642049502550) -->
+    <skip />
+    <!-- no translation found for kg_too_many_failed_password_attempts_dialog_message (7813713389422226531) -->
+    <skip />
+    <!-- no translation found for kg_too_many_failed_pattern_attempts_dialog_message (74089475965050805) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_almost_at_wipe (1575557200627128949) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_almost_at_wipe (5621231220154419413) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_almost_at_wipe (4051015943038199910) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_now_wiping (2072996269148483637) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_now_wiping (4987878286750741463) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_now_wiping (4817627474419471518) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_almost_at_login (3253575572118914370) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_almost_at_login (4224651132862313471) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_almost_at_login (1437638152015574839) -->
+    <skip />
+    <!-- no translation found for kg_text_message_separator (4160700433287233771) -->
+    <skip />
+    <!-- no translation found for kg_reordering_delete_drop_target_text (7899202978204438708) -->
+    <skip />
+    <!-- no translation found for safe_media_volume_warning (2276318909314492312) -->
+    <skip />
+    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
+    <skip />
+    <!-- no translation found for accessibility_enabled (1381972048564547685) -->
+    <skip />
+    <!-- no translation found for enable_accessibility_canceled (3833923257966635673) -->
+    <skip />
+    <!-- no translation found for user_switched (3768006783166984410) -->
+    <skip />
+    <!-- no translation found for user_switching_message (2871009331809089783) -->
+    <skip />
+    <!-- no translation found for user_logging_out_message (8939524935808875155) -->
+    <skip />
+    <!-- no translation found for owner_name (2716755460376028154) -->
+    <!-- no translation found for owner_name (3879126011135546571) -->
+    <skip />
+    <!-- no translation found for error_message_title (4510373083082500195) -->
+    <skip />
+    <!-- no translation found for error_message_change_not_allowed (1347282344200417578) -->
+    <skip />
+    <!-- no translation found for app_not_found (3429141853498927379) -->
+    <skip />
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_a0 (1994474252931294172) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_a1 (3333060421529791786) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_a2 (3097535991925798280) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_a3 (3023213259314236123) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_a4 (231745325296873764) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_a5 (3484327407340865411) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_a6 (4861908487129577530) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_a7 (5890208588072936130) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_a8 (4319425041085816612) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_a9 (4882220529506432008) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_a10 (2382866026365359391) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_b0 (3651827147402009675) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_b1 (6072859628278739957) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_b2 (1348731852150380378) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_b3 (2612510181259261379) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_b4 (695151378838115434) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_b5 (4863754285582212487) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_b6 (5305816292139647241) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_b7 (531673542602786624) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_b8 (9164474595708850034) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_b9 (282102976764774160) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_b10 (4517141714407898976) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_c0 (3103521357901591100) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_c1 (1231954105985048595) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_c2 (927702816980087462) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_c3 (835154173518304159) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_c4 (5095951985108194011) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_c5 (1985397450332305739) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_c6 (8147421924174693013) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_c7 (8993994925276122950) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_c8 (6871178104139598957) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_c9 (7983532635227561362) -->
+    <skip />
+    <!-- no translation found for mediasize_iso_c10 (5040764293406765584) -->
+    <skip />
+    <!-- no translation found for mediasize_na_letter (2841414839888344296) -->
+    <skip />
+    <!-- no translation found for mediasize_na_gvrnmt_letter (5295836838862962809) -->
+    <skip />
+    <!-- no translation found for mediasize_na_legal (8621364037680465666) -->
+    <skip />
+    <!-- no translation found for mediasize_na_junior_legal (3309324162155085904) -->
+    <skip />
+    <!-- no translation found for mediasize_na_ledger (5567030340509075333) -->
+    <skip />
+    <!-- no translation found for mediasize_na_tabloid (4571735038501661757) -->
+    <skip />
+    <!-- no translation found for mediasize_na_index_3x5 (5182901917818625126) -->
+    <skip />
+    <!-- no translation found for mediasize_na_index_4x6 (7687620625422312396) -->
+    <skip />
+    <!-- no translation found for mediasize_na_index_5x8 (8834215284646872800) -->
+    <skip />
+    <!-- no translation found for mediasize_na_monarch (213639906956550754) -->
+    <skip />
+    <!-- no translation found for mediasize_na_quarto (835778493593023223) -->
+    <skip />
+    <!-- no translation found for mediasize_na_foolscap (1573911237983677138) -->
+    <skip />
+    <!-- no translation found for mediasize_chinese_roc_8k (3626855847189438896) -->
+    <skip />
+    <!-- no translation found for mediasize_chinese_roc_16k (9182191577022943355) -->
+    <skip />
+    <!-- no translation found for mediasize_chinese_prc_1 (4793232644980170500) -->
+    <skip />
+    <!-- no translation found for mediasize_chinese_prc_2 (5404109730975720670) -->
+    <skip />
+    <!-- no translation found for mediasize_chinese_prc_3 (1335092253339363526) -->
+    <skip />
+    <!-- no translation found for mediasize_chinese_prc_4 (9167997800486569834) -->
+    <skip />
+    <!-- no translation found for mediasize_chinese_prc_5 (845875168823541497) -->
+    <skip />
+    <!-- no translation found for mediasize_chinese_prc_6 (3220325667692648789) -->
+    <skip />
+    <!-- no translation found for mediasize_chinese_prc_7 (1776792138507038527) -->
+    <skip />
+    <!-- no translation found for mediasize_chinese_prc_8 (1417176642687456692) -->
+    <skip />
+    <!-- no translation found for mediasize_chinese_prc_9 (4785983473123798365) -->
+    <skip />
+    <!-- no translation found for mediasize_chinese_prc_10 (7847982299391851899) -->
+    <skip />
+    <!-- no translation found for mediasize_chinese_prc_16k (262793383539980677) -->
+    <skip />
+    <!-- no translation found for mediasize_chinese_om_pa_kai (5256815579447959814) -->
+    <skip />
+    <!-- no translation found for mediasize_chinese_om_dai_pa_kai (7336412963441354407) -->
+    <skip />
+    <!-- no translation found for mediasize_chinese_om_jurro_ku_kai (6324465444100490742) -->
+    <skip />
+    <!-- no translation found for mediasize_japanese_jis_b10 (1787262845627694376) -->
+    <skip />
+    <!-- no translation found for mediasize_japanese_jis_b9 (3336035783663287470) -->
+    <skip />
+    <!-- no translation found for mediasize_japanese_jis_b8 (6195398299104345731) -->
+    <skip />
+    <!-- no translation found for mediasize_japanese_jis_b7 (1674621886902828884) -->
+    <skip />
+    <!-- no translation found for mediasize_japanese_jis_b6 (4170576286062657435) -->
+    <skip />
+    <!-- no translation found for mediasize_japanese_jis_b5 (4899297958100032533) -->
+    <skip />
+    <!-- no translation found for mediasize_japanese_jis_b4 (4213158129126666847) -->
+    <skip />
+    <!-- no translation found for mediasize_japanese_jis_b3 (8513715307410310696) -->
+    <skip />
+    <!-- no translation found for mediasize_japanese_jis_b2 (4777690211897131190) -->
+    <skip />
+    <!-- no translation found for mediasize_japanese_jis_b1 (4608142385457034603) -->
+    <skip />
+    <!-- no translation found for mediasize_japanese_jis_b0 (7587108366572243991) -->
+    <skip />
+    <!-- no translation found for mediasize_japanese_jis_exec (5244075432263649068) -->
+    <skip />
+    <!-- no translation found for mediasize_japanese_chou4 (4941652015032631361) -->
+    <skip />
+    <!-- no translation found for mediasize_japanese_chou3 (6387319169263957010) -->
+    <skip />
+    <!-- no translation found for mediasize_japanese_chou2 (1299112025415343982) -->
+    <skip />
+    <!-- no translation found for mediasize_japanese_hagaki (8070115620644254565) -->
+    <skip />
+    <!-- no translation found for mediasize_japanese_oufuku (6049065587307896564) -->
+    <skip />
+    <!-- no translation found for mediasize_japanese_kahu (6872696027560065173) -->
+    <skip />
+    <!-- no translation found for mediasize_japanese_kaku2 (2359077233775455405) -->
+    <skip />
+    <!-- no translation found for mediasize_japanese_you4 (2091777168747058008) -->
+    <skip />
+    <!-- no translation found for mediasize_unknown_portrait (3088043641616409762) -->
+    <skip />
+    <!-- no translation found for mediasize_unknown_landscape (4876995327029361552) -->
+    <skip />
+    <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
+    <skip />
+    <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
+    <skip />
+    <!-- no translation found for reason_unknown (6048913880184628119) -->
+    <skip />
+    <!-- no translation found for reason_service_unavailable (7824008732243903268) -->
+    <skip />
+    <!-- no translation found for print_service_installed_title (2246317169444081628) -->
+    <skip />
+    <!-- no translation found for print_service_installed_message (5897362931070459152) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_admin_pin (783643731895143970) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
+    <skip />
+    <!-- no translation found for restr_pin_incorrect (8571512003955077924) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
+    <skip />
+    <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
+    <skip />
+    <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
+    <skip />
+    <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
+    <skip />
+    <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
+    <skip />
+    <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
+    <skip />
+    <!-- no translation found for restr_pin_countdown (9061246974881224688) -->
+    <!-- no translation found for restr_pin_try_later (973144472490532377) -->
+    <skip />
+    <!-- no translation found for immersive_cling_title (8394201622932303336) -->
+    <skip />
+    <!-- no translation found for immersive_cling_description (3482371193207536040) -->
+    <skip />
+    <!-- no translation found for immersive_cling_positive (5016839404568297683) -->
+    <skip />
+    <!-- no translation found for done_label (2093726099505892398) -->
+    <skip />
+    <!-- no translation found for hour_picker_description (6698199186859736512) -->
+    <skip />
+    <!-- no translation found for minute_picker_description (8606010966873791190) -->
+    <skip />
+    <!-- no translation found for select_hours (6043079511766008245) -->
+    <skip />
+    <!-- no translation found for select_minutes (3974345615920336087) -->
+    <skip />
+    <!-- no translation found for select_day (7774759604701773332) -->
+    <skip />
+    <!-- no translation found for select_year (7952052866994196170) -->
+    <skip />
+    <!-- no translation found for deleted_key (7659477886625566590) -->
+    <skip />
+    <!-- no translation found for managed_profile_label_badge (2355652472854327647) -->
+    <skip />
+    <!-- no translation found for lock_to_app_toast (7570091317001980053) -->
+    <skip />
+    <!-- no translation found for lock_to_app_toast_accessible (8239120109365070664) -->
+    <skip />
+    <!-- no translation found for lock_to_app_toast_locked (9125176335701699164) -->
+    <skip />
+    <!-- no translation found for lock_to_app_start (6643342070839862795) -->
+    <skip />
+    <!-- no translation found for lock_to_app_exit (8598219838213787430) -->
+    <skip />
+    <!-- no translation found for lock_to_app_unlock_pin (2552556656504331634) -->
+    <skip />
+    <!-- no translation found for lock_to_app_unlock_pattern (4182192144797225137) -->
+    <skip />
+    <!-- no translation found for lock_to_app_unlock_password (6380979775916974414) -->
+    <skip />
+    <!-- no translation found for dock_non_resizeble_text (9156251681042762723) -->
+    <skip />
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_updated_device_owner (8856631322440187071) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
+    <!-- no translation found for battery_saver_description (1960431123816253034) -->
+    <skip />
+    <!-- no translation found for zen_mode_duration_minutes_summary (4367877408072000848) -->
+    <!-- no translation found for zen_mode_duration_minutes_summary_short (6830154222366042597) -->
+    <!-- no translation found for zen_mode_duration_hours_summary (8152974162096743862) -->
+    <!-- no translation found for zen_mode_duration_hours_summary_short (4787552595253082371) -->
+    <!-- no translation found for zen_mode_duration_minutes (5127407202506485571) -->
+    <!-- no translation found for zen_mode_duration_minutes_short (2199350154433426128) -->
+    <!-- no translation found for zen_mode_duration_hours (3938821308277433854) -->
+    <!-- no translation found for zen_mode_duration_hours_short (6748277774662434217) -->
+    <!-- no translation found for zen_mode_until (7336308492289875088) -->
+    <skip />
+    <!-- no translation found for zen_mode_alarm (9128205721301330797) -->
+    <skip />
+    <!-- no translation found for zen_mode_forever (7420011936770086993) -->
+    <skip />
+    <!-- no translation found for zen_mode_forever_dnd (3792132696572189081) -->
+    <skip />
+    <!-- no translation found for zen_mode_rule_name_combination (191109939968076477) -->
+    <skip />
+    <!-- no translation found for toolbar_collapse_description (2821479483960330739) -->
+    <skip />
+    <!-- no translation found for zen_mode_feature_name (5254089399895895004) -->
+    <skip />
+    <!-- no translation found for zen_mode_downtime_feature_name (2626974636779860146) -->
+    <skip />
+    <!-- no translation found for zen_mode_default_weeknights_name (3081318299464998143) -->
+    <skip />
+    <!-- no translation found for zen_mode_default_weekends_name (2786495801019345244) -->
+    <skip />
+    <!-- no translation found for zen_mode_default_events_name (8158334939013085363) -->
+    <skip />
+    <!-- no translation found for muted_by (6147073845094180001) -->
+    <skip />
+    <!-- no translation found for system_error_wipe_data (6608165524785354962) -->
+    <skip />
+    <!-- no translation found for system_error_manufacturer (8086872414744210668) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_dial (5202342984749947872) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ss (2345360594181405482) -->
+    <skip />
+    <!-- no translation found for stk_cc_ussd_to_ussd (7466087659967191653) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_dial (2151304435775557162) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ussd (3951862188105305589) -->
+    <skip />
+    <!-- no translation found for stk_cc_ss_to_ss (5470768854991452695) -->
+    <skip />
+    <!-- no translation found for notification_work_profile_content_description (4600554564103770764) -->
+    <skip />
+    <!-- no translation found for usb_midi_peripheral_name (7221113987741003817) -->
+    <skip />
+    <!-- no translation found for usb_midi_peripheral_manufacturer_name (7176526170008970168) -->
+    <skip />
+    <!-- no translation found for usb_midi_peripheral_product_name (4971827859165280403) -->
+    <skip />
+    <!-- no translation found for floating_toolbar_open_overflow_description (4797287862999444631) -->
+    <skip />
+    <!-- no translation found for floating_toolbar_close_overflow_description (559796923090723804) -->
+    <skip />
+    <!-- no translation found for maximize_button_text (7543285286182446254) -->
+    <skip />
+    <!-- no translation found for close_button_text (3937902162644062866) -->
+    <skip />
+    <!-- no translation found for selected_count (7187339492915744615) -->
+    <!-- no translation found for default_notification_topic_label (227586145791870829) -->
+    <skip />
+    <!-- no translation found for importance_from_topic (3572280439880023233) -->
+    <skip />
+    <!-- no translation found for importance_from_person (9160133597262938296) -->
+    <skip />
+    <!-- no translation found for user_creation_cannot_add (7740333663230045315) -->
+    <skip />
+    <!-- no translation found for user_creation_cannot_add_any_more (6244197709981359266) -->
+    <skip />
+    <!-- no translation found for user_creation_account_exists (4880171855014489789) -->
+    <skip />
+    <!-- no translation found for user_creation_adding (3206420861363021392) -->
+    <skip />
+    <!-- no translation found for language_selection_title (7181332986330337171) -->
+    <skip />
+    <!-- no translation found for country_selection_title (2954859441620215513) -->
+    <skip />
+    <!-- no translation found for search_language_hint (7042102592055108574) -->
+    <skip />
+    <!-- no translation found for language_picker_section_suggested (8414489646861640885) -->
+    <skip />
+    <!-- no translation found for language_picker_section_all (3097279199511617537) -->
+    <skip />
+    <!-- no translation found for locale_search_menu (2560710726687249178) -->
+    <skip />
+</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index df7cf79..602532c 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Informe d\'error"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Crea informe d\'errors"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Es recopilarà informació sobre l\'estat actual del dispositiu i se t\'enviarà per correu electrònic. Passaran uns quants minuts des de l\'inici de l\'informe d\'errors fins al seu enviament, per la qual cosa et recomanem que tinguis paciència."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Informe interactiu"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Utilitza aquesta opció en la majoria de circumstàncies. Et permet fer un seguiment del progrés de l\'informe i introduir més dades sobre el problema. És possible que ometi seccions menys utilitzades que requereixen molt de temps i que no n\'informi."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Informe complet"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Es farà una captura de pantalla de l\'informe d\'errors d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons.</item>
+      <item quantity="one">Es farà una captura de pantalla de l\'informe d\'errors d\'aquí a <xliff:g id="NUMBER_0">%d</xliff:g> segon.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Mode silenciós"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"So desactivat"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"El so està activat"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Inclou dades personals com ara números de targetes de crèdit i contrasenyes."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Controla l\'ampliació de la pantalla"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controla el nivell i el posicionament del zoom de la pantalla."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Utilitza gestos"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Pot tocar, lliscar, pessigar i utilitzar altres gestos."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"desactivar o modificar la barra d\'estat"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Permet que l\'aplicació desactivi la barra d\'estat o afegeixi i elimini icones del sistema."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"aparèixer a la barra d\'estat"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permet que l\'aplicació faci fotos i vídeos amb la càmera. Aquest permís permet que l\'aplicació utilitzi la càmera en qualsevol moment sense la teva confirmació."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"controlar la vibració"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Permet que l\'aplicació controli el vibrador."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"controla la llanterna"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Permet que l\'aplicació controli la llanterna."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"trucar directament a números de telèfon"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Permet que l\'aplicació truqui a números de telèfon sense la teva intervenció. Aquesta acció pot produir càrrecs o trucades inesperades. Tingues en compte que això no permet que l\'aplicació truqui a números d\'emergència. Les aplicacions malicioses poden fer trucades sense la teva confirmació, cosa que et pot fer gastar diners."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"accés al servei de trucades IMS"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Retalla"</string>
     <string name="copy" msgid="2681946229533511987">"Copia"</string>
     <string name="paste" msgid="5629880836805036433">"Enganxa"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Enganxa com a text sense format"</string>
     <string name="replace" msgid="5781686059063148930">"Vols substituir..."</string>
     <string name="delete" msgid="6098684844021697789">"Suprimeix"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Copia l\'URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Selecciona el text"</string>
+    <string name="undo" msgid="7905788502491742328">"Desfés"</string>
+    <string name="redo" msgid="7759464876566803888">"Refés"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Selecció de text"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Afegeix al diccionari"</string>
     <string name="deleteText" msgid="6979668428458199034">"Suprimeix"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Vols compartir l\'informe d\'errors amb l\'administrador?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"El teu administrador de TI ha sol·licitat un informe d\'errors per tal de resoldre problemes"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPTA"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"REBUTJA"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"S\'està creant l\'informe d\'errors…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Toca per cancel·lar"</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="9157568568695230830">"Mostra mètode d\'introducció"</string>
-    <string name="hardware" msgid="7517821086888990278">"Maquinari"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <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="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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"L\'administrador l\'ha actualitzat"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"L\'administrador ho ha suprimit"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Per tal d\'augmentar la durada de la bateria, la funció d\'estalvi de bateria redueix el rendiment del dispositiu i en limita la vibració i la majoria de dades en segon pla. És possible que el correu electrònic, la missatgeria i la resta d\'aplicacions que se sincronitzen amb freqüència no s\'actualitzin llevat que les obris.\n\nL\'estalvi de bateria es desactiva automàticament mentre el dispositiu s\'està carregant."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Importància"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloquejada: no mostra mai aquestes notificacions"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Baixa: mostra de manera silenciosa a la part inferior de la llista de notificacions"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normal: mostra aquestes notificacions de manera silenciosa"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Alta: mostra a la part superior de la llista de notificacions i emet un so"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Urgent: mostra a la pantalla i emet un so"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">Durant %1$d minuts (fins a les <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">Durant 1 minut (fins a les <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1512,5 +1526,15 @@
     </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_person" msgid="9160133597262938296">"Aquest missatge és important per les persones que hi ha."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"Aquest missatge és important per les persones implicades."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" està provant d\'afegir un usuari, però actualment aquesta acció no està permesa."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" està provant d\'afegir un usuari, però s\'ha assolit el límit d\'usuaris."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" està provant d\'afegir un usuari, però el compte "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" ja existeix en aquest dispositiu. Vols continuar igualment?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" està provant d\'afegir un usuari per al compte "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Vols continuar?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Preferència d\'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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Tots els idiomes"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Cerca"</string>
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index b4c19a4..4c830f9 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -213,6 +213,17 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Hlášení chyb"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Vytvořit chybové hlášení"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Shromažďuje informace o aktuálním stavu zařízení. Tyto informace je následně možné poslat v e-mailové zprávě, chvíli však potrvá, než bude hlášení o chybě připraveno k odeslání. Buďte prosím trpěliví."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktivní přehled"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Tato možnost se používá ve většině případů. Umožňuje sledovat průběh přehledu a zadat další podrobnosti o problému. Mohou být vynechány některé méně používané sekce, jejichž kontrola trvá dlouho."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Úplný přehled"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="few">Snímek obrazovky pro zprávu o chybě bude pořízen za <xliff:g id="NUMBER_1">%d</xliff:g> sekundy.</item>
+      <item quantity="many">Snímek obrazovky pro zprávu o chybě bude pořízen za <xliff:g id="NUMBER_1">%d</xliff:g> sekundy.</item>
+      <item quantity="other">Snímek obrazovky pro zprávu o chybě bude pořízen za <xliff:g id="NUMBER_1">%d</xliff:g> sekund.</item>
+      <item quantity="one">Snímek obrazovky pro zprávu o chybě bude pořízen za <xliff:g id="NUMBER_0">%d</xliff:g> sekundu.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Tichý režim"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Zvuk je VYPNUTÝ."</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Zvuk je zapnutý"</string>
@@ -225,6 +236,7 @@
     <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="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>
@@ -257,6 +269,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Sledování zahrnuje osobní údaje, jako jsou například čísla kreditních karet a hesla."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Nastavení zvětšení obsahu obrazovky"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Určuje umístění a úroveň přiblížení displeje."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Provádění gest"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Může provádět gesta klepnutí, přejetí, stažení prstů a další."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"zakázání či změny stavového řádku"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Umožňuje aplikaci zakázat stavový řádek nebo přidat či odebrat systémové ikony."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"vydávání se za stavový řádek"</string>
@@ -355,8 +369,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Umožňuje aplikaci pořizovat fotografie a videa pomocí fotoaparátu. Toto oprávnění umožňuje aplikaci používat fotoaparát kdykoliv i bez vašeho svolení."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"ovládání vibrací"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Umožňuje aplikaci ovládat vibrace."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ovládání kontrolky"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Umožňuje aplikaci ovládat svítilnu."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"přímé volání na telefonní čísla"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Umožňuje aplikaci volat na telefonní čísla bez vašeho přičinění. Může mít za následek neočekávané poplatky nebo hovory. Toto oprávnění neumožňuje aplikaci volat na tísňová čísla. Škodlivé aplikace vás mohou připravit o peníze uskutečňováním hovorů bez vašeho svolení."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"přístup ke službě zasílání rychlých zpráv pro účely hovorů"</string>
@@ -868,10 +880,13 @@
     <string name="cut" msgid="3092569408438626261">"Vyjmout"</string>
     <string name="copy" msgid="2681946229533511987">"Kopírovat"</string>
     <string name="paste" msgid="5629880836805036433">"Vložit"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Vložit jako prostý text"</string>
     <string name="replace" msgid="5781686059063148930">"Nahradit•"</string>
     <string name="delete" msgid="6098684844021697789">"Smazat"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Kopírovat adresu URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Vybrat text"</string>
+    <string name="undo" msgid="7905788502491742328">"Vrátit zpět"</string>
+    <string name="redo" msgid="7759464876566803888">"Opakovat"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Výběr textu"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Přidat do slovníku"</string>
     <string name="deleteText" msgid="6979668428458199034">"Smazat"</string>
@@ -1042,10 +1057,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Sdílet zprávu o chybě s administrátorem?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Administrátor IT si vyžádal zprávu o chybě, aby mohl problém odstranit."</string>
+    <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="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Vytváření zprávy o chybě…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Klepnutím zrušíte"</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="9157568568695230830">"Zobrazit metodu zadávání"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardware"</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="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
@@ -1121,6 +1142,7 @@
     <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="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="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>
@@ -1458,12 +1480,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Aktualizováno administrátorem"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Smazáno administrátorem"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Spořič baterie za účelem prodloužení výdrže baterie snižuje výkon zařízení a omezuje vibrace, služby určování polohy a většinu dat na pozadí. E-mail, aplikace pro zasílání zpráv a další aplikace, které používají synchronizaci, se nemusejí aktualizovat, dokud je neotevřete.\n\nPři nabíjení zařízení se spořič baterie automaticky vypne."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Důležitost"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokováno: Tato oznámení nikdy nezobrazovat"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Nízká: Tato oznámení zobrazovat na konci seznamu bez zvukového upozornění"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normální: Tato oznámení zobrazovat bez zvukového upozornění"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Vysoká: Tato oznámení zobrazovat na začátku seznamu a upozornit na ně zvukem"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Urgentní: Tato oznámení zobrazovat přímo na obrazovce a upozornit na ně zvukem"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="few">%1$d minuty (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="many">%1$d minuty (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1549,4 +1565,14 @@
     <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_person" msgid="9160133597262938296">"Tato zpráva je důležitá kvůli lidem zapojeným do konverzace."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315">"Aplikace "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" se pokouší přidat nového uživatele, avšak v tuto chvíli je zakázána."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266">"Aplikace "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" se pokouší přidat nového uživatele, avšak byl dosažen maximální počet uživatelů."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789">"Aplikace "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" se pokouší přidat nového uživatele, avšak účet "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" již v zařízení existuje. Chcete přesto pokračovat?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392">"Aplikace "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" se pro účet "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" pokouší přidat nového uživatele. Pokračovat?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Preferovaný 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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Všechny jazyky"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Vyhledávání"</string>
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 2d5ec09..164ae6b 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Fejlrapport"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Lav fejlrapport"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Der indsamles oplysninger om din enheds aktuelle status, der efterfølgende sendes i en e-mail. Der går lidt tid, fra fejlrapporten påbegyndes, til den er klar til at blive sendt. Tak for tålmodigheden."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktiv rapport"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Brug dette workflow under de fleste omstændigheder. Det giver dig mulighed for at se status på rapporten og angive flere oplysninger om problemet. Nogle mindre brugte sektioner, der tager lang tid at rapportere, udelades muligvis."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Fuld rapport"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">Der tages et skærmbillede til fejlrapporten om <xliff:g id="NUMBER_1">%d</xliff:g> sekund.</item>
+      <item quantity="other">Der tages et skærmbillede til fejlrapporten om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Lydløs"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Lyden er slået FRA"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Lyden er TIL"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Dette omfatter personlige data såsom kreditkortnumre og adgangskoder."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Kontrollér skærmforstørrelsen"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrollér skærmens zoomniveau og position."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Udfør bevægelser"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Kan trykke, stryge, knibe sammen og udføre andre bevægelser."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"deaktiver eller rediger statuslinje"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Tillader, at appen kan deaktivere statusbjælken eller tilføje og fjerne systemikoner."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"vær statusbjælken"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Tillader, at appen kan tage billeder og videoer med kameraet. Med denne tilladelse kan appen til enhver tid bruge kameraet uden din bekræftelse."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"kontrollere vibration"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Tillader, at appen kan kontrollere vibratoren."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"kontroller lommelygte"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Tillader, at appen kan kontrollere lommelygten."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ringe direkte op til telefonnumre"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Tillader, at appen kan ringe til telefonnumre uden din indgriben. Dette kan resultere i uventede opkrævninger eller opkald. Bemærk, at appen med denne tilladelse ikke kan ringe til nødopkaldsnumre. Skadelige apps kan koste dig penge ved at foretage opkald uden din bekræftelse."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"få adgang til chat-opkaldstjeneste"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Klip"</string>
     <string name="copy" msgid="2681946229533511987">"Kopier"</string>
     <string name="paste" msgid="5629880836805036433">"Indsæt"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Indsæt som almindelig tekst"</string>
     <string name="replace" msgid="5781686059063148930">"Erstat..."</string>
     <string name="delete" msgid="6098684844021697789">"Slet"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Kopier webadresse"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Markér tekst"</string>
+    <string name="undo" msgid="7905788502491742328">"Fortryd"</string>
+    <string name="redo" msgid="7759464876566803888">"Annuller fortryd"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Tekstmarkering"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Føj til ordbog"</string>
     <string name="deleteText" msgid="6979668428458199034">"Slet"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Vil du dele fejlrapporten med administratoren?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Din it-administrator har anmodet om en fejlrapport for bedre at kunne finde og rette fejlen"</string>
+    <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="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Opretter fejlrapport…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Tryk for at annullere"</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="9157568568695230830">"Vis indtastningsmetode"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardware"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Skift baggrund"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Underretningslytter"</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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Opdateret af administrator"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Slettet af din administrator"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Batterisparefunktionen hjælper med at forlænge batteriets levetid ved at reducere enhedens ydeevne og begrænse vibration, placeringstjenester og det meste baggrundsdata. E-mail, beskedfunktioner og andre apps, der benytter synkronisering, opdateres muligvis ikke, medmindre du åbner dem.\n\nBatterisparefunktionen slukker automatisk, når enheden oplader."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Vigtighed"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokeret: Vis aldrig disse underretninger"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Lav: Vis lydløst nederst på listen over underretninger"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Vis disse underretninger lydløst"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Høj: Vis øverst på listen over underretninger, og giv lyd"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Presserende: Vis på skærmen, og giv lyd"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="one">I %1$d minutter (indtil <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="other">I %1$d minutter (indtil <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"Dette er vigtigt på grund af de personer, det handler om."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" forsøger at tilføje en ny bruger, men det er i øjeblikket forbudt."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" forsøger at tilføje en ny bruger, men grænsen for antal brugere er nået."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" forsøger at tilføje en ny bruger, men kontoen "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" findes allerede på denne enhed. Vil du fortsætte?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" forsøger at føje en ny bruger til kontoen "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Vil du fortsætte?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Sprogindstilling"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Alle sprog"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Søg"</string>
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 77f049b..4f43c2a 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -45,7 +45,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Mailbox"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
     <string name="mmiError" msgid="5154499457739052907">"Verbindungsproblem oder ungültiger MMI-Code."</string>
-    <string name="mmiFdnError" msgid="5224398216385316471">"Der Vorgang ist nur für Ihre zugelassenen Rufnummern möglich."</string>
+    <string name="mmiFdnError" msgid="5224398216385316471">"Der Vorgang ist nur für deine zugelassenen Rufnummern möglich."</string>
     <string name="serviceEnabled" msgid="8147278346414714315">"Dienst wurde aktiviert."</string>
     <string name="serviceEnabledFor" msgid="6856228140453471041">"Dienst wurde aktiviert für:"</string>
     <string name="serviceDisabled" msgid="1937553226592516411">"Dienst wurde deaktiviert."</string>
@@ -53,17 +53,17 @@
     <string name="serviceErased" msgid="1288584695297200972">"Löschvorgang erfolgreich."</string>
     <string name="passwordIncorrect" msgid="7612208839450128715">"Falsches Passwort."</string>
     <string name="mmiComplete" msgid="8232527495411698359">"MMI abgeschlossen."</string>
-    <string name="badPin" msgid="9015277645546710014">"Die von Ihnen eingegebene alte PIN ist nicht korrekt."</string>
-    <string name="badPuk" msgid="5487257647081132201">"Der von Ihnen eingegebene PUK ist nicht korrekt."</string>
-    <string name="mismatchPin" msgid="609379054496863419">"Die von Ihnen eingegebenen PIN-Nummern stimmen nicht überein."</string>
-    <string name="invalidPin" msgid="3850018445187475377">"Geben Sie eine PIN ein, die 4 bis 8 Zahlen enthält."</string>
-    <string name="invalidPuk" msgid="8761456210898036513">"Geben Sie eine mindestens achtstellige PUK ein."</string>
-    <string name="needPuk" msgid="919668385956251611">"Ihre SIM-Karte ist mit einem PUK gesperrt. Geben Sie zum Entsperren den PUK-Code ein."</string>
-    <string name="needPuk2" msgid="4526033371987193070">"Geben Sie zum Entsperren der SIM-Karte den PUK2 ein."</string>
+    <string name="badPin" msgid="9015277645546710014">"Die von dir eingegebene alte PIN ist nicht korrekt."</string>
+    <string name="badPuk" msgid="5487257647081132201">"Der von dir eingegebene PUK ist nicht korrekt."</string>
+    <string name="mismatchPin" msgid="609379054496863419">"Die von dir eingegebenen PIN-Nummern stimmen nicht überein."</string>
+    <string name="invalidPin" msgid="3850018445187475377">"Gib eine PIN ein, die 4 bis 8 Zahlen enthält."</string>
+    <string name="invalidPuk" msgid="8761456210898036513">"Gib eine mindestens achtstellige PUK ein."</string>
+    <string name="needPuk" msgid="919668385956251611">"Deine SIM-Karte ist mit einem PUK gesperrt. Gib zum Entsperren den PUK-Code ein."</string>
+    <string name="needPuk2" msgid="4526033371987193070">"Gib zum Entsperren der SIM-Karte den PUK2 ein."</string>
     <string name="enablePin" msgid="209412020907207950">"Fehler. SIM-/RUIM-Sperre aktivieren."</string>
     <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
-      <item quantity="other">Sie haben noch <xliff:g id="NUMBER_1">%d</xliff:g> Versuche, bevor Ihre SIM-Karte gesperrt wird.</item>
-      <item quantity="one">Sie haben noch <xliff:g id="NUMBER_0">%d</xliff:g> Versuch, bevor Ihre SIM-Karte gesperrt wird.</item>
+      <item quantity="other">Du hast noch <xliff:g id="NUMBER_1">%d</xliff:g> Versuche, bevor deine SIM-Karte gesperrt wird.</item>
+      <item quantity="one">Du hast noch <xliff:g id="NUMBER_0">%d</xliff:g> Versuch, bevor deine SIM-Karte gesperrt wird.</item>
     </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
@@ -87,7 +87,7 @@
     <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Anrufer-ID ist standardmäßig nicht beschränkt. Nächster Anruf: Beschränkt"</string>
     <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">"Sie können die Einstellung für die Anrufer-ID nicht ändern."</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>
@@ -148,7 +148,7 @@
     <string name="httpErrorAuth" msgid="1435065629438044534">"Bei der Authentifizierung ist ein Fehler aufgetreten."</string>
     <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Authentifizierung via Proxyserver ist fehlgeschlagen."</string>
     <string name="httpErrorConnect" msgid="8714273236364640549">"Verbindung zum Server konnte nicht hergestellt werden."</string>
-    <string name="httpErrorIO" msgid="2340558197489302188">"Kommunikation mit dem Server konnte nicht hergestellt werden. Bitte versuchen Sie es später erneut."</string>
+    <string name="httpErrorIO" msgid="2340558197489302188">"Kommunikation mit dem Server konnte nicht hergestellt werden. Bitte versuche es später erneut."</string>
     <string name="httpErrorTimeout" msgid="4743403703762883954">"Zeitüberschreitung bei Serververbindung."</string>
     <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Die Seite enthält zu viele Server-Redirects."</string>
     <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Das Protokoll wird nicht unterstützt."</string>
@@ -156,25 +156,25 @@
     <string name="httpErrorBadUrl" msgid="3636929722728881972">"Die Seite kann nicht geöffnet werden, weil die URL ungültig ist."</string>
     <string name="httpErrorFile" msgid="2170788515052558676">"Auf die Datei konnte nicht zugegriffen werden."</string>
     <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Die angeforderte Datei wurde nicht gefunden."</string>
-    <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Es werden zurzeit zu viele Anfragen verarbeitet. Versuchen Sie es später erneut."</string>
+    <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Es werden zurzeit zu viele Anfragen verarbeitet. Versuche es später erneut."</string>
     <string name="notification_title" msgid="8967710025036163822">"Fehler bei Anmeldung für <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
     <string name="contentServiceSync" msgid="8353523060269335667">"Synchronisierung"</string>
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronisierung"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Zu viele <xliff:g id="CONTENT_TYPE">%s</xliff:g> gelöscht."</string>
-    <string name="low_memory" product="tablet" msgid="6494019234102154896">"Der Tablet-Speicher ist voll. Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
-    <string name="low_memory" product="watch" msgid="4415914910770005166">"Der Speicher Ihrer Uhr ist voll. Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
-    <string name="low_memory" product="tv" msgid="516619861191025923">"Der TV-Speicher ist voll. Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
-    <string name="low_memory" product="default" msgid="3475999286680000541">"Der Handyspeicher ist voll! Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
+    <string name="low_memory" product="tablet" msgid="6494019234102154896">"Der Tablet-Speicher ist voll. Lösche Dateien, um Speicherplatz freizugeben."</string>
+    <string name="low_memory" product="watch" msgid="4415914910770005166">"Der Speicher deiner Uhr ist voll. Lösche Dateien, um Speicherplatz freizugeben."</string>
+    <string name="low_memory" product="tv" msgid="516619861191025923">"Der TV-Speicher ist voll. Lösche Dateien, um Speicherplatz freizugeben."</string>
+    <string name="low_memory" product="default" msgid="3475999286680000541">"Der Handyspeicher ist voll! Lösche Dateien, um Speicherplatz freizugeben."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Das Netzwerk wird möglicherweise überwacht."</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Von einem unbekannten Dritten"</string>
-    <string name="ssl_ca_cert_noti_by_administrator" msgid="550758088185764312">"Vom Administrator Ihres Arbeitsprofils"</string>
+    <string name="ssl_ca_cert_noti_by_administrator" msgid="550758088185764312">"Vom Administrator deines Arbeitsprofils"</string>
     <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Von <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
     <string name="work_profile_deleted" msgid="5005572078641980632">"Arbeitsprofil gelöscht"</string>
     <string name="work_profile_deleted_description" msgid="6305147513054341102">"Arbeitsprofil aufgrund fehlender Admin-App gelöscht"</string>
-    <string name="work_profile_deleted_details" msgid="226615743462361248">"Die Admin-App für das Arbeitsprofil fehlt oder ist beschädigt. Daher wurden Ihr Arbeitsprofil und alle zugehörigen Daten gelöscht. Wenden Sie sich für weitere Hilfe an Ihren Administrator."</string>
-    <string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Ihr Arbeitsprofil ist auf diesem Gerät nicht mehr verfügbar."</string>
-    <string name="factory_reset_warning" msgid="5423253125642394387">"Die Daten auf Ihrem Gerät werden gelöscht."</string>
-    <string name="factory_reset_message" msgid="4905025204141900666">"Die Admin-App kann nicht verwendet werden, da sie beschädigt wurde oder Komponenten fehlen. Die Daten auf Ihrem Gerät werden nun gelöscht. Wenden Sie sich für weitere Hilfe an Ihren Administrator."</string>
+    <string name="work_profile_deleted_details" msgid="226615743462361248">"Die Admin-App für das Arbeitsprofil fehlt oder ist beschädigt. Daher wurden dein Arbeitsprofil und alle zugehörigen Daten gelöscht. Wende dich für weitere Hilfe an deinen Administrator."</string>
+    <string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Dein Arbeitsprofil ist auf diesem Gerät nicht mehr verfügbar."</string>
+    <string name="factory_reset_warning" msgid="5423253125642394387">"Die Daten auf deinem Gerät werden gelöscht."</string>
+    <string name="factory_reset_message" msgid="4905025204141900666">"Die Admin-App kann nicht verwendet werden, da sie beschädigt wurde oder Komponenten fehlen. Die Daten auf deinem Gerät werden nun gelöscht. Wende dich für weitere Hilfe an deinen Administrator."</string>
     <string name="me" msgid="6545696007631404292">"Eigene"</string>
     <string name="power_dialog" product="tablet" msgid="8545351420865202853">"Tablet-Optionen"</string>
     <string name="power_dialog" product="tv" msgid="6153888706430556356">"TV-Optionen"</string>
@@ -194,13 +194,13 @@
     <string name="reboot_to_reset_title" msgid="4142355915340627490">"Auf Werkszustand zurück"</string>
     <string name="reboot_to_reset_message" msgid="2432077491101416345">"Neustart…"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Wird heruntergefahren..."</string>
-    <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Ihr Tablet wird heruntergefahren."</string>
-    <string name="shutdown_confirm" product="tv" msgid="476672373995075359">"Ihr Fernseher wird ausgeschaltet."</string>
-    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Ihre Uhr wird heruntergefahren."</string>
+    <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Dein Tablet wird heruntergefahren."</string>
+    <string name="shutdown_confirm" product="tv" msgid="476672373995075359">"Dein Fernseher wird ausgeschaltet."</string>
+    <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Deine Uhr wird heruntergefahren."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefon wird heruntergefahren."</string>
-    <string name="shutdown_confirm_question" msgid="2906544768881136183">"Möchten Sie das Gerät herunterfahren?"</string>
+    <string name="shutdown_confirm_question" msgid="2906544768881136183">"Möchtest du das Gerät herunterfahren?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Im abgesicherten Modus starten"</string>
-    <string name="reboot_safemode_confirm" msgid="55293944502784668">"Möchten Sie im abgesicherten Modus neu starten? Dadurch werden alle Apps von Drittanbietern deaktiviert, die Sie installiert haben. Sie werden jedoch nach einem weiteren Neustart wiederhergestellt."</string>
+    <string name="reboot_safemode_confirm" msgid="55293944502784668">"Möchtest du im abgesicherten Modus neu starten? Dadurch werden alle Apps von Drittanbietern deaktiviert, die du installiert hast. Die Apps werden jedoch nach einem weiteren Neustart wiederhergestellt."</string>
     <string name="recent_tasks_title" msgid="3691764623638127888">"Kürzlich geöffnet"</string>
     <string name="no_recent_tasks" msgid="8794906658732193473">"Keine kürzlich geöffneten Apps"</string>
     <string name="global_actions" product="tablet" msgid="408477140088053665">"Tablet-Optionen"</string>
@@ -210,7 +210,16 @@
     <string name="global_action_power_off" msgid="4471879440839879722">"Ausschalten"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Fehlerbericht"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Fehlerbericht abrufen"</string>
-    <string name="bugreport_message" msgid="398447048750350456">"Bei diesem Fehlerbericht werden Daten zum aktuellen Status Ihres Geräts erfasst und als E-Mail versandt. Vom Start des Berichts bis zu seinem Versand kann es eine Weile dauern. Bitte haben Sie etwas Geduld."</string>
+    <string name="bugreport_message" msgid="398447048750350456">"Bei diesem Fehlerbericht werden Daten zum aktuellen Status deines Geräts erfasst und als E-Mail versandt. Vom Start des Berichts bis zu seinem Versand kann es eine Weile dauern. Bitte habe etwas Geduld."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktiver Bericht"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Diese Option kann in den meisten Fällen verwendet werden. Du kannst darüber den aktuellen Stand der Berichterstellung verfolgen und genauere Angaben zu dem Problem machen. Einige selten genutzte Bereiche, deren Berichterstellung längere Zeit in Anspruch nimmt, werden unter Umständen ausgelassen."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Vollständiger Bericht"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Screenshot für den Fehlerbericht wird in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden aufgenommen.</item>
+      <item quantity="one">Screenshot für den Fehlerbericht wird in <xliff:g id="NUMBER_0">%d</xliff:g> Sekunde aufgenommen.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Lautlos-Modus"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Ton ist AUS."</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Ton ist AN."</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -230,13 +240,13 @@
     <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>
-    <string name="permgroupdesc_location" msgid="1346617465127855033">"auf den Standort Ihres Geräts zuzugreifen"</string>
+    <string name="permgroupdesc_location" msgid="1346617465127855033">"auf den Standort deines Geräts zuzugreifen"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalender"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"auf Kalender zuzugreifen"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
     <string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS zu senden und abzurufen"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Speicher"</string>
-    <string name="permgroupdesc_storage" msgid="637758554581589203">"auf Fotos, Medien und Dateien auf Ihrem Gerät zuzugreifen"</string>
+    <string name="permgroupdesc_storage" msgid="637758554581589203">"auf Fotos, Medien und Dateien auf deinem Gerät zuzugreifen"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofon"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"Audio aufzunehmen"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
@@ -244,9 +254,9 @@
     <string name="permgrouplab_phone" msgid="5229115638567440675">"Telefon"</string>
     <string name="permgroupdesc_phone" msgid="6234224354060641055">"Telefonanrufe zu tätigen und zu verwalten"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"Körpersensoren"</string>
-    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"auf Sensordaten zu Ihren Vitaldaten zuzugreifen"</string>
+    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"auf Sensordaten zu deinen Vitaldaten zuzugreifen"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Fensterinhalte abrufen"</string>
-    <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Die Inhalte eines Fensters, mit dem Sie interagieren, werden abgerufen."</string>
+    <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Die Inhalte eines Fensters, mit dem du interagierst, werden abgerufen."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"\"Tippen &amp; Entdecken\" aktivieren"</string>
     <string name="capability_desc_canRequestTouchExploration" msgid="5800552516779249356">"Berührte Elemente werden laut vorgelesen und der Bildschirm kann über Gesten erkundet werden."</string>
     <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"Verbesserte Web-Bedienung aktivieren"</string>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Einschließlich personenbezogener Daten wie Kreditkartennummern und Passwörter."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Displayvergrößerung festlegen"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Legt die Zoom-Stufe des Displays und die Zoom-Position auf dem Display fest."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Bewegungen möglich"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Tippen, Wischen, Zusammenziehen und andere Bewegungen möglich."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"Statusleiste deaktivieren oder ändern"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Ermöglicht der App, die Statusleiste zu deaktivieren oder Systemsymbole hinzuzufügen oder zu entfernen"</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"Statusleiste darstellen"</string>
@@ -268,23 +280,23 @@
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"Ausgehende Anrufe umleiten"</string>
     <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Ermöglicht der App die Erkennung der während eines ausgehenden Anrufs gewählten Nummer und gibt ihr die Möglichkeit, den Anruf an eine andere Nummer umzuleiten oder den Anruf ganz abzubrechen"</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"SMS empfangen"</string>
-    <string name="permdesc_receiveSms" msgid="6424387754228766939">"Ermöglicht der App, SMS zu empfangen und zu verarbeiten. Das bedeutet, dass die App an Ihr Gerät gesendete Nachrichten überwachen und löschen kann, ohne sie Ihnen anzuzeigen."</string>
+    <string name="permdesc_receiveSms" msgid="6424387754228766939">"Ermöglicht der App, SMS zu empfangen und zu verarbeiten. Das bedeutet, dass die App an dein Gerät gesendete Nachrichten überwachen und löschen kann, ohne sie dir anzuzeigen."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"MMS empfangen"</string>
-    <string name="permdesc_receiveMms" msgid="533019437263212260">"Ermöglicht der App, MMS zu empfangen und zu verarbeiten. Das bedeutet, dass die App an Ihr Gerät gesendete Nachrichten überwachen und löschen kann, ohne sie Ihnen anzuzeigen."</string>
+    <string name="permdesc_receiveMms" msgid="533019437263212260">"Ermöglicht der App, MMS zu empfangen und zu verarbeiten. Das bedeutet, dass die App an dein Gerät gesendete Nachrichten überwachen und löschen kann, ohne sie dir anzuzeigen."</string>
     <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"Cell Broadcast-Nachrichten lesen"</string>
-    <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Ermöglicht der App, von Ihrem Gerät empfangene Cell Broadcast-Nachrichten zu lesen. Cell Broadcast-Benachrichtigungen werden an einigen Standorten gesendet, um Sie über Notfallsituationen zu informieren. Schädliche Apps können die Leistung oder den Betrieb Ihres Geräts beeinträchtigen, wenn eine Cell Broadcast-Notfallbenachrichtigung eingeht."</string>
+    <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Ermöglicht der App, von deinem Gerät empfangene Cell Broadcast-Nachrichten zu lesen. Cell Broadcast-Benachrichtigungen werden an einigen Standorten gesendet, um dich über Notfallsituationen zu informieren. Schädliche Apps können die Leistung oder den Betrieb deines Geräts beeinträchtigen, wenn eine Cell Broadcast-Notfallbenachrichtigung eingeht."</string>
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"Abonnierte Feeds lesen"</string>
     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Ermöglicht der App, Details zu den zurzeit synchronisierten Feeds abzurufen"</string>
     <string name="permlab_sendSms" msgid="7544599214260982981">"SMS senden und abrufen"</string>
-    <string name="permdesc_sendSms" msgid="7094729298204937667">"Ermöglicht der App, SMS zu senden. Dies kann zu unerwarteten Kosten führen. Schädliche Apps können Kosten verursachen, indem sie Nachrichten ohne Ihre Bestätigung senden."</string>
+    <string name="permdesc_sendSms" msgid="7094729298204937667">"Ermöglicht der App, SMS zu senden. Dies kann zu unerwarteten Kosten führen. Schädliche Apps können Kosten verursachen, indem sie Nachrichten ohne deine Bestätigung senden."</string>
     <string name="permlab_readSms" msgid="8745086572213270480">"SMS oder MMS lesen"</string>
-    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Ermöglicht der App, auf Ihrem Tablet oder Ihrer SIM-Karte gespeicherte SMS zu lesen. Die App kann alle SMS lesen, unabhängig von Inhalt und Vertraulichkeit."</string>
-    <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Ermöglicht der App, auf Ihrem Fernseher oder Ihrer SIM-Karte gespeicherte SMS zu lesen. Die App kann alle SMS lesen, unabhängig von Inhalt und Vertraulichkeit."</string>
-    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Ermöglicht der App, auf Ihrem Telefon oder Ihrer SIM-Karte gespeicherte SMS zu lesen. Die App kann alle SMS lesen, unabhängig von Inhalt und Vertraulichkeit."</string>
+    <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Ermöglicht der App, auf deinem Tablet oder deiner SIM-Karte gespeicherte SMS zu lesen. Die App kann alle SMS lesen, unabhängig von Inhalt und Vertraulichkeit."</string>
+    <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Ermöglicht der App, auf deinem Fernseher oder deiner SIM-Karte gespeicherte SMS zu lesen. Die App kann alle SMS lesen, unabhängig von Inhalt und Vertraulichkeit."</string>
+    <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Ermöglicht der App, auf deinem Telefon oder deiner SIM-Karte gespeicherte SMS zu lesen. Die App kann alle SMS lesen, unabhängig von Inhalt und Vertraulichkeit."</string>
     <string name="permlab_receiveWapPush" msgid="5991398711936590410">"Textnachrichten (WAP) empfangen"</string>
-    <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Ermöglicht der App, WAP-Nachrichten zu empfangen und zu verarbeiten. Mit der Berechtigung können Nachrichten, die an Sie gesendet wurden, überwacht und gelöscht werden, bevor sie Ihnen angezeigt werden."</string>
+    <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Ermöglicht der App, WAP-Nachrichten zu empfangen und zu verarbeiten. Mit der Berechtigung können Nachrichten, die an dich gesendet wurden, überwacht und gelöscht werden, bevor sie dir angezeigt werden."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"Aktive Apps abrufen"</string>
-    <string name="permdesc_getTasks" msgid="7454215995847658102">"Ermöglicht der App, Informationen zu aktuellen und kürzlich ausgeführten Aufgaben abzurufen. Damit kann die App möglicherweise ermitteln, welche Apps auf Ihrem Gerät zum Einsatz kommen."</string>
+    <string name="permdesc_getTasks" msgid="7454215995847658102">"Ermöglicht der App, Informationen zu aktuellen und kürzlich ausgeführten Aufgaben abzurufen. Damit kann die App möglicherweise ermitteln, welche Apps auf deinem Gerät zum Einsatz kommen."</string>
     <string name="permlab_manageProfileAndDeviceOwners" msgid="7918181259098220004">"Profilinhaber und Geräteeigentümer verwalten"</string>
     <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"Ermöglicht Apps das Einrichten der Profilinhaber und des Geräteeigentümers"</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"Aktive Apps neu ordnen"</string>
@@ -312,51 +324,49 @@
     <string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"Ermöglicht der App, dauerhafte Broadcasts zu senden, die auch nach Ende des Broadcasts bestehen bleiben. Ein zu intensiver Einsatz kann das Gerät langsam oder instabil machen, weil zu viel Arbeitsspeicher belegt wird."</string>
     <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Ermöglicht der App, dauerhafte Broadcasts zu senden, die auch nach Ende des Broadcasts bestehen bleiben. Ein zu intensiver Einsatz kann das Telefon langsam oder instabil machen, weil zu viel Arbeitsspeicher belegt wird."</string>
     <string name="permlab_readContacts" msgid="8348481131899886131">"Kontakte lesen"</string>
-    <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Ermöglicht der App, Daten zu den auf Ihrem Tablet gespeicherten Kontakten zu lesen, einschließlich der Häufigkeit, mit der Sie bestimmte Personen angerufen, diesen E-Mails gesendet oder anderweitig mit ihnen kommuniziert haben. Die Berechtigung erlaubt Apps, Ihre Kontaktdaten zu speichern, und schädliche Apps können Kontaktdaten ohne Ihr Wissen weiterleiten."</string>
-    <string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Ermöglicht der App, Daten zu den auf Ihrem Fernseher gespeicherten Kontakten zu lesen, einschließlich der Häufigkeit, mit der Sie bestimmte Kontakte angerufen, diesen E-Mails gesendet oder anderweitig mit ihnen kommuniziert haben. Diese Berechtigung ermöglicht der App, Ihre Kontaktdaten zu speichern. Schädliche Apps können so Kontaktdaten ohne Ihr Wissen weitergeben."</string>
-    <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Ermöglicht der App, Daten zu den auf Ihrem Telefon gespeicherten Kontakten zu lesen, einschließlich der Häufigkeit, mit der Sie bestimmte Personen angerufen, diesen E-Mails gesendet oder anderweitig mit ihnen kommuniziert haben. Die Berechtigung erlaubt Apps, Ihre Kontaktdaten zu speichern, und schädliche Apps können Kontaktdaten ohne Ihr Wissen weiterleiten."</string>
+    <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Ermöglicht der App, Daten zu den auf deinem Tablet gespeicherten Kontakten zu lesen, einschließlich der Häufigkeit, mit der du bestimmte Personen angerufen, diesen E-Mails gesendet oder anderweitig mit ihnen kommuniziert hast. Die Berechtigung erlaubt Apps, deine Kontaktdaten zu speichern, und schädliche Apps können Kontaktdaten ohne dein Wissen weiterleiten."</string>
+    <string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Ermöglicht der App, Daten zu den auf deinem Fernseher gespeicherten Kontakten zu lesen, einschließlich der Häufigkeit, mit der du bestimmte Kontakte angerufen, diesen E-Mails gesendet oder anderweitig mit ihnen kommuniziert hast. Diese Berechtigung ermöglicht der App, deine Kontaktdaten zu speichern. Schädliche Apps können so Kontaktdaten ohne dein Wissen weitergeben."</string>
+    <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Ermöglicht der App, Daten zu den auf deinem Telefon gespeicherten Kontakten zu lesen, einschließlich der Häufigkeit, mit der du bestimmte Personen angerufen, diesen E-Mails gesendet oder anderweitig mit ihnen kommuniziert hast. Die Berechtigung erlaubt Apps, deine Kontaktdaten zu speichern, und schädliche Apps können Kontaktdaten ohne dein Wissen weiterleiten."</string>
     <string name="permlab_writeContacts" msgid="5107492086416793544">"Kontakte ändern"</string>
-    <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Ermöglicht der App, Daten zu Kontakten, die auf Ihrem Tablet gespeichert sind, zu ändern, einschließlich der Häufigkeit, mit der Sie bestimmte Kontakte angerufen, diesen E-Mails gesendet oder anderweitig mit ihnen kommuniziert haben. Die Berechtigung erlaubt Apps, Kontaktdaten zu löschen."</string>
-    <string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"Ermöglicht der App, Daten zu den auf Ihrem Fernseher gespeicherten Kontakten zu ändern, einschließlich der Häufigkeit, mit der Sie bestimmte Kontakte angerufen, diesen E-Mails gesendet oder anderweitig mit ihnen kommuniziert haben. Die Berechtigung erlaubt Apps, Kontaktdaten zu löschen."</string>
-    <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Ermöglicht der App, Daten zu Kontakten, die auf Ihrem Telefon gespeichert sind, zu ändern, einschließlich der Häufigkeit, mit der Sie bestimmte Kontakte angerufen, diesen E-Mails gesendet oder anderweitig mit ihnen kommuniziert haben. Die Berechtigung erlaubt Apps, Kontaktdaten zu löschen."</string>
+    <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Ermöglicht der App, Daten zu Kontakten, die auf deinem Tablet gespeichert sind, zu ändern, einschließlich der Häufigkeit, mit der du bestimmte Kontakte angerufen, diesen E-Mails gesendet oder anderweitig mit ihnen kommuniziert hast. Die Berechtigung erlaubt Apps, Kontaktdaten zu löschen."</string>
+    <string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"Ermöglicht der App, Daten zu den auf deinem Fernseher gespeicherten Kontakten zu ändern, einschließlich der Häufigkeit, mit der du bestimmte Kontakte angerufen, diesen E-Mails gesendet oder anderweitig mit ihnen kommuniziert hast. Die Berechtigung erlaubt Apps, Kontaktdaten zu löschen."</string>
+    <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Ermöglicht der App, Daten zu Kontakten, die auf deinem Telefon gespeichert sind, zu ändern, einschließlich der Häufigkeit, mit der du bestimmte Kontakte angerufen, diesen E-Mails gesendet oder anderweitig mit ihnen kommuniziert hast. Die Berechtigung erlaubt Apps, Kontaktdaten zu löschen."</string>
     <string name="permlab_readCallLog" msgid="3478133184624102739">"Anrufliste lesen"</string>
-    <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Ermöglicht der App, die Anrufliste Ihres Tablets zu lesen, einschließlich der Daten über ein- und ausgehende Anrufe. Die Berechtigung erlaubt Apps, Ihre Anruflistendaten zu speichern, und schädliche Apps können diese Daten ohne Ihr Wissen weiterleiten."</string>
-    <string name="permdesc_readCallLog" product="tv" msgid="5611770887047387926">"Ermöglicht der App, die Anrufliste Ihres Fernsehers zu lesen, einschließlich der Daten über ein- und ausgehende Anrufe. Diese Berechtigung ermöglicht es Apps, Daten aus Ihrer Anrufliste zu speichern. Schädliche Apps können so Ihre Anrufliste ohne Ihr Wissen weitergeben."</string>
-    <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Ermöglicht der App, die Anrufliste Ihres Telefons zu lesen, einschließlich der Daten über ein- und ausgehende Anrufe. Die Berechtigung erlaubt Apps, Ihre Anruflistendaten zu speichern, und schädliche Apps können diese Daten ohne Ihr Wissen weiterleiten."</string>
+    <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Ermöglicht der App, die Anrufliste deines Tablets zu lesen, einschließlich der Daten über ein- und ausgehende Anrufe. Die Berechtigung erlaubt Apps, deine Anruflistendaten zu speichern, und schädliche Apps können diese Daten ohne dein Wissen weiterleiten."</string>
+    <string name="permdesc_readCallLog" product="tv" msgid="5611770887047387926">"Ermöglicht der App, die Anrufliste deines Fernsehers zu lesen, einschließlich der Daten über ein- und ausgehende Anrufe. Diese Berechtigung ermöglicht es Apps, Daten aus deiner Anrufliste zu speichern. Schädliche Apps können so deine Anrufliste ohne dein Wissen weitergeben."</string>
+    <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Ermöglicht der App, die Anrufliste deines Telefons zu lesen, einschließlich der Daten über ein- und ausgehende Anrufe. Die Berechtigung erlaubt Apps, deine Anruflistendaten zu speichern, und schädliche Apps können diese Daten ohne dein Wissen weiterleiten."</string>
     <string name="permlab_writeCallLog" msgid="8552045664743499354">"Anrufliste bearbeiten"</string>
-    <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Ermöglicht der App, die Anrufliste Ihres Tablets zu ändern, einschließlich der Daten über ein- und ausgehende Anrufe. Schädliche Apps können so Ihre Anrufliste löschen oder ändern."</string>
-    <string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"Ermöglicht der App, die Anrufliste Ihres Fernsehers zu ändern, einschließlich der Daten über ein- und ausgehende Anrufe. Schädliche Apps können so Ihre Anrufliste löschen oder ändern."</string>
-    <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Ermöglicht der App, die Anrufliste Ihres Telefons zu ändern, einschließlich der Daten über ein- und ausgehende Anrufe. Schädliche Apps können so Ihre Anrufliste löschen oder ändern."</string>
+    <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Ermöglicht der App, die Anrufliste deines Tablets zu ändern, einschließlich der Daten über ein- und ausgehende Anrufe. Schädliche Apps können so deine Anrufliste löschen oder ändern."</string>
+    <string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"Ermöglicht der App, die Anrufliste deines Fernsehers zu ändern, einschließlich der Daten über ein- und ausgehende Anrufe. Schädliche Apps können so deine Anrufliste löschen oder ändern."</string>
+    <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Ermöglicht der App, die Anrufliste deines Telefons zu ändern, einschließlich der Daten über ein- und ausgehende Anrufe. Schädliche Apps können so deine Anrufliste löschen oder ändern."</string>
     <string name="permlab_bodySensors" msgid="4683341291818520277">"Auf Körpersensoren wie z. B. Herzfrequenzmesser zugreifen"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"Ermöglicht der App, auf Daten von Sensoren zuzugreifen, die Ihre körperliche Verfassung überwachen, beispielsweise Ihren Puls"</string>
+    <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"Ermöglicht der App, auf Daten von Sensoren zuzugreifen, die deine körperliche Verfassung überwachen, beispielsweise deinen Puls"</string>
     <string name="permlab_readCalendar" msgid="5972727560257612398">"Kalendertermine sowie vertrauliche Informationen lesen"</string>
-    <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"Ermöglicht der App, alle auf Ihrem Tablet gespeicherten Kalendertermine zu lesen, einschließlich der von Freunden und Kollegen. Damit kann die App möglicherweise Ihre Kalenderdaten unabhängig von der Vertraulichkeit weiterleiten oder speichern."</string>
-    <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"Ermöglicht der App, alle auf Ihrem Fernseher gespeicherten Kalendertermine zu lesen, einschließlich der von Freunden und Kollegen. Damit kann die App möglicherweise Ihre Kalenderdaten unabhängig von der Vertraulichkeit teilen oder speichern."</string>
-    <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"Ermöglicht der App, alle auf Ihrem Telefon gespeicherten Kalendertermine zu lesen, einschließlich der von Freunden und Kollegen. Damit kann die App möglicherweise Ihre Kalenderdaten unabhängig von der Vertraulichkeit weiterleiten oder speichern."</string>
+    <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"Ermöglicht der App, alle auf deinem Tablet gespeicherten Kalendertermine zu lesen, einschließlich der von Freunden und Kollegen. Damit kann die App möglicherweise deine Kalenderdaten unabhängig von der Vertraulichkeit weiterleiten oder speichern."</string>
+    <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"Ermöglicht der App, alle auf deinem Fernseher gespeicherten Kalendertermine zu lesen, einschließlich der von Freunden und Kollegen. Damit kann die App möglicherweise deine Kalenderdaten unabhängig von der Vertraulichkeit teilen oder speichern."</string>
+    <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"Ermöglicht der App, alle auf deinem Telefon gespeicherten Kalendertermine zu lesen, einschließlich der von Freunden und Kollegen. Damit kann die App möglicherweise deine Kalenderdaten unabhängig von der Vertraulichkeit weiterleiten oder speichern."</string>
     <string name="permlab_writeCalendar" msgid="8438874755193825647">"Ohne das Wissen der Eigentümer Kalendertermine hinzufügen oder ändern und E-Mails an Gäste senden"</string>
-    <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Ermöglicht der App, Termine, die Sie auf Ihrem Tablet ändern können, hinzuzufügen, zu entfernen und zu ändern, einschließlich der von Freunden und Kollegen. Damit kann die App Nachrichten senden, die so erscheinen, als stammten sie vom jeweiligen Kalenderinhaber, oder Termine ohne Wissen des Inhabers ändern."</string>
-    <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"Ermöglicht der App, Termine, die Sie auf Ihrem Fernseher bearbeiten können ‒ einschließlich der von Freunden und Kollegen ‒ hinzuzufügen, zu entfernen und zu ändern. Dadurch kann die App möglicherweise Nachrichten senden, die scheinbar von Kalendereigentümern stammen, oder Termine ohne Wissen der Eigentümer ändern."</string>
-    <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Ermöglicht der App, Termine, die Sie auf Ihrem Telefon ändern können, hinzuzufügen, zu entfernen und zu ändern, einschließlich der von Freunden und Kollegen. Damit kann die App Nachrichten senden, die so erscheinen, als stammten sie vom jeweiligen Kalenderinhaber, oder Termine ohne Wissen des Inhabers ändern."</string>
+    <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Ermöglicht der App, Termine, die du auf deinem Tablet ändern kannst, hinzuzufügen, zu entfernen und zu ändern, einschließlich derjenigen von Freunden und Kollegen. Damit kann die App Nachrichten senden, die so erscheinen, als stammten sie vom jeweiligen Kalenderinhaber, oder Termine ohne Wissen des Inhabers ändern."</string>
+    <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"Ermöglicht der App, Termine, die du auf deinem Fernseher bearbeiten kannst ‒ einschließlich der von Freunden und Kollegen ‒, hinzuzufügen, zu entfernen und zu ändern. Dadurch kann die App möglicherweise Nachrichten senden, die scheinbar von Kalendereigentümern stammen, oder Termine ohne Wissen der Eigentümer ändern."</string>
+    <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Ermöglicht der App, Termine, die du auf deinem Telefon ändern kannst, hinzuzufügen, zu entfernen und zu ändern, einschließlich derjenigen von Freunden und Kollegen. Damit kann die App Nachrichten senden, die so erscheinen, als stammten sie vom jeweiligen Kalenderinhaber, oder kann Termine ohne Wissen des Inhabers ändern."</string>
     <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"Auf zusätzliche Dienstanbieterbefehle für Standort zugreifen"</string>
     <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Ermöglicht der App, auf zusätzliche Standortanbieterbefehle zuzugreifen. Damit könnte die App die Funktionsweise von GPS oder anderen Standortquellen beeinträchtigen."</string>
     <string name="permlab_accessFineLocation" msgid="251034415460950944">"Auf genauen Standort zugreifen (GPS- und netzwerkbasiert)"</string>
-    <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Ermöglicht der App, Ihre genaue Position anhand von GPS-Daten (Global Positioning System) oder über Netzwerkstandortquellen wie Sendemasten oder WLAN zu ermitteln. Diese Standortdienste müssen auf Ihrem Gerät verfügbar und aktiviert sein, damit die App sie verwenden kann. Apps können Ihren Standort anhand dieser Daten ermitteln und verbrauchen eventuell zusätzliche Akkuleistung."</string>
+    <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Ermöglicht der App, deine genaue Position anhand von GPS-Daten (Global Positioning System) oder über Netzwerkstandortquellen wie Sendemasten oder WLAN zu ermitteln. Diese Standortdienste müssen auf deinem Gerät verfügbar und aktiviert sein, damit die App sie verwenden kann. Apps können deinen Standort anhand dieser Daten ermitteln und verbrauchen eventuell zusätzliche Akkuleistung."</string>
     <string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"Auf den ungefähren Standort zugreifen (netzwerkbasiert)"</string>
-    <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Ermöglicht der App, Ihren ungefähren Standort zu ermitteln. Diese Standortangabe stammt von Standortdiensten, die Netzwerkstandortquellen wie etwa Sendemasten oder WLAN verwenden. Diese Standortdienste müssen auf Ihrem Gerät verfügbar und aktiviert sein, damit die App sie verwenden kann. Apps können Ihren ungefähren Standort anhand dieser Daten ermitteln."</string>
+    <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Ermöglicht der App, deinen ungefähren Standort zu ermitteln. Diese Standortangabe stammt von Standortdiensten, die Netzwerkstandortquellen wie etwa Sendemasten oder WLAN verwenden. Diese Standortdienste müssen auf deinem Gerät verfügbar und aktiviert sein, damit die App sie verwenden kann. Apps können deinen ungefähren Standort anhand dieser Daten ermitteln."</string>
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"Audio-Einstellungen ändern"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Ermöglicht der App, globale Audio-Einstellungen zu ändern, etwa die Lautstärke und den Lautsprecher für die Ausgabe."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"Audio aufnehmen"</string>
-    <string name="permdesc_recordAudio" msgid="4906839301087980680">"Ermöglicht der App, Ton mithilfe des Mikrofons aufzunehmen. Die Berechtigung erlaubt der App, Tonaufnahmen jederzeit und ohne Ihre Bestätigung durchzuführen."</string>
+    <string name="permdesc_recordAudio" msgid="4906839301087980680">"Ermöglicht der App, Ton mithilfe des Mikrofons aufzunehmen. Die Berechtigung erlaubt der App, Tonaufnahmen jederzeit und ohne deine Bestätigung durchzuführen."</string>
     <string name="permlab_sim_communication" msgid="2935852302216852065">"Befehle an die SIM senden"</string>
     <string name="permdesc_sim_communication" msgid="5725159654279639498">"Ermöglicht der App das Senden von Befehlen an die SIM-Karte. Dies ist äußerst risikoreich."</string>
     <string name="permlab_camera" msgid="3616391919559751192">"Bilder und Videos aufnehmen"</string>
-    <string name="permdesc_camera" msgid="8497216524735535009">"Ermöglicht der App, Bilder und Videos mit der Kamera aufzunehmen. Die Berechtigung erlaubt der App, die Kamera jederzeit und ohne Ihre Bestätigung zu nutzen."</string>
+    <string name="permdesc_camera" msgid="8497216524735535009">"Ermöglicht der App, Bilder und Videos mit der Kamera aufzunehmen. Die Berechtigung erlaubt der App, die Kamera jederzeit und ohne deine Bestätigung zu nutzen."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"Vibrationsalarm steuern"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Ermöglicht der App, den Vibrationsalarm zu steuern"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"Lichtanzeige steuern"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Ermöglicht der App, die Lichtanzeige zu steuern"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"Telefonnummern direkt anrufen"</string>
-    <string name="permdesc_callPhone" msgid="3740797576113760827">"Ermöglicht der App, ohne Ihr Eingreifen Telefonnummern zu wählen. Dies kann zu unerwarteten Kosten und Anrufen führen. Beachten Sie, dass die App keine Notrufnummern wählen kann. Schädliche Apps verursachen möglicherweise Kosten, indem sie Anrufe ohne Ihre Bestätigung tätigen."</string>
+    <string name="permdesc_callPhone" msgid="3740797576113760827">"Ermöglicht der App, ohne dein Eingreifen Telefonnummern zu wählen. Dies kann zu unerwarteten Kosten und Anrufen führen. Beachte, dass die App keine Notrufnummern wählen kann. Schädliche Apps verursachen möglicherweise Kosten, indem sie Anrufe ohne deine Bestätigung tätigen."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"Zugriff auf IMS-Anrufdienst"</string>
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Ermöglicht der App die Verwendung des IMS-Dienstes zum Tätigen von Anrufen ohne Nutzereingriffe"</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"Telefonstatus und Identität abrufen"</string>
@@ -396,9 +406,9 @@
     <string name="permlab_changeWifiState" msgid="6550641188749128035">"WLAN-Verbindungen herstellen und trennen"</string>
     <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Ermöglicht der App, eine Verbindung zu WLAN-Zugriffspunkten herzustellen und solche zu trennen und Änderungen an der Gerätekonfiguration für WLAN-Netzwerke vorzunehmen."</string>
     <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"WLAN-Multicast-Empfang zulassen"</string>
-    <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Ermöglicht der App, Pakete zu empfangen, die mithilfe von Multicast-Adressen an sämtliche Geräte in einem WLAN versendet wurden, nicht nur an Ihr Tablet. Dies kostet mehr Leistung als der Nicht-Multicast-Modus."</string>
-    <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"Ermöglicht der App, Pakete zu empfangen, die mithilfe von Multicast-Adressen an sämtliche Geräte in einem WLAN gesendet wurden, nicht nur an Ihren Fernseher. Dies kostet mehr Leistung als der Nicht-Multicast-Modus."</string>
-    <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Ermöglicht der App, Pakete zu empfangen, die mithilfe von Multicast-Adressen an sämtliche Geräte in einem WLAN versendet wurden, nicht nur an Ihr Telefon. Dies kostet mehr Leistung als der Nicht-Multicast-Modus."</string>
+    <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Ermöglicht der App, Pakete zu empfangen, die mithilfe von Multicast-Adressen an sämtliche Geräte in einem WLAN versendet wurden, nicht nur an dein Tablet. Dies nicht mehr Leistung in Anspruch als der Nicht-Multicast-Modus."</string>
+    <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"Ermöglicht der App, Pakete zu empfangen, die mithilfe von Multicast-Adressen an sämtliche Geräte in einem WLAN gesendet wurden, nicht nur an deinen Fernseher. Dies nimmt mehr Leistung in Anspruch als der Nicht-Multicast-Modus."</string>
+    <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Ermöglicht der App, Pakete zu empfangen, die mithilfe von Multicast-Adressen an sämtliche Geräte in einem WLAN versendet wurden, nicht nur an dein Telefon. Dies nimmt mehr Leistung in Anspruch als der Nicht-Multicast-Modus."</string>
     <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"Auf Bluetooth-Einstellungen zugreifen"</string>
     <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Ermöglicht der App, das lokale Bluetooth-Tablet zu konfigurieren, Remote-Geräte zu erkennen und eine Verbindung zu diesen herzustellen"</string>
     <string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"Ermöglicht der App, den lokalen Bluetooth-Fernseher zu konfigurieren, Remote-Geräte zu erkennen und ein Pairing mit diesen durchzuführen"</string>
@@ -421,19 +431,19 @@
     <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Erlaubt der App, Methoden zum Hinzufügen und Löschen zu verwendender Fingerabdruckvorlagen aufzurufen"</string>
     <string name="permlab_useFingerprint" msgid="3150478619915124905">"Fingerabdruckhardware verwenden"</string>
     <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Erlaubt der App, Fingerabdruckhardware zur Authentifizierung zu verwenden"</string>
-    <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Fingerabdruck teilweise erkannt. Versuchen Sie es erneut."</string>
-    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Fingerabdruck konnte nicht verarbeitet werden. Versuchen Sie es erneut."</string>
-    <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingerabdrucksensor ist verschmutzt. Reinigen Sie ihn und versuchen Sie es erneut."</string>
-    <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Finger zu schnell bewegt. Versuchen Sie es erneut."</string>
-    <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Finger zu langsam bewegt. Versuchen Sie es erneut."</string>
+    <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Fingerabdruck teilweise erkannt. Versuche es erneut."</string>
+    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Fingerabdruck konnte nicht verarbeitet werden. Versuche es erneut."</string>
+    <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingerabdrucksensor ist verschmutzt. Reinige ihn und versuche es erneut."</string>
+    <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Finger zu schnell bewegt. Versuche es erneut."</string>
+    <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Finger zu langsam bewegt. Versuche es erneut."</string>
   <string-array name="fingerprint_acquired_vendor">
   </string-array>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerabdruckhardware nicht verfügbar"</string>
-    <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerabdruck kann nicht gespeichert werden. Entfernen Sie einen vorhandenen Fingerabdruck."</string>
-    <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Zeitüberschreitung für Fingerabdruck. Versuchen Sie es erneut."</string>
+    <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerabdruck kann nicht gespeichert werden. Entferne einen vorhandenen Fingerabdruck."</string>
+    <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Zeitüberschreitung für Fingerabdruck. Versuche es erneut."</string>
     <string name="fingerprint_error_canceled" msgid="4402024612660774395">"Fingerabdruckvorgang abgebrochen"</string>
-    <string name="fingerprint_error_lockout" msgid="5536934748136933450">"Zu viele Versuche. Versuchen Sie es später erneut."</string>
-    <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Bitte versuchen Sie es erneut."</string>
+    <string name="fingerprint_error_lockout" msgid="5536934748136933450">"Zu viele Versuche. Versuche es später erneut."</string>
+    <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Bitte versuche es erneut."</string>
     <string name="fingerprint_name_template" msgid="5870957565512716938">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
@@ -510,11 +520,11 @@
     <string name="policylab_resetPassword" msgid="4934707632423915395">"Displaysperre ändern"</string>
     <string name="policydesc_resetPassword" msgid="1278323891710619128">"Displaysperre ändern"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Bildschirm sperren"</string>
-    <string name="policydesc_forceLock" msgid="1141797588403827138">"Legen Sie fest, wie und wann der Bildschirm gesperrt wird."</string>
+    <string name="policydesc_forceLock" msgid="1141797588403827138">"Lege fest, wie und wann der Bildschirm gesperrt wird."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Alle Daten löschen"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Auf Werkseinstellungen zurücksetzen und Daten auf dem Tablet ohne Warnung löschen"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Auf Werkseinstellungen zurücksetzen und Daten auf dem Fernseher ohne Warnung löschen"</string>
-    <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Setzen Sie das Telefon auf die Werkseinstellungen zurück. Dabei werden alle Daten ohne Warnung gelöscht."</string>
+    <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Setze das Telefon auf die Werkseinstellungen zurück. Dabei werden alle Daten ohne Warnung gelöscht."</string>
     <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Nutzerdaten löschen"</string>
     <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Daten dieses Nutzers auf diesem Tablet ohne vorherige Warnung löschen"</string>
     <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Daten dieses Nutzers auf diesem Fernseher ohne vorherige Warnung löschen"</string>
@@ -651,11 +661,11 @@
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Passwort zum Entsperren eingeben"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"PIN zum Entsperren eingeben"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Falscher PIN-Code"</string>
-    <string name="keyguard_label_text" msgid="861796461028298424">"Drücken Sie zum Entsperren die Menütaste und dann auf \"0\"."</string>
+    <string name="keyguard_label_text" msgid="861796461028298424">"Drücke zum Entsperren die Menütaste und dann auf \"0\"."</string>
     <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Notrufnummer"</string>
     <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Kein Dienst"</string>
     <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Display gesperrt"</string>
-    <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Drücken Sie die Menütaste, um das Telefon zu entsperren oder einen Notruf zu tätigen."</string>
+    <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Drücke die Menütaste, um das Telefon zu entsperren oder einen Notruf zu tätigen."</string>
     <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Zum Entsperren die Menütaste drücken"</string>
     <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Muster zum Entsperren zeichnen"</string>
     <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Notfall"</string>
@@ -668,10 +678,10 @@
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Keine SIM-Karte im Tablet"</string>
     <string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"Keine SIM-Karte im Fernseher"</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"Keine SIM-Karte im Telefon"</string>
-    <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Legen Sie eine SIM-Karte ein."</string>
-    <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM-Karte fehlt oder ist nicht lesbar. Bitte legen Sie eine SIM-Karte ein."</string>
+    <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Lege eine SIM-Karte ein."</string>
+    <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM-Karte fehlt oder ist nicht lesbar. Bitte lege eine SIM-Karte ein."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"SIM-Karte unbrauchbar"</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Ihre SIM-Karte wurde dauerhaft deaktiviert.\n Wenden Sie sich an Ihren Mobilfunkanbieter, um eine andere SIM-Karte zu erhalten."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Deine SIM-Karte wurde dauerhaft deaktiviert.\n Wende dich an deinen Mobilfunkanbieter, um eine andere SIM-Karte zu erhalten."</string>
     <string name="lockscreen_transport_prev_description" msgid="6300840251218161534">"Vorheriger Titel"</string>
     <string name="lockscreen_transport_next_description" msgid="573285210424377338">"Nächster Titel"</string>
     <string name="lockscreen_transport_pause_description" msgid="3980308465056173363">"Pausieren"</string>
@@ -682,31 +692,31 @@
     <string name="emergency_calls_only" msgid="6733978304386365407">"Nur Notrufe"</string>
     <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Netzwerk gesperrt"</string>
     <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"PUK-Sperre auf SIM"</string>
-    <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Weitere Informationen erhalten Sie im Nutzerhandbuch oder beim Kundendienst."</string>
+    <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Weitere Informationen erhältst du im Nutzerhandbuch oder beim Kundendienst."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"PIN eingeben"</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM-Karte wird entsperrt..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. \n\nBitte versuchen Sie es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden noch einmal."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Sie haben Ihr Passwort <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch eingegeben.\n\nBitte versuchen Sie es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden noch einmal."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Sie haben Ihr Passwort <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch eingegeben.\n\nBitte versuchen Sie es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden noch einmal."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Tablet mithilfe Ihrer Google-Anmeldeinformationen zu entsperren.\n\n Bitte versuchen Sie es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden noch einmal."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Wenn Sie es noch <xliff:g id="NUMBER_1">%2$d</xliff:g>-mal falsch eingeben, werden Sie aufgefordert, Ihren Fernseher mithilfe Ihrer Google-Anmeldeinformationen zu entsperren.\n\n Versuchen Sie es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden erneut."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe Ihrer Google-Anmeldeinformationen zu entsperren.\n\nBitte versuchen Sie es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden noch einmal."</string>
-    <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Sie haben <xliff:g id="NUMBER_0">%1$d</xliff:g> Mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird das Tablet auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
-    <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"Sie haben <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, den Fernseher zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird der Fernseher auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
-    <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Sie haben <xliff:g id="NUMBER_0">%1$d</xliff:g> Mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird das Telefon auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
-    <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Das Tablet wird nun auf die Werkseinstellungen zurückgesetzt."</string>
-    <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, den Fernseher zu entsperren. Der Fernseher wird nun auf die Werkseinstellungen zurückgesetzt."</string>
-    <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Das Telefon wird nun auf die Werkseinstellungen zurückgesetzt."</string>
-    <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Versuchen Sie es in <xliff:g id="NUMBER">%d</xliff:g> Sekunden erneut."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. \n\nBitte versuche es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden noch einmal."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Du hast dein Passwort <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch eingegeben.\n\nBitte versuche es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden noch einmal."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Du hast dein Passwort <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch eingegeben.\n\nBitte versuche es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden noch einmal."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Tablet mithilfe deiner Google-Anmeldeinformationen zu entsperren.\n\n Bitte versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden noch einmal."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Wenn du es noch <xliff:g id="NUMBER_1">%2$d</xliff:g>-mal falsch eingibst, wirst du aufgefordert, deinen Fernseher mithilfe deiner Google-Anmeldeinformationen zu entsperren.\n\n Versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden erneut."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Telefon mithilfe deiner Google-Anmeldeinformationen zu entsperren.\n\nBitte versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden noch einmal."</string>
+    <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g> Mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird das Tablet auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
+    <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, den Fernseher zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird der Fernseher auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
+    <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g> Mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird das Telefon auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
+    <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Das Tablet wird nun auf die Werkseinstellungen zurückgesetzt."</string>
+    <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, den Fernseher zu entsperren. Der Fernseher wird nun auf die Werkseinstellungen zurückgesetzt."</string>
+    <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Das Telefon wird nun auf die Werkseinstellungen zurückgesetzt."</string>
+    <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Versuche es in <xliff:g id="NUMBER">%d</xliff:g> Sekunden erneut."</string>
     <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Muster vergessen?"</string>
     <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Kontoentsperrung"</string>
     <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Zu viele Schemaversuche"</string>
-    <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Melden Sie sich zum Entsperren mit Ihrem Google-Konto an."</string>
+    <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Melde dich zum Entsperren mit deinem Google-Konto an."</string>
     <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nutzername (E-Mail)"</string>
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Passwort"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Anmelden"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Ungültiger  Nutzername oder ungültiges Passwort."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Nutzernamen oder Passwort vergessen?\nBesuchen Sie "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Nutzernamen oder Passwort vergessen?\nBesuche "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Überprüfung..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Entsperren"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Ton ein"</string>
@@ -754,7 +764,7 @@
     <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Navigation bestätigen"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Diese Seite verlassen"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Auf dieser Seite bleiben"</string>
-    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nMöchten Sie diese Seite wirklich verlassen?"</string>
+    <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nMöchtest du diese Seite wirklich verlassen?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Bestätigen"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tipp: Zum Vergrößern und Verkleinern zweimal tippen"</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"AutoFill"</string>
@@ -778,20 +788,20 @@
     <string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"Lesezeichen für Webseiten und das Webprotokoll lesen"</string>
     <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Ermöglicht der App, den Verlauf aller mit dem Browser besuchten URLs und sämtliche Lesezeichen des Browsers zu lesen. Hinweis: Diese Berechtigung kann nicht von Browsern von Drittanbietern oder anderen Apps mit Internetfunktionen erzwungen werden."</string>
     <string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"Lesezeichen für Webseiten setzen und das Webprotokoll aufzeichnen"</string>
-    <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Ermöglicht der App, den Browserverlauf und die Lesezeichen auf Ihrem Tablet zu ändern. Damit kann die App Browserdaten löschen und ändern. Hinweis: Diese Berechtigung kann nicht von Browsern von Drittanbietern oder anderen Apps mit Internetfunktionen erzwungen werden."</string>
-    <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"Ermöglicht der App, den Browserverlauf und die Lesezeichen auf Ihrem Fernseher zu bearbeiten. Damit kann die App Browserdaten löschen und ändern. Hinweis: Diese Berechtigung kann nicht von Browsern von Drittanbietern oder anderen Apps mit Internetfunktionen erzwungen werden."</string>
-    <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Ermöglicht der App, den Browserverlauf und die Lesezeichen auf Ihrem Telefon zu ändern. Damit kann die App Browserdaten löschen und ändern. Hinweis: Diese Berechtigung kann nicht von Browsern von Drittanbietern oder anderen Apps mit Internetfunktionen erzwungen werden."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Ermöglicht der App, den Browserverlauf und die Lesezeichen auf deinem Tablet zu ändern. Damit kann die App Browserdaten löschen und ändern. Hinweis: Diese Berechtigung kann nicht von Browsern von Drittanbietern oder anderen Apps mit Internetfunktionen erzwungen werden."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"Ermöglicht der App, den Browserverlauf und die Lesezeichen auf deinem Fernseher zu bearbeiten. Damit kann die App Browserdaten löschen und ändern. Hinweis: Diese Berechtigung kann nicht von Browsern von Drittanbietern oder anderen Apps mit Internetfunktionen erzwungen werden."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Ermöglicht der App, den Browserverlauf und die Lesezeichen auf deinem Telefon zu ändern. Damit kann die App Browserdaten löschen und ändern. Hinweis: Diese Berechtigung kann nicht von Browsern von Drittanbietern oder anderen Apps mit Internetfunktionen erzwungen werden."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"Wecker stellen"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Ermöglicht der App, einen Alarm in einer installierten Wecker-App einzurichten. Einige Wecker-Apps implementieren diese Funktion möglicherweise nicht."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"Mailbox-Nachrichten hinzufügen"</string>
-    <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Ermöglicht der App, Nachrichten zu Ihrem Mailbox-Posteingang hinzuzufügen"</string>
+    <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Ermöglicht der App, Nachrichten zu deinem Mailbox-Posteingang hinzuzufügen"</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Geolokalisierungsberechtigungen des Browsers ändern"</string>
     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Ermöglicht der App, die Geolokalisierungsberechtigungen des Browsers zu ändern. Schädliche Apps können so Standortinformationen an beliebige Websites senden."</string>
-    <string name="save_password_message" msgid="767344687139195790">"Möchten Sie, dass der Browser dieses Passwort speichert?"</string>
+    <string name="save_password_message" msgid="767344687139195790">"Möchtest du, dass der Browser dieses Passwort speichert?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Nicht jetzt"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Speichern"</string>
     <string name="save_password_never" msgid="8274330296785855105">"Nie"</string>
-    <string name="open_permission_deny" msgid="7374036708316629800">"Sie sind nicht zum Öffnen dieser Seite berechtigt."</string>
+    <string name="open_permission_deny" msgid="7374036708316629800">"Du bist nicht zum Öffnen dieser Seite berechtigt."</string>
     <string name="text_copied" msgid="4985729524670131385">"Text in Zwischenablage kopiert."</string>
     <string name="more_item_label" msgid="4650918923083320495">"Mehr"</string>
     <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menü+"</string>
@@ -806,8 +816,8 @@
     <string name="searchview_description_submit" msgid="2688450133297983542">"Anfrage senden"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Sprachsuche"</string>
     <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"\"Tippen &amp; Entdecken\" aktivieren?"</string>
-    <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> fordert die Aktivierung von \"Tippen &amp; Entdecken\". Wenn \"Tippen &amp; Entdecken\" aktiviert ist, können Sie Beschreibungen dessen hören oder sehen, was sich unter ihren Fingern befindet, oder Gesten ausführen, um mit dem Tablet zu kommunizieren."</string>
-    <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> fordert die Aktivierung von \"Tippen &amp; Entdecken\". Wenn \"Tippen &amp; Entdecken\" aktiviert ist, können Sie Beschreibungen dessen hören oder sehen, was sich unter ihren Fingern befindet, oder Gesten ausführen, um mit dem Telefon zu kommunizieren."</string>
+    <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> fordert die Aktivierung von \"Tippen &amp; Entdecken\" an. Wenn \"Tippen &amp; Entdecken\" aktiviert ist, kannst du Beschreibungen dessen hören oder sehen, was sich unter deinen Fingern befindet, oder Gesten ausführen, um mit dem Tablet zu kommunizieren."</string>
+    <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> fordert die Aktivierung von \"Tippen &amp; Entdecken\" an. Wenn \"Tippen &amp; Entdecken\" aktiviert ist, kannst du Beschreibungen dessen hören oder sehen, was sich unter deinen Fingern befindet, oder Gesten ausführen, um mit dem Telefon zu kommunizieren."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"Vor 1 Monat"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Vor mehr als 1 Monat"</string>
     <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Ausschneiden"</string>
     <string name="copy" msgid="2681946229533511987">"Kopieren"</string>
     <string name="paste" msgid="5629880836805036433">"Einfügen"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Nur Text einfügen"</string>
     <string name="replace" msgid="5781686059063148930">"Ersetzen..."</string>
     <string name="delete" msgid="6098684844021697789">"Löschen"</string>
     <string name="copyUrl" msgid="2538211579596067402">"URL kopieren"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Text auswählen"</string>
+    <string name="undo" msgid="7905788502491742328">"Rückgängig machen"</string>
+    <string name="redo" msgid="7759464876566803888">"Wiederholen"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Textauswahl"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Zum Wörterbuch hinzufügen"</string>
     <string name="deleteText" msgid="6979668428458199034">"Löschen"</string>
@@ -869,7 +882,7 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Textaktionen"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Der Speicherplatz wird knapp"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Einige Systemfunktionen funktionieren möglicherweise nicht."</string>
-    <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Der Speicherplatz reicht nicht für das System aus. Stellen Sie sicher, dass 250 MB freier Speicherplatz vorhanden ist, und starten Sie das Gerät dann neu."</string>
+    <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Der Speicherplatz reicht nicht für das System aus. Stelle sicher, dass 250 MB freier Speicherplatz vorhanden sind, und starte das Gerät dann neu."</string>
     <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> wird ausgeführt"</string>
     <string name="app_running_notification_text" msgid="4653586947747330058">"Für weitere Informationen oder zum Anhalten der App tippen"</string>
     <string name="ok" msgid="5970060430562524910">"OK"</string>
@@ -901,21 +914,21 @@
     <string name="aerr_process" msgid="4507058997035697579">"Der Prozess \"<xliff:g id="PROCESS">%1$s</xliff:g>\" wurde beendet."</string>
     <string name="aerr_process_silence" msgid="4226685530196000222">"Silence stürzt bei <xliff:g id="PROCESS">%1$s</xliff:g> bis zum Neustart ab."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> reagiert nicht.\n\nMöchten Sie die App schließen?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"Aktivität \"<xliff:g id="ACTIVITY">%1$s</xliff:g>\" reagiert nicht.\n\nMöchten Sie sie beenden?"</string>
-    <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> reagiert nicht. Möchten Sie die App schließen?"</string>
-    <string name="anr_process" msgid="6513209874880517125">"Prozess \"<xliff:g id="PROCESS">%1$s</xliff:g>\" reagiert nicht.\n\nMöchten Sie ihn beenden?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> reagiert nicht.\n\nMöchtest du die App schließen?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Aktivität \"<xliff:g id="ACTIVITY">%1$s</xliff:g>\" reagiert nicht.\n\nMöchtest du sie beenden?"</string>
+    <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> reagiert nicht. Möchtest du die App schließen?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Prozess \"<xliff:g id="PROCESS">%1$s</xliff:g>\" reagiert nicht.\n\nMöchtest du ihn beenden?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Bericht"</string>
     <string name="wait" msgid="7147118217226317732">"Warten"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"Die Seite reagiert nicht mehr.\n\nMöchten Sie die Seite schließen?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Die Seite reagiert nicht mehr.\n\nMöchtest du die Seite schließen?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"App umgeleitet"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> wird jetzt ausgeführt."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> wurde ursprünglich gestartet."</string>
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Skalieren"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Immer anzeigen"</string>
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Eine erneute Aktivierung ist in den Systemeinstellungen unter \"Apps &gt; Heruntergeladen\" möglich."</string>
-    <string name="smv_application" msgid="3307209192155442829">"Die App <xliff:g id="APPLICATION">%1$s</xliff:g> (Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) hat gegen ihre selbsterzwungene StrictMode-Richtlinie verstoßen."</string>
+    <string name="smv_application" msgid="3307209192155442829">"Die App <xliff:g id="APPLICATION">%1$s</xliff:g> (Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) hat gegen deine selbsterzwungene StrictMode-Richtlinie verstoßen."</string>
     <string name="smv_process" msgid="5120397012047462446">"Der Prozess <xliff:g id="PROCESS">%1$s</xliff:g> hat gegen seine selbsterzwungene StrictMode-Richtlinie verstoßen."</string>
     <string name="android_upgrading_title" msgid="1584192285441405746">"Android wird aktualisiert..."</string>
     <string name="android_start_title" msgid="8418054686415318207">"Android wird gestartet…"</string>
@@ -935,7 +948,7 @@
     <string name="dump_heap_notification" msgid="2618183274836056542">"Speicherlimit für \"<xliff:g id="PROC">%1$s</xliff:g>\" überschritten"</string>
     <string name="dump_heap_notification_detail" msgid="2075673362317481664">"Heap-Dump wurde erfasst, zum Teilen tippen"</string>
     <string name="dump_heap_title" msgid="5864292264307651673">"Heap-Dump teilen?"</string>
-    <string name="dump_heap_text" msgid="4809417337240334941">"Für den Prozess \"<xliff:g id="PROC">%1$s</xliff:g>\" wurde das Prozessspeicherlimit von <xliff:g id="SIZE">%2$s</xliff:g> überschritten. Es steht ein Heap-Dump zur Verfügung, den Sie mit dem Entwickler teilen können. Beachten Sie jedoch unbedingt, dass der Heap-Dump personenbezogene Daten von Ihnen enthalten kann, auf die die App zugreifen kann."</string>
+    <string name="dump_heap_text" msgid="4809417337240334941">"Für den Prozess \"<xliff:g id="PROC">%1$s</xliff:g>\" wurde das Prozessspeicherlimit von <xliff:g id="SIZE">%2$s</xliff:g> überschritten. Es steht ein Heap-Dump zur Verfügung, den du mit dem Entwickler teilen kannst. Beachte jedoch unbedingt, dass der Heap-Dump personenbezogene Daten von dir enthalten kann, auf die die App zugreifen kann."</string>
     <string name="sendText" msgid="5209874571959469142">"Aktion für Text auswählen"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Klingeltonlautstärke"</string>
     <string name="volume_music" msgid="5421651157138628171">"Medienlautstärke"</string>
@@ -986,30 +999,30 @@
     <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Einladung zum Aufbau einer Verbindung"</string>
     <string name="wifi_p2p_from_message" msgid="570389174731951769">"Von:"</string>
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"An:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Geben Sie die PIN ein:"</string>
+    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Gib die PIN ein:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
     <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Das Tablet wird vorübergehend vom WLAN getrennt, während eine Verbindung mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> besteht."</string>
     <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="3087858235069421128">"Der Fernseher wird vorübergehend vom WLAN getrennt, während eine Verbindung mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> besteht."</string>
     <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Das Telefon wird vorübergehend vom WLAN getrennt, während eine Verbindung mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> hergestellt wird."</string>
     <string name="select_character" msgid="3365550120617701745">"Zeichen einfügen"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS werden gesendet"</string>
-    <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sendet eine große Anzahl SMS. Möchten Sie zulassen, dass die App weiterhin Nachrichten sendet?"</string>
+    <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sendet eine große Anzahl SMS. Möchtest du zulassen, dass die App weiterhin Nachrichten sendet?"</string>
     <string name="sms_control_yes" msgid="3663725993855816807">"Zulassen"</string>
     <string name="sms_control_no" msgid="625438561395534982">"Nicht zulassen"</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; möchte eine Nachricht an &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt; senden."</string>
-    <string name="sms_short_code_details" msgid="5873295990846059400">"Hierfür könnten Ihrem Mobilfunkkonto "<b>"Gebühren berechnet werden"</b>"."</string>
-    <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Hierfür werden Ihrem Mobilfunkkonto Gebühren berechnet."</b></string>
+    <string name="sms_short_code_details" msgid="5873295990846059400">"Hierfür könnten deinem Mobilfunkkonto "<b>"Gebühren berechnet werden"</b>"."</string>
+    <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Hierfür werden deinem Mobilfunkkonto Gebühren berechnet."</b></string>
     <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Senden"</string>
     <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Abbrechen"</string>
     <string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Auswahl merken"</string>
-    <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Sie können dies unter \"Einstellungen &gt; Apps\" ändern."</string>
+    <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Du kannst dies unter \"Einstellungen &gt; Apps\" ändern."</string>
     <string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Immer zulassen"</string>
     <string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Nie zulassen"</string>
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM-Karte entfernt"</string>
-    <string name="sim_removed_message" msgid="5450336489923274918">"Das Mobilfunknetz ist erst wieder verfügbar, wenn Sie einen Neustart mit einer gültigen SIM-Karte durchführen."</string>
+    <string name="sim_removed_message" msgid="5450336489923274918">"Das Mobilfunknetz ist erst wieder verfügbar, wenn du einen Neustart mit einer gültigen SIM-Karte durchführst."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Fertig"</string>
     <string name="sim_added_title" msgid="3719670512889674693">"SIM-Karte hinzugefügt"</string>
-    <string name="sim_added_message" msgid="7797975656153714319">"Starten Sie zur Nutzung des Mobilfunknetzes Ihr Gerät neu."</string>
+    <string name="sim_added_message" msgid="7797975656153714319">"Starte zur Nutzung des Mobilfunknetzes dein Gerät neu."</string>
     <string name="sim_restart_button" msgid="4722407842815232347">"Neu starten"</string>
     <string name="time_picker_dialog_title" msgid="8349362623068819295">"Uhrzeit festlegen"</string>
     <string name="date_picker_dialog_title" msgid="5879450659453782278">"Datum festlegen"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Fehlerbericht mit Administrator teilen?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Dein IT-Administrator hat einen Fehlerbericht zur Fehlerbehebung angefordert."</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"AKZEPTIEREN"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ABLEHNEN"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Fehlerbericht wird aufgerufen…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Zum Abbrechen tippen"</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="9157568568695230830">"Eingabemethode anzeigen"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardware"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1046,7 +1065,7 @@
     <string name="ext_media_unsupported_notification_title" msgid="3797642322958803257">"<xliff:g id="NAME">%s</xliff:g> nicht unterstützt"</string>
     <string name="ext_media_unsupported_notification_message" msgid="8789610369456474891">"<xliff:g id="NAME">%s</xliff:g> wird von diesem Gerät nicht unterstützt. Zum Einrichten in einem unterstützten Format tippen."</string>
     <string name="ext_media_badremoval_notification_title" msgid="3206248947375505416">"<xliff:g id="NAME">%s</xliff:g> wurde unerwartet entfernt"</string>
-    <string name="ext_media_badremoval_notification_message" msgid="380176703346946313">"Trennen Sie die <xliff:g id="NAME">%s</xliff:g> vor dem Entfernen, um Datenverluste zu vermeiden."</string>
+    <string name="ext_media_badremoval_notification_message" msgid="380176703346946313">"Trenne die <xliff:g id="NAME">%s</xliff:g> vor dem Entfernen, um Datenverluste zu vermeiden."</string>
     <string name="ext_media_nomedia_notification_title" msgid="1704840188641749091">"<xliff:g id="NAME">%s</xliff:g> wurde entfernt"</string>
     <string name="ext_media_nomedia_notification_message" msgid="6471542972147056586">"<xliff:g id="NAME">%s</xliff:g> entfernt. Neuen Speicher einlegen"</string>
     <string name="ext_media_unmounting_notification_title" msgid="640674168454809372">"<xliff:g id="NAME">%s</xliff:g> wird gerade ausgeworfen…"</string>
@@ -1091,15 +1110,15 @@
     <string name="ime_action_default" msgid="2840921885558045721">"Ausführen"</string>
     <string name="dial_number_using" msgid="5789176425167573586">"Nummer\nmit <xliff:g id="NUMBER">%s</xliff:g> wählen"</string>
     <string name="create_contact_using" msgid="4947405226788104538">"Neuer Kontakt\nmit <xliff:g id="NUMBER">%s</xliff:g> erstellen"</string>
-    <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Die folgenden Apps benötigen die Berechtigung zum aktuellen und zukünftigen Zugriff auf Ihr Konto."</string>
-    <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Möchten Sie diese Anfrage zulassen?"</string>
+    <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Die folgenden Apps benötigen die Berechtigung zum aktuellen und zukünftigen Zugriff auf dein Konto."</string>
+    <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Möchtest du diese Anfrage zulassen?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Zugriffsanforderung"</string>
     <string name="allow" msgid="7225948811296386551">"Zulassen"</string>
     <string name="deny" msgid="2081879885755434506">"Ablehnen"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Berechtigung angefordert"</string>
     <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Berechtigung angefordert\nfür Konto <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
-    <string name="forward_intent_to_owner" msgid="1207197447013960896">"Sie verwenden diese App außerhalb Ihres Arbeitsprofils."</string>
-    <string name="forward_intent_to_work" msgid="621480743856004612">"Sie verwenden diese App in Ihrem Arbeitsprofil."</string>
+    <string name="forward_intent_to_owner" msgid="1207197447013960896">"Du verwendest diese App außerhalb deines Arbeitsprofils."</string>
+    <string name="forward_intent_to_work" msgid="621480743856004612">"Du verwendest diese App in deinem Arbeitsprofil."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Eingabemethode"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Synchronisieren"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Bedienungshilfen"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Hintergrund ändern"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Benachrichtigungs-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="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>
@@ -1146,7 +1166,7 @@
     <string name="gpsVerifYes" msgid="2346566072867213563">"Ja"</string>
     <string name="gpsVerifNo" msgid="1146564937346454865">"Nein"</string>
     <string name="sync_too_many_deletes" msgid="5296321850662746890">"Löschbegrenzung überschritten"</string>
-    <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"Es sind <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> gelöschte Elemente für <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>, Konto <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>, vorhanden. Wie möchten Sie fortfahren?"</string>
+    <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"Es sind <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> gelöschte Elemente für <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>, Konto <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>, vorhanden. Wie möchtest du fortfahren?"</string>
     <string name="sync_really_delete" msgid="2572600103122596243">"Elemente löschen"</string>
     <string name="sync_undo_deletes" msgid="2941317360600338602">"Löschen rückgängig machen"</string>
     <string name="sync_do_nothing" msgid="3743764740430821845">"Im Moment nichts unternehmen"</string>
@@ -1184,7 +1204,7 @@
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Mit <xliff:g id="APPLICATION_NAME">%s</xliff:g> teilen"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Schieberegler: Berühren und halten"</string>
     <string name="description_target_unlock_tablet" msgid="3833195335629795055">"Zum Entsperren den Finger über den Bildschirm ziehen"</string>
-    <string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Schließen Sie ein Headset an, um das Passwort gesprochen zu hören."</string>
+    <string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Schließe ein Headset an, um das Passwort gesprochen zu hören."</string>
     <string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Punkt."</string>
     <string name="action_bar_home_description" msgid="5293600496601490216">"Zur Startseite navigieren"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Nach oben navigieren"</string>
@@ -1264,44 +1284,44 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Falsches Muster"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Falsches Passwort"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Falsche PIN"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Versuchen Sie es in <xliff:g id="NUMBER">%1$d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Versuche es in <xliff:g id="NUMBER">%1$d</xliff:g> Sekunden erneut."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Muster zeichnen"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM-PIN eingeben"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"PIN eingeben"</string>
     <string name="kg_password_instructions" msgid="5753646556186936819">"Passwort eingeben"</string>
-    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Die SIM-Karte ist jetzt deaktiviert. Geben Sie den PUK-Code ein, um fortzufahren. Weitere Informationen erhalten Sie von Ihrem Mobilfunkanbieter."</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Die SIM-Karte ist jetzt deaktiviert. Gib den PUK-Code ein, um fortzufahren. Weitere Informationen erhältst du von deinem Mobilfunkanbieter."</string>
     <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Gewünschten PIN-Code eingeben"</string>
     <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Gewünschten PIN-Code bestätigen"</string>
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM-Karte wird entsperrt…"</string>
     <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Falscher PIN-Code"</string>
-    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Geben Sie eine 4- bis 8-stellige PIN ein."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Gib eine 4- bis 8-stellige PIN ein."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"Der PUK-Code muss 8 Ziffern aufweisen."</string>
-    <string name="kg_invalid_puk" msgid="3638289409676051243">"Geben Sie den richtigen PUK-Code ein. Bei wiederholten Versuchen wird die SIM-Karte dauerhaft deaktiviert."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Gib den richtigen PUK-Code ein. Bei wiederholten Versuchen wird die SIM-Karte dauerhaft deaktiviert."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-Codes stimmen nicht überein"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Zu viele Musterversuche"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Melden Sie sich zum Entsperren mit Ihrem Google-Konto an."</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Melde dich zum Entsperren mit deinem Google-Konto an."</string>
     <string name="kg_login_username_hint" msgid="5718534272070920364">"Nutzername (E-Mail)"</string>
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Passwort"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Anmelden"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ungültiger Nutzername oder ungültiges Passwort"</string>
-    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Nutzernamen oder Passwort vergessen?\nBesuchen Sie "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Nutzernamen oder Passwort vergessen?\nBesuche "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Konto wird geprüft…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Sie haben Ihre PIN <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch eingegeben.\n\nVersuchen Sie es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden erneut."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Sie haben Ihr Passwort <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch eingegeben.\n\nVersuchen Sie es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden erneut."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. \n\nVersuchen Sie es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden erneut."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Sie haben <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird das Tablet auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"Sie haben <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, den Fernseher zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird der Fernseher auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Sie haben <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird das Telefon auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Das Tablet wird nun auf die Werkseinstellungen zurückgesetzt."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tv" msgid="4987878286750741463">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, den Fernseher zu entsperren. Der Fernseher wird nun auf die Werkseinstellungen zurückgesetzt."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Das Telefon wird nun auf die Werkseinstellungen zurückgesetzt."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Tablet mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuchen Sie es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden erneut."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Wenn Sie es noch <xliff:g id="NUMBER_1">%2$d</xliff:g>-mal falsch eingeben, werden Sie aufgefordert, Ihren Fernseher mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuchen Sie es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden erneut."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuchen Sie es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du hast deine PIN <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch eingegeben.\n\nVersuche es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du hast dein Passwort <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch eingegeben.\n\nVersuche es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. \n\nVersuche es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird das Tablet auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, den Fernseher zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird der Fernseher auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird das Telefon auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Das Tablet wird nun auf die Werkseinstellungen zurückgesetzt."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tv" msgid="4987878286750741463">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, den Fernseher zu entsperren. Der Fernseher wird nun auf die Werkseinstellungen zurückgesetzt."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Das Telefon wird nun auf die Werkseinstellungen zurückgesetzt."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Tablet mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Wenn du es noch <xliff:g id="NUMBER_1">%2$d</xliff:g>-mal falsch eingibst, wirst du aufgefordert, deinen Fernseher mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Telefon mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden erneut."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Entfernen"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Lautstärke über den Schwellenwert anheben?\n\nWenn Sie über längere Zeiträume hinweg Musik in hoher Lautstärke hören, kann dies Ihr Gehör schädigen."</string>
-    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Drücken Sie mit zwei Fingern, um die Bedienungshilfen zu aktivieren."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Lautstärke über den Schwellenwert anheben?\n\nWenn du über einen längeren Zeitraum Musik in hoher Lautstärke hörst, kann dies dein Gehör schädigen."</string>
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Drücke mit zwei Fingern, um die Bedienungshilfen zu aktivieren."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Bedienungshilfen aktiviert"</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Bedienungshilfen abgebrochen"</string>
     <string name="user_switched" msgid="3768006783166984410">"Aktueller Nutzer <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -1309,7 +1329,7 @@
     <string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> wird abgemeldet…"</string>
     <string name="owner_name" msgid="2716755460376028154">"Eigentümer"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Fehler"</string>
-    <string name="error_message_change_not_allowed" msgid="1347282344200417578">"Ihr Administrator lässt diese Änderung nicht zu."</string>
+    <string name="error_message_change_not_allowed" msgid="1347282344200417578">"Dein Administrator lässt diese Änderung nicht zu."</string>
     <string name="app_not_found" msgid="3429141853498927379">"Für diese Aktion wurde keine App gefunden."</string>
     <string name="revoke" msgid="5404479185228271586">"Aufheben"</string>
     <string name="mediasize_iso_a0" msgid="1994474252931294172">"ISO A0"</string>
@@ -1408,7 +1428,7 @@
     <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Neue PIN"</string>
     <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Neue PIN bestätigen"</string>
     <string name="restr_pin_create_pin" msgid="8017600000263450337">"PIN für das Ändern von Einschränkungen erstellen"</string>
-    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Die PINs stimmen nicht überein. Bitte versuchen Sie es erneut."</string>
+    <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Die PINs stimmen nicht überein. Bitte versuche es erneut."</string>
     <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Die PIN ist zu kurz. Sie muss mindestens 4 Ziffern umfassen."</string>
     <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
       <item quantity="other">In <xliff:g id="COUNT">%d</xliff:g> Sek. wiederholen</item>
@@ -1427,25 +1447,19 @@
     <string name="select_year" msgid="7952052866994196170">"Jahr auswählen"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> gelöscht"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (geschäftlich)"</string>
-    <string name="lock_to_app_toast" msgid="7570091317001980053">"Um die Fixierung dieses Bildschirms aufzuheben, berühren und halten Sie gleichzeitig \"Zurück\" und \"Übersicht\"."</string>
-    <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Um die Fixierung dieses Bildschirms aufzuheben, berühren und halten Sie \"Übersicht\"."</string>
+    <string name="lock_to_app_toast" msgid="7570091317001980053">"Um die Fixierung dieses Bildschirms aufzuheben, berühre und halte gleichzeitig \"Zurück\" und \"Übersicht\"."</string>
+    <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Um die Fixierung dieses Bildschirms aufzuheben, berühre und halte \"Übersicht\"."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Die App ist fixiert. Das Aufheben der Fixierung ist auf diesem Gerät nicht zulässig."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Bildschirm fixiert"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Bildschirm gelöst"</string>
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Vor dem Beenden nach PIN fragen"</string>
     <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_non_resizeble_text" msgid="9156251681042762723">"Die Größe der App kann nicht angepasst werden. Scrollen Sie sie mit zwei Fingern."</string>
-    <string name="package_installed_device_owner" msgid="8420696545959087545">"Von Ihrem Administrator installiert"</string>
-    <string name="package_updated_device_owner" msgid="8856631322440187071">"Von Ihrem Administrator aktualisiert"</string>
-    <string name="package_deleted_device_owner" msgid="7650577387493101353">"Von Ihrem Administrator gelöscht"</string>
-    <string name="battery_saver_description" msgid="1960431123816253034">"Der Energiesparmodus schont den Akku, indem er die Leistung des Geräts reduziert und die Vibrationsfunktion sowie die meisten Hintergrunddatenaktivitäten einschränkt. E-Mail, SMS/MMS und andere Apps, die auf Ihrem Gerät synchronisiert werden, werden möglicherweise erst nach dem Öffnen aktualisiert.\n\nDer Energiesparmodus wird automatisch deaktiviert, wenn Ihr Gerät aufgeladen wird."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Wichtigkeit"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Blockiert: Keine Benachrichtigungen anzeigen"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Niedrig: Benachrichtigungen ganz unten in der Benachrichtigungsliste und ohne Ton anzeigen"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Benachrichtigungen ohne Ton anzeigen"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Hoch: Benachrichtigungen ganz oben in der Benachrichtigungsliste und mit Ton anzeigen"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Dringend: Mit Ton auf dem Display einblenden"</string>
+    <string name="dock_non_resizeble_text" msgid="9156251681042762723">"Die Größe der App kann nicht angepasst werden. Scrolle sie mit zwei Fingern."</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>
+    <string name="package_deleted_device_owner" msgid="7650577387493101353">"Von deinem Administrator gelöscht"</string>
+    <string name="battery_saver_description" msgid="1960431123816253034">"Der Energiesparmodus schont den Akku, indem er die Leistung des Geräts reduziert und die Vibrationsfunktion sowie die meisten Hintergrunddatenaktivitäten einschränkt. E-Mail, SMS/MMS und andere Apps, die auf deinem Gerät synchronisiert werden, werden möglicherweise erst nach dem Öffnen aktualisiert.\n\nDer Energiesparmodus wird automatisch deaktiviert, wenn dein Gerät aufgeladen wird."</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">%1$d Minuten (bis <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">1 Minute (bis <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1490,8 +1504,8 @@
     <string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Wochenende"</string>
     <string name="zen_mode_default_events_name" msgid="8158334939013085363">"Termin"</string>
     <string name="muted_by" msgid="6147073845094180001">"Stummgeschaltet durch <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
-    <string name="system_error_wipe_data" msgid="6608165524785354962">"Es liegt ein internes Problem mit Ihrem Gerät vor. Möglicherweise verhält es sich instabil, bis Sie es auf die Werkseinstellungen zurücksetzen."</string>
-    <string name="system_error_manufacturer" msgid="8086872414744210668">"Es liegt ein internes Problem mit Ihrem Gerät vor. Bitte wenden Sie sich diesbezüglich an den Hersteller."</string>
+    <string name="system_error_wipe_data" msgid="6608165524785354962">"Es liegt ein internes Problem mit deinem Gerät vor. Möglicherweise verhält es sich instabil, bis du es auf die Werkseinstellungen zurücksetzt."</string>
+    <string name="system_error_manufacturer" msgid="8086872414744210668">"Es liegt ein internes Problem mit deinem Gerät vor. Bitte wende dich diesbezüglich an den Hersteller."</string>
     <string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD-Anfrage wird in DIAL-Anfrage geändert."</string>
     <string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD-Anfrage wird in SS-Anfrage geändert."</string>
     <string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD-Anfrage wird in neue USSD-Anfrage geändert."</string>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"Diese Benachrichtigung ist aufgrund der beteiligten Personen wichtig."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" versucht, einen neuen Nutzer hinzuzufügen. Dieser Vorgang ist momentan nicht zulässig."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" versucht, einen neuen Nutzer hinzuzufügen. Die maximal zulässige Anzahl an Nutzern ist aber schon erreicht."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" versucht, einen neuen Nutzer hinzuzufügen, aber das Konto "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" besteht bereits auf diesem Gerät. Trotzdem fortfahren?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" versucht, einen neuen Nutzer für das Konto "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" hinzuzufügen. Fortfahren?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Spracheinstellung"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Alle Sprachen"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Suche"</string>
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 666b65b..d572e22 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Αναφορά σφαλμάτων"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Λήψη αναφοράς σφάλματος"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Θα συλλέξει πληροφορίες σχετικά με την τρέχουσα κατάσταση της συσκευής σας και θα τις στείλει μέσω μηνύματος ηλεκτρονικού ταχυδρομείου. Απαιτείται λίγος χρόνος για τη σύνταξη της αναφοράς σφάλματος και την αποστολή της. Κάντε λίγη υπομονή."</string>
+    <string name="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 />
+    <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>
+    </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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"Ασφαλής λειτουργία"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Σύστημα Android"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"Προσωπικό"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Επιτρέπει στην εφαρμογή τη λήψη φωτογραφιών και βίντεο με τη φωτογραφική μηχανή. Αυτή η άδεια δίνει τη δυνατότητα στην εφαρμογή να χρησιμοποιεί τη φωτογραφική μηχανή ανά πάσα στιγμή χωρίς την έγκρισή σας."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"έλεγχος δόνησης"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Επιτρέπει στην εφαρμογή τον έλεγχο της δόνησης."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"έλεγχος φακού"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Επιτρέπει στην εφαρμογή τον έλεγχο του φακού."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"απευθείας κλήση τηλεφωνικών αριθμών"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Επιτρέπει στην εφαρμογή την κλήση αριθμών τηλεφώνου χωρίς δική σας παρέμβαση. Αυτό μπορεί να προκαλέσει μη αναμενόμενες χρεώσεις ή κλήσεις. Έχετε υπόψη ότι δεν επιτρέπεται στην εφαρμογή η κλήση αριθμών έκτακτης ανάγκης. Οι κακόβουλες εφαρμογές ενδέχεται να σας κοστίσουν χρήματα, πραγματοποιώντας κλήσεις χωρίς την έγκρισή σας."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"πρόσβαση στην υπηρεσία κλήσεων της IMS"</string>
@@ -858,10 +868,13 @@
     <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">"Διαγραφή"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Να κοινοποιηθεί η αναφορά σφάλματος στο διαχειριστή;"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Ο διαχειριστής σας IT ζήτησε μια αναφορά σφάλματος για να συμβάλει στην αντιμετώπιση του προβλήματος"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ΑΠΟΔΟΧΗ"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ΑΠΟΡΡΙΨΗ"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Λήψη αναφοράς σφάλματος…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Αγγίξτε για ακύρωση"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Αλλαγή πληκτρολογίου"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"Επιλογή πληκτρολογίων"</string>
-    <string name="show_ime" msgid="9157568568695230830">"Εμφάνιση μεθόδου εισαγ."</string>
-    <string name="hardware" msgid="7517821086888990278">"Υλικό"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Αλλαγή ταπετσαρίας"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Υπηρεσία ακρόασης ειδοποίησης"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Πάροχος συνθηκών"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Βοηθός ειδοποιήσεων"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"Βαρύτητα"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Αποκλεισμένες: Να μην εμφανίζονται ποτέ αυτές οι ειδοποιήσεις"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Χαμηλής βαρύτητας: Να εμφανίζονται στο κάτω τμήμα της λίστας ειδοποιήσεων χωρίς τη συνοδεία ήχου"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Κανονική βαρύτητα: Να εμφανίζονται αυτές οι ειδοποιήσεις χωρίς ήχο"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Υψηλής βαρύτητας: Να εμφανίζονται στην κορυφή της λίστας ειδοποιήσεων συνοδευόμενες από κάποιον ήχο"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Επείγουσες: Να προβάλλονται στην οθόνη και να συνοδεύονται από κάποιον ήχο"</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">Για ένα λεπτό (έως τις <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"Διάφορα"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"Μπορείτε να ρυθμίσετε τη βαρύτητα αυτών των ειδοποιήσεων."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Αυτό είναι σημαντικό λόγω των ατόμων που συμμετέχουν."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315">"Το "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" προσπαθεί να προσθέσει έναν νέο χρήστη, αλλά προς το παρόν αυτό απαγορεύεται."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266">"Το "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" προσπαθεί να προσθέσει έναν νέο χρήστη, αλλά έχετε φτάσει το όριο χρηστών."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789">"Το "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" προσπαθεί να προσθέσει έναν νέο χρήστη, αλλά ο λογαριασμός "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" υπάρχει ήδη σε αυτήν τη συσκευή. Θέλετε να συνεχίσετε ούτως ή άλλως;"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392">"Το "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" προσπαθεί να προσθέσει έναν νέο χρήστη για το λογαριασμό "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Θέλετε να συνεχίσετε;"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Προτίμηση γλώσσας"</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>
 </resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 9350ef7..ee7dd71 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Bug report"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Take bug report"</string>
     <string name="bugreport_message" msgid="398447048750350456">"This will collect information about your current device state, to send as an email message. It will take a little time from starting the bug report until it is ready to be sent. Please be patient."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interactive report"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Use this under most circumstances. It allows you to track progress of the report and enter more details about the problem. It might omit some less-used sections that take a long time to report."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Full report"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Taking screenshot for bug report in <xliff:g id="NUMBER_1">%d</xliff:g> seconds.</item>
+      <item quantity="one">Taking screenshot for bug report in <xliff:g id="NUMBER_0">%d</xliff:g> second.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Silent mode"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Sound is OFF"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Sound is ON"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Includes personal data such as credit card numbers and passwords."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Control display magnification"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Control the display\'s zoom level and positioning."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Perform gestures"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Can tap, swipe, pinch and perform other gestures."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"disable or modify status bar"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Allows the app to disable the status bar or add and remove system icons."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"be the status bar"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Allows the app to take pictures and videos with the camera. This permission allows the app to use the camera at any time without your confirmation."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"control vibration"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Allows the app to control the vibrator."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"control flashlight"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Allows the app to control the flashlight."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"directly call phone numbers"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Allows the app to call phone numbers without your intervention. This may result in unexpected charges or calls. Note that this doesn\'t allow the app to call emergency numbers. Malicious apps may cost you money by making calls without your confirmation."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"access IMS call service"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Cut"</string>
     <string name="copy" msgid="2681946229533511987">"Copy"</string>
     <string name="paste" msgid="5629880836805036433">"Paste"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Paste as plain text"</string>
     <string name="replace" msgid="5781686059063148930">"Replace..."</string>
     <string name="delete" msgid="6098684844021697789">"Delete"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Copy URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Select text"</string>
+    <string name="undo" msgid="7905788502491742328">"Undo"</string>
+    <string name="redo" msgid="7759464876566803888">"Redo"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Text selection"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Add to dictionary"</string>
     <string name="deleteText" msgid="6979668428458199034">"Delete"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Share bug report with admin?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Your IT admin requested a bug report to help troubleshoot"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPT"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"DECLINE"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Taking bug report…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Touch to cancel"</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="9157568568695230830">"Show input method"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardware"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Change wallpaper"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Notification 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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Updated by your administrator"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Deleted by your administrator"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Importance"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Blocked: Never show these notifications"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Low: Silently show at the bottom of the notification list"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Silently show these notifications"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"High: Show at the top of the notifications list and make sound"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Urgent: Peek onto the screen and make sound"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">For %1$d minutes (until <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">For one minute (until <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"This is important because of the people involved."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" is trying to add a new user, but is currently prohibited."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" is trying to add a new user, but the user limit has been reached."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" is trying to add a new user, but the account "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" already exists on this device. Proceed anyway?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" is trying to add a new user for the account "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Proceed?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Language preference"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"All languages"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Search"</string>
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 9350ef7..ee7dd71 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Bug report"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Take bug report"</string>
     <string name="bugreport_message" msgid="398447048750350456">"This will collect information about your current device state, to send as an email message. It will take a little time from starting the bug report until it is ready to be sent. Please be patient."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interactive report"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Use this under most circumstances. It allows you to track progress of the report and enter more details about the problem. It might omit some less-used sections that take a long time to report."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Full report"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Taking screenshot for bug report in <xliff:g id="NUMBER_1">%d</xliff:g> seconds.</item>
+      <item quantity="one">Taking screenshot for bug report in <xliff:g id="NUMBER_0">%d</xliff:g> second.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Silent mode"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Sound is OFF"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Sound is ON"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Includes personal data such as credit card numbers and passwords."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Control display magnification"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Control the display\'s zoom level and positioning."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Perform gestures"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Can tap, swipe, pinch and perform other gestures."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"disable or modify status bar"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Allows the app to disable the status bar or add and remove system icons."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"be the status bar"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Allows the app to take pictures and videos with the camera. This permission allows the app to use the camera at any time without your confirmation."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"control vibration"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Allows the app to control the vibrator."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"control flashlight"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Allows the app to control the flashlight."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"directly call phone numbers"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Allows the app to call phone numbers without your intervention. This may result in unexpected charges or calls. Note that this doesn\'t allow the app to call emergency numbers. Malicious apps may cost you money by making calls without your confirmation."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"access IMS call service"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Cut"</string>
     <string name="copy" msgid="2681946229533511987">"Copy"</string>
     <string name="paste" msgid="5629880836805036433">"Paste"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Paste as plain text"</string>
     <string name="replace" msgid="5781686059063148930">"Replace..."</string>
     <string name="delete" msgid="6098684844021697789">"Delete"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Copy URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Select text"</string>
+    <string name="undo" msgid="7905788502491742328">"Undo"</string>
+    <string name="redo" msgid="7759464876566803888">"Redo"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Text selection"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Add to dictionary"</string>
     <string name="deleteText" msgid="6979668428458199034">"Delete"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Share bug report with admin?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Your IT admin requested a bug report to help troubleshoot"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPT"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"DECLINE"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Taking bug report…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Touch to cancel"</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="9157568568695230830">"Show input method"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardware"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Change wallpaper"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Notification 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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Updated by your administrator"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Deleted by your administrator"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Importance"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Blocked: Never show these notifications"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Low: Silently show at the bottom of the notification list"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Silently show these notifications"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"High: Show at the top of the notifications list and make sound"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Urgent: Peek onto the screen and make sound"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">For %1$d minutes (until <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">For one minute (until <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"This is important because of the people involved."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" is trying to add a new user, but is currently prohibited."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" is trying to add a new user, but the user limit has been reached."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" is trying to add a new user, but the account "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" already exists on this device. Proceed anyway?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" is trying to add a new user for the account "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Proceed?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Language preference"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"All languages"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Search"</string>
 </resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 9350ef7..ee7dd71 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Bug report"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Take bug report"</string>
     <string name="bugreport_message" msgid="398447048750350456">"This will collect information about your current device state, to send as an email message. It will take a little time from starting the bug report until it is ready to be sent. Please be patient."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interactive report"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Use this under most circumstances. It allows you to track progress of the report and enter more details about the problem. It might omit some less-used sections that take a long time to report."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Full report"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Taking screenshot for bug report in <xliff:g id="NUMBER_1">%d</xliff:g> seconds.</item>
+      <item quantity="one">Taking screenshot for bug report in <xliff:g id="NUMBER_0">%d</xliff:g> second.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Silent mode"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Sound is OFF"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Sound is ON"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Includes personal data such as credit card numbers and passwords."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Control display magnification"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Control the display\'s zoom level and positioning."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Perform gestures"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Can tap, swipe, pinch and perform other gestures."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"disable or modify status bar"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Allows the app to disable the status bar or add and remove system icons."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"be the status bar"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Allows the app to take pictures and videos with the camera. This permission allows the app to use the camera at any time without your confirmation."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"control vibration"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Allows the app to control the vibrator."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"control flashlight"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Allows the app to control the flashlight."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"directly call phone numbers"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Allows the app to call phone numbers without your intervention. This may result in unexpected charges or calls. Note that this doesn\'t allow the app to call emergency numbers. Malicious apps may cost you money by making calls without your confirmation."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"access IMS call service"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Cut"</string>
     <string name="copy" msgid="2681946229533511987">"Copy"</string>
     <string name="paste" msgid="5629880836805036433">"Paste"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Paste as plain text"</string>
     <string name="replace" msgid="5781686059063148930">"Replace..."</string>
     <string name="delete" msgid="6098684844021697789">"Delete"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Copy URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Select text"</string>
+    <string name="undo" msgid="7905788502491742328">"Undo"</string>
+    <string name="redo" msgid="7759464876566803888">"Redo"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Text selection"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Add to dictionary"</string>
     <string name="deleteText" msgid="6979668428458199034">"Delete"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Share bug report with admin?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Your IT admin requested a bug report to help troubleshoot"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPT"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"DECLINE"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Taking bug report…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Touch to cancel"</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="9157568568695230830">"Show input method"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardware"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Change wallpaper"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Notification 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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Updated by your administrator"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Deleted by your administrator"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Importance"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Blocked: Never show these notifications"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Low: Silently show at the bottom of the notification list"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Silently show these notifications"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"High: Show at the top of the notifications list and make sound"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Urgent: Peek onto the screen and make sound"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">For %1$d minutes (until <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">For one minute (until <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"This is important because of the people involved."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" is trying to add a new user, but is currently prohibited."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" is trying to add a new user, but the user limit has been reached."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" is trying to add a new user, but the account "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" already exists on this device. Proceed anyway?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" is trying to add a new user for the account "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Proceed?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Language preference"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"All languages"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Search"</string>
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 339c315..45a0e02 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Informe de errores"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Iniciar informe de errores"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Se recopilará información sobre el estado actual de tu dispositivo, que se enviará por correo. Pasarán unos minutos desde que se inicie el informe de errores hasta que se envíe, por lo que te recomendamos que tengas paciencia."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Informe interactivo"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Usa esta opción en la mayoría de los casos. Te permite ingresar más detalles acerca del problema y realizar un seguimiento del progreso del informe. Es posible que se omitan secciones menos usadas cuyos informes demoran más en completarse."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Informe completo"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Se tomará una captura de pantalla para el informe de errores en <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item>
+      <item quantity="one">Se tomará una captura de pantalla para el informe de errores en <xliff:g id="NUMBER_0">%d</xliff:g> segundo.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modo silencioso"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"El sonido está Desactivado"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"El sonido está Activado"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Incluye datos personales, como números de tarjeta de crédito y contraseñas."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Controlar la ampliación de pantalla"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controla el posicionamiento y el nivel de zoom de la pantalla."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Usar gestos"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Permite presionar, deslizar, pellizcar y usar otros gestos."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"desactivar o modificar la barra de estado"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Permite que la aplicación inhabilite la barra de estado o que agregue y elimine íconos del sistema."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"aparecer en la barra de estado"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permite que la aplicación saque fotos o grabe videos con la cámara. Este permiso autoriza a la aplicación a utilizar la cámara en cualquier momento sin tu confirmación."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"controlar la vibración"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite que la aplicación controle la vibración."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"controlar linterna"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite que la aplicación controle la función de linterna."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"llamar directamente a números de teléfono"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que la aplicación haga llamadas a números de teléfono sin intervención del usuario, lo que puede dar lugar a llamadas o cargos inesperados. Ten en cuenta que las aplicaciones no pueden usar este servicio para realizar llamadas a números de emergencia, pero las aplicaciones malintencionadas pueden causarte gastos imprevistos al realizar llamadas sin tu confirmación."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"acceder al servicio IMS para realizar llamadas"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Cortar"</string>
     <string name="copy" msgid="2681946229533511987">"Copiar"</string>
     <string name="paste" msgid="5629880836805036433">"Pegar"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Pegar como texto sin formato"</string>
     <string name="replace" msgid="5781686059063148930">"Reemplazar..."</string>
     <string name="delete" msgid="6098684844021697789">"Eliminar"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Copiar URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Seleccionar texto"</string>
+    <string name="undo" msgid="7905788502491742328">"Deshacer"</string>
+    <string name="redo" msgid="7759464876566803888">"Rehacer"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Selección de texto"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Agregar al diccionario"</string>
     <string name="deleteText" msgid="6979668428458199034">"Eliminar"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"¿Quieres compartir el informe de errores con el administrador?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"El administrador de TI solicitó un informe de errores para ayudar a solucionar el problema"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEPTAR"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RECHAZAR"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Realizando un informe de errores…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Toca para cancelar"</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="9157568568695230830">"Mostrar método de entrada"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardware"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <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="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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizado por el administrador"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Lo eliminó el administrador."</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Para ayudar a mejorar la duración de la batería, el ahorro de batería reduce el rendimiento del dispositivo y limita la vibración, los servicios de ubicación y la mayoría de los datos en segundo plano. Es posible que el correo electrónico, la mensajería y otras aplicaciones que se basan en la sincronización no puedan actualizarse, a menos que los abras.\n\nEl ahorro de batería se desactiva de forma automática cuando el dispositivo se está cargando."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Importancia"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloqueada: no mostrar nunca estas notificaciones"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Baja: mostrar en la parte inferior de la lista de notificación sin emitir sonido"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normal: mostrar estas notificaciones de manera silenciosa"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Alta: mostrar en la parte superior de la lista de notificaciones y emitir sonido"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Urgente: mostrar en la pantalla y emitir sonido"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">Durante %1$d minutos hasta la(s) <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g></item>
       <item quantity="one">Durante 1 minuto; hasta la(s) <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g></item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"Es importante debido a las personas involucradas."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" está intentando agregar un usuario nuevo, pero esta app no está permitida."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" está intentado agregar un usuario nuevo, pero ya se alcanzó el límite máximo de usuarios."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" está intentado agregar un usuario nuevo, pero la cuenta "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" ya existe en este dispositivo. ¿Deseas continuar de todas formas?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" está intentando agregar un usuario nuevo a la cuenta "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". ¿Deseas continuar?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Preferencia de 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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Todos los idiomas"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Búsqueda"</string>
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 5b82a08..2f1c4a8 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Informe de error"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Crear informe de errores"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Se recopilará información sobre el estado actual de tu dispositivo y se enviará por correo electrónico. Pasarán unos minutos desde que empiece a generarse el informe de errores hasta que se envíe."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Informe interactivo"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Usa esta opción en la mayoría de los casos. Te permite realizar un seguimiento del progreso de la notificación e introducir más información sobre el problema. Es posible que se omitan algunas secciones menos utilizadas y que requieran más tiempo."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Informe completo"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">La captura de pantalla para el informe de errores se realizará en <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item>
+      <item quantity="one">La captura de pantalla para el informe de errores se realizará en <xliff:g id="NUMBER_0">%d</xliff:g> segundo.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modo silencio"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"El sonido está desactivado. Activar"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"El sonido está activado. Desactivar"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Incluye datos personales como números de tarjetas de crédito y contraseñas."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Controla la ampliación de la pantalla"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controla el posicionamiento y el nivel de zoom de la pantalla."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Realizar gestos"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Puedes tocar y pellizcar la pantalla, deslizar el dedo y hacer otros gestos."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"inhabilitar o modificar la barra de estado"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Permite que la aplicación inhabilite la barra de estado o añada y elimine iconos del sistema."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"aparecer en la barra de estado"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permite que la aplicación haga fotos o grabe vídeos con la cámara. Este permiso autoriza a la aplicación a utilizar la cámara en cualquier momento sin tu confirmación."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"controlar la vibración"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite que la aplicación controle la función de vibración."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"controlar linterna"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite que la aplicación controle la función de linterna."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"llamar directamente a números de teléfono"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que la aplicación haga llamadas sin intervención del usuario, lo que puede dar lugar a llamadas o cargos inesperados. Ten en cuenta que las aplicaciones no pueden usar este servicio para realizar llamadas a números de emergencia, pero las aplicaciones malintencionadas pueden causarte gastos imprevistos al realizar llamadas sin tu confirmación."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"acceder al servicio de llamadas IMS"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Cortar"</string>
     <string name="copy" msgid="2681946229533511987">"Copiar"</string>
     <string name="paste" msgid="5629880836805036433">"Pegar"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Pegar como texto sin formato"</string>
     <string name="replace" msgid="5781686059063148930">"Sustituir..."</string>
     <string name="delete" msgid="6098684844021697789">"Eliminar"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Copiar URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Seleccionar texto"</string>
+    <string name="undo" msgid="7905788502491742328">"Deshacer"</string>
+    <string name="redo" msgid="7759464876566803888">"Rehacer"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Selección de texto"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Añadir al diccionario"</string>
     <string name="deleteText" msgid="6979668428458199034">"Eliminar"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"¿Compartir informe de errores con el administrador?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Tu administrador de TI ha solicitado un informe de errores para solucionar problemas"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEPTAR"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RECHAZAR"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Creando informe de errores…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Toca para cancelar"</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="9157568568695230830">"Mostrar método de entrada"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardware"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <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="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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizado por tu administrador"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Eliminado por tu administrador"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Para ayudar a mejorar la duración de la batería, la función de ahorro de energía reduce el rendimiento del dispositivo y limita la vibración, los servicios de ubicación y la mayor parte de la transmisión de datos en segundo plano. Es posible que las aplicaciones que se sincronizan, como las de correo y mensajes, no se actualicen a menos que las abras.\n\nLa función de ahorro de energía se desactiva automáticamente cuando el dispositivo se está cargando."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Importancia"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloqueada: no mostrar estas notificaciones"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Baja: mostrar en la parte inferior de la lista de notificaciones de forma silenciosa"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normal: mostrar estas notificaciones de forma silenciosa"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Alta: mostrar en la parte superior de la lista de notificaciones y emitir sonido"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Urgente: mostrar en la pantalla y emitir sonido"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">Durante %1$d minutos (hasta las <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">Durante un minuto (hasta las <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"Esto es importante por los usuarios implicados."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" quiere añadir un usuario nuevo, pero no está permitido."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" quiere añadir un usuario nuevo, pero se ha alcanzado el límite de usuarios."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" quiere añadir un usuario nuevo, pero la cuenta "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" ya existe en este dispositivo. ¿Quieres continuar de todas formas?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" quiere añadir un usuario nuevo a la cuenta "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". ¿Quieres continuar?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Preferencia de 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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Todos los idiomas"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Buscar"</string>
 </resources>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 9bb955b..3a4f2af 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Veaaruanne"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Veaaruande võtmine"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Nii kogutakse teavet teie seadme praeguse oleku kohta, et saata see meilisõnumina. Enne kui saate veaaruande ära saata, võtab selle loomine natuke aega; varuge kannatust."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interakt. aruanne"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Kasutage seda enamikul juhtudel. See võimaldab jälgida aruande edenemist ja sisestada probleemi kohta täpsemat teavet. Vahele võivad jääda mõned vähem kasutatud jaotised, millest teavitamine võtab rohkem aega."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Täielik aruanne"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Veaaruande jaoks ekraanipildi jäädvustamine <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast.</item>
+      <item quantity="one">Veaaruande jaoks ekraanipildi jäädvustamine <xliff:g id="NUMBER_0">%d</xliff:g> sekundi pärast.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Hääletu režiim"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Heli on VÄLJAS"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Heli on SEES"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Sisaldab isiklikke andmeid, nt krediitkaardi numbreid ja paroole."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Ekraani suurenduse juhtimine"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Saate juhtida ekraani suumitaset ja asendit."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Liigutuste tegemine"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Saate puudutada, pühkida, sõrmi kokku-lahku liigutada ja teisi liigutusi teha."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"keela või muuda olekuriba"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Võimaldab rakendusel keelata olekuriba või lisada ja eemaldada süsteemiikoone."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"olekuribana kuvamine"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Võimaldab rakendusel teha kaameraga pilte ja videoid. See luba võimaldab rakendusel kasutada kaamerat mis tahes ajal teie kinnituseta."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"juhtige vibreerimist"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Võimaldab rakendusel juhtida vibreerimist."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"juhi taskulampi"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Võimaldab rakendusel juhtida taskulampi."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"helista otse telefoninumbritele"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Võimaldab rakendusel teie sekkumiseta telefoninumbritele helistada. See võib põhjustada ootamatuid tasusid või telefonikõnesid. Pange tähele, et see ei luba rakendusel helistada hädaabinumbritele. Pahatahtlikud rakendused võivad teile kulusid tekitada, tehes telefonikõnesid teie kinnituseta."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"juurdepääs IMS-kõneteenusele"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Lõika"</string>
     <string name="copy" msgid="2681946229533511987">"Kopeeri"</string>
     <string name="paste" msgid="5629880836805036433">"Kleebi"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Kleebi lihttekstina"</string>
     <string name="replace" msgid="5781686059063148930">"Asenda..."</string>
     <string name="delete" msgid="6098684844021697789">"Kustuta"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Kopeeri URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Valige tekst"</string>
+    <string name="undo" msgid="7905788502491742328">"Võta tagasi"</string>
+    <string name="redo" msgid="7759464876566803888">"Tee uuesti"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Teksti valimine"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Lisa sõnastikku"</string>
     <string name="deleteText" msgid="6979668428458199034">"Kustuta"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Kas jagada veaaruannet administraatoriga?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"IT-administraator taotles veaaruannet, mis aitaks vigu otsida"</string>
+    <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="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Veaaruande võtmine …"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Puudutage tühistamiseks"</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="9157568568695230830">"Sisestusmeetodi kuvamine"</string>
-    <string name="hardware" msgid="7517821086888990278">"Riistvara"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Muutke taustapilti"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Märguannete kuulamisteenus"</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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Värskendas administraator"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Kustutas teie administraator"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Aku kestuse parandamiseks vähendab akusäästja teie seadme toimivust ning piirab vibratsiooni, asukohateenuseid ja suuremat osa taustaandmetest. E-posti, sõnumsidet ja muid sünkroonimisele tuginevaid rakendusi võidakse värskendada ainult siis, kui te need avate.\n\nAkusäästja lülitatakse seadme laadimise ajal automaatselt välja."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Tähtsus"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokeeritud: ära kunagi näita neid märguandeid"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Madal: kuva vaikselt märguannete loendi allosas"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Tavaline: kuva need märguanded vaikselt"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Kõrge: kuva märguannete loendi ülaosas koos heliga"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Kiireloomuline: kuva ekraani servas koos heliga"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">%1$d minutiks (kuni <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">Üheks minutiks (kuni <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"See on tähtis osalevate inimeste tõttu."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" üritab lisada uut kasutajat, kuid see on praegu keelatud."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" üritab lisada uut kasutajat, ent olete jõudnud kasutajate maksimumarvuni."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" üritab lisada uut kasutajat, ent konto "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" on juba seadmes olemas. Kas soovite siiski jätkata?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" üritab lisada uut kasutajat kontole "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Kas soovite jätkata?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Keele-eelistus"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Kõik keeled"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Otsing"</string>
 </resources>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index efff589..35d67e9 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Akatsen txostena"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Sortu akatsen txostena"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Gailuaren uneko egoerari buruzko informazioa bilduko da, mezu elektroniko gisa bidaltzeko. Minutu batzuk igaroko dira akatsen txostena sortzen hasten denetik bidaltzeko prest egon arte. Itxaron, mesedez."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Txosten dinamikoa"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Aukera hau erabili beharko zenuke ia beti. Txostenaren jarraipena egin ahal izango duzu eta arazoari buruzko xehetasunak eman ahal izango dituzu. Baliteke gutxitan erabili behar izaten diren atalak ez agertzea, denbora aurrezteko."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Txosten osoa"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Akatsen txostenaren argazkia aterako da <xliff:g id="NUMBER_1">%d</xliff:g> segundo barru.</item>
+      <item quantity="one">Akatsen txostenaren argazkia aterako da <xliff:g id="NUMBER_0">%d</xliff:g> segundo barru.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Isilik modua"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Soinua DESAKTIBATUTA dago"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Soinua AKTIBATUTA dago"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Ez da salbuespenik egiten datu pertsonalekin, hala nola, kreditu-txartelen zenbakiekin eta pasahitzekin."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Kontrolatu pantailaren zoom-maila"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrolatu pantailaren zoom-maila eta kokapena."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Keinuak egin"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Sakatu, lerratu, atximurkatu eta beste hainbat keinu egin ditzake."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"Desgaitu edo aldatu egoera-barra"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Egoera-barra desgaitzea edo sistema-ikonoak gehitzea edo kentzea baimentzen die aplikazioei."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"Bihurtu egoera-barra"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Kamerarekin argazkiak ateratzeko eta bideoak grabatzeko baimena ematen die aplikazioei. Baimen horrekin, aplikazioak kamera edonoiz erabil dezake zure baimenik gabe."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"bibrazioa kontrolatzea"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Bibragailua kontrolatzea baimentzen die aplikazioei."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolatu linterna"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Linterna kontrolatzea baimentzen die aplikazioei."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"deitu zuzenean telefono-zenbakietara"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Telefono-zenbakietara zuk esku hartu gabe deitzeko baimena ematen die aplikazioei. Horrela, ustekabeko gastuak edo deiak eragin daitezke. Aplikazio gaiztoek erabil dezakete zuk berretsi gabeko deiak eginda gastuak eragiteko."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"Atzitu IMS dei-zerbitzua"</string>
@@ -383,8 +393,8 @@
     <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Tabletak ezagutzen dituen kontuen zerrenda lortzeko baimena ematen die aplikazioei. Instalatuta dituzun aplikazioek sortutako kontuak har daitezke barne."</string>
     <string name="permdesc_getAccounts" product="tv" msgid="4190633395633907543">"Telebistak ezagutzen dituen kontuen zerrenda lortzea baimentzen die aplikazioei. Instalatuta dituzun aplikazioek sortutako kontuak sar daitezke."</string>
     <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Telefonoak ezagutzen dituen kontuen zerrenda lortzeko baimena ematen die aplikazioei. Instalatuta dituzun aplikazioek sortutako kontuak har daitezke barne."</string>
-    <string name="permlab_accessNetworkState" msgid="4951027964348974773">"sare-konexioak ikustea"</string>
-    <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Sare-konexioei buruzko informazioa ikusteko baimena ematen die aplikazioei; adibidez, zer sare dauden eta zeintzuk dauden konektatuta."</string>
+    <string name="permlab_accessNetworkState" msgid="4951027964348974773">"sareko konexioak ikustea"</string>
+    <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Sareko konexioei buruzko informazioa ikusteko baimena ematen die aplikazioei; adibidez, zer sare dauden eta zeintzuk dauden konektatuta."</string>
     <string name="permlab_createNetworkSockets" msgid="7934516631384168107">"Izan sarerako sarbide osoa"</string>
     <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Sare-socketak sortzeko eta sare-protokolo pertsonalizatuak erabiltzeko baimena ematen die aplikazioei. Arakatzaileak eta beste aplikazio batzuek Internetera konektatzeko moduak eskaintzen dituzte, beraz, baimen hori ez da beharrezkoa datuak Internetera bidaltzeko."</string>
     <string name="permlab_changeNetworkState" msgid="958884291454327309">"aldatu sarearen konektagarritasuna"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Ebaki"</string>
     <string name="copy" msgid="2681946229533511987">"Kopiatu"</string>
     <string name="paste" msgid="5629880836805036433">"Itsatsi"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Itsatsi testu arrunt gisa"</string>
     <string name="replace" msgid="5781686059063148930">"Ordeztu…"</string>
     <string name="delete" msgid="6098684844021697789">"Ezabatu"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Kopiatu URLa"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Hautatu testua"</string>
+    <string name="undo" msgid="7905788502491742328">"Desegin"</string>
+    <string name="redo" msgid="7759464876566803888">"Berregin"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Testua hautatzea"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Gehitu hiztegian"</string>
     <string name="deleteText" msgid="6979668428458199034">"Ezabatu"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Partekatu nahi duzu administratzailearekin akatsen txostena?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"IKT administratzaileak akatsen txostena eskatu du arazoa konpontzen laguntzeko"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ONARTU"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"BAZTERTU"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Akatsen txostena sortzen…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Ukitu bertan behera uzteko"</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="9157568568695230830">"Erakutsi idazketa-metodoa"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardwarea"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Aldatu horma-papera"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Jakinarazpenak hautemateko zerbitzua"</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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Administratzaileak eguneratu du"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Administratzaileak ezabatu du"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Bateriak gehiago iraun dezan, bateria-aurrezleak gailuaren funtzionamendua, dardara,  kokapen-zerbitzuak eta atzeko planoko datuen erabilera gehiena mugatzen ditu. Posta elektronikoa, mezuak eta sinkronizatzen diren gainerako zerbitzuak ez dira eguneratuko ireki ezean.\n\nGailua kargatzen ezarri orduko desaktibatzen da bateria-aurrezlea."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Garrantzia"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokeatuta: ez erakutsi jakinarazpen hauek"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Txikia: erakutsi jakinarazpen hauek zerrendaren behealdean"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normala: erakutsi jakinarazpen hauek, baina soinurik egin gabe"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Handia: erakutsi jakinarazpen hauek zerrendaren goialdean eta egin soinua"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Premiazkoa: agerrarazi jakinarazpen hauek pantailan eta egin soinua"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">%1$d minutuz (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> arte)</item>
       <item quantity="one">Minutu batez (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> arte)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"Garrantzitsua da eragiten dien pertsonengatik."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" beste erabiltzaile bat gehitzen saiatzen ari da, baina unean debekatuta dago."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" beste erabiltzaile bat gehitzen saiatzen ari da, baina erabiltzaileen mugara irisi da."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" beste erabiltzaile bat gehitzen saiatzen ari da, baina "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" badago gailuan. Jarraitu nahi duzu halere?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" beste erabiltzaile bat gehitzen saiatzen ari da "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" kontuan. Jarraitu nahi duzu?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Hizkuntza-hobespena"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Hizkuntza guztiak"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Bilaketa"</string>
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index d5ed5db..e1adfb9 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"گزارش اشکال"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"گرفتن گزارش اشکال"</string>
     <string name="bugreport_message" msgid="398447048750350456">"این گزارش اطلاعات مربوط به وضعیت دستگاه کنونی شما را جمع‌آوری می‌کند تا به صورت یک پیام ایمیل ارسال شود. از زمان شروع گزارش اشکال تا آماده شدن برای ارسال اندکی زمان می‌برد؛ لطفاً شکیبا باشید."</string>
+    <string name="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 />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">تا <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دیگر عکس صفحه‌نمایش برای گزارش اشکال گرفته می‌شود.</item>
+      <item quantity="other">تا <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دیگر عکس صفحه‌نمایش برای گزارش اشکال گرفته می‌شود.</item>
+    </plurals>
     <string name="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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"حالت ایمن"</string>
     <string name="android_system_label" msgid="6577375335728551336">"‏سیستم Android"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"شخصی"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"به برنامه اجازه می‌دهد با دوربین به عکسبرداری و فیلمبرداری بپردازد. این مجوز به برنامه اجازه می‌‌دهد از دوربین در هر زمانی بدون تأیید شما استفاده کند."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"کنترل لرزش"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"‏به برنامه اجازه می‎دهد تا لرزاننده را کنترل کند."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"کنترل چراغ قوه"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"‏به برنامه اجازه می‎دهد تا چراغ قوه را کنترل کند."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"تماس مستقیم با شماره تلفن‌ها"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"به برنامه اجازه می‌دهد بدون دخالت شما با شماره‌های تلفن تماس بگیرد. این ممکن است باعث ایجاد هزینه یا تماس‌های پیش‌بینی نشده شود. توجه داشته باشید که این به برنامه اجازه نمی‌دهد به برقراری تماس‌های اضطراری بپردازد. برنامه‌های مخرب ممکن است با برقراری تماس بدون تأیید شما هزینه‌هایی را برای شما ایجاد کنند."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"‏دسترسی به سرویس تماس IMS"</string>
@@ -858,10 +868,13 @@
     <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">"حذف"</string>
@@ -892,7 +905,7 @@
     <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="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>
@@ -914,7 +927,7 @@
     <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="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>
@@ -927,7 +940,7 @@
     <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="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>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"گزارش اشکال را با سرپرست سیستم به اشتراک می‌گذارید؟"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"سرپرست فناوری اطلاعات شما برای کمک به عیب‌یابی، گزارش اشکال درخواست کرد"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"پذیرفتن"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"نپذیرفتن"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"درحال گرفتن گزارش اشکال…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"برای لغو کردن لمس کنید"</string>
     <string name="select_input_method" msgid="8547250819326693584">"تغییر صفحه‌کلید"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"انتخاب صفحه‌کلیدها"</string>
-    <string name="show_ime" msgid="9157568568695230830">"نمایش روش ورودی"</string>
-    <string name="hardware" msgid="7517821086888990278">"سخت‌افزار"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"تغییر کاغذدیواری"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"شنونده اعلان"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ارائه‌دهنده وضعیت"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"دستیار اعلان"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"اهمیت"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"مسدود: هرگز این اعلان‌ها نشان داده نشود"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"پایین: بدون صدا در پایین فهرست اعلان نشان داده شود"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"عادی: این اعلان‌ها بدون صدا نشان داده شود"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"بالا: در بالای فهرست اعلان‌ها و به همراه صدا نشان داده شود"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"ضروری: نمای کلی به همراه صدا در صفحه نشان داده شود"</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="other">‏به مدت %1$d دقیقه (تا <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"متفرقه"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"شما اهمیت این اعلان‌ها را تنظیم می‌کنید."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"به دلیل افراد درگیر مهم است."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" در تلاش است کاربر جدیدی اضافه کند، اما در حال حاضر این اقدام ممنوع است."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" در تلاش است کاربر جدیدی اضافه کند، اما تعداد کاربران به حداکثر مجاز رسیده است."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" در تلاش است کاربر جدیدی اضافه کند، اما حساب "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" از قبل در این دستگاه وجود دارد. در هر صورت ادامه داده شود؟"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" در تلاش است کاربر جدیدی برای حساب "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" اضافه کند. ادامه می‌دهید؟"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"اولویت‌های زبان"</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>
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 7b42a1a..9274b87 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Virheraportti"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Luo virheraportti"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Toiminto kerää tietoja laitteen tilasta ja lähettää ne sähköpostitse. Virheraportti on valmis lähetettäväksi hetken kuluttua - kiitos kärsivällisyydestäsi."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktiivinen"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Valitse tämä vaihtoehto useimmissa tapauksissa. Voit seurata raportin etenemistä ja antaa lisätietoja ongelmasta. Tämä vaihtoehto saattaa ohittaa joitakin harvoin käytettyjä osioita, joiden käsittely raportissa kestää kauan."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Koko raportti"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Virheraporttiin otetaan kuvakaappaus <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua.</item>
+      <item quantity="one">Virheraporttiin otetaan kuvakaappaus <xliff:g id="NUMBER_0">%d</xliff:g> sekunnin kuluttua.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Äänetön tila"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Äänet ovat POISSA KÄYTÖSTÄ"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Äänet ovat KÄYTÖSSÄ"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Sisältää henkilökohtaisia tietoja, kuten luottokortin numeroita ja salasanoja."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Näytön suurentamisen hallinnointi"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Hallinnoi näytön zoomaustasoa ja asettelua."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Eleiden käyttäminen"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Lupa napauttaa, pyyhkäistä, nipistää ja käyttää muita eleitä."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"poista tilapalkki käytöstä tai muokkaa tilapalkkia"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Antaa sovelluksen poistaa tilapalkin käytöstä ja lisätä tai poistaa järjestelmäkuvakkeita."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"sijaita tilapalkissa"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Antaa sovelluksen ottaa kuvia ja kuvata videoita kameralla. Sovellus voi käyttää kameraa milloin tahansa ilman lupaasi."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"hallitse värinää"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Antaa sovelluksen hallita värinää."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"hallitse taskulamppua"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Antaa sovelluksen hallita taskulamppua."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"soittaa puhelinnumeroihin suoraan"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Antaa sovelluksen soittaa puhelinnumeroihin kysymättä sinulta. Tämä voi aiheuttaa odottamattomia kuluja tai puheluita. Huomaa, että tämä ei anna sovellukselle lupaa soittaa hätänumeroihin. Haitalliset sovellukset voivat aiheuttaa sinulle kuluja soittamalla puheluita ilman lupaa."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"pikaviestipalvelun puhelukäyttöoikeus"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Leikkaa"</string>
     <string name="copy" msgid="2681946229533511987">"Kopioi"</string>
     <string name="paste" msgid="5629880836805036433">"Liitä"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Liitä pelkkänä tekstinä"</string>
     <string name="replace" msgid="5781686059063148930">"Korvaa..."</string>
     <string name="delete" msgid="6098684844021697789">"Poista"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Kopioi URL-osoite"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Valitse tekstiä"</string>
+    <string name="undo" msgid="7905788502491742328">"Kumoa"</string>
+    <string name="redo" msgid="7759464876566803888">"Toista"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Tekstin valinta"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Lisää sanakirjaan"</string>
     <string name="deleteText" msgid="6979668428458199034">"Poista"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Jaetaanko virheraportti järjestelmänvalvojalle?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"IT-järjestelmänvalvojasi pyysi virheraporttia voidakseen auttaa vianetsinnässä."</string>
+    <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="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Luodaan virheraporttia…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Peruuta koskettamalla"</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="9157568568695230830">"Näytä syöttötapa"</string>
-    <string name="hardware" msgid="7517821086888990278">"Laitteisto"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Vaihda taustakuvaa"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Ilmoituskuuntelija"</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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Järjestelmänvalvojasi on päivittänyt paketin."</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Järjestelmänvalvoja on poistanut paketin."</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Jos haluat parantaa akun kestoa, virransäästö vähentää laitteesi suorituskykyä ja rajoittaa värinää, sijaintipalveluita ja useimpia taustatietoja. Sähköposti, viestit ja muut synkronointiin perustuvat sovellukset eivät välttämättä päivity, ellet avaa niitä.\n\nVirransäästö poistuu käytöstä automaattisesti, kun laitteesi latautuu."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Tärkeys"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Estetty: älä koskaan näytä näitä ilmoituksia."</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Matala: näytä nämä ilmoitukset huomaamattomasti luettelon alaosassa."</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Tavallinen: näytä nämä ilmoitukset huomaamattomasti."</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Korkea: näytä nämä ilmoitukset luettelon yläosassa ja toista äänimerkki."</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Kiireellinen: näytä ilmoitus näytöllä ja toista äänimerkki."</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">%1$d minuutiksi (kunnes kello on <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">Yhdeksi minuutiksi (kunnes kello on <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"Tämä on tärkeää siihen liittyvien ihmisten perusteella."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" yrittää lisätä uutta käyttäjää, mutta se on tällä hetkellä estetty."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" yrittää lisätä uutta käyttäjää, mutta käyttäjiä on jo enimmäismäärä."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" yrittää lisätä uutta käyttäjää, mutta tili "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" on jo tässä laitteessa. Jatketaanko silti?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" yrittää lisätä uutta käyttäjää tilille "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Jatketaanko?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Kieliasetus"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Kaikki kielet"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Haku"</string>
 </resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 5debc9c..965a83c 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Rapport de bogue"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Créer un rapport de bogue"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Cela permet de recueillir des informations concernant l\'état actuel de votre appareil. Ces informations sont ensuite envoyées sous forme de courriel. Merci de patienter pendant la préparation du rapport de bogue. Cette opération peut prendre quelques instants."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Rapport interactif"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Utilisez cette option dans la plupart des circonstances. Elle vous permet de suivre la progression du rapport et d\'entrer plus de données sur le problème. Certaines sections moins utilisées et dont le remplissage demande beaucoup de temps peuvent être omises."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Rapport complet"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">Saisie d\'écran pour le rapport de bogue dans <xliff:g id="NUMBER_1">%d</xliff:g> seconde.</item>
+      <item quantity="other">Saisie d\'écran pour le rapport de bogue dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Mode silencieux"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Le son est désactivé."</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Le son est activé."</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Inclut des données personnelles telles que les numéros de cartes de paiement et les mots de passe."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Contrôler l\'agrandissement de l\'écran"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Contrôler le niveau de zoom et le positionnement de l\'écran."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Effectuer des gestes"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Peut toucher, balayer, pincer et effectuer d\'autres gestes."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"désactiver ou modifier la barre d\'état"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Permet à l\'application de désactiver la barre d\'état, ou d\'ajouter et de supprimer des icônes système."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"servir de barre d\'état"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permet à l\'application de prendre des photos et de filmer des vidéos avec l\'appareil photo. Cette autorisation lui permet d\'utiliser l\'appareil photo à tout moment sans votre consentement."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"gérer le vibreur"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Permet à l\'application de gérer le vibreur de l\'appareil."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"gérer la lampe de poche"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Permet à l\'application de gérer la lampe de poche."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"appeler directement des numéros de téléphone"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Permet à l\'application d\'appeler des numéros de téléphone sans votre intervention. Cette autorisation peut entraîner des frais ou des appels imprévus et ne permet pas à l\'application d\'appeler des numéros d\'urgence. Des applications malveillantes peuvent générer des frais en passant des appels sans votre consentement."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"accéder au service d\'appel IMS"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Couper"</string>
     <string name="copy" msgid="2681946229533511987">"Copier"</string>
     <string name="paste" msgid="5629880836805036433">"Coller"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Coller en texte brut"</string>
     <string name="replace" msgid="5781686059063148930">"Remplacer..."</string>
     <string name="delete" msgid="6098684844021697789">"Supprimer"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Copier l\'URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Sélectionner du texte"</string>
+    <string name="undo" msgid="7905788502491742328">"Annuler"</string>
+    <string name="redo" msgid="7759464876566803888">"Répéter"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Sélection de texte"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Ajouter au dictionnaire"</string>
     <string name="deleteText" msgid="6979668428458199034">"Supprimer"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Partager le rapport de bogue avec l\'administrateur?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Votre administrateur informatique a demandé un rapport de bogue pour l\'aider à résoudre le problème"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPTER"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"REFUSER"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Création d\'un rapport de bogue en cours..."</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Touchez pour annuler"</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="9157568568695230830">"Afficher le mode d\'entrée"</string>
-    <string name="hardware" msgid="7517821086888990278">"Matériel"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <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="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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Mis à jour par votre administrateur"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Supprimé par votre administrateur"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Pour améliorer l\'autonomie de la pile, la fonction d\'économie d\'énergie réduit les performances de votre appareil et limite la vibration, les services de localisation ainsi que la plupart des données en arrière-plan. Les applications Courriel, Messages et d\'autres qui reposent sur la synchronisation ne peuvent pas se mettre à jour, sauf si vous les ouvrez. \n\n L\'économiseur d\'énergie se désactive automatiquement lorsque votre appareil est en charge."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Importance"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloquée : ne jamais afficher ces notifications"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Faible : afficher en mode silencieux au bas de la liste de notifications"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normale : afficher ces notifications en mode silencieux"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Élevée : afficher en haut de la liste des notifications et émettre un son"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Urgent : afficher sur l\'écran et émettre un son"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="one">Pendant %1$d minute (jusqu\'à <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="other">Pendant %1$d minutes (jusqu\'à <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"Ces notifications sont importantes en raison des participants."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" essaie d\'ajouter un utilisateur, mais n\'y est pas autorisé."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" essaie d\'ajouter un utilisateur, mais le nombre maximal d\'utilisateurs a été atteint."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" essaie d\'ajouter un utilisateur, mais le compte "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" existe déjà sur cet appareil. Continuer?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" essaie d\'ajouter un utilisateur, mais le compte "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Continuer?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Préférences linguistiques"</string>
+    <string name="country_selection_title" msgid="2954859441620215513">"Préférence régionales"</string>
+    <string name="search_language_hint" msgid="7042102592055108574">"Entrez la langue"</string>
+    <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggestions"</string>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Toutes les langues"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Rechercher"</string>
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 6c1af87..b0260ef 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -189,7 +189,7 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Sonnerie activée"</string>
     <string name="reboot_to_update_title" msgid="6212636802536823850">"Mise à jour du système Android"</string>
     <string name="reboot_to_update_prepare" msgid="6305853831955310890">"Préparation de la mise à jour en cours…"</string>
-    <string name="reboot_to_update_package" msgid="3871302324500927291">"Traitement du package de mises à jour en cours…"</string>
+    <string name="reboot_to_update_package" msgid="3871302324500927291">"Traitement du package de mise à jour…"</string>
     <string name="reboot_to_update_reboot" msgid="6428441000951565185">"Redémarrage en cours…"</string>
     <string name="reboot_to_reset_title" msgid="4142355915340627490">"Rétablir la configuration d\'usine"</string>
     <string name="reboot_to_reset_message" msgid="2432077491101416345">"Redémarrage en cours…"</string>
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Rapport de bug"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Créer un rapport de bug"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Cela permet de recueillir des informations concernant l\'état actuel de votre appareil. Ces informations sont ensuite envoyées sous forme d\'e-mail. Merci de patienter pendant la préparation du rapport de bug. Cette opération peut prendre quelques instants."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Rapport interactif"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Utilisez cette option dans la plupart des circonstances. Elle vous permet de suivre la progression du rapport et de saisir plus d\'informations sur le problème. Certaines sections moins utilisées et dont le remplissage demande beaucoup de temps peuvent être omises."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Rapport complet"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">Capture d\'écran pour le rapport de bug dans <xliff:g id="NUMBER_1">%d</xliff:g> seconde</item>
+      <item quantity="other">Capture d\'écran pour le rapport de bug dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Mode silencieux"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Le son est désactivé."</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Le son est activé."</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Inclut des données personnelles telles que les numéros de cartes de paiement et les mots de passe."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Contrôler l\'agrandissement de l\'écran"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Contrôler le niveau de zoom et le positionnement de l\'écran"</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Effectuer des gestes"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Permet d\'appuyer sur l\'écran, de le balayer, de le pincer et d\'effectuer d\'autres gestes."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"Désactivation ou modification de la barre d\'état"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Permet à l\'application de désactiver la barre d\'état, ou d\'ajouter et de supprimer des icônes système."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"remplacer la barre d\'état"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permet à l\'application de prendre des photos et de filmer des vidéos avec l\'appareil photo. Cette autorisation lui permet d\'utiliser l\'appareil photo à tout moment sans votre consentement."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"contrôler le vibreur"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Permet à l\'application de contrôler le vibreur."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"contrôler la lampe de poche"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Permet à l\'application de contrôler la lampe de poche."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"appeler directement les numéros de téléphone"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Permet à l\'application d\'appeler des numéros de téléphone sans votre intervention. Cette autorisation peut entraîner des frais ou des appels imprévus et ne permet pas à l\'application d\'appeler des numéros d\'urgence. Les applications malveillantes peuvent générer des frais en passant des appels sans votre consentement."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"accéder au service d\'appel IMS"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Couper"</string>
     <string name="copy" msgid="2681946229533511987">"Copier"</string>
     <string name="paste" msgid="5629880836805036433">"Coller"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Coller au format texte brut"</string>
     <string name="replace" msgid="5781686059063148930">"Remplacer..."</string>
     <string name="delete" msgid="6098684844021697789">"Supprimer"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Copier l\'URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Sélectionner texte"</string>
+    <string name="undo" msgid="7905788502491742328">"Annuler"</string>
+    <string name="redo" msgid="7759464876566803888">"Rétablir"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Sélection de texte"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Ajouter au dictionnaire"</string>
     <string name="deleteText" msgid="6979668428458199034">"Supprimer"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Partager le rapport de bug avec l\'administrateur ?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Votre administrateur informatique a demandé un rapport de bug pour l\'aider à résoudre le problème."</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPTER"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"REFUSER"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Création du rapport de bug…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Appuyer pour annuler"</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="9157568568695230830">"Afficher mode de saisie"</string>
-    <string name="hardware" msgid="7517821086888990278">"Matériel"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <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="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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Mis à jour par votre administrateur"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Supprimé par votre administrateur"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Pour améliorer l\'autonomie de la batterie, l\'économiseur de batterie réduit les performances et désactive le vibreur, les services de localisation et la plupart des données en arrière-plan. Les messageries électroniques ou autres applications utilisant la synchronisation pourraient ne pas se mettre à jour, sauf si vous les ouvrez.\n\nL\'économiseur de batterie s\'éteint automatiquement lorsque l\'appareil est en charge."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Importance"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloquée : ne jamais afficher ces notifications"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Faible : afficher en mode silencieux au bas de la liste de notifications"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normale : afficher ces notifications en mode silencieux"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Élevée : afficher en haut de la liste des notifications et émettre un son"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Urgent : afficher sur l\'écran et émettre un son"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="one">Pendant %1$d minute (jusqu\'à <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="other">Pendant %1$d minutes (jusqu\'à <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1511,6 +1525,16 @@
       <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 avez défini l\'importance de ces notifications."</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"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_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" essaie d\'ajouter un utilisateur, mais n\'y est pas autorisé."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" essaie d\'ajouter un utilisateur, mais le nombre maximal d\'utilisateurs a été atteint."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" essaie d\'ajouter un utilisateur, mais le compte "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" existe déjà sur cet appareil. Continuer ?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" essaie d\'ajouter un utilisateur au compte "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Continuer ?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Préférences linguistiques"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Toutes les langues"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Rechercher"</string>
 </resources>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 27ac490..b2a69fc 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Informe de erros"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Crear informe de erros"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Este informe recompilará información acerca do estado actual do teu dispositivo para enviala en forma de mensaxe de correo electrónico. O informe de erros tardará un pouco en completarse desde o seu inicio ata que estea preparado para enviarse, polo que che recomendamos que teñas paciencia."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Informe interactivo"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Usa esta opción na maioría das circunstancias. Permíteche realizar un seguimento do progreso do informe e introducir máis detalles sobre o problema. Pode que omita algunhas seccións menos usadas para as que se tarda máis en facer o informe."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Informe completo"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Facendo captura de pantalla para informe de erros en <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item>
+      <item quantity="one">Facendo captura de pantalla para informe de erros en <xliff:g id="NUMBER_0">%d</xliff:g> segundo.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modo de silencio"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"O son está desactivado"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"O son está activado"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Inclúe datos persoais como números e contrasinais de tarxetas de crédito."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Controlar ampliación da pantalla"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlar o nivel do zoom e o posicionamento da pantalla"</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Realizar xestos"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Podes tocar, pasar o dedo, beliscar e realizar outros xestos."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"desactivar ou modificar a barra de estado"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Permite á aplicación desactivar a barra de estado ou engadir e eliminar as iconas do sistema."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"actuar como a barra de estado"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permite á aplicación tomar imaxes e vídeos coa cámara. Con este permiso a aplicación pode utilizar a cámara en calquera momento sen a túa confirmación."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"controlar a vibración"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite á aplicación controlar o vibrador."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"controlar a lanterna"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite á aplicación controlar a luz do flash."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"chamar directamente aos números de teléfono"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite á aplicación chamar a números de teléfono sen a túa intervención. Esta acción pode implicar chamadas ou custos inesperados. Ten en conta que isto non permite á aplicación chamar a números de emerxencia. É posible que aplicacións maliciosas che custen diñeiro debido á realización de chamadas sen a túa confirmación."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"acceso ao servizo de chamadas de IMS"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Cortar"</string>
     <string name="copy" msgid="2681946229533511987">"Copiar"</string>
     <string name="paste" msgid="5629880836805036433">"Pegar"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Pegar como texto sen formato"</string>
     <string name="replace" msgid="5781686059063148930">"Substituír…"</string>
     <string name="delete" msgid="6098684844021697789">"Eliminar"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Copiar URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Seleccionar texto"</string>
+    <string name="undo" msgid="7905788502491742328">"Desfacer"</string>
+    <string name="redo" msgid="7759464876566803888">"Refacer"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Selección de texto"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Engadir ao dicionario"</string>
     <string name="deleteText" msgid="6979668428458199034">"Eliminar"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Queres compartir o informe de erros co administrador?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"O teu administrador de TI solicitou un informe de erros para axudar a solucionar problemas"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEPTAR"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ANULAR"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Creando informe de erros…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Tocar para cancelar o informe de erros"</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="9157568568695230830">"Mostra método de entrada"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardware"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <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="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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizado polo administrador"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Eliminado polo administrador"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Para axudar a mellorar a duración da batería, a función aforro de batería reduce o rendemento do teu dispositivo e limita a vibración, os servizos de localización e a maioría dos datos en segundo plano. É posible que o correo electrónico, as mensaxes e outras aplicacións que dependen da sincronización non se actualicen a menos que os abras. \n\nA función aforro de batería desactívase automaticamente cando pos a cargar o teu dispositivo."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Importancia"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloqueada: non mostrar nunca estas notificacións"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Baixa: mostrar de forma silenciosa na parte inferior da lista de notificacións"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normal: mostrar estas notificacións de forma silenciosa"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Alta: mostrar na parte superior da lista de notificacións e emitir son"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Urxente: mostrar na pantalla e emitir son"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">Durante %1$d minutos (ata as <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">Durante un minuto (ata as <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"É importante polas persoas involucradas."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" está tentando engadir un usuario novo, pero está prohibido."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" está tentando engadir un usuario novo, pero alcanzouse o límite de usuarios."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" está tentando engadir un usuario novo, pero a conta "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" xa existe neste dispositivo. Queres continuar igualmente?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" está tentando engadir un usuario novo á conta "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Queres continuar?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Preferencia de idioma"</string>
+    <string name="country_selection_title" msgid="2954859441620215513">"Preferencia de rexión"</string>
+    <string name="search_language_hint" msgid="7042102592055108574">"Escribe o nome"</string>
+    <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suxeridos"</string>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Todos os idiomas"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Buscar"</string>
 </resources>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index bcb3321..9848cfb 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"બગ રિપોર્ટ"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"બગ રિપોર્ટ લો"</string>
     <string name="bugreport_message" msgid="398447048750350456">"આ, એક ઇ-મેઇલ સંદેશ તરીકે મોકલવા માટે, તમારા વર્તમાન ઉપકરણ સ્થિતિ વિશેની માહિતી એકત્રિત કરશે. એક બગ રિપોર્ટ પ્રારંભ કરીને તે મોકલવા માટે તૈયાર ન થઈ જાય ત્યાં સુધી તેમાં થોડો સમય લાગશે; કૃપા કરીને ધીરજ રાખો."</string>
+    <string name="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 />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">બગ રિપોર્ટ માટે <xliff:g id="NUMBER_1">%d</xliff:g> સેકન્ડમાં સ્ક્રીનશોટ લઈ રહ્યાં છે.</item>
+      <item quantity="other">બગ રિપોર્ટ માટે <xliff:g id="NUMBER_1">%d</xliff:g> સેકન્ડમાં સ્ક્રીનશોટ લઈ રહ્યાં છે.</item>
+    </plurals>
     <string name="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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"સુરક્ષિત મોડ"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android સિસ્ટમ"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"વ્યક્તિગત"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"એપ્લિકેશનને કૅમેરા વડે ચિત્રો અને વિડિઓઝ લેવાની મંજૂરી આપે છે. આ પરવાનગી એપ્લિકેશનને તમારી પુષ્ટિ વિના કોઈપણ સમયે કૅમેરાના ઉપયોગની મંજૂરી આપે છે."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"વાઇબ્રેશન નિયંત્રિત કરો"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"એપ્લિકેશનને વાઇબ્રેટરને નિયંત્રિત કરવાની મંજૂરી આપે છે."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ફ્લેશલાઇટ નિયંત્રિત કરો"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"એપ્લિકેશનને ફ્લેશલાઇટને નિયંત્રિત કરવાની મંજૂરી આપે છે."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"સીધા જ ફોન નંબર્સ પર કૉલ કરો"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"એપ્લિકેશનને તમારા હસ્તક્ષેપ વિના ફોન નંબર્સ પર કૉલ કરવાની મંજૂરી આપે છે. આ અનપેક્ષિત શુલ્ક અથવા કૉલ્સમાં પરિણમી શકે છે. નોંધો કે આ એપ્લિકેશનને કટોકટીના નંબર્સ પર કૉલ કરવાની મંજૂરી આપતું નથી. દુર્ભાવનાપૂર્ણ એપ્લિકેશનો તમારી પુષ્ટિ વિના કૉલ્સ કરીને તમારા પૈસા ખર્ચ કરી શકે છે."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS કૉલ સેવા ઍક્સેસ કરો"</string>
@@ -858,10 +868,13 @@
     <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">"કાઢી નાખો"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"વ્યવસ્થાપક સાથે બગ રિપોર્ટ શેર કરીએ?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"તમારા IT વ્યવસ્થાપક એ સમસ્યા નિવારણમાં સહાય માટે બગ રિપોર્ટની વિનંતી કરી છે"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"સ્વીકારો"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"નકારો"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"બગ રિપોર્ટ લઈ રહ્યાં છે…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"રદ કરવા માટે ટચ કરો"</string>
     <string name="select_input_method" msgid="8547250819326693584">"કીબોર્ડ બદલો"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"કીબોર્ડ્સ પસંદ કરો"</string>
-    <string name="show_ime" msgid="9157568568695230830">"ઇનપુટ પદ્ધતિ બતાવો"</string>
-    <string name="hardware" msgid="7517821086888990278">"હાર્ડવેર"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"વૉલપેપર બદલો"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"સૂચના સાંભળનાર"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"શરત પ્રદાતા"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"સૂચના સહાયક"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"મહત્વ"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"અવરોધિત: આ સૂચનાઓ ક્યારેય બતાવશો નહીં"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"નિમ્ન: સૂચનાની સૂચિની નીચે ચુપચાપ બતાવો"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"સામાન્ય: આ સૂચનાઓ ચુપચાપ બતાવો"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"ઉચ્ચ: સૂચનાઓની સૂચિની ટોચ પર બતાવો અને અવાજ કરો"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"તાત્કાલિક : સ્ક્રીન પર ત્વરિત દ્રષ્ટિ કરો અને અવાજ કરો"</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="other">%1$d મિનિટ માટે (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> સુધી)</item>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"વિવિધ"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"તમે આ સૂચનાઓનું મહત્વ સેટ કર્યું છે."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"શામેલ થયેલ લોકોને કારણે આ મહત્વપૂર્ણ છે."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>", નવા વપરાશકર્તાને ઉમેરવાનો પ્રયાસ કરી રહી છે, પરંતુ હાલમાં પ્રતિબંધિત છે."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>", નવા વપરાશકર્તાને ઉમેરવાનો પ્રયાસ કરી રહી છે, પરંતુ વપરાશકર્તા મર્યાદા સુધી પહોંચી ગયા છો."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>", નવા વપરાશકર્તાને ઉમેરવાનો પ્રયાસ કરી રહી છે, પરંતુ "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" એકાઉન્ટ પહેલાંથી જ આ ઉપકરણ પર અસ્તિત્વમાં છે. કોઇપણ રીતે આગળ વધીએ?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>", "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" એકાઉન્ટ માટે એક નવા વપરાશકર્તાને ઉમેરવાનો પ્રયાસ કરી રહી છે. આગળ વધીએ?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"ભાષા પસંદગી"</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>
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index ef8be64..39608cb 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"बग रिपोर्ट"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"बग रिपोर्ट प्राप्त करें"</string>
     <string name="bugreport_message" msgid="398447048750350456">"ईमेल संदेश के रूप में भेजने के लिए, इसके द्वारा आपके डिवाइस की वर्तमान स्थिति के बारे में जानकारी एकत्र की जाएगी. बग रिपोर्ट प्रारंभ करने से लेकर भेजने के लिए तैयार होने तक कुछ समय लगेगा; कृपया धैर्य रखें."</string>
+    <string name="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 />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">बग रिपोर्ट के लिए <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में स्‍क्रीनशॉट लिया जा रहा है.</item>
+      <item quantity="other">बग रिपोर्ट के लिए <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में स्‍क्रीनशॉट लिया जा रहा है.</item>
+    </plurals>
     <string name="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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android सिस्‍टम"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"व्यक्तिगत"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ऐप्स  को कैमरे से चित्र और वीडियो लेने देता है. यह अनुमति ऐप्स  को किसी भी समय आपकी पुष्टि के बिना कैमरे का उपयोग करने देती है."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"कंपन नियंत्रित करें"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"ऐप्स को कंपनकर्ता नियंत्रित करने देता है."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"फ़्लैशलाइट नियंत्रित करें"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"ऐप्स को फ़्लैशलाइट नियंत्रित करने देता है."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"फ़ोन नंबर पर सीधे कॉल करें"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"ऐप्स  को आपके हस्‍तक्षेप के बिना फ़ोन नंबर पर कॉल करने देता है. इसके परिणाम अप्रत्‍याशित शुल्‍क या कॉल हो सकते हैं. ध्यान दें कि यह ऐप्स  को आपातकालीन नंबर पर कॉल नहीं करने देता. दुर्भावनापूर्ण ऐप्स  आपकी पुष्टि के बिना कॉल करके आपका धन व्‍यय कर सकते हैं."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS कॉल सेवा ऐक्‍सेस करें"</string>
@@ -858,10 +868,13 @@
     <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">"हटाएं"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"व्यवस्थापक के साथ बग रिपोर्ट साझा करें?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"समस्या निवारण में सहायता हेतु आपके आईटी व्यवस्थापक ने बग रिपोर्ट के लिए अनुरोध किया है"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"स्वीकार करें"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"अस्वीकार करें"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"बग रिपोर्ट प्राप्त की जा रही है…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"रद्द करने के लिए स्पर्श करें"</string>
     <string name="select_input_method" msgid="8547250819326693584">"कीबोर्ड बदलें"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"कीबोर्ड चुनें"</string>
-    <string name="show_ime" msgid="9157568568695230830">"इनपुट विधि दिखाएं"</string>
-    <string name="hardware" msgid="7517821086888990278">"हार्डवेयर"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"वॉलपेपर बदलें"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"नोटिफिकेशन श्रवणकर्ता"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"स्थिति प्रदाता"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"नोटिफिकेशन सहायक"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"महत्‍व"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"अवरोधित: ये नोटिफिकेशन कभी ना दिखाएं"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"निम्‍न: नोटिफिकेशन सूची के नीचे मौन रूप से दिखाएं"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"सामान्‍य: ये नोटिफिकेशन मौन रूप से दिखाएं"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"उच्‍च: नोटिफिकेशन सूची के शीर्ष पर दिखाएं और ध्‍वनि करें"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"तत्‍काल: स्‍क्रीन पर एक झलक देखें और ध्‍वनि करें"</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="other">%1$d मिनट के लिए (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> तक)</item>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"विविध"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"आपने इन नोटिफिकेशन का महत्व सेट किया है."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"यह मौजूद व्यक्तियों के कारण महत्वपूर्ण है."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" नए उपयोगकर्ता को जोड़ने का प्रयास कर रहा है, लेकिन वह इस समय प्रतिबंधित है."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" नए उपयोगकर्ता को जोड़ने का प्रयास कर रहा है, लेकिन उपयोगकर्ता की सीमा पूरी हो गई है."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" नए उपयोगकर्ता को जोड़ने का प्रयास कर रहा है, लेकिन "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" खाता इस डिवाइस पर पहले से मौजूद है. फिर भी आगे बढ़ें?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" इस "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" खाते के लिए नया उपयोगकर्ता जोड़ने का प्रयास कर रहा है. आगे बढ़ें?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"भाषा प्राथमिकता"</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>
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index bd0b1fa..2584260 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -212,6 +212,16 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Izvješće o bugovima"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Izvješće o programskoj pogrešci"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Time će se prikupiti podaci o trenutačnom stanju vašeg uređaja koje ćete nam poslati u e-poruci. Za pripremu izvješća o programskoj pogrešci potrebno je nešto vremena pa vas molimo za strpljenje."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktivno izvješće"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"To možete upotrebljavati u većini slučajeva. Moći ćete pratiti izradu izvješća i unijeti više pojedinosti o problemu. Mogu se izostaviti neki odjeljci koji se upotrebljavaju rjeđe i produljuju izradu izvješća."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Potpuno izvješće"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">Izrada snimke zaslona za izvješće o programskoj pogrešci za <xliff:g id="NUMBER_1">%d</xliff:g> sekundu.</item>
+      <item quantity="few">Izrada snimke zaslona za izvješće o programskoj pogrešci za <xliff:g id="NUMBER_1">%d</xliff:g> sekunde.</item>
+      <item quantity="other">Izrada snimke zaslona za izvješće o programskoj pogrešci za <xliff:g id="NUMBER_1">%d</xliff:g> sekundi.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Bešumni način"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Zvuk je isključen"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Zvuk je uključen"</string>
@@ -224,6 +234,7 @@
     <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="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>
@@ -256,6 +267,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Uključuje osobne podatke kao što su brojevi kreditnih kartica i zaporke."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Kontrola uvećanja zaslona"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrolira razinu zumiranja i položaj zaslona."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Izvođenje pokreta"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Može dodirnuti, prijeći prstom, spojiti prste i izvoditi druge pokrete."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"onemogućavanje ili izmjena trake statusa"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Aplikaciji omogućuje onemogućavanje trake statusa ili dodavanje i uklanjanje sistemskih ikona."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"biti traka statusa"</string>
@@ -354,8 +367,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Aplikaciji omogućuje snimanje slika i videozapisa fotoaparatom. Ta dozvola aplikaciji omogućuje upotrebu fotoaparata u bilo kojem trenutku bez vašeg odobrenja."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"upravljanje vibracijom"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Aplikaciji omogućuje nadzor nad vibratorom."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"upravljanje svjetiljkom"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Aplikaciji omogućuje upravljanje svjetiljkom."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"izravno pozivanje telefonskog broja"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Aplikaciji omogućuje pozivanje telefonskih brojeva bez vašeg sudjelovanja. To može dovesti do neočekivanih troškova ili poziva. Uzmite u obzir da se aplikaciji time ne omogućuje pozivanje brojeva u nuždi. Zlonamjerne aplikacije mogu vam uzrokovati dodatne troškove postavljanjem poziva bez vašeg odobrenja."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"pristupiti usluzi poziva izravnih poruka"</string>
@@ -863,10 +874,13 @@
     <string name="cut" msgid="3092569408438626261">"Izreži"</string>
     <string name="copy" msgid="2681946229533511987">"Kopiraj"</string>
     <string name="paste" msgid="5629880836805036433">"Zalijepi"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Zalijepi kao obični tekst"</string>
     <string name="replace" msgid="5781686059063148930">"Zamijeni…"</string>
     <string name="delete" msgid="6098684844021697789">"Izbriši"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Kopiraj URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Odabir teksta"</string>
+    <string name="undo" msgid="7905788502491742328">"Poništi"</string>
+    <string name="redo" msgid="7759464876566803888">"Ponovi"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Odabir teksta"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Dodaj u rječnik"</string>
     <string name="deleteText" msgid="6979668428458199034">"Izbriši"</string>
@@ -1035,10 +1049,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Želite li podijeliti izvješće o programskoj pogrešci s administratorom?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Vaš IT administrator zatražio je izvješće o programskoj pogrešci radi lakšeg rješavanja problema"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"PRIHVATI"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ODBIJ"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Izrada izvješća o programskoj pogrešci…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Dodirnite da biste otkazali"</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="9157568568695230830">"Prikaz način unosa"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardver"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1114,6 +1134,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Promjena pozadinske slike"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Slušatelj obavijesti"</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="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>
@@ -1449,12 +1470,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Ažurira vaš administrator"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Izbrisao administrator"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Da bi se produljilo trajanje baterije, ušteda baterije smanjuje rad uređaja i ograničava vibraciju, usluge lokacije i većinu pozadinskih podataka. Aplikacije za e-poštu, slanje poruka i druge aplikacije koje se oslanjaju na sinkronizaciju možda se neće ažurirati ako ih ne otvorite.\n\nUšteda baterije isključuje se automatski dok se uređaj puni."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Važnost"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokirano: nikad ne prikazuj te obavijesti"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Nisko: tiho prikaži na dnu popisa obavijesti"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Uobičajeno: prikazuj te obavijesti tiho"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Visoko: prikaži na vrhu popisa obavijesti i emitiraj zvučni signal"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Hitno: prikaži na zaslonu i emitiraj zvučni signal"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="one">%1$d minutu (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="few">%1$d minute (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1531,4 +1546,14 @@
     <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_person" msgid="9160133597262938296">"Važno je zbog uključenih osoba."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" pokušava dodati novog korisnika, no to trenutačno nije dopušteno."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" pokušava dodati novog korisnika, no dosegnuto je ograničenje broja korisnika."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" pokušava dodati novog korisnika, ali račun "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" već postoji na ovom uređaju. Želite li ipak nastaviti?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" pokušava dodati novog korisnika za račun "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Želite li nastaviti?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Postavke 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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Svi jezici"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Pretraži"</string>
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 0f3b849..a5d8f14 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Programhiba bejelentése"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Hibajelentés készítése"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Ezzel információt fog gyűjteni az eszköz jelenlegi állapotáról, amelyet a rendszer e-mailben fog elküldeni. Kérjük, legyen türelemmel, amíg a hibajelentés elkészül, és küldhető állapotba kerül."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktív jelentés"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Ezt használja a legtöbb esetben. Segítségével nyomon követheti a jelentés folyamatát, és további információkat kaphat a problémáról. A folyamat során kimaradhatnak az olyan kevésbé használt részek, amelyek jelentése túl sok időt igényel."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Teljes jelentés"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Képernyőkép készítése a hibajelentéshez <xliff:g id="NUMBER_1">%d</xliff:g> másodpercen belül.</item>
+      <item quantity="one">Képernyőkép készítése a hibajelentéshez <xliff:g id="NUMBER_0">%d</xliff:g> másodpercen belül.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Néma üzemmód"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Hang kikapcsolva"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Hang bekapcsolva"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Beleértve a személyes adatokat, például a hitelkártyaszámokat és jelszavakat."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"A kijelző nagyításának vezérlése"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"A kijelző nagyítási/kicsinyítési szintjének és pozíciójának vezérlése"</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Kézmozdulatok végrehajtása"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Koppintás, ujjak gyors csúsztatása és összehúzása, illetve egyéb kézmozdulatok végrehajtása."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"állapotsor kikapcsolása vagy módosítása"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Lehetővé teszi az alkalmazás számára az állapotsor kikapcsolását, illetve rendszerikonok hozzáadását és eltávolítását."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"az állapotsor szerepének átvétele"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Lehetővé teszi az alkalmazás számára, hogy a fényképezőgéppel fotókat és videókat készítsen. Az engedéllyel rendelkező alkalmazás bármikor, az Ön jóváhagyása nélkül használhatja a fényképezőgépet."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"rezgés szabályozása"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Lehetővé teszi az alkalmazás számára a rezgés vezérlését."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"vaku vezérlése"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Lehetővé teszi az alkalmazás számára a vaku vezérlését."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"telefonszámok közvetlen hívása"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Lehetővé teszi az alkalmazás számára, hogy az Ön jóváhagyása nélkül hívjon fel telefonszámokat. Ennek eredményeként váratlan terhelésekkel vagy telefonhívásokkal találkozhat. Vegye figyelembe, hogy ez nem teszi lehetővé segélyhívó számok hívását az alkalmazás számára. A rosszindulatú alkalmazások az Ön jóváhagyása nélkül kezdeményezhetnek hívásokat, így költségek merülhetnek fel."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"hozzáférés az IMS-hívásszolgáltatáshoz"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Kivágás"</string>
     <string name="copy" msgid="2681946229533511987">"Másolás"</string>
     <string name="paste" msgid="5629880836805036433">"Beillesztés"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Beillesztés egyszerű szövegként"</string>
     <string name="replace" msgid="5781686059063148930">"Csere..."</string>
     <string name="delete" msgid="6098684844021697789">"Törlés"</string>
     <string name="copyUrl" msgid="2538211579596067402">"URL másolása"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Szöveg kijelölése"</string>
+    <string name="undo" msgid="7905788502491742328">"Visszavonás"</string>
+    <string name="redo" msgid="7759464876566803888">"Újra"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Szöveg kijelölése"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Hozzáadás a szótárhoz"</string>
     <string name="deleteText" msgid="6979668428458199034">"Törlés"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Megosztja a hibajelentést a rendszergazdával?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"A rendszergazda hibajelentést kért, hogy segíthessen a problémamegoldásban"</string>
+    <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="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Hibajelentés készítése…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"A visszavonáshoz érintse meg"</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="9157568568695230830">"Beviteli mód megjelenítése"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardver"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <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="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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Frissítette a rendszergazda"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"A rendszergazda törölte"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Az akkumulátoridő növelése érdekében az energiatakarékos mód csökkenti az eszköz teljesítményét, és korlátozza a rezgést, a helyszolgáltatásokat, valamint a legtöbb háttéradatot is. Előfordulhat, hogy azok az e-mail-, üzenetküldő és egyéb alkalmazások, amelyek szinkronizálására számít, csak akkor frissítenek, ha megnyitja azokat.\n\nAz energiatakarékos mód automatikusan kikapcsol, ha eszköze töltőn van."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Fontosság"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Letiltva: soha nem jelennek meg ezek az értesítések"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Alacsony: az értesítések az értesítési lista végén jelennek meg hangjelzés nélkül"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normál: hang nélkül jelennek meg ezek az értesítések"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Magas: az értesítések az értesítési lista elején jelennek meg hangjelzéssel"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Sürgős: az értesítések felugranak a képernyőn hangjelzéssel"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">%1$d percen át (eddig: <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">Egy percen át (eddig: <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"Ez az üzenet a résztvevők miatt fontos."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315">"A(z) "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" alkalmazás egy új felhasználót szeretne megadni, ami jelenleg nem engedélyezett."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266">"A(z) "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" alkalmazás egy új felhasználót szeretne megadni, azonban Ön elérte a felhasználók számára vonatkozó felső korlátot."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789">"A(z) "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" alkalmazás egy új felhasználót szeretne megadni, de a(z) "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" fiók már létezik ezen az eszközön. Ettől függetlenül is folytatja?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392">"A(z) "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" alkalmazás egy új felhasználót szeretne hozzáadni a(z) "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" fiókhoz. Folytatja a műveletet?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Nyelvi beállítás"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Minden nyelv"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Keresés"</string>
 </resources>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index dc67e2d..1149ec1 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Վրիպակի զեկույց"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Գրել սխալի զեկույց"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Սա տեղեկություններ կհավաքագրի ձեր սարքի առկա կարգավիճակի մասին և կուղարկի այն էլեկտրոնային նամակով: Որոշակի ժամանակ կպահանջվի վրիպակի մասին զեկուցելու պահից սկսած մինչ ուղարկելը: Խնդրում ենք փոքր-ինչ համբերատար լինել:"</string>
+    <string name="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 />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">Վրիպակի զեկույցի համար էկրանի պատկերի լուսանկարումը կատարվելու է <xliff:g id="NUMBER_1">%d</xliff:g> վայրկյանից:</item>
+      <item quantity="other">Վրիպակի զեկույցի համար էկրանի պատկերի լուսանկարումը կատարվելու է <xliff:g id="NUMBER_1">%d</xliff:g> վայրկյանից:</item>
+    </plurals>
     <string name="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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"Անվտանգ ռեժիմ"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android համակարգ"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"Անձնական"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Թույլ է տալիս հավելվածին ֆոտոխցիկով լուսանկարել և տեսանկարել: Այս թույլտվությունը հնարավորություն է տալիս հավելվածին օգտագործել ֆոտոխցիկը ցանկացած ժամանակ` առանց ձեր հաստատման:"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"կառավարել թրթռումը"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Թույլ է տալիս հավելվածին կառավարել թրթռոցը:"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"կառավարել լապտերը"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Թույլ է տալիս հավելվածին կառավարել լապտերը:"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ուղղակիորեն զանգել հեռախոսահամարներին"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Թույլ է տալիս հավելվածին զանգել հեռախոսահամարներին առանց ձեր միջամտության: Սա կարող է հանգեցնել անկանխատեսելի գանձումների կամ զանգերի: Նկատի ունեցեք, որ սա թույլ չի տալիս հավելվածին զանգել արտակարգ իրավիճակների համարներին: Վնասարար հավելվածները կարող են ձեր հաշվից զանգեր կատարել` առանց ձեր հաստատման:"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"օգտվել IMS զանգերի ծառայությունից"</string>
@@ -858,10 +868,13 @@
     <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">"Ջնջել"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Ուղարկե՞լ վրիպակի զեկույց ադմինիստրատորին:"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Անսարքությունների վերացման նպատակով ձեր ՏՏ ադմինիստրատորին անհրաժեշտ է վրիպակի զեկույց"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ԸՆԴՈՒՆԵԼ"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ՄԵՐԺԵԼ"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Վրիպակի զեկույցի ստեղծում…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Հպեք՝ չեղարկելու համար"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Փոխել ստեղնաշարը"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"Ընտրել ստեղնաշար"</string>
-    <string name="show_ime" msgid="9157568568695230830">"Ցուցադրել մուտքագրման եղանակը"</string>
-    <string name="hardware" msgid="7517821086888990278">"Սարքաշար"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՈՒՓՔԵւՕՖ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Փոխել պաստառը"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Ծանուցման ունկնդիր"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Պայմանների մատակարար"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Ծանուցումների օգնական"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"Կարևորություն"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Արգելափակված է. Երբեք չցուցադրել այս ծանուցումները"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Ցածր. Ցուցադրել ծանուցումների ցանկի ներքևում առանց ձայնային ազդանշանի"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Նորմալ. Ցուցադրել այս ծանուցումներն առանց ձայնային ազդանշանի"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Բարձր. Ցուցադրել ծանուցումների ցանկի վերևում և հնչեցնել ձայնային ազդանշան"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Հրատապ. Ցուցադրել էկրանին և հնչեցնել ձայնային ազդանշան"</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="other">%1$d րոպե (մինչև <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"Զանազան"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"Դուք սահմանել եք այս ծանուցումների կարևորությունը:"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Կարևոր է, քանի որ որոշակի մարդիկ են ներգրավված:"</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" հավելվածը փորձում է նոր օգտվող ավելացնել, սակայն ներկայումս արգելափակված է:"</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" հավելվածը փորձում է նոր օգտվող ավելացնել, սակայն օգտվողների քանակի սահմանաչափը լրացել է:"</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" հավելվածը փորձում է նոր օգտվող ավելացնել, սակայն "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" հաշիվն այս սարքում արդեն գոյություն ունի: Շարունակե՞լ:"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" հավելվածը փորձում է "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" հաշվի համար նոր օգտվող ավելացնել: Շարունակե՞լ:"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Նախընտրելի լեզու"</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>
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index d13168a..37084e3 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Laporan bug"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Ambil laporan bug"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Ini akan mengumpulkan informasi status perangkat Anda saat ini, untuk dikirimkan sebagai pesan email. Harap bersabar, mungkin perlu waktu untuk memulai laporan bug hingga siap dikirim."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Laporan interaktif"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Gunakan ini di berbagai keadaan. Ini memungkinkan Anda melacak kemajuan laporan dan memasukkan detail masalah selengkapnya. Mungkin menghilangkan beberapa bagian yang jarang digunakan dan yang perlu waktu lama untuk dilaporkan."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Laporan lengkap"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Mengambil tangkapan layar untuk laporan bug dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik.</item>
+      <item quantity="one">Mengambil tangkapan layar untuk laporan bug dalam <xliff:g id="NUMBER_0">%d</xliff:g> detik.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Mode senyap"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Suara MATI"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Suara AKTIF"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Meliputi data pribadi seperti nomor kartu kredit dan sandi."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Mengontrol perbesaran layar"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Mengontrol tingkat zoom dan pemosisian layar."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Melakukan isyarat"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Dapat mengetuk, menggesek, mencubit, dan melakukan isyarat lainnya."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"nonaktifkan atau ubah bilah status"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Mengizinkan apl menonaktifkan bilah status atau menambah dan menghapus ikon sistem."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"jadikan bilah status"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Memungkinkan aplikasi mengambil gambar dan video dengan kamera. Izin ini memungkinkan aplikasi menggunakan kamera kapan saja tanpa konfirmasi Anda."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"kontrol getaran"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Mengizinkan aplikasi untuk mengendalikan vibrator."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"mengontrol lampu senter"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Mengizinkan apl mengontrol lampu kilat."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"panggil nomor telepon secara langsung"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Memungkinkan aplikasi menghubungi nomor telepon tanpa campur tangan Anda. Izin ini dapat mengakibatkan biaya atau panggilan tak terduga. Perhatikan bahwa izin ini tidak memungkinkan aplikasi menghubungi nomor darurat. Aplikasi berbahaya dapat menyebabkan Anda dikenakan biaya dengan melakukan panggilan tanpa konfirmasi Anda."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"akses layanan panggilan IMS"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Potong"</string>
     <string name="copy" msgid="2681946229533511987">"Salin"</string>
     <string name="paste" msgid="5629880836805036433">"Tempel"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Tempel sebagai teks biasa"</string>
     <string name="replace" msgid="5781686059063148930">"Ganti..."</string>
     <string name="delete" msgid="6098684844021697789">"Hapus"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Salin URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Pilih teks"</string>
+    <string name="undo" msgid="7905788502491742328">"Urungkan"</string>
+    <string name="redo" msgid="7759464876566803888">"Ulangi"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Pemilihan teks"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Tambahkan ke kamus"</string>
     <string name="deleteText" msgid="6979668428458199034">"Hapus"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Bagikan laporan bug kepada admin?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Admin IT meminta laporan bug untuk membantu memecahkan masalah"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"SETUJU"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"TOLAK"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Mengambil laporan bug…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Sentuh untuk membatalkan"</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="9157568568695230830">"Tampilkan metode masukan"</string>
-    <string name="hardware" msgid="7517821086888990278">"Perangkat Keras"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Ubah wallpaper"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Pendengar pemberitahuan"</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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Diperbarui oleh administrator"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Dihapus oleh administrator"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Untuk membantu meningkatkan masa pakai baterai, penghemat baterai mengurangi kinerja perangkat dan membatasi getaran, layanan lokasi, dan kebanyakan data latar belakang. Email, perpesanan, dan aplikasi lain yang mengandalkan sinkronisasi mungkin tidak diperbarui kecuali jika dibuka.\n\nPenghemat baterai otomatis nonaktif jika perangkat diisi dayanya."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Tingkat Kepentingan"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Diblokir: Jangan pernah menampilkan notifikasi ini"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Rendah: Menampilkan di bagian bawah daftar notifikasi secara diam-diam"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Menampilkan notifikasi ini secara diam-diam"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Tinggi: Menampilkan di bagian atas daftar notifikasi dan membunyikan suara"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Darurat: Muncul di layar dan membunyikan suara"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">Selama %1$d menit (hingga <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">Selama satu menit (hingga <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"Ini penting karena orang-orang yang terlibat."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" mencoba menambahkan pengguna baru, tetapi saat ini dilarang."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" mencoba menambahkan pengguna baru, tetapi batas jumlah pengguna telah tercapai."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" mencoba menambahkan pengguna baru, tetapi akun "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" sudah ada di perangkat. Tetap lanjutkan?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" mencoba menambahkan pengguna baru untuk akun "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Lanjutkan?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Preferensi 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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Semua bahasa"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Telusuri"</string>
 </resources>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 0c42293..662d1dd 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Villutilkynning"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Útbúa villutilkynningu"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Þetta safnar upplýsingum um núverandi stöðu tækisins til að senda með tölvupósti. Það tekur smástund frá því villutilkynningin er ræst og þar til hún er tilbúin til sendingar – sýndu biðlund."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Gagnvirk skýrsla"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Þú getur notað þetta í flestum tilvikum. Með þessu móti geturðu fylgst með framgangi skýrslunnar og slegið inn viðbótarupplýsingar um vandamálið. Hugsanlegt er að lítið notuðum hlutum verði sleppt til að spara tíma."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Heildarskýrsla"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">Tekur skjámynd fyrir villutilkynningu eftir <xliff:g id="NUMBER_1">%d</xliff:g> sekúndu.</item>
+      <item quantity="other">Tekur skjámynd fyrir villutilkynningu eftir <xliff:g id="NUMBER_1">%d</xliff:g> sekúndur.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Hljóðlaus stilling"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"SLÖKKT er á hljóði"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"KVEIKT er á hljóði"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Felur í sér persónuleg gögn á borð við kreditkortanúmer og aðgangsorð."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Stilla skjástærð"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Stjórnaðu aðdrætti og afstöðu skjásins."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Nota bendingar"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Getur ýtt, strokið, fært fingur saman og gert ýmsar aðrar bendingar."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"slökkva á eða breyta stöðustiku"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Leyfir forriti að slökkva á stöðustikunni eða bæta við og fjarlægja kerfistákn."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"vera stöðustikan"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Leyfir forriti að taka myndir og myndskeið með myndavélinni. Þessi heimild leyfir forritinu að nota myndavélina hvenær sem er án þinnar heimildar."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"stjórna titringi"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Leyfir forriti að stjórna titraranum."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"stjórna vasaljósi"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Leyfir forriti að stjórna vasaljósinu."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"hringja beint í símanúmer"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Leyfir forriti að hringja í símanúmer án íhlutunar notanda. Þetta getur haft í för með sér óumbeðin gjöld og símtöl. Athugaðu að þetta leyfir forritinu ekki að hringja í neyðarnúmer. Spilliforrit geta stofnað til kostnaðar fyrir þig með því að hringja símtöl án þinnar heimildar."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"fá aðgang að IMS-símtalsþjónustu"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Klippa"</string>
     <string name="copy" msgid="2681946229533511987">"Afrita"</string>
     <string name="paste" msgid="5629880836805036433">"Líma"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Líma sem ósniðinn texta"</string>
     <string name="replace" msgid="5781686059063148930">"Skipta út…"</string>
     <string name="delete" msgid="6098684844021697789">"Eyða"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Afrita vefslóð"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Velja texta"</string>
+    <string name="undo" msgid="7905788502491742328">"Afturkalla"</string>
+    <string name="redo" msgid="7759464876566803888">"Endurgera"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Textaval"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Bæta við orðabók"</string>
     <string name="deleteText" msgid="6979668428458199034">"Eyða"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Deila villutilkynningu með kerfisstjóra?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Kerfisstjórinn þinn óskaði eftir villutilkynningu til að auðvelda úrræðaleit"</string>
+    <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="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Tekur við villutilkynningu…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Snertu til að hætta við"</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="9157568568695230830">"Sýna innsláttaraðferð"</string>
-    <string name="hardware" msgid="7517821086888990278">"Vélbúnaður"</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="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCDÐEÉFGHIÍJKLMNOÓPQRSTUÚVWXYÝZÞÆÖ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Skipta um veggfóður"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Tilkynningahlustun"</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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Uppfært af kerfisstjóranum"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Eytt af kerfisstjóra"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Til að auka endingu rafhlöðunnar mun orkusparnaður draga úr afköstum tækisins og takmarka titring, staðsetningarþjónustu og megnið af bakgrunnsgögnum. Ekki er víst að tölvupóstur, skilaboð og önnur forrit sem reiða sig á samstillingu uppfærist nema þú opnir þau.\n\nSjálfkrafa er slökkt á orkusparnaði þegar tækið er í hleðslu."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Mikilvægi"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Útilokaðar: Aldrei sýna þessar tilkynningar"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Léttvægar: Sýna neðst á tilkynningalistanum án hljóðs"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Venjulegar: Sýna þessar tilkynningar án hljóðs"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Mikilvægar: Sýna efst á tilkynningalistanum og spila hljóð"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Áríðandi: Birta á skjánum og spila hljóð"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="one">Í %1$d mínútu (til <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="other">Í %1$d mínútur (til <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"Þetta er mikilvægt vegna fólksins sem tekur þátt í þessu."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" er að reyna að bæta við nýjum notanda, en er sjálfur á bannlista."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" er að reyna að bæta við nýjum notanda, en notandahámarkinu hefur þegar verið náð."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" er að reyna að bæta við nýjum notanda, en reikningurinn "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" er nú þegar til á þessu tæki. Halda samt áfram?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" er að reyna að bæta nýjum notanda við reikninginn "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Halda áfram?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Val tungumáls"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Öll tungumál"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Leita"</string>
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 58176ce..230f3e0 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Segnalazione di bug"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Apri segnalazione bug"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Verranno raccolte informazioni sullo stato corrente del dispositivo che saranno inviate sotto forma di messaggio email. Passerà un po\' di tempo prima che la segnalazione di bug aperta sia pronta per essere inviata; ti preghiamo di avere pazienza."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Rapporto interattivo"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Utilizza questa opzione nella maggior parte dei casi. Ti consente di monitorare l\'avanzamento del rapporto e di inserire maggiori dettagli relativi al problema. Potrebbero essere omesse alcune sezioni meno utilizzate il cui inserimento nel rapporto richiede molto tempo."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Rapporto completo"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Lo screenshot per la segnalazione di bug verrà acquisito tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi.</item>
+      <item quantity="one">Lo screenshot per la segnalazione di bug verrà acquisito tra <xliff:g id="NUMBER_0">%d</xliff:g> secondo.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modalità silenziosa"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Audio non attivo"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Audio attivo"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Sono inclusi dati personali come numeri di carte di credito e password."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Controlla l\'ingrandimento del display"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlla il livello di zoom e la posizione del display."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Esegui gesti"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Consente di toccare, far scorrere, pizzicare ed eseguire altri gesti."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"disattivare o modificare la barra di stato"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Consente all\'applicazione di disattivare la barra di stato o di aggiungere e rimuovere icone di sistema."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"ruolo di barra di stato"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Consente all\'applicazione di scattare foto e riprendere video con la fotocamera. Questa autorizzazione consente all\'applicazione di utilizzare la fotocamera in qualsiasi momento senza la tua conferma."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"controllo vibrazione"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Consente all\'applicazione di controllare la vibrazione."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"controllo flash"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Consente all\'applicazione di controllare il flash."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"chiamata diretta n. telefono"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Consente all\'applicazione di chiamare numeri di telefono senza il tuo intervento. Ciò può comportare chiamate o addebiti imprevisti. Tieni presente che ciò non consente all\'applicazione di chiamare numeri di emergenza. Applicazioni dannose potrebbero generare dei costi effettuando chiamate senza la tua conferma."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"Accesso al servizio di chiamata IMS"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Taglia"</string>
     <string name="copy" msgid="2681946229533511987">"Copia"</string>
     <string name="paste" msgid="5629880836805036433">"Incolla"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Incolla come testo normale"</string>
     <string name="replace" msgid="5781686059063148930">"Sostituisci..."</string>
     <string name="delete" msgid="6098684844021697789">"Elimina"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Copia URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Seleziona testo"</string>
+    <string name="undo" msgid="7905788502491742328">"Annulla"</string>
+    <string name="redo" msgid="7759464876566803888">"Ripeti"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Selezione testo"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Aggiungi al dizionario"</string>
     <string name="deleteText" msgid="6979668428458199034">"Elimina"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Condividere la segnalazione di bug con l\'amministratore?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"L\'amministratore IT ha richiesto una segnalazione di bug per poter risolvere più facilmente i problemi"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCETTO"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RIFIUTO"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Recupero della segnalazione di bug…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Tocca per annullare"</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="9157568568695230830">"Mostra metodo immissione"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardware"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Cambia sfondo"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Listener di notifica"</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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Aggiornato dall\'amministratore"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Eliminato dall\'amministratore"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Per aumentare la durata della batteria, la funzione di risparmio energetico riduce le prestazioni del dispositivo e limita vibrazione, servizi di localizzazione e la maggior parte dei dati in background. App di email, messaggi e altre app che si basano sulla sincronizzazione potrebbero essere aggiornate soltanto all\'apertura.\n\nLa funzione di risparmio energetico viene disattivata automaticamente quando il dispositivo è in carica."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Importanza"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloccato: non mostrare mai queste notifiche"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Bassa: mostra silenziosamente alla fine dell\'elenco di notifiche"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normale: mostra silenziosamente queste notifiche"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Alta: mostra all\'inizio dell\'elenco di notifiche e riproduci suono"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Urgente: apri sullo schermo e riproduci suono"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">Per %1$d minuti (fino alle ore <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">Per un minuto (fino alle ore <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1478,8 +1492,8 @@
       <item quantity="other">Per %d ore</item>
       <item quantity="one">Per 1 ora</item>
     </plurals>
-    <string name="zen_mode_until" msgid="7336308492289875088">"Fino alle ore <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_alarm" msgid="9128205721301330797">"Fino alle ore <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (prossima sveglia)"</string>
+    <string name="zen_mode_until" msgid="7336308492289875088">"Fino a <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
+    <string name="zen_mode_alarm" msgid="9128205721301330797">"Fino a <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (prossima sveglia)"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Fino alla disattivazione"</string>
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Fino alla disattivazione di Non disturbare"</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>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"Importante a causa delle persone coinvolte."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" sta cercando di aggiungere un nuovo utente, ma l\'app non è consentita."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" sta cercando di aggiungere un nuovo utente, ma è stato raggiunto il limite massimo di utenti."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" sta cercando di aggiungere un nuovo utente, ma l\'account "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" esiste già su questo dispositivo. Continuare comunque?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" sta cercando di aggiungere un nuovo utente per l\'account "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Continuare?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Preferenza 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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Tutte le lingue"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Cerca"</string>
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index b0c7437..0278191 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -213,6 +213,17 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"דיווח על באג"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"שלח דיווח על באג"</string>
     <string name="bugreport_message" msgid="398447048750350456">"פעולה זו תאסוף מידע על מצב המכשיר הנוכחי שלך על מנת לשלוח אותו כהודעת אימייל. היא תימשך זמן קצר מרגע פתיחת דיווח הבאג ועד לשליחת ההודעה בפועל. אנא המתן בסבלנות."</string>
+    <string name="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 />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="two">יוצר צילום מסך לדוח על באג בעוד <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>
+      <item quantity="one">יוצר צילום מסך לדוח על באג בעוד <xliff:g id="NUMBER_0">%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>
@@ -225,6 +236,7 @@
     <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="safeMode" msgid="2788228061547930246">"מצב בטוח"</string>
     <string name="android_system_label" msgid="6577375335728551336">"‏מערכת Android"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"אישי"</string>
@@ -257,6 +269,8 @@
     <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>
@@ -355,8 +369,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"מאפשר לאפליקציה לצלם תמונות וסרטונים באמצעות המצלמה. אישור זה מאפשר לאפליקציה להשתמש במצלמה בכל עת ללא אישורך."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"שליטה ברטט"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"מאפשר לאפליקציה לשלוט ברטט."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"שליטה בפנס"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"מאפשר לאפליקציה לשלוט בפנס."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"התקשר ישירות למספרי טלפון"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"מאפשר לאפליקציה להתקשר למספרי טלפון ללא התערבותך. פעולה זו עשויה לגרום לשיחות או לחיובים לא צפויים. שים לב שהדבר לא מאפשר לאפליקציה להתקשר למספרי חירום. אפליקציות זדוניות עשויות לגרום לעלויות על ידי ביצוע שיחות ללא התערבותך."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"‏גישה אל שירות שיחות IMS"</string>
@@ -868,10 +880,13 @@
     <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">"העתק כתובת אתר"</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">"מחק"</string>
@@ -1042,10 +1057,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"האם לשתף את הדוח על הבאג עם מנהל המערכת?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"‏מנהל ה-IT ביקש דוח על באג כדי לסייע בפתרון בעיות"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"אישור"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"דחייה"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"עיבוד דוח על באג..."</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"גע כדי לבטל"</string>
     <string name="select_input_method" msgid="8547250819326693584">"שינוי מקלדת"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"בחר מקלדות"</string>
-    <string name="show_ime" msgid="9157568568695230830">"הצג שיטת קלט"</string>
-    <string name="hardware" msgid="7517821086888990278">"חומרה"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1121,6 +1142,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"שנה טפט"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"מאזין להתראות"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ספק תנאי"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"אסיסטנט ההודעות"</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>
@@ -1458,12 +1480,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"חשיבות"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"חסימה: לעולם אל תציג הודעות אלה"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"נמוכה: הצג בתחתית רשימת ההודעות בלי להשמיע צליל"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"רגילה: הצג הודעות אלה בלי להשמיע צליל"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"גבוהה: הצג בראש רשימת ההודעות והשמע צליל"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"דחופה: הצג לרגע על המסך והשמע צליל"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="two">‏למשך %d דקות (עד <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="many">‏למשך %1$d דקות (עד <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1547,6 +1563,16 @@
       <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_topic" msgid="3572280439880023233">"אתה מגדיר את החשיבות של ההודעות האלה."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ההודעה חשובה בשל האנשים המעורבים."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" מנסה להוסיף משתמש חדש, אך אין הרשאה מתאימה."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" מנסה להוסיף משתמש חדש, אך מכסת המשתמשים כבר מלאה."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" מנסה להוסיף משתמש חדש, אך החשבון "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" כבר קיים במכשיר זה. להמשיך בכל זאת?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" מנסה להוסיף משתמש חדש לחשבון "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". להמשיך?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"העדפת שפה"</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>
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index a81b8b4..a92a800 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"バグレポート"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"バグレポートを取得"</string>
     <string name="bugreport_message" msgid="398447048750350456">"現在の端末の状態に関する情報が収集され、その内容がメールで送信されます。バグレポートが開始してから送信可能な状態となるまでには多少の時間がかかりますのでご了承ください。"</string>
+    <string name="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 />
+    <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>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"マナーモード"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"サウンドOFF"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"サウンドON"</string>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"セーフモード"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Androidシステム"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"個人用"</string>
@@ -236,13 +246,13 @@
     <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="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="permgroupdesc_camera" msgid="3250611594678347720">"写真と動画の撮影"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"電話"</string>
-    <string name="permgroupdesc_phone" msgid="6234224354060641055">"通話の発信と管理"</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">"ウィンドウコンテンツの取得"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"カメラでの写真と動画の撮影をアプリに許可します。これにより、アプリが確認なしでいつでもカメラを使用できるようになります。"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"バイブレーションの制御"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"バイブレーションの制御をアプリに許可します。"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ライトのコントロール"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"ライトの制御をアプリに許可します。"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"電話番号発信"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"電話番号への自動発信をアプリに許可します。これにより、予期せぬ発信や料金が発生する可能性があります。なお、緊急通報番号への発信は許可されません。悪意のあるアプリが確認なしで発信し、料金が発生する恐れがあります。"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS通話サービスへのアクセス"</string>
@@ -858,10 +868,13 @@
     <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">"削除"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"管理者とバグレポートを共有しますか?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"IT 管理者からトラブルシューティングに役立てるためバグレポートを共有するようリクエストがありました"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"同意する"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"同意しない"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"バグレポートを取得しています…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"キャンセルするにはタップしてください"</string>
     <string name="select_input_method" msgid="8547250819326693584">"キーボードの変更"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"キーボードの選択"</string>
-    <string name="show_ime" msgid="9157568568695230830">"スクリーンキーボードを表示する"</string>
-    <string name="hardware" msgid="7517821086888990278">"ハードウェア"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"壁紙を変更"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"通知リスナー"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"コンディションプロバイダ"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"通知アシスタント"</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>
@@ -1440,12 +1460,6 @@
     <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">"バッテリーを長持ちさせるため、バッテリーセーバーは端末のパフォーマンスを抑え、バイブレーション、位置情報サービス、大半のバックグラウンドデータを制限します。メール、SMSや、同期を使用するその他のアプリは、起動しても更新されないことがあります。\n\nバッテリーセーバーは端末の充電中は自動的にOFFになります。"</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"重要度"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"ブロック: 今後はこの通知を表示しない"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"低: 通知リストの下にマナーモードで表示する"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"標準: この通知をマナーモードで表示する"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"高: 通知リストの上に表示し、音声でも知らせる"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"緊急: 画面にプレビューを表示し、音声でも知らせる"</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>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"その他"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"このような通知の重要度を設定します。"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"関係するユーザーのため、この設定は重要です。"</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" で新しいユーザーを追加しようとしていますが、現在この操作は禁止されています。"</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" で新しいユーザーを追加しようとしていますが、ユーザー数の上限に達しています。"</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" で新しいユーザーを追加しようとしていますが、アカウント "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" は既にこの端末に存在します。続行しますか?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" でアカウント "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" に新しいユーザーを追加しようとしています。続行しますか?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"言語設定"</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>
 </resources>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 269af61..3f5ad1f 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"ხარვეზის შესახებ ანგარიში"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"შექმენით შეცდომის ანგარიში"</string>
     <string name="bugreport_message" msgid="398447048750350456">"იგი შეაგროვებს ინფორმაციას თქვენი მოწყობილობის ამჟამინდელი მდგომარეობის შესახებ, რათა ის ელფოსტის შეტყობინების სახით გააგზავნოს. ხარვეზის ანგარიშის მომზადებასა და შეტყობინების გაგზავნას გარკვეული დრო სჭირდება. გთხოვთ, მოითმინოთ."</string>
+    <string name="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 />
+    <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>
+    </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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"უსაფრთხო რეჟიმი"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-ის სისტემა"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"პირადი"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"აპს შეეძლება კამერით სურათისა და ვიდეოს გადაღება. ეს ნებართვა აპს უფლებას აძლევს, ნებისმიერ დროს გამოიყენოს კამერა თქვენი დადასტურების გარეშე."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"ვიბრაციის კონტროლი"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"აპს შეეძლება, მართოს ვიბრირება."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ფანრის მართვა"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"აპს შეეძლება, მართოს განათება."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"პირდაპირი დარეკვა ტელეფონის ნომრებზე"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"აპს შეეძლება დარეკოს ტელეფონის ნომრებზე თქვენი ჩარევის გარეშე. ამან შესაძლოა გამოიწვიოს თქვენს სატელეფონი ქვითარზე მოულოდნელი ხარჯებისა და ზარების გაჩენა. გაითვალისწინეთ, რომ აპს გადაუდებელი დახმარების ნომრებზე დარეკვა არ შეუძლია. მავნე აპებს შეეძლება თქვენი დადასტურების გარეშე ზარების განხორციელება და შესაბამისი საფასურის გადახდაც მოგიწევთ."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ზარების სერვისზე წვდომა"</string>
@@ -858,10 +868,13 @@
     <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">"წაშლა"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"გსურთ ხარვეზის შესახებ ანგარიშის ადმინისტრატორთან გაზიარება?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"პრობლემის აღმოფხვრაში დასახმარებლად, თქვენი IT ადმინისტრატორი ხარვეზის შესახებ ანგარიშს ითხოვს."</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"მიღება"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"უარყოფა"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"მიმდინარეობს ხარვეზის შესახებ ანგარიშის შექმნა…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"შეეხეთ გასაუქმებლად"</string>
     <string name="select_input_method" msgid="8547250819326693584">"კლავიატურის შეცვლა"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"კლავიატურების არჩევა"</string>
-    <string name="show_ime" msgid="9157568568695230830">"შეყვანის მეთოდის ჩვენება"</string>
-    <string name="hardware" msgid="7517821086888990278">"მოწყობილობა"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"ფონის შეცვლა"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"შეტყობინებების მსმენელი"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"მდგომარეობის პროვაიდერი"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"შეტყობინებათა ასისტენტი"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"მნიშვნელობის დონე"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"დაბლოკილი: ეს შეტყობინებები აღარასოდეს გამოჩნდება"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"დაბალი: ეს შეტყობინებები სიის ბოლოში, უხმოდ გამოჩნდება"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"ნორმალური: ეს შეტყობინებები უხმოდ გამოჩნდება"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"მაღალი: ეს შეტყობინებები სიის თავში, ხმოვან სიგნალთან ერთად გამოჩნდება"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"გადაუდებელი: შეტყობინებები პირდაპირ ეკრანზე, ხმოვან სიგნალთან ერთად გამოჩნდება"</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">ერთი წუთის განმავლობაში (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>-მდე)</item>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"სხვადასხვა"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"ამ შეტყობინებების მნიშვნელობის დონე განისაზღვრება თქვენ მიერ."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"მნიშვნელოვანია ჩართული მომხმარებლების გამო."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ახალი მომხმარებლის დამატებას ცდილობს, მაგრამ ამჟამად ეს მას ეკრძალება."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ახალი მომხმარებლის დამატებას ცდილობს, მაგრამ მიღწეულია მომხმარებლების ლიმიტი."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ახალი მომხმარებლის დამატებას ცდილობს, მაგრამ ანგარიში — "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" უკვე არსებობს ამ მოწყობილობაში. მაინც გსურთ გაგრძელება?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ცდილობს, ანგარიშს — "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" ახალი მომხმარებელი დაუმატოს. გსურთ გაგრძელება?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"ენის პარამეტრები"</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>
 </resources>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index 6e26292..25de46b 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Вирус туралы хабарлау"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Қате туралы есеп құру"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Құрылғының қазіргі күйі туралы ақпаратты жинап, электрондық хабармен жібереді. Есеп әзір болғанша біраз уақыт кетеді, шыдай тұрыңыз."</string>
+    <string name="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 />
+    <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>
+    </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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"Қауіпсіз режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android жүйесі"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"Жеке"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Қолданбаға камераны қолданып, фотосурет немесе бейне жазу мүмкіндігін береді. Бұл рұқсат камераны кез келген уақытта сіздің құптауыңызды қажет етпей қолдану мүмкіндігін береді."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"тербелісті басқару"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Қолданбаға вибраторды басқаруға рұқсат береді."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"сигналдық шамды басқару"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Қолданбаға қалта шамын басқаруға рұқсат береді."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"нөмірлерге тікелей телефон шалу"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Қолданбаға сіздің қатысуыңызсыз қоңырау шалу мүмкіндігін береді. Нәтижесінде қосымша төлем немесе күтпеген қоңырау алуыңыз мүмкін. Есіңізде болсын, қолданба төтенше байланыстарға қоңырау шала алмайды. Залалды қолданбалар сіздің рұқсатыңызсыз қоңыраулар шалып, күтпеген төлемдерге себеп болуы мүмкін."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS қоңырау қызметін пайдалану"</string>
@@ -858,10 +868,13 @@
     <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">"Жою"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Қате туралы есепті әкімшімен бөлісу керек пе?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"АТ әкімшісі ақауларды жоюға көмектесу үшін қате туралы есепті сұрады"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ҚАБЫЛДАУ"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ҚАБЫЛДАМАУ"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Қате туралы есеп құрылуда…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Бас тарту үшін түртіңіз"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Пернетақтаны өзгерту"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"Пернетақталарды таңдау"</string>
-    <string name="show_ime" msgid="9157568568695230830">"Енгізу әдісін көрсету"</string>
-    <string name="hardware" msgid="7517821086888990278">"Компьютерлік жабдық"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Артқы фонын өзгерту"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Хабар бақылағыш"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Шарт провайдері"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Хабарландыру көмекшісі"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"Маңыздылық"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Бұғатталған: осы хабарландыруларды ешқашан көрсетпеу"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Төмен: хабарландырулар тізімнің төменгі жағында үнсіз көрсету"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Қалыпты: осы хабарландыруларды үнсіз көрсету"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Жоғары: хабарландырулар тізімінің жоғарғы жағында көрсету және дыбыс шығару"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Шұғыл: экранға бекіту және дыбыс шығару"</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">Бір минут бойы (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> дейін)</item>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"Әр түрлі"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"Сіз осы хабарландырулардың маңыздылығын орнатасасыз."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Қатысты адамдарға байланысты бұл маңызды."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" есептік жазбасы үшін жаңа пайдаланушыны қосуға тырысуда, бірақ қазіргі уақытта тыйым салынған."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" жаңа пайдаланушыны қосуға тырысуда, бірақ пайдаланушылар саны шегіне жетті."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" жаңа пайдаланушыны қосуға тырысуда, бірақ "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" есептік жазбасы осы құрылғыда әлдеқашан бар. Бәрібір жалғастыру керек пе?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" есептік жазбасы үшін жаңа пайдаланушыны қосуға тырысуда. Жалғастыру керек пе?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Тіл параметрі"</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>
 </resources>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 167fa17..6b51f61 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"របាយការណ៍​កំហុស"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"យក​របាយការណ៍​កំហុស"</string>
     <string name="bugreport_message" msgid="398447048750350456">"វា​នឹង​​ប្រមូល​ព័ត៌មាន​អំពី​ស្ថានភាព​ឧបករណ៍​របស់​អ្នក ដើម្បី​ផ្ញើ​ជា​សារ​អ៊ីមែល។ វា​នឹង​ចំណាយ​ពេល​តិច​ពី​ពេល​ចាប់ផ្ដើម​របាយការណ៍​រហូត​ដល់​ពេល​វា​រួចរាល់​ដើម្បី​ផ្ញើ សូម​អត់ធ្មត់។"</string>
+    <string name="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 />
+    <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>
+    </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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"របៀប​​​សុវត្ថិភាព"</string>
     <string name="android_system_label" msgid="6577375335728551336">"ប្រព័ន្ធ​​ Android"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"ផ្ទាល់ខ្លួន"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ឲ្យ​កម្មវិធី​ថត​រូប និង​វីដេអូ​ដោយ​ប្រើ​ម៉ាស៊ីន​ថត។ វា​ឲ្យ​កម្មវិធី​​ប្រើ​ម៉ាស៊ីន​ថត​នៅ​ពេល​​ណាមួយ​ដោយ​គ្មាន​ការ​បញ្ជាក់​របស់​អ្នក។"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"ពិនិត្យ​ការ​ញ័រ"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"ឲ្យ​កម្មវិធី​គ្រប់គ្រង​កម្មវិធី​ញ័រ។"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ត្រួតពិនិត្យ​ពិល"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"ឲ្យ​កម្មវិធី​ពិនិត្យ​ពិល។"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ហៅ​លេខ​ទូរស័ព្ទ​ដោយ​ផ្ទាល់"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"ឲ្យ​កម្មវិធី​ហៅ​លេខ​ទូរស័ព្ទ​ដោយ​គ្មាន​សកម្មភាព​របស់​អ្នក។​ វា​អាច​កាត់​លុយ​ ឬ​ហៅ​ដោយ​មិន​រំពឹង​ទុក។ ចំណាំ​ថា​ វា​មិន​អនុញ្ញាត​ឲ្យ​កម្មវិធី​ហៅ​លេខ​ពេល​អាសន្ន​ទេ។ កម្មវិធី​ព្យាបាទ​អាច​កាត់​លុយ​របស់​អ្នក​ ដោយ​ធ្វើការ​ហៅ​ដោយ​គ្មាន​ការ​បញ្ជាក់​របស់​អ្នក។"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"ចូលដំណើរការសេវាកម្មការហៅតាម IMS"</string>
@@ -858,10 +868,13 @@
     <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">"លុប"</string>
@@ -1030,10 +1043,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"ចែករំលែករបាយការណ៍កំហុសជាមួយអ្នកគ្រប់គ្រងឬ?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"អ្នកគ្រប់គ្រងព័ត៌មានវិទ្យារបស់អ្នកបានស្នើរបាយការណ៍កំហុសដើម្បីជួយដោះស្រាយបញ្ហា"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ព្រមទទួល"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"បដិសេធ"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"ទទួលយករបាយការណ៍កំហុស…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"ប៉ះដើម្បីបោះបង់"</string>
     <string name="select_input_method" msgid="8547250819326693584">"ប្ដូរ​ក្ដារចុច"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"ជ្រើស​ក្ដារចុច"</string>
-    <string name="show_ime" msgid="9157568568695230830">"បង្ហាញ​វិធី​សាស្ត្រ​បញ្ចូល"</string>
-    <string name="hardware" msgid="7517821086888990278">"ផ្នែក​រឹង"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1109,6 +1128,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"ប្ដូរ​ផ្ទាំង​រូបភាព"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"កម្មវិធី​ស្ដាប់​ការ​ជូន​ដំណឹង"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ក្រុមហ៊ុន​ផ្ដល់​លក្ខខណ្ឌ"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"ជំនួយការជូនដំណឹង"</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>
@@ -1442,12 +1462,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"សារៈសំខាន់"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"បានរារាំង៖ កុំបង្ហាញការជូនដំណឹងទាំងនេះ"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"កម្រិតទាប៖ បង្ហាញស្ងាត់ៗនៅផ្នែកខាងក្រោមបញ្ជីនៃការជូនដំណឹង"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"ធម្មតា៖ បង្ហាញការជូនដំណឹងទាំងនេះស្ងាត់ៗ"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"កម្រិតខ្ពស់៖ បង្ហាញនៅផ្នែកខាងលើបញ្ជីនៃការជូនដំណឹង និងបន្លឺសំឡេង"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"បន្ទាន់៖ លោតបង្ហាញនៅលើអេក្រង់ និងបន្លឺសំឡេង"</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">រយៈពេលមួយនាទី (រហូតដល់ <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1515,4 +1529,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"ផ្សេងៗ"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"អ្នកបានកំណត់សារៈសំខាន់នៃការជូនដំណឹងទាំងនេះ"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"វាមានសារៈសំខាន់ដោយសារតែមនុស្សដែលពាក់ព័ន្ធ"</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" កំពុងព្យាយាមបន្ថែមអ្នកប្រើថ្មី ប៉ុន្តែគណនីត្រូូវបានហាមឃាត់នាពេលបច្ចុប្បន្ន។"</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" កំពុងព្យាយាមបន្ថែមអ្នកប្រើថ្មី ប៉ុន្តែបានឈានដល់ចំនួនកំណត់អ្នកប្រើហើយ។"</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" កំពុងព្យាយាមបន្ថែមអ្នកប្រើថ្មី ប៉ុន្តែគណនី "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" មានរួចទៅហើយនៅលើឧបករណ៍នេះ។ បន្តទោះយ៉ាងណាក៏ដោយ?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" កំពុងព្យាយាមបន្ថែមអ្នកប្រើថ្មីសម្រាប់គណនី "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>"។ បន្តឬ?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"ចំណូល​ចិត្ត​ភាសា"</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>
 </resources>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index 17ccbd1..d85d3984 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"ದೋಷದ ವರದಿ"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"ದೋಷ ವರದಿ ರಚಿಸಿ"</string>
     <string name="bugreport_message" msgid="398447048750350456">"ನಿಮ್ಮ ಸಾಧನದ ಪ್ರಸ್ತುತ ಸ್ಥಿತಿಯ ಕುರಿತು ಮಾಹಿತಿಯನ್ನು ಸಂಗ್ರಹಿಸಿಕೊಳ್ಳುವುದರ ಜೊತೆ ಇ-ಮೇಲ್ ರೂಪದಲ್ಲಿ ನಿಮಗೆ ರವಾನಿಸುತ್ತದೆ. ಇದು ದೋಷ ವರದಿಯನ್ನು ಪ್ರಾರಂಭಿಸಿದ ಸಮಯದಿಂದ ಅದನ್ನು ಕಳುಹಿಸುವವರೆಗೆ ಸ್ವಲ್ಪ ಸಮಯವನ್ನು ತೆಗೆದುಕೊಳ್ಳುತ್ತದೆ; ದಯವಿಟ್ಟು ತಾಳ್ಮೆಯಿಂದಿರಿ."</string>
+    <string name="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 />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">ಬಗ್ ವರದಿ ಮಾಡಲು <xliff:g id="NUMBER_1">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ತೆಗೆದುಕೊಳ್ಳಲಾಗುತ್ತಿದೆ.</item>
+      <item quantity="other">ಬಗ್ ವರದಿ ಮಾಡಲು <xliff:g id="NUMBER_1">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ತೆಗೆದುಕೊಳ್ಳಲಾಗುತ್ತಿದೆ.</item>
+    </plurals>
     <string name="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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"ಸುರಕ್ಷಿತ ಮೋಡ್"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android ಸಿಸ್ಟಂ"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"ವೈಯಕ್ತಿಕ"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ಕ್ಯಾಮರಾ ಮೂಲಕ ಚಿತ್ರಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳನ್ನು ಸೆರೆಹಿಡಿಯಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಈ ಅನುಮತಿಯು ನಿಮ್ಮ ಖಾತರಿ ಇಲ್ಲದೆಯೇ ಯಾವುದೇ ಸಮಯದಲ್ಲಿ ಕ್ಯಾಮರಾವನ್ನು ಬಳಸಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"ವೈಬ್ರೇಷನ್‌‌ ನಿಯಂತ್ರಿಸಿ"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"ವೈಬ್ರೇಟರ್‌ ನಿಯಂತ್ರಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ಫ್ಲ್ಯಾಶ್‌ಲೈಟ್ ನಿಯಂತ್ರಿಸಿ"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"ಫ್ಲ್ಯಾಶ್‌ಲೈಟ್ ನಿಯಂತ್ರಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ಫೋನ್ ಸಂಖ್ಯೆಗಳಿಗೆ ನೇರವಾಗಿ ಕರೆ ಮಾಡಿ"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"ನಿಮ್ಮ ಹಸ್ತಕ್ಷೇಪ ಇಲ್ಲದೆಯೇ ಫೋನ್‍ ಸಂಖ್ಯೆಗಳಿಗೆ ಕರೆ ಮಾಡಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅನುಮತಿಸುತ್ತದೆ. ಇದು ಅನಿರೀಕ್ಷಿತ ಶುಲ್ಕಗಳು ಅಥವಾ ಕರೆಗಳಿಗೆ ಕಾರಣವಾಗಬಹುದು. ತುರ್ತು ಸಂಖ್ಯೆಗಳಿಗೆ ಕರೆಮಾಡಲು ಈ ಅಪ್ಲಿಕೇಶನ್‍ ಅನುಮತಿಸುವುದಿಲ್ಲ ಎಂಬುದು ಗಮನದಲ್ಲಿರಲಿ. ದುರುದ್ದೇಶಪೂರಿತ ಅಪ್ಲಿಕೇಶನ್‍‍ಗಳು ನಿಮ್ಮ ಖಾತರಿ ಇಲ್ಲದೆಯೇ ಕರೆಗಳನ್ನು ಮಾಡುವುದರ ಮೂಲಕ ನಿಮ್ಮ ಹಣ ಖರ್ಚಾಗಬಹುದು."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ಕರೆ ಸೇವೆಯನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
@@ -858,10 +868,13 @@
     <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">"ಅಳಿಸು"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"ದೋಷ ವರದಿಯನ್ನು ನಿರ್ವಾಹಕರ ಜೊತೆಗೆ ಹಂಚಿಕೊಳ್ಳುವುದೇ?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"ನಿಮ್ಮ ಐಟಿ ನಿರ್ವಾಹಕರು ಸಮಸ್ಯೆ ನಿವಾರಣೆಗೆ ಸಹಾಯ ಮಾಡಲು ದೋಷ ವರದಿಯನ್ನು ಮನವಿ ಮಾಡಿದ್ದಾರೆ"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ಸಮ್ಮತಿಸು"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ತಿರಸ್ಕರಿಸು"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"ದೋಷದ ವರದಿಯನ್ನು ತೆಗೆದುಕೊಳ್ಳಲಾಗುತ್ತಿದೆ…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"ರದ್ದುಗೊಳಿಸಲು ಸ್ಪರ್ಶಿಸಿ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"ಕೀಬೋರ್ಡ್ ಬದಲಿಸಿ"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"ಕೀಬೋರ್ಡ್‌ಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
-    <string name="show_ime" msgid="9157568568695230830">"ಇನ್‌ಪುಟ್‌ ವಿಧಾನವನ್ನು ತೋರಿಸು"</string>
-    <string name="hardware" msgid="7517821086888990278">"ಹಾರ್ಡ್‌ವೇರ್"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"ವಾಲ್‌ಪೇಪರ್ ಬದಲಿಸಿ"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"ಅಧಿಸೂಚನೆ ಕೇಳುಗ"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ಕಂಡೀಶನ್ ಪೂರೈಕೆದಾರರು"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"ಅಧಿಸೂಚನೆ ಸಹಾಯಕ"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"ಪ್ರಾಮುಖ್ಯತೆ"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ: ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಎಂದಿಗೂ ತೋರಿಸಬೇಡ"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"ಕಡಿಮೆ: ಅಧಿಸೂಚನೆ ಪಟ್ಟಿಯ ಕೆಳಭಾಗದಲ್ಲಿ ಸ್ಥಬ್ಧವಾಗಿ ತೋರಿಸು"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"ಸಾಮಾನ್ಯ: ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಸ್ಥಬ್ಧವಾಗಿ ತೋರಿಸು"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"ಅಧಿಕ: ಅಧಿಸೂಚನೆಗಳ ಪಟ್ಟಿಯ ಮೇಲ್ಭಾಗದಲ್ಲಿ ತೋರಿಸು ಮತ್ತು ಧ್ವನಿ ಮಾಡು"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"ತುರ್ತು: ಪರದೆಯನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ಧ್ವನಿ ಮಾಡು"</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="other">%1$d ನಿಮಿಷಗಳವರೆಗೆ (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> ವರೆಗೆ)</item>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"ಇತರೆ"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"ನೀವು ಈ ಅಧಿಸೂಚನೆಗಳ ಪ್ರಾಮುಖ್ಯತೆಯನ್ನು ಹೊಂದಿಸಿರುವಿರಿ."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ಜನರು ತೊಡಗಿಕೊಂಡಿರುವ ಕಾರಣ ಇದು ಅತ್ಯಂತ ಪ್ರಮುಖವಾಗಿದೆ."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ಹೊಸ ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಲು ಪ್ರಯತ್ನಿಸುತ್ತಿದ್ದಾರೆ, ಆದರೆ ಪ್ರಸ್ತುತವಾಗಿ ನಿಷೇಧಿಸಲಾಗಿದೆ."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ಹೊಸ ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಲು ಪ್ರಯತ್ನಿಸುತ್ತಿದ್ದಾರೆ, ಆದರೆ ಬಳಕೆದಾರರ ಮಿತಿಯನ್ನು ತಲುಪಲಾಗಿದೆ."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ಹೊಸ ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಲು ಪ್ರಯತ್ನಿಸುತ್ತಿದ್ದಾರೆ, ಆದರೆ ಈ ಸಾಧನದಲ್ಲಿ "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" ಖಾತೆ ಈಗಾಗಲೇ ಅಸ್ತಿತ್ವದಲ್ಲಿದೆ. ಹೇಗಾದರೂ ಮುಂದುವರೆಯುವುದೇ?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" ಖಾತೆಗೆ ಹೊಸ ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಲು "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ಪ್ರಯತ್ನಿಸುತ್ತಿದ್ದಾರೆ. ಮುಂದುವರೆಯುವುದೇ?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"ಭಾಷೆಯ ಪ್ರಾಶಸ್ತ್ಯ"</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>
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index a78037f..1a92e93 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"버그 신고"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"버그 신고"</string>
     <string name="bugreport_message" msgid="398447048750350456">"현재 기기 상태에 대한 정보를 수집하여 이메일 메시지로 전송합니다. 버그 신고를 시작하여 전송할 준비가 되려면 약간 시간이 걸립니다."</string>
+    <string name="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 />
+    <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>
+    </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>
@@ -223,28 +232,29 @@
     <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="safeMode" msgid="2788228061547930246">"안전 모드"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 시스템"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"개인"</string>
     <string name="managed_profile_label" msgid="6260850669674791528">"직장"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"주소록"</string>
-    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"주소록 액세스"</string>
+    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"주소록에 접근할 수 있도록"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"위치"</string>
-    <string name="permgroupdesc_location" msgid="1346617465127855033">"이 기기의 위치에 액세스"</string>
+    <string name="permgroupdesc_location" msgid="1346617465127855033">"이 기기의 위치정보에 접근할 수 있도록"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"캘린더"</string>
-    <string name="permgroupdesc_calendar" msgid="3889615280211184106">"캘린더 액세스"</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="permgroupdesc_sms" msgid="4656988620100940350">"문자 메시지를 보내고 확인할 수 있도록"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"저장"</string>
-    <string name="permgroupdesc_storage" msgid="637758554581589203">"기기 사진, 미디어, 파일 액세스"</string>
+    <string name="permgroupdesc_storage" msgid="637758554581589203">"기기 사진, 미디어, 파일에 접근할 수 있도록"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"마이크"</string>
-    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"오디오 녹음"</string>
+    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"오디오를 녹음할 수 있도록"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"카메라"</string>
-    <string name="permgroupdesc_camera" msgid="3250611594678347720">"사진 및 동영상 촬영"</string>
+    <string name="permgroupdesc_camera" msgid="3250611594678347720">"사진 및 동영상을 촬영할 수 있도록"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"전화"</string>
-    <string name="permgroupdesc_phone" msgid="6234224354060641055">"전화 걸기 및 관리"</string>
+    <string name="permgroupdesc_phone" msgid="6234224354060641055">"통화 상태를 관리하거나 전화를 걸 수 있도록"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"신체 센서"</string>
-    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"생체 신호에 관한 센서 데이터에 액세스"</string>
+    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"생체 신호에 관한 센서 데이터에 접근할 수 있도록"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"창 콘텐츠 가져오기"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"상호작용 중인 창의 콘텐츠를 검사합니다."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"터치하여 탐색 사용"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"앱이 카메라로 사진과 동영상을 찍을 수 있도록 허용합니다. 이 권한을 사용하면 앱이 언제든지 사용자의 확인 없이 카메라를 사용할 수 있습니다."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"진동 제어"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"앱이 진동을 제어할 수 있도록 허용합니다."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"카메라 플래시 제어"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"앱이 카메라 플래시를 제어할 수 있도록 허용합니다."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"전화번호 자동 연결"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"앱이 사용자의 조작 없이 전화번호로 전화를 걸 수 있도록 허용합니다. 이 경우 예상치 못한 통화 요금이 부과될 수 있습니다. 앱이 비상 전화를 걸도록 하는 권한은 주어지지 않습니다. 악성 앱이 사용자의 확인 없이 전화를 걸어 요금이 부과될 수 있습니다."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS 통화 서비스에 액세스"</string>
@@ -858,10 +868,13 @@
     <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">"삭제"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"관리자와 버그 보고서를 공유하시겠습니까?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"IT 관리자가 문제해결을 위해 버그 보고서를 요청했습니다."</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"수락"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"거절"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"버그 보고서 가져오는 중..."</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"취소하려면 터치하세요."</string>
     <string name="select_input_method" msgid="8547250819326693584">"키보드 변경"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"키보드 선택"</string>
-    <string name="show_ime" msgid="9157568568695230830">"입력 방법 표시"</string>
-    <string name="hardware" msgid="7517821086888990278">"하드웨어"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"배경화면 변경"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"알림 수신기"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"조건 제공자"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"알림 어시스턴트"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"중요도"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"차단: 알림 다시 표시 안함"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"낮음: 알림 목록 하단에 무음으로 표시"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"일반: 무음으로 알림 표시"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"높음: 알림 목록 상단에 표시하고 소리로 알림"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"긴급: 화면에 표시하고 소리로 알림"</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>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"기타"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"이러한 알림의 중요도를 설정했습니다."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"관련된 사용자가 있으므로 중요합니다."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>"에서 새 사용자를 추가하려고 하지만 현재 금지되어 있습니다."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>"에서 새 사용자를 추가하려고 하지만 사용자 한도에 도달했습니다."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>"에서 새 사용자를 추가하려고 하지만 계정 "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>"이(가) 이미 기기에 있습니다. 계속할까요?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>"에서 계정 "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>"에 새 사용자를 추가하려고 합니다. 계속할까요?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"언어 환경설정"</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>
 </resources>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 9d2c80c3..f9dcce5 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Ката тууралуу билдирүү"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Ката тууралуу билдирүү түзүү"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Бул сиздин түзмөгүңүздүн учурдагы абалын эмейл билдирүүсү катары жөнөтүш максатында маалымат чогултат. Ката тууралуу билдирүү түзүлүп башталып, жөнөтүлгөнгө чейин бир аз убакыт керек болот; сураныч, бир аз күтө туруңуз."</string>
+    <string name="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 />
+    <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>
+    </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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"Коопсуз режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android Тутуму"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"Жеке"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Колдонмого камера аркылуу видео жана сүрөт тартуу уруксатын берет. Бул уруксат, камераны каалаган убакта, сиздин ырастооңузсуз колдонуу уруксатын берет."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"титирөөнү башкаруу"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Колдонмого дирилдегичти көзөмөлдөө мүмкүнчүлүгүн берет."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"кол чыракты көзөмөлдөө"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Колдонмого колчыракты көзөмөлдөө мүмкүнчүлүгүн берет."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"телефон номерлерине түз чалуу"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Колдонмого сиздин катышууңузсуз телефон номурларга чалуу уруксатын берет. Бул сиз күтпөгөн чыгымдарга же чалууларга алып келиши мүмкүн. Бул куткаруучулардын номурларына чалууга уруксат бербей тургандыгын эске алыңыз. Зыяндуу колдонмолор, сиздин ырастооңузсуз чалууларды аткарып, көп чыгымдарга себепкер болушу мүмкүн."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS чалуу кызматына мүмкүнчүлүк алуу"</string>
@@ -859,10 +869,13 @@
     <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">"Жок кылуу"</string>
@@ -1029,10 +1042,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Администратор менен мүчүлүштүктөр тууралуу кабар бөлүшүлсүнбү?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"IT администраторуңуз мүчүлүштүктөр тууралуу маалыматты сурап жатат. Бул маалыматтын жардамы менен бузулган жерлерди аныктап, оңдоп берет."</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"КАБЫЛ АЛУУ"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ЧЕТКЕ КАГУУ"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Мүчүлүштүк тууралуу кабар алынууда…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Жокко чыгаруу үчүн тийип коюңуз"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Баскычтопту өзгөртүү"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"Баскычтопторду тандаңыз"</string>
-    <string name="show_ime" msgid="9157568568695230830">"Киргизүү ыкмасын көрсөтүү"</string>
-    <string name="hardware" msgid="7517821086888990278">"Аппараттык"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1108,6 +1127,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Тушкагазды өзгөртүү"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Эскертүү тыңшагычы"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Шарт түзүүчү"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Эскертме жардамчысы"</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>
@@ -1441,12 +1461,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"Маанилүүлүгү"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Бөгөттөлгөн: Бул эскертмелер эч качан көрсөтүлбөсүн"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Төмөн: Эскертмелер тизмесинин эң ылдыйында үнсүз көрсөтүлсүн"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Кадимки: Бул эскертмелер үнсүз көрсөтүлсүн"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Жогору: Эскертмелер тизмесинин эң жогорусунда үн чыгарып көрсөтүлсүн"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Шашылыш: Үн менен коштолуп, экранга чыгарылсын"</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">Бир мүнөткө (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> чейин)</item>
@@ -1512,6 +1526,16 @@
       <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_person" msgid="9160133597262938296">"Ага катышкан адамдардан улам ал маанилүү."</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"Бул эскертмелердин маанилүүлүгүн белгиледиңиз."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"Булар сиз үчүн маанилүү адамдар."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" жаңы колдонуучуну кошууга аракет кылууда, бирок учурда ага тыюу салынган."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" жаңы колдонуучуну кошууга аракет кылууда, бирок колдонуучулардын саны эң жогорку чекке жетип калды."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" жаңы колдонуучуну кошууга аракет кылууда, бирок түзмөктө мындай каттоо эсеби "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" мурунтан эле бар. Баары бир уланта бересизби?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" жаңы колдонуучуну "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" каттоо эсебине кошууга аракет кылууда. Улантылсынбы?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Тил жөндөөлөрү"</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>
 </resources>
diff --git a/core/res/res/values-land/config.xml b/core/res/res/values-land/config.xml
new file mode 100644
index 0000000..7308dc5
--- /dev/null
+++ b/core/res/res/values-land/config.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<resources>
+    <integer name="config_dockedStackDividerSnapMode">2</integer>
+</resources>
\ No newline at end of file
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 0510a25..1fe72ac 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"ລາຍງານຂໍ້ຜິດພາດ"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"ໃຊ້ລາຍງານຂໍ້ບົກພ່ອງ"</string>
     <string name="bugreport_message" msgid="398447048750350456">"ນີ້ຈະເປັນການເກັບກຳຂໍ້ມູນກ່ຽວກັບ ສະຖານະປັດຈຸບັນຂອງອຸປະກອນທ່ານ ເພື່ອສົ່ງເປັນຂໍ້ຄວາມທາງອີເມວ. ມັນຈະໃຊ້ເວລາໜ້ອຍນຶ່ງ ໃນການເລີ່ມຕົ້ນການລາຍງານຂໍ້ຜິດພາດ ຈົນກວ່າຈະພ້ອມທີ່ຈະສົ່ງໄດ້, ກະລຸນາລໍຖ້າ."</string>
+    <string name="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 />
+    <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>
+    </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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"ລະບົບ Android"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"​ສ່ວນ​ໂຕ"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ອະນຸຍາດໃຫ້ແອັບຯຖ່າຍຮູບ ແລະວິດີໂອດ້ວຍກ້ອງຖ່າຍຮູບ. ການອະນຸຍາດນີ້ຈະອານຸຍາດໃຫ້ແອັບຯ ສາມາດໃຊ້ກ້ອງຖ່າຍຮູບໄດ້ຕະຫລອດເວລາ ໂດຍບໍ່ຕ້ອງຖ້າການຢືນຢັນຈາກທ່ານ."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"ຄວບຄຸມການສັ່ນ"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"ອະນຸຍາດໃຫ້ແອັບຯຄວບຄຸມໂຕສັ່ນ."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ຄວບຄຸມໄຟແຟລດ"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"ອະນຸຍາດໃຫ້ແອັບຯ ຄວບຄຸມໄຟແຟລດ."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ໂທຫາເບີໂທລະສັບໂດຍກົງ"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"ອະນຸຍາດໃຫ້ແອັບຯໂທຫາເບີໂທລະສັບໄດ້ ໂດຍບໍ່ຕ້ອງຖ້າການດຳເນີນການໃດໆຈາກທ່ານ. ຄຸນສົມບັດນີ້ອາດກໍ່ໃຫ້ເກີດຄ່າໃຊ້ຈ່າຍໃນການໂທທີ່ບໍ່ຄາດຄິດໄດ້. ໝາຍເຫດ: ຄຸນສົມບັດນີ້ບໍ່ໄດ້ເປັນການອະນຸຍາດໃຫ້ແອັບຯ ສາມາດໂທຫາເບີສຸກເສີນ. ແອັບຯທີ່ເປັນອັນຕະລາຍອາດເຮັດໃຫ້ທ່ານ ຕ້ອງເສຍຄ່າໂທໂດຍທີ່ບໍ່ໄດ້ຄາດຄິດ."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"ເຂົ້າ​ຫາ​ການ​ບໍ​ລິ​ການ​ໂທ IMS"</string>
@@ -858,10 +868,13 @@
     <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">"ລຶບ"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"ແບ່ງປັນລາຍງານຂໍ້ຜິດພາດກັບຜູ້ເບິ່ງແຍງລະບົບບໍ?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"ຜູ້ເບິ່ງແຍງລະບົບໄອທີຂອງທ່ານໄດ້ຮ້ອງຂໍເອົາລາຍງານຂໍ້ຜິດພາດເພື່ອຊ່ວຍແກ້ໄຂບັນຫາ"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ຍອມຮັບ"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ປະຕິເສດ"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"ກຳລັງເອົາລາຍງານຂໍ້ຜິດພາດ…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"ແຕະເພື່ອຍົກເລີກ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"​ປ່ຽນ​ແປ້ນ​ພິມ"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"​ເລືອກ​ແປ້ນ​ພິມ"</string>
-    <string name="show_ime" msgid="9157568568695230830">"​ສະ​ແດງ​ຮູບ​ແບບ​ການ​ປ້ອນ​ຂໍ້​ມູນ"</string>
-    <string name="hardware" msgid="7517821086888990278">"ຮາດແວ"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"ປ່ຽນພາບພື້ນຫຼັງ"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"ໂຕຟັງການແຈ້ງເຕືອນ"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"​ຜູ່​ສະ​ໜອງ​ເງື່ອນ​ໄຂ"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"ຕົວຊ່ວຍ​ການ​ແຈ້ງ​ເຕືອນ"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"ຄວາມສໍາຄັນ"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"ບລັອກແລ້ວ: ຢ່າສະແດງການແຈ້ງເຕືອນເຫຼົ່ານີ້"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"ຕໍ່າ: ສະແດງຢູ່ສ່ວນລຸ່ມຂອງລາຍການແຈ້ງເຕືອນແບບມີບໍ່ສຽງ"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"ປົກກະຕິ: ສະແດງການແຈ້ງເຕືອນເຫຼົ່ານີ້ແບບບໍ່ມີສຽງ"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"ສູງ: ສະແດງຢູ່ສ່ວນເທິງຂອງລາຍການແຈ້ງເຕືອນ ແລະສົ່ງສຽງດັງ"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"ດ່ວນ: ເດັ້ງຂຶ້ນເທິງຫນ້າຈໍ ແລະສົ່ງສຽງດັງ"</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>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"ອື່ນໆ"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"ທ່ານຕັ້ງຄວາມສຳຄັນຂອງການແຈ້ງເຕືອນເຫຼົ່ານີ້."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ຂໍ້ຄວາມນີ້ສຳຄັນເນື່ອງຈາກບຸກຄົນທີ່ກ່ຽວຂ້ອງ."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ກຳລັງພະຍາຍາມເພີ່ມຜູ້ໃຊ້ໃໝ່, ແຕ່ຖືກຫ້າມໃນຂະນະນີ້."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ກຳລັງພະຍາຍາມເພີ່ມຜູ້ໃຊ້ໃໝ່, ແຕ່ໄດ້ຮອດຂີດຈຳກັດຜູ້ໃຊ້ແລ້ວ."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ກຳລັງພະຍາຍາມເພີ່ມຜູ້ໃຊ້ໃໝ່, ແຕ່ບັນຊີ "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" ມີຢູ່ແລ້ວໃນອຸປະກອນນີ້. ແນວໃດກໍດຳເນີນຕໍ່ບໍ?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ກຳລັງພະຍາຍາມເພີ່ມຜູ້ໃຊ້ໃໝ່ສຳລັບບັນຊີ "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". ດຳເນີນຕໍ່ບໍ?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"ການຕັ້ງຄ່າພາສາ"</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>
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 67eff63..2e78344 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -213,6 +213,17 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Pranešimas apie riktą"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Pranešti apie riktą"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Bus surinkta informacija apie dabartinę įrenginio būseną ir išsiųsta el. pašto pranešimu. Šiek tiek užtruks, kol pranešimas apie riktą bus paruoštas siųsti; būkite kantrūs."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interakt. ataskaita"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Naudokite tai esant daugumai aplinkybių. Galite stebėti ataskaitos eigą ir įvesti daugiau išsamios informacijos apie problemą. Gali būti praleidžiamos kelios nelabai naudingos skiltys, kurių ataskaitų teikimas ilgai trunka."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Išsami ataskaita"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">Pranešimo apie riktą ekrano kopija bus užfiksuota po <xliff:g id="NUMBER_1">%d</xliff:g> sekundės.</item>
+      <item quantity="few">Pranešimo apie riktą ekrano kopija bus užfiksuota po <xliff:g id="NUMBER_1">%d</xliff:g> sekundžių.</item>
+      <item quantity="many">Pranešimo apie riktą ekrano kopija bus užfiksuota po <xliff:g id="NUMBER_1">%d</xliff:g> sekundės.</item>
+      <item quantity="other">Pranešimo apie riktą ekrano kopija bus užfiksuota po <xliff:g id="NUMBER_1">%d</xliff:g> sekundžių.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Tylus režimas"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Garsas IŠJUNGTAS"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Garsas ĮJUNGTAS"</string>
@@ -225,6 +236,7 @@
     <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="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>
@@ -257,6 +269,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Įtraukiami asmeniniai duomenys, pavyzdžiui, kredito kortelių numeriai ir slaptažodžiai."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Ekrano didinimo valdymas"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Valdykite ekrano mastelio keitimo lygį ir pozicijos nustatymą."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Veiksmai gestais"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Galima paliesti, perbraukti, suimti ir atlikti kitus veiksmus gestais."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"išjungti ar keisti būsenos juostą"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Leidžiama programai neleisti būsenos juostos arba pridėti ir pašalinti sistemos piktogramas."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"būti būsenos juosta"</string>
@@ -355,8 +369,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Leidžiama programai fotografuoti ir filmuoti kamera. Šis leidimas suteikia teisę programai naudoti kamerą bet kada be jūsų patvirtinimo."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"valdyti vibraciją"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Leidžiama programai valdyti vibravimą."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"valdyti šviesos signalą"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Leidžiama programai valdyti šviesos signalą."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"skambinti tiesiogiai telefono numeriais"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Leidžiama programai skambinti telefonų numeriais be jūsų įsikišimo. Dėl to gali atsirasti nenumatytų apmokestinimų ar skambučių. Atminkite, kad programai neleidžiama skambinti pagalbos telefonų numeriais. Kenkėjiškos programos gali skambinti be jūsų patvirtinimo, o dėl to jums gali būti taikomi mokesčiai."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"pasiekti IMS skambučių paslaugą"</string>
@@ -868,10 +880,13 @@
     <string name="cut" msgid="3092569408438626261">"Iškirpti"</string>
     <string name="copy" msgid="2681946229533511987">"Kopijuoti"</string>
     <string name="paste" msgid="5629880836805036433">"Įklijuoti"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Įklijuoti kaip grynąjį tekstą"</string>
     <string name="replace" msgid="5781686059063148930">"Pakeisti•"</string>
     <string name="delete" msgid="6098684844021697789">"Ištrinti"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Kopijuoti URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Pasirinkti tekstą"</string>
+    <string name="undo" msgid="7905788502491742328">"Anuliuoti"</string>
+    <string name="redo" msgid="7759464876566803888">"Grąžinti"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Teksto pasirinkimas"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Pridėti prie žodyno"</string>
     <string name="deleteText" msgid="6979668428458199034">"Ištrinti"</string>
@@ -1042,10 +1057,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Bendrinti pranešimą apie riktą su administratoriumi?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Jūsų IT administratorius pateikė pranešimo apie riktą užklausą, kad galėtų padėti pašalinti triktis"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"SUTIKTI"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ATMESTI"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Pateikiamas pranešimas apie riktą…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Palieskite, kad atšauktumėte"</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="9157568568695230830">"Rodyti įvesties metodą"</string>
-    <string name="hardware" msgid="7517821086888990278">"Apar. įr."</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="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
@@ -1121,6 +1142,7 @@
     <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="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="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>
@@ -1458,12 +1480,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Atnaujino administratorius"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Ištrynė administratorius"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Kad tausotų akumuliatoriaus energiją akumuliatoriaus tausojimo priemonė sumažina įrenginio veikimą ir apriboja vibravimą, vietovės paslaugas bei daugumą foninių duomenų. El. pašto, susirašinėjimo ir kitos programos, kurios veikia sinchronizavimo pagrindu, gali būti neatnaujintos, nebent jas atidarysite.\n\nAkumuliatoriaus tausojimo priemonė automatiškai išjungiama, kai įrenginys įkraunamas."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Svarba"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Užblokuota: niekada nerodyti šių pranešimų"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Maža: tyliai rodyti pranešimų sąrašo apačioje"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Įprasta: tyliai rodyti šiuos pranešimus"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Didelė: rodyti pranešimų sąrašo viršuje ir skambėti"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Skubu: rodyti ekrane ir skambėti"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="one">%1$d minutę (iki <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="few">%1$d minutes (iki <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1549,4 +1565,14 @@
     <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_person" msgid="9160133597262938296">"Tai svarbu dėl susijusių žmonių."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"„<xliff:g id="APP">%1$s</xliff:g>“"</b>" bando pridėti naują naudotoją, tačiau šiuo metu tai draudžiama."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"„<xliff:g id="APP">%1$s</xliff:g>“"</b>" bando pridėti naują naudotoją, tačiau pasiektas naudotojų skaičiaus apribojimas."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"„<xliff:g id="APP">%1$s</xliff:g>“"</b>" bando pridėti naują naudotoją, tačiau paskyra "<b>"„<xliff:g id="ACCOUNT">%2$s</xliff:g>“"</b>" jau yra šiame įrenginyje. Vis tiek tęsti?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"„<xliff:g id="APP">%1$s</xliff:g>“"</b>" bando pridėti naują paskyros "<b>"„<xliff:g id="ACCOUNT">%2$s</xliff:g>“"</b>" naudotoją. Tęsti?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Kalbos nuostata"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Visos kalbos"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Paieška"</string>
 </resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 95c3536..9da04df 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -212,6 +212,16 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Kļūdu ziņojums"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Kļūdu ziņojuma sagatavošana"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Veicot šo darbību, tiks apkopota informācija par jūsu ierīces pašreizējo stāvokli un nosūtīta e-pasta ziņojuma veidā. Kļūdu ziņojuma pabeigšanai un nosūtīšanai var būt nepieciešams laiks. Lūdzu, esiet pacietīgs."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktīvs pārskats"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Izmantojiet lielākajā daļā gadījumu. Varat izsekot pārskata izveides norisi un ievadīt papildu informāciju par problēmu. Var tikt izlaistas dažas mazāk izmantotas sadaļas, kuru izveidei nepieciešams daudz laika."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Viss pārskats"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="zero">Pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm tiks veikts ekrānuzņēmums kļūdas pārskatam.</item>
+      <item quantity="one">Pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundes tiks veikts ekrānuzņēmums kļūdas pārskatam.</item>
+      <item quantity="other">Pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm tiks veikts ekrānuzņēmums kļūdas pārskatam.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Klusuma režīms"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Skaņa ir IZSLĒGTA."</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Skaņa ir IESLĒGTA."</string>
@@ -224,6 +234,7 @@
     <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="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>
@@ -256,6 +267,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Ietver personas datus, piemēram, kredītkartes numurus un paroles."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Displeja palielinājuma kontrole"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrolējiet displeja tālummaiņas līmeni un pozicionēšanu."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Žestu izpilde"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Atbalsta pieskaršanos, vilkšanu, savilkšanu un citus žestus."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"atspējot vai pārveidot statusa joslu"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Ļauj lietotnei atspējot statusa joslu vai pievienot un noņemt sistēmas ikonas."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"Būt par statusa joslu"</string>
@@ -354,8 +367,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Ļauj lietotnei uzņemt attēlus un videoklipus ar kameru. Ar šo atļauju lietotne var jebkurā brīdī izmantot kameru bez jūsu apstiprinājuma."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"kontrolēt vibrosignālu"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Ļauj lietotnei kontrolēt vibrosignālu."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolēt uzliesmojumu"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Ļauj lietotnei kontrolēt zibspuldzi."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"tieši zvanīt uz tālruņa numuriem"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Ļauj lietotnei zvanīt uz tālruņa numuriem bez jūsu iejaukšanās. Tas var radīt neparedzētas izmaksas vai zvanus. Ņemiet vērā, ka lietotnei nav atļauts zvanīt uz tālruņa numuriem ārkārtas situācijām. Ļaunprātīgas lietotnes var radīt jums izmaksas, veicot zvanus bez jūsu apstiprinājuma."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"piekļūt tūlītējās ziņojumapmaiņas pakalpojumam, lai veiktu zvanus"</string>
@@ -863,10 +874,13 @@
     <string name="cut" msgid="3092569408438626261">"Izgriezt"</string>
     <string name="copy" msgid="2681946229533511987">"Kopēt"</string>
     <string name="paste" msgid="5629880836805036433">"Ielīmēt"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Ielīmēt kā vienkāršu tekstu"</string>
     <string name="replace" msgid="5781686059063148930">"Aizstāt"</string>
     <string name="delete" msgid="6098684844021697789">"Dzēst"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Kopēt URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Atlasīt tekstu"</string>
+    <string name="undo" msgid="7905788502491742328">"Atsaukt"</string>
+    <string name="redo" msgid="7759464876566803888">"Atcelt atsaukšanu"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Teksta atlase"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Pievienot vārdnīcai"</string>
     <string name="deleteText" msgid="6979668428458199034">"Dzēst"</string>
@@ -1035,10 +1049,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Vai kopīgot kļūdas pārskatu ar administratoru?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Jūsu IT administrators pieprasīja kļūdas pārskatu, lai palīdzētu novērst problēmu."</string>
+    <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="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Notiek kļūdas pārskata izveide…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Pieskarieties, lai atceltu"</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="9157568568695230830">"Rādīt ievades metodi"</string>
-    <string name="hardware" msgid="7517821086888990278">"Aparatūra"</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="fast_scroll_alphabet" msgid="5433275485499039199">" AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
@@ -1114,6 +1134,7 @@
     <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="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="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>
@@ -1449,12 +1470,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Atjaunināja administrators"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Izdzēsa jūsu administrators"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Lai paildzinātu akumulatora darbību, akumulatora jaudas taupīšanas režīmā tiek samazināta ierīces veiktspēja un tiek ierobežota vibrācija, atrašanās vietu pakalpojumi un lielākā daļa fona datu. E-pasta, ziņojumapmaiņas un cita veida lietotnes, kuru darbības pamatā ir datu sinhronizācija, var netikt atjauninātas, ja tās neatverat.\n\nTiklīdz tiek sākta ierīces uzlāde, akumulatora jaudas taupīšanas režīms automātiski tiek izslēgts."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Svarīgums"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloķēts: nekad nerādīt šos paziņojumus"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Zemu: rādīt paziņojumu saraksta apakšdaļā bez skaņas signāla"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normāli: rādīt šos paziņojumus bez skaņas signāla"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Augstu: rādīt paziņojumu saraksta augšdaļā un ar skaņas signālu"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Steidzami: rādīt ekrānā ar skaņas signālu"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="zero">%1$d minūtes (līdz <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">%1$d minūti (līdz <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1531,4 +1546,14 @@
     <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_person" msgid="9160133597262938296">"Tas ir svarīgi iesaistīto personu dēļ."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" mēģina pievienot jaunu lietotāju, taču pašlaik tas ir aizliegts."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" mēģina pievienot jaunu lietotāju, taču ir sasniegts lietotāju skaita ierobežojums."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" mēģina pievienot jaunu lietotāju, taču šajā ierīcē jau ir izveidots konts "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Vai turpināt?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" mēģina pievienot jaunu lietotāju kontam "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Vai turpināt?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Valodas preference"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Visas valodas"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Meklēt"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc160-af/strings.xml b/core/res/res/values-mcc310-mnc160-af/strings.xml
new file mode 100644
index 0000000..72ca2f2
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-af/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">"Om oproepe te maak en boodskappe oor Wi-Fi te stuur, vra jou diensverskaffer eers om hierdie diens op te stel. Skakel Wi-Fi-oproepe dan weer in Instellings aan."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Registreer by jou diensverskaffer"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s Wi-Fi-oproep"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-am/strings.xml b/core/res/res/values-mcc310-mnc160-am/strings.xml
new file mode 100644
index 0000000..5a6635c
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-am/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">"የ%s Wi-Fi ጥሪ"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-ar/strings.xml b/core/res/res/values-mcc310-mnc160-ar/strings.xml
new file mode 100644
index 0000000..c0e4229
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-ar/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">"‏%s جارٍ الاتصال عبر Wi-Fi"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-az-rAZ/strings.xml b/core/res/res/values-mcc310-mnc160-az-rAZ/strings.xml
new file mode 100644
index 0000000..0c250cd
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-az-rAZ/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 üzərindən zəng etmək və mesaj göndərmək üçün ilk öncə operatordan bu xidməti ayarlamağı tələb edin. Sonra Ayarlardan Wi-Fi çağrısını aktivləşdirin."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Operatorla qeydiyyatdan keçin"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s Wi-Fi Zəngi"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-b+sr+Latn/strings.xml b/core/res/res/values-mcc310-mnc160-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..d351d5e
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-b+sr+Latn/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 upućivali pozive i slali poruke preko Wi-Fi-ja, prvo zatražite od mobilnog operatera da vam omogući ovu uslugu. Zatim u Podešavanjima ponovo uključite Pozivanje preko Wi-Fi-ja."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Registrujte se kod mobilnog 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-mnc160-bg/strings.xml b/core/res/res/values-mcc310-mnc160-bg/strings.xml
new file mode 100644
index 0000000..88715f5
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-bg/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">"%s – обаждания през Wi-Fi"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-bn-rBD/strings.xml b/core/res/res/values-mcc310-mnc160-bn-rBD/strings.xml
new file mode 100644
index 0000000..0c3e816
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-bn-rBD/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">"%s Wi-Fi কলিং"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-ca/strings.xml b/core/res/res/values-mcc310-mnc160-ca/strings.xml
new file mode 100644
index 0000000..89baf1b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-ca/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">"Per fer trucades i enviar missatges per Wi-Fi, primer has de demanar a l\'operador de telefonia mòbil que configuri aquest servei. Després, torna a activar les trucades per Wi-Fi des de Configuració."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Registra\'t amb el teu operador de telefonia mòbil"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"Trucada per Wi-Fi amb %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-cs/strings.xml b/core/res/res/values-mcc310-mnc160-cs/strings.xml
new file mode 100644
index 0000000..3eb962e
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-cs/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">"Chcete-li volat a odesílat textové zprávy přes síť Wi-Fi, nejprve požádejte operátora, aby vám tuto službu nastavil. Poté volání přes Wi-Fi opět zapněte v Nastavení."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Registrace u operátora"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"Volání přes Wi-Fi: %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-da/strings.xml b/core/res/res/values-mcc310-mnc160-da/strings.xml
new file mode 100644
index 0000000..8e401d8
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-da/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">"Hvis du vil foretage opkald og sende beskeder via Wi-Fi, skal du først anmode dit mobilselskab om at konfigurere denne tjeneste. Derefter skal du slå Wi-Fi-opkald til igen fra Indstillinger."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Registrer dig hos dit mobilselskab"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s Wi-Fi-opkald"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-de/strings.xml b/core/res/res/values-mcc310-mnc160-de/strings.xml
new file mode 100644
index 0000000..7b172d8
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-de/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">"Um über WLAN telefonieren und Nachrichten senden zu können, bitte zuerst deinen Mobilfunkanbieter, diesen Dienst einzurichten. Aktiviere die Option \"Anrufe über WLAN\" dann erneut über die Einstellungen."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Registriere dich bei deinem Mobilfunkanbieter."</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s Anrufe über WLAN"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-el/strings.xml b/core/res/res/values-mcc310-mnc160-el/strings.xml
new file mode 100644
index 0000000..bfd09c0
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-el/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">"%s Κλήση Wi-Fi"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-en-rAU/strings.xml b/core/res/res/values-mcc310-mnc160-en-rAU/strings.xml
new file mode 100644
index 0000000..d4f59ed
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-en-rAU/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">"To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Register with your operator"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s Wi-Fi Calling"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-en-rGB/strings.xml b/core/res/res/values-mcc310-mnc160-en-rGB/strings.xml
new file mode 100644
index 0000000..d4f59ed
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-en-rGB/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">"To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Register with your operator"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s Wi-Fi Calling"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-en-rIN/strings.xml b/core/res/res/values-mcc310-mnc160-en-rIN/strings.xml
new file mode 100644
index 0000000..d4f59ed
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-en-rIN/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">"To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Register with your operator"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s Wi-Fi Calling"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-es-rUS/strings.xml b/core/res/res/values-mcc310-mnc160-es-rUS/strings.xml
new file mode 100644
index 0000000..8930a3e
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-es-rUS/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">"Para realizar llamadas o enviar mensajes por Wi-Fi, primero solicítale al proveedor que instale el servicio. Luego, vuelve a activar las llamadas por Wi-Fi desde Configuración."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Regístrate con tu proveedor."</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"Llamada por Wi-Fi de %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-es/strings.xml b/core/res/res/values-mcc310-mnc160-es/strings.xml
new file mode 100644
index 0000000..1aac00b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-es/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">"Para hacer llamadas y enviar mensajes por Wi-Fi, debes pedir antes a tu operador que configure este servicio. Una vez hecho esto, vuelva a activar las llamadas Wi-Fi en Ajustes."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Regístrate con tu operador"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"Llamada Wi-Fi de %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-et-rEE/strings.xml b/core/res/res/values-mcc310-mnc160-et-rEE/strings.xml
new file mode 100644
index 0000000..c3be115
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-et-rEE/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">"WiFi-võrgu kaudu helistamiseks ja sõnumite saatmiseks paluge operaatoril esmalt see teenus seadistada. Seejärel lülitage WiFi-kõned menüüs Seaded uuesti sisse."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Registreeruge operaatori juures"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"Operaatori %s WiFi-kõned"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-eu-rES/strings.xml b/core/res/res/values-mcc310-mnc160-eu-rES/strings.xml
new file mode 100644
index 0000000..93c4026
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-eu-rES/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 bidez deiak egiteko eta mezuak bidaltzeko, eskatu operadoreari zerbitzu hori gaitzeko. Ondoren, aktibatu Wi-Fi bidezko deiak Ezarpenak atalean."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Erregistratu operadorearekin"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s Wi-Fi bidezko deiak"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-fa/strings.xml b/core/res/res/values-mcc310-mnc160-fa/strings.xml
new file mode 100644
index 0000000..247693a
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-fa/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">"‏تماس ‪%s Wi-Fi"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-fi/strings.xml b/core/res/res/values-mcc310-mnc160-fi/strings.xml
new file mode 100644
index 0000000..aebdf71
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-fi/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">"Jos haluat soittaa puheluita ja lähettää viestejä Wi-Fin kautta, pyydä ensin operaattoriasi ottamaan tämä palvelu käyttöön. Ota sitten Wi-Fi-puhelut käyttöön asetuksissa."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Rekisteröidy operaattorisi asiakkaaksi."</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"Wi-Fi-puhelut: %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-fr-rCA/strings.xml b/core/res/res/values-mcc310-mnc160-fr-rCA/strings.xml
new file mode 100644
index 0000000..b0d21c2
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-fr-rCA/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">"Pour effectuer des appels et envoyer des messages par Wi-Fi, demandez tout d\'abord à votre fournisseur de services de configurer ce service. Réactivez ensuite les appels Wi-Fi dans les paramètres."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Inscrivez-vous auprès de votre fournisseur de services"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"Appels Wi-Fi %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-fr/strings.xml b/core/res/res/values-mcc310-mnc160-fr/strings.xml
new file mode 100644
index 0000000..9fe787c
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-fr/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">"Pour effectuer des appels et envoyer des messages via le Wi-Fi, demandez tout d\'abord à votre opérateur de configurer ce service. Réactivez ensuite les appels Wi-Fi dans les paramètres."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Inscrivez-vous auprès de votre opérateur."</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"Appels Wi-Fi %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-gl-rES/strings.xml b/core/res/res/values-mcc310-mnc160-gl-rES/strings.xml
new file mode 100644
index 0000000..f02d667
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-gl-rES/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">"Para facer chamadas e enviar mensaxes a través da wifi, primeiro pídelle ao teu operador que configure este servizo. A continuación, activa de novo as chamadas por wifi en Configuración."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Rexístrate co teu operador"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"Chamadas por wifi de %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-gu-rIN/strings.xml b/core/res/res/values-mcc310-mnc160-gu-rIN/strings.xml
new file mode 100644
index 0000000..e218ee6
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-gu-rIN/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">"%s Wi-Fi કૉલિંગ"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-hi/strings.xml b/core/res/res/values-mcc310-mnc160-hi/strings.xml
new file mode 100644
index 0000000..23f4dc8
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-hi/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">"वाई-फ़ाई से कॉल करने और संदेश भेजने के लिए, सबसे पहले अपने वाहक से इस सेवा को सेट करने के लिए कहें. उसके बाद सेटिंग से पुन: वाई-फ़ाई कॉलिंग चालू करें."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"अपने वाहक के साथ पंजीकृत करें"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s वाई-फ़ाई कॉलिंग"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-hr/strings.xml b/core/res/res/values-mcc310-mnc160-hr/strings.xml
new file mode 100644
index 0000000..956093a
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-hr/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 telefonirali i slali pozive putem Wi-Fi-ja, morate tražiti od mobilnog operatera da vam postavi tu uslugu. Zatim ponovo uključite Wi-Fi pozive u Postavkama."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Registrirajte se kod mobilnog operatera"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s Wi-Fi pozivanje"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-hu/strings.xml b/core/res/res/values-mcc310-mnc160-hu/strings.xml
new file mode 100644
index 0000000..7dbf9e8
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-hu/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">"Ha Wi-Fin szeretne telefonálni és üzenetet küldeni, kérje meg szolgáltatóját, hogy állítsa be ezt a szolgáltatást. Ezután a Beállítások menüben kapcsolhatja be újra a Wi-Fi-hívást."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Regisztráljon szolgáltatójánál"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s Wi-Fi-hívás"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-hy-rAM/strings.xml b/core/res/res/values-mcc310-mnc160-hy-rAM/strings.xml
new file mode 100644
index 0000000..aadc509
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-hy-rAM/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">"%s Wi-Fi զանգեր"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-in/strings.xml b/core/res/res/values-mcc310-mnc160-in/strings.xml
new file mode 100644
index 0000000..3640291
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-in/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">"Untuk melakukan panggilan telepon dan mengirim pesan melalui Wi-Fi, terlebih dahulu minta operator untuk menyiapkan layanan ini. Lalu, aktifkan lagi panggilan telepon Wi-Fi dari Setelan."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Harap daftarkan ke operator"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s Panggilan Wi-Fi"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-is-rIS/strings.xml b/core/res/res/values-mcc310-mnc160-is-rIS/strings.xml
new file mode 100644
index 0000000..fd10da5
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-is-rIS/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">"Til að hringja og senda skilaboð yfir Wi-Fi þarftu fyrst að biðja símafyrirtækið þitt um að setja þá þjónustu upp. Kveiktu síðan á Wi-Fi símtölum í stillingunum."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Skráðu þig hjá símafyrirtækinu"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s Wi-Fi símtöl"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-it/strings.xml b/core/res/res/values-mcc310-mnc160-it/strings.xml
new file mode 100644
index 0000000..d8479d3
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-it/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">"Per poter effettuare chiamate e inviare messaggi tramite Wi-Fi, devi chiedere all\'operatore di attivare il servizio. Dopodiché, riattiva le chiamate Wi-Fi dalle Impostazioni."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Registrati con il tuo operatore"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"Chiamate Wi-Fi %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-iw/strings.xml b/core/res/res/values-mcc310-mnc160-iw/strings.xml
new file mode 100644
index 0000000..2aa3937
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-iw/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-ja/strings.xml b/core/res/res/values-mcc310-mnc160-ja/strings.xml
new file mode 100644
index 0000000..e589334
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-ja/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サービスを申し込んだ上で、設定画面でWi-Fi発信を再度ONにしてください。"</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-ka-rGE/strings.xml b/core/res/res/values-mcc310-mnc160-ka-rGE/strings.xml
new file mode 100644
index 0000000..2b8fd07
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-ka-rGE/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">"%s დარეკვა Wi-Fi-ს მეშვეობით"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-kk-rKZ/strings.xml b/core/res/res/values-mcc310-mnc160-kk-rKZ/strings.xml
new file mode 100644
index 0000000..b4f2433
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-kk-rKZ/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">"%s Wi-Fi арқылы қоңырау шалу"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-km-rKH/strings.xml b/core/res/res/values-mcc310-mnc160-km-rKH/strings.xml
new file mode 100644
index 0000000..1806fbc
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-km-rKH/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-kn-rIN/strings.xml b/core/res/res/values-mcc310-mnc160-kn-rIN/strings.xml
new file mode 100644
index 0000000..43d942a
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-kn-rIN/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">"%s Wi-Fi ಕರೆ ಮಾಡುವಿಕೆ"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-ko/strings.xml b/core/res/res/values-mcc310-mnc160-ko/strings.xml
new file mode 100644
index 0000000..9e13223
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-ko/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">"%s Wi-Fi 통화"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-ky-rKG/strings.xml b/core/res/res/values-mcc310-mnc160-ky-rKG/strings.xml
new file mode 100644
index 0000000..8b88ac1
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-ky-rKG/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">"%s Wi-Fi чалуу"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-lo-rLA/strings.xml b/core/res/res/values-mcc310-mnc160-lo-rLA/strings.xml
new file mode 100644
index 0000000..a5347a9
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-lo-rLA/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">"ການ​ໂທ %s Wi-Fi"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-lt/strings.xml b/core/res/res/values-mcc310-mnc160-lt/strings.xml
new file mode 100644
index 0000000..81b7488
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-lt/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">"Jei norite skambinti ir siųsti pranešimus „Wi-Fi“ ryšiu, pirmiausia paprašykite operatoriaus nustatyti šią paslaugą. Tada vėl įjunkite skambinimą „Wi-Fi“ ryšiu „Nustatymų“ skiltyje."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Užregistruokite pas operatorių"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"„%s“ „Wi-Fi“ skambinimas"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-lv/strings.xml b/core/res/res/values-mcc310-mnc160-lv/strings.xml
new file mode 100644
index 0000000..5d24c5f
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-lv/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">"Lai veiktu zvanus un sūtītu īsziņas Wi-Fi tīklā, vispirms lūdziet mobilo sakaru operatoru iestatīt šo pakalpojumu. Pēc tam iestatījumos vēlreiz ieslēdziet Wi-Fi zvanus."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Reģistrēt to pie sava mobilo sakaru operatora"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s Wi-Fi zvani"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-mk-rMK/strings.xml b/core/res/res/values-mcc310-mnc160-mk-rMK/strings.xml
new file mode 100644
index 0000000..aea280e
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-mk-rMK/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">"%s Повикување преку Wi-Fi"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-ml-rIN/strings.xml b/core/res/res/values-mcc310-mnc160-ml-rIN/strings.xml
new file mode 100644
index 0000000..9e244eb
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-ml-rIN/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">"വൈഫൈ വഴി കോളുകൾ വിളിക്കാനും സന്ദേശങ്ങൾ അയയ്‌ക്കാനും ആദ്യം നിങ്ങളുടെ കാരിയറോട് ഈ സേവനം സജ്ജമാക്കാൻ ആവശ്യപ്പെടുക. ക്രമീകരണത്തിൽ നിന്ന് വീണ്ടും വൈഫൈ കോളിംഗ് ഓണാക്കുക."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"നിങ്ങളുടെ കാരിയറിൽ രജിസ്റ്റർ ചെയ്യുക"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s വൈഫൈ കോളിംഗ്"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-mn-rMN/strings.xml b/core/res/res/values-mcc310-mnc160-mn-rMN/strings.xml
new file mode 100644
index 0000000..5b59d99
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-mn-rMN/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">"%s Wi-Fi Дуудлага"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-mr-rIN/strings.xml b/core/res/res/values-mcc310-mnc160-mr-rIN/strings.xml
new file mode 100644
index 0000000..168c36b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-mr-rIN/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">"वाय-फायवरून कॉल करण्यासाठी आणि संदेश पाठविण्यासाठी, प्रथम आपल्या वाहकास ही सेवा सेट करण्यास सांगा. नंतर सेटिंग्जमधून पुन्हा वाय-फाय कॉलिंग चालू करा."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"आपल्या वाहकासह नोंदणी करा"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s वाय-फाय कॉलिंग"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-ms-rMY/strings.xml b/core/res/res/values-mcc310-mnc160-ms-rMY/strings.xml
new file mode 100644
index 0000000..74bd9d6
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-ms-rMY/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">"Untuk membuat panggilan dan menghantar mesej melalui Wi-Fi, mula-mula minta pembawa anda menyediakan perkhidmatan ini. Kemudian hidupkan panggilan Wi-Fi sekali lagi daripada Tetapan."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Daftar dengan pembawa anda"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"Panggilan Wi-Fi %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-my-rMM/strings.xml b/core/res/res/values-mcc310-mnc160-my-rMM/strings.xml
new file mode 100644
index 0000000..ae87ae7
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-my-rMM/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">"ဝိုင်ဖိုင်သုံး၍ ဖုန်းခေါ်ဆိုရန်နှင့် မက်စေ့ဂျ်များပို့ရန်၊ ဤဝန်ဆောင်မှုအား စတင်သုံးနိုင်ရန်အတွက် သင့် မိုဘိုင်းဝန်ဆောင်မှုအား ဦးစွာမေးမြန်းပါ။ ထို့နောက် ဆက်တင်မှတဆင့် ဝိုင်ဖိုင် ခေါ်ဆိုမှုအား ထပ်ဖွင့်ပါ။"</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"သင့် မိုဘိုင်းဝန်ဆောင်မှုဖြင့် မှတ်ပုံတင်ရန်"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s ဝိုင်ဖိုင် ခေါ်ဆိုမှု"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-nb/strings.xml b/core/res/res/values-mcc310-mnc160-nb/strings.xml
new file mode 100644
index 0000000..34357e1
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-nb/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">"For å ringe og sende meldinger over Wi-Fi må du først be operatøren om å konfigurere denne tjenesten. Deretter slår du på Wi-Fi-anrop igjen fra Innstillinger."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Registrer deg hos operatøren din"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s Wi-Fi-anrop"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-ne-rNP/strings.xml b/core/res/res/values-mcc310-mnc160-ne-rNP/strings.xml
new file mode 100644
index 0000000..8956249
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-ne-rNP/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">"%s Wi-Fi कलिङ"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-nl/strings.xml b/core/res/res/values-mcc310-mnc160-nl/strings.xml
new file mode 100644
index 0000000..319f799
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-nl/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">"Als je wilt bellen en berichten wilt verzenden via wifi, moet je eerst je provider vragen deze service in te stellen. Schakel bellen via wifi vervolgens opnieuw in via \'Instellingen\'."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Registreren bij je provider"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"Bellen via wifi van %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-pa-rIN/strings.xml b/core/res/res/values-mcc310-mnc160-pa-rIN/strings.xml
new file mode 100644
index 0000000..5641abe
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-pa-rIN/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">"%s Wi-Fi ਕਾਲਿੰਗ"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-pl/strings.xml b/core/res/res/values-mcc310-mnc160-pl/strings.xml
new file mode 100644
index 0000000..1d916cb
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-pl/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">"Aby dzwonić i wysyłać wiadomości przez Wi-Fi, poproś swojego operatora o skonfigurowanie tej usługi. Potem ponownie włącz połączenia przez Wi-Fi w Ustawieniach."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Zarejestruj u operatora"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"Połączenia przez Wi-Fi (%s)"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-pt-rBR/strings.xml b/core/res/res/values-mcc310-mnc160-pt-rBR/strings.xml
new file mode 100644
index 0000000..1c68cb1
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-pt-rBR/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">"Para fazer chamadas e enviar mensagens por Wi-Fi, primeiro peça à sua operadora para configurar esse serviço. Depois ative novamente as chamadas por Wi-Fi nas configurações."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Faça registro na sua operadora"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s chamada Wi-Fi"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-pt-rPT/strings.xml b/core/res/res/values-mcc310-mnc160-pt-rPT/strings.xml
new file mode 100644
index 0000000..86dba8c
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-pt-rPT/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">"Para fazer chamadas e enviar mensagens por Wi-Fi, comece por pedir ao seu operador para configurar este serviço. Em seguida, nas Definições, ative novamente as Chamadas Wi-Fi."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Registar-se junto do seu operador"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"Chamadas Wi-Fi da %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-pt/strings.xml b/core/res/res/values-mcc310-mnc160-pt/strings.xml
new file mode 100644
index 0000000..1c68cb1
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-pt/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">"Para fazer chamadas e enviar mensagens por Wi-Fi, primeiro peça à sua operadora para configurar esse serviço. Depois ative novamente as chamadas por Wi-Fi nas configurações."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Faça registro na sua operadora"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s chamada Wi-Fi"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-ro/strings.xml b/core/res/res/values-mcc310-mnc160-ro/strings.xml
new file mode 100644
index 0000000..f2490d8
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-ro/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">"Pentru a apela și a trimite mesaje prin Wi-Fi, mai întâi solicitați configurarea acestui serviciu la operator. Apoi, activați din nou apelarea prin Wi-Fi din Setări."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Înregistrați-vă la operatorul dvs."</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"Apelare prin Wi-Fi %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-ru/strings.xml b/core/res/res/values-mcc310-mnc160-ru/strings.xml
new file mode 100644
index 0000000..9f2bc43
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-ru/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, необходимо сначала обратиться к оператору связи и подключить эту услугу. После этого вы сможете снова выбрать этот параметр в настройках."</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-si-rLK/strings.xml b/core/res/res/values-mcc310-mnc160-si-rLK/strings.xml
new file mode 100644
index 0000000..0c13341
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-si-rLK/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">"%s Wi-Fi අමතමින්"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-sk/strings.xml b/core/res/res/values-mcc310-mnc160-sk/strings.xml
new file mode 100644
index 0000000..3fe32f7
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-sk/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">"Ak chcete volať a odosielať správy prostredníctvom siete Wi-Fi, kontaktujte najskôr svojho operátora v súvislosti s nastavením tejto služby. Potom opäť zapnite v Nastaveniach volanie cez Wi-Fi."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Registrujte sa so svojím operátorom"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"Volanie siete Wi-Fi %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-sl/strings.xml b/core/res/res/values-mcc310-mnc160-sl/strings.xml
new file mode 100644
index 0000000..3818309
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-sl/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">"Če želite klicati ali pošiljati sporočila prek omrežja Wi-Fi, se najprej obrnite na operaterja, da nastavi to storitev. Nato v nastavitvah znova vklopite klicanje prek omrežja Wi-Fi."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Registracija pri operaterju"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"Klicanje prek Wi-Fi-ja (%s)"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-sq-rAL/strings.xml b/core/res/res/values-mcc310-mnc160-sq-rAL/strings.xml
new file mode 100644
index 0000000..647cd03
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-sq-rAL/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">"Për të bërë telefonata dhe për të dërguar mesazhe me Wi-Fi, në fillim kërkoji operatorit celular ta konfigurojë këtë shërbim. Më pas aktivizo përsëri telefonatat me Wi-Fi, nga Cilësimet."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Regjistrohu me operatorin tënd celular"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"Telefonatat me Wi-Fi nga %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-sr/strings.xml b/core/res/res/values-mcc310-mnc160-sr/strings.xml
new file mode 100644
index 0000000..7f8381a
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-sr/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-sv/strings.xml b/core/res/res/values-mcc310-mnc160-sv/strings.xml
new file mode 100644
index 0000000..e72b3b7
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-sv/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">"Om du vill ringa samtal och skicka meddelanden via Wi-Fi ber du först operatören att konfigurera tjänsten. Därefter kan du aktivera Wi-Fi-samtal på nytt från Inställningar."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Registrera dig hos operatören"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s Wi-Fi-samtal"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-sw/strings.xml b/core/res/res/values-mcc310-mnc160-sw/strings.xml
new file mode 100644
index 0000000..08ee7536
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-sw/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">"Ili upige simu na kutuma ujumbe kupitia Wi-Fi, mwambie mtoa huduma wako asanidi huduma hii kwanza. Kisha uwashe tena upigaji simu kwa Wi-Fi kutoka kwenye Mipangilio."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Jisajili na mtoa huduma wako"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s Upigaji Simu kwa Wi-Fi"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-ta-rIN/strings.xml b/core/res/res/values-mcc310-mnc160-ta-rIN/strings.xml
new file mode 100644
index 0000000..d6ea49c
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-ta-rIN/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">"வைஃபை மூலம் அழைக்க மற்றும் செய்திகள் அனுப்ப, முதலில் மொபைல் நிறுவனத்திடம் இந்தச் சேவையை அமைக்குமாறு கேட்கவும். பிறகு அமைப்புகளில் மீண்டும் வைஃபை அழைப்பை இயக்கவும்."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"உங்கள் மொபைல் நிறுவனத்தில் பதிவுசெய்யவும்"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s வைஃபை அழைப்பு"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-te-rIN/strings.xml b/core/res/res/values-mcc310-mnc160-te-rIN/strings.xml
new file mode 100644
index 0000000..61f3929
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-te-rIN/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">"%s Wi-Fi కాలింగ్"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-th/strings.xml b/core/res/res/values-mcc310-mnc160-th/strings.xml
new file mode 100644
index 0000000..f1ff305
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-th/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-tl/strings.xml b/core/res/res/values-mcc310-mnc160-tl/strings.xml
new file mode 100644
index 0000000..380b410
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-tl/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">"Upang tumawag at magpadala ng mga mensahe sa pamamagitan ng Wi-Fi, hilingin muna sa iyong carrier na i-set up ang serbisyong ito. Pagkatapos ay muling i-on ang pagtawag gamit ang Wi-Fi mula sa Mga Setting."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Magparehistro sa iyong carrier"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"Pagtawag Gamit ang Wi-Fi ng %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-tr/strings.xml b/core/res/res/values-mcc310-mnc160-tr/strings.xml
new file mode 100644
index 0000000..2cb1dc9
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-tr/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">"Kablosuz ağ üzerinden telefon etmek ve ileti göndermek için ilk önce operatörünüzden bu hizmeti ayarlamasını isteyin. Sonra tekrar Ayarlar\'dan Kablosuz çağrı özelliğini açın."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Operatörünüze kaydolun"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s Kablosuz Çağrı"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-uk/strings.xml b/core/res/res/values-mcc310-mnc160-uk/strings.xml
new file mode 100644
index 0000000..9e4d94c
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-uk/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-ur-rPK/strings.xml b/core/res/res/values-mcc310-mnc160-ur-rPK/strings.xml
new file mode 100644
index 0000000..e617582
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-ur-rPK/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">"‏‎%s Wi-Fi کالنگ"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-uz-rUZ/strings.xml b/core/res/res/values-mcc310-mnc160-uz-rUZ/strings.xml
new file mode 100644
index 0000000..a951fc4
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-uz-rUZ/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 orqali qo‘ng‘iroqlarni amalga oshirish va xabarlar bilan almashinish uchun uyali aloqa operatoringizdan ushbu xizmatni yoqib qo‘yishni so‘rashingiz lozim. Keyin sozlamalarda Wi-Fi qo‘ng‘irog‘i imkoniyatini yoqib olishingiz mumkin."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Mobil operatoringiz yordamida ro‘yxatdan o‘ting"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s Wi-Fi qo‘ng‘iroqlar"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-vi/strings.xml b/core/res/res/values-mcc310-mnc160-vi/strings.xml
new file mode 100644
index 0000000..8f68be6
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-vi/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">"Để gọi điện và gửi tin nhắn qua Wi-Fi, trước tiên hãy yêu cầu nhà cung cấp dịch vụ của bạn thiết lập dịch vụ này. Sau đó, bật lại Gọi qua Wi-Fi từ Cài đặt."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Đăng ký với nhà cung cấp dịch vụ của bạn"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"Gọi qua Wi-Fi %s"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-zh-rCN/strings.xml b/core/res/res/values-mcc310-mnc160-zh-rCN/strings.xml
new file mode 100644
index 0000000..3b10a63
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-zh-rCN/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">"要通过 WLAN 打电话和发信息,请先让您的运营商开通此服务,然后再到“设置”中重新开启 WLAN 通话功能。"</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"向您的运营商注册"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s WLAN 通话功能"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-zh-rHK/strings.xml b/core/res/res/values-mcc310-mnc160-zh-rHK/strings.xml
new file mode 100644
index 0000000..a39b37c
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-zh-rHK/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">"%s Wi-Fi 通話"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-zh-rTW/strings.xml b/core/res/res/values-mcc310-mnc160-zh-rTW/strings.xml
new file mode 100644
index 0000000..28690aa
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-zh-rTW/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">"%s Wi-Fi 通話"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160-zu/strings.xml b/core/res/res/values-mcc310-mnc160-zu/strings.xml
new file mode 100644
index 0000000..d08486d
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160-zu/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">"Ukuze wenze amakholi uphinde uthumele imilayezo nge-Wi-Fi, qala ucele inkampani yakho yenethiwekhi ukuthi isethe le divayisi. Bese uvula ukushaya kwe-Wi-Fi futhi kusukela kuzilungiselelo."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="7068215934335709161">"Bhalisa ngenkampani yakho yenethiwekhi"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="2031160810542298336">"%s ukushaya kwe-Wi-Fi"</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc160/strings.xml b/core/res/res/values-mcc310-mnc160/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc160/strings.xml
@@ -0,0 +1,38 @@
+<?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:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- WFC Operator Error Codes -->
+    <string-array name="wfcOperatorErrorCodes" translatable="false">
+        <item>REG09</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as alerts -->
+    <string-array name="wfcOperatorErrorAlertMessages">
+        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as notifications -->
+    <string-array name="wfcOperatorErrorNotificationMessages">
+        <item>Register with your carrier</item>
+    </string-array>
+    <!-- Template for showing cellular network operator name while WFC is active -->
+    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc200/strings.xml b/core/res/res/values-mcc310-mnc200/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc200/strings.xml
@@ -0,0 +1,38 @@
+<?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:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- WFC Operator Error Codes -->
+    <string-array name="wfcOperatorErrorCodes" translatable="false">
+        <item>REG09</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as alerts -->
+    <string-array name="wfcOperatorErrorAlertMessages">
+        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as notifications -->
+    <string-array name="wfcOperatorErrorNotificationMessages">
+        <item>Register with your carrier</item>
+    </string-array>
+    <!-- Template for showing cellular network operator name while WFC is active -->
+    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc210/strings.xml b/core/res/res/values-mcc310-mnc210/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc210/strings.xml
@@ -0,0 +1,38 @@
+<?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:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- WFC Operator Error Codes -->
+    <string-array name="wfcOperatorErrorCodes" translatable="false">
+        <item>REG09</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as alerts -->
+    <string-array name="wfcOperatorErrorAlertMessages">
+        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as notifications -->
+    <string-array name="wfcOperatorErrorNotificationMessages">
+        <item>Register with your carrier</item>
+    </string-array>
+    <!-- Template for showing cellular network operator name while WFC is active -->
+    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc220/strings.xml b/core/res/res/values-mcc310-mnc220/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc220/strings.xml
@@ -0,0 +1,38 @@
+<?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:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- WFC Operator Error Codes -->
+    <string-array name="wfcOperatorErrorCodes" translatable="false">
+        <item>REG09</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as alerts -->
+    <string-array name="wfcOperatorErrorAlertMessages">
+        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as notifications -->
+    <string-array name="wfcOperatorErrorNotificationMessages">
+        <item>Register with your carrier</item>
+    </string-array>
+    <!-- Template for showing cellular network operator name while WFC is active -->
+    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc230/strings.xml b/core/res/res/values-mcc310-mnc230/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc230/strings.xml
@@ -0,0 +1,38 @@
+<?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:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- WFC Operator Error Codes -->
+    <string-array name="wfcOperatorErrorCodes" translatable="false">
+        <item>REG09</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as alerts -->
+    <string-array name="wfcOperatorErrorAlertMessages">
+        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as notifications -->
+    <string-array name="wfcOperatorErrorNotificationMessages">
+        <item>Register with your carrier</item>
+    </string-array>
+    <!-- Template for showing cellular network operator name while WFC is active -->
+    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc240/strings.xml b/core/res/res/values-mcc310-mnc240/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc240/strings.xml
@@ -0,0 +1,38 @@
+<?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:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- WFC Operator Error Codes -->
+    <string-array name="wfcOperatorErrorCodes" translatable="false">
+        <item>REG09</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as alerts -->
+    <string-array name="wfcOperatorErrorAlertMessages">
+        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as notifications -->
+    <string-array name="wfcOperatorErrorNotificationMessages">
+        <item>Register with your carrier</item>
+    </string-array>
+    <!-- Template for showing cellular network operator name while WFC is active -->
+    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc250/strings.xml b/core/res/res/values-mcc310-mnc250/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc250/strings.xml
@@ -0,0 +1,38 @@
+<?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:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- WFC Operator Error Codes -->
+    <string-array name="wfcOperatorErrorCodes" translatable="false">
+        <item>REG09</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as alerts -->
+    <string-array name="wfcOperatorErrorAlertMessages">
+        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as notifications -->
+    <string-array name="wfcOperatorErrorNotificationMessages">
+        <item>Register with your carrier</item>
+    </string-array>
+    <!-- Template for showing cellular network operator name while WFC is active -->
+    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc260-de/strings.xml b/core/res/res/values-mcc310-mnc260-de/strings.xml
index 3994bba..b9cbb48 100644
--- a/core/res/res/values-mcc310-mnc260-de/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-de/strings.xml
@@ -23,10 +23,10 @@
 <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">"Um über WLAN telefonieren und Nachrichten senden zu können, bitten Sie zuerst Ihren Mobilfunkanbieter, diesen Dienst einzurichten. Aktivieren Sie die Option \"Anrufe über WLAN\" dann erneut über die Einstellungen."</item>
+    <item msgid="7239039348648848288">"Um über WLAN telefonieren und Nachrichten senden zu können, bitte zuerst deinen Mobilfunkanbieter, diesen Dienst einzurichten. Aktiviere die Option \"Anrufe über WLAN\" dann erneut über die Einstellungen."</item>
   </string-array>
   <string-array name="wfcOperatorErrorNotificationMessages">
-    <item msgid="483847327467331298">"Registrieren Sie sich bei Ihrem Mobilfunkanbieter."</item>
+    <item msgid="483847327467331298">"Registriere dich bei deinem Mobilfunkanbieter."</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Anrufe über WLAN"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc270/strings.xml b/core/res/res/values-mcc310-mnc270/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc270/strings.xml
@@ -0,0 +1,38 @@
+<?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:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- WFC Operator Error Codes -->
+    <string-array name="wfcOperatorErrorCodes" translatable="false">
+        <item>REG09</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as alerts -->
+    <string-array name="wfcOperatorErrorAlertMessages">
+        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as notifications -->
+    <string-array name="wfcOperatorErrorNotificationMessages">
+        <item>Register with your carrier</item>
+    </string-array>
+    <!-- Template for showing cellular network operator name while WFC is active -->
+    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc310/strings.xml b/core/res/res/values-mcc310-mnc310/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc310/strings.xml
@@ -0,0 +1,38 @@
+<?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:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- WFC Operator Error Codes -->
+    <string-array name="wfcOperatorErrorCodes" translatable="false">
+        <item>REG09</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as alerts -->
+    <string-array name="wfcOperatorErrorAlertMessages">
+        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as notifications -->
+    <string-array name="wfcOperatorErrorNotificationMessages">
+        <item>Register with your carrier</item>
+    </string-array>
+    <!-- Template for showing cellular network operator name while WFC is active -->
+    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc490/strings.xml b/core/res/res/values-mcc310-mnc490/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc490/strings.xml
@@ -0,0 +1,38 @@
+<?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:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- WFC Operator Error Codes -->
+    <string-array name="wfcOperatorErrorCodes" translatable="false">
+        <item>REG09</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as alerts -->
+    <string-array name="wfcOperatorErrorAlertMessages">
+        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as notifications -->
+    <string-array name="wfcOperatorErrorNotificationMessages">
+        <item>Register with your carrier</item>
+    </string-array>
+    <!-- Template for showing cellular network operator name while WFC is active -->
+    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc660/strings.xml b/core/res/res/values-mcc310-mnc660/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc660/strings.xml
@@ -0,0 +1,38 @@
+<?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:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- WFC Operator Error Codes -->
+    <string-array name="wfcOperatorErrorCodes" translatable="false">
+        <item>REG09</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as alerts -->
+    <string-array name="wfcOperatorErrorAlertMessages">
+        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as notifications -->
+    <string-array name="wfcOperatorErrorNotificationMessages">
+        <item>Register with your carrier</item>
+    </string-array>
+    <!-- Template for showing cellular network operator name while WFC is active -->
+    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mcc310-mnc800/strings.xml b/core/res/res/values-mcc310-mnc800/strings.xml
new file mode 100644
index 0000000..526d08b
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc800/strings.xml
@@ -0,0 +1,38 @@
+<?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:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- WFC Operator Error Codes -->
+    <string-array name="wfcOperatorErrorCodes" translatable="false">
+        <item>REG09</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as alerts -->
+    <string-array name="wfcOperatorErrorAlertMessages">
+        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as notifications -->
+    <string-array name="wfcOperatorErrorNotificationMessages">
+        <item>Register with your carrier</item>
+    </string-array>
+    <!-- Template for showing cellular network operator name while WFC is active -->
+    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
+</resources>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index 5c12a36..14fe940 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Извештај за грешка"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Земи извештај за грешки"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Ова ќе собира информации за моменталната состојба на вашиот уред, за да ги испрати како порака по е-пошта. Тоа ќе одземе малку време почнувајќи од извештајот за грешки додека не се подготви за праќање; бидете трпеливи."</string>
+    <string name="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 />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">Ќе се направи слика од екранот за извештајот за грешки за <xliff:g id="NUMBER_1">%d</xliff:g> секунда.</item>
+      <item quantity="other">Ќе се направи слика од екранот за извештајот за грешки за <xliff:g id="NUMBER_1">%d</xliff:g> секунди.</item>
+    </plurals>
     <string name="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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"Безбеден режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Систем Android"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"Лични"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Овозможува апликацијата да прави фотографии и да снима видеа со камерата. Оваа дозвола овозможува апликацијата да ја користи камерата во кое било време без ваша потврда."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"контролирај вибрации"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Дозволува апликацијата да ги контролира вибрациите."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"контролирај сијаличка"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Дозволува апликацијата да ја контролира батериската ламба."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"директно избирај телефонски броеви"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Овозможува апликацијата да повикува телефонски броеви без ваша интервенција. Ова може да предизвика неочекувани трошоци или повици. Имајте на ум дека ова не дозволува апликацијата да повикува броеви на служби за итна помош. Злонамерните апликации може да ве чинат пари поради повици без ваша потврда."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"пристапи до услугата за повици IMS"</string>
@@ -858,10 +868,13 @@
     <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">"Копирај УРЛ"</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">"Избриши"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Да се сподели извештајот за грешки со администраторот?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Вашиот ИТ-администратор побара извештај за грешки за да помогне со отстранување на грешките"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ПРИФАТИ"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ОДБИЈ"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Се зема извештајот за грешки…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Допрете за да откажете"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Измени тастатура"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"Избери тастатури"</string>
-    <string name="show_ime" msgid="9157568568695230830">"Прикажи влезен метод"</string>
-    <string name="hardware" msgid="7517821086888990278">"Хардвер"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Промени тапет"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Слушател на известувања"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Давател на услов"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Помошник за известувања"</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>
@@ -1250,7 +1270,7 @@
     <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_chooser_extended_settings" msgid="87015534236701604">"Поставки"</string>
     <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Исклучи"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Скенирање..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Се поврзува..."</string>
@@ -1442,12 +1462,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"Важност"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Блокирано: никогаш не покажувај ги овие известувања"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Ниско: покажувај ги тивко на дното на списокот со известувања"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Нормално: покажувај ги овие известувања тивко"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Високо: покажувај ги на врв на списокот со известувања и дај звук"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Итно: нека се појават на екранот и дај им звук"</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="other">За %1$d минути (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1515,4 +1529,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"Разно"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"Ја поставивте важноста на известувањава."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ова е важно заради луѓето кои се вклучени."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" се обидува да додаде нов корисник, но во моментов е забрането."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" се обидува да додаде нов корисник, но ограничувањето за корисници е достигнато."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" се обидува да додаде нов корисник, но сметката "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" веќе постои на уредот. Сепак продолжете?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" се обидува да додаде нов корисник за сметката "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Продолжете?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Претпочитувања за јазик"</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>
 </resources>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index 842ee4a..ce3c32f 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"ബഗ് റിപ്പോർട്ട്"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"ബഗ് റിപ്പോർട്ട് എടുക്കുക"</string>
     <string name="bugreport_message" msgid="398447048750350456">"ഒരു ഇമെയിൽ സന്ദേശമായി അയയ്‌ക്കുന്നതിന്, ഇത് നിങ്ങളുടെ നിലവിലെ ഉപകരണ നിലയെക്കുറിച്ചുള്ള വിവരങ്ങൾ ശേഖരിക്കും. ബഗ് റിപ്പോർട്ട് ആരംഭിക്കുന്നതിൽ നിന്ന് ഇത് അയയ്‌ക്കാനായി തയ്യാറാകുന്നതുവരെ അൽപ്പസമയമെടുക്കും; ക്ഷമയോടെ കാത്തിരിക്കുക."</string>
+    <string name="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 />
+    <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>
+    </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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"സുരക്ഷിത മോഡ്"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android സിസ്റ്റം"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"വ്യക്തിഗതം"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ക്യാമറ ഉപയോഗിച്ച് ചിത്രങ്ങളും വീഡിയോകളും എടുക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. നിങ്ങളുടെ സ്ഥിരീകരണമില്ലാതെ ഏതുസമയത്തും ക്യാമറ ഉപയോഗിക്കാൻ ഈ അനുമതി അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"വൈബ്രേറ്റുചെയ്യൽ നിയന്ത്രിക്കുക"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"വൈബ്രേറ്റർ നിയന്ത്രിക്കുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ടോർച്ച് നിയന്ത്രിക്കുക"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"ഫ്ലാഷ്ലൈറ്റിനെ നിയന്ത്രിക്കുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ഫോൺ നമ്പറുകളിലേക്ക് നേരിട്ട് വിളിക്കുക"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"നിങ്ങളുടെ ഇടപെടൽ ഇല്ലാതെ ഫോൺ നമ്പറുകളിലേക്ക് കോൾ ചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഇത് അപ്രതീക്ഷിത നിരക്കുകൾക്കോ കോളുകൾക്കോ ഇടയാക്കാം. ഇത് അടിയന്തര നമ്പറുകളിലേക്ക് വിളിക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കില്ലെന്ന കാര്യം ശ്രദ്ധിക്കുക. ക്ഷുദ്രകരമായ അപ്ലിക്കേഷനുകൾ നിങ്ങളുടെ സ്ഥിരീകരണമില്ലാതെ കോളുകൾ ചെയ്യുന്നത് പണച്ചെലവിനിടയാക്കാം."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS കോൾ സേവനം ആക്സസ് ചെയ്യുക"</string>
@@ -858,10 +868,13 @@
     <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">"ഇല്ലാതാക്കുക"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"അഡ്‌മിനുമായി ബഗ് റിപ്പോർട്ട് പങ്കിടണോ?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"പ്രശ്നം പരിഹരിക്കുന്നതിന് നിങ്ങളുടെ ഐടി അഡ്‌മിൻ ഒരു ബഗ് റിപ്പോർട്ട് അഭ്യർത്ഥിച്ചു"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"അംഗീകരിക്കുക"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"നിരസിക്കുക"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"ബഗ് റിപ്പോർട്ട് എടുക്കുന്നു…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"റദ്ദാക്കുന്നതിന് സ്പർശിക്കുക"</string>
     <string name="select_input_method" msgid="8547250819326693584">"കീബോഡ് മാറ്റുക"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"കീബോർഡുകൾ തിരഞ്ഞെടുക്കുക"</string>
-    <string name="show_ime" msgid="9157568568695230830">"ടൈപ്പുചെയ്യൽ രീതി കാണിക്കുക"</string>
-    <string name="hardware" msgid="7517821086888990278">"ഹാർഡ്‌വെയർ"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"വാൾപേപ്പർ മാറ്റുക"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"അറിയിപ്പ് ലിസണർ"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"കണ്ടീഷൻ ദാതാവ്"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"അറിയിപ്പ് സഹായി"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"പ്രാധാന്യം"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"ബ്ലോക്കുചെയ്തു: ഈ അറിയിപ്പുകൾ ഒരിക്കലും കാണിക്കരുത്"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"താഴ്ന്നത്: അറിയിപ്പ് ലിസ്റ്റിന്റെ താഴെ ശബ്ദമുണ്ടാക്കാതെ കാണിക്കുക"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"സാധാരണം: ഈ അറിയിപ്പുകൾ നിശബ്ദമായി കാണിക്കുക"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"ഉയർന്നത്: അറിയിപ്പ് ലിസ്റ്റിന്റെ ഏറ്റവും മുകളിൽ കാണിക്കുക, ശബ്ദമുണ്ടാക്കുക"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"അടിയന്തരം: സ്ക്രീനിൽ ദൃശ്യമാക്കുക, ശബ്ദമുണ്ടാക്കുക"</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">ഒരു മിനിറ്റ് സമയത്തേക്ക് (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> വരെ)</item>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"പലവക"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"ഈ അറിയിപ്പുകളുടെ പ്രാധാന്യം നിങ്ങൾ സജ്ജീകരിച്ചു."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ഉൾപ്പെട്ടിട്ടുള്ള ആളുകളെ കണക്കിലെടുക്കുമ്പോള്‍ ഇത് പ്രധാനപ്പെട്ടതാണ്‌."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315">"പുതിയൊരു ഉപയോക്താവിനെ ചേർക്കാൻ "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ശ്രമിക്കുന്നു, എന്നാലിത് നിലവിൽ നിരോധിക്കപ്പെട്ടിരിക്കുന്നു."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266">"പുതിയൊരു ഉപയോക്താവിനെ ചേർക്കാൻ "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ശ്രമിക്കുന്നു, എന്നാൽ ഉപയോക്തൃ പരിധി എത്തിക്കഴിഞ്ഞിരിക്കുന്നു."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789">"പുതിയൊരു ഉപയോക്താവിനെ ചേർക്കാൻ "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ശ്രമിക്കുന്നു, എന്നാൽ "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" എന്ന അക്കൗണ്ട് ഇതിനകം തന്നെ ഈ ഉപകരണത്തിൽ നിലവിലുണ്ട്. എന്തായാലും തുടരണോ?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" എന്ന അക്കൗണ്ടിനായി പുതിയൊരു ഉപയോക്താവിനെ ചേർക്കാൻ "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ശ്രമിക്കുന്നു. തുടരണോ?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"ഭാഷാ മുൻഗണന"</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>
 </resources>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index bdfbe7a..08233f8 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Алдаа мэдээллэх"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Согог репорт авах"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Энэ таны төхөөрөмжийн одоогийн статусын талаарх мэдээллийг цуглуулах ба имэйл мессеж болгон илгээнэ. Алдааны мэдэгдлээс эхэлж илгээхэд бэлэн болоход хэсэг хугацаа зарцуулагдана тэвчээртэй байна уу."</string>
+    <string name="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 />
+    <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>
+    </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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"Аюулгүй горим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Андройд систем"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"Хувийн"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Апп нь камераар зураг авах болон видео бичих боломжтой. Энэ зөвшөөрөл нь апп-д ямар ч үед таны зөвшөөрөлгүйгээр камер ашиглах боломжийг олгоно."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"чичиргээг удирдах"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Апп нь чичиргээг удирдах боломжтой."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"гар чийдэн удирдах"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Апп нь гар чийдэнг удирдах боломжтой."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"утасны дугаарт шууд дуудлага хийх"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Апп нь таны оролцоогүйгээр дуудлага хийх боломжтой. Энэ нь төлөвлөгдөөгүй төлбөрт оруулах эсвэл дуудлага хийнэ. Энэ нь апп-г яаралтай дугаарт дуудлага хийхйг зөвшөөрөхгүй. Хортой апп нь таны зөвшөөрөлгүйгээр дуудлага хийж таныг төлбөрт оруулж болзошгүй"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS дуудлагын үйлчилгээнд хандах"</string>
@@ -858,10 +868,13 @@
     <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">"Устгах"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Алдааны тайланг админтай хуваалцах уу?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Асуудлыг шийдвэрлэхийн таны МТ админтулд алдааны тайланг хүслээ"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ЗӨВШӨӨРӨХ"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ТАТГАЛЗАХ"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Алдааны тайланг авч байна..."</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Цуцлахын тулд хүрэх"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Гарыг өөрчлөх"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"Гар сонгох"</string>
-    <string name="show_ime" msgid="9157568568695230830">"Оруулах аргыг харуулах"</string>
-    <string name="hardware" msgid="7517821086888990278">"Хардвер"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Ханын зураг солих"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Мэдэгдэл сонсогч"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Нөхцөл нийлүүлэгч"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Мэдэгдлийн туслагч"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"Ач холбогдол"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Блоклосон: Эдгээр мэдэгдлийг хэзээ ч харуулахгүй"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Бага: Мэдэгдлийг жагсаалтын доод хэсэгт дуугүй харуулах"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Ердийн: Эдгээр мэдэгдлийг дуугүй харуулах"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Өндөр: мэдэгдлийг жагсаалтын эхэнд дуутай харуулах"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Яаралтай: Дэлгэцэнд яаралтай, дуутай гаргах"</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">нэг минутын турш (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> хүртэл)</item>
@@ -1511,4 +1525,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"Бусад"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"Та эдгээр мэдэгдлийн ач холбогдлыг тогтоосон."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Оролцсон хүмүүсээс шалтгаалан энэ нь өндөр ач холбогдолтой."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" шинэ хэрэглэгч нэмэхээр оролдож байгаа боловч одоогоор боломжгүй байна."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" шинэ хэрэглэгч нэмэхээр оролдож байгаа ч хэрэглэгчийн тооны хязгаарт хүрсэн байна."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" шинэ хэрэглэгч нэмэх гэсэн боловч "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" бүртгэл нь энэ төхөөрөмжид аль хэдийн бүртгэгдсэн байна. Үргэлжлүүлэх үү?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" нь "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" бүртгэлд шинэ хэрэглэгч нэмэх гэж байна. Үргэлжлүүлэх үү?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Хэлний тохиргоо"</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>
 </resources>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index c323b85..30edff7 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"दोष अहवाल"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"दोष अहवाल घ्या"</string>
     <string name="bugreport_message" msgid="398447048750350456">"ई-मेल संदेश म्हणून पाठविण्यासाठी, हे आपल्या वर्तमान डिव्हाइस स्थितीविषयी माहिती संकलित करेल. दोष अहवाल प्रारंभ करण्यापासून तो पाठविण्यापर्यंत थोडा वेळ लागेल; कृपया धीर धरा."</string>
+    <string name="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 />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">दोष अहवालासाठी <xliff:g id="NUMBER_1">%d</xliff:g> सेकंदामध्‍ये स्क्रीनशॉट घेत आहे.</item>
+      <item quantity="other">दोष अहवालासाठी <xliff:g id="NUMBER_1">%d</xliff:g> सेकंदांमध्‍ये स्क्रीनशॉट घेत आहे.</item>
+    </plurals>
     <string name="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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android सिस्‍टम"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"वैयक्तिक"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"कॅमेर्‍यासह चित्रे आणि व्हिडिओ घेण्यासाठी अॅप ला अनुमती देते. ही परवानगी आपल्या पुष्टीकरणाशिवाय कोणत्याही वेळी कॅमेरा वापरण्यासाठी अॅप ला परवानगी देते."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"कंपन नियंत्रित करा"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"अॅप ला व्हायब्रेटर नियंत्रित करण्यासाठी अनुमती देते."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"फ्लॅशलाइट नियंत्रित करा"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"फ्लॅशलाइट नियंत्रित करण्यासाठी अॅप ला अनुमती देते."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"फोन नंबरवर प्रत्यक्ष कॉल करा"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"आपल्या हस्तक्षेपाशिवाय फोन नंबरवर कॉल करण्यासाठी अॅप ला अनुमती देते. यामुळे अनपेक्षित शुल्क किंवा कॉल लागू शकतात. लक्षात ठेवा की हे आणीबाणीच्या नंबरवर कॉल करण्यासाठी अॅप ला अनुमती देत नाही. दुर्भावनापूर्ण अॅप्स नी आपल्या पुष्टिकरणाशिवाय कॉल केल्यामुळे आपले पैसे खर्च होऊ शकतात."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS कॉल सेवेमध्‍ये प्रवेश करा"</string>
@@ -858,10 +868,13 @@
     <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">"हटवा"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"प्रशासकासह दोष अहवाल सामायिक करायचा?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"आपल्या IT प्रशासकाने समस्या निवारण करण्‍यात मदत करण्यासाठी दोष अहवालाची विनंती केली"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"स्वीकार करा"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"नकार द्या"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"दोष अहवाल घेत आहे..."</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"रद्द करण्यासाठी स्पर्श करा"</string>
     <string name="select_input_method" msgid="8547250819326693584">"कीबोर्ड बदला"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"कीबोर्ड निवडा"</string>
-    <string name="show_ime" msgid="9157568568695230830">"इनपुट पद्धत दर्शवा"</string>
-    <string name="hardware" msgid="7517821086888990278">"हार्डवेअर"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"वॉलपेपर बदला"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"सूचना ऐकणारा"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"अट प्रदाता"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"सूचना सहाय्यक"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"महत्त्व"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"अवरोधित केले: या सूचना कधीही दर्शवू नका"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"कमी: शांतपणे सूचना सूचीच्या तळाशी दर्शवा"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"सामान्य: या सूचना शांतपणे दर्शवा"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"सर्वोच्च: सूचना सूचीच्या शीर्षस्थानी दर्शवा आणि ध्वनी चालू करा"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"त्वरित: स्क्रीनवर डोकावून पहा आणि ध्वनी चालू करा"</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="other">%1$d मिनिटांसाठी (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> पर्यंत)</item>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"संकीर्ण"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"आपण या सूचनांचे महत्त्व सेट केले."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"सामील असलेल्या लोकांमुळे हे महत्वाचे आहे."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" नवीन वापरकर्ता जोडण्याचा प्रयत्न करीत आहे परंतु तो सध्‍या प्रतिबंधित आहे."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" नवीन वापरकर्ता जोडण्यासाठी प्रयत्न करीत आहे परंतु वापरकर्ता मर्यादा गाठली गेली आहे."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" नवीन वापरकर्ता जोडण्‍याचा प्रयत्न करीत आहे परंतु या डिव्‍हाइसवर "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" खाते आधीपासून अस्तित्वात आहे. तरीही पुढे सुरु ठेवायचे?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" खात्यासाठी "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" नवीन वापरकर्ता जोडण्याचा प्रयत्न करीत आहे. पुढे सुरु ठेवायचे?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"भाषा प्राधान्य"</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>
 </resources>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 2105b90..3f1bb14 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Laporan pepijat"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Ambil laporan pepijat"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Ini akan mengumpul maklumat tentang keadaan peranti semasa anda untuk dihantarkan sebagai mesej e-mel. Harap bersabar, mungkin perlu sedikit masa untuk memulakan laporan sehingga siap untuk dihantar."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Laporan interaktif"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Gunakan laporan ini dalam kebanyakan keadaan. Anda boleh menjejak kemajuan dan memasukkan butiran lanjut tentang masalah tersebut. Laporan ini mungkin meninggalkan beberapa bahagian yang kurang digunakan, yang mengambil masa lama untuk dilaporkan."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Laporan penuh"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Mengambil tangkapan skrin untuk laporan pepijat dalam masa <xliff:g id="NUMBER_1">%d</xliff:g> saat.</item>
+      <item quantity="one">Mengambil tangkapan skrin untuk laporan pepijat dalam masa <xliff:g id="NUMBER_0">%d</xliff:g> saat.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Mod senyap"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Bunyi DIMATIKAN"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Bunyi DIHIDUPKAN"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Termasuk data peribadi seperti nombor kad kredit dan kata laluan."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Kawal pembesaran paparan"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kawal tahap zum dan kedudukan paparan."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Lakukan gerak isyarat"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Boleh ketik, leret, cubit dan laksanakan gerak isyarat lain."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"lumpuhkan atau ubah suai bar status"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Membenarkan apl melumpuhkan bar status atau menambah dan mengalih keluar ikon sistem."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"jadi bar status"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Membenarkan apl mengambil gambar dan video menggunakan kamera. Kebenaran ini membenarkan apl untuk menggunakan kamera pada bila-bila masa tanpa pengesahan anda."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"kawal getaran"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Membenarkan apl mengawal penggetar."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"mengawal lampu suluh"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Membenarkan apl mengawal lampu suluh."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"panggil terus nombor telefon"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Membenarkan apl memanggil nombor telefon tanpa campur tangan anda. Ini mungkin menyebabkan caj atau panggilan yang di luar jangkaan. Apl hasad boleh menyebabkan anda kerugian wang dengan membuat panggilan tanpa pengesahan anda."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"akses perkhidmatan panggilan IMS"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Potong"</string>
     <string name="copy" msgid="2681946229533511987">"Salin"</string>
     <string name="paste" msgid="5629880836805036433">"Tampal"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Tampal sebagai teks biasa"</string>
     <string name="replace" msgid="5781686059063148930">"Ganti..."</string>
     <string name="delete" msgid="6098684844021697789">"Padam"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Salin URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Pilih teks"</string>
+    <string name="undo" msgid="7905788502491742328">"Buat asal"</string>
+    <string name="redo" msgid="7759464876566803888">"Buat semula"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Pemilihan teks"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Tambah ke kamus"</string>
     <string name="deleteText" msgid="6979668428458199034">"Padam"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Kongsi laporan pepijat dengan pentadbir?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Pentadbir IT anda meminta laporan pepijat untuk membantu menyelesaikan masalah"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"TERIMA"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"TOLAK"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Mengambil laporan pepijat…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Sentuh untuk membatalkan"</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="9157568568695230830">"Tunjukkan kaedah input"</string>
-    <string name="hardware" msgid="7517821086888990278">"Perkakasan"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Tukar kertas dinding"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Pendengar pemberitahuan"</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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Dikemas kini oleh pentadbir anda"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Dipadamkan oleh pentadbir anda"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Untuk membantu memperbaik hayat bateri, penjimat bateri mengurangkan prestasi peranti anda dan mengehadkan getaran, perkhidmatan lokasi dan kebanyakan data latar belakang. E-mel, pemesejan dan apl lain yang bergantung kepada penyegerakan mungkin tidak mengemas kini, melainkan anda membuka apl itu.\n\nPenjimat bateri dimatikan secara automatik semasa peranti anda sedang dicas."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Kepentingan"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Disekat: Jangan sekali-kali tunjukkan pemberitahuan ini"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Rendah: Tunjukkan pada bahagian bawah senarai pemberitahuan secara senyap"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Biasa: Tunjukkan pemberitahuan ini secara senyap"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Tinggi: Tunjukkan pada bahagian atas senarai pemberitahuan dan bunyikan"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Segera: Intai pada skrin dan bunyikan"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">Selama %1$d minit (sehingga <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">Selama satu minit (sehingga <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"Mesej ini penting disebabkan orang yang terlibat."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" cuba menambahkan pengguna baharu tetapi dilarang pada masa ini."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" cuba menambahkan pengguna baharu tetapi had pengguna telah dicapai."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" cuba menambahkan pengguna baharu tetapi akaun "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" sudah wujud pada peranti ini. Teruskan juga?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" cuba menambahkan pengguna baharu untuk akaun "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Teruskan?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Pilihan 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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Semua bahasa"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Cari"</string>
 </resources>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index e8178e3..17c1eda 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"အမှားရှာဖွေပြင်ဆင်မှုမှတ်တမ်း"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"အမှားရှာဖွေပြင်ဆင်မှုမှတ်တမ်းအား ယူရန်"</string>
     <string name="bugreport_message" msgid="398447048750350456">"သင့်ရဲ့ လက်ရှိ စက်အခြေအနေ အချက်အလက်များကို အီးမေးလ် အနေဖြင့် ပေးပို့ရန် စုဆောင်းပါမည်။ အမှားရှာဖွေပြင်ဆင်မှုမှတ်တမ်းမှ ပေးပို့ရန် အသင့်ဖြစ်သည်အထိ အချိန် အနည်းငယ်ကြာမြင့်မှာ ဖြစ်သဖြင့် သည်းခံပြီး စောင့်ပါရန်"</string>
+    <string name="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 />
+    <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>
+    </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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"အန္တရာယ်ကင်းမှု စနစ်(Safe mode)"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android စနစ်"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"ကိုယ်ရေး"</string>
@@ -255,6 +265,8 @@
     <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">"appအား အခြေအနေပြ ဘားကို ပိတ်ခွင့် သို့မဟတ် စနစ် အိုင်ကွန်များကို ထည့်ခြင်း ဖယ်ရှားခြင်း ပြုလုပ်ခွင့် ပြုသည်။"</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"အခြေအနေပြ ဘားဖြစ်ပါစေ"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"အပလီကေးရှင်းအား အလိုအလျောက် ဓာတ်ပုံရိုက်ခွင့်၊ ဗီဒီယို ရိုက်ကူးခွင့် ပြုပါ။ ဒီခွင့်ပြုချက်က အပလီကေးရှင်းကို အချိန်မရွေး ကင်မရာအား ခွင့်ပြုချက် မလိုအပ်ပဲ သုံးခွင့်ပြုပါသည်။"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"တုန်ခုန်မှုအား ထိန်းချုပ်ခြင်း"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"appအား တုန်ခါစက်ကို ထိန်းချုပ်ခွင့် ပြုသည်။"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ဓါတ်မီးအား ထိန်းသိမ်းရန်"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"appအား ကား ဖလက်ရှမီးကို ထိန်းချုပ်ခွင့် ပြုသည်။"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ဖုန်းနံပါတ်များကိုတိုက်ရိုက်ခေါ်ဆိုခြင်း"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"အပလီကေးရှင်းအား အလိုအလျောက် ဖုန်းခေါ်ခွင့် ပြုပါ။ မလိုအပ်သော ဖုန်းခ များ ဖြစ်ပေါ်နိုင်ပါသည်။ ဒီခွင့်ပြုခြင်းမှာ အရေးပေါ်ဖုန်းခေါ်ခြင်း မပါဝင်ပါ။ သံသယဖြစ်စရာ အပလီကေးရှင်းများက သင့်မသိပဲ ဖုန်းခေါ်ခြင်းဖြင့် ဖုန်းခ ပိုမိုကျနိုင်ပါသည်။"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ဖုန်းခေါ်ဆိုမှု ဝန်ဆောင်ဌာန ဝင်ကြည့်ပါ"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"ဖြတ်ခြင်း"</string>
     <string name="copy" msgid="2681946229533511987">"ကူးခြင်း"</string>
     <string name="paste" msgid="5629880836805036433">"Paste"</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">"ဖျက်ပစ်ရန်"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"ချွတ်ယွင်းချက် အစီရင်ခံစာကို စီမံအုပ်ချုပ်သူထံ ပို့မလား။"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"သင်၏ IT စီမံအုပ်ချုပ်သူက ပြဿနာကို ဖြေရှင်းနိုင်ရန် ချွတ်ယွင်းချက်အစီရင်ခံစာကို တောင်းဆိုပါသည်"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"လက်ခံပါ"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ငြင်းပယ်ပါ"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"ချွတ်ယွင်းချက် စာရင်းကို ယူနေပါသည်..."</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"ဖျက်သိမ်းရန် တို့ပါ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"ကီးဘုတ် ပြောင်းလဲရန်"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"ကီးဘုတ်များကို ရွေးရန်"</string>
-    <string name="show_ime" msgid="9157568568695230830">"ရိုက်သွင်းမှု နည်းလမ်းကို ပြရန်"</string>
-    <string name="hardware" msgid="7517821086888990278">"ဟာ့ဒ်ဝဲ"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"နောက်ခံပြောင်းခြင်း"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"အကြောင်းကြားချက် နားတောင်သူ"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"အခြေအနေ စီမံပေးသူ"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"သတိပေးချက် အကူ"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"အရေးပါမှု"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"ပိတ်ဆို့ထား- ဤသတိပေးချက်များကို ဘယ်တော့မှ မပြပါနှင့်"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"နိမ့်- တိတ်ဆိတ်စွာ သတိပေးချက်များ၏ စာရင်း အောက်ပိုင်းမှာ ပြပါ"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"\'ပုံမှန်- ဤသတိပေးချက်များကို တိတ်ဆိတ်စွာ ပြပါ"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"မြင့်မား- သတိပေးချက်များ၏ စာရင်းထိပ်မှာ ပြလျက် အသံမြည်ပေးပါ"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"အရေးကြီး- : မျက်နှာပြင်မှာ ပြပေးလျက် အသံမြည်ပေးပါ"</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">တစ်မိနစ်တွင် (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> အထိ)</item>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"အထွေထွေ"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"ဤအသိပေးချက်များ၏ အရေးပါမှုကိုသင်သတ်မှတ်ပြီးပါပြီ။"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ပါဝင်သည့်လူများကြောင့် အရေးပါပါသည်။"</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>"က အသုံးပြုသူ အသစ်ကို ထည့်ရန် ကြိုးစားနေပါသည်၊ သို့သော် လောလောဆယ်မှာ တားမြစ်ထားပါသည်။"</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>"က အသုံးပြုသူ အသစ်ကို ထည့်ရန် ကြိုးစားနေပါသည်၊ သို့သော် အသုံးပြုသူ ကန့်သတ်ချက် ပြည့်မီသွားပါပြီ။"</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>"က အသုံးပြုသူ အသစ်ကို ထည့်ရန် ကြိုးစားနေပါသည်၊ သို့သော် အကောင့် "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>"မှာ ဤကိရိယာထဲတွင် ရှိနှင့်နေပါပြီ။ မည်သို့ပင်ဖြစ်စေ ဆက်လက်လုပ်ဆောင်ရမလား။"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>"က အကောင့် "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>"အတွက် အသုံးပြုသူ အသစ်ကို ထည့်ရန် ကြိုးစားနေပါသည်။ ဆက်လက်လုပ်ဆောင်ရမလား။"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"ဘာသာစကားရွေးချယ်မှု"</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>
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 033c541..2385ad7 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Feilrapport"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Utfør feilrapport"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Informasjon om tilstanden til enheten din samles inn og sendes som en e-post. Det tar litt tid fra du starter feilrapporten til e-posten er klar, så vær tålmodig."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktiv rapport"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Bruk dette alternativet i de fleste tilfeller. Da kan du spore fremgangen for rapporten samt skrive inn flere detaljer om problemet. Noen deler som tar lang tid å behandle, blir kanskje utelatt."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Fullstendig rapport"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Tar skjermdump for feilrapporten om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder.</item>
+      <item quantity="one">Tar skjermdump for feilrapporten om <xliff:g id="NUMBER_0">%d</xliff:g> sekund.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Stillemodus"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Lyden er av"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Lyden er på"</string>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"Sikkermodus"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"Personlig"</string>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Dette omfatter personlige data, som kredittkortnumre og passord."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Kontrollér forstørrelse for skjermen"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrollér zoomenivået og plasseringen for skjermen."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Gjøre bevegelser"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Kan trykke, sveipe, klype og gjøre andre bevegelser."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"deaktivere eller endre statusfeltet"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Lar appen deaktivere statusfeltet eller legge til og fjerne systemikoner."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"vise appen i statusfeltet"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Appen tillates å ta bilder og filme med kameraet. Det betyr at appen kan bruke kameraet når som helst uten bekreftelse fra deg."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"kontrollere vibreringen"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Lar appen kontrollere vibreringsfunksjonen."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"kontrollere lommelykten"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Lar appen kontrollere lommelykten."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ringe telefonnummer direkte"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Lar appen ringe telefonnumre uten at du gjør noe. Dette kan resultere i uventede oppringninger og kostnader. Appen kan imidlertid ikke ringe nødnumre. Merk at skadelige apper kan påføre deg kostnader ved å ringe uten bekreftelse fra deg."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"få tilgang til nettprattjenesten for ringing"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Klipp ut"</string>
     <string name="copy" msgid="2681946229533511987">"Kopier"</string>
     <string name="paste" msgid="5629880836805036433">"Lim inn"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Lim inn som ren tekst"</string>
     <string name="replace" msgid="5781686059063148930">"Erstatt"</string>
     <string name="delete" msgid="6098684844021697789">"Slett"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Kopier URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Marker tekst"</string>
+    <string name="undo" msgid="7905788502491742328">"Angre"</string>
+    <string name="redo" msgid="7759464876566803888">"Utfør likevel"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Merket tekst"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Legg til i ordlisten"</string>
     <string name="deleteText" msgid="6979668428458199034">"Slett"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Vil du dele feilrapporten med administratoren?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"IT-administratoren din har bedt om en feilrapport for å hjelpe med feilsøkingen"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"GODTA"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"AVSLÅ"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Kjører feilrapport …"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Trykk for å avbryte"</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="9157568568695230830">"Vis inndatametode"</string>
-    <string name="hardware" msgid="7517821086888990278">"Maskinvare"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Velg bakgrunnsbilde"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Varsellytteren"</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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Oppdatert av administratoren"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Slettet av administratoren"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"For å forlenge batterilevetiden reduserer batterispareren ytelsen til enheten din og begrenser vibrering, posisjonstjenester og mesteparten av bakgrunnsdataene. E-post, sending av meldinger og andre apper som er avhengig av synkronisering, oppdateres kanskje ikke med mindre du åpner dem.\n\nBatterisparing slås av automatisk når enheten lader."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Viktighet"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokkert: Aldri vis disse varslene"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Lavt: Vis nederst i varsellisten uten lyd"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normalt: Vis disse varslene uten lyd"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Høyt: Vis øverst i varsellisten med lyd"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Haster: Vises fort på skjermen med lyd"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">I %1$d minutter (til <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">I 1 minutt (til <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"Dette er viktig på grunn av folkene som er involvert."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" prøver å legge til en ny bruker, men den har for øyeblikket ikke de nødvendige tillatelsene."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" prøver å legge til en ny bruker, men brukergrensen er nådd."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" prøver å legge til en ny bruker, men kontoen "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" finnes allerede på denne enheten. Vil du fortsette likevel?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" prøver å legge til en ny bruker på kontoen "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Vil du fortsette?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Språkinnstilling"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Alle språk"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Søk"</string>
 </resources>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index ec13ebb..3e0cb29 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -146,7 +146,7 @@
     <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="httpErrorProxyAuth" msgid="1788207010559081331">"प्रोक्सी सर्भरको माध्यमद्वारा प्रमाणीकरण असफल भएको छ।"</string>
     <string name="httpErrorConnect" msgid="8714273236364640549">"सर्भरसँग जोड्न सकेन।"</string>
     <string name="httpErrorIO" msgid="2340558197489302188">"सर्भरसँग संचार गर्न सकेन। फेरि पछि कोसिस गर्नुहोस्।"</string>
     <string name="httpErrorTimeout" msgid="4743403703762883954">"सर्भर संगको सम्पर्क प्रक्रिया समय सकियो।"</string>
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"बग रिपोर्ट"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"बग रिपोर्ट लिनुहोस्"</string>
     <string name="bugreport_message" msgid="398447048750350456">"एउटा इमेल सन्देशको रूपमा पठाउनलाई यसले तपाईँको हालैको उपकरणको अवस्थाको बारेमा सूचना जम्मा गर्ने छ। बग रिपोर्ट सुरु गरेदेखि पठाउन तयार नभएसम्म यसले केही समय लिन्छ; कृपया धैर्य गर्नुहोस्।"</string>
+    <string name="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 />
+    <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>
+    </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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
     <string name="android_system_label" msgid="6577375335728551336">"एन्ड्रोइड प्रणाली"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"व्यक्तिगत"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"अनुप्रयोगलाई क्यामेरासँग तस्बिर र भिडियोहरू लिन अनुमति दिन्छ। यस अनुमतिले अनुप्रयोगलाई तपाईंको पुष्टिकरण बिना कुनै पनि समयमा क्यामेरा प्रयोग गर्न स्वीकृति दिन्छ।"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"कम्पन नियन्त्रण गर्नुहोस्"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"अनुप्रयोगलाई भाइब्रेटर नियन्त्रण गर्न अनुमति दिन्छ।"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"फ्ल्यासलाईट नियन्त्रण गर्नुहोस्"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"फ्ल्यास प्रकाशलाई नियन्त्रण गर्न अनुप्रयोगलाई अनुमति दिन्छ।"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"फोन नम्बरहरूमा सिधै कल गर्नुहोस्"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"तपाईँको हस्तक्षेप बेगरै फोन नम्बर कल गर्न अनुप्रयोगलाई अनुमति दिन्छ। यसले अनपेक्षित शुल्क वा कलहरू गराउन सक्छ। यसले अनुप्रयोगलाई आपतकालीन नम्बरहरू कल गर्न अनुमति दिँदैन विचार गर्नुहोस्। खराब अनुप्रयोगहरूले तपाईँको स्वीकार बिना कलहरू गरेर तपाईँलाई बढी पैसा तिराउन सक्छ।"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS कल सेवा पहुँच गर्नुहोस्"</string>
@@ -858,10 +868,13 @@
     <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">"मेट्नुहोस्"</string>
@@ -1034,10 +1047,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"प्रशासकसँग बग रिपोर्ट साझेदारी गर्ने हो?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"तपाईंको IT व्यवस्थापकले समस्या निवारणमा मद्दत गर्न बग रिपोर्ट अनुरोध गर्नुभयो"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"स्वीकार गर्नुहोस्"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"अस्वीकार गर्नुहोस्"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"बग रिपोर्ट लिँदै..."</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"रद्द गर्न छुनुहोस्"</string>
     <string name="select_input_method" msgid="8547250819326693584">"कुञ्जीपाटी परिवर्तन गर्नुहोस्"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"कीबोर्ड छान्नुहोस्"</string>
-    <string name="show_ime" msgid="9157568568695230830">"आगत विधि देखाउनुहोस्"</string>
-    <string name="hardware" msgid="7517821086888990278">"हार्डवेयर"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1113,6 +1132,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"वालपेपर परिवर्तन गर्नुहोस्"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"सूचना सुन्नेवाला"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"सर्त प्रदायक"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"सूचना सहायक"</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>
@@ -1446,12 +1466,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"महत्त्व"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"रोकिएका: यी सूचनाहरू कहिल्यै नदेखाउनुहोस्"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"न्यून: चुपचाप सूचना सूचीको फेदमा देखाउनुहोस्"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"सामान्य: चुपचाप यी सूचनाहरू देखाउनुहोस्"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"उच्च: सूचना सूचीको शीर्षमा देखाउनुहोस् र आवाज निकाल्नुहोस्"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"जरुरी: स्क्रिनमा झलक्क हेर्नुहोस् र आवाज निकाल्नुहोस्"</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">एक मिनेटको लागि (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> सम्म)</item>
@@ -1517,6 +1531,16 @@
       <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_topic" msgid="3572280439880023233">"तपाईंले यी सूचनाहरूको महत्त्व सेट गर्नुहुन्छ।"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"यसमा सङ्लग्न भएका मानिसहरूको कारणले गर्दा यो महत्वपूर्ण छ।"</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ले नयाँ प्रयोगकर्ता थप्ने प्रयास गरिरहेको छ तर हाललाई निषेधित छ।"</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ले नयाँ प्रयोगकर्ता थप्ने प्रयास गरिरहेको छ तर प्रयोगकर्ताको सीमा पुगेको छ।"</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ले नयाँ प्रयोगकर्ता थप्ने प्रयास गरिरहेको छ तर यो यन्त्रमा खाता "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" पहिले नै अवस्थित छ। जे भए पनि अगाडि बढ्ने हो?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ले खाता "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" मा नयाँ प्रयोगकर्ता थप्ने प्रयास गरिरहेको छ। अगाडि बढ्ने हो?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"भाषाको प्राथमिकता"</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>
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index d30d836..d0a333b 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Foutenrapport"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Foutenrapport genereren"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Hiermee worden gegevens over de huidige status van je apparaat verzameld en als e-mail verzonden. Wanneer u een foutenrapport start, duurt het even voordat het kan worden verzonden. Even geduld alstublieft."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interactief rapport"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Gebruik deze optie in de meeste situaties. Hiermee kun je de voortgang van het rapport bijhouden en meer gegevens over het probleem opgeven. Mogelijk worden bepaalde minder vaak gebruikte gedeelten weggelaten (waarvoor het lang zou duren om een rapport te genereren)."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Volledig rapport"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Er wordt over <xliff:g id="NUMBER_1">%d</xliff:g> seconden een screenshot gemaakt voor het bugrapport.</item>
+      <item quantity="one">Er wordt over <xliff:g id="NUMBER_0">%d</xliff:g> seconde een screenshot gemaakt voor het bugrapport.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Stille modus"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Geluid is UIT"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Geluid is AAN"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Omvat persoonlijke gegevens zoals creditcardnummers en wachtwoorden."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Schermvergroting bedienen"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Bedien het zoomniveau en de positionering van het scherm."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Gebaren uitvoeren"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Kan tikken, vegen, samenknijpen en andere gebaren uitvoeren."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"statusbalk uitschakelen of wijzigen"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Hiermee kan de app de statusbalk uitschakelen of systeempictogrammen toevoegen en verwijderen."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"de statusbalk zijn"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Hiermee kan de app foto\'s en video\'s maken met de camera. Met deze toestemming kan de app de camera altijd gebruiken, zonder je bevestiging."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"trilling beheren"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Hiermee kan de app de trilstand beheren."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"zaklamp bedienen"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Hiermee kan de app de zaklamp bedienen."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"telefoonnummers rechtstreeks bellen"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Hiermee kan de app zonder je tussenkomst telefoonnummers bellen. Dit kan tot onverwachte kosten of oproepen leiden. De app kan hiermee geen noodnummers bellen. Schadelijke apps kunnen u geld kosten door nummers te bellen zonder om je bevestiging te vragen."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"toegang tot IMS-service voor bellen"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Knippen"</string>
     <string name="copy" msgid="2681946229533511987">"Kopiëren"</string>
     <string name="paste" msgid="5629880836805036433">"Plakken"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Plakken als platte tekst"</string>
     <string name="replace" msgid="5781686059063148930">"Vervangen..."</string>
     <string name="delete" msgid="6098684844021697789">"Verwijderen"</string>
     <string name="copyUrl" msgid="2538211579596067402">"URL kopiëren"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Tekst selecteren"</string>
+    <string name="undo" msgid="7905788502491742328">"Ongedaan maken"</string>
+    <string name="redo" msgid="7759464876566803888">"Opnieuw"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Tekstselectie"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Toevoegen aan woordenboek"</string>
     <string name="deleteText" msgid="6979668428458199034">"Verwijderen"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Bugrapport delen met beheerder?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Je IT-beheerder heeft een bugrapport aangevraagd om het probleem op te lossen"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACCEPTEREN"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"WEIGEREN"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Bugrapport genereren…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Tik om te annuleren"</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="9157568568695230830">"Invoermethode weergeven"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardware"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Achtergrond wijzigen"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Listener voor meldingen"</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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Geüpdatet door je beheerder"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Verwijderd door je beheerder"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Accubesparing beperkt de prestaties van je apparaat, de trilstand, locatieservices en de meeste achtergrondgegevens om de gebruiksduur van de accu te verlengen.\n\nAccubesparing wordt automatisch uitgeschakeld terwijl je apparaat wordt opgeladen."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Belang"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Geblokkeerd: deze meldingen nooit weergeven"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Laag: zonder geluid onder aan de lijst met meldingen weergeven"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normaal: deze meldingen zonder geluid weergeven"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Hoog: boven aan de lijst met meldingen weergeven en geluid laten horen"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Urgent: op het scherm weergeven en geluid laten horen"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">%1$d minuten (tot <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">Eén minuut (tot <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"Dit is belangrijk vanwege de betrokken mensen."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" probeert een nieuwe gebruiker toe te voegen, maar dit is momenteel niet toegestaan."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" probeert een nieuwe gebruiker toe te voegen, maar de gebruikerslimiet is al bereikt."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" probeert een nieuwe gebruiker toe te voegen, maar het account "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" bestaat al op dit apparaat. Toch doorgaan?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" probeert een nieuwe gebruiker toe te voegen voor het account "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Doorgaan?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Taalvoorkeur"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Alle talen"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Zoeken"</string>
 </resources>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index 06b549e..7e762b0 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"ਬਗ ਰਿਪੋਰਟ"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"ਬਗ ਰਿਪੋਰਟ ਲਓ"</string>
     <string name="bugreport_message" msgid="398447048750350456">"ਇਹ ਇੱਕ ਈ-ਮੇਲ ਸੁਨੇਹਾ ਭੇਜਣ ਲਈ, ਤੁਹਾਡੀ ਵਰਤਮਾਨ ਡਿਵਾਈਸ ਬਾਰੇ ਜਾਣਕਾਰੀ ਇਕੱਤਰ ਕਰੇਗਾ। ਬਗ ਰਿਪੋਰਟ ਸ਼ੁਰੂ ਕਰਨ ਵਿੱਚ ਥੋੜ੍ਹਾ ਸਮਾਂ ਲੱਗੇਗਾ ਜਦੋਂ ਤੱਕ ਇਹ ਭੇਜੇ ਜਾਣ ਲਈ ਤਿਆਰ ਨਾ ਹੋਵੇ, ਕਿਰਪਾ ਕਰਕੇ ਧੀਰਜ ਰੱਖੋ।"</string>
+    <string name="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 />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">ਬੱਗ ਰਿਪੋਰਟ ਲਈ <xliff:g id="NUMBER_1">%d</xliff:g> ਸਕਿੰਟ ਵਿੱਚ ਸਕ੍ਰੀਨਸ਼ਾਟ ਲਿਆ ਜਾ ਰਿਹਾ ਹੈ।</item>
+      <item quantity="other">ਬੱਗ ਰਿਪੋਰਟ ਲਈ <xliff:g id="NUMBER_1">%d</xliff:g> ਸਕਿੰਟ ਵਿੱਚ ਸਕ੍ਰੀਨਸ਼ਾਟ ਲਿਆ ਜਾ ਰਿਹਾ ਹੈ।</item>
+    </plurals>
     <string name="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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"ਸੁਰੱਖਿਅਤ ਮੋਡ"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"ਨਿੱਜੀ"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ਐਪ ਨੂੰ ਕੈਮਰੇ ਨਾਲ ਤਸਵੀਰਾਂ ਅਤੇ ਵੀਡੀਓ ਲੈਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਅਨੁਮਤੀ ਐਪ ਨੂੰ ਤੁਹਾਡੀ ਪੁਸ਼ਟੀ ਤੋਂ ਬਿਨਾਂ ਕਿਸੇ ਵੀ ਸਮੇਂ ਕੈਮਰਾ ਵਰਤਣ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ।"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"ਵਾਈਬ੍ਰੇਸ਼ਨ ਤੇ ਨਿਯੰਤਰਣ ਪਾਓ"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"ਐਪ ਨੂੰ ਵਾਈਬ੍ਰੇਟਰ ਤੇ ਨਿਯੰਤਰਣ ਪਾਉਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ਫਲੈਸ਼ਲਾਈਟ ਤੇ ਨਿਯੰਤਰਣ ਪਾਓ"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"ਐਪ ਨੂੰ ਫਲੈਸ਼ਲਾਈਟ ਤੇ ਨਿਯੰਤਰਣ ਪਾਉਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ਫੋਨ ਨੰਬਰਾਂ ਤੇ ਸਿੱਧੇ ਕਾਲ ਕਰੋ"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਦਖ਼ਲ ਤੋਂ ਬਿਨਾਂ ਫੋਨ ਨੰਬਰਾਂ ਤੇ ਕਾਲ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਸਦੇ ਸਿੱਟੇ ਵਜੋਂ ਅਕਲਪਿਤ ਖ਼ਰਚੇ ਜਾਂ ਕਾਲਾਂ ਹੋ ਸਕਦੀਆਂ ਹਨ। ਧਿਆਨ ਦਿਓ ਕਿ ਇਹ ਐਪ ਨੂੰ ਐਮਰਜੈਂਸੀ ਨੰਬਰਾਂ ਤੇ ਕਾਲ ਕਰਨ ਦੀ ਆਗਿਆ ਨਹੀਂ ਦਿੰਦਾ। ਖ਼ਰਾਬ ਐਪਸ ਤੁਹਾਡੀ ਪੁਸ਼ਟੀ ਤੋਂ ਬਿਨਾਂ ਕਾਲਾਂ ਕਰਕੇ ਤੁਹਾਨੂੰ ਖ਼ਰਚੇ ਪਾ ਸਕਦੇ ਹਨ।"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ਕਾਲ ਸੇਵਾ ਤੱਕ ਪਹੁੰਚ"</string>
@@ -858,10 +868,13 @@
     <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">"ਮਿਟਾਓ"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"ਕੀ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਬੱਗ ਰਿਪੋਰਟ ਸਾਂਝੀ ਕਰਨੀ ਹੈ?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"ਸਮੱਸਿਆ ਦੇ ਨਿਪਟਾਰੇ ਵਿੱਚ ਮਦਦ ਲਈ ਤੁਹਾਡੇ IT ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਇੱਕ ਬੱਗ ਰਿਪੋਰਟ ਦੀ ਬੇਨਤੀ ਕੀਤੀ"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ਸਵੀਕਾਰ ਕਰੋ"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ਅਸਵੀਕਾਰ ਕਰੋ"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"ਬੱਗ ਰਿਪਰੋਟ ਪ੍ਰਾਪਤ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ..."</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"ਰੱਦ ਕਰਨ ਲਈ ਸਪਰਸ਼ ਕਰੋ"</string>
     <string name="select_input_method" msgid="8547250819326693584">"ਕੀਬੋਰਡ ਬਦਲੋ"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"ਕੀਬੋਰਡਸ ਚੁਣੋ"</string>
-    <string name="show_ime" msgid="9157568568695230830">"ਇਨਪੁਟ ਵਿਧੀ ਦਿਖਾਓ"</string>
-    <string name="hardware" msgid="7517821086888990278">"ਹਾਰਡਵੇਅਰ"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"ਵਾਲਪੇਪਰ ਬਦਲੋ"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"ਸੂਚਨਾ ਸੁਣਨ ਵਾਲਾ"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ਸਥਿਤੀ ਪ੍ਰਦਾਤਾ"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"ਸੂਚਨਾ ਸਹਾਇਕ"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"ਮਹੱਤਤਾ"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"ਬਲੌਕ ਕੀਤਾ: ਇਹ ਸੂਚਨਾਵਾਂ ਕਦੇ ਨਾ ਵਿਖਾਓ"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"ਘੱਟ: ਚੁੱਪਚਾਪ ਢੰਗ ਨਾਲ ਸੂਚਨਾ ਸੂਚੀ ਦੇ ਹੇਠਾਂ ਵਿਖਾਓ"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"ਸਧਾਰਨ: ਇਹ ਸੂਚਨਾਵਾਂ ਚੁੱਪਚਾਪ ਢੰਗ ਨਾਲ ਵਿਖਾਓ"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"ਵੱਧ: ਸੂਚਨਾਵਾਂ ਸੂਚੀ ਦੇ ਸਿਖਰ \'ਤੇ ਵਿਖਾਓ ਅਤੇ ਆਵਾਜ਼ ਕਰੋ"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"ਜ਼ਰੂਰੀ: ਸਕਰੀਨ \'ਤੇ ਝਾਤੀ ਮਾਰੋ ਅਤੇ ਆਵਾਜ਼ ਕਰੋ"</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="other">%1$d ਮਿੰਟਾਂ ਤੱਕ (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> ਤੱਕ)</item>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"ਵਿਵਿਧ"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"ਤੁਸੀਂ ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਦੀ ਮਹੱਤਤਾ ਸੈੱਟ ਕੀਤੀ।"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ਇਹ ਸ਼ਾਮਲ ਲੋਕਾਂ ਦੇ ਕਾਰਨ ਮਹੱਤਵਪੂਰਨ ਹੈ।"</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ਇੱਕ ਨਵੇਂ ਵਰਤੋਂਕਾਰ ਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰ ਰਿਹਾ ਹੈ, ਪਰ ਇਸ \'ਤੇ ਮੌਜੂਦਾ ਤੌਰ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਈ ਗਈ ਹੈ।"</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ਇੱਕ ਨਵੇਂ ਵਰਤੋਂਕਾਰ ਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰ ਰਿਹਾ ਹੈ, ਪਰ ਵਰਤੋਂਕਾਰ ਮਿਆਦ ਪੂਰੀ ਹੋ ਚੁੱਕੀ ਹੈ।"</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ਇੱਕ ਨਵੇਂ ਵਰਤੋਂਕਾਰ ਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰ ਰਿਹਾ ਹੈ, ਪਰ "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" ਖਾਤਾ ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਪਹਿਲਾਂ ਤੋਂ ਹੀ ਮੌਜੂਦ ਹੈ। ਕੀ ਫਿਰ ਵੀ ਅੱਗੇ ਵੱਧਣਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" ਖਾਤੇ ਵਿੱਚ ਇੱਕ ਨਵੇਂ ਵਰਤੋਂਕਾਰ ਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰ ਰਿਹਾ ਹੈ। ਕੀ ਅੱਗੇ ਵੱਧਣਾ ਹੈ?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"ਭਾਸ਼ਾ ਤਰਜੀਹ"</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>
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 93ea9f4..8f475d5 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -213,6 +213,17 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Zgłoszenie błędu"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Zgłoś błąd"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Informacje o bieżącym stanie urządzenia zostaną zebrane i wysłane e-mailem. Przygotowanie zgłoszenia błędu do wysłania chwilę potrwa, więc zachowaj cierpliwość."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Raport interaktywny"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Używaj tej opcji w większości przypadków. Umożliwia śledzenie postępów raportu i podanie dodatkowych szczegółów problemu. Raport może pomijać niektóre rzadko używane sekcje, których utworzenie zajmuje dużo czasu."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Pełny raport"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="few">Zrzut ekranu do raportu o błędzie zostanie zrobiony za <xliff:g id="NUMBER_1">%d</xliff:g> sekundy.</item>
+      <item quantity="many">Zrzut ekranu do raportu o błędzie zostanie zrobiony za <xliff:g id="NUMBER_1">%d</xliff:g> sekund.</item>
+      <item quantity="other">Zrzut ekranu do raportu o błędzie zostanie zrobiony za <xliff:g id="NUMBER_1">%d</xliff:g> sekundy.</item>
+      <item quantity="one">Zrzut ekranu do raportu o błędzie zostanie zrobiony za <xliff:g id="NUMBER_0">%d</xliff:g> sekundę.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Tryb cichy"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Dźwięk jest wyłączony"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Dźwięk jest włączony"</string>
@@ -225,6 +236,7 @@
     <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="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>
@@ -257,6 +269,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Obejmuje informacje osobiste, takie jak numery kart kredytowych i hasła."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Regulowanie powiększenia ekranu"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Regulowanie poziomu i obszaru powiększenia ekranu."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Obsługa gestów"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Obsługuje kliknięcia, przesunięcia, ściągnięcia palców i inne gesty."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"wyłączanie lub zmienianie paska stanu"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Pozwala aplikacji na wyłączanie paska stanu oraz dodawanie i usuwanie ikon systemowych."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"działanie jako pasek stanu"</string>
@@ -355,8 +369,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Pozwala aplikacji na robienie zdjęć i nagrywanie filmów przy użyciu aparatu. Aplikacja z tym uprawnieniem może użyć aparatu w dowolnym momencie bez Twojego potwierdzenia."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"sterowanie wibracjami"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Pozwala aplikacji na sterowanie wibracjami."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolowanie latarki"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Pozwala aplikacji na sterowanie latarką."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"bezpośrednie wybieranie numerów telefonów"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Pozwala aplikacji na dzwonienie pod numery telefonów bez Twojej wiedzy. Może to skutkować nieoczekiwanymi opłatami lub połączeniami. Aplikacja nie może dzwonić pod numery alarmowe. Złośliwe aplikacje mogą generować koszty, wykonując połączenia bez Twojego potwierdzenia."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"usługa telefoniczna z dostępem do komunikatora"</string>
@@ -868,10 +880,13 @@
     <string name="cut" msgid="3092569408438626261">"Wytnij"</string>
     <string name="copy" msgid="2681946229533511987">"Kopiuj"</string>
     <string name="paste" msgid="5629880836805036433">"Wklej"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Wklej jako zwykły tekst"</string>
     <string name="replace" msgid="5781686059063148930">"Zastąp"</string>
     <string name="delete" msgid="6098684844021697789">"Usuń"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Kopiuj adres URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Zaznacz tekst"</string>
+    <string name="undo" msgid="7905788502491742328">"Cofnij"</string>
+    <string name="redo" msgid="7759464876566803888">"Ponów"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Zaznaczanie tekstu"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Dodaj do słownika"</string>
     <string name="deleteText" msgid="6979668428458199034">"Usuń"</string>
@@ -1042,10 +1057,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Udostępnić raport o błędzie administratorowi?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Administrator poprosił o raport o błędzie, który pomoże w rozwiązaniu problemu"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"AKCEPTUJ"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ODRZUĆ"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Zgłaszam błąd…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Kliknij, by anulować"</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="9157568568695230830">"Pokaż metodę wprowadzania"</string>
-    <string name="hardware" msgid="7517821086888990278">"Sprzęt"</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="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCĆDEĘFGHIJKLŁMNŃOÓPQRSŚTUVWXYZŹŻ"</string>
@@ -1121,6 +1142,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Zmień tapetę"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Odbiornik powiadomień"</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="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>
@@ -1458,12 +1480,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Zaktualizowane przez administratora"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Usunięty przez administratora"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Aby wydłużyć czas pracy baterii, Oszczędzanie baterii ogranicza aktywność urządzenia, w tym wibracje, usługi lokalizacyjne i przetwarzanie większości danych w tle. Poczta, czat i inne synchronizowane aplikacje mogą nie aktualizować swojej zawartości, dopóki ich nie otworzysz.\n\nOszczędzanie baterii wyłącza się automatycznie podczas ładowania urządzenia."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Ważność"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Zablokowana: nigdy nie pokazuj tych powiadomień"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Niska: pokazuj na dole listy powiadomień bez sygnału dźwiękowego"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normalna: pokazuj te powiadomienia bez sygnału dźwiękowego"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Wysoka: pokazuj na początku listy powiadomień i odtwarzaj dźwięk"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Pilna: wyświetlaj na ekranie i odtwarzaj dźwięk"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="few">Przez %1$d minuty (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="many">Przez %1$d minut (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1549,4 +1565,14 @@
     <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_person" msgid="9160133597262938296">"Ta wiadomość jest ważna ze względu na osoby uczestniczące w wątku."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315">"Aplikacja "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" próbuje dodać nowego użytkownika, ale jest obecnie zabroniona."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266">"Aplikacja "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" próbuje dodać nowego użytkownika, ale osiągnięto już limit użytkowników."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789">"Aplikacja "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" próbuje dodać nowego użytkownika, ale na tym urządzeniu istnieje już konto "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Kontynuować mimo to?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392">"Aplikacja "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" próbuje dodać nowego użytkownika do konta "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Kontynuować?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Ustawienie języka"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Wszystkie języki"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Szukaj"</string>
 </resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 3552795..60d4860 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Relatório de bugs"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Obter relatório de bugs"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Isto coletará informações sobre o estado atual do dispositivo para enviá-las em uma mensagem de e-mail. Após iniciar o relatório de bugs, será necessário aguardar algum tempo até que esteja pronto para ser enviado."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Relatório interativo"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Use este recurso na maioria das circunstâncias. Ele permite que você acompanhe o progresso do relatório e informe mais detalhes sobre o problema. É possível que ele omita algumas seções menos utilizadas que levam muito tempo na emissão dos relatórios."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Relatório completo"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">Capturas de tela para o relatório do bug serão feitas em <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item>
+      <item quantity="other">Capturas de tela para o relatório do bug serão feitas em <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modo silencioso"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Som DESATIVADO"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"O som está ATIVADO"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Inclui dados pessoais, como números de cartão de crédito e senhas."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Controlar ampliação da tela"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlar o posicionamento e nível de zoom da tela."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Fazer gestos"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Toque, deslize, faça gestos de pinça e faça outros gestos."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"desativar ou modificar a barra de status"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Permite que o app desative a barra de status ou adicione e remova ícones do sistema."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"ser a barra de status"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permite que o app tire fotos e filme vídeos com a câmera. Esta permissão autoriza o app a usar a câmera a qualquer momento sem sua confirmação."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"controlar vibração"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite que o app controle a vibração."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite que o app controle a lanterna."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ligar diretamente para números de telefone"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que o app ligue para números de telefone sem sua intervenção. Isso pode resultar em cobranças ou chamadas inesperadas. Esta opção não permite que o app ligue para números de emergência. Apps maliciosos podem gerar custos com chamadas feitas sem sua confirmação."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"acessar serviço de mensagens instantâneas para chamadas"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Recortar"</string>
     <string name="copy" msgid="2681946229533511987">"Copiar"</string>
     <string name="paste" msgid="5629880836805036433">"Colar"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Colar como texto simples"</string>
     <string name="replace" msgid="5781686059063148930">"Substituir..."</string>
     <string name="delete" msgid="6098684844021697789">"Excluir"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Copiar URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Selecionar texto"</string>
+    <string name="undo" msgid="7905788502491742328">"Desfazer"</string>
+    <string name="redo" msgid="7759464876566803888">"Refazer"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Seleção de texto"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Adicionar ao dicionário"</string>
     <string name="deleteText" msgid="6979668428458199034">"Excluir"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Compartilhar o relatório do bug com o administrador?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Seu administrador de TI solicitou um relatório do bug para ajudar a resolver problemas"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEITAR"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RECUSAR"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Gerando relatório do bug..."</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Toque para cancelar"</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="9157568568695230830">"Mostrar método de entrada"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardware"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <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="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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Atualizado pelo administrador"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Excluído pelo seu administrador"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Para ajudar a melhorar a duração da bateria, o economizador de bateria reduz o desempenho e os limites de vibração do dispositivo, os serviços de localização e a maioria dos dados de segundo plano. E-mail, mensagens e outros aplicativos que dependem de sincronização não podem ser atualizados, a não ser que você os abra.\n\nO economizador de bateria é desligado automaticamente quando o dispositivo está sendo carregado."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Importância"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloqueada: nunca mostrar essas notificações"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Baixa: mostrar na parte inferior da lista de notificações de forma silenciosa"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normal: mostrar essas notificações de forma silenciosa"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Alta: mostrar na parte superior da lista de notificações e emitir som"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Urgente: mostrar parcialmente na tela e emitir som"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="one">Por %1$d minutos (até às <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="other">Por %1$d minutos (até às <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"Isso é importante por causa das pessoas envolvidas."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" está tentando adicionar um novo usuário, mas isso não é permitido no momento."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" está tentando adicionar um novo usuário, mas o limite de usuários foi atingido."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" está tentando adicionar um novo usuário, mas a conta "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" já existe neste dispositivo. Continuar mesmo assim?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" está tentando adicionar um novo usuário à conta "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Continuar?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Preferência de 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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Todos os idiomas"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Pesquisa"</string>
 </resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index f2e9402..e58e693 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Relatório de erros"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Criar relatório de erros"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Será recolhida informação sobre o estado atual do seu dispositivo a enviar através de uma mensagem de email. Demorará algum tempo até que o relatório de erro esteja pronto para ser enviado. Aguarde um pouco."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Relatório interativo"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Utilize esta opção na maioria das circunstâncias. Permite monitorizar o progresso do relatório e introduzir mais detalhes acerca do problema. Pode omitir algumas secções menos utilizadas que demoram muito tempo a comunicar."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Relatório completo"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">A tirar uma captura de ecrã do relatório de erro dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item>
+      <item quantity="one">A tirar uma captura de ecrã do relatório de erro dentro de <xliff:g id="NUMBER_0">%d</xliff:g> segundo.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modo silencioso"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Som desativado"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"O som está ativado"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Inclui dados pessoais, como números de cartões de crédito e palavras-passe."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Controlar a ampliação do ecrã"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlar o nível de zoom e o posicionamento do ecrã."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Realizar gestos"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"É possível tocar, deslizar rapidamente, juntar os dedos e realizar outros gestos"</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"desativar ou modificar barra de estado"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Permite à aplicação desativar a barra de estado ou adicionar e remover ícones do sistema."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"ser apresentada na barra de estado"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permite que a aplicação tire fotografias e grave vídeos com a câmara. Esta autorização permite que a aplicação utilize a câmara sem a sua confirmação em qualquer altura."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"controlar vibração"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite à aplicação controlar o vibrador."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite à aplicação controlar a lanterna."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"marcar números de telefone diretamente"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que a aplicação ligue para números de telefone sem a intervenção do utilizador. Esta ação pode resultar em cobranças ou chamadas inesperadas. Tenha em atenção que isto não permite que a aplicação ligue para números de emergência. As aplicações maliciosas podem fazer com que incorra em custos, fazendo chamadas sem a sua confirmação."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"aceder ao serviço de chamadas IMS"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Cortar"</string>
     <string name="copy" msgid="2681946229533511987">"Copiar"</string>
     <string name="paste" msgid="5629880836805036433">"Colar"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Colar como texto simples"</string>
     <string name="replace" msgid="5781686059063148930">"Substituir..."</string>
     <string name="delete" msgid="6098684844021697789">"Eliminar"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Copiar URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Selecionar texto"</string>
+    <string name="undo" msgid="7905788502491742328">"Anular"</string>
+    <string name="redo" msgid="7759464876566803888">"Refazer"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Selecção de texto"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Adicionar ao dicionário"</string>
     <string name="deleteText" msgid="6979668428458199034">"Eliminar"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Pretende partilhar o relatório de erros com o administrador?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"O seu administrador de TI solicitou um relatório de erros para ajudar na resolução de problemas"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEITAR"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RECUSAR"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"A criar relatório de erros…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Toque para cancelar"</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="9157568568695230830">"Mostrar método de entrada"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardware"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <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="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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Atualizado pelo administrador"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Eliminado pelo administrador"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Para ajudar a melhorar a autonomia da bateria, a poupança de bateria reduz o desempenho do seu dispositivo e limita a vibração, os serviços de localização e a maioria dos dados em segundo plano. O email, as mensagens e outras aplicações que dependem da sincronização não podem ser atualizados exceto se os abrir.\n\nA poupança de bateria desliga-se automaticamente quando o dispositivo está a carregar."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Importância"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloqueado: nunca mostrar estas notificações"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Baixo: mostrar na parte inferior da lista de notificações sem som"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normal: mostrar estas notificações sem som"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Elevado: mostrar na parte superior da lista de notificações com som"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Urgente: mostrar no ecrã com som"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">Durante %1$d minutos (até às <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">Durante um minuto (até às <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1479,7 +1493,7 @@
       <item quantity="one">Durante 1 h</item>
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_alarm" msgid="9128205721301330797">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string>
+    <string name="zen_mode_alarm" msgid="9128205721301330797">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Até que o utilizador desative"</string>
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Até desativar Não incomodar"</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>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"É importante devido às pessoas envolvidas."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" está a tentar adicionar um novo utilizador, mas está atualmente proibido(a)."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" está a tentar adicionar um novo utilizador, mas foi atingido o limite de utilizadores."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" está a tentar adicionar um novo utilizador, mas a conta "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" já existe neste dispositivo. Pretende continuar mesmo assim?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" está a tentar adicionar um novo utilizador à conta "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Pretende continuar?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Preferência de 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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Todos os idiomas"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Pesquisa"</string>
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 3552795..60d4860 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Relatório de bugs"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Obter relatório de bugs"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Isto coletará informações sobre o estado atual do dispositivo para enviá-las em uma mensagem de e-mail. Após iniciar o relatório de bugs, será necessário aguardar algum tempo até que esteja pronto para ser enviado."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Relatório interativo"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Use este recurso na maioria das circunstâncias. Ele permite que você acompanhe o progresso do relatório e informe mais detalhes sobre o problema. É possível que ele omita algumas seções menos utilizadas que levam muito tempo na emissão dos relatórios."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Relatório completo"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">Capturas de tela para o relatório do bug serão feitas em <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item>
+      <item quantity="other">Capturas de tela para o relatório do bug serão feitas em <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modo silencioso"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Som DESATIVADO"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"O som está ATIVADO"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Inclui dados pessoais, como números de cartão de crédito e senhas."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Controlar ampliação da tela"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlar o posicionamento e nível de zoom da tela."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Fazer gestos"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Toque, deslize, faça gestos de pinça e faça outros gestos."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"desativar ou modificar a barra de status"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Permite que o app desative a barra de status ou adicione e remova ícones do sistema."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"ser a barra de status"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permite que o app tire fotos e filme vídeos com a câmera. Esta permissão autoriza o app a usar a câmera a qualquer momento sem sua confirmação."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"controlar vibração"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite que o app controle a vibração."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite que o app controle a lanterna."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ligar diretamente para números de telefone"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que o app ligue para números de telefone sem sua intervenção. Isso pode resultar em cobranças ou chamadas inesperadas. Esta opção não permite que o app ligue para números de emergência. Apps maliciosos podem gerar custos com chamadas feitas sem sua confirmação."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"acessar serviço de mensagens instantâneas para chamadas"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Recortar"</string>
     <string name="copy" msgid="2681946229533511987">"Copiar"</string>
     <string name="paste" msgid="5629880836805036433">"Colar"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Colar como texto simples"</string>
     <string name="replace" msgid="5781686059063148930">"Substituir..."</string>
     <string name="delete" msgid="6098684844021697789">"Excluir"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Copiar URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Selecionar texto"</string>
+    <string name="undo" msgid="7905788502491742328">"Desfazer"</string>
+    <string name="redo" msgid="7759464876566803888">"Refazer"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Seleção de texto"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Adicionar ao dicionário"</string>
     <string name="deleteText" msgid="6979668428458199034">"Excluir"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Compartilhar o relatório do bug com o administrador?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Seu administrador de TI solicitou um relatório do bug para ajudar a resolver problemas"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ACEITAR"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"RECUSAR"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Gerando relatório do bug..."</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Toque para cancelar"</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="9157568568695230830">"Mostrar método de entrada"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardware"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <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="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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Atualizado pelo administrador"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Excluído pelo seu administrador"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Para ajudar a melhorar a duração da bateria, o economizador de bateria reduz o desempenho e os limites de vibração do dispositivo, os serviços de localização e a maioria dos dados de segundo plano. E-mail, mensagens e outros aplicativos que dependem de sincronização não podem ser atualizados, a não ser que você os abra.\n\nO economizador de bateria é desligado automaticamente quando o dispositivo está sendo carregado."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Importância"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloqueada: nunca mostrar essas notificações"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Baixa: mostrar na parte inferior da lista de notificações de forma silenciosa"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normal: mostrar essas notificações de forma silenciosa"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Alta: mostrar na parte superior da lista de notificações e emitir som"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Urgente: mostrar parcialmente na tela e emitir som"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="one">Por %1$d minutos (até às <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="other">Por %1$d minutos (até às <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"Isso é importante por causa das pessoas envolvidas."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" está tentando adicionar um novo usuário, mas isso não é permitido no momento."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" está tentando adicionar um novo usuário, mas o limite de usuários foi atingido."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" está tentando adicionar um novo usuário, mas a conta "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" já existe neste dispositivo. Continuar mesmo assim?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" está tentando adicionar um novo usuário à conta "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Continuar?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Preferência de 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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Todos os idiomas"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Pesquisa"</string>
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 2f862b2..4db1209 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -212,6 +212,16 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Raport despre erori"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Executați un raport despre erori"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Acest raport va colecta informații despre starea actuală a dispozitivului, pentru a le trimite într-un e-mail. Aveți răbdare după pornirea raportului despre erori până când va fi gata de trimis."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Raport interactiv"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Folosiți această opțiune în majoritatea situațiilor. Astfel, puteți să urmăriți progresul raportului și să introduceți mai multe detalii în privința problemei. Pot fi omise unele secțiuni mai puțin folosite pentru care raportarea durează prea mult."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Raport complet"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="few">Peste <xliff:g id="NUMBER_1">%d</xliff:g> secunde se va realiza o captură de ecran pentru raportul de eroare.</item>
+      <item quantity="other">Peste <xliff:g id="NUMBER_1">%d</xliff:g> de secunde se va realiza o captură de ecran pentru raportul de eroare.</item>
+      <item quantity="one">Peste <xliff:g id="NUMBER_0">%d</xliff:g> secundă se va realiza o captură de ecran pentru raportul de eroare.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Mod Silențios"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Sunetul este DEZACTIVAT"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Sunetul este ACTIVAT"</string>
@@ -224,6 +234,7 @@
     <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="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>
@@ -256,6 +267,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Include date personale, cum ar fi numere ale cardurilor de credit sau parole."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Controlați mărirea pe afișaj"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Controlați nivelul de zoom și poziționarea afișajului."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Folosiți gesturi"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Se poate atinge, glisa, ciupi și se pot folosi alte gesturi."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"dezactivare sau modificare bare de stare"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Permite aplicației să dezactiveze bara de stare sau să adauge și să elimine pictograme de sistem."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"să fie bara de stare"</string>
@@ -354,8 +367,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permite aplicației să realizeze fotografii și videoclipuri cu camera foto. Cu această permisiune aplicația utilizează camera foto oricând și fără confirmare."</string>
     <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_flashlight" msgid="2155920810121984215">"control lanternă"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite aplicației să controleze lanterna."</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="permlab_accessImsCallService" msgid="3574943847181793918">"accesează serviciul de apelare IMS"</string>
@@ -863,10 +874,13 @@
     <string name="cut" msgid="3092569408438626261">"Decupaţi"</string>
     <string name="copy" msgid="2681946229533511987">"Copiați"</string>
     <string name="paste" msgid="5629880836805036433">"Inserați"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Inserați ca text simplu"</string>
     <string name="replace" msgid="5781686059063148930">"Înlocuiţi..."</string>
     <string name="delete" msgid="6098684844021697789">"Ștergeți"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Copiați adresa URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Selectați text"</string>
+    <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="deleteText" msgid="6979668428458199034">"Ștergeți"</string>
@@ -1035,10 +1049,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Trimiteți raportul de eroare administratorului?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Administratorul IT a solicitat un raport de eroare pentru a remedia problemele"</string>
+    <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="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Se creează un raport de eroare…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Atingeți pentru a anula"</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="9157568568695230830">"Afișați metoda de introducere a textului"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardware"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1114,6 +1134,7 @@
     <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="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="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>
@@ -1449,12 +1470,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizat de un administrator"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Șters de administrator"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Pentru a îmbunătăți autonomia bateriei, funcția de economisire a energiei reduce performanțele dispozitivului și limitează vibrațiile, serviciile de localizare și majoritatea datelor de fundal. Este posibil ca e-mailurile, mesageria și alte aplicații care depind de sincronizare să nu se actualizeze dacă nu le deschideți.\n\nFuncția de economisire a energiei se dezactivează automat când dispozitivul se încarcă."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Importanță"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Blocate: aceste notificări nu se afișează niciodată"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Redusă: 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="7991157697609575271">"Normală: aceste notificări se afișează fără a se emite un sunet"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Ridicată: se afișează în partea de sus a listei cu notificări și se emite un sunet"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Urgente: se afișează pentru o scurtă durată pe ecran și se emite un sunet"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="few">Timp de %1$d minute (până la <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="other">Timp de %1$d de minute (până la <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1531,4 +1546,14 @@
     <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_person" msgid="9160133597262938296">"Notificarea este importantă având în vedere persoanele implicate."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" încearcă să adauge un nou utilizator, dar momentan nu îi este permis."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" încearcă să adauge un nou utilizator, dar a fost atinsă limita de utilizatori."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" încearcă să adauge un nou utilizator, dar contul "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" există deja pe acest dispozitiv. Continuați oricum?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" încearcă să adauge un nou utilizator pentru contul "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Continuați?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Limba preferată"</string>
+    <string name="country_selection_title" msgid="2954859441620215513">"Regiunea preferată"</string>
+    <string name="search_language_hint" msgid="7042102592055108574">"Scrieți nume limbă"</string>
+    <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugerate"</string>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Toate limbile"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Căutați"</string>
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 3b45d41..1185422 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -213,6 +213,17 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Отчет об ошибке"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Отчет об ошибке"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Информация о текущем состоянии вашего устройства будет собрана и отправлена по электронной почте. Подготовка отчета займет некоторое время."</string>
+    <string name="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 />
+    <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>
@@ -225,6 +236,7 @@
     <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="safeMode" msgid="2788228061547930246">"Безопасный режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"Личные данные"</string>
@@ -257,6 +269,8 @@
     <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>
@@ -355,8 +369,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Приложение сможет снимать фотографии и видеоролики с помощью камеры в любое время без вашего разрешения."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"Управление функцией вибросигнала"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Приложение сможет контролировать вибросигналы."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"Управление вспышкой"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Приложение сможет контролировать вспышку."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"Осуществление телефонных вызовов"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Приложение сможет без вашего участия звонить на любой номер телефона. Это не относится к номерам экстренных служб. Вредоносные программы смогут совершать вызовы без вашего разрешения, что может привести к непредвиденным расходам."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"совершение звонков с помощью службы IMS"</string>
@@ -868,10 +880,13 @@
     <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">"Удалить"</string>
@@ -1042,10 +1057,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Отправить администратору информацию об ошибке?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Ваш администратор запросил информацию об ошибке. Эти данные помогут устранить неполадку."</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ПРИНЯТЬ"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ОТКЛОНИТЬ"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Подождите…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Нажмите, чтобы отменить"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Выбор раскладки"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"Выбрать раскладку"</string>
-    <string name="show_ime" msgid="9157568568695230830">"Показать способ ввода"</string>
-    <string name="hardware" msgid="7517821086888990278">"Аппаратная"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1121,6 +1142,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Сменить обои"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Служба просмотра уведомлений"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Поставщик условий"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Ассистент уведомлений"</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>
@@ -1458,12 +1480,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"Важность"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Заблокировано: не показывать эти уведомления"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Низкая: показывать без звука в конце списка уведомлений"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Обычная: показывать уведомления без звука"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Высокая: показывать со звуком в начале списка уведомлений"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Срочно: показывать со звуковым сигналом поверх всех окон"</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>
@@ -1547,6 +1563,16 @@
       <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_person" msgid="9160133597262938296">"Эти люди для вас важны"</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"Вы определяете важность этих уведомлений."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"Важное (люди)"</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315">"Приложение "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" хочет добавить пользователя, однако в настоящее время это действие запрещено."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266">"Приложение "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" хочет добавить пользователя, однако лимит уже достигнут."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789">"Приложение "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" хочет добавить пользователя, однако аккаунт "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" уже есть на этом устройстве. Продолжить?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392">"Приложение "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" хочет добавить пользователя для аккаунта "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Продолжить?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Языковые настройки"</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>
 </resources>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 0fcb6b5..2cbf5ad 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"දෝෂ වර්තාව"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"දෝෂ වාර්තාවක් ගන්න"</string>
     <string name="bugreport_message" msgid="398447048750350456">"ඊ-තැපැල් පණිවිඩයක් ලෙස යැවීමට මෙය ඔබගේ වත්මන් උපාංග තත්වය ගැන තොරතුරු එකතු කරනු ඇත. දෝෂ වාර්තාව ආරම්භ කර එය යැවීමට සූදානම් කරන තෙක් එයට කිසියම් කාලයක් ගතවනු ඇත; කරුණාකර ඉවසන්න."</string>
+    <string name="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 />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">තත්පර <xliff:g id="NUMBER_1">%d</xliff:g>කින් දෝෂ වාර්තාව සඳහා තිර රුවක් ලබා ගනිමින්</item>
+      <item quantity="other">තත්පර <xliff:g id="NUMBER_1">%d</xliff:g>කින් දෝෂ වාර්තාව සඳහා තිර රුවක් ලබා ගනිමින්</item>
+    </plurals>
     <string name="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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"ආරක්‍ෂිත ආකාරය"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android පද්ධතිය"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"පෞද්ගලික"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"කැමරාවෙන් පින්තූර ගැනීමට සහ වීඩියෝ කිරීමට යෙදුමට අවසර දෙන්න. මෙම අවසරය මඟින් ඔබගේ අනුදැනුමකින් තොරව ඕනෑම වේලාවකදී කැමරාව භාවිතා කිරීමට යෙදුමට අවසර දෙන්න."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"කම්පනය පාලනය කිරීම"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"කම්පකය පාලනයට යෙදුමට අවසර දෙන්න."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"සැණෙළි ආලෝකය පාලනය කරන්න"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"සැණෙළිය පාලනයට යෙදුමට අවසර දෙන්න."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"දුරකථන අංක වෙත ඍජුවම අමතන්න"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"ඔබගේ මැදිහත් වීමක් නොමැතිව දුරකථන අංක ඇමතීමට යෙදුමට අවසර දෙන්න. මෙහි ප්‍රතිඑලය වන්නේ අනපේක්ෂිත අයකිරීම් හෝ ඇමතුම් ඇතිවීමයි. මෙයන් හදිසි අංක වලට ඇමතුම් ගැනීමට යෙදුමට අවසර නොදෙන බවට සටහන් කරගන්න. ඔබගේ අනුදැනුමක් නොමැතිව ඇමතුම් ගැනීමෙන් අනිෂ්ට යෙදුම් ඔබගේ මුදල් නිකරුණේ වැය කරයි."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ඇමතුම් සේවාවට පිවිසෙන්න"</string>
@@ -860,10 +870,13 @@
     <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">"මකන්න"</string>
@@ -1030,10 +1043,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"පරිපාලක සමඟ දෝෂ වාර්තාවක් බෙදා ගන්නද?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"දෝෂාවේක්ෂණය සඳහා උදවු කිරීමට ඔබේ IT පරිපාලක දෝෂ වාර්තාවක් ඉල්ලා ඇත"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"පිළිගන්න"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ප්‍රතික්ෂේප කරන්න"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"දෝෂ වාර්තාවක් ගනිමින්…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"අවලංගු කිරීමට ස්පර්ශ කරන්න"</string>
     <string name="select_input_method" msgid="8547250819326693584">"යතුරු පුවරු වෙනස් කිරීම"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"යතුරු පුවරු තෝරන්න"</string>
-    <string name="show_ime" msgid="9157568568695230830">"ආදාන ක්‍රමය පෙන්වන්න"</string>
-    <string name="hardware" msgid="7517821086888990278">"දෘඨාංග"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1109,6 +1128,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"බිතුපත වෙනස් කරන්න"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"දැනුම්දීම් අසන්නා"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"තත්ත්වය සපයන්නා"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"දැනුම්දීම් සහායක"</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>
@@ -1442,12 +1462,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"වැදගත්කම"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"අවහිර කළ: මෙම දැනුම්දීම් කිසිදා නොපෙන්වන්න"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"අඩු: දැනුම්දීම් ලැයිස්තුවෙහි පහළින්ම නිශ්ශබ්දව පෙන්වන්න"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"සාමාන්‍ය: නිශ්ශබ්දව මෙම දැනුම්දීම් පෙන්වන්න"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"වැඩි: දැනුම්දීම් ලැයිස්තුවෙහි ඉහළින්ම පෙන්වන්න සහ ශබ්ද කරන්න"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"හදිසි: තිරයට පැමිණ ශබ්ද කරන්න"</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="other">මිනිත්තු %1$d ක් සඳහා (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> තෙක්)</item>
@@ -1515,4 +1529,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"විවිධාකාර"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"ඔබ මෙම දැනුම්දීම්වල වැදගත්කම සකසා ඇත."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"සම්බන්ධ වූ පුද්ගලයන් නිසා මෙය වැදගත් වේ."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" නව පරිශීලකයෙකු එක් කිරීමට උත්සාහ කරමින් සිටින නමුත්, දැනට තහනම්ය."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" නව පරිශීලකයෙකු එක් කිරීමට උත්සාහ කරමින් සිටින නමුත්, පරිශීලක සීමාවට ළඟා වී ඇත."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" නව පරිශීලකයෙකු එක් කිරීමට උත්සාහ කරමින් සිටී, නමුත් "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" ගිණුම මෙම උපාංගය මත දැනටමත් පවතී. කෙසේ වෙතත් ඉදිරියට යන්නද?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" නව පරිශීලකයෙකු "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" ගිණුම සඳහා එක් කිරීමට උත්සාහ කරමින් සිටී. ඉදිරියට යන්නද?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"භාෂා මනාප"</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>
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index d26dcc6..8e08adc 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -213,6 +213,17 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Hlásenie o chybách"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Vytvoriť hlásenie chyby"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Týmto zhromaždíte informácie o aktuálnom stave zariadenia. Informácie je potom možné odoslať e-mailom, chvíľu však potrvá, kým bude hlásenie chyby pripravené na odoslanie. Prosíme vás preto o trpezlivosť."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktívne nahlásenie"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Táto možnosť je vhodná pre väčšinu prípadov. Umožňuje sledovať priebeh nahlásenia a zadať ďalšie podrobnosti o probléme. Môžu byť vynechané niektoré menej používané sekcie, ktorých nahlásenie trvá dlho."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Úplné nahlásenie"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="few">Snímka obrazovky pre hlásenie chyby sa vytvorí o <xliff:g id="NUMBER_1">%d</xliff:g> sekundy.</item>
+      <item quantity="many">Snímka obrazovky pre hlásenie chyby sa vytvorí o <xliff:g id="NUMBER_1">%d</xliff:g> sekundy.</item>
+      <item quantity="other">Snímka obrazovky pre hlásenie chyby sa vytvorí o <xliff:g id="NUMBER_1">%d</xliff:g> sekúnd.</item>
+      <item quantity="one">Snímka obrazovky pre hlásenie chyby sa vytvorí o <xliff:g id="NUMBER_0">%d</xliff:g> sekundu.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Tichý režim"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Zvuk je VYPNUTÝ."</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Zvuk je zapnutý"</string>
@@ -225,6 +236,7 @@
     <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="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>
@@ -257,6 +269,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Sledovanie zahŕňa osobné údaje ako sú čísla kreditných kariet a heslá."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Ovládanie priblíženia obrazovky"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ovládajte úroveň priblíženia/oddialenia obrazovky a umiestnenie"</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Gestá"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Je možné použiť klepnutie, prejdenie, stiahnutie prstami a ďalšie gestá."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"zakázanie alebo zmeny stavového riadka"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Umožňuje aplikácii vypnúť stavový riadok alebo pridať a odstrániť systémové ikony."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"vydávanie sa za stavový riadok"</string>
@@ -355,8 +369,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Umožňuje aplikácii fotografovať a nahrávať videá pomocou fotoaparátu. Toto povolenie umožňuje aplikácii používať fotoaparát kedykoľvek a bez vášho potvrdenia."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"ovládať vibrovanie"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Umožňuje aplikácii ovládať vibrácie."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ovládať kontrolku"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Umožňuje aplikácii ovládať svetlo."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"priamo volať na telefónne čísla"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Umožňuje aplikácii volať telefónne čísla bez vášho zásahu. V dôsledku toho sa môžu účtovať neočakávané poplatky alebo sa môžu uskutočniť neočakávané hovory. Toto povolenie neumožňuje aplikácii volať na čísla tiesňového volania."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"prístup k službe volania IMS"</string>
@@ -868,10 +880,13 @@
     <string name="cut" msgid="3092569408438626261">"Vystrihnúť"</string>
     <string name="copy" msgid="2681946229533511987">"Kopírovať"</string>
     <string name="paste" msgid="5629880836805036433">"Prilepiť"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Prilepiť ako obyčajný text"</string>
     <string name="replace" msgid="5781686059063148930">"Nahradiť•"</string>
     <string name="delete" msgid="6098684844021697789">"Odstrániť"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Skopírovať webovú adresu"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Vybrať text"</string>
+    <string name="undo" msgid="7905788502491742328">"Späť"</string>
+    <string name="redo" msgid="7759464876566803888">"Znova"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Výber textu"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Pridať do slovníka"</string>
     <string name="deleteText" msgid="6979668428458199034">"Odstrániť"</string>
@@ -1042,10 +1057,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Zdieľať hlásenie chyby so správcom?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Správca IT si vyžiadal hlásenie chyby, aby mohol problém vyriešiť"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"PRIJAŤ"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ODMIETNUŤ"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Vytvára sa hlásenie chyby…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Dotykom zrušíte"</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="9157568568695230830">"Zobraziť metódu vstupu"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardvér"</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="fast_scroll_alphabet" msgid="5433275485499039199">" AÁÄBCČDĎDZDŽEÉFGHCHIÍJKLĽMNŇOÓÔPRŔSŠTŤUÚVWXYÝZŽ"</string>
@@ -1121,6 +1142,7 @@
     <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="condition_provider_service_binding_label" msgid="1321343352906524564">"Poskytovateľ podmienky"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistent 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>
@@ -1458,12 +1480,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Aktualizované správcom"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Odstránený správcom"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"S cieľom predĺžiť výdrž batérie zníži šetrič batérie výkonnosť zariadenia a obmedzí vibrácie, služby určovania polohy a dátové prenosy na pozadí. Pošta, čet a ďalšie aplikácie, ktoré sa spoliehajú na synchronizáciu, sa možno nebudú aktualizovať, dokiaľ ich neotvoríte.\n\nPri nabíjaní zariadenia sa šetrič batérie automaticky vypne."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Dôležitosť"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokované: Tieto upozornenia nikdy nezobrazovať"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Nízke: Zobrazovať v dolnej časti zoznamu upozornení bez zvukového signálu"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normálne: Tieto upozornenia zobrazovať bez zvukového signálu"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Vysoké: Zobrazovať v hornej časti zoznamu upozornení so zvukovým signálom"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Neodkladné: Zobraziť cez obrazovku so zvukovým signálom"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="few">%1$d minúty (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="many">%1$d minúty (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1549,4 +1565,14 @@
     <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_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_cannot_add" msgid="7740333663230045315">"Aplikácia "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" sa pokúša pridať nového používateľa, avšak momentálne je zakázaná."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266">"Aplikácia "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" sa pokúša pridať nového používateľa, bol však prekročený limit počtu používateľov."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789">"Aplikácia "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" sa pokúša pridať nového používateľa, účet "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" však na tomto zariadení už existuje. Chcete napriek tomu pokračovať?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392">"Aplikácia "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" sa pokúša pridať nového používateľa pre účet "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Chcete pokračovať?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Jazykové predvoľby"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Všetky jazyky"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Vyhľadávanie"</string>
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index d840ecd..c85f7b5 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -213,6 +213,17 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Poročilo o napakah"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Ustvari poročilo o napakah"</string>
     <string name="bugreport_message" msgid="398447048750350456">"S tem bodo zbrani podatki o trenutnem stanju naprave, ki bodo poslani v e-poštnem sporočilu. Izvedba poročila o napakah in priprava trajata nekaj časa, zato bodite potrpežljivi."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktivno poročilo"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"To možnost uporabite v večini primerov. Omogoča sledenje napredka poročila in vnos več podrobnosti o težavi. Morda bodo izpuščeni nekateri redkeje uporabljani razdelki, za katere je poročanje dolgotrajno."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Celotno poročilo"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">Posnetek zaslona za poročilo o napakah bo narejen čez <xliff:g id="NUMBER_1">%d</xliff:g> s.</item>
+      <item quantity="two">Posnetek zaslona za poročilo o napakah bo narejen čez <xliff:g id="NUMBER_1">%d</xliff:g> s.</item>
+      <item quantity="few">Posnetek zaslona za poročilo o napakah bo narejen čez <xliff:g id="NUMBER_1">%d</xliff:g> s.</item>
+      <item quantity="other">Posnetek zaslona za poročilo o napakah bo narejen čez <xliff:g id="NUMBER_1">%d</xliff:g> s.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Tihi način"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Zvok je IZKLOPLJEN"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Zvok je VKLOPLJEN"</string>
@@ -225,6 +236,7 @@
     <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="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>
@@ -257,6 +269,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Vključuje osebne podatke, kot so številke kreditnih kartic in gesla."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Nadziranje povečave prikaza"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Nadziranje stopnje povečave in položaja prikaza."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Izvajanje potez"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Mogoče je izvajanje dotikov, vlečenja, primikanja in razmikanja prstov ter drugih potez."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"onemogočanje ali spreminjanje vrstice stanja"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Aplikacijam omogoča onemogočenje vrstice stanja ali dodajanje in odstranjevanje ikon sistema."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"postane vrstica stanja"</string>
@@ -355,8 +369,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Aplikaciji omogoča fotografiranje in snemanje videoposnetkov s kamero. S tem dovoljenjem lahko aplikacija kadar koli uporablja kamero brez vaše potrditve."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"nadzor vibriranja"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Aplikaciji omogoča nadzor vibriranja."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"nadzor svetilke"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Aplikaciji omogoča nadzor svetilke."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"neposredno klicanje telefonskih številk"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Aplikaciji omogoča klicanje telefonskih številk brez vašega posredovanja. Zaradi tega lahko pride do nepričakovanih stroškov ali klicev. Aplikaciji to ne dovoljuje opravljanja klicev v sili. Zlonamerne aplikacije lahko kličejo brez vaše potrditve, kar vas lahko drago stane."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"dostop do storitve za klicanje IMS"</string>
@@ -868,10 +880,13 @@
     <string name="cut" msgid="3092569408438626261">"Izreži"</string>
     <string name="copy" msgid="2681946229533511987">"Kopiraj"</string>
     <string name="paste" msgid="5629880836805036433">"Prilepi"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Prilepi kot navadno besedilo"</string>
     <string name="replace" msgid="5781686059063148930">"Zamenjaj •"</string>
     <string name="delete" msgid="6098684844021697789">"Izbriši"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Kopiraj URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Izbira besedila"</string>
+    <string name="undo" msgid="7905788502491742328">"Razveljavi"</string>
+    <string name="redo" msgid="7759464876566803888">"Uveljavi"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Izbrano besedilo"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Dodaj v slovar"</string>
     <string name="deleteText" msgid="6979668428458199034">"Izbriši"</string>
@@ -1042,10 +1057,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Želite skrbniku poslati poročilo o napakah?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Skrbnik IT je zahteval poročilo o napakah za pomoč pri odpravljanju napak"</string>
+    <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="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Zajemanje poročila o napakah …"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Če želite prekiniti, se dotaknite"</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="9157568568695230830">"Pokaži način vnosa"</string>
-    <string name="hardware" msgid="7517821086888990278">"Strojna oprema"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1121,6 +1142,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Spreminjanje ozadja"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Poslušalec obvestil"</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="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>
@@ -1458,12 +1480,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Posodobil skrbnik"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Izbrisal skrbnik"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Varčevanje z energijo akumulatorja podaljša čas njegovega delovanja tako, da zmanjša zmogljivost delovanja naprave in omeji vibriranje, lokacijske storitve ter prenos večine podatkov v ozadju. Aplikacije za e-pošto, sporočanje in drugo, ki uporabljajo sinhroniziranje, se morda ne posodabljajo, razen če jih odprete.\n\nVarčevanje z energijo akumulatorja se samodejno izklopi med polnjenjem akumulatorja naprave."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Pomembnost"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokirano: nikoli ne prikaži teh obvestil"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Manj pomembno: prikaži na dnu seznama obvestil brez zvoka"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Običajno: prikaži ta obvestila brez zvoka"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Pomembno: prikaži na vrhu seznama obvestil in predvajaj zvok"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Nujno: za hip pokaži predogled na zaslonu in predvajaj zvok"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="one">%d minuto (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="two">%d minuti (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1549,4 +1565,14 @@
     <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_person" msgid="9160133597262938296">"Pomembno zaradi udeleženih ljudi."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315">"Aplikacija "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" poskuša dodati novega uporabnika, vendar trenutno nima dovoljenja."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266">"Aplikacija "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" poskuša dodati novega uporabnika, vendar je dosežena omejitev števila uporabnikov."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789">"Aplikacija "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" poskuša dodati novega uporabnika, vendar račun "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" v napravi že obstaja. Ali želite kljub temu nadaljevati?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392">"Aplikacija "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" poskuša dodati novega uporabnika za račun "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Ali želite nadaljevati?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Nastavitev 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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Vsi jeziki"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Išči"</string>
 </resources>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index 4365796c..65156f0 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Raporti i defekteve në kod"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Merr raportin e defekteve në kod"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Ky funksion mundëson mbledhjen e informacioneve mbi gjendjen aktuale të pajisjes për ta dërguar si mesazh mail-i. Do të duhet pak kohë nga nisja e raportit të defekteve në kod. Faleminderit për durimin."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Raport interaktiv"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Përdore këtë në shumicën e rrethanave. Të lejon të gjurmosh progresin e raportit dhe të fusësh më shumë detaje rreth problemit. Mund të fshijë disa seksione që përdoren më pak të cilat kërkojnë shumë kohë për t\'u raportuar."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Raporti i plotë"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Marrja e pamjes së ekranit për raportin e defektit në kod në <xliff:g id="NUMBER_1">%d</xliff:g> sekonda.</item>
+      <item quantity="one">Marrja e pamjes së ekranit për raportin e defektit në kod në <xliff:g id="NUMBER_0">%d</xliff:g> sekondë.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modaliteti \"në heshtje\""</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Zëri është çaktivizuar"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Zëri është i aktivizuar"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Përfshi të dhënat personale si numrat e kartave të kreditit si dhe fjalëkalimet."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Kontrollo zmadhimin e ekranit"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrollo nivelin dhe pozicionimin e zmadhimit të ekranit."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Kryen gjeste"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Mund të trokasë, rrëshqasë, bashkojë gishtat dhe kryejë gjeste të tjera."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"çaktivizo ose modifiko shiritin e statusit"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Lejon aplikacionin të çaktivizojë shiritin e statusit dhe të heqë ikonat e sistemit."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"të bëhet shiriti i statusit"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Lejon aplikacion të krijojë fotografi dhe video me kamerën. Kjo leje mundëson përdorimin e kamerës në çdo kohë pa konfirmimin tënd."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"kontrollo dridhjen"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Lejon aplikacionin të kontrollojë dridhësin."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"kontrollo elektrikun"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Lejon aplikacionin të kontrollojë elektrikun."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"telefono drejtpërdrejt numrat e telefonit"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Lejon aplikacionin të telefonojë numra pa ndërhyrjen tënde. Kjo mund të rezultojë në tarifa ose telefonata të papritura. Ki parasysh se kjo nuk e lejon aplikacionin të telefonojë numra urgjence. Aplikacione keqdashëse mund të të kushtojnë para duke kryer telefonata pa konfirmimin tënd."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"qasje në shërbimin e telefonatave IMS"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Pri"</string>
     <string name="copy" msgid="2681946229533511987">"Kopjo"</string>
     <string name="paste" msgid="5629880836805036433">"Ngjit"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Ngjite si tekst të thjeshtë"</string>
     <string name="replace" msgid="5781686059063148930">"Zëvendëso…"</string>
     <string name="delete" msgid="6098684844021697789">"Fshi"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Kopjo URL-në"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Përzgjidh tekstin"</string>
+    <string name="undo" msgid="7905788502491742328">"Zhbëj"</string>
+    <string name="redo" msgid="7759464876566803888">"Ribëj"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Përzgjedhja e tekstit"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Shto në fjalor"</string>
     <string name="deleteText" msgid="6979668428458199034">"Fshi"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Ndaje raportin e defekteve në kod me administratorin?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Administratori i teknologjisë së informacionit kërkoi një raport të defekteve në kod për të ndihmuar me zgjidhjen e problemeve"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"PRANO"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"REFUZO"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Po merret raporti i defekteve në kod…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Prek për ta anuluar"</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="9157568568695230830">"Shfaq metodën e hyrjes"</string>
-    <string name="hardware" msgid="7517821086888990278">"Harduer"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <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="condition_provider_service_binding_label" msgid="1321343352906524564">"Ofrues kushtesh"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistenti i 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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Përditësuar nga administratori"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"U fshi nga administratori yt"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Për të përmirësuar jetëgjatësinë e baterisë, opsioni i kursimit të baterisë ul rendimentin e pajisjes tënde si dhe kufizon dridhjet dhe shumicën e të dhënave në sfond. Mail-i, mesazhet dhe aplikacionet e tjera që sinkronizohen automatikisht mund të mos përditësohen pa i hapur.\n\nKursimi i baterisë çaktivizohet automatikisht kur pajisja vihet në ngarkim."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Rëndësia"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Të bllokuara: Mos i shfaq asnjëherë këto njoftime"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Të ulëta: Shfaqi në heshtje në fund të listës së njoftimeve"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normale: Shfaqi këto njoftime në heshtje"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Të larta: Shfaqi në krye të listës së njoftimeve dhe lësho tingull"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Urgjente: Shfaq një vështrim të shpejtë në ekran dhe lësho tingull"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">Për %1$d minuta (deri në <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">Për një minutë (deri në <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"Është i rëndësishëm për shkak të personave të përfshirë."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" po përpiqet të shtojë një përdorues të ri, por aktualisht nuk i lejohet."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" po përpiqet të shtojë një përdorues të ri, por është arritur limiti i përdoruesve."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" po provon të shtojë një përdorues të ri, por llogaria "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" ekziston tashmë në këtë pajisje. Dëshiron të vazhdosh gjithsesi?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" po provon të shtojë një përdorues të ri për llogarinë "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Dëshiron të vazhdosh?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Preferenca për gjuhën"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Të gjitha gjuhët"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Kërko"</string>
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 4e195cc..fe7b0d7 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -212,6 +212,16 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Извештај о грешци"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Направи извештај о грешци"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Овим ће се прикупити информације о тренутном стању уређаја како би биле послате у поруци е-поште. Од започињања извештаја о грешци до тренутка за његово слање проћи ће неко време; будите стрпљиви."</string>
+    <string name="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 />
+    <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="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>
@@ -224,6 +234,7 @@
     <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="safeMode" msgid="2788228061547930246">"Безбедни режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android систем"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"Лично"</string>
@@ -256,6 +267,8 @@
     <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>
@@ -354,8 +367,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Дозвољава апликацији да снима слике и видео снимке камером. Ова дозвола омогућава апликацији да у било ком тренутку користи камеру без ваше потврде."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"контрола вибрације"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Дозвољава апликацији да контролише вибрацију."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"контрола осветљења"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Дозвољава апликацији да контролише блиц."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"директно позивање бројева телефона"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Дозвољава апликацији да позива бројеве телефона без ваше дозволе. Ово може да доведе до неочекиваних трошкова или позива. Имајте на уму да ово не дозвољава апликацији да позива бројеве за хитне случајеве. Злонамерне апликације могу да позивају без ваше потврде, што може да доведе до трошкова."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"приступ услузи позива помоћу размене тренутних порука"</string>
@@ -863,10 +874,13 @@
     <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">"Избриши"</string>
@@ -1035,10 +1049,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Желите ли да делите извештај о грешци са администратором?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"ИТ администратор је затражио извештај о грешци ради лакшег решавања проблема"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ПРИХВАТИ"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ОДБИЈ"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Извештај о грешци се генерише…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Додирните да бисте отказали"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Промените тастатуру"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"Изаберите тастатуре"</string>
-    <string name="show_ime" msgid="9157568568695230830">"Приказивање метода уноса"</string>
-    <string name="hardware" msgid="7517821086888990278">"Хардвер"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1114,6 +1134,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Промена позадине"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Монитор обавештења"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Добављач услова"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Помоћник за обавештења"</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>
@@ -1449,12 +1470,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"Важност"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Блокирана: Ова обавештења се никада не приказују"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Ниска: Приказују се у дну листе обавештења без звука"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Уобичајена: Ова обавештења се приказују без звука"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Висока: Приказују се у врху листе обавештења и активира се звучни сигнал"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Хитна: Накратко се приказују на екрану и активира се звучни сигнал"</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>
@@ -1531,4 +1546,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"Разно"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"Ви подешавате важност ових обавештења."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ово је важно због људи који учествују."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" покушава да дода новог корисника, али то је тренутно забрањено."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" покушава да дода новог корисника, али је ограничење за број корисника достигнуто."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" покушава да дода новог корисника, али налог "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" већ постоји на овом уређају. Желите ли ипак да наставите?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" покушава да дода новог корисника за налог "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Желите ли да наставите?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Подешавање језика"</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>
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 8986073..d80b4c2 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Felrapport"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Skapa felrapport"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Nu hämtas information om aktuell status för enheten, som sedan skickas i ett e-postmeddelade. Det tar en liten stund innan felrapporten är färdig och kan skickas, så vi ber dig ha tålamod."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktiv rapport"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Bör användas i de flesta fall. Då kan du spåra rapportförloppet och ange mer information om problemet. En del mindre använda avsnitt, som det tar lång tid att rapportera om, kan uteslutas."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Fullständig rapport"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Tar en skärmdump till felrapporten om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder.</item>
+      <item quantity="one">Tar en skärmdump till felrapporten om <xliff:g id="NUMBER_0">%d</xliff:g> sekund.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Tyst läge"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Ljudet är AV"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Ljudet är PÅ"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Omfattar personuppgifter som kreditkortsnummer och lösenord."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Styr skärmförstoringen"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Styr skärmens zoomnivå och positionering."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Göra rörelser"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Kan trycka, svepa, nypa och göra andra rörelser."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"inaktivera eller ändra statusfält"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Tillåter att appen inaktiverar statusfältet eller lägger till och tar bort systemikoner."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"visas i statusfältet"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Tillåter att appen tar bilder och spelar in videor med kameran. Med den här behörigheten tillåts appen att använda kameran när som helst utan ditt godkännande."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"styra vibration"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Tillåter att appen styr vibrationen."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"styra lampa"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Tillåter att appen styr lampan."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ringa telefonnummer direkt"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Tillåter att appen ringer telefonnummer utan någon aktiv åtgärd från dig. Detta kan leda till oväntade avgifter och samtal. Observera att appen inte tillåts ringa nödsamtal. Skadliga appar kan ringa utan ditt godkännande och detta kan kosta pengar."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"tillgång till tjänsten för snabbmeddelanden vid samtal"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Klipp ut"</string>
     <string name="copy" msgid="2681946229533511987">"Kopiera"</string>
     <string name="paste" msgid="5629880836805036433">"Klistra in"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Klistra in som oformaterad text"</string>
     <string name="replace" msgid="5781686059063148930">"Ersätt..."</string>
     <string name="delete" msgid="6098684844021697789">"Ta bort"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Kopiera webbadress"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Markera text"</string>
+    <string name="undo" msgid="7905788502491742328">"Ångra"</string>
+    <string name="redo" msgid="7759464876566803888">"Gör om"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Textmarkering"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Lägg till i ordlista"</string>
     <string name="deleteText" msgid="6979668428458199034">"Ta bort"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Vill du dela en felrapport med administratören?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"IT-administratören har bett om en felrapport som hjälp vid felsökningen."</string>
+    <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="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Felrapporten överförs …"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Tryck här om du vill avbryta"</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="9157568568695230830">"Visa inmatningsmetod"</string>
-    <string name="hardware" msgid="7517821086888990278">"Maskinvara"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Ändra bakgrund"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Meddelandelyssnare"</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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Uppdaterat av administratören"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Paketet har raderats av administratören"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"I batterisparläget reduceras enhetens prestanda så att batteriet ska räcka längre och vibration, platstjänster samt den mesta användningen av bakgrundsdata begränsas. Det kan hända att appar för e-post, sms och annat som kräver synkronisering inte uppdateras förrän du öppnar dem.\n\nBatterisparläget inaktiveras automatiskt när enheten laddas."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Relevans"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Blockerad: Visa aldrig dessa aviseringar"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Låg: Visa längst ned i aviseringslistan – utan ljud"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Visa aviseringarna – utan ljud"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Hög: Visa högst upp i aviseringslistan – med ljud"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Brådskande: Visa på skärmen – med ljud"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">I %1$d minuter (till kl. <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">I en minut (till kl. <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"Detta är viktigt på grund av personerna som deltar."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" försöker lägga till en ny användare, men får inte göra det för närvarande."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" försöker lägga till en ny användare, men gränsen för antal användare har uppnåtts."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" försöker lägga till en ny användare, men kontot "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" finns redan på den här enheten. Vill du fortsätta ändå?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" försöker lägga till en ny användare för kontot "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Vill du fortsätta?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Språkinställning"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Alla språk"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Söka"</string>
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 7d0f3ca..5ae50b8 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -213,6 +213,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Ripoti ya hitilafu"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Chukua ripoti ya hitilafu"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Hii itakusanya maelezo kuhusu hali ya kifaa chako kwa sasa, na itume kama barua pepe. Itachukua muda mfupi tangu ripoti ya hitilafu ianze kuzalishwa hadi iwe tayari kutumwa; vumilia."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Ripoti ya kushirikiana"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Itumie katika hali nyingi. Inakuruhusu kufuatilia maendeleo ya ripoti na kuweka maelezo zaidi kuhusu tatizo. Huenda ikaondoa sehemu ambazo hazitumiki sana, ambazo huchukua muda mrefu kuripoti."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Ripoti kamili"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Inapiga picha ya skrini ili iripoti hitilafu baada ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>.</item>
+      <item quantity="one">Inapiga picha ya skrini ili iripoti hitilafu baada ya sekunde <xliff:g id="NUMBER_0">%d</xliff:g>.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Mtindo wa kimya"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Sauti Imezimwa"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Sauti imewashwa"</string>
@@ -225,6 +234,7 @@
     <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="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>
@@ -257,6 +267,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Inajumuisha data binafsi kama vile nambari za kadi ya mkopo na manenosiri."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Dhibiti ukuzaji wa onyesho"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Dhibiti kiwango cha kukuza na nafasi cha onyesho."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Tekeleza ishara"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Unaweza kugonga, kutelezesha kidole, kubana na kutekeleza ishara zingine."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"zima au rekebisha mwambaa hali"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Inaruhusu programu kulemaza upau wa hali au kuongeza na kutoa ikoni za mfumo."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"kuwa sehemu ya arifa"</string>
@@ -355,8 +367,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Inaruhusu programu kupiga picha na video kwa kamera. Kibali hiki kinaruhusu programu kutumia kamera kwa wakati wowote bila uthibitisho wako."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"Kudhibiti mtetemo"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Inaruhusu programu kudhibiti kitingishi."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"dhibiti tochi"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Inaruhusu programu kudhibiti tochi."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"piga simu moja kwa moja kwa nambari za simu"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Inaruhusu programu kupiga nambari za simu bila ya wewe kuingilia kati. Hii inaweza kusababisha gharama zisizotarajiwa au simu. Kumbuka kuwa hii hairuhusu programu kupiga nambari za dharura. Programu hasidi zinaweza kukugharimu pesa kwa kupiga simu bila uthibitisho wako."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"fikia huduma ya simu ya IMS"</string>
@@ -794,7 +804,7 @@
     <string name="save_password_remember" msgid="6491879678996749466">"Kumbuka"</string>
     <string name="save_password_never" msgid="8274330296785855105">"Katu"</string>
     <string name="open_permission_deny" msgid="7374036708316629800">"Hauna idhini ya kufungua ukurasa huu."</string>
-    <string name="text_copied" msgid="4985729524670131385">"Maandishi yamenakiliwa kwenye ubao klipu."</string>
+    <string name="text_copied" msgid="4985729524670131385">"Maandishi yamenakiliwa kwenye ubao wa kunakili."</string>
     <string name="more_item_label" msgid="4650918923083320495">"Zaidi"</string>
     <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menyu+"</string>
     <string name="menu_space_shortcut_label" msgid="2410328639272162537">"mwanya"</string>
@@ -860,10 +870,13 @@
     <string name="cut" msgid="3092569408438626261">"Kata"</string>
     <string name="copy" msgid="2681946229533511987">"Nakala"</string>
     <string name="paste" msgid="5629880836805036433">"Bandika"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Bandika kama maandishi dhahiri"</string>
     <string name="replace" msgid="5781686059063148930">"Badilisha..."</string>
     <string name="delete" msgid="6098684844021697789">"Futa"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Nakili URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Chagua maandishi"</string>
+    <string name="undo" msgid="7905788502491742328">"Tendua"</string>
+    <string name="redo" msgid="7759464876566803888">"Rejesha"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Uchaguzi wa maandishi?"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Ongeza kwenye kamusi"</string>
     <string name="deleteText" msgid="6979668428458199034">"Futa"</string>
@@ -1030,10 +1043,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Ungependa kushiriki ripoti ya hitilafu na msimamizi?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Msimamizi wako wa IT ameomba ripoti ya hitilafu ili kusaidia katika utatuzi"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"KUBALI"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"KATAA"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Inatayarisha ripoti ya hitilafu…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Gusa ili ufute"</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="9157568568695230830">"Onyesha mbinu ya kuingiza"</string>
-    <string name="hardware" msgid="7517821086888990278">"Maunzi"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1109,6 +1128,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Badilisha mandhari"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Kisikilizi cha arifa"</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="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>
@@ -1442,12 +1462,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Kimesasiswa na msimamizi wako"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Kilifutwa na msimamizi wako"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Kusaidia kuboresha muda wa matumizi ya betri, inayookoa betri hupunguza utendaji wa kifaa chako na kupunguza mtetemo, huduma za utambuzi wa mahali, na data nyingi ya chini chini. Barua pepe, ujumbe na programu nyingine zinazotege,ea usawazishaji huenda zisisasishwe usipozifungua.\n\nInayookoa betri hujizima kiotomatiki kifaa chako kinapokuwa kinachaji."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Umuhimu"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Imezuiwa: Usionyeshe arifa hizi kamwe"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Chini: Onyesha katika sehemu ya chini ya orodha ya arifa bila kutoa sauti"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Kawaida: Onyesha arifa hizi bila sauti"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Juu: Onyesha katika sehemu ya juu ya orodha ya arifa na itoe sauti"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Muhimu: Weka onyesho la kuchungulia kwenye skrini na itoe sauti"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">Kwa dakika %1$d (hadi <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">Kwa dakika moja (hadi <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1515,4 +1529,14 @@
     <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_person" msgid="9160133597262938296">"Hii ni muhimu kwa sababu ya watu waliohusika."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" inajaribu kuongeza mtumiaji mpya, lakini hatua hii hairuhusiwi kwa sasa."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" inajaribu kuongeza mtumiaji mpya, lakini idadi ya juu ya watumiaji imefikiwa."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" inajaribu kuongeza mtumiaji mpya, lakini akaunti ya "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" tayari ipo kwenye kifaa hiki. Ungependa kundelea?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" inajaribu kuongeza mtumiaji mpya kwenye akaunti ya "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Ungependa kuendelea?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Lugha ninayopendelea"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Lugha zote"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Tafuta"</string>
 </resources>
diff --git a/core/res/res/values-sw600dp/config.xml b/core/res/res/values-sw600dp/config.xml
index 5a007ce..7f57ded 100644
--- a/core/res/res/values-sw600dp/config.xml
+++ b/core/res/res/values-sw600dp/config.xml
@@ -40,5 +40,6 @@
     <!-- Use a larger scaling span for larger screen devices. -->
     <dimen name="config_minScalingSpan">32mm</dimen>
 
+    <integer name="config_dockedStackDividerSnapMode">1</integer>
 </resources>
 
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index e419eea..4671344 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"பிழை அறிக்கை"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"பிழை அறிக்கையை எடு"</string>
     <string name="bugreport_message" msgid="398447048750350456">"உங்கள் நடப்புச் சாதன நிலையை மின்னஞ்சல் செய்தியாக அனுப்ப, அது குறித்த தகவலை இது சேகரிக்கும். பிழை அறிக்கையைத் தொடங்குவதில் இருந்து, அது அனுப்புவதற்குத் தயாராகும் வரை, இதற்குச் சிறிது நேரம் ஆகும்; பொறுமையாகக் காத்திருக்கவும்."</string>
+    <string name="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 />
+    <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>
+    </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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"பாதுகாப்பு பயன்முறை"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android அமைப்பு"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"தனிப்பட்ட"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"கேமரா மூலமாகப் படங்களையும், வீடியோக்களையும் எடுக்க பயன்பாட்டை அனுமதிக்கிறது. உங்கள் உறுதிப்படுத்தல் இன்றி கேமராவை எந்நேரத்திலும் பயன்படுத்தப் பயன்பாட்டை இது அனுமதிக்கிறது."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"அதிர்வைக் கட்டுப்படுத்துதல்"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"அதிர்வைக் கட்டுப்படுத்தப் பயன்பாட்டை அனுமதிக்கிறது."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ஃப்லாஷ்லைட்டை இயக்குதல்"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"ஃப்ளாஷ் லைட்டைக் கட்டுப்படுத்த, பயன்பாட்டை அனுமதிக்கிறது."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"தொலைபேசி எண்களை நேரடியாக அழைத்தல்"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"உங்கள் தலையீட்டின்றி மொபைல் எண்களை அழைக்கப் பயன்பாட்டை அனுமதிக்கிறது. இதன் விளைவாக எதிர்பாராத கட்டணங்களோ அழைப்புகளோ ஏற்படலாம். அவசரகால எண்களை அழைக்க இது பயன்பாட்டை அனுமதிக்காது என்பதை நினைவில்கொள்ளவும். தீங்கிழைக்கும் பயன்பாடுகள், உங்கள் உறுதிப்படுத்தல் இன்றி அழைப்புகளைச் செய்வதால் உங்களுக்குச் செலவு ஏற்படக்கூடும்."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS அழைப்புச் சேவையை அணுகுதல்"</string>
@@ -858,10 +868,13 @@
     <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">"நீக்கு"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"பிழை அறிக்கையை நிர்வாகியுடன் பகிரவா?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"பிழைகாண்பதற்கு உதவ, உங்கள் ஐடி நிர்வாகி பிழை அறிக்கையைக் கோரியுள்ளார்"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"சரி"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"வேண்டாம்"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"பிழை அறிக்கையை எடுக்கிறது…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"ரத்துசெய்ய, தொடவும்"</string>
     <string name="select_input_method" msgid="8547250819326693584">"விசைப்பலகையை மாற்று"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"விசைப்பலகைகளைத் தேர்வுசெய்க"</string>
-    <string name="show_ime" msgid="9157568568695230830">"உள்ளீட்டு முறையைக் காட்டு"</string>
-    <string name="hardware" msgid="7517821086888990278">"வன்பொருள்"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"வால்பேப்பரை மாற்று"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"அறிவிப்புகளைக் கண்காணிக்கும் சேவை"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"நிபந்தனை வழங்குநர்"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"அறிவிப்பு உதவி"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"முக்கியத்துவம்"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"தடுக்கப்பட்டது: இந்த அறிவிப்புகளை ஒருபோதும் காட்டாது"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"குறைவு: ஒலியின்றி அறிவிப்புப் பட்டியலின் கீழே காட்டும்"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"இயல்பு: ஒலியின்றி இந்த அறிவிப்புகளைக் காட்டும்"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"அதிகம்: அறிவிப்புகள் பட்டியலின் மேல் பகுதியில் ஒலியுடன் காட்டும்"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"அவசரம்: ஒலியுடன் திரையில் தோன்றும்"</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">ஒரு நிமிடத்திற்கு (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> வரை)</item>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"இதர அமைப்பு"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"இந்த அறிவிப்புகளின் முக்கியத்துவத்தை அமைத்துள்ளீர்கள்."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ஈடுபட்டுள்ளவர்களின் காரணமாக, இது முக்கியமானது."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" பயன்பாடு புதிய பயனரைச் சேர்க்க முயல்கிறது, ஆனால் பயனரைச் சேர்ப்பது தற்போது தடுக்கப்பட்டுள்ளது."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" பயன்பாடு புதிய பயனரைச் சேர்க்க முயல்கிறது, ஆனால் பயனருக்கான வரம்பு முடிந்துவிட்டது."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" பயன்பாடு புதிய பயனரைச் சேர்க்க முயல்கிறது. ஆனால் "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" கணக்கு ஏற்கனவே இந்தச் சாதனத்தில் உள்ளது. தொடரவா?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" பயன்பாடு "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" கணக்கிற்குப் புதிய பயனரைச் சேர்க்க முயல்கிறது. தொடரவா?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"மொழி விருப்பம்"</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>
 </resources>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index a6c80ad..8535b9c 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"బగ్ నివేదిక"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"బగ్ నివేదికను సిద్ధం చేయి"</string>
     <string name="bugreport_message" msgid="398447048750350456">"ఇది ఇ-మెయిల్ సందేశం రూపంలో పంపడానికి మీ ప్రస్తుత పరికర స్థితి గురించి సమాచారాన్ని సేకరిస్తుంది. బగ్ నివేదికను ప్రారంభించడం మొదలుకొని పంపడానికి సిద్ధం చేసే వరకు ఇందుకు కొంత సమయం పడుతుంది; దయచేసి ఓపిక పట్టండి."</string>
+    <string name="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 />
+    <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>
+    </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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"సురక్షిత మోడ్"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android సిస్టమ్"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"వ్యక్తిగతం"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"కెమెరాతో చిత్రాలు మరియు వీడియోలను తీయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. ఈ అనుమతి మీ నిర్ధారణ లేకుండానే ఎప్పుడైనా కెమెరాను ఉపయోగించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"వైబ్రేషన్‌ను నియంత్రించడం"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"వైబ్రేటర్‌ను నియంత్రించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ఫ్లాష్‌కాంతిని నియంత్రించడం"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"ఫ్లాష్‌లైట్‌ను నియంత్రించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ఫోన్ నంబర్‌లకు నేరుగా కాల్ చేయడం"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"మీ ప్రమేయం లేకుండా ఫోన్ నంబర్‌లకు కాల్ చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. దీని వలన అనుకోని ఛార్జీలు విధించబడవచ్చు లేదా కాల్‌లు రావచ్చు. ఇది అత్యవసర నంబర్‌లకు కాల్ చేయడానికి అనువర్తనాన్ని అనుమతించదని గుర్తుంచుకోండి. హానికరమైన అనువర్తనాలు మీ నిర్ధారణ లేకుండానే కాల్‌లు చేయడం ద్వారా మీకు డబ్బు ఖర్చయ్యేలా చేయవచ్చు."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS కాల్ సేవ ప్రాప్యత అనుమతి"</string>
@@ -858,10 +868,13 @@
     <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">"తొలగించు"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"బగ్ నివేదికను నిర్వాహకులకు భాగస్వామ్యం చేయాలా?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"మీ ఐటి నిర్వాహకులు సమస్య పరిష్కారాన్ని కనుగొనడంలో సహాయం కోసం బగ్ నివేదికను అభ్యర్థించారు"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ఆమోదిస్తున్నాను"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"తిరస్కరిస్తున్నాను"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"బగ్ నివేదికను తీస్తోంది…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"రద్దు చేయడానికి తాకండి"</string>
     <string name="select_input_method" msgid="8547250819326693584">"కీబోర్డ్‌ను మార్చు"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"కీబోర్డ్‌లను ఎంచుకోండి"</string>
-    <string name="show_ime" msgid="9157568568695230830">"ఇన్‌పుట్ పద్ధతిని చూపు"</string>
-    <string name="hardware" msgid="7517821086888990278">"హార్డ్‌వేర్"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"వాల్‌పేపర్‌ను మార్చండి"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"నోటిఫికేషన్ పరిశీలన"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"షరతు ప్రదాత"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"నోటిఫికేషన్ సహాయకం"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"ప్రాముఖ్యత"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"బ్లాక్ చేయబడింది: ఈ నోటిఫికేషన్‌లను ఎప్పుడూ చూపదు"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"తక్కువ: నోటిఫికేషన్‌ల జాబితా దిగువ భాగంలో శబ్దం లేకుండా చూపుతుంది"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"సాధారణం: ఈ నోటిఫికేషన్‌లను శబ్దం లేకుండా చూపుతుంది"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"అధికం: నోటిఫికేషన్‌ల జాబితా ఎగువ భాగంలో శబ్దంతో చూపుతుంది"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"అత్యవసరం: స్క్రీన్‌పై శీఘ్రంగా శబ్దంతో చూపుతుంది"</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">ఒక నిమిషం పాటు (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> వరకు)</item>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"ఇతరాలు"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"మీరు ఈ నోటిఫికేషన్‌ల ప్రాముఖ్యతను సెట్ చేసారు."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ఇందులో పేర్కొనబడిన వ్యక్తులను బట్టి ఇది చాలా ముఖ్యమైనది."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" కొత్త వినియోగదారుని జోడించడానికి ప్రయత్నిస్తోంది, కానీ ప్రస్తుతం ఇది నిషిద్ధం."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" కొత్త వినియోగదారుని జోడించడానికి ప్రయత్నిస్తోంది, కానీ వినియోగదారు పరిమితి చేరుకుంది."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" కొత్త వినియోగదారుని జోడించడానికి ప్రయత్నిస్తోంది, కానీ ఖాతా "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" ఇప్పటికే ఈ పరికరంలో ఉంది. ఏదేమైనా కొనసాగించాలా?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ఖాతా "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" కోసం కొత్త వినియోగదారుని జోడించడానికి ప్రయత్నిస్తోంది. కొనసాగించాలా?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"భాష ప్రాధాన్యత"</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>
 </resources>
diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml
index 3435474..0f98cfb 100644
--- a/core/res/res/values-television/config.xml
+++ b/core/res/res/values-television/config.xml
@@ -23,4 +23,12 @@
 
     <!-- Flags enabling default window features. See Window.java -->
     <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>
+
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 518a629..a759145 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"รายงานข้อบกพร่อง"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"ใช้รายงานข้อบกพร่อง"</string>
     <string name="bugreport_message" msgid="398447048750350456">"การดำเนินการนี้จะรวบรวมข้อมูลเกี่ยวกับสถานะปัจจุบันของอุปกรณ์ของคุณ โดยจะส่งไปในรูปแบบข้อความอีเมล อาจใช้เวลาสักครู่ตั้งแต่เริ่มการสร้างรายงานข้อบกพร่องจนกระทั่งเสร็จสมบูรณ์ โปรดอดทนรอ"</string>
+    <string name="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 />
+    <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>
+    </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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"โหมดปลอดภัย"</string>
     <string name="android_system_label" msgid="6577375335728551336">"ระบบ Android"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"ส่วนตัว"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"อนุญาตให้แอปพลิเคชันถ่ายภาพและวิดีโอด้วยกล้องถ่ายรูปนี้ การอนุญาตนี้จะทำให้แอปพลิเคชันสามารถใช้กล้องถ่ายรูปได้ทุกเมื่อโดยไม่ต้องรอการยืนยันจากคุณ"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"ควบคุมการสั่นเตือน"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"อนุญาตให้แอปพลิเคชันควบคุมการสั่นเตือน"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ควบคุมไฟฉาย"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"อนุญาตให้แอปพลิเคชันควบคุมไฟฉาย"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"โทรติดต่อหมายเลขโทรศัพท์โดยตรง"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"อนุญาตให้แอปพลิเคชันโทรเข้าโทรศัพท์โดยไม่ต้องให้คุณจัดการ ซึ่งอาจทำให้มีการเรียกเก็บเงินหรือการโทรที่ไม่คาดคิด โปรดทราบว่าการทำงานนี้ไม่ได้อนุญาตให้แอปพลิเคชันโทรไปหมายเลขฉุกเฉิน แอปพลิเคชันที่เป็นอันตรายอาจทำให้คุณต้องเสียค่าบริการด้วยการโทรโดยไม่ขอการยืนยันจากคุณ"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"เข้าถึงบริการโทร IMS"</string>
@@ -858,10 +868,13 @@
     <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">"ลบ"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"ต้องการแชร์รายงานข้อบกพร่องกับผู้ดูแลระบบไหม"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"ผู้ดูแลระบบไอทีของคุณขอรายงานข้อบกพร่องเพื่อช่วยในการแก้ไขปัญหา"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ยอมรับ"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ปฏิเสธ"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"กำลังสร้างรายงานข้อบกพร่อง…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"แตะเพื่อยกเลิก"</string>
     <string name="select_input_method" msgid="8547250819326693584">"เปลี่ยนแป้นพิมพ์"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"เลือกแป้นพิมพ์"</string>
-    <string name="show_ime" msgid="9157568568695230830">"แสดงวิธีการป้อนข้อมูล"</string>
-    <string name="hardware" msgid="7517821086888990278">"ฮาร์ดแวร์"</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="fast_scroll_alphabet" msgid="5433275485499039199">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"เปลี่ยนวอลเปเปอร์"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"ตัวฟังการแจ้งเตือน"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ผู้เสนอเงื่อนไข"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"ผู้ช่วยการแจ้งเตือน"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"ความสำคัญ"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"บล็อก: อย่าแสดงการแจ้งเตือนเหล่านี้"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"ต่ำ: แสดงที่ด้านล่างของรายการแจ้งเตือนโดยไม่ส่งเสียง"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"ปกติ: แสดงการแจ้งเตือนเหล่านี้โดยไม่ส่งเสียง"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"สูง: แสดงที่ด้านบนของรายการแจ้งเตือนและส่งเสียง"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"ด่วน: แสดงบนหน้าจอในช่วงเวลาสั้นๆ และส่งเสียง"</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>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"เบ็ดเตล็ด"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"คุณตั้งค่าความสำคัญของการแจ้งเตือนเหล่านี้"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ข้อความนี้สำคัญเนื่องจากบุคคลที่เกี่ยวข้อง"</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" กำลังพยายามเพิ่มผู้ใช้ใหม่ แต่ระบบไม่อนุญาตในขณะนี้"</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" กำลังพยายามเพิ่มผู้ใช้ใหม่ แต่ถึงขีดจำกัดของผู้ใช้แล้ว"</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" กำลังพยายามเพิ่มผู้ใช้ใหม่ แต่มีบัญชี "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" อยู่แล้วบนอุปกรณ์เครื่องนี้ ดำเนินการต่อไหม"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" กำลังพยายามเพิ่มผู้ใช้ใหม่สำหรับบัญชี "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" ดำเนินการต่อไหม"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"ค่ากำหนดภาษา"</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>
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 1b7a10d..b5e1de8 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Ulat sa bug"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Kunin ang ulat sa bug"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Mangongolekta ito ng impormasyon tungkol sa kasalukuyang katayuan ng iyong device, na ipapadala bilang mensaheng e-mail. Gugugol ito ng kaunting oras mula sa pagsisimula ng ulat sa bug hanggang sa handa na itong maipadala; mangyaring magpasensya."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interactive na ulat"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Gamitin ito sa karamihan ng sitwasyon. Nagbibigay-daan ito sa iyo na subaybayan ang pag-usad ng ulat at magbigay ng higit pang mga detalye tungkol sa problema. Maaari itong mag-alis ng ilan sa mga hindi masyadong ginagamit na seksyon na nangangailangan ng mahabang panahon upang iulat."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Buong ulat"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">Kukuha ng screenshot para sa ulat ng bug sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> segundo.</item>
+      <item quantity="other">Kukuha ng screenshot para sa ulat ng bug sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> na segundo.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Silent mode"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Naka-OFF ang tunog"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Naka-ON ang sound"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"May kasamang personal na data tulad ng mga numero ng credit card at password."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Kontrolin ang pag-magnify ng display"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrolin ang antas ng pag-zoom at pagpoposisyon ng display."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Magsagawa ng mga galaw"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"May kakayahang mag-tap, mag-swipe, mag-pinch at magsagawa ng iba pang mga galaw."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"huwag paganahin o baguhin ang status bar"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Pinapayagan ang app na huwag paganahin ang status bar o magdagdag at mag-alis ng mga icon ng system."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"maging status bar"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Pinapayagan ang app na kumuha ng mga larawan at video gamit ang camera. Pinapayagan ng pahintulot na ito ang app na gamitin ang camera anumang oras nang wala ng iyong kumpirmasyon."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"kontrolin ang pag-vibrate"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Pinapayagan ang app na kontrolin ang vibrator."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolin ang flashlight"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Pinapayagan ang app na kontrolin ang flashlight."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"direktang tawagan ang mga numero ng telepono"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Pinapayagan ang app na tumawag sa mga numero ng telepono nang wala ng iyong panghihimasok. Maaari itong magresulta sa mga hindi inaasahang pagsingil o tawag. Tandaan na hindi nito pinapayagan ang app na tumawag sa mga numerong pang-emergency. Maaaring magpagastos sa iyo ng pera ang nakakahamak na apps sa pamamagitan ng pagtawag nang wala ng iyong kumpirmasyon."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"i-access ang serbisyo sa tawag ng IMS"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"I-cut"</string>
     <string name="copy" msgid="2681946229533511987">"Kopyahin"</string>
     <string name="paste" msgid="5629880836805036433">"I-paste"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"I-paste bilang plain text"</string>
     <string name="replace" msgid="5781686059063148930">"Palitan..."</string>
     <string name="delete" msgid="6098684844021697789">"Tanggalin"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Kopyahin ang URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Pumili ng teksto"</string>
+    <string name="undo" msgid="7905788502491742328">"I-undo"</string>
+    <string name="redo" msgid="7759464876566803888">"Gawing muli"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Pagpili ng teksto"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Idagdag sa diksyunaryo"</string>
     <string name="deleteText" msgid="6979668428458199034">"Tanggalin"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Ibahagi ang ulat ng bug sa admin?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Humiling ang iyong admin ng IT ng ulat ng bug upang makatulong sa pag-troubleshoot"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"TANGGAPIN"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"TANGGIHAN"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Kinukuha ang ulat ng bug…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Pindutin upang kanselahin"</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="9157568568695230830">"Ipakita ang pamamaraan ng pag-input"</string>
-    <string name="hardware" msgid="7517821086888990278">"Hardware"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Baguhin ang wallpaper"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Notification 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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Na-update ng iyong administrator"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Na-delete ng iyong administrator"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Upang matulungang pagbutihin ang tagal ng baterya, binabawasan ng pangtipid ng baterya ang pagganap ng iyong device at nililimitahan ang pag-vibrate, mga serbisyo ng lokasyon at karamihan sa data ng background. Maaaring hindi mag-update ang email, pagmemensahe at iba pang mga app na umaasa sa pagsi-sync maliban kung buksan mo ang mga iyon.\n\nAwtomatikong nag-o-off ang pangtipid ng baterya kapag nagcha-charge ang iyong device."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Kahalagahan"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Naka-block: Huwag kailanman ipakita ang mga notification na ito"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Mababa: Tahimik na ipakita sa ibaba ng listahan ng mga notification"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Tahimik na ipakita ang mga notification na ito"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Mataas: Ipakita sa taas ng listahan ng mga notification at mag-play ng tunog"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Agaran: Ipasilip sa screen at mag-play ng tunog"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="one">Sa loob ng %1$d minuto (hanggang <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="other">Sa loob ng %1$d na minuto (hanggang <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"Mahalaga ito dahil sa mga taong kasangkot."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315">"Sinusubukan ng "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" na magdagdag ng bagong user, ngunit kasalukuyan itong ipinagbabawal."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266">"Sinusubukan ng "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" na magdagdag ng bagong user, ngunit naabot na ang limitasyon sa user."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789">"Sinusubukan ng "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" na magdagdag ng bagong user, ngunit nasa device na ito na ang account na "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Magpatuloy pa rin?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392">"Sinusubukan ng "<b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" na magdagdag ng bagong user para sa account na "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Magpatuloy?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Kagustuhan sa 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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Lahat ng wika"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Maghanap"</string>
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 3904aa5..79a5c54 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Hata raporu"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Hata raporu al"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Bu rapor, e-posta iletisi olarak göndermek üzere cihazınızın şu anki durumuyla ilgili bilgi toplar. Hata raporu başlatıldıktan sonra hazır olması biraz zaman alabilir, lütfen sabırlı olun."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Etkileşimli rapor"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Çoğu durumda bunu kullanın. Bu seçenek, raporun ilerleme durumunu takip etmenize ve sorunla ilgili daha fazla ayrıntı girmenize olanak sağlar. Rapor edilmesi uzun süren ve az kullanılan bazı bölümleri yok sayabilir."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Tam rapor"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde hata raporu ekran görüntüsü alınıyor.</item>
+      <item quantity="one">Hata raporu ekran görüntüsü <xliff:g id="NUMBER_0">%d</xliff:g> saniye içinde alınacak.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Sessiz mod"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Ses KAPALI"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Ses AÇIK"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Kredi kartı ve şifre gibi kişisel bilgiler içerir."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Ekran büyütecini kontrol et"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ekranın yakınlaştırma seviyesini ve konumunu kontrol edin."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Haraketleri yapma"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Hafifçe dokunabilir, hızlıca kaydırabilir, sıkıştırabilir ve diğer hareketleri yapabilirsiniz."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"durum çubuğunu devre dışı bırak veya değiştir"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Uygulamaya, durum çubuğunu devre dışı bırakma ve sistem simgelerini ekleyip kaldırma izni verir."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"durum çubuğunda olma"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Uygulamaya kamerayla fotoğraf ve video çekme izni verir. Bu izin, uygulamanın sizin onayınız olmadan istediği zaman kamerayı kullanmasına olanak sağlar."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"titreşimi denetleme"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Uygulamaya, titreşimi denetleme izni verir."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"el fenerini denetle"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Uygulamaya, el fenerini denetleme izni verir."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"telefon numaralarına doğrudan çağrı yap"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Uygulamaya sizin müdahaleniz olmadan telefon numaralarına çağrı yapma izni verir. Bu durum beklenmeyen ödemelere veya çağrılara neden olabilir. Ancak bu iznin, uygulamanın acil numaralara çağrı yapmasına olanak sağlamadığını unutmayın. Kötü amaçlı uygulamalar onayınız olmadan çağrılar yaparak sizi zarara sokabilir."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS çağrı hizmetine erişme"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Kes"</string>
     <string name="copy" msgid="2681946229533511987">"Kopyala"</string>
     <string name="paste" msgid="5629880836805036433">"Yapıştır"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Düz metin olarak yapıştır"</string>
     <string name="replace" msgid="5781686059063148930">"Değiştir..."</string>
     <string name="delete" msgid="6098684844021697789">"Sil"</string>
     <string name="copyUrl" msgid="2538211579596067402">"URL\'yi kopyala"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Metin seç"</string>
+    <string name="undo" msgid="7905788502491742328">"Geri al"</string>
+    <string name="redo" msgid="7759464876566803888">"Yeniden yap"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Metin seçimi"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Sözlüğe ekle"</string>
     <string name="deleteText" msgid="6979668428458199034">"Sil"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Hata raporu yöneticiyle paylaşılsın mı?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"BT yöneticiniz, sorun gidermeye yardımcı olması için bir hata raporu istedi"</string>
+    <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="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Hata raporu alınıyor…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"İptal etmek için dokunun"</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="9157568568695230830">"Giriş yöntemini göster"</string>
-    <string name="hardware" msgid="7517821086888990278">"Donanım"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <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="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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Yöneticiniz tarafından güncellendi"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Yöneticiniz tarafından silindi"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Pil tasarrufu özelliği, pil ömrünü iyileştirmeye yardımcı olmak için cihazın performansını düşürür, titreşimi, konum hizmetlerini ve arka plan verilerinin çoğunu sınırlar. Senkronizasyona dayalı olarak çalışan e-posta, mesajlaşma uygulamaları ve diğer uygulamalar, bunları açmadığınız sürece güncellenmeyebilir.\n\nCihazınız şarj olurken pil tasarrufu otomatik olarak kapatılır."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Önem"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Engellendi: Bu bildirimleri hiçbir zaman gösterme"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Düşük: Bildirim listesinin altında sessizce göster"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Bu bildirimleri sessizce göster"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Yüksek: Bildirim listesinin üstünde göster ve ses çıkar"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Acil: Ekrana getir ve ses çıkar"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">%1$d dakika için (şu saate kadar: <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">Bir dakika için (şu saate kadar: <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"Bu, dahil olan kişiler nedeniyle önemlidir."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>", yeni bir kullanıcı eklemeye çalışıyor, ancak şu anda bunu yapmak için izni yok."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>", yeni bir kullanıcı eklemeye çalışıyor, ancak kullanıcı sınırına ulaşıldı."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>", yeni bir kullanıcı eklemeye çalışıyor, ancak "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" hesabı bu cihazda zaten var. Yine de devam edilsin mi?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>", "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" hesabı için yeni bir kullanıcı eklemeye çalışıyor. Devam edilsin mi?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Dil tercihi"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Tüm diller"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Ara"</string>
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index e38ec1d..f4ba226 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -213,6 +213,17 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Звіт про помилки"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Звіт про помилку"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Інформація про поточний стан вашого пристрою буде зібрана й надіслана електронною поштою. Підготовка звіту триватиме певний час."</string>
+    <string name="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 />
+    <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>
@@ -225,6 +236,7 @@
     <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="safeMode" msgid="2788228061547930246">"Безп. режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"Особисті дані"</string>
@@ -257,6 +269,8 @@
     <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>
@@ -355,8 +369,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Дозволяє програмі фотографувати та знімати відео за допомогою камери. Такий дозвіл дає програмі змогу будь-коли використовувати камеру без вашого підтвердження."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"контролювати вібросигнал"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Дозволяє програмі контролювати вібросигнал."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"контр. блим. світло"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Дозволяє програмі контролювати світловий сигнал."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"прямо набирати номери тел."</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Дозволяє програмі набирати номери телефону без вашого відома. Це може спричинити неочікуване стягнення плати чи здійснення дзвінків. Зауважте, що це не дозволяє програмі набирати екстрені номери. Шкідливі програми можуть здійснювати дзвінки без вашого підтвердження, за що з вас стягуватимуться кошти."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"отримувати доступ до телефонної служби IMS"</string>
@@ -542,8 +554,8 @@
     <item msgid="9192514806975898961">"Указати"</item>
   </string-array>
   <string-array name="emailAddressTypes">
-    <item msgid="8073994352956129127">"Дом."</item>
-    <item msgid="7084237356602625604">"Роб."</item>
+    <item msgid="8073994352956129127">"Домашня"</item>
+    <item msgid="7084237356602625604">"Робоча"</item>
     <item msgid="1112044410659011023">"Інше"</item>
     <item msgid="2374913952870110618">"Указати"</item>
   </string-array>
@@ -868,10 +880,13 @@
     <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">"Видалити"</string>
@@ -1042,10 +1057,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Надіслати адміністратору повідомлення про помилку?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Ваш ІТ-адміністратор просить надіслати повідомлення про помилку, щоб вирішити проблему"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"ПРИЙНЯТИ"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"ВІДХИЛИТИ"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Створюється повідомлення про помилку…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Торкніться, щоб скасувати"</string>
     <string name="select_input_method" msgid="8547250819326693584">"Змінити клавіатуру"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"Вибрати клавіатури"</string>
-    <string name="show_ime" msgid="9157568568695230830">"Показати метод введення"</string>
-    <string name="hardware" msgid="7517821086888990278">"Обладнання"</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="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
@@ -1121,6 +1142,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Змінити фоновий малюнок"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Служба читання сповіщень"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Постачальник умов"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"Диспетчер сповіщень"</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>
@@ -1458,12 +1480,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"Пріоритет"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Заблоковано: не показувати ці сповіщення"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Низький пріоритет: показувати ці сповіщення внизу списку без звукового сигналу"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Стандартний пріоритет: показувати ці сповіщення без звукового сигналу"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Високий пріоритет: показувати ці сповіщення вгорі списку зі звуковим сигналом"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Терміново: показувати ці сповіщення на екрані зі звуковим сигналом"</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>
@@ -1549,4 +1565,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"Інше"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"Ви вказуєте пріоритет цих сповіщень."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Важливе з огляду на учасників."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" хоче додати нового користувача, але зараз це заборонено."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" хоче додати нового користувача, але вже додано максимальну кількість користувачів."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" хоче додати нового користувача, але обліковий запис "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" уже існує на цьому пристрої. Продовжити?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" хоче додати нового користувача облікового запису "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Продовжити?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Вибір мови"</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>
 </resources>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index ffb2900..bf2f989 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"بگ کی اطلاع"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"بگ کی اطلاع لیں"</string>
     <string name="bugreport_message" msgid="398447048750350456">"ایک ای میل پیغام کے بطور بھیجنے کیلئے، یہ آپ کے موجودہ آلہ کی حالت کے بارے میں معلومات جمع کرے گا۔ بگ کی اطلاع شروع کرنے سے لے کر بھیجنے کیلئے تیار ہونے تک اس میں تھوڑا وقت لگے گا؛ براہ کرم تحمل سے کام لیں۔"</string>
+    <string name="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 />
+    <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>
+    </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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"حفاظتی وضع"</string>
     <string name="android_system_label" msgid="6577375335728551336">"‏Android سسٹم"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"ذاتی"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ایپ کو کیمرے سے تصویریں لینے اور ویڈیوز بنانے کی اجازت دیتا ہے۔ یہ اجازت ایپ کو آپ کی تصدیق کے بغیر کسی بھی وقت کیمرا استعمال کرنے کی اجازت دیتی ہے۔"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"ارتعاش کو کنٹرول کریں"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"ایپ کو وائبریٹر کنٹرول کرنے کی اجازت دیتا ہے۔"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"فلیش لائٹ کنٹرول"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"ایپ کو فلیش لائٹ کنٹرول کرنے کی اجازت دیتا ہے۔"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"براہ راست فون نمبرز پر کال کریں"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"ایپ کو آپ کی مداخلت کے بغیر فون نمبروں پر کال کرنے کی اجازت دیتا ہے۔ اس کے نتیجے میں غیر متوقع چارجز یا کالیں ہوسکتی ہیں۔ نوٹ کرلیں کہ یہ ایپ کو ہنگامی نمبروں پر کال کرنے کی اجازت نہیں دیتا ہے۔ نقصان دہ ایپس آپ کی تصدیق کے بغیر کالیں کرکے آپ کی رقم صرف کروا سکتے ہیں۔"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"‏IMS کال سروس تک رسائی حاصل کریں"</string>
@@ -858,10 +868,13 @@
     <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">"حذف کریں"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"منتظم کے ساتھ بگ رپورٹ کا اشتراک کریں؟"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"‏آپ کے IT منتظم نے ٹربل شوٹ میں مدد کیلئے ایک بگ رپورٹ کی درخواست کی"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"قبول کریں"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"مسترد کریں"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"بگ رپورٹ لی جا رہی ہے…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"منسوخ کرنے کیلئے ٹچ کریں"</string>
     <string name="select_input_method" msgid="8547250819326693584">"کی بورڈ تبدیل کریں"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"کی بورڈز منتخب کریں"</string>
-    <string name="show_ime" msgid="9157568568695230830">"ان پٹ طریقہ دکھائیں"</string>
-    <string name="hardware" msgid="7517821086888990278">"ہارڈ ویئر"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"وال پیپر تبدیل کریں"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"اطلاع سننے والا"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"شرط فراہم کنندہ"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"اطلاع کا معاون"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"اہمیت"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"مسدود کردہ: یہ اطلاعات کبھی مت دکھائیں"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"پست: اطلاعات کی فہرست کے نیچے خاموشی سے دکھائیں"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"عام: خاموشی سے یہ اطلاعات دکھائیں"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"اعلی: اطلاعات کی فہرست پر سب سے اوپر دکھائیں اور آواز چلائیں"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"ارجنٹ: اسکرین پر دکھائیں اور آواز چلائیں"</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">ایک منٹ کیلئے (تک <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"متفرقات"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"ان اطلاعات کی اہمیت آپ مقرر کرتے ہیں۔"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"اس میں موجود لوگوں کی وجہ سے یہ اہم ہے۔"</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ایک نیا صارف شامل کرنے کی کوشش کر رہی ہے مگر فی الحال ممنوع ہے۔"</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ایک نیا صارف شامل کرنے کی کوشش کر رہی ہے، لیکن صارف کی حد پوری ہوگئی ہے۔"</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ایک نیا صارف شامل کرنے کی کوشش کر رہی ہے لیکن اکاؤنٹ "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" پہلے سے اس آلہ پر موجود ہے۔ بہر صورت آگے بڑھیں؟"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" اکاؤنٹ "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" کیلئے ایک نیا صارف شامل کرنے کی کوشش کر رہی ہے۔ آگے بڑھیں؟"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"زبان کی ترجیح"</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>
 </resources>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index c33360d..a33a283 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Nosozlik haqida ma’lumot berish"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Xatoliklar hisoboti"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Qurilmangiz holati haqidagi ma’lumotlar to‘planib, e-pochta orqali yuboriladi. Hisobotni tayyorlash biroz vaqt olishi mumkin."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktiv hisobot"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Bundan maxsus vaziyatlarda foydalaning. Bu hisobot jarayonini kuzatish imkonini beradi va muammo haqida batafsil ma’lumotlarni ko‘rishingiz mumkin bo‘ladi. Hisobot uchun ko‘p vaqt oladigan kam ishlatiladigan bo‘limlar qoldirib ketilishi mumkin."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"To‘liq hisobot"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Xatoliklar hisoboti uchun skrinshot <xliff:g id="NUMBER_1">%d</xliff:g> soniyadan so‘ng olinadi.</item>
+      <item quantity="one">Xatoliklar hisoboti uchun skrinshot <xliff:g id="NUMBER_0">%d</xliff:g> soniyadan so‘ng olinadi.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Ovozsiz rejim"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Tovush o‘chirilgan"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"YONIQ"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Bunga kredit karta raqamlari va parollar kabi shaxsiy ma’lumotlar kiradi."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Ekranni kattalashtirishni boshqarish"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Ekranni kattalashtirish darajasi va joylashuvini boshqaradi."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Imo-ishoralar bilan boshqarish"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Bosish, surish; jipslashtirish va boshqa imo-ishoralarni amalga oshirish mumkin."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"holat panelini o‘zgartirish yoki o‘chirish"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Ilova holat panelini o‘chirib qo‘yishi hamda tizim ikonkalarini qo‘shishi yoki olib tashlashi mumkin."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"holat qatorida ko‘rinishi"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Ilovaga kameradan foydalanib rasm va videoga olishga ruxsat beradi. Bu ruxsat ilovaga sizdan tasdiqlashni so‘ramasdan kameradan foydalanishga imkon beradi."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"tebranishni boshqarish"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Ilova tebranishli signallarni boshqarishi mumkin."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"chiroq chaqnashini boshqarish"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Ilova chaqnoqni boshqarishi mumkin."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"telefon raqamlariga tog‘ridan to‘g‘ri qo‘ng‘iroq qilish"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Ilovaga sizning yordamingizsiz telefonga qo‘ng‘iroq qilish imkonini beradi. Bu kutilmagan qo‘ng‘iroqlarni amalga oshirishi yoki ortiqcha to‘lovlarni yuzaga keltirishi mumkin. Shunga e’tibor qilinki, u favqulodda telefon raqamlariga qo‘ng‘iroqlar qilishga ruxsat bermaydi. Zararli ilovalar sizdan so‘ramasdan qo‘ng‘iroqlarni amalga oshirib, pulingizni sarflashi mumkin."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS qo‘ng‘iroq xizmatiga kirish"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Kesish"</string>
     <string name="copy" msgid="2681946229533511987">"Nusxa olish"</string>
     <string name="paste" msgid="5629880836805036433">"Joylash"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Oddiy matn sifatida joylash"</string>
     <string name="replace" msgid="5781686059063148930">"Almashtirish"</string>
     <string name="delete" msgid="6098684844021697789">"O‘chirish"</string>
     <string name="copyUrl" msgid="2538211579596067402">"URL’dan nusxa olish"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Matnni tanlash"</string>
+    <string name="undo" msgid="7905788502491742328">"Bekor qilish"</string>
+    <string name="redo" msgid="7759464876566803888">"Qaytarish"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Matni belgilash"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Lug‘atga qo‘shish"</string>
     <string name="deleteText" msgid="6979668428458199034">"O‘chirish"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Administrator bilan xatoliklar hisoboti ulashilsinmi?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Administratoringiz nosozliklarni tuzatish uchun xatoliklar hisobotini so‘ramoqda"</string>
+    <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="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Xatoliklar hisoboti olinmoqda…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Bekor qilish uchun bosing"</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="9157568568695230830">"Kiritish usulini ko‘rish"</string>
-    <string name="hardware" msgid="7517821086888990278">"Qurilma"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Fon rasmini o‘zgartirish"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Bildirishnoma tinglovchisi"</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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Administratoringiz tomonidan yangilandi"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Administratoringiz tomonidan o‘chirilgan"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Batareya quvvatini uzoqroq vaqtga yetkazish uchun quvvat tejash funksiyasi qurilmangiz unumdorligini kamaytiradi hamda uning tebranishi va orqa fonda internetdan foydalanishini cheklaydi. Sinxronlanishni talab qiladigan e-pochta, xabar almashinuv va boshqa ilovalar esa qachonki ularni ishga tushirganingizda yangilanadi.\n\nQurilma quvvat olayotganda quvvat tejash funksiyasi avtomatik tarzda o‘chadi."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Muhimligi"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloklangan: bu bildirishnomalar boshqa ko‘rsatilmasin"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Past: bildirishnomalar ro‘yxatining oxirida ovozsiz ko‘rsatilsin"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Oddiy: bu bildirishnomalar ovozsiz ko‘rsatilsin"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Yuqori: bildirishnomalar ro‘yxatining boshida ovoz bilan ko‘rsatilsin"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Shoshilinch: barcha oynalar ustida signal ovozi bilan ko‘rsatilsin"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">%1$d daqiqa (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> gacha)</item>
       <item quantity="one">Bir daqiqa (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> gacha)</item>
@@ -1511,6 +1525,16 @@
       <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">"Ushbu bildirishnomalarning muhimligini o‘rnatgansiz."</string>
-    <string name="importance_from_person" msgid="9160133597262938296">"Jalb qilingan odamlar tufayli bu muhim."</string>
+    <string name="importance_from_topic" msgid="3572280439880023233">"Siz ushbu bildirishnomalarning muhimligini belgilagansiz."</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"Bu odamlar siz uchun muhim."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ilovasi yangi foydalanuvchi qo‘shishga urinmoqda, lekin hozirda taqiqlangan."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ilovasi yangi foydalanuvchi qo‘shishga urinmqoda, lekin ortiq foydalanuvchi qo‘shib bo‘lmaydi."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ilovasi yangi foydalanuvchi qo‘shishga urinmoqda, lekin "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" hisobi allaqachon qurilmada mavjud. Baribir davom etilsinmi?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" ilovasi "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" hisobi uchun yangi foydalanuvchi qo‘shishga urinmoqda. Davom etilsinmi?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Til sozlamalari"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Barcha tillar"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Qidiruv"</string>
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 49e14df..56af67d 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Báo cáo lỗi"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Nhận báo cáo lỗi"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Báo cáo này sẽ thu thập thông tin về tình trạng thiết bị hiện tại của bạn, để gửi dưới dạng thông báo qua email. Sẽ mất một chút thời gian kể từ khi bắt đầu báo cáo lỗi cho tới khi báo cáo sẵn sàng để gửi; xin vui lòng kiên nhẫn."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Báo cáo tương tác"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Sử dụng tùy chọn này trong hầu hết các trường hợp. Tùy chọn này cho phép bạn theo dõi tiến trình của báo cáo và nhập thêm thông tin chi tiết về sự cố. Tùy chọn này có thể bỏ qua một số phần ít được sử dụng mà mất nhiều thời gian để báo cáo."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Báo cáo đầy đủ"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="other">Sẽ chụp ảnh màn hình để báo cáo lỗi sau <xliff:g id="NUMBER_1">%d</xliff:g> giây.</item>
+      <item quantity="one">Sẽ chụp ảnh màn hình để báo cáo lỗi sau <xliff:g id="NUMBER_0">%d</xliff:g> giây.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Chế độ im lặng"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Âm thanh TẮT"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Âm thanh BẬT"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Bao gồm dữ liệu cá nhân chẳng hạn như số thẻ tín dụng và mật khẩu."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Kiểm soát thu phóng màn hình"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kiểm soát vị trí và mức thu phóng của màn hình."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Thực hiện cử chỉ"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Có thể nhấn, vuốt, chụm và thực hiện các cử chỉ khác."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"vô hiệu hóa hoặc sửa đổi thanh trạng thái"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Cho phép ứng dụng vô hiệu hóa thanh trạng thái hoặc thêm và xóa biểu tượng hệ thống."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"trở thành thanh trạng thái"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Cho phép ứng dụng chụp ảnh và quay video bằng máy ảnh. Quyền này cho phép ứng dụng sử dụng máy ảnh bất kỳ lúc nào mà không cần sự xác nhận của bạn."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"kiểm soát rung"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Cho phép ứng dụng kiểm soát bộ rung."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"kiểm soát đèn nháy"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Cho phép ứng dụng kiểm soát đèn nháy."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"gọi trực tiếp số điện thoại"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Cho phép ứng dụng gọi các số điện thoại mà không cần sự can thiệp của bạn. Việc này có thể dẫn đến các khoản phí hoặc cuộc gọi không mong muốn. Lưu ý rằng quyền này không cho phép ứng dụng gọi các số khẩn cấp. Các ứng dụng độc hại có thể khiến bạn tốn tiền do thực hiện cuộc gọi mà không cần sự xác nhận của bạn."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"truy cập dịch vụ gọi điện qua IMS"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Cắt"</string>
     <string name="copy" msgid="2681946229533511987">"Sao chép"</string>
     <string name="paste" msgid="5629880836805036433">"Dán"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Dán dưới dạng văn bản thuần túy"</string>
     <string name="replace" msgid="5781686059063148930">"Thay thế..."</string>
     <string name="delete" msgid="6098684844021697789">"Xóa"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Sao chép URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Chọn văn bản"</string>
+    <string name="undo" msgid="7905788502491742328">"Hoàn tác"</string>
+    <string name="redo" msgid="7759464876566803888">"Làm lại"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Lựa chọn văn bản"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Thêm vào từ điển"</string>
     <string name="deleteText" msgid="6979668428458199034">"Xóa"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Chia sẻ báo cáo lỗi với quản trị viên?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"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ố"</string>
+    <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="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Đang thực hiện báo cáo lỗi…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Chạm để hủy"</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="9157568568695230830">"Hiển thị phương thức nhập"</string>
-    <string name="hardware" msgid="7517821086888990278">"Phần cứng"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <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="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="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>
@@ -1440,12 +1460,6 @@
     <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>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Đã bị xóa bởi quản trị viên của bạn"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Để giúp tăng tuổi thọ pin, trình tiết kiệm pin sẽ giảm hiệu suất thiết bị của bạn và hạn chế rung, dịch vụ vị trí và hầu hết dữ liệu nền. Email, nhắn tin và các ứng dụng khác dựa trên đồng bộ hóa có thể không cập nhật nếu bạn không mở chúng.\n\nTrình tiết kiệm pin tự động tắt khi thiết bị của bạn đang sạc."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Mức độ quan trọng"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Đã chặn: Không bao giờ hiển thị các thông báo này"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Thấp: Hiển thị im lặng ở cuối danh sách thông báo"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Bình thường: Hiển thị im lặng các thông báo này"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Cao: Hiển thị ở đầu danh sách thông báo và phát ra âm thanh"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Khẩn cấp: Hiển thị trên màn hình và phát ra âm thanh"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="other">Trong %1$d phút (cho đến <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="one">Trong một phút (cho đến <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_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_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" đang cố thêm người dùng mới nhưng hiện không được cho phép."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" đang cố thêm người dùng mới nhưng đã đạt đến giới hạn người dùng."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" đang cố thêm người dùng mới nhưng tài khoản "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" đã tồn tại trên thiết bị này. Vẫn tiếp tục?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" đang cố thêm người dùng mới cho tài khoản "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Tiếp tục?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Tùy chọn 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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Tất cả ngôn ngữ"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Tìm kiếm"</string>
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 1803f99..45d13e8 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"错误报告"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"提交错误报告"</string>
     <string name="bugreport_message" msgid="398447048750350456">"这会收集有关当前设备状态的信息,并以电子邮件的形式进行发送。从开始生成错误报告到准备好发送需要一点时间,请耐心等待。"</string>
+    <string name="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 />
+    <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>
+    </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>
@@ -223,14 +232,15 @@
     <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="safeMode" msgid="2788228061547930246">"安全模式"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 系统"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"个人"</string>
     <string name="managed_profile_label" msgid="6260850669674791528">"工作"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"通讯录"</string>
-    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"使用您的通讯录"</string>
+    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"访问您的通讯录"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"位置信息"</string>
-    <string name="permgroupdesc_location" msgid="1346617465127855033">"使用此设备的位置信息"</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">"短信"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"允许该应用使用相机拍摄照片和视频。此权限可让该应用随时使用相机,而无需您的确认。"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"控制振动"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"允许应用控制振动器。"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"控制闪光灯"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"允许应用控制闪光灯。"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"直接拨打电话号码"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"允许该应用在您未执行操作的情况下拨打电话号码。此权限可能会导致意外收费或呼叫。请注意,此权限不允许该应用拨打紧急电话号码。恶意应用可通过拨打电话产生相关费用,而无需您的确认。"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"使用即时通讯通话服务"</string>
@@ -858,10 +868,13 @@
     <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">"复制网址"</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">"删除"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"要与管理员分享错误报告吗?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"您的 IT 管理员已请求获取错误报告,以便帮助您排查问题"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"接受"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"拒绝"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"正在生成错误报告…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"触摸可取消"</string>
     <string name="select_input_method" msgid="8547250819326693584">"更改键盘"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"选择键盘"</string>
-    <string name="show_ime" msgid="9157568568695230830">"显示输入法"</string>
-    <string name="hardware" msgid="7517821086888990278">"硬件"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"更改壁纸"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"通知侦听器"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"条件提供程序"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"通知助手"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"重要性"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"屏蔽:一律不显示这些通知"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"低:在通知列表底部显示,不发出提示音"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"一般:显示这些通知,但不发出提示音"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"高:在通知列表顶部显示,并发出提示音"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"紧急:在屏幕上持续显示,并发出提示音"</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>
@@ -1512,5 +1526,15 @@
     </plurals>
     <string name="default_notification_topic_label" msgid="227586145791870829">"其他"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"这些通知的重要性由您来设置。"</string>
-    <string name="importance_from_person" msgid="9160133597262938296">"这条通知涉及特定人士,因此被归为重要通知。"</string>
+    <string name="importance_from_person" msgid="9160133597262938296">"这条通知涉及特定的人,因此被归为重要通知。"</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>"正尝试添加新用户,但是系统目前禁止执行这项操作。"</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>"正尝试添加新用户,但已达到用户人数上限。"</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>"正尝试添加新用户,但这个设备上已经存在"<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>"这个帐号。仍要继续吗?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>"正尝试为"<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>"这个帐号添加新用户,要继续吗?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"语言偏好设置"</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>
 </resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 4b6320c..2fe2228 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"錯誤報告"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"取得錯誤報告"</string>
     <string name="bugreport_message" msgid="398447048750350456">"這會收集您目前裝置狀態的相關資訊,並以電郵傳送給您。從開始建立錯誤報告到準備傳送需要一段時間,請耐心等候。"</string>
+    <string name="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 />
+    <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>
+    </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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"安全模式"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"個人"</string>
@@ -238,7 +248,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"允許應用程式使用相機拍照和錄影。這項權限允許應用程式隨時使用相機,而不需經您確認。"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"控制震動"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"允許應用程式控制震動。"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"控制閃光燈"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"允許應用程式控制閃光燈。"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"直接撥打電話號碼"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"允許應用程式繞過您自行撥打電話號碼,但可能會產生未預期的費用或撥打未預期的電話。注意:這項權限不允許應用程式撥打緊急電話。惡意應用程式可能未經您確認擅自撥打電話,增加您的支出。"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"使用 IMS 通話服務"</string>
@@ -858,10 +868,13 @@
     <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">"複製網址"</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">"刪除"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"要與管理員分享錯誤報告嗎?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"您的 IT 管理員要求您提供錯誤報告,以協助解決疑難"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"接受"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"拒絕"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"正在取得錯誤報告…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"輕觸即可取消"</string>
     <string name="select_input_method" msgid="8547250819326693584">"變更鍵盤"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"選擇鍵盤"</string>
-    <string name="show_ime" msgid="9157568568695230830">"顯示輸入法"</string>
-    <string name="hardware" msgid="7517821086888990278">"硬件"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"變更桌布"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"通知接聽器"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"條件供應商"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"通知小幫手"</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>
@@ -1440,12 +1460,6 @@
     <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="notification_importance_title" msgid="7493989722610008700">"重要性"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"已封鎖:永不顯示這些通知"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"低:以靜音方式顯示在通知清單底部"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"一般:以靜音方式顯示這些通知"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"高:顯示在通知清單頂部並發出音效"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"緊急:不時於螢幕出現並發出音效"</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>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"其他"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"您可以為這些通知設定重要性。"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"列為重要的原因:涉及的人。"</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" 正在嘗試新增使用者,但系統目前禁止相關操作。"</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" 正在嘗試新增使用者,但使用者人數已達上限。"</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" 正在嘗試新增使用者,但此裝置上已有 "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" 這個帳戶。仍要繼續嗎?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" 正在嘗試為 "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" 這個帳戶新增使用者。要繼續嗎?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"語言偏好設定"</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>
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 98f1848..6554153 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"錯誤報告"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"取得錯誤報告"</string>
     <string name="bugreport_message" msgid="398447048750350456">"這會收集您目前裝置狀態的相關資訊,以便透過電子郵件傳送。從錯誤報告開始建立到準備傳送的這段過程可能需要一點時間,敬請耐心等候。"</string>
+    <string name="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 />
+    <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>
+    </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>
@@ -223,6 +232,7 @@
     <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="safeMode" msgid="2788228061547930246">"安全模式"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"個人"</string>
@@ -244,7 +254,7 @@
     <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="permgroupdesc_sensors" msgid="7147968539346634043">"存取與您生命徵象相關的感應器資料"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"擷取視窗內容"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"檢查您存取的視窗內容。"</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"啟用輕觸探索功能"</string>
@@ -255,6 +265,8 @@
     <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>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"允許應用程式使用相機拍照和錄影。這項權限可讓應用程式隨時使用相機,而不需請求您進行確認。"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"控制震動"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"允許應用程式控制震動。"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"控制閃光燈"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"允許應用程式控制閃光燈。"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"直接撥打電話號碼"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"允許應用程式自行撥打電話,但可能產生非預期的費用或撥打非預期的電話。注意:這項權限不允許應用程式撥打緊急電話。惡意應用程式可能利用此功能擅自撥打電話,增加您不必要的額外支出。"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"存取 IMS 撥號服務"</string>
@@ -522,7 +532,7 @@
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"設定裝置全域 Proxy"</string>
     <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"設定政策啟用時要使用的裝置全域 Proxy。只有裝置擁有者可以設定全域 Proxy。"</string>
     <string name="policylab_expirePassword" msgid="5610055012328825874">"設定螢幕鎖定密碼到期日"</string>
-    <string name="policydesc_expirePassword" msgid="5367525762204416046">"調整螢幕鎖定密碼、PIN 碼或解鎖圖形的強制變更頻率。"</string>
+    <string name="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>
@@ -657,7 +667,7 @@
     <string name="lockscreen_screen_locked" msgid="7288443074806832904">"螢幕已鎖定。"</string>
     <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"按下 [Menu] 解鎖或撥打緊急電話。"</string>
     <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"按下 Menu 鍵解鎖。"</string>
-    <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"畫出解鎖圖形"</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>
@@ -685,12 +695,12 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"參閱《使用者指南》或與客戶服務中心聯絡。"</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM 卡已鎖定。"</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"解鎖 SIM 卡中…"</string>
-    <string name="lockscreen_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_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> 次,如果再嘗試 <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> 次,目前還剩 <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> 次,如果再試 <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="tablet" msgid="9191611984625460820">"您的解鎖圖案已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <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> 次,目前還剩 <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> 次,如果再試 <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">"您嘗試解除這個平板電腦的鎖定已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,平板電腦將恢復原廠設定,所有使用者資料都會遺失。"</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"您嘗試解鎖電視已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,電視將恢復原廠設定,所有使用者資料都會遺失。"</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"您嘗試解除這支手機的鎖定已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,手機將恢復原廠設定,所有使用者資料都會遺失。"</string>
@@ -698,7 +708,7 @@
     <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">"您嘗試解除這支手機的鎖定已失敗 <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_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>
@@ -711,12 +721,12 @@
     <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_start" msgid="3941045502933142847">"已開始繪製解鎖圖案"</string>
+    <string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"已清除解鎖圖案"</string>
     <string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"已加入 1 格"</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="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。第 %2$d 個小工具,共 %3$d 個。"</string>
     <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"新增小工具。"</string>
     <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"空白"</string>
@@ -732,7 +742,7 @@
     <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g>小工具已刪除。"</string>
     <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"展開解鎖區域。"</string>
     <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"滑動解鎖。"</string>
-    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"圖形解鎖。"</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"圖案解鎖。"</string>
     <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"人臉解鎖。"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN 解鎖。"</string>
     <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"密碼解鎖。"</string>
@@ -858,10 +868,13 @@
     <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">"複製網址"</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">"刪除"</string>
@@ -1028,10 +1041,16 @@
     <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="share_remote_bugreport_notification_title" msgid="3116061729914615290">"要與管理員分享錯誤報告嗎?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"您的 IT 管理員要求您提供錯誤報告以便排解問題"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"接受"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"拒絕"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"正在接收錯誤報告…"</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"輕觸即可取消"</string>
     <string name="select_input_method" msgid="8547250819326693584">"變更鍵盤"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"選擇鍵盤"</string>
-    <string name="show_ime" msgid="9157568568695230830">"顯示輸入法"</string>
-    <string name="hardware" msgid="7517821086888990278">"硬體"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"變更桌布"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"通知接聽器"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"條件提供者"</string>
+    <string name="notification_assistant_binding_label" msgid="909456055569102952">"通知小幫手"</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>
@@ -1288,16 +1308,16 @@
     <string name="kg_login_checking_password" msgid="1052685197710252395">"正在檢查帳戶…"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"您的 PIN 已輸錯 <xliff:g id="NUMBER_0">%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">"您的解鎖圖形已畫錯 <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">"您的解鎖圖案已畫錯 <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">"您嘗試解除這個平板電腦的鎖定已失敗 <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="tv" msgid="5621231220154419413">"您嘗試解鎖電視已失敗 <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="4051015943038199910">"您嘗試解除這支手機的鎖定已失敗 <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="2072996269148483637">"您嘗試解除這個平板電腦的鎖定已失敗 <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">"您嘗試解除這支手機的鎖定已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次,手機現在將恢復原廠設定。"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統就會要求您透過電子郵件帳戶解除平板電腦的鎖定狀態。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"您已畫錯解鎖圖形 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次嘗試機會。如果失敗次數超過限制,您就必須使用電子郵件帳戶才能解鎖電視。\n\n請過 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統就會要求您透過電子郵件帳戶解除手機的鎖定狀態。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您的解鎖圖案已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統就會要求您透過電子郵件帳戶解除平板電腦的鎖定狀態。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次嘗試機會。如果失敗次數超過限制,您就必須使用電子郵件帳戶才能解鎖電視。\n\n請過 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您的解鎖圖案已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統就會要求您透過電子郵件帳戶解除手機的鎖定狀態。\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">"移除"</string>
     <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"要調高音量,比建議的音量更大聲嗎?\n\n長時間聆聽高分貝音量可能會使您的聽力受損。"</string>
@@ -1433,19 +1453,13 @@
     <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_pattern" msgid="4182192144797225137">"取消固定時必須畫出解鎖圖案"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"取消固定時必須輸入密碼"</string>
     <string name="dock_non_resizeble_text" msgid="9156251681042762723">"無法調整這個應用程式的大小,請用雙指捲動該應用程式。"</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="notification_importance_title" msgid="7493989722610008700">"重要性"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"封鎖:一律不顯示這些通知"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"低:顯示在通知清單底部且不發出任何音效"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"一般:顯示這些通知且不發出任何音效"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"高:顯示在通知清單頂端並發出音效"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"緊急:持續顯示在螢幕上並發出音效"</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>
@@ -1513,4 +1527,14 @@
     <string name="default_notification_topic_label" msgid="227586145791870829">"其他"</string>
     <string name="importance_from_topic" msgid="3572280439880023233">"這些通知的重要性由您決定。"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"這則通知涉及特定人士,因此被歸為重要通知。"</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b></b>"「<xliff:g id="APP">%1$s</xliff:g>」正在嘗試新增使用者,但系統目前禁止相關操作。"</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b></b>"「<xliff:g id="APP">%1$s</xliff:g>」正在嘗試新增使用者,但已達到使用者人數上限。"</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b></b>"「<xliff:g id="APP">%1$s</xliff:g>」正在嘗試新增使用者,但這個裝置上已經有 <xliff:g id="ACCOUNT">%2$s</xliff:g> "<b></b>"這個帳戶。仍要繼續嗎?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b></b>"「<xliff:g id="APP">%1$s</xliff:g>」正在嘗試為 <xliff:g id="ACCOUNT">%2$s</xliff:g> "<b></b>"這個帳戶新增使用者。要繼續嗎?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"語言偏好設定"</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>
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 09341ee..b6a8039 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -211,6 +211,15 @@
     <string name="global_action_bug_report" msgid="7934010578922304799">"Umbiko wephutha"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Thatha umbiko wesiphazamiso"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Lokhu kuzoqoqa ulwazi mayelana nesimo samanje sedivayisi yakho, ukuthumela imilayezo ye-imeyili. Kuzothatha isikhathi esincane kusuka ekuqaleni umbiko wesiphazamiso uze ulungele ukuthunyelwa; sicela ubekezele."</string>
+    <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Umbiko obandakanyayo"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Sebenzisa lokhu ngaphansi kwezimo eziningi. Kukuvumela ukuthi ulandelele ukuqhubeka kombiko uphinde ufake imininingwane engaphezulu mayelana nenkinga. Kungakhipha ezinye izigaba ezisetshenziswe kancane ezithatha isikhathi eside ukuze zibikwe."</string>
+    <string name="bugreport_option_full_title" msgid="6354382025840076439">"Umbiko ogcwele"</string>
+    <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
+    <skip />
+    <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
+      <item quantity="one">Ithathela umbiko wesiphazamisi isithombe-skrini kumasekhondi angu-<xliff:g id="NUMBER_1">%d</xliff:g>.</item>
+      <item quantity="other">Ithathela umbiko wesiphazamisi isithombe-skrini kumasekhondi angu-<xliff:g id="NUMBER_1">%d</xliff:g>.</item>
+    </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Imodi ethulile"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Umsindo UVALIWE"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Umsindo UVULIWE"</string>
@@ -223,6 +232,7 @@
     <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="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>
@@ -255,6 +265,8 @@
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Kufaka phakathi idatha yomuntu siqu efana nezinombolo zekhadi lesikweletu namaphasiwedi."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Lawula ukulungiswa kwesibonisi"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Lawula ileveli yokusondeza yesibonisi nendawo."</string>
+    <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Yenza ukuthinta"</string>
+    <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Ingathepha, iswayiphe, incinze, futhi yenze okunye ukuthintwa."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"khubaza noma guqula ibha yomumo"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Ivumela uhlelo lokusebenza ukuthi yenze umudwa ochaza ngesimo ukuthi ungasebenzi noma ukufaka noma ukukhipha izithonjana zohlelo."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"yiba yibha yesimo"</string>
@@ -353,8 +365,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Ivumela uhlelo lokusebenza ukuthatha izithombe namavidiyo ngekhamera. Le mvume ivumela uhlelo lokusebenza ukusebenzisa ikhamera nganoma isiphi isikhathi ngaphandle kwemvume yakho."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"lawula ukudlidliza"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Ivumela uhlelo lokusebenza ukulawula isidlidlizi."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"lawula ukukhanya kwefulashi"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Ivumela uhlelo lokusebenza ukulawula ukukhanya kwefuleshi."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ngokuqondile shayela izinombolo zocingo"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Ivumela uhlelo lokusebenza ukushayela izinombolo zefoni ngaphandle kokuhlanganyela kwakho. Lokhu kungaholela emashajini noma amakholi angalindelekile. Qaphela ukuthi lokhu akuvumeli uhlelo lokusebenza ukushayela izinombolo zesimo esiphuthumayo. Izinhlelo zokusebenza ezingalungile zingabiza imali ngokwenze amakholi ngaphandle kokuqinisekisa kwakho."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"finyelela kusevisi yekholi ye-IMS"</string>
@@ -858,10 +868,13 @@
     <string name="cut" msgid="3092569408438626261">"Nqamula"</string>
     <string name="copy" msgid="2681946229533511987">"Kopisha"</string>
     <string name="paste" msgid="5629880836805036433">"Namathisela"</string>
+    <string name="paste_as_plain_text" msgid="5427792741908010675">"Namathisela njengombhalo osobala"</string>
     <string name="replace" msgid="5781686059063148930">"Buyisela"</string>
     <string name="delete" msgid="6098684844021697789">"Susa"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Kopisha i-URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Khetha umbhalo"</string>
+    <string name="undo" msgid="7905788502491742328">"Hlehlisa"</string>
+    <string name="redo" msgid="7759464876566803888">"Yenza futhi"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Inketho yombhalo"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Engeza kwisichazamazwi"</string>
     <string name="deleteText" msgid="6979668428458199034">"Susa"</string>
@@ -1028,10 +1041,16 @@
     <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>
+    <string name="share_remote_bugreport_notification_title" msgid="3116061729914615290">"Yabelana ngombiko wesiphazamisi nomqondisi?"</string>
+    <string name="share_remote_bugreport_notification_message" msgid="1310517845557771773">"Umqondisi wakho we-IT ucele umbiko wesiphazamisi ukuze asize ukuxazulula inkinga"</string>
+    <string name="share_remote_bugreport_notification_accept" msgid="8203856129078669677">"YAMUKELA"</string>
+    <string name="share_remote_bugreport_notification_decline" msgid="6337969352057443969">"YENQABA"</string>
+    <string name="remote_bugreport_progress_notification_title" msgid="2785600634417078622">"Ithatha umbiko wesiphazamisi..."</string>
+    <string name="remote_bugreport_progress_notification_message_can_cancel" msgid="5743435483005099451">"Thinta ukuze ukhansele"</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="9157568568695230830">"Bonisa indlela yokufaka"</string>
-    <string name="hardware" msgid="7517821086888990278">"I-Hardware"</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="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1107,6 +1126,7 @@
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Shintsha iphephadonga"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"Umlaleli wesaziso"</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="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>
@@ -1440,12 +1460,6 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Ibuyekezwe ngumqondisi wakho"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Isuswe ngumlawuli wakho"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Ukusiza ukuthuthukisa impilo yebhethri, isilondoloze sebhethri sehlisa ukusebenza kwedivayisi yakho futhi sikhawulele ukudlidliza, amasevisi wendawo, nedatha eningi yangasemuva. I-imeyili, imilayezo, nezinye izinhlelo zokusebenza ezincike ekuvumelaniseni zingahle zingabuyekezwa ngaphandle kokuthi uzivule.\n\nIsilondolozi sebhethri siyavaleka ngokuzenzakalelayo uma idivayisi yakho ishaja."</string>
-    <string name="notification_importance_title" msgid="7493989722610008700">"Ukubaluleka"</string>
-    <string name="notification_importance_blocked" msgid="7118826900767047125">"Okuvinjiwe: Ungalokothi ubonise lezi zaziso"</string>
-    <string name="notification_importance_low" msgid="6447640449918427187">"Okuphansi: Bonisa ngokuthulile ngaphansi kohlu lwesaziso"</string>
-    <string name="notification_importance_default" msgid="7991157697609575271">"Okujwayelekile: Bonisa ngokuthulile lezi zaziso"</string>
-    <string name="notification_importance_high" msgid="3152238637737215654">"Okuphezulu: Bonisa ngaphezulu kohlu lwezaziso uphinde wenze umsindo"</string>
-    <string name="notification_importance_max" msgid="1153693080467904474">"Okuphuthumayo: Bheka kusikrini uphinde wenze umsindo"</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="one">Okwamaminithi angu-%1$d (kuze kube ngo-<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="other">Okwamaminithi angu-%1$d (kuze kube ngo-<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1513,4 +1527,14 @@
     <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_person" msgid="9160133597262938296">"Lokhu kubalulekile ngenxa yabantu ababandakanyekayo."</string>
+    <string name="user_creation_cannot_add" msgid="7740333663230045315"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" izama ukungeza umsebenzisi omusha, kodwa okwamanje inqatshelewe."</string>
+    <string name="user_creation_cannot_add_any_more" msgid="6244197709981359266"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" izama ukungeza umsebenzisi omusha, kodwa umkhawulo womsebenzisi ufinyelelwe."</string>
+    <string name="user_creation_account_exists" msgid="4880171855014489789"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" izama ukungeza umsebenzisi omusha, kodwa i-akhawunti "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>" isivele ikhona kule divayisi. Qhubeka noma kunjalo?"</string>
+    <string name="user_creation_adding" msgid="3206420861363021392"><b>"<xliff:g id="APP">%1$s</xliff:g>"</b>" izama ukungeza umsebenzisi omusha we-akhawunti "<b>"<xliff:g id="ACCOUNT">%2$s</xliff:g>"</b>". Qhubeka?"</string>
+    <string name="language_selection_title" msgid="7181332986330337171">"Okuncamelayo kolimi"</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>
+    <string name="language_picker_section_all" msgid="3097279199511617537">"Zonke izilimi"</string>
+    <string name="locale_search_menu" msgid="2560710726687249178">"Sesha"</string>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 9f13565..1f7206e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3316,7 +3316,14 @@
              </p>
          -->
         <attr name="canControlMagnification" format="boolean" />
-        <!-- Short description of the accessibility serivce purpose or behavior.-->
+        <!-- Attribute whether the accessibility service wants to be able to perform gestures.
+             <p>
+             Required to allow setting the {@link android.accessibilityservice
+             #AccessibilityServiceInfo#FLAG_CAN_PERFORM_GESTURES} flag.
+             </p>
+         -->
+        <attr name="canPerformGestures" format="boolean" />
+        <!-- Short description of the accessibility service purpose or behavior.-->
         <attr name="description" />
     </declare-styleable>
 
@@ -3405,6 +3412,32 @@
         <attr name="name" />
     </declare-styleable>
 
+    <!-- Use <code>host-nfcf-service</code> as the root tag of the XML resource that
+         describes an {@link android.nfc.cardemulation.HostNfcFService} service, which
+         is referenced from its {@link android.nfc.cardemulation.HostNfcFService#SERVICE_META_DATA}
+         entry. -->
+    <declare-styleable name="HostNfcFService">
+        <!-- Short description of the functionality the service implements. This attribute
+             is mandatory.-->
+        <attr name="description" />
+    </declare-styleable>
+
+    <!-- Specify one or more <code>system-code-filter</code> elements inside a
+         <code>host-nfcf-service</code> element to specify a System Code
+         your service can handle. -->
+    <declare-styleable name="SystemCodeFilter">
+        <!-- The System Code. This attribute is mandatory. -->
+        <attr name="name" />
+    </declare-styleable>
+
+    <!-- Specify one or more <code>nfcid2-filter</code> elements inside a
+         <code>host-nfcf-service</code> element to specify a NFCID2
+         your service can handle. -->
+    <declare-styleable name="Nfcid2Filter">
+        <!-- The NFCID2. This attribute is mandatory. -->
+        <attr name="name" />
+    </declare-styleable>
+
     <declare-styleable name="ActionMenuItemView">
         <attr name="minWidth" />
     </declare-styleable>
@@ -3694,7 +3727,7 @@
         <!-- Controls how the image should be resized or moved to match the size
              of this ImageView.  See {@link android.widget.ImageView.ScaleType} -->
         <attr name="scaleType">
-            <!-- Scale using the image matrix when drawing. See  
+            <!-- Scale using the image matrix when drawing. See
                  {@link android.widget.ImageView#setImageMatrix(Matrix)}. -->
             <enum name="matrix" value="0" />
             <!-- Scale the image using {@link android.graphics.Matrix.ScaleToFit#FILL}. -->
@@ -3707,7 +3740,7 @@
             <enum name="fitEnd" value="4" />
             <!-- Center the image in the view, but perform no scaling. -->
             <enum name="center" value="5" />
-            <!-- Scale the image uniformly (maintain the image's aspect ratio) so both dimensions 
+            <!-- Scale the image uniformly (maintain the image's aspect ratio) so both dimensions
                  (width and height) of the image will be equal to or larger than the corresponding
                  dimension of the view (minus padding). The image is then centered in the view. -->
             <enum name="centerCrop" value="6" />
@@ -4039,9 +4072,9 @@
              should always be false for Material and  beyond.
              @hide Developers shouldn't need to change this. -->
         <attr name="useDisabledAlpha" format="boolean" />
-        <!-- Tint to apply to the button graphic. -->
+        <!-- Tint to apply to the thumb drawable. -->
         <attr name="thumbTint" format="color" />
-        <!-- Blending mode used to apply the button graphic tint. -->
+        <!-- Blending mode used to apply the thumb tint. -->
         <attr name="thumbTintMode">
             <!-- The tint is drawn on top of the drawable.
                  [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
@@ -4061,6 +4094,30 @@
                  result to valid color values. Saturate(S + D) -->
             <enum name="add" value="16" />
         </attr>
+        <!-- Drawable displayed at each progress position on a seekbar. -->
+        <attr name="tickMark" format="reference" />
+        <!-- Tint to apply to the tick mark drawable. -->
+        <attr name="tickMarkTint" format="color" />
+        <!-- Blending mode used to apply the tick mark tint. -->
+        <attr name="tickMarkTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
+        </attr>
     </declare-styleable>
 
     <declare-styleable name="StackView">
@@ -7481,6 +7538,10 @@
         <!-- Flag indicating whether this voice interaction service is capable of being launched
              from the keyguard. -->
         <attr name="supportsLaunchVoiceAssistFromKeyguard" format="boolean" />
+        <!-- Flag indicating whether this voice interaction service can handle local voice
+             interaction requests from an Activity. This flag is new in
+             {@link android.os.Build.VERSION_CODES#N} and not used in previous versions. -->
+        <attr name="supportsLocalInteraction" format="boolean" />
     </declare-styleable>
 
     <!-- Use <code>voice-enrollment-application</code>
@@ -7836,6 +7897,12 @@
         <attr name="label" />
         <!-- The key character map file resource. -->
         <attr name="keyboardLayout" format="reference" />
+        <!-- The locales the given keyboard layout corresponds to. -->
+        <attr name="locale" format="string" />
+        <!-- The vendor ID of the hardware the given layout corresponds to. @hide -->
+        <attr name="vendorId" format="integer" />
+        <!-- The product ID of the hardware the given layout corresponds to. @hide -->
+        <attr name="productId" format="integer" />
     </declare-styleable>
 
     <declare-styleable name="MediaRouteButton">
@@ -8068,4 +8135,52 @@
         <attr name="entries" />
         <attr name="entryValues" />
     </declare-styleable>
+
+    <!-- Used to describe the gradient for fill or stroke in a path of VectorDrawable. -->
+    <declare-styleable name="GradientColor">
+        <!-- Start color of the gradient. -->
+        <attr name="startColor" />
+        <!-- Optional center color. -->
+        <attr name="centerColor" />
+        <!-- End color of the gradient. -->
+        <attr name="endColor" />
+        <!-- Type of gradient. The default type is linear. -->
+        <attr name="type" />
+
+        <!-- Only applied to RadialGradient-->
+        <!-- Radius of the gradient, used only with radial gradient. -->
+        <attr name="gradientRadius" />
+
+        <!-- Only applied to SweepGradient / RadialGradient-->
+        <!-- X coordinate of the center of the gradient within the path. -->
+        <attr name="centerX" />
+        <!-- Y coordinate of the center of the gradient within the path. -->
+        <attr name="centerY" />
+
+        <!-- LinearGradient specific -->
+        <!-- X coordinate of the start point origin of the gradient.
+             Defined in same coordinates as the path itself -->
+        <attr name="startX" format="float" />
+        <!-- Y coordinate of the start point of the gradient within the shape.
+             Defined in same coordinates as the path itself -->
+        <attr name="startY" format="float" />
+        <!-- X coordinate of the end point origin of the gradient.
+             Defined in same coordinates as the path itself -->
+        <attr name="endX" format="float" />
+        <!-- Y coordinate of the end point of the gradient within the shape.
+             Defined in same coordinates as the path itself -->
+        <attr name="endY" format="float" />
+
+    </declare-styleable>
+
+    <!-- Describes an item of a GradientColor. Minimally need 2 items to define the gradient
+         Colors defined in <item> override the simple color attributes such as
+         "startColor / centerColor / endColor" are ignored -->
+    <declare-styleable name="GradientColorItem">
+        <!-- The offset (or ratio) of this current color item inside the gradient.
+             The value is only meaningful when it is between 0 and 1. -->
+        <attr name="offset" format="float" />
+        <!-- The current color for the offset inside the gradient. -->
+        <attr name="color" />
+    </declare-styleable>
 </resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 2a11081..6eba78a 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1748,6 +1748,10 @@
         <attr name="isolatedProcess" format="boolean" />
         <attr name="singleUser" />
         <attr name="encryptionAware" />
+        <!-- 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. -->
+        <attr name="externalService" format="boolean" />
     </declare-styleable>
 
     <!-- The <code>receiver</code> tag declares an
@@ -1857,6 +1861,11 @@
         <attr name="lockTaskMode" />
         <attr name="showForAllUsers" />
         <attr name="encryptionAware" />
+        <!-- @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
+             in a task/stack that isn't focusable. This flag allows them to be focusable.-->
+        <attr name="alwaysFocusable" format="boolean" />
     </declare-styleable>
 
     <!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index bff8b1a..507925b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -27,31 +27,59 @@
     <!-- Do not translate. Defines the slots for the right-hand side icons.  That is to say, the
          icons in the status bar that are not notifications. -->
     <string-array name="config_statusBarIcons">
-       <item><xliff:g id="id">managed_profile</xliff:g></item>
-       <item><xliff:g id="id">ime</xliff:g></item>
-       <item><xliff:g id="id">sync_failing</xliff:g></item>
-       <item><xliff:g id="id">sync_active</xliff:g></item>
-       <item><xliff:g id="id">cast</xliff:g></item>
-       <item><xliff:g id="id">hotspot</xliff:g></item>
-       <item><xliff:g id="id">location</xliff:g></item>
-       <item><xliff:g id="id">bluetooth</xliff:g></item>
-       <item><xliff:g id="id">nfc</xliff:g></item>
-       <item><xliff:g id="id">tty</xliff:g></item>
-       <item><xliff:g id="id">speakerphone</xliff:g></item>
-       <item><xliff:g id="id">zen</xliff:g></item>
-       <item><xliff:g id="id">mute</xliff:g></item>
-       <item><xliff:g id="id">volume</xliff:g></item>
-       <item><xliff:g id="id">wifi</xliff:g></item>
-       <item><xliff:g id="id">cdma_eri</xliff:g></item>
-       <item><xliff:g id="id">data_connection</xliff:g></item>
-       <item><xliff:g id="id">phone_evdo_signal</xliff:g></item>
-       <item><xliff:g id="id">phone_signal</xliff:g></item>
-       <item><xliff:g id="id">battery</xliff:g></item>
-       <item><xliff:g id="id">alarm_clock</xliff:g></item>
-       <item><xliff:g id="id">secure</xliff:g></item>
-       <item><xliff:g id="id">clock</xliff:g></item>
+        <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_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>
+        <item><xliff:g id="id">@string/status_bar_sync_active</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_cast</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_hotspot</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_location</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_bluetooth</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_nfc</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_tty</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_speakerphone</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_zen</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_mute</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_volume</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_wifi</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_cdma_eri</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_data_connection</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_phone_evdo_signal</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_phone_signal</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_battery</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_alarm_clock</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_secure</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_clock</xliff:g></item>
     </string-array>
 
+    <string translatable="false" name="status_bar_rotate">rotate</string>
+    <string translatable="false" name="status_bar_headset">headset</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>
+    <string translatable="false" name="status_bar_sync_active">sync_active</string>
+    <string translatable="false" name="status_bar_cast">cast</string>
+    <string translatable="false" name="status_bar_hotspot">hotspot</string>
+    <string translatable="false" name="status_bar_location">location</string>
+    <string translatable="false" name="status_bar_bluetooth">bluetooth</string>
+    <string translatable="false" name="status_bar_nfc">nfc</string>
+    <string translatable="false" name="status_bar_tty">tty</string>
+    <string translatable="false" name="status_bar_speakerphone">speakerphone</string>
+    <string translatable="false" name="status_bar_zen">zen</string>
+    <string translatable="false" name="status_bar_mute">mute</string>
+    <string translatable="false" name="status_bar_volume">volume</string>
+    <string translatable="false" name="status_bar_wifi">wifi</string>
+    <string translatable="false" name="status_bar_cdma_eri">cdma_eri</string>
+    <string translatable="false" name="status_bar_data_connection">data_connection</string>
+    <string translatable="false" name="status_bar_phone_evdo_signal">phone_evdo_signal</string>
+    <string translatable="false" name="status_bar_phone_signal">phone_signal</string>
+    <string translatable="false" name="status_bar_battery">battery</string>
+    <string translatable="false" name="status_bar_alarm_clock">alarm_clock</string>
+    <string translatable="false" name="status_bar_secure">secure</string>
+    <string translatable="false" name="status_bar_clock">clock</string>
+
     <!-- Flag indicating whether the surface flinger has limited
          alpha compositing functionality in hardware.  If set, the window
          manager will disable alpha trasformation in animations where not
@@ -413,22 +441,29 @@
     <!-- Boolean indicating whether or not wifi firmware debugging is enabled -->
     <bool translatable="false" name="config_wifi_enable_wifi_firmware_debugging">true</bool>
 
+    <!-- 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>
+
     <!-- Integer specifying the basic autojoin parameters -->
     <integer translatable="false" name="config_wifi_framework_5GHz_preference_boost_threshold">-65</integer>
-    <integer translatable="false" name="config_wifi_framework_5GHz_preference_boost_factor">5</integer>
+    <integer translatable="false" name="config_wifi_framework_5GHz_preference_boost_factor">40</integer>
     <integer translatable="false" name="config_wifi_framework_current_association_hysteresis_high">16</integer>
     <integer translatable="false" name="config_wifi_framework_current_association_hysteresis_low">10</integer>
     <integer translatable="false" name="config_wifi_framework_5GHz_preference_penalty_threshold">-75</integer>
-    <integer translatable="false" name="config_wifi_framework_5GHz_preference_penalty_factor">2</integer>
-
+    <integer translatable="false" name="config_wifi_framework_RSSI_SCORE_OFFSET">85</integer>
+    <integer translatable="false" name="config_wifi_framework_RSSI_SCORE_SLOPE">4</integer>
+    <integer translatable="false" name="config_wifi_framework_SAME_BSSID_AWARD">24</integer>
+    <integer translatable="false" name="config_wifi_framework_LAST_SELECTION_AWARD">480</integer>
+    <integer translatable="false" name="config_wifi_framework_PASSPOINT_SECURITY_AWARD">40</integer>
+    <integer translatable="false" name="config_wifi_framework_SECURITY_AWARD">80</integer>
     <!-- Integer parameters of the wifi to cellular handover feature
          wifi should not stick to bad networks -->
     <integer translatable="false" name="config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz">-82</integer>
-    <integer translatable="false" name="config_wifi_framework_wifi_score_low_rssi_threshold_5GHz">-72</integer>
-    <integer translatable="false" name="config_wifi_framework_wifi_score_good_rssi_threshold_5GHz">-60</integer>
-    <integer translatable="false" name="config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz">-87</integer>
-    <integer translatable="false" name="config_wifi_framework_wifi_score_low_rssi_threshold_24GHz">-77</integer>
-    <integer translatable="false" name="config_wifi_framework_wifi_score_good_rssi_threshold_24GHz">-65</integer>
+    <integer translatable="false" name="config_wifi_framework_wifi_score_low_rssi_threshold_5GHz">-70</integer>
+    <integer translatable="false" name="config_wifi_framework_wifi_score_good_rssi_threshold_5GHz">-57</integer>
+    <integer translatable="false" name="config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz">-85</integer>
+    <integer translatable="false" name="config_wifi_framework_wifi_score_low_rssi_threshold_24GHz">-73</integer>
+    <integer translatable="false" name="config_wifi_framework_wifi_score_good_rssi_threshold_24GHz">-60</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_bad_link_speed_24">6</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_bad_link_speed_5">12</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_good_link_speed_24">24</integer>
@@ -502,7 +537,7 @@
     <integer translatable="false" name="config_wifi_framework_network_black_list_min_time_milli">120000</integer>
 
     <!-- Integer indicating RSSI boost given to current network -->
-    <integer translatable="false" name="config_wifi_framework_current_network_boost">25</integer>
+    <integer translatable="false" name="config_wifi_framework_current_network_boost">16</integer>
 
     <!-- Integer indicating how to handle beacons with uninitialized RSSI value of 0 -->
     <integer translatable="false" name="config_wifi_framework_scan_result_rssi_level_patchup_value">-85</integer>
@@ -644,17 +679,6 @@
         <!-- rotation: 270 (rotate CW)  --> <item>-25</item> <item>65</item>
     </integer-array>
 
-    <!-- Indicate the name of the window orientation sensor type if present. A
-         window orientation sensor produces values to be used in lieu of the
-         typical, accelerometer based sensor. It must only produce integral
-         values between 0 and 3, inclusive, with each one corresponding to a
-         given rotation:
-            0: 0 degrees of rotation (natural)
-            1: 90 degrees of rotation (rotate CCW)
-            2: 180 degrees of rotation (reverse)
-            3: 270 degrees of rotation (rotate CW) -->
-    <string name="config_orientationSensorType" translatable="false">@null</string>
-
     <!-- Lid switch behavior -->
 
     <!-- The number of degrees to rotate the display when the keyboard is open.
@@ -974,6 +998,7 @@
             0 - Nothing
             1 - Recent apps view in SystemUI
             2 - Launch assist intent
+            3 - Start picture-in-picture (PIP) or launch PIP UI
          This needs to match the constants in
          policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
     -->
@@ -1969,9 +1994,9 @@
     <string-array name="config_notificationSignalExtractors">
         <item>com.android.server.notification.ValidateNotificationPeople</item>
         <item>com.android.server.notification.TopicPriorityExtractor</item>
+        <item>com.android.server.notification.TopicImportanceExtractor</item>
         <item>com.android.server.notification.NotificationIntrusivenessExtractor</item>
         <item>com.android.server.notification.TopicVisibilityExtractor</item>
-        <item>com.android.server.notification.TopicImportanceExtractor</item>
     </string-array>
 
     <!-- Flag indicating that this device does not rotate and will always remain in its default
@@ -2354,6 +2379,9 @@
          (range of 18 - 21 kHz). -->
     <bool name="config_supportSpeakerNearUltrasound">true</bool>
 
+    <!-- Whether the Unprocessed audio source supports the required frequency range and level -->
+    <bool name="config_supportAudioSourceUnprocessed">false</bool>
+
     <!-- Flag indicating device support for EAP SIM, AKA, AKA' -->
     <bool name="config_eap_sim_based_auth_supported">true</bool>
 
@@ -2370,7 +2398,7 @@
     <!-- Set initial MaxRetry value for operators -->
     <integer name="config_mdc_initial_max_retry">1</integer>
 
-    <!-- The OEM specified sensor type for the gesture to launch the camear app. -->
+    <!-- The OEM specified sensor type for the gesture to launch the camera app. -->
     <integer name="config_cameraLaunchGestureSensorType">-1</integer>
     <!-- The OEM specified sensor string type for the gesture to launch camera app, this value
          must match the value of config_cameraLaunchGestureSensorType in OEM's HAL -->
@@ -2407,4 +2435,38 @@
          that have not requested doing so (via the WindowManager.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
          flag). -->
     <bool name="config_forceWindowDrawsStatusBarBackground">true</bool>
+
+    <!-- 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)
+             2 - 1 snap target: 1:1
+    -->
+    <integer name="config_dockedStackDividerSnapMode">0</integer>
+
+    <!-- List of comma separated package names for which we the system will not show crash, ANR,
+         etc. dialogs. -->
+    <string translatable="false" name="config_appsNotReportingCrashes"></string>
+
+    <!-- Inactivity threshold (in milliseconds) used in JobScheduler. JobScheduler will consider
+         the device to be "idle" after being inactive for this long. -->
+    <integer name="config_jobSchedulerInactivityIdleThreshold">4260000</integer>
+    <!-- The alarm window (in milliseconds) that JobScheduler uses to enter the idle state -->
+    <integer name="config_jobSchedulerIdleWindowSlop">300000</integer>
+
+    <!-- If true, all guest users created on the device will be ephemeral. -->
+    <bool name="config_guestUserEphemeral">false</bool>
+
+    <!-- Enforce strong auth on boot. Setting this to false represents a security risk and should
+         not be ordinarily done. The only case in which this might be permissible is in a car head
+         unit where there are hardware mechanisms to protect the device (physical keys) and not
+         much in the way of user data.
+    -->
+    <bool name="config_strongAuthRequiredOnBoot">true</bool>
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index b167711..f92e7f0 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -35,6 +35,13 @@
     <dimen name="navigation_bar_height_landscape">48dp</dimen>
     <!-- Width of the navigation bar when it is placed vertically on the screen -->
     <dimen name="navigation_bar_width">48dp</dimen>
+    <!-- Height of the bottom navigation / system bar in car mode. -->
+    <dimen name="navigation_bar_height_car_mode">96dp</dimen>
+    <!-- Height of the bottom navigation bar in portrait; often the same as
+         @dimen/navigation_bar_height_car_mode -->
+    <dimen name="navigation_bar_height_landscape_car_mode">96dp</dimen>
+    <!-- Width of the navigation bar when it is placed vertically on the screen in car mode -->
+    <dimen name="navigation_bar_width_car_mode">96dp</dimen>
     <!-- Height of notification icons in the status bar -->
     <dimen name="status_bar_icon_size">24dip</dimen>
     <!-- Size of the giant number (unread count) in the notifications -->
@@ -47,7 +54,7 @@
 
     <!-- How much the content in the divider is inset from the window bounds when resting. Used to
          calculate the bounds of the stacks-->
-    <dimen name="docked_stack_divider_insets">18dp</dimen>
+    <dimen name="docked_stack_divider_insets">19dp</dimen>
 
     <!-- Min width for a tablet device -->
     <dimen name="min_xlarge_screen_width">800dp</dimen>
@@ -142,6 +149,9 @@
     <!-- height of the content margin to accomodate for the header -->
     <dimen name="notification_content_margin_top">30dp</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>
 
@@ -153,14 +163,11 @@
     <!-- The width of the big icons in notifications. -->
     <dimen name="notification_large_icon_height">64dp</dimen>
 
-    <!--  Min height of the notification content. -->
-    <dimen name="notification_min_content_height">54dp</dimen>
-
     <!-- The minimum width of the app name in the header if it shrinks -->
     <dimen name="notification_header_shrink_min_width">72dp</dimen>
 
-    <!-- The minimum height of the content if there is a picture present with big picture -->
-    <dimen name="notification_big_picture_content_min_height_with_picture">41dp</dimen>
+    <!-- The minimum height of the content if there are at least two lines or a picture-->
+    <dimen name="notification_min_content_height">41dp</dimen>
 
     <!-- Preferred width of the search view. -->
     <dimen name="search_view_preferred_width">320dip</dimen>
@@ -268,7 +275,7 @@
     <dimen name="notification_large_icon_circle_padding">11dp</dimen>
 
     <!-- Size of the profile badge for notifications -->
-    <dimen name="notification_badge_size">16dp</dimen>
+    <dimen name="notification_badge_size">12dp</dimen>
 
     <!-- Keyguard dimensions -->
     <!-- TEMP -->
@@ -429,4 +436,6 @@
 
     <item type="dimen" format="integer" name="time_picker_column_start_material">0</item>
     <item type="dimen" format="integer" name="time_picker_column_end_material">1</item>
+
+    <item type="fraction" name="docked_stack_divider_fixed_ratio">34.15%</item>
 </resources>
diff --git a/core/res/res/values/locale_config.xml b/core/res/res/values/locale_config.xml
new file mode 100644
index 0000000..f07fe70
--- /dev/null
+++ b/core/res/res/values/locale_config.xml
@@ -0,0 +1,498 @@
+<?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>
+
+    <string-array translatable="false" name="supported_locales">
+        <item>af-NA</item> <!-- Afrikaans (Namibia) -->
+        <item>af-ZA</item> <!-- Afrikaans (South Africa) -->
+        <item>agq-CM</item> <!-- Aghem (Cameroon) -->
+        <item>ak-GH</item> <!-- Akan (Ghana) -->
+        <item>am-ET</item> <!-- Amharic (Ethiopia) -->
+        <item>ar-AE</item> <!-- Arabic (United Arab Emirates) -->
+        <item>ar-BH</item> <!-- Arabic (Bahrain) -->
+        <item>ar-DJ</item> <!-- Arabic (Djibouti) -->
+        <item>ar-DZ</item> <!-- Arabic (Algeria) -->
+        <item>ar-EG</item> <!-- Arabic (Egypt) -->
+        <item>ar-EH</item> <!-- Arabic (Western Sahara) -->
+        <item>ar-ER</item> <!-- Arabic (Eritrea) -->
+        <item>ar-IL</item> <!-- Arabic (Israel) -->
+        <item>ar-IQ</item> <!-- Arabic (Iraq) -->
+        <item>ar-JO</item> <!-- Arabic (Jordan) -->
+        <item>ar-KM</item> <!-- Arabic (Comoros) -->
+        <item>ar-KW</item> <!-- Arabic (Kuwait) -->
+        <item>ar-LB</item> <!-- Arabic (Lebanon) -->
+        <item>ar-LY</item> <!-- Arabic (Libya) -->
+        <item>ar-MA</item> <!-- Arabic (Morocco) -->
+        <item>ar-MR</item> <!-- Arabic (Mauritania) -->
+        <item>ar-OM</item> <!-- Arabic (Oman) -->
+        <item>ar-PS</item> <!-- Arabic (Palestine) -->
+        <item>ar-QA</item> <!-- Arabic (Qatar) -->
+        <item>ar-SA</item> <!-- Arabic (Saudi Arabia) -->
+        <item>ar-SD</item> <!-- Arabic (Sudan) -->
+        <item>ar-SO</item> <!-- Arabic (Somalia) -->
+        <item>ar-SS</item> <!-- Arabic (South Sudan) -->
+        <item>ar-SY</item> <!-- Arabic (Syria) -->
+        <item>ar-TD</item> <!-- Arabic (Chad) -->
+        <item>ar-TN</item> <!-- Arabic (Tunisia) -->
+        <item>ar-XB</item> <!-- Right-to-left pseudolocale -->
+        <item>ar-YE</item> <!-- Arabic (Yemen) -->
+        <item>as-IN</item> <!-- Assamese (India) -->
+        <item>asa-TZ</item> <!-- Asu (Tanzania) -->
+        <item>az-Cyrl-AZ</item> <!-- Azerbaijani (Cyrillic,Azerbaijan) -->
+        <item>az-Latn-AZ</item> <!-- Azerbaijani (Latin,Azerbaijan) -->
+        <item>bas-CM</item> <!-- Basaa (Cameroon) -->
+        <item>be-BY</item> <!-- Belarusian (Belarus) -->
+        <item>bem-ZM</item> <!-- Bemba (Zambia) -->
+        <item>bez-TZ</item> <!-- Bena (Tanzania) -->
+        <item>bg-BG</item> <!-- Bulgarian (Bulgaria) -->
+        <item>bm-ML</item> <!-- Bambara (Mali) -->
+        <item>bn-BD</item> <!-- Bengali (Bangladesh) -->
+        <item>bn-IN</item> <!-- Bengali (India) -->
+        <item>bo-CN</item> <!-- Tibetan (China) -->
+        <item>bo-IN</item> <!-- Tibetan (India) -->
+        <item>br-FR</item> <!-- Breton (France) -->
+        <item>brx-IN</item> <!-- Bodo (India) -->
+        <item>bs-Cyrl-BA</item> <!-- Bosnian (Cyrillic,Bosnia & Herzegovina) -->
+        <item>bs-Latn-BA</item> <!-- Bosnian (Latin,Bosnia & Herzegovina) -->
+        <item>ca-AD</item> <!-- Catalan (Andorra) -->
+        <item>ca-ES</item> <!-- Catalan (Spain) -->
+        <item>ca-FR</item> <!-- Catalan (France) -->
+        <item>ca-IT</item> <!-- Catalan (Italy) -->
+        <item>ce-RU</item> <!-- Chechen (Russia) -->
+        <item>cgg-UG</item> <!-- Chiga (Uganda) -->
+        <item>chr-US</item> <!-- Cherokee (United States) -->
+        <item>cs-CZ</item> <!-- Czech (Czech Republic) -->
+        <item>cy-GB</item> <!-- Welsh (United Kingdom) -->
+        <item>da-DK</item> <!-- Danish (Denmark) -->
+        <item>da-GL</item> <!-- Danish (Greenland) -->
+        <item>dav-KE</item> <!-- Taita (Kenya) -->
+        <item>de-AT</item> <!-- German (Austria) -->
+        <item>de-BE</item> <!-- German (Belgium) -->
+        <item>de-CH</item> <!-- German (Switzerland) -->
+        <item>de-DE</item> <!-- German (Germany) -->
+        <item>de-LI</item> <!-- German (Liechtenstein) -->
+        <item>de-LU</item> <!-- German (Luxembourg) -->
+        <item>dje-NE</item> <!-- Zarma (Niger) -->
+        <item>dsb-DE</item> <!-- Lower Sorbian (Germany) -->
+        <item>dua-CM</item> <!-- Duala (Cameroon) -->
+        <item>dyo-SN</item> <!-- Jola-Fonyi (Senegal) -->
+        <item>dz-BT</item> <!-- Dzongkha (Bhutan) -->
+        <item>ebu-KE</item> <!-- Embu (Kenya) -->
+        <item>ee-GH</item> <!-- Ewe (Ghana) -->
+        <item>ee-TG</item> <!-- Ewe (Togo) -->
+        <item>el-CY</item> <!-- Greek (Cyprus) -->
+        <item>el-GR</item> <!-- Greek (Greece) -->
+        <item>en-AG</item> <!-- English (Antigua & Barbuda) -->
+        <item>en-AI</item> <!-- English (Anguilla) -->
+        <item>en-AS</item> <!-- English (American Samoa) -->
+        <item>en-AT</item> <!-- English (Austria) -->
+        <item>en-AU</item> <!-- English (Australia) -->
+        <item>en-BB</item> <!-- English (Barbados) -->
+        <item>en-BE</item> <!-- English (Belgium) -->
+        <item>en-BI</item> <!-- English (Burundi) -->
+        <item>en-BM</item> <!-- English (Bermuda) -->
+        <item>en-BS</item> <!-- English (Bahamas) -->
+        <item>en-BW</item> <!-- English (Botswana) -->
+        <item>en-BZ</item> <!-- English (Belize) -->
+        <item>en-CA</item> <!-- English (Canada) -->
+        <item>en-CC</item> <!-- English (Cocos (Keeling) Islands) -->
+        <item>en-CH</item> <!-- English (Switzerland) -->
+        <item>en-CK</item> <!-- English (Cook Islands) -->
+        <item>en-CM</item> <!-- English (Cameroon) -->
+        <item>en-CX</item> <!-- English (Christmas Island) -->
+        <item>en-CY</item> <!-- English (Cyprus) -->
+        <item>en-DE</item> <!-- English (Germany) -->
+        <item>en-DG</item> <!-- English (Diego Garcia) -->
+        <item>en-DK</item> <!-- English (Denmark) -->
+        <item>en-DM</item> <!-- English (Dominica) -->
+        <item>en-ER</item> <!-- English (Eritrea) -->
+        <item>en-FI</item> <!-- English (Finland) -->
+        <item>en-FJ</item> <!-- English (Fiji) -->
+        <item>en-FK</item> <!-- English (Falkland Islands (Islas Malvinas)) -->
+        <item>en-FM</item> <!-- English (Micronesia) -->
+        <item>en-GB</item> <!-- English (United Kingdom) -->
+        <item>en-GD</item> <!-- English (Grenada) -->
+        <item>en-GG</item> <!-- English (Guernsey) -->
+        <item>en-GH</item> <!-- English (Ghana) -->
+        <item>en-GI</item> <!-- English (Gibraltar) -->
+        <item>en-GM</item> <!-- English (Gambia) -->
+        <item>en-GU</item> <!-- English (Guam) -->
+        <item>en-GY</item> <!-- English (Guyana) -->
+        <item>en-HK</item> <!-- English (Hong Kong) -->
+        <item>en-IE</item> <!-- English (Ireland) -->
+        <item>en-IL</item> <!-- English (Israel) -->
+        <item>en-IM</item> <!-- English (Isle of Man) -->
+        <item>en-IN</item> <!-- English (India) -->
+        <item>en-IO</item> <!-- English (British Indian Ocean Territory) -->
+        <item>en-JE</item> <!-- English (Jersey) -->
+        <item>en-JM</item> <!-- English (Jamaica) -->
+        <item>en-KE</item> <!-- English (Kenya) -->
+        <item>en-KI</item> <!-- English (Kiribati) -->
+        <item>en-KN</item> <!-- English (St. Kitts & Nevis) -->
+        <item>en-KY</item> <!-- English (Cayman Islands) -->
+        <item>en-LC</item> <!-- English (St. Lucia) -->
+        <item>en-LR</item> <!-- English (Liberia) -->
+        <item>en-LS</item> <!-- English (Lesotho) -->
+        <item>en-MG</item> <!-- English (Madagascar) -->
+        <item>en-MH</item> <!-- English (Marshall Islands) -->
+        <item>en-MO</item> <!-- English (Macau) -->
+        <item>en-MP</item> <!-- English (Northern Mariana Islands) -->
+        <item>en-MS</item> <!-- English (Montserrat) -->
+        <item>en-MT</item> <!-- English (Malta) -->
+        <item>en-MU</item> <!-- English (Mauritius) -->
+        <item>en-MW</item> <!-- English (Malawi) -->
+        <item>en-MY</item> <!-- English (Malaysia) -->
+        <item>en-NA</item> <!-- English (Namibia) -->
+        <item>en-NF</item> <!-- English (Norfolk Island) -->
+        <item>en-NG</item> <!-- English (Nigeria) -->
+        <item>en-NL</item> <!-- English (Netherlands) -->
+        <item>en-NR</item> <!-- English (Nauru) -->
+        <item>en-NU</item> <!-- English (Niue) -->
+        <item>en-NZ</item> <!-- English (New Zealand) -->
+        <item>en-PG</item> <!-- English (Papua New Guinea) -->
+        <item>en-PH</item> <!-- English (Philippines) -->
+        <item>en-PK</item> <!-- English (Pakistan) -->
+        <item>en-PN</item> <!-- English (Pitcairn Islands) -->
+        <item>en-PR</item> <!-- English (Puerto Rico) -->
+        <item>en-PW</item> <!-- English (Palau) -->
+        <item>en-RW</item> <!-- English (Rwanda) -->
+        <item>en-SB</item> <!-- English (Solomon Islands) -->
+        <item>en-SC</item> <!-- English (Seychelles) -->
+        <item>en-SD</item> <!-- English (Sudan) -->
+        <item>en-SE</item> <!-- English (Sweden) -->
+        <item>en-SG</item> <!-- English (Singapore) -->
+        <item>en-SH</item> <!-- English (St. Helena) -->
+        <item>en-SI</item> <!-- English (Slovenia) -->
+        <item>en-SL</item> <!-- English (Sierra Leone) -->
+        <item>en-SS</item> <!-- English (South Sudan) -->
+        <item>en-SX</item> <!-- English (Sint Maarten) -->
+        <item>en-SZ</item> <!-- English (Swaziland) -->
+        <item>en-TC</item> <!-- English (Turks & Caicos Islands) -->
+        <item>en-TK</item> <!-- English (Tokelau) -->
+        <item>en-TO</item> <!-- English (Tonga) -->
+        <item>en-TT</item> <!-- English (Trinidad & Tobago) -->
+        <item>en-TV</item> <!-- English (Tuvalu) -->
+        <item>en-TZ</item> <!-- English (Tanzania) -->
+        <item>en-UG</item> <!-- English (Uganda) -->
+        <item>en-UM</item> <!-- English (U.S. Outlying Islands) -->
+        <item>en-US</item> <!-- English (United States) -->
+        <item>en-VC</item> <!-- English (St. Vincent & Grenadines) -->
+        <item>en-VG</item> <!-- English (British Virgin Islands) -->
+        <item>en-VI</item> <!-- English (U.S. Virgin Islands) -->
+        <item>en-VU</item> <!-- English (Vanuatu) -->
+        <item>en-WS</item> <!-- English (Samoa) -->
+        <item>en-XA</item> <!-- Left-to-right pseudolocale -->
+        <item>en-ZA</item> <!-- English (South Africa) -->
+        <item>en-ZM</item> <!-- English (Zambia) -->
+        <item>en-ZW</item> <!-- English (Zimbabwe) -->
+        <item>es-AR</item> <!-- Spanish (Argentina) -->
+        <item>es-BO</item> <!-- Spanish (Bolivia) -->
+        <item>es-CL</item> <!-- Spanish (Chile) -->
+        <item>es-CO</item> <!-- Spanish (Colombia) -->
+        <item>es-CR</item> <!-- Spanish (Costa Rica) -->
+        <item>es-CU</item> <!-- Spanish (Cuba) -->
+        <item>es-DO</item> <!-- Spanish (Dominican Republic) -->
+        <item>es-EA</item> <!-- Spanish (Ceuta & Melilla) -->
+        <item>es-EC</item> <!-- Spanish (Ecuador) -->
+        <item>es-ES</item> <!-- Spanish (Spain) -->
+        <item>es-GQ</item> <!-- Spanish (Equatorial Guinea) -->
+        <item>es-GT</item> <!-- Spanish (Guatemala) -->
+        <item>es-HN</item> <!-- Spanish (Honduras) -->
+        <item>es-IC</item> <!-- Spanish (Canary Islands) -->
+        <item>es-MX</item> <!-- Spanish (Mexico) -->
+        <item>es-NI</item> <!-- Spanish (Nicaragua) -->
+        <item>es-PA</item> <!-- Spanish (Panama) -->
+        <item>es-PE</item> <!-- Spanish (Peru) -->
+        <item>es-PH</item> <!-- Spanish (Philippines) -->
+        <item>es-PR</item> <!-- Spanish (Puerto Rico) -->
+        <item>es-PY</item> <!-- Spanish (Paraguay) -->
+        <item>es-SV</item> <!-- Spanish (El Salvador) -->
+        <item>es-US</item> <!-- Spanish (United States) -->
+        <item>es-UY</item> <!-- Spanish (Uruguay) -->
+        <item>es-VE</item> <!-- Spanish (Venezuela) -->
+        <item>et-EE</item> <!-- Estonian (Estonia) -->
+        <item>eu-ES</item> <!-- Basque (Spain) -->
+        <item>ewo-CM</item> <!-- Ewondo (Cameroon) -->
+        <item>fa-AF</item> <!-- Persian (Afghanistan) -->
+        <item>fa-IR</item> <!-- Persian (Iran) -->
+        <item>ff-CM</item> <!-- Fulah (Cameroon) -->
+        <item>ff-GN</item> <!-- Fulah (Guinea) -->
+        <item>ff-MR</item> <!-- Fulah (Mauritania) -->
+        <item>ff-SN</item> <!-- Fulah (Senegal) -->
+        <item>fi-FI</item> <!-- Finnish (Finland) -->
+        <item>fil-PH</item> <!-- Filipino (Philippines) -->
+        <item>fo-DK</item> <!-- Faroese (Denmark) -->
+        <item>fo-FO</item> <!-- Faroese (Faroe Islands) -->
+        <item>fr-BE</item> <!-- French (Belgium) -->
+        <item>fr-BF</item> <!-- French (Burkina Faso) -->
+        <item>fr-BI</item> <!-- French (Burundi) -->
+        <item>fr-BJ</item> <!-- French (Benin) -->
+        <item>fr-BL</item> <!-- French (St. Barthélemy) -->
+        <item>fr-CA</item> <!-- French (Canada) -->
+        <item>fr-CD</item> <!-- French (Congo (DRC)) -->
+        <item>fr-CF</item> <!-- French (Central African Republic) -->
+        <item>fr-CG</item> <!-- French (Congo (Republic)) -->
+        <item>fr-CH</item> <!-- French (Switzerland) -->
+        <item>fr-CI</item> <!-- French (Côte d’Ivoire) -->
+        <item>fr-CM</item> <!-- French (Cameroon) -->
+        <item>fr-DJ</item> <!-- French (Djibouti) -->
+        <item>fr-DZ</item> <!-- French (Algeria) -->
+        <item>fr-FR</item> <!-- French (France) -->
+        <item>fr-GA</item> <!-- French (Gabon) -->
+        <item>fr-GF</item> <!-- French (French Guiana) -->
+        <item>fr-GN</item> <!-- French (Guinea) -->
+        <item>fr-GP</item> <!-- French (Guadeloupe) -->
+        <item>fr-GQ</item> <!-- French (Equatorial Guinea) -->
+        <item>fr-HT</item> <!-- French (Haiti) -->
+        <item>fr-KM</item> <!-- French (Comoros) -->
+        <item>fr-LU</item> <!-- French (Luxembourg) -->
+        <item>fr-MA</item> <!-- French (Morocco) -->
+        <item>fr-MC</item> <!-- French (Monaco) -->
+        <item>fr-MF</item> <!-- French (St. Martin) -->
+        <item>fr-MG</item> <!-- French (Madagascar) -->
+        <item>fr-ML</item> <!-- French (Mali) -->
+        <item>fr-MQ</item> <!-- French (Martinique) -->
+        <item>fr-MR</item> <!-- French (Mauritania) -->
+        <item>fr-MU</item> <!-- French (Mauritius) -->
+        <item>fr-NC</item> <!-- French (New Caledonia) -->
+        <item>fr-NE</item> <!-- French (Niger) -->
+        <item>fr-PF</item> <!-- French (French Polynesia) -->
+        <item>fr-PM</item> <!-- French (St. Pierre & Miquelon) -->
+        <item>fr-RE</item> <!-- French (Réunion) -->
+        <item>fr-RW</item> <!-- French (Rwanda) -->
+        <item>fr-SC</item> <!-- French (Seychelles) -->
+        <item>fr-SN</item> <!-- French (Senegal) -->
+        <item>fr-SY</item> <!-- French (Syria) -->
+        <item>fr-TD</item> <!-- French (Chad) -->
+        <item>fr-TG</item> <!-- French (Togo) -->
+        <item>fr-TN</item> <!-- French (Tunisia) -->
+        <item>fr-VU</item> <!-- French (Vanuatu) -->
+        <item>fr-WF</item> <!-- French (Wallis & Futuna) -->
+        <item>fr-YT</item> <!-- French (Mayotte) -->
+        <item>fur-IT</item> <!-- Friulian (Italy) -->
+        <item>fy-NL</item> <!-- Western Frisian (Netherlands) -->
+        <item>ga-IE</item> <!-- Irish (Ireland) -->
+        <item>gd-GB</item> <!-- Scottish Gaelic (United Kingdom) -->
+        <item>gl-ES</item> <!-- Galician (Spain) -->
+        <item>gsw-CH</item> <!-- Swiss German (Switzerland) -->
+        <item>gsw-FR</item> <!-- Swiss German (France) -->
+        <item>gsw-LI</item> <!-- Swiss German (Liechtenstein) -->
+        <item>gu-IN</item> <!-- Gujarati (India) -->
+        <item>guz-KE</item> <!-- Gusii (Kenya) -->
+        <item>gv-IM</item> <!-- Manx (Isle of Man) -->
+        <item>ha-GH</item> <!-- Hausa (Ghana) -->
+        <item>ha-NE</item> <!-- Hausa (Niger) -->
+        <item>ha-NG</item> <!-- Hausa (Nigeria) -->
+        <item>haw-US</item> <!-- Hawaiian (United States) -->
+        <item>iw-IL</item> <!-- Hebrew (Israel) -->
+        <item>hi-IN</item> <!-- Hindi (India) -->
+        <item>hr-BA</item> <!-- Croatian (Bosnia & Herzegovina) -->
+        <item>hr-HR</item> <!-- Croatian (Croatia) -->
+        <item>hsb-DE</item> <!-- Upper Sorbian (Germany) -->
+        <item>hu-HU</item> <!-- Hungarian (Hungary) -->
+        <item>hy-AM</item> <!-- Armenian (Armenia) -->
+        <item>in-ID</item> <!-- Indonesian (Indonesia) -->
+        <item>ig-NG</item> <!-- Igbo (Nigeria) -->
+        <item>ii-CN</item> <!-- Sichuan Yi (China) -->
+        <item>is-IS</item> <!-- Icelandic (Iceland) -->
+        <item>it-CH</item> <!-- Italian (Switzerland) -->
+        <item>it-IT</item> <!-- Italian (Italy) -->
+        <item>it-SM</item> <!-- Italian (San Marino) -->
+        <item>ja-JP</item> <!-- Japanese (Japan) -->
+        <item>jgo-CM</item> <!-- Ngomba (Cameroon) -->
+        <item>jmc-TZ</item> <!-- Machame (Tanzania) -->
+        <item>ka-GE</item> <!-- Georgian (Georgia) -->
+        <item>kab-DZ</item> <!-- Kabyle (Algeria) -->
+        <item>kam-KE</item> <!-- Kamba (Kenya) -->
+        <item>kde-TZ</item> <!-- Makonde (Tanzania) -->
+        <item>kea-CV</item> <!-- Kabuverdianu (Cape Verde) -->
+        <item>khq-ML</item> <!-- Koyra Chiini (Mali) -->
+        <item>ki-KE</item> <!-- Kikuyu (Kenya) -->
+        <item>kk-KZ</item> <!-- Kazakh (Kazakhstan) -->
+        <item>kkj-CM</item> <!-- Kako (Cameroon) -->
+        <item>kl-GL</item> <!-- Kalaallisut (Greenland) -->
+        <item>kln-KE</item> <!-- Kalenjin (Kenya) -->
+        <item>km-KH</item> <!-- Khmer (Cambodia) -->
+        <item>kn-IN</item> <!-- Kannada (India) -->
+        <item>ko-KP</item> <!-- Korean (North Korea) -->
+        <item>ko-KR</item> <!-- Korean (South Korea) -->
+        <item>kok-IN</item> <!-- Konkani (India) -->
+        <item>ksb-TZ</item> <!-- Shambala (Tanzania) -->
+        <item>ksf-CM</item> <!-- Bafia (Cameroon) -->
+        <item>ksh-DE</item> <!-- Colognian (Germany) -->
+        <item>kw-GB</item> <!-- Cornish (United Kingdom) -->
+        <item>ky-KG</item> <!-- Kyrgyz (Kyrgyzstan) -->
+        <item>lag-TZ</item> <!-- Langi (Tanzania) -->
+        <item>lb-LU</item> <!-- Luxembourgish (Luxembourg) -->
+        <item>lg-UG</item> <!-- Ganda (Uganda) -->
+        <item>lkt-US</item> <!-- Lakota (United States) -->
+        <item>ln-AO</item> <!-- Lingala (Angola) -->
+        <item>ln-CD</item> <!-- Lingala (Congo (DRC)) -->
+        <item>ln-CF</item> <!-- Lingala (Central African Republic) -->
+        <item>ln-CG</item> <!-- Lingala (Congo (Republic)) -->
+        <item>lo-LA</item> <!-- Lao (Laos) -->
+        <item>lt-LT</item> <!-- Lithuanian (Lithuania) -->
+        <item>lu-CD</item> <!-- Luba-Katanga (Congo (DRC)) -->
+        <item>luo-KE</item> <!-- Luo (Kenya) -->
+        <item>luy-KE</item> <!-- Luyia (Kenya) -->
+        <item>lv-LV</item> <!-- Latvian (Latvia) -->
+        <item>mas-KE</item> <!-- Masai (Kenya) -->
+        <item>mas-TZ</item> <!-- Masai (Tanzania) -->
+        <item>mer-KE</item> <!-- Meru (Kenya) -->
+        <item>mfe-MU</item> <!-- Morisyen (Mauritius) -->
+        <item>mg-MG</item> <!-- Malagasy (Madagascar) -->
+        <item>mgh-MZ</item> <!-- Makhuwa-Meetto (Mozambique) -->
+        <item>mgo-CM</item> <!-- Metaʼ (Cameroon) -->
+        <item>mk-MK</item> <!-- Macedonian (Macedonia (FYROM)) -->
+        <item>ml-IN</item> <!-- Malayalam (India) -->
+        <item>mn-MN</item> <!-- Mongolian (Mongolia) -->
+        <item>mr-IN</item> <!-- Marathi (India) -->
+        <item>ms-BN</item> <!-- Malay (Brunei) -->
+        <item>ms-MY</item> <!-- Malay (Malaysia) -->
+        <item>ms-SG</item> <!-- Malay (Singapore) -->
+        <item>mt-MT</item> <!-- Maltese (Malta) -->
+        <item>my-MM</item> <!-- Burmese (Myanmar (Burma)) -->
+        <item>mzn-IR</item> <!-- Mazanderani (Iran) -->
+        <item>naq-NA</item> <!-- Nama (Namibia) -->
+        <item>nb-NO</item> <!-- Norwegian Bokmål (Norway) -->
+        <item>nb-SJ</item> <!-- Norwegian Bokmål (Svalbard & Jan Mayen) -->
+        <item>nd-ZW</item> <!-- North Ndebele (Zimbabwe) -->
+        <item>ne-IN</item> <!-- Nepali (India) -->
+        <item>ne-NP</item> <!-- Nepali (Nepal) -->
+        <item>nl-AW</item> <!-- Dutch (Aruba) -->
+        <item>nl-BE</item> <!-- Dutch (Belgium) -->
+        <item>nl-BQ</item> <!-- Dutch (Caribbean Netherlands) -->
+        <item>nl-CW</item> <!-- Dutch (Curaçao) -->
+        <item>nl-NL</item> <!-- Dutch (Netherlands) -->
+        <item>nl-SR</item> <!-- Dutch (Suriname) -->
+        <item>nl-SX</item> <!-- Dutch (Sint Maarten) -->
+        <item>nmg-CM</item> <!-- Kwasio (Cameroon) -->
+        <item>nn-NO</item> <!-- Norwegian Nynorsk (Norway) -->
+        <item>nnh-CM</item> <!-- Ngiemboon (Cameroon) -->
+        <item>nus-SS</item> <!-- Nuer (South Sudan) -->
+        <item>nyn-UG</item> <!-- Nyankole (Uganda) -->
+        <item>om-ET</item> <!-- Oromo (Ethiopia) -->
+        <item>om-KE</item> <!-- Oromo (Kenya) -->
+        <item>or-IN</item> <!-- Oriya (India) -->
+        <item>os-GE</item> <!-- Ossetic (Georgia) -->
+        <item>os-RU</item> <!-- Ossetic (Russia) -->
+        <item>pa-Arab-PK</item> <!-- Punjabi (Arabic,Pakistan) -->
+        <item>pa-Guru-IN</item> <!-- Punjabi (Gurmukhi,India) -->
+        <item>pl-PL</item> <!-- Polish (Poland) -->
+        <item>ps-AF</item> <!-- Pashto (Afghanistan) -->
+        <item>pt-AO</item> <!-- Portuguese (Angola) -->
+        <item>pt-BR</item> <!-- Portuguese (Brazil) -->
+        <item>pt-CV</item> <!-- Portuguese (Cape Verde) -->
+        <item>pt-GW</item> <!-- Portuguese (Guinea-Bissau) -->
+        <item>pt-MO</item> <!-- Portuguese (Macau) -->
+        <item>pt-MZ</item> <!-- Portuguese (Mozambique) -->
+        <item>pt-PT</item> <!-- Portuguese (Portugal) -->
+        <item>pt-ST</item> <!-- Portuguese (São Tomé & Príncipe) -->
+        <item>pt-TL</item> <!-- Portuguese (Timor-Leste) -->
+        <item>qu-BO</item> <!-- Quechua (Bolivia) -->
+        <item>qu-EC</item> <!-- Quechua (Ecuador) -->
+        <item>qu-PE</item> <!-- Quechua (Peru) -->
+        <item>rm-CH</item> <!-- Romansh (Switzerland) -->
+        <item>rn-BI</item> <!-- Rundi (Burundi) -->
+        <item>ro-MD</item> <!-- Romanian (Moldova) -->
+        <item>ro-RO</item> <!-- Romanian (Romania) -->
+        <item>rof-TZ</item> <!-- Rombo (Tanzania) -->
+        <item>ru-BY</item> <!-- Russian (Belarus) -->
+        <item>ru-KG</item> <!-- Russian (Kyrgyzstan) -->
+        <item>ru-KZ</item> <!-- Russian (Kazakhstan) -->
+        <item>ru-MD</item> <!-- Russian (Moldova) -->
+        <item>ru-RU</item> <!-- Russian (Russia) -->
+        <item>ru-UA</item> <!-- Russian (Ukraine) -->
+        <item>rw-RW</item> <!-- Kinyarwanda (Rwanda) -->
+        <item>rwk-TZ</item> <!-- Rwa (Tanzania) -->
+        <item>sah-RU</item> <!-- Sakha (Russia) -->
+        <item>saq-KE</item> <!-- Samburu (Kenya) -->
+        <item>sbp-TZ</item> <!-- Sangu (Tanzania) -->
+        <item>se-FI</item> <!-- Northern Sami (Finland) -->
+        <item>se-NO</item> <!-- Northern Sami (Norway) -->
+        <item>se-SE</item> <!-- Northern Sami (Sweden) -->
+        <item>seh-MZ</item> <!-- Sena (Mozambique) -->
+        <item>ses-ML</item> <!-- Koyraboro Senni (Mali) -->
+        <item>sg-CF</item> <!-- Sango (Central African Republic) -->
+        <item>si-LK</item> <!-- Sinhala (Sri Lanka) -->
+        <item>sk-SK</item> <!-- Slovak (Slovakia) -->
+        <item>sl-SI</item> <!-- Slovenian (Slovenia) -->
+        <item>smn-FI</item> <!-- Inari Sami (Finland) -->
+        <item>sn-ZW</item> <!-- Shona (Zimbabwe) -->
+        <item>so-DJ</item> <!-- Somali (Djibouti) -->
+        <item>so-ET</item> <!-- Somali (Ethiopia) -->
+        <item>so-KE</item> <!-- Somali (Kenya) -->
+        <item>so-SO</item> <!-- Somali (Somalia) -->
+        <item>sq-AL</item> <!-- Albanian (Albania) -->
+        <item>sq-MK</item> <!-- Albanian (Macedonia (FYROM)) -->
+        <item>sq-XK</item> <!-- Albanian (Kosovo) -->
+        <item>sr-Cyrl-BA</item> <!-- Serbian (Cyrillic,Bosnia & Herzegovina) -->
+        <item>sr-Cyrl-ME</item> <!-- Serbian (Cyrillic,Montenegro) -->
+        <item>sr-Cyrl-RS</item> <!-- Serbian (Cyrillic,Serbia) -->
+        <item>sr-Cyrl-XK</item> <!-- Serbian (Cyrillic,Kosovo) -->
+        <item>sr-Latn-BA</item> <!-- Serbian (Latin,Bosnia & Herzegovina) -->
+        <item>sr-Latn-ME</item> <!-- Serbian (Latin,Montenegro) -->
+        <item>sr-Latn-RS</item> <!-- Serbian (Latin,Serbia) -->
+        <item>sr-Latn-XK</item> <!-- Serbian (Latin,Kosovo) -->
+        <item>sv-AX</item> <!-- Swedish (Åland Islands) -->
+        <item>sv-FI</item> <!-- Swedish (Finland) -->
+        <item>sv-SE</item> <!-- Swedish (Sweden) -->
+        <item>sw-CD</item> <!-- Swahili (Congo (DRC)) -->
+        <item>sw-KE</item> <!-- Swahili (Kenya) -->
+        <item>sw-TZ</item> <!-- Swahili (Tanzania) -->
+        <item>sw-UG</item> <!-- Swahili (Uganda) -->
+        <item>ta-IN</item> <!-- Tamil (India) -->
+        <item>ta-LK</item> <!-- Tamil (Sri Lanka) -->
+        <item>ta-MY</item> <!-- Tamil (Malaysia) -->
+        <item>ta-SG</item> <!-- Tamil (Singapore) -->
+        <item>te-IN</item> <!-- Telugu (India) -->
+        <item>teo-KE</item> <!-- Teso (Kenya) -->
+        <item>teo-UG</item> <!-- Teso (Uganda) -->
+        <item>th-TH</item> <!-- Thai (Thailand) -->
+        <item>ti-ER</item> <!-- Tigrinya (Eritrea) -->
+        <item>ti-ET</item> <!-- Tigrinya (Ethiopia) -->
+        <item>to-TO</item> <!-- Tongan (Tonga) -->
+        <item>tr-CY</item> <!-- Turkish (Cyprus) -->
+        <item>tr-TR</item> <!-- Turkish (Turkey) -->
+        <item>twq-NE</item> <!-- Tasawaq (Niger) -->
+        <item>tzm-MA</item> <!-- Central Atlas Tamazight (Morocco) -->
+        <item>ug-CN</item> <!-- Uyghur (China) -->
+        <item>uk-UA</item> <!-- Ukrainian (Ukraine) -->
+        <item>ur-IN</item> <!-- Urdu (India) -->
+        <item>ur-PK</item> <!-- Urdu (Pakistan) -->
+        <item>uz-Arab-AF</item> <!-- Uzbek (Arabic,Afghanistan) -->
+        <item>uz-Cyrl-UZ</item> <!-- Uzbek (Cyrillic,Uzbekistan) -->
+        <item>uz-Latn-UZ</item> <!-- Uzbek (Latin,Uzbekistan) -->
+        <item>vi-VN</item> <!-- Vietnamese (Vietnam) -->
+        <item>vun-TZ</item> <!-- Vunjo (Tanzania) -->
+        <item>wae-CH</item> <!-- Walser (Switzerland) -->
+        <item>xog-UG</item> <!-- Soga (Uganda) -->
+        <item>yav-CM</item> <!-- Yangben (Cameroon) -->
+        <item>yo-BJ</item> <!-- Yoruba (Benin) -->
+        <item>yo-NG</item> <!-- Yoruba (Nigeria) -->
+        <item>zgh-MA</item> <!-- Standard Moroccan Tamazight (Morocco) -->
+        <item>zh-Hans-CN</item> <!-- Chinese (Simplified Han,China) -->
+        <item>zh-Hans-HK</item> <!-- Chinese (Simplified Han,Hong Kong) -->
+        <item>zh-Hans-MO</item> <!-- Chinese (Simplified Han,Macau) -->
+        <item>zh-Hans-SG</item> <!-- Chinese (Simplified Han,Singapore) -->
+        <item>zh-Hant-HK</item> <!-- Chinese (Traditional Han,Hong Kong) -->
+        <item>zh-Hant-MO</item> <!-- Chinese (Traditional Han,Macau) -->
+        <item>zh-Hant-TW</item> <!-- Chinese (Traditional Han,Taiwan) -->
+        <item>zu-ZA</item> <!-- Zulu (South Africa) -->
+    </string-array>
+
+</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index ad36f3c..a2ad09b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2685,24 +2685,20 @@
     <public type="attr" name="canControlMagnification" />
     <public type="attr" name="languageTag" />
     <public type="attr" name="pointerShape" />
+    <public type="attr" name="tickMark" />
+    <public type="attr" name="tickMarkTint" />
+    <public type="attr" name="tickMarkTintMode" />
+    <public type="attr" name="canPerformGestures" />
+    <public type="attr" name="externalService" />
+    <public type="attr" name="supportsLocalInteraction" />
+    <public type="attr" name="startX" />
+    <public type="attr" name="startY" />
+    <public type="attr" name="endX" />
+    <public type="attr" name="endY" />
+    <public type="attr" name="offset" />
 
-    <public type="style" name="Theme.Material.DayNight" />
-    <public type="style" name="Theme.Material.DayNight.DarkActionBar" />
-    <public type="style" name="Theme.Material.DayNight.Dialog" />
-    <public type="style" name="Theme.Material.DayNight.Dialog.Alert" />
-    <public type="style" name="Theme.Material.DayNight.Dialog.MinWidth" />
-    <public type="style" name="Theme.Material.DayNight.Dialog.NoActionBar" />
-    <public type="style" name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" />
-    <public type="style" name="Theme.Material.DayNight.Dialog.Presentation" />
-    <public type="style" name="Theme.Material.DayNight.DialogWhenLarge" />
-    <public type="style" name="Theme.Material.DayNight.DialogWhenLarge.NoActionBar" />
-    <public type="style" name="Theme.Material.DayNight.NoActionBar" />
-    <public type="style" name="Theme.Material.DayNight.NoActionBar.Fullscreen" />
-    <public type="style" name="Theme.Material.DayNight.NoActionBar.Overscan" />
-    <public type="style" name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" />
-    <public type="style" name="Theme.Material.DayNight.Panel" />
     <public type="style" name="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
-    <public type="style" name="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar" />
+    <public type="style" name="Widget.Material.SeekBar.Discrete" />
 
     <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 4d967ff..26421fb 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -487,10 +487,29 @@
     <!-- Take bug report menu title [CHAR LIMIT=NONE] -->
     <string name="bugreport_title">Take bug report</string>
     <!-- Message in bugreport dialog describing what it does [CHAR LIMIT=NONE] -->
+    <!-- TODO: remove if not used anymore -->
     <string name="bugreport_message">This will collect information about your
         current device state, to send as an e-mail message.  It will take a little
         time from starting the bug report until it is ready to be sent; please be
         patient.</string>
+    <!-- Title in the bugreport dialog for the interactive workflow. Should fit in one line. [CHAR LIMIT=30] -->
+    <string name="bugreport_option_interactive_title">Interactive report</string>
+    <!-- Summary in the bugreport dialog for the interactive workflow. [CHAR LIMIT=NONE] -->
+    <string name="bugreport_option_interactive_summary">Use this under most circumstances.
+        It allows you to track progress of the report and enter more details about the problem.
+        It might omit some less-used sections that take a long time to report.</string>
+    <!-- Title in the bugreport dialog for the full workflow. Should fit in one line. [CHAR LIMIT=30] -->
+    <string name="bugreport_option_full_title">Full report</string>
+    <!-- Summary in the bugreport dialog for the full workflow. [CHAR LIMIT=NONE] -->
+    <string name="bugreport_option_full_summary">Use this option for minimal system interference when
+        your device is unresponsive or too slow, or when you need all report sections.
+        Does not take a screenshot or allow you to enter more details.</string>
+    <!--  Toast message informing user in how many seconds a bugreport screenshot will be taken -->
+    <plurals name="bugreport_countdown">
+        <item quantity="one">Taking screenshot for bug report in <xliff:g id="number">%d</xliff:g> second.</item>
+        <item quantity="other">Taking screenshot for bug report in <xliff:g id="number">%d</xliff:g> seconds.</item>
+    </plurals>
+
     <!-- Format for build summary info [CHAR LIMIT=NONE] -->
     <string name="bugreport_status" translatable="false">%s (%s)</string>
 
@@ -537,6 +556,12 @@
     <!-- The divider symbol between different parts of the notification header. not translatable [CHAR LIMIT=1] -->
     <string name="notification_header_divider_symbol" translatable="false">•</string>
 
+    <!-- Text shown in place of notification contents when the notification is hidden on a secure lockscreen -->
+    <string name="notification_hidden_text">Contents hidden</string>
+
+    <!-- Text shown in place of notification contents when the notification is hidden by policy on a secure lockscreen -->
+    <string name="notification_hidden_by_policy_text">Contents hidden by policy</string>
+
     <!-- Displayed to the user to tell them that they have started up the phone in "safe mode" -->
     <string name="safeMode">Safe mode</string>
 
@@ -625,6 +650,12 @@
     <string name="capability_desc_canControlMagnification">Control the display\'s zoom level and
         positioning.</string>
 
+    <!-- Title for the capability of an accessibility service to perform gestures. -->
+    <string name="capability_title_canPerformGestures">Perform gestures</string>
+    <!-- Description for the capability of an accessibility service to perform gestures. -->
+    <string name="capability_desc_canPerformGestures">Can tap, swipe, pinch, and perform other
+        gestures.</string>
+
     <!--  Permissions -->
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -999,11 +1030,6 @@
     <string name="permdesc_vibrate">Allows the app to control the vibrator.</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_flashlight">control flashlight</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_flashlight">Allows the app to control the flashlight.</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_callPhone">directly call phone numbers</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_callPhone">Allows the app to call phone numbers
@@ -2453,6 +2479,9 @@
     <!-- Item on EditText context menu. This action is used to paste from the clipboard into the eidt field -->
     <string name="paste">Paste</string>
 
+    <!-- Item on EditText context menu. This action is used to paste from the clipboard into the eidt field without formatting -->
+    <string name="paste_as_plain_text">Paste as plain text</string>
+
     <!-- Item on EditText context menu. This action is used to replace the current word by other suggested words, suggested by the IME or the spell checker -->
     <string name="replace">Replace\u2026</string>
 
@@ -2465,6 +2494,12 @@
     <!-- Item on EditText context menu. Added only when the context menu is not empty, it enable selection context mode. [CHAR LIMIT=20] -->
     <string name="selectTextMode">Select text</string>
 
+    <!-- Item on EditText context menu. This action is used to undo a text edit operation. -->
+    <string name="undo">Undo</string>
+
+    <!-- Item on EditText context menu. This action is used to redo a text edit operation. -->
+    <string name="redo">Redo</string>
+
     <!-- Text selection contextual mode title, displayed in the CAB. [CHAR LIMIT=20] -->
     <string name="textSelectionCABTitle">Text selection</string>
 
@@ -2556,16 +2591,27 @@
     <!-- Text to display when there are no activities found to display in the
          activity chooser. See the "Select an action" title. -->
     <string name="noApplications">No apps can perform this action.</string>
-    <!-- Title of the alert when an application has crashed. -->
-    <string name="aerr_title"></string>
     <!-- Text of the alert that is displayed when an application has crashed. -->
-    <string name="aerr_application">Unfortunately, <xliff:g id="application">%1$s</xliff:g> has stopped.</string>
-    <!-- Text of the alert that is displayed when an application has crashed. -->
-    <string name="aerr_process">Unfortunately, the process <xliff:g id="process">%1$s</xliff:g> has
-        stopped.</string>
-    <!-- Text of the alert that is displayed when an application has crashed. -->
-    <string name="aerr_process_silence">Silence crashes from <xliff:g id="process">%1$s</xliff:g>
-        until reboot.</string>
+    <string name="aerr_application"><xliff:g id="application">%1$s</xliff:g> has stopped</string>
+    <!-- Text of the alert that is displayed when a process has crashed. -->
+    <string name="aerr_process"><xliff:g id="process">%1$s</xliff:g> has
+        stopped</string>
+    <!-- Text of the alert that is displayed when an application has crashed repeatedly. -->
+    <string name="aerr_application_repeated"><xliff:g id="application">%1$s</xliff:g> is repeatedly stopping</string>
+    <!-- Text of the alert that is displayed when a process has crashed repeatedly. -->
+    <string name="aerr_process_repeated"><xliff:g id="process">%1$s</xliff:g> is
+        repeatedly stopping</string>
+    <!-- Button that restarts a crashed application -->
+    <string name="aerr_restart">Restart app</string>
+    <!-- Button that clears cache and restarts a crashed application -->
+    <string name="aerr_reset">Reset and restart app</string>
+    <!-- Button that sends feedback about a crashed application -->
+    <string name="aerr_report">Send feedback</string>
+    <!-- Button that closes a crashed application -->
+    <string name="aerr_close">Close</string>
+    <!-- Button that mutes further crashes of the crashed application-->
+    <string name="aerr_mute">Mute</string>
+
     <!-- Title of the alert when an application is not responding. -->
     <string name="anr_title"></string>
     <!-- Text of the alert that is displayed when an application is not responding. -->
@@ -2862,6 +2908,19 @@
     <!-- 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 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 with admin?</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</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>
+    <!-- Decline label of notification shown to ask for user consent for sharing the remote bugreport. -->
+    <string name="share_remote_bugreport_notification_decline">DECLINE</string>
+    <!-- Title of notification shown for remote bugreport progress. -->
+    <string name="remote_bugreport_progress_notification_title">Taking bug report\u2026</string>
+    <!-- Message of notification shown for remote bugreport progress. User can cancel the bugreport -->
+    <string name="remote_bugreport_progress_notification_message_can_cancel">Touch to cancel</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    -->
     <!-- locale string based on mcc values.  By default (0-length string) we don't replace the %s   -->
@@ -2874,10 +2933,10 @@
     <!-- 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[CHAR LIMIT=25] -->
-    <string name="show_ime">Show input method</string>
-    <!-- Title of the physical keyboard category in the input method selector [CHAR LIMIT=10] -->
-    <string name="hardware">Hardware</string>
+         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>
@@ -3069,6 +3128,9 @@
     <string name="notification_listener_binding_label">Notification 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>
 
     <!-- Do Not Translate: Alternate eri.xml -->
     <string name="alternate_eri_file">/data/eri.xml</string>
@@ -3954,25 +4016,6 @@
     <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description -->
     <string name="battery_saver_description">To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services, and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging.</string>
 
-
-    <!-- [CHAR LIMIT=100] Notification importance slider title -->
-    <string name="notification_importance_title">Importance</string>
-
-    <!-- [CHAR LIMIT=100] Notification Importance slider: blocked importance level description -->
-    <string name="notification_importance_blocked">Blocked: Never show these notifications</string>
-
-    <!-- [CHAR LIMIT=100] Notification Importance slider: low importance level description -->
-    <string name="notification_importance_low">Low: Silently show at the bottom of the notification list</string>
-
-    <!-- [CHAR LIMIT=100] Notification Importance slider: normal importance level description -->
-    <string name="notification_importance_default">Normal: Silently show these notifications</string>
-
-    <!-- [CHAR LIMIT=100] Notification Importance slider: high importance level description -->
-    <string name="notification_importance_high">High: Show at the top of the notifications list and make sound</string>
-
-    <!-- [CHAR LIMIT=100] Notification Importance slider: max importance level description -->
-    <string name="notification_importance_max">Urgent: Peek onto the screen and make sound</string>
-
     <!-- Zen mode condition - summary: time duration in minutes. [CHAR LIMIT=NONE] -->
     <plurals name="zen_mode_duration_minutes_summary">
         <item quantity="one">For one minute (until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g>)</item>
@@ -4108,4 +4151,50 @@
 
     <string name="importance_from_topic">You set the importance of these notifications.</string>
     <string name="importance_from_person">This is important because of the people involved.</string>
+
+    <!-- Message to user that app trying to create user for an account that already exists. [CHAR LIMIT=none] -->
+    <string name="user_creation_account_exists">Allow <xliff:g id="app" example="Gmail">%1$s</xliff:g> to create a new User with <xliff:g id="account" example="foobar@gmail.com">%2$s</xliff:g> ?</string>
+    <!-- Message to user that app is trying to create user for a specified account. [CHAR LIMIT=none] -->
+    <string name="user_creation_adding">Allow <xliff:g id="app" example="Gmail">%1$s</xliff:g> to create a new User with <xliff:g id="account" example="foobar">%2$s</xliff:g> (a User with this account already exists) ?</string>
+
+    <!-- Locale picker strings -->
+
+    <!-- Title for the language selection screen [CHAR LIMIT=25] -->
+    <string name="language_selection_title">Language preference</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=20] -->
+    <string name="search_language_hint">Type language name</string>
+
+    <!-- List section subheader for the language picker, containing a list of suggested languages determined by the default region [CHAR LIMIT=30] -->
+    <string name="language_picker_section_suggested">Suggested</string>
+    <!-- List section subheader for the language picker, containing a list of all languages available [CHAR LIMIT=30] -->
+    <string name="language_picker_section_all">All languages</string>
+
+    <!-- Menu item in the locale menu  [CHAR LIMIT=30] -->
+    <string name="locale_search_menu">Search</string>
+
+    <!-- Title for dialog displayed when work profile is turned off. [CHAR LIMIT=30] -->
+    <string name="work_mode_off_title">Work mode is OFF</string>
+    <!-- Message displayed in dialog when work profile is turned off. [CHAR LIMIT=NONE] -->
+    <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>
+    <!-- Notification content shown when new SMS/MMS is received while the device is locked [CHAR LIMIT=NONE] -->
+    <string name="new_sms_notification_content">Open SMS app to view</string>
+
+    <!-- Notification title shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
+    <string name="user_encrypted_title">Some functions might not be available</string>
+    <!-- Notification message shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
+    <string name="user_encrypted_message">Touch to continue</string>
+    <!-- Notification detail shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
+    <string name="user_encrypted_detail">User profile locked</string>
+
 </resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 9a4016b..f0960c7 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1199,13 +1199,6 @@
         <item name="windowExitAnimation">@anim/fast_fade_out</item>
     </style>
 
-    <!-- Style for the popup window that contains text suggestions. -->
-    <style name="Widget.TextSuggestionsPopupWindow">
-        <item name="dropDownSelector">@drawable/list_selector_background</item>
-        <item name="popupBackground">@drawable/text_edit_suggestions_window</item>
-        <item name="dropDownWidth">wrap_content</item>
-    </style>
-
     <style name="Widget.ActionBar">
         <item name="background">@drawable/action_bar_background</item>
         <item name="displayOptions">useLogo|showHome|showTitle</item>
@@ -1235,7 +1228,7 @@
         <item name="subtitleTextAppearance">@style/TextAppearance.Widget.Toolbar.Subtitle</item>
         <item name="minHeight">?attr/actionBarSize</item>
         <item name="titleMargin">4dp</item>
-        <item name="maxButtonHeight">56dp</item>
+        <item name="maxButtonHeight">@dimen/action_bar_default_height_material</item>
         <item name="buttonGravity">top</item>
         <item name="navigationButtonStyle">@style/Widget.Toolbar.Button.Navigation</item>
         <item name="collapseIcon">?attr/homeAsUpIndicator</item>
@@ -1404,6 +1397,16 @@
         <item name="pointerIconGrabbing">@drawable/pointer_grabbing_large_icon</item>
     </style>
 
+    <!-- @hide -->
+    <style name="aerr_list_item" parent="Widget.Material.Light.Button.Borderless">
+        <item name="minHeight">?attr/listPreferredItemHeightSmall</item>
+        <item name="textAppearance">?attr/textAppearanceListItemSmall</item>
+        <item name="textColor">?attr/textColorAlertDialogListItem</item>
+        <item name="gravity">center_vertical</item>
+        <item name="paddingStart">?attr/listPreferredItemPaddingStart</item>
+        <item name="paddingEnd">?attr/listPreferredItemPaddingEnd</item>
+    </style>
+
     <!-- Wifi dialog styles -->
     <!-- @hide -->
     <style name="wifi_item">
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 23ac221..93a5264 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -113,7 +113,6 @@
     <style name="Widget.DeviceDefault.Spinner.DropDown" parent="Widget.Material.Spinner.DropDown"/>
     <style name="Widget.DeviceDefault.StackView" parent="Widget.Material.StackView"/>
     <style name="Widget.DeviceDefault.TextSelectHandle" parent="Widget.Material.TextSelectHandle"/>
-    <style name="Widget.DeviceDefault.TextSuggestionsPopupWindow" parent="Widget.Material.TextSuggestionsPopupWindow"/>
     <style name="Widget.DeviceDefault.TextView.ListSeparator" parent="Widget.Material.TextView.ListSeparator"/>
     <style name="Widget.DeviceDefault.TimePicker" parent="Widget.Material.TimePicker"/>
 
@@ -199,7 +198,6 @@
     <style name="Widget.DeviceDefault.Light.Spinner.DropDown" parent="Widget.Material.Light.Spinner.DropDown"/>
     <style name="Widget.DeviceDefault.Light.TextView.ListSeparator" parent="Widget.Material.Light.TextView.ListSeparator"/>
     <style name="Widget.DeviceDefault.Light.TimePicker" parent="Widget.Material.Light.TimePicker"/>
-    <style name="Widget.DeviceDefault.Light.TextSuggestionsPopupWindow" parent="Widget.Material.Light.TextSuggestionsPopupWindow"/>
 
     <!-- Text Appearance Styles -->
     <style name="TextAppearance.DeviceDefault" parent="TextAppearance.Material"/>
diff --git a/core/res/res/values/styles_holo.xml b/core/res/res/values/styles_holo.xml
index 3cd60df..6c69141 100644
--- a/core/res/res/values/styles_holo.xml
+++ b/core/res/res/values/styles_holo.xml
@@ -401,8 +401,6 @@
 
     <style name="Widget.Holo.TextSelectHandle" parent="Widget.TextSelectHandle" />
 
-    <style name="Widget.Holo.TextSuggestionsPopupWindow" parent="Widget.TextSuggestionsPopupWindow" />
-
     <style name="Widget.Holo.AbsListView" parent="Widget.AbsListView" />
 
     <style name="Widget.Holo.AutoCompleteTextView" parent="Widget.AutoCompleteTextView">
@@ -814,8 +812,6 @@
 
     <style name="Widget.Holo.Light.TextSelectHandle" parent="Widget.TextSelectHandle" />
 
-    <style name="Widget.Holo.Light.TextSuggestionsPopupWindow" parent="Widget.TextSuggestionsPopupWindow" />
-
     <style name="Widget.Holo.Light.AbsListView" parent="Widget.AbsListView" />
 
     <style name="Widget.Holo.Light.AutoCompleteTextView" parent="Widget.AutoCompleteTextView">
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 74ebf26..7aa0c12 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -432,6 +432,8 @@
         <item name="textSize">@dimen/notification_text_size</item>
     </style>
 
+    <style name="TextAppearance.Material.Notification.Reply" />
+
     <style name="TextAppearance.Material.Notification.Title">
         <item name="textColor">@color/primary_text_default_material_light</item>
         <item name="textSize">@dimen/notification_title_text_size</item>
@@ -568,7 +570,6 @@
 
     <style name="Widget.Material.CheckedTextView" parent="Widget.CheckedTextView" />
     <style name="Widget.Material.TextSelectHandle" parent="Widget.TextSelectHandle"/>
-    <style name="Widget.Material.TextSuggestionsPopupWindow" parent="Widget.TextSuggestionsPopupWindow"/>
     <style name="Widget.Material.AbsListView" parent="Widget.AbsListView"/>
 
     <style name="Widget.Material.AutoCompleteTextView" parent="Widget.AutoCompleteTextView">
@@ -743,6 +744,11 @@
         <item name="background">@drawable/control_background_32dp_material</item>
     </style>
 
+    <!-- A seek bar with tick marks at each progress value. -->
+    <style name="Widget.Material.SeekBar.Discrete">
+        <item name="tickMark">@drawable/seekbar_tick_mark_material</item>
+    </style>
+
     <style name="Widget.Material.RatingBar" parent="Widget.RatingBar">
         <item name="progressDrawable">@drawable/ratingbar_material</item>
         <item name="indeterminateDrawable">@drawable/ratingbar_material</item>
@@ -870,7 +876,6 @@
 
     <style name="Widget.Material.ContextPopupMenu" parent="Widget.Material.ListPopupWindow">
         <item name="overlapAnchor">true</item>
-        <item name="popupEnterTransition">@null</item>
     </style>
 
     <style name="Widget.Material.ActionButton">
@@ -988,7 +993,6 @@
     </style>
 
     <style name="Widget.Material.SuggestionItem" parent="@android:style/TextAppearance.Material.Body1">
-        <item name="background">@color/white</item>
         <item name="alpha">.87</item>
         <item name="textColor">@color/black</item>
         <item name="drawablePadding">8dip</item>
@@ -1010,7 +1014,6 @@
     </style>
 
     <style name="Widget.Material.SuggestionButton" parent="@android:style/TextAppearance.Material.Button">
-        <item name="background">@color/white</item>
         <item name="alpha">.87</item>
         <item name="textColor">#009688</item>
         <item name="drawablePadding">8dip</item>
@@ -1054,7 +1057,6 @@
     <style name="Widget.Material.Light.TextView.SpinnerItem" parent="Widget.Material.TextView.SpinnerItem"/>
     <style name="Widget.Material.Light.CheckedTextView" parent="Widget.Material.CheckedTextView"/>
     <style name="Widget.Material.Light.TextSelectHandle" parent="Widget.Material.TextSelectHandle"/>
-    <style name="Widget.Material.Light.TextSuggestionsPopupWindow" parent="Widget.Material.TextSuggestionsPopupWindow"/>
     <style name="Widget.Material.Light.AbsListView" parent="Widget.Material.AbsListView"/>
     <style name="Widget.Material.Light.AutoCompleteTextView" parent="Widget.Material.AutoCompleteTextView" />
     <style name="Widget.Material.Light.CompoundButton" parent="Widget.Material.CompoundButton"/>
diff --git a/core/res/res/values/styles_micro.xml b/core/res/res/values/styles_micro.xml
index 05835e7..7dde5f8 100644
--- a/core/res/res/values/styles_micro.xml
+++ b/core/res/res/values/styles_micro.xml
@@ -26,6 +26,10 @@
         <item name="taskOpenExitAnimation">@null</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="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>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 832984e..aa44d7c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -86,7 +86,6 @@
   <java-symbol type="id" name="left_icon" />
   <java-symbol type="id" name="leftSpacer" />
   <java-symbol type="id" name="line1" />
-  <java-symbol type="id" name="line3" />
   <java-symbol type="id" name="list_footer" />
   <java-symbol type="id" name="list_item" />
   <java-symbol type="id" name="listContainer" />
@@ -209,8 +208,7 @@
   <java-symbol type="id" name="pin_confirm_text" />
   <java-symbol type="id" name="pin_error_message" />
   <java-symbol type="id" name="timePickerLayout" />
-  <java-symbol type="id" name="profile_badge_large_template" />
-  <java-symbol type="id" name="profile_badge_line3" />
+  <java-symbol type="id" name="profile_badge" />
   <java-symbol type="id" name="transitionPosition" />
   <java-symbol type="id" name="selection_start_handle" />
   <java-symbol type="id" name="selection_end_handle" />
@@ -300,16 +298,26 @@
   <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="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_guestUserEphemeral" />
+  <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" />
   <java-symbol type="integer" name="config_wifi_framework_current_association_hysteresis_high" />
   <java-symbol type="integer" name="config_wifi_framework_current_association_hysteresis_low" />
   <java-symbol type="integer" name="config_wifi_framework_5GHz_preference_penalty_threshold" />
-  <java-symbol type="integer" name="config_wifi_framework_5GHz_preference_penalty_factor" />
+  <java-symbol type="integer" name="config_wifi_framework_RSSI_SCORE_OFFSET" />
+  <java-symbol type="integer" name="config_wifi_framework_RSSI_SCORE_SLOPE" />
+  <java-symbol type="integer" name="config_wifi_framework_SAME_BSSID_AWARD" />
+  <java-symbol type="integer" name="config_wifi_framework_LAST_SELECTION_AWARD" />
+  <java-symbol type="integer" name="config_wifi_framework_PASSPOINT_SECURITY_AWARD" />
+  <java-symbol type="integer" name="config_wifi_framework_SECURITY_AWARD" />
   <java-symbol type="integer" name="config_wifi_disconnected_short_scan_interval" />
   <java-symbol type="integer" name="config_wifi_disconnected_long_scan_interval" />
   <java-symbol type="integer" name="config_wifi_associated_short_scan_interval" />
@@ -455,7 +463,10 @@
   <java-symbol type="string" name="notification_title" />
   <java-symbol type="string" name="permission_request_notification_with_subtitle" />
   <java-symbol type="string" name="prepend_shortcut_label" />
+  <java-symbol type="string" name="paste_as_plain_text" />
   <java-symbol type="string" name="replace" />
+  <java-symbol type="string" name="undo" />
+  <java-symbol type="string" name="redo" />
   <java-symbol type="string" name="textSelectionCABTitle" />
   <java-symbol type="string" name="BaMmi" />
   <java-symbol type="string" name="CLIRDefaultOffNextCallOff" />
@@ -557,6 +568,8 @@
   <java-symbol type="string" name="capability_title_canRetrieveWindowContent" />
   <java-symbol type="string" name="capability_desc_canControlMagnification" />
   <java-symbol type="string" name="capability_title_canControlMagnification" />
+  <java-symbol type="string" name="capability_desc_canPerformGestures" />
+  <java-symbol type="string" name="capability_title_canPerformGestures" />
   <java-symbol type="string" name="cfTemplateForwarded" />
   <java-symbol type="string" name="cfTemplateForwardedTime" />
   <java-symbol type="string" name="cfTemplateNotForwarded" />
@@ -571,6 +584,7 @@
   <java-symbol type="string" name="config_ntpServer" />
   <java-symbol type="string" name="config_useragentprofile_url" />
   <java-symbol type="string" name="config_wifi_p2p_device_type" />
+  <java-symbol type="string" name="config_appsNotReportingCrashes" />
   <java-symbol type="string" name="contentServiceSync" />
   <java-symbol type="string" name="contentServiceSyncNotificationTitle" />
   <java-symbol type="string" name="contentServiceTooManyDeletesNotificationDesc" />
@@ -923,6 +937,8 @@
   <java-symbol type="string" name="time_picker_increment_minute_button" />
   <java-symbol type="string" name="time_picker_increment_set_pm_button" />
   <java-symbol type="string" name="upload_file" />
+  <java-symbol type="string" name="user_creation_account_exists" />
+  <java-symbol type="string" name="user_creation_adding" />
   <java-symbol type="string" name="user_switched" />
   <java-symbol type="string" name="user_switching_message" />
   <java-symbol type="string" name="user_logging_out_message" />
@@ -1100,6 +1116,7 @@
   <java-symbol type="string" name="config_ethernet_tcp_buffers" />
   <java-symbol type="string" name="config_wifi_tcp_buffers" />
 
+  <java-symbol type="plurals" name="bugreport_countdown" />
   <java-symbol type="plurals" name="duration_hours" />
   <java-symbol type="plurals" name="duration_minutes" />
   <java-symbol type="plurals" name="duration_seconds" />
@@ -1120,6 +1137,7 @@
   <java-symbol type="array" name="sim_colors" />
   <java-symbol type="array" name="special_locale_codes" />
   <java-symbol type="array" name="special_locale_names" />
+  <java-symbol type="array" name="supported_locales" />
   <java-symbol type="array" name="config_cdma_dun_supported_types" />
   <java-symbol type="array" name="config_disabledUntilUsedPreinstalledImes" />
   <java-symbol type="array" name="config_disabledUntilUsedPreinstalledCarrierApps" />
@@ -1245,6 +1263,7 @@
   <java-symbol type="drawable" name="ic_corp_badge" />
   <java-symbol type="drawable" name="ic_corp_badge_off" />
   <java-symbol type="drawable" name="ic_corp_icon_badge" />
+  <java-symbol type="drawable" name="ic_corp_badge_no_background" />
   <java-symbol type="drawable" name="ic_corp_icon" />
   <java-symbol type="drawable" name="ic_corp_statusbar_icon" />
   <java-symbol type="drawable" name="emulator_circular_window_overlay" />
@@ -1486,9 +1505,14 @@
   <java-symbol type="bool" name="target_honeycomb_needs_options_menu" />
   <java-symbol type="dimen" name="docked_stack_divider_thickness" />
   <java-symbol type="dimen" name="docked_stack_divider_insets" />
+  <java-symbol type="integer" name="config_dockedStackDividerSnapMode" />
+  <java-symbol type="fraction" name="docked_stack_divider_fixed_ratio" />
   <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" />
+  <java-symbol type="dimen" name="navigation_bar_height_car_mode" />
+  <java-symbol type="dimen" name="navigation_bar_height_landscape_car_mode" />
+  <java-symbol type="dimen" name="navigation_bar_width_car_mode" />
   <java-symbol type="dimen" name="status_bar_height" />
   <java-symbol type="drawable" name="ic_jog_dial_sound_off" />
   <java-symbol type="drawable" name="ic_jog_dial_sound_on" />
@@ -1559,10 +1583,13 @@
   <java-symbol type="string" name="android_preparing_apk" />
   <java-symbol type="string" name="android_start_title" />
   <java-symbol type="string" name="android_upgrading_title" />
-  <java-symbol type="string" name="bugreport_title" />
   <java-symbol type="string" name="bugreport_message" />
+  <java-symbol type="string" name="bugreport_option_full_summary" />
+  <java-symbol type="string" name="bugreport_option_full_title" />
+  <java-symbol type="string" name="bugreport_option_interactive_summary" />
+  <java-symbol type="string" name="bugreport_option_interactive_title" />
   <java-symbol type="string" name="bugreport_status" />
-  <java-symbol type="string" name="config_orientationSensorType" />
+  <java-symbol type="string" name="bugreport_title" />
   <java-symbol type="string" name="faceunlock_multiple_failures" />
   <java-symbol type="string" name="global_action_power_off" />
   <java-symbol type="string" name="global_actions_airplane_mode_off_status" />
@@ -1734,16 +1761,22 @@
   <java-symbol type="layout" name="launch_warning" />
   <java-symbol type="layout" name="safe_mode" />
   <java-symbol type="layout" name="simple_list_item_2_single_choice" />
-  <java-symbol type="layout" name="app_error_dialog_dont_show_again" />
+  <java-symbol type="layout" name="app_error_dialog" />
   <java-symbol type="plurals" name="wifi_available" />
   <java-symbol type="plurals" name="wifi_available_detailed" />
   <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="share_remote_bugreport_notification_title" />
+  <java-symbol type="string" name="share_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="remote_bugreport_progress_notification_title" />
+  <java-symbol type="string" name="remote_bugreport_progress_notification_message_can_cancel" />
   <java-symbol type="string" name="aerr_application" />
   <java-symbol type="string" name="aerr_process" />
-  <java-symbol type="string" name="aerr_process_silence" />
-  <java-symbol type="string" name="aerr_title" />
+  <java-symbol type="string" name="aerr_application_repeated" />
+  <java-symbol type="string" name="aerr_process_repeated" />
   <java-symbol type="string" name="android_upgrading_fstrim" />
   <java-symbol type="string" name="android_upgrading_apk" />
   <java-symbol type="string" name="android_upgrading_complete" />
@@ -1806,6 +1839,7 @@
   <java-symbol type="string" name="low_internal_storage_view_title" />
   <java-symbol type="string" name="notification_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="report" />
   <java-symbol type="string" name="select_input_method" />
   <java-symbol type="string" name="select_keyboard_layout_notification_title" />
@@ -2086,12 +2120,6 @@
   <java-symbol type="array" name="config_system_condition_providers" />
   <java-symbol type="string" name="muted_by" />
   <java-symbol type="string" name="zen_mode_alarm" />
-  <java-symbol type="string" name="notification_importance_blocked" />
-  <java-symbol type="string" name="notification_importance_low" />
-  <java-symbol type="string" name="notification_importance_default" />
-  <java-symbol type="string" name="notification_importance_high" />
-  <java-symbol type="string" name="notification_importance_max" />
-  <java-symbol type="string" name="notification_importance_title" />
 
   <java-symbol type="string" name="select_day" />
   <java-symbol type="string" name="select_year" />
@@ -2239,6 +2267,9 @@
 
   <java-symbol type="integer" name="config_defaultNightMode" />
 
+  <java-symbol type="integer" name="config_jobSchedulerInactivityIdleThreshold" />
+  <java-symbol type="integer" name="config_jobSchedulerIdleWindowSlop" />
+
   <java-symbol type="style" name="Animation.ImmersiveModeConfirmation" />
 
   <java-symbol type="integer" name="config_screen_magnification_multi_tap_adjustment" />
@@ -2361,7 +2392,14 @@
   <java-symbol type="id" name="addToDictionaryButton" />
   <java-symbol type="id" name="deleteButton" />
 
+  <java-symbol type="id" name="notification_material_reply_container" />
+  <java-symbol type="id" name="notification_material_reply_text_1" />
+  <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" />
@@ -2377,7 +2415,7 @@
   <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_big_picture_content_min_height_with_picture" />
+  <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" />
@@ -2389,4 +2427,87 @@
   <java-symbol type="layout" name="work_widget_mask_view" />
   <java-symbol type="id" name="work_widget_app_icon" />
   <java-symbol type="drawable" name="work_widget_mask_view_background" />
+
+  <java-symbol type="id" name="aerr_report" />
+  <java-symbol type="id" name="aerr_reset" />
+  <java-symbol type="id" name="aerr_restart" />
+  <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_managed_profile" />
+  <java-symbol type="string" name="status_bar_ime" />
+  <java-symbol type="string" name="status_bar_sync_failing" />
+  <java-symbol type="string" name="status_bar_sync_active" />
+  <java-symbol type="string" name="status_bar_cast" />
+  <java-symbol type="string" name="status_bar_hotspot" />
+  <java-symbol type="string" name="status_bar_location" />
+  <java-symbol type="string" name="status_bar_bluetooth" />
+  <java-symbol type="string" name="status_bar_nfc" />
+  <java-symbol type="string" name="status_bar_tty" />
+  <java-symbol type="string" name="status_bar_speakerphone" />
+  <java-symbol type="string" name="status_bar_zen" />
+  <java-symbol type="string" name="status_bar_mute" />
+  <java-symbol type="string" name="status_bar_volume" />
+  <java-symbol type="string" name="status_bar_wifi" />
+  <java-symbol type="string" name="status_bar_cdma_eri" />
+  <java-symbol type="string" name="status_bar_data_connection" />
+  <java-symbol type="string" name="status_bar_phone_evdo_signal" />
+  <java-symbol type="string" name="status_bar_phone_signal" />
+  <java-symbol type="string" name="status_bar_battery" />
+  <java-symbol type="string" name="status_bar_alarm_clock" />
+  <java-symbol type="string" name="status_bar_secure" />
+  <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" />
+  <java-symbol type="menu" name="language_selection_list" />
+  <java-symbol type="string" name="country_selection_title" />
+  <java-symbol type="string" name="language_picker_section_all" />
+  <java-symbol type="string" name="language_picker_section_suggested" />
+  <java-symbol type="string" name="language_selection_title" />
+  <java-symbol type="string" name="search_language_hint" />
+
+  <java-symbol type="layout" name="unlaunchable_app_activity" />
+  <java-symbol type="id" name="unlaunchable_app_title" />
+  <java-symbol type="id" name="unlaunchable_app_message" />
+  <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" />
+  <java-symbol type="string" name="new_sms_notification_content" />
+
+  <java-symbol type="bool" name="config_strongAuthRequiredOnBoot" />
+
+  <!-- Encryption notification while accounts are locked by credential encryption -->
+  <java-symbol type="string" name="user_encrypted_title" />
+  <java-symbol type="string" name="user_encrypted_message" />
+  <java-symbol type="string" name="user_encrypted_detail" />
+
 </resources>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index def8659..dd8baa7 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -98,7 +98,6 @@
 
         <!-- Text selection handle attributes -->
         <item name="textSelectHandleWindowStyle">@style/Widget.DeviceDefault.TextSelectHandle</item>
-        <item name="textSuggestionsWindowStyle">@style/Widget.DeviceDefault.TextSuggestionsPopupWindow</item>
 
         <!-- Widget styles -->
         <item name="absListViewStyle">@style/Widget.DeviceDefault.AbsListView</item>
@@ -350,7 +349,6 @@
 
         <!-- Text selection handle attributes -->
         <item name="textSelectHandleWindowStyle">@style/Widget.DeviceDefault.TextSelectHandle</item>
-        <item name="textSuggestionsWindowStyle">@style/Widget.DeviceDefault.Light.TextSuggestionsPopupWindow</item>
 
         <!-- Widget styles -->
         <item name="absListViewStyle">@style/Widget.DeviceDefault.Light.AbsListView</item>
diff --git a/core/res/res/values/themes_holo.xml b/core/res/res/values/themes_holo.xml
index 4cbaacb..34c89fc 100644
--- a/core/res/res/values/themes_holo.xml
+++ b/core/res/res/values/themes_holo.xml
@@ -136,7 +136,6 @@
         <item name="textEditSuggestionItemLayout">@layout/text_edit_suggestion_item</item>
         <item name="textEditSuggestionContainerLayout">@layout/text_edit_suggestion_container</item>
         <item name="textEditSuggestionHighlightStyle">@style/TextAppearance.Holo.SuggestionHighlight</item>
-        <item name="textSuggestionsWindowStyle">@style/Widget.Holo.TextSuggestionsPopupWindow</item>
 
         <!-- Button styles -->
         <item name="buttonStyle">@style/Widget.Holo.Button</item>
@@ -590,7 +589,6 @@
         <item name="textSelectHandleRight">@drawable/text_select_handle_right</item>
         <item name="textSelectHandle">@drawable/text_select_handle_middle</item>
         <item name="textSelectHandleWindowStyle">@style/Widget.Holo.TextSelectHandle</item>
-        <item name="textSuggestionsWindowStyle">@style/Widget.Holo.Light.TextSuggestionsPopupWindow</item>
         <item name="textCursorDrawable">@drawable/text_cursor_holo_light</item>
 
         <!-- Widget styles -->
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index b011094..47892a3 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -223,7 +223,6 @@
         <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="textSuggestionsWindowStyle">@style/Widget.Material.TextSuggestionsPopupWindow</item>
         <item name="textCursorDrawable">@drawable/text_cursor_material</item>
 
         <!-- Widget styles -->
@@ -588,7 +587,6 @@
         <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="textSuggestionsWindowStyle">@style/Widget.Material.Light.TextSuggestionsPopupWindow</item>
 
         <!-- Widget styles -->
         <item name="absListViewStyle">@style/Widget.Material.Light.AbsListView</item>
diff --git a/core/res/res/xml/config_webview_packages.xml b/core/res/res/xml/config_webview_packages.xml
index 6f9c58d..f062b59 100644
--- a/core/res/res/xml/config_webview_packages.xml
+++ b/core/res/res/xml/config_webview_packages.xml
@@ -16,5 +16,6 @@
 
 <webviewproviders>
     <!-- The default WebView implementation -->
-    <webviewprovider description="Android WebView" packageName="com.android.webview" />
+    <webviewprovider description="Android WebView" packageName="com.android.webview" availableByDefault="true">
+    </webviewprovider>
 </webviewproviders>
diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml
index ddd0ca2..76b5fe1 100644
--- a/core/res/res/xml/power_profile.xml
+++ b/core/res/res/xml/power_profile.xml
@@ -39,15 +39,27 @@
   <item name="dsp.video">0.1</item> <!-- ~50mA -->
   <item name="camera.flashlight">0.1</item> <!-- Avg. power for camera flash, ~160mA -->
   <item name="camera.avg">0.1</item> <!-- Avg. power use of camera in standard usecases, ~550mA -->
+  <item name="gps.on">0.1</item> <!-- ~50mA -->
+
+  <!-- Radio related values. For modems without energy reporting support in firmware, use
+       radio.active, radio.scanning, and radio.on. -->
   <item name="radio.active">0.1</item> <!-- ~200mA -->
   <item name="radio.scanning">0.1</item> <!-- cellular radio scanning for signal, ~10mA -->
-  <item name="gps.on">0.1</item> <!-- ~50mA -->
   <!-- Current consumed by the radio at different signal strengths, when paging -->
   <array name="radio.on"> <!-- Strength 0 to BINS-1 -->
       <value>0.2</value> <!-- ~2mA -->
       <value>0.1</value> <!-- ~1mA -->
   </array>
 
+
+  <!-- Radio related values. For modems WITH energy reporting support in firmware, use
+       modem.controller.idle, modem.controller.tx, modem.controller.rx, modem.controller.voltage.
+       -->
+  <item name="modem.controller.idle">0</item>
+  <item name="modem.controller.rx">0</item>
+  <item name="modem.controller.tx">0</item>
+  <item name="modem.controller.voltage">0</item>
+
   <!-- A list of heterogeneous CPU clusters, where the value for each cluster represents the
        number of CPU cores for that cluster.
 
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 5f1f927..cf7978c 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -33,6 +33,9 @@
          and http://mobilcent.com/info-worldwide.asp and extracted from:
          http://smscoin.net/software/engine/WordPress/Paid+SMS-registration/ -->
 
+    <!-- Arab Emirates -->
+    <shortcode country="ae" free="3214|1017" />
+
     <!-- Albania: 5 digits, known short codes listed -->
     <shortcode country="al" pattern="\\d{5}" premium="15191|55[56]00" />
 
@@ -43,7 +46,7 @@
     <shortcode country="at" pattern="11\\d{4}" premium="09.*" free="116\\d{3}" />
 
     <!-- Australia: 6 or 8 digits starting with "19" -->
-    <shortcode country="au" pattern="19(?:\\d{4}|\\d{6})" premium="19998882" />
+    <shortcode country="au" pattern="19(?:\\d{4}|\\d{6})" premium="19998882|19944444" />
 
     <!-- Azerbaijan: 4-5 digits, known premium codes listed -->
     <shortcode country="az" pattern="\\d{4,5}" premium="330[12]|87744|901[234]|93(?:94|101)|9426|9525" />
@@ -58,10 +61,10 @@
     <shortcode country="by" pattern="\\d{4}" premium="3336|4161|444[4689]|501[34]|7781" />
 
     <!-- Canada: 5-6 digits -->
-    <shortcode country="ca" pattern="\\d{5,6}" premium="60999|88188" />
+    <shortcode country="ca" pattern="\\d{5,6}" premium="60999|88188|43030" />
 
     <!-- Switzerland: 3-5 digits: http://www.swisscom.ch/fxres/kmu/thirdpartybusiness_code_of_conduct_en.pdf -->
-    <shortcode country="ch" pattern="[2-9]\\d{2,4}" premium="543|83111" />
+    <shortcode country="ch" pattern="[2-9]\\d{2,4}" premium="543|83111|30118" />
 
     <!-- China: premium shortcodes start with "1066", free shortcodes start with "1065":
          http://clients.txtnation.com/entries/197192-china-premium-sms-short-code-requirements -->
@@ -75,10 +78,10 @@
     <shortcode country="cz" premium="9\\d{6,7}" free="116\\d{3}" />
 
     <!-- Germany: 4-5 digits plus 1232xxx (premium codes from http://www.vodafone.de/infofaxe/537.pdf and http://premiumdienste.eplus.de/pdf/kodex.pdf), plus EU. To keep the premium regex from being too large, it only includes payment processors that have been used by SMS malware, with the regular pattern matching the other premium short codes. -->
-    <shortcode country="de" pattern="\\d{4,5}|1232\\d{3}" premium="11(?:111|833)|1232(?:013|021|060|075|286|358)|118(?:44|80|86)|20[25]00|220(?:21|22|88|99)|221(?:14|21)|223(?:44|53|77)|224[13]0|225(?:20|59|90)|226(?:06|10|20|26|30|40|56|70)|227(?:07|33|39|66|76|78|79|88|99)|228(?:08|11|66|77)|23300|30030|3[12347]000|330(?:33|55|66)|33(?:233|331|366|533)|34(?:34|567)|37000|40(?:040|123|444|[3568]00)|41(?:010|414)|44(?:000|044|344|44[24]|544)|50005|50100|50123|50555|51000|52(?:255|783)|54(?:100|2542)|55(?:077|[24]00|222|333|55|[12369]55)|56(?:789|886)|60800|6[13]000|66(?:[12348]66|566|766|777|88|999)|68888|70(?:07|123|777)|76766|77(?:007|070|222|444|[567]77)|80(?:008|123|888)|82(?:002|[378]00|323|444|472|474|488|727)|83(?:005|[169]00|333|830)|84(?:141|300|32[34]|343|488|499|777|888)|85888|86(?:188|566|640|644|650|677|868|888)|870[24]9|871(?:23|[49]9)|872(?:1[0-8]|49|99)|87499|875(?:49|55|99)|876(?:0[1367]|1[1245678]|54|99)|877(?:00|99)|878(?:15|25|3[567]|8[12])|87999|880(?:08|44|55|77|99)|88688|888(?:03|10|8|89)|8899|90(?:009|999)|99999" free="116\\d{3}|81214|81215" />
+    <shortcode country="de" pattern="\\d{4,5}|1232\\d{3}" premium="11(?:111|833)|1232(?:013|021|060|075|286|358)|118(?:44|80|86)|20[25]00|220(?:21|22|88|99)|221(?:14|21)|223(?:44|53|77)|224[13]0|225(?:20|59|90)|226(?:06|10|20|26|30|40|56|70)|227(?:07|33|39|66|76|78|79|88|99)|228(?:08|11|66|77)|23300|30030|3[12347]000|330(?:33|55|66)|33(?:233|331|366|533)|34(?:34|567)|37000|40(?:040|123|444|[3568]00)|41(?:010|414)|44(?:000|044|344|44[24]|544)|50005|50100|50123|50555|51000|52(?:255|783)|54(?:100|2542)|55(?:077|[24]00|222|333|55|[12369]55)|56(?:789|886)|60800|6[13]000|66(?:[12348]66|566|766|777|88|999)|68888|70(?:07|123|777)|76766|77(?:007|070|222|444|[567]77)|80(?:008|123|888)|82(?:002|[378]00|323|444|472|474|488|727)|83(?:005|[169]00|333|830)|84(?:141|300|32[34]|343|488|499|777|888)|85888|86(?:188|566|640|644|650|677|868|888)|870[24]9|871(?:23|[49]9)|872(?:1[0-8]|49|99)|87499|875(?:49|55|99)|876(?:0[1367]|1[1245678]|54|99)|877(?:00|99)|878(?:15|25|3[567]|8[12])|87999|880(?:08|44|55|77|99)|88688|888(?:03|10|8|89)|8899|90(?:009|999)|99999" free="116\\d{3}|81214|81215|47529|70296" />
 
     <!-- Denmark: see http://iprs.webspacecommerce.com/Denmark-Premium-Rate-Numbers -->
-    <shortcode country="dk" pattern="\\d{4,5}" premium="1\\d{3}" free="116\\d{3}" />
+    <shortcode country="dk" pattern="\\d{4,5}" premium="1\\d{3}" free="116\\d{3}|4665" />
 
     <!-- Estonia: short codes 3-5 digits starting with 1, plus premium 7 digit numbers starting with 90, plus EU.
          http://www.tja.ee/public/documents/Elektrooniline_side/Oigusaktid/ENG/Estonian_Numbering_Plan_annex_06_09_2010.mht -->
@@ -89,7 +92,7 @@
     <shortcode country="es" premium="[23][57]\\d{3}|280\\d{2}|[79]9[57]\\d{3}" free="116\\d{3}" />
 
     <!-- Finland: 5-6 digits, premium 0600, 0700: http://en.wikipedia.org/wiki/Telephone_numbers_in_Finland -->
-    <shortcode country="fi" pattern="\\d{5,6}" premium="0600.*|0700.*|171(?:59|63)" free="116\\d{3}" />
+    <shortcode country="fi" pattern="\\d{5,6}" premium="0600.*|0700.*|171(?:59|63)" free="116\\d{3}|14789" />
 
     <!-- France: 5 digits, free: 3xxxx, premium [4-8]xxxx, plus EU:
          http://clients.txtnation.com/entries/161972-france-premium-sms-short-code-requirements,
@@ -99,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" />
+    <shortcode country="gb" pattern="\\d{4,6}" premium="[5-8]\\d{4}" free="116\\d{3}|887|83669|34664|40406" />
 
     <!-- Georgia: 4 digits, known premium codes listed -->
     <shortcode country="ge" pattern="\\d{4}" premium="801[234]|888[239]" />
@@ -111,6 +114,9 @@
          http://clients.txtnation.com/entries/209633-hungary-premium-sms-short-code-regulations -->
     <shortcode country="hu" pattern="[01](?:\\d{3}|\\d{9})" premium="0691227910|1784" free="116\\d{3}" />
 
+    <!-- Indonesia -->
+    <shortcode country="id" free="99477|6006|46645" />
+
     <!-- Ireland: 5 digits, 5xxxx (50xxx=free, 5[12]xxx=standard), plus EU:
          http://www.comreg.ie/_fileupload/publications/ComReg1117.pdf -->
     <shortcode country="ie" pattern="\\d{5}" premium="5[3-9]\\d{3}" free="50\\d{3}|116\\d{3}" standard="5[12]\\d{3}" />
@@ -120,14 +126,23 @@
 
     <!-- Italy: 5 digits (premium=4xxxx), plus EU:
          http://clients.txtnation.com/attachments/token/di5kfblvubttvlw/?name=Italy_CASP_EN.pdf -->
-    <shortcode country="it" pattern="\\d{5}" premium="4\\d{4}" free="116\\d{3}" />
+    <shortcode country="it" pattern="\\d{5}" premium="4\\d{4}" free="116\\d{3}|4112503" />
+
+    <!-- Japan: 8083 used by SOFTBANK_DCB_2 -->
+    <shortcode country="jp" free="8083" />
 
     <!-- Kyrgyzstan: 4 digits, known premium codes listed -->
     <shortcode country="kg" pattern="\\d{4}" premium="415[2367]|444[69]" />
 
+    <!-- Korea: http://www.smsideatechnosolutions.com/chhattisgarh/korea/sms-short-code.html -->
+    <shortcode country="kr" pattern="\\d{4,7}" free="\\*9712|\\*9090|##900" />
+
     <!-- Kazakhstan: 4 digits, known premium codes listed: http://smscoin.net/info/pricing-kazakhstan/ -->
     <shortcode country="kz" pattern="\\d{4}" premium="335[02]|4161|444[469]|77[2359]0|8444|919[3-5]|968[2-5]" />
 
+    <!-- Kuwait -->
+    <shortcode country="kw" free="1378|50420|94006" />
+
     <!-- Lithuania: 3-5 digits, known premium codes listed, plus EU -->
     <shortcode country="lt" pattern="\\d{3,5}" premium="13[89]1|1394|16[34]5" free="116\\d{3}" />
 
@@ -139,39 +154,45 @@
     <shortcode country="lv" pattern="\\d{4}" premium="18(?:19|63|7[1-4])" free="116\\d{3}" />
 
     <!-- Mexico: 4-5 digits (not confirmed), known premium codes listed -->
-    <shortcode country="mx" pattern="\\d{4,5}" premium="53035|7766" />
+    <shortcode country="mx" pattern="\\d{4,5}" premium="53035|7766" free="46645" />
 
     <!-- Malaysia: 5 digits: http://www.skmm.gov.my/attachment/Consumer_Regulation/Mobile_Content_Services_FAQs.pdf -->
-    <shortcode country="my" pattern="\\d{5}" premium="32298|33776" />
+    <shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099" />
 
     <!-- The Netherlands, 4 digits, known premium codes listed, plus EU -->
-    <shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}" />
+    <shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223" />
 
     <!-- Norway: 4-5 digits (not confirmed), known premium codes listed -->
     <shortcode country="no" pattern="\\d{4,5}" premium="2201|222[67]" />
 
     <!-- New Zealand: 3-4 digits, known premium codes listed -->
-    <shortcode country="nz" pattern="\\d{3,4}" premium="3903|8995" />
+    <shortcode country="nz" pattern="\\d{3,4}" premium="3903|8995|4679" />
+
+    <!-- Philippines -->
+    <shortcode country="ph" free="2147|5495|5496" />
 
     <!-- Poland: 4-5 digits (not confirmed), known premium codes listed, plus EU -->
-    <shortcode country="pl" pattern="\\d{4,5}" premium="74240|79(?:10|866)|92525" free="116\\d{3}" />
+    <shortcode country="pl" pattern="\\d{4,5}" premium="74240|79(?:10|866)|92525" free="116\\d{3}|8012|80921" />
 
     <!-- Portugal: 5 digits, plus EU:
          http://clients.txtnation.com/entries/158326-portugal-premium-sms-short-code-regulations -->
     <shortcode country="pt" premium="6[1289]\\d{3}" free="116\\d{3}" />
 
     <!-- Romania: 4 digits, plus EU: http://www.simplus.ro/en/resources/glossary-of-terms/ -->
-    <shortcode country="ro" pattern="\\d{4}" premium="12(?:63|66|88)|13(?:14|80)" free="116\\d{3}" />
+    <shortcode country="ro" pattern="\\d{4}" premium="12(?:63|66|88)|13(?:14|80)" free="116\\d{3}|3654" />
 
     <!-- Russia: 4 digits, known premium codes listed: http://smscoin.net/info/pricing-russia/ -->
-    <shortcode country="ru" pattern="\\d{4}" premium="1(?:1[56]1|899)|2(?:09[57]|322|47[46]|880|990)|3[589]33|4161|44(?:4[3-9]|81)|77(?:33|81)" />
+    <shortcode country="ru" pattern="\\d{4}" premium="1(?:1[56]1|899)|2(?:09[57]|322|47[46]|880|990)|3[589]33|4161|44(?:4[3-9]|81)|77(?:33|81)|8424" />
+
+    <!-- Saudi Arabia -->
+    <shortcode country="sa" free="8145" />
 
     <!-- Sweden: 5 digits (72xxx), plus EU: http://www.viatel.se/en/premium-sms/ -->
     <shortcode country="se" premium="72\\d{3}" free="116\\d{3}" />
 
     <!-- Singapore: 5 digits: http://clients.txtnation.com/entries/306442-singapore-premium-sms-short-code-requirements
          Free government directory info at 74688: http://app.sgdi.gov.sg/sms_help.asp -->
-    <shortcode country="sg" pattern="7\\d{4}" premium="73800" standard="74688" />
+    <shortcode country="sg" pattern="7\\d{4}" premium="73800" standard="74688|70134" />
 
     <!-- Slovenia: 4 digits (premium=3xxx, 6xxx, 8xxx), plus EU: http://www.cmtelecom.com/premium-sms/slovenia -->
     <shortcode country="si" pattern="\\d{4}" premium="[368]\\d{3}" free="116\\d{3}" />
@@ -179,14 +200,23 @@
     <!-- Slovakia: 4 digits (premium), plus EU: http://www.cmtelecom.com/premium-sms/slovakia -->
     <shortcode country="sk" premium="\\d{4}" free="116\\d{3}" />
 
+    <!-- Thailand: 4186001 used by AIS_TH_DCB -->
+    <shortcode country="th" free="4186001" />
+
     <!-- Tajikistan: 4 digits, known premium codes listed -->
     <shortcode country="tj" pattern="\\d{4}" premium="11[3-7]1|4161|4333|444[689]" />
 
+    <!-- Turkey -->
+    <shortcode country="tr" free="7529|5528" />
+
     <!-- Ukraine: 4 digits, known premium codes listed -->
     <shortcode country="ua" pattern="\\d{4}" premium="444[3-9]|70[579]4|7540" />
 
     <!-- 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(?:578|711|811)|45814|46(?:157|173|327|654)|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(?: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" />
+
+    <!-- Vietnam -->
+    <shortcode country="vn" free="5001" />
 
 </shortcodes>
diff --git a/core/tests/ConnectivityManagerTest/AndroidManifest.xml b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
index 6bd8f6e..a391e1f 100644
--- a/core/tests/ConnectivityManagerTest/AndroidManifest.xml
+++ b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
@@ -75,6 +75,7 @@
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
     <!-- This permission is added for API call setAirplaneMode() in ConnectivityManager -->
     <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+    <uses-permission android:name="android.permission.TETHER_PRIVILEGED" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
diff --git a/core/tests/benchmarks/src/android/text/SpannableStringBuilderBenchmark.java b/core/tests/benchmarks/src/android/text/SpannableStringBuilderBenchmark.java
new file mode 100644
index 0000000..23f8810
--- /dev/null
+++ b/core/tests/benchmarks/src/android/text/SpannableStringBuilderBenchmark.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text;
+
+import com.google.caliper.AfterExperiment;
+import com.google.caliper.BeforeExperiment;
+import com.google.caliper.Benchmark;
+import com.google.caliper.Param;
+
+public class SpannableStringBuilderBenchmark {
+
+    @Param({"android.text.style.ImageSpan",
+            "android.text.style.ParagraphStyle",
+            "android.text.style.CharacterStyle",
+            "java.lang.Object"})
+    private String paramType;
+
+    @Param({"1", "4", "16"})
+    private String paramStringMult;
+
+    private Class clazz;
+    private SpannableStringBuilder builder;
+
+    @BeforeExperiment
+    protected void setUp() throws Exception {
+        clazz = Class.forName(paramType);
+        int strSize = Integer.valueOf(paramStringMult);
+        StringBuilder strBuilder = new StringBuilder();
+        for (int i = 0; i < strSize; i++) {
+            strBuilder.append(TEST_STRING);
+        }
+        builder = new SpannableStringBuilder(Html.fromHtml(strBuilder.toString()));
+    }
+
+    @AfterExperiment
+    protected void tearDown() {
+        builder.clear();
+        builder = null;
+    }
+
+    @Benchmark
+    public void timeGetSpans(int reps) throws Exception {
+        for (int i = 0; i < reps; i++) {
+            builder.getSpans(0, builder.length(), clazz);
+        }
+    }
+
+    //contains 0 ImageSpans, 2 ParagraphSpans, 53 CharacterStyleSpans
+    public static String TEST_STRING =
+            "<p><span><a href=\"http://android.com\">some link</a></span></p>\n" +
+            "<h1 style=\"margin: 0.0px 0.0px 10.0px 0.0px; line-height: 64.0px; font: 62.0px " +
+                    "'Helvetica Neue Light'; color: #000000; \"><span>some title</span></h1>\n" +
+            "<p><span>by <a href=\"http://android.com\"><span>some name</span></a>\n" +
+            "  <a href=\"https://android.com\"><span>some text</span></a></span></p>\n" +
+            "<p><span>some date</span></p>\n" +
+            "<table cellspacing=\"0\" cellpadding=\"0\">\n" +
+            "  <tbody><tr><td valign=\"bottom\">\n" +
+            "        <p><span><blockquote>a paragraph</blockquote></span><br></p>\n" +
+            "  </tbody></tr></td>\n" +
+            "</table>\n" +
+            "<h2 style=\"margin: 0.0px 0.0px 0.0px 0.0px; line-height: 38.0px; font: 26.0px " +
+                    "'Helvetica Neue Light'; color: #262626; -webkit-text-stroke: #262626\">" +
+                    "<span>some header two</span></h2>\n" +
+            "<p><span>Lorem ipsum dolor concludaturque. </span></p>\n" +
+            "<p><span></span><br></p>\n" +
+            "<p><span>Vix te doctus</span></p>\n" +
+            "<p><span><b>Error mel</b></span><span>, est ei. <a href=\"http://andorid.com\">" +
+                    "<span>asda</span></a> ullamcorper eam.</span></p>\n" +
+            "<p><span>adversarium <a href=\"http://android.com\"><span>efficiantur</span></a>, " +
+                    "mea te.</span></p>\n" +
+            "<p><span></span><br></p>\n" +
+            "<h1>Testing display of HTML elements</h1>\n" +
+            "<h2>2nd level heading</h2>\n" +
+            "<p>test paragraph.</p>\n" +
+            "<h3>3rd level heading</h3>\n" +
+            "<p>test paragraph.</p>\n" +
+            "<h4>4th level heading</h4>\n" +
+            "<p>test paragraph.</p>\n" +
+            "<h5>5th level heading</h5>\n" +
+            "<p>test paragraph.</p>\n" +
+            "<h6>6th level heading</h6>\n" +
+            "<p>test paragraph.</p>\n" +
+            "<h2>level elements</h2>\n" +
+            "<p>a normap paragraph(<code>p</code> element).\n" +
+            "  with some <strong>strong</strong>.</p>\n" +
+            "<div>This is a <code>div</code> element. </div>\n" +
+            "<blockquote><p>This is a block quotation with some <em>style</em></p></blockquote>\n" +
+            "<address>an address element</address>\n" +
+            "<h2>Text-level markup</h2>\n" +
+            "<ul>\n" +
+            "  <li> <abbr title=\"Cascading Style Sheets\">CSS</abbr> (an abbreviation;\n" +
+            "    <code>abbr</code> markup used)\n" +
+            "  <li> <acronym title=\"radio detecting and ranging\">radar</acronym>\n" +
+            "  <li> <b>bolded</b>\n" +
+            "  <li> <big>big thing</big>\n" +
+            "  <li> <font size=6>large size</font>\n" +
+            "  <li> <font face=Courier>Courier font</font>\n" +
+            "  <li> <font color=red>red text</font>\n" +
+            "  <li> <cite>Origin of Species</cite>\n" +
+            "  <li> <code>a[i] = b[i] + c[i);</code>\n" +
+            "  <li> some <del>deleted</del> text\n" +
+            "  <li> an <dfn>octet</dfn> is an\n" +
+            "  <li> this is <em>very</em> simple\n" +
+            "  <li> <i lang=\"la\">Homo sapiens</i>\n" +
+            "  <li> some <ins>inserted</ins> text\n" +
+            "  <li> type <kbd>yes</kbd> when\n" +
+            "  <li> <q>Hello!</q>\n" +
+            "  <li> <q>She said <q>Hello!</q></q>\n" +
+            "  <li> <samp>ccc</samp>\n" +
+            "  <li> <small>important</small>\n" +
+            "  <li> <strike>overstruck</strike>\n" +
+            "  <li> <strong>this is highlighted text</strong>\n" +
+            "  <li> <code>sub</code> and\n" +
+            "    <code>sup</code> x<sub>1</sub> and H<sub>2</sub>O\n" +
+            "    M<sup>lle</sup>, 1<sup>st</sup>, e<sup>x</sup>, sin<sup>2</sup> <i>x</i>,\n" +
+            "    e<sup>x<sup>2</sup></sup> and f(x)<sup>g(x)<sup>a+b+c</sup></sup>\n" +
+            "    (where 2 and a+b+c should appear as exponents of exponents).\n" +
+            "  <li> <tt>text in monospace font</tt>\n" +
+            "  <li> <u>underlined</u> text\n" +
+            "  <li> <code>cat</code> <var>filename</var> displays the\n" +
+            "    the <var>filename</var>.\n" +
+            "</ul>\n";
+
+}
diff --git a/core/tests/benchmarks/src/android/text/SpannableStringInternalCopyBenchmark.java b/core/tests/benchmarks/src/android/text/SpannableStringInternalCopyBenchmark.java
new file mode 100644
index 0000000..dc5fed0
--- /dev/null
+++ b/core/tests/benchmarks/src/android/text/SpannableStringInternalCopyBenchmark.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text;
+
+import com.google.caliper.AfterExperiment;
+import com.google.caliper.BeforeExperiment;
+import com.google.caliper.Benchmark;
+import com.google.caliper.Param;
+
+public class SpannableStringInternalCopyBenchmark {
+
+    @Param({"1", "4", "16"})
+    private String paramStringMult;
+
+    private SpannedString spanned;
+
+    @BeforeExperiment
+    protected void setUp() throws Exception {
+        int strSize = Integer.valueOf(paramStringMult);
+        StringBuilder strBuilder = new StringBuilder();
+        for (int i = 0; i < strSize; i++) {
+            strBuilder.append(SpannableStringBuilderBenchmark.TEST_STRING);
+        }
+        Spanned source = Html.fromHtml(strBuilder.toString());
+        spanned = new SpannedString(source);
+    }
+
+    @AfterExperiment
+    protected void tearDown() {
+        spanned = null;
+    }
+
+    @Benchmark
+    public void timeCopyConstructor(int reps) throws Exception {
+        for (int i = 0; i < reps; i++) {
+            new SpannedString(spanned);
+        }
+    }
+
+    @Benchmark
+    public void timeSubsequence(int reps) throws Exception {
+        for (int i = 0; i < reps; i++) {
+            spanned.subSequence(1, spanned.length()-1);
+        }
+    }
+
+}
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index 7cd25af..eb055de 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -22,7 +22,7 @@
 	$(call all-java-files-under, EnabledTestApp/src)
 
 LOCAL_DX_FLAGS := --core-library
-LOCAL_AAPT_FLAGS = -0 dat -0 gld
+LOCAL_AAPT_FLAGS = -0 dat -0 gld -c fa
 LOCAL_STATIC_JAVA_LIBRARIES := \
     core-tests-support \
     android-common \
@@ -32,7 +32,8 @@
     littlemock \
     android-support-test \
     mockito-target \
-    espresso-core
+    espresso-core \
+    ub-uiautomator
 LOCAL_JAVA_LIBRARIES := android.test.runner conscrypt telephony-common org.apache.http.legacy
 LOCAL_PACKAGE_NAME := FrameworksCoreTests
 
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 5177836..bfa2b10 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -53,6 +53,7 @@
     <uses-permission android:name="android.permission.DOWNLOAD_CACHE_NON_PURGEABLE" />
     <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
     <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.INJECT_EVENTS" />
     <uses-permission android:name="android.permission.READ_CONTACTS" />
     <uses-permission android:name="android.permission.READ_LOGS"/>
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
@@ -146,6 +147,16 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.widget.DatePickerActivity"
+                android:label="DatePickerActivity"
+                android:screenOrientation="portrait"
+                android:theme="@android:style/Theme.Material.Light">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="android.widget.focus.DescendantFocusability" android:label="DescendantFocusability">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -1284,6 +1295,26 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.print.PrintTestActivity"/>
+
+        <service
+            android:name="android.print.mockservice.MockPrintService"
+            android:permission="android.permission.BIND_PRINT_SERVICE">
+            <intent-filter>
+                <action android:name="android.printservice.PrintService" />
+            </intent-filter>
+            <meta-data
+               android:name="android.printservice"
+               android:resource="@xml/printservice">
+            </meta-data>
+        </service>
+
+        <activity
+            android:name="android.print.mockservice.SettingsActivity"
+            android:permission="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"
+            android:exported="true">
+        </activity>
+
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/core/tests/coretests/res/layout/datepicker_layout.xml b/core/tests/coretests/res/layout/datepicker_layout.xml
new file mode 100644
index 0000000..a79f87d
--- /dev/null
+++ b/core/tests/coretests/res/layout/datepicker_layout.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<RelativeLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+    <DatePicker
+            android:id="@+id/datePicker"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerInParent="true"/>
+    <EditText
+            android:id="@+id/belowPicker"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="Some Text"
+            android:textAlignment="center"
+            android:layout_below="@id/datePicker"/>
+</RelativeLayout>
diff --git a/core/tests/coretests/res/values-fa/strings.xml b/core/tests/coretests/res/values-fa/strings.xml
new file mode 100644
index 0000000..c83f5f1
--- /dev/null
+++ b/core/tests/coretests/res/values-fa/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="dummy_string">رشتهٔ الکی</string>
+</resources>
diff --git a/core/tests/coretests/res/values/strings.xml b/core/tests/coretests/res/values/strings.xml
index 04b0478..ef915bb 100644
--- a/core/tests/coretests/res/values/strings.xml
+++ b/core/tests/coretests/res/values/strings.xml
@@ -139,4 +139,7 @@
     <!-- RestrictionsManagerTest -->
     <string name="restrictionManager_title">Title</string>
     <string name="restrictionManager_desc">Description</string>
+
+    <!-- ResourcesLocaleResolutionTest -->
+    <string name="dummy_string">dummy string</string>
 </resources>
diff --git a/core/tests/coretests/res/xml/printservice.xml b/core/tests/coretests/res/xml/printservice.xml
new file mode 100644
index 0000000..abbebda
--- /dev/null
+++ b/core/tests/coretests/res/xml/printservice.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.
+-->
+
+<print-service  xmlns:android="http://schemas.android.com/apk/res/android"
+     android:settingsActivity="android.print.mockservice.SettingsActivity"/>
diff --git a/core/tests/coretests/src/android/animation/AutoCancelTest.java b/core/tests/coretests/src/android/animation/AutoCancelTest.java
index 5810818..b1f88db 100644
--- a/core/tests/coretests/src/android/animation/AutoCancelTest.java
+++ b/core/tests/coretests/src/android/animation/AutoCancelTest.java
@@ -18,12 +18,10 @@
 import android.os.Handler;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
 
 import java.util.HashMap;
 import java.util.concurrent.TimeUnit;
 
-@Suppress  // Failing
 public class AutoCancelTest extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
 
     boolean mAnimX1Canceled = false;
diff --git a/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java b/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java
index dcf2c89..9c03e1a 100644
--- a/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java
+++ b/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java
@@ -90,6 +90,18 @@
         assertEqualsIgnoreOrder(Arrays.asList("sys_app1", "app4"), apps);
     }
 
+    public void testQueryAppsRequiredForSystemUser() {
+        // Test query only system apps required for system user
+        List<String> apps = mAppsQueryHelper.queryApps(AppsQueryHelper.GET_REQUIRED_FOR_SYSTEM_USER,
+                true, UserHandle.SYSTEM);
+        assertEqualsIgnoreOrder(Arrays.asList("sys_app3"), apps);
+
+        // Test query all apps required for system user
+        apps = mAppsQueryHelper.queryApps(AppsQueryHelper.GET_REQUIRED_FOR_SYSTEM_USER, false,
+                UserHandle.SYSTEM);
+        assertEqualsIgnoreOrder(Arrays.asList("sys_app3", "app4"), apps);
+    }
+
     private class AppsQueryHelperTestable extends AppsQueryHelper {
 
         @Override
@@ -104,7 +116,9 @@
             final ApplicationInfo ai3 = new ApplicationInfo();
             ai3.packageName = "sys_app3";
             ai3.flags |= ApplicationInfo.FLAG_SYSTEM;
+            ai3.privateFlags |= ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER;
             final ApplicationInfo ai4 = new ApplicationInfo();
+            ai4.privateFlags |= ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER;
             ai4.packageName = "app4";
             return Arrays.asList(ai1, ai2, ai3, ai4);
         }
diff --git a/core/tests/coretests/src/android/content/pm/ManifestDigestTest.java b/core/tests/coretests/src/android/content/pm/ManifestDigestTest.java
deleted file mode 100644
index 37495e1..0000000
--- a/core/tests/coretests/src/android/content/pm/ManifestDigestTest.java
+++ /dev/null
@@ -1,77 +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.content.pm;
-
-import android.os.Parcel;
-import android.test.AndroidTestCase;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.MessageDigest;
-
-public class ManifestDigestTest extends AndroidTestCase {
-    private static final byte[] MESSAGE_1 = {
-            (byte) 0x00, (byte) 0xAA, (byte) 0x55, (byte) 0xFF
-    };
-
-    public void testManifestDigest_FromInputStream_Null() {
-        assertNull("Attributes were null, so ManifestDigest.fromAttributes should return null",
-                ManifestDigest.fromInputStream(null));
-    }
-
-    public void testManifestDigest_FromInputStream_ThrowsIoException() {
-        InputStream is = new InputStream() {
-            @Override
-            public int read() throws IOException {
-                throw new IOException();
-            }
-        };
-
-        assertNull("InputStream threw exception, so ManifestDigest should be null",
-                ManifestDigest.fromInputStream(is));
-    }
-
-    public void testManifestDigest_Equals() throws Exception {
-        InputStream is = new ByteArrayInputStream(MESSAGE_1);
-
-        ManifestDigest expected =
-                new ManifestDigest(MessageDigest.getInstance("SHA-256").digest(MESSAGE_1));
-
-        ManifestDigest actual = ManifestDigest.fromInputStream(is);
-        assertEquals(expected, actual);
-
-        ManifestDigest unexpected = new ManifestDigest(new byte[0]);
-        assertFalse(unexpected.equals(actual));
-    }
-
-    public void testManifestDigest_Parcel() throws Exception {
-        InputStream is = new ByteArrayInputStream(MESSAGE_1);
-
-        ManifestDigest digest = ManifestDigest.fromInputStream(is);
-
-        Parcel p = Parcel.obtain();
-        digest.writeToParcel(p, 0);
-        p.setDataPosition(0);
-
-        ManifestDigest fromParcel = ManifestDigest.CREATOR.createFromParcel(p);
-
-        assertEquals("ManifestDigest going through parceling should be the same as before: "
-                + digest.toString() + " and " + fromParcel.toString(), digest,
-                fromParcel);
-    }
-}
diff --git a/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java b/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
index 9b216cb..d963812 100644
--- a/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
+++ b/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
@@ -16,7 +16,6 @@
 
 package android.content.pm;
 
-import android.content.pm.ManifestDigest;
 import android.content.pm.VerificationParams;
 import android.net.Uri;
 import android.os.Parcel;
@@ -33,7 +32,6 @@
     private final static String VERIFICATION_URI_STRING = "http://verification.uri/path";
     private final static String ORIGINATING_URI_STRING = "http://originating.uri/path";
     private final static String REFERRER_STRING = "http://referrer.uri/path";
-    private final static byte[] DIGEST_BYTES = "fake digest".getBytes();
     private final static int INSTALLER_UID = 42;
 
     private final static Uri VERIFICATION_URI = Uri.parse(VERIFICATION_URI_STRING);
@@ -42,11 +40,9 @@
 
     private final static int ORIGINATING_UID = 10042;
 
-    private final static ManifestDigest MANIFEST_DIGEST = new ManifestDigest(DIGEST_BYTES);
-
     public void testParcel() throws Exception {
         VerificationParams expected = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         Parcel parcel = Parcel.obtain();
         expected.writeToParcel(parcel, 0);
@@ -61,85 +57,70 @@
         assertEquals(REFERRER, actual.getReferrer());
 
         assertEquals(ORIGINATING_UID, actual.getOriginatingUid());
-
-        assertEquals(MANIFEST_DIGEST, actual.getManifestDigest());
     }
 
     public void testEquals_Success() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(
                 Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
 
         assertEquals(params1, params2);
     }
 
     public void testEquals_VerificationUri_Failure() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(
                 Uri.parse("http://a.different.uri/"), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
 
         assertFalse(params1.equals(params2));
     }
 
     public void testEquals_OriginatingUri_Failure() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(
                 Uri.parse(VERIFICATION_URI_STRING), Uri.parse("http://a.different.uri/"),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
 
         assertFalse(params1.equals(params2));
     }
 
     public void testEquals_Referrer_Failure() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(
                 Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse("http://a.different.uri/"), ORIGINATING_UID,
-                new ManifestDigest(DIGEST_BYTES));
+                Uri.parse("http://a.different.uri/"), ORIGINATING_UID);
 
         assertFalse(params1.equals(params2));
     }
 
     public void testEquals_Originating_Uid_Failure() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(
                 Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), 12345, new ManifestDigest(DIGEST_BYTES));
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testEquals_ManifestDigest_Failure() throws Exception {
-        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
-
-        VerificationParams params2 = new VerificationParams(
-                Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID,
-                new ManifestDigest("a different digest".getBytes()));
+                Uri.parse(REFERRER_STRING), 12345);
 
         assertFalse(params1.equals(params2));
     }
 
     public void testEquals_InstallerUid_Failure() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(
                 Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
         params2.setInstallerUid(INSTALLER_UID);
 
         assertFalse(params1.equals(params2));
@@ -147,78 +128,65 @@
 
     public void testHashCode_Success() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(
                 Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
 
         assertEquals(params1.hashCode(), params2.hashCode());
     }
 
     public void testHashCode_VerificationUri_Failure() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(null, Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
 
         assertFalse(params1.hashCode() == params2.hashCode());
     }
 
     public void testHashCode_OriginatingUri_Failure() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(
                 Uri.parse(VERIFICATION_URI_STRING), Uri.parse("http://a.different.uri/"),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
 
         assertFalse(params1.hashCode() == params2.hashCode());
     }
 
     public void testHashCode_Referrer_Failure() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(
                 Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING), null,
-                ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+                ORIGINATING_UID);
 
         assertFalse(params1.hashCode() == params2.hashCode());
     }
 
     public void testHashCode_Originating_Uid_Failure() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(
                 Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), 12345, new ManifestDigest(DIGEST_BYTES));
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-
-    public void testHashCode_ManifestDigest_Failure() throws Exception {
-        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
-
-        VerificationParams params2 = new VerificationParams(
-                Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID,
-                new ManifestDigest("a different digest".getBytes()));
+                Uri.parse(REFERRER_STRING), 12345);
 
         assertFalse(params1.hashCode() == params2.hashCode());
     }
 
     public void testHashCode_InstallerUid_Failure() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(
                 Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID,
-                new ManifestDigest("a different digest".getBytes()));
+                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
         params2.setInstallerUid(INSTALLER_UID);
 
         assertFalse(params1.hashCode() == params2.hashCode());
diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java
index a470de1..a723977 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java
@@ -16,6 +16,9 @@
 
 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.SET_DEFAULT;
 import static android.net.NetworkStats.SET_FOREGROUND;
 import static android.net.NetworkStats.SET_DBG_VPN_IN;
@@ -42,62 +45,103 @@
     private static final long TEST_START = 1194220800000L;
 
     public void testFindIndex() throws Exception {
-        final NetworkStats stats = new NetworkStats(TEST_START, 3)
-                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 10)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 11)
-                .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 12);
+        final NetworkStats stats = new NetworkStats(TEST_START, 4)
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1024L, 8L, 0L,
+                        0L, 10)
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 0L, 0L, 1024L,
+                        8L, 11)
+                .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1024L, 8L,
+                        1024L, 8L, 12)
+                .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING, 1024L, 8L,
+                        1024L, 8L, 12);
 
-        assertEquals(2, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE));
-        assertEquals(2, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE));
-        assertEquals(0, stats.findIndex(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE));
-        assertEquals(-1, stats.findIndex(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE));
+        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));
     }
 
     public void testFindIndexHinted() {
         final NetworkStats stats = new NetworkStats(TEST_START, 3)
-                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 10)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 11)
-                .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 12)
-                .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 1024L, 8L, 0L, 0L, 10)
-                .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, 0L, 0L, 1024L, 8L, 11)
-                .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 12);
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1024L, 8L, 0L,
+                        0L, 10)
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 0L, 0L, 1024L,
+                        8L, 11)
+                .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1024L, 8L,
+                        1024L, 8L, 12)
+                .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT, 1024L, 8L,
+                        0L, 0L, 10)
+                .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT, 0L, 0L, 1024L,
+                        8L, 11)
+                .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1024L, 8L,
+                        1024L, 8L, 12)
+                .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING, 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, hint));
-            assertEquals(1, stats.findIndexHinted(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, hint));
-            assertEquals(2, stats.findIndexHinted(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, hint));
-            assertEquals(3, stats.findIndexHinted(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, hint));
-            assertEquals(4, stats.findIndexHinted(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, hint));
-            assertEquals(5, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, hint));
-            assertEquals(-1, stats.findIndexHinted(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE, hint));
+            assertEquals(0, stats.findIndexHinted(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE,
+                    ROAMING_DEFAULT, hint));
+            assertEquals(1, stats.findIndexHinted(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE,
+                    ROAMING_DEFAULT, hint));
+            assertEquals(2, stats.findIndexHinted(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE,
+                    ROAMING_DEFAULT, hint));
+            assertEquals(3, stats.findIndexHinted(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE,
+                    ROAMING_DEFAULT, hint));
+            assertEquals(4, stats.findIndexHinted(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D,
+                    ROAMING_DEFAULT, hint));
+            assertEquals(5, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE,
+                    ROAMING_DEFAULT, hint));
+            assertEquals(6, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE,
+                    ROAMING_ROAMING, hint));
+            assertEquals(-1, stats.findIndexHinted(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE,
+                    ROAMING_DEFAULT, hint));
         }
     }
 
     public void testAddEntryGrow() throws Exception {
-        final NetworkStats stats = new NetworkStats(TEST_START, 2);
+        final NetworkStats stats = new NetworkStats(TEST_START, 3);
 
         assertEquals(0, stats.size());
-        assertEquals(2, stats.internalSize());
+        assertEquals(3, stats.internalSize());
 
-        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, 1L, 1L, 2L, 2L, 3);
-        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, 2L, 2L, 2L, 2L, 4);
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1L, 1L, 2L,
+                2L, 3);
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 2L, 2L, 2L,
+                2L, 4);
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING, 3L, 3L, 2L,
+                2L, 5);
 
-        assertEquals(2, stats.size());
-        assertEquals(2, stats.internalSize());
+        assertEquals(3, stats.size());
+        assertEquals(3, stats.internalSize());
 
-        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, 3L, 30L, 4L, 40L, 7);
-        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, 4L, 40L, 4L, 40L, 8);
-        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, 5L, 50L, 5L, 50L, 10);
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 4L, 40L, 4L,
+                40L, 7);
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 5L, 50L, 4L,
+                40L, 8);
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 6L, 60L, 5L,
+                50L, 10);
+        stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING, 7L, 70L, 5L,
+                50L, 11);
 
-        assertEquals(5, stats.size());
-        assertTrue(stats.internalSize() >= 5);
+        assertEquals(7, stats.size());
+        assertTrue(stats.internalSize() >= 7);
 
-        assertValues(stats, 0, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, 1L, 1L, 2L, 2L, 3);
-        assertValues(stats, 1, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, 2L, 2L, 2L, 2L, 4);
-        assertValues(stats, 2, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, 3L, 30L, 4L, 40L, 7);
-        assertValues(stats, 3, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, 4L, 40L, 4L, 40L, 8);
-        assertValues(stats, 4, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, 5L, 50L, 5L, 50L, 10);
+        assertValues(stats, 0, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1L, 1L,
+                2L, 2L, 3);
+        assertValues(stats, 1, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 2L, 2L,
+                2L, 2L, 4);
+        assertValues(stats, 2, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING, 3L, 3L,
+                2L, 2L, 5);
+        assertValues(stats, 3, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 4L,
+                40L, 4L, 40L, 7);
+        assertValues(stats, 4, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 5L,
+                50L, 4L, 40L, 8);
+        assertValues(stats, 5, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 6L,
+                60L, 5L, 50L, 10);
+        assertValues(stats, 6, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING, 7L,
+                70L, 5L, 50L, 11);
     }
 
     public void testCombineExisting() throws Exception {
@@ -105,16 +149,23 @@
 
         stats.addValues(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 10);
         stats.addValues(TEST_IFACE, 1001, SET_DEFAULT, 0xff, 128L, 1L, 128L, 1L, 2);
-        stats.combineValues(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, -128L, -1L, -128L, -1L, -1);
+        stats.combineValues(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, -128L, -1L,
+                -128L, -1L, -1);
 
-        assertValues(stats, 0, TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, 384L, 3L, 128L, 1L, 9);
-        assertValues(stats, 1, TEST_IFACE, 1001, SET_DEFAULT, 0xff, 128L, 1L, 128L, 1L, 2);
+        assertValues(stats, 0, TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 384L, 3L,
+                128L, 1L, 9);
+        assertValues(stats, 1, TEST_IFACE, 1001, SET_DEFAULT, 0xff, ROAMING_DEFAULT, 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, 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, 256L, 2L, 256L, 2L, 6);
+        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,
+                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,
+                256L, 2L, 6);
     }
 
     public void testSubtractIdenticalData() throws Exception {
@@ -129,8 +180,10 @@
         final NetworkStats result = after.subtract(before);
 
         // identical data should result in zero delta
-        assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0);
-        assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0);
+        assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 0L, 0L, 0L,
+                0L, 0);
+        assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 0L, 0L, 0L,
+                0L, 0);
     }
 
     public void testSubtractIdenticalRows() throws Exception {
@@ -145,8 +198,10 @@
         final NetworkStats result = after.subtract(before);
 
         // expect delta between measurements
-        assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1L, 1L, 2L, 1L, 4);
-        assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 3L, 1L, 4L, 1L, 8);
+        assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1L, 1L, 2L,
+                1L, 4);
+        assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 3L, 1L, 4L,
+                1L, 8);
     }
 
     public void testSubtractNewRows() throws Exception {
@@ -162,9 +217,12 @@
         final NetworkStats result = after.subtract(before);
 
         // its okay to have new rows
-        assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0);
-        assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0);
-        assertValues(result, 2, TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 20);
+        assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 0L, 0L, 0L,
+                0L, 0);
+        assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 0L, 0L, 0L,
+                0L, 0);
+        assertValues(result, 2, TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1024L, 8L,
+                1024L, 8L, 20);
     }
 
     public void testSubtractMissingRows() throws Exception {
@@ -179,7 +237,8 @@
 
         // should silently drop omitted rows
         assertEquals(1, result.size());
-        assertValues(result, 0, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 1L, 2L, 3L, 4L, 0);
+        assertValues(result, 0, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1L,
+                2L, 3L, 4L, 0);
         assertEquals(4L, result.getTotalBytes());
     }
 
@@ -195,7 +254,7 @@
                 .addValues(TEST_IFACE, 101, SET_FOREGROUND, TAG_NONE, 32L, 0L, 0L, 0L, 0L);
         assertEquals(96L, uidSet.getTotalBytes());
 
-        final NetworkStats uidTag = new NetworkStats(TEST_START, 3)
+        final NetworkStats uidTag = new NetworkStats(TEST_START, 6)
                 .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
                 .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
                 .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L)
@@ -203,6 +262,15 @@
                 .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
                 .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L);
         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,
+                        0L)
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 32L, 0L, 0L, 0L,
+                        0L)
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING, 32L, 0L, 0L, 0L,
+                        0L);
+        assertEquals(96L, uidRoaming.getTotalBytes());
     }
 
     public void testGroupedByIfaceEmpty() throws Exception {
@@ -215,62 +283,98 @@
 
     public void testGroupedByIfaceAll() throws Exception {
         final NetworkStats uidStats = new NetworkStats(TEST_START, 3)
-                .addValues(IFACE_ALL, 100, SET_ALL, TAG_NONE, 128L, 8L, 0L, 2L, 20L)
-                .addValues(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, 128L, 8L, 0L, 2L, 20L);
+                .addValues(IFACE_ALL, 100, SET_ALL, TAG_NONE, ROAMING_DEFAULT, 128L, 8L, 0L, 2L,
+                        20L)
+                .addValues(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT, 128L, 8L, 0L,
+                        2L, 20L)
+                .addValues(IFACE_ALL, 101, SET_ALL, TAG_NONE, ROAMING_ROAMING, 128L, 8L, 0L, 2L,
+                        20L);
         final NetworkStats grouped = uidStats.groupedByIface();
 
-        assertEquals(2, uidStats.size());
+        assertEquals(3, uidStats.size());
         assertEquals(1, grouped.size());
 
-        assertValues(grouped, 0, IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, 256L, 16L, 0L, 4L, 0L);
+        assertValues(grouped, 0, IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, ROAMING_ALL, 384L, 24L, 0L,
+                6L, 0L);
     }
 
     public void testGroupedByIface() throws Exception {
-        final NetworkStats uidStats = new NetworkStats(TEST_START, 3)
-                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L)
-                .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L)
-                .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 64L, 4L, 0L, 0L, 0L)
-                .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 512L, 32L, 0L, 0L, 0L)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 0L, 0L)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 128L, 8L, 0L, 0L, 0L);
+        final NetworkStats uidStats = new NetworkStats(TEST_START, 7)
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 128L, 8L, 0L,
+                        2L, 20L)
+                .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 512L, 32L, 0L,
+                        0L, 0L)
+                .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT, 64L, 4L, 0L, 0L,
+                        0L)
+                .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT, 512L, 32L,
+                        0L, 0L, 0L)
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 128L, 8L, 0L,
+                        0L, 0L)
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT, 128L, 8L, 0L, 0L,
+                        0L)
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING, 128L, 8L, 0L,
+                        0L, 0L);
 
         final NetworkStats grouped = uidStats.groupedByIface();
 
-        assertEquals(6, uidStats.size());
+        assertEquals(7, uidStats.size());
 
         assertEquals(2, grouped.size());
-        assertValues(grouped, 0, TEST_IFACE, UID_ALL, SET_ALL, TAG_NONE, 256L, 16L, 0L, 2L, 0L);
-        assertValues(grouped, 1, TEST_IFACE2, UID_ALL, SET_ALL, TAG_NONE, 1024L, 64L, 0L, 0L, 0L);
+        assertValues(grouped, 0, TEST_IFACE, UID_ALL, SET_ALL, TAG_NONE, ROAMING_ALL, 384L, 24L, 0L,
+                2L, 0L);
+        assertValues(grouped, 1, TEST_IFACE2, UID_ALL, SET_ALL, TAG_NONE, ROAMING_ALL, 1024L, 64L,
+                0L, 0L, 0L);
     }
 
     public void testAddAllValues() {
         final NetworkStats first = new NetworkStats(TEST_START, 5)
-                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L)
-                .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, 32L, 0L, 0L, 0L, 0L);
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 32L, 0L, 0L, 0L,
+                        0L)
+                .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT, 32L, 0L, 0L,
+                        0L, 0L)
+                .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_ROAMING, 32L, 0L, 0L,
+                        0L, 0L);
 
         final NetworkStats second = new NetworkStats(TEST_START, 2)
-                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L)
-                .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L);
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 32L, 0L, 0L, 0L,
+                        0L)
+                .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 32L, 0L,
+                        0L, 0L, 0L)
+                .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_ROAMING, 32L, 0L, 0L,
+                        0L, 0L);
 
         first.combineAllValues(second);
 
-        assertEquals(3, first.size());
-        assertValues(first, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 64L, 0L, 0L, 0L, 0L);
-        assertValues(first, 1, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, 32L, 0L, 0L, 0L, 0L);
-        assertValues(first, 2, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L);
+        assertEquals(4, first.size());
+        assertValues(first, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 64L, 0L, 0L,
+                0L, 0L);
+        assertValues(first, 1, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT, 32L, 0L,
+                0L, 0L, 0L);
+        assertValues(first, 2, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, ROAMING_ROAMING, 64L, 0L,
+                0L, 0L, 0L);
+        assertValues(first, 3, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 32L,
+                0L, 0L, 0L, 0L);
     }
 
     public void testGetTotal() {
-        final NetworkStats stats = new NetworkStats(TEST_START, 3)
-                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L)
-                .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L)
-                .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 64L, 4L, 0L, 0L, 0L)
-                .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 512L, 32L, 0L, 0L, 0L)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 0L, 0L)
-                .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 128L, 8L, 0L, 0L, 0L);
+        final NetworkStats stats = new NetworkStats(TEST_START, 7)
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 128L, 8L, 0L,
+                        2L, 20L)
+                .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 512L, 32L, 0L,
+                        0L, 0L)
+                .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT, 64L, 4L, 0L, 0L,
+                        0L)
+                .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT, 512L, 32L,
+                        0L, 0L, 0L)
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 128L, 8L, 0L,
+                        0L, 0L)
+                .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT, 128L, 8L, 0L, 0L,
+                        0L)
+                .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING, 128L, 8L, 0L,
+                        0L, 0L);
 
-        assertValues(stats.getTotal(null), 1280L, 80L, 0L, 2L, 20L);
-        assertValues(stats.getTotal(null, 100), 1152L, 72L, 0L, 2L, 20L);
+        assertValues(stats.getTotal(null), 1408L, 88L, 0L, 2L, 20L);
+        assertValues(stats.getTotal(null, 100), 1280L, 80L, 0L, 2L, 20L);
         assertValues(stats.getTotal(null, 101), 128L, 8L, 0L, 0L, 0L);
 
         final HashSet<String> ifaces = Sets.newHashSet();
@@ -292,8 +396,10 @@
         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, 128L, 8L, 0L, 0L, 0L);
-        assertValues(after, 1, TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 128L, 8L, 0L, 0L, 0L);
+        assertValues(after, 0, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 128L, 8L,
+                0L, 0L, 0L);
+        assertValues(after, 1, TEST_IFACE, 101, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT, 128L, 8L, 0L,
+                0L, 0L);
     }
 
     public void testClone() throws Exception {
@@ -351,76 +457,83 @@
         assertEquals(21, delta.size());
 
         // tunIface and TEST_IFACE entries are not changed.
-        assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE,
+        assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
                 39605L, 46L, 12259L, 55L, 0L);
-        assertValues(delta, 1, tunIface, 10100, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
-        assertValues(delta, 2, tunIface, 10120, SET_DEFAULT, TAG_NONE,
+        assertValues(delta, 1, tunIface, 10100, SET_FOREGROUND, TAG_NONE,  ROAMING_DEFAULT, 0L, 0L,
+                0L, 0L, 0L);
+        assertValues(delta, 2, tunIface, 10120, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
                 72667L, 197L, 43909L, 241L, 0L);
-        assertValues(delta, 3, tunIface, 10120, SET_FOREGROUND, TAG_NONE,
+        assertValues(delta, 3, tunIface, 10120, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT,
                 9297L, 17L, 4128L, 21L, 0L);
-        assertValues(delta, 4, tunIface, tunUid, SET_DEFAULT, TAG_NONE,
+        assertValues(delta, 4, tunIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
                 4983L, 10L, 1801L, 12L, 0L);
-        assertValues(delta, 5, tunIface, tunUid, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
-        assertValues(delta, 6, tunIface, 10120, SET_DEFAULT, testTag1,
+        assertValues(delta, 5, tunIface, tunUid, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT, 0L, 0L,
+                0L, 0L, 0L);
+        assertValues(delta, 6, tunIface, 10120, SET_DEFAULT, testTag1, ROAMING_DEFAULT,
                 21691L, 41L, 13820L, 51L, 0L);
-        assertValues(delta, 7, tunIface, 10120, SET_FOREGROUND, testTag1, 1281L, 2L, 665L, 2L, 0L);
-        assertValues(delta, 8, TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, 1685L, 5L, 2070L, 6L, 0L);
+        assertValues(delta, 7, tunIface, 10120, SET_FOREGROUND, testTag1, ROAMING_DEFAULT, 1281L,
+                2L, 665L, 2L, 0L);
+        assertValues(delta, 8, TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1685L, 5L,
+                2070L, 6L, 0L);
 
         // Existing underlying Iface entries are updated
-        assertValues(delta, 9, underlyingIface, 10100, SET_DEFAULT, TAG_NONE,
+        assertValues(delta, 9, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
                 44783L, 54L, 13829L, 60L, 0L);
-        assertValues(delta, 10, underlyingIface, 10100, SET_FOREGROUND, TAG_NONE,
+        assertValues(delta, 10, underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT,
                 0L, 0L, 0L, 0L, 0L);
 
         // VPN underlying Iface entries are updated
-        assertValues(delta, 11, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE,
+        assertValues(delta, 11, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
                 28304L, 27L, 1719L, 12L, 0L);
-        assertValues(delta, 12, underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE,
+        assertValues(delta, 12, underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT,
                 0L, 0L, 0L, 0L, 0L);
 
         // New entries are added for new application's underlying Iface traffic
-        assertContains(delta, underlyingIface, 10120, SET_DEFAULT, TAG_NONE,
-                72667L, 197L, 41872l, 219L, 0L);
-        assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, TAG_NONE,
+        assertContains(delta, underlyingIface, 10120, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+                72667L, 197L, 41872L, 219L, 0L);
+        assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT,
                 9297L, 17L, 3936, 19L, 0L);
-        assertContains(delta, underlyingIface, 10120, SET_DEFAULT, testTag1,
+        assertContains(delta, underlyingIface, 10120, SET_DEFAULT, testTag1, ROAMING_DEFAULT,
                 21691L, 41L, 13179L, 46L, 0L);
-        assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, testTag1,
+        assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, testTag1, ROAMING_DEFAULT,
                 1281L, 2L, 634L, 1L, 0L);
 
         // New entries are added for debug purpose
-        assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE,
+        assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, ROAMING_DEFAULT,
                 39605L, 46L, 11690, 49, 0);
-        assertContains(delta, underlyingIface, 10120, SET_DBG_VPN_IN, TAG_NONE,
+        assertContains(delta, underlyingIface, 10120, SET_DBG_VPN_IN, TAG_NONE, ROAMING_DEFAULT,
                 81964, 214, 45808, 238, 0);
-        assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_IN, TAG_NONE,
+        assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_IN, TAG_NONE, ROAMING_DEFAULT,
                 4983, 10, 1717, 10, 0);
-        assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE,
+        assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, ROAMING_ALL,
                 126552, 270, 59215, 297, 0);
 
     }
 
     private static void assertContains(NetworkStats stats,  String iface, int uid, int set,
-            int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
-        int index = stats.findIndex(iface, uid, set, tag);
+            int tag, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets,
+            long operations) {
+        int index = stats.findIndex(iface, uid, set, tag, roaming);
         assertTrue(index != -1);
-        assertValues(stats, index, iface, uid, set, tag,
+        assertValues(stats, index, iface, uid, set, tag, roaming,
                 rxBytes, rxPackets, txBytes, txPackets, operations);
     }
 
     private static void assertValues(NetworkStats stats, int index, String iface, int uid, int set,
-            int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
+            int tag, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets,
+            long operations) {
         final NetworkStats.Entry entry = stats.getValues(index, null);
-        assertValues(entry, iface, uid, set, tag);
+        assertValues(entry, iface, uid, set, tag, roaming);
         assertValues(entry, rxBytes, rxPackets, txBytes, txPackets, operations);
     }
 
     private static void assertValues(
-            NetworkStats.Entry entry, String iface, int uid, int set, int tag) {
+            NetworkStats.Entry entry, String iface, int uid, int set, int tag, int roaming) {
         assertEquals(iface, entry.iface);
         assertEquals(uid, entry.uid);
         assertEquals(set, entry.set);
         assertEquals(tag, entry.tag);
+        assertEquals(roaming, entry.roaming);
     }
 
     private static void assertValues(NetworkStats.Entry entry, long rxBytes, long rxPackets,
diff --git a/core/tests/coretests/src/android/print/BasePrintTest.java b/core/tests/coretests/src/android/print/BasePrintTest.java
new file mode 100644
index 0000000..19ce44a
--- /dev/null
+++ b/core/tests/coretests/src/android/print/BasePrintTest.java
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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 static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.ParcelFileDescriptor;
+import android.os.SystemClock;
+import android.print.PrintAttributes;
+import android.print.PrintDocumentAdapter;
+import android.print.PrintManager;
+import android.print.PrinterId;
+import android.print.mockservice.PrintServiceCallbacks;
+import android.print.mockservice.PrinterDiscoverySessionCallbacks;
+import android.print.mockservice.StubbablePrinterDiscoverySession;
+import android.printservice.CustomPrinterIconCallback;
+import android.printservice.PrintJob;
+import android.printservice.PrintService;
+import android.test.InstrumentationTestCase;
+import android.util.DisplayMetrics;
+import android.util.LocaleList;
+
+import org.mockito.stubbing.Answer;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * This is the base class for print tests.
+ */
+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 ";
+    private static final String COMMAND_PREFIX_DISABLE_IME = "ime disable ";
+    private static final int CURRENT_USER_ID = -2; // Mirrors UserHandle.USER_CURRENT
+
+    private PrintTestActivity mActivity;
+    private android.print.PrintJob mPrintJob;
+
+    private LocaleList mOldLocale;
+
+    private CallCounter mStartCallCounter;
+    private CallCounter mStartSessionCallCounter;
+
+    private String[] mEnabledImes;
+
+    private String[] getEnabledImes() throws IOException {
+        List<String> imeList = new ArrayList<>();
+
+        ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation()
+                .executeShellCommand(COMMAND_LIST_ENABLED_IME_COMPONENTS);
+        try (BufferedReader reader = new BufferedReader(
+                new InputStreamReader(new FileInputStream(pfd.getFileDescriptor())))) {
+
+            String line;
+            while ((line = reader.readLine()) != null) {
+                imeList.add(line);
+            }
+        }
+
+        String[] imeArray = new String[imeList.size()];
+        imeList.toArray(imeArray);
+
+        return imeArray;
+    }
+
+    private void disableImes() throws Exception {
+        mEnabledImes = getEnabledImes();
+        for (String ime : mEnabledImes) {
+            String disableImeCommand = COMMAND_PREFIX_DISABLE_IME + ime;
+            runShellCommand(getInstrumentation(), disableImeCommand);
+        }
+    }
+
+    private void enableImes() throws Exception {
+        for (String ime : mEnabledImes) {
+            String enableImeCommand = COMMAND_PREFIX_ENABLE_IME + ime;
+            runShellCommand(getInstrumentation(), enableImeCommand);
+        }
+        mEnabledImes = null;
+    }
+
+    @Override
+    protected void runTest() throws Throwable {
+        // Do nothing if the device does not support printing.
+        if (supportsPrinting()) {
+            super.runTest();
+        }
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        if (!supportsPrinting()) {
+            return;
+        }
+
+        // Make sure we start with a clean slate.
+        clearPrintSpoolerData();
+        disableImes();
+
+        // Workaround for dexmaker bug: https://code.google.com/p/dexmaker/issues/detail?id=2
+        // Dexmaker is used by mockito.
+        System.setProperty("dexmaker.dexcache", getInstrumentation()
+                .getTargetContext().getCacheDir().getPath());
+
+        // Set to US locale.
+        Resources resources = getInstrumentation().getTargetContext().getResources();
+        Configuration oldConfiguration = resources.getConfiguration();
+        if (!oldConfiguration.getLocales().getPrimary().equals(Locale.US)) {
+            mOldLocale = oldConfiguration.getLocales();
+            DisplayMetrics displayMetrics = resources.getDisplayMetrics();
+            Configuration newConfiguration = new Configuration(oldConfiguration);
+            newConfiguration.setLocale(Locale.US);
+            resources.updateConfiguration(newConfiguration, displayMetrics);
+        }
+
+        // Initialize the latches.
+        mStartCallCounter = new CallCounter();
+        mStartSessionCallCounter = new CallCounter();
+
+        // Create the activity for the right locale.
+        createActivity();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        if (!supportsPrinting()) {
+            return;
+        }
+
+        // Done with the activity.
+        getActivity().finish();
+        enableImes();
+
+        // Restore the locale if needed.
+        if (mOldLocale != null) {
+            Resources resources = getInstrumentation().getTargetContext().getResources();
+            DisplayMetrics displayMetrics = resources.getDisplayMetrics();
+            Configuration newConfiguration = new Configuration(resources.getConfiguration());
+            newConfiguration.setLocales(mOldLocale);
+            mOldLocale = null;
+            resources.updateConfiguration(newConfiguration, displayMetrics);
+        }
+
+        // Make sure the spooler is cleaned, this also un-approves all services
+        clearPrintSpoolerData();
+
+        super.tearDown();
+    }
+
+    protected android.print.PrintJob print(@NonNull final PrintDocumentAdapter adapter,
+            final PrintAttributes attributes) {
+        // Initiate printing as if coming from the app.
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                PrintManager printManager = (PrintManager) getActivity()
+                        .getSystemService(Context.PRINT_SERVICE);
+                mPrintJob = printManager.print("Print job", adapter, attributes);
+            }
+        });
+
+        return mPrintJob;
+    }
+
+    protected void onStartCalled() {
+        mStartCallCounter.call();
+    }
+
+    protected void onPrinterDiscoverySessionStartCalled() {
+        mStartSessionCallCounter.call();
+    }
+
+    protected void waitForPrinterDiscoverySessionStartCallbackCalled() {
+        waitForCallbackCallCount(mStartSessionCallCounter, 1,
+                "Did not get expected call to onStartPrinterDiscoverySession.");
+    }
+
+    protected void waitForStartAdapterCallbackCalled() {
+        waitForCallbackCallCount(mStartCallCounter, 1, "Did not get expected call to start.");
+    }
+
+    private void waitForCallbackCallCount(CallCounter counter, int count, String message) {
+        try {
+            counter.waitForCount(count, OPERATION_TIMEOUT);
+        } catch (TimeoutException te) {
+            fail(message);
+        }
+    }
+
+    protected PrintTestActivity getActivity() {
+        return mActivity;
+    }
+
+    protected void createActivity() {
+        mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
+                PrintTestActivity.class, null);
+    }
+
+    public static String runShellCommand(Instrumentation instrumentation, String cmd)
+            throws IOException {
+        ParcelFileDescriptor pfd = instrumentation.getUiAutomation().executeShellCommand(cmd);
+        byte[] buf = new byte[512];
+        int bytesRead;
+        FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+        StringBuffer stdout = new StringBuffer();
+        while ((bytesRead = fis.read(buf)) != -1) {
+            stdout.append(new String(buf, 0, bytesRead));
+        }
+        fis.close();
+        return stdout.toString();
+    }
+
+    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));
+    }
+
+    @SuppressWarnings("unchecked")
+    protected PrinterDiscoverySessionCallbacks createMockPrinterDiscoverySessionCallbacks(
+            Answer<Void> onStartPrinterDiscovery, Answer<Void> onStopPrinterDiscovery,
+            Answer<Void> onValidatePrinters, Answer<Void> onStartPrinterStateTracking,
+            Answer<Void> onRequestCustomPrinterIcon, Answer<Void> onStopPrinterStateTracking,
+            Answer<Void> onDestroy) {
+        PrinterDiscoverySessionCallbacks callbacks = mock(PrinterDiscoverySessionCallbacks.class);
+
+        doCallRealMethod().when(callbacks).setSession(any(StubbablePrinterDiscoverySession.class));
+        when(callbacks.getSession()).thenCallRealMethod();
+
+        if (onStartPrinterDiscovery != null) {
+            doAnswer(onStartPrinterDiscovery).when(callbacks).onStartPrinterDiscovery(
+                    any(List.class));
+        }
+        if (onStopPrinterDiscovery != null) {
+            doAnswer(onStopPrinterDiscovery).when(callbacks).onStopPrinterDiscovery();
+        }
+        if (onValidatePrinters != null) {
+            doAnswer(onValidatePrinters).when(callbacks).onValidatePrinters(
+                    any(List.class));
+        }
+        if (onStartPrinterStateTracking != null) {
+            doAnswer(onStartPrinterStateTracking).when(callbacks).onStartPrinterStateTracking(
+                    any(PrinterId.class));
+        }
+        if (onRequestCustomPrinterIcon != null) {
+            doAnswer(onRequestCustomPrinterIcon).when(callbacks).onRequestCustomPrinterIcon(
+                    any(PrinterId.class), any(CustomPrinterIconCallback.class));
+        }
+        if (onStopPrinterStateTracking != null) {
+            doAnswer(onStopPrinterStateTracking).when(callbacks).onStopPrinterStateTracking(
+                    any(PrinterId.class));
+        }
+        if (onDestroy != null) {
+            doAnswer(onDestroy).when(callbacks).onDestroy();
+        }
+
+        return callbacks;
+    }
+
+    protected PrintServiceCallbacks createMockPrintServiceCallbacks(
+            Answer<PrinterDiscoverySessionCallbacks> onCreatePrinterDiscoverySessionCallbacks,
+            Answer<Void> onPrintJobQueued, Answer<Void> onRequestCancelPrintJob) {
+        final PrintServiceCallbacks service = mock(PrintServiceCallbacks.class);
+
+        doCallRealMethod().when(service).setService(any(PrintService.class));
+        when(service.getService()).thenCallRealMethod();
+
+        if (onCreatePrinterDiscoverySessionCallbacks != null) {
+            doAnswer(onCreatePrinterDiscoverySessionCallbacks).when(service)
+                    .onCreatePrinterDiscoverySessionCallbacks();
+        }
+        if (onPrintJobQueued != null) {
+            doAnswer(onPrintJobQueued).when(service).onPrintJobQueued(any(PrintJob.class));
+        }
+        if (onRequestCancelPrintJob != null) {
+            doAnswer(onRequestCancelPrintJob).when(service).onRequestCancelPrintJob(
+                    any(PrintJob.class));
+        }
+
+        return service;
+    }
+
+    protected final class CallCounter {
+        private final Object mLock = new Object();
+
+        private int mCallCount;
+
+        public void call() {
+            synchronized (mLock) {
+                mCallCount++;
+                mLock.notifyAll();
+            }
+        }
+
+        public int getCallCount() {
+            synchronized (mLock) {
+                return mCallCount;
+            }
+        }
+
+        public void waitForCount(int count, long timeoutMillis) throws TimeoutException {
+            synchronized (mLock) {
+                final long startTimeMillis = SystemClock.uptimeMillis();
+                while (mCallCount < count) {
+                    try {
+                        final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                        final long remainingTimeMillis = timeoutMillis - elapsedTimeMillis;
+                        if (remainingTimeMillis <= 0) {
+                            throw new TimeoutException();
+                        }
+                        mLock.wait(timeoutMillis);
+                    } catch (InterruptedException ie) {
+                        /* ignore */
+                    }
+                }
+            }
+        }
+    }
+
+    protected boolean supportsPrinting() {
+        return getInstrumentation().getContext().getPackageManager()
+                .hasSystemFeature(PackageManager.FEATURE_PRINTING);
+    }
+}
diff --git a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
new file mode 100644
index 0000000..5179b42
--- /dev/null
+++ b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
@@ -0,0 +1,669 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.ComponentName;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.ParcelFileDescriptor;
+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.print.mockservice.MockPrintService;
+import android.print.mockservice.PrintServiceCallbacks;
+import android.print.mockservice.PrinterDiscoverySessionCallbacks;
+import android.print.mockservice.StubbablePrinterDiscoverySession;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * tests feeding all possible parameters to the IPrintManager Binder.
+ */
+public class IPrintManagerParametersTest extends BasePrintTest {
+
+    private final int BAD_APP_ID = 0xffffffff;
+
+    private final int mAppId;
+    private final int mUserId;
+    private final PrintJobId mBadPrintJobId;
+
+    private PrintJob mGoodPrintJob;
+    private PrinterId mBadPrinterId;
+    private PrinterId mGoodPrinterId;
+    private ComponentName mGoodComponentName;
+    private ComponentName mBadComponentName;
+
+    private IPrintManager mIPrintManager;
+
+    /**
+     * Create a new IPrintManagerParametersTest and setup basic fields.
+     */
+    public IPrintManagerParametersTest() {
+        super();
+
+        mAppId = UserHandle.getAppId(Process.myUid());
+        mUserId = UserHandle.myUserId();
+        mBadPrintJobId = new PrintJobId();
+        mBadComponentName = new ComponentName("bad", "bad");
+    }
+
+    /**
+     * Create a mock PrintDocumentAdapter.
+     *
+     * @return The adapter
+     */
+    private @NonNull PrintDocumentAdapter createMockAdapter() {
+        return new PrintDocumentAdapter() {
+            @Override
+            public void onStart() {
+                onStartCalled();
+            }
+
+            @Override
+            public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
+                    CancellationSignal cancellationSignal, LayoutResultCallback callback,
+                    Bundle extras) {
+            }
+
+            @Override
+            public void onWrite(PageRange[] pages, ParcelFileDescriptor destination,
+                    CancellationSignal cancellationSignal, WriteResultCallback callback) {
+            }
+        };
+    }
+
+    /**
+     * Create mock print service callbacks.
+     *
+     * @return the callbacks
+     */
+    private PrintServiceCallbacks createMockCallbacks() {
+        return createMockPrintServiceCallbacks(
+                new Answer<PrinterDiscoverySessionCallbacks>() {
+                    @Override
+                    public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
+                        return createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
+                            @Override
+                            public Void answer(InvocationOnMock invocation) {
+                                // Get the session.
+                                StubbablePrinterDiscoverySession session =
+                                        ((PrinterDiscoverySessionCallbacks) invocation
+                                        .getMock()).getSession();
+
+                                if (session.getPrinters().isEmpty()) {
+                                    final String PRINTER_NAME = "good printer";
+                                    List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
+
+                                    // Add the printer.
+                                    mGoodPrinterId = session.getService()
+                                            .generatePrinterId(PRINTER_NAME);
+
+                                    PrinterCapabilitiesInfo capabilities =
+                                            new PrinterCapabilitiesInfo.Builder(mGoodPrinterId)
+                                                    .setMinMargins(
+                                                            new Margins(200, 200, 200, 200))
+                                                    .addMediaSize(MediaSize.ISO_A4, true)
+                                                    .addResolution(new Resolution("300x300",
+                                                            "300x300", 300, 300),
+                                                            true)
+                                                    .setColorModes(
+                                                            PrintAttributes.COLOR_MODE_COLOR,
+                                                            PrintAttributes.COLOR_MODE_COLOR)
+                                                    .build();
+
+                                    PrinterInfo printer = new PrinterInfo.Builder(
+                                            mGoodPrinterId,
+                                            PRINTER_NAME,
+                                            PrinterInfo.STATUS_IDLE)
+                                                    .setCapabilities(capabilities)
+                                                    .build();
+                                    printers.add(printer);
+
+                                    session.addPrinters(printers);
+                                }
+                                onPrinterDiscoverySessionStartCalled();
+                                return null;
+                            }
+                        }, null, null, null, null, null, null);
+                    }
+                },
+                null, null);
+    }
+
+    /**
+     * Create a IPrintJobStateChangeListener object.
+     *
+     * @return the object
+     * @throws Exception if the object could not be created.
+     */
+    private IPrintJobStateChangeListener createMockIPrintJobStateChangeListener() throws Exception {
+        return new PrintManager.PrintJobStateChangeListenerWrapper(null,
+                new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Create a IPrinterDiscoveryObserver object.
+     *
+     * @return the object
+     * @throws Exception if the object could not be created.
+     */
+    private IPrinterDiscoveryObserver createMockIPrinterDiscoveryObserver() throws Exception {
+        return new PrinterDiscoverySession.PrinterDiscoveryObserver(null);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        MockPrintService.setCallbacks(createMockCallbacks());
+
+        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();
+    }
+
+    /**
+     * {@link Runnable} that can throw and {@link Exception}
+     */
+    private interface Invokable {
+        /**
+         * Execute the {@link Invokable}
+         *
+         * @throws Exception
+         */
+        public void run() throws Exception;
+    }
+
+    /**
+     * Assert that the invokable throws an expectedException
+     *
+     * @param invokable The {@link Invokable} to run
+     * @param expectedClass The {@link Exception} that is supposed to be thrown
+     */
+    public void assertException(Invokable invokable, Class<? extends Exception> expectedClass)
+            throws Exception {
+        try {
+            invokable.run();
+        } catch (Exception e) {
+            if (e.getClass().isAssignableFrom(expectedClass)) {
+                return;
+            } else {
+                throw new AssertionError("Expected: " + expectedClass.getName() + ", got: "
+                                + e.getClass().getName());
+            }
+        }
+
+        throw new AssertionError("No exception thrown");
+    }
+
+    /**
+     * test IPrintManager.getPrintJobInfo
+     */
+    public void testGetPrintJobInfo() throws Exception {
+        assertEquals(mGoodPrintJob.getId(), mIPrintManager.getPrintJobInfo(mGoodPrintJob.getId(),
+                        mAppId, mUserId).getId());
+        assertEquals(null, mIPrintManager.getPrintJobInfo(mBadPrintJobId, mAppId, mUserId));
+        assertEquals(null, mIPrintManager.getPrintJobInfo(null, mAppId, mUserId));
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.getPrintJobInfo(mGoodPrintJob.getId(), BAD_APP_ID, mUserId);
+            }
+        }, SecurityException.class);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+
+    /**
+     * test IPrintManager.getPrintJobInfos
+     */
+    public void testGetPrintJobInfos() throws Exception {
+        List<PrintJobInfo> infos = mIPrintManager.getPrintJobInfos(mAppId, mUserId);
+
+        boolean foundPrintJob = false;
+        for (PrintJobInfo info : infos) {
+            if (info.getId().equals(mGoodPrintJob.getId())) {
+                assertEquals(PrintJobInfo.STATE_CREATED, info.getState());
+                foundPrintJob = true;
+            }
+        }
+        assertTrue(foundPrintJob);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.getPrintJobInfos(BAD_APP_ID, mUserId);
+            }
+        }, SecurityException.class);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+
+    /**
+     * test IPrintManager.print
+     */
+    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()
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.print(null, adapter, null, mGoodComponentName.getPackageName(),
+                        mAppId, mUserId);
+            }
+        }, IllegalArgumentException.class);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.print(name, null, null, mGoodComponentName.getPackageName(),
+                        mAppId, mUserId);
+            }
+        }, NullPointerException.class);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.print(name, adapter, null, null, mAppId, mUserId);
+            }
+        }, IllegalArgumentException.class);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.print(name, adapter, null, mBadComponentName.getPackageName(),
+                        mAppId, mUserId);
+            }
+        }, IllegalArgumentException.class);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.print(name, adapter, null, mGoodComponentName.getPackageName(),
+                        BAD_APP_ID, mUserId);
+            }
+        }, SecurityException.class);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+
+    /**
+     * test IPrintManager.cancelPrintJob
+     */
+    public void testCancelPrintJob() throws Exception {
+        // Invalid print jobs IDs do not produce an exception
+        mIPrintManager.cancelPrintJob(mBadPrintJobId, mAppId, mUserId);
+        mIPrintManager.cancelPrintJob(null, mAppId, mUserId);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.cancelPrintJob(mGoodPrintJob.getId(), BAD_APP_ID, mUserId);
+            }
+        }, SecurityException.class);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+
+        // Must be last as otherwise mGoodPrintJob will not be good anymore
+        mIPrintManager.cancelPrintJob(mGoodPrintJob.getId(), mAppId, mUserId);
+    }
+
+    /**
+     * test IPrintManager.restartPrintJob
+     */
+    public void testRestartPrintJob() throws Exception {
+        mIPrintManager.restartPrintJob(mGoodPrintJob.getId(), mAppId, mUserId);
+
+        // Invalid print jobs IDs do not produce an exception
+        mIPrintManager.restartPrintJob(mBadPrintJobId, mAppId, mUserId);
+        mIPrintManager.restartPrintJob(null, mAppId, mUserId);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.restartPrintJob(mGoodPrintJob.getId(), BAD_APP_ID, mUserId);
+            }
+        }, SecurityException.class);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+
+    /**
+     * test IPrintManager.addPrintJobStateChangeListener
+     */
+    public void testAddPrintJobStateChangeListener() throws Exception {
+        final IPrintJobStateChangeListener listener = createMockIPrintJobStateChangeListener();
+
+        mIPrintManager.addPrintJobStateChangeListener(listener, mAppId, mUserId);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.addPrintJobStateChangeListener(null, mAppId, mUserId);
+            }
+        }, NullPointerException.class);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.addPrintJobStateChangeListener(listener, BAD_APP_ID, mUserId);
+            }
+        }, SecurityException.class);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+
+    /**
+     * test IPrintManager.removePrintJobStateChangeListener
+     */
+    public void testRemovePrintJobStateChangeListener() throws Exception {
+        final IPrintJobStateChangeListener listener = createMockIPrintJobStateChangeListener();
+
+        mIPrintManager.addPrintJobStateChangeListener(listener, mAppId, mUserId);
+        mIPrintManager.removePrintJobStateChangeListener(listener, mUserId);
+
+        // Removing unknown listeners is a no-op
+        mIPrintManager.removePrintJobStateChangeListener(listener, mUserId);
+
+        mIPrintManager.addPrintJobStateChangeListener(listener, mAppId, mUserId);
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.removePrintJobStateChangeListener(null, mUserId);
+            }
+        }, NullPointerException.class);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+
+    /**
+     * test IPrintManager.getInstalledPrintServices
+     */
+    public void testGetInstalledPrintServices() throws Exception {
+        List<PrintServiceInfo> printServices = mIPrintManager.getInstalledPrintServices(mUserId);
+        assertTrue(printServices.size() >= 2);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+
+    /**
+     * test IPrintManager.getEnabledPrintServices
+     */
+    public void testGetEnabledPrintServices() throws Exception {
+        List<PrintServiceInfo> printServices = mIPrintManager.getEnabledPrintServices(mUserId);
+        assertTrue(printServices.size() >= 2);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+
+    /**
+     * test IPrintManager.createPrinterDiscoverySession
+     */
+    public void testCreatePrinterDiscoverySession() throws Exception {
+        final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
+
+        mIPrintManager.createPrinterDiscoverySession(listener, mUserId);
+
+        try {
+            assertException(new Invokable() {
+                @Override
+                public void run() throws Exception {
+                    mIPrintManager.createPrinterDiscoverySession(null, mUserId);
+                }
+            }, NullPointerException.class);
+
+            // Cannot test bad user Id as these tests are allowed to call across users
+        } finally {
+            // Remove discovery session so that the next test create a new one. Usually a leaked
+            // session is removed on the next call from the print service. But in this case we want
+            // to force a new call to onPrinterDiscoverySessionStart in the next test.
+            mIPrintManager.destroyPrinterDiscoverySession(listener, mUserId);
+        }
+    }
+
+    /**
+     * test IPrintManager.startPrinterDiscovery
+     */
+    public void testStartPrinterDiscovery() throws Exception {
+        final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
+        final List<PrinterId> goodPrinters = new ArrayList<>();
+        goodPrinters.add(mGoodPrinterId);
+
+        final List<PrinterId> badPrinters = new ArrayList<>();
+        badPrinters.add(mBadPrinterId);
+
+        final List<PrinterId> emptyPrinters = new ArrayList<>();
+
+        final List<PrinterId> nullPrinters = new ArrayList<>();
+        nullPrinters.add(null);
+
+        mIPrintManager.startPrinterDiscovery(listener, goodPrinters, mUserId);
+
+        // Bad or no printers do no cause exceptions
+        mIPrintManager.startPrinterDiscovery(listener, badPrinters, mUserId);
+        mIPrintManager.startPrinterDiscovery(listener, emptyPrinters, mUserId);
+        mIPrintManager.startPrinterDiscovery(listener, null, mUserId);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.startPrinterDiscovery(listener, nullPrinters, mUserId);
+            }
+        }, NullPointerException.class);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.startPrinterDiscovery(null, goodPrinters, mUserId);
+            }
+        }, NullPointerException.class);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+
+    /**
+     * test IPrintManager.stopPrinterDiscovery
+     */
+    public void testStopPrinterDiscovery() throws Exception {
+        final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
+
+        mIPrintManager.startPrinterDiscovery(listener, null, mUserId);
+        mIPrintManager.stopPrinterDiscovery(listener, mUserId);
+
+        // Stopping an already stopped session is a no-op
+        mIPrintManager.stopPrinterDiscovery(listener, mUserId);
+
+        mIPrintManager.startPrinterDiscovery(listener, null, mUserId);
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.stopPrinterDiscovery(null, mUserId);
+            }
+        }, NullPointerException.class);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+
+    /**
+     * test IPrintManager.validatePrinters
+     */
+    public void testValidatePrinters() throws Exception {
+        final List<PrinterId> goodPrinters = new ArrayList<>();
+        goodPrinters.add(mGoodPrinterId);
+
+        final List<PrinterId> badPrinters = new ArrayList<>();
+        badPrinters.add(mBadPrinterId);
+
+        final List<PrinterId> emptyPrinters = new ArrayList<>();
+
+        final List<PrinterId> nullPrinters = new ArrayList<>();
+        nullPrinters.add(null);
+
+        mIPrintManager.validatePrinters(goodPrinters, mUserId);
+
+        // Bad or empty list of printers do no cause exceptions
+        mIPrintManager.validatePrinters(badPrinters, mUserId);
+        mIPrintManager.validatePrinters(emptyPrinters, mUserId);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.validatePrinters(null, mUserId);
+            }
+        }, NullPointerException.class);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.validatePrinters(nullPrinters, mUserId);
+            }
+        }, NullPointerException.class);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+
+    /**
+     * test IPrintManager.startPrinterStateTracking
+     */
+    public void testStartPrinterStateTracking() throws Exception {
+        mIPrintManager.startPrinterStateTracking(mGoodPrinterId, mUserId);
+
+        // Bad printers do no cause exceptions
+        mIPrintManager.startPrinterStateTracking(mBadPrinterId, mUserId);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.startPrinterStateTracking(null, mUserId);
+            }
+        }, NullPointerException.class);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+
+    /**
+     * test IPrintManager.getCustomPrinterIcon
+     */
+    public void testGetCustomPrinterIcon() throws Exception {
+        mIPrintManager.getCustomPrinterIcon(mGoodPrinterId, mUserId);
+
+        // Bad printers do no cause exceptions
+        mIPrintManager.getCustomPrinterIcon(mBadPrinterId, mUserId);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.getCustomPrinterIcon(null, mUserId);
+            }
+        }, NullPointerException.class);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+
+    /**
+     * test IPrintManager.stopPrinterStateTracking
+     */
+    public void testStopPrinterStateTracking() throws Exception {
+        mIPrintManager.startPrinterStateTracking(mGoodPrinterId, mUserId);
+        mIPrintManager.stopPrinterStateTracking(mGoodPrinterId, mUserId);
+
+        // Stop to track a non-tracked printer is a no-op
+        mIPrintManager.stopPrinterStateTracking(mGoodPrinterId, mUserId);
+
+        // Bad printers do no cause exceptions
+        mIPrintManager.startPrinterStateTracking(mBadPrinterId, mUserId);
+        mIPrintManager.stopPrinterStateTracking(mBadPrinterId, mUserId);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.stopPrinterStateTracking(null, mUserId);
+            }
+        }, NullPointerException.class);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+
+    /**
+     * test IPrintManager.destroyPrinterDiscoverySession
+     */
+    public void testDestroyPrinterDiscoverySession() throws Exception {
+        final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
+
+        mIPrintManager.createPrinterDiscoverySession(listener, mUserId);
+        mIPrintManager.destroyPrinterDiscoverySession(listener, mUserId);
+
+        // Destroying already destroyed session is a no-op
+        mIPrintManager.destroyPrinterDiscoverySession(listener, mUserId);
+
+        assertException(new Invokable() {
+            @Override
+            public void run() throws Exception {
+                mIPrintManager.destroyPrinterDiscoverySession(null, mUserId);
+            }
+        }, NullPointerException.class);
+
+        // Cannot test bad user Id as these tests are allowed to call across users
+    }
+}
diff --git a/core/tests/coretests/src/android/print/PrintTestActivity.java b/core/tests/coretests/src/android/print/PrintTestActivity.java
new file mode 100644
index 0000000..86074a6
--- /dev/null
+++ b/core/tests/coretests/src/android/print/PrintTestActivity.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 android.print;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+public class PrintTestActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
+    }
+}
diff --git a/core/tests/coretests/src/android/print/mockservice/MockPrintService.java b/core/tests/coretests/src/android/print/mockservice/MockPrintService.java
new file mode 100644
index 0000000..9c11c22
--- /dev/null
+++ b/core/tests/coretests/src/android/print/mockservice/MockPrintService.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.print.mockservice;
+
+public class MockPrintService extends StubbablePrintService {
+
+    private static final Object sLock = new Object();
+
+    private static PrintServiceCallbacks sCallbacks;
+
+    public static void setCallbacks(PrintServiceCallbacks callbacks) {
+        synchronized (sLock) {
+            sCallbacks = callbacks;
+        }
+    }
+
+    @Override
+    protected PrintServiceCallbacks getCallbacks() {
+        synchronized (sLock) {
+            if (sCallbacks != null) {
+                sCallbacks.setService(this);
+            }
+            return sCallbacks;
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/print/mockservice/PrintServiceCallbacks.java b/core/tests/coretests/src/android/print/mockservice/PrintServiceCallbacks.java
new file mode 100644
index 0000000..4e89207
--- /dev/null
+++ b/core/tests/coretests/src/android/print/mockservice/PrintServiceCallbacks.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 android.print.mockservice;
+
+import android.printservice.PrintJob;
+import android.printservice.PrintService;
+
+public abstract class PrintServiceCallbacks {
+
+    private PrintService mService;
+
+    public PrintService getService() {
+        return mService;
+    }
+
+    public void setService(PrintService service) {
+        mService = service;
+    }
+
+    public abstract PrinterDiscoverySessionCallbacks onCreatePrinterDiscoverySessionCallbacks();
+
+    public abstract void onRequestCancelPrintJob(PrintJob printJob);
+
+    public abstract void onPrintJobQueued(PrintJob printJob);
+}
diff --git a/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java b/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java
new file mode 100644
index 0000000..26b7cae
--- /dev/null
+++ b/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.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.print.mockservice;
+
+import android.print.PrinterId;
+import android.printservice.CustomPrinterIconCallback;
+
+import java.util.List;
+
+public abstract class PrinterDiscoverySessionCallbacks {
+
+    private StubbablePrinterDiscoverySession mSession;
+
+    public void setSession(StubbablePrinterDiscoverySession session) {
+        mSession = session;
+    }
+
+    public StubbablePrinterDiscoverySession getSession() {
+        return mSession;
+    }
+
+    public abstract void onStartPrinterDiscovery(List<PrinterId> priorityList);
+
+    public abstract void onStopPrinterDiscovery();
+
+    public abstract void onValidatePrinters(List<PrinterId> printerIds);
+
+    public abstract void onStartPrinterStateTracking(PrinterId printerId);
+
+    public abstract void onRequestCustomPrinterIcon(PrinterId printerId,
+            CustomPrinterIconCallback callback);
+
+    public abstract void onStopPrinterStateTracking(PrinterId printerId);
+
+    public abstract void onDestroy();
+}
diff --git a/core/tests/coretests/src/android/print/mockservice/SettingsActivity.java b/core/tests/coretests/src/android/print/mockservice/SettingsActivity.java
new file mode 100644
index 0000000..fb76e67
--- /dev/null
+++ b/core/tests/coretests/src/android/print/mockservice/SettingsActivity.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.print.mockservice;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class SettingsActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+}
diff --git a/core/tests/coretests/src/android/print/mockservice/StubbablePrintService.java b/core/tests/coretests/src/android/print/mockservice/StubbablePrintService.java
new file mode 100644
index 0000000..b58b2735
--- /dev/null
+++ b/core/tests/coretests/src/android/print/mockservice/StubbablePrintService.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.print.mockservice;
+
+import android.printservice.PrintJob;
+import android.printservice.PrintService;
+import android.printservice.PrinterDiscoverySession;
+
+public abstract class StubbablePrintService extends PrintService {
+
+    @Override
+    public PrinterDiscoverySession onCreatePrinterDiscoverySession() {
+        PrintServiceCallbacks callbacks = getCallbacks();
+        if (callbacks != null) {
+            return new StubbablePrinterDiscoverySession(this,
+                    getCallbacks().onCreatePrinterDiscoverySessionCallbacks());
+        }
+        return null;
+    }
+
+    @Override
+    public void onRequestCancelPrintJob(PrintJob printJob) {
+        PrintServiceCallbacks callbacks = getCallbacks();
+        if (callbacks != null) {
+            callbacks.onRequestCancelPrintJob(printJob);
+        }
+    }
+
+    @Override
+    public void onPrintJobQueued(PrintJob printJob) {
+        PrintServiceCallbacks callbacks = getCallbacks();
+        if (callbacks != null) {
+            callbacks.onPrintJobQueued(printJob);
+        }
+    }
+
+    protected abstract PrintServiceCallbacks getCallbacks();
+}
diff --git a/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java b/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java
new file mode 100644
index 0000000..04683f2
--- /dev/null
+++ b/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java
@@ -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 android.print.mockservice;
+
+import android.print.PrinterId;
+import android.printservice.CustomPrinterIconCallback;
+import android.printservice.PrintService;
+import android.printservice.PrinterDiscoverySession;
+
+import java.util.List;
+
+public class StubbablePrinterDiscoverySession extends PrinterDiscoverySession {
+    private final PrintService mService;
+    private final PrinterDiscoverySessionCallbacks mCallbacks;
+
+    public StubbablePrinterDiscoverySession(PrintService service,
+            PrinterDiscoverySessionCallbacks callbacks) {
+        mService = service;
+        mCallbacks = callbacks;
+        if (mCallbacks != null) {
+            mCallbacks.setSession(this);
+        }
+    }
+
+    public PrintService getService() {
+        return mService;
+    }
+
+    @Override
+    public void onStartPrinterDiscovery(List<PrinterId> priorityList) {
+        if (mCallbacks != null) {
+            mCallbacks.onStartPrinterDiscovery(priorityList);
+        }
+    }
+
+    @Override
+    public void onStopPrinterDiscovery() {
+        if (mCallbacks != null) {
+            mCallbacks.onStopPrinterDiscovery();
+        }
+    }
+
+    @Override
+    public void onValidatePrinters(List<PrinterId> printerIds) {
+        if (mCallbacks != null) {
+            mCallbacks.onValidatePrinters(printerIds);
+        }
+    }
+
+    @Override
+    public void onStartPrinterStateTracking(PrinterId printerId) {
+        if (mCallbacks != null) {
+            mCallbacks.onStartPrinterStateTracking(printerId);
+        }
+    }
+
+    @Override
+    public void onRequestCustomPrinterIcon(PrinterId printerId,
+            CustomPrinterIconCallback callback) {
+        if (mCallbacks != null) {
+            mCallbacks.onRequestCustomPrinterIcon(printerId, callback);
+        }
+    }
+
+    @Override
+    public void onStopPrinterStateTracking(PrinterId printerId) {
+        if (mCallbacks != null) {
+            mCallbacks.onStopPrinterStateTracking(printerId);
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        if (mCallbacks != null) {
+            mCallbacks.onDestroy();
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/text/StaticLayoutTextMeasuringTest.java b/core/tests/coretests/src/android/text/StaticLayoutTextMeasuringTest.java
new file mode 100644
index 0000000..2e0e6dc
--- /dev/null
+++ b/core/tests/coretests/src/android/text/StaticLayoutTextMeasuringTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.text;
+
+import android.text.Layout.Alignment;
+import junit.framework.TestCase;
+
+/**
+ * Tests for text measuring methods of StaticLayout.
+ */
+public class StaticLayoutTextMeasuringTest extends TestCase {
+    private static final float SPACE_MULTI = 1.0f;
+    private static final float SPACE_ADD = 0.0f;
+    private static final int DEFAULT_OUTER_WIDTH = 150;
+    private static final Alignment DEFAULT_ALIGN = Alignment.ALIGN_LEFT;
+
+    private TextPaint mDefaultPaint;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        if (mDefaultPaint == null) {
+            mDefaultPaint = new TextPaint();
+        }
+    }
+
+    public void testGetPrimaryHorizontal_zwnbsp() {
+        // a, ZERO WIDTH NO-BREAK SPACE
+        String testString = "a\uFEFF";
+        StaticLayout layout = new StaticLayout(testString, mDefaultPaint,
+                DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
+
+        assertEquals(0.0f, layout.getPrimaryHorizontal(0));
+        assertEquals(layout.getPrimaryHorizontal(2), layout.getPrimaryHorizontal(1));
+    }
+
+    public void testGetPrimaryHorizontal_devanagari() {
+        // DEVANAGARI LETTER KA, DEVANAGARI VOWEL SIGN AA
+        String testString = "\u0915\u093E";
+        StaticLayout layout = new StaticLayout(testString, mDefaultPaint,
+                DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
+
+        assertEquals(0.0f, layout.getPrimaryHorizontal(0));
+        assertEquals(layout.getPrimaryHorizontal(2), layout.getPrimaryHorizontal(1));
+    }
+
+    public void testGetPrimaryHorizontal_flagEmoji() {
+        // REGIONAL INDICATOR SYMBOL LETTER U, REGIONAL INDICATOR SYMBOL LETTER S, REGIONAL
+        // INDICATOR SYMBOL LETTER Z
+        // First two code points (U and S) forms a US flag.
+        String testString = "\uD83C\uDDFA\uD83C\uDDF8\uD83C\uDDFF";
+        StaticLayout layout = new StaticLayout(testString, mDefaultPaint,
+                DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true);
+
+        assertEquals(0.0f, layout.getPrimaryHorizontal(0));
+        assertEquals(layout.getPrimaryHorizontal(4), layout.getPrimaryHorizontal(1));
+        assertEquals(layout.getPrimaryHorizontal(4), layout.getPrimaryHorizontal(2));
+        assertEquals(layout.getPrimaryHorizontal(4), layout.getPrimaryHorizontal(3));
+
+        assertTrue(layout.getPrimaryHorizontal(6) > layout.getPrimaryHorizontal(4));
+        assertEquals(layout.getPrimaryHorizontal(6), layout.getPrimaryHorizontal(5));
+    }
+}
diff --git a/core/tests/coretests/src/android/util/LocaleListTest.java b/core/tests/coretests/src/android/util/LocaleListTest.java
new file mode 100644
index 0000000..de1382d
--- /dev/null
+++ b/core/tests/coretests/src/android/util/LocaleListTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.util;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.LocaleList;
+
+import java.util.Locale;
+
+import junit.framework.TestCase;
+
+public class LocaleListTest extends TestCase {
+    @SmallTest
+    public void testConstructor() throws Exception {
+        LocaleList ll;
+        ll = new LocaleList(Locale.forLanguageTag("fr"), null);
+        assertEquals("fr", ll.toLanguageTags());
+
+        ll = new LocaleList(Locale.forLanguageTag("fr"), LocaleList.getEmptyLocaleList());
+        assertEquals("fr", ll.toLanguageTags());
+
+        ll = new LocaleList(Locale.forLanguageTag("fr"), LocaleList.forLanguageTags("fr"));
+        assertEquals("fr", ll.toLanguageTags());
+
+        ll = new LocaleList(Locale.forLanguageTag("fr"), LocaleList.forLanguageTags("de"));
+        assertEquals("fr,de", ll.toLanguageTags());
+
+        ll = new LocaleList(Locale.forLanguageTag("fr"), LocaleList.forLanguageTags("de,ja"));
+        assertEquals("fr,de,ja", ll.toLanguageTags());
+
+        ll = new LocaleList(Locale.forLanguageTag("fr"), LocaleList.forLanguageTags("de,fr,ja"));
+        assertEquals("fr,de,ja", ll.toLanguageTags());
+
+        ll = new LocaleList(Locale.forLanguageTag("fr"), LocaleList.forLanguageTags("de,fr"));
+        assertEquals("fr,de", ll.toLanguageTags());
+
+        ll = new LocaleList(Locale.forLanguageTag("fr"), LocaleList.forLanguageTags("fr,de"));
+        assertEquals("fr,de", ll.toLanguageTags());
+    }
+
+    @SmallTest
+    public void testConstructor_nullThrows() throws Exception {
+        try {
+            final LocaleList ll = new LocaleList(null, LocaleList.getEmptyLocaleList());
+            fail("Constructing with locale and locale list should throw with a null locale.");
+        } catch (Throwable e) {
+            assertEquals(NullPointerException.class, e.getClass());
+        }
+    }
+
+    @SmallTest
+    public void testGetDefault_localeSetDefaultCalledButNoChangeNecessary() throws Exception {
+        final Locale originalLocale = Locale.getDefault();
+        final LocaleList originalLocaleList = LocaleList.getDefault();
+        final int originalLocaleIndex = originalLocaleList.indexOf(originalLocale);
+
+        // This simulates a situation potentially set by the system processes
+        LocaleList.setDefault(LocaleList.forLanguageTags("ae,en,ja"), 1 /* en */);
+
+        // check our assumptions about input
+        assertEquals("en", Locale.getDefault().toLanguageTag());
+        final LocaleList firstResult = LocaleList.getDefault();
+        assertEquals("ae,en,ja", LocaleList.getDefault().toLanguageTags());
+
+        Locale.setDefault(Locale.forLanguageTag("ae"));
+        assertSame(firstResult, LocaleList.getDefault());
+
+        // restore the original values
+        LocaleList.setDefault(originalLocaleList, originalLocaleIndex);
+    }
+}
diff --git a/core/tests/coretests/src/android/util/PatternsTest.java b/core/tests/coretests/src/android/util/PatternsTest.java
index 253eb25..d383775 100644
--- a/core/tests/coretests/src/android/util/PatternsTest.java
+++ b/core/tests/coretests/src/android/util/PatternsTest.java
@@ -17,14 +17,16 @@
 
 import android.test.suitebuilder.annotation.SmallTest;
 import android.test.suitebuilder.annotation.Suppress;
-import android.util.Patterns;
 
 import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import junit.framework.TestCase;
 
 public class PatternsTest extends TestCase {
 
+    //Tests for Patterns.TOP_LEVEL_DOMAIN
+
     @SmallTest
     public void testTldPattern() throws Exception {
         boolean t;
@@ -40,7 +42,7 @@
         t = Patterns.TOP_LEVEL_DOMAIN.matcher("xn--0zwm56d").matches();
         assertTrue("Missed valid TLD", t);
 
-        // One of the new top level internationalized domain.
+        // One of the new top level unicode domain.
         t = Patterns.TOP_LEVEL_DOMAIN.matcher("\uD55C\uAD6D").matches();
         assertTrue("Missed valid TLD", t);
 
@@ -54,60 +56,372 @@
         assertFalse("Matched invalid TLD!", t);
     }
 
+    //Tests for Patterns.IANA_TOP_LEVEL_DOMAINS
+
     @SmallTest
-    @Suppress // Failing.
-    public void testUrlPattern() throws Exception {
-        boolean t;
-
-        t = Patterns.WEB_URL.matcher("http://www.google.com").matches();
-        assertTrue("Valid URL", t);
-
-        // Google in one of the new top level domain.
-        t = Patterns.WEB_URL.matcher("http://www.google.me").matches();
-        assertTrue("Valid URL", t);
-        t = Patterns.WEB_URL.matcher("google.me").matches();
-        assertTrue("Valid URL", t);
-
-        // Test url in Chinese: http://xn--fsqu00a.xn--0zwm56d
-        t = Patterns.WEB_URL.matcher("http://xn--fsqu00a.xn--0zwm56d").matches();
-        assertTrue("Valid URL", t);
-        t = Patterns.WEB_URL.matcher("xn--fsqu00a.xn--0zwm56d").matches();
-        assertTrue("Valid URL", t);
-
-        // Url for testing top level Arabic country code domain in Punycode:
-        //   http://xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx
-        t = Patterns.WEB_URL.matcher("http://xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx").matches();
-        assertTrue("Valid URL", t);
-        t = Patterns.WEB_URL.matcher("xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx").matches();
-        assertTrue("Valid URL", t);
-
-        // Internationalized URL.
-        t = Patterns.WEB_URL.matcher("http://\uD604\uAE08\uC601\uC218\uC99D.kr").matches();
-        assertTrue("Valid URL", t);
-        t = Patterns.WEB_URL.matcher("\uD604\uAE08\uC601\uC218\uC99D.kr").matches();
-        assertTrue("Valid URL", t);
-        // URL with international TLD.
-        t = Patterns.WEB_URL.matcher("\uB3C4\uBA54\uC778.\uD55C\uAD6D").matches();
-        assertTrue("Valid URL", t);
-
-        t = Patterns.WEB_URL.matcher("http://brainstormtech.blogs.fortune.cnn.com/2010/03/11/" +
-            "top-five-moments-from-eric-schmidt\u2019s-talk-in-abu-dhabi/").matches();
-        assertTrue("Valid URL", t);
-
-        t = Patterns.WEB_URL.matcher("ftp://www.example.com").matches();
-        assertFalse("Matched invalid protocol", t);
-
-        t = Patterns.WEB_URL.matcher("http://www.example.com:8080").matches();
-        assertTrue("Didn't match valid URL with port", t);
-
-        t = Patterns.WEB_URL.matcher("http://www.example.com:8080/?foo=bar").matches();
-        assertTrue("Didn't match valid URL with port and query args", t);
-
-        t = Patterns.WEB_URL.matcher("http://www.example.com:8080/~user/?foo=bar").matches();
-        assertTrue("Didn't match valid URL with ~", t);
+    public void testIanaTopLevelDomains_matchesValidTld() throws Exception {
+        Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
+        assertTrue("Should match 'com'", pattern.matcher("com").matches());
     }
 
     @SmallTest
+    public void testIanaTopLevelDomains_matchesValidNewTld() throws Exception {
+        Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
+        assertTrue("Should match 'me'", pattern.matcher("me").matches());
+    }
+
+    @SmallTest
+    public void testIanaTopLevelDomains_matchesPunycodeTld() throws Exception {
+        Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
+        assertTrue("Should match Punycode TLD", pattern.matcher("xn--qxam").matches());
+    }
+
+    @SmallTest
+    public void testIanaTopLevelDomains_matchesIriTLD() throws Exception {
+        Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
+        assertTrue("Should match IRI TLD", pattern.matcher("\uD55C\uAD6D").matches());
+    }
+
+    @SmallTest
+    public void testIanaTopLevelDomains_doesNotMatchWrongTld() throws Exception {
+        Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
+        assertFalse("Should not match 'mem'", pattern.matcher("mem").matches());
+    }
+
+    @SmallTest
+    public void testIanaTopLevelDomains_doesNotMatchWrongPunycodeTld() throws Exception {
+        Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
+        assertFalse("Should not match invalid Punycode TLD", pattern.matcher("xn").matches());
+    }
+
+    //Tests for Patterns.WEB_URL
+
+    @SmallTest
+    public void testWebUrl_matchesValidUrlWithSchemeAndHostname() throws Exception {
+        String url = "http://www.android.com";
+        assertTrue("Should match URL with scheme and hostname",
+                Patterns.WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testWebUrl_matchesValidUrlWithSchemeHostnameAndNewTld() throws Exception {
+        String url = "http://www.android.me";
+        assertTrue("Should match URL with scheme, hostname and new TLD",
+                Patterns.WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testWebUrl_matchesValidUrlWithHostnameAndNewTld() throws Exception {
+        String url = "android.me";
+        assertTrue("Should match URL with hostname and new TLD",
+                Patterns.WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testWebUrl_matchesChinesePunycodeUrlWithProtocol() throws Exception {
+        String url = "http://xn--fsqu00a.xn--0zwm56d";
+        assertTrue("Should match Chinese Punycode URL with protocol",
+                Patterns.WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testWebUrl_matchesChinesePunycodeUrlWithoutProtocol() throws Exception {
+        String url = "xn--fsqu00a.xn--0zwm56d";
+        assertTrue("Should match Chinese Punycode URL without protocol",
+                Patterns.WEB_URL.matcher(url).matches());
+    }
+
+
+    @SmallTest
+    public void testWebUrl_matchesArabicPunycodeUrlWithProtocol() throws Exception {
+        String url = "http://xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx";
+        assertTrue("Should match arabic Punycode URL with protocol",
+                Patterns.WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testWebUrl_matchesArabicPunycodeUrlWithoutProtocol() throws Exception {
+        String url = "xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx";
+        assertTrue("Should match Arabic Punycode URL without protocol",
+                Patterns.WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testWebUrl_matchesUrlWithUnicodeDomainNameWithProtocol() throws Exception {
+        String url = "http://\uD604\uAE08\uC601\uC218\uC99D.kr";
+        assertTrue("Should match URL with Unicode domain name",
+                Patterns.WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testWebUrl_matchesUrlWithUnicodeDomainNameWithoutProtocol() throws Exception {
+        String url = "\uD604\uAE08\uC601\uC218\uC99D.kr";
+        assertTrue("Should match URL without protocol and with Unicode domain name",
+                Patterns.WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testWebUrl_matchesUrlWithUnicodeTld() throws Exception {
+        String url = "\uB3C4\uBA54\uC778.\uD55C\uAD6D";
+        assertTrue("Should match URL with Unicode TLD",
+                Patterns.WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testWebUrl_matchesUrlWithUnicodePath() throws Exception {
+        String url = "http://brainstormtech.blogs.fortune.cnn.com/2010/03/11/" +
+                "top-five-moments-from-eric-schmidt\u2019s-talk-in-abu-dhabi/";
+        assertTrue("Should match URL with Unicode path",
+                Patterns.WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testWebUrl_doesNotMatchValidUrlWithInvalidProtocol() throws Exception {
+        String url = "ftp://www.example.com";
+        assertFalse("Should not match URL with invalid protocol",
+                Patterns.WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testWebUrl_matchesValidUrlWithPort() throws Exception {
+        String url = "http://www.example.com:8080";
+        assertTrue("Should match URL with port", Patterns.WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testWebUrl_matchesUrlWithPortAndQuery() throws Exception {
+        String url = "http://www.example.com:8080/?foo=bar";
+        assertTrue("Should match URL with port and query",
+                Patterns.WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testWebUrl_matchesUrlWithTilde() throws Exception {
+        String url = "http://www.example.com:8080/~user/?foo=bar";
+        assertTrue("Should match URL with tilde", Patterns.WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testWebUrl_matchesProtocolCaseInsensitive() throws Exception {
+        String url = "hTtP://android.com";
+        assertTrue("Protocol matching should be case insensitive",
+                Patterns.WEB_URL.matcher(url).matches());
+    }
+
+    //Tests for Patterns.AUTOLINK_WEB_URL
+
+    @SmallTest
+    public void testAutoLinkWebUrl_matchesValidUrlWithSchemeAndHostname() throws Exception {
+        String url = "http://www.android.com";
+        assertTrue("Should match URL with scheme and hostname",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_matchesValidUrlWithSchemeHostnameAndNewTld() throws Exception {
+        String url = "http://www.android.me";
+        assertTrue("Should match URL with scheme, hostname and new TLD",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_matchesValidUrlWithHostnameAndNewTld() throws Exception {
+        String url = "android.me";
+        assertTrue("Should match URL with hostname and new TLD",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+
+        url = "android.camera";
+        assertTrue("Should match URL with hostname and new TLD",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_matchesChinesePunycodeUrlWithProtocol() throws Exception {
+        String url = "http://xn--fsqu00a.xn--0zwm56d";
+        assertTrue("Should match Chinese Punycode URL with protocol",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_matchesChinesePunycodeUrlWithoutProtocol() throws Exception {
+        String url = "xn--fsqu00a.xn--0zwm56d";
+        assertTrue("Should match Chinese Punycode URL without protocol",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_matchesArabicPunycodeUrlWithProtocol() throws Exception {
+        String url = "http://xn--4gbrim.xn--rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx";
+        assertTrue("Should match Arabic Punycode URL with protocol",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_matchesArabicPunycodeUrlWithoutProtocol() throws Exception {
+        String url = "xn--4gbrim.xn--rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx";
+        assertTrue("Should match Arabic Punycode URL without protocol",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_doesNotMatchPunycodeTldThatStartsWithDash() throws Exception {
+        String url = "http://xn--fsqu00a.-xn--0zwm56d";
+        assertFalse("Should not match Punycode TLD that starts with dash",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_doesNotMatchPunycodeTldThatEndsWithDash() throws Exception {
+        String url = "http://xn--fsqu00a.xn--0zwm56d-";
+        assertFalse("Should not match Punycode TLD that ends with dash",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_matchesUrlWithUnicodeDomainName() throws Exception {
+        String url = "http://\uD604\uAE08\uC601\uC218\uC99D.kr";
+        assertTrue("Should match URL with Unicode domain name",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+
+        url = "\uD604\uAE08\uC601\uC218\uC99D.kr";
+        assertTrue("hould match URL without protocol and with Unicode domain name",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_matchesUrlWithUnicodeTld() throws Exception {
+        String url = "\uB3C4\uBA54\uC778.\uD55C\uAD6D";
+        assertTrue("Should match URL with Unicode TLD",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_matchesUrlWithUnicodePath() throws Exception {
+        String url = "http://brainstormtech.blogs.fortune.cnn.com/2010/03/11/" +
+                "top-five-moments-from-eric-schmidt\u2019s-talk-in-abu-dhabi/";
+        assertTrue("Should match URL with Unicode path",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_doesNotMatchValidUrlWithInvalidProtocol() throws Exception {
+        String url = "ftp://www.example.com";
+        assertFalse("Should not match URL with invalid protocol",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_matchesValidUrlWithPort() throws Exception {
+        String url = "http://www.example.com:8080";
+        assertTrue("Should match URL with port",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_matchesUrlWithPortAndQuery() throws Exception {
+        String url = "http://www.example.com:8080/?foo=bar";
+        assertTrue("Should match URL with port and query",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_matchesUrlWithTilde() throws Exception {
+        String url = "http://www.example.com:8080/~user/?foo=bar";
+        assertTrue("Should match URL with tilde",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_matchesProtocolCaseInsensitive() throws Exception {
+        String url = "hTtP://android.com";
+        assertTrue("Protocol matching should be case insensitive",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_matchesUrlStartingWithHttpAndDoesNotHaveTld() throws Exception {
+        String url = "http://android/#notld///a/n/d/r/o/i/d&p1=1&p2=2";
+        assertTrue("Should match URL without a TLD and starting with http ",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_doesNotMatchUrlsWithoutProtocolAndWithUnknownTld()
+            throws Exception {
+        String url = "thank.you";
+        assertFalse("Should not match URL that does not start with a protocol and " +
+                "does not contain a known TLD",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_doesNotMatchUrlWithInvalidRequestParameter() throws Exception {
+        String url = "http://android.com?p=value";
+        assertFalse("Should not match URL with invalid request parameter",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_doesNotPartiallyMatchUnknownProtocol() throws Exception {
+        String url = "ftp://foo.bar/baz";
+        assertFalse("Should not partially match URL with unknown protocol",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).find());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_matchesValidUrlWithEmoji() throws Exception {
+        String url = "Thank\u263A.com";
+        assertTrue("Should match URL with emoji",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_doesNotMatchUrlsWithEmojiWithoutProtocolAndWithoutKnownTld()
+            throws Exception {
+        String url = "Thank\u263A.you";
+        assertFalse("Should not match URLs containing emoji and with unknown TLD",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_doesNotMatchEmailAddress()
+            throws Exception {
+        String url = "android@android.com";
+        assertFalse("Should not match email address",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_matchesDomainNameWithSurrogatePairs() throws Exception {
+        String url = "android\uD83C\uDF38.com";
+        assertTrue("Should match domain name with Unicode surrogate pairs",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_matchesTldWithSurrogatePairs() throws Exception {
+        String url = "http://android.\uD83C\uDF38com";
+        assertTrue("Should match TLD with Unicode surrogate pairs",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_matchesPathWithSurrogatePairs() throws Exception {
+        String url = "http://android.com/path-with-\uD83C\uDF38?v=\uD83C\uDF38";
+        assertTrue("Should match path and query with Unicode surrogate pairs",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    @SmallTest
+    public void testAutoLinkWebUrl_doesNotMatchUrlWithExcludedSurrogate() throws Exception {
+        String url = "http://android\uD83F\uDFFE.com";
+        assertFalse("Should not match URL with excluded Unicode surrogate pair",
+                Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+    }
+
+    //Tests for Patterns.IP_ADDRESS
+
+    @SmallTest
     public void testIpPattern() throws Exception {
         boolean t;
 
@@ -118,34 +432,85 @@
         assertFalse("Invalid IP", t);
     }
 
+    //Tests for Patterns.DOMAIN_NAME
+
     @SmallTest
-    @Suppress // Failing.
-    public void testDomainPattern() throws Exception {
-        boolean t;
-
-        t = Patterns.DOMAIN_NAME.matcher("mail.example.com").matches();
-        assertTrue("Valid domain", t);
-
-        t = Patterns.DOMAIN_NAME.matcher("google.me").matches();
-        assertTrue("Valid domain", t);
-
-        // Internationalized domains.
-        t = Patterns.DOMAIN_NAME.matcher("\uD604\uAE08\uC601\uC218\uC99D.kr").matches();
-        assertTrue("Valid domain", t);
-
-        t = Patterns.DOMAIN_NAME.matcher("__+&42.xer").matches();
-        assertFalse("Invalid domain", t);
-
-        // Obsolete domain .yu
-        t = Patterns.DOMAIN_NAME.matcher("test.yu").matches();
-        assertFalse("Obsolete country code top level domain", t);
-
-        // Testing top level Arabic country code domain in Punycode:
-        t = Patterns.DOMAIN_NAME.matcher("xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c").matches();
-        assertTrue("Valid domain", t);
+    public void testDomain_matchesPunycodeTld() throws Exception {
+        String domain = "xn--fsqu00a.xn--0zwm56d";
+        assertTrue("Should match domain name in Punycode",
+                Patterns.DOMAIN_NAME.matcher(domain).matches());
     }
 
     @SmallTest
+    public void testDomain_doesNotMatchPunycodeThatStartsWithDash() throws Exception {
+        String domain = "xn--fsqu00a.-xn--0zwm56d";
+        assertFalse("Should not match Punycode TLD that starts with a dash",
+                Patterns.DOMAIN_NAME.matcher(domain).matches());
+    }
+
+    @SmallTest
+    public void testDomain_doesNotMatchPunycodeThatEndsWithDash() throws Exception {
+        String domain = "xn--fsqu00a.xn--0zwm56d-";
+        assertFalse("Should not match Punycode TLD that ends with a dash",
+                Patterns.DOMAIN_NAME.matcher(domain).matches());
+    }
+
+    @SmallTest
+    public void testDomain_doesNotMatchPunycodeLongerThanAllowed() throws Exception {
+        String tld = "xn--";
+        for(int i=0; i<=6; i++) {
+            tld += "0123456789";
+        }
+        String domain = "xn--fsqu00a." + tld;
+        assertFalse("Should not match Punycode TLD that is longer than 63 chars",
+                Patterns.DOMAIN_NAME.matcher(domain).matches());
+    }
+
+    @SmallTest
+    public void testDomain_matchesObsoleteTld() throws Exception {
+        String domain = "test.yu";
+        assertTrue("Should match domain names with obsolete TLD",
+                Patterns.DOMAIN_NAME.matcher(domain).matches());
+    }
+
+    @SmallTest
+    public void testDomain_matchesWithSubDomain() throws Exception {
+        String domain = "mail.example.com";
+        assertTrue("Should match domain names with subdomains",
+                Patterns.DOMAIN_NAME.matcher(domain).matches());
+    }
+
+    @SmallTest
+    public void testDomain_matchesWithoutSubDomain() throws Exception {
+        String domain = "android.me";
+        assertTrue("Should match domain names without subdomains",
+                Patterns.DOMAIN_NAME.matcher(domain).matches());
+    }
+
+    @SmallTest
+    public void testDomain_matchesUnicodeDomainNames() throws Exception {
+        String domain = "\uD604\uAE08\uC601\uC218\uC99D.kr";
+        assertTrue("Should match unicodedomain names",
+                Patterns.DOMAIN_NAME.matcher(domain).matches());
+    }
+
+    @SmallTest
+    public void testDomain_doesNotMatchInvalidDomain() throws Exception {
+        String domain = "__+&42.xer";
+        assertFalse("Should not match invalid domain name",
+                Patterns.DOMAIN_NAME.matcher(domain).matches());
+    }
+
+    @SmallTest
+    public void testDomain_matchesPunycodeArabicDomainName() throws Exception {
+        String domain = "xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c";
+        assertTrue("Should match Punycode Arabic domain name",
+                Patterns.DOMAIN_NAME.matcher(domain).matches());
+    }
+
+    //Tests for Patterns.PHONE
+
+    @SmallTest
     public void testPhonePattern() throws Exception {
         boolean t;
 
diff --git a/core/tests/coretests/src/android/widget/DatePickerActivity.java b/core/tests/coretests/src/android/widget/DatePickerActivity.java
new file mode 100644
index 0000000..c3b25a1
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/DatePickerActivity.java
@@ -0,0 +1,32 @@
+/*
+ * 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.widget;
+
+import android.app.Activity;
+import android.os.Bundle;
+import com.android.frameworks.coretests.R;
+
+/**
+ * A minimal application for DatePickerFocusTest.
+ */
+public class DatePickerActivity extends Activity {
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.datepicker_layout);
+    }
+}
diff --git a/core/tests/coretests/src/android/widget/DatePickerFocusTest.java b/core/tests/coretests/src/android/widget/DatePickerFocusTest.java
new file mode 100644
index 0000000..513e40f
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/DatePickerFocusTest.java
@@ -0,0 +1,250 @@
+/*
+ * 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.widget;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.os.SystemClock;
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.KeyEvent;
+import android.view.View;
+
+import com.android.frameworks.coretests.R;
+
+/**
+ * Test {@link DatePicker} focus changes.
+ */
+public class DatePickerFocusTest extends ActivityInstrumentationTestCase2<DatePickerActivity> {
+
+    private Activity mActivity;
+    private Instrumentation mInstrumentation;
+    private DatePicker mDatePicker;
+
+    public DatePickerFocusTest() {
+        super(DatePickerActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mInstrumentation = getInstrumentation();
+
+        mDatePicker = (DatePicker) mActivity.findViewById(R.id.datePicker);
+    }
+
+    /**
+     * Tabs (forward and backward) through the DatePicker to ensure the correct
+     * Views gain focus.
+     */
+    public void testFocusTravel() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(mDatePicker.requestFocus());
+            }
+        });
+        assertViewHasFocus(com.android.internal.R.id.date_picker_header_year);
+        sendKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(com.android.internal.R.id.prev);
+        sendKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(com.android.internal.R.id.next);
+        sendKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
+        sendKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(R.id.belowPicker);
+        sendShiftKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
+        sendShiftKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(com.android.internal.R.id.next);
+        sendShiftKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(com.android.internal.R.id.prev);
+        sendShiftKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(com.android.internal.R.id.date_picker_header_year);
+    }
+
+    private void sendKey(int keycode) {
+        mInstrumentation.sendKeyDownUpSync(keycode);
+        mInstrumentation.waitForIdleSync();
+    }
+
+    private void assertViewHasFocus(final int id) throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                View view = mActivity.findViewById(id);
+                assertTrue(view.hasFocus());
+            }
+        });
+    }
+
+    private void sendShiftKey(int keycode) {
+        final KeyEvent shiftDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SHIFT_LEFT);
+        mInstrumentation.sendKeySync(shiftDown);
+
+        final KeyEvent keyDown = new KeyEvent(SystemClock.uptimeMillis(),
+                SystemClock.uptimeMillis(), KeyEvent.ACTION_DOWN, keycode, 0,
+                KeyEvent.META_SHIFT_ON);
+        mInstrumentation.sendKeySync(keyDown);
+
+        final KeyEvent keyUp = new KeyEvent(SystemClock.uptimeMillis(),
+                SystemClock.uptimeMillis(), KeyEvent.ACTION_UP, keycode, 0,
+                KeyEvent.META_SHIFT_ON);
+        mInstrumentation.sendKeySync(keyUp);
+
+        final KeyEvent shiftUp = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SHIFT_LEFT);
+        mInstrumentation.sendKeySync(shiftUp);
+
+        mInstrumentation.waitForIdleSync();
+    }
+
+    /**
+     * Tests to ensure the keyboard can select the current year.
+     */
+    public void testYearChoice() throws Throwable {
+        setKnownDate();
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                View year = mDatePicker.
+                        findViewById(com.android.internal.R.id.date_picker_header_year);
+                assertTrue(year.requestFocus());
+            }
+        });
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                View yearSelect = mDatePicker.
+                        findViewById(com.android.internal.R.id.date_picker_year_picker);
+                assertEquals(yearSelect, mDatePicker.findFocus());
+            }
+        });
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                View yearSelect = mDatePicker.
+                        findViewById(com.android.internal.R.id.date_picker_year_picker);
+                assertNotSame(View.VISIBLE, yearSelect.getVisibility());
+                View year = mDatePicker.
+                        findViewById(com.android.internal.R.id.date_picker_header_year);
+                assertTrue(year.hasFocus());
+                assertEquals(2014, mDatePicker.getYear());
+            }
+        });
+    }
+
+    public void testArrowThroughDays() throws Throwable {
+        setKnownDate();
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                View prev = mDatePicker.findViewById(com.android.internal.R.id.next);
+                prev.requestFocus();
+            }
+        });
+        sendKey(KeyEvent.KEYCODE_TAB);
+        // Should select the current date and the date shouldn't change
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(12, 31, 2015);
+        // Move right to January 24, 2016
+        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(1, 24, 2016);
+        // Move down to January 31, 2016
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(1, 31, 2016);
+        // Move up to January 5, 2016
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(1, 5, 2016);
+        // Move up to prev arrow key
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        assertViewHasFocus(com.android.internal.R.id.prev);
+        // tab back into the day-selection pager
+        sendKey(KeyEvent.KEYCODE_TAB);
+        sendKey(KeyEvent.KEYCODE_TAB);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
+        assertDateIs(1, 5, 2016);
+
+        // Move up out again, then down back into the day-selection pager.
+        // It should land right below the prev button (1/3/2016)
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
+        assertDateIs(1, 3, 2016);
+
+        // Move left to previous month (12/12/2015)
+        sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(12, 12, 2015);
+        // Now make sure the start of the month works
+        // Move up to 12/5/2015 and right to 1/1/2016
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(1, 1, 2016);
+        // Now make sure the left key goes back to previous month (12/5/2015)
+        sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(12, 5, 2015);
+        // Now go to a mismatched row (no such row on previous month)
+        // This moves over to 1/31/2016 and then left to 12/31/2015
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(12, 31, 2015);
+    }
+
+    private void assertDateIs(int month, final int day, final int year) throws Throwable {
+        final int monthInt = month - 1; // months are 0-based
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertEquals(day, mDatePicker.getDayOfMonth());
+                assertEquals(year, mDatePicker.getYear());
+                assertEquals(monthInt, mDatePicker.getMonth());
+            }
+        });
+    }
+
+    private void setKnownDate() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mDatePicker.updateDate(2015, 11, 31); // December 31, 2015
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+}
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
index 83a9e01..00df87d 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
@@ -26,19 +26,26 @@
 import static android.widget.espresso.TextViewActions.mouseLongClickAndDragOnText;
 import static android.widget.espresso.TextViewActions.mouseTripleClickAndDragOnText;
 import static android.widget.espresso.TextViewActions.mouseTripleClickOnTextAtIndex;
+import static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex;
 import static android.widget.espresso.TextViewAssertions.hasSelection;
+
 import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.Espresso.pressBack;
 import static android.support.test.espresso.action.ViewActions.click;
 import static android.support.test.espresso.action.ViewActions.replaceText;
 import static android.support.test.espresso.action.ViewActions.typeTextIntoFocusedView;
 import static android.support.test.espresso.assertion.ViewAssertions.matches;
 import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
 import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
 
 import com.android.frameworks.coretests.R;
 
+import android.support.test.espresso.Espresso;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.view.MotionEvent;
+import android.widget.espresso.ContextMenuUtils;
 
 /**
  * Tests mouse interaction of the TextView widget from an Activity
@@ -49,10 +56,13 @@
         super(TextViewActivity.class);
     }
 
+    @Override
+    public void setUp() {
+        getActivity();
+    }
+
     @SmallTest
     public void testSelectTextByDrag() throws Exception {
-        getActivity();
-
         final String helloWorld = "Hello world!";
         onView(withId(R.id.textview)).perform(click());
         onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
@@ -77,8 +87,6 @@
 
     @SmallTest
     public void testSelectTextByDrag_reverse() throws Exception {
-        getActivity();
-
         final String helloWorld = "Hello world!";
         onView(withId(R.id.textview)).perform(click());
         onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
@@ -89,9 +97,90 @@
     }
 
     @SmallTest
-    public void testSelectTextByLongClick() throws Exception {
-        getActivity();
+    public void testContextMenu() throws Exception {
+        final String text = "abc def ghi.";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
 
+        ContextMenuUtils.assertContextMenuIsNotDisplayed();
+
+        onView(withId(R.id.textview)).perform(
+                mouseClickOnTextAtIndex(text.indexOf("d"), MotionEvent.BUTTON_SECONDARY));
+
+        ContextMenuUtils.assertContextMenuContainsItemDisabled(
+                getActivity().getString(com.android.internal.R.string.copy));
+        ContextMenuUtils.assertContextMenuContainsItemEnabled(
+                getActivity().getString(com.android.internal.R.string.undo));
+
+        // Hide context menu.
+        pressBack();
+        ContextMenuUtils.assertContextMenuIsNotDisplayed();
+
+        onView(withId(R.id.textview)).perform(
+                mouseDragOnText(text.indexOf("c"), text.indexOf("h")));
+        onView(withId(R.id.textview)).perform(
+                mouseClickOnTextAtIndex(text.indexOf("d"), MotionEvent.BUTTON_SECONDARY));
+
+        ContextMenuUtils.assertContextMenuContainsItemEnabled(
+                getActivity().getString(com.android.internal.R.string.copy));
+        ContextMenuUtils.assertContextMenuContainsItemEnabled(
+                getActivity().getString(com.android.internal.R.string.undo));
+
+        // Hide context menu.
+        pressBack();
+
+        onView(withId(R.id.textview)).check(hasSelection("c def g"));
+
+        onView(withId(R.id.textview)).perform(
+                mouseClickOnTextAtIndex(text.indexOf("i"), MotionEvent.BUTTON_SECONDARY));
+        ContextMenuUtils.assertContextMenuContainsItemDisabled(
+                getActivity().getString(com.android.internal.R.string.copy));
+        ContextMenuUtils.assertContextMenuContainsItemEnabled(
+                getActivity().getString(com.android.internal.R.string.undo));
+
+        // Hide context menu.
+        pressBack();
+
+        onView(withId(R.id.textview)).check(hasSelection(""));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("i")));
+    }
+
+    @SmallTest
+    public void testDragAndDrop() throws Exception {
+        final String text = "abc def ghi.";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+        onView(withId(R.id.textview)).perform(
+                mouseDragOnText(text.indexOf("d"), text.indexOf("f") + 1));
+
+        onView(withId(R.id.textview)).perform(
+                mouseDragOnText(text.indexOf("e"), text.length()));
+
+        onView(withId(R.id.textview)).check(matches(withText("abc ghi.def")));
+        onView(withId(R.id.textview)).check(hasSelection(""));
+        assertNoSelectionHandles();
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex("abc ghi.def".length()));
+    }
+
+    @SmallTest
+    public void testDragAndDrop_longClick() throws Exception {
+        final String text = "abc def ghi.";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+        onView(withId(R.id.textview)).perform(
+                mouseDragOnText(text.indexOf("d"), text.indexOf("f") + 1));
+
+        onView(withId(R.id.textview)).perform(
+                mouseLongClickAndDragOnText(text.indexOf("e"), text.length()));
+
+        onView(withId(R.id.textview)).check(matches(withText("abc ghi.def")));
+        onView(withId(R.id.textview)).check(hasSelection(""));
+        assertNoSelectionHandles();
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex("abc ghi.def".length()));
+    }
+
+    @SmallTest
+    public void testSelectTextByLongClick() throws Exception {
         final String helloWorld = "Hello world!";
         onView(withId(R.id.textview)).perform(click());
         onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
@@ -117,8 +206,6 @@
 
     @SmallTest
     public void testSelectTextByDoubleClick() throws Exception {
-        getActivity();
-
         final String helloWorld = "Hello world!";
         onView(withId(R.id.textview)).perform(click());
         onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
@@ -144,8 +231,6 @@
 
     @SmallTest
     public void testSelectTextByDoubleClickAndDrag() throws Exception {
-        getActivity();
-
         final String text = "abcd efg hijk lmn";
         onView(withId(R.id.textview)).perform(click());
         onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
@@ -157,8 +242,6 @@
 
     @SmallTest
     public void testSelectTextByDoubleClickAndDrag_reverse() throws Exception {
-        getActivity();
-
         final String text = "abcd efg hijk lmn";
         onView(withId(R.id.textview)).perform(click());
         onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
@@ -170,8 +253,6 @@
 
     @SmallTest
     public void testSelectTextByLongPressAndDrag() throws Exception {
-        getActivity();
-
         final String text = "abcd efg hijk lmn";
         onView(withId(R.id.textview)).perform(click());
         onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
@@ -183,8 +264,6 @@
 
     @SmallTest
     public void testSelectTextByLongPressAndDrag_reverse() throws Exception {
-        getActivity();
-
         final String text = "abcd efg hijk lmn";
         onView(withId(R.id.textview)).perform(click());
         onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
@@ -196,8 +275,6 @@
 
     @SmallTest
     public void testSelectTextByTripleClick() throws Exception {
-        getActivity();
-
         final StringBuilder builder = new StringBuilder();
         builder.append("First paragraph.\n");
         builder.append("Second paragraph.");
@@ -232,8 +309,6 @@
 
     @SmallTest
     public void testSelectTextByTripleClickAndDrag() throws Exception {
-        getActivity();
-
         final StringBuilder builder = new StringBuilder();
         builder.append("First paragraph.\n");
         builder.append("Second paragraph.");
@@ -263,8 +338,6 @@
 
     @SmallTest
     public void testSelectTextByTripleClickAndDrag_reverse() throws Exception {
-        getActivity();
-
         final StringBuilder builder = new StringBuilder();
         builder.append("First paragraph.\n");
         builder.append("Second paragraph.");
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index e54723e..5dae4a8 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -48,6 +48,9 @@
 import android.test.suitebuilder.annotation.SmallTest;
 import android.view.KeyEvent;
 
+import static org.hamcrest.Matchers.anyOf;
+import static org.hamcrest.Matchers.is;
+
 /**
  * Tests the TextView widget from an Activity
  */
@@ -84,6 +87,43 @@
     }
 
     @SmallTest
+    public void testPositionCursorAtTextAtIndex_arabic() throws Exception {
+        // Arabic text. The expected cursorable boundary is
+        // | \u0623 \u064F | \u067A | \u0633 \u0652 |
+        final String text = "\u0623\u064F\u067A\u0633\u0652";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(replaceText(text));
+
+        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(0));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
+        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(1));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(anyOf(is(0), is(2))));
+        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(2));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(2));
+        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(3));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(3));
+        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(4));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(anyOf(is(3), is(5))));
+        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(5));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(5));
+    }
+
+    @SmallTest
+    public void testPositionCursorAtTextAtIndex_devanagari() throws Exception {
+        // Devanagari text. The expected cursorable boundary is | \u0915 \u093E |
+        final String text = "\u0915\u093E";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(replaceText(text));
+
+        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(0));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
+        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(1));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(anyOf(is(0), is(2))));
+        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(2));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(2));
+    }
+
+    @SmallTest
     public void testLongPressToSelect() throws Exception {
         final String helloWorld = "Hello Kirk!";
         onView(withId(R.id.textview)).perform(click());
@@ -119,6 +159,22 @@
     }
 
     @SmallTest
+    public void testDragAndDrop() throws Exception {
+        final String text = "abc def ghi.";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf("e")));
+
+        onView(withId(R.id.textview)).perform(
+                longPressAndDragOnText(text.indexOf("e"), text.length()));
+
+        onView(withId(R.id.textview)).check(matches(withText("abc ghi.def")));
+        onView(withId(R.id.textview)).check(hasSelection(""));
+        assertNoSelectionHandles();
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex("abc ghi.def".length()));
+    }
+
+    @SmallTest
     public void testDoubleTapToSelect() throws Exception {
         final String helloWorld = "Hello SuetYi!";
         onView(withId(R.id.textview)).perform(click());
diff --git a/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java b/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java
new file mode 100644
index 0000000..c8218aa
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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 static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
+import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
+import static android.support.test.espresso.matcher.ViewMatchers.hasFocus;
+import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.isEnabled;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.not;
+
+import com.android.internal.view.menu.ListMenuItemView;
+
+import android.support.test.espresso.NoMatchingRootException;
+import android.support.test.espresso.NoMatchingViewException;
+import android.support.test.espresso.ViewInteraction;
+import android.support.test.espresso.matcher.ViewMatchers;
+import android.widget.MenuPopupWindow.MenuDropDownListView;
+
+/**
+ * Espresso utility methods for the context menu.
+ */
+public final class ContextMenuUtils {
+    private ContextMenuUtils() {}
+
+    private static ViewInteraction onContextMenu() {
+        // TODO: Have more reliable way to get context menu.
+        return onView(ViewMatchers.isAssignableFrom(MenuDropDownListView.class))
+                .inRoot(withDecorView(hasFocus()));
+    }
+
+    /**
+     * Asserts that the context menu is displayed
+     *
+     * @throws AssertionError if the assertion fails
+     */
+    private static void assertContextMenuIsDisplayed() {
+        onContextMenu().check(matches(isDisplayed()));
+    }
+
+    /**
+     * Asserts that the context menu is not displayed
+     *
+     * @throws AssertionError if the assertion fails
+     */
+    public static void assertContextMenuIsNotDisplayed() {
+        try {
+            assertContextMenuIsDisplayed();
+        } catch (NoMatchingRootException | NoMatchingViewException | AssertionError e) {
+            return;
+        }
+        throw new AssertionError("Context menu is displayed");
+    }
+
+    /**
+     * Asserts that the context menu contains the specified item and the item has specified enabled
+     *  state.
+     *
+     * @param itemLabel label of the item.
+     * @param enabled enabled state of the item.
+     * @throws AssertionError if the assertion fails
+     */
+    private static void asssertContextMenuContainsItemWithEnabledState(String itemLabel,
+            boolean enabled) {
+        onContextMenu().check(matches(
+                hasDescendant(allOf(
+                        isAssignableFrom(ListMenuItemView.class),
+                        enabled ? isEnabled() : not(isEnabled()),
+                        hasDescendant(withText(itemLabel))))));
+    }
+
+    /**
+     * Asserts that the context menu contains the specified item and the item is enabled.
+     *
+     * @param itemLabel label of the item.
+     * @throws AssertionError if the assertion fails
+     */
+    public static void assertContextMenuContainsItemEnabled(String itemLabel) {
+        asssertContextMenuContainsItemWithEnabledState(itemLabel, true);
+    }
+
+    /**
+     * Asserts that the context menu contains the specified item and the item is disabled.
+     *
+     * @param itemLabel label of the item.
+     * @throws AssertionError if the assertion fails
+     */
+    public static void assertContextMenuContainsItemDisabled(String itemLabel) {
+        asssertContextMenuContainsItemWithEnabledState(itemLabel, false);
+    }
+}
diff --git a/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java b/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
index e51f2785..b8ea2de 100644
--- a/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
+++ b/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
@@ -24,9 +24,9 @@
 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.PrecisionDescriber;
 import android.support.test.espresso.action.Press;
 import android.support.test.espresso.action.Tapper;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
 
@@ -35,6 +35,8 @@
  */
 public final class MouseClickAction implements ViewAction {
     private final GeneralClickAction mGeneralClickAction;
+    @MouseUiController.MouseButton
+    private final int mButton;
 
     public enum CLICK implements Tapper {
         TRIPLE {
@@ -86,8 +88,20 @@
     };
 
     public MouseClickAction(Tapper tapper, CoordinatesProvider coordinatesProvider) {
-        mGeneralClickAction = new GeneralClickAction(tapper, coordinatesProvider,
-                Press.PINPOINT);
+        this(tapper, coordinatesProvider, MotionEvent.BUTTON_PRIMARY);
+    }
+
+    /**
+     * Constructs MouseClickAction
+     *
+     * @param tapper the tapper
+     * @param coordinatesProvider the provider of the event coordinates
+     * @param button the mouse button used to send motion events
+     */
+    public MouseClickAction(Tapper tapper, CoordinatesProvider coordinatesProvider,
+            @MouseUiController.MouseButton int button) {
+        mGeneralClickAction = new GeneralClickAction(tapper, coordinatesProvider, Press.PINPOINT);
+        mButton = button;
     }
 
     @Override
@@ -102,7 +116,7 @@
 
     @Override
     public void perform(UiController uiController, View view) {
-        mGeneralClickAction.perform(new MouseUiController(uiController), 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
diff --git a/core/tests/coretests/src/android/widget/espresso/MouseUiController.java b/core/tests/coretests/src/android/widget/espresso/MouseUiController.java
index f1387f8..022be76 100644
--- a/core/tests/coretests/src/android/widget/espresso/MouseUiController.java
+++ b/core/tests/coretests/src/android/widget/espresso/MouseUiController.java
@@ -16,6 +16,12 @@
 
 package android.widget.espresso;
 
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import android.annotation.IntDef;
 import android.support.test.espresso.InjectEventSecurityException;
 import android.support.test.espresso.UiController;
 import android.view.InputDevice;
@@ -26,11 +32,28 @@
  * Class to wrap an UiController to overwrite source of motion events to SOURCE_MOUSE.
  * Note that this doesn't change the tool type.
  */
-public class MouseUiController implements UiController {
+public final class MouseUiController implements UiController {
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({MotionEvent.BUTTON_PRIMARY, MotionEvent.BUTTON_SECONDARY, MotionEvent.BUTTON_TERTIARY})
+    public @interface MouseButton {}
+
     private final UiController mUiController;
+    @MouseButton
+    private final int mButton;
 
     public MouseUiController(UiController uiController) {
-        mUiController = uiController;
+        this(uiController, MotionEvent.BUTTON_PRIMARY);
+    }
+
+    /**
+     * Constructs MouseUiController.
+     *
+     * @param uiController the uiController to wrap
+     * @param button the button to be used for generating input events.
+     */
+    public MouseUiController(UiController uiController, @MouseButton int button) {
+        mUiController = checkNotNull(uiController);
+        mButton = button;
     }
 
     @Override
@@ -40,9 +63,11 @@
 
     @Override
     public boolean injectMotionEvent(MotionEvent event) throws InjectEventSecurityException {
-        // Modify the event to mimic mouse primary button event.
+        // Modify the event to mimic mouse event.
         event.setSource(InputDevice.SOURCE_MOUSE);
-        event.setButtonState(MotionEvent.BUTTON_PRIMARY);
+        if (event.getActionMasked() != MotionEvent.ACTION_UP) {
+            event.setButtonState(mButton);
+        }
         return mUiController.injectMotionEvent(event);
     }
 
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
index 54d5823..1dd6e17 100644
--- a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
@@ -26,6 +26,7 @@
 import android.support.test.espresso.action.Tap;
 import android.support.test.espresso.util.HumanReadables;
 import android.text.Layout;
+import android.view.MotionEvent;
 import android.view.View;
 import android.widget.Editor;
 import android.widget.TextView;
@@ -63,8 +64,24 @@
      * @param index The index of the TextView's text to click on.
      */
     public static ViewAction mouseClickOnTextAtIndex(int index) {
+        return mouseClickOnTextAtIndex(index, MotionEvent.BUTTON_PRIMARY);
+    }
+
+    /**
+     * Returns an action that clicks by mouse on text at an index on the TextView.<br>
+     * <br>
+     * View constraints:
+     * <ul>
+     * <li>must be a TextView displayed on screen
+     * <ul>
+     *
+     * @param index The index of the TextView's text to click on.
+     * @param button the mouse button to use.
+     */
+    public static ViewAction mouseClickOnTextAtIndex(int index,
+            @MouseUiController.MouseButton int button) {
         return actionWithAssertions(
-                new MouseClickAction(Tap.SINGLE, new TextCoordinates(index)));
+                new MouseClickAction(Tap.SINGLE, new TextCoordinates(index), button));
     }
 
     /**
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 d3dd01a..12a75b8 100644
--- a/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java
+++ b/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.net;
 
+import static android.net.NetworkStats.ROAMING_DEFAULT;
 import static android.net.NetworkStats.SET_ALL;
 import static android.net.NetworkStats.SET_DEFAULT;
 import static android.net.NetworkStats.SET_FOREGROUND;
@@ -156,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);
+        final int i = stats.findIndex(iface, uid, set, tag, ROAMING_DEFAULT);
         final NetworkStats.Entry entry = stats.getValues(i, null);
         assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
         assertEquals("unexpected txBytes", txBytes, entry.txBytes);
@@ -164,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);
+        final int i = stats.findIndex(iface, uid, set, tag, ROAMING_DEFAULT);
         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/policy/PhoneWindowActionModeTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
index 48590c1..1966313 100644
--- a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
@@ -22,6 +22,7 @@
 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;
@@ -32,6 +33,8 @@
 import android.view.WindowManager.LayoutParams;
 import android.view.accessibility.AccessibilityEvent;
 
+import java.util.List;
+
 /**
  * Tests {@link PhoneWindow}'s {@link ActionMode} related methods.
  */
@@ -288,6 +291,9 @@
 
         @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/LineBreakBufferedWriterTest.java b/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java
new file mode 100644
index 0000000..49ae104
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java
@@ -0,0 +1,223 @@
+/*
+ * 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.util;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Tests for {@link IndentingPrintWriter}.
+ */
+public class LineBreakBufferedWriterTest extends TestCase {
+
+    private ByteArrayOutputStream mStream;
+    private RecordingWriter mWriter;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mWriter = new RecordingWriter();
+    }
+
+    public void testLessThanBufferSize() {
+        final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 1000);
+
+        lw.println("Hello");
+        lw.println("World");
+        lw.println("Test");
+        lw.flush();
+
+        assertOutput("Hello\nWorld\nTest\n");
+    }
+
+    public void testMoreThanBufferSizeNoLineBreaks() {
+        final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20);
+
+        String literal = "aaaaaaaaaaaaaaa";
+        lw.print(literal);
+        lw.print(literal);
+        lw.flush();
+
+        // Have to manually inspect output.
+        List<String> result = mWriter.getStrings();
+        // Expect two strings.
+        assertEquals(2, result.size());
+        // Expect the strings to sum up to the original input.
+        assertEquals(2 * literal.length(), result.get(0).length() + result.get(1).length());
+        // Strings should only be a.
+        for (String s : result) {
+            for (int i = 0; i < s.length(); i++) {
+                assertEquals('a', s.charAt(i));
+            }
+        }
+    }
+
+    public void testMoreThanBufferSizeNoLineBreaksSingleString() {
+        final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20);
+
+        String literal = "aaaaaaaaaaaaaaa";
+        lw.print(literal + literal);
+        lw.flush();
+
+        // Have to manually inspect output.
+        List<String> result = mWriter.getStrings();
+        // Expect two strings.
+        assertEquals(2, result.size());
+        // Expect the strings to sum up to the original input.
+        assertEquals(2 * literal.length(), result.get(0).length() + result.get(1).length());
+        // Strings should only be a.
+        for (String s : result) {
+            for (int i = 0; i < s.length(); i++) {
+                assertEquals('a', s.charAt(i));
+            }
+        }
+    }
+
+    public void testMoreThanBufferSizeLineBreakBefore() {
+        final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20);
+
+        String literal1 = "aaaaaaaaaa\nbbbb";
+        String literal2 = "cccccccccc";
+        lw.print(literal1);
+        lw.print(literal2);
+        lw.flush();
+
+        assertOutput("aaaaaaaaaa", "bbbbcccccccccc");
+    }
+
+    public void testMoreThanBufferSizeLineBreakBeforeSingleString() {
+        final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20);
+
+        String literal1 = "aaaaaaaaaa\nbbbb";
+        String literal2 = "cccccccccc";
+        lw.print(literal1 + literal2);
+        lw.flush();
+
+        assertOutput("aaaaaaaaaa", "bbbbcccccccccc");
+    }
+
+    public void testMoreThanBufferSizeLineBreakNew() {
+        final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20);
+
+        String literal1 = "aaaaaaaaaabbbbb";
+        String literal2 = "c\nd\nddddddddd";
+        lw.print(literal1);
+        lw.print(literal2);
+        lw.flush();
+
+        assertOutput("aaaaaaaaaabbbbbc\nd", "ddddddddd");
+    }
+
+    public void testMoreThanBufferSizeLineBreakBeforeAndNew() {
+        final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20);
+
+        String literal1 = "aaaaaaaaaa\nbbbbb";
+        String literal2 = "c\nd\nddddddddd";
+        lw.print(literal1);
+        lw.print(literal2);
+        lw.flush();
+
+        assertOutput("aaaaaaaaaa\nbbbbbc\nd", "ddddddddd");
+    }
+
+    public void testMoreThanBufferSizeInt() {
+        final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 15);
+
+        int literal1 = 1234567890;
+        int literal2 = 987654321;
+        lw.print(literal1);
+        lw.print(literal2);
+        lw.flush();
+
+        assertOutput("123456789098765", "4321");
+    }
+
+    public void testMoreThanBufferSizeChar() {
+        final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 15);
+
+        for(int i = 0; i < 10; i++) {
+            lw.print('$');
+        }
+        for(int i = 0; i < 10; i++) {
+            lw.print('%');
+        }
+        lw.flush();
+
+        assertOutput("$$$$$$$$$$%%%%%", "%%%%%");
+    }
+
+    public void testMoreThanBufferSizeLineBreakNewChars() {
+        final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20);
+
+        String literal1 = "aaaaaaaaaabbbbb";
+        String literal2 = "c\nd\nddddddddd";
+        lw.print(literal1.toCharArray());
+        lw.print(literal2.toCharArray());
+        lw.flush();
+
+        assertOutput("aaaaaaaaaabbbbbc\nd", "ddddddddd");
+    }
+
+    private void assertOutput(String... golden) {
+        List<String> goldList = createTestGolden(golden);
+        assertEquals(goldList, mWriter.getStrings());
+    }
+
+    private static List<String> createTestGolden(String... args) {
+        List<String> ret = new ArrayList<String>();
+        for (String s : args) {
+            ret.add(s);
+        }
+        return ret;
+    }
+
+    // A writer recording calls to write.
+    private final static class RecordingWriter extends Writer {
+
+        private List<String> strings = new ArrayList<String>();
+
+        public RecordingWriter() {
+        }
+
+        public List<String> getStrings() {
+            return strings;
+        }
+
+        @Override
+        public void write(char[] cbuf, int off, int len) {
+            strings.add(new String(cbuf, off, len));
+        }
+
+        @Override
+        public void flush() {
+            // Ignore.
+        }
+
+        @Override
+        public void close() {
+            // Ignore.
+        }
+    }
+}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index b4f88c33..d412d7c 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -4,9 +4,9 @@
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at
-  
+
           http://www.apache.org/licenses/LICENSE-2.0
-  
+
      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -44,6 +44,7 @@
 
     <permission name="android.permission.BLUETOOTH_STACK" >
         <group gid="net_bt_stack" />
+        <group gid="wakelock" />
     </permission>
 
     <permission name="android.permission.NET_TUNNELING" >
@@ -135,6 +136,12 @@
     <assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="audioserver" />
     <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="audioserver" />
 
+    <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="cameraserver" />
+    <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="cameraserver" />
+    <assign-permission name="android.permission.WAKE_LOCK" uid="cameraserver" />
+    <assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="cameraserver" />
+    <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="cameraserver" />
+
     <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />
 
     <!-- This is a list of all the libraries available for application
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 554b6f1..961d0eb 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -341,15 +341,9 @@
     <family lang="ko">
         <font weight="400" style="normal" index="1">NotoSansCJK-Regular.ttc</font>
     </family>
-    <family>
-        <font weight="400" style="normal">NanumGothic.ttf</font>
-    </family>
-    <family lang="und-Qaae">
+    <family lang="und-Zsye">
         <font weight="400" style="normal">NotoColorEmoji.ttf</font>
     </family>
-    <family>
-        <font weight="400" style="normal">DroidSansFallback.ttf</font>
-    </family>
     <!--
         Tai Le and Mongolian are intentionally kept last, to make sure they don't override
         the East Asian punctuation for Chinese.
diff --git a/docs/html/preview/support.jd b/docs/html/preview/support.jd
index cfd9467..8c392aa 100644
--- a/docs/html/preview/support.jd
+++ b/docs/html/preview/support.jd
@@ -160,20 +160,21 @@
         still perform BTLE and WiFi scans, but only when they are in the foreground. While in the background, those apps will get no results from BTLE and WiFi scans.</li>
     </ul>
   </li>
-  <li>Permission changes
+  <li>Accessing accounts
     <ul>
-      <li>Updated the user interface for permissions and enhanced some of the permissions
-        behaviors.</li>
-      <li>The {@link android.Manifest.permission#GET_ACCOUNTS} permission is now a member of the
-        {@link android.Manifest.permission_group#CONTACTS} permission group and it has a
-        {@code android:protectionLevel} of {@code dangerous}. This change means that when
-        targeting Android 6.0 (API level 23), you must check for and request this permission if
-        your app requires it.
+      <li>Updated the behavior of {@link android.accounts.AccountManager} account
+        discovery methods.
       </li>
-
-      <li>The {@code android.permission.READ_PROFILE} and {@code android.permission.WRITE_PROFILE}
-       permissions have been removed from the {@link android.Manifest.permission_group#CONTACTS}
-       permission group.
+      <li>The GET_ACCOUNTS permission has been deprecated.
+      </li>
+      <li>Apps targeting API level 24 should start the intent returned by
+        newChooseAccountIntent(...) and await the result to acquire a reference
+        to the user's selected account. AccountManager methods like getAccounts and
+        related methods will only return those accounts managed by
+        authenticators that match the signatures of the calling app.
+      </li>
+      <li>Apps targeting API level 23 or earlier will continue to behave as
+        before.
       </li>
     </ul>
   </li>
diff --git a/docs/html/training/id-auth/identify.jd b/docs/html/training/id-auth/identify.jd
index db9ab3a..4c399f9 100644
--- a/docs/html/training/id-auth/identify.jd
+++ b/docs/html/training/id-auth/identify.jd
@@ -15,8 +15,7 @@
 <ol>
   <li><a href="#ForYou">Determine if AccountManager is for You</a></li>
   <li><a href="#TaskTwo">Decide What Type of Account to Use</a></li>
-  <li><a href="#GetPermission">Request GET_ACCOUNT permission</a></li>
-  <li><a href="#TaskFive">Query AccountManager for a List of Accounts</a></li>
+  <li><a href="#QueryAccounts">Query the user for an Account</a></li>
   <li><a href="#IdentifyUser">Use the Account Object to Personalize Your App</a></li>
   <li><a href="#IdIsEnough">Decide Whether an Account Name is Enough</a></li>
 </ol>
@@ -71,48 +70,46 @@
 <h2 id="TaskTwo">Decide What Type of Account to Use</h2>
 
 <p>Android devices can store multiple accounts from many different providers.
-When you query {@link android.accounts.AccountManager} for account names, you can choose to filter
-by
-account type. The account type is a string that uniquely identifies the entity
-that issued the account. For instance, Google accounts have type "com.google,"
-while Twitter uses "com.twitter.android.auth.login."</p>
+When you query {@link android.accounts.AccountManager} for account names, you
+can choose to filter by account type. The account type is a string that
+uniquely identifies the entity that issued the account. For instance, Google
+accounts have type "com.google," while Twitter uses
+"com.twitter.android.auth.login."</p>
 
+<h2 id="QueryAccounts">Query the user for an Account</h2>
 
-<h2 id="GetPermission">Request GET_ACCOUNT permission</h2>
-
-<p>In order to get a list of accounts on the device, your app needs the {@link
-android.Manifest.permission#GET_ACCOUNTS}
-permission. Add a <a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">{@code
-<uses-permission>}</a> tag in your manifest file to request
-this permission:</p>
+<p>Once an account type has been determined, you can prompt the user with an
+account chooser as follows:
 
 <pre>
-&lt;manifest ... >
-    &lt;uses-permission android:name="android.permission.GET_ACCOUNTS" /&gt;
-    ...
-&lt;/manifest>
+AccountManager am = AccountManager.get(this);  // "this" reference the current Context
+Intent chooserIntent = am.newChooseAccountIntent(
+        null, // currently select account
+        null, // list of accounts that are allowed to be shown
+        new String[] { "com.google" }, // Only allow the user to select Google accounts
+        false,
+        null,  // description text
+        null, // add account auth token type
+        null, // required features for added accounts
+        null);  // options for adding an account
+this.startActivityForResult(chooserIntent, MY_REQUEST_CODE);
 </pre>
 
-
-<h2 id="TaskFive">Query AccountManager for a List of Accounts</h2>
-
-<p>Once you decide what account type you're interested in, you need to query for accounts of that
-type. Get an instance of {@link android.accounts.AccountManager} by calling {@link
-android.accounts.AccountManager#get(android.content.Context) AccountManager.get()}. Then use that
-instance to call {@link android.accounts.AccountManager#getAccountsByType(java.lang.String)
-getAccountsByType()}.</p>
+<p>Once the chooser intent is started, the user will be presented with a list of
+appropriately typed accounts. From this list they will select one which will be
+returned to your app upon onActivityResult as follows:
 
 <pre>
-AccountManager am = AccountManager.get(this); // "this" references the current Context
-
-Account[] accounts = am.getAccountsByType("com.google");
+protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+    if (requestCode == MY_REQUEST_CODE && resultCode == RESULT_OK) {
+        String name = data.getStringExtra(AccountManage.KEY_ACCOUNT_NAME);
+        String type = data.getStringExtra(AccountManage.KEY_ACCOUNT_TYPE);
+        Account selectedAccount = new Account(name, type);
+        doSomethingWithSelectedAccount(selectedAccount);
+    }
+}
 </pre>
 
-<p>This returns an array of {@link android.accounts.Account} objects. If there's more than one
-{@link android.accounts.Account} in
-the array, you should present a dialog asking the user to select one.</p>
-
-
 <h2 id="IdentifyUser">Use the Account Object to Personalize Your App</h2>
 
 <p>The {@link android.accounts.Account} object contains an account name, which for Google accounts
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
index c05ea2e..704f0ce 100644
--- a/drm/java/android/drm/DrmManagerClient.java
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -38,13 +38,14 @@
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * The main programming interface for the DRM framework. An application must instantiate this class
  * to access DRM agents through the DRM framework.
  *
  */
-public class DrmManagerClient {
+public class DrmManagerClient implements AutoCloseable {
     /**
      * Indicates that a request was successful or that no error occurred.
      */
@@ -61,6 +62,7 @@
     HandlerThread mEventThread;
     private static final String TAG = "DrmManagerClient";
 
+    private final AtomicBoolean mClosed = new AtomicBoolean();
     private final CloseGuard mCloseGuard = CloseGuard.get();
 
     static {
@@ -117,7 +119,6 @@
 
     private int mUniqueId;
     private long mNativeContext;
-    private volatile boolean mReleased;
     private Context mContext;
     private InfoHandler mInfoHandler;
     private EventHandler mEventHandler;
@@ -261,41 +262,47 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            if (mCloseGuard != null) {
-                mCloseGuard.warnIfOpen();
-            }
-            release();
+            mCloseGuard.warnIfOpen();
+            close();
         } finally {
             super.finalize();
         }
     }
 
     /**
-     * Releases resources associated with the current session of DrmManagerClient.
-     *
-     * It is considered good practice to call this method when the {@link DrmManagerClient} object
-     * is no longer needed in your application. After release() is called,
-     * {@link DrmManagerClient} is no longer usable since it has lost all of its required resource.
+     * Releases resources associated with the current session of
+     * DrmManagerClient. It is considered good practice to call this method when
+     * the {@link DrmManagerClient} object is no longer needed in your
+     * application. After this method is called, {@link DrmManagerClient} is no
+     * longer usable since it has lost all of its required resource.
      */
-    public void release() {
-        if (mReleased) return;
-        mReleased = true;
-
-        if (mEventHandler != null) {
-            mEventThread.quit();
-            mEventThread = null;
-        }
-        if (mInfoHandler != null) {
-            mInfoThread.quit();
-            mInfoThread = null;
-        }
-        mEventHandler = null;
-        mInfoHandler = null;
-        mOnEventListener = null;
-        mOnInfoListener = null;
-        mOnErrorListener = null;
-        _release(mUniqueId);
+    @Override
+    public void close() {
         mCloseGuard.close();
+        if (mClosed.compareAndSet(false, true)) {
+            if (mEventHandler != null) {
+                mEventThread.quit();
+                mEventThread = null;
+            }
+            if (mInfoHandler != null) {
+                mInfoThread.quit();
+                mInfoThread = null;
+            }
+            mEventHandler = null;
+            mInfoHandler = null;
+            mOnEventListener = null;
+            mOnInfoListener = null;
+            mOnErrorListener = null;
+            _release(mUniqueId);
+        }
+    }
+
+    /**
+     * @deprecated replaced by {@link #close()}.
+     */
+    @Deprecated
+    public void release() {
+        close();
     }
 
     /**
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index b5b1a25..169ef0b 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -25,14 +25,14 @@
 import android.util.DisplayMetrics;
 import android.util.Log;
 
-import dalvik.system.VMRuntime;
-
 import java.io.OutputStream;
 import java.nio.Buffer;
 import java.nio.ByteBuffer;
 import java.nio.IntBuffer;
 import java.nio.ShortBuffer;
 
+import libcore.util.NativeAllocationRegistry;
+
 public final class Bitmap implements Parcelable {
     private static final String TAG = "Bitmap";
 
@@ -44,6 +44,10 @@
      */
     public static final int DENSITY_NONE = 0;
 
+    // Estimated size of the Bitmap native allocation, not including
+    // pixel data.
+    private static final long NATIVE_ALLOCATION_SIZE = 32;
+
     /**
      * Backing buffer for the Bitmap.
      */
@@ -51,7 +55,6 @@
 
     // Convenience for JNI access
     private final long mNativePtr;
-    private final BitmapFinalizer mFinalizer;
 
     private final boolean mIsMutable;
 
@@ -125,9 +128,13 @@
         }
 
         mNativePtr = nativeBitmap;
-        mFinalizer = new BitmapFinalizer(nativeBitmap);
-        int nativeAllocationByteCount = (buffer == null ? getByteCount() : 0);
-        mFinalizer.setNativeAllocationByteCount(nativeAllocationByteCount);
+        long nativeSize = NATIVE_ALLOCATION_SIZE;
+        if (buffer == null) {
+            nativeSize += getByteCount();
+        }
+        NativeAllocationRegistry registry = new NativeAllocationRegistry(
+            nativeGetNativeFinalizer(), nativeSize);
+        registry.registerNativeAllocation(this, nativeBitmap);
     }
 
     /**
@@ -253,7 +260,7 @@
             throw new IllegalStateException("native-backed bitmaps may not be reconfigured");
         }
 
-        nativeReconfigure(mFinalizer.mNativeBitmap, width, height, config.nativeInt,
+        nativeReconfigure(mNativePtr, width, height, config.nativeInt,
                 mBuffer.length, mRequestPremultiplied);
         mWidth = width;
         mHeight = height;
@@ -330,8 +337,8 @@
      * there are no more references to this bitmap.
      */
     public void recycle() {
-        if (!mRecycled && mFinalizer.mNativeBitmap != 0) {
-            if (nativeRecycle(mFinalizer.mNativeBitmap)) {
+        if (!mRecycled && mNativePtr != 0) {
+            if (nativeRecycle(mNativePtr)) {
                 // return value indicates whether native pixel object was actually recycled.
                 // false indicates that it is still in use at the native level and these
                 // objects should not be collected now. They will be collected later when the
@@ -364,7 +371,7 @@
         if (mRecycled) {
             Log.w(TAG, "Called getGenerationId() on a recycle()'d bitmap! This is undefined behavior!");
         }
-        return nativeGenerationId(mFinalizer.mNativeBitmap);
+        return nativeGenerationId(mNativePtr);
     }
 
     /**
@@ -520,7 +527,7 @@
             throw new RuntimeException("Buffer not large enough for pixels");
         }
 
-        nativeCopyPixelsToBuffer(mFinalizer.mNativeBitmap, dst);
+        nativeCopyPixelsToBuffer(mNativePtr, dst);
 
         // now update the buffer's position
         int position = dst.position();
@@ -560,7 +567,7 @@
             throw new RuntimeException("Buffer not large enough for pixels");
         }
 
-        nativeCopyPixelsFromBuffer(mFinalizer.mNativeBitmap, src);
+        nativeCopyPixelsFromBuffer(mNativePtr, src);
 
         // now update the buffer's position
         int position = src.position();
@@ -582,7 +589,7 @@
      */
     public Bitmap copy(Config config, boolean isMutable) {
         checkRecycled("Can't copy a recycled bitmap");
-        Bitmap b = nativeCopy(mFinalizer.mNativeBitmap, config.nativeInt, isMutable);
+        Bitmap b = nativeCopy(mNativePtr, config.nativeInt, isMutable);
         if (b != null) {
             b.setPremultiplied(mRequestPremultiplied);
             b.mDensity = mDensity;
@@ -598,7 +605,7 @@
      */
     public Bitmap createAshmemBitmap() {
         checkRecycled("Can't copy a recycled bitmap");
-        Bitmap b = nativeCopyAshmem(mFinalizer.mNativeBitmap);
+        Bitmap b = nativeCopyAshmem(mNativePtr);
         if (b != null) {
             b.setPremultiplied(mRequestPremultiplied);
             b.mDensity = mDensity;
@@ -859,7 +866,7 @@
         }
         bm.setHasAlpha(hasAlpha);
         if (config == Config.ARGB_8888 && !hasAlpha) {
-            nativeErase(bm.mFinalizer.mNativeBitmap, 0xff000000);
+            nativeErase(bm.mNativePtr, 0xff000000);
         }
         // No need to initialize the bitmap to zeroes with other configs;
         // it is backed by a VM byte array which is by definition preinitialized
@@ -1049,7 +1056,7 @@
             throw new IllegalArgumentException("quality must be 0..100");
         }
         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "Bitmap.compress");
-        boolean result = nativeCompress(mFinalizer.mNativeBitmap, format.nativeInt,
+        boolean result = nativeCompress(mNativePtr, format.nativeInt,
                 quality, stream, new byte[WORKING_COMPRESS_STORAGE]);
         Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
         return result;
@@ -1093,7 +1100,7 @@
         if (mRecycled) {
             Log.w(TAG, "Called isPremultiplied() on a recycle()'d bitmap! This is undefined behavior!");
         }
-        return nativeIsPremultiplied(mFinalizer.mNativeBitmap);
+        return nativeIsPremultiplied(mNativePtr);
     }
 
     /**
@@ -1119,7 +1126,7 @@
     public final void setPremultiplied(boolean premultiplied) {
         checkRecycled("setPremultiplied called on a recycled bitmap");
         mRequestPremultiplied = premultiplied;
-        nativeSetPremultiplied(mFinalizer.mNativeBitmap, premultiplied);
+        nativeSetPremultiplied(mNativePtr, premultiplied);
     }
 
     /** Returns the bitmap's width */
@@ -1220,7 +1227,7 @@
         if (mRecycled) {
             Log.w(TAG, "Called getRowBytes() on a recycle()'d bitmap! This is undefined behavior!");
         }
-        return nativeRowBytes(mFinalizer.mNativeBitmap);
+        return nativeRowBytes(mNativePtr);
     }
 
     /**
@@ -1266,7 +1273,7 @@
         if (mRecycled) {
             Log.w(TAG, "Called getConfig() on a recycle()'d bitmap! This is undefined behavior!");
         }
-        return Config.nativeToConfig(nativeConfig(mFinalizer.mNativeBitmap));
+        return Config.nativeToConfig(nativeConfig(mNativePtr));
     }
 
     /** Returns true if the bitmap's config supports per-pixel alpha, and
@@ -1281,7 +1288,7 @@
         if (mRecycled) {
             Log.w(TAG, "Called hasAlpha() on a recycle()'d bitmap! This is undefined behavior!");
         }
-        return nativeHasAlpha(mFinalizer.mNativeBitmap);
+        return nativeHasAlpha(mNativePtr);
     }
 
     /**
@@ -1296,7 +1303,7 @@
      */
     public void setHasAlpha(boolean hasAlpha) {
         checkRecycled("setHasAlpha called on a recycled bitmap");
-        nativeSetHasAlpha(mFinalizer.mNativeBitmap, hasAlpha, mRequestPremultiplied);
+        nativeSetHasAlpha(mNativePtr, hasAlpha, mRequestPremultiplied);
     }
 
     /**
@@ -1320,7 +1327,7 @@
         if (mRecycled) {
             Log.w(TAG, "Called hasMipMap() on a recycle()'d bitmap! This is undefined behavior!");
         }
-        return nativeHasMipMap(mFinalizer.mNativeBitmap);
+        return nativeHasMipMap(mNativePtr);
     }
 
     /**
@@ -1345,7 +1352,7 @@
      */
     public final void setHasMipMap(boolean hasMipMap) {
         checkRecycled("setHasMipMap called on a recycled bitmap");
-        nativeSetHasMipMap(mFinalizer.mNativeBitmap, hasMipMap);
+        nativeSetHasMipMap(mNativePtr, hasMipMap);
     }
 
     /**
@@ -1358,7 +1365,7 @@
         if (!isMutable()) {
             throw new IllegalStateException("cannot erase immutable bitmaps");
         }
-        nativeErase(mFinalizer.mNativeBitmap, c);
+        nativeErase(mNativePtr, c);
     }
 
     /**
@@ -1375,7 +1382,7 @@
     public int getPixel(int x, int y) {
         checkRecycled("Can't call getPixel() on a recycled bitmap");
         checkPixelAccess(x, y);
-        return nativeGetPixel(mFinalizer.mNativeBitmap, x, y);
+        return nativeGetPixel(mNativePtr, x, y);
     }
 
     /**
@@ -1408,7 +1415,7 @@
             return; // nothing to do
         }
         checkPixelsAccess(x, y, width, height, offset, stride, pixels);
-        nativeGetPixels(mFinalizer.mNativeBitmap, pixels, offset, stride,
+        nativeGetPixels(mNativePtr, pixels, offset, stride,
                         x, y, width, height);
     }
 
@@ -1489,7 +1496,7 @@
             throw new IllegalStateException();
         }
         checkPixelAccess(x, y);
-        nativeSetPixel(mFinalizer.mNativeBitmap, x, y, color);
+        nativeSetPixel(mNativePtr, x, y, color);
     }
 
     /**
@@ -1525,7 +1532,7 @@
             return; // nothing to do
         }
         checkPixelsAccess(x, y, width, height, offset, stride, pixels);
-        nativeSetPixels(mFinalizer.mNativeBitmap, pixels, offset, stride,
+        nativeSetPixels(mNativePtr, pixels, offset, stride,
                         x, y, width, height);
     }
 
@@ -1563,7 +1570,7 @@
      */
     public void writeToParcel(Parcel p, int flags) {
         checkRecycled("Can't parcel a recycled bitmap");
-        if (!nativeWriteToParcel(mFinalizer.mNativeBitmap, mIsMutable, mDensity, p)) {
+        if (!nativeWriteToParcel(mNativePtr, mIsMutable, mDensity, p)) {
             throw new RuntimeException("native writeToParcel failed");
         }
     }
@@ -1609,7 +1616,7 @@
     public Bitmap extractAlpha(Paint paint, int[] offsetXY) {
         checkRecycled("Can't extractAlpha on a recycled bitmap");
         long nativePaint = paint != null ? paint.getNativeInstance() : 0;
-        Bitmap bm = nativeExtractAlpha(mFinalizer.mNativeBitmap, nativePaint, offsetXY);
+        Bitmap bm = nativeExtractAlpha(mNativePtr, nativePaint, offsetXY);
         if (bm == null) {
             throw new RuntimeException("Failed to extractAlpha on Bitmap");
         }
@@ -1629,7 +1636,7 @@
         if (other.isRecycled()) {
             throw new IllegalArgumentException("Can't compare to a recycled bitmap!");
         }
-        return nativeSameAs(mFinalizer.mNativeBitmap, other.mFinalizer.mNativeBitmap);
+        return nativeSameAs(mNativePtr, other.mNativePtr);
     }
 
     /**
@@ -1660,41 +1667,6 @@
         return nativeRefPixelRef(mNativePtr);
     }
 
-    private static class BitmapFinalizer {
-        private long mNativeBitmap;
-
-        // Native memory allocated for the duration of the Bitmap,
-        // if pixel data allocated into native memory, instead of java byte[]
-        private int mNativeAllocationByteCount;
-
-        BitmapFinalizer(long nativeBitmap) {
-            mNativeBitmap = nativeBitmap;
-        }
-
-        public void setNativeAllocationByteCount(int nativeByteCount) {
-            if (mNativeAllocationByteCount != 0) {
-                VMRuntime.getRuntime().registerNativeFree(mNativeAllocationByteCount);
-            }
-            mNativeAllocationByteCount = nativeByteCount;
-            if (mNativeAllocationByteCount != 0) {
-                VMRuntime.getRuntime().registerNativeAllocation(mNativeAllocationByteCount);
-            }
-        }
-
-        @Override
-        public void finalize() {
-            try {
-                super.finalize();
-            } catch (Throwable t) {
-                // Ignore
-            } finally {
-                setNativeAllocationByteCount(0);
-                nativeDestructor(mNativeBitmap);
-                mNativeBitmap = 0;
-            }
-        }
-    }
-
     //////////// native methods
 
     private static native Bitmap nativeCreate(int[] colors, int offset,
@@ -1703,7 +1675,7 @@
     private static native Bitmap nativeCopy(long nativeSrcBitmap, int nativeConfig,
                                             boolean isMutable);
     private static native Bitmap nativeCopyAshmem(long nativeSrcBitmap);
-    private static native void nativeDestructor(long nativeBitmap);
+    private static native long nativeGetNativeFinalizer();
     private static native boolean nativeRecycle(long nativeBitmap);
     private static native void nativeReconfigure(long nativeBitmap, int width, int height,
                                                  int config, int allocSize,
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index da58884..447a4c4 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -163,8 +163,11 @@
         public boolean inPremultiplied;
 
         /**
-         * If dither is true, the decoder will attempt to dither the decoded
-         * image.
+         * @deprecated As of {@link android.os.Build.VERSION_CODES#N}, this is
+         * ignored.
+         *
+         * In {@link android.os.Build.VERSION_CODES#M} and below, if dither is
+         * true, the decoder will attempt to dither the decoded image.
          */
         public boolean inDither;
 
@@ -308,7 +311,11 @@
         public boolean inInputShareable;
 
         /**
-         * If inPreferQualityOverSpeed is set to true, the decoder will try to
+         * @deprecated As of {@link android.os.Build.VERSION_CODES#N}, this is
+         * ignored.  The output will always be high quality.
+         *
+         * In {@link android.os.Build.VERSION_CODES#M} and below, if
+         * inPreferQualityOverSpeed is set to true, the decoder will try to
          * decode the reconstructed image to a higher quality even at the
          * expense of the decoding speed. Currently the field only affects JPEG
          * decode, in the case of which a more accurate, but slightly slower,
@@ -347,9 +354,10 @@
          */
         public byte[] inTempStorage;
 
-        private native void requestCancel();
-
         /**
+         * @deprecated As of {@link android.os.Build.VERSION_CODES#N}, see
+         * comments on {@link #requestCancelDecode()}.
+         *
          * Flag to indicate that cancel has been called on this object.  This
          * is useful if there's an intermediary that wants to first decode the
          * bounds and then decode the image.  In that case the intermediary
@@ -359,16 +367,19 @@
         public boolean mCancel;
 
         /**
-         *  This can be called from another thread while this options object is
-         *  inside a decode... call. Calling this will notify the decoder that
-         *  it should cancel its operation. This is not guaranteed to cancel
-         *  the decode, but if it does, the decoder... operation will return
-         *  null, or if inJustDecodeBounds is true, will set outWidth/outHeight
+         *  @deprecated As of {@link android.os.Build.VERSION_CODES#N}, this
+         *  will not affect the decode, though it will still set mCancel.
+         *
+         *  In {@link android.os.Build.VERSION_CODES#M} and below, if this can
+         *  be called from another thread while this options object is inside
+         *  a decode... call. Calling this will notify the decoder that it
+         *  should cancel its operation. This is not guaranteed to cancel the
+         *  decode, but if it does, the decoder... operation will return null,
+         *  or if inJustDecodeBounds is true, will set outWidth/outHeight
          *  to -1
          */
         public void requestCancelDecode() {
             mCancel = true;
-            requestCancel();
         }
     }
 
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 5acc1a3..d4f745d 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -31,6 +31,8 @@
 
 import javax.microedition.khronos.opengles.GL;
 
+import libcore.util.NativeAllocationRegistry;
+
 /**
  * The Canvas class holds the "draw" calls. To draw something, you need
  * 4 basic components: A Bitmap to hold the pixels, a Canvas to host
@@ -50,7 +52,7 @@
 
     /**
      * Should only be assigned in constructors (or setBitmap if software canvas),
-     * freed in finalizer.
+     * freed by NativeAllocation.
      * @hide
      */
     protected long mNativeCanvasWrapper;
@@ -85,32 +87,15 @@
     // (see SkCanvas.cpp, SkDraw.cpp)
     private static final int MAXMIMUM_BITMAP_SIZE = 32766;
 
+    // The approximate size of the native allocation associated with
+    // a Canvas object.
+    private static final long NATIVE_ALLOCATION_SIZE = 525;
+
+    private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
+        getNativeFinalizer(), NATIVE_ALLOCATION_SIZE);
+
     // This field is used to finalize the native Canvas properly
-    private final CanvasFinalizer mFinalizer;
-
-    private static final class CanvasFinalizer {
-        private long mNativeCanvasWrapper;
-
-        public CanvasFinalizer(long nativeCanvas) {
-            mNativeCanvasWrapper = nativeCanvas;
-        }
-
-        @Override
-        protected void finalize() throws Throwable {
-            try {
-                dispose();
-            } finally {
-                super.finalize();
-            }
-        }
-
-        public void dispose() {
-            if (mNativeCanvasWrapper != 0) {
-                finalizer(mNativeCanvasWrapper);
-                mNativeCanvasWrapper = 0;
-            }
-        }
-    }
+    private Runnable mFinalizer;
 
     /**
      * Construct an empty raster canvas. Use setBitmap() to specify a bitmap to
@@ -122,7 +107,7 @@
         if (!isHardwareAccelerated()) {
             // 0 means no native bitmap
             mNativeCanvasWrapper = initRaster(null);
-            mFinalizer = new CanvasFinalizer(mNativeCanvasWrapper);
+            mFinalizer = sRegistry.registerNativeAllocation(this, mNativeCanvasWrapper);
         } else {
             mFinalizer = null;
         }
@@ -143,7 +128,7 @@
         }
         throwIfCannotDraw(bitmap);
         mNativeCanvasWrapper = initRaster(bitmap);
-        mFinalizer = new CanvasFinalizer(mNativeCanvasWrapper);
+        mFinalizer = sRegistry.registerNativeAllocation(this, mNativeCanvasWrapper);
         mBitmap = bitmap;
         mDensity = bitmap.mDensity;
     }
@@ -154,7 +139,7 @@
             throw new IllegalStateException();
         }
         mNativeCanvasWrapper = nativeCanvas;
-        mFinalizer = new CanvasFinalizer(mNativeCanvasWrapper);
+        mFinalizer = sRegistry.registerNativeAllocation(this, mNativeCanvasWrapper);
         mDensity = Bitmap.getDefaultDensity();
     }
 
@@ -654,6 +639,12 @@
     /**
      * Return, in ctm, the current transformation matrix. This does not alter
      * the matrix in the canvas, but just returns a copy of it.
+     *
+     * @deprecated {@link #isHardwareAccelerated() Hardware accelerated} canvases may have any
+     * matrix when passed to a View or Drawable, as it is implementation defined where in the
+     * hierarchy such canvases are created. It is recommended in such cases to either draw contents
+     * irrespective of the current matrix, or to track relevant transform state outside of the
+     * canvas.
      */
     @Deprecated
     public void getMatrix(@NonNull Matrix ctm) {
@@ -663,6 +654,12 @@
     /**
      * Return a new matrix with a copy of the canvas' current transformation
      * matrix.
+     *
+     * @deprecated {@link #isHardwareAccelerated() Hardware accelerated} canvases may have any
+     * matrix when passed to a View or Drawable, as it is implementation defined where in the
+     * hierarchy such canvases are created. It is recommended in such cases to either draw contents
+     * irrespective of the current matrix, or to track relevant transform state outside of the
+     * canvas.
      */
     @Deprecated
     public final @NonNull Matrix getMatrix() {
@@ -812,6 +809,7 @@
      * @deprecated Unlike all other clip calls this API does not respect the
      *             current matrix. Use {@link #clipRect(Rect)} as an alternative.
      */
+    @Deprecated
     public boolean clipRegion(@NonNull Region region, @NonNull Region.Op op) {
         return native_clipRegion(mNativeCanvasWrapper, region.ni(), op.nativeInt);
     }
@@ -829,6 +827,7 @@
      * @deprecated Unlike all other clip calls this API does not respect the
      *             current matrix. Use {@link #clipRect(Rect)} as an alternative.
      */
+    @Deprecated
     public boolean clipRegion(@NonNull Region region) {
         return clipRegion(region, Region.Op.INTERSECT);
     }
@@ -1079,11 +1078,12 @@
      *                 (count >> 2).
      * @param paint    The paint used to draw the points
      */
-    public void drawLines(@Size(min=4,multiple=2) float[] pts, int offset, int count, Paint paint) {
+    public void drawLines(@Size(multiple=4) @NonNull float[] pts, int offset, int count,
+            @NonNull Paint paint) {
         native_drawLines(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance());
     }
 
-    public void drawLines(@Size(min=4,multiple=2) @NonNull float[] pts, @NonNull Paint paint) {
+    public void drawLines(@Size(multiple=4) @NonNull float[] pts, @NonNull Paint paint) {
         drawLines(pts, 0, pts.length, paint);
     }
 
@@ -1829,16 +1829,16 @@
      * Draw the text in the array, with each character's origin specified by
      * the pos array.
      *
-     * This method does not support glyph composition and decomposition and
-     * should therefore not be used to render complex scripts. It also doesn't
-     * handle supplementary characters (eg emoji).
-     *
      * @param text     The text to be drawn
      * @param index    The index of the first character to draw
      * @param count    The number of characters to draw, starting from index.
      * @param pos      Array of [x,y] positions, used to position each
      *                 character
      * @param paint    The paint used for the text (e.g. color, size, style)
+     *
+     * @deprecated This method does not support glyph composition and decomposition and
+     * should therefore not be used to render complex scripts. It also doesn't
+     * handle supplementary characters (eg emoji).
      */
     @Deprecated
     public void drawPosText(@NonNull char[] text, int index, int count,
@@ -1856,13 +1856,13 @@
      * Draw the text in the array, with each character's origin specified by
      * the pos array.
      *
-     * This method does not support glyph composition and decomposition and
-     * should therefore not be used to render complex scripts. It also doesn't
-     * handle supplementary characters (eg emoji).
-     *
      * @param text  The text to be drawn
      * @param pos   Array of [x,y] positions, used to position each character
      * @param paint The paint used for the text (e.g. color, size, style)
+     *
+     * @deprecated This method does not support glyph composition and decomposition and
+     * should therefore not be used to render complex scripts. It also doesn't
+     * handle supplementary characters (eg emoji).
      */
     @Deprecated
     public void drawPosText(@NonNull String text, @NonNull @Size(multiple=2) float[] pos,
@@ -1965,7 +1965,11 @@
      * @hide
      */
     public void release() {
-        mFinalizer.dispose();
+        mNativeCanvasWrapper = 0;
+        if (mFinalizer != null) {
+            mFinalizer.run();
+            mFinalizer = null;
+        }
     }
 
     /**
@@ -2133,5 +2137,5 @@
                                                      float hOffset,
                                                      float vOffset,
                                                      int flags, long nativePaint, long nativeTypeface);
-    private static native void finalizer(long nativeCanvas);
+    private static native long getNativeFinalizer();
 }
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 90522f7..dfb8bb8 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -30,6 +30,8 @@
 import java.util.HashMap;
 import java.util.Locale;
 
+import libcore.util.NativeAllocationRegistry;
+
 /**
  * The Paint class holds the style and color information about how to draw
  * geometries, text and bitmaps.
@@ -39,6 +41,12 @@
     private long mNativePaint;
     private long mNativeShader = 0;
 
+    // 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);
+
     /**
      * @hide
      */
@@ -444,6 +452,7 @@
      */
     public Paint(int flags) {
         mNativePaint = nInit();
+        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
@@ -462,12 +471,12 @@
      */
     public Paint(Paint paint) {
         mNativePaint = nInitWithPaint(paint.getNativeInstance());
+        sRegistry.registerNativeAllocation(this, mNativePaint);
         setClassVariablesFrom(paint);
     }
 
     /** Restores the paint to its default settings. */
     public void reset() {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nReset(mNativePaint);
         setFlags(HIDDEN_DEFAULT_PAINT_FLAGS);
 
@@ -502,8 +511,6 @@
      * methods on this.
      */
     public void set(Paint src) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
-        if (src.mNativePaint == 0) throw new NullPointerException("Source is already finalized!");
         if (this != src) {
             // copy over the native settings
             nSet(mNativePaint, src.mNativePaint);
@@ -554,7 +561,6 @@
      * @hide
      */
     public long getNativeInstance() {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         long newNativeShader = mShader == null ? 0 : mShader.getNativeInstance();
         if (newNativeShader != mNativeShader) {
             mNativeShader = newNativeShader;
@@ -592,7 +598,6 @@
      * @return the paint's flags (see enums ending in _Flag for bit masks)
      */
     public int getFlags() {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return nGetFlags(mNativePaint);
     }
 
@@ -604,7 +609,6 @@
      * @param flags The new flag bits for the paint
      */
     public void setFlags(int flags) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetFlags(mNativePaint, flags);
     }
 
@@ -615,7 +619,6 @@
      * {@link #HINTING_OFF} or {@link #HINTING_ON}.
      */
     public int getHinting() {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return nGetHinting(mNativePaint);
     }
 
@@ -626,7 +629,6 @@
      * {@link #HINTING_OFF} or {@link #HINTING_ON}.
      */
     public void setHinting(int mode) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetHinting(mNativePaint, mode);
     }
 
@@ -653,7 +655,6 @@
      * @param aa true to set the antialias bit in the flags, false to clear it
      */
     public void setAntiAlias(boolean aa) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetAntiAlias(mNativePaint, aa);
     }
 
@@ -684,7 +685,6 @@
      * @param dither true to set the dithering bit in flags, false to clear it
      */
     public void setDither(boolean dither) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetDither(mNativePaint, dither);
     }
 
@@ -706,7 +706,6 @@
      *                   false to clear it.
      */
     public void setLinearText(boolean linearText) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetLinearText(mNativePaint, linearText);
     }
 
@@ -728,7 +727,6 @@
      *                     flags, false to clear it.
      */
     public void setSubpixelText(boolean subpixelText) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetSubpixelText(mNativePaint, subpixelText);
     }
 
@@ -750,7 +748,6 @@
      *                      flags, false to clear it.
      */
     public void setUnderlineText(boolean underlineText) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetUnderlineText(mNativePaint, underlineText);
     }
 
@@ -772,7 +769,6 @@
      *                       flags, false to clear it.
      */
     public void setStrikeThruText(boolean strikeThruText) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetStrikeThruText(mNativePaint, strikeThruText);
     }
 
@@ -794,7 +790,6 @@
      *                     flags, false to clear it.
      */
     public void setFakeBoldText(boolean fakeBoldText) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetFakeBoldText(mNativePaint, fakeBoldText);
     }
 
@@ -822,7 +817,6 @@
      *               flags, false to clear it.
      */
     public void setFilterBitmap(boolean filter) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetFilterBitmap(mNativePaint, filter);
     }
 
@@ -836,7 +830,6 @@
      * @return the paint's style setting (Fill, Stroke, StrokeAndFill)
      */
     public Style getStyle() {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return sStyleArray[nGetStyle(mNativePaint)];
     }
 
@@ -848,7 +841,6 @@
      * @param style The new style to set in the paint
      */
     public void setStyle(Style style) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetStyle(mNativePaint, style.nativeInt);
     }
 
@@ -862,7 +854,6 @@
      */
     @ColorInt
     public int getColor() {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return nGetColor(mNativePaint);
     }
 
@@ -877,7 +868,6 @@
      * @param color The new color (including alpha) to set in the paint.
      */
     public void setColor(@ColorInt int color) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetColor(mNativePaint, color);
     }
 
@@ -891,7 +881,6 @@
      * @return the alpha component of the paint's color.
      */
     public int getAlpha() {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return nGetAlpha(mNativePaint);
     }
 
@@ -905,7 +894,6 @@
      * @param a set the alpha component [0..255] of the paint's color.
      */
     public void setAlpha(int a) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetAlpha(mNativePaint, a);
     }
 
@@ -933,7 +921,6 @@
      *         Stroke or StrokeAndFill.
      */
     public float getStrokeWidth() {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return nGetStrokeWidth(mNativePaint);
     }
 
@@ -948,7 +935,6 @@
      *              style is Stroke or StrokeAndFill.
      */
     public void setStrokeWidth(float width) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetStrokeWidth(mNativePaint, width);
     }
 
@@ -962,7 +948,6 @@
      *         Stroke or StrokeAndFill.
      */
     public float getStrokeMiter() {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return nGetStrokeMiter(mNativePaint);
     }
 
@@ -976,7 +961,6 @@
      *              style is Stroke or StrokeAndFill.
      */
     public void setStrokeMiter(float miter) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetStrokeMiter(mNativePaint, miter);
     }
 
@@ -990,7 +974,6 @@
      *         style is Stroke or StrokeAndFill.
      */
     public Cap getStrokeCap() {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return sCapArray[nGetStrokeCap(mNativePaint)];
     }
 
@@ -1001,7 +984,6 @@
      *            style is Stroke or StrokeAndFill.
      */
     public void setStrokeCap(Cap cap) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetStrokeCap(mNativePaint, cap.nativeInt);
     }
 
@@ -1011,7 +993,6 @@
      * @return the paint's Join.
      */
     public Join getStrokeJoin() {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return sJoinArray[nGetStrokeJoin(mNativePaint)];
     }
 
@@ -1022,7 +1003,6 @@
      *             Stroke or StrokeAndFill.
      */
     public void setStrokeJoin(Join join) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetStrokeJoin(mNativePaint, join.nativeInt);
     }
 
@@ -1038,7 +1018,6 @@
      *                 drawn with a hairline (width == 0)
      */
     public boolean getFillPath(Path src, Path dst) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return nGetFillPath(mNativePaint, src.ni(), dst.ni());
     }
 
@@ -1061,6 +1040,11 @@
      * @return       shader
      */
     public Shader setShader(Shader shader) {
+        // If mShader changes, cached value of native shader aren't valid, since
+        // old shader's pointer may be reused by another shader allocation later
+        if (mShader != shader) {
+            mNativeShader = -1;
+        }
         // Defer setting the shader natively until getNativeInstance() is called
         mShader = shader;
         return shader;
@@ -1082,7 +1066,6 @@
      * @return       filter
      */
     public ColorFilter setColorFilter(ColorFilter filter) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         long filterNative = 0;
         if (filter != null)
             filterNative = filter.native_instance;
@@ -1110,7 +1093,6 @@
      * @return         xfermode
      */
     public Xfermode setXfermode(Xfermode xfermode) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         long xfermodeNative = 0;
         if (xfermode != null)
             xfermodeNative = xfermode.native_instance;
@@ -1138,7 +1120,6 @@
      * @return       effect
      */
     public PathEffect setPathEffect(PathEffect effect) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         long effectNative = 0;
         if (effect != null) {
             effectNative = effect.native_instance;
@@ -1168,7 +1149,6 @@
      * @return           maskfilter
      */
     public MaskFilter setMaskFilter(MaskFilter maskfilter) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         long maskfilterNative = 0;
         if (maskfilter != null) {
             maskfilterNative = maskfilter.native_instance;
@@ -1200,7 +1180,6 @@
      * @return         typeface
      */
     public Typeface setTypeface(Typeface typeface) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         long typefaceNative = 0;
         if (typeface != null) {
             typefaceNative = typeface.native_instance;
@@ -1239,7 +1218,6 @@
      */
     @Deprecated
     public Rasterizer setRasterizer(Rasterizer rasterizer) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         long rasterizerNative = 0;
         if (rasterizer != null) {
             rasterizerNative = rasterizer.native_instance;
@@ -1262,7 +1240,6 @@
      * opaque, or the alpha from the shadow color if not.
      */
     public void setShadowLayer(float radius, float dx, float dy, int shadowColor) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
       nSetShadowLayer(mNativePaint, radius, dx, dy, shadowColor);
     }
 
@@ -1280,7 +1257,6 @@
      * @hide
      */
     public boolean hasShadowLayer() {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return nHasShadowLayer(mNativePaint);
     }
 
@@ -1293,7 +1269,6 @@
      * @return the paint's Align value for drawing text.
      */
     public Align getTextAlign() {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return sAlignArray[nGetTextAlign(mNativePaint)];
     }
 
@@ -1306,7 +1281,6 @@
      * @param align set the paint's Align value for drawing text.
      */
     public void setTextAlign(Align align) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetTextAlign(mNativePaint, align.nativeInt);
     }
 
@@ -1340,7 +1314,6 @@
      * @param locale the paint's locale value for drawing text, must not be null.
      */
     public void setTextLocale(@NonNull Locale locale) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (locale == null) {
             throw new IllegalArgumentException("locale cannot be null");
         }
@@ -1379,7 +1352,6 @@
      * @param locales the paint's locale list for drawing text, must not be null or empty.
      */
     public void setTextLocales(@NonNull @Size(min=1) LocaleList locales) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (locales == null || locales.isEmpty()) {
             throw new IllegalArgumentException("locales cannot be null or empty");
         }
@@ -1408,7 +1380,6 @@
      * @return true if elegant metrics are enabled for text drawing.
      */
     public boolean isElegantTextHeight() {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return nIsElegantTextHeight(mNativePaint);
     }
 
@@ -1422,7 +1393,6 @@
      * @param elegant set the paint's elegant metrics flag for drawing text.
      */
     public void setElegantTextHeight(boolean elegant) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetElegantTextHeight(mNativePaint, elegant);
     }
 
@@ -1434,7 +1404,6 @@
      * @return the paint's text size.
      */
     public float getTextSize() {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return nGetTextSize(mNativePaint);
     }
 
@@ -1446,7 +1415,6 @@
      * @param textSize set the paint's text size.
      */
     public void setTextSize(float textSize) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetTextSize(mNativePaint, textSize);
     }
 
@@ -1459,7 +1427,6 @@
      * @return the paint's scale factor in X for drawing/measuring text
      */
     public float getTextScaleX() {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return nGetTextScaleX(mNativePaint);
     }
 
@@ -1473,7 +1440,6 @@
      * @param scaleX set the paint's scale in X for drawing/measuring text.
      */
     public void setTextScaleX(float scaleX) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetTextScaleX(mNativePaint, scaleX);
     }
 
@@ -1486,7 +1452,6 @@
      * @return         the paint's skew factor in X for drawing text.
      */
     public float getTextSkewX() {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return nGetTextSkewX(mNativePaint);
     }
 
@@ -1499,7 +1464,6 @@
      * @param skewX set the paint's skew factor in X for drawing text.
      */
     public void setTextSkewX(float skewX) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetTextSkewX(mNativePaint, skewX);
     }
 
@@ -1512,7 +1476,6 @@
      * @return         the paint's letter-spacing for drawing text.
      */
     public float getLetterSpacing() {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return nGetLetterSpacing(mNativePaint);
     }
 
@@ -1524,7 +1487,6 @@
      * @param letterSpacing set the paint's letter-spacing for drawing text.
      */
     public void setLetterSpacing(float letterSpacing) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetLetterSpacing(mNativePaint, letterSpacing);
     }
 
@@ -1546,7 +1508,6 @@
      * @param settings the font feature settings string to use, may be null.
      */
     public void setFontFeatureSettings(String settings) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (settings != null && settings.equals("")) {
             settings = null;
         }
@@ -1566,7 +1527,6 @@
      * @hide
      */
     public int getHyphenEdit() {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return nGetHyphenEdit(mNativePaint);
     }
 
@@ -1579,7 +1539,6 @@
      * @hide
      */
     public void setHyphenEdit(int hyphen) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         nSetHyphenEdit(mNativePaint, hyphen);
     }
 
@@ -1591,7 +1550,6 @@
      *         current typeface and text size.
      */
     public float ascent() {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return nAscent(mNativePaint, mNativeTypeface);
     }
 
@@ -1605,7 +1563,6 @@
      *         the current typeface and text size.
      */
     public float descent() {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return nDescent(mNativePaint, mNativeTypeface);
     }
 
@@ -1652,7 +1609,6 @@
      * @return the font's recommended interline spacing.
      */
     public float getFontMetrics(FontMetrics metrics) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return nGetFontMetrics(mNativePaint, mNativeTypeface, metrics);
     }
 
@@ -1698,7 +1654,6 @@
      * @return the font's interline spacing.
      */
     public int getFontMetricsInt(FontMetricsInt fmi) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return nGetFontMetricsInt(mNativePaint, mNativeTypeface, fmi);
     }
 
@@ -1731,7 +1686,6 @@
      * @return      The width of the text
      */
     public float measureText(char[] text, int index, int count) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -1764,7 +1718,6 @@
      * @return      The width of the text
      */
     public float measureText(String text, int start, int end) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -1794,7 +1747,6 @@
      * @return      The width of the text
      */
     public float measureText(String text) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -1855,7 +1807,6 @@
      */
     public int breakText(char[] text, int index, int count,
                                 float maxWidth, float[] measuredWidth) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -1903,7 +1854,6 @@
     public int breakText(CharSequence text, int start, int end,
                          boolean measureForwards,
                          float maxWidth, float[] measuredWidth) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -1952,7 +1902,6 @@
      */
     public int breakText(String text, boolean measureForwards,
                                 float maxWidth, float[] measuredWidth) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -1990,7 +1939,6 @@
      */
     public int getTextWidths(char[] text, int index, int count,
                              float[] widths) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -2074,7 +2022,6 @@
      * @return       the number of code units in the specified text.
      */
     public int getTextWidths(String text, int start, int end, float[] widths) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -2128,7 +2075,6 @@
             int contextIndex, int contextCount, boolean isRtl, float[] advances,
             int advancesIndex) {
 
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (chars == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -2175,7 +2121,6 @@
     public float getTextRunAdvances(CharSequence text, int start, int end,
             int contextStart, int contextEnd, boolean isRtl, float[] advances,
             int advancesIndex) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -2257,7 +2202,6 @@
      */
     public float getTextRunAdvances(String text, int start, int end, int contextStart,
             int contextEnd, boolean isRtl, float[] advances, int advancesIndex) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -2322,7 +2266,6 @@
      */
     public int getTextRunCursor(char[] text, int contextStart, int contextLength,
             int dir, int offset, int cursorOpt) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         int contextEnd = contextStart + contextLength;
         if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
                 | (offset - contextStart) | (contextEnd - offset)
@@ -2410,7 +2353,6 @@
      */
     public int getTextRunCursor(String text, int contextStart, int contextEnd,
             int dir, int offset, int cursorOpt) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
                 | (offset - contextStart) | (contextEnd - offset)
                 | (text.length() - contextEnd) | cursorOpt) < 0)
@@ -2437,7 +2379,6 @@
      */
     public void getTextPath(char[] text, int index, int count,
                             float x, float y, Path path) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if ((index | count) < 0 || index + count > text.length) {
             throw new ArrayIndexOutOfBoundsException();
         }
@@ -2460,7 +2401,6 @@
      */
     public void getTextPath(String text, int start, int end,
                             float x, float y, Path path) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if ((start | end | (end - start) | (text.length() - end)) < 0) {
             throw new IndexOutOfBoundsException();
         }
@@ -2479,7 +2419,6 @@
      *               allocated by the caller.
      */
     public void getTextBounds(String text, int start, int end, Rect bounds) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if ((start | end | (end - start) | (text.length() - end)) < 0) {
             throw new IndexOutOfBoundsException();
         }
@@ -2500,7 +2439,6 @@
      *               allocated by the caller.
      */
     public void getTextBounds(char[] text, int index, int count, Rect bounds) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if ((index | count) < 0 || index + count > text.length) {
             throw new ArrayIndexOutOfBoundsException();
         }
@@ -2528,7 +2466,6 @@
      * @return true if the typeface has a glyph for the string
      */
     public boolean hasGlyph(String string) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         return nHasGlyph(mNativePaint, mNativeTypeface, mBidiFlags, string);
     }
 
@@ -2570,7 +2507,6 @@
      */
     public float getRunAdvance(char[] text, int start, int end, int contextStart, int contextEnd,
             boolean isRtl, int offset) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -2601,7 +2537,6 @@
      */
     public float getRunAdvance(CharSequence text, int start, int end, int contextStart,
             int contextEnd, boolean isRtl, int offset) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -2652,7 +2587,6 @@
      */
     public int getOffsetForAdvance(char[] text, int start, int end, int contextStart,
             int contextEnd, boolean isRtl, float advance) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -2680,7 +2614,6 @@
      */
     public int getOffsetForAdvance(CharSequence text, int start, int end, int contextStart,
             int contextEnd, boolean isRtl, float advance) {
-        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -2698,18 +2631,6 @@
         return result;
     }
 
-    @Override
-    protected void finalize() throws Throwable {
-        try {
-            if (mNativePaint != 0) {
-                nFinalizer(mNativePaint);
-                mNativePaint = 0;
-            }
-        } finally {
-            super.finalize();
-        }
-    }
-
     private static native long nInit();
     private static native long nInitWithPaint(long paint);
     private static native void nReset(long paintPtr);
@@ -2765,7 +2686,7 @@
                                 String text, int start, int end, int bidiFlags, Rect bounds);
     private static native void nGetCharArrayBounds(long nativePaint, long typefacePtr,
                                 char[] text, int index, int count, int bidiFlags, Rect bounds);
-    private static native void nFinalizer(long nativePaint);
+    private static native long nGetNativeFinalizer();
 
     private static native void nSetShadowLayer(long paintPtr,
             float radius, float dx, float dy, int color);
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index adb282f..94983b3 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -117,7 +117,10 @@
         }
     }
 
-    /* package */ long getNativeInstance() {
+    /**
+     * @hide
+     */
+    public long getNativeInstance() {
         return native_instance;
     }
 
diff --git a/graphics/java/android/graphics/drawable/Icon.aidl b/graphics/java/android/graphics/drawable/Icon.aidl
new file mode 100644
index 0000000..b82cfc4
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/Icon.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.drawable;
+
+parcelable Icon;
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 651b453..e2150c0 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -82,8 +82,13 @@
      */
     public static final int PADDING_MODE_STACK = 1;
 
-    /** Value used for undefined start and end insets. */
-    private static final int UNDEFINED_INSET = Integer.MIN_VALUE;
+    /**
+     * Value used for undefined start and end insets.
+     *
+     * @see #getLayerInsetStart(int)
+     * @see #getLayerInsetEnd(int)
+     */
+    public static final int UNDEFINED_INSET = Integer.MIN_VALUE;
 
     LayerState mLayerState;
 
@@ -867,7 +872,8 @@
 
     /**
      * @param index the index of the layer
-     * @return number of pixels to inset from the start bound
+     * @return the number of pixels to inset from the start bound, or
+     *         {@link #UNDEFINED_INSET} if not specified
      * @attr ref android.R.styleable#LayerDrawableItem_start
      */
     public int getLayerInsetStart(int index) {
@@ -877,7 +883,8 @@
 
     /**
      * @param index the index of the layer to adjust
-     * @param e number of pixels to inset from the end bound
+     * @param e number of pixels to inset from the end bound, or
+     *         {@link #UNDEFINED_INSET} if not specified
      * @attr ref android.R.styleable#LayerDrawableItem_end
      */
     public void setLayerInsetEnd(int index, int e) {
@@ -977,34 +984,33 @@
             computeStackedPadding(padding);
         }
 
+        final int paddingT = layerState.mPaddingTop;
+        final int paddingB = layerState.mPaddingBottom;
+
+        // Resolve padding for RTL. Relative padding overrides absolute
+        // padding.
+        final boolean isLayoutRtl = getLayoutDirection() == LayoutDirection.RTL;
+        final int paddingRtlL = isLayoutRtl ? layerState.mPaddingEnd : layerState.mPaddingStart;
+        final int paddingRtlR = isLayoutRtl ? layerState.mPaddingStart : layerState.mPaddingEnd;
+        final int paddingL = paddingRtlL >= 0 ? paddingRtlL : layerState.mPaddingLeft;
+        final int paddingR = paddingRtlR >= 0 ? paddingRtlR : layerState.mPaddingRight;
+
         // If padding was explicitly specified (e.g. not -1) then override the
         // computed padding in that dimension.
-        if (layerState.mPaddingTop >= 0) {
-            padding.top = layerState.mPaddingTop;
+        if (paddingL >= 0) {
+            padding.left = paddingL;
         }
 
-        if (layerState.mPaddingBottom >= 0) {
-            padding.bottom = layerState.mPaddingBottom;
+        if (paddingT >= 0) {
+            padding.top = paddingT;
         }
 
-        final int paddingRtlLeft;
-        final int paddingRtlRight;
-        if (getLayoutDirection() == LayoutDirection.RTL) {
-            paddingRtlLeft = layerState.mPaddingEnd;
-            paddingRtlRight = layerState.mPaddingStart;
-        } else {
-            paddingRtlLeft = layerState.mPaddingStart;
-            paddingRtlRight = layerState.mPaddingEnd;
+        if (paddingR >= 0) {
+            padding.right = paddingR;
         }
 
-        final int paddingLeft =  paddingRtlLeft >= 0 ? paddingRtlLeft : layerState.mPaddingLeft;
-        if (paddingLeft >= 0) {
-            padding.left = paddingLeft;
-        }
-
-        final int paddingRight =  paddingRtlRight >= 0 ? paddingRtlRight : layerState.mPaddingRight;
-        if (paddingRight >= 0) {
-            padding.right = paddingRight;
+        if (paddingB >= 0) {
+            padding.bottom = paddingB;
         }
 
         return padding.left != 0 || padding.top != 0 || padding.right != 0 || padding.bottom != 0;
@@ -1471,58 +1477,59 @@
     }
 
     private void updateLayerBounds(Rect bounds) {
-        int padL = 0;
-        int padT = 0;
-        int padR = 0;
-        int padB = 0;
+        int paddingL = 0;
+        int paddingT = 0;
+        int paddingR = 0;
+        int paddingB = 0;
 
         final Rect outRect = mTmpOutRect;
         final int layoutDirection = getLayoutDirection();
-        final boolean nest = mLayerState.mPaddingMode == PADDING_MODE_NEST;
+        final boolean isLayoutRtl = layoutDirection == LayoutDirection.RTL;
+        final boolean isPaddingNested = mLayerState.mPaddingMode == PADDING_MODE_NEST;
         final ChildDrawable[] array = mLayerState.mChildren;
-        final int N = mLayerState.mNum;
-        for (int i = 0; i < N; i++) {
+
+        for (int i = 0, count = mLayerState.mNum; i < count; i++) {
             final ChildDrawable r = array[i];
             final Drawable d = r.mDrawable;
             if (d == null) {
                 continue;
             }
 
-            final Rect container = mTmpContainer;
-            container.set(d.getBounds());
+            final int insetT = r.mInsetT;
+            final int insetB = r.mInsetB;
 
-            // Take the resolved layout direction into account. If start / end
-            // padding are defined, they will be resolved (hence overriding) to
-            // left / right or right / left depending on the resolved layout
-            // direction. If start / end padding are not defined, use the
-            // left / right ones.
-            final int insetL, insetR;
-            if (layoutDirection == LayoutDirection.RTL) {
-                insetL = r.mInsetE == UNDEFINED_INSET ? r.mInsetL : r.mInsetE;
-                insetR = r.mInsetS == UNDEFINED_INSET ? r.mInsetR : r.mInsetS;
-            } else {
-                insetL = r.mInsetS == UNDEFINED_INSET ? r.mInsetL : r.mInsetS;
-                insetR = r.mInsetE == UNDEFINED_INSET ? r.mInsetR : r.mInsetE;
-            }
+            // Resolve insets for RTL. Relative insets override absolute
+            // 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;
 
             // Establish containing region based on aggregate padding and
             // requested insets for the current layer.
-            container.set(bounds.left + insetL + padL, bounds.top + r.mInsetT + padT,
-                    bounds.right - insetR - padR, bounds.bottom - r.mInsetB - padB);
+            final Rect container = mTmpContainer;
+            container.set(bounds.left + insetL + paddingL, bounds.top + insetT + paddingT,
+                    bounds.right - insetR - paddingR, bounds.bottom - insetB - paddingB);
 
-            // Apply resolved gravity to drawable based on resolved size.
-            final int gravity = resolveGravity(r.mGravity, r.mWidth, r.mHeight,
-                    d.getIntrinsicWidth(), d.getIntrinsicHeight());
-            final int w = r.mWidth < 0 ? d.getIntrinsicWidth() : r.mWidth;
-            final int h = r.mHeight < 0 ? d.getIntrinsicHeight() : r.mHeight;
-            Gravity.apply(gravity, w, h, container, outRect, layoutDirection);
+            // Compute a reasonable default gravity based on the intrinsic and
+            // explicit dimensions, if specified.
+            final int intrinsicW = d.getIntrinsicWidth();
+            final int intrinsicH = d.getIntrinsicHeight();
+            final int layerW = r.mWidth;
+            final int layerH = r.mHeight;
+            final int gravity = resolveGravity(r.mGravity, layerW, layerH, intrinsicW, intrinsicH);
+
+            // Explicit dimensions override intrinsic dimensions.
+            final int resolvedW = layerW < 0 ? intrinsicW : layerW;
+            final int resolvedH = layerH < 0 ? intrinsicH : layerH;
+            Gravity.apply(gravity, resolvedW, resolvedH, container, outRect, layoutDirection);
             d.setBounds(outRect);
 
-            if (nest) {
-                padL += mPaddingL[i];
-                padR += mPaddingR[i];
-                padT += mPaddingT[i];
-                padB += mPaddingB[i];
+            if (isPaddingNested) {
+                paddingL += mPaddingL[i];
+                paddingR += mPaddingR[i];
+                paddingT += mPaddingT[i];
+                paddingB += mPaddingB[i];
             }
         }
     }
@@ -1578,6 +1585,7 @@
         int padR = 0;
 
         final boolean nest = mLayerState.mPaddingMode == PADDING_MODE_NEST;
+        final boolean isLayoutRtl = getLayoutDirection() == LayoutDirection.RTL;
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
@@ -1591,15 +1599,10 @@
             // left / right or right / left depending on the resolved layout
             // direction. If start / end padding are not defined, use the
             // left / right ones.
-            final int insetL, insetR;
-            final int layoutDirection = getLayoutDirection();
-            if (layoutDirection == LayoutDirection.RTL) {
-                insetL = r.mInsetE == UNDEFINED_INSET ? r.mInsetL : r.mInsetE;
-                insetR = r.mInsetS == UNDEFINED_INSET ? r.mInsetR : r.mInsetS;
-            } else {
-                insetL = r.mInsetS == UNDEFINED_INSET ? r.mInsetL : r.mInsetS;
-                insetR = r.mInsetE == UNDEFINED_INSET ? r.mInsetR : r.mInsetE;
-            }
+            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;
 
             // Don't apply padding and insets for children that don't have
             // an intrinsic dimension.
@@ -1659,8 +1662,8 @@
         if (r.mDrawable != null) {
             final Rect rect = mTmpRect;
             r.mDrawable.getPadding(rect);
-            if (rect.left != mPaddingL[i] || rect.top != mPaddingT[i] ||
-                    rect.right != mPaddingR[i] || rect.bottom != mPaddingB[i]) {
+            if (rect.left != mPaddingL[i] || rect.top != mPaddingT[i]
+                    || rect.right != mPaddingR[i] || rect.bottom != mPaddingB[i]) {
                 mPaddingL[i] = rect.left;
                 mPaddingT[i] = rect.top;
                 mPaddingR[i] = rect.right;
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index d313aa5..6bd2646 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -33,6 +33,7 @@
  * Draws a ripple background.
  */
 class RippleBackground extends RippleComponent {
+
     private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
 
     private static final int OPACITY_ENTER_DURATION = 600;
@@ -48,8 +49,14 @@
     // Software rendering properties.
     private float mOpacity = 0;
 
-    public RippleBackground(RippleDrawable owner, Rect bounds, boolean forceSoftware) {
+    /** Whether this ripple is bounded. */
+    private boolean mIsBounded;
+
+    public RippleBackground(RippleDrawable owner, Rect bounds, boolean isBounded,
+            boolean forceSoftware) {
         super(owner, bounds, forceSoftware);
+
+        mIsBounded = isBounded;
     }
 
     public boolean isVisible() {
@@ -105,7 +112,8 @@
         final AnimatorSet.Builder builder = set.play(exit);
 
         // Linear "fast" enter based on current opacity.
-        final int fastEnterDuration = (int) ((1 - mOpacity) * OPACITY_ENTER_DURATION_FAST);
+        final int fastEnterDuration = mIsBounded ?
+                (int) ((1 - mOpacity) * OPACITY_ENTER_DURATION_FAST) : 0;
         if (fastEnterDuration > 0) {
             final ObjectAnimator enter = ObjectAnimator.ofFloat(this, RippleBackground.OPACITY, 1);
             enter.setInterpolator(LINEAR_INTERPOLATOR);
@@ -131,15 +139,18 @@
         mPropX = CanvasProperty.createFloat(0);
         mPropY = CanvasProperty.createFloat(0);
 
-        final int fastEnterDuration = (int) ((1 - mOpacity) * OPACITY_ENTER_DURATION_FAST);
+        final int fastEnterDuration = mIsBounded ?
+                (int) ((1 - mOpacity) * OPACITY_ENTER_DURATION_FAST) : 0;
 
         // Linear exit after enter is completed.
         final RenderNodeAnimator exit = new RenderNodeAnimator(
                 mPropPaint, RenderNodeAnimator.PAINT_ALPHA, 0);
         exit.setInterpolator(LINEAR_INTERPOLATOR);
         exit.setDuration(OPACITY_EXIT_DURATION);
-        exit.setStartDelay(fastEnterDuration);
-        exit.setStartValue(targetAlpha);
+        if (fastEnterDuration > 0) {
+            exit.setStartDelay(fastEnterDuration);
+            exit.setStartValue(targetAlpha);
+        }
         set.add(exit);
 
         // Linear "fast" enter based on current opacity.
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 5213e10..9c691e5 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -540,7 +540,8 @@
      */
     private void tryBackgroundEnter(boolean focused) {
         if (mBackground == null) {
-            mBackground = new RippleBackground(this, mHotspotBounds, mForceSoftware);
+            final boolean isBounded = isBounded();
+            mBackground = new RippleBackground(this, mHotspotBounds, isBounded, mForceSoftware);
         }
 
         mBackground.setup(mState.mMaxRadius, mDensity);
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 78424e3..c0dfe77 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -204,11 +204,13 @@
 
     /**
      * Sets the X position around which the drawable is rotated.
+     * <p>
+     * If the X pivot is relative (as specified by
+     * {@link #setPivotXRelative(boolean)}), then the position represents a
+     * fraction of the drawable width. Otherwise, the position represents an
+     * absolute value in pixels.
      *
-     * @param pivotX X position around which to rotate. If the X pivot is
-     *            relative, the position represents a fraction of the drawable
-     *            width. Otherwise, the position represents an absolute value in
-     *            pixels.
+     * @param pivotX X position around which to rotate
      * @see #setPivotXRelative(boolean)
      * @attr ref android.R.styleable#RotateDrawable_pivotX
      */
@@ -254,11 +256,13 @@
 
     /**
      * Sets the Y position around which the drawable is rotated.
+     * <p>
+     * If the Y pivot is relative (as specified by
+     * {@link #setPivotYRelative(boolean)}), then the position represents a
+     * fraction of the drawable height. Otherwise, the position represents an
+     * absolute value in pixels.
      *
-     * @param pivotY Y position around which to rotate. If the Y pivot is
-     *            relative, the position represents a fraction of the drawable
-     *            height. Otherwise, the position represents an absolute value
-     *            in pixels.
+     * @param pivotY Y position around which to rotate
      * @see #getPivotY()
      * @attr ref android.R.styleable#RotateDrawable_pivotY
      */
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 3761a99..1fc1b83 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -17,28 +17,24 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.res.ColorStateList;
+import android.content.res.ComplexColor;
+import android.content.res.GradientColor;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
-import android.graphics.Bitmap;
 import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.ColorFilter;
 import android.graphics.Insets;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PathMeasure;
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
 import android.graphics.PorterDuff.Mode;
+import android.graphics.Shader;
 import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.LayoutDirection;
 import android.util.Log;
-import android.util.MathUtils;
 import android.util.PathParser;
 import android.util.Xml;
 
@@ -48,6 +44,8 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.util.ArrayList;
 import java.util.Stack;
 
@@ -126,9 +124,9 @@
  * <dd>Defines path data using exactly same format as "d" attribute
  * in the SVG's path data. This is defined in the viewport space.</dd>
  * <dt><code>android:fillColor</code></dt>
- * <dd>Specifies the color used to fill the path. May be a color or (SDK 24+ only) a color state
- * list. If this property is animated, any value set by the animation will override the original
- * value. No path fill is drawn if this property is not specified.</dd>
+ * <dd>Specifies the color used to fill the path. May be a color, also may be a color state list or
+ * a gradient color for SDK 24+. If this property is animated, any value set by the animation will
+ * override the original value. No path fill is drawn if this property is not specified.</dd>
  * <dt><code>android:strokeColor</code></dt>
  * <dd>Specifies the color used to draw the path outline. May be a color or (SDK 24+ only) a color
  * state list. If this property is animated, any value set by the animation will override the
@@ -196,21 +194,6 @@
     private static final String SHAPE_PATH = "path";
     private static final String SHAPE_VECTOR = "vector";
 
-    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;
-
-    // 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.
-    private static final int MAX_CACHED_BITMAP_SIZE = 2048;
-
-    private static final boolean DBG_VECTOR_DRAWABLE = false;
-
     private VectorDrawableState mVectorState;
 
     private PorterDuffColorFilter mTintFilter;
@@ -218,10 +201,6 @@
 
     private boolean mMutated;
 
-    // AnimatedVectorDrawable needs to turn off the cache all the time, otherwise,
-    // caching the bitmap by default is allowed.
-    private boolean mAllowCaching = true;
-
     /** The density of the display on which this drawable will be rendered. */
     private int mTargetDensity;
 
@@ -235,8 +214,6 @@
     private boolean mDpiScaledDirty = true;
 
     // Temp variable, only for saving "new" operation at the draw() time.
-    private final float[] mTmpFloats = new float[9];
-    private final Matrix mTmpMatrix = new Matrix();
     private final Rect mTmpBounds = new Rect();
 
     public VectorDrawable() {
@@ -249,7 +226,6 @@
      */
     private VectorDrawable(@NonNull VectorDrawableState state, @Nullable Resources res) {
         mVectorState = state;
-
         updateLocalState(res);
     }
 
@@ -262,7 +238,7 @@
      *            displayed, or {@code null} to use the constant state defaults
      */
     private void updateLocalState(Resources res) {
-        final int density = Drawable.resolveDensity(res, mVectorState.mVPathRenderer.mDensity);
+        final int density = Drawable.resolveDensity(res, mVectorState.mDensity);
         if (mTargetDensity != density) {
             mTargetDensity = density;
             mDpiScaledDirty = true;
@@ -289,7 +265,7 @@
     }
 
     Object getTargetByName(String name) {
-        return mVectorState.mVPathRenderer.mVGTargetsMap.get(name);
+        return mVectorState.mVGTargetsMap.get(name);
     }
 
     @Override
@@ -310,61 +286,23 @@
 
         // Color filters always override tint filters.
         final ColorFilter colorFilter = (mColorFilter == null ? mTintFilter : mColorFilter);
-
-        // The imageView can scale the canvas in different ways, in order to
-        // 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.
-        canvas.getMatrix(mTmpMatrix);
-        mTmpMatrix.getValues(mTmpFloats);
-        float canvasScaleX = Math.abs(mTmpFloats[Matrix.MSCALE_X]);
-        float canvasScaleY = Math.abs(mTmpFloats[Matrix.MSCALE_Y]);
-        int scaledWidth = (int) (mTmpBounds.width() * canvasScaleX);
-        int scaledHeight = (int) (mTmpBounds.height() * canvasScaleY);
-        scaledWidth = Math.min(MAX_CACHED_BITMAP_SIZE, scaledWidth);
-        scaledHeight = Math.min(MAX_CACHED_BITMAP_SIZE, scaledHeight);
-
-        if (scaledWidth <= 0 || scaledHeight <= 0) {
-            return;
-        }
-
-        final int saveCount = canvas.save();
-        canvas.translate(mTmpBounds.left, mTmpBounds.top);
-
-        // Handle RTL mirroring.
-        final boolean needMirroring = needMirroring();
-        if (needMirroring) {
-            canvas.translate(mTmpBounds.width(), 0);
-            canvas.scale(-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);
-        mTmpBounds.offsetTo(0, 0);
-
-        mVectorState.createCachedBitmapIfNeeded(scaledWidth, scaledHeight);
-        if (!mAllowCaching) {
-            mVectorState.updateCachedBitmap(scaledWidth, scaledHeight);
-        } else {
-            if (!mVectorState.canReuseCache()) {
-                mVectorState.updateCachedBitmap(scaledWidth, scaledHeight);
-                mVectorState.updateCacheStates();
-            }
-        }
-        mVectorState.drawCachedBitmapWithRootAlpha(canvas, colorFilter, mTmpBounds);
-        canvas.restoreToCount(saveCount);
+        final long colorFilterNativeInstance = colorFilter == null ? 0 :
+                colorFilter.native_instance;
+        boolean canReuseCache = mVectorState.canReuseCache();
+        nDraw(mVectorState.getNativeRenderer(), canvas.getNativeCanvasWrapper(),
+                colorFilterNativeInstance, mTmpBounds, needMirroring(),
+                canReuseCache);
     }
 
+
     @Override
     public int getAlpha() {
-        return mVectorState.mVPathRenderer.getRootAlpha();
+        return (int) (mVectorState.getAlpha() * 255);
     }
 
     @Override
     public void setAlpha(int alpha) {
-        if (mVectorState.mVPathRenderer.getRootAlpha() != alpha) {
-            mVectorState.mVPathRenderer.setRootAlpha(alpha);
+        if (mVectorState.setAlpha(alpha / 255f)) {
             invalidateSelf();
         }
     }
@@ -410,7 +348,7 @@
         boolean changed = false;
 
         final VectorDrawableState state = mVectorState;
-        if (state.mVPathRenderer != null && state.mVPathRenderer.onStateChange(stateSet)) {
+        if (state.onStateChange(stateSet)) {
             changed = true;
             state.mCacheDirty = true;
         }
@@ -457,16 +395,15 @@
      * from the source density against which the constant state was loaded.
      */
     void computeVectorSize() {
-        final VPathRenderer pathRenderer = mVectorState.mVPathRenderer;
-        final Insets opticalInsets = pathRenderer.mOpticalInsets;
+        final Insets opticalInsets = mVectorState.mOpticalInsets;
 
-        final int sourceDensity = pathRenderer.mDensity;
+        final int sourceDensity = mVectorState.mDensity;
         final int targetDensity = mTargetDensity;
         if (targetDensity != sourceDensity) {
             mDpiScaledWidth = Drawable.scaleFromDensity(
-                    (int) pathRenderer.mBaseWidth, sourceDensity, targetDensity, true);
+                    (int) mVectorState.mBaseWidth, sourceDensity, targetDensity, true);
             mDpiScaledHeight = Drawable.scaleFromDensity(
-                    (int) pathRenderer.mBaseHeight,sourceDensity, targetDensity, true);
+                    (int) mVectorState.mBaseHeight,sourceDensity, targetDensity, true);
             final int left = Drawable.scaleFromDensity(
                     opticalInsets.left, sourceDensity, targetDensity, false);
             final int right = Drawable.scaleFromDensity(
@@ -477,8 +414,8 @@
                     opticalInsets.bottom, sourceDensity, targetDensity, false);
             mDpiScaledInsets = Insets.of(left, top, right, bottom);
         } else {
-            mDpiScaledWidth = (int) pathRenderer.mBaseWidth;
-            mDpiScaledHeight = (int) pathRenderer.mBaseHeight;
+            mDpiScaledWidth = (int) mVectorState.mBaseWidth;
+            mDpiScaledHeight = (int) mVectorState.mBaseHeight;
             mDpiScaledInsets = opticalInsets;
         }
 
@@ -499,8 +436,7 @@
             return;
         }
 
-        final VPathRenderer path = state.mVPathRenderer;
-        final boolean changedDensity = path.setDensity(
+        final boolean changedDensity = mVectorState.setDensity(
                 Drawable.resolveDensity(t.getResources(), 0));
         mDpiScaledDirty |= changedDensity;
 
@@ -511,7 +447,7 @@
                 state.mCacheDirty = true;
                 updateStateFromTypedArray(a);
             } catch (XmlPullParserException e) {
-                rethrowAsRuntimeException(e);
+                throw new RuntimeException(e);
             } finally {
                 a.recycle();
             }
@@ -525,8 +461,8 @@
             state.mTint = state.mTint.obtainForTheme(t);
         }
 
-        if (path != null && path.canApplyTheme()) {
-            path.applyTheme(t);
+        if (mVectorState != null && mVectorState.canApplyTheme()) {
+            mVectorState.applyTheme(t);
         }
 
         // Update local properties.
@@ -540,17 +476,17 @@
      * @hide
      */
     public float getPixelSize() {
-        if (mVectorState == null || mVectorState.mVPathRenderer == null ||
-                mVectorState.mVPathRenderer.mBaseWidth == 0 ||
-                mVectorState.mVPathRenderer.mBaseHeight == 0 ||
-                mVectorState.mVPathRenderer.mViewportHeight == 0 ||
-                mVectorState.mVPathRenderer.mViewportWidth == 0) {
+        if (mVectorState == null ||
+                mVectorState.mBaseWidth == 0 ||
+                mVectorState.mBaseHeight == 0 ||
+                mVectorState.mViewportHeight == 0 ||
+                mVectorState.mViewportWidth == 0) {
             return 1; // fall back to 1:1 pixel mapping.
         }
-        float intrinsicWidth = mVectorState.mVPathRenderer.mBaseWidth;
-        float intrinsicHeight = mVectorState.mVPathRenderer.mBaseHeight;
-        float viewportWidth = mVectorState.mVPathRenderer.mViewportWidth;
-        float viewportHeight = mVectorState.mVPathRenderer.mViewportHeight;
+        float intrinsicWidth = mVectorState.mBaseWidth;
+        float intrinsicHeight = mVectorState.mBaseHeight;
+        float viewportWidth = mVectorState.mViewportWidth;
+        float viewportHeight = mVectorState.mViewportHeight;
         float scaleX = viewportWidth / intrinsicWidth;
         float scaleY = viewportHeight / intrinsicHeight;
         return Math.min(scaleX, scaleY);
@@ -582,20 +518,20 @@
         return null;
     }
 
-    private static int applyAlpha(int color, float alpha) {
-        int alphaBytes = Color.alpha(color);
-        color &= 0x00FFFFFF;
-        color |= ((int) (alphaBytes * alpha)) << 24;
-        return color;
-    }
-
     @Override
     public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
             @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
+        if (mVectorState.mRootGroup != null || mVectorState.mNativeRendererPtr != 0) {
+            // This VD has been used to display other VD resource content, clean up.
+            mVectorState.mRootGroup = new VGroup();
+            if (mVectorState.mNativeRendererPtr != 0) {
+                nDestroyRenderer(mVectorState.mNativeRendererPtr);
+            }
+            mVectorState.mNativeRendererPtr = nCreateRenderer(mVectorState.mRootGroup.mNativePtr);
+        }
         final VectorDrawableState state = mVectorState;
-        state.mVPathRenderer = new VPathRenderer();
-        state.mVPathRenderer.setDensity(Drawable.resolveDensity(r, 0));
+        state.setDensity(Drawable.resolveDensity(r, 0));
 
         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawable);
         updateStateFromTypedArray(a);
@@ -612,7 +548,6 @@
 
     private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
         final VectorDrawableState state = mVectorState;
-        final VPathRenderer pathRenderer = state.mVPathRenderer;
 
         // Account for any configuration changes.
         state.mChangingConfigurations |= a.getChangingConfigurations();
@@ -633,63 +568,63 @@
         state.mAutoMirrored = a.getBoolean(
                 R.styleable.VectorDrawable_autoMirrored, state.mAutoMirrored);
 
-        pathRenderer.mViewportWidth = a.getFloat(
-                R.styleable.VectorDrawable_viewportWidth, pathRenderer.mViewportWidth);
-        pathRenderer.mViewportHeight = a.getFloat(
-                R.styleable.VectorDrawable_viewportHeight, pathRenderer.mViewportHeight);
+        float viewportWidth = a.getFloat(
+                R.styleable.VectorDrawable_viewportWidth, state.mViewportWidth);
+        float viewportHeight = a.getFloat(
+                R.styleable.VectorDrawable_viewportHeight, state.mViewportHeight);
+        state.setViewportSize(viewportWidth, viewportHeight);
 
-        if (pathRenderer.mViewportWidth <= 0) {
+        if (state.mViewportWidth <= 0) {
             throw new XmlPullParserException(a.getPositionDescription() +
                     "<vector> tag requires viewportWidth > 0");
-        } else if (pathRenderer.mViewportHeight <= 0) {
+        } else if (state.mViewportHeight <= 0) {
             throw new XmlPullParserException(a.getPositionDescription() +
                     "<vector> tag requires viewportHeight > 0");
         }
 
-        pathRenderer.mBaseWidth = a.getDimension(
-                R.styleable.VectorDrawable_width, pathRenderer.mBaseWidth);
-        pathRenderer.mBaseHeight = a.getDimension(
-                R.styleable.VectorDrawable_height, pathRenderer.mBaseHeight);
+        state.mBaseWidth = a.getDimension(
+                R.styleable.VectorDrawable_width, state.mBaseWidth);
+        state.mBaseHeight = a.getDimension(
+                R.styleable.VectorDrawable_height, state.mBaseHeight);
 
-        if (pathRenderer.mBaseWidth <= 0) {
+        if (state.mBaseWidth <= 0) {
             throw new XmlPullParserException(a.getPositionDescription() +
                     "<vector> tag requires width > 0");
-        } else if (pathRenderer.mBaseHeight <= 0) {
+        } else if (state.mBaseHeight <= 0) {
             throw new XmlPullParserException(a.getPositionDescription() +
                     "<vector> tag requires height > 0");
         }
 
         final int insetLeft = a.getDimensionPixelOffset(
-                R.styleable.VectorDrawable_opticalInsetLeft, pathRenderer.mOpticalInsets.left);
+                R.styleable.VectorDrawable_opticalInsetLeft, state.mOpticalInsets.left);
         final int insetTop = a.getDimensionPixelOffset(
-                R.styleable.VectorDrawable_opticalInsetTop, pathRenderer.mOpticalInsets.top);
+                R.styleable.VectorDrawable_opticalInsetTop, state.mOpticalInsets.top);
         final int insetRight = a.getDimensionPixelOffset(
-                R.styleable.VectorDrawable_opticalInsetRight, pathRenderer.mOpticalInsets.right);
+                R.styleable.VectorDrawable_opticalInsetRight, state.mOpticalInsets.right);
         final int insetBottom = a.getDimensionPixelOffset(
-                R.styleable.VectorDrawable_opticalInsetBottom, pathRenderer.mOpticalInsets.bottom);
-        pathRenderer.mOpticalInsets = Insets.of(insetLeft, insetTop, insetRight, insetBottom);
+                R.styleable.VectorDrawable_opticalInsetBottom, state.mOpticalInsets.bottom);
+        state.mOpticalInsets = Insets.of(insetLeft, insetTop, insetRight, insetBottom);
 
         final float alphaInFloat = a.getFloat(
-                R.styleable.VectorDrawable_alpha, pathRenderer.getAlpha());
-        pathRenderer.setAlpha(alphaInFloat);
+                R.styleable.VectorDrawable_alpha, state.getAlpha());
+        state.setAlpha(alphaInFloat);
 
         final String name = a.getString(R.styleable.VectorDrawable_name);
         if (name != null) {
-            pathRenderer.mRootName = name;
-            pathRenderer.mVGTargetsMap.put(name, pathRenderer);
+            state.mRootName = name;
+            state.mVGTargetsMap.put(name, state);
         }
     }
 
     private void inflateChildElements(Resources res, XmlPullParser parser, AttributeSet attrs,
             Theme theme) throws XmlPullParserException, IOException {
         final VectorDrawableState state = mVectorState;
-        final VPathRenderer pathRenderer = state.mVPathRenderer;
         boolean noPathTag = true;
 
         // Use a stack to help to build the group tree.
         // The top of the stack is always the current group.
         final Stack<VGroup> groupStack = new Stack<VGroup>();
-        groupStack.push(pathRenderer.mRootGroup);
+        groupStack.push(state.mRootGroup);
 
         int eventType = parser.getEventType();
         while (eventType != XmlPullParser.END_DOCUMENT) {
@@ -702,7 +637,7 @@
                     path.inflate(res, attrs, theme);
                     currentGroup.addChild(path);
                     if (path.getPathName() != null) {
-                        pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
+                        state.mVGTargetsMap.put(path.getPathName(), path);
                     }
                     noPathTag = false;
                     state.mChangingConfigurations |= path.mChangingConfigurations;
@@ -711,7 +646,7 @@
                     path.inflate(res, attrs, theme);
                     currentGroup.addChild(path);
                     if (path.getPathName() != null) {
-                        pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
+                        state.mVGTargetsMap.put(path.getPathName(), path);
                     }
                     state.mChangingConfigurations |= path.mChangingConfigurations;
                 } else if (SHAPE_GROUP.equals(tagName)) {
@@ -720,7 +655,7 @@
                     currentGroup.addChild(newChildGroup);
                     groupStack.push(newChildGroup);
                     if (newChildGroup.getGroupName() != null) {
-                        pathRenderer.mVGTargetsMap.put(newChildGroup.getGroupName(),
+                        state.mVGTargetsMap.put(newChildGroup.getGroupName(),
                                 newChildGroup);
                     }
                     state.mChangingConfigurations |= newChildGroup.mChangingConfigurations;
@@ -734,11 +669,6 @@
             eventType = parser.next();
         }
 
-        // Print the tree out for debug.
-        if (DBG_VECTOR_DRAWABLE) {
-            pathRenderer.printGroupTree();
-        }
-
         if (noPathTag) {
             final StringBuffer tag = new StringBuffer();
 
@@ -757,7 +687,7 @@
     }
 
     void setAllowCaching(boolean allowCaching) {
-        mAllowCaching = allowCaching;
+        nSetAllowCaching(mVectorState.getNativeRenderer(), allowCaching);
     }
 
     private boolean needMirroring() {
@@ -778,84 +708,68 @@
     }
 
     private static class VectorDrawableState extends ConstantState {
+        // Variables below need to be copied (deep copy if applicable) for mutation.
         int[] mThemeAttrs;
         int mChangingConfigurations;
-        VPathRenderer mVPathRenderer;
         ColorStateList mTint = null;
         Mode mTintMode = DEFAULT_TINT_MODE;
         boolean mAutoMirrored;
 
-        Bitmap mCachedBitmap;
+        float mBaseWidth = 0;
+        float mBaseHeight = 0;
+        float mViewportWidth = 0;
+        float mViewportHeight = 0;
+        Insets mOpticalInsets = Insets.NONE;
+        String mRootName = null;
+        VGroup mRootGroup;
+        long mNativeRendererPtr;
+
+        int mDensity = DisplayMetrics.DENSITY_DEFAULT;
+        final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<>();
+
+        // Fields for cache
         int[] mCachedThemeAttrs;
         ColorStateList mCachedTint;
         Mode mCachedTintMode;
-        int mCachedRootAlpha;
         boolean mCachedAutoMirrored;
         boolean mCacheDirty;
-        /** Temporary paint object used to draw cached bitmaps. */
-        Paint mTempPaint;
 
         // Deep copy for mutate() or implicitly mutate.
         public VectorDrawableState(VectorDrawableState copy) {
             if (copy != null) {
                 mThemeAttrs = copy.mThemeAttrs;
                 mChangingConfigurations = copy.mChangingConfigurations;
-                mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
                 mTint = copy.mTint;
                 mTintMode = copy.mTintMode;
                 mAutoMirrored = copy.mAutoMirrored;
+                mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap);
+                mNativeRendererPtr = nCreateRenderer(mRootGroup.mNativePtr);
+
+                mBaseWidth = copy.mBaseWidth;
+                mBaseHeight = copy.mBaseHeight;
+                setViewportSize(copy.mViewportWidth, copy.mViewportHeight);
+                mOpticalInsets = copy.mOpticalInsets;
+
+                mRootName = copy.mRootName;
+                mDensity = copy.mDensity;
+                if (copy.mRootName != null) {
+                    mVGTargetsMap.put(copy.mRootName, this);
+                }
             }
         }
 
-        public void drawCachedBitmapWithRootAlpha(Canvas canvas, ColorFilter filter,
-                Rect originalBounds) {
-            // The bitmap's size is the same as the bounds.
-            final Paint p = getPaint(filter);
-            canvas.drawBitmap(mCachedBitmap, null, originalBounds, p);
-        }
-
-        public boolean hasTranslucentRoot() {
-            return mVPathRenderer.getRootAlpha() < 255;
-        }
-
-        /**
-         * @return null when there is no need for alpha paint.
-         */
-        public Paint getPaint(ColorFilter filter) {
-            if (!hasTranslucentRoot() && filter == null) {
-                return null;
+        @Override
+        public void finalize() throws Throwable {
+            if (mNativeRendererPtr != 0) {
+                nDestroyRenderer(mNativeRendererPtr);
+                mNativeRendererPtr = 0;
             }
-
-            if (mTempPaint == null) {
-                mTempPaint = new Paint();
-                mTempPaint.setFilterBitmap(true);
-            }
-            mTempPaint.setAlpha(mVPathRenderer.getRootAlpha());
-            mTempPaint.setColorFilter(filter);
-            return mTempPaint;
+            super.finalize();
         }
 
-        public void updateCachedBitmap(int width, int height) {
-            mCachedBitmap.eraseColor(Color.TRANSPARENT);
-            Canvas tmpCanvas = new Canvas(mCachedBitmap);
-            mVPathRenderer.draw(tmpCanvas, width, height, null);
-        }
 
-        public void createCachedBitmapIfNeeded(int width, int height) {
-            if (mCachedBitmap == null || !canReuseBitmap(width, height)) {
-                mCachedBitmap = Bitmap.createBitmap(width, height,
-                        Bitmap.Config.ARGB_8888);
-                mCacheDirty = true;
-            }
-
-        }
-
-        public boolean canReuseBitmap(int width, int height) {
-            if (width == mCachedBitmap.getWidth()
-                    && height == mCachedBitmap.getHeight()) {
-                return true;
-            }
-            return false;
+        long getNativeRenderer() {
+            return mNativeRendererPtr;
         }
 
         public boolean canReuseCache() {
@@ -863,10 +777,10 @@
                     && mCachedThemeAttrs == mThemeAttrs
                     && mCachedTint == mTint
                     && mCachedTintMode == mTintMode
-                    && mCachedAutoMirrored == mAutoMirrored
-                    && mCachedRootAlpha == mVPathRenderer.getRootAlpha()) {
+                    && mCachedAutoMirrored == mAutoMirrored) {
                 return true;
             }
+            updateCacheStates();
             return false;
         }
 
@@ -876,21 +790,25 @@
             mCachedThemeAttrs = mThemeAttrs;
             mCachedTint = mTint;
             mCachedTintMode = mTintMode;
-            mCachedRootAlpha = mVPathRenderer.getRootAlpha();
             mCachedAutoMirrored = mAutoMirrored;
             mCacheDirty = false;
         }
 
+        public void applyTheme(Theme t) {
+            mRootGroup.applyTheme(t);
+        }
+
         @Override
         public boolean canApplyTheme() {
             return mThemeAttrs != null
-                    || (mVPathRenderer != null && mVPathRenderer.canApplyTheme())
+                    || (mRootGroup != null && mRootGroup.canApplyTheme())
                     || (mTint != null && mTint.canApplyTheme())
                     || super.canApplyTheme();
         }
 
         public VectorDrawableState() {
-            mVPathRenderer = new VPathRenderer();
+            mRootGroup = new VGroup();
+            mNativeRendererPtr = nCreateRenderer(mRootGroup.mNativePtr);
         }
 
         @Override
@@ -911,80 +829,13 @@
 
         public boolean isStateful() {
             return (mTint != null && mTint.isStateful())
-                    || (mVPathRenderer != null && mVPathRenderer.isStateful());
-        }
-    }
-
-    private static class VPathRenderer {
-        /* 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 TempState mTempState = new TempState();
-
-        /////////////////////////////////////////////////////
-        // Variables below need to be copied (deep copy if applicable) for mutation.
-        private int mChangingConfigurations;
-        private final VGroup mRootGroup;
-        float mBaseWidth = 0;
-        float mBaseHeight = 0;
-        float mViewportWidth = 0;
-        float mViewportHeight = 0;
-        Insets mOpticalInsets = Insets.NONE;
-        int mRootAlpha = 0xFF;
-        String mRootName = null;
-
-        int mDensity = DisplayMetrics.DENSITY_DEFAULT;
-
-        final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<>();
-
-        public VPathRenderer() {
-            mRootGroup = new VGroup();
+                    || (mRootGroup != null && mRootGroup.isStateful());
         }
 
-        public void setRootAlpha(int alpha) {
-            mRootAlpha = alpha;
-        }
-
-        public int getRootAlpha() {
-            return mRootAlpha;
-        }
-
-        // setAlpha() and getAlpha() are used mostly for animation purpose, since
-        // Animator like to use alpha from 0 to 1.
-        public void setAlpha(float alpha) {
-            setRootAlpha((int) (alpha * 255));
-        }
-
-        @SuppressWarnings("unused")
-        public float getAlpha() {
-            return getRootAlpha() / 255.0f;
-        }
-
-        public VPathRenderer(VPathRenderer copy) {
-            mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap);
-            mBaseWidth = copy.mBaseWidth;
-            mBaseHeight = copy.mBaseHeight;
-            mViewportWidth = copy.mViewportWidth;
-            mViewportHeight = copy.mViewportHeight;
-            mOpticalInsets = copy.mOpticalInsets;
-            mChangingConfigurations = copy.mChangingConfigurations;
-            mRootAlpha = copy.mRootAlpha;
-            mRootName = copy.mRootName;
-            mDensity = copy.mDensity;
-            if (copy.mRootName != null) {
-                mVGTargetsMap.put(copy.mRootName, this);
-            }
+        void setViewportSize(float viewportWidth, float viewportHeight) {
+            mViewportWidth = viewportWidth;
+            mViewportHeight = viewportHeight;
+            nSetRendererViewportSize(getNativeRenderer(), viewportWidth, viewportHeight);
         }
 
         public final boolean setDensity(int targetDensity) {
@@ -1012,68 +863,50 @@
             mOpticalInsets = Insets.of(insetLeft, insetTop, insetRight, insetBottom);
         }
 
-        public boolean canApplyTheme() {
-            return mRootGroup.canApplyTheme();
-        }
-
-        public void applyTheme(Theme t) {
-            mRootGroup.applyTheme(t);
-        }
-
         public boolean onStateChange(int[] stateSet) {
             return mRootGroup.onStateChange(stateSet);
         }
 
-        public boolean isStateful() {
-            return mRootGroup.isStateful();
+        /**
+         * setAlpha() and getAlpha() are used mostly for animation purpose. Return true if alpha
+         * has changed.
+         */
+        public boolean setAlpha(float alpha) {
+            return nSetRootAlpha(mNativeRendererPtr, alpha);
         }
 
-        public void draw(Canvas canvas, int w, int h, ColorFilter filter) {
-            final float scaleX = w / mViewportWidth;
-            final float scaleY = h / mViewportHeight;
-            mRootGroup.draw(canvas, mTempState, Matrix.IDENTITY_MATRIX, filter, scaleX, scaleY);
-        }
-
-        public void printGroupTree() {
-            mRootGroup.printGroupTree("");
+        @SuppressWarnings("unused")
+        public float getAlpha() {
+            return nGetRootAlpha(mNativeRendererPtr);
         }
     }
 
     private static class VGroup implements VObject {
-        private static final String GROUP_INDENT = "    ";
+        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;
+        private static final int TRANSFORM_PROPERTY_COUNT = 7;
 
-        // mStackedMatrix is only used temporarily when drawing, it combines all
-        // the parents' local matrices with the current one.
-        private final Matrix mStackedMatrix = new Matrix();
-
+        // Temp array to store transform values obtained from native.
+        private float[] mTransform;
         /////////////////////////////////////////////////////
         // Variables below need to be copied (deep copy if applicable) for mutation.
         private final ArrayList<VObject> mChildren = new ArrayList<>();
-
-        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 boolean mIsStateful;
 
         // 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 int mChangingConfigurations;
         private int[] mThemeAttrs;
         private String mGroupName = null;
+        private long mNativePtr = 0;
 
         public VGroup(VGroup 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;
+
             mIsStateful = copy.mIsStateful;
             mThemeAttrs = copy.mThemeAttrs;
             mGroupName = copy.mGroupName;
@@ -1081,15 +914,14 @@
             if (mGroupName != null) {
                 targetsMap.put(mGroupName, this);
             }
-
-            mLocalMatrix.set(copy.mLocalMatrix);
+            mNativePtr = nCreateGroup(copy.mNativePtr);
 
             final ArrayList<VObject> children = copy.mChildren;
             for (int i = 0; i < children.size(); i++) {
                 final VObject copyChild = children.get(i);
                 if (copyChild instanceof VGroup) {
                     final VGroup copyGroup = (VGroup) copyChild;
-                    mChildren.add(new VGroup(copyGroup, targetsMap));
+                    addChild(new VGroup(copyGroup, targetsMap));
                 } else {
                     final VPath newPath;
                     if (copyChild instanceof VFullPath) {
@@ -1099,7 +931,7 @@
                     } else {
                         throw new IllegalStateException("Unknown object in the tree!");
                     }
-                    mChildren.add(newPath);
+                    addChild(newPath);
                     if (newPath.mPathName != null) {
                         targetsMap.put(newPath.mPathName, newPath);
                     }
@@ -1108,43 +940,23 @@
         }
 
         public VGroup() {
+            mNativePtr = nCreateGroup();
         }
 
         public String getGroupName() {
             return mGroupName;
         }
 
-        public Matrix getLocalMatrix() {
-            return mLocalMatrix;
-        }
-
         public void addChild(VObject child) {
+            nAddChild(mNativePtr, child.getNativePtr());
             mChildren.add(child);
 
             mIsStateful |= child.isStateful();
         }
 
         @Override
-        public void draw(Canvas canvas, TempState temp, Matrix currentMatrix,
-                ColorFilter filter, float scaleX, float scaleY) {
-            // 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.
-            mStackedMatrix.set(currentMatrix);
-            mStackedMatrix.preConcat(mLocalMatrix);
-
-            // Save the current clip information, which is local to this group.
-            canvas.save();
-
-            // Draw the group tree in the same order as the XML file.
-            for (int i = 0, count = mChildren.size(); i < count; i++) {
-                final VObject child = mChildren.get(i);
-                child.draw(canvas, temp, mStackedMatrix, filter, scaleX, scaleY);
-            }
-
-            // Restore the previous clip information.
-            canvas.restore();
+        public long getNativePtr() {
+            return mNativePtr;
         }
 
         @Override
@@ -1155,27 +967,43 @@
             a.recycle();
         }
 
-        private void updateStateFromTypedArray(TypedArray a) {
+        void updateStateFromTypedArray(TypedArray a) {
             // Account for any configuration changes.
             mChangingConfigurations |= a.getChangingConfigurations();
 
             // Extract the theme attributes, if any.
             mThemeAttrs = a.extractThemeAttrs();
-
-            mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate);
-            mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX);
-            mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY);
-            mScaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX, mScaleX);
-            mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY);
-            mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX);
-            mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY);
+            if (mTransform == null) {
+                // Lazy initialization: If the group is created through copy constructor, this may
+                // never get called.
+                mTransform = new float[TRANSFORM_PROPERTY_COUNT];
+            }
+            boolean success = nGetGroupProperties(mNativePtr, mTransform, TRANSFORM_PROPERTY_COUNT);
+            if (!success) {
+                throw new RuntimeException("Error: inconsistent property count");
+            }
+            float rotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation,
+                    mTransform[ROTATE_INDEX]);
+            float pivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX,
+                    mTransform[PIVOT_X_INDEX]);
+            float pivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY,
+                    mTransform[PIVOT_Y_INDEX]);
+            float scaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX,
+                    mTransform[SCALE_X_INDEX]);
+            float scaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY,
+                    mTransform[SCALE_Y_INDEX]);
+            float translateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX,
+                    mTransform[TRANSLATE_X_INDEX]);
+            float translateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY,
+                    mTransform[TRANSLATE_Y_INDEX]);
 
             final String groupName = a.getString(R.styleable.VectorDrawableGroup_name);
             if (groupName != null) {
                 mGroupName = groupName;
+                nSetName(mNativePtr, mGroupName);
             }
-
-            updateLocalMatrix();
+             nUpdateGroupProperties(mNativePtr, rotate, pivotX, pivotY, scaleX, scaleY,
+                     translateX, translateY);
         }
 
         @Override
@@ -1216,6 +1044,16 @@
         }
 
         @Override
+        protected void finalize() throws Throwable {
+            if (mNativePtr != 0) {
+                nDestroy(mNativePtr);
+                mNativePtr = 0;
+            }
+            super.finalize();
+        }
+
+
+        @Override
         public void applyTheme(Theme t) {
             if (mThemeAttrs != null) {
                 final TypedArray a = t.resolveAttributes(mThemeAttrs,
@@ -1236,124 +1074,75 @@
             }
         }
 
-        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);
-        }
-
-        public void printGroupTree(String indent) {
-            Log.v(LOGTAG, indent + "group:" + getGroupName() + " rotation is " + mRotate);
-            Log.v(LOGTAG, indent + "matrix:" + getLocalMatrix().toString());
-
-            final int count = mChildren.size();
-            if (count > 0) {
-                indent += GROUP_INDENT;
-            }
-
-            // Then print all the children groups.
-            for (int i = 0; i < count; i++) {
-                final VObject child = mChildren.get(i);
-                if (child instanceof VGroup) {
-                    ((VGroup) child).printGroupTree(indent);
-                }
-            }
-        }
-
         /* Setters and Getters, used by animator from AnimatedVectorDrawable. */
         @SuppressWarnings("unused")
         public float getRotation() {
-            return mRotate;
+            return nGetRotation(mNativePtr);
         }
 
         @SuppressWarnings("unused")
         public void setRotation(float rotation) {
-            if (rotation != mRotate) {
-                mRotate = rotation;
-                updateLocalMatrix();
-            }
+            nSetRotation(mNativePtr, rotation);
         }
 
         @SuppressWarnings("unused")
         public float getPivotX() {
-            return mPivotX;
+            return nGetPivotX(mNativePtr);
         }
 
         @SuppressWarnings("unused")
         public void setPivotX(float pivotX) {
-            if (pivotX != mPivotX) {
-                mPivotX = pivotX;
-                updateLocalMatrix();
-            }
+            nSetPivotX(mNativePtr, pivotX);
         }
 
         @SuppressWarnings("unused")
         public float getPivotY() {
-            return mPivotY;
+            return nGetPivotY(mNativePtr);
         }
 
         @SuppressWarnings("unused")
         public void setPivotY(float pivotY) {
-            if (pivotY != mPivotY) {
-                mPivotY = pivotY;
-                updateLocalMatrix();
-            }
+            nSetPivotY(mNativePtr, pivotY);
         }
 
         @SuppressWarnings("unused")
         public float getScaleX() {
-            return mScaleX;
+            return nGetScaleX(mNativePtr);
         }
 
         @SuppressWarnings("unused")
         public void setScaleX(float scaleX) {
-            if (scaleX != mScaleX) {
-                mScaleX = scaleX;
-                updateLocalMatrix();
-            }
+            nSetScaleX(mNativePtr, scaleX);
         }
 
         @SuppressWarnings("unused")
         public float getScaleY() {
-            return mScaleY;
+            return nGetScaleY(mNativePtr);
         }
 
         @SuppressWarnings("unused")
         public void setScaleY(float scaleY) {
-            if (scaleY != mScaleY) {
-                mScaleY = scaleY;
-                updateLocalMatrix();
-            }
+            nSetScaleY(mNativePtr, scaleY);
         }
 
         @SuppressWarnings("unused")
         public float getTranslateX() {
-            return mTranslateX;
+            return nGetTranslateX(mNativePtr);
         }
 
         @SuppressWarnings("unused")
         public void setTranslateX(float translateX) {
-            if (translateX != mTranslateX) {
-                mTranslateX = translateX;
-                updateLocalMatrix();
-            }
+            nSetTranslateX(mNativePtr, translateX);
         }
 
         @SuppressWarnings("unused")
         public float getTranslateY() {
-            return mTranslateY;
+            return nGetTranslateY(mNativePtr);
         }
 
         @SuppressWarnings("unused")
         public void setTranslateY(float translateY) {
-            if (translateY != mTranslateY) {
-                mTranslateY = translateY;
-                updateLocalMatrix();
-            }
+            nSetTranslateY(mNativePtr, translateY);
         }
     }
 
@@ -1362,6 +1151,7 @@
      */
     private static abstract class VPath implements VObject {
         protected PathParser.PathData mPathData = null;
+
         String mPathName;
         int mChangingConfigurations;
 
@@ -1379,10 +1169,6 @@
             return mPathName;
         }
 
-        public boolean isClipPath() {
-            return false;
-        }
-
         /* Setters and Getters, used by animator from AnimatedVectorDrawable. */
         @SuppressWarnings("unused")
         public PathParser.PathData getPathData() {
@@ -1393,79 +1179,7 @@
         @SuppressWarnings("unused")
         public void setPathData(PathParser.PathData pathData) {
             mPathData.setPathData(pathData);
-        }
-
-        @Override
-        public final void draw(Canvas canvas, TempState temp, Matrix groupStackedMatrix,
-                ColorFilter filter, float scaleX, float scaleY) {
-            final float matrixScale = VPath.getMatrixScale(groupStackedMatrix);
-            if (matrixScale == 0) {
-                // When either x or y is scaled to 0, we don't need to draw anything.
-                return;
-            }
-
-            final Path path = temp.path;
-            path.reset();
-            toPath(temp, path);
-
-            final Matrix pathMatrix = temp.pathMatrix;
-            pathMatrix.set(groupStackedMatrix);
-            pathMatrix.postScale(scaleX, scaleY);
-
-            final Path renderPath = temp.renderPath;
-            renderPath.reset();
-            renderPath.addPath(path, pathMatrix);
-
-            final float minScale = Math.min(scaleX, scaleY);
-            final float strokeScale = minScale * matrixScale;
-            drawPath(temp, renderPath, canvas, filter, strokeScale);
-        }
-
-        /**
-         * Writes the path's nodes to an output Path for rendering.
-         *
-         * @param temp temporary state variables
-         * @param outPath the output path
-         */
-        protected void toPath(TempState temp, Path outPath) {
-            if (mPathData != null) {
-                PathParser.createPathFromPathData(outPath, mPathData);
-            }
-        }
-
-        /**
-         * Draws the specified path into the supplied canvas.
-         */
-        protected abstract void drawPath(TempState temp, Path path, Canvas canvas,
-                ColorFilter filter, float strokeScale);
-
-        private static 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;
+            nSetPathData(getNativePtr(), mPathData.getNativePtr());
         }
     }
 
@@ -1473,21 +1187,31 @@
      * Clip path, which only has name and pathData.
      */
     private static class VClipPath extends VPath {
+        long mNativePtr = 0;
         public VClipPath() {
+            mNativePtr = nCreateClipPath();
             // Empty constructor.
         }
 
         public VClipPath(VClipPath copy) {
             super(copy);
+            mNativePtr = nCreateClipPath(copy.mNativePtr);
         }
 
         @Override
-        protected void drawPath(TempState temp, Path renderPath, Canvas canvas, ColorFilter filter,
-                float strokeScale) {
-            canvas.clipPath(renderPath);
+        public long getNativePtr() {
+            return mNativePtr;
         }
 
         @Override
+        protected void finalize() throws Throwable {
+            if (mNativePtr != 0) {
+                nDestroy(mNativePtr);
+                mNativePtr = 0;
+            }
+            super.finalize();
+        }
+        @Override
         public void inflate(Resources r, AttributeSet attrs, Theme theme) {
             final TypedArray a = obtainAttributes(r, theme, attrs,
                     R.styleable.VectorDrawableClipPath);
@@ -1522,111 +1246,78 @@
             final String pathName = a.getString(R.styleable.VectorDrawableClipPath_name);
             if (pathName != null) {
                 mPathName = pathName;
+                nSetName(mNativePtr, mPathName);
             }
 
             final String pathDataString = a.getString(R.styleable.VectorDrawableClipPath_pathData);
             if (pathDataString != null) {
                 mPathData = new PathParser.PathData(pathDataString);
+                nSetPathString(mNativePtr, pathDataString, pathDataString.length());
             }
         }
-
-        @Override
-        public boolean isClipPath() {
-            return true;
-        }
     }
 
     /**
      * Normal path, which contains all the fill / paint information.
      */
     private static class VFullPath extends VPath {
+        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 TOTAL_PROPERTY_COUNT = 11;
+
+        // Temp array to store property data obtained from native getter.
+        private byte[] mPropertyData;
         /////////////////////////////////////////////////////
         // Variables below need to be copied (deep copy if applicable) for mutation.
         private int[] mThemeAttrs;
 
-        ColorStateList mStrokeColors = null;
-        int mStrokeColor = Color.TRANSPARENT;
-        float mStrokeWidth = 0;
-
-        ColorStateList mFillColors = null;
-        int mFillColor = Color.TRANSPARENT;
-        float mStrokeAlpha = 1.0f;
-        int mFillRule;
-        float mFillAlpha = 1.0f;
-        float mTrimPathStart = 0;
-        float mTrimPathEnd = 1;
-        float mTrimPathOffset = 0;
-
-        Paint.Cap mStrokeLineCap = Paint.Cap.BUTT;
-        Paint.Join mStrokeLineJoin = Paint.Join.MITER;
-        float mStrokeMiterlimit = 4;
+        ComplexColor mStrokeColors = null;
+        ComplexColor mFillColors = null;
+        private long mNativePtr = 0;
 
         public VFullPath() {
             // Empty constructor.
+            mNativePtr = nCreateFullPath();
         }
 
         public VFullPath(VFullPath copy) {
             super(copy);
-
+            mNativePtr = nCreateFullPath(copy.mNativePtr);
             mThemeAttrs = copy.mThemeAttrs;
-
             mStrokeColors = copy.mStrokeColors;
-            mStrokeColor = copy.mStrokeColor;
-            mStrokeWidth = copy.mStrokeWidth;
-            mStrokeAlpha = copy.mStrokeAlpha;
             mFillColors = copy.mFillColors;
-            mFillColor = copy.mFillColor;
-            mFillRule = copy.mFillRule;
-            mFillAlpha = copy.mFillAlpha;
-            mTrimPathStart = copy.mTrimPathStart;
-            mTrimPathEnd = copy.mTrimPathEnd;
-            mTrimPathOffset = copy.mTrimPathOffset;
-
-            mStrokeLineCap = copy.mStrokeLineCap;
-            mStrokeLineJoin = copy.mStrokeLineJoin;
-            mStrokeMiterlimit = copy.mStrokeMiterlimit;
-        }
-
-        private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) {
-            switch (id) {
-                case LINECAP_BUTT:
-                    return Paint.Cap.BUTT;
-                case LINECAP_ROUND:
-                    return Paint.Cap.ROUND;
-                case LINECAP_SQUARE:
-                    return Paint.Cap.SQUARE;
-                default:
-                    return defValue;
-            }
-        }
-
-        private Paint.Join getStrokeLineJoin(int id, Paint.Join defValue) {
-            switch (id) {
-                case LINEJOIN_MITER:
-                    return Paint.Join.MITER;
-                case LINEJOIN_ROUND:
-                    return Paint.Join.ROUND;
-                case LINEJOIN_BEVEL:
-                    return Paint.Join.BEVEL;
-                default:
-                    return defValue;
-            }
         }
 
         @Override
         public boolean onStateChange(int[] stateSet) {
             boolean changed = false;
 
-            if (mStrokeColors != null) {
-                final int oldStrokeColor = mStrokeColor;
-                mStrokeColor = mStrokeColors.getColorForState(stateSet, oldStrokeColor);
-                changed |= oldStrokeColor != mStrokeColor;
+            if (mStrokeColors != null && mStrokeColors instanceof ColorStateList) {
+                final int oldStrokeColor = getStrokeColor();
+                final int newStrokeColor =
+                        ((ColorStateList) mStrokeColors).getColorForState(stateSet, oldStrokeColor);
+                changed |= oldStrokeColor != newStrokeColor;
+                if (oldStrokeColor != newStrokeColor) {
+                    nSetStrokeColor(mNativePtr, newStrokeColor);
+                }
             }
 
-            if (mFillColors != null) {
-                final int oldFillColor = mFillColor;
-                mFillColor = mFillColors.getColorForState(stateSet, oldFillColor);
-                changed |= oldFillColor != mFillColor;
+            if (mFillColors != null && mFillColors instanceof ColorStateList) {
+                final int oldFillColor = getFillColor();
+                final int newFillColor = ((ColorStateList) mFillColors).getColorForState(stateSet, oldFillColor);
+                changed |= oldFillColor != newFillColor;
+                if (oldFillColor != newFillColor) {
+                    nSetFillColor(mNativePtr, newFillColor);
+                }
             }
 
             return changed;
@@ -1638,101 +1329,8 @@
         }
 
         @Override
-        public void toPath(TempState temp, Path path) {
-            super.toPath(temp, path);
-
-            if (mTrimPathStart != 0.0f || mTrimPathEnd != 1.0f) {
-                VFullPath.applyTrim(temp, path, mTrimPathStart, mTrimPathEnd, mTrimPathOffset);
-            }
-        }
-
-        @Override
-        protected void drawPath(TempState temp, Path path, Canvas canvas, ColorFilter filter,
-                float strokeScale) {
-            drawPathFill(temp, path, canvas, filter);
-            drawPathStroke(temp, path, canvas, filter, strokeScale);
-        }
-
-        /**
-         * Draws this path's fill, if necessary.
-         */
-        private void drawPathFill(TempState temp, Path path, Canvas canvas, ColorFilter filter) {
-            if (mFillColor == Color.TRANSPARENT) {
-                return;
-            }
-
-            if (temp.mFillPaint == null) {
-                temp.mFillPaint = new Paint();
-                temp.mFillPaint.setStyle(Paint.Style.FILL);
-                temp.mFillPaint.setAntiAlias(true);
-            }
-
-            final Paint fillPaint = temp.mFillPaint;
-            fillPaint.setColor(applyAlpha(mFillColor, mFillAlpha));
-            fillPaint.setColorFilter(filter);
-            canvas.drawPath(path, fillPaint);
-        }
-
-        /**
-         * Draws this path's stroke, if necessary.
-         */
-        private void drawPathStroke(TempState temp, Path path, Canvas canvas, ColorFilter filter,
-                float strokeScale) {
-            if (mStrokeColor == Color.TRANSPARENT) {
-                return;
-            }
-
-            if (temp.mStrokePaint == null) {
-                temp.mStrokePaint = new Paint();
-                temp.mStrokePaint.setStyle(Paint.Style.STROKE);
-                temp.mStrokePaint.setAntiAlias(true);
-            }
-
-            final Paint strokePaint = temp.mStrokePaint;
-            if (mStrokeLineJoin != null) {
-                strokePaint.setStrokeJoin(mStrokeLineJoin);
-            }
-
-            if (mStrokeLineCap != null) {
-                strokePaint.setStrokeCap(mStrokeLineCap);
-            }
-
-            strokePaint.setStrokeMiter(mStrokeMiterlimit);
-            strokePaint.setColor(applyAlpha(mStrokeColor, mStrokeAlpha));
-            strokePaint.setColorFilter(filter);
-            strokePaint.setStrokeWidth(mStrokeWidth * strokeScale);
-            canvas.drawPath(path, strokePaint);
-        }
-
-        /**
-         * Applies trimming to the specified path.
-         */
-        private static void applyTrim(TempState temp, Path path, float mTrimPathStart,
-                float mTrimPathEnd, float mTrimPathOffset) {
-            if (mTrimPathStart == 0.0f && mTrimPathEnd == 1.0f) {
-                // No trimming necessary.
-                return;
-            }
-
-            if (temp.mPathMeasure == null) {
-                temp.mPathMeasure = new PathMeasure();
-            }
-            final PathMeasure pathMeasure = temp.mPathMeasure;
-            pathMeasure.setPath(path, false);
-
-            final float len = pathMeasure.getLength();
-            final float start = len * ((mTrimPathStart + mTrimPathOffset) % 1.0f);
-            final float end = len * ((mTrimPathEnd + mTrimPathOffset) % 1.0f);
-            path.reset();
-            if (start > end) {
-                pathMeasure.getSegment(start, len, path, true);
-                pathMeasure.getSegment(0, end, path, true);
-            } else {
-                pathMeasure.getSegment(start, end, path, true);
-            }
-
-            // Fix bug in measure.
-            path.rLineTo(0, 0);
+        public long getNativePtr() {
+            return mNativePtr;
         }
 
         @Override
@@ -1743,7 +1341,45 @@
             a.recycle();
         }
 
+        @Override
+        protected void finalize() throws Throwable {
+            if (mNativePtr != 0) {
+                nDestroy(mNativePtr);
+                mNativePtr = 0;
+            }
+            super.finalize();
+        }
+
         private void updateStateFromTypedArray(TypedArray a) {
+            int byteCount = TOTAL_PROPERTY_COUNT * 4;
+            if (mPropertyData == null) {
+                // Lazy initialization: If the path is created through copy constructor, this may
+                // never get called.
+                mPropertyData = new byte[byteCount];
+            }
+            // The bulk getters/setters of property data (e.g. stroke width, color, etc) allows us
+            // to pull current values from native and store modifications with only two methods,
+            // minimizing JNI overhead.
+            boolean success = nGetFullPathProperties(mNativePtr, mPropertyData, byteCount);
+            if (!success) {
+                throw new RuntimeException("Error: inconsistent property count");
+            }
+
+            ByteBuffer properties = ByteBuffer.wrap(mPropertyData);
+            properties.order(ByteOrder.nativeOrder());
+            float strokeWidth = properties.getFloat(STROKE_WIDTH_INDEX * 4);
+            int strokeColor = properties.getInt(STROKE_COLOR_INDEX * 4);
+            float strokeAlpha = properties.getFloat(STROKE_ALPHA_INDEX * 4);
+            int fillColor =  properties.getInt(FILL_COLOR_INDEX * 4);
+            float fillAlpha = properties.getFloat(FILL_ALPHA_INDEX * 4);
+            float trimPathStart = properties.getFloat(TRIM_PATH_START_INDEX * 4);
+            float trimPathEnd = properties.getFloat(TRIM_PATH_END_INDEX * 4);
+            float trimPathOffset = properties.getFloat(TRIM_PATH_OFFSET_INDEX * 4);
+            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);
+            Shader fillGradient = null;
+            Shader strokeGradient = null;
             // Account for any configuration changes.
             mChangingConfigurations |= a.getChangingConfigurations();
 
@@ -1753,164 +1389,286 @@
             final String pathName = a.getString(R.styleable.VectorDrawablePath_name);
             if (pathName != null) {
                 mPathName = pathName;
+                nSetName(mNativePtr, mPathName);
             }
 
             final String pathString = a.getString(R.styleable.VectorDrawablePath_pathData);
             if (pathString != null) {
                 mPathData = new PathParser.PathData(pathString);
+                nSetPathString(mNativePtr, pathString, pathString.length());
             }
 
-            final ColorStateList fillColors = a.getColorStateList(
+            final ComplexColor fillColors = a.getComplexColor(
                     R.styleable.VectorDrawablePath_fillColor);
             if (fillColors != null) {
-                // If the color state list isn't stateful, discard the state
-                // list and keep the default (e.g. the only) color.
-                mFillColors = fillColors.isStateful() ? fillColors : null;
-                mFillColor = fillColors.getDefaultColor();
+                // If the colors is a gradient color, or the color state list is stateful, keep the
+                // colors information. Otherwise, discard the colors and keep the default color.
+                if (fillColors instanceof  GradientColor) {
+                    mFillColors = fillColors;
+                    fillGradient = ((GradientColor) fillColors).getShader();
+                } else if (fillColors.isStateful()) {
+                    mFillColors = fillColors;
+                } else {
+                    mFillColors = null;
+                }
+                fillColor = fillColors.getDefaultColor();
             }
 
-            final ColorStateList strokeColors = a.getColorStateList(
+            final ComplexColor strokeColors = a.getComplexColor(
                     R.styleable.VectorDrawablePath_strokeColor);
             if (strokeColors != null) {
-                // If the color state list isn't stateful, discard the state
-                // list and keep the default (e.g. the only) color.
-                mStrokeColors = strokeColors.isStateful() ? strokeColors : null;
-                mStrokeColor = strokeColors.getDefaultColor();
+                // If the colors is a gradient color, or the color state list is stateful, keep the
+                // colors information. Otherwise, discard the colors and keep the default color.
+                if (strokeColors instanceof GradientColor) {
+                    mStrokeColors = strokeColors;
+                    strokeGradient = ((GradientColor) strokeColors).getShader();
+                } else if (strokeColors.isStateful()) {
+                    mStrokeColors = strokeColors;
+                } else {
+                    mStrokeColors = null;
+                }
+                strokeColor = strokeColors.getDefaultColor();
             }
+            // Update the gradient info, even if the gradiet is null.
+            nUpdateFullPathFillGradient(mNativePtr,
+                    fillGradient != null ? fillGradient.getNativeInstance() : 0);
+            nUpdateFullPathStrokeGradient(mNativePtr,
+                    strokeGradient != null ? strokeGradient.getNativeInstance() : 0);
 
-            mFillAlpha = a.getFloat(R.styleable.VectorDrawablePath_fillAlpha, mFillAlpha);
-            mStrokeLineCap = getStrokeLineCap(a.getInt(
-                    R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
-            mStrokeLineJoin = getStrokeLineJoin(a.getInt(
-                    R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
-            mStrokeMiterlimit = a.getFloat(
-                    R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
-            mStrokeAlpha = a.getFloat(R.styleable.VectorDrawablePath_strokeAlpha, mStrokeAlpha);
-            mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
-            mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
-            mTrimPathOffset = a.getFloat(
-                    R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
-            mTrimPathStart = a.getFloat(
-                    R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
+            fillAlpha = a.getFloat(R.styleable.VectorDrawablePath_fillAlpha, fillAlpha);
+
+            strokeLineCap = a.getInt(
+                    R.styleable.VectorDrawablePath_strokeLineCap, strokeLineCap);
+            strokeLineJoin = a.getInt(
+                    R.styleable.VectorDrawablePath_strokeLineJoin, strokeLineJoin);
+            strokeMiterLimit = a.getFloat(
+                    R.styleable.VectorDrawablePath_strokeMiterLimit, strokeMiterLimit);
+            strokeAlpha = a.getFloat(R.styleable.VectorDrawablePath_strokeAlpha,
+                    strokeAlpha);
+            strokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth,
+                    strokeWidth);
+            trimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd,
+                    trimPathEnd);
+            trimPathOffset = a.getFloat(
+                    R.styleable.VectorDrawablePath_trimPathOffset, trimPathOffset);
+            trimPathStart = a.getFloat(
+                    R.styleable.VectorDrawablePath_trimPathStart, trimPathStart);
+
+            nUpdateFullPathProperties(mNativePtr, strokeWidth, strokeColor, strokeAlpha,
+                    fillColor, fillAlpha, trimPathStart, trimPathEnd, trimPathOffset,
+                    strokeMiterLimit, strokeLineCap, strokeLineJoin);
         }
 
         @Override
         public boolean canApplyTheme() {
-            return mThemeAttrs != null;
+            if (mThemeAttrs != null) {
+                return true;
+            }
+            boolean fillCanApplyTheme = canGradientApplyTheme(mFillColors);
+            boolean strokeCanApplyTheme = canGradientApplyTheme(mStrokeColors);
+            if (fillCanApplyTheme || strokeCanApplyTheme) {
+                return true;
+            }
+            return false;
+
         }
 
         @Override
         public void applyTheme(Theme t) {
-            if (mThemeAttrs == null) {
-                return;
+            if (mThemeAttrs != null) {
+                final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawablePath);
+                updateStateFromTypedArray(a);
+                a.recycle();
             }
 
-            final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawablePath);
-            updateStateFromTypedArray(a);
-            a.recycle();
+            boolean fillCanApplyTheme = canGradientApplyTheme(mFillColors);
+            boolean strokeCanApplyTheme = canGradientApplyTheme(mStrokeColors);
+            if (fillCanApplyTheme) {
+                mFillColors = mFillColors.obtainForTheme(t);
+                nUpdateFullPathFillGradient(mNativePtr,
+                        ((GradientColor)mFillColors).getShader().getNativeInstance());
+            }
+
+            if (strokeCanApplyTheme) {
+                mStrokeColors = mStrokeColors.obtainForTheme(t);
+                nUpdateFullPathStrokeGradient(mNativePtr,
+                        ((GradientColor)mStrokeColors).getShader().getNativeInstance());
+            }
+        }
+
+        private boolean canGradientApplyTheme(ComplexColor complexColor) {
+            return complexColor != null && complexColor.canApplyTheme()
+                    && complexColor instanceof GradientColor;
         }
 
         /* Setters and Getters, used by animator from AnimatedVectorDrawable. */
         @SuppressWarnings("unused")
         int getStrokeColor() {
-            return mStrokeColor;
+            return nGetStrokeColor(mNativePtr);
         }
 
         @SuppressWarnings("unused")
         void setStrokeColor(int strokeColor) {
             mStrokeColors = null;
-            mStrokeColor = strokeColor;
+            nSetStrokeColor(mNativePtr, strokeColor);
         }
 
         @SuppressWarnings("unused")
         float getStrokeWidth() {
-            return mStrokeWidth;
+            return nGetStrokeWidth(mNativePtr);
         }
 
         @SuppressWarnings("unused")
         void setStrokeWidth(float strokeWidth) {
-            mStrokeWidth = strokeWidth;
+            nSetStrokeWidth(mNativePtr, strokeWidth);
         }
 
         @SuppressWarnings("unused")
         float getStrokeAlpha() {
-            return mStrokeAlpha;
+            return nGetStrokeAlpha(mNativePtr);
         }
 
         @SuppressWarnings("unused")
         void setStrokeAlpha(float strokeAlpha) {
-            mStrokeAlpha = strokeAlpha;
+            nSetStrokeAlpha(mNativePtr, strokeAlpha);
         }
 
         @SuppressWarnings("unused")
         int getFillColor() {
-            return mFillColor;
+            return nGetFillColor(mNativePtr);
         }
 
         @SuppressWarnings("unused")
         void setFillColor(int fillColor) {
             mFillColors = null;
-            mFillColor = fillColor;
+            nSetFillColor(mNativePtr, fillColor);
         }
 
         @SuppressWarnings("unused")
         float getFillAlpha() {
-            return mFillAlpha;
+            return nGetFillAlpha(mNativePtr);
         }
 
         @SuppressWarnings("unused")
         void setFillAlpha(float fillAlpha) {
-            mFillAlpha = fillAlpha;
+            nSetFillAlpha(mNativePtr, fillAlpha);
         }
 
         @SuppressWarnings("unused")
         float getTrimPathStart() {
-            return mTrimPathStart;
+            return nGetTrimPathStart(mNativePtr);
         }
 
         @SuppressWarnings("unused")
         void setTrimPathStart(float trimPathStart) {
-            mTrimPathStart = trimPathStart;
+            nSetTrimPathStart(mNativePtr, trimPathStart);
         }
 
         @SuppressWarnings("unused")
         float getTrimPathEnd() {
-            return mTrimPathEnd;
+            return nGetTrimPathEnd(mNativePtr);
         }
 
         @SuppressWarnings("unused")
         void setTrimPathEnd(float trimPathEnd) {
-            mTrimPathEnd = trimPathEnd;
+            nSetTrimPathEnd(mNativePtr, trimPathEnd);
         }
 
         @SuppressWarnings("unused")
         float getTrimPathOffset() {
-            return mTrimPathOffset;
+            return nGetTrimPathOffset(mNativePtr);
         }
 
         @SuppressWarnings("unused")
         void setTrimPathOffset(float trimPathOffset) {
-            mTrimPathOffset = trimPathOffset;
+            nSetTrimPathOffset(mNativePtr, trimPathOffset);
         }
     }
 
-    static class TempState {
-        final Matrix pathMatrix = new Matrix();
-        final Path path = new Path();
-        final Path renderPath = new Path();
-
-        PathMeasure mPathMeasure;
-        Paint mFillPaint;
-        Paint mStrokePaint;
-    }
-
     interface VObject {
-        void draw(Canvas canvas, TempState temp, Matrix currentMatrix,
-                ColorFilter filter, float scaleX, float scaleY);
+        long getNativePtr();
         void inflate(Resources r, AttributeSet attrs, Theme theme);
         boolean canApplyTheme();
         void applyTheme(Theme t);
         boolean onStateChange(int[] state);
         boolean isStateful();
     }
+
+    private static native long nCreateRenderer(long rootGroupPtr);
+    private static native void nDestroyRenderer(long rendererPtr);
+    private static native void nSetRendererViewportSize(long rendererPtr, float viewportWidth,
+            float viewportHeight);
+    private static native boolean nSetRootAlpha(long rendererPtr, float alpha);
+    private static native float nGetRootAlpha(long rendererPtr);
+    private static native void nSetAllowCaching(long rendererPtr, boolean allowCaching);
+
+    private static native void nDraw(long rendererPtr, long canvasWrapperPtr,
+            long colorFilterPtr, Rect bounds, boolean needsMirroring, boolean canReuseCache);
+    private static native long nCreateFullPath();
+    private static native long nCreateFullPath(long mNativeFullPathPtr);
+    private static native boolean nGetFullPathProperties(long pathPtr, byte[] properties,
+            int length);
+
+    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);
+    private static native void nUpdateFullPathFillGradient(long pathPtr, long fillGradientPtr);
+    private static native void nUpdateFullPathStrokeGradient(long pathPtr, long strokeGradientPtr);
+
+    private static native long nCreateClipPath();
+    private static native long nCreateClipPath(long clipPathPtr);
+
+    private static native long nCreateGroup();
+    private static native long nCreateGroup(long groupPtr);
+    private static native void nDestroy(long nodePtr);
+    private static native void nSetName(long nodePtr, String name);
+    private static native boolean nGetGroupProperties(long groupPtr, float[] properties,
+            int length);
+    private static native void nUpdateGroupProperties(long groupPtr, float rotate, float pivotX,
+            float pivotY, float scaleX, float scaleY, float translateX, float translateY);
+
+    private static native void nAddChild(long groupPtr, long nodePtr);
+    private static native void nSetPathString(long pathPtr, String pathString, int length);
+
+    /**
+     * 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.
+    private static native float nGetRotation(long groupPtr);
+    private static native void nSetRotation(long groupPtr, float rotation);
+    private static native float nGetPivotX(long groupPtr);
+    private static native void nSetPivotX(long groupPtr, float pivotX);
+    private static native float nGetPivotY(long groupPtr);
+    private static native void nSetPivotY(long groupPtr, float pivotY);
+    private static native float nGetScaleX(long groupPtr);
+    private static native void nSetScaleX(long groupPtr, float scaleX);
+    private static native float nGetScaleY(long groupPtr);
+    private static native void nSetScaleY(long groupPtr, float scaleY);
+    private static native float nGetTranslateX(long groupPtr);
+    private static native void nSetTranslateX(long groupPtr, float translateX);
+    private static native float nGetTranslateY(long groupPtr);
+    private static native void nSetTranslateY(long groupPtr, float translateY);
+
+    // Setters and getters for VPath during animation.
+    private static native void nSetPathData(long pathPtr, long pathDataPtr);
+    private static native float nGetStrokeWidth(long pathPtr);
+    private static native void nSetStrokeWidth(long pathPtr, float width);
+    private static native int nGetStrokeColor(long pathPtr);
+    private static native void nSetStrokeColor(long pathPtr, int strokeColor);
+    private static native float nGetStrokeAlpha(long pathPtr);
+    private static native void nSetStrokeAlpha(long pathPtr, float alpha);
+    private static native int nGetFillColor(long pathPtr);
+    private static native void nSetFillColor(long pathPtr, int fillColor);
+    private static native float nGetFillAlpha(long pathPtr);
+    private static native void nSetFillAlpha(long pathPtr, float fillAlpha);
+    private static native float nGetTrimPathStart(long pathPtr);
+    private static native void nSetTrimPathStart(long pathPtr, float trimPathStart);
+    private static native float nGetTrimPathEnd(long pathPtr);
+    private static native void nSetTrimPathEnd(long pathPtr, float trimPathEnd);
+    private static native float nGetTrimPathOffset(long pathPtr);
+    private static native void nSetTrimPathOffset(long pathPtr, float trimPathOffset);
 }
diff --git a/include/androidfw/AssetManager.h b/include/androidfw/AssetManager.h
index 3d4e47d..914ac3d 100644
--- a/include/androidfw/AssetManager.h
+++ b/include/androidfw/AssetManager.h
@@ -100,16 +100,17 @@
      * then on success, *cookie is set to the value corresponding to the
      * newly-added asset source.
      */
-    bool addAssetPath(const String8& path, int32_t* cookie, bool appAsLib=false);
+    bool addAssetPath(const String8& path, int32_t* cookie,
+        bool appAsLib=false, bool isSystemAsset=false);
     bool addOverlayPath(const String8& path, int32_t* cookie);
 
-    /*                                                                       
+    /*
      * Convenience for adding the standard system assets.  Uses the
      * ANDROID_ROOT environment variable to find them.
      */
     bool addDefaultAssets();
 
-    /*                                                                       
+    /*
      * Iterate over the asset paths in this manager.  (Previously
      * added via addAssetPath() and addDefaultAssets().)  On first call,
      * 'cookie' must be 0, resulting in the first cookie being returned.
@@ -118,7 +119,7 @@
      */
     int32_t nextAssetPath(const int32_t cookie) const;
 
-    /*                                                                       
+    /*
      * Return an asset path in the manager.  'which' must be between 0 and
      * countAssetPaths().
      */
@@ -221,11 +222,11 @@
      * the current data.
      */
     bool isUpToDate();
-    
+
     /**
      * Get the known locales for this asset manager object.
      */
-    void getLocales(Vector<String8>* locales) const;
+    void getLocales(Vector<String8>* locales, bool includeSystemLocales=true) const;
 
     /**
      * Generate idmap data to translate resources IDs between a package and a
@@ -237,11 +238,13 @@
 private:
     struct asset_path
     {
-        asset_path() : path(""), type(kFileTypeRegular), idmap(""), isSystemOverlay(false) {}
+        asset_path() : path(""), type(kFileTypeRegular), idmap(""),
+                       isSystemOverlay(false), isSystemAsset(false) {}
         String8 path;
         FileType type;
         String8 idmap;
         bool isSystemOverlay;
+        bool isSystemAsset;
     };
 
     Asset* openInPathLocked(const char* fileName, AccessMode mode,
diff --git a/include/androidfw/DisplayEventDispatcher.h b/include/androidfw/DisplayEventDispatcher.h
new file mode 100644
index 0000000..3ade215
--- /dev/null
+++ b/include/androidfw/DisplayEventDispatcher.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/DisplayEventReceiver.h>
+#include <utils/Log.h>
+#include <utils/Looper.h>
+
+namespace android {
+
+class DisplayEventDispatcher : public LooperCallback {
+public:
+    DisplayEventDispatcher(const sp<Looper>& looper);
+
+    status_t initialize();
+    void dispose();
+    status_t scheduleVsync();
+
+protected:
+    virtual ~DisplayEventDispatcher() = default;
+
+private:
+    sp<Looper> mLooper;
+    DisplayEventReceiver mReceiver;
+    bool mWaitingForVsync;
+
+    virtual void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) = 0;
+    virtual void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected) = 0;
+
+    virtual int handleEvent(int receiveFd, int events, void* data);
+    bool processPendingEvents(nsecs_t* outTimestamp, int32_t* id, uint32_t* outCount);
+};
+}
diff --git a/include/androidfw/LocaleData.h b/include/androidfw/LocaleData.h
new file mode 100644
index 0000000..add0ab5
--- /dev/null
+++ b/include/androidfw/LocaleData.h
@@ -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.
+ */
+
+#ifndef _LIBS_UTILS_LOCALE_DATA_H
+#define _LIBS_UTILS_LOCALE_DATA_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace android {
+
+int localeDataCompareRegions(
+        const char* left_region, const char* right_region,
+        const char* requested_language, const char* requested_script,
+        const char* requested_region);
+
+void localeDataComputeScript(char out[4], const char* language, const char* region);
+
+} // namespace android
+
+#endif // _LIBS_UTILS_LOCALE_DATA_H
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index 49b6333..d8801b8 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -21,6 +21,7 @@
 #define _LIBS_UTILS_RESOURCE_TYPES_H
 
 #include <androidfw/Asset.h>
+#include <androidfw/LocaleData.h>
 #include <utils/ByteOrder.h>
 #include <utils/Errors.h>
 #include <utils/String16.h>
@@ -1128,7 +1129,7 @@
     // the locale field.
     char localeScript[4];
 
-    // A single BCP-47 variant subtag. Will vary in length between 5 and 8
+    // A single BCP-47 variant subtag. Will vary in length between 4 and 8
     // chars. Interpreted in conjunction with the locale field.
     char localeVariant[8];
 
@@ -1150,6 +1151,10 @@
         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;
+
     void copyFromDeviceNoSwap(const ResTable_config& o);
     
     void copyFromDtoH(const ResTable_config& o);
@@ -1228,10 +1233,15 @@
 
     inline void clearLocale() {
         locale = 0;
+        localeScriptWasProvided = false;
         memset(localeScript, 0, sizeof(localeScript));
         memset(localeVariant, 0, sizeof(localeVariant));
     }
 
+    inline void computeScript() {
+        localeDataComputeScript(localeScript, language, country);
+    }
+
     // Get the 2 or 3 letter language code of this configuration. Trailing
     // bytes are set to '\0'.
     size_t unpackLanguage(char language[4]) const;
@@ -1255,6 +1265,12 @@
     // and 0 if they're equally specific.
     int isLocaleMoreSpecificThan(const ResTable_config &o) const;
 
+    // Return true if 'this' is a better locale match than 'o' for the
+    // 'requested' configuration. Similar to isBetterThan(), this assumes that
+    // match() has already been used to remove any configurations that don't
+    // match the requested configuration at all.
+    bool isLocaleBetterThan(const ResTable_config& o, const ResTable_config* requested) const;
+
     String8 toString() const;
 };
 
@@ -1552,9 +1568,9 @@
 
     status_t add(Asset* asset, const int32_t cookie=-1, bool copyData=false);
     status_t add(Asset* asset, Asset* idmapAsset, const int32_t cookie=-1, bool copyData=false,
-            bool appAsLib=false);
+            bool appAsLib=false, bool isSystemAsset=false);
 
-    status_t add(ResTable* src);
+    status_t add(ResTable* src, bool isSystemAsset=false);
     status_t addEmpty(const int32_t cookie);
 
     status_t getError() const;
@@ -1822,9 +1838,9 @@
 
     // Return the configurations (ResTable_config) that we know about
     void getConfigurations(Vector<ResTable_config>* configs, bool ignoreMipmap=false,
-            bool ignoreAndroidPackage=false) const;
+            bool ignoreAndroidPackage=false, bool includeSystemConfigs=true) const;
 
-    void getLocales(Vector<String8>* locales) const;
+    void getLocales(Vector<String8>* locales, bool includeSystemLocales=true) const;
 
     // Generate an idmap.
     //
@@ -1860,7 +1876,7 @@
     typedef Vector<Type*> TypeList;
 
     status_t addInternal(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
-            bool appAsLib, const int32_t cookie, bool copyData);
+            bool appAsLib, const int32_t cookie, bool copyData, bool isSystemAsset=false);
 
     ssize_t getResourcePackageIndex(uint32_t resID) const;
 
@@ -1873,10 +1889,11 @@
             size_t nameLen, uint32_t* outTypeSpecFlags) const;
 
     status_t parsePackage(
-        const ResTable_package* const pkg, const Header* const header, bool appAsLib);
+        const ResTable_package* const pkg, const Header* const header,
+        bool appAsLib, bool isSystemAsset);
 
     void print_value(const Package* pkg, const Res_value& value) const;
-    
+
     mutable Mutex               mLock;
 
     status_t                    mError;
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 40fb0d3..7adad8a 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -350,7 +350,7 @@
 
     /**
      * Returns the {@code PrivateKey} for the requested alias, or null
-     * if no there is no result.
+     * if there is no result.
      *
      * <p> This method may block while waiting for a connection to another process, and must never
      * be called from the main thread.
@@ -371,7 +371,7 @@
             final IKeyChainService keyChainService = keyChainConnection.getService();
             final String keyId = keyChainService.requestPrivateKey(alias);
             if (keyId == null) {
-                throw new KeyChainException("keystore had a problem");
+                return null;
             }
             return AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore(
                     KeyStore.getInstance(), keyId, KeyStore.UID_SELF);
diff --git a/libs/androidfw/Android.mk b/libs/androidfw/Android.mk
index f682fb8..6bbfcd2 100644
--- a/libs/androidfw/Android.mk
+++ b/libs/androidfw/Android.mk
@@ -21,6 +21,7 @@
     Asset.cpp \
     AssetDir.cpp \
     AssetManager.cpp \
+    LocaleData.cpp \
     misc.cpp \
     ObbFile.cpp \
     ResourceTypes.cpp \
@@ -33,7 +34,8 @@
     $(commonSources) \
     BackupData.cpp \
     BackupHelpers.cpp \
-    CursorWindow.cpp
+    CursorWindow.cpp \
+    DisplayEventDispatcher.cpp
 
 hostSources := $(commonSources)
 
@@ -65,6 +67,7 @@
     libbinder \
     liblog \
     libcutils \
+    libgui \
     libutils \
     libz
 
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 8a03b94..6913f43 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -176,7 +176,8 @@
     delete[] mVendor;
 }
 
-bool AssetManager::addAssetPath(const String8& path, int32_t* cookie, bool appAsLib)
+bool AssetManager::addAssetPath(
+        const String8& path, int32_t* cookie, bool appAsLib, bool isSystemAsset)
 {
     AutoMutex _l(mLock);
 
@@ -222,6 +223,7 @@
     }
     delete manifestAsset;
 
+    ap.isSystemAsset = isSystemAsset;
     mAssetPaths.add(ap);
 
     // new paths are always added at the end
@@ -233,6 +235,7 @@
     // Load overlays, if any
     asset_path oap;
     for (size_t idx = 0; mZipSet.getOverlay(ap.path, idx, &oap); idx++) {
+        oap.isSystemAsset = isSystemAsset;
         mAssetPaths.add(oap);
     }
 #endif
@@ -340,7 +343,7 @@
     String8 path(root);
     path.appendPath(kSystemAssets);
 
-    return addAssetPath(path, NULL);
+    return addAssetPath(path, NULL, false /* appAsLib */, true /* isSystemAsset */);
 }
 
 int32_t AssetManager::nextAssetPath(const int32_t cookie) const
@@ -682,10 +685,10 @@
         ALOGV("Installing resource asset %p in to table %p\n", ass, mResources);
         if (sharedRes != NULL) {
             ALOGV("Copying existing resources for %s", ap.path.string());
-            mResources->add(sharedRes);
+            mResources->add(sharedRes, ap.isSystemAsset);
         } else {
             ALOGV("Parsing resources for %s", ap.path.string());
-            mResources->add(ass, idmap, nextEntryIdx + 1, !shared, appAsLib);
+            mResources->add(ass, idmap, nextEntryIdx + 1, !shared, appAsLib, ap.isSystemAsset);
         }
         onlyEmptyResources = false;
 
@@ -831,11 +834,11 @@
     return mZipSet.isUpToDate();
 }
 
-void AssetManager::getLocales(Vector<String8>* locales) const
+void AssetManager::getLocales(Vector<String8>* locales, bool includeSystemLocales) const
 {
     ResTable* res = mResources;
     if (res != NULL) {
-        res->getLocales(locales);
+        res->getLocales(locales, includeSystemLocales);
     }
 
     const size_t numLocales = locales->size();
diff --git a/libs/androidfw/DisplayEventDispatcher.cpp b/libs/androidfw/DisplayEventDispatcher.cpp
new file mode 100644
index 0000000..b8ef9ea
--- /dev/null
+++ b/libs/androidfw/DisplayEventDispatcher.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "DisplayEventDispatcher"
+
+#include <cinttypes>
+#include <cstdint>
+
+#include <androidfw/DisplayEventDispatcher.h>
+#include <gui/DisplayEventReceiver.h>
+#include <utils/Log.h>
+#include <utils/Looper.h>
+
+#include <utils/Timers.h>
+
+namespace android {
+
+// Number of events to read at a time from the DisplayEventDispatcher pipe.
+// The value should be large enough that we can quickly drain the pipe
+// using just a few large reads.
+static const size_t EVENT_BUFFER_SIZE = 100;
+
+DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper) :
+        mLooper(looper), mWaitingForVsync(false) {
+    ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
+}
+
+status_t DisplayEventDispatcher::initialize() {
+    status_t result = mReceiver.initCheck();
+    if (result) {
+        ALOGW("Failed to initialize display event receiver, status=%d", result);
+        return result;
+    }
+
+    int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT,
+            this, NULL);
+    if (rc < 0) {
+        return UNKNOWN_ERROR;
+    }
+    return OK;
+}
+
+void DisplayEventDispatcher::dispose() {
+    ALOGV("dispatcher %p ~ Disposing display event dispatcher.", this);
+
+    if (!mReceiver.initCheck()) {
+        mLooper->removeFd(mReceiver.getFd());
+    }
+}
+
+status_t DisplayEventDispatcher::scheduleVsync() {
+    if (!mWaitingForVsync) {
+        ALOGV("dispatcher %p ~ Scheduling vsync.", this);
+
+        // Drain all pending events.
+        nsecs_t vsyncTimestamp;
+        int32_t vsyncDisplayId;
+        uint32_t vsyncCount;
+        if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
+            ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "",
+                    this, ns2ms(static_cast<nsecs_t>(vsyncTimestamp)));
+        }
+
+        status_t status = mReceiver.requestNextVsync();
+        if (status) {
+            ALOGW("Failed to request next vsync, status=%d", status);
+            return status;
+        }
+
+        mWaitingForVsync = true;
+    }
+    return OK;
+}
+
+int DisplayEventDispatcher::handleEvent(int, int events, void*) {
+    if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
+        ALOGE("Display event receiver pipe was closed or an error occurred.  "
+                "events=0x%x", events);
+        return 0; // remove the callback
+    }
+
+    if (!(events & Looper::EVENT_INPUT)) {
+        ALOGW("Received spurious callback for unhandled poll event.  "
+                "events=0x%x", events);
+        return 1; // keep the callback
+    }
+
+    // Drain all pending events, keep the last vsync.
+    nsecs_t vsyncTimestamp;
+    int32_t vsyncDisplayId;
+    uint32_t vsyncCount;
+    if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
+        ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64 ", id=%d, count=%d",
+                this, ns2ms(vsyncTimestamp), vsyncDisplayId, vsyncCount);
+        mWaitingForVsync = false;
+        dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
+    }
+
+    return 1; // keep the callback
+}
+
+bool DisplayEventDispatcher::processPendingEvents(
+        nsecs_t* outTimestamp, int32_t* outId, uint32_t* outCount) {
+    bool gotVsync = false;
+    DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
+    ssize_t n;
+    while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
+        ALOGV("dispatcher %p ~ Read %d events.", this, int(n));
+        for (ssize_t i = 0; i < n; i++) {
+            const DisplayEventReceiver::Event& ev = buf[i];
+            switch (ev.header.type) {
+            case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
+                // Later vsync events will just overwrite the info from earlier
+                // ones. That's fine, we only care about the most recent.
+                gotVsync = true;
+                *outTimestamp = ev.header.timestamp;
+                *outId = ev.header.id;
+                *outCount = ev.vsync.count;
+                break;
+            case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
+                dispatchHotplug(ev.header.timestamp, ev.header.id, ev.hotplug.connected);
+                break;
+            default:
+                ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type);
+                break;
+            }
+        }
+    }
+    if (n < 0) {
+        ALOGW("Failed to get events from display event dispatcher, status=%d", status_t(n));
+    }
+    return gotVsync;
+}
+}
diff --git a/libs/androidfw/LocaleData.cpp b/libs/androidfw/LocaleData.cpp
new file mode 100644
index 0000000..c0c3ab8
--- /dev/null
+++ b/libs/androidfw/LocaleData.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <androidfw/LocaleData.h>
+
+namespace android {
+
+#include "LocaleDataTables.cpp"
+
+inline uint32_t packLocale(const char* language, const char* region) {
+    return (((uint8_t) language[0]) << 24u) | (((uint8_t) language[1]) << 16u) |
+           (((uint8_t) region[0]) << 8u) | ((uint8_t) region[1]);
+}
+
+inline uint32_t dropRegion(uint32_t packed_locale) {
+    return packed_locale & 0xFFFF0000lu;
+}
+
+inline bool hasRegion(uint32_t packed_locale) {
+    return (packed_locale & 0x0000FFFFlu) != 0;
+}
+
+const size_t SCRIPT_LENGTH = 4;
+const size_t SCRIPT_PARENTS_COUNT = sizeof(SCRIPT_PARENTS)/sizeof(SCRIPT_PARENTS[0]);
+const uint32_t PACKED_ROOT = 0; // to represent the root locale
+
+uint32_t findParent(uint32_t packed_locale, const char* script) {
+    if (hasRegion(packed_locale)) {
+        for (size_t i = 0; i < SCRIPT_PARENTS_COUNT; i++) {
+            if (memcmp(script, SCRIPT_PARENTS[i].script, SCRIPT_LENGTH) == 0) {
+                auto map = SCRIPT_PARENTS[i].map;
+                auto lookup_result = map->find(packed_locale);
+                if (lookup_result != map->end()) {
+                    return lookup_result->second;
+                }
+                break;
+            }
+        }
+        return dropRegion(packed_locale);
+    }
+    return PACKED_ROOT;
+}
+
+// Find the ancestors of a locale, and fill 'out' with it (assumes out has enough
+// space). If any of the members of stop_list was seen, write it in the
+// output but stop afterwards.
+//
+// This also outputs the index of the last written ancestor in the stop_list
+// to stop_list_index, which will be -1 if it is not found in the stop_list.
+//
+// Returns the number of ancestors written in the output, which is always
+// at least one.
+size_t findAncestors(uint32_t* out, ssize_t* stop_list_index,
+                     uint32_t packed_locale, const char* script,
+                     const uint32_t* stop_list, size_t stop_set_length) {
+    uint32_t ancestor = packed_locale;
+    size_t count = 0;
+    do {
+        out[count++] = ancestor;
+        for (size_t i = 0; i < stop_set_length; i++) {
+            if (stop_list[i] == ancestor) {
+                *stop_list_index = (ssize_t) i;
+                return count;
+            }
+        }
+        ancestor = findParent(ancestor, script);
+    } while (ancestor != PACKED_ROOT);
+    *stop_list_index = (ssize_t) -1;
+    return count;
+}
+
+size_t findDistance(uint32_t supported,
+                    const char* script,
+                    const uint32_t* request_ancestors,
+                    size_t request_ancestors_count) {
+    uint32_t supported_ancestors[MAX_PARENT_DEPTH+1];
+    ssize_t request_ancestors_index;
+    const size_t supported_ancestor_count = findAncestors(
+            supported_ancestors, &request_ancestors_index,
+            supported, script,
+            request_ancestors, request_ancestors_count);
+    // Since both locales share the same root, there will always be a shared
+    // ancestor, so the distance in the parent tree is the sum of the distance
+    // of 'supported' to the lowest common ancestor (number of ancestors
+    // written for 'supported' minus 1) plus the distance of 'request' to the
+    // lowest common ancestor (the index of the ancestor in request_ancestors).
+    return supported_ancestor_count + request_ancestors_index - 1;
+}
+
+inline bool isRepresentative(uint32_t language_and_region, const char* script) {
+    const uint64_t packed_locale = (
+            (((uint64_t) language_and_region) << 32u) |
+            (((uint64_t) script[0]) << 24u) |
+            (((uint64_t) script[1]) << 16u) |
+            (((uint64_t) script[2]) <<  8u) |
+            ((uint64_t) script[3]));
+
+    return (REPRESENTATIVE_LOCALES.count(packed_locale) != 0);
+}
+
+int localeDataCompareRegions(
+        const char* left_region, const char* right_region,
+        const char* requested_language, const char* requested_script,
+        const char* requested_region) {
+
+    if (left_region[0] == right_region[0] && left_region[1] == right_region[1]) {
+        return 0;
+    }
+    const uint32_t left = packLocale(requested_language, left_region);
+    const uint32_t right = packLocale(requested_language, right_region);
+    const uint32_t request = packLocale(requested_language, requested_region);
+
+    uint32_t request_ancestors[MAX_PARENT_DEPTH+1];
+    ssize_t left_right_index;
+    // Find the parents of the request, but stop as soon as we saw left or right
+    const uint32_t left_and_right[] = {left, right};
+    const size_t ancestor_count = findAncestors(
+            request_ancestors, &left_right_index,
+            request, requested_script,
+            left_and_right, sizeof(left_and_right)/sizeof(left_and_right[0]));
+    if (left_right_index == 0) { // We saw left earlier
+        return 1;
+    }
+    if (left_right_index == 1) { // We saw right earlier
+        return -1;
+    }
+
+    // If we are here, neither left nor right are an ancestor of the
+    // request. This means that all the ancestors have been computed and
+    // the last ancestor is just the language by itself. We will use the
+    // distance in the parent tree for determining the better match.
+    const size_t left_distance = findDistance(
+            left, requested_script, request_ancestors, ancestor_count);
+    const size_t right_distance = findDistance(
+            right, requested_script, request_ancestors, ancestor_count);
+    if (left_distance != right_distance) {
+        return (int) right_distance - (int) left_distance; // smaller distance is better
+    }
+
+    // If we are here, left and right are equidistant from the request. We will
+    // try and see if any of them is a representative locale.
+    const bool left_is_representative = isRepresentative(left, requested_script);
+    const bool right_is_representative = isRepresentative(right, requested_script);
+    if (left_is_representative != right_is_representative) {
+        return (int) left_is_representative - (int) right_is_representative;
+    }
+
+    // We have no way of figuring out which locale is a better match. For
+    // the sake of stability, we consider the locale with the lower region
+    // code (in dictionary order) better, with two-letter codes before
+    // three-digit codes (since two-letter codes are more specific).
+    return (int64_t) right - (int64_t) left;
+}
+
+void localeDataComputeScript(char out[4], const char* language, const char* region) {
+    if (language[0] == '\0') {
+        memset(out, '\0', SCRIPT_LENGTH);
+        return;
+    }
+    uint32_t lookup_key = packLocale(language, region);
+    auto lookup_result = LIKELY_SCRIPTS.find(lookup_key);
+    if (lookup_result == LIKELY_SCRIPTS.end()) {
+        // We couldn't find the locale. Let's try without the region
+        if (region[0] != '\0') {
+            lookup_key = dropRegion(lookup_key);
+            lookup_result = LIKELY_SCRIPTS.find(lookup_key);
+            if (lookup_result != LIKELY_SCRIPTS.end()) {
+                memcpy(out, SCRIPT_CODES[lookup_result->second], SCRIPT_LENGTH);
+                return;
+            }
+        }
+        // We don't know anything about the locale
+        memset(out, '\0', SCRIPT_LENGTH);
+        return;
+    } else {
+        // We found the locale.
+        memcpy(out, SCRIPT_CODES[lookup_result->second], SCRIPT_LENGTH);
+    }
+}
+
+} // namespace android
diff --git a/libs/androidfw/LocaleDataTables.cpp b/libs/androidfw/LocaleDataTables.cpp
new file mode 100644
index 0000000..1ac5085
--- /dev/null
+++ b/libs/androidfw/LocaleDataTables.cpp
@@ -0,0 +1,1701 @@
+// Auto-generated by frameworks/base/tools/localedata/extract_icu_data.py
+
+const char SCRIPT_CODES[][4] = {
+    /* 0  */ {'A', 'h', 'o', 'm'},
+    /* 1  */ {'A', 'r', 'a', 'b'},
+    /* 2  */ {'A', 'r', 'm', 'i'},
+    /* 3  */ {'A', 'r', 'm', 'n'},
+    /* 4  */ {'A', 'v', 's', 't'},
+    /* 5  */ {'B', 'a', 'm', 'u'},
+    /* 6  */ {'B', 'a', 's', 's'},
+    /* 7  */ {'B', 'e', 'n', 'g'},
+    /* 8  */ {'B', 'r', 'a', 'h'},
+    /* 9  */ {'C', 'a', 'n', 's'},
+    /* 10 */ {'C', 'a', 'r', 'i'},
+    /* 11 */ {'C', 'h', 'a', 'm'},
+    /* 12 */ {'C', 'h', 'e', 'r'},
+    /* 13 */ {'C', 'o', 'p', 't'},
+    /* 14 */ {'C', 'p', 'r', 't'},
+    /* 15 */ {'C', 'y', 'r', 'l'},
+    /* 16 */ {'D', 'e', 'v', 'a'},
+    /* 17 */ {'E', 'g', 'y', 'p'},
+    /* 18 */ {'E', 't', 'h', 'i'},
+    /* 19 */ {'G', 'e', 'o', 'r'},
+    /* 20 */ {'G', 'o', 't', 'h'},
+    /* 21 */ {'G', 'r', 'e', 'k'},
+    /* 22 */ {'G', 'u', 'j', 'r'},
+    /* 23 */ {'G', 'u', 'r', 'u'},
+    /* 24 */ {'H', 'a', 'n', 's'},
+    /* 25 */ {'H', 'a', 'n', 't'},
+    /* 26 */ {'H', 'a', 't', 'r'},
+    /* 27 */ {'H', 'e', 'b', 'r'},
+    /* 28 */ {'H', 'l', 'u', 'w'},
+    /* 29 */ {'H', 'm', 'n', 'g'},
+    /* 30 */ {'I', 't', 'a', 'l'},
+    /* 31 */ {'J', 'p', 'a', 'n'},
+    /* 32 */ {'K', 'a', 'l', 'i'},
+    /* 33 */ {'K', 'a', 'n', 'a'},
+    /* 34 */ {'K', 'h', 'a', 'r'},
+    /* 35 */ {'K', 'h', 'm', 'r'},
+    /* 36 */ {'K', 'n', 'd', 'a'},
+    /* 37 */ {'K', 'o', 'r', 'e'},
+    /* 38 */ {'K', 't', 'h', 'i'},
+    /* 39 */ {'L', 'a', 'n', 'a'},
+    /* 40 */ {'L', 'a', 'o', 'o'},
+    /* 41 */ {'L', 'a', 't', 'n'},
+    /* 42 */ {'L', 'e', 'p', 'c'},
+    /* 43 */ {'L', 'i', 'n', 'a'},
+    /* 44 */ {'L', 'i', 's', 'u'},
+    /* 45 */ {'L', 'y', 'c', 'i'},
+    /* 46 */ {'L', 'y', 'd', 'i'},
+    /* 47 */ {'M', 'a', 'n', 'd'},
+    /* 48 */ {'M', 'a', 'n', 'i'},
+    /* 49 */ {'M', 'e', 'r', 'c'},
+    /* 50 */ {'M', 'l', 'y', 'm'},
+    /* 51 */ {'M', 'o', 'n', 'g'},
+    /* 52 */ {'M', 'r', 'o', 'o'},
+    /* 53 */ {'M', 'y', 'm', 'r'},
+    /* 54 */ {'N', 'a', 'r', 'b'},
+    /* 55 */ {'N', 'k', 'o', 'o'},
+    /* 56 */ {'O', 'g', 'a', 'm'},
+    /* 57 */ {'O', 'r', 'k', 'h'},
+    /* 58 */ {'O', 'r', 'y', 'a'},
+    /* 59 */ {'P', 'a', 'u', 'c'},
+    /* 60 */ {'P', 'h', 'l', 'i'},
+    /* 61 */ {'P', 'h', 'n', 'x'},
+    /* 62 */ {'P', 'l', 'r', 'd'},
+    /* 63 */ {'P', 'r', 't', 'i'},
+    /* 64 */ {'R', 'u', 'n', 'r'},
+    /* 65 */ {'S', 'a', 'm', 'r'},
+    /* 66 */ {'S', 'a', 'r', 'b'},
+    /* 67 */ {'S', 'a', 'u', 'r'},
+    /* 68 */ {'S', 'g', 'n', 'w'},
+    /* 69 */ {'S', 'i', 'n', 'h'},
+    /* 70 */ {'S', 'o', 'r', 'a'},
+    /* 71 */ {'S', 'y', 'r', 'c'},
+    /* 72 */ {'T', 'a', 'l', 'e'},
+    /* 73 */ {'T', 'a', 'l', 'u'},
+    /* 74 */ {'T', 'a', 'm', 'l'},
+    /* 75 */ {'T', 'a', 'v', 't'},
+    /* 76 */ {'T', 'e', 'l', 'u'},
+    /* 77 */ {'T', 'f', 'n', 'g'},
+    /* 78 */ {'T', 'h', 'a', 'a'},
+    /* 79 */ {'T', 'h', 'a', 'i'},
+    /* 80 */ {'T', 'i', 'b', 't'},
+    /* 81 */ {'U', 'g', 'a', 'r'},
+    /* 82 */ {'V', 'a', 'i', 'i'},
+    /* 83 */ {'X', 'p', 'e', 'o'},
+    /* 84 */ {'X', 's', 'u', 'x'},
+    /* 85 */ {'Y', 'i', 'i', 'i'},
+    /* 86 */ {'~', '~', '~', 'A'},
+    /* 87 */ {'~', '~', '~', 'B'},
+};
+
+
+const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
+    {0x61610000u, 41u}, // aa -> Latn
+    {0x61620000u, 15u}, // ab -> Cyrl
+    {0xC4200000u, 41u}, // abr -> Latn
+    {0x90400000u, 41u}, // ace -> Latn
+    {0x9C400000u, 41u}, // ach -> Latn
+    {0x80600000u, 41u}, // ada -> Latn
+    {0xE0600000u, 15u}, // ady -> Cyrl
+    {0x61650000u,  4u}, // ae -> Avst
+    {0x84800000u,  1u}, // aeb -> Arab
+    {0x61660000u, 41u}, // af -> Latn
+    {0xC0C00000u, 41u}, // agq -> Latn
+    {0xB8E00000u,  0u}, // aho -> Ahom
+    {0x616B0000u, 41u}, // ak -> Latn
+    {0xA9400000u, 84u}, // akk -> Xsux
+    {0xB5600000u, 41u}, // aln -> Latn
+    {0xCD600000u, 15u}, // alt -> Cyrl
+    {0x616D0000u, 18u}, // am -> Ethi
+    {0xB9800000u, 41u}, // amo -> Latn
+    {0xE5C00000u, 41u}, // aoz -> Latn
+    {0x61720000u,  1u}, // ar -> Arab
+    {0x61725842u, 87u}, // ar-XB -> ~~~B
+    {0x8A200000u,  2u}, // arc -> Armi
+    {0xB6200000u, 41u}, // arn -> Latn
+    {0xBA200000u, 41u}, // aro -> Latn
+    {0xC2200000u,  1u}, // arq -> Arab
+    {0xE2200000u,  1u}, // ary -> Arab
+    {0xE6200000u,  1u}, // arz -> Arab
+    {0x61730000u,  7u}, // as -> Beng
+    {0x82400000u, 41u}, // asa -> Latn
+    {0x92400000u, 68u}, // ase -> Sgnw
+    {0xCE400000u, 41u}, // ast -> Latn
+    {0xA6600000u, 41u}, // atj -> Latn
+    {0x61760000u, 15u}, // av -> Cyrl
+    {0x82C00000u, 16u}, // awa -> Deva
+    {0x61790000u, 41u}, // ay -> Latn
+    {0x617A0000u, 41u}, // az -> Latn
+    {0x617A4951u,  1u}, // az-IQ -> Arab
+    {0x617A4952u,  1u}, // az-IR -> Arab
+    {0x617A5255u, 15u}, // az-RU -> Cyrl
+    {0x62610000u, 15u}, // ba -> Cyrl
+    {0xAC010000u,  1u}, // bal -> Arab
+    {0xB4010000u, 41u}, // ban -> Latn
+    {0xBC010000u, 16u}, // bap -> Deva
+    {0xC4010000u, 41u}, // bar -> Latn
+    {0xC8010000u, 41u}, // bas -> Latn
+    {0xDC010000u,  5u}, // bax -> Bamu
+    {0x88210000u, 41u}, // bbc -> Latn
+    {0xA4210000u, 41u}, // bbj -> Latn
+    {0xA0410000u, 41u}, // bci -> Latn
+    {0x62650000u, 15u}, // be -> Cyrl
+    {0xA4810000u,  1u}, // bej -> Arab
+    {0xB0810000u, 41u}, // bem -> Latn
+    {0xD8810000u, 41u}, // bew -> Latn
+    {0xE4810000u, 41u}, // bez -> Latn
+    {0x8CA10000u, 41u}, // bfd -> Latn
+    {0xC0A10000u, 74u}, // bfq -> Taml
+    {0xCCA10000u,  1u}, // bft -> Arab
+    {0xE0A10000u, 16u}, // bfy -> Deva
+    {0x62670000u, 15u}, // bg -> Cyrl
+    {0x88C10000u, 16u}, // bgc -> Deva
+    {0xB4C10000u,  1u}, // bgn -> Arab
+    {0xDCC10000u, 21u}, // bgx -> Grek
+    {0x62680000u, 38u}, // bh -> Kthi
+    {0x84E10000u, 16u}, // bhb -> Deva
+    {0xA0E10000u, 16u}, // bhi -> Deva
+    {0xA8E10000u, 41u}, // bhk -> Latn
+    {0xB8E10000u, 16u}, // bho -> Deva
+    {0x62690000u, 41u}, // bi -> Latn
+    {0xA9010000u, 41u}, // bik -> Latn
+    {0xB5010000u, 41u}, // bin -> Latn
+    {0xA5210000u, 16u}, // bjj -> Deva
+    {0xB5210000u, 41u}, // bjn -> Latn
+    {0xB1410000u, 41u}, // bkm -> Latn
+    {0xD1410000u, 41u}, // bku -> Latn
+    {0xCD610000u, 75u}, // blt -> Tavt
+    {0x626D0000u, 41u}, // bm -> Latn
+    {0xC1810000u, 41u}, // bmq -> Latn
+    {0x626E0000u,  7u}, // bn -> Beng
+    {0x626F0000u, 80u}, // bo -> Tibt
+    {0xE1E10000u,  7u}, // bpy -> Beng
+    {0xA2010000u,  1u}, // bqi -> Arab
+    {0xD6010000u, 41u}, // bqv -> Latn
+    {0x62720000u, 41u}, // br -> Latn
+    {0x82210000u, 16u}, // bra -> Deva
+    {0x9E210000u,  1u}, // brh -> Arab
+    {0xDE210000u, 16u}, // brx -> Deva
+    {0x62730000u, 41u}, // bs -> Latn
+    {0xC2410000u,  6u}, // bsq -> Bass
+    {0xCA410000u, 41u}, // bss -> Latn
+    {0xBA610000u, 41u}, // bto -> Latn
+    {0xD6610000u, 16u}, // btv -> Deva
+    {0x82810000u, 15u}, // bua -> Cyrl
+    {0x8A810000u, 41u}, // buc -> Latn
+    {0x9A810000u, 41u}, // bug -> Latn
+    {0xB2810000u, 41u}, // bum -> Latn
+    {0x86A10000u, 41u}, // bvb -> Latn
+    {0xB7010000u, 18u}, // byn -> Ethi
+    {0xD7010000u, 41u}, // byv -> Latn
+    {0x93210000u, 41u}, // bze -> Latn
+    {0x63610000u, 41u}, // ca -> Latn
+    {0x9C420000u, 41u}, // cch -> Latn
+    {0xBC420000u,  7u}, // ccp -> Beng
+    {0x63650000u, 15u}, // ce -> Cyrl
+    {0x84820000u, 41u}, // ceb -> Latn
+    {0x98C20000u, 41u}, // cgg -> Latn
+    {0x63680000u, 41u}, // ch -> Latn
+    {0xA8E20000u, 41u}, // chk -> Latn
+    {0xB0E20000u, 15u}, // chm -> Cyrl
+    {0xB8E20000u, 41u}, // cho -> Latn
+    {0xBCE20000u, 41u}, // chp -> Latn
+    {0xC4E20000u, 12u}, // chr -> Cher
+    {0x81220000u,  1u}, // cja -> Arab
+    {0xB1220000u, 11u}, // cjm -> Cham
+    {0x85420000u,  1u}, // ckb -> Arab
+    {0x636F0000u, 41u}, // co -> Latn
+    {0xBDC20000u, 13u}, // cop -> Copt
+    {0xC9E20000u, 41u}, // cps -> Latn
+    {0x63720000u,  9u}, // cr -> Cans
+    {0xA6220000u,  9u}, // crj -> Cans
+    {0xAA220000u,  9u}, // crk -> Cans
+    {0xAE220000u,  9u}, // crl -> Cans
+    {0xB2220000u,  9u}, // crm -> Cans
+    {0xCA220000u, 41u}, // crs -> Latn
+    {0x63730000u, 41u}, // cs -> Latn
+    {0x86420000u, 41u}, // csb -> Latn
+    {0xDA420000u,  9u}, // csw -> Cans
+    {0x8E620000u, 59u}, // ctd -> Pauc
+    {0x63750000u, 15u}, // cu -> Cyrl
+    {0x63760000u, 15u}, // cv -> Cyrl
+    {0x63790000u, 41u}, // cy -> Latn
+    {0x64610000u, 41u}, // da -> Latn
+    {0xA8030000u, 41u}, // dak -> Latn
+    {0xC4030000u, 15u}, // dar -> Cyrl
+    {0xD4030000u, 41u}, // dav -> Latn
+    {0x88430000u,  1u}, // dcc -> Arab
+    {0x64650000u, 41u}, // de -> Latn
+    {0xB4830000u, 41u}, // den -> Latn
+    {0xC4C30000u, 41u}, // dgr -> Latn
+    {0x91230000u, 41u}, // dje -> Latn
+    {0xA5A30000u, 41u}, // dnj -> Latn
+    {0xA1C30000u,  1u}, // doi -> Arab
+    {0x86430000u, 41u}, // dsb -> Latn
+    {0xB2630000u, 41u}, // dtm -> Latn
+    {0xBE630000u, 41u}, // dtp -> Latn
+    {0x82830000u, 41u}, // dua -> Latn
+    {0x64760000u, 78u}, // dv -> Thaa
+    {0xBB030000u, 41u}, // dyo -> Latn
+    {0xD3030000u, 41u}, // dyu -> Latn
+    {0x647A0000u, 80u}, // dz -> Tibt
+    {0xD0240000u, 41u}, // ebu -> Latn
+    {0x65650000u, 41u}, // ee -> Latn
+    {0xA0A40000u, 41u}, // efi -> Latn
+    {0xACC40000u, 41u}, // egl -> Latn
+    {0xE0C40000u, 17u}, // egy -> Egyp
+    {0xE1440000u, 32u}, // eky -> Kali
+    {0x656C0000u, 21u}, // el -> Grek
+    {0x656E0000u, 41u}, // en -> Latn
+    {0x656E5841u, 86u}, // en-XA -> ~~~A
+    {0x656F0000u, 41u}, // eo -> Latn
+    {0x65730000u, 41u}, // es -> Latn
+    {0xD2440000u, 41u}, // esu -> Latn
+    {0x65740000u, 41u}, // et -> Latn
+    {0xCE640000u, 30u}, // ett -> Ital
+    {0x65750000u, 41u}, // eu -> Latn
+    {0xBAC40000u, 41u}, // ewo -> Latn
+    {0xCEE40000u, 41u}, // ext -> Latn
+    {0x66610000u,  1u}, // fa -> Arab
+    {0xB4050000u, 41u}, // fan -> Latn
+    {0x66660000u, 41u}, // ff -> Latn
+    {0xB0A50000u, 41u}, // ffm -> Latn
+    {0x66690000u, 41u}, // fi -> Latn
+    {0x81050000u,  1u}, // fia -> Arab
+    {0xAD050000u, 41u}, // fil -> Latn
+    {0xCD050000u, 41u}, // fit -> Latn
+    {0x666A0000u, 41u}, // fj -> Latn
+    {0x666F0000u, 41u}, // fo -> Latn
+    {0xB5C50000u, 41u}, // fon -> Latn
+    {0x66720000u, 41u}, // fr -> Latn
+    {0x8A250000u, 41u}, // frc -> Latn
+    {0xBE250000u, 41u}, // frp -> Latn
+    {0xC6250000u, 41u}, // frr -> Latn
+    {0xCA250000u, 41u}, // frs -> Latn
+    {0x8E850000u, 41u}, // fud -> Latn
+    {0xC2850000u, 41u}, // fuq -> Latn
+    {0xC6850000u, 41u}, // fur -> Latn
+    {0xD6850000u, 41u}, // fuv -> Latn
+    {0xC6A50000u, 41u}, // fvr -> Latn
+    {0x66790000u, 41u}, // fy -> Latn
+    {0x67610000u, 41u}, // ga -> Latn
+    {0x80060000u, 41u}, // gaa -> Latn
+    {0x98060000u, 41u}, // gag -> Latn
+    {0xB4060000u, 24u}, // gan -> Hans
+    {0xE0060000u, 41u}, // gay -> Latn
+    {0xB0260000u, 16u}, // gbm -> Deva
+    {0xE4260000u,  1u}, // gbz -> Arab
+    {0xC4460000u, 41u}, // gcr -> Latn
+    {0x67640000u, 41u}, // gd -> Latn
+    {0xE4860000u, 18u}, // gez -> Ethi
+    {0xB4C60000u, 16u}, // ggn -> Deva
+    {0xAD060000u, 41u}, // gil -> Latn
+    {0xA9260000u,  1u}, // gjk -> Arab
+    {0xD1260000u,  1u}, // gju -> Arab
+    {0x676C0000u, 41u}, // gl -> Latn
+    {0xA9660000u,  1u}, // glk -> Arab
+    {0x676E0000u, 41u}, // gn -> Latn
+    {0xB1C60000u, 16u}, // gom -> Deva
+    {0xB5C60000u, 76u}, // gon -> Telu
+    {0xC5C60000u, 41u}, // gor -> Latn
+    {0xC9C60000u, 41u}, // gos -> Latn
+    {0xCDC60000u, 20u}, // got -> Goth
+    {0x8A260000u, 14u}, // grc -> Cprt
+    {0xCE260000u,  7u}, // grt -> Beng
+    {0xDA460000u, 41u}, // gsw -> Latn
+    {0x67750000u, 22u}, // gu -> Gujr
+    {0x86860000u, 41u}, // gub -> Latn
+    {0x8A860000u, 41u}, // guc -> Latn
+    {0xC6860000u, 41u}, // gur -> Latn
+    {0xE6860000u, 41u}, // guz -> Latn
+    {0x67760000u, 41u}, // gv -> Latn
+    {0xC6A60000u, 16u}, // gvr -> Deva
+    {0xA2C60000u, 41u}, // gwi -> Latn
+    {0x68610000u, 41u}, // ha -> Latn
+    {0x6861434Du,  1u}, // ha-CM -> Arab
+    {0x68615344u,  1u}, // ha-SD -> Arab
+    {0xA8070000u, 24u}, // hak -> Hans
+    {0xD8070000u, 41u}, // haw -> Latn
+    {0xE4070000u,  1u}, // haz -> Arab
+    {0x68650000u, 27u}, // he -> Hebr
+    {0x68690000u, 16u}, // hi -> Deva
+    {0x95070000u, 41u}, // hif -> Latn
+    {0xAD070000u, 41u}, // hil -> Latn
+    {0xD1670000u, 28u}, // hlu -> Hluw
+    {0x8D870000u, 62u}, // hmd -> Plrd
+    {0x8DA70000u,  1u}, // hnd -> Arab
+    {0x91A70000u, 16u}, // hne -> Deva
+    {0xA5A70000u, 29u}, // hnj -> Hmng
+    {0xB5A70000u, 41u}, // hnn -> Latn
+    {0xB9A70000u,  1u}, // hno -> Arab
+    {0x686F0000u, 41u}, // ho -> Latn
+    {0x89C70000u, 16u}, // hoc -> Deva
+    {0xA5C70000u, 16u}, // hoj -> Deva
+    {0x68720000u, 41u}, // hr -> Latn
+    {0x86470000u, 41u}, // hsb -> Latn
+    {0xB6470000u, 24u}, // hsn -> Hans
+    {0x68740000u, 41u}, // ht -> Latn
+    {0x68750000u, 41u}, // hu -> Latn
+    {0x68790000u,  3u}, // hy -> Armn
+    {0x687A0000u, 41u}, // hz -> Latn
+    {0x69610000u, 41u}, // ia -> Latn
+    {0x80280000u, 41u}, // iba -> Latn
+    {0x84280000u, 41u}, // ibb -> Latn
+    {0x69640000u, 41u}, // id -> Latn
+    {0x69670000u, 41u}, // ig -> Latn
+    {0x69690000u, 85u}, // ii -> Yiii
+    {0x696B0000u, 41u}, // ik -> Latn
+    {0xCD480000u, 41u}, // ikt -> Latn
+    {0xB9680000u, 41u}, // ilo -> Latn
+    {0x696E0000u, 41u}, // in -> Latn
+    {0x9DA80000u, 15u}, // inh -> Cyrl
+    {0x69730000u, 41u}, // is -> Latn
+    {0x69740000u, 41u}, // it -> Latn
+    {0x69750000u,  9u}, // iu -> Cans
+    {0x69770000u, 27u}, // iw -> Hebr
+    {0x9F280000u, 41u}, // izh -> Latn
+    {0x6A610000u, 31u}, // ja -> Jpan
+    {0xB0090000u, 41u}, // jam -> Latn
+    {0xB8C90000u, 41u}, // jgo -> Latn
+    {0x6A690000u, 27u}, // ji -> Hebr
+    {0x89890000u, 41u}, // jmc -> Latn
+    {0xAD890000u, 16u}, // jml -> Deva
+    {0xCE890000u, 41u}, // jut -> Latn
+    {0x6A760000u, 41u}, // jv -> Latn
+    {0x6A770000u, 41u}, // jw -> Latn
+    {0x6B610000u, 19u}, // ka -> Geor
+    {0x800A0000u, 15u}, // kaa -> Cyrl
+    {0x840A0000u, 41u}, // kab -> Latn
+    {0x880A0000u, 41u}, // kac -> Latn
+    {0xA40A0000u, 41u}, // kaj -> Latn
+    {0xB00A0000u, 41u}, // kam -> Latn
+    {0xB80A0000u, 41u}, // kao -> Latn
+    {0x8C2A0000u, 15u}, // kbd -> Cyrl
+    {0x984A0000u, 41u}, // kcg -> Latn
+    {0xA84A0000u, 41u}, // kck -> Latn
+    {0x906A0000u, 41u}, // kde -> Latn
+    {0xCC6A0000u, 79u}, // kdt -> Thai
+    {0x808A0000u, 41u}, // kea -> Latn
+    {0xB48A0000u, 41u}, // ken -> Latn
+    {0xB8AA0000u, 41u}, // kfo -> Latn
+    {0xC4AA0000u, 16u}, // kfr -> Deva
+    {0xE0AA0000u, 16u}, // kfy -> Deva
+    {0x6B670000u, 41u}, // kg -> Latn
+    {0x90CA0000u, 41u}, // kge -> Latn
+    {0xBCCA0000u, 41u}, // kgp -> Latn
+    {0x80EA0000u, 41u}, // kha -> Latn
+    {0x84EA0000u, 73u}, // khb -> Talu
+    {0xB4EA0000u, 16u}, // khn -> Deva
+    {0xC0EA0000u, 41u}, // khq -> Latn
+    {0xCCEA0000u, 53u}, // kht -> Mymr
+    {0xD8EA0000u,  1u}, // khw -> Arab
+    {0x6B690000u, 41u}, // ki -> Latn
+    {0xD10A0000u, 41u}, // kiu -> Latn
+    {0x6B6A0000u, 41u}, // kj -> Latn
+    {0x992A0000u, 40u}, // kjg -> Laoo
+    {0x6B6B0000u, 15u}, // kk -> Cyrl
+    {0x6B6B4146u,  1u}, // kk-AF -> Arab
+    {0x6B6B434Eu,  1u}, // kk-CN -> Arab
+    {0x6B6B4952u,  1u}, // kk-IR -> Arab
+    {0x6B6B4D4Eu,  1u}, // kk-MN -> Arab
+    {0xA54A0000u, 41u}, // kkj -> Latn
+    {0x6B6C0000u, 41u}, // kl -> Latn
+    {0xB56A0000u, 41u}, // kln -> Latn
+    {0x6B6D0000u, 35u}, // km -> Khmr
+    {0x858A0000u, 41u}, // kmb -> Latn
+    {0x6B6E0000u, 36u}, // kn -> Knda
+    {0x6B6F0000u, 37u}, // ko -> Kore
+    {0xA1CA0000u, 15u}, // koi -> Cyrl
+    {0xA9CA0000u, 16u}, // kok -> Deva
+    {0xC9CA0000u, 41u}, // kos -> Latn
+    {0x91EA0000u, 41u}, // kpe -> Latn
+    {0x8A2A0000u, 15u}, // krc -> Cyrl
+    {0xA22A0000u, 41u}, // kri -> Latn
+    {0xA62A0000u, 41u}, // krj -> Latn
+    {0xAE2A0000u, 41u}, // krl -> Latn
+    {0xD22A0000u, 16u}, // kru -> Deva
+    {0x6B730000u,  1u}, // ks -> Arab
+    {0x864A0000u, 41u}, // ksb -> Latn
+    {0x964A0000u, 41u}, // ksf -> Latn
+    {0x9E4A0000u, 41u}, // ksh -> Latn
+    {0x6B750000u, 41u}, // ku -> Latn
+    {0x6B754952u,  1u}, // ku-IR -> Arab
+    {0x6B754C42u,  1u}, // ku-LB -> Arab
+    {0xB28A0000u, 15u}, // kum -> Cyrl
+    {0x6B760000u, 15u}, // kv -> Cyrl
+    {0xC6AA0000u, 41u}, // kvr -> Latn
+    {0xDEAA0000u,  1u}, // kvx -> Arab
+    {0x6B770000u, 41u}, // kw -> Latn
+    {0xB2EA0000u, 79u}, // kxm -> Thai
+    {0xBEEA0000u,  1u}, // kxp -> Arab
+    {0x6B790000u, 15u}, // ky -> Cyrl
+    {0x6B79434Eu,  1u}, // ky-CN -> Arab
+    {0x6B795452u, 41u}, // ky-TR -> Latn
+    {0x6C610000u, 41u}, // la -> Latn
+    {0x840B0000u, 43u}, // lab -> Lina
+    {0x8C0B0000u, 27u}, // lad -> Hebr
+    {0x980B0000u, 41u}, // lag -> Latn
+    {0x9C0B0000u,  1u}, // lah -> Arab
+    {0xA40B0000u, 41u}, // laj -> Latn
+    {0x6C620000u, 41u}, // lb -> Latn
+    {0x902B0000u, 15u}, // lbe -> Cyrl
+    {0xD82B0000u, 41u}, // lbw -> Latn
+    {0xBC4B0000u, 79u}, // lcp -> Thai
+    {0xBC8B0000u, 42u}, // lep -> Lepc
+    {0xE48B0000u, 15u}, // lez -> Cyrl
+    {0x6C670000u, 41u}, // lg -> Latn
+    {0x6C690000u, 41u}, // li -> Latn
+    {0x950B0000u, 16u}, // lif -> Deva
+    {0xA50B0000u, 41u}, // lij -> Latn
+    {0xC90B0000u, 44u}, // lis -> Lisu
+    {0xBD2B0000u, 41u}, // ljp -> Latn
+    {0xA14B0000u,  1u}, // lki -> Arab
+    {0xCD4B0000u, 41u}, // lkt -> Latn
+    {0xB58B0000u, 76u}, // lmn -> Telu
+    {0xB98B0000u, 41u}, // lmo -> Latn
+    {0x6C6E0000u, 41u}, // ln -> Latn
+    {0x6C6F0000u, 40u}, // lo -> Laoo
+    {0xADCB0000u, 41u}, // lol -> Latn
+    {0xE5CB0000u, 41u}, // loz -> Latn
+    {0x8A2B0000u,  1u}, // lrc -> Arab
+    {0x6C740000u, 41u}, // lt -> Latn
+    {0x9A6B0000u, 41u}, // ltg -> Latn
+    {0x6C750000u, 41u}, // lu -> Latn
+    {0x828B0000u, 41u}, // lua -> Latn
+    {0xBA8B0000u, 41u}, // luo -> Latn
+    {0xE28B0000u, 41u}, // luy -> Latn
+    {0xE68B0000u,  1u}, // luz -> Arab
+    {0x6C760000u, 41u}, // lv -> Latn
+    {0xAECB0000u, 79u}, // lwl -> Thai
+    {0x9F2B0000u, 24u}, // lzh -> Hans
+    {0xE72B0000u, 41u}, // lzz -> Latn
+    {0x8C0C0000u, 41u}, // mad -> Latn
+    {0x940C0000u, 41u}, // maf -> Latn
+    {0x980C0000u, 16u}, // mag -> Deva
+    {0xA00C0000u, 16u}, // mai -> Deva
+    {0xA80C0000u, 41u}, // mak -> Latn
+    {0xB40C0000u, 41u}, // man -> Latn
+    {0xB40C474Eu, 55u}, // man-GN -> Nkoo
+    {0xC80C0000u, 41u}, // mas -> Latn
+    {0xE40C0000u, 41u}, // maz -> Latn
+    {0x946C0000u, 15u}, // mdf -> Cyrl
+    {0x9C6C0000u, 41u}, // mdh -> Latn
+    {0xC46C0000u, 41u}, // mdr -> Latn
+    {0xB48C0000u, 41u}, // men -> Latn
+    {0xC48C0000u, 41u}, // mer -> Latn
+    {0x80AC0000u,  1u}, // mfa -> Arab
+    {0x90AC0000u, 41u}, // mfe -> Latn
+    {0x6D670000u, 41u}, // mg -> Latn
+    {0x9CCC0000u, 41u}, // mgh -> Latn
+    {0xB8CC0000u, 41u}, // mgo -> Latn
+    {0xBCCC0000u, 16u}, // mgp -> Deva
+    {0xE0CC0000u, 41u}, // mgy -> Latn
+    {0x6D680000u, 41u}, // mh -> Latn
+    {0x6D690000u, 41u}, // mi -> Latn
+    {0xB50C0000u, 41u}, // min -> Latn
+    {0xC90C0000u, 26u}, // mis -> Hatr
+    {0x6D6B0000u, 15u}, // mk -> Cyrl
+    {0x6D6C0000u, 50u}, // ml -> Mlym
+    {0xC96C0000u, 41u}, // mls -> Latn
+    {0x6D6E0000u, 15u}, // mn -> Cyrl
+    {0x6D6E434Eu, 51u}, // mn-CN -> Mong
+    {0xA1AC0000u,  7u}, // mni -> Beng
+    {0xD9AC0000u, 53u}, // mnw -> Mymr
+    {0x91CC0000u, 41u}, // moe -> Latn
+    {0x9DCC0000u, 41u}, // moh -> Latn
+    {0xC9CC0000u, 41u}, // mos -> Latn
+    {0x6D720000u, 16u}, // mr -> Deva
+    {0x8E2C0000u, 16u}, // mrd -> Deva
+    {0xA62C0000u, 15u}, // mrj -> Cyrl
+    {0xD22C0000u, 52u}, // mru -> Mroo
+    {0x6D730000u, 41u}, // ms -> Latn
+    {0x6D734343u,  1u}, // ms-CC -> Arab
+    {0x6D734944u,  1u}, // ms-ID -> Arab
+    {0x6D740000u, 41u}, // mt -> Latn
+    {0xC66C0000u, 16u}, // mtr -> Deva
+    {0x828C0000u, 41u}, // mua -> Latn
+    {0xCA8C0000u, 41u}, // mus -> Latn
+    {0xE2AC0000u,  1u}, // mvy -> Arab
+    {0xAACC0000u, 41u}, // mwk -> Latn
+    {0xC6CC0000u, 16u}, // mwr -> Deva
+    {0xD6CC0000u, 41u}, // mwv -> Latn
+    {0x8AEC0000u, 41u}, // mxc -> Latn
+    {0x6D790000u, 53u}, // my -> Mymr
+    {0xD70C0000u, 15u}, // myv -> Cyrl
+    {0xDF0C0000u, 41u}, // myx -> Latn
+    {0xE70C0000u, 47u}, // myz -> Mand
+    {0xB72C0000u,  1u}, // mzn -> Arab
+    {0x6E610000u, 41u}, // na -> Latn
+    {0xB40D0000u, 24u}, // nan -> Hans
+    {0xBC0D0000u, 41u}, // nap -> Latn
+    {0xC00D0000u, 41u}, // naq -> Latn
+    {0x6E620000u, 41u}, // nb -> Latn
+    {0x9C4D0000u, 41u}, // nch -> Latn
+    {0x6E640000u, 41u}, // nd -> Latn
+    {0x886D0000u, 41u}, // ndc -> Latn
+    {0xC86D0000u, 41u}, // nds -> Latn
+    {0x6E650000u, 16u}, // ne -> Deva
+    {0xD88D0000u, 16u}, // new -> Deva
+    {0x6E670000u, 41u}, // ng -> Latn
+    {0xACCD0000u, 41u}, // ngl -> Latn
+    {0x90ED0000u, 41u}, // nhe -> Latn
+    {0xD8ED0000u, 41u}, // nhw -> Latn
+    {0xA50D0000u, 41u}, // nij -> Latn
+    {0xD10D0000u, 41u}, // niu -> Latn
+    {0xB92D0000u, 41u}, // njo -> Latn
+    {0x6E6C0000u, 41u}, // nl -> Latn
+    {0x998D0000u, 41u}, // nmg -> Latn
+    {0x6E6E0000u, 41u}, // nn -> Latn
+    {0x9DAD0000u, 41u}, // nnh -> Latn
+    {0x6E6F0000u, 41u}, // no -> Latn
+    {0x8DCD0000u, 39u}, // nod -> Lana
+    {0x91CD0000u, 16u}, // noe -> Deva
+    {0xB5CD0000u, 64u}, // non -> Runr
+    {0xBA0D0000u, 55u}, // nqo -> Nkoo
+    {0x6E720000u, 41u}, // nr -> Latn
+    {0xAA4D0000u,  9u}, // nsk -> Cans
+    {0xBA4D0000u, 41u}, // nso -> Latn
+    {0xCA8D0000u, 41u}, // nus -> Latn
+    {0x6E760000u, 41u}, // nv -> Latn
+    {0xC2ED0000u, 41u}, // nxq -> Latn
+    {0x6E790000u, 41u}, // ny -> Latn
+    {0xB30D0000u, 41u}, // nym -> Latn
+    {0xB70D0000u, 41u}, // nyn -> Latn
+    {0xA32D0000u, 41u}, // nzi -> Latn
+    {0x6F630000u, 41u}, // oc -> Latn
+    {0x6F6D0000u, 41u}, // om -> Latn
+    {0x6F720000u, 58u}, // or -> Orya
+    {0x6F730000u, 15u}, // os -> Cyrl
+    {0xAA6E0000u, 57u}, // otk -> Orkh
+    {0x70610000u, 23u}, // pa -> Guru
+    {0x7061504Bu,  1u}, // pa-PK -> Arab
+    {0x980F0000u, 41u}, // pag -> Latn
+    {0xAC0F0000u, 60u}, // pal -> Phli
+    {0xB00F0000u, 41u}, // pam -> Latn
+    {0xBC0F0000u, 41u}, // pap -> Latn
+    {0xD00F0000u, 41u}, // pau -> Latn
+    {0x8C4F0000u, 41u}, // pcd -> Latn
+    {0xB04F0000u, 41u}, // pcm -> Latn
+    {0x886F0000u, 41u}, // pdc -> Latn
+    {0xCC6F0000u, 41u}, // pdt -> Latn
+    {0xB88F0000u, 83u}, // peo -> Xpeo
+    {0xACAF0000u, 41u}, // pfl -> Latn
+    {0xB4EF0000u, 61u}, // phn -> Phnx
+    {0x814F0000u,  8u}, // pka -> Brah
+    {0xB94F0000u, 41u}, // pko -> Latn
+    {0x706C0000u, 41u}, // pl -> Latn
+    {0xC98F0000u, 41u}, // pms -> Latn
+    {0xCDAF0000u, 21u}, // pnt -> Grek
+    {0xB5CF0000u, 41u}, // pon -> Latn
+    {0x822F0000u, 34u}, // pra -> Khar
+    {0x8E2F0000u,  1u}, // prd -> Arab
+    {0x9A2F0000u, 41u}, // prg -> Latn
+    {0x70730000u,  1u}, // ps -> Arab
+    {0x70740000u, 41u}, // pt -> Latn
+    {0xD28F0000u, 41u}, // puu -> Latn
+    {0x71750000u, 41u}, // qu -> Latn
+    {0x8A900000u, 41u}, // quc -> Latn
+    {0x9A900000u, 41u}, // qug -> Latn
+    {0xA4110000u, 16u}, // raj -> Deva
+    {0x94510000u, 41u}, // rcf -> Latn
+    {0xA4910000u, 41u}, // rej -> Latn
+    {0xB4D10000u, 41u}, // rgn -> Latn
+    {0x81110000u, 41u}, // ria -> Latn
+    {0x95110000u, 77u}, // rif -> Tfng
+    {0x95114E4Cu, 41u}, // rif-NL -> Latn
+    {0xC9310000u, 16u}, // rjs -> Deva
+    {0xCD510000u,  7u}, // rkt -> Beng
+    {0x726D0000u, 41u}, // rm -> Latn
+    {0x95910000u, 41u}, // rmf -> Latn
+    {0xB9910000u, 41u}, // rmo -> Latn
+    {0xCD910000u,  1u}, // rmt -> Arab
+    {0xD1910000u, 41u}, // rmu -> Latn
+    {0x726E0000u, 41u}, // rn -> Latn
+    {0x99B10000u, 41u}, // rng -> Latn
+    {0x726F0000u, 41u}, // ro -> Latn
+    {0x85D10000u, 41u}, // rob -> Latn
+    {0x95D10000u, 41u}, // rof -> Latn
+    {0xB2710000u, 41u}, // rtm -> Latn
+    {0x72750000u, 15u}, // ru -> Cyrl
+    {0x92910000u, 15u}, // rue -> Cyrl
+    {0x9A910000u, 41u}, // rug -> Latn
+    {0x72770000u, 41u}, // rw -> Latn
+    {0xAAD10000u, 41u}, // rwk -> Latn
+    {0xD3110000u, 33u}, // ryu -> Kana
+    {0x73610000u, 16u}, // sa -> Deva
+    {0x94120000u, 41u}, // saf -> Latn
+    {0x9C120000u, 15u}, // sah -> Cyrl
+    {0xC0120000u, 41u}, // saq -> Latn
+    {0xC8120000u, 41u}, // sas -> Latn
+    {0xCC120000u, 41u}, // sat -> Latn
+    {0xE4120000u, 67u}, // saz -> Saur
+    {0xBC320000u, 41u}, // sbp -> Latn
+    {0x73630000u, 41u}, // sc -> Latn
+    {0xA8520000u, 16u}, // sck -> Deva
+    {0xB4520000u, 41u}, // scn -> Latn
+    {0xB8520000u, 41u}, // sco -> Latn
+    {0xC8520000u, 41u}, // scs -> Latn
+    {0x73640000u,  1u}, // sd -> Arab
+    {0x88720000u, 41u}, // sdc -> Latn
+    {0x9C720000u,  1u}, // sdh -> Arab
+    {0x73650000u, 41u}, // se -> Latn
+    {0x94920000u, 41u}, // sef -> Latn
+    {0x9C920000u, 41u}, // seh -> Latn
+    {0xA0920000u, 41u}, // sei -> Latn
+    {0xC8920000u, 41u}, // ses -> Latn
+    {0x73670000u, 41u}, // sg -> Latn
+    {0x80D20000u, 56u}, // sga -> Ogam
+    {0xC8D20000u, 41u}, // sgs -> Latn
+    {0x73680000u, 41u}, // sh -> Latn
+    {0xA0F20000u, 77u}, // shi -> Tfng
+    {0xB4F20000u, 53u}, // shn -> Mymr
+    {0x73690000u, 69u}, // si -> Sinh
+    {0x8D120000u, 41u}, // sid -> Latn
+    {0x736B0000u, 41u}, // sk -> Latn
+    {0xC5520000u,  1u}, // skr -> Arab
+    {0x736C0000u, 41u}, // sl -> Latn
+    {0xA1720000u, 41u}, // sli -> Latn
+    {0xE1720000u, 41u}, // sly -> Latn
+    {0x736D0000u, 41u}, // sm -> Latn
+    {0x81920000u, 41u}, // sma -> Latn
+    {0xA5920000u, 41u}, // smj -> Latn
+    {0xB5920000u, 41u}, // smn -> Latn
+    {0xBD920000u, 65u}, // smp -> Samr
+    {0xC9920000u, 41u}, // sms -> Latn
+    {0x736E0000u, 41u}, // sn -> Latn
+    {0xA9B20000u, 41u}, // snk -> Latn
+    {0x736F0000u, 41u}, // so -> Latn
+    {0xD1D20000u, 79u}, // sou -> Thai
+    {0x73710000u, 41u}, // sq -> Latn
+    {0x73720000u, 15u}, // sr -> Cyrl
+    {0x73724D45u, 41u}, // sr-ME -> Latn
+    {0x7372524Fu, 41u}, // sr-RO -> Latn
+    {0x73725255u, 41u}, // sr-RU -> Latn
+    {0x73725452u, 41u}, // sr-TR -> Latn
+    {0x86320000u, 70u}, // srb -> Sora
+    {0xB6320000u, 41u}, // srn -> Latn
+    {0xC6320000u, 41u}, // srr -> Latn
+    {0xDE320000u, 16u}, // srx -> Deva
+    {0x73730000u, 41u}, // ss -> Latn
+    {0xE2520000u, 41u}, // ssy -> Latn
+    {0x73740000u, 41u}, // st -> Latn
+    {0xC2720000u, 41u}, // stq -> Latn
+    {0x73750000u, 41u}, // su -> Latn
+    {0xAA920000u, 41u}, // suk -> Latn
+    {0xCA920000u, 41u}, // sus -> Latn
+    {0x73760000u, 41u}, // sv -> Latn
+    {0x73770000u, 41u}, // sw -> Latn
+    {0x86D20000u,  1u}, // swb -> Arab
+    {0x8AD20000u, 41u}, // swc -> Latn
+    {0x9AD20000u, 41u}, // swg -> Latn
+    {0xD6D20000u, 16u}, // swv -> Deva
+    {0xB6F20000u, 41u}, // sxn -> Latn
+    {0xAF120000u,  7u}, // syl -> Beng
+    {0xC7120000u, 71u}, // syr -> Syrc
+    {0xAF320000u, 41u}, // szl -> Latn
+    {0x74610000u, 74u}, // ta -> Taml
+    {0xA4130000u, 16u}, // taj -> Deva
+    {0xD8330000u, 41u}, // tbw -> Latn
+    {0xE0530000u, 36u}, // tcy -> Knda
+    {0x8C730000u, 72u}, // tdd -> Tale
+    {0x98730000u, 16u}, // tdg -> Deva
+    {0x9C730000u, 16u}, // tdh -> Deva
+    {0x74650000u, 76u}, // te -> Telu
+    {0xB0930000u, 41u}, // tem -> Latn
+    {0xB8930000u, 41u}, // teo -> Latn
+    {0xCC930000u, 41u}, // tet -> Latn
+    {0x74670000u, 15u}, // tg -> Cyrl
+    {0x7467504Bu,  1u}, // tg-PK -> Arab
+    {0x74680000u, 79u}, // th -> Thai
+    {0xACF30000u, 16u}, // thl -> Deva
+    {0xC0F30000u, 16u}, // thq -> Deva
+    {0xC4F30000u, 16u}, // thr -> Deva
+    {0x74690000u, 18u}, // ti -> Ethi
+    {0x99130000u, 18u}, // tig -> Ethi
+    {0xD5130000u, 41u}, // tiv -> Latn
+    {0x746B0000u, 41u}, // tk -> Latn
+    {0xAD530000u, 41u}, // tkl -> Latn
+    {0xC5530000u, 41u}, // tkr -> Latn
+    {0xCD530000u, 16u}, // tkt -> Deva
+    {0x746C0000u, 41u}, // tl -> Latn
+    {0xE1730000u, 41u}, // tly -> Latn
+    {0x9D930000u, 41u}, // tmh -> Latn
+    {0x746E0000u, 41u}, // tn -> Latn
+    {0x746F0000u, 41u}, // to -> Latn
+    {0x99D30000u, 41u}, // tog -> Latn
+    {0xA1F30000u, 41u}, // tpi -> Latn
+    {0x74720000u, 41u}, // tr -> Latn
+    {0xD2330000u, 41u}, // tru -> Latn
+    {0xD6330000u, 41u}, // trv -> Latn
+    {0x74730000u, 41u}, // ts -> Latn
+    {0x8E530000u, 21u}, // tsd -> Grek
+    {0x96530000u, 16u}, // tsf -> Deva
+    {0x9A530000u, 41u}, // tsg -> Latn
+    {0xA6530000u, 80u}, // tsj -> Tibt
+    {0x74740000u, 15u}, // tt -> Cyrl
+    {0xA6730000u, 41u}, // ttj -> Latn
+    {0xCA730000u, 79u}, // tts -> Thai
+    {0xCE730000u, 41u}, // ttt -> Latn
+    {0xB2930000u, 41u}, // tum -> Latn
+    {0xAEB30000u, 41u}, // tvl -> Latn
+    {0xC2D30000u, 41u}, // twq -> Latn
+    {0x74790000u, 41u}, // ty -> Latn
+    {0xD7130000u, 15u}, // tyv -> Cyrl
+    {0xB3330000u, 41u}, // tzm -> Latn
+    {0xB0740000u, 15u}, // udm -> Cyrl
+    {0x75670000u,  1u}, // ug -> Arab
+    {0x75674B5Au, 15u}, // ug-KZ -> Cyrl
+    {0x75674D4Eu, 15u}, // ug-MN -> Cyrl
+    {0x80D40000u, 81u}, // uga -> Ugar
+    {0x756B0000u, 15u}, // uk -> Cyrl
+    {0xA1740000u, 41u}, // uli -> Latn
+    {0x85940000u, 41u}, // umb -> Latn
+    {0xC5B40000u,  7u}, // unr -> Beng
+    {0xC5B44E50u, 16u}, // unr-NP -> Deva
+    {0xDDB40000u,  7u}, // unx -> Beng
+    {0x75720000u,  1u}, // ur -> Arab
+    {0x757A0000u, 41u}, // uz -> Latn
+    {0x757A4146u,  1u}, // uz-AF -> Arab
+    {0x757A434Eu, 15u}, // uz-CN -> Cyrl
+    {0xA0150000u, 82u}, // vai -> Vaii
+    {0x76650000u, 41u}, // ve -> Latn
+    {0x88950000u, 41u}, // vec -> Latn
+    {0xBC950000u, 41u}, // vep -> Latn
+    {0x76690000u, 41u}, // vi -> Latn
+    {0x89150000u, 41u}, // vic -> Latn
+    {0xC9750000u, 41u}, // vls -> Latn
+    {0x95950000u, 41u}, // vmf -> Latn
+    {0xD9950000u, 41u}, // vmw -> Latn
+    {0x766F0000u, 41u}, // vo -> Latn
+    {0xCDD50000u, 41u}, // vot -> Latn
+    {0xBA350000u, 41u}, // vro -> Latn
+    {0xB6950000u, 41u}, // vun -> Latn
+    {0x77610000u, 41u}, // wa -> Latn
+    {0x90160000u, 41u}, // wae -> Latn
+    {0xAC160000u, 18u}, // wal -> Ethi
+    {0xC4160000u, 41u}, // war -> Latn
+    {0xBC360000u, 41u}, // wbp -> Latn
+    {0xC0360000u, 76u}, // wbq -> Telu
+    {0xC4360000u, 16u}, // wbr -> Deva
+    {0xC9760000u, 41u}, // wls -> Latn
+    {0xA1B60000u,  1u}, // wni -> Arab
+    {0x776F0000u, 41u}, // wo -> Latn
+    {0xB2760000u, 16u}, // wtm -> Deva
+    {0xD2960000u, 24u}, // wuu -> Hans
+    {0xD4170000u, 41u}, // xav -> Latn
+    {0xC4570000u, 10u}, // xcr -> Cari
+    {0x78680000u, 41u}, // xh -> Latn
+    {0x89770000u, 45u}, // xlc -> Lyci
+    {0x8D770000u, 46u}, // xld -> Lydi
+    {0x95970000u, 19u}, // xmf -> Geor
+    {0xB5970000u, 48u}, // xmn -> Mani
+    {0xC5970000u, 49u}, // xmr -> Merc
+    {0x81B70000u, 54u}, // xna -> Narb
+    {0xC5B70000u, 16u}, // xnr -> Deva
+    {0x99D70000u, 41u}, // xog -> Latn
+    {0xC5F70000u, 63u}, // xpr -> Prti
+    {0x82570000u, 66u}, // xsa -> Sarb
+    {0xC6570000u, 16u}, // xsr -> Deva
+    {0xB8180000u, 41u}, // yao -> Latn
+    {0xBC180000u, 41u}, // yap -> Latn
+    {0xD4180000u, 41u}, // yav -> Latn
+    {0x84380000u, 41u}, // ybb -> Latn
+    {0x79690000u, 27u}, // yi -> Hebr
+    {0x796F0000u, 41u}, // yo -> Latn
+    {0xAE380000u, 41u}, // yrl -> Latn
+    {0x82980000u, 41u}, // yua -> Latn
+    {0x7A610000u, 41u}, // za -> Latn
+    {0x98190000u, 41u}, // zag -> Latn
+    {0xA4790000u,  1u}, // zdj -> Arab
+    {0x80990000u, 41u}, // zea -> Latn
+    {0x9CD90000u, 77u}, // zgh -> Tfng
+    {0x7A680000u, 24u}, // zh -> Hans
+    {0x7A684155u, 25u}, // zh-AU -> Hant
+    {0x7A68424Eu, 25u}, // zh-BN -> Hant
+    {0x7A684742u, 25u}, // zh-GB -> Hant
+    {0x7A684746u, 25u}, // zh-GF -> Hant
+    {0x7A68484Bu, 25u}, // zh-HK -> Hant
+    {0x7A684944u, 25u}, // zh-ID -> Hant
+    {0x7A684D4Fu, 25u}, // zh-MO -> Hant
+    {0x7A684D59u, 25u}, // zh-MY -> Hant
+    {0x7A685041u, 25u}, // zh-PA -> Hant
+    {0x7A685046u, 25u}, // zh-PF -> Hant
+    {0x7A685048u, 25u}, // zh-PH -> Hant
+    {0x7A685352u, 25u}, // zh-SR -> Hant
+    {0x7A685448u, 25u}, // zh-TH -> Hant
+    {0x7A685457u, 25u}, // zh-TW -> Hant
+    {0x7A685553u, 25u}, // zh-US -> Hant
+    {0x7A68564Eu, 25u}, // zh-VN -> Hant
+    {0xA1990000u, 41u}, // zmi -> Latn
+    {0x7A750000u, 41u}, // zu -> Latn
+    {0x83390000u, 41u}, // zza -> Latn
+});
+
+std::unordered_set<uint64_t> REPRESENTATIVE_LOCALES({
+    0x616145544C61746Ellu, // aa_Latn_ET
+    0x616247454379726Cllu, // ab_Cyrl_GE
+    0xC42047484C61746Ellu, // abr_Latn_GH
+    0x904049444C61746Ellu, // ace_Latn_ID
+    0x9C4055474C61746Ellu, // ach_Latn_UG
+    0x806047484C61746Ellu, // ada_Latn_GH
+    0xE06052554379726Cllu, // ady_Cyrl_RU
+    0x6165495241767374llu, // ae_Avst_IR
+    0x8480544E41726162llu, // aeb_Arab_TN
+    0x61665A414C61746Ellu, // af_Latn_ZA
+    0xC0C0434D4C61746Ellu, // agq_Latn_CM
+    0xB8E0494E41686F6Dllu, // aho_Ahom_IN
+    0x616B47484C61746Ellu, // ak_Latn_GH
+    0xA940495158737578llu, // akk_Xsux_IQ
+    0xB560584B4C61746Ellu, // aln_Latn_XK
+    0xCD6052554379726Cllu, // alt_Cyrl_RU
+    0x616D455445746869llu, // am_Ethi_ET
+    0xB9804E474C61746Ellu, // amo_Latn_NG
+    0xE5C049444C61746Ellu, // aoz_Latn_ID
+    0x6172454741726162llu, // ar_Arab_EG
+    0x8A20495241726D69llu, // arc_Armi_IR
+    0x8A204A4F4E626174llu, // arc_Nbat_JO
+    0x8A20535950616C6Dllu, // arc_Palm_SY
+    0xB620434C4C61746Ellu, // arn_Latn_CL
+    0xBA20424F4C61746Ellu, // aro_Latn_BO
+    0xC220445A41726162llu, // arq_Arab_DZ
+    0xE2204D4141726162llu, // ary_Arab_MA
+    0xE620454741726162llu, // arz_Arab_EG
+    0x6173494E42656E67llu, // as_Beng_IN
+    0x8240545A4C61746Ellu, // asa_Latn_TZ
+    0x9240555353676E77llu, // ase_Sgnw_US
+    0xCE4045534C61746Ellu, // ast_Latn_ES
+    0xA66043414C61746Ellu, // atj_Latn_CA
+    0x617652554379726Cllu, // av_Cyrl_RU
+    0x82C0494E44657661llu, // awa_Deva_IN
+    0x6179424F4C61746Ellu, // ay_Latn_BO
+    0x617A495241726162llu, // az_Arab_IR
+    0x617A415A4C61746Ellu, // az_Latn_AZ
+    0x626152554379726Cllu, // ba_Cyrl_RU
+    0xAC01504B41726162llu, // bal_Arab_PK
+    0xB40149444C61746Ellu, // ban_Latn_ID
+    0xBC014E5044657661llu, // bap_Deva_NP
+    0xC40141544C61746Ellu, // bar_Latn_AT
+    0xC801434D4C61746Ellu, // bas_Latn_CM
+    0xDC01434D42616D75llu, // bax_Bamu_CM
+    0x882149444C61746Ellu, // bbc_Latn_ID
+    0xA421434D4C61746Ellu, // bbj_Latn_CM
+    0xA04143494C61746Ellu, // bci_Latn_CI
+    0x626542594379726Cllu, // be_Cyrl_BY
+    0xA481534441726162llu, // bej_Arab_SD
+    0xB0815A4D4C61746Ellu, // bem_Latn_ZM
+    0xD88149444C61746Ellu, // bew_Latn_ID
+    0xE481545A4C61746Ellu, // bez_Latn_TZ
+    0x8CA1434D4C61746Ellu, // bfd_Latn_CM
+    0xC0A1494E54616D6Cllu, // bfq_Taml_IN
+    0xCCA1504B41726162llu, // bft_Arab_PK
+    0xE0A1494E44657661llu, // bfy_Deva_IN
+    0x626742474379726Cllu, // bg_Cyrl_BG
+    0x88C1494E44657661llu, // bgc_Deva_IN
+    0xB4C1504B41726162llu, // bgn_Arab_PK
+    0xDCC154524772656Bllu, // bgx_Grek_TR
+    0x6268494E4B746869llu, // bh_Kthi_IN
+    0x84E1494E44657661llu, // bhb_Deva_IN
+    0xA0E1494E44657661llu, // bhi_Deva_IN
+    0xA8E150484C61746Ellu, // bhk_Latn_PH
+    0xB8E1494E44657661llu, // bho_Deva_IN
+    0x626956554C61746Ellu, // bi_Latn_VU
+    0xA90150484C61746Ellu, // bik_Latn_PH
+    0xB5014E474C61746Ellu, // bin_Latn_NG
+    0xA521494E44657661llu, // bjj_Deva_IN
+    0xB52149444C61746Ellu, // bjn_Latn_ID
+    0xB141434D4C61746Ellu, // bkm_Latn_CM
+    0xD14150484C61746Ellu, // bku_Latn_PH
+    0xCD61564E54617674llu, // blt_Tavt_VN
+    0x626D4D4C4C61746Ellu, // bm_Latn_ML
+    0xC1814D4C4C61746Ellu, // bmq_Latn_ML
+    0x626E424442656E67llu, // bn_Beng_BD
+    0x626F434E54696274llu, // bo_Tibt_CN
+    0xE1E1494E42656E67llu, // bpy_Beng_IN
+    0xA201495241726162llu, // bqi_Arab_IR
+    0xD60143494C61746Ellu, // bqv_Latn_CI
+    0x627246524C61746Ellu, // br_Latn_FR
+    0x8221494E44657661llu, // bra_Deva_IN
+    0x9E21504B41726162llu, // brh_Arab_PK
+    0xDE21494E44657661llu, // brx_Deva_IN
+    0x627342414C61746Ellu, // bs_Latn_BA
+    0xC2414C5242617373llu, // bsq_Bass_LR
+    0xCA41434D4C61746Ellu, // bss_Latn_CM
+    0xBA6150484C61746Ellu, // bto_Latn_PH
+    0xD661504B44657661llu, // btv_Deva_PK
+    0x828152554379726Cllu, // bua_Cyrl_RU
+    0x8A8159544C61746Ellu, // buc_Latn_YT
+    0x9A8149444C61746Ellu, // bug_Latn_ID
+    0xB281434D4C61746Ellu, // bum_Latn_CM
+    0x86A147514C61746Ellu, // bvb_Latn_GQ
+    0xB701455245746869llu, // byn_Ethi_ER
+    0xD701434D4C61746Ellu, // byv_Latn_CM
+    0x93214D4C4C61746Ellu, // bze_Latn_ML
+    0x636145534C61746Ellu, // ca_Latn_ES
+    0x9C424E474C61746Ellu, // cch_Latn_NG
+    0xBC42494E42656E67llu, // ccp_Beng_IN
+    0xBC42424443616B6Dllu, // ccp_Cakm_BD
+    0x636552554379726Cllu, // ce_Cyrl_RU
+    0x848250484C61746Ellu, // ceb_Latn_PH
+    0x98C255474C61746Ellu, // cgg_Latn_UG
+    0x636847554C61746Ellu, // ch_Latn_GU
+    0xA8E2464D4C61746Ellu, // chk_Latn_FM
+    0xB0E252554379726Cllu, // chm_Cyrl_RU
+    0xB8E255534C61746Ellu, // cho_Latn_US
+    0xBCE243414C61746Ellu, // chp_Latn_CA
+    0xC4E2555343686572llu, // chr_Cher_US
+    0x81224B4841726162llu, // cja_Arab_KH
+    0xB122564E4368616Dllu, // cjm_Cham_VN
+    0x8542495141726162llu, // ckb_Arab_IQ
+    0x636F46524C61746Ellu, // co_Latn_FR
+    0xBDC24547436F7074llu, // cop_Copt_EG
+    0xC9E250484C61746Ellu, // cps_Latn_PH
+    0x6372434143616E73llu, // cr_Cans_CA
+    0xA622434143616E73llu, // crj_Cans_CA
+    0xAA22434143616E73llu, // crk_Cans_CA
+    0xAE22434143616E73llu, // crl_Cans_CA
+    0xB222434143616E73llu, // crm_Cans_CA
+    0xCA2253434C61746Ellu, // crs_Latn_SC
+    0x6373435A4C61746Ellu, // cs_Latn_CZ
+    0x8642504C4C61746Ellu, // csb_Latn_PL
+    0xDA42434143616E73llu, // csw_Cans_CA
+    0x8E624D4D50617563llu, // ctd_Pauc_MM
+    0x637552554379726Cllu, // cu_Cyrl_RU
+    0x63754247476C6167llu, // cu_Glag_BG
+    0x637652554379726Cllu, // cv_Cyrl_RU
+    0x637947424C61746Ellu, // cy_Latn_GB
+    0x6461444B4C61746Ellu, // da_Latn_DK
+    0xA80355534C61746Ellu, // dak_Latn_US
+    0xC40352554379726Cllu, // dar_Cyrl_RU
+    0xD4034B454C61746Ellu, // dav_Latn_KE
+    0x8843494E41726162llu, // dcc_Arab_IN
+    0x646544454C61746Ellu, // de_Latn_DE
+    0xB48343414C61746Ellu, // den_Latn_CA
+    0xC4C343414C61746Ellu, // dgr_Latn_CA
+    0x91234E454C61746Ellu, // dje_Latn_NE
+    0xA5A343494C61746Ellu, // dnj_Latn_CI
+    0xA1C3494E41726162llu, // doi_Arab_IN
+    0x864344454C61746Ellu, // dsb_Latn_DE
+    0xB2634D4C4C61746Ellu, // dtm_Latn_ML
+    0xBE634D594C61746Ellu, // dtp_Latn_MY
+    0x8283434D4C61746Ellu, // dua_Latn_CM
+    0x64764D5654686161llu, // dv_Thaa_MV
+    0xBB03534E4C61746Ellu, // dyo_Latn_SN
+    0xD30342464C61746Ellu, // dyu_Latn_BF
+    0x647A425454696274llu, // dz_Tibt_BT
+    0xD0244B454C61746Ellu, // ebu_Latn_KE
+    0x656547484C61746Ellu, // ee_Latn_GH
+    0xA0A44E474C61746Ellu, // efi_Latn_NG
+    0xACC449544C61746Ellu, // egl_Latn_IT
+    0xE0C4454745677970llu, // egy_Egyp_EG
+    0xE1444D4D4B616C69llu, // eky_Kali_MM
+    0x656C47524772656Bllu, // el_Grek_GR
+    0x656E47424C61746Ellu, // en_Latn_GB
+    0x656E55534C61746Ellu, // en_Latn_US
+    0x656E474253686177llu, // en_Shaw_GB
+    0x657345534C61746Ellu, // es_Latn_ES
+    0x65734D584C61746Ellu, // es_Latn_MX
+    0x657355534C61746Ellu, // es_Latn_US
+    0xD24455534C61746Ellu, // esu_Latn_US
+    0x657445454C61746Ellu, // et_Latn_EE
+    0xCE6449544974616Cllu, // ett_Ital_IT
+    0x657545534C61746Ellu, // eu_Latn_ES
+    0xBAC4434D4C61746Ellu, // ewo_Latn_CM
+    0xCEE445534C61746Ellu, // ext_Latn_ES
+    0x6661495241726162llu, // fa_Arab_IR
+    0xB40547514C61746Ellu, // fan_Latn_GQ
+    0x6666534E4C61746Ellu, // ff_Latn_SN
+    0xB0A54D4C4C61746Ellu, // ffm_Latn_ML
+    0x666946494C61746Ellu, // fi_Latn_FI
+    0x8105534441726162llu, // fia_Arab_SD
+    0xAD0550484C61746Ellu, // fil_Latn_PH
+    0xCD0553454C61746Ellu, // fit_Latn_SE
+    0x666A464A4C61746Ellu, // fj_Latn_FJ
+    0x666F464F4C61746Ellu, // fo_Latn_FO
+    0xB5C5424A4C61746Ellu, // fon_Latn_BJ
+    0x667246524C61746Ellu, // fr_Latn_FR
+    0x8A2555534C61746Ellu, // frc_Latn_US
+    0xBE2546524C61746Ellu, // frp_Latn_FR
+    0xC62544454C61746Ellu, // frr_Latn_DE
+    0xCA2544454C61746Ellu, // frs_Latn_DE
+    0x8E8557464C61746Ellu, // fud_Latn_WF
+    0xC2854E454C61746Ellu, // fuq_Latn_NE
+    0xC68549544C61746Ellu, // fur_Latn_IT
+    0xD6854E474C61746Ellu, // fuv_Latn_NG
+    0xC6A553444C61746Ellu, // fvr_Latn_SD
+    0x66794E4C4C61746Ellu, // fy_Latn_NL
+    0x676149454C61746Ellu, // ga_Latn_IE
+    0x800647484C61746Ellu, // gaa_Latn_GH
+    0x98064D444C61746Ellu, // gag_Latn_MD
+    0xB406434E48616E73llu, // gan_Hans_CN
+    0xE00649444C61746Ellu, // gay_Latn_ID
+    0xB026494E44657661llu, // gbm_Deva_IN
+    0xE426495241726162llu, // gbz_Arab_IR
+    0xC44647464C61746Ellu, // gcr_Latn_GF
+    0x676447424C61746Ellu, // gd_Latn_GB
+    0xE486455445746869llu, // gez_Ethi_ET
+    0xB4C64E5044657661llu, // ggn_Deva_NP
+    0xAD064B494C61746Ellu, // gil_Latn_KI
+    0xA926504B41726162llu, // gjk_Arab_PK
+    0xD126504B41726162llu, // gju_Arab_PK
+    0x676C45534C61746Ellu, // gl_Latn_ES
+    0xA966495241726162llu, // glk_Arab_IR
+    0x676E50594C61746Ellu, // gn_Latn_PY
+    0xB1C6494E44657661llu, // gom_Deva_IN
+    0xB5C6494E54656C75llu, // gon_Telu_IN
+    0xC5C649444C61746Ellu, // gor_Latn_ID
+    0xC9C64E4C4C61746Ellu, // gos_Latn_NL
+    0xCDC65541476F7468llu, // got_Goth_UA
+    0x8A26435943707274llu, // grc_Cprt_CY
+    0x8A2647524C696E62llu, // grc_Linb_GR
+    0xCE26494E42656E67llu, // grt_Beng_IN
+    0xDA4643484C61746Ellu, // gsw_Latn_CH
+    0x6775494E47756A72llu, // gu_Gujr_IN
+    0x868642524C61746Ellu, // gub_Latn_BR
+    0x8A86434F4C61746Ellu, // guc_Latn_CO
+    0xC68647484C61746Ellu, // gur_Latn_GH
+    0xE6864B454C61746Ellu, // guz_Latn_KE
+    0x6776494D4C61746Ellu, // gv_Latn_IM
+    0xC6A64E5044657661llu, // gvr_Deva_NP
+    0xA2C643414C61746Ellu, // gwi_Latn_CA
+    0x68614E474C61746Ellu, // ha_Latn_NG
+    0xA807434E48616E73llu, // hak_Hans_CN
+    0xD80755534C61746Ellu, // haw_Latn_US
+    0xE407414641726162llu, // haz_Arab_AF
+    0x6865494C48656272llu, // he_Hebr_IL
+    0x6869494E44657661llu, // hi_Deva_IN
+    0x9507464A4C61746Ellu, // hif_Latn_FJ
+    0xAD0750484C61746Ellu, // hil_Latn_PH
+    0xD1675452486C7577llu, // hlu_Hluw_TR
+    0x8D87434E506C7264llu, // hmd_Plrd_CN
+    0x8DA7504B41726162llu, // hnd_Arab_PK
+    0x91A7494E44657661llu, // hne_Deva_IN
+    0xA5A74C41486D6E67llu, // hnj_Hmng_LA
+    0xB5A750484C61746Ellu, // hnn_Latn_PH
+    0xB9A7504B41726162llu, // hno_Arab_PK
+    0x686F50474C61746Ellu, // ho_Latn_PG
+    0x89C7494E44657661llu, // hoc_Deva_IN
+    0xA5C7494E44657661llu, // hoj_Deva_IN
+    0x687248524C61746Ellu, // hr_Latn_HR
+    0x864744454C61746Ellu, // hsb_Latn_DE
+    0xB647434E48616E73llu, // hsn_Hans_CN
+    0x687448544C61746Ellu, // ht_Latn_HT
+    0x687548554C61746Ellu, // hu_Latn_HU
+    0x6879414D41726D6Ellu, // hy_Armn_AM
+    0x687A4E414C61746Ellu, // hz_Latn_NA
+    0x696146524C61746Ellu, // ia_Latn_FR
+    0x80284D594C61746Ellu, // iba_Latn_MY
+    0x84284E474C61746Ellu, // ibb_Latn_NG
+    0x696449444C61746Ellu, // id_Latn_ID
+    0x69674E474C61746Ellu, // ig_Latn_NG
+    0x6969434E59696969llu, // ii_Yiii_CN
+    0x696B55534C61746Ellu, // ik_Latn_US
+    0xCD4843414C61746Ellu, // ikt_Latn_CA
+    0xB96850484C61746Ellu, // ilo_Latn_PH
+    0x696E49444C61746Ellu, // in_Latn_ID
+    0x9DA852554379726Cllu, // inh_Cyrl_RU
+    0x697349534C61746Ellu, // is_Latn_IS
+    0x697449544C61746Ellu, // it_Latn_IT
+    0x6975434143616E73llu, // iu_Cans_CA
+    0x6977494C48656272llu, // iw_Hebr_IL
+    0x9F2852554C61746Ellu, // izh_Latn_RU
+    0x6A614A504A70616Ellu, // ja_Jpan_JP
+    0xB0094A4D4C61746Ellu, // jam_Latn_JM
+    0xB8C9434D4C61746Ellu, // jgo_Latn_CM
+    0x6A69554148656272llu, // ji_Hebr_UA
+    0x8989545A4C61746Ellu, // jmc_Latn_TZ
+    0xAD894E5044657661llu, // jml_Deva_NP
+    0xCE89444B4C61746Ellu, // jut_Latn_DK
+    0x6A7649444C61746Ellu, // jv_Latn_ID
+    0x6A7749444C61746Ellu, // jw_Latn_ID
+    0x6B61474547656F72llu, // ka_Geor_GE
+    0x800A555A4379726Cllu, // kaa_Cyrl_UZ
+    0x840A445A4C61746Ellu, // kab_Latn_DZ
+    0x880A4D4D4C61746Ellu, // kac_Latn_MM
+    0xA40A4E474C61746Ellu, // kaj_Latn_NG
+    0xB00A4B454C61746Ellu, // kam_Latn_KE
+    0xB80A4D4C4C61746Ellu, // kao_Latn_ML
+    0x8C2A52554379726Cllu, // kbd_Cyrl_RU
+    0x984A4E474C61746Ellu, // kcg_Latn_NG
+    0xA84A5A574C61746Ellu, // kck_Latn_ZW
+    0x906A545A4C61746Ellu, // kde_Latn_TZ
+    0xCC6A544854686169llu, // kdt_Thai_TH
+    0x808A43564C61746Ellu, // kea_Latn_CV
+    0xB48A434D4C61746Ellu, // ken_Latn_CM
+    0xB8AA43494C61746Ellu, // kfo_Latn_CI
+    0xC4AA494E44657661llu, // kfr_Deva_IN
+    0xE0AA494E44657661llu, // kfy_Deva_IN
+    0x6B6743444C61746Ellu, // kg_Latn_CD
+    0x90CA49444C61746Ellu, // kge_Latn_ID
+    0xBCCA42524C61746Ellu, // kgp_Latn_BR
+    0x80EA494E4C61746Ellu, // kha_Latn_IN
+    0x84EA434E54616C75llu, // khb_Talu_CN
+    0xB4EA494E44657661llu, // khn_Deva_IN
+    0xC0EA4D4C4C61746Ellu, // khq_Latn_ML
+    0xCCEA494E4D796D72llu, // kht_Mymr_IN
+    0xD8EA504B41726162llu, // khw_Arab_PK
+    0x6B694B454C61746Ellu, // ki_Latn_KE
+    0xD10A54524C61746Ellu, // kiu_Latn_TR
+    0x6B6A4E414C61746Ellu, // kj_Latn_NA
+    0x992A4C414C616F6Fllu, // kjg_Laoo_LA
+    0x6B6B434E41726162llu, // kk_Arab_CN
+    0x6B6B4B5A4379726Cllu, // kk_Cyrl_KZ
+    0xA54A434D4C61746Ellu, // kkj_Latn_CM
+    0x6B6C474C4C61746Ellu, // kl_Latn_GL
+    0xB56A4B454C61746Ellu, // kln_Latn_KE
+    0x6B6D4B484B686D72llu, // km_Khmr_KH
+    0x858A414F4C61746Ellu, // kmb_Latn_AO
+    0x6B6E494E4B6E6461llu, // kn_Knda_IN
+    0x6B6F4B524B6F7265llu, // ko_Kore_KR
+    0xA1CA52554379726Cllu, // koi_Cyrl_RU
+    0xA9CA494E44657661llu, // kok_Deva_IN
+    0xC9CA464D4C61746Ellu, // kos_Latn_FM
+    0x91EA4C524C61746Ellu, // kpe_Latn_LR
+    0x8A2A52554379726Cllu, // krc_Cyrl_RU
+    0xA22A534C4C61746Ellu, // kri_Latn_SL
+    0xA62A50484C61746Ellu, // krj_Latn_PH
+    0xAE2A52554C61746Ellu, // krl_Latn_RU
+    0xD22A494E44657661llu, // kru_Deva_IN
+    0x6B73494E41726162llu, // ks_Arab_IN
+    0x864A545A4C61746Ellu, // ksb_Latn_TZ
+    0x964A434D4C61746Ellu, // ksf_Latn_CM
+    0x9E4A44454C61746Ellu, // ksh_Latn_DE
+    0x6B75495141726162llu, // ku_Arab_IQ
+    0x6B7554524C61746Ellu, // ku_Latn_TR
+    0xB28A52554379726Cllu, // kum_Cyrl_RU
+    0x6B7652554379726Cllu, // kv_Cyrl_RU
+    0xC6AA49444C61746Ellu, // kvr_Latn_ID
+    0xDEAA504B41726162llu, // kvx_Arab_PK
+    0x6B7747424C61746Ellu, // kw_Latn_GB
+    0xB2EA544854686169llu, // kxm_Thai_TH
+    0xBEEA504B41726162llu, // kxp_Arab_PK
+    0x6B79434E41726162llu, // ky_Arab_CN
+    0x6B794B474379726Cllu, // ky_Cyrl_KG
+    0x6B7954524C61746Ellu, // ky_Latn_TR
+    0x6C6156414C61746Ellu, // la_Latn_VA
+    0x840B47524C696E61llu, // lab_Lina_GR
+    0x8C0B494C48656272llu, // lad_Hebr_IL
+    0x980B545A4C61746Ellu, // lag_Latn_TZ
+    0x9C0B504B41726162llu, // lah_Arab_PK
+    0xA40B55474C61746Ellu, // laj_Latn_UG
+    0x6C624C554C61746Ellu, // lb_Latn_LU
+    0x902B52554379726Cllu, // lbe_Cyrl_RU
+    0xD82B49444C61746Ellu, // lbw_Latn_ID
+    0xBC4B434E54686169llu, // lcp_Thai_CN
+    0xBC8B494E4C657063llu, // lep_Lepc_IN
+    0xE48B52554379726Cllu, // lez_Cyrl_RU
+    0x6C6755474C61746Ellu, // lg_Latn_UG
+    0x6C694E4C4C61746Ellu, // li_Latn_NL
+    0x950B4E5044657661llu, // lif_Deva_NP
+    0x950B494E4C696D62llu, // lif_Limb_IN
+    0xA50B49544C61746Ellu, // lij_Latn_IT
+    0xC90B434E4C697375llu, // lis_Lisu_CN
+    0xBD2B49444C61746Ellu, // ljp_Latn_ID
+    0xA14B495241726162llu, // lki_Arab_IR
+    0xCD4B55534C61746Ellu, // lkt_Latn_US
+    0xB58B494E54656C75llu, // lmn_Telu_IN
+    0xB98B49544C61746Ellu, // lmo_Latn_IT
+    0x6C6E43444C61746Ellu, // ln_Latn_CD
+    0x6C6F4C414C616F6Fllu, // lo_Laoo_LA
+    0xADCB43444C61746Ellu, // lol_Latn_CD
+    0xE5CB5A4D4C61746Ellu, // loz_Latn_ZM
+    0x8A2B495241726162llu, // lrc_Arab_IR
+    0x6C744C544C61746Ellu, // lt_Latn_LT
+    0x9A6B4C564C61746Ellu, // ltg_Latn_LV
+    0x6C7543444C61746Ellu, // lu_Latn_CD
+    0x828B43444C61746Ellu, // lua_Latn_CD
+    0xBA8B4B454C61746Ellu, // luo_Latn_KE
+    0xE28B4B454C61746Ellu, // luy_Latn_KE
+    0xE68B495241726162llu, // luz_Arab_IR
+    0x6C764C564C61746Ellu, // lv_Latn_LV
+    0xAECB544854686169llu, // lwl_Thai_TH
+    0x9F2B434E48616E73llu, // lzh_Hans_CN
+    0xE72B54524C61746Ellu, // lzz_Latn_TR
+    0x8C0C49444C61746Ellu, // mad_Latn_ID
+    0x940C434D4C61746Ellu, // maf_Latn_CM
+    0x980C494E44657661llu, // mag_Deva_IN
+    0xA00C494E44657661llu, // mai_Deva_IN
+    0xA80C49444C61746Ellu, // mak_Latn_ID
+    0xB40C474D4C61746Ellu, // man_Latn_GM
+    0xB40C474E4E6B6F6Fllu, // man_Nkoo_GN
+    0xC80C4B454C61746Ellu, // mas_Latn_KE
+    0xE40C4D584C61746Ellu, // maz_Latn_MX
+    0x946C52554379726Cllu, // mdf_Cyrl_RU
+    0x9C6C50484C61746Ellu, // mdh_Latn_PH
+    0xC46C49444C61746Ellu, // mdr_Latn_ID
+    0xB48C534C4C61746Ellu, // men_Latn_SL
+    0xC48C4B454C61746Ellu, // mer_Latn_KE
+    0x80AC544841726162llu, // mfa_Arab_TH
+    0x90AC4D554C61746Ellu, // mfe_Latn_MU
+    0x6D674D474C61746Ellu, // mg_Latn_MG
+    0x9CCC4D5A4C61746Ellu, // mgh_Latn_MZ
+    0xB8CC434D4C61746Ellu, // mgo_Latn_CM
+    0xBCCC4E5044657661llu, // mgp_Deva_NP
+    0xE0CC545A4C61746Ellu, // mgy_Latn_TZ
+    0x6D684D484C61746Ellu, // mh_Latn_MH
+    0x6D694E5A4C61746Ellu, // mi_Latn_NZ
+    0xB50C49444C61746Ellu, // min_Latn_ID
+    0xC90C495148617472llu, // mis_Hatr_IQ
+    0x6D6B4D4B4379726Cllu, // mk_Cyrl_MK
+    0x6D6C494E4D6C796Dllu, // ml_Mlym_IN
+    0xC96C53444C61746Ellu, // mls_Latn_SD
+    0x6D6E4D4E4379726Cllu, // mn_Cyrl_MN
+    0x6D6E434E4D6F6E67llu, // mn_Mong_CN
+    0xA1AC494E42656E67llu, // mni_Beng_IN
+    0xD9AC4D4D4D796D72llu, // mnw_Mymr_MM
+    0x91CC43414C61746Ellu, // moe_Latn_CA
+    0x9DCC43414C61746Ellu, // moh_Latn_CA
+    0xC9CC42464C61746Ellu, // mos_Latn_BF
+    0x6D72494E44657661llu, // mr_Deva_IN
+    0x8E2C4E5044657661llu, // mrd_Deva_NP
+    0xA62C52554379726Cllu, // mrj_Cyrl_RU
+    0xD22C42444D726F6Fllu, // mru_Mroo_BD
+    0x6D734D594C61746Ellu, // ms_Latn_MY
+    0x6D744D544C61746Ellu, // mt_Latn_MT
+    0xC66C494E44657661llu, // mtr_Deva_IN
+    0x828C434D4C61746Ellu, // mua_Latn_CM
+    0xCA8C55534C61746Ellu, // mus_Latn_US
+    0xE2AC504B41726162llu, // mvy_Arab_PK
+    0xAACC4D4C4C61746Ellu, // mwk_Latn_ML
+    0xC6CC494E44657661llu, // mwr_Deva_IN
+    0xD6CC49444C61746Ellu, // mwv_Latn_ID
+    0x8AEC5A574C61746Ellu, // mxc_Latn_ZW
+    0x6D794D4D4D796D72llu, // my_Mymr_MM
+    0xD70C52554379726Cllu, // myv_Cyrl_RU
+    0xDF0C55474C61746Ellu, // myx_Latn_UG
+    0xE70C49524D616E64llu, // myz_Mand_IR
+    0xB72C495241726162llu, // mzn_Arab_IR
+    0x6E614E524C61746Ellu, // na_Latn_NR
+    0xB40D434E48616E73llu, // nan_Hans_CN
+    0xBC0D49544C61746Ellu, // nap_Latn_IT
+    0xC00D4E414C61746Ellu, // naq_Latn_NA
+    0x6E624E4F4C61746Ellu, // nb_Latn_NO
+    0x9C4D4D584C61746Ellu, // nch_Latn_MX
+    0x6E645A574C61746Ellu, // nd_Latn_ZW
+    0x886D4D5A4C61746Ellu, // ndc_Latn_MZ
+    0xC86D44454C61746Ellu, // nds_Latn_DE
+    0x6E654E5044657661llu, // ne_Deva_NP
+    0xD88D4E5044657661llu, // new_Deva_NP
+    0x6E674E414C61746Ellu, // ng_Latn_NA
+    0xACCD4D5A4C61746Ellu, // ngl_Latn_MZ
+    0x90ED4D584C61746Ellu, // nhe_Latn_MX
+    0xD8ED4D584C61746Ellu, // nhw_Latn_MX
+    0xA50D49444C61746Ellu, // nij_Latn_ID
+    0xD10D4E554C61746Ellu, // niu_Latn_NU
+    0xB92D494E4C61746Ellu, // njo_Latn_IN
+    0x6E6C4E4C4C61746Ellu, // nl_Latn_NL
+    0x998D434D4C61746Ellu, // nmg_Latn_CM
+    0x6E6E4E4F4C61746Ellu, // nn_Latn_NO
+    0x9DAD434D4C61746Ellu, // nnh_Latn_CM
+    0x6E6F4E4F4C61746Ellu, // no_Latn_NO
+    0x8DCD54484C616E61llu, // nod_Lana_TH
+    0x91CD494E44657661llu, // noe_Deva_IN
+    0xB5CD534552756E72llu, // non_Runr_SE
+    0xBA0D474E4E6B6F6Fllu, // nqo_Nkoo_GN
+    0x6E725A414C61746Ellu, // nr_Latn_ZA
+    0xAA4D434143616E73llu, // nsk_Cans_CA
+    0xBA4D5A414C61746Ellu, // nso_Latn_ZA
+    0xCA8D53534C61746Ellu, // nus_Latn_SS
+    0x6E7655534C61746Ellu, // nv_Latn_US
+    0xC2ED434E4C61746Ellu, // nxq_Latn_CN
+    0x6E794D574C61746Ellu, // ny_Latn_MW
+    0xB30D545A4C61746Ellu, // nym_Latn_TZ
+    0xB70D55474C61746Ellu, // nyn_Latn_UG
+    0xA32D47484C61746Ellu, // nzi_Latn_GH
+    0x6F6346524C61746Ellu, // oc_Latn_FR
+    0x6F6D45544C61746Ellu, // om_Latn_ET
+    0x6F72494E4F727961llu, // or_Orya_IN
+    0x6F7347454379726Cllu, // os_Cyrl_GE
+    0xAA6E4D4E4F726B68llu, // otk_Orkh_MN
+    0x7061504B41726162llu, // pa_Arab_PK
+    0x7061494E47757275llu, // pa_Guru_IN
+    0x980F50484C61746Ellu, // pag_Latn_PH
+    0xAC0F495250686C69llu, // pal_Phli_IR
+    0xAC0F434E50686C70llu, // pal_Phlp_CN
+    0xB00F50484C61746Ellu, // pam_Latn_PH
+    0xBC0F41574C61746Ellu, // pap_Latn_AW
+    0xD00F50574C61746Ellu, // pau_Latn_PW
+    0x8C4F46524C61746Ellu, // pcd_Latn_FR
+    0xB04F4E474C61746Ellu, // pcm_Latn_NG
+    0x886F55534C61746Ellu, // pdc_Latn_US
+    0xCC6F43414C61746Ellu, // pdt_Latn_CA
+    0xB88F49525870656Fllu, // peo_Xpeo_IR
+    0xACAF44454C61746Ellu, // pfl_Latn_DE
+    0xB4EF4C4250686E78llu, // phn_Phnx_LB
+    0x814F494E42726168llu, // pka_Brah_IN
+    0xB94F4B454C61746Ellu, // pko_Latn_KE
+    0x706C504C4C61746Ellu, // pl_Latn_PL
+    0xC98F49544C61746Ellu, // pms_Latn_IT
+    0xCDAF47524772656Bllu, // pnt_Grek_GR
+    0xB5CF464D4C61746Ellu, // pon_Latn_FM
+    0x822F504B4B686172llu, // pra_Khar_PK
+    0x8E2F495241726162llu, // prd_Arab_IR
+    0x7073414641726162llu, // ps_Arab_AF
+    0x707442524C61746Ellu, // pt_Latn_BR
+    0xD28F47414C61746Ellu, // puu_Latn_GA
+    0x717550454C61746Ellu, // qu_Latn_PE
+    0x8A9047544C61746Ellu, // quc_Latn_GT
+    0x9A9045434C61746Ellu, // qug_Latn_EC
+    0xA411494E44657661llu, // raj_Deva_IN
+    0x945152454C61746Ellu, // rcf_Latn_RE
+    0xA49149444C61746Ellu, // rej_Latn_ID
+    0xB4D149544C61746Ellu, // rgn_Latn_IT
+    0x8111494E4C61746Ellu, // ria_Latn_IN
+    0x95114D4154666E67llu, // rif_Tfng_MA
+    0xC9314E5044657661llu, // rjs_Deva_NP
+    0xCD51424442656E67llu, // rkt_Beng_BD
+    0x726D43484C61746Ellu, // rm_Latn_CH
+    0x959146494C61746Ellu, // rmf_Latn_FI
+    0xB99143484C61746Ellu, // rmo_Latn_CH
+    0xCD91495241726162llu, // rmt_Arab_IR
+    0xD19153454C61746Ellu, // rmu_Latn_SE
+    0x726E42494C61746Ellu, // rn_Latn_BI
+    0x99B14D5A4C61746Ellu, // rng_Latn_MZ
+    0x726F524F4C61746Ellu, // ro_Latn_RO
+    0x85D149444C61746Ellu, // rob_Latn_ID
+    0x95D1545A4C61746Ellu, // rof_Latn_TZ
+    0xB271464A4C61746Ellu, // rtm_Latn_FJ
+    0x727552554379726Cllu, // ru_Cyrl_RU
+    0x929155414379726Cllu, // rue_Cyrl_UA
+    0x9A9153424C61746Ellu, // rug_Latn_SB
+    0x727752574C61746Ellu, // rw_Latn_RW
+    0xAAD1545A4C61746Ellu, // rwk_Latn_TZ
+    0xD3114A504B616E61llu, // ryu_Kana_JP
+    0x7361494E44657661llu, // sa_Deva_IN
+    0x941247484C61746Ellu, // saf_Latn_GH
+    0x9C1252554379726Cllu, // sah_Cyrl_RU
+    0xC0124B454C61746Ellu, // saq_Latn_KE
+    0xC81249444C61746Ellu, // sas_Latn_ID
+    0xCC12494E4C61746Ellu, // sat_Latn_IN
+    0xE412494E53617572llu, // saz_Saur_IN
+    0xBC32545A4C61746Ellu, // sbp_Latn_TZ
+    0x736349544C61746Ellu, // sc_Latn_IT
+    0xA852494E44657661llu, // sck_Deva_IN
+    0xB45249544C61746Ellu, // scn_Latn_IT
+    0xB85247424C61746Ellu, // sco_Latn_GB
+    0xC85243414C61746Ellu, // scs_Latn_CA
+    0x7364504B41726162llu, // sd_Arab_PK
+    0x7364494E44657661llu, // sd_Deva_IN
+    0x7364494E4B686F6Allu, // sd_Khoj_IN
+    0x7364494E53696E64llu, // sd_Sind_IN
+    0x887249544C61746Ellu, // sdc_Latn_IT
+    0x9C72495241726162llu, // sdh_Arab_IR
+    0x73654E4F4C61746Ellu, // se_Latn_NO
+    0x949243494C61746Ellu, // sef_Latn_CI
+    0x9C924D5A4C61746Ellu, // seh_Latn_MZ
+    0xA0924D584C61746Ellu, // sei_Latn_MX
+    0xC8924D4C4C61746Ellu, // ses_Latn_ML
+    0x736743464C61746Ellu, // sg_Latn_CF
+    0x80D249454F67616Dllu, // sga_Ogam_IE
+    0xC8D24C544C61746Ellu, // sgs_Latn_LT
+    0xA0F24D4154666E67llu, // shi_Tfng_MA
+    0xB4F24D4D4D796D72llu, // shn_Mymr_MM
+    0x73694C4B53696E68llu, // si_Sinh_LK
+    0x8D1245544C61746Ellu, // sid_Latn_ET
+    0x736B534B4C61746Ellu, // sk_Latn_SK
+    0xC552504B41726162llu, // skr_Arab_PK
+    0x736C53494C61746Ellu, // sl_Latn_SI
+    0xA172504C4C61746Ellu, // sli_Latn_PL
+    0xE17249444C61746Ellu, // sly_Latn_ID
+    0x736D57534C61746Ellu, // sm_Latn_WS
+    0x819253454C61746Ellu, // sma_Latn_SE
+    0xA59253454C61746Ellu, // smj_Latn_SE
+    0xB59246494C61746Ellu, // smn_Latn_FI
+    0xBD92494C53616D72llu, // smp_Samr_IL
+    0xC99246494C61746Ellu, // sms_Latn_FI
+    0x736E5A574C61746Ellu, // sn_Latn_ZW
+    0xA9B24D4C4C61746Ellu, // snk_Latn_ML
+    0x736F534F4C61746Ellu, // so_Latn_SO
+    0xD1D2544854686169llu, // sou_Thai_TH
+    0x7371414C4C61746Ellu, // sq_Latn_AL
+    0x737252534379726Cllu, // sr_Cyrl_RS
+    0x737252534C61746Ellu, // sr_Latn_RS
+    0x8632494E536F7261llu, // srb_Sora_IN
+    0xB63253524C61746Ellu, // srn_Latn_SR
+    0xC632534E4C61746Ellu, // srr_Latn_SN
+    0xDE32494E44657661llu, // srx_Deva_IN
+    0x73735A414C61746Ellu, // ss_Latn_ZA
+    0xE25245524C61746Ellu, // ssy_Latn_ER
+    0x73745A414C61746Ellu, // st_Latn_ZA
+    0xC27244454C61746Ellu, // stq_Latn_DE
+    0x737549444C61746Ellu, // su_Latn_ID
+    0xAA92545A4C61746Ellu, // suk_Latn_TZ
+    0xCA92474E4C61746Ellu, // sus_Latn_GN
+    0x737653454C61746Ellu, // sv_Latn_SE
+    0x7377545A4C61746Ellu, // sw_Latn_TZ
+    0x86D2595441726162llu, // swb_Arab_YT
+    0x8AD243444C61746Ellu, // swc_Latn_CD
+    0x9AD244454C61746Ellu, // swg_Latn_DE
+    0xD6D2494E44657661llu, // swv_Deva_IN
+    0xB6F249444C61746Ellu, // sxn_Latn_ID
+    0xAF12424442656E67llu, // syl_Beng_BD
+    0xC712495153797263llu, // syr_Syrc_IQ
+    0xAF32504C4C61746Ellu, // szl_Latn_PL
+    0x7461494E54616D6Cllu, // ta_Taml_IN
+    0xA4134E5044657661llu, // taj_Deva_NP
+    0xD83350484C61746Ellu, // tbw_Latn_PH
+    0xE053494E4B6E6461llu, // tcy_Knda_IN
+    0x8C73434E54616C65llu, // tdd_Tale_CN
+    0x98734E5044657661llu, // tdg_Deva_NP
+    0x9C734E5044657661llu, // tdh_Deva_NP
+    0x7465494E54656C75llu, // te_Telu_IN
+    0xB093534C4C61746Ellu, // tem_Latn_SL
+    0xB89355474C61746Ellu, // teo_Latn_UG
+    0xCC93544C4C61746Ellu, // tet_Latn_TL
+    0x7467504B41726162llu, // tg_Arab_PK
+    0x7467544A4379726Cllu, // tg_Cyrl_TJ
+    0x7468544854686169llu, // th_Thai_TH
+    0xACF34E5044657661llu, // thl_Deva_NP
+    0xC0F34E5044657661llu, // thq_Deva_NP
+    0xC4F34E5044657661llu, // thr_Deva_NP
+    0x7469455445746869llu, // ti_Ethi_ET
+    0x9913455245746869llu, // tig_Ethi_ER
+    0xD5134E474C61746Ellu, // tiv_Latn_NG
+    0x746B544D4C61746Ellu, // tk_Latn_TM
+    0xAD53544B4C61746Ellu, // tkl_Latn_TK
+    0xC553415A4C61746Ellu, // tkr_Latn_AZ
+    0xCD534E5044657661llu, // tkt_Deva_NP
+    0x746C50484C61746Ellu, // tl_Latn_PH
+    0xE173415A4C61746Ellu, // tly_Latn_AZ
+    0x9D934E454C61746Ellu, // tmh_Latn_NE
+    0x746E5A414C61746Ellu, // tn_Latn_ZA
+    0x746F544F4C61746Ellu, // to_Latn_TO
+    0x99D34D574C61746Ellu, // tog_Latn_MW
+    0xA1F350474C61746Ellu, // tpi_Latn_PG
+    0x747254524C61746Ellu, // tr_Latn_TR
+    0xD23354524C61746Ellu, // tru_Latn_TR
+    0xD63354574C61746Ellu, // trv_Latn_TW
+    0x74735A414C61746Ellu, // ts_Latn_ZA
+    0x8E5347524772656Bllu, // tsd_Grek_GR
+    0x96534E5044657661llu, // tsf_Deva_NP
+    0x9A5350484C61746Ellu, // tsg_Latn_PH
+    0xA653425454696274llu, // tsj_Tibt_BT
+    0x747452554379726Cllu, // tt_Cyrl_RU
+    0xA67355474C61746Ellu, // ttj_Latn_UG
+    0xCA73544854686169llu, // tts_Thai_TH
+    0xCE73415A4C61746Ellu, // ttt_Latn_AZ
+    0xB2934D574C61746Ellu, // tum_Latn_MW
+    0xAEB354564C61746Ellu, // tvl_Latn_TV
+    0xC2D34E454C61746Ellu, // twq_Latn_NE
+    0x747950464C61746Ellu, // ty_Latn_PF
+    0xD71352554379726Cllu, // tyv_Cyrl_RU
+    0xB3334D414C61746Ellu, // tzm_Latn_MA
+    0xB07452554379726Cllu, // udm_Cyrl_RU
+    0x7567434E41726162llu, // ug_Arab_CN
+    0x75674B5A4379726Cllu, // ug_Cyrl_KZ
+    0x80D4535955676172llu, // uga_Ugar_SY
+    0x756B55414379726Cllu, // uk_Cyrl_UA
+    0xA174464D4C61746Ellu, // uli_Latn_FM
+    0x8594414F4C61746Ellu, // umb_Latn_AO
+    0xC5B4494E42656E67llu, // unr_Beng_IN
+    0xC5B44E5044657661llu, // unr_Deva_NP
+    0xDDB4494E42656E67llu, // unx_Beng_IN
+    0x7572504B41726162llu, // ur_Arab_PK
+    0x757A414641726162llu, // uz_Arab_AF
+    0x757A555A4C61746Ellu, // uz_Latn_UZ
+    0xA0154C5256616969llu, // vai_Vaii_LR
+    0x76655A414C61746Ellu, // ve_Latn_ZA
+    0x889549544C61746Ellu, // vec_Latn_IT
+    0xBC9552554C61746Ellu, // vep_Latn_RU
+    0x7669564E4C61746Ellu, // vi_Latn_VN
+    0x891553584C61746Ellu, // vic_Latn_SX
+    0xC97542454C61746Ellu, // vls_Latn_BE
+    0x959544454C61746Ellu, // vmf_Latn_DE
+    0xD9954D5A4C61746Ellu, // vmw_Latn_MZ
+    0xCDD552554C61746Ellu, // vot_Latn_RU
+    0xBA3545454C61746Ellu, // vro_Latn_EE
+    0xB695545A4C61746Ellu, // vun_Latn_TZ
+    0x776142454C61746Ellu, // wa_Latn_BE
+    0x901643484C61746Ellu, // wae_Latn_CH
+    0xAC16455445746869llu, // wal_Ethi_ET
+    0xC41650484C61746Ellu, // war_Latn_PH
+    0xBC3641554C61746Ellu, // wbp_Latn_AU
+    0xC036494E54656C75llu, // wbq_Telu_IN
+    0xC436494E44657661llu, // wbr_Deva_IN
+    0xC97657464C61746Ellu, // wls_Latn_WF
+    0xA1B64B4D41726162llu, // wni_Arab_KM
+    0x776F534E4C61746Ellu, // wo_Latn_SN
+    0xB276494E44657661llu, // wtm_Deva_IN
+    0xD296434E48616E73llu, // wuu_Hans_CN
+    0xD41742524C61746Ellu, // xav_Latn_BR
+    0xC457545243617269llu, // xcr_Cari_TR
+    0x78685A414C61746Ellu, // xh_Latn_ZA
+    0x897754524C796369llu, // xlc_Lyci_TR
+    0x8D7754524C796469llu, // xld_Lydi_TR
+    0x9597474547656F72llu, // xmf_Geor_GE
+    0xB597434E4D616E69llu, // xmn_Mani_CN
+    0xC59753444D657263llu, // xmr_Merc_SD
+    0x81B753414E617262llu, // xna_Narb_SA
+    0xC5B7494E44657661llu, // xnr_Deva_IN
+    0x99D755474C61746Ellu, // xog_Latn_UG
+    0xC5F7495250727469llu, // xpr_Prti_IR
+    0x8257594553617262llu, // xsa_Sarb_YE
+    0xC6574E5044657661llu, // xsr_Deva_NP
+    0xB8184D5A4C61746Ellu, // yao_Latn_MZ
+    0xBC18464D4C61746Ellu, // yap_Latn_FM
+    0xD418434D4C61746Ellu, // yav_Latn_CM
+    0x8438434D4C61746Ellu, // ybb_Latn_CM
+    0x796F4E474C61746Ellu, // yo_Latn_NG
+    0xAE3842524C61746Ellu, // yrl_Latn_BR
+    0x82984D584C61746Ellu, // yua_Latn_MX
+    0x7A61434E4C61746Ellu, // za_Latn_CN
+    0x981953444C61746Ellu, // zag_Latn_SD
+    0xA4794B4D41726162llu, // zdj_Arab_KM
+    0x80994E4C4C61746Ellu, // zea_Latn_NL
+    0x9CD94D4154666E67llu, // zgh_Tfng_MA
+    0x7A685457426F706Fllu, // zh_Bopo_TW
+    0x7A68434E48616E73llu, // zh_Hans_CN
+    0x7A68545748616E74llu, // zh_Hant_TW
+    0xA1994D594C61746Ellu, // zmi_Latn_MY
+    0x7A755A414C61746Ellu, // zu_Latn_ZA
+    0x833954524C61746Ellu, // zza_Latn_TR
+});
+
+const std::unordered_map<uint32_t, uint32_t> ARAB_PARENTS({
+    {0x6172445Au, 0x61729420u}, // ar-DZ -> ar-015
+    {0x61724548u, 0x61729420u}, // ar-EH -> ar-015
+    {0x61724C59u, 0x61729420u}, // ar-LY -> ar-015
+    {0x61724D41u, 0x61729420u}, // ar-MA -> ar-015
+    {0x6172544Eu, 0x61729420u}, // ar-TN -> ar-015
+});
+
+const std::unordered_map<uint32_t, uint32_t> HANT_PARENTS({
+    {0x7A684D4Fu, 0x7A68484Bu}, // zh-Hant-MO -> zh-Hant-HK
+});
+
+const std::unordered_map<uint32_t, uint32_t> LATN_PARENTS({
+    {0x656E80A1u, 0x656E8400u}, // en-150 -> en-001
+    {0x656E4147u, 0x656E8400u}, // en-AG -> en-001
+    {0x656E4149u, 0x656E8400u}, // en-AI -> en-001
+    {0x656E4154u, 0x656E80A1u}, // en-AT -> en-150
+    {0x656E4155u, 0x656E8400u}, // en-AU -> en-001
+    {0x656E4242u, 0x656E8400u}, // en-BB -> en-001
+    {0x656E4245u, 0x656E8400u}, // en-BE -> en-001
+    {0x656E424Du, 0x656E8400u}, // en-BM -> en-001
+    {0x656E4253u, 0x656E8400u}, // en-BS -> en-001
+    {0x656E4257u, 0x656E8400u}, // en-BW -> en-001
+    {0x656E425Au, 0x656E8400u}, // en-BZ -> en-001
+    {0x656E4341u, 0x656E8400u}, // en-CA -> en-001
+    {0x656E4343u, 0x656E8400u}, // en-CC -> en-001
+    {0x656E4348u, 0x656E80A1u}, // en-CH -> en-150
+    {0x656E434Bu, 0x656E8400u}, // en-CK -> en-001
+    {0x656E434Du, 0x656E8400u}, // en-CM -> en-001
+    {0x656E4358u, 0x656E8400u}, // en-CX -> en-001
+    {0x656E4359u, 0x656E8400u}, // en-CY -> en-001
+    {0x656E4445u, 0x656E80A1u}, // en-DE -> en-150
+    {0x656E4447u, 0x656E8400u}, // en-DG -> en-001
+    {0x656E444Bu, 0x656E80A1u}, // en-DK -> en-150
+    {0x656E444Du, 0x656E8400u}, // en-DM -> en-001
+    {0x656E4552u, 0x656E8400u}, // en-ER -> en-001
+    {0x656E4649u, 0x656E80A1u}, // en-FI -> en-150
+    {0x656E464Au, 0x656E8400u}, // en-FJ -> en-001
+    {0x656E464Bu, 0x656E8400u}, // en-FK -> en-001
+    {0x656E464Du, 0x656E8400u}, // en-FM -> en-001
+    {0x656E4742u, 0x656E8400u}, // en-GB -> en-001
+    {0x656E4744u, 0x656E8400u}, // en-GD -> en-001
+    {0x656E4747u, 0x656E8400u}, // en-GG -> en-001
+    {0x656E4748u, 0x656E8400u}, // en-GH -> en-001
+    {0x656E4749u, 0x656E8400u}, // en-GI -> en-001
+    {0x656E474Du, 0x656E8400u}, // en-GM -> en-001
+    {0x656E4759u, 0x656E8400u}, // en-GY -> en-001
+    {0x656E484Bu, 0x656E8400u}, // en-HK -> en-001
+    {0x656E4945u, 0x656E8400u}, // en-IE -> en-001
+    {0x656E494Cu, 0x656E8400u}, // en-IL -> en-001
+    {0x656E494Du, 0x656E8400u}, // en-IM -> en-001
+    {0x656E494Eu, 0x656E8400u}, // en-IN -> en-001
+    {0x656E494Fu, 0x656E8400u}, // en-IO -> en-001
+    {0x656E4A45u, 0x656E8400u}, // en-JE -> en-001
+    {0x656E4A4Du, 0x656E8400u}, // en-JM -> en-001
+    {0x656E4B45u, 0x656E8400u}, // en-KE -> en-001
+    {0x656E4B49u, 0x656E8400u}, // en-KI -> en-001
+    {0x656E4B4Eu, 0x656E8400u}, // en-KN -> en-001
+    {0x656E4B59u, 0x656E8400u}, // en-KY -> en-001
+    {0x656E4C43u, 0x656E8400u}, // en-LC -> en-001
+    {0x656E4C52u, 0x656E8400u}, // en-LR -> en-001
+    {0x656E4C53u, 0x656E8400u}, // en-LS -> en-001
+    {0x656E4D47u, 0x656E8400u}, // en-MG -> en-001
+    {0x656E4D4Fu, 0x656E8400u}, // en-MO -> en-001
+    {0x656E4D53u, 0x656E8400u}, // en-MS -> en-001
+    {0x656E4D54u, 0x656E8400u}, // en-MT -> en-001
+    {0x656E4D55u, 0x656E8400u}, // en-MU -> en-001
+    {0x656E4D57u, 0x656E8400u}, // en-MW -> en-001
+    {0x656E4D59u, 0x656E8400u}, // en-MY -> en-001
+    {0x656E4E41u, 0x656E8400u}, // en-NA -> en-001
+    {0x656E4E46u, 0x656E8400u}, // en-NF -> en-001
+    {0x656E4E47u, 0x656E8400u}, // en-NG -> en-001
+    {0x656E4E4Cu, 0x656E80A1u}, // en-NL -> en-150
+    {0x656E4E52u, 0x656E8400u}, // en-NR -> en-001
+    {0x656E4E55u, 0x656E8400u}, // en-NU -> en-001
+    {0x656E4E5Au, 0x656E8400u}, // en-NZ -> en-001
+    {0x656E5047u, 0x656E8400u}, // en-PG -> en-001
+    {0x656E5048u, 0x656E8400u}, // en-PH -> en-001
+    {0x656E504Bu, 0x656E8400u}, // en-PK -> en-001
+    {0x656E504Eu, 0x656E8400u}, // en-PN -> en-001
+    {0x656E5057u, 0x656E8400u}, // en-PW -> en-001
+    {0x656E5257u, 0x656E8400u}, // en-RW -> en-001
+    {0x656E5342u, 0x656E8400u}, // en-SB -> en-001
+    {0x656E5343u, 0x656E8400u}, // en-SC -> en-001
+    {0x656E5344u, 0x656E8400u}, // en-SD -> en-001
+    {0x656E5345u, 0x656E80A1u}, // en-SE -> en-150
+    {0x656E5347u, 0x656E8400u}, // en-SG -> en-001
+    {0x656E5348u, 0x656E8400u}, // en-SH -> en-001
+    {0x656E5349u, 0x656E80A1u}, // en-SI -> en-150
+    {0x656E534Cu, 0x656E8400u}, // en-SL -> en-001
+    {0x656E5353u, 0x656E8400u}, // en-SS -> en-001
+    {0x656E5358u, 0x656E8400u}, // en-SX -> en-001
+    {0x656E535Au, 0x656E8400u}, // en-SZ -> en-001
+    {0x656E5443u, 0x656E8400u}, // en-TC -> en-001
+    {0x656E544Bu, 0x656E8400u}, // en-TK -> en-001
+    {0x656E544Fu, 0x656E8400u}, // en-TO -> en-001
+    {0x656E5454u, 0x656E8400u}, // en-TT -> en-001
+    {0x656E5456u, 0x656E8400u}, // en-TV -> en-001
+    {0x656E545Au, 0x656E8400u}, // en-TZ -> en-001
+    {0x656E5547u, 0x656E8400u}, // en-UG -> en-001
+    {0x656E5643u, 0x656E8400u}, // en-VC -> en-001
+    {0x656E5647u, 0x656E8400u}, // en-VG -> en-001
+    {0x656E5655u, 0x656E8400u}, // en-VU -> en-001
+    {0x656E5753u, 0x656E8400u}, // en-WS -> en-001
+    {0x656E5A41u, 0x656E8400u}, // en-ZA -> en-001
+    {0x656E5A4Du, 0x656E8400u}, // en-ZM -> en-001
+    {0x656E5A57u, 0x656E8400u}, // en-ZW -> en-001
+    {0x65734152u, 0x6573A424u}, // es-AR -> es-419
+    {0x6573424Fu, 0x6573A424u}, // es-BO -> es-419
+    {0x6573434Cu, 0x6573A424u}, // es-CL -> es-419
+    {0x6573434Fu, 0x6573A424u}, // es-CO -> es-419
+    {0x65734352u, 0x6573A424u}, // es-CR -> es-419
+    {0x65734355u, 0x6573A424u}, // es-CU -> es-419
+    {0x6573444Fu, 0x6573A424u}, // es-DO -> es-419
+    {0x65734543u, 0x6573A424u}, // es-EC -> es-419
+    {0x65734754u, 0x6573A424u}, // es-GT -> es-419
+    {0x6573484Eu, 0x6573A424u}, // es-HN -> es-419
+    {0x65734D58u, 0x6573A424u}, // es-MX -> es-419
+    {0x65734E49u, 0x6573A424u}, // es-NI -> es-419
+    {0x65735041u, 0x6573A424u}, // es-PA -> es-419
+    {0x65735045u, 0x6573A424u}, // es-PE -> es-419
+    {0x65735052u, 0x6573A424u}, // es-PR -> es-419
+    {0x65735059u, 0x6573A424u}, // es-PY -> es-419
+    {0x65735356u, 0x6573A424u}, // es-SV -> es-419
+    {0x65735553u, 0x6573A424u}, // es-US -> es-419
+    {0x65735559u, 0x6573A424u}, // es-UY -> es-419
+    {0x65735645u, 0x6573A424u}, // es-VE -> es-419
+    {0x7074414Fu, 0x70745054u}, // pt-AO -> pt-PT
+    {0x70744356u, 0x70745054u}, // pt-CV -> pt-PT
+    {0x70744757u, 0x70745054u}, // pt-GW -> pt-PT
+    {0x70744D4Fu, 0x70745054u}, // pt-MO -> pt-PT
+    {0x70744D5Au, 0x70745054u}, // pt-MZ -> pt-PT
+    {0x70745354u, 0x70745054u}, // pt-ST -> pt-PT
+    {0x7074544Cu, 0x70745054u}, // pt-TL -> pt-PT
+});
+
+const struct {
+    const char script[4];
+    const std::unordered_map<uint32_t, uint32_t>* map;
+} SCRIPT_PARENTS[] = {
+    {{'A', 'r', 'a', 'b'}, &ARAB_PARENTS},
+    {{'H', 'a', 'n', 't'}, &HANT_PARENTS},
+    {{'L', 'a', 't', 'n'}, &LATN_PARENTS},
+};
+
+const size_t MAX_PARENT_DEPTH = 3;
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 21b543e..71e9c92 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -1868,7 +1868,10 @@
     }
 
     // The language & region are equal, so compare the scripts and variants.
-    int script = memcmp(l.localeScript, r.localeScript, sizeof(l.localeScript));
+    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;
+    int script = memcmp(lScript, rScript, sizeof(l.localeScript));
     if (script) {
         return script;
     }
@@ -2012,10 +2015,10 @@
     // 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 = ((localeScript[0] != 0) ? 1 : 0) +
+    const int score = (localeScriptWasProvided ? 1 : 0) +
         ((localeVariant[0] != 0) ? 2 : 0);
 
-    const int oScore = ((o.localeScript[0] != 0) ? 1 : 0) +
+    const int oScore = (o.localeScriptWasProvided ? 1 : 0) +
         ((o.localeVariant[0] != 0) ? 2 : 0);
 
     return score - oScore;
@@ -2165,6 +2168,63 @@
     return false;
 }
 
+bool ResTable_config::isLocaleBetterThan(const ResTable_config& o,
+        const ResTable_config* requested) const {
+    if (requested->locale == 0) {
+        // The request doesn't have a locale, so no resource is better
+        // than the other.
+        return false;
+    }
+
+    if (locale == 0 && o.locale == 0) {
+        // The locales parts of both resources are empty, so no one is better
+        // than the other.
+        return false;
+    }
+
+    // Non-matching locales have been filtered out, so both resources
+    // match the requested locale.
+    //
+    // Because of the locale-related checks in match() and the checks, we know
+    // that:
+    // 1) The resource languages are either empty or match the request;
+    // and
+    // 2) If the request's script is known, the resource scripts are either
+    //    unknown or match the request.
+
+    if (language[0] != o.language[0]) {
+        // The languages of the two resources are not the same. We can only
+        // assume that one of the two resources matched the request because one
+        // doesn't have a language and the other has a matching language.
+        return (language[0] != 0);
+    }
+
+    // If we are here, both the resources have the same non-empty language as
+    // the request.
+    //
+    // Because the languages are the same, computeScript() always
+    // returns a non-empty script for languages it knows about, and we have passed
+    // the script checks in match(), the scripts are either all unknown or are
+    // all the same. So we can't gain anything by checking the scripts. We need
+    // to check the region and variant.
+
+    // See if any of the regions is better than the other
+    const int region_comparison = localeDataCompareRegions(
+            country, o.country,
+            language, localeScript, requested->country);
+    if (region_comparison != 0) {
+        return (region_comparison > 0);
+    }
+
+    // The regions are the same. Try the variant.
+    if (requested->localeVariant[0] != '\0'
+            && strncmp(localeVariant, requested->localeVariant, sizeof(localeVariant)) == 0) {
+        return (strncmp(o.localeVariant, requested->localeVariant, sizeof(localeVariant)) != 0);
+    }
+
+    return false;
+}
+
 bool ResTable_config::isBetterThan(const ResTable_config& o,
         const ResTable_config* requested) const {
     if (requested) {
@@ -2178,26 +2238,8 @@
             }
         }
 
-        if (locale || o.locale) {
-            if ((language[0] != o.language[0]) && requested->language[0]) {
-                return (language[0]);
-            }
-
-            if ((country[0] != o.country[0]) && requested->country[0]) {
-                return (country[0]);
-            }
-        }
-
-        if (localeScript[0] || o.localeScript[0]) {
-            if (localeScript[0] != o.localeScript[0] && requested->localeScript[0]) {
-                return localeScript[0];
-            }
-        }
-
-        if (localeVariant[0] || o.localeVariant[0]) {
-            if (localeVariant[0] != o.localeVariant[0] && requested->localeVariant[0]) {
-                return localeVariant[0];
-            }
+        if (isLocaleBetterThan(o, requested)) {
+            return true;
         }
 
         if (screenLayout || o.screenLayout) {
@@ -2445,20 +2487,33 @@
         }
     }
     if (locale != 0) {
-        // Don't consider the script & variants when deciding matches.
+        // Don't consider country and variants when deciding matches.
+        // (Theoretically, the variant can also affect the script. For
+        // example, "ar-alalc97" probably implies the Latin script, but since
+        // CLDR doesn't support getting likely scripts for that, we'll assume
+        // the variant doesn't change the script.)
         //
-        // If we two configs differ only in their script or language, they
-        // can be weeded out in the isMoreSpecificThan test.
-        if (language[0] != 0
-            && (language[0] != settings.language[0]
-                || language[1] != settings.language[1])) {
+        // If two configs differ only in their country and variant,
+        // they can be weeded out in the isMoreSpecificThan test.
+        if (language[0] != settings.language[0] || language[1] != settings.language[1]) {
             return false;
         }
 
-        if (country[0] != 0
-            && (country[0] != settings.country[0]
-                || country[1] != settings.country[1])) {
-            return false;
+        // For backward compatibility and supporting private-use locales, we
+        // fall back to old behavior if we couldn't determine the script for
+        // either of the desired locale or the provided locale.
+        if (localeScript[0] == '\0' || localeScript[1] == '\0') {
+            if (country[0] != '\0'
+                && (country[0] != settings.country[0]
+                    || country[1] != settings.country[1])) {
+                return false;
+            }
+        } else {
+            // But if we could determine the scripts, they should be the same
+            // for the locales to match.
+            if (memcmp(localeScript, settings.localeScript, sizeof(localeScript)) != 0) {
+                return false;
+            }
         }
     }
 
@@ -2587,7 +2642,7 @@
         return;
     }
 
-    if (!localeScript[0] && !localeVariant[0]) {
+    if (!localeScriptWasProvided && !localeVariant[0]) {
         // Legacy format.
         if (out.size() > 0) {
             out.append("-");
@@ -2605,7 +2660,7 @@
         return;
     }
 
-    // We are writing the modified bcp47 tag.
+    // We are writing the modified BCP 47 tag.
     // It starts with 'b+' and uses '+' as a separator.
 
     if (out.size() > 0) {
@@ -2617,7 +2672,7 @@
     size_t len = unpackLanguage(buf);
     out.append(buf, len);
 
-    if (localeScript[0]) {
+    if (localeScriptWasProvided) {
         out.append("+");
         out.append(localeScript, sizeof(localeScript));
     }
@@ -2630,7 +2685,7 @@
 
     if (localeVariant[0]) {
         out.append("+");
-        out.append(localeVariant, sizeof(localeVariant));
+        out.append(localeVariant, strnlen(localeVariant, sizeof(localeVariant)));
     }
 }
 
@@ -2648,7 +2703,7 @@
         charsWritten += unpackLanguage(str);
     }
 
-    if (localeScript[0]) {
+    if (localeScriptWasProvided) {
         if (charsWritten) {
             str[charsWritten++] = '-';
         }
@@ -2682,11 +2737,16 @@
            config->language[0] ? config->packRegion(start) : config->packLanguage(start);
            break;
        case 4:
-           config->localeScript[0] = toupper(start[0]);
-           for (size_t i = 1; i < 4; ++i) {
-               config->localeScript[i] = tolower(start[i]);
+           if ('0' <= start[0] && start[0] <= '9') {
+               // this is a variant, so fall through
+           } else {
+               config->localeScript[0] = toupper(start[0]);
+               for (size_t i = 1; i < 4; ++i) {
+                   config->localeScript[i] = tolower(start[i]);
+               }
+               config->localeScriptWasProvided = true;
+               break;
            }
-           break;
        case 5:
        case 6:
        case 7:
@@ -2704,6 +2764,7 @@
 
 void ResTable_config::setBcp47Locale(const char* in) {
     locale = 0;
+    localeScriptWasProvided = false;
     memset(localeScript, 0, sizeof(localeScript));
     memset(localeVariant, 0, sizeof(localeVariant));
 
@@ -2720,6 +2781,9 @@
 
     const size_t size = in + strlen(in) - start;
     assignLocaleComponent(this, start, size);
+    if (localeScript[0] == '\0') {
+        computeScript();
+    };
 }
 
 String8 ResTable_config::toString() const {
@@ -3080,13 +3144,16 @@
 // table that defined the package); the ones after are skins on top of it.
 struct ResTable::PackageGroup
 {
-    PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id, bool appAsLib)
+    PackageGroup(
+            ResTable* _owner, const String16& _name, uint32_t _id,
+            bool appAsLib, bool _isSystemAsset)
         : owner(_owner)
         , name(_name)
         , id(_id)
         , largestTypeId(0)
         , bags(NULL)
         , dynamicRefTable(static_cast<uint8_t>(_id), appAsLib)
+        , isSystemAsset(_isSystemAsset)
     { }
 
     ~PackageGroup() {
@@ -3178,6 +3245,10 @@
     // by having these tables in a per-package scope rather than
     // per-package-group.
     DynamicRefTable                 dynamicRefTable;
+
+    // If the package group comes from a system asset. Used in
+    // determining non-system locales.
+    const bool                      isSystemAsset;
 };
 
 struct ResTable::bag_set
@@ -3572,8 +3643,9 @@
             copyData);
 }
 
-status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData,
-        bool appAsLib) {
+status_t ResTable::add(
+        Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData,
+        bool appAsLib, bool isSystemAsset) {
     const void* data = asset->getBuffer(true);
     if (data == NULL) {
         ALOGW("Unable to get buffer of resource asset file");
@@ -3592,20 +3664,21 @@
     }
 
     return addInternal(data, static_cast<size_t>(asset->getLength()),
-            idmapData, idmapSize, appAsLib, cookie, copyData);
+            idmapData, idmapSize, appAsLib, cookie, copyData, isSystemAsset);
 }
 
-status_t ResTable::add(ResTable* src)
+status_t ResTable::add(ResTable* src, bool isSystemAsset)
 {
     mError = src->mError;
 
-    for (size_t i=0; i<src->mHeaders.size(); i++) {
+    for (size_t i=0; i < src->mHeaders.size(); i++) {
         mHeaders.add(src->mHeaders[i]);
     }
 
-    for (size_t i=0; i<src->mPackageGroups.size(); i++) {
+    for (size_t i=0; i < src->mPackageGroups.size(); i++) {
         PackageGroup* srcPg = src->mPackageGroups[i];
-        PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id, false);
+        PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id,
+                false /* appAsLib */, isSystemAsset || srcPg->isSystemAsset);
         for (size_t j=0; j<srcPg->packages.size(); j++) {
             pg->packages.add(srcPg->packages[j]);
         }
@@ -3646,7 +3719,7 @@
 }
 
 status_t ResTable::addInternal(const void* data, size_t dataSize, const void* idmapData, size_t idmapDataSize,
-        bool appAsLib, const int32_t cookie, bool copyData)
+        bool appAsLib, const int32_t cookie, bool copyData, bool isSystemAsset)
 {
     if (!data) {
         return NO_ERROR;
@@ -3749,7 +3822,8 @@
                 return (mError=BAD_TYPE);
             }
 
-            if (parsePackage((ResTable_package*)chunk, header, appAsLib) != NO_ERROR) {
+            if (parsePackage(
+                    (ResTable_package*)chunk, header, appAsLib, isSystemAsset) != NO_ERROR) {
                 return mError;
             }
             curPackage++;
@@ -5663,7 +5737,7 @@
 }
 
 void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMipmap,
-        bool ignoreAndroidPackage) const {
+        bool ignoreAndroidPackage, bool includeSystemConfigs) const {
     const size_t packageCount = mPackageGroups.size();
     String16 android("android");
     for (size_t i = 0; i < packageCount; i++) {
@@ -5671,6 +5745,9 @@
         if (ignoreAndroidPackage && android == packageGroup->name) {
             continue;
         }
+        if (!includeSystemConfigs && packageGroup->isSystemAsset) {
+            continue;
+        }
         const size_t typeCount = packageGroup->types.size();
         for (size_t j = 0; j < typeCount; j++) {
             const TypeList& typeList = packageGroup->types[j];
@@ -5707,11 +5784,14 @@
     }
 }
 
-void ResTable::getLocales(Vector<String8>* locales) const
+void ResTable::getLocales(Vector<String8>* locales, bool includeSystemLocales) const
 {
     Vector<ResTable_config> configs;
     ALOGV("calling getConfigurations");
-    getConfigurations(&configs);
+    getConfigurations(&configs,
+            false /* ignoreMipmap */,
+            false /* ignoreAndroidPackage */,
+            includeSystemLocales /* includeSystemConfigs */);
     ALOGV("called getConfigurations size=%d", (int)configs.size());
     const size_t I = configs.size();
 
@@ -5937,7 +6017,7 @@
 }
 
 status_t ResTable::parsePackage(const ResTable_package* const pkg,
-                                const Header* const header, bool appAsLib)
+                                const Header* const header, bool appAsLib, bool isSystemAsset)
 {
     const uint8_t* base = (const uint8_t*)pkg;
     status_t err = validate_chunk(&pkg->header, sizeof(*pkg) - sizeof(pkg->typeIdOffset),
@@ -5985,8 +6065,8 @@
     if (id >= 256) {
         LOG_ALWAYS_FATAL("Package id out of range");
         return NO_ERROR;
-    } else if (id == 0 || appAsLib) {
-        // This is a library so assign an ID
+    } else if (id == 0 || appAsLib || isSystemAsset) {
+        // This is a library or a system asset, so assign an ID
         id = mNextPackageId++;
     }
 
@@ -6018,7 +6098,7 @@
 
         char16_t tmpName[sizeof(pkg->name)/sizeof(pkg->name[0])];
         strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(pkg->name[0]));
-        group = new PackageGroup(this, String16(tmpName), id, appAsLib);
+        group = new PackageGroup(this, String16(tmpName), id, appAsLib, isSystemAsset);
         if (group == NULL) {
             delete package;
             return (mError=NO_MEMORY);
diff --git a/libs/androidfw/tests/ConfigLocale_test.cpp b/libs/androidfw/tests/ConfigLocale_test.cpp
index 4999594..1941563 100644
--- a/libs/androidfw/tests/ConfigLocale_test.cpp
+++ b/libs/androidfw/tests/ConfigLocale_test.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <androidfw/LocaleData.h>
 #include <androidfw/ResourceTypes.h>
 #include <utils/Log.h>
 #include <utils/String8.h>
@@ -28,7 +29,7 @@
      EXPECT_EQ('e', config.language[0]);
      EXPECT_EQ('n', config.language[1]);
 
-     char out[4] = { 1, 1, 1, 1};
+     char out[4] = {1, 1, 1, 1};
      config.unpackLanguage(out);
      EXPECT_EQ('e', out[0]);
      EXPECT_EQ('n', out[1]);
@@ -51,7 +52,7 @@
      EXPECT_EQ('U', config.country[0]);
      EXPECT_EQ('S', config.country[1]);
 
-     char out[4] = { 1, 1, 1, 1};
+     char out[4] = {1, 1, 1, 1};
      config.unpackRegion(out);
      EXPECT_EQ('U', out[0]);
      EXPECT_EQ('S', out[1]);
@@ -67,7 +68,7 @@
      EXPECT_EQ('\x99', config.language[0]);
      EXPECT_EQ('\xA4', config.language[1]);
 
-     char out[4] = { 1, 1, 1, 1};
+     char out[4] = {1, 1, 1, 1};
      config.unpackLanguage(out);
      EXPECT_EQ('e', out[0]);
      EXPECT_EQ('n', out[1]);
@@ -91,7 +92,7 @@
      EXPECT_EQ(char(0xbc), config.language[0]);
      EXPECT_EQ(char(0xd3), config.language[1]);
 
-     char out[4] = { 1, 1, 1, 1};
+     char out[4] = {1, 1, 1, 1};
      config.unpackLanguage(out);
      EXPECT_EQ('t', out[0]);
      EXPECT_EQ('g', out[1]);
@@ -103,7 +104,7 @@
      ResTable_config config;
      config.packRegion("419");
 
-     char out[4] = { 1, 1, 1, 1};
+     char out[4] = {1, 1, 1, 1};
      config.unpackRegion(out);
 
      EXPECT_EQ('4', out[0]);
@@ -124,6 +125,10 @@
 
      if (script != NULL) {
          memcpy(out->localeScript, script, 4);
+         out->localeScriptWasProvided = true;
+     } else {
+         out->computeScript();
+         out->localeScriptWasProvided = false;
      }
 
      if (variant != NULL) {
@@ -177,11 +182,12 @@
     EXPECT_EQ('n', test.language[1]);
     EXPECT_EQ('U', test.country[0]);
     EXPECT_EQ('S', test.country[1]);
-    EXPECT_EQ(0, test.localeScript[0]);
+    EXPECT_FALSE(test.localeScriptWasProvided);
+    EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
     EXPECT_EQ(0, test.localeVariant[0]);
 
     test.setBcp47Locale("eng-419");
-    char out[4] = { 1, 1, 1, 1};
+    char out[4] = {1, 1, 1, 1};
     test.unpackLanguage(out);
     EXPECT_EQ('e', out[0]);
     EXPECT_EQ('n', out[1]);
@@ -193,17 +199,397 @@
     EXPECT_EQ('1', out[1]);
     EXPECT_EQ('9', out[2]);
 
-
     test.setBcp47Locale("en-Latn-419");
-    memset(out, 1, 4);
     EXPECT_EQ('e', test.language[0]);
     EXPECT_EQ('n', test.language[1]);
-
     EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
+    EXPECT_TRUE(test.localeScriptWasProvided);
+    memset(out, 1, 4);
     test.unpackRegion(out);
     EXPECT_EQ('4', out[0]);
     EXPECT_EQ('1', out[1]);
     EXPECT_EQ('9', out[2]);
+
+    test.setBcp47Locale("de-1901");
+    memset(out, 1, 4);
+    test.unpackLanguage(out);
+    EXPECT_EQ('d', out[0]);
+    EXPECT_EQ('e', out[1]);
+    EXPECT_EQ('\0', out[2]);
+    EXPECT_FALSE(test.localeScriptWasProvided);
+    EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
+    memset(out, 1, 4);
+    test.unpackRegion(out);
+    EXPECT_EQ('\0', out[0]);
+    EXPECT_EQ(0, strcmp("1901", test.localeVariant));
+
+    test.setBcp47Locale("de-Latn-1901");
+    memset(out, 1, 4);
+    test.unpackLanguage(out);
+    EXPECT_EQ('d', out[0]);
+    EXPECT_EQ('e', out[1]);
+    EXPECT_EQ('\0', out[2]);
+    EXPECT_TRUE(test.localeScriptWasProvided);
+    EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
+    memset(out, 1, 4);
+    test.unpackRegion(out);
+    EXPECT_EQ('\0', out[0]);
+    EXPECT_EQ(0, strcmp("1901", test.localeVariant));
 }
 
-}  // namespace android.
+TEST(ConfigLocaleTest, computeScript) {
+    ResTable_config config;
+
+    fillIn(NULL, NULL, NULL, NULL, &config);
+    EXPECT_EQ(0, memcmp("\0\0\0\0", config.localeScript, 4));
+
+    fillIn("zh", "TW", NULL, NULL, &config);
+    EXPECT_EQ(0, memcmp("Hant", config.localeScript, 4));
+
+    fillIn("zh", "CN", NULL, NULL, &config);
+    EXPECT_EQ(0, memcmp("Hans", config.localeScript, 4));
+
+    fillIn("az", NULL, NULL, NULL, &config);
+    EXPECT_EQ(0, memcmp("Latn", config.localeScript, 4));
+
+    fillIn("az", "AZ", NULL, NULL, &config);
+    EXPECT_EQ(0, memcmp("Latn", config.localeScript, 4));
+
+    fillIn("az", "IR", NULL, NULL, &config);
+    EXPECT_EQ(0, memcmp("Arab", config.localeScript, 4));
+
+    fillIn("peo", NULL, NULL, NULL, &config);
+    EXPECT_EQ(0, memcmp("Xpeo", config.localeScript, 4));
+
+    fillIn("qaa", NULL, NULL, NULL, &config);
+    EXPECT_EQ(0, memcmp("\0\0\0\0", config.localeScript, 4));
+}
+
+TEST(ConfigLocaleTest, getBcp47Locale_script) {
+    ResTable_config config;
+    fillIn("en", NULL, "Latn", NULL, &config);
+
+    char out[RESTABLE_MAX_LOCALE_LEN];
+    config.localeScriptWasProvided = true;
+    config.getBcp47Locale(out);
+    EXPECT_EQ(0, strcmp("en-Latn", out));
+
+    config.localeScriptWasProvided = false;
+    config.getBcp47Locale(out);
+    EXPECT_EQ(0, strcmp("en", out));
+}
+
+TEST(ConfigLocaleTest, match) {
+    ResTable_config supported, requested;
+
+    fillIn(NULL, NULL, NULL, NULL, &supported);
+    fillIn("fr", "CA", NULL, NULL, &requested);
+    // Empty locale matches everything (as a default).
+    EXPECT_TRUE(supported.match(requested));
+
+    fillIn("en", "CA", NULL, NULL, &supported);
+    fillIn("fr", "CA", NULL, NULL, &requested);
+    // Different languages don't match.
+    EXPECT_FALSE(supported.match(requested));
+
+    fillIn("qaa", "FR", NULL, NULL, &supported);
+    fillIn("qaa", "CA", NULL, NULL, &requested);
+    // If we can't infer the scripts, different regions don't match.
+    EXPECT_FALSE(supported.match(requested));
+
+    fillIn("qaa", "FR", "Latn", NULL, &supported);
+    fillIn("qaa", "CA", NULL, NULL, &requested);
+    // If we can't infer any of the scripts, different regions don't match.
+    EXPECT_FALSE(supported.match(requested));
+
+    fillIn("qaa", "FR", NULL, NULL, &supported);
+    fillIn("qaa", "CA", "Latn", NULL, &requested);
+    // If we can't infer any of the scripts, different regions don't match.
+    EXPECT_FALSE(supported.match(requested));
+
+    fillIn("qaa", NULL, NULL, NULL, &supported);
+    fillIn("qaa", "CA", NULL, NULL, &requested);
+    // language-only resources still support language+region requests, even if we can't infer the
+    // script.
+    EXPECT_TRUE(supported.match(requested));
+
+    fillIn("qaa", "CA", NULL, NULL, &supported);
+    fillIn("qaa", "CA", NULL, NULL, &requested);
+    // Even if we can't infer the scripts, exactly equal locales match.
+    EXPECT_TRUE(supported.match(requested));
+
+    fillIn("az", NULL, NULL, NULL, &supported);
+    fillIn("az", NULL, "Latn", NULL, &requested);
+    // If the resolved scripts are the same, it doesn't matter if they were explicitly provided
+    // or not, and they match.
+    EXPECT_TRUE(supported.match(requested));
+
+    fillIn("az", NULL, NULL, NULL, &supported);
+    fillIn("az", NULL, "Cyrl", NULL, &requested);
+    // If the resolved scripts are different, they don't match.
+    EXPECT_FALSE(supported.match(requested));
+
+    fillIn("az", NULL, NULL, NULL, &supported);
+    fillIn("az", "IR", NULL, NULL, &requested);
+    // If the resolved scripts are different, they don't match.
+    EXPECT_FALSE(supported.match(requested));
+
+    fillIn("az", "IR", NULL, NULL, &supported);
+    fillIn("az", NULL, "Arab", NULL, &requested);
+    // If the resolved scripts are the same, it doesn't matter if they were explicitly provided
+    // or not, and they match.
+    EXPECT_TRUE(supported.match(requested));
+
+    fillIn("en", NULL, NULL, NULL, &supported);
+    fillIn("en", "XA", NULL, NULL, &requested);
+    // en-XA is a pseudo-locale, and English resources are not a match for it.
+    EXPECT_FALSE(supported.match(requested));
+
+    fillIn("en", "XA", NULL, NULL, &supported);
+    fillIn("en", NULL, NULL, NULL, &requested);
+    // en-XA is a pseudo-locale, and its resources don't support English locales.
+    EXPECT_FALSE(supported.match(requested));
+
+    fillIn("en", "XA", NULL, NULL, &supported);
+    fillIn("en", "XA", NULL, NULL, &requested);
+    // Even if they are pseudo-locales, exactly equal locales match.
+    EXPECT_TRUE(supported.match(requested));
+
+    fillIn("ar", NULL, NULL, NULL, &supported);
+    fillIn("ar", "XB", NULL, NULL, &requested);
+    // ar-XB is a pseudo-locale, and Arabic resources are not a match for it.
+    EXPECT_FALSE(supported.match(requested));
+
+    fillIn("ar", "XB", NULL, NULL, &supported);
+    fillIn("ar", NULL, NULL, NULL, &requested);
+    // ar-XB is a pseudo-locale, and its resources don't support Arabic locales.
+    EXPECT_FALSE(supported.match(requested));
+
+    fillIn("ar", "XB", NULL, NULL, &supported);
+    fillIn("ar", "XB", NULL, NULL, &requested);
+    // Even if they are pseudo-locales, exactly equal locales match.
+    EXPECT_TRUE(supported.match(requested));
+}
+
+TEST(ConfigLocaleTest, isLocaleBetterThan_basics) {
+    ResTable_config config1, config2, request;
+
+    fillIn(NULL, NULL, NULL, NULL, &request);
+    fillIn("fr", "FR", NULL, NULL, &config1);
+    fillIn("fr", "CA", NULL, NULL, &config2);
+    EXPECT_FALSE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("fr", "CA", NULL, NULL, &request);
+    fillIn(NULL, NULL, NULL, NULL, &config1);
+    fillIn(NULL, NULL, NULL, NULL, &config2);
+    EXPECT_FALSE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("fr", "CA", NULL, NULL, &request);
+    fillIn("fr", "FR", NULL, NULL, &config1);
+    fillIn(NULL, NULL, NULL, NULL, &config2);
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("de", "DE", NULL, NULL, &request);
+    fillIn("de", "DE", NULL, "1901", &config1);
+    fillIn("de", "DE", NULL, "1996", &config2);
+    EXPECT_FALSE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("de", "DE", NULL, "1901", &request);
+    fillIn("de", "DE", NULL, "1901", &config1);
+    fillIn("de", "DE", NULL, NULL, &config2);
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("de", "DE", NULL, "1901", &request);
+    fillIn("de", "DE", NULL, "1996", &config1);
+    fillIn("de", "DE", NULL, NULL, &config2);
+    EXPECT_FALSE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+}
+
+TEST(ConfigLocaleTest, isLocaleBetterThan_regionComparison) {
+    ResTable_config config1, config2, request;
+
+    fillIn("es", "AR", NULL, NULL, &request);
+    fillIn("es", "419", NULL, NULL, &config1);
+    fillIn("es", "419", NULL, NULL, &config2);
+    // Both supported locales are the same, so none is better than the other.
+    EXPECT_FALSE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("es", "AR", NULL, NULL, &request);
+    fillIn("es", "AR", NULL, NULL, &config1);
+    fillIn("es", "419", NULL, NULL, &config2);
+    // An exact locale match is better than a parent.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("es", "AR", NULL, NULL, &request);
+    fillIn("es", "419", NULL, NULL, &config1);
+    fillIn("es", NULL, NULL, NULL, &config2);
+    // A closer parent is better.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("es", "AR", NULL, NULL, &request);
+    fillIn("es", "419", NULL, NULL, &config1);
+    fillIn("es", "ES", NULL, NULL, &config2);
+    // A parent is better than a non-parent representative locale.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("es", "AR", NULL, NULL, &request);
+    fillIn("es", NULL, NULL, NULL, &config1);
+    fillIn("es", "ES", NULL, NULL, &config2);
+    // A parent is better than a non-parent representative locale.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("es", "AR", NULL, NULL, &request);
+    fillIn("es", "PE", NULL, NULL, &config1);
+    fillIn("es", "ES", NULL, NULL, &config2);
+    // A closer locale is better.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("es", "AR", NULL, NULL, &request);
+    fillIn("es", "MX", NULL, NULL, &config1);
+    fillIn("es", "BO", NULL, NULL, &config2);
+    // A representative locale is better if they are equidistant.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("es", "AR", NULL, NULL, &request);
+    fillIn("es", "US", NULL, NULL, &config1);
+    fillIn("es", "BO", NULL, NULL, &config2);
+    // A representative locale is better if they are equidistant.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("es", "AR", NULL, NULL, &request);
+    fillIn("es", "MX", NULL, NULL, &config1);
+    fillIn("es", "US", NULL, NULL, &config2);
+    // If all is equal, the locale earlier in the dictionary is better.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("es", "GQ", NULL, NULL, &request);
+    fillIn("es", "IC", NULL, NULL, &config1);
+    fillIn("es", "419", NULL, NULL, &config2);
+    // If all is equal, the locale earlier in the dictionary is better and
+    // letters are better than numbers.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("en", "GB", NULL, NULL, &request);
+    fillIn("en", "001", NULL, NULL, &config1);
+    fillIn("en", NULL, NULL, NULL, &config2);
+    // A closer parent is better.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("en", "PR", NULL, NULL, &request);
+    fillIn("en", NULL, NULL, NULL, &config1);
+    fillIn("en", "001", NULL, NULL, &config2);
+    // A parent is better than a non-parent.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("en", "DE", NULL, NULL, &request);
+    fillIn("en", "150", NULL, NULL, &config1);
+    fillIn("en", "001", NULL, NULL, &config2);
+    // A closer parent is better.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("en", "IN", NULL, NULL, &request);
+    fillIn("en", "AU", NULL, NULL, &config1);
+    fillIn("en", "US", NULL, NULL, &config2);
+    // A closer locale is better.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("en", "PR", NULL, NULL, &request);
+    fillIn("en", "001", NULL, NULL, &config1);
+    fillIn("en", "GB", NULL, NULL, &config2);
+    // A closer locale is better.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("en", "IN", NULL, NULL, &request);
+    fillIn("en", "GB", NULL, NULL, &config1);
+    fillIn("en", "AU", NULL, NULL, &config2);
+    // A representative locale is better if they are equidistant.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("en", "IN", NULL, NULL, &request);
+    fillIn("en", "AU", NULL, NULL, &config1);
+    fillIn("en", "CA", NULL, NULL, &config2);
+    // If all is equal, the locale earlier in the dictionary is better.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("pt", "MZ", NULL, NULL, &request);
+    fillIn("pt", "PT", NULL, NULL, &config1);
+    fillIn("pt", NULL, NULL, NULL, &config2);
+    // A closer parent is better.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("pt", "MZ", NULL, NULL, &request);
+    fillIn("pt", "PT", NULL, NULL, &config1);
+    fillIn("pt", "BR", NULL, NULL, &config2);
+    // A parent is better than a non-parent.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("zh", "MO", "Hant", NULL, &request);
+    fillIn("zh", "HK", "Hant", NULL, &config1);
+    fillIn("zh", "TW", "Hant", NULL, &config2);
+    // A parent is better than a non-parent.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("zh", "US", "Hant", NULL, &request);
+    fillIn("zh", "TW", "Hant", NULL, &config1);
+    fillIn("zh", "HK", "Hant", NULL, &config2);
+    // A representative locale is better if they are equidistant.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("ar", "DZ", NULL, NULL, &request);
+    fillIn("ar", "015", NULL, NULL, &config1);
+    fillIn("ar", NULL, NULL, NULL, &config2);
+    // A closer parent is better.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("ar", "EG", NULL, NULL, &request);
+    fillIn("ar", NULL, NULL, NULL, &config1);
+    fillIn("ar", "015", NULL, NULL, &config2);
+    // A parent is better than a non-parent.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("ar", "QA", NULL, NULL, &request);
+    fillIn("ar", "EG", NULL, NULL, &config1);
+    fillIn("ar", "BH", NULL, NULL, &config2);
+    // A representative locale is better if they are equidistant.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+
+    fillIn("ar", "QA", NULL, NULL, &request);
+    fillIn("ar", "SA", NULL, NULL, &config1);
+    fillIn("ar", "015", NULL, NULL, &config2);
+    // If all is equal, the locale earlier in the dictionary is better and
+    // letters are better than numbers.
+    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
+    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
+}
+
+}  // namespace android
diff --git a/libs/common_time/common_time_server.cpp b/libs/common_time/common_time_server.cpp
index 01372e0..f72ffaa 100644
--- a/libs/common_time/common_time_server.cpp
+++ b/libs/common_time/common_time_server.cpp
@@ -143,7 +143,7 @@
 
     // Create the eventfd we will use to signal our thread to wake up when
     // needed.
-    mWakeupThreadFD = eventfd(0, EFD_NONBLOCK);
+    mWakeupThreadFD = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
 
     // seed the random number generator (used to generated timeline IDs)
     srand48(static_cast<unsigned int>(systemTime()));
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 0d1ee46..fc40554 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -2,7 +2,12 @@
 include $(CLEAR_VARS)
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
-HWUI_NEW_OPS := false
+HWUI_NEW_OPS := true
+
+# Enables fine-grained GLES error checking
+# If set to true, every GLES call is wrapped & error checked
+# Has moderate overhead
+HWUI_ENABLE_OPENGL_VALIDATION := false
 
 hwui_src_files := \
     font/CacheTexture.cpp \
@@ -53,6 +58,7 @@
     FrameInfoVisualizer.cpp \
     GammaFontRenderer.cpp \
     GlopBuilder.cpp \
+    GpuMemoryTracker.cpp \
     GradientCache.cpp \
     Image.cpp \
     Interpolator.cpp \
@@ -86,7 +92,7 @@
     TextDropShadowCache.cpp \
     Texture.cpp \
     TextureCache.cpp \
-    VectorDrawablePath.cpp \
+    VectorDrawable.cpp \
     protos/hwui.proto
 
 hwui_test_common_src_files := \
@@ -108,7 +114,9 @@
     hwui_src_files += \
         BakedOpDispatcher.cpp \
         BakedOpRenderer.cpp \
-        OpReorderer.cpp \
+        BakedOpState.cpp \
+        FrameBuilder.cpp \
+        LayerBuilder.cpp \
         RecordingCanvas.cpp
 
     hwui_cflags += -DHWUI_NEW_OPS
@@ -154,6 +162,13 @@
         frameworks/rs
 endif
 
+ifeq (true, $(HWUI_ENABLE_OPENGL_VALIDATION))
+    hwui_cflags += -include debug/wrap_gles.h
+    hwui_src_files += debug/wrap_gles.cpp
+    hwui_c_includes += frameworks/native/opengl/libs/GLES2
+    hwui_cflags += -DDEBUG_OPENGL=3
+endif
+
 
 # ------------------------
 # static library
@@ -185,8 +200,8 @@
         -DHWUI_NULL_GPU
 LOCAL_SRC_FILES := \
         $(hwui_src_files) \
-        tests/common/nullegl.cpp \
-        tests/common/nullgles.cpp
+        debug/nullegl.cpp \
+        debug/nullgles.cpp
 LOCAL_C_INCLUDES := $(hwui_c_includes) $(call hwui_proto_include)
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(hwui_c_includes) $(call hwui_proto_include)
 
@@ -223,20 +238,24 @@
     $(hwui_test_common_src_files) \
     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/GpuMemoryTrackerTests.cpp \
     tests/unit/LayerUpdateQueueTests.cpp \
     tests/unit/LinearAllocatorTests.cpp \
     tests/unit/VectorDrawableTests.cpp \
     tests/unit/OffscreenBufferPoolTests.cpp \
-    tests/unit/StringUtilsTests.cpp
+    tests/unit/StringUtilsTests.cpp \
+    tests/unit/BufferPoolTests.cpp
 
 ifeq (true, $(HWUI_NEW_OPS))
     LOCAL_SRC_FILES += \
         tests/unit/BakedOpStateTests.cpp \
-        tests/unit/RecordingCanvasTests.cpp \
-        tests/unit/OpReordererTests.cpp
+        tests/unit/FrameBuilderTests.cpp \
+        tests/unit/LeakCheckTests.cpp \
+        tests/unit/RecordingCanvasTests.cpp
 endif
 
 include $(BUILD_NATIVE_TEST)
@@ -297,7 +316,7 @@
 
 ifeq (true, $(HWUI_NEW_OPS))
     LOCAL_SRC_FILES += \
-        tests/microbench/OpReordererBench.cpp
+        tests/microbench/FrameBuilderBench.cpp
 endif
 
 include $(BUILD_EXECUTABLE)
diff --git a/libs/hwui/AssetAtlas.cpp b/libs/hwui/AssetAtlas.cpp
index 41411a9..6afff1b 100644
--- a/libs/hwui/AssetAtlas.cpp
+++ b/libs/hwui/AssetAtlas.cpp
@@ -39,40 +39,22 @@
         if (!mTexture) {
             Caches& caches = Caches::getInstance();
             mTexture = new Texture(caches);
-            mTexture->width = buffer->getWidth();
-            mTexture->height = buffer->getHeight();
+            mTexture->wrap(mImage->getTexture(),
+                    buffer->getWidth(), buffer->getHeight(), GL_RGBA);
             createEntries(caches, map, count);
         }
     } else {
         ALOGW("Could not create atlas image");
-        delete mImage;
-        mImage = nullptr;
+        terminate();
     }
-
-    updateTextureId();
 }
 
 void AssetAtlas::terminate() {
-    if (mImage) {
-        delete mImage;
-        mImage = nullptr;
-        updateTextureId();
-    }
-}
-
-
-void AssetAtlas::updateTextureId() {
-    mTexture->id = mImage ? mImage->getTexture() : 0;
-    if (mTexture->id) {
-        // Texture ID changed, force-set to defaults to sync the wrapper & GL
-        // state objects
-        mTexture->setWrap(GL_CLAMP_TO_EDGE, false, true);
-        mTexture->setFilter(GL_NEAREST, false, true);
-    }
-    for (size_t i = 0; i < mEntries.size(); i++) {
-        AssetAtlas::Entry* entry = mEntries.valueAt(i);
-        entry->texture->id = mTexture->id;
-    }
+    delete mImage;
+    mImage = nullptr;
+    delete mTexture;
+    mTexture = nullptr;
+    mEntries.clear();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -80,13 +62,13 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 AssetAtlas::Entry* AssetAtlas::getEntry(const SkPixelRef* pixelRef) const {
-    ssize_t index = mEntries.indexOfKey(pixelRef);
-    return index >= 0 ? mEntries.valueAt(index) : nullptr;
+    auto result = mEntries.find(pixelRef);
+    return result != mEntries.end() ? result->second.get() : nullptr;
 }
 
 Texture* AssetAtlas::getEntryTexture(const SkPixelRef* pixelRef) const {
-    ssize_t index = mEntries.indexOfKey(pixelRef);
-    return index >= 0 ? mEntries.valueAt(index)->texture : nullptr;
+    auto result = mEntries.find(pixelRef);
+    return result != mEntries.end() ? result->second->texture : nullptr;
 }
 
 /**
@@ -94,7 +76,8 @@
  * instead of applying the changes to the virtual textures.
  */
 struct DelegateTexture: public Texture {
-    DelegateTexture(Caches& caches, Texture* delegate): Texture(caches), mDelegate(delegate) { }
+    DelegateTexture(Caches& caches, Texture* delegate)
+            : Texture(caches), mDelegate(delegate) { }
 
     virtual void setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture = false,
             bool force = false, GLenum renderTarget = GL_TEXTURE_2D) override {
@@ -111,8 +94,8 @@
 }; // struct DelegateTexture
 
 void AssetAtlas::createEntries(Caches& caches, int64_t* map, int count) {
-    const float width = float(mTexture->width);
-    const float height = float(mTexture->height);
+    const float width = float(mTexture->width());
+    const float height = float(mTexture->height());
 
     for (int i = 0; i < count; ) {
         SkPixelRef* pixelRef = reinterpret_cast<SkPixelRef*>(map[i++]);
@@ -133,13 +116,13 @@
 
         Texture* texture = new DelegateTexture(caches, mTexture);
         texture->blend = !SkAlphaTypeIsOpaque(pixelRef->info().alphaType());
-        texture->width = pixelRef->info().width();
-        texture->height = pixelRef->info().height();
+        texture->wrap(mTexture->id(), pixelRef->info().width(),
+                pixelRef->info().height(), mTexture->format());
 
-        Entry* entry = new Entry(pixelRef, texture, mapper, *this);
+        std::unique_ptr<Entry> entry(new Entry(pixelRef, texture, mapper, *this));
         texture->uvMapper = &entry->uvMapper;
 
-        mEntries.add(entry->pixelRef, entry);
+        mEntries.emplace(entry->pixelRef, std::move(entry));
     }
 }
 
diff --git a/libs/hwui/AssetAtlas.h b/libs/hwui/AssetAtlas.h
index a037725..75400ff 100644
--- a/libs/hwui/AssetAtlas.h
+++ b/libs/hwui/AssetAtlas.h
@@ -17,19 +17,17 @@
 #ifndef ANDROID_HWUI_ASSET_ATLAS_H
 #define ANDROID_HWUI_ASSET_ATLAS_H
 
-#include <GLES2/gl2.h>
-
-#include <ui/GraphicBuffer.h>
-
-#include <utils/KeyedVector.h>
-
-#include <cutils/compiler.h>
-
-#include <SkBitmap.h>
-
 #include "Texture.h"
 #include "UvMapper.h"
 
+#include <cutils/compiler.h>
+#include <GLES2/gl2.h>
+#include <ui/GraphicBuffer.h>
+#include <SkBitmap.h>
+
+#include <memory>
+#include <unordered_map>
+
 namespace android {
 namespace uirenderer {
 
@@ -71,6 +69,10 @@
             return texture->blend ? &atlas.mBlendKey : &atlas.mOpaqueKey;
         }
 
+        ~Entry() {
+            delete texture;
+        }
+
     private:
         /**
          * The pixel ref that generated this atlas entry.
@@ -90,10 +92,6 @@
                 , atlas(atlas) {
         }
 
-        ~Entry() {
-            delete texture;
-        }
-
         friend class AssetAtlas;
     };
 
@@ -127,7 +125,7 @@
      * Can return 0 if the atlas is not initialized.
      */
     uint32_t getWidth() const {
-        return mTexture ? mTexture->width : 0;
+        return mTexture ? mTexture->width() : 0;
     }
 
     /**
@@ -135,7 +133,7 @@
      * Can return 0 if the atlas is not initialized.
      */
     uint32_t getHeight() const {
-        return mTexture ? mTexture->height : 0;
+        return mTexture ? mTexture->height() : 0;
     }
 
     /**
@@ -143,7 +141,7 @@
      * Can return 0 if the atlas is not initialized.
      */
     GLuint getTexture() const {
-        return mTexture ? mTexture->id : 0;
+        return mTexture ? mTexture->id() : 0;
     }
 
     /**
@@ -160,7 +158,6 @@
 
 private:
     void createEntries(Caches& caches, int64_t* map, int count);
-    void updateTextureId();
 
     Texture* mTexture;
     Image* mImage;
@@ -168,7 +165,7 @@
     const bool mBlendKey;
     const bool mOpaqueKey;
 
-    KeyedVector<const SkPixelRef*, Entry*> mEntries;
+    std::unordered_map<const SkPixelRef*, std::unique_ptr<Entry>> mEntries;
 }; // class AssetAtlas
 
 }; // namespace uirenderer
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index 9e39797..7ecc743 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -79,7 +79,9 @@
             .setTransform(Matrix4::identity(), TransformFlags::None)
             .setModelViewIdentityEmptyBounds()
             .build();
-    renderer.renderGlop(nullptr, opList.clipSideFlags ? &opList.clip : nullptr, glop);
+    ClipRect renderTargetClip(opList.clip);
+    const ClipBase* clip = opList.clipSideFlags ? &renderTargetClip : nullptr;
+    renderer.renderGlop(nullptr, clip, glop);
 }
 
 void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer,
@@ -183,7 +185,9 @@
             .setTransform(Matrix4::identity(), TransformFlags::None)
             .setModelViewIdentityEmptyBounds()
             .build();
-    renderer.renderGlop(nullptr, opList.clipSideFlags ? &opList.clip : nullptr, glop);
+    ClipRect renderTargetClip(opList.clip);
+    const ClipBase* clip = opList.clipSideFlags ? &renderTargetClip : nullptr;
+    renderer.renderGlop(nullptr, clip, glop);
 }
 
 static void renderTextShadow(BakedOpRenderer& renderer, FontRenderer& fontRenderer,
@@ -213,7 +217,7 @@
             .setMeshTexturedUnitQuad(nullptr)
             .setFillShadowTexturePaint(*texture, textShadow.color, *op.paint, state.alpha)
             .setTransform(state.computedState.transform, TransformFlags::None)
-            .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width, sy + texture->height))
+            .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width(), sy + texture->height()))
             .build();
     renderer.renderGlop(state, glop);
 }
@@ -224,7 +228,7 @@
 };
 
 static void renderTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state,
-        const Rect* renderClip, TextRenderType renderType) {
+        const ClipBase* renderClip, TextRenderType renderType) {
     FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer();
 
     if (CC_UNLIKELY(PaintUtils::hasTextShadow(op.paint))) {
@@ -272,7 +276,7 @@
 
     bool forceFinish = (renderType == TextRenderType::Flush);
     bool mustDirtyRenderTarget = renderer.offscreenRenderTarget();
-    const Rect* localOpClip = pureTranslate ? &state.computedState.clipRect : nullptr;
+    const Rect* localOpClip = pureTranslate ? &state.computedState.clipRect() : nullptr;
     fontRenderer.renderPosText(op.paint, localOpClip,
             (const char*) op.glyphs, op.glyphCount, x, y,
             op.positions, mustDirtyRenderTarget ? &layerBounds : nullptr, &functor, forceFinish);
@@ -287,7 +291,8 @@
 
 void BakedOpDispatcher::onMergedTextOps(BakedOpRenderer& renderer,
         const MergedBakedOpList& opList) {
-    const Rect* clip = opList.clipSideFlags ? &opList.clip : nullptr;
+    ClipRect renderTargetClip(opList.clip);
+    const ClipBase* clip = opList.clipSideFlags ? &renderTargetClip : nullptr;
     for (size_t i = 0; i < opList.count; i++) {
         const BakedOpState& state = *(opList.states[i]);
         const TextOp& op = *(static_cast<const TextOp*>(state.op));
@@ -297,26 +302,6 @@
     }
 }
 
-void BakedOpDispatcher::onRenderNodeOp(BakedOpRenderer&, const RenderNodeOp&, const BakedOpState&) {
-    LOG_ALWAYS_FATAL("unsupported operation");
-}
-
-void BakedOpDispatcher::onBeginLayerOp(BakedOpRenderer&, const BeginLayerOp&, const BakedOpState&) {
-    LOG_ALWAYS_FATAL("unsupported operation");
-}
-
-void BakedOpDispatcher::onEndLayerOp(BakedOpRenderer&, const EndLayerOp&, const BakedOpState&) {
-    LOG_ALWAYS_FATAL("unsupported operation");
-}
-
-void BakedOpDispatcher::onCirclePropsOp(BakedOpRenderer&, const CirclePropsOp&, const BakedOpState&) {
-    LOG_ALWAYS_FATAL("unsupported operation");
-}
-
-void BakedOpDispatcher::onRoundRectPropsOp(BakedOpRenderer&, const RoundRectPropsOp&, const BakedOpState&) {
-    LOG_ALWAYS_FATAL("unsupported operation");
-}
-
 namespace VertexBufferRenderFlags {
     enum {
         Offset = 0x1,
@@ -352,9 +337,9 @@
 
 static void renderPathTexture(BakedOpRenderer& renderer, const BakedOpState& state,
         PathTexture& texture, const RecordedOp& op) {
-    Rect dest(texture.width, texture.height);
-    dest.translate(texture.left + op.unmappedBounds.left - texture.offset,
-            texture.top + op.unmappedBounds.top - texture.offset);
+    Rect dest(texture.width(), texture.height());
+    dest.translate(texture.left - texture.offset,
+            texture.top - texture.offset);
     Glop glop;
     GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
             .setRoundRectClipState(state.roundRectClipState)
@@ -414,7 +399,7 @@
             .setMeshTexturedUnitQuad(texture->uvMapper)
             .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
             .setTransform(state.computedState.transform, TransformFlags::None)
-            .setModelViewMapUnitToRectSnap(Rect(texture->width, texture->height))
+            .setModelViewMapUnitToRectSnap(Rect(texture->width(), texture->height()))
             .build();
     renderer.renderGlop(state, glop);
 }
@@ -498,10 +483,10 @@
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
-    Rect uv(std::max(0.0f, op.src.left / texture->width),
-            std::max(0.0f, op.src.top / texture->height),
-            std::min(1.0f, op.src.right / texture->width),
-            std::min(1.0f, op.src.bottom / texture->height));
+    Rect uv(std::max(0.0f, op.src.left / texture->width()),
+            std::max(0.0f, op.src.top / texture->height()),
+            std::min(1.0f, op.src.right / texture->width()),
+            std::min(1.0f, op.src.bottom / texture->height()));
 
     const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType)
             ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
@@ -560,19 +545,19 @@
             op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch);
 
     Texture* texture = entry ? entry->texture : renderer.caches().textureCache.get(op.bitmap);
-    if (!texture) return;
-    const AutoTexture autoCleanup(texture);
-    Glop glop;
-    GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
-            .setRoundRectClipState(state.roundRectClipState)
-            .setMeshPatchQuads(*mesh)
-            .setMeshTexturedUnitQuad(texture->uvMapper)
-            .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
-            .setTransform(state.computedState.transform, TransformFlags::None)
-            .setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top,
-                    Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight()))
-            .build();
-    renderer.renderGlop(state, glop);
+    if (CC_LIKELY(texture)) {
+        const AutoTexture autoCleanup(texture);
+        Glop glop;
+        GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+                .setRoundRectClipState(state.roundRectClipState)
+                .setMeshPatchQuads(*mesh)
+                .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
+                .setTransform(state.computedState.transform, TransformFlags::None)
+                .setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top,
+                        Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight()))
+                .build();
+        renderer.renderGlop(state, glop);
+    }
 }
 
 void BakedOpDispatcher::onPathOp(BakedOpRenderer& renderer, const PathOp& op, const BakedOpState& state) {
@@ -701,13 +686,57 @@
 }
 
 void BakedOpDispatcher::onTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state) {
-    const Rect* clip = state.computedState.clipSideFlags ? &state.computedState.clipRect : nullptr;
-    renderTextOp(renderer, op, state, clip, TextRenderType::Flush);
+    renderTextOp(renderer, op, state, state.computedState.getClipIfNeeded(), TextRenderType::Flush);
+}
+
+void BakedOpDispatcher::onTextOnPathOp(BakedOpRenderer& renderer, const TextOnPathOp& op, const BakedOpState& state) {
+    // Note: can't trust clipSideFlags since we record with unmappedBounds == clip.
+    // TODO: respect clipSideFlags, once we record with bounds
+    auto renderTargetClip = state.computedState.clipState;
+
+    FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer();
+    fontRenderer.setFont(op.paint, SkMatrix::I());
+    fontRenderer.setTextureFiltering(true);
+
+    Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
+
+    int alpha = PaintUtils::getAlphaDirect(op.paint) * state.alpha;
+    SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(op.paint);
+    TextDrawFunctor functor(&renderer, &state, renderTargetClip,
+            0.0f, 0.0f, false, alpha, mode, op.paint);
+
+    bool mustDirtyRenderTarget = renderer.offscreenRenderTarget();
+    const Rect localSpaceClip = state.computedState.computeLocalSpaceClip();
+    if (fontRenderer.renderTextOnPath(op.paint, &localSpaceClip,
+            reinterpret_cast<const char*>(op.glyphs), op.glyphCount,
+            op.path, op.hOffset, op.vOffset,
+            mustDirtyRenderTarget ? &layerBounds : nullptr, &functor)) {
+        if (mustDirtyRenderTarget) {
+            // manually dirty render target, since TextDrawFunctor won't
+            state.computedState.transform.mapRect(layerBounds);
+            renderer.dirtyRenderTarget(layerBounds);
+        }
+    }
+}
+
+void BakedOpDispatcher::onTextureLayerOp(BakedOpRenderer& renderer, const TextureLayerOp& op, const BakedOpState& state) {
+    const bool tryToSnap = !op.layer->getForceFilter();
+    float alpha = (op.layer->getAlpha() / 255.0f) * state.alpha;
+    Glop glop;
+    GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+            .setRoundRectClipState(state.roundRectClipState)
+            .setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
+            .setFillTextureLayer(*(op.layer), alpha)
+            .setTransform(state.computedState.transform, TransformFlags::None)
+            .setModelViewMapUnitToRectOptionalSnap(tryToSnap, Rect(op.layer->getWidth(), op.layer->getHeight()))
+            .build();
+    renderer.renderGlop(state, glop);
 }
 
 void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) {
     OffscreenBuffer* buffer = *op.layerHandle;
 
+    // Note that we don't use op->paint here - it's never set on a LayerOp
     float layerAlpha = op.alpha * state.alpha;
     Glop glop;
     GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
@@ -725,5 +754,38 @@
     }
 }
 
+void BakedOpDispatcher::onCopyToLayerOp(BakedOpRenderer& renderer, const CopyToLayerOp& op, const BakedOpState& state) {
+    LOG_ALWAYS_FATAL_IF(*(op.layerHandle) != nullptr, "layer already exists!");
+    *(op.layerHandle) = renderer.copyToLayer(state.computedState.clippedBounds);
+    LOG_ALWAYS_FATAL_IF(*op.layerHandle == nullptr, "layer copy failed");
+}
+
+void BakedOpDispatcher::onCopyFromLayerOp(BakedOpRenderer& renderer, const CopyFromLayerOp& op, const BakedOpState& state) {
+    LOG_ALWAYS_FATAL_IF(*op.layerHandle == nullptr, "no layer to draw underneath!");
+    if (!state.computedState.clippedBounds.isEmpty()) {
+        if (op.paint && op.paint->getAlpha() < 255) {
+            SkPaint layerPaint;
+            layerPaint.setAlpha(op.paint->getAlpha());
+            layerPaint.setXfermodeMode(SkXfermode::kDstIn_Mode);
+            layerPaint.setColorFilter(op.paint->getColorFilter());
+            RectOp rectOp(state.computedState.clippedBounds, Matrix4::identity(), nullptr, &layerPaint);
+            BakedOpDispatcher::onRectOp(renderer, rectOp, state);
+        }
+
+        OffscreenBuffer& layer = **(op.layerHandle);
+        auto mode = PaintUtils::getXfermodeDirect(op.paint);
+        Glop glop;
+        GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+                .setRoundRectClipState(state.roundRectClipState)
+                .setMeshTexturedUvQuad(nullptr, layer.getTextureCoordinates())
+                .setFillLayer(layer.texture, nullptr, 1.0f, mode, Blend::ModeOrderSwap::Swap)
+                .setTransform(state.computedState.transform, TransformFlags::None)
+                .setModelViewMapUnitToRect(state.computedState.clippedBounds)
+                .build();
+        renderer.renderGlop(state, glop);
+    }
+    renderer.renderState().layerPool().putOrDelete(*op.layerHandle);
+}
+
 } // namespace uirenderer
 } // namespace android
diff --git a/libs/hwui/BakedOpDispatcher.h b/libs/hwui/BakedOpDispatcher.h
index ed34ada..4dfdd3f 100644
--- a/libs/hwui/BakedOpDispatcher.h
+++ b/libs/hwui/BakedOpDispatcher.h
@@ -36,13 +36,13 @@
     // Declares all "onMergedBitmapOps(...)" style methods for mergeable op types
 #define X(Type) \
         static void onMerged##Type##s(BakedOpRenderer& renderer, const MergedBakedOpList& opList);
-    MAP_MERGED_OPS(X)
+    MAP_MERGEABLE_OPS(X)
 #undef X
 
     // Declares all "onBitmapOp(...)" style methods for every op type
 #define X(Type) \
         static void on##Type(BakedOpRenderer& renderer, const Type& op, const BakedOpState& state);
-    MAP_OPS(X)
+    MAP_RENDERABLE_OPS(X)
 #undef X
 
 };
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index f8282dc..5736c70 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -48,8 +48,9 @@
 
     // attach the texture to the FBO
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
-            offscreenBuffer->texture.id, 0);
-    LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "startLayer FAILED");
+            offscreenBuffer->texture.id(), 0);
+    GL_CHECKPOINT(LOW);
+
     LOG_ALWAYS_FATAL_IF(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE,
             "framebuffer incomplete!");
 
@@ -60,34 +61,84 @@
 }
 
 void BakedOpRenderer::endLayer() {
+    if (mRenderTarget.stencil) {
+        // if stencil was used for clipping, detach it and return it to pool
+        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
+        GL_CHECKPOINT(MODERATE);
+        mCaches.renderBufferCache.put(mRenderTarget.stencil);
+        mRenderTarget.stencil = nullptr;
+    }
+    mRenderTarget.lastStencilClip = nullptr;
+
     mRenderTarget.offscreenBuffer->updateMeshFromRegion();
-    mRenderTarget.offscreenBuffer = nullptr;
+    mRenderTarget.offscreenBuffer = nullptr; // It's in drawLayerOp's hands now.
 
     // Detach the texture from the FBO
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
-    LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "endLayer FAILED");
+    GL_CHECKPOINT(LOW);
     mRenderState.deleteFramebuffer(mRenderTarget.frameBufferId);
-    mRenderTarget.frameBufferId = -1;
+    mRenderTarget.frameBufferId = 0;
+}
+
+OffscreenBuffer* BakedOpRenderer::copyToLayer(const Rect& area) {
+    OffscreenBuffer* buffer = mRenderState.layerPool().get(mRenderState,
+            area.getWidth(), area.getHeight());
+    if (!area.isEmpty()) {
+        mCaches.textureState().activateTexture(0);
+        mCaches.textureState().bindTexture(buffer->texture.id());
+
+        glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
+                area.left, mRenderTarget.viewportHeight - area.bottom,
+                area.getWidth(), area.getHeight());
+    }
+    return buffer;
 }
 
 void BakedOpRenderer::startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {
+    LOG_ALWAYS_FATAL_IF(mRenderTarget.frameBufferId != 0, "primary framebufferId must be 0");
     mRenderState.bindFramebuffer(0);
     setViewport(width, height);
-    mCaches.clearGarbage();
 
     if (!mOpaque) {
         clearColorBuffer(repaintRect);
     }
+
+    mRenderState.debugOverdraw(true, true);
 }
 
-void BakedOpRenderer::endFrame() {
+void BakedOpRenderer::endFrame(const Rect& repaintRect) {
+    if (CC_UNLIKELY(Properties::debugOverdraw)) {
+        ClipRect overdrawClip(repaintRect);
+        Rect viewportRect(mRenderTarget.viewportWidth, mRenderTarget.viewportHeight);
+        // overdraw visualization
+        for (int i = 1; i <= 4; i++) {
+            if (i < 4) {
+                // nth level of overdraw tests for n+1 draws per pixel
+                mRenderState.stencil().enableDebugTest(i + 1, false);
+            } else {
+                // 4th level tests for 4 or higher draws per pixel
+                mRenderState.stencil().enableDebugTest(4, true);
+            }
+
+            SkPaint paint;
+            paint.setColor(mCaches.getOverdrawColor(i));
+            Glop glop;
+            GlopBuilder(mRenderState, mCaches, &glop)
+                    .setRoundRectClipState(nullptr)
+                    .setMeshUnitQuad()
+                    .setFillPaint(paint, 1.0f)
+                    .setTransform(Matrix4::identity(), TransformFlags::None)
+                    .setModelViewMapUnitToRect(viewportRect)
+                    .build();
+            renderGlop(nullptr, &overdrawClip, glop);
+        }
+        mRenderState.stencil().disable();
+    }
+
+    mCaches.clearGarbage();
     mCaches.pathCache.trim();
     mCaches.tessellationCache.trim();
 
-#if DEBUG_OPENGL
-    GLUtils::dumpGLErrors();
-#endif
-
 #if DEBUG_MEMORY_USAGE
     mCaches.dumpMemoryUsage();
 #else
@@ -107,7 +158,7 @@
 }
 
 void BakedOpRenderer::clearColorBuffer(const Rect& rect) {
-    if (Rect(mRenderTarget.viewportWidth, mRenderTarget.viewportHeight).contains(rect)) {
+    if (rect.contains(Rect(mRenderTarget.viewportWidth, mRenderTarget.viewportHeight))) {
         // Full viewport is being cleared - disable scissor
         mRenderState.scissor().setEnabled(false);
     } else {
@@ -128,12 +179,124 @@
     return texture;
 }
 
-void BakedOpRenderer::prepareRender(const Rect* dirtyBounds, const Rect* clip) {
+// clears and re-fills stencil with provided rendertarget space quads,
+// and then put stencil into test mode
+void BakedOpRenderer::setupStencilQuads(std::vector<Vertex>& quadVertices,
+        int incrementThreshold) {
+    mRenderState.stencil().enableWrite(incrementThreshold);
+    mRenderState.stencil().clear();
+    Glop glop;
+    GlopBuilder(mRenderState, mCaches, &glop)
+            .setRoundRectClipState(nullptr)
+            .setMeshIndexedQuads(quadVertices.data(), quadVertices.size() / 4)
+            .setFillBlack()
+            .setTransform(Matrix4::identity(), TransformFlags::None)
+            .setModelViewIdentityEmptyBounds()
+            .build();
+    mRenderState.render(glop, mRenderTarget.orthoMatrix);
+    mRenderState.stencil().enableTest(incrementThreshold);
+}
+
+void BakedOpRenderer::setupStencilRectList(const ClipBase* clip) {
+    LOG_ALWAYS_FATAL_IF(clip->mode != ClipMode::RectangleList, "can't rectlist clip without rectlist");
+    auto&& rectList = reinterpret_cast<const ClipRectList*>(clip)->rectList;
+    int quadCount = rectList.getTransformedRectanglesCount();
+    std::vector<Vertex> rectangleVertices;
+    rectangleVertices.reserve(quadCount * 4);
+    for (int i = 0; i < quadCount; i++) {
+        const TransformedRectangle& tr(rectList.getTransformedRectangle(i));
+        const Matrix4& transform = tr.getTransform();
+        Rect bounds = tr.getBounds();
+        if (transform.rectToRect()) {
+            // If rectToRect, can simply map bounds before storing verts
+            transform.mapRect(bounds);
+            bounds.doIntersect(clip->rect);
+            if (bounds.isEmpty()) {
+                continue; // will be outside of scissor, skip
+            }
+        }
+
+        rectangleVertices.push_back(Vertex{bounds.left, bounds.top});
+        rectangleVertices.push_back(Vertex{bounds.right, bounds.top});
+        rectangleVertices.push_back(Vertex{bounds.left, bounds.bottom});
+        rectangleVertices.push_back(Vertex{bounds.right, bounds.bottom});
+
+        if (!transform.rectToRect()) {
+            // If not rectToRect, must map each point individually
+            for (auto cur = rectangleVertices.end() - 4; cur < rectangleVertices.end(); cur++) {
+                transform.mapPoint(cur->x, cur->y);
+            }
+        }
+    }
+    setupStencilQuads(rectangleVertices, rectList.getTransformedRectanglesCount());
+}
+
+void BakedOpRenderer::setupStencilRegion(const ClipBase* clip) {
+    LOG_ALWAYS_FATAL_IF(clip->mode != ClipMode::Region, "can't region clip without region");
+    auto&& region = reinterpret_cast<const ClipRegion*>(clip)->region;
+
+    std::vector<Vertex> regionVertices;
+    SkRegion::Cliperator it(region, clip->rect.toSkIRect());
+    while (!it.done()) {
+        const SkIRect& r = it.rect();
+        regionVertices.push_back(Vertex{(float)r.fLeft, (float)r.fTop});
+        regionVertices.push_back(Vertex{(float)r.fRight, (float)r.fTop});
+        regionVertices.push_back(Vertex{(float)r.fLeft, (float)r.fBottom});
+        regionVertices.push_back(Vertex{(float)r.fRight, (float)r.fBottom});
+        it.next();
+    }
+    setupStencilQuads(regionVertices, 0);
+}
+
+void BakedOpRenderer::prepareRender(const Rect* dirtyBounds, const ClipBase* clip) {
+    // Prepare scissor (done before stencil, to simplify filling stencil)
     mRenderState.scissor().setEnabled(clip != nullptr);
     if (clip) {
-        mRenderState.scissor().set(clip->left, mRenderTarget.viewportHeight - clip->bottom,
-            clip->getWidth(), clip->getHeight());
+        mRenderState.scissor().set(mRenderTarget.viewportHeight, clip->rect);
     }
+
+    // If stencil may be used for clipping, enable it, fill it, or disable it as appropriate
+    if (CC_LIKELY(!Properties::debugOverdraw)) {
+        // only modify stencil mode and content when it's not used for overdraw visualization
+        if (CC_UNLIKELY(clip && clip->mode != ClipMode::Rectangle)) {
+            // NOTE: this pointer check is only safe for non-rect clips,
+            // since rect clips may be created on the stack
+            if (mRenderTarget.lastStencilClip != clip) {
+                // Stencil needed, but current stencil isn't up to date
+                mRenderTarget.lastStencilClip = clip;
+
+                if (mRenderTarget.frameBufferId != 0 && !mRenderTarget.stencil) {
+                    OffscreenBuffer* layer = mRenderTarget.offscreenBuffer;
+                    mRenderTarget.stencil = mCaches.renderBufferCache.get(
+                            Stencil::getLayerStencilFormat(),
+                            layer->texture.width(), layer->texture.height());
+                    // stencil is bound + allocated - associate it with current FBO
+                    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+                            GL_RENDERBUFFER, mRenderTarget.stencil->getName());
+                }
+
+                if (clip->mode == ClipMode::RectangleList) {
+                    setupStencilRectList(clip);
+                } else {
+                    setupStencilRegion(clip);
+                }
+            } else {
+                // stencil is up to date - just need to ensure it's enabled (since an unclipped
+                // or scissor-only clipped op may have been drawn, disabling the stencil)
+                int incrementThreshold = 0;
+                if (CC_LIKELY(clip->mode == ClipMode::RectangleList)) {
+                    auto&& rectList = reinterpret_cast<const ClipRectList*>(clip)->rectList;
+                    incrementThreshold = rectList.getTransformedRectanglesCount();
+                }
+                mRenderState.stencil().enableTest(incrementThreshold);
+            }
+        } else {
+            // either scissor or no clip, so disable stencil test
+            mRenderState.stencil().disable();
+        }
+    }
+
+    // dirty offscreenbuffer
     if (dirtyBounds && mRenderTarget.offscreenBuffer) {
         // register layer damage to draw-back region
         android::Rect dirty(dirtyBounds->left, dirtyBounds->top,
@@ -142,17 +305,18 @@
     }
 }
 
-void BakedOpRenderer::renderGlop(const Rect* dirtyBounds, const Rect* clip, const Glop& glop) {
+void BakedOpRenderer::renderGlop(const Rect* dirtyBounds, const ClipBase* clip,
+        const Glop& glop) {
     prepareRender(dirtyBounds, clip);
     mRenderState.render(glop, mRenderTarget.orthoMatrix);
     if (!mRenderTarget.frameBufferId) mHasDrawn = true;
 }
 
 void BakedOpRenderer::renderFunctor(const FunctorOp& op, const BakedOpState& state) {
-    prepareRender(&state.computedState.clippedBounds, &state.computedState.clipRect);
+    prepareRender(&state.computedState.clippedBounds, state.computedState.getClipIfNeeded());
 
     DrawGlInfo info;
-    auto&& clip = state.computedState.clipRect;
+    auto&& clip = state.computedState.clipRect();
     info.clipLeft = clip.left;
     info.clipTop = clip.top;
     info.clipRight = clip.right;
@@ -165,9 +329,28 @@
     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) {
-        android::Rect dirty(uiDirty.left, uiDirty.top, uiDirty.right, uiDirty.bottom);
+        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);
     }
 }
diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h
index f158e8b..10c4698 100644
--- a/libs/hwui/BakedOpRenderer.h
+++ b/libs/hwui/BakedOpRenderer.h
@@ -19,6 +19,7 @@
 
 #include "BakedOpState.h"
 #include "Matrix.h"
+#include "utils/Macros.h"
 
 namespace android {
 namespace uirenderer {
@@ -27,6 +28,7 @@
 struct Glop;
 class Layer;
 class RenderState;
+struct ClipBase;
 
 /**
  * Main rendering manager for a collection of work - one frame + any contained FBOs.
@@ -43,9 +45,15 @@
      * Position agnostic shadow lighting info. Used with all shadow ops in scene.
      */
     struct LightInfo {
-        float lightRadius = 0;
-        uint8_t ambientShadowAlpha = 0;
-        uint8_t spotShadowAlpha = 0;
+        LightInfo() : LightInfo(0, 0, 0) {}
+        LightInfo(float lightRadius, uint8_t ambientShadowAlpha,
+                uint8_t spotShadowAlpha)
+                : lightRadius(lightRadius)
+                , ambientShadowAlpha(ambientShadowAlpha)
+                , spotShadowAlpha(spotShadowAlpha) {}
+        float lightRadius;
+        uint8_t ambientShadowAlpha;
+        uint8_t spotShadowAlpha;
     };
 
     BakedOpRenderer(Caches& caches, RenderState& renderState, bool opaque, const LightInfo& lightInfo)
@@ -59,30 +67,33 @@
     Caches& caches() { return mCaches; }
 
     void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect);
-    void endFrame();
-    OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height);
+    void endFrame(const Rect& repaintRect);
+    WARN_UNUSED_RESULT OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height);
     void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect);
     void endLayer();
+    WARN_UNUSED_RESULT OffscreenBuffer* copyToLayer(const Rect& area);
 
     Texture* getTexture(const SkBitmap* bitmap);
     const LightInfo& getLightInfo() const { return mLightInfo; }
 
     void renderGlop(const BakedOpState& state, const Glop& glop) {
-        bool useScissor = state.computedState.clipSideFlags != OpClipSideFlags::None;
         renderGlop(&state.computedState.clippedBounds,
-                useScissor ? &state.computedState.clipRect : nullptr,
+                state.computedState.getClipIfNeeded(),
                 glop);
     }
     void renderFunctor(const FunctorOp& op, const BakedOpState& state);
 
-    void renderGlop(const Rect* dirtyBounds, const Rect* clip, const Glop& glop);
+    void renderGlop(const Rect* dirtyBounds, const ClipBase* clip, const Glop& glop);
     bool offscreenRenderTarget() { return mRenderTarget.offscreenBuffer != nullptr; }
     void dirtyRenderTarget(const Rect& dirtyRect);
     bool didDraw() const { return mHasDrawn; }
 private:
     void setViewport(uint32_t width, uint32_t height);
     void clearColorBuffer(const Rect& clearRect);
-    void prepareRender(const Rect* dirtyBounds, const Rect* clip);
+    void prepareRender(const Rect* dirtyBounds, const ClipBase* clip);
+    void setupStencilRectList(const ClipBase* clip);
+    void setupStencilRegion(const ClipBase* clip);
+    void setupStencilQuads(std::vector<Vertex>& quadVertices, int incrementThreshold);
 
     RenderState& mRenderState;
     Caches& mCaches;
@@ -92,10 +103,23 @@
     // render target state - setup by start/end layer/frame
     // only valid to use in between start/end pairs.
     struct {
+        // If not drawing to a layer: fbo = 0, offscreenBuffer = null,
+        // Otherwise these refer to currently painting layer's state
         GLuint frameBufferId = 0;
         OffscreenBuffer* offscreenBuffer = nullptr;
+
+        // Used when drawing to a layer and using stencil clipping. otherwise null.
+        RenderBuffer* stencil = nullptr;
+
+        // value representing the ClipRectList* or ClipRegion* currently stored in
+        // the stencil of the current render target
+        const ClipBase* lastStencilClip = nullptr;
+
+        // Size of renderable region in current render target - for layers, may not match actual
+        // bounds of FBO texture. offscreenBuffer->texture has this information.
         uint32_t viewportWidth = 0;
         uint32_t viewportHeight = 0;
+
         Matrix4 orthoMatrix;
     } mRenderTarget;
 
diff --git a/libs/hwui/BakedOpState.cpp b/libs/hwui/BakedOpState.cpp
new file mode 100644
index 0000000..87844f9
--- /dev/null
+++ b/libs/hwui/BakedOpState.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BakedOpState.h"
+
+#include "ClipArea.h"
+
+namespace android {
+namespace uirenderer {
+
+ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
+        const RecordedOp& recordedOp, bool expandForStroke) {
+    // resolvedMatrix = parentMatrix * localMatrix
+    transform.loadMultiply(*snapshot.transform, recordedOp.localMatrix);
+
+    // resolvedClippedBounds = intersect(resolvedMatrix * opBounds, resolvedClipRect)
+    clippedBounds = recordedOp.unmappedBounds;
+    if (CC_UNLIKELY(expandForStroke)) {
+        // account for non-hairline stroke
+        clippedBounds.outset(recordedOp.paint->getStrokeWidth() * 0.5f);
+    }
+    transform.mapRect(clippedBounds);
+    if (CC_UNLIKELY(expandForStroke
+            && (!transform.isPureTranslate() || recordedOp.paint->getStrokeWidth() < 1.0f))) {
+        // account for hairline stroke when stroke may be < 1 scaled pixel
+        // Non translate || strokeWidth < 1 is conservative, but will cover all cases
+        clippedBounds.outset(0.5f);
+    }
+
+    // resolvedClipRect = intersect(parentMatrix * localClip, parentClip)
+    clipState = snapshot.mutateClipArea().serializeIntersectedClip(allocator,
+            recordedOp.localClip, *(snapshot.transform));
+    LOG_ALWAYS_FATAL_IF(!clipState, "must clip!");
+
+    const Rect& clipRect = clipState->rect;
+    if (CC_UNLIKELY(clipRect.isEmpty() || !clippedBounds.intersects(clipRect))) {
+        // Rejected based on either empty clip, or bounds not intersecting with clip
+
+        // Note: we could rewind the clipState object in situations where the clipRect is empty,
+        // but *only* if the caching logic within ClipArea was aware of the rewind.
+        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;
+        clippedBounds.doIntersect(clipRect);
+    }
+}
+
+ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot) {
+    transform = *snapshot.transform;
+
+    // Since the op doesn't have known bounds, we conservatively set the mapped bounds
+    // to the current clipRect, and clipSideFlags to Full.
+    clipState = snapshot.mutateClipArea().serializeClip(allocator);
+    LOG_ALWAYS_FATAL_IF(!clipState, "clipState required");
+    clippedBounds = clipState->rect;
+    clipSideFlags = OpClipSideFlags::Full;
+}
+
+ResolvedRenderState::ResolvedRenderState(const ClipRect* viewportRect, const Rect& dstRect)
+        : transform(Matrix4::identity())
+        , clipState(viewportRect)
+        , clippedBounds(dstRect)
+        , clipSideFlags(OpClipSideFlags::None) {}
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h
index 9c836a0..3db28c9 100644
--- a/libs/hwui/BakedOpState.h
+++ b/libs/hwui/BakedOpState.h
@@ -52,82 +52,42 @@
  */
 class ResolvedRenderState {
 public:
-    // TODO: remove the mapRects/matrix multiply when snapshot & recorded transforms are translates
-    ResolvedRenderState(const Snapshot& snapshot, const RecordedOp& recordedOp, bool expandForStroke) {
-        /* TODO: benchmark a fast path for translate-only matrices, such as:
-        if (CC_LIKELY(snapshot.transform->getType() == Matrix4::kTypeTranslate
-                && recordedOp.localMatrix.getType() == Matrix4::kTypeTranslate)) {
-            float translateX = snapshot.transform->getTranslateX() + recordedOp.localMatrix.getTranslateX();
-            float translateY = snapshot.transform->getTranslateY() + recordedOp.localMatrix.getTranslateY();
-            transform.loadTranslate(translateX, translateY, 0);
+    ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
+            const RecordedOp& recordedOp, bool expandForStroke);
 
-            // resolvedClipRect = intersect(parentMatrix * localClip, parentClip)
-            clipRect = recordedOp.localClipRect;
-            clipRect.translate(translateX, translateY);
-            clipRect.doIntersect(snapshot.getClipRect());
-            clipRect.snapToPixelBoundaries();
+    // Constructor for unbounded ops without transform/clip (namely shadows)
+    ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot);
 
-            // resolvedClippedBounds = intersect(resolvedMatrix * opBounds, resolvedClipRect)
-            clippedBounds = recordedOp.unmappedBounds;
-            clippedBounds.translate(translateX, translateY);
-        } ... */
+    // Constructor for primitive ops provided clip, and no transform
+    ResolvedRenderState(const ClipRect* viewportRect, const Rect& dstRect);
 
-        // resolvedMatrix = parentMatrix * localMatrix
-        transform.loadMultiply(*snapshot.transform, recordedOp.localMatrix);
+    Rect computeLocalSpaceClip() const {
+        Matrix4 inverse;
+        inverse.loadInverse(transform);
 
-        // resolvedClipRect = intersect(parentMatrix * localClip, parentClip)
-        clipRect = recordedOp.localClipRect;
-        snapshot.transform->mapRect(clipRect);
-        clipRect.doIntersect(snapshot.getRenderTargetClip());
-        clipRect.snapToPixelBoundaries();
-
-        // resolvedClippedBounds = intersect(resolvedMatrix * opBounds, resolvedClipRect)
-        clippedBounds = recordedOp.unmappedBounds;
-        if (CC_UNLIKELY(expandForStroke)) {
-            // account for non-hairline stroke
-            clippedBounds.outset(recordedOp.paint->getStrokeWidth() * 0.5f);
-        }
-        transform.mapRect(clippedBounds);
-        if (CC_UNLIKELY(expandForStroke
-                && (!transform.isPureTranslate() || recordedOp.paint->getStrokeWidth() < 1.0f))) {
-            // account for hairline stroke when stroke may be < 1 scaled pixel
-            // Non translate || strokeWidth < 1 is conservative, but will cover all cases
-            clippedBounds.outset(0.5f);
-        }
-
-        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;
-        clippedBounds.doIntersect(clipRect);
-
-        /**
-         * TODO: once we support complex clips, we may want to reject to avoid that work where
-         * possible. Should we:
-         * 1 - quickreject based on clippedBounds, quick early (duplicating logic in resolvedOp)
-         * 2 - merge stuff into tryConstruct factory method, so it can handle quickRejection
-         *         and early return null in one place.
-         */
+        Rect outClip(clipRect());
+        inverse.mapRect(outClip);
+        return outClip;
     }
 
-    /**
-     * Constructor for unbounded ops without transform/clip (namely shadows)
-     *
-     * Since the op doesn't have known bounds, we conservatively set the mapped bounds
-     * to the current clipRect, and clipSideFlags to Full.
-     */
-    ResolvedRenderState(const Snapshot& snapshot) {
-        transform = *snapshot.transform;
-        clipRect = snapshot.getRenderTargetClip();
-        clippedBounds = clipRect;
-        transform.mapRect(clippedBounds);
-        clipSideFlags = OpClipSideFlags::Full;
+    const Rect& clipRect() const {
+        return clipState->rect;
+    }
+
+    bool requiresClip() const {
+        return clipSideFlags != OpClipSideFlags::None
+               || CC_UNLIKELY(clipState->mode != ClipMode::Rectangle);
+    }
+
+    // returns the clip if it's needed to draw the operation, otherwise nullptr
+    const ClipBase* getClipIfNeeded() const {
+        return requiresClip() ? clipState : nullptr;
     }
 
     Matrix4 transform;
-    Rect clipRect;
-    int clipSideFlags = 0;
+    const ClipBase* clipState = nullptr;
     Rect clippedBounds;
+    int clipSideFlags = 0;
 };
 
 /**
@@ -138,8 +98,10 @@
 class BakedOpState {
 public:
     static BakedOpState* tryConstruct(LinearAllocator& allocator,
-            const Snapshot& snapshot, const RecordedOp& recordedOp) {
-        BakedOpState* bakedState = new (allocator) BakedOpState(snapshot, recordedOp, false);
+            Snapshot& snapshot, const RecordedOp& recordedOp) {
+        if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
+        BakedOpState* bakedState = new (allocator) BakedOpState(
+                allocator, snapshot, recordedOp, false);
         if (bakedState->computedState.clippedBounds.isEmpty()) {
             // bounds are empty, so op is rejected
             allocator.rewindIfLastAlloc(bakedState);
@@ -156,15 +118,17 @@
     };
 
     static BakedOpState* tryStrokeableOpConstruct(LinearAllocator& allocator,
-            const Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior) {
+            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 = new (allocator) BakedOpState(
-                snapshot, recordedOp, expandForStroke);
+                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;
         }
@@ -172,11 +136,16 @@
     }
 
     static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator,
-            const Snapshot& snapshot, const ShadowOp* shadowOpPtr) {
-        if (snapshot.getRenderTargetClip().isEmpty()) return nullptr;
+            Snapshot& snapshot, const ShadowOp* shadowOpPtr) {
+        if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
 
         // clip isn't empty, so construct the op
-        return new (allocator) BakedOpState(snapshot, shadowOpPtr);
+        return new (allocator) BakedOpState(allocator, snapshot, shadowOpPtr);
+    }
+
+    static BakedOpState* directConstruct(LinearAllocator& allocator,
+            const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp) {
+        return new (allocator) BakedOpState(clip, dstRect, recordedOp);
     }
 
     static void* operator new(size_t size, LinearAllocator& allocator) {
@@ -184,7 +153,7 @@
     }
 
     // computed state:
-    const ResolvedRenderState computedState;
+    ResolvedRenderState computedState;
 
     // simple state (straight pointer/value storage):
     const float alpha;
@@ -193,19 +162,27 @@
     const RecordedOp* op;
 
 private:
-    BakedOpState(const Snapshot& snapshot, const RecordedOp& recordedOp, bool expandForStroke)
-            : computedState(snapshot, recordedOp, expandForStroke)
+    BakedOpState(LinearAllocator& allocator, Snapshot& snapshot,
+            const RecordedOp& recordedOp, bool expandForStroke)
+            : computedState(allocator, snapshot, recordedOp, expandForStroke)
             , alpha(snapshot.alpha)
             , roundRectClipState(snapshot.roundRectClipState)
             , projectionPathMask(snapshot.projectionPathMask)
             , op(&recordedOp) {}
 
-    BakedOpState(const Snapshot& snapshot, const ShadowOp* shadowOpPtr)
-            : computedState(snapshot)
+    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)
+            , alpha(1.0f)
+            , roundRectClipState(nullptr)
+            , projectionPathMask(nullptr)
+            , op(&recordedOp) {}
 };
 
 }; // namespace uirenderer
diff --git a/libs/hwui/BufferPool.h b/libs/hwui/BufferPool.h
new file mode 100644
index 0000000..005b399
--- /dev/null
+++ b/libs/hwui/BufferPool.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "utils/RefBase.h"
+#include "utils/Log.h"
+#include "utils/Macros.h"
+
+#include <atomic>
+#include <stdint.h>
+#include <memory>
+#include <mutex>
+
+namespace android {
+namespace uirenderer {
+
+/*
+ * Simple thread-safe pool of int64_t arrays of a provided size.
+ *
+ * Permits allocating a client-provided max number of buffers.
+ * If all buffers are in use, refuses to service any more
+ * acquire requests until buffers are re-released to the pool.
+ */
+class BufferPool : public VirtualLightRefBase {
+public:
+    class Buffer {
+        PREVENT_COPY_AND_ASSIGN(Buffer);
+    public:
+        int64_t* getBuffer() { return mBuffer.get(); }
+        size_t getSize() { return mSize; }
+
+        void release() {
+            LOG_ALWAYS_FATAL_IF(mPool.get() == nullptr, "attempt to release unacquired buffer");
+            mPool->release(this);
+        }
+
+        Buffer* incRef() {
+            mRefs++;
+            return this;
+        }
+
+        int decRef() {
+            int refs = mRefs.fetch_sub(1);
+            LOG_ALWAYS_FATAL_IF(refs == 0, "buffer reference decremented below 0");
+            return refs - 1;
+        }
+
+        bool isUniqueRef() {
+            return mRefs.load() == 1;
+        }
+
+    private:
+        friend class BufferPool;
+
+        Buffer(BufferPool* pool, size_t size) : mRefs(1) {
+            mSize = size;
+            mBuffer.reset(new int64_t[size]);
+            mPool = pool;
+        }
+
+        void setPool(BufferPool* pool) {
+            mPool = pool;
+        }
+
+        std::unique_ptr<Buffer> mNext;
+        std::unique_ptr<int64_t[]> mBuffer;
+        sp<BufferPool> mPool;
+        size_t mSize;
+
+        std::atomic_int mRefs;
+    };
+
+    BufferPool(size_t bufferSize, size_t count)
+            : mBufferSize(bufferSize), mCount(count) {}
+
+    /**
+     * Acquires a buffer from the buffer pool if available.
+     *
+     * Only `mCount` buffers are allowed to be in use at a single
+     * instance.
+     *
+     * If no buffer is available, i.e. `mCount` buffers are in use,
+     * returns nullptr.
+     *
+     * The pointer returned from this method *MUST NOT* be freed, instead
+     * BufferPool::release() must be called upon it when the client
+     * is done with it. Failing to release buffers will eventually make the
+     * BufferPool refuse to service any more BufferPool::acquire() requests.
+     */
+    BufferPool::Buffer* acquire() {
+        std::lock_guard<std::mutex> lock(mLock);
+
+        if (mHead.get() != nullptr) {
+            BufferPool::Buffer* res = mHead.release();
+            mHead = std::move(res->mNext);
+            res->mNext.reset(nullptr);
+            res->setPool(this);
+            res->incRef();
+            return res;
+        }
+
+        if (mAllocatedCount < mCount) {
+            ++mAllocatedCount;
+            return new BufferPool::Buffer(this, mBufferSize);
+        }
+
+        return nullptr;
+    }
+
+    /**
+     * Releases a buffer previously acquired by BufferPool::acquire().
+     *
+     * The released buffer is not valid after calling this method and
+     * attempting to use will result in undefined behavior.
+     */
+    void release(BufferPool::Buffer* buffer) {
+        std::lock_guard<std::mutex> lock(mLock);
+
+        if (buffer->decRef() != 0) {
+            return;
+        }
+
+        buffer->setPool(nullptr);
+
+        BufferPool::Buffer* list = mHead.get();
+        if (list == nullptr) {
+            mHead.reset(buffer);
+            mHead->mNext.reset(nullptr);
+            return;
+        }
+
+        while (list->mNext.get() != nullptr) {
+            list = list->mNext.get();
+        }
+
+        list->mNext.reset(buffer);
+    }
+
+    /*
+     * Used for testing.
+     */
+    size_t getAvailableBufferCount() {
+        size_t remainingToAllocateCount = mCount - mAllocatedCount;
+
+        BufferPool::Buffer* list = mHead.get();
+        if (list == nullptr) return remainingToAllocateCount;
+
+        int count = 1;
+        while (list->mNext.get() != nullptr) {
+            count++;
+            list = list->mNext.get();
+        }
+
+        return count + remainingToAllocateCount;
+    }
+
+private:
+    mutable std::mutex mLock;
+
+    size_t mBufferSize;
+    size_t mCount;
+    size_t mAllocatedCount = 0;
+    std::unique_ptr<BufferPool::Buffer> mHead;
+};
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Canvas.h b/libs/hwui/Canvas.h
index 0643a54..9dfe454 100644
--- a/libs/hwui/Canvas.h
+++ b/libs/hwui/Canvas.h
@@ -27,6 +27,22 @@
 
 namespace android {
 
+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
+
 class ANDROID_API Canvas {
 public:
     virtual ~Canvas() {};
@@ -70,16 +86,17 @@
 // ----------------------------------------------------------------------------
 // Canvas state operations
 // ----------------------------------------------------------------------------
+
     // Save (layer)
     virtual int getSaveCount() const = 0;
-    virtual int save(SkCanvas::SaveFlags flags) = 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, SkCanvas::SaveFlags flags) = 0;
+                const SkPaint* paint, SaveFlags::Flags flags) = 0;
     virtual int saveLayerAlpha(float left, float top, float right, float bottom,
-            int alpha, SkCanvas::SaveFlags flags) = 0;
+            int alpha, SaveFlags::Flags flags) = 0;
 
     // Matrix
     virtual void getMatrix(SkMatrix* outMatrix) const = 0;
diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp
index 6a6cc42..43ff33f 100644
--- a/libs/hwui/CanvasState.cpp
+++ b/libs/hwui/CanvasState.cpp
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#include <SkCanvas.h>
-
+#include "Canvas.h"
 #include "CanvasState.h"
 #include "utils/MathUtils.h"
 
@@ -45,6 +44,20 @@
     }
 }
 
+void CanvasState::initializeRecordingSaveStack(int viewportWidth, int viewportHeight) {
+    if (mWidth != viewportWidth || mHeight != viewportHeight) {
+        mWidth = viewportWidth;
+        mHeight = viewportHeight;
+        mFirstSnapshot.initializeViewport(viewportWidth, viewportHeight);
+        mCanvas.onViewportInitialized();
+    }
+
+    freeAllSnapshots();
+    mSnapshot = allocSnapshot(&mFirstSnapshot, SaveFlags::MatrixClip);
+    mSnapshot->setRelativeLightCenter(Vector3());
+    mSaveCount = 1;
+}
+
 void CanvasState::initializeSaveStack(
         int viewportWidth, int viewportHeight,
         float clipLeft, float clipTop,
@@ -57,8 +70,7 @@
     }
 
     freeAllSnapshots();
-    mSnapshot = allocSnapshot(&mFirstSnapshot,
-            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+    mSnapshot = allocSnapshot(&mFirstSnapshot, SaveFlags::MatrixClip);
     mSnapshot->setClip(clipLeft, clipTop, clipRight, clipBottom);
     mSnapshot->fbo = mCanvas.getTargetFbo();
     mSnapshot->setRelativeLightCenter(lightCenter);
@@ -192,7 +204,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 bool CanvasState::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
-    mSnapshot->clip(left, top, right, bottom, op);
+    mSnapshot->clip(Rect(left, top, right, bottom), op);
     mDirtyClip = true;
     return !mSnapshot->clipIsEmpty();
 }
diff --git a/libs/hwui/CanvasState.h b/libs/hwui/CanvasState.h
index 4709ef4..b9e87ae 100644
--- a/libs/hwui/CanvasState.h
+++ b/libs/hwui/CanvasState.h
@@ -80,6 +80,12 @@
      * Initializes the first snapshot, computing the projection matrix,
      * and stores the dimensions of the render target.
      */
+    void initializeRecordingSaveStack(int viewportWidth, int viewportHeight);
+
+    /**
+     * Initializes the first snapshot, computing the projection matrix,
+     * and stores the dimensions of the render target.
+     */
     void initializeSaveStack(int viewportWidth, int viewportHeight,
             float clipLeft, float clipTop, float clipRight, float clipBottom,
             const Vector3& lightCenter);
@@ -168,6 +174,7 @@
     void freeAllSnapshots();
 
     /// indicates that the clip has been changed since the last time it was consumed
+    // TODO: delete when switching to HWUI_NEW_OPS
     bool mDirtyClip;
 
     /// Dimensions of the drawing surface
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
index fd6f0b5..160090d 100644
--- a/libs/hwui/ClipArea.cpp
+++ b/libs/hwui/ClipArea.cpp
@@ -15,10 +15,11 @@
  */
 #include "ClipArea.h"
 
+#include "utils/LinearAllocator.h"
+
 #include <SkPath.h>
 #include <limits>
-
-#include "Rect.h"
+#include <type_traits>
 
 namespace android {
 namespace uirenderer {
@@ -171,12 +172,18 @@
     return rectangleListAsRegion;
 }
 
+void RectangleList::transform(const Matrix4& transform) {
+    for (int index = 0; index < mTransformedRectanglesCount; index++) {
+        mTransformedRectangles[index].transform(transform);
+    }
+}
+
 /*
  * ClipArea
  */
 
 ClipArea::ClipArea()
-        : mMode(Mode::Rectangle) {
+        : mMode(ClipMode::Rectangle) {
 }
 
 /*
@@ -184,45 +191,44 @@
  */
 
 void ClipArea::setViewportDimensions(int width, int height) {
+    mPostViewportClipObserved = false;
     mViewportBounds.set(0, 0, width, height);
     mClipRect = mViewportBounds;
 }
 
 void ClipArea::setEmpty() {
-    mMode = Mode::Rectangle;
+    onClipUpdated();
+    mMode = ClipMode::Rectangle;
     mClipRect.setEmpty();
     mClipRegion.setEmpty();
     mRectangleList.setEmpty();
 }
 
 void ClipArea::setClip(float left, float top, float right, float bottom) {
-    mMode = Mode::Rectangle;
+    onClipUpdated();
+    mMode = ClipMode::Rectangle;
     mClipRect.set(left, top, right, bottom);
     mClipRegion.setEmpty();
 }
 
-void ClipArea::clipRectWithTransform(float left, float top, float right,
-        float bottom, const mat4* transform, SkRegion::Op op) {
-    Rect r(left, top, right, bottom);
-    clipRectWithTransform(r, transform, op);
-}
-
 void ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform,
         SkRegion::Op op) {
+    onClipUpdated();
     switch (mMode) {
-    case Mode::Rectangle:
+    case ClipMode::Rectangle:
         rectangleModeClipRectWithTransform(r, transform, op);
         break;
-    case Mode::RectangleList:
+    case ClipMode::RectangleList:
         rectangleListModeClipRectWithTransform(r, transform, op);
         break;
-    case Mode::Region:
+    case ClipMode::Region:
         regionModeClipRectWithTransform(r, transform, op);
         break;
     }
 }
 
 void ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) {
+    onClipUpdated();
     enterRegionMode();
     mClipRegion.op(region, op);
     onClipRegionUpdated();
@@ -230,6 +236,7 @@
 
 void ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform,
         SkRegion::Op op) {
+    onClipUpdated();
     SkMatrix skTransform;
     transform->copyTo(skTransform);
     SkPath transformed;
@@ -247,7 +254,7 @@
     // Entering rectangle mode discards any
     // existing clipping information from the other modes.
     // The only way this occurs is by a clip setting operation.
-    mMode = Mode::Rectangle;
+    mMode = ClipMode::Rectangle;
 }
 
 void ClipArea::rectangleModeClipRectWithTransform(const Rect& r,
@@ -274,13 +281,6 @@
     rectangleListModeClipRectWithTransform(r, transform, op);
 }
 
-void ClipArea::rectangleModeClipRectWithTransform(float left, float top,
-        float right, float bottom, const mat4* transform, SkRegion::Op op) {
-    Rect r(left, top, right, bottom);
-    rectangleModeClipRectWithTransform(r, transform, op);
-    mClipRect = mRectangleList.calculateBounds();
-}
-
 /*
  * RectangleList mode implementation
  */
@@ -289,8 +289,8 @@
     // Is is only legal to enter rectangle list mode from
     // rectangle mode, since rectangle list mode cannot represent
     // all clip areas that can be represented by a region.
-    ALOG_ASSERT(mMode == Mode::Rectangle);
-    mMode = Mode::RectangleList;
+    ALOG_ASSERT(mMode == ClipMode::Rectangle);
+    mMode = ClipMode::RectangleList;
     mRectangleList.set(mClipRect, Matrix4::identity());
 }
 
@@ -303,23 +303,16 @@
     }
 }
 
-void ClipArea::rectangleListModeClipRectWithTransform(float left, float top,
-        float right, float bottom, const mat4* transform, SkRegion::Op op) {
-    Rect r(left, top, right, bottom);
-    rectangleListModeClipRectWithTransform(r, transform, op);
-}
-
 /*
  * Region mode implementation
  */
 
 void ClipArea::enterRegionMode() {
-    Mode oldMode = mMode;
-    mMode = Mode::Region;
-    if (oldMode != Mode::Region) {
-        if (oldMode == Mode::Rectangle) {
-            mClipRegion.setRect(mClipRect.left, mClipRect.top,
-                    mClipRect.right, mClipRect.bottom);
+    ClipMode oldMode = mMode;
+    mMode = ClipMode::Region;
+    if (oldMode != ClipMode::Region) {
+        if (oldMode == ClipMode::Rectangle) {
+            mClipRegion.setRect(mClipRect.toSkIRect());
         } else {
             mClipRegion = mRectangleList.convertToRegion(createViewportRegion());
             onClipRegionUpdated();
@@ -336,11 +329,6 @@
     onClipRegionUpdated();
 }
 
-void ClipArea::regionModeClipRectWithTransform(float left, float top,
-        float right, float bottom, const mat4* transform, SkRegion::Op op) {
-    regionModeClipRectWithTransform(Rect(left, top, right, bottom), transform, op);
-}
-
 void ClipArea::onClipRegionUpdated() {
     if (!mClipRegion.isEmpty()) {
         mClipRect.set(mClipRegion.getBounds());
@@ -354,5 +342,172 @@
     }
 }
 
+/**
+ * Clip serialization
+ */
+
+const ClipBase* ClipArea::serializeClip(LinearAllocator& allocator) {
+    if (!mPostViewportClipObserved) {
+        // Only initial clip-to-viewport observed, so no serialization of clip necessary
+        return nullptr;
+    }
+
+    static_assert(std::is_trivially_destructible<Rect>::value,
+            "expect Rect to be trivially destructible");
+    static_assert(std::is_trivially_destructible<RectangleList>::value,
+            "expect RectangleList to be trivially destructible");
+
+    if (mLastSerialization == nullptr) {
+        switch (mMode) {
+        case ClipMode::Rectangle:
+            mLastSerialization = allocator.create<ClipRect>(mClipRect);
+            break;
+        case ClipMode::RectangleList:
+            mLastSerialization = allocator.create<ClipRectList>(mRectangleList);
+            break;
+        case ClipMode::Region:
+            mLastSerialization = allocator.create<ClipRegion>(mClipRegion);
+            break;
+        }
+    }
+    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;
+}
+
+inline static const SkRegion& getRegion(const ClipBase* scb) {
+    return reinterpret_cast<const ClipRegion*>(scb)->region;
+}
+
+// Conservative check for too many rectangles to fit in rectangle list.
+// For simplicity, doesn't account for rect merging
+static bool cannotFitInRectangleList(const ClipArea& clipArea, const ClipBase* scb) {
+    int currentRectCount = clipArea.isRectangleList()
+            ? clipArea.getRectangleList().getTransformedRectanglesCount()
+            : 1;
+    int recordedRectCount = (scb->mode == ClipMode::RectangleList)
+            ? getRectList(scb).getTransformedRectanglesCount()
+            : 1;
+    return currentRectCount + recordedRectCount > RectangleList::kMaxTransformedRectangles;
+}
+
+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 (!mLastResolutionResult
+            || recordedClip != mLastResolutionClip
+            || recordedClipTransform != mLastResolutionTransform) {
+        mLastResolutionClip = recordedClip;
+        mLastResolutionTransform = recordedClipTransform;
+
+        if (CC_LIKELY(mMode == ClipMode::Rectangle
+                && recordedClip->mode == ClipMode::Rectangle
+                && recordedClipTransform.rectToRect())) {
+            // common case - result is a single rectangle
+            auto rectClip = allocator.create<ClipRect>(getRect(recordedClip));
+            recordedClipTransform.mapRect(rectClip->rect);
+            rectClip->rect.doIntersect(mClipRect);
+            mLastResolutionResult = rectClip;
+        } else if (CC_UNLIKELY(mMode == ClipMode::Region
+                || recordedClip->mode == ClipMode::Region
+                || cannotFitInRectangleList(*this, recordedClip))) {
+            // region case
+            SkRegion other;
+            switch (recordedClip->mode) {
+            case ClipMode::Rectangle:
+                if (CC_LIKELY(recordedClipTransform.rectToRect())) {
+                    // simple transform, skip creating SkPath
+                    Rect resultClip(getRect(recordedClip));
+                    recordedClipTransform.mapRect(resultClip);
+                    other.setRect(resultClip.toSkIRect());
+                } else {
+                    SkPath transformedRect = pathFromTransformedRectangle(getRect(recordedClip),
+                            recordedClipTransform);
+                    other.setPath(transformedRect, createViewportRegion());
+                }
+                break;
+            case ClipMode::RectangleList: {
+                RectangleList transformedList(getRectList(recordedClip));
+                transformedList.transform(recordedClipTransform);
+                other = transformedList.convertToRegion(createViewportRegion());
+                break;
+            }
+            case ClipMode::Region:
+                other = getRegion(recordedClip);
+
+                // TODO: handle non-translate transforms properly!
+                other.translate(recordedClipTransform.getTranslateX(),
+                        recordedClipTransform.getTranslateY());
+            }
+
+            ClipRegion* regionClip = allocator.create<ClipRegion>();
+            switch (mMode) {
+            case ClipMode::Rectangle:
+                regionClip->region.op(mClipRect.toSkIRect(), other, SkRegion::kIntersect_Op);
+                break;
+            case ClipMode::RectangleList:
+                regionClip->region.op(mRectangleList.convertToRegion(createViewportRegion()),
+                        other, SkRegion::kIntersect_Op);
+                break;
+            case ClipMode::Region:
+                regionClip->region.op(mClipRegion, other, SkRegion::kIntersect_Op);
+                break;
+            }
+            regionClip->rect.set(regionClip->region.getBounds());
+            mLastResolutionResult = regionClip;
+        } else {
+            auto rectListClip = allocator.create<ClipRectList>(mRectangleList);
+            auto&& rectList = rectListClip->rectList;
+            if (mMode == ClipMode::Rectangle) {
+                rectList.set(mClipRect, Matrix4::identity());
+            }
+
+            if (recordedClip->mode == ClipMode::Rectangle) {
+                rectList.intersectWith(getRect(recordedClip), recordedClipTransform);
+            } else {
+                const RectangleList& other = getRectList(recordedClip);
+                for (int i = 0; i < other.getTransformedRectanglesCount(); i++) {
+                    auto&& tr = other.getTransformedRectangle(i);
+                    Matrix4 totalTransform(recordedClipTransform);
+                    totalTransform.multiply(tr.getTransform());
+                    rectList.intersectWith(tr.getBounds(), totalTransform);
+                }
+            }
+            rectListClip->rect = rectList.calculateBounds();
+            mLastResolutionResult = rectListClip;
+        }
+    }
+    return mLastResolutionResult;
+}
+
+void ClipArea::applyClip(const ClipBase* clip, const Matrix4& transform) {
+    if (!clip) return; // nothing to do
+
+    if (CC_LIKELY(clip->mode == ClipMode::Rectangle)) {
+        clipRectWithTransform(getRect(clip), &transform, SkRegion::kIntersect_Op);
+    } else if (CC_LIKELY(clip->mode == ClipMode::RectangleList)) {
+        auto&& rectList = getRectList(clip);
+        for (int i = 0; i < rectList.getTransformedRectanglesCount(); i++) {
+            auto&& tr = rectList.getTransformedRectangle(i);
+            Matrix4 totalTransform(transform);
+            totalTransform.multiply(tr.getTransform());
+            clipRectWithTransform(tr.getBounds(), &totalTransform, SkRegion::kIntersect_Op);
+        }
+    } else {
+        SkRegion region(getRegion(clip));
+        // TODO: handle non-translate transforms properly!
+        region.translate(transform.getTranslateX(), transform.getTranslateY());
+        clipRegion(region, SkRegion::kIntersect_Op);
+    }
+}
+
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/ClipArea.h b/libs/hwui/ClipArea.h
index f88fd92..479796d 100644
--- a/libs/hwui/ClipArea.h
+++ b/libs/hwui/ClipArea.h
@@ -16,15 +16,17 @@
 #ifndef CLIPAREA_H
 #define CLIPAREA_H
 
-#include <SkRegion.h>
-
 #include "Matrix.h"
 #include "Rect.h"
 #include "utils/Pair.h"
 
+#include <SkRegion.h>
+
 namespace android {
 namespace uirenderer {
 
+class LinearAllocator;
+
 Rect transformAndCalculateBounds(const Rect& r, const Matrix4& transform);
 
 class TransformedRectangle {
@@ -50,6 +52,12 @@
         return mTransform;
     }
 
+    void transform(const Matrix4& transform) {
+        Matrix4 t;
+        t.loadMultiply(transform, mTransform);
+        mTransform = t;
+    }
+
 private:
     Rect mBounds;
     Matrix4 mTransform;
@@ -66,27 +74,62 @@
     void setEmpty();
     void set(const Rect& bounds, const Matrix4& transform);
     bool intersectWith(const Rect& bounds, const Matrix4& transform);
+    void transform(const Matrix4& transform);
 
     SkRegion convertToRegion(const SkRegion& clip) const;
     Rect calculateBounds() const;
 
-private:
     enum {
         kMaxTransformedRectangles = 5
     };
 
+private:
     int mTransformedRectanglesCount;
     TransformedRectangle mTransformedRectangles[kMaxTransformedRectangles];
 };
 
-class ClipArea {
-private:
-    enum class Mode {
-        Rectangle,
-        Region,
-        RectangleList
-    };
+enum class ClipMode {
+    Rectangle,
+    RectangleList,
 
+    // region and path - intersected. if either is empty, don't use
+    Region
+};
+
+struct ClipBase {
+    ClipBase(ClipMode mode)
+            : mode(mode) {}
+    ClipBase(const Rect& rect)
+            : mode(ClipMode::Rectangle)
+            , rect(rect) {}
+    const ClipMode mode;
+    // Bounds of the clipping area, used to define the scissor, and define which
+    // portion of the stencil is updated/used
+    Rect rect;
+};
+
+struct ClipRect : ClipBase {
+    ClipRect(const Rect& rect)
+            : ClipBase(rect) {}
+};
+
+struct ClipRectList : ClipBase {
+    ClipRectList(const RectangleList& rectList)
+            : ClipBase(ClipMode::RectangleList)
+            , rectList(rectList) {}
+    RectangleList rectList;
+};
+
+struct ClipRegion : ClipBase {
+    ClipRegion(const SkRegion& region)
+            : ClipBase(ClipMode::Region)
+            , region(region) {}
+    ClipRegion()
+            : ClipBase(ClipMode::Region) {}
+    SkRegion region;
+};
+
+class ClipArea {
 public:
     ClipArea();
 
@@ -98,8 +141,6 @@
 
     void setEmpty();
     void setClip(float left, float top, float right, float bottom);
-    void clipRectWithTransform(float left, float top, float right, float bottom,
-            const mat4* transform, SkRegion::Op op);
     void clipRectWithTransform(const Rect& r, const mat4* transform,
             SkRegion::Op op);
     void clipRegion(const SkRegion& region, SkRegion::Op op);
@@ -119,26 +160,27 @@
     }
 
     bool isRegion() const {
-        return Mode::Region == mMode;
+        return ClipMode::Region == mMode;
     }
 
     bool isSimple() const {
-        return mMode == Mode::Rectangle;
+        return mMode == ClipMode::Rectangle;
     }
 
     bool isRectangleList() const {
-        return mMode == Mode::RectangleList;
+        return mMode == ClipMode::RectangleList;
     }
 
+    const ClipBase* serializeClip(LinearAllocator& allocator);
+    const ClipBase* serializeIntersectedClip(LinearAllocator& allocator,
+            const ClipBase* recordedClip, const Matrix4& recordedClipTransform);
+    void applyClip(const ClipBase* recordedClip, const Matrix4& recordedClipTransform);
+
 private:
     void enterRectangleMode();
     void rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
-    void rectangleModeClipRectWithTransform(float left, float top, float right,
-            float bottom, const mat4* transform, SkRegion::Op op);
 
     void enterRectangleListMode();
-    void rectangleListModeClipRectWithTransform(float left, float top,
-            float right, float bottom, const mat4* transform, SkRegion::Op op);
     void rectangleListModeClipRectWithTransform(const Rect& r,
             const mat4* transform, SkRegion::Op op);
 
@@ -147,12 +189,17 @@
     void enterRegionMode();
     void regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
             SkRegion::Op op);
-    void regionModeClipRectWithTransform(float left, float top, float right,
-            float bottom, const mat4* transform, SkRegion::Op op);
 
     void ensureClipRegion();
     void onClipRegionUpdated();
 
+    // Called by every state modifying public method.
+    void onClipUpdated() {
+        mPostViewportClipObserved = true;
+        mLastSerialization = nullptr;
+        mLastResolutionResult = nullptr;
+    }
+
     SkRegion createViewportRegion() {
         return SkRegion(mViewportBounds.toSkIRect());
     }
@@ -163,7 +210,22 @@
         pathAsRegion.setPath(path, createViewportRegion());
     }
 
-    Mode mMode;
+    ClipMode mMode;
+    bool mPostViewportClipObserved = false;
+
+    /**
+     * If mLastSerialization is non-null, it represents an already serialized copy
+     * of the current clip state. If null, it has not been computed.
+     */
+    const ClipBase* mLastSerialization = nullptr;
+
+    /**
+     * This pair of pointers is a single entry cache of most recently seen
+     */
+    const ClipBase* mLastResolutionResult = nullptr;
+    const ClipBase* mLastResolutionClip = nullptr;
+    Matrix4 mLastResolutionTransform;
+
     Rect mViewportBounds;
     Rect mClipRect;
     SkRegion mClipRegion;
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index e98fa04..748edef 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -17,8 +17,18 @@
 #ifndef ANDROID_HWUI_DEBUG_H
 #define ANDROID_HWUI_DEBUG_H
 
+#define DEBUG_LEVEL_HIGH 3
+#define DEBUG_LEVEL_MODERATE 2
+#define DEBUG_LEVEL_LOW 1
+#define DEBUG_LEVEL_NONE 0
+
 // Turn on to check for OpenGL errors on each frame
-#define DEBUG_OPENGL 1
+// Note DEBUG_LEVEL_HIGH for DEBUG_OPENGL is only setable by enabling
+// HWUI_ENABLE_OPENGL_VALIDATION when building HWUI. Similarly if
+// HWUI_ENABLE_OPENGL_VALIDATION is set then this is always DEBUG_LEVEL_HIGH
+#ifndef DEBUG_OPENGL
+#define DEBUG_OPENGL DEBUG_LEVEL_LOW
+#endif
 
 // Turn on to enable initialization information
 #define DEBUG_INIT 0
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index a1825c5..1b0f424 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#include <SkCanvas.h>
-
 #include <utils/Trace.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
@@ -419,7 +417,7 @@
  * beginning of the frame. This would avoid targetting and removing an FBO in the middle of a frame.
  *
  * saveLayer operations should be pulled to the beginning of the frame if the canvas doesn't have a
- * complex clip, and if the flags (kClip_SaveFlag & kClipToLayer_SaveFlag) are set.
+ * complex clip, and if the flags (SaveFlags::Clip & SaveFlags::ClipToLayer) are set.
  */
 void DeferredDisplayList::addSaveLayer(OpenGLRenderer& renderer,
         SaveLayerOp* op, int newSaveCount) {
@@ -438,7 +436,7 @@
     int saveFlags = op->getFlags();
     DEFER_LOGD("%p adding saveOp %p, flags %x, new count %d", this, op, saveFlags, newSaveCount);
 
-    if (recordingComplexClip() && (saveFlags & SkCanvas::kClip_SaveFlag)) {
+    if (recordingComplexClip() && (saveFlags & SaveFlags::Clip)) {
         // store and replay the save operation, as it may be needed to correctly playback the clip
         DEFER_LOGD("    adding save barrier with new save count %d", newSaveCount);
         storeStateOpBarrier(renderer, op);
@@ -621,7 +619,7 @@
             this, newSaveCount, mBatches.size());
 
     // store displayState for the restore operation, as it may be associated with a saveLayer that
-    // doesn't have kClip_SaveFlag set
+    // doesn't have SaveFlags::Clip set
     DeferredDisplayState* state = createState();
     renderer.storeDisplayState(*state, getStateOpDeferFlags());
     mBatches.push_back(new RestoreToCountBatch(op, state, newSaveCount));
@@ -654,7 +652,7 @@
     renderer.eventMark("Flush");
 
     // save and restore so that reordering doesn't affect final state
-    renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+    renderer.save(SaveFlags::MatrixClip);
 
     if (CC_LIKELY(avoidOverdraw())) {
         for (unsigned int i = 1; i < mBatches.size(); i++) {
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 7038334..f833a54 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -53,8 +53,7 @@
     SkRefCnt_SafeAssign(mColorFilter, colorFilter);
 }
 
-bool DeferredLayerUpdater::apply() {
-    bool success = true;
+void DeferredLayerUpdater::apply() {
     // These properties are applied the same to both layer types
     mLayer->setColorFilter(mColorFilter);
     mLayer->setAlpha(mAlpha, mMode);
@@ -73,7 +72,6 @@
             setTransform(nullptr);
         }
     }
-    return success;
 }
 
 void DeferredLayerUpdater::doUpdateTexImage() {
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index df7c594..6a3c890 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -77,13 +77,13 @@
 
     ANDROID_API void setPaint(const SkPaint* paint);
 
-    ANDROID_API bool apply();
+    void apply();
 
     Layer* backingLayer() {
         return mLayer;
     }
 
-    ANDROID_API void detachSurfaceTexture();
+    void detachSurfaceTexture();
 
 private:
     // Generic properties
diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp
index 759c12a..384e64d 100644
--- a/libs/hwui/DisplayListCanvas.cpp
+++ b/libs/hwui/DisplayListCanvas.cpp
@@ -102,7 +102,7 @@
     return mSkiaCanvasProxy.get();
 }
 
-int DisplayListCanvas::save(SkCanvas::SaveFlags flags) {
+int DisplayListCanvas::save(SaveFlags::Flags flags) {
     addStateOp(new (alloc()) SaveOp((int) flags));
     return mState.save((int) flags);
 }
@@ -125,9 +125,9 @@
 }
 
 int DisplayListCanvas::saveLayer(float left, float top, float right, float bottom,
-        const SkPaint* paint, SkCanvas::SaveFlags flags) {
+        const SkPaint* paint, SaveFlags::Flags flags) {
     // force matrix/clip isolation for layer
-    flags |= SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag;
+    flags |= SaveFlags::MatrixClip;
 
     paint = refPaint(paint);
     addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, paint, (int) flags));
@@ -232,7 +232,7 @@
 
 void DisplayListCanvas::drawBitmap(const SkBitmap& bitmap, float left, float top,
         const SkPaint* paint) {
-    save(SkCanvas::kMatrix_SaveFlag);
+    save(SaveFlags::Matrix);
     translate(left, top);
     drawBitmap(&bitmap, paint);
     restore();
@@ -253,7 +253,7 @@
         drawBitmap(bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom,
                    dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint);
     } else {
-        save(SkCanvas::kMatrix_SaveFlag);
+        save(SaveFlags::Matrix);
         concat(matrix);
         drawBitmap(&bitmap, paint);
         restore();
@@ -269,7 +269,7 @@
             && (srcBottom - srcTop == dstBottom - dstTop)
             && (srcRight - srcLeft == dstRight - dstLeft)) {
         // transform simple rect to rect drawing case into position bitmap ops, since they merge
-        save(SkCanvas::kMatrix_SaveFlag);
+        save(SaveFlags::Matrix);
         translate(dstLeft, dstTop);
         drawBitmap(&bitmap, paint);
         restore();
@@ -283,7 +283,7 @@
                 // Apply the scale transform on the canvas, so that the shader
                 // effectively calculates positions relative to src rect space
 
-                save(SkCanvas::kMatrix_SaveFlag);
+                save(SaveFlags::Matrix);
                 translate(dstLeft, dstTop);
                 scale(scaleX, scaleY);
 
diff --git a/libs/hwui/DisplayListCanvas.h b/libs/hwui/DisplayListCanvas.h
index 72fc100..f1cfa08 100644
--- a/libs/hwui/DisplayListCanvas.h
+++ b/libs/hwui/DisplayListCanvas.h
@@ -128,14 +128,14 @@
 // ----------------------------------------------------------------------------
     // Save (layer)
     virtual int getSaveCount() const override { return mState.getSaveCount(); }
-    virtual int save(SkCanvas::SaveFlags flags) override;
+    virtual int save(SaveFlags::Flags flags) override;
     virtual void restore() override;
     virtual void restoreToCount(int saveCount) override;
 
     virtual int saveLayer(float left, float top, float right, float bottom, const SkPaint* paint,
-        SkCanvas::SaveFlags flags) override;
+        SaveFlags::Flags flags) override;
     virtual int saveLayerAlpha(float left, float top, float right, float bottom,
-            int alpha, SkCanvas::SaveFlags flags) override {
+            int alpha, SaveFlags::Flags flags) override {
         SkPaint paint;
         paint.setAlpha(alpha);
         return saveLayer(left, top, right, bottom, &paint, flags);
diff --git a/libs/hwui/Dither.cpp b/libs/hwui/Dither.cpp
index 1ba6511..ec2013e 100644
--- a/libs/hwui/Dither.cpp
+++ b/libs/hwui/Dither.cpp
@@ -54,7 +54,6 @@
                 15 * dither,  7 * dither, 13 * dither,  5 * dither
             };
 
-            glPixelStorei(GL_UNPACK_ALIGNMENT, sizeof(GLfloat));
             glTexImage2D(GL_TEXTURE_2D, 0, GL_R16F, DITHER_KERNEL_SIZE, DITHER_KERNEL_SIZE, 0,
                     GL_RED, GL_FLOAT, &pattern);
         } else {
@@ -65,7 +64,6 @@
                 15,  7, 13,  5
             };
 
-            glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
             glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, DITHER_KERNEL_SIZE, DITHER_KERNEL_SIZE, 0,
                     GL_ALPHA, GL_UNSIGNED_BYTE, &pattern);
         }
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index ed31a2c..68bae6d 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -458,7 +458,6 @@
     GLuint lastTextureId = 0;
 
     bool resetPixelStore = false;
-    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 
     // Iterate over all the cache textures and see which ones need to be updated
     checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index ff4dc4a..9994498 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -47,6 +47,7 @@
 #if HWUI_NEW_OPS
 class BakedOpState;
 class BakedOpRenderer;
+struct ClipBase;
 #else
 class OpenGLRenderer;
 #endif
@@ -57,7 +58,7 @@
 #if HWUI_NEW_OPS
             BakedOpRenderer* renderer,
             const BakedOpState* bakedState,
-            const Rect* clip,
+            const ClipBase* clip,
 #else
             OpenGLRenderer* renderer,
 #endif
@@ -81,7 +82,7 @@
 #if HWUI_NEW_OPS
     BakedOpRenderer* renderer;
     const BakedOpState* bakedState;
-    const Rect* clip;
+    const ClipBase* clip;
 #else
     OpenGLRenderer* renderer;
 #endif
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
new file mode 100644
index 0000000..a457212
--- /dev/null
+++ b/libs/hwui/FrameBuilder.cpp
@@ -0,0 +1,797 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "FrameBuilder.h"
+
+#include "Canvas.h"
+#include "LayerUpdateQueue.h"
+#include "RenderNode.h"
+#include "renderstate/OffscreenBufferPool.h"
+#include "utils/FatVector.h"
+#include "utils/PaintUtils.h"
+#include "utils/TraceUtils.h"
+
+#include <SkPathOps.h>
+#include <utils/TypeHelpers.h>
+
+namespace android {
+namespace uirenderer {
+
+FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
+        uint32_t viewportWidth, uint32_t viewportHeight,
+        const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter)
+        : FrameBuilder(layers, clip, viewportWidth, viewportHeight, nodes, lightCenter,
+                Rect(0, 0, 0, 0)) {
+}
+
+
+FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
+        uint32_t viewportWidth, uint32_t viewportHeight,
+        const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter,
+        const Rect &contentDrawBounds)
+        : mCanvasState(*this) {
+    ATRACE_NAME("prepare drawing commands");
+
+    mLayerBuilders.reserve(layers.entries().size());
+    mLayerStack.reserve(layers.entries().size());
+
+    // Prepare to defer Fbo0
+    auto fbo0 = mAllocator.create<LayerBuilder>(viewportWidth, viewportHeight, Rect(clip));
+    mLayerBuilders.push_back(fbo0);
+    mLayerStack.push_back(0);
+    mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
+            clip.fLeft, clip.fTop, clip.fRight, clip.fBottom,
+            lightCenter);
+
+    // Render all layers to be updated, in order. Defer in reverse order, so that they'll be
+    // updated in the order they're passed in (mLayerBuilders are issued to Renderer in reverse)
+    for (int i = layers.entries().size() - 1; i >= 0; i--) {
+        RenderNode* layerNode = layers.entries()[i].renderNode;
+        // only schedule repaint if node still on layer - possible it may have been
+        // removed during a dropped frame, but layers may still remain scheduled so
+        // as not to lose info on what portion is damaged
+        if (CC_LIKELY(layerNode->getLayer() != nullptr)) {
+            const Rect& layerDamage = layers.entries()[i].damage;
+            layerNode->computeOrdering();
+
+            // map current light center into RenderNode's coordinate space
+            Vector3 lightCenter = mCanvasState.currentSnapshot()->getRelativeLightCenter();
+            layerNode->getLayer()->inverseTransformInWindow.mapPoint3d(lightCenter);
+
+            saveForLayer(layerNode->getWidth(), layerNode->getHeight(), 0, 0,
+                    layerDamage, lightCenter, nullptr, layerNode);
+
+            if (layerNode->getDisplayList()) {
+                deferNodeOps(*layerNode);
+            }
+            restoreForLayer();
+        }
+    }
+
+    // It there are multiple render nodes, they are laid out as follows:
+    // #0 - backdrop (content + caption)
+    // #1 - content (positioned at (0,0) and clipped to - its bounds mContentDrawBounds)
+    // #2 - additional overlay nodes
+    // Usually the backdrop cannot be seen since it will be entirely covered by the content. While
+    // resizing however it might become partially visible. The following render loop will crop the
+    // backdrop against the content and draw the remaining part of it. It will then draw the content
+    // cropped to the backdrop (since that indicates a shrinking of the window).
+    //
+    // Additional nodes will be drawn on top with no particular clipping semantics.
+
+    // The bounds of the backdrop against which the content should be clipped.
+    Rect backdropBounds = contentDrawBounds;
+    // Usually the contents bounds should be mContentDrawBounds - however - we will
+    // move it towards the fixed edge to give it a more stable appearance (for the moment).
+    // If there is no content bounds we ignore the layering as stated above and start with 2.
+    int layer = (contentDrawBounds.isEmpty() || nodes.size() == 1) ? 2 : 0;
+
+    for (const sp<RenderNode>& node : nodes) {
+        if (node->nothingToDraw()) continue;
+        node->computeOrdering();
+        int count = mCanvasState.save(SaveFlags::MatrixClip);
+
+        if (layer == 0) {
+            const RenderProperties& properties = node->properties();
+            Rect targetBounds(properties.getLeft(), properties.getTop(),
+                              properties.getRight(), properties.getBottom());
+            // Move the content bounds towards the fixed corner of the backdrop.
+            const int x = targetBounds.left;
+            const int y = targetBounds.top;
+            // Remember the intersection of the target bounds and the intersection bounds against
+            // which we have to crop the content.
+            backdropBounds.set(x, y, x + backdropBounds.getWidth(), y + backdropBounds.getHeight());
+            backdropBounds.doIntersect(targetBounds);
+        } else if (layer == 1) {
+            // We shift and clip the content to match its final location in the window.
+            const float left = contentDrawBounds.left;
+            const float top = contentDrawBounds.top;
+            const float dx = backdropBounds.left - left;
+            const float dy = backdropBounds.top - top;
+            const float width = backdropBounds.getWidth();
+            const float height = backdropBounds.getHeight();
+            mCanvasState.translate(dx, dy);
+            // It gets cropped against the bounds of the backdrop to stay inside.
+            mCanvasState.clipRect(left, top, left + width, top + height, SkRegion::kIntersect_Op);
+        }
+
+        deferNodePropsAndOps(*node);
+        mCanvasState.restoreToCount(count);
+        layer++;
+    }
+}
+
+void FrameBuilder::onViewportInitialized() {}
+
+void FrameBuilder::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
+
+void FrameBuilder::deferNodePropsAndOps(RenderNode& node) {
+    const RenderProperties& properties = node.properties();
+    const Outline& outline = properties.getOutline();
+    if (properties.getAlpha() <= 0
+            || (outline.getShouldClip() && outline.isEmpty())
+            || properties.getScaleX() == 0
+            || properties.getScaleY() == 0) {
+        return; // rejected
+    }
+
+    if (properties.getLeft() != 0 || properties.getTop() != 0) {
+        mCanvasState.translate(properties.getLeft(), properties.getTop());
+    }
+    if (properties.getStaticMatrix()) {
+        mCanvasState.concatMatrix(*properties.getStaticMatrix());
+    } else if (properties.getAnimationMatrix()) {
+        mCanvasState.concatMatrix(*properties.getAnimationMatrix());
+    }
+    if (properties.hasTransformMatrix()) {
+        if (properties.isTransformTranslateOnly()) {
+            mCanvasState.translate(properties.getTranslationX(), properties.getTranslationY());
+        } else {
+            mCanvasState.concatMatrix(*properties.getTransformMatrix());
+        }
+    }
+
+    const int width = properties.getWidth();
+    const int height = properties.getHeight();
+
+    Rect saveLayerBounds; // will be set to non-empty if saveLayer needed
+    const bool isLayer = properties.effectiveLayerType() != LayerType::None;
+    int clipFlags = properties.getClippingFlags();
+    if (properties.getAlpha() < 1) {
+        if (isLayer) {
+            clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
+        }
+        if (CC_LIKELY(isLayer || !properties.getHasOverlappingRendering())) {
+            // simply scale rendering content's alpha
+            mCanvasState.scaleAlpha(properties.getAlpha());
+        } else {
+            // schedule saveLayer by initializing saveLayerBounds
+            saveLayerBounds.set(0, 0, width, height);
+            if (clipFlags) {
+                properties.getClippingRectForFlags(clipFlags, &saveLayerBounds);
+                clipFlags = 0; // all clipping done by savelayer
+            }
+        }
+
+        if (CC_UNLIKELY(ATRACE_ENABLED() && properties.promotedToLayer())) {
+            // pretend alpha always causes savelayer to warn about
+            // performance problem affecting old versions
+            ATRACE_FORMAT("%s alpha caused saveLayer %dx%d", node.getName(), width, height);
+        }
+    }
+    if (clipFlags) {
+        Rect clipRect;
+        properties.getClippingRectForFlags(clipFlags, &clipRect);
+        mCanvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom,
+                SkRegion::kIntersect_Op);
+    }
+
+    if (properties.getRevealClip().willClip()) {
+        Rect bounds;
+        properties.getRevealClip().getBounds(&bounds);
+        mCanvasState.setClippingRoundRect(mAllocator,
+                bounds, properties.getRevealClip().getRadius());
+    } else if (properties.getOutline().willClip()) {
+        mCanvasState.setClippingOutline(mAllocator, &(properties.getOutline()));
+    }
+
+    if (!mCanvasState.quickRejectConservative(0, 0, width, height)) {
+        // not rejected, so defer render as either Layer, or direct (possibly wrapped in saveLayer)
+        if (node.getLayer()) {
+            // HW layer
+            LayerOp* drawLayerOp = new (mAllocator) LayerOp(node);
+            BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp);
+            if (bakedOpState) {
+                // Node's layer already deferred, schedule it to render into parent layer
+                currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Bitmap);
+            }
+        } else if (CC_UNLIKELY(!saveLayerBounds.isEmpty())) {
+            // draw DisplayList contents within temporary, since persisted layer could not be used.
+            // (temp layers are clipped to viewport, since they don't persist offscreen content)
+            SkPaint saveLayerPaint;
+            saveLayerPaint.setAlpha(properties.getAlpha());
+            deferBeginLayerOp(*new (mAllocator) BeginLayerOp(
+                    saveLayerBounds,
+                    Matrix4::identity(),
+                    nullptr, // no record-time clip - need only respect defer-time one
+                    &saveLayerPaint));
+            deferNodeOps(node);
+            deferEndLayerOp(*new (mAllocator) EndLayerOp());
+        } else {
+            deferNodeOps(node);
+        }
+    }
+}
+
+typedef key_value_pair_t<float, const RenderNodeOp*> ZRenderNodeOpPair;
+
+template <typename V>
+static void buildZSortedChildList(V* zTranslatedNodes,
+        const DisplayList& displayList, const DisplayList::Chunk& chunk) {
+    if (chunk.beginChildIndex == chunk.endChildIndex) return;
+
+    for (size_t i = chunk.beginChildIndex; i < chunk.endChildIndex; i++) {
+        RenderNodeOp* childOp = displayList.getChildren()[i];
+        RenderNode* child = childOp->renderNode;
+        float childZ = child->properties().getZ();
+
+        if (!MathUtils::isZero(childZ) && chunk.reorderChildren) {
+            zTranslatedNodes->push_back(ZRenderNodeOpPair(childZ, childOp));
+            childOp->skipInOrderDraw = true;
+        } else if (!child->properties().getProjectBackwards()) {
+            // regular, in order drawing DisplayList
+            childOp->skipInOrderDraw = false;
+        }
+    }
+
+    // Z sort any 3d children (stable-ness makes z compare fall back to standard drawing order)
+    std::stable_sort(zTranslatedNodes->begin(), zTranslatedNodes->end());
+}
+
+template <typename V>
+static size_t findNonNegativeIndex(const V& zTranslatedNodes) {
+    for (size_t i = 0; i < zTranslatedNodes.size(); i++) {
+        if (zTranslatedNodes[i].key >= 0.0f) return i;
+    }
+    return zTranslatedNodes.size();
+}
+
+template <typename V>
+void FrameBuilder::defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedNodes) {
+    const int size = zTranslatedNodes.size();
+    if (size == 0
+            || (mode == ChildrenSelectMode::Negative&& zTranslatedNodes[0].key > 0.0f)
+            || (mode == ChildrenSelectMode::Positive && zTranslatedNodes[size - 1].key < 0.0f)) {
+        // no 3d children to draw
+        return;
+    }
+
+    /**
+     * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters
+     * with very similar Z heights to draw together.
+     *
+     * This way, if Views A & B have the same Z height and are both casting shadows, the shadows are
+     * underneath both, and neither's shadow is drawn on top of the other.
+     */
+    const size_t nonNegativeIndex = findNonNegativeIndex(zTranslatedNodes);
+    size_t drawIndex, shadowIndex, endIndex;
+    if (mode == ChildrenSelectMode::Negative) {
+        drawIndex = 0;
+        endIndex = nonNegativeIndex;
+        shadowIndex = endIndex; // draw no shadows
+    } else {
+        drawIndex = nonNegativeIndex;
+        endIndex = size;
+        shadowIndex = drawIndex; // potentially draw shadow for each pos Z child
+    }
+
+    float lastCasterZ = 0.0f;
+    while (shadowIndex < endIndex || drawIndex < endIndex) {
+        if (shadowIndex < endIndex) {
+            const RenderNodeOp* casterNodeOp = zTranslatedNodes[shadowIndex].value;
+            const float casterZ = zTranslatedNodes[shadowIndex].key;
+            // attempt to render the shadow if the caster about to be drawn is its caster,
+            // OR if its caster's Z value is similar to the previous potential caster
+            if (shadowIndex == drawIndex || casterZ - lastCasterZ < 0.1f) {
+                deferShadow(*casterNodeOp);
+
+                lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
+                shadowIndex++;
+                continue;
+            }
+        }
+
+        const RenderNodeOp* childOp = zTranslatedNodes[drawIndex].value;
+        deferRenderNodeOpImpl(*childOp);
+        drawIndex++;
+    }
+}
+
+void FrameBuilder::deferShadow(const RenderNodeOp& casterNodeOp) {
+    auto& node = *casterNodeOp.renderNode;
+    auto& properties = node.properties();
+
+    if (properties.getAlpha() <= 0.0f
+            || properties.getOutline().getAlpha() <= 0.0f
+            || !properties.getOutline().getPath()
+            || properties.getScaleX() == 0
+            || properties.getScaleY() == 0) {
+        // no shadow to draw
+        return;
+    }
+
+    const SkPath* casterOutlinePath = properties.getOutline().getPath();
+    const SkPath* revealClipPath = properties.getRevealClip().getPath();
+    if (revealClipPath && revealClipPath->isEmpty()) return;
+
+    float casterAlpha = properties.getAlpha() * properties.getOutline().getAlpha();
+
+    // holds temporary SkPath to store the result of intersections
+    SkPath* frameAllocatedPath = nullptr;
+    const SkPath* casterPath = casterOutlinePath;
+
+    // intersect the shadow-casting path with the reveal, if present
+    if (revealClipPath) {
+        frameAllocatedPath = createFrameAllocatedPath();
+
+        Op(*casterPath, *revealClipPath, kIntersect_SkPathOp, frameAllocatedPath);
+        casterPath = frameAllocatedPath;
+    }
+
+    // intersect the shadow-casting path with the clipBounds, if present
+    if (properties.getClippingFlags() & CLIP_TO_CLIP_BOUNDS) {
+        if (!frameAllocatedPath) {
+            frameAllocatedPath = createFrameAllocatedPath();
+        }
+        Rect clipBounds;
+        properties.getClippingRectForFlags(CLIP_TO_CLIP_BOUNDS, &clipBounds);
+        SkPath clipBoundsPath;
+        clipBoundsPath.addRect(clipBounds.left, clipBounds.top,
+                clipBounds.right, clipBounds.bottom);
+
+        Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, frameAllocatedPath);
+        casterPath = frameAllocatedPath;
+    }
+
+    ShadowOp* shadowOp = new (mAllocator) ShadowOp(casterNodeOp, casterAlpha, casterPath,
+            mCanvasState.getLocalClipBounds(),
+            mCanvasState.currentSnapshot()->getRelativeLightCenter());
+    BakedOpState* bakedOpState = BakedOpState::tryShadowOpConstruct(
+            mAllocator, *mCanvasState.writableSnapshot(), shadowOp);
+    if (CC_LIKELY(bakedOpState)) {
+        currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Shadow);
+    }
+}
+
+void FrameBuilder::deferProjectedChildren(const RenderNode& renderNode) {
+    const SkPath* projectionReceiverOutline = renderNode.properties().getOutline().getPath();
+    int count = mCanvasState.save(SaveFlags::MatrixClip);
+
+    // 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);
+    }
+
+    mCanvasState.restoreToCount(count);
+}
+
+/**
+ * Used to define a list of lambdas referencing private FrameBuilder::onXX::defer() methods.
+ *
+ * This allows opIds embedded in the RecordedOps to be used for dispatching to these lambdas.
+ * E.g. a BitmapOp op then would be dispatched to FrameBuilder::onBitmapOp(const BitmapOp&)
+ */
+#define OP_RECEIVER(Type) \
+        [](FrameBuilder& frameBuilder, const RecordedOp& op) { frameBuilder.defer##Type(static_cast<const Type&>(op)); },
+void FrameBuilder::deferNodeOps(const RenderNode& renderNode) {
+    typedef void (*OpDispatcher) (FrameBuilder& frameBuilder, const RecordedOp& op);
+    static OpDispatcher receivers[] = BUILD_DEFERRABLE_OP_LUT(OP_RECEIVER);
+
+    // can't be null, since DL=null node rejection happens before deferNodePropsAndOps
+    const DisplayList& displayList = *(renderNode.getDisplayList());
+    for (const DisplayList::Chunk& chunk : displayList.getChunks()) {
+        FatVector<ZRenderNodeOpPair, 16> zTranslatedNodes;
+        buildZSortedChildList(&zTranslatedNodes, displayList, chunk);
+
+        defer3dChildren(ChildrenSelectMode::Negative, zTranslatedNodes);
+        for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
+            const RecordedOp* op = displayList.getOps()[opIndex];
+            receivers[op->opId](*this, *op);
+
+            if (CC_UNLIKELY(!renderNode.mProjectedNodes.empty()
+                    && displayList.projectionReceiveIndex >= 0
+                    && static_cast<int>(opIndex) == displayList.projectionReceiveIndex)) {
+                deferProjectedChildren(renderNode);
+            }
+        }
+        defer3dChildren(ChildrenSelectMode::Positive, zTranslatedNodes);
+    }
+}
+
+void FrameBuilder::deferRenderNodeOpImpl(const RenderNodeOp& op) {
+    if (op.renderNode->nothingToDraw()) return;
+    int count = mCanvasState.save(SaveFlags::MatrixClip);
+
+    // apply state from RecordedOp (clip first, since op's clip is transformed by current matrix)
+    mCanvasState.writableSnapshot()->mutateClipArea().applyClip(op.localClip,
+            *mCanvasState.currentSnapshot()->transform);
+    mCanvasState.concatMatrix(op.localMatrix);
+
+    // then apply state from node properties, and defer ops
+    deferNodePropsAndOps(*op.renderNode);
+
+    mCanvasState.restoreToCount(count);
+}
+
+void FrameBuilder::deferRenderNodeOp(const RenderNodeOp& op) {
+    if (!op.skipInOrderDraw) {
+        deferRenderNodeOpImpl(op);
+    }
+}
+
+/**
+ * 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::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
+    currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId);
+}
+
+/**
+ * Returns batch id for tessellatable shapes, based on paint. Checks to see if path effect/AA will
+ * be used, since they trigger significantly different rendering paths.
+ *
+ * Note: not used for lines/points, since they don't currently support path effects.
+ */
+static batchid_t tessBatchId(const RecordedOp& op) {
+    const SkPaint& paint = *(op.paint);
+    return paint.getPathEffect()
+            ? OpBatchType::AlphaMaskTexture
+            : (paint.isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices);
+}
+
+void FrameBuilder::deferArcOp(const ArcOp& op) {
+    deferStrokeableOp(op, tessBatchId(op));
+}
+
+static bool hasMergeableClip(const BakedOpState& state) {
+    return state.computedState.clipState
+            || state.computedState.clipState->mode == ClipMode::Rectangle;
+}
+
+void FrameBuilder::deferBitmapOp(const BitmapOp& op) {
+    BakedOpState* bakedState = tryBakeOpState(op);
+    if (!bakedState) return; // quick rejected
+
+    currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
+
+    // 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()
+    if (bakedState->computedState.transform.isSimple()
+            && bakedState->computedState.transform.positiveScale()
+            && PaintUtils::getXfermodeDirect(op.paint) == SkXfermode::kSrcOver_Mode
+            && op.bitmap->colorType() != kAlpha_8_SkColorType
+            && hasMergeableClip(*bakedState)) {
+        mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.bitmap->getGenerationID());
+        // TODO: AssetAtlas in mergeId
+        currentLayer().deferMergeableOp(mAllocator, bakedState, OpBatchType::Bitmap, mergeId);
+    } else {
+        currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
+    }
+*/
+}
+
+void FrameBuilder::deferBitmapMeshOp(const BitmapMeshOp& op) {
+    BakedOpState* bakedState = tryBakeOpState(op);
+    if (!bakedState) return; // quick rejected
+    currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
+}
+
+void FrameBuilder::deferBitmapRectOp(const BitmapRectOp& op) {
+    BakedOpState* bakedState = tryBakeOpState(op);
+    if (!bakedState) return; // quick rejected
+    currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
+}
+
+void FrameBuilder::deferCirclePropsOp(const CirclePropsOp& op) {
+    // allocate a temporary oval op (with mAllocator, so it persists until render), so the
+    // renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple.
+    float x = *(op.x);
+    float y = *(op.y);
+    float radius = *(op.radius);
+    Rect unmappedBounds(x - radius, y - radius, x + radius, y + radius);
+    const OvalOp* resolvedOp = new (mAllocator) OvalOp(
+            unmappedBounds,
+            op.localMatrix,
+            op.localClip,
+            op.paint);
+    deferOvalOp(*resolvedOp);
+}
+
+void FrameBuilder::deferFunctorOp(const FunctorOp& op) {
+    BakedOpState* bakedState = tryBakeOpState(op);
+    if (!bakedState) return; // quick rejected
+    currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Functor);
+}
+
+void FrameBuilder::deferLinesOp(const LinesOp& op) {
+    batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices;
+    deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced);
+}
+
+void FrameBuilder::deferOvalOp(const OvalOp& op) {
+    deferStrokeableOp(op, tessBatchId(op));
+}
+
+void FrameBuilder::deferPatchOp(const PatchOp& op) {
+    BakedOpState* bakedState = tryBakeOpState(op);
+    if (!bakedState) return; // quick rejected
+
+    if (bakedState->computedState.transform.isPureTranslate()
+            && PaintUtils::getXfermodeDirect(op.paint) == SkXfermode::kSrcOver_Mode
+            && hasMergeableClip(*bakedState)) {
+        mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.bitmap->getGenerationID());
+        // TODO: AssetAtlas in mergeId
+
+        // Only use the MergedPatch batchId when merged, so Bitmap+Patch don't try to merge together
+        currentLayer().deferMergeableOp(mAllocator, bakedState, OpBatchType::MergedPatch, mergeId);
+    } else {
+        // Use Bitmap batchId since Bitmap+Patch use same shader
+        currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
+    }
+}
+
+void FrameBuilder::deferPathOp(const PathOp& op) {
+    deferStrokeableOp(op, OpBatchType::Bitmap);
+}
+
+void FrameBuilder::deferPointsOp(const PointsOp& op) {
+    batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices;
+    deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced);
+}
+
+void FrameBuilder::deferRectOp(const RectOp& op) {
+    deferStrokeableOp(op, tessBatchId(op));
+}
+
+void FrameBuilder::deferRoundRectOp(const RoundRectOp& op) {
+    deferStrokeableOp(op, tessBatchId(op));
+}
+
+void FrameBuilder::deferRoundRectPropsOp(const RoundRectPropsOp& op) {
+    // allocate a temporary round rect op (with mAllocator, so it persists until render), so the
+    // renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple.
+    const RoundRectOp* resolvedOp = new (mAllocator) RoundRectOp(
+            Rect(*(op.left), *(op.top), *(op.right), *(op.bottom)),
+            op.localMatrix,
+            op.localClip,
+            op.paint, *op.rx, *op.ry);
+    deferRoundRectOp(*resolvedOp);
+}
+
+void FrameBuilder::deferSimpleRectsOp(const SimpleRectsOp& op) {
+    BakedOpState* bakedState = tryBakeOpState(op);
+    if (!bakedState) return; // quick rejected
+    currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices);
+}
+
+static batchid_t textBatchId(const SkPaint& paint) {
+    // TODO: better handling of shader (since we won't care about color then)
+    return paint.getColor() == SK_ColorBLACK ? OpBatchType::Text : OpBatchType::ColorText;
+}
+
+void FrameBuilder::deferTextOp(const TextOp& op) {
+    BakedOpState* bakedState = tryBakeOpState(op);
+    if (!bakedState) return; // quick rejected
+
+    batchid_t batchId = textBatchId(*(op.paint));
+    if (bakedState->computedState.transform.isPureTranslate()
+            && PaintUtils::getXfermodeDirect(op.paint) == SkXfermode::kSrcOver_Mode
+            && hasMergeableClip(*bakedState)) {
+        mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.paint->getColor());
+        currentLayer().deferMergeableOp(mAllocator, bakedState, batchId, mergeId);
+    } else {
+        currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId);
+    }
+}
+
+void FrameBuilder::deferTextOnPathOp(const TextOnPathOp& op) {
+    BakedOpState* bakedState = tryBakeOpState(op);
+    if (!bakedState) return; // quick rejected
+    currentLayer().deferUnmergeableOp(mAllocator, bakedState, textBatchId(*(op.paint)));
+}
+
+void FrameBuilder::deferTextureLayerOp(const TextureLayerOp& op) {
+    BakedOpState* bakedState = tryBakeOpState(op);
+    if (!bakedState) return; // quick rejected
+    currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::TextureLayer);
+}
+
+void FrameBuilder::saveForLayer(uint32_t layerWidth, uint32_t layerHeight,
+        float contentTranslateX, float contentTranslateY,
+        const Rect& repaintRect,
+        const Vector3& lightCenter,
+        const BeginLayerOp* beginLayerOp, RenderNode* renderNode) {
+    mCanvasState.save(SaveFlags::MatrixClip);
+    mCanvasState.writableSnapshot()->initializeViewport(layerWidth, layerHeight);
+    mCanvasState.writableSnapshot()->roundRectClipState = nullptr;
+    mCanvasState.writableSnapshot()->setRelativeLightCenter(lightCenter);
+    mCanvasState.writableSnapshot()->transform->loadTranslate(
+            contentTranslateX, contentTranslateY, 0);
+    mCanvasState.writableSnapshot()->setClip(
+            repaintRect.left, repaintRect.top, repaintRect.right, repaintRect.bottom);
+
+    // create a new layer repaint, and push its index on the stack
+    mLayerStack.push_back(mLayerBuilders.size());
+    auto newFbo = mAllocator.create<LayerBuilder>(layerWidth, layerHeight,
+            repaintRect, beginLayerOp, renderNode);
+    mLayerBuilders.push_back(newFbo);
+}
+
+void FrameBuilder::restoreForLayer() {
+    // restore canvas, and pop finished layer off of the stack
+    mCanvasState.restore();
+    mLayerStack.pop_back();
+}
+
+// TODO: defer time rejection (when bounds become empty) + tests
+// Option - just skip layers with no bounds at playback + defer?
+void FrameBuilder::deferBeginLayerOp(const BeginLayerOp& op) {
+    uint32_t layerWidth = (uint32_t) op.unmappedBounds.getWidth();
+    uint32_t layerHeight = (uint32_t) op.unmappedBounds.getHeight();
+
+    auto previous = mCanvasState.currentSnapshot();
+    Vector3 lightCenter = previous->getRelativeLightCenter();
+
+    // Combine all transforms used to present saveLayer content:
+    // parent content transform * canvas transform * bounds offset
+    Matrix4 contentTransform(*(previous->transform));
+    contentTransform.multiply(op.localMatrix);
+    contentTransform.translate(op.unmappedBounds.left, op.unmappedBounds.top);
+
+    Matrix4 inverseContentTransform;
+    inverseContentTransform.loadInverse(contentTransform);
+
+    // map the light center into layer-relative space
+    inverseContentTransform.mapPoint3d(lightCenter);
+
+    // Clip bounds of temporary layer to parent's clip rect, so:
+    Rect saveLayerBounds(layerWidth, layerHeight);
+    //     1) transform Rect(width, height) into parent's space
+    //        note: left/top offsets put in contentTransform above
+    contentTransform.mapRect(saveLayerBounds);
+    //     2) intersect with parent's clip
+    saveLayerBounds.doIntersect(previous->getRenderTargetClip());
+    //     3) and transform back
+    inverseContentTransform.mapRect(saveLayerBounds);
+    saveLayerBounds.doIntersect(Rect(layerWidth, layerHeight));
+    saveLayerBounds.roundOut();
+
+    // if bounds are reduced, will clip the layer's area by reducing required bounds...
+    layerWidth = saveLayerBounds.getWidth();
+    layerHeight = saveLayerBounds.getHeight();
+    // ...and shifting drawing content to account for left/top side clipping
+    float contentTranslateX = -saveLayerBounds.left;
+    float contentTranslateY = -saveLayerBounds.top;
+
+    saveForLayer(layerWidth, layerHeight,
+            contentTranslateX, contentTranslateY,
+            Rect(layerWidth, layerHeight),
+            lightCenter,
+            &op, nullptr);
+}
+
+void FrameBuilder::deferEndLayerOp(const EndLayerOp& /* ignored */) {
+    const BeginLayerOp& beginLayerOp = *currentLayer().beginLayerOp;
+    int finishedLayerIndex = mLayerStack.back();
+
+    restoreForLayer();
+
+    // record the draw operation into the previous layer's list of draw commands
+    // uses state from the associated beginLayerOp, since it has all the state needed for drawing
+    LayerOp* drawLayerOp = new (mAllocator) LayerOp(
+            beginLayerOp.unmappedBounds,
+            beginLayerOp.localMatrix,
+            beginLayerOp.localClip,
+            beginLayerOp.paint,
+            &(mLayerBuilders[finishedLayerIndex]->offscreenBuffer));
+    BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp);
+
+    if (bakedOpState) {
+        // Layer will be drawn into parent layer (which is now current, since we popped mLayerStack)
+        currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Bitmap);
+    } else {
+        // Layer won't be drawn - delete its drawing batches to prevent it from doing any work
+        // TODO: need to prevent any render work from being done
+        // - create layerop earlier for reject purposes?
+        mLayerBuilders[finishedLayerIndex]->clear();
+        return;
+    }
+}
+
+void FrameBuilder::deferBeginUnclippedLayerOp(const BeginUnclippedLayerOp& op) {
+    Matrix4 boundsTransform(*(mCanvasState.currentSnapshot()->transform));
+    boundsTransform.multiply(op.localMatrix);
+
+    Rect dstRect(op.unmappedBounds);
+    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);
+
+    /**
+     * First, defer an operation to copy out the content from the rendertarget into a layer.
+     */
+    auto copyToOp = new (mAllocator) CopyToLayerOp(op, layerHandle);
+    BakedOpState* bakedState = BakedOpState::directConstruct(mAllocator,
+            &(currentLayer().viewportClip), 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);
+
+    /**
+     * And stash an operation to copy that layer back under the rendertarget until
+     * a balanced EndUnclippedLayerOp is seen
+     */
+    auto copyFromOp = new (mAllocator) CopyFromLayerOp(op, layerHandle);
+    bakedState = BakedOpState::directConstruct(mAllocator,
+            &(currentLayer().viewportClip), 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();
+}
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/FrameBuilder.h b/libs/hwui/FrameBuilder.h
new file mode 100644
index 0000000..dea9934
--- /dev/null
+++ b/libs/hwui/FrameBuilder.h
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "BakedOpState.h"
+#include "CanvasState.h"
+#include "DisplayList.h"
+#include "LayerBuilder.h"
+#include "RecordedOp.h"
+#include "utils/GLUtils.h"
+
+#include <vector>
+#include <unordered_map>
+
+struct SkRect;
+
+namespace android {
+namespace uirenderer {
+
+class BakedOpState;
+class LayerUpdateQueue;
+class OffscreenBuffer;
+class Rect;
+
+/**
+ * Traverses all of the drawing commands from the layers and RenderNodes passed into it, preparing
+ * them to be rendered.
+ *
+ * Resolves final drawing state for each operation (including clip, alpha and matrix), and then
+ * reorder and merge each op as it is resolved for drawing efficiency. Each layer of content (either
+ * from the LayerUpdateQueue, or temporary layers created by saveLayer operations in the
+ * draw stream) will create different reorder contexts, each in its own LayerBuilder.
+ *
+ * Then the prepared or 'baked' drawing commands can be issued by calling the templated
+ * replayBakedOps() function, which will dispatch them (including any created merged op collections)
+ * to a Dispatcher and Renderer. See BakedOpDispatcher for how these baked drawing operations are
+ * resolved into Glops and rendered via BakedOpRenderer.
+ *
+ * This class is also the authoritative source for traversing RenderNodes, both for standard op
+ * traversal within a DisplayList, and for out of order RenderNode traversal for Z and projection.
+ */
+class FrameBuilder : public CanvasStateClient {
+public:
+    FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
+            uint32_t viewportWidth, uint32_t viewportHeight,
+            const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter);
+
+    FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
+            uint32_t viewportWidth, uint32_t viewportHeight,
+            const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter,
+            const Rect &contentDrawBounds);
+
+    virtual ~FrameBuilder() {}
+
+    /**
+     * replayBakedOps() is templated based on what class will receive ops being replayed.
+     *
+     * 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) {
+        /**
+         * 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.
+         *
+         * For example a BitmapOp would resolve, via the lambda lookup, to calling:
+         *
+         * StaticDispatcher::onBitmapOp(Renderer& renderer, const BitmapOp& op, const BakedOpState& state);
+         */
+        #define X(Type) \
+                [](void* renderer, const BakedOpState& state) { \
+                    StaticDispatcher::on##Type(*(static_cast<Renderer*>(renderer)), \
+                            static_cast<const Type&>(*(state.op)), state); \
+                },
+        static BakedOpReceiver unmergedReceivers[] = BUILD_RENDERABLE_OP_LUT(X);
+        #undef X
+
+        /**
+         * Defines a LUT of lambdas which allow merged arrays of BakedOpState* to be passed to a
+         * static dispatcher when the group of merged ops is replayed.
+         */
+        #define X(Type) \
+                [](void* renderer, const MergedBakedOpList& opList) { \
+                    StaticDispatcher::onMerged##Type##s(*(static_cast<Renderer*>(renderer)), opList); \
+                },
+        static MergedOpReceiver mergedReceivers[] = BUILD_MERGEABLE_OP_LUT(X);
+        #undef X
+
+        // Relay through layers in reverse order, since layers
+        // later in the list will be drawn by earlier ones
+        for (int i = mLayerBuilders.size() - 1; i >= 1; i--) {
+            GL_CHECKPOINT(MODERATE);
+            LayerBuilder& layer = *(mLayerBuilders[i]);
+            if (layer.renderNode) {
+                // cached HW layer - can't skip layer if empty
+                renderer.startRepaintLayer(layer.offscreenBuffer, layer.repaintRect);
+                GL_CHECKPOINT(MODERATE);
+                layer.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers);
+                GL_CHECKPOINT(MODERATE);
+                renderer.endLayer();
+            } else if (!layer.empty()) { // save layer - skip entire layer if empty
+                layer.offscreenBuffer = renderer.startTemporaryLayer(layer.width, layer.height);
+                GL_CHECKPOINT(MODERATE);
+                layer.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers);
+                GL_CHECKPOINT(MODERATE);
+                renderer.endLayer();
+            }
+        }
+
+        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);
+    }
+
+    void dump() const {
+        for (auto&& layer : mLayerBuilders) {
+            layer->dump();
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////
+    /// CanvasStateClient interface
+    ///////////////////////////////////////////////////////////////////
+    virtual void onViewportInitialized() override;
+    virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) override;
+    virtual GLuint getTargetFbo() const override { return 0; }
+
+private:
+    enum class ChildrenSelectMode {
+        Negative,
+        Positive
+    };
+    void saveForLayer(uint32_t layerWidth, uint32_t layerHeight,
+            float contentTranslateX, float contentTranslateY,
+            const Rect& repaintRect,
+            const Vector3& lightCenter,
+            const BeginLayerOp* beginLayerOp, RenderNode* renderNode);
+    void restoreForLayer();
+
+    LayerBuilder& currentLayer() { return *(mLayerBuilders[mLayerStack.back()]); }
+
+    BakedOpState* tryBakeOpState(const RecordedOp& recordedOp) {
+        return BakedOpState::tryConstruct(mAllocator, *mCanvasState.writableSnapshot(), recordedOp);
+    }
+
+    // should always be surrounded by a save/restore pair, and not called if DisplayList is null
+    void deferNodePropsAndOps(RenderNode& node);
+
+    template <typename V>
+    void defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedNodes);
+
+    void deferShadow(const RenderNodeOp& casterOp);
+
+    void deferProjectedChildren(const RenderNode& renderNode);
+
+    void deferNodeOps(const RenderNode& renderNode);
+
+    void deferRenderNodeOpImpl(const RenderNodeOp& op);
+
+    void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers);
+
+    SkPath* createFrameAllocatedPath() {
+        return mAllocator.create<SkPath>();
+    }
+
+    void deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
+            BakedOpState::StrokeBehavior strokeBehavior = BakedOpState::StrokeBehavior::StyleDefined);
+
+    /**
+     * Declares all FrameBuilder::deferXXXXOp() methods for every RecordedOp type.
+     *
+     * These private methods are called from within deferImpl to defer each individual op
+     * type differently.
+     */
+#define X(Type) void defer##Type(const Type& op);
+    MAP_DEFERRABLE_OPS(X)
+#undef X
+
+    // List of every deferred layer's render state. Replayed in reverse order to render a frame.
+    std::vector<LayerBuilder*> mLayerBuilders;
+
+    /*
+     * Stack of indices within mLayerBuilders representing currently active layers. If drawing
+     * layerA within a layerB, will contain, in order:
+     *  - 0 (representing FBO 0, always present)
+     *  - layerB's index
+     *  - layerA's index
+     *
+     * Note that this doesn't vector doesn't always map onto all values of mLayerBuilders. When a
+     * layer is finished deferring, it will still be represented in mLayerBuilders, but it's index
+     * won't be in mLayerStack. This is because it can be replayed, but can't have any more drawing
+     * ops added to it.
+    */
+    std::vector<size_t> mLayerStack;
+
+    CanvasState mCanvasState;
+
+    // contains ResolvedOps and Batches
+    LinearAllocator mAllocator;
+};
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
index f8013ab..0baca39 100644
--- a/libs/hwui/FrameInfo.h
+++ b/libs/hwui/FrameInfo.h
@@ -118,6 +118,10 @@
         set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag);
     }
 
+    const int64_t* data() const {
+        return mFrameInfo;
+    }
+
     inline int64_t operator[](FrameInfoIndex index) const {
         return get(index);
     }
diff --git a/libs/hwui/FrameStatsObserver.h b/libs/hwui/FrameStatsObserver.h
new file mode 100644
index 0000000..7abc9f1
--- /dev/null
+++ b/libs/hwui/FrameStatsObserver.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 <utils/RefBase.h>
+
+#include "BufferPool.h"
+
+namespace android {
+namespace uirenderer {
+
+class FrameStatsObserver : public VirtualLightRefBase {
+public:
+    virtual void notify(BufferPool::Buffer* buffer);
+};
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/FrameStatsReporter.h b/libs/hwui/FrameStatsReporter.h
new file mode 100644
index 0000000..b8a9432
--- /dev/null
+++ b/libs/hwui/FrameStatsReporter.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <utils/RefBase.h>
+#include <utils/Log.h>
+
+#include "BufferPool.h"
+#include "FrameInfo.h"
+#include "FrameStatsObserver.h"
+
+#include <string.h>
+#include <vector>
+
+namespace android {
+namespace uirenderer {
+
+class FrameStatsReporter {
+public:
+    FrameStatsReporter() {
+        mBufferPool = new BufferPool(kBufferSize, kBufferCount);
+        LOG_ALWAYS_FATAL_IF(mBufferPool.get() == nullptr, "OOM: unable to allocate buffer pool");
+    }
+
+    void addObserver(FrameStatsObserver* observer) {
+        mObservers.push_back(observer);
+    }
+
+    bool removeObserver(FrameStatsObserver* observer) {
+        for (size_t i = 0; i < mObservers.size(); i++) {
+            if (mObservers[i].get() == observer) {
+                mObservers.erase(mObservers.begin() + i);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    bool hasObservers() {
+        return mObservers.size() > 0;
+    }
+
+    void reportFrameStats(const int64_t* stats) {
+        BufferPool::Buffer* statsBuffer = mBufferPool->acquire();
+
+        if (statsBuffer != nullptr) {
+            // copy in frame stats
+            memcpy(statsBuffer->getBuffer(), stats, kBufferSize * sizeof(*stats));
+
+            // notify on requested threads
+            for (size_t i = 0; i < mObservers.size(); i++) {
+                mObservers[i]->notify(statsBuffer);
+            }
+
+            // drop our reference
+            statsBuffer->release();
+        } else {
+            mDroppedReports++;
+        }
+    }
+
+    int getDroppedReports() { return mDroppedReports; }
+
+private:
+    static const size_t kBufferCount = 3;
+    static const size_t kBufferSize = static_cast<size_t>(FrameInfoIndex::NumIndexes);
+
+    std::vector< sp<FrameStatsObserver> > mObservers;
+
+    sp<BufferPool> mBufferPool;
+
+    int mDroppedReports = 0;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h
index bcf819e..e72f396 100644
--- a/libs/hwui/Glop.h
+++ b/libs/hwui/Glop.h
@@ -64,7 +64,7 @@
 
         // Canvas transform isn't applied to the mesh at draw time,
         //since it's already built in.
-        MeshIgnoresCanvasTransform = 1 << 1, // TODO: remove
+        MeshIgnoresCanvasTransform = 1 << 1, // TODO: remove for HWUI_NEW_OPS
     };
 };
 
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 2507ff3..45fc16c 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -78,7 +78,7 @@
     mOutGlop->mesh.vertices = {
             vbo,
             VertexAttribFlags::TextureCoord,
-            nullptr, nullptr, nullptr,
+            nullptr, (const void*) kMeshTextureOffset, nullptr,
             kTextureVertexStride };
     mOutGlop->mesh.elementCount = elementCount;
     return *this;
diff --git a/libs/hwui/GpuMemoryTracker.cpp b/libs/hwui/GpuMemoryTracker.cpp
new file mode 100644
index 0000000..4fb5701
--- /dev/null
+++ b/libs/hwui/GpuMemoryTracker.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utils/StringUtils.h"
+#include "Texture.h"
+
+#include <cutils/compiler.h>
+#include <GpuMemoryTracker.h>
+#include <utils/Trace.h>
+#include <array>
+#include <sstream>
+#include <unordered_set>
+#include <vector>
+
+namespace android {
+namespace uirenderer {
+
+pthread_t gGpuThread = 0;
+
+#define NUM_TYPES static_cast<int>(GpuObjectType::TypeCount)
+
+const char* TYPE_NAMES[] = {
+        "Texture",
+        "OffscreenBuffer",
+        "Layer",
+};
+
+struct TypeStats {
+    int totalSize = 0;
+    int count = 0;
+};
+
+static std::array<TypeStats, NUM_TYPES> gObjectStats;
+static std::unordered_set<GpuMemoryTracker*> gObjectSet;
+
+void GpuMemoryTracker::notifySizeChanged(int newSize) {
+    int delta = newSize - mSize;
+    mSize = newSize;
+    gObjectStats[static_cast<int>(mType)].totalSize += delta;
+}
+
+void GpuMemoryTracker::startTrackingObject() {
+    auto result = gObjectSet.insert(this);
+    LOG_ALWAYS_FATAL_IF(!result.second,
+            "startTrackingObject() on %p failed, already being tracked!", this);
+    gObjectStats[static_cast<int>(mType)].count++;
+}
+
+void GpuMemoryTracker::stopTrackingObject() {
+    size_t removed = gObjectSet.erase(this);
+    LOG_ALWAYS_FATAL_IF(removed != 1,
+            "stopTrackingObject removed %zd, is %p not being tracked?",
+            removed, this);
+    gObjectStats[static_cast<int>(mType)].count--;
+}
+
+void GpuMemoryTracker::onGLContextCreated() {
+    LOG_ALWAYS_FATAL_IF(gGpuThread != 0, "We already have a GL thread? "
+            "current = %lu, gl thread = %lu", pthread_self(), gGpuThread);
+    gGpuThread = pthread_self();
+}
+
+void GpuMemoryTracker::onGLContextDestroyed() {
+    gGpuThread = 0;
+    if (CC_UNLIKELY(gObjectSet.size() > 0)) {
+        std::stringstream os;
+        dump(os);
+        ALOGE("%s", os.str().c_str());
+        LOG_ALWAYS_FATAL("Leaked %zd GPU objects!", gObjectSet.size());
+    }
+}
+
+void GpuMemoryTracker::dump() {
+    std::stringstream strout;
+    dump(strout);
+    ALOGD("%s", strout.str().c_str());
+}
+
+void GpuMemoryTracker::dump(std::ostream& stream) {
+    for (int type = 0; type < NUM_TYPES; type++) {
+        const TypeStats& stats = gObjectStats[type];
+        stream << TYPE_NAMES[type];
+        stream << " is using " << SizePrinter{stats.totalSize};
+        stream << ", count = " << stats.count;
+        stream << std::endl;
+    }
+}
+
+int GpuMemoryTracker::getInstanceCount(GpuObjectType type) {
+    return gObjectStats[static_cast<int>(type)].count;
+}
+
+int GpuMemoryTracker::getTotalSize(GpuObjectType type) {
+    return gObjectStats[static_cast<int>(type)].totalSize;
+}
+
+void GpuMemoryTracker::onFrameCompleted() {
+    if (ATRACE_ENABLED()) {
+        char buf[128];
+        for (int type = 0; type < NUM_TYPES; type++) {
+            snprintf(buf, 128, "hwui_%s", TYPE_NAMES[type]);
+            const TypeStats& stats = gObjectStats[type];
+            ATRACE_INT(buf, stats.totalSize);
+            snprintf(buf, 128, "hwui_%s_count", TYPE_NAMES[type]);
+            ATRACE_INT(buf, stats.count);
+        }
+    }
+
+    std::vector<const Texture*> freeList;
+    for (const auto& obj : gObjectSet) {
+        if (obj->objectType() == GpuObjectType::Texture) {
+            const Texture* texture = static_cast<Texture*>(obj);
+            if (texture->cleanup) {
+                ALOGE("Leaked texture marked for cleanup! id=%u, size %ux%u",
+                        texture->id(), texture->width(), texture->height());
+                freeList.push_back(texture);
+            }
+        }
+    }
+    for (auto& texture : freeList) {
+        const_cast<Texture*>(texture)->deleteTexture();
+        delete texture;
+    }
+}
+
+} // namespace uirenderer
+} // namespace android;
diff --git a/libs/hwui/GpuMemoryTracker.h b/libs/hwui/GpuMemoryTracker.h
new file mode 100644
index 0000000..851aeae
--- /dev/null
+++ b/libs/hwui/GpuMemoryTracker.h
@@ -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.
+ */
+#pragma once
+
+#include <cutils/log.h>
+#include <pthread.h>
+#include <ostream>
+
+namespace android {
+namespace uirenderer {
+
+extern pthread_t gGpuThread;
+
+#define ASSERT_GPU_THREAD() LOG_ALWAYS_FATAL_IF( \
+        !pthread_equal(gGpuThread, pthread_self()), \
+        "Error, %p of type %d (size=%d) used on wrong thread! cur thread %lu " \
+        "!= gpu thread %lu", this, static_cast<int>(mType), mSize, \
+        pthread_self(), gGpuThread)
+
+enum class GpuObjectType {
+    Texture = 0,
+    OffscreenBuffer,
+    Layer,
+
+    TypeCount,
+};
+
+class GpuMemoryTracker {
+public:
+    GpuObjectType objectType() { return mType; }
+    int objectSize() { return mSize; }
+
+    static void onGLContextCreated();
+    static void onGLContextDestroyed();
+    static void dump();
+    static void dump(std::ostream& stream);
+    static int getInstanceCount(GpuObjectType type);
+    static int getTotalSize(GpuObjectType type);
+    static void onFrameCompleted();
+
+protected:
+    GpuMemoryTracker(GpuObjectType type) : mType(type) {
+        ASSERT_GPU_THREAD();
+        startTrackingObject();
+    }
+
+    ~GpuMemoryTracker() {
+        notifySizeChanged(0);
+        stopTrackingObject();
+    }
+
+    void notifySizeChanged(int newSize);
+
+private:
+    void startTrackingObject();
+    void stopTrackingObject();
+
+    int mSize = 0;
+    GpuObjectType mType;
+};
+
+} // namespace uirenderer
+} // namespace android;
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 8c46450..e899ac7 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -110,9 +110,7 @@
 
 void GradientCache::operator()(GradientCacheEntry&, Texture*& texture) {
     if (texture) {
-        const uint32_t size = texture->width * texture->height * bytesPerPixel();
-        mSize -= size;
-
+        mSize -= texture->objectSize();
         texture->deleteTexture();
         delete texture;
     }
@@ -167,18 +165,16 @@
     getGradientInfo(colors, count, info);
 
     Texture* texture = new Texture(Caches::getInstance());
-    texture->width = info.width;
-    texture->height = 2;
     texture->blend = info.hasAlpha;
     texture->generation = 1;
 
     // Asume the cache is always big enough
-    const uint32_t size = texture->width * texture->height * bytesPerPixel();
+    const uint32_t size = info.width * 2 * bytesPerPixel();
     while (getSize() + size > mMaxSize) {
         mCache.removeOldest();
     }
 
-    generateTexture(colors, positions, texture);
+    generateTexture(colors, positions, info.width, 2, texture);
 
     mSize += size;
     mCache.put(gradient, texture);
@@ -231,10 +227,10 @@
     dst += 4 * sizeof(float);
 }
 
-void GradientCache::generateTexture(uint32_t* colors, float* positions, Texture* texture) {
-    const uint32_t width = texture->width;
+void GradientCache::generateTexture(uint32_t* colors, float* positions,
+        const uint32_t width, const uint32_t height, Texture* texture) {
     const GLsizei rowBytes = width * bytesPerPixel();
-    uint8_t pixels[rowBytes * texture->height];
+    uint8_t pixels[rowBytes * height];
 
     static ChannelSplitter gSplitters[] = {
             &android::uirenderer::GradientCache::splitToBytes,
@@ -277,17 +273,11 @@
 
     memcpy(pixels + rowBytes, pixels, rowBytes);
 
-    glGenTextures(1, &texture->id);
-    Caches::getInstance().textureState().bindTexture(texture->id);
-    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
-
     if (mUseFloatTexture) {
         // We have to use GL_RGBA16F because GL_RGBA32F does not support filtering
-        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, texture->height, 0,
-                GL_RGBA, GL_FLOAT, pixels);
+        texture->upload(GL_RGBA16F, width, height, GL_RGBA, GL_FLOAT, pixels);
     } else {
-        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, texture->height, 0,
-                GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+        texture->upload(GL_RGBA, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
     }
 
     texture->setFilter(GL_LINEAR);
diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h
index 7534c5d..b762ca7 100644
--- a/libs/hwui/GradientCache.h
+++ b/libs/hwui/GradientCache.h
@@ -143,7 +143,8 @@
     Texture* addLinearGradient(GradientCacheEntry& gradient,
             uint32_t* colors, float* positions, int count);
 
-    void generateTexture(uint32_t* colors, float* positions, Texture* texture);
+    void generateTexture(uint32_t* colors, float* positions,
+            const uint32_t width, const uint32_t height, Texture* texture);
 
     struct GradientInfo {
         uint32_t width;
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index eb9b55f..c305f65 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -243,6 +243,7 @@
     dprintf(fd, "\nTotal frames rendered: %u", data->totalFrameCount);
     dprintf(fd, "\nJanky frames: %u (%.2f%%)", data->jankFrameCount,
             (float) data->jankFrameCount / (float) data->totalFrameCount * 100.0f);
+    dprintf(fd, "\n50th percentile: %ums", findPercentile(data, 50));
     dprintf(fd, "\n90th percentile: %ums", findPercentile(data, 90));
     dprintf(fd, "\n95th percentile: %ums", findPercentile(data, 95));
     dprintf(fd, "\n99th percentile: %ums", findPercentile(data, 99));
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 0fe20ad..114347d 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -36,7 +36,8 @@
 namespace uirenderer {
 
 Layer::Layer(Type layerType, RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight)
-        : state(State::Uncached)
+        : GpuMemoryTracker(GpuObjectType::Layer)
+        , state(State::Uncached)
         , caches(Caches::getInstance())
         , renderState(renderState)
         , texture(caches)
@@ -45,8 +46,8 @@
     // preserves the old inc/dec ref locations. This should be changed...
     incStrong(nullptr);
     renderTarget = GL_TEXTURE_2D;
-    texture.width = layerWidth;
-    texture.height = layerHeight;
+    texture.mWidth = layerWidth;
+    texture.mHeight = layerHeight;
     renderState.registerLayer(this);
 }
 
@@ -54,10 +55,9 @@
     renderState.unregisterLayer(this);
     SkSafeUnref(colorFilter);
 
-    if (stencil || fbo || texture.id) {
-        renderState.requireGLContext();
+    if (stencil || fbo || texture.mId) {
         removeFbo();
-        deleteTexture();
+        texture.deleteTexture();
     }
 
     delete[] mesh;
@@ -65,7 +65,7 @@
 
 void Layer::onGlContextLost() {
     removeFbo();
-    deleteTexture();
+    texture.deleteTexture();
 }
 
 uint32_t Layer::computeIdealWidth(uint32_t layerWidth) {
@@ -179,8 +179,8 @@
 }
 
 void Layer::bindTexture() const {
-    if (texture.id) {
-        caches.textureState().bindTexture(renderTarget, texture.id);
+    if (texture.mId) {
+        caches.textureState().bindTexture(renderTarget, texture.mId);
     }
 }
 
@@ -191,29 +191,22 @@
 }
 
 void Layer::generateTexture() {
-    if (!texture.id) {
-        glGenTextures(1, &texture.id);
-    }
-}
-
-void Layer::deleteTexture() {
-    if (texture.id) {
-        texture.deleteTexture();
-        texture.id = 0;
+    if (!texture.mId) {
+        glGenTextures(1, &texture.mId);
     }
 }
 
 void Layer::clearTexture() {
-    caches.textureState().unbindTexture(texture.id);
-    texture.id = 0;
+    caches.textureState().unbindTexture(texture.mId);
+    texture.mId = 0;
 }
 
 void Layer::allocateTexture() {
 #if DEBUG_LAYERS
     ALOGD("  Allocate layer: %dx%d", getWidth(), getHeight());
 #endif
-    if (texture.id) {
-        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+    if (texture.mId) {
+        texture.updateSize(getWidth(), getHeight(), GL_RGBA);
         glTexImage2D(renderTarget, 0, GL_RGBA, getWidth(), getHeight(), 0,
                 GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
     }
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index e90f055..e00ae66 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -24,6 +24,7 @@
 #include <memory>
 
 #include <GLES2/gl2.h>
+#include <GpuMemoryTracker.h>
 
 #include <ui/Region.h>
 
@@ -54,7 +55,7 @@
 /**
  * A layer has dimensions and is backed by an OpenGL texture or FBO.
  */
-class Layer : public VirtualLightRefBase {
+class Layer : public VirtualLightRefBase, GpuMemoryTracker {
 public:
     enum class Type {
         Texture,
@@ -94,8 +95,8 @@
         regionRect.set(bounds.leftTop().x, bounds.leftTop().y,
                bounds.rightBottom().x, bounds.rightBottom().y);
 
-        const float texX = 1.0f / float(texture.width);
-        const float texY = 1.0f / float(texture.height);
+        const float texX = 1.0f / float(texture.mWidth);
+        const float texY = 1.0f / float(texture.mHeight);
         const float height = layer.getHeight();
         texCoords.set(
                regionRect.left * texX, (height - regionRect.top) * texY,
@@ -112,11 +113,11 @@
     void updateDeferred(RenderNode* renderNode, int left, int top, int right, int bottom);
 
     inline uint32_t getWidth() const {
-        return texture.width;
+        return texture.mWidth;
     }
 
     inline uint32_t getHeight() const {
-        return texture.height;
+        return texture.mHeight;
     }
 
     /**
@@ -131,8 +132,7 @@
     bool resize(const uint32_t width, const uint32_t height);
 
     void setSize(uint32_t width, uint32_t height) {
-        texture.width = width;
-        texture.height = height;
+        texture.updateSize(width, height, texture.format());
     }
 
     ANDROID_API void setPaint(const SkPaint* paint);
@@ -201,7 +201,7 @@
     }
 
     inline GLuint getTextureId() const {
-        return texture.id;
+        return texture.id();
     }
 
     inline Texture& getTexture() {
@@ -263,7 +263,6 @@
     void bindTexture() const;
     void generateTexture();
     void allocateTexture();
-    void deleteTexture();
 
     /**
      * When the caller frees the texture itself, the caller
diff --git a/libs/hwui/LayerBuilder.cpp b/libs/hwui/LayerBuilder.cpp
new file mode 100644
index 0000000..7170d4f
--- /dev/null
+++ b/libs/hwui/LayerBuilder.cpp
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "LayerBuilder.h"
+
+#include "BakedOpState.h"
+#include "RenderNode.h"
+#include "utils/PaintUtils.h"
+#include "utils/TraceUtils.h"
+
+#include <utils/TypeHelpers.h>
+
+namespace android {
+namespace uirenderer {
+
+class BatchBase {
+public:
+    BatchBase(batchid_t batchId, BakedOpState* op, bool merging)
+            : mBatchId(batchId)
+            , mMerging(merging) {
+        mBounds = op->computedState.clippedBounds;
+        mOps.push_back(op);
+    }
+
+    bool intersects(const Rect& rect) const {
+        if (!rect.intersects(mBounds)) return false;
+
+        for (const BakedOpState* op : mOps) {
+            if (rect.intersects(op->computedState.clippedBounds)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    batchid_t getBatchId() const { return mBatchId; }
+    bool isMerging() const { return mMerging; }
+
+    const std::vector<BakedOpState*>& getOps() const { return mOps; }
+
+    void dump() const {
+        ALOGD("    Batch %p, id %d, merging %d, count %d, bounds " RECT_STRING,
+                this, mBatchId, mMerging, (int) mOps.size(), RECT_ARGS(mBounds));
+    }
+protected:
+    batchid_t mBatchId;
+    Rect mBounds;
+    std::vector<BakedOpState*> mOps;
+    bool mMerging;
+};
+
+class OpBatch : public BatchBase {
+public:
+    static void* operator new(size_t size, LinearAllocator& allocator) {
+        return allocator.alloc(size);
+    }
+
+    OpBatch(batchid_t batchId, BakedOpState* op)
+            : BatchBase(batchId, op, false) {
+    }
+
+    void batchOp(BakedOpState* op) {
+        mBounds.unionWith(op->computedState.clippedBounds);
+        mOps.push_back(op);
+    }
+};
+
+class MergingOpBatch : public BatchBase {
+public:
+    static void* operator new(size_t size, LinearAllocator& allocator) {
+        return allocator.alloc(size);
+    }
+
+    MergingOpBatch(batchid_t batchId, BakedOpState* op)
+            : BatchBase(batchId, op, true)
+            , mClipSideFlags(op->computedState.clipSideFlags) {
+    }
+
+    /*
+     * Helper for determining if a new op can merge with a MergingDrawBatch based on their bounds
+     * and clip side flags. Positive bounds delta means new bounds fit in old.
+     */
+    static inline bool checkSide(const int currentFlags, const int newFlags, const int side,
+            float boundsDelta) {
+        bool currentClipExists = currentFlags & side;
+        bool newClipExists = newFlags & side;
+
+        // if current is clipped, we must be able to fit new bounds in current
+        if (boundsDelta > 0 && currentClipExists) return false;
+
+        // if new is clipped, we must be able to fit current bounds in new
+        if (boundsDelta < 0 && newClipExists) return false;
+
+        return true;
+    }
+
+    static bool paintIsDefault(const SkPaint& paint) {
+        return paint.getAlpha() == 255
+                && paint.getColorFilter() == nullptr
+                && paint.getShader() == nullptr;
+    }
+
+    static bool paintsAreEquivalent(const SkPaint& a, const SkPaint& b) {
+        // Note: don't check color, since all currently mergeable ops can merge across colors
+        return a.getAlpha() == b.getAlpha()
+                && a.getColorFilter() == b.getColorFilter()
+                && a.getShader() == b.getShader();
+    }
+
+    /*
+     * Checks if a (mergeable) op can be merged into this batch
+     *
+     * If true, the op's multiDraw must be guaranteed to handle both ops simultaneously, so it is
+     * important to consider all paint attributes used in the draw calls in deciding both a) if an
+     * op tries to merge at all, and b) if the op can merge with another set of ops
+     *
+     * False positives can lead to information from the paints of subsequent merged operations being
+     * dropped, so we make simplifying qualifications on the ops that can merge, per op type.
+     */
+    bool canMergeWith(BakedOpState* op) const {
+        bool isTextBatch = getBatchId() == OpBatchType::Text
+                || getBatchId() == OpBatchType::ColorText;
+
+        // Overlapping other operations is only allowed for text without shadow. For other ops,
+        // multiDraw isn't guaranteed to overdraw correctly
+        if (!isTextBatch || PaintUtils::hasTextShadow(op->op->paint)) {
+            if (intersects(op->computedState.clippedBounds)) return false;
+        }
+
+        const BakedOpState* lhs = op;
+        const BakedOpState* rhs = mOps[0];
+
+        if (!MathUtils::areEqual(lhs->alpha, rhs->alpha)) return false;
+
+        // 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;
+
+        /* Clipping compatibility check
+         *
+         * Exploits the fact that if a op or batch is clipped on a side, its bounds will equal its
+         * clip for that side.
+         */
+        const int currentFlags = mClipSideFlags;
+        const int newFlags = op->computedState.clipSideFlags;
+        if (currentFlags != OpClipSideFlags::None || newFlags != OpClipSideFlags::None) {
+            const Rect& opBounds = op->computedState.clippedBounds;
+            float boundsDelta = mBounds.left - opBounds.left;
+            if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Left, boundsDelta)) return false;
+            boundsDelta = mBounds.top - opBounds.top;
+            if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Top, boundsDelta)) return false;
+
+            // right and bottom delta calculation reversed to account for direction
+            boundsDelta = opBounds.right - mBounds.right;
+            if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Right, boundsDelta)) return false;
+            boundsDelta = opBounds.bottom - mBounds.bottom;
+            if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Bottom, boundsDelta)) return false;
+        }
+
+        const SkPaint* newPaint = op->op->paint;
+        const SkPaint* oldPaint = mOps[0]->op->paint;
+
+        if (newPaint == oldPaint) {
+            // if paints are equal, then modifiers + paint attribs don't need to be compared
+            return true;
+        } else if (newPaint && !oldPaint) {
+            return paintIsDefault(*newPaint);
+        } else if (!newPaint && oldPaint) {
+            return paintIsDefault(*oldPaint);
+        }
+        return paintsAreEquivalent(*newPaint, *oldPaint);
+    }
+
+    void mergeOp(BakedOpState* op) {
+        mBounds.unionWith(op->computedState.clippedBounds);
+        mOps.push_back(op);
+
+        // Because a new op must have passed canMergeWith(), we know it's passed the clipping compat
+        // check, and doesn't extend past a side of the clip that's in use by the merged batch.
+        // Therefore it's safe to simply always merge flags, and use the bounds as the clip rect.
+        mClipSideFlags |= op->computedState.clipSideFlags;
+    }
+
+    int getClipSideFlags() const { return mClipSideFlags; }
+    const Rect& getClipRect() const { return mBounds; }
+
+private:
+    int mClipSideFlags;
+};
+
+LayerBuilder::LayerBuilder(uint32_t width, uint32_t height,
+        const Rect& repaintRect, const BeginLayerOp* beginLayerOp, RenderNode* renderNode)
+        : width(width)
+        , height(height)
+        , repaintRect(repaintRect)
+        , offscreenBuffer(renderNode ? renderNode->getLayer() : nullptr)
+        , beginLayerOp(beginLayerOp)
+        , renderNode(renderNode)
+        , viewportClip(Rect(width, height)) {}
+
+// 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
+void LayerBuilder::locateInsertIndex(int batchId, const Rect& clippedBounds,
+        BatchBase** targetBatch, size_t* insertBatchIndex) const {
+    for (int i = mBatches.size() - 1; i >= 0; i--) {
+        BatchBase* overBatch = mBatches[i];
+
+        if (overBatch == *targetBatch) break;
+
+        // TODO: also consider shader shared between batch types
+        if (batchId == overBatch->getBatchId()) {
+            *insertBatchIndex = i + 1;
+            if (!*targetBatch) break; // found insert position, quit
+        }
+
+        if (overBatch->intersects(clippedBounds)) {
+            // NOTE: it may be possible to optimize for special cases where two operations
+            // of the same batch/paint could swap order, such as with a non-mergeable
+            // (clipped) and a mergeable text operation
+            *targetBatch = nullptr;
+            break;
+        }
+    }
+}
+
+void LayerBuilder::deferLayerClear(const Rect& rect) {
+    mClearRects.push_back(rect);
+}
+
+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(vertCount * sizeof(Vertex));
+
+        Vertex* currentVert = verts;
+        Rect bounds = mClearRects[0];
+        for (auto&& rect : mClearRects) {
+            bounds.unionWith(rect);
+            Vertex::set(currentVert++, rect.left, rect.top);
+            Vertex::set(currentVert++, rect.right, rect.top);
+            Vertex::set(currentVert++, rect.left, rect.bottom);
+            Vertex::set(currentVert++, rect.right, rect.bottom);
+        }
+        mClearRects.clear(); // discard rects before drawing so this method isn't reentrant
+
+        // One or more unclipped saveLayers have been enqueued, with deferred clears.
+        // Flush all of these clears with a single draw
+        SkPaint* paint = allocator.create<SkPaint>();
+        paint->setXfermodeMode(SkXfermode::kClear_Mode);
+        SimpleRectsOp* op = new (allocator) SimpleRectsOp(bounds,
+                Matrix4::identity(), nullptr, paint,
+                verts, vertCount);
+        BakedOpState* bakedState = BakedOpState::directConstruct(allocator,
+                &viewportClip, 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);
+    }
+
+    OpBatch* targetBatch = mBatchLookup[batchId];
+
+    size_t insertBatchIndex = mBatches.size();
+    if (targetBatch) {
+        locateInsertIndex(batchId, op->computedState.clippedBounds,
+                (BatchBase**)(&targetBatch), &insertBatchIndex);
+    }
+
+    if (targetBatch) {
+        targetBatch->batchOp(op);
+    } else  {
+        // new non-merging batch
+        targetBatch = new (allocator) OpBatch(batchId, op);
+        mBatchLookup[batchId] = targetBatch;
+        mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch);
+    }
+}
+
+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);
+    }
+    MergingOpBatch* targetBatch = nullptr;
+
+    // Try to merge with any existing batch with same mergeId
+    auto getResult = mMergingBatchLookup[batchId].find(mergeId);
+    if (getResult != mMergingBatchLookup[batchId].end()) {
+        targetBatch = getResult->second;
+        if (!targetBatch->canMergeWith(op)) {
+            targetBatch = nullptr;
+        }
+    }
+
+    size_t insertBatchIndex = mBatches.size();
+    locateInsertIndex(batchId, op->computedState.clippedBounds,
+            (BatchBase**)(&targetBatch), &insertBatchIndex);
+
+    if (targetBatch) {
+        targetBatch->mergeOp(op);
+    } else  {
+        // new merging batch
+        targetBatch = new (allocator) MergingOpBatch(batchId, op);
+        mMergingBatchLookup[batchId].insert(std::make_pair(mergeId, targetBatch));
+
+        mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch);
+    }
+}
+
+void LayerBuilder::replayBakedOpsImpl(void* arg,
+        BakedOpReceiver* unmergedReceivers, MergedOpReceiver* mergedReceivers) const {
+    ATRACE_NAME("flush drawing commands");
+    for (const BatchBase* batch : mBatches) {
+        size_t size = batch->getOps().size();
+        if (size > 1 && batch->isMerging()) {
+            int opId = batch->getOps()[0]->op->opId;
+            const MergingOpBatch* mergingBatch = static_cast<const MergingOpBatch*>(batch);
+            MergedBakedOpList data = {
+                    batch->getOps().data(),
+                    size,
+                    mergingBatch->getClipSideFlags(),
+                    mergingBatch->getClipRect()
+            };
+            mergedReceivers[opId](arg, data);
+        } else {
+            for (const BakedOpState* op : batch->getOps()) {
+                unmergedReceivers[op->op->opId](arg, *op);
+            }
+        }
+    }
+}
+
+void LayerBuilder::dump() const {
+    ALOGD("LayerBuilder %p, %ux%u buffer %p, blo %p, rn %p",
+            this, width, height, offscreenBuffer, beginLayerOp, renderNode);
+    for (const BatchBase* batch : mBatches) {
+        batch->dump();
+    }
+}
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/LayerBuilder.h b/libs/hwui/LayerBuilder.h
new file mode 100644
index 0000000..99968e1
--- /dev/null
+++ b/libs/hwui/LayerBuilder.h
@@ -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.
+ */
+
+#pragma once
+
+#include "ClipArea.h"
+#include "Rect.h"
+#include "utils/Macros.h"
+
+#include <vector>
+#include <unordered_map>
+
+struct SkRect;
+
+namespace android {
+namespace uirenderer {
+
+class BakedOpState;
+struct BeginLayerOp;
+class BatchBase;
+class LinearAllocator;
+struct MergedBakedOpList;
+class MergingOpBatch;
+class OffscreenBuffer;
+class OpBatch;
+class RenderNode;
+
+typedef int batchid_t;
+typedef const void* mergeid_t;
+
+namespace OpBatchType {
+    enum {
+        Bitmap,
+        MergedPatch,
+        AlphaVertices,
+        Vertices,
+        AlphaMaskTexture,
+        Text,
+        ColorText,
+        Shadow,
+        TextureLayer,
+        Functor,
+        CopyToLayer,
+        CopyFromLayer,
+
+        Count // must be last
+    };
+}
+
+typedef void (*BakedOpReceiver)(void*, const BakedOpState&);
+typedef void (*MergedOpReceiver)(void*, const MergedBakedOpList& opList);
+
+/**
+ * Stores the deferred render operations and state used to compute ordering
+ * for a single FBO/layer.
+ */
+class LayerBuilder {
+// Prevent copy/assign because users may stash pointer to offscreenBuffer and viewportClip
+PREVENT_COPY_AND_ASSIGN(LayerBuilder);
+public:
+    // Create LayerBuilder for Fbo0
+    LayerBuilder(uint32_t width, uint32_t height, const Rect& repaintRect)
+            : LayerBuilder(width, height, repaintRect, nullptr, nullptr) {};
+
+    // Create LayerBuilder for an offscreen layer, where beginLayerOp is present for a
+    // saveLayer, renderNode is present for a HW layer.
+    LayerBuilder(uint32_t width, uint32_t height,
+            const Rect& repaintRect, const BeginLayerOp* beginLayerOp, 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
+    void locateInsertIndex(int batchId, const Rect& clippedBounds,
+            BatchBase** targetBatch, size_t* insertBatchIndex) const;
+
+    void deferUnmergeableOp(LinearAllocator& allocator, BakedOpState* op, batchid_t batchId);
+
+    // insertion point of a new batch, will hopefully be immediately after similar batch
+    // (generally, should be similar shader)
+    void deferMergeableOp(LinearAllocator& allocator,
+            BakedOpState* op, batchid_t batchId, mergeid_t mergeId);
+
+    void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers, MergedOpReceiver*) const;
+
+    void deferLayerClear(const Rect& dstRect);
+
+    bool empty() const {
+        return mBatches.empty();
+    }
+
+    void clear() {
+        mBatches.clear();
+    }
+
+    void dump() const;
+
+    const uint32_t width;
+    const uint32_t height;
+    const Rect repaintRect;
+    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 flushLayerClears(LinearAllocator& allocator);
+
+    std::vector<BatchBase*> mBatches;
+
+    /**
+     * Maps the mergeid_t returned by an op's getMergeId() to the most recently seen
+     * MergingDrawBatch of that id. These ids are unique per draw type and guaranteed to not
+     * collide, which avoids the need to resolve mergeid collisions.
+     */
+    std::unordered_map<mergeid_t, MergingOpBatch*> mMergingBatchLookup[OpBatchType::Count];
+
+    // Maps batch ids to the most recent *non-merging* batch of that id
+    OpBatch* mBatchLookup[OpBatchType::Count] = { nullptr };
+
+    std::vector<Rect> mClearRects;
+};
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index b117754..f5681ce 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -112,7 +112,6 @@
         layer->bindTexture();
         layer->setFilter(GL_NEAREST);
         layer->setWrap(GL_CLAMP_TO_EDGE, false);
-        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
 
 #if DEBUG_LAYERS
         dump();
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index e9e5d81..3123e8e 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -287,7 +287,7 @@
 }
 
 void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
-        bool isOpaque, bool forceFilter, GLenum renderTarget, float* textureTransform) {
+        bool isOpaque, bool forceFilter, GLenum renderTarget, const float* textureTransform) {
     if (layer) {
         layer->setBlend(!isOpaque);
         layer->setForceFilter(forceFilter);
@@ -373,7 +373,6 @@
         GLenum format;
         GLenum type;
 
-        GLenum error = GL_NO_ERROR;
         bool status = false;
 
         switch (bitmap->colorType()) {
@@ -408,7 +407,6 @@
         renderState.bindFramebuffer(fbo);
 
         glGenTextures(1, &texture);
-        if ((error = glGetError()) != GL_NO_ERROR) goto error;
 
         caches.textureState().activateTexture(0);
         caches.textureState().bindTexture(texture);
@@ -423,11 +421,9 @@
 
         glTexImage2D(GL_TEXTURE_2D, 0, format, bitmap->width(), bitmap->height(),
                 0, format, type, nullptr);
-        if ((error = glGetError()) != GL_NO_ERROR) goto error;
 
         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                 GL_TEXTURE_2D, texture, 0);
-        if ((error = glGetError()) != GL_NO_ERROR) goto error;
 
         {
             LayerRenderer renderer(renderState, layer);
@@ -438,8 +434,6 @@
             renderer.translate(0.0f, bitmap->height());
             renderer.scale(1.0f, -1.0f);
 
-            if ((error = glGetError()) != GL_NO_ERROR) goto error;
-
             {
                 Rect bounds;
                 bounds.set(0.0f, 0.0f, bitmap->width(), bitmap->height());
@@ -448,19 +442,11 @@
                 glReadPixels(0, 0, bitmap->width(), bitmap->height(), format,
                         type, bitmap->getPixels());
 
-                if ((error = glGetError()) != GL_NO_ERROR) goto error;
             }
 
             status = true;
         }
 
-error:
-#if DEBUG_OPENGL
-        if (error != GL_NO_ERROR) {
-            ALOGD("GL error while copying layer into bitmap = 0x%x", error);
-        }
-#endif
-
         renderState.bindFramebuffer(previousFbo);
         layer->setAlpha(alpha, mode);
         layer->setFbo(previousLayerFbo);
@@ -468,6 +454,8 @@
         renderState.deleteFramebuffer(fbo);
         renderState.setViewport(previousViewportWidth, previousViewportHeight);
 
+        GL_CHECKPOINT(MODERATE);
+
         return status;
     }
     return false;
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index e4a54b0..38c3705 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -59,7 +59,7 @@
     static Layer* createRenderLayer(RenderState& renderState, uint32_t width, uint32_t height);
     static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
     static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
-            bool isOpaque, bool forceFilter, GLenum renderTarget, float* textureTransform);
+            bool isOpaque, bool forceFilter, GLenum renderTarget, const float* textureTransform);
     static void destroyLayer(Layer* layer);
     static bool copyLayer(RenderState& renderState, Layer* layer, SkBitmap* bitmap);
 
diff --git a/libs/hwui/LayerUpdateQueue.h b/libs/hwui/LayerUpdateQueue.h
index be612d2..5b1a854 100644
--- a/libs/hwui/LayerUpdateQueue.h
+++ b/libs/hwui/LayerUpdateQueue.h
@@ -42,7 +42,7 @@
     LayerUpdateQueue() {}
     void enqueueLayerWithDamage(RenderNode* renderNode, Rect dirty);
     void clear();
-    const std::vector<Entry> entries() const { return mEntries; }
+    const std::vector<Entry>& entries() const { return mEntries; }
 private:
     std::vector<Entry> mEntries;
 };
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index c017638..1c25f26 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -139,9 +139,11 @@
     }
 
     void multiply(const Matrix4& v) {
-        Matrix4 u;
-        u.loadMultiply(*this, v);
-        *this = u;
+        if (!v.isIdentity()) {
+            Matrix4 u;
+            u.loadMultiply(*this, v);
+            *this = u;
+        }
     }
 
     void multiply(float v);
diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp
deleted file mode 100644
index 6d90a42..0000000
--- a/libs/hwui/OpReorderer.cpp
+++ /dev/null
@@ -1,976 +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 "OpReorderer.h"
-
-#include "LayerUpdateQueue.h"
-#include "RenderNode.h"
-#include "renderstate/OffscreenBufferPool.h"
-#include "utils/FatVector.h"
-#include "utils/PaintUtils.h"
-#include "utils/TraceUtils.h"
-
-#include <SkCanvas.h>
-#include <SkPathOps.h>
-#include <utils/TypeHelpers.h>
-
-namespace android {
-namespace uirenderer {
-
-class BatchBase {
-
-public:
-    BatchBase(batchid_t batchId, BakedOpState* op, bool merging)
-            : mBatchId(batchId)
-            , mMerging(merging) {
-        mBounds = op->computedState.clippedBounds;
-        mOps.push_back(op);
-    }
-
-    bool intersects(const Rect& rect) const {
-        if (!rect.intersects(mBounds)) return false;
-
-        for (const BakedOpState* op : mOps) {
-            if (rect.intersects(op->computedState.clippedBounds)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    batchid_t getBatchId() const { return mBatchId; }
-    bool isMerging() const { return mMerging; }
-
-    const std::vector<BakedOpState*>& getOps() const { return mOps; }
-
-    void dump() const {
-        ALOGD("    Batch %p, id %d, merging %d, count %d, bounds " RECT_STRING,
-                this, mBatchId, mMerging, mOps.size(), RECT_ARGS(mBounds));
-    }
-protected:
-    batchid_t mBatchId;
-    Rect mBounds;
-    std::vector<BakedOpState*> mOps;
-    bool mMerging;
-};
-
-class OpBatch : public BatchBase {
-public:
-    static void* operator new(size_t size, LinearAllocator& allocator) {
-        return allocator.alloc(size);
-    }
-
-    OpBatch(batchid_t batchId, BakedOpState* op)
-            : BatchBase(batchId, op, false) {
-    }
-
-    void batchOp(BakedOpState* op) {
-        mBounds.unionWith(op->computedState.clippedBounds);
-        mOps.push_back(op);
-    }
-};
-
-class MergingOpBatch : public BatchBase {
-public:
-    static void* operator new(size_t size, LinearAllocator& allocator) {
-        return allocator.alloc(size);
-    }
-
-    MergingOpBatch(batchid_t batchId, BakedOpState* op)
-            : BatchBase(batchId, op, true) {
-    }
-
-    /*
-     * Helper for determining if a new op can merge with a MergingDrawBatch based on their bounds
-     * and clip side flags. Positive bounds delta means new bounds fit in old.
-     */
-    static inline bool checkSide(const int currentFlags, const int newFlags, const int side,
-            float boundsDelta) {
-        bool currentClipExists = currentFlags & side;
-        bool newClipExists = newFlags & side;
-
-        // if current is clipped, we must be able to fit new bounds in current
-        if (boundsDelta > 0 && currentClipExists) return false;
-
-        // if new is clipped, we must be able to fit current bounds in new
-        if (boundsDelta < 0 && newClipExists) return false;
-
-        return true;
-    }
-
-    static bool paintIsDefault(const SkPaint& paint) {
-        return paint.getAlpha() == 255
-                && paint.getColorFilter() == nullptr
-                && paint.getShader() == nullptr;
-    }
-
-    static bool paintsAreEquivalent(const SkPaint& a, const SkPaint& b) {
-        return a.getAlpha() == b.getAlpha()
-                && a.getColorFilter() == b.getColorFilter()
-                && a.getShader() == b.getShader();
-    }
-
-    /*
-     * Checks if a (mergeable) op can be merged into this batch
-     *
-     * If true, the op's multiDraw must be guaranteed to handle both ops simultaneously, so it is
-     * important to consider all paint attributes used in the draw calls in deciding both a) if an
-     * op tries to merge at all, and b) if the op can merge with another set of ops
-     *
-     * False positives can lead to information from the paints of subsequent merged operations being
-     * dropped, so we make simplifying qualifications on the ops that can merge, per op type.
-     */
-    bool canMergeWith(BakedOpState* op) const {
-        bool isTextBatch = getBatchId() == OpBatchType::Text
-                || getBatchId() == OpBatchType::ColorText;
-
-        // Overlapping other operations is only allowed for text without shadow. For other ops,
-        // multiDraw isn't guaranteed to overdraw correctly
-        if (!isTextBatch || PaintUtils::hasTextShadow(op->op->paint)) {
-            if (intersects(op->computedState.clippedBounds)) return false;
-        }
-
-        const BakedOpState* lhs = op;
-        const BakedOpState* rhs = mOps[0];
-
-        if (!MathUtils::areEqual(lhs->alpha, rhs->alpha)) return false;
-
-        // 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;
-
-        /* Clipping compatibility check
-         *
-         * Exploits the fact that if a op or batch is clipped on a side, its bounds will equal its
-         * clip for that side.
-         */
-        const int currentFlags = mClipSideFlags;
-        const int newFlags = op->computedState.clipSideFlags;
-        if (currentFlags != OpClipSideFlags::None || newFlags != OpClipSideFlags::None) {
-            const Rect& opBounds = op->computedState.clippedBounds;
-            float boundsDelta = mBounds.left - opBounds.left;
-            if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Left, boundsDelta)) return false;
-            boundsDelta = mBounds.top - opBounds.top;
-            if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Top, boundsDelta)) return false;
-
-            // right and bottom delta calculation reversed to account for direction
-            boundsDelta = opBounds.right - mBounds.right;
-            if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Right, boundsDelta)) return false;
-            boundsDelta = opBounds.bottom - mBounds.bottom;
-            if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Bottom, boundsDelta)) return false;
-        }
-
-        const SkPaint* newPaint = op->op->paint;
-        const SkPaint* oldPaint = mOps[0]->op->paint;
-
-        if (newPaint == oldPaint) {
-            // if paints are equal, then modifiers + paint attribs don't need to be compared
-            return true;
-        } else if (newPaint && !oldPaint) {
-            return paintIsDefault(*newPaint);
-        } else if (!newPaint && oldPaint) {
-            return paintIsDefault(*oldPaint);
-        }
-        return paintsAreEquivalent(*newPaint, *oldPaint);
-    }
-
-    void mergeOp(BakedOpState* op) {
-        mBounds.unionWith(op->computedState.clippedBounds);
-        mOps.push_back(op);
-
-        const int newClipSideFlags = op->computedState.clipSideFlags;
-        mClipSideFlags |= newClipSideFlags;
-
-        const Rect& opClip = op->computedState.clipRect;
-        if (newClipSideFlags & OpClipSideFlags::Left) mClipRect.left = opClip.left;
-        if (newClipSideFlags & OpClipSideFlags::Top) mClipRect.top = opClip.top;
-        if (newClipSideFlags & OpClipSideFlags::Right) mClipRect.right = opClip.right;
-        if (newClipSideFlags & OpClipSideFlags::Bottom) mClipRect.bottom = opClip.bottom;
-    }
-
-    bool getClipSideFlags() const { return mClipSideFlags; }
-    const Rect& getClipRect() const { return mClipRect; }
-
-private:
-    int mClipSideFlags = 0;
-    Rect mClipRect;
-};
-
-OpReorderer::LayerReorderer::LayerReorderer(uint32_t width, uint32_t height,
-        const Rect& repaintRect, const BeginLayerOp* beginLayerOp, RenderNode* renderNode)
-        : width(width)
-        , height(height)
-        , repaintRect(repaintRect)
-        , offscreenBuffer(renderNode ? renderNode->getLayer() : nullptr)
-        , beginLayerOp(beginLayerOp)
-        , 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
-void OpReorderer::LayerReorderer::locateInsertIndex(int batchId, const Rect& clippedBounds,
-        BatchBase** targetBatch, size_t* insertBatchIndex) const {
-    for (int i = mBatches.size() - 1; i >= 0; i--) {
-        BatchBase* overBatch = mBatches[i];
-
-        if (overBatch == *targetBatch) break;
-
-        // TODO: also consider shader shared between batch types
-        if (batchId == overBatch->getBatchId()) {
-            *insertBatchIndex = i + 1;
-            if (!*targetBatch) break; // found insert position, quit
-        }
-
-        if (overBatch->intersects(clippedBounds)) {
-            // NOTE: it may be possible to optimize for special cases where two operations
-            // of the same batch/paint could swap order, such as with a non-mergeable
-            // (clipped) and a mergeable text operation
-            *targetBatch = nullptr;
-            break;
-        }
-    }
-}
-
-void OpReorderer::LayerReorderer::deferUnmergeableOp(LinearAllocator& allocator,
-        BakedOpState* op, batchid_t batchId) {
-    OpBatch* targetBatch = mBatchLookup[batchId];
-
-    size_t insertBatchIndex = mBatches.size();
-    if (targetBatch) {
-        locateInsertIndex(batchId, op->computedState.clippedBounds,
-                (BatchBase**)(&targetBatch), &insertBatchIndex);
-    }
-
-    if (targetBatch) {
-        targetBatch->batchOp(op);
-    } else  {
-        // new non-merging batch
-        targetBatch = new (allocator) OpBatch(batchId, op);
-        mBatchLookup[batchId] = targetBatch;
-        mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch);
-    }
-}
-
-// insertion point of a new batch, will hopefully be immediately after similar batch
-// (generally, should be similar shader)
-void OpReorderer::LayerReorderer::deferMergeableOp(LinearAllocator& allocator,
-        BakedOpState* op, batchid_t batchId, mergeid_t mergeId) {
-    MergingOpBatch* targetBatch = nullptr;
-
-    // Try to merge with any existing batch with same mergeId
-    auto getResult = mMergingBatchLookup[batchId].find(mergeId);
-    if (getResult != mMergingBatchLookup[batchId].end()) {
-        targetBatch = getResult->second;
-        if (!targetBatch->canMergeWith(op)) {
-            targetBatch = nullptr;
-        }
-    }
-
-    size_t insertBatchIndex = mBatches.size();
-    locateInsertIndex(batchId, op->computedState.clippedBounds,
-            (BatchBase**)(&targetBatch), &insertBatchIndex);
-
-    if (targetBatch) {
-        targetBatch->mergeOp(op);
-    } else  {
-        // new merging batch
-        targetBatch = new (allocator) MergingOpBatch(batchId, op);
-        mMergingBatchLookup[batchId].insert(std::make_pair(mergeId, targetBatch));
-
-        mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch);
-    }
-}
-
-void OpReorderer::LayerReorderer::replayBakedOpsImpl(void* arg,
-        BakedOpReceiver* unmergedReceivers, MergedOpReceiver* mergedReceivers) const {
-    ATRACE_NAME("flush drawing commands");
-    for (const BatchBase* batch : mBatches) {
-        size_t size = batch->getOps().size();
-        if (size > 1 && batch->isMerging()) {
-            int opId = batch->getOps()[0]->op->opId;
-            const MergingOpBatch* mergingBatch = static_cast<const MergingOpBatch*>(batch);
-            MergedBakedOpList data = {
-                    batch->getOps().data(),
-                    size,
-                    mergingBatch->getClipSideFlags(),
-                    mergingBatch->getClipRect()
-            };
-            if (data.clipSideFlags) {
-                // if right or bottom sides aren't used to clip, init them to viewport bounds
-                // in the clip rect, so it can be used to scissor
-                if (!(data.clipSideFlags & OpClipSideFlags::Right)) data.clip.right = width;
-                if (!(data.clipSideFlags & OpClipSideFlags::Bottom)) data.clip.bottom = height;
-            }
-            mergedReceivers[opId](arg, data);
-        } else {
-            for (const BakedOpState* op : batch->getOps()) {
-                unmergedReceivers[op->op->opId](arg, *op);
-            }
-        }
-    }
-}
-
-void OpReorderer::LayerReorderer::dump() const {
-    ALOGD("LayerReorderer %p, %ux%u buffer %p, blo %p, rn %p",
-            this, width, height, offscreenBuffer, beginLayerOp, renderNode);
-    for (const BatchBase* batch : mBatches) {
-        batch->dump();
-    }
-}
-
-OpReorderer::OpReorderer(const LayerUpdateQueue& layers, const SkRect& clip,
-        uint32_t viewportWidth, uint32_t viewportHeight,
-        const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter)
-        : mCanvasState(*this) {
-    ATRACE_NAME("prepare drawing commands");
-
-    mLayerReorderers.reserve(layers.entries().size());
-    mLayerStack.reserve(layers.entries().size());
-
-    // Prepare to defer Fbo0
-    mLayerReorderers.emplace_back(viewportWidth, viewportHeight, Rect(clip));
-    mLayerStack.push_back(0);
-    mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
-            clip.fLeft, clip.fTop, clip.fRight, clip.fBottom,
-            lightCenter);
-
-    // Render all layers to be updated, in order. Defer in reverse order, so that they'll be
-    // updated in the order they're passed in (mLayerReorderers are issued to Renderer in reverse)
-    for (int i = layers.entries().size() - 1; i >= 0; i--) {
-        RenderNode* layerNode = layers.entries()[i].renderNode;
-        const Rect& layerDamage = layers.entries()[i].damage;
-        layerNode->computeOrdering();
-
-        // map current light center into RenderNode's coordinate space
-        Vector3 lightCenter = mCanvasState.currentSnapshot()->getRelativeLightCenter();
-        layerNode->getLayer()->inverseTransformInWindow.mapPoint3d(lightCenter);
-
-        saveForLayer(layerNode->getWidth(), layerNode->getHeight(), 0, 0,
-                layerDamage, lightCenter, nullptr, layerNode);
-
-        if (layerNode->getDisplayList()) {
-            deferNodeOps(*layerNode);
-        }
-        restoreForLayer();
-    }
-
-    // Defer Fbo0
-    for (const sp<RenderNode>& node : nodes) {
-        if (node->nothingToDraw()) continue;
-        node->computeOrdering();
-
-        int count = mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
-        deferNodePropsAndOps(*node);
-        mCanvasState.restoreToCount(count);
-    }
-}
-
-void OpReorderer::onViewportInitialized() {}
-
-void OpReorderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
-
-void OpReorderer::deferNodePropsAndOps(RenderNode& node) {
-    const RenderProperties& properties = node.properties();
-    const Outline& outline = properties.getOutline();
-    if (properties.getAlpha() <= 0
-            || (outline.getShouldClip() && outline.isEmpty())
-            || properties.getScaleX() == 0
-            || properties.getScaleY() == 0) {
-        return; // rejected
-    }
-
-    if (properties.getLeft() != 0 || properties.getTop() != 0) {
-        mCanvasState.translate(properties.getLeft(), properties.getTop());
-    }
-    if (properties.getStaticMatrix()) {
-        mCanvasState.concatMatrix(*properties.getStaticMatrix());
-    } else if (properties.getAnimationMatrix()) {
-        mCanvasState.concatMatrix(*properties.getAnimationMatrix());
-    }
-    if (properties.hasTransformMatrix()) {
-        if (properties.isTransformTranslateOnly()) {
-            mCanvasState.translate(properties.getTranslationX(), properties.getTranslationY());
-        } else {
-            mCanvasState.concatMatrix(*properties.getTransformMatrix());
-        }
-    }
-
-    const int width = properties.getWidth();
-    const int height = properties.getHeight();
-
-    Rect saveLayerBounds; // will be set to non-empty if saveLayer needed
-    const bool isLayer = properties.effectiveLayerType() != LayerType::None;
-    int clipFlags = properties.getClippingFlags();
-    if (properties.getAlpha() < 1) {
-        if (isLayer) {
-            clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
-        }
-        if (CC_LIKELY(isLayer || !properties.getHasOverlappingRendering())) {
-            // simply scale rendering content's alpha
-            mCanvasState.scaleAlpha(properties.getAlpha());
-        } else {
-            // schedule saveLayer by initializing saveLayerBounds
-            saveLayerBounds.set(0, 0, width, height);
-            if (clipFlags) {
-                properties.getClippingRectForFlags(clipFlags, &saveLayerBounds);
-                clipFlags = 0; // all clipping done by savelayer
-            }
-        }
-
-        if (CC_UNLIKELY(ATRACE_ENABLED() && properties.promotedToLayer())) {
-            // pretend alpha always causes savelayer to warn about
-            // performance problem affecting old versions
-            ATRACE_FORMAT("%s alpha caused saveLayer %dx%d", node.getName(), width, height);
-        }
-    }
-    if (clipFlags) {
-        Rect clipRect;
-        properties.getClippingRectForFlags(clipFlags, &clipRect);
-        mCanvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom,
-                SkRegion::kIntersect_Op);
-    }
-
-    if (properties.getRevealClip().willClip()) {
-        Rect bounds;
-        properties.getRevealClip().getBounds(&bounds);
-        mCanvasState.setClippingRoundRect(mAllocator,
-                bounds, properties.getRevealClip().getRadius());
-    } else if (properties.getOutline().willClip()) {
-        mCanvasState.setClippingOutline(mAllocator, &(properties.getOutline()));
-    }
-
-    if (!mCanvasState.quickRejectConservative(0, 0, width, height)) {
-        // not rejected, so defer render as either Layer, or direct (possibly wrapped in saveLayer)
-        if (node.getLayer()) {
-            // HW layer
-            LayerOp* drawLayerOp = new (mAllocator) LayerOp(node);
-            BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp);
-            if (bakedOpState) {
-                // Node's layer already deferred, schedule it to render into parent layer
-                currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Bitmap);
-            }
-        } else if (CC_UNLIKELY(!saveLayerBounds.isEmpty())) {
-            // draw DisplayList contents within temporary, since persisted layer could not be used.
-            // (temp layers are clipped to viewport, since they don't persist offscreen content)
-            SkPaint saveLayerPaint;
-            saveLayerPaint.setAlpha(properties.getAlpha());
-            deferBeginLayerOp(*new (mAllocator) BeginLayerOp(
-                    saveLayerBounds,
-                    Matrix4::identity(),
-                    saveLayerBounds,
-                    &saveLayerPaint));
-            deferNodeOps(node);
-            deferEndLayerOp(*new (mAllocator) EndLayerOp());
-        } else {
-            deferNodeOps(node);
-        }
-    }
-}
-
-typedef key_value_pair_t<float, const RenderNodeOp*> ZRenderNodeOpPair;
-
-template <typename V>
-static void buildZSortedChildList(V* zTranslatedNodes,
-        const DisplayList& displayList, const DisplayList::Chunk& chunk) {
-    if (chunk.beginChildIndex == chunk.endChildIndex) return;
-
-    for (size_t i = chunk.beginChildIndex; i < chunk.endChildIndex; i++) {
-        RenderNodeOp* childOp = displayList.getChildren()[i];
-        RenderNode* child = childOp->renderNode;
-        float childZ = child->properties().getZ();
-
-        if (!MathUtils::isZero(childZ) && chunk.reorderChildren) {
-            zTranslatedNodes->push_back(ZRenderNodeOpPair(childZ, childOp));
-            childOp->skipInOrderDraw = true;
-        } else if (!child->properties().getProjectBackwards()) {
-            // regular, in order drawing DisplayList
-            childOp->skipInOrderDraw = false;
-        }
-    }
-
-    // Z sort any 3d children (stable-ness makes z compare fall back to standard drawing order)
-    std::stable_sort(zTranslatedNodes->begin(), zTranslatedNodes->end());
-}
-
-template <typename V>
-static size_t findNonNegativeIndex(const V& zTranslatedNodes) {
-    for (size_t i = 0; i < zTranslatedNodes.size(); i++) {
-        if (zTranslatedNodes[i].key >= 0.0f) return i;
-    }
-    return zTranslatedNodes.size();
-}
-
-template <typename V>
-void OpReorderer::defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedNodes) {
-    const int size = zTranslatedNodes.size();
-    if (size == 0
-            || (mode == ChildrenSelectMode::Negative&& zTranslatedNodes[0].key > 0.0f)
-            || (mode == ChildrenSelectMode::Positive && zTranslatedNodes[size - 1].key < 0.0f)) {
-        // no 3d children to draw
-        return;
-    }
-
-    /**
-     * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters
-     * with very similar Z heights to draw together.
-     *
-     * This way, if Views A & B have the same Z height and are both casting shadows, the shadows are
-     * underneath both, and neither's shadow is drawn on top of the other.
-     */
-    const size_t nonNegativeIndex = findNonNegativeIndex(zTranslatedNodes);
-    size_t drawIndex, shadowIndex, endIndex;
-    if (mode == ChildrenSelectMode::Negative) {
-        drawIndex = 0;
-        endIndex = nonNegativeIndex;
-        shadowIndex = endIndex; // draw no shadows
-    } else {
-        drawIndex = nonNegativeIndex;
-        endIndex = size;
-        shadowIndex = drawIndex; // potentially draw shadow for each pos Z child
-    }
-
-    float lastCasterZ = 0.0f;
-    while (shadowIndex < endIndex || drawIndex < endIndex) {
-        if (shadowIndex < endIndex) {
-            const RenderNodeOp* casterNodeOp = zTranslatedNodes[shadowIndex].value;
-            const float casterZ = zTranslatedNodes[shadowIndex].key;
-            // attempt to render the shadow if the caster about to be drawn is its caster,
-            // OR if its caster's Z value is similar to the previous potential caster
-            if (shadowIndex == drawIndex || casterZ - lastCasterZ < 0.1f) {
-                deferShadow(*casterNodeOp);
-
-                lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
-                shadowIndex++;
-                continue;
-            }
-        }
-
-        const RenderNodeOp* childOp = zTranslatedNodes[drawIndex].value;
-        deferRenderNodeOpImpl(*childOp);
-        drawIndex++;
-    }
-}
-
-void OpReorderer::deferShadow(const RenderNodeOp& casterNodeOp) {
-    auto& node = *casterNodeOp.renderNode;
-    auto& properties = node.properties();
-
-    if (properties.getAlpha() <= 0.0f
-            || properties.getOutline().getAlpha() <= 0.0f
-            || !properties.getOutline().getPath()
-            || properties.getScaleX() == 0
-            || properties.getScaleY() == 0) {
-        // no shadow to draw
-        return;
-    }
-
-    const SkPath* casterOutlinePath = properties.getOutline().getPath();
-    const SkPath* revealClipPath = properties.getRevealClip().getPath();
-    if (revealClipPath && revealClipPath->isEmpty()) return;
-
-    float casterAlpha = properties.getAlpha() * properties.getOutline().getAlpha();
-
-    // holds temporary SkPath to store the result of intersections
-    SkPath* frameAllocatedPath = nullptr;
-    const SkPath* casterPath = casterOutlinePath;
-
-    // intersect the shadow-casting path with the reveal, if present
-    if (revealClipPath) {
-        frameAllocatedPath = createFrameAllocatedPath();
-
-        Op(*casterPath, *revealClipPath, kIntersect_SkPathOp, frameAllocatedPath);
-        casterPath = frameAllocatedPath;
-    }
-
-    // intersect the shadow-casting path with the clipBounds, if present
-    if (properties.getClippingFlags() & CLIP_TO_CLIP_BOUNDS) {
-        if (!frameAllocatedPath) {
-            frameAllocatedPath = createFrameAllocatedPath();
-        }
-        Rect clipBounds;
-        properties.getClippingRectForFlags(CLIP_TO_CLIP_BOUNDS, &clipBounds);
-        SkPath clipBoundsPath;
-        clipBoundsPath.addRect(clipBounds.left, clipBounds.top,
-                clipBounds.right, clipBounds.bottom);
-
-        Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, frameAllocatedPath);
-        casterPath = frameAllocatedPath;
-    }
-
-    ShadowOp* shadowOp = new (mAllocator) ShadowOp(casterNodeOp, casterAlpha, casterPath,
-            mCanvasState.getLocalClipBounds(),
-            mCanvasState.currentSnapshot()->getRelativeLightCenter());
-    BakedOpState* bakedOpState = BakedOpState::tryShadowOpConstruct(
-            mAllocator, *mCanvasState.currentSnapshot(), shadowOp);
-    if (CC_LIKELY(bakedOpState)) {
-        currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Shadow);
-    }
-}
-
-void OpReorderer::deferProjectedChildren(const RenderNode& renderNode) {
-    const SkPath* projectionReceiverOutline = renderNode.properties().getOutline().getPath();
-    int count = mCanvasState.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-
-    // 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(SkCanvas::kMatrix_SaveFlag);
-        mCanvasState.concatMatrix(childOp->transformFromCompositingAncestor);
-        deferRenderNodeOpImpl(*childOp);
-        mCanvasState.restoreToCount(restoreTo);
-    }
-
-    mCanvasState.restoreToCount(count);
-}
-
-/**
- * Used to define a list of lambdas referencing private OpReorderer::onXX::defer() methods.
- *
- * This allows opIds embedded in the RecordedOps to be used for dispatching to these lambdas.
- * E.g. a BitmapOp op then would be dispatched to OpReorderer::onBitmapOp(const BitmapOp&)
- */
-#define OP_RECEIVER(Type) \
-        [](OpReorderer& reorderer, const RecordedOp& op) { reorderer.defer##Type(static_cast<const Type&>(op)); },
-void OpReorderer::deferNodeOps(const RenderNode& renderNode) {
-    typedef void (*OpDispatcher) (OpReorderer& reorderer, const RecordedOp& op);
-    static OpDispatcher receivers[] = {
-        MAP_OPS(OP_RECEIVER)
-    };
-
-    // can't be null, since DL=null node rejection happens before deferNodePropsAndOps
-    const DisplayList& displayList = *(renderNode.getDisplayList());
-    for (const DisplayList::Chunk& chunk : displayList.getChunks()) {
-        FatVector<ZRenderNodeOpPair, 16> zTranslatedNodes;
-        buildZSortedChildList(&zTranslatedNodes, displayList, chunk);
-
-        defer3dChildren(ChildrenSelectMode::Negative, zTranslatedNodes);
-        for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
-            const RecordedOp* op = displayList.getOps()[opIndex];
-            receivers[op->opId](*this, *op);
-
-            if (CC_UNLIKELY(!renderNode.mProjectedNodes.empty()
-                    && displayList.projectionReceiveIndex >= 0
-                    && static_cast<int>(opIndex) == displayList.projectionReceiveIndex)) {
-                deferProjectedChildren(renderNode);
-            }
-        }
-        defer3dChildren(ChildrenSelectMode::Positive, zTranslatedNodes);
-    }
-}
-
-void OpReorderer::deferRenderNodeOpImpl(const RenderNodeOp& op) {
-    if (op.renderNode->nothingToDraw()) return;
-    int count = mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
-
-    // apply state from RecordedOp
-    mCanvasState.concatMatrix(op.localMatrix);
-    mCanvasState.clipRect(op.localClipRect.left, op.localClipRect.top,
-            op.localClipRect.right, op.localClipRect.bottom, SkRegion::kIntersect_Op);
-
-    // then apply state from node properties, and defer ops
-    deferNodePropsAndOps(*op.renderNode);
-
-    mCanvasState.restoreToCount(count);
-}
-
-void OpReorderer::deferRenderNodeOp(const RenderNodeOp& op) {
-    if (!op.skipInOrderDraw) {
-        deferRenderNodeOpImpl(op);
-    }
-}
-
-/**
- * Defers an unmergeable, strokeable op, accounting correctly
- * for paint's style on the bounds being computed.
- */
-void OpReorderer::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.currentSnapshot(), op, strokeBehavior);
-    if (!bakedState) return; // quick rejected
-    currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId);
-}
-
-/**
- * Returns batch id for tessellatable shapes, based on paint. Checks to see if path effect/AA will
- * be used, since they trigger significantly different rendering paths.
- *
- * Note: not used for lines/points, since they don't currently support path effects.
- */
-static batchid_t tessBatchId(const RecordedOp& op) {
-    const SkPaint& paint = *(op.paint);
-    return paint.getPathEffect()
-            ? OpBatchType::AlphaMaskTexture
-            : (paint.isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices);
-}
-
-void OpReorderer::deferArcOp(const ArcOp& op) {
-    deferStrokeableOp(op, tessBatchId(op));
-}
-
-void OpReorderer::deferBitmapOp(const BitmapOp& op) {
-    BakedOpState* bakedState = tryBakeOpState(op);
-    if (!bakedState) return; // quick rejected
-
-    // 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()
-    if (bakedState->computedState.transform.isSimple()
-            && bakedState->computedState.transform.positiveScale()
-            && PaintUtils::getXfermodeDirect(op.paint) == SkXfermode::kSrcOver_Mode
-            && op.bitmap->colorType() != kAlpha_8_SkColorType) {
-        mergeid_t mergeId = (mergeid_t) op.bitmap->getGenerationID();
-        // TODO: AssetAtlas in mergeId
-        currentLayer().deferMergeableOp(mAllocator, bakedState, OpBatchType::Bitmap, mergeId);
-    } else {
-        currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
-    }
-}
-
-void OpReorderer::deferBitmapMeshOp(const BitmapMeshOp& op) {
-    BakedOpState* bakedState = tryBakeOpState(op);
-    if (!bakedState) return; // quick rejected
-    currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
-}
-
-void OpReorderer::deferBitmapRectOp(const BitmapRectOp& op) {
-    BakedOpState* bakedState = tryBakeOpState(op);
-    if (!bakedState) return; // quick rejected
-    currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
-}
-
-void OpReorderer::deferCirclePropsOp(const CirclePropsOp& op) {
-    // allocate a temporary oval op (with mAllocator, so it persists until render), so the
-    // renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple.
-    float x = *(op.x);
-    float y = *(op.y);
-    float radius = *(op.radius);
-    Rect unmappedBounds(x - radius, y - radius, x + radius, y + radius);
-    const OvalOp* resolvedOp = new (mAllocator) OvalOp(
-            unmappedBounds,
-            op.localMatrix,
-            op.localClipRect,
-            op.paint);
-    deferOvalOp(*resolvedOp);
-}
-
-void OpReorderer::deferFunctorOp(const FunctorOp& op) {
-    BakedOpState* bakedState = tryBakeOpState(op);
-    if (!bakedState) return; // quick rejected
-    currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::None);
-}
-
-void OpReorderer::deferLinesOp(const LinesOp& op) {
-    batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices;
-    deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced);
-}
-
-void OpReorderer::deferOvalOp(const OvalOp& op) {
-    deferStrokeableOp(op, tessBatchId(op));
-}
-
-void OpReorderer::deferPatchOp(const PatchOp& op) {
-    BakedOpState* bakedState = tryBakeOpState(op);
-    if (!bakedState) return; // quick rejected
-
-    if (bakedState->computedState.transform.isPureTranslate()
-            && PaintUtils::getXfermodeDirect(op.paint) == SkXfermode::kSrcOver_Mode) {
-        mergeid_t mergeId = (mergeid_t) op.bitmap->getGenerationID();
-        // TODO: AssetAtlas in mergeId
-
-        // Only use the MergedPatch batchId when merged, so Bitmap+Patch don't try to merge together
-        currentLayer().deferMergeableOp(mAllocator, bakedState, OpBatchType::MergedPatch, mergeId);
-    } else {
-        // Use Bitmap batchId since Bitmap+Patch use same shader
-        currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
-    }
-}
-
-void OpReorderer::deferPathOp(const PathOp& op) {
-    deferStrokeableOp(op, OpBatchType::Bitmap);
-}
-
-void OpReorderer::deferPointsOp(const PointsOp& op) {
-    batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices;
-    deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced);
-}
-
-void OpReorderer::deferRectOp(const RectOp& op) {
-    deferStrokeableOp(op, tessBatchId(op));
-}
-
-void OpReorderer::deferRoundRectOp(const RoundRectOp& op) {
-    deferStrokeableOp(op, tessBatchId(op));
-}
-
-void OpReorderer::deferRoundRectPropsOp(const RoundRectPropsOp& op) {
-    // allocate a temporary round rect op (with mAllocator, so it persists until render), so the
-    // renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple.
-    const RoundRectOp* resolvedOp = new (mAllocator) RoundRectOp(
-            Rect(*(op.left), *(op.top), *(op.right), *(op.bottom)),
-            op.localMatrix,
-            op.localClipRect,
-            op.paint, *op.rx, *op.ry);
-    deferRoundRectOp(*resolvedOp);
-}
-
-void OpReorderer::deferSimpleRectsOp(const SimpleRectsOp& op) {
-    BakedOpState* bakedState = tryBakeOpState(op);
-    if (!bakedState) return; // quick rejected
-    currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices);
-}
-
-void OpReorderer::deferTextOp(const TextOp& op) {
-    BakedOpState* bakedState = tryBakeOpState(op);
-    if (!bakedState) return; // quick rejected
-
-    // TODO: better handling of shader (since we won't care about color then)
-    batchid_t batchId = op.paint->getColor() == SK_ColorBLACK
-            ? OpBatchType::Text : OpBatchType::ColorText;
-
-    if (bakedState->computedState.transform.isPureTranslate()
-            && PaintUtils::getXfermodeDirect(op.paint) == SkXfermode::kSrcOver_Mode) {
-        mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.paint->getColor());
-        currentLayer().deferMergeableOp(mAllocator, bakedState, batchId, mergeId);
-    } else {
-        currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId);
-    }
-}
-
-void OpReorderer::saveForLayer(uint32_t layerWidth, uint32_t layerHeight,
-        float contentTranslateX, float contentTranslateY,
-        const Rect& repaintRect,
-        const Vector3& lightCenter,
-        const BeginLayerOp* beginLayerOp, RenderNode* renderNode) {
-    mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
-    mCanvasState.writableSnapshot()->initializeViewport(layerWidth, layerHeight);
-    mCanvasState.writableSnapshot()->roundRectClipState = nullptr;
-    mCanvasState.writableSnapshot()->setRelativeLightCenter(lightCenter);
-    mCanvasState.writableSnapshot()->transform->loadTranslate(
-            contentTranslateX, contentTranslateY, 0);
-    mCanvasState.writableSnapshot()->setClip(
-            repaintRect.left, repaintRect.top, repaintRect.right, repaintRect.bottom);
-
-    // create a new layer repaint, and push its index on the stack
-    mLayerStack.push_back(mLayerReorderers.size());
-    mLayerReorderers.emplace_back(layerWidth, layerHeight, repaintRect, beginLayerOp, renderNode);
-}
-
-void OpReorderer::restoreForLayer() {
-    // restore canvas, and pop finished layer off of the stack
-    mCanvasState.restore();
-    mLayerStack.pop_back();
-}
-
-// TODO: test rejection at defer time, where the bounds become empty
-void OpReorderer::deferBeginLayerOp(const BeginLayerOp& op) {
-    uint32_t layerWidth = (uint32_t) op.unmappedBounds.getWidth();
-    uint32_t layerHeight = (uint32_t) op.unmappedBounds.getHeight();
-
-    auto previous = mCanvasState.currentSnapshot();
-    Vector3 lightCenter = previous->getRelativeLightCenter();
-
-    // Combine all transforms used to present saveLayer content:
-    // parent content transform * canvas transform * bounds offset
-    Matrix4 contentTransform(*previous->transform);
-    contentTransform.multiply(op.localMatrix);
-    contentTransform.translate(op.unmappedBounds.left, op.unmappedBounds.top);
-
-    Matrix4 inverseContentTransform;
-    inverseContentTransform.loadInverse(contentTransform);
-
-    // map the light center into layer-relative space
-    inverseContentTransform.mapPoint3d(lightCenter);
-
-    // Clip bounds of temporary layer to parent's clip rect, so:
-    Rect saveLayerBounds(layerWidth, layerHeight);
-    //     1) transform Rect(width, height) into parent's space
-    //        note: left/top offsets put in contentTransform above
-    contentTransform.mapRect(saveLayerBounds);
-    //     2) intersect with parent's clip
-    saveLayerBounds.doIntersect(previous->getRenderTargetClip());
-    //     3) and transform back
-    inverseContentTransform.mapRect(saveLayerBounds);
-    saveLayerBounds.doIntersect(Rect(layerWidth, layerHeight));
-    saveLayerBounds.roundOut();
-
-    // if bounds are reduced, will clip the layer's area by reducing required bounds...
-    layerWidth = saveLayerBounds.getWidth();
-    layerHeight = saveLayerBounds.getHeight();
-    // ...and shifting drawing content to account for left/top side clipping
-    float contentTranslateX = -saveLayerBounds.left;
-    float contentTranslateY = -saveLayerBounds.top;
-
-    saveForLayer(layerWidth, layerHeight,
-            contentTranslateX, contentTranslateY,
-            Rect(layerWidth, layerHeight),
-            lightCenter,
-            &op, nullptr);
-}
-
-void OpReorderer::deferEndLayerOp(const EndLayerOp& /* ignored */) {
-    const BeginLayerOp& beginLayerOp = *currentLayer().beginLayerOp;
-    int finishedLayerIndex = mLayerStack.back();
-
-    restoreForLayer();
-
-    // record the draw operation into the previous layer's list of draw commands
-    // uses state from the associated beginLayerOp, since it has all the state needed for drawing
-    LayerOp* drawLayerOp = new (mAllocator) LayerOp(
-            beginLayerOp.unmappedBounds,
-            beginLayerOp.localMatrix,
-            beginLayerOp.localClipRect,
-            beginLayerOp.paint,
-            &mLayerReorderers[finishedLayerIndex].offscreenBuffer);
-    BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp);
-
-    if (bakedOpState) {
-        // Layer will be drawn into parent layer (which is now current, since we popped mLayerStack)
-        currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Bitmap);
-    } else {
-        // Layer won't be drawn - delete its drawing batches to prevent it from doing any work
-        mLayerReorderers[finishedLayerIndex].clear();
-        return;
-    }
-}
-
-void OpReorderer::deferLayerOp(const LayerOp& op) {
-    LOG_ALWAYS_FATAL("unsupported");
-}
-
-void OpReorderer::deferShadowOp(const ShadowOp& op) {
-    LOG_ALWAYS_FATAL("unsupported");
-}
-
-} // namespace uirenderer
-} // namespace android
diff --git a/libs/hwui/OpReorderer.h b/libs/hwui/OpReorderer.h
deleted file mode 100644
index 35343c8b..0000000
--- a/libs/hwui/OpReorderer.h
+++ /dev/null
@@ -1,290 +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 ANDROID_HWUI_OP_REORDERER_H
-#define ANDROID_HWUI_OP_REORDERER_H
-
-#include "BakedOpState.h"
-#include "CanvasState.h"
-#include "DisplayList.h"
-#include "RecordedOp.h"
-
-#include <vector>
-#include <unordered_map>
-
-struct SkRect;
-
-namespace android {
-namespace uirenderer {
-
-class BakedOpState;
-class BatchBase;
-class LayerUpdateQueue;
-class MergingOpBatch;
-class OffscreenBuffer;
-class OpBatch;
-class Rect;
-
-typedef int batchid_t;
-typedef const void* mergeid_t;
-
-namespace OpBatchType {
-    enum {
-        None = 0, // Don't batch
-        Bitmap,
-        MergedPatch,
-        AlphaVertices,
-        Vertices,
-        AlphaMaskTexture,
-        Text,
-        ColorText,
-        Shadow,
-
-        Count // must be last
-    };
-}
-
-class OpReorderer : public CanvasStateClient {
-    typedef void (*BakedOpReceiver)(void*, const BakedOpState&);
-    typedef void (*MergedOpReceiver)(void*, const MergedBakedOpList& opList);
-
-    /**
-     * Stores the deferred render operations and state used to compute ordering
-     * for a single FBO/layer.
-     */
-    class LayerReorderer {
-    public:
-        // Create LayerReorderer for Fbo0
-        LayerReorderer(uint32_t width, uint32_t height, const Rect& repaintRect)
-                : LayerReorderer(width, height, repaintRect, nullptr, nullptr) {};
-
-        // Create LayerReorderer for an offscreen layer, where beginLayerOp is present for a
-        // saveLayer, renderNode is present for a HW layer.
-        LayerReorderer(uint32_t width, uint32_t height,
-                const Rect& repaintRect, const BeginLayerOp* beginLayerOp, 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
-        void locateInsertIndex(int batchId, const Rect& clippedBounds,
-                BatchBase** targetBatch, size_t* insertBatchIndex) const;
-
-        void deferUnmergeableOp(LinearAllocator& allocator, BakedOpState* op, batchid_t batchId);
-
-        // insertion point of a new batch, will hopefully be immediately after similar batch
-        // (generally, should be similar shader)
-        void deferMergeableOp(LinearAllocator& allocator,
-                BakedOpState* op, batchid_t batchId, mergeid_t mergeId);
-
-        void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers, MergedOpReceiver*) const;
-
-        bool empty() const {
-            return mBatches.empty();
-        }
-
-        void clear() {
-            mBatches.clear();
-        }
-
-        void dump() const;
-
-        const uint32_t width;
-        const uint32_t height;
-        const Rect repaintRect;
-        OffscreenBuffer* offscreenBuffer;
-        const BeginLayerOp* beginLayerOp;
-        const RenderNode* renderNode;
-    private:
-        std::vector<BatchBase*> mBatches;
-
-        /**
-         * Maps the mergeid_t returned by an op's getMergeId() to the most recently seen
-         * MergingDrawBatch of that id. These ids are unique per draw type and guaranteed to not
-         * collide, which avoids the need to resolve mergeid collisions.
-         */
-        std::unordered_map<mergeid_t, MergingOpBatch*> mMergingBatchLookup[OpBatchType::Count];
-
-        // Maps batch ids to the most recent *non-merging* batch of that id
-        OpBatch* mBatchLookup[OpBatchType::Count] = { nullptr };
-    };
-
-public:
-    OpReorderer(const LayerUpdateQueue& layers, const SkRect& clip,
-            uint32_t viewportWidth, uint32_t viewportHeight,
-            const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter);
-
-    virtual ~OpReorderer() {}
-
-    /**
-     * replayBakedOps() is templated based on what class will receive ops being replayed.
-     *
-     * 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) {
-        /**
-         * 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.
-         *
-         * For example a BitmapOp would resolve, via the lambda lookup, to calling:
-         *
-         * StaticDispatcher::onBitmapOp(Renderer& renderer, const BitmapOp& op, const BakedOpState& state);
-         */
-        #define X(Type) \
-                [](void* renderer, const BakedOpState& state) { \
-                    StaticDispatcher::on##Type(*(static_cast<Renderer*>(renderer)), static_cast<const Type&>(*(state.op)), state); \
-                },
-        static BakedOpReceiver unmergedReceivers[] = {
-            MAP_OPS(X)
-        };
-        #undef X
-
-        /**
-         * defines a LUT of lambdas which allow merged arrays of BakedOpState* to be passed to a
-         * static dispatcher when the group of merged ops is replayed. Unmergeable ops trigger
-         * a LOG_ALWAYS_FATAL().
-         */
-        #define X(Type) \
-                [](void* renderer, const MergedBakedOpList& opList) { \
-                    LOG_ALWAYS_FATAL("op type %d does not support merging", opList.states[0]->op->opId); \
-                },
-        #define Y(Type) \
-                [](void* renderer, const MergedBakedOpList& opList) { \
-                    StaticDispatcher::onMerged##Type##s(*(static_cast<Renderer*>(renderer)), opList); \
-                },
-        static MergedOpReceiver mergedReceivers[] = {
-            MAP_OPS_BASED_ON_MERGEABILITY(X, Y)
-        };
-        #undef X
-        #undef Y
-
-        // Relay through layers in reverse order, since layers
-        // later in the list will be drawn by earlier ones
-        for (int i = mLayerReorderers.size() - 1; i >= 1; i--) {
-            LayerReorderer& layer = mLayerReorderers[i];
-            if (layer.renderNode) {
-                // cached HW layer - can't skip layer if empty
-                renderer.startRepaintLayer(layer.offscreenBuffer, layer.repaintRect);
-                layer.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers);
-                renderer.endLayer();
-            } else if (!layer.empty()) { // save layer - skip entire layer if empty
-                layer.offscreenBuffer = renderer.startTemporaryLayer(layer.width, layer.height);
-                layer.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers);
-                renderer.endLayer();
-            }
-        }
-
-        const LayerReorderer& fbo0 = mLayerReorderers[0];
-        renderer.startFrame(fbo0.width, fbo0.height, fbo0.repaintRect);
-        fbo0.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers);
-        renderer.endFrame();
-    }
-
-    void dump() const {
-        for (auto&& layer : mLayerReorderers) {
-            layer.dump();
-        }
-    }
-
-    ///////////////////////////////////////////////////////////////////
-    /// CanvasStateClient interface
-    ///////////////////////////////////////////////////////////////////
-    virtual void onViewportInitialized() override;
-    virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) override;
-    virtual GLuint getTargetFbo() const override { return 0; }
-
-private:
-    enum class ChildrenSelectMode {
-        Negative,
-        Positive
-    };
-    void saveForLayer(uint32_t layerWidth, uint32_t layerHeight,
-            float contentTranslateX, float contentTranslateY,
-            const Rect& repaintRect,
-            const Vector3& lightCenter,
-            const BeginLayerOp* beginLayerOp, RenderNode* renderNode);
-    void restoreForLayer();
-
-    LayerReorderer& currentLayer() { return mLayerReorderers[mLayerStack.back()]; }
-
-    BakedOpState* tryBakeOpState(const RecordedOp& recordedOp) {
-        return BakedOpState::tryConstruct(mAllocator, *mCanvasState.currentSnapshot(), recordedOp);
-    }
-
-    // should always be surrounded by a save/restore pair, and not called if DisplayList is null
-    void deferNodePropsAndOps(RenderNode& node);
-
-    template <typename V>
-    void defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedNodes);
-
-    void deferShadow(const RenderNodeOp& casterOp);
-
-    void deferProjectedChildren(const RenderNode& renderNode);
-
-    void deferNodeOps(const RenderNode& renderNode);
-
-    void deferRenderNodeOpImpl(const RenderNodeOp& op);
-
-    void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers);
-
-    SkPath* createFrameAllocatedPath() {
-        mFrameAllocatedPaths.emplace_back(new SkPath);
-        return mFrameAllocatedPaths.back().get();
-    }
-
-    void deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
-            BakedOpState::StrokeBehavior strokeBehavior = BakedOpState::StrokeBehavior::StyleDefined);
-
-    /**
-     * Declares all OpReorderer::deferXXXXOp() methods for every RecordedOp type.
-     *
-     * These private methods are called from within deferImpl to defer each individual op
-     * type differently.
-     */
-#define INTERNAL_OP_HANDLER(Type) \
-    void defer##Type(const Type& op);
-    MAP_OPS(INTERNAL_OP_HANDLER)
-
-    std::vector<std::unique_ptr<SkPath> > mFrameAllocatedPaths;
-
-    // List of every deferred layer's render state. Replayed in reverse order to render a frame.
-    std::vector<LayerReorderer> mLayerReorderers;
-
-    /*
-     * Stack of indices within mLayerReorderers representing currently active layers. If drawing
-     * layerA within a layerB, will contain, in order:
-     *  - 0 (representing FBO 0, always present)
-     *  - layerB's index
-     *  - layerA's index
-     *
-     * Note that this doesn't vector doesn't always map onto all values of mLayerReorderers. When a
-     * layer is finished deferring, it will still be represented in mLayerReorderers, but it's index
-     * won't be in mLayerStack. This is because it can be replayed, but can't have any more drawing
-     * ops added to it.
-    */
-    std::vector<size_t> mLayerStack;
-
-    CanvasState mCanvasState;
-
-    // contains ResolvedOps and Batches
-    LinearAllocator mAllocator;
-};
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_OP_REORDERER_H
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 92b758d..6c2e244 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
+#include <GpuMemoryTracker.h>
 #include "OpenGLRenderer.h"
 
+#include "Canvas.h"
 #include "DeferredDisplayList.h"
 #include "GammaFontRenderer.h"
 #include "Glop.h"
@@ -38,7 +40,6 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <SkCanvas.h>
 #include <SkColor.h>
 #include <SkPaintDefaults.h>
 #include <SkPathOps.h>
@@ -194,12 +195,11 @@
     }
 
     if (!suppressErrorChecks()) {
-#if DEBUG_OPENGL
-        GLUtils::dumpGLErrors();
-#endif
+        GL_CHECKPOINT(MODERATE);
 
 #if DEBUG_MEMORY_USAGE
         mCaches.dumpMemoryUsage();
+        GPUMemoryTracker::dump();
 #else
         if (Properties::debugLevel & kDebugMemory) {
             mCaches.dumpMemoryUsage();
@@ -472,7 +472,7 @@
 int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
         const SkPaint* paint, int flags, const SkPath* convexMask) {
     // force matrix/clip isolation for layer
-    flags |= SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag;
+    flags |= SaveFlags::MatrixClip;
 
     const int count = mState.saveSnapshot(flags);
 
@@ -531,7 +531,7 @@
         const SkPaint* paint, int flags) {
     const int count = mState.saveSnapshot(flags);
 
-    if (!mState.currentlyIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) {
+    if (!mState.currentlyIgnored() && (flags & SaveFlags::ClipToLayer)) {
         // initialize the snapshot as though it almost represents an FBO layer so deferred draw
         // operations will be able to store and restore the current clip and transform info, and
         // quick rejection will be correct (for display lists)
@@ -558,7 +558,7 @@
  * and the frame buffer still receive every drawing command. For instance, if a
  * layer is created and a shape intersecting the bounds of the layers and the
  * framebuffer is draw, the shape will be drawn on both (unless the layer was
- * created with the SkCanvas::kClipToLayer_SaveFlag flag.)
+ * created with the SaveFlags::ClipToLayer flag.)
  *
  * A way to implement layers is to create an FBO for each layer, backed by an RGBA
  * texture. Unfortunately, this is inefficient as it requires every primitive to
@@ -608,7 +608,7 @@
     LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top);
     LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
 
-    const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag;
+    const bool fboLayer = flags & SaveFlags::ClipToLayer;
 
     // Window coordinates of the layer
     Rect clip;
@@ -890,7 +890,7 @@
     if (CC_UNLIKELY(layer->region.isEmpty())) return; // nothing to draw
 
     if (layer->getConvexMask()) {
-        save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
+        save(SaveFlags::MatrixClip);
 
         // clip to the area of the layer the mask can be larger
         clipRect(rect.left, rect.top, rect.right, rect.bottom, SkRegion::kIntersect_Op);
@@ -1497,7 +1497,7 @@
             .setMeshTexturedUnitQuad(texture->uvMapper)
             .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
             .setTransform(*currentSnapshot(),  TransformFlags::None)
-            .setModelViewMapUnitToRectSnap(Rect(texture->width, texture->height))
+            .setModelViewMapUnitToRectSnap(Rect(texture->width(), texture->height()))
             .build();
     renderGlop(glop);
 }
@@ -1601,10 +1601,10 @@
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
-    Rect uv(std::max(0.0f, src.left / texture->width),
-            std::max(0.0f, src.top / texture->height),
-            std::min(1.0f, src.right / texture->width),
-            std::min(1.0f, src.bottom / texture->height));
+    Rect uv(std::max(0.0f, src.left / texture->width()),
+            std::max(0.0f, src.top / texture->height()),
+            std::min(1.0f, src.right / texture->width()),
+            std::min(1.0f, src.bottom / texture->height()));
 
     const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType)
             ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
@@ -1630,6 +1630,7 @@
 
     Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
     if (!texture) return;
+    const AutoTexture autoCleanup(texture);
 
     // 9 patches are built for stretching - always filter
     int textureFillFlags = TextureFillFlags::ForceFilter;
@@ -1977,7 +1978,7 @@
             .setMeshTexturedUnitQuad(nullptr)
             .setFillShadowTexturePaint(*texture, textShadow.color, *paint, currentSnapshot()->alpha)
             .setTransform(*currentSnapshot(),  TransformFlags::None)
-            .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width, sy + texture->height))
+            .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width(), sy + texture->height()))
             .build();
     renderGlop(glop);
 }
@@ -2232,7 +2233,7 @@
     if (layer->isTextureLayer()) {
         transform = &layer->getTransform();
         if (!transform->isIdentity()) {
-            save(SkCanvas::kMatrix_SaveFlag);
+            save(SaveFlags::Matrix);
             concatMatrix(*transform);
         }
     }
@@ -2316,7 +2317,7 @@
 
 void OpenGLRenderer::drawPathTexture(PathTexture* texture, float x, float y,
         const SkPaint* paint) {
-    if (quickRejectSetupScissor(x, y, x + texture->width, y + texture->height)) {
+    if (quickRejectSetupScissor(x, y, x + texture->width(), y + texture->height())) {
         return;
     }
 
@@ -2326,7 +2327,7 @@
             .setMeshTexturedUnitQuad(nullptr)
             .setFillPathTexturePaint(*texture, *paint, currentSnapshot()->alpha)
             .setTransform(*currentSnapshot(),  TransformFlags::None)
-            .setModelViewMapUnitToRect(Rect(x, y, x + texture->width, y + texture->height))
+            .setModelViewMapUnitToRect(Rect(x, y, x + texture->width(), y + texture->height()))
             .build();
     renderGlop(glop);
 }
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index 06ea55a..bfabc1d 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -185,7 +185,7 @@
 
 void PathCache::removeTexture(PathTexture* texture) {
     if (texture) {
-        const uint32_t size = texture->width * texture->height;
+        const uint32_t size = texture->width() * texture->height();
 
         // If there is a pending task we must wait for it to return
         // before attempting our cleanup
@@ -209,9 +209,7 @@
             ALOGD("Shape deleted, size = %d", size);
         }
 
-        if (texture->id) {
-            Caches::getInstance().textureState().deleteTexture(texture->id);
-        }
+        texture->deleteTexture();
         delete texture;
     }
 }
@@ -248,8 +246,7 @@
     drawPath(path, paint, bitmap, left, top, offset, width, height);
 
     PathTexture* texture = new PathTexture(Caches::getInstance(),
-            left, top, offset, width, height,
-            path->getGenerationID());
+            left, top, offset, path->getGenerationID());
     generateTexture(entry, &bitmap, texture);
 
     return texture;
@@ -262,7 +259,7 @@
     // Note here that we upload to a texture even if it's bigger than mMaxSize.
     // Such an entry in mCache will only be temporary, since it will be evicted
     // immediately on trim, or on any other Path entering the cache.
-    uint32_t size = texture->width * texture->height;
+    uint32_t size = texture->width() * texture->height();
     mSize += size;
     PATH_LOGD("PathCache::get/create: name, size, mSize = %d, %d, %d",
             texture->id, size, mSize);
@@ -280,24 +277,8 @@
 
 void PathCache::generateTexture(SkBitmap& bitmap, Texture* texture) {
     ATRACE_NAME("Upload Path Texture");
-    SkAutoLockPixels alp(bitmap);
-    if (!bitmap.readyToDraw()) {
-        ALOGE("Cannot generate texture from bitmap");
-        return;
-    }
-
-    glGenTextures(1, &texture->id);
-
-    Caches::getInstance().textureState().bindTexture(texture->id);
-    // Textures are Alpha8
-    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-
-    texture->blend = true;
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0,
-            GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.getPixels());
-
+    texture->upload(bitmap);
     texture->setFilter(GL_LINEAR);
-    texture->setWrap(GL_CLAMP_TO_EDGE);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -320,16 +301,12 @@
     texture->left = left;
     texture->top = top;
     texture->offset = offset;
-    texture->width = width;
-    texture->height = height;
 
     if (width <= mMaxTextureSize && height <= mMaxTextureSize) {
         SkBitmap* bitmap = new SkBitmap();
         drawPath(&t->path, &t->paint, *bitmap, left, top, offset, width, height);
         t->setResult(bitmap);
     } else {
-        texture->width = 0;
-        texture->height = 0;
         t->setResult(nullptr);
     }
 }
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index 302e9f8..18f380f 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -61,13 +61,11 @@
  */
 struct PathTexture: public Texture {
     PathTexture(Caches& caches, float left, float top,
-            float offset, int width, int height, int generation)
+            float offset, int generation)
             : Texture(caches)
             , left(left)
             , top(top)
             , offset(offset) {
-        this->width = width;
-        this->height = height;
         this->generation = generation;
     }
     PathTexture(Caches& caches, int generation)
diff --git a/libs/hwui/PathParser.h b/libs/hwui/PathParser.h
index 4c87b18..c4bbb74 100644
--- a/libs/hwui/PathParser.h
+++ b/libs/hwui/PathParser.h
@@ -17,7 +17,7 @@
 #ifndef ANDROID_HWUI_PATHPARSER_H
 #define ANDROID_HWUI_PATHPARSER_H
 
-#include "VectorDrawablePath.h"
+#include "VectorDrawable.h"
 #include "utils/VectorDrawableUtils.h"
 
 #include <jni.h>
diff --git a/libs/hwui/PixelBuffer.cpp b/libs/hwui/PixelBuffer.cpp
index 9624726..6df994c 100644
--- a/libs/hwui/PixelBuffer.cpp
+++ b/libs/hwui/PixelBuffer.cpp
@@ -20,6 +20,7 @@
 #include "Extensions.h"
 #include "Properties.h"
 #include "renderstate/RenderState.h"
+#include "utils/GLUtils.h"
 
 #include <utils/Log.h>
 
@@ -112,14 +113,10 @@
     if (mAccessMode == kAccessMode_None) {
         mCaches.pixelBufferState().bind(mBuffer);
         mMappedPointer = (uint8_t*) glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode);
-#if DEBUG_OPENGL
-        if (!mMappedPointer) {
-            GLenum status = GL_NO_ERROR;
-            while ((status = glGetError()) != GL_NO_ERROR) {
-                ALOGE("Could not map GPU pixel buffer: 0x%x", status);
-            }
+        if (CC_UNLIKELY(!mMappedPointer)) {
+            GLUtils::dumpGLErrors();
+            LOG_ALWAYS_FATAL("Failed to map PBO");
         }
-#endif
         mAccessMode = mode;
     }
 
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 0669596..083aeb7 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -53,6 +53,8 @@
 ProfileType Properties::sProfileType = ProfileType::None;
 bool Properties::sDisableProfileBars = false;
 
+bool Properties::waitForGpuCompletion = false;
+
 static int property_get_int(const char* key, int defaultValue) {
     char buf[PROPERTY_VALUE_MAX] = {'\0',};
 
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 1dde7e0..88f1dbc 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -285,6 +285,9 @@
 
     static ProfileType getProfileType();
 
+    // Should be used only by test apps
+    static bool waitForGpuCompletion;
+
 private:
     static ProfileType sProfileType;
     static bool sDisableProfileBars;
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index b58b774..30d5c29 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -33,66 +33,116 @@
 namespace android {
 namespace uirenderer {
 
+struct ClipBase;
 class OffscreenBuffer;
 class RenderNode;
 struct Vertex;
 
 /**
- * On of the provided macros is executed for each op type in order. The first will be used for ops
- * that cannot merge, and the second for those that can.
+ * Authoritative op list, used for generating the op ID enum, ID based LUTS, and
+ * the functions to which they dispatch. Parameter macros are executed for each op,
+ * in order, based on the op's type.
  *
- * This serves as the authoritative list of ops, used for generating ID enum, and ID based LUTs.
+ * There are 4 types of op, which defines dispatch/LUT capability:
+ *
+ *              | DisplayList |   Render    |    Merge    |
+ * -------------|-------------|-------------|-------------|
+ * PRE RENDER   |     Yes     |             |             |
+ * RENDER ONLY  |             |     Yes     |             |
+ * UNMERGEABLE  |     Yes     |     Yes     |             |
+ * MERGEABLE    |     Yes     |     Yes     |     Yes     |
+ *
+ * PRE RENDER - These ops are recorded into DisplayLists, but can't be directly rendered. This
+ *      may be because they need to be transformed into other op types (e.g. CirclePropsOp),
+ *      be traversed to access multiple renderable ops within (e.g. RenderNodeOp), or because they
+ *      modify renderbuffer lifecycle, instead of directly rendering content (the various LayerOps).
+ *
+ * RENDER ONLY - These ops cannot be recorded into DisplayLists, and are instead implicitly
+ *      constructed from other commands/RenderNode properties. They cannot be merged.
+ *
+ * UNMERGEABLE - These ops can be recorded into DisplayLists and rendered directly, but do not
+ *      support merged rendering.
+ *
+ * MERGEABLE - These ops can be recorded into DisplayLists and rendered individually, or merged
+ *      under certain circumstances.
  */
-#define MAP_OPS_BASED_ON_MERGEABILITY(U_OP_FN, M_OP_FN) \
-        U_OP_FN(ArcOp) \
-        M_OP_FN(BitmapOp) \
-        U_OP_FN(BitmapMeshOp) \
-        U_OP_FN(BitmapRectOp) \
-        U_OP_FN(CirclePropsOp) \
-        U_OP_FN(FunctorOp) \
-        U_OP_FN(LinesOp) \
-        U_OP_FN(OvalOp) \
-        M_OP_FN(PatchOp) \
-        U_OP_FN(PathOp) \
-        U_OP_FN(PointsOp) \
-        U_OP_FN(RectOp) \
-        U_OP_FN(RenderNodeOp) \
-        U_OP_FN(RoundRectOp) \
-        U_OP_FN(RoundRectPropsOp) \
-        U_OP_FN(ShadowOp) \
-        U_OP_FN(SimpleRectsOp) \
-        M_OP_FN(TextOp) \
-        U_OP_FN(BeginLayerOp) \
-        U_OP_FN(EndLayerOp) \
-        U_OP_FN(LayerOp)
+#define MAP_OPS_BASED_ON_TYPE(PRE_RENDER_OP_FN, RENDER_ONLY_OP_FN, UNMERGEABLE_OP_FN, MERGEABLE_OP_FN) \
+        PRE_RENDER_OP_FN(RenderNodeOp) \
+        PRE_RENDER_OP_FN(CirclePropsOp) \
+        PRE_RENDER_OP_FN(RoundRectPropsOp) \
+        PRE_RENDER_OP_FN(BeginLayerOp) \
+        PRE_RENDER_OP_FN(EndLayerOp) \
+        PRE_RENDER_OP_FN(BeginUnclippedLayerOp) \
+        PRE_RENDER_OP_FN(EndUnclippedLayerOp) \
+        \
+        RENDER_ONLY_OP_FN(ShadowOp) \
+        RENDER_ONLY_OP_FN(LayerOp) \
+        RENDER_ONLY_OP_FN(CopyToLayerOp) \
+        RENDER_ONLY_OP_FN(CopyFromLayerOp) \
+        \
+        UNMERGEABLE_OP_FN(ArcOp) \
+        UNMERGEABLE_OP_FN(BitmapMeshOp) \
+        UNMERGEABLE_OP_FN(BitmapRectOp) \
+        UNMERGEABLE_OP_FN(FunctorOp) \
+        UNMERGEABLE_OP_FN(LinesOp) \
+        UNMERGEABLE_OP_FN(OvalOp) \
+        UNMERGEABLE_OP_FN(PathOp) \
+        UNMERGEABLE_OP_FN(PointsOp) \
+        UNMERGEABLE_OP_FN(RectOp) \
+        UNMERGEABLE_OP_FN(RoundRectOp) \
+        UNMERGEABLE_OP_FN(SimpleRectsOp) \
+        UNMERGEABLE_OP_FN(TextOnPathOp) \
+        UNMERGEABLE_OP_FN(TextureLayerOp) \
+        \
+        MERGEABLE_OP_FN(BitmapOp) \
+        MERGEABLE_OP_FN(PatchOp) \
+        MERGEABLE_OP_FN(TextOp)
 
 /**
- * The provided macro is executed for each op type in order. This is used in cases where
- * merge-ability of ops doesn't matter.
+ * LUT generators, which will insert nullptr for unsupported ops
  */
-#define MAP_OPS(OP_FN) \
-        MAP_OPS_BASED_ON_MERGEABILITY(OP_FN, OP_FN)
+#define NULLPTR_OP_FN(Type) nullptr,
 
+#define BUILD_DEFERRABLE_OP_LUT(OP_FN) \
+        { MAP_OPS_BASED_ON_TYPE(OP_FN, NULLPTR_OP_FN, OP_FN, OP_FN) }
+
+#define BUILD_MERGEABLE_OP_LUT(OP_FN) \
+        { MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, NULLPTR_OP_FN, NULLPTR_OP_FN, OP_FN) }
+
+#define BUILD_RENDERABLE_OP_LUT(OP_FN) \
+        { MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, OP_FN, OP_FN, OP_FN) }
+
+/**
+ * Op mapping functions, which skip unsupported ops.
+ *
+ * Note: Do not use for LUTS, since these do not preserve ID order.
+ */
 #define NULL_OP_FN(Type)
 
-#define MAP_MERGED_OPS(OP_FN) \
-        MAP_OPS_BASED_ON_MERGEABILITY(NULL_OP_FN, OP_FN)
+#define MAP_DEFERRABLE_OPS(OP_FN) \
+        MAP_OPS_BASED_ON_TYPE(OP_FN, NULL_OP_FN, OP_FN, OP_FN)
+
+#define MAP_MERGEABLE_OPS(OP_FN) \
+        MAP_OPS_BASED_ON_TYPE(NULL_OP_FN, NULL_OP_FN, NULL_OP_FN, OP_FN)
+
+#define MAP_RENDERABLE_OPS(OP_FN) \
+        MAP_OPS_BASED_ON_TYPE(NULL_OP_FN, OP_FN, OP_FN, OP_FN)
 
 // Generate OpId enum
 #define IDENTITY_FN(Type) Type,
 namespace RecordedOpId {
     enum {
-        MAP_OPS(IDENTITY_FN)
+        MAP_OPS_BASED_ON_TYPE(IDENTITY_FN, IDENTITY_FN, IDENTITY_FN, IDENTITY_FN)
         Count,
     };
 }
-static_assert(RecordedOpId::ArcOp == 0,
+static_assert(RecordedOpId::RenderNodeOp == 0,
         "First index must be zero for LUTs to work");
 
-#define BASE_PARAMS const Rect& unmappedBounds, const Matrix4& localMatrix, const Rect& localClipRect, const SkPaint* paint
-#define BASE_PARAMS_PAINTLESS const Rect& unmappedBounds, const Matrix4& localMatrix, const Rect& localClipRect
-#define SUPER(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClipRect, paint)
-#define SUPER_PAINTLESS(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClipRect, nullptr)
+#define BASE_PARAMS const Rect& unmappedBounds, const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint
+#define BASE_PARAMS_PAINTLESS const Rect& unmappedBounds, const Matrix4& localMatrix, const ClipBase* localClip
+#define SUPER(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClip, paint)
+#define SUPER_PAINTLESS(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClip, nullptr)
 
 struct RecordedOp {
     /* ID from RecordedOpId - generally used for jumping into function tables */
@@ -104,8 +154,8 @@
     /* transform in recording space (vs DisplayList origin) */
     const Matrix4 localMatrix;
 
-    /* clip in recording space */
-    const Rect localClipRect;
+    /* clip in recording space - nullptr if not clipped */
+    const ClipBase* localClip;
 
     /* optional paint, stored in base object to simplify merging logic */
     const SkPaint* paint;
@@ -114,7 +164,7 @@
             : opId(opId)
             , unmappedBounds(unmappedBounds)
             , localMatrix(localMatrix)
-            , localClipRect(localClipRect)
+            , localClip(localClip)
             , paint(paint) {}
 };
 
@@ -185,9 +235,9 @@
 };
 
 struct CirclePropsOp : RecordedOp {
-    CirclePropsOp(const Matrix4& localMatrix, const Rect& localClipRect, const SkPaint* paint,
+    CirclePropsOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint,
             float* x, float* y, float* radius)
-            : RecordedOp(RecordedOpId::CirclePropsOp, Rect(), localMatrix, localClipRect, paint)
+            : RecordedOp(RecordedOpId::CirclePropsOp, Rect(), localMatrix, localClip, paint)
             , x(x)
             , y(y)
             , radius(radius) {}
@@ -257,9 +307,9 @@
 };
 
 struct RoundRectPropsOp : RecordedOp {
-    RoundRectPropsOp(const Matrix4& localMatrix, const Rect& localClipRect, const SkPaint* paint,
+    RoundRectPropsOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint,
             float* left, float* top, float* right, float* bottom, float *rx, float *ry)
-            : RecordedOp(RecordedOpId::RoundRectPropsOp, Rect(), localMatrix, localClipRect, paint)
+            : RecordedOp(RecordedOpId::RoundRectPropsOp, Rect(), localMatrix, localClip, paint)
             , left(left)
             , top(top)
             , right(right)
@@ -284,12 +334,13 @@
  */
 struct ShadowOp : RecordedOp {
     ShadowOp(const RenderNodeOp& casterOp, float casterAlpha, const SkPath* casterPath,
-            const Rect& clipRect, const Vector3& lightCenter)
-            : RecordedOp(RecordedOpId::ShadowOp, Rect(), Matrix4::identity(), clipRect, nullptr)
+            const Rect& localClipRect, const Vector3& lightCenter)
+            : RecordedOp(RecordedOpId::ShadowOp, Rect(), Matrix4::identity(), nullptr, nullptr)
             , shadowMatrixXY(casterOp.localMatrix)
             , shadowMatrixZ(casterOp.localMatrix)
             , casterAlpha(casterAlpha)
             , casterPath(casterPath)
+            , localClipRect(localClipRect)
             , lightCenter(lightCenter) {
         const RenderNode& node = *casterOp.renderNode;
         node.applyViewPropertyTransforms(shadowMatrixXY, false);
@@ -299,6 +350,7 @@
     Matrix4 shadowMatrixZ;
     const float casterAlpha;
     const SkPath* casterPath;
+    const Rect localClipRect;
     const Vector3 lightCenter;
 };
 
@@ -327,11 +379,34 @@
     const float y;
 };
 
+struct TextOnPathOp : RecordedOp {
+    TextOnPathOp(BASE_PARAMS, const glyph_t* glyphs, int glyphCount,
+            const SkPath* path, float hOffset, float vOffset)
+            : SUPER(TextOnPathOp)
+            , glyphs(glyphs)
+            , glyphCount(glyphCount)
+            , path(path)
+            , hOffset(hOffset)
+            , vOffset(vOffset) {}
+    const glyph_t* glyphs;
+    const int glyphCount;
+
+    const SkPath* path;
+    const float hOffset;
+    const float vOffset;
+};
+
+struct TextureLayerOp : RecordedOp {
+    TextureLayerOp(BASE_PARAMS_PAINTLESS, Layer* layer)
+            : SUPER_PAINTLESS(TextureLayerOp)
+            , layer(layer) {}
+    Layer* layer;
+};
+
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // Layers
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 
-
 /**
  * Stateful operation! denotes the creation of an off-screen layer,
  * and that commands following will render into it.
@@ -349,7 +424,47 @@
  */
 struct EndLayerOp : RecordedOp {
     EndLayerOp()
-            : RecordedOp(RecordedOpId::EndLayerOp, Rect(), Matrix4::identity(), Rect(), nullptr) {}
+            : RecordedOp(RecordedOpId::EndLayerOp, Rect(), Matrix4::identity(), nullptr, nullptr) {}
+};
+
+struct BeginUnclippedLayerOp : RecordedOp {
+    BeginUnclippedLayerOp(BASE_PARAMS)
+            : SUPER(BeginUnclippedLayerOp) {}
+};
+
+struct EndUnclippedLayerOp : RecordedOp {
+    EndUnclippedLayerOp()
+            : RecordedOp(RecordedOpId::EndUnclippedLayerOp, Rect(), Matrix4::identity(), nullptr, nullptr) {}
+};
+
+struct CopyToLayerOp : RecordedOp {
+    CopyToLayerOp(const RecordedOp& op, OffscreenBuffer** layerHandle)
+            : RecordedOp(RecordedOpId::CopyToLayerOp,
+                    op.unmappedBounds,
+                    op.localMatrix,
+                    nullptr, // clip intentionally ignored
+                    op.paint)
+            , layerHandle(layerHandle) {}
+
+    // Records a handle to the Layer object, since the Layer itself won't be
+    // constructed until after this operation is constructed.
+    OffscreenBuffer** layerHandle;
+};
+
+
+// draw the parameter layer underneath
+struct CopyFromLayerOp : RecordedOp {
+    CopyFromLayerOp(const RecordedOp& op, OffscreenBuffer** layerHandle)
+            : RecordedOp(RecordedOpId::CopyFromLayerOp,
+                    op.unmappedBounds,
+                    op.localMatrix,
+                    nullptr, // clip intentionally ignored
+                    op.paint)
+            , layerHandle(layerHandle) {}
+
+    // Records a handle to the Layer object, since the Layer itself won't be
+    // constructed until after this operation is constructed.
+    OffscreenBuffer** layerHandle;
 };
 
 /**
@@ -363,18 +478,18 @@
     LayerOp(BASE_PARAMS, OffscreenBuffer** layerHandle)
             : SUPER_PAINTLESS(LayerOp)
             , layerHandle(layerHandle)
-            , alpha(paint->getAlpha() / 255.0f)
+            , alpha(paint ? paint->getAlpha() / 255.0f : 1.0f)
             , mode(PaintUtils::getXfermodeDirect(paint))
-            , colorFilter(paint->getColorFilter())
+            , colorFilter(paint ? paint->getColorFilter() : nullptr)
             , destroy(true) {}
 
     LayerOp(RenderNode& node)
-        : RecordedOp(RecordedOpId::LayerOp, Rect(node.getWidth(), node.getHeight()), Matrix4::identity(), Rect(node.getWidth(), node.getHeight()), nullptr)
-        , layerHandle(node.getLayerHandle())
-        , alpha(node.properties().layerProperties().alpha() / 255.0f)
-        , mode(node.properties().layerProperties().xferMode())
-        , colorFilter(node.properties().layerProperties().colorFilter())
-        , destroy(false) {}
+            : 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) {}
 
     // Records a handle to the Layer object, since the Layer itself won't be
     // constructed until after this operation is constructed.
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 7f035e5..328e291 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -16,6 +16,7 @@
 
 #include "RecordingCanvas.h"
 
+#include "DeferredLayerUpdater.h"
 #include "RecordedOp.h"
 #include "RenderNode.h"
 
@@ -38,14 +39,14 @@
             "prepareDirty called a second time during a recording!");
     mDisplayList = new DisplayList();
 
-    mState.initializeSaveStack(width, height, 0, 0, width, height, Vector3());
+    mState.initializeRecordingSaveStack(width, height);
 
     mDeferredBarrierType = DeferredBarrierType::InOrder;
     mState.setDirtyClip(false);
-    mRestoreSaveCount = -1;
 }
 
 DisplayList* RecordingCanvas::finishRecording() {
+    restoreToCount(1);
     mPaintMap.clear();
     mRegionMap.clear();
     mPathMap.clear();
@@ -82,6 +83,8 @@
 void RecordingCanvas::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
     if (removed.flags & Snapshot::kFlagIsFboLayer) {
         addOp(new (alloc()) EndLayerOp());
+    } else if (removed.flags & Snapshot::kFlagIsLayer) {
+        addOp(new (alloc()) EndUnclippedLayerOp());
     }
 }
 
@@ -89,33 +92,23 @@
 // android/graphics/Canvas state operations
 // ----------------------------------------------------------------------------
 // Save (layer)
-int RecordingCanvas::save(SkCanvas::SaveFlags flags) {
+int RecordingCanvas::save(SaveFlags::Flags flags) {
     return mState.save((int) flags);
 }
 
 void RecordingCanvas::RecordingCanvas::restore() {
-    if (mRestoreSaveCount < 0) {
-        restoreToCount(getSaveCount() - 1);
-        return;
-    }
-
-    mRestoreSaveCount--;
     mState.restore();
 }
 
 void RecordingCanvas::restoreToCount(int saveCount) {
-    mRestoreSaveCount = saveCount;
     mState.restoreToCount(saveCount);
 }
 
-int RecordingCanvas::saveLayer(float left, float top, float right, float bottom, const SkPaint* paint,
-        SkCanvas::SaveFlags flags) {
-    if (!(flags & SkCanvas::kClipToLayer_SaveFlag)) {
-        LOG_ALWAYS_FATAL("unclipped layers not supported");
-    }
+int RecordingCanvas::saveLayer(float left, float top, float right, float bottom,
+        const SkPaint* paint, SaveFlags::Flags flags) {
     // force matrix/clip isolation for layer
-    flags |= SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag;
-
+    flags |= SaveFlags::MatrixClip;
+    bool clippedLayer = flags & SaveFlags::ClipToLayer;
 
     const Snapshot& previous = *mState.currentSnapshot();
 
@@ -123,51 +116,70 @@
     // operations will be able to store and restore the current clip and transform info, and
     // quick rejection will be correct (for display lists)
 
-    const Rect untransformedBounds(left, top, right, bottom);
+    const Rect unmappedBounds(left, top, right, bottom);
 
     // determine clipped bounds relative to previous viewport.
-    Rect visibleBounds = untransformedBounds;
+    Rect visibleBounds = unmappedBounds;
     previous.transform->mapRect(visibleBounds);
 
+    if (CC_UNLIKELY(!clippedLayer
+            && previous.transform->rectToRect()
+            && visibleBounds.contains(previous.getRenderTargetClip()))) {
+        // unlikely case where an unclipped savelayer is recorded with a clip it can use,
+        // as none of its unaffected/unclipped area is visible
+        clippedLayer = true;
+        flags |= SaveFlags::ClipToLayer;
+    }
 
     visibleBounds.doIntersect(previous.getRenderTargetClip());
     visibleBounds.snapToPixelBoundaries();
-
-    Rect previousViewport(0, 0, previous.getViewportWidth(), previous.getViewportHeight());
-    visibleBounds.doIntersect(previousViewport);
+    visibleBounds.doIntersect(Rect(previous.getViewportWidth(), previous.getViewportHeight()));
 
     // Map visible bounds back to layer space, and intersect with parameter bounds
     Rect layerBounds = visibleBounds;
     Matrix4 inverse;
     inverse.loadInverse(*previous.transform);
     inverse.mapRect(layerBounds);
-    layerBounds.doIntersect(untransformedBounds);
+    layerBounds.doIntersect(unmappedBounds);
 
     int saveValue = mState.save((int) flags);
     Snapshot& snapshot = *mState.writableSnapshot();
 
-    // layerBounds is now original bounds, but with clipped to clip
-    // and viewport to ensure it's minimal size.
-    if (layerBounds.isEmpty() || untransformedBounds.isEmpty()) {
+    // layerBounds is in original bounds space, but clipped by current recording clip
+    if (layerBounds.isEmpty() || unmappedBounds.isEmpty()) {
         // Don't bother recording layer, since it's been rejected
-        snapshot.resetClip(0, 0, 0, 0);
+        if (CC_LIKELY(clippedLayer)) {
+            snapshot.resetClip(0, 0, 0, 0);
+        }
         return saveValue;
     }
 
-    snapshot.flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
-    snapshot.initializeViewport(untransformedBounds.getWidth(), untransformedBounds.getHeight());
-    snapshot.transform->loadTranslate(-untransformedBounds.left, -untransformedBounds.top, 0.0f);
+    if (CC_LIKELY(clippedLayer)) {
+        auto previousClip = getRecordedClip(); // note: done before new snapshot's clip has changed
 
-    Rect clip = layerBounds;
-    clip.translate(-untransformedBounds.left, -untransformedBounds.top);
-    snapshot.resetClip(clip.left, clip.top, clip.right, clip.bottom);
-    snapshot.roundRectClipState = nullptr;
+        snapshot.flags |= Snapshot::kFlagIsLayer | Snapshot::kFlagIsFboLayer;
+        snapshot.initializeViewport(unmappedBounds.getWidth(), unmappedBounds.getHeight());
+        snapshot.transform->loadTranslate(-unmappedBounds.left, -unmappedBounds.top, 0.0f);
 
-    addOp(new (alloc()) BeginLayerOp(
-            Rect(left, top, right, bottom),
-            *previous.transform, // transform to *draw* with
-            previous.getRenderTargetClip(), // clip to *draw* with
-            refPaint(paint)));
+        Rect clip = layerBounds;
+        clip.translate(-unmappedBounds.left, -unmappedBounds.top);
+        snapshot.resetClip(clip.left, clip.top, clip.right, clip.bottom);
+        snapshot.roundRectClipState = nullptr;
+
+        addOp(new (alloc()) BeginLayerOp(
+                unmappedBounds,
+                *previous.transform, // transform to *draw* with
+                previousClip, // clip to *draw* with
+                refPaint(paint)));
+    } else {
+        snapshot.flags |= Snapshot::kFlagIsLayer;
+
+        addOp(new (alloc()) BeginUnclippedLayerOp(
+                unmappedBounds,
+                *mState.currentSnapshot()->transform,
+                getRecordedClip(),
+                refPaint(paint)));
+    }
 
     return saveValue;
 }
@@ -228,11 +240,10 @@
 }
 
 void RecordingCanvas::drawPaint(const SkPaint& paint) {
-    // TODO: more efficient recording?
     addOp(new (alloc()) RectOp(
-            mState.getRenderTargetClipBounds(),
+            mState.getRenderTargetClipBounds(), // OK, since we've not passed transform
             Matrix4::identity(),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(&paint)));
 }
 
@@ -252,7 +263,7 @@
     addOp(new (alloc()) PointsOp(
             calcBoundsOfPoints(points, floatCount),
             *mState.currentSnapshot()->transform,
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(&paint), refBuffer<float>(points, floatCount), floatCount));
 }
 
@@ -263,7 +274,7 @@
     addOp(new (alloc()) LinesOp(
             calcBoundsOfPoints(points, floatCount),
             *mState.currentSnapshot()->transform,
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(&paint), refBuffer<float>(points, floatCount), floatCount));
 }
 
@@ -271,7 +282,7 @@
     addOp(new (alloc()) RectOp(
             Rect(left, top, right, bottom),
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(&paint)));
 }
 
@@ -304,7 +315,7 @@
     addOp(new (alloc()) SimpleRectsOp(
             Rect(left, top, right, bottom),
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(paint), rectData, vertexCount));
 }
 
@@ -338,7 +349,7 @@
     addOp(new (alloc()) RoundRectOp(
             Rect(left, top, right, bottom),
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(&paint), rx, ry));
 }
 
@@ -357,7 +368,7 @@
     refBitmapsInShader(paint->value.getShader());
     addOp(new (alloc()) RoundRectPropsOp(
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             &paint->value,
             &left->value, &top->value, &right->value, &bottom->value,
             &rx->value, &ry->value));
@@ -379,7 +390,7 @@
     refBitmapsInShader(paint->value.getShader());
     addOp(new (alloc()) CirclePropsOp(
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             &paint->value,
             &x->value, &y->value, &radius->value));
 }
@@ -389,7 +400,7 @@
     addOp(new (alloc()) OvalOp(
             Rect(left, top, right, bottom),
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(&paint)));
 }
 
@@ -398,7 +409,7 @@
     addOp(new (alloc()) ArcOp(
             Rect(left, top, right, bottom),
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(&paint),
             startAngle, sweepAngle, useCenter));
 }
@@ -407,13 +418,13 @@
     addOp(new (alloc()) PathOp(
             Rect(path.getBounds()),
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(&paint), refPath(&path)));
 }
 
 // Bitmap-based
 void RecordingCanvas::drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint) {
-    save(SkCanvas::kMatrix_SaveFlag);
+    save(SaveFlags::Matrix);
     translate(left, top);
     drawBitmap(&bitmap, paint);
     restore();
@@ -434,7 +445,7 @@
         drawBitmap(bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom,
                    dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint);
     } else {
-        save(SkCanvas::kMatrix_SaveFlag);
+        save(SaveFlags::Matrix);
         concat(matrix);
         drawBitmap(&bitmap, paint);
         restore();
@@ -450,7 +461,7 @@
             && (srcBottom - srcTop == dstBottom - dstTop)
             && (srcRight - srcLeft == dstRight - dstLeft)) {
         // transform simple rect to rect drawing case into position bitmap ops, since they merge
-        save(SkCanvas::kMatrix_SaveFlag);
+        save(SaveFlags::Matrix);
         translate(dstLeft, dstTop);
         drawBitmap(&bitmap, paint);
         restore();
@@ -458,7 +469,7 @@
         addOp(new (alloc()) BitmapRectOp(
                 Rect(dstLeft, dstTop, dstRight, dstBottom),
                 *(mState.currentSnapshot()->transform),
-                mState.getRenderTargetClipBounds(),
+                getRecordedClip(),
                 refPaint(paint), refBitmap(bitmap),
                 Rect(srcLeft, srcTop, srcRight, srcBottom)));
     }
@@ -470,7 +481,7 @@
     addOp(new (alloc()) BitmapMeshOp(
             calcBoundsOfPoints(vertices, vertexCount * 2),
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(paint), refBitmap(bitmap), meshWidth, meshHeight,
             refBuffer<float>(vertices, vertexCount * 2), // 2 floats per vertex
             refBuffer<int>(colors, vertexCount))); // 1 color per vertex
@@ -482,7 +493,7 @@
     addOp(new (alloc()) PatchOp(
             Rect(dstLeft, dstTop, dstRight, dstBottom),
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(paint), refBitmap(bitmap), refPatch(&patch)));
 }
 
@@ -498,21 +509,27 @@
     addOp(new (alloc()) TextOp(
             Rect(boundsLeft, boundsTop, boundsRight, boundsBottom),
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(&paint), glyphs, positions, glyphCount, x, y));
     drawTextDecorations(x, y, totalAdvance, paint);
 }
 
-void RecordingCanvas::drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
+void RecordingCanvas::drawTextOnPath(const uint16_t* glyphs, int glyphCount, const SkPath& path,
             float hOffset, float vOffset, const SkPaint& paint) {
-    LOG_ALWAYS_FATAL("TODO!");
+    if (!glyphs || glyphCount <= 0 || PaintUtils::paintWillNotDrawText(paint)) return;
+    glyphs = refBuffer<glyph_t>(glyphs, glyphCount);
+    addOp(new (alloc()) TextOnPathOp(
+            mState.getLocalClipBounds(), // TODO: explicitly define bounds
+            *(mState.currentSnapshot()->transform),
+            getRecordedClip(),
+            refPaint(&paint), glyphs, glyphCount, refPath(&path), hOffset, vOffset));
 }
 
 void RecordingCanvas::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
     addOp(new (alloc()) BitmapOp(
             Rect(bitmap->width(), bitmap->height()),
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(paint), refBitmap(*bitmap)));
 }
 
@@ -521,7 +538,7 @@
     RenderNodeOp* op = new (alloc()) RenderNodeOp(
             Rect(stagingProps.getWidth(), stagingProps.getHeight()),
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             renderNode);
     int opIndex = addOp(op);
     int childIndex = mDisplayList->addChild(op);
@@ -536,12 +553,27 @@
     }
 }
 
+void RecordingCanvas::drawLayer(DeferredLayerUpdater* layerHandle) {
+    // 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());
+
+    addOp(new (alloc()) TextureLayerOp(
+            Rect(layer->getWidth(), layer->getHeight()),
+            totalTransform,
+            getRecordedClip(),
+            layer));
+}
+
 void RecordingCanvas::callDrawGLFunction(Functor* functor) {
     mDisplayList->functors.push_back(functor);
     addOp(new (alloc()) FunctorOp(
-            mState.getRenderTargetClipBounds(), // TODO: explicitly define bounds
+            mState.getLocalClipBounds(), // TODO: explicitly define bounds
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             functor));
 }
 
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 49bdba8..786f96e 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -36,10 +36,11 @@
 namespace android {
 namespace uirenderer {
 
-class OpReceiver;
+struct ClipBase;
+class DeferredLayerUpdater;
 struct RecordedOp;
 
-class RecordingCanvas: public Canvas, public CanvasStateClient {
+class ANDROID_API RecordingCanvas: public Canvas, public CanvasStateClient {
     enum class DeferredBarrierType {
         None,
         InOrder,
@@ -59,6 +60,8 @@
         mDeferredBarrierType = enableReorder
                 ? DeferredBarrierType::OutOfOrder : DeferredBarrierType::InOrder;
     }
+
+    void drawLayer(DeferredLayerUpdater* layerHandle);
     void drawRenderNode(RenderNode* renderNode);
 
     // TODO: rename for consistency
@@ -105,14 +108,14 @@
 // ----------------------------------------------------------------------------
     // Save (layer)
     virtual int getSaveCount() const override { return mState.getSaveCount(); }
-    virtual int save(SkCanvas::SaveFlags flags) override;
+    virtual int save(SaveFlags::Flags flags) override;
     virtual void restore() override;
     virtual void restoreToCount(int saveCount) override;
 
     virtual int saveLayer(float left, float top, float right, float bottom, const SkPaint* paint,
-        SkCanvas::SaveFlags flags) override;
+        SaveFlags::Flags flags) override;
     virtual int saveLayerAlpha(float left, float top, float right, float bottom,
-            int alpha, SkCanvas::SaveFlags flags) override {
+            int alpha, SaveFlags::Flags flags) override {
         SkPaint paint;
         paint.setAlpha(alpha);
         return saveLayer(left, top, right, bottom, &paint, flags);
@@ -189,14 +192,17 @@
             const SkPaint* paint) override;
 
     // Text
-    virtual void drawText(const uint16_t* glyphs, const float* positions, int count,
+    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 count, const SkPath& path,
+    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; }
 
 private:
+    const ClipBase* getRecordedClip() {
+        return mState.writableSnapshot()->mutateClipArea().serializeClip(alloc());
+    }
 
     void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint);
     void drawSimpleRects(const float* rects, int vertexCount, const SkPaint* paint);
@@ -308,7 +314,6 @@
     DisplayList* mDisplayList = nullptr;
     bool mHighContrastText = false;
     SkAutoTUnref<SkDrawFilter> mDrawFilter;
-    int mRestoreSaveCount = -1;
 }; // class RecordingCanvas
 
 }; // namespace uirenderer
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index ae690fd..d4588ed 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -33,8 +33,6 @@
 #include "protos/hwui.pb.h"
 #include "protos/ProtoHelpers.h"
 
-#include <SkCanvas.h>
-
 #include <algorithm>
 #include <sstream>
 #include <string>
@@ -105,8 +103,7 @@
             (isRenderable() ? "" : ", empty"),
             (properties().getProjectBackwards() ? ", projected" : ""),
             (mLayer != nullptr ? ", on HW Layer" : ""));
-    ALOGD("%*s%s %d", level * 2, "", "Save",
-            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+    ALOGD("%*s%s %d", level * 2, "", "Save", SaveFlags::MatrixClip);
 
     properties().debugOutputProperties(level);
 
@@ -574,7 +571,7 @@
                     layerBounds.left, layerBounds.top,
                     layerBounds.right, layerBounds.bottom,
                     (int) (properties().getAlpha() * 255),
-                    SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kClipToLayer_SaveFlag);
+                    SaveFlags::HasAlphaLayer | SaveFlags::ClipToLayer);
             handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
         }
 
@@ -875,7 +872,7 @@
 
     // Apply the base transform of the parent of the 3d children. This isolates
     // 3d children of the current chunk from transformations made in previous chunks.
-    int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag);
+    int rootRestoreTo = renderer.save(SaveFlags::Matrix);
     renderer.setGlobalMatrix(initialTransform);
 
     /**
@@ -919,7 +916,7 @@
 
         // only the actual child DL draw needs to be in save/restore,
         // since it modifies the renderer's matrix
-        int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag);
+        int restoreTo = renderer.save(SaveFlags::Matrix);
 
         DrawRenderNodeOp* childOp = zTranslatedNodes[drawIndex].value;
 
@@ -941,7 +938,7 @@
     int restoreTo = renderer.getSaveCount();
 
     LinearAllocator& alloc = handler.allocator();
-    handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
+    handler(new (alloc) SaveOp(SaveFlags::MatrixClip),
             PROPERTY_SAVECOUNT, properties().getClipToBounds());
 
     // Transform renderer to match background we're projecting onto
@@ -966,7 +963,7 @@
         renderNodeOp_t* childOp = mProjectedNodes[i];
 
         // matrix save, concat, and restore can be done safely without allocating operations
-        int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag);
+        int restoreTo = renderer.save(SaveFlags::Matrix);
         renderer.concatMatrix(childOp->transformFromCompositingAncestor);
         childOp->skipInOrderDraw = false; // this is horrible, I'm so sorry everyone
         handler(childOp, renderer.getSaveCount() - 1, properties().getClipToBounds());
@@ -1027,11 +1024,11 @@
 
     LinearAllocator& alloc = handler.allocator();
     int restoreTo = renderer.getSaveCount();
-    handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
+    handler(new (alloc) SaveOp(SaveFlags::MatrixClip),
             PROPERTY_SAVECOUNT, properties().getClipToBounds());
 
     DISPLAY_LIST_LOGD("%*sSave %d %d", (handler.level() + 1) * 2, "",
-            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
+            SaveFlags::MatrixClip, restoreTo);
 
     if (useViewProperties) {
         setViewProperties<T>(renderer, handler);
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index b6f50b1..8e4a3df 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -47,11 +47,11 @@
 class DisplayListCanvas;
 class DisplayListOp;
 class OpenGLRenderer;
-class OpReorderer;
 class Rect;
 class SkiaShader;
 
 #if HWUI_NEW_OPS
+class FrameBuilder;
 class OffscreenBuffer;
 struct RenderNodeOp;
 typedef OffscreenBuffer layer_t;
@@ -87,7 +87,7 @@
  */
 class RenderNode : public VirtualLightRefBase {
 friend class TestUtils; // allow TestUtils to access syncDisplayList / syncProperties
-friend class OpReorderer;
+friend class FrameBuilder;
 public:
     enum DirtyPropertyMask {
         GENERIC         = 1 << 1,
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index ce1bd6a..b848af4 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -18,12 +18,12 @@
 
 #include <utils/Trace.h>
 
-#include <SkCanvas.h>
 #include <SkColorFilter.h>
 #include <SkMatrix.h>
 #include <SkPath.h>
 #include <SkPathOps.h>
 
+#include "Canvas.h"
 #include "Matrix.h"
 #include "OpenGLRenderer.h"
 #include "utils/MathUtils.h"
@@ -144,7 +144,7 @@
                     (int)layerBounds.left, (int)layerBounds.top,
                     (int)layerBounds.right, (int)layerBounds.bottom,
                     (int)(mPrimitiveFields.mAlpha * 255),
-                    SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kClipToLayer_SaveFlag);
+                    SaveFlags::HasAlphaLayer | SaveFlags::ClipToLayer);
         }
 
 
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 96c1a7c..20e7c71 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -24,6 +24,7 @@
 #include <SkGraphics.h>
 #include <SkShader.h>
 #include <SkTArray.h>
+#include <SkTLazy.h>
 #include <SkTemplates.h>
 
 #include <memory>
@@ -63,14 +64,14 @@
     virtual bool isHighContrastText() override { return mHighContrastText; }
 
     virtual int getSaveCount() const override;
-    virtual int save(SkCanvas::SaveFlags flags) override;
+    virtual int save(SaveFlags::Flags flags) override;
     virtual void restore() override;
     virtual void restoreToCount(int saveCount) override;
 
     virtual int saveLayer(float left, float top, float right, float bottom,
-                const SkPaint* paint, SkCanvas::SaveFlags flags) override;
+                const SkPaint* paint, SaveFlags::Flags flags) override;
     virtual int saveLayerAlpha(float left, float top, float right, float bottom,
-            int alpha, SkCanvas::SaveFlags flags) override;
+            int alpha, SaveFlags::Flags flags) override;
 
     virtual void getMatrix(SkMatrix* outMatrix) const override;
     virtual void setMatrix(const SkMatrix& matrix) override;
@@ -138,13 +139,13 @@
 
 private:
     struct SaveRec {
-        int                 saveCount;
-        SkCanvas::SaveFlags saveFlags;
+        int              saveCount;
+        SaveFlags::Flags saveFlags;
     };
 
     bool mHighContrastText = false;
 
-    void recordPartialSave(SkCanvas::SaveFlags flags);
+    void recordPartialSave(SaveFlags::Flags flags);
     void saveClipsForFrame(SkTArray<SkClipStack::Element>& clips, int frameSaveCount);
     void applyClips(const SkTArray<SkClipStack::Element>& clips);
 
@@ -231,7 +232,7 @@
     return mCanvas->getSaveCount();
 }
 
-int SkiaCanvas::save(SkCanvas::SaveFlags flags) {
+int SkiaCanvas::save(SaveFlags::Flags flags) {
     int count = mCanvas->save();
     recordPartialSave(flags);
     return count;
@@ -254,8 +255,8 @@
         return;
     }
 
-    bool preserveMatrix = !(rec->saveFlags & SkCanvas::kMatrix_SaveFlag);
-    bool preserveClip   = !(rec->saveFlags & SkCanvas::kClip_SaveFlag);
+    bool preserveMatrix = !(rec->saveFlags & SaveFlags::Matrix);
+    bool preserveClip   = !(rec->saveFlags & SaveFlags::Clip);
 
     SkMatrix savedMatrix;
     if (preserveMatrix) {
@@ -291,34 +292,53 @@
     }
 }
 
+static inline SkCanvas::SaveLayerFlags layerFlags(SaveFlags::Flags flags) {
+    SkCanvas::SaveLayerFlags layerFlags = 0;
+
+    if (!(flags & SaveFlags::HasAlphaLayer)) {
+        layerFlags |= SkCanvas::kIsOpaque_SaveLayerFlag;
+    }
+
+    if (!(flags & SaveFlags::ClipToLayer)) {
+        layerFlags |= SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag;
+    }
+
+    return layerFlags;
+}
+
 int SkiaCanvas::saveLayer(float left, float top, float right, float bottom,
-            const SkPaint* paint, SkCanvas::SaveFlags flags) {
-    SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
-    int count = mCanvas->saveLayer(&bounds, paint, flags | SkCanvas::kMatrixClip_SaveFlag);
+            const SkPaint* paint, SaveFlags::Flags flags) {
+    const SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
+    const SkCanvas::SaveLayerRec rec(&bounds, paint, layerFlags(flags));
+
+    int count = mCanvas->saveLayer(rec);
     recordPartialSave(flags);
     return count;
 }
 
 int SkiaCanvas::saveLayerAlpha(float left, float top, float right, float bottom,
-        int alpha, SkCanvas::SaveFlags flags) {
-    SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
-    int count = mCanvas->saveLayerAlpha(&bounds, alpha, flags | SkCanvas::kMatrixClip_SaveFlag);
-    recordPartialSave(flags);
-    return count;
+        int alpha, SaveFlags::Flags flags) {
+    SkTLazy<SkPaint> alphaPaint;
+    if (static_cast<unsigned>(alpha) < 0xFF) {
+        alphaPaint.init()->setAlpha(alpha);
+    }
+
+    return this->saveLayer(left, top, right, bottom, alphaPaint.getMaybeNull(),
+                           flags);
 }
 
 // ----------------------------------------------------------------------------
 // functions to emulate legacy SaveFlags (i.e. independent matrix/clip flags)
 // ----------------------------------------------------------------------------
 
-void SkiaCanvas::recordPartialSave(SkCanvas::SaveFlags flags) {
+void SkiaCanvas::recordPartialSave(SaveFlags::Flags flags) {
     // A partial save is a save operation which doesn't capture the full canvas state.
-    // (either kMatrix_SaveFlags or kClip_SaveFlag is missing).
+    // (either SaveFlags::Matrix or SaveFlags::Clip is missing).
 
     // Mask-out non canvas state bits.
-    flags = static_cast<SkCanvas::SaveFlags>(flags & SkCanvas::kMatrixClip_SaveFlag);
+    flags &= SaveFlags::MatrixClip;
 
-    if (SkCanvas::kMatrixClip_SaveFlag == flags) {
+    if (flags == SaveFlags::MatrixClip) {
         // not a partial save.
         return;
     }
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
index 2d5f70f..6530d4ed8 100644
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -138,15 +138,6 @@
     SkDEBUGFAIL("SkiaCanvasProxy::onDrawBitmapNine is not yet supported");
 }
 
-void SkiaCanvasProxy::onDrawSprite(const SkBitmap& bitmap, int left, int top,
-        const SkPaint* paint) {
-    // TODO: if bitmap is a subset, do we need to add pixelRefOrigin to src?
-    mCanvas->save(SkCanvas::kMatrixClip_SaveFlag);
-    mCanvas->setMatrix(SkMatrix::I());
-    mCanvas->drawBitmap(bitmap, left, top, paint);
-    mCanvas->restore();
-}
-
 void SkiaCanvasProxy::onDrawVertices(VertexMode mode, int vertexCount, const SkPoint vertices[],
         const SkPoint texs[], const SkColor colors[], SkXfermode*, const uint16_t indices[],
         int indexCount, const SkPaint& paint) {
@@ -168,18 +159,32 @@
 }
 
 void SkiaCanvasProxy::willSave() {
-    mCanvas->save(SkCanvas::kMatrixClip_SaveFlag);
+    mCanvas->save(android::SaveFlags::MatrixClip);
 }
 
-SkCanvas::SaveLayerStrategy SkiaCanvasProxy::willSaveLayer(const SkRect* rectPtr,
-        const SkPaint* paint, SaveFlags flags) {
+static inline SaveFlags::Flags saveFlags(SkCanvas::SaveLayerFlags layerFlags) {
+    SaveFlags::Flags saveFlags = 0;
+
+    if (!(layerFlags & SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag)) {
+        saveFlags |= SaveFlags::ClipToLayer;
+    }
+
+    if (!(layerFlags & SkCanvas::kIsOpaque_SaveLayerFlag)) {
+        saveFlags |= SaveFlags::HasAlphaLayer;
+    }
+
+    return saveFlags;
+}
+
+SkCanvas::SaveLayerStrategy SkiaCanvasProxy::getSaveLayerStrategy(const SaveLayerRec& saveLayerRec) {
     SkRect rect;
-    if (rectPtr) {
-        rect = *rectPtr;
-    } else if(!mCanvas->getClipBounds(&rect)) {
+    if (saveLayerRec.fBounds) {
+        rect = *saveLayerRec.fBounds;
+    } else if (!mCanvas->getClipBounds(&rect)) {
         rect = SkRect::MakeEmpty();
     }
-    mCanvas->saveLayer(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, paint, flags);
+    mCanvas->saveLayer(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, saveLayerRec.fPaint,
+                       saveFlags(saveLayerRec.fSaveLayerFlags));
     return SkCanvas::kNoLayer_SaveLayerStrategy;
 }
 
diff --git a/libs/hwui/SkiaCanvasProxy.h b/libs/hwui/SkiaCanvasProxy.h
index 2fe4327..e342d19 100644
--- a/libs/hwui/SkiaCanvasProxy.h
+++ b/libs/hwui/SkiaCanvasProxy.h
@@ -47,7 +47,7 @@
     virtual SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override;
 
     virtual void willSave() override;
-    virtual SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) override;
+    virtual SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override;
     virtual void willRestore() override;
 
     virtual void didConcat(const SkMatrix&) override;
@@ -66,8 +66,6 @@
                                   const SkPaint* paint, SrcRectConstraint) override;
     virtual void onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
                                   const SkRect& dst, const SkPaint*) override;
-    virtual void onDrawSprite(const SkBitmap&, int left, int top,
-                              const SkPaint*) override;
     virtual void onDrawVertices(VertexMode, int vertexCount, const SkPoint vertices[],
                                 const SkPoint texs[], const SkColor colors[], SkXfermode*,
                                 const uint16_t indices[], int indexCount,
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 83652c6..6f4a683 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -57,7 +57,7 @@
 }
 
 static inline void bindTexture(Caches* caches, Texture* texture, GLenum wrapS, GLenum wrapT) {
-    caches->textureState().bindTexture(texture->id);
+    caches->textureState().bindTexture(texture->id());
     texture->setWrapST(wrapS, wrapT);
 }
 
@@ -219,8 +219,8 @@
 
     outData->bitmapSampler = (*textureUnit)++;
 
-    const float width = outData->bitmapTexture->width;
-    const float height = outData->bitmapTexture->height;
+    const float width = outData->bitmapTexture->width();
+    const float height = outData->bitmapTexture->height();
 
     description->hasBitmap = true;
     if (!caches.extensions().hasNPot()
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index 2f535bb..27fea1f 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -16,7 +16,7 @@
 
 #include "Snapshot.h"
 
-#include <SkCanvas.h>
+#include "Canvas.h"
 
 namespace android {
 namespace uirenderer {
@@ -57,14 +57,14 @@
         , mClipArea(nullptr)
         , mViewportData(s->mViewportData)
         , mRelativeLightCenter(s->mRelativeLightCenter) {
-    if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
+    if (saveFlags & SaveFlags::Matrix) {
         mTransformRoot = *s->transform;
         transform = &mTransformRoot;
     } else {
         transform = s->transform;
     }
 
-    if (saveFlags & SkCanvas::kClip_SaveFlag) {
+    if (saveFlags & SaveFlags::Clip) {
         mClipAreaRoot = s->getClipArea();
         mClipArea = &mClipAreaRoot;
     } else {
@@ -88,9 +88,9 @@
     mClipArea->clipRegion(region, op);
 }
 
-void Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
+void Snapshot::clip(const Rect& localClip, SkRegion::Op op) {
     flags |= Snapshot::kFlagClipSet;
-    mClipArea->clipRectWithTransform(left, top, right, bottom, transform, op);
+    mClipArea->clipRectWithTransform(localClip, transform, op);
 }
 
 void Snapshot::clipPath(const SkPath& path, SkRegion::Op op) {
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 4789b33..dbaa905 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -116,7 +116,7 @@
          * Indicates that this snapshot or an ancestor snapshot is
          * an FBO layer.
          */
-        kFlagFboTarget = 0x8,
+        kFlagFboTarget = 0x8, // TODO: remove for HWUI_NEW_OPS
     };
 
     /**
@@ -124,7 +124,7 @@
      * the specified operation. The specified rectangle is transformed
      * by this snapshot's trasnformation.
      */
-    void clip(float left, float top, float right, float bottom, SkRegion::Op op);
+    void clip(const Rect& localClip, SkRegion::Op op);
 
     /**
      * Modifies the current clip with the new clip rectangle and
@@ -167,6 +167,7 @@
     const SkRegion& getClipRegion() const { return mClipArea->getClipRegion(); }
     bool clipIsSimple() const { return mClipArea->isSimple(); }
     const ClipArea& getClipArea() const { return *mClipArea; }
+    ClipArea& mutateClipArea() { return *mClipArea; }
 
     /**
      * Resets the clip to the specified rect.
diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp
index 51f1652..62a20fc 100644
--- a/libs/hwui/TextDropShadowCache.cpp
+++ b/libs/hwui/TextDropShadowCache.cpp
@@ -187,13 +187,10 @@
         texture = new ShadowTexture(caches);
         texture->left = shadow.penX;
         texture->top = shadow.penY;
-        texture->width = shadow.width;
-        texture->height = shadow.height;
         texture->generation = 0;
         texture->blend = true;
 
         const uint32_t size = shadow.width * shadow.height;
-        texture->bitmapSize = size;
 
         // Don't even try to cache a bitmap that's bigger than the cache
         if (size < mMaxSize) {
@@ -202,15 +199,9 @@
             }
         }
 
-        glGenTextures(1, &texture->id);
-
-        caches.textureState().bindTexture(texture->id);
         // Textures are Alpha8
-        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-
-        glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0,
+        texture->upload(GL_ALPHA, shadow.width, shadow.height,
                 GL_ALPHA, GL_UNSIGNED_BYTE, shadow.image);
-
         texture->setFilter(GL_LINEAR);
         texture->setWrap(GL_CLAMP_TO_EDGE);
 
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index 5195b45..c09b6dd 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -14,25 +14,39 @@
  * limitations under the License.
  */
 
-#include <utils/Log.h>
-
 #include "Caches.h"
 #include "Texture.h"
+#include "utils/GLUtils.h"
+#include "utils/TraceUtils.h"
+
+#include <utils/Log.h>
+
+#include <SkCanvas.h>
 
 namespace android {
 namespace uirenderer {
 
+static int bytesPerPixel(GLint glFormat) {
+    switch (glFormat) {
+    case GL_ALPHA:
+        return 1;
+    case GL_RGB:
+        return 3;
+    case GL_RGBA:
+    default:
+        return 4;
+    }
+}
+
 void Texture::setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture, bool force,
         GLenum renderTarget) {
 
-    if (mFirstWrap || force || wrapS != mWrapS || wrapT != mWrapT) {
-        mFirstWrap = false;
-
+    if (force || wrapS != mWrapS || wrapT != mWrapT) {
         mWrapS = wrapS;
         mWrapT = wrapT;
 
         if (bindTexture) {
-            mCaches.textureState().bindTexture(renderTarget, id);
+            mCaches.textureState().bindTexture(renderTarget, mId);
         }
 
         glTexParameteri(renderTarget, GL_TEXTURE_WRAP_S, wrapS);
@@ -43,14 +57,12 @@
 void Texture::setFilterMinMag(GLenum min, GLenum mag, bool bindTexture, bool force,
         GLenum renderTarget) {
 
-    if (mFirstFilter || force || min != mMinFilter || mag != mMagFilter) {
-        mFirstFilter = false;
-
+    if (force || min != mMinFilter || mag != mMagFilter) {
         mMinFilter = min;
         mMagFilter = mag;
 
         if (bindTexture) {
-            mCaches.textureState().bindTexture(renderTarget, id);
+            mCaches.textureState().bindTexture(renderTarget, mId);
         }
 
         if (mipMap && min == GL_LINEAR) min = GL_LINEAR_MIPMAP_LINEAR;
@@ -60,8 +72,197 @@
     }
 }
 
-void Texture::deleteTexture() const {
-    mCaches.textureState().deleteTexture(id);
+void Texture::deleteTexture() {
+    mCaches.textureState().deleteTexture(mId);
+    mId = 0;
+}
+
+bool Texture::updateSize(uint32_t width, uint32_t height, GLint format) {
+    if (mWidth == width && mHeight == height && mFormat == format) {
+        return false;
+    }
+    mWidth = width;
+    mHeight = height;
+    mFormat = format;
+    notifySizeChanged(mWidth * mHeight * bytesPerPixel(mFormat));
+    return true;
+}
+
+void Texture::resetCachedParams() {
+    mWrapS = GL_REPEAT;
+    mWrapT = GL_REPEAT;
+    mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
+    mMagFilter = GL_LINEAR;
+}
+
+void Texture::upload(GLint internalformat, uint32_t width, uint32_t height,
+        GLenum format, GLenum type, const void* pixels) {
+    GL_CHECKPOINT(MODERATE);
+    bool needsAlloc = updateSize(width, height, internalformat);
+    if (!mId) {
+        glGenTextures(1, &mId);
+        needsAlloc = true;
+        resetCachedParams();
+    }
+    mCaches.textureState().bindTexture(GL_TEXTURE_2D, mId);
+    if (needsAlloc) {
+        glTexImage2D(GL_TEXTURE_2D, 0, mFormat, mWidth, mHeight, 0,
+                format, type, pixels);
+    } else if (pixels) {
+        glTexSubImage2D(GL_TEXTURE_2D, 0, mFormat, mWidth, mHeight, 0,
+                format, type, pixels);
+    }
+    GL_CHECKPOINT(MODERATE);
+}
+
+static void uploadToTexture(bool resize, GLenum format, GLenum type, GLsizei stride, GLsizei bpp,
+        GLsizei width, GLsizei height, const GLvoid * data) {
+
+    const bool useStride = stride != width
+            && Caches::getInstance().extensions().hasUnpackRowLength();
+    if ((stride == width) || useStride) {
+        if (useStride) {
+            glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
+        }
+
+        if (resize) {
+            glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data);
+        } else {
+            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data);
+        }
+
+        if (useStride) {
+            glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+        }
+    } else {
+        //  With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer
+        //  if the stride doesn't match the width
+
+        GLvoid * temp = (GLvoid *) malloc(width * height * bpp);
+        if (!temp) return;
+
+        uint8_t * pDst = (uint8_t *)temp;
+        uint8_t * pSrc = (uint8_t *)data;
+        for (GLsizei i = 0; i < height; i++) {
+            memcpy(pDst, pSrc, width * bpp);
+            pDst += width * bpp;
+            pSrc += stride * bpp;
+        }
+
+        if (resize) {
+            glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, temp);
+        } else {
+            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, temp);
+        }
+
+        free(temp);
+    }
+}
+
+static void uploadSkBitmapToTexture(const SkBitmap& bitmap,
+        bool resize, GLenum format, GLenum type) {
+    uploadToTexture(resize, format, type, bitmap.rowBytesAsPixels(), bitmap.bytesPerPixel(),
+            bitmap.width(), bitmap.height(), bitmap.getPixels());
+}
+
+static void colorTypeToGlFormatAndType(SkColorType colorType,
+        GLint* outFormat, GLint* outType) {
+    switch (colorType) {
+    case kAlpha_8_SkColorType:
+        *outFormat = GL_ALPHA;
+        *outType = GL_UNSIGNED_BYTE;
+        break;
+    case kRGB_565_SkColorType:
+        *outFormat = GL_RGB;
+        *outType = GL_UNSIGNED_SHORT_5_6_5;
+        break;
+    // ARGB_4444 and Index_8 are both upconverted to RGBA_8888
+    case kARGB_4444_SkColorType:
+    case kIndex_8_SkColorType:
+    case kN32_SkColorType:
+        *outFormat = GL_RGBA;
+        *outType = GL_UNSIGNED_BYTE;
+        break;
+    case kGray_8_SkColorType:
+        *outFormat = GL_LUMINANCE;
+        *outType = GL_UNSIGNED_BYTE;
+        break;
+    default:
+        LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", colorType);
+        break;
+    }
+}
+
+void Texture::upload(const SkBitmap& bitmap) {
+    SkAutoLockPixels alp(bitmap);
+
+    if (!bitmap.readyToDraw()) {
+        ALOGE("Cannot generate texture from bitmap");
+        return;
+    }
+
+    ATRACE_FORMAT("Upload %ux%u Texture", bitmap.width(), bitmap.height());
+
+    // We could also enable mipmapping if both bitmap dimensions are powers
+    // of 2 but we'd have to deal with size changes. Let's keep this simple
+    const bool canMipMap = mCaches.extensions().hasNPot();
+
+    // If the texture had mipmap enabled but not anymore,
+    // force a glTexImage2D to discard the mipmap levels
+    bool needsAlloc = canMipMap && mipMap && !bitmap.hasHardwareMipMap();
+    bool setDefaultParams = false;
+
+    if (!mId) {
+        glGenTextures(1, &mId);
+        needsAlloc = true;
+        setDefaultParams = true;
+    }
+
+    GLint format, type;
+    colorTypeToGlFormatAndType(bitmap.colorType(), &format, &type);
+
+    if (updateSize(bitmap.width(), bitmap.height(), format)) {
+        needsAlloc = true;
+    }
+
+    blend = !bitmap.isOpaque();
+    mCaches.textureState().bindTexture(mId);
+
+    if (CC_UNLIKELY(bitmap.colorType() == kARGB_4444_SkColorType
+            || bitmap.colorType() == kIndex_8_SkColorType)) {
+        SkBitmap rgbaBitmap;
+        rgbaBitmap.allocPixels(SkImageInfo::MakeN32(mWidth, mHeight,
+                bitmap.alphaType()));
+        rgbaBitmap.eraseColor(0);
+
+        SkCanvas canvas(rgbaBitmap);
+        canvas.drawBitmap(bitmap, 0.0f, 0.0f, nullptr);
+
+        uploadSkBitmapToTexture(rgbaBitmap, needsAlloc, format, type);
+    } else {
+        uploadSkBitmapToTexture(bitmap, needsAlloc, format, type);
+    }
+
+    if (canMipMap) {
+        mipMap = bitmap.hasHardwareMipMap();
+        if (mipMap) {
+            glGenerateMipmap(GL_TEXTURE_2D);
+        }
+    }
+
+    if (setDefaultParams) {
+        setFilter(GL_NEAREST);
+        setWrap(GL_CLAMP_TO_EDGE);
+    }
+}
+
+void Texture::wrap(GLuint id, uint32_t width, uint32_t height, GLint format) {
+    mId = id;
+    mWidth = width;
+    mHeight = height;
+    mFormat = format;
+    // We're wrapping an existing texture, so don't double count this memory
+    notifySizeChanged(0);
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index 1c544b9..9749f73 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -17,20 +17,27 @@
 #ifndef ANDROID_HWUI_TEXTURE_H
 #define ANDROID_HWUI_TEXTURE_H
 
+#include "GpuMemoryTracker.h"
+
 #include <GLES2/gl2.h>
+#include <SkBitmap.h>
 
 namespace android {
 namespace uirenderer {
 
 class Caches;
 class UvMapper;
+class Layer;
 
 /**
  * Represents an OpenGL texture.
  */
-class Texture {
+class Texture : public GpuMemoryTracker {
 public:
-    Texture(Caches& caches) : mCaches(caches) { }
+    Texture(Caches& caches)
+        : GpuMemoryTracker(GpuObjectType::Texture)
+        , mCaches(caches)
+    { }
 
     virtual ~Texture() { }
 
@@ -53,12 +60,55 @@
     /**
      * Convenience method to call glDeleteTextures() on this texture's id.
      */
-    void deleteTexture() const;
+    void deleteTexture();
 
     /**
-     * Name of the texture.
+     * Sets the width, height, and format of the texture along with allocating
+     * the texture ID. Does nothing if the width, height, and format are already
+     * the requested values.
+     *
+     * The image data is undefined after calling this.
      */
-    GLuint id = 0;
+    void resize(uint32_t width, uint32_t height, GLint format) {
+        upload(format, width, height, format, GL_UNSIGNED_BYTE, nullptr);
+    }
+
+    /**
+     * Updates this Texture with the contents of the provided SkBitmap,
+     * also setting the appropriate width, height, and format. It is not necessary
+     * to call resize() prior to this.
+     *
+     * Note this does not set the generation from the SkBitmap.
+     */
+    void upload(const SkBitmap& source);
+
+    /**
+     * Basically glTexImage2D/glTexSubImage2D.
+     */
+    void upload(GLint internalformat, uint32_t width, uint32_t height,
+            GLenum format, GLenum type, const void* pixels);
+
+    /**
+     * Wraps an existing texture.
+     */
+    void wrap(GLuint id, uint32_t width, uint32_t height, GLint format);
+
+    GLuint id() const {
+        return mId;
+    }
+
+    uint32_t width() const {
+        return mWidth;
+    }
+
+    uint32_t height() const {
+        return mHeight;
+    }
+
+    GLint format() const {
+        return mFormat;
+    }
+
     /**
      * Generation of the backing bitmap,
      */
@@ -68,14 +118,6 @@
      */
     bool blend = false;
     /**
-     * Width of the backing bitmap.
-     */
-    uint32_t width = 0;
-    /**
-     * Height of the backing bitmap.
-     */
-    uint32_t height = 0;
-    /**
      * Indicates whether this texture should be cleaned up after use.
      */
     bool cleanup = false;
@@ -100,27 +142,36 @@
     void* isInUse = nullptr;
 
 private:
-    /**
-     * Last wrap modes set on this texture.
-     */
-    GLenum mWrapS = GL_CLAMP_TO_EDGE;
-    GLenum mWrapT = GL_CLAMP_TO_EDGE;
+    // TODO: Temporarily grant private access to Layer, remove once
+    // Layer can be de-tangled from being a dual-purpose render target
+    // and external texture wrapper
+    friend class Layer;
 
-    /**
-     * Last filters set on this texture.
-     */
-    GLenum mMinFilter = GL_NEAREST;
-    GLenum mMagFilter = GL_NEAREST;
+    // Returns true if the size changed, false if it was the same
+    bool updateSize(uint32_t width, uint32_t height, GLint format);
+    void resetCachedParams();
 
-    bool mFirstFilter = true;
-    bool mFirstWrap = true;
+    GLuint mId = 0;
+    uint32_t mWidth = 0;
+    uint32_t mHeight = 0;
+    GLint mFormat = 0;
+
+    /* See GLES spec section 3.8.14
+     * "In the initial state, the value assigned to TEXTURE_MIN_FILTER is
+     * NEAREST_MIPMAP_LINEAR and the value for TEXTURE_MAG_FILTER is LINEAR.
+     * s, t, and r wrap modes are all set to REPEAT."
+     */
+    GLenum mWrapS = GL_REPEAT;
+    GLenum mWrapT = GL_REPEAT;
+    GLenum mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
+    GLenum mMagFilter = GL_LINEAR;
 
     Caches& mCaches;
 }; // struct Texture
 
 class AutoTexture {
 public:
-    AutoTexture(const Texture* texture)
+    AutoTexture(Texture* texture)
             : texture(texture) {}
     ~AutoTexture() {
         if (texture && texture->cleanup) {
@@ -129,7 +180,7 @@
         }
     }
 
-    const Texture *const texture;
+    Texture* const texture;
 }; // class AutoTexture
 
 }; // namespace uirenderer
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 21901cf..31bfa3a 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -166,7 +166,8 @@
         if (canCache) {
             texture = new Texture(Caches::getInstance());
             texture->bitmapSize = size;
-            Caches::getInstance().textureState().generateTexture(bitmap, texture, false);
+            texture->generation = bitmap->getGenerationID();
+            texture->upload(*bitmap);
 
             mSize += size;
             TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d",
@@ -179,7 +180,8 @@
     } else if (!texture->isInUse && bitmap->getGenerationID() != texture->generation) {
         // Texture was in the cache but is dirty, re-upload
         // TODO: Re-adjust the cache size if the bitmap's dimensions have changed
-        Caches::getInstance().textureState().generateTexture(bitmap, texture, true);
+        texture->upload(*bitmap);
+        texture->generation = bitmap->getGenerationID();
     }
 
     return texture;
@@ -204,7 +206,8 @@
         const uint32_t size = bitmap->rowBytes() * bitmap->height();
         texture = new Texture(Caches::getInstance());
         texture->bitmapSize = size;
-        Caches::getInstance().textureState().generateTexture(bitmap, texture, false);
+        texture->upload(*bitmap);
+        texture->generation = bitmap->getGenerationID();
         texture->cleanup = true;
     }
 
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index 191c8a8..463450c 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -25,6 +25,7 @@
 #include "Debug.h"
 
 #include <vector>
+#include <unordered_map>
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
new file mode 100644
index 0000000..1cf15ac
--- /dev/null
+++ b/libs/hwui/VectorDrawable.cpp
@@ -0,0 +1,518 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "VectorDrawable.h"
+
+#include "PathParser.h"
+#include "SkImageInfo.h"
+#include "SkShader.h"
+#include <utils/Log.h>
+#include "utils/Macros.h"
+#include "utils/VectorDrawableUtils.h"
+
+#include <math.h>
+#include <string.h>
+
+namespace android {
+namespace uirenderer {
+namespace VectorDrawable {
+
+const int Tree::MAX_CACHED_BITMAP_SIZE = 2048;
+
+void Path::draw(SkCanvas* outCanvas, const SkMatrix& groupStackedMatrix, float scaleX, float scaleY) {
+    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);
+
+    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;
+}
+
+void Path::dump() {
+    ALOGD("Path: %s has %zu points", mName.c_str(), mData.points.size());
+}
+
+float Path::getMatrixScale(const SkMatrix& 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.
+    SkVector skVectors[2];
+    skVectors[0].set(0, 1);
+    skVectors[1].set(1, 0);
+    groupStackedMatrix.mapVectors(skVectors, 2);
+    float scaleX = hypotf(skVectors[0].fX, skVectors[0].fY);
+    float scaleY = hypotf(skVectors[1].fX, skVectors[1].fY);
+    float crossProduct = skVectors[0].cross(skVectors[1]);
+    float maxScale = fmax(scaleX, scaleY);
+
+    float matrixScale = 0;
+    if (maxScale > 0) {
+        matrixScale = fabs(crossProduct) / maxScale;
+    }
+    return matrixScale;
+}
+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);
+}
+
+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);
+}
+
+const SkPath& Path::getUpdatedPath() {
+    if (mSkPathDirty) {
+        mSkPath.reset();
+        VectorDrawableUtils::verbsToPath(&mSkPath, mData);
+        mSkPathDirty = false;
+    }
+    return mSkPath;
+}
+
+void Path::setPath(const char* pathStr, size_t strLength) {
+    PathParser::ParseResult result;
+    mSkPathDirty = true;
+    PathParser::getPathDataFromString(&mData, &result, pathStr, strLength);
+}
+
+FullPath::FullPath(const FullPath& path) : Path(path) {
+    mStrokeWidth = path.mStrokeWidth;
+    mStrokeColor = path.mStrokeColor;
+    mStrokeAlpha = path.mStrokeAlpha;
+    mFillColor = path.mFillColor;
+    mFillAlpha = path.mFillAlpha;
+    mTrimPathStart = path.mTrimPathStart;
+    mTrimPathEnd = path.mTrimPathEnd;
+    mTrimPathOffset = path.mTrimPathOffset;
+    mStrokeMiterLimit = path.mStrokeMiterLimit;
+    mStrokeLineCap = path.mStrokeLineCap;
+    mStrokeLineJoin = path.mStrokeLineJoin;
+
+    SkRefCnt_SafeAssign(mStrokeGradient, path.mStrokeGradient);
+    SkRefCnt_SafeAssign(mFillGradient, path.mFillGradient);
+}
+
+const SkPath& FullPath::getUpdatedPath() {
+    if (!mSkPathDirty && !mTrimDirty) {
+        return mTrimmedSkPath;
+    }
+    Path::getUpdatedPath();
+    if (mTrimPathStart != 0.0f || mTrimPathEnd != 1.0f) {
+        applyTrim();
+        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) {
+    mStrokeWidth = strokeWidth;
+    mStrokeColor = strokeColor;
+    mStrokeAlpha = strokeAlpha;
+    mFillColor = fillColor;
+    mFillAlpha = fillAlpha;
+    mStrokeMiterLimit = strokeMiterLimit;
+    mStrokeLineCap = SkPaint::Cap(strokeLineCap);
+    mStrokeLineJoin = SkPaint::Join(strokeLineJoin);
+
+    // If any trim property changes, mark trim dirty and update the trim path
+    setTrimPathStart(trimPathStart);
+    setTrimPathEnd(trimPathEnd);
+    setTrimPathOffset(trimPathOffset);
+}
+
+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){
+    // Draw path's fill, if fill color or gradient is valid
+    bool needsFill = false;
+    if (mFillGradient != nullptr) {
+        mPaint.setColor(applyAlpha(SK_ColorBLACK, mFillAlpha));
+        SkShader* newShader = mFillGradient->newWithLocalMatrix(matrix);
+        mPaint.setShader(newShader);
+        needsFill = true;
+    } else if (mFillColor != SK_ColorTRANSPARENT) {
+        mPaint.setColor(applyAlpha(mFillColor, mFillAlpha));
+        needsFill = true;
+    }
+
+    if (needsFill) {
+        mPaint.setStyle(SkPaint::Style::kFill_Style);
+        mPaint.setAntiAlias(true);
+        outCanvas->drawPath(renderPath, mPaint);
+    }
+
+    // Draw path's stroke, if stroke color or gradient is valid
+    bool needsStroke = false;
+    if (mStrokeGradient != nullptr) {
+        mPaint.setColor(applyAlpha(SK_ColorBLACK, mStrokeAlpha));
+        SkShader* newShader = mStrokeGradient->newWithLocalMatrix(matrix);
+        mPaint.setShader(newShader);
+        needsStroke = true;
+    } else if (mStrokeColor != SK_ColorTRANSPARENT) {
+        mPaint.setColor(applyAlpha(mStrokeColor, mStrokeAlpha));
+        needsStroke = true;
+    }
+    if (needsStroke) {
+        mPaint.setStyle(SkPaint::Style::kStroke_Style);
+        mPaint.setAntiAlias(true);
+        mPaint.setStrokeJoin(mStrokeLineJoin);
+        mPaint.setStrokeCap(mStrokeLineCap);
+        mPaint.setStrokeMiter(mStrokeMiterLimit);
+        mPaint.setStrokeWidth(mStrokeWidth * strokeScale);
+        outCanvas->drawPath(renderPath, mPaint);
+    }
+}
+
+/**
+ * Applies trimming to the specified path.
+ */
+void FullPath::applyTrim() {
+    if (mTrimPathStart == 0.0f && mTrimPathEnd == 1.0f) {
+        // No trimming necessary.
+        return;
+    }
+    SkPathMeasure measure(mSkPath, false);
+    float len = SkScalarToFloat(measure.getLength());
+    float start = len * fmod((mTrimPathStart + mTrimPathOffset), 1.0f);
+    float end = len * fmod((mTrimPathEnd + mTrimPathOffset), 1.0f);
+
+    mTrimmedSkPath.reset();
+    if (start > end) {
+        measure.getSegment(start, len, &mTrimmedSkPath, true);
+        measure.getSegment(0, end, &mTrimmedSkPath, true);
+    } else {
+        measure.getSegment(start, end, &mTrimmedSkPath, true);
+    }
+    mTrimDirty = false;
+}
+
+inline int putData(int8_t* outBytes, int startIndex, float value) {
+    int size = sizeof(float);
+    memcpy(&outBytes[startIndex], &value, size);
+    return size;
+}
+
+inline int putData(int8_t* outBytes, int startIndex, int value) {
+    int size = sizeof(int);
+    memcpy(&outBytes[startIndex], &value, size);
+    return size;
+}
+
+struct FullPathProperties {
+    // TODO: Consider storing full path properties in this struct instead of the fields.
+    float strokeWidth;
+    SkColor strokeColor;
+    float strokeAlpha;
+    SkColor fillColor;
+    float fillAlpha;
+    float trimPathStart;
+    float trimPathEnd;
+    float trimPathOffset;
+    int32_t strokeLineCap;
+    int32_t strokeLineJoin;
+    float strokeMiterLimit;
+};
+
+REQUIRE_COMPATIBLE_LAYOUT(FullPathProperties);
+
+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(FullPathProperties);
+    if (length != propertyDataSize) {
+        LOG_ALWAYS_FATAL("Properties needs exactly %d bytes, a byte array of size %d is provided",
+                propertyDataSize, length);
+        return false;
+    }
+    // TODO: consider replacing the property fields with a FullPathProperties struct.
+    FullPathProperties properties;
+    properties.strokeWidth = mStrokeWidth;
+    properties.strokeColor = mStrokeColor;
+    properties.strokeAlpha = mStrokeAlpha;
+    properties.fillColor = mFillColor;
+    properties.fillAlpha = mFillAlpha;
+    properties.trimPathStart = mTrimPathStart;
+    properties.trimPathEnd = mTrimPathEnd;
+    properties.trimPathOffset = mTrimPathOffset;
+    properties.strokeLineCap = mStrokeLineCap;
+    properties.strokeLineJoin = mStrokeLineJoin;
+    properties.strokeMiterLimit = mStrokeMiterLimit;
+
+    memcpy(outProperties, &properties, length);
+    return true;
+}
+
+void ClipPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath,
+        float strokeScale, const SkMatrix& matrix){
+    outCanvas->clipPath(renderPath, SkRegion::kIntersect_Op);
+}
+
+Group::Group(const Group& group) : Node(group) {
+    mRotate = group.mRotate;
+    mPivotX = group.mPivotX;
+    mPivotY = group.mPivotY;
+    mScaleX = group.mScaleX;
+    mScaleY = group.mScaleY;
+    mTranslateX = group.mTranslateX;
+    mTranslateY = group.mTranslateY;
+}
+
+void Group::draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix, float scaleX,
+        float scaleY) {
+    // 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
+    // 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.
+    SkMatrix stackedMatrix;
+    getLocalMatrix(&stackedMatrix);
+    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 (Node* child : mChildren) {
+        child->draw(outCanvas, stackedMatrix, scaleX, scaleY);
+    }
+    // Restore the previous clip information.
+    outCanvas->restore();
+}
+
+void Group::dump() {
+    ALOGD("Group %s has %zu children: ", mName.c_str(), mChildren.size());
+    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::getLocalMatrix(SkMatrix* outMatrix) {
+    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(-mPivotX, -mPivotY);
+    outMatrix->postScale(mScaleX, mScaleY);
+    outMatrix->postRotate(mRotate, 0, 0);
+    outMatrix->postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY);
+}
+
+void Group::addChild(Node* child) {
+    mChildren.push_back(child);
+}
+
+bool Group::getProperties(float* outProperties, int length) {
+    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;
+    }
+    for (int i = 0; i < propertyCount; i++) {
+        Property currentProperty = static_cast<Property>(i);
+        switch (currentProperty) {
+        case Property::Rotate_Property:
+            outProperties[i] = mRotate;
+            break;
+        case Property::PivotX_Property:
+            outProperties[i] = mPivotX;
+            break;
+        case Property::PivotY_Property:
+            outProperties[i] = mPivotY;
+            break;
+        case Property::ScaleX_Property:
+            outProperties[i] = mScaleX;
+            break;
+        case Property::ScaleY_Property:
+            outProperties[i] = mScaleY;
+            break;
+        case Property::TranslateX_Property:
+            outProperties[i] = mTranslateX;
+            break;
+        case Property::TranslateY_Property:
+            outProperties[i] = mTranslateY;
+            break;
+        default:
+            LOG_ALWAYS_FATAL("Invalid input index: %d", i);
+            return false;
+        }
+    }
+    return true;
+}
+
+void Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter,
+        const SkRect& bounds, bool needsMirroring, bool canReuseCache) {
+    // The imageView can scale the canvas in different ways, in order to
+    // 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;
+    float canvasScaleX = 1.0f;
+    float canvasScaleY = 1.0f;
+    if (mCanvasMatrix.getSkewX() == 0 && mCanvasMatrix.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());
+    }
+    int scaledWidth = (int) (mBounds.width() * canvasScaleX);
+    int scaledHeight = (int) (mBounds.height() * canvasScaleY);
+    scaledWidth = std::min(Tree::MAX_CACHED_BITMAP_SIZE, scaledWidth);
+    scaledHeight = std::min(Tree::MAX_CACHED_BITMAP_SIZE, scaledHeight);
+
+    if (scaledWidth <= 0 || scaledHeight <= 0) {
+        return;
+    }
+
+    int saveCount = outCanvas->save(SaveFlags::MatrixClip);
+    outCanvas->translate(mBounds.fLeft, mBounds.fTop);
+
+    // Handle RTL mirroring.
+    if (needsMirroring) {
+        outCanvas->translate(mBounds.width(), 0);
+        outCanvas->scale(-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);
+    mBounds.offsetTo(0, 0);
+
+    createCachedBitmapIfNeeded(scaledWidth, scaledHeight);
+    if (!mAllowCaching) {
+        updateCachedBitmap(scaledWidth, scaledHeight);
+    } else {
+        if (!canReuseCache || mCacheDirty) {
+            updateCachedBitmap(scaledWidth, scaledHeight);
+        }
+    }
+    drawCachedBitmapWithRootAlpha(outCanvas, colorFilter, mBounds);
+
+    outCanvas->restoreToCount(saveCount);
+}
+
+void Tree::drawCachedBitmapWithRootAlpha(Canvas* outCanvas, SkColorFilter* filter,
+        const SkRect& originalBounds) {
+    SkPaint* paint;
+    if (mRootAlpha == 1.0f && filter == NULL) {
+        paint = NULL;
+    } else {
+        mPaint.setFilterQuality(kLow_SkFilterQuality);
+        mPaint.setAlpha(mRootAlpha * 255);
+        mPaint.setColorFilter(filter);
+        paint = &mPaint;
+    }
+    outCanvas->drawBitmap(mCachedBitmap, 0, 0, mCachedBitmap.width(), mCachedBitmap.height(),
+            originalBounds.fLeft, originalBounds.fTop, originalBounds.fRight,
+            originalBounds.fBottom, paint);
+}
+
+void Tree::updateCachedBitmap(int width, int height) {
+    mCachedBitmap.eraseColor(SK_ColorTRANSPARENT);
+    SkCanvas outCanvas(mCachedBitmap);
+    float scaleX = width / mViewportWidth;
+    float scaleY = height / mViewportHeight;
+    mRootNode->draw(&outCanvas, SkMatrix::I(), scaleX, scaleY);
+    mCacheDirty = false;
+}
+
+void Tree::createCachedBitmapIfNeeded(int width, int height) {
+    if (!canReuseBitmap(width, height)) {
+        SkImageInfo info = SkImageInfo::Make(width, height,
+                kN32_SkColorType, kPremul_SkAlphaType);
+        mCachedBitmap.setInfo(info);
+        // TODO: Count the bitmap cache against app's java heap
+        mCachedBitmap.allocPixels(info);
+        mCacheDirty = true;
+    }
+}
+
+bool Tree::canReuseBitmap(int width, int height) {
+    return width == mCachedBitmap.width() && height == mCachedBitmap.height();
+}
+
+}; // namespace VectorDrawable
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
new file mode 100644
index 0000000..09bdce5
--- /dev/null
+++ b/libs/hwui/VectorDrawable.h
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWUI_VPATH_H
+#define ANDROID_HWUI_VPATH_H
+
+#include "Canvas.h"
+#include <SkBitmap.h>
+#include <SkColor.h>
+#include <SkCanvas.h>
+#include <SkMatrix.h>
+#include <SkPaint.h>
+#include <SkPath.h>
+#include <SkPathMeasure.h>
+#include <SkRect.h>
+#include <SkShader.h>
+
+#include <cutils/compiler.h>
+#include <stddef.h>
+#include <vector>
+#include <string>
+
+namespace android {
+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(field, value) (value != field ? (field = value, true) : false)
+
+/* A VectorDrawable is composed of a tree of nodes.
+ * 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
+ *
+ */
+class ANDROID_API Node {
+public:
+    Node(const Node& node) {
+        mName = node.mName;
+    }
+    Node() {}
+    virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
+            float scaleX, float scaleY) = 0;
+    virtual void dump() = 0;
+    void setName(const char* name) {
+        mName = name;
+    }
+    virtual ~Node(){}
+protected:
+    std::string mName;
+};
+
+class ANDROID_API Path : public Node {
+public:
+    struct ANDROID_API Data {
+        std::vector<char> verbs;
+        std::vector<size_t> verbSizes;
+        std::vector<float> points;
+        bool operator==(const Data& data) const {
+            return verbs == data.verbs && verbSizes == data.verbSizes
+                    && points == data.points;
+        }
+    };
+    Path(const Data& nodes);
+    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);
+    static float getMatrixScale(const SkMatrix& groupStackedMatrix);
+
+protected:
+    virtual const SkPath& getUpdatedPath();
+    virtual void drawPath(SkCanvas *outCanvas, const SkPath& renderPath,
+            float strokeScale, const SkMatrix& matrix) = 0;
+    Data mData;
+    SkPath mSkPath;
+    bool mSkPathDirty = true;
+};
+
+class ANDROID_API FullPath: public Path {
+public:
+    FullPath(const FullPath& path); // for cloning
+    FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
+    FullPath() : Path() {}
+    FullPath(const Data& nodes) : Path(nodes) {}
+
+    ~FullPath() {
+        SkSafeUnref(mFillGradient);
+        SkSafeUnref(mStrokeGradient);
+    }
+
+    void updateProperties(float strokeWidth, SkColor strokeColor,
+            float strokeAlpha, SkColor fillColor, float fillAlpha,
+            float trimPathStart, float trimPathEnd, float trimPathOffset,
+            float strokeMiterLimit, int strokeLineCap, int strokeLineJoin);
+    float getStrokeWidth() {
+        return mStrokeWidth;
+    }
+    void setStrokeWidth(float strokeWidth) {
+        mStrokeWidth = strokeWidth;
+    }
+    SkColor getStrokeColor() {
+        return mStrokeColor;
+    }
+    void setStrokeColor(SkColor strokeColor) {
+        mStrokeColor = strokeColor;
+    }
+    float getStrokeAlpha() {
+        return mStrokeAlpha;
+    }
+    void setStrokeAlpha(float strokeAlpha) {
+        mStrokeAlpha = strokeAlpha;
+    }
+    SkColor getFillColor() {
+        return mFillColor;
+    }
+    void setFillColor(SkColor fillColor) {
+        mFillColor = fillColor;
+    }
+    float getFillAlpha() {
+        return mFillAlpha;
+    }
+    void setFillAlpha(float fillAlpha) {
+        mFillAlpha = fillAlpha;
+    }
+    float getTrimPathStart() {
+        return mTrimPathStart;
+    }
+    void setTrimPathStart(float trimPathStart) {
+        VD_SET_PROP_WITH_FLAG(mTrimPathStart, trimPathStart, mTrimDirty);
+    }
+    float getTrimPathEnd() {
+        return mTrimPathEnd;
+    }
+    void setTrimPathEnd(float trimPathEnd) {
+        VD_SET_PROP_WITH_FLAG(mTrimPathEnd, trimPathEnd, mTrimDirty);
+    }
+    float getTrimPathOffset() {
+        return mTrimPathOffset;
+    }
+    void setTrimPathOffset(float trimPathOffset) {
+        VD_SET_PROP_WITH_FLAG(mTrimPathOffset, trimPathOffset, mTrimDirty);
+    }
+    bool getProperties(int8_t* outProperties, int length);
+
+    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;
+
+private:
+    // Applies trimming to the specified path.
+    void applyTrim();
+    float mStrokeWidth = 0;
+    SkColor mStrokeColor = SK_ColorTRANSPARENT;
+    float mStrokeAlpha = 1;
+    SkColor mFillColor = SK_ColorTRANSPARENT;
+    SkShader* mStrokeGradient = nullptr;
+    SkShader* mFillGradient = nullptr;
+    float mFillAlpha = 1;
+    float mTrimPathStart = 0;
+    float mTrimPathEnd = 1;
+    float mTrimPathOffset = 0;
+    bool mTrimDirty = true;
+    SkPaint::Cap mStrokeLineCap = SkPaint::Cap::kButt_Cap;
+    SkPaint::Join mStrokeLineJoin = SkPaint::Join::kMiter_Join;
+    float mStrokeMiterLimit = 4;
+    SkPath mTrimmedSkPath;
+    SkPaint mPaint;
+};
+
+class ANDROID_API ClipPath: public Path {
+public:
+    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;
+};
+
+class ANDROID_API Group: public Node {
+public:
+    Group(const Group& group);
+    Group() {}
+    float getRotation() {
+        return mRotate;
+    }
+    void setRotation(float rotation) {
+        mRotate = rotation;
+    }
+    float getPivotX() {
+        return mPivotX;
+    }
+    void setPivotX(float pivotX) {
+        mPivotX = pivotX;
+    }
+    float getPivotY() {
+        return mPivotY;
+    }
+    void setPivotY(float pivotY) {
+        mPivotY = pivotY;
+    }
+    float getScaleX() {
+        return mScaleX;
+    }
+    void setScaleX(float scaleX) {
+        mScaleX = scaleX;
+    }
+    float getScaleY() {
+        return mScaleY;
+    }
+    void setScaleY(float scaleY) {
+        mScaleY = scaleY;
+    }
+    float getTranslateX() {
+        return mTranslateX;
+    }
+    void setTranslateX(float translateX) {
+        mTranslateX = translateX;
+    }
+    float getTranslateY() {
+        return mTranslateY;
+    }
+    void setTranslateY(float translateY) {
+        mTranslateY = 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);
+    void dump() override;
+    bool getProperties(float* outProperties, int length);
+
+private:
+    enum class Property {
+        Rotate_Property = 0,
+        PivotX_Property,
+        PivotY_Property,
+        ScaleX_Property,
+        ScaleY_Property,
+        TranslateX_Property,
+        TranslateY_Property,
+        // Count of the properties, must be at the end.
+        Count,
+    };
+    float mRotate = 0;
+    float mPivotX = 0;
+    float mPivotY = 0;
+    float mScaleX = 1;
+    float mScaleY = 1;
+    float mTranslateX = 0;
+    float mTranslateY = 0;
+    std::vector<Node*> mChildren;
+};
+
+class ANDROID_API Tree {
+public:
+    Tree(Group* rootNode) : mRootNode(rootNode) {}
+    void draw(Canvas* outCanvas, SkColorFilter* colorFilter,
+            const SkRect& bounds, bool needsMirroring, bool canReuseCache);
+    void drawCachedBitmapWithRootAlpha(Canvas* outCanvas, SkColorFilter* filter,
+            const SkRect& originalBounds);
+
+    void updateCachedBitmap(int width, int height);
+    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);
+    }
+
+    float getRootAlpha() {
+        return mRootAlpha;
+    }
+    void setViewportSize(float viewportWidth, float viewportHeight) {
+        mViewportWidth = viewportWidth;
+        mViewportHeight = viewportHeight;
+    }
+
+private:
+    // 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;
+
+    Group* mRootNode;
+    SkRect mBounds;
+    SkMatrix mCanvasMatrix;
+    SkPaint mPaint;
+    SkPathMeasure mPathMeasure;
+    SkBitmap mCachedBitmap;
+
+};
+
+} // namespace VectorDrawable
+
+typedef VectorDrawable::Path::Data PathData;
+} // namespace uirenderer
+} // namespace android
+
+#endif // ANDROID_HWUI_VPATH_H
diff --git a/libs/hwui/VectorDrawablePath.cpp b/libs/hwui/VectorDrawablePath.cpp
deleted file mode 100644
index c9a54ca..0000000
--- a/libs/hwui/VectorDrawablePath.cpp
+++ /dev/null
@@ -1,59 +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 "VectorDrawablePath.h"
-
-#include "PathParser.h"
-#include "utils/VectorDrawableUtils.h"
-
-#include <math.h>
-#include <utils/Log.h>
-
-namespace android {
-namespace uirenderer {
-
-
-VectorDrawablePath::VectorDrawablePath(const char* pathStr, size_t strLength) {
-    PathParser::ParseResult result;
-    PathParser::getPathDataFromString(&mData, &result, pathStr, strLength);
-    if (!result.failureOccurred) {
-        VectorDrawableUtils::verbsToPath(&mSkPath, mData);
-    }
-}
-
-VectorDrawablePath::VectorDrawablePath(const PathData& data) {
-    mData = data;
-    // Now we need to construct a path
-    VectorDrawableUtils::verbsToPath(&mSkPath, data);
-}
-
-VectorDrawablePath::VectorDrawablePath(const VectorDrawablePath& path) {
-    mData = path.mData;
-    VectorDrawableUtils::verbsToPath(&mSkPath, mData);
-}
-
-
-bool VectorDrawablePath::canMorph(const PathData& morphTo) {
-    return VectorDrawableUtils::canMorph(mData, morphTo);
-}
-
-bool VectorDrawablePath::canMorph(const VectorDrawablePath& path) {
-    return canMorph(path.mData);
-}
-
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/VectorDrawablePath.h b/libs/hwui/VectorDrawablePath.h
deleted file mode 100644
index 2e56349..0000000
--- a/libs/hwui/VectorDrawablePath.h
+++ /dev/null
@@ -1,55 +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 ANDROID_HWUI_VPATH_H
-#define ANDROID_HWUI_VPATH_H
-
-#include <cutils/compiler.h>
-#include "SkPath.h"
-#include <vector>
-
-namespace android {
-namespace uirenderer {
-
-struct ANDROID_API PathData {
-    // TODO: Try using FatVector instead of std::vector and do a micro benchmark on the performance
-    // difference.
-    std::vector<char> verbs;
-    std::vector<size_t> verbSizes;
-    std::vector<float> points;
-    bool operator== (const PathData& data) const {
-        return verbs == data.verbs && verbSizes == data.verbSizes && points == data.points;
-    }
-
-};
-
-class VectorDrawablePath {
-public:
-    VectorDrawablePath(const PathData& nodes);
-    VectorDrawablePath(const VectorDrawablePath& path);
-    VectorDrawablePath(const char* path, size_t strLength);
-    bool canMorph(const PathData& path);
-    bool canMorph(const VectorDrawablePath& path);
-
-private:
-    PathData mData;
-    SkPath mSkPath;
-};
-
-} // namespace uirenderer
-} // namespace android
-
-#endif // ANDROID_HWUI_VPATH_H
diff --git a/libs/hwui/tests/common/nullegl.cpp b/libs/hwui/debug/nullegl.cpp
similarity index 100%
rename from libs/hwui/tests/common/nullegl.cpp
rename to libs/hwui/debug/nullegl.cpp
diff --git a/libs/hwui/debug/nullgles.cpp b/libs/hwui/debug/nullgles.cpp
new file mode 100644
index 0000000..ffb0649
--- /dev/null
+++ b/libs/hwui/debug/nullgles.cpp
@@ -0,0 +1,275 @@
+/*
+ * Copyright(C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0(the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "unwrap_gles.h"
+
+#include <GLES3/gl3.h>
+#include <GLES2/gl2ext.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+struct {
+    GLboolean scissorEnabled;
+} gState;
+
+void glGenCommon(GLsizei n, GLuint *buffers) {
+    static GLuint nextId = 0;
+    int i;
+    for(i = 0; i < n; i++) {
+        buffers[i] = ++nextId;
+    }
+}
+
+void glGenBuffers(GLsizei n, GLuint *buffers) {
+    glGenCommon(n, buffers);
+}
+
+void glGenFramebuffers(GLsizei n, GLuint *framebuffers) {
+    glGenCommon(n, framebuffers);
+}
+
+void glGenRenderbuffers(GLsizei n, GLuint *renderbuffers) {
+    glGenCommon(n, renderbuffers);
+}
+
+void glGenTextures(GLsizei n, GLuint *textures) {
+    glGenCommon(n, textures);
+}
+
+GLuint glCreateProgram(void) {
+    static GLuint nextProgram = 0;
+    return ++nextProgram;
+}
+
+GLuint glCreateShader(GLenum type) {
+    static GLuint nextShader = 0;
+    return ++nextShader;
+}
+
+void glGetProgramiv(GLuint program, GLenum pname, GLint *params) {
+    switch (pname) {
+    case GL_DELETE_STATUS:
+    case GL_LINK_STATUS:
+    case GL_VALIDATE_STATUS:
+        *params = GL_TRUE;
+        break;
+    case GL_INFO_LOG_LENGTH:
+        *params = 16;
+        break;
+    }
+}
+
+void glGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+    *length = snprintf(infoLog, bufSize, "success");
+    if (*length >= bufSize) {
+        *length = bufSize - 1;
+    }
+}
+
+void glGetShaderiv(GLuint shader, GLenum pname, GLint *params) {
+    switch (pname) {
+    case GL_COMPILE_STATUS:
+    case GL_DELETE_STATUS:
+        *params = GL_TRUE;
+    }
+}
+
+void glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+    *length = snprintf(infoLog, bufSize, "success");
+    if (*length >= bufSize) {
+        *length = bufSize - 1;
+    }
+}
+
+void setBooleanState(GLenum cap, GLboolean value) {
+    switch (cap) {
+    case GL_SCISSOR_TEST:
+        gState.scissorEnabled = value;
+        break;
+    }
+}
+
+void glEnable(GLenum cap) {
+    setBooleanState(cap, GL_TRUE);
+}
+
+void glDisable(GLenum cap) {
+    setBooleanState(cap, GL_FALSE);
+}
+
+GLboolean glIsEnabled(GLenum cap) {
+    switch (cap) {
+    case GL_SCISSOR_TEST:
+        return gState.scissorEnabled;
+    default:
+        return GL_FALSE;
+    }
+}
+
+void glGetIntegerv(GLenum pname, GLint *data) {
+    switch (pname) {
+    case GL_MAX_TEXTURE_SIZE:
+        *data = 2048;
+        break;
+    case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
+        *data = 4;
+        break;
+    default:
+        *data = 0;
+    }
+}
+
+const char* getString(GLenum name) {
+    switch (name) {
+    case GL_VENDOR:
+        return "android";
+    case GL_RENDERER:
+        return "null";
+    case GL_VERSION:
+        return "OpenGL ES 2.0 rev1";
+    case GL_SHADING_LANGUAGE_VERSION:
+        return "OpenGL ES GLSL ES 2.0 rev1";
+    case GL_EXTENSIONS:
+    default:
+        return "";
+    }
+}
+
+const GLubyte* glGetString(GLenum name) {
+    return (GLubyte*) getString(name);
+}
+
+void glActiveTexture(GLenum texture) {}
+void glAttachShader(GLuint program, GLuint shader) {}
+void glBindAttribLocation(GLuint program, GLuint index, const GLchar *name) {}
+void glBindBuffer(GLenum target, GLuint buffer) {}
+void glBindFramebuffer(GLenum target, GLuint framebuffer) {}
+void glBindRenderbuffer(GLenum target, GLuint renderbuffer) {}
+void glBindTexture(GLenum target, GLuint texture) {}
+void glBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {}
+void glBlendEquation(GLenum mode) {}
+void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) {}
+void glBlendFunc(GLenum sfactor, GLenum dfactor) {}
+void glBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) {}
+void glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage) {}
+void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void *data) {}
+void glClear(GLbitfield mask) {}
+void glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {}
+void glClearDepthf(GLfloat d) {}
+void glClearStencil(GLint s) {}
+void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {}
+void glCompileShader(GLuint shader) {}
+void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data) {}
+void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) {}
+void glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {}
+void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {}
+void glCullFace(GLenum mode) {}
+void glDeleteBuffers(GLsizei n, const GLuint *buffers) {}
+void glDeleteFramebuffers(GLsizei n, const GLuint *framebuffers) {}
+void glDeleteProgram(GLuint program) {}
+void glDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) {}
+void glDeleteShader(GLuint shader) {}
+void glDeleteTextures(GLsizei n, const GLuint *textures) {}
+void glDepthFunc(GLenum func) {}
+void glDepthMask(GLboolean flag) {}
+void glDepthRangef(GLfloat n, GLfloat f) {}
+void glDetachShader(GLuint program, GLuint shader) {}
+void glDisableVertexAttribArray(GLuint index) {}
+void glDrawArrays(GLenum mode, GLint first, GLsizei count) {}
+void glDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices) {}
+void glEnableVertexAttribArray(GLuint index) {}
+void glFinish(void) {}
+void glFlush(void) {}
+void glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) {}
+void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {}
+void glFrontFace(GLenum mode) {}
+void glGenerateMipmap(GLenum target) {}
+GLint glGetAttribLocation(GLuint program, const GLchar *name) { return 1; }
+GLenum glGetError(void) { return GL_NO_ERROR; }
+GLint glGetUniformLocation(GLuint program, const GLchar *name) { return 2; }
+void glHint(GLenum target, GLenum mode) {}
+void glLineWidth(GLfloat width) {}
+void glLinkProgram(GLuint program) {}
+void glPixelStorei(GLenum pname, GLint param) {}
+void glPolygonOffset(GLfloat factor, GLfloat units) {}
+void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) {}
+void glReleaseShaderCompiler(void) {}
+void glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {}
+void glSampleCoverage(GLfloat value, GLboolean invert) {}
+void glScissor(GLint x, GLint y, GLsizei width, GLsizei height) {}
+void glShaderBinary(GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length) {}
+void glShaderSource(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length) {}
+void glStencilFunc(GLenum func, GLint ref, GLuint mask) {}
+void glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) {}
+void glStencilMask(GLuint mask) {}
+void glStencilMaskSeparate(GLenum face, GLuint mask) {}
+void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) {}
+void glStencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) {}
+void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) {}
+void glTexParameterf(GLenum target, GLenum pname, GLfloat param) {}
+void glTexParameterfv(GLenum target, GLenum pname, const GLfloat *params) {}
+void glTexParameteri(GLenum target, GLenum pname, GLint param) {}
+void glTexParameteriv(GLenum target, GLenum pname, const GLint *params) {}
+void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) {}
+void glUniform1f(GLint location, GLfloat v0) {}
+void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform1i(GLint location, GLint v0) {}
+void glUniform1iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniform2f(GLint location, GLfloat v0, GLfloat v1) {}
+void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform2i(GLint location, GLint v0, GLint v1) {}
+void glUniform2iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) {}
+void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform3i(GLint location, GLint v0, GLint v1, GLint v2) {}
+void glUniform3iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {}
+void glUniform4fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) {}
+void glUniform4iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {}
+void glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {}
+void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {}
+void glUseProgram(GLuint program) {}
+void glValidateProgram(GLuint program) {}
+void glVertexAttrib1f(GLuint index, GLfloat x) {}
+void glVertexAttrib1fv(GLuint index, const GLfloat *v) {}
+void glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) {}
+void glVertexAttrib2fv(GLuint index, const GLfloat *v) {}
+void glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) {}
+void glVertexAttrib3fv(GLuint index, const GLfloat *v) {}
+void glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {}
+void glVertexAttrib4fv(GLuint index, const GLfloat *v) {}
+void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) {}
+void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) {}
+
+
+// gles2 ext
+void glInsertEventMarkerEXT(GLsizei length, const GLchar *marker) {}
+void glPushGroupMarkerEXT(GLsizei length, const GLchar *marker) {}
+void glPopGroupMarkerEXT(void) {}
+void glDiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum *attachments) {}
+void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image) {}
+
+// GLES3
+void* glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) {
+    return 0;
+}
+
+GLboolean glUnmapBuffer(GLenum target) {
+    return GL_FALSE;
+}
diff --git a/libs/hwui/debug/unwrap_gles.h b/libs/hwui/debug/unwrap_gles.h
new file mode 100644
index 0000000..7716a73
--- /dev/null
+++ b/libs/hwui/debug/unwrap_gles.h
@@ -0,0 +1,918 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef HWUI_GLES_WRAP_ENABLED
+#undef HWUI_GLES_WRAP_ENABLED
+
+#undef glActiveShaderProgram
+#undef glActiveShaderProgramEXT
+#undef glActiveTexture
+#undef glAlphaFunc
+#undef glAlphaFuncQCOM
+#undef glAlphaFuncx
+#undef glAlphaFuncxOES
+#undef glApplyFramebufferAttachmentCMAAINTEL
+#undef glAttachShader
+#undef glBeginConditionalRenderNV
+#undef glBeginPerfMonitorAMD
+#undef glBeginPerfQueryINTEL
+#undef glBeginQuery
+#undef glBeginQueryEXT
+#undef glBeginTransformFeedback
+#undef glBindAttribLocation
+#undef glBindBuffer
+#undef glBindBufferBase
+#undef glBindBufferRange
+#undef glBindFragDataLocationEXT
+#undef glBindFragDataLocationIndexedEXT
+#undef glBindFramebuffer
+#undef glBindFramebufferOES
+#undef glBindImageTexture
+#undef glBindProgramPipeline
+#undef glBindProgramPipelineEXT
+#undef glBindRenderbuffer
+#undef glBindRenderbufferOES
+#undef glBindSampler
+#undef glBindTexture
+#undef glBindTransformFeedback
+#undef glBindVertexArray
+#undef glBindVertexArrayOES
+#undef glBindVertexBuffer
+#undef glBlendBarrier
+#undef glBlendBarrierKHR
+#undef glBlendBarrierNV
+#undef glBlendColor
+#undef glBlendEquation
+#undef glBlendEquationOES
+#undef glBlendEquationSeparate
+#undef glBlendEquationSeparateOES
+#undef glBlendEquationSeparatei
+#undef glBlendEquationSeparateiEXT
+#undef glBlendEquationSeparateiOES
+#undef glBlendEquationi
+#undef glBlendEquationiEXT
+#undef glBlendEquationiOES
+#undef glBlendFunc
+#undef glBlendFuncSeparate
+#undef glBlendFuncSeparateOES
+#undef glBlendFuncSeparatei
+#undef glBlendFuncSeparateiEXT
+#undef glBlendFuncSeparateiOES
+#undef glBlendFunci
+#undef glBlendFunciEXT
+#undef glBlendFunciOES
+#undef glBlendParameteriNV
+#undef glBlitFramebuffer
+#undef glBlitFramebufferANGLE
+#undef glBlitFramebufferNV
+#undef glBufferData
+#undef glBufferStorageEXT
+#undef glBufferSubData
+#undef glCheckFramebufferStatus
+#undef glCheckFramebufferStatusOES
+#undef glClear
+#undef glClearBufferfi
+#undef glClearBufferfv
+#undef glClearBufferiv
+#undef glClearBufferuiv
+#undef glClearColor
+#undef glClearColorx
+#undef glClearColorxOES
+#undef glClearDepthf
+#undef glClearDepthfOES
+#undef glClearDepthx
+#undef glClearDepthxOES
+#undef glClearStencil
+#undef glClientActiveTexture
+#undef glClientWaitSync
+#undef glClientWaitSyncAPPLE
+#undef glClipPlanef
+#undef glClipPlanefIMG
+#undef glClipPlanefOES
+#undef glClipPlanex
+#undef glClipPlanexIMG
+#undef glClipPlanexOES
+#undef glColor4f
+#undef glColor4ub
+#undef glColor4x
+#undef glColor4xOES
+#undef glColorMask
+#undef glColorMaski
+#undef glColorMaskiEXT
+#undef glColorMaskiOES
+#undef glColorPointer
+#undef glCompileShader
+#undef glCompressedTexImage2D
+#undef glCompressedTexImage3D
+#undef glCompressedTexImage3DOES
+#undef glCompressedTexSubImage2D
+#undef glCompressedTexSubImage3D
+#undef glCompressedTexSubImage3DOES
+#undef glCopyBufferSubData
+#undef glCopyBufferSubDataNV
+#undef glCopyImageSubData
+#undef glCopyImageSubDataEXT
+#undef glCopyImageSubDataOES
+#undef glCopyPathNV
+#undef glCopyTexImage2D
+#undef glCopyTexSubImage2D
+#undef glCopyTexSubImage3D
+#undef glCopyTexSubImage3DOES
+#undef glCopyTextureLevelsAPPLE
+#undef glCoverFillPathInstancedNV
+#undef glCoverFillPathNV
+#undef glCoverStrokePathInstancedNV
+#undef glCoverStrokePathNV
+#undef glCoverageMaskNV
+#undef glCoverageModulationNV
+#undef glCoverageModulationTableNV
+#undef glCoverageOperationNV
+#undef glCreatePerfQueryINTEL
+#undef glCreateProgram
+#undef glCreateShader
+#undef glCreateShaderProgramv
+#undef glCreateShaderProgramvEXT
+#undef glCullFace
+#undef glCurrentPaletteMatrixOES
+#undef glDebugMessageCallback
+#undef glDebugMessageCallbackKHR
+#undef glDebugMessageControl
+#undef glDebugMessageControlKHR
+#undef glDebugMessageInsert
+#undef glDebugMessageInsertKHR
+#undef glDeleteBuffers
+#undef glDeleteFencesNV
+#undef glDeleteFramebuffers
+#undef glDeleteFramebuffersOES
+#undef glDeletePathsNV
+#undef glDeletePerfMonitorsAMD
+#undef glDeletePerfQueryINTEL
+#undef glDeleteProgram
+#undef glDeleteProgramPipelines
+#undef glDeleteProgramPipelinesEXT
+#undef glDeleteQueries
+#undef glDeleteQueriesEXT
+#undef glDeleteRenderbuffers
+#undef glDeleteRenderbuffersOES
+#undef glDeleteSamplers
+#undef glDeleteShader
+#undef glDeleteSync
+#undef glDeleteSyncAPPLE
+#undef glDeleteTextures
+#undef glDeleteTransformFeedbacks
+#undef glDeleteVertexArrays
+#undef glDeleteVertexArraysOES
+#undef glDepthFunc
+#undef glDepthMask
+#undef glDepthRangeArrayfvNV
+#undef glDepthRangeIndexedfNV
+#undef glDepthRangef
+#undef glDepthRangefOES
+#undef glDepthRangex
+#undef glDepthRangexOES
+#undef glDetachShader
+#undef glDisable
+#undef glDisableClientState
+#undef glDisableDriverControlQCOM
+#undef glDisableVertexAttribArray
+#undef glDisablei
+#undef glDisableiEXT
+#undef glDisableiNV
+#undef glDisableiOES
+#undef glDiscardFramebufferEXT
+#undef glDispatchCompute
+#undef glDispatchComputeIndirect
+#undef glDrawArrays
+#undef glDrawArraysIndirect
+#undef glDrawArraysInstanced
+#undef glDrawArraysInstancedANGLE
+#undef glDrawArraysInstancedBaseInstanceEXT
+#undef glDrawArraysInstancedEXT
+#undef glDrawArraysInstancedNV
+#undef glDrawBuffers
+#undef glDrawBuffersEXT
+#undef glDrawBuffersIndexedEXT
+#undef glDrawBuffersNV
+#undef glDrawElements
+#undef glDrawElementsBaseVertex
+#undef glDrawElementsBaseVertexEXT
+#undef glDrawElementsBaseVertexOES
+#undef glDrawElementsIndirect
+#undef glDrawElementsInstanced
+#undef glDrawElementsInstancedANGLE
+#undef glDrawElementsInstancedBaseInstanceEXT
+#undef glDrawElementsInstancedBaseVertex
+#undef glDrawElementsInstancedBaseVertexBaseInstanceEXT
+#undef glDrawElementsInstancedBaseVertexEXT
+#undef glDrawElementsInstancedBaseVertexOES
+#undef glDrawElementsInstancedEXT
+#undef glDrawElementsInstancedNV
+#undef glDrawRangeElements
+#undef glDrawRangeElementsBaseVertex
+#undef glDrawRangeElementsBaseVertexEXT
+#undef glDrawRangeElementsBaseVertexOES
+#undef glDrawTexfOES
+#undef glDrawTexfvOES
+#undef glDrawTexiOES
+#undef glDrawTexivOES
+#undef glDrawTexsOES
+#undef glDrawTexsvOES
+#undef glDrawTexxOES
+#undef glDrawTexxvOES
+#undef glEGLImageTargetRenderbufferStorageOES
+#undef glEGLImageTargetTexture2DOES
+#undef glEnable
+#undef glEnableClientState
+#undef glEnableDriverControlQCOM
+#undef glEnableVertexAttribArray
+#undef glEnablei
+#undef glEnableiEXT
+#undef glEnableiNV
+#undef glEnableiOES
+#undef glEndConditionalRenderNV
+#undef glEndPerfMonitorAMD
+#undef glEndPerfQueryINTEL
+#undef glEndQuery
+#undef glEndQueryEXT
+#undef glEndTilingQCOM
+#undef glEndTransformFeedback
+#undef glExtGetBufferPointervQCOM
+#undef glExtGetBuffersQCOM
+#undef glExtGetFramebuffersQCOM
+#undef glExtGetProgramBinarySourceQCOM
+#undef glExtGetProgramsQCOM
+#undef glExtGetRenderbuffersQCOM
+#undef glExtGetShadersQCOM
+#undef glExtGetTexLevelParameterivQCOM
+#undef glExtGetTexSubImageQCOM
+#undef glExtGetTexturesQCOM
+#undef glExtIsProgramBinaryQCOM
+#undef glExtTexObjectStateOverrideiQCOM
+#undef glFenceSync
+#undef glFenceSyncAPPLE
+#undef glFinish
+#undef glFinishFenceNV
+#undef glFlush
+#undef glFlushMappedBufferRange
+#undef glFlushMappedBufferRangeEXT
+#undef glFogf
+#undef glFogfv
+#undef glFogx
+#undef glFogxOES
+#undef glFogxv
+#undef glFogxvOES
+#undef glFragmentCoverageColorNV
+#undef glFramebufferParameteri
+#undef glFramebufferRenderbuffer
+#undef glFramebufferRenderbufferOES
+#undef glFramebufferSampleLocationsfvNV
+#undef glFramebufferTexture
+#undef glFramebufferTexture2D
+#undef glFramebufferTexture2DMultisampleEXT
+#undef glFramebufferTexture2DMultisampleIMG
+#undef glFramebufferTexture2DOES
+#undef glFramebufferTexture3DOES
+#undef glFramebufferTextureEXT
+#undef glFramebufferTextureLayer
+#undef glFramebufferTextureMultisampleMultiviewOVR
+#undef glFramebufferTextureMultiviewOVR
+#undef glFramebufferTextureOES
+#undef glFrontFace
+#undef glFrustumf
+#undef glFrustumfOES
+#undef glFrustumx
+#undef glFrustumxOES
+#undef glGenBuffers
+#undef glGenFencesNV
+#undef glGenFramebuffers
+#undef glGenFramebuffersOES
+#undef glGenPathsNV
+#undef glGenPerfMonitorsAMD
+#undef glGenProgramPipelines
+#undef glGenProgramPipelinesEXT
+#undef glGenQueries
+#undef glGenQueriesEXT
+#undef glGenRenderbuffers
+#undef glGenRenderbuffersOES
+#undef glGenSamplers
+#undef glGenTextures
+#undef glGenTransformFeedbacks
+#undef glGenVertexArrays
+#undef glGenVertexArraysOES
+#undef glGenerateMipmap
+#undef glGenerateMipmapOES
+#undef glGetActiveAttrib
+#undef glGetActiveUniform
+#undef glGetActiveUniformBlockName
+#undef glGetActiveUniformBlockiv
+#undef glGetActiveUniformsiv
+#undef glGetAttachedShaders
+#undef glGetAttribLocation
+#undef glGetBooleani_v
+#undef glGetBooleanv
+#undef glGetBufferParameteri64v
+#undef glGetBufferParameteriv
+#undef glGetBufferPointerv
+#undef glGetBufferPointervOES
+#undef glGetClipPlanef
+#undef glGetClipPlanefOES
+#undef glGetClipPlanex
+#undef glGetClipPlanexOES
+#undef glGetCoverageModulationTableNV
+#undef glGetDebugMessageLog
+#undef glGetDebugMessageLogKHR
+#undef glGetDriverControlStringQCOM
+#undef glGetDriverControlsQCOM
+#undef glGetError
+#undef glGetFenceivNV
+#undef glGetFirstPerfQueryIdINTEL
+#undef glGetFixedv
+#undef glGetFixedvOES
+#undef glGetFloati_vNV
+#undef glGetFloatv
+#undef glGetFragDataIndexEXT
+#undef glGetFragDataLocation
+#undef glGetFramebufferAttachmentParameteriv
+#undef glGetFramebufferAttachmentParameterivOES
+#undef glGetFramebufferParameteriv
+#undef glGetGraphicsResetStatus
+#undef glGetGraphicsResetStatusEXT
+#undef glGetGraphicsResetStatusKHR
+#undef glGetImageHandleNV
+#undef glGetInteger64i_v
+#undef glGetInteger64v
+#undef glGetInteger64vAPPLE
+#undef glGetIntegeri_v
+#undef glGetIntegeri_vEXT
+#undef glGetIntegerv
+#undef glGetInternalformatSampleivNV
+#undef glGetInternalformativ
+#undef glGetLightfv
+#undef glGetLightxv
+#undef glGetLightxvOES
+#undef glGetMaterialfv
+#undef glGetMaterialxv
+#undef glGetMaterialxvOES
+#undef glGetMultisamplefv
+#undef glGetNextPerfQueryIdINTEL
+#undef glGetObjectLabel
+#undef glGetObjectLabelEXT
+#undef glGetObjectLabelKHR
+#undef glGetObjectPtrLabel
+#undef glGetObjectPtrLabelKHR
+#undef glGetPathCommandsNV
+#undef glGetPathCoordsNV
+#undef glGetPathDashArrayNV
+#undef glGetPathLengthNV
+#undef glGetPathMetricRangeNV
+#undef glGetPathMetricsNV
+#undef glGetPathParameterfvNV
+#undef glGetPathParameterivNV
+#undef glGetPathSpacingNV
+#undef glGetPerfCounterInfoINTEL
+#undef glGetPerfMonitorCounterDataAMD
+#undef glGetPerfMonitorCounterInfoAMD
+#undef glGetPerfMonitorCounterStringAMD
+#undef glGetPerfMonitorCountersAMD
+#undef glGetPerfMonitorGroupStringAMD
+#undef glGetPerfMonitorGroupsAMD
+#undef glGetPerfQueryDataINTEL
+#undef glGetPerfQueryIdByNameINTEL
+#undef glGetPerfQueryInfoINTEL
+#undef glGetPointerv
+#undef glGetPointervKHR
+#undef glGetProgramBinary
+#undef glGetProgramBinaryOES
+#undef glGetProgramInfoLog
+#undef glGetProgramInterfaceiv
+#undef glGetProgramPipelineInfoLog
+#undef glGetProgramPipelineInfoLogEXT
+#undef glGetProgramPipelineiv
+#undef glGetProgramPipelineivEXT
+#undef glGetProgramResourceIndex
+#undef glGetProgramResourceLocation
+#undef glGetProgramResourceLocationIndexEXT
+#undef glGetProgramResourceName
+#undef glGetProgramResourcefvNV
+#undef glGetProgramResourceiv
+#undef glGetProgramiv
+#undef glGetQueryObjecti64vEXT
+#undef glGetQueryObjectivEXT
+#undef glGetQueryObjectui64vEXT
+#undef glGetQueryObjectuiv
+#undef glGetQueryObjectuivEXT
+#undef glGetQueryiv
+#undef glGetQueryivEXT
+#undef glGetRenderbufferParameteriv
+#undef glGetRenderbufferParameterivOES
+#undef glGetSamplerParameterIiv
+#undef glGetSamplerParameterIivEXT
+#undef glGetSamplerParameterIivOES
+#undef glGetSamplerParameterIuiv
+#undef glGetSamplerParameterIuivEXT
+#undef glGetSamplerParameterIuivOES
+#undef glGetSamplerParameterfv
+#undef glGetSamplerParameteriv
+#undef glGetShaderInfoLog
+#undef glGetShaderPrecisionFormat
+#undef glGetShaderSource
+#undef glGetShaderiv
+#undef glGetString
+#undef glGetStringi
+#undef glGetSynciv
+#undef glGetSyncivAPPLE
+#undef glGetTexEnvfv
+#undef glGetTexEnviv
+#undef glGetTexEnvxv
+#undef glGetTexEnvxvOES
+#undef glGetTexGenfvOES
+#undef glGetTexGenivOES
+#undef glGetTexGenxvOES
+#undef glGetTexLevelParameterfv
+#undef glGetTexLevelParameteriv
+#undef glGetTexParameterIiv
+#undef glGetTexParameterIivEXT
+#undef glGetTexParameterIivOES
+#undef glGetTexParameterIuiv
+#undef glGetTexParameterIuivEXT
+#undef glGetTexParameterIuivOES
+#undef glGetTexParameterfv
+#undef glGetTexParameteriv
+#undef glGetTexParameterxv
+#undef glGetTexParameterxvOES
+#undef glGetTextureHandleNV
+#undef glGetTextureSamplerHandleNV
+#undef glGetTransformFeedbackVarying
+#undef glGetTranslatedShaderSourceANGLE
+#undef glGetUniformBlockIndex
+#undef glGetUniformIndices
+#undef glGetUniformLocation
+#undef glGetUniformfv
+#undef glGetUniformiv
+#undef glGetUniformuiv
+#undef glGetVertexAttribIiv
+#undef glGetVertexAttribIuiv
+#undef glGetVertexAttribPointerv
+#undef glGetVertexAttribfv
+#undef glGetVertexAttribiv
+#undef glGetnUniformfv
+#undef glGetnUniformfvEXT
+#undef glGetnUniformfvKHR
+#undef glGetnUniformiv
+#undef glGetnUniformivEXT
+#undef glGetnUniformivKHR
+#undef glGetnUniformuiv
+#undef glGetnUniformuivKHR
+#undef glHint
+#undef glInsertEventMarkerEXT
+#undef glInterpolatePathsNV
+#undef glInvalidateFramebuffer
+#undef glInvalidateSubFramebuffer
+#undef glIsBuffer
+#undef glIsEnabled
+#undef glIsEnabledi
+#undef glIsEnablediEXT
+#undef glIsEnablediNV
+#undef glIsEnablediOES
+#undef glIsFenceNV
+#undef glIsFramebuffer
+#undef glIsFramebufferOES
+#undef glIsImageHandleResidentNV
+#undef glIsPathNV
+#undef glIsPointInFillPathNV
+#undef glIsPointInStrokePathNV
+#undef glIsProgram
+#undef glIsProgramPipeline
+#undef glIsProgramPipelineEXT
+#undef glIsQuery
+#undef glIsQueryEXT
+#undef glIsRenderbuffer
+#undef glIsRenderbufferOES
+#undef glIsSampler
+#undef glIsShader
+#undef glIsSync
+#undef glIsSyncAPPLE
+#undef glIsTexture
+#undef glIsTextureHandleResidentNV
+#undef glIsTransformFeedback
+#undef glIsVertexArray
+#undef glIsVertexArrayOES
+#undef glLabelObjectEXT
+#undef glLightModelf
+#undef glLightModelfv
+#undef glLightModelx
+#undef glLightModelxOES
+#undef glLightModelxv
+#undef glLightModelxvOES
+#undef glLightf
+#undef glLightfv
+#undef glLightx
+#undef glLightxOES
+#undef glLightxv
+#undef glLightxvOES
+#undef glLineWidth
+#undef glLineWidthx
+#undef glLineWidthxOES
+#undef glLinkProgram
+#undef glLoadIdentity
+#undef glLoadMatrixf
+#undef glLoadMatrixx
+#undef glLoadMatrixxOES
+#undef glLoadPaletteFromModelViewMatrixOES
+#undef glLogicOp
+#undef glMakeImageHandleNonResidentNV
+#undef glMakeImageHandleResidentNV
+#undef glMakeTextureHandleNonResidentNV
+#undef glMakeTextureHandleResidentNV
+#undef glMapBufferOES
+#undef glMapBufferRange
+#undef glMapBufferRangeEXT
+#undef glMaterialf
+#undef glMaterialfv
+#undef glMaterialx
+#undef glMaterialxOES
+#undef glMaterialxv
+#undef glMaterialxvOES
+#undef glMatrixIndexPointerOES
+#undef glMatrixLoad3x2fNV
+#undef glMatrixLoad3x3fNV
+#undef glMatrixLoadTranspose3x3fNV
+#undef glMatrixMode
+#undef glMatrixMult3x2fNV
+#undef glMatrixMult3x3fNV
+#undef glMatrixMultTranspose3x3fNV
+#undef glMemoryBarrier
+#undef glMemoryBarrierByRegion
+#undef glMinSampleShading
+#undef glMinSampleShadingOES
+#undef glMultMatrixf
+#undef glMultMatrixx
+#undef glMultMatrixxOES
+#undef glMultiDrawArraysEXT
+#undef glMultiDrawArraysIndirectEXT
+#undef glMultiDrawElementsBaseVertexEXT
+#undef glMultiDrawElementsBaseVertexOES
+#undef glMultiDrawElementsEXT
+#undef glMultiDrawElementsIndirectEXT
+#undef glMultiTexCoord4f
+#undef glMultiTexCoord4x
+#undef glMultiTexCoord4xOES
+#undef glNamedFramebufferSampleLocationsfvNV
+#undef glNormal3f
+#undef glNormal3x
+#undef glNormal3xOES
+#undef glNormalPointer
+#undef glObjectLabel
+#undef glObjectLabelKHR
+#undef glObjectPtrLabel
+#undef glObjectPtrLabelKHR
+#undef glOrthof
+#undef glOrthofOES
+#undef glOrthox
+#undef glOrthoxOES
+#undef glPatchParameteri
+#undef glPatchParameteriEXT
+#undef glPatchParameteriOES
+#undef glPathCommandsNV
+#undef glPathCoordsNV
+#undef glPathCoverDepthFuncNV
+#undef glPathDashArrayNV
+#undef glPathGlyphIndexArrayNV
+#undef glPathGlyphIndexRangeNV
+#undef glPathGlyphRangeNV
+#undef glPathGlyphsNV
+#undef glPathMemoryGlyphIndexArrayNV
+#undef glPathParameterfNV
+#undef glPathParameterfvNV
+#undef glPathParameteriNV
+#undef glPathParameterivNV
+#undef glPathStencilDepthOffsetNV
+#undef glPathStencilFuncNV
+#undef glPathStringNV
+#undef glPathSubCommandsNV
+#undef glPathSubCoordsNV
+#undef glPauseTransformFeedback
+#undef glPixelStorei
+#undef glPointAlongPathNV
+#undef glPointParameterf
+#undef glPointParameterfv
+#undef glPointParameterx
+#undef glPointParameterxOES
+#undef glPointParameterxv
+#undef glPointParameterxvOES
+#undef glPointSize
+#undef glPointSizePointerOES
+#undef glPointSizex
+#undef glPointSizexOES
+#undef glPolygonModeNV
+#undef glPolygonOffset
+#undef glPolygonOffsetx
+#undef glPolygonOffsetxOES
+#undef glPopDebugGroup
+#undef glPopDebugGroupKHR
+#undef glPopGroupMarkerEXT
+#undef glPopMatrix
+#undef glPrimitiveBoundingBox
+#undef glPrimitiveBoundingBoxEXT
+#undef glPrimitiveBoundingBoxOES
+#undef glProgramBinary
+#undef glProgramBinaryOES
+#undef glProgramParameteri
+#undef glProgramParameteriEXT
+#undef glProgramPathFragmentInputGenNV
+#undef glProgramUniform1f
+#undef glProgramUniform1fEXT
+#undef glProgramUniform1fv
+#undef glProgramUniform1fvEXT
+#undef glProgramUniform1i
+#undef glProgramUniform1iEXT
+#undef glProgramUniform1iv
+#undef glProgramUniform1ivEXT
+#undef glProgramUniform1ui
+#undef glProgramUniform1uiEXT
+#undef glProgramUniform1uiv
+#undef glProgramUniform1uivEXT
+#undef glProgramUniform2f
+#undef glProgramUniform2fEXT
+#undef glProgramUniform2fv
+#undef glProgramUniform2fvEXT
+#undef glProgramUniform2i
+#undef glProgramUniform2iEXT
+#undef glProgramUniform2iv
+#undef glProgramUniform2ivEXT
+#undef glProgramUniform2ui
+#undef glProgramUniform2uiEXT
+#undef glProgramUniform2uiv
+#undef glProgramUniform2uivEXT
+#undef glProgramUniform3f
+#undef glProgramUniform3fEXT
+#undef glProgramUniform3fv
+#undef glProgramUniform3fvEXT
+#undef glProgramUniform3i
+#undef glProgramUniform3iEXT
+#undef glProgramUniform3iv
+#undef glProgramUniform3ivEXT
+#undef glProgramUniform3ui
+#undef glProgramUniform3uiEXT
+#undef glProgramUniform3uiv
+#undef glProgramUniform3uivEXT
+#undef glProgramUniform4f
+#undef glProgramUniform4fEXT
+#undef glProgramUniform4fv
+#undef glProgramUniform4fvEXT
+#undef glProgramUniform4i
+#undef glProgramUniform4iEXT
+#undef glProgramUniform4iv
+#undef glProgramUniform4ivEXT
+#undef glProgramUniform4ui
+#undef glProgramUniform4uiEXT
+#undef glProgramUniform4uiv
+#undef glProgramUniform4uivEXT
+#undef glProgramUniformHandleui64NV
+#undef glProgramUniformHandleui64vNV
+#undef glProgramUniformMatrix2fv
+#undef glProgramUniformMatrix2fvEXT
+#undef glProgramUniformMatrix2x3fv
+#undef glProgramUniformMatrix2x3fvEXT
+#undef glProgramUniformMatrix2x4fv
+#undef glProgramUniformMatrix2x4fvEXT
+#undef glProgramUniformMatrix3fv
+#undef glProgramUniformMatrix3fvEXT
+#undef glProgramUniformMatrix3x2fv
+#undef glProgramUniformMatrix3x2fvEXT
+#undef glProgramUniformMatrix3x4fv
+#undef glProgramUniformMatrix3x4fvEXT
+#undef glProgramUniformMatrix4fv
+#undef glProgramUniformMatrix4fvEXT
+#undef glProgramUniformMatrix4x2fv
+#undef glProgramUniformMatrix4x2fvEXT
+#undef glProgramUniformMatrix4x3fv
+#undef glProgramUniformMatrix4x3fvEXT
+#undef glPushDebugGroup
+#undef glPushDebugGroupKHR
+#undef glPushGroupMarkerEXT
+#undef glPushMatrix
+#undef glQueryCounterEXT
+#undef glQueryMatrixxOES
+#undef glRasterSamplesEXT
+#undef glReadBuffer
+#undef glReadBufferIndexedEXT
+#undef glReadBufferNV
+#undef glReadPixels
+#undef glReadnPixels
+#undef glReadnPixelsEXT
+#undef glReadnPixelsKHR
+#undef glReleaseShaderCompiler
+#undef glRenderbufferStorage
+#undef glRenderbufferStorageMultisample
+#undef glRenderbufferStorageMultisampleANGLE
+#undef glRenderbufferStorageMultisampleAPPLE
+#undef glRenderbufferStorageMultisampleEXT
+#undef glRenderbufferStorageMultisampleIMG
+#undef glRenderbufferStorageMultisampleNV
+#undef glRenderbufferStorageOES
+#undef glResolveDepthValuesNV
+#undef glResolveMultisampleFramebufferAPPLE
+#undef glResumeTransformFeedback
+#undef glRotatef
+#undef glRotatex
+#undef glRotatexOES
+#undef glSampleCoverage
+#undef glSampleCoveragex
+#undef glSampleCoveragexOES
+#undef glSampleMaski
+#undef glSamplerParameterIiv
+#undef glSamplerParameterIivEXT
+#undef glSamplerParameterIivOES
+#undef glSamplerParameterIuiv
+#undef glSamplerParameterIuivEXT
+#undef glSamplerParameterIuivOES
+#undef glSamplerParameterf
+#undef glSamplerParameterfv
+#undef glSamplerParameteri
+#undef glSamplerParameteriv
+#undef glScalef
+#undef glScalex
+#undef glScalexOES
+#undef glScissor
+#undef glScissorArrayvNV
+#undef glScissorIndexedNV
+#undef glScissorIndexedvNV
+#undef glSelectPerfMonitorCountersAMD
+#undef glSetFenceNV
+#undef glShadeModel
+#undef glShaderBinary
+#undef glShaderSource
+#undef glStartTilingQCOM
+#undef glStencilFillPathInstancedNV
+#undef glStencilFillPathNV
+#undef glStencilFunc
+#undef glStencilFuncSeparate
+#undef glStencilMask
+#undef glStencilMaskSeparate
+#undef glStencilOp
+#undef glStencilOpSeparate
+#undef glStencilStrokePathInstancedNV
+#undef glStencilStrokePathNV
+#undef glStencilThenCoverFillPathInstancedNV
+#undef glStencilThenCoverFillPathNV
+#undef glStencilThenCoverStrokePathInstancedNV
+#undef glStencilThenCoverStrokePathNV
+#undef glSubpixelPrecisionBiasNV
+#undef glTestFenceNV
+#undef glTexBuffer
+#undef glTexBufferEXT
+#undef glTexBufferOES
+#undef glTexBufferRange
+#undef glTexBufferRangeEXT
+#undef glTexBufferRangeOES
+#undef glTexCoordPointer
+#undef glTexEnvf
+#undef glTexEnvfv
+#undef glTexEnvi
+#undef glTexEnviv
+#undef glTexEnvx
+#undef glTexEnvxOES
+#undef glTexEnvxv
+#undef glTexEnvxvOES
+#undef glTexGenfOES
+#undef glTexGenfvOES
+#undef glTexGeniOES
+#undef glTexGenivOES
+#undef glTexGenxOES
+#undef glTexGenxvOES
+#undef glTexImage2D
+#undef glTexImage3D
+#undef glTexImage3DOES
+#undef glTexPageCommitmentEXT
+#undef glTexParameterIiv
+#undef glTexParameterIivEXT
+#undef glTexParameterIivOES
+#undef glTexParameterIuiv
+#undef glTexParameterIuivEXT
+#undef glTexParameterIuivOES
+#undef glTexParameterf
+#undef glTexParameterfv
+#undef glTexParameteri
+#undef glTexParameteriv
+#undef glTexParameterx
+#undef glTexParameterxOES
+#undef glTexParameterxv
+#undef glTexParameterxvOES
+#undef glTexStorage1DEXT
+#undef glTexStorage2D
+#undef glTexStorage2DEXT
+#undef glTexStorage2DMultisample
+#undef glTexStorage3D
+#undef glTexStorage3DEXT
+#undef glTexStorage3DMultisample
+#undef glTexStorage3DMultisampleOES
+#undef glTexSubImage2D
+#undef glTexSubImage3D
+#undef glTexSubImage3DOES
+#undef glTextureStorage1DEXT
+#undef glTextureStorage2DEXT
+#undef glTextureStorage3DEXT
+#undef glTextureViewEXT
+#undef glTextureViewOES
+#undef glTransformFeedbackVaryings
+#undef glTransformPathNV
+#undef glTranslatef
+#undef glTranslatex
+#undef glTranslatexOES
+#undef glUniform1f
+#undef glUniform1fv
+#undef glUniform1i
+#undef glUniform1iv
+#undef glUniform1ui
+#undef glUniform1uiv
+#undef glUniform2f
+#undef glUniform2fv
+#undef glUniform2i
+#undef glUniform2iv
+#undef glUniform2ui
+#undef glUniform2uiv
+#undef glUniform3f
+#undef glUniform3fv
+#undef glUniform3i
+#undef glUniform3iv
+#undef glUniform3ui
+#undef glUniform3uiv
+#undef glUniform4f
+#undef glUniform4fv
+#undef glUniform4i
+#undef glUniform4iv
+#undef glUniform4ui
+#undef glUniform4uiv
+#undef glUniformBlockBinding
+#undef glUniformHandleui64NV
+#undef glUniformHandleui64vNV
+#undef glUniformMatrix2fv
+#undef glUniformMatrix2x3fv
+#undef glUniformMatrix2x3fvNV
+#undef glUniformMatrix2x4fv
+#undef glUniformMatrix2x4fvNV
+#undef glUniformMatrix3fv
+#undef glUniformMatrix3x2fv
+#undef glUniformMatrix3x2fvNV
+#undef glUniformMatrix3x4fv
+#undef glUniformMatrix3x4fvNV
+#undef glUniformMatrix4fv
+#undef glUniformMatrix4x2fv
+#undef glUniformMatrix4x2fvNV
+#undef glUniformMatrix4x3fv
+#undef glUniformMatrix4x3fvNV
+#undef glUnmapBuffer
+#undef glUnmapBufferOES
+#undef glUseProgram
+#undef glUseProgramStages
+#undef glUseProgramStagesEXT
+#undef glValidateProgram
+#undef glValidateProgramPipeline
+#undef glValidateProgramPipelineEXT
+#undef glVertexAttrib1f
+#undef glVertexAttrib1fv
+#undef glVertexAttrib2f
+#undef glVertexAttrib2fv
+#undef glVertexAttrib3f
+#undef glVertexAttrib3fv
+#undef glVertexAttrib4f
+#undef glVertexAttrib4fv
+#undef glVertexAttribBinding
+#undef glVertexAttribDivisor
+#undef glVertexAttribDivisorANGLE
+#undef glVertexAttribDivisorEXT
+#undef glVertexAttribDivisorNV
+#undef glVertexAttribFormat
+#undef glVertexAttribI4i
+#undef glVertexAttribI4iv
+#undef glVertexAttribI4ui
+#undef glVertexAttribI4uiv
+#undef glVertexAttribIFormat
+#undef glVertexAttribIPointer
+#undef glVertexAttribPointer
+#undef glVertexBindingDivisor
+#undef glVertexPointer
+#undef glViewport
+#undef glViewportArrayvNV
+#undef glViewportIndexedfNV
+#undef glViewportIndexedfvNV
+#undef glWaitSync
+#undef glWaitSyncAPPLE
+#undef glWeightPathsNV
+#undef glWeightPointerOES
+
+#endif // HWUI_GLES_WRAP_ENABLED
diff --git a/libs/hwui/debug/wrap_gles.cpp b/libs/hwui/debug/wrap_gles.cpp
new file mode 100644
index 0000000..c4f2e35
--- /dev/null
+++ b/libs/hwui/debug/wrap_gles.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "unwrap_gles.h"
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
+#include <GLES3/gl31.h>
+#include <GLES3/gl32.h>
+
+#include <cutils/log.h>
+
+void assertNoGlErrors(const char* apicall) {
+    GLenum status = GL_NO_ERROR;
+    GLenum lastError = GL_NO_ERROR;
+    const char* lastErrorName = nullptr;
+    while ((status = glGetError()) != GL_NO_ERROR) {
+        lastError = status;
+        switch (status) {
+        case GL_INVALID_ENUM:
+            ALOGE("GL error:  GL_INVALID_ENUM");
+            lastErrorName = "GL_INVALID_ENUM";
+            break;
+        case GL_INVALID_VALUE:
+            ALOGE("GL error:  GL_INVALID_VALUE");
+            lastErrorName = "GL_INVALID_VALUE";
+            break;
+        case GL_INVALID_OPERATION:
+            ALOGE("GL error:  GL_INVALID_OPERATION");
+            lastErrorName = "GL_INVALID_OPERATION";
+            break;
+        case GL_OUT_OF_MEMORY:
+            ALOGE("GL error:  Out of memory!");
+            lastErrorName = "GL_OUT_OF_MEMORY";
+            break;
+        default:
+            ALOGE("GL error: 0x%x", status);
+            lastErrorName = "UNKNOWN";
+        }
+    }
+    LOG_ALWAYS_FATAL_IF(lastError != GL_NO_ERROR,
+            "%s error! %s (0x%x)", apicall, lastErrorName, lastError);
+}
+
+#define API_ENTRY(x) wrap_##x
+#define CALL_GL_API(x, ...) x(__VA_ARGS__); assertNoGlErrors(#x)
+#define CALL_GL_API_RETURN(x, ...) auto ret = x(__VA_ARGS__);\
+    assertNoGlErrors(#x);\
+    return ret
+
+extern "C" {
+#include <gl2_api.in>
+#include <gl2ext_api.in>
+
+// libGLESv2 handles these specially, so they are not in gl2_api.in
+
+void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean *data) {
+    CALL_GL_API(glGetBooleanv, pname, data);
+}
+void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat *data) {
+    CALL_GL_API(glGetFloatv, pname, data);
+}
+void API_ENTRY(glGetIntegerv)(GLenum pname, GLint *data) {
+    CALL_GL_API(glGetIntegerv, pname, data);
+}
+const GLubyte * API_ENTRY(glGetString)(GLenum name) {
+    CALL_GL_API_RETURN(glGetString, name);
+}
+const GLubyte * API_ENTRY(glGetStringi)(GLenum name, GLuint index) {
+    CALL_GL_API_RETURN(glGetStringi, name, index);
+}
+void API_ENTRY(glGetInteger64v)(GLenum pname, GLint64 *data) {
+    CALL_GL_API(glGetInteger64v, pname, data);
+}
+}
diff --git a/libs/hwui/debug/wrap_gles.h b/libs/hwui/debug/wrap_gles.h
new file mode 100644
index 0000000..4a35374
--- /dev/null
+++ b/libs/hwui/debug/wrap_gles.h
@@ -0,0 +1,918 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 HWUI_GLES_WRAP_ENABLED
+#define HWUI_GLES_WRAP_ENABLED
+
+#define glActiveShaderProgram wrap_glActiveShaderProgram
+#define glActiveShaderProgramEXT wrap_glActiveShaderProgramEXT
+#define glActiveTexture wrap_glActiveTexture
+#define glAlphaFunc wrap_glAlphaFunc
+#define glAlphaFuncQCOM wrap_glAlphaFuncQCOM
+#define glAlphaFuncx wrap_glAlphaFuncx
+#define glAlphaFuncxOES wrap_glAlphaFuncxOES
+#define glApplyFramebufferAttachmentCMAAINTEL wrap_glApplyFramebufferAttachmentCMAAINTEL
+#define glAttachShader wrap_glAttachShader
+#define glBeginConditionalRenderNV wrap_glBeginConditionalRenderNV
+#define glBeginPerfMonitorAMD wrap_glBeginPerfMonitorAMD
+#define glBeginPerfQueryINTEL wrap_glBeginPerfQueryINTEL
+#define glBeginQuery wrap_glBeginQuery
+#define glBeginQueryEXT wrap_glBeginQueryEXT
+#define glBeginTransformFeedback wrap_glBeginTransformFeedback
+#define glBindAttribLocation wrap_glBindAttribLocation
+#define glBindBuffer wrap_glBindBuffer
+#define glBindBufferBase wrap_glBindBufferBase
+#define glBindBufferRange wrap_glBindBufferRange
+#define glBindFragDataLocationEXT wrap_glBindFragDataLocationEXT
+#define glBindFragDataLocationIndexedEXT wrap_glBindFragDataLocationIndexedEXT
+#define glBindFramebuffer wrap_glBindFramebuffer
+#define glBindFramebufferOES wrap_glBindFramebufferOES
+#define glBindImageTexture wrap_glBindImageTexture
+#define glBindProgramPipeline wrap_glBindProgramPipeline
+#define glBindProgramPipelineEXT wrap_glBindProgramPipelineEXT
+#define glBindRenderbuffer wrap_glBindRenderbuffer
+#define glBindRenderbufferOES wrap_glBindRenderbufferOES
+#define glBindSampler wrap_glBindSampler
+#define glBindTexture wrap_glBindTexture
+#define glBindTransformFeedback wrap_glBindTransformFeedback
+#define glBindVertexArray wrap_glBindVertexArray
+#define glBindVertexArrayOES wrap_glBindVertexArrayOES
+#define glBindVertexBuffer wrap_glBindVertexBuffer
+#define glBlendBarrier wrap_glBlendBarrier
+#define glBlendBarrierKHR wrap_glBlendBarrierKHR
+#define glBlendBarrierNV wrap_glBlendBarrierNV
+#define glBlendColor wrap_glBlendColor
+#define glBlendEquation wrap_glBlendEquation
+#define glBlendEquationOES wrap_glBlendEquationOES
+#define glBlendEquationSeparate wrap_glBlendEquationSeparate
+#define glBlendEquationSeparateOES wrap_glBlendEquationSeparateOES
+#define glBlendEquationSeparatei wrap_glBlendEquationSeparatei
+#define glBlendEquationSeparateiEXT wrap_glBlendEquationSeparateiEXT
+#define glBlendEquationSeparateiOES wrap_glBlendEquationSeparateiOES
+#define glBlendEquationi wrap_glBlendEquationi
+#define glBlendEquationiEXT wrap_glBlendEquationiEXT
+#define glBlendEquationiOES wrap_glBlendEquationiOES
+#define glBlendFunc wrap_glBlendFunc
+#define glBlendFuncSeparate wrap_glBlendFuncSeparate
+#define glBlendFuncSeparateOES wrap_glBlendFuncSeparateOES
+#define glBlendFuncSeparatei wrap_glBlendFuncSeparatei
+#define glBlendFuncSeparateiEXT wrap_glBlendFuncSeparateiEXT
+#define glBlendFuncSeparateiOES wrap_glBlendFuncSeparateiOES
+#define glBlendFunci wrap_glBlendFunci
+#define glBlendFunciEXT wrap_glBlendFunciEXT
+#define glBlendFunciOES wrap_glBlendFunciOES
+#define glBlendParameteriNV wrap_glBlendParameteriNV
+#define glBlitFramebuffer wrap_glBlitFramebuffer
+#define glBlitFramebufferANGLE wrap_glBlitFramebufferANGLE
+#define glBlitFramebufferNV wrap_glBlitFramebufferNV
+#define glBufferData wrap_glBufferData
+#define glBufferStorageEXT wrap_glBufferStorageEXT
+#define glBufferSubData wrap_glBufferSubData
+#define glCheckFramebufferStatus wrap_glCheckFramebufferStatus
+#define glCheckFramebufferStatusOES wrap_glCheckFramebufferStatusOES
+#define glClear wrap_glClear
+#define glClearBufferfi wrap_glClearBufferfi
+#define glClearBufferfv wrap_glClearBufferfv
+#define glClearBufferiv wrap_glClearBufferiv
+#define glClearBufferuiv wrap_glClearBufferuiv
+#define glClearColor wrap_glClearColor
+#define glClearColorx wrap_glClearColorx
+#define glClearColorxOES wrap_glClearColorxOES
+#define glClearDepthf wrap_glClearDepthf
+#define glClearDepthfOES wrap_glClearDepthfOES
+#define glClearDepthx wrap_glClearDepthx
+#define glClearDepthxOES wrap_glClearDepthxOES
+#define glClearStencil wrap_glClearStencil
+#define glClientActiveTexture wrap_glClientActiveTexture
+#define glClientWaitSync wrap_glClientWaitSync
+#define glClientWaitSyncAPPLE wrap_glClientWaitSyncAPPLE
+#define glClipPlanef wrap_glClipPlanef
+#define glClipPlanefIMG wrap_glClipPlanefIMG
+#define glClipPlanefOES wrap_glClipPlanefOES
+#define glClipPlanex wrap_glClipPlanex
+#define glClipPlanexIMG wrap_glClipPlanexIMG
+#define glClipPlanexOES wrap_glClipPlanexOES
+#define glColor4f wrap_glColor4f
+#define glColor4ub wrap_glColor4ub
+#define glColor4x wrap_glColor4x
+#define glColor4xOES wrap_glColor4xOES
+#define glColorMask wrap_glColorMask
+#define glColorMaski wrap_glColorMaski
+#define glColorMaskiEXT wrap_glColorMaskiEXT
+#define glColorMaskiOES wrap_glColorMaskiOES
+#define glColorPointer wrap_glColorPointer
+#define glCompileShader wrap_glCompileShader
+#define glCompressedTexImage2D wrap_glCompressedTexImage2D
+#define glCompressedTexImage3D wrap_glCompressedTexImage3D
+#define glCompressedTexImage3DOES wrap_glCompressedTexImage3DOES
+#define glCompressedTexSubImage2D wrap_glCompressedTexSubImage2D
+#define glCompressedTexSubImage3D wrap_glCompressedTexSubImage3D
+#define glCompressedTexSubImage3DOES wrap_glCompressedTexSubImage3DOES
+#define glCopyBufferSubData wrap_glCopyBufferSubData
+#define glCopyBufferSubDataNV wrap_glCopyBufferSubDataNV
+#define glCopyImageSubData wrap_glCopyImageSubData
+#define glCopyImageSubDataEXT wrap_glCopyImageSubDataEXT
+#define glCopyImageSubDataOES wrap_glCopyImageSubDataOES
+#define glCopyPathNV wrap_glCopyPathNV
+#define glCopyTexImage2D wrap_glCopyTexImage2D
+#define glCopyTexSubImage2D wrap_glCopyTexSubImage2D
+#define glCopyTexSubImage3D wrap_glCopyTexSubImage3D
+#define glCopyTexSubImage3DOES wrap_glCopyTexSubImage3DOES
+#define glCopyTextureLevelsAPPLE wrap_glCopyTextureLevelsAPPLE
+#define glCoverFillPathInstancedNV wrap_glCoverFillPathInstancedNV
+#define glCoverFillPathNV wrap_glCoverFillPathNV
+#define glCoverStrokePathInstancedNV wrap_glCoverStrokePathInstancedNV
+#define glCoverStrokePathNV wrap_glCoverStrokePathNV
+#define glCoverageMaskNV wrap_glCoverageMaskNV
+#define glCoverageModulationNV wrap_glCoverageModulationNV
+#define glCoverageModulationTableNV wrap_glCoverageModulationTableNV
+#define glCoverageOperationNV wrap_glCoverageOperationNV
+#define glCreatePerfQueryINTEL wrap_glCreatePerfQueryINTEL
+#define glCreateProgram wrap_glCreateProgram
+#define glCreateShader wrap_glCreateShader
+#define glCreateShaderProgramv wrap_glCreateShaderProgramv
+#define glCreateShaderProgramvEXT wrap_glCreateShaderProgramvEXT
+#define glCullFace wrap_glCullFace
+#define glCurrentPaletteMatrixOES wrap_glCurrentPaletteMatrixOES
+#define glDebugMessageCallback wrap_glDebugMessageCallback
+#define glDebugMessageCallbackKHR wrap_glDebugMessageCallbackKHR
+#define glDebugMessageControl wrap_glDebugMessageControl
+#define glDebugMessageControlKHR wrap_glDebugMessageControlKHR
+#define glDebugMessageInsert wrap_glDebugMessageInsert
+#define glDebugMessageInsertKHR wrap_glDebugMessageInsertKHR
+#define glDeleteBuffers wrap_glDeleteBuffers
+#define glDeleteFencesNV wrap_glDeleteFencesNV
+#define glDeleteFramebuffers wrap_glDeleteFramebuffers
+#define glDeleteFramebuffersOES wrap_glDeleteFramebuffersOES
+#define glDeletePathsNV wrap_glDeletePathsNV
+#define glDeletePerfMonitorsAMD wrap_glDeletePerfMonitorsAMD
+#define glDeletePerfQueryINTEL wrap_glDeletePerfQueryINTEL
+#define glDeleteProgram wrap_glDeleteProgram
+#define glDeleteProgramPipelines wrap_glDeleteProgramPipelines
+#define glDeleteProgramPipelinesEXT wrap_glDeleteProgramPipelinesEXT
+#define glDeleteQueries wrap_glDeleteQueries
+#define glDeleteQueriesEXT wrap_glDeleteQueriesEXT
+#define glDeleteRenderbuffers wrap_glDeleteRenderbuffers
+#define glDeleteRenderbuffersOES wrap_glDeleteRenderbuffersOES
+#define glDeleteSamplers wrap_glDeleteSamplers
+#define glDeleteShader wrap_glDeleteShader
+#define glDeleteSync wrap_glDeleteSync
+#define glDeleteSyncAPPLE wrap_glDeleteSyncAPPLE
+#define glDeleteTextures wrap_glDeleteTextures
+#define glDeleteTransformFeedbacks wrap_glDeleteTransformFeedbacks
+#define glDeleteVertexArrays wrap_glDeleteVertexArrays
+#define glDeleteVertexArraysOES wrap_glDeleteVertexArraysOES
+#define glDepthFunc wrap_glDepthFunc
+#define glDepthMask wrap_glDepthMask
+#define glDepthRangeArrayfvNV wrap_glDepthRangeArrayfvNV
+#define glDepthRangeIndexedfNV wrap_glDepthRangeIndexedfNV
+#define glDepthRangef wrap_glDepthRangef
+#define glDepthRangefOES wrap_glDepthRangefOES
+#define glDepthRangex wrap_glDepthRangex
+#define glDepthRangexOES wrap_glDepthRangexOES
+#define glDetachShader wrap_glDetachShader
+#define glDisable wrap_glDisable
+#define glDisableClientState wrap_glDisableClientState
+#define glDisableDriverControlQCOM wrap_glDisableDriverControlQCOM
+#define glDisableVertexAttribArray wrap_glDisableVertexAttribArray
+#define glDisablei wrap_glDisablei
+#define glDisableiEXT wrap_glDisableiEXT
+#define glDisableiNV wrap_glDisableiNV
+#define glDisableiOES wrap_glDisableiOES
+#define glDiscardFramebufferEXT wrap_glDiscardFramebufferEXT
+#define glDispatchCompute wrap_glDispatchCompute
+#define glDispatchComputeIndirect wrap_glDispatchComputeIndirect
+#define glDrawArrays wrap_glDrawArrays
+#define glDrawArraysIndirect wrap_glDrawArraysIndirect
+#define glDrawArraysInstanced wrap_glDrawArraysInstanced
+#define glDrawArraysInstancedANGLE wrap_glDrawArraysInstancedANGLE
+#define glDrawArraysInstancedBaseInstanceEXT wrap_glDrawArraysInstancedBaseInstanceEXT
+#define glDrawArraysInstancedEXT wrap_glDrawArraysInstancedEXT
+#define glDrawArraysInstancedNV wrap_glDrawArraysInstancedNV
+#define glDrawBuffers wrap_glDrawBuffers
+#define glDrawBuffersEXT wrap_glDrawBuffersEXT
+#define glDrawBuffersIndexedEXT wrap_glDrawBuffersIndexedEXT
+#define glDrawBuffersNV wrap_glDrawBuffersNV
+#define glDrawElements wrap_glDrawElements
+#define glDrawElementsBaseVertex wrap_glDrawElementsBaseVertex
+#define glDrawElementsBaseVertexEXT wrap_glDrawElementsBaseVertexEXT
+#define glDrawElementsBaseVertexOES wrap_glDrawElementsBaseVertexOES
+#define glDrawElementsIndirect wrap_glDrawElementsIndirect
+#define glDrawElementsInstanced wrap_glDrawElementsInstanced
+#define glDrawElementsInstancedANGLE wrap_glDrawElementsInstancedANGLE
+#define glDrawElementsInstancedBaseInstanceEXT wrap_glDrawElementsInstancedBaseInstanceEXT
+#define glDrawElementsInstancedBaseVertex wrap_glDrawElementsInstancedBaseVertex
+#define glDrawElementsInstancedBaseVertexBaseInstanceEXT wrap_glDrawElementsInstancedBaseVertexBaseInstanceEXT
+#define glDrawElementsInstancedBaseVertexEXT wrap_glDrawElementsInstancedBaseVertexEXT
+#define glDrawElementsInstancedBaseVertexOES wrap_glDrawElementsInstancedBaseVertexOES
+#define glDrawElementsInstancedEXT wrap_glDrawElementsInstancedEXT
+#define glDrawElementsInstancedNV wrap_glDrawElementsInstancedNV
+#define glDrawRangeElements wrap_glDrawRangeElements
+#define glDrawRangeElementsBaseVertex wrap_glDrawRangeElementsBaseVertex
+#define glDrawRangeElementsBaseVertexEXT wrap_glDrawRangeElementsBaseVertexEXT
+#define glDrawRangeElementsBaseVertexOES wrap_glDrawRangeElementsBaseVertexOES
+#define glDrawTexfOES wrap_glDrawTexfOES
+#define glDrawTexfvOES wrap_glDrawTexfvOES
+#define glDrawTexiOES wrap_glDrawTexiOES
+#define glDrawTexivOES wrap_glDrawTexivOES
+#define glDrawTexsOES wrap_glDrawTexsOES
+#define glDrawTexsvOES wrap_glDrawTexsvOES
+#define glDrawTexxOES wrap_glDrawTexxOES
+#define glDrawTexxvOES wrap_glDrawTexxvOES
+#define glEGLImageTargetRenderbufferStorageOES wrap_glEGLImageTargetRenderbufferStorageOES
+#define glEGLImageTargetTexture2DOES wrap_glEGLImageTargetTexture2DOES
+#define glEnable wrap_glEnable
+#define glEnableClientState wrap_glEnableClientState
+#define glEnableDriverControlQCOM wrap_glEnableDriverControlQCOM
+#define glEnableVertexAttribArray wrap_glEnableVertexAttribArray
+#define glEnablei wrap_glEnablei
+#define glEnableiEXT wrap_glEnableiEXT
+#define glEnableiNV wrap_glEnableiNV
+#define glEnableiOES wrap_glEnableiOES
+#define glEndConditionalRenderNV wrap_glEndConditionalRenderNV
+#define glEndPerfMonitorAMD wrap_glEndPerfMonitorAMD
+#define glEndPerfQueryINTEL wrap_glEndPerfQueryINTEL
+#define glEndQuery wrap_glEndQuery
+#define glEndQueryEXT wrap_glEndQueryEXT
+#define glEndTilingQCOM wrap_glEndTilingQCOM
+#define glEndTransformFeedback wrap_glEndTransformFeedback
+#define glExtGetBufferPointervQCOM wrap_glExtGetBufferPointervQCOM
+#define glExtGetBuffersQCOM wrap_glExtGetBuffersQCOM
+#define glExtGetFramebuffersQCOM wrap_glExtGetFramebuffersQCOM
+#define glExtGetProgramBinarySourceQCOM wrap_glExtGetProgramBinarySourceQCOM
+#define glExtGetProgramsQCOM wrap_glExtGetProgramsQCOM
+#define glExtGetRenderbuffersQCOM wrap_glExtGetRenderbuffersQCOM
+#define glExtGetShadersQCOM wrap_glExtGetShadersQCOM
+#define glExtGetTexLevelParameterivQCOM wrap_glExtGetTexLevelParameterivQCOM
+#define glExtGetTexSubImageQCOM wrap_glExtGetTexSubImageQCOM
+#define glExtGetTexturesQCOM wrap_glExtGetTexturesQCOM
+#define glExtIsProgramBinaryQCOM wrap_glExtIsProgramBinaryQCOM
+#define glExtTexObjectStateOverrideiQCOM wrap_glExtTexObjectStateOverrideiQCOM
+#define glFenceSync wrap_glFenceSync
+#define glFenceSyncAPPLE wrap_glFenceSyncAPPLE
+#define glFinish wrap_glFinish
+#define glFinishFenceNV wrap_glFinishFenceNV
+#define glFlush wrap_glFlush
+#define glFlushMappedBufferRange wrap_glFlushMappedBufferRange
+#define glFlushMappedBufferRangeEXT wrap_glFlushMappedBufferRangeEXT
+#define glFogf wrap_glFogf
+#define glFogfv wrap_glFogfv
+#define glFogx wrap_glFogx
+#define glFogxOES wrap_glFogxOES
+#define glFogxv wrap_glFogxv
+#define glFogxvOES wrap_glFogxvOES
+#define glFragmentCoverageColorNV wrap_glFragmentCoverageColorNV
+#define glFramebufferParameteri wrap_glFramebufferParameteri
+#define glFramebufferRenderbuffer wrap_glFramebufferRenderbuffer
+#define glFramebufferRenderbufferOES wrap_glFramebufferRenderbufferOES
+#define glFramebufferSampleLocationsfvNV wrap_glFramebufferSampleLocationsfvNV
+#define glFramebufferTexture wrap_glFramebufferTexture
+#define glFramebufferTexture2D wrap_glFramebufferTexture2D
+#define glFramebufferTexture2DMultisampleEXT wrap_glFramebufferTexture2DMultisampleEXT
+#define glFramebufferTexture2DMultisampleIMG wrap_glFramebufferTexture2DMultisampleIMG
+#define glFramebufferTexture2DOES wrap_glFramebufferTexture2DOES
+#define glFramebufferTexture3DOES wrap_glFramebufferTexture3DOES
+#define glFramebufferTextureEXT wrap_glFramebufferTextureEXT
+#define glFramebufferTextureLayer wrap_glFramebufferTextureLayer
+#define glFramebufferTextureMultisampleMultiviewOVR wrap_glFramebufferTextureMultisampleMultiviewOVR
+#define glFramebufferTextureMultiviewOVR wrap_glFramebufferTextureMultiviewOVR
+#define glFramebufferTextureOES wrap_glFramebufferTextureOES
+#define glFrontFace wrap_glFrontFace
+#define glFrustumf wrap_glFrustumf
+#define glFrustumfOES wrap_glFrustumfOES
+#define glFrustumx wrap_glFrustumx
+#define glFrustumxOES wrap_glFrustumxOES
+#define glGenBuffers wrap_glGenBuffers
+#define glGenFencesNV wrap_glGenFencesNV
+#define glGenFramebuffers wrap_glGenFramebuffers
+#define glGenFramebuffersOES wrap_glGenFramebuffersOES
+#define glGenPathsNV wrap_glGenPathsNV
+#define glGenPerfMonitorsAMD wrap_glGenPerfMonitorsAMD
+#define glGenProgramPipelines wrap_glGenProgramPipelines
+#define glGenProgramPipelinesEXT wrap_glGenProgramPipelinesEXT
+#define glGenQueries wrap_glGenQueries
+#define glGenQueriesEXT wrap_glGenQueriesEXT
+#define glGenRenderbuffers wrap_glGenRenderbuffers
+#define glGenRenderbuffersOES wrap_glGenRenderbuffersOES
+#define glGenSamplers wrap_glGenSamplers
+#define glGenTextures wrap_glGenTextures
+#define glGenTransformFeedbacks wrap_glGenTransformFeedbacks
+#define glGenVertexArrays wrap_glGenVertexArrays
+#define glGenVertexArraysOES wrap_glGenVertexArraysOES
+#define glGenerateMipmap wrap_glGenerateMipmap
+#define glGenerateMipmapOES wrap_glGenerateMipmapOES
+#define glGetActiveAttrib wrap_glGetActiveAttrib
+#define glGetActiveUniform wrap_glGetActiveUniform
+#define glGetActiveUniformBlockName wrap_glGetActiveUniformBlockName
+#define glGetActiveUniformBlockiv wrap_glGetActiveUniformBlockiv
+#define glGetActiveUniformsiv wrap_glGetActiveUniformsiv
+#define glGetAttachedShaders wrap_glGetAttachedShaders
+#define glGetAttribLocation wrap_glGetAttribLocation
+#define glGetBooleani_v wrap_glGetBooleani_v
+#define glGetBooleanv wrap_glGetBooleanv
+#define glGetBufferParameteri64v wrap_glGetBufferParameteri64v
+#define glGetBufferParameteriv wrap_glGetBufferParameteriv
+#define glGetBufferPointerv wrap_glGetBufferPointerv
+#define glGetBufferPointervOES wrap_glGetBufferPointervOES
+#define glGetClipPlanef wrap_glGetClipPlanef
+#define glGetClipPlanefOES wrap_glGetClipPlanefOES
+#define glGetClipPlanex wrap_glGetClipPlanex
+#define glGetClipPlanexOES wrap_glGetClipPlanexOES
+#define glGetCoverageModulationTableNV wrap_glGetCoverageModulationTableNV
+#define glGetDebugMessageLog wrap_glGetDebugMessageLog
+#define glGetDebugMessageLogKHR wrap_glGetDebugMessageLogKHR
+#define glGetDriverControlStringQCOM wrap_glGetDriverControlStringQCOM
+#define glGetDriverControlsQCOM wrap_glGetDriverControlsQCOM
+#define glGetError wrap_glGetError
+#define glGetFenceivNV wrap_glGetFenceivNV
+#define glGetFirstPerfQueryIdINTEL wrap_glGetFirstPerfQueryIdINTEL
+#define glGetFixedv wrap_glGetFixedv
+#define glGetFixedvOES wrap_glGetFixedvOES
+#define glGetFloati_vNV wrap_glGetFloati_vNV
+#define glGetFloatv wrap_glGetFloatv
+#define glGetFragDataIndexEXT wrap_glGetFragDataIndexEXT
+#define glGetFragDataLocation wrap_glGetFragDataLocation
+#define glGetFramebufferAttachmentParameteriv wrap_glGetFramebufferAttachmentParameteriv
+#define glGetFramebufferAttachmentParameterivOES wrap_glGetFramebufferAttachmentParameterivOES
+#define glGetFramebufferParameteriv wrap_glGetFramebufferParameteriv
+#define glGetGraphicsResetStatus wrap_glGetGraphicsResetStatus
+#define glGetGraphicsResetStatusEXT wrap_glGetGraphicsResetStatusEXT
+#define glGetGraphicsResetStatusKHR wrap_glGetGraphicsResetStatusKHR
+#define glGetImageHandleNV wrap_glGetImageHandleNV
+#define glGetInteger64i_v wrap_glGetInteger64i_v
+#define glGetInteger64v wrap_glGetInteger64v
+#define glGetInteger64vAPPLE wrap_glGetInteger64vAPPLE
+#define glGetIntegeri_v wrap_glGetIntegeri_v
+#define glGetIntegeri_vEXT wrap_glGetIntegeri_vEXT
+#define glGetIntegerv wrap_glGetIntegerv
+#define glGetInternalformatSampleivNV wrap_glGetInternalformatSampleivNV
+#define glGetInternalformativ wrap_glGetInternalformativ
+#define glGetLightfv wrap_glGetLightfv
+#define glGetLightxv wrap_glGetLightxv
+#define glGetLightxvOES wrap_glGetLightxvOES
+#define glGetMaterialfv wrap_glGetMaterialfv
+#define glGetMaterialxv wrap_glGetMaterialxv
+#define glGetMaterialxvOES wrap_glGetMaterialxvOES
+#define glGetMultisamplefv wrap_glGetMultisamplefv
+#define glGetNextPerfQueryIdINTEL wrap_glGetNextPerfQueryIdINTEL
+#define glGetObjectLabel wrap_glGetObjectLabel
+#define glGetObjectLabelEXT wrap_glGetObjectLabelEXT
+#define glGetObjectLabelKHR wrap_glGetObjectLabelKHR
+#define glGetObjectPtrLabel wrap_glGetObjectPtrLabel
+#define glGetObjectPtrLabelKHR wrap_glGetObjectPtrLabelKHR
+#define glGetPathCommandsNV wrap_glGetPathCommandsNV
+#define glGetPathCoordsNV wrap_glGetPathCoordsNV
+#define glGetPathDashArrayNV wrap_glGetPathDashArrayNV
+#define glGetPathLengthNV wrap_glGetPathLengthNV
+#define glGetPathMetricRangeNV wrap_glGetPathMetricRangeNV
+#define glGetPathMetricsNV wrap_glGetPathMetricsNV
+#define glGetPathParameterfvNV wrap_glGetPathParameterfvNV
+#define glGetPathParameterivNV wrap_glGetPathParameterivNV
+#define glGetPathSpacingNV wrap_glGetPathSpacingNV
+#define glGetPerfCounterInfoINTEL wrap_glGetPerfCounterInfoINTEL
+#define glGetPerfMonitorCounterDataAMD wrap_glGetPerfMonitorCounterDataAMD
+#define glGetPerfMonitorCounterInfoAMD wrap_glGetPerfMonitorCounterInfoAMD
+#define glGetPerfMonitorCounterStringAMD wrap_glGetPerfMonitorCounterStringAMD
+#define glGetPerfMonitorCountersAMD wrap_glGetPerfMonitorCountersAMD
+#define glGetPerfMonitorGroupStringAMD wrap_glGetPerfMonitorGroupStringAMD
+#define glGetPerfMonitorGroupsAMD wrap_glGetPerfMonitorGroupsAMD
+#define glGetPerfQueryDataINTEL wrap_glGetPerfQueryDataINTEL
+#define glGetPerfQueryIdByNameINTEL wrap_glGetPerfQueryIdByNameINTEL
+#define glGetPerfQueryInfoINTEL wrap_glGetPerfQueryInfoINTEL
+#define glGetPointerv wrap_glGetPointerv
+#define glGetPointervKHR wrap_glGetPointervKHR
+#define glGetProgramBinary wrap_glGetProgramBinary
+#define glGetProgramBinaryOES wrap_glGetProgramBinaryOES
+#define glGetProgramInfoLog wrap_glGetProgramInfoLog
+#define glGetProgramInterfaceiv wrap_glGetProgramInterfaceiv
+#define glGetProgramPipelineInfoLog wrap_glGetProgramPipelineInfoLog
+#define glGetProgramPipelineInfoLogEXT wrap_glGetProgramPipelineInfoLogEXT
+#define glGetProgramPipelineiv wrap_glGetProgramPipelineiv
+#define glGetProgramPipelineivEXT wrap_glGetProgramPipelineivEXT
+#define glGetProgramResourceIndex wrap_glGetProgramResourceIndex
+#define glGetProgramResourceLocation wrap_glGetProgramResourceLocation
+#define glGetProgramResourceLocationIndexEXT wrap_glGetProgramResourceLocationIndexEXT
+#define glGetProgramResourceName wrap_glGetProgramResourceName
+#define glGetProgramResourcefvNV wrap_glGetProgramResourcefvNV
+#define glGetProgramResourceiv wrap_glGetProgramResourceiv
+#define glGetProgramiv wrap_glGetProgramiv
+#define glGetQueryObjecti64vEXT wrap_glGetQueryObjecti64vEXT
+#define glGetQueryObjectivEXT wrap_glGetQueryObjectivEXT
+#define glGetQueryObjectui64vEXT wrap_glGetQueryObjectui64vEXT
+#define glGetQueryObjectuiv wrap_glGetQueryObjectuiv
+#define glGetQueryObjectuivEXT wrap_glGetQueryObjectuivEXT
+#define glGetQueryiv wrap_glGetQueryiv
+#define glGetQueryivEXT wrap_glGetQueryivEXT
+#define glGetRenderbufferParameteriv wrap_glGetRenderbufferParameteriv
+#define glGetRenderbufferParameterivOES wrap_glGetRenderbufferParameterivOES
+#define glGetSamplerParameterIiv wrap_glGetSamplerParameterIiv
+#define glGetSamplerParameterIivEXT wrap_glGetSamplerParameterIivEXT
+#define glGetSamplerParameterIivOES wrap_glGetSamplerParameterIivOES
+#define glGetSamplerParameterIuiv wrap_glGetSamplerParameterIuiv
+#define glGetSamplerParameterIuivEXT wrap_glGetSamplerParameterIuivEXT
+#define glGetSamplerParameterIuivOES wrap_glGetSamplerParameterIuivOES
+#define glGetSamplerParameterfv wrap_glGetSamplerParameterfv
+#define glGetSamplerParameteriv wrap_glGetSamplerParameteriv
+#define glGetShaderInfoLog wrap_glGetShaderInfoLog
+#define glGetShaderPrecisionFormat wrap_glGetShaderPrecisionFormat
+#define glGetShaderSource wrap_glGetShaderSource
+#define glGetShaderiv wrap_glGetShaderiv
+#define glGetString wrap_glGetString
+#define glGetStringi wrap_glGetStringi
+#define glGetSynciv wrap_glGetSynciv
+#define glGetSyncivAPPLE wrap_glGetSyncivAPPLE
+#define glGetTexEnvfv wrap_glGetTexEnvfv
+#define glGetTexEnviv wrap_glGetTexEnviv
+#define glGetTexEnvxv wrap_glGetTexEnvxv
+#define glGetTexEnvxvOES wrap_glGetTexEnvxvOES
+#define glGetTexGenfvOES wrap_glGetTexGenfvOES
+#define glGetTexGenivOES wrap_glGetTexGenivOES
+#define glGetTexGenxvOES wrap_glGetTexGenxvOES
+#define glGetTexLevelParameterfv wrap_glGetTexLevelParameterfv
+#define glGetTexLevelParameteriv wrap_glGetTexLevelParameteriv
+#define glGetTexParameterIiv wrap_glGetTexParameterIiv
+#define glGetTexParameterIivEXT wrap_glGetTexParameterIivEXT
+#define glGetTexParameterIivOES wrap_glGetTexParameterIivOES
+#define glGetTexParameterIuiv wrap_glGetTexParameterIuiv
+#define glGetTexParameterIuivEXT wrap_glGetTexParameterIuivEXT
+#define glGetTexParameterIuivOES wrap_glGetTexParameterIuivOES
+#define glGetTexParameterfv wrap_glGetTexParameterfv
+#define glGetTexParameteriv wrap_glGetTexParameteriv
+#define glGetTexParameterxv wrap_glGetTexParameterxv
+#define glGetTexParameterxvOES wrap_glGetTexParameterxvOES
+#define glGetTextureHandleNV wrap_glGetTextureHandleNV
+#define glGetTextureSamplerHandleNV wrap_glGetTextureSamplerHandleNV
+#define glGetTransformFeedbackVarying wrap_glGetTransformFeedbackVarying
+#define glGetTranslatedShaderSourceANGLE wrap_glGetTranslatedShaderSourceANGLE
+#define glGetUniformBlockIndex wrap_glGetUniformBlockIndex
+#define glGetUniformIndices wrap_glGetUniformIndices
+#define glGetUniformLocation wrap_glGetUniformLocation
+#define glGetUniformfv wrap_glGetUniformfv
+#define glGetUniformiv wrap_glGetUniformiv
+#define glGetUniformuiv wrap_glGetUniformuiv
+#define glGetVertexAttribIiv wrap_glGetVertexAttribIiv
+#define glGetVertexAttribIuiv wrap_glGetVertexAttribIuiv
+#define glGetVertexAttribPointerv wrap_glGetVertexAttribPointerv
+#define glGetVertexAttribfv wrap_glGetVertexAttribfv
+#define glGetVertexAttribiv wrap_glGetVertexAttribiv
+#define glGetnUniformfv wrap_glGetnUniformfv
+#define glGetnUniformfvEXT wrap_glGetnUniformfvEXT
+#define glGetnUniformfvKHR wrap_glGetnUniformfvKHR
+#define glGetnUniformiv wrap_glGetnUniformiv
+#define glGetnUniformivEXT wrap_glGetnUniformivEXT
+#define glGetnUniformivKHR wrap_glGetnUniformivKHR
+#define glGetnUniformuiv wrap_glGetnUniformuiv
+#define glGetnUniformuivKHR wrap_glGetnUniformuivKHR
+#define glHint wrap_glHint
+#define glInsertEventMarkerEXT wrap_glInsertEventMarkerEXT
+#define glInterpolatePathsNV wrap_glInterpolatePathsNV
+#define glInvalidateFramebuffer wrap_glInvalidateFramebuffer
+#define glInvalidateSubFramebuffer wrap_glInvalidateSubFramebuffer
+#define glIsBuffer wrap_glIsBuffer
+#define glIsEnabled wrap_glIsEnabled
+#define glIsEnabledi wrap_glIsEnabledi
+#define glIsEnablediEXT wrap_glIsEnablediEXT
+#define glIsEnablediNV wrap_glIsEnablediNV
+#define glIsEnablediOES wrap_glIsEnablediOES
+#define glIsFenceNV wrap_glIsFenceNV
+#define glIsFramebuffer wrap_glIsFramebuffer
+#define glIsFramebufferOES wrap_glIsFramebufferOES
+#define glIsImageHandleResidentNV wrap_glIsImageHandleResidentNV
+#define glIsPathNV wrap_glIsPathNV
+#define glIsPointInFillPathNV wrap_glIsPointInFillPathNV
+#define glIsPointInStrokePathNV wrap_glIsPointInStrokePathNV
+#define glIsProgram wrap_glIsProgram
+#define glIsProgramPipeline wrap_glIsProgramPipeline
+#define glIsProgramPipelineEXT wrap_glIsProgramPipelineEXT
+#define glIsQuery wrap_glIsQuery
+#define glIsQueryEXT wrap_glIsQueryEXT
+#define glIsRenderbuffer wrap_glIsRenderbuffer
+#define glIsRenderbufferOES wrap_glIsRenderbufferOES
+#define glIsSampler wrap_glIsSampler
+#define glIsShader wrap_glIsShader
+#define glIsSync wrap_glIsSync
+#define glIsSyncAPPLE wrap_glIsSyncAPPLE
+#define glIsTexture wrap_glIsTexture
+#define glIsTextureHandleResidentNV wrap_glIsTextureHandleResidentNV
+#define glIsTransformFeedback wrap_glIsTransformFeedback
+#define glIsVertexArray wrap_glIsVertexArray
+#define glIsVertexArrayOES wrap_glIsVertexArrayOES
+#define glLabelObjectEXT wrap_glLabelObjectEXT
+#define glLightModelf wrap_glLightModelf
+#define glLightModelfv wrap_glLightModelfv
+#define glLightModelx wrap_glLightModelx
+#define glLightModelxOES wrap_glLightModelxOES
+#define glLightModelxv wrap_glLightModelxv
+#define glLightModelxvOES wrap_glLightModelxvOES
+#define glLightf wrap_glLightf
+#define glLightfv wrap_glLightfv
+#define glLightx wrap_glLightx
+#define glLightxOES wrap_glLightxOES
+#define glLightxv wrap_glLightxv
+#define glLightxvOES wrap_glLightxvOES
+#define glLineWidth wrap_glLineWidth
+#define glLineWidthx wrap_glLineWidthx
+#define glLineWidthxOES wrap_glLineWidthxOES
+#define glLinkProgram wrap_glLinkProgram
+#define glLoadIdentity wrap_glLoadIdentity
+#define glLoadMatrixf wrap_glLoadMatrixf
+#define glLoadMatrixx wrap_glLoadMatrixx
+#define glLoadMatrixxOES wrap_glLoadMatrixxOES
+#define glLoadPaletteFromModelViewMatrixOES wrap_glLoadPaletteFromModelViewMatrixOES
+#define glLogicOp wrap_glLogicOp
+#define glMakeImageHandleNonResidentNV wrap_glMakeImageHandleNonResidentNV
+#define glMakeImageHandleResidentNV wrap_glMakeImageHandleResidentNV
+#define glMakeTextureHandleNonResidentNV wrap_glMakeTextureHandleNonResidentNV
+#define glMakeTextureHandleResidentNV wrap_glMakeTextureHandleResidentNV
+#define glMapBufferOES wrap_glMapBufferOES
+#define glMapBufferRange wrap_glMapBufferRange
+#define glMapBufferRangeEXT wrap_glMapBufferRangeEXT
+#define glMaterialf wrap_glMaterialf
+#define glMaterialfv wrap_glMaterialfv
+#define glMaterialx wrap_glMaterialx
+#define glMaterialxOES wrap_glMaterialxOES
+#define glMaterialxv wrap_glMaterialxv
+#define glMaterialxvOES wrap_glMaterialxvOES
+#define glMatrixIndexPointerOES wrap_glMatrixIndexPointerOES
+#define glMatrixLoad3x2fNV wrap_glMatrixLoad3x2fNV
+#define glMatrixLoad3x3fNV wrap_glMatrixLoad3x3fNV
+#define glMatrixLoadTranspose3x3fNV wrap_glMatrixLoadTranspose3x3fNV
+#define glMatrixMode wrap_glMatrixMode
+#define glMatrixMult3x2fNV wrap_glMatrixMult3x2fNV
+#define glMatrixMult3x3fNV wrap_glMatrixMult3x3fNV
+#define glMatrixMultTranspose3x3fNV wrap_glMatrixMultTranspose3x3fNV
+#define glMemoryBarrier wrap_glMemoryBarrier
+#define glMemoryBarrierByRegion wrap_glMemoryBarrierByRegion
+#define glMinSampleShading wrap_glMinSampleShading
+#define glMinSampleShadingOES wrap_glMinSampleShadingOES
+#define glMultMatrixf wrap_glMultMatrixf
+#define glMultMatrixx wrap_glMultMatrixx
+#define glMultMatrixxOES wrap_glMultMatrixxOES
+#define glMultiDrawArraysEXT wrap_glMultiDrawArraysEXT
+#define glMultiDrawArraysIndirectEXT wrap_glMultiDrawArraysIndirectEXT
+#define glMultiDrawElementsBaseVertexEXT wrap_glMultiDrawElementsBaseVertexEXT
+#define glMultiDrawElementsBaseVertexOES wrap_glMultiDrawElementsBaseVertexOES
+#define glMultiDrawElementsEXT wrap_glMultiDrawElementsEXT
+#define glMultiDrawElementsIndirectEXT wrap_glMultiDrawElementsIndirectEXT
+#define glMultiTexCoord4f wrap_glMultiTexCoord4f
+#define glMultiTexCoord4x wrap_glMultiTexCoord4x
+#define glMultiTexCoord4xOES wrap_glMultiTexCoord4xOES
+#define glNamedFramebufferSampleLocationsfvNV wrap_glNamedFramebufferSampleLocationsfvNV
+#define glNormal3f wrap_glNormal3f
+#define glNormal3x wrap_glNormal3x
+#define glNormal3xOES wrap_glNormal3xOES
+#define glNormalPointer wrap_glNormalPointer
+#define glObjectLabel wrap_glObjectLabel
+#define glObjectLabelKHR wrap_glObjectLabelKHR
+#define glObjectPtrLabel wrap_glObjectPtrLabel
+#define glObjectPtrLabelKHR wrap_glObjectPtrLabelKHR
+#define glOrthof wrap_glOrthof
+#define glOrthofOES wrap_glOrthofOES
+#define glOrthox wrap_glOrthox
+#define glOrthoxOES wrap_glOrthoxOES
+#define glPatchParameteri wrap_glPatchParameteri
+#define glPatchParameteriEXT wrap_glPatchParameteriEXT
+#define glPatchParameteriOES wrap_glPatchParameteriOES
+#define glPathCommandsNV wrap_glPathCommandsNV
+#define glPathCoordsNV wrap_glPathCoordsNV
+#define glPathCoverDepthFuncNV wrap_glPathCoverDepthFuncNV
+#define glPathDashArrayNV wrap_glPathDashArrayNV
+#define glPathGlyphIndexArrayNV wrap_glPathGlyphIndexArrayNV
+#define glPathGlyphIndexRangeNV wrap_glPathGlyphIndexRangeNV
+#define glPathGlyphRangeNV wrap_glPathGlyphRangeNV
+#define glPathGlyphsNV wrap_glPathGlyphsNV
+#define glPathMemoryGlyphIndexArrayNV wrap_glPathMemoryGlyphIndexArrayNV
+#define glPathParameterfNV wrap_glPathParameterfNV
+#define glPathParameterfvNV wrap_glPathParameterfvNV
+#define glPathParameteriNV wrap_glPathParameteriNV
+#define glPathParameterivNV wrap_glPathParameterivNV
+#define glPathStencilDepthOffsetNV wrap_glPathStencilDepthOffsetNV
+#define glPathStencilFuncNV wrap_glPathStencilFuncNV
+#define glPathStringNV wrap_glPathStringNV
+#define glPathSubCommandsNV wrap_glPathSubCommandsNV
+#define glPathSubCoordsNV wrap_glPathSubCoordsNV
+#define glPauseTransformFeedback wrap_glPauseTransformFeedback
+#define glPixelStorei wrap_glPixelStorei
+#define glPointAlongPathNV wrap_glPointAlongPathNV
+#define glPointParameterf wrap_glPointParameterf
+#define glPointParameterfv wrap_glPointParameterfv
+#define glPointParameterx wrap_glPointParameterx
+#define glPointParameterxOES wrap_glPointParameterxOES
+#define glPointParameterxv wrap_glPointParameterxv
+#define glPointParameterxvOES wrap_glPointParameterxvOES
+#define glPointSize wrap_glPointSize
+#define glPointSizePointerOES wrap_glPointSizePointerOES
+#define glPointSizex wrap_glPointSizex
+#define glPointSizexOES wrap_glPointSizexOES
+#define glPolygonModeNV wrap_glPolygonModeNV
+#define glPolygonOffset wrap_glPolygonOffset
+#define glPolygonOffsetx wrap_glPolygonOffsetx
+#define glPolygonOffsetxOES wrap_glPolygonOffsetxOES
+#define glPopDebugGroup wrap_glPopDebugGroup
+#define glPopDebugGroupKHR wrap_glPopDebugGroupKHR
+#define glPopGroupMarkerEXT wrap_glPopGroupMarkerEXT
+#define glPopMatrix wrap_glPopMatrix
+#define glPrimitiveBoundingBox wrap_glPrimitiveBoundingBox
+#define glPrimitiveBoundingBoxEXT wrap_glPrimitiveBoundingBoxEXT
+#define glPrimitiveBoundingBoxOES wrap_glPrimitiveBoundingBoxOES
+#define glProgramBinary wrap_glProgramBinary
+#define glProgramBinaryOES wrap_glProgramBinaryOES
+#define glProgramParameteri wrap_glProgramParameteri
+#define glProgramParameteriEXT wrap_glProgramParameteriEXT
+#define glProgramPathFragmentInputGenNV wrap_glProgramPathFragmentInputGenNV
+#define glProgramUniform1f wrap_glProgramUniform1f
+#define glProgramUniform1fEXT wrap_glProgramUniform1fEXT
+#define glProgramUniform1fv wrap_glProgramUniform1fv
+#define glProgramUniform1fvEXT wrap_glProgramUniform1fvEXT
+#define glProgramUniform1i wrap_glProgramUniform1i
+#define glProgramUniform1iEXT wrap_glProgramUniform1iEXT
+#define glProgramUniform1iv wrap_glProgramUniform1iv
+#define glProgramUniform1ivEXT wrap_glProgramUniform1ivEXT
+#define glProgramUniform1ui wrap_glProgramUniform1ui
+#define glProgramUniform1uiEXT wrap_glProgramUniform1uiEXT
+#define glProgramUniform1uiv wrap_glProgramUniform1uiv
+#define glProgramUniform1uivEXT wrap_glProgramUniform1uivEXT
+#define glProgramUniform2f wrap_glProgramUniform2f
+#define glProgramUniform2fEXT wrap_glProgramUniform2fEXT
+#define glProgramUniform2fv wrap_glProgramUniform2fv
+#define glProgramUniform2fvEXT wrap_glProgramUniform2fvEXT
+#define glProgramUniform2i wrap_glProgramUniform2i
+#define glProgramUniform2iEXT wrap_glProgramUniform2iEXT
+#define glProgramUniform2iv wrap_glProgramUniform2iv
+#define glProgramUniform2ivEXT wrap_glProgramUniform2ivEXT
+#define glProgramUniform2ui wrap_glProgramUniform2ui
+#define glProgramUniform2uiEXT wrap_glProgramUniform2uiEXT
+#define glProgramUniform2uiv wrap_glProgramUniform2uiv
+#define glProgramUniform2uivEXT wrap_glProgramUniform2uivEXT
+#define glProgramUniform3f wrap_glProgramUniform3f
+#define glProgramUniform3fEXT wrap_glProgramUniform3fEXT
+#define glProgramUniform3fv wrap_glProgramUniform3fv
+#define glProgramUniform3fvEXT wrap_glProgramUniform3fvEXT
+#define glProgramUniform3i wrap_glProgramUniform3i
+#define glProgramUniform3iEXT wrap_glProgramUniform3iEXT
+#define glProgramUniform3iv wrap_glProgramUniform3iv
+#define glProgramUniform3ivEXT wrap_glProgramUniform3ivEXT
+#define glProgramUniform3ui wrap_glProgramUniform3ui
+#define glProgramUniform3uiEXT wrap_glProgramUniform3uiEXT
+#define glProgramUniform3uiv wrap_glProgramUniform3uiv
+#define glProgramUniform3uivEXT wrap_glProgramUniform3uivEXT
+#define glProgramUniform4f wrap_glProgramUniform4f
+#define glProgramUniform4fEXT wrap_glProgramUniform4fEXT
+#define glProgramUniform4fv wrap_glProgramUniform4fv
+#define glProgramUniform4fvEXT wrap_glProgramUniform4fvEXT
+#define glProgramUniform4i wrap_glProgramUniform4i
+#define glProgramUniform4iEXT wrap_glProgramUniform4iEXT
+#define glProgramUniform4iv wrap_glProgramUniform4iv
+#define glProgramUniform4ivEXT wrap_glProgramUniform4ivEXT
+#define glProgramUniform4ui wrap_glProgramUniform4ui
+#define glProgramUniform4uiEXT wrap_glProgramUniform4uiEXT
+#define glProgramUniform4uiv wrap_glProgramUniform4uiv
+#define glProgramUniform4uivEXT wrap_glProgramUniform4uivEXT
+#define glProgramUniformHandleui64NV wrap_glProgramUniformHandleui64NV
+#define glProgramUniformHandleui64vNV wrap_glProgramUniformHandleui64vNV
+#define glProgramUniformMatrix2fv wrap_glProgramUniformMatrix2fv
+#define glProgramUniformMatrix2fvEXT wrap_glProgramUniformMatrix2fvEXT
+#define glProgramUniformMatrix2x3fv wrap_glProgramUniformMatrix2x3fv
+#define glProgramUniformMatrix2x3fvEXT wrap_glProgramUniformMatrix2x3fvEXT
+#define glProgramUniformMatrix2x4fv wrap_glProgramUniformMatrix2x4fv
+#define glProgramUniformMatrix2x4fvEXT wrap_glProgramUniformMatrix2x4fvEXT
+#define glProgramUniformMatrix3fv wrap_glProgramUniformMatrix3fv
+#define glProgramUniformMatrix3fvEXT wrap_glProgramUniformMatrix3fvEXT
+#define glProgramUniformMatrix3x2fv wrap_glProgramUniformMatrix3x2fv
+#define glProgramUniformMatrix3x2fvEXT wrap_glProgramUniformMatrix3x2fvEXT
+#define glProgramUniformMatrix3x4fv wrap_glProgramUniformMatrix3x4fv
+#define glProgramUniformMatrix3x4fvEXT wrap_glProgramUniformMatrix3x4fvEXT
+#define glProgramUniformMatrix4fv wrap_glProgramUniformMatrix4fv
+#define glProgramUniformMatrix4fvEXT wrap_glProgramUniformMatrix4fvEXT
+#define glProgramUniformMatrix4x2fv wrap_glProgramUniformMatrix4x2fv
+#define glProgramUniformMatrix4x2fvEXT wrap_glProgramUniformMatrix4x2fvEXT
+#define glProgramUniformMatrix4x3fv wrap_glProgramUniformMatrix4x3fv
+#define glProgramUniformMatrix4x3fvEXT wrap_glProgramUniformMatrix4x3fvEXT
+#define glPushDebugGroup wrap_glPushDebugGroup
+#define glPushDebugGroupKHR wrap_glPushDebugGroupKHR
+#define glPushGroupMarkerEXT wrap_glPushGroupMarkerEXT
+#define glPushMatrix wrap_glPushMatrix
+#define glQueryCounterEXT wrap_glQueryCounterEXT
+#define glQueryMatrixxOES wrap_glQueryMatrixxOES
+#define glRasterSamplesEXT wrap_glRasterSamplesEXT
+#define glReadBuffer wrap_glReadBuffer
+#define glReadBufferIndexedEXT wrap_glReadBufferIndexedEXT
+#define glReadBufferNV wrap_glReadBufferNV
+#define glReadPixels wrap_glReadPixels
+#define glReadnPixels wrap_glReadnPixels
+#define glReadnPixelsEXT wrap_glReadnPixelsEXT
+#define glReadnPixelsKHR wrap_glReadnPixelsKHR
+#define glReleaseShaderCompiler wrap_glReleaseShaderCompiler
+#define glRenderbufferStorage wrap_glRenderbufferStorage
+#define glRenderbufferStorageMultisample wrap_glRenderbufferStorageMultisample
+#define glRenderbufferStorageMultisampleANGLE wrap_glRenderbufferStorageMultisampleANGLE
+#define glRenderbufferStorageMultisampleAPPLE wrap_glRenderbufferStorageMultisampleAPPLE
+#define glRenderbufferStorageMultisampleEXT wrap_glRenderbufferStorageMultisampleEXT
+#define glRenderbufferStorageMultisampleIMG wrap_glRenderbufferStorageMultisampleIMG
+#define glRenderbufferStorageMultisampleNV wrap_glRenderbufferStorageMultisampleNV
+#define glRenderbufferStorageOES wrap_glRenderbufferStorageOES
+#define glResolveDepthValuesNV wrap_glResolveDepthValuesNV
+#define glResolveMultisampleFramebufferAPPLE wrap_glResolveMultisampleFramebufferAPPLE
+#define glResumeTransformFeedback wrap_glResumeTransformFeedback
+#define glRotatef wrap_glRotatef
+#define glRotatex wrap_glRotatex
+#define glRotatexOES wrap_glRotatexOES
+#define glSampleCoverage wrap_glSampleCoverage
+#define glSampleCoveragex wrap_glSampleCoveragex
+#define glSampleCoveragexOES wrap_glSampleCoveragexOES
+#define glSampleMaski wrap_glSampleMaski
+#define glSamplerParameterIiv wrap_glSamplerParameterIiv
+#define glSamplerParameterIivEXT wrap_glSamplerParameterIivEXT
+#define glSamplerParameterIivOES wrap_glSamplerParameterIivOES
+#define glSamplerParameterIuiv wrap_glSamplerParameterIuiv
+#define glSamplerParameterIuivEXT wrap_glSamplerParameterIuivEXT
+#define glSamplerParameterIuivOES wrap_glSamplerParameterIuivOES
+#define glSamplerParameterf wrap_glSamplerParameterf
+#define glSamplerParameterfv wrap_glSamplerParameterfv
+#define glSamplerParameteri wrap_glSamplerParameteri
+#define glSamplerParameteriv wrap_glSamplerParameteriv
+#define glScalef wrap_glScalef
+#define glScalex wrap_glScalex
+#define glScalexOES wrap_glScalexOES
+#define glScissor wrap_glScissor
+#define glScissorArrayvNV wrap_glScissorArrayvNV
+#define glScissorIndexedNV wrap_glScissorIndexedNV
+#define glScissorIndexedvNV wrap_glScissorIndexedvNV
+#define glSelectPerfMonitorCountersAMD wrap_glSelectPerfMonitorCountersAMD
+#define glSetFenceNV wrap_glSetFenceNV
+#define glShadeModel wrap_glShadeModel
+#define glShaderBinary wrap_glShaderBinary
+#define glShaderSource wrap_glShaderSource
+#define glStartTilingQCOM wrap_glStartTilingQCOM
+#define glStencilFillPathInstancedNV wrap_glStencilFillPathInstancedNV
+#define glStencilFillPathNV wrap_glStencilFillPathNV
+#define glStencilFunc wrap_glStencilFunc
+#define glStencilFuncSeparate wrap_glStencilFuncSeparate
+#define glStencilMask wrap_glStencilMask
+#define glStencilMaskSeparate wrap_glStencilMaskSeparate
+#define glStencilOp wrap_glStencilOp
+#define glStencilOpSeparate wrap_glStencilOpSeparate
+#define glStencilStrokePathInstancedNV wrap_glStencilStrokePathInstancedNV
+#define glStencilStrokePathNV wrap_glStencilStrokePathNV
+#define glStencilThenCoverFillPathInstancedNV wrap_glStencilThenCoverFillPathInstancedNV
+#define glStencilThenCoverFillPathNV wrap_glStencilThenCoverFillPathNV
+#define glStencilThenCoverStrokePathInstancedNV wrap_glStencilThenCoverStrokePathInstancedNV
+#define glStencilThenCoverStrokePathNV wrap_glStencilThenCoverStrokePathNV
+#define glSubpixelPrecisionBiasNV wrap_glSubpixelPrecisionBiasNV
+#define glTestFenceNV wrap_glTestFenceNV
+#define glTexBuffer wrap_glTexBuffer
+#define glTexBufferEXT wrap_glTexBufferEXT
+#define glTexBufferOES wrap_glTexBufferOES
+#define glTexBufferRange wrap_glTexBufferRange
+#define glTexBufferRangeEXT wrap_glTexBufferRangeEXT
+#define glTexBufferRangeOES wrap_glTexBufferRangeOES
+#define glTexCoordPointer wrap_glTexCoordPointer
+#define glTexEnvf wrap_glTexEnvf
+#define glTexEnvfv wrap_glTexEnvfv
+#define glTexEnvi wrap_glTexEnvi
+#define glTexEnviv wrap_glTexEnviv
+#define glTexEnvx wrap_glTexEnvx
+#define glTexEnvxOES wrap_glTexEnvxOES
+#define glTexEnvxv wrap_glTexEnvxv
+#define glTexEnvxvOES wrap_glTexEnvxvOES
+#define glTexGenfOES wrap_glTexGenfOES
+#define glTexGenfvOES wrap_glTexGenfvOES
+#define glTexGeniOES wrap_glTexGeniOES
+#define glTexGenivOES wrap_glTexGenivOES
+#define glTexGenxOES wrap_glTexGenxOES
+#define glTexGenxvOES wrap_glTexGenxvOES
+#define glTexImage2D wrap_glTexImage2D
+#define glTexImage3D wrap_glTexImage3D
+#define glTexImage3DOES wrap_glTexImage3DOES
+#define glTexPageCommitmentEXT wrap_glTexPageCommitmentEXT
+#define glTexParameterIiv wrap_glTexParameterIiv
+#define glTexParameterIivEXT wrap_glTexParameterIivEXT
+#define glTexParameterIivOES wrap_glTexParameterIivOES
+#define glTexParameterIuiv wrap_glTexParameterIuiv
+#define glTexParameterIuivEXT wrap_glTexParameterIuivEXT
+#define glTexParameterIuivOES wrap_glTexParameterIuivOES
+#define glTexParameterf wrap_glTexParameterf
+#define glTexParameterfv wrap_glTexParameterfv
+#define glTexParameteri wrap_glTexParameteri
+#define glTexParameteriv wrap_glTexParameteriv
+#define glTexParameterx wrap_glTexParameterx
+#define glTexParameterxOES wrap_glTexParameterxOES
+#define glTexParameterxv wrap_glTexParameterxv
+#define glTexParameterxvOES wrap_glTexParameterxvOES
+#define glTexStorage1DEXT wrap_glTexStorage1DEXT
+#define glTexStorage2D wrap_glTexStorage2D
+#define glTexStorage2DEXT wrap_glTexStorage2DEXT
+#define glTexStorage2DMultisample wrap_glTexStorage2DMultisample
+#define glTexStorage3D wrap_glTexStorage3D
+#define glTexStorage3DEXT wrap_glTexStorage3DEXT
+#define glTexStorage3DMultisample wrap_glTexStorage3DMultisample
+#define glTexStorage3DMultisampleOES wrap_glTexStorage3DMultisampleOES
+#define glTexSubImage2D wrap_glTexSubImage2D
+#define glTexSubImage3D wrap_glTexSubImage3D
+#define glTexSubImage3DOES wrap_glTexSubImage3DOES
+#define glTextureStorage1DEXT wrap_glTextureStorage1DEXT
+#define glTextureStorage2DEXT wrap_glTextureStorage2DEXT
+#define glTextureStorage3DEXT wrap_glTextureStorage3DEXT
+#define glTextureViewEXT wrap_glTextureViewEXT
+#define glTextureViewOES wrap_glTextureViewOES
+#define glTransformFeedbackVaryings wrap_glTransformFeedbackVaryings
+#define glTransformPathNV wrap_glTransformPathNV
+#define glTranslatef wrap_glTranslatef
+#define glTranslatex wrap_glTranslatex
+#define glTranslatexOES wrap_glTranslatexOES
+#define glUniform1f wrap_glUniform1f
+#define glUniform1fv wrap_glUniform1fv
+#define glUniform1i wrap_glUniform1i
+#define glUniform1iv wrap_glUniform1iv
+#define glUniform1ui wrap_glUniform1ui
+#define glUniform1uiv wrap_glUniform1uiv
+#define glUniform2f wrap_glUniform2f
+#define glUniform2fv wrap_glUniform2fv
+#define glUniform2i wrap_glUniform2i
+#define glUniform2iv wrap_glUniform2iv
+#define glUniform2ui wrap_glUniform2ui
+#define glUniform2uiv wrap_glUniform2uiv
+#define glUniform3f wrap_glUniform3f
+#define glUniform3fv wrap_glUniform3fv
+#define glUniform3i wrap_glUniform3i
+#define glUniform3iv wrap_glUniform3iv
+#define glUniform3ui wrap_glUniform3ui
+#define glUniform3uiv wrap_glUniform3uiv
+#define glUniform4f wrap_glUniform4f
+#define glUniform4fv wrap_glUniform4fv
+#define glUniform4i wrap_glUniform4i
+#define glUniform4iv wrap_glUniform4iv
+#define glUniform4ui wrap_glUniform4ui
+#define glUniform4uiv wrap_glUniform4uiv
+#define glUniformBlockBinding wrap_glUniformBlockBinding
+#define glUniformHandleui64NV wrap_glUniformHandleui64NV
+#define glUniformHandleui64vNV wrap_glUniformHandleui64vNV
+#define glUniformMatrix2fv wrap_glUniformMatrix2fv
+#define glUniformMatrix2x3fv wrap_glUniformMatrix2x3fv
+#define glUniformMatrix2x3fvNV wrap_glUniformMatrix2x3fvNV
+#define glUniformMatrix2x4fv wrap_glUniformMatrix2x4fv
+#define glUniformMatrix2x4fvNV wrap_glUniformMatrix2x4fvNV
+#define glUniformMatrix3fv wrap_glUniformMatrix3fv
+#define glUniformMatrix3x2fv wrap_glUniformMatrix3x2fv
+#define glUniformMatrix3x2fvNV wrap_glUniformMatrix3x2fvNV
+#define glUniformMatrix3x4fv wrap_glUniformMatrix3x4fv
+#define glUniformMatrix3x4fvNV wrap_glUniformMatrix3x4fvNV
+#define glUniformMatrix4fv wrap_glUniformMatrix4fv
+#define glUniformMatrix4x2fv wrap_glUniformMatrix4x2fv
+#define glUniformMatrix4x2fvNV wrap_glUniformMatrix4x2fvNV
+#define glUniformMatrix4x3fv wrap_glUniformMatrix4x3fv
+#define glUniformMatrix4x3fvNV wrap_glUniformMatrix4x3fvNV
+#define glUnmapBuffer wrap_glUnmapBuffer
+#define glUnmapBufferOES wrap_glUnmapBufferOES
+#define glUseProgram wrap_glUseProgram
+#define glUseProgramStages wrap_glUseProgramStages
+#define glUseProgramStagesEXT wrap_glUseProgramStagesEXT
+#define glValidateProgram wrap_glValidateProgram
+#define glValidateProgramPipeline wrap_glValidateProgramPipeline
+#define glValidateProgramPipelineEXT wrap_glValidateProgramPipelineEXT
+#define glVertexAttrib1f wrap_glVertexAttrib1f
+#define glVertexAttrib1fv wrap_glVertexAttrib1fv
+#define glVertexAttrib2f wrap_glVertexAttrib2f
+#define glVertexAttrib2fv wrap_glVertexAttrib2fv
+#define glVertexAttrib3f wrap_glVertexAttrib3f
+#define glVertexAttrib3fv wrap_glVertexAttrib3fv
+#define glVertexAttrib4f wrap_glVertexAttrib4f
+#define glVertexAttrib4fv wrap_glVertexAttrib4fv
+#define glVertexAttribBinding wrap_glVertexAttribBinding
+#define glVertexAttribDivisor wrap_glVertexAttribDivisor
+#define glVertexAttribDivisorANGLE wrap_glVertexAttribDivisorANGLE
+#define glVertexAttribDivisorEXT wrap_glVertexAttribDivisorEXT
+#define glVertexAttribDivisorNV wrap_glVertexAttribDivisorNV
+#define glVertexAttribFormat wrap_glVertexAttribFormat
+#define glVertexAttribI4i wrap_glVertexAttribI4i
+#define glVertexAttribI4iv wrap_glVertexAttribI4iv
+#define glVertexAttribI4ui wrap_glVertexAttribI4ui
+#define glVertexAttribI4uiv wrap_glVertexAttribI4uiv
+#define glVertexAttribIFormat wrap_glVertexAttribIFormat
+#define glVertexAttribIPointer wrap_glVertexAttribIPointer
+#define glVertexAttribPointer wrap_glVertexAttribPointer
+#define glVertexBindingDivisor wrap_glVertexBindingDivisor
+#define glVertexPointer wrap_glVertexPointer
+#define glViewport wrap_glViewport
+#define glViewportArrayvNV wrap_glViewportArrayvNV
+#define glViewportIndexedfNV wrap_glViewportIndexedfNV
+#define glViewportIndexedfvNV wrap_glViewportIndexedfvNV
+#define glWaitSync wrap_glWaitSync
+#define glWaitSyncAPPLE wrap_glWaitSyncAPPLE
+#define glWeightPathsNV wrap_glWeightPathsNV
+#define glWeightPointerOES wrap_glWeightPointerOES
+
+#endif // HWUI_GLES_WRAP_ENABLED
diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
index d2685da..8ba4761 100644
--- a/libs/hwui/font/CacheTexture.cpp
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -111,11 +111,11 @@
 
 CacheTexture::CacheTexture(uint16_t width, uint16_t height, GLenum format, uint32_t maxQuadCount)
         : mTexture(Caches::getInstance())
+        , mWidth(width)
+        , mHeight(height)
         , mFormat(format)
         , mMaxQuadCount(maxQuadCount)
         , mCaches(Caches::getInstance()) {
-    mTexture.width = width;
-    mTexture.height = height;
     mTexture.blend = true;
 
     mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
@@ -160,10 +160,7 @@
         delete mPixelBuffer;
         mPixelBuffer = nullptr;
     }
-    if (mTexture.id) {
-        mCaches.textureState().deleteTexture(mTexture.id);
-        mTexture.id = 0;
-    }
+    mTexture.deleteTexture();
     mDirty = false;
     mCurrentQuad = 0;
 }
@@ -183,22 +180,9 @@
         mPixelBuffer = PixelBuffer::create(mFormat, getWidth(), getHeight());
     }
 
-    if (!mTexture.id) {
-        glGenTextures(1, &mTexture.id);
-
-        mCaches.textureState().bindTexture(mTexture.id);
-        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-        // Initialize texture dimensions
-        glTexImage2D(GL_TEXTURE_2D, 0, mFormat, getWidth(), getHeight(), 0,
-                mFormat, GL_UNSIGNED_BYTE, nullptr);
-
-        const GLenum filtering = getLinearFiltering() ? GL_LINEAR : GL_NEAREST;
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
-
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-    }
+    mTexture.resize(mWidth, mHeight, mFormat);
+    mTexture.setFilter(getLinearFiltering() ? GL_LINEAR : GL_NEAREST);
+    mTexture.setWrap(GL_CLAMP_TO_EDGE);
 }
 
 bool CacheTexture::upload() {
diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h
index 6dabc76..5510666 100644
--- a/libs/hwui/font/CacheTexture.h
+++ b/libs/hwui/font/CacheTexture.h
@@ -92,11 +92,11 @@
     bool fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY);
 
     inline uint16_t getWidth() const {
-        return mTexture.width;
+        return mWidth;
     }
 
     inline uint16_t getHeight() const {
-        return mTexture.height;
+        return mHeight;
     }
 
     inline GLenum getFormat() const {
@@ -122,7 +122,7 @@
 
     GLuint getTextureId() {
         allocatePixelBuffer();
-        return mTexture.id;
+        return mTexture.id();
     }
 
     inline bool isDirty() const {
@@ -183,6 +183,7 @@
 
     PixelBuffer* mPixelBuffer = nullptr;
     Texture mTexture;
+    uint32_t mWidth, mHeight;
     GLenum mFormat;
     bool mLinearFiltering = false;
     bool mDirty = false;
diff --git a/libs/hwui/renderstate/OffscreenBufferPool.cpp b/libs/hwui/renderstate/OffscreenBufferPool.cpp
index 6b44557..54f38e8 100644
--- a/libs/hwui/renderstate/OffscreenBufferPool.cpp
+++ b/libs/hwui/renderstate/OffscreenBufferPool.cpp
@@ -34,24 +34,24 @@
 
 OffscreenBuffer::OffscreenBuffer(RenderState& renderState, Caches& caches,
         uint32_t viewportWidth, uint32_t viewportHeight)
-        : renderState(renderState)
+        : GpuMemoryTracker(GpuObjectType::OffscreenBuffer)
+        , renderState(renderState)
         , viewportWidth(viewportWidth)
         , viewportHeight(viewportHeight)
         , texture(caches) {
-    texture.width = computeIdealDimension(viewportWidth);
-    texture.height = computeIdealDimension(viewportHeight);
-    texture.blend = true;
-
+    uint32_t width = computeIdealDimension(viewportWidth);
+    uint32_t height = computeIdealDimension(viewportHeight);
     caches.textureState().activateTexture(0);
-    glGenTextures(1, &texture.id);
-    caches.textureState().bindTexture(GL_TEXTURE_2D, texture.id);
-
-    texture.setWrap(GL_CLAMP_TO_EDGE, false, false, GL_TEXTURE_2D);
+    texture.resize(width, height, GL_RGBA);
+    texture.blend = true;
+    texture.setWrap(GL_CLAMP_TO_EDGE);
     // not setting filter on texture, since it's set when drawing, based on transform
+}
 
-    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0,
-            GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+Rect OffscreenBuffer::getTextureCoordinates() {
+    const float texX = 1.0f / static_cast<float>(texture.width());
+    const float texY = 1.0f / static_cast<float>(texture.height());
+    return Rect(0, viewportHeight * texY, viewportWidth * texX, 0);
 }
 
 void OffscreenBuffer::updateMeshFromRegion() {
@@ -63,8 +63,8 @@
     size_t count;
     const android::Rect* rects = safeRegion.getArray(&count);
 
-    const float texX = 1.0f / float(texture.width);
-    const float texY = 1.0f / float(texture.height);
+    const float texX = 1.0f / float(texture.width());
+    const float texY = 1.0f / float(texture.height());
 
     FatVector<TextureVertex, 64> meshVector(count * 4); // uses heap if more than 64 vertices needed
     TextureVertex* mesh = &meshVector[0];
@@ -151,8 +151,8 @@
 OffscreenBuffer* OffscreenBufferPool::resize(OffscreenBuffer* layer,
         const uint32_t width, const uint32_t height) {
     RenderState& renderState = layer->renderState;
-    if (layer->texture.width == OffscreenBuffer::computeIdealDimension(width)
-            && layer->texture.height == OffscreenBuffer::computeIdealDimension(height)) {
+    if (layer->texture.width() == OffscreenBuffer::computeIdealDimension(width)
+            && layer->texture.height() == OffscreenBuffer::computeIdealDimension(height)) {
         // resize in place
         layer->viewportWidth = width;
         layer->viewportHeight = height;
diff --git a/libs/hwui/renderstate/OffscreenBufferPool.h b/libs/hwui/renderstate/OffscreenBufferPool.h
index fac6c35..94155ef 100644
--- a/libs/hwui/renderstate/OffscreenBufferPool.h
+++ b/libs/hwui/renderstate/OffscreenBufferPool.h
@@ -17,10 +17,10 @@
 #ifndef ANDROID_HWUI_OFFSCREEN_BUFFER_POOL_H
 #define ANDROID_HWUI_OFFSCREEN_BUFFER_POOL_H
 
+#include <GpuMemoryTracker.h>
 #include "Caches.h"
 #include "Texture.h"
 #include "utils/Macros.h"
-
 #include <ui/Region.h>
 
 #include <set>
@@ -40,12 +40,14 @@
  * viewport bounds, since textures are always allocated with width / height as a multiple of 64, for
  * the purpose of improving reuse.
  */
-class OffscreenBuffer {
+class OffscreenBuffer : GpuMemoryTracker {
 public:
     OffscreenBuffer(RenderState& renderState, Caches& caches,
             uint32_t viewportWidth, uint32_t viewportHeight);
     ~OffscreenBuffer();
 
+    Rect getTextureCoordinates();
+
     // must be called prior to rendering, to construct/update vertex buffer
     void updateMeshFromRegion();
 
@@ -56,7 +58,7 @@
 
     static uint32_t computeIdealDimension(uint32_t dimension);
 
-    uint32_t getSizeInBytes() { return texture.width * texture.height * 4; }
+    uint32_t getSizeInBytes() { return texture.objectSize(); }
 
     RenderState& renderState;
 
@@ -122,8 +124,8 @@
 
         Entry(OffscreenBuffer* layer)
                 : layer(layer)
-                , width(layer->texture.width)
-                , height(layer->texture.height) {
+                , width(layer->texture.width())
+                , height(layer->texture.height()) {
         }
 
         static int compare(const Entry& lhs, const Entry& rhs);
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index 4fa8200..81363d9 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -13,12 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include <GpuMemoryTracker.h>
 #include "renderstate/RenderState.h"
 
 #include "renderthread/CanvasContext.h"
 #include "renderthread/EglManager.h"
 #include "utils/GLUtils.h"
-
 #include <algorithm>
 
 namespace android {
@@ -40,6 +40,8 @@
 void RenderState::onGLContextCreated() {
     LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
             "State object lifecycle not managed correctly");
+    GpuMemoryTracker::onGLContextCreated();
+
     mBlend = new Blend();
     mMeshState = new MeshState();
     mScissor = new Scissor();
@@ -106,6 +108,8 @@
     mScissor = nullptr;
     delete mStencil;
     mStencil = nullptr;
+
+    GpuMemoryTracker::onGLContextDestroyed();
 }
 
 void RenderState::flush(Caches::FlushMode mode) {
@@ -205,17 +209,6 @@
     }
 }
 
-void RenderState::requireGLContext() {
-    assertOnGLThread();
-    LOG_ALWAYS_FATAL_IF(!mRenderThread.eglManager().hasEglContext(),
-            "No GL context!");
-}
-
-void RenderState::assertOnGLThread() {
-    pthread_t curr = pthread_self();
-    LOG_ALWAYS_FATAL_IF(!pthread_equal(mThreadId, curr), "Wrong thread!");
-}
-
 class DecStrongTask : public renderthread::RenderTask {
 public:
     DecStrongTask(VirtualLightRefBase* object) : mObject(object) {}
@@ -231,7 +224,11 @@
 };
 
 void RenderState::postDecStrong(VirtualLightRefBase* object) {
-    mRenderThread.queue(new DecStrongTask(object));
+    if (pthread_equal(mThreadId, pthread_self())) {
+        object->decStrong(nullptr);
+    } else {
+        mRenderThread.queue(new DecStrongTask(object));
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -244,6 +241,8 @@
     const Glop::Mesh::Indices& indices = mesh.indices;
     const Glop::Fill& fill = glop.fill;
 
+    GL_CHECKPOINT(MODERATE);
+
     // ---------------------------------------------
     // ---------- Program + uniform setup ----------
     // ---------------------------------------------
@@ -287,6 +286,8 @@
                 roundedOutRadius);
     }
 
+    GL_CHECKPOINT(MODERATE);
+
     // --------------------------------
     // ---------- Mesh setup ----------
     // --------------------------------
@@ -310,7 +311,7 @@
             texture.texture->setFilter(texture.filter, true, false, texture.target);
         }
 
-        mCaches->textureState().bindTexture(texture.target, texture.texture->id);
+        mCaches->textureState().bindTexture(texture.target, texture.texture->id());
         meshState().enableTexCoordsVertexArray();
         meshState().bindTexCoordsVertexPointer(force, vertices.texCoord, vertices.stride);
 
@@ -338,11 +339,18 @@
     // Shader uniforms
     SkiaShader::apply(*mCaches, fill.skiaShaderData);
 
+    GL_CHECKPOINT(MODERATE);
+    Texture* texture = (fill.skiaShaderData.skiaShaderType & kBitmap_SkiaShaderType) ?
+            fill.skiaShaderData.bitmapData.bitmapTexture : nullptr;
+    const AutoTexture autoCleanup(texture);
+
     // ------------------------------------
     // ---------- GL state setup ----------
     // ------------------------------------
     blend().setFactors(glop.blend.src, glop.blend.dst);
 
+    GL_CHECKPOINT(MODERATE);
+
     // ------------------------------------
     // ---------- Actual drawing ----------
     // ------------------------------------
@@ -371,6 +379,8 @@
         glDrawArrays(mesh.primitiveMode, 0, mesh.elementCount);
     }
 
+    GL_CHECKPOINT(MODERATE);
+
     // -----------------------------------
     // ---------- Mesh teardown ----------
     // -----------------------------------
@@ -380,6 +390,8 @@
     if (vertices.attribFlags & VertexAttribFlags::Color) {
         glDisableVertexAttribArray(colorLocation);
     }
+
+    GL_CHECKPOINT(MODERATE);
 }
 
 void RenderState::dump() {
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
index dcd5ea6..e5d3e79 100644
--- a/libs/hwui/renderstate/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -86,8 +86,6 @@
         mRegisteredContexts.erase(context);
     }
 
-    void requireGLContext();
-
     // TODO: This system is a little clunky feeling, this could use some
     // more thinking...
     void postDecStrong(VirtualLightRefBase* object);
@@ -107,7 +105,6 @@
 private:
     void interruptForFunctorInvoke();
     void resumeFromFunctorInvoke();
-    void assertOnGLThread();
 
     RenderState(renderthread::RenderThread& thread);
     ~RenderState();
diff --git a/libs/hwui/renderstate/Scissor.cpp b/libs/hwui/renderstate/Scissor.cpp
index 95dcd18..61dd8c3 100644
--- a/libs/hwui/renderstate/Scissor.cpp
+++ b/libs/hwui/renderstate/Scissor.cpp
@@ -15,6 +15,8 @@
  */
 #include "renderstate/Scissor.h"
 
+#include "Rect.h"
+
 #include <utils/Log.h>
 
 namespace android {
@@ -71,6 +73,26 @@
     return false;
 }
 
+void Scissor::set(int viewportHeight, const Rect& clip) {
+    // transform to Y-flipped GL space, and prevent negatives
+    GLint x = std::max(0, (int)clip.left);
+    GLint y = std::max(0, viewportHeight - (int)clip.bottom);
+    GLint width = std::max(0, ((int)clip.right) - x);
+    GLint height = std::max(0, (viewportHeight - (int)clip.top) - y);
+
+    if (x != mScissorX
+            || y != mScissorY
+            || width != mScissorWidth
+            || height != mScissorHeight) {
+        glScissor(x, y, width, height);
+
+        mScissorX = x;
+        mScissorY = y;
+        mScissorWidth = width;
+        mScissorHeight = height;
+    }
+}
+
 void Scissor::reset() {
     mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
 }
diff --git a/libs/hwui/renderstate/Scissor.h b/libs/hwui/renderstate/Scissor.h
index b37ec58..f302244 100644
--- a/libs/hwui/renderstate/Scissor.h
+++ b/libs/hwui/renderstate/Scissor.h
@@ -22,11 +22,14 @@
 namespace android {
 namespace uirenderer {
 
+class Rect;
+
 class Scissor {
     friend class RenderState;
 public:
     bool setEnabled(bool enabled);
     bool set(GLint x, GLint y, GLint width, GLint height);
+    void set(int viewportHeight, const Rect& clip);
     void reset();
     bool isEnabled() { return mEnabled; }
     void dump();
diff --git a/libs/hwui/renderstate/TextureState.cpp b/libs/hwui/renderstate/TextureState.cpp
index 1f50f71..78b8eda 100644
--- a/libs/hwui/renderstate/TextureState.cpp
+++ b/libs/hwui/renderstate/TextureState.cpp
@@ -34,134 +34,6 @@
     GL_TEXTURE3
 };
 
-static void uploadToTexture(bool resize, GLenum format, GLenum type, GLsizei stride, GLsizei bpp,
-        GLsizei width, GLsizei height, const GLvoid * data) {
-
-    glPixelStorei(GL_UNPACK_ALIGNMENT, bpp);
-    const bool useStride = stride != width
-            && Caches::getInstance().extensions().hasUnpackRowLength();
-    if ((stride == width) || useStride) {
-        if (useStride) {
-            glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
-        }
-
-        if (resize) {
-            glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data);
-        } else {
-            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data);
-        }
-
-        if (useStride) {
-            glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
-        }
-    } else {
-        //  With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer
-        //  if the stride doesn't match the width
-
-        GLvoid * temp = (GLvoid *) malloc(width * height * bpp);
-        if (!temp) return;
-
-        uint8_t * pDst = (uint8_t *)temp;
-        uint8_t * pSrc = (uint8_t *)data;
-        for (GLsizei i = 0; i < height; i++) {
-            memcpy(pDst, pSrc, width * bpp);
-            pDst += width * bpp;
-            pSrc += stride * bpp;
-        }
-
-        if (resize) {
-            glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, temp);
-        } else {
-            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, temp);
-        }
-
-        free(temp);
-    }
-}
-
-static void uploadSkBitmapToTexture(const SkBitmap& bitmap,
-        bool resize, GLenum format, GLenum type) {
-    uploadToTexture(resize, format, type, bitmap.rowBytesAsPixels(), bitmap.bytesPerPixel(),
-            bitmap.width(), bitmap.height(), bitmap.getPixels());
-}
-
-void TextureState::generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate) {
-    SkAutoLockPixels alp(*bitmap);
-
-    if (!bitmap->readyToDraw()) {
-        ALOGE("Cannot generate texture from bitmap");
-        return;
-    }
-
-    ATRACE_FORMAT("Upload %ux%u Texture", bitmap->width(), bitmap->height());
-
-    // We could also enable mipmapping if both bitmap dimensions are powers
-    // of 2 but we'd have to deal with size changes. Let's keep this simple
-    const bool canMipMap = Caches::getInstance().extensions().hasNPot();
-
-    // If the texture had mipmap enabled but not anymore,
-    // force a glTexImage2D to discard the mipmap levels
-    const bool resize = !regenerate || bitmap->width() != int(texture->width) ||
-            bitmap->height() != int(texture->height) ||
-            (regenerate && canMipMap && texture->mipMap && !bitmap->hasHardwareMipMap());
-
-    if (!regenerate) {
-        glGenTextures(1, &texture->id);
-    }
-
-    texture->generation = bitmap->getGenerationID();
-    texture->width = bitmap->width();
-    texture->height = bitmap->height();
-
-    bindTexture(texture->id);
-
-    switch (bitmap->colorType()) {
-    case kAlpha_8_SkColorType:
-        uploadSkBitmapToTexture(*bitmap, resize, GL_ALPHA, GL_UNSIGNED_BYTE);
-        texture->blend = true;
-        break;
-    case kRGB_565_SkColorType:
-        uploadSkBitmapToTexture(*bitmap, resize, GL_RGB, GL_UNSIGNED_SHORT_5_6_5);
-        texture->blend = false;
-        break;
-    case kN32_SkColorType:
-        uploadSkBitmapToTexture(*bitmap, resize, GL_RGBA, GL_UNSIGNED_BYTE);
-        // Do this after calling getPixels() to make sure Skia's deferred
-        // decoding happened
-        texture->blend = !bitmap->isOpaque();
-        break;
-    case kARGB_4444_SkColorType:
-    case kIndex_8_SkColorType: {
-        SkBitmap rgbaBitmap;
-        rgbaBitmap.allocPixels(SkImageInfo::MakeN32(texture->width, texture->height,
-                bitmap->alphaType()));
-        rgbaBitmap.eraseColor(0);
-
-        SkCanvas canvas(rgbaBitmap);
-        canvas.drawBitmap(*bitmap, 0.0f, 0.0f, nullptr);
-
-        uploadSkBitmapToTexture(rgbaBitmap, resize, GL_RGBA, GL_UNSIGNED_BYTE);
-        texture->blend = !bitmap->isOpaque();
-        break;
-    }
-    default:
-        ALOGW("Unsupported bitmap colorType: %d", bitmap->colorType());
-        break;
-    }
-
-    if (canMipMap) {
-        texture->mipMap = bitmap->hasHardwareMipMap();
-        if (texture->mipMap) {
-            glGenerateMipmap(GL_TEXTURE_2D);
-        }
-    }
-
-    if (!regenerate) {
-        texture->setFilter(GL_NEAREST);
-        texture->setWrap(GL_CLAMP_TO_EDGE);
-    }
-}
-
 TextureState::TextureState()
         : mTextureUnit(0) {
     glActiveTexture(kTextureUnits[0]);
@@ -171,6 +43,7 @@
     glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
     LOG_ALWAYS_FATAL_IF(maxTextureUnits < kTextureUnitsCount,
             "At least %d texture units are required!", kTextureUnitsCount);
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 }
 
 void TextureState::activateTexture(GLuint textureUnit) {
diff --git a/libs/hwui/renderstate/TextureState.h b/libs/hwui/renderstate/TextureState.h
index 3a2b85a..ec94d7e 100644
--- a/libs/hwui/renderstate/TextureState.h
+++ b/libs/hwui/renderstate/TextureState.h
@@ -76,13 +76,6 @@
      */
     void unbindTexture(GLuint texture);
 
-    /**
-     * Generates the texture from a bitmap into the specified texture structure.
-     *
-     * @param regenerate If true, the bitmap data is reuploaded into the texture, but
-     *        no new texture is generated.
-     */
-    void generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate);
 private:
     // total number of texture units available for use
     static const int kTextureUnitsCount = 4;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 0620653..e7cf3ec 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -14,10 +14,12 @@
  * limitations under the License.
  */
 
+#include <GpuMemoryTracker.h>
 #include "CanvasContext.h"
 
 #include "AnimationContext.h"
 #include "Caches.h"
+#include "Canvas.h"
 #include "DeferredLayerUpdater.h"
 #include "EglManager.h"
 #include "LayerUpdateQueue.h"
@@ -28,10 +30,11 @@
 #include "renderstate/RenderState.h"
 #include "renderstate/Stencil.h"
 #include "protos/hwui.pb.h"
+#include "utils/GLUtils.h"
 #include "utils/TimeUtils.h"
 
 #if HWUI_NEW_OPS
-#include "OpReorderer.h"
+#include "FrameBuilder.h"
 #endif
 
 #include <cutils/properties.h>
@@ -128,14 +131,13 @@
     mSwapBehavior = swapBehavior;
 }
 
-bool CanvasContext::initialize(ANativeWindow* window) {
+void CanvasContext::initialize(ANativeWindow* window) {
     setSurface(window);
 #if !HWUI_NEW_OPS
-    if (mCanvas) return false;
+    if (mCanvas) return;
     mCanvas = new OpenGLRenderer(mRenderThread.renderState());
     mCanvas->initProperties();
 #endif
-    return true;
 }
 
 void CanvasContext::updateSurface(ANativeWindow* window) {
@@ -182,16 +184,6 @@
     }
 }
 
-void CanvasContext::processLayerUpdate(DeferredLayerUpdater* layerUpdater) {
-#if !HWUI_NEW_OPS
-    bool success = layerUpdater->apply();
-    LOG_ALWAYS_FATAL_IF(!success, "Failed to update layer!");
-    if (layerUpdater->backingLayer()->deferredUpdateScheduled) {
-        mCanvas->pushLayerUpdate(layerUpdater->backingLayer());
-    }
-#endif
-}
-
 static bool wasSkipped(FrameInfo* info) {
     return info && ((*info)[FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame);
 }
@@ -223,10 +215,13 @@
         // node(s) are non client / filler nodes.
         info.mode = (node.get() == target ? TreeInfo::MODE_FULL : TreeInfo::MODE_RT_ONLY);
         node->prepareTree(info);
+        GL_CHECKPOINT(MODERATE);
     }
     mAnimationContext->runRemainingAnimations(info);
+    GL_CHECKPOINT(MODERATE);
 
     freePrefetechedLayers();
+    GL_CHECKPOINT(MODERATE);
 
     if (CC_UNLIKELY(!mNativeWindow.get())) {
         mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
@@ -349,14 +344,13 @@
     mEglManager.damageFrame(frame, dirty);
 
 #if HWUI_NEW_OPS
-    OpReorderer reorderer(mLayerUpdateQueue, dirty, frame.width(), frame.height(),
-            mRenderNodes, mLightCenter);
+    FrameBuilder frameBuilder(mLayerUpdateQueue, dirty, frame.width(), frame.height(),
+            mRenderNodes, mLightCenter, mContentDrawBounds);
     mLayerUpdateQueue.clear();
     BakedOpRenderer renderer(Caches::getInstance(), mRenderThread.renderState(),
             mOpaque, mLightInfo);
     // TODO: profiler().draw(mCanvas);
-    reorderer.replayBakedOps<BakedOpDispatcher>(renderer);
-
+    frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
     bool drew = renderer.didDraw();
 
 #else
@@ -401,7 +395,7 @@
             backdropBounds.doIntersect(targetBounds);
             // Check if we have to draw something on the left side ...
             if (targetBounds.left < contentBounds.left) {
-                mCanvas->save(SkCanvas::kClip_SaveFlag);
+                mCanvas->save(SaveFlags::Clip);
                 if (mCanvas->clipRect(targetBounds.left, targetBounds.top,
                                       contentBounds.left, targetBounds.bottom,
                                       SkRegion::kIntersect_Op)) {
@@ -414,7 +408,7 @@
             // ... or on the right side ...
             if (targetBounds.right > contentBounds.right &&
                 !targetBounds.isEmpty()) {
-                mCanvas->save(SkCanvas::kClip_SaveFlag);
+                mCanvas->save(SaveFlags::Clip);
                 if (mCanvas->clipRect(contentBounds.right, targetBounds.top,
                                       targetBounds.right, targetBounds.bottom,
                                       SkRegion::kIntersect_Op)) {
@@ -427,7 +421,7 @@
             // ... or at the top ...
             if (targetBounds.top < contentBounds.top &&
                 !targetBounds.isEmpty()) {
-                mCanvas->save(SkCanvas::kClip_SaveFlag);
+                mCanvas->save(SaveFlags::Clip);
                 if (mCanvas->clipRect(targetBounds.left, targetBounds.top, targetBounds.right,
                                       contentBounds.top,
                                       SkRegion::kIntersect_Op)) {
@@ -440,7 +434,7 @@
             // ... or at the bottom.
             if (targetBounds.bottom > contentBounds.bottom &&
                 !targetBounds.isEmpty()) {
-                mCanvas->save(SkCanvas::kClip_SaveFlag);
+                mCanvas->save(SaveFlags::Clip);
                 if (mCanvas->clipRect(targetBounds.left, contentBounds.bottom, targetBounds.right,
                                       targetBounds.bottom, SkRegion::kIntersect_Op)) {
                     mCanvas->drawRenderNode(node.get(), outBounds);
@@ -449,7 +443,7 @@
             }
         } else if (layer == 1) { // Content
             // It gets cropped against the bounds of the backdrop to stay inside.
-            mCanvas->save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
+            mCanvas->save(SaveFlags::MatrixClip);
 
             // We shift and clip the content to match its final location in the window.
             const float left = mContentDrawBounds.left;
@@ -474,6 +468,9 @@
 
     bool drew = mCanvas->finish();
 #endif
+
+    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();
@@ -509,6 +506,11 @@
 
     mJankTracker.addFrame(*mCurrentFrameInfo);
     mRenderThread.jankTracker().addFrame(*mCurrentFrameInfo);
+    if (CC_UNLIKELY(mFrameStatsReporter.get() != nullptr)) {
+        mFrameStatsReporter->reportFrameStats(mCurrentFrameInfo->data());
+    }
+
+    GpuMemoryTracker::onFrameCompleted();
 }
 
 // Called by choreographer to do an RT-driven animation
@@ -524,11 +526,11 @@
 void CanvasContext::prepareAndDraw(RenderNode* node) {
     ATRACE_CALL();
 
+    nsecs_t vsync = mRenderThread.timeLord().computeFrameTimeNanos();
     int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE];
     UiFrameInfoBuilder(frameInfo)
         .addFlag(FrameInfoFlags::RTAnimation)
-        .setVsync(mRenderThread.timeLord().computeFrameTimeNanos(),
-                mRenderThread.timeLord().latestVsync());
+        .setVsync(vsync, vsync);
 
     TreeInfo info(TreeInfo::MODE_RT_ONLY, *this);
     prepareTree(info, frameInfo, systemTime(CLOCK_MONOTONIC), node);
@@ -590,7 +592,7 @@
     node->setPropertyFieldsDirty(RenderNode::GENERIC);
 
 #if HWUI_NEW_OPS
-    LOG_ALWAYS_FATAL("unsupported");
+    // TODO: support buildLayer
 #else
     mCanvas->markLayersAsBuildLayers();
     mCanvas->flushLayerUpdates();
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index d36ce99..270fb1f 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -20,6 +20,7 @@
 #include "DamageAccumulator.h"
 #include "FrameInfo.h"
 #include "FrameInfoVisualizer.h"
+#include "FrameStatsReporter.h"
 #include "IContextFactory.h"
 #include "LayerUpdateQueue.h"
 #include "RenderNode.h"
@@ -73,7 +74,7 @@
     // Won't take effect until next EGLSurface creation
     void setSwapBehavior(SwapBehavior swapBehavior);
 
-    bool initialize(ANativeWindow* window);
+    void initialize(ANativeWindow* window);
     void updateSurface(ANativeWindow* window);
     bool pauseSurface(ANativeWindow* window);
     bool hasSurface() { return mNativeWindow.get(); }
@@ -83,7 +84,6 @@
     void setLightCenter(const Vector3& lightCenter);
     void setOpaque(bool opaque);
     void makeCurrent();
-    void processLayerUpdate(DeferredLayerUpdater* layerUpdater);
     void prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
             int64_t syncQueued, RenderNode* target);
     void draw();
@@ -140,6 +140,31 @@
         return mRenderThread.renderState();
     }
 
+    void addFrameStatsObserver(FrameStatsObserver* observer) {
+        if (mFrameStatsReporter.get() == nullptr) {
+            mFrameStatsReporter.reset(new FrameStatsReporter());
+        }
+
+        mFrameStatsReporter->addObserver(observer);
+    }
+
+    void removeFrameStatsObserver(FrameStatsObserver* observer) {
+        if (mFrameStatsReporter.get() != nullptr) {
+            mFrameStatsReporter->removeObserver(observer);
+            if (!mFrameStatsReporter->hasObservers()) {
+                mFrameStatsReporter.reset(nullptr);
+            }
+        }
+    }
+
+    long getDroppedFrameReportCount() {
+        if (mFrameStatsReporter.get() != nullptr) {
+            return mFrameStatsReporter->getDroppedReports();
+        }
+
+        return 0;
+    }
+
 private:
     friend class RegisterFrameCallbackTask;
     // TODO: Replace with something better for layer & other GL object
@@ -188,6 +213,7 @@
     std::string mName;
     JankTracker mJankTracker;
     FrameInfoVisualizer mProfiler;
+    std::unique_ptr<FrameStatsReporter> mFrameStatsReporter;
 
     std::set<RenderNode*> mPrefetechedLayers;
 
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index ab860c7..e8b9725 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -117,7 +117,7 @@
     Caches::getInstance().textureCache.resetMarkInUse(mContext);
 
     for (size_t i = 0; i < mLayers.size(); i++) {
-        mContext->processLayerUpdate(mLayers[i].get());
+        mLayers[i]->apply();
     }
     mLayers.clear();
     mContext->prepareTree(info, mFrameInfo, mSyncQueued, mTargetNode);
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 78df297..466fef9 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -29,8 +29,6 @@
 
 #define GLES_VERSION 2
 
-#define WAIT_FOR_GPU_COMPLETION 0
-
 // Android-specific addition that is used to show when frames began in systrace
 EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
 
@@ -179,7 +177,10 @@
 }
 
 void EglManager::createContext() {
-    EGLint attribs[] = { EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION, EGL_NONE };
+    EGLint attribs[] = {
+            EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION,
+            EGL_NONE
+    };
     mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, attribs);
     LOG_ALWAYS_FATAL_IF(mEglContext == EGL_NO_CONTEXT,
         "Failed to create context, error = %s", egl_error_str());
@@ -318,12 +319,10 @@
 
 bool EglManager::swapBuffers(const Frame& frame, const SkRect& screenDirty) {
 
-#if WAIT_FOR_GPU_COMPLETION
-    {
+    if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
         ATRACE_NAME("Finishing GPU work");
         fence();
     }
-#endif
 
     EGLint rects[4];
     frame.map(screenDirty, rects);
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 15ccd6a..1d1b144 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -140,14 +140,15 @@
 }
 
 CREATE_BRIDGE2(initialize, CanvasContext* context, ANativeWindow* window) {
-    return (void*) args->context->initialize(args->window);
+    args->context->initialize(args->window);
+    return nullptr;
 }
 
-bool RenderProxy::initialize(const sp<ANativeWindow>& window) {
+void RenderProxy::initialize(const sp<ANativeWindow>& window) {
     SETUP_TASK(initialize);
     args->context = mContext;
     args->window = window.get();
-    return (bool) postAndWait(task);
+    post(task);
 }
 
 CREATE_BRIDGE2(updateSurface, CanvasContext* context, ANativeWindow* window) {
@@ -383,6 +384,12 @@
     postAndWait(task);
 }
 
+void RenderProxy::staticFence() {
+    SETUP_TASK(fence);
+    UNUSED(args);
+    staticPostAndWait(task);
+}
+
 CREATE_BRIDGE1(stopDrawing, CanvasContext* context) {
     args->context->stopDrawing();
     return nullptr;
@@ -449,6 +456,11 @@
     } else {
         fprintf(file, "\nNo caches instance.\n");
     }
+#if HWUI_NEW_OPS
+    fprintf(file, "\nPipeline=FrameBuilder\n");
+#else
+    fprintf(file, "\nPipeline=OpenGLRenderer\n");
+#endif
     fflush(file);
     return nullptr;
 }
@@ -556,6 +568,54 @@
     post(task);
 }
 
+CREATE_BRIDGE2(addFrameStatsObserver, CanvasContext* context,
+        FrameStatsObserver* frameStatsObserver) {
+   args->context->addFrameStatsObserver(args->frameStatsObserver);
+   if (args->frameStatsObserver != nullptr) {
+       args->frameStatsObserver->decStrong(args->context);
+   }
+   return nullptr;
+}
+
+void RenderProxy::addFrameStatsObserver(FrameStatsObserver* observer) {
+    SETUP_TASK(addFrameStatsObserver);
+    args->context = mContext;
+    args->frameStatsObserver = observer;
+    if (observer != nullptr) {
+        observer->incStrong(mContext);
+    }
+    post(task);
+}
+
+CREATE_BRIDGE2(removeFrameStatsObserver, CanvasContext* context,
+        FrameStatsObserver* frameStatsObserver) {
+   args->context->removeFrameStatsObserver(args->frameStatsObserver);
+   if (args->frameStatsObserver != nullptr) {
+       args->frameStatsObserver->decStrong(args->context);
+   }
+   return nullptr;
+}
+
+void RenderProxy::removeFrameStatsObserver(FrameStatsObserver* observer) {
+    SETUP_TASK(removeFrameStatsObserver);
+    args->context = mContext;
+    args->frameStatsObserver = observer;
+    if (observer != nullptr) {
+        observer->incStrong(mContext);
+    }
+    post(task);
+}
+
+CREATE_BRIDGE1(getDroppedFrameReportCount, CanvasContext* context) {
+    return (void*) args->context->getDroppedFrameReportCount();
+}
+
+long RenderProxy::getDroppedFrameReportCount() {
+    SETUP_TASK(getDroppedFrameReportCount);
+    args->context = mContext;
+    return (long) postAndWait(task);
+}
+
 void RenderProxy::post(RenderTask* task) {
     mRenderThread.queue(task);
 }
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 338fab6..4180d802 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -29,6 +29,7 @@
 #include <utils/StrongPointer.h>
 
 #include "../Caches.h"
+#include "../FrameStatsObserver.h"
 #include "../IContextFactory.h"
 #include "CanvasContext.h"
 #include "DrawFrameTask.h"
@@ -66,7 +67,7 @@
     ANDROID_API bool loadSystemProperties();
     ANDROID_API void setName(const char* name);
 
-    ANDROID_API bool initialize(const sp<ANativeWindow>& window);
+    ANDROID_API void initialize(const sp<ANativeWindow>& window);
     ANDROID_API void updateSurface(const sp<ANativeWindow>& window);
     ANDROID_API bool pauseSurface(const sp<ANativeWindow>& window);
     ANDROID_API void setup(int width, int height, float lightRadius,
@@ -93,6 +94,7 @@
     ANDROID_API static void overrideProperty(const char* name, const char* value);
 
     ANDROID_API void fence();
+    ANDROID_API static void staticFence();
     ANDROID_API void stopDrawing();
     ANDROID_API void notifyFramePending();
 
@@ -111,6 +113,10 @@
     ANDROID_API void drawRenderNode(RenderNode* node);
     ANDROID_API void setContentDrawBounds(int left, int top, int right, int bottom);
 
+    ANDROID_API void addFrameStatsObserver(FrameStatsObserver* observer);
+    ANDROID_API void removeFrameStatsObserver(FrameStatsObserver* observer);
+    ANDROID_API long getDroppedFrameReportCount();
+
 private:
     RenderThread& mRenderThread;
     CanvasContext* mContext;
diff --git a/libs/hwui/tests/common/TestScene.h b/libs/hwui/tests/common/TestScene.h
index df8d194..706f2ff 100644
--- a/libs/hwui/tests/common/TestScene.h
+++ b/libs/hwui/tests/common/TestScene.h
@@ -37,6 +37,7 @@
 public:
     struct Options {
         int count = 0;
+        int reportFrametimeWeight = 0;
     };
 
     template <class T>
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 6cef852..5ed7aa4 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -16,6 +16,12 @@
 
 #include "TestUtils.h"
 
+#include "DeferredLayerUpdater.h"
+#include "LayerRenderer.h"
+
+#include <unistd.h>
+#include <signal.h>
+
 namespace android {
 namespace uirenderer {
 
@@ -36,16 +42,29 @@
             | (int)((startB + (int)(fraction * (endB - startB))));
 }
 
+sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater(
+        renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
+        std::function<void(Matrix4*)> transformSetupCallback) {
+    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()));
+
+    sp<DeferredLayerUpdater> layerUpdater = new DeferredLayerUpdater(layer);
+    return layerUpdater;
+}
+
 void TestUtils::drawTextToCanvas(TestCanvas* 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");
-
-    SkMatrix identity;
-    identity.setIdentity();
     SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
-    SkAutoGlyphCacheNoGamma autoCache(paint, &surfaceProps, &identity);
+    SkAutoGlyphCacheNoGamma autoCache(paint, &surfaceProps, &SkMatrix::I());
 
     float totalAdvance = 0;
     std::vector<glyph_t> glyphs;
@@ -89,5 +108,53 @@
                 bounds.left, bounds.top, bounds.right, bounds.bottom, totalAdvance);
 }
 
+void TestUtils::drawTextToCanvas(TestCanvas* 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;
+}
+
+void TestUtils::TestTask::run() {
+    gPreviousSignalHandler = signal(SIGABRT, signalHandler);
+
+    // RenderState only valid once RenderThread is running, so queried here
+    RenderState& renderState = renderthread::RenderThread::getInstance().renderState();
+
+    renderState.onGLContextCreated();
+    rtCallback(renderthread::RenderThread::getInstance());
+    renderState.onGLContextDestroyed();
+
+    // Restore the previous signal handler
+    signal(SIGABRT, gPreviousSignalHandler);
+}
+
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 0af9939..ae08142 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -53,6 +53,13 @@
             && MathUtils::areEqual(a.right, b.right) \
             && MathUtils::areEqual(a.bottom, b.bottom));
 
+#define EXPECT_CLIP_RECT(expRect, clipStatePtr) \
+        EXPECT_NE(nullptr, (clipStatePtr)) << "Op is unclipped"; \
+        if ((clipStatePtr)->mode == ClipMode::Rectangle) { \
+            EXPECT_EQ((expRect), reinterpret_cast<const ClipRect*>(clipStatePtr)->rect); \
+        } else { \
+            ADD_FAILURE() << "ClipState not a rect"; \
+        }
 /**
  * Like gtest's TEST, but runs on the RenderThread, and 'renderThread' is passed, in top level scope
  * (for e.g. accessing its RenderState)
@@ -98,7 +105,7 @@
 
     static std::unique_ptr<Snapshot> makeSnapshot(const Matrix4& transform, const Rect& clip) {
         std::unique_ptr<Snapshot> snapshot(new Snapshot());
-        snapshot->clip(clip.left, clip.top, clip.right, clip.bottom, SkRegion::kReplace_Op);
+        snapshot->clip(clip, SkRegion::kReplace_Op); // store clip first, so it isn't transformed
         *(snapshot->transform) = transform;
         return snapshot;
     }
@@ -113,6 +120,10 @@
         return bitmap;
     }
 
+    static sp<DeferredLayerUpdater> createTextureLayerUpdater(
+            renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
+            std::function<void(Matrix4*)> transformSetupCallback);
+
     template<class CanvasType>
     static std::unique_ptr<DisplayList> createDisplayList(int width, int height,
             std::function<void(CanvasType& canvas)> canvasCallback) {
@@ -160,21 +171,23 @@
         syncHierarchyPropertiesAndDisplayListImpl(node.get());
     }
 
+    static std::vector<sp<RenderNode>> createSyncedNodeList(sp<RenderNode>& node) {
+        TestUtils::syncHierarchyPropertiesAndDisplayList(node);
+        std::vector<sp<RenderNode>> vec;
+        vec.emplace_back(node);
+        return vec;
+    }
+
     typedef std::function<void(renderthread::RenderThread& thread)> RtCallback;
 
+    static void setRenderThreadCrashHandler(std::function<void()> crashHandler);
+
     class TestTask : public renderthread::RenderTask {
     public:
         TestTask(RtCallback rtCallback)
                 : rtCallback(rtCallback) {}
         virtual ~TestTask() {}
-        virtual void run() override {
-            // RenderState only valid once RenderThread is running, so queried here
-            RenderState& renderState = renderthread::RenderThread::getInstance().renderState();
-
-            renderState.onGLContextCreated();
-            rtCallback(renderthread::RenderThread::getInstance());
-            renderState.onGLContextDestroyed();
-        };
+        virtual void run() override;
         RtCallback rtCallback;
     };
 
@@ -186,11 +199,18 @@
         renderthread::RenderThread::getInstance().queueAndWait(&task);
     }
 
+    static bool isRenderThreadRunning() {
+        return renderthread::RenderThread::hasInstance();
+    }
+
     static SkColor interpolateColor(float fraction, SkColor start, SkColor end);
 
     static void drawTextToCanvas(TestCanvas* canvas, const char* text,
             const SkPaint& paint, float x, float y);
 
+    static void drawTextToCanvas(TestCanvas* canvas, const char* text,
+            const SkPaint& paint, const SkPath& path);
+
 private:
     static void syncHierarchyPropertiesAndDisplayListImpl(RenderNode* node) {
         node->syncProperties();
diff --git a/libs/hwui/tests/common/nullgles.cpp b/libs/hwui/tests/common/nullgles.cpp
deleted file mode 100644
index f8e8c98..0000000
--- a/libs/hwui/tests/common/nullgles.cpp
+++ /dev/null
@@ -1,273 +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 <GLES3/gl3.h>
-#include <GLES2/gl2ext.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-struct {
-    GLboolean scissorEnabled;
-} gState;
-
-void glGenCommon(GLsizei n, GLuint *buffers) {
-    static GLuint nextId = 0;
-    int i;
-    for(i = 0; i < n; i++) {
-        buffers[i] = ++nextId;
-    }
-}
-
-void glGenBuffers(GLsizei n, GLuint *buffers) {
-    glGenCommon(n, buffers);
-}
-
-void glGenFramebuffers(GLsizei n, GLuint *framebuffers) {
-    glGenCommon(n, framebuffers);
-}
-
-void glGenRenderbuffers(GLsizei n, GLuint *renderbuffers) {
-    glGenCommon(n, renderbuffers);
-}
-
-void glGenTextures(GLsizei n, GLuint *textures) {
-    glGenCommon(n, textures);
-}
-
-GLuint glCreateProgram(void) {
-    static GLuint nextProgram = 0;
-    return ++nextProgram;
-}
-
-GLuint glCreateShader(GLenum type) {
-    static GLuint nextShader = 0;
-    return ++nextShader;
-}
-
-void glGetProgramiv(GLuint program, GLenum pname, GLint *params) {
-    switch (pname) {
-    case GL_DELETE_STATUS:
-    case GL_LINK_STATUS:
-    case GL_VALIDATE_STATUS:
-        *params = GL_TRUE;
-        break;
-    case GL_INFO_LOG_LENGTH:
-        *params = 16;
-        break;
-    }
-}
-
-void glGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
-    *length = snprintf(infoLog, bufSize, "success");
-    if (*length >= bufSize) {
-        *length = bufSize - 1;
-    }
-}
-
-void glGetShaderiv(GLuint shader, GLenum pname, GLint *params) {
-    switch (pname) {
-    case GL_COMPILE_STATUS:
-    case GL_DELETE_STATUS:
-        *params = GL_TRUE;
-    }
-}
-
-void glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
-    *length = snprintf(infoLog, bufSize, "success");
-    if (*length >= bufSize) {
-        *length = bufSize - 1;
-    }
-}
-
-void setBooleanState(GLenum cap, GLboolean value) {
-    switch (cap) {
-    case GL_SCISSOR_TEST:
-        gState.scissorEnabled = value;
-        break;
-    }
-}
-
-void glEnable(GLenum cap) {
-    setBooleanState(cap, GL_TRUE);
-}
-
-void glDisable(GLenum cap) {
-    setBooleanState(cap, GL_FALSE);
-}
-
-GLboolean glIsEnabled(GLenum cap) {
-    switch (cap) {
-    case GL_SCISSOR_TEST:
-        return gState.scissorEnabled;
-    default:
-        return GL_FALSE;
-    }
-}
-
-void glGetIntegerv(GLenum pname, GLint *data) {
-    switch (pname) {
-    case GL_MAX_TEXTURE_SIZE:
-        *data = 2048;
-        break;
-    case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
-        *data = 4;
-        break;
-    default:
-        *data = 0;
-    }
-}
-
-const char* getString(GLenum name) {
-    switch (name) {
-    case GL_VENDOR:
-        return "android";
-    case GL_RENDERER:
-        return "null";
-    case GL_VERSION:
-        return "OpenGL ES 2.0 rev1";
-    case GL_SHADING_LANGUAGE_VERSION:
-        return "OpenGL ES GLSL ES 2.0 rev1";
-    case GL_EXTENSIONS:
-    default:
-        return "";
-    }
-}
-
-const GLubyte* glGetString(GLenum name) {
-    return (GLubyte*) getString(name);
-}
-
-void glActiveTexture(GLenum texture) {}
-void glAttachShader(GLuint program, GLuint shader) {}
-void glBindAttribLocation(GLuint program, GLuint index, const GLchar *name) {}
-void glBindBuffer(GLenum target, GLuint buffer) {}
-void glBindFramebuffer(GLenum target, GLuint framebuffer) {}
-void glBindRenderbuffer(GLenum target, GLuint renderbuffer) {}
-void glBindTexture(GLenum target, GLuint texture) {}
-void glBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {}
-void glBlendEquation(GLenum mode) {}
-void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) {}
-void glBlendFunc(GLenum sfactor, GLenum dfactor) {}
-void glBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) {}
-void glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage) {}
-void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void *data) {}
-void glClear(GLbitfield mask) {}
-void glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {}
-void glClearDepthf(GLfloat d) {}
-void glClearStencil(GLint s) {}
-void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {}
-void glCompileShader(GLuint shader) {}
-void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data) {}
-void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) {}
-void glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {}
-void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {}
-void glCullFace(GLenum mode) {}
-void glDeleteBuffers(GLsizei n, const GLuint *buffers) {}
-void glDeleteFramebuffers(GLsizei n, const GLuint *framebuffers) {}
-void glDeleteProgram(GLuint program) {}
-void glDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) {}
-void glDeleteShader(GLuint shader) {}
-void glDeleteTextures(GLsizei n, const GLuint *textures) {}
-void glDepthFunc(GLenum func) {}
-void glDepthMask(GLboolean flag) {}
-void glDepthRangef(GLfloat n, GLfloat f) {}
-void glDetachShader(GLuint program, GLuint shader) {}
-void glDisableVertexAttribArray(GLuint index) {}
-void glDrawArrays(GLenum mode, GLint first, GLsizei count) {}
-void glDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices) {}
-void glEnableVertexAttribArray(GLuint index) {}
-void glFinish(void) {}
-void glFlush(void) {}
-void glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) {}
-void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {}
-void glFrontFace(GLenum mode) {}
-void glGenerateMipmap(GLenum target) {}
-GLint glGetAttribLocation(GLuint program, const GLchar *name) { return 1; }
-GLenum glGetError(void) { return GL_NO_ERROR; }
-GLint glGetUniformLocation(GLuint program, const GLchar *name) { return 2; }
-void glHint(GLenum target, GLenum mode) {}
-void glLineWidth(GLfloat width) {}
-void glLinkProgram(GLuint program) {}
-void glPixelStorei(GLenum pname, GLint param) {}
-void glPolygonOffset(GLfloat factor, GLfloat units) {}
-void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) {}
-void glReleaseShaderCompiler(void) {}
-void glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {}
-void glSampleCoverage(GLfloat value, GLboolean invert) {}
-void glScissor(GLint x, GLint y, GLsizei width, GLsizei height) {}
-void glShaderBinary(GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length) {}
-void glShaderSource(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length) {}
-void glStencilFunc(GLenum func, GLint ref, GLuint mask) {}
-void glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) {}
-void glStencilMask(GLuint mask) {}
-void glStencilMaskSeparate(GLenum face, GLuint mask) {}
-void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) {}
-void glStencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) {}
-void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) {}
-void glTexParameterf(GLenum target, GLenum pname, GLfloat param) {}
-void glTexParameterfv(GLenum target, GLenum pname, const GLfloat *params) {}
-void glTexParameteri(GLenum target, GLenum pname, GLint param) {}
-void glTexParameteriv(GLenum target, GLenum pname, const GLint *params) {}
-void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) {}
-void glUniform1f(GLint location, GLfloat v0) {}
-void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) {}
-void glUniform1i(GLint location, GLint v0) {}
-void glUniform1iv(GLint location, GLsizei count, const GLint *value) {}
-void glUniform2f(GLint location, GLfloat v0, GLfloat v1) {}
-void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) {}
-void glUniform2i(GLint location, GLint v0, GLint v1) {}
-void glUniform2iv(GLint location, GLsizei count, const GLint *value) {}
-void glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) {}
-void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) {}
-void glUniform3i(GLint location, GLint v0, GLint v1, GLint v2) {}
-void glUniform3iv(GLint location, GLsizei count, const GLint *value) {}
-void glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {}
-void glUniform4fv(GLint location, GLsizei count, const GLfloat *value) {}
-void glUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) {}
-void glUniform4iv(GLint location, GLsizei count, const GLint *value) {}
-void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {}
-void glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {}
-void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {}
-void glUseProgram(GLuint program) {}
-void glValidateProgram(GLuint program) {}
-void glVertexAttrib1f(GLuint index, GLfloat x) {}
-void glVertexAttrib1fv(GLuint index, const GLfloat *v) {}
-void glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) {}
-void glVertexAttrib2fv(GLuint index, const GLfloat *v) {}
-void glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) {}
-void glVertexAttrib3fv(GLuint index, const GLfloat *v) {}
-void glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {}
-void glVertexAttrib4fv(GLuint index, const GLfloat *v) {}
-void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) {}
-void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) {}
-
-
-// gles2 ext
-void glInsertEventMarkerEXT(GLsizei length, const GLchar *marker) {}
-void glPushGroupMarkerEXT(GLsizei length, const GLchar *marker) {}
-void glPopGroupMarkerEXT(void) {}
-void glDiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum *attachments) {}
-void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image) {}
-
-// GLES3
-void* glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) {
-    return 0;
-}
-
-GLboolean glUnmapBuffer(GLenum target) {
-    return GL_FALSE;
-}
diff --git a/libs/hwui/tests/common/scenes/ClippingAnimation.cpp b/libs/hwui/tests/common/scenes/ClippingAnimation.cpp
new file mode 100644
index 0000000..a5fd712
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/ClippingAnimation.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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"
+
+class ClippingAnimation;
+
+static TestScene::Registrar _RectGrid(TestScene::Info{
+    "clip",
+    "Complex clip cases"
+    "Low CPU/GPU load.",
+    TestScene::simpleCreateScene<ClippingAnimation>
+});
+
+class ClippingAnimation : public TestScene {
+public:
+    sp<RenderNode> card;
+    void createContent(int width, int height, TestCanvas& canvas) override {
+        canvas.drawColor(Color::White, SkXfermode::kSrcOver_Mode);
+        card = TestUtils::createNode(0, 0, 200, 400,
+                [](RenderProperties& props, TestCanvas& canvas) {
+            canvas.save(SaveFlags::MatrixClip);
+            {
+                canvas.clipRect(0, 0, 200, 200, SkRegion::kIntersect_Op);
+                canvas.translate(100, 100);
+                canvas.rotate(45);
+                canvas.translate(-100, -100);
+                canvas.clipRect(0, 0, 200, 200, SkRegion::kIntersect_Op);
+                canvas.drawColor(Color::Blue_500, SkXfermode::kSrcOver_Mode);
+            }
+            canvas.restore();
+
+            canvas.save(SaveFlags::MatrixClip);
+            {
+                SkPath clipCircle;
+                clipCircle.addCircle(100, 300, 100);
+                canvas.clipPath(&clipCircle, SkRegion::kIntersect_Op);
+                canvas.drawColor(Color::Red_500, SkXfermode::kSrcOver_Mode);
+            }
+            canvas.restore();
+
+            // put on a layer, to test stencil attachment
+            props.mutateLayerProperties().setType(LayerType::RenderLayer);
+            props.setAlpha(0.9f);
+        });
+        canvas.drawRenderNode(card.get());
+    }
+    void doFrame(int frameNr) override {
+        int curFrame = frameNr % 150;
+        card->mutateStagingProperties().setTranslationX(curFrame);
+        card->mutateStagingProperties().setTranslationY(curFrame);
+        card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+    }
+};
diff --git a/libs/hwui/tests/common/scenes/OvalAnimation.cpp b/libs/hwui/tests/common/scenes/OvalAnimation.cpp
index 082c628..e56f2f9 100644
--- a/libs/hwui/tests/common/scenes/OvalAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/OvalAnimation.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "TestSceneBase.h"
+#include "utils/Color.h"
 
 class OvalAnimation;
 
@@ -28,12 +29,12 @@
 public:
     sp<RenderNode> card;
     void createContent(int width, int height, TestCanvas& canvas) override {
-        canvas.drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
+        canvas.drawColor(Color::White, SkXfermode::kSrcOver_Mode);
         card = TestUtils::createNode(0, 0, 200, 200,
                 [](RenderProperties& props, TestCanvas& canvas) {
             SkPaint paint;
             paint.setAntiAlias(true);
-            paint.setColor(0xFF000000);
+            paint.setColor(Color::Black);
             canvas.drawOval(0, 0, 200, 200, paint);
         });
         canvas.drawRenderNode(card.get());
diff --git a/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp b/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
index 78fcd8b..6904bec 100644
--- a/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
@@ -29,14 +29,27 @@
 public:
     sp<RenderNode> card;
     void createContent(int width, int height, TestCanvas& canvas) override {
-        canvas.drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode); // background
+        canvas.drawColor(Color::White, SkXfermode::kSrcOver_Mode); // background
 
-        card = TestUtils::createNode(0, 0, 200, 200,
+        card = TestUtils::createNode(0, 0, 400, 800,
                 [](RenderProperties& props, TestCanvas& canvas) {
-            canvas.saveLayerAlpha(0, 0, 200, 200, 128, SkCanvas::kClipToLayer_SaveFlag);
-            canvas.drawColor(0xFF00FF00, SkXfermode::kSrcOver_Mode); // outer, unclipped
-            canvas.saveLayerAlpha(50, 50, 150, 150, 128, SkCanvas::kClipToLayer_SaveFlag);
-            canvas.drawColor(0xFF0000FF, SkXfermode::kSrcOver_Mode); // inner, clipped
+            // nested clipped saveLayers
+            canvas.saveLayerAlpha(0, 0, 400, 400, 200, SaveFlags::ClipToLayer);
+            canvas.drawColor(Color::Green_700, SkXfermode::kSrcOver_Mode);
+            canvas.clipRect(50, 50, 350, 350, SkRegion::kIntersect_Op);
+            canvas.saveLayerAlpha(100, 100, 300, 300, 128, SaveFlags::ClipToLayer);
+            canvas.drawColor(Color::Blue_500, SkXfermode::kSrcOver_Mode);
+            canvas.restore();
+            canvas.restore();
+
+            // single unclipped saveLayer
+            canvas.save(SaveFlags::MatrixClip);
+            canvas.translate(0, 400);
+            canvas.saveLayerAlpha(100, 100, 300, 300, 128, SaveFlags::Flags(0)); // unclipped
+            SkPaint paint;
+            paint.setAntiAlias(true);
+            paint.setColor(Color::Green_700);
+            canvas.drawCircle(200, 200, 200, paint);
             canvas.restore();
             canvas.restore();
         });
diff --git a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
index 0cba344..6d27c9d 100644
--- a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
@@ -69,7 +69,7 @@
             float cellSize = floorf(width / 7 - cellSpace);
 
             // each combination of strokeWidth + style gets a column
-            int outerCount = canvas.save(SkCanvas::kMatrixClip_SaveFlag);
+            int outerCount = canvas.save(SaveFlags::MatrixClip);
             SkPaint paint;
             paint.setAntiAlias(true);
             SkPaint::Style styles[] = {
@@ -79,9 +79,9 @@
                 for (auto strokeWidth : { 0.0f, 0.5f, 8.0f }) {
                     paint.setStrokeWidth(strokeWidth);
                     // fill column with each op
-                    int middleCount = canvas.save(SkCanvas::kMatrixClip_SaveFlag);
+                    int middleCount = canvas.save(SaveFlags::MatrixClip);
                     for (auto op : ops) {
-                        int innerCount = canvas.save(SkCanvas::kMatrixClip_SaveFlag);
+                        int innerCount = canvas.save(SaveFlags::MatrixClip);
                         canvas.clipRect(0, 0, cellSize, cellSize, SkRegion::kIntersect_Op);
                         canvas.drawColor(Color::White, SkXfermode::Mode::kSrcOver_Mode);
                         op(canvas, cellSize, paint);
diff --git a/libs/hwui/tests/common/scenes/TestSceneBase.h b/libs/hwui/tests/common/scenes/TestSceneBase.h
index ac78124..935ddcf 100644
--- a/libs/hwui/tests/common/scenes/TestSceneBase.h
+++ b/libs/hwui/tests/common/scenes/TestSceneBase.h
@@ -22,6 +22,7 @@
 #include "tests/common/TestContext.h"
 #include "tests/common/TestScene.h"
 #include "tests/common/TestUtils.h"
+#include "utils/Color.h"
 
 #include <functional>
 
diff --git a/libs/hwui/tests/common/scenes/TextAnimation.cpp b/libs/hwui/tests/common/scenes/TextAnimation.cpp
new file mode 100644
index 0000000..1823db2
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/TextAnimation.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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"
+
+class TextAnimation;
+
+static TestScene::Registrar _Text(TestScene::Info{
+    "text",
+    "Draws a bunch of text.",
+    TestScene::simpleCreateScene<TextAnimation>
+});
+
+class TextAnimation : public TestScene {
+public:
+    sp<RenderNode> card;
+    void createContent(int width, int height, TestCanvas& canvas) override {
+        canvas.drawColor(Color::White, SkXfermode::kSrcOver_Mode);
+        card = TestUtils::createNode(0, 0, width, height,
+                [](RenderProperties& props, TestCanvas& canvas) {
+            SkPaint paint;
+            paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+            paint.setAntiAlias(true);
+            paint.setTextSize(50);
+
+            paint.setColor(Color::Black);
+            for (int i = 0; i < 10; i++) {
+                TestUtils::drawTextToCanvas(&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);
+        });
+        canvas.drawRenderNode(card.get());
+    }
+
+    void doFrame(int frameNr) override {
+        int curFrame = frameNr % 150;
+        card->mutateStagingProperties().setTranslationX(curFrame);
+        card->mutateStagingProperties().setTranslationY(curFrame);
+        card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+    }
+};
diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index 8261220..a843e92 100644
--- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp
+++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
@@ -38,6 +38,30 @@
     }
 };
 
+template<class T>
+class ModifiedMovingAverage {
+public:
+    ModifiedMovingAverage(int weight) : mWeight(weight) {}
+
+    T add(T today) {
+        if (!mHasValue) {
+            mAverage = today;
+        } else {
+            mAverage = (((mWeight - 1) * mAverage) + today) / mWeight;
+        }
+        return mAverage;
+    }
+
+    T average() {
+        return mAverage;
+    }
+
+private:
+    bool mHasValue = false;
+    int mWeight;
+    T mAverage;
+};
+
 void run(const TestScene::Info& info, const TestScene::Options& opts) {
     // Switch to the real display
     gDisplay = getBuiltInDisplay();
@@ -67,22 +91,35 @@
     proxy->setLightCenter((Vector3){lightX, dp(-200.0f), dp(800.0f)});
 
     // Do a few cold runs then reset the stats so that the caches are all hot
-    for (int i = 0; i < 3; i++) {
+    for (int i = 0; i < 5; i++) {
         testContext.waitForVsync();
         nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
         UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
         proxy->syncAndDrawFrame();
     }
+
     proxy->resetProfileInfo();
+    proxy->fence();
+
+    ModifiedMovingAverage<double> avgMs(opts.reportFrametimeWeight);
 
     for (int i = 0; i < opts.count; i++) {
         testContext.waitForVsync();
-
-        ATRACE_NAME("UI-Draw Frame");
         nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
-        UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
-        scene->doFrame(i);
-        proxy->syncAndDrawFrame();
+        {
+            ATRACE_NAME("UI-Draw Frame");
+            UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
+            scene->doFrame(i);
+            proxy->syncAndDrawFrame();
+        }
+        proxy->fence();
+        nsecs_t done = systemTime(CLOCK_MONOTONIC);
+        if (opts.reportFrametimeWeight) {
+            avgMs.add((done - vsync) / 1000000.0);
+            if (i % 10 == 9) {
+                printf("Average frametime %.3fms\n", avgMs.average());
+            }
+        }
     }
 
     proxy->dumpProfileInfo(STDOUT_FILENO, 0);
diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp
index 619713c..02a3950 100644
--- a/libs/hwui/tests/macrobench/main.cpp
+++ b/libs/hwui/tests/macrobench/main.cpp
@@ -17,6 +17,7 @@
 #include "tests/common/TestScene.h"
 
 #include "protos/hwui.pb.h"
+#include "Properties.h"
 
 #include <getopt.h>
 #include <stdio.h>
@@ -24,27 +25,40 @@
 #include <unistd.h>
 #include <unordered_map>
 #include <vector>
+#include <pthread.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
 
 using namespace android;
 using namespace android::uirenderer;
 using namespace android::uirenderer::test;
 
-static int gFrameCount = 150;
 static int gRepeatCount = 1;
 static std::vector<TestScene::Info> gRunTests;
+static TestScene::Options gOpts;
 
 void run(const TestScene::Info& info, const TestScene::Options& opts);
 
 static void printHelp() {
-    printf("\
-USAGE: hwuitest [OPTIONS] <TESTNAME>\n\
-\n\
-OPTIONS:\n\
-  -c, --count=NUM      NUM loops a test should run (example, number of frames)\n\
-  -r, --runs=NUM       Repeat the test(s) NUM times\n\
-  -h, --help           Display this help\n\
-  --list               List all tests\n\
-\n");
+    printf(R"(
+USAGE: hwuitest [OPTIONS] <TESTNAME>
+
+OPTIONS:
+  -c, --count=NUM      NUM loops a test should run (example, number of frames)
+  -r, --runs=NUM       Repeat the test(s) NUM times
+  -h, --help           Display this help
+  --list               List all tests
+  --wait-for-gpu       Set this to wait for the GPU before producing the
+                       next frame. Note that without locked clocks this will
+                       pathologically bad performance due to large idle time
+  --report-frametime[=weight] If set, the test will print to stdout the
+                       moving average frametime. Weight is optional, default is 10
+  --cpuset=name        Adds the test to the specified cpuset before running
+                       Not supported on all devices and needs root
+)");
 }
 
 static void listTests() {
@@ -77,11 +91,56 @@
     }
 }
 
+static void moveToCpuSet(const char* cpusetName) {
+    if (access("/dev/cpuset/tasks", F_OK)) {
+        fprintf(stderr, "don't have access to cpusets, skipping...\n");
+        return;
+    }
+    static const int BUF_SIZE = 100;
+    char buffer[BUF_SIZE];
+
+    if (snprintf(buffer, BUF_SIZE, "/dev/cpuset/%s/tasks", cpusetName) >= BUF_SIZE) {
+        fprintf(stderr, "Error, cpusetName too large to fit in buffer '%s'\n", cpusetName);
+        return;
+    }
+    int fd = open(buffer, O_WRONLY | O_CLOEXEC);
+    if (fd == -1) {
+        fprintf(stderr, "Error opening file %d\n", errno);
+        return;
+    }
+    pid_t pid = getpid();
+
+    int towrite = snprintf(buffer, BUF_SIZE, "%ld", (long) pid);
+    if (towrite >= BUF_SIZE) {
+        fprintf(stderr, "Buffer wasn't large enough?\n");
+    } else {
+        if (write(fd, buffer, towrite) != towrite) {
+            fprintf(stderr, "Failed to write, errno=%d", errno);
+        }
+    }
+    close(fd);
+}
+
+// For options that only exist in long-form. Anything in the
+// 0-255 range is reserved for short options (which just use their ASCII value)
+namespace LongOpts {
+enum {
+    Reserved = 255,
+    List,
+    WaitForGpu,
+    ReportFrametime,
+    CpuSet,
+};
+}
+
 static const struct option LONG_OPTIONS[] = {
     { "frames", required_argument, nullptr, 'f' },
     { "repeat", required_argument, nullptr, 'r' },
     { "help", no_argument, nullptr, 'h' },
-    { "list", no_argument, nullptr, 'l' },
+    { "list", no_argument, nullptr, LongOpts::List },
+    { "wait-for-gpu", no_argument, nullptr, LongOpts::WaitForGpu },
+    { "report-frametime", optional_argument, nullptr, LongOpts::ReportFrametime },
+    { "cpuset", required_argument, nullptr, LongOpts::CpuSet },
     { 0, 0, 0, 0 }
 };
 
@@ -89,8 +148,6 @@
 
 void parseOptions(int argc, char* argv[]) {
     int c;
-    // temporary variable
-    int count;
     bool error = false;
     opterr = 0;
 
@@ -110,31 +167,53 @@
             // (although none of the current LONG_OPTIONS do this...)
             break;
 
-        case 'l':
+        case LongOpts::List:
             listTests();
             exit(EXIT_SUCCESS);
             break;
 
         case 'c':
-            count = atoi(optarg);
-            if (!count) {
+            gOpts.count = atoi(optarg);
+            if (!gOpts.count) {
                 fprintf(stderr, "Invalid frames argument '%s'\n", optarg);
                 error = true;
-            } else {
-                gFrameCount = (count > 0 ? count : INT_MAX);
             }
             break;
 
         case 'r':
-            count = atoi(optarg);
-            if (!count) {
+            gRepeatCount = atoi(optarg);
+            if (!gRepeatCount) {
                 fprintf(stderr, "Invalid repeat argument '%s'\n", optarg);
                 error = true;
             } else {
-                gRepeatCount = (count > 0 ? count : INT_MAX);
+                gRepeatCount = (gRepeatCount > 0 ? gRepeatCount : INT_MAX);
             }
             break;
 
+        case LongOpts::ReportFrametime:
+            if (optarg) {
+                gOpts.reportFrametimeWeight = atoi(optarg);
+                if (!gOpts.reportFrametimeWeight) {
+                    fprintf(stderr, "Invalid report frametime weight '%s'\n", optarg);
+                    error = true;
+                }
+            } else {
+                gOpts.reportFrametimeWeight = 10;
+            }
+            break;
+
+        case LongOpts::WaitForGpu:
+            Properties::waitForGpuCompletion = true;
+            break;
+
+        case LongOpts::CpuSet:
+            if (!optarg) {
+                error = true;
+                break;
+            }
+            moveToCpuSet(optarg);
+            break;
+
         case 'h':
             printHelp();
             exit(EXIT_SUCCESS);
@@ -172,13 +251,14 @@
 }
 
 int main(int argc, char* argv[]) {
+    // set defaults
+    gOpts.count = 150;
+
     parseOptions(argc, argv);
 
-    TestScene::Options opts;
-    opts.count = gFrameCount;
     for (int i = 0; i < gRepeatCount; i++) {
         for (auto&& test : gRunTests) {
-            run(test, opts);
+            run(test, gOpts);
         }
     }
     printf("Success!\n");
diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
index 2e59eb4..83af148 100644
--- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
+++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
@@ -78,8 +78,8 @@
     StartBenchmarkTiming();
     for (int i = 0; i < iters; ++i) {
         canvas.reset(100, 100);
-        canvas.save(SkCanvas::kMatrixClip_SaveFlag);
-        canvas.save(SkCanvas::kMatrixClip_SaveFlag);
+        canvas.save(SaveFlags::MatrixClip);
+        canvas.save(SaveFlags::MatrixClip);
         MicroBench::DoNotOptimize(&canvas);
         canvas.restore();
         canvas.restore();
@@ -121,12 +121,12 @@
     for (int i = 0; i < iters; ++i) {
         canvas.reset(100, 100);
         {
-            canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+            canvas.save(SaveFlags::MatrixClip);
             canvas.drawRect(0, 0, 100, 100, rectPaint);
             canvas.restore();
         }
         {
-            canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+            canvas.save(SaveFlags::MatrixClip);
             canvas.translate(10, 10);
             canvas.drawBitmap(iconBitmap, 0, 0, nullptr);
             canvas.restore();
@@ -151,8 +151,8 @@
 
     StartBenchmarkTiming();
     for (int i = 0; i < iters; ++i) {
-        state.save(SkCanvas::kMatrixClip_SaveFlag);
-        state.save(SkCanvas::kMatrixClip_SaveFlag);
+        state.save(SaveFlags::MatrixClip);
+        state.save(SaveFlags::MatrixClip);
         MicroBench::DoNotOptimize(&state);
         state.restore();
         state.restore();
diff --git a/libs/hwui/tests/microbench/FrameBuilderBench.cpp b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
new file mode 100644
index 0000000..f9c2b67
--- /dev/null
+++ b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
@@ -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.
+ */
+
+#include <benchmark/Benchmark.h>
+
+#include "BakedOpState.h"
+#include "BakedOpDispatcher.h"
+#include "BakedOpRenderer.h"
+#include "FrameBuilder.h"
+#include "LayerUpdateQueue.h"
+#include "RecordedOp.h"
+#include "RecordingCanvas.h"
+#include "tests/common/TestContext.h"
+#include "tests/common/TestScene.h"
+#include "tests/common/TestUtils.h"
+#include "Vector.h"
+#include "tests/microbench/MicroBench.h"
+
+#include <vector>
+
+using namespace android;
+using namespace android::uirenderer;
+using namespace android::uirenderer::renderthread;
+using namespace android::uirenderer::test;
+
+const LayerUpdateQueue sEmptyLayerUpdateQueue;
+const Vector3 sLightCenter = {100, 100, 100};
+
+static std::vector<sp<RenderNode>> createTestNodeList() {
+    auto node = TestUtils::createNode(0, 0, 200, 200,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        SkBitmap bitmap = TestUtils::createSkBitmap(10, 10);
+        SkPaint paint;
+
+        // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
+        // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
+        canvas.save(SaveFlags::MatrixClip);
+        for (int i = 0; i < 30; i++) {
+            canvas.translate(0, 10);
+            canvas.drawRect(0, 0, 10, 10, paint);
+            canvas.drawBitmap(bitmap, 5, 0, nullptr);
+        }
+        canvas.restore();
+    });
+    TestUtils::syncHierarchyPropertiesAndDisplayList(node);
+    std::vector<sp<RenderNode>> vec;
+    vec.emplace_back(node);
+    return vec;
+}
+
+BENCHMARK_NO_ARG(BM_FrameBuilder_defer);
+void BM_FrameBuilder_defer::Run(int iters) {
+    auto nodes = createTestNodeList();
+    StartBenchmarkTiming();
+    for (int i = 0; i < iters; i++) {
+        FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
+                nodes, sLightCenter);
+        MicroBench::DoNotOptimize(&frameBuilder);
+    }
+    StopBenchmarkTiming();
+}
+
+BENCHMARK_NO_ARG(BM_FrameBuilder_deferAndRender);
+void BM_FrameBuilder_deferAndRender::Run(int iters) {
+    TestUtils::runOnRenderThread([this, iters](RenderThread& thread) {
+        auto nodes = createTestNodeList();
+        BakedOpRenderer::LightInfo lightInfo = {50.0f, 128, 128 };
+
+        RenderState& renderState = thread.renderState();
+        Caches& caches = Caches::getInstance();
+
+        StartBenchmarkTiming();
+        for (int i = 0; i < iters; i++) {
+            FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
+                    nodes, sLightCenter);
+
+            BakedOpRenderer renderer(caches, renderState, true, lightInfo);
+            frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
+            MicroBench::DoNotOptimize(&renderer);
+        }
+        StopBenchmarkTiming();
+    });
+}
+
+static std::vector<sp<RenderNode>> getSyncedSceneNodes(const char* sceneName) {
+    gDisplay = getBuiltInDisplay(); // switch to real display if present
+
+    TestContext testContext;
+    TestScene::Options opts;
+    std::unique_ptr<TestScene> scene(TestScene::testMap()[sceneName].createScene(opts));
+
+    sp<RenderNode> rootNode = TestUtils::createNode(0, 0, gDisplay.w, gDisplay.h,
+                [&scene](RenderProperties& props, TestCanvas& canvas) {
+            scene->createContent(gDisplay.w, gDisplay.h, canvas);
+    });
+
+    TestUtils::syncHierarchyPropertiesAndDisplayList(rootNode);
+    std::vector<sp<RenderNode>> nodes;
+    nodes.emplace_back(rootNode);
+    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, sLightCenter);
+        MicroBench::DoNotOptimize(&frameBuilder);
+    }
+    benchmark.StopBenchmarkTiming();
+}
+
+static void benchDeferAndRenderScene(testing::Benchmark& benchmark,
+        int iters, const char* sceneName) {
+    TestUtils::runOnRenderThread([&benchmark, iters, sceneName](RenderThread& thread) {
+        auto nodes = getSyncedSceneNodes(sceneName);
+        BakedOpRenderer::LightInfo lightInfo = {50.0f, 128, 128 }; // TODO!
+
+        RenderState& renderState = thread.renderState();
+        Caches& caches = Caches::getInstance();
+
+        benchmark.StartBenchmarkTiming();
+        for (int i = 0; i < iters; i++) {
+            FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
+                    SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, gDisplay.h,
+                    nodes, sLightCenter);
+
+            BakedOpRenderer renderer(caches, renderState, true, lightInfo);
+            frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
+            MicroBench::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");
+}
+
diff --git a/libs/hwui/tests/microbench/OpReordererBench.cpp b/libs/hwui/tests/microbench/OpReordererBench.cpp
deleted file mode 100644
index 6bfe5a9..0000000
--- a/libs/hwui/tests/microbench/OpReordererBench.cpp
+++ /dev/null
@@ -1,160 +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 <benchmark/Benchmark.h>
-
-#include "BakedOpState.h"
-#include "BakedOpDispatcher.h"
-#include "BakedOpRenderer.h"
-#include "LayerUpdateQueue.h"
-#include "OpReorderer.h"
-#include "RecordedOp.h"
-#include "RecordingCanvas.h"
-#include "tests/common/TestContext.h"
-#include "tests/common/TestScene.h"
-#include "tests/common/TestUtils.h"
-#include "Vector.h"
-#include "tests/microbench/MicroBench.h"
-
-#include <vector>
-
-using namespace android;
-using namespace android::uirenderer;
-using namespace android::uirenderer::renderthread;
-using namespace android::uirenderer::test;
-
-const LayerUpdateQueue sEmptyLayerUpdateQueue;
-const Vector3 sLightCenter = {100, 100, 100};
-
-static std::vector<sp<RenderNode>> createTestNodeList() {
-    auto node = TestUtils::createNode(0, 0, 200, 200,
-            [](RenderProperties& props, RecordingCanvas& canvas) {
-        SkBitmap bitmap = TestUtils::createSkBitmap(10, 10);
-        SkPaint paint;
-
-        // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
-        // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
-        canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-        for (int i = 0; i < 30; i++) {
-            canvas.translate(0, 10);
-            canvas.drawRect(0, 0, 10, 10, paint);
-            canvas.drawBitmap(bitmap, 5, 0, nullptr);
-        }
-        canvas.restore();
-    });
-    TestUtils::syncHierarchyPropertiesAndDisplayList(node);
-    std::vector<sp<RenderNode>> vec;
-    vec.emplace_back(node);
-    return vec;
-}
-
-BENCHMARK_NO_ARG(BM_OpReorderer_defer);
-void BM_OpReorderer_defer::Run(int iters) {
-    auto nodes = createTestNodeList();
-    StartBenchmarkTiming();
-    for (int i = 0; i < iters; i++) {
-        OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
-                nodes, sLightCenter);
-        MicroBench::DoNotOptimize(&reorderer);
-    }
-    StopBenchmarkTiming();
-}
-
-BENCHMARK_NO_ARG(BM_OpReorderer_deferAndRender);
-void BM_OpReorderer_deferAndRender::Run(int iters) {
-    TestUtils::runOnRenderThread([this, iters](RenderThread& thread) {
-        auto nodes = createTestNodeList();
-        BakedOpRenderer::LightInfo lightInfo = {50.0f, 128, 128 };
-
-        RenderState& renderState = thread.renderState();
-        Caches& caches = Caches::getInstance();
-
-        StartBenchmarkTiming();
-        for (int i = 0; i < iters; i++) {
-            OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
-                    nodes, sLightCenter);
-
-            BakedOpRenderer renderer(caches, renderState, true, lightInfo);
-            reorderer.replayBakedOps<BakedOpDispatcher>(renderer);
-            MicroBench::DoNotOptimize(&renderer);
-        }
-        StopBenchmarkTiming();
-    });
-}
-
-static std::vector<sp<RenderNode>> getSyncedSceneNodes(const char* sceneName) {
-    gDisplay = getBuiltInDisplay(); // switch to real display if present
-
-    TestContext testContext;
-    TestScene::Options opts;
-    std::unique_ptr<TestScene> scene(TestScene::testMap()[sceneName].createScene(opts));
-
-    sp<RenderNode> rootNode = TestUtils::createNode(0, 0, gDisplay.w, gDisplay.h,
-                [&scene](RenderProperties& props, TestCanvas& canvas) {
-            scene->createContent(gDisplay.w, gDisplay.h, canvas);
-    });
-
-    TestUtils::syncHierarchyPropertiesAndDisplayList(rootNode);
-    std::vector<sp<RenderNode>> nodes;
-    nodes.emplace_back(rootNode);
-    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++) {
-        OpReorderer reorderer(sEmptyLayerUpdateQueue,
-                SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, gDisplay.h,
-                nodes, sLightCenter);
-        MicroBench::DoNotOptimize(&reorderer);
-    }
-    benchmark.StopBenchmarkTiming();
-}
-
-static void benchDeferAndRenderScene(testing::Benchmark& benchmark,
-        int iters, const char* sceneName) {
-    TestUtils::runOnRenderThread([&benchmark, iters, sceneName](RenderThread& thread) {
-        auto nodes = getSyncedSceneNodes(sceneName);
-        BakedOpRenderer::LightInfo lightInfo = {50.0f, 128, 128 }; // TODO!
-
-        RenderState& renderState = thread.renderState();
-        Caches& caches = Caches::getInstance();
-
-        benchmark.StartBenchmarkTiming();
-        for (int i = 0; i < iters; i++) {
-            OpReorderer reorderer(sEmptyLayerUpdateQueue,
-                    SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, gDisplay.h,
-                    nodes, sLightCenter);
-
-            BakedOpRenderer renderer(caches, renderState, true, lightInfo);
-            reorderer.replayBakedOps<BakedOpDispatcher>(renderer);
-            MicroBench::DoNotOptimize(&renderer);
-        }
-        benchmark.StopBenchmarkTiming();
-    });
-}
-
-BENCHMARK_NO_ARG(BM_OpReorderer_listview_defer);
-void BM_OpReorderer_listview_defer::Run(int iters) {
-    benchDeferScene(*this, iters, "listview");
-}
-
-BENCHMARK_NO_ARG(BM_OpReorderer_listview_deferAndRender);
-void BM_OpReorderer_listview_deferAndRender::Run(int iters) {
-    benchDeferAndRenderScene(*this, iters, "listview");
-}
-
diff --git a/libs/hwui/tests/microbench/PathParserBench.cpp b/libs/hwui/tests/microbench/PathParserBench.cpp
index 3d9fafa..bd742c6 100644
--- a/libs/hwui/tests/microbench/PathParserBench.cpp
+++ b/libs/hwui/tests/microbench/PathParserBench.cpp
@@ -17,7 +17,7 @@
 #include <benchmark/Benchmark.h>
 
 #include "PathParser.h"
-#include "VectorDrawablePath.h"
+#include "VectorDrawable.h"
 
 #include <SkPath.h>
 
diff --git a/libs/hwui/tests/scripts/prep_volantis.sh b/libs/hwui/tests/scripts/prep_volantis.sh
new file mode 100755
index 0000000..09d4869
--- /dev/null
+++ b/libs/hwui/tests/scripts/prep_volantis.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+adb root
+adb wait-for-device
+adb shell stop mpdecision
+adb shell stop perfd
+adb shell stop
+for pid in $( adb shell ps | awk '{ if ( $9 == "surfaceflinger" ) { print $2 } }' ); do
+    adb shell kill $pid
+done
+adb shell setprop debug.egl.traceGpuCompletion 1
+adb shell daemonize surfaceflinger
+sleep 3
+adb shell setprop service.bootanim.exit 1
+
+# cpu possible frequencies
+# 204000 229500 255000 280500 306000 331500 357000 382500 408000 433500 459000
+# 484500 510000 535500 561000 586500 612000 637500 663000 688500 714000 739500
+# 765000 790500 816000 841500 867000 892500 918000 943500 969000 994500 1020000
+# 1122000 1224000 1326000 1428000 1530000 1632000 1734000 1836000 1938000
+# 2014500 2091000 2193000 2295000 2397000 2499000
+
+S=1326000
+echo "set cpu $cpu to $S hz";
+adb shell "echo userspace > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
+adb shell "echo $S > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
+adb shell "echo $S > /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq"
+adb shell "echo $S > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed"
+
+#disable hotplug
+adb shell "echo 0 > /sys/devices/system/cpu/cpuquiet/tegra_cpuquiet/enable"
+
+# gbus possible rates
+# 72000 108000 180000 252000 324000 396000 468000 540000 612000 648000
+# 684000 708000 756000 804000 852000 (kHz)
+
+S=324000000
+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/BakedOpStateTests.cpp b/libs/hwui/tests/unit/BakedOpStateTests.cpp
index 33eff5b..0f8e047 100644
--- a/libs/hwui/tests/unit/BakedOpStateTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpStateTests.cpp
@@ -17,6 +17,7 @@
 #include <gtest/gtest.h>
 
 #include <BakedOpState.h>
+#include <ClipArea.h>
 #include <RecordedOp.h>
 #include <tests/common/TestUtils.h>
 
@@ -24,31 +25,33 @@
 namespace uirenderer {
 
 TEST(ResolvedRenderState, construct) {
+    LinearAllocator allocator;
     Matrix4 translate10x20;
     translate10x20.loadTranslate(10, 20, 0);
 
     SkPaint paint;
-    RectOp recordedOp(Rect(30, 40, 100, 200), translate10x20, Rect(100, 200), &paint);
+    ClipRect clip(Rect(100, 200));
+    RectOp recordedOp(Rect(30, 40, 100, 200), translate10x20, &clip, &paint);
     {
         // recorded with transform, no parent transform
         auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
-        ResolvedRenderState state(*parentSnapshot, recordedOp, false);
+        ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
         EXPECT_MATRIX_APPROX_EQ(state.transform, translate10x20);
-        EXPECT_EQ(Rect(100, 200), state.clipRect);
+        EXPECT_EQ(Rect(100, 200), state.clipRect());
         EXPECT_EQ(Rect(40, 60, 100, 200), state.clippedBounds); // translated and also clipped
         EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags);
     }
     {
         // recorded with transform and parent transform
         auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
-        ResolvedRenderState state(*parentSnapshot, recordedOp, false);
+        ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
 
         Matrix4 expectedTranslate;
         expectedTranslate.loadTranslate(20, 40, 0);
         EXPECT_MATRIX_APPROX_EQ(expectedTranslate, state.transform);
 
         // intersection of parent & transformed child clip
-        EXPECT_EQ(Rect(10, 20, 100, 200), state.clipRect);
+        EXPECT_EQ(Rect(10, 20, 100, 200), state.clipRect());
 
         // translated and also clipped
         EXPECT_EQ(Rect(50, 80, 100, 200), state.clippedBounds);
@@ -56,6 +59,30 @@
     }
 }
 
+TEST(ResolvedRenderState, computeLocalSpaceClip) {
+    LinearAllocator allocator;
+    Matrix4 translate10x20;
+    translate10x20.loadTranslate(10, 20, 0);
+
+    SkPaint paint;
+    ClipRect clip(Rect(100, 200));
+    RectOp recordedOp(Rect(1000, 1000), translate10x20, &clip, &paint);
+    {
+        // recorded with transform, no parent transform
+        auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
+        ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
+        EXPECT_EQ(Rect(-10, -20, 90, 180), state.computeLocalSpaceClip())
+            << "Local clip rect should be 100x200, offset by -10,-20";
+    }
+    {
+        // recorded with transform + parent transform
+        auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
+        ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
+        EXPECT_EQ(Rect(-10, -20, 80, 160), state.computeLocalSpaceClip())
+            << "Local clip rect should be 90x190, offset by -10,-20";
+    }
+}
+
 const float HAIRLINE = 0.0f;
 
 // Note: bounds will be conservative, but not precise for non-hairline
@@ -127,6 +154,7 @@
 };
 
 TEST(ResolvedRenderState, construct_expandForStroke) {
+    LinearAllocator allocator;
     // Loop over table of test cases and verify different combinations of stroke width and transform
     for (auto&& testCase : sStrokeTestCases) {
         SkPaint strokedPaint;
@@ -134,58 +162,64 @@
         strokedPaint.setStyle(SkPaint::kStroke_Style);
         strokedPaint.setStrokeWidth(testCase.strokeWidth);
 
+        ClipRect clip(Rect(200, 200));
         RectOp recordedOp(Rect(50, 50, 150, 150),
-                Matrix4::identity(), Rect(200, 200), &strokedPaint);
+                Matrix4::identity(), &clip, &strokedPaint);
 
         Matrix4 snapshotMatrix;
         snapshotMatrix.loadScale(testCase.scale, testCase.scale, 1);
         auto parentSnapshot = TestUtils::makeSnapshot(snapshotMatrix, Rect(200, 200));
 
-        ResolvedRenderState state(*parentSnapshot, recordedOp, true);
+        ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, true);
         testCase.validator(state);
     }
 }
 
 TEST(BakedOpState, tryConstruct) {
-    LinearAllocator allocator;
-
     Matrix4 translate100x0;
     translate100x0.loadTranslate(100, 0, 0);
 
     SkPaint paint;
-    {
-        RectOp rejectOp(Rect(30, 40, 100, 200), translate100x0, Rect(100, 200), &paint);
-        auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
-        BakedOpState* bakedState = BakedOpState::tryConstruct(allocator, *snapshot, rejectOp);
+    ClipRect clip(Rect(100, 200));
 
-        EXPECT_EQ(nullptr, bakedState); // rejected by clip, so not constructed
-        EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op
-    }
-    {
-        RectOp successOp(Rect(30, 40, 100, 200), Matrix4::identity(), Rect(100, 200), &paint);
-        auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
-        BakedOpState* bakedState = BakedOpState::tryConstruct(allocator, *snapshot, successOp);
+    LinearAllocator allocator;
+    RectOp successOp(Rect(30, 40, 100, 200), Matrix4::identity(), &clip, &paint);
+    auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
+    EXPECT_NE(nullptr, BakedOpState::tryConstruct(allocator, *snapshot, successOp))
+            << "successOp NOT rejected by clip, so should be constructed";
+    size_t successAllocSize = allocator.usedSize();
+    EXPECT_LE(64u, successAllocSize) << "relatively large alloc for non-rejected op";
 
-        EXPECT_NE(nullptr, bakedState); // NOT rejected by clip, so will be constructed
-        EXPECT_LE(64u, allocator.usedSize()); // relatively large alloc for non-rejected op
-    }
+    RectOp rejectOp(Rect(30, 40, 100, 200), translate100x0, &clip, &paint);
+    EXPECT_EQ(nullptr, BakedOpState::tryConstruct(allocator, *snapshot, rejectOp))
+            << "rejectOp rejected by clip, so should not be constructed";
+
+    // NOTE: this relies on the clip having already been serialized by the op above
+    EXPECT_EQ(successAllocSize, allocator.usedSize()) << "no extra allocation used for rejected op";
 }
 
 TEST(BakedOpState, tryShadowOpConstruct) {
+    Matrix4 translate10x20;
+    translate10x20.loadTranslate(10, 20, 0);
+
     LinearAllocator allocator;
     {
-        auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip
+        auto snapshot = TestUtils::makeSnapshot(translate10x20, Rect()); // Note: empty clip
         BakedOpState* bakedState = BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
 
-        EXPECT_EQ(nullptr, bakedState); // rejected by clip, so not constructed
-        EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op
+        EXPECT_EQ(nullptr, bakedState) << "op should be rejected by clip, so not constructed";
+        EXPECT_EQ(0u, allocator.usedSize()) << "no serialization, even for clip,"
+                "since op is quick rejected based on snapshot clip";
     }
     {
-        auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
+        auto snapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
         BakedOpState* bakedState = BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
 
-        ASSERT_NE(nullptr, bakedState); // NOT rejected by clip, so will be constructed
-        EXPECT_LE(64u, allocator.usedSize()); // relatively large alloc for non-rejected op
+        ASSERT_NE(nullptr, bakedState) << "NOT rejected by clip, so op should be constructed";
+        EXPECT_LE(64u, allocator.usedSize()) << "relatively large alloc for non-rejected op";
+
+        EXPECT_MATRIX_APPROX_EQ(translate10x20, bakedState->computedState.transform);
+        EXPECT_EQ(Rect(100, 200), bakedState->computedState.clippedBounds);
     }
 }
 
@@ -196,7 +230,8 @@
         SkPaint paint;
         paint.setStyle(SkPaint::kStrokeAndFill_Style);
         paint.setStrokeWidth(0.0f);
-        RectOp rejectOp(Rect(100, 200), Matrix4::identity(), Rect(100, 200), &paint);
+        ClipRect clip(Rect(100, 200));
+        RectOp rejectOp(Rect(100, 200), Matrix4::identity(), &clip, &paint);
         auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip
         auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
                 BakedOpState::StrokeBehavior::StyleDefined);
@@ -209,7 +244,8 @@
         SkPaint paint;
         paint.setStyle(SkPaint::kStrokeAndFill_Style);
         paint.setStrokeWidth(10.0f);
-        RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), Rect(200, 200), &paint);
+        ClipRect clip(Rect(200, 200));
+        RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint);
         auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
         auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
                 BakedOpState::StrokeBehavior::StyleDefined);
@@ -223,7 +259,8 @@
         SkPaint paint;
         paint.setStyle(SkPaint::kFill_Style);
         paint.setStrokeWidth(10.0f);
-        RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), Rect(200, 200), &paint);
+        ClipRect clip(Rect(200, 200));
+        RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint);
         auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
         auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
                 BakedOpState::StrokeBehavior::Forced);
diff --git a/libs/hwui/tests/unit/BufferPoolTests.cpp b/libs/hwui/tests/unit/BufferPoolTests.cpp
new file mode 100644
index 0000000..44e6d3a
--- /dev/null
+++ b/libs/hwui/tests/unit/BufferPoolTests.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <BufferPool.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace uirenderer {
+
+TEST(BufferPool, acquireThenRelease) {
+    static const int numRuns = 5;
+
+    // 10 buffers of size 1
+    static const size_t bufferSize = 1;
+    static const size_t bufferCount = 10;
+    sp<BufferPool> pool = new BufferPool(bufferSize, bufferCount);
+
+    for (int run = 0; run < numRuns; run++) {
+        BufferPool::Buffer* acquiredBuffers[bufferCount];
+        for (size_t i = 0; i < bufferCount; i++) {
+            ASSERT_EQ(bufferCount - i, pool->getAvailableBufferCount());
+            acquiredBuffers[i] = pool->acquire();
+            ASSERT_NE(nullptr, acquiredBuffers[i]);
+            ASSERT_TRUE(acquiredBuffers[i]->isUniqueRef());
+        }
+
+        for (size_t i = 0; i < bufferCount; i++) {
+            ASSERT_EQ(i, pool->getAvailableBufferCount());
+            acquiredBuffers[i]->release();
+            acquiredBuffers[i] = nullptr;
+        }
+
+        ASSERT_EQ(bufferCount, pool->getAvailableBufferCount());
+    }
+}
+
+TEST(BufferPool, acquireReleaseInterleaved) {
+    static const int numRuns = 5;
+
+    // 10 buffers of size 1
+    static const size_t bufferSize = 1;
+    static const size_t bufferCount = 10;
+
+    sp<BufferPool> pool = new BufferPool(bufferSize, bufferCount);
+
+    for (int run = 0; run < numRuns; run++) {
+        BufferPool::Buffer* acquiredBuffers[bufferCount];
+
+        // acquire all
+        for (size_t i = 0; i < bufferCount; i++) {
+            ASSERT_EQ(bufferCount - i, pool->getAvailableBufferCount());
+            acquiredBuffers[i] = pool->acquire();
+            ASSERT_NE(nullptr, acquiredBuffers[i]);
+        }
+
+        // release half
+        for (size_t i = 0; i < bufferCount / 2; i++) {
+            ASSERT_EQ(i, pool->getAvailableBufferCount());
+            acquiredBuffers[i]->release();
+            acquiredBuffers[i] = nullptr;
+        }
+
+        const size_t expectedRemaining = bufferCount / 2;
+        ASSERT_EQ(expectedRemaining, pool->getAvailableBufferCount());
+
+        // acquire half
+        for (size_t i = 0; i < bufferCount / 2; i++) {
+            ASSERT_EQ(expectedRemaining - i, pool->getAvailableBufferCount());
+            acquiredBuffers[i] = pool->acquire();
+        }
+
+        // acquire one more, should fail
+        ASSERT_EQ(nullptr, pool->acquire());
+
+        // release all
+        for (size_t i = 0; i < bufferCount; i++) {
+            ASSERT_EQ(i, pool->getAvailableBufferCount());
+            acquiredBuffers[i]->release();
+            acquiredBuffers[i] = nullptr;
+        }
+
+        ASSERT_EQ(bufferCount, pool->getAvailableBufferCount());
+    }
+}
+
+};
+};
diff --git a/libs/hwui/tests/unit/CanvasStateTests.cpp b/libs/hwui/tests/unit/CanvasStateTests.cpp
index 4df2687..68d74ee 100644
--- a/libs/hwui/tests/unit/CanvasStateTests.cpp
+++ b/libs/hwui/tests/unit/CanvasStateTests.cpp
@@ -16,6 +16,7 @@
 
 #include "CanvasState.h"
 
+#include "Canvas.h"
 #include "Matrix.h"
 #include "Rect.h"
 #include "utils/LinearAllocator.h"
@@ -23,7 +24,6 @@
 #include <gtest/gtest.h>
 #include <SkPath.h>
 #include <SkRegion.h>
-#include <SkCanvas.h>
 
 namespace android {
 namespace uirenderer {
@@ -83,7 +83,7 @@
     state.initializeSaveStack(200, 200,
             0, 0, 200, 200, Vector3());
 
-    state.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
+    state.save(SaveFlags::MatrixClip);
     {
         // rotated clip causes complex clip
         state.rotate(10);
@@ -93,7 +93,7 @@
     }
     state.restore();
 
-    state.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
+    state.save(SaveFlags::MatrixClip);
     {
         // subtracted clip causes complex clip
         EXPECT_TRUE(state.clipIsSimple());
@@ -102,7 +102,7 @@
     }
     state.restore();
 
-    state.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
+    state.save(SaveFlags::MatrixClip);
     {
         // complex path causes complex clip
         SkPath path;
@@ -119,7 +119,7 @@
     state.initializeSaveStack(200, 200,
             0, 0, 200, 200, Vector3());
 
-    state.save(SkCanvas::kClip_SaveFlag);
+    state.save(SaveFlags::Clip);
     {
         state.clipRect(0, 0, 10, 10, SkRegion::kIntersect_Op);
         ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10));
@@ -129,7 +129,7 @@
 
     Matrix4 simpleTranslate;
     simpleTranslate.loadTranslate(10, 10, 0);
-    state.save(SkCanvas::kMatrix_SaveFlag);
+    state.save(SaveFlags::Matrix);
     {
         state.translate(10, 10, 0);
         EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
@@ -143,7 +143,7 @@
     state.initializeSaveStack(200, 200,
             0, 0, 200, 200, Vector3());
 
-    state.save(SkCanvas::kMatrix_SaveFlag); // NOTE: clip not saved
+    state.save(SaveFlags::Matrix); // NOTE: clip not saved
     {
         state.clipRect(0, 0, 10, 10, SkRegion::kIntersect_Op);
         ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10));
@@ -153,7 +153,7 @@
 
     Matrix4 simpleTranslate;
     simpleTranslate.loadTranslate(10, 10, 0);
-    state.save(SkCanvas::kClip_SaveFlag); // NOTE: matrix not saved
+    state.save(SaveFlags::Clip); // NOTE: matrix not saved
     {
         state.translate(10, 10, 0);
         EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
diff --git a/libs/hwui/tests/unit/ClipAreaTests.cpp b/libs/hwui/tests/unit/ClipAreaTests.cpp
index c4d305e..4cae737 100644
--- a/libs/hwui/tests/unit/ClipAreaTests.cpp
+++ b/libs/hwui/tests/unit/ClipAreaTests.cpp
@@ -119,5 +119,122 @@
     EXPECT_EQ(expected, area.getClipRect());
 }
 
+TEST(ClipArea, serializeClip) {
+    ClipArea area(createClipArea());
+    LinearAllocator allocator;
+
+    // unset clip
+    EXPECT_EQ(nullptr, area.serializeClip(allocator));
+
+    // rect clip
+    area.setClip(0, 0, 200, 200);
+    {
+        auto serializedClip = area.serializeClip(allocator);
+        ASSERT_NE(nullptr, serializedClip);
+        ASSERT_EQ(ClipMode::Rectangle, serializedClip->mode);
+        auto clipRect = reinterpret_cast<const ClipRect*>(serializedClip);
+        ASSERT_EQ(Rect(200, 200), clipRect->rect);
+        EXPECT_EQ(serializedClip, area.serializeClip(allocator))
+                << "Requery of clip on unmodified ClipArea must return same pointer.";
+    }
+
+    // rect list
+    Matrix4 rotate;
+    rotate.loadRotate(2.0f);
+    area.clipRectWithTransform(Rect(200, 200), &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);
+        ASSERT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount());
+        EXPECT_EQ(serializedClip, area.serializeClip(allocator))
+                << "Requery of clip on unmodified ClipArea must return same pointer.";
+    }
+
+    // region
+    SkPath circlePath;
+    circlePath.addCircle(100, 100, 100);
+    area.clipPathWithTransform(circlePath, &Matrix4::identity(), SkRegion::kReplace_Op);
+    {
+        auto serializedClip = area.serializeClip(allocator);
+        ASSERT_NE(nullptr, serializedClip);
+        ASSERT_EQ(ClipMode::Region, serializedClip->mode);
+        auto clipRegion = reinterpret_cast<const ClipRegion*>(serializedClip);
+        ASSERT_EQ(SkIRect::MakeWH(200, 200), clipRegion->region.getBounds())
+                << "Clip region should be 200x200";
+        EXPECT_EQ(serializedClip, area.serializeClip(allocator))
+                << "Requery of clip on unmodified ClipArea must return same pointer.";
+    }
 }
+
+TEST(ClipArea, serializeIntersectedClip) {
+    ClipArea area(createClipArea());
+    LinearAllocator allocator;
+
+    // simple state;
+    EXPECT_EQ(nullptr, area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity()));
+    area.setClip(0, 0, 200, 200);
+    {
+        auto origRectClip = area.serializeClip(allocator);
+        ASSERT_NE(nullptr, origRectClip);
+        EXPECT_EQ(origRectClip, area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity()));
+    }
+
+    // rect
+    {
+        ClipRect recordedClip(Rect(100, 100));
+        Matrix4 translateScale;
+        translateScale.loadTranslate(100, 100, 0);
+        translateScale.scale(2, 3, 1);
+        auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, translateScale);
+        ASSERT_NE(nullptr, resolvedClip);
+        ASSERT_EQ(ClipMode::Rectangle, resolvedClip->mode);
+        EXPECT_EQ(Rect(100, 100, 200, 200),
+                reinterpret_cast<const ClipRect*>(resolvedClip)->rect);
+
+        EXPECT_EQ(resolvedClip, area.serializeIntersectedClip(allocator, &recordedClip, translateScale))
+                << "Must return previous serialization, since input is same";
+
+        ClipRect recordedClip2(Rect(100, 100));
+        EXPECT_NE(resolvedClip, area.serializeIntersectedClip(allocator, &recordedClip2, translateScale))
+                << "Shouldn't return previous serialization, since matrix location is different";
+    }
+
+    // rect list
+    Matrix4 rotate;
+    rotate.loadRotate(2.0f);
+    area.clipRectWithTransform(Rect(200, 200), &rotate, SkRegion::kIntersect_Op);
+    {
+        ClipRect recordedClip(Rect(100, 100));
+        auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, Matrix4::identity());
+        ASSERT_NE(nullptr, resolvedClip);
+        ASSERT_EQ(ClipMode::RectangleList, resolvedClip->mode);
+        auto clipRectList = reinterpret_cast<const ClipRectList*>(resolvedClip);
+        EXPECT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount());
+    }
+
+    // region
+    SkPath circlePath;
+    circlePath.addCircle(100, 100, 100);
+    area.clipPathWithTransform(circlePath, &Matrix4::identity(), SkRegion::kReplace_Op);
+    {
+        SkPath ovalPath;
+        ovalPath.addOval(SkRect::MakeLTRB(50, 0, 150, 200));
+
+        ClipRegion recordedClip;
+        recordedClip.region.setPath(ovalPath, SkRegion(SkIRect::MakeWH(200, 200)));
+
+        Matrix4 translate10x20;
+        translate10x20.loadTranslate(10, 20, 0);
+        auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip,
+                translate10x20); // Note: only translate for now, others not handled correctly
+        ASSERT_NE(nullptr, resolvedClip);
+        ASSERT_EQ(ClipMode::Region, resolvedClip->mode);
+        auto clipRegion = reinterpret_cast<const ClipRegion*>(resolvedClip);
+        EXPECT_EQ(SkIRect::MakeLTRB(60, 20, 160, 200), clipRegion->region.getBounds());
+    }
 }
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/unit/CrashHandlerInjector.cpp b/libs/hwui/tests/unit/CrashHandlerInjector.cpp
new file mode 100644
index 0000000..b1c678d
--- /dev/null
+++ b/libs/hwui/tests/unit/CrashHandlerInjector.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
new file mode 100644
index 0000000..618df14
--- /dev/null
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -0,0 +1,1389 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <BakedOpState.h>
+#include <DeferredLayerUpdater.h>
+#include <FrameBuilder.h>
+#include <LayerUpdateQueue.h>
+#include <RecordedOp.h>
+#include <RecordingCanvas.h>
+#include <tests/common/TestUtils.h>
+
+#include <unordered_map>
+
+namespace android {
+namespace uirenderer {
+
+const LayerUpdateQueue sEmptyLayerUpdateQueue;
+const Vector3 sLightCenter = {100, 100, 100};
+
+/**
+ * Virtual class implemented by each test to redirect static operation / state transitions to
+ * virtual methods.
+ *
+ * Virtual dispatch allows for default behaviors to be specified (very common case in below tests),
+ * and allows Renderer vs Dispatching behavior to be merged.
+ *
+ * onXXXOp methods fail by default - tests should override ops they expect
+ * startRepaintLayer fails by default - tests should override if expected
+ * startFrame/endFrame do nothing by default - tests should override to intercept
+ */
+class TestRendererBase {
+public:
+    virtual ~TestRendererBase() {}
+    virtual OffscreenBuffer* startTemporaryLayer(uint32_t, uint32_t) {
+        ADD_FAILURE() << "Layer creation not expected in this test";
+        return nullptr;
+    }
+    virtual void startRepaintLayer(OffscreenBuffer*, const Rect& repaintRect) {
+        ADD_FAILURE() << "Layer repaint not expected in this test";
+    }
+    virtual void endLayer() {
+        ADD_FAILURE() << "Layer updates not expected in this test";
+    }
+    virtual void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {}
+    virtual void endFrame(const Rect& repaintRect) {}
+
+    // define virtual defaults for single draw methods
+#define X(Type) \
+    virtual void on##Type(const Type&, const BakedOpState&) { \
+        ADD_FAILURE() << #Type " not expected in this test"; \
+    }
+    MAP_RENDERABLE_OPS(X)
+#undef X
+
+    // define virtual defaults for merged draw methods
+#define X(Type) \
+    virtual void onMerged##Type##s(const MergedBakedOpList& opList) { \
+        ADD_FAILURE() << "Merged " #Type "s not expected in this test"; \
+    }
+    MAP_MERGEABLE_OPS(X)
+#undef X
+
+    int getIndex() { return mIndex; }
+
+protected:
+    int mIndex = 0;
+};
+
+/**
+ * Dispatches all static methods to similar formed methods on renderer, which fail by default but
+ * are overridden by subclasses per test.
+ */
+class TestDispatcher {
+public:
+    // define single op methods, which redirect to TestRendererBase
+#define X(Type) \
+    static void on##Type(TestRendererBase& renderer, const Type& op, const BakedOpState& state) { \
+        renderer.on##Type(op, state); \
+    }
+    MAP_RENDERABLE_OPS(X);
+#undef X
+
+    // define merged op methods, which redirect to TestRendererBase
+#define X(Type) \
+    static void onMerged##Type##s(TestRendererBase& renderer, const MergedBakedOpList& opList) { \
+        renderer.onMerged##Type##s(opList); \
+    }
+    MAP_MERGEABLE_OPS(X);
+#undef X
+};
+
+class FailRenderer : public TestRendererBase {};
+
+TEST(FrameBuilder, simple) {
+    class SimpleTestRenderer : public TestRendererBase {
+    public:
+        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
+            EXPECT_EQ(0, mIndex++);
+            EXPECT_EQ(100u, width);
+            EXPECT_EQ(200u, height);
+        }
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(1, mIndex++);
+        }
+        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(2, mIndex++);
+        }
+        void endFrame(const Rect& repaintRect) override {
+            EXPECT_EQ(3, mIndex++);
+        }
+    };
+
+    auto node = TestUtils::createNode(0, 0, 100, 200,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        SkBitmap bitmap = TestUtils::createSkBitmap(25, 25);
+        canvas.drawRect(0, 0, 100, 200, SkPaint());
+        canvas.drawBitmap(bitmap, 10, 10, nullptr);
+    });
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
+            TestUtils::createSyncedNodeList(node), sLightCenter);
+    SimpleTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
+}
+
+TEST(FrameBuilder, simpleStroke) {
+    class SimpleStrokeTestRenderer : public TestRendererBase {
+    public:
+        void onPointsOp(const PointsOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(0, mIndex++);
+            // even though initial bounds are empty...
+            EXPECT_TRUE(op.unmappedBounds.isEmpty())
+                    << "initial bounds should be empty, since they're unstroked";
+            EXPECT_EQ(Rect(45, 45, 55, 55), state.computedState.clippedBounds)
+                    << "final bounds should account for stroke";
+        }
+    };
+
+    auto node = TestUtils::createNode(0, 0, 100, 200,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        SkPaint strokedPaint;
+        strokedPaint.setStrokeWidth(10);
+        canvas.drawPoint(50, 50, strokedPaint);
+    });
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
+            TestUtils::createSyncedNodeList(node), sLightCenter);
+    SimpleStrokeTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(1, renderer.getIndex());
+}
+
+TEST(FrameBuilder, simpleRejection) {
+    auto node = TestUtils::createNode(0, 0, 200, 200,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        canvas.save(SaveFlags::MatrixClip);
+        canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op); // intersection should be empty
+        canvas.drawRect(0, 0, 400, 400, SkPaint());
+        canvas.restore();
+    });
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            TestUtils::createSyncedNodeList(node), sLightCenter);
+
+    FailRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+}
+
+TEST(FrameBuilder, simpleBatching) {
+    const int LOOPS = 5;
+    class SimpleBatchingTestRenderer : public TestRendererBase {
+    public:
+        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
+            EXPECT_TRUE(mIndex++ >= LOOPS) << "Bitmaps should be above all rects";
+        }
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            EXPECT_TRUE(mIndex++ < LOOPS) << "Rects should be below all bitmaps";
+        }
+    };
+
+    auto node = TestUtils::createNode(0, 0, 200, 200,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        SkBitmap bitmap = TestUtils::createSkBitmap(10, 10,
+                kAlpha_8_SkColorType); // Disable merging by using alpha 8 bitmap
+
+        // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
+        // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
+        canvas.save(SaveFlags::MatrixClip);
+        for (int i = 0; i < LOOPS; i++) {
+            canvas.translate(0, 10);
+            canvas.drawRect(0, 0, 10, 10, SkPaint());
+            canvas.drawBitmap(bitmap, 5, 0, nullptr);
+        }
+        canvas.restore();
+    });
+
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            TestUtils::createSyncedNodeList(node), sLightCenter);
+    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) {
+    class ClippedMergingTestRenderer : public TestRendererBase {
+    public:
+        void onMergedBitmapOps(const MergedBakedOpList& opList) override {
+            EXPECT_EQ(0, mIndex);
+            mIndex += opList.count;
+            EXPECT_EQ(4u, opList.count);
+            EXPECT_EQ(Rect(10, 10, 90, 90), opList.clip);
+            EXPECT_EQ(OpClipSideFlags::Left | OpClipSideFlags::Top | OpClipSideFlags::Right,
+                    opList.clipSideFlags);
+        }
+    };
+    auto node = TestUtils::createNode(0, 0, 100, 100,
+            [](RenderProperties& props, TestCanvas& canvas) {
+        SkBitmap bitmap = TestUtils::createSkBitmap(20, 20);
+
+        // left side clipped (to inset left half)
+        canvas.clipRect(10, 0, 50, 100, SkRegion::kReplace_Op);
+        canvas.drawBitmap(bitmap, 0, 40, nullptr);
+
+        // top side clipped (to inset top half)
+        canvas.clipRect(0, 10, 100, 50, SkRegion::kReplace_Op);
+        canvas.drawBitmap(bitmap, 40, 0, nullptr);
+
+        // right side clipped (to inset right half)
+        canvas.clipRect(50, 0, 90, 100, SkRegion::kReplace_Op);
+        canvas.drawBitmap(bitmap, 80, 40, nullptr);
+
+        // bottom not clipped, just abutting (inset bottom half)
+        canvas.clipRect(0, 50, 100, 90, SkRegion::kReplace_Op);
+        canvas.drawBitmap(bitmap, 40, 70, nullptr);
+    });
+
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
+            TestUtils::createSyncedNodeList(node), sLightCenter);
+    ClippedMergingTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(4, renderer.getIndex());
+}
+
+TEST(FrameBuilder, textMerging) {
+    class TextMergingTestRenderer : public TestRendererBase {
+    public:
+        void onMergedTextOps(const MergedBakedOpList& opList) override {
+            EXPECT_EQ(0, mIndex);
+            mIndex += opList.count;
+            EXPECT_EQ(2u, opList.count);
+            EXPECT_EQ(OpClipSideFlags::Top, opList.clipSideFlags);
+            EXPECT_EQ(OpClipSideFlags::Top, opList.states[0]->computedState.clipSideFlags);
+            EXPECT_EQ(OpClipSideFlags::None, opList.states[1]->computedState.clipSideFlags);
+        }
+    };
+    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);
+        TestUtils::drawTextToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
+        TestUtils::drawTextToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
+    });
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
+            TestUtils::createSyncedNodeList(node), sLightCenter);
+    TextMergingTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops";
+}
+
+TEST(FrameBuilder, textStrikethrough) {
+    const int LOOPS = 5;
+    class TextStrikethroughTestRenderer : public TestRendererBase {
+    public:
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            EXPECT_TRUE(mIndex++ >= LOOPS) << "Strikethrough rects should be above all text";
+        }
+        void onMergedTextOps(const MergedBakedOpList& opList) override {
+            EXPECT_EQ(0, mIndex);
+            mIndex += opList.count;
+            EXPECT_EQ(5u, opList.count);
+        }
+    };
+    auto node = TestUtils::createNode(0, 0, 200, 2000,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        SkPaint textPaint;
+        textPaint.setAntiAlias(true);
+        textPaint.setTextSize(20);
+        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));
+        }
+    });
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 2000), 200, 2000,
+            TestUtils::createSyncedNodeList(node), sLightCenter);
+    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 {
+    public:
+        void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(0, mIndex++);
+            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipRect());
+            EXPECT_EQ(Rect(50, 50, 105, 105), state.computedState.clippedBounds);
+
+            Matrix4 expected;
+            expected.loadTranslate(5, 5, 0);
+            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
+        }
+    };
+
+    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
+            [](Matrix4* transform) {
+        transform->loadTranslate(5, 5, 0);
+    });
+
+    auto node = TestUtils::createNode(0, 0, 200, 200,
+            [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
+        canvas.save(SaveFlags::MatrixClip);
+        canvas.clipRect(50, 50, 150, 150, SkRegion::kIntersect_Op);
+        canvas.drawLayer(layerUpdater.get());
+        canvas.restore();
+    });
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            TestUtils::createSyncedNodeList(node), sLightCenter);
+    TextureLayerTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(1, renderer.getIndex());
+}
+
+TEST(FrameBuilder, renderNode) {
+    class RenderNodeTestRenderer : public TestRendererBase {
+    public:
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            switch(mIndex++) {
+            case 0:
+                EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
+                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
+                break;
+            case 1:
+                EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds);
+                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
+                break;
+            default:
+                ADD_FAILURE();
+            }
+        }
+    };
+
+    auto child = TestUtils::createNode(10, 10, 110, 110,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        SkPaint paint;
+        paint.setColor(SK_ColorWHITE);
+        canvas.drawRect(0, 0, 100, 100, paint);
+    });
+
+    auto parent = TestUtils::createNode(0, 0, 200, 200,
+            [&child](RenderProperties& props, RecordingCanvas& canvas) {
+        SkPaint paint;
+        paint.setColor(SK_ColorDKGRAY);
+        canvas.drawRect(0, 0, 200, 200, paint);
+
+        canvas.save(SaveFlags::MatrixClip);
+        canvas.translate(40, 40);
+        canvas.drawRenderNode(child.get());
+        canvas.restore();
+    });
+
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            TestUtils::createSyncedNodeList(parent), sLightCenter);
+    RenderNodeTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+}
+
+TEST(FrameBuilder, clipped) {
+    class ClippedTestRenderer : public TestRendererBase {
+    public:
+        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(0, mIndex++);
+            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
+            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect());
+            EXPECT_TRUE(state.computedState.transform.isIdentity());
+        }
+    };
+
+    auto node = TestUtils::createNode(0, 0, 200, 200,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        SkBitmap bitmap = TestUtils::createSkBitmap(200, 200);
+        canvas.drawBitmap(bitmap, 0, 0, nullptr);
+    });
+
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
+            SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver
+            200, 200, TestUtils::createSyncedNodeList(node), sLightCenter);
+    ClippedTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+}
+
+TEST(FrameBuilder, saveLayer_simple) {
+    class SaveLayerSimpleTestRenderer : public TestRendererBase {
+    public:
+        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
+            EXPECT_EQ(0, mIndex++);
+            EXPECT_EQ(180u, width);
+            EXPECT_EQ(180u, height);
+            return nullptr;
+        }
+        void endLayer() override {
+            EXPECT_EQ(2, mIndex++);
+        }
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(1, mIndex++);
+            EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
+            EXPECT_EQ(Rect(180, 180), state.computedState.clippedBounds);
+            EXPECT_EQ(Rect(180, 180), state.computedState.clipRect());
+
+            Matrix4 expectedTransform;
+            expectedTransform.loadTranslate(-10, -10, 0);
+            EXPECT_MATRIX_APPROX_EQ(expectedTransform, state.computedState.transform);
+        }
+        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(3, mIndex++);
+            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
+            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
+            EXPECT_TRUE(state.computedState.transform.isIdentity());
+        }
+    };
+
+    auto node = TestUtils::createNode(0, 0, 200, 200,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        canvas.saveLayerAlpha(10, 10, 190, 190, 128, SaveFlags::ClipToLayer);
+        canvas.drawRect(10, 10, 190, 190, SkPaint());
+        canvas.restore();
+    });
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            TestUtils::createSyncedNodeList(node), sLightCenter);
+    SaveLayerSimpleTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(4, renderer.getIndex());
+}
+
+TEST(FrameBuilder, saveLayer_nested) {
+    /* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as:
+     * - startTemporaryLayer2, rect2 endLayer2
+     * - startTemporaryLayer1, rect1, drawLayer2, endLayer1
+     * - startFrame, layerOp1, endFrame
+     */
+    class SaveLayerNestedTestRenderer : public TestRendererBase {
+    public:
+        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
+            const int index = mIndex++;
+            if (index == 0) {
+                EXPECT_EQ(400u, width);
+                EXPECT_EQ(400u, height);
+                return (OffscreenBuffer*) 0x400;
+            } else if (index == 3) {
+                EXPECT_EQ(800u, width);
+                EXPECT_EQ(800u, height);
+                return (OffscreenBuffer*) 0x800;
+            } else { ADD_FAILURE(); }
+            return (OffscreenBuffer*) nullptr;
+        }
+        void endLayer() override {
+            int index = mIndex++;
+            EXPECT_TRUE(index == 2 || index == 6);
+        }
+        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
+            EXPECT_EQ(7, mIndex++);
+        }
+        void endFrame(const Rect& repaintRect) override {
+            EXPECT_EQ(9, mIndex++);
+        }
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            const int index = mIndex++;
+            if (index == 1) {
+                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner rect
+            } else if (index == 4) {
+                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer rect
+            } else { ADD_FAILURE(); }
+        }
+        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
+            const int index = mIndex++;
+            if (index == 5) {
+                EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
+                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner layer
+            } else if (index == 8) {
+                EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
+                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
+            } else { ADD_FAILURE(); }
+        }
+    };
+
+    auto node = TestUtils::createNode(0, 0, 800, 800,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        canvas.saveLayerAlpha(0, 0, 800, 800, 128, SaveFlags::ClipToLayer);
+        {
+            canvas.drawRect(0, 0, 800, 800, SkPaint());
+            canvas.saveLayerAlpha(0, 0, 400, 400, 128, SaveFlags::ClipToLayer);
+            {
+                canvas.drawRect(0, 0, 400, 400, SkPaint());
+            }
+            canvas.restore();
+        }
+        canvas.restore();
+    });
+
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(800, 800), 800, 800,
+            TestUtils::createSyncedNodeList(node), sLightCenter);
+    SaveLayerNestedTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(10, renderer.getIndex());
+}
+
+TEST(FrameBuilder, saveLayer_contentRejection) {
+        auto node = TestUtils::createNode(0, 0, 200, 200,
+                [](RenderProperties& props, RecordingCanvas& canvas) {
+        canvas.save(SaveFlags::MatrixClip);
+        canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op);
+        canvas.saveLayerAlpha(200, 200, 400, 400, 128, SaveFlags::ClipToLayer);
+
+        // draw within save layer may still be recorded, but shouldn't be drawn
+        canvas.drawRect(200, 200, 400, 400, SkPaint());
+
+        canvas.restore();
+        canvas.restore();
+    });
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            TestUtils::createSyncedNodeList(node), sLightCenter);
+
+    FailRenderer renderer;
+    // should see no ops, even within the layer, since the layer should be rejected
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+}
+
+TEST(FrameBuilder, saveLayerUnclipped_simple) {
+    class SaveLayerUnclippedSimpleTestRenderer : public TestRendererBase {
+    public:
+        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(0, mIndex++);
+            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
+            EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
+            EXPECT_TRUE(state.computedState.transform.isIdentity());
+        }
+        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(1, mIndex++);
+            ASSERT_NE(nullptr, op.paint);
+            ASSERT_EQ(SkXfermode::kClear_Mode, PaintUtils::getXfermodeDirect(op.paint));
+        }
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(2, mIndex++);
+            EXPECT_EQ(Rect(200, 200), op.unmappedBounds);
+            EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
+            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
+            EXPECT_TRUE(state.computedState.transform.isIdentity());
+        }
+        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(3, mIndex++);
+            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
+            EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
+            EXPECT_TRUE(state.computedState.transform.isIdentity());
+        }
+    };
+
+    auto node = TestUtils::createNode(0, 0, 200, 200,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
+        canvas.drawRect(0, 0, 200, 200, SkPaint());
+        canvas.restore();
+    });
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            TestUtils::createSyncedNodeList(node), sLightCenter);
+    SaveLayerUnclippedSimpleTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(4, renderer.getIndex());
+}
+
+TEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
+    class SaveLayerUnclippedMergedClearsTestRenderer : public TestRendererBase {
+    public:
+        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
+            int index = mIndex++;
+            EXPECT_GT(4, index);
+            EXPECT_EQ(5, op.unmappedBounds.getWidth());
+            EXPECT_EQ(5, op.unmappedBounds.getHeight());
+            if (index == 0) {
+                EXPECT_EQ(Rect(10, 10), state.computedState.clippedBounds);
+            } else if (index == 1) {
+                EXPECT_EQ(Rect(190, 0, 200, 10), state.computedState.clippedBounds);
+            } else if (index == 2) {
+                EXPECT_EQ(Rect(0, 190, 10, 200), state.computedState.clippedBounds);
+            } else if (index == 3) {
+                EXPECT_EQ(Rect(190, 190, 200, 200), state.computedState.clippedBounds);
+            }
+        }
+        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(4, mIndex++);
+            ASSERT_EQ(op.vertexCount, 16u);
+            for (size_t i = 0; i < op.vertexCount; i++) {
+                auto v = op.vertices[i];
+                EXPECT_TRUE(v.x == 0 || v.x == 10 || v.x == 190 || v.x == 200);
+                EXPECT_TRUE(v.y == 0 || v.y == 10 || v.y == 190 || v.y == 200);
+            }
+        }
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(5, mIndex++);
+        }
+        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
+            EXPECT_LT(5, mIndex++);
+        }
+    };
+
+    auto node = TestUtils::createNode(0, 0, 200, 200,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+
+        int restoreTo = canvas.save(SaveFlags::MatrixClip);
+        canvas.scale(2, 2);
+        canvas.saveLayerAlpha(0, 0, 5, 5, 128, SaveFlags::MatrixClip);
+        canvas.saveLayerAlpha(95, 0, 100, 5, 128, SaveFlags::MatrixClip);
+        canvas.saveLayerAlpha(0, 95, 5, 100, 128, SaveFlags::MatrixClip);
+        canvas.saveLayerAlpha(95, 95, 100, 100, 128, SaveFlags::MatrixClip);
+        canvas.drawRect(0, 0, 100, 100, SkPaint());
+        canvas.restoreToCount(restoreTo);
+    });
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            TestUtils::createSyncedNodeList(node), sLightCenter);
+    SaveLayerUnclippedMergedClearsTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(10, renderer.getIndex())
+            << "Expect 4 copyTos, 4 copyFroms, 1 clear SimpleRects, and 1 rect.";
+}
+
+/* saveLayerUnclipped { saveLayer { saveLayerUnclipped { rect } } } will play back as:
+ * - startTemporaryLayer, onCopyToLayer, onSimpleRects, onRect, onCopyFromLayer, endLayer
+ * - startFrame, onCopyToLayer, onSimpleRects, drawLayer, onCopyFromLayer, endframe
+ */
+TEST(FrameBuilder, saveLayerUnclipped_complex) {
+    class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase {
+    public:
+        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
+            EXPECT_EQ(0, mIndex++); // savelayer first
+            return (OffscreenBuffer*)0xabcd;
+        }
+        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
+            int index = mIndex++;
+            EXPECT_TRUE(index == 1 || index == 7);
+        }
+        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
+            int index = mIndex++;
+            EXPECT_TRUE(index == 2 || index == 8);
+        }
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(3, mIndex++);
+            Matrix4 expected;
+            expected.loadTranslate(-100, -100, 0);
+            EXPECT_EQ(Rect(100, 100, 200, 200), state.computedState.clippedBounds);
+            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
+        }
+        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
+            int index = mIndex++;
+            EXPECT_TRUE(index == 4 || index == 10);
+        }
+        void endLayer() override {
+            EXPECT_EQ(5, mIndex++);
+        }
+        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
+            EXPECT_EQ(6, mIndex++);
+        }
+        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(9, mIndex++);
+        }
+        void endFrame(const Rect& repaintRect) override {
+            EXPECT_EQ(11, mIndex++);
+        }
+    };
+
+    auto node = TestUtils::createNode(0, 0, 600, 600, // 500x500 triggers clipping
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        canvas.saveLayerAlpha(0, 0, 500, 500, 128, (SaveFlags::Flags)0); // unclipped
+        canvas.saveLayerAlpha(100, 100, 400, 400, 128, SaveFlags::ClipToLayer); // clipped
+        canvas.saveLayerAlpha(200, 200, 300, 300, 128, (SaveFlags::Flags)0); // unclipped
+        canvas.drawRect(200, 200, 300, 300, SkPaint());
+        canvas.restore();
+        canvas.restore();
+        canvas.restore();
+    });
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(600, 600), 600, 600,
+            TestUtils::createSyncedNodeList(node), sLightCenter);
+    SaveLayerUnclippedComplexTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(12, renderer.getIndex());
+}
+
+RENDERTHREAD_TEST(FrameBuilder, hwLayer_simple) {
+    class HwLayerSimpleTestRenderer : 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 onRectOp(const RectOp& 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 {
+            EXPECT_EQ(3, mIndex++);
+        }
+        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(4, mIndex++);
+        }
+        void endFrame(const Rect& repaintRect) override {
+            EXPECT_EQ(5, mIndex++);
+        }
+    };
+
+    auto node = TestUtils::createNode(10, 10, 110, 110,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        props.mutateLayerProperties().setType(LayerType::RenderLayer);
+        SkPaint paint;
+        paint.setColor(SK_ColorWHITE);
+        canvas.drawRect(0, 0, 100, 100, paint);
+    });
+    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));
+
+    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            syncedNodeList, sLightCenter);
+    HwLayerSimpleTestRenderer 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, hwLayer_complex) {
+    /* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as:
+     * - startRepaintLayer(child), rect(grey), endLayer
+     * - startTemporaryLayer, drawLayer(child), endLayer
+     * - startRepaintLayer(parent), rect(white), drawLayer(saveLayer), endLayer
+     * - startFrame, drawLayer(parent), endLayerb
+     */
+    class HwLayerComplexTestRenderer : public TestRendererBase {
+    public:
+        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
+            EXPECT_EQ(3, mIndex++); // savelayer first
+            return (OffscreenBuffer*)0xabcd;
+        }
+        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
+            int index = mIndex++;
+            if (index == 0) {
+                // starting inner layer
+                EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
+                EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
+            } else if (index == 6) {
+                // starting outer layer
+                EXPECT_EQ(200u, offscreenBuffer->viewportWidth);
+                EXPECT_EQ(200u, offscreenBuffer->viewportHeight);
+            } else { ADD_FAILURE(); }
+        }
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            int index = mIndex++;
+            if (index == 1) {
+                // inner layer's rect (white)
+                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
+            } else if (index == 7) {
+                // outer layer's rect (grey)
+                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
+            } else { ADD_FAILURE(); }
+        }
+        void endLayer() override {
+            int index = mIndex++;
+            EXPECT_TRUE(index == 2 || index == 5 || index == 9);
+        }
+        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
+            EXPECT_EQ(10, mIndex++);
+        }
+        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
+            OffscreenBuffer* layer = *op.layerHandle;
+            int index = mIndex++;
+            if (index == 4) {
+                EXPECT_EQ(100u, layer->viewportWidth);
+                EXPECT_EQ(100u, layer->viewportHeight);
+            } else if (index == 8) {
+                EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
+            } else if (index == 11) {
+                EXPECT_EQ(200u, layer->viewportWidth);
+                EXPECT_EQ(200u, layer->viewportHeight);
+            } else { ADD_FAILURE(); }
+        }
+        void endFrame(const Rect& repaintRect) override {
+            EXPECT_EQ(12, mIndex++);
+        }
+    };
+
+    auto child = TestUtils::createNode(50, 50, 150, 150,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        props.mutateLayerProperties().setType(LayerType::RenderLayer);
+        SkPaint paint;
+        paint.setColor(SK_ColorWHITE);
+        canvas.drawRect(0, 0, 100, 100, paint);
+    });
+    OffscreenBuffer childLayer(renderThread.renderState(), Caches::getInstance(), 100, 100);
+    *(child->getLayerHandle()) = &childLayer;
+
+    RenderNode* childPtr = child.get();
+    auto parent = TestUtils::createNode(0, 0, 200, 200,
+            [childPtr](RenderProperties& props, RecordingCanvas& canvas) {
+        props.mutateLayerProperties().setType(LayerType::RenderLayer);
+        SkPaint paint;
+        paint.setColor(SK_ColorDKGRAY);
+        canvas.drawRect(0, 0, 200, 200, paint);
+
+        canvas.saveLayerAlpha(50, 50, 150, 150, 128, SaveFlags::ClipToLayer);
+        canvas.drawRenderNode(childPtr);
+        canvas.restore();
+    });
+    OffscreenBuffer parentLayer(renderThread.renderState(), Caches::getInstance(), 200, 200);
+    *(parent->getLayerHandle()) = &parentLayer;
+
+    auto syncedList = TestUtils::createSyncedNodeList(parent);
+
+    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
+    layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(100, 100));
+    layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200));
+
+    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            syncedList, sLightCenter);
+    HwLayerComplexTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(13, renderer.getIndex());
+
+    // clean up layer pointers, so we can safely destruct RenderNodes
+    *(child->getLayerHandle()) = nullptr;
+    *(parent->getLayerHandle()) = nullptr;
+}
+
+static void drawOrderedRect(RecordingCanvas* canvas, uint8_t expectedDrawOrder) {
+    SkPaint paint;
+    paint.setColor(SkColorSetARGB(256, 0, 0, expectedDrawOrder)); // order put in blue channel
+    canvas->drawRect(0, 0, 100, 100, paint);
+}
+static void drawOrderedNode(RecordingCanvas* canvas, uint8_t expectedDrawOrder, float z) {
+    auto node = TestUtils::createNode(0, 0, 100, 100,
+            [expectedDrawOrder](RenderProperties& props, RecordingCanvas& canvas) {
+        drawOrderedRect(&canvas, expectedDrawOrder);
+    });
+    node->mutateStagingProperties().setTranslationZ(z);
+    node->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z);
+    canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
+}
+TEST(FrameBuilder, zReorder) {
+    class ZReorderTestRenderer : public TestRendererBase {
+    public:
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            int expectedOrder = SkColorGetB(op.paint->getColor()); // extract order from blue channel
+            EXPECT_EQ(expectedOrder, mIndex++) << "An op was drawn out of order";
+        }
+    };
+
+    auto parent = TestUtils::createNode(0, 0, 100, 100,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
+        drawOrderedRect(&canvas, 1);
+        canvas.insertReorderBarrier(true);
+        drawOrderedNode(&canvas, 6, 2.0f);
+        drawOrderedRect(&canvas, 3);
+        drawOrderedNode(&canvas, 4, 0.0f);
+        drawOrderedRect(&canvas, 5);
+        drawOrderedNode(&canvas, 2, -2.0f);
+        drawOrderedNode(&canvas, 7, 2.0f);
+        canvas.insertReorderBarrier(false);
+        drawOrderedRect(&canvas, 8);
+        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), sLightCenter);
+    ZReorderTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(10, renderer.getIndex());
+};
+
+TEST(FrameBuilder, projectionReorder) {
+    static const int scrollX = 5;
+    static const int scrollY = 10;
+    class ProjectionReorderTestRenderer : public TestRendererBase {
+    public:
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            const int index = mIndex++;
+
+            Matrix4 expectedMatrix;
+            switch (index) {
+            case 0:
+                EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
+                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
+                expectedMatrix.loadIdentity();
+                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?
+                break;
+            case 2:
+                EXPECT_EQ(Rect(100, 50), op.unmappedBounds);
+                EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
+                expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0);
+                break;
+            default:
+                ADD_FAILURE();
+            }
+            EXPECT_MATRIX_APPROX_EQ(expectedMatrix, state.computedState.transform);
+        }
+    };
+
+    /**
+     * Construct a tree of nodes, where the root (A) has a receiver background (B), and a child (C)
+     * with a projecting child (P) of its own. P would normally draw between B and C's "background"
+     * draw, but because it is projected backwards, it's drawn in between B and C.
+     *
+     * The parent is scrolled by scrollX/scrollY, but this does not affect the background
+     * (which isn't affected by scroll).
+     */
+    auto receiverBackground = TestUtils::createNode(0, 0, 100, 100,
+            [](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);
+
+        SkPaint paint;
+        paint.setColor(SK_ColorWHITE);
+        canvas.drawRect(0, 0, 100, 100, paint);
+    });
+    auto projectingRipple = TestUtils::createNode(50, 0, 100, 50,
+            [](RenderProperties& properties, RecordingCanvas& canvas) {
+        properties.setProjectBackwards(true);
+        properties.setClipToBounds(false);
+        SkPaint paint;
+        paint.setColor(SK_ColorDKGRAY);
+        canvas.drawRect(-10, -10, 60, 60, paint);
+    });
+    auto child = TestUtils::createNode(0, 50, 100, 100,
+            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
+        SkPaint paint;
+        paint.setColor(SK_ColorBLUE);
+        canvas.drawRect(0, 0, 100, 50, paint);
+        canvas.drawRenderNode(projectingRipple.get());
+    });
+    auto parent = TestUtils::createNode(0, 0, 100, 100,
+            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
+        canvas.save(SaveFlags::MatrixClip);
+        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
+        canvas.drawRenderNode(receiverBackground.get());
+        canvas.drawRenderNode(child.get());
+        canvas.restore();
+    });
+
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
+            TestUtils::createSyncedNodeList(parent), sLightCenter);
+    ProjectionReorderTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(3, renderer.getIndex());
+}
+
+// creates a 100x100 shadow casting node with provided translationZ
+static sp<RenderNode> createWhiteRectShadowCaster(float translationZ) {
+    return TestUtils::createNode(0, 0, 100, 100,
+            [translationZ](RenderProperties& properties, RecordingCanvas& canvas) {
+        properties.setTranslationZ(translationZ);
+        properties.mutableOutline().setRoundRect(0, 0, 100, 100, 0.0f, 1.0f);
+        SkPaint paint;
+        paint.setColor(SK_ColorWHITE);
+        canvas.drawRect(0, 0, 100, 100, paint);
+    });
+}
+
+TEST(FrameBuilder, shadow) {
+    class ShadowTestRenderer : public TestRendererBase {
+    public:
+        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(0, mIndex++);
+            EXPECT_FLOAT_EQ(1.0f, op.casterAlpha);
+            EXPECT_TRUE(op.casterPath->isRect(nullptr));
+            EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.shadowMatrixXY);
+
+            Matrix4 expectedZ;
+            expectedZ.loadTranslate(0, 0, 5);
+            EXPECT_MATRIX_APPROX_EQ(expectedZ, op.shadowMatrixZ);
+        }
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(1, mIndex++);
+        }
+    };
+
+    auto parent = TestUtils::createNode(0, 0, 200, 200,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        canvas.insertReorderBarrier(true);
+        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
+    });
+
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            TestUtils::createSyncedNodeList(parent), sLightCenter);
+    ShadowTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(2, renderer.getIndex());
+}
+
+TEST(FrameBuilder, shadowSaveLayer) {
+    class ShadowSaveLayerTestRenderer : public TestRendererBase {
+    public:
+        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
+            EXPECT_EQ(0, mIndex++);
+            return nullptr;
+        }
+        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(1, mIndex++);
+            EXPECT_FLOAT_EQ(50, op.lightCenter.x);
+            EXPECT_FLOAT_EQ(40, op.lightCenter.y);
+        }
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(2, mIndex++);
+        }
+        void endLayer() override {
+            EXPECT_EQ(3, mIndex++);
+        }
+        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(4, mIndex++);
+        }
+    };
+
+    auto parent = TestUtils::createNode(0, 0, 200, 200,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        // save/restore outside of reorderBarrier, so they don't get moved out of place
+        canvas.translate(20, 10);
+        int count = canvas.saveLayerAlpha(30, 50, 130, 150, 128, SaveFlags::ClipToLayer);
+        canvas.insertReorderBarrier(true);
+        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
+        canvas.insertReorderBarrier(false);
+        canvas.restoreToCount(count);
+    });
+
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            TestUtils::createSyncedNodeList(parent), (Vector3) { 100, 100, 100 });
+    ShadowSaveLayerTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(5, renderer.getIndex());
+}
+
+RENDERTHREAD_TEST(FrameBuilder, shadowHwLayer) {
+    class ShadowHwLayerTestRenderer : public TestRendererBase {
+    public:
+        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
+            EXPECT_EQ(0, mIndex++);
+        }
+        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(1, mIndex++);
+            EXPECT_FLOAT_EQ(50, op.lightCenter.x);
+            EXPECT_FLOAT_EQ(40, op.lightCenter.y);
+        }
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(2, mIndex++);
+        }
+        void endLayer() override {
+            EXPECT_EQ(3, mIndex++);
+        }
+        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(4, mIndex++);
+        }
+    };
+
+    auto parent = TestUtils::createNode(50, 60, 150, 160,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        props.mutateLayerProperties().setType(LayerType::RenderLayer);
+        canvas.insertReorderBarrier(true);
+        canvas.save(SaveFlags::MatrixClip);
+        canvas.translate(20, 10);
+        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
+        canvas.restore();
+    });
+    OffscreenBuffer** layerHandle = parent->getLayerHandle();
+
+    // create RenderNode's layer here in same way prepareTree would, setting windowTransform
+    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
+    Matrix4 windowTransform;
+    windowTransform.loadTranslate(50, 60, 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(parent.get(), Rect(100, 100));
+    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            syncedList, (Vector3) { 100, 100, 100 });
+    ShadowHwLayerTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(5, renderer.getIndex());
+
+    // clean up layer pointer, so we can safely destruct RenderNode
+    *layerHandle = nullptr;
+}
+
+TEST(FrameBuilder, shadowLayering) {
+    class ShadowLayeringTestRenderer : public TestRendererBase {
+    public:
+        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
+            int index = mIndex++;
+            EXPECT_TRUE(index == 0 || index == 1);
+        }
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            int index = mIndex++;
+            EXPECT_TRUE(index == 2 || index == 3);
+        }
+    };
+    auto parent = TestUtils::createNode(0, 0, 200, 200,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        canvas.insertReorderBarrier(true);
+        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
+        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get());
+    });
+
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            TestUtils::createSyncedNodeList(parent), sLightCenter);
+    ShadowLayeringTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(4, renderer.getIndex());
+}
+
+static void testProperty(std::function<void(RenderProperties&)> propSetupCallback,
+        std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
+    class PropertyTestRenderer : public TestRendererBase {
+    public:
+        PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback)
+                : mCallback(callback) {}
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(mIndex++, 0);
+            mCallback(op, state);
+        }
+        std::function<void(const RectOp&, const BakedOpState&)> mCallback;
+    };
+
+    auto node = TestUtils::createNode(0, 0, 100, 100,
+            [propSetupCallback](RenderProperties& props, RecordingCanvas& canvas) {
+        propSetupCallback(props);
+        SkPaint paint;
+        paint.setColor(SK_ColorWHITE);
+        canvas.drawRect(0, 0, 100, 100, paint);
+    });
+
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
+            TestUtils::createSyncedNodeList(node), sLightCenter);
+    PropertyTestRenderer renderer(opValidateCallback);
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
+}
+
+TEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
+    testProperty([](RenderProperties& properties) {
+        properties.setAlpha(0.5f);
+        properties.setHasOverlappingRendering(false);
+    }, [](const RectOp& op, const BakedOpState& state) {
+        EXPECT_EQ(0.5f, state.alpha) << "Alpha should be applied directly to op";
+    });
+}
+
+TEST(FrameBuilder, renderPropClipping) {
+    testProperty([](RenderProperties& properties) {
+        properties.setClipToBounds(true);
+        properties.setClipBounds(Rect(10, 20, 300, 400));
+    }, [](const RectOp& op, const BakedOpState& state) {
+        EXPECT_EQ(Rect(10, 20, 100, 100), state.computedState.clippedBounds)
+                << "Clip rect should be intersection of node bounds and clip bounds";
+    });
+}
+
+TEST(FrameBuilder, renderPropRevealClip) {
+    testProperty([](RenderProperties& properties) {
+        properties.mutableRevealClip().set(true, 50, 50, 25);
+    }, [](const RectOp& op, const BakedOpState& state) {
+        ASSERT_NE(nullptr, state.roundRectClipState);
+        EXPECT_TRUE(state.roundRectClipState->highPriority);
+        EXPECT_EQ(25, state.roundRectClipState->radius);
+        EXPECT_EQ(Rect(50, 50, 50, 50), state.roundRectClipState->innerRect);
+    });
+}
+
+TEST(FrameBuilder, renderPropOutlineClip) {
+    testProperty([](RenderProperties& properties) {
+        properties.mutableOutline().setShouldClip(true);
+        properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
+    }, [](const RectOp& op, const BakedOpState& state) {
+        ASSERT_NE(nullptr, state.roundRectClipState);
+        EXPECT_FALSE(state.roundRectClipState->highPriority);
+        EXPECT_EQ(5, state.roundRectClipState->radius);
+        EXPECT_EQ(Rect(15, 25, 25, 35), state.roundRectClipState->innerRect);
+    });
+}
+
+TEST(FrameBuilder, renderPropTransform) {
+    testProperty([](RenderProperties& properties) {
+        properties.setLeftTopRightBottom(10, 10, 110, 110);
+
+        SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
+        properties.setStaticMatrix(&staticMatrix);
+
+        // ignored, since static overrides animation
+        SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
+        properties.setAnimationMatrix(&animationMatrix);
+
+        properties.setTranslationX(10);
+        properties.setTranslationY(20);
+        properties.setScaleX(0.5f);
+        properties.setScaleY(0.7f);
+    }, [](const RectOp& op, const BakedOpState& state) {
+        Matrix4 matrix;
+        matrix.loadTranslate(10, 10, 0); // left, top
+        matrix.scale(1.2f, 1.2f, 1); // static matrix
+        // ignore animation matrix, since static overrides it
+
+        // translation xy
+        matrix.translate(10, 20);
+
+        // scale xy (from default pivot - center)
+        matrix.translate(50, 50);
+        matrix.scale(0.5f, 0.7f, 1);
+        matrix.translate(-50, -50);
+        EXPECT_MATRIX_APPROX_EQ(matrix, state.computedState.transform)
+                << "Op draw matrix must match expected combination of transformation properties";
+    });
+}
+
+struct SaveLayerAlphaData {
+    uint32_t layerWidth = 0;
+    uint32_t layerHeight = 0;
+    Rect rectClippedBounds;
+    Matrix4 rectMatrix;
+};
+/**
+ * Constructs a view to hit the temporary layer alpha property implementation:
+ *     a) 0 < alpha < 1
+ *     b) too big for layer (larger than maxTextureSize)
+ *     c) overlapping rendering content
+ * returning observed data about layer size and content clip/transform.
+ *
+ * Used to validate clipping behavior of temporary layer, where requested layer size is reduced
+ * (for efficiency, and to fit in layer size constraints) based on parent clip.
+ */
+void testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
+        std::function<void(RenderProperties&)> propSetupCallback) {
+    class SaveLayerAlphaClipTestRenderer : public TestRendererBase {
+    public:
+        SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData)
+                : mOutData(outData) {}
+
+        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
+            EXPECT_EQ(0, mIndex++);
+            mOutData->layerWidth = width;
+            mOutData->layerHeight = height;
+            return nullptr;
+        }
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(1, mIndex++);
+
+            mOutData->rectClippedBounds = state.computedState.clippedBounds;
+            mOutData->rectMatrix = state.computedState.transform;
+        }
+        void endLayer() override {
+            EXPECT_EQ(2, mIndex++);
+        }
+        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(3, mIndex++);
+        }
+    private:
+        SaveLayerAlphaData* mOutData;
+    };
+
+    ASSERT_GT(10000, DeviceInfo::get()->maxTextureSize())
+            << "Node must be bigger than max texture size to exercise saveLayer codepath";
+    auto node = TestUtils::createNode(0, 0, 10000, 10000,
+            [&propSetupCallback](RenderProperties& properties, RecordingCanvas& canvas) {
+        properties.setHasOverlappingRendering(true);
+        properties.setAlpha(0.5f); // force saveLayer, since too big for HW layer
+        // apply other properties
+        propSetupCallback(properties);
+
+        SkPaint paint;
+        paint.setColor(SK_ColorWHITE);
+        canvas.drawRect(0, 0, 10000, 10000, paint);
+    });
+    auto nodes = TestUtils::createSyncedNodeList(node); // sync before querying height
+
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, nodes, sLightCenter);
+    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.";
+}
+
+TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
+    SaveLayerAlphaData observedData;
+    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
+        properties.setTranslationX(10); // offset rendering content
+        properties.setTranslationY(-2000); // offset rendering content
+    });
+    EXPECT_EQ(190u, observedData.layerWidth);
+    EXPECT_EQ(200u, observedData.layerHeight);
+    EXPECT_EQ(Rect(190, 200), observedData.rectClippedBounds)
+            << "expect content to be clipped to screen area";
+    Matrix4 expected;
+    expected.loadTranslate(0, -2000, 0);
+    EXPECT_MATRIX_APPROX_EQ(expected, observedData.rectMatrix)
+            << "expect content to be translated as part of being clipped";
+}
+
+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
+        // the view. It will form an isosceles right triangle with a long side length of 200 at the
+        // bottom of the viewport.
+        properties.setTranslationX(100);
+        properties.setTranslationY(100);
+        properties.setPivotX(0);
+        properties.setPivotY(0);
+        properties.setRotation(45);
+    });
+    // ceil(sqrt(2) / 2 * 200) = 142
+    EXPECT_EQ(142u, observedData.layerWidth);
+    EXPECT_EQ(142u, observedData.layerHeight);
+    EXPECT_EQ(Rect(142, 142), observedData.rectClippedBounds);
+    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
+}
+
+TEST(FrameBuilder, renderPropSaveLayerAlphaScale) {
+    SaveLayerAlphaData observedData;
+    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
+        properties.setPivotX(0);
+        properties.setPivotY(0);
+        properties.setScaleX(2);
+        properties.setScaleY(0.5f);
+    });
+    EXPECT_EQ(100u, observedData.layerWidth);
+    EXPECT_EQ(400u, observedData.layerHeight);
+    EXPECT_EQ(Rect(100, 400), observedData.rectClippedBounds);
+    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
+}
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp b/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp
new file mode 100644
index 0000000..aa1dcb2
--- /dev/null
+++ b/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp
@@ -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.
+ */
+
+
+#include <gtest/gtest.h>
+#include <GpuMemoryTracker.h>
+
+#include "renderthread/EglManager.h"
+#include "renderthread/RenderThread.h"
+#include "tests/common/TestUtils.h"
+
+#include <utils/StrongPointer.h>
+
+using namespace android;
+using namespace android::uirenderer;
+using namespace android::uirenderer::renderthread;
+
+class TestGPUObject : public GpuMemoryTracker {
+public:
+    TestGPUObject() : GpuMemoryTracker(GpuObjectType::Texture) {}
+
+    void changeSize(int newSize) {
+        notifySizeChanged(newSize);
+    }
+};
+
+// Other tests may have created a renderthread and EGL context.
+// This will destroy the EGLContext on RenderThread if it exists so that the
+// current thread can spoof being a GPU thread
+static void destroyEglContext() {
+    if (TestUtils::isRenderThreadRunning()) {
+        TestUtils::runOnRenderThread([](RenderThread& thread) {
+            thread.eglManager().destroy();
+        });
+    }
+}
+
+TEST(GpuMemoryTracker, sizeCheck) {
+    destroyEglContext();
+
+    GpuMemoryTracker::onGLContextCreated();
+    ASSERT_EQ(0, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture));
+    ASSERT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture));
+    {
+        TestGPUObject myObj;
+        ASSERT_EQ(1, GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture));
+        myObj.changeSize(500);
+        ASSERT_EQ(500, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture));
+        myObj.changeSize(1000);
+        ASSERT_EQ(1000, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture));
+        myObj.changeSize(300);
+        ASSERT_EQ(300, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture));
+    }
+    ASSERT_EQ(0, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture));
+    ASSERT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture));
+    GpuMemoryTracker::onGLContextDestroyed();
+}
diff --git a/libs/hwui/tests/unit/LeakCheckTests.cpp b/libs/hwui/tests/unit/LeakCheckTests.cpp
new file mode 100644
index 0000000..4a635fb
--- /dev/null
+++ b/libs/hwui/tests/unit/LeakCheckTests.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "BakedOpRenderer.h"
+#include "BakedOpDispatcher.h"
+#include "FrameBuilder.h"
+#include "LayerUpdateQueue.h"
+#include "RecordingCanvas.h"
+#include "tests/common/TestUtils.h"
+
+#include <gtest/gtest.h>
+
+using namespace android;
+using namespace android::uirenderer;
+
+const LayerUpdateQueue sEmptyLayerUpdateQueue;
+const Vector3 sLightCenter = {100, 100, 100};
+
+RENDERTHREAD_TEST(LeakCheck, saveLayerUnclipped_simple) {
+    auto node = TestUtils::createNode(0, 0, 200, 200,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
+        canvas.drawRect(0, 0, 200, 200, SkPaint());
+        canvas.restore();
+    });
+    BakedOpRenderer::LightInfo lightInfo = {50.0f, 128, 128};
+    RenderState& renderState = renderThread.renderState();
+    Caches& caches = Caches::getInstance();
+
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            TestUtils::createSyncedNodeList(node), sLightCenter);
+    BakedOpRenderer renderer(caches, renderState, true, lightInfo);
+    frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
+}
diff --git a/libs/hwui/tests/unit/LinearAllocatorTests.cpp b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
index 78d65dd..5c44290 100644
--- a/libs/hwui/tests/unit/LinearAllocatorTests.cpp
+++ b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
@@ -27,7 +27,7 @@
     int two = 2;
 };
 
-TEST(LinearAllocator, alloc) {
+TEST(LinearAllocator, create) {
     LinearAllocator la;
     EXPECT_EQ(0u, la.usedSize());
     la.alloc(64);
@@ -35,7 +35,7 @@
     // so the usedSize isn't strictly defined
     EXPECT_LE(64u, la.usedSize());
     EXPECT_GT(80u, la.usedSize());
-    auto pair = la.alloc<SimplePair>();
+    auto pair = la.create<SimplePair>();
     EXPECT_LE(64u + sizeof(SimplePair), la.usedSize());
     EXPECT_GT(80u + sizeof(SimplePair), la.usedSize());
     EXPECT_EQ(1, pair->one);
@@ -47,8 +47,8 @@
     {
         LinearAllocator la;
         for (int i = 0; i < 5; i++) {
-            la.alloc<TestUtils::SignalingDtor>()->setSignal(destroyed + i);
-            la.alloc<SimplePair>();
+            la.create<TestUtils::SignalingDtor>()->setSignal(destroyed + i);
+            la.create<SimplePair>();
         }
         la.alloc(100);
         for (int i = 0; i < 5; i++) {
@@ -75,7 +75,7 @@
         la.rewindIfLastAlloc(addr, 100);
         EXPECT_GT(16u, la.usedSize());
         size_t emptySize = la.usedSize();
-        auto sigdtor = la.alloc<TestUtils::SignalingDtor>();
+        auto sigdtor = la.create<TestUtils::SignalingDtor>();
         sigdtor->setSignal(&destroyed);
         EXPECT_EQ(0, destroyed);
         EXPECT_LE(emptySize, la.usedSize());
diff --git a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
index 2187654..2fd8795 100644
--- a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
+++ b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
@@ -15,11 +15,11 @@
  */
 
 #include <gtest/gtest.h>
+#include <Rect.h>
 #include <renderstate/OffscreenBufferPool.h>
 
 #include <tests/common/TestUtils.h>
 
-using namespace android;
 using namespace android::uirenderer;
 
 TEST(OffscreenBuffer, computeIdealDimension) {
@@ -36,13 +36,25 @@
         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());
     });
 }
 
+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());
+
+        OffscreenBuffer layerUnaligned(thread.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;
@@ -51,7 +63,6 @@
         EXPECT_EQ((uint32_t) Properties::layerPoolSize, pool.getMaxSize())
                 << "pool must read size from Properties";
     });
-
 }
 
 TEST(OffscreenBufferPool, getPutClear) {
@@ -89,8 +100,8 @@
         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);
+        EXPECT_EQ(64u, layer->texture.width());
+        EXPECT_EQ(64u, layer->texture.height());
 
         // resized to use different object in pool
         auto layer2 = pool.get(thread.renderState(), 128u, 128u);
@@ -99,12 +110,14 @@
         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);
+        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);
     });
 }
 
diff --git a/libs/hwui/tests/unit/OpReordererTests.cpp b/libs/hwui/tests/unit/OpReordererTests.cpp
deleted file mode 100644
index ac356a47..0000000
--- a/libs/hwui/tests/unit/OpReordererTests.cpp
+++ /dev/null
@@ -1,1136 +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 <gtest/gtest.h>
-
-#include <BakedOpState.h>
-#include <LayerUpdateQueue.h>
-#include <OpReorderer.h>
-#include <RecordedOp.h>
-#include <RecordingCanvas.h>
-#include <tests/common/TestUtils.h>
-
-#include <unordered_map>
-
-namespace android {
-namespace uirenderer {
-
-const LayerUpdateQueue sEmptyLayerUpdateQueue;
-const Vector3 sLightCenter = {100, 100, 100};
-
-static std::vector<sp<RenderNode>> createSyncedNodeList(sp<RenderNode>& node) {
-    TestUtils::syncHierarchyPropertiesAndDisplayList(node);
-    std::vector<sp<RenderNode>> vec;
-    vec.emplace_back(node);
-    return vec;
-}
-
-/**
- * Virtual class implemented by each test to redirect static operation / state transitions to
- * virtual methods.
- *
- * Virtual dispatch allows for default behaviors to be specified (very common case in below tests),
- * and allows Renderer vs Dispatching behavior to be merged.
- *
- * onXXXOp methods fail by default - tests should override ops they expect
- * startRepaintLayer fails by default - tests should override if expected
- * startFrame/endFrame do nothing by default - tests should override to intercept
- */
-class TestRendererBase {
-public:
-    virtual ~TestRendererBase() {}
-    virtual OffscreenBuffer* startTemporaryLayer(uint32_t, uint32_t) {
-        ADD_FAILURE() << "Layer creation not expected in this test";
-        return nullptr;
-    }
-    virtual void startRepaintLayer(OffscreenBuffer*, const Rect& repaintRect) {
-        ADD_FAILURE() << "Layer repaint not expected in this test";
-    }
-    virtual void endLayer() {
-        ADD_FAILURE() << "Layer updates not expected in this test";
-    }
-    virtual void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {}
-    virtual void endFrame() {}
-
-    // define virtual defaults for single draw methods
-#define X(Type) \
-    virtual void on##Type(const Type&, const BakedOpState&) { \
-        ADD_FAILURE() << #Type " not expected in this test"; \
-    }
-    MAP_OPS(X)
-#undef X
-
-    // define virtual defaults for merged draw methods
-#define X(Type) \
-    virtual void onMerged##Type##s(const MergedBakedOpList& opList) { \
-        ADD_FAILURE() << "Merged " #Type "s not expected in this test"; \
-    }
-    MAP_MERGED_OPS(X)
-#undef X
-
-    int getIndex() { return mIndex; }
-
-protected:
-    int mIndex = 0;
-};
-
-/**
- * Dispatches all static methods to similar formed methods on renderer, which fail by default but
- * are overridden by subclasses per test.
- */
-class TestDispatcher {
-public:
-    // define single op methods, which redirect to TestRendererBase
-#define X(Type) \
-    static void on##Type(TestRendererBase& renderer, const Type& op, const BakedOpState& state) { \
-        renderer.on##Type(op, state); \
-    }
-    MAP_OPS(X);
-#undef X
-
-    // define merged op methods, which redirect to TestRendererBase
-#define X(Type) \
-    static void onMerged##Type##s(TestRendererBase& renderer, const MergedBakedOpList& opList) { \
-        renderer.onMerged##Type##s(opList); \
-    }
-    MAP_MERGED_OPS(X);
-#undef X
-};
-
-class FailRenderer : public TestRendererBase {};
-
-TEST(OpReorderer, simple) {
-    class SimpleTestRenderer : public TestRendererBase {
-    public:
-        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
-            EXPECT_EQ(0, mIndex++);
-            EXPECT_EQ(100u, width);
-            EXPECT_EQ(200u, height);
-        }
-        void onRectOp(const RectOp& op, const BakedOpState& state) override {
-            EXPECT_EQ(1, mIndex++);
-        }
-        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
-            EXPECT_EQ(2, mIndex++);
-        }
-        void endFrame() override {
-            EXPECT_EQ(3, mIndex++);
-        }
-    };
-
-    auto node = TestUtils::createNode(0, 0, 100, 200,
-            [](RenderProperties& props, RecordingCanvas& canvas) {
-        SkBitmap bitmap = TestUtils::createSkBitmap(25, 25);
-        canvas.drawRect(0, 0, 100, 200, SkPaint());
-        canvas.drawBitmap(bitmap, 10, 10, nullptr);
-    });
-    OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
-            createSyncedNodeList(node), sLightCenter);
-    SimpleTestRenderer renderer;
-    reorderer.replayBakedOps<TestDispatcher>(renderer);
-    EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
-}
-
-TEST(OpReorderer, simpleStroke) {
-    class SimpleStrokeTestRenderer : public TestRendererBase {
-    public:
-        void onPointsOp(const PointsOp& op, const BakedOpState& state) override {
-            EXPECT_EQ(0, mIndex++);
-            // even though initial bounds are empty...
-            EXPECT_TRUE(op.unmappedBounds.isEmpty())
-                    << "initial bounds should be empty, since they're unstroked";
-            EXPECT_EQ(Rect(45, 45, 55, 55), state.computedState.clippedBounds)
-                    << "final bounds should account for stroke";
-        }
-    };
-
-    auto node = TestUtils::createNode(0, 0, 100, 200,
-            [](RenderProperties& props, RecordingCanvas& canvas) {
-        SkPaint strokedPaint;
-        strokedPaint.setStrokeWidth(10);
-        canvas.drawPoint(50, 50, strokedPaint);
-    });
-    OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
-            createSyncedNodeList(node), sLightCenter);
-    SimpleStrokeTestRenderer renderer;
-    reorderer.replayBakedOps<TestDispatcher>(renderer);
-    EXPECT_EQ(1, renderer.getIndex());
-}
-
-TEST(OpReorderer, simpleRejection) {
-    auto node = TestUtils::createNode(0, 0, 200, 200,
-            [](RenderProperties& props, RecordingCanvas& canvas) {
-        canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-        canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op); // intersection should be empty
-        canvas.drawRect(0, 0, 400, 400, SkPaint());
-        canvas.restore();
-    });
-    OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            createSyncedNodeList(node), sLightCenter);
-
-    FailRenderer renderer;
-    reorderer.replayBakedOps<TestDispatcher>(renderer);
-}
-
-TEST(OpReorderer, simpleBatching) {
-    const int LOOPS = 5;
-    class SimpleBatchingTestRenderer : public TestRendererBase {
-    public:
-        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
-            EXPECT_TRUE(mIndex++ >= LOOPS) << "Bitmaps should be above all rects";
-        }
-        void onRectOp(const RectOp& op, const BakedOpState& state) override {
-            EXPECT_TRUE(mIndex++ < LOOPS) << "Rects should be below all bitmaps";
-        }
-    };
-
-    auto node = TestUtils::createNode(0, 0, 200, 200,
-            [](RenderProperties& props, RecordingCanvas& canvas) {
-        SkBitmap bitmap = TestUtils::createSkBitmap(10, 10,
-                kAlpha_8_SkColorType); // Disable merging by using alpha 8 bitmap
-
-        // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
-        // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
-        canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-        for (int i = 0; i < LOOPS; i++) {
-            canvas.translate(0, 10);
-            canvas.drawRect(0, 0, 10, 10, SkPaint());
-            canvas.drawBitmap(bitmap, 5, 0, nullptr);
-        }
-        canvas.restore();
-    });
-
-    OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            createSyncedNodeList(node), sLightCenter);
-    SimpleBatchingTestRenderer renderer;
-    reorderer.replayBakedOps<TestDispatcher>(renderer);
-    EXPECT_EQ(2 * LOOPS, renderer.getIndex())
-            << "Expect number of ops = 2 * loop count";
-}
-
-TEST(OpReorderer, textStrikethroughBatching) {
-    const int LOOPS = 5;
-    class TextStrikethroughTestRenderer : public TestRendererBase {
-    public:
-        void onRectOp(const RectOp& op, const BakedOpState& state) override {
-            EXPECT_TRUE(mIndex++ >= LOOPS) << "Strikethrough rects should be above all text";
-        }
-        void onMergedTextOps(const MergedBakedOpList& opList) override {
-            EXPECT_EQ(0, mIndex);
-            mIndex += opList.count;
-            EXPECT_EQ(5u, opList.count);
-        }
-    };
-    auto node = TestUtils::createNode(0, 0, 200, 2000,
-            [](RenderProperties& props, RecordingCanvas& canvas) {
-        SkPaint textPaint;
-        textPaint.setAntiAlias(true);
-        textPaint.setTextSize(20);
-        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));
-        }
-    });
-    OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 2000), 200, 2000,
-            createSyncedNodeList(node), sLightCenter);
-    TextStrikethroughTestRenderer renderer;
-    reorderer.replayBakedOps<TestDispatcher>(renderer);
-    EXPECT_EQ(2 * LOOPS, renderer.getIndex())
-            << "Expect number of ops = 2 * loop count"; // TODO: force no merging
-}
-
-TEST(OpReorderer, renderNode) {
-    class RenderNodeTestRenderer : public TestRendererBase {
-    public:
-        void onRectOp(const RectOp& op, const BakedOpState& state) override {
-            switch(mIndex++) {
-            case 0:
-                EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
-                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
-                break;
-            case 1:
-                EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds);
-                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
-                break;
-            default:
-                ADD_FAILURE();
-            }
-        }
-    };
-
-    auto child = TestUtils::createNode(10, 10, 110, 110,
-            [](RenderProperties& props, RecordingCanvas& canvas) {
-        SkPaint paint;
-        paint.setColor(SK_ColorWHITE);
-        canvas.drawRect(0, 0, 100, 100, paint);
-    });
-
-    RenderNode* childPtr = child.get();
-    auto parent = TestUtils::createNode(0, 0, 200, 200,
-            [childPtr](RenderProperties& props, RecordingCanvas& canvas) {
-        SkPaint paint;
-        paint.setColor(SK_ColorDKGRAY);
-        canvas.drawRect(0, 0, 200, 200, paint);
-
-        canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-        canvas.translate(40, 40);
-        canvas.drawRenderNode(childPtr);
-        canvas.restore();
-    });
-
-    OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            createSyncedNodeList(parent), sLightCenter);
-    RenderNodeTestRenderer renderer;
-    reorderer.replayBakedOps<TestDispatcher>(renderer);
-}
-
-TEST(OpReorderer, clipped) {
-    class ClippedTestRenderer : public TestRendererBase {
-    public:
-        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
-            EXPECT_EQ(0, mIndex++);
-            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
-            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect);
-            EXPECT_TRUE(state.computedState.transform.isIdentity());
-        }
-    };
-
-    auto node = TestUtils::createNode(0, 0, 200, 200,
-            [](RenderProperties& props, RecordingCanvas& canvas) {
-        SkBitmap bitmap = TestUtils::createSkBitmap(200, 200);
-        canvas.drawBitmap(bitmap, 0, 0, nullptr);
-    });
-
-    OpReorderer reorderer(sEmptyLayerUpdateQueue,
-            SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver
-            200, 200, createSyncedNodeList(node), sLightCenter);
-    ClippedTestRenderer renderer;
-    reorderer.replayBakedOps<TestDispatcher>(renderer);
-}
-
-TEST(OpReorderer, saveLayerSimple) {
-    class SaveLayerSimpleTestRenderer : public TestRendererBase {
-    public:
-        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
-            EXPECT_EQ(0, mIndex++);
-            EXPECT_EQ(180u, width);
-            EXPECT_EQ(180u, height);
-            return nullptr;
-        }
-        void endLayer() override {
-            EXPECT_EQ(2, mIndex++);
-        }
-        void onRectOp(const RectOp& op, const BakedOpState& state) override {
-            EXPECT_EQ(1, mIndex++);
-            EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
-            EXPECT_EQ(Rect(180, 180), state.computedState.clippedBounds);
-            EXPECT_EQ(Rect(180, 180), state.computedState.clipRect);
-
-            Matrix4 expectedTransform;
-            expectedTransform.loadTranslate(-10, -10, 0);
-            EXPECT_MATRIX_APPROX_EQ(expectedTransform, state.computedState.transform);
-        }
-        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
-            EXPECT_EQ(3, mIndex++);
-            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
-            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect);
-            EXPECT_TRUE(state.computedState.transform.isIdentity());
-        }
-    };
-
-    auto node = TestUtils::createNode(0, 0, 200, 200,
-            [](RenderProperties& props, RecordingCanvas& canvas) {
-        canvas.saveLayerAlpha(10, 10, 190, 190, 128, SkCanvas::kClipToLayer_SaveFlag);
-        canvas.drawRect(10, 10, 190, 190, SkPaint());
-        canvas.restore();
-    });
-    OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            createSyncedNodeList(node), sLightCenter);
-    SaveLayerSimpleTestRenderer renderer;
-    reorderer.replayBakedOps<TestDispatcher>(renderer);
-    EXPECT_EQ(4, renderer.getIndex());
-}
-
-TEST(OpReorderer, saveLayerNested) {
-    /* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as:
-     * - startTemporaryLayer2, rect2 endLayer2
-     * - startTemporaryLayer1, rect1, drawLayer2, endLayer1
-     * - startFrame, layerOp1, endFrame
-     */
-    class SaveLayerNestedTestRenderer : public TestRendererBase {
-    public:
-        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
-            const int index = mIndex++;
-            if (index == 0) {
-                EXPECT_EQ(400u, width);
-                EXPECT_EQ(400u, height);
-                return (OffscreenBuffer*) 0x400;
-            } else if (index == 3) {
-                EXPECT_EQ(800u, width);
-                EXPECT_EQ(800u, height);
-                return (OffscreenBuffer*) 0x800;
-            } else { ADD_FAILURE(); }
-            return (OffscreenBuffer*) nullptr;
-        }
-        void endLayer() override {
-            int index = mIndex++;
-            EXPECT_TRUE(index == 2 || index == 6);
-        }
-        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
-            EXPECT_EQ(7, mIndex++);
-        }
-        void endFrame() override {
-            EXPECT_EQ(9, mIndex++);
-        }
-        void onRectOp(const RectOp& op, const BakedOpState& state) override {
-            const int index = mIndex++;
-            if (index == 1) {
-                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner rect
-            } else if (index == 4) {
-                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer rect
-            } else { ADD_FAILURE(); }
-        }
-        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
-            const int index = mIndex++;
-            if (index == 5) {
-                EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
-                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner layer
-            } else if (index == 8) {
-                EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
-                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
-            } else { ADD_FAILURE(); }
-        }
-    };
-
-    auto node = TestUtils::createNode(0, 0, 800, 800,
-            [](RenderProperties& props, RecordingCanvas& canvas) {
-        canvas.saveLayerAlpha(0, 0, 800, 800, 128, SkCanvas::kClipToLayer_SaveFlag);
-        {
-            canvas.drawRect(0, 0, 800, 800, SkPaint());
-            canvas.saveLayerAlpha(0, 0, 400, 400, 128, SkCanvas::kClipToLayer_SaveFlag);
-            {
-                canvas.drawRect(0, 0, 400, 400, SkPaint());
-            }
-            canvas.restore();
-        }
-        canvas.restore();
-    });
-
-    OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(800, 800), 800, 800,
-            createSyncedNodeList(node), sLightCenter);
-    SaveLayerNestedTestRenderer renderer;
-    reorderer.replayBakedOps<TestDispatcher>(renderer);
-    EXPECT_EQ(10, renderer.getIndex());
-}
-
-TEST(OpReorderer, saveLayerContentRejection) {
-        auto node = TestUtils::createNode(0, 0, 200, 200,
-                [](RenderProperties& props, RecordingCanvas& canvas) {
-        canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-        canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op);
-        canvas.saveLayerAlpha(200, 200, 400, 400, 128, SkCanvas::kClipToLayer_SaveFlag);
-
-        // draw within save layer may still be recorded, but shouldn't be drawn
-        canvas.drawRect(200, 200, 400, 400, SkPaint());
-
-        canvas.restore();
-        canvas.restore();
-    });
-    OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            createSyncedNodeList(node), sLightCenter);
-
-    FailRenderer renderer;
-    // should see no ops, even within the layer, since the layer should be rejected
-    reorderer.replayBakedOps<TestDispatcher>(renderer);
-}
-
-RENDERTHREAD_TEST(OpReorderer, hwLayerSimple) {
-    class HwLayerSimpleTestRenderer : 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 onRectOp(const RectOp& op, const BakedOpState& state) override {
-            EXPECT_EQ(1, mIndex++);
-
-            EXPECT_TRUE(state.computedState.transform.isIdentity())
-                    << "Transform should be reset within layer";
-
-            EXPECT_EQ(state.computedState.clipRect, Rect(25, 25, 75, 75))
-                    << "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 {
-            EXPECT_EQ(3, mIndex++);
-        }
-        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
-            EXPECT_EQ(4, mIndex++);
-        }
-        void endFrame() override {
-            EXPECT_EQ(5, mIndex++);
-        }
-    };
-
-    auto node = TestUtils::createNode(10, 10, 110, 110,
-            [](RenderProperties& props, RecordingCanvas& canvas) {
-        props.mutateLayerProperties().setType(LayerType::RenderLayer);
-        SkPaint paint;
-        paint.setColor(SK_ColorWHITE);
-        canvas.drawRect(0, 0, 100, 100, paint);
-    });
-    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 = 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));
-
-    OpReorderer reorderer(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            syncedNodeList, sLightCenter);
-    HwLayerSimpleTestRenderer renderer;
-    reorderer.replayBakedOps<TestDispatcher>(renderer);
-    EXPECT_EQ(6, renderer.getIndex());
-
-    // clean up layer pointer, so we can safely destruct RenderNode
-    *layerHandle = nullptr;
-}
-
-RENDERTHREAD_TEST(OpReorderer, hwLayerComplex) {
-    /* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as:
-     * - startRepaintLayer(child), rect(grey), endLayer
-     * - startTemporaryLayer, drawLayer(child), endLayer
-     * - startRepaintLayer(parent), rect(white), drawLayer(saveLayer), endLayer
-     * - startFrame, drawLayer(parent), endLayerb
-     */
-    class HwLayerComplexTestRenderer : public TestRendererBase {
-    public:
-        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
-            EXPECT_EQ(3, mIndex++); // savelayer first
-            return (OffscreenBuffer*)0xabcd;
-        }
-        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
-            int index = mIndex++;
-            if (index == 0) {
-                // starting inner layer
-                EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
-                EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
-            } else if (index == 6) {
-                // starting outer layer
-                EXPECT_EQ(200u, offscreenBuffer->viewportWidth);
-                EXPECT_EQ(200u, offscreenBuffer->viewportHeight);
-            } else { ADD_FAILURE(); }
-        }
-        void onRectOp(const RectOp& op, const BakedOpState& state) override {
-            int index = mIndex++;
-            if (index == 1) {
-                // inner layer's rect (white)
-                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
-            } else if (index == 7) {
-                // outer layer's rect (grey)
-                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
-            } else { ADD_FAILURE(); }
-        }
-        void endLayer() override {
-            int index = mIndex++;
-            EXPECT_TRUE(index == 2 || index == 5 || index == 9);
-        }
-        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
-            EXPECT_EQ(10, mIndex++);
-        }
-        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
-            OffscreenBuffer* layer = *op.layerHandle;
-            int index = mIndex++;
-            if (index == 4) {
-                EXPECT_EQ(100u, layer->viewportWidth);
-                EXPECT_EQ(100u, layer->viewportHeight);
-            } else if (index == 8) {
-                EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
-            } else if (index == 11) {
-                EXPECT_EQ(200u, layer->viewportWidth);
-                EXPECT_EQ(200u, layer->viewportHeight);
-            } else { ADD_FAILURE(); }
-        }
-        void endFrame() override {
-            EXPECT_EQ(12, mIndex++);
-        }
-    };
-
-    auto child = TestUtils::createNode(50, 50, 150, 150,
-            [](RenderProperties& props, RecordingCanvas& canvas) {
-        props.mutateLayerProperties().setType(LayerType::RenderLayer);
-        SkPaint paint;
-        paint.setColor(SK_ColorWHITE);
-        canvas.drawRect(0, 0, 100, 100, paint);
-    });
-    OffscreenBuffer childLayer(renderThread.renderState(), Caches::getInstance(), 100, 100);
-    *(child->getLayerHandle()) = &childLayer;
-
-    RenderNode* childPtr = child.get();
-    auto parent = TestUtils::createNode(0, 0, 200, 200,
-            [childPtr](RenderProperties& props, RecordingCanvas& canvas) {
-        props.mutateLayerProperties().setType(LayerType::RenderLayer);
-        SkPaint paint;
-        paint.setColor(SK_ColorDKGRAY);
-        canvas.drawRect(0, 0, 200, 200, paint);
-
-        canvas.saveLayerAlpha(50, 50, 150, 150, 128, SkCanvas::kClipToLayer_SaveFlag);
-        canvas.drawRenderNode(childPtr);
-        canvas.restore();
-    });
-    OffscreenBuffer parentLayer(renderThread.renderState(), Caches::getInstance(), 200, 200);
-    *(parent->getLayerHandle()) = &parentLayer;
-
-    auto syncedList = createSyncedNodeList(parent);
-
-    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
-    layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(100, 100));
-    layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200));
-
-    OpReorderer reorderer(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            syncedList, sLightCenter);
-    HwLayerComplexTestRenderer renderer;
-    reorderer.replayBakedOps<TestDispatcher>(renderer);
-    EXPECT_EQ(13, renderer.getIndex());
-
-    // clean up layer pointers, so we can safely destruct RenderNodes
-    *(child->getLayerHandle()) = nullptr;
-    *(parent->getLayerHandle()) = nullptr;
-}
-
-static void drawOrderedRect(RecordingCanvas* canvas, uint8_t expectedDrawOrder) {
-    SkPaint paint;
-    paint.setColor(SkColorSetARGB(256, 0, 0, expectedDrawOrder)); // order put in blue channel
-    canvas->drawRect(0, 0, 100, 100, paint);
-}
-static void drawOrderedNode(RecordingCanvas* canvas, uint8_t expectedDrawOrder, float z) {
-    auto node = TestUtils::createNode(0, 0, 100, 100,
-            [expectedDrawOrder](RenderProperties& props, RecordingCanvas& canvas) {
-        drawOrderedRect(&canvas, expectedDrawOrder);
-    });
-    node->mutateStagingProperties().setTranslationZ(z);
-    node->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z);
-    canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
-}
-TEST(OpReorderer, zReorder) {
-    class ZReorderTestRenderer : public TestRendererBase {
-    public:
-        void onRectOp(const RectOp& op, const BakedOpState& state) override {
-            int expectedOrder = SkColorGetB(op.paint->getColor()); // extract order from blue channel
-            EXPECT_EQ(expectedOrder, mIndex++) << "An op was drawn out of order";
-        }
-    };
-
-    auto parent = TestUtils::createNode(0, 0, 100, 100,
-            [](RenderProperties& props, RecordingCanvas& canvas) {
-        drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
-        drawOrderedRect(&canvas, 1);
-        canvas.insertReorderBarrier(true);
-        drawOrderedNode(&canvas, 6, 2.0f);
-        drawOrderedRect(&canvas, 3);
-        drawOrderedNode(&canvas, 4, 0.0f);
-        drawOrderedRect(&canvas, 5);
-        drawOrderedNode(&canvas, 2, -2.0f);
-        drawOrderedNode(&canvas, 7, 2.0f);
-        canvas.insertReorderBarrier(false);
-        drawOrderedRect(&canvas, 8);
-        drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
-    });
-    OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
-            createSyncedNodeList(parent), sLightCenter);
-    ZReorderTestRenderer renderer;
-    reorderer.replayBakedOps<TestDispatcher>(renderer);
-    EXPECT_EQ(10, renderer.getIndex());
-};
-
-TEST(OpReorderer, projectionReorder) {
-    static const int scrollX = 5;
-    static const int scrollY = 10;
-    class ProjectionReorderTestRenderer : public TestRendererBase {
-    public:
-        void onRectOp(const RectOp& op, const BakedOpState& state) override {
-            const int index = mIndex++;
-
-            Matrix4 expectedMatrix;
-            switch (index) {
-            case 0:
-                EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
-                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
-                expectedMatrix.loadIdentity();
-                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?
-                break;
-            case 2:
-                EXPECT_EQ(Rect(100, 50), op.unmappedBounds);
-                EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
-                expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0);
-                break;
-            default:
-                ADD_FAILURE();
-            }
-            EXPECT_MATRIX_APPROX_EQ(expectedMatrix, state.computedState.transform);
-        }
-    };
-
-    /**
-     * Construct a tree of nodes, where the root (A) has a receiver background (B), and a child (C)
-     * with a projecting child (P) of its own. P would normally draw between B and C's "background"
-     * draw, but because it is projected backwards, it's drawn in between B and C.
-     *
-     * The parent is scrolled by scrollX/scrollY, but this does not affect the background
-     * (which isn't affected by scroll).
-     */
-    auto receiverBackground = TestUtils::createNode(0, 0, 100, 100,
-            [](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);
-
-        SkPaint paint;
-        paint.setColor(SK_ColorWHITE);
-        canvas.drawRect(0, 0, 100, 100, paint);
-    });
-    auto projectingRipple = TestUtils::createNode(50, 0, 100, 50,
-            [](RenderProperties& properties, RecordingCanvas& canvas) {
-        properties.setProjectBackwards(true);
-        properties.setClipToBounds(false);
-        SkPaint paint;
-        paint.setColor(SK_ColorDKGRAY);
-        canvas.drawRect(-10, -10, 60, 60, paint);
-    });
-    auto child = TestUtils::createNode(0, 50, 100, 100,
-            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
-        SkPaint paint;
-        paint.setColor(SK_ColorBLUE);
-        canvas.drawRect(0, 0, 100, 50, paint);
-        canvas.drawRenderNode(projectingRipple.get());
-    });
-    auto parent = TestUtils::createNode(0, 0, 100, 100,
-            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
-        canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
-        canvas.drawRenderNode(receiverBackground.get());
-        canvas.drawRenderNode(child.get());
-        canvas.restore();
-    });
-
-    OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
-            createSyncedNodeList(parent), sLightCenter);
-    ProjectionReorderTestRenderer renderer;
-    reorderer.replayBakedOps<TestDispatcher>(renderer);
-    EXPECT_EQ(3, renderer.getIndex());
-}
-
-// creates a 100x100 shadow casting node with provided translationZ
-static sp<RenderNode> createWhiteRectShadowCaster(float translationZ) {
-    return TestUtils::createNode(0, 0, 100, 100,
-            [translationZ](RenderProperties& properties, RecordingCanvas& canvas) {
-        properties.setTranslationZ(translationZ);
-        properties.mutableOutline().setRoundRect(0, 0, 100, 100, 0.0f, 1.0f);
-        SkPaint paint;
-        paint.setColor(SK_ColorWHITE);
-        canvas.drawRect(0, 0, 100, 100, paint);
-    });
-}
-
-TEST(OpReorderer, shadow) {
-    class ShadowTestRenderer : public TestRendererBase {
-    public:
-        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
-            EXPECT_EQ(0, mIndex++);
-            EXPECT_FLOAT_EQ(1.0f, op.casterAlpha);
-            EXPECT_TRUE(op.casterPath->isRect(nullptr));
-            EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.shadowMatrixXY);
-
-            Matrix4 expectedZ;
-            expectedZ.loadTranslate(0, 0, 5);
-            EXPECT_MATRIX_APPROX_EQ(expectedZ, op.shadowMatrixZ);
-        }
-        void onRectOp(const RectOp& op, const BakedOpState& state) override {
-            EXPECT_EQ(1, mIndex++);
-        }
-    };
-
-    auto parent = TestUtils::createNode(0, 0, 200, 200,
-            [](RenderProperties& props, RecordingCanvas& canvas) {
-        canvas.insertReorderBarrier(true);
-        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
-    });
-
-    OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            createSyncedNodeList(parent), sLightCenter);
-    ShadowTestRenderer renderer;
-    reorderer.replayBakedOps<TestDispatcher>(renderer);
-    EXPECT_EQ(2, renderer.getIndex());
-}
-
-TEST(OpReorderer, shadowSaveLayer) {
-    class ShadowSaveLayerTestRenderer : public TestRendererBase {
-    public:
-        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
-            EXPECT_EQ(0, mIndex++);
-            return nullptr;
-        }
-        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
-            EXPECT_EQ(1, mIndex++);
-            EXPECT_FLOAT_EQ(50, op.lightCenter.x);
-            EXPECT_FLOAT_EQ(40, op.lightCenter.y);
-        }
-        void onRectOp(const RectOp& op, const BakedOpState& state) override {
-            EXPECT_EQ(2, mIndex++);
-        }
-        void endLayer() override {
-            EXPECT_EQ(3, mIndex++);
-        }
-        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
-            EXPECT_EQ(4, mIndex++);
-        }
-    };
-
-    auto parent = TestUtils::createNode(0, 0, 200, 200,
-            [](RenderProperties& props, RecordingCanvas& canvas) {
-        // save/restore outside of reorderBarrier, so they don't get moved out of place
-        canvas.translate(20, 10);
-        int count = canvas.saveLayerAlpha(30, 50, 130, 150, 128, SkCanvas::kClipToLayer_SaveFlag);
-        canvas.insertReorderBarrier(true);
-        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
-        canvas.insertReorderBarrier(false);
-        canvas.restoreToCount(count);
-    });
-
-    OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            createSyncedNodeList(parent), (Vector3) { 100, 100, 100 });
-    ShadowSaveLayerTestRenderer renderer;
-    reorderer.replayBakedOps<TestDispatcher>(renderer);
-    EXPECT_EQ(5, renderer.getIndex());
-}
-
-RENDERTHREAD_TEST(OpReorderer, shadowHwLayer) {
-    class ShadowHwLayerTestRenderer : public TestRendererBase {
-    public:
-        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
-            EXPECT_EQ(0, mIndex++);
-        }
-        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
-            EXPECT_EQ(1, mIndex++);
-            EXPECT_FLOAT_EQ(50, op.lightCenter.x);
-            EXPECT_FLOAT_EQ(40, op.lightCenter.y);
-        }
-        void onRectOp(const RectOp& op, const BakedOpState& state) override {
-            EXPECT_EQ(2, mIndex++);
-        }
-        void endLayer() override {
-            EXPECT_EQ(3, mIndex++);
-        }
-        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
-            EXPECT_EQ(4, mIndex++);
-        }
-    };
-
-    auto parent = TestUtils::createNode(50, 60, 150, 160,
-            [](RenderProperties& props, RecordingCanvas& canvas) {
-        props.mutateLayerProperties().setType(LayerType::RenderLayer);
-        canvas.insertReorderBarrier(true);
-        canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-        canvas.translate(20, 10);
-        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
-        canvas.restore();
-    });
-    OffscreenBuffer** layerHandle = parent->getLayerHandle();
-
-    // create RenderNode's layer here in same way prepareTree would, setting windowTransform
-    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
-    Matrix4 windowTransform;
-    windowTransform.loadTranslate(50, 60, 0); // total transform of layer's origin
-    layer.setWindowTransform(windowTransform);
-    *layerHandle = &layer;
-
-    auto syncedList = createSyncedNodeList(parent);
-    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
-    layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100));
-    OpReorderer reorderer(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            syncedList, (Vector3) { 100, 100, 100 });
-    ShadowHwLayerTestRenderer renderer;
-    reorderer.replayBakedOps<TestDispatcher>(renderer);
-    EXPECT_EQ(5, renderer.getIndex());
-
-    // clean up layer pointer, so we can safely destruct RenderNode
-    *layerHandle = nullptr;
-}
-
-TEST(OpReorderer, shadowLayering) {
-    class ShadowLayeringTestRenderer : public TestRendererBase {
-    public:
-        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
-            int index = mIndex++;
-            EXPECT_TRUE(index == 0 || index == 1);
-        }
-        void onRectOp(const RectOp& op, const BakedOpState& state) override {
-            int index = mIndex++;
-            EXPECT_TRUE(index == 2 || index == 3);
-        }
-    };
-    auto parent = TestUtils::createNode(0, 0, 200, 200,
-            [](RenderProperties& props, RecordingCanvas& canvas) {
-        canvas.insertReorderBarrier(true);
-        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
-        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get());
-    });
-
-    OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
-            createSyncedNodeList(parent), sLightCenter);
-    ShadowLayeringTestRenderer renderer;
-    reorderer.replayBakedOps<TestDispatcher>(renderer);
-    EXPECT_EQ(4, renderer.getIndex());
-}
-
-static void testProperty(std::function<void(RenderProperties&)> propSetupCallback,
-        std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
-    class PropertyTestRenderer : public TestRendererBase {
-    public:
-        PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback)
-                : mCallback(callback) {}
-        void onRectOp(const RectOp& op, const BakedOpState& state) override {
-            EXPECT_EQ(mIndex++, 0);
-            mCallback(op, state);
-        }
-        std::function<void(const RectOp&, const BakedOpState&)> mCallback;
-    };
-
-    auto node = TestUtils::createNode(0, 0, 100, 100,
-            [propSetupCallback](RenderProperties& props, RecordingCanvas& canvas) {
-        propSetupCallback(props);
-        SkPaint paint;
-        paint.setColor(SK_ColorWHITE);
-        canvas.drawRect(0, 0, 100, 100, paint);
-    });
-
-    OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
-            createSyncedNodeList(node), sLightCenter);
-    PropertyTestRenderer renderer(opValidateCallback);
-    reorderer.replayBakedOps<TestDispatcher>(renderer);
-    EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
-}
-
-TEST(OpReorderer, renderPropOverlappingRenderingAlpha) {
-    testProperty([](RenderProperties& properties) {
-        properties.setAlpha(0.5f);
-        properties.setHasOverlappingRendering(false);
-    }, [](const RectOp& op, const BakedOpState& state) {
-        EXPECT_EQ(0.5f, state.alpha) << "Alpha should be applied directly to op";
-    });
-}
-
-TEST(OpReorderer, renderPropClipping) {
-    testProperty([](RenderProperties& properties) {
-        properties.setClipToBounds(true);
-        properties.setClipBounds(Rect(10, 20, 300, 400));
-    }, [](const RectOp& op, const BakedOpState& state) {
-        EXPECT_EQ(Rect(10, 20, 100, 100), state.computedState.clippedBounds)
-                << "Clip rect should be intersection of node bounds and clip bounds";
-    });
-}
-
-TEST(OpReorderer, renderPropRevealClip) {
-    testProperty([](RenderProperties& properties) {
-        properties.mutableRevealClip().set(true, 50, 50, 25);
-    }, [](const RectOp& op, const BakedOpState& state) {
-        ASSERT_NE(nullptr, state.roundRectClipState);
-        EXPECT_TRUE(state.roundRectClipState->highPriority);
-        EXPECT_EQ(25, state.roundRectClipState->radius);
-        EXPECT_EQ(Rect(50, 50, 50, 50), state.roundRectClipState->innerRect);
-    });
-}
-
-TEST(OpReorderer, renderPropOutlineClip) {
-    testProperty([](RenderProperties& properties) {
-        properties.mutableOutline().setShouldClip(true);
-        properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
-    }, [](const RectOp& op, const BakedOpState& state) {
-        ASSERT_NE(nullptr, state.roundRectClipState);
-        EXPECT_FALSE(state.roundRectClipState->highPriority);
-        EXPECT_EQ(5, state.roundRectClipState->radius);
-        EXPECT_EQ(Rect(15, 25, 25, 35), state.roundRectClipState->innerRect);
-    });
-}
-
-TEST(OpReorderer, renderPropTransform) {
-    testProperty([](RenderProperties& properties) {
-        properties.setLeftTopRightBottom(10, 10, 110, 110);
-
-        SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
-        properties.setStaticMatrix(&staticMatrix);
-
-        // ignored, since static overrides animation
-        SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
-        properties.setAnimationMatrix(&animationMatrix);
-
-        properties.setTranslationX(10);
-        properties.setTranslationY(20);
-        properties.setScaleX(0.5f);
-        properties.setScaleY(0.7f);
-    }, [](const RectOp& op, const BakedOpState& state) {
-        Matrix4 matrix;
-        matrix.loadTranslate(10, 10, 0); // left, top
-        matrix.scale(1.2f, 1.2f, 1); // static matrix
-        // ignore animation matrix, since static overrides it
-
-        // translation xy
-        matrix.translate(10, 20);
-
-        // scale xy (from default pivot - center)
-        matrix.translate(50, 50);
-        matrix.scale(0.5f, 0.7f, 1);
-        matrix.translate(-50, -50);
-        EXPECT_MATRIX_APPROX_EQ(matrix, state.computedState.transform)
-                << "Op draw matrix must match expected combination of transformation properties";
-    });
-}
-
-struct SaveLayerAlphaData {
-    uint32_t layerWidth = 0;
-    uint32_t layerHeight = 0;
-    Rect rectClippedBounds;
-    Matrix4 rectMatrix;
-};
-/**
- * Constructs a view to hit the temporary layer alpha property implementation:
- *     a) 0 < alpha < 1
- *     b) too big for layer (larger than maxTextureSize)
- *     c) overlapping rendering content
- * returning observed data about layer size and content clip/transform.
- *
- * Used to validate clipping behavior of temporary layer, where requested layer size is reduced
- * (for efficiency, and to fit in layer size constraints) based on parent clip.
- */
-void testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
-        std::function<void(RenderProperties&)> propSetupCallback) {
-    class SaveLayerAlphaClipTestRenderer : public TestRendererBase {
-    public:
-        SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData)
-                : mOutData(outData) {}
-
-        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
-            EXPECT_EQ(0, mIndex++);
-            mOutData->layerWidth = width;
-            mOutData->layerHeight = height;
-            return nullptr;
-        }
-        void onRectOp(const RectOp& op, const BakedOpState& state) override {
-            EXPECT_EQ(1, mIndex++);
-
-            mOutData->rectClippedBounds = state.computedState.clippedBounds;
-            mOutData->rectMatrix = state.computedState.transform;
-        }
-        void endLayer() override {
-            EXPECT_EQ(2, mIndex++);
-        }
-        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
-            EXPECT_EQ(3, mIndex++);
-        }
-    private:
-        SaveLayerAlphaData* mOutData;
-    };
-
-    ASSERT_GT(10000, DeviceInfo::get()->maxTextureSize())
-            << "Node must be bigger than max texture size to exercise saveLayer codepath";
-    auto node = TestUtils::createNode(0, 0, 10000, 10000,
-            [&propSetupCallback](RenderProperties& properties, RecordingCanvas& canvas) {
-        properties.setHasOverlappingRendering(true);
-        properties.setAlpha(0.5f); // force saveLayer, since too big for HW layer
-        // apply other properties
-        propSetupCallback(properties);
-
-        SkPaint paint;
-        paint.setColor(SK_ColorWHITE);
-        canvas.drawRect(0, 0, 10000, 10000, paint);
-    });
-    auto nodes = createSyncedNodeList(node); // sync before querying height
-
-    OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, nodes, sLightCenter);
-    SaveLayerAlphaClipTestRenderer renderer(outObservedData);
-    reorderer.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.";
-}
-
-TEST(OpReorderer, renderPropSaveLayerAlphaClipBig) {
-    SaveLayerAlphaData observedData;
-    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
-        properties.setTranslationX(10); // offset rendering content
-        properties.setTranslationY(-2000); // offset rendering content
-    });
-    EXPECT_EQ(190u, observedData.layerWidth);
-    EXPECT_EQ(200u, observedData.layerHeight);
-    EXPECT_EQ(Rect(190, 200), observedData.rectClippedBounds)
-            << "expect content to be clipped to screen area";
-    Matrix4 expected;
-    expected.loadTranslate(0, -2000, 0);
-    EXPECT_MATRIX_APPROX_EQ(expected, observedData.rectMatrix)
-            << "expect content to be translated as part of being clipped";
-}
-
-TEST(OpReorderer, renderPropSaveLayerAlphaRotate) {
-    SaveLayerAlphaData observedData;
-    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
-        // Translate and rotate the view so that the only visible part is the top left corner of
-        // the view. It will form an isosceles right triangle with a long side length of 200 at the
-        // bottom of the viewport.
-        properties.setTranslationX(100);
-        properties.setTranslationY(100);
-        properties.setPivotX(0);
-        properties.setPivotY(0);
-        properties.setRotation(45);
-    });
-    // ceil(sqrt(2) / 2 * 200) = 142
-    EXPECT_EQ(142u, observedData.layerWidth);
-    EXPECT_EQ(142u, observedData.layerHeight);
-    EXPECT_EQ(Rect(142, 142), observedData.rectClippedBounds);
-    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
-}
-
-TEST(OpReorderer, renderPropSaveLayerAlphaScale) {
-    SaveLayerAlphaData observedData;
-    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
-        properties.setPivotX(0);
-        properties.setPivotY(0);
-        properties.setScaleX(2);
-        properties.setScaleY(0.5f);
-    });
-    EXPECT_EQ(100u, observedData.layerWidth);
-    EXPECT_EQ(400u, observedData.layerHeight);
-    EXPECT_EQ(Rect(100, 400), observedData.rectClippedBounds);
-    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
-}
-
-} // namespace uirenderer
-} // namespace android
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index 08f927c..01bfc5a 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -35,12 +35,28 @@
 
 TEST(RecordingCanvas, emptyPlayback) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
-        canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+        canvas.save(SaveFlags::MatrixClip);
         canvas.restore();
     });
     playbackOps(*dl, [](const RecordedOp& op) { ADD_FAILURE(); });
 }
 
+TEST(RecordingCanvas, clipRect) {
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [](RecordingCanvas& canvas) {
+        canvas.save(SaveFlags::MatrixClip);
+        canvas.clipRect(0, 0, 100, 100, SkRegion::kIntersect_Op);
+        canvas.drawRect(0, 0, 50, 50, SkPaint());
+        canvas.drawRect(50, 50, 100, 100, SkPaint());
+        canvas.restore();
+    });
+
+    ASSERT_EQ(2u, dl->getOps().size()) << "Must be exactly two ops";
+    EXPECT_CLIP_RECT(Rect(100, 100), dl->getOps()[0]->localClip);
+    EXPECT_CLIP_RECT(Rect(100, 100), dl->getOps()[1]->localClip);
+    EXPECT_EQ(dl->getOps()[0]->localClip, dl->getOps()[1]->localClip)
+            << "Clip should be serialized once";
+}
+
 TEST(RecordingCanvas, drawLines) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
         SkPaint paint;
@@ -66,7 +82,7 @@
     ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
     auto op = *(dl->getOps()[0]);
     ASSERT_EQ(RecordedOpId::RectOp, op.opId);
-    EXPECT_EQ(Rect(100, 200), op.localClipRect);
+    EXPECT_EQ(nullptr, op.localClip);
     EXPECT_EQ(Rect(10, 20, 90, 180), op.unmappedBounds);
 }
 
@@ -83,7 +99,7 @@
     playbackOps(*dl, [&count](const RecordedOp& op) {
         count++;
         ASSERT_EQ(RecordedOpId::TextOp, op.opId);
-        EXPECT_EQ(Rect(200, 200), op.localClipRect);
+        EXPECT_EQ(nullptr, op.localClip);
         EXPECT_TRUE(op.localMatrix.isIdentity());
         EXPECT_TRUE(op.unmappedBounds.contains(25, 15, 50, 25))
                 << "Op expected to be 25+ pixels wide, 10+ pixels tall";
@@ -160,16 +176,16 @@
         SkPaint paint;
         paint.setColor(SK_ColorBLUE);
 
-        canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+        canvas.save(SaveFlags::MatrixClip);
         {
             // a background!
-            canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+            canvas.save(SaveFlags::MatrixClip);
             canvas.drawRect(0, 0, 100, 200, paint);
             canvas.restore();
         }
         {
             // an image!
-            canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+            canvas.save(SaveFlags::MatrixClip);
             canvas.translate(25, 25);
             canvas.scale(2, 2);
             canvas.drawBitmap(bitmap, 0, 0, nullptr);
@@ -185,7 +201,7 @@
             ASSERT_NE(nullptr, op.paint);
             EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
             EXPECT_EQ(Rect(100, 200), op.unmappedBounds);
-            EXPECT_EQ(Rect(100, 200), op.localClipRect);
+            EXPECT_EQ(nullptr, op.localClip);
 
             Matrix4 expectedMatrix;
             expectedMatrix.loadIdentity();
@@ -194,7 +210,7 @@
             ASSERT_EQ(RecordedOpId::BitmapOp, op.opId);
             EXPECT_EQ(nullptr, op.paint);
             EXPECT_EQ(Rect(25, 25), op.unmappedBounds);
-            EXPECT_EQ(Rect(100, 200), op.localClipRect);
+            EXPECT_EQ(nullptr, op.localClip);
 
             Matrix4 expectedMatrix;
             expectedMatrix.loadTranslate(25, 25, 0);
@@ -208,7 +224,7 @@
 
 TEST(RecordingCanvas, saveLayer_simple) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
-        canvas.saveLayerAlpha(10, 20, 190, 180, 128, SkCanvas::kARGB_ClipLayer_SaveFlag);
+        canvas.saveLayerAlpha(10, 20, 190, 180, 128, SaveFlags::ClipToLayer);
         canvas.drawRect(10, 20, 190, 180, SkPaint());
         canvas.restore();
     });
@@ -219,12 +235,12 @@
         case 0:
             EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId);
             EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
-            EXPECT_EQ(Rect(200, 200), op.localClipRect);
+            EXPECT_EQ(nullptr, op.localClip);
             EXPECT_TRUE(op.localMatrix.isIdentity());
             break;
         case 1:
             EXPECT_EQ(RecordedOpId::RectOp, op.opId);
-            EXPECT_EQ(Rect(180, 160), op.localClipRect);
+            EXPECT_CLIP_RECT(Rect(180, 160), op.localClip);
             EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
             expectedMatrix.loadTranslate(-10, -20, 0);
             EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
@@ -240,12 +256,78 @@
     EXPECT_EQ(3, count);
 }
 
+TEST(RecordingCanvas, saveLayer_missingRestore) {
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+        canvas.saveLayerAlpha(0, 0, 200, 200, 128, SaveFlags::ClipToLayer);
+        canvas.drawRect(0, 0, 200, 200, SkPaint());
+        // Note: restore omitted, shouldn't result in unmatched save
+    });
+    int count = 0;
+    playbackOps(*dl, [&count](const RecordedOp& op) {
+        if (count++ == 2) {
+            EXPECT_EQ(RecordedOpId::EndLayerOp, op.opId);
+        }
+    });
+    EXPECT_EQ(3, count) << "Missing a restore shouldn't result in an unmatched saveLayer";
+}
+
+TEST(RecordingCanvas, saveLayer_simpleUnclipped) {
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+        canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SaveFlags::Flags)0); // unclipped
+        canvas.drawRect(10, 20, 190, 180, SkPaint());
+        canvas.restore();
+    });
+    int count = 0;
+    playbackOps(*dl, [&count](const RecordedOp& op) {
+        switch(count++) {
+        case 0:
+            EXPECT_EQ(RecordedOpId::BeginUnclippedLayerOp, op.opId);
+            EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
+            EXPECT_EQ(nullptr, op.localClip);
+            EXPECT_TRUE(op.localMatrix.isIdentity());
+            break;
+        case 1:
+            EXPECT_EQ(RecordedOpId::RectOp, op.opId);
+            EXPECT_EQ(nullptr, op.localClip);
+            EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
+            EXPECT_TRUE(op.localMatrix.isIdentity());
+            break;
+        case 2:
+            EXPECT_EQ(RecordedOpId::EndUnclippedLayerOp, op.opId);
+            // Don't bother asserting recording state data - it's not used
+            break;
+        default:
+            ADD_FAILURE();
+        }
+    });
+    EXPECT_EQ(3, count);
+}
+
+TEST(RecordingCanvas, saveLayer_addClipFlag) {
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+        canvas.save(SaveFlags::MatrixClip);
+        canvas.clipRect(10, 20, 190, 180, SkRegion::kIntersect_Op);
+        canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SaveFlags::Flags)0); // unclipped
+        canvas.drawRect(10, 20, 190, 180, SkPaint());
+        canvas.restore();
+        canvas.restore();
+    });
+    int count = 0;
+    playbackOps(*dl, [&count](const RecordedOp& op) {
+        if (count++ == 0) {
+            EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId)
+                    << "Clip + unclipped saveLayer should result in a clipped layer";
+        }
+    });
+    EXPECT_EQ(3, count);
+}
+
 TEST(RecordingCanvas, saveLayer_viewportCrop) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         // shouldn't matter, since saveLayer will clip to its bounds
         canvas.clipRect(-1000, -1000, 1000, 1000, SkRegion::kReplace_Op);
 
-        canvas.saveLayerAlpha(100, 100, 300, 300, 128, SkCanvas::kARGB_ClipLayer_SaveFlag);
+        canvas.saveLayerAlpha(100, 100, 300, 300, 128, SaveFlags::ClipToLayer);
         canvas.drawRect(0, 0, 400, 400, SkPaint());
         canvas.restore();
     });
@@ -254,8 +336,8 @@
         if (count++ == 1) {
             Matrix4 expectedMatrix;
             EXPECT_EQ(RecordedOpId::RectOp, op.opId);
-            EXPECT_EQ(Rect(100, 100), op.localClipRect) << "Recorded clip rect should be"
-                    " intersection of viewport and saveLayer bounds, in layer space";
+            EXPECT_CLIP_RECT(Rect(100, 100), op.localClip) // Recorded clip rect should be
+            // intersection of viewport and saveLayer bounds, in layer space;
             EXPECT_EQ(Rect(400, 400), op.unmappedBounds);
             expectedMatrix.loadTranslate(-100, -100, 0);
             EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
@@ -266,12 +348,12 @@
 
 TEST(RecordingCanvas, saveLayer_rotateUnclipped) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
-        canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+        canvas.save(SaveFlags::MatrixClip);
         canvas.translate(100, 100);
         canvas.rotate(45);
         canvas.translate(-50, -50);
 
-        canvas.saveLayerAlpha(0, 0, 100, 100, 128, SkCanvas::kARGB_ClipLayer_SaveFlag);
+        canvas.saveLayerAlpha(0, 0, 100, 100, 128, SaveFlags::ClipToLayer);
         canvas.drawRect(0, 0, 100, 100, SkPaint());
         canvas.restore();
 
@@ -281,7 +363,7 @@
     playbackOps(*dl, [&count](const RecordedOp& op) {
         if (count++ == 1) {
             EXPECT_EQ(RecordedOpId::RectOp, op.opId);
-            EXPECT_EQ(Rect(100, 100), op.localClipRect);
+            EXPECT_CLIP_RECT(Rect(100, 100), op.localClip);
             EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
             EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.localMatrix)
                     << "Recorded op shouldn't see any canvas transform before the saveLayer";
@@ -292,13 +374,13 @@
 
 TEST(RecordingCanvas, saveLayer_rotateClipped) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
-        canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+        canvas.save(SaveFlags::MatrixClip);
         canvas.translate(100, 100);
         canvas.rotate(45);
         canvas.translate(-200, -200);
 
         // area of saveLayer will be clipped to parent viewport, so we ask for 400x400...
-        canvas.saveLayerAlpha(0, 0, 400, 400, 128, SkCanvas::kARGB_ClipLayer_SaveFlag);
+        canvas.saveLayerAlpha(0, 0, 400, 400, 128, SaveFlags::ClipToLayer);
         canvas.drawRect(0, 0, 400, 400, SkPaint());
         canvas.restore();
 
@@ -312,7 +394,16 @@
 
             // ...and get about 58.6, 58.6, 341.4 341.4, because the bounds are clipped by
             // the parent 200x200 viewport, but prior to rotation
-            EXPECT_RECT_APPROX_EQ(Rect(58.57864, 58.57864, 341.42136, 341.42136), op.localClipRect);
+            ASSERT_NE(nullptr, op.localClip);
+            ASSERT_EQ(ClipMode::Rectangle, op.localClip->mode);
+            // NOTE: this check relies on saveLayer altering the clip post-viewport init. This
+            // causes the clip to be recorded by contained draw commands, though it's not necessary
+            // 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(400, 400), op.unmappedBounds);
             expectedMatrix.loadIdentity();
             EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
diff --git a/libs/hwui/tests/unit/StringUtilsTests.cpp b/libs/hwui/tests/unit/StringUtilsTests.cpp
index 6b2e265..b60e96c 100644
--- a/libs/hwui/tests/unit/StringUtilsTests.cpp
+++ b/libs/hwui/tests/unit/StringUtilsTests.cpp
@@ -36,3 +36,18 @@
     EXPECT_TRUE(collection.has("GL_ext1"));
     EXPECT_FALSE(collection.has("GL_ext")); // string present, but not in list
 }
+
+TEST(StringUtils, sizePrinter) {
+    std::stringstream os;
+    os << SizePrinter{500};
+    EXPECT_EQ("500.00B", os.str());
+    os.str("");
+    os << SizePrinter{46080};
+    EXPECT_EQ("45.00KiB", os.str());
+    os.str("");
+    os << SizePrinter{5 * 1024 * 1024 + 520 * 1024};
+    EXPECT_EQ("5.51MiB", os.str());
+    os.str("");
+    os << SizePrinter{2147483647};
+    EXPECT_EQ("2048.00MiB", os.str());
+}
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index 77dd73a..7208547 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -17,6 +17,7 @@
 #include <gtest/gtest.h>
 
 #include "PathParser.h"
+#include "VectorDrawable.h"
 #include "utils/MathUtils.h"
 #include "utils/VectorDrawableUtils.h"
 
@@ -98,6 +99,65 @@
         }
     },
 
+    // Check box VectorDrawable path data
+    {
+        // Path
+        "M 0.0,-1.0 l 0.0,0.0 c 0.5522847498,0.0 1.0,0.4477152502 1.0,1.0 l 0.0,0.0 c 0.0,0.5522847498 -0.4477152502,1.0 -1.0,1.0 l 0.0,0.0 c -0.5522847498,0.0 -1.0,-0.4477152502 -1.0,-1.0 l 0.0,0.0 c 0.0,-0.5522847498 0.4477152502,-1.0 1.0,-1.0 Z M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z",
+        {
+            {'M', 'l', 'c', 'l', 'c', 'l', 'c', 'l', 'c', 'Z', 'M', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'Z'},
+            {2, 2, 6, 2, 6, 2, 6, 2, 6, 0, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0},
+            {0.0, -1.0, 0.0, 0.0, 0.5522848, 0.0, 1.0, 0.44771525, 1.0, 1.0, 0.0, 0.0, 0.0, 0.5522848, -0.44771525, 1.0, -1.0, 1.0, 0.0, 0.0, -0.5522848, 0.0, -1.0, -0.44771525, -1.0, -1.0, 0.0, 0.0, 0.0, -0.5522848, 0.44771525, -1.0, 1.0, -1.0, 7.0, -9.0, 0.0, 0.0, -14.0, 0.0, -14.0, 0.0, -1.1044922, 0.0, -2.0, 0.8955078, -2.0, 2.0, 0.0, 0.0, 0.0, 14.0, 0.0, 14.0, 0.0, 1.1044922, 0.8955078, 2.0, 2.0, 2.0, 0.0, 0.0, 14.0, 0.0, 14.0, 0.0, 1.1044922, 0.0, 2.0, -0.8955078, 2.0, -2.0, 0.0, 0.0, 0.0, -14.0, 0.0, -14.0, 0.0, -1.1044922, -0.8955078, -2.0, -2.0, -2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
+        },
+        [](SkPath* outPath) {
+            outPath->moveTo(0.0, -1.0);
+            outPath->rLineTo(0.0, 0.0);
+            outPath->rCubicTo(0.5522848, 0.0, 1.0, 0.44771525, 1.0, 1.0);
+            outPath->rLineTo(0.0, 0.0);
+            outPath->rCubicTo(0.0, 0.5522848, -0.44771525, 1.0, -1.0, 1.0);
+            outPath->rLineTo(0.0, 0.0);
+            outPath->rCubicTo(-0.5522848, 0.0, -1.0, -0.44771525, -1.0, -1.0);
+            outPath->rLineTo(0.0, 0.0);
+            outPath->rCubicTo(0.0, -0.5522848, 0.44771525, -1.0, 1.0, -1.0);
+            outPath->close();
+            outPath->moveTo(0.0, -1.0);
+            outPath->moveTo(7.0, -9.0);
+            outPath->rCubicTo(0.0, 0.0, -14.0, 0.0, -14.0, 0.0);
+            outPath->rCubicTo(-1.1044922, 0.0, -2.0, 0.8955078, -2.0, 2.0);
+            outPath->rCubicTo(0.0, 0.0, 0.0, 14.0, 0.0, 14.0);
+            outPath->rCubicTo(0.0, 1.1044922, 0.8955078, 2.0, 2.0, 2.0);
+            outPath->rCubicTo(0.0, 0.0, 14.0, 0.0, 14.0, 0.0);
+            outPath->rCubicTo(1.1044922, 0.0, 2.0, -0.8955078, 2.0, -2.0);
+            outPath->rCubicTo(0.0, 0.0, 0.0, -14.0, 0.0, -14.0);
+            outPath->rCubicTo(0.0, -1.1044922, -0.8955078, -2.0, -2.0, -2.0);
+            outPath->rCubicTo(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+            outPath->close();
+            outPath->moveTo(7.0, -9.0);
+        }
+    },
+
+    // pie1 in progress bar
+    {
+        "M300,70 a230,230 0 1,0 1,0 z",
+        {
+             {'M', 'a', 'z', },
+             {2, 7, 0, },
+             {300.0, 70.0, 230.0, 230.0, 0.0, 1.0, 0.0, 1.0, 0.0, },
+        },
+        [](SkPath* outPath) {
+            outPath->moveTo(300.0, 70.0);
+            outPath->cubicTo(239.06697794203706, 70.13246340443499, 180.6164396449267, 94.47383115953485, 137.6004913602211, 137.6302781499585);
+            outPath->cubicTo(94.58454307551551, 180.78672514038215, 70.43390412842275, 239.3163266242308, 70.50013586976587, 300.2494566687817);
+            outPath->cubicTo(70.56636761110899, 361.1825867133326, 94.84418775550249, 419.65954850554147, 137.9538527586204, 462.72238058830936);
+            outPath->cubicTo(181.06351776173827, 505.7852126710772, 239.5668339599056, 529.999456521097, 300.49999999999994, 529.999456521097);
+            outPath->cubicTo(361.43316604009436, 529.999456521097, 419.93648223826176, 505.78521267107726, 463.0461472413797, 462.7223805883093);
+            outPath->cubicTo(506.1558122444976, 419.65954850554135, 530.433632388891, 361.1825867133324, 530.4998641302341, 300.2494566687815);
+            outPath->cubicTo(530.5660958715771, 239.31632662423056, 506.4154569244844, 180.7867251403819, 463.3995086397787, 137.6302781499583);
+            outPath->cubicTo(420.383560355073, 94.47383115953468, 361.93302205796255, 70.13246340443492, 300.9999999999996, 70.00000000000003);
+            outPath->close();
+            outPath->moveTo(300.0, 70.0);
+        }
+    },
+
     // Random long data
     {
         // Path
@@ -178,6 +238,7 @@
     {"1-2e34567", false}
 };
 
+
 static bool hasSameVerbs(const PathData& from, const PathData& to) {
     return from.verbs == to.verbs && from.verbSizes == to.verbSizes;
 }
@@ -284,6 +345,49 @@
     }
 }
 
+TEST(VectorDrawable, matrixScale) {
+    struct MatrixAndScale {
+        float buffer[9];
+        float matrixScale;
+    };
 
+    const MatrixAndScale sMatrixAndScales[] {
+        {
+            {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+            1.0
+        },
+        {
+            {1.0f, 0.0f, 240.0f, 0.0f, 1.0f, 240.0f, 0.0f, 0.0f, 1.0f},
+            1.0f,
+        },
+        {
+            {1.5f, 0.0f, 24.0f, 0.0f, 1.5f, 24.0f, 0.0f, 0.0f, 1.0f},
+            1.5f,
+        },
+        {
+            {0.99999994f, 0.0f, 300.0f, 0.0f, 0.99999994f, 158.57864f, 0.0f, 0.0f, 1.0f},
+            0.99999994f,
+        },
+        {
+            {0.7071067f, 0.7071067f, 402.5305f, -0.7071067f, 0.7071067f, 169.18524f, 0.0f, 0.0f, 1.0f},
+            0.99999994f,
+        },
+        {
+            {0.0f, 0.9999999f, 482.5305f, -0.9999999f, 0.0f, 104.18525f, 0.0f, 0.0f, 1.0f},
+            0.9999999f,
+        },
+        {
+            {-0.35810637f, -0.93368083f, 76.55821f, 0.93368083f, -0.35810637f, 89.538506f, 0.0f, 0.0f, 1.0f},
+            1.0000001f,
+        },
+    };
+
+    for (MatrixAndScale matrixAndScale : sMatrixAndScales) {
+        SkMatrix matrix;
+        matrix.set9(matrixAndScale.buffer);
+        float actualMatrixScale = VectorDrawable::Path::getMatrixScale(matrix);
+        EXPECT_EQ(matrixAndScale.matrixScale, actualMatrixScale);
+    }
+}
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/utils/GLUtils.cpp b/libs/hwui/utils/GLUtils.cpp
index 55104de..33209759 100644
--- a/libs/hwui/utils/GLUtils.cpp
+++ b/libs/hwui/utils/GLUtils.cpp
@@ -21,10 +21,19 @@
 
 #include "GLUtils.h"
 
+#if DEBUG_OPENGL >= DEBUG_LEVEL_HIGH && !defined(HWUI_GLES_WRAP_ENABLED)
+#error Setting DEBUG_OPENGL to HIGH requires setting HWUI_ENABLE_OPENGL_VALIDATION to true in the Android.mk!
+#endif
+
 namespace android {
 namespace uirenderer {
 
 bool GLUtils::dumpGLErrors() {
+#if DEBUG_OPENGL >= DEBUG_LEVEL_HIGH
+    // If DEBUG_LEVEL_HIGH is set then every GLES call is already wrapped
+    // and asserts that there was no error. So this can just return success.
+    return false;
+#else
     bool errorObserved = false;
     GLenum status = GL_NO_ERROR;
     while ((status = glGetError()) != GL_NO_ERROR) {
@@ -47,6 +56,7 @@
         }
     }
     return errorObserved;
+#endif
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/utils/GLUtils.h b/libs/hwui/utils/GLUtils.h
index 7020461..b49c1eb 100644
--- a/libs/hwui/utils/GLUtils.h
+++ b/libs/hwui/utils/GLUtils.h
@@ -16,13 +16,29 @@
 #ifndef GLUTILS_H
 #define GLUTILS_H
 
+#include "Debug.h"
+
+#include <cutils/log.h>
+
 namespace android {
 namespace uirenderer {
 
+
+#if DEBUG_OPENGL
+#define GL_CHECKPOINT(LEVEL) \
+    do { if (DEBUG_OPENGL >= DEBUG_LEVEL_##LEVEL) {\
+    LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(),\
+            "GL errors! %s:%d", __FILE__, __LINE__);\
+    } } while (0)
+#else
+#define GL_CHECKPOINT(LEVEL)
+#endif
+
 class GLUtils {
 public:
     /**
      * Print out any GL errors with ALOGE, returns true if any errors were found.
+     * You probably want to use GL_CHECKPOINT(LEVEL) instead of calling this directly
      */
     static bool dumpGLErrors();
 
diff --git a/libs/hwui/utils/LinearAllocator.h b/libs/hwui/utils/LinearAllocator.h
index e1c6f6c..dcbc0dd 100644
--- a/libs/hwui/utils/LinearAllocator.h
+++ b/libs/hwui/utils/LinearAllocator.h
@@ -56,12 +56,12 @@
     void* alloc(size_t size);
 
     /**
-     * Allocates an instance of the template type with the default constructor
+     * Allocates an instance of the template type with the given construction parameters
      * and adds it to the automatic destruction list.
      */
-    template<class T>
-    T* alloc() {
-        T* ret = new (*this) T;
+    template<class T, typename... Params>
+    T* create(Params... params) {
+        T* ret = new (*this) T(params...);
         autoDestroy(ret);
         return ret;
     }
diff --git a/libs/hwui/utils/StringUtils.h b/libs/hwui/utils/StringUtils.h
index 055869f..05a3d59 100644
--- a/libs/hwui/utils/StringUtils.h
+++ b/libs/hwui/utils/StringUtils.h
@@ -18,6 +18,8 @@
 
 #include <string>
 #include <unordered_set>
+#include <ostream>
+#include <iomanip>
 
 namespace android {
 namespace uirenderer {
@@ -34,6 +36,21 @@
     static unordered_string_set split(const char* spacedList);
 };
 
+struct SizePrinter {
+    int bytes;
+    friend std::ostream& operator<<(std::ostream& stream, const SizePrinter& d) {
+        static const char* SUFFIXES[] = {"B", "KiB", "MiB"};
+        size_t suffix = 0;
+        double temp = d.bytes;
+        while (temp > 1000 && suffix < 2) {
+            temp /= 1024.0;
+            suffix++;
+        }
+        stream << std::fixed << std::setprecision(2) << temp << SUFFIXES[suffix];
+        return stream;
+    }
+};
+
 } /* namespace uirenderer */
 } /* namespace android */
 
diff --git a/libs/hwui/utils/TestWindowContext.cpp b/libs/hwui/utils/TestWindowContext.cpp
index 05b4a72..b0431ce 100644
--- a/libs/hwui/utils/TestWindowContext.cpp
+++ b/libs/hwui/utils/TestWindowContext.cpp
@@ -18,6 +18,7 @@
 #include "AnimationContext.h"
 #include "DisplayListCanvas.h"
 #include "IContextFactory.h"
+#include "RecordingCanvas.h"
 #include "RenderNode.h"
 #include "SkTypes.h"
 #include "gui/BufferQueue.h"
@@ -88,9 +89,11 @@
         mProxy->setup(mSize.width(), mSize.height(), 800.0f,
                              255 * 0.075f, 255 * 0.15f);
         mProxy->setLightCenter(lightVector);
-        mCanvas.reset(new
-            android::uirenderer::DisplayListCanvas(mSize.width(),
-                                                   mSize.height()));
+#if HWUI_NEW_OPS
+        mCanvas.reset(new android::uirenderer::RecordingCanvas(mSize.width(), mSize.height()));
+#else
+        mCanvas.reset(new android::uirenderer::DisplayListCanvas(mSize.width(), mSize.height()));
+#endif
     }
 
     SkCanvas* prepareToDraw() {
@@ -135,8 +138,8 @@
 
         // Move the pixels into the destination SkBitmap
 
-        SK_ALWAYSBREAK(nativeBuffer.format == android::PIXEL_FORMAT_RGBA_8888 &&
-                       "Native buffer not RGBA!");
+        LOG_ALWAYS_FATAL_IF(nativeBuffer.format != android::PIXEL_FORMAT_RGBA_8888,
+                            "Native buffer not RGBA!");
         SkImageInfo nativeConfig =
             SkImageInfo::Make(nativeBuffer.width, nativeBuffer.height,
                               kRGBA_8888_SkColorType, kPremul_SkAlphaType);
@@ -150,8 +153,8 @@
             return false;
         }
 
-        SK_ALWAYSBREAK(bmp->colorType() == kRGBA_8888_SkColorType &&
-                       "Destination buffer not RGBA!");
+        LOG_ALWAYS_FATAL_IF(bmp->colorType() != kRGBA_8888_SkColorType,
+                            "Destination buffer not RGBA!");
         success =
             nativeWrapper.readPixels(destinationConfig, bmp->getPixels(), bmp->rowBytes(), 0, 0);
         if (!success) {
@@ -168,7 +171,11 @@
 
     std::unique_ptr<android::uirenderer::RenderNode> mRootNode;
     std::unique_ptr<android::uirenderer::renderthread::RenderProxy> mProxy;
+#if HWUI_NEW_OPS
+    std::unique_ptr<android::uirenderer::RecordingCanvas> mCanvas;
+#else
     std::unique_ptr<android::uirenderer::DisplayListCanvas> mCanvas;
+#endif
     android::sp<android::IGraphicBufferProducer> mProducer;
     android::sp<android::IGraphicBufferConsumer> mConsumer;
     android::sp<android::CpuConsumer> mCpuConsumer;
diff --git a/libs/hwui/utils/VectorDrawableUtils.h b/libs/hwui/utils/VectorDrawableUtils.h
index 21c1cdc..b5ef510 100644
--- a/libs/hwui/utils/VectorDrawableUtils.h
+++ b/libs/hwui/utils/VectorDrawableUtils.h
@@ -17,7 +17,7 @@
 #ifndef ANDROID_HWUI_VECTORDRAWABLE_UTILS_H
 #define ANDROID_HWUI_VECTORDRAWABLE_UTILS_H
 
-#include "VectorDrawablePath.h"
+#include "VectorDrawable.h"
 
 #include <cutils/compiler.h>
 #include "SkPath.h"
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 529849e..212c6a0 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -90,6 +90,7 @@
     mLocked.lastFrameUpdatedTime = 0;
 
     mLocked.buttonState = 0;
+    mLocked.iconDetached = false;
 
     mPolicy->loadPointerIcon(&mLocked.pointerIcon);
 
@@ -184,6 +185,10 @@
 }
 
 void PointerController::setPositionLocked(float x, float y) {
+    if (mLocked.iconDetached) {
+        return;
+    }
+
     float minX, minY, maxX, maxY;
     if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
         if (x <= minX) {
@@ -217,6 +222,10 @@
     // Remove the inactivity timeout, since we are fading now.
     removeInactivityTimeoutLocked();
 
+    if (mLocked.iconDetached) {
+        return;
+    }
+
     // Start fading.
     if (transition == TRANSITION_IMMEDIATE) {
         mLocked.pointerFadeDirection = 0;
@@ -234,6 +243,10 @@
     // Always reset the inactivity timer.
     resetInactivityTimeoutLocked();
 
+    if (mLocked.iconDetached) {
+        return;
+    }
+
     // Start unfading.
     if (transition == TRANSITION_IMMEDIATE) {
         mLocked.pointerFadeDirection = 0;
@@ -349,6 +362,22 @@
     updatePointerLocked();
 }
 
+void PointerController::detachPointerIcon(bool detached) {
+    AutoMutex _l(mLock);
+
+    if (mLocked.iconDetached == detached) {
+        return;
+    }
+
+    mLocked.iconDetached = detached;
+    if (detached) {
+        mLocked.pointerFadeDirection = -1;
+    } else {
+        mLocked.pointerFadeDirection = 1;
+    }
+    startAnimationLocked();
+}
+
 void PointerController::setDisplayViewport(int32_t width, int32_t height, int32_t orientation) {
     AutoMutex _l(mLock);
 
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 9ba37b3..c1381f3 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -111,6 +111,10 @@
     void setInactivityTimeout(InactivityTimeout inactivityTimeout);
     void reloadPointerResources();
 
+    /* Detach or attach the pointer icon status. When detached, the pointer icon disappears
+     * and the icon location does not change at all. */
+    void detachPointerIcon(bool detached);
+
 private:
     static const size_t MAX_RECYCLED_SPRITES = 12;
     static const size_t MAX_SPOTS = 12;
@@ -180,6 +184,8 @@
 
         int32_t buttonState;
 
+        bool iconDetached;
+
         Vector<Spot*> spots;
         Vector<sp<Sprite> > recycledSprites;
     } mLocked;
diff --git a/location/java/android/location/GnssNmeaListener.java b/location/java/android/location/GnssNmeaListener.java
new file mode 100644
index 0000000..6c9b08a
--- /dev/null
+++ b/location/java/android/location/GnssNmeaListener.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.location;
+
+/**
+* Used for receiving NMEA sentences from the GNSS.
+* NMEA 0183 is a standard for communicating with marine electronic devices
+* and is a common method for receiving data from a GNSS, typically over a serial port.
+* See <a href="http://en.wikipedia.org/wiki/NMEA_0183">NMEA 0183</a> for more details.
+* You can implement this interface and call {@link LocationManager#addNmeaListener}
+* to receive NMEA data from the GNSS engine.
+*/
+public interface GnssNmeaListener {
+    /** Called when an NMEA message is received. */
+    void onNmeaReceived(long timestamp, String nmea);
+}
\ No newline at end of file
diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java
new file mode 100644
index 0000000..77e8a5b
--- /dev/null
+++ b/location/java/android/location/GnssStatus.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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;
+
+/**
+ * This class represents the current state of the GNSS engine.
+ * This class is used in conjunction with the {@link GnssStatusCallback}.
+ */
+public final class GnssStatus {
+    /** Unknown constellation type. */
+    public static final int CONSTELLATION_UNKNOWN = 0;
+    /** Constellation type constant for GPS. */
+    public static final int CONSTELLATION_GPS = 1;
+    /** Constellation type constant for SBAS. */
+    public static final int CONSTELLATION_SBAS = 2;
+    /** Constellation type constant for Glonass. */
+    public static final int CONSTELLATION_GLONASS = 3;
+    /** Constellation type constant for QZSS. */
+    public static final int CONSTELLATION_QZSS = 4;
+    /** Constellation type constant for Beidou. */
+    public static final int CONSTELLATION_BEIDOU = 5;
+    /** Constellation type constant for Galileo. */
+    public static final int CONSTELLATION_GALILEO = 6;
+
+    // these must match the definitions in gps.h
+    /** @hide */
+    public static final int GNSS_SV_FLAGS_NONE = 0;
+    /** @hide */
+    public static final int GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA = (1 << 0);
+    /** @hide */
+    public static final int GNSS_SV_FLAGS_HAS_ALMANAC_DATA = (1 << 1);
+    /** @hide */
+    public static final int GNSS_SV_FLAGS_USED_IN_FIX = (1 << 2);
+
+    /** @hide */
+    public static final int PRN_SHIFT_WIDTH = 3;
+
+    /* These package private values are modified by the LocationManager class */
+    /* package */ int[] mPrnWithFlags;
+    /* package */ float[] mSnrs;
+    /* package */ float[] mElevations;
+    /* package */ float[] mAzimuths;
+    /* package */ int[] mConstellationTypes;
+    /* package */ int mSvCount;
+
+    GnssStatus(int svCount, int[] prnWithFlags, float[] snrs, float[] elevations, float[] azimuths,
+            int[] constellationTypes) {
+        mSvCount = svCount;
+        mPrnWithFlags = prnWithFlags;
+        mSnrs = snrs;
+        mElevations = elevations;
+        mAzimuths = azimuths;
+        mConstellationTypes = constellationTypes;
+    }
+
+    /**
+     * Gets the total number of satellites in satellite list.
+     */
+    public int getNumSatellites() {
+        return mSvCount;
+    }
+
+    /**
+     * Retrieves the constellation type of the satellite at the specified position.
+     * @param satIndex the index of the satellite in the list.
+     */
+    public int getConstellationType(int satIndex) {
+        return mConstellationTypes[satIndex];
+    }
+
+    /**
+     * Retrieves the pseudo-random number of the satellite at the specified position.
+     * @param satIndex the index of the satellite in the list.
+     */
+    public int getPrn(int satIndex) {
+        return mPrnWithFlags[satIndex] >> PRN_SHIFT_WIDTH;
+    }
+
+    /**
+     * 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];
+    }
+
+    /**
+     * 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;
+    }
+
+    /**
+     * Retrieves the azimuth the satellite at the specified position.
+     * @param satIndex the index of the satellite in the list.
+     */
+    public float getAzimuth(int satIndex) {
+        return mAzimuths[satIndex];
+    }
+
+    /**
+     * Detects whether the satellite at the specified position has ephemeris data.
+     * @param satIndex the index of the satellite in the list.
+     */
+    public boolean hasEphemeris(int satIndex) {
+        return (mPrnWithFlags[satIndex] & GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) != 0;
+    }
+
+    /**
+     * Detects whether the satellite at the specified position has almanac data.
+     * @param satIndex the index of the satellite in the list.
+     */
+    public boolean hasAlmanac(int satIndex) {
+        return (mPrnWithFlags[satIndex] & GNSS_SV_FLAGS_HAS_ALMANAC_DATA) != 0;
+    }
+
+    /**
+     * Detects whether the satellite at the specified position is used in fix.
+     * @param satIndex the index of the satellite in the list.
+     */
+    public boolean usedInFix(int satIndex) {
+        return (mPrnWithFlags[satIndex] & GNSS_SV_FLAGS_USED_IN_FIX) != 0;
+    }
+}
diff --git a/location/java/android/location/GnssStatusCallback.java b/location/java/android/location/GnssStatusCallback.java
new file mode 100644
index 0000000..b86171b
--- /dev/null
+++ b/location/java/android/location/GnssStatusCallback.java
@@ -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.
+ */
+
+package android.location;
+
+/**
+ * Used for receiving notifications when GNSS events happen.
+ */
+public abstract class GnssStatusCallback {
+    /**
+     * Called when GNSS system has started.
+     */
+    public void onStarted() {}
+
+    /**
+     * Called when GNSS system has stopped.
+     */
+    public void onStopped() {}
+
+    /**
+     * Called when the GNSS system has received its first fix since starting.
+     * @param ttff the time from start to first fix.
+     */
+    public void onFirstFix(int ttff) {}
+
+    /**
+     * 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/GpsClock.java b/location/java/android/location/GpsClock.java
index 4135a1c..719e56f 100644
--- a/location/java/android/location/GpsClock.java
+++ b/location/java/android/location/GpsClock.java
@@ -16,36 +16,41 @@
 
 package android.location;
 
-import android.annotation.SystemApi;
+import android.annotation.IntDef;
 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.
- *
- * @hide
  */
-@SystemApi
-public class GpsClock implements Parcelable {
+public final class GpsClock 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 GpsClockType {}
+
     /**
      * The type of the time stored is not available or it is unknown.
      */
-    public static final byte TYPE_UNKNOWN = 0;
+    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 TYPE_LOCAL_HW_TIME = 1;
+    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 TYPE_GPS_TIME = 2;
+    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);
@@ -68,6 +73,7 @@
     private double mBiasUncertaintyInNs;
     private double mDriftInNsPerSec;
     private double mDriftUncertaintyInNsPerSec;
+    private long mTimeOfLastHwClockDiscontinuityInNs;
 
     GpsClock() {
         initialize();
@@ -87,6 +93,7 @@
         mBiasUncertaintyInNs = clock.mBiasUncertaintyInNs;
         mDriftInNsPerSec = clock.mDriftInNsPerSec;
         mDriftUncertaintyInNsPerSec = clock.mDriftUncertaintyInNsPerSec;
+        mTimeOfLastHwClockDiscontinuityInNs = clock.mTimeOfLastHwClockDiscontinuityInNs;
     }
 
     /**
@@ -99,6 +106,7 @@
     /**
      * Gets the type of time reported by {@link #getTimeInNs()}.
      */
+    @GpsClockType
     public byte getType() {
         return mType;
     }
@@ -106,7 +114,7 @@
     /**
      * Sets the type of time reported.
      */
-    public void setType(byte value) {
+    public void setType(@GpsClockType byte value) {
         mType = value;
     }
 
@@ -116,11 +124,11 @@
      */
     private String getTypeString() {
         switch (mType) {
-            case TYPE_UNKNOWN:
+            case CLOCK_TYPE_UNKNOWN:
                 return "Unknown";
-            case TYPE_GPS_TIME:
+            case CLOCK_TYPE_GPS_TIME:
                 return "GpsTime";
-            case TYPE_LOCAL_HW_TIME:
+            case CLOCK_TYPE_LOCAL_HW_TIME:
                 return "LocalHwClock";
             default:
                 return "<Invalid:" + mType + ">";
@@ -163,8 +171,8 @@
 
     /**
      * Gets the GPS receiver internal clock value in nanoseconds.
-     * This can be either the 'local hardware clock' value ({@link #TYPE_LOCAL_HW_TIME}), or the
-     * current GPS time derived inside GPS receiver ({@link #TYPE_GPS_TIME}).
+     * 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.
      *
      * For 'local hardware clock' this value is expected to be monotonically increasing during the
@@ -223,7 +231,7 @@
     }
 
     /**
-     * Returns true if {@link @getFullBiasInNs()} is available, false otherwise.
+     * Returns true if {@link #getFullBiasInNs()} is available, false otherwise.
      */
     public boolean hasFullBiasInNs() {
         return isFlagSet(HAS_FULL_BIAS);
@@ -233,7 +241,7 @@
      * Gets the difference between hardware clock ({@link #getTimeInNs()}) inside GPS receiver and
      * the true GPS time since 0000Z, January 6, 1980, in nanoseconds.
      *
-     * This value is available if {@link #TYPE_LOCAL_HW_TIME} is set, and GPS receiver has solved
+     * 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.
      *
@@ -387,6 +395,20 @@
     }
 
     /**
+     * Gets time of last hardware clock discontinuity.
+     */
+    public long getTimeOfLastHwClockDiscontinuityInNs() {
+        return mTimeOfLastHwClockDiscontinuityInNs;
+    }
+
+    /**
+     * Sets time of last hardware clock discontinuity.
+     */
+    public void setTimeOfLastHwClockDiscontinuityInNs(long timeOfLastHwClockDiscontinuityInNs) {
+        mTimeOfLastHwClockDiscontinuityInNs = timeOfLastHwClockDiscontinuityInNs;
+    }
+
+    /**
      * Resets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
      */
     public void resetDriftUncertaintyInNsPerSec() {
@@ -409,6 +431,7 @@
             gpsClock.mBiasUncertaintyInNs = parcel.readDouble();
             gpsClock.mDriftInNsPerSec = parcel.readDouble();
             gpsClock.mDriftUncertaintyInNsPerSec = parcel.readDouble();
+            gpsClock.mTimeOfLastHwClockDiscontinuityInNs = parcel.readLong();
 
             return gpsClock;
         }
@@ -430,6 +453,7 @@
         parcel.writeDouble(mBiasUncertaintyInNs);
         parcel.writeDouble(mDriftInNsPerSec);
         parcel.writeDouble(mDriftUncertaintyInNsPerSec);
+        parcel.writeLong(mTimeOfLastHwClockDiscontinuityInNs);
     }
 
     @Override
@@ -473,13 +497,17 @@
                 "DriftUncertaintyInNsPerSec",
                 hasDriftUncertaintyInNsPerSec() ? mDriftUncertaintyInNsPerSec : null));
 
+        builder.append(String.format(format, "TimeOfLastHwClockDiscontinuityInNs",
+                getType() == CLOCK_TYPE_LOCAL_HW_TIME
+                        ? mTimeOfLastHwClockDiscontinuityInNs : null));
+
         return builder.toString();
     }
 
     private void initialize() {
         mFlags = HAS_NO_FLAGS;
         resetLeapSecond();
-        setType(TYPE_UNKNOWN);
+        setType(CLOCK_TYPE_UNKNOWN);
         setTimeInNs(Long.MIN_VALUE);
         resetTimeUncertaintyInNs();
         resetFullBiasInNs();
@@ -487,6 +515,7 @@
         resetBiasUncertaintyInNs();
         resetDriftInNsPerSec();
         resetDriftUncertaintyInNsPerSec();
+        setTimeOfLastHwClockDiscontinuityInNs(Long.MIN_VALUE);
     }
 
     private void setFlag(short flag) {
diff --git a/location/java/android/location/GpsMeasurement.java b/location/java/android/location/GpsMeasurement.java
index f13a440..366ad61 100644
--- a/location/java/android/location/GpsMeasurement.java
+++ b/location/java/android/location/GpsMeasurement.java
@@ -16,17 +16,17 @@
 
 package android.location;
 
-import android.annotation.SystemApi;
+import android.annotation.IntDef;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * A class representing a GPS satellite measurement, containing raw and computed information.
- *
- * @hide
  */
-@SystemApi
-public class GpsMeasurement implements Parcelable {
+public final class GpsMeasurement implements Parcelable {
     private int mFlags;
     private byte mPrn;
     private double mTimeOffsetInNs;
@@ -59,6 +59,8 @@
     private double mAzimuthInDeg;
     private double mAzimuthUncertaintyInDeg;
     private boolean mUsedInFix;
+    private double mPseudorangeRateCarrierInMetersPerSec;
+    private double mPseudorangeRateCarrierUncertaintyInMetersPerSec;
 
     // The following enumerations must be in sync with the values declared in gps.h
 
@@ -83,6 +85,11 @@
     private static final int HAS_USED_IN_FIX = (1<<17);
     private static final int GPS_MEASUREMENT_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.
      */
@@ -98,6 +105,12 @@
      */
     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})
+    public @interface MultipathIndicator {}
+
     /**
      * The indicator is not available or it is unknown.
      */
@@ -218,6 +231,10 @@
         mAzimuthInDeg = measurement.mAzimuthInDeg;
         mAzimuthUncertaintyInDeg = measurement.mAzimuthUncertaintyInDeg;
         mUsedInFix = measurement.mUsedInFix;
+        mPseudorangeRateCarrierInMetersPerSec =
+                measurement.mPseudorangeRateCarrierInMetersPerSec;
+        mPseudorangeRateCarrierUncertaintyInMetersPerSec =
+                measurement.mPseudorangeRateCarrierUncertaintyInMetersPerSec;
     }
 
     /**
@@ -776,6 +793,7 @@
     /**
      * Gets a value indicating the 'loss of lock' state of the event.
      */
+    @LossOfLockStatus
     public byte getLossOfLock() {
         return mLossOfLock;
     }
@@ -783,7 +801,7 @@
     /**
      * Sets the 'loss of lock' status.
      */
-    public void setLossOfLock(byte value) {
+    public void setLossOfLock(@LossOfLockStatus byte value) {
         mLossOfLock = value;
     }
 
@@ -941,6 +959,7 @@
     /**
      * Gets a value indicating the 'multipath' state of the event.
      */
+    @MultipathIndicator
     public byte getMultipathIndicator() {
         return mMultipathIndicator;
     }
@@ -948,7 +967,7 @@
     /**
      * Sets the 'multi-path' indicator.
      */
-    public void setMultipathIndicator(byte value) {
+    public void setMultipathIndicator(@MultipathIndicator byte value) {
         mMultipathIndicator = value;
     }
 
@@ -1157,6 +1176,34 @@
         mUsedInFix = value;
     }
 
+    /**
+     * Gets pseudorange rate (based on carrier phase changes) at the timestamp in m/s.
+     */
+    public double getPseudorangeRateCarrierInMetersPerSec() {
+        return mPseudorangeRateCarrierInMetersPerSec;
+    }
+
+    /**
+     * Sets pseudorange rate (based on carrier phase changes) at the timestamp in m/s.
+     */
+    public void setPseudorangeRateCarrierInMetersPerSec(double value) {
+        mPseudorangeRateCarrierInMetersPerSec = value;
+    }
+
+    /**
+     * Gets 1-Sigma uncertainty of the pseudorange rate carrier.
+     */
+    public double getPseudorangeRateCarrierUncertaintyInMetersPerSec() {
+        return mPseudorangeRateCarrierUncertaintyInMetersPerSec;
+    }
+
+    /**
+     * Sets 1-Sigma uncertainty of the pseudorange rate carrier.
+     */
+    public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double value) {
+        mPseudorangeRateCarrierUncertaintyInMetersPerSec = value;
+    }
+
     public static final Creator<GpsMeasurement> CREATOR = new Creator<GpsMeasurement>() {
         @Override
         public GpsMeasurement createFromParcel(Parcel parcel) {
@@ -1194,6 +1241,8 @@
             gpsMeasurement.mAzimuthInDeg = parcel.readDouble();
             gpsMeasurement.mAzimuthUncertaintyInDeg = parcel.readDouble();
             gpsMeasurement.mUsedInFix = parcel.readInt() != 0;
+            gpsMeasurement.mPseudorangeRateCarrierInMetersPerSec = parcel.readDouble();
+            gpsMeasurement.mPseudorangeRateCarrierUncertaintyInMetersPerSec = parcel.readDouble();
 
             return gpsMeasurement;
         }
@@ -1237,6 +1286,8 @@
         parcel.writeDouble(mAzimuthInDeg);
         parcel.writeDouble(mAzimuthUncertaintyInDeg);
         parcel.writeInt(mUsedInFix ? 1 : 0);
+        parcel.writeDouble(mPseudorangeRateCarrierInMetersPerSec);
+        parcel.writeDouble(mPseudorangeRateCarrierUncertaintyInMetersPerSec);
     }
 
     @Override
@@ -1361,6 +1412,11 @@
 
         builder.append(String.format(format, "UsedInFix", mUsedInFix));
 
+        builder.append(String.format(format, "PseudorangeRateCarrierInMetersPerSec",
+                    mPseudorangeRateCarrierInMetersPerSec));
+        builder.append(String.format(format, "PseudorangeRateCarrierUncertaintyInMetersPerSec",
+                    mPseudorangeRateCarrierUncertaintyInMetersPerSec));
+
         return builder.toString();
     }
 
@@ -1397,6 +1453,8 @@
         resetAzimuthInDeg();
         resetAzimuthUncertaintyInDeg();
         setUsedInFix(false);
+        setPseudorangeRateCarrierInMetersPerSec(Double.MIN_VALUE);
+        setPseudorangeRateCarrierUncertaintyInMetersPerSec(Double.MIN_VALUE);
     }
 
     private void setFlag(int flag) {
diff --git a/location/java/android/location/GpsMeasurementCallbackTransport.java b/location/java/android/location/GpsMeasurementCallbackTransport.java
new file mode 100644
index 0000000..02d9026
--- /dev/null
+++ b/location/java/android/location/GpsMeasurementCallbackTransport.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.location;
+
+import android.content.Context;
+import android.os.RemoteException;
+
+/**
+ * A handler class to manage transport callbacks for {@link GpsMeasurementsEvent.Callback}.
+ *
+ * @hide
+ */
+class GpsMeasurementCallbackTransport
+        extends LocalListenerHelper<GpsMeasurementsEvent.Callback> {
+    private final ILocationManager mLocationManager;
+
+    private final IGpsMeasurementsListener mListenerTransport = new ListenerTransport();
+
+    public GpsMeasurementCallbackTransport(Context context, ILocationManager locationManager) {
+        super(context, "GpsMeasurementListenerTransport");
+        mLocationManager = locationManager;
+    }
+
+    @Override
+    protected boolean registerWithServer() throws RemoteException {
+        return mLocationManager.addGpsMeasurementsListener(
+                mListenerTransport,
+                getContext().getPackageName());
+    }
+
+    @Override
+    protected void unregisterFromServer() throws RemoteException {
+        mLocationManager.removeGpsMeasurementsListener(mListenerTransport);
+    }
+
+    private class ListenerTransport extends IGpsMeasurementsListener.Stub {
+        @Override
+        public void onGpsMeasurementsReceived(final GpsMeasurementsEvent event) {
+            ListenerOperation<GpsMeasurementsEvent.Callback> operation =
+                    new ListenerOperation<GpsMeasurementsEvent.Callback>() {
+                @Override
+                public void execute(GpsMeasurementsEvent.Callback callback) throws RemoteException {
+                    callback.onGpsMeasurementsReceived(event);
+                }
+            };
+            foreach(operation);
+        }
+
+        @Override
+        public void onStatusChanged(final int status) {
+            ListenerOperation<GpsMeasurementsEvent.Callback> operation =
+                    new ListenerOperation<GpsMeasurementsEvent.Callback>() {
+                @Override
+                public void execute(GpsMeasurementsEvent.Callback callback) throws RemoteException {
+                    callback.onStatusChanged(status);
+                }
+            };
+            foreach(operation);
+        }
+    }
+}
diff --git a/location/java/android/location/GpsMeasurementListenerTransport.java b/location/java/android/location/GpsMeasurementListenerTransport.java
deleted file mode 100644
index 610da96..0000000
--- a/location/java/android/location/GpsMeasurementListenerTransport.java
+++ /dev/null
@@ -1,75 +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.location;
-
-import android.content.Context;
-import android.os.RemoteException;
-
-/**
- * A handler class to manage transport listeners for {@link GpsMeasurementsEvent.Listener}.
- *
- * @hide
- */
-class GpsMeasurementListenerTransport
-        extends LocalListenerHelper<GpsMeasurementsEvent.Listener> {
-    private final ILocationManager mLocationManager;
-
-    private final IGpsMeasurementsListener mListenerTransport = new ListenerTransport();
-
-    public GpsMeasurementListenerTransport(Context context, ILocationManager locationManager) {
-        super(context, "GpsMeasurementListenerTransport");
-        mLocationManager = locationManager;
-    }
-
-    @Override
-    protected boolean registerWithServer() throws RemoteException {
-        return mLocationManager.addGpsMeasurementsListener(
-                mListenerTransport,
-                getContext().getPackageName());
-    }
-
-    @Override
-    protected void unregisterFromServer() throws RemoteException {
-        mLocationManager.removeGpsMeasurementsListener(mListenerTransport);
-    }
-
-    private class ListenerTransport extends IGpsMeasurementsListener.Stub {
-        @Override
-        public void onGpsMeasurementsReceived(final GpsMeasurementsEvent event) {
-            ListenerOperation<GpsMeasurementsEvent.Listener> operation =
-                    new ListenerOperation<GpsMeasurementsEvent.Listener>() {
-                @Override
-                public void execute(GpsMeasurementsEvent.Listener listener) throws RemoteException {
-                    listener.onGpsMeasurementsReceived(event);
-                }
-            };
-            foreach(operation);
-        }
-
-        @Override
-        public void onStatusChanged(final int status) {
-            ListenerOperation<GpsMeasurementsEvent.Listener> operation =
-                    new ListenerOperation<GpsMeasurementsEvent.Listener>() {
-                @Override
-                public void execute(GpsMeasurementsEvent.Listener listener) throws RemoteException {
-                    listener.onStatusChanged(status);
-                }
-            };
-            foreach(operation);
-        }
-    }
-}
diff --git a/location/java/android/location/GpsMeasurementsEvent.java b/location/java/android/location/GpsMeasurementsEvent.java
index 1366873..ef9edeb 100644
--- a/location/java/android/location/GpsMeasurementsEvent.java
+++ b/location/java/android/location/GpsMeasurementsEvent.java
@@ -16,11 +16,13 @@
 
 package android.location;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.security.InvalidParameterException;
 import java.util.Arrays;
 import java.util.Collection;
@@ -28,12 +30,13 @@
 
 /**
  * A class implementing a container for data associated with a measurement event.
- * Events are delivered to registered instances of {@link Listener}.
- *
- * @hide
+ * Events are delivered to registered instances of {@link Callback}.
  */
-@SystemApi
-public class GpsMeasurementsEvent implements Parcelable {
+public final class GpsMeasurementsEvent implements Parcelable {
+    /** The status of GPS measurements event. */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_GPS_LOCATION_DISABLED})
+    public @interface GpsMeasurementsStatus {}
 
     /**
      * The system does not support tracking of GPS Measurements. This status will not change in the
@@ -58,22 +61,20 @@
     /**
      * Used for receiving GPS satellite measurements from the GPS engine.
      * Each measurement contains raw and computed data identifying a satellite.
-     * You can implement this interface and call {@link LocationManager#addGpsMeasurementListener}.
-     *
-     * @hide
+     * You can implement this interface and call
+     * {@link LocationManager#registerGpsMeasurementCallback}.
      */
-    @SystemApi
-    public interface Listener {
+    public static abstract class Callback {
 
         /**
          * Returns the latest collected GPS Measurements.
          */
-        void onGpsMeasurementsReceived(GpsMeasurementsEvent eventArgs);
+        public void onGpsMeasurementsReceived(GpsMeasurementsEvent eventArgs) {}
 
         /**
          * Returns the latest status of the GPS Measurements sub-system.
          */
-        void onStatusChanged(int status);
+        public void onStatusChanged(@GpsMeasurementsStatus int status) {}
     }
 
     public GpsMeasurementsEvent(GpsClock clock, GpsMeasurement[] measurements) {
diff --git a/location/java/android/location/GpsNavigationMessage.java b/location/java/android/location/GpsNavigationMessage.java
index 5c3c710..d799572 100644
--- a/location/java/android/location/GpsNavigationMessage.java
+++ b/location/java/android/location/GpsNavigationMessage.java
@@ -16,49 +16,54 @@
 
 package android.location;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.security.InvalidParameterException;
 
 /**
  * A class containing a GPS satellite Navigation Message.
- *
- * @hide
  */
-@SystemApi
-public class GpsNavigationMessage implements Parcelable {
+public final class GpsNavigationMessage implements Parcelable {
 
     private static final byte[] EMPTY_ARRAY = new byte[0];
 
+    /** The type of the GPS Clock. */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({MESSAGE_TYPE_UNKNOWN, MESSAGE_TYPE_L1CA, MESSAGE_TYPE_L2CNAV, MESSAGE_TYPE_L5CNAV,
+            MESSAGE_TYPE_CNAV2})
+    public @interface GpsNavigationMessageType {}
+
     // The following enumerations must be in sync with the values declared in gps.h
 
     /**
      * The type of the navigation message is not available or unknown.
      */
-    public static final byte TYPE_UNKNOWN = 0;
+    public static final byte MESSAGE_TYPE_UNKNOWN = 0;
 
     /**
      * The Navigation Message is of type L1 C/A.
      */
-    public static final byte TYPE_L1CA = 1;
+    public static final byte MESSAGE_TYPE_L1CA = 1;
 
     /**
      * The Navigation Message is of type L1-CNAV.
      */
-    public static final byte TYPE_L2CNAV = 2;
+    public static final byte MESSAGE_TYPE_L2CNAV = 2;
 
     /**
      * The Navigation Message is of type L5-CNAV.
      */
-    public static final byte TYPE_L5CNAV = 3;
+    public static final byte MESSAGE_TYPE_L5CNAV = 3;
 
     /**
      * The Navigation Message is of type CNAV-2.
      */
-    public static final byte TYPE_CNAV2 = 4;
+    public static final byte MESSAGE_TYPE_CNAV2 = 4;
 
     /**
      * The Navigation Message Status is 'unknown'.
@@ -111,6 +116,7 @@
     /**
      * Gets the type of the navigation message contained in the object.
      */
+    @GpsNavigationMessageType
     public byte getType() {
         return mType;
     }
@@ -118,7 +124,7 @@
     /**
      * Sets the type of the navigation message.
      */
-    public void setType(byte value) {
+    public void setType(@GpsNavigationMessageType byte value) {
         mType = value;
     }
 
@@ -128,15 +134,15 @@
      */
     private String getTypeString() {
         switch (mType) {
-            case TYPE_UNKNOWN:
+            case MESSAGE_TYPE_UNKNOWN:
                 return "Unknown";
-            case TYPE_L1CA:
+            case MESSAGE_TYPE_L1CA:
                 return "L1 C/A";
-            case TYPE_L2CNAV:
+            case MESSAGE_TYPE_L2CNAV:
                 return "L2-CNAV";
-            case TYPE_L5CNAV:
+            case MESSAGE_TYPE_L5CNAV:
                 return "L5-CNAV";
-            case TYPE_CNAV2:
+            case MESSAGE_TYPE_CNAV2:
                 return "CNAV-2";
             default:
                 return "<Invalid:" + mType + ">";
@@ -314,7 +320,7 @@
     }
 
     private void initialize() {
-        mType = TYPE_UNKNOWN;
+        mType = MESSAGE_TYPE_UNKNOWN;
         mPrn = 0;
         mMessageId = -1;
         mSubmessageId = -1;
diff --git a/location/java/android/location/GpsNavigationMessageCallbackTransport.java b/location/java/android/location/GpsNavigationMessageCallbackTransport.java
new file mode 100644
index 0000000..155d96d
--- /dev/null
+++ b/location/java/android/location/GpsNavigationMessageCallbackTransport.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.location;
+
+import android.content.Context;
+import android.os.RemoteException;
+
+/**
+ * A handler class to manage transport callback for {@link GpsNavigationMessageEvent.Callback}.
+ *
+ * @hide
+ */
+class GpsNavigationMessageCallbackTransport
+        extends LocalListenerHelper<GpsNavigationMessageEvent.Callback> {
+    private final ILocationManager mLocationManager;
+
+    private final IGpsNavigationMessageListener mListenerTransport = new ListenerTransport();
+
+    public GpsNavigationMessageCallbackTransport(
+            Context context,
+            ILocationManager locationManager) {
+        super(context, "GpsNavigationMessageCallbackTransport");
+        mLocationManager = locationManager;
+    }
+
+    @Override
+    protected boolean registerWithServer() throws RemoteException {
+        return mLocationManager.addGpsNavigationMessageListener(
+                mListenerTransport,
+                getContext().getPackageName());
+    }
+
+    @Override
+    protected void unregisterFromServer() throws RemoteException {
+        mLocationManager.removeGpsNavigationMessageListener(mListenerTransport);
+    }
+
+    private class ListenerTransport extends IGpsNavigationMessageListener.Stub {
+        @Override
+        public void onGpsNavigationMessageReceived(final GpsNavigationMessageEvent event) {
+            ListenerOperation<GpsNavigationMessageEvent.Callback> operation =
+                    new ListenerOperation<GpsNavigationMessageEvent.Callback>() {
+                @Override
+                public void execute(GpsNavigationMessageEvent.Callback callback)
+                        throws RemoteException {
+                    callback.onGpsNavigationMessageReceived(event);
+                }
+            };
+            foreach(operation);
+        }
+
+        @Override
+        public void onStatusChanged(final int status) {
+            ListenerOperation<GpsNavigationMessageEvent.Callback> operation =
+                    new ListenerOperation<GpsNavigationMessageEvent.Callback>() {
+                @Override
+                public void execute(GpsNavigationMessageEvent.Callback callback)
+                        throws RemoteException {
+                    callback.onStatusChanged(status);
+                }
+            };
+            foreach(operation);
+        }
+    }
+}
diff --git a/location/java/android/location/GpsNavigationMessageEvent.java b/location/java/android/location/GpsNavigationMessageEvent.java
index bd6921c..b16a485 100644
--- a/location/java/android/location/GpsNavigationMessageEvent.java
+++ b/location/java/android/location/GpsNavigationMessageEvent.java
@@ -16,60 +16,60 @@
 
 package android.location;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.security.InvalidParameterException;
 
 /**
  * A class implementing a container for data associated with a navigation message event.
- * Events are delivered to registered instances of {@link Listener}.
- *
- * @hide
+ * Events are delivered to registered instances of {@link Callback}.
  */
-@SystemApi
-public class GpsNavigationMessageEvent implements Parcelable {
+public final class GpsNavigationMessageEvent implements Parcelable {
+    /** The status of GPS measurements event. */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_GPS_LOCATION_DISABLED})
+    public @interface GpsNavigationMessageStatus {}
 
     /**
      * The system does not support tracking of GPS Navigation Messages. This status will not change
      * in the future.
      */
-    public static int STATUS_NOT_SUPPORTED = 0;
+    public static final int STATUS_NOT_SUPPORTED = 0;
 
     /**
      * GPS Navigation Messages are successfully being tracked, it will receive updates once they are
      * available.
      */
-    public static int STATUS_READY = 1;
+    public static final int STATUS_READY = 1;
 
     /**
      * GPS provider or Location is disabled, updated will not be received until they are enabled.
      */
-    public static int STATUS_GPS_LOCATION_DISABLED = 2;
+    public static final int STATUS_GPS_LOCATION_DISABLED = 2;
 
     private final GpsNavigationMessage mNavigationMessage;
 
     /**
      * Used for receiving GPS satellite Navigation Messages from the GPS engine.
      * You can implement this interface and call
-     * {@link LocationManager#addGpsNavigationMessageListener}.
-     *
-     * @hide
+     * {@link LocationManager#registerGpsNavigationMessageCallback}.
      */
-    @SystemApi
-    public interface Listener {
+    public static abstract class Callback {
 
         /**
          * Returns the latest collected GPS Navigation Message.
          */
-        void onGpsNavigationMessageReceived(GpsNavigationMessageEvent event);
+        public void onGpsNavigationMessageReceived(GpsNavigationMessageEvent event) {}
 
         /**
          * Returns the latest status of the GPS Navigation Messages sub-system.
          */
-        void onStatusChanged(int status);
+        public void onStatusChanged(@GpsNavigationMessageStatus int status) {}
     }
 
     public GpsNavigationMessageEvent(GpsNavigationMessage message) {
diff --git a/location/java/android/location/GpsNavigationMessageListenerTransport.java b/location/java/android/location/GpsNavigationMessageListenerTransport.java
deleted file mode 100644
index f6ba407..0000000
--- a/location/java/android/location/GpsNavigationMessageListenerTransport.java
+++ /dev/null
@@ -1,79 +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.location;
-
-import android.content.Context;
-import android.os.RemoteException;
-
-/**
- * A handler class to manage transport listeners for {@link GpsNavigationMessageEvent.Listener}.
- *
- * @hide
- */
-class GpsNavigationMessageListenerTransport
-        extends LocalListenerHelper<GpsNavigationMessageEvent.Listener> {
-    private final ILocationManager mLocationManager;
-
-    private final IGpsNavigationMessageListener mListenerTransport = new ListenerTransport();
-
-    public GpsNavigationMessageListenerTransport(
-            Context context,
-            ILocationManager locationManager) {
-        super(context, "GpsNavigationMessageListenerTransport");
-        mLocationManager = locationManager;
-    }
-
-    @Override
-    protected boolean registerWithServer() throws RemoteException {
-        return mLocationManager.addGpsNavigationMessageListener(
-                mListenerTransport,
-                getContext().getPackageName());
-    }
-
-    @Override
-    protected void unregisterFromServer() throws RemoteException {
-        mLocationManager.removeGpsNavigationMessageListener(mListenerTransport);
-    }
-
-    private class ListenerTransport extends IGpsNavigationMessageListener.Stub {
-        @Override
-        public void onGpsNavigationMessageReceived(final GpsNavigationMessageEvent event) {
-            ListenerOperation<GpsNavigationMessageEvent.Listener> operation =
-                    new ListenerOperation<GpsNavigationMessageEvent.Listener>() {
-                @Override
-                public void execute(GpsNavigationMessageEvent.Listener listener)
-                        throws RemoteException {
-                    listener.onGpsNavigationMessageReceived(event);
-                }
-            };
-            foreach(operation);
-        }
-
-        @Override
-        public void onStatusChanged(final int status) {
-            ListenerOperation<GpsNavigationMessageEvent.Listener> operation =
-                    new ListenerOperation<GpsNavigationMessageEvent.Listener>() {
-                @Override
-                public void execute(GpsNavigationMessageEvent.Listener listener)
-                        throws RemoteException {
-                    listener.onStatusChanged(status);
-                }
-            };
-            foreach(operation);
-        }
-    }
-}
diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java
index 323f326..8d2f781 100644
--- a/location/java/android/location/GpsStatus.java
+++ b/location/java/android/location/GpsStatus.java
@@ -34,17 +34,15 @@
     private final SparseArray<GpsSatellite> mSatellites = new SparseArray<>();
 
     private final class SatelliteIterator implements Iterator<GpsSatellite> {
-
-        private final SparseArray<GpsSatellite> mSatellites;
         private final int mSatellitesCount;
 
         private int mIndex = 0;
 
-        SatelliteIterator(SparseArray<GpsSatellite> satellites) {
-            mSatellites = satellites;
-            mSatellitesCount = satellites.size();
+        SatelliteIterator() {
+            mSatellitesCount = mSatellites.size();
         }
 
+        @Override
         public boolean hasNext() {
             for (; mIndex < mSatellitesCount; ++mIndex) {
                 GpsSatellite satellite = mSatellites.valueAt(mIndex);
@@ -55,6 +53,7 @@
             return false;
         }
 
+        @Override
         public GpsSatellite next() {
             while (mIndex < mSatellitesCount) {
                 GpsSatellite satellite = mSatellites.valueAt(mIndex);
@@ -66,14 +65,16 @@
             throw new NoSuchElementException();
         }
 
+        @Override
         public void remove() {
             throw new UnsupportedOperationException();
         }
     }
 
     private Iterable<GpsSatellite> mSatelliteList = new Iterable<GpsSatellite>() {
+        @Override
         public Iterator<GpsSatellite> iterator() {
-            return new SatelliteIterator(mSatellites);
+            return new SatelliteIterator();
         }
     };
 
@@ -137,18 +138,15 @@
     // For API-compat a public ctor() is not available
     GpsStatus() {}
 
-    /**
-     * Used internally within {@link LocationManager} to copy GPS status
-     * data from the Location Manager Service to its cached GpsStatus instance.
-     * Is synchronized to ensure that GPS status updates are atomic.
-     */
-    synchronized void setStatus(int svCount, int[] prns, float[] snrs,
-            float[] elevations, float[] azimuths, int ephemerisMask,
-            int almanacMask, int usedInFixMask) {
+    private void setStatus(int svCount, int[] prnWithFlags, float[] snrs, float[] elevations,
+            float[] azimuths, int[] constellationTypes) { 
         clearSatellites();
         for (int i = 0; i < svCount; i++) {
-            int prn = prns[i];
-            int prnShift = (1 << (prn - 1));
+            // Skip all non-GPS satellites.
+            if (constellationTypes[i] != GnssStatus.CONSTELLATION_GPS) {
+                continue;
+            }
+            int prn = prnWithFlags[i] >> GnssStatus.PRN_SHIFT_WIDTH;
             if (prn > 0 && prn <= NUM_SATELLITES) {
                 GpsSatellite satellite = mSatellites.get(prn);
                 if (satellite == null) {
@@ -160,53 +158,26 @@
                 satellite.mSnr = snrs[i];
                 satellite.mElevation = elevations[i];
                 satellite.mAzimuth = azimuths[i];
-                satellite.mHasEphemeris = ((ephemerisMask & prnShift) != 0);
-                satellite.mHasAlmanac = ((almanacMask & prnShift) != 0);
-                satellite.mUsedInFix = ((usedInFixMask & prnShift) != 0);
+                satellite.mHasEphemeris =
+                        (prnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) != 0;
+                satellite.mHasAlmanac =
+                        (prnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) != 0;
+                satellite.mUsedInFix =
+                        (prnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0;
             }
         }
     }
 
     /**
-     * Used by {@link LocationManager#getGpsStatus} to copy LocationManager's
-     * cached GpsStatus instance to the client's copy.
+     * Copies GPS satellites information from GnssStatus object.
      * Since this method is only used within {@link LocationManager#getGpsStatus},
      * it does not need to be synchronized.
+     * @hide
      */
-    void setStatus(GpsStatus status) {
-        mTimeToFirstFix = status.getTimeToFirstFix();
-        clearSatellites();
-
-        SparseArray<GpsSatellite> otherSatellites = status.mSatellites;
-        int otherSatellitesCount = otherSatellites.size();
-        int satelliteIndex = 0;
-        // merge both sparse arrays, note that we have already invalidated the elements in the
-        // receiver array
-        for (int i = 0; i < otherSatellitesCount; ++i) {
-            GpsSatellite otherSatellite = otherSatellites.valueAt(i);
-            int otherSatellitePrn = otherSatellite.getPrn();
-
-            int satellitesCount = mSatellites.size();
-            while (satelliteIndex < satellitesCount
-                    && mSatellites.valueAt(satelliteIndex).getPrn() < otherSatellitePrn) {
-                ++satelliteIndex;
-            }
-
-            if (satelliteIndex < mSatellites.size()) {
-                GpsSatellite satellite = mSatellites.valueAt(satelliteIndex);
-                if (satellite.getPrn() == otherSatellitePrn) {
-                    satellite.setStatus(otherSatellite);
-                } else {
-                    satellite = new GpsSatellite(otherSatellitePrn);
-                    satellite.setStatus(otherSatellite);
-                    mSatellites.put(otherSatellitePrn, satellite);
-                }
-            } else {
-                GpsSatellite satellite = new GpsSatellite(otherSatellitePrn);
-                satellite.setStatus(otherSatellite);
-                mSatellites.append(otherSatellitePrn, satellite);
-            }
-        }
+    void setStatus(GnssStatus status, int timeToFirstFix) {
+        mTimeToFirstFix = timeToFirstFix;
+        setStatus(status.mSvCount, status.mPrnWithFlags, status.mSnrs, status.mElevations,
+                status.mAzimuths, status.mConstellationTypes);
     }
 
     void setTimeToFirstFix(int ttff) {
diff --git a/location/java/android/location/IGnssStatusListener.aidl b/location/java/android/location/IGnssStatusListener.aidl
new file mode 100644
index 0000000..d1c6a85
--- /dev/null
+++ b/location/java/android/location/IGnssStatusListener.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.location;
+
+import android.location.Location;
+
+/**
+ * {@hide}
+ */
+oneway interface IGnssStatusListener
+{
+    void onGnssStarted();
+    void onGnssStopped();
+    void onFirstFix(int ttff);
+    void onSvStatusChanged(int svCount, in int[] prnWithFlags, in float[] snrs,
+            in float[] elevations, in float[] azimuths, in int[] constellationTypes);
+    void onNmeaReceived(long timestamp, String nmea);
+}
diff --git a/location/java/android/location/IGnssStatusProvider.aidl b/location/java/android/location/IGnssStatusProvider.aidl
new file mode 100644
index 0000000..006b5d3
--- /dev/null
+++ b/location/java/android/location/IGnssStatusProvider.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location;
+
+import android.location.IGnssStatusListener;
+
+/**
+ * An interface for location providers that provide GNSS status information.
+ *
+ * {@hide}
+ */
+interface IGnssStatusProvider {
+    void registerGnssStatusCallback(IGnssStatusListener callback);
+    void unregisterGnssStatusCallback(IGnssStatusListener callback);
+}
diff --git a/location/java/android/location/IGpsStatusListener.aidl b/location/java/android/location/IGpsStatusListener.aidl
deleted file mode 100644
index 62b1c6b..0000000
--- a/location/java/android/location/IGpsStatusListener.aidl
+++ /dev/null
@@ -1,33 +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.location;
-
-import android.location.Location;
-
-/**
- * {@hide}
- */
-oneway interface IGpsStatusListener
-{
-    void onGpsStarted();
-    void onGpsStopped();
-    void onFirstFix(int ttff);
-    void onSvStatusChanged(int svCount, in int[] prns, in float[] snrs, 
-            in float[] elevations, in float[] azimuths, 
-            int ephemerisMask, int almanacMask, int usedInFixMask);
-    void onNmeaReceived(long timestamp, String nmea);
-}
diff --git a/location/java/android/location/IGpsStatusProvider.aidl b/location/java/android/location/IGpsStatusProvider.aidl
deleted file mode 100644
index cf277c8..0000000
--- a/location/java/android/location/IGpsStatusProvider.aidl
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.location;
-
-import android.location.IGpsStatusListener;
-
-/**
- * An interface for location providers that provide GPS status information.
- *
- * {@hide}
- */
-interface IGpsStatusProvider {
-    void addGpsStatusListener(IGpsStatusListener listener);
-    void removeGpsStatusListener(IGpsStatusListener listener);
-}
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index f3d755c..49d841f 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -21,9 +21,9 @@
 import android.location.Criteria;
 import android.location.GeocoderParams;
 import android.location.Geofence;
+import android.location.IGnssStatusListener;
 import android.location.IGpsMeasurementsListener;
 import android.location.IGpsNavigationMessageListener;
-import android.location.IGpsStatusListener;
 import android.location.ILocationListener;
 import android.location.Location;
 import android.location.LocationRequest;
@@ -48,8 +48,8 @@
 
     Location getLastLocation(in LocationRequest request, String packageName);
 
-    boolean addGpsStatusListener(IGpsStatusListener listener, String packageName);
-    void removeGpsStatusListener(IGpsStatusListener listener);
+    boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName);
+    void unregisterGnssStatusCallback(IGnssStatusListener callback);
 
     boolean geocoderIsPresent();
     String getFromLocation(double latitude, double longitude, int maxResults,
@@ -69,6 +69,8 @@
             in String packageName);
     void removeGpsNavigationMessageListener(in IGpsNavigationMessageListener listener);
 
+    int getGpsYearOfHardware();
+
     // --- deprecated ---
     List<String> getAllProviders();
     List<String> getProviders(in Criteria criteria, boolean enabledOnly);
diff --git a/location/java/android/location/LocalListenerHelper.java b/location/java/android/location/LocalListenerHelper.java
index 458c451..d7d2c513 100644
--- a/location/java/android/location/LocalListenerHelper.java
+++ b/location/java/android/location/LocalListenerHelper.java
@@ -20,12 +20,14 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.os.Handler;
 import android.os.RemoteException;
 import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashSet;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * A base handler class to manage transport and local listeners.
@@ -33,7 +35,7 @@
  * @hide
  */
 abstract class LocalListenerHelper<TListener> {
-    private final HashSet<TListener> mListeners = new HashSet<>();
+    private final HashMap<TListener, Handler> mListeners = new HashMap<>();
 
     private final String mTag;
     private final Context mContext;
@@ -44,7 +46,7 @@
         mTag = name;
     }
 
-    public boolean add(@NonNull TListener listener) {
+    public boolean add(@NonNull TListener listener, Handler handler) {
         Preconditions.checkNotNull(listener);
         synchronized (mListeners) {
             // we need to register with the service first, because we need to find out if the
@@ -62,17 +64,19 @@
                     return false;
                 }
             }
-            if (mListeners.contains(listener)) {
+            if (mListeners.containsKey(listener)) {
                 return true;
             }
-            return mListeners.add(listener);
+            mListeners.put(listener, handler);
+            return true;
         }
     }
 
     public void remove(@NonNull TListener listener) {
         Preconditions.checkNotNull(listener);
         synchronized (mListeners) {
-            boolean removed = mListeners.remove(listener);
+            boolean removed = mListeners.containsKey(listener);
+            mListeners.remove(listener);
             boolean isLastRemoved = removed && mListeners.isEmpty();
             if (isLastRemoved) {
                 try {
@@ -95,17 +99,30 @@
         return mContext;
     }
 
-    protected void foreach(ListenerOperation<TListener> operation) {
-        Collection<TListener> listeners;
-        synchronized (mListeners) {
-            listeners = new ArrayList<>(mListeners);
+    private void executeOperation(ListenerOperation<TListener> operation, TListener listener) {
+        try {
+            operation.execute(listener);
+        } catch (RemoteException e) {
+            Log.e(mTag, "Error in monitored listener.", e);
+            // don't return, give a fair chance to all listeners to receive the event
         }
-        for (TListener listener : listeners) {
-            try {
-                operation.execute(listener);
-            } catch (RemoteException e) {
-                Log.e(mTag, "Error in monitored listener.", e);
-                // don't return, give a fair chance to all listeners to receive the event
+    }
+
+    protected void foreach(final ListenerOperation<TListener> operation) {
+        Collection<Map.Entry<TListener, Handler>> listeners;
+        synchronized (mListeners) {
+            listeners = new ArrayList<>(mListeners.entrySet());
+        }
+        for (final Map.Entry<TListener, Handler> listener : listeners) {
+            if (listener.getValue() == null) {
+                executeOperation(operation, listener.getKey());
+            } else {
+                listener.getValue().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        executeOperation(operation, listener.getKey());
+                    }
+                });
             }
         }
     }
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 2c19324..5447bb1 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -20,6 +20,7 @@
 
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
@@ -63,13 +64,18 @@
 
     private final Context mContext;
     private final ILocationManager mService;
-    private final GpsMeasurementListenerTransport mGpsMeasurementListenerTransport;
-    private final GpsNavigationMessageListenerTransport mGpsNavigationMessageListenerTransport;
-    private final HashMap<GpsStatus.Listener, GpsStatusListenerTransport> mGpsStatusListeners =
-            new HashMap<GpsStatus.Listener, GpsStatusListenerTransport>();
-    private final HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport> mNmeaListeners =
-            new HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport>();
-    private final GpsStatus mGpsStatus = new GpsStatus();
+    private final GpsMeasurementCallbackTransport mGpsMeasurementCallbackTransport;
+    private final GpsNavigationMessageCallbackTransport mGpsNavigationMessageCallbackTransport;
+    private final HashMap<GpsStatus.Listener, GnssStatusListenerTransport> mGpsStatusListeners =
+            new HashMap<>();
+    private final HashMap<GpsStatus.NmeaListener, GnssStatusListenerTransport> mGpsNmeaListeners =
+            new HashMap<>();
+    private final HashMap<GnssStatusCallback, GnssStatusListenerTransport> mGnssStatusListeners =
+            new HashMap<>();
+    private final HashMap<GnssNmeaListener, GnssStatusListenerTransport> mGnssNmeaListeners =
+            new HashMap<>();
+    private GnssStatus mGnssStatus;
+    private int mTimeToFirstFix;
 
     /**
      * Name of the network location provider.
@@ -315,9 +321,9 @@
     public LocationManager(Context context, ILocationManager service) {
         mService = service;
         mContext = context;
-        mGpsMeasurementListenerTransport = new GpsMeasurementListenerTransport(mContext, mService);
-        mGpsNavigationMessageListenerTransport =
-                new GpsNavigationMessageListenerTransport(mContext, mService);
+        mGpsMeasurementCallbackTransport = new GpsMeasurementCallbackTransport(mContext, mService);
+        mGpsNavigationMessageCallbackTransport =
+                new GpsNavigationMessageCallbackTransport(mContext, mService);
     }
 
     private LocationProvider createProvider(String name, ProviderProperties properties) {
@@ -1389,11 +1395,51 @@
 
     // --- GPS-specific support ---
 
-    // This class is used to send GPS status events to the client's main thread.
-    private class GpsStatusListenerTransport extends IGpsStatusListener.Stub {
+    // This class is used to send Gnss status events to the client's specific thread.
+    private class GnssStatusListenerTransport extends IGnssStatusListener.Stub {
 
-        private final GpsStatus.Listener mListener;
-        private final GpsStatus.NmeaListener mNmeaListener;
+        private final GpsStatus.Listener mGpsListener;
+        private final GpsStatus.NmeaListener mGpsNmeaListener;
+        private final GnssStatusCallback mGnssCallback;
+        private final GnssNmeaListener mGnssNmeaListener;
+
+        private class GnssHandler extends Handler {
+            public GnssHandler(Handler handler) {
+                super(handler != null ? handler.getLooper() : Looper.myLooper());
+            }
+
+            @Override
+            public void handleMessage(Message msg) {
+                switch (msg.what) {
+                    case NMEA_RECEIVED:
+                        synchronized (mNmeaBuffer) {
+                            int length = mNmeaBuffer.size();
+                            for (int i = 0; i < length; i++) {
+                                Nmea nmea = mNmeaBuffer.get(i);
+                                mGnssNmeaListener.onNmeaReceived(nmea.mTimestamp, nmea.mNmea);
+                            }
+                            mNmeaBuffer.clear();
+                        }
+                        break;
+                    case GpsStatus.GPS_EVENT_STARTED:
+                        mGnssCallback.onStarted();
+                        break;
+                    case GpsStatus.GPS_EVENT_STOPPED:
+                        mGnssCallback.onStopped();
+                        break;
+                    case GpsStatus.GPS_EVENT_FIRST_FIX:
+                        mGnssCallback.onFirstFix(mTimeToFirstFix);
+                        break;
+                    case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
+                        mGnssCallback.onSatelliteStatusChanged(mGnssStatus);
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+
+        private final Handler mGnssHandler;
 
         // This must not equal any of the GpsStatus event IDs
         private static final int NMEA_RECEIVED = 1000;
@@ -1407,97 +1453,141 @@
                 mNmea = nmea;
             }
         }
-        private ArrayList<Nmea> mNmeaBuffer;
+        private final ArrayList<Nmea> mNmeaBuffer;
 
-        GpsStatusListenerTransport(GpsStatus.Listener listener) {
-            mListener = listener;
-            mNmeaListener = null;
+        GnssStatusListenerTransport(GpsStatus.Listener listener) {
+            this(listener, null);
         }
 
-        GpsStatusListenerTransport(GpsStatus.NmeaListener listener) {
-            mNmeaListener = listener;
-            mListener = null;
+        GnssStatusListenerTransport(GpsStatus.Listener listener, Handler handler) {
+            mGpsListener = listener;
+            mGnssHandler = new GnssHandler(handler);
+            mGpsNmeaListener = null;
+            mNmeaBuffer = null;
+            mGnssCallback = new GnssStatusCallback() {
+                @Override
+                public void onStarted() {
+                    mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_STARTED);
+                }
+
+                @Override
+                public void onStopped() {
+                    mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_STOPPED);
+                }
+
+                @Override
+                public void onFirstFix(int ttff) {
+                    mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_FIRST_FIX);
+                }
+
+                @Override
+                public void onSatelliteStatusChanged(GnssStatus status) {
+                    mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
+                }
+            };
+            mGnssNmeaListener = null;
+        }
+
+        GnssStatusListenerTransport(GpsStatus.NmeaListener listener) {
+            this(listener, null);
+        }
+
+        GnssStatusListenerTransport(GpsStatus.NmeaListener listener, Handler handler) {
+            mGpsListener = null;
+            mGnssHandler = new GnssHandler(handler);
+            mGpsNmeaListener = listener;
+            mNmeaBuffer = new ArrayList<Nmea>();
+            mGnssCallback = null;
+            mGnssNmeaListener = new GnssNmeaListener() {
+                @Override
+                public void onNmeaReceived(long timestamp, String nmea) {
+                    mGpsNmeaListener.onNmeaReceived(timestamp, nmea);
+                }
+            };
+        }
+
+        GnssStatusListenerTransport(GnssStatusCallback callback) {
+            this(callback, null);
+        }
+
+        GnssStatusListenerTransport(GnssStatusCallback callback, Handler handler) {
+            mGnssCallback = callback;
+            mGnssHandler = new GnssHandler(handler);
+            mGnssNmeaListener = null;
+            mNmeaBuffer = null;
+            mGpsListener = null;
+            mGpsNmeaListener = null;
+        }
+
+        GnssStatusListenerTransport(GnssNmeaListener listener) {
+            this(listener, null);
+        }
+
+        GnssStatusListenerTransport(GnssNmeaListener listener, Handler handler) {
+            mGnssCallback = null;
+            mGnssHandler = new GnssHandler(handler);
+            mGnssNmeaListener = listener;
+            mGpsListener = null;
+            mGpsNmeaListener = null;
             mNmeaBuffer = new ArrayList<Nmea>();
         }
 
         @Override
-        public void onGpsStarted() {
-            if (mListener != null) {
+        public void onGnssStarted() {
+            if (mGpsListener != null) {
                 Message msg = Message.obtain();
                 msg.what = GpsStatus.GPS_EVENT_STARTED;
-                mGpsHandler.sendMessage(msg);
+                mGnssHandler.sendMessage(msg);
             }
         }
 
         @Override
-        public void onGpsStopped() {
-            if (mListener != null) {
+        public void onGnssStopped() {
+            if (mGpsListener != null) {
                 Message msg = Message.obtain();
                 msg.what = GpsStatus.GPS_EVENT_STOPPED;
-                mGpsHandler.sendMessage(msg);
+                mGnssHandler.sendMessage(msg);
             }
         }
 
         @Override
         public void onFirstFix(int ttff) {
-            if (mListener != null) {
-                mGpsStatus.setTimeToFirstFix(ttff);
+            if (mGpsListener != null) {
+                mTimeToFirstFix = ttff;
                 Message msg = Message.obtain();
                 msg.what = GpsStatus.GPS_EVENT_FIRST_FIX;
-                mGpsHandler.sendMessage(msg);
+                mGnssHandler.sendMessage(msg);
             }
         }
 
         @Override
-        public void onSvStatusChanged(int svCount, int[] prns, float[] snrs,
-                float[] elevations, float[] azimuths, int ephemerisMask,
-                int almanacMask, int usedInFixMask) {
-            if (mListener != null) {
-                mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths,
-                        ephemerisMask, almanacMask, usedInFixMask);
+        public void onSvStatusChanged(int svCount, int[] prnWithFlags,
+                float[] snrs, float[] elevations, float[] azimuths, int[] constellationTypes) {
+            if (mGnssCallback != null) {
+                mGnssStatus = new GnssStatus(svCount, prnWithFlags, snrs, elevations, azimuths,
+                        constellationTypes);
 
                 Message msg = Message.obtain();
                 msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
                 // remove any SV status messages already in the queue
-                mGpsHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
-                mGpsHandler.sendMessage(msg);
+                mGnssHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
+                mGnssHandler.sendMessage(msg);
             }
         }
 
         @Override
         public void onNmeaReceived(long timestamp, String nmea) {
-            if (mNmeaListener != null) {
+            if (mGnssNmeaListener != null) {
                 synchronized (mNmeaBuffer) {
                     mNmeaBuffer.add(new Nmea(timestamp, nmea));
                 }
                 Message msg = Message.obtain();
                 msg.what = NMEA_RECEIVED;
                 // remove any NMEA_RECEIVED messages already in the queue
-                mGpsHandler.removeMessages(NMEA_RECEIVED);
-                mGpsHandler.sendMessage(msg);
+                mGnssHandler.removeMessages(NMEA_RECEIVED);
+                mGnssHandler.sendMessage(msg);
             }
         }
-
-        private final Handler mGpsHandler = new Handler() {
-            @Override
-            public void handleMessage(Message msg) {
-                if (msg.what == NMEA_RECEIVED) {
-                    synchronized (mNmeaBuffer) {
-                        int length = mNmeaBuffer.size();
-                        for (int i = 0; i < length; i++) {
-                            Nmea nmea = mNmeaBuffer.get(i);
-                            mNmeaListener.onNmeaReceived(nmea.mTimestamp, nmea.mNmea);
-                        }
-                        mNmeaBuffer.clear();
-                    }
-                } else {
-                    // synchronize on mGpsStatus to ensure the data is copied atomically.
-                    synchronized(mGpsStatus) {
-                        mListener.onGpsStatusChanged(msg.what);
-                    }
-                }
-            }
-        };
     }
 
     /**
@@ -1508,7 +1598,9 @@
      * @return true if the listener was successfully added
      *
      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
+     * @deprecated use {@link #registerGnssStatusCallback(GnssStatusCallback)} instead.
      */
+    @Deprecated
     @RequiresPermission(ACCESS_FINE_LOCATION)
     public boolean addGpsStatusListener(GpsStatus.Listener listener) {
         boolean result;
@@ -1518,8 +1610,8 @@
             return true;
         }
         try {
-            GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
-            result = mService.addGpsStatusListener(transport, mContext.getPackageName());
+            GnssStatusListenerTransport transport = new GnssStatusListenerTransport(listener);
+            result = mService.registerGnssStatusCallback(transport, mContext.getPackageName());
             if (result) {
                 mGpsStatusListeners.put(listener, transport);
             }
@@ -1536,17 +1628,81 @@
      *
      * @param listener GPS status listener object to remove
      */
+    @Deprecated
     public void removeGpsStatusListener(GpsStatus.Listener listener) {
         try {
-            GpsStatusListenerTransport transport = mGpsStatusListeners.remove(listener);
+            GnssStatusListenerTransport transport = mGpsStatusListeners.remove(listener);
             if (transport != null) {
-                mService.removeGpsStatusListener(transport);
+                mService.unregisterGnssStatusCallback(transport);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e);
         }
     }
 
+
+    /**
+     * Registers a GNSS status listener.
+     *
+     * @param callback GNSS status listener object to register
+     *
+     * @return true if the listener was successfully added
+     *
+     * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
+     */
+    @RequiresPermission(ACCESS_FINE_LOCATION)
+    public boolean registerGnssStatusCallback(GnssStatusCallback callback) {
+        return registerGnssStatusCallback(callback, null);
+    }
+
+    /**
+     * Registers a GNSS status listener.
+     *
+     * @param callback GNSS status listener object to register
+     * @param handler the handler that the callback runs on.
+     *
+     * @return true if the listener was successfully added
+     *
+     * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
+     */
+    @RequiresPermission(ACCESS_FINE_LOCATION)
+    public boolean registerGnssStatusCallback(GnssStatusCallback callback, Handler handler) {
+        boolean result;
+        if (mGnssStatusListeners.get(callback) != null) {
+            // listener is already registered
+            return true;
+        }
+        try {
+            GnssStatusListenerTransport transport =
+                    new GnssStatusListenerTransport(callback, handler);
+            result = mService.registerGnssStatusCallback(transport, mContext.getPackageName());
+            if (result) {
+                mGnssStatusListeners.put(callback, transport);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in registerGnssStatusCallback: ", e);
+            result = false;
+        }
+
+        return result;
+    }
+
+    /**
+     * Removes a GNSS status listener.
+     *
+     * @param callback GNSS status listener object to remove
+     */
+    public void unregisterGnssStatusCallback(GnssStatusCallback callback) {
+        try {
+            GnssStatusListenerTransport transport = mGnssStatusListeners.remove(callback);
+            if (transport != null) {
+                mService.unregisterGnssStatusCallback(transport);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in unregisterGnssStatusCallback: ", e);
+        }
+    }
+
     /**
      * Adds an NMEA listener.
      *
@@ -1555,20 +1711,22 @@
      * @return true if the listener was successfully added
      *
      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
+     * @deprecated use {@link #addNmeaListener(GnssNmeaListener)} instead.
      */
+    @Deprecated
     @RequiresPermission(ACCESS_FINE_LOCATION)
     public boolean addNmeaListener(GpsStatus.NmeaListener listener) {
         boolean result;
 
-        if (mNmeaListeners.get(listener) != null) {
+        if (mGpsNmeaListeners.get(listener) != null) {
             // listener is already registered
             return true;
         }
         try {
-            GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
-            result = mService.addGpsStatusListener(transport, mContext.getPackageName());
+            GnssStatusListenerTransport transport = new GnssStatusListenerTransport(listener);
+            result = mService.registerGnssStatusCallback(transport, mContext.getPackageName());
             if (result) {
-                mNmeaListeners.put(listener, transport);
+                mGpsNmeaListeners.put(listener, transport);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e);
@@ -1583,11 +1741,12 @@
      *
      * @param listener a {@link GpsStatus.NmeaListener} object to remove
      */
+    @Deprecated
     public void removeNmeaListener(GpsStatus.NmeaListener listener) {
         try {
-            GpsStatusListenerTransport transport = mNmeaListeners.remove(listener);
+            GnssStatusListenerTransport transport = mGpsNmeaListeners.remove(listener);
             if (transport != null) {
-                mService.removeGpsStatusListener(transport);
+                mService.unregisterGnssStatusCallback(transport);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e);
@@ -1595,54 +1754,133 @@
     }
 
     /**
-     * Adds a GPS Measurement listener.
+     * Adds an NMEA listener.
      *
-     * @param listener a {@link GpsMeasurementsEvent.Listener} object to register.
-     * @return {@code true} if the listener was added successfully, {@code false} otherwise.
+     * @param listener a {@link GnssNmeaListener} object to register
      *
-     * @hide
+     * @return true if the listener was successfully added
+     *
+     * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
      */
-    @SystemApi
-    public boolean addGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {
-        return mGpsMeasurementListenerTransport.add(listener);
+    @RequiresPermission(ACCESS_FINE_LOCATION)
+    public boolean addNmeaListener(GnssNmeaListener listener) {
+        return addNmeaListener(listener, null);
     }
 
     /**
-     * Removes a GPS Measurement listener.
+     * Adds an NMEA listener.
      *
-     * @param listener a {@link GpsMeasurementsEvent.Listener} object to remove.
+     * @param listener a {@link GnssNmeaListener} object to register
+     * @param handler the handler that the listener runs on.
      *
-     * @hide
+     * @return true if the listener was successfully added
+     *
+     * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
      */
-    @SystemApi
-    public void removeGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {
-        mGpsMeasurementListenerTransport.remove(listener);
+    @RequiresPermission(ACCESS_FINE_LOCATION)
+    public boolean addNmeaListener(GnssNmeaListener listener, Handler handler) {
+        boolean result;
+
+        if (mGpsNmeaListeners.get(listener) != null) {
+            // listener is already registered
+            return true;
+        }
+        try {
+            GnssStatusListenerTransport transport =
+                    new GnssStatusListenerTransport(listener, handler);
+            result = mService.registerGnssStatusCallback(transport, mContext.getPackageName());
+            if (result) {
+                mGnssNmeaListeners.put(listener, transport);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in registerGnssStatusCallback: ", e);
+            result = false;
+        }
+
+        return result;
     }
 
     /**
-     * Adds a GPS Navigation Message listener.
+     * Removes an NMEA listener.
      *
-     * @param listener a {@link GpsNavigationMessageEvent.Listener} object to register.
-     * @return {@code true} if the listener was added successfully, {@code false} otherwise.
-     *
-     * @hide
+     * @param listener a {@link GnssNmeaListener} object to remove
      */
-    @SystemApi
-    public boolean addGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) {
-        return mGpsNavigationMessageListenerTransport.add(listener);
+    public void removeNmeaListener(GnssNmeaListener listener) {
+        try {
+            GnssStatusListenerTransport transport = mGnssNmeaListeners.remove(listener);
+            if (transport != null) {
+                mService.unregisterGnssStatusCallback(transport);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in unregisterGnssStatusCallback: ", e);
+        }
     }
 
     /**
-     * Removes a GPS Navigation Message listener.
+     * Registers a GPS Measurement callback.
      *
-     * @param listener a {@link GpsNavigationMessageEvent.Listener} object to remove.
-     *
-     * @hide
+     * @param callback a {@link GpsMeasurementsEvent.Callback} object to register.
+     * @return {@code true} if the callback was added successfully, {@code false} otherwise.
      */
-    @SystemApi
-    public void removeGpsNavigationMessageListener(
-            GpsNavigationMessageEvent.Listener listener) {
-        mGpsNavigationMessageListenerTransport.remove(listener);
+    @RequiresPermission(ACCESS_FINE_LOCATION)
+    public boolean registerGpsMeasurementCallback(GpsMeasurementsEvent.Callback callback) {
+        return registerGpsMeasurementCallback(callback, null);
+    }
+
+    /**
+     * Registers a GPS Measurement callback.
+     *
+     * @param callback a {@link GpsMeasurementsEvent.Callback} object to register.
+     * @param handler the handler that the callback runs on.
+     * @return {@code true} if the callback was added successfully, {@code false} otherwise.
+     */
+    @RequiresPermission(ACCESS_FINE_LOCATION)
+    public boolean registerGpsMeasurementCallback(GpsMeasurementsEvent.Callback callback,
+            Handler handler) {
+        return mGpsMeasurementCallbackTransport.add(callback, handler);
+    }
+
+    /**
+     * Unregisters a GPS Measurement callback.
+     *
+     * @param callback a {@link GpsMeasurementsEvent.Callback} object to remove.
+     */
+    public void unregisterGpsMeasurementCallback(GpsMeasurementsEvent.Callback callback) {
+        mGpsMeasurementCallbackTransport.remove(callback);
+    }
+
+    /**
+     * Registers a GPS Navigation Message callback.
+     *
+     * @param callback a {@link GpsNavigationMessageEvent.Callback} object to register.
+     * @return {@code true} if the callback was added successfully, {@code false} otherwise.
+     */
+    public boolean registerGpsNavigationMessageCallback(
+            GpsNavigationMessageEvent.Callback callback) {
+        return registerGpsNavigationMessageCallback(callback, null);
+    }
+
+    /**
+     * Registers a GPS Navigation Message callback.
+     *
+     * @param callback a {@link GpsNavigationMessageEvent.Callback} object to register.
+     * @param handler the handler that the callback runs on.
+     * @return {@code true} if the callback was added successfully, {@code false} otherwise.
+     */
+    @RequiresPermission(ACCESS_FINE_LOCATION)
+    public boolean registerGpsNavigationMessageCallback(
+            GpsNavigationMessageEvent.Callback callback, Handler handler) {
+        return mGpsNavigationMessageCallbackTransport.add(callback, handler);
+    }
+
+    /**
+     * Unregisters a GPS Navigation Message callback.
+     *
+     * @param callback a {@link GpsNavigationMessageEvent.Callback} object to remove.
+     */
+    public void unregisterGpsNavigationMessageCallback(
+            GpsNavigationMessageEvent.Callback callback) {
+        mGpsNavigationMessageCallbackTransport.remove(callback);
     }
 
      /**
@@ -1656,15 +1894,36 @@
      * @param status object containing GPS status details, or null.
      * @return status object containing updated GPS status.
      */
+    @Deprecated
+    @RequiresPermission(ACCESS_FINE_LOCATION)
     public GpsStatus getGpsStatus(GpsStatus status) {
         if (status == null) {
             status = new GpsStatus();
         }
-        status.setStatus(mGpsStatus);
+        // When mGnssStatus is null, that means that this method is called outside
+        // onGpsStatusChanged().  Return an empty status  to maintain backwards compatibility.
+        if (mGnssStatus != null) {
+            status.setStatus(mGnssStatus, mTimeToFirstFix);
+        }
         return status;
     }
 
     /**
+     * Returns the system information of the GPS hardware.
+     * May return 0 if GPS hardware is earlier than 2016.
+     * @hide
+     */
+    @TestApi
+    public int getGpsYearOfHardware() {
+        try {
+            return mService.getGpsYearOfHardware();
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in getGpsSystemInfo: ", e);
+            return 0;
+        }
+    }
+
+    /**
      * Sends additional commands to a location provider.
      * Can be used to support provider specific extensions to the Location Manager API
      *
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index 260f380..93e86af 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -62,7 +62,7 @@
     public static final String NI_INTENT_KEY_TIMEOUT = "timeout";
     public static final String NI_INTENT_KEY_DEFAULT_RESPONSE = "default_resp";
 
-    // the extra command to send NI response to GpsLocationProvider
+    // the extra command to send NI response to GnssLocationProvider
     public static final String NI_RESPONSE_EXTRA_CMD = "send_ni_response";
 
     // the extra command parameter names in the Bundle
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index e92f294..c194711 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -223,10 +223,18 @@
     @SystemApi
     public final static int FLAG_BYPASS_MUTE = 0x1 << 7;
 
+    /**
+     * Flag requesting a low latency path.
+     * When using this flag, the sample rate must match the native sample rate
+     * of the device. Effects processing is also unavailable.
+     */
+    public final static int FLAG_LOW_LATENCY = 0x1 << 8;
+
     private final static int FLAG_ALL = FLAG_AUDIBILITY_ENFORCED | FLAG_SECURE | FLAG_SCO |
             FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD | FLAG_BYPASS_INTERRUPTION_POLICY |
-            FLAG_BYPASS_MUTE;
-    private final static int FLAG_ALL_PUBLIC = FLAG_AUDIBILITY_ENFORCED | FLAG_HW_AV_SYNC;
+            FLAG_BYPASS_MUTE | FLAG_LOW_LATENCY;
+    private final static int FLAG_ALL_PUBLIC = FLAG_AUDIBILITY_ENFORCED |
+            FLAG_HW_AV_SYNC | FLAG_LOW_LATENCY;
 
     private int mUsage = USAGE_UNKNOWN;
     private int mContentType = CONTENT_TYPE_UNKNOWN;
@@ -433,7 +441,8 @@
 
         /**
          * Sets the combination of flags.
-         * @param flags the {@link AudioAttributes#FLAG_AUDIBILITY_ENFORCED} flag.
+         * @param flags a combination of {@link AudioAttributes#FLAG_AUDIBILITY_ENFORCED},
+         *    {@link AudioAttributes#FLAG_HW_AV_SYNC}.
          * @return the same Builder instance.
          */
         public Builder setFlags(int flags) {
@@ -520,8 +529,9 @@
          * instance with {@link AudioRecord#AudioRecord(AudioAttributes, AudioFormat, int)}.
          * @param preset one of {@link MediaRecorder.AudioSource#DEFAULT},
          *     {@link MediaRecorder.AudioSource#MIC}, {@link MediaRecorder.AudioSource#CAMCORDER},
-         *     {@link MediaRecorder.AudioSource#VOICE_RECOGNITION} or
-         *     {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION}.
+         *     {@link MediaRecorder.AudioSource#VOICE_RECOGNITION},
+         *     {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION} or
+         *     {@link MediaRecorder.AudioSource#UNPROCESSED}
          * @return the same Builder instance.
          */
         @SystemApi
@@ -532,6 +542,7 @@
                 case MediaRecorder.AudioSource.CAMCORDER:
                 case MediaRecorder.AudioSource.VOICE_RECOGNITION:
                 case MediaRecorder.AudioSource.VOICE_COMMUNICATION:
+                case MediaRecorder.AudioSource.UNPROCESSED:
                     mSource = preset;
                     break;
                 default:
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index bde3d19..000a56d 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -251,6 +251,10 @@
      * @hide
      * */
     public static final int ENCODING_AAC_HE_V2 = 12;
+    /** Audio data format: compressed audio wrapped in PCM for HDMI
+     * or S/PDIF passthrough.
+     */
+    public static final int ENCODING_IEC61937 = 13;
 
     /** Invalid audio channel configuration */
     /** @deprecated Use {@link #CHANNEL_INVALID} instead.  */
@@ -418,6 +422,7 @@
         case ENCODING_PCM_8BIT:
             return 1;
         case ENCODING_PCM_16BIT:
+        case ENCODING_IEC61937:
         case ENCODING_DEFAULT:
             return 2;
         case ENCODING_PCM_FLOAT:
@@ -443,6 +448,7 @@
         case ENCODING_AAC_LC:
         case ENCODING_AAC_HE_V1:
         case ENCODING_AAC_HE_V2:
+        case ENCODING_IEC61937:
             return true;
         default:
             return false;
@@ -460,6 +466,7 @@
         case ENCODING_E_AC3:
         case ENCODING_DTS:
         case ENCODING_DTS_HD:
+        case ENCODING_IEC61937:
             return true;
         default:
             return false;
@@ -483,6 +490,7 @@
         case ENCODING_AAC_LC:
         case ENCODING_AAC_HE_V1:
         case ENCODING_AAC_HE_V2:
+        case ENCODING_IEC61937: // wrapped in PCM but compressed
             return false;
         case ENCODING_INVALID:
         default:
@@ -490,6 +498,30 @@
         }
     }
 
+    /** @hide */
+    public static boolean isEncodingLinearFrames(int audioFormat)
+    {
+        switch (audioFormat) {
+        case ENCODING_PCM_8BIT:
+        case ENCODING_PCM_16BIT:
+        case ENCODING_PCM_FLOAT:
+        case ENCODING_IEC61937: // same size as stereo PCM
+        case ENCODING_DEFAULT:
+            return true;
+        case ENCODING_AC3:
+        case ENCODING_E_AC3:
+        case ENCODING_DTS:
+        case ENCODING_DTS_HD:
+        case ENCODING_MP3:
+        case ENCODING_AAC_LC:
+        case ENCODING_AAC_HE_V1:
+        case ENCODING_AAC_HE_V2:
+            return false;
+        case ENCODING_INVALID:
+        default:
+            throw new IllegalArgumentException("Bad audio format " + audioFormat);
+        }
+    }
     /**
      * Returns an array of public encoding values extracted from an array of
      * encoding values.
@@ -715,6 +747,7 @@
                 case ENCODING_E_AC3:
                 case ENCODING_DTS:
                 case ENCODING_DTS_HD:
+                case ENCODING_IEC61937:
                     mEncoding = encoding;
                     break;
                 case ENCODING_INVALID:
@@ -859,7 +892,8 @@
         ENCODING_AC3,
         ENCODING_E_AC3,
         ENCODING_DTS,
-        ENCODING_DTS_HD
+        ENCODING_DTS_HD,
+        ENCODING_IEC61937
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Encoding {}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index c658675..dc534be 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -51,6 +51,7 @@
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 
 /**
  * AudioManager provides access to volume and ringer mode control.
@@ -176,6 +177,16 @@
         "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
@@ -254,6 +265,13 @@
         "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
@@ -880,6 +898,17 @@
         }
     }
 
+    /** @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);
+        }
+    }
+
     /**
      * Returns the current ringtone mode.
      *
@@ -1142,6 +1171,21 @@
     }
 
     /**
+     * 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;
+        }
+    }
+
+    /**
      * forces the stream controlled by hard volume keys
      * specifying streamType == -1 releases control to the
      * logic.
@@ -2115,36 +2159,59 @@
     }
 
     /**
-     * Handler for audio focus events coming from the audio service.
+     * Handler for events (audio focus change, recording config change) coming from the
+     * audio service.
      */
-    private final FocusEventHandlerDelegate mAudioFocusEventHandlerDelegate =
-            new FocusEventHandlerDelegate();
+    private final ServiceEventHandlerDelegate mServiceEventHandlerDelegate =
+            new ServiceEventHandlerDelegate(null);
 
     /**
-     * Helper class to handle the forwarding of audio focus events to the appropriate listener
+     * Event types
      */
-    private class FocusEventHandlerDelegate {
+    private final static int MSSG_FOCUS_CHANGE = 0;
+    private final static int MSSG_RECORDING_CONFIG_CHANGE = 1;
+
+    /**
+     * Helper class to handle the forwarding of audio service events to the appropriate listener
+     */
+    private class ServiceEventHandlerDelegate {
         private final Handler mHandler;
 
-        FocusEventHandlerDelegate() {
+        ServiceEventHandlerDelegate(Handler handler) {
             Looper looper;
-            if ((looper = Looper.myLooper()) == null) {
-                looper = Looper.getMainLooper();
+            if (handler == null) {
+                if ((looper = Looper.myLooper()) == null) {
+                    looper = Looper.getMainLooper();
+                }
+            } else {
+                looper = handler.getLooper();
             }
 
             if (looper != null) {
-                // implement the event handler delegate to receive audio focus events
+                // implement the event handler delegate to receive events from audio service
                 mHandler = new Handler(looper) {
                     @Override
                     public void handleMessage(Message msg) {
-                        OnAudioFocusChangeListener listener = null;
-                        synchronized(mFocusListenerLock) {
-                            listener = findFocusListener((String)msg.obj);
-                        }
-                        if (listener != null) {
-                            Log.d(TAG, "AudioManager dispatching onAudioFocusChange("
-                                    + msg.what + ") for " + msg.obj);
-                            listener.onAudioFocusChange(msg.what);
+                        switch (msg.what) {
+                            case MSSG_FOCUS_CHANGE:
+                                OnAudioFocusChangeListener listener = null;
+                                synchronized(mFocusListenerLock) {
+                                    listener = findFocusListener((String)msg.obj);
+                                }
+                                if (listener != null) {
+                                    Log.d(TAG, "AudioManager dispatching onAudioFocusChange("
+                                            + msg.what + ") for " + msg.obj);
+                                    listener.onAudioFocusChange(msg.arg1);
+                                }
+                                break;
+                            case MSSG_RECORDING_CONFIG_CHANGE:
+                                final AudioRecordingCallback cb = (AudioRecordingCallback) msg.obj;
+                                if (cb != null) {
+                                    cb.onRecordConfigChanged();
+                                }
+                                break;
+                            default:
+                                Log.e(TAG, "Unknown event " + msg.what);
                         }
                     }
                 };
@@ -2161,8 +2228,9 @@
     private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
 
         public void dispatchAudioFocusChange(int focusChange, String id) {
-            Message m = mAudioFocusEventHandlerDelegate.getHandler().obtainMessage(focusChange, id);
-            mAudioFocusEventHandlerDelegate.getHandler().sendMessage(m);
+            final Message m = mServiceEventHandlerDelegate.getHandler().obtainMessage(
+                    MSSG_FOCUS_CHANGE/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/, id/*obj*/);
+            mServiceEventHandlerDelegate.getHandler().sendMessage(m);
         }
 
     };
@@ -2659,6 +2727,8 @@
     }
 
 
+    //====================================================================
+    // Audio policy
     /**
      * @hide
      * Register the given {@link AudioPolicy}.
@@ -2711,6 +2781,186 @@
     }
 
 
+    //====================================================================
+    // Recording configuration
+    /**
+     * Interface for receiving update notifications about the recording configuration. Extend
+     * this abstract class and register it with
+     * {@link AudioManager#registerAudioRecordingCallback(AudioRecordingCallback, Handler)}
+     * to be notified.
+     * Use {@link AudioManager#getActiveRecordConfigurations()} to query the current configuration.
+     */
+    public static abstract class AudioRecordingCallback {
+        /**
+         * Called whenever the device recording configuration has changed.
+         */
+        public void onRecordConfigChanged() {}
+    }
+
+    private static class AudioRecordingCallbackInfo {
+        final AudioRecordingCallback mCb;
+        final Handler mHandler;
+        AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler) {
+            mCb = cb;
+            mHandler = handler;
+        }
+    }
+
+    /**
+     * Register a callback to be notified of audio recording changes through
+     * {@link AudioRecordingCallback}
+     * @param cb non-null callback to register
+     * @param handler the {@link Handler} object for the thread on which to execute
+     * the callback. If <code>null</code>, the {@link Handler} associated with the main
+     * {@link Looper} will be used.
+     */
+    public void registerAudioRecordingCallback(@NonNull AudioRecordingCallback cb, Handler handler)
+    {
+        if (cb == null) {
+            throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
+        }
+
+        synchronized(mRecordCallbackLock) {
+            // lazy initialization of the list of recording callbacks
+            if (mRecordCallbackList == null) {
+                mRecordCallbackList = new ArrayList<AudioRecordingCallbackInfo>();
+            }
+            final int oldCbCount = mRecordCallbackList.size();
+            if (!hasRecordCallback_sync(cb)) {
+                mRecordCallbackList.add(new AudioRecordingCallbackInfo(cb,
+                        new ServiceEventHandlerDelegate(handler).getHandler()));
+                final int newCbCount = mRecordCallbackList.size();
+                if ((oldCbCount == 0) && (newCbCount > 0)) {
+                    // register binder for callbacks
+                    final IAudioService service = getService();
+                    try {
+                        service.registerRecordingCallback(mRecCb);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Dead object in registerRecordingCallback", e);
+                    }
+                }
+            } else {
+                Log.w(TAG, "attempt to call registerAudioRecordingCallback() on a previously"
+                        + "registered callback");
+            }
+        }
+    }
+
+    /**
+     * Unregister an audio recording callback previously registered with
+     * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
+     * @param cb non-null callback to unregister
+     */
+    public void unregisterAudioRecordingCallback(@NonNull AudioRecordingCallback cb) {
+        if (cb == null) {
+            throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
+        }
+        synchronized(mRecordCallbackLock) {
+            if (mRecordCallbackList == null) {
+                return;
+            }
+            final int oldCbCount = mRecordCallbackList.size();
+            if (removeRecordCallback_sync(cb)) {
+                final int newCbCount = mRecordCallbackList.size();
+                if ((oldCbCount > 0) && (newCbCount == 0)) {
+                    // unregister binder for callbacks
+                    final IAudioService service = getService();
+                    try {
+                        service.unregisterRecordingCallback(mRecCb);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Dead object in unregisterRecordingCallback", e);
+                    }
+                }
+            } else {
+                Log.w(TAG, "attempt to call unregisterAudioRecordingCallback() on a callback"
+                        + " already unregistered or never registered");
+            }
+        }
+    }
+
+    /**
+     * Returns the current active audio recording configurations of the device.
+     * @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() {
+        final IAudioService service = getService();
+        try {
+            return service.getActiveRecordConfigurations();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to retrieve active record configurations", e);
+            return null;
+        }
+    }
+
+    /**
+     * constants for the recording events, to keep in sync
+     * with frameworks/av/include/media/AudioPolicy.h
+     */
+    /** @hide */
+    public final static int RECORD_CONFIG_EVENT_START = 1;
+    /** @hide */
+    public final static int RECORD_CONFIG_EVENT_STOP = 0;
+
+    /**
+     * All operations on this list are sync'd on mRecordCallbackLock.
+     * List is lazy-initialized in
+     * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
+     * List can be null.
+     */
+    private List<AudioRecordingCallbackInfo> mRecordCallbackList;
+    private final Object mRecordCallbackLock = new Object();
+
+    /**
+     * Must be called synchronized on mRecordCallbackLock
+     */
+    private boolean hasRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
+        if (mRecordCallbackList != null) {
+            for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
+                if (cb.equals(mRecordCallbackList.get(i).mCb)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Must be called synchronized on mRecordCallbackLock
+     */
+    private boolean removeRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
+        if (mRecordCallbackList != null) {
+            for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
+                if (cb.equals(mRecordCallbackList.get(i).mCb)) {
+                    mRecordCallbackList.remove(i);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() {
+
+        public void dispatchRecordingConfigChange() {
+            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*/);
+                            arci.mHandler.sendMessage(m);
+                        }
+                    }
+                }
+            }
+        }
+
+    };
+
+    //=====================================================================
+
     /**
      *  @hide
      *  Reload audio settings. This method is called by Settings backup
@@ -3096,12 +3346,19 @@
             "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND";
 
     /**
+     * Used as a key for {@link #getProperty} to determine if the unprocessed audio source is
+     * available and supported with the expected frequency range and level response.
+     */
+    public static final String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED =
+            "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED";
+    /**
      * Returns the value of the property with the specified key.
      * @param key One of the strings corresponding to a property key: either
      *            {@link #PROPERTY_OUTPUT_SAMPLE_RATE},
      *            {@link #PROPERTY_OUTPUT_FRAMES_PER_BUFFER},
-     *            {@link #PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND}, or
-     *            {@link #PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND}.
+     *            {@link #PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND},
+     *            {@link #PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND}, or
+     *            {@link #PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED}.
      * @return A string representing the associated value for that property key,
      *         or null if there is no value for that key.
      */
@@ -3120,6 +3377,9 @@
         } else if (PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND.equals(key)) {
             return String.valueOf(getContext().getResources().getBoolean(
                     com.android.internal.R.bool.config_supportSpeakerNearUltrasound));
+        } else if (PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED.equals(key)) {
+            return String.valueOf(getContext().getResources().getBoolean(
+                    com.android.internal.R.bool.config_supportAudioSourceUnprocessed));
         } else {
             // null or unknown key
             return null;
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 974b62e..7c21893 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -51,7 +51,7 @@
  * been read yet. Data should be read from the audio hardware in chunks of sizes inferior to
  * the total recording buffer size.
  */
-public class AudioRecord
+public class AudioRecord implements AudioRouting
 {
     //---------------------------------------------------------
     // Constants
@@ -392,6 +392,20 @@
     }
 
     /**
+     * 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).
+     */
+    /*package*/ AudioRecord(long nativeRecordInJavaObj) {
+        mNativeRecorderInJavaObj = nativeRecordInJavaObj;
+
+        // other initialization here...
+
+        mState = STATE_INITIALIZED;
+    }
+
+    /**
      * Builder class for {@link AudioRecord} objects.
      * Use this class to configure and create an <code>AudioRecord</code> instance. By setting the
      * recording source and audio format parameters, you indicate which of
@@ -1221,23 +1235,6 @@
         return native_set_marker_pos(markerInFrames);
     }
 
-
-    //--------------------------------------------------------------------------
-    // (Re)Routing Info
-    //--------------------
-    /**
-     * Defines the interface by which applications can receive notifications of routing
-     * changes for the associated {@link AudioRecord}.
-     */
-    public interface OnRoutingChangedListener {
-        /**
-         * Called when the routing of an AudioRecord changes from either and explicit or
-         * policy rerouting. Use {@link #getRoutedDevice()} to retrieve the newly routed-from
-         * device.
-         */
-        public void onRoutingChanged(AudioRecord audioRecord);
-    }
-
     /**
      * Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioRecord.
      * Note: The query is only valid if the AudioRecord is currently recording. If it is not,
@@ -1258,6 +1255,89 @@
         return null;
     }
 
+    /*
+     * Call BEFORE adding a routing callback handler.
+     */
+    private void testEnableNativeRoutingCallbacks() {
+        if (mRoutingChangeListeners.size() == 0 && mNewRoutingChangeListeners.size() == 0) {
+            native_enableDeviceCallback();
+        }
+    }
+
+    /*
+     * Call AFTER removing a routing callback handler.
+     */
+    private void testDisableNativeRoutingCallbacks() {
+        if (mRoutingChangeListeners.size() == 0 && mNewRoutingChangeListeners.size() == 0) {
+            native_disableDeviceCallback();
+        }
+    }
+
+    //--------------------------------------------------------------------------
+    // >= "N" (Re)Routing Info
+    //--------------------
+    /**
+     * The list of AudioRouting.OnRoutingChangedListener interfaces added (with
+     * {@link AudioRecord#addOnRoutingListener(AudioRouting.OnRoutingChangedListener,
+     *      android.os.Handler)}
+     * by an app to receive (re)routing notifications.
+     */
+    private ArrayMap<AudioRouting.OnRoutingChangedListener, NativeNewRoutingEventHandlerDelegate>
+    mNewRoutingChangeListeners =
+        new ArrayMap<AudioRouting.OnRoutingChangedListener, NativeNewRoutingEventHandlerDelegate>();
+
+    /**
+     * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of
+     * routing changes on this AudioRecord.
+     * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
+     * notifications of rerouting events.
+     * @param handler  Specifies the {@link Handler} object for the thread on which to execute
+     * the callback. If <code>null</code>, the {@link Handler} associated with the main
+     * {@link Looper} will be used.
+     */
+    public void addOnRoutingListener(AudioRouting.OnRoutingChangedListener listener,
+            android.os.Handler handler) {
+        if (listener != null && !mNewRoutingChangeListeners.containsKey(listener)) {
+            synchronized (mNewRoutingChangeListeners) {
+                testEnableNativeRoutingCallbacks();
+                mNewRoutingChangeListeners.put(
+                    listener, new NativeNewRoutingEventHandlerDelegate(this, listener,
+                            handler != null ? handler : new Handler(mInitializationLooper)));
+            }
+        }
+    }
+
+    /**
+     * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added
+    * to receive rerouting notifications.
+    * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
+    * to remove.
+    */
+    public void removeOnRoutingListener(AudioRouting.OnRoutingChangedListener listener) {
+        synchronized (mNewRoutingChangeListeners) {
+            if (mNewRoutingChangeListeners.containsKey(listener)) {
+                mNewRoutingChangeListeners.remove(listener);
+                testDisableNativeRoutingCallbacks();
+            }
+        }
+    }
+
+    //--------------------------------------------------------------------------
+    // Marshmallow (Re)Routing Info
+    //--------------------
+    /**
+     * Defines the interface by which applications can receive notifications of routing
+     * changes for the associated {@link AudioRecord}.
+     */
+    public interface OnRoutingChangedListener {
+        /**
+         * Called when the routing of an AudioRecord changes from either and explicit or
+         * policy rerouting. Use {@link #getRoutedDevice()} to retrieve the newly routed-from
+         * device.
+         */
+        public void onRoutingChanged(AudioRecord audioRecord);
+    }
+
     /**
      * The list of AudioRecord.OnRoutingChangedListener interface added (with
      * {@link AudioRecord#addOnRoutingChangedListener(OnRoutingChangedListener,android.os.Handler)}
@@ -1276,13 +1356,12 @@
      * the callback. If <code>null</code>, the {@link Handler} associated with the main
      * {@link Looper} will be used.
      */
+    @Deprecated
     public void addOnRoutingChangedListener(OnRoutingChangedListener listener,
             android.os.Handler handler) {
         if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
             synchronized (mRoutingChangeListeners) {
-                if (mRoutingChangeListeners.size() == 0) {
-                    native_enableDeviceCallback();
-                }
+                testEnableNativeRoutingCallbacks();
                 mRoutingChangeListeners.put(
                     listener, new NativeRoutingEventHandlerDelegate(this, listener,
                             handler != null ? handler : new Handler(mInitializationLooper)));
@@ -1291,22 +1370,73 @@
     }
 
     /**
-     * Removes an {@link OnRoutingChangedListener} which has been previously added
+      * Removes an {@link OnRoutingChangedListener} which has been previously added
      * to receive rerouting notifications.
      * @param listener The previously added {@link OnRoutingChangedListener} interface to remove.
      */
+    @Deprecated
     public void removeOnRoutingChangedListener(OnRoutingChangedListener listener) {
         synchronized (mRoutingChangeListeners) {
             if (mRoutingChangeListeners.containsKey(listener)) {
                 mRoutingChangeListeners.remove(listener);
-                if (mRoutingChangeListeners.size() == 0) {
-                    native_disableDeviceCallback();
-                }
+                testDisableNativeRoutingCallbacks();
             }
         }
     }
 
     /**
+     * >= "N" Routing
+     * Helper class to handle the forwarding of native events to the appropriate listener
+     * (potentially) handled in a different thread
+     */
+    private class NativeNewRoutingEventHandlerDelegate {
+        private final Handler mHandler;
+
+        NativeNewRoutingEventHandlerDelegate(final AudioRecord record,
+                                   final AudioRouting.OnRoutingChangedListener listener,
+                                   Handler handler) {
+            // find the looper for our new event handler
+            Looper looper;
+            if (handler != null) {
+                looper = handler.getLooper();
+            } else {
+                // no given handler, use the looper the AudioRecord was created in
+                looper = mInitializationLooper;
+            }
+
+            // construct the event handler with this looper
+            if (looper != null) {
+                // implement the event handler delegate
+                mHandler = new Handler(looper) {
+                    @Override
+                    public void handleMessage(Message msg) {
+                        if (record == null) {
+                            return;
+                        }
+                        switch(msg.what) {
+                        case AudioSystem.NATIVE_EVENT_ROUTING_CHANGE:
+                            if (listener != null) {
+                                listener.onRoutingChanged(record);
+                            }
+                            break;
+                        default:
+                            loge("Unknown native event type: " + msg.what);
+                            break;
+                        }
+                    }
+                };
+            } else {
+                mHandler = null;
+            }
+        }
+
+        Handler getHandler() {
+            return mHandler;
+        }
+    }
+
+    /**
+     * Marshmallow Routing
      * Helper class to handle the forwarding of native events to the appropriate listener
      * (potentially) handled in a different thread
      */
@@ -1355,21 +1485,34 @@
             return mHandler;
         }
     }
+
     /**
      * Sends device list change notification to all listeners.
      */
     private void broadcastRoutingChange() {
+        AudioManager.resetAudioPortGeneration();
+        // Marshmallow Routing
         Collection<NativeRoutingEventHandlerDelegate> values;
         synchronized (mRoutingChangeListeners) {
             values = mRoutingChangeListeners.values();
         }
-        AudioManager.resetAudioPortGeneration();
         for(NativeRoutingEventHandlerDelegate delegate : values) {
             Handler handler = delegate.getHandler();
             if (handler != null) {
                 handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE);
             }
         }
+        // >= "N" Routing
+        Collection<NativeNewRoutingEventHandlerDelegate> newValues;
+        synchronized (mNewRoutingChangeListeners) {
+            newValues = mNewRoutingChangeListeners.values();
+        }
+        for(NativeNewRoutingEventHandlerDelegate delegate : newValues) {
+            Handler handler = delegate.getHandler();
+            if (handler != null) {
+                handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE);
+            }
+        }
     }
 
     /**
diff --git a/media/java/android/media/AudioRecordConfiguration.aidl b/media/java/android/media/AudioRecordConfiguration.aidl
new file mode 100644
index 0000000..afe912b
--- /dev/null
+++ b/media/java/android/media/AudioRecordConfiguration.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 AudioRecordConfiguration;
diff --git a/media/java/android/media/AudioRecordConfiguration.java b/media/java/android/media/AudioRecordConfiguration.java
new file mode 100644
index 0000000..69df88f
--- /dev/null
+++ b/media/java/android/media/AudioRecordConfiguration.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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/AudioRecordRoutingProxy.java b/media/java/android/media/AudioRecordRoutingProxy.java
new file mode 100644
index 0000000..b0c19e4
--- /dev/null
+++ b/media/java/android/media/AudioRecordRoutingProxy.java
@@ -0,0 +1,32 @@
+/*
+ * 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.media;
+
+/**
+ * An AudioRecord connected to a native (C/C++) which allows access only to routing methods.
+ */
+class AudioRecordRoutingProxy extends AudioRecord {
+    /**
+     * 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).
+     */
+    public AudioRecordRoutingProxy(long nativeRecordInJavaObj) {
+        super(nativeRecordInJavaObj);
+    }
+}
diff --git a/media/java/android/media/AudioRouting.java b/media/java/android/media/AudioRouting.java
new file mode 100644
index 0000000..2161cf3
--- /dev/null
+++ b/media/java/android/media/AudioRouting.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 android.media;
+
+import android.os.Handler;
+import android.os.Looper;
+
+/**
+ * AudioRouting defines an interface for controlling routing and routing notifications in
+ * AudioTrack and AudioRecord objects.
+ */
+public interface AudioRouting {
+    /**
+     * Specifies an audio device (via an {@link AudioDeviceInfo} object) to route
+     * the output/input to/from.
+     * @param deviceInfo The {@link AudioDeviceInfo} specifying the audio sink or source.
+     *  If deviceInfo is null, default routing is restored.
+     * @return true if succesful, false if the specified {@link AudioDeviceInfo} is non-null and
+     * does not correspond to a valid audio device.
+     */
+    public boolean setPreferredDevice(AudioDeviceInfo deviceInfo);
+
+    /**
+     * Returns the selected output/input specified by {@link #setPreferredDevice}. Note that this
+     * is not guaranteed to correspond to the actual device being used for playback/recording.
+     */
+    public AudioDeviceInfo getPreferredDevice();
+
+    /**
+     * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
+     * changes on this AudioTrack/AudioRecord.
+     * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
+     * notifications of rerouting events.
+     * @param handler  Specifies the {@link Handler} object for the thread on which to execute
+     * the callback. If <code>null</code>, the {@link Handler} associated with the main
+     * {@link Looper} will be used.
+     */
+    public void addOnRoutingListener(OnRoutingChangedListener listener,
+            Handler handler);
+
+    /**
+     * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added
+     * to receive rerouting notifications.
+     * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
+     * to remove.
+     */
+    public void removeOnRoutingListener(OnRoutingChangedListener listener);
+
+    /**
+     * Defines the interface by which applications can receive notifications of routing
+     * changes for the associated {@link AudioRouting}.
+     */
+    public interface OnRoutingChangedListener {
+        public void onRoutingChanged(AudioRouting router);
+    }
+}
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index c59d1c7..aa0d78d 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -227,7 +227,7 @@
     }
 
     /**
-     * Handles events for the audio policy manager about dynamic audio policies
+     * Handles events from the audio policy manager about dynamic audio policies
      * @see android.media.audiopolicy.AudioPolicy
      */
     public interface DynamicPolicyCallback
@@ -267,6 +267,33 @@
         }
     }
 
+    /**
+     * Handles events from the audio policy manager about recording events
+     * @see android.media.AudioManager.AudioRecordingCallback
+     */
+    public interface AudioRecordingCallback
+    {
+        void onRecordingConfigurationChanged(int event, int session, int source);
+    }
+
+    private static AudioRecordingCallback sRecordingCallback;
+
+    public static void setRecordingCallback(AudioRecordingCallback cb) {
+        synchronized (AudioSystem.class) {
+            sRecordingCallback = cb;
+            native_register_recording_callback();
+        }
+    }
+
+    private static void recordingCallbackFromNative(int event, int session, int source) {
+        AudioRecordingCallback cb = null;
+        synchronized (AudioSystem.class) {
+            cb = sRecordingCallback;
+        }
+        if (cb != null) {
+            cb.onRecordingConfigurationChanged(event, session, source);
+        }
+    }
 
     /*
      * Error codes used by public APIs (AudioTrack, AudioRecord, AudioManager ...)
@@ -624,6 +651,11 @@
     public static native boolean getMasterMute();
     public static native int getDevicesForStream(int stream);
 
+    /** @hide returns true if master mono is enabled. */
+    public static native boolean getMasterMono();
+    /** @hide enables or disables the master mono mode. */
+    public static native int setMasterMono(boolean mono);
+
     // helpers for android.media.AudioManager.getProperty(), see description there for meaning
     public static native int getPrimaryOutputSamplingRate();
     public static native int getPrimaryOutputFrameCount();
@@ -641,6 +673,8 @@
 
     // declare this instance as having a dynamic policy callback handler
     private static native final void native_register_dynamic_policy_callback();
+    // declare this instance as having a recording configuration update callback handler
+    private static native final void native_register_recording_callback();
 
     // must be kept in sync with value in include/system/audio.h
     public static final int AUDIO_HW_SYNC_INVALID = 0;
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index bb4f7d9..3007d86 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -42,7 +42,6 @@
 
 import com.android.internal.app.IAppOpsService;
 
-
 /**
  * The AudioTrack class manages and plays a single audio resource for Java applications.
  * It allows streaming of PCM audio buffers to the audio sink for playback. This is
@@ -78,7 +77,7 @@
  *
  * AudioTrack is not final and thus permits subclasses, but such use is not recommended.
  */
-public class AudioTrack
+public class AudioTrack implements AudioRouting
 {
     //---------------------------------------------------------
     // Constants
@@ -97,9 +96,10 @@
     /** Maximum value for sample rate */
     private static final int SAMPLE_RATE_HZ_MAX = 192000;
 
-    // FCC_8
-    /** Maximum value for AudioTrack channel count */
-    private static final int CHANNEL_COUNT_MAX = 8;
+    /** Maximum value for AudioTrack channel count
+     * @hide public for MediaCode only, do not un-hide or change to a numeric literal
+     */
+    public static final int CHANNEL_COUNT_MAX = native_get_FCC_8();
 
     /** indicates AudioTrack state is stopped */
     public static final int PLAYSTATE_STOPPED = 1;  // matches SL_PLAYSTATE_STOPPED
@@ -317,10 +317,11 @@
     // Used exclusively by native code
     //--------------------
     /**
+     * @hide
      * Accessed by native methods: provides access to C++ AudioTrack object.
      */
     @SuppressWarnings("unused")
-    private long mNativeTrackInJavaObj;
+    protected long mNativeTrackInJavaObj;
     /**
      * Accessed by native methods: provides access to the JNI data (i.e. resources used by
      * the native AudioTrack object, but not stored in it).
@@ -523,6 +524,31 @@
     }
 
     /**
+     * A constructor which explicitly connects a Native (C++) AudioTrack. For use by
+     * the AudioTrackRoutingProxy subclass.
+     * @param nativeTrackInJavaObj a C/C++ pointer to a native AudioTrack
+     * (associated with an OpenSL ES player).
+     */
+    /*package*/ AudioTrack(long nativeTrackInJavaObj) {
+        mNativeTrackInJavaObj = nativeTrackInJavaObj;
+
+        // "final"s
+        mAttributes = null;
+        mAppOps = null;
+
+        // remember which looper is associated with the AudioTrack instantiation
+        Looper looper;
+        if ((looper = Looper.myLooper()) == null) {
+            looper = Looper.getMainLooper();
+        }
+        mInitializationLooper = looper;
+
+        // other initialization...
+
+        mState = STATE_INITIALIZED;
+    }
+
+    /**
      * Builder class for {@link AudioTrack} objects.
      * Use this class to configure and create an <code>AudioTrack</code> instance. By setting audio
      * attributes and audio format parameters, you indicate which of those vary from the default
@@ -1026,8 +1052,67 @@
         }
     }
 
+// TODO Change getBufferCapacityInFrames() reference below to
+// {@link #getBufferCapacityInFrames()} after @hide is removed.
+// TODO Change setBufferSizeInFrames(int) reference below to
+// {@link #setBufferSizeInFrames(int)} after @hide is removed.
     /**
-     *  Returns the frame count of the native <code>AudioTrack</code> buffer.
+     *  Returns the effective size of the <code>AudioTrack</code> buffer
+     * that the application writes to.
+     *  <p> This will be less than or equal to the result of
+     * getBufferCapacityInFrames().
+     * It will be equal if setBufferSizeInFrames(int) has never been called.
+     *  <p> If the track is subsequently routed to a different output sink, the buffer
+     *  size and capacity may enlarge to accommodate.
+     *  <p> If the <code>AudioTrack</code> encoding indicates compressed data,
+     *  e.g. {@link AudioFormat#ENCODING_AC3}, then the frame count returned is
+     *  the size of the native <code>AudioTrack</code> buffer in bytes.
+     *  <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
+     */
+    public int getBufferSizeInFrames() {
+        return native_get_buffer_size_frames();
+    }
+
+// TODO Change getBufferCapacityInFrames() reference below to
+// {@link #getBufferCapacityInFrames()} after @hide is removed.
+    /**
+     * Limits the effective size of the <code>AudioTrack</code> buffer
+     * that the application writes to.
+     * <p> A write to this AudioTrack will not fill the buffer beyond this limit.
+     * If a blocking write is used then the write will block until the the data
+     * can fit within this limit.
+     * <p>Changing this limit modifies the latency associated with
+     * the buffer for this track. A smaller size will give lower latency
+     * but there may be more glitches due to buffer underruns.
+     *  <p>The actual size used may not be equal to this requested size.
+     * It will be limited to a valid range with a maximum of
+     * getBufferCapacityInFrames().
+     * It may also be adjusted slightly for internal reasons.
+     * If bufferSizeInFrames is less than zero then {@link #ERROR_BAD_VALUE}
+     * will be returned.
+     * <p>This method is only supported for PCM audio.
+     * It is not supported for compressed audio tracks.
+     *
+     * @param bufferSizeInFrames requested buffer size
+     * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
+     *    {@link #ERROR_INVALID_OPERATION}
+     *  @throws IllegalStateException
+     */
+    public int setBufferSizeInFrames(int bufferSizeInFrames) {
+        if (mDataLoadMode == MODE_STATIC || mState == STATE_UNINITIALIZED) {
+            return ERROR_INVALID_OPERATION;
+        }
+        if (bufferSizeInFrames < 0) {
+            return ERROR_BAD_VALUE;
+        }
+        return native_set_buffer_size_frames(bufferSizeInFrames);
+    }
+
+    /**
+     *  Returns the maximum size of the native <code>AudioTrack</code> buffer.
      *  <p> If the track's creation mode is {@link #MODE_STATIC},
      *  it is equal to the specified bufferSizeInBytes on construction, converted to frame units.
      *  A static track's native frame count will not change.
@@ -1042,11 +1127,11 @@
      *  the size of the native <code>AudioTrack</code> buffer in bytes.
      *  <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.
+     *  @return maximum size in frames of the <code>AudioTrack</code> buffer.
      *  @throws IllegalStateException
      */
-    public int getBufferSizeInFrames() {
-        return native_get_native_frame_count();
+    public int getBufferCapacityInFrames() {
+        return native_get_buffer_capacity_frames();
     }
 
     /**
@@ -1057,7 +1142,7 @@
      */
     @Deprecated
     protected int getNativeFrameCount() {
-        return native_get_native_frame_count();
+        return native_get_buffer_capacity_frames();
     }
 
     /**
@@ -1105,6 +1190,24 @@
     }
 
     /**
+     * Returns the number of underrun occurrences in the application-level write buffer
+     * since the AudioTrack was created.
+     * 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.
+     * 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.
+     */
+    public int getUnderrunCount() {
+        return native_get_underrun_count();
+    }
+
+    /**
      *  Returns the output sample rate in Hz for the specified stream type.
      */
     static public int getNativeOutputSampleRate(int streamType) {
@@ -2246,22 +2349,6 @@
         }
     }
 
-    //--------------------------------------------------------------------------
-    // (Re)Routing Info
-    //--------------------
-    /**
-     * Defines the interface by which applications can receive notifications of routing
-     * changes for the associated {@link AudioTrack}.
-     */
-    public interface OnRoutingChangedListener {
-        /**
-         * Called when the routing of an AudioTrack changes from either and explicit or
-         * policy rerouting.  Use {@link #getRoutedDevice()} to retrieve the newly routed-to
-         * device.
-         */
-        public void onRoutingChanged(AudioTrack audioTrack);
-    }
-
     /**
      * Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioTrack.
      * Note: The query is only valid if the AudioTrack is currently playing. If it is not,
@@ -2282,6 +2369,89 @@
         return null;
     }
 
+    /*
+     * Call BEFORE adding a routing callback handler.
+     */
+    private void testEnableNativeRoutingCallbacks() {
+        if (mRoutingChangeListeners.size() == 0 && mNewRoutingChangeListeners.size() == 0) {
+            native_enableDeviceCallback();
+        }
+    }
+
+    /*
+     * Call AFTER removing a routing callback handler.
+     */
+    private void testDisableNativeRoutingCallbacks() {
+        if (mRoutingChangeListeners.size() == 0 && mNewRoutingChangeListeners.size() == 0) {
+            native_disableDeviceCallback();
+        }
+    }
+
+    //--------------------------------------------------------------------------
+    // >= "N" (Re)Routing Info
+    //--------------------
+    /**
+     * The list of AudioRouting.OnRoutingChangedListener interfaces added (with
+     * {@link AudioTrack#addOnRoutingListener(AudioRouting.OnRoutingChangedListener,
+     *          android.os.Handler)}
+     * by an app to receive (re)routing notifications.
+     */
+   private ArrayMap<AudioRouting.OnRoutingChangedListener, NativeNewRoutingEventHandlerDelegate>
+    mNewRoutingChangeListeners =
+        new ArrayMap<AudioRouting.OnRoutingChangedListener, NativeNewRoutingEventHandlerDelegate>();
+
+   /**
+    * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
+    * changes on this AudioTrack.
+    * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
+    * notifications of rerouting events.
+    * @param handler  Specifies the {@link Handler} object for the thread on which to execute
+    * the callback. If <code>null</code>, the {@link Handler} associated with the main
+    * {@link Looper} will be used.
+    */
+    public void addOnRoutingListener(AudioRouting.OnRoutingChangedListener listener,
+            Handler handler) {
+        if (listener != null && !mNewRoutingChangeListeners.containsKey(listener)) {
+            synchronized (mNewRoutingChangeListeners) {
+                testEnableNativeRoutingCallbacks();
+                mNewRoutingChangeListeners.put(
+                    listener, new NativeNewRoutingEventHandlerDelegate(this, listener,
+                            handler != null ? handler : new Handler(mInitializationLooper)));
+            }
+        }
+    }
+
+    /**
+     * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added
+     * to receive rerouting notifications.
+     * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
+     * to remove.
+     */
+    public void removeOnRoutingListener(AudioRouting.OnRoutingChangedListener listener) {
+        if (mNewRoutingChangeListeners.containsKey(listener)) {
+            mNewRoutingChangeListeners.remove(listener);
+        }
+        testDisableNativeRoutingCallbacks();
+    }
+
+    //--------------------------------------------------------------------------
+    // Marshmallow (Re)Routing Info
+    //--------------------
+    /**
+     * Defines the interface by which applications can receive notifications of routing
+     * changes for the associated {@link AudioTrack}.
+     */
+    @Deprecated
+    public interface OnRoutingChangedListener {
+        /**
+         * Called when the routing of an AudioTrack changes from either and explicit or
+         * policy rerouting.  Use {@link #getRoutedDevice()} to retrieve the newly routed-to
+         * device.
+         */
+        @Deprecated
+        public void onRoutingChanged(AudioTrack audioTrack);
+    }
+
     /**
      * The list of AudioTrack.OnRoutingChangedListener interfaces added (with
      * {@link AudioTrack#addOnRoutingChangedListener(OnRoutingChangedListener, android.os.Handler)}
@@ -2300,13 +2470,12 @@
      * the callback. If <code>null</code>, the {@link Handler} associated with the main
      * {@link Looper} will be used.
      */
+    @Deprecated
     public void addOnRoutingChangedListener(OnRoutingChangedListener listener,
             android.os.Handler handler) {
         if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
             synchronized (mRoutingChangeListeners) {
-                if (mRoutingChangeListeners.size() == 0) {
-                    native_enableDeviceCallback();
-                }
+                testEnableNativeRoutingCallbacks();
                 mRoutingChangeListeners.put(
                     listener, new NativeRoutingEventHandlerDelegate(this, listener,
                             handler != null ? handler : new Handler(mInitializationLooper)));
@@ -2319,14 +2488,13 @@
      * to receive rerouting notifications.
      * @param listener The previously added {@link OnRoutingChangedListener} interface to remove.
      */
+    @Deprecated
     public void removeOnRoutingChangedListener(OnRoutingChangedListener listener) {
         synchronized (mRoutingChangeListeners) {
             if (mRoutingChangeListeners.containsKey(listener)) {
                 mRoutingChangeListeners.remove(listener);
             }
-            if (mRoutingChangeListeners.size() == 0) {
-                native_disableDeviceCallback();
-            }
+            testDisableNativeRoutingCallbacks();
         }
     }
 
@@ -2334,17 +2502,30 @@
      * Sends device list change notification to all listeners.
      */
     private void broadcastRoutingChange() {
+        AudioManager.resetAudioPortGeneration();
+
+        // Marshmallow Routing
         Collection<NativeRoutingEventHandlerDelegate> values;
         synchronized (mRoutingChangeListeners) {
             values = mRoutingChangeListeners.values();
         }
-        AudioManager.resetAudioPortGeneration();
         for(NativeRoutingEventHandlerDelegate delegate : values) {
             Handler handler = delegate.getHandler();
             if (handler != null) {
                 handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE);
             }
         }
+        // >= "N" Routing
+        Collection<NativeNewRoutingEventHandlerDelegate> newValues;
+        synchronized (mNewRoutingChangeListeners) {
+            newValues = mNewRoutingChangeListeners.values();
+        }
+        for(NativeNewRoutingEventHandlerDelegate delegate : newValues) {
+            Handler handler = delegate.getHandler();
+            if (handler != null) {
+                handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE);
+            }
+        }
     }
 
     //---------------------------------------------------------
@@ -2427,6 +2608,7 @@
     }
 
     /**
+     * Marshmallow Routing API.
      * Helper class to handle the forwarding of native events to the appropriate listener
      * (potentially) handled in a different thread
      */
@@ -2476,6 +2658,57 @@
         }
     }
 
+    /**
+     * Marshmallow Routing API.
+     * Helper class to handle the forwarding of native events to the appropriate listener
+     * (potentially) handled in a different thread
+     */
+    private class NativeNewRoutingEventHandlerDelegate {
+        private final Handler mHandler;
+
+        NativeNewRoutingEventHandlerDelegate(final AudioTrack track,
+                                   final AudioRouting.OnRoutingChangedListener listener,
+                                   Handler handler) {
+            // find the looper for our new event handler
+            Looper looper;
+            if (handler != null) {
+                looper = handler.getLooper();
+            } else {
+                // no given handler, use the looper the AudioTrack was created in
+                looper = mInitializationLooper;
+            }
+
+            // construct the event handler with this looper
+            if (looper != null) {
+                // implement the event handler delegate
+                mHandler = new Handler(looper) {
+                    @Override
+                    public void handleMessage(Message msg) {
+                        if (track == null) {
+                            return;
+                        }
+                        switch(msg.what) {
+                        case AudioSystem.NATIVE_EVENT_ROUTING_CHANGE:
+                            if (listener != null) {
+                                listener.onRoutingChanged(track);
+                            }
+                            break;
+                        default:
+                            loge("Unknown native event type: " + msg.what);
+                            break;
+                        }
+                    }
+                };
+            } else {
+                mHandler = null;
+            }
+        }
+
+        Handler getHandler() {
+            return mHandler;
+        }
+    }
+
     //---------------------------------------------------------
     // Java methods called from the native side
     //--------------------
@@ -2544,7 +2777,9 @@
 
     private native final int native_reload_static();
 
-    private native final int native_get_native_frame_count();
+    private native final int native_get_buffer_size_frames();
+    private native final int native_set_buffer_size_frames(int bufferSizeInFrames);
+    private native final int native_get_buffer_capacity_frames();
 
     private native final void native_setVolume(float leftVolume, float rightVolume);
 
@@ -2565,6 +2800,8 @@
 
     private native final int native_get_latency();
 
+    private native final int native_get_underrun_count();
+
     // longArray must be a non-null array of length >= 2
     // [0] is assigned the frame position
     // [1] is assigned the time in CLOCK_MONOTONIC nanoseconds
@@ -2583,6 +2820,7 @@
     private native final int native_getRoutedDeviceId();
     private native final void native_enableDeviceCallback();
     private native final void native_disableDeviceCallback();
+    static private native int native_get_FCC_8();
 
     //---------------------------------------------------------
     // Utility methods
diff --git a/media/java/android/media/AudioTrackRoutingProxy.java b/media/java/android/media/AudioTrackRoutingProxy.java
new file mode 100644
index 0000000..9b97ae9
--- /dev/null
+++ b/media/java/android/media/AudioTrackRoutingProxy.java
@@ -0,0 +1,32 @@
+/*
+ * 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.media;
+
+/**
+ * An AudioTrack connected to a native (C/C++) which allows access only to routing methods.
+ */
+class AudioTrackRoutingProxy extends AudioTrack {
+    /**
+     * A constructor which explicitly connects a Native (C++) AudioTrack. For use by
+     * the AudioTrackRoutingProxy subclass.
+     * @param nativeTrackInJavaObj a C/C++ pointer to a native AudioTrack
+     * (associated with an OpenSL ES player).
+     */
+    public AudioTrackRoutingProxy(long nativeTrackInJavaObj) {
+        super(nativeTrackInJavaObj);
+    }
+}
diff --git a/media/java/android/media/Cea708CaptionRenderer.java b/media/java/android/media/Cea708CaptionRenderer.java
new file mode 100644
index 0000000..88912fe
--- /dev/null
+++ b/media/java/android/media/Cea708CaptionRenderer.java
@@ -0,0 +1,2151 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.os.Handler;
+import android.os.Message;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.style.CharacterStyle;
+import android.text.style.RelativeSizeSpan;
+import android.text.style.StyleSpan;
+import android.text.style.SubscriptSpan;
+import android.text.style.SuperscriptSpan;
+import android.text.style.UnderlineSpan;
+import android.util.AttributeSet;
+import android.text.Layout.Alignment;
+import android.util.Log;
+import android.text.TextUtils;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.CaptioningManager;
+import android.view.accessibility.CaptioningManager.CaptionStyle;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Vector;
+
+import com.android.internal.widget.SubtitleView;
+
+/** @hide */
+public class Cea708CaptionRenderer extends SubtitleController.Renderer {
+    private final Context mContext;
+    private Cea708CCWidget mCCWidget;
+
+    public Cea708CaptionRenderer(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public boolean supports(MediaFormat format) {
+        if (format.containsKey(MediaFormat.KEY_MIME)) {
+            String mimeType = format.getString(MediaFormat.KEY_MIME);
+            return MediaPlayer.MEDIA_MIMETYPE_TEXT_CEA_708.equals(mimeType);
+        }
+        return false;
+    }
+
+    @Override
+    public SubtitleTrack createTrack(MediaFormat format) {
+        String mimeType = format.getString(MediaFormat.KEY_MIME);
+        if (MediaPlayer.MEDIA_MIMETYPE_TEXT_CEA_708.equals(mimeType)) {
+            if (mCCWidget == null) {
+                mCCWidget = new Cea708CCWidget(mContext);
+            }
+            return new Cea708CaptionTrack(mCCWidget, format);
+        }
+        throw new RuntimeException("No matching format: " + format.toString());
+    }
+}
+
+/** @hide */
+class Cea708CaptionTrack extends SubtitleTrack {
+    private final Cea708CCParser mCCParser;
+    private final Cea708CCWidget mRenderingWidget;
+
+    Cea708CaptionTrack(Cea708CCWidget renderingWidget, MediaFormat format) {
+        super(format);
+
+        mRenderingWidget = renderingWidget;
+        mCCParser = new Cea708CCParser(mRenderingWidget);
+    }
+
+    @Override
+    public void onData(byte[] data, boolean eos, long runID) {
+        mCCParser.parse(data);
+    }
+
+    @Override
+    public RenderingWidget getRenderingWidget() {
+        return mRenderingWidget;
+    }
+
+    @Override
+    public void updateView(Vector<Cue> activeCues) {
+        // Overriding with NO-OP, CC rendering by-passes this
+    }
+}
+
+/**
+ * @hide
+ *
+ * A class for parsing CEA-708, which is the standard for closed captioning for ATSC DTV.
+ *
+ * <p>ATSC DTV closed caption data are carried on picture user data of video streams.
+ * This class starts to parse from picture user data payload, so extraction process of user_data
+ * from video streams is up to outside of this code.
+ *
+ * <p>There are 4 steps to decode user_data to provide closed caption services. Step 1 and 2 are
+ * done in NuPlayer and libstagefright.
+ *
+ * <h3>Step 1. user_data -&gt; CcPacket</h3>
+ *
+ * <p>First, user_data consists of cc_data packets, which are 3-byte segments. Here, CcPacket is a
+ * collection of cc_data packets in a frame along with same presentation timestamp. Because cc_data
+ * packets must be reassembled in the frame display order, CcPackets are reordered.
+ *
+ * <h3>Step 2. CcPacket -&gt; DTVCC packet</h3>
+ *
+ * <p>Each cc_data packet has a one byte for declaring a type of itself and data validity, and the
+ * subsequent two bytes for input data of a DTVCC packet. There are 4 types for cc_data packet.
+ * We're interested in DTVCC_PACKET_START(type 3) and DTVCC_PACKET_DATA(type 2). Each DTVCC packet
+ * begins with DTVCC_PACKET_START(type 3) and the following cc_data packets which has
+ * DTVCC_PACKET_DATA(type 2) are appended into the DTVCC packet being assembled.
+ *
+ * <h3>Step 3. DTVCC packet -&gt; Service Blocks</h3>
+ *
+ * <p>A DTVCC packet consists of multiple service blocks. Each service block represents a caption
+ * track and has a service number, which ranges from 1 to 63, that denotes caption track identity.
+ * In here, we listen at most one chosen caption track by service number. Otherwise, just skip the
+ * other service blocks.
+ *
+ * <h3>Step 4. Interpreting Service Block Data ({@link #parseServiceBlockData}, {@code parseXX},
+ * and {@link #parseExt1} methods)</h3>
+ *
+ * <p>Service block data is actual caption stream. it looks similar to telnet. It uses most parts of
+ * ASCII table and consists of specially defined commands and some ASCII control codes which work
+ * in a behavior slightly different from their original purpose. ASCII control codes and caption
+ * commands are explicit instructions that control the state of a closed caption service and the
+ * other ASCII and text codes are implicit instructions that send their characters to buffer.
+ *
+ * <p>There are 4 main code groups and 4 extended code groups. Both the range of code groups are the
+ * same as the range of a byte.
+ *
+ * <p>4 main code groups: C0, C1, G0, G1
+ * <br>4 extended code groups: C2, C3, G2, G3
+ *
+ * <p>Each code group has its own handle method. For example, {@link #parseC0} handles C0 code group
+ * and so on. And {@link #parseServiceBlockData} method maps a stream on the main code groups while
+ * {@link #parseExt1} method maps on the extended code groups.
+ *
+ * <p>The main code groups:
+ * <ul>
+ * <li>C0 - contains modified ASCII control codes. It is not intended by CEA-708 but Korea TTA
+ *      standard for ATSC CC uses P16 character heavily, which is unclear entity in CEA-708 doc,
+ *      even for the alphanumeric characters instead of ASCII characters.</li>
+ * <li>C1 - contains the caption commands. There are 3 categories of a caption command.</li>
+ * <ul>
+ * <li>Window commands: The window commands control a caption window which is addressable area being
+ *                  with in the Safe title area. (CWX, CLW, DSW, HDW, TGW, DLW, SWA, DFX)</li>
+ * <li>Pen commands: Th pen commands control text style and location. (SPA, SPC, SPL)</li>
+ * <li>Job commands: The job commands make a delay and recover from the delay. (DLY, DLC, RST)</li>
+ * </ul>
+ * <li>G0 - same as printable ASCII character set except music note character.</li>
+ * <li>G1 - same as ISO 8859-1 Latin 1 character set.</li>
+ * </ul>
+ * <p>Most of the extended code groups are being skipped.
+ *
+ */
+class Cea708CCParser {
+    private static final String TAG = "Cea708CCParser";
+    private static final boolean DEBUG = false;
+
+    private static final String MUSIC_NOTE_CHAR = new String(
+            "\u266B".getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
+
+    private final StringBuffer mBuffer = new StringBuffer();
+    private int mCommand = 0;
+
+    // Assign a dummy listener in order to avoid null checks.
+    private DisplayListener mListener = new DisplayListener() {
+        @Override
+        public void emitEvent(CaptionEvent event) {
+            // do nothing
+        }
+    };
+
+    /**
+     * {@link Cea708Parser} emits caption event of three different types.
+     * {@link DisplayListener#emitEvent} is invoked with the parameter
+     * {@link CaptionEvent} to pass all the results to an observer of the decoding process .
+     *
+     * <p>{@link CaptionEvent#type} determines the type of the result and
+     * {@link CaptionEvent#obj} contains the output value of a caption event.
+     * The observer must do the casting to the corresponding type.
+     *
+     * <ul><li>{@code CAPTION_EMIT_TYPE_BUFFER}: Passes a caption text buffer to a observer.
+     * {@code obj} must be of {@link String}.</li>
+     *
+     * <li>{@code CAPTION_EMIT_TYPE_CONTROL}: Passes a caption character control code to a observer.
+     * {@code obj} must be of {@link Character}.</li>
+     *
+     * <li>{@code CAPTION_EMIT_TYPE_CLEAR_COMMAND}: Passes a clear command to a observer.
+     * {@code obj} must be {@code NULL}.</li></ul>
+     */
+    public static final int CAPTION_EMIT_TYPE_BUFFER = 1;
+    public static final int CAPTION_EMIT_TYPE_CONTROL = 2;
+    public static final int CAPTION_EMIT_TYPE_COMMAND_CWX = 3;
+    public static final int CAPTION_EMIT_TYPE_COMMAND_CLW = 4;
+    public static final int CAPTION_EMIT_TYPE_COMMAND_DSW = 5;
+    public static final int CAPTION_EMIT_TYPE_COMMAND_HDW = 6;
+    public static final int CAPTION_EMIT_TYPE_COMMAND_TGW = 7;
+    public static final int CAPTION_EMIT_TYPE_COMMAND_DLW = 8;
+    public static final int CAPTION_EMIT_TYPE_COMMAND_DLY = 9;
+    public static final int CAPTION_EMIT_TYPE_COMMAND_DLC = 10;
+    public static final int CAPTION_EMIT_TYPE_COMMAND_RST = 11;
+    public static final int CAPTION_EMIT_TYPE_COMMAND_SPA = 12;
+    public static final int CAPTION_EMIT_TYPE_COMMAND_SPC = 13;
+    public static final int CAPTION_EMIT_TYPE_COMMAND_SPL = 14;
+    public static final int CAPTION_EMIT_TYPE_COMMAND_SWA = 15;
+    public static final int CAPTION_EMIT_TYPE_COMMAND_DFX = 16;
+
+    Cea708CCParser(DisplayListener listener) {
+        if (listener != null) {
+            mListener = listener;
+        }
+    }
+
+    interface DisplayListener {
+        void emitEvent(CaptionEvent event);
+    }
+
+    private void emitCaptionEvent(CaptionEvent captionEvent) {
+        // Emit the existing string buffer before a new event is arrived.
+        emitCaptionBuffer();
+        mListener.emitEvent(captionEvent);
+    }
+
+    private void emitCaptionBuffer() {
+        if (mBuffer.length() > 0) {
+            mListener.emitEvent(new CaptionEvent(CAPTION_EMIT_TYPE_BUFFER, mBuffer.toString()));
+            mBuffer.setLength(0);
+        }
+    }
+
+    // Step 3. DTVCC packet -> Service Blocks (parseDtvCcPacket method)
+    public void parse(byte[] data) {
+        // From this point, starts to read DTVCC coding layer.
+        // First, identify code groups, which is defined in CEA-708B Section 7.1.
+        int pos = 0;
+        while (pos < data.length) {
+            pos = parseServiceBlockData(data, pos);
+        }
+
+        // Emit the buffer after reading codes.
+        emitCaptionBuffer();
+    }
+
+    // Step 4. Main code groups
+    private int parseServiceBlockData(byte[] data, int pos) {
+        // For the details of the ranges of DTVCC code groups, see CEA-708B Table 6.
+        mCommand = data[pos] & 0xff;
+        ++pos;
+        if (mCommand == Const.CODE_C0_EXT1) {
+            if (DEBUG) {
+                Log.d(TAG, String.format("parseServiceBlockData EXT1 %x", mCommand));
+            }
+            pos = parseExt1(data, pos);
+        } else if (mCommand >= Const.CODE_C0_RANGE_START
+                && mCommand <= Const.CODE_C0_RANGE_END) {
+            if (DEBUG) {
+                Log.d(TAG, String.format("parseServiceBlockData C0 %x", mCommand));
+            }
+            pos = parseC0(data, pos);
+        } else if (mCommand >= Const.CODE_C1_RANGE_START
+                && mCommand <= Const.CODE_C1_RANGE_END) {
+            if (DEBUG) {
+                Log.d(TAG, String.format("parseServiceBlockData C1 %x", mCommand));
+            }
+            pos = parseC1(data, pos);
+        } else if (mCommand >= Const.CODE_G0_RANGE_START
+                && mCommand <= Const.CODE_G0_RANGE_END) {
+            if (DEBUG) {
+                Log.d(TAG, String.format("parseServiceBlockData G0 %x", mCommand));
+            }
+            pos = parseG0(data, pos);
+        } else if (mCommand >= Const.CODE_G1_RANGE_START
+                && mCommand <= Const.CODE_G1_RANGE_END) {
+            if (DEBUG) {
+                Log.d(TAG, String.format("parseServiceBlockData G1 %x", mCommand));
+            }
+            pos = parseG1(data, pos);
+        }
+        return pos;
+    }
+
+    private int parseC0(byte[] data, int pos) {
+        // For the details of C0 code group, see CEA-708B Section 7.4.1.
+        // CL Group: C0 Subset of ASCII Control codes
+        if (mCommand >= Const.CODE_C0_SKIP2_RANGE_START
+                && mCommand <= Const.CODE_C0_SKIP2_RANGE_END) {
+            if (mCommand == Const.CODE_C0_P16) {
+                // P16 escapes next two bytes for the large character maps.(no standard rule)
+                // For Korea broadcasting, express whole letters by using this.
+                try {
+                    if (data[pos] == 0) {
+                        mBuffer.append((char) data[pos + 1]);
+                    } else {
+                        String value = new String(Arrays.copyOfRange(data, pos, pos + 2), "EUC-KR");
+                        mBuffer.append(value);
+                    }
+                } catch (UnsupportedEncodingException e) {
+                    Log.e(TAG, "P16 Code - Could not find supported encoding", e);
+                }
+            }
+            pos += 2;
+        } else if (mCommand >= Const.CODE_C0_SKIP1_RANGE_START
+                && mCommand <= Const.CODE_C0_SKIP1_RANGE_END) {
+            ++pos;
+        } else {
+            // NUL, BS, FF, CR interpreted as they are in ASCII control codes.
+            // HCR moves the pen location to th beginning of the current line and deletes contents.
+            // FF clears the screen and moves the pen location to (0,0).
+            // ETX is the NULL command which is used to flush text to the current window when no
+            // other command is pending.
+            switch (mCommand) {
+                case Const.CODE_C0_NUL:
+                    break;
+                case Const.CODE_C0_ETX:
+                    emitCaptionEvent(new CaptionEvent(CAPTION_EMIT_TYPE_CONTROL, (char) mCommand));
+                    break;
+                case Const.CODE_C0_BS:
+                    emitCaptionEvent(new CaptionEvent(CAPTION_EMIT_TYPE_CONTROL, (char) mCommand));
+                    break;
+                case Const.CODE_C0_FF:
+                    emitCaptionEvent(new CaptionEvent(CAPTION_EMIT_TYPE_CONTROL, (char) mCommand));
+                    break;
+                case Const.CODE_C0_CR:
+                    mBuffer.append('\n');
+                    break;
+                case Const.CODE_C0_HCR:
+                    emitCaptionEvent(new CaptionEvent(CAPTION_EMIT_TYPE_CONTROL, (char) mCommand));
+                    break;
+                default:
+                    break;
+            }
+        }
+        return pos;
+    }
+
+    private int parseC1(byte[] data, int pos) {
+        // For the details of C1 code group, see CEA-708B Section 8.10.
+        // CR Group: C1 Caption Control Codes
+        switch (mCommand) {
+            case Const.CODE_C1_CW0:
+            case Const.CODE_C1_CW1:
+            case Const.CODE_C1_CW2:
+            case Const.CODE_C1_CW3:
+            case Const.CODE_C1_CW4:
+            case Const.CODE_C1_CW5:
+            case Const.CODE_C1_CW6:
+            case Const.CODE_C1_CW7: {
+                // SetCurrentWindow0-7
+                int windowId = mCommand - Const.CODE_C1_CW0;
+                emitCaptionEvent(new CaptionEvent(CAPTION_EMIT_TYPE_COMMAND_CWX, windowId));
+                if (DEBUG) {
+                    Log.d(TAG, String.format("CaptionCommand CWX windowId: %d", windowId));
+                }
+                break;
+            }
+
+            case Const.CODE_C1_CLW: {
+                // ClearWindows
+                int windowBitmap = data[pos] & 0xff;
+                ++pos;
+                emitCaptionEvent(new CaptionEvent(CAPTION_EMIT_TYPE_COMMAND_CLW, windowBitmap));
+                if (DEBUG) {
+                    Log.d(TAG, String.format("CaptionCommand CLW windowBitmap: %d", windowBitmap));
+                }
+                break;
+            }
+
+            case Const.CODE_C1_DSW: {
+                // DisplayWindows
+                int windowBitmap = data[pos] & 0xff;
+                ++pos;
+                emitCaptionEvent(new CaptionEvent(CAPTION_EMIT_TYPE_COMMAND_DSW, windowBitmap));
+                if (DEBUG) {
+                    Log.d(TAG, String.format("CaptionCommand DSW windowBitmap: %d", windowBitmap));
+                }
+                break;
+            }
+
+            case Const.CODE_C1_HDW: {
+                // HideWindows
+                int windowBitmap = data[pos] & 0xff;
+                ++pos;
+                emitCaptionEvent(new CaptionEvent(CAPTION_EMIT_TYPE_COMMAND_HDW, windowBitmap));
+                if (DEBUG) {
+                    Log.d(TAG, String.format("CaptionCommand HDW windowBitmap: %d", windowBitmap));
+                }
+                break;
+            }
+
+            case Const.CODE_C1_TGW: {
+                // ToggleWindows
+                int windowBitmap = data[pos] & 0xff;
+                ++pos;
+                emitCaptionEvent(new CaptionEvent(CAPTION_EMIT_TYPE_COMMAND_TGW, windowBitmap));
+                if (DEBUG) {
+                    Log.d(TAG, String.format("CaptionCommand TGW windowBitmap: %d", windowBitmap));
+                }
+                break;
+            }
+
+            case Const.CODE_C1_DLW: {
+                // DeleteWindows
+                int windowBitmap = data[pos] & 0xff;
+                ++pos;
+                emitCaptionEvent(new CaptionEvent(CAPTION_EMIT_TYPE_COMMAND_DLW, windowBitmap));
+                if (DEBUG) {
+                    Log.d(TAG, String.format("CaptionCommand DLW windowBitmap: %d", windowBitmap));
+                }
+                break;
+            }
+
+            case Const.CODE_C1_DLY: {
+                // Delay
+                int tenthsOfSeconds = data[pos] & 0xff;
+                ++pos;
+                emitCaptionEvent(new CaptionEvent(CAPTION_EMIT_TYPE_COMMAND_DLY, tenthsOfSeconds));
+                if (DEBUG) {
+                    Log.d(TAG, String.format("CaptionCommand DLY %d tenths of seconds",
+                            tenthsOfSeconds));
+                }
+                break;
+            }
+            case Const.CODE_C1_DLC: {
+                // DelayCancel
+                emitCaptionEvent(new CaptionEvent(CAPTION_EMIT_TYPE_COMMAND_DLC, null));
+                if (DEBUG) {
+                    Log.d(TAG, "CaptionCommand DLC");
+                }
+                break;
+            }
+
+            case Const.CODE_C1_RST: {
+                // Reset
+                emitCaptionEvent(new CaptionEvent(CAPTION_EMIT_TYPE_COMMAND_RST, null));
+                if (DEBUG) {
+                    Log.d(TAG, "CaptionCommand RST");
+                }
+                break;
+            }
+
+            case Const.CODE_C1_SPA: {
+                // SetPenAttributes
+                int textTag = (data[pos] & 0xf0) >> 4;
+                int penSize = data[pos] & 0x03;
+                int penOffset = (data[pos] & 0x0c) >> 2;
+                boolean italic = (data[pos + 1] & 0x80) != 0;
+                boolean underline = (data[pos + 1] & 0x40) != 0;
+                int edgeType = (data[pos + 1] & 0x38) >> 3;
+                int fontTag = data[pos + 1] & 0x7;
+                pos += 2;
+                emitCaptionEvent(new CaptionEvent(CAPTION_EMIT_TYPE_COMMAND_SPA,
+                        new CaptionPenAttr(penSize, penOffset, textTag, fontTag, edgeType,
+                                underline, italic)));
+                if (DEBUG) {
+                    Log.d(TAG, String.format(
+                            "CaptionCommand SPA penSize: %d, penOffset: %d, textTag: %d, "
+                                    + "fontTag: %d, edgeType: %d, underline: %s, italic: %s",
+                            penSize, penOffset, textTag, fontTag, edgeType, underline, italic));
+                }
+                break;
+            }
+
+            case Const.CODE_C1_SPC: {
+                // SetPenColor
+                int opacity = (data[pos] & 0xc0) >> 6;
+                int red = (data[pos] & 0x30) >> 4;
+                int green = (data[pos] & 0x0c) >> 2;
+                int blue = data[pos] & 0x03;
+                CaptionColor foregroundColor = new CaptionColor(opacity, red, green, blue);
+                ++pos;
+                opacity = (data[pos] & 0xc0) >> 6;
+                red = (data[pos] & 0x30) >> 4;
+                green = (data[pos] & 0x0c) >> 2;
+                blue = data[pos] & 0x03;
+                CaptionColor backgroundColor = new CaptionColor(opacity, red, green, blue);
+                ++pos;
+                red = (data[pos] & 0x30) >> 4;
+                green = (data[pos] & 0x0c) >> 2;
+                blue = data[pos] & 0x03;
+                CaptionColor edgeColor = new CaptionColor(
+                        CaptionColor.OPACITY_SOLID, red, green, blue);
+                ++pos;
+                emitCaptionEvent(new CaptionEvent(CAPTION_EMIT_TYPE_COMMAND_SPC,
+                        new CaptionPenColor(foregroundColor, backgroundColor, edgeColor)));
+                if (DEBUG) {
+                    Log.d(TAG, String.format(
+                            "CaptionCommand SPC foregroundColor %s backgroundColor %s edgeColor %s",
+                            foregroundColor, backgroundColor, edgeColor));
+                }
+                break;
+            }
+
+            case Const.CODE_C1_SPL: {
+                // SetPenLocation
+                // column is normally 0-31 for 4:3 formats, and 0-41 for 16:9 formats
+                int row = data[pos] & 0x0f;
+                int column = data[pos + 1] & 0x3f;
+                pos += 2;
+                emitCaptionEvent(new CaptionEvent(CAPTION_EMIT_TYPE_COMMAND_SPL,
+                        new CaptionPenLocation(row, column)));
+                if (DEBUG) {
+                    Log.d(TAG, String.format("CaptionCommand SPL row: %d, column: %d",
+                            row, column));
+                }
+                break;
+            }
+
+            case Const.CODE_C1_SWA: {
+                // SetWindowAttributes
+                int opacity = (data[pos] & 0xc0) >> 6;
+                int red = (data[pos] & 0x30) >> 4;
+                int green = (data[pos] & 0x0c) >> 2;
+                int blue = data[pos] & 0x03;
+                CaptionColor fillColor = new CaptionColor(opacity, red, green, blue);
+                int borderType = (data[pos + 1] & 0xc0) >> 6 | (data[pos + 2] & 0x80) >> 5;
+                red = (data[pos + 1] & 0x30) >> 4;
+                green = (data[pos + 1] & 0x0c) >> 2;
+                blue = data[pos + 1] & 0x03;
+                CaptionColor borderColor = new CaptionColor(
+                        CaptionColor.OPACITY_SOLID, red, green, blue);
+                boolean wordWrap = (data[pos + 2] & 0x40) != 0;
+                int printDirection = (data[pos + 2] & 0x30) >> 4;
+                int scrollDirection = (data[pos + 2] & 0x0c) >> 2;
+                int justify = (data[pos + 2] & 0x03);
+                int effectSpeed = (data[pos + 3] & 0xf0) >> 4;
+                int effectDirection = (data[pos + 3] & 0x0c) >> 2;
+                int displayEffect = data[pos + 3] & 0x3;
+                pos += 4;
+                emitCaptionEvent(new CaptionEvent(CAPTION_EMIT_TYPE_COMMAND_SWA,
+                        new CaptionWindowAttr(fillColor, borderColor, borderType, wordWrap,
+                                printDirection, scrollDirection, justify,
+                                effectDirection, effectSpeed, displayEffect)));
+                if (DEBUG) {
+                    Log.d(TAG, String.format(
+                            "CaptionCommand SWA fillColor: %s, borderColor: %s, borderType: %d"
+                                    + "wordWrap: %s, printDirection: %d, scrollDirection: %d, "
+                                    + "justify: %s, effectDirection: %d, effectSpeed: %d, "
+                                    + "displayEffect: %d",
+                            fillColor, borderColor, borderType, wordWrap, printDirection,
+                            scrollDirection, justify, effectDirection, effectSpeed, displayEffect));
+                }
+                break;
+            }
+
+            case Const.CODE_C1_DF0:
+            case Const.CODE_C1_DF1:
+            case Const.CODE_C1_DF2:
+            case Const.CODE_C1_DF3:
+            case Const.CODE_C1_DF4:
+            case Const.CODE_C1_DF5:
+            case Const.CODE_C1_DF6:
+            case Const.CODE_C1_DF7: {
+                // DefineWindow0-7
+                int windowId = mCommand - Const.CODE_C1_DF0;
+                boolean visible = (data[pos] & 0x20) != 0;
+                boolean rowLock = (data[pos] & 0x10) != 0;
+                boolean columnLock = (data[pos] & 0x08) != 0;
+                int priority = data[pos] & 0x07;
+                boolean relativePositioning = (data[pos + 1] & 0x80) != 0;
+                int anchorVertical = data[pos + 1] & 0x7f;
+                int anchorHorizontal = data[pos + 2] & 0xff;
+                int anchorId = (data[pos + 3] & 0xf0) >> 4;
+                int rowCount = data[pos + 3] & 0x0f;
+                int columnCount = data[pos + 4] & 0x3f;
+                int windowStyle = (data[pos + 5] & 0x38) >> 3;
+                int penStyle = data[pos + 5] & 0x07;
+                pos += 6;
+                emitCaptionEvent(new CaptionEvent(CAPTION_EMIT_TYPE_COMMAND_DFX,
+                        new CaptionWindow(windowId, visible, rowLock, columnLock, priority,
+                                relativePositioning, anchorVertical, anchorHorizontal, anchorId,
+                                rowCount, columnCount, penStyle, windowStyle)));
+                if (DEBUG) {
+                    Log.d(TAG, String.format(
+                            "CaptionCommand DFx windowId: %d, priority: %d, columnLock: %s, "
+                                    + "rowLock: %s, visible: %s, anchorVertical: %d, "
+                                    + "relativePositioning: %s, anchorHorizontal: %d, "
+                                    + "rowCount: %d, anchorId: %d, columnCount: %d, penStyle: %d, "
+                                    + "windowStyle: %d",
+                            windowId, priority, columnLock, rowLock, visible, anchorVertical,
+                            relativePositioning, anchorHorizontal, rowCount, anchorId, columnCount,
+                            penStyle, windowStyle));
+                }
+                break;
+            }
+
+            default:
+                break;
+        }
+        return pos;
+    }
+
+    private int parseG0(byte[] data, int pos) {
+        // For the details of G0 code group, see CEA-708B Section 7.4.3.
+        // GL Group: G0 Modified version of ANSI X3.4 Printable Character Set (ASCII)
+        if (mCommand == Const.CODE_G0_MUSICNOTE) {
+            // Music note.
+            mBuffer.append(MUSIC_NOTE_CHAR);
+        } else {
+            // Put ASCII code into buffer.
+            mBuffer.append((char) mCommand);
+        }
+        return pos;
+    }
+
+    private int parseG1(byte[] data, int pos) {
+        // For the details of G0 code group, see CEA-708B Section 7.4.4.
+        // GR Group: G1 ISO 8859-1 Latin 1 Characters
+        // Put ASCII Extended character set into buffer.
+        mBuffer.append((char) mCommand);
+        return pos;
+    }
+
+    // Step 4. Extended code groups
+    private int parseExt1(byte[] data, int pos) {
+        // For the details of EXT1 code group, see CEA-708B Section 7.2.
+        mCommand = data[pos] & 0xff;
+        ++pos;
+        if (mCommand >= Const.CODE_C2_RANGE_START
+                && mCommand <= Const.CODE_C2_RANGE_END) {
+            pos = parseC2(data, pos);
+        } else if (mCommand >= Const.CODE_C3_RANGE_START
+                && mCommand <= Const.CODE_C3_RANGE_END) {
+            pos = parseC3(data, pos);
+        } else if (mCommand >= Const.CODE_G2_RANGE_START
+                && mCommand <= Const.CODE_G2_RANGE_END) {
+            pos = parseG2(data, pos);
+        } else if (mCommand >= Const.CODE_G3_RANGE_START
+                && mCommand <= Const.CODE_G3_RANGE_END) {
+            pos = parseG3(data ,pos);
+        }
+        return pos;
+    }
+
+    private int parseC2(byte[] data, int pos) {
+        // For the details of C2 code group, see CEA-708B Section 7.4.7.
+        // Extended Miscellaneous Control Codes
+        // C2 Table : No commands as of CEA-708B. A decoder must skip.
+        if (mCommand >= Const.CODE_C2_SKIP0_RANGE_START
+                && mCommand <= Const.CODE_C2_SKIP0_RANGE_END) {
+            // Do nothing.
+        } else if (mCommand >= Const.CODE_C2_SKIP1_RANGE_START
+                && mCommand <= Const.CODE_C2_SKIP1_RANGE_END) {
+            ++pos;
+        } else if (mCommand >= Const.CODE_C2_SKIP2_RANGE_START
+                && mCommand <= Const.CODE_C2_SKIP2_RANGE_END) {
+            pos += 2;
+        } else if (mCommand >= Const.CODE_C2_SKIP3_RANGE_START
+                && mCommand <= Const.CODE_C2_SKIP3_RANGE_END) {
+            pos += 3;
+        }
+        return pos;
+    }
+
+    private int parseC3(byte[] data, int pos) {
+        // For the details of C3 code group, see CEA-708B Section 7.4.8.
+        // Extended Control Code Set 2
+        // C3 Table : No commands as of CEA-708B. A decoder must skip.
+        if (mCommand >= Const.CODE_C3_SKIP4_RANGE_START
+                && mCommand <= Const.CODE_C3_SKIP4_RANGE_END) {
+            pos += 4;
+        } else if (mCommand >= Const.CODE_C3_SKIP5_RANGE_START
+                && mCommand <= Const.CODE_C3_SKIP5_RANGE_END) {
+            pos += 5;
+        }
+        return pos;
+    }
+
+    private int parseG2(byte[] data, int pos) {
+        // For the details of C3 code group, see CEA-708B Section 7.4.5.
+        // Extended Control Code Set 1(G2 Table)
+        switch (mCommand) {
+            case Const.CODE_G2_TSP:
+                // TODO : TSP is the Transparent space
+                break;
+            case Const.CODE_G2_NBTSP:
+                // TODO : NBTSP is Non-Breaking Transparent Space.
+                break;
+            case Const.CODE_G2_BLK:
+                // TODO : BLK indicates a solid block which fills the entire character block
+                // TODO : with a solid foreground color.
+                break;
+            default:
+                break;
+        }
+        return pos;
+    }
+
+    private int parseG3(byte[] data, int pos) {
+        // For the details of C3 code group, see CEA-708B Section 7.4.6.
+        // Future characters and icons(G3 Table)
+        if (mCommand == Const.CODE_G3_CC) {
+            // TODO : [CC] icon with square corners
+        }
+
+        // Do nothing
+        return pos;
+    }
+
+    /**
+     * @hide
+     *
+     * Collection of CEA-708 structures.
+     */
+    private static class Const {
+
+        private Const() {
+        }
+
+        // For the details of the ranges of DTVCC code groups, see CEA-708B Table 6.
+        public static final int CODE_C0_RANGE_START = 0x00;
+        public static final int CODE_C0_RANGE_END = 0x1f;
+        public static final int CODE_C1_RANGE_START = 0x80;
+        public static final int CODE_C1_RANGE_END = 0x9f;
+        public static final int CODE_G0_RANGE_START = 0x20;
+        public static final int CODE_G0_RANGE_END = 0x7f;
+        public static final int CODE_G1_RANGE_START = 0xa0;
+        public static final int CODE_G1_RANGE_END = 0xff;
+        public static final int CODE_C2_RANGE_START = 0x00;
+        public static final int CODE_C2_RANGE_END = 0x1f;
+        public static final int CODE_C3_RANGE_START = 0x80;
+        public static final int CODE_C3_RANGE_END = 0x9f;
+        public static final int CODE_G2_RANGE_START = 0x20;
+        public static final int CODE_G2_RANGE_END = 0x7f;
+        public static final int CODE_G3_RANGE_START = 0xa0;
+        public static final int CODE_G3_RANGE_END = 0xff;
+
+        // The following ranges are defined in CEA-708B Section 7.4.1.
+        public static final int CODE_C0_SKIP2_RANGE_START = 0x18;
+        public static final int CODE_C0_SKIP2_RANGE_END = 0x1f;
+        public static final int CODE_C0_SKIP1_RANGE_START = 0x10;
+        public static final int CODE_C0_SKIP1_RANGE_END = 0x17;
+
+        // The following ranges are defined in CEA-708B Section 7.4.7.
+        public static final int CODE_C2_SKIP0_RANGE_START = 0x00;
+        public static final int CODE_C2_SKIP0_RANGE_END = 0x07;
+        public static final int CODE_C2_SKIP1_RANGE_START = 0x08;
+        public static final int CODE_C2_SKIP1_RANGE_END = 0x0f;
+        public static final int CODE_C2_SKIP2_RANGE_START = 0x10;
+        public static final int CODE_C2_SKIP2_RANGE_END = 0x17;
+        public static final int CODE_C2_SKIP3_RANGE_START = 0x18;
+        public static final int CODE_C2_SKIP3_RANGE_END = 0x1f;
+
+        // The following ranges are defined in CEA-708B Section 7.4.8.
+        public static final int CODE_C3_SKIP4_RANGE_START = 0x80;
+        public static final int CODE_C3_SKIP4_RANGE_END = 0x87;
+        public static final int CODE_C3_SKIP5_RANGE_START = 0x88;
+        public static final int CODE_C3_SKIP5_RANGE_END = 0x8f;
+
+        // The following values are the special characters of CEA-708 spec.
+        public static final int CODE_C0_NUL = 0x00;
+        public static final int CODE_C0_ETX = 0x03;
+        public static final int CODE_C0_BS = 0x08;
+        public static final int CODE_C0_FF = 0x0c;
+        public static final int CODE_C0_CR = 0x0d;
+        public static final int CODE_C0_HCR = 0x0e;
+        public static final int CODE_C0_EXT1 = 0x10;
+        public static final int CODE_C0_P16 = 0x18;
+        public static final int CODE_G0_MUSICNOTE = 0x7f;
+        public static final int CODE_G2_TSP = 0x20;
+        public static final int CODE_G2_NBTSP = 0x21;
+        public static final int CODE_G2_BLK = 0x30;
+        public static final int CODE_G3_CC = 0xa0;
+
+        // The following values are the command bits of CEA-708 spec.
+        public static final int CODE_C1_CW0 = 0x80;
+        public static final int CODE_C1_CW1 = 0x81;
+        public static final int CODE_C1_CW2 = 0x82;
+        public static final int CODE_C1_CW3 = 0x83;
+        public static final int CODE_C1_CW4 = 0x84;
+        public static final int CODE_C1_CW5 = 0x85;
+        public static final int CODE_C1_CW6 = 0x86;
+        public static final int CODE_C1_CW7 = 0x87;
+        public static final int CODE_C1_CLW = 0x88;
+        public static final int CODE_C1_DSW = 0x89;
+        public static final int CODE_C1_HDW = 0x8a;
+        public static final int CODE_C1_TGW = 0x8b;
+        public static final int CODE_C1_DLW = 0x8c;
+        public static final int CODE_C1_DLY = 0x8d;
+        public static final int CODE_C1_DLC = 0x8e;
+        public static final int CODE_C1_RST = 0x8f;
+        public static final int CODE_C1_SPA = 0x90;
+        public static final int CODE_C1_SPC = 0x91;
+        public static final int CODE_C1_SPL = 0x92;
+        public static final int CODE_C1_SWA = 0x97;
+        public static final int CODE_C1_DF0 = 0x98;
+        public static final int CODE_C1_DF1 = 0x99;
+        public static final int CODE_C1_DF2 = 0x9a;
+        public static final int CODE_C1_DF3 = 0x9b;
+        public static final int CODE_C1_DF4 = 0x9c;
+        public static final int CODE_C1_DF5 = 0x9d;
+        public static final int CODE_C1_DF6 = 0x9e;
+        public static final int CODE_C1_DF7 = 0x9f;
+    }
+
+    /**
+     * @hide
+     *
+     * CEA-708B-specific color.
+     */
+    public static class CaptionColor {
+        public static final int OPACITY_SOLID = 0;
+        public static final int OPACITY_FLASH = 1;
+        public static final int OPACITY_TRANSLUCENT = 2;
+        public static final int OPACITY_TRANSPARENT = 3;
+
+        private static final int[] COLOR_MAP = new int[] { 0x00, 0x0f, 0xf0, 0xff };
+        private static final int[] OPACITY_MAP = new int[] { 0xff, 0xfe, 0x80, 0x00 };
+
+        public final int opacity;
+        public final int red;
+        public final int green;
+        public final int blue;
+
+        public CaptionColor(int opacity, int red, int green, int blue) {
+            this.opacity = opacity;
+            this.red = red;
+            this.green = green;
+            this.blue = blue;
+        }
+
+        public int getArgbValue() {
+            return Color.argb(
+                    OPACITY_MAP[opacity], COLOR_MAP[red], COLOR_MAP[green], COLOR_MAP[blue]);
+        }
+    }
+
+    /**
+     * @hide
+     *
+     * Caption event generated by {@link Cea708CCParser}.
+     */
+    public static class CaptionEvent {
+        public final int type;
+        public final Object obj;
+
+        public CaptionEvent(int type, Object obj) {
+            this.type = type;
+            this.obj = obj;
+        }
+    }
+
+    /**
+     * @hide
+     *
+     * Pen style information.
+     */
+    public static class CaptionPenAttr {
+        // Pen sizes
+        public static final int PEN_SIZE_SMALL = 0;
+        public static final int PEN_SIZE_STANDARD = 1;
+        public static final int PEN_SIZE_LARGE = 2;
+
+        // Offsets
+        public static final int OFFSET_SUBSCRIPT = 0;
+        public static final int OFFSET_NORMAL = 1;
+        public static final int OFFSET_SUPERSCRIPT = 2;
+
+        public final int penSize;
+        public final int penOffset;
+        public final int textTag;
+        public final int fontTag;
+        public final int edgeType;
+        public final boolean underline;
+        public final boolean italic;
+
+        public CaptionPenAttr(int penSize, int penOffset, int textTag, int fontTag, int edgeType,
+                boolean underline, boolean italic) {
+            this.penSize = penSize;
+            this.penOffset = penOffset;
+            this.textTag = textTag;
+            this.fontTag = fontTag;
+            this.edgeType = edgeType;
+            this.underline = underline;
+            this.italic = italic;
+        }
+    }
+
+    /**
+     * @hide
+     *
+     * {@link CaptionColor} objects that indicate the foreground, background, and edge color of a
+     * pen.
+     */
+    public static class CaptionPenColor {
+        public final CaptionColor foregroundColor;
+        public final CaptionColor backgroundColor;
+        public final CaptionColor edgeColor;
+
+        public CaptionPenColor(CaptionColor foregroundColor, CaptionColor backgroundColor,
+                CaptionColor edgeColor) {
+            this.foregroundColor = foregroundColor;
+            this.backgroundColor = backgroundColor;
+            this.edgeColor = edgeColor;
+        }
+    }
+
+    /**
+     * @hide
+     *
+     * Location information of a pen.
+     */
+    public static class CaptionPenLocation {
+        public final int row;
+        public final int column;
+
+        public CaptionPenLocation(int row, int column) {
+            this.row = row;
+            this.column = column;
+        }
+    }
+
+    /**
+     * @hide
+     *
+     * Attributes of a caption window, which is defined in CEA-708B.
+     */
+    public static class CaptionWindowAttr {
+        public final CaptionColor fillColor;
+        public final CaptionColor borderColor;
+        public final int borderType;
+        public final boolean wordWrap;
+        public final int printDirection;
+        public final int scrollDirection;
+        public final int justify;
+        public final int effectDirection;
+        public final int effectSpeed;
+        public final int displayEffect;
+
+        public CaptionWindowAttr(CaptionColor fillColor, CaptionColor borderColor, int borderType,
+                boolean wordWrap, int printDirection, int scrollDirection, int justify,
+                int effectDirection,
+                int effectSpeed, int displayEffect) {
+            this.fillColor = fillColor;
+            this.borderColor = borderColor;
+            this.borderType = borderType;
+            this.wordWrap = wordWrap;
+            this.printDirection = printDirection;
+            this.scrollDirection = scrollDirection;
+            this.justify = justify;
+            this.effectDirection = effectDirection;
+            this.effectSpeed = effectSpeed;
+            this.displayEffect = displayEffect;
+        }
+    }
+
+    /**
+     * @hide
+     *
+     * Construction information of the caption window of CEA-708B.
+     */
+    public static class CaptionWindow {
+        public final int id;
+        public final boolean visible;
+        public final boolean rowLock;
+        public final boolean columnLock;
+        public final int priority;
+        public final boolean relativePositioning;
+        public final int anchorVertical;
+        public final int anchorHorizontal;
+        public final int anchorId;
+        public final int rowCount;
+        public final int columnCount;
+        public final int penStyle;
+        public final int windowStyle;
+
+        public CaptionWindow(int id, boolean visible,
+                boolean rowLock, boolean columnLock, int priority, boolean relativePositioning,
+                int anchorVertical, int anchorHorizontal, int anchorId,
+                int rowCount, int columnCount, int penStyle, int windowStyle) {
+            this.id = id;
+            this.visible = visible;
+            this.rowLock = rowLock;
+            this.columnLock = columnLock;
+            this.priority = priority;
+            this.relativePositioning = relativePositioning;
+            this.anchorVertical = anchorVertical;
+            this.anchorHorizontal = anchorHorizontal;
+            this.anchorId = anchorId;
+            this.rowCount = rowCount;
+            this.columnCount = columnCount;
+            this.penStyle = penStyle;
+            this.windowStyle = windowStyle;
+        }
+    }
+}
+
+/**
+ * Widget capable of rendering CEA-708 closed captions.
+ *
+ * @hide
+ */
+class Cea708CCWidget extends ClosedCaptionWidget implements Cea708CCParser.DisplayListener {
+    private final CCHandler mCCHandler;
+
+    public Cea708CCWidget(Context context) {
+        this(context, null);
+    }
+
+    public Cea708CCWidget(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public Cea708CCWidget(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public Cea708CCWidget(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+
+        mCCHandler = new CCHandler((CCLayout) mClosedCaptionLayout);
+    }
+
+    @Override
+    public ClosedCaptionLayout createCaptionLayout(Context context) {
+        return new CCLayout(context);
+    }
+
+    @Override
+    public void emitEvent(Cea708CCParser.CaptionEvent event) {
+        mCCHandler.processCaptionEvent(event);
+
+        setSize(getWidth(), getHeight());
+
+        if (mListener != null) {
+            mListener.onChanged(this);
+        }
+    }
+
+    @Override
+    public void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        ((ViewGroup) mClosedCaptionLayout).draw(canvas);
+    }
+
+    /**
+     * @hide
+     *
+     * A layout that scales its children using the given percentage value.
+     */
+    static class ScaledLayout extends ViewGroup {
+        private static final String TAG = "ScaledLayout";
+        private static final boolean DEBUG = false;
+        private static final Comparator<Rect> mRectTopLeftSorter = new Comparator<Rect>() {
+            @Override
+            public int compare(Rect lhs, Rect rhs) {
+                if (lhs.top != rhs.top) {
+                    return lhs.top - rhs.top;
+                } else {
+                    return lhs.left - rhs.left;
+                }
+            }
+        };
+
+        private Rect[] mRectArray;
+
+        public ScaledLayout(Context context) {
+            super(context);
+        }
+
+        /**
+         * @hide
+         *
+         * ScaledLayoutParams stores the four scale factors.
+         * <br>
+         * Vertical coordinate system:   (scaleStartRow * 100) % ~ (scaleEndRow * 100) %
+         * Horizontal coordinate system: (scaleStartCol * 100) % ~ (scaleEndCol * 100) %
+         * <br>
+         * In XML, for example,
+         * <pre>
+         * {@code
+         * <View
+         *     app:layout_scaleStartRow="0.1"
+         *     app:layout_scaleEndRow="0.5"
+         *     app:layout_scaleStartCol="0.4"
+         *     app:layout_scaleEndCol="1" />
+         * }
+         * </pre>
+         */
+        static class ScaledLayoutParams extends ViewGroup.LayoutParams {
+            public static final float SCALE_UNSPECIFIED = -1;
+            public float scaleStartRow;
+            public float scaleEndRow;
+            public float scaleStartCol;
+            public float scaleEndCol;
+
+            public ScaledLayoutParams(float scaleStartRow, float scaleEndRow,
+                    float scaleStartCol, float scaleEndCol) {
+                super(MATCH_PARENT, MATCH_PARENT);
+                this.scaleStartRow = scaleStartRow;
+                this.scaleEndRow = scaleEndRow;
+                this.scaleStartCol = scaleStartCol;
+                this.scaleEndCol = scaleEndCol;
+            }
+
+            public ScaledLayoutParams(Context context, AttributeSet attrs) {
+                super(MATCH_PARENT, MATCH_PARENT);
+            }
+        }
+
+        @Override
+        public LayoutParams generateLayoutParams(AttributeSet attrs) {
+            return new ScaledLayoutParams(getContext(), attrs);
+        }
+
+        @Override
+        protected boolean checkLayoutParams(LayoutParams p) {
+            return (p instanceof ScaledLayoutParams);
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
+            int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
+            int width = widthSpecSize - getPaddingLeft() - getPaddingRight();
+            int height = heightSpecSize - getPaddingTop() - getPaddingBottom();
+            if (DEBUG) {
+                Log.d(TAG, String.format("onMeasure width: %d, height: %d", width, height));
+            }
+            int count = getChildCount();
+            mRectArray = new Rect[count];
+            for (int i = 0; i < count; ++i) {
+                View child = getChildAt(i);
+                ViewGroup.LayoutParams params = child.getLayoutParams();
+                float scaleStartRow, scaleEndRow, scaleStartCol, scaleEndCol;
+                if (!(params instanceof ScaledLayoutParams)) {
+                    throw new RuntimeException(
+                            "A child of ScaledLayout cannot have the UNSPECIFIED scale factors");
+                }
+                scaleStartRow = ((ScaledLayoutParams) params).scaleStartRow;
+                scaleEndRow = ((ScaledLayoutParams) params).scaleEndRow;
+                scaleStartCol = ((ScaledLayoutParams) params).scaleStartCol;
+                scaleEndCol = ((ScaledLayoutParams) params).scaleEndCol;
+                if (scaleStartRow < 0 || scaleStartRow > 1) {
+                    throw new RuntimeException("A child of ScaledLayout should have a range of "
+                            + "scaleStartRow between 0 and 1");
+                }
+                if (scaleEndRow < scaleStartRow || scaleStartRow > 1) {
+                    throw new RuntimeException("A child of ScaledLayout should have a range of "
+                            + "scaleEndRow between scaleStartRow and 1");
+                }
+                if (scaleEndCol < 0 || scaleEndCol > 1) {
+                    throw new RuntimeException("A child of ScaledLayout should have a range of "
+                            + "scaleStartCol between 0 and 1");
+                }
+                if (scaleEndCol < scaleStartCol || scaleEndCol > 1) {
+                    throw new RuntimeException("A child of ScaledLayout should have a range of "
+                            + "scaleEndCol between scaleStartCol and 1");
+                }
+                if (DEBUG) {
+                    Log.d(TAG, String.format("onMeasure child scaleStartRow: %f scaleEndRow: %f "
+                                    + "scaleStartCol: %f scaleEndCol: %f",
+                            scaleStartRow, scaleEndRow, scaleStartCol, scaleEndCol));
+                }
+                mRectArray[i] = new Rect((int) (scaleStartCol * width), (int) (scaleStartRow
+                        * height), (int) (scaleEndCol * width), (int) (scaleEndRow * height));
+                int childWidthSpec = MeasureSpec.makeMeasureSpec(
+                        (int) (width * (scaleEndCol - scaleStartCol)), MeasureSpec.EXACTLY);
+                int childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+                child.measure(childWidthSpec, childHeightSpec);
+
+                // If the height of the measured child view is bigger than the height of the
+                // calculated region by the given ScaleLayoutParams, the height of the region should
+                // be increased to fit the size of the child view.
+                if (child.getMeasuredHeight() > mRectArray[i].height()) {
+                    int overflowedHeight = child.getMeasuredHeight() - mRectArray[i].height();
+                    overflowedHeight = (overflowedHeight + 1) / 2;
+                    mRectArray[i].bottom += overflowedHeight;
+                    mRectArray[i].top -= overflowedHeight;
+                    if (mRectArray[i].top < 0) {
+                        mRectArray[i].bottom -= mRectArray[i].top;
+                        mRectArray[i].top = 0;
+                    }
+                    if (mRectArray[i].bottom > height) {
+                        mRectArray[i].top -= mRectArray[i].bottom - height;
+                        mRectArray[i].bottom = height;
+                    }
+                }
+                childHeightSpec = MeasureSpec.makeMeasureSpec(
+                        (int) (height * (scaleEndRow - scaleStartRow)), MeasureSpec.EXACTLY);
+                child.measure(childWidthSpec, childHeightSpec);
+            }
+
+            // Avoid overlapping rectangles.
+            // Step 1. Sort rectangles by position (top-left).
+            int visibleRectCount = 0;
+            int[] visibleRectGroup = new int[count];
+            Rect[] visibleRectArray = new Rect[count];
+            for (int i = 0; i < count; ++i) {
+                if (getChildAt(i).getVisibility() == View.VISIBLE) {
+                    visibleRectGroup[visibleRectCount] = visibleRectCount;
+                    visibleRectArray[visibleRectCount] = mRectArray[i];
+                    ++visibleRectCount;
+                }
+            }
+            Arrays.sort(visibleRectArray, 0, visibleRectCount, mRectTopLeftSorter);
+
+            // Step 2. Move down if there are overlapping rectangles.
+            for (int i = 0; i < visibleRectCount - 1; ++i) {
+                for (int j = i + 1; j < visibleRectCount; ++j) {
+                    if (Rect.intersects(visibleRectArray[i], visibleRectArray[j])) {
+                        visibleRectGroup[j] = visibleRectGroup[i];
+                        visibleRectArray[j].set(visibleRectArray[j].left,
+                                visibleRectArray[i].bottom,
+                                visibleRectArray[j].right,
+                                visibleRectArray[i].bottom + visibleRectArray[j].height());
+                    }
+                }
+            }
+
+            // Step 3. Move up if there is any overflowed rectangle.
+            for (int i = visibleRectCount - 1; i >= 0; --i) {
+                if (visibleRectArray[i].bottom > height) {
+                    int overflowedHeight = visibleRectArray[i].bottom - height;
+                    for (int j = 0; j <= i; ++j) {
+                        if (visibleRectGroup[i] == visibleRectGroup[j]) {
+                            visibleRectArray[j].set(visibleRectArray[j].left,
+                                    visibleRectArray[j].top - overflowedHeight,
+                                    visibleRectArray[j].right,
+                                    visibleRectArray[j].bottom - overflowedHeight);
+                        }
+                    }
+                }
+            }
+            setMeasuredDimension(widthSpecSize, heightSpecSize);
+        }
+
+        @Override
+        protected void onLayout(boolean changed, int l, int t, int r, int b) {
+            int paddingLeft = getPaddingLeft();
+            int paddingTop = getPaddingTop();
+            int count = getChildCount();
+            for (int i = 0; i < count; ++i) {
+                View child = getChildAt(i);
+                if (child.getVisibility() != GONE) {
+                    int childLeft = paddingLeft + mRectArray[i].left;
+                    int childTop = paddingTop + mRectArray[i].top;
+                    int childBottom = paddingLeft + mRectArray[i].bottom;
+                    int childRight = paddingTop + mRectArray[i].right;
+                    if (DEBUG) {
+                        Log.d(TAG, String.format(
+                                "child layout bottom: %d left: %d right: %d top: %d",
+                                childBottom, childLeft, childRight, childTop));
+                    }
+                    child.layout(childLeft, childTop, childRight, childBottom);
+                }
+            }
+        }
+
+        @Override
+        public void dispatchDraw(Canvas canvas) {
+            int paddingLeft = getPaddingLeft();
+            int paddingTop = getPaddingTop();
+            int count = getChildCount();
+            for (int i = 0; i < count; ++i) {
+                View child = getChildAt(i);
+                if (child.getVisibility() != GONE) {
+                    if (i >= mRectArray.length) {
+                        break;
+                    }
+                    int childLeft = paddingLeft + mRectArray[i].left;
+                    int childTop = paddingTop + mRectArray[i].top;
+                    final int saveCount = canvas.save();
+                    canvas.translate(childLeft, childTop);
+                    child.draw(canvas);
+                    canvas.restoreToCount(saveCount);
+                }
+            }
+        }
+    }
+
+    /**
+     * @hide
+     *
+     * Layout containing the safe title area that helps the closed captions look more prominent.
+     *
+     * <p>This is required by CEA-708B.
+     */
+    static class CCLayout extends ScaledLayout implements ClosedCaptionLayout {
+        private static final float SAFE_TITLE_AREA_SCALE_START_X = 0.1f;
+        private static final float SAFE_TITLE_AREA_SCALE_END_X = 0.9f;
+        private static final float SAFE_TITLE_AREA_SCALE_START_Y = 0.1f;
+        private static final float SAFE_TITLE_AREA_SCALE_END_Y = 0.9f;
+
+        private final ScaledLayout mSafeTitleAreaLayout;
+
+        public CCLayout(Context context) {
+            super(context);
+
+            mSafeTitleAreaLayout = new ScaledLayout(context);
+            addView(mSafeTitleAreaLayout, new ScaledLayout.ScaledLayoutParams(
+                    SAFE_TITLE_AREA_SCALE_START_X, SAFE_TITLE_AREA_SCALE_END_X,
+                    SAFE_TITLE_AREA_SCALE_START_Y, SAFE_TITLE_AREA_SCALE_END_Y));
+        }
+
+        public void addOrUpdateViewToSafeTitleArea(CCWindowLayout captionWindowLayout,
+                ScaledLayoutParams scaledLayoutParams) {
+            int index = mSafeTitleAreaLayout.indexOfChild(captionWindowLayout);
+            if (index < 0) {
+                mSafeTitleAreaLayout.addView(captionWindowLayout, scaledLayoutParams);
+                return;
+            }
+            mSafeTitleAreaLayout.updateViewLayout(captionWindowLayout, scaledLayoutParams);
+        }
+
+        public void removeViewFromSafeTitleArea(CCWindowLayout captionWindowLayout) {
+            mSafeTitleAreaLayout.removeView(captionWindowLayout);
+        }
+
+        public void setCaptionStyle(CaptionStyle style) {
+            final int count = mSafeTitleAreaLayout.getChildCount();
+            for (int i = 0; i < count; ++i) {
+                final CCWindowLayout windowLayout =
+                        (CCWindowLayout) mSafeTitleAreaLayout.getChildAt(i);
+                windowLayout.setCaptionStyle(style);
+            }
+        }
+
+        public void setFontScale(float fontScale) {
+            final int count = mSafeTitleAreaLayout.getChildCount();
+            for (int i = 0; i < count; ++i) {
+                final CCWindowLayout windowLayout =
+                        (CCWindowLayout) mSafeTitleAreaLayout.getChildAt(i);
+                windowLayout.setFontScale(fontScale);
+            }
+        }
+    }
+
+    /**
+     * @hide
+     *
+     * Renders the selected CC track.
+     */
+    static class CCHandler implements Handler.Callback {
+        // TODO: Remaining works
+        // CaptionTrackRenderer does not support the full spec of CEA-708. The remaining works are
+        // described in the follows.
+        // C0 Table: Backspace, FF, and HCR are not supported. The rule for P16 is not standardized
+        //           but it is handled as EUC-KR charset for Korea broadcasting.
+        // C1 Table: All the styles of windows and pens except underline, italic, pen size, and pen
+        //           offset specified in CEA-708 are ignored and this follows system wide CC
+        //           preferences for look and feel. SetPenLocation is not implemented.
+        // G2 Table: TSP, NBTSP and BLK are not supported.
+        // Text/commands: Word wrapping, fonts, row and column locking are not supported.
+
+        private static final String TAG = "CCHandler";
+        private static final boolean DEBUG = false;
+
+        private static final int TENTHS_OF_SECOND_IN_MILLIS = 100;
+
+        // According to CEA-708B, there can exist up to 8 caption windows.
+        private static final int CAPTION_WINDOWS_MAX = 8;
+        private static final int CAPTION_ALL_WINDOWS_BITMAP = 255;
+
+        private static final int MSG_DELAY_CANCEL = 1;
+        private static final int MSG_CAPTION_CLEAR = 2;
+
+        private static final long CAPTION_CLEAR_INTERVAL_MS = 60000;
+
+        private final CCLayout mCCLayout;
+        private boolean mIsDelayed = false;
+        private CCWindowLayout mCurrentWindowLayout;
+        private final CCWindowLayout[] mCaptionWindowLayouts =
+                new CCWindowLayout[CAPTION_WINDOWS_MAX];
+        private final ArrayList<Cea708CCParser.CaptionEvent> mPendingCaptionEvents
+                = new ArrayList<>();
+        private final Handler mHandler;
+
+        public CCHandler(CCLayout ccLayout) {
+            mCCLayout = ccLayout;
+            mHandler = new Handler(this);
+        }
+
+        @Override
+        public boolean handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_DELAY_CANCEL:
+                    delayCancel();
+                    return true;
+                case MSG_CAPTION_CLEAR:
+                    clearWindows(CAPTION_ALL_WINDOWS_BITMAP);
+                    return true;
+            }
+            return false;
+        }
+
+        public void processCaptionEvent(Cea708CCParser.CaptionEvent event) {
+            if (mIsDelayed) {
+                mPendingCaptionEvents.add(event);
+                return;
+            }
+            switch (event.type) {
+                case Cea708CCParser.CAPTION_EMIT_TYPE_BUFFER:
+                    sendBufferToCurrentWindow((String) event.obj);
+                    break;
+                case Cea708CCParser.CAPTION_EMIT_TYPE_CONTROL:
+                    sendControlToCurrentWindow((char) event.obj);
+                    break;
+                case Cea708CCParser.CAPTION_EMIT_TYPE_COMMAND_CWX:
+                    setCurrentWindowLayout((int) event.obj);
+                    break;
+                case Cea708CCParser.CAPTION_EMIT_TYPE_COMMAND_CLW:
+                    clearWindows((int) event.obj);
+                    break;
+                case Cea708CCParser.CAPTION_EMIT_TYPE_COMMAND_DSW:
+                    displayWindows((int) event.obj);
+                    break;
+                case Cea708CCParser.CAPTION_EMIT_TYPE_COMMAND_HDW:
+                    hideWindows((int) event.obj);
+                    break;
+                case Cea708CCParser.CAPTION_EMIT_TYPE_COMMAND_TGW:
+                    toggleWindows((int) event.obj);
+                    break;
+                case Cea708CCParser.CAPTION_EMIT_TYPE_COMMAND_DLW:
+                    deleteWindows((int) event.obj);
+                    break;
+                case Cea708CCParser.CAPTION_EMIT_TYPE_COMMAND_DLY:
+                    delay((int) event.obj);
+                    break;
+                case Cea708CCParser.CAPTION_EMIT_TYPE_COMMAND_DLC:
+                    delayCancel();
+                    break;
+                case Cea708CCParser.CAPTION_EMIT_TYPE_COMMAND_RST:
+                    reset();
+                    break;
+                case Cea708CCParser.CAPTION_EMIT_TYPE_COMMAND_SPA:
+                    setPenAttr((Cea708CCParser.CaptionPenAttr) event.obj);
+                    break;
+                case Cea708CCParser.CAPTION_EMIT_TYPE_COMMAND_SPC:
+                    setPenColor((Cea708CCParser.CaptionPenColor) event.obj);
+                    break;
+                case Cea708CCParser.CAPTION_EMIT_TYPE_COMMAND_SPL:
+                    setPenLocation((Cea708CCParser.CaptionPenLocation) event.obj);
+                    break;
+                case Cea708CCParser.CAPTION_EMIT_TYPE_COMMAND_SWA:
+                    setWindowAttr((Cea708CCParser.CaptionWindowAttr) event.obj);
+                    break;
+                case Cea708CCParser.CAPTION_EMIT_TYPE_COMMAND_DFX:
+                    defineWindow((Cea708CCParser.CaptionWindow) event.obj);
+                    break;
+            }
+        }
+
+        // The window related caption commands
+        private void setCurrentWindowLayout(int windowId) {
+            if (windowId < 0 || windowId >= mCaptionWindowLayouts.length) {
+                return;
+            }
+            CCWindowLayout windowLayout = mCaptionWindowLayouts[windowId];
+            if (windowLayout == null) {
+                return;
+            }
+            if (DEBUG) {
+                Log.d(TAG, "setCurrentWindowLayout to " + windowId);
+            }
+            mCurrentWindowLayout = windowLayout;
+        }
+
+        // Each bit of windowBitmap indicates a window.
+        // If a bit is set, the window id is the same as the number of the trailing zeros of the
+        // bit.
+        private ArrayList<CCWindowLayout> getWindowsFromBitmap(int windowBitmap) {
+            ArrayList<CCWindowLayout> windows = new ArrayList<>();
+            for (int i = 0; i < CAPTION_WINDOWS_MAX; ++i) {
+                if ((windowBitmap & (1 << i)) != 0) {
+                    CCWindowLayout windowLayout = mCaptionWindowLayouts[i];
+                    if (windowLayout != null) {
+                        windows.add(windowLayout);
+                    }
+                }
+            }
+            return windows;
+        }
+
+        private void clearWindows(int windowBitmap) {
+            if (windowBitmap == 0) {
+                return;
+            }
+            for (CCWindowLayout windowLayout : getWindowsFromBitmap(windowBitmap)) {
+                windowLayout.clear();
+            }
+        }
+
+        private void displayWindows(int windowBitmap) {
+            if (windowBitmap == 0) {
+                return;
+            }
+            for (CCWindowLayout windowLayout : getWindowsFromBitmap(windowBitmap)) {
+                windowLayout.show();
+            }
+        }
+
+        private void hideWindows(int windowBitmap) {
+            if (windowBitmap == 0) {
+                return;
+            }
+            for (CCWindowLayout windowLayout : getWindowsFromBitmap(windowBitmap)) {
+                windowLayout.hide();
+            }
+        }
+
+        private void toggleWindows(int windowBitmap) {
+            if (windowBitmap == 0) {
+                return;
+            }
+            for (CCWindowLayout windowLayout : getWindowsFromBitmap(windowBitmap)) {
+                if (windowLayout.isShown()) {
+                    windowLayout.hide();
+                } else {
+                    windowLayout.show();
+                }
+            }
+        }
+
+        private void deleteWindows(int windowBitmap) {
+            if (windowBitmap == 0) {
+                return;
+            }
+            for (CCWindowLayout windowLayout : getWindowsFromBitmap(windowBitmap)) {
+                windowLayout.removeFromCaptionView();
+                mCaptionWindowLayouts[windowLayout.getCaptionWindowId()] = null;
+            }
+        }
+
+        public void reset() {
+            mCurrentWindowLayout = null;
+            mIsDelayed = false;
+            mPendingCaptionEvents.clear();
+            for (int i = 0; i < CAPTION_WINDOWS_MAX; ++i) {
+                if (mCaptionWindowLayouts[i] != null) {
+                    mCaptionWindowLayouts[i].removeFromCaptionView();
+                }
+                mCaptionWindowLayouts[i] = null;
+            }
+            mCCLayout.setVisibility(View.INVISIBLE);
+            mHandler.removeMessages(MSG_CAPTION_CLEAR);
+        }
+
+        private void setWindowAttr(Cea708CCParser.CaptionWindowAttr windowAttr) {
+            if (mCurrentWindowLayout != null) {
+                mCurrentWindowLayout.setWindowAttr(windowAttr);
+            }
+        }
+
+        private void defineWindow(Cea708CCParser.CaptionWindow window) {
+            if (window == null) {
+                return;
+            }
+            int windowId = window.id;
+            if (windowId < 0 || windowId >= mCaptionWindowLayouts.length) {
+                return;
+            }
+            CCWindowLayout windowLayout = mCaptionWindowLayouts[windowId];
+            if (windowLayout == null) {
+                windowLayout = new CCWindowLayout(mCCLayout.getContext());
+            }
+            windowLayout.initWindow(mCCLayout, window);
+            mCurrentWindowLayout = mCaptionWindowLayouts[windowId] = windowLayout;
+        }
+
+        // The job related caption commands
+        private void delay(int tenthsOfSeconds) {
+            if (tenthsOfSeconds < 0 || tenthsOfSeconds > 255) {
+                return;
+            }
+            mIsDelayed = true;
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_DELAY_CANCEL),
+                    tenthsOfSeconds * TENTHS_OF_SECOND_IN_MILLIS);
+        }
+
+        private void delayCancel() {
+            mIsDelayed = false;
+            processPendingBuffer();
+        }
+
+        private void processPendingBuffer() {
+            for (Cea708CCParser.CaptionEvent event : mPendingCaptionEvents) {
+                processCaptionEvent(event);
+            }
+            mPendingCaptionEvents.clear();
+        }
+
+        // The implicit write caption commands
+        private void sendControlToCurrentWindow(char control) {
+            if (mCurrentWindowLayout != null) {
+                mCurrentWindowLayout.sendControl(control);
+            }
+        }
+
+        private void sendBufferToCurrentWindow(String buffer) {
+            if (mCurrentWindowLayout != null) {
+                mCurrentWindowLayout.sendBuffer(buffer);
+                mHandler.removeMessages(MSG_CAPTION_CLEAR);
+                mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CAPTION_CLEAR),
+                        CAPTION_CLEAR_INTERVAL_MS);
+            }
+        }
+
+        // The pen related caption commands
+        private void setPenAttr(Cea708CCParser.CaptionPenAttr attr) {
+            if (mCurrentWindowLayout != null) {
+                mCurrentWindowLayout.setPenAttr(attr);
+            }
+        }
+
+        private void setPenColor(Cea708CCParser.CaptionPenColor color) {
+            if (mCurrentWindowLayout != null) {
+                mCurrentWindowLayout.setPenColor(color);
+            }
+        }
+
+        private void setPenLocation(Cea708CCParser.CaptionPenLocation location) {
+            if (mCurrentWindowLayout != null) {
+                mCurrentWindowLayout.setPenLocation(location.row, location.column);
+            }
+        }
+    }
+
+    /**
+     * @hide
+     *
+     * Layout which renders a caption window of CEA-708B. It contains a {@link TextView} that takes
+     * care of displaying the actual CC text.
+     */
+    static class CCWindowLayout extends RelativeLayout implements View.OnLayoutChangeListener {
+        private static final String TAG = "CCWindowLayout";
+
+        private static final float PROPORTION_PEN_SIZE_SMALL = .75f;
+        private static final float PROPORTION_PEN_SIZE_LARGE = 1.25f;
+
+        // The following values indicates the maximum cell number of a window.
+        private static final int ANCHOR_RELATIVE_POSITIONING_MAX = 99;
+        private static final int ANCHOR_VERTICAL_MAX = 74;
+        private static final int ANCHOR_HORIZONTAL_16_9_MAX = 209;
+        private static final int MAX_COLUMN_COUNT_16_9 = 42;
+
+        // The following values indicates a gravity of a window.
+        private static final int ANCHOR_MODE_DIVIDER = 3;
+        private static final int ANCHOR_HORIZONTAL_MODE_LEFT = 0;
+        private static final int ANCHOR_HORIZONTAL_MODE_CENTER = 1;
+        private static final int ANCHOR_HORIZONTAL_MODE_RIGHT = 2;
+        private static final int ANCHOR_VERTICAL_MODE_TOP = 0;
+        private static final int ANCHOR_VERTICAL_MODE_CENTER = 1;
+        private static final int ANCHOR_VERTICAL_MODE_BOTTOM = 2;
+
+        private CCLayout mCCLayout;
+
+        private CCView mCCView;
+        private CaptionStyle mCaptionStyle;
+        private int mRowLimit = 0;
+        private final SpannableStringBuilder mBuilder = new SpannableStringBuilder();
+        private final List<CharacterStyle> mCharacterStyles = new ArrayList<>();
+        private int mCaptionWindowId;
+        private int mRow = -1;
+        private float mFontScale;
+        private float mTextSize;
+        private String mWidestChar;
+        private int mLastCaptionLayoutWidth;
+        private int mLastCaptionLayoutHeight;
+
+        public CCWindowLayout(Context context) {
+            this(context, null);
+        }
+
+        public CCWindowLayout(Context context, AttributeSet attrs) {
+            this(context, attrs, 0);
+        }
+
+        public CCWindowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+            this(context, attrs, defStyleAttr, 0);
+        }
+
+        public CCWindowLayout(Context context, AttributeSet attrs, int defStyleAttr,
+                int defStyleRes) {
+            super(context, attrs, defStyleAttr, defStyleRes);
+
+            // Add a subtitle view to the layout.
+            mCCView = new CCView(context);
+            LayoutParams params = new RelativeLayout.LayoutParams(
+                    ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+            addView(mCCView, params);
+
+            // Set the system wide CC preferences to the subtitle view.
+            CaptioningManager captioningManager =
+                    (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE);
+            mFontScale = captioningManager.getFontScale();
+            setCaptionStyle(captioningManager.getUserStyle());
+            mCCView.setText("");
+            updateWidestChar();
+        }
+
+        public void setCaptionStyle(CaptionStyle style) {
+            mCaptionStyle = style;
+            mCCView.setCaptionStyle(style);
+        }
+
+        public void setFontScale(float fontScale) {
+            mFontScale = fontScale;
+            updateTextSize();
+        }
+
+        public int getCaptionWindowId() {
+            return mCaptionWindowId;
+        }
+
+        public void setCaptionWindowId(int captionWindowId) {
+            mCaptionWindowId = captionWindowId;
+        }
+
+        public void clear() {
+            clearText();
+            hide();
+        }
+
+        public void show() {
+            setVisibility(View.VISIBLE);
+            requestLayout();
+        }
+
+        public void hide() {
+            setVisibility(View.INVISIBLE);
+            requestLayout();
+        }
+
+        public void setPenAttr(Cea708CCParser.CaptionPenAttr penAttr) {
+            mCharacterStyles.clear();
+            if (penAttr.italic) {
+                mCharacterStyles.add(new StyleSpan(Typeface.ITALIC));
+            }
+            if (penAttr.underline) {
+                mCharacterStyles.add(new UnderlineSpan());
+            }
+            switch (penAttr.penSize) {
+                case Cea708CCParser.CaptionPenAttr.PEN_SIZE_SMALL:
+                    mCharacterStyles.add(new RelativeSizeSpan(PROPORTION_PEN_SIZE_SMALL));
+                    break;
+                case Cea708CCParser.CaptionPenAttr.PEN_SIZE_LARGE:
+                    mCharacterStyles.add(new RelativeSizeSpan(PROPORTION_PEN_SIZE_LARGE));
+                    break;
+            }
+            switch (penAttr.penOffset) {
+                case Cea708CCParser.CaptionPenAttr.OFFSET_SUBSCRIPT:
+                    mCharacterStyles.add(new SubscriptSpan());
+                    break;
+                case Cea708CCParser.CaptionPenAttr.OFFSET_SUPERSCRIPT:
+                    mCharacterStyles.add(new SuperscriptSpan());
+                    break;
+            }
+        }
+
+        public void setPenColor(Cea708CCParser.CaptionPenColor penColor) {
+            // TODO: apply pen colors or skip this and use the style of system wide CC style as is.
+        }
+
+        public void setPenLocation(int row, int column) {
+            // TODO: change the location of pen based on row and column both.
+            if (mRow >= 0) {
+                for (int r = mRow; r < row; ++r) {
+                    appendText("\n");
+                }
+            }
+            mRow = row;
+        }
+
+        public void setWindowAttr(Cea708CCParser.CaptionWindowAttr windowAttr) {
+            // TODO: apply window attrs or skip this and use the style of system wide CC style as
+            // is.
+        }
+
+        public void sendBuffer(String buffer) {
+            appendText(buffer);
+        }
+
+        public void sendControl(char control) {
+            // TODO: there are a bunch of ASCII-style control codes.
+        }
+
+        /**
+         * This method places the window on a given CaptionLayout along with the anchor of the
+         * window.
+         * <p>
+         * According to CEA-708B, the anchor id indicates the gravity of the window as the follows.
+         * For example, A value 7 of a anchor id says that a window is align with its parent bottom
+         * and is located at the center horizontally of its parent.
+         * </p>
+         * <h4>Anchor id and the gravity of a window</h4>
+         * <table>
+         *     <tr>
+         *         <th>GRAVITY</th>
+         *         <th>LEFT</th>
+         *         <th>CENTER_HORIZONTAL</th>
+         *         <th>RIGHT</th>
+         *     </tr>
+         *     <tr>
+         *         <th>TOP</th>
+         *         <td>0</td>
+         *         <td>1</td>
+         *         <td>2</td>
+         *     </tr>
+         *     <tr>
+         *         <th>CENTER_VERTICAL</th>
+         *         <td>3</td>
+         *         <td>4</td>
+         *         <td>5</td>
+         *     </tr>
+         *     <tr>
+         *         <th>BOTTOM</th>
+         *         <td>6</td>
+         *         <td>7</td>
+         *         <td>8</td>
+         *     </tr>
+         * </table>
+         * <p>
+         * In order to handle the gravity of a window, there are two steps. First, set the size of
+         * the window. Since the window will be positioned at ScaledLayout, the size factors are
+         * determined in a ratio. Second, set the gravity of the window. CaptionWindowLayout is
+         * inherited from RelativeLayout. Hence, we could set the gravity of its child view,
+         * SubtitleView.
+         * </p>
+         * <p>
+         * The gravity of the window is also related to its size. When it should be pushed to a one
+         * of the end of the window, like LEFT, RIGHT, TOP or BOTTOM, the anchor point should be a
+         * boundary of the window. When it should be pushed in the horizontal/vertical center of its
+         * container, the horizontal/vertical center point of the window should be the same as the
+         * anchor point.
+         * </p>
+         *
+         * @param ccLayout a given CaptionLayout, which contains a safe title area.
+         * @param captionWindow a given CaptionWindow, which stores the construction info of the
+         *                      window.
+         */
+        public void initWindow(CCLayout ccLayout, Cea708CCParser.CaptionWindow captionWindow) {
+            if (mCCLayout != ccLayout) {
+                if (mCCLayout != null) {
+                    mCCLayout.removeOnLayoutChangeListener(this);
+                }
+                mCCLayout = ccLayout;
+                mCCLayout.addOnLayoutChangeListener(this);
+                updateWidestChar();
+            }
+
+            // Both anchor vertical and horizontal indicates the position cell number of the window.
+            float scaleRow = (float) captionWindow.anchorVertical /
+                    (captionWindow.relativePositioning
+                            ? ANCHOR_RELATIVE_POSITIONING_MAX : ANCHOR_VERTICAL_MAX);
+
+            // Assumes it has a wide aspect ratio track.
+            float scaleCol = (float) captionWindow.anchorHorizontal /
+                    (captionWindow.relativePositioning ? ANCHOR_RELATIVE_POSITIONING_MAX
+                            : ANCHOR_HORIZONTAL_16_9_MAX);
+
+            // The range of scaleRow/Col need to be verified to be in [0, 1].
+            // Otherwise a RuntimeException will be raised in ScaledLayout.
+            if (scaleRow < 0 || scaleRow > 1) {
+                Log.i(TAG, "The vertical position of the anchor point should be at the range of 0 "
+                        + "and 1 but " + scaleRow);
+                scaleRow = Math.max(0, Math.min(scaleRow, 1));
+            }
+            if (scaleCol < 0 || scaleCol > 1) {
+                Log.i(TAG, "The horizontal position of the anchor point should be at the range of 0"
+                        + " and 1 but " + scaleCol);
+                scaleCol = Math.max(0, Math.min(scaleCol, 1));
+            }
+            int gravity = Gravity.CENTER;
+            int horizontalMode = captionWindow.anchorId % ANCHOR_MODE_DIVIDER;
+            int verticalMode = captionWindow.anchorId / ANCHOR_MODE_DIVIDER;
+            float scaleStartRow = 0;
+            float scaleEndRow = 1;
+            float scaleStartCol = 0;
+            float scaleEndCol = 1;
+            switch (horizontalMode) {
+                case ANCHOR_HORIZONTAL_MODE_LEFT:
+                    gravity = Gravity.LEFT;
+                    mCCView.setAlignment(Alignment.ALIGN_NORMAL);
+                    scaleStartCol = scaleCol;
+                    break;
+                case ANCHOR_HORIZONTAL_MODE_CENTER:
+                    float gap = Math.min(1 - scaleCol, scaleCol);
+
+                    // Since all TV sets use left text alignment instead of center text alignment
+                    // for this case, we follow the industry convention if possible.
+                    int columnCount = captionWindow.columnCount + 1;
+                    columnCount = Math.min(getScreenColumnCount(), columnCount);
+                    StringBuilder widestTextBuilder = new StringBuilder();
+                    for (int i = 0; i < columnCount; ++i) {
+                        widestTextBuilder.append(mWidestChar);
+                    }
+                    Paint paint = new Paint();
+                    paint.setTypeface(mCaptionStyle.getTypeface());
+                    paint.setTextSize(mTextSize);
+                    float maxWindowWidth = paint.measureText(widestTextBuilder.toString());
+                    float halfMaxWidthScale = mCCLayout.getWidth() > 0
+                            ? maxWindowWidth / 2.0f / (mCCLayout.getWidth() * 0.8f) : 0.0f;
+                    if (halfMaxWidthScale > 0f && halfMaxWidthScale < scaleCol) {
+                        // Calculate the expected max window size based on the column count of the
+                        // caption window multiplied by average alphabets char width, then align the
+                        // left side of the window with the left side of the expected max window.
+                        gravity = Gravity.LEFT;
+                        mCCView.setAlignment(Alignment.ALIGN_NORMAL);
+                        scaleStartCol = scaleCol - halfMaxWidthScale;
+                        scaleEndCol = 1.0f;
+                    } else {
+                        // The gap will be the minimum distance value of the distances from both
+                        // horizontal end points to the anchor point.
+                        // If scaleCol <= 0.5, the range of scaleCol is [0, the anchor point * 2].
+                        // If scaleCol > 0.5, the range of scaleCol is
+                        // [(1 - the anchor point) * 2, 1].
+                        // The anchor point is located at the horizontal center of the window in
+                        // both cases.
+                        gravity = Gravity.CENTER_HORIZONTAL;
+                        mCCView.setAlignment(Alignment.ALIGN_CENTER);
+                        scaleStartCol = scaleCol - gap;
+                        scaleEndCol = scaleCol + gap;
+                    }
+                    break;
+                case ANCHOR_HORIZONTAL_MODE_RIGHT:
+                    gravity = Gravity.RIGHT;
+                    mCCView.setAlignment(Alignment.ALIGN_RIGHT);
+                    scaleEndCol = scaleCol;
+                    break;
+            }
+            switch (verticalMode) {
+                case ANCHOR_VERTICAL_MODE_TOP:
+                    gravity |= Gravity.TOP;
+                    scaleStartRow = scaleRow;
+                    break;
+                case ANCHOR_VERTICAL_MODE_CENTER:
+                    gravity |= Gravity.CENTER_VERTICAL;
+
+                    // See the above comment.
+                    float gap = Math.min(1 - scaleRow, scaleRow);
+                    scaleStartRow = scaleRow - gap;
+                    scaleEndRow = scaleRow + gap;
+                    break;
+                case ANCHOR_VERTICAL_MODE_BOTTOM:
+                    gravity |= Gravity.BOTTOM;
+                    scaleEndRow = scaleRow;
+                    break;
+            }
+            mCCLayout.addOrUpdateViewToSafeTitleArea(this, new ScaledLayout
+                    .ScaledLayoutParams(scaleStartRow, scaleEndRow, scaleStartCol, scaleEndCol));
+            setCaptionWindowId(captionWindow.id);
+            setRowLimit(captionWindow.rowCount);
+            setGravity(gravity);
+            if (captionWindow.visible) {
+                show();
+            } else {
+                hide();
+            }
+        }
+
+        @Override
+        public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+                int oldTop, int oldRight, int oldBottom) {
+            int width = right - left;
+            int height = bottom - top;
+            if (width != mLastCaptionLayoutWidth || height != mLastCaptionLayoutHeight) {
+                mLastCaptionLayoutWidth = width;
+                mLastCaptionLayoutHeight = height;
+                updateTextSize();
+            }
+        }
+
+        private void updateWidestChar() {
+            Paint paint = new Paint();
+            paint.setTypeface(mCaptionStyle.getTypeface());
+            Charset latin1 = Charset.forName("ISO-8859-1");
+            float widestCharWidth = 0f;
+            for (int i = 0; i < 256; ++i) {
+                String ch = new String(new byte[]{(byte) i}, latin1);
+                float charWidth = paint.measureText(ch);
+                if (widestCharWidth < charWidth) {
+                    widestCharWidth = charWidth;
+                    mWidestChar = ch;
+                }
+            }
+            updateTextSize();
+        }
+
+        private void updateTextSize() {
+            if (mCCLayout == null) return;
+
+            // Calculate text size based on the max window size.
+            StringBuilder widestTextBuilder = new StringBuilder();
+            int screenColumnCount = getScreenColumnCount();
+            for (int i = 0; i < screenColumnCount; ++i) {
+                widestTextBuilder.append(mWidestChar);
+            }
+            String widestText = widestTextBuilder.toString();
+            Paint paint = new Paint();
+            paint.setTypeface(mCaptionStyle.getTypeface());
+            float startFontSize = 0f;
+            float endFontSize = 255f;
+            while (startFontSize < endFontSize) {
+                float testTextSize = (startFontSize + endFontSize) / 2f;
+                paint.setTextSize(testTextSize);
+                float width = paint.measureText(widestText);
+                if (mCCLayout.getWidth() * 0.8f > width) {
+                    startFontSize = testTextSize + 0.01f;
+                } else {
+                    endFontSize = testTextSize - 0.01f;
+                }
+            }
+            mTextSize = endFontSize * mFontScale;
+            mCCView.setTextSize(mTextSize);
+        }
+
+        private int getScreenColumnCount() {
+            // Assume it has a wide aspect ratio track.
+            return MAX_COLUMN_COUNT_16_9;
+        }
+
+        public void removeFromCaptionView() {
+            if (mCCLayout != null) {
+                mCCLayout.removeViewFromSafeTitleArea(this);
+                mCCLayout.removeOnLayoutChangeListener(this);
+                mCCLayout = null;
+            }
+        }
+
+        public void setText(String text) {
+            updateText(text, false);
+        }
+
+        public void appendText(String text) {
+            updateText(text, true);
+        }
+
+        public void clearText() {
+            mBuilder.clear();
+            mCCView.setText("");
+        }
+
+        private void updateText(String text, boolean appended) {
+            if (!appended) {
+                mBuilder.clear();
+            }
+            if (text != null && text.length() > 0) {
+                int length = mBuilder.length();
+                mBuilder.append(text);
+                for (CharacterStyle characterStyle : mCharacterStyles) {
+                    mBuilder.setSpan(characterStyle, length, mBuilder.length(),
+                            Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                }
+            }
+            String[] lines = TextUtils.split(mBuilder.toString(), "\n");
+
+            // Truncate text not to exceed the row limit.
+            // Plus one here since the range of the rows is [0, mRowLimit].
+            String truncatedText = TextUtils.join("\n", Arrays.copyOfRange(
+                    lines, Math.max(0, lines.length - (mRowLimit + 1)), lines.length));
+            mBuilder.delete(0, mBuilder.length() - truncatedText.length());
+
+            // Trim the buffer first then set text to CCView.
+            int start = 0, last = mBuilder.length() - 1;
+            int end = last;
+            while ((start <= end) && (mBuilder.charAt(start) <= ' ')) {
+                ++start;
+            }
+            while ((end >= start) && (mBuilder.charAt(end) <= ' ')) {
+                --end;
+            }
+            if (start == 0 && end == last) {
+                mCCView.setText(mBuilder);
+            } else {
+                SpannableStringBuilder trim = new SpannableStringBuilder();
+                trim.append(mBuilder);
+                if (end < last) {
+                    trim.delete(end + 1, last + 1);
+                }
+                if (start > 0) {
+                    trim.delete(0, start);
+                }
+                mCCView.setText(trim);
+            }
+        }
+
+        public void setRowLimit(int rowLimit) {
+            if (rowLimit < 0) {
+                throw new IllegalArgumentException("A rowLimit should have a positive number");
+            }
+            mRowLimit = rowLimit;
+        }
+    }
+
+    /** @hide */
+    static class CCView extends SubtitleView {
+        private static final CaptionStyle DEFAULT_CAPTION_STYLE = CaptionStyle.DEFAULT;
+
+        public CCView(Context context) {
+            this(context, null);
+        }
+
+        public CCView(Context context, AttributeSet attrs) {
+            this(context, attrs, 0);
+        }
+
+        public CCView(Context context, AttributeSet attrs, int defStyleAttr) {
+            this(context, attrs, defStyleAttr, 0);
+        }
+
+        public CCView(Context context, AttributeSet attrs, int defStyleAttr,
+                int defStyleRes) {
+            super(context, attrs, defStyleAttr, defStyleRes);
+        }
+
+        public void setCaptionStyle(CaptionStyle style) {
+            setForegroundColor(style.hasForegroundColor()
+                    ? style.foregroundColor : DEFAULT_CAPTION_STYLE.foregroundColor);
+            setBackgroundColor(style.hasBackgroundColor()
+                    ? style.backgroundColor : DEFAULT_CAPTION_STYLE.backgroundColor);
+            setEdgeType(style.hasEdgeType()
+                    ? style.edgeType : DEFAULT_CAPTION_STYLE.edgeType);
+            setEdgeColor(style.hasEdgeColor()
+                    ? style.edgeColor : DEFAULT_CAPTION_STYLE.edgeColor);
+            setTypeface(style.getTypeface());
+        }
+    }
+}
diff --git a/media/java/android/media/ClosedCaptionRenderer.java b/media/java/android/media/ClosedCaptionRenderer.java
index 8403c1c..cc7722a 100644
--- a/media/java/android/media/ClosedCaptionRenderer.java
+++ b/media/java/android/media/ClosedCaptionRenderer.java
@@ -23,12 +23,9 @@
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.Typeface;
-import android.os.Parcel;
-import android.text.ParcelableSpan;
 import android.text.Spannable;
 import android.text.SpannableStringBuilder;
 import android.text.TextPaint;
-import android.text.TextUtils;
 import android.text.style.CharacterStyle;
 import android.text.style.StyleSpan;
 import android.text.style.UnderlineSpan;
@@ -52,7 +49,7 @@
 /** @hide */
 public class ClosedCaptionRenderer extends SubtitleController.Renderer {
     private final Context mContext;
-    private ClosedCaptionWidget mRenderingWidget;
+    private Cea608CCWidget mCCWidget;
 
     public ClosedCaptionRenderer(Context context) {
         mContext = context;
@@ -61,31 +58,35 @@
     @Override
     public boolean supports(MediaFormat format) {
         if (format.containsKey(MediaFormat.KEY_MIME)) {
-            return format.getString(MediaFormat.KEY_MIME).equals(
-                    MediaPlayer.MEDIA_MIMETYPE_TEXT_CEA_608);
+            String mimeType = format.getString(MediaFormat.KEY_MIME);
+            return MediaPlayer.MEDIA_MIMETYPE_TEXT_CEA_608.equals(mimeType);
         }
         return false;
     }
 
     @Override
     public SubtitleTrack createTrack(MediaFormat format) {
-        if (mRenderingWidget == null) {
-            mRenderingWidget = new ClosedCaptionWidget(mContext);
+        String mimeType = format.getString(MediaFormat.KEY_MIME);
+        if (MediaPlayer.MEDIA_MIMETYPE_TEXT_CEA_608.equals(mimeType)) {
+            if (mCCWidget == null) {
+                mCCWidget = new Cea608CCWidget(mContext);
+            }
+            return new Cea608CaptionTrack(mCCWidget, format);
         }
-        return new ClosedCaptionTrack(mRenderingWidget, format);
+        throw new RuntimeException("No matching format: " + format.toString());
     }
 }
 
 /** @hide */
-class ClosedCaptionTrack extends SubtitleTrack {
-    private final ClosedCaptionWidget mRenderingWidget;
-    private final CCParser mCCParser;
+class Cea608CaptionTrack extends SubtitleTrack {
+    private final Cea608CCParser mCCParser;
+    private final Cea608CCWidget mRenderingWidget;
 
-    ClosedCaptionTrack(ClosedCaptionWidget renderingWidget, MediaFormat format) {
+    Cea608CaptionTrack(Cea608CCWidget renderingWidget, MediaFormat format) {
         super(format);
 
         mRenderingWidget = renderingWidget;
-        mCCParser = new CCParser(renderingWidget);
+        mCCParser = new Cea608CCParser(mRenderingWidget);
     }
 
     @Override
@@ -105,6 +106,149 @@
 }
 
 /**
+ * Abstract widget class to render a closed caption track.
+ *
+ * @hide
+ */
+abstract class ClosedCaptionWidget extends ViewGroup implements SubtitleTrack.RenderingWidget {
+
+    /** @hide */
+    interface ClosedCaptionLayout {
+        void setCaptionStyle(CaptionStyle captionStyle);
+        void setFontScale(float scale);
+    }
+
+    private static final CaptionStyle DEFAULT_CAPTION_STYLE = CaptionStyle.DEFAULT;
+
+    /** Captioning manager, used to obtain and track caption properties. */
+    private final CaptioningManager mManager;
+
+    /** Current caption style. */
+    protected CaptionStyle mCaptionStyle;
+
+    /** Callback for rendering changes. */
+    protected OnChangedListener mListener;
+
+    /** Concrete layout of CC. */
+    protected ClosedCaptionLayout mClosedCaptionLayout;
+
+    /** Whether a caption style change listener is registered. */
+    private boolean mHasChangeListener;
+
+    public ClosedCaptionWidget(Context context) {
+        this(context, null);
+    }
+
+    public ClosedCaptionWidget(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public ClosedCaptionWidget(Context context, AttributeSet attrs, int defStyle) {
+        this(context, attrs, defStyle, 0);
+    }
+
+    public ClosedCaptionWidget(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+
+        // Cannot render text over video when layer type is hardware.
+        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+
+        mManager = (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE);
+        mCaptionStyle = DEFAULT_CAPTION_STYLE.applyStyle(mManager.getUserStyle());
+
+        mClosedCaptionLayout = createCaptionLayout(context);
+        mClosedCaptionLayout.setCaptionStyle(mCaptionStyle);
+        mClosedCaptionLayout.setFontScale(mManager.getFontScale());
+        addView((ViewGroup) mClosedCaptionLayout, LayoutParams.MATCH_PARENT,
+                LayoutParams.MATCH_PARENT);
+
+        requestLayout();
+    }
+
+    public abstract ClosedCaptionLayout createCaptionLayout(Context context);
+
+    @Override
+    public void setOnChangedListener(OnChangedListener listener) {
+        mListener = listener;
+    }
+
+    @Override
+    public void setSize(int width, int height) {
+        final int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
+        final int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+
+        measure(widthSpec, heightSpec);
+        layout(0, 0, width, height);
+    }
+
+    @Override
+    public void setVisible(boolean visible) {
+        if (visible) {
+            setVisibility(View.VISIBLE);
+        } else {
+            setVisibility(View.GONE);
+        }
+
+        manageChangeListener();
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        manageChangeListener();
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+
+        manageChangeListener();
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        ((ViewGroup) mClosedCaptionLayout).measure(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        ((ViewGroup) mClosedCaptionLayout).layout(l, t, r, b);
+    }
+
+    /**
+     * Manages whether this renderer is listening for caption style changes.
+     */
+    private final CaptioningChangeListener mCaptioningListener = new CaptioningChangeListener() {
+        @Override
+        public void onUserStyleChanged(CaptionStyle userStyle) {
+            mCaptionStyle = DEFAULT_CAPTION_STYLE.applyStyle(userStyle);
+            mClosedCaptionLayout.setCaptionStyle(mCaptionStyle);
+        }
+
+        @Override
+        public void onFontScaleChanged(float fontScale) {
+            mClosedCaptionLayout.setFontScale(fontScale);
+        }
+    };
+
+    private void manageChangeListener() {
+        final boolean needsListener = isAttachedToWindow() && getVisibility() == View.VISIBLE;
+        if (mHasChangeListener != needsListener) {
+            mHasChangeListener = needsListener;
+
+            if (needsListener) {
+                mManager.addCaptioningChangeListener(mCaptioningListener);
+            } else {
+                mManager.removeCaptioningChangeListener(mCaptioningListener);
+            }
+        }
+    }
+}
+
+/**
  * @hide
  *
  * CCParser processes CEA-608 closed caption data.
@@ -113,11 +257,11 @@
  * display change with styled text for rendering.
  *
  */
-class CCParser {
+class Cea608CCParser {
     public static final int MAX_ROWS = 15;
     public static final int MAX_COLS = 32;
 
-    private static final String TAG = "CCParser";
+    private static final String TAG = "Cea608CCParser";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private static final int INVALID = -1;
@@ -160,11 +304,11 @@
     private CCMemory mNonDisplay = new CCMemory();
     private CCMemory mTextMem = new CCMemory();
 
-    CCParser(DisplayListener listener) {
+    Cea608CCParser(DisplayListener listener) {
         mListener = listener;
     }
 
-    void parse(byte[] data) {
+    public void parse(byte[] data) {
         CCData[] ccData = CCData.fromByteArray(data);
 
         for (int i = 0; i < ccData.length; i++) {
@@ -184,8 +328,8 @@
     }
 
     interface DisplayListener {
-        public void onDisplayChanged(SpannableStringBuilder[] styledTexts);
-        public CaptionStyle getCaptionStyle();
+        void onDisplayChanged(SpannableStringBuilder[] styledTexts);
+        CaptionStyle getCaptionStyle();
     }
 
     private CCMemory getMemory() {
@@ -480,6 +624,33 @@
         }
     }
 
+    /**
+     * Mutable version of BackgroundSpan to facilitate text rendering with edge styles.
+     *
+     * @hide
+     */
+    public static class MutableBackgroundColorSpan extends CharacterStyle
+            implements UpdateAppearance {
+        private int mColor;
+
+        public MutableBackgroundColorSpan(int color) {
+            mColor = color;
+        }
+
+        public void setBackgroundColor(int color) {
+            mColor = color;
+        }
+
+        public int getBackgroundColor() {
+            return mColor;
+        }
+
+        @Override
+        public void updateDrawState(TextPaint ds) {
+            ds.bgColor = mColor;
+        }
+    }
+
     /* CCLineBuilder keeps track of displayable chars, as well as
      * MidRow styles and PACs, for a single line of CC memory.
      *
@@ -682,8 +853,7 @@
         }
 
         SpannableStringBuilder[] getStyledText(CaptionStyle captionStyle) {
-            ArrayList<SpannableStringBuilder> rows =
-                    new ArrayList<SpannableStringBuilder>(MAX_ROWS);
+            ArrayList<SpannableStringBuilder> rows = new ArrayList<>(MAX_ROWS);
             for (int i = 1; i <= MAX_ROWS; i++) {
                 rows.add(mLines[i] != null ?
                         mLines[i].getStyledText(captionStyle) : null);
@@ -1044,127 +1214,39 @@
 }
 
 /**
- * Mutable version of BackgroundSpan to facilitate text rendering with edge
- * styles.
- *
- * @hide
- */
-class MutableBackgroundColorSpan extends CharacterStyle implements UpdateAppearance {
-    private int mColor;
-
-    public MutableBackgroundColorSpan(int color) {
-        mColor = color;
-    }
-
-    public void setBackgroundColor(int color) {
-        mColor = color;
-    }
-
-    public int getBackgroundColor() {
-        return mColor;
-    }
-
-    @Override
-    public void updateDrawState(TextPaint ds) {
-        ds.bgColor = mColor;
-    }
-}
-
-/**
  * Widget capable of rendering CEA-608 closed captions.
  *
  * @hide
  */
-class ClosedCaptionWidget extends ViewGroup implements
-        SubtitleTrack.RenderingWidget,
-        CCParser.DisplayListener {
-    private static final String TAG = "ClosedCaptionWidget";
-
+class Cea608CCWidget extends ClosedCaptionWidget implements Cea608CCParser.DisplayListener {
     private static final Rect mTextBounds = new Rect();
     private static final String mDummyText = "1234567890123456789012345678901234";
-    private static final CaptionStyle DEFAULT_CAPTION_STYLE = CaptionStyle.DEFAULT;
 
-    /** Captioning manager, used to obtain and track caption properties. */
-    private final CaptioningManager mManager;
-
-    /** Callback for rendering changes. */
-    private OnChangedListener mListener;
-
-    /** Current caption style. */
-    private CaptionStyle mCaptionStyle;
-
-    /* Closed caption layout. */
-    private CCLayout mClosedCaptionLayout;
-
-    /** Whether a caption style change listener is registered. */
-    private boolean mHasChangeListener;
-
-    public ClosedCaptionWidget(Context context) {
+    public Cea608CCWidget(Context context) {
         this(context, null);
     }
 
-    public ClosedCaptionWidget(Context context, AttributeSet attrs) {
-        this(context, null, 0);
+    public Cea608CCWidget(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
     }
 
-    public ClosedCaptionWidget(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
+    public Cea608CCWidget(Context context, AttributeSet attrs, int defStyle) {
+        this(context, attrs, defStyle, 0);
+    }
 
-        // Cannot render text over video when layer type is hardware.
-        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
-
-        mManager = (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE);
-        mCaptionStyle = DEFAULT_CAPTION_STYLE.applyStyle(mManager.getUserStyle());
-
-        mClosedCaptionLayout = new CCLayout(context);
-        mClosedCaptionLayout.setCaptionStyle(mCaptionStyle);
-        addView(mClosedCaptionLayout, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
-
-        requestLayout();
+    public Cea608CCWidget(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
     }
 
     @Override
-    public void setOnChangedListener(OnChangedListener listener) {
-        mListener = listener;
-    }
-
-    @Override
-    public void setSize(int width, int height) {
-        final int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
-        final int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
-
-        measure(widthSpec, heightSpec);
-        layout(0, 0, width, height);
-    }
-
-    @Override
-    public void setVisible(boolean visible) {
-        if (visible) {
-            setVisibility(View.VISIBLE);
-        } else {
-            setVisibility(View.GONE);
-        }
-
-        manageChangeListener();
-    }
-
-    @Override
-    public void onAttachedToWindow() {
-        super.onAttachedToWindow();
-
-        manageChangeListener();
-    }
-
-    @Override
-    public void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-
-        manageChangeListener();
+    public ClosedCaptionLayout createCaptionLayout(Context context) {
+        return new CCLayout(context);
     }
 
     @Override
     public void onDisplayChanged(SpannableStringBuilder[] styledTexts) {
-        mClosedCaptionLayout.update(styledTexts);
+        ((CCLayout) mClosedCaptionLayout).update(styledTexts);
 
         if (mListener != null) {
             mListener.onChanged(this);
@@ -1176,41 +1258,6 @@
         return mCaptionStyle;
     }
 
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        mClosedCaptionLayout.measure(widthMeasureSpec, heightMeasureSpec);
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        mClosedCaptionLayout.layout(l, t, r, b);
-    }
-
-    /**
-     * Manages whether this renderer is listening for caption style changes.
-     */
-    private final CaptioningChangeListener mCaptioningListener = new CaptioningChangeListener() {
-        @Override
-        public void onUserStyleChanged(CaptionStyle userStyle) {
-            mCaptionStyle = DEFAULT_CAPTION_STYLE.applyStyle(userStyle);
-            mClosedCaptionLayout.setCaptionStyle(mCaptionStyle);
-        }
-    };
-
-    private void manageChangeListener() {
-        final boolean needsListener = isAttachedToWindow() && getVisibility() == View.VISIBLE;
-        if (mHasChangeListener != needsListener) {
-            mHasChangeListener = needsListener;
-
-            if (needsListener) {
-                mManager.addCaptioningChangeListener(mCaptioningListener);
-            } else {
-                mManager.removeCaptioningChangeListener(mCaptioningListener);
-            }
-        }
-    }
-
     private static class CCLineBox extends TextView {
         private static final float FONT_PADDING_RATIO = 0.75f;
         private static final float EDGE_OUTLINE_RATIO = 0.1f;
@@ -1260,8 +1307,7 @@
 
         @Override
         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-            float fontSize = MeasureSpec.getSize(heightMeasureSpec)
-                    * FONT_PADDING_RATIO;
+            float fontSize = MeasureSpec.getSize(heightMeasureSpec) * FONT_PADDING_RATIO;
             setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize);
 
             mOutlineWidth = EDGE_OUTLINE_RATIO * fontSize + 1.0f;
@@ -1358,8 +1404,8 @@
             CharSequence text = getText();
             if (text instanceof Spannable) {
                 Spannable spannable = (Spannable) text;
-                MutableBackgroundColorSpan[] bgSpans = spannable.getSpans(
-                        0, spannable.length(), MutableBackgroundColorSpan.class);
+                Cea608CCParser.MutableBackgroundColorSpan[] bgSpans = spannable.getSpans(
+                        0, spannable.length(), Cea608CCParser.MutableBackgroundColorSpan.class);
                 for (int i = 0; i < bgSpans.length; i++) {
                     bgSpans[i].setBackgroundColor(color);
                 }
@@ -1367,8 +1413,8 @@
         }
     }
 
-    private static class CCLayout extends LinearLayout {
-        private static final int MAX_ROWS = CCParser.MAX_ROWS;
+    private static class CCLayout extends LinearLayout implements ClosedCaptionLayout {
+        private static final int MAX_ROWS = Cea608CCParser.MAX_ROWS;
         private static final float SAFE_AREA_RATIO = 0.9f;
 
         private final CCLineBox[] mLineBoxes = new CCLineBox[MAX_ROWS];
@@ -1383,12 +1429,18 @@
             }
         }
 
-        void setCaptionStyle(CaptionStyle captionStyle) {
+        @Override
+        public void setCaptionStyle(CaptionStyle captionStyle) {
             for (int i = 0; i < MAX_ROWS; i++) {
                 mLineBoxes[i].setCaptionStyle(captionStyle);
             }
         }
 
+        @Override
+        public void setFontScale(float fontScale) {
+            // Ignores the font scale changes of the system wide CC preference.
+        }
+
         void update(SpannableStringBuilder[] textBuffer) {
             for (int i = 0; i < MAX_ROWS; i++) {
                 if (textBuffer[i] != null) {
@@ -1455,4 +1507,4 @@
             }
         }
     }
-};
+}
diff --git a/media/java/android/media/DrmInitData.java b/media/java/android/media/DrmInitData.java
new file mode 100644
index 0000000..06fe6ff
--- /dev/null
+++ b/media/java/android/media/DrmInitData.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.media.MediaDrm;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * Encapsulates initialization data required by a {@link MediaDrm} instance.
+ */
+public abstract class DrmInitData {
+
+    /**
+     * Retrieves initialization data for a given DRM scheme, specified by its UUID.
+     *
+     * @param schemeUuid The DRM scheme's UUID.
+     * @return The initialization data for the scheme, or null if the scheme is not supported.
+     */
+    public abstract SchemeInitData get(UUID schemeUuid);
+
+    /**
+     * Scheme initialization data.
+     */
+    public static final class SchemeInitData {
+
+        /**
+         * The mimeType of {@link #data}.
+         */
+        public final String mimeType;
+        /**
+         * The initialization data.
+         */
+        public final byte[] data;
+
+        /**
+         * @param mimeType The mimeType of the initialization data.
+         * @param data The initialization data.
+         *
+         * @hide
+         */
+        public SchemeInitData(String mimeType, byte[] data) {
+            this.mimeType = mimeType;
+            this.data = data;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof SchemeInitData)) {
+                return false;
+            }
+            if (obj == this) {
+                return true;
+            }
+
+            SchemeInitData other = (SchemeInitData) obj;
+            return mimeType.equals(other.mimeType) && Arrays.equals(data, other.data);
+        }
+
+        @Override
+        public int hashCode() {
+            return mimeType.hashCode() + 31 * Arrays.hashCode(data);
+        }
+
+    }
+
+}
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 445ee6f..7fb67ee 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -17,7 +17,7 @@
 package android.media;
 
 import java.io.IOException;
-import java.util.regex.Matcher;
+import java.io.RandomAccessFile;
 import java.util.regex.Pattern;
 import java.text.ParsePosition;
 import java.text.SimpleDateFormat;
@@ -27,7 +27,9 @@
 import java.util.TimeZone;
 
 /**
- * This is a class for reading and writing Exif tags in a JPEG file.
+ * 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.
  */
 public class ExifInterface {
     // The Exif tag names
@@ -68,8 +70,6 @@
     /** Type is int. */
     public static final String TAG_SUBSEC_TIME_DIG = "SubSecTimeDigitized";
 
-
-
     /**
      * @hide
      */
@@ -98,15 +98,22 @@
     /** Type is String. Name of GPS processing method used for location finding. */
     public static final String TAG_GPS_PROCESSING_METHOD = "GPSProcessingMethod";
 
+    // 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";
+
     // Constants used for the Orientation Exif tag.
     public static final int ORIENTATION_UNDEFINED = 0;
     public static final int ORIENTATION_NORMAL = 1;
     public static final int ORIENTATION_FLIP_HORIZONTAL = 2;  // left right reversed mirror
     public static final int ORIENTATION_ROTATE_180 = 3;
     public static final int ORIENTATION_FLIP_VERTICAL = 4;  // upside down mirror
-    public static final int ORIENTATION_TRANSPOSE = 5;  // flipped about top-left <--> bottom-right axis
+    // flipped about top-left <--> bottom-right axis
+    public static final int ORIENTATION_TRANSPOSE = 5;
     public static final int ORIENTATION_ROTATE_90 = 6;  // rotate 90 cw to right it
-    public static final int ORIENTATION_TRANSVERSE = 7;  // flipped about top-right <--> bottom-left axis
+    // flipped about top-right <--> bottom-left axis
+    public static final int ORIENTATION_TRANSVERSE = 7;
     public static final int ORIENTATION_ROTATE_270 = 8;  // rotate 270 to right it
 
     // Constants used for white balance
@@ -116,13 +123,20 @@
 
     static {
         System.loadLibrary("jhead_jni");
+        System.loadLibrary("media_jni");
+        initRawNative();
+
         sFormatter = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
         sFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
     }
 
-    private String mFilename;
-    private HashMap<String, String> mAttributes;
+    private final String mFilename;
+    private final HashMap<String, String> mAttributes = new HashMap<>();
+    private boolean mIsRaw;
     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
@@ -134,19 +148,20 @@
     private static final Pattern sNonZeroTimePattern = Pattern.compile(".*[1-9].*");
 
     /**
-     * Reads Exif tags from the specified JPEG file.
+     * Reads Exif tags from the specified image file.
      */
     public ExifInterface(String filename) throws IOException {
         if (filename == null) {
             throw new IllegalArgumentException("filename cannot be null");
         }
         mFilename = filename;
+        // First test whether a given file is a one of RAW format or not.
         loadAttributes();
     }
 
     /**
      * Returns the value of the specified tag or {@code null} if there
-     * is no such tag in the JPEG file.
+     * is no such tag in the image file.
      *
      * @param tag the name of the tag.
      */
@@ -156,7 +171,7 @@
 
     /**
      * Returns the integer value of the specified tag. If there is no such tag
-     * in the JPEG file or the value cannot be parsed as integer, return
+     * in the image file or the value cannot be parsed as integer, return
      * <var>defaultValue</var>.
      *
      * @param tag the name of the tag.
@@ -174,7 +189,7 @@
 
     /**
      * Returns the double value of the specified rational tag. If there is no
-     * such tag in the JPEG file or the value cannot be parsed as double, return
+     * 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.
@@ -210,17 +225,42 @@
      *
      * 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 -> Nikon. Numeric values are stored as strings.
+     * Model -&gt; Nikon. Numeric values are stored as strings.
      *
      * This function also initialize mHasThumbnail to indicate whether the
      * file has a thumbnail inside.
      */
     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();
+
+                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;
+                }
+            }
+            return;
+        }
+
         // 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"
-        mAttributes = new HashMap<String, String>();
 
         String attrStr;
         synchronized (sLock) {
@@ -248,7 +288,7 @@
             String attrValue = attrStr.substring(ptr, ptr + attrLen);
             ptr += attrLen;
 
-            if (attrName.equals("hasThumbnail")) {
+            if (attrName.equals(TAG_HAS_THUMBNAIL)) {
                 mHasThumbnail = attrValue.equalsIgnoreCase("true");
             } else {
                 mAttributes.put(attrName, attrValue);
@@ -257,32 +297,36 @@
     }
 
     /**
-     * Save the tag data into the JPEG file. This is expensive because it involves
-     * copying all the JPG 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 and make a single call rather than multiple
-     * calls for each attribute.
+     * 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
+     * and make a single call rather than multiple calls for each attribute.
      */
     public void saveAttributes() throws IOException {
+        if (mIsRaw) {
+            throw new UnsupportedOperationException(
+                    "ExifInterface does not support saving attributes on RAW formats.");
+        }
+
         // 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("hasThumbnail")) {
+        if (mAttributes.containsKey(TAG_HAS_THUMBNAIL)) {
             --size;
         }
-        sb.append(size + " ");
-        for (Map.Entry<String, String> iter : mAttributes.entrySet()) {
-            String key = iter.getKey();
-            if (key.equals("hasThumbnail")) {
+        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;
             }
-            String val = iter.getValue();
-            sb.append(key + "=");
-            sb.append(val.length() + " ");
+            String val = entry.getValue();
+            sb.append(key).append("=");
+            sb.append(val.length()).append(" ");
             sb.append(val);
         }
         String s = sb.toString();
@@ -293,25 +337,43 @@
     }
 
     /**
-     * Returns true if the JPEG file has a thumbnail.
+     * Returns true if the image file has a thumbnail.
      */
     public boolean hasThumbnail() {
         return mHasThumbnail;
     }
 
     /**
-     * Returns the thumbnail inside the JPEG file, or {@code null} if there is no thumbnail.
+     * Returns the thumbnail inside the image file, or {@code null} if there is no thumbnail.
      * The returned data is in JPEG format and can be decoded using
      * {@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.
+                }
+            }
+            return null;
+        }
+
         synchronized (sLock) {
             return getThumbnailNative(mFilename);
         }
     }
 
     /**
-     * Returns the offset and length of thumbnail inside the JPEG file, or
+     * Returns the offset and length of thumbnail inside the image file, or
      * {@code null} if there is no thumbnail.
      *
      * @return two-element array, the offset in the first value, and length in
@@ -319,6 +381,13 @@
      * @hide
      */
     public long[] getThumbnailRange() {
+        if (mIsRaw) {
+            long[] range = new long[2];
+            range[0] = mThumbnailOffset;
+            range[1] = mThumbnailLength;
+            return range;
+        }
+
         synchronized (sLock) {
             return getThumbnailRangeNative(mFilename);
         }
@@ -447,26 +516,28 @@
                 return (float) -result;
             }
             return (float) result;
-        } catch (NumberFormatException e) {
-            // Some of the nubmers are not valid
-            throw new IllegalArgumentException();
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // Some of the rational does not follow the correct format
+        } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
+            // Not valid
             throw new IllegalArgumentException();
         }
     }
 
-    private native boolean appendThumbnailNative(String fileName,
+    // JNI methods for JPEG.
+    private static native boolean appendThumbnailNative(String fileName,
             String thumbnailFileName);
 
-    private native void saveAttributesNative(String fileName,
+    private static native void saveAttributesNative(String fileName,
             String compressedAttributes);
 
-    private native String getAttributesNative(String fileName);
+    private static native String getAttributesNative(String fileName);
 
-    private native void commitChangesNative(String fileName);
+    private static native void commitChangesNative(String fileName);
 
-    private native byte[] getThumbnailNative(String fileName);
+    private static native byte[] getThumbnailNative(String fileName);
 
-    private native long[] getThumbnailRangeNative(String fileName);
+    private static native long[] getThumbnailRangeNative(String fileName);
+
+    // JNI methods for RAW formats.
+    private static native void initRawNative();
+    private static native HashMap getRawAttributesNative(String filename);
 }
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 693a519..abe92c7 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -20,9 +20,11 @@
 import android.bluetooth.BluetoothDevice;
 import android.content.ComponentName;
 import android.media.AudioAttributes;
+import android.media.AudioRecordConfiguration;
 import android.media.AudioRoutesInfo;
 import android.media.IAudioFocusDispatcher;
 import android.media.IAudioRoutesObserver;
+import android.media.IRecordingConfigDispatcher;
 import android.media.IRingtonePlayer;
 import android.media.IVolumeController;
 import android.media.Rating;
@@ -52,6 +54,10 @@
 
     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);
@@ -157,4 +163,10 @@
     int setFocusPropertiesForPolicy(int duckingBehavior, in IAudioPolicyCallback pcb);
 
     void setVolumePolicy(in VolumePolicy policy);
+
+    void registerRecordingCallback(in IRecordingConfigDispatcher rcdb);
+
+    oneway void unregisterRecordingCallback(in IRecordingConfigDispatcher rcdb);
+
+    AudioRecordConfiguration[] getActiveRecordConfigurations();
 }
diff --git a/media/java/android/media/IMediaResourceMonitor.aidl b/media/java/android/media/IMediaResourceMonitor.aidl
new file mode 100644
index 0000000..7b4bc39
--- /dev/null
+++ b/media/java/android/media/IMediaResourceMonitor.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+/** {@hide} */
+interface IMediaResourceMonitor
+{
+    oneway void notifyResourceGranted(in int pid, String type, String subType, long value);
+}
+
diff --git a/media/java/android/media/IRecordingConfigDispatcher.aidl b/media/java/android/media/IRecordingConfigDispatcher.aidl
new file mode 100644
index 0000000..a5eb8b9f
--- /dev/null
+++ b/media/java/android/media/IRecordingConfigDispatcher.aidl
@@ -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.media;
+
+/**
+ * AIDL for the RecordingActivity monitor in AudioService to signal audio recording updates.
+ *
+ * {@hide}
+ */
+oneway interface IRecordingConfigDispatcher {
+
+    void dispatchRecordingConfigChange();
+
+}
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 478fd99..f1f8437 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -2175,8 +2175,6 @@
             int offset, int size, long presentationTimeUs, int flags)
         throws CryptoException;
 
-    // The following mode constants MUST stay in sync with their equivalents
-    // in media/hardware/CryptoAPI.h !
     public static final int CRYPTO_MODE_UNENCRYPTED = 0;
     public static final int CRYPTO_MODE_AES_CTR     = 1;
     public static final int CRYPTO_MODE_AES_CBC     = 2;
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index e6bc8f1..d9690f0 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -460,6 +460,11 @@
         public static final String FEATURE_TunneledPlayback       = "tunneled-playback";
 
         /**
+         * <b>video encoder only</b>: codec supports intra refresh.
+         */
+        public static final String FEATURE_IntraRefresh = "intra-refresh";
+
+        /**
          * Query codec feature capabilities.
          * <p>
          * These features are supported to be used by the codec.  These
@@ -486,6 +491,10 @@
             new Feature(FEATURE_TunneledPlayback, (1 << 2), false),
         };
 
+        private static final Feature[] encoderFeatures = {
+            new Feature(FEATURE_IntraRefresh, (1 << 0), false),
+        };
+
         /** @hide */
         public String[] validFeatures() {
             Feature[] features = getValidFeatures();
@@ -500,7 +509,7 @@
             if (!isEncoder()) {
                 return decoderFeatures;
             }
-            return new Feature[] {};
+            return encoderFeatures;
         }
 
         private boolean checkFeature(String name, int flags) {
@@ -907,7 +916,7 @@
             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_RAW)) {
                 sampleRateRange = Range.create(1, 96000);
                 bitRates = Range.create(1, 10000000);
-                maxChannels = 8;
+                maxChannels = AudioTrack.CHANNEL_COUNT_MAX;
             } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
                 sampleRateRange = Range.create(1, 655350);
                 // lossless codec, so bitrate is ignored
@@ -1726,7 +1735,7 @@
         }
 
         private void applyLevelLimits() {
-            int maxBlocksPerSecond = 0;
+            long maxBlocksPerSecond = 0;
             int maxBlocks = 0;
             int maxBps = 0;
             int maxDPBBlocks = 0;
@@ -1735,8 +1744,7 @@
             CodecProfileLevel[] profileLevels = mParent.profileLevels;
             String mime = mParent.getMimeType();
 
-            if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AVC) ||
-                    mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_DOLBY_AVC)) {
+            if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AVC)) {
                 maxBlocks = 99;
                 maxBlocksPerSecond = 1485;
                 maxBps = 64000;
@@ -2053,11 +2061,11 @@
                         16 /* blockWidth */, 16 /* blockHeight */,
                         1 /* widthAlignment */, 1 /* heightAlignment */);
                 mFrameRateRange = Range.create(1, maxRate);
-            } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8) ||
-                    mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) {
-                maxBlocks = maxBlocksPerSecond = Integer.MAX_VALUE;
+            } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8)) {
+                maxBlocks = Integer.MAX_VALUE;
+                maxBlocksPerSecond = Integer.MAX_VALUE;
 
-                // TODO: set to 100Mbps for now, need a number for VPX
+                // TODO: set to 100Mbps for now, need a number for VP8
                 maxBps = 100000000;
 
                 // profile levels are not indicative for VPx, but verify
@@ -2085,13 +2093,81 @@
                     errors &= ~ERROR_NONE_SUPPORTED;
                 }
 
-                final int blockSize =
-                    mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8) ? 16 : 8;
+                final int blockSize = 16;
                 applyMacroBlockLimits(Short.MAX_VALUE, Short.MAX_VALUE,
                         maxBlocks, maxBlocksPerSecond, blockSize, blockSize,
                         1 /* widthAlignment */, 1 /* heightAlignment */);
-            } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC) ||
-                    mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_DOLBY_HEVC)) {
+            } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) {
+                maxBlocksPerSecond = 829440;
+                maxBlocks = 36864;
+                maxBps = 200000;
+
+                for (CodecProfileLevel profileLevel: profileLevels) {
+                    long SR = 0;
+                    int FS = 0;
+                    int BR = 0;
+                    switch (profileLevel.level) {
+                        case CodecProfileLevel.VP9Level1:
+                            SR =      829440; FS =    36864; BR =    200; break;
+                        case CodecProfileLevel.VP9Level11:
+                            SR =     2764800; FS =    73728; BR =    800; break;
+                        case CodecProfileLevel.VP9Level2:
+                            SR =     4608000; FS =   122880; BR =   1800; break;
+                        case CodecProfileLevel.VP9Level21:
+                            SR =     9216000; FS =   245760; BR =   3600; break;
+                        case CodecProfileLevel.VP9Level3:
+                            SR =    20736000; FS =   552960; BR =   7200; break;
+                        case CodecProfileLevel.VP9Level31:
+                            SR =    36864000; FS =   983040; BR =  12000; break;
+                        case CodecProfileLevel.VP9Level4:
+                            SR =    83558400; FS =  2228224; BR =  18000; break;
+                        case CodecProfileLevel.VP9Level41:
+                            SR =   160432128; FS =  2228224; BR =  30000; break;
+                        case CodecProfileLevel.VP9Level5:
+                            SR =   311951360; FS =  8912896; BR =  60000; break;
+                        case CodecProfileLevel.VP9Level51:
+                            SR =   588251136; FS =  8912896; BR = 120000; break;
+                        case CodecProfileLevel.VP9Level52:
+                            SR =  1176502272; FS =  8912896; BR = 180000; break;
+                        case CodecProfileLevel.VP9Level6:
+                            SR =  1176502272; FS = 35651584; BR = 180000; break;
+                        case CodecProfileLevel.VP9Level61:
+                            SR = 2353004544L; FS = 35651584; BR = 240000; break;
+                        case CodecProfileLevel.VP9Level62:
+                            SR = 4706009088L; FS = 35651584; BR = 480000; break;
+                        default:
+                            Log.w(TAG, "Unrecognized level "
+                                    + profileLevel.level + " for " + mime);
+                            errors |= ERROR_UNRECOGNIZED;
+                    }
+                    switch (profileLevel.profile) {
+                        case CodecProfileLevel.VP9Profile0:
+                        case CodecProfileLevel.VP9Profile1:
+                        case CodecProfileLevel.VP9Profile2:
+                        case CodecProfileLevel.VP9Profile3:
+                            break;
+                        default:
+                            Log.w(TAG, "Unrecognized profile "
+                                    + profileLevel.profile + " for " + mime);
+                            errors |= ERROR_UNRECOGNIZED;
+                    }
+                    errors &= ~ERROR_NONE_SUPPORTED;
+                    maxBlocksPerSecond = Math.max(SR, maxBlocksPerSecond);
+                    maxBlocks = Math.max(FS, maxBlocks);
+                    maxBps = Math.max(BR * 1000, maxBps);
+                }
+
+                final int blockSize = 8;
+                int maxLengthInBlocks = Utils.divUp(maxBlocks, blockSize);
+                maxBlocks = Utils.divUp(maxBlocks, blockSize * blockSize);
+                maxBlocksPerSecond = Utils.divUp(maxBlocksPerSecond, blockSize * blockSize);
+
+                applyMacroBlockLimits(
+                        maxLengthInBlocks, maxLengthInBlocks,
+                        maxBlocks, maxBlocksPerSecond,
+                        blockSize, blockSize,
+                        1 /* widthAlignment */, 1 /* heightAlignment */);
+            } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
                 maxBlocks = 36864;
                 maxBlocksPerSecond = maxBlocks * 15;
                 maxBps = 128000;
@@ -2533,6 +2609,28 @@
         // from OMX_VIDEO_VP8PROFILETYPE
         public static final int VP8ProfileMain = 0x01;
 
+        // from OMX_VIDEO_VP9PROFILETYPE
+        public static final int VP9Profile0 = 0x00;
+        public static final int VP9Profile1 = 0x01;
+        public static final int VP9Profile2 = 0x02;
+        public static final int VP9Profile3 = 0x03;
+
+        // from OMX_VIDEO_VP9LEVELTYPE
+        public static final int VP9Level1  = 0x0;
+        public static final int VP9Level11 = 0x1;
+        public static final int VP9Level2  = 0x2;
+        public static final int VP9Level21 = 0x4;
+        public static final int VP9Level3  = 0x8;
+        public static final int VP9Level31 = 0x10;
+        public static final int VP9Level4  = 0x20;
+        public static final int VP9Level41 = 0x40;
+        public static final int VP9Level5  = 0x80;
+        public static final int VP9Level51 = 0x100;
+        public static final int VP9Level52 = 0x200;
+        public static final int VP9Level6  = 0x400;
+        public static final int VP9Level61 = 0x800;
+        public static final int VP9Level62 = 0x1000;
+
         // from OMX_VIDEO_HEVCPROFILETYPE
         public static final int HEVCProfileMain   = 0x01;
         public static final int HEVCProfileMain10 = 0x02;
@@ -2565,17 +2663,40 @@
         public static final int HEVCMainTierLevel62 = 0x1000000;
         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;
+
+        // from OMX_VIDEO_DOLBYVISIONLEVELTYPE
+        public static final int DolbyVisionLevelHd24    = 0x1;
+        public static final int DolbyVisionLevelHd30    = 0x2;
+        public static final int DolbyVisionLevelFhd24   = 0x4;
+        public static final int DolbyVisionLevelFhd30   = 0x8;
+        public static final int DolbyVisionLevelFhd60   = 0x10;
+        public static final int DolbyVisionLevelUhd24   = 0x20;
+        public static final int DolbyVisionLevelUhd30   = 0x40;
+        public static final int DolbyVisionLevelUhd48   = 0x80;
+        public static final int DolbyVisionLevelUhd60   = 0x100;
+
         /**
          * Defined in the OpenMAX IL specs, depending on the type of media
          * this can be OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE,
-         * OMX_VIDEO_MPEG4PROFILETYPE or OMX_VIDEO_VP8PROFILETYPE.
+         * OMX_VIDEO_MPEG4PROFILETYPE, OMX_VIDEO_VP8PROFILETYPE or OMX_VIDEO_VP9PROFILETYPE.
          */
         public int profile;
 
         /**
          * Defined in the OpenMAX IL specs, depending on the type of media
          * this can be OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE
-         * OMX_VIDEO_MPEG4LEVELTYPE or OMX_VIDEO_VP8LEVELTYPE.
+         * OMX_VIDEO_MPEG4LEVELTYPE, OMX_VIDEO_VP8LEVELTYPE or OMX_VIDEO_VP9LEVELTYPE.
+         *
+         * Note that VP9 decoder on platforms before {@link android.os.Build.VERSION_CODES#N} may
+         * not advertise a profile level support. For those VP9 decoders, please use
+         * {@link VideoCapabilities} to determine the codec capabilities.
          */
         public int level;
     };
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 0bf995f..b339925 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -34,7 +34,9 @@
 import java.lang.annotation.RetentionPolicy;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
@@ -226,6 +228,46 @@
     public native final int getTrackCount();
 
     /**
+     * Extract DRM initialization data if it exists
+     *
+     * @return DRM initialization data in the content, or {@code null}
+     * if no recognizable DRM format is found;
+     * @see DrmInitData
+     */
+    public DrmInitData getDrmInitData() {
+        Map<String, Object> formatMap = getFileFormatNative();
+        if (formatMap == null) {
+            return null;
+        }
+        if (formatMap.containsKey("pssh")) {
+            Map<UUID, byte[]> psshMap = getPsshInfo();
+            final Map<UUID, DrmInitData.SchemeInitData> initDataMap =
+                new HashMap<UUID, DrmInitData.SchemeInitData>();
+            for (Map.Entry<UUID, byte[]> e: psshMap.entrySet()) {
+                UUID uuid = e.getKey();
+                byte[] data = e.getValue();
+                initDataMap.put(uuid, new DrmInitData.SchemeInitData("cenc", data));
+            }
+            return new DrmInitData() {
+                public SchemeInitData get(UUID schemeUuid) {
+                    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);
+                }
+            };
+        }
+        return null;
+    }
+
+    /**
      * Get the PSSH info if present.
      * @return a map of uuid-to-bytes, with the uuid specifying
      * the crypto scheme, and the bytes being the data specific to that scheme.
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index 526656a..f7becf5 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -52,7 +52,7 @@
     public static final int FILE_TYPE_IMY     = 13;
     private static final int FIRST_MIDI_FILE_TYPE = FILE_TYPE_MID;
     private static final int LAST_MIDI_FILE_TYPE = FILE_TYPE_IMY;
-   
+
     // Video file types
     public static final int FILE_TYPE_MP4     = 21;
     public static final int FILE_TYPE_M4V     = 22;
@@ -66,7 +66,7 @@
     public static final int FILE_TYPE_WEBM    = 30;
     private static final int FIRST_VIDEO_FILE_TYPE = FILE_TYPE_MP4;
     private static final int LAST_VIDEO_FILE_TYPE = FILE_TYPE_WEBM;
-    
+
     // More video file types
     public static final int FILE_TYPE_MP2PS   = 200;
     private static final int FIRST_VIDEO_FILE_TYPE2 = FILE_TYPE_MP2PS;
@@ -81,7 +81,21 @@
     public static final int FILE_TYPE_WEBP    = 36;
     private static final int FIRST_IMAGE_FILE_TYPE = FILE_TYPE_JPEG;
     private static final int LAST_IMAGE_FILE_TYPE = FILE_TYPE_WEBP;
-   
+
+    // Raw image file types
+    public static final int FILE_TYPE_DNG     = 300;
+    public static final int FILE_TYPE_CR2     = 301;
+    public static final int FILE_TYPE_NEF     = 302;
+    public static final int FILE_TYPE_NRW     = 303;
+    public static final int FILE_TYPE_ARW     = 304;
+    public static final int FILE_TYPE_RW2     = 305;
+    public static final int FILE_TYPE_ORF     = 306;
+    public static final int FILE_TYPE_RAF     = 307;
+    public static final int FILE_TYPE_PEF     = 308;
+    public static final int FILE_TYPE_SRW     = 309;
+    private static final int FIRST_RAW_IMAGE_FILE_TYPE = FILE_TYPE_DNG;
+    private static final int LAST_RAW_IMAGE_FILE_TYPE = FILE_TYPE_SRW;
+
     // Playlist file types
     public static final int FILE_TYPE_M3U      = 41;
     public static final int FILE_TYPE_PLS      = 42;
@@ -105,17 +119,17 @@
     public static final int FILE_TYPE_MS_EXCEL      = 105;
     public static final int FILE_TYPE_MS_POWERPOINT = 106;
     public static final int FILE_TYPE_ZIP           = 107;
-    
+
     public static class MediaFileType {
         public final int fileType;
         public final String mimeType;
-        
+
         MediaFileType(int fileType, String mimeType) {
             this.fileType = fileType;
             this.mimeType = mimeType;
         }
     }
-    
+
     private static final HashMap<String, MediaFileType> sFileTypeMap
             = new HashMap<String, MediaFileType>();
     private static final HashMap<String, Integer> sMimeTypeMap
@@ -182,7 +196,7 @@
         addFileType("AAC", FILE_TYPE_AAC, "audio/aac", MtpConstants.FORMAT_AAC);
         addFileType("AAC", FILE_TYPE_AAC, "audio/aac-adts", MtpConstants.FORMAT_AAC);
         addFileType("MKA", FILE_TYPE_MKA, "audio/x-matroska");
- 
+
         addFileType("MID", FILE_TYPE_MID, "audio/midi");
         addFileType("MIDI", FILE_TYPE_MID, "audio/midi");
         addFileType("XMF", FILE_TYPE_MID, "audio/midi");
@@ -192,7 +206,7 @@
         addFileType("RTX", FILE_TYPE_MID, "audio/midi");
         addFileType("OTA", FILE_TYPE_MID, "audio/midi");
         addFileType("MXMF", FILE_TYPE_MID, "audio/midi");
-        
+
         addFileType("MPEG", FILE_TYPE_MP4, "video/mpeg", MtpConstants.FORMAT_MPEG);
         addFileType("MPG", FILE_TYPE_MP4, "video/mpeg", MtpConstants.FORMAT_MPEG);
         addFileType("MP4", FILE_TYPE_MP4, "video/mp4", MtpConstants.FORMAT_MPEG);
@@ -216,9 +230,20 @@
         addFileType("GIF", FILE_TYPE_GIF, "image/gif", MtpConstants.FORMAT_GIF);
         addFileType("PNG", FILE_TYPE_PNG, "image/png", MtpConstants.FORMAT_PNG);
         addFileType("BMP", FILE_TYPE_BMP, "image/x-ms-bmp", MtpConstants.FORMAT_BMP);
-        addFileType("WBMP", FILE_TYPE_WBMP, "image/vnd.wap.wbmp");
-        addFileType("WEBP", FILE_TYPE_WEBP, "image/webp");
- 
+        addFileType("WBMP", FILE_TYPE_WBMP, "image/vnd.wap.wbmp", MtpConstants.FORMAT_DEFINED);
+        addFileType("WEBP", FILE_TYPE_WEBP, "image/webp", MtpConstants.FORMAT_DEFINED);
+
+        addFileType("DNG", FILE_TYPE_DNG, "image/x-adobe-dng", MtpConstants.FORMAT_DNG);
+        addFileType("CR2", FILE_TYPE_CR2, "image/x-canon-cr2", MtpConstants.FORMAT_TIFF);
+        addFileType("NEF", FILE_TYPE_NEF, "image/x-nikon-nef", MtpConstants.FORMAT_TIFF_EP);
+        addFileType("NRW", FILE_TYPE_NRW, "image/x-nikon-nrw", MtpConstants.FORMAT_TIFF);
+        addFileType("ARW", FILE_TYPE_ARW, "image/x-sony-arw", MtpConstants.FORMAT_TIFF);
+        addFileType("RW2", FILE_TYPE_RW2, "image/x-panasonic-rw2", MtpConstants.FORMAT_TIFF);
+        addFileType("ORF", FILE_TYPE_ORF, "image/x-olympus-orf", MtpConstants.FORMAT_TIFF);
+        addFileType("RAF", FILE_TYPE_RAF, "image/x-fuji-raf", MtpConstants.FORMAT_DEFINED);
+        addFileType("PEF", FILE_TYPE_PEF, "image/x-pentax-pef", MtpConstants.FORMAT_TIFF);
+        addFileType("SRW", FILE_TYPE_SRW, "image/x-samsung-srw", MtpConstants.FORMAT_TIFF);
+
         addFileType("M3U", FILE_TYPE_M3U, "audio/x-mpegurl", MtpConstants.FORMAT_M3U_PLAYLIST);
         addFileType("M3U", FILE_TYPE_M3U, "application/x-mpegurl", MtpConstants.FORMAT_M3U_PLAYLIST);
         addFileType("PLS", FILE_TYPE_PLS, "audio/x-scpls", MtpConstants.FORMAT_PLS_PLAYLIST);
@@ -258,7 +283,14 @@
 
     public static boolean isImageFileType(int fileType) {
         return (fileType >= FIRST_IMAGE_FILE_TYPE &&
-                fileType <= LAST_IMAGE_FILE_TYPE);
+                fileType <= LAST_IMAGE_FILE_TYPE)
+            || (fileType >= FIRST_RAW_IMAGE_FILE_TYPE &&
+                fileType <= LAST_RAW_IMAGE_FILE_TYPE);
+    }
+
+    public static boolean isRawImageFileType(int fileType) {
+        return (fileType >= FIRST_RAW_IMAGE_FILE_TYPE &&
+                fileType <= LAST_RAW_IMAGE_FILE_TYPE);
     }
 
     public static boolean isPlayListFileType(int fileType) {
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index a102e51..d06da97 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -44,7 +44,8 @@
  *         for encoders, readable in the output format of decoders</b></td></tr>
  * <tr><td>{@link #KEY_FRAME_RATE}</td><td>Integer or Float</td><td><b>encoder-only</b></td></tr>
  * <tr><td>{@link #KEY_CAPTURE_RATE}</td><td>Integer</td><td></td></tr>
-* <tr><td>{@link #KEY_I_FRAME_INTERVAL}</td><td>Integer</td><td><b>encoder-only</b></td></tr>
+ * <tr><td>{@link #KEY_I_FRAME_INTERVAL}</td><td>Integer</td><td><b>encoder-only</b></td></tr>
+ * <tr><td>{@link #KEY_INTRA_REFRESH_PERIOD}</td><td>Integer</td><td><b>encoder-only</b>, optional</td></tr>
  * <tr><td>{@link #KEY_MAX_WIDTH}</td><td>Integer</td><td><b>decoder-only</b>, optional, max-resolution width</td></tr>
  * <tr><td>{@link #KEY_MAX_HEIGHT}</td><td>Integer</td><td><b>decoder-only</b>, optional, max-resolution height</td></tr>
  * <tr><td>{@link #KEY_REPEAT_PREVIOUS_FRAME_AFTER}</td><td>Long</td><td><b>video encoder in surface-mode only</b></td></tr>
@@ -92,8 +93,6 @@
     public static final String MIMETYPE_VIDEO_H263 = "video/3gpp";
     public static final String MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
     public static final String MIMETYPE_VIDEO_RAW = "video/raw";
-    public static final String MIMETYPE_VIDEO_DOLBY_AVC = "video/dolby-avc";
-    public static final String MIMETYPE_VIDEO_DOLBY_HEVC = "video/dolby-hevc";
 
     public static final String MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
     public static final String MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
@@ -109,6 +108,7 @@
     public static final String MIMETYPE_AUDIO_MSGSM = "audio/gsm";
     public static final String MIMETYPE_AUDIO_AC3 = "audio/ac3";
     public static final String MIMETYPE_AUDIO_EAC3 = "audio/eac3";
+    public static final String MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision";
 
     /**
      * MIME type for WebVTT subtitle data.
@@ -219,6 +219,20 @@
     public static final String KEY_I_FRAME_INTERVAL = "i-frame-interval";
 
     /**
+    * An optional key describing the period of intra refresh in frames. This is an
+    * optional parameter that applies only to video encoders. If encoder supports it
+    * ({@link MediaCodecInfo.CodecCapabilities#FEATURE_IntraRefresh}), the whole
+    * frame is completely refreshed after the specified period. Also for each frame,
+    * a fix subset of macroblocks must be intra coded which leads to more constant bitrate
+    * than inserting a key frame. This key is recommended for video streaming applications
+    * as it provides low-delay and good error-resilience. This key is ignored if the
+    * video encoder does not support the intra refresh feature. Use the output format to
+    * verify that this feature was enabled.
+    * The associated value is an integer.
+    */
+    public static final String KEY_INTRA_REFRESH_PERIOD = "intra-refresh-period";
+
+   /**
      * A key describing the temporal layering schema.  This is an optional parameter
      * that applies only to video encoders.  Use {@link MediaCodec#getInputFormat}
      * after {@link MediaCodec#configure configure} to query if the encoder supports
@@ -549,6 +563,66 @@
     /** @hide */
     public static final String KEY_IS_TIMED_TEXT = "is-timed-text";
 
+    // The following color aspect values must be in sync with the ones in HardwareAPI.h.
+    /*
+     * An optional key describing the color primaries, white point and
+     * luminance factors for video content.
+     *
+     * The associated value is an integer: 0 if unspecified, or one of the
+     * COLOR_STANDARD_ values.
+     */
+    public static final String KEY_COLOR_STANDARD = "color-standard";
+
+    /** BT.709 color chromacity coordinates with KR = 0.2126, KB = 0.0722. */
+    public static final int COLOR_STANDARD_BT709 = 1;
+
+    /** BT.601 625 color chromacity coordinates with KR = 0.299, KB = 0.114. */
+    public static final int COLOR_STANDARD_BT601_PAL = 2;
+
+    /** BT.601 525 color chromacity coordinates with KR = 0.299, KB = 0.114. */
+    public static final int COLOR_STANDARD_BT601_NTSC = 4;
+
+    /** BT.2020 color chromacity coordinates with KR = 0.2627, KB = 0.0593. */
+    public static final int COLOR_STANDARD_BT2020 = 6;
+
+    /**
+     * An optional key describing the opto-electronic transfer function used
+     * for the video content.
+     *
+     * The associated value is an integer: 0 if unspecified, or one of the
+     * COLOR_TRANSFER_ values.
+     */
+    public static final String KEY_COLOR_TRANSFER = "color-transfer";
+
+    /** Linear transfer characteristic curve. */
+    public static final int COLOR_TRANSFER_LINEAR = 1;
+
+    /** SMPTE 170M transfer characteristic curve used by BT.601/BT.709/BT.2020. This is the curve
+     *  used by most non-HDR video content. */
+    public static final int COLOR_TRANSFER_SDR_VIDEO = 3;
+
+    /** SMPTE ST 2084 transfer function. This is used by some HDR video content. */
+    public static final int COLOR_TRANSFER_ST2084 = 6;
+
+    /** ARIB STD-B67 hybrid-log-gamma transfer function. This is used by some HDR video content. */
+    public static final int COLOR_TRANSFER_HLG = 7;
+
+    /**
+     * An optional key describing the range of the component values of the video content.
+     *
+     * The associated value is an integer: 0 if unspecified, or one of the
+     * COLOR_RANGE_ values.
+     */
+    public static final String KEY_COLOR_RANGE = "color-range";
+
+    /** Limited range. Y component values range from 16 to 235 for 8-bit content.
+     *  Cr, Cy values range from 16 to 240 for 8-bit content.
+     *  This is the default for video content. */
+    public static final int COLOR_RANGE_LIMITED = 2;
+
+    /** 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;
+
     /* package private */ MediaFormat(Map<String, Object> map) {
         mMap = map;
     }
diff --git a/media/java/android/media/MediaInserter.java b/media/java/android/media/MediaInserter.java
index 41b369d..dd06921 100644
--- a/media/java/android/media/MediaInserter.java
+++ b/media/java/android/media/MediaInserter.java
@@ -16,8 +16,8 @@
 
 package android.media;
 
+import android.content.ContentProviderClient;
 import android.content.ContentValues;
-import android.content.IContentProvider;
 import android.net.Uri;
 import android.os.RemoteException;
 
@@ -37,13 +37,11 @@
     private final HashMap<Uri, List<ContentValues>> mPriorityRowMap =
             new HashMap<Uri, List<ContentValues>>();
 
-    private final IContentProvider mProvider;
-    private final String mPackageName;
+    private final ContentProviderClient mProvider;
     private final int mBufferSizePerUri;
 
-    public MediaInserter(IContentProvider provider, String packageName, int bufferSizePerUri) {
+    public MediaInserter(ContentProviderClient provider, int bufferSizePerUri) {
         mProvider = provider;
-        mPackageName = packageName;
         mBufferSizePerUri = bufferSizePerUri;
     }
 
@@ -90,7 +88,7 @@
         if (!list.isEmpty()) {
             ContentValues[] valuesArray = new ContentValues[list.size()];
             valuesArray = list.toArray(valuesArray);
-            mProvider.bulkInsert(mPackageName, tableUri, valuesArray);
+            mProvider.bulkInsert(tableUri, valuesArray);
             list.clear();
         }
     }
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index f5b7a2e..26e466e 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -2127,6 +2127,12 @@
      */
     public static final String MEDIA_MIMETYPE_TEXT_CEA_608 = "text/cea-608";
 
+    /**
+     * MIME type for CEA-708 closed caption data.
+     * @hide
+     */
+    public static final String MEDIA_MIMETYPE_TEXT_CEA_708 = "text/cea-708";
+
     /*
      * A helper function to check if the mime type is supported by media framework.
      */
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 8ac86b0..f09f654 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -251,6 +251,10 @@
          */
         public static final int REMOTE_SUBMIX = 8;
 
+        /** Microphone audio source tuned for unprocessed (raw) sound if available, behaves like
+         *  {@link #DEFAULT} otherwise. */
+        public static final int UNPROCESSED = 9;
+
         /**
          * Audio source for capturing broadcast radio tuner output.
          * @hide
@@ -385,6 +389,7 @@
         public static final int H264 = 2;
         public static final int MPEG_4_SP = 3;
         public static final int VP8 = 4;
+        public static final int HEVC = 5;
     }
 
     /**
@@ -405,7 +410,7 @@
      * @see android.media.MediaRecorder.AudioSource
      */
     public static final int getAudioSourceMax() {
-        return AudioSource.REMOTE_SUBMIX;
+        return AudioSource.UNPROCESSED;
     }
 
     /**
@@ -817,7 +822,6 @@
      *
      * @throws IllegalStateException if it is called before start() or after
      * stop()
-     * {@hide}
      */
     public native void pause() throws IllegalStateException;
 
@@ -828,7 +832,6 @@
      * @throws IllegalStateException if it is called before start() or after
      * stop()
      * @see android.media.MediaRecorder#pause
-     * {@hide}
      */
     public native void resume() throws IllegalStateException;
 
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 9ea6722..78f357f 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -16,14 +16,11 @@
 
 package android.media;
 
-import org.xml.sax.Attributes;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.SAXException;
-
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
-import android.content.IContentProvider;
 import android.database.Cursor;
 import android.database.SQLException;
 import android.drm.DrmManagerClient;
@@ -41,6 +38,7 @@
 import android.provider.MediaStore.Images;
 import android.provider.MediaStore.Video;
 import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
 import android.sax.Element;
 import android.sax.ElementListener;
 import android.sax.RootElement;
@@ -50,6 +48,12 @@
 import android.util.Log;
 import android.util.Xml;
 
+import dalvik.system.CloseGuard;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileDescriptor;
@@ -61,6 +65,7 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Locale;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Internal service helper that no-one should use directly.
@@ -107,8 +112,7 @@
  *
  * {@hide}
  */
-public class MediaScanner
-{
+public class MediaScanner implements AutoCloseable {
     static {
         System.loadLibrary("media_jni");
         native_init();
@@ -302,21 +306,23 @@
     };
 
     private long mNativeContext;
-    private Context mContext;
-    private String mPackageName;
-    private IContentProvider mMediaProvider;
-    private Uri mAudioUri;
-    private Uri mVideoUri;
-    private Uri mImagesUri;
-    private Uri mThumbsUri;
-    private Uri mPlaylistsUri;
-    private Uri mFilesUri;
-    private Uri mFilesUriNoNotify;
-    private boolean mProcessPlaylists, mProcessGenres;
+    private final Context mContext;
+    private final String mPackageName;
+    private final String mVolumeName;
+    private final ContentProviderClient mMediaProvider;
+    private final Uri mAudioUri;
+    private final Uri mVideoUri;
+    private final Uri mImagesUri;
+    private final Uri mThumbsUri;
+    private final Uri mPlaylistsUri;
+    private final Uri mFilesUri;
+    private final Uri mFilesUriNoNotify;
+    private final boolean mProcessPlaylists;
+    private final boolean mProcessGenres;
     private int mMtpObjectHandle;
 
-    private final String mExternalStoragePath;
-    private final boolean mExternalIsEmulated;
+    private final AtomicBoolean mClosed = new AtomicBoolean();
+    private final CloseGuard mCloseGuard = CloseGuard.get();
 
     /** whether to use bulk inserts or individual inserts for each item */
     private static final boolean ENABLE_BULK_INSERTS = true;
@@ -324,8 +330,6 @@
     // used when scanning the image database so we know whether we have to prune
     // old thumbnail files
     private int mOriginalCount;
-    /** Whether the database had any entries in it before the scan started */
-    private boolean mWasEmptyPriorToScan = false;
     /** Whether the scanner has set a default sound for the ringer ringtone. */
     private boolean mDefaultRingtoneSet;
     /** Whether the scanner has set a default sound for the notification ringtone. */
@@ -345,10 +349,6 @@
      */
     private static final String DEFAULT_RINGTONE_PROPERTY_PREFIX = "ro.config.";
 
-    // set to true if file path comparisons should be case insensitive.
-    // this should be set when scanning files on a case insensitive file system.
-    private boolean mCaseInsensitivePaths;
-
     private final BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
 
     private static class FileEntry {
@@ -378,26 +378,59 @@
         int bestmatchlevel;
     }
 
-    private ArrayList<PlaylistEntry> mPlaylistEntries = new ArrayList<PlaylistEntry>();
+    private final ArrayList<PlaylistEntry> mPlaylistEntries = new ArrayList<>();
+    private final ArrayList<FileEntry> mPlayLists = new ArrayList<>();
 
     private MediaInserter mMediaInserter;
 
-    private ArrayList<FileEntry> mPlayLists;
-
     private DrmManagerClient mDrmManagerClient = null;
 
-    public MediaScanner(Context c) {
+    public MediaScanner(Context c, String volumeName) {
         native_setup();
         mContext = c;
         mPackageName = c.getPackageName();
+        mVolumeName = volumeName;
+
         mBitmapOptions.inSampleSize = 1;
         mBitmapOptions.inJustDecodeBounds = true;
 
         setDefaultRingtoneFileNames();
 
-        mExternalStoragePath = Environment.getExternalStorageDirectory().getAbsolutePath();
-        mExternalIsEmulated = Environment.isExternalStorageEmulated();
-        //mClient.testGenreNameConverter();
+        mMediaProvider = mContext.getContentResolver()
+                .acquireContentProviderClient(MediaStore.AUTHORITY);
+
+        mAudioUri = Audio.Media.getContentUri(volumeName);
+        mVideoUri = Video.Media.getContentUri(volumeName);
+        mImagesUri = Images.Media.getContentUri(volumeName);
+        mThumbsUri = Images.Thumbnails.getContentUri(volumeName);
+        mFilesUri = Files.getContentUri(volumeName);
+        mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build();
+
+        if (!volumeName.equals("internal")) {
+            // we only support playlists on external media
+            mProcessPlaylists = true;
+            mProcessGenres = true;
+            mPlaylistsUri = Playlists.getContentUri(volumeName);
+        } else {
+            mProcessPlaylists = false;
+            mProcessGenres = false;
+            mPlaylistsUri = null;
+        }
+
+        final Locale locale = mContext.getResources().getConfiguration().locale;
+        if (locale != null) {
+            String language = locale.getLanguage();
+            String country = locale.getCountry();
+            if (language != null) {
+                if (country != null) {
+                    setLocale(language + "_" + country);
+                } else {
+                    setLocale(language);
+                }
+            }
+        }
+
+        mCloseGuard.open("close");
     }
 
     private void setDefaultRingtoneFileNames() {
@@ -529,12 +562,29 @@
                 FileEntry entry = beginFile(path, mimeType, lastModified,
                         fileSize, isDirectory, noMedia);
 
+                if (entry == null) {
+                    return null;
+                }
+
                 // if this file was just inserted via mtp, set the rowid to zero
                 // (even though it already exists in the database), to trigger
                 // the correct code path for updating its entry
                 if (mMtpObjectHandle != 0) {
                     entry.mRowId = 0;
                 }
+
+                if (entry.mPath != null &&
+                        ((!mDefaultNotificationSet &&
+                                doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename))
+                        || (!mDefaultRingtoneSet &&
+                                doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename))
+                        || (!mDefaultAlarmSet &&
+                                doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)))) {
+                    Log.w(TAG, "forcing rescan of " + entry.mPath +
+                            "since ringtone setting didn't finish");
+                    scanAlways = true;
+                }
+
                 // rescan for metadata if file was modified since last scan
                 if (entry != null && (entry.mLastModifiedChanged || scanAlways)) {
                     if (noMedia) {
@@ -849,7 +899,8 @@
                 values.put(Audio.Media.IS_ALARM, alarms);
                 values.put(Audio.Media.IS_MUSIC, music);
                 values.put(Audio.Media.IS_PODCAST, podcasts);
-            } else if (mFileType == MediaFile.FILE_TYPE_JPEG && !mNoMedia) {
+            } else if ((mFileType == MediaFile.FILE_TYPE_JPEG
+                    || MediaFile.isRawImageFileType(mFileType)) && !mNoMedia) {
                 ExifInterface exif = null;
                 try {
                     exif = new ExifInterface(entry.mPath);
@@ -914,6 +965,26 @@
             }
             Uri result = null;
             boolean needToSetSettings = false;
+            // Setting a flag in order not to use bulk insert for the file related with
+            // notifications, ringtones, and alarms, because the rowId of the inserted file is
+            // needed.
+            if (notifications && !mDefaultNotificationSet) {
+                if (TextUtils.isEmpty(mDefaultNotificationFilename) ||
+                        doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) {
+                    needToSetSettings = true;
+                }
+            } else if (ringtones && !mDefaultRingtoneSet) {
+                if (TextUtils.isEmpty(mDefaultRingtoneFilename) ||
+                        doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) {
+                    needToSetSettings = true;
+                }
+            } else if (alarms && !mDefaultAlarmSet) {
+                if (TextUtils.isEmpty(mDefaultAlarmAlertFilename) ||
+                        doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)) {
+                    needToSetSettings = true;
+                }
+            }
+
             if (rowId == 0) {
                 if (mMtpObjectHandle != 0) {
                     values.put(MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, mMtpObjectHandle);
@@ -925,28 +996,6 @@
                     }
                     values.put(Files.FileColumns.FORMAT, format);
                 }
-                // Setting a flag in order not to use bulk insert for the file related with
-                // notifications, ringtones, and alarms, because the rowId of the inserted file is
-                // needed.
-                if (mWasEmptyPriorToScan) {
-                    if (notifications && !mDefaultNotificationSet) {
-                        if (TextUtils.isEmpty(mDefaultNotificationFilename) ||
-                                doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) {
-                            needToSetSettings = true;
-                        }
-                    } else if (ringtones && !mDefaultRingtoneSet) {
-                        if (TextUtils.isEmpty(mDefaultRingtoneFilename) ||
-                                doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) {
-                            needToSetSettings = true;
-                        }
-                    } else if (alarms && !mDefaultAlarmSet) {
-                        if (TextUtils.isEmpty(mDefaultAlarmAlertFilename) ||
-                                doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)) {
-                            needToSetSettings = true;
-                        }
-                    }
-                }
-
                 // New file, insert it.
                 // Directories need to be inserted before the files they contain, so they
                 // get priority when bulk inserting.
@@ -956,7 +1005,7 @@
                     if (inserter != null) {
                         inserter.flushAll();
                     }
-                    result = mMediaProvider.insert(mPackageName, tableUri, values);
+                    result = mMediaProvider.insert(tableUri, values);
                 } else if (entry.mFormat == MtpConstants.FORMAT_ASSOCIATION) {
                     inserter.insertwithPriority(tableUri, values);
                 } else {
@@ -988,7 +1037,7 @@
                     }
                     values.put(FileColumns.MEDIA_TYPE, mediaType);
                 }
-                mMediaProvider.update(mPackageName, result, values, null, null);
+                mMediaProvider.update(result, values, null, null);
             }
 
             if(needToSetSettings) {
@@ -1016,14 +1065,18 @@
 
         private void setSettingIfNotSet(String settingName, Uri uri, long rowId) {
 
-            String existingSettingValue = Settings.System.getString(mContext.getContentResolver(),
-                    settingName);
+            if(wasSettingAlreadySet(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(mContext.getContentResolver(), settingName,
+                Settings.System.putString(cr, settingName,
                         ContentUris.withAppendedId(uri, rowId).toString());
             }
+            Settings.System.putInt(cr, settingSetIndicatorName(settingName), 1);
         }
 
         private int getFileTypeFromDrm(String path) {
@@ -1050,16 +1103,26 @@
 
     }; // end of anonymous MediaScannerClient instance
 
+    private String settingSetIndicatorName(String base) {
+        return base + "_set";
+    }
+
+    private boolean wasSettingAlreadySet(String name) {
+        ContentResolver cr = mContext.getContentResolver();
+        String indicatorName = settingSetIndicatorName(name);
+        try {
+            return Settings.System.getInt(cr, indicatorName) != 0;
+        } catch (SettingNotFoundException e) {
+            return false;
+        }
+    }
+
     private void prescan(String filePath, boolean prescanFiles) throws RemoteException {
         Cursor c = null;
         String where = null;
         String[] selectionArgs = null;
 
-        if (mPlayLists == null) {
-            mPlayLists = new ArrayList<FileEntry>();
-        } else {
-            mPlayLists.clear();
-        }
+        mPlayLists.clear();
 
         if (filePath != null) {
             // query for only one file
@@ -1071,14 +1134,17 @@
             selectionArgs = new String[] { "" };
         }
 
+        mDefaultRingtoneSet = wasSettingAlreadySet(Settings.System.RINGTONE);
+        mDefaultNotificationSet = wasSettingAlreadySet(Settings.System.NOTIFICATION_SOUND);
+        mDefaultAlarmSet = wasSettingAlreadySet(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
         // accidentally deleting files that are really there (this may happen if the
         // filesystem is mounted and unmounted while the scanner is running).
         Uri.Builder builder = mFilesUri.buildUpon();
         builder.appendQueryParameter(MediaStore.PARAM_DELETE_DATA, "false");
-        MediaBulkDeleter deleter = new MediaBulkDeleter(mMediaProvider, mPackageName,
-                builder.build());
+        MediaBulkDeleter deleter = new MediaBulkDeleter(mMediaProvider, builder.build());
 
         // Build the list of files from the content provider
         try {
@@ -1089,7 +1155,6 @@
                 // with CursorWindow positioning.
                 long lastId = Long.MIN_VALUE;
                 Uri limitUri = mFilesUri.buildUpon().appendQueryParameter("limit", "1000").build();
-                mWasEmptyPriorToScan = true;
 
                 while (true) {
                     selectionArgs[0] = "" + lastId;
@@ -1097,7 +1162,7 @@
                         c.close();
                         c = null;
                     }
-                    c = mMediaProvider.query(mPackageName, limitUri, FILES_PRESCAN_PROJECTION,
+                    c = mMediaProvider.query(limitUri, FILES_PRESCAN_PROJECTION,
                             where, selectionArgs, MediaStore.Files.FileColumns._ID, null);
                     if (c == null) {
                         break;
@@ -1108,7 +1173,6 @@
                     if (num == 0) {
                         break;
                     }
-                    mWasEmptyPriorToScan = false;
                     while (c.moveToNext()) {
                         long rowId = c.getLong(FILES_PRESCAN_ID_COLUMN_INDEX);
                         String path = c.getString(FILES_PRESCAN_PATH_COLUMN_INDEX);
@@ -1138,8 +1202,7 @@
                                     if (path.toLowerCase(Locale.US).endsWith("/.nomedia")) {
                                         deleter.flush();
                                         String parent = new File(path).getParent();
-                                        mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL,
-                                                parent, null);
+                                        mMediaProvider.call(MediaStore.UNHIDE_CALL, parent, null);
                                     }
                                 }
                             }
@@ -1157,7 +1220,7 @@
 
         // compute original size of images
         mOriginalCount = 0;
-        c = mMediaProvider.query(mPackageName, mImagesUri, ID_PROJECTION, null, null, null, null);
+        c = mMediaProvider.query(mImagesUri, ID_PROJECTION, null, null, null, null);
         if (c != null) {
             mOriginalCount = c.getCount();
             c.close();
@@ -1189,7 +1252,6 @@
 
         try {
             c = mMediaProvider.query(
-                    mPackageName,
                     mThumbsUri,
                     new String [] { "_data" },
                     null,
@@ -1225,13 +1287,11 @@
     static class MediaBulkDeleter {
         StringBuilder whereClause = new StringBuilder();
         ArrayList<String> whereArgs = new ArrayList<String>(100);
-        final IContentProvider mProvider;
-        final String mPackageName;
+        final ContentProviderClient mProvider;
         final Uri mBaseUri;
 
-        public MediaBulkDeleter(IContentProvider provider, String packageName, Uri baseUri) {
+        public MediaBulkDeleter(ContentProviderClient provider, Uri baseUri) {
             mProvider = provider;
-            mPackageName = packageName;
             mBaseUri = baseUri;
         }
 
@@ -1250,7 +1310,7 @@
             if (size > 0) {
                 String [] foo = new String [size];
                 foo = whereArgs.toArray(foo);
-                int numrows = mProvider.delete(mPackageName, mBaseUri,
+                int numrows = mProvider.delete(mBaseUri,
                         MediaStore.MediaColumns._ID + " IN (" +
                         whereClause.toString() + ")", foo);
                 //Log.i("@@@@@@@@@", "rows deleted: " + numrows);
@@ -1260,7 +1320,7 @@
         }
     }
 
-    private void postscan(String[] directories) throws RemoteException {
+    private void postscan(final String[] directories) throws RemoteException {
 
         // handle playlists last, after we know what media files are on the storage.
         if (mProcessPlaylists) {
@@ -1271,48 +1331,26 @@
             pruneDeadThumbnailFiles();
 
         // allow GC to clean up
-        mPlayLists = null;
-        mMediaProvider = null;
+        mPlayLists.clear();
     }
 
     private void releaseResources() {
         // release the DrmManagerClient resources
         if (mDrmManagerClient != null) {
-            mDrmManagerClient.release();
+            mDrmManagerClient.close();
             mDrmManagerClient = null;
         }
     }
 
-    private void initialize(String volumeName) {
-        mMediaProvider = mContext.getContentResolver().acquireProvider("media");
-
-        mAudioUri = Audio.Media.getContentUri(volumeName);
-        mVideoUri = Video.Media.getContentUri(volumeName);
-        mImagesUri = Images.Media.getContentUri(volumeName);
-        mThumbsUri = Images.Thumbnails.getContentUri(volumeName);
-        mFilesUri = Files.getContentUri(volumeName);
-        mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build();
-
-        if (!volumeName.equals("internal")) {
-            // we only support playlists on external media
-            mProcessPlaylists = true;
-            mProcessGenres = true;
-            mPlaylistsUri = Playlists.getContentUri(volumeName);
-
-            mCaseInsensitivePaths = true;
-        }
-    }
-
-    public void scanDirectories(String[] directories, String volumeName) {
+    public void scanDirectories(String[] directories) {
         try {
             long start = System.currentTimeMillis();
-            initialize(volumeName);
             prescan(null, true);
             long prescan = System.currentTimeMillis();
 
             if (ENABLE_BULK_INSERTS) {
                 // create MediaInserter for bulk inserts
-                mMediaInserter = new MediaInserter(mMediaProvider, mPackageName, 500);
+                mMediaInserter = new MediaInserter(mMediaProvider, 500);
             }
 
             for (int i = 0; i < directories.length; i++) {
@@ -1349,9 +1387,8 @@
     }
 
     // this function is used to scan a single file
-    public Uri scanSingleFile(String path, String volumeName, String mimeType) {
+    public Uri scanSingleFile(String path, String mimeType) {
         try {
-            initialize(volumeName);
             prescan(path, true);
 
             File file = new File(path);
@@ -1464,8 +1501,7 @@
         return isNoMediaFile(path);
     }
 
-    public void scanMtpFile(String path, String volumeName, int objectHandle, int format) {
-        initialize(volumeName);
+    public void scanMtpFile(String path, int objectHandle, int format) {
         MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path);
         int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType);
         File file = new File(path);
@@ -1481,7 +1517,7 @@
             values.put(Files.FileColumns.DATE_MODIFIED, lastModifiedSeconds);
             try {
                 String[] whereArgs = new String[] {  Integer.toString(objectHandle) };
-                mMediaProvider.update(mPackageName, Files.getMtpObjectsUri(volumeName), values,
+                mMediaProvider.update(Files.getMtpObjectsUri(mVolumeName), values,
                         "_id=?", whereArgs);
             } catch (RemoteException e) {
                 Log.e(TAG, "RemoteException in scanMtpFile", e);
@@ -1498,7 +1534,7 @@
 
                 FileEntry entry = makeEntryFor(path);
                 if (entry != null) {
-                    fileList = mMediaProvider.query(mPackageName, mFilesUri,
+                    fileList = mMediaProvider.query(mFilesUri,
                             FILES_PRESCAN_PROJECTION, null, null, null, null);
                     processPlayList(entry, fileList);
                 }
@@ -1529,7 +1565,7 @@
         try {
             where = Files.FileColumns.DATA + "=?";
             selectionArgs = new String[] { path };
-            c = mMediaProvider.query(mPackageName, mFilesUriNoNotify, FILES_PRESCAN_PROJECTION,
+            c = mMediaProvider.query(mFilesUriNoNotify, FILES_PRESCAN_PROJECTION,
                     where, selectionArgs, null, null);
             if (c.moveToFirst()) {
                 long rowId = c.getLong(FILES_PRESCAN_ID_COLUMN_INDEX);
@@ -1641,7 +1677,7 @@
                     values.clear();
                     values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(index));
                     values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, Long.valueOf(entry.bestmatchid));
-                    mMediaProvider.insert(mPackageName, playlistUri, values);
+                    mMediaProvider.insert(playlistUri, values);
                     index++;
                 } catch (RemoteException e) {
                     Log.e(TAG, "RemoteException in MediaScanner.processCachedPlaylist()", e);
@@ -1806,16 +1842,16 @@
 
         if (rowId == 0) {
             values.put(MediaStore.Audio.Playlists.DATA, path);
-            uri = mMediaProvider.insert(mPackageName, mPlaylistsUri, values);
+            uri = mMediaProvider.insert(mPlaylistsUri, values);
             rowId = ContentUris.parseId(uri);
             membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY);
         } else {
             uri = ContentUris.withAppendedId(mPlaylistsUri, rowId);
-            mMediaProvider.update(mPackageName, uri, values, null, null);
+            mMediaProvider.update(uri, values, null, null);
 
             // delete members of existing playlist
             membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY);
-            mMediaProvider.delete(mPackageName, membersUri, null, null);
+            mMediaProvider.delete(membersUri, null, null);
         }
 
         String playListDirectory = path.substring(0, lastSlash + 1);
@@ -1837,7 +1873,7 @@
         try {
             // use the files uri and projection because we need the format column,
             // but restrict the query to just audio files
-            fileList = mMediaProvider.query(mPackageName, mFilesUri, FILES_PRESCAN_PROJECTION,
+            fileList = mMediaProvider.query(mFilesUri, FILES_PRESCAN_PROJECTION,
                     "media_type=2", null, null, null);
             while (iterator.hasNext()) {
                 FileEntry entry = iterator.next();
@@ -1856,7 +1892,7 @@
 
     private native void processDirectory(String path, MediaScannerClient client);
     private native void processFile(String path, String mimeType, MediaScannerClient client);
-    public native void setLocale(String locale);
+    private native void setLocale(String locale);
 
     public native byte[] extractAlbumArt(FileDescriptor fd);
 
@@ -1864,19 +1900,22 @@
     private native final void native_setup();
     private native final void native_finalize();
 
-    /**
-     * Releases resources associated with this MediaScanner object.
-     * It is considered good practice to call this method when
-     * one is done using the MediaScanner object. After this method
-     * is called, the MediaScanner object can no longer be used.
-     */
-    public void release() {
-        native_finalize();
+    @Override
+    public void close() {
+        mCloseGuard.close();
+        if (mClosed.compareAndSet(false, true)) {
+            mMediaProvider.close();
+            native_finalize();
+        }
     }
 
     @Override
-    protected void finalize() {
-        mContext.getContentResolver().releaseProvider(mMediaProvider);
-        native_finalize();
+    protected void finalize() throws Throwable {
+        try {
+            mCloseGuard.warnIfOpen();
+            close();
+        } finally {
+            super.finalize();
+        }
     }
 }
diff --git a/media/java/android/media/ThumbnailUtils.java b/media/java/android/media/ThumbnailUtils.java
index daa5fa5..abd6f4a 100644
--- a/media/java/android/media/ThumbnailUtils.java
+++ b/media/java/android/media/ThumbnailUtils.java
@@ -92,7 +92,8 @@
         SizedThumbnailBitmap sizedThumbnailBitmap = new SizedThumbnailBitmap();
         Bitmap bitmap = null;
         MediaFileType fileType = MediaFile.getFileType(filePath);
-        if (fileType != null && fileType.fileType == MediaFile.FILE_TYPE_JPEG) {
+        if (fileType != null && (fileType.fileType == MediaFile.FILE_TYPE_JPEG
+                || MediaFile.isRawImageFileType(fileType.fileType))) {
             createThumbnailFromEXIF(filePath, targetSize, maxPixels, sizedThumbnailBitmap);
             bitmap = sizedThumbnailBitmap.mBitmap;
         }
diff --git a/media/java/android/media/Utils.java b/media/java/android/media/Utils.java
index 2cd3c43..35b083e 100644
--- a/media/java/android/media/Utils.java
+++ b/media/java/android/media/Utils.java
@@ -174,7 +174,7 @@
         return (num + den - 1) / den;
     }
 
-    private static long divUp(long num, long den) {
+    static long divUp(long num, long den) {
         return (num + den - 1) / den;
     }
 
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index 02b03d2..b9fcba2 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -19,6 +19,7 @@
 import android.annotation.SystemApi;
 import android.media.AudioAttributes;
 import android.os.Parcel;
+import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -48,14 +49,27 @@
 
     /**
      * A rule requiring the usage information of the {@link AudioAttributes} to match.
+     * This mixing rule can be added with {@link Builder#addRule(AudioAttributes, int)} or
+     * {@link Builder#addMixRule(int, Object)} where the Object parameter is an instance of
+     * {@link AudioAttributes}.
      */
     @SystemApi
     public static final int RULE_MATCH_ATTRIBUTE_USAGE = 0x1;
     /**
      * A rule requiring the capture preset information of the {@link AudioAttributes} to match.
+     * This mixing rule can be added with {@link Builder#addRule(AudioAttributes, int)} or
+     * {@link Builder#addMixRule(int, Object)} where the Object parameter is an instance of
+     * {@link AudioAttributes}.
      */
     @SystemApi
     public static final int RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET = 0x1 << 1;
+    /**
+     * A rule requiring the UID of the audio stream to match that specified.
+     * This mixing rule can be added with {@link Builder#addMixRule(int, Object)} where the Object
+     * parameter is an instance of {@link java.lang.Integer}.
+     */
+    @SystemApi
+    public static final int RULE_MATCH_UID = 0x1 << 2;
 
     private final static int RULE_EXCLUSION_MASK = 0x8000;
     /**
@@ -70,29 +84,53 @@
      */
     public static final int RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET =
             RULE_EXCLUSION_MASK | RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET;
+    /**
+     * @hide
+     * A rule requiring the UID information to differ.
+     */
+    public static final int RULE_EXCLUDE_UID =
+            RULE_EXCLUSION_MASK | RULE_MATCH_UID;
 
     static final class AttributeMatchCriterion {
-        AudioAttributes mAttr;
-        int mRule;
+        final AudioAttributes mAttr;
+        final Integer mIntProp;
+        final int mRule;
 
         /** input parameters must be valid */
         AttributeMatchCriterion(AudioAttributes attributes, int rule) {
             mAttr = attributes;
+            mIntProp = null;
+            mRule = rule;
+        }
+        /** input parameters must be valid */
+        AttributeMatchCriterion(Integer intProp, int rule) {
+            mAttr = null;
+            mIntProp = intProp;
             mRule = rule;
         }
 
         @Override
         public int hashCode() {
-            return Objects.hash(mAttr, mRule);
+            return Objects.hash(mAttr, mIntProp, mRule);
         }
 
         void writeToParcel(Parcel dest) {
             dest.writeInt(mRule);
-            if ((mRule == RULE_MATCH_ATTRIBUTE_USAGE) || (mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE)) {
+            final int match_rule = mRule & ~RULE_EXCLUSION_MASK;
+            switch (match_rule) {
+            case RULE_MATCH_ATTRIBUTE_USAGE:
                 dest.writeInt(mAttr.getUsage());
-            } else {
-                // capture preset rule
+                break;
+            case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
                 dest.writeInt(mAttr.getCapturePreset());
+                break;
+            case RULE_MATCH_UID:
+                dest.writeInt(mIntProp.intValue());
+                break;
+            default:
+                Log.e("AttributeMatchCriterion", "Unknown match rule" + match_rule
+                        + " when writing to Parcel");
+                dest.writeInt(-1);
             }
         }
     }
@@ -111,18 +149,31 @@
         switch(rule) {
             case RULE_MATCH_ATTRIBUTE_USAGE:
             case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
+            case RULE_MATCH_UID:
                 return true;
             default:
                 return false;
         }
     }
 
-    private static boolean isValidIntRule(int rule) {
+    private static boolean isValidAttributesSystemApiRule(int rule) {
+        switch(rule) {
+            case RULE_MATCH_ATTRIBUTE_USAGE:
+            case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    private static boolean isValidRule(int rule) {
         switch(rule) {
             case RULE_MATCH_ATTRIBUTE_USAGE:
             case RULE_EXCLUDE_ATTRIBUTE_USAGE:
             case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
             case RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET:
+            case RULE_MATCH_UID:
+            case RULE_EXCLUDE_UID:
                 return true;
             default:
                 return false;
@@ -130,8 +181,24 @@
     }
 
     private static boolean isPlayerRule(int rule) {
-        return ((rule == RULE_MATCH_ATTRIBUTE_USAGE)
-                || (rule == RULE_EXCLUDE_ATTRIBUTE_USAGE));
+        final int match_rule = rule & ~RULE_EXCLUSION_MASK;
+        switch (match_rule) {
+        case RULE_MATCH_ATTRIBUTE_USAGE:
+        case RULE_MATCH_UID:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    private static boolean isAudioAttributeRule(int match_rule) {
+        switch(match_rule) {
+            case RULE_MATCH_ATTRIBUTE_USAGE:
+            case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
+                return true;
+            default:
+                return false;
+        }
     }
 
     /**
@@ -158,14 +225,15 @@
          *     {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET}.
          * @return the same Builder instance.
          * @throws IllegalArgumentException
+         * @see {@link #excludeRule(AudioAttributes, int)}
          */
         @SystemApi
         public Builder addRule(AudioAttributes attrToMatch, int rule)
                 throws IllegalArgumentException {
-            if (!isValidSystemApiRule(rule)) {
+            if (!isValidAttributesSystemApiRule(rule)) {
                 throw new IllegalArgumentException("Illegal rule value " + rule);
             }
-            return addRuleInt(attrToMatch, rule);
+            return checkAddRuleObjInternal(rule, attrToMatch);
         }
 
         /**
@@ -186,33 +254,82 @@
          *     {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET}.
          * @return the same Builder instance.
          * @throws IllegalArgumentException
+         * @see {@link #addRule(AudioAttributes, int)}
          */
         @SystemApi
         public Builder excludeRule(AudioAttributes attrToMatch, int rule)
                 throws IllegalArgumentException {
+            if (!isValidAttributesSystemApiRule(rule)) {
+                throw new IllegalArgumentException("Illegal rule value " + rule);
+            }
+            return checkAddRuleObjInternal(rule | RULE_EXCLUSION_MASK, attrToMatch);
+        }
+
+        /**
+         * Add a rule for the selection of which streams are mixed together.
+         * The rule defines what the matching will be made on. It also determines the type of the
+         * property to match against.
+         * @param rule one of {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_USAGE},
+         *     {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET} or
+         *     {@link AudioMixingRule#RULE_MATCH_UID}.
+         * @param property see the definition of each rule for the type to use (either an
+         *     {@link AudioAttributes} or an {@link java.lang.Integer}).
+         * @return the same Builder instance.
+         * @throws IllegalArgumentException
+         * @see {@link #excludeMixRule(int, Object)}
+         */
+        @SystemApi
+        public Builder addMixRule(int rule, Object property) throws IllegalArgumentException {
             if (!isValidSystemApiRule(rule)) {
                 throw new IllegalArgumentException("Illegal rule value " + rule);
             }
-            return addRuleInt(attrToMatch, rule | RULE_EXCLUSION_MASK);
+            return checkAddRuleObjInternal(rule, property);
+        }
+
+        /**
+         * Add a rule by exclusion for the selection of which streams are mixed together.
+         * <br>For instance the following code
+         * <br><pre>
+         * AudioAttributes mediaAttr = new AudioAttributes.Builder()
+         *         .setUsage(AudioAttributes.USAGE_MEDIA)
+         *         .build();
+         * AudioMixingRule noMediaRule = new AudioMixingRule.Builder()
+         *         .addMixRule(AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE, mediaAttr)
+         *         .excludeMixRule(AudioMixingRule.RULE_MATCH_UID, new Integer(uidToExclude)
+         *         .build();
+         * </pre>
+         * <br>will create a rule which maps to usage USAGE_MEDIA, but excludes any stream
+         * coming from the specified UID.
+         * @param rule one of {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_USAGE},
+         *     {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET} or
+         *     {@link AudioMixingRule#RULE_MATCH_UID}.
+         * @param property see the definition of each rule for the type to use (either an
+         *     {@link AudioAttributes} or an {@link java.lang.Integer}).
+         * @return the same Builder instance.
+         * @throws IllegalArgumentException
+         */
+        @SystemApi
+        public Builder excludeMixRule(int rule, Object property) throws IllegalArgumentException {
+            if (!isValidSystemApiRule(rule)) {
+                throw new IllegalArgumentException("Illegal rule value " + rule);
+            }
+            return checkAddRuleObjInternal(rule | RULE_EXCLUSION_MASK, property);
         }
 
         /**
          * Add or exclude a rule for the selection of which streams are mixed together.
-         * @param attrToMatch a non-null AudioAttributes instance for which a contradictory
-         *     rule hasn't been set yet.
-         * @param rule one of {@link AudioMixingRule#RULE_EXCLUDE_ATTRIBUTE_USAGE},
-         *     {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_USAGE},
-         *     {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET} or
-         *     {@link AudioMixingRule#RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET}.
+         * Does error checking on the parameters.
+         * @param rule
+         * @param property
          * @return the same Builder instance.
          * @throws IllegalArgumentException
          */
-        Builder addRuleInt(AudioAttributes attrToMatch, int rule)
+        private Builder checkAddRuleObjInternal(int rule, Object property)
                 throws IllegalArgumentException {
-            if (attrToMatch == null) {
-                throw new IllegalArgumentException("Illegal null AudioAttributes argument");
+            if (property == null) {
+                throw new IllegalArgumentException("Illegal null Object argument");
             }
-            if (!isValidIntRule(rule)) {
+            if (!isValidRule(rule)) {
                 throw new IllegalArgumentException("Illegal rule value " + rule);
             } else {
                 // as rules are added to the Builder, we verify they are consistent with the type
@@ -229,36 +346,87 @@
                     throw new IllegalArgumentException("Incompatible rule for mix");
                 }
             }
+            final int match_rule = rule & ~RULE_EXCLUSION_MASK;
+            if (isAudioAttributeRule(match_rule)) {
+                if (!(property instanceof AudioAttributes)) {
+                    throw new IllegalArgumentException("Invalid AudioAttributes argument");
+                }
+                return addRuleInternal((AudioAttributes) property, null, rule);
+            } else {
+                // implies integer match rule
+                if (!(property instanceof Integer)) {
+                    throw new IllegalArgumentException("Invalid Integer argument");
+                }
+                return addRuleInternal(null, (Integer) property, rule);
+            }
+        }
+
+        /**
+         * Add or exclude a rule on AudioAttributes or integer property for the selection of which
+         * streams are mixed together.
+         * No rule-to-parameter type check, all done in {@link #checkAddRuleObjInternal(int, Object)}.
+         * Exceptions are thrown only when incompatible rules are added.
+         * @param attrToMatch a non-null AudioAttributes instance for which a contradictory
+         *     rule hasn't been set yet, null if not used.
+         * @param intProp an integer property to match or exclude, null if not used.
+         * @param rule one of {@link AudioMixingRule#RULE_EXCLUDE_ATTRIBUTE_USAGE},
+         *     {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_USAGE},
+         *     {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET} or
+         *     {@link AudioMixingRule#RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET},
+         *     {@link AudioMixingRule#RULE_MATCH_UID}, {@link AudioMixingRule#RULE_EXCLUDE_UID}.
+         * @return the same Builder instance.
+         * @throws IllegalArgumentException
+         */
+        private Builder addRuleInternal(AudioAttributes attrToMatch, Integer intProp, int rule)
+                throws IllegalArgumentException {
             synchronized (mCriteria) {
                 Iterator<AttributeMatchCriterion> crIterator = mCriteria.iterator();
+                final int match_rule = rule & ~RULE_EXCLUSION_MASK;
                 while (crIterator.hasNext()) {
                     final AttributeMatchCriterion criterion = crIterator.next();
-                    if ((rule == RULE_MATCH_ATTRIBUTE_USAGE)
-                            || (rule == RULE_EXCLUDE_ATTRIBUTE_USAGE)) {
-                        // "usage"-based rule
-                        if (criterion.mAttr.getUsage() == attrToMatch.getUsage()) {
-                            if (criterion.mRule == rule) {
-                                // rule already exists, we're done
-                                return this;
-                            } else {
-                                // criterion already exists with a another rule, it is incompatible
-                                throw new IllegalArgumentException("Contradictory rule exists for "
-                                        + attrToMatch);
+                    switch (match_rule) {
+                        case RULE_MATCH_ATTRIBUTE_USAGE:
+                            // "usage"-based rule
+                            if (criterion.mAttr.getUsage() == attrToMatch.getUsage()) {
+                                if (criterion.mRule == rule) {
+                                    // rule already exists, we're done
+                                    return this;
+                                } else {
+                                    // criterion already exists with a another rule,
+                                    // it is incompatible
+                                    throw new IllegalArgumentException("Contradictory rule exists"
+                                            + " for " + attrToMatch);
+                                }
                             }
-                        }
-                    } else if ((rule == RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET)
-                            || (rule == RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET)) {
-                        // "capture preset"-base rule
-                        if (criterion.mAttr.getCapturePreset() == attrToMatch.getCapturePreset()) {
-                            if (criterion.mRule == rule) {
-                             // rule already exists, we're done
-                                return this;
-                            } else {
-                                // criterion already exists with a another rule, it is incompatible
-                                throw new IllegalArgumentException("Contradictory rule exists for "
-                                        + attrToMatch);
+                            break;
+                        case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
+                            // "capture preset"-base rule
+                            if (criterion.mAttr.getCapturePreset() == attrToMatch.getCapturePreset()) {
+                                if (criterion.mRule == rule) {
+                                    // rule already exists, we're done
+                                    return this;
+                                } else {
+                                    // criterion already exists with a another rule,
+                                    // it is incompatible
+                                    throw new IllegalArgumentException("Contradictory rule exists"
+                                            + " for " + attrToMatch);
+                                }
                             }
-                        }
+                            break;
+                        case RULE_MATCH_UID:
+                            // "usage"-based rule
+                            if (criterion.mIntProp.intValue() == intProp.intValue()) {
+                                if (criterion.mRule == rule) {
+                                    // rule already exists, we're done
+                                    return this;
+                                } else {
+                                    // criterion already exists with a another rule,
+                                    // it is incompatible
+                                    throw new IllegalArgumentException("Contradictory rule exists"
+                                            + " for UID " + intProp);
+                                }
+                            }
+                            break;
                     }
                 }
                 // rule didn't exist, add it
@@ -268,22 +436,30 @@
         }
 
         Builder addRuleFromParcel(Parcel in) throws IllegalArgumentException {
-            int rule = in.readInt();
-            AudioAttributes attr;
-            if ((rule == RULE_MATCH_ATTRIBUTE_USAGE) || (rule == RULE_EXCLUDE_ATTRIBUTE_USAGE)) {
-                int usage = in.readInt();
-                attr = new AudioAttributes.Builder()
-                        .setUsage(usage).build();
-            } else if ((rule == RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET)
-                    || (rule == RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET)) {
-                int preset = in.readInt();
-                attr = new AudioAttributes.Builder()
-                        .setInternalCapturePreset(preset).build();
-            } else {
-                in.readInt(); // assume there was in int value to read as for now they come in pair
-                throw new IllegalArgumentException("Illegal rule value " + rule + " in parcel");
+            final int rule = in.readInt();
+            final int match_rule = rule & ~RULE_EXCLUSION_MASK;
+            AudioAttributes attr = null;
+            Integer intProp = null;
+            switch (match_rule) {
+                case RULE_MATCH_ATTRIBUTE_USAGE:
+                    int usage = in.readInt();
+                    attr = new AudioAttributes.Builder()
+                            .setUsage(usage).build();
+                    break;
+                case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
+                    int preset = in.readInt();
+                    attr = new AudioAttributes.Builder()
+                            .setInternalCapturePreset(preset).build();
+                    break;
+                case RULE_MATCH_UID:
+                    intProp = new Integer(in.readInt());
+                    break;
+                default:
+                    // assume there was in int value to read as for now they come in pair
+                    in.readInt();
+                    throw new IllegalArgumentException("Illegal rule value " + rule + " in parcel");
             }
-            return addRuleInt(attr, rule);
+            return addRuleInternal(attr, intProp, rule);
         }
 
         /**
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index 252f5f4..5ad6126 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -169,6 +169,14 @@
                         textDump += "  match capture preset ";
                         textDump += criterion.mAttr.getCapturePreset();
                         break;
+                    case AudioMixingRule.RULE_MATCH_UID:
+                        textDump += "  match UID ";
+                        textDump += criterion.mIntProp.toString();
+                        break;
+                    case AudioMixingRule.RULE_EXCLUDE_UID:
+                        textDump += "  exclude UID ";
+                        textDump += criterion.mIntProp.toString();
+                        break;
                     default:
                         textDump += "invalid rule!";
                 }
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index be9fb47..869512d 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -34,9 +34,9 @@
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
-import android.service.media.MediaBrowserService;
 import android.service.media.IMediaBrowserService;
 import android.service.media.IMediaBrowserServiceCallbacks;
+import android.service.media.MediaBrowserService;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -44,7 +44,9 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.Map.Entry;
 
 /**
  * Browses media content offered by a link MediaBrowserService.
@@ -52,11 +54,39 @@
  * This object is not thread-safe. All calls should happen on the thread on which the browser
  * was constructed.
  * </p>
+ * <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)}.
+ *
+ * <ul>
+ *     <li> {@link #EXTRA_PAGE}
+ *     <li> {@link #EXTRA_PAGE_SIZE}
+ * </ul>
  */
 public final class MediaBrowser {
     private static final String TAG = "MediaBrowser";
     private static final boolean DBG = false;
 
+    /**
+     * 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.
+     *
+     * @see android.service.media.MediaBrowserService.BrowserRoot
+     * @see #EXTRA_PAGE_SIZE
+     */
+    public static final String EXTRA_PAGE = "android.media.browse.extra.PAGE";
+
+    /**
+     * 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";
+
     private static final int CONNECT_STATE_DISCONNECTED = 0;
     private static final int CONNECT_STATE_CONNECTING = 1;
     private static final int CONNECT_STATE_CONNECTED = 2;
@@ -67,8 +97,7 @@
     private final ConnectionCallback mCallback;
     private final Bundle mRootHints;
     private final Handler mHandler = new Handler();
-    private final ArrayMap<String,Subscription> mSubscriptions =
-            new ArrayMap<String, MediaBrowser.Subscription>();
+    private final ArrayMap<String, Subscription> mSubscriptions = new ArrayMap<>();
 
     private int mState = CONNECT_STATE_DISCONNECTED;
     private MediaServiceConnection mServiceConnection;
@@ -291,7 +320,7 @@
      * the specified id and subscribes to receive updates when they change.
      * <p>
      * The list of subscriptions is maintained even when not connected and is
-     * restored after reconnection. It is ok to subscribe while not connected
+     * restored after the reconnection. It is ok to subscribe while not connected
      * but the results will not be returned until the connection completes.
      * </p>
      * <p>
@@ -305,34 +334,37 @@
      * @param callback The callback to receive the list of children.
      */
     public void subscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
-        // Check arguments.
-        if (parentId == null) {
-            throw new IllegalArgumentException("parentId is null");
-        }
-        if (callback == null) {
-            throw new IllegalArgumentException("callback is null");
-        }
+        subscribeInternal(parentId, null, callback);
+    }
 
-        // Update or create the subscription.
-        Subscription sub = mSubscriptions.get(parentId);
-        boolean newSubscription = sub == null;
-        if (newSubscription) {
-            sub = new Subscription(parentId);
-            mSubscriptions.put(parentId, sub);
+    /**
+     * Queries with service-specific arguments for information about the media items
+     * that are contained within the specified id and subscribes to receive updates
+     * when they change.
+     * <p>
+     * The list of subscriptions is maintained even when not connected and is
+     * restored after the reconnection. It is ok to subscribe while not connected
+     * but the results will not be returned until the connection completes.
+     * </p>
+     * <p>
+     * If the id is already subscribed with a different callback then the new
+     * callback will replace the previous one and the child data will be
+     * reloaded.
+     * </p>
+     *
+     * @param parentId The id of the parent media item whose list of children
+     *            will be subscribed.
+     * @param options A bundle of service-specific arguments to send to the media
+     *            browse service. The contents of this bundle may affect the
+     *            information returned when browsing.
+     * @param callback The callback to receive the list of children.
+     */
+    public void subscribe(@NonNull String parentId, @NonNull Bundle options,
+            @NonNull SubscriptionCallback callback) {
+        if (options == null) {
+            throw new IllegalArgumentException("options are null");
         }
-        sub.callback = callback;
-
-        // If we are connected, tell the service that we are watching.  If we aren't
-        // connected, the service will be told when we connect.
-        if (mState == CONNECT_STATE_CONNECTED) {
-            try {
-                mServiceBinder.addSubscription(parentId, mServiceCallbacks);
-            } catch (RemoteException ex) {
-                // Process is crashing.  We will disconnect, and upon reconnect we will
-                // automatically reregister. So nothing to do here.
-                Log.d(TAG, "addSubscription failed with RemoteException parentId=" + parentId);
-            }
-        }
+        subscribeInternal(parentId, options, callback);
     }
 
     /**
@@ -343,27 +375,28 @@
      * </p>
      *
      * @param parentId The id of the parent media item whose list of children
-     * will be unsubscribed.
+     *            will be unsubscribed.
      */
     public void unsubscribe(@NonNull String parentId) {
-        // Check arguments.
-        if (TextUtils.isEmpty(parentId)) {
-            throw new IllegalArgumentException("parentId is empty.");
-        }
+        unsubscribeInternal(parentId, null);
+    }
 
-        // Remove from our list.
-        final Subscription sub = mSubscriptions.remove(parentId);
-
-        // Tell the service if necessary.
-        if (mState == CONNECT_STATE_CONNECTED && sub != null) {
-            try {
-                mServiceBinder.removeSubscription(parentId, mServiceCallbacks);
-            } catch (RemoteException ex) {
-                // Process is crashing.  We will disconnect, and upon reconnect we will
-                // automatically reregister. So nothing to do here.
-                Log.d(TAG, "removeSubscription failed with RemoteException parentId=" + parentId);
-            }
+    /**
+     * Unsubscribes for changes to the children of the specified media id.
+     * <p>
+     * The query callback will no longer be invoked for results associated with
+     * this id once this method returns.
+     * </p>
+     *
+     * @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.
+     */
+    public void unsubscribe(@NonNull String parentId, @NonNull Bundle options) {
+        if (options == null) {
+            throw new IllegalArgumentException("options are null");
         }
+        unsubscribeInternal(parentId, options);
     }
 
     /**
@@ -420,6 +453,73 @@
         }
     }
 
+    private void subscribeInternal(String parentId, Bundle options, SubscriptionCallback callback) {
+        // Check arguments.
+        if (parentId == null) {
+            throw new IllegalArgumentException("parentId is null");
+        }
+        if (callback == null) {
+            throw new IllegalArgumentException("callback is null");
+        }
+        // Update or create the subscription.
+        Subscription sub = mSubscriptions.get(parentId);
+        if (sub == null) {
+            sub = new Subscription();
+            mSubscriptions.put(parentId, sub);
+        }
+        sub.add(callback, options);
+
+        // If we are connected, tell the service that we are watching. If we aren't connected,
+        // the service will be told when we connect.
+        if (mState == CONNECT_STATE_CONNECTED) {
+            try {
+                // NOTE: In order not to break the behavior of the support library, call
+                // addSubscription instead of addSubscriptionWithOptions when the options are null.
+                if (options == null) {
+                    mServiceBinder.addSubscription(parentId, mServiceCallbacks);
+                } else {
+                    mServiceBinder.addSubscriptionWithOptions(parentId, options, mServiceCallbacks);
+                }
+            } catch (RemoteException ex) {
+                // Process is crashing. We will disconnect, and upon reconnect we will
+                // automatically reregister. So nothing to do here.
+                Log.d(TAG, "addSubscription failed with RemoteException parentId=" + parentId);
+            }
+        }
+    }
+
+    private void unsubscribeInternal(String parentId, Bundle options) {
+        // Check arguments.
+        if (TextUtils.isEmpty(parentId)) {
+            throw new IllegalArgumentException("parentId is empty.");
+        }
+
+        // Remove from our list.
+        Subscription sub = mSubscriptions.get(parentId);
+
+        // Tell the service if necessary.
+        if (sub != null && sub.remove(options) && mState == CONNECT_STATE_CONNECTED) {
+            try {
+                // NOTE: In order not to break the behavior of the support library, call
+                // removeSubscription instead of removeSubscriptionWithOptions when the options
+                // are null.
+                if (options == null) {
+                    mServiceBinder.removeSubscription(parentId, mServiceCallbacks);
+                } else {
+                    mServiceBinder.removeSubscriptionWithOptions(
+                            parentId, options, mServiceCallbacks);
+                }
+            } catch (RemoteException ex) {
+                // Process is crashing. We will disconnect, and upon reconnect we will
+                // automatically reregister. So nothing to do here.
+                Log.d(TAG, "removeSubscription failed with RemoteException parentId=" + parentId);
+            }
+        }
+        if (sub != null && sub.isEmpty()) {
+            mSubscriptions.remove(parentId);
+        }
+    }
+
     /**
      * For debugging.
      */
@@ -467,13 +567,26 @@
 
                 // we may receive some subscriptions before we are connected, so re-subscribe
                 // everything now
-                for (String id : mSubscriptions.keySet()) {
-                    try {
-                        mServiceBinder.addSubscription(id, mServiceCallbacks);
-                    } catch (RemoteException ex) {
-                        // Process is crashing.  We will disconnect, and upon reconnect we will
-                        // automatically reregister. So nothing to do here.
-                        Log.d(TAG, "addSubscription failed with RemoteException parentId=" + id);
+                for (Entry<String, Subscription> subscriptionEntry : mSubscriptions.entrySet()) {
+                    String id = subscriptionEntry.getKey();
+                    Subscription sub = subscriptionEntry.getValue();
+                    for (Bundle options : sub.getOptionsList()) {
+                        try {
+                            // NOTE: In order not to break the behavior of the support library,
+                            // call addSubscription instead of addSubscriptionWithOptions when
+                            // the options are null.
+                            if (options == null) {
+                                mServiceBinder.addSubscription(id, mServiceCallbacks);
+                            } else {
+                                mServiceBinder.addSubscriptionWithOptions(
+                                        id, options, mServiceCallbacks);
+                            }
+                        } catch (RemoteException ex) {
+                            // Process is crashing. We will disconnect, and upon reconnect we will
+                            // automatically reregister. So nothing to do here.
+                            Log.d(TAG, "addSubscription failed with RemoteException parentId="
+                                    + id);
+                        }
                     }
                 }
             }
@@ -508,7 +621,7 @@
     }
 
     private final void onLoadChildren(final IMediaBrowserServiceCallbacks callback,
-            final String parentId, final ParceledListSlice list) {
+            final String parentId, final ParceledListSlice list, final Bundle options) {
         mHandler.post(new Runnable() {
             @Override
             public void run() {
@@ -525,16 +638,21 @@
 
                 // Check that the subscription is still subscribed.
                 final Subscription subscription = mSubscriptions.get(parentId);
-                if (subscription == null) {
-                    if (DBG) {
-                        Log.d(TAG, "onLoadChildren for id that isn't subscribed id="
-                                + parentId);
+                if (subscription != null) {
+                    // Tell the app.
+                    SubscriptionCallback subscriptionCallback = subscription.getCallback(options);
+                    if (subscriptionCallback != null) {
+                        if (options == null) {
+                            subscriptionCallback.onChildrenLoaded(parentId, data);
+                        } else {
+                            subscriptionCallback.onChildrenLoaded(parentId, data, options);
+                        }
+                        return;
                     }
-                    return;
                 }
-
-                // Tell the app.
-                subscription.callback.onChildrenLoaded(parentId, data);
+                if (DBG) {
+                    Log.d(TAG, "onLoadChildren for id that isn't subscribed id=" + parentId);
+                }
             }
         });
     }
@@ -574,6 +692,9 @@
         Log.d(TAG, "  mMediaSessionToken=" + mMediaSessionToken);
     }
 
+    /**
+     * A class with information on a single media item for use in browsing media.
+     */
     public static class MediaItem implements Parcelable {
         private final int mFlags;
         private final MediaDescription mDescription;
@@ -694,7 +815,6 @@
         }
     }
 
-
     /**
      * Callbacks for connection related events.
      */
@@ -732,6 +852,19 @@
         }
 
         /**
+         * 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
+         *            browse service. The contents of this bundle may affect the
+         *            information returned when browsing.
+         */
+        public void onChildrenLoaded(@NonNull String parentId, List<MediaItem> children,
+                @NonNull Bundle options) {
+        }
+
+        /**
          * Called when the id doesn't exist or other errors in subscribing.
          * <p>
          * If this is called, the subscription remains until {@link MediaBrowser#unsubscribe}
@@ -739,10 +872,25 @@
          * </p>
          *
          * @param parentId The media id of the parent media item whose children could
-         * not be loaded.
+         *            not be loaded.
          */
         public void onError(@NonNull String parentId) {
         }
+
+        /**
+         * Called when the id doesn't exist or other errors in subscribing.
+         * <p>
+         * If this is called, the subscription remains until {@link MediaBrowser#unsubscribe}
+         * called, because some errors may heal themselves.
+         * </p>
+         *
+         * @param parentId The media id of the parent media item whose children could
+         *            not be loaded.
+         * @param options A bundle of service-specific arguments sent to the media
+         *            browse service.
+         */
+        public void onError(@NonNull String parentId, @NonNull Bundle options) {
+        }
     }
 
     /**
@@ -906,20 +1054,65 @@
         }
 
         @Override
-        public void onLoadChildren(final String parentId, final ParceledListSlice list) {
+        public void onLoadChildren(final String parentId, final ParceledListSlice list,
+                final Bundle options) {
             MediaBrowser mediaBrowser = mMediaBrowser.get();
             if (mediaBrowser != null) {
-                mediaBrowser.onLoadChildren(this, parentId, list);
+                mediaBrowser.onLoadChildren(this, parentId, list, options);
             }
         }
     }
 
     private static class Subscription {
-        final String id;
-        SubscriptionCallback callback;
+        private final List<SubscriptionCallback> mCallbacks;
+        private final List<Bundle> mOptionsList;
 
-        Subscription(String id) {
-            this.id = id;
+        public Subscription() {
+            mCallbacks = new ArrayList<>();
+            mOptionsList = new ArrayList<>();
+        }
+
+        public boolean isEmpty() {
+            return mCallbacks.isEmpty();
+        }
+
+        public List<Bundle> getOptionsList() {
+            return mOptionsList;
+        }
+
+        public List<SubscriptionCallback> getCallbacks() {
+            return mCallbacks;
+        }
+
+        public void add(SubscriptionCallback callback, Bundle options) {
+            for (int i = 0; i < mOptionsList.size(); ++i) {
+                if (MediaBrowserUtils.areSameOptions(mOptionsList.get(i), options)) {
+                    mCallbacks.set(i, callback);
+                    return;
+                }
+            }
+            mCallbacks.add(callback);
+            mOptionsList.add(options);
+        }
+
+        public boolean remove(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;
+        }
+
+        public SubscriptionCallback getCallback(Bundle options) {
+            for (int i = 0; i < mOptionsList.size(); ++i) {
+                if (MediaBrowserUtils.areSameOptions(mOptionsList.get(i), options)) {
+                    return mCallbacks.get(i);
+                }
+            }
+            return null;
         }
     }
 }
diff --git a/media/java/android/media/browse/MediaBrowserUtils.java b/media/java/android/media/browse/MediaBrowserUtils.java
new file mode 100644
index 0000000..4f198ac
--- /dev/null
+++ b/media/java/android/media/browse/MediaBrowserUtils.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.browse;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+public class MediaBrowserUtils {
+    public static boolean areSameOptions(Bundle options1, Bundle options2) {
+        if (options1 == options2) {
+            return true;
+        } else if (options1 == null) {
+            return options2.getInt(MediaBrowser.EXTRA_PAGE, -1) == -1
+                    && options2.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1) == -1;
+        } else if (options2 == null) {
+            return options1.getInt(MediaBrowser.EXTRA_PAGE, -1) == -1
+                    && options1.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1) == -1;
+        } else {
+            return options1.getInt(MediaBrowser.EXTRA_PAGE, -1)
+                    == options2.getInt(MediaBrowser.EXTRA_PAGE, -1)
+                    && options1.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1)
+                    == options2.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
+        }
+    }
+
+    public static boolean hasDuplicatedItems(Bundle options1, Bundle options2) {
+        int page1 = options1.getInt(MediaBrowser.EXTRA_PAGE, -1);
+        int page2 = options2.getInt(MediaBrowser.EXTRA_PAGE, -1);
+        int pageSize1 = options1.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
+        int pageSize2 = options2.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
+
+        int startIndex1, startIndex2, endIndex1, endIndex2;
+        if (page1 == -1 || pageSize1 == -1) {
+            startIndex1 = 0;
+            endIndex1 = Integer.MAX_VALUE;
+        } else {
+            startIndex1 = pageSize1 * (page1 - 1);
+            endIndex1 = startIndex1 + pageSize1 - 1;
+        }
+
+        if (page2 == -1 || pageSize2 == -1) {
+            startIndex2 = 0;
+            endIndex2 = Integer.MAX_VALUE;
+        } else {
+            startIndex2 = pageSize2 * (page2 - 1);
+            endIndex2 = startIndex2 + pageSize2 - 1;
+        }
+
+        if (startIndex1 <= startIndex2 && startIndex2 <= endIndex1) {
+            return true;
+        } else if (startIndex1 <= endIndex2 && endIndex2 <= endIndex1) {
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index b1a51a56..3d9b60d 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -605,6 +605,7 @@
         /**
          * Request that the player start playback for a specific media id.
          *
+         * @see PlaybackState#EXTRA_PREPARE_ONLY
          * @param mediaId The id of the requested media.
          * @param extras Optional extras that can include extra information about the media item
          *               to be played.
@@ -626,6 +627,7 @@
          * An empty or null query should be treated as a request to play any
          * music.
          *
+         * @see PlaybackState#EXTRA_PREPARE_ONLY
          * @param query The search query.
          * @param extras Optional extras that can include extra information
          *            about the query.
@@ -646,6 +648,7 @@
         /**
          * Request that the player start playback for a specific {@link Uri}.
          *
+         * @see PlaybackState#EXTRA_PREPARE_ONLY
          * @param uri  The URI of the requested media.
          * @param extras Optional extras that can include extra information about the media item
          *               to be played.
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index e1e9b79..8c5b19c 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -87,6 +87,12 @@
     public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1;
 
     /**
+     * Set this flag on the session to indicate that it can handle
+     * the {@link PlaybackState#EXTRA_PREPARE_ONLY} field.
+     */
+    public static final int FLAG_HANDLES_PREPARE_ONLY = 1 << 2;
+
+    /**
      * System only flag for a session that needs to have priority over all other
      * sessions. This flag ensures this session will receive media button events
      * regardless of the current ordering in the system.
@@ -100,6 +106,7 @@
     @IntDef(flag = true, value = {
             FLAG_HANDLES_MEDIA_BUTTONS,
             FLAG_HANDLES_TRANSPORT_CONTROLS,
+            FLAG_HANDLES_PREPARE_ONLY,
             FLAG_EXCLUSIVE_GLOBAL_PRIORITY })
     public @interface SessionFlags { }
 
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index bbe04b5..1079a1f 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -133,6 +133,21 @@
     public static final long ACTION_PLAY_FROM_URI = 1 << 13;
 
     /**
+     * Used as an optional boolean extra field in
+     * {@link MediaController.TransportControls#playFromMediaId},
+     * {@link MediaController.TransportControls#playFromSearch}, and
+     * {@link MediaController.TransportControls#playFromUri}. Value of {@code true} overrides
+     * the default behavior of starting the playback after preparing. Check
+     * {@link MediaSession#FLAG_HANDLES_PREPARE_ONLY} to see if the media session supports this.
+     *
+     * @see MediaSession#FLAG_HANDLES_PREPARE_ONLY
+     * @see MediaController.TransportControls#playFromMediaId
+     * @see MediaController.TransportControls#playFromSearch
+     * @see MediaController.TransportControls#playFromUri
+     */
+    public static final String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
+
+    /**
      * 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.
      *
diff --git a/media/java/android/media/soundtrigger/SoundTriggerDetector.java b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
new file mode 100644
index 0000000..707db06
--- /dev/null
+++ b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
@@ -0,0 +1,184 @@
+/**
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.soundtrigger;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.SoundTrigger;
+import android.os.Handler;
+import android.os.ParcelUuid;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.app.ISoundTriggerService;
+
+import java.io.PrintWriter;
+import java.util.UUID;
+
+/**
+ * A class that allows interaction with the actual sound trigger detection on the system.
+ * Sound trigger detection refers to a detectors that match generic sound patterns that are
+ * not voice-based. The voice-based recognition models should utilize the {@link
+ * VoiceInteractionService} instead. Access to this class is protected by a permission
+ * granted only to system or privileged apps.
+ *
+ * @hide
+ */
+@SystemApi
+public final class SoundTriggerDetector {
+    private static final boolean DBG = false;
+    private static final String TAG = "SoundTriggerDetector";
+
+    private final Object mLock = new Object();
+
+    private final ISoundTriggerService mSoundTriggerService;
+    private final UUID mSoundModelId;
+    private final Callback mCallback;
+    private final Handler mHandler;
+    private final RecognitionCallback mRecognitionCallback;
+
+    public abstract class Callback {
+        /**
+         * Called when the availability of the sound model changes.
+         */
+        public abstract void onAvailabilityChanged(int status);
+
+        /**
+         * Called when the sound model has triggered (such as when it matched a
+         * given sound pattern).
+         */
+        public abstract void onDetected();
+
+        /**
+         *  Called when the detection fails due to an error.
+         */
+        public abstract void onError();
+
+        /**
+         * Called when the recognition is paused temporarily for some reason.
+         * This is an informational callback, and the clients shouldn't be doing anything here
+         * except showing an indication on their UI if they have to.
+         */
+        public abstract void onRecognitionPaused();
+
+        /**
+         * Called when the recognition is resumed after it was temporarily paused.
+         * This is an informational callback, and the clients shouldn't be doing anything here
+         * except showing an indication on their UI if they have to.
+         */
+        public abstract void onRecognitionResumed();
+    }
+
+    /**
+     * This class should be constructed by the {@link SoundTriggerManager}.
+     * @hide
+     */
+    SoundTriggerDetector(ISoundTriggerService soundTriggerService, UUID soundModelId,
+            @NonNull Callback callback, @Nullable Handler handler) {
+        mSoundTriggerService = soundTriggerService;
+        mSoundModelId = soundModelId;
+        mCallback = callback;
+        if (handler == null) {
+            mHandler = new Handler();
+        } else {
+            mHandler = handler;
+        }
+        mRecognitionCallback = new RecognitionCallback();
+    }
+
+    /**
+     * Starts recognition on the associated sound model. Result is indicated via the
+     * {@link Callback}.
+     * @return Indicates whether the call succeeded or not.
+     */
+    public boolean startRecognition() {
+        if (DBG) {
+            Slog.d(TAG, "startRecognition()");
+        }
+        try {
+            mSoundTriggerService.startRecognition(new ParcelUuid(mSoundModelId),
+                    mRecognitionCallback);
+        } catch (RemoteException e) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Stops recognition for the associated model.
+     */
+    public boolean stopRecognition() {
+        try {
+            mSoundTriggerService.stopRecognition(new ParcelUuid(mSoundModelId),
+                    mRecognitionCallback);
+        } catch (RemoteException e) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * @hide
+     */
+    public void dump(String prefix, PrintWriter pw) {
+        synchronized (mLock) {
+            // TODO: Dump useful debug information.
+        }
+    }
+
+    /**
+     * Callback that handles events from the lower sound trigger layer.
+     * @hide
+     */
+    private static class RecognitionCallback extends
+            IRecognitionStatusCallback.Stub {
+
+        /**
+         * @hide
+         */
+        @Override
+        public void onDetected(SoundTrigger.RecognitionEvent event) {
+            Slog.e(TAG, "onDetected()" + event);
+        }
+
+        /**
+         * @hide
+         */
+        @Override
+        public void onError(int status) {
+            Slog.e(TAG, "onError()" + status);
+        }
+
+        /**
+         * @hide
+         */
+        @Override
+        public void onRecognitionPaused() {
+            Slog.e(TAG, "onRecognitionPaused()");
+        }
+
+        /**
+         * @hide
+         */
+        @Override
+        public void onRecognitionResumed() {
+            Slog.e(TAG, "onRecognitionResumed()");
+        }
+    }
+}
diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java
new file mode 100644
index 0000000..4fd3310
--- /dev/null
+++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java
@@ -0,0 +1,172 @@
+/**
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.soundtrigger;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.hardware.soundtrigger.SoundTrigger;
+import android.os.Handler;
+import android.os.ParcelUuid;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.app.ISoundTriggerService;
+
+import java.util.HashMap;
+import java.util.UUID;
+
+/**
+ * This class provides management of non-voice (general sound trigger) based sound recognition
+ * models. Usage of this class is restricted to system or signature applications only. This allows
+ * OEMs to write apps that can manage non-voice based sound trigger models.
+ *
+ * @hide
+ */
+@SystemApi
+public final class SoundTriggerManager {
+    private static final boolean DBG = false;
+    private static final String TAG = "SoundTriggerManager";
+
+    private final Context mContext;
+    private final ISoundTriggerService mSoundTriggerService;
+
+    // Stores a mapping from the sound model UUID to the SoundTriggerInstance created by
+    // the createSoundTriggerDetector() call.
+    private final HashMap<UUID, SoundTriggerDetector> mReceiverInstanceMap;
+
+    /**
+     * @hide
+     */
+    public SoundTriggerManager(Context context, ISoundTriggerService soundTriggerService ) {
+        if (DBG) {
+            Slog.i(TAG, "SoundTriggerManager created.");
+        }
+        mSoundTriggerService = soundTriggerService;
+        mContext = context;
+        mReceiverInstanceMap = new HashMap<UUID, SoundTriggerDetector>();
+    }
+
+    /**
+     * Updates the given sound trigger model.
+     */
+    public void updateModel(Model model) {
+        try {
+            mSoundTriggerService.updateSoundModel(model.getGenericSoundModel());
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Returns the sound trigger model represented by the given UUID. An instance of {@link Model}
+     * is returned.
+     */
+    public Model getModel(UUID soundModelId) {
+        try {
+            return new Model(mSoundTriggerService.getSoundModel(
+                    new ParcelUuid(soundModelId)));
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Deletes the sound model represented by the provided UUID.
+     */
+    public void deleteModel(UUID soundModelId) {
+        try {
+            mSoundTriggerService.deleteSoundModel(new ParcelUuid(soundModelId));
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Creates an instance of {@link SoundTriggerDetector} which can be used to start/stop
+     * recognition on the model and register for triggers from the model. Note that this call
+     * invalidates any previously returned instances for the same sound model Uuid.
+     *
+     * @param soundModelId UUID of the sound model to create the receiver object for.
+     * @param callback Instance of the {@link SoundTriggerDetector#Callback} object for the
+     * callbacks for the given sound model.
+     * @param handler The Handler to use for the callback operations. A null value will use the
+     * current thread's Looper.
+     * @return Instance of {@link SoundTriggerDetector} or null on error.
+     */
+    @Nullable
+    public SoundTriggerDetector createSoundTriggerDetector(UUID soundModelId,
+            @NonNull SoundTriggerDetector.Callback callback, @Nullable Handler handler) {
+        if (soundModelId == null) {
+            return null;
+        }
+
+        SoundTriggerDetector oldInstance = mReceiverInstanceMap.get(soundModelId);
+        if (oldInstance != null) {
+            // Shutdown old instance.
+        }
+        SoundTriggerDetector newInstance = new SoundTriggerDetector(mSoundTriggerService,
+                soundModelId, callback, handler);
+        mReceiverInstanceMap.put(soundModelId, newInstance);
+        return newInstance;
+    }
+
+    /**
+     * Class captures the data and fields that represent a non-keyphrase sound model. Use the
+     * factory constructor {@link Model#create()} to create an instance.
+     */
+    // We use encapsulation to expose the SoundTrigger.GenericSoundModel as a SystemApi. This
+    // prevents us from exposing SoundTrigger.GenericSoundModel as an Api.
+    public static class Model {
+
+        private SoundTrigger.GenericSoundModel mGenericSoundModel;
+
+        /**
+         * @hide
+         */
+        Model(SoundTrigger.GenericSoundModel soundTriggerModel) {
+            mGenericSoundModel = soundTriggerModel;
+        }
+
+        /**
+         * Factory constructor to create a SoundModel instance for use with methods in this
+         * class.
+         */
+        public static Model create(UUID modelUuid, UUID vendorUuid, byte[] data) {
+            return new Model(new SoundTrigger.GenericSoundModel(modelUuid,
+                        vendorUuid, data));
+        }
+
+        public UUID getModelUuid() {
+            return mGenericSoundModel.uuid;
+        }
+
+        public UUID getVendorUuid() {
+            return mGenericSoundModel.vendorUuid;
+        }
+
+        public byte[] getModelData() {
+            return mGenericSoundModel.data;
+        }
+
+        /**
+         * @hide
+         */
+        SoundTrigger.GenericSoundModel getGenericSoundModel() {
+            return mGenericSoundModel;
+        }
+    }
+}
diff --git a/media/java/android/media/tv/ITvInputClient.aidl b/media/java/android/media/tv/ITvInputClient.aidl
index 86c0e5d..8ef5ca0 100644
--- a/media/java/android/media/tv/ITvInputClient.aidl
+++ b/media/java/android/media/tv/ITvInputClient.aidl
@@ -43,4 +43,10 @@
     void onTimeShiftStatusChanged(int status, int seq);
     void onTimeShiftStartPositionChanged(long timeMs, int seq);
     void onTimeShiftCurrentPositionChanged(long timeMs, int seq);
+
+    // For the recording session
+    void onConnected(int seq);
+    void onRecordingStarted(int seq);
+    void onRecordingStopped(in Uri recordedProgramUri, int seq);
+    void onError(int error, int seq);
 }
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index f8057db..d189333 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -41,6 +41,7 @@
 interface ITvInputManager {
     List<TvInputInfo> getTvInputList(int userId);
     TvInputInfo getTvInputInfo(in String inputId, int userId);
+    void setTvInputInfo(in TvInputInfo inputInfo, int userId);
     int getTvInputState(in String inputId, int userId);
 
     List<TvContentRatingSystemInfo> getTvContentRatingSystemList(int userId);
@@ -55,7 +56,8 @@
     void addBlockedRating(in String rating, int userId);
     void removeBlockedRating(in String rating, int userId);
 
-    void createSession(in ITvInputClient client, in String inputId, int seq, int userId);
+    void createSession(in ITvInputClient client, in String inputId, boolean isRecordingSession,
+            int seq, int userId);
     void releaseSession(in IBinder sessionToken, int userId);
 
     void setMainSession(in IBinder sessionToken, int userId);
@@ -77,12 +79,18 @@
 
     void unblockContent(in IBinder sessionToken, in String unblockedRating, int userId);
 
+    void timeShiftPlay(in IBinder sessionToken, in Uri recordedProgramUri, int userId);
     void timeShiftPause(in IBinder sessionToken, int userId);
     void timeShiftResume(in IBinder sessionToken, int userId);
     void timeShiftSeekTo(in IBinder sessionToken, long timeMs, int userId);
     void timeShiftSetPlaybackParams(in IBinder sessionToken, in PlaybackParams params, int userId);
     void timeShiftEnablePositionTracking(in IBinder sessionToken, boolean enable, int userId);
 
+    // For the recording session
+    void connect(in IBinder sessionToken, in Uri channelUri, in Bundle params, int userId);
+    void startRecording(in IBinder sessionToken, int userId);
+    void stopRecording(in IBinder sessionToken, int userId);
+
     // For TV input hardware binding
     List<TvInputHardwareInfo> getHardwareList();
     ITvInputHardware acquireTvInputHardware(int deviceId, in ITvInputHardwareCallback callback,
diff --git a/media/java/android/media/tv/ITvInputManagerCallback.aidl b/media/java/android/media/tv/ITvInputManagerCallback.aidl
index 6792680..395c9f3 100644
--- a/media/java/android/media/tv/ITvInputManagerCallback.aidl
+++ b/media/java/android/media/tv/ITvInputManagerCallback.aidl
@@ -16,13 +16,18 @@
 
 package android.media.tv;
 
+import android.media.tv.TvInputInfo;
+
 /**
  * Interface to receive callbacks from ITvInputManager regardless of sessions.
  * @hide
  */
 oneway interface ITvInputManagerCallback {
-    void onInputStateChanged(in String inputId, int state);
     void onInputAdded(in String inputId);
     void onInputRemoved(in String inputId);
     void onInputUpdated(in String inputId);
+
+    void onInputStateChanged(in String inputId, int state);
+
+    void onTvInputInfoChanged(in TvInputInfo TvInputInfo);
 }
diff --git a/media/java/android/media/tv/ITvInputService.aidl b/media/java/android/media/tv/ITvInputService.aidl
index 7a853d1..bd05184 100644
--- a/media/java/android/media/tv/ITvInputService.aidl
+++ b/media/java/android/media/tv/ITvInputService.aidl
@@ -27,10 +27,11 @@
  * @hide
  */
 oneway interface ITvInputService {
-    void registerCallback(ITvInputServiceCallback callback);
+    void registerCallback(in ITvInputServiceCallback callback);
     void unregisterCallback(in ITvInputServiceCallback callback);
-    void createSession(in InputChannel channel, ITvInputSessionCallback callback,
+    void createSession(in InputChannel channel, in ITvInputSessionCallback callback,
             in String inputId);
+    void createRecordingSession(in ITvInputSessionCallback callback, in String inputId);
 
     // For hardware TvInputService
     void notifyHardwareAdded(in TvInputHardwareInfo hardwareInfo);
diff --git a/media/java/android/media/tv/ITvInputSession.aidl b/media/java/android/media/tv/ITvInputSession.aidl
index 6a06b8f..408a762 100644
--- a/media/java/android/media/tv/ITvInputSession.aidl
+++ b/media/java/android/media/tv/ITvInputSession.aidl
@@ -48,9 +48,16 @@
 
     void unblockContent(in String unblockedRating);
 
+    void timeShiftPlay(in Uri recordedProgramUri);
     void timeShiftPause();
     void timeShiftResume();
     void timeShiftSeekTo(long timeMs);
     void timeShiftSetPlaybackParams(in PlaybackParams params);
     void timeShiftEnablePositionTracking(boolean enable);
+
+    // For the recording session
+    void connect(in Uri channelUri, in Bundle params);
+    void disconnect();
+    void startRecording();
+    void stopRecording();
 }
diff --git a/media/java/android/media/tv/ITvInputSessionCallback.aidl b/media/java/android/media/tv/ITvInputSessionCallback.aidl
index e936810..cb6a05e 100644
--- a/media/java/android/media/tv/ITvInputSessionCallback.aidl
+++ b/media/java/android/media/tv/ITvInputSessionCallback.aidl
@@ -40,4 +40,10 @@
     void onTimeShiftStatusChanged(int status);
     void onTimeShiftStartPositionChanged(long timeMs);
     void onTimeShiftCurrentPositionChanged(long timeMs);
+
+    // For the recording session
+    void onConnected();
+    void onRecordingStarted();
+    void onRecordingStopped(in Uri recordedProgramUri);
+    void onError(int error);
 }
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index f8c6f3f..4ac5876 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -59,20 +59,29 @@
     private static final int DO_RELAYOUT_OVERLAY_VIEW = 11;
     private static final int DO_REMOVE_OVERLAY_VIEW = 12;
     private static final int DO_UNBLOCK_CONTENT = 13;
-    private static final int DO_TIME_SHIFT_PAUSE = 14;
-    private static final int DO_TIME_SHIFT_RESUME = 15;
-    private static final int DO_TIME_SHIFT_SEEK_TO = 16;
-    private static final int DO_TIME_SHIFT_SET_PLAYBACK_PARAMS = 17;
-    private static final int DO_TIME_SHIFT_ENABLE_POSITION_TRACKING = 18;
+    private static final int DO_TIME_SHIFT_PLAY = 14;
+    private static final int DO_TIME_SHIFT_PAUSE = 15;
+    private static final int DO_TIME_SHIFT_RESUME = 16;
+    private static final int DO_TIME_SHIFT_SEEK_TO = 17;
+    private static final int DO_TIME_SHIFT_SET_PLAYBACK_PARAMS = 18;
+    private static final int DO_TIME_SHIFT_ENABLE_POSITION_TRACKING = 19;
+    private static final int DO_CONNECT = 20;
+    private static final int DO_DISCONNECT = 21;
+    private static final int DO_START_RECORDING = 22;
+    private static final int DO_STOP_RECORDING = 23;
 
+    private final boolean mIsRecordingSession;
     private final HandlerCaller mCaller;
 
     private TvInputService.Session mTvInputSessionImpl;
+    private TvInputService.RecordingSession mTvInputRecordingSessionImpl;
+
     private InputChannel mChannel;
     private TvInputEventReceiver mReceiver;
 
     public ITvInputSessionWrapper(Context context, TvInputService.Session sessionImpl,
             InputChannel channel) {
+        mIsRecordingSession = false;
         mCaller = new HandlerCaller(context, null, this, true /* asyncHandler */);
         mTvInputSessionImpl = sessionImpl;
         mChannel = channel;
@@ -81,9 +90,19 @@
         }
     }
 
+    public ITvInputSessionWrapper(Context context,
+            TvInputService.RecordingSession recordingSessionImpl) {
+        mIsRecordingSession = true;
+        mCaller = new HandlerCaller(context, null, this, true /* asyncHandler */);
+        mTvInputRecordingSessionImpl = recordingSessionImpl;
+    }
+
     @Override
     public void executeMessage(Message msg) {
-        if (mTvInputSessionImpl == null) {
+        if (!mIsRecordingSession && mTvInputSessionImpl == null) {
+            return;
+        }
+        if (mIsRecordingSession && mTvInputRecordingSessionImpl == null) {
             return;
         }
 
@@ -138,7 +157,12 @@
             }
             case DO_APP_PRIVATE_COMMAND: {
                 SomeArgs args = (SomeArgs) msg.obj;
-                mTvInputSessionImpl.appPrivateCommand((String) args.arg1, (Bundle) args.arg2);
+                if (mIsRecordingSession) {
+                    mTvInputRecordingSessionImpl.appPrivateCommand(
+                            (String) args.arg1, (Bundle) args.arg2);
+                } else {
+                    mTvInputSessionImpl.appPrivateCommand((String) args.arg1, (Bundle) args.arg2);
+                }
                 args.recycle();
                 break;
             }
@@ -160,6 +184,10 @@
                 mTvInputSessionImpl.unblockContent((String) msg.obj);
                 break;
             }
+            case DO_TIME_SHIFT_PLAY: {
+                mTvInputSessionImpl.timeShiftPlay((Uri) msg.obj);
+                break;
+            }
             case DO_TIME_SHIFT_PAUSE: {
                 mTvInputSessionImpl.timeShiftPause();
                 break;
@@ -180,6 +208,25 @@
                 mTvInputSessionImpl.timeShiftEnablePositionTracking((Boolean) msg.obj);
                 break;
             }
+            case DO_CONNECT: {
+                SomeArgs args = (SomeArgs) msg.obj;
+                mTvInputRecordingSessionImpl.connect((Uri) args.arg1, (Bundle) args.arg2);
+                args.recycle();
+                break;
+            }
+            case DO_DISCONNECT: {
+                mTvInputRecordingSessionImpl.disconnect();
+                mTvInputRecordingSessionImpl = null;
+                break;
+            }
+            case DO_START_RECORDING: {
+                mTvInputRecordingSessionImpl.startRecording();
+                break;
+            }
+            case DO_STOP_RECORDING: {
+                mTvInputRecordingSessionImpl.stopRecording();
+                break;
+            }
             default: {
                 Log.w(TAG, "Unhandled message code: " + msg.what);
                 break;
@@ -274,6 +321,12 @@
     }
 
     @Override
+    public void timeShiftPlay(Uri recordedProgramUri) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageO(
+                DO_TIME_SHIFT_PLAY, recordedProgramUri));
+    }
+
+    @Override
     public void timeShiftPause() {
         mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_TIME_SHIFT_PAUSE));
     }
@@ -300,6 +353,28 @@
                 DO_TIME_SHIFT_ENABLE_POSITION_TRACKING, enable));
     }
 
+    @Override
+    public void connect(Uri channelUri, Bundle params) {
+        // Clear the pending connect requests.
+        mCaller.removeMessages(DO_CONNECT);
+        mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_CONNECT, channelUri, params));
+    }
+
+    @Override
+    public void disconnect() {
+        mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_DISCONNECT));
+    }
+
+    @Override
+    public void startRecording() {
+        mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_START_RECORDING));
+    }
+
+    @Override
+    public void stopRecording() {
+        mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_STOP_RECORDING));
+    }
+
     private final class TvInputEventReceiver extends InputEventReceiver {
         public TvInputEventReceiver(InputChannel inputChannel, Looper looper) {
             super(inputChannel, looper);
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 7cd086e..62a01dc 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -54,6 +54,7 @@
 
     private static final String PATH_CHANNEL = "channel";
     private static final String PATH_PROGRAM = "program";
+    private static final String PATH_RECORDED_PROGRAM = "recorded_program";
     private static final String PATH_PASSTHROUGH = "passthrough";
 
     /**
@@ -273,6 +274,15 @@
     }
 
     /**
+     * Builds a URI that points to a specific recorded program.
+     *
+     * @param recordedProgramId The ID of the recorded program to point to.
+     */
+    public static final Uri buildRecordedProgramUri(long recordedProgramId) {
+        return ContentUris.withAppendedId(RecordedPrograms.CONTENT_URI, recordedProgramId);
+    }
+
+    /**
      * Builds a URI that points to a specific program the user watched.
      *
      * @param watchedProgramId The ID of the watched program to point to.
@@ -941,6 +951,8 @@
          *
          * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
          *
+         * <p>This is a required field.
+         *
          * <p>Type: INTEGER (long)
          */
         public static final String COLUMN_CHANNEL_ID = "channel_id";
@@ -1336,6 +1348,382 @@
     }
 
     /**
+     * Column definitions for the recorded TV programs table.
+     *
+     * <p>By default, the query results will be sorted by {@link #COLUMN_START_TIME_UTC_MILLIS} in
+     * ascending order.
+     */
+    public static final class RecordedPrograms implements BaseTvColumns {
+
+        /** The content:// style URI for this table. */
+        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
+                + PATH_RECORDED_PROGRAM);
+
+        /** The MIME type of a directory of recorded TV programs. */
+        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/recorded_program";
+
+        /** The MIME type of a single recorded TV program. */
+        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
+
+        /**
+         * The ID of the TV channel that provided this recorded TV program.
+         *
+         * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
+         *
+         * <p>This is a required field.
+         *
+         * <p>Type: INTEGER (long)
+         * @see Programs#COLUMN_CHANNEL_ID
+         */
+        public static final String COLUMN_CHANNEL_ID = Programs.COLUMN_CHANNEL_ID;
+
+        /**
+         * 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.
+         *
+         * <p>Type: TEXT
+         * @see Programs#COLUMN_TITLE
+         */
+        public static final String COLUMN_TITLE = Programs.COLUMN_TITLE;
+
+        /**
+         * The season number of this recorded TV program for episodic TV shows.
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: INTEGER
+         * @see Programs#COLUMN_SEASON_NUMBER
+         */
+        public static final String COLUMN_SEASON_NUMBER = Programs.COLUMN_SEASON_NUMBER;
+
+        /**
+         * The episode number of this recorded TV program for episodic TV shows.
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: INTEGER
+         * @see Programs#COLUMN_EPISODE_NUMBER
+         */
+        public static final String COLUMN_EPISODE_NUMBER = Programs.COLUMN_EPISODE_NUMBER;
+
+        /**
+         * The episode title of this recorded TV program for episodic TV shows.
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         * @see Programs#COLUMN_EPISODE_TITLE
+         */
+        public static final String COLUMN_EPISODE_TITLE = Programs.COLUMN_EPISODE_TITLE;
+
+        /**
+         * The start time of the original TV program, in milliseconds since the epoch.
+         *
+         * <p>Type: INTEGER (long)
+         * @see Programs#COLUMN_START_TIME_UTC_MILLIS
+         */
+        public static final String COLUMN_START_TIME_UTC_MILLIS =
+                Programs.COLUMN_START_TIME_UTC_MILLIS;
+
+        /**
+         * The end time of the original TV program, in milliseconds since the epoch.
+         *
+         * <p>Type: INTEGER (long)
+         * @see Programs#COLUMN_END_TIME_UTC_MILLIS
+         */
+        public static final String COLUMN_END_TIME_UTC_MILLIS = Programs.COLUMN_END_TIME_UTC_MILLIS;
+
+        /**
+         * The comma-separated genre string of this recorded TV program.
+         *
+         * <p>Use the same language appeared in the underlying broadcast standard, if applicable.
+         * (For example, one can refer to the genre strings used in Genre Descriptor of ATSC A/65 or
+         * Content Descriptor of ETSI EN 300 468, if appropriate.) Otherwise, leave empty.
+         *
+         * <p>Type: TEXT
+         * @see Programs#COLUMN_BROADCAST_GENRE
+         */
+        public static final String COLUMN_BROADCAST_GENRE = Programs.COLUMN_BROADCAST_GENRE;
+
+        /**
+         * The comma-separated canonical genre string of this recorded TV program.
+         *
+         * <p>Canonical genres are defined in {@link Programs.Genres}. Use
+         * {@link Programs.Genres#encode Genres.encode()} to create a text that can be stored in
+         * this column. Use {@link Programs.Genres#decode Genres.decode()} to get the canonical
+         * genre strings from the text stored in this column.
+         *
+         * <p>Type: TEXT
+         * @see Programs#COLUMN_CANONICAL_GENRE
+         * @see Programs.Genres
+         */
+        public static final String COLUMN_CANONICAL_GENRE = Programs.COLUMN_CANONICAL_GENRE;
+
+        /**
+         * The short description of this recorded TV program that is displayed to the user by
+         * default.
+         *
+         * <p>It is recommended to limit the length of the descriptions to 256 characters.
+         *
+         * <p>Type: TEXT
+         * @see Programs#COLUMN_SHORT_DESCRIPTION
+         */
+        public static final String COLUMN_SHORT_DESCRIPTION = Programs.COLUMN_SHORT_DESCRIPTION;
+
+        /**
+         * The detailed, lengthy description of this recorded TV program that is displayed only when
+         * the user wants to see more information.
+         *
+         * <p>TV input services should leave this field empty if they have no additional details
+         * beyond {@link #COLUMN_SHORT_DESCRIPTION}.
+         *
+         * <p>Type: TEXT
+         * @see Programs#COLUMN_LONG_DESCRIPTION
+         */
+        public static final String COLUMN_LONG_DESCRIPTION = Programs.COLUMN_LONG_DESCRIPTION;
+
+        /**
+         * The width of the video for this recorded TV program, in the unit of pixels.
+         *
+         * <p>Together with {@link #COLUMN_VIDEO_HEIGHT} this is used to determine the video
+         * resolution of the current recorded TV program. Can be empty if it is not known or the
+         * recorded program does not convey any video.
+         *
+         * <p>Type: INTEGER
+         * @see Programs#COLUMN_VIDEO_WIDTH
+         */
+        public static final String COLUMN_VIDEO_WIDTH = Programs.COLUMN_VIDEO_WIDTH;
+
+        /**
+         * The height of the video for this recorded TV program, in the unit of pixels.
+         *
+         * <p>Together with {@link #COLUMN_VIDEO_WIDTH} this is used to determine the video
+         * resolution of the current recorded TV program. Can be empty if it is not known or the
+         * recorded program does not convey any video.
+         *
+         * <p>Type: INTEGER
+         * @see Programs#COLUMN_VIDEO_HEIGHT
+         */
+        public static final String COLUMN_VIDEO_HEIGHT = Programs.COLUMN_VIDEO_HEIGHT;
+
+        /**
+         * The comma-separated audio languages of this recorded TV program.
+         *
+         * <p>This is used to describe available audio languages included in the recorded program.
+         * Use either ISO 639-1 or 639-2/T codes.
+         *
+         * <p>Type: TEXT
+         * @see Programs#COLUMN_AUDIO_LANGUAGE
+         */
+        public static final String COLUMN_AUDIO_LANGUAGE = Programs.COLUMN_AUDIO_LANGUAGE;
+
+        /**
+         * The comma-separated content ratings of this recorded TV program.
+         *
+         * <p>This is used to describe the content rating(s) of this recorded program. Each
+         * comma-separated content rating sub-string should be generated by calling
+         * {@link TvContentRating#flattenToString}. Note that in most cases the recorded program
+         * content is rated by a single rating system, thus resulting in a corresponding single
+         * sub-string that does not require comma separation and multiple sub-strings appear only
+         * when the recorded program content is rated by two or more content rating systems. If any
+         * of those ratings is specified as "blocked rating" in the user's parental control
+         * settings, the TV input service should block the current content and wait for the signal
+         * that it is okay to unblock.
+         *
+         * <p>Type: TEXT
+         * @see Programs#COLUMN_CONTENT_RATING
+         */
+        public static final String COLUMN_CONTENT_RATING = Programs.COLUMN_CONTENT_RATING;
+
+        /**
+         * The URI for the poster art of this recorded TV program.
+         *
+         * <p>The data in the column must be a URL, or a URI in one of the following formats:
+         *
+         * <ul>
+         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+         * </li>
+         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+         * </ul>
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         * @see Programs#COLUMN_POSTER_ART_URI
+         */
+        public static final String COLUMN_POSTER_ART_URI = Programs.COLUMN_POSTER_ART_URI;
+
+        /**
+         * The URI for the thumbnail of this recorded TV program.
+         *
+         * <p>The system can generate a thumbnail from the poster art if this column is not
+         * specified. Thus it is not necessary for TV input services to include a thumbnail if it is
+         * just a scaled image of the poster art.
+         *
+         * <p>The data in the column must be a URL, or a URI in one of the following formats:
+         *
+         * <ul>
+         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+         * </li>
+         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+         * </ul>
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: TEXT
+         * @see Programs#COLUMN_THUMBNAIL_URI
+         */
+        public static final String COLUMN_THUMBNAIL_URI = Programs.COLUMN_THUMBNAIL_URI;
+
+        /**
+         * The flag indicating whether this recorded TV program is searchable or not.
+         *
+         * <p>The columns of searchable recorded programs can be read by other applications that
+         * have proper permission. Care must be taken not to open sensitive data.
+         *
+         * <p>A value of 1 indicates that the recorded program is searchable and its columns can be
+         * read by other applications, a value of 0 indicates that the recorded program is hidden
+         * and its columns can be read only by the package that owns the recorded program and the
+         * system. If not specified, this value is set to 1 (searchable) by default.
+         *
+         * <p>Type: INTEGER (boolean)
+         * @see Programs#COLUMN_SEARCHABLE
+         */
+        public static final String COLUMN_SEARCHABLE = Programs.COLUMN_SEARCHABLE;
+
+        /**
+         * The URI of the recording data for this recorded program.
+         *
+         * <p>Together with {@link #COLUMN_RECORDING_DATA_BYTES}, applications can use this
+         * information to manage recording storage. The URI should indicate a file or directory with
+         * the scheme {@link android.content.ContentResolver#SCHEME_FILE}.
+         *
+         * <p>Type: TEXT
+         * @see #COLUMN_RECORDING_DATA_BYTES
+         */
+        public static final String COLUMN_RECORDING_DATA_URI = "recording_data_uri";
+
+        /**
+         * The data size (in bytes) for this recorded program.
+         *
+         * <p>Together with {@link #COLUMN_RECORDING_DATA_URI}, applications can use this
+         * information to manage recording storage.
+         *
+         * <p>Type: INTEGER (long)
+         * @see #COLUMN_RECORDING_DATA_URI
+         */
+        public static final String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
+
+        /**
+         * The duration (in milliseconds) of this recorded program.
+         *
+         * <p>The actual duration of the recorded program can differ from the one calculated by
+         * {@link #COLUMN_END_TIME_UTC_MILLIS} - {@link #COLUMN_START_TIME_UTC_MILLIS} as program
+         * recording can be interrupted in the middle for some reason, resulting in a partially
+         * recorded program, which is still playable.
+         *
+         * <p>Type: INTEGER
+         */
+        public static final String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
+
+        /**
+         * The expiration time for this recorded program, in milliseconds since the epoch.
+         *
+         * <p>Recorded TV programs do not expire by default unless explicitly requested by the user
+         * or the user allows applications to delete them in order to free up disk space for future
+         * recording. However, some TV content can have expiration date set by the content provider
+         * when recorded. This field is used to indicate such a restriction.
+         *
+         * <p>Can be empty.
+         *
+         * <p>Type: INTEGER (long)
+         */
+        public static final String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS =
+                "recording_expire_time_utc_millis";
+
+
+        /**
+         * Internal data used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: BLOB
+         * @see Programs#COLUMN_INTERNAL_PROVIDER_DATA
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_DATA =
+                Programs.COLUMN_INTERNAL_PROVIDER_DATA;
+
+        /**
+         * Internal integer flag used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: INTEGER
+         * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG1
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 =
+                Programs.COLUMN_INTERNAL_PROVIDER_FLAG1;
+
+        /**
+         * Internal integer flag used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: INTEGER
+         * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG2
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 =
+                Programs.COLUMN_INTERNAL_PROVIDER_FLAG2;
+
+        /**
+         * Internal integer flag used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: INTEGER
+         * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG3
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 =
+                Programs.COLUMN_INTERNAL_PROVIDER_FLAG3;
+
+        /**
+         * Internal integer flag used by individual TV input services.
+         *
+         * <p>This is internal to the provider that inserted it, and should not be decoded by other
+         * apps.
+         *
+         * <p>Type: INTEGER
+         * @see Programs#COLUMN_INTERNAL_PROVIDER_FLAG4
+         */
+        public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 =
+                Programs.COLUMN_INTERNAL_PROVIDER_FLAG4;
+
+        /**
+         * The version number of this row entry used by TV input services.
+         *
+         * <p>This is best used by sync adapters to identify the rows to update. The number can be
+         * defined by individual TV input services. One may assign the same value as
+         * {@code version_number} in ETSI EN 300 468 or ATSC A/65, if the data are coming from a TV
+         * broadcast.
+         *
+         * <p>Type: INTEGER
+         * @see Programs#COLUMN_VERSION_NUMBER
+         */
+        public static final String COLUMN_VERSION_NUMBER = Programs.COLUMN_VERSION_NUMBER;
+
+        private RecordedPrograms() {}
+    }
+
+    /**
      * Column definitions for the TV programs that the user watched. Applications do not have access
      * to this table.
      *
@@ -1376,6 +1764,8 @@
         /**
          * The ID of the TV channel that provides this TV program.
          *
+         * <p>This is a required field.
+         *
          * <p>Type: INTEGER (long)
          */
         public static final String COLUMN_CHANNEL_ID = "channel_id";
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index a3d748e..20491e4 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -107,19 +107,12 @@
      */
     public static final String EXTRA_INPUT_ID = "android.media.tv.extra.INPUT_ID";
 
-    private static final SparseIntArray sHardwareTypeToTvInputType = new SparseIntArray();
-
-    private static final String XML_START_TAG_NAME = "tv-input";
-    private static final String DELIMITER_INFO_IN_ID = "/";
-    private static final String PREFIX_HDMI_DEVICE = "HDMI";
-    private static final String PREFIX_HARDWARE_DEVICE = "HW";
-    private static final int LENGTH_HDMI_PHYSICAL_ADDRESS = 4;
-    private static final int LENGTH_HDMI_DEVICE_ID = 2;
-
     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;
 
     // Attributes from XML meta data.
@@ -127,41 +120,14 @@
     private String mSettingsActivity;
 
     private HdmiDeviceInfo mHdmiDeviceInfo;
-    private int mLabelRes;
+    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;
 
-    static {
-        sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_OTHER_HARDWARE,
-                TYPE_OTHER);
-        sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_TUNER, TYPE_TUNER);
-        sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_COMPOSITE, TYPE_COMPOSITE);
-        sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_SVIDEO, TYPE_SVIDEO);
-        sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_SCART, TYPE_SCART);
-        sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_COMPONENT, TYPE_COMPONENT);
-        sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_VGA, TYPE_VGA);
-        sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_DVI, TYPE_DVI);
-        sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_HDMI, TYPE_HDMI);
-        sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_DISPLAY_PORT,
-                TYPE_DISPLAY_PORT);
-    }
-
-    /**
-     * Create a new instance of the TvInputInfo class,
-     * instantiating it from the given Context and ResolveInfo.
-     *
-     * @param service The ResolveInfo returned from the package manager about this TV input service.
-     * @hide
-     */
-    public static TvInputInfo createTvInputInfo(Context context, ResolveInfo service)
-            throws XmlPullParserException, IOException {
-        return createTvInputInfo(context, service, generateInputIdForComponentName(
-                new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name)),
-                null, TYPE_TUNER, false, 0, null, null, null, false);
-    }
-
     /**
      * Create a new instance of the TvInputInfo class, instantiating it from the given Context,
      * ResolveInfo, and HdmiDeviceInfo.
@@ -175,18 +141,20 @@
      *            {@link android.content.ContentResolver#openInputStream}. If it is {@code null},
      *            the application icon of {@code service} will be loaded.
      * @hide
+     * @deprecated Use {@link Builder} instead.
      */
+    @Deprecated
     @SystemApi
     public static TvInputInfo createTvInputInfo(Context context, ResolveInfo service,
             HdmiDeviceInfo hdmiDeviceInfo, String parentId, String label, Uri iconUri)
                     throws XmlPullParserException, IOException {
-        boolean isConnectedToHdmiSwitch = (hdmiDeviceInfo.getPhysicalAddress() & 0x0FFF) != 0;
-        TvInputInfo input = createTvInputInfo(context, service, generateInputIdForHdmiDevice(
-                new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name),
-                hdmiDeviceInfo), parentId, TYPE_HDMI, true, 0, label, null, iconUri,
-                isConnectedToHdmiSwitch);
-        input.mHdmiDeviceInfo = hdmiDeviceInfo;
-        return input;
+        TvInputInfo info = new TvInputInfo.Builder(context, service)
+                .setHdmiDeviceInfo(hdmiDeviceInfo)
+                .setParentId(parentId)
+                .build();
+        info.mLabel = label;
+        info.mIconUri = iconUri;
+        return info;
     }
 
     /**
@@ -201,18 +169,19 @@
      * @param icon The {@link android.graphics.drawable.Icon} to load the icon image. If it is
      *            {@code null}, the application icon of {@code service} will be loaded.
      * @hide
+     * @deprecated Use {@link Builder} instead.
      */
+    @Deprecated
     @SystemApi
     public static TvInputInfo createTvInputInfo(Context context, ResolveInfo service,
             HdmiDeviceInfo hdmiDeviceInfo, String parentId, int labelRes, Icon icon)
             throws XmlPullParserException, IOException {
-        boolean isConnectedToHdmiSwitch = (hdmiDeviceInfo.getPhysicalAddress() & 0x0FFF) != 0;
-        TvInputInfo input = createTvInputInfo(context, service, generateInputIdForHdmiDevice(
-                new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name),
-                hdmiDeviceInfo), parentId, TYPE_HDMI, true, labelRes, null, icon, null,
-                isConnectedToHdmiSwitch);
-        input.mHdmiDeviceInfo = hdmiDeviceInfo;
-        return input;
+        return new TvInputInfo.Builder(context, service)
+                .setHdmiDeviceInfo(hdmiDeviceInfo)
+                .setParentId(parentId)
+                .setLabel(labelRes)
+                .setIcon(icon)
+                .build();
     }
 
     /**
@@ -227,15 +196,19 @@
      *            {@link android.content.ContentResolver#openInputStream}. If it is {@code null},
      *            the application icon of {@code service} will be loaded.
      * @hide
+     * @deprecated Use {@link Builder} instead.
      */
+    @Deprecated
     @SystemApi
     public static TvInputInfo createTvInputInfo(Context context, ResolveInfo service,
             TvInputHardwareInfo hardwareInfo, String label, Uri iconUri)
                     throws XmlPullParserException, IOException {
-        int inputType = sHardwareTypeToTvInputType.get(hardwareInfo.getType(), TYPE_TUNER);
-        return createTvInputInfo(context, service, generateInputIdForHardware(
-                new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name),
-                hardwareInfo), null, inputType, true, 0, label, null, iconUri, false);
+        TvInputInfo info = new TvInputInfo.Builder(context, service)
+                .setTvInputHardwareInfo(hardwareInfo)
+                .build();
+        info.mLabel = label;
+        info.mIconUri = iconUri;
+        return info;
     }
 
     /**
@@ -249,77 +222,18 @@
      * @param icon The {@link android.graphics.drawable.Icon} to load the icon image. If it is
      *            {@code null}, the application icon of {@code service} will be loaded.
      * @hide
+     * @deprecated Use {@link Builder} instead.
      */
+    @Deprecated
     @SystemApi
     public static TvInputInfo createTvInputInfo(Context context, ResolveInfo service,
             TvInputHardwareInfo hardwareInfo, int labelRes, Icon icon)
             throws XmlPullParserException, IOException {
-        int inputType = sHardwareTypeToTvInputType.get(hardwareInfo.getType(), TYPE_TUNER);
-        return createTvInputInfo(context, service, generateInputIdForHardware(
-                new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name),
-                hardwareInfo), null, inputType, true, labelRes, null, icon, null, false);
-    }
-
-    private static TvInputInfo createTvInputInfo(Context context, ResolveInfo service, String id,
-            String parentId, int inputType, boolean isHardwareInput, int labelRes, String label,
-            Icon icon, Uri iconUri, boolean isConnectedToHdmiSwitch)
-                    throws XmlPullParserException, IOException {
-        ServiceInfo si = service.serviceInfo;
-        PackageManager pm = context.getPackageManager();
-        XmlResourceParser parser = null;
-        try {
-            parser = si.loadXmlMetaData(pm, TvInputService.SERVICE_META_DATA);
-            if (parser == null) {
-                throw new XmlPullParserException("No " + TvInputService.SERVICE_META_DATA
-                        + " meta-data for " + si.name);
-            }
-
-            Resources res = pm.getResourcesForApplication(si.applicationInfo);
-            AttributeSet attrs = Xml.asAttributeSet(parser);
-
-            int type;
-            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
-                    && type != XmlPullParser.START_TAG) {
-            }
-
-            String nodeName = parser.getName();
-            if (!XML_START_TAG_NAME.equals(nodeName)) {
-                throw new XmlPullParserException(
-                        "Meta-data does not start with tv-input-service tag in " + si.name);
-            }
-
-            TvInputInfo input = new TvInputInfo(service, id, parentId, inputType, isHardwareInput);
-            TypedArray sa = res.obtainAttributes(attrs,
-                    com.android.internal.R.styleable.TvInputService);
-            input.mSetupActivity = sa.getString(
-                    com.android.internal.R.styleable.TvInputService_setupActivity);
-            if (DEBUG) {
-                Log.d(TAG, "Setup activity loaded. [" + input.mSetupActivity + "] for " + si.name);
-            }
-            if (inputType == TYPE_TUNER && TextUtils.isEmpty(input.mSetupActivity)) {
-                throw new XmlPullParserException("Setup activity not found in " + si.name);
-            }
-            input.mSettingsActivity = sa.getString(
-                    com.android.internal.R.styleable.TvInputService_settingsActivity);
-            if (DEBUG) {
-                Log.d(TAG, "Settings activity loaded. [" + input.mSettingsActivity + "] for "
-                        + si.name);
-            }
-            sa.recycle();
-
-            input.mLabelRes = labelRes;
-            input.mLabel = label;
-            input.mIcon = icon;
-            input.mIconUri = iconUri;
-            input.mIsConnectedToHdmiSwitch = isConnectedToHdmiSwitch;
-            return input;
-        } catch (NameNotFoundException e) {
-            throw new XmlPullParserException("Unable to create context for: " + si.packageName);
-        } finally {
-            if (parser != null) {
-                parser.close();
-            }
-        }
+        return new TvInputInfo.Builder(context, service)
+                .setTvInputHardwareInfo(hardwareInfo)
+                .setLabel(labelRes)
+                .setIcon(icon)
+                .build();
     }
 
     /**
@@ -330,15 +244,23 @@
      * @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.
+     *            {@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 isHardwareInput, boolean isConnectedToHdmiSwitch, int tunerCount,
+            boolean canRecord) {
         mService = service;
         mId = id;
         mParentId = parentId;
         mType = type;
         mIsHardwareInput = isHardwareInput;
+        mIsConnectedToHdmiSwitch = isConnectedToHdmiSwitch;
+        mTunerCount = tunerCount;
+        mCanRecord = canRecord;
     }
 
     /**
@@ -419,6 +341,27 @@
     }
 
     /**
+     * Returns the number of tuners this TV input has.
+     *
+     * <p>This method is valid only for the input of type {@link #TYPE_TUNER}.
+     *
+     * <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;
+    }
+
+    /**
+     * Returns {@code true} if this TV input can record TV programs, {@code false} otherwise.
+     */
+    public boolean canRecord() {
+        return mCanRecord;
+    }
+
+    /**
      * Returns the HDMI device information of this TV input.
      * @hide
      */
@@ -481,9 +424,9 @@
      *         a label, its name is returned.
      */
     public CharSequence loadLabel(@NonNull Context context) {
-        if (mLabelRes != 0) {
-            return context.getPackageManager().getText(mService.serviceInfo.packageName, mLabelRes,
-                    null);
+        if (mLabelResId != 0) {
+            return context.getPackageManager().getText(mService.serviceInfo.packageName,
+                    mLabelResId, null);
         } else if (!TextUtils.isEmpty(mLabel)) {
             return mLabel;
         }
@@ -572,11 +515,13 @@
         dest.writeString(mSetupActivity);
         dest.writeString(mSettingsActivity);
         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);
         dest.writeParcelable(mIconUri, flags);
-        dest.writeInt(mLabelRes);
+        dest.writeInt(mLabelResId);
         dest.writeString(mLabel);
         dest.writeByte(mIsConnectedToHdmiSwitch ? (byte) 1 : 0);
     }
@@ -589,46 +534,6 @@
         return mService.serviceInfo.loadIcon(context.getPackageManager());
     }
 
-    /**
-     * Used to generate an input id from a ComponentName.
-     *
-     * @param name the component name for generating an input id.
-     * @return the generated input id for the given {@code name}.
-     */
-    private static String generateInputIdForComponentName(ComponentName name) {
-        return name.flattenToShortString();
-    }
-
-    /**
-     * Used to generate an input id from a ComponentName and HdmiDeviceInfo.
-     *
-     * @param name the component name for generating an input id.
-     * @param deviceInfo HdmiDeviceInfo describing this TV input.
-     * @return the generated input id for the given {@code name} and {@code deviceInfo}.
-     */
-    private static String generateInputIdForHdmiDevice(
-            ComponentName name, HdmiDeviceInfo deviceInfo) {
-        // Example of the format : "/HDMI%04X%02X"
-        String format = DELIMITER_INFO_IN_ID + PREFIX_HDMI_DEVICE
-                + "%0" + LENGTH_HDMI_PHYSICAL_ADDRESS + "X"
-                + "%0" + LENGTH_HDMI_DEVICE_ID + "X";
-        return name.flattenToShortString() + String.format(Locale.ENGLISH, format,
-                deviceInfo.getPhysicalAddress(), deviceInfo.getId());
-    }
-
-    /**
-     * Used to generate an input id from a ComponentName and TvInputHardwareInfo
-     *
-     * @param name the component name for generating an input id.
-     * @param hardwareInfo TvInputHardwareInfo describing this TV input.
-     * @return the generated input id for the given {@code name} and {@code hardwareInfo}.
-     */
-    private static String generateInputIdForHardware(
-            ComponentName name, TvInputHardwareInfo hardwareInfo) {
-        return name.flattenToShortString() + DELIMITER_INFO_IN_ID + PREFIX_HARDWARE_DEVICE
-                + hardwareInfo.getDeviceId();
-    }
-
     public static final Parcelable.Creator<TvInputInfo> CREATOR =
             new Parcelable.Creator<TvInputInfo>() {
         @Override
@@ -649,16 +554,291 @@
         mSetupActivity = in.readString();
         mSettingsActivity = in.readString();
         mType = in.readInt();
+        mTunerCount = in.readInt();
+        mCanRecord = in.readByte() == 1;
         mIsHardwareInput = in.readByte() == 1;
         mHdmiDeviceInfo = in.readParcelable(null);
         mIcon = in.readParcelable(null);
         mIconUri = in.readParcelable(null);
-        mLabelRes = in.readInt();
+        mLabelResId = in.readInt();
         mLabel = in.readString();
         mIsConnectedToHdmiSwitch = in.readByte() == 1;
     }
 
     /**
+     * A convenience builder for creating {@link TvInputInfo} objects.
+     */
+    public static final class Builder {
+        private static final int LENGTH_HDMI_PHYSICAL_ADDRESS = 4;
+        private static final int LENGTH_HDMI_DEVICE_ID = 2;
+
+        private static final String XML_START_TAG_NAME = "tv-input";
+        private static final String DELIMITER_INFO_IN_ID = "/";
+        private static final String PREFIX_HDMI_DEVICE = "HDMI";
+        private static final String PREFIX_HARDWARE_DEVICE = "HW";
+
+        private static final SparseIntArray sHardwareTypeToTvInputType = new SparseIntArray();
+        static {
+            sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_OTHER_HARDWARE,
+                    TYPE_OTHER);
+            sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_TUNER, TYPE_TUNER);
+            sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_COMPOSITE,
+                    TYPE_COMPOSITE);
+            sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_SVIDEO, TYPE_SVIDEO);
+            sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_SCART, TYPE_SCART);
+            sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_COMPONENT,
+                    TYPE_COMPONENT);
+            sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_VGA, TYPE_VGA);
+            sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_DVI, TYPE_DVI);
+            sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_HDMI, TYPE_HDMI);
+            sHardwareTypeToTvInputType.put(TvInputHardwareInfo.TV_INPUT_TYPE_DISPLAY_PORT,
+                    TYPE_DISPLAY_PORT);
+        }
+
+        private final Context mContext;
+        private final ResolveInfo mResolveInfo;
+        private Icon mIcon;
+        private int mLabelResId;
+        private int mTunerCount = 1;
+        private boolean mCanRecord;
+        private HdmiDeviceInfo mHdmiDeviceInfo;
+        private String mParentId;
+        private TvInputHardwareInfo mTvInputHardwareInfo;
+
+        /**
+         * 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}.
+         */
+        public Builder(Context context, Class<?> cls) {
+            mContext = context;
+            Intent intent = new Intent(TvInputService.SERVICE_INTERFACE).setClass(context, cls);
+            mResolveInfo = context.getPackageManager().resolveService(intent,
+                    PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
+        }
+
+        /**
+         * Constructs a new builder for {@link TvInputInfo}.
+         *
+         * @param resolveInfo The ResolveInfo returned from the package manager about this TV input
+         *            service.
+         * @hide
+         */
+        public Builder(Context context, ResolveInfo resolveInfo) {
+            if (context == null) {
+                throw new IllegalArgumentException("context cannot be null");
+            }
+            if (resolveInfo == null) {
+                throw new IllegalArgumentException("resolveInfo cannot be null");
+            }
+            mContext = context;
+            mResolveInfo = resolveInfo;
+        }
+
+        /**
+         * Sets the icon.
+         *
+         * @param icon The icon that represents this TV input.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @hide
+         */
+        @SystemApi
+        public Builder setIcon(Icon icon) {
+            this.mIcon = icon;
+            return this;
+        }
+
+        /**
+         * Sets the label.
+         *
+         * @param resId The resource ID of the text to use.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @hide
+         */
+        @SystemApi
+        public Builder setLabel(int resId) {
+            this.mLabelResId = resId;
+            return this;
+        }
+
+        /**
+         * Sets the HdmiDeviceInfo.
+         *
+         * @param hdmiDeviceInfo The HdmiDeviceInfo for a HDMI CEC logical device.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @hide
+         */
+        @SystemApi
+        public Builder setHdmiDeviceInfo(HdmiDeviceInfo hdmiDeviceInfo) {
+            if (mTvInputHardwareInfo != null) {
+                Log.w(TAG, "TvInputHardwareInfo will not be used to build this TvInputInfo");
+                mTvInputHardwareInfo = null;
+            }
+            this.mHdmiDeviceInfo = hdmiDeviceInfo;
+            return this;
+        }
+
+        /**
+         * Sets the parent ID.
+         *
+         * @param parentId The parent ID.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @hide
+         */
+        @SystemApi
+        public Builder setParentId(String parentId) {
+            this.mParentId = parentId;
+            return this;
+        }
+
+        /**
+         * Sets the TvInputHardwareInfo.
+         *
+         * @param tvInputHardwareInfo
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @hide
+         */
+        @SystemApi
+        public Builder setTvInputHardwareInfo(TvInputHardwareInfo tvInputHardwareInfo) {
+            if (mHdmiDeviceInfo != null) {
+                Log.w(TAG, "mHdmiDeviceInfo will not be used to build this TvInputInfo");
+                mHdmiDeviceInfo = null;
+            }
+            this.mTvInputHardwareInfo = tvInputHardwareInfo;
+            return this;
+        }
+
+        /**
+         * Sets the tuner count. Valid only for {@link #TYPE_TUNER}.
+         *
+         * @param tunerCount The number of tuners this TV input has.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setTunerCount(int tunerCount) {
+            this.mTunerCount = tunerCount;
+            return this;
+        }
+
+        /**
+         * Sets whether this TV input can record TV programs or not.
+         *
+         * @param canRecord Whether this TV input can record TV programs.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setCanRecord(boolean canRecord) {
+            this.mCanRecord = canRecord;
+            return this;
+        }
+
+        /**
+         * Creates a {@link TvInputInfo} instance with the specified fields. Most of the information
+         * is obtained by parsing the AndroidManifest and {@link TvInputService#SERVICE_META_DATA}
+         * for the {@link TvInputService} this TV input implements.
+         *
+         * @return TvInputInfo containing information about this TV input.
+         * @throws IOException If there was an I/O error.
+         * @throws XmlPullParserException If there was an XML parsing error.
+         */
+        public TvInputInfo build() throws IOException, XmlPullParserException {
+            ComponentName componentName = new ComponentName(mResolveInfo.serviceInfo.packageName,
+                    mResolveInfo.serviceInfo.name);
+            String id;
+            int type;
+            boolean isHardwareInput = false;
+            boolean isConnectedToHdmiSwitch = false;
+
+            if (mHdmiDeviceInfo != null) {
+                id = generateInputId(componentName, mHdmiDeviceInfo);
+                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);
+            return parseServiceMetadata(type, info);
+        }
+
+        private static String generateInputId(ComponentName name) {
+            return name.flattenToShortString();
+        }
+
+        private static String generateInputId(ComponentName name, HdmiDeviceInfo hdmiDeviceInfo) {
+            // Example of the format : "/HDMI%04X%02X"
+            String format = DELIMITER_INFO_IN_ID + PREFIX_HDMI_DEVICE
+                    + "%0" + LENGTH_HDMI_PHYSICAL_ADDRESS + "X"
+                    + "%0" + LENGTH_HDMI_DEVICE_ID + "X";
+            return name.flattenToShortString() + String.format(Locale.ENGLISH, format,
+                    hdmiDeviceInfo.getPhysicalAddress(), hdmiDeviceInfo.getId());
+        }
+
+        private static String generateInputId(ComponentName name,
+                TvInputHardwareInfo tvInputHardwareInfo) {
+            return name.flattenToShortString() + DELIMITER_INFO_IN_ID + PREFIX_HARDWARE_DEVICE
+                    + tvInputHardwareInfo.getDeviceId();
+        }
+
+        private TvInputInfo parseServiceMetadata(int inputType, TvInputInfo info)
+                throws XmlPullParserException, IOException {
+            ServiceInfo si = mResolveInfo.serviceInfo;
+            PackageManager pm = mContext.getPackageManager();
+            try (XmlResourceParser parser =
+                         si.loadXmlMetaData(pm, TvInputService.SERVICE_META_DATA)) {
+                if (parser == null) {
+                    throw new XmlPullParserException("No " + TvInputService.SERVICE_META_DATA
+                            + " meta-data for " + si.name);
+                }
+
+                Resources res = pm.getResourcesForApplication(si.applicationInfo);
+                AttributeSet attrs = Xml.asAttributeSet(parser);
+
+                int type;
+                while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                        && type != XmlPullParser.START_TAG) {
+                }
+
+                String nodeName = parser.getName();
+                if (!XML_START_TAG_NAME.equals(nodeName)) {
+                    throw new XmlPullParserException(
+                            "Meta-data does not start with tv-input-service tag in " + si.name);
+                }
+
+                TypedArray sa = res.obtainAttributes(attrs,
+                        com.android.internal.R.styleable.TvInputService);
+                info.mSetupActivity = sa.getString(
+                        com.android.internal.R.styleable.TvInputService_setupActivity);
+                if (DEBUG) {
+                    Log.d(TAG, "Setup activity loaded. [" + info.mSetupActivity + "] for "
+                            + si.name);
+                }
+                if (inputType == TYPE_TUNER && TextUtils.isEmpty(info.mSetupActivity)) {
+                    throw new XmlPullParserException("Setup activity not found in " + si.name);
+                }
+                info.mSettingsActivity = sa.getString(
+                        com.android.internal.R.styleable.TvInputService_settingsActivity);
+                if (DEBUG) {
+                    Log.d(TAG, "Settings activity loaded. [" + info.mSettingsActivity + "] for "
+                            + si.name);
+                }
+                sa.recycle();
+            } catch (NameNotFoundException e) {
+                throw new XmlPullParserException("Unable to create context for: " + si.packageName);
+            }
+            return info;
+        }
+    }
+
+    /**
      * Utility class for putting and getting settings for TV input.
      *
      * @hide
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index e9c94c0..86bded9 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -16,6 +16,7 @@
 
 package android.media.tv;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -44,6 +45,8 @@
 
 import com.android.internal.util.Preconditions;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.LinkedList;
@@ -126,12 +129,40 @@
     public static final long TIME_SHIFT_INVALID_TIME = Long.MIN_VALUE;
 
     /**
+     * RecordingError when a requested operation cannot be completed due to a problem that does not
+     * fit under any other error code.
+     */
+    public static final int RECORDING_ERROR_UNKNOWN = 0;
+
+    /**
+     * RecordingError when an attempt to connect to a recording session has failed or the
+     * established connection has been disconnected without a known reason.
+     */
+    public static final int RECORDING_ERROR_CONNECTION_FAILED = 1;
+
+    /**
+     * RecordingError when recording cannot proceed due to insufficient storage space.
+     */
+    public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 2;
+
+    /**
+     * RecordingError when recording cannot proceed because the required recording resource is not
+     * able to be allocated.
+     */
+    public static final int RECORDING_ERROR_RESOURCE_BUSY = 3;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({RECORDING_ERROR_UNKNOWN, RECORDING_ERROR_CONNECTION_FAILED,
+            RECORDING_ERROR_INSUFFICIENT_SPACE, RECORDING_ERROR_RESOURCE_BUSY})
+    public @interface RecordingError {}
+
+    /**
      * The TV input is connected.
      *
      * <p>This state indicates that a source device is connected to the input port and is in the
-     * normal operation mode. It is mostly relevant to hardware inputs such as HDMI input. This is
-     * the default state for any hardware inputs where their states are unknown. Non-hardware inputs
-     * are considered connected all the time.
+     * normal operation mode. It is mostly relevant to hardware inputs such as HDMI input.
+     * Non-hardware inputs are considered connected all the time.
      *
      * @see #getInputState
      * @see TvInputManager.TvInputCallback#onInputStateChanged
@@ -141,7 +172,8 @@
      * The TV input is connected but in standby mode.
      *
      * <p>This state indicates that a source device is connected to the input port but is in standby
-     * mode. It is mostly relevant to hardware inputs such as HDMI input.
+     * or low power mode. It is mostly relevant to hardware inputs such as HDMI inputs and Component
+     * inputs.
      *
      * @see #getInputState
      * @see TvInputManager.TvInputCallback#onInputStateChanged
@@ -416,6 +448,39 @@
          */
         public void onTimeShiftCurrentPositionChanged(Session session, long timeMs) {
         }
+
+        /**
+         * This is called when a recording session initiated by a call to {@link
+         * TvRecordingClient#connect(String, Uri)} has been established.
+         */
+        void onConnected(Session session) {
+        }
+
+        /**
+         * This is called when TV program recording on the current channel has started.
+         *
+         * @param session A {@link TvInputManager.Session} associated with this callback.
+         */
+        void onRecordingStarted(Session session) {
+        }
+
+        /**
+         * This is called when TV program recording on the current channel has stopped. The passed
+         * URI contains information about the new recorded program.
+         *
+         * @param recordedProgramUri The URI for the new recorded program.
+         * @see android.media.tv.TvContract.RecordedPrograms
+         **/
+        void onRecordingStopped(Session session, Uri recordedProgramUri) {
+        }
+
+        /**
+         * This is called when an issue has occurred before or during recording.
+         *
+         * @param error The error code.
+         */
+        void onError(Session session, @TvInputManager.RecordingError int error) {
+        }
     }
 
     private static final class SessionCallbackRecord {
@@ -565,6 +630,46 @@
                 }
             });
         }
+
+        // For the recording session only
+        void postConnected() {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mSessionCallback.onConnected(mSession);
+                }
+            });
+        }
+
+        // For the recording session only
+        void postRecordingStarted() {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mSessionCallback.onRecordingStarted(mSession);
+                }
+            });
+        }
+
+        // For the recording session only
+        void postRecordingStopped(final Uri recordedProgramUri) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mSessionCallback.onRecordingStopped(mSession, recordedProgramUri);
+                }
+            });
+        }
+
+        // For the recording session only
+        void postError(final int error) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mSessionCallback.onError(mSession, error);
+                }
+            });
+        }
     }
 
     /**
@@ -574,7 +679,7 @@
         /**
          * This is called when the state of a given TV input is changed.
          *
-         * @param inputId The id of the TV input.
+         * @param inputId The ID of the TV input.
          * @param state State of the TV input. The value is one of the following:
          * <ul>
          * <li>{@link TvInputManager#INPUT_STATE_CONNECTED}
@@ -591,7 +696,7 @@
          * <p>Normally it happens when the user installs a new TV input package that implements
          * {@link TvInputService} interface.
          *
-         * @param inputId The id of the TV input.
+         * @param inputId The ID of the TV input.
          */
         public void onInputAdded(String inputId) {
         }
@@ -602,7 +707,7 @@
          * <p>Normally it happens when the user uninstalls the previously installed TV input
          * package.
          *
-         * @param inputId The id of the TV input.
+         * @param inputId The ID of the TV input.
          */
         public void onInputRemoved(String inputId) {
         }
@@ -613,12 +718,20 @@
          * <p>Normally it happens when a previously installed TV input package is re-installed or
          * the media on which a newer version of the package exists becomes available/unavailable.
          *
-         * @param inputId The id of the TV input.
+         * @param inputId The ID of the TV input.
          * @hide
          */
         @SystemApi
         public void onInputUpdated(String inputId) {
         }
+
+        /**
+         * This is called when the information about a given TV input has been changed.
+         *
+         * @param inputInfo TvInputInfo object that contains the information about the TV input.
+         */
+        public void onTvInputInfoChanged(TvInputInfo inputInfo) {
+        }
     }
 
     private static final class TvInputCallbackRecord {
@@ -634,15 +747,6 @@
             return mCallback;
         }
 
-        public void postInputStateChanged(final String inputId, final int state) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    mCallback.onInputStateChanged(inputId, state);
-                }
-            });
-        }
-
         public void postInputAdded(final String inputId) {
             mHandler.post(new Runnable() {
                 @Override
@@ -669,6 +773,24 @@
                 }
             });
         }
+
+        public void postInputStateChanged(final String inputId, final int state) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mCallback.onInputStateChanged(inputId, state);
+                }
+            });
+        }
+
+        public void postTvInputInfoChanged(final TvInputInfo inputInfo) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mCallback.onTvInputInfoChanged(inputInfo);
+                }
+            });
+        }
     }
 
     /**
@@ -876,19 +998,57 @@
                     record.postTimeShiftCurrentPositionChanged(timeMs);
                 }
             }
-        };
-        ITvInputManagerCallback managerCallback = new ITvInputManagerCallback.Stub() {
+
             @Override
-            public void onInputStateChanged(String inputId, int state) {
-                synchronized (mLock) {
-                    mStateMap.put(inputId, state);
-                    for (TvInputCallbackRecord record : mCallbackRecords) {
-                        record.postInputStateChanged(inputId, state);
+            public void onConnected(int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq " + seq);
+                        return;
                     }
+                    record.postConnected();
                 }
             }
 
             @Override
+            public void onRecordingStarted(int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq " + seq);
+                        return;
+                    }
+                    record.postRecordingStarted();
+                }
+            }
+
+            @Override
+            public void onRecordingStopped(Uri recordedProgramUri, int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq " + seq);
+                        return;
+                    }
+                    record.postRecordingStopped(recordedProgramUri);
+                }
+            }
+
+            @Override
+            public void onError(int error, int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq " + seq);
+                        return;
+                    }
+                    record.postError(error);
+                }
+            }
+        };
+        ITvInputManagerCallback managerCallback = new ITvInputManagerCallback.Stub() {
+            @Override
             public void onInputAdded(String inputId) {
                 synchronized (mLock) {
                     mStateMap.put(inputId, INPUT_STATE_CONNECTED);
@@ -916,6 +1076,25 @@
                     }
                 }
             }
+
+            @Override
+            public void onInputStateChanged(String inputId, int state) {
+                synchronized (mLock) {
+                    mStateMap.put(inputId, state);
+                    for (TvInputCallbackRecord record : mCallbackRecords) {
+                        record.postInputStateChanged(inputId, state);
+                    }
+                }
+            }
+
+            @Override
+            public void onTvInputInfoChanged(TvInputInfo inputInfo) {
+                synchronized (mLock) {
+                    for (TvInputCallbackRecord record : mCallbackRecords) {
+                        record.postTvInputInfoChanged(inputInfo);
+                    }
+                }
+            }
         };
         try {
             if (mService != null) {
@@ -963,6 +1142,23 @@
     }
 
     /**
+     * Sets a new TvInputInfo object for a given input.
+     *
+     * <p>This is called internally only by {@link TvInputService}.
+     *
+     * @param inputInfo The TvInputInfo object to set.
+     * @throws IllegalArgumentException if the argument is {@code null}.
+     */
+    void setTvInputInfo(@NonNull TvInputInfo inputInfo) {
+        Preconditions.checkNotNull(inputInfo);
+        try {
+            mService.setTvInputInfo(inputInfo, mUserId);
+        } catch (RemoteException e) {
+            throw new RuntimeException("Error trying to set " + inputInfo, e);
+        }
+    }
+
+    /**
      * Returns the state of a given TV input.
      *
      * <p>The state is one of the following:
@@ -972,7 +1168,7 @@
      * <li>{@link #INPUT_STATE_DISCONNECTED}
      * </ul>
      *
-     * @param inputId The id of the TV input.
+     * @param inputId The ID of the TV input.
      * @throws IllegalArgumentException if the argument is {@code null}.
      */
     public int getInputState(@NonNull String inputId) {
@@ -1139,7 +1335,7 @@
      * <p>The number of sessions that can be created at the same time is limited by the capability
      * of the given TV input.
      *
-     * @param inputId The id of the TV input.
+     * @param inputId The ID of the TV input.
      * @param callback A callback used to receive the created session.
      * @param handler A {@link Handler} that the session creation will be delivered to.
      * @hide
@@ -1147,6 +1343,28 @@
     @SystemApi
     public void createSession(@NonNull String inputId, @NonNull final SessionCallback callback,
             @NonNull Handler handler) {
+        createSessionInternal(inputId, false, callback, handler);
+    }
+
+    /**
+     * Creates a recording {@link Session} for a given TV input.
+     *
+     * <p>The number of sessions that can be created at the same time is limited by the capability
+     * of the given TV input.
+     *
+     * @param inputId The ID of the TV input.
+     * @param callback A callback used to receive the created session.
+     * @param handler A {@link Handler} that the session creation will be delivered to.
+     * @hide
+     */
+    @SystemApi
+    public void createRecordingSession(@NonNull String inputId,
+            @NonNull final SessionCallback callback, @NonNull Handler handler) {
+        createSessionInternal(inputId, true, callback, handler);
+    }
+
+    private void createSessionInternal(String inputId, boolean isRecordingSession,
+            SessionCallback callback, Handler handler) {
         Preconditions.checkNotNull(inputId);
         Preconditions.checkNotNull(callback);
         Preconditions.checkNotNull(handler);
@@ -1155,7 +1373,7 @@
             int seq = mNextSeq++;
             mSessionCallbackRecordMap.put(seq, record);
             try {
-                mService.createSession(mClient, inputId, seq, mUserId);
+                mService.createSession(mClient, inputId, isRecordingSession, seq, mUserId);
             } catch (RemoteException e) {
                 throw new RuntimeException(e);
             }
@@ -1171,7 +1389,7 @@
      * here. This method is designed to be used with {@link #captureFrame} in
      * capture scenarios specifically and not suitable for any other use.
      *
-     * @param inputId the id of the TV input.
+     * @param inputId The ID of the TV input.
      * @return List of {@link TvStreamConfig} which is available for capturing
      *   of the given TV input.
      * @hide
@@ -1188,7 +1406,7 @@
     /**
      * Take a snapshot of the given TV input into the provided Surface.
      *
-     * @param inputId the id of the TV input.
+     * @param inputId The ID of the TV input.
      * @param surface the {@link Surface} to which the snapshot is captured.
      * @param config the {@link TvStreamConfig} which is used for capturing.
      * @return true when the {@link Surface} is ready to be captured.
@@ -1607,7 +1825,7 @@
          * Returns the selected track for a given type. Returns {@code null} if the information is
          * not available or any of the tracks for the given type is not selected.
          *
-         * @return the ID of the selected track.
+         * @return The ID of the selected track.
          * @see #selectTrack
          */
         @Nullable
@@ -1697,6 +1915,21 @@
         }
 
         /**
+         * Plays a given recorded TV program.
+         */
+        void timeShiftPlay(Uri recordedProgramUri) {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.timeShiftPlay(mToken, recordedProgramUri, mUserId);
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        /**
          * Pauses the playback. Call {@link #timeShiftResume()} to restart the playback.
          */
         void timeShiftPause() {
@@ -1782,6 +2015,62 @@
         }
 
         /**
+         * Connects to a given channel for TV program recording.
+         */
+        void connect(Uri channelUri) {
+            connect(channelUri, null);
+        }
+
+        /**
+         * Tunes to a given channel.
+         *
+         * @param channelUri The URI of a channel.
+         * @param params Extra parameters.
+         */
+        void connect(@NonNull Uri channelUri, Bundle params) {
+            Preconditions.checkNotNull(channelUri);
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.connect(mToken, channelUri, params, mUserId);
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        /**
+         * Starts TV program recording for the current recording session.
+         */
+        void startRecording() {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.startRecording(mToken, mUserId);
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        /**
+         * Stops TV program recording for the current recording session.
+         */
+        void stopRecording() {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.stopRecording(mToken, mUserId);
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        /**
          * Calls {@link TvInputService.Session#appPrivateCommand(String, Bundle)
          * TvInputService.Session.appPrivateCommand()} on the current TvView.
          *
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 053d43b6..a2b6346 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -16,6 +16,7 @@
 
 package android.media.tv;
 
+import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
@@ -136,6 +137,18 @@
             }
 
             @Override
+            public void createRecordingSession(ITvInputSessionCallback cb, String inputId) {
+                if (cb == null) {
+                    return;
+                }
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = cb;
+                args.arg2 = inputId;
+                mServiceHandler.obtainMessage(ServiceHandler.DO_CREATE_RECORDING_SESSION, args)
+                        .sendToTarget();
+            }
+
+            @Override
             public void notifyHardwareAdded(TvInputHardwareInfo hardwareInfo) {
                 mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HARDWARE_TV_INPUT,
                         hardwareInfo).sendToTarget();
@@ -174,6 +187,19 @@
     public abstract Session onCreateSession(String inputId);
 
     /**
+     * Returns a concrete implementation of {@link RecordingSession}.
+     *
+     * <p>May return {@code null} if this TV input service fails to create a recording session for
+     * some reason.
+     *
+     * @param inputId The ID of the TV input associated with the recording session.
+     */
+    @Nullable
+    public RecordingSession onCreateRecordingSession(String inputId) {
+        return null;
+    }
+
+    /**
      * Returns a new {@link TvInputInfo} object if this service is responsible for
      * {@code hardwareInfo}; otherwise, return {@code null}. Override to modify default behavior of
      * ignoring all hardware input.
@@ -229,6 +255,25 @@
         return null;
     }
 
+
+    /**
+     * Sets the TvInputInfo for this TV input.
+     *
+     * <p>The system service automatically creates the TvInputInfo for each TV input based on
+     * information collected from the AndroidManifest.xml, thus it is not necessary to call this
+     * method unless the TV input has additional information to pass such as ability to record and
+     * tuner count. Attempting to change information about a TV input that the calling package does
+     * not own does nothing.
+     *
+     * @param context The application context.
+     * @param inputInfo The TvInputInfo object that contains that new information.
+     */
+    public static final void setTvInputInfo(Context context, TvInputInfo inputInfo) {
+        TvInputManager manager = (TvInputManager) context.getSystemService(
+                Context.TV_INPUT_SERVICE);
+        manager.setTvInputInfo(inputInfo);
+    }
+
     private boolean isPassthroughInput(String inputId) {
         if (mTvInputManager == null) {
             mTvInputManager = (TvInputManager) getSystemService(Context.TV_INPUT_SERVICE);
@@ -322,7 +367,7 @@
         @SystemApi
         public void notifySessionEvent(@NonNull final String eventType, final Bundle eventArgs) {
             Preconditions.checkNotNull(eventType);
-            executeOrPostRunnable(new Runnable() {
+            executeOrPostRunnableOnMainThread(new Runnable() {
                 @Override
                 public void run() {
                     try {
@@ -347,7 +392,8 @@
          * @param channelUri The URI of the new channel.
          */
         public void notifyChannelRetuned(final Uri channelUri) {
-            executeOrPostRunnable(new Runnable() {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
                 @Override
                 public void run() {
                     try {
@@ -387,7 +433,8 @@
 
             // TODO: Validate the track list.
             final List<TvTrackInfo> tracksCopy = new ArrayList<>(tracks);
-            executeOrPostRunnable(new Runnable() {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
                 @Override
                 public void run() {
                     try {
@@ -417,7 +464,8 @@
          * @see #onSelectTrack
          */
         public void notifyTrackSelected(final int type, final String trackId) {
-            executeOrPostRunnable(new Runnable() {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
                 @Override
                 public void run() {
                     try {
@@ -443,7 +491,8 @@
          * @see #notifyVideoUnavailable
          */
         public void notifyVideoAvailable() {
-            executeOrPostRunnable(new Runnable() {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
                 @Override
                 public void run() {
                     try {
@@ -478,7 +527,8 @@
                     || reason > TvInputManager.VIDEO_UNAVAILABLE_REASON_END) {
                 throw new IllegalArgumentException("Unknown reason: " + reason);
             }
-            executeOrPostRunnable(new Runnable() {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
                 @Override
                 public void run() {
                     try {
@@ -518,7 +568,8 @@
          * @see TvInputManager
          */
         public void notifyContentAllowed() {
-            executeOrPostRunnable(new Runnable() {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
                 @Override
                 public void run() {
                     try {
@@ -562,7 +613,8 @@
          */
         public void notifyContentBlocked(@NonNull final TvContentRating rating) {
             Preconditions.checkNotNull(rating);
-            executeOrPostRunnable(new Runnable() {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
                 @Override
                 public void run() {
                     try {
@@ -603,7 +655,8 @@
          * </ul>
          */
         public void notifyTimeShiftStatusChanged(final int status) {
-            executeOrPostRunnable(new Runnable() {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
                 @Override
                 public void run() {
                     try {
@@ -619,7 +672,8 @@
         }
 
         private void notifyTimeShiftStartPositionChanged(final long timeMs) {
-            executeOrPostRunnable(new Runnable() {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
                 @Override
                 public void run() {
                     try {
@@ -635,7 +689,8 @@
         }
 
         private void notifyTimeShiftCurrentPositionChanged(final long timeMs) {
-            executeOrPostRunnable(new Runnable() {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
                 @Override
                 public void run() {
                     try {
@@ -665,7 +720,8 @@
             if (left > right || top > bottom) {
                 throw new IllegalArgumentException("Invalid parameter");
             }
-            executeOrPostRunnable(new Runnable() {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
                 @Override
                 public void run() {
                     try {
@@ -858,13 +914,28 @@
         }
 
         /**
+         * Called when the application requests to play a given recorded TV program.
+         *
+         * @param recordedProgramUri The URI of a recorded TV program.
+         * @see #onTimeShiftResume()
+         * @see #onTimeShiftPause()
+         * @see #onTimeShiftSeekTo(long)
+         * @see #onTimeShiftSetPlaybackParams(PlaybackParams)
+         * @see #onTimeShiftGetStartPosition()
+         * @see #onTimeShiftGetCurrentPosition()
+         */
+        public void onTimeShiftPlay(Uri recordedProgramUri) {
+        }
+
+        /**
          * Called when the application requests to pause playback.
          *
-         * @see #onTimeShiftResume
-         * @see #onTimeShiftSeekTo
-         * @see #onTimeShiftSetPlaybackParams
-         * @see #onTimeShiftGetStartPosition
-         * @see #onTimeShiftGetCurrentPosition
+         * @see #onTimeShiftPlay(Uri)
+         * @see #onTimeShiftResume()
+         * @see #onTimeShiftSeekTo(long)
+         * @see #onTimeShiftSetPlaybackParams(PlaybackParams)
+         * @see #onTimeShiftGetStartPosition()
+         * @see #onTimeShiftGetCurrentPosition()
          */
         public void onTimeShiftPause() {
         }
@@ -872,11 +943,12 @@
         /**
          * Called when the application requests to resume playback.
          *
-         * @see #onTimeShiftPause
-         * @see #onTimeShiftSeekTo
-         * @see #onTimeShiftSetPlaybackParams
-         * @see #onTimeShiftGetStartPosition
-         * @see #onTimeShiftGetCurrentPosition
+         * @see #onTimeShiftPlay(Uri)
+         * @see #onTimeShiftPause()
+         * @see #onTimeShiftSeekTo(long)
+         * @see #onTimeShiftSetPlaybackParams(PlaybackParams)
+         * @see #onTimeShiftGetStartPosition()
+         * @see #onTimeShiftGetCurrentPosition()
          */
         public void onTimeShiftResume() {
         }
@@ -888,11 +960,12 @@
          * not in the range.
          *
          * @param timeMs The time position to seek to, in milliseconds since the epoch.
-         * @see #onTimeShiftResume
-         * @see #onTimeShiftPause
-         * @see #onTimeShiftSetPlaybackParams
-         * @see #onTimeShiftGetStartPosition
-         * @see #onTimeShiftGetCurrentPosition
+         * @see #onTimeShiftPlay(Uri)
+         * @see #onTimeShiftResume()
+         * @see #onTimeShiftPause()
+         * @see #onTimeShiftSetPlaybackParams(PlaybackParams)
+         * @see #onTimeShiftGetStartPosition()
+         * @see #onTimeShiftGetCurrentPosition()
          */
         public void onTimeShiftSeekTo(long timeMs) {
         }
@@ -905,11 +978,12 @@
          * parameters previously set.
          *
          * @param params The playback params.
-         * @see #onTimeShiftResume
-         * @see #onTimeShiftPause
-         * @see #onTimeShiftSeekTo
-         * @see #onTimeShiftGetStartPosition
-         * @see #onTimeShiftGetCurrentPosition
+         * @see #onTimeShiftPlay(Uri)
+         * @see #onTimeShiftResume()
+         * @see #onTimeShiftPause()
+         * @see #onTimeShiftSeekTo(long)
+         * @see #onTimeShiftGetStartPosition()
+         * @see #onTimeShiftGetCurrentPosition()
          */
         public void onTimeShiftSetPlaybackParams(PlaybackParams params) {
         }
@@ -925,11 +999,12 @@
          * seek to, thus failure to notifying its change immediately might result in bad experience
          * where the application allows the user to seek to an invalid time position.
          *
-         * @see #onTimeShiftResume
-         * @see #onTimeShiftPause
-         * @see #onTimeShiftSeekTo
-         * @see #onTimeShiftSetPlaybackParams
-         * @see #onTimeShiftGetCurrentPosition
+         * @see #onTimeShiftPlay(Uri)
+         * @see #onTimeShiftResume()
+         * @see #onTimeShiftPause()
+         * @see #onTimeShiftSeekTo(long)
+         * @see #onTimeShiftSetPlaybackParams(PlaybackParams)
+         * @see #onTimeShiftGetCurrentPosition()
          */
         public long onTimeShiftGetStartPosition() {
             return TvInputManager.TIME_SHIFT_INVALID_TIME;
@@ -944,11 +1019,12 @@
          * playback position reported by {@link #onTimeShiftGetStartPosition}. Failure to notifying
          * the correct current position might lead to bad user experience.
          *
-         * @see #onTimeShiftResume
-         * @see #onTimeShiftPause
-         * @see #onTimeShiftSeekTo
-         * @see #onTimeShiftSetPlaybackParams
-         * @see #onTimeShiftGetStartPosition
+         * @see #onTimeShiftPlay(Uri)
+         * @see #onTimeShiftResume()
+         * @see #onTimeShiftPause()
+         * @see #onTimeShiftSeekTo(long)
+         * @see #onTimeShiftSetPlaybackParams(PlaybackParams)
+         * @see #onTimeShiftGetStartPosition()
          */
         public long onTimeShiftGetCurrentPosition() {
             return TvInputManager.TIME_SHIFT_INVALID_TIME;
@@ -1263,6 +1339,14 @@
         }
 
         /**
+         * Calls {@link #onTimeShiftPlay(Uri)}.
+         */
+        void timeShiftPlay(Uri recordedProgramUri) {
+            mCurrentPositionMs = 0;
+            onTimeShiftPlay(recordedProgramUri);
+        }
+
+        /**
          * Calls {@link #onTimeShiftPause}.
          */
         void timeShiftPause() {
@@ -1385,7 +1469,7 @@
             }
         }
 
-        private void executeOrPostRunnable(Runnable action) {
+        private void executeOrPostRunnableOnMainThread(Runnable action) {
             synchronized(mLock) {
                 if (mSessionCallback == null) {
                     // The session is not initialized yet.
@@ -1449,6 +1533,267 @@
     }
 
     /**
+     * Base class for derived classes to implement to provide a TV input recording session.
+     */
+    public abstract static class RecordingSession {
+        final Handler mHandler;
+
+        private final Object mLock = new Object();
+        // @GuardedBy("mLock")
+        private ITvInputSessionCallback mSessionCallback;
+        // @GuardedBy("mLock")
+        private final List<Runnable> mPendingActions = new ArrayList<>();
+
+        /**
+         * Creates a new Recording Session for TV program recording.
+         *
+         * @param context The context of the application
+         */
+        public RecordingSession(Context context) {
+            mHandler = new Handler(context.getMainLooper());
+        }
+
+        /**
+         * Informs the application that recording session has been connected.
+         */
+        public void notifyConnected() {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) Log.d(TAG, "notifyConnected");
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onConnected();
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "error in notifyConnected", e);
+                    }
+                }
+            });
+        }
+
+        /**
+         * Informs the application that recording has started.
+         */
+        public void notifyRecordingStarted() {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) Log.d(TAG, "notifyRecordingStarted");
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onRecordingStarted();
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "error in notifyRecordingStarted", e);
+                    }
+                }
+            });
+        }
+
+        /**
+         * Informs the application that recording has stopped successfully. Each TV input service
+         * should create a new data entry in the recorded programs table upon completion of the
+         * recording and send its URI.
+         *
+         * @param recordedProgramUri The URI of the new recorded program.
+         */
+        public void notifyRecordingStopped(final Uri recordedProgramUri) {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) Log.d(TAG, "notifyRecordingStopped");
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onRecordingStopped(recordedProgramUri);
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "error in notifyRecordingStopped", e);
+                    }
+                }
+            });
+        }
+
+        /**
+         * Sends an error to the application at any moment.
+         *
+         * @param error The error code. Should be one of the followings.
+         * <ul>
+         * <li>{@link TvInputManager#RECORDING_ERROR_UNKNOWN}
+         * <li>{@link TvInputManager#RECORDING_ERROR_CONNECTION_FAILED}
+         * <li>{@link TvInputManager#RECORDING_ERROR_INSUFFICIENT_SPACE}
+         * <li>{@link TvInputManager#RECORDING_ERROR_RESOURCE_BUSY}
+         * </ul>
+         */
+        public void notifyError(@TvInputManager.RecordingError final int error) {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) Log.d(TAG, "notifyError");
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onError(error);
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "error in notifyError", e);
+                    }
+                }
+            });
+        }
+
+        /**
+         * Dispatches an event to the application using this recording session.
+         *
+         * @param eventType The type of the event.
+         * @param eventArgs Optional arguments of the event.
+         * @hide
+         */
+        @SystemApi
+        public void notifySessionEvent(@NonNull final String eventType, final Bundle eventArgs) {
+            Preconditions.checkNotNull(eventType);
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) Log.d(TAG, "notifySessionEvent(" + eventType + ")");
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onSessionEvent(eventType, eventArgs);
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "error in sending event (event=" + eventType + ")", e);
+                    }
+                }
+            });
+        }
+
+        /**
+         * Called when the recording session is connected.
+         *
+         * @param channelUri The URI of the channel.
+         */
+        public abstract void onConnect(Uri channelUri);
+
+        /**
+         * Called when the recording session is connected.
+         *
+         * @param channelUri The URI of the channel.
+         * @param params Extra parameters.
+         * @hide
+         */
+        @SystemApi
+        public void onConnect(Uri channelUri, Bundle params) {
+            onConnect(channelUri);
+        }
+
+        /**
+         * Called when the application requests to disconnect the current recording session.
+         */
+        public abstract void onDisconnect();
+
+        /**
+         * Called when the application requests to start recording. Recording must start
+         * immediately.
+         *
+         * <p>The session must call either {@link #notifyRecordingStarted()} or
+         * {@link #notifyError(int)}}.
+         */
+        public abstract void onStartRecording();
+
+        /**
+         * Called when the application requests to stop recording. Recording must stop immediately.
+         *
+         * <p>The session must call either {@link #notifyRecordingStopped(Uri)} or
+         * {@link #notifyError(int)}}.
+         */
+        public abstract void onStopRecording();
+
+        /**
+         * Processes a private command sent from the application to the TV input. This can be used
+         * to provide domain-specific features that are only known between certain TV inputs and
+         * their clients.
+         *
+         * @param action Name of the command to be performed. 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 Any data to include with the command.
+         * @hide
+         */
+        @SystemApi
+        public void onAppPrivateCommand(@NonNull String action, Bundle data) {
+        }
+
+        /**
+         * Calls {@link #onConnect(Uri, Bundle)}.
+         *
+         */
+        void connect(Uri channelUri, Bundle params) {
+            onConnect(channelUri, params);
+        }
+
+        /**
+         * Calls {@link #onDisconnect()}.
+         *
+         */
+        void disconnect() {
+            onDisconnect();
+        }
+
+        /**
+         * Calls {@link #onStartRecording()}.
+         *
+         */
+        void startRecording() {
+            onStartRecording();
+        }
+
+        /**
+         * Calls {@link #onStopRecording()}.
+         *
+         */
+        void stopRecording() {
+            onStopRecording();
+        }
+
+        /**
+         * Calls {@link #onAppPrivateCommand(String, Bundle)}.
+         */
+        void appPrivateCommand(String action, Bundle data) {
+            onAppPrivateCommand(action, data);
+        }
+
+        private void initialize(ITvInputSessionCallback callback) {
+            synchronized(mLock) {
+                mSessionCallback = callback;
+                for (Runnable runnable : mPendingActions) {
+                    runnable.run();
+                }
+                mPendingActions.clear();
+            }
+        }
+
+        private void executeOrPostRunnableOnMainThread(Runnable action) {
+            synchronized(mLock) {
+                if (mSessionCallback == null) {
+                    // The session is not initialized yet.
+                    mPendingActions.add(action);
+                } else {
+                    if (mHandler.getLooper().isCurrentThread()) {
+                        action.run();
+                    } else {
+                        // Posts the runnable if this is not called from the main thread
+                        mHandler.post(action);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
      * Base class for a TV input session which represents an external device connected to a
      * hardware TV input.
      *
@@ -1588,10 +1933,11 @@
     private final class ServiceHandler extends Handler {
         private static final int DO_CREATE_SESSION = 1;
         private static final int DO_NOTIFY_SESSION_CREATED = 2;
-        private static final int DO_ADD_HARDWARE_TV_INPUT = 3;
-        private static final int DO_REMOVE_HARDWARE_TV_INPUT = 4;
-        private static final int DO_ADD_HDMI_TV_INPUT = 5;
-        private static final int DO_REMOVE_HDMI_TV_INPUT = 6;
+        private static final int DO_CREATE_RECORDING_SESSION = 3;
+        private static final int DO_ADD_HARDWARE_TV_INPUT = 4;
+        private static final int DO_REMOVE_HARDWARE_TV_INPUT = 5;
+        private static final int DO_ADD_HDMI_TV_INPUT = 6;
+        private static final int DO_REMOVE_HDMI_TV_INPUT = 7;
 
         private void broadcastAddHardwareTvInput(int deviceId, TvInputInfo inputInfo) {
             int n = mCallbacks.beginBroadcast();
@@ -1704,6 +2050,31 @@
                     args.recycle();
                     return;
                 }
+                case DO_CREATE_RECORDING_SESSION: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    ITvInputSessionCallback cb = (ITvInputSessionCallback) args.arg1;
+                    String inputId = (String) args.arg2;
+                    args.recycle();
+                    RecordingSession recordingSessionImpl = onCreateRecordingSession(inputId);
+                    if (recordingSessionImpl == null) {
+                        try {
+                            // Failed to create a recording session.
+                            cb.onSessionCreated(null, null);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "error in onSessionCreated", e);
+                        }
+                        return;
+                    }
+                    ITvInputSession stub = new ITvInputSessionWrapper(TvInputService.this,
+                            recordingSessionImpl);
+                    try {
+                        cb.onSessionCreated(stub, null);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "error in onSessionCreated", e);
+                    }
+                    recordingSessionImpl.initialize(cb);
+                    return;
+                }
                 case DO_ADD_HARDWARE_TV_INPUT: {
                     TvInputHardwareInfo hardwareInfo = (TvInputHardwareInfo) msg.obj;
                     TvInputInfo inputInfo = onHardwareAdded(hardwareInfo);
diff --git a/media/java/android/media/tv/TvRecordingClient.java b/media/java/android/media/tv/TvRecordingClient.java
new file mode 100644
index 0000000..865e000
--- /dev/null
+++ b/media/java/android/media/tv/TvRecordingClient.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.tv;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+
+import java.util.ArrayDeque;
+import java.util.Queue;
+
+/**
+ * The public interface object used to interact with a specific TV input service for TV program
+ * recording.
+ */
+public class TvRecordingClient {
+    private static final String TAG = "TvRecordingClient";
+    private static final boolean DEBUG = false;
+
+    private final RecordingCallback mCallback;
+    private final Handler mHandler;
+
+    private final TvInputManager mTvInputManager;
+    private TvInputManager.Session mSession;
+    private MySessionCallback mSessionCallback;
+
+    private final Queue<Pair<String, Bundle>> mPendingAppPrivateCommands = new ArrayDeque<>();
+
+    /**
+     * Creates a new TvRecordingClient object.
+     *
+     * @param context The application context to create the TvRecordingClient with.
+     * @param tag A short name for debugging purposes.
+     * @param callback The callback to receive recording status changes.
+     * @param handler The handler to invoke the callback on.
+     */
+    public TvRecordingClient(Context context, String tag, @NonNull RecordingCallback callback,
+            Handler handler) {
+        mCallback = callback;
+        mHandler = handler == null ? new Handler(Looper.getMainLooper()) : handler;
+        mTvInputManager = (TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE);
+    }
+
+    /**
+     * Connects to a given input for TV program recording. This will create a new recording session
+     * from the TV input and establishes the connection between the application and the session.
+     *
+     * <p>The recording session will respond by calling
+     * {@link RecordingCallback#onConnected()} or {@link RecordingCallback#onError(int)}.
+     *
+     * @param inputId The ID of the TV input for the given channel.
+     * @param channelUri The URI of a channel.
+     */
+    public void connect(String inputId, Uri channelUri) {
+        connect(inputId, channelUri, null);
+    }
+
+    /**
+     * Connects to a given input for TV program recording. This will create a new recording session
+     * from the TV input and establishes the connection between the application and the session.
+     *
+     * <p>The recording session will respond by calling
+     * {@link RecordingCallback#onConnected()} or {@link RecordingCallback#onError(int)}.
+     *
+     * @param inputId The ID of the TV input for the given channel.
+     * @param channelUri The URI of a channel.
+     * @param params Extra parameters.
+     * @hide
+     */
+    @SystemApi
+    public void connect(String inputId, Uri channelUri, Bundle params) {
+        if (DEBUG) Log.d(TAG, "connect(" + channelUri + ")");
+        if (TextUtils.isEmpty(inputId)) {
+            throw new IllegalArgumentException("inputId cannot be null or an empty string");
+        }
+        if (mSessionCallback != null && TextUtils.equals(mSessionCallback.mInputId, inputId)) {
+            if (mSession != null) {
+                mSession.connect(channelUri, params);
+            } else {
+                mSessionCallback.mChannelUri = channelUri;
+                mSessionCallback.mConnectionParams = params;
+            }
+        } else {
+            resetInternal();
+            mSessionCallback = new MySessionCallback(inputId, channelUri, params);
+            if (mTvInputManager != null) {
+                mTvInputManager.createRecordingSession(inputId, mSessionCallback, mHandler);
+            }
+        }
+    }
+
+    /**
+     * Disconnects the established connection between the application and the recording session.
+     *
+     * <p>The recording session will respond by calling
+     * {@link RecordingCallback#onDisconnected()} or {@link RecordingCallback#onError(int)}.
+     */
+    public void disconnect() {
+        if (DEBUG) Log.d(TAG, "disconnect()");
+        resetInternal();
+    }
+
+    private void resetInternal() {
+        mSessionCallback = null;
+        mPendingAppPrivateCommands.clear();
+        if (mSession != null) {
+            mSession.release();
+            mSession = null;
+        }
+    }
+
+    /**
+     * Starts TV program recording for the current recording session. It is expected that recording
+     * starts immediately after calling this method.
+     *
+     * <p>The recording session will respond by calling
+     * {@link RecordingCallback#onRecordingStarted()} or {@link RecordingCallback#onError(int)}.
+     */
+    public void startRecording() {
+        if (mSession != null) {
+            mSession.startRecording();
+        }
+    }
+
+    /**
+     * Stops TV program recording for the current recording session. It is expected that recording
+     * stops immediately after calling this method.
+     *
+     * <p>The recording session will respond by calling
+     * {@link RecordingCallback#onRecordingStopped(Uri)} or {@link RecordingCallback#onError(int)}.
+     */
+    public void stopRecording() {
+        if (mSession != null) {
+            mSession.stopRecording();
+        }
+    }
+
+    /**
+     * Calls {@link TvInputService.RecordingSession#appPrivateCommand(String, Bundle)
+     * TvInputService.RecordingSession.appPrivateCommand()} on the current TvView.
+     *
+     * @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");
+        }
+        if (mSession != null) {
+            mSession.sendAppPrivateCommand(action, data);
+        } else {
+            Log.w(TAG, "sendAppPrivateCommand - session not yet created (action \"" + action
+                    + "\" pending)");
+            mPendingAppPrivateCommands.add(Pair.create(action, data));
+        }
+    }
+
+    /**
+     * Callback used to receive various status updates on the
+     * {@link android.media.tv.TvInputService.RecordingSession}
+     */
+    public class RecordingCallback {
+        /**
+         * This is called when a recording session initiated by a call to
+         * {@link #connect(String, Uri)} has been established.
+         */
+        public void onConnected() {
+        }
+
+        /**
+         * This is called when the established connection between the application and the recording
+         * session has been disconnected. Disconnection can be initiated either by an explicit
+         * request (i.e. a call to {@link #disconnect()} or by an error on the TV input service
+         * side.
+         */
+        public void onDisconnected() {
+        }
+
+        /**
+         * This is called when TV program recording on the current channel has started.
+         */
+        public void onRecordingStarted() {
+        }
+
+        /**
+         * This is called when TV program recording on the current channel has stopped. The passed
+         * URI contains information about the new recorded program.
+         *
+         * @param recordedProgramUri The URI for the new recorded program.
+         * @see android.media.tv.TvContract.RecordedPrograms
+         */
+        public void onRecordingStopped(Uri recordedProgramUri) {
+        }
+
+        /**
+         * This is called when an issue has occurred before or during recording. If the TV input
+         * service cannot proceed recording due to this error, a call to {@link #onDisconnected()}
+         * is expected to follow.
+         *
+         * @param error The error code. Should be one of the followings.
+         * <ul>
+         * <li>{@link TvInputManager#RECORDING_ERROR_UNKNOWN}
+         * <li>{@link TvInputManager#RECORDING_ERROR_CONNECTION_FAILED}
+         * <li>{@link TvInputManager#RECORDING_ERROR_INSUFFICIENT_SPACE}
+         * <li>{@link TvInputManager#RECORDING_ERROR_RESOURCE_BUSY}
+         * </ul>
+         */
+        public void onError(@TvInputManager.RecordingError int error) {
+        }
+
+        /**
+         * This is invoked when a custom event from the bound TV input is sent to this client.
+         *
+         * @param inputId The ID of the TV input bound to this client.
+         * @param eventType The type of the event.
+         * @param eventArgs Optional arguments of the event.
+         * @hide
+         */
+        @SystemApi
+        public void onEvent(String inputId, String eventType, Bundle eventArgs) {
+        }
+    }
+
+    private class MySessionCallback extends TvInputManager.SessionCallback {
+        final String mInputId;
+        Uri mChannelUri;
+        Bundle mConnectionParams;
+
+        MySessionCallback(String inputId, Uri channelUri, Bundle connectionParams) {
+            mInputId = inputId;
+            mChannelUri = channelUri;
+            mConnectionParams = connectionParams;
+        }
+
+        @Override
+        public void onSessionCreated(TvInputManager.Session session) {
+            if (DEBUG) {
+                Log.d(TAG, "onSessionCreated()");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onSessionCreated - session already created");
+                // This callback is obsolete.
+                if (session != null) {
+                    session.release();
+                }
+                return;
+            }
+            mSession = session;
+            if (session != null) {
+                // Sends the pending app private commands.
+                for (Pair<String, Bundle> command : mPendingAppPrivateCommands) {
+                    mSession.sendAppPrivateCommand(command.first, command.second);
+                }
+                mPendingAppPrivateCommands.clear();
+                mSession.connect(mChannelUri, mConnectionParams);
+            } else {
+                mSessionCallback = null;
+                mCallback.onError(TvInputManager.RECORDING_ERROR_CONNECTION_FAILED);
+            }
+        }
+
+        @Override
+        public void onSessionReleased(TvInputManager.Session session) {
+            if (DEBUG) {
+                Log.d(TAG, "onSessionReleased()");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onSessionReleased - session not created");
+                return;
+            }
+            mSessionCallback = null;
+            mSession = null;
+            mCallback.onDisconnected();
+        }
+
+        @Override
+        public void onRecordingStarted(TvInputManager.Session session) {
+            if (DEBUG) {
+                Log.d(TAG, "onRecordingStarted()");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onRecordingStarted - session not created");
+                return;
+            }
+            mCallback.onRecordingStarted();
+        }
+
+        @Override
+        public void onRecordingStopped(TvInputManager.Session session, Uri recordedProgramUri) {
+            if (DEBUG) {
+                Log.d(TAG, "onRecordingStopped()");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onRecordingStopped - session not created");
+                return;
+            }
+            mCallback.onRecordingStopped(recordedProgramUri);
+        }
+
+        @Override
+        public void onError(TvInputManager.Session session, int error) {
+            if (DEBUG) {
+                Log.d(TAG, "onError()");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onError - session not created");
+                return;
+            }
+            mCallback.onError(error);
+        }
+
+        @Override
+        public void onSessionEvent(TvInputManager.Session session, String eventType,
+                Bundle eventArgs) {
+            if (DEBUG) {
+                Log.d(TAG, "onSessionEvent(" + eventType + ")");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onSessionEvent - session not created");
+                return;
+            }
+            if (mCallback != null) {
+                mCallback.onEvent(mInputId, eventType, eventArgs);
+            }
+        }
+    }
+}
diff --git a/media/java/android/media/tv/TvStreamConfig.java b/media/java/android/media/tv/TvStreamConfig.java
index 0c2f3fe..eae83cf 100644
--- a/media/java/android/media/tv/TvStreamConfig.java
+++ b/media/java/android/media/tv/TvStreamConfig.java
@@ -28,8 +28,15 @@
 public class TvStreamConfig implements Parcelable {
     static final String TAG = TvStreamConfig.class.getSimpleName();
 
+    // Must be in sync with tv_input.h
     public final static int STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE = 1;
     public final static int STREAM_TYPE_BUFFER_PRODUCER = 2;
+    /**
+     * A flag indicating whether the HAL is sure about signal at this stream. Note that
+     * value of 0 here does not necessarily mean no signal. It just means that it may not have
+     * signal and the underlying layer is not sure.
+     */
+    public static final int FLAG_MASK_SIGNAL_DETECTION = 0x1;
 
     private int mStreamId;
     private int mType;
@@ -41,6 +48,10 @@
      * via tv_input_device::get_stream_configurations().
      */
     private int mGeneration;
+    /**
+     * Flags for stream status. See FLAG_MASK_* for details.
+     */
+    private int mFlags;
 
     public static final Parcelable.Creator<TvStreamConfig> CREATOR =
             new Parcelable.Creator<TvStreamConfig>() {
@@ -52,7 +63,8 @@
                         type(source.readInt()).
                         maxWidth(source.readInt()).
                         maxHeight(source.readInt()).
-                        generation(source.readInt()).build();
+                        generation(source.readInt()).
+                        flags(source.readInt()).build();
             } catch (Exception e) {
                 Log.e(TAG, "Exception creating TvStreamConfig from parcel", e);
                 return null;
@@ -87,6 +99,10 @@
         return mGeneration;
     }
 
+    public int getFlags() {
+        return mFlags;
+    }
+
     @Override
     public String toString() {
         return "TvStreamConfig {mStreamId=" + mStreamId + ";" + "mType=" + mType + ";mGeneration="
@@ -106,6 +122,7 @@
         dest.writeInt(mMaxWidth);
         dest.writeInt(mMaxHeight);
         dest.writeInt(mGeneration);
+        dest.writeInt(mFlags);
     }
 
     /**
@@ -117,6 +134,7 @@
         private Integer mMaxWidth;
         private Integer mMaxHeight;
         private Integer mGeneration;
+        private int mFlags = 0;
 
         public Builder() {
         }
@@ -146,6 +164,11 @@
             return this;
         }
 
+        public Builder flags(int flag) {
+            mFlags = flag;
+            return this;
+        }
+
         public TvStreamConfig build() {
             if (mStreamId == null || mType == null || mMaxWidth == null || mMaxHeight == null
                     || mGeneration == null) {
@@ -158,6 +181,7 @@
             config.mMaxWidth = mMaxWidth;
             config.mMaxHeight = mMaxHeight;
             config.mGeneration = mGeneration;
+            config.mFlags = mFlags;
             return config;
         }
     }
@@ -172,6 +196,7 @@
             && config.mStreamId == mStreamId
             && config.mType == mType
             && config.mMaxWidth == mMaxWidth
-            && config.mMaxHeight == mMaxHeight;
+            && config.mMaxHeight == mMaxHeight
+            && config.mFlags == mFlags;
     }
 }
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 003a274..0132d24 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -448,6 +448,37 @@
     }
 
     /**
+     * Plays a given recorded TV program.
+     *
+     * @param inputId The ID of the TV input that created the given recorded program.
+     * @param recordedProgramUri The URI of a recorded program.
+     */
+    public void timeShiftPlay(String inputId, Uri recordedProgramUri) {
+        if (DEBUG) Log.d(TAG, "timeShiftPlay(" + recordedProgramUri + ")");
+        if (TextUtils.isEmpty(inputId)) {
+            throw new IllegalArgumentException("inputId cannot be null or an empty string");
+        }
+        synchronized (sMainTvViewLock) {
+            if (sMainTvView.get() == null) {
+                sMainTvView = new WeakReference<>(this);
+            }
+        }
+        if (mSessionCallback != null && TextUtils.equals(mSessionCallback.mInputId, inputId)) {
+            if (mSession != null) {
+                mSession.timeShiftPlay(recordedProgramUri);
+            } else {
+                mSessionCallback.mRecordedProgramUri = recordedProgramUri;
+            }
+        } else {
+            resetInternal();
+            mSessionCallback = new MySessionCallback(inputId, recordedProgramUri);
+            if (mTvInputManager != null) {
+                mTvInputManager.createSession(inputId, mSessionCallback, mHandler);
+            }
+        }
+    }
+
+    /**
      * Pauses playback. No-op if it is already paused. Call {@link #timeShiftResume} to resume.
      */
     public void timeShiftPause() {
@@ -994,6 +1025,7 @@
         final String mInputId;
         Uri mChannelUri;
         Bundle mTuneParams;
+        Uri mRecordedProgramUri;
 
         MySessionCallback(String inputId, Uri channelUri, Bundle tuneParams) {
             mInputId = inputId;
@@ -1001,6 +1033,11 @@
             mTuneParams = tuneParams;
         }
 
+        MySessionCallback(String inputId, Uri recordedProgramUri) {
+            mInputId = inputId;
+            mRecordedProgramUri = recordedProgramUri;
+        }
+
         @Override
         public void onSessionCreated(Session session) {
             if (DEBUG) {
@@ -1043,7 +1080,11 @@
                 if (mCaptionEnabled != null) {
                     mSession.setCaptionEnabled(mCaptionEnabled);
                 }
-                mSession.tune(mChannelUri, mTuneParams);
+                if (mChannelUri != null) {
+                    mSession.tune(mChannelUri, mTuneParams);
+                } else {
+                    mSession.timeShiftPlay(mRecordedProgramUri);
+                }
                 ensurePositionTracking();
             } else {
                 mSessionCallback = null;
diff --git a/media/java/android/mtp/MtpConstants.java b/media/java/android/mtp/MtpConstants.java
index d245f588..0dcc718 100644
--- a/media/java/android/mtp/MtpConstants.java
+++ b/media/java/android/mtp/MtpConstants.java
@@ -182,6 +182,13 @@
     public static final int FORMAT_MPEG = 0x300B;
     /** Format code for ASF files */
     public static final int FORMAT_ASF = 0x300C;
+    /**
+     * Format code for unknown image files.
+     * <p>
+     * Will be used for the formats which are not specified in PTP specification.
+     * For instance, WEBP and WBMP.
+     */
+    public static final int FORMAT_DEFINED = 0x3800;
     /** Format code for JPEG image files */
     public static final int FORMAT_EXIF_JPEG = 0x3801;
     /** Format code for TIFF EP image files */
@@ -202,6 +209,8 @@
     public static final int FORMAT_JP2 = 0x380F;
     /** Format code for JPX files */
     public static final int FORMAT_JPX = 0x3810;
+    /** Format code for DNG files */
+    public static final int FORMAT_DNG = 0x3811;
     /** Format code for firmware files */
     public static final int FORMAT_UNDEFINED_FIRMWARE = 0xB802;
     /** Format code for Windows image files */
@@ -270,12 +279,12 @@
     public static final int FORMAT_MS_POWERPOINT_PRESENTATION = 0xBA86;
 
     /**
-      * Returns true if the object is abstract (that is, it has no representation
-      * in the underlying file system).
-      *
-      * @param format the format of the object
-      * @return true if the object is abstract
-      */
+     * Returns true if the object is abstract (that is, it has no representation
+     * in the underlying file system).
+     *
+     * @param format the format of the object
+     * @return true if the object is abstract
+     */
     public static boolean isAbstractObject(int format) {
         switch (format) {
             case FORMAT_ABSTRACT_MULTIMEDIA_ALBUM:
@@ -573,4 +582,114 @@
      * Association type for objects representing file system directories.
      */
     public static final int ASSOCIATION_TYPE_GENERIC_FOLDER = 0x0001;
+
+    /** Event code for UNDEFINED event */
+    public static final int EVENT_UNDEFINED = 0x4000;
+    /** Event code for CANCEL_TRANSACTION event */
+    public static final int EVENT_CANCEL_TRANSACTION = 0x4001;
+    /** Event code for OBJECT_ADDED event */
+    public static final int EVENT_OBJECT_ADDED = 0x4002;
+    /** Event code for OBJECT_REMOVED event */
+    public static final int EVENT_OBJECT_REMOVED = 0x4003;
+    /** Event code for STORE_ADDED event */
+    public static final int EVENT_STORE_ADDED = 0x4004;
+    /** Event code for STORE_REMOVED event */
+    public static final int EVENT_STORE_REMOVED = 0x4005;
+    /** Event code for DEVICE_PROP_CHANGED event */
+    public static final int EVENT_DEVICE_PROP_CHANGED = 0x4006;
+    /** Event code for OBJECT_INFO_CHANGED event */
+    public static final int EVENT_OBJECT_INFO_CHANGED = 0x4007;
+    /** Event code for DEVICE_INFO_CHANGED event */
+    public static final int EVENT_DEVICE_INFO_CHANGED = 0x4008;
+    /** Event code for REQUEST_OBJECT_TRANSFER event */
+    public static final int EVENT_REQUEST_OBJECT_TRANSFER = 0x4009;
+    /** Event code for STORE_FULL event */
+    public static final int EVENT_STORE_FULL = 0x400A;
+    /** Event code for DEVICE_RESET event */
+    public static final int EVENT_DEVICE_RESET = 0x400B;
+    /** Event code for STORAGE_INFO_CHANGED event */
+    public static final int EVENT_STORAGE_INFO_CHANGED = 0x400C;
+    /** Event code for CAPTURE_COMPLETE event */
+    public static final int EVENT_CAPTURE_COMPLETE = 0x400D;
+    /** Event code for UNREPORTED_STATUS event */
+    public static final int EVENT_UNREPORTED_STATUS = 0x400E;
+    /** Event code for OBJECT_PROP_CHANGED event */
+    public static final int EVENT_OBJECT_PROP_CHANGED = 0xC801;
+    /** Event code for OBJECT_PROP_DESC_CHANGED event */
+    public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 0xC802;
+    /** Event code for OBJECT_REFERENCES_CHANGED event */
+    public static final int EVENT_OBJECT_REFERENCES_CHANGED = 0xC803;
+
+    /** Operation code for GetDeviceInfo */
+    public static final int OPERATION_GET_DEVICE_INFO = 0x1001;
+    /** Operation code for OpenSession */
+    public static final int OPERATION_OPEN_SESSION = 0x1002;
+    /** Operation code for CloseSession */
+    public static final int OPERATION_CLOSE_SESSION = 0x1003;
+    /** Operation code for GetStorageIDs */
+    public static final int OPERATION_GET_STORAGE_I_DS = 0x1004;
+    /** Operation code for GetStorageInfo */
+    public static final int OPERATION_GET_STORAGE_INFO = 0x1005;
+    /** Operation code for GetNumObjects */
+    public static final int OPERATION_GET_NUM_OBJECTS = 0x1006;
+    /** Operation code for GetObjectHandles */
+    public static final int OPERATION_GET_OBJECT_HANDLES = 0x1007;
+    /** Operation code for GetObjectInfo */
+    public static final int OPERATION_GET_OBJECT_INFO = 0x1008;
+    /** Operation code for GetObject */
+    public static final int OPERATION_GET_OBJECT = 0x1009;
+    /** Operation code for GetThumb */
+    public static final int OPERATION_GET_THUMB = 0x100A;
+    /** Operation code for DeleteObject */
+    public static final int OPERATION_DELETE_OBJECT = 0x100B;
+    /** Operation code for SendObjectInfo */
+    public static final int OPERATION_SEND_OBJECT_INFO = 0x100C;
+    /** Operation code for SendObject */
+    public static final int OPERATION_SEND_OBJECT = 0x100D;
+    /** Operation code for InitiateCapture */
+    public static final int OPERATION_INITIATE_CAPTURE = 0x100E;
+    /** Operation code for FormatStore */
+    public static final int OPERATION_FORMAT_STORE = 0x100F;
+    /** Operation code for ResetDevice */
+    public static final int OPERATION_RESET_DEVICE = 0x1010;
+    /** Operation code for SelfTest */
+    public static final int OPERATION_SELF_TEST = 0x1011;
+    /** Operation code for SetObjectProtection */
+    public static final int OPERATION_SET_OBJECT_PROTECTION = 0x1012;
+    /** Operation code for PowerDown */
+    public static final int OPERATION_POWER_DOWN = 0x1013;
+    /** Operation code for GetDevicePropDesc */
+    public static final int OPERATION_GET_DEVICE_PROP_DESC = 0x1014;
+    /** Operation code for GetDevicePropValue */
+    public static final int OPERATION_GET_DEVICE_PROP_VALUE = 0x1015;
+    /** Operation code for SetDevicePropValue */
+    public static final int OPERATION_SET_DEVICE_PROP_VALUE = 0x1016;
+    /** Operation code for ResetDevicePropValue */
+    public static final int OPERATION_RESET_DEVICE_PROP_VALUE = 0x1017;
+    /** Operation code for TerminateOpenCapture */
+    public static final int OPERATION_TERMINATE_OPEN_CAPTURE = 0x1018;
+    /** Operation code for MoveObject */
+    public static final int OPERATION_MOVE_OBJECT = 0x1019;
+    /** Operation code for CopyObject */
+    public static final int OPERATION_COPY_OBJECT = 0x101A;
+    /** Operation code for GetPartialObject */
+    public static final int OPERATION_GET_PARTIAL_OBJECT = 0x101B;
+    /** Operation code for InitiateOpenCapture */
+    public static final int OPERATION_INITIATE_OPEN_CAPTURE = 0x101C;
+    /** Operation code for GetObjectPropsSupported */
+    public static final int OPERATION_GET_OBJECT_PROPS_SUPPORTED = 0x9801;
+    /** Operation code for GetObjectPropDesc */
+    public static final int OPERATION_GET_OBJECT_PROP_DESC = 0x9802;
+    /** Operation code for GetObjectPropValue */
+    public static final int OPERATION_GET_OBJECT_PROP_VALUE = 0x9803;
+    /** Operation code for SetObjectPropValue */
+    public static final int OPERATION_SET_OBJECT_PROP_VALUE = 0x9804;
+    /** Operation code for GetObjectReferences */
+    public static final int OPERATION_GET_OBJECT_REFERENCES = 0x9810;
+    /** Operation code for SetObjectReferences */
+    public static final int OPERATION_SET_OBJECT_REFERENCES = 0x9811;
+    /** Operation code for Skip */
+    public static final int OPERATION_SKIP = 0x9820;
+    /** Operation code for GetPartialObject64 */
+    public static final int OPERATION_GET_PARTIAL_OBJECT_64 = 0x95C1;
 }
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 3541fba..29bcc19 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -17,9 +17,9 @@
 package android.mtp;
 
 import android.content.BroadcastReceiver;
-import android.content.Context;
+import android.content.ContentProviderClient;
 import android.content.ContentValues;
-import android.content.IContentProvider;
+import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
@@ -37,23 +37,30 @@
 import android.view.Display;
 import android.view.WindowManager;
 
+import dalvik.system.CloseGuard;
+
 import java.io.File;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Locale;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * {@hide}
  */
-public class MtpDatabase {
-
+public class MtpDatabase implements AutoCloseable {
     private static final String TAG = "MtpDatabase";
 
     private final Context mContext;
     private final String mPackageName;
-    private final IContentProvider mMediaProvider;
+    private final ContentProviderClient mMediaProvider;
     private final String mVolumeName;
     private final Uri mObjectsUri;
+    private final MediaScanner mMediaScanner;
+
+    private final AtomicBoolean mClosed = new AtomicBoolean();
+    private final CloseGuard mCloseGuard = CloseGuard.get();
+
     // path to primary storage
     private final String mMediaStoragePath;
     // if not null, restrict all queries to these subdirectories
@@ -120,7 +127,6 @@
     private static final String STORAGE_FORMAT_PARENT_WHERE = STORAGE_FORMAT_WHERE + " AND "
                                             + Files.FileColumns.PARENT + "=?";
 
-    private final MediaScanner mMediaScanner;
     private MtpServer mServer;
 
     // read from native code
@@ -156,11 +162,12 @@
 
         mContext = context;
         mPackageName = context.getPackageName();
-        mMediaProvider = context.getContentResolver().acquireProvider("media");
+        mMediaProvider = context.getContentResolver()
+                .acquireContentProviderClient(MediaStore.AUTHORITY);
         mVolumeName = volumeName;
         mMediaStoragePath = storagePath;
         mObjectsUri = Files.getMtpObjectsUri(volumeName);
-        mMediaScanner = new MediaScanner(context);
+        mMediaScanner = new MediaScanner(context, mVolumeName);
 
         mSubDirectories = subDirectories;
         if (subDirectories != null) {
@@ -187,20 +194,9 @@
             }
         }
 
-        // Set locale to MediaScanner.
-        Locale locale = context.getResources().getConfiguration().locale;
-        if (locale != null) {
-            String language = locale.getLanguage();
-            String country = locale.getCountry();
-            if (language != null) {
-                if (country != null) {
-                    mMediaScanner.setLocale(language + "_" + country);
-                } else {
-                    mMediaScanner.setLocale(language);
-                }
-            }
-        }
         initDeviceProperties(context);
+
+        mCloseGuard.open("close");
     }
 
     public void setServer(MtpServer server) {
@@ -221,9 +217,20 @@
     }
 
     @Override
+    public void close() {
+        mCloseGuard.close();
+        if (mClosed.compareAndSet(false, true)) {
+            mMediaScanner.close();
+            mMediaProvider.close();
+            native_finalize();
+        }
+    }
+
+    @Override
     protected void finalize() throws Throwable {
         try {
-            native_finalize();
+            mCloseGuard.warnIfOpen();
+            close();
         } finally {
             super.finalize();
         }
@@ -334,7 +341,7 @@
         if (path != null) {
             Cursor c = null;
             try {
-                c = mMediaProvider.query(mPackageName, mObjectsUri, ID_PROJECTION, PATH_WHERE,
+                c = mMediaProvider.query(mObjectsUri, ID_PROJECTION, PATH_WHERE,
                         new String[] { path }, null, null);
                 if (c != null && c.getCount() > 0) {
                     Log.w(TAG, "file already exists in beginSendObject: " + path);
@@ -359,7 +366,7 @@
         values.put(Files.FileColumns.DATE_MODIFIED, modified);
 
         try {
-            Uri uri = mMediaProvider.insert(mPackageName, mObjectsUri, values);
+            Uri uri = mMediaProvider.insert(mObjectsUri, values);
             if (uri != null) {
                 return Integer.parseInt(uri.getPathSegments().get(2));
             } else {
@@ -394,13 +401,13 @@
                 values.put(Files.FileColumns.DATE_MODIFIED, System.currentTimeMillis() / 1000);
                 values.put(MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, handle);
                 try {
-                    Uri uri = mMediaProvider.insert(mPackageName,
+                    Uri uri = mMediaProvider.insert(
                             Audio.Playlists.EXTERNAL_CONTENT_URI, values);
                 } catch (RemoteException e) {
                     Log.e(TAG, "RemoteException in endSendObject", e);
                 }
             } else {
-                mMediaScanner.scanMtpFile(path, mVolumeName, handle, format);
+                mMediaScanner.scanMtpFile(path, handle, format);
             }
         } else {
             deleteFile(handle);
@@ -503,7 +510,7 @@
             }
         }
 
-        return mMediaProvider.query(mPackageName, mObjectsUri, ID_PROJECTION, where,
+        return mMediaProvider.query(mObjectsUri, ID_PROJECTION, where,
                 whereArgs, null, null);
     }
 
@@ -580,6 +587,7 @@
             MtpConstants.FORMAT_PLS_PLAYLIST,
             MtpConstants.FORMAT_XML_DOCUMENT,
             MtpConstants.FORMAT_FLAC,
+            MtpConstants.FORMAT_DNG,
         };
     }
 
@@ -689,6 +697,7 @@
             case MtpConstants.FORMAT_GIF:
             case MtpConstants.FORMAT_PNG:
             case MtpConstants.FORMAT_BMP:
+            case MtpConstants.FORMAT_DNG:
                 return IMAGE_PROPERTIES;
             default:
                 return FILE_PROPERTIES;
@@ -721,7 +730,7 @@
              propertyGroup = mPropertyGroupsByFormat.get(format);
              if (propertyGroup == null) {
                 int[] propertyList = getSupportedObjectProperties(format);
-                propertyGroup = new MtpPropertyGroup(this, mMediaProvider, mPackageName,
+                propertyGroup = new MtpPropertyGroup(this, mMediaProvider,
                         mVolumeName, propertyList);
                 mPropertyGroupsByFormat.put(new Integer(format), propertyGroup);
             }
@@ -729,7 +738,7 @@
               propertyGroup = mPropertyGroupsByProperty.get(property);
              if (propertyGroup == null) {
                 int[] propertyList = new int[] { (int)property };
-                propertyGroup = new MtpPropertyGroup(this, mMediaProvider, mPackageName,
+                propertyGroup = new MtpPropertyGroup(this, mMediaProvider,
                         mVolumeName, propertyList);
                 mPropertyGroupsByProperty.put(new Integer((int)property), propertyGroup);
             }
@@ -745,7 +754,7 @@
         String path = null;
         String[] whereArgs = new String[] {  Integer.toString(handle) };
         try {
-            c = mMediaProvider.query(mPackageName, mObjectsUri, PATH_PROJECTION, ID_WHERE,
+            c = mMediaProvider.query(mObjectsUri, PATH_PROJECTION, ID_WHERE,
                     whereArgs, null, null);
             if (c != null && c.moveToNext()) {
                 path = c.getString(1);
@@ -788,7 +797,7 @@
         try {
             // note - we are relying on a special case in MediaProvider.update() to update
             // the paths for all children in the case where this is a directory.
-            updated = mMediaProvider.update(mPackageName, mObjectsUri, values, ID_WHERE, whereArgs);
+            updated = mMediaProvider.update(mObjectsUri, values, ID_WHERE, whereArgs);
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in mMediaProvider.update", e);
         }
@@ -805,7 +814,7 @@
             if (oldFile.getName().startsWith(".") && !newPath.startsWith(".")) {
                 // directory was unhidden
                 try {
-                    mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, newPath, null);
+                    mMediaProvider.call(MediaStore.UNHIDE_CALL, newPath, null);
                 } catch (RemoteException e) {
                     Log.e(TAG, "failed to unhide/rescan for " + newPath);
                 }
@@ -815,7 +824,7 @@
             if (oldFile.getName().toLowerCase(Locale.US).equals(".nomedia")
                     && !newPath.toLowerCase(Locale.US).equals(".nomedia")) {
                 try {
-                    mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, oldFile.getParent(), null);
+                    mMediaProvider.call(MediaStore.UNHIDE_CALL, oldFile.getParent(), null);
                 } catch (RemoteException e) {
                     Log.e(TAG, "failed to unhide/rescan for " + newPath);
                 }
@@ -886,7 +895,7 @@
                         char[] outName, long[] outCreatedModified) {
         Cursor c = null;
         try {
-            c = mMediaProvider.query(mPackageName, mObjectsUri, OBJECT_INFO_PROJECTION,
+            c = mMediaProvider.query(mObjectsUri, OBJECT_INFO_PROJECTION,
                             ID_WHERE, new String[] {  Integer.toString(handle) }, null, null);
             if (c != null && c.moveToNext()) {
                 outStorageFormatParent[0] = c.getInt(1);
@@ -933,7 +942,7 @@
         }
         Cursor c = null;
         try {
-            c = mMediaProvider.query(mPackageName, mObjectsUri, PATH_FORMAT_PROJECTION,
+            c = mMediaProvider.query(mObjectsUri, PATH_FORMAT_PROJECTION,
                             ID_WHERE, new String[] {  Integer.toString(handle) }, null, null);
             if (c != null && c.moveToNext()) {
                 String path = c.getString(1);
@@ -960,7 +969,7 @@
     private int getObjectFormat(int handle) {
         Cursor c = null;
         try {
-            c = mMediaProvider.query(mPackageName, mObjectsUri, FORMAT_PROJECTION,
+            c = mMediaProvider.query(mObjectsUri, FORMAT_PROJECTION,
                             ID_WHERE, new String[] {  Integer.toString(handle) }, null, null);
             if (c != null && c.moveToNext()) {
                 return c.getInt(1);
@@ -984,7 +993,7 @@
 
         Cursor c = null;
         try {
-            c = mMediaProvider.query(mPackageName, mObjectsUri, PATH_FORMAT_PROJECTION,
+            c = mMediaProvider.query(mObjectsUri, PATH_FORMAT_PROJECTION,
                             ID_WHERE, new String[] {  Integer.toString(handle) }, null, null);
             if (c != null && c.moveToNext()) {
                 // don't convert to media path here, since we will be matching
@@ -1007,7 +1016,7 @@
             if (format == MtpConstants.FORMAT_ASSOCIATION) {
                 // recursive case - delete all children first
                 Uri uri = Files.getMtpObjectsUri(mVolumeName);
-                int count = mMediaProvider.delete(mPackageName, uri,
+                int count = mMediaProvider.delete(uri,
                     // the 'like' makes it use the index, the 'lower()' makes it correct
                     // when the path contains sqlite wildcard characters
                     "_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)",
@@ -1015,12 +1024,12 @@
             }
 
             Uri uri = Files.getMtpObjectsUri(mVolumeName, handle);
-            if (mMediaProvider.delete(mPackageName, uri, null, null) > 0) {
+            if (mMediaProvider.delete(uri, null, null) > 0) {
                 if (format != MtpConstants.FORMAT_ASSOCIATION
                         && path.toLowerCase(Locale.US).endsWith("/.nomedia")) {
                     try {
                         String parentPath = path.substring(0, path.lastIndexOf("/"));
-                        mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, parentPath, null);
+                        mMediaProvider.call(MediaStore.UNHIDE_CALL, parentPath, null);
                     } catch (RemoteException e) {
                         Log.e(TAG, "failed to unhide/rescan for " + path);
                     }
@@ -1043,7 +1052,7 @@
         Uri uri = Files.getMtpReferencesUri(mVolumeName, handle);
         Cursor c = null;
         try {
-            c = mMediaProvider.query(mPackageName, uri, ID_PROJECTION, null, null, null, null);
+            c = mMediaProvider.query(uri, ID_PROJECTION, null, null, null, null);
             if (c == null) {
                 return null;
             }
@@ -1077,7 +1086,7 @@
             valuesList[i] = values;
         }
         try {
-            if (mMediaProvider.bulkInsert(mPackageName, uri, valuesList) > 0) {
+            if (mMediaProvider.bulkInsert(uri, valuesList) > 0) {
                 return MtpConstants.RESPONSE_OK;
             }
         } catch (RemoteException e) {
diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java
index 95cb520..0e7013c 100644
--- a/media/java/android/mtp/MtpDevice.java
+++ b/media/java/android/mtp/MtpDevice.java
@@ -19,9 +19,12 @@
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbDeviceConnection;
 import android.os.CancellationSignal;
-import android.os.OperationCanceledException;
 import android.os.ParcelFileDescriptor;
 
+import com.android.internal.util.Preconditions;
+
+import java.io.IOException;
+
 /**
  * This class represents an MTP or PTP device connected on the USB host bus. An application can
  * instantiate an object of this type, by referencing an attached {@link
@@ -150,14 +153,54 @@
      *
      * @param objectHandle handle of the object to read
      * @param objectSize the size of the object (this should match
-     *      {@link MtpObjectInfo#getCompressedSize}
+     *      {@link MtpObjectInfo#getCompressedSize})
      * @return the object's data, or null if reading fails
      */
     public byte[] getObject(int objectHandle, int objectSize) {
+        Preconditions.checkArgumentNonnegative(objectSize, "objectSize should not be negative");
         return native_get_object(objectHandle, objectSize);
     }
 
     /**
+     * Obtains object bytes in the specified range and writes it to an array.
+     * This call may block for an arbitrary amount of time depending on the size
+     * of the data and speed of the devices.
+     *
+     * @param objectHandle handle of the object to read
+     * @param offset Start index of reading range. It must be a non-negative value at most
+     *     0xffffffff.
+     * @param size Size of reading range. It must be a non-negative value at most 0xffffffff. If
+     *     0xffffffff is specified, the method obtains the full bytes of object.
+     * @param buffer Array to write data.
+     * @return Size of bytes that are actually read.
+     */
+    public long getPartialObject(int objectHandle, long offset, long size, byte[] buffer)
+            throws IOException {
+        return native_get_partial_object(objectHandle, offset, size, buffer);
+    }
+
+    /**
+     * Obtains object bytes in the specified range and writes it to an array.
+     * This call may block for an arbitrary amount of time depending on the size
+     * of the data and speed of the devices.
+     *
+     * This is a vender-extended operation supported by Android that enables us to pass
+     * unsigned 64-bit offset. Check if the MTP device supports the operation by using
+     * {@link MtpDeviceInfo#getOperationsSupported()}.
+     *
+     * @param objectHandle handle of the object to read
+     * @param offset Start index of reading range. It must be a non-negative value.
+     * @param size Size of reading range. It must be a non-negative value at most 0xffffffff.
+     * @param buffer Array to write data.
+     * @return Size of bytes that are actually read.
+     * @see MtpConstants#OPERATION_GET_PARTIAL_OBJECT_64
+     */
+    public long getPartialObject64(int objectHandle, long offset, long size, byte[] buffer)
+            throws IOException {
+        return native_get_partial_object_64(objectHandle, offset, size, buffer);
+    }
+
+    /**
      * Returns the thumbnail data for an object as a byte array.
      * The size and format of the thumbnail data can be determined via
      * {@link MtpObjectInfo#getThumbCompressedSize} and
@@ -263,7 +306,7 @@
      * @param descriptor file descriptor to read the data from.
      * @return true if the file transfer succeeds
      */
-    public boolean sendObject(int objectHandle, int size, ParcelFileDescriptor descriptor) {
+    public boolean sendObject(int objectHandle, long size, ParcelFileDescriptor descriptor) {
         return native_send_object(objectHandle, size, descriptor.getFd());
     }
 
@@ -322,14 +365,18 @@
     private native MtpStorageInfo native_get_storage_info(int storageId);
     private native int[] native_get_object_handles(int storageId, int format, int objectHandle);
     private native MtpObjectInfo native_get_object_info(int objectHandle);
-    private native byte[] native_get_object(int objectHandle, int objectSize);
+    private native byte[] native_get_object(int objectHandle, long objectSize);
+    private native long native_get_partial_object(
+            int objectHandle, long offset, long objectSize, byte[] buffer) throws IOException;
+    private native int native_get_partial_object_64(
+            int objectHandle, long offset, long objectSize, byte[] buffer) throws IOException;
     private native byte[] native_get_thumbnail(int objectHandle);
     private native boolean native_delete_object(int objectHandle);
-    private native long native_get_parent(int objectHandle);
-    private native long native_get_storage_id(int objectHandle);
+    private native int native_get_parent(int objectHandle);
+    private native int native_get_storage_id(int objectHandle);
     private native boolean native_import_file(int objectHandle, String destPath);
     private native boolean native_import_file(int objectHandle, int fd);
-    private native boolean native_send_object(int objectHandle, int size, int fd);
+    private native boolean native_send_object(int objectHandle, long size, int fd);
     private native MtpObjectInfo native_send_object_info(MtpObjectInfo info);
     private native int native_submit_event_request();
     private native MtpEvent native_reap_event_request(int handle);
diff --git a/media/java/android/mtp/MtpDeviceInfo.java b/media/java/android/mtp/MtpDeviceInfo.java
index ef9436d..2e4f451 100644
--- a/media/java/android/mtp/MtpDeviceInfo.java
+++ b/media/java/android/mtp/MtpDeviceInfo.java
@@ -16,6 +16,8 @@
 
 package android.mtp;
 
+import android.annotation.Nullable;
+
 /**
  * This class encapsulates information about an MTP device.
  * This corresponds to the DeviceInfo Dataset described in
@@ -27,6 +29,8 @@
     private String mModel;
     private String mVersion;
     private String mSerialNumber;
+    private int[] mOperationsSupported;
+    private int[] mEventsSupported;
 
     // only instantiated via JNI
     private MtpDeviceInfo() {
@@ -67,4 +71,75 @@
     public final String getSerialNumber() {
         return mSerialNumber;
     }
-}
\ No newline at end of file
+
+    /**
+     * Returns operation code supported by the device.
+     *
+     * @return supported operation code. Can be null if device does not provide the property.
+     * @see MtpConstants#OPERATION_GET_DEVICE_INFO
+     * @see MtpConstants#OPERATION_OPEN_SESSION
+     * @see MtpConstants#OPERATION_CLOSE_SESSION
+     * @see MtpConstants#OPERATION_GET_STORAGE_I_DS
+     * @see MtpConstants#OPERATION_GET_STORAGE_INFO
+     * @see MtpConstants#OPERATION_GET_NUM_OBJECTS
+     * @see MtpConstants#OPERATION_GET_OBJECT_HANDLES
+     * @see MtpConstants#OPERATION_GET_OBJECT_INFO
+     * @see MtpConstants#OPERATION_GET_OBJECT
+     * @see MtpConstants#OPERATION_GET_THUMB
+     * @see MtpConstants#OPERATION_DELETE_OBJECT
+     * @see MtpConstants#OPERATION_SEND_OBJECT_INFO
+     * @see MtpConstants#OPERATION_SEND_OBJECT
+     * @see MtpConstants#OPERATION_INITIATE_CAPTURE
+     * @see MtpConstants#OPERATION_FORMAT_STORE
+     * @see MtpConstants#OPERATION_RESET_DEVICE
+     * @see MtpConstants#OPERATION_SELF_TEST
+     * @see MtpConstants#OPERATION_SET_OBJECT_PROTECTION
+     * @see MtpConstants#OPERATION_POWER_DOWN
+     * @see MtpConstants#OPERATION_GET_DEVICE_PROP_DESC
+     * @see MtpConstants#OPERATION_GET_DEVICE_PROP_VALUE
+     * @see MtpConstants#OPERATION_SET_DEVICE_PROP_VALUE
+     * @see MtpConstants#OPERATION_RESET_DEVICE_PROP_VALUE
+     * @see MtpConstants#OPERATION_TERMINATE_OPEN_CAPTURE
+     * @see MtpConstants#OPERATION_MOVE_OBJECT
+     * @see MtpConstants#OPERATION_COPY_OBJECT
+     * @see MtpConstants#OPERATION_GET_PARTIAL_OBJECT
+     * @see MtpConstants#OPERATION_INITIATE_OPEN_CAPTURE
+     * @see MtpConstants#OPERATION_GET_OBJECT_PROPS_SUPPORTED
+     * @see MtpConstants#OPERATION_GET_OBJECT_PROP_DESC
+     * @see MtpConstants#OPERATION_GET_OBJECT_PROP_VALUE
+     * @see MtpConstants#OPERATION_SET_OBJECT_PROP_VALUE
+     * @see MtpConstants#OPERATION_GET_OBJECT_REFERENCES
+     * @see MtpConstants#OPERATION_SET_OBJECT_REFERENCES
+     * @see MtpConstants#OPERATION_SKIP
+     */
+    public final @Nullable int[] getOperationsSupported() {
+        return mOperationsSupported;
+    }
+
+    /**
+     * Returns event code supported by the device.
+     *
+     * @return supported event code. Can be null if device does not provide the property.
+     * @see MtpConstants#EVENT_UNDEFINED
+     * @see MtpConstants#EVENT_CANCEL_TRANSACTION
+     * @see MtpConstants#EVENT_OBJECT_ADDED
+     * @see MtpConstants#EVENT_OBJECT_REMOVED
+     * @see MtpConstants#EVENT_STORE_ADDED
+     * @see MtpConstants#EVENT_STORE_REMOVED
+     * @see MtpConstants#EVENT_DEVICE_PROP_CHANGED
+     * @see MtpConstants#EVENT_OBJECT_INFO_CHANGED
+     * @see MtpConstants#EVENT_DEVICE_INFO_CHANGED
+     * @see MtpConstants#EVENT_REQUEST_OBJECT_TRANSFER
+     * @see MtpConstants#EVENT_STORE_FULL
+     * @see MtpConstants#EVENT_DEVICE_RESET
+     * @see MtpConstants#EVENT_STORAGE_INFO_CHANGED
+     * @see MtpConstants#EVENT_CAPTURE_COMPLETE
+     * @see MtpConstants#EVENT_UNREPORTED_STATUS
+     * @see MtpConstants#EVENT_OBJECT_PROP_CHANGED
+     * @see MtpConstants#EVENT_OBJECT_PROP_DESC_CHANGED
+     * @see MtpConstants#EVENT_OBJECT_REFERENCES_CHANGED
+     */
+    public final @Nullable int[] getEventsSupported() {
+        return mEventsSupported;
+    }
+}
diff --git a/media/java/android/mtp/MtpEvent.java b/media/java/android/mtp/MtpEvent.java
index 4c8a742..dc89a56 100644
--- a/media/java/android/mtp/MtpEvent.java
+++ b/media/java/android/mtp/MtpEvent.java
@@ -18,29 +18,15 @@
 
 /**
  * This class encapsulates information about a MTP event.
- * Event constants are defined by the USB-IF MTP specification.
+ * This corresponds to the events described in appendix G of the MTP specification.
  */
 public class MtpEvent {
-    public static final int EVENT_UNDEFINED = 0x4000;
-    public static final int EVENT_CANCEL_TRANSACTION = 0x4001;
-    public static final int EVENT_OBJECT_ADDED = 0x4002;
-    public static final int EVENT_OBJECT_REMOVED = 0x4003;
-    public static final int EVENT_STORE_ADDED = 0x4004;
-    public static final int EVENT_STORE_REMOVED = 0x4005;
-    public static final int EVENT_DEVICE_PROP_CHANGED = 0x4006;
-    public static final int EVENT_OBJECT_INFO_CHANGED = 0x4007;
-    public static final int EVENT_DEVICE_INFO_CHANGED = 0x4008;
-    public static final int EVENT_REQUEST_OBJECT_TRANSFER = 0x4009;
-    public static final int EVENT_STORE_FULL = 0x400A;
-    public static final int EVENT_DEVICE_RESET = 0x400B;
-    public static final int EVENT_STORAGE_INFO_CHANGED = 0x400C;
-    public static final int EVENT_CAPTURE_COMPLETE = 0x400D;
-    public static final int EVENT_UNREPORTED_STATUS = 0x400E;
-    public static final int EVENT_OBJECT_PROP_CHANGED = 0xC801;
-    public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 0xC802;
-    public static final int EVENT_OBJECT_REFERENCES_CHANGED = 0xC803;
+    private int mEventCode = MtpConstants.EVENT_UNDEFINED;
 
-    private int mEventCode = EVENT_UNDEFINED;
+    // Parameters for event. The interpretation of event parameters depends upon mEventCode.
+    private int mParameter1;
+    private int mParameter2;
+    private int mParameter3;
 
     /**
      * Returns event code of MTP event.
@@ -48,4 +34,136 @@
      * @return event code
      */
     public int getEventCode() { return mEventCode; }
+
+    /**
+     * Obtains the first event parameter.
+     */
+    public int getParameter1() { return mParameter1; }
+
+    /**
+     * Obtains the second event parameter.
+     */
+    public int getParameter2() { return mParameter2; }
+
+    /**
+     * Obtains the third event parameter.
+     */
+    public int getParameter3() { return mParameter3; }
+
+    /**
+     * Obtains objectHandle event parameter.
+     *
+     * @see MtpConstants#EVENT_OBJECT_ADDED
+     * @see MtpConstants#EVENT_OBJECT_REMOVED
+     * @see MtpConstants#EVENT_OBJECT_INFO_CHANGED
+     * @see MtpConstants#EVENT_REQUEST_OBJECT_TRANSFER
+     * @see MtpConstants#EVENT_OBJECT_PROP_CHANGED
+     * @see MtpConstants#EVENT_OBJECT_REFERENCES_CHANGED
+     */
+    public int getObjectHandle() {
+        switch (mEventCode) {
+            case MtpConstants.EVENT_OBJECT_ADDED:
+                return mParameter1;
+            case MtpConstants.EVENT_OBJECT_REMOVED:
+                return mParameter1;
+            case MtpConstants.EVENT_OBJECT_INFO_CHANGED:
+                return mParameter1;
+            case MtpConstants.EVENT_REQUEST_OBJECT_TRANSFER:
+                return mParameter1;
+            case MtpConstants.EVENT_OBJECT_PROP_CHANGED:
+                return mParameter1;
+            case MtpConstants.EVENT_OBJECT_REFERENCES_CHANGED:
+                return mParameter1;
+            default:
+                throw new IllegalParameterAccess("objectHandle", mEventCode);
+        }
+    }
+
+    /**
+     * Obtains storageID event parameter.
+     *
+     * @see MtpConstants#EVENT_STORE_ADDED
+     * @see MtpConstants#EVENT_STORE_REMOVED
+     * @see MtpConstants#EVENT_STORE_FULL
+     * @see MtpConstants#EVENT_STORAGE_INFO_CHANGED
+     */
+    public int getStorageId() {
+        switch (mEventCode) {
+            case MtpConstants.EVENT_STORE_ADDED:
+                return mParameter1;
+            case MtpConstants.EVENT_STORE_REMOVED:
+                return mParameter1;
+            case MtpConstants.EVENT_STORE_FULL:
+                return mParameter1;
+            case MtpConstants.EVENT_STORAGE_INFO_CHANGED:
+                return mParameter1;
+            default:
+                throw new IllegalParameterAccess("storageID", mEventCode);
+        }
+    }
+
+    /**
+     * Obtains devicePropCode event parameter.
+     *
+     * @see MtpConstants#EVENT_DEVICE_PROP_CHANGED
+     */
+    public int getDevicePropCode() {
+        switch (mEventCode) {
+            case MtpConstants.EVENT_DEVICE_PROP_CHANGED:
+                return mParameter1;
+            default:
+                throw new IllegalParameterAccess("devicePropCode", mEventCode);
+        }
+    }
+
+    /**
+     * Obtains transactionID event parameter.
+     *
+     * @see MtpConstants#EVENT_CAPTURE_COMPLETE
+     */
+    public int getTransactionId() {
+        switch (mEventCode) {
+            case MtpConstants.EVENT_CAPTURE_COMPLETE:
+                return mParameter1;
+            default:
+                throw new IllegalParameterAccess("transactionID", mEventCode);
+        }
+    }
+
+    /**
+     * Obtains objectPropCode event parameter.
+     *
+     * @see MtpConstants#EVENT_OBJECT_PROP_CHANGED
+     * @see MtpConstants#EVENT_OBJECT_PROP_DESC_CHANGED
+     */
+    public int getObjectPropCode() {
+        switch (mEventCode) {
+            case MtpConstants.EVENT_OBJECT_PROP_CHANGED:
+                return mParameter2;
+            case MtpConstants.EVENT_OBJECT_PROP_DESC_CHANGED:
+                return mParameter1;
+            default:
+                throw new IllegalParameterAccess("objectPropCode", mEventCode);
+        }
+    }
+
+    /**
+     * Obtains objectFormatCode event parameter.
+     *
+     * @see MtpConstants#EVENT_OBJECT_PROP_DESC_CHANGED
+     */
+    public int getObjectFormatCode() {
+        switch (mEventCode) {
+            case MtpConstants.EVENT_OBJECT_PROP_DESC_CHANGED:
+                return mParameter2;
+            default:
+                throw new IllegalParameterAccess("objectFormatCode", mEventCode);
+        }
+    }
+
+    private static class IllegalParameterAccess extends UnsupportedOperationException {
+        public IllegalParameterAccess(String propertyName, int eventCode) {
+            super("Cannot obtain " + propertyName + " for the event: " + eventCode + ".");
+        }
+    }
 }
diff --git a/media/java/android/mtp/MtpObjectInfo.java b/media/java/android/mtp/MtpObjectInfo.java
index 64aa997..02092b1 100644
--- a/media/java/android/mtp/MtpObjectInfo.java
+++ b/media/java/android/mtp/MtpObjectInfo.java
@@ -16,6 +16,8 @@
 
 package android.mtp;
 
+import com.android.internal.util.Preconditions;
+
 /**
  * This class encapsulates information about an object on an MTP device.
  * This corresponds to the ObjectInfo Dataset described in
@@ -96,10 +98,20 @@
      * @return the object size
      */
     public final int getCompressedSize() {
+        Preconditions.checkState(mCompressedSize >= 0);
         return mCompressedSize;
     }
 
     /**
+     * Returns the size of the MTP object
+     *
+     * @return the object size
+     */
+    public final long getCompressedSizeLong() {
+        return uint32ToLong(mCompressedSize);
+    }
+
+    /**
      * Returns the format code for the MTP object's thumbnail
      * Will be zero for objects with no thumbnail
      *
@@ -116,60 +128,126 @@
      * @return the thumbnail size
      */
     public final int getThumbCompressedSize() {
+        Preconditions.checkState(mThumbCompressedSize >= 0);
         return mThumbCompressedSize;
     }
 
     /**
+     * Returns the size of the MTP object's thumbnail
+     * Will be zero for objects with no thumbnail
+     *
+     * @return the thumbnail size
+     */
+    public final long getThumbCompressedSizeLong() {
+        return uint32ToLong(mThumbCompressedSize);
+    }
+
+    /**
      * Returns the width of the MTP object's thumbnail in pixels
      * Will be zero for objects with no thumbnail
      *
      * @return the thumbnail width
      */
     public final int getThumbPixWidth() {
+        Preconditions.checkState(mThumbPixWidth >= 0);
         return mThumbPixWidth;
     }
 
     /**
+     * Returns the width of the MTP object's thumbnail in pixels
+     * Will be zero for objects with no thumbnail
+     *
+     * @return the thumbnail width
+     */
+    public final long getThumbPixWidthLong() {
+        return uint32ToLong(mThumbPixWidth);
+    }
+
+    /**
      * Returns the height of the MTP object's thumbnail in pixels
      * Will be zero for objects with no thumbnail
      *
      * @return the thumbnail height
      */
     public final int getThumbPixHeight() {
+        Preconditions.checkState(mThumbPixHeight >= 0);
         return mThumbPixHeight;
     }
 
     /**
+     * Returns the height of the MTP object's thumbnail in pixels
+     * Will be zero for objects with no thumbnail
+     *
+     * @return the thumbnail height
+     */
+    public final long getThumbPixHeightLong() {
+        return uint32ToLong(mThumbPixHeight);
+    }
+
+    /**
      * Returns the width of the MTP object in pixels
      * Will be zero for non-image objects
      *
      * @return the image width
      */
     public final int getImagePixWidth() {
+        Preconditions.checkState(mImagePixWidth >= 0);
         return mImagePixWidth;
     }
 
     /**
+     * Returns the width of the MTP object in pixels
+     * Will be zero for non-image objects
+     *
+     * @return the image width
+     */
+    public final long getImagePixWidthLong() {
+        return uint32ToLong(mImagePixWidth);
+    }
+
+    /**
      * Returns the height of the MTP object in pixels
      * Will be zero for non-image objects
      *
      * @return the image height
      */
     public final int getImagePixHeight() {
+        Preconditions.checkState(mImagePixHeight >= 0);
         return mImagePixHeight;
     }
 
     /**
+     * Returns the height of the MTP object in pixels
+     * Will be zero for non-image objects
+     *
+     * @return the image height
+     */
+    public final long getImagePixHeightLong() {
+        return uint32ToLong(mImagePixHeight);
+    }
+
+    /**
      * Returns the depth of the MTP object in bits per pixel
      * Will be zero for non-image objects
      *
      * @return the image depth
      */
     public final int getImagePixDepth() {
+        Preconditions.checkState(mImagePixDepth >= 0);
         return mImagePixDepth;
     }
 
     /**
+     * Returns the depth of the MTP object in bits per pixel
+     * Will be zero for non-image objects
+     *
+     * @return the image depth
+     */
+    public final long getImagePixDepthLong() {
+        return uint32ToLong(mImagePixDepth);
+    }
+
+    /**
      * Returns the object handle for the object's parent
      * Will be zero for the root directory of a storage unit
      *
@@ -203,7 +281,7 @@
         return mAssociationDesc;
     }
 
-   /**
+    /**
      * Returns the sequence number for the MTP object
      * This field is typically not used for MTP devices,
      * but is sometimes used to define a sequence of photos
@@ -212,9 +290,22 @@
      * @return the object's sequence number
      */
     public final int getSequenceNumber() {
+        Preconditions.checkState(mSequenceNumber >= 0);
         return mSequenceNumber;
     }
 
+    /**
+     * Returns the sequence number for the MTP object
+     * This field is typically not used for MTP devices,
+     * but is sometimes used to define a sequence of photos
+     * on PTP cameras.
+     *
+     * @return the object's sequence number
+     */
+    public final long getSequenceNumberLong() {
+        return uint32ToLong(mSequenceNumber);
+    }
+
    /**
      * Returns the name of the MTP object
      *
@@ -309,8 +400,8 @@
             return this;
         }
 
-        public Builder setCompressedSize(int value) {
-            mObjectInfo.mCompressedSize = value;
+        public Builder setCompressedSize(long value) {
+            mObjectInfo.mCompressedSize = longToUint32(value, "value");
             return this;
         }
 
@@ -329,18 +420,18 @@
             return this;
         }
 
-        public Builder setImagePixDepth(int value) {
-            mObjectInfo.mImagePixDepth = value;
+        public Builder setImagePixDepth(long value) {
+            mObjectInfo.mImagePixDepth = longToUint32(value, "value");
             return this;
         }
 
-        public Builder setImagePixHeight(int value) {
-            mObjectInfo.mImagePixHeight = value;
+        public Builder setImagePixHeight(long value) {
+            mObjectInfo.mImagePixHeight = longToUint32(value, "value");
             return this;
         }
 
-        public Builder setImagePixWidth(int value) {
-            mObjectInfo.mImagePixWidth = value;
+        public Builder setImagePixWidth(long value) {
+            mObjectInfo.mImagePixWidth = longToUint32(value, "value");
             return this;
         }
 
@@ -364,8 +455,8 @@
             return this;
         }
 
-        public Builder setSequenceNumber(int value) {
-            mObjectInfo.mSequenceNumber = value;
+        public Builder setSequenceNumber(long value) {
+            mObjectInfo.mSequenceNumber = longToUint32(value, "value");
             return this;
         }
 
@@ -374,8 +465,8 @@
             return this;
         }
 
-        public Builder setThumbCompressedSize(int value) {
-            mObjectInfo.mThumbCompressedSize = value;
+        public Builder setThumbCompressedSize(long value) {
+            mObjectInfo.mThumbCompressedSize = longToUint32(value, "value");
             return this;
         }
 
@@ -384,13 +475,13 @@
             return this;
         }
 
-        public Builder setThumbPixHeight(int value) {
-            mObjectInfo.mThumbPixHeight = value;
+        public Builder setThumbPixHeight(long value) {
+            mObjectInfo.mThumbPixHeight = longToUint32(value, "value");
             return this;
         }
 
-        public Builder setThumbPixWidth(int value) {
-            mObjectInfo.mThumbPixWidth = value;
+        public Builder setThumbPixWidth(long value) {
+            mObjectInfo.mThumbPixWidth = longToUint32(value, "value");
             return this;
         }
 
@@ -407,4 +498,13 @@
             return result;
         }
     }
+
+    private static long uint32ToLong(int value) {
+        return value < 0 ? 0x100000000L + value : value;
+    }
+
+    private static int longToUint32(long value, String valueName) {
+        Preconditions.checkArgumentInRange(value, 0, 0xffffffffL, valueName);
+        return (int) value;
+    }
 }
diff --git a/media/java/android/mtp/MtpPropertyGroup.java b/media/java/android/mtp/MtpPropertyGroup.java
index c80adfa..dea3008 100644
--- a/media/java/android/mtp/MtpPropertyGroup.java
+++ b/media/java/android/mtp/MtpPropertyGroup.java
@@ -16,7 +16,7 @@
 
 package android.mtp;
 
-import android.content.IContentProvider;
+import android.content.ContentProviderClient;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.RemoteException;
@@ -48,8 +48,7 @@
     }
 
     private final MtpDatabase mDatabase;
-    private final IContentProvider mProvider;
-    private final String mPackageName;
+    private final ContentProviderClient mProvider;
     private final String mVolumeName;
     private final Uri mUri;
 
@@ -65,13 +64,12 @@
     private static final String PARENT_WHERE = Files.FileColumns.PARENT + "=?";
     private static final String PARENT_FORMAT_WHERE = PARENT_WHERE + " AND " + FORMAT_WHERE;
     // constructs a property group for a list of properties
-    public MtpPropertyGroup(MtpDatabase database, IContentProvider provider, String packageName,
-            String volume, int[] properties) {
+    public MtpPropertyGroup(MtpDatabase database, ContentProviderClient provider, String volumeName,
+            int[] properties) {
         mDatabase = database;
         mProvider = provider;
-        mPackageName = packageName;
-        mVolumeName = volume;
-        mUri = Files.getMtpObjectsUri(volume);
+        mVolumeName = volumeName;
+        mUri = Files.getMtpObjectsUri(volumeName);
 
         int count = properties.length;
         ArrayList<String> columns = new ArrayList<String>(count);
@@ -201,7 +199,7 @@
         Cursor c = null;
         try {
             // for now we are only reading properties from the "objects" table
-            c = mProvider.query(mPackageName, mUri,
+            c = mProvider.query(mUri,
                             new String [] { Files.FileColumns._ID, column },
                             ID_WHERE, new String[] { Integer.toString(id) }, null, null);
             if (c != null && c.moveToNext()) {
@@ -221,7 +219,7 @@
     private String queryAudio(int id, String column) {
         Cursor c = null;
         try {
-            c = mProvider.query(mPackageName, Audio.Media.getContentUri(mVolumeName),
+            c = mProvider.query(Audio.Media.getContentUri(mVolumeName),
                             new String [] { Files.FileColumns._ID, column },
                             ID_WHERE, new String[] { Integer.toString(id) }, null, null);
             if (c != null && c.moveToNext()) {
@@ -242,7 +240,7 @@
         Cursor c = null;
         try {
             Uri uri = Audio.Genres.getContentUriForAudioId(mVolumeName, id);
-            c = mProvider.query(mPackageName, uri,
+            c = mProvider.query(uri,
                             new String [] { Files.FileColumns._ID, Audio.GenresColumns.NAME },
                             null, null, null, null);
             if (c != null && c.moveToNext()) {
@@ -264,7 +262,7 @@
         Cursor c = null;
         try {
             // for now we are only reading properties from the "objects" table
-            c = mProvider.query(mPackageName, mUri,
+            c = mProvider.query(mUri,
                             new String [] { Files.FileColumns._ID, column },
                             ID_WHERE, new String[] { Integer.toString(id) }, null, null);
             if (c != null && c.moveToNext()) {
@@ -335,7 +333,7 @@
         try {
             // don't query if not necessary
             if (depth > 0 || handle == 0xFFFFFFFF || mColumns.length > 1) {
-                c = mProvider.query(mPackageName, mUri, mColumns, where, whereArgs, null, null);
+                c = mProvider.query(mUri, mColumns, where, whereArgs, null, null);
                 if (c == null) {
                     return new MtpPropertyList(0, MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE);
                 }
diff --git a/media/java/android/service/media/IMediaBrowserService.aidl b/media/java/android/service/media/IMediaBrowserService.aidl
index f01fc07..fe7ebfa 100644
--- a/media/java/android/service/media/IMediaBrowserService.aidl
+++ b/media/java/android/service/media/IMediaBrowserService.aidl
@@ -14,10 +14,19 @@
  * @hide
  */
 oneway interface IMediaBrowserService {
+
+    // Warning: DO NOT CHANGE the methods signature and order of methods.
+    // The change of the order or the method signatures could break the support library.
+
     void connect(String pkg, in Bundle rootHints, IMediaBrowserServiceCallbacks callbacks);
     void disconnect(IMediaBrowserServiceCallbacks callbacks);
 
     void addSubscription(String uri, IMediaBrowserServiceCallbacks callbacks);
     void removeSubscription(String uri, IMediaBrowserServiceCallbacks callbacks);
     void getMediaItem(String uri, in ResultReceiver cb);
-}
\ No newline at end of file
+
+    void addSubscriptionWithOptions(String uri, in Bundle options,
+            IMediaBrowserServiceCallbacks callbacks);
+    void removeSubscriptionWithOptions(String uri, in Bundle options,
+            IMediaBrowserServiceCallbacks callbacks);
+}
diff --git a/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
index 2a37ada..dadb025 100644
--- a/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
+++ b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
@@ -22,5 +22,5 @@
      */
     void onConnect(String root, in MediaSession.Token session, in Bundle extras);
     void onConnectFailed();
-    void onLoadChildren(String mediaId, in ParceledListSlice list);
+    void onLoadChildren(String mediaId, in ParceledListSlice list, in Bundle options);
 }
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index f2c6a6c..6cf90d5 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -25,11 +25,12 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.media.browse.MediaBrowser;
+import android.media.browse.MediaBrowserUtils;
 import android.media.session.MediaSession;
 import android.os.Binder;
 import android.os.Bundle;
-import android.os.IBinder;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.service.media.IMediaBrowserService;
@@ -40,7 +41,8 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.HashSet;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 
 /**
@@ -82,7 +84,9 @@
      */
     public static final String KEY_MEDIA_ITEM = "media_item";
 
-    private final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap();
+    private static final int RESULT_FLAG_OPTION_NOT_HANDLED = 0x00000001;
+
+    private final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap<>();
     private final Handler mHandler = new Handler();
     private ServiceBinder mBinder;
     MediaSession.Token mSession;
@@ -95,7 +99,7 @@
         Bundle rootHints;
         IMediaBrowserServiceCallbacks callbacks;
         BrowserRoot root;
-        HashSet<String> subscriptions = new HashSet();
+        HashMap<String, List<Bundle>> subscriptions = new HashMap<>();
     }
 
     /**
@@ -115,6 +119,7 @@
         private Object mDebug;
         private boolean mDetachCalled;
         private boolean mSendResultCalled;
+        private int mFlag;
 
         Result(Object debug) {
             mDebug = debug;
@@ -128,7 +133,7 @@
                 throw new IllegalStateException("sendResult() called twice for: " + mDebug);
             }
             mSendResultCalled = true;
-            onResultSent(result);
+            onResultSent(result, mFlag);
         }
 
         /**
@@ -151,11 +156,15 @@
             return mDetachCalled || mSendResultCalled;
         }
 
+        void setFlag(int flag) {
+            mFlag = flag;
+        }
+
         /**
          * Called when the result is sent, after assertions about not being called twice
          * have happened.
          */
-        void onResultSent(T result) {
+        void onResultSent(T result, int flag) {
         }
     }
 
@@ -228,9 +237,15 @@
                 });
         }
 
+        @Override
+        public void addSubscription(final String id,
+                final IMediaBrowserServiceCallbacks callbacks) {
+            addSubscriptionWithOptions(id, null, callbacks);
+        }
 
         @Override
-        public void addSubscription(final String id, final IMediaBrowserServiceCallbacks callbacks) {
+        public void addSubscriptionWithOptions(final String id, final Bundle options,
+                final IMediaBrowserServiceCallbacks callbacks) {
             mHandler.post(new Runnable() {
                     @Override
                     public void run() {
@@ -244,7 +259,7 @@
                             return;
                         }
 
-                        MediaBrowserService.this.addSubscription(id, connection);
+                        MediaBrowserService.this.addSubscription(id, connection, options);
                     }
                 });
         }
@@ -252,6 +267,12 @@
         @Override
         public void removeSubscription(final String id,
                 final IMediaBrowserServiceCallbacks callbacks) {
+            removeSubscriptionWithOptions(id, null, callbacks);
+        }
+
+        @Override
+        public void removeSubscriptionWithOptions(final String id, final Bundle options,
+                final IMediaBrowserServiceCallbacks callbacks) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
@@ -263,7 +284,7 @@
                                 + id);
                         return;
                     }
-                    if (!connection.subscriptions.remove(id)) {
+                    if (!MediaBrowserService.this.removeSubscription(id, connection, options)) {
                         Log.w(TAG, "removeSubscription called for " + id
                                 + " which is not subscribed");
                     }
@@ -345,6 +366,33 @@
             @NonNull Result<List<MediaBrowser.MediaItem>> result);
 
     /**
+     * Called to get information about the children of a media item.
+     * <p>
+     * Implementations must call {@link Result#sendResult result.sendResult}
+     * with the list of children. If loading the children will be an expensive
+     * operation that should be performed on another thread,
+     * {@link Result#detach result.detach} may be called before returning from
+     * this function, and then {@link Result#sendResult result.sendResult}
+     * called when the loading is complete.
+     *
+     * @param parentId The id of the parent media item whose children are to be
+     *            queried.
+     * @param result The Result to send the list of children to, or null if the
+     *            id is invalid.
+     * @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.
+     */
+    public void onLoadChildren(@NonNull String parentId,
+            @NonNull Result<List<MediaBrowser.MediaItem>> result, @NonNull Bundle options) {
+        // To support backward compatibility, when the implementation of MediaBrowserService doesn't
+        // override onLoadChildren() with options, onLoadChildren() without options will be used
+        // instead, and the options will be applied in the implementation of result.onResultSent().
+        result.setFlag(RESULT_FLAG_OPTION_NOT_HANDLED);
+        onLoadChildren(parentId, result);
+    }
+
+    /**
      * Called to get information about a specific media item.
      * <p>
      * Implementations must call {@link Result#sendResult result.sendResult}. If
@@ -413,7 +461,29 @@
      * @param parentId The id of the parent media item whose
      * children changed.
      */
-    public void notifyChildrenChanged(@NonNull final String parentId) {
+    public void notifyChildrenChanged(@NonNull String parentId) {
+        notifyChildrenChangedInternal(parentId, null);
+    }
+
+    /**
+     * Notifies all connected media browsers that the children of
+     * the specified parent id have changed in some way.
+     * This will cause browsers to fetch subscribed content again.
+     *
+     * @param parentId The id of the parent media item whose
+     *            children changed.
+     * @param options A bundle of service-specific arguments to send
+     *            to the media browse. The contents of this bundle may
+     *            contain the information about the change.
+     */
+    public void notifyChildrenChanged(@NonNull String parentId, @NonNull Bundle options) {
+        if (options == null) {
+            throw new IllegalArgumentException("options cannot be null in notifyChildrenChanged");
+        }
+        notifyChildrenChangedInternal(parentId, options);
+    }
+
+    private void notifyChildrenChangedInternal(final String parentId, final Bundle options) {
         if (parentId == null) {
             throw new IllegalArgumentException("parentId cannot be null in notifyChildrenChanged");
         }
@@ -422,8 +492,13 @@
             public void run() {
                 for (IBinder binder : mConnections.keySet()) {
                     ConnectionRecord connection = mConnections.get(binder);
-                    if (connection.subscriptions.contains(parentId)) {
-                        performLoadChildren(parentId, connection);
+                    List<Bundle> optionsList = connection.subscriptions.get(parentId);
+                    if (optionsList != null) {
+                        for (Bundle bundle : optionsList) {
+                            if (MediaBrowserUtils.hasDuplicatedItems(options, bundle)) {
+                                performLoadChildren(parentId, connection, bundle);
+                            }
+                        }
                     }
                 }
             }
@@ -451,12 +526,42 @@
     /**
      * Save the subscription and if it is a new subscription send the results.
      */
-    private void addSubscription(String id, ConnectionRecord connection) {
+    private void addSubscription(String id, ConnectionRecord connection, Bundle options) {
         // Save the subscription
-        connection.subscriptions.add(id);
-
+        List<Bundle> optionsList = connection.subscriptions.get(id);
+        if (optionsList == null) {
+            optionsList = new ArrayList<>();
+        }
+        for (Bundle bundle : optionsList) {
+            if (MediaBrowserUtils.areSameOptions(options, bundle)) {
+                return;
+            }
+        }
+        optionsList.add(options);
+        connection.subscriptions.put(id, optionsList);
         // send the results
-        performLoadChildren(id, connection);
+        performLoadChildren(id, connection, options);
+    }
+
+    /**
+     * Remove the subscription.
+     */
+    private boolean removeSubscription(String id, ConnectionRecord connection, Bundle options) {
+        boolean removed = false;
+        List<Bundle> optionsList = connection.subscriptions.get(id);
+        if (optionsList != null) {
+            for (Bundle bundle : optionsList) {
+                if (MediaBrowserUtils.areSameOptions(options, bundle)) {
+                    removed = true;
+                    optionsList.remove(bundle);
+                    break;
+                }
+            }
+            if (optionsList.size() == 0) {
+                connection.subscriptions.remove(id);
+            }
+        }
+        return removed;
     }
 
     /**
@@ -464,11 +569,12 @@
      * <p>
      * Callers must make sure that this connection is still connected.
      */
-    private void performLoadChildren(final String parentId, final ConnectionRecord connection) {
+    private void performLoadChildren(final String parentId, final ConnectionRecord connection,
+            final Bundle options) {
         final Result<List<MediaBrowser.MediaItem>> result
                 = new Result<List<MediaBrowser.MediaItem>>(parentId) {
             @Override
-            void onResultSent(List<MediaBrowser.MediaItem> list) {
+            void onResultSent(List<MediaBrowser.MediaItem> list, int flag) {
                 if (mConnections.get(connection.callbacks.asBinder()) != connection) {
                     if (DBG) {
                         Log.d(TAG, "Not sending onLoadChildren result for connection that has"
@@ -477,10 +583,13 @@
                     return;
                 }
 
+                List<MediaBrowser.MediaItem> filteredList =
+                        (flag & RESULT_FLAG_OPTION_NOT_HANDLED) != 0
+                        ? applyOptions(list, options) : list;
                 final ParceledListSlice<MediaBrowser.MediaItem> pls =
-                        list == null ? null : new ParceledListSlice(list);
+                        filteredList == null ? null : new ParceledListSlice<>(filteredList);
                 try {
-                    connection.callbacks.onLoadChildren(parentId, pls);
+                    connection.callbacks.onLoadChildren(parentId, pls, options);
                 } catch (RemoteException ex) {
                     // The other side is in the process of crashing.
                     Log.w(TAG, "Calling onLoadChildren() failed for id=" + parentId
@@ -489,7 +598,11 @@
             }
         };
 
-        onLoadChildren(parentId, result);
+        if (options == null) {
+            onLoadChildren(parentId, result);
+        } else {
+            onLoadChildren(parentId, result, options);
+        }
 
         if (!result.isDone()) {
             throw new IllegalStateException("onLoadChildren must call detach() or sendResult()"
@@ -497,11 +610,29 @@
         }
     }
 
+    private List<MediaBrowser.MediaItem> applyOptions(List<MediaBrowser.MediaItem> list,
+            final Bundle options) {
+        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 toIndex = fromIndex + pageSize;
+        if (page < 1 || pageSize < 1 || fromIndex >= list.size()) {
+            return null;
+        }
+        if (toIndex > list.size()) {
+            toIndex = list.size();
+        }
+        return list.subList(fromIndex, toIndex);
+    }
+
     private void performLoadItem(String itemId, final ResultReceiver receiver) {
         final Result<MediaBrowser.MediaItem> result =
                 new Result<MediaBrowser.MediaItem>(itemId) {
             @Override
-            void onResultSent(MediaBrowser.MediaItem item) {
+            void onResultSent(MediaBrowser.MediaItem item, int flag) {
                 Bundle bundle = new Bundle();
                 bundle.putParcelable(KEY_MEDIA_ITEM, item);
                 receiver.send(0, bundle);
@@ -546,7 +677,7 @@
         }
 
         /**
-         * Gets any extras about the brwoser service.
+         * Gets any extras about the browser service.
          */
         public Bundle getExtras() {
             return mExtras;
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 79557bc..a326f6f 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -3,6 +3,7 @@
 
 LOCAL_SRC_FILES:= \
     android_media_AmrInputStream.cpp \
+    android_media_ExifInterface.cpp \
     android_media_ImageWriter.cpp \
     android_media_ImageReader.cpp \
     android_media_MediaCrypto.cpp \
@@ -44,6 +45,7 @@
     libusbhost \
     libjhead \
     libexif \
+    libpiex \
     libstagefright_amrnb_common
 
 LOCAL_REQUIRED_MODULES := \
@@ -54,6 +56,7 @@
 
 LOCAL_C_INCLUDES += \
     external/libexif/ \
+    external/piex/ \
     external/tremor/Tremor \
     frameworks/base/core/jni \
     frameworks/base/libs/hwui \
diff --git a/media/jni/android_media_ExifInterface.cpp b/media/jni/android_media_ExifInterface.cpp
new file mode 100644
index 0000000..ba38569
--- /dev/null
+++ b/media/jni/android_media_ExifInterface.cpp
@@ -0,0 +1,276 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ExifInterface_JNI"
+
+#include "android_media_Utils.h"
+
+#include "src/piex_types.h"
+#include "src/piex.h"
+
+#include <jni.h>
+#include <JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <nativehelper/ScopedLocalRef.h>
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <utils/KeyedVector.h>
+
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+#define FIND_CLASS(var, className) \
+    var = env->FindClass(className); \
+    LOG_FATAL_IF(! var, "Unable to find class " className);
+
+#define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
+    var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
+    LOG_FATAL_IF(! var, "Unable to find method " fieldName);
+
+struct HashMapFields {
+    jmethodID init;
+    jmethodID put;
+};
+
+struct fields_t {
+    HashMapFields hashMap;
+    jclass hashMapClassId;
+};
+
+static fields_t gFields;
+
+static jobject KeyedVectorToHashMap(JNIEnv *env, KeyedVector<String8, String8> const &map) {
+    jclass clazz = gFields.hashMapClassId;
+    jobject hashMap = env->NewObject(clazz, gFields.hashMap.init);
+    for (size_t i = 0; i < map.size(); ++i) {
+        jstring jkey = env->NewStringUTF(map.keyAt(i).string());
+        jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
+        env->CallObjectMethod(hashMap, gFields.hashMap.put, jkey, jvalue);
+        env->DeleteLocalRef(jkey);
+        env->DeleteLocalRef(jvalue);
+    }
+    return hashMap;
+}
+
+extern "C" {
+
+// -------------------------- ExifInterface methods ---------------------------
+
+static void ExifInterface_initRaw(JNIEnv *env) {
+    jclass clazz;
+    FIND_CLASS(clazz, "java/util/HashMap");
+    gFields.hashMapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
+
+    GET_METHOD_ID(gFields.hashMap.init, clazz, "<init>", "()V");
+    GET_METHOD_ID(gFields.hashMap.put, clazz, "put",
+                  "(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) {
+        return NULL;
+    }
+    String8 filename(filenameChars);
+    env->ReleaseStringUTFChars(jfilename, filenameChars);
+
+    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());
+        return NULL;
+    }
+
+    KeyedVector<String8, String8> map;
+
+    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));
+    } else {
+        map.add(String8("hasThumbnail"), String8("false"));
+    }
+
+    map.add(
+            String8("Orientation"),
+            String8::format("%u", image_data.exif_orientation));
+    map.add(
+            String8("ImageWidth"),
+            String8::format("%u", image_data.full_width));
+    map.add(
+            String8("ImageLength"),
+            String8::format("%u", image_data.full_height));
+
+    // Current PIEX does not have LightSource information while JPEG version of
+    // EXIFInterface always declares the light source field. For the
+    // compatibility, it provides the default value of the light source field.
+    map.add(String8("LightSource"), String8("0"));
+
+    if (!image_data.maker.empty()) {
+        map.add(String8("Make"), String8(image_data.maker.c_str()));
+    }
+
+    if (!image_data.model.empty()) {
+        map.add(String8("Model"), String8(image_data.model.c_str()));
+    }
+
+    if (!image_data.date_time.empty()) {
+        map.add(String8("DateTime"), String8(image_data.date_time.c_str()));
+    }
+
+    if (image_data.iso) {
+        map.add(
+                String8("ISOSpeedRatings"),
+                String8::format("%u", image_data.iso));
+    }
+
+    if (image_data.exposure_time.numerator != 0
+            && image_data.exposure_time.denominator != 0) {
+        double exposureTime =
+            (double)image_data.exposure_time.numerator
+            / image_data.exposure_time.denominator;
+
+        const char* format;
+        if (exposureTime < 0.01) {
+            format = "%6.4f";
+        } else {
+            format = "%5.3f";
+        }
+        map.add(String8("ExposureTime"), String8::format(format, exposureTime));
+    }
+
+    if (image_data.fnumber.numerator != 0
+            && image_data.fnumber.denominator != 0) {
+        double fnumber =
+            (double)image_data.fnumber.numerator
+            / image_data.fnumber.denominator;
+        map.add(String8("FNumber"), String8::format("%5.3f", fnumber));
+    }
+
+    if (image_data.focal_length.numerator != 0
+            && image_data.focal_length.denominator != 0) {
+        map.add(
+                String8("FocalLength"),
+                String8::format(
+                        "%u/%u",
+                        image_data.focal_length.numerator,
+                        image_data.focal_length.denominator));
+    }
+
+    if (image_data.gps.is_valid) {
+        if (image_data.gps.latitude[0].denominator != 0
+                && image_data.gps.latitude[1].denominator != 0
+                && image_data.gps.latitude[2].denominator != 0) {
+            map.add(
+                    String8("GPSLatitude"),
+                    String8::format(
+                            "%u/%u,%u/%u,%u/%u",
+                            image_data.gps.latitude[0].numerator,
+                            image_data.gps.latitude[0].denominator,
+                            image_data.gps.latitude[1].numerator,
+                            image_data.gps.latitude[1].denominator,
+                            image_data.gps.latitude[2].numerator,
+                            image_data.gps.latitude[2].denominator));
+        }
+
+        if (image_data.gps.latitude_ref) {
+            char str[2];
+            str[0] = image_data.gps.latitude_ref;
+            str[1] = 0;
+            map.add(String8("GPSLatitudeRef"), String8(str));
+        }
+
+        if (image_data.gps.longitude[0].denominator != 0
+                && image_data.gps.longitude[1].denominator != 0
+                && image_data.gps.longitude[2].denominator != 0) {
+            map.add(
+                    String8("GPSLongitude"),
+                    String8::format(
+                            "%u/%u,%u/%u,%u/%u",
+                            image_data.gps.longitude[0].numerator,
+                            image_data.gps.longitude[0].denominator,
+                            image_data.gps.longitude[1].numerator,
+                            image_data.gps.longitude[1].denominator,
+                            image_data.gps.longitude[2].numerator,
+                            image_data.gps.longitude[2].denominator));
+        }
+
+        if (image_data.gps.longitude_ref) {
+            char str[2];
+            str[0] = image_data.gps.longitude_ref;
+            str[1] = 0;
+            map.add(String8("GPSLongitudeRef"), String8(str));
+        }
+
+        if (image_data.gps.altitude.denominator != 0) {
+            map.add(
+                    String8("GPSAltitude"),
+                    String8::format("%u/%u",
+                            image_data.gps.altitude.numerator,
+                            image_data.gps.altitude.denominator));
+
+            map.add(
+                    String8("GPSAltitudeRef"),
+                    String8(image_data.gps.altitude_ref ? "1" : "0"));
+        }
+
+        if (image_data.gps.time_stamp[0].denominator != 0
+                && image_data.gps.time_stamp[1].denominator != 0
+                && image_data.gps.time_stamp[2].denominator != 0) {
+            map.add(
+                    String8("GPSTimeStamp"),
+                    String8::format(
+                            "%02u:%02u:%02u",
+                            image_data.gps.time_stamp[0].numerator
+                            / image_data.gps.time_stamp[0].denominator,
+                            image_data.gps.time_stamp[1].numerator
+                            / image_data.gps.time_stamp[1].denominator,
+                            image_data.gps.time_stamp[2].numerator
+                            / image_data.gps.time_stamp[2].denominator));
+        }
+
+        if (!image_data.gps.date_stamp.empty()) {
+            map.add(
+                    String8("GPSDateStamp"),
+                    String8(image_data.gps.date_stamp.c_str()));
+        }
+    }
+
+    return KeyedVectorToHashMap(env, map);
+}
+
+} // extern "C"
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod gMethods[] = {
+    { "initRawNative", "()V", (void *)ExifInterface_initRaw },
+    { "getRawAttributesNative", "(Ljava/lang/String;)Ljava/util/HashMap;",
+      (void*)ExifInterface_getRawMetadata },
+};
+
+int register_android_media_ExifInterface(JNIEnv *env) {
+    return AndroidRuntime::registerNativeMethods(
+            env,
+            "android/media/ExifInterface",
+            gMethods,
+            NELEM(gMethods));
+}
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 1c043e0..4ac62f5 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -574,6 +574,7 @@
         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;
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 49b579c..2004a3a 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -85,6 +85,13 @@
     jmethodID setNativeObjectLocked;
 } gPersistentSurfaceClassInfo;
 
+static struct {
+    jint Unencrypted;
+    jint AesCtr;
+    jint AesCbc;
+} gCryptoModes;
+
+
 struct fields_t {
     jfieldID context;
     jmethodID postEventFromNativeID;
@@ -94,6 +101,9 @@
     jfieldID cryptoInfoKeyID;
     jfieldID cryptoInfoIVID;
     jfieldID cryptoInfoModeID;
+    jfieldID cryptoInfoPatternID;
+    jfieldID patternEncryptBlocksID;
+    jfieldID patternSkipBlocksID;
 };
 
 static fields_t gFields;
@@ -325,11 +335,12 @@
         const uint8_t key[16],
         const uint8_t iv[16],
         CryptoPlugin::Mode mode,
+        const CryptoPlugin::Pattern &pattern,
         int64_t presentationTimeUs,
         uint32_t flags,
         AString *errorDetailMsg) {
     return mCodec->queueSecureInputBuffer(
-            index, offset, subSamples, numSubSamples, key, iv, mode,
+            index, offset, subSamples, numSubSamples, key, iv, mode, pattern,
             presentationTimeUs, flags, errorDetailMsg);
 }
 
@@ -1275,7 +1286,26 @@
     jbyteArray ivObj =
         (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
 
-    jint mode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
+    jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
+    enum CryptoPlugin::Mode mode;
+    if (jmode == gCryptoModes.Unencrypted) {
+        mode = CryptoPlugin::kMode_Unencrypted;
+    } else if (jmode == gCryptoModes.AesCtr) {
+        mode = CryptoPlugin::kMode_AES_CTR;
+    } else if (jmode == gCryptoModes.AesCbc) {
+        mode = CryptoPlugin::kMode_AES_CBC;
+    }  else {
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        return;
+    }
+
+    jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID);
+
+    CryptoPlugin::Pattern pattern;
+    if (patternObj != NULL) {
+        pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID);
+        pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID);
+    }
 
     status_t err = OK;
 
@@ -1360,7 +1390,8 @@
                 index, offset,
                 subSamples, numSubSamples,
                 (const uint8_t *)key, (const uint8_t *)iv,
-                (CryptoPlugin::Mode)mode,
+                mode,
+                pattern,
                 timestampUs,
                 flags,
                 &errorDetailMsg);
@@ -1658,6 +1689,22 @@
 
     CHECK(gFields.postEventFromNativeID != NULL);
 
+    jfieldID field;
+    field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I");
+    CHECK(field != NULL);
+    gCryptoModes.Unencrypted =
+        env->GetStaticIntField(clazz.get(), field);
+
+    field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CTR", "I");
+    CHECK(field != NULL);
+    gCryptoModes.AesCtr =
+        env->GetStaticIntField(clazz.get(), field);
+
+    field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CBC", "I");
+    CHECK(field != NULL);
+    gCryptoModes.AesCbc =
+        env->GetStaticIntField(clazz.get(), field);
+
     clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
     CHECK(clazz.get() != NULL);
 
@@ -1682,10 +1729,22 @@
     gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I");
     CHECK(gFields.cryptoInfoModeID != NULL);
 
+    gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "pattern",
+        "Landroid/media/MediaCodec$CryptoInfo$Pattern;");
+    CHECK(gFields.cryptoInfoPatternID != NULL);
+
+    clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo$Pattern"));
+    CHECK(clazz.get() != NULL);
+
+    gFields.patternEncryptBlocksID = env->GetFieldID(clazz.get(), "mEncryptBlocks", "I");
+    CHECK(gFields.patternEncryptBlocksID != NULL);
+
+    gFields.patternSkipBlocksID = env->GetFieldID(clazz.get(), "mSkipBlocks", "I");
+    CHECK(gFields.patternSkipBlocksID != NULL);
+
     clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException"));
     CHECK(clazz.get() != NULL);
 
-    jfieldID field;
     field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I");
     CHECK(field != NULL);
     gCryptoErrorCodes.cryptoErrorNoKey =
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 6650cf9..c0c47ef 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -81,6 +81,7 @@
             const uint8_t key[16],
             const uint8_t iv[16],
             CryptoPlugin::Mode mode,
+            const CryptoPlugin::Pattern &pattern,
             int64_t presentationTimeUs,
             uint32_t flags,
             AString *errorDetailMsg);
diff --git a/media/jni/android_media_MediaDataSource.cpp b/media/jni/android_media_MediaDataSource.cpp
index 025133f..3b892cb 100644
--- a/media/jni/android_media_MediaDataSource.cpp
+++ b/media/jni/android_media_MediaDataSource.cpp
@@ -150,4 +150,8 @@
     mJavaObjStatus = UNKNOWN_ERROR;
 }
 
+uint32_t JMediaDataSource::getFlags() {
+    return 0;
+}
+
 }  // namespace android
diff --git a/media/jni/android_media_MediaDataSource.h b/media/jni/android_media_MediaDataSource.h
index 2bc237e..34624eb 100644
--- a/media/jni/android_media_MediaDataSource.h
+++ b/media/jni/android_media_MediaDataSource.h
@@ -45,6 +45,7 @@
     virtual ssize_t readAt(off64_t offset, size_t size);
     virtual status_t getSize(off64_t* size);
     virtual void close();
+    virtual uint32_t getFlags();
 
 private:
     // Protect all member variables with mLock because this object will be
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index be36729..e9d62de 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -1088,6 +1088,7 @@
     return AndroidRuntime::registerNativeMethods(env,
                 "android/media/MediaPlayer", gMethods, NELEM(gMethods));
 }
+extern int register_android_media_ExifInterface(JNIEnv *env);
 extern int register_android_media_ImageReader(JNIEnv *env);
 extern int register_android_media_ImageWriter(JNIEnv *env);
 extern int register_android_media_Crypto(JNIEnv *env);
@@ -1219,6 +1220,11 @@
         goto bail;
     }
 
+    if (register_android_media_ExifInterface(env) < 0) {
+        ALOGE("ERROR: ExifInterface native registration failed");
+        goto bail;
+    }
+
     /* success -- return valid version number */
     result = JNI_VERSION_1_4;
 
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index e101709..c08a5e3 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -28,6 +28,91 @@
 
 namespace android {
 
+FileStream::FileStream(const String8 filename)
+    : mPosition(0),
+      mSize(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() {
+    if (mFile != NULL) {
+        fclose(mFile);
+        mFile = NULL;
+    }
+}
+
+piex::Error FileStream::GetData(
+        const size_t offset, const size_t length, std::uint8_t* data) {
+    if (mFile == NULL) {
+        return piex::Error::kFail;
+    }
+
+    // Seek first.
+    if (mPosition != offset) {
+        fseek(mFile, offset, SEEK_SET);
+    }
+
+    // Read bytes.
+    size_t size = fread((void*)data, sizeof(std::uint8_t), length, mFile);
+    mPosition += size;
+
+    // Handle errors.
+    if (ferror(mFile) || (size == 0 && feof(mFile))) {
+        ALOGV("GetData read failed: (offset: %zu, length: %zu)", offset, length);
+        return piex::Error::kFail;
+    }
+    return piex::Error::kOk;
+}
+
+bool FileStream::exists() const {
+    return mFile != NULL;
+}
+
+size_t FileStream::size() const {
+    return mSize;
+}
+
+bool GetExifFromRawImage(
+        FileStream* 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());
+        return false;
+    }
+
+    piex::Error err = piex::GetPreviewImageData(stream, &image_data);
+
+    if (err != piex::Error::kOk) {
+        // The input data seems to be broken.
+        ALOGV("Raw image not detected: %s (piex error code: %d)", filename.string(), (int32_t)err);
+        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;
+}
+
 bool ConvertKeyValueArraysToKeyedVector(
         JNIEnv *env, jobjectArray keys, jobjectArray values,
         KeyedVector<String8, String8>* keyedVector) {
diff --git a/media/jni/android_media_Utils.h b/media/jni/android_media_Utils.h
index 635bceb..762c904 100644
--- a/media/jni/android_media_Utils.h
+++ b/media/jni/android_media_Utils.h
@@ -17,21 +17,48 @@
 #ifndef _ANDROID_MEDIA_UTILS_H_
 #define _ANDROID_MEDIA_UTILS_H_
 
-#include "jni.h"
-#include "JNIHelp.h"
-#include "android_runtime/AndroidRuntime.h"
+#include "src/piex_types.h"
+#include "src/piex.h"
 
+#include <android_runtime/AndroidRuntime.h>
+#include <jni.h>
+#include <JNIHelp.h>
 #include <utils/KeyedVector.h>
 #include <utils/String8.h>
 
 namespace android {
 
-/**
- * Returns true if the conversion is successful; otherwise, false.
- */
+class FileStream : public piex::StreamInterface {
+private:
+    FILE *mFile;
+    size_t mPosition;
+    size_t mSize;
+
+public:
+    FileStream(const String8 filename);
+    ~FileStream();
+
+    // 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;
+    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);
+
+// Returns true if the conversion is successful; otherwise, false.
 bool ConvertKeyValueArraysToKeyedVector(
-    JNIEnv *env, jobjectArray keys, jobjectArray values,
-    KeyedVector<String8, String8>* vector);
+        JNIEnv *env, jobjectArray keys, jobjectArray values,
+        KeyedVector<String8, String8>* vector);
 
 struct AMessage;
 status_t ConvertMessageToMap(
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index ec2f98a..556f2c7 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -17,25 +17,17 @@
 #define LOG_TAG "MtpDatabaseJNI"
 #include "utils/Log.h"
 
-#include <assert.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#include "jni.h"
-#include "JNIHelp.h"
-#include "android_runtime/AndroidRuntime.h"
-#include "android_runtime/Log.h"
-
+#include "android_media_Utils.h"
+#include "mtp.h"
 #include "MtpDatabase.h"
 #include "MtpDataPacket.h"
 #include "MtpObjectInfo.h"
 #include "MtpProperty.h"
 #include "MtpStringBuffer.h"
 #include "MtpUtils.h"
-#include "mtp.h"
+
+#include "src/piex_types.h"
+#include "src/piex.h"
 
 extern "C" {
 #include "libexif/exif-content.h"
@@ -44,6 +36,19 @@
 #include "libexif/exif-utils.h"
 }
 
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
+#include <jni.h>
+#include <JNIHelp.h>
+#include <nativehelper/ScopedLocalRef.h>
+
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdio.h>
+#include <unistd.h>
+
 using namespace android;
 
 // ----------------------------------------------------------------------------
@@ -823,24 +828,48 @@
     env->ReleaseCharArrayElements(mStringBuffer, str, 0);
 
     // read EXIF data for thumbnail information
-    if (info.mFormat == MTP_FORMAT_EXIF_JPEG || info.mFormat == MTP_FORMAT_JFIF) {
+    switch (info.mFormat) {
+        case MTP_FORMAT_EXIF_JPEG:
+        case MTP_FORMAT_JFIF: {
+            ExifData *exifdata = exif_data_new_from_file(path);
+            if (exifdata) {
+                if ((false)) {
+                    exif_data_foreach_content(exifdata, foreachcontent, NULL);
+                }
 
-        ExifData *exifdata = exif_data_new_from_file(path);
-        if (exifdata) {
-            if ((false)) {
-                exif_data_foreach_content(exifdata, foreachcontent, NULL);
+                ExifEntry *w = exif_content_get_entry(
+                        exifdata->ifd[EXIF_IFD_EXIF], EXIF_TAG_PIXEL_X_DIMENSION);
+                ExifEntry *h = exif_content_get_entry(
+                        exifdata->ifd[EXIF_IFD_EXIF], EXIF_TAG_PIXEL_Y_DIMENSION);
+                info.mThumbCompressedSize = exifdata->data ? exifdata->size : 0;
+                info.mThumbFormat = MTP_FORMAT_EXIF_JPEG;
+                info.mImagePixWidth = w ? getLongFromExifEntry(w) : 0;
+                info.mImagePixHeight = h ? getLongFromExifEntry(h) : 0;
+                exif_data_unref(exifdata);
+            }
+            break;
+        }
+
+        // Except DNG, all supported RAW image formats are not defined in PTP 1.2 specification.
+        // Most of RAW image formats are based on TIFF or TIFF/EP. To render Fuji's RAF format,
+        // it checks MTP_FORMAT_DEFINED case since it's designed as a custom format.
+        case MTP_FORMAT_DNG:
+        case MTP_FORMAT_TIFF:
+        case MTP_FORMAT_TIFF_EP:
+        case MTP_FORMAT_DEFINED: {
+            std::unique_ptr<FileStream> stream(new FileStream(path));
+            piex::PreviewImageData image_data;
+            if (!GetExifFromRawImage(stream.get(), path, image_data)) {
+                // Couldn't parse EXIF data from a image file via piex.
+                break;
             }
 
-            // XXX get this from exif, or parse jpeg header instead?
-            ExifEntry *w = exif_content_get_entry(
-                    exifdata->ifd[EXIF_IFD_EXIF], EXIF_TAG_PIXEL_X_DIMENSION);
-            ExifEntry *h = exif_content_get_entry(
-                    exifdata->ifd[EXIF_IFD_EXIF], EXIF_TAG_PIXEL_Y_DIMENSION);
-            info.mThumbCompressedSize = exifdata->data ? exifdata->size : 0;
+            info.mThumbCompressedSize = image_data.thumbnail_length;
             info.mThumbFormat = MTP_FORMAT_EXIF_JPEG;
-            info.mImagePixWidth = w ? getLongFromExifEntry(w) : 0;
-            info.mImagePixHeight = h ? getLongFromExifEntry(h) : 0;
-            exif_data_unref(exifdata);
+            info.mImagePixWidth = image_data.full_width;
+            info.mImagePixHeight = image_data.full_height;
+
+            break;
         }
     }
 
@@ -855,19 +884,55 @@
     void* result = NULL;
     outThumbSize = 0;
 
-    if (getObjectFilePath(handle, path, length, format) == MTP_RESPONSE_OK
-            && (format == MTP_FORMAT_EXIF_JPEG || format == MTP_FORMAT_JFIF)) {
-
-        ExifData *exifdata = exif_data_new_from_file(path);
-        if (exifdata) {
-            if (exifdata->data) {
-                result = malloc(exifdata->size);
-                if (result) {
-                    memcpy(result, exifdata->data, exifdata->size);
-                    outThumbSize = exifdata->size;
+    if (getObjectFilePath(handle, path, length, format) == MTP_RESPONSE_OK) {
+        switch (format) {
+            case MTP_FORMAT_EXIF_JPEG:
+            case MTP_FORMAT_JFIF: {
+                ExifData *exifdata = exif_data_new_from_file(path);
+                if (exifdata) {
+                    if (exifdata->data) {
+                        result = malloc(exifdata->size);
+                        if (result) {
+                            memcpy(result, exifdata->data, exifdata->size);
+                            outThumbSize = exifdata->size;
+                        }
+                    }
+                    exif_data_unref(exifdata);
                 }
+                break;
             }
-            exif_data_unref(exifdata);
+
+            // See the above comment on getObjectInfo() method.
+            case MTP_FORMAT_DNG:
+            case MTP_FORMAT_TIFF:
+            case MTP_FORMAT_TIFF_EP:
+            case MTP_FORMAT_DEFINED: {
+                std::unique_ptr<FileStream> stream(new FileStream(path));
+                piex::PreviewImageData image_data;
+                if (!GetExifFromRawImage(stream.get(), path, image_data)) {
+                    // Couldn't parse EXIF data from a image file via piex.
+                    break;
+                }
+
+                if (image_data.thumbnail_length == 0) {
+                    // No thumbnail.
+                    break;
+                }
+
+                result = malloc(image_data.thumbnail_length);
+                if (result) {
+                    piex::Error err = stream.get()->GetData(
+                            image_data.thumbnail_offset,
+                            image_data.thumbnail_length,
+                            (std::uint8_t *)result);
+                    if (err == piex::Error::kOk) {
+                        outThumbSize = image_data.thumbnail_length;
+                    } else {
+                        free(result);
+                    }
+                }
+                break;
+            }
         }
     }
 
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index 3f4d183..0ecb750 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -25,10 +25,16 @@
 #include <unistd.h>
 #include <fcntl.h>
 
+#include <memory>
+#include <string>
+
 #include "jni.h"
 #include "JNIHelp.h"
+#include "ScopedPrimitiveArray.h"
+
 #include "android_runtime/AndroidRuntime.h"
 #include "android_runtime/Log.h"
+#include "nativehelper/ScopedLocalRef.h"
 #include "private/android_filesystem_config.h"
 
 #include "MtpTypes.h"
@@ -41,6 +47,8 @@
 
 // ----------------------------------------------------------------------------
 
+namespace {
+
 static jfieldID field_context;
 
 jclass clazz_deviceInfo;
@@ -60,6 +68,8 @@
 static jfieldID field_deviceInfo_model;
 static jfieldID field_deviceInfo_version;
 static jfieldID field_deviceInfo_serialNumber;
+static jfieldID field_deviceInfo_operationsSupported;
+static jfieldID field_deviceInfo_eventsSupported;
 
 // MtpStorageInfo fields
 static jfieldID field_storageInfo_storageId;
@@ -92,6 +102,32 @@
 
 // MtpEvent fields
 static jfieldID field_event_eventCode;
+static jfieldID field_event_parameter1;
+static jfieldID field_event_parameter2;
+static jfieldID field_event_parameter3;
+
+class JavaArrayWriter {
+public:
+    JavaArrayWriter(JNIEnv* env, jbyteArray array) :
+        mEnv(env), mArray(array), mSize(mEnv->GetArrayLength(mArray)) {}
+    bool write(void* data, uint32_t offset, uint32_t length) {
+        if (static_cast<uint32_t>(mSize) < offset + length) {
+            return false;
+        }
+        mEnv->SetByteArrayRegion(mArray, offset, length, static_cast<jbyte*>(data));
+        return true;
+    }
+    static bool writeTo(void* data, uint32_t offset, uint32_t length, void* clientData) {
+        return static_cast<JavaArrayWriter*>(clientData)->write(data, offset, length);
+    }
+
+private:
+    JNIEnv* mEnv;
+    jbyteArray mArray;
+    jsize mSize;
+};
+
+}
 
 MtpDevice* get_device_from_object(JNIEnv* env, jobject javaDevice)
 {
@@ -184,7 +220,7 @@
         ALOGD("android_mtp_MtpDevice_get_device_info device is null");
         return NULL;
     }
-    MtpDeviceInfo* deviceInfo = device->getDeviceInfo();
+    std::unique_ptr<MtpDeviceInfo> deviceInfo(device->getDeviceInfo());
     if (!deviceInfo) {
         ALOGD("android_mtp_MtpDevice_get_device_info deviceInfo is null");
         return NULL;
@@ -192,7 +228,6 @@
     jobject info = env->NewObject(clazz_deviceInfo, constructor_deviceInfo);
     if (info == NULL) {
         ALOGE("Could not create a MtpDeviceInfo object");
-        delete deviceInfo;
         return NULL;
     }
 
@@ -208,8 +243,37 @@
     if (deviceInfo->mSerial)
         env->SetObjectField(info, field_deviceInfo_serialNumber,
             env->NewStringUTF(deviceInfo->mSerial));
+    if (deviceInfo->mOperations) {
+        const size_t size = deviceInfo->mOperations->size();
+        ScopedLocalRef<jintArray> operations(env, static_cast<jintArray>(env->NewIntArray(size)));
+        {
+            ScopedIntArrayRW elements(env, operations.get());
+            if (elements.get() == NULL) {
+                ALOGE("Could not create operationsSupported element.");
+                return NULL;
+            }
+            for (size_t i = 0; i < size; ++i) {
+                elements[i] = deviceInfo->mOperations->itemAt(i);
+            }
+            env->SetObjectField(info, field_deviceInfo_operationsSupported, operations.get());
+        }
+    }
+    if (deviceInfo->mEvents) {
+        const size_t size = deviceInfo->mEvents->size();
+        ScopedLocalRef<jintArray> events(env, static_cast<jintArray>(env->NewIntArray(size)));
+        {
+            ScopedIntArrayRW elements(env, events.get());
+            if (elements.get() == NULL) {
+                ALOGE("Could not create eventsSupported element.");
+                return NULL;
+            }
+            for (size_t i = 0; i < size; ++i) {
+                elements[i] = deviceInfo->mEvents->itemAt(i);
+            }
+            env->SetObjectField(info, field_deviceInfo_eventsSupported, events.get());
+        }
+    }
 
-    delete deviceInfo;
     return info;
 }
 
@@ -307,38 +371,134 @@
     return info;
 }
 
-struct get_object_callback_data {
-    JNIEnv *env;
-    jbyteArray array;
-};
-
-static bool get_object_callback(void* data, int offset, int length, void* clientData)
-{
-    get_object_callback_data* cbData = (get_object_callback_data *)clientData;
-    cbData->env->SetByteArrayRegion(cbData->array, offset, length, (jbyte *)data);
+bool check_uint32_arg(JNIEnv *env, const char* name, jlong value, uint32_t* out) {
+    if (value < 0 || 0xffffffff < value) {
+        jniThrowException(
+                env,
+                "java/lang/IllegalArgumentException",
+                (std::string("argument must be a 32-bit unsigned integer: ") + name).c_str());
+        return false;
+    }
+    *out = static_cast<uint32_t>(value);
     return true;
 }
 
 static jbyteArray
-android_mtp_MtpDevice_get_object(JNIEnv *env, jobject thiz, jint objectID, jint objectSize)
+android_mtp_MtpDevice_get_object(JNIEnv *env, jobject thiz, jint objectID, jlong objectSizeLong)
 {
-    MtpDevice* device = get_device_from_object(env, thiz);
-    if (!device)
-        return NULL;
-
-    jbyteArray array = env->NewByteArray(objectSize);
-    if (!array) {
-        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
-        return NULL;
+    uint32_t objectSize;
+    if (!check_uint32_arg(env, "objectSize", objectSizeLong, &objectSize)) {
+        return nullptr;
     }
 
-    get_object_callback_data data;
-    data.env = env;
-    data.array = array;
+    MtpDevice* device = get_device_from_object(env, thiz);
+    if (!device) {
+        return nullptr;
+    }
 
-    if (device->readObject(objectID, get_object_callback, objectSize, &data))
-        return array;
-    return NULL;
+    ScopedLocalRef<jbyteArray> array(env, env->NewByteArray(objectSize));
+    if (!array.get()) {
+        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+        return nullptr;
+    }
+
+    JavaArrayWriter writer(env, array.get());
+
+    if (device->readObject(objectID, JavaArrayWriter::writeTo, objectSize, &writer)) {
+        return array.release();
+    }
+    return nullptr;
+}
+
+static jlong
+android_mtp_MtpDevice_get_partial_object(JNIEnv *env,
+                                         jobject thiz,
+                                         jint objectID,
+                                         jlong offsetLong,
+                                         jlong sizeLong,
+                                         jbyteArray array)
+{
+    if (!array) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "Array must not be null.");
+        return -1;
+    }
+
+    uint32_t offset;
+    uint32_t size;
+    if (!check_uint32_arg(env, "offset", offsetLong, &offset) ||
+            !check_uint32_arg(env, "size", sizeLong, &size)) {
+        return -1;
+    }
+
+    MtpDevice* const device = get_device_from_object(env, thiz);
+    if (!device) {
+        jniThrowException(env, "java/io/IOException", "Failed to obtain MtpDevice.");
+        return -1;
+    }
+
+    JavaArrayWriter writer(env, array);
+    uint32_t written_size;
+    const bool success = device->readPartialObject(
+            objectID, offset, size, &written_size, JavaArrayWriter::writeTo, &writer);
+    if (!success) {
+        jniThrowException(env, "java/io/IOException", "Failed to read data.");
+        return -1;
+    }
+    return static_cast<jlong>(written_size);
+}
+
+static jint
+android_mtp_MtpDevice_get_partial_object_64(JNIEnv *env,
+                                            jobject thiz,
+                                            jint objectID,
+                                            jlong offset,
+                                            jlong size,
+                                            jbyteArray array) {
+    if (!array) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "Array must not be null.");
+        return -1;
+    }
+
+    if (offset < 0) {
+        jniThrowException(
+                env,
+                "java/lang/IllegalArgumentException",
+                "Offset argument must not be a negative value.");
+        return -1;
+    }
+
+    if (size < 0 || 0xffffffffL < size) {
+        jniThrowException(
+                env,
+                "java/lang/IllegalArgumentException",
+                "Size argument must be a 32-bit unsigned integer.");
+        return -1;
+    }
+
+    MtpDevice* const device = get_device_from_object(env, thiz);
+    if (!device) {
+        jniThrowException(env, "java/io/IOException", "Failed to obtain MtpDevice.");
+        return -1;
+    }
+
+    const uint32_t native_object_handle = static_cast<uint32_t>(objectID);
+    const uint64_t native_offset = static_cast<uint64_t>(offset);
+    const uint32_t native_size = static_cast<uint32_t>(size);
+
+    JavaArrayWriter writer(env, array);
+    uint32_t written_size;
+    const bool success = device->readPartialObject64(
+            native_object_handle,
+            native_offset,
+            native_size,
+            &written_size,
+            JavaArrayWriter::writeTo,
+            &writer);
+    if (!success) {
+        jniThrowException(env, "java/io/IOException", "Failed to read data.");
+        return -1;
+    }
+    return static_cast<jint>(written_size);
 }
 
 static jbyteArray
@@ -370,22 +530,22 @@
     }
 }
 
-static jlong
+static jint
 android_mtp_MtpDevice_get_parent(JNIEnv *env, jobject thiz, jint object_id)
 {
     MtpDevice* device = get_device_from_object(env, thiz);
     if (device)
-        return (jlong)device->getParent(object_id);
+        return static_cast<jint>(device->getParent(object_id));
     else
         return -1;
 }
 
-static jlong
+static jint
 android_mtp_MtpDevice_get_storage_id(JNIEnv *env, jobject thiz, jint object_id)
 {
     MtpDevice* device = get_device_from_object(env, thiz);
     if (device)
-        return (jlong)device->getStorageID(object_id);
+        return static_cast<jint>(device->getStorageID(object_id));
     else
         return -1;
 }
@@ -419,8 +579,13 @@
 }
 
 static jboolean
-android_mtp_MtpDevice_send_object(JNIEnv *env, jobject thiz, jint object_id, jint size, jint fd)
+android_mtp_MtpDevice_send_object(
+        JNIEnv *env, jobject thiz, jint object_id, jlong sizeLong, jint fd)
 {
+    uint32_t size;
+    if (!check_uint32_arg(env, "size", sizeLong, &size))
+        return JNI_FALSE;
+
     MtpDevice* device = get_device_from_object(env, thiz);
     if (!device)
         return JNI_FALSE;
@@ -512,13 +677,17 @@
         env->ThrowNew(clazz_io_exception, "");
         return NULL;
     }
-    const int eventCode = device->reapEventRequest(seq);
+    uint32_t parameters[3];
+    const int eventCode = device->reapEventRequest(seq, &parameters);
     if (eventCode <= 0) {
         env->ThrowNew(clazz_operation_canceled_exception, "");
         return NULL;
     }
     jobject result = env->NewObject(clazz_event, constructor_event);
     env->SetIntField(result, field_event_eventCode, eventCode);
+    env->SetIntField(result, field_event_parameter1, static_cast<jint>(parameters[0]));
+    env->SetIntField(result, field_event_parameter2, static_cast<jint>(parameters[1]));
+    env->SetIntField(result, field_event_parameter3, static_cast<jint>(parameters[2]));
     return result;
 }
 
@@ -546,15 +715,18 @@
                                         (void *)android_mtp_MtpDevice_get_object_handles},
     {"native_get_object_info",  "(I)Landroid/mtp/MtpObjectInfo;",
                                         (void *)android_mtp_MtpDevice_get_object_info},
-    {"native_get_object",       "(II)[B",(void *)android_mtp_MtpDevice_get_object},
+    {"native_get_object",       "(IJ)[B",(void *)android_mtp_MtpDevice_get_object},
+    {"native_get_partial_object", "(IJJ[B)J", (void *)android_mtp_MtpDevice_get_partial_object},
+    {"native_get_partial_object_64", "(IJJ[B)I",
+                                        (void *)android_mtp_MtpDevice_get_partial_object_64},
     {"native_get_thumbnail",    "(I)[B",(void *)android_mtp_MtpDevice_get_thumbnail},
     {"native_delete_object",    "(I)Z", (void *)android_mtp_MtpDevice_delete_object},
-    {"native_get_parent",       "(I)J", (void *)android_mtp_MtpDevice_get_parent},
-    {"native_get_storage_id",   "(I)J", (void *)android_mtp_MtpDevice_get_storage_id},
+    {"native_get_parent",       "(I)I", (void *)android_mtp_MtpDevice_get_parent},
+    {"native_get_storage_id",   "(I)I", (void *)android_mtp_MtpDevice_get_storage_id},
     {"native_import_file",      "(ILjava/lang/String;)Z",
                                         (void *)android_mtp_MtpDevice_import_file},
     {"native_import_file",      "(II)Z",(void *)android_mtp_MtpDevice_import_file_to_fd},
-    {"native_send_object",      "(III)Z",(void *)android_mtp_MtpDevice_send_object},
+    {"native_send_object",      "(IJI)Z",(void *)android_mtp_MtpDevice_send_object},
     {"native_send_object_info", "(Landroid/mtp/MtpObjectInfo;)Landroid/mtp/MtpObjectInfo;",
                                         (void *)android_mtp_MtpDevice_send_object_info},
     {"native_submit_event_request",  "()I", (void *)android_mtp_MtpDevice_submit_event_request},
@@ -599,6 +771,16 @@
         ALOGE("Can't find MtpDeviceInfo.mSerialNumber");
         return -1;
     }
+    field_deviceInfo_operationsSupported = env->GetFieldID(clazz, "mOperationsSupported", "[I");
+    if (field_deviceInfo_operationsSupported == NULL) {
+        ALOGE("Can't find MtpDeviceInfo.mOperationsSupported");
+        return -1;
+    }
+    field_deviceInfo_eventsSupported = env->GetFieldID(clazz, "mEventsSupported", "[I");
+    if (field_deviceInfo_eventsSupported == NULL) {
+        ALOGE("Can't find MtpDeviceInfo.mEventsSupported");
+        return -1;
+    }
     clazz_deviceInfo = (jclass)env->NewGlobalRef(clazz);
 
     clazz = env->FindClass("android/mtp/MtpStorageInfo");
@@ -765,6 +947,21 @@
         ALOGE("Can't find MtpObjectInfo.mEventCode");
         return -1;
     }
+    field_event_parameter1 = env->GetFieldID(clazz, "mParameter1", "I");
+    if (field_event_parameter1 == NULL) {
+        ALOGE("Can't find MtpObjectInfo.mParameter1");
+        return -1;
+    }
+    field_event_parameter2 = env->GetFieldID(clazz, "mParameter2", "I");
+    if (field_event_parameter2 == NULL) {
+        ALOGE("Can't find MtpObjectInfo.mParameter2");
+        return -1;
+    }
+    field_event_parameter3 = env->GetFieldID(clazz, "mParameter3", "I");
+    if (field_event_parameter3 == NULL) {
+        ALOGE("Can't find MtpObjectInfo.mParameter3");
+        return -1;
+    }
     clazz_event = (jclass)env->NewGlobalRef(clazz);
 
     clazz = env->FindClass("android/mtp/MtpDevice");
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 70d651f..b63df6f 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -655,7 +655,7 @@
        goto error;
     }
 
-    if ((numChannels < 1) || (numChannels > 8)) {
+    if ((numChannels < 1) || (numChannels > FCC_8)) {
         ALOGE("Sample channel count (%d) out of range", numChannels);
         status = BAD_VALUE;
         goto error;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
index 05df014..06efa90 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
@@ -16,6 +16,7 @@
 
 package com.android.mediaframeworktest.unit;
 
+import android.content.ContentProviderClient;
 import android.content.ContentValues;
 import android.content.IContentProvider;
 import android.media.MediaInserter;
@@ -81,8 +82,9 @@
     protected void setUp() throws Exception {
         super.setUp();
         mMockProvider = EasyMock.createMock(IContentProvider.class);
-        mMediaInserter = new MediaInserter(mMockProvider,
-        mPackageName, TEST_BUFFER_SIZE);
+        final ContentProviderClient client = new ContentProviderClient(
+                getInstrumentation().getContext().getContentResolver(), mMockProvider, true);
+        mMediaInserter = new MediaInserter(client, TEST_BUFFER_SIZE);
         mPackageName = getInstrumentation().getContext().getPackageName();
         mFilesCounter = 0;
         mAudioCounter = 0;
diff --git a/native/android/Android.mk b/native/android/Android.mk
index 1742bee..5386e6f 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -7,6 +7,7 @@
 #
 LOCAL_SRC_FILES:= \
     asset_manager.cpp \
+    choreographer.cpp \
     configuration.cpp \
     input.cpp \
     looper.cpp \
@@ -43,4 +44,7 @@
 
 LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
+# Required because of b/25642296
+LOCAL_CLANG_arm64 := false
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/native/android/choreographer.cpp b/native/android/choreographer.cpp
new file mode 100644
index 0000000..e35c85b
--- /dev/null
+++ b/native/android/choreographer.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Choreographer"
+//#define LOG_NDEBUG 0
+
+#include <cinttypes>
+#include <queue>
+#include <thread>
+
+#include <android/choreographer.h>
+#include <androidfw/DisplayEventDispatcher.h>
+#include <gui/ISurfaceComposer.h>
+#include <utils/Looper.h>
+#include <utils/Mutex.h>
+#include <utils/Timers.h>
+
+namespace android {
+
+static inline const char* toString(bool value) {
+    return value ? "true" : "false";
+}
+
+struct FrameCallback {
+    AChoreographer_frameCallback callback;
+    void* data;
+    nsecs_t dueTime;
+
+    inline bool operator<(const FrameCallback& rhs) const {
+        // Note that this is intentionally flipped because we want callbacks due sooner to be at
+        // the head of the queue
+        return dueTime > rhs.dueTime;
+    }
+};
+
+
+class Choreographer : public DisplayEventDispatcher, public MessageHandler {
+public:
+    void postFrameCallback(AChoreographer_frameCallback cb, void* data);
+    void postFrameCallbackDelayed(AChoreographer_frameCallback cb, void* data, nsecs_t delay);
+
+    enum {
+        MSG_SCHEDULE_CALLBACKS = 0,
+        MSG_SCHEDULE_VSYNC = 1
+    };
+    virtual void handleMessage(const Message& message) override;
+
+    static Choreographer* getForThread();
+
+protected:
+    virtual ~Choreographer() = default;
+
+private:
+    Choreographer(const sp<Looper>& looper);
+    Choreographer(const Choreographer&) = delete;
+
+    virtual void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count);
+    virtual void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected);
+
+    void scheduleCallbacks();
+
+    // Protected by mLock
+    std::priority_queue<FrameCallback> mCallbacks;
+
+    mutable Mutex mLock;
+
+    const sp<Looper> mLooper;
+    const std::thread::id mThreadId;
+};
+
+
+static thread_local Choreographer* gChoreographer;
+Choreographer* Choreographer::getForThread() {
+    if (gChoreographer == nullptr) {
+        sp<Looper> looper = Looper::getForThread();
+        if (!looper.get()) {
+            ALOGW("No looper prepared for thread");
+            return nullptr;
+        }
+        gChoreographer = new Choreographer(looper);
+        status_t result = gChoreographer->initialize();
+        if (result != OK) {
+            ALOGW("Failed to initialize");
+            return nullptr;
+        }
+    }
+    return gChoreographer;
+}
+
+Choreographer::Choreographer(const sp<Looper>& looper) :
+    DisplayEventDispatcher(looper), mLooper(looper), mThreadId(std::this_thread::get_id()) {
+}
+
+void Choreographer::postFrameCallback(AChoreographer_frameCallback cb, void* data) {
+    postFrameCallbackDelayed(cb, data, 0);
+}
+
+void Choreographer::postFrameCallbackDelayed(
+        AChoreographer_frameCallback cb, void* data, nsecs_t delay) {
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    FrameCallback callback{cb, data, now + delay};
+    {
+        AutoMutex _l{mLock};
+        mCallbacks.push(callback);
+    }
+    if (callback.dueTime <= now) {
+        if (std::this_thread::get_id() != mThreadId) {
+            Message m{MSG_SCHEDULE_VSYNC};
+            mLooper->sendMessage(this, m);
+        } else {
+            scheduleVsync();
+        }
+    } else {
+        Message m{MSG_SCHEDULE_CALLBACKS};
+        mLooper->sendMessageDelayed(delay, this, m);
+    }
+}
+
+void Choreographer::scheduleCallbacks() {
+    AutoMutex _{mLock};
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    if (mCallbacks.top().dueTime <= now) {
+        ALOGV("choreographer %p ~ scheduling vsync", this);
+        scheduleVsync();
+        return;
+    }
+}
+
+
+void Choreographer::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t) {
+    if (id != ISurfaceComposer::eDisplayIdMain) {
+        ALOGV("choreographer %p ~ ignoring vsync signal for non-main display (id=%d)", this, id);
+        scheduleVsync();
+        return;
+    }
+    std::vector<FrameCallback> callbacks{};
+    {
+        AutoMutex _l{mLock};
+        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+        while (!mCallbacks.empty() && mCallbacks.top().dueTime < now) {
+            callbacks.push_back(mCallbacks.top());
+            mCallbacks.pop();
+        }
+    }
+    for (const auto& cb : callbacks) {
+        cb.callback(timestamp, cb.data);
+    }
+}
+
+void Choreographer::dispatchHotplug(nsecs_t, int32_t id, bool connected) {
+    ALOGV("choreographer %p ~ received hotplug event (id=%" PRId32 ", connected=%s), ignoring.",
+            this, id, toString(connected));
+}
+
+void Choreographer::handleMessage(const Message& message) {
+    switch (message.what) {
+    case MSG_SCHEDULE_CALLBACKS:
+        scheduleCallbacks();
+        break;
+    case MSG_SCHEDULE_VSYNC:
+        scheduleVsync();
+        break;
+    }
+}
+
+}
+
+/* Glue for the NDK interface */
+
+using android::Choreographer;
+
+static inline Choreographer* AChoreographer_to_Choreographer(AChoreographer* choreographer) {
+    return reinterpret_cast<Choreographer*>(choreographer);
+}
+
+static inline AChoreographer* Choreographer_to_AChoreographer(Choreographer* choreographer) {
+    return reinterpret_cast<AChoreographer*>(choreographer);
+}
+
+AChoreographer* AChoreographer_getInstance() {
+    return Choreographer_to_AChoreographer(Choreographer::getForThread());
+}
+
+void AChoreographer_postFrameCallback(AChoreographer* choreographer,
+        AChoreographer_frameCallback callback, void* data) {
+    AChoreographer_to_Choreographer(choreographer)->postFrameCallback(callback, data);
+}
+void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
+        AChoreographer_frameCallback callback, void* data, long delayMillis) {
+    AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
+            callback, data, ms2ns(delayMillis));
+}
diff --git a/opengl/java/android/opengl/GLES31.java b/opengl/java/android/opengl/GLES31.java
index 805930e..679108f 100644
--- a/opengl/java/android/opengl/GLES31.java
+++ b/opengl/java/android/opengl/GLES31.java
@@ -204,7 +204,8 @@
         _nativeClassInit();
     }
 
-    private GLES31() {}
+    /** @hide */
+    GLES31() {}
     // C function void glDispatchCompute ( GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z )
 
     public static native void glDispatchCompute(
diff --git a/opengl/java/android/opengl/GLES32.java b/opengl/java/android/opengl/GLES32.java
new file mode 100644
index 0000000..7a392b8
--- /dev/null
+++ b/opengl/java/android/opengl/GLES32.java
@@ -0,0 +1,785 @@
+/*
+ * 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.
+ */
+
+// This source file is automatically generated
+
+package android.opengl;
+
+/** OpenGL ES 3.2
+ */
+public class GLES32 extends GLES31 {
+
+    public static final int GL_CONTEXT_FLAG_DEBUG_BIT                          = 0x00000002;
+
+    public static final int GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT                  = 0x00000004;
+
+    public static final int GL_GEOMETRY_SHADER_BIT                             = 0x00000004;
+    public static final int GL_TESS_CONTROL_SHADER_BIT                         = 0x00000008;
+    public static final int GL_TESS_EVALUATION_SHADER_BIT                      = 0x00000010;
+
+    public static final int GL_QUADS                                           = 0x0007;
+    public static final int GL_LINES_ADJACENCY                                 = 0x000A;
+    public static final int GL_LINE_STRIP_ADJACENCY                            = 0x000B;
+    public static final int GL_TRIANGLES_ADJACENCY                             = 0x000C;
+    public static final int GL_TRIANGLE_STRIP_ADJACENCY                        = 0x000D;
+    public static final int GL_PATCHES                                         = 0x000E;
+    public static final int GL_STACK_OVERFLOW                                  = 0x0503;
+    public static final int GL_STACK_UNDERFLOW                                 = 0x0504;
+    public static final int GL_CONTEXT_LOST                                    = 0x0507;
+    public static final int GL_TEXTURE_BORDER_COLOR                            = 0x1004;
+    public static final int GL_VERTEX_ARRAY                                    = 0x8074;
+    public static final int GL_CLAMP_TO_BORDER                                 = 0x812D;
+    public static final int GL_CONTEXT_FLAGS                                   = 0x821E;
+    public static final int GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED         = 0x8221;
+    public static final int GL_DEBUG_OUTPUT_SYNCHRONOUS                        = 0x8242;
+    public static final int GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH                = 0x8243;
+    public static final int GL_DEBUG_CALLBACK_FUNCTION                         = 0x8244;
+    public static final int GL_DEBUG_CALLBACK_USER_PARAM                       = 0x8245;
+    public static final int GL_DEBUG_SOURCE_API                                = 0x8246;
+    public static final int GL_DEBUG_SOURCE_WINDOW_SYSTEM                      = 0x8247;
+    public static final int GL_DEBUG_SOURCE_SHADER_COMPILER                    = 0x8248;
+    public static final int GL_DEBUG_SOURCE_THIRD_PARTY                        = 0x8249;
+    public static final int GL_DEBUG_SOURCE_APPLICATION                        = 0x824A;
+    public static final int GL_DEBUG_SOURCE_OTHER                              = 0x824B;
+    public static final int GL_DEBUG_TYPE_ERROR                                = 0x824C;
+    public static final int GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR                  = 0x824D;
+    public static final int GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR                   = 0x824E;
+    public static final int GL_DEBUG_TYPE_PORTABILITY                          = 0x824F;
+    public static final int GL_DEBUG_TYPE_PERFORMANCE                          = 0x8250;
+    public static final int GL_DEBUG_TYPE_OTHER                                = 0x8251;
+    public static final int GL_LOSE_CONTEXT_ON_RESET                           = 0x8252;
+    public static final int GL_GUILTY_CONTEXT_RESET                            = 0x8253;
+    public static final int GL_INNOCENT_CONTEXT_RESET                          = 0x8254;
+    public static final int GL_UNKNOWN_CONTEXT_RESET                           = 0x8255;
+    public static final int GL_RESET_NOTIFICATION_STRATEGY                     = 0x8256;
+    public static final int GL_LAYER_PROVOKING_VERTEX                          = 0x825E;
+    public static final int GL_UNDEFINED_VERTEX                                = 0x8260;
+    public static final int GL_NO_RESET_NOTIFICATION                           = 0x8261;
+    public static final int GL_DEBUG_TYPE_MARKER                               = 0x8268;
+    public static final int GL_DEBUG_TYPE_PUSH_GROUP                           = 0x8269;
+    public static final int GL_DEBUG_TYPE_POP_GROUP                            = 0x826A;
+    public static final int GL_DEBUG_SEVERITY_NOTIFICATION                     = 0x826B;
+    public static final int GL_MAX_DEBUG_GROUP_STACK_DEPTH                     = 0x826C;
+    public static final int GL_DEBUG_GROUP_STACK_DEPTH                         = 0x826D;
+    public static final int GL_BUFFER                                          = 0x82E0;
+    public static final int GL_SHADER                                          = 0x82E1;
+    public static final int GL_PROGRAM                                         = 0x82E2;
+    public static final int GL_QUERY                                           = 0x82E3;
+    public static final int GL_PROGRAM_PIPELINE                                = 0x82E4;
+    public static final int GL_SAMPLER                                         = 0x82E6;
+    public static final int GL_MAX_LABEL_LENGTH                                = 0x82E8;
+    public static final int GL_MAX_TESS_CONTROL_INPUT_COMPONENTS               = 0x886C;
+    public static final int GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS            = 0x886D;
+    public static final int GL_GEOMETRY_SHADER_INVOCATIONS                     = 0x887F;
+    public static final int GL_GEOMETRY_VERTICES_OUT                           = 0x8916;
+    public static final int GL_GEOMETRY_INPUT_TYPE                             = 0x8917;
+    public static final int GL_GEOMETRY_OUTPUT_TYPE                            = 0x8918;
+    public static final int GL_MAX_GEOMETRY_UNIFORM_BLOCKS                     = 0x8A2C;
+    public static final int GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS        = 0x8A32;
+    public static final int GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS                = 0x8C29;
+    public static final int GL_TEXTURE_BUFFER                                  = 0x8C2A;
+    public static final int GL_TEXTURE_BUFFER_BINDING                          = 0x8C2A;
+    public static final int GL_MAX_TEXTURE_BUFFER_SIZE                         = 0x8C2B;
+    public static final int GL_TEXTURE_BINDING_BUFFER                          = 0x8C2C;
+    public static final int GL_TEXTURE_BUFFER_DATA_STORE_BINDING               = 0x8C2D;
+    public static final int GL_SAMPLE_SHADING                                  = 0x8C36;
+    public static final int GL_MIN_SAMPLE_SHADING_VALUE                        = 0x8C37;
+    public static final int GL_PRIMITIVES_GENERATED                            = 0x8C87;
+    public static final int GL_FRAMEBUFFER_ATTACHMENT_LAYERED                  = 0x8DA7;
+    public static final int GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS            = 0x8DA8;
+    public static final int GL_SAMPLER_BUFFER                                  = 0x8DC2;
+    public static final int GL_INT_SAMPLER_BUFFER                              = 0x8DD0;
+    public static final int GL_UNSIGNED_INT_SAMPLER_BUFFER                     = 0x8DD8;
+    public static final int GL_GEOMETRY_SHADER                                 = 0x8DD9;
+    public static final int GL_MAX_GEOMETRY_UNIFORM_COMPONENTS                 = 0x8DDF;
+    public static final int GL_MAX_GEOMETRY_OUTPUT_VERTICES                    = 0x8DE0;
+    public static final int GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS            = 0x8DE1;
+    public static final int GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS    = 0x8E1E;
+    public static final int GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS = 0x8E1F;
+    public static final int GL_FIRST_VERTEX_CONVENTION                         = 0x8E4D;
+    public static final int GL_LAST_VERTEX_CONVENTION                          = 0x8E4E;
+    public static final int GL_MAX_GEOMETRY_SHADER_INVOCATIONS                 = 0x8E5A;
+    public static final int GL_MIN_FRAGMENT_INTERPOLATION_OFFSET               = 0x8E5B;
+    public static final int GL_MAX_FRAGMENT_INTERPOLATION_OFFSET               = 0x8E5C;
+    public static final int GL_FRAGMENT_INTERPOLATION_OFFSET_BITS              = 0x8E5D;
+    public static final int GL_PATCH_VERTICES                                  = 0x8E72;
+    public static final int GL_TESS_CONTROL_OUTPUT_VERTICES                    = 0x8E75;
+    public static final int GL_TESS_GEN_MODE                                   = 0x8E76;
+    public static final int GL_TESS_GEN_SPACING                                = 0x8E77;
+    public static final int GL_TESS_GEN_VERTEX_ORDER                           = 0x8E78;
+    public static final int GL_TESS_GEN_POINT_MODE                             = 0x8E79;
+    public static final int GL_ISOLINES                                        = 0x8E7A;
+    public static final int GL_FRACTIONAL_ODD                                  = 0x8E7B;
+    public static final int GL_FRACTIONAL_EVEN                                 = 0x8E7C;
+    public static final int GL_MAX_PATCH_VERTICES                              = 0x8E7D;
+    public static final int GL_MAX_TESS_GEN_LEVEL                              = 0x8E7E;
+    public static final int GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS             = 0x8E7F;
+    public static final int GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS          = 0x8E80;
+    public static final int GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS            = 0x8E81;
+    public static final int GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS         = 0x8E82;
+    public static final int GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS              = 0x8E83;
+    public static final int GL_MAX_TESS_PATCH_COMPONENTS                       = 0x8E84;
+    public static final int GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS        = 0x8E85;
+    public static final int GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS           = 0x8E86;
+    public static final int GL_TESS_EVALUATION_SHADER                          = 0x8E87;
+    public static final int GL_TESS_CONTROL_SHADER                             = 0x8E88;
+    public static final int GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS                 = 0x8E89;
+    public static final int GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS              = 0x8E8A;
+    public static final int GL_TEXTURE_CUBE_MAP_ARRAY                          = 0x9009;
+    public static final int GL_TEXTURE_BINDING_CUBE_MAP_ARRAY                  = 0x900A;
+    public static final int GL_SAMPLER_CUBE_MAP_ARRAY                          = 0x900C;
+    public static final int GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW                   = 0x900D;
+    public static final int GL_INT_SAMPLER_CUBE_MAP_ARRAY                      = 0x900E;
+    public static final int GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY             = 0x900F;
+    public static final int GL_IMAGE_BUFFER                                    = 0x9051;
+    public static final int GL_IMAGE_CUBE_MAP_ARRAY                            = 0x9054;
+    public static final int GL_INT_IMAGE_BUFFER                                = 0x905C;
+    public static final int GL_INT_IMAGE_CUBE_MAP_ARRAY                        = 0x905F;
+    public static final int GL_UNSIGNED_INT_IMAGE_BUFFER                       = 0x9067;
+    public static final int GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY               = 0x906A;
+    public static final int GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS                 = 0x90CB;
+    public static final int GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS              = 0x90CC;
+    public static final int GL_MAX_GEOMETRY_IMAGE_UNIFORMS                     = 0x90CD;
+    public static final int GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS              = 0x90D7;
+    public static final int GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS          = 0x90D8;
+    public static final int GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS       = 0x90D9;
+    public static final int GL_TEXTURE_2D_MULTISAMPLE_ARRAY                    = 0x9102;
+    public static final int GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY            = 0x9105;
+    public static final int GL_SAMPLER_2D_MULTISAMPLE_ARRAY                    = 0x910B;
+    public static final int GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY                = 0x910C;
+    public static final int GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY       = 0x910D;
+    public static final int GL_MAX_GEOMETRY_INPUT_COMPONENTS                   = 0x9123;
+    public static final int GL_MAX_GEOMETRY_OUTPUT_COMPONENTS                  = 0x9124;
+    public static final int GL_MAX_DEBUG_MESSAGE_LENGTH                        = 0x9143;
+    public static final int GL_MAX_DEBUG_LOGGED_MESSAGES                       = 0x9144;
+    public static final int GL_DEBUG_LOGGED_MESSAGES                           = 0x9145;
+    public static final int GL_DEBUG_SEVERITY_HIGH                             = 0x9146;
+    public static final int GL_DEBUG_SEVERITY_MEDIUM                           = 0x9147;
+    public static final int GL_DEBUG_SEVERITY_LOW                              = 0x9148;
+    public static final int GL_TEXTURE_BUFFER_OFFSET                           = 0x919D;
+    public static final int GL_TEXTURE_BUFFER_SIZE                             = 0x919E;
+    public static final int GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT                 = 0x919F;
+    public static final int GL_MULTIPLY                                        = 0x9294;
+    public static final int GL_SCREEN                                          = 0x9295;
+    public static final int GL_OVERLAY                                         = 0x9296;
+    public static final int GL_DARKEN                                          = 0x9297;
+    public static final int GL_LIGHTEN                                         = 0x9298;
+    public static final int GL_COLORDODGE                                      = 0x9299;
+    public static final int GL_COLORBURN                                       = 0x929A;
+    public static final int GL_HARDLIGHT                                       = 0x929B;
+    public static final int GL_SOFTLIGHT                                       = 0x929C;
+    public static final int GL_DIFFERENCE                                      = 0x929E;
+    public static final int GL_EXCLUSION                                       = 0x92A0;
+    public static final int GL_HSL_HUE                                         = 0x92AD;
+    public static final int GL_HSL_SATURATION                                  = 0x92AE;
+    public static final int GL_HSL_COLOR                                       = 0x92AF;
+    public static final int GL_HSL_LUMINOSITY                                  = 0x92B0;
+    public static final int GL_PRIMITIVE_BOUNDING_BOX                          = 0x92BE;
+    public static final int GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS         = 0x92CD;
+    public static final int GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS      = 0x92CE;
+    public static final int GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS             = 0x92CF;
+    public static final int GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS                = 0x92D3;
+    public static final int GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS             = 0x92D4;
+    public static final int GL_MAX_GEOMETRY_ATOMIC_COUNTERS                    = 0x92D5;
+    public static final int GL_DEBUG_OUTPUT                                    = 0x92E0;
+    public static final int GL_IS_PER_PATCH                                    = 0x92E7;
+    public static final int GL_REFERENCED_BY_TESS_CONTROL_SHADER               = 0x9307;
+    public static final int GL_REFERENCED_BY_TESS_EVALUATION_SHADER            = 0x9308;
+    public static final int GL_REFERENCED_BY_GEOMETRY_SHADER                   = 0x9309;
+    public static final int GL_FRAMEBUFFER_DEFAULT_LAYERS                      = 0x9312;
+    public static final int GL_MAX_FRAMEBUFFER_LAYERS                          = 0x9317;
+    public static final int GL_MULTISAMPLE_LINE_WIDTH_RANGE                    = 0x9381;
+    public static final int GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY              = 0x9382;
+    public static final int GL_COMPRESSED_RGBA_ASTC_4x4                        = 0x93B0;
+    public static final int GL_COMPRESSED_RGBA_ASTC_5x4                        = 0x93B1;
+    public static final int GL_COMPRESSED_RGBA_ASTC_5x5                        = 0x93B2;
+    public static final int GL_COMPRESSED_RGBA_ASTC_6x5                        = 0x93B3;
+    public static final int GL_COMPRESSED_RGBA_ASTC_6x6                        = 0x93B4;
+    public static final int GL_COMPRESSED_RGBA_ASTC_8x5                        = 0x93B5;
+    public static final int GL_COMPRESSED_RGBA_ASTC_8x6                        = 0x93B6;
+    public static final int GL_COMPRESSED_RGBA_ASTC_8x8                        = 0x93B7;
+    public static final int GL_COMPRESSED_RGBA_ASTC_10x5                       = 0x93B8;
+    public static final int GL_COMPRESSED_RGBA_ASTC_10x6                       = 0x93B9;
+    public static final int GL_COMPRESSED_RGBA_ASTC_10x8                       = 0x93BA;
+    public static final int GL_COMPRESSED_RGBA_ASTC_10x10                      = 0x93BB;
+    public static final int GL_COMPRESSED_RGBA_ASTC_12x10                      = 0x93BC;
+    public static final int GL_COMPRESSED_RGBA_ASTC_12x12                      = 0x93BD;
+    public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4                = 0x93D0;
+    public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4                = 0x93D1;
+    public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5                = 0x93D2;
+    public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5                = 0x93D3;
+    public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6                = 0x93D4;
+    public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5                = 0x93D5;
+    public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6                = 0x93D6;
+    public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8                = 0x93D7;
+    public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5               = 0x93D8;
+    public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6               = 0x93D9;
+    public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8               = 0x93DA;
+    public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10              = 0x93DB;
+    public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10              = 0x93DC;
+    public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12              = 0x93DD;
+
+
+    native private static void _nativeClassInit();
+    static {
+        _nativeClassInit();
+    }
+
+    private GLES32() {}
+    // C function void glBlendBarrier ( void )
+
+    public static native void glBlendBarrier(
+    );
+
+    // C function void glCopyImageSubData ( GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth )
+
+    public static native void glCopyImageSubData(
+        int srcName,
+        int srcTarget,
+        int srcLevel,
+        int srcX,
+        int srcY,
+        int srcZ,
+        int dstName,
+        int dstTarget,
+        int dstLevel,
+        int dstX,
+        int dstY,
+        int dstZ,
+        int srcWidth,
+        int srcHeight,
+        int srcDepth
+    );
+
+    // C function void glDebugMessageControl ( GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled )
+
+    public static native void glDebugMessageControl(
+        int source,
+        int type,
+        int severity,
+        int count,
+        int[] ids,
+        int offset,
+        boolean enabled
+    );
+
+    // C function void glDebugMessageControl ( GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled )
+
+    public static native void glDebugMessageControl(
+        int source,
+        int type,
+        int severity,
+        int count,
+        java.nio.IntBuffer ids,
+        boolean enabled
+    );
+
+    // C function void glDebugMessageInsert ( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf )
+
+    public static native void glDebugMessageInsert(
+        int source,
+        int type,
+        int id,
+        int severity,
+        int length,
+        String buf
+    );
+
+    // C function void glDebugMessageCallback ( GLDEBUGPROC callback, const void *userParam )
+
+    public interface DebugProc {
+        void onMessage(int source, int type, int id, int severity, String message);
+    }
+
+    public static native void glDebugMessageCallback(DebugProc callback);
+
+    // C function GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog )
+
+    public static native int glGetDebugMessageLog(
+        int count,
+        int bufSize,
+        int[] sources,
+        int sourcesOffset,
+        int[] types,
+        int typesOffset,
+        int[] ids,
+        int idsOffset,
+        int[] severities,
+        int severitiesOffset,
+        int[] lengths,
+        int lengthsOffset,
+        byte[] messageLog,
+        int messageLogOffset);
+
+    // C function GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog )
+
+    public static native int glGetDebugMessageLog(
+        int count,
+        java.nio.IntBuffer sources,
+        java.nio.IntBuffer types,
+        java.nio.IntBuffer ids,
+        java.nio.IntBuffer severities,
+        java.nio.IntBuffer lengths,
+        java.nio.ByteBuffer messageLog);
+
+    // C function GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog )
+
+    public static native String[] glGetDebugMessageLog(
+        int count,
+        int[] sources,
+        int sourcesOffset,
+        int[] types,
+        int typesOffset,
+        int[] ids,
+        int idsOffset,
+        int[] severities,
+        int severitiesOffset);
+
+    // C function GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog )
+
+    public static native String[] glGetDebugMessageLog(
+        int count,
+        java.nio.IntBuffer sources,
+        java.nio.IntBuffer types,
+        java.nio.IntBuffer ids,
+        java.nio.IntBuffer severities);
+
+    // C function void glPushDebugGroup ( GLenum source, GLuint id, GLsizei length, const GLchar *message )
+
+    public static native void glPushDebugGroup(
+        int source,
+        int id,
+        int length,
+        String message
+    );
+
+    // C function void glPopDebugGroup ( void )
+
+    public static native void glPopDebugGroup(
+    );
+
+    // C function void glObjectLabel ( GLenum identifier, GLuint name, GLsizei length, const GLchar *label )
+
+    public static native void glObjectLabel(
+        int identifier,
+        int name,
+        int length,
+        String label
+    );
+
+    // C function void glGetObjectLabel ( GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label )
+
+    public static native String glGetObjectLabel(int identifier, int name);
+
+    // C function void glObjectPtrLabel ( const void *ptr, GLsizei length, const GLchar *label )
+
+    public static native void glObjectPtrLabel(long ptr, String label);
+
+    // C function void glGetObjectPtrLabel ( const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label )
+
+    public static native String glGetObjectPtrLabel(long ptr);
+
+    // C function void glGetPointerv ( GLenum pname, void **params )
+
+    public static native long glGetPointerv(
+        int pname
+    );
+
+    // C function void glEnablei ( GLenum target, GLuint index )
+
+    public static native void glEnablei(
+        int target,
+        int index
+    );
+
+    // C function void glDisablei ( GLenum target, GLuint index )
+
+    public static native void glDisablei(
+        int target,
+        int index
+    );
+
+    // C function void glBlendEquationi ( GLuint buf, GLenum mode )
+
+    public static native void glBlendEquationi(
+        int buf,
+        int mode
+    );
+
+    // C function void glBlendEquationSeparatei ( GLuint buf, GLenum modeRGB, GLenum modeAlpha )
+
+    public static native void glBlendEquationSeparatei(
+        int buf,
+        int modeRGB,
+        int modeAlpha
+    );
+
+    // C function void glBlendFunci ( GLuint buf, GLenum src, GLenum dst )
+
+    public static native void glBlendFunci(
+        int buf,
+        int src,
+        int dst
+    );
+
+    // C function void glBlendFuncSeparatei ( GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha )
+
+    public static native void glBlendFuncSeparatei(
+        int buf,
+        int srcRGB,
+        int dstRGB,
+        int srcAlpha,
+        int dstAlpha
+    );
+
+    // C function void glColorMaski ( GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a )
+
+    public static native void glColorMaski(
+        int index,
+        boolean r,
+        boolean g,
+        boolean b,
+        boolean a
+    );
+
+    // C function GLboolean glIsEnabledi ( GLenum target, GLuint index )
+
+    public static native boolean glIsEnabledi(
+        int target,
+        int index
+    );
+
+    // C function void glDrawElementsBaseVertex ( GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex )
+
+    public static native void glDrawElementsBaseVertex(
+        int mode,
+        int count,
+        int type,
+        java.nio.Buffer indices,
+        int basevertex
+    );
+
+    // C function void glDrawRangeElementsBaseVertex ( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex )
+
+    public static native void glDrawRangeElementsBaseVertex(
+        int mode,
+        int start,
+        int end,
+        int count,
+        int type,
+        java.nio.Buffer indices,
+        int basevertex
+    );
+
+    // C function void glDrawElementsInstancedBaseVertex ( GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount, GLint basevertex )
+
+    public static native void glDrawElementsInstancedBaseVertex(
+        int mode,
+        int count,
+        int type,
+        java.nio.Buffer indices,
+        int instanceCount,
+        int basevertex
+    );
+
+    // C function void glDrawElementsInstancedBaseVertex ( GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount, GLint basevertex )
+
+    public static native void glDrawElementsInstancedBaseVertex(
+        int mode,
+        int count,
+        int type,
+        int indicesOffset,
+        int instanceCount,
+        int basevertex
+    );
+
+    // C function void glFramebufferTexture ( GLenum target, GLenum attachment, GLuint texture, GLint level )
+
+    public static native void glFramebufferTexture(
+        int target,
+        int attachment,
+        int texture,
+        int level
+    );
+
+    // C function void glPrimitiveBoundingBox ( GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW )
+
+    public static native void glPrimitiveBoundingBox(
+        float minX,
+        float minY,
+        float minZ,
+        float minW,
+        float maxX,
+        float maxY,
+        float maxZ,
+        float maxW
+    );
+
+    // C function GLenum glGetGraphicsResetStatus ( void )
+
+    public static native int glGetGraphicsResetStatus(
+    );
+
+    // C function void glReadnPixels ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data )
+
+    public static native void glReadnPixels(
+        int x,
+        int y,
+        int width,
+        int height,
+        int format,
+        int type,
+        int bufSize,
+        java.nio.Buffer data
+    );
+
+    // C function void glGetnUniformfv ( GLuint program, GLint location, GLsizei bufSize, GLfloat *params )
+
+    public static native void glGetnUniformfv(
+        int program,
+        int location,
+        int bufSize,
+        float[] params,
+        int offset
+    );
+
+    // C function void glGetnUniformfv ( GLuint program, GLint location, GLsizei bufSize, GLfloat *params )
+
+    public static native void glGetnUniformfv(
+        int program,
+        int location,
+        int bufSize,
+        java.nio.FloatBuffer params
+    );
+
+    // C function void glGetnUniformiv ( GLuint program, GLint location, GLsizei bufSize, GLint *params )
+
+    public static native void glGetnUniformiv(
+        int program,
+        int location,
+        int bufSize,
+        int[] params,
+        int offset
+    );
+
+    // C function void glGetnUniformiv ( GLuint program, GLint location, GLsizei bufSize, GLint *params )
+
+    public static native void glGetnUniformiv(
+        int program,
+        int location,
+        int bufSize,
+        java.nio.IntBuffer params
+    );
+
+    // C function void glGetnUniformuiv ( GLuint program, GLint location, GLsizei bufSize, GLuint *params )
+
+    public static native void glGetnUniformuiv(
+        int program,
+        int location,
+        int bufSize,
+        int[] params,
+        int offset
+    );
+
+    // C function void glGetnUniformuiv ( GLuint program, GLint location, GLsizei bufSize, GLuint *params )
+
+    public static native void glGetnUniformuiv(
+        int program,
+        int location,
+        int bufSize,
+        java.nio.IntBuffer params
+    );
+
+    // C function void glMinSampleShading ( GLfloat value )
+
+    public static native void glMinSampleShading(
+        float value
+    );
+
+    // C function void glPatchParameteri ( GLenum pname, GLint value )
+
+    public static native void glPatchParameteri(
+        int pname,
+        int value
+    );
+
+    // C function void glTexParameterIiv ( GLenum target, GLenum pname, const GLint *params )
+
+    public static native void glTexParameterIiv(
+        int target,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    // C function void glTexParameterIiv ( GLenum target, GLenum pname, const GLint *params )
+
+    public static native void glTexParameterIiv(
+        int target,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    // C function void glTexParameterIuiv ( GLenum target, GLenum pname, const GLuint *params )
+
+    public static native void glTexParameterIuiv(
+        int target,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    // C function void glTexParameterIuiv ( GLenum target, GLenum pname, const GLuint *params )
+
+    public static native void glTexParameterIuiv(
+        int target,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    // C function void glGetTexParameterIiv ( GLenum target, GLenum pname, GLint *params )
+
+    public static native void glGetTexParameterIiv(
+        int target,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    // C function void glGetTexParameterIiv ( GLenum target, GLenum pname, GLint *params )
+
+    public static native void glGetTexParameterIiv(
+        int target,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    // C function void glGetTexParameterIuiv ( GLenum target, GLenum pname, GLuint *params )
+
+    public static native void glGetTexParameterIuiv(
+        int target,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    // C function void glGetTexParameterIuiv ( GLenum target, GLenum pname, GLuint *params )
+
+    public static native void glGetTexParameterIuiv(
+        int target,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    // C function void glSamplerParameterIiv ( GLuint sampler, GLenum pname, const GLint *param )
+
+    public static native void glSamplerParameterIiv(
+        int sampler,
+        int pname,
+        int[] param,
+        int offset
+    );
+
+    // C function void glSamplerParameterIiv ( GLuint sampler, GLenum pname, const GLint *param )
+
+    public static native void glSamplerParameterIiv(
+        int sampler,
+        int pname,
+        java.nio.IntBuffer param
+    );
+
+    // C function void glSamplerParameterIuiv ( GLuint sampler, GLenum pname, const GLuint *param )
+
+    public static native void glSamplerParameterIuiv(
+        int sampler,
+        int pname,
+        int[] param,
+        int offset
+    );
+
+    // C function void glSamplerParameterIuiv ( GLuint sampler, GLenum pname, const GLuint *param )
+
+    public static native void glSamplerParameterIuiv(
+        int sampler,
+        int pname,
+        java.nio.IntBuffer param
+    );
+
+    // C function void glGetSamplerParameterIiv ( GLuint sampler, GLenum pname, GLint *params )
+
+    public static native void glGetSamplerParameterIiv(
+        int sampler,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    // C function void glGetSamplerParameterIiv ( GLuint sampler, GLenum pname, GLint *params )
+
+    public static native void glGetSamplerParameterIiv(
+        int sampler,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    // C function void glGetSamplerParameterIuiv ( GLuint sampler, GLenum pname, GLuint *params )
+
+    public static native void glGetSamplerParameterIuiv(
+        int sampler,
+        int pname,
+        int[] params,
+        int offset
+    );
+
+    // C function void glGetSamplerParameterIuiv ( GLuint sampler, GLenum pname, GLuint *params )
+
+    public static native void glGetSamplerParameterIuiv(
+        int sampler,
+        int pname,
+        java.nio.IntBuffer params
+    );
+
+    // C function void glTexBuffer ( GLenum target, GLenum internalformat, GLuint buffer )
+
+    public static native void glTexBuffer(
+        int target,
+        int internalformat,
+        int buffer
+    );
+
+    // C function void glTexBufferRange ( GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size )
+
+    public static native void glTexBufferRange(
+        int target,
+        int internalformat,
+        int buffer,
+        int offset,
+        int size
+    );
+
+    // C function void glTexStorage3DMultisample ( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations )
+
+    public static native void glTexStorage3DMultisample(
+        int target,
+        int samples,
+        int internalformat,
+        int width,
+        int height,
+        int depth,
+        boolean fixedsamplelocations
+    );
+
+}
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 359a7a9..f37ec58 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -161,7 +161,7 @@
  * </pre>
  *
  */
-public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
+public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback2 {
     private final static String TAG = "GLSurfaceView";
     private final static boolean LOG_ATTACH_DETACH = false;
     private final static boolean LOG_THREADS = false;
@@ -542,6 +542,16 @@
     }
 
     /**
+     * This method is part of the SurfaceHolder.Callback interface, and is
+     * not normally called or subclassed by clients of GLSurfaceView.
+     */
+    @Override
+    public void surfaceRedrawNeeded(SurfaceHolder holder) {
+        mGLThread.requestRenderAndWait();
+    }
+
+
+    /**
      * Inform the view that the activity is paused. The owner of this view must
      * call this method when the activity is paused. Calling this method will
      * pause the rendering thread.
@@ -1226,6 +1236,7 @@
             mHeight = 0;
             mRequestRender = true;
             mRenderMode = RENDERMODE_CONTINUOUSLY;
+            mWantRenderNotification = false;
             mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;
         }
 
@@ -1271,6 +1282,8 @@
             mEglHelper = new EglHelper(mGLSurfaceViewWeakRef);
             mHaveEglContext = false;
             mHaveEglSurface = false;
+            mWantRenderNotification = false;
+
             try {
                 GL10 gl = null;
                 boolean createEglContext = false;
@@ -1383,7 +1396,7 @@
                                 if (LOG_SURFACE) {
                                     Log.i("GLThread", "sending render notification tid=" + getId());
                                 }
-                                wantRenderNotification = false;
+                                mWantRenderNotification = false;
                                 doRenderNotification = false;
                                 mRenderComplete = true;
                                 sGLThreadManager.notifyAll();
@@ -1422,7 +1435,7 @@
                                         sizeChanged = true;
                                         w = mWidth;
                                         h = mHeight;
-                                        wantRenderNotification = true;
+                                        mWantRenderNotification = true;
                                         if (LOG_SURFACE) {
                                             Log.i("GLThread",
                                                     "noticing that we want render notification tid="
@@ -1436,6 +1449,9 @@
                                     }
                                     mRequestRender = false;
                                     sGLThreadManager.notifyAll();
+                                    if (mWantRenderNotification) {
+                                        wantRenderNotification = true;
+                                    }
                                     break;
                                 }
                             }
@@ -1564,6 +1580,7 @@
 
                     if (wantRenderNotification) {
                         doRenderNotification = true;
+                        wantRenderNotification = false;
                     }
                 }
 
@@ -1611,6 +1628,33 @@
             }
         }
 
+        public void requestRenderAndWait() {
+            synchronized(sGLThreadManager) {
+                // If we are already on the GL thread, this means a client callback
+                // has caused reentrancy, for example via updating the SurfaceView parameters.
+                // We will return to the client rendering code, so here we don't need to
+                // do anything.
+                if (Thread.currentThread() == this) {
+                    return;
+                }
+
+                mWantRenderNotification = true;
+                mRequestRender = true;
+                mRenderComplete = false;
+
+                sGLThreadManager.notifyAll();
+
+                while (!mExited && !mPaused && !mRenderComplete && ableToDraw()) {
+                    try {
+                        sGLThreadManager.wait();
+                    } catch (InterruptedException ex) {
+                        Thread.currentThread().interrupt();
+                    }
+                }
+
+            }
+        }
+
         public void surfaceCreated() {
             synchronized(sGLThreadManager) {
                 if (LOG_THREADS) {
@@ -1697,6 +1741,16 @@
                 mSizeChanged = true;
                 mRequestRender = true;
                 mRenderComplete = false;
+
+                // If we are already on the GL thread, this means a client callback
+                // has caused reentrancy, for example via updating the SurfaceView parameters.
+                // We need to process the size change eventually though and update our EGLSurface.
+                // So we set the parameters and return so they can be processed on our
+                // next iteration.
+                if (Thread.currentThread() == this) {
+                    return;
+                }
+
                 sGLThreadManager.notifyAll();
 
                 // Wait for thread to react to resize and render a frame
@@ -1766,6 +1820,7 @@
         private int mHeight;
         private int mRenderMode;
         private boolean mRequestRender;
+        private boolean mWantRenderNotification;
         private boolean mRenderComplete;
         private ArrayList<Runnable> mEventQueue = new ArrayList<Runnable>();
         private boolean mSizeChanged = true;
diff --git a/packages/BackupRestoreConfirmation/res/values-de/strings.xml b/packages/BackupRestoreConfirmation/res/values-de/strings.xml
index a2e24e7..55940c8 100644
--- a/packages/BackupRestoreConfirmation/res/values-de/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-de/strings.xml
@@ -18,19 +18,19 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Vollständige Sicherung"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Vollständige Wiederherstellung"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Es wurde eine vollständige Sicherung sämtlicher Daten auf einen verbundenen Desktop-Computer angefordert. Möchten Sie dies zulassen?\n\nWenn Sie die Sicherung nicht selbst angefordert haben, sollten Sie dem Vorgang nicht zustimmen."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Es wurde eine vollständige Sicherung sämtlicher Daten auf einen verbundenen Desktop-Computer angefordert. Möchtest du dies zulassen?\n\nWenn du die Sicherung nicht selbst angefordert hast, solltest du dem Vorgang nicht zustimmen."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Meine Daten sichern"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Nicht sichern"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Es wurde eine vollständige Wiederherstellung aller Daten von einem verbundenen Desktop-Computer angefordert. Möchten Sie dies zulassen?\n\nWenn Sie die Wiederherstellung nicht selbst angefordert haben, sollten Sie dem Vorgang nicht zustimmen. Dadurch werden alle zurzeit auf dem Gerät befindlichen Daten ersetzt!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Es wurde eine vollständige Wiederherstellung aller Daten von einem verbundenen Desktop-Computer angefordert. Möchtest du dies zulassen?\n\nWenn du die Wiederherstellung nicht selbst angefordert hast, solltest du dem Vorgang nicht zustimmen. Dadurch werden alle derzeit auf dem Gerät befindlichen Daten ersetzt!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Meine Daten wiederherstellen"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Nicht wiederherstellen"</string>
-    <string name="current_password_text" msgid="8268189555578298067">"Geben Sie Ihr aktuelles Sicherungspasswort unten ein:"</string>
-    <string name="device_encryption_restore_text" msgid="1570864916855208992">"Geben Sie Ihr Passwort zur Geräteverschlüsselung unten ein."</string>
-    <string name="device_encryption_backup_text" msgid="5866590762672844664">"Geben Sie Ihr Passwort zur Geräteverschlüsselung unten ein. Damit wird auch das Sicherungsarchiv verschlüsselt."</string>
-    <string name="backup_enc_password_text" msgid="4981585714795233099">"Geben Sie ein Passwort für die Verschlüsselung der vollständigen Sicherungsdaten ein. Wenn Sie dieses Feld leer lassen, wird Ihr aktuelles Sicherungspasswort verwendet:"</string>
-    <string name="backup_enc_password_optional" msgid="1350137345907579306">"Wenn Sie die gesamten Sicherungsdaten verschlüsseln möchten, geben Sie unten ein Passwort ein:"</string>
-    <string name="backup_enc_password_required" msgid="7889652203371654149">"Da Ihr Gerät verschlüsselt ist, muss auch die Sicherung verschlüsselt werden. Geben Sie unten ein Passwort ein:"</string>
-    <string name="restore_enc_password_text" msgid="6140898525580710823">"Geben Sie das Passwort unten ein, wenn die Daten für die Wiederherstellung verschlüsselt sind:"</string>
+    <string name="current_password_text" msgid="8268189555578298067">"Gib dein aktuelles Sicherungspasswort unten ein:"</string>
+    <string name="device_encryption_restore_text" msgid="1570864916855208992">"Gib dein Passwort zur Geräteverschlüsselung unten ein."</string>
+    <string name="device_encryption_backup_text" msgid="5866590762672844664">"Gib dein Passwort zur Geräteverschlüsselung unten ein. Damit wird auch das Sicherungsarchiv verschlüsselt."</string>
+    <string name="backup_enc_password_text" msgid="4981585714795233099">"Gib ein Passwort für die Verschlüsselung der vollständigen Sicherungsdaten ein. Wenn du dieses Feld leer lässt, wird dein aktuelles Sicherungspasswort verwendet:"</string>
+    <string name="backup_enc_password_optional" msgid="1350137345907579306">"Wenn du die gesamten Sicherungsdaten verschlüsseln möchtest, gib unten ein Passwort ein:"</string>
+    <string name="backup_enc_password_required" msgid="7889652203371654149">"Da dein Gerät verschlüsselt ist, muss auch die Sicherung verschlüsselt werden. Gib unten ein Passwort ein:"</string>
+    <string name="restore_enc_password_text" msgid="6140898525580710823">"Gib das Passwort unten ein, wenn die Daten für die Wiederherstellung verschlüsselt sind:"</string>
     <string name="toast_backup_started" msgid="550354281452756121">"Sicherung wird gestartet..."</string>
     <string name="toast_backup_ended" msgid="3818080769548726424">"Sicherung abgeschlossen"</string>
     <string name="toast_restore_started" msgid="7881679218971277385">"Wiederherstellung wird gestartet..."</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-zh-rCN/strings.xml b/packages/BackupRestoreConfirmation/res/values-zh-rCN/strings.xml
index ac20aed..23688ae 100644
--- a/packages/BackupRestoreConfirmation/res/values-zh-rCN/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-zh-rCN/strings.xml
@@ -18,10 +18,10 @@
     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如果您本人未要求备份,请阻止该操作。"</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"系统请求将所有数据完整备份至已连接的桌面设备。允许此操作吗?\n\n如果您本人未要求备份,请阻止该操作。"</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="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>
diff --git a/packages/CaptivePortalLogin/res/values-de/strings.xml b/packages/CaptivePortalLogin/res/values-de/strings.xml
index fd2058d..52c9dc8 100644
--- a/packages/CaptivePortalLogin/res/values-de/strings.xml
+++ b/packages/CaptivePortalLogin/res/values-de/strings.xml
@@ -5,7 +5,7 @@
     <string name="action_use_network" msgid="6076184727448466030">"Dieses Netzwerk im Istzustand verwenden"</string>
     <string name="action_do_not_use_network" msgid="4577366536956516683">"Dieses Netzwerk nicht verwenden"</string>
     <string name="action_bar_label" msgid="917235635415966620">"Im Netzwerk anmelden"</string>
-    <string name="ssl_error_warning" msgid="6653188881418638872">"Im Netzwerk, zu dem Sie eine Verbindung herstellen möchten, liegen Sicherheitsprobleme vor."</string>
+    <string name="ssl_error_warning" msgid="6653188881418638872">"Im Netzwerk, zu dem du eine Verbindung herstellen möchtest, liegen Sicherheitsprobleme vor."</string>
     <string name="ssl_error_example" msgid="647898534624078900">"Beispiel: Die Log-in-Seite gehört möglicherweise nicht zur angezeigten Organisation."</string>
     <string name="ssl_error_continue" msgid="6492718244923937110">"Trotzdem in einem Browser fortfahren"</string>
 </resources>
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index abb464e..6fb8b51 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -56,7 +56,6 @@
 
 public class CaptivePortalLoginActivity extends Activity {
     private static final String TAG = "CaptivePortalLogin";
-    private static final String DEFAULT_SERVER = "connectivitycheck.gstatic.com";
     private static final int SOCKET_TIMEOUT_MS = 10000;
 
     private enum Result { DISMISSED, UNWANTED, WANTED_AS_IS };
@@ -72,16 +71,14 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-
-        String server = Settings.Global.getString(getContentResolver(), "captive_portal_server");
-        if (server == null) server = DEFAULT_SERVER;
         mCm = ConnectivityManager.from(this);
         String url = getIntent().getStringExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL);
+        if (url == null) url = mCm.getCaptivePortalServerUrl();
         try {
-            mURL = url != null ? new URL(url) : new URL("http", server, "/generate_204");
+            mURL = new URL(url);
         } catch (MalformedURLException e) {
             // System misconfigured, bail out in a way that at least provides network access.
-            Log.e(TAG, "Invalid captive portal URL, server=" + server);
+            Log.e(TAG, "Invalid captive portal URL, url=" + url);
             done(Result.WANTED_AS_IS);
         }
         mNetwork = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_NETWORK);
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index 8cc79a4c..fa9ff01 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -40,7 +40,7 @@
 
         <activity
             android:name=".DownloadsActivity"
-            android:theme="@style/DocumentsFullScreenTheme"
+            android:theme="@style/DocumentsTheme"
             android:label="@string/downloads_label"
             android:icon="@drawable/ic_doc_text">
             <intent-filter>
@@ -54,8 +54,7 @@
             android:name=".LauncherActivity"
             android:theme="@android:style/Theme.NoDisplay"
             android:icon="@drawable/ic_files_app"
-            android:label="@string/files_label"
-            android:enabled="@bool/productivity_device">
+            android:label="@string/files_label">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
@@ -64,7 +63,7 @@
 
         <activity
             android:name=".FilesActivity"
-            android:theme="@style/DocumentsFullScreenTheme"
+            android:theme="@style/DocumentsTheme"
             android:icon="@drawable/ic_files_app"
             android:label="@string/files_label"
             android:documentLaunchMode="intoExisting">
@@ -78,6 +77,16 @@
             </intent-filter>
         </activity>
 
+        <activity
+            android:name=".OpenExternalDirectoryActivity"
+            android:theme="@android:style/Theme.Translucent.NoTitleBar">
+            <intent-filter>
+                <action android:name="android.intent.action.OPEN_EXTERNAL_DIRECTORY" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="file" />
+            </intent-filter>
+        </activity>
+
         <provider
             android:name=".RecentsProvider"
             android:authorities="com.android.documentsui.recents"
@@ -92,7 +101,7 @@
         </receiver>
 
         <service
-            android:name=".CopyService"
+            android:name=".services.FileOperationService"
             android:exported="false">
         </service>
     </application>
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album_alpha.png
deleted file mode 100644
index 2b21c12..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk_alpha.png
deleted file mode 100644
index ed3ee45..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_alpha.png
deleted file mode 100644
index 1a3ebc47..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate_alpha.png
deleted file mode 100644
index 3086a69..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes_alpha.png
deleted file mode 100644
index b86f0f7..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed_alpha.png
deleted file mode 100644
index 9d0988d..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am_alpha.png
deleted file mode 100644
index 6c31360..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am_alpha.png
deleted file mode 100644
index 1450ff0..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel_alpha.png
deleted file mode 100644
index 4ad54bb..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_folder_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_folder_alpha.png
deleted file mode 100644
index 7f7c636..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_folder_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font_alpha.png
deleted file mode 100644
index d867847..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am_alpha.png
deleted file mode 100644
index 5459767..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_alpha.png
deleted file mode 100644
index 0cbd992..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf_alpha.png
deleted file mode 100644
index db46702..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint_alpha.png
deleted file mode 100644
index b9f7af5..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation_alpha.png
deleted file mode 100644
index 1218c2f..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am_alpha.png
deleted file mode 100644
index 46d755f..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am_alpha.png
deleted file mode 100644
index 933570b..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_am_alpha.png
deleted file mode 100644
index 30cea25..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_word_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_word_alpha.png
deleted file mode 100644
index 67b60de..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_word_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_alpha.png
deleted file mode 100644
index 65e42aa..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album_alpha.png
deleted file mode 100644
index ac27eea..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk_alpha.png
deleted file mode 100644
index a4add51..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_alpha.png
deleted file mode 100644
index a9a7f20..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate_alpha.png
deleted file mode 100644
index 26beb79..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes_alpha.png
deleted file mode 100644
index ed9cab7..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed_alpha.png
deleted file mode 100644
index 451d287..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am_alpha.png
deleted file mode 100644
index 7bc02c9..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am_alpha.png
deleted file mode 100644
index de39cd4..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel_alpha.png
deleted file mode 100644
index c3eb845..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_folder_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_folder_alpha.png
deleted file mode 100644
index 97f6e507..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_folder_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font_alpha.png
deleted file mode 100644
index b2f043f..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am_alpha.png
deleted file mode 100644
index 483d7fb..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_alpha.png
deleted file mode 100644
index 2941b8a..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf_alpha.png
deleted file mode 100644
index d3ac072..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint_alpha.png
deleted file mode 100644
index a43f902..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation_alpha.png
deleted file mode 100644
index c572cd1..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am_alpha.png
deleted file mode 100644
index 7ae671b..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am_alpha.png
deleted file mode 100644
index a5ebd51..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_am_alpha.png
deleted file mode 100644
index 89ac434..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_word_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_word_alpha.png
deleted file mode 100644
index 855c44b..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_word_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_alpha.png
deleted file mode 100644
index 1de8292..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album_alpha.png
deleted file mode 100644
index 4203d35..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk_alpha.png
deleted file mode 100644
index 41558f2..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_alpha.png
deleted file mode 100644
index e190c4d..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate_alpha.png
deleted file mode 100644
index fabc8c3..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes_alpha.png
deleted file mode 100644
index d8ba6e0..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed_alpha.png
deleted file mode 100644
index 1b5111a..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am_alpha.png
deleted file mode 100644
index e7b7460..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am_alpha.png
deleted file mode 100644
index 3183bfc..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel_alpha.png
deleted file mode 100644
index 9a4e844..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_folder_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_folder_alpha.png
deleted file mode 100644
index 96d5721..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_folder_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font_alpha.png
deleted file mode 100644
index 23a1302..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am_alpha.png
deleted file mode 100644
index b0811f1..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_alpha.png
deleted file mode 100644
index 5f1f537..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf_alpha.png
deleted file mode 100644
index 8083584..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint_alpha.png
deleted file mode 100644
index 898e26a..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation_alpha.png
deleted file mode 100644
index 2e9c667..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am_alpha.png
deleted file mode 100644
index 56951c3..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am_alpha.png
deleted file mode 100644
index 08ed9f0..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_am_alpha.png
deleted file mode 100644
index cd64e56..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word_alpha.png
deleted file mode 100644
index 0bc40de..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_alpha.png
deleted file mode 100644
index 00b8a8b7..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album_alpha.png
deleted file mode 100644
index 60f59f5..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk_alpha.png
deleted file mode 100644
index 6006b12..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_alpha.png
deleted file mode 100644
index 7926188..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate_alpha.png
deleted file mode 100644
index e65d74c..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes_alpha.png
deleted file mode 100644
index 7d32801..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed_alpha.png
deleted file mode 100644
index d528708..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am_alpha.png
deleted file mode 100644
index 274c524..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am_alpha.png
deleted file mode 100644
index 6053b0a..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel_alpha.png
deleted file mode 100644
index 78ee13b..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_folder_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_folder_alpha.png
deleted file mode 100644
index dcf9cc2..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_folder_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font_alpha.png
deleted file mode 100644
index 74fbbbc..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am_alpha.png
deleted file mode 100644
index 11a219a..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_alpha.png
deleted file mode 100644
index 9a461c9..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf_alpha.png
deleted file mode 100644
index 9a67956..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint_alpha.png
deleted file mode 100644
index 853aa8c..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation_alpha.png
deleted file mode 100644
index 84ae9ae..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am_alpha.png
deleted file mode 100644
index 111439e..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am_alpha.png
deleted file mode 100644
index b876f86..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_am_alpha.png
deleted file mode 100644
index 7cf656a..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word_alpha.png
deleted file mode 100644
index acc3d7b..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_alpha.png
deleted file mode 100644
index 5236774..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_album_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_album_alpha.png
deleted file mode 100644
index d2dd494..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_album_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_apk_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_apk_alpha.png
deleted file mode 100644
index 4f935bf..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_apk_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_audio_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_audio_alpha.png
deleted file mode 100644
index 7499cbc..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_audio_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_certificate_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_certificate_alpha.png
deleted file mode 100644
index ca12928..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_certificate_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_codes_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_codes_alpha.png
deleted file mode 100644
index c4afa37..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_codes_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_compressed_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_compressed_alpha.png
deleted file mode 100644
index 0b0aa04..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_compressed_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_contact_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_contact_am_alpha.png
deleted file mode 100644
index ebd0535..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_contact_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_event_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_event_am_alpha.png
deleted file mode 100644
index 29cdbb7..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_event_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_excel_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_excel_alpha.png
deleted file mode 100644
index ca349b6..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_excel_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_folder_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_folder_alpha.png
deleted file mode 100644
index 02249d2..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_folder_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_font_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_font_alpha.png
deleted file mode 100644
index 469b911..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_font_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_generic_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_generic_am_alpha.png
deleted file mode 100644
index ef479c3..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_generic_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_image_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_image_alpha.png
deleted file mode 100644
index 3168d6f..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_image_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_pdf_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_pdf_alpha.png
deleted file mode 100644
index 9bb4d66..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_pdf_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_powerpoint_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_powerpoint_alpha.png
deleted file mode 100644
index 88ba9ad..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_powerpoint_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_presentation_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_presentation_alpha.png
deleted file mode 100644
index 5fe18da..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_presentation_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_spreadsheet_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_spreadsheet_am_alpha.png
deleted file mode 100644
index 1d05f6f..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_spreadsheet_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_text_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_text_am_alpha.png
deleted file mode 100644
index c2308fe..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_text_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_video_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_video_am_alpha.png
deleted file mode 100644
index 9a173be..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_video_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_word_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_word_alpha.png
deleted file mode 100644
index a564f5a..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_word_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_sdcard_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_sdcard_alpha.png
deleted file mode 100644
index c7daa2a..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_sdcard_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable/cabinet.png b/packages/DocumentsUI/res/drawable/cabinet.png
new file mode 100644
index 0000000..da44023
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/cabinet.png
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable/ic_check_circle.xml b/packages/DocumentsUI/res/drawable/ic_check_circle.xml
new file mode 100644
index 0000000..d49ba6a
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_check_circle.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.
+-->
+<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="#FF009688"
+        android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10,-4.48 10,-10S17.52 2 12 2zm-2 15l-5,-5 1.41,-1.41L10 14.17l7.59,-7.59L19 8l-9 9z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_album.xml b/packages/DocumentsUI/res/drawable/ic_doc_album.xml
index e7965e6..1ce3f02 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_album.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_album.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_doc_album_alpha"
-    android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="#FF737373"
+        android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10,-4.48 10,-10S17.52 2 12 2zm0 14.5c-2.49 0,-4.5,-2.01,-4.5,-4.5S9.51 7.5 12 7.5s4.5 2.01 4.5 4.5,-2.01 4.5,-4.5 4.5zm0,-5.5c-.55 0,-1 .45,-1 1s.45 1 1 1 1,-.45 1,-1,-.45,-1,-1,-1z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_apk.xml b/packages/DocumentsUI/res/drawable/ic_doc_apk.xml
index 4f8f06e..197445e 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_apk.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_apk.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_doc_apk_alpha"
-    android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="#FF737373"
+        android:pathData="M6 18c0 .55.45 1 1 1h1v3.5c0 .83.67 1.5 1.5 1.5s1.5,-.67 1.5,-1.5V19h2v3.5c0 .83.67 1.5 1.5 1.5s1.5,-.67 1.5,-1.5V19h1c.55 0 1,-.45 1,-1V8H6v10zM3.5 8C2.67 8 2 8.67 2 9.5v7c0 .83.67 1.5 1.5 1.5S5 17.33 5 16.5v-7C5 8.67 4.33 8 3.5 8zm17 0c-.83 0,-1.5.67,-1.5 1.5v7c0 .83.67 1.5 1.5 1.5s1.5,-.67 1.5,-1.5v-7c0,-.83,-.67,-1.5,-1.5,-1.5zm-4.97,-5.84l1.3,-1.3c.2,-.2.2,-.51 0,-.71,-.2,-.2,-.51,-.2,-.71 0l-1.48 1.48C13.85 1.23 12.95 1 12 1c-.96 0,-1.86.23,-2.66.63L7.85.15c-.2,-.2,-.51,-.2,-.71 0,-.2.2,-.2.51 0 .71l1.31 1.31C6.97 3.26 6 5.01 6 7h12c0,-1.99,-.97,-3.75,-2.47,-4.84zM10 5H9V4h1v1zm5 0h-1V4h1v1z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml b/packages/DocumentsUI/res/drawable/ic_doc_audio.xml
index cf18b4f..454eea3 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_audio.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_doc_audio_alpha"
-    android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="#FFDB4437"
+        android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zM7.2 18c-.66 0,-1.2,-.54,-1.2,-1.2V12c0,-3.31 2.69,-6 6,-6s6 2.69 6 6v4.8c0 .66,-.54 1.2,-1.2 1.2H14v-4h2v-2c0,-2.21,-1.79,-4,-4,-4s-4 1.79,-4 4v2h2v4H7.2z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_certificate.xml b/packages/DocumentsUI/res/drawable/ic_doc_certificate.xml
index c28ed4f..b99baf6 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_certificate.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_certificate.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_doc_certificate_alpha"
-    android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="#FF737373"
+        android:pathData="M17.81 4.47c-.08 0,-.16,-.02,-.23,-.06C15.66 3.42 14 3 12.01 3c-1.98 0,-3.86.47,-5.57 1.41,-.24.13,-.54.04,-.68,-.2,-.13,-.24,-.04,-.55.2,-.68C7.82 2.52 9.86 2 12.01 2c2.13 0 3.99.47 6.03 1.52.25.13.34.43.21.67,-.09.18,-.26.28,-.44.28zM3.5 9.72c-.1 0,-.2,-.03,-.29,-.09,-.23,-.16,-.28,-.47,-.12,-.7.99,-1.4 2.25,-2.5 3.75,-3.27C9.98 4.04 14 4.03 17.15 5.65c1.5.77 2.76 1.86 3.75 3.25.16.22.11.54,-.12.7,-.23.16,-.54.11,-.7,-.12,-.9,-1.26,-2.04,-2.25,-3.39,-2.94,-2.87,-1.47,-6.54,-1.47,-9.4.01,-1.36.7,-2.5 1.7,-3.4 2.96,-.08.14,-.23.21,-.39.21zm6.25 12.07c-.13 0,-.26,-.05,-.35,-.15,-.87,-.87,-1.34,-1.43,-2.01,-2.64,-.69,-1.23,-1.05,-2.73,-1.05,-4.34 0,-2.97 2.54,-5.39 5.66,-5.39s5.66 2.42 5.66 5.39c0 .28,-.22.5,-.5.5s-.5,-.22,-.5,-.5c0,-2.42,-2.09,-4.39,-4.66,-4.39,-2.57 0,-4.66 1.97,-4.66 4.39 0 1.44.32 2.77.93 3.85.64 1.15 1.08 1.64 1.85 2.42.19.2.19.51 0 .71,-.11.1,-.24.15,-.37.15zm7.17,-1.85c-1.19 0,-2.24,-.3,-3.1,-.89,-1.49,-1.01,-2.38,-2.65,-2.38,-4.39 0,-.28.22,-.5.5,-.5s.5.22.5.5c0 1.41.72 2.74 1.94 3.56.71.48 1.54.71 2.54.71.24 0 .64,-.03 1.04,-.1.27,-.05.53.13.58.41.05.27,-.13.53,-.41.58,-.57.11,-1.07.12,-1.21.12zM14.91 22c-.04 0,-.09,-.01,-.13,-.02,-1.59,-.44,-2.63,-1.03,-3.72,-2.1,-1.4,-1.39,-2.17,-3.24,-2.17,-5.22 0,-1.62 1.38,-2.94 3.08,-2.94 1.7 0 3.08 1.32 3.08 2.94 0 1.07.93 1.94 2.08 1.94s2.08,-.87 2.08,-1.94c0,-3.77,-3.25,-6.83,-7.25,-6.83,-2.84 0,-5.44 1.58,-6.61 4.03,-.39.81,-.59 1.76,-.59 2.8 0 .78.07 2.01.67 3.61.1.26,-.03.55,-.29.64,-.26.1,-.55,-.04,-.64,-.29,-.49,-1.31,-.73,-2.61,-.73,-3.96 0,-1.2.23,-2.29.68,-3.24 1.33,-2.79 4.28,-4.6 7.51,-4.6 4.55 0 8.25 3.51 8.25 7.83 0 1.62,-1.38 2.94,-3.08 2.94s-3.08,-1.32,-3.08,-2.94c0,-1.07,-.93,-1.94,-2.08,-1.94s-2.08.87,-2.08 1.94c0 1.71.66 3.31 1.87 4.51.95.94 1.86 1.46 3.27 1.85.27.07.42.35.35.61,-.05.23,-.26.38,-.47.38z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_codes.xml b/packages/DocumentsUI/res/drawable/ic_doc_codes.xml
index 0de721a9..ea1c464 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_codes.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_codes.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_doc_codes_alpha"
-    android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="#FF737373"
+        android:pathData="M9.4 16.6L4.8 12l4.6,-4.6L8 6l-6 6 6 6 1.4,-1.4zm5.2 0l4.6,-4.6,-4.6,-4.6L16 6l6 6,-6 6,-1.4,-1.4z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_compressed.xml b/packages/DocumentsUI/res/drawable/ic_doc_compressed.xml
index a49cfa4..e0eb669 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_compressed.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_compressed.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_doc_compressed_alpha"
-    android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="#FF737373"
+        android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm-5 6h-2v2h2v2h-2v-2h-2V9h2V7h-2V5h2v2h2v2zm0 8h-2v-2h-2v-2h2v2h2v2z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_contact.xml b/packages/DocumentsUI/res/drawable/ic_doc_contact.xml
index bf550cb..a77cb6b 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_contact.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_contact.xml
@@ -1,5 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_doc_contact_am_alpha"
-    android:tint="?android:attr/colorControlNormal"
-    android:autoMirrored="true" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="#FF737373"
+        android:pathData="M19 3H5c-1.11 0,-2 .89,-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.11,-.9,-2,-2,-2zm-7 3c1.65 0 3 1.35 3 3 0 1.66,-1.35 3,-3 3s-3,-1.34,-3,-3c0,-1.65 1.35,-3 3,-3zm6 12H6v-1c0,-2 4,-3.1 6,-3.1s6 1.1 6 3.1v1z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_document.xml b/packages/DocumentsUI/res/drawable/ic_doc_document.xml
new file mode 100644
index 0000000..29251ad
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_doc_document.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="#FF4883F3"
+        android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm-1.99 6H7V7h10.01v2zm0 4H7v-2h10.01v2zm-3 4H7v-2h7.01v2z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_event.xml b/packages/DocumentsUI/res/drawable/ic_doc_event.xml
index 25cf0f3..113f079 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_event.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_event.xml
@@ -1,5 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_doc_event_am_alpha"
-    android:tint="?android:attr/colorControlNormal"
-    android:autoMirrored="true" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="#FF737373"
+        android:pathData="M17 12h-5v5h5v-5zM16 1v2H8V1H6v2H5c-1.11 0,-1.99.9,-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2h-1V1h-2zm3 18H5V8h14v11z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_excel.xml b/packages/DocumentsUI/res/drawable/ic_doc_excel.xml
index 3354725..3ed27e1 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_excel.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_excel.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_doc_excel_alpha"
-    android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="#FF16A765"
+        android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm-2.8 14h-2L12 13.2 9.8 17h-2l3.2,-5,-3.2,-5h2l2.2 3.8L14.2 7h2L13 12l3.2 5z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_folder.xml b/packages/DocumentsUI/res/drawable/ic_doc_folder.xml
index 73de60e..dcbce01 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_folder.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_folder.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_doc_folder_alpha"
-    android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="#FF737373"
+        android:pathData="M10 4H4c-1.1 0,-1.99.9,-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2,-.9 2,-2V8c0,-1.1,-.9,-2,-2,-2h-8l-2,-2z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_font.xml b/packages/DocumentsUI/res/drawable/ic_doc_font.xml
index c74cb9c..4c13d71 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_font.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_font.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_doc_font_alpha"
-    android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="#FF737373"
+        android:pathData="M9.93 13.5h4.14L12 7.98zM20 2H4c-1.1 0,-2 .9,-2 2v16c0 1.1.9 2 2 2h16c1.1 0 2,-.9 2,-2V4c0,-1.1,-.9,-2,-2,-2zm-4.05 16.5l-1.14,-3H9.17l-1.12 3H5.96l5.11,-13h1.86l5.11 13h-2.09z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_generic.xml b/packages/DocumentsUI/res/drawable/ic_doc_generic.xml
index a4ee29d..006dfba 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_generic.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_generic.xml
@@ -1,5 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_doc_generic_am_alpha"
-    android:tint="?android:attr/colorControlNormal"
-    android:autoMirrored="true" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="#FF737373"
+        android:pathData="M6 2c-1.1 0,-1.99.9,-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2,-.9 2,-2V8l-6,-6H6zm7 7V3.5L18.5 9H13z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_image.xml b/packages/DocumentsUI/res/drawable/ic_doc_image.xml
index 9d4c359..23953f7 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_image.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_image.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_doc_image_alpha"
-    android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="#FFDB4437"
+        android:pathData="M21 19V5c0,-1.1,-.9,-2,-2,-2H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5,-4.5z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_pdf.xml b/packages/DocumentsUI/res/drawable/ic_doc_pdf.xml
index 5c37498..b2d0193 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_pdf.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_pdf.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_doc_pdf_alpha"
-    android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="#FFDB4437"
+        android:pathData="M7 11.5h1v-1H7v1zM19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm-9.5 8.5c0 .83,-.67 1.5,-1.5 1.5H7v2H5.5V9H8c.83 0 1.5.67 1.5 1.5v1zm10,-1H17v1h1.5V13H17v2h-1.5V9h4v1.5zm-5 3c0 .83,-.67 1.5,-1.5 1.5h-2.5V9H13c.83 0 1.5.67 1.5 1.5v3zm-2.5 0h1v-3h-1v3z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_powerpoint.xml b/packages/DocumentsUI/res/drawable/ic_doc_powerpoint.xml
index f0a6c39..aa5bfc8 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_powerpoint.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_powerpoint.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_doc_powerpoint_alpha"
-    android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="#FFFF7537"
+        android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zM9.8 13.4V17H8V7h4.3c1.53 0 2.15.3 2.8.89.65.59.9 1.37.9 2.34 0 1.02,-.26 1.8,-.9 2.35s-1.3.82,-2.8.82H9.8zm0,-1.4V8.4h2.3c.66 0 1.17.25 1.5.6.33.35.5.72.5 1.25 0 .55,-.18.95,-.5 1.25,-.32.31,-.7.5,-1.38.5H9.8z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_presentation.xml b/packages/DocumentsUI/res/drawable/ic_doc_presentation.xml
index a14f866..7937bc1 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_presentation.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_presentation.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_doc_presentation_alpha"
-    android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="#FFF4B400"
+        android:pathData="M19 3H5c-1.1 0,-1.99.9,-1.99 2v14c0 1.1.89 2 1.99 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm0 13H5V8h14v8z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_spreadsheet.xml b/packages/DocumentsUI/res/drawable/ic_doc_spreadsheet.xml
index 40f2515..1663c0a 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_spreadsheet.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_spreadsheet.xml
@@ -1,5 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_doc_spreadsheet_am_alpha"
-    android:tint="?android:attr/colorControlNormal"
-    android:autoMirrored="true" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="#FF16A765"
+        android:pathData="M19 3H5c-1.1 0,-1.99.9,-1.99 2L3 8v11c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm0 8h-8v8H9v-8H5V9h4V5h2v4h8v2z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_text.xml b/packages/DocumentsUI/res/drawable/ic_doc_text.xml
index ffa9e70..7fc04e8 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_text.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_text.xml
@@ -1,5 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_doc_text_am_alpha"
-    android:tint="?android:attr/colorControlNormal"
-    android:autoMirrored="true" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="#FF737373"
+        android:pathData="M14 2H6c-1.1 0,-1.99.9,-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2,-.9 2,-2V8l-6,-6zm2 16H8v-2h8v2zm0,-4H8v-2h8v2zm-3,-5V3.5L18.5 9H13z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_video.xml b/packages/DocumentsUI/res/drawable/ic_doc_video.xml
index 2d048c2..ad4dae8 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_video.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_video.xml
@@ -1,5 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_doc_video_am_alpha"
-    android:tint="?android:attr/colorControlNormal"
-    android:autoMirrored="true" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="#FFDB4437"
+        android:pathData="M18 4l2 4h-3l-2,-4h-2l2 4h-3l-2,-4H8l2 4H7L5 4H4c-1.1 0,-1.99.9,-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2,-.9 2,-2V4h-4z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_word.xml b/packages/DocumentsUI/res/drawable/ic_doc_word.xml
index afcc533..7a3a0ec 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_word.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_word.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_doc_word_alpha"
-    android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="#FF4883F3"
+        android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm-3.5 14H14l-2,-7.5,-2 7.5H8.5L6.1 7h1.7l1.54 7.51L11.3 7h1.4l1.97 7.51L16.2 7h1.7l-2.4 10z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_root_home.xml b/packages/DocumentsUI/res/drawable/ic_root_home.xml
index 0a258ac..696ee05 100644
--- a/packages/DocumentsUI/res/drawable/ic_root_home.xml
+++ b/packages/DocumentsUI/res/drawable/ic_root_home.xml
@@ -1,15 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="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="#000000"
-        android:pathData="M20 6h-8l-2-2H4c-1.1 0-1.99 .9 -1.99 2L2 18c0 1.1 .9 2 2 2h16c1.1 0 2-.9
-2-2V8c0-1.1-.9-2-2-2zm-5 3c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm4
-8h-8v-1c0-1.33 2.67-2 4-2s4 .67 4 2v1z" />
-    <path
-        android:pathData="M0 0h24v24H0z" />
+        android:fillColor="#FF000000"
+        android:pathData="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/>
 </vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_root_sdcard.xml b/packages/DocumentsUI/res/drawable/ic_root_sdcard.xml
deleted file mode 100644
index 27cfa81d..0000000
--- a/packages/DocumentsUI/res/drawable/ic_root_sdcard.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_root_sdcard_alpha"
-    android:tint="?android:attr/colorControlNormal" />
diff --git a/packages/DocumentsUI/res/drawable/ic_root_smartphone.xml b/packages/DocumentsUI/res/drawable/ic_root_smartphone.xml
new file mode 100644
index 0000000..3021b16
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_root_smartphone.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="M17 1.01L7 1c-1.1 0,-2 .9,-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2,-.9 2,-2V3c0,-1.1,-.9,-1.99,-2,-1.99zM17 19H7V5h10v14z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml b/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml
index fe06eaf..ecc26e1 100644
--- a/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml
+++ b/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
+<!--
+     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.
@@ -18,8 +19,8 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:background="@color/item_doc_background"
-    android:orientation="horizontal"
-    android:focusable="true">
+    android:focusable="true"
+    android:orientation="horizontal" >
 
     <View
         android:id="@+id/focus_indicator"
@@ -29,71 +30,76 @@
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:minHeight="@dimen/list_item_height"
-        android:paddingStart="@dimen/list_item_padding"
-        android:paddingEnd="@dimen/list_item_padding"
+        android:baselineAligned="false"
         android:gravity="center_vertical"
+        android:minHeight="@dimen/list_item_height"
         android:orientation="horizontal"
-        android:baselineAligned="false">
+        android:paddingEnd="@dimen/list_item_padding"
+        android:paddingStart="@dimen/list_item_padding" >
 
         <FrameLayout
             android:id="@android:id/icon"
-            android:layout_width="@dimen/icon_size"
-            android:layout_height="@dimen/icon_size"
-            android:layout_marginStart="0dp"
-            android:layout_marginEnd="16dp">
+            android:layout_width="@dimen/list_item_thumbnail_size"
+            android:layout_height="@dimen/list_item_thumbnail_size"
+            android:layout_marginEnd="16dp"
+            android:layout_marginStart="0dp" >
 
             <ImageView
                 android:id="@+id/icon_mime"
                 android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:scaleType="centerInside"
-                android:contentDescription="@null" />
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:contentDescription="@null"
+                android:scaleType="centerInside" />
 
             <ImageView
                 android:id="@+id/icon_thumb"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
-                android:scaleType="centerCrop"
-                android:contentDescription="@null" />
+                android:layout_gravity="center"
+                android:contentDescription="@null"
+                android:scaleType="centerCrop" />
+
+            <ImageView
+                android:id="@+id/icon_check"
+                android:layout_width="@dimen/check_icon_size"
+                android:layout_height="@dimen/check_icon_size"
+                android:layout_gravity="center"
+                android:alpha="0"
+                android:contentDescription="@null"
+                android:scaleType="fitCenter"
+                android:src="@drawable/ic_check_circle" />
 
         </FrameLayout>
 
         <!-- This is the one special case where we want baseline alignment! -->
+
         <LinearLayout
             android:layout_width="0dp"
             android:layout_height="wrap_content"
             android:layout_weight="1"
-            android:orientation="horizontal">
+            android:orientation="horizontal" >
 
             <TextView
                 android:id="@android:id/title"
                 android:layout_width="0dp"
                 android:layout_height="wrap_content"
-                android:layout_weight="0.5"
                 android:layout_marginEnd="12dp"
-                android:singleLine="true"
+                android:layout_weight="0.5"
                 android:ellipsize="middle"
+                android:singleLine="true"
                 android:textAlignment="viewStart"
                 android:textAppearance="@android:style/TextAppearance.Material.Subhead"
                 android:textColor="?android:attr/textColorPrimary" />
 
-            <ImageView
-                android:id="@android:id/icon1"
-                android:layout_width="@dimen/root_icon_size"
-                android:layout_height="@dimen/root_icon_size"
-                android:layout_marginEnd="8dp"
-                android:scaleType="centerInside"
-                android:contentDescription="@null" />
-
             <TextView
                 android:id="@android:id/summary"
                 android:layout_width="0dp"
                 android:layout_height="wrap_content"
-                android:layout_weight="0.25"
                 android:layout_marginEnd="12dp"
-                android:singleLine="true"
+                android:layout_weight="0.25"
                 android:ellipsize="end"
+                android:singleLine="true"
                 android:textAlignment="viewStart"
                 android:textAppearance="@android:style/TextAppearance.Material.Body1"
                 android:textColor="?android:attr/textColorSecondary" />
@@ -102,11 +108,11 @@
                 android:id="@+id/size"
                 android:layout_width="0dp"
                 android:layout_height="wrap_content"
-                android:layout_weight="0.125"
                 android:layout_marginEnd="12dp"
+                android:layout_weight="0.125"
+                android:ellipsize="end"
                 android:minWidth="70dp"
                 android:singleLine="true"
-                android:ellipsize="end"
                 android:textAlignment="viewEnd"
                 android:textAppearance="@android:style/TextAppearance.Material.Body1"
                 android:textColor="?android:attr/textColorSecondary" />
@@ -115,17 +121,15 @@
                 android:id="@+id/date"
                 android:layout_width="0dp"
                 android:layout_height="wrap_content"
-                android:layout_weight="0.125"
                 android:layout_marginEnd="12dp"
+                android:layout_weight="0.125"
+                android:ellipsize="end"
                 android:minWidth="70dp"
                 android:singleLine="true"
-                android:ellipsize="end"
                 android:textAlignment="viewEnd"
                 android:textAppearance="@android:style/TextAppearance.Material.Body1"
                 android:textColor="?android:attr/textColorSecondary" />
-
         </LinearLayout>
-
     </LinearLayout>
 
 </com.android.documentsui.ListItem>
diff --git a/packages/DocumentsUI/res/layout/dialog_create_dir.xml b/packages/DocumentsUI/res/layout/dialog_file_name.xml
similarity index 100%
rename from packages/DocumentsUI/res/layout/dialog_create_dir.xml
rename to packages/DocumentsUI/res/layout/dialog_file_name.xml
diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml
index f9bbccb..223d729 100644
--- a/packages/DocumentsUI/res/layout/fragment_directory.xml
+++ b/packages/DocumentsUI/res/layout/fragment_directory.xml
@@ -23,11 +23,11 @@
     <ProgressBar
         android:id="@+id/progressbar"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
+        android:layout_height="@dimen/progress_bar_height"
         android:indeterminate="true"
         style="@style/TrimmedHorizontalProgressBar"
         android:visibility="gone"/>
-  
+
     <FrameLayout
         android:id="@+id/container_message_bar"
         android:layout_width="match_parent"
@@ -36,31 +36,44 @@
         android:background="@color/material_grey_50"
         android:visibility="gone"/>
 
-    <!-- The empty directory view -->
-    <LinearLayout
+    <!-- The empty container view -->
+    <FrameLayout
         android:id="@android:id/empty"
         android:gravity="center"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:orientation="vertical"
         android:visibility="gone">
-        
-        <TextView
-            android:id="@+id/message"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/empty"
-            style="@android:style/TextAppearance.Material.Subhead" />
 
-         <Button
-            android:id="@+id/button_retry"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/button_retry"
-            style="?android:attr/buttonBarPositiveButtonStyle" />
-        
-    </LinearLayout>
-    
+        <LinearLayout
+            android:id="@+id/content"
+            android:gravity="center"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="vertical">
+
+            <ImageView
+                android:id="@+id/artwork"
+                android:src="@drawable/cabinet"
+                android:adjustViewBounds="true"
+                android:layout_height="250dp"
+                android:layout_width="fill_parent"
+                android:alpha="1"
+                android:layout_centerVertical="true"
+                android:layout_marginBottom="25dp"
+                android:scaleType="fitCenter"
+                android:contentDescription="@null" />
+
+            <TextView
+                android:id="@+id/message"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/empty"
+                style="@android:style/TextAppearance.Material.Subhead" />
+
+        </LinearLayout>
+    </FrameLayout>
+
     <!-- This FrameLayout works around b/24189541 -->
     <FrameLayout
         android:layout_width="match_parent"
@@ -68,6 +81,7 @@
 
         <android.support.v7.widget.RecyclerView
             android:id="@+id/list"
+            android:background="@color/window_background"
             android:scrollbars="vertical"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
diff --git a/packages/DocumentsUI/res/layout/item_dir_grid.xml b/packages/DocumentsUI/res/layout/item_dir_grid.xml
new file mode 100644
index 0000000..b0331be
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/item_dir_grid.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_margin="@dimen/grid_item_margin"
+    android:background="@color/item_doc_background"
+    android:elevation="5dp"
+    android:focusable="true" >
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="horizontal"
+        android:paddingBottom="16dp"
+        android:paddingLeft="12dp"
+        android:paddingRight="12dp"
+        android:paddingTop="16dp"
+        android:gravity="center_vertical">
+
+        <FrameLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="8dp" >
+
+            <ImageView
+                android:id="@+id/icon_mime_sm"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:contentDescription="@null"
+                android:scaleType="centerInside"
+                android:src="@drawable/ic_doc_folder" />
+
+            <ImageView
+                android:id="@+id/icon_check"
+                android:layout_width="@dimen/check_icon_size"
+                android:layout_height="@dimen/check_icon_size"
+                android:alpha="0"
+                android:contentDescription="@null"
+                android:scaleType="fitCenter"
+                android:src="@drawable/ic_check_circle" />
+
+        </FrameLayout>
+
+        <TextView
+            android:id="@android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:ellipsize="middle"
+            android:singleLine="true"
+            android:textAlignment="viewStart"
+            android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+            android:textColor="@*android:color/primary_text_default_material_light" />
+
+    </LinearLayout>
+
+    <!-- An overlay that draws the item border when it is focused. -->
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@drawable/item_doc_grid_border"
+        android:contentDescription="@null"
+        android:duplicateParentState="true" />
+
+</FrameLayout>
diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml
index dcd5cfd..dd02d1c 100644
--- a/packages/DocumentsUI/res/layout/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml
@@ -19,6 +19,7 @@
     android:layout_height="wrap_content"
     android:layout_margin="@dimen/grid_item_margin"
     android:background="@color/item_doc_background"
+    android:elevation="5dp"
     android:focusable="true">
 
     <!-- Main item thumbnail.  Comprised of two overlapping images, the
@@ -38,10 +39,11 @@
             android:contentDescription="@null" />
 
         <com.android.documentsui.GridItemThumbnail
-            android:id="@+id/icon_mime"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:scaleType="centerInside"
+            android:id="@+id/icon_mime_lg"
+            android:layout_width="@dimen/icon_size"
+            android:layout_height="@dimen/icon_size"
+            android:layout_gravity="center"
+            android:scaleType="fitCenter"
             android:contentDescription="@null" />
 
     </FrameLayout>
@@ -60,13 +62,25 @@
         android:paddingRight="12dp">
 
         <ImageView
-            android:id="@android:id/icon1"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
+            android:id="@+id/icon_mime_sm"
+            android:layout_width="@dimen/grid_item_icon_size"
+            android:layout_height="@dimen/grid_item_icon_size"
             android:layout_marginEnd="8dp"
             android:layout_alignParentStart="true"
             android:layout_centerVertical="true"
-            android:scaleType="centerInside"
+            android:scaleType="center"
+            android:contentDescription="@null"/>
+
+        <ImageView
+            android:id="@+id/icon_check"
+            android:src="@drawable/ic_check_circle"
+            android:alpha="0"
+            android:layout_width="@dimen/check_icon_size"
+            android:layout_height="@dimen/check_icon_size"
+            android:layout_marginEnd="8dp"
+            android:layout_alignParentStart="true"
+            android:layout_centerVertical="true"
+            android:scaleType="fitCenter"
             android:contentDescription="@null"/>
 
         <TextView
@@ -74,7 +88,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_alignParentTop="true"
-            android:layout_toEndOf="@android:id/icon1"
+            android:layout_toEndOf="@id/icon_mime_sm"
             android:singleLine="true"
             android:ellipsize="middle"
             android:textAlignment="viewStart"
@@ -85,7 +99,7 @@
             android:id="@+id/size"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_toEndOf="@android:id/icon1"
+            android:layout_toEndOf="@id/icon_mime_sm"
             android:layout_below="@android:id/title"
             android:layout_marginEnd="4dp"
             android:singleLine="true"
diff --git a/packages/DocumentsUI/res/layout/item_doc_list.xml b/packages/DocumentsUI/res/layout/item_doc_list.xml
index e068423..8d98377 100644
--- a/packages/DocumentsUI/res/layout/item_doc_list.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_list.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
+<!--
+     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.
@@ -18,8 +19,8 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:background="@color/item_doc_background"
-    android:orientation="horizontal"
-    android:focusable="true">
+    android:focusable="true"
+    android:orientation="horizontal" >
 
     <View
         android:id="@+id/focus_indicator"
@@ -29,82 +30,76 @@
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:minHeight="@dimen/list_item_height"
-        android:paddingStart="@dimen/list_item_padding"
-        android:paddingEnd="@dimen/list_item_padding"
+        android:baselineAligned="false"
         android:gravity="center_vertical"
+        android:minHeight="@dimen/list_item_height"
         android:orientation="horizontal"
-        android:baselineAligned="false">
+        android:paddingEnd="@dimen/list_item_padding"
+        android:paddingStart="@dimen/list_item_padding" >
 
         <FrameLayout
             android:id="@android:id/icon"
-            android:layout_width="@dimen/icon_size"
-            android:layout_height="@dimen/icon_size"
-            android:layout_marginEnd="16dp">
+            android:layout_width="@dimen/list_item_thumbnail_size"
+            android:layout_height="@dimen/list_item_thumbnail_size"
+            android:layout_marginEnd="16dp" >
 
             <ImageView
                 android:id="@+id/icon_mime"
                 android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:scaleType="centerInside"
-                android:contentDescription="@null" />
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:contentDescription="@null"
+                android:scaleType="centerInside" />
 
             <ImageView
                 android:id="@+id/icon_thumb"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
-                android:scaleType="centerCrop"
-                android:contentDescription="@null" />
+                android:contentDescription="@null"
+                android:scaleType="centerCrop" />
 
+            <ImageView
+                android:id="@+id/icon_check"
+                android:layout_width="@dimen/check_icon_size"
+                android:layout_height="@dimen/check_icon_size"
+                android:layout_gravity="center"
+                android:alpha="0"
+                android:contentDescription="@null"
+                android:scaleType="fitCenter"
+                android:src="@drawable/ic_check_circle" />
         </FrameLayout>
 
         <LinearLayout
             android:layout_width="0dp"
             android:layout_height="wrap_content"
             android:layout_weight="1"
-            android:orientation="vertical">
+            android:orientation="vertical" >
 
-            <LinearLayout
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal"
-                android:baselineAligned="false">
-
-                <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:textAlignment="viewStart"
-                    android:textAppearance="@android:style/TextAppearance.Material.Subhead"
-                    android:textColor="?android:attr/textColorPrimary" />
-
-                <ImageView
-                    android:id="@android:id/icon1"
-                    android:layout_width="@dimen/root_icon_size"
-                    android:layout_height="@dimen/root_icon_size"
-                    android:layout_marginStart="8dp"
-                    android:scaleType="centerInside"
-                    android:contentDescription="@null" />
-
-            </LinearLayout>
+            <TextView
+                android:id="@android:id/title"
+                android:layout_width="wrap_content"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:ellipsize="middle"
+                android:singleLine="true"
+                android:textAlignment="viewStart"
+                android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+                android:textColor="?android:attr/textColorPrimary" />
 
             <LinearLayout
                 android:id="@+id/line2"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
+                android:baselineAligned="false"
                 android:gravity="center_vertical"
-                android:orientation="horizontal"
-                android:baselineAligned="false">
+                android:orientation="horizontal" >
 
                 <TextView
                     android:id="@+id/date"
                     android:layout_width="90dp"
                     android:layout_height="wrap_content"
-                    android:singleLine="true"
                     android:ellipsize="end"
+                    android:singleLine="true"
                     android:textAlignment="viewStart"
                     android:textAppearance="@android:style/TextAppearance.Material.Body1"
                     android:textColor="?android:attr/textColorSecondary" />
@@ -114,8 +109,8 @@
                     android:layout_width="90dp"
                     android:layout_height="wrap_content"
                     android:layout_marginStart="8dp"
-                    android:singleLine="true"
                     android:ellipsize="end"
+                    android:singleLine="true"
                     android:textAlignment="viewStart"
                     android:textAppearance="@android:style/TextAppearance.Material.Body1"
                     android:textColor="?android:attr/textColorSecondary" />
@@ -124,18 +119,15 @@
                     android:id="@android:id/summary"
                     android:layout_width="0dp"
                     android:layout_height="wrap_content"
-                    android:layout_weight="1"
                     android:layout_marginStart="8dp"
-                    android:singleLine="true"
+                    android:layout_weight="1"
                     android:ellipsize="end"
+                    android:singleLine="true"
                     android:textAlignment="viewStart"
                     android:textAppearance="@android:style/TextAppearance.Material.Body1"
                     android:textColor="?android:attr/textColorSecondary" />
-
             </LinearLayout>
-
         </LinearLayout>
-
     </LinearLayout>
 
 </com.android.documentsui.ListItem>
diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml
index 7e0649b..a3cfde8 100644
--- a/packages/DocumentsUI/res/menu/activity.xml
+++ b/packages/DocumentsUI/res/menu/activity.xml
@@ -15,11 +15,19 @@
 -->
 
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
+<!-- showAsAction flag impacts the behavior of SearchView.
+     When set to collapseActionView, collapsing SearchView to icon is the
+     default behavior. It would fit UX, however after expanding SearchView is
+     shown on the left site of the toolbar (replacing title). Since no way to
+     prevent this behavior was found, the flag is set to always. SearchView is
+     always visible by default and it is being collapse manually by calling
+     setIconified() method
+-->
     <item
         android:id="@+id/menu_search"
         android:title="@string/menu_search"
         android:icon="@drawable/ic_menu_search"
-        android:showAsAction="always|collapseActionView"
+        android:showAsAction="always"
         android:actionViewClass="android.widget.SearchView"
         android:imeOptions="actionSearch" />
     <item
diff --git a/packages/DocumentsUI/res/menu/mode_directory.xml b/packages/DocumentsUI/res/menu/mode_directory.xml
index 4ff396f..6f9bfb5 100644
--- a/packages/DocumentsUI/res/menu/mode_directory.xml
+++ b/packages/DocumentsUI/res/menu/mode_directory.xml
@@ -48,4 +48,9 @@
         android:title="@string/menu_move"
         android:showAsAction="never"
         android:visible="false" />
+    <item
+        android:id="@+id/menu_rename"
+        android:title="@string/menu_rename"
+        android:showAsAction="never"
+        android:visible="false" />
 </menu>
diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml
index 1599178..9931a6b 100644
--- a/packages/DocumentsUI/res/values-af/strings.xml
+++ b/packages/DocumentsUI/res/values-af/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Toestelle"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Nog programme"</string>
     <string name="empty" msgid="7858882803708117596">"Geen items nie"</string>
+    <string name="no_results" msgid="6622510343880730446">"Geen passings in %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Kan lêer nie oopmaak nie"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Kan sommige dokumente nie uitvee nie"</string>
     <string name="share_via" msgid="8966594246261344259">"Deel via"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Ontdoen"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Maak tans gereed vir kopieer …"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Berei tans voor vir skuif …"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Maak tans gereed om uit te vee …"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other">Kon <xliff:g id="COUNT_1">%1$d</xliff:g> lêers nie kopieer nie</item>
       <item quantity="one">Kon <xliff:g id="COUNT_0">%1$d</xliff:g> lêer nie kopieer nie</item>
@@ -92,8 +94,13 @@
       <item quantity="other">Kon <xliff:g id="COUNT_1">%1$d</xliff:g> lêers nie skuif nie</item>
       <item quantity="one">Kon <xliff:g id="COUNT_0">%1$d</xliff:g> lêer nie skuif nie</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Raak om besonderhede te bekyk"</string>
-    <string name="retry" msgid="7564024179122207376">"Herprobeer"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other">Kon <xliff:g id="COUNT_1">%1$d</xliff:g> lêers nie uitvee nie</item>
+      <item quantity="one">Kon <xliff:g id="COUNT_0">%1$d</xliff:g> lêer nie uitvee nie</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Tik om besonderhede te bekyk"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Hierdie lêers is nie gekopieer nie: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Hierdie lêers is nie geskuif nie: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">Het <xliff:g id="COUNT_0">%1$d</xliff:g> lêer na die knipbord gekopieer.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Kan nie die geselekteerde lêers in hierdie ligging plak nie."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Hernoem"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Kon nie dokument hernoem nie"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml
index 1a6c85a..cccaf51 100644
--- a/packages/DocumentsUI/res/values-am/strings.xml
+++ b/packages/DocumentsUI/res/values-am/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"ፋይል መክፈት አይቻልም"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"አንዳንድ ሰነዶችን መሰረዝ አልተቻለም"</string>
     <string name="share_via" msgid="8966594246261344259">"በሚከተለው በኩል ያጋሩ"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"ዝርዝሮችን ለመመልከት ይንኩ።"</string>
-    <string name="retry" msgid="7564024179122207376">"እንደገና ይሞክሩ"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"ዝርዝሮችን ለመመልከት መታ ያድርጉ"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"እነዚህ ፋይሎች አልተቀዱም፦ <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"እነዚህ ፋይሎች አልተወሰዱም፦ <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml
index 1e86c03..1177de7 100644
--- a/packages/DocumentsUI/res/values-ar/strings.xml
+++ b/packages/DocumentsUI/res/values-ar/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"لا يمكن فتح الملف"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"تعذر حذف بعض المستندات"</string>
     <string name="share_via" msgid="8966594246261344259">"مشاركة عبر"</string>
@@ -96,6 +97,7 @@
     <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="5267616889076217261">
       <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>
@@ -112,8 +114,17 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"المس لعرض التفاصيل"</string>
-    <string name="retry" msgid="7564024179122207376">"إعادة المحاولة"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"انقر لعرض التفاصيل."</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"لم يتم نسخ هذه الملفات: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"لم يتم نقل الملفات التالية: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -125,4 +136,6 @@
       <item quantity="one">تم نسخ ملف واحد (<xliff:g id="COUNT_0">%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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-az-rAZ/strings.xml b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
index b6dd297..2482ff0 100644
--- a/packages/DocumentsUI/res/values-az-rAZ/strings.xml
+++ b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Cihazlar"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Daha çox tətbiq"</string>
     <string name="empty" msgid="7858882803708117596">"Element yoxdur"</string>
+    <string name="no_results" msgid="6622510343880730446">"%1$s ilə heç bir uyğunluq yoxdur"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Faylı aça bilmir"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Bəzi sənədləri silə bilmir"</string>
     <string name="share_via" msgid="8966594246261344259">"Bunun vasitəsilə paylaş:"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Ləğv edin"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Kopyalanmaq üçün hazırlanır ..."</string>
     <string name="move_preparing" msgid="2772219441375531410">"Köçürmə üçün hazırlanır..."</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Silmək üçün hazırlanır..."</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fayl kopyalanmadı</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> fayl kopyalanmadı</item>
@@ -92,8 +94,13 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fayl köçürülə bilmədi</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> fayl köçürülə bilmədi</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Detallara baxmaq üçün toxunun"</string>
-    <string name="retry" msgid="7564024179122207376">"Yenidən cəhd edin"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> fayl silinmədi</item>
+      <item quantity="one"> <xliff:g id="COUNT_0">%1$d</xliff:g> fayl silinmədi</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Detallara baxmaq üçün basın"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Bu fayllar kopyalanmadı: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Bu fayllar köçürülmədi: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> fayl buferə kopyalandı.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Seçilmiş faylları bu məkana yerləşdirmək olmaz."</string>
+    <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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
index feace71..28a35c7 100644
--- a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Uređaji"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Još aplikacija"</string>
     <string name="empty" msgid="7858882803708117596">"Nema stavki"</string>
+    <string name="no_results" msgid="6622510343880730446">"Nema podudaranja u %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Nije moguće otvoriti datoteku"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Nije moguće izbrisati neke dokumente"</string>
     <string name="share_via" msgid="8966594246261344259">"Delite preko"</string>
@@ -87,6 +88,7 @@
     <string name="undo" msgid="7905788502491742328">"Opozovi"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Priprema se kopiranje…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Priprema se premeštanje..."</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Priprema se brisanje…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="one">Nismo uspeli da kopiramo <xliff:g id="COUNT_1">%1$d</xliff:g> datoteku</item>
       <item quantity="few">Nismo uspeli da kopiramo <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke</item>
@@ -97,8 +99,14 @@
       <item quantity="few">Nije uspelo premeštanje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke</item>
       <item quantity="other">Nije uspelo premeštanje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Dodirnite da biste videli detalje"</string>
-    <string name="retry" msgid="7564024179122207376">"Pokušaj ponovo"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="one">Brisanje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke nije uspelo</item>
+      <item quantity="few">Brisanje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke nije uspelo</item>
+      <item quantity="other">Brisanje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka nije uspelo</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Dodirnite da biste prikazali detalje"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Sledeće datoteke nisu kopirane: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Ove datoteke nisu premeštene: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -107,4 +115,6 @@
       <item quantity="other">Kopirali ste <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka u privremenu memoriju.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Izabrane datoteke ne mogu da se nalepe na ovoj lokaciji."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Preimenuj"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Preimenovanje dokumenta nije uspelo"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml
index f4aff3e..bdebffb 100644
--- a/packages/DocumentsUI/res/values-bg/strings.xml
+++ b/packages/DocumentsUI/res/values-bg/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"Файлът не може да се отвори"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Някои документи не могат да бъдат изтрити"</string>
     <string name="share_via" msgid="8966594246261344259">"Споделяне чрез"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"Докоснете, за да видите подробностите"</string>
-    <string name="retry" msgid="7564024179122207376">"Нов опит"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"Докоснете, за да видите подробности"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Следните файлове не бяха копирани: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Следните файлове не бяха преместени: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">Копирахте <xliff:g id="COUNT_0">%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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-bn-rBD/strings.xml b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
index c757eaf..0ede613 100644
--- a/packages/DocumentsUI/res/values-bn-rBD/strings.xml
+++ b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"ফাইল খোলা যাবে না"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"কিছু দস্তাবেজ মুছতে অসমর্থ"</string>
     <string name="share_via" msgid="8966594246261344259">"এর মাধ্যমে ভাগ করুন"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"বিশদ বিবরণ দেখতে স্পর্শ করুন"</string>
-    <string name="retry" msgid="7564024179122207376">"পুনরায় চেষ্টা করুন"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"বিশদ বিবরণ দেখতে আলতো চাপুন"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"এই ফাইলগুলির প্রতিলিপি করা হয় নি: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"এই ফাইলগুলি সরানো হয়নি: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-bs-rBA/config.xml b/packages/DocumentsUI/res/values-bs-rBA/config.xml
new file mode 100644
index 0000000..843a8aa
--- /dev/null
+++ b/packages/DocumentsUI/res/values-bs-rBA/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources 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
new file mode 100644
index 0000000..bba1053
--- /dev/null
+++ b/packages/DocumentsUI/res/values-bs-rBA/strings.xml
@@ -0,0 +1,155 @@
+<?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">
+    <!-- no translation found for app_label (2783841764617238354) -->
+    <skip />
+    <!-- no translation found for files_label (6051402950202690279) -->
+    <skip />
+    <!-- no translation found for downloads_label (959113951084633612) -->
+    <skip />
+    <!-- no translation found for title_open (4353228937663917801) -->
+    <skip />
+    <!-- no translation found for title_save (2433679664882857999) -->
+    <skip />
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
+    <!-- no translation found for menu_grid (6878021334497835259) -->
+    <skip />
+    <!-- no translation found for menu_list (7279285939892417279) -->
+    <skip />
+    <!-- no translation found for menu_sort (7677740407158414452) -->
+    <skip />
+    <!-- no translation found for menu_search (3816712084502856974) -->
+    <skip />
+    <!-- no translation found for menu_settings (6008033148948428823) -->
+    <skip />
+    <!-- no translation found for menu_open (432922957274920903) -->
+    <skip />
+    <!-- no translation found for menu_save (2394743337684426338) -->
+    <skip />
+    <!-- no translation found for menu_share (3075149983979628146) -->
+    <skip />
+    <!-- no translation found for menu_delete (8138799623850614177) -->
+    <skip />
+    <!-- no translation found for menu_select_all (8323579667348729928) -->
+    <skip />
+    <!-- no translation found for menu_copy (3612326052677229148) -->
+    <skip />
+    <!-- no translation found for menu_move (1828090633118079817) -->
+    <skip />
+    <!-- no translation found for menu_new_window (1226032889278727538) -->
+    <skip />
+    <!-- no translation found for menu_copy_to_clipboard (489311381979634291) -->
+    <skip />
+    <!-- no translation found for menu_paste_from_clipboard (2071583031180257091) -->
+    <skip />
+    <!-- no translation found for menu_advanced_show (4693652895715631401) -->
+    <skip />
+    <!-- no translation found for menu_advanced_show (5792182900084144261) -->
+    <skip />
+    <!-- no translation found for menu_advanced_hide (4218809952721972589) -->
+    <skip />
+    <!-- no translation found for menu_advanced_hide (4845869969015718848) -->
+    <skip />
+    <!-- no translation found for menu_file_size_show (3240323619260823076) -->
+    <skip />
+    <!-- no translation found for menu_file_size_hide (8881975928502581042) -->
+    <skip />
+    <!-- no translation found for button_select (527196987259139214) -->
+    <skip />
+    <!-- no translation found for button_copy (8706475544635021302) -->
+    <skip />
+    <!-- no translation found for button_move (2202666023104202232) -->
+    <skip />
+    <!-- no translation found for button_dismiss (3714065566893946085) -->
+    <skip />
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
+    <!-- no translation found for sort_name (9183560467917256779) -->
+    <skip />
+    <!-- no translation found for sort_date (586080032956151448) -->
+    <skip />
+    <!-- no translation found for sort_size (3350681319735474741) -->
+    <skip />
+    <!-- no translation found for drawer_open (4545466532430226949) -->
+    <skip />
+    <!-- no translation found for drawer_close (7602734368552123318) -->
+    <skip />
+    <!-- no translation found for save_error (6167009778003223664) -->
+    <skip />
+    <!-- no translation found for create_error (3735649141335444215) -->
+    <skip />
+    <!-- no translation found for query_error (1222448261663503501) -->
+    <skip />
+    <!-- no translation found for root_recent (4470053704320518133) -->
+    <skip />
+    <!-- no translation found for root_available_bytes (8568452858617033281) -->
+    <skip />
+    <!-- no translation found for root_type_service (2178854894416775409) -->
+    <skip />
+    <!-- no translation found for root_type_shortcut (3318760609471618093) -->
+    <skip />
+    <!-- no translation found for root_type_device (7121342474653483538) -->
+    <skip />
+    <!-- no translation found for root_type_apps (8838065367985945189) -->
+    <skip />
+    <!-- no translation found for empty (7858882803708117596) -->
+    <skip />
+    <string name="no_results" msgid="6622510343880730446">"Nema utakmica u %1$s"</string>
+    <!-- no translation found for toast_no_application (1339885974067891667) -->
+    <skip />
+    <!-- no translation found for toast_failed_delete (2180678019407244069) -->
+    <skip />
+    <!-- no translation found for share_via (8966594246261344259) -->
+    <skip />
+    <!-- no translation found for copy_notification_title (6374299806748219777) -->
+    <skip />
+    <!-- no translation found for move_notification_title (6193835179777284805) -->
+    <skip />
+    <!-- no translation found for copy_remaining (6283790937387975095) -->
+    <skip />
+    <!-- no translation found for copy_begin (9071199452634086365) -->
+    <!-- no translation found for move_begin (8430330882138871643) -->
+    <!-- no translation found for deleting (5054338566802559411) -->
+    <!-- no translation found for undo (7905788502491742328) -->
+    <skip />
+    <!-- no translation found for copy_preparing (3896202461003039386) -->
+    <skip />
+    <!-- no translation found for move_preparing (2772219441375531410) -->
+    <skip />
+    <string name="delete_preparing" msgid="5655813182533491992">"Pripremanje za brisanje…"</string>
+    <!-- no translation found for copy_error_notification_title (5267616889076217261) -->
+    <!-- no translation found for move_error_notification_title (2779299594174898891) -->
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="one">Nije bilo moguće izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteku</item>
+      <item quantity="few">Nije bilo moguće izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke</item>
+      <item quantity="other">Nije bilo moguće izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Dodirnite za prikaz detalja"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
+    <!-- no translation found for copy_failure_alert_content (3715575000297709082) -->
+    <skip />
+    <!-- no translation found for move_failure_alert_content (7151140279020481180) -->
+    <skip />
+    <!-- no translation found for clipboard_files_clipped (855459017537058539) -->
+    <!-- no translation found for clipboard_files_cannot_paste (2878324825602325706) -->
+    <skip />
+    <string name="menu_rename" msgid="7678802479104285353">"Preimenuj"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Nije uspjelo preimenovanje dokumenta"</string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml
index f01624a..93e92cc 100644
--- a/packages/DocumentsUI/res/values-ca/strings.xml
+++ b/packages/DocumentsUI/res/values-ca/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Dispositius"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Més aplicacions"</string>
     <string name="empty" msgid="7858882803708117596">"Sense elements"</string>
+    <string name="no_results" msgid="6622510343880730446">"No hi ha cap coincidència a %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"No es pot obrir el fitxer."</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"No es poden suprimir alguns documents."</string>
     <string name="share_via" msgid="8966594246261344259">"Comparteix mitjançant"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Desfés"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"S\'està preparant una còpia…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"S\'està preparant per moure\'ls..."</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"S\'està preparant per suprimir…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other">No s\'han pogut copiar <xliff:g id="COUNT_1">%1$d</xliff:g> fitxers</item>
       <item quantity="one">No s\'ha pogut copiar <xliff:g id="COUNT_0">%1$d</xliff:g> fitxer</item>
@@ -92,8 +94,13 @@
       <item quantity="other">No s\'han pogut moure <xliff:g id="COUNT_1">%1$d</xliff:g> fitxers</item>
       <item quantity="one">No s\'ha pogut moure <xliff:g id="COUNT_0">%1$d</xliff:g> fitxer</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Toca per veure els detalls"</string>
-    <string name="retry" msgid="7564024179122207376">"Torna-ho a provar"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other">No s\'han pogut suprimir <xliff:g id="COUNT_1">%1$d</xliff:g> fitxers</item>
+      <item quantity="one">No s\'ha pogut suprimir <xliff:g id="COUNT_0">%1$d</xliff:g> fitxer</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Toca per veure\'n els detalls"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Aquests fitxers no s\'han copiat: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Aquests fitxers no s\'han mogut: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">S\'ha copiat <xliff:g id="COUNT_0">%1$d</xliff:g> fitxer al porta-retalls.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"No s\'han pogut enganxar els fitxers seleccionats en aquesta ubicació."</string>
+    <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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml
index 7c70809..ef2b554 100644
--- a/packages/DocumentsUI/res/values-cs/strings.xml
+++ b/packages/DocumentsUI/res/values-cs/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Zařízení"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Další aplikace"</string>
     <string name="empty" msgid="7858882803708117596">"Žádné položky"</string>
+    <string name="no_results" msgid="6622510343880730446">"%1$s – žádné shody"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Soubor nelze otevřít"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Některé dokumenty nelze smazat"</string>
     <string name="share_via" msgid="8966594246261344259">"Sdílet pomocí"</string>
@@ -90,6 +91,7 @@
     <string name="undo" msgid="7905788502491742328">"Vrátit zpět"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Příprava na kopírování…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Příprava na přesunutí…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Příprava na mazání…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="few">Nepodařilo se zkopírovat <xliff:g id="COUNT_1">%1$d</xliff:g> soubory</item>
       <item quantity="many">Nepodařilo se zkopírovat <xliff:g id="COUNT_1">%1$d</xliff:g> souboru</item>
@@ -102,8 +104,15 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> souborů nelze přesunout</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> soubor nelze přesunout</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Podrobnosti zobrazíte klepnutím"</string>
-    <string name="retry" msgid="7564024179122207376">"Opakovat"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> soubory se smazat nepodařilo</item>
+      <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> souboru se smazat nepodařilo</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> souborů se smazat nepodařilo</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> soubor se smazat nepodařilo</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Klepnutím zobrazíte podrobnosti"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Tyto soubory nebyly zkopírovány: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Následující soubory nebyly přesunuty: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -113,4 +122,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> soubor byl zkopírován do schránky.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Vybrané soubory nelze vložit do tohoto umístění."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Přejmenovat"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Dokument se nepodařilo přejmenovat."</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml
index ef7819a..b80ec57 100644
--- a/packages/DocumentsUI/res/values-da/strings.xml
+++ b/packages/DocumentsUI/res/values-da/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Enheder"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Flere apps"</string>
     <string name="empty" msgid="7858882803708117596">"Ingen elementer"</string>
+    <string name="no_results" msgid="6622510343880730446">"Ingen kampe i %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Filen kan ikke åbnes"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Nogle dokumenter kan ikke slettes"</string>
     <string name="share_via" msgid="8966594246261344259">"Del via"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Fortryd"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Forbereder kopiering…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Forbereder flytning…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Forbereder til sletning…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> filer blev ikke kopieret</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> filer blev ikke kopieret</item>
@@ -92,8 +94,13 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> filer blev ikke flyttet</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> filer blev ikke flyttet</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Tryk for at se yderligere oplysninger."</string>
-    <string name="retry" msgid="7564024179122207376">"Prøv igen"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> fil kunne ikke slettes</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> filer kunne ikke slettes</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Tryk for at se oplysninger"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Disse filer blev ikke kopieret: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Følgende filer blev ikke flyttet: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> filer blev kopieret til udklipsholder.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"De valgte filer kan ikke indsættes på denne placering."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Omdøb"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Dokumentet kunne ikke omdøbes"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml
index 83eb8e0..1363428 100644
--- a/packages/DocumentsUI/res/values-de/strings.xml
+++ b/packages/DocumentsUI/res/values-de/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Geräte"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Weitere Apps"</string>
     <string name="empty" msgid="7858882803708117596">"Keine Dokumente"</string>
+    <string name="no_results" msgid="6622510343880730446">"Keine Übereinstimmungen in %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Datei kann nicht geöffnet werden."</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Einige Dokumente konnten nicht gelöscht werden."</string>
     <string name="share_via" msgid="8966594246261344259">"Teilen über"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Rückgängig machen"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Kopieren wird vorbereitet…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Verschieben wird vorbereitet…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Löschvorgang wird vorbereitet…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> Dateien konnten nicht kopiert werden.</item>
       <item quantity="one"> <xliff:g id="COUNT_0">%1$d</xliff:g> Datei konnte nicht kopiert werden.</item>
@@ -92,8 +94,13 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> Dateien konnten nicht verschoben werden.</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> Datei konnte nicht verschoben werden.</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Zum Einblenden von Details tippen"</string>
-    <string name="retry" msgid="7564024179122207376">"Erneut versuchen"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> Dateien konnten nicht gelöscht werden</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> Datei konnte nicht gelöscht werden</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Zum Ansehen der Details tippen"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Diese Dateien wurden nicht kopiert: <xliff:g id="LIST">%1$s</xliff:g>."</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Diese Dateien wurden nicht verschoben: <xliff:g id="LIST">%1$s</xliff:g>."</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> Datei wurde in die Zwischenablage kopiert.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Die ausgewählten Dateien können an diesem Ort nicht eingefügt werden."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Umbenennen"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Dokument konnte nicht umbenannt werden"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml
index 42959af..a1d28f5 100644
--- a/packages/DocumentsUI/res/values-el/strings.xml
+++ b/packages/DocumentsUI/res/values-el/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"Δεν είναι δυνατό το άνοιγμα του αρχείου"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Δεν είναι δυνατή η διαγραφή ορισμένων εγγράφων"</string>
     <string name="share_via" msgid="8966594246261344259">"Κοινή χρήση μέσω"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"Αγγίξτε για προβολή λεπτομερειών"</string>
-    <string name="retry" msgid="7564024179122207376">"Επανάληψη"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"Πατήστε για προβολή λεπτομερειών"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Αυτά τα αρχεία δεν αντιγράφηκαν: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Αυτά τα αρχεία δεν μετακινήθηκαν: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-en-rAU/strings.xml b/packages/DocumentsUI/res/values-en-rAU/strings.xml
index 5dca8e8..ad4fafd 100644
--- a/packages/DocumentsUI/res/values-en-rAU/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rAU/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Devices"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"More apps"</string>
     <string name="empty" msgid="7858882803708117596">"No items"</string>
+    <string name="no_results" msgid="6622510343880730446">"No matches in %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Cannot open file"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Unable to delete some documents"</string>
     <string name="share_via" msgid="8966594246261344259">"Share via"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Undo"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Preparing for copy…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Preparing for move…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Preparing to delete…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other">Couldn\'t copy <xliff:g id="COUNT_1">%1$d</xliff:g> files</item>
       <item quantity="one">Couldn\'t copy <xliff:g id="COUNT_0">%1$d</xliff:g> file</item>
@@ -92,8 +94,13 @@
       <item quantity="other">Couldn\'t move <xliff:g id="COUNT_1">%1$d</xliff:g> files</item>
       <item quantity="one">Couldn\'t move <xliff:g id="COUNT_0">%1$d</xliff:g> file</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Touch to view details"</string>
-    <string name="retry" msgid="7564024179122207376">"Retry"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other">Couldn\'t delete <xliff:g id="COUNT_1">%1$d</xliff:g> files</item>
+      <item quantity="one">Couldn\'t delete <xliff:g id="COUNT_0">%1$d</xliff:g> file</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Tap to view details"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"These files weren\'t copied: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"These files weren\'t moved: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">Copied <xliff:g id="COUNT_0">%1$d</xliff:g> file to clipboard.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Cannot paste the selected files in this location."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"rename"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Failed to rename document"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml
index 5dca8e8..ad4fafd 100644
--- a/packages/DocumentsUI/res/values-en-rGB/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Devices"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"More apps"</string>
     <string name="empty" msgid="7858882803708117596">"No items"</string>
+    <string name="no_results" msgid="6622510343880730446">"No matches in %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Cannot open file"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Unable to delete some documents"</string>
     <string name="share_via" msgid="8966594246261344259">"Share via"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Undo"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Preparing for copy…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Preparing for move…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Preparing to delete…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other">Couldn\'t copy <xliff:g id="COUNT_1">%1$d</xliff:g> files</item>
       <item quantity="one">Couldn\'t copy <xliff:g id="COUNT_0">%1$d</xliff:g> file</item>
@@ -92,8 +94,13 @@
       <item quantity="other">Couldn\'t move <xliff:g id="COUNT_1">%1$d</xliff:g> files</item>
       <item quantity="one">Couldn\'t move <xliff:g id="COUNT_0">%1$d</xliff:g> file</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Touch to view details"</string>
-    <string name="retry" msgid="7564024179122207376">"Retry"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other">Couldn\'t delete <xliff:g id="COUNT_1">%1$d</xliff:g> files</item>
+      <item quantity="one">Couldn\'t delete <xliff:g id="COUNT_0">%1$d</xliff:g> file</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Tap to view details"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"These files weren\'t copied: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"These files weren\'t moved: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">Copied <xliff:g id="COUNT_0">%1$d</xliff:g> file to clipboard.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Cannot paste the selected files in this location."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"rename"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Failed to rename document"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml
index 5dca8e8..ad4fafd 100644
--- a/packages/DocumentsUI/res/values-en-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Devices"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"More apps"</string>
     <string name="empty" msgid="7858882803708117596">"No items"</string>
+    <string name="no_results" msgid="6622510343880730446">"No matches in %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Cannot open file"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Unable to delete some documents"</string>
     <string name="share_via" msgid="8966594246261344259">"Share via"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Undo"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Preparing for copy…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Preparing for move…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Preparing to delete…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other">Couldn\'t copy <xliff:g id="COUNT_1">%1$d</xliff:g> files</item>
       <item quantity="one">Couldn\'t copy <xliff:g id="COUNT_0">%1$d</xliff:g> file</item>
@@ -92,8 +94,13 @@
       <item quantity="other">Couldn\'t move <xliff:g id="COUNT_1">%1$d</xliff:g> files</item>
       <item quantity="one">Couldn\'t move <xliff:g id="COUNT_0">%1$d</xliff:g> file</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Touch to view details"</string>
-    <string name="retry" msgid="7564024179122207376">"Retry"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other">Couldn\'t delete <xliff:g id="COUNT_1">%1$d</xliff:g> files</item>
+      <item quantity="one">Couldn\'t delete <xliff:g id="COUNT_0">%1$d</xliff:g> file</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Tap to view details"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"These files weren\'t copied: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"These files weren\'t moved: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">Copied <xliff:g id="COUNT_0">%1$d</xliff:g> file to clipboard.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Cannot paste the selected files in this location."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"rename"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Failed to rename document"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml
index 58090ce..53daa40 100644
--- a/packages/DocumentsUI/res/values-es-rUS/strings.xml
+++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Dispositivos"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Más aplicaciones"</string>
     <string name="empty" msgid="7858882803708117596">"Sin elementos"</string>
+    <string name="no_results" msgid="6622510343880730446">"No hay coincidencias en %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"No se puede abrir el archivo."</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"No es posible eliminar algunos documentos."</string>
     <string name="share_via" msgid="8966594246261344259">"Compartir mediante"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Deshacer"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Preparando para copiar…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Preparación para mover archivos…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Preparando para borrar…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other">No se pudieron copiar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos.</item>
       <item quantity="one">No se pudo copiar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo.</item>
@@ -92,8 +94,13 @@
       <item quantity="other">No se pudieron mover <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item>
       <item quantity="one">No se pudo mover <xliff:g id="COUNT_0">%1$d</xliff:g> archivo</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Toca el elemento para ver más información."</string>
-    <string name="retry" msgid="7564024179122207376">"Reintentar"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other">No se pudieron borrar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item>
+      <item quantity="one">No se pudo borrar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Presiona para ver los detalles"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"No se copiaron estos archivos: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"No se movieron los siguientes archivos: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">Se copió <xliff:g id="COUNT_0">%1$d</xliff:g> archivo al portapapeles.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"No se pueden pegar los archivos seleccionados en esta ubicación."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Cambiar nombre"</string>
+    <string name="rename_error" msgid="4203041674883412606">"No se pudo cambiar el nombre del documento"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml
index c91a990..d55220c 100644
--- a/packages/DocumentsUI/res/values-es/strings.xml
+++ b/packages/DocumentsUI/res/values-es/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Dispositivos"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Más aplicaciones"</string>
     <string name="empty" msgid="7858882803708117596">"No hay elementos"</string>
+    <string name="no_results" msgid="6622510343880730446">"Sin coincidencias en %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Error al abrir el archivo"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"No es posible eliminar algunos documentos"</string>
     <string name="share_via" msgid="8966594246261344259">"Compartir a través de"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Deshacer"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Preparando para copiar..."</string>
     <string name="move_preparing" msgid="2772219441375531410">"Preparando para mover…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Preparando para eliminar…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other">No se han podido copiar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item>
       <item quantity="one">No se ha podido copiar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo</item>
@@ -92,8 +94,13 @@
       <item quantity="other">No se han podido mover <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item>
       <item quantity="one">No se ha podido mover <xliff:g id="COUNT_0">%1$d</xliff:g> archivo</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Toca para ver más información"</string>
-    <string name="retry" msgid="7564024179122207376">"Volver a intentar"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other">No se han podido eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item>
+      <item quantity="one">No se ha podido eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Toca para ver detalles"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Archivos que no se han copiado: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Archivos que no se han movido: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">Se ha copiado <xliff:g id="COUNT_0">%1$d</xliff:g> archivo al portapapeles.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Los archivos seleccionados no se pueden pegar en esta ubicación."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Cambiar nombre"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Error al cambiar el nombre del documento"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml
index 55d2503..580e203 100644
--- a/packages/DocumentsUI/res/values-et-rEE/strings.xml
+++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Seadmed"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Rohkem rakendusi"</string>
     <string name="empty" msgid="7858882803708117596">"Üksusi ei ole"</string>
+    <string name="no_results" msgid="6622510343880730446">"Otsing %1$s ei andnud vasteid"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Faili ei saa avada"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Mõnda dokumenti ei õnnestu kustutada"</string>
     <string name="share_via" msgid="8966594246261344259">"Jagage teenusega"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Võta tagasi"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Kopeerimise ettevalmistamine …"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Teisaldamise ettevalmistamine …"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Kustutamise ettevalmistamine …"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> faili ei saanud kopeerida</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> faili ei saanud kopeerida</item>
@@ -92,8 +94,13 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> faili ei saanud teisaldada</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> faili ei saanud teisaldada</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Puudutage üksikasjade vaatamiseks"</string>
-    <string name="retry" msgid="7564024179122207376">"Proovi uuesti"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> faili ei õnnestunud kustutada</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> faili ei õnnestunud kustutada</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Puudutage üksikasjade vaatamiseks"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Neid faile ei kopeeritud: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Neid faile ei teisaldatud: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> fail kopeeriti lõikelauale.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Valitud faile ei saa sellesse asukohta kleepida."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Nimeta ümber"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Dokumendi ümbernimetamine ebaõnnestus"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-eu-rES/strings.xml b/packages/DocumentsUI/res/values-eu-rES/strings.xml
index 7ad1dbc..2dab78b 100644
--- a/packages/DocumentsUI/res/values-eu-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-eu-rES/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Gailuak"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Aplikazio gehiago"</string>
     <string name="empty" msgid="7858882803708117596">"Ez dago elementurik"</string>
+    <string name="no_results" msgid="6622510343880730446">"Ez da aurkitu ezer %1$s atalean"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Ezin da fitxategia ireki"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Ezin izan dira dokumentu batzuk ezabatu"</string>
     <string name="share_via" msgid="8966594246261344259">"Partekatu honen bidez:"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Desegin"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Kopiatzeko prestatzen…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Mugitzeko prestatzen…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Ezabatzeko prestatzen…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other">Ezin izan dira kopiatu <xliff:g id="COUNT_1">%1$d</xliff:g> fitxategi</item>
       <item quantity="one">Ezin izan da kopiatu <xliff:g id="COUNT_0">%1$d</xliff:g> fitxategi</item>
@@ -92,8 +94,13 @@
       <item quantity="other">Ezin izan dira mugitu <xliff:g id="COUNT_1">%1$d</xliff:g> fitxategi</item>
       <item quantity="one">Ezin izan da mugitu <xliff:g id="COUNT_0">%1$d</xliff:g> fitxategi</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Xehetasunak ikusteko, ukitu hau."</string>
-    <string name="retry" msgid="7564024179122207376">"Saiatu berriro"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other">Ezin izan dira ezabatu <xliff:g id="COUNT_1">%1$d</xliff:g> fitxategi</item>
+      <item quantity="one">Ezin izan da ezabatu <xliff:g id="COUNT_0">%1$d</xliff:g> fitxategi</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Sakatu xehetasunak ikusteko"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Ez dira kopiatu fitxategi hauek: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Ez dira mugitu fitxategi hauek: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> fitxategi kopiatu da arbelean.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Ezin dira itsatsi hautatutako fitxategiak kokapen honetan."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Aldatu izena"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Ezin izan zaio aldatu izena dokumentuari"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml
index 1989c62..2cfea03 100644
--- a/packages/DocumentsUI/res/values-fa/strings.xml
+++ b/packages/DocumentsUI/res/values-fa/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"فایل باز نمی‌شود"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"برخی از اسناد حذف نمی‌شوند"</string>
     <string name="share_via" msgid="8966594246261344259">"اشتراک‌گذاری از طریق"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"برای مشاهده جزئیات لمس کنید"</string>
-    <string name="retry" msgid="7564024179122207376">"امتحان مجدد"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"برای مشاهده جزئیات ضربه بزنید"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"این فایل‌ها کپی نشدند: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"این فایل‌ها منتقل نشدند: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml
index 9228634..b4ed0fd 100644
--- a/packages/DocumentsUI/res/values-fi/strings.xml
+++ b/packages/DocumentsUI/res/values-fi/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Laitteet"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Lisää sovelluksia"</string>
     <string name="empty" msgid="7858882803708117596">"Ei kohteita"</string>
+    <string name="no_results" msgid="6622510343880730446">"Ei osumia kohteessa %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Tiedostoa ei voi avata"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Joitakin asiakirjoja ei voi poistaa"</string>
     <string name="share_via" msgid="8966594246261344259">"Jaa sovelluksessa"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Kumoa"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Valmistellaan kopiointia…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Valmistellaan siirtämistä…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Valmistellaan poistamista…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> tiedoston kopioiminen epäonnistui.</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> tiedoston kopioiminen epäonnistui.</item>
@@ -92,8 +94,13 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> tiedoston siirtäminen epäonnistui.</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> tiedoston siirtäminen epäonnistui.</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Lue lisätietoja koskettamalla"</string>
-    <string name="retry" msgid="7564024179122207376">"Yritä uudelleen"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> tiedoston poistaminen epäonnistui</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> tiedoston poistaminen epäonnistui</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Tarkastele tietoja napauttamalla"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Seuraavia tiedostoja ei kopioitu: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Näitä tiedostoja ei siirretty: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> tiedosto kopioitiin leikepöydälle.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Valittuja tiedostoja ei voi liittää tähän sijaintiin."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Nimeä uudelleen"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Dokumentin nimen muuttaminen epäonnistui."</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
index ec81e67..5bbc884 100644
--- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml
+++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Appareils"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Plus d\'applications"</string>
     <string name="empty" msgid="7858882803708117596">"Aucun élément"</string>
+    <string name="no_results" msgid="6622510343880730446">"Aucune correspondance dans %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Impossible d\'ouvrir le fichier"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Impossible de supprimer certains documents"</string>
     <string name="share_via" msgid="8966594246261344259">"Partager par"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Annuler"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Préparation de la copie en cours"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Préparation du déplacement..."</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Préparation de la suppression..."</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="one">Impossible de copier <xliff:g id="COUNT_1">%1$d</xliff:g> fichier</item>
       <item quantity="other">Impossible de copier <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers</item>
@@ -92,8 +94,13 @@
       <item quantity="one">Impossible de déplacer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier</item>
       <item quantity="other">Impossible de déplacer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Touchez ici pour afficher les détails"</string>
-    <string name="retry" msgid="7564024179122207376">"Réessayer"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="one">Impossible de supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossier</item>
+      <item quantity="other">Impossible de supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> dossiers</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Touchez pour afficher les détails"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Ces fichiers ne ont pas été copiés : <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Ces fichiers n\'ont pas été déplacés : <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fichiers ont été copiés dans le presse-papiers.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Impossible de coller les fichiers sélectionnés à cet endroit."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Renommer"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Impossible de renommer le document"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml
index 3d7ab32..2e06b74 100644
--- a/packages/DocumentsUI/res/values-fr/strings.xml
+++ b/packages/DocumentsUI/res/values-fr/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Appareils"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Autres applications"</string>
     <string name="empty" msgid="7858882803708117596">"Aucun élément"</string>
+    <string name="no_results" msgid="6622510343880730446">"Aucune correspondance dans %1$s."</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Impossible d\'ouvrir le fichier."</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Impossible de supprimer certains documents."</string>
     <string name="share_via" msgid="8966594246261344259">"Partager via"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Annuler"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Préparation de la copie en cours…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Préparation au déplacement…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Préparation à la suppression…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="one">Impossible de copier <xliff:g id="COUNT_1">%1$d</xliff:g> fichier</item>
       <item quantity="other">Impossible de copier <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers</item>
@@ -92,8 +94,13 @@
       <item quantity="one">Impossible de déplacer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier</item>
       <item quantity="other">Impossible de déplacer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Appuyez pour en savoir plus."</string>
-    <string name="retry" msgid="7564024179122207376">"Réessayer"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="one">Impossible de supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier</item>
+      <item quantity="other">Impossible de supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Appuyez pour afficher plus d\'informations."</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Les fichiers suivants n\'ont pas été copiés : <xliff:g id="LIST">%1$s</xliff:g>."</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Les fichiers suivants n\'ont pas été déplacés : <xliff:g id="LIST">%1$s</xliff:g>."</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fichiers ont bien été copiés dans le Presse-papiers.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Impossible de coller les fichiers sélectionnés à cet endroit."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Renommer"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Échec du changement de nom du document."</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-gl-rES/strings.xml b/packages/DocumentsUI/res/values-gl-rES/strings.xml
index db98006..5997e3d 100644
--- a/packages/DocumentsUI/res/values-gl-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-gl-rES/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Dispositivos"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Máis aplicacións"</string>
     <string name="empty" msgid="7858882803708117596">"Ningún elemento"</string>
+    <string name="no_results" msgid="6622510343880730446">"Non hai coincidencias en %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Non se pode abrir o ficheiro"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Non se poden eliminar algúns documentos"</string>
     <string name="share_via" msgid="8966594246261344259">"Compartir a través de"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Desfacer"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Preparando para copiar…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Preparándose para mover..."</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Preparando para eliminar…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other">Non se puideron copiar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros</item>
       <item quantity="one">Non se puido copiar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro</item>
@@ -92,8 +94,13 @@
       <item quantity="other">Non se puideron mover <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros</item>
       <item quantity="one">Non se puido mover <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Toca para ver detalles"</string>
-    <string name="retry" msgid="7564024179122207376">"Tentar de novo"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other">Non se puideron eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros</item>
+      <item quantity="one">Non se puido eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Toca para ver detalles"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Non se copiaron estes ficheiros: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Non se moveron estes ficheiros: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">Copiouse <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro no portapapeis.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Non se poden pegar os ficheiros seleccionados nesta localización."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Cambiar nome"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Non se puido cambiar o nome do documento"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-gu-rIN/strings.xml b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
index 9f5eba0..f013e0f 100644
--- a/packages/DocumentsUI/res/values-gu-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"ફાઇલ ખોલી શકાતી નથી"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"કેટલાક દસ્તાવેજો કાઢી નાખવામાં અસમર્થ"</string>
     <string name="share_via" msgid="8966594246261344259">"આના દ્વારા શેર કરો"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"વિગતો જોવા માટે ટચ કરો"</string>
-    <string name="retry" msgid="7564024179122207376">"ફરી પ્રયાસ કરો"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"વિગતો જોવા માટે ટૅપ કરો"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"આ ફાઇલો કૉપિ કરી નહોતી: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"આ ફાઇલો ખસેડી નહોતી: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml
index d146145..008995e 100644
--- a/packages/DocumentsUI/res/values-hi/strings.xml
+++ b/packages/DocumentsUI/res/values-hi/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"फ़ाइल नहीं खोली जा सकती"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"कुछ दस्तावेज़ों को हटाने में अक्षम"</string>
     <string name="share_via" msgid="8966594246261344259">"इसके द्वारा साझा करें"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"विवरण देखने के लिए स्पर्श करें"</string>
-    <string name="retry" msgid="7564024179122207376">"पुन: प्रयास करें"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"विवरणों को देखने के लिए टैप करें"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"इन फ़ाइलों की कॉपी नहीं बनाई गई: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"ये फ़ाइलें नहीं ले जाई गईं: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml
index 5884d6f..d6110a5 100644
--- a/packages/DocumentsUI/res/values-hr/strings.xml
+++ b/packages/DocumentsUI/res/values-hr/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Uređaji"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Više aplikacija"</string>
     <string name="empty" msgid="7858882803708117596">"Nema stavki"</string>
+    <string name="no_results" msgid="6622510343880730446">"%1$s ne sadrži podudaranja"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Datoteku nije moguće otvoriti"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Nije moguće izbrisati neke dokumente"</string>
     <string name="share_via" msgid="8966594246261344259">"Dijeli putem"</string>
@@ -87,6 +88,7 @@
     <string name="undo" msgid="7905788502491742328">"Poništi"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Priprema za kopiranje…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Priprema za premještanje…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Priprema za brisanje…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> datoteka nije kopirana</item>
       <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> datoteke nisu kopirane</item>
@@ -97,8 +99,14 @@
       <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> datoteke nisu premještene</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> datoteka nije premješteno</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Dodirnite da biste vidjeli pojedinosti"</string>
-    <string name="retry" msgid="7564024179122207376">"Pokušaj ponovo"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> datoteka nije izbrisana</item>
+      <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> datoteke nisu izbrisane</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> datoteka nije izbrisano</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Dodirnite da biste vidjeli pojedinosti"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Ove datoteke nisu kopirane: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Ove datoteke nisu premještene: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -107,4 +115,6 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> datoteka kopirano je u međuspremnik.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Nije moguće zalijepiti odabrane datoteke na ovu lokaciju."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Promijeni naziv"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Naziv dokumenta nije promijenjen"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml
index 95b45ba..139b834 100644
--- a/packages/DocumentsUI/res/values-hu/strings.xml
+++ b/packages/DocumentsUI/res/values-hu/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Eszközök"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"További alkalmazások"</string>
     <string name="empty" msgid="7858882803708117596">"Nincsenek elemek"</string>
+    <string name="no_results" msgid="6622510343880730446">"Nincs találat itt: %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"A fájlt nem lehet megnyitni"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Néhány dokumentumot nem lehet törölni"</string>
     <string name="share_via" msgid="8966594246261344259">"Megosztás itt:"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Visszavonás"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Felkészülés a másolásra…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Áthelyezés előkészítése…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Törlés előkészítése…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fájlt nem sikerült átmásolni</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> fájlt nem sikerült átmásolni</item>
@@ -92,8 +94,13 @@
       <item quantity="other">Nem sikerült áthelyezni <xliff:g id="COUNT_1">%1$d</xliff:g> fájlt</item>
       <item quantity="one">Nem sikerült áthelyezni <xliff:g id="COUNT_0">%1$d</xliff:g> fájlt</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Érintse meg a részletek megtekintéséhez"</string>
-    <string name="retry" msgid="7564024179122207376">"Újra"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fájlt nem sikerült törölni</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> fájlt nem sikerült törölni</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Koppintson rá a részletek megtekintéséhez"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"A következő fájlokat nem sikerült átmásolni: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"A következő fájlok nem lettek áthelyezve: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one"> <xliff:g id="COUNT_0">%1$d</xliff:g> fájl vágólapra másolva.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"A kijelölt fájlokat nem lehet beilleszteni erre a helyre."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Átnevezés"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Nem sikerült átnevezni a dokumentumot"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index 7be66d3..8fc7e09 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"Հնարավոր չէ բացել ֆայլը"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Անհնար է ջնջել որոշ փաստաթղթեր"</string>
     <string name="share_via" msgid="8966594246261344259">"Տարածել"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"Հպեք՝ մանրամասները դիտելու համար"</string>
-    <string name="retry" msgid="7564024179122207376">"Կրկնել"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"Հպեք՝ մանրամասները դիտելու համար"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Հետևյալ ֆայլերը չեն պատճենվել՝ <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Հետևյալ ֆայլերը չեն տեղափոխվել՝ <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml
index 29d66c0..0cb438a 100644
--- a/packages/DocumentsUI/res/values-in/strings.xml
+++ b/packages/DocumentsUI/res/values-in/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Perangkat"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Aplikasi lain"</string>
     <string name="empty" msgid="7858882803708117596">"Tidak ada item"</string>
+    <string name="no_results" msgid="6622510343880730446">"Tidak ada kecocokan dalam %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Tidak dapat membuka file"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Tidak dapat menghapus beberapa dokumen"</string>
     <string name="share_via" msgid="8966594246261344259">"Bagikan melalui"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Urungkan"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Menyiapkan salinan..."</string>
     <string name="move_preparing" msgid="2772219441375531410">"Menyiapkan pemindahan…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Bersiap menghapus…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other">Tidak dapat menyalin <xliff:g id="COUNT_1">%1$d</xliff:g> file</item>
       <item quantity="one">Tidak dapat menyalin <xliff:g id="COUNT_0">%1$d</xliff:g> file</item>
@@ -92,8 +94,13 @@
       <item quantity="other">Tidak dapat memindahkan <xliff:g id="COUNT_1">%1$d</xliff:g> file</item>
       <item quantity="one">Tidak dapat memindahkan <xliff:g id="COUNT_0">%1$d</xliff:g> file</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Sentuh untuk melihat detail"</string>
-    <string name="retry" msgid="7564024179122207376">"Coba lagi"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other">Tidak dapat menghapus <xliff:g id="COUNT_1">%1$d</xliff:g> file</item>
+      <item quantity="one">Tidak dapat menghapus <xliff:g id="COUNT_0">%1$d</xliff:g> file</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Ketuk untuk melihat detail"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Semua file ini tidak disalin: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Semua file ini tidak dipindahkan: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one"> <xliff:g id="COUNT_0">%1$d</xliff:g> file disalin ke papan klip.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Tidak dapat menempel file yang dipilih di lokasi ini."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Ganti nama"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Gagal mengganti nama dokumen"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-is-rIS/strings.xml b/packages/DocumentsUI/res/values-is-rIS/strings.xml
index 76dbe32..efd3f7b 100644
--- a/packages/DocumentsUI/res/values-is-rIS/strings.xml
+++ b/packages/DocumentsUI/res/values-is-rIS/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Tæki"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Fleiri forrit"</string>
     <string name="empty" msgid="7858882803708117596">"Engin atriði"</string>
+    <string name="no_results" msgid="6622510343880730446">"Engar samsvarandi niðurstöður í %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Ekki er hægt að opna skrána"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Ekki er hægt að eyða einhverjum skjölum"</string>
     <string name="share_via" msgid="8966594246261344259">"Deila í gegnum"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Afturkalla"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Undirbúningur fyrir afritun…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Flutningur undirbúinn…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Býr sig undir að eyða…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="one">Ekki var hægt að afrita <xliff:g id="COUNT_1">%1$d</xliff:g> skrá</item>
       <item quantity="other">Ekki var hægt að afrita <xliff:g id="COUNT_1">%1$d</xliff:g> skrár</item>
@@ -92,8 +94,13 @@
       <item quantity="one">Ekki tókst að færa <xliff:g id="COUNT_1">%1$d</xliff:g> skrá</item>
       <item quantity="other">Ekki tókst að færa <xliff:g id="COUNT_1">%1$d</xliff:g> skrár</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Snertu til að skoða nánari upplýsingar"</string>
-    <string name="retry" msgid="7564024179122207376">"Reyna aftur"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="one">Ekki tókst að eyða <xliff:g id="COUNT_1">%1$d</xliff:g> skrá</item>
+      <item quantity="other">Ekki tókst að eyða <xliff:g id="COUNT_1">%1$d</xliff:g> skrám</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Ýttu til að skoða frekari upplýsingar"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Þessar skrár voru ekki afritaðar: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Þessar skrár voru ekki færðar: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> skrár afritaðar á klippiborð.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Ekki er hægt að vista valdar skrár á þessum stað."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Endurnefna"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Ekki tókst að endurnefna skjalið"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml
index 2e74550..1b7506d 100644
--- a/packages/DocumentsUI/res/values-it/strings.xml
+++ b/packages/DocumentsUI/res/values-it/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Dispositivi"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Altre app"</string>
     <string name="empty" msgid="7858882803708117596">"Nessun elemento"</string>
+    <string name="no_results" msgid="6622510343880730446">"Nessuna corrispondenza in %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Impossibile aprire il file"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Impossibile eliminare alcuni documenti"</string>
     <string name="share_via" msgid="8966594246261344259">"Condividi via"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Annulla"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Preparazione alla copia…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Preparazione dello spostamento…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Preparazione eliminazione…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other">Impossibile copiare <xliff:g id="COUNT_1">%1$d</xliff:g> file</item>
       <item quantity="one">Impossibile copiare <xliff:g id="COUNT_0">%1$d</xliff:g> file</item>
@@ -92,8 +94,13 @@
       <item quantity="other">Impossibile spostare <xliff:g id="COUNT_1">%1$d</xliff:g> file</item>
       <item quantity="one">Impossibile spostare <xliff:g id="COUNT_0">%1$d</xliff:g> file</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Tocca per visualizzare i dettagli"</string>
-    <string name="retry" msgid="7564024179122207376">"Riprova"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other">Impossibile eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> file</item>
+      <item quantity="one">Impossibile eliminare <xliff:g id="COUNT_0">%1$d</xliff:g> file</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Tocca per vedere i dettagli"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"I seguenti file non sono stati copiati: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"I seguenti file non sono stati spostati: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> file copiato negli appunti.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Impossibile incollare i file selezionati in questa posizione."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Rinomina"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Ridenominazione documento non riuscita"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml
index ed0a6a4..ef966f4 100644
--- a/packages/DocumentsUI/res/values-iw/strings.xml
+++ b/packages/DocumentsUI/res/values-iw/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"לא ניתן לפתוח את הקובץ"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"לא ניתן למחוק חלק מהמסמכים"</string>
     <string name="share_via" msgid="8966594246261344259">"שתף באמצעות"</string>
@@ -90,6 +91,7 @@
     <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="5267616889076217261">
       <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>
@@ -102,8 +104,15 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"גע כדי להציג את הפרטים"</string>
-    <string name="retry" msgid="7564024179122207376">"נסה שוב"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"הקש כדי להציג פרטים"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"הקבצים הבאים לא הועתקו: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"הקבצים הבאים לא הועברו: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -113,4 +122,6 @@
       <item quantity="one">קובץ <xliff:g id="COUNT_0">%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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml
index a954927..932e7fc 100644
--- a/packages/DocumentsUI/res/values-ja/strings.xml
+++ b/packages/DocumentsUI/res/values-ja/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"ファイルを開けません"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"一部のドキュメントを削除できません"</string>
     <string name="share_via" msgid="8966594246261344259">"共有ツール"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"タップして詳細をご覧ください"</string>
-    <string name="retry" msgid="7564024179122207376">"再試行"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"タップすると詳細が表示されます"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"ファイル(<xliff:g id="LIST">%1$s</xliff:g>)をコピーできませんでした"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"ファイル(<xliff:g id="LIST">%1$s</xliff:g>)を移動できませんでした"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
index ef91fab..370e228 100644
--- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml
+++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"ფაილის გახსნა ვერ ხერხდება"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"ზოგიერთი დოკუმენტის წაშლა ვერ ხერხდება"</string>
     <string name="share_via" msgid="8966594246261344259">"გაზიარება:"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"შეეხეთ მონაცემების სანახავად."</string>
-    <string name="retry" msgid="7564024179122207376">"ხელახლა ცდა"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"შეეხეთ დეტალების სანახავად"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"ეს ფაილები არ იყო გადაწერილი: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"ეს ფაილები ვერ გადაადგილდა: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">მოხდა <xliff:g id="COUNT_0">%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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
index 09d7e37..bea34c7 100644
--- a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
+++ b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"Файлды аша алмады"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Кейбір құжаттарды жою мүмкін болмады"</string>
     <string name="share_via" msgid="8966594246261344259">"Бөлісу"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"Толығырақ мәліметті көру үшін түртіңіз"</string>
-    <string name="retry" msgid="7564024179122207376">"Қайталау"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"Мәліметтерді көру үшін түртіңіз"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Мына файлдар көшірілген жоқ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Мына файлдар тасымалданған жоқ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">Аралық сақтағышқа <xliff:g id="COUNT_0">%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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml
index f95594b6..31b8816 100644
--- a/packages/DocumentsUI/res/values-km-rKH/strings.xml
+++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"មិន​អាច​បើក​ឯកសារ"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"មិន​អាច​លុប​ឯកសារ​មួយ​ចំនួន"</string>
     <string name="share_via" msgid="8966594246261344259">"ចែករំលែក​តាម"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"ប៉ះ ដើម្បីមើលព័ត៌មានលម្អិត"</string>
-    <string name="retry" msgid="7564024179122207376">"ព្យាយាមម្ដងទៀត"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"ប៉ះដើម្បីមើលព័ត៌មានលម្អិត"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"ឯកសារទាំងនេះមិនបានចម្លងទេ៖ <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"ឯកសារទាំងនេះមិនអាចផ្លាស់ទីបានទេ៖ <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">បានចម្លងឯកសារ <xliff:g id="COUNT_0">%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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-kn-rIN/strings.xml b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
index 5da5cd0..ab4e90b 100644
--- a/packages/DocumentsUI/res/values-kn-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"ಫೈಲ್ ತೆರೆಯಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"ಕೆಲವು ಡಾಕ್ಯುಮೆಂಟ್‌ಗಳನ್ನು ಅಳಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
     <string name="share_via" msgid="8966594246261344259">"ಈ ಮೂಲಕ ಹಂಚಿಕೊಳ್ಳಿ"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"ವಿವರಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಸ್ಪರ್ಶಿಸಿ"</string>
-    <string name="retry" msgid="7564024179122207376">"ಮರುಪ್ರಯತ್ನಿಸು"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"ವಿವರಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"ಈ ಫೈಲ್‌ಗಳನ್ನು ನಕಲು ಮಾಡಿಲ್ಲ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"ಈ ಫೈಲ್‌ಗಳನ್ನು ಸರಿಸಲಾಗಿಲ್ಲ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml
index 4074841..9bb596d 100644
--- a/packages/DocumentsUI/res/values-ko/strings.xml
+++ b/packages/DocumentsUI/res/values-ko/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"파일을 열 수 없음"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"일부 문서를 삭제할 수 없음"</string>
     <string name="share_via" msgid="8966594246261344259">"공유 방법"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"세부정보를 보려면 터치하세요."</string>
-    <string name="retry" msgid="7564024179122207376">"다시 시도"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"세부정보를 보려면 탭하세요."</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"다음 파일이 복사되지 않았습니다. <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"다음 파일이 이동되지 않았습니다. <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">파일 <xliff:g id="COUNT_0">%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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ky-rKG/strings.xml b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
index 6172c77..c29fc45 100644
--- a/packages/DocumentsUI/res/values-ky-rKG/strings.xml
+++ b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"Файл ачылбады"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Кээ бир документтерди өчүрүү кыйрады"</string>
     <string name="share_via" msgid="8966594246261344259">"Кийинки аркылуу бөлүшүү:"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"Чоо-жайын билүү үчүн тийип коюңуз"</string>
-    <string name="retry" msgid="7564024179122207376">"Дагы аракет кылуу"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"Чоо-жайын көрүү үчүн таптаңыз"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Төмөнкү файлдар көчүрүлгөн жок: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Төмөнкү файлдар жылдырылган жок: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one"> <xliff:g id="COUNT_0">%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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
index baa7e25..223adae 100644
--- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml
+++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"ບໍ່ສາມດາເປີດໄຟລ໌ໄດ້"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"ບໍ່ສາມາດລຶບບາງເອກະສານໄດ້"</string>
     <string name="share_via" msgid="8966594246261344259">"ແບ່ງປັນຜ່ານ"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"ສຳ​ພັດເພື່ອເບິ່ງລາຍລະອຽດ"</string>
-    <string name="retry" msgid="7564024179122207376">"ລອງໃໝ່"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"ແຕະເພື່ອເບິ່ງລາຍລະອຽດ"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"ໄຟ​ລ໌​ເຫຼົ່າ​ນີ້​ບໍ່​ຖື​ກ​ອັດ​ສຳ​ເນົາ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"ໄຟ​ລ໌​ເຫຼົ່າ​ນີ້​ບໍ່​ຖືກ​ຍ້າຍ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">ອັດ​ສຳ​ເນົາ <xliff:g id="COUNT_0">%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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml
index dadd006..8993ffa 100644
--- a/packages/DocumentsUI/res/values-lt/strings.xml
+++ b/packages/DocumentsUI/res/values-lt/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Įrenginiai"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Daugiau programų"</string>
     <string name="empty" msgid="7858882803708117596">"Nėra elementų"</string>
+    <string name="no_results" msgid="6622510343880730446">"Nėra jokių atitikčių pagal %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Nepavyksta atidaryti failo"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Nepavyko ištrinti kai kurių dokumentų"</string>
     <string name="share_via" msgid="8966594246261344259">"Bendrinti naudojant"</string>
@@ -90,6 +91,7 @@
     <string name="undo" msgid="7905788502491742328">"Anuliuoti"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Ruošiamasi kopijuoti…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Ruošiamasi perkelti…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Ruošiama ištrinti…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="one">Nepavyko nukopijuoti <xliff:g id="COUNT_1">%1$d</xliff:g> failo</item>
       <item quantity="few">Nepavyko nukopijuoti <xliff:g id="COUNT_1">%1$d</xliff:g> failų</item>
@@ -102,8 +104,15 @@
       <item quantity="many">Nepavyko perkelti <xliff:g id="COUNT_1">%1$d</xliff:g> failo</item>
       <item quantity="other">Nepavyko perkelti <xliff:g id="COUNT_1">%1$d</xliff:g> failų</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Palieskite, kad peržiūr. išsamią informaciją"</string>
-    <string name="retry" msgid="7564024179122207376">"Bandyti dar kartą"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="one">Nepavyko ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failo</item>
+      <item quantity="few">Nepavyko ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failų</item>
+      <item quantity="many">Nepavyko ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failo</item>
+      <item quantity="other">Nepavyko ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failų</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Palieskite, kad peržiūrėtumėte informaciją"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Šie failai nenukopijuoti: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Šie failai nebuvo perkelti: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -113,4 +122,6 @@
       <item quantity="other">Nukopijuota <xliff:g id="COUNT_1">%1$d</xliff:g> failų į iškarpinę.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Nepavyko įklijuoti pasirinktų failų šioje vietoje."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Pervardyti"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Nepavyko pervardyti dokumento"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml
index 4e0d519..6544834 100644
--- a/packages/DocumentsUI/res/values-lv/strings.xml
+++ b/packages/DocumentsUI/res/values-lv/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Ierīces"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Vairāk lietotņu"</string>
     <string name="empty" msgid="7858882803708117596">"Nav vienumu"</string>
+    <string name="no_results" msgid="6622510343880730446">"Failā %1$s nav atbilstību"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Nevar atvērt failu."</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Nevar dzēst dažus dokumentus."</string>
     <string name="share_via" msgid="8966594246261344259">"Kopīgot, izmantojot"</string>
@@ -87,6 +88,7 @@
     <string name="undo" msgid="7905788502491742328">"Atsaukt"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Gatavošanās kopēšanai…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Sagatavošana pārvietošanai…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Notiek gatavošanās dzēšanai…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="zero">Nevarēja nokopēt <xliff:g id="COUNT_1">%1$d</xliff:g> failus</item>
       <item quantity="one">Nevarēja nokopēt <xliff:g id="COUNT_1">%1$d</xliff:g> failu</item>
@@ -97,8 +99,14 @@
       <item quantity="one">Nevarēja pārvietot <xliff:g id="COUNT_1">%1$d</xliff:g> failu.</item>
       <item quantity="other">Nevarēja pārvietot <xliff:g id="COUNT_1">%1$d</xliff:g> failus.</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Pieskarieties, lai skatītu informāciju"</string>
-    <string name="retry" msgid="7564024179122207376">"Mēģināt vēlreiz"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="zero">Nevarēja izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failus.</item>
+      <item quantity="one">Nevarēja izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failu.</item>
+      <item quantity="other">Nevarēja izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failus.</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Pieskarieties, lai skatītu informāciju"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Netika nokopēti šādi faili: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Šie faili netika pārvietoti: <xliff:g id="LIST">%1$s</xliff:g>."</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -107,4 +115,6 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> faili tika kopēti starpliktuvē.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Atlasītos failus šeit nevar ielīmēt."</string>
+    <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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-mk-rMK/strings.xml b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
index 2d8be1b..ec2ab82 100644
--- a/packages/DocumentsUI/res/values-mk-rMK/strings.xml
+++ b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
@@ -26,7 +26,7 @@
     <string name="menu_list" msgid="7279285939892417279">"Приказ на список"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Подреди по"</string>
     <string name="menu_search" msgid="3816712084502856974">"Пребарај"</string>
-    <string name="menu_settings" msgid="6008033148948428823">"Подесувања"</string>
+    <string name="menu_settings" msgid="6008033148948428823">"Поставки"</string>
     <string name="menu_open" msgid="432922957274920903">"Отвори"</string>
     <string name="menu_save" msgid="2394743337684426338">"Зачувај"</string>
     <string name="menu_share" msgid="3075149983979628146">"Сподели"</string>
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"Датотеката не се отвора"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Некои документи не може да се избришат"</string>
     <string name="share_via" msgid="8966594246261344259">"Сподели преку"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"Допрете за да ги погледнете деталите"</string>
-    <string name="retry" msgid="7564024179122207376">"Обидете се повторно"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"Допрете за да ги погледнете деталите"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Датотекиве не се ископирани: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Овие датотеки не се преместија: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ml-rIN/strings.xml b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
index 1de31ce..6e23f6c 100644
--- a/packages/DocumentsUI/res/values-ml-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"ഫയൽ തുറക്കാനായില്ല"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"ചില പ്രമാണങ്ങൾ ഇല്ലാതാക്കാനായില്ല"</string>
     <string name="share_via" msgid="8966594246261344259">"ഇതുവഴി പങ്കിടുക"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"വിശദാംശങ്ങൾ കാണാൻ സ്‌പർശിക്കുക"</string>
-    <string name="retry" msgid="7564024179122207376">"വീണ്ടും ശ്രമിക്കുക"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"വിശദാംശങ്ങൾ കാണുന്നതിന് ടാപ്പുചെയ്യുക"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"ഈ ഫയലുകൾ പകർത്താനായില്ല: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"ഈ ഫയലുകളെ നീക്കിയില്ല: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
index d0e43f4..137d5eb 100644
--- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml
+++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"Файлыг нээх боломжгүй"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Зарим документуудыг устгах боломжгүй"</string>
     <string name="share_via" msgid="8966594246261344259">"Дараахаар дамжуулан хуваалцах"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"Дэлгэрэнгүй мэдээллийг үзэхийн тулд хүрнэ үү."</string>
-    <string name="retry" msgid="7564024179122207376">"Дахин оролдох"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"Дэлгэрэнгүй мэдээллийг үзэхийн тулд дарна уу"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Дараах файлуудыг хуулаагүй: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Эдгээр файлыг зөөвөрлөөгүй байна: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one"> <xliff:g id="COUNT_0">%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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-mr-rIN/strings.xml b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
index e359e1e..babb452 100644
--- a/packages/DocumentsUI/res/values-mr-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"फाईल उघडू शकत नाही"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"काही दस्‍तऐवज हटविण्‍यात अक्षम"</string>
     <string name="share_via" msgid="8966594246261344259">"द्वारे सामायिक करा"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"तपशील पाहण्यासाठी स्पर्श करा"</string>
-    <string name="retry" msgid="7564024179122207376">"पुन्हा प्रयत्न करा"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"तपशील पाहण्यासाठी टॅप करा"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"या फायली कॉपी झाल्या नाहीत: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"या फायली हलविल्या नव्हत्या: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
index ea88ef6..5d0dbdf 100644
--- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml
+++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Peranti"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Lebih banyak apl"</string>
     <string name="empty" msgid="7858882803708117596">"Tiada item"</string>
+    <string name="no_results" msgid="6622510343880730446">"Tiada padanan dalam %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Tidak dapat membuka fail"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Tidak dapat memadam beberapa dokumen"</string>
     <string name="share_via" msgid="8966594246261344259">"Kongsi melalui"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Buat asal"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Bersedia untuk salin..."</string>
     <string name="move_preparing" msgid="2772219441375531410">"Bersedia untuk mengalih…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Bersedia untuk memadam…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other">Tidak dapat menyalin <xliff:g id="COUNT_1">%1$d</xliff:g> fail</item>
       <item quantity="one">Tidak dapat menyalin <xliff:g id="COUNT_0">%1$d</xliff:g> fail</item>
@@ -92,8 +94,13 @@
       <item quantity="other">Tidak dapat mengalihkan <xliff:g id="COUNT_1">%1$d</xliff:g> fail</item>
       <item quantity="one">Tidak dapat mengalihkan <xliff:g id="COUNT_0">%1$d</xliff:g> fail</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Sentuh untuk melihat butiran"</string>
-    <string name="retry" msgid="7564024179122207376">"Cuba semula"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other">Tidak dapat memadamkan <xliff:g id="COUNT_1">%1$d</xliff:g> fail</item>
+      <item quantity="one">Tidak dapat memadamkan <xliff:g id="COUNT_0">%1$d</xliff:g> fail</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Ketik untuk melihat butiran"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Fail ini tidak disalin: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Fail ini tidak dialihkan: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> fail disalin ke papan keratan.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Tidak boleh menampalkan fail yang dipilih dalam lokasi ini."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Namakan semula"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Gagal menamakan semula dokumen"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-my-rMM/strings.xml b/packages/DocumentsUI/res/values-my-rMM/strings.xml
index 4c8fb49..0621d44 100644
--- a/packages/DocumentsUI/res/values-my-rMM/strings.xml
+++ b/packages/DocumentsUI/res/values-my-rMM/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"ဖိုင်အား ဖွင့်မရပါ"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"တချို့ စာရွက်စာတန်းများ မဖျက်စီးနိုင်ပါ"</string>
     <string name="share_via" msgid="8966594246261344259">"မှ ဝေမျှပါ"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"အသေးစိတ် ကြည့်ရန် ထိပါ။"</string>
-    <string name="retry" msgid="7564024179122207376">"ထပ်စမ်းရန်"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"အသေးစိတ်ကြည့်ရန် တို့ပါ"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"ဤဖိုင်များ ကော်ပီကူးမထားပါ- <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"ဤဖိုင်များကို မရွှေ့ခဲ့ပါ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one"> ဖိုင် <xliff:g id="COUNT_0">%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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml
index 01dda74..c4a8e2a 100644
--- a/packages/DocumentsUI/res/values-nb/strings.xml
+++ b/packages/DocumentsUI/res/values-nb/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Enheter"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Flere apper"</string>
     <string name="empty" msgid="7858882803708117596">"Ingen elementer"</string>
+    <string name="no_results" msgid="6622510343880730446">"Ingen treff i %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Kan ikke åpne filen"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Enkelte dokumenter kunne ikke slettes"</string>
     <string name="share_via" msgid="8966594246261344259">"Del via"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Angre"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Forbereder kopiering …"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Forbereder flytting …"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Gjøres klar for sletting …"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other">Kunne ikke kopiere <xliff:g id="COUNT_1">%1$d</xliff:g> filer</item>
       <item quantity="one">Kunne ikke kopiere <xliff:g id="COUNT_0">%1$d</xliff:g> fil</item>
@@ -92,8 +94,13 @@
       <item quantity="other">Kunne ikke flytte <xliff:g id="COUNT_1">%1$d</xliff:g> filer</item>
       <item quantity="one">Kunne ikke flytte <xliff:g id="COUNT_0">%1$d</xliff:g> fil</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Trykk for å se detaljer"</string>
-    <string name="retry" msgid="7564024179122207376">"Prøv på nytt"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other">Kunne ikke slette <xliff:g id="COUNT_1">%1$d</xliff:g> filer</item>
+      <item quantity="one">Kunne ikke slette <xliff:g id="COUNT_0">%1$d</xliff:g> fil</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Trykk for å se detaljer"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Disse filene ble ikke kopiert: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Disse filene ble ikke flyttet: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">Kopierte <xliff:g id="COUNT_0">%1$d</xliff:g> fil til utklippstavlen.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Kan ikke lime inn de valgte filene her."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Gi nytt navn"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Kunne ikke gi dokumentet nytt navn"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ne-rNP/strings.xml b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
index cd809af..a40edc7 100644
--- a/packages/DocumentsUI/res/values-ne-rNP/strings.xml
+++ b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"फाइल खोल्न सक्दैन"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"केही कागजातहरू मेट्न असमर्थ छ"</string>
     <string name="share_via" msgid="8966594246261344259">"माध्यमबाट साझेदारी गर्नुहोस्"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"विवरणहरू हेर्न छुनुहोस्"</string>
-    <string name="retry" msgid="7564024179122207376">"पुनःप्रयास गर्नुहोस्"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"विवरणहरू हेर्न ट्याप गर्नुहोस्"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"यी फाइलहरू प्रतिलिपि गरिएको थिएनः <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"यी फाइलहरू सारिएनन्: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one"> क्लिपबोर्डमा <xliff:g id="COUNT_0">%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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml
index 5948167..eecc871 100644
--- a/packages/DocumentsUI/res/values-nl/strings.xml
+++ b/packages/DocumentsUI/res/values-nl/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Apparaten"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Meer apps"</string>
     <string name="empty" msgid="7858882803708117596">"Geen items"</string>
+    <string name="no_results" msgid="6622510343880730446">"Geen overeenkomsten in %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Kan bestand niet openen"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Kan bepaalde documenten niet verwijderen"</string>
     <string name="share_via" msgid="8966594246261344259">"Delen via"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Ongedaan maken"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Kopiëren voorbereiden…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Verplaatsen voorbereiden…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Verwijderen voorbereiden…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other">Kan <xliff:g id="COUNT_1">%1$d</xliff:g> bestanden niet kopiëren</item>
       <item quantity="one">Kan <xliff:g id="COUNT_0">%1$d</xliff:g> bestand niet kopiëren</item>
@@ -92,8 +94,13 @@
       <item quantity="other">Kan <xliff:g id="COUNT_1">%1$d</xliff:g> bestanden niet verplaatsen</item>
       <item quantity="one">Kan <xliff:g id="COUNT_0">%1$d</xliff:g> bestand niet verplaatsen</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Tik om details weer te geven"</string>
-    <string name="retry" msgid="7564024179122207376">"Opnieuw proberen"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other">Kan <xliff:g id="COUNT_1">%1$d</xliff:g> bestanden niet verwijderen</item>
+      <item quantity="one">Kan <xliff:g id="COUNT_0">%1$d</xliff:g> bestand niet verwijderen</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Tik om details te bekijken"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Deze bestanden zijn niet gekopieerd: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Deze bestanden zijn niet verplaatst: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> bestand gekopieerd naar klembord.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Kan de geselecteerde bestanden niet plakken op deze locatie."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Naam wijzigen"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Kan naam van document niet wijzigen"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-pa-rIN/strings.xml b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
index dd081ab..075ca4d 100644
--- a/packages/DocumentsUI/res/values-pa-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"ਫਾਈਲ ਨਹੀਂ ਖੋਲ੍ਹ ਸਕਦਾ"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"ਕੁਝ ਦਸਤਾਵੇਜ਼ ਮਿਟਾਉਣ ਵਿੱਚ ਅਸਮਰੱਥ"</string>
     <string name="share_via" msgid="8966594246261344259">"ਇਸ ਰਾਹੀਂ ਸ਼ੇਅਰ ਕਰੋ"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"ਵੇਰਵੇ ਵੇਖਣ ਲਈ ਸਪਰਸ਼ ਕਰੋ"</string>
-    <string name="retry" msgid="7564024179122207376">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"ਵੇਰਵਿਆਂ ਨੂੰ ਵੇਖਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"ਇਹਨਾਂ ਫ਼ਾਈਲਾਂ ਦੀ ਪ੍ਰਤੀਲਿਪੀ ਨਹੀਂ ਬਣਾਈ ਗਈ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"ਇਹਨਾਂ ਫ਼ਾਈਲਾਂ ਨੂੰ ਮੂਵ ਨਹੀਂ ਕੀਤਾ ਗਿਆ: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml
index 3fd3266..3c86b7b 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Urządzenia"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Więcej aplikacji"</string>
     <string name="empty" msgid="7858882803708117596">"Brak elementów"</string>
+    <string name="no_results" msgid="6622510343880730446">"Brak wyników w %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Nie można otworzyć pliku"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Nie można usunąć niektórych dokumentów"</string>
     <string name="share_via" msgid="8966594246261344259">"Udostępnij przez:"</string>
@@ -90,6 +91,7 @@
     <string name="undo" msgid="7905788502491742328">"Cofnij"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Przygotowuję do kopiowania…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Przygotowuję przenoszenie…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Przygotowuję do usunięcia…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="few">Nie można skopiować <xliff:g id="COUNT_1">%1$d</xliff:g> plików</item>
       <item quantity="many">Nie można skopiować <xliff:g id="COUNT_1">%1$d</xliff:g> plików</item>
@@ -102,8 +104,15 @@
       <item quantity="other">Nie udało się przenieść <xliff:g id="COUNT_1">%1$d</xliff:g> pliku</item>
       <item quantity="one">Nie udało się przenieść <xliff:g id="COUNT_0">%1$d</xliff:g> pliku</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Kliknij, by zobaczyć szczegóły"</string>
-    <string name="retry" msgid="7564024179122207376">"Ponów"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="few">Nie udało się usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> plików</item>
+      <item quantity="many">Nie udało się usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> plików</item>
+      <item quantity="other">Nie udało się usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> pliku</item>
+      <item quantity="one">Nie udało się usunąć <xliff:g id="COUNT_0">%1$d</xliff:g> pliku</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Kliknij, by zobaczyć szczegóły"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Te pliki nie zostały skopiowane: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Te pliki nie zostały przeniesione: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -113,4 +122,6 @@
       <item quantity="one">Skopiowano <xliff:g id="COUNT_0">%1$d</xliff:g> plik do schowka.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Nie można wkleić wybranych plików w tej lokalizacji."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Zmień nazwę"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Nie udało się zmienić nazwy dokumentu"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-pt-rBR/strings.xml b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
index dce7cc0..186569c 100644
--- a/packages/DocumentsUI/res/values-pt-rBR/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Dispositivos"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Mais apps"</string>
     <string name="empty" msgid="7858882803708117596">"Nenhum item"</string>
+    <string name="no_results" msgid="6622510343880730446">"Nenhum resultado em %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Não é possível abrir o arquivo"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Não foi possível excluir alguns documentos"</string>
     <string name="share_via" msgid="8966594246261344259">"Compartilhar via"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Desfazer"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Preparando para copiar..."</string>
     <string name="move_preparing" msgid="2772219441375531410">"Preparando para mover..."</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Preparando-se para excluir..."</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="one">Não foi possível copiar <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
       <item quantity="other">Não foi possível copiar <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
@@ -92,8 +94,13 @@
       <item quantity="one">Não foi possível mover <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
       <item quantity="other">Não foi possível mover <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Toque para ver detalhes"</string>
-    <string name="retry" msgid="7564024179122207376">"Repetir"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="one">Não foi possível excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+      <item quantity="other">Não foi possível excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Tocar para ver detalhes"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Estes arquivos não foram copiados: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Estes arquivos não foram movidos: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> arquivos copiados para a área de transferência.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Não é possível colar os arquivos selecionados neste local."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Renomear"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Falha ao renomear documento"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
index 02cd2dd..961330e 100644
--- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Dispositivos"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Mais aplicações"</string>
     <string name="empty" msgid="7858882803708117596">"Sem itens"</string>
+    <string name="no_results" msgid="6622510343880730446">"Sem correspondências para %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Não é possível abrir o ficheiro"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Não é possível eliminar alguns documentos"</string>
     <string name="share_via" msgid="8966594246261344259">"Partilhar através de"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Anular"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"A preparar para copiar…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"A preparar para mover…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"A preparar para eliminar…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other">Não foi possível copiar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros</item>
       <item quantity="one">Não foi possível copiar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro</item>
@@ -92,8 +94,13 @@
       <item quantity="other">Não foi possível mover <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros</item>
       <item quantity="one">Não foi possível mover <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Toque para ver detalhes"</string>
-    <string name="retry" msgid="7564024179122207376">"Tentar novamente"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other">Não foi possível eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros</item>
+      <item quantity="one">Não foi possível eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Toque para ver detalhes"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Os seguintes ficheiros não foram copiados: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Os seguintes ficheiros não foram movidos: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">Copiou <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro para a área de transferência.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Não é possível colar os ficheiros selecionados nesta localização."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Mudar o nome"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Falha ao mudar o nome do documento"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml
index dce7cc0..186569c 100644
--- a/packages/DocumentsUI/res/values-pt/strings.xml
+++ b/packages/DocumentsUI/res/values-pt/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Dispositivos"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Mais apps"</string>
     <string name="empty" msgid="7858882803708117596">"Nenhum item"</string>
+    <string name="no_results" msgid="6622510343880730446">"Nenhum resultado em %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Não é possível abrir o arquivo"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Não foi possível excluir alguns documentos"</string>
     <string name="share_via" msgid="8966594246261344259">"Compartilhar via"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Desfazer"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Preparando para copiar..."</string>
     <string name="move_preparing" msgid="2772219441375531410">"Preparando para mover..."</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Preparando-se para excluir..."</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="one">Não foi possível copiar <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
       <item quantity="other">Não foi possível copiar <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
@@ -92,8 +94,13 @@
       <item quantity="one">Não foi possível mover <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
       <item quantity="other">Não foi possível mover <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Toque para ver detalhes"</string>
-    <string name="retry" msgid="7564024179122207376">"Repetir"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="one">Não foi possível excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+      <item quantity="other">Não foi possível excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Tocar para ver detalhes"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Estes arquivos não foram copiados: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Estes arquivos não foram movidos: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> arquivos copiados para a área de transferência.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Não é possível colar os arquivos selecionados neste local."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Renomear"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Falha ao renomear documento"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml
index 5d32285..4ba7618 100644
--- a/packages/DocumentsUI/res/values-ro/strings.xml
+++ b/packages/DocumentsUI/res/values-ro/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Dispozitive"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Alte aplicații"</string>
     <string name="empty" msgid="7858882803708117596">"Nu există elemente"</string>
+    <string name="no_results" msgid="6622510343880730446">"Niciun rezultat în %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Fișierul nu poate fi deschis"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Unele documente nu au putut fi șterse"</string>
     <string name="share_via" msgid="8966594246261344259">"Trimiteți prin"</string>
@@ -87,6 +88,7 @@
     <string name="undo" msgid="7905788502491742328">"Anulați"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Se pregătește copierea..."</string>
     <string name="move_preparing" msgid="2772219441375531410">"Se pregătește mutarea…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Se pregătește ștergerea…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="few">Nu s-au putut copia <xliff:g id="COUNT_1">%1$d</xliff:g> fișiere</item>
       <item quantity="other">Nu s-au putut copia <xliff:g id="COUNT_1">%1$d</xliff:g> de fișiere</item>
@@ -97,8 +99,14 @@
       <item quantity="other">Nu s-au putut muta <xliff:g id="COUNT_1">%1$d</xliff:g> de fișiere</item>
       <item quantity="one">Nu s-a putut muta <xliff:g id="COUNT_0">%1$d</xliff:g> fișier</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Atingeți pentru a afișa detaliile"</string>
-    <string name="retry" msgid="7564024179122207376">"Reîncercați"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> fișiere nu au fost șterse</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> de fișiere nu au fost șterse</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> fișier nu a fost șters</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Atingeți pentru a vedea detaliile"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Aceste fișiere nu au fost copiate: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Aceste fișiere nu au fost mutate: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -107,4 +115,6 @@
       <item quantity="one">A fost copiat <xliff:g id="COUNT_0">%1$d</xliff:g> fișier în clipboard.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Fișierele selectate nu au putut fi inserate în această locație."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Redenumiți"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Documentul nu a putut fi redenumit"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml
index e68c137..924473a 100644
--- a/packages/DocumentsUI/res/values-ru/strings.xml
+++ b/packages/DocumentsUI/res/values-ru/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"Не удалось открыть файл"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Не удалось удалить некоторые документы"</string>
     <string name="share_via" msgid="8966594246261344259">"Поделиться"</string>
@@ -90,6 +91,7 @@
     <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="5267616889076217261">
       <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>
@@ -102,8 +104,15 @@
       <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="4483108577842961665">"Нажмите, чтобы узнать подробности."</string>
-    <string name="retry" msgid="7564024179122207376">"Повторить"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Не удалось скопировать эти файлы: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Эти файлы не были перемещены: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -113,4 +122,6 @@
       <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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-si-rLK/strings.xml b/packages/DocumentsUI/res/values-si-rLK/strings.xml
index 0f40df9..382bed1 100644
--- a/packages/DocumentsUI/res/values-si-rLK/strings.xml
+++ b/packages/DocumentsUI/res/values-si-rLK/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"ගොනුව විවෘත කළ නොහැක"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"සමහර ලේඛන මැකීමට නොහැකි විය"</string>
     <string name="share_via" msgid="8966594246261344259">"හරහා බෙදාගන්න"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"විස්තර බැලීමට ස්පර්ශ කරන්න"</string>
-    <string name="retry" msgid="7564024179122207376">"නැවත උත්සාහ කරන්න"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"විස්තර බැලීමට තට්ටු කරන්න"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"මෙම ගොනු පිටපත් නොකරන ලදී: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"මෙම ගොනු ගෙන නොයන ලදී: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml
index 2f0cbe8..882f513 100644
--- a/packages/DocumentsUI/res/values-sk/strings.xml
+++ b/packages/DocumentsUI/res/values-sk/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Zariadenia"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Ďalšie aplikácie"</string>
     <string name="empty" msgid="7858882803708117596">"Žiadne položky"</string>
+    <string name="no_results" msgid="6622510343880730446">"Žiadne zhody – %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Súbor sa nepodarilo otvoriť"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Niektoré dokumenty sa nepodarilo odstrániť"</string>
     <string name="share_via" msgid="8966594246261344259">"Zdieľať"</string>
@@ -90,6 +91,7 @@
     <string name="undo" msgid="7905788502491742328">"Späť"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Pripravuje sa na kopírovanie..."</string>
     <string name="move_preparing" msgid="2772219441375531410">"Prebieha príprava na presunutie…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Príprava na odstránenie…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="few">Zlyhalo kopírovanie <xliff:g id="COUNT_1">%1$d</xliff:g> súborov</item>
       <item quantity="many">Zlyhalo kopírovanie <xliff:g id="COUNT_1">%1$d</xliff:g> súboru</item>
@@ -102,8 +104,15 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> súborov nie je možné presunúť</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> súbor nie je možné presunúť</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Klepnutím zobrazíte podrobné informácie"</string>
-    <string name="retry" msgid="7564024179122207376">"Skúsiť znova"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="few">Nepodarilo sa odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súbory</item>
+      <item quantity="many">Nepodarilo sa odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súboru</item>
+      <item quantity="other">Nepodarilo sa odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súborov</item>
+      <item quantity="one">Nepodarilo sa odstrániť <xliff:g id="COUNT_0">%1$d</xliff:g> súbor</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Klepnutím zobrazíte podrobnosti"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Tieto súbory neboli skopírované: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Tieto súbory neboli presunuté: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -113,4 +122,6 @@
       <item quantity="one">Do schránky bol skopírovaný <xliff:g id="COUNT_0">%1$d</xliff:g> súbor.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Do tohto umiestnenia nie je možné prilepiť vybrané súbory"</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Premenovať"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Premenovanie dokumentu zlyhalo"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml
index 6da1290..154fdb2 100644
--- a/packages/DocumentsUI/res/values-sl/strings.xml
+++ b/packages/DocumentsUI/res/values-sl/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Naprave"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Več aplikacij"</string>
     <string name="empty" msgid="7858882803708117596">"Ni elementov"</string>
+    <string name="no_results" msgid="6622510343880730446">"Tukaj ni ujemanj: %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Datoteke ni mogoče odpreti"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Nekaterih dokumentov ni mogoče izbrisati"</string>
     <string name="share_via" msgid="8966594246261344259">"Deli z drugimi prek"</string>
@@ -90,6 +91,7 @@
     <string name="undo" msgid="7905788502491742328">"Razveljavi"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Pripravljanje na kopiranje …"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Priprava na premikanje …"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Pripravljanje na izbris …"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> datoteke ni bilo mogoče kopirati</item>
       <item quantity="two"><xliff:g id="COUNT_1">%1$d</xliff:g> datotek ni bilo mogoče kopirati</item>
@@ -102,8 +104,15 @@
       <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> datotek ni bilo mogoče premakniti</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> datotek ni bilo mogoče premakniti</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Dotaknite se za ogled podrobnosti"</string>
-    <string name="retry" msgid="7564024179122207376">"Poskusi znova"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> datoteke ni bilo mogoče izbrisati</item>
+      <item quantity="two"><xliff:g id="COUNT_1">%1$d</xliff:g> datotek ni bilo mogoče izbrisati</item>
+      <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> datotek ni bilo mogoče izbrisati</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> datotek ni bilo mogoče izbrisati</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Dotaknite se za prikaz podrobnosti"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Te datoteke niso bile kopirane: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Te datoteke niso bile premaknjene: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -113,4 +122,6 @@
       <item quantity="other">V odložišče je bilo kopiranih <xliff:g id="COUNT_1">%1$d</xliff:g> datotek.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Izbranih datotek ni mogoče prilepiti sem."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Preimenuj"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Dokumenta ni bilo mogoče preimenovati"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sq-rAL/strings.xml b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
index b880bb4..bcb4ff0 100644
--- a/packages/DocumentsUI/res/values-sq-rAL/strings.xml
+++ b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Pajisjet"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Aplikacione të tjera"</string>
     <string name="empty" msgid="7858882803708117596">"Nuk ka artikuj"</string>
+    <string name="no_results" msgid="6622510343880730446">"Nuk ka asnjë përputhje në %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Skedari nuk mund të hapet"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"E pamundur të fshihen disa dokumente"</string>
     <string name="share_via" msgid="8966594246261344259">"Shpërnda publikisht përmes"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Zhbëj"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Po përgatitet për kopjimin…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Po përgatitet për zhvendosjen…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Po përgatitet për fshirje…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> skedarë nuk mund të kopjoheshin</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> skedar nuk mund të kopjohej</item>
@@ -92,8 +94,13 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> skedarë nuk mund të zhvendoseshin</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> skedar nuk mund të zhvendosej</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Prek për të parë detajet"</string>
-    <string name="retry" msgid="7564024179122207376">"Provo përsëri"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> skedarë nuk mund të fshiheshin</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> skedar nuk mund të fshihej</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Trokit për të parë detajet"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Këta skedarë nuk u kopjuan: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Këta skedarë nuk u zhvendosën: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">U kopjua <xliff:g id="COUNT_0">%1$d</xliff:g> skedar në kujtesën e fragmenteve.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Skedarët e zgjedhur nuk mund të ngjiten në këtë vendndodhje."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Riemërto"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Riemërtimi i dokumentit dështoi"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml
index 93a1cf6..c0f8099 100644
--- a/packages/DocumentsUI/res/values-sr/strings.xml
+++ b/packages/DocumentsUI/res/values-sr/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"Није могуће отворити датотеку"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Није могуће избрисати неке документе"</string>
     <string name="share_via" msgid="8966594246261344259">"Делите преко"</string>
@@ -87,6 +88,7 @@
     <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="5267616889076217261">
       <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>
@@ -97,8 +99,14 @@
       <item quantity="few">Није успело премештање <xliff:g id="COUNT_1">%1$d</xliff:g> датотекe</item>
       <item quantity="other">Није успело премештање <xliff:g id="COUNT_1">%1$d</xliff:g> датотека</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Додирните да бисте видели детаље"</string>
-    <string name="retry" msgid="7564024179122207376">"Покушај поново"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"Додирните да бисте приказали детаље"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Следеће датотеке нису копиране: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Ове датотеке нису премештене: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -107,4 +115,6 @@
       <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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml
index 63da2c6..e9af1f9 100644
--- a/packages/DocumentsUI/res/values-sv/strings.xml
+++ b/packages/DocumentsUI/res/values-sv/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Enheter"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Fler appar"</string>
     <string name="empty" msgid="7858882803708117596">"Inga objekt"</string>
+    <string name="no_results" msgid="6622510343880730446">"Det finns inga träffar i %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Det går inte att öppna filen"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Det gick inte att ta bort vissa dokument"</string>
     <string name="share_via" msgid="8966594246261344259">"Dela via"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Ångra"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Kopieringen förbereds …"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Förbereder för att flytta …"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Radering förbereds …"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> filer gick inte att kopiera</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> fil gick inte att kopiera</item>
@@ -92,8 +94,13 @@
       <item quantity="other">Det gick inte att flytta <xliff:g id="COUNT_1">%1$d</xliff:g> filer</item>
       <item quantity="one">Det gick inte att flytta <xliff:g id="COUNT_0">%1$d</xliff:g> fil</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Tryck här om du vill veta mer"</string>
-    <string name="retry" msgid="7564024179122207376">"Försök igen"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other">Det gick inte att radera <xliff:g id="COUNT_1">%1$d</xliff:g> filer</item>
+      <item quantity="one">Det gick inte att radera <xliff:g id="COUNT_0">%1$d</xliff:g> fil</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Tryck om du vill visa informationen"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Följande filer kopierades inte: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Följande filer har inte flyttats: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> fil har kopierats till Urklipp.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Det går inte att klistra in den valda filen på den här platsen."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Byt namn"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Det gick inte att byta namn på dokumentet"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index b522e0a..188f5b5 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Vifaa"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Programu zaidi"</string>
     <string name="empty" msgid="7858882803708117596">"Hakuna vipengee"</string>
+    <string name="no_results" msgid="6622510343880730446">"Hakuna zinazolingana katika %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Haiwezi kufungua faili"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Imeshindwa kufuta baadhi ya hati"</string>
     <string name="share_via" msgid="8966594246261344259">"Shiriki kupitia"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Tendua"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Inaanda kunakili..."</string>
     <string name="move_preparing" msgid="2772219441375531410">"Inatayarisha kuhamisha..."</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Inajitayarisha kufuta..."</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other">Haikuweza kunakili faili <xliff:g id="COUNT_1">%1$d</xliff:g> </item>
       <item quantity="one">Haikuweza kunakili faili <xliff:g id="COUNT_0">%1$d</xliff:g></item>
@@ -92,13 +94,20 @@
       <item quantity="other">Haikuweza kuhamisha faili <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="one">Haikuweza kuhamisha faili <xliff:g id="COUNT_0">%1$d</xliff:g></item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Gusa ili uone maelezo"</string>
-    <string name="retry" msgid="7564024179122207376">"Jaribu tena"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other">Haikuweza kufuta faili <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="one">Haikuweza kufuta faili <xliff:g id="COUNT_0">%1$d</xliff:g></item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Gonga ili uangalie maelezo"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Faili hizi hazikunakiliwa: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Faili hizi hazikuhamishwa: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
-      <item quantity="other">Alinakili faili <xliff:g id="COUNT_1">%1$d</xliff:g> kwenye ubaoklipu.</item>
-      <item quantity="one">Alinakili faili <xliff:g id="COUNT_0">%1$d</xliff:g> kwenye ubaoklipu.</item>
+      <item quantity="other">Alinakili faili <xliff:g id="COUNT_1">%1$d</xliff:g> kwenye ubao wa kunakili.</item>
+      <item quantity="one">Alinakili faili <xliff:g id="COUNT_0">%1$d</xliff:g> kwenye ubao wa kunakili.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Haiwezi kubandika faili zilizochaguliwa katika eneo hili."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Badilisha jina"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Imeshindwa kubadilisha jina la hati"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp/dimens.xml b/packages/DocumentsUI/res/values-sw720dp/dimens.xml
index f393d88..2488fa2 100644
--- a/packages/DocumentsUI/res/values-sw720dp/dimens.xml
+++ b/packages/DocumentsUI/res/values-sw720dp/dimens.xml
@@ -15,12 +15,7 @@
 -->
 
 <resources>
-    <bool name="show_as_dialog">true</bool>
-
-    <item type="dimen" name="dialog_width">85%</item>
-
     <dimen name="grid_padding_horiz">16dp</dimen>
     <dimen name="grid_padding_vert">16dp</dimen>
 
-    <dimen name="grid_item_margin">8dp</dimen>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp/layouts.xml b/packages/DocumentsUI/res/values-sw720dp/layouts.xml
deleted file mode 100644
index 7d28f9c..0000000
--- a/packages/DocumentsUI/res/values-sw720dp/layouts.xml
+++ /dev/null
@@ -1,19 +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>
-    <item name="docs_activity" type="layout">@layout/fixed_layout</item>
-</resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp/styles.xml b/packages/DocumentsUI/res/values-sw720dp/styles.xml
deleted file mode 100644
index a8dcbb0..0000000
--- a/packages/DocumentsUI/res/values-sw720dp/styles.xml
+++ /dev/null
@@ -1,26 +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.
--->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <style name="DocumentsBaseTheme" parent="@style/Theme.AppCompat.Light.Dialog">
-        <!-- We do not specify width of window here because the max size of
-             floating window specified by windowFixedWidthis is limited. -->
-        <item name="*android:windowFixedHeightMajor">80%</item>
-        <item name="*android:windowFixedHeightMinor">90%</item>
-    </style>
-
-</resources>
diff --git a/packages/DocumentsUI/res/values-ta-rIN/strings.xml b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
index 87cb68d..a6d52c4 100644
--- a/packages/DocumentsUI/res/values-ta-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"கோப்பைத் திறக்க முடியவில்லை"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"சில ஆவணங்களை நீக்க முடியவில்லை"</string>
     <string name="share_via" msgid="8966594246261344259">"இதன் வழியாகப் பகிர்"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"விவரங்களைப் பார்க்க, தொடவும்"</string>
-    <string name="retry" msgid="7564024179122207376">"மீண்டும் முயற்சிக்கவும்"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"விவரங்களைப் பார்க்க, தட்டவும்"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"நகலெடுக்கப்படாத கோப்புகள்: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"இந்தக் கோப்புகள் நகர்த்தப்படவில்லை: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">கிளிப்போர்டிற்கு <xliff:g id="COUNT_0">%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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-te-rIN/strings.xml b/packages/DocumentsUI/res/values-te-rIN/strings.xml
index 7b34df5..b2ac712 100644
--- a/packages/DocumentsUI/res/values-te-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-te-rIN/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"ఫైల్‌ను తెరవడం సాధ్యపడదు"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"కొన్ని పత్రాలను తొలగించడం సాధ్యపడలేదు"</string>
     <string name="share_via" msgid="8966594246261344259">"దీని ద్వారా భాగస్వామ్యం చేయండి"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"వివరాలను వీక్షించడానికి తాకండి"</string>
-    <string name="retry" msgid="7564024179122207376">"మళ్లీ ప్రయత్నించు"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"వివరాలను వీక్షించడానికి నొక్కండి"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"ఈ ఫైల్‌లు కాపీ చేయబడలేదు: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"ఈ ఫైల్‌లు తరలించబడలేదు: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">క్లిప్‌బోర్డ్‌కి <xliff:g id="COUNT_0">%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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml
index dfb423e..3261019 100644
--- a/packages/DocumentsUI/res/values-th/strings.xml
+++ b/packages/DocumentsUI/res/values-th/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"ไม่สามารถเปิดไฟล์ได้"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"ไม่สามารถลบเอกสารบางรายการ"</string>
     <string name="share_via" msgid="8966594246261344259">"แชร์ผ่าน"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"แตะเพื่อดูรายละเอียด"</string>
-    <string name="retry" msgid="7564024179122207376">"ลองอีกครั้ง"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"แตะเพื่อดูรายละเอียด"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"ไม่มีการคัดลอกไฟล์เหล่านี้: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"ไม่มีการย้ายไฟล์เหล่านี้: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">คัดลอก <xliff:g id="COUNT_0">%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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml
index 813b39a..6548908 100644
--- a/packages/DocumentsUI/res/values-tl/strings.xml
+++ b/packages/DocumentsUI/res/values-tl/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Mga Device"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Higit pang apps"</string>
     <string name="empty" msgid="7858882803708117596">"Walang mga item"</string>
+    <string name="no_results" msgid="6622510343880730446">"Walang mga katugma sa %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Hindi mabuksan ang file"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Hindi matanggal ang ilang dokumento"</string>
     <string name="share_via" msgid="8966594246261344259">"Ibahagi sa pamamagitan ng"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"I-undo"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Naghahanda para sa pagkopya…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Naghahanda para sa paglilipat…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Naghahanda para sa pag-delete…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="one">Hindi makopya ang <xliff:g id="COUNT_1">%1$d</xliff:g> file</item>
       <item quantity="other">Hindi makopya ang <xliff:g id="COUNT_1">%1$d</xliff:g> na file</item>
@@ -92,8 +94,13 @@
       <item quantity="one">Hindi nailipat ang <xliff:g id="COUNT_1">%1$d</xliff:g> file</item>
       <item quantity="other">Hindi nailipat ang <xliff:g id="COUNT_1">%1$d</xliff:g> na file</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Pindutin upang tingnan ang mga detalye"</string>
-    <string name="retry" msgid="7564024179122207376">"Subukang muli"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="one">Hindi ma-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> file</item>
+      <item quantity="other">Hindi ma-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> na file</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"I-tap upang tingnan ang mga detalye"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Hindi nakopya ang mga file na ito: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Hindi nailipat ang mga file na ito: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="other">Nakopya ang <xliff:g id="COUNT_1">%1$d</xliff:g> na file sa clipboard.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Hindi mai-paste sa lokasyong ito ang mga piniling file."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Palitan ang pangalan"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Hindi napalitan ang pangalan ng dokumento"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml
index 90794a2..2db4a1b 100644
--- a/packages/DocumentsUI/res/values-tr/strings.xml
+++ b/packages/DocumentsUI/res/values-tr/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Cihazlar"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Diğer uygulamalar"</string>
     <string name="empty" msgid="7858882803708117596">"Öğe yok"</string>
+    <string name="no_results" msgid="6622510343880730446">"%1$s içinde eşleşme bulunamadı"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Dosya açılamıyor"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Bazı dokümanlar silinemiyor"</string>
     <string name="share_via" msgid="8966594246261344259">"Şunu kullanarak paylaş:"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Geri al"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Kopyalanmak için hazırlanıyor…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Taşıma için hazırlanıyor…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Silmek için hazırlanıyor…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dosya kopyalanamadı</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dosya kopyalanamadı</item>
@@ -92,8 +94,13 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dosya taşınamadı</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dosya taşınamadı</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Ayrıntıları görüntülemek için dokunun"</string>
-    <string name="retry" msgid="7564024179122207376">"Yeniden dene"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dosya silinemedi</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dosya silinemedi</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Ayrıntıları görmek için hafifçe dokunun"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Şu dosyalar kopyalanmadı: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Şu dosyalar taşınmadı: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dosya panoya kopyalandı.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Seçili dosyalar bu konuma yapıştırılamıyor."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Yeniden Adlandır"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Dokümanın adı değiştirilemedi"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml
index a8278d9..8624aec 100644
--- a/packages/DocumentsUI/res/values-uk/strings.xml
+++ b/packages/DocumentsUI/res/values-uk/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"Не вдалося відкрити файл"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Не вдалося видалити деякі документи"</string>
     <string name="share_via" msgid="8966594246261344259">"Надіслати через"</string>
@@ -90,6 +91,7 @@
     <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="5267616889076217261">
       <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>
@@ -102,8 +104,15 @@
       <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="4483108577842961665">"Торкніться, щоб дізнатися більше"</string>
-    <string name="retry" msgid="7564024179122207376">"Повторити"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Ці файли не скопійовано: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Не переміщено ці файли: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -113,4 +122,6 @@
       <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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ur-rPK/strings.xml b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
index d8caa37..6ddad5f 100644
--- a/packages/DocumentsUI/res/values-ur-rPK/strings.xml
+++ b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"فائل نہيں کھول سکتے ہیں"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"کچھ دستاویزات کو حذف کرنے سے قاصر"</string>
     <string name="share_via" msgid="8966594246261344259">"اشتراک کریں بذریعہ"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"تفصیلات دیکھنے کیلئے ٹچ کریں"</string>
-    <string name="retry" msgid="7564024179122207376">"دوبارہ کوشش کریں"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"تفصیلات دیکھنے کیلئے تھپتھپائیں"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"یہ فائلز کاپی نہیں کی گئیں: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"یہ فائلیں منتقل نہیں ہوئیں: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
index 1b5ace4..78e48c6 100644
--- a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
+++ b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Qurilmalar"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Ko‘proq dasturlar"</string>
     <string name="empty" msgid="7858882803708117596">"Hech narsa yo‘q"</string>
+    <string name="no_results" msgid="6622510343880730446">"%1$s jildidan topilmadi"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Fayl ochilmadi"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Ba’zi hujjatlar o‘chirilmadi"</string>
     <string name="share_via" msgid="8966594246261344259">"Quyidagi orqali ulashish"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Bekor qilish"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Nuxsa olishga tayyorgarlik..."</string>
     <string name="move_preparing" msgid="2772219441375531410">"Ko‘chirishga tayyorgarlik…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"O‘chirishga tayyorlanmoqda…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta fayldan nusxa olinmadi</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta fayldan nusxa olinmadi</item>
@@ -92,8 +94,13 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta fayl ko‘chirib o‘tkazilmadi</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta fayl ko‘chirib o‘tkazilmadi</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Batafsil ma’lumot olish uchun bosing"</string>
-    <string name="retry" msgid="7564024179122207376">"Qayta urinish"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta faylni o‘chirib bo‘lmadi</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta faylni o‘chirib bo‘lmadi</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Batafsil ma’lumot olish uchun bosing"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Ushbu fayllardan nusxa olinmadi: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Ushbu fayllar ko‘chirib o‘tkazilmadi: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta fayldan vaqtinchalik xotiraga nusxa olindi.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Tanlangan fayllarni bu yerga joylab bo‘lmadi."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Qayta nomlash"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Hujjatni qayta nomlab bo‘lmadi"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml
index 287ca70..3f44f62 100644
--- a/packages/DocumentsUI/res/values-vi/strings.xml
+++ b/packages/DocumentsUI/res/values-vi/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Thiết bị"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Các ứng dụng khác"</string>
     <string name="empty" msgid="7858882803708117596">"Không có mục nào"</string>
+    <string name="no_results" msgid="6622510343880730446">"Không có kết quả phù hợp trong %1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Không thể mở tệp"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Không thể xóa một số tài liệu"</string>
     <string name="share_via" msgid="8966594246261344259">"Chia sẻ qua"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Hoàn tác"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Đang chuẩn bị sao chép…"</string>
     <string name="move_preparing" msgid="2772219441375531410">"Đang chuẩn bị di chuyển…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Đang chuẩn bị xóa…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="other">Không thể sao chép <xliff:g id="COUNT_1">%1$d</xliff:g> tệp</item>
       <item quantity="one">Không thể sao chép <xliff:g id="COUNT_0">%1$d</xliff:g> tệp</item>
@@ -92,8 +94,13 @@
       <item quantity="other">Không thể di chuyển <xliff:g id="COUNT_1">%1$d</xliff:g> tệp</item>
       <item quantity="one">Không thể di chuyển <xliff:g id="COUNT_0">%1$d</xliff:g> tệp</item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Chạm để xem chi tiết"</string>
-    <string name="retry" msgid="7564024179122207376">"Thử lại"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="other">Không thể xóa <xliff:g id="COUNT_1">%1$d</xliff:g> tệp</item>
+      <item quantity="one">Không thể xóa <xliff:g id="COUNT_0">%1$d</xliff:g> tệp</item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Nhấn để xem chi tiết"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Những tệp này chưa được sao chép: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Những tệp này chưa được di chuyển: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">Đã sao chép <xliff:g id="COUNT_0">%1$d</xliff:g> tệp vào khay nhớ tạm.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Không thể dán các tệp đã chọn vào vị trí này."</string>
+    <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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
index 9901abf..c8b4a82 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"无法打开文件"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"无法删除部分文档"</string>
     <string name="share_via" msgid="8966594246261344259">"分享方式"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"触摸可查看详情"</string>
-    <string name="retry" msgid="7564024179122207376">"重试"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"点按即可查看详情"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"以下文件无法复制:<xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"以下文件无法移动:<xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">已将 <xliff:g id="COUNT_0">%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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index 9cfba1d..46c1be3 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"無法開啟檔案"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"無法刪除部分文件"</string>
     <string name="share_via" msgid="8966594246261344259">"分享方式:"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"輕觸即可查看詳情"</string>
-    <string name="retry" msgid="7564024179122207376">"重試"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"輕按即可查看詳細資訊"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"以下檔案未能複製:<xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"這些檔案並未移動:<xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">已複製 <xliff:g id="COUNT_0">%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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
index b2cee9c..1502176 100644
--- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
@@ -63,6 +63,7 @@
     <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="1339885974067891667">"無法開啟檔案"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"無法刪除部分文件"</string>
     <string name="share_via" msgid="8966594246261344259">"分享方式:"</string>
@@ -84,6 +85,7 @@
     <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="5267616889076217261">
       <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>
@@ -92,8 +94,13 @@
       <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="notification_touch_for_details" msgid="4483108577842961665">"輕觸即可查看詳細資料"</string>
-    <string name="retry" msgid="7564024179122207376">"重試"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <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="notification_touch_for_details" msgid="6268189413228855582">"輕按即可查看詳細資訊"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"未複製這些檔案:<xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"未移動以下檔案:<xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="one">已將 <xliff:g id="COUNT_0">%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>
 </resources>
diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml
index 308a6f9..44f82cf 100644
--- a/packages/DocumentsUI/res/values-zu/strings.xml
+++ b/packages/DocumentsUI/res/values-zu/strings.xml
@@ -63,6 +63,7 @@
     <string name="root_type_device" msgid="7121342474653483538">"Amadivayisi"</string>
     <string name="root_type_apps" msgid="8838065367985945189">"Izinhlelo zokusebenza eziningi"</string>
     <string name="empty" msgid="7858882803708117596">"Azikho izinto"</string>
+    <string name="no_results" msgid="6622510343880730446">"Akukho okufanayo ku-%1$s"</string>
     <string name="toast_no_application" msgid="1339885974067891667">"Ayikwazi ukuvula ifayela"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Ayikwazi ukususa amanye amadokhumenti"</string>
     <string name="share_via" msgid="8966594246261344259">"Yabelana nge-"</string>
@@ -84,6 +85,7 @@
     <string name="undo" msgid="7905788502491742328">"Hlehlisa"</string>
     <string name="copy_preparing" msgid="3896202461003039386">"Ilungiselela ukukopisha..."</string>
     <string name="move_preparing" msgid="2772219441375531410">"Ilungiselela ukuhambisa…"</string>
+    <string name="delete_preparing" msgid="5655813182533491992">"Ilungiselela ukususa…"</string>
     <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
       <item quantity="one">Ayikwazanga ukukopisha amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="other">Ayikwazanga ukukopisha amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g></item>
@@ -92,8 +94,13 @@
       <item quantity="one">Ayikwazanga ukuhambisa amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="other">Ayikwazanga ukuhambisa amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g></item>
     </plurals>
-    <string name="notification_touch_for_details" msgid="4483108577842961665">"Thinta ukuze ubuke imininingwane"</string>
-    <string name="retry" msgid="7564024179122207376">"Zama futhi"</string>
+    <plurals name="delete_error_notification_title" formatted="false" msgid="7600379830348969563">
+      <item quantity="one">Ayikwazanga ukususa amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g></item>
+      <item quantity="other">Ayikwazanga ukususa amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g></item>
+    </plurals>
+    <string name="notification_touch_for_details" msgid="6268189413228855582">"Thepha ukuze ubuke imininingwane"</string>
+    <!-- no translation found for close (3043722427445528732) -->
+    <skip />
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Lawa mafayela awazange akopishwe: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Lawa mafayela awazange ahanjiswe: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
@@ -101,4 +108,6 @@
       <item quantity="other">Kukopishwe amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g> kubhodi lokunamathisela.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Ayikwazi ukunamathisela amafayela akhethiwe kule ndawo."</string>
+    <string name="menu_rename" msgid="7678802479104285353">"Qamba kabusha"</string>
+    <string name="rename_error" msgid="4203041674883412606">"Yehlulekile ukuqamba kabusha idokhumenti"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values/attrs.xml b/packages/DocumentsUI/res/values/attrs.xml
index 0afc3a2..9e13001 100644
--- a/packages/DocumentsUI/res/values/attrs.xml
+++ b/packages/DocumentsUI/res/values/attrs.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <resources>
-    <declare-styleable name="DocumentsBaseTheme">
+    <declare-styleable name="DocumentsTheme">
         <attr name="colorActionMode" format="color"/>
     </declare-styleable>
 </resources>
diff --git a/packages/DocumentsUI/res/values/colors.xml b/packages/DocumentsUI/res/values/colors.xml
index 153c673..c868d34 100644
--- a/packages/DocumentsUI/res/values/colors.xml
+++ b/packages/DocumentsUI/res/values/colors.xml
@@ -33,4 +33,6 @@
     <color name="item_doc_background">#fffafafa</color>
     <color name="item_doc_background_selected">#ffe0f2f1</color>
 
+    <color name="menu_search_background">#ff676f74</color>
+
 </resources>
diff --git a/packages/DocumentsUI/res/values/config.xml b/packages/DocumentsUI/res/values/config.xml
index ff28e15..e8d8c8e 100644
--- a/packages/DocumentsUI/res/values/config.xml
+++ b/packages/DocumentsUI/res/values/config.xml
@@ -18,7 +18,6 @@
     <!-- Allow Advanced Devices default value to be customised -->
     <bool name="config_defaultAdvancedDevices">false</bool>
 
-    <bool name="productivity_device">true</bool>
     <!-- Intentionally unset. Vendors should set this in an overlay. -->
     <string name="trusted_quick_viewer_package"></string>
 </resources>
diff --git a/packages/DocumentsUI/res/values/dimens.xml b/packages/DocumentsUI/res/values/dimens.xml
index f94a00e..5adb165 100644
--- a/packages/DocumentsUI/res/values/dimens.xml
+++ b/packages/DocumentsUI/res/values/dimens.xml
@@ -15,9 +15,18 @@
 -->
 
 <resources>
+    <dimen name="grid_container_padding">10dp</dimen>
+    <dimen name="list_container_padding">0dp</dimen>
+
     <dimen name="icon_size">40dp</dimen>
     <dimen name="root_icon_size">24dp</dimen>
     <dimen name="root_icon_margin">0dp</dimen>
+    <dimen name="check_icon_size">30dp</dimen>
+
+    <dimen name="list_item_thumbnail_size">40dp</dimen>
+    <dimen name="grid_item_icon_size">30dp</dimen>
+
+    <dimen name="progress_bar_height">4dp</dimen>
 
     <dimen name="grid_width">152dp</dimen>
     <dimen name="grid_height">176dp</dimen>
@@ -35,7 +44,6 @@
     <dimen name="list_divider_inset">72dp</dimen>
     <bool name="list_divider_inset_left">true</bool>
 
-    <bool name="show_as_dialog">false</bool>
     <bool name="always_show_summary">false</bool>
 
     <dimen name="dir_elevation">8dp</dimen>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index 016657e..afe9336 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -65,13 +65,9 @@
     <string name="menu_paste_from_clipboard">Paste</string>
 
     <!-- Menu item that reveals internal storage built into the device [CHAR LIMIT=24] -->
-    <string name="menu_advanced_show" product="nosdcard">Show internal storage</string>
-    <!-- Menu item that reveals SD cards built into the device [CHAR LIMIT=24] -->
-    <string name="menu_advanced_show" product="default">Show SD card</string>
+    <string name="menu_advanced_show">Show internal storage</string>
     <!-- Menu item that hides internal storage built into the device [CHAR LIMIT=24] -->
-    <string name="menu_advanced_hide" product="nosdcard">Hide internal storage</string>
-    <!-- Menu item that hides SD cards built into the device [CHAR LIMIT=24] -->
-    <string name="menu_advanced_hide" product="default">Hide SD card</string>
+    <string name="menu_advanced_hide">Hide internal storage</string>
 
     <!-- Menu item that reveals the sizes of displayed files [CHAR LIMIT=24] -->
     <string name="menu_file_size_show">Show file size</string>
@@ -87,7 +83,7 @@
     <!-- Button label that hides the error bar [CHAR LIMIT=24] -->
     <string name="button_dismiss">Dismiss</string>
     <string name="button_retry">Try Again</string>
-    
+
     <!-- Mode that sorts documents by their display name alphabetically [CHAR LIMIT=24] -->
     <string name="sort_name">By name</string>
     <!-- Mode that sorts documents by their last modified time in descending order; most recent first [CHAR LIMIT=24] -->
@@ -123,6 +119,8 @@
 
     <!-- Text shown when a directory of documents is empty [CHAR LIMIT=24] -->
     <string name="empty">No items</string>
+    <!-- Text shown when a file search returns no items [CHAR LIMIT=32] -->
+    <string name="no_results">No matches in %1$s</string>
 
     <!-- Toast shown when no app can be found to open the selected document [CHAR LIMIT=48] -->
     <string name="toast_no_application">Can\'t open file</string>
@@ -158,6 +156,8 @@
     <string name="copy_preparing">Preparing for copy\u2026</string>
     <!-- Text shown on the notification while DocumentsUI performs setup in preparation for moving files [CHAR LIMIT=32] -->
     <string name="move_preparing">Preparing for move\u2026</string>
+    <!-- Text shown on the notification while DocumentsUI performs setup in preparation for deleting files [CHAR LIMIT=32] -->
+    <string name="delete_preparing">Preparing for delete\u2026</string>
     <!-- Title of the copy error notification [CHAR LIMIT=48] -->
     <plurals name="copy_error_notification_title">
         <item quantity="one">Couldn\'t copy <xliff:g id="count" example="1">%1$d</xliff:g> file</item>
@@ -168,14 +168,21 @@
         <item quantity="one">Couldn\'t move <xliff:g id="count" example="1">%1$d</xliff:g> file</item>
         <item quantity="other">Couldn\'t move <xliff:g id="count" example="2">%1$d</xliff:g> files</item>
     </plurals>
+    <!-- Title of the delete error notification [CHAR LIMIT=48] -->
+    <plurals name="delete_error_notification_title">
+        <item quantity="one">Couldn\'t delete <xliff:g id="count" example="1">%1$d</xliff:g> file</item>
+        <item quantity="other">Couldn\'t delete <xliff:g id="count" example="2">%1$d</xliff:g> files</item>
+    </plurals>
     <!-- Second line for notifications saying that more information will be shown after touching [CHAR LIMIT=48] -->
-    <string name="notification_touch_for_details">Touch to view details</string>
-    <!-- Label of a dialog button for retrying a failed operation [CHAR LIMIT=24] -->
-    <string name="retry">Retry</string>
+    <string name="notification_touch_for_details">Tap to view details</string>
+    <!-- Label of the close dialog button.[CHAR LIMIT=24] -->
+    <string name="close">Close</string>
     <!-- Contents of the copying failure alert dialog. [CHAR LIMIT=48] -->
     <string name="copy_failure_alert_content">These files weren\'t copied: <xliff:g id="list">%1$s</xliff:g></string>
     <!-- Contents of the moving failure alert dialog. [CHAR LIMIT=48] -->
     <string name="move_failure_alert_content">These files weren\'t moved: <xliff:g id="list">%1$s</xliff:g></string>
+    <!-- Contents of the copying warning dialog due to converted files. [CHAR LIMIT=64] -->
+    <string name="copy_converted_warning_content">These files were converted to another format: <xliff:g id="list" example="Document.pdf, Photo.jpg, Song.ogg">%1$s</xliff:g></string>
     <!-- Toast shown when a user copies files to clipboard. -->
     <plurals name="clipboard_files_clipped">
         <item quantity="one">Copied <xliff:g id="count" example="1">%1$d</xliff:g> file to clipboard.</item>
@@ -183,4 +190,20 @@
     </plurals>
     <!-- Toast shown when a user tries to paste files into an unsupported location. -->
     <string name="clipboard_files_cannot_paste">Cannot paste the selected files in this location.</string>
+    <!-- Menu item that renames the selected document [CHAR LIMIT=24] -->
+    <string name="menu_rename">Rename</string>
+    <!-- Toast shown when renaming document failed with an error [CHAR LIMIT=48] -->
+    <string name="rename_error">Failed to rename document</string>
+    <!-- First line for notifications saying that some files were converted to a different format
+         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) -->
+    <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
+        <xliff:g id="storage" example="SD Card"><i>^3</i></xliff:g>?</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>
 </resources>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index 6712e2d..f4dfd73 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -16,31 +16,10 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <style name="DocumentsBaseTheme" parent="@style/Theme.AppCompat.Light.DarkActionBar" />
     <style name="ActionBarTheme" parent="@*android:style/ThemeOverlay.Material.Dark.ActionBar" />
     <style name="ActionBarPopupTheme" parent="@*android:style/ThemeOverlay.Material.Light" />
 
-    <style name="DocumentsTheme" parent="@style/DocumentsBaseTheme">
-        <item name="actionBarWidgetTheme">@null</item>
-        <item name="actionBarTheme">@style/ActionBarTheme</item>
-        <item name="actionBarPopupTheme">@style/ActionBarPopupTheme</item>
-
-        <item name="android:windowBackground">@color/window_background</item>
-        <item name="android:colorPrimaryDark">@color/primary_dark</item>
-        <item name="android:colorPrimary">@color/primary</item>
-        <item name="android:colorAccent">@color/accent</item>
-        <item name="colorActionMode">@color/action_mode</item>
-
-        <item name="android:listDivider">@*android:drawable/list_divider_material</item>
-
-        <item name="android:windowActionBar">false</item>
-        <item name="android:windowActionModeOverlay">true</item>
-        <item name="android:windowNoTitle">true</item>
-
-        <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
-    </style>
-
-    <style name="DocumentsFullScreenTheme" parent="@style/Theme.AppCompat.Light.DarkActionBar">
+    <style name="DocumentsTheme" parent="@style/Theme.AppCompat.Light.DarkActionBar">
         <item name="actionBarWidgetTheme">@null</item>
         <item name="actionBarTheme">@style/ActionBarTheme</item>
         <item name="actionBarPopupTheme">@style/ActionBarPopupTheme</item>
@@ -66,4 +45,8 @@
         <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">
+    </style>
+
 </resources>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index edf384e..9309693 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -17,11 +17,13 @@
 package com.android.documentsui;
 
 import static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.State.MODE_GRID;
 import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_DOWN;
 import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
 import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_SIDE;
 import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_UP;
 import static com.android.internal.util.Preconditions.checkArgument;
+import static com.android.internal.util.Preconditions.checkState;
 
 import android.app.Activity;
 import android.app.Fragment;
@@ -39,27 +41,26 @@
 import android.support.annotation.LayoutRes;
 import android.support.annotation.Nullable;
 import android.util.Log;
-import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
-import android.view.MenuItem.OnActionExpandListener;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemSelectedListener;
 import android.widget.BaseAdapter;
 import android.widget.ImageView;
-import android.widget.SearchView;
-import android.widget.SearchView.OnQueryTextListener;
 import android.widget.TextView;
 
 import com.android.documentsui.RecentsProvider.ResumeColumns;
+import com.android.documentsui.SearchManager.SearchManagerListener;
+import com.android.documentsui.State.ViewMode;
 import com.android.documentsui.dirlist.DirectoryFragment;
 import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.DocumentStack;
 import com.android.documentsui.model.DurableUtils;
 import com.android.documentsui.model.RootInfo;
+import com.android.internal.util.Preconditions;
 
 import libcore.io.IoUtils;
 
@@ -70,7 +71,7 @@
 import java.util.List;
 import java.util.concurrent.Executor;
 
-public abstract class BaseActivity extends Activity {
+public abstract class BaseActivity extends Activity implements SearchManagerListener {
 
     static final String EXTRA_STATE = "state";
 
@@ -85,11 +86,11 @@
     private int mLayoutId;
     private DirectoryContainerView mDirectoryContainer;
 
-    public abstract void onDocumentPicked(DocumentInfo doc, @Nullable DocumentContext siblings);
+    public abstract void onDocumentPicked(DocumentInfo doc, @Nullable SiblingProvider siblings);
     public abstract void onDocumentsPicked(List<DocumentInfo> docs);
 
     abstract void onTaskFinished(Uri... uris);
-    abstract void onDirectoryChanged(int anim);
+    abstract void refreshDirectory(int anim);
     abstract void updateActionBar();
     abstract void saveStackBlocking();
     abstract State buildState();
@@ -103,16 +104,24 @@
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
-        mProductivityDevice = getResources().getBoolean(R.bool.productivity_device);
         mState = (icicle != null)
                 ? icicle.<State>getParcelable(EXTRA_STATE)
                         : buildState();
 
+        Metrics.logActivityLaunch(this, mState, getIntent());
+
         setContentView(mLayoutId);
 
         mRoots = DocumentsApplication.getRootsCache(this);
+        mRoots.setOnCacheUpdateListener(
+                new RootsCache.OnCacheUpdateListener() {
+                    @Override
+                    public void onCacheUpdate() {
+                        new HandleRootsChangedTask().execute(getCurrentRoot());
+                    }
+                });
         mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
-        mSearchManager = new SearchManager();
+        mSearchManager = new SearchManager(this);
 
         // Base classes must update result in their onCreate.
         setResult(Activity.RESULT_CANCELED);
@@ -167,6 +176,12 @@
         return true;
     }
 
+    @Override
+    protected void onDestroy() {
+        mRoots.setOnCacheUpdateListener(null);
+        super.onDestroy();
+    }
+
     State buildDefaultState() {
         State state = new State();
 
@@ -190,20 +205,19 @@
     void onStackRestored(boolean restored, boolean external) {}
 
     void onRootPicked(RootInfo root) {
-        // Clear entire backstack and start in new root
-        mState.stack.root = root;
-        mState.stack.clear();
-        mState.stackTouched = true;
+        mState.derivedMode = LocalPreferences.getViewMode(this, root, MODE_GRID);
 
+        // 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)) {
-            onCurrentDirectoryChanged(ANIM_SIDE);
+            refreshCurrentRootAndDirectory(ANIM_SIDE);
         } else {
-            new PickRootTask(root).executeOnExecutor(getExecutorForCurrentDirectory());
+            new PickRootTask(root, true).executeOnExecutor(getExecutorForCurrentDirectory());
         }
     }
 
@@ -214,6 +228,7 @@
                 case R.id.menu_advanced:
                 case R.id.menu_file_size:
                 case R.id.menu_new_window:
+                case R.id.menu_search:
                     break;
                 default:
                     item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
@@ -248,11 +263,11 @@
                 return true;
 
             case R.id.menu_grid:
-                setUserMode(State.MODE_GRID);
+                setViewMode(State.MODE_GRID);
                 return true;
 
             case R.id.menu_list:
-                setUserMode(State.MODE_LIST);
+                setViewMode(State.MODE_LIST);
                 return true;
 
             case R.id.menu_paste_from_clipboard:
@@ -305,19 +320,20 @@
 
     void openContainerDocument(DocumentInfo doc) {
         checkArgument(doc.isContainer());
-        mState.stack.push(doc);
-        mState.stackTouched = true;
-        onCurrentDirectoryChanged(ANIM_DOWN);
+        mState.pushDocument(doc);
+        refreshCurrentRootAndDirectory(ANIM_DOWN);
     }
 
     /**
-     * Call this when directory changes. Prior to root fragment update
-     * the (abstract) directoryChanged method will be called.
+     * Refreshes the content of the director and the menu/action bar.
+     * The current directory name and selection will get updated.
      * @param anim
      */
-    final void onCurrentDirectoryChanged(int anim) {
+    final void refreshCurrentRootAndDirectory(int anim) {
+        mSearchManager.cancelSearch();
+
         mDirectoryContainer.setDrawDisappearingFirst(anim == ANIM_DOWN);
-        onDirectoryChanged(anim);
+        refreshDirectory(anim);
 
         final RootsFragment roots = RootsFragment.get(getFragmentManager());
         if (roots != null) {
@@ -325,9 +341,31 @@
         }
 
         updateActionBar();
+
         invalidateOptionsMenu();
     }
 
+    /**
+     * 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() {
+        mDirectoryContainer.setDrawDisappearingFirst(false);
+        refreshDirectory(ANIM_NONE);
+    }
+
+    /**
+     * Called when search query changed.
+     * Updates the state object.
+     * @param query - New query
+     */
+    @Override
+    public void onSearchQueryChanged(String query) {
+        mState.currentSearch = query;
+    }
+
     final List<String> getExcludedAuthorities() {
         List<String> authorities = new ArrayList<>();
         if (getIntent().getBooleanExtra(DocumentsContract.EXTRA_EXCLUDE_SELF, false)) {
@@ -384,27 +422,30 @@
         invalidateOptionsMenu();
     }
 
-    public void onStateChanged() {
-        invalidateOptionsMenu();
-    }
-
     /**
      * Set state sort order based on explicit user action.
      */
     void setUserSortOrder(int sortOrder) {
         mState.userSortOrder = sortOrder;
-        DirectoryFragment.get(getFragmentManager()).onUserSortOrderChanged();
+        DirectoryFragment.get(getFragmentManager()).onSortOrderChanged();
     }
 
     /**
-     * Set state mode based on explicit user action.
+     * Set mode based on explicit user action.
      */
-    void setUserMode(int mode) {
-        mState.userMode = mode;
-        DirectoryFragment.get(getFragmentManager()).onUserModeChanged();
+    void setViewMode(@ViewMode int mode) {
+        checkState(mState.stack.root != null);
+        LocalPreferences.setViewMode(this, mState.stack.root, mode);
+        mState.derivedMode = mode;
+
+        // view icon needs to be updated, but we *could* do it
+        // in onOptionsItemSelected, and not do the full invalidation
+        // But! That's a larger refactoring we'll save for another day.
+        invalidateOptionsMenu();
+        DirectoryFragment.get(getFragmentManager()).onViewModeChanged();
     }
 
-    void setPending(boolean pending) {
+    public void setPending(boolean pending) {
         final SaveFragment save = SaveFragment.get(getFragmentManager());
         if (save != null) {
             save.setPending(pending);
@@ -450,7 +491,7 @@
             return;
         }
 
-        if (!mState.stackTouched) {
+        if (!mState.hasLocationChanged()) {
             super.onBackPressed();
             return;
         }
@@ -461,7 +502,7 @@
             mDrawer.setOpen(false);
         } else if (size > 1) {
             mState.stack.pop();
-            onCurrentDirectoryChanged(ANIM_UP);
+            refreshCurrentRootAndDirectory(ANIM_UP);
         } else {
             super.onBackPressed();
         }
@@ -471,41 +512,43 @@
         try {
             // Update the restored stack to ensure we have freshest data
             stack.updateDocuments(getContentResolver());
-
-            mState.stack = stack;
-            mState.stackTouched = true;
-            onCurrentDirectoryChanged(ANIM_SIDE);
+            mState.setStack(stack);
+            refreshCurrentRootAndDirectory(ANIM_SIDE);
 
         } catch (FileNotFoundException e) {
             Log.w(mTag, "Failed to restore stack: " + e);
         }
     }
 
+    private DocumentInfo getRootDocumentBlocking(RootInfo root) {
+        try {
+            final Uri uri = DocumentsContract.buildDocumentUri(
+                    root.authority, root.documentId);
+            return DocumentInfo.fromUri(getContentResolver(), uri);
+        } catch (FileNotFoundException e) {
+            Log.w(mTag, "Failed to find root", e);
+            return null;
+        }
+    }
+
     final class PickRootTask extends AsyncTask<Void, Void, DocumentInfo> {
         private RootInfo mRoot;
+        private boolean mTouched;
 
-        public PickRootTask(RootInfo root) {
+        public PickRootTask(RootInfo root, boolean touched) {
             mRoot = root;
+            mTouched = touched;
         }
 
         @Override
         protected DocumentInfo doInBackground(Void... params) {
-            try {
-                final Uri uri = DocumentsContract.buildDocumentUri(
-                        mRoot.authority, mRoot.documentId);
-                return DocumentInfo.fromUri(getContentResolver(), uri);
-            } catch (FileNotFoundException e) {
-                Log.w(mTag, "Failed to find root", e);
-                return null;
-            }
+            return getRootDocumentBlocking(mRoot);
         }
 
         @Override
         protected void onPostExecute(DocumentInfo result) {
-            if (result != null) {
-                mState.stack.push(result);
-                mState.stackTouched = true;
-                onCurrentDirectoryChanged(ANIM_SIDE);
+            if (result != null && !isDestroyed()) {
+                openContainerDocument(result);
             }
         }
     }
@@ -559,7 +602,7 @@
         protected void onPostExecute(Void result) {
             if (isDestroyed()) return;
             mState.restored = true;
-            onCurrentDirectoryChanged(ANIM_NONE);
+            refreshCurrentRootAndDirectory(ANIM_NONE);
             onStackRestored(mRestoredStack, mExternal);
         }
     }
@@ -591,6 +634,40 @@
         }
     }
 
+    final class HandleRootsChangedTask extends AsyncTask<RootInfo, Void, RootInfo> {
+        DocumentInfo mHome;
+
+        @Override
+        protected RootInfo doInBackground(RootInfo... roots) {
+            checkArgument(roots.length == 1);
+            final RootInfo currentRoot = roots[0];
+            final Collection<RootInfo> cachedRoots = mRoots.getRootsBlocking();
+            RootInfo homeRoot = null;
+            for (final RootInfo root : cachedRoots) {
+                if (root.isHome()) {
+                    homeRoot = 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 = getRootDocumentBlocking(homeRoot);
+            return homeRoot;
+        }
+
+        @Override
+        protected void onPostExecute(RootInfo homeRoot) {
+            if (homeRoot != null && mHome != null && !isDestroyed()) {
+                // Clear entire backstack and start in new root
+                mState.onRootChanged(homeRoot);
+                mSearchManager.update(homeRoot);
+                openContainerDocument(mHome);
+            }
+        }
+    }
+
     final class ItemSelectedListener implements OnItemSelectedListener {
 
         boolean mIgnoreNextNavigation;
@@ -603,10 +680,9 @@
             }
 
             while (mState.stack.size() > position + 1) {
-                mState.stackTouched = true;
-                mState.stack.pop();
+                mState.popDocument();
             }
-            onCurrentDirectoryChanged(ANIM_UP);
+            refreshCurrentRootAndDirectory(ANIM_UP);
         }
 
         @Override
@@ -679,154 +755,10 @@
     }
 
     /**
-     * Facade over the various search parts in the menu.
-     */
-    final class SearchManager implements
-            SearchView.OnCloseListener, OnActionExpandListener, OnQueryTextListener,
-            DocumentsToolBar.OnActionViewCollapsedListener {
-
-        private boolean mSearchExpanded;
-        private boolean mIgnoreNextClose;
-        private boolean mIgnoreNextCollapse;
-
-        private DocumentsToolBar mActionBar;
-        private MenuItem mMenu;
-        private SearchView mView;
-
-        public void install(DocumentsToolBar actionBar) {
-            assert(mActionBar == null);
-            mActionBar = actionBar;
-            mMenu = actionBar.getSearchMenu();
-            mView = (SearchView) mMenu.getActionView();
-
-            mActionBar.setOnActionViewCollapsedListener(this);
-            mMenu.setOnActionExpandListener(this);
-            mView.setOnQueryTextListener(this);
-            mView.setOnCloseListener(this);
-        }
-
-        /**
-         * @param root Info about the current directory.
-         */
-        void update(RootInfo root) {
-            if (mMenu == null) {
-                Log.d(mTag, "update called before Search MenuItem installed.");
-                return;
-            }
-
-            if (mState.currentSearch != null) {
-                mMenu.expandActionView();
-
-                mView.setIconified(false);
-                mView.clearFocus();
-                mView.setQuery(mState.currentSearch, false);
-            } else {
-                mView.clearFocus();
-                if (!mView.isIconified()) {
-                    mIgnoreNextClose = true;
-                    mView.setIconified(true);
-                }
-
-                if (mMenu.isActionViewExpanded()) {
-                    mIgnoreNextCollapse = true;
-                    mMenu.collapseActionView();
-                }
-            }
-
-            showMenu(root != null
-                    && ((root.flags & Root.FLAG_SUPPORTS_SEARCH) != 0));
-        }
-
-        void showMenu(boolean visible) {
-            if (mMenu == null) {
-                Log.d(mTag, "showMenu called before Search MenuItem installed.");
-                return;
-            }
-
-            mMenu.setVisible(visible);
-            if (!visible) {
-                mState.currentSearch = null;
-            }
-        }
-
-        /**
-         * Cancels current search operation.
-         * @return True if it cancels search. False if it does not operate
-         *     search currently.
-         */
-        boolean cancelSearch() {
-            if (mActionBar.hasExpandedActionView()) {
-                mActionBar.collapseActionView();
-                return true;
-            }
-            return false;
-        }
-
-        boolean isSearching() {
-            return mState.currentSearch != null;
-        }
-
-        boolean isExpanded() {
-            return mSearchExpanded;
-        }
-
-        @Override
-        public boolean onClose() {
-            mSearchExpanded = false;
-            if (mIgnoreNextClose) {
-                mIgnoreNextClose = false;
-                return false;
-            }
-
-            mState.currentSearch = null;
-            onCurrentDirectoryChanged(ANIM_NONE);
-            return false;
-        }
-
-        @Override
-        public boolean onMenuItemActionExpand(MenuItem item) {
-            mSearchExpanded = true;
-            updateActionBar();
-            return true;
-        }
-
-        @Override
-        public boolean onMenuItemActionCollapse(MenuItem item) {
-            mSearchExpanded = false;
-            if (mIgnoreNextCollapse) {
-                mIgnoreNextCollapse = false;
-                return true;
-            }
-            mState.currentSearch = null;
-            onCurrentDirectoryChanged(ANIM_NONE);
-            return true;
-        }
-
-        @Override
-        public boolean onQueryTextSubmit(String query) {
-            mSearchExpanded = true;
-            mState.currentSearch = query;
-            mView.clearFocus();
-            onCurrentDirectoryChanged(ANIM_NONE);
-            return true;
-        }
-
-        @Override
-        public boolean onQueryTextChange(String newText) {
-            return false;
-        }
-
-        @Override
-        public void onActionViewCollapsed() {
-            updateActionBar();
-        }
-    }
-
-    /**
      * Interface providing access to current view of documents
      * even when all documents are not homed to the same parent.
      */
-    public interface DocumentContext {
+    public interface SiblingProvider {
         /**
          * Returns the cursor for the selected document. The cursor can be used to retrieve
          * details about a document and its siblings.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
deleted file mode 100644
index 6d947d1..0000000
--- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
+++ /dev/null
@@ -1,666 +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.Shared.DEBUG;
-import static com.android.documentsui.model.DocumentInfo.getCursorLong;
-import static com.android.documentsui.model.DocumentInfo.getCursorString;
-
-import android.app.Activity;
-import android.app.IntentService;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.ContentProviderClient;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.AssetFileDescriptor;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.CancellationSignal;
-import android.os.ParcelFileDescriptor;
-import android.os.Parcelable;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.provider.DocumentsContract;
-import android.provider.DocumentsContract.Document;
-import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
-import android.support.design.widget.Snackbar;
-import android.text.format.DateUtils;
-import android.util.Log;
-
-import com.android.documentsui.model.DocumentInfo;
-import com.android.documentsui.model.DocumentStack;
-import com.android.documentsui.model.RootInfo;
-
-import libcore.io.IoUtils;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.text.NumberFormat;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-public class CopyService extends IntentService {
-    public static final String TAG = "CopyService";
-
-    private static final String EXTRA_CANCEL = "com.android.documentsui.CANCEL";
-    public static final String EXTRA_SRC_LIST = "com.android.documentsui.SRC_LIST";
-    public static final String EXTRA_FAILURE = "com.android.documentsui.FAILURE";
-    public static final String EXTRA_TRANSFER_MODE = "com.android.documentsui.TRANSFER_MODE";
-
-    public static final int TRANSFER_MODE_COPY = 1;
-    public static final int TRANSFER_MODE_MOVE = 2;
-
-    // TODO: Move it to a shared file when more operations are implemented.
-    public static final int FAILURE_COPY = 1;
-
-    // Parameters of the copy job. Requests to an IntentService are serialized so this code only
-    // needs to deal with one job at a time.
-    // NOTE: This must be declared by concrete type as the concrete type
-    // is required by putParcelableArrayListExtra.
-    private final ArrayList<DocumentInfo> mFailedFiles = new ArrayList<>();
-
-    private PowerManager mPowerManager;
-
-    private NotificationManager mNotificationManager;
-    private Notification.Builder mProgressBuilder;
-
-    // Jobs are serialized but a job ID is used, to avoid mixing up cancellation requests.
-    private String mJobId;
-    private volatile boolean mIsCancelled;
-    private long mBatchSize;
-    private long mBytesCopied;
-    private long mStartTime;
-    private long mLastNotificationTime;
-    // Speed estimation
-    private long mBytesCopiedSample;
-    private long mSampleTime;
-    private long mSpeed;
-    private long mRemainingTime;
-    // Provider clients are acquired for the duration of each copy job. Note that there is an
-    // implicit assumption that all srcs come from the same authority.
-    private ContentProviderClient mSrcClient;
-    private ContentProviderClient mDstClient;
-
-    // For testing only.
-    @Nullable private TestOnlyListener mJobFinishedListener;
-
-    public CopyService() {
-        super("CopyService");
-    }
-
-    /**
-     * Starts the service for a copy operation.
-     *
-     * @param context Context for the intent.
-     * @param srcDocs A list of src files to copy.
-     * @param dstStack The copy destination stack.
-     */
-    public static void start(Activity activity, List<DocumentInfo> srcDocs, DocumentStack dstStack,
-            int mode) {
-        final Resources res = activity.getResources();
-        final Intent copyIntent = new Intent(activity, CopyService.class);
-        copyIntent.putParcelableArrayListExtra(
-                EXTRA_SRC_LIST,
-                // Don't create a copy unless absolutely necessary :)
-                srcDocs instanceof ArrayList
-                    ? (ArrayList<DocumentInfo>) srcDocs
-                    : new ArrayList<DocumentInfo>(srcDocs));
-        copyIntent.putExtra(Shared.EXTRA_STACK, (Parcelable) dstStack);
-        copyIntent.putExtra(EXTRA_TRANSFER_MODE, mode);
-
-        int toastMessage = (mode == TRANSFER_MODE_COPY) ? R.plurals.copy_begin
-                : R.plurals.move_begin;
-        Snackbars.makeSnackbar(activity,
-                res.getQuantityString(toastMessage, srcDocs.size(), srcDocs.size()),
-                Snackbar.LENGTH_SHORT).show();
-        activity.startService(copyIntent);
-    }
-
-    @Override
-    public int onStartCommand(Intent intent, int flags, int startId) {
-        if (intent.hasExtra(EXTRA_CANCEL)) {
-            handleCancel(intent);
-        }
-        return super.onStartCommand(intent, flags, startId);
-    }
-
-    @Override
-    protected void onHandleIntent(Intent intent) {
-        if (intent.hasExtra(EXTRA_CANCEL)) {
-            handleCancel(intent);
-            return;
-        }
-
-        final PowerManager.WakeLock wakeLock = mPowerManager
-                .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
-        final ArrayList<DocumentInfo> srcs = intent.getParcelableArrayListExtra(EXTRA_SRC_LIST);
-        final DocumentStack stack = intent.getParcelableExtra(Shared.EXTRA_STACK);
-        // Copy by default.
-        final int transferMode = intent.getIntExtra(EXTRA_TRANSFER_MODE, TRANSFER_MODE_COPY);
-
-        try {
-            wakeLock.acquire();
-
-            // Acquire content providers.
-            mSrcClient = DocumentsApplication.acquireUnstableProviderOrThrow(getContentResolver(),
-                    srcs.get(0).authority);
-            mDstClient = DocumentsApplication.acquireUnstableProviderOrThrow(getContentResolver(),
-                    stack.peek().authority);
-
-            setupCopyJob(srcs, stack, transferMode);
-
-            final String opDesc = transferMode == TRANSFER_MODE_COPY ? "copy" : "move";
-            DocumentInfo srcInfo;
-            DocumentInfo dstInfo;
-            for (int i = 0; i < srcs.size() && !mIsCancelled; ++i) {
-                srcInfo = srcs.get(i);
-                dstInfo = stack.peek();
-
-                // Guard unsupported recursive operation.
-                if (dstInfo.equals(srcInfo) || isDescendentOf(srcInfo, dstInfo)) {
-                    if (DEBUG) Log.d(TAG,
-                            "Skipping recursive " + opDesc + " of directory " + dstInfo.derivedUri);
-                    mFailedFiles.add(srcInfo);
-                    continue;
-                }
-
-                if (DEBUG) Log.d(TAG,
-                        "Performing " + opDesc + " of " + srcInfo.displayName
-                        + " (" + srcInfo.derivedUri + ")" + " to " + dstInfo.displayName
-                        + " (" + dstInfo.derivedUri + ")");
-
-                copy(srcInfo, dstInfo, transferMode);
-            }
-        } catch (Exception e) {
-            // Catch-all to prevent any copy errors from wedging the app.
-            Log.e(TAG, "Exceptions occurred during copying", e);
-        } finally {
-            if (DEBUG) Log.d(TAG, "Cleaning up after copy");
-            ContentProviderClient.releaseQuietly(mSrcClient);
-            ContentProviderClient.releaseQuietly(mDstClient);
-
-            wakeLock.release();
-
-            // Dismiss the ongoing copy notification when the copy is done.
-            mNotificationManager.cancel(mJobId, 0);
-
-            if (mFailedFiles.size() > 0) {
-                Log.e(TAG, mFailedFiles.size() + " files failed to copy");
-                final Context context = getApplicationContext();
-                final Intent navigateIntent = buildNavigateIntent(context, stack);
-                navigateIntent.putExtra(EXTRA_FAILURE, FAILURE_COPY);
-                navigateIntent.putExtra(EXTRA_TRANSFER_MODE, transferMode);
-                navigateIntent.putParcelableArrayListExtra(EXTRA_SRC_LIST, mFailedFiles);
-
-                final int titleResourceId = (transferMode == TRANSFER_MODE_COPY ?
-                        R.plurals.copy_error_notification_title :
-                        R.plurals.move_error_notification_title);
-                final Notification.Builder errorBuilder = new Notification.Builder(this)
-                        .setContentTitle(context.getResources().getQuantityString(titleResourceId,
-                                mFailedFiles.size(), mFailedFiles.size()))
-                        .setContentText(getString(R.string.notification_touch_for_details))
-                        .setContentIntent(PendingIntent.getActivity(context, 0, navigateIntent,
-                                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT))
-                        .setCategory(Notification.CATEGORY_ERROR)
-                        .setSmallIcon(R.drawable.ic_menu_copy)
-                        .setAutoCancel(true);
-                mNotificationManager.notify(mJobId, 0, errorBuilder.build());
-            }
-
-            if (mJobFinishedListener != null) {
-                mJobFinishedListener.onFinished(mFailedFiles);
-            }
-
-            if (DEBUG) Log.d(TAG, "Done cleaning up");
-        }
-    }
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        mPowerManager = getSystemService(PowerManager.class);
-        mNotificationManager = getSystemService(NotificationManager.class);
-    }
-
-    /**
-     * Sets up the CopyService to start tracking and sending notifications for the given batch of
-     * files.
-     *
-     * @param srcs A list of src files to copy.
-     * @param stack The copy destination stack.
-     * @param transferMode The mode (i.e. copy, or move)
-     * @throws RemoteException
-     */
-    private void setupCopyJob(ArrayList<DocumentInfo> srcs, DocumentStack stack, int transferMode)
-            throws RemoteException {
-        final boolean copying = (transferMode == TRANSFER_MODE_COPY);
-        // Create an ID for this copy job. Use the timestamp.
-        mJobId = String.valueOf(SystemClock.elapsedRealtime());
-        // Reset the cancellation flag.
-        mIsCancelled = false;
-
-        final Context context = getApplicationContext();
-        final Intent navigateIntent = buildNavigateIntent(context, stack);
-
-        final String contentTitle = getString(copying ? R.string.copy_notification_title
-                : R.string.move_notification_title);
-        mProgressBuilder = new Notification.Builder(this)
-                .setContentTitle(contentTitle)
-                .setContentIntent(PendingIntent.getActivity(context, 0, navigateIntent, 0))
-                .setCategory(Notification.CATEGORY_PROGRESS)
-                .setSmallIcon(R.drawable.ic_menu_copy)
-                .setOngoing(true);
-
-        final Intent cancelIntent = new Intent(this, CopyService.class);
-        cancelIntent.putExtra(EXTRA_CANCEL, mJobId);
-        mProgressBuilder.addAction(R.drawable.ic_cab_cancel,
-                getString(android.R.string.cancel), PendingIntent.getService(this, 0,
-                        cancelIntent,
-                        PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT));
-
-        // Send an initial progress notification.
-        final String contentText = getString(copying ? R.string.copy_preparing
-                : R.string.move_preparing);
-        mProgressBuilder.setProgress(0, 0, true); // Indeterminate progress while setting up.
-        mProgressBuilder.setContentText(contentText);
-        mNotificationManager.notify(mJobId, 0, mProgressBuilder.build());
-
-        // Reset batch parameters.
-        mFailedFiles.clear();
-        mBatchSize = calculateFileSizes(srcs);
-        mBytesCopied = 0;
-        mStartTime = SystemClock.elapsedRealtime();
-        mLastNotificationTime = 0;
-        mBytesCopiedSample = 0;
-        mSampleTime = 0;
-        mSpeed = 0;
-        mRemainingTime = 0;
-
-        // TODO: Check preconditions for copy.
-        // - check that the destination has enough space and is writeable?
-        // - check MIME types?
-    }
-
-    /**
-     * Sets a callback to be run when the next run job is finished.
-     * This is test ONLY instrumentation. The alternative is for us to add
-     * broadcast intents SOLELY for the purpose of testing.
-     * @param listener
-     */
-    @VisibleForTesting
-    void addFinishedListener(TestOnlyListener listener) {
-        this.mJobFinishedListener = listener;
-
-    }
-
-    /**
-     * Only used for testing. Is that obvious enough?
-     */
-    @VisibleForTesting
-    interface TestOnlyListener {
-        void onFinished(List<DocumentInfo> failed);
-    }
-
-    /**
-     * Calculates the cumulative size of all the documents in the list. Directories are recursed
-     * into and totaled up.
-     *
-     * @param srcs
-     * @return Size in bytes.
-     * @throws RemoteException
-     */
-    private long calculateFileSizes(List<DocumentInfo> srcs) throws RemoteException {
-        long result = 0;
-        for (DocumentInfo src : srcs) {
-            if (src.isDirectory()) {
-                // Directories need to be recursed into.
-                result += calculateFileSizesHelper(src.derivedUri);
-            } else {
-                result += src.size;
-            }
-        }
-        return result;
-    }
-
-    /**
-     * Calculates (recursively) the cumulative size of all the files under the given directory.
-     *
-     * @throws RemoteException
-     */
-    private long calculateFileSizesHelper(Uri uri) throws RemoteException {
-        final String authority = uri.getAuthority();
-        final Uri queryUri = DocumentsContract.buildChildDocumentsUri(authority,
-                DocumentsContract.getDocumentId(uri));
-        final String queryColumns[] = new String[] {
-                Document.COLUMN_DOCUMENT_ID,
-                Document.COLUMN_MIME_TYPE,
-                Document.COLUMN_SIZE
-        };
-
-        long result = 0;
-        Cursor cursor = null;
-        try {
-            cursor = mSrcClient.query(queryUri, queryColumns, null, null, null);
-            while (cursor.moveToNext()) {
-                if (Document.MIME_TYPE_DIR.equals(
-                        getCursorString(cursor, Document.COLUMN_MIME_TYPE))) {
-                    // Recurse into directories.
-                    final Uri subdirUri = DocumentsContract.buildDocumentUri(authority,
-                            getCursorString(cursor, Document.COLUMN_DOCUMENT_ID));
-                    result += calculateFileSizesHelper(subdirUri);
-                } else {
-                    // This may return -1 if the size isn't defined. Ignore those cases.
-                    long size = getCursorLong(cursor, Document.COLUMN_SIZE);
-                    result += size > 0 ? size : 0;
-                }
-            }
-        } finally {
-            IoUtils.closeQuietly(cursor);
-        }
-
-        return result;
-    }
-
-    /**
-     * Cancels the current copy job, if its ID matches the given ID.
-     *
-     * @param intent The cancellation intent.
-     */
-    private void handleCancel(Intent intent) {
-        final String cancelledId = intent.getStringExtra(EXTRA_CANCEL);
-        // Do nothing if the cancelled ID doesn't match the current job ID. This prevents racey
-        // cancellation requests from affecting unrelated copy jobs.  However, if the current job ID
-        // is null, the service most likely crashed and was revived by the incoming cancel intent.
-        // In that case, always allow the cancellation to proceed.
-        if (Objects.equals(mJobId, cancelledId) || mJobId == null) {
-            // Set the cancel flag. This causes the copy loops to exit.
-            mIsCancelled = true;
-            // Dismiss the progress notification here rather than in the copy loop. This preserves
-            // interactivity for the user in case the copy loop is stalled.
-            mNotificationManager.cancel(cancelledId, 0);
-        }
-    }
-
-    /**
-     * Logs progress on the current copy operation. Displays/Updates the progress notification.
-     *
-     * @param bytesCopied
-     */
-    private void makeProgress(long bytesCopied) {
-        mBytesCopied += bytesCopied;
-        double done = (double) mBytesCopied / mBatchSize;
-        String percent = NumberFormat.getPercentInstance().format(done);
-
-        // Update time estimate
-        long currentTime = SystemClock.elapsedRealtime();
-        long elapsedTime = currentTime - mStartTime;
-
-        // Send out progress notifications once a second.
-        if (currentTime - mLastNotificationTime > 1000) {
-            updateRemainingTimeEstimate(elapsedTime);
-            mProgressBuilder.setProgress(100, (int) (done * 100), false);
-            mProgressBuilder.setContentInfo(percent);
-            if (mRemainingTime > 0) {
-                mProgressBuilder.setContentText(getString(R.string.copy_remaining,
-                        DateUtils.formatDuration(mRemainingTime)));
-            } else {
-                mProgressBuilder.setContentText(null);
-            }
-            mNotificationManager.notify(mJobId, 0, mProgressBuilder.build());
-            mLastNotificationTime = currentTime;
-        }
-    }
-
-    /**
-     * Generates an estimate of the remaining time in the copy.
-     *
-     * @param elapsedTime The time elapsed so far.
-     */
-    private void updateRemainingTimeEstimate(long elapsedTime) {
-        final long sampleDuration = elapsedTime - mSampleTime;
-        final long sampleSpeed = ((mBytesCopied - mBytesCopiedSample) * 1000) / sampleDuration;
-        if (mSpeed == 0) {
-            mSpeed = sampleSpeed;
-        } else {
-            mSpeed = ((3 * mSpeed) + sampleSpeed) / 4;
-        }
-
-        if (mSampleTime > 0 && mSpeed > 0) {
-            mRemainingTime = ((mBatchSize - mBytesCopied) * 1000) / mSpeed;
-        } else {
-            mRemainingTime = 0;
-        }
-
-        mSampleTime = elapsedTime;
-        mBytesCopiedSample = mBytesCopied;
-    }
-
-    /**
-     * Copies a the given documents to the given location.
-     *
-     * @param srcInfo DocumentInfos for the documents to copy.
-     * @param dstDirInfo The destination directory.
-     * @param mode The transfer mode (copy or move).
-     * @throws RemoteException
-     */
-    private void copy(DocumentInfo srcInfo, DocumentInfo dstDirInfo, int mode)
-            throws RemoteException {
-        // When copying within the same provider, try to use optimized copying and moving.
-        // If not supported, then fallback to byte-by-byte copy/move.
-        if (srcInfo.authority.equals(dstDirInfo.authority)) {
-            switch (mode) {
-                case TRANSFER_MODE_COPY:
-                    if ((srcInfo.flags & Document.FLAG_SUPPORTS_COPY) != 0) {
-                        if (DocumentsContract.copyDocument(mSrcClient, srcInfo.derivedUri,
-                                dstDirInfo.derivedUri) == null) {
-                            mFailedFiles.add(srcInfo);
-                        }
-                        return;
-                    }
-                    break;
-                case TRANSFER_MODE_MOVE:
-                    if ((srcInfo.flags & Document.FLAG_SUPPORTS_MOVE) != 0) {
-                        if (DocumentsContract.moveDocument(mSrcClient, srcInfo.derivedUri,
-                                dstDirInfo.derivedUri) == null) {
-                            mFailedFiles.add(srcInfo);
-                        }
-                        return;
-                    }
-                    break;
-                default:
-                    throw new IllegalArgumentException("Unknown transfer mode.");
-            }
-        }
-
-        // Create the target document (either a file or a directory), then copy recursively the
-        // contents (bytes or children).
-        final Uri dstUri = DocumentsContract.createDocument(mDstClient, dstDirInfo.derivedUri,
-                srcInfo.mimeType, srcInfo.displayName);
-        if (dstUri == null) {
-            // If this is a directory, the entire subdir will not be copied over.
-            mFailedFiles.add(srcInfo);
-            return;
-        }
-
-        DocumentInfo dstInfo = null;
-        try {
-            final DocumentInfo dstDocInfo = DocumentInfo.fromUri(getContentResolver(), dstUri);
-        } catch (FileNotFoundException e) {
-            mFailedFiles.add(srcInfo);
-            return;
-        }
-
-        if (Document.MIME_TYPE_DIR.equals(srcInfo.mimeType)) {
-            copyDirectoryHelper(srcInfo, dstInfo, mode);
-        } else {
-            copyFileHelper(srcInfo, dstInfo, mode);
-        }
-
-        if (mode == TRANSFER_MODE_MOVE) {
-            try {
-                DocumentsContract.deleteDocument(mSrcClient, srcInfo.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 clean up after move: " + srcInfo.derivedUri, e);
-                throw e;
-            }
-        }
-    }
-
-    /**
-     * Returns true if {@code doc} is a descendant of {@code parentDoc}.
-     */
-    boolean isDescendentOf(DocumentInfo doc, DocumentInfo parentDoc) throws RemoteException {
-        if (parentDoc.isDirectory() && doc.authority.equals(parentDoc.authority)) {
-            return DocumentsContract.isChildDocument(
-                    mDstClient, doc.derivedUri, parentDoc.derivedUri);
-        }
-        return false;
-    }
-
-    /**
-     * Handles recursion into a directory and copying its contents. Note that in linux terms, this
-     * does the equivalent of "cp src/* dst", not "cp -r src dst".
-     *
-     * @param srcDirInfo Info of the directory to copy from. The routine will copy the directory's
-     *            contents, not the directory itself.
-     * @param dstDirInfo Info of the directory to copy to. Must be created beforehand.
-     * @throws RemoteException
-     */
-    private void copyDirectoryHelper(DocumentInfo srcDirInfo, DocumentInfo dstDirInfo, int mode)
-            throws RemoteException {
-        // Recurse into directories. Copy children into the new subdirectory.
-        final String queryColumns[] = new String[] {
-                Document.COLUMN_DISPLAY_NAME,
-                Document.COLUMN_DOCUMENT_ID,
-                Document.COLUMN_MIME_TYPE,
-                Document.COLUMN_SIZE,
-                Document.COLUMN_FLAGS
-        };
-        Cursor cursor = null;
-        try {
-            // Iterate over srcs in the directory; copy to the destination directory.
-            DocumentInfo srcInfo;
-            cursor = mSrcClient.query(srcDirInfo.derivedUri, queryColumns, null, null, null);
-            while (cursor.moveToNext()) {
-                srcInfo = DocumentInfo.fromCursor(cursor, srcDirInfo.authority);
-                copy(srcInfo, dstDirInfo, mode);
-            }
-        } finally {
-            IoUtils.closeQuietly(cursor);
-        }
-    }
-
-    /**
-     * 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.
-     * @throws RemoteException
-     */
-    private void copyFileHelper(DocumentInfo srcInfo, DocumentInfo dstInfo, int mode)
-            throws RemoteException {
-        // Copy an individual file.
-        CancellationSignal canceller = new CancellationSignal();
-        ParcelFileDescriptor srcFile = null;
-        ParcelFileDescriptor dstFile = null;
-        InputStream src = null;
-        OutputStream dst = null;
-
-        IOException copyError = null;
-        try {
-            // If the file is virtual, but can be converted to another format, then try to copy it
-            // as such format.
-            if (srcInfo.isVirtualDocument() && srcInfo.isTypedDocument()) {
-                final String[] streamTypes = mSrcClient.getStreamTypes(srcInfo.derivedUri, "*/*");
-                if (streamTypes.length > 0) {
-                    // Pick the first streamable format.
-                    final AssetFileDescriptor srcFileAsAsset =
-                            mSrcClient.openTypedAssetFileDescriptor(
-                                    srcInfo.derivedUri, streamTypes[0], null, canceller);
-                    srcFile = srcFileAsAsset.getParcelFileDescriptor();
-                    src = new AssetFileDescriptor.AutoCloseInputStream(srcFileAsAsset);
-                } else {
-                    // TODO: Log failures. b/26192412
-                    mFailedFiles.add(srcInfo);
-                }
-            } else {
-                srcFile = mSrcClient.openFile(srcInfo.derivedUri, "r", canceller);
-                src = new ParcelFileDescriptor.AutoCloseInputStream(srcFile);
-            }
-            dstFile = mDstClient.openFile(dstInfo.derivedUri, "w", canceller);
-            dst = new ParcelFileDescriptor.AutoCloseOutputStream(dstFile);
-
-            byte[] buffer = new byte[8192];
-            int len;
-            while (!mIsCancelled && ((len = src.read(buffer)) != -1)) {
-                dst.write(buffer, 0, len);
-                makeProgress(len);
-            }
-
-            srcFile.checkError();
-        } catch (IOException e) {
-            copyError = e;
-            mFailedFiles.add(srcInfo);
-
-            if (dstFile != null) {
-                try {
-                    dstFile.closeWithError(copyError.getMessage());
-                } catch (IOException closeError) {
-                    Log.e(TAG, "Error closing destination", closeError);
-                }
-            }
-        } finally {
-            // This also ensures the file descriptors are closed.
-            IoUtils.closeQuietly(src);
-            IoUtils.closeQuietly(dst);
-        }
-
-        if (copyError != null || mIsCancelled) {
-            // Clean up half-copied files.
-            canceller.cancel();
-            try {
-                DocumentsContract.deleteDocument(mDstClient, dstInfo.derivedUri);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed to clean up after copy error: " + dstInfo.derivedUri, 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.
-                throw e;
-            }
-        }
-    }
-
-    /**
-     * Creates an intent for navigating back to the destination directory.
-     */
-    private Intent buildNavigateIntent(Context context, DocumentStack stack) {
-        Intent intent = new Intent(context, FilesActivity.class);
-        intent.setAction(DocumentsContract.ACTION_BROWSE);
-        intent.putExtra(Shared.EXTRA_STACK, (Parcelable) stack);
-        return intent;
-    }
-}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index f3c3f2f..df036b9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -63,7 +63,7 @@
         final AlertDialog.Builder builder = new AlertDialog.Builder(context);
         final LayoutInflater dialogInflater = LayoutInflater.from(builder.getContext());
 
-        final View view = dialogInflater.inflate(R.layout.dialog_create_dir, null, false);
+        final View view = dialogInflater.inflate(R.layout.dialog_file_name, null, false);
         final EditText editText = (EditText) view.findViewById(android.R.id.text1);
 
         builder.setTitle(R.string.menu_create_dir);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index b0bbec3..b0542b9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -16,11 +16,11 @@
 
 package com.android.documentsui;
 
+import static com.android.documentsui.Shared.DEBUG;
 import static com.android.documentsui.Shared.TAG;
 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.getCursorInt;
 
 import android.content.AsyncTaskLoader;
 import android.content.ContentProviderClient;
@@ -35,7 +35,6 @@
 import android.provider.DocumentsContract.Document;
 import android.util.Log;
 
-import com.android.documentsui.RecentsProvider.StateColumns;
 import com.android.documentsui.dirlist.DirectoryFragment;
 import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.RootInfo;
@@ -52,10 +51,10 @@
 
     private final int mType;
     private final RootInfo mRoot;
-    private DocumentInfo mDoc;
     private final Uri mUri;
     private final int mUserSortOrder;
 
+    private DocumentInfo mDoc;
     private CancellationSignal mSignal;
     private DirectoryResult mResult;
 
@@ -64,9 +63,9 @@
         super(context, ProviderExecutor.forAuthority(root.authority));
         mType = type;
         mRoot = root;
-        mDoc = doc;
         mUri = uri;
         mUserSortOrder = userSortOrder;
+        mDoc = doc;
     }
 
     @Override
@@ -83,8 +82,6 @@
 
         final DirectoryResult result = new DirectoryResult();
 
-        int userMode = State.MODE_UNKNOWN;
-
         // Use default document when searching
         if (mType == DirectoryFragment.TYPE_SEARCH) {
             final Uri docUri = DocumentsContract.buildDocumentUri(
@@ -98,29 +95,6 @@
             }
         }
 
-        // Pick up any custom modes requested by user
-        Cursor cursor = null;
-        try {
-            final Uri stateUri = RecentsProvider.buildState(
-                    mRoot.authority, mRoot.rootId, mDoc.documentId);
-            cursor = resolver.query(stateUri, null, null, null, null);
-            if (cursor.moveToFirst()) {
-                userMode = getCursorInt(cursor, StateColumns.MODE);
-            }
-        } finally {
-            IoUtils.closeQuietly(cursor);
-        }
-
-        if (userMode != State.MODE_UNKNOWN) {
-            result.mode = userMode;
-        } else {
-            if ((mDoc.flags & Document.FLAG_DIR_PREFERS_GRID) != 0) {
-                result.mode = State.MODE_GRID;
-            } else {
-                result.mode = State.MODE_LIST;
-            }
-        }
-
         if (mUserSortOrder != State.SORT_ORDER_UNKNOWN) {
             result.sortOrder = mUserSortOrder;
         } else {
@@ -136,13 +110,13 @@
             result.sortOrder = State.SORT_ORDER_UNKNOWN;
         }
 
-        Log.d(TAG, "userMode=" + userMode + ", userSortOrder=" + mUserSortOrder + " --> mode="
-                + result.mode + ", sortOrder=" + result.sortOrder);
+        if (DEBUG)
+                Log.d(TAG, "userSortOrder=" + mUserSortOrder + ", sortOrder=" + result.sortOrder);
 
         ContentProviderClient client = null;
+        Cursor cursor = null;
         try {
             client = DocumentsApplication.acquireUnstableProviderOrThrow(resolver, authority);
-
             cursor = client.query(
                     mUri, null, null, null, getQuerySortOrder(result.sortOrder), mSignal);
             if (cursor == null) {
@@ -156,9 +130,6 @@
             if (mType == DirectoryFragment.TYPE_SEARCH) {
                 // Filter directories out of search results, for now
                 cursor = new FilteringCursorWrapper(cursor, null, SEARCH_REJECT_MIMES);
-            } else {
-                // Normal directories should have sorting applied
-                cursor = new SortingCursorWrapper(cursor, result.sortOrder);
             }
 
             result.client = client;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryResult.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryResult.java
index e7e4f73..22e438a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryResult.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryResult.java
@@ -29,7 +29,6 @@
     public Cursor cursor;
     public Exception exception;
 
-    public int mode = MODE_UNKNOWN;
     public int sortOrder = SORT_ORDER_UNKNOWN;
 
     @Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 8754f68..c3395ae 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -19,8 +19,8 @@
 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_PICK_COPY_DESTINATION;
 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;
@@ -31,11 +31,9 @@
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
 import android.content.ContentValues;
-import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
-import android.graphics.Point;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
@@ -46,7 +44,6 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
-import android.view.WindowManager;
 import android.widget.BaseAdapter;
 import android.widget.Spinner;
 import android.widget.Toolbar;
@@ -57,6 +54,7 @@
 import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.DurableUtils;
 import com.android.documentsui.model.RootInfo;
+import com.android.documentsui.services.FileOperationService;
 
 import java.util.Arrays;
 import java.util.List;
@@ -65,8 +63,6 @@
     private static final int CODE_FORWARD = 42;
     private static final String TAG = "DocumentsActivity";
 
-    private boolean mShowAsDialog;
-
     private Toolbar mToolbar;
     private Spinner mToolbarStack;
 
@@ -84,29 +80,8 @@
         super.onCreate(icicle);
 
         final Resources res = getResources();
-        mShowAsDialog = res.getBoolean(R.bool.show_as_dialog);
 
-        if (!mShowAsDialog) {
-            setTheme(R.style.DocumentsFullScreenTheme);
-        }
-
-        if (mShowAsDialog) {
-            mDrawer = DrawerController.createDummy();
-
-            // Strongly define our horizontal dimension; we leave vertical as
-            // WRAP_CONTENT so that system resizes us when IME is showing.
-            final WindowManager.LayoutParams a = getWindow().getAttributes();
-
-            final Point size = new Point();
-            getWindowManager().getDefaultDisplay().getSize(size);
-            a.width = (int) res.getFraction(R.dimen.dialog_width, size.x, size.x);
-
-            getWindow().setAttributes(a);
-
-        } else {
-            mDrawer = DrawerController.create(this);
-        }
-
+        mDrawer = DrawerController.create(this);
         mToolbar = (Toolbar) findViewById(R.id.toolbar);
 
         mStackAdapter = new StackAdapter();
@@ -145,7 +120,7 @@
             setTitle("");
             new RestoreStackTask().execute();
         } else {
-            onCurrentDirectoryChanged(ANIM_NONE);
+            refreshCurrentRootAndDirectory(ANIM_NONE);
         }
     }
 
@@ -180,8 +155,8 @@
         if (state.action == ACTION_PICK_COPY_DESTINATION) {
             state.directoryCopy = intent.getBooleanExtra(
                     Shared.EXTRA_DIRECTORY_COPY, false);
-            state.transferMode = intent.getIntExtra(CopyService.EXTRA_TRANSFER_MODE,
-                    CopyService.TRANSFER_MODE_COPY);
+            state.transferMode = intent.getIntExtra(FileOperationService.EXTRA_OPERATION,
+                    FileOperationService.OPERATION_COPY);
         }
 
         return state;
@@ -268,15 +243,16 @@
             }
         }
 
-        if (!mShowAsDialog && mDrawer.isUnlocked()) {
+        if (mDrawer.isUnlocked()) {
             mToolbar.setNavigationIcon(R.drawable.ic_hamburger);
             mToolbar.setNavigationContentDescription(R.string.drawer_open);
-            mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    setRootsDrawerOpen(true);
-                }
-            });
+            mToolbar.setNavigationOnClickListener(
+                    new View.OnClickListener() {
+                        @Override
+                        public void onClick(View v) {
+                            setRootsDrawerOpen(true);
+                        }
+                    });
         } else {
             mToolbar.setNavigationIcon(null);
             mToolbar.setNavigationContentDescription(R.string.drawer_open);
@@ -307,10 +283,7 @@
     public boolean onCreateOptionsMenu(Menu menu) {
         boolean showMenu = super.onCreateOptionsMenu(menu);
 
-        // Most actions are visible when showing as dialog
-        if (mShowAsDialog) {
-            expandMenus(menu);
-        }
+        expandMenus(menu);
         return showMenu;
     }
 
@@ -335,8 +308,10 @@
         mSearchManager.showMenu(!picking);
 
         // No display options in recent directories
-        grid.setVisible(!(picking && recents));
-        list.setVisible(!(picking && recents));
+        if (picking && recents) {
+            grid.setVisible(false);
+            list.setVisible(false);
+        }
 
         fileSize.setVisible(fileSize.isVisible() && !picking);
         settings.setVisible(false);
@@ -357,7 +332,7 @@
     }
 
     @Override
-    void onDirectoryChanged(int anim) {
+    void refreshDirectory(int anim) {
         final FragmentManager fm = getFragmentManager();
         final RootInfo root = getCurrentRoot();
         final DocumentInfo cwd = getCurrentDirectory();
@@ -371,19 +346,21 @@
             } else {
                 DirectoryFragment.showRecentsOpen(fm, anim);
 
-                // Start recents in grid when requesting visual things
-                final boolean visualMimes = MimePredicate.mimeMatches(
+                // In recents we pick layout mode based on the mimetype,
+                // picking GRID for visual types. We intentionally don't
+                // consult a user's saved preferences here since they are
+                // set per root (not per root and per mimetype).
+                boolean visualMimes = MimePredicate.mimeMatches(
                         MimePredicate.VISUAL_MIMES, mState.acceptMimes);
-                mState.userMode = visualMimes ? State.MODE_GRID : State.MODE_LIST;
-                mState.derivedMode = mState.userMode;
+                mState.derivedMode = visualMimes ? State.MODE_GRID : State.MODE_LIST;
             }
         } else {
-            if (mState.currentSearch != null) {
+            if (mSearchManager.isSearching()) {
                 // Ongoing search
                 DirectoryFragment.showSearch(fm, root, mState.currentSearch, anim);
             } else {
                 // Normal boring directory
-                DirectoryFragment.showNormal(fm, root, cwd, anim);
+                DirectoryFragment.showDirectory(fm, root, cwd, anim);
             }
         }
 
@@ -419,7 +396,7 @@
     }
 
     @Override
-    public void onDocumentPicked(DocumentInfo doc, DocumentContext context) {
+    public void onDocumentPicked(DocumentInfo doc, SiblingProvider siblings) {
         final FragmentManager fm = getFragmentManager();
         if (doc.isContainer()) {
             openContainerDocument(doc);
@@ -509,7 +486,7 @@
             // Picking a copy destination is only used internally by us, so we
             // don't need to extend permissions to the caller.
             intent.putExtra(Shared.EXTRA_STACK, (Parcelable) mState.stack);
-            intent.putExtra(CopyService.EXTRA_TRANSFER_MODE, mState.transferMode);
+            intent.putExtra(FileOperationService.EXTRA_OPERATION, mState.transferMode);
         } else {
             intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
                     | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
index cccbbc8..3302da9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
@@ -92,7 +92,7 @@
             final Uri rootUri = getIntent().getData();
             new RestoreRootTask(rootUri).executeOnExecutor(getExecutorForCurrentDirectory());
         } else {
-            onCurrentDirectoryChanged(ANIM_NONE);
+            refreshCurrentRootAndDirectory(ANIM_NONE);
         }
     }
 
@@ -164,7 +164,7 @@
     }
 
     @Override
-    void onDirectoryChanged(int anim) {
+    void refreshDirectory(int anim) {
         final FragmentManager fm = getFragmentManager();
         final RootInfo root = getCurrentRoot();
         final DocumentInfo cwd = getCurrentDirectory();
@@ -178,12 +178,12 @@
             DirectoryFragment.showSearch(fm, root, mState.currentSearch, anim);
         } else {
             // Normal boring directory
-            DirectoryFragment.showNormal(fm, root, cwd, anim);
+            DirectoryFragment.showDirectory(fm, root, cwd, anim);
         }
     }
 
     @Override
-    public void onDocumentPicked(DocumentInfo doc, DocumentContext context) {
+    public void onDocumentPicked(DocumentInfo doc, SiblingProvider siblings) {
         final FragmentManager fm = getFragmentManager();
         if (doc.isContainer()) {
             openContainerDocument(doc);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Events.java b/packages/DocumentsUI/src/com/android/documentsui/Events.java
index 1b5b60de..10a78b9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Events.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Events.java
@@ -111,17 +111,15 @@
 
     public static final class MotionInputEvent implements InputEvent {
         private final MotionEvent mEvent;
-        private final RecyclerView mView;
         private final int mPosition;
 
         public MotionInputEvent(MotionEvent event, RecyclerView view) {
             mEvent = event;
-            mView = view;
 
             // Consider determining position lazily as an optimization.
-            View child = mView.findChildViewUnder(mEvent.getX(), mEvent.getY());
-            mPosition = (child != null)
-                    ? mView.getChildAdapterPosition(child)
+            View child = view.findChildViewUnder(mEvent.getX(), mEvent.getY());
+            mPosition = (child!= null)
+                    ? view.getChildAdapterPosition(child)
                     : RecyclerView.NO_POSITION;
         }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FailureDialogFragment.java b/packages/DocumentsUI/src/com/android/documentsui/FailureDialogFragment.java
deleted file mode 100644
index 23074f0..0000000
--- a/packages/DocumentsUI/src/com/android/documentsui/FailureDialogFragment.java
+++ /dev/null
@@ -1,95 +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 android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.app.FragmentManager;
-import android.app.FragmentTransaction;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.text.Html;
-
-import com.android.documentsui.model.DocumentInfo;
-import com.android.documentsui.model.DocumentStack;
-
-import java.util.ArrayList;
-
-/**
- * Alert dialog for failed operations.
- */
-public class FailureDialogFragment extends DialogFragment
-        implements DialogInterface.OnClickListener {
-    private static final String TAG = "FailureDialogFragment";
-
-    private int mTransferMode;
-    private ArrayList<DocumentInfo> mFailedSrcList;
-
-    public static void show(FragmentManager fm, int failure,
-            ArrayList<DocumentInfo> failedSrcList, DocumentStack dstStack, int transferMode) {
-        // TODO: Add support for other failures than copy.
-        if (failure != CopyService.FAILURE_COPY) {
-            return;
-        }
-
-        final Bundle args = new Bundle();
-        args.putInt(CopyService.EXTRA_FAILURE, failure);
-        args.putInt(CopyService.EXTRA_TRANSFER_MODE, transferMode);
-        args.putParcelableArrayList(CopyService.EXTRA_SRC_LIST, failedSrcList);
-
-        final FragmentTransaction ft = fm.beginTransaction();
-        final FailureDialogFragment fragment = new FailureDialogFragment();
-        fragment.setArguments(args);
-
-        ft.add(fragment, TAG);
-        ft.commitAllowingStateLoss();
-    }
-
-    @Override
-    public void onClick(DialogInterface dialog, int whichButton) {
-        if (whichButton == DialogInterface.BUTTON_POSITIVE) {
-            CopyService.start(getActivity(), mFailedSrcList,
-                    (DocumentStack) getActivity().getIntent().getParcelableExtra(
-                            Shared.EXTRA_STACK),
-                            mTransferMode);
-        }
-    }
-
-    @Override
-    public Dialog onCreateDialog(Bundle inState) {
-        super.onCreate(inState);
-
-        mTransferMode = getArguments().getInt(CopyService.EXTRA_TRANSFER_MODE);
-        mFailedSrcList = getArguments().getParcelableArrayList(CopyService.EXTRA_SRC_LIST);
-
-        final StringBuilder list = new StringBuilder("<p>");
-        for (DocumentInfo documentInfo : mFailedSrcList) {
-            list.append(String.format("&#8226; %s<br>", documentInfo.displayName));
-        }
-        list.append("</p>");
-        final String messageFormat = getString(mTransferMode == CopyService.TRANSFER_MODE_COPY ?
-                R.string.copy_failure_alert_content : R.string.move_failure_alert_content);
-        final String message = String.format(messageFormat, list.toString());
-
-        return new AlertDialog.Builder(getActivity())
-                .setMessage(Html.fromHtml(message))
-                .setPositiveButton(R.string.retry, this)
-                .setNegativeButton(android.R.string.cancel, this)
-                .create();
-    }
-}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index 0b6a09f..f51f689 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -16,6 +16,7 @@
 
 package com.android.documentsui;
 
+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;
@@ -43,12 +44,14 @@
 import android.widget.Spinner;
 import android.widget.Toolbar;
 
+import com.android.documentsui.OperationDialogFragment.DialogType;
 import com.android.documentsui.RecentsProvider.ResumeColumns;
 import com.android.documentsui.dirlist.DirectoryFragment;
 import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.DocumentStack;
 import com.android.documentsui.model.DurableUtils;
 import com.android.documentsui.model.RootInfo;
+import com.android.documentsui.services.FileOperationService;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -89,53 +92,53 @@
 
         RootsFragment.show(getFragmentManager(), null);
 
-        if (mState.restored) {
-            if (DEBUG) Log.d(TAG, "Restored instance for uri: " + getIntent().getData());
-            onCurrentDirectoryChanged(ANIM_NONE);
-        } else {
-            Intent intent = getIntent();
-            Uri uri = intent.getData();
+        final Intent intent = getIntent();
+        final Uri uri = intent.getData();
 
-            if (DEBUG) Log.d(TAG, "Creating new instance for uri: " + uri);
+        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
             // loading or restoring the stack.
-            if (!mState.stack.isEmpty()) {
-                if (DEBUG) Log.d(TAG, "Launching with non-empty stack.");
-                // When restoring from a stack, if a URI is present, it should only ever
-                // be a launch URI. Launch URIs support sensible activity management, but
-                // don't specify a real content target.
-                checkState(uri == null || LauncherActivity.isLaunchUri(uri));
-                onCurrentDirectoryChanged(ANIM_NONE);
-            } 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(uri).executeOnExecutor(
-                        ProviderExecutor.forAuthority(uri.getAuthority()));
-            } else {
-                if (DEBUG) Log.d(TAG, "Launching into Home directory.");
-                // If all else fails, try to load "Home" directory.
-                uri = DocumentsContract.buildHomeUri();
-                new RestoreRootTask(uri).executeOnExecutor(
-                        ProviderExecutor.forAuthority(uri.getAuthority()));
-            }
+            //
+            // When restoring from a stack, if a URI is present, it should only ever
+            // be a launch URI. 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 || LauncherActivity.isLaunchUri(uri));
+            refreshCurrentRootAndDirectory(ANIM_NONE);
+        } 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(uri).executeOnExecutor(
+                    ProviderExecutor.forAuthority(uri.getAuthority()));
+        } 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(homeUri).executeOnExecutor(
+                    ProviderExecutor.forAuthority(homeUri.getAuthority()));
+        }
 
-            // TODO: Ensure we're handling CopyService errors correctly across all activities.
-            // Show a failure dialog if there was a failed operation.
-            final int failure = intent.getIntExtra(CopyService.EXTRA_FAILURE, 0);
-            final int transferMode = intent.getIntExtra(CopyService.EXTRA_TRANSFER_MODE,
-                    CopyService.TRANSFER_MODE_COPY);
-            if (failure != 0) {
-                final ArrayList<DocumentInfo> failedSrcList =
-                        intent.getParcelableArrayListExtra(CopyService.EXTRA_SRC_LIST);
-                FailureDialogFragment.show(
-                        getFragmentManager(),
-                        failure,
-                        failedSrcList,
-                        mState.stack,
-                        transferMode);
-            }
+        final @DialogType int dialogType = intent.getIntExtra(
+                FileOperationService.EXTRA_DIALOG_TYPE, DIALOG_TYPE_UNKNOWN);
+        // DialogFragment takes care of restoring the dialog on configuration change.
+        // Only show it manually for the first time (icicle is null).
+        if (icicle == null && dialogType != DIALOG_TYPE_UNKNOWN) {
+            final int opType = intent.getIntExtra(
+                    FileOperationService.EXTRA_OPERATION,
+                    FileOperationService.OPERATION_COPY);
+            final ArrayList<DocumentInfo> srcList =
+                    intent.getParcelableArrayListExtra(FileOperationService.EXTRA_SRC_LIST);
+            OperationDialogFragment.show(
+                    getFragmentManager(),
+                    dialogType,
+                    srcList,
+                    mState.stack,
+                    opType);
         }
     }
 
@@ -253,9 +256,6 @@
 
         pasteFromCb.setEnabled(mClipper.hasItemsToPaste());
 
-        newWindow.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
-        newWindow.setVisible(mProductivityDevice);
-
         Menus.disableHiddenItems(menu, pasteFromCb);
         return true;
     }
@@ -281,32 +281,35 @@
     }
 
     private void createNewWindow() {
+        Metrics.logMultiWindow(this);
         Intent intent = LauncherActivity.createLaunchIntent(this);
         intent.putExtra(Shared.EXTRA_STACK, (Parcelable) mState.stack);
+
+        // 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 (inMultiWindowMode()) {
+            intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_TO_SIDE);
+        }
+
         startActivity(intent);
     }
 
     @Override
-    void onDirectoryChanged(int anim) {
+    void refreshDirectory(int anim) {
         final FragmentManager fm = getFragmentManager();
         final RootInfo root = getCurrentRoot();
         final DocumentInfo cwd = getCurrentDirectory();
 
         if (cwd == null) {
             DirectoryFragment.showRecentsOpen(fm, anim);
-
-            // Start recents in grid when requesting visual things
-            final boolean visualMimes = MimePredicate.mimeMatches(
-                    MimePredicate.VISUAL_MIMES, mState.acceptMimes);
-            mState.userMode = visualMimes ? State.MODE_GRID : State.MODE_LIST;
-            mState.derivedMode = mState.userMode;
         } else {
             if (mState.currentSearch != null) {
                 // Ongoing search
                 DirectoryFragment.showSearch(fm, root, mState.currentSearch, anim);
             } else {
                 // Normal boring directory
-                DirectoryFragment.showNormal(fm, root, cwd, anim);
+                DirectoryFragment.showDirectory(fm, root, cwd, anim);
             }
         }
     }
@@ -323,7 +326,7 @@
     }
 
     @Override
-    public void onDocumentPicked(DocumentInfo doc, @Nullable DocumentContext siblings) {
+    public void onDocumentPicked(DocumentInfo doc, @Nullable SiblingProvider siblings) {
         if (doc.isContainer()) {
             openContainerDocument(doc);
         } else {
@@ -334,7 +337,7 @@
     /**
      * Launches an intent to view the specified document.
      */
-    private void openDocument(DocumentInfo doc, @Nullable DocumentContext siblings) {
+    private void openDocument(DocumentInfo doc, @Nullable SiblingProvider siblings) {
         Intent intent = null;
         if (siblings != null) {
             QuickViewIntentBuilder builder = new QuickViewIntentBuilder(
diff --git a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
index a1213d2..c28fae8 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
@@ -159,8 +159,8 @@
         add("application/vnd.sun.xml.calc.template", icon);
         add("application/x-kspread", icon);
 
-        // Text
-        icon = R.drawable.ic_doc_text;
+        // Document
+        icon = R.drawable.ic_doc_document;
         add("application/vnd.oasis.opendocument.text", icon);
         add("application/vnd.oasis.opendocument.text-master", icon);
         add("application/vnd.oasis.opendocument.text-template", icon);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java b/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java
index b3d0cf3..7930c28 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java
@@ -74,6 +74,9 @@
 
     private void startTask() {
         Intent intent = createLaunchIntent(this);
+
+        // Forward any flags from the original intent.
+        intent.setFlags(getIntent().getFlags());
         if (DEBUG) Log.d(TAG, "Starting new task > " + intent.getData());
         startActivity(intent);
     }
@@ -84,7 +87,7 @@
         startActivity(intent);
     }
 
-    static Intent createLaunchIntent(Context context) {
+    static final Intent createLaunchIntent(Context context) {
         Intent intent = new Intent(context, FilesActivity.class);
         intent.setData(buildLaunchUri());
         return intent;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java b/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
index 113e9d7..4bffc49 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
@@ -16,12 +16,19 @@
 
 package com.android.documentsui;
 
+import static com.android.documentsui.State.MODE_UNKNOWN;
+import static com.android.internal.util.Preconditions.checkArgument;
+
 import android.content.Context;
 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()
@@ -35,6 +42,12 @@
                 .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();
@@ -44,4 +57,14 @@
         PreferenceManager.getDefaultSharedPreferences(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();
+    }
+
+    private static String createKey(RootInfo root) {
+        return ROOT_VIEW_MODE_PREFIX + root.authority + root.rootId;
+    }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Metrics.java b/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
new file mode 100644
index 0000000..eb90b75
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.provider.DocumentsContract;
+import android.util.Log;
+
+import com.android.documentsui.model.RootInfo;
+import com.android.internal.logging.MetricsLogger;
+
+/** @hide */
+public final class Metrics {
+    private static final String TAG = "Metrics";
+
+    // These are the native provider authorities that the metrics code is capable of recognizing and
+    // explicitly counting.
+    private static final String AUTHORITY_MEDIA = "com.android.providers.media.documents";
+    private static final String AUTHORITY_STORAGE = "com.android.externalstorage.documents";
+    private static final String AUTHORITY_DOWNLOADS = "com.android.providers.downloads.documents";
+
+    // These strings have to be whitelisted in tron. Do not change them.
+    private static final String COUNT_LAUNCH_ACTION = "docsui_launch_action";
+    private static final String COUNT_ROOT_VISITED = "docsui_root_visited";
+    private static final String COUNT_OPEN_MIME = "docsui_open_mime";
+    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";
+    private static final String COUNT_MULTI_WINDOW = "docsui_multi_window";
+
+    // 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
+    // #getSanitizedRootIndex}). Apps are also bucketed in this histogram using negative indices
+    // (see below).
+    private static final int ROOT_NONE = 0;
+    private static final int ROOT_OTHER = 1;
+    private static final int ROOT_AUDIO = 2;
+    private static final int ROOT_DEVICE_STORAGE = 3;
+    private static final int ROOT_DOWNLOADS = 4;
+    private static final int ROOT_HOME = 5;
+    private static final int ROOT_IMAGES = 6;
+    private static final int ROOT_RECENTS = 7;
+    private static final int ROOT_VIDEOS = 8;
+    // Apps aren't really "roots", but they are treated as such in the roots fragment UI and so they
+    // are logged analogously to roots. Use negative numbers to identify apps.
+    private static final int ROOT_THIRD_PARTY_APP = -1;
+
+    // Indices for bucketing mime types.
+    private static final int MIME_OTHER = -2; // anything not enumerated below
+    private static final int MIME_NONE = -1; // null mime
+    private static final int MIME_ANY = 0; // */*
+    private static final int MIME_APPLICATION = 1; // application/*
+    private static final int MIME_AUDIO = 2; // audio/*
+    private static final int MIME_IMAGE = 3; // image/*
+    private static final int MIME_MESSAGE = 4; // message/*
+    private static final int MIME_MULTIPART = 5; // multipart/*
+    private static final int MIME_TEXT = 6; // text/*
+    private static final int MIME_VIDEO = 7; // video/*
+
+    /**
+     * Logs when DocumentsUI is started, and how. Call this when DocumentsUI first starts up.
+     *
+     * @param context
+     * @param state
+     * @param intent
+     */
+    public static void logActivityLaunch(Context context, State state, Intent intent) {
+        // Log the launch action.
+        logHistogram(context, COUNT_LAUNCH_ACTION, state.action);
+        // Then log auxiliary data (roots/mime types) associated with some actions.
+        Uri uri = intent.getData();
+        switch (state.action) {
+            case State.ACTION_OPEN:
+                logHistogram(context, COUNT_OPEN_MIME, sanitizeMime(intent.getType()));
+                break;
+            case State.ACTION_CREATE:
+                logHistogram(context, COUNT_CREATE_MIME, sanitizeMime(intent.getType()));
+                break;
+            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;
+            default:
+                break;
+        }
+    }
+
+    /**
+     * Logs a root visited event. Call this when the user clicks on a root in the RootsFragment.
+     *
+     * @param context
+     * @param info
+     */
+    public static void logRootVisited(Context context, RootInfo info) {
+        logHistogram(context, COUNT_ROOT_VISITED, sanitizeRoot(info));
+    }
+
+    /**
+     * Logs an app visited event. Call this when the user clicks on an app in the RootsFragment.
+     *
+     * @param context
+     * @param info
+     */
+    public static void logAppVisited(Context context, ResolveInfo info) {
+        logHistogram(context, COUNT_ROOT_VISITED, sanitizeRoot(info));
+    }
+
+    /**
+     * Logs a multi-window start. Call this when the user spawns a new DocumentsUI window.
+     *
+     * @param context
+     */
+    public static void logMultiWindow(Context context) {
+        logCount(context, COUNT_MULTI_WINDOW);
+    }
+
+    /**
+     * Internal method for making a MetricsLogger.count call. Increments the given counter by 1.
+     *
+     * @param context
+     * @param name The counter to increment.
+     */
+    private static void logCount(Context context, String name) {
+        if (DEBUG) Log.d(TAG, name + ": " + 1);
+        MetricsLogger.count(context, name, 1);
+    }
+
+    /**
+     * Internal method for making a MetricsLogger.histogram call.
+     *
+     * @param context
+     * @param name The name of the histogram.
+     * @param bucket The bucket to increment.
+     */
+    private static void logHistogram(Context context, String name, int bucket) {
+        if (DEBUG) Log.d(TAG, name + ": " + bucket);
+        MetricsLogger.histogram(context, name, bucket);
+    }
+
+    /**
+     * Generates an integer identifying the given root. For privacy, this function only recognizes a
+     * small set of hard-coded roots (ones provided by the system). Other roots are all grouped into
+     * a single ROOT_OTHER bucket.
+     */
+    private static int sanitizeRoot(Uri uri) {
+        if (LauncherActivity.isLaunchUri(uri)) {
+            return ROOT_NONE;
+        }
+
+        switch (uri.getAuthority()) {
+            case AUTHORITY_MEDIA:
+                switch (DocumentsContract.getRootId(uri)) {
+                    case "audio_root":
+                        return ROOT_AUDIO;
+                    case "images_root":
+                        return ROOT_IMAGES;
+                    case "videos_root":
+                        return ROOT_VIDEOS;
+                    default:
+                        return ROOT_OTHER;
+                }
+            case AUTHORITY_STORAGE:
+                if ("home".equals(DocumentsContract.getRootId(uri))) {
+                    return ROOT_HOME;
+                } else {
+                    return ROOT_DEVICE_STORAGE;
+                }
+            case AUTHORITY_DOWNLOADS:
+                return ROOT_DOWNLOADS;
+            default:
+                return ROOT_OTHER;
+        }
+    }
+
+    /** @see #sanitizeRoot(Uri) */
+    private static int sanitizeRoot(RootInfo root) {
+        if (root.isRecents()) {
+            // Recents root is special and only identifiable via this method call. Other roots are
+            // identified by URI.
+            return ROOT_RECENTS;
+        } else {
+            return sanitizeRoot(root.getUri());
+        }
+    }
+
+    /** @see #sanitizeRoot(Uri) */
+    private static int sanitizeRoot(ResolveInfo info) {
+        // Log all apps under a single bucket in the roots histogram.
+        return ROOT_THIRD_PARTY_APP;
+    }
+
+    /**
+     * Generates an int identifying a mime type. For privacy, this function only recognizes a small
+     * set of hard-coded types. For any other type, this function returns "other".
+     *
+     * @param mimeType
+     * @return
+     */
+    private static int sanitizeMime(String mimeType) {
+        if (mimeType == null) {
+            return MIME_NONE;
+        } else if ("*/*".equals(mimeType)) {
+            return MIME_ANY;
+        } else {
+            String type = mimeType.substring(0, mimeType.indexOf('/'));
+            switch (type) {
+                case "application":
+                    return MIME_APPLICATION;
+                case "audio":
+                    return MIME_AUDIO;
+                case "image":
+                    return MIME_IMAGE;
+                case "message":
+                    return MIME_MESSAGE;
+                case "multipart":
+                    return MIME_MULTIPART;
+                case "text":
+                    return MIME_TEXT;
+                case "video":
+                    return MIME_VIDEO;
+            }
+        }
+        // Bucket all other types into one bucket.
+        return MIME_OTHER;
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java b/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
new file mode 100644
index 0000000..5dc4f57
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 android.os.Environment.isStandardDirectory;
+import static com.android.documentsui.Shared.DEBUG;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.content.ContentProvider;
+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.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.provider.DocumentsContract;
+import android.text.TextUtils;
+import android.util.Log;
+
+/**
+ * Activity responsible for handling {@link Intent#ACTION_OPEN_EXTERNAL_DOCUMENT}.
+ */
+public class OpenExternalDirectoryActivity extends Activity {
+    private static final String TAG = "OpenExternalDirectoryActivity";
+    private static final String FM_TAG = "open_external_directory";
+    private static final String EXTERNAL_STORAGE_AUTH = "com.android.externalstorage.documents";
+    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";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final Intent intent = getIntent();
+        if (intent == null || intent.getData() == null) {
+            Log.d(TAG, "missing intent or intent data: " + intent);
+            setResult(RESULT_CANCELED);
+            finish();
+            return;
+        }
+
+        final String path = intent.getData().getPath();
+        final int userId = UserHandle.myUserId();
+        if (!showFragment(this, userId, path)) {
+            setResult(RESULT_CANCELED);
+            finish();
+            return;
+        }
+    }
+
+    /**
+     * Validates the given {@code path} and display the appropriate dialog asking the user to grant
+     * access to it.
+     */
+    static boolean showFragment(Activity activity, int userId, String path) {
+        Log.d(TAG, "showFragment() for path " + path + " and user " + userId);
+        if (path == null) {
+            Log.e(TAG, "INTERNAL ERROR: showFragment() with null path");
+            return false;
+        }
+        File file;
+        try {
+            file = new File(new File(path).getCanonicalPath());
+        } catch (IOException e) {
+            Log.e(TAG, "Could not get canonical file from " + path);
+            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)) {
+            Log.d(TAG, "Directory '" + directory + "' is not standard (full path: '" + path + "')");
+            return false;
+        }
+
+        // Gets volume label and converted path
+        String volumeLabel = null;
+        final List<VolumeInfo> volumes = sm.getVolumes();
+        if (DEBUG) Log.d(TAG, "Number of volumes: " + volumes.size());
+        for (VolumeInfo volume : volumes) {
+            if (isRightVolume(volume, root, userId)) {
+                final File internalRoot = volume.getInternalPathForUser(userId);
+                // Must convert path before calling getDocIdForFileCreateNewDir()
+                if (DEBUG) Log.d(TAG, "Converting " + root + " to " + internalRoot);
+                file = new File(internalRoot, directory);
+                volumeLabel = sm.getBestVolumeDescription(volume);
+                break;
+            }
+        }
+        if (volumeLabel == null) {
+            Log.e(TAG, "Could not get volume for " + path);
+            return false;
+        }
+
+        // Gets the package label.
+        final String appLabel = getAppLabel(activity);
+        if (appLabel == null) {
+            return false;
+        }
+
+        // Sets args that will be retrieve on onCreate()
+        final Bundle args = new Bundle();
+        args.putString(EXTRA_FILE, file.getAbsolutePath());
+        args.putString(EXTRA_VOLUME_LABEL, volumeLabel);
+        args.putString(EXTRA_APP_LABEL, appLabel);
+
+        final FragmentManager fm = activity.getFragmentManager();
+        final FragmentTransaction ft = fm.beginTransaction();
+        final OpenExternalDirectoryDialogFragment fragment =
+                new OpenExternalDirectoryDialogFragment();
+        fragment.setArguments(args);
+        ft.add(fragment, FM_TAG);
+        ft.commitAllowingStateLoss();
+
+        return true;
+    }
+
+    private static String getAppLabel(Activity activity) {
+        final String packageName = activity.getCallingPackage();
+        final PackageManager pm = activity.getPackageManager();
+        try {
+            return pm.getApplicationLabel(pm.getApplicationInfo(packageName, 0)).toString();
+        } catch (NameNotFoundException e) {
+            Log.w(TAG, "Could not get label for package " + packageName);
+            return null;
+        }
+    }
+
+    private static boolean isRightVolume(VolumeInfo volume, String root, int userId) {
+        final File userPath = volume.getPathForUser(userId);
+        final String path = userPath == null ? null : volume.getPathForUser(userId).getPath();
+        final boolean isVisible = volume.isVisibleForWrite(userId);
+        if (DEBUG) {
+            Log.d(TAG, "Volume: " + volume + " userId: " + userId + " root: " + root
+                    + " volumePath: " + volume.getPath().getPath()
+                    + " pathForUser: " + path
+                    + " internalPathForUser: " + volume.getInternalPath()
+                    + " isVisible: " + isVisible);
+        }
+        return volume.isVisibleForWrite(userId) && root.equals(path);
+    }
+
+    private static Intent createGrantedUriPermissionsIntent(ContentProviderClient provider,
+            File file) {
+        // Calls ExternalStorageProvider to get the doc id for the file
+        final Bundle bundle;
+        try {
+            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);
+            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);
+            return null;
+        }
+        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);
+        final Intent intent = new Intent();
+        intent.setData(uri);
+        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
+                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+                | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+                | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
+        return intent;
+    }
+
+    private static class OpenExternalDirectoryDialogFragment extends DialogFragment {
+
+        private File mFile;
+        private String mVolumeLabel;
+        private String mAppLabel;
+        private ContentProviderClient mExternalStorageClient;
+        private ContentResolver mResolver;
+
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            final Bundle args = getArguments();
+            if (args != null) {
+                mFile = new File(args.getString(EXTRA_FILE));
+                mVolumeLabel = args.getString(EXTRA_VOLUME_LABEL);
+                mAppLabel = args.getString(EXTRA_APP_LABEL);
+                mResolver = getContext().getContentResolver();
+            }
+        }
+
+        @Override
+        public void onDestroy() {
+            super.onDestroy();
+            if (mExternalStorageClient != null) {
+                mExternalStorageClient.close();
+            }
+        }
+
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            final String folder = mFile.getName();
+            final Activity activity = getActivity();
+            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);
+                    }
+                    if (which == DialogInterface.BUTTON_NEGATIVE || intent == null) {
+                        activity.setResult(RESULT_CANCELED);
+                    } else {
+                        activity.setResult(RESULT_OK, intent);
+                    }
+                    activity.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)
+                    .setPositiveButton(R.string.allow, listener)
+                    .setNegativeButton(R.string.deny, listener)
+                    .create();
+        }
+
+        @Override
+        public void onCancel(DialogInterface dialog) {
+            super.onCancel(dialog);
+            final Activity activity = getActivity();
+            activity.setResult(RESULT_CANCELED);
+            activity.finish();
+        }
+
+        private synchronized ContentProviderClient getExternalStorageClient() {
+            if (mExternalStorageClient == null) {
+                mExternalStorageClient =
+                        mResolver.acquireContentProviderClient(EXTERNAL_STORAGE_AUTH);
+            }
+            return mExternalStorageClient;
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/OperationDialogFragment.java b/packages/DocumentsUI/src/com/android/documentsui/OperationDialogFragment.java
new file mode 100644
index 0000000..85cc12b
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/OperationDialogFragment.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.documentsui;
+
+import static com.android.documentsui.services.FileOperationService.OpType;
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import android.annotation.IntDef;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.text.Html;
+
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.services.FileOperationService;
+import com.android.documentsui.services.FileOperations;
+import com.android.documentsui.services.Job;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Alert dialog for operation dialogs.
+ */
+public class OperationDialogFragment extends DialogFragment {
+
+    public static final int DIALOG_TYPE_UNKNOWN = 0;
+    public static final int DIALOG_TYPE_FAILURE = 1;
+    public static final int DIALOG_TYPE_CONVERTED = 2;
+
+    @IntDef(flag = true, value = {
+        DIALOG_TYPE_UNKNOWN,
+        DIALOG_TYPE_FAILURE,
+        DIALOG_TYPE_CONVERTED
+    })
+
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DialogType {}
+
+    private static final String TAG = "OperationDialogFragment";
+
+    public static void show(FragmentManager fm, @DialogType int dialogType,
+            ArrayList<DocumentInfo> failedSrcList, DocumentStack dstStack,
+            @OpType int operationType) {
+        final Bundle args = new Bundle();
+        args.putInt(FileOperationService.EXTRA_DIALOG_TYPE, dialogType);
+        args.putInt(FileOperationService.EXTRA_OPERATION, operationType);
+        args.putParcelableArrayList(FileOperationService.EXTRA_SRC_LIST, failedSrcList);
+
+        final FragmentTransaction ft = fm.beginTransaction();
+        final OperationDialogFragment fragment = new OperationDialogFragment();
+        fragment.setArguments(args);
+
+        ft.add(fragment, TAG);
+        ft.commitAllowingStateLoss();
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle inState) {
+        super.onCreate(inState);
+
+        final @DialogType int dialogType =
+              getArguments().getInt(FileOperationService.EXTRA_DIALOG_TYPE);
+        final @OpType int operationType =
+              getArguments().getInt(FileOperationService.EXTRA_OPERATION);
+        final ArrayList<DocumentInfo> srcList = getArguments().getParcelableArrayList(
+                FileOperationService.EXTRA_SRC_LIST);
+
+        final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+        String messageFormat;
+
+        switch (dialogType) {
+            case DIALOG_TYPE_CONVERTED:
+                messageFormat = getString(R.string.copy_converted_warning_content);
+                break;
+
+            case DIALOG_TYPE_FAILURE:
+                switch (operationType) {
+                    case FileOperationService.OPERATION_COPY:
+                        messageFormat = getString(R.string.copy_failure_alert_content);
+                        break;
+                    case FileOperationService.OPERATION_MOVE:
+                        messageFormat = getString(R.string.move_failure_alert_content);
+                        break;
+                    default:
+                        throw new UnsupportedOperationException();
+                }
+                break;
+
+            default:
+                throw new UnsupportedOperationException();
+        }
+
+        final StringBuilder list = new StringBuilder("<p>");
+        for (DocumentInfo documentInfo : srcList) {
+            list.append(String.format("&#8226; %s<br>", documentInfo.displayName));
+        }
+        list.append("</p>");
+        builder.setMessage(Html.fromHtml(String.format(messageFormat, list.toString())));
+        builder.setPositiveButton(
+                R.string.close,
+                new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int id) {
+                        dialog.dismiss();
+                    }
+                });
+
+        return builder.create();
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
index 605c530..4543162 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
@@ -34,7 +34,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 
-import com.android.documentsui.BaseActivity.DocumentContext;
+import com.android.documentsui.BaseActivity.SiblingProvider;
 import com.android.documentsui.model.DocumentInfo;
 
 /**
@@ -43,7 +43,7 @@
 final class QuickViewIntentBuilder {
 
     private final DocumentInfo mDocument;
-    private final DocumentContext mContext;
+    private final SiblingProvider mSiblings;
 
     private final PackageManager mPkgManager;
     private final Resources mResources;
@@ -55,12 +55,12 @@
             PackageManager pkgManager,
             Resources resources,
             DocumentInfo doc,
-            DocumentContext context) {
+            SiblingProvider siblings) {
 
         mPkgManager = pkgManager;
         mResources = resources;
         mDocument = doc;
-        mContext = context;
+        mSiblings = siblings;
     }
 
     /**
@@ -72,19 +72,13 @@
 
         String trustedPkg = mResources.getString(R.string.trusted_quick_viewer_package);
 
-        Intent intent = new Intent(Intent.ACTION_QUICK_VIEW);
-        intent.setDataAndType(mDocument.derivedUri, mDocument.mimeType);
-        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-
-        if (TextUtils.isEmpty(trustedPkg)) {
-            if (hasRegisteredHandler(intent)) {
-                return intent;
-            }
-        } else {
+        if (!TextUtils.isEmpty(trustedPkg)) {
+            Intent intent = new Intent(Intent.ACTION_QUICK_VIEW);
+            intent.setDataAndType(mDocument.derivedUri, mDocument.mimeType);
+            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
             intent.setPackage(trustedPkg);
             if (hasRegisteredHandler(intent)) {
-                // We have a trusted handler. Load all of the docs into the intent.
-                Cursor cursor = mContext.getCursor();
+                Cursor cursor = mSiblings.getCursor();
                 for (int i = 0; i < cursor.getCount(); i++) {
                     onNextItem(i, cursor);
                 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
index 4bd6ae6..0ee54e6 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
@@ -233,12 +233,6 @@
         final DirectoryResult result = new DirectoryResult();
         result.sortOrder = SORT_ORDER_LAST_MODIFIED;
 
-        // Hint to UI if we're still loading
-        final Bundle extras = new Bundle();
-        if (!allDone) {
-            extras.putBoolean(DocumentsContract.EXTRA_LOADING, true);
-        }
-
         final Cursor merged;
         if (cursors.size() > 0) {
             merged = new MergeCursor(cursors.toArray(new Cursor[cursors.size()]));
@@ -247,14 +241,13 @@
             merged = new MatrixCursor(new String[0]);
         }
 
-        final SortingCursorWrapper sorted = new SortingCursorWrapper(merged, result.sortOrder) {
-            @Override
-            public Bundle getExtras() {
-                return extras;
-            }
-        };
+        // Tell the UI if this is an in-progress result. When loading is complete, another update is
+        // sent with EXTRA_LOADING set to false.
+        Bundle extras = new Bundle();
+        extras.putBoolean(DocumentsContract.EXTRA_LOADING, !allDone);
+        merged.setExtras(extras);
 
-        result.cursor = sorted;
+        result.cursor = merged;
 
         return result;
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
index bb6c3b5e..7dac0c1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
@@ -107,7 +107,7 @@
                 mAdapter.update(data);
 
                 // When launched into empty recents, show drawer
-                if (mAdapter.isEmpty() && !state.stackTouched &&
+                if (mAdapter.isEmpty() && !state.hasLocationChanged() &&
                         context instanceof DocumentsActivity) {
                     ((DocumentsActivity) context).setRootsDrawerOpen(true);
                 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
index 82eb732..92ffb93 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
@@ -85,6 +85,8 @@
         public static final String AUTHORITY = "authority";
         public static final String ROOT_ID = Root.COLUMN_ROOT_ID;
         public static final String DOCUMENT_ID = Document.COLUMN_DOCUMENT_ID;
+
+        @Deprecated  // mode is tracked in local preferences now...by root only
         public static final String MODE = "mode";
         public static final String SORT_ORDER = "sortOrder";
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index 72ee6cbab..21e7566 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -63,6 +63,7 @@
 
     private final Context mContext;
     private final ContentObserver mObserver;
+    private OnCacheUpdateListener mCacheUpdateListener;
 
     private final RootInfo mRecentsRoot = new RootInfo();
 
@@ -94,6 +95,10 @@
         }
     }
 
+    static interface OnCacheUpdateListener {
+        void onCacheUpdate();
+    }
+
     /**
      * Gather roots from all known storage providers.
      */
@@ -209,6 +214,13 @@
             return null;
         }
 
+        @Override
+        protected void onPostExecute(Void result) {
+            if (mCacheUpdateListener != null) {
+                mCacheUpdateListener.onCacheUpdate();
+            }
+        }
+
         private void handleDocumentsProvider(ProviderInfo info) {
             // Ignore stopped packages for now; we might query them
             // later during UI interaction.
@@ -348,6 +360,10 @@
         }
     }
 
+    public void setOnCacheUpdateListener(OnCacheUpdateListener cacheUpdateListener) {
+        mCacheUpdateListener = cacheUpdateListener;
+    }
+
     @VisibleForTesting
     static List<RootInfo> getMatchingRoots(Collection<RootInfo> roots, State state) {
         final List<RootInfo> matching = new ArrayList<>();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index 4c844c4..c2aeb86 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -180,10 +180,14 @@
             Item item = mAdapter.getItem(position);
             if (item instanceof RootItem) {
                 BaseActivity activity = BaseActivity.get(RootsFragment.this);
-                activity.onRootPicked(((RootItem) item).root);
+                RootInfo info = ((RootItem) item).root;
+                Metrics.logRootVisited(getActivity(), info);
+                activity.onRootPicked(info);
             } else if (item instanceof AppItem) {
                 DocumentsActivity activity = DocumentsActivity.get(RootsFragment.this);
-                activity.onAppPicked(((AppItem) item).info);
+                ResolveInfo info = ((AppItem) item).info;
+                Metrics.logAppVisited(getActivity(), info);
+                activity.onAppPicked(info);
             } else if (item instanceof SpacerItem) {
                 if (DEBUG) Log.d(TAG, "Ignoring click on spacer item.");
             } else {
@@ -297,7 +301,7 @@
 
             for (final RootInfo root : roots) {
                 final RootItem item = new RootItem(root);
-                if (root.isLibrary() || root.isHome()) {
+                if (root.isLibrary()) {
                     libraries.add(item);
                 } else {
                     others.add(item);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SearchManager.java b/packages/DocumentsUI/src/com/android/documentsui/SearchManager.java
new file mode 100644
index 0000000..fb585a6
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/SearchManager.java
@@ -0,0 +1,210 @@
+/*
+ * 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/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
index 570c9bf..22cb25a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
@@ -17,6 +17,11 @@
 package com.android.documentsui;
 
 import android.content.Context;
+import android.text.format.DateUtils;
+import android.text.format.Time;
+
+import java.util.ArrayList;
+import java.util.List;
 
 /** @hide */
 public final class Shared {
@@ -40,4 +45,35 @@
     public static final String getQuantityString(Context context, int resourceId, int quantity) {
         return context.getResources().getQuantityString(resourceId, quantity, quantity);
     }
+
+    public static String formatTime(Context context, long when) {
+        // TODO: DateUtils should make this easier
+        Time then = new Time();
+        then.set(when);
+        Time now = new Time();
+        now.setToNow();
+
+        int flags = DateUtils.FORMAT_NO_NOON | DateUtils.FORMAT_NO_MIDNIGHT
+                | DateUtils.FORMAT_ABBREV_ALL;
+
+        if (then.year != now.year) {
+            flags |= DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE;
+        } else if (then.yearDay != now.yearDay) {
+            flags |= DateUtils.FORMAT_SHOW_DATE;
+        } else {
+            flags |= DateUtils.FORMAT_SHOW_TIME;
+        }
+
+        return DateUtils.formatDateTime(context, when, flags);
+    }
+
+    /**
+     * A convenient way to transform any list into a (parcelable) ArrayList.
+     * Uses cast if possible, else creates a new list with entries from {@code list}.
+     */
+    public static <T> ArrayList<T> asArrayList(List<T> list) {
+        return list instanceof ArrayList
+            ? (ArrayList<T>) list
+            : new ArrayList<T>(list);
+    }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
deleted file mode 100644
index 6698ff1..0000000
--- a/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
+++ /dev/null
@@ -1,257 +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.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 android.database.AbstractCursor;
-import android.database.Cursor;
-import android.os.Bundle;
-import android.provider.DocumentsContract.Document;
-
-import com.android.documentsui.model.DocumentInfo;
-
-/**
- * Cursor wrapper that presents a sorted view of the underlying cursor. Handles
- * common {@link Document} sorting modes, such as ordering directories first.
- */
-public class SortingCursorWrapper extends AbstractCursor {
-    private final Cursor mCursor;
-
-    private final int[] mPosition;
-    private final String[] mValueString;
-    private final long[] mValueLong;
-
-    public SortingCursorWrapper(Cursor cursor, int sortOrder) {
-        mCursor = cursor;
-
-        final int count = cursor.getCount();
-        mPosition = new int[count];
-        switch (sortOrder) {
-            case SORT_ORDER_DISPLAY_NAME:
-                mValueString = new String[count];
-                mValueLong = null;
-                break;
-            case SORT_ORDER_LAST_MODIFIED:
-            case SORT_ORDER_SIZE:
-                mValueString = null;
-                mValueLong = new long[count];
-                break;
-            default:
-                throw new IllegalArgumentException();
-        }
-
-        cursor.moveToPosition(-1);
-        for (int i = 0; i < count; i++) {
-            cursor.moveToNext();
-            mPosition[i] = i;
-
-            switch (sortOrder) {
-                case SORT_ORDER_DISPLAY_NAME:
-                    final String mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
-                    final String displayName = getCursorString(
-                            cursor, Document.COLUMN_DISPLAY_NAME);
-                    if (Document.MIME_TYPE_DIR.equals(mimeType)) {
-                        mValueString[i] = DocumentInfo.DIR_PREFIX + displayName;
-                    } else {
-                        mValueString[i] = displayName;
-                    }
-                    break;
-                case SORT_ORDER_LAST_MODIFIED:
-                    mValueLong[i] = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED);
-                    break;
-                case SORT_ORDER_SIZE:
-                    mValueLong[i] = getCursorLong(cursor, Document.COLUMN_SIZE);
-                    break;
-            }
-        }
-
-        switch (sortOrder) {
-            case SORT_ORDER_DISPLAY_NAME:
-                synchronized (SortingCursorWrapper.class) {
-
-                    binarySort(mPosition, mValueString);
-                }
-                break;
-            case SORT_ORDER_LAST_MODIFIED:
-            case SORT_ORDER_SIZE:
-                binarySort(mPosition, mValueLong);
-                break;
-        }
-    }
-
-    @Override
-    public Bundle getExtras() {
-        return mCursor.getExtras();
-    }
-
-    @Override
-    public void close() {
-        super.close();
-        mCursor.close();
-    }
-
-    @Override
-    public boolean onMove(int oldPosition, int newPosition) {
-        return mCursor.moveToPosition(mPosition[newPosition]);
-    }
-
-    @Override
-    public String[] getColumnNames() {
-        return mCursor.getColumnNames();
-    }
-
-    @Override
-    public int getCount() {
-        return mCursor.getCount();
-    }
-
-    @Override
-    public double getDouble(int column) {
-        return mCursor.getDouble(column);
-    }
-
-    @Override
-    public float getFloat(int column) {
-        return mCursor.getFloat(column);
-    }
-
-    @Override
-    public int getInt(int column) {
-        return mCursor.getInt(column);
-    }
-
-    @Override
-    public long getLong(int column) {
-        return mCursor.getLong(column);
-    }
-
-    @Override
-    public short getShort(int column) {
-        return mCursor.getShort(column);
-    }
-
-    @Override
-    public String getString(int column) {
-        return mCursor.getString(column);
-    }
-
-    @Override
-    public int getType(int column) {
-        return mCursor.getType(column);
-    }
-
-    @Override
-    public boolean isNull(int column) {
-        return mCursor.isNull(column);
-    }
-
-    /**
-     * Borrowed from TimSort.binarySort(), but modified to sort two column
-     * dataset.
-     */
-    private static void binarySort(int[] position, String[] value) {
-        final int count = position.length;
-        for (int start = 1; start < count; start++) {
-            final int pivotPosition = position[start];
-            final String pivotValue = value[start];
-
-            int left = 0;
-            int right = start;
-
-            while (left < right) {
-                int mid = (left + right) >>> 1;
-
-                final String lhs = pivotValue;
-                final String rhs = value[mid];
-                final int compare = DocumentInfo.compareToIgnoreCaseNullable(lhs, rhs);
-
-                if (compare < 0) {
-                    right = mid;
-                } else {
-                    left = mid + 1;
-                }
-            }
-
-            int n = start - left;
-            switch (n) {
-                case 2:
-                    position[left + 2] = position[left + 1];
-                    value[left + 2] = value[left + 1];
-                case 1:
-                    position[left + 1] = position[left];
-                    value[left + 1] = value[left];
-                    break;
-                default:
-                    System.arraycopy(position, left, position, left + 1, n);
-                    System.arraycopy(value, left, value, left + 1, n);
-            }
-
-            position[left] = pivotPosition;
-            value[left] = pivotValue;
-        }
-    }
-
-    /**
-     * Borrowed from TimSort.binarySort(), but modified to sort two column
-     * dataset.
-     */
-    private static void binarySort(int[] position, long[] value) {
-        final int count = position.length;
-        for (int start = 1; start < count; start++) {
-            final int pivotPosition = position[start];
-            final long pivotValue = value[start];
-
-            int left = 0;
-            int right = start;
-
-            while (left < right) {
-                int mid = (left + right) >>> 1;
-
-                final long lhs = pivotValue;
-                final long rhs = value[mid];
-                final int compare = Long.compare(lhs, rhs);
-                if (compare > 0) {
-                    right = mid;
-                } else {
-                    left = mid + 1;
-                }
-            }
-
-            int n = start - left;
-            switch (n) {
-                case 2:
-                    position[left + 2] = position[left + 1];
-                    value[left + 2] = value[left + 1];
-                case 1:
-                    position[left + 1] = position[left];
-                    value[left + 1] = value[left];
-                    break;
-                default:
-                    System.arraycopy(position, left, position, left + 1, n);
-                    System.arraycopy(value, left, value, left + 1, n);
-            }
-
-            position[left] = pivotPosition;
-            value[left] = pivotValue;
-        }
-    }
-}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java
index c81d4fb..28f7432 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/State.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/State.java
@@ -16,6 +16,7 @@
 
 package com.android.documentsui;
 
+import android.annotation.IntDef;
 import android.content.Intent;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -24,19 +25,45 @@
 import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.DocumentStack;
 import com.android.documentsui.model.DurableUtils;
+import com.android.documentsui.model.RootInfo;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 
 public class State implements android.os.Parcelable {
+
+    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 = {
+            MODE_UNKNOWN,
+            MODE_LIST,
+            MODE_GRID
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ViewMode {}
+    public static final int MODE_UNKNOWN = 0;
+    public static final int MODE_LIST = 1;
+    public static final int MODE_GRID = 2;
+
+    public static final int SORT_ORDER_UNKNOWN = 0;
+    public static final int SORT_ORDER_DISPLAY_NAME = 1;
+    public static final int SORT_ORDER_LAST_MODIFIED = 2;
+    public static final int SORT_ORDER_SIZE = 3;
+
     public int action;
     public String[] acceptMimes;
 
-    /** Explicit user choice */
-    public int userMode = MODE_UNKNOWN;
-    /** Derived after loader */
-    public int derivedMode = MODE_LIST;
+    /** Derived from local preferences */
+    public @ViewMode int derivedMode = MODE_GRID;
 
     /** Explicit user choice */
     public int userSortOrder = SORT_ORDER_UNKNOWN;
@@ -49,7 +76,6 @@
     public boolean localOnly;
     public boolean forceAdvanced;
     public boolean showAdvanced;
-    public boolean stackTouched;
     public boolean restored;
     public boolean directoryCopy;
     public boolean openableOnly;
@@ -58,6 +84,8 @@
 
     /** Current user navigation stack; empty implies recents. */
     public DocumentStack stack = new DocumentStack();
+    private boolean mStackTouched;
+
     /** Currently active search, overriding any stack. */
     public String currentSearch;
 
@@ -70,23 +98,6 @@
     /** Name of the package that started DocsUI */
     public List<String> excludedAuthorities = new ArrayList<>();
 
-    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;
-
-    public static final int MODE_UNKNOWN = 0;
-    public static final int MODE_LIST = 1;
-    public static final int MODE_GRID = 2;
-
-    public static final int SORT_ORDER_UNKNOWN = 0;
-    public static final int SORT_ORDER_DISPLAY_NAME = 1;
-    public static final int SORT_ORDER_LAST_MODIFIED = 2;
-    public static final int SORT_ORDER_SIZE = 3;
-
     public void initAcceptMimes(Intent intent) {
         if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {
             acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES);
@@ -96,6 +107,31 @@
         }
     }
 
+    public void onRootChanged(RootInfo root) {
+        stack.root = root;
+        stack.clear();
+        mStackTouched = true;
+    }
+
+    public void pushDocument(DocumentInfo info) {
+        stack.push(info);
+        mStackTouched = true;
+    }
+
+    public void popDocument() {
+        stack.pop();
+        mStackTouched = true;
+    }
+
+    public void setStack(DocumentStack stack) {
+        this.stack = stack;
+        mStackTouched = true;
+    }
+
+    public boolean hasLocationChanged() {
+        return mStackTouched;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -104,7 +140,6 @@
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(action);
-        out.writeInt(userMode);
         out.writeStringArray(acceptMimes);
         out.writeInt(userSortOrder);
         out.writeInt(allowMultiple ? 1 : 0);
@@ -113,7 +148,6 @@
         out.writeInt(localOnly ? 1 : 0);
         out.writeInt(forceAdvanced ? 1 : 0);
         out.writeInt(showAdvanced ? 1 : 0);
-        out.writeInt(stackTouched ? 1 : 0);
         out.writeInt(restored ? 1 : 0);
         DurableUtils.writeToParcel(out, stack);
         out.writeString(currentSearch);
@@ -121,6 +155,7 @@
         out.writeList(selectedDocumentsForCopy);
         out.writeList(excludedAuthorities);
         out.writeInt(openableOnly ? 1 : 0);
+        out.writeInt(mStackTouched ? 1 : 0);
     }
 
     public static final Creator<State> CREATOR = new Creator<State>() {
@@ -128,7 +163,6 @@
         public State createFromParcel(Parcel in) {
             final State state = new State();
             state.action = in.readInt();
-            state.userMode = in.readInt();
             state.acceptMimes = in.readStringArray();
             state.userSortOrder = in.readInt();
             state.allowMultiple = in.readInt() != 0;
@@ -137,7 +171,6 @@
             state.localOnly = in.readInt() != 0;
             state.forceAdvanced = in.readInt() != 0;
             state.showAdvanced = in.readInt() != 0;
-            state.stackTouched = in.readInt() != 0;
             state.restored = in.readInt() != 0;
             DurableUtils.readFromParcel(in, state.stack);
             state.currentSearch = in.readString();
@@ -145,6 +178,7 @@
             in.readList(state.selectedDocumentsForCopy, null);
             in.readList(state.excludedAuthorities, null);
             state.openableOnly = in.readInt() != 0;
+            state.mStackTouched = in.readInt() != 0;
             return state;
         }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 770d011..f57aa4b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -20,15 +20,14 @@
 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.MODE_UNKNOWN;
 import static com.android.documentsui.State.SORT_ORDER_UNKNOWN;
 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 static com.android.internal.util.Preconditions.checkState;
 import static com.google.common.base.Preconditions.checkArgument;
 
+import android.annotation.StringRes;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.Fragment;
@@ -36,30 +35,24 @@
 import android.app.FragmentTransaction;
 import android.app.LoaderManager.LoaderCallbacks;
 import android.content.ClipData;
-import android.content.ContentProviderClient;
 import android.content.ContentResolver;
-import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
 import android.content.Loader;
 import android.database.Cursor;
-import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Point;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
-import android.os.CancellationSignal;
-import android.os.Looper;
-import android.os.OperationCanceledException;
 import android.os.Parcelable;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
 import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
 import android.support.design.widget.Snackbar;
 import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.GridLayoutManager.SpanSizeLookup;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.LayoutManager;
@@ -67,17 +60,12 @@
 import android.support.v7.widget.RecyclerView.RecyclerListener;
 import android.support.v7.widget.RecyclerView.ViewHolder;
 import android.text.TextUtils;
-import android.text.format.DateUtils;
-import android.text.format.Formatter;
-import android.text.format.Time;
 import android.util.Log;
 import android.util.SparseArray;
-import android.util.SparseBooleanArray;
 import android.util.TypedValue;
 import android.view.ActionMode;
 import android.view.DragEvent;
 import android.view.GestureDetector;
-import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -89,50 +77,39 @@
 import android.widget.TextView;
 
 import com.android.documentsui.BaseActivity;
-import com.android.documentsui.BaseActivity.DocumentContext;
-import com.android.documentsui.CopyService;
 import com.android.documentsui.DirectoryLoader;
 import com.android.documentsui.DirectoryResult;
 import com.android.documentsui.DocumentClipper;
 import com.android.documentsui.DocumentsActivity;
 import com.android.documentsui.DocumentsApplication;
 import com.android.documentsui.Events;
-import com.android.documentsui.IconUtils;
+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.ProviderExecutor;
-import com.android.documentsui.ProviderExecutor.Preemptable;
 import com.android.documentsui.R;
 import com.android.documentsui.RecentLoader;
-import com.android.documentsui.RecentsProvider;
-import com.android.documentsui.RecentsProvider.StateColumns;
-import com.android.documentsui.RootCursorWrapper;
 import com.android.documentsui.RootsCache;
 import com.android.documentsui.Shared;
-import com.android.documentsui.Shared;
 import com.android.documentsui.Snackbars;
 import com.android.documentsui.State;
-import com.android.documentsui.ThumbnailCache;
 import com.android.documentsui.dirlist.MultiSelectManager.Selection;
 import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.DocumentStack;
 import com.android.documentsui.model.RootInfo;
-import com.android.internal.annotations.GuardedBy;
+import com.android.documentsui.services.FileOperationService;
+import com.android.documentsui.services.FileOperations;
 
 import com.google.common.collect.Lists;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
 /**
  * Display the documents inside a single directory.
  */
-public class DirectoryFragment extends Fragment {
-
-    public static final String TAG = "DirectoryFragment";
+public class DirectoryFragment extends Fragment implements DocumentsAdapter.Environment {
 
     public static final int TYPE_NORMAL = 1;
     public static final int TYPE_SEARCH = 2;
@@ -145,8 +122,13 @@
 
     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 boolean DEBUG_ENABLE_DND = true;
+    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";
@@ -157,20 +139,19 @@
     private Model mModel;
     private MultiSelectManager mSelectionManager;
     private Model.UpdateListener mModelUpdateListener = new ModelUpdateListener();
-    private ItemClickListener mItemClickListener = new ItemClickListener();
+    private ItemEventListener mItemEventListener = new ItemEventListener();
+
+    private IconHelper mIconHelper;
 
     private View mEmptyView;
     private RecyclerView mRecView;
+    private ListeningGestureDetector mGestureDetector;
 
     private int mType = TYPE_NORMAL;
     private String mStateKey;
 
-    private int mLastMode = MODE_UNKNOWN;
     private int mLastSortOrder = SORT_ORDER_UNKNOWN;
     private boolean mLastShowSize;
-    private boolean mHideGridTitles;
-    private boolean mSvelteRecents;
-    private Point mThumbSize;
     private DocumentsAdapter mAdapter;
     private LoaderCallbacks<DirectoryResult> mCallbacks;
     private FragmentTuner mTuner;
@@ -183,66 +164,6 @@
     private MessageBar mMessageBar;
     private View mProgressBar;
 
-    private int mSelectedItemColor;
-    private int mDefaultItemColor;
-
-    public static void showNormal(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);
-    }
-
-    public static void showRecentsOpen(FragmentManager fm, int anim) {
-        show(fm, TYPE_RECENT_OPEN, null, null, null, anim);
-    }
-
-    private static void show(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);
-
-        final FragmentTransaction ft = fm.beginTransaction();
-        switch (anim) {
-            case ANIM_SIDE:
-                args.putBoolean(EXTRA_IGNORE_STATE, true);
-                break;
-            case ANIM_DOWN:
-                args.putBoolean(EXTRA_IGNORE_STATE, true);
-                ft.setCustomAnimations(R.animator.dir_down, R.animator.dir_frozen);
-                break;
-            case ANIM_UP:
-                ft.setCustomAnimations(R.animator.dir_frozen, R.animator.dir_up);
-                break;
-        }
-
-        final DirectoryFragment fragment = new DirectoryFragment();
-        fragment.setArguments(args);
-
-        ft.replace(R.id.container_directory, fragment);
-        ft.commitAllowingStateLoss();
-    }
-
-    private static String buildStateKey(RootInfo root, DocumentInfo doc) {
-        final StringBuilder builder = new StringBuilder();
-        builder.append(root != null ? root.authority : "null").append(';');
-        builder.append(root != null ? root.rootId : "null").append(';');
-        builder.append(doc != null ? doc.documentId : "null");
-        return builder.toString();
-    }
-
-    public static @Nullable DirectoryFragment get(FragmentManager fm) {
-        // TODO: deal with multiple directories shown at once
-        Fragment fragment = fm.findFragmentById(R.id.container_directory);
-        return fragment instanceof DirectoryFragment
-                ? (DirectoryFragment) fragment
-                : null;
-    }
-
     @Override
     public View onCreateView(
             LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@@ -313,54 +234,30 @@
         final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
         final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
 
-        mAdapter = new DocumentsAdapter(context);
+        mIconHelper = new IconHelper(context, MODE_GRID);
+
+        mAdapter = new SectionBreakDocumentsAdapterWrapper(
+                this, new ModelBackedDocumentsAdapter(this, mIconHelper));
+
         mRecView.setAdapter(mAdapter);
 
-        mDefaultItemColor = context.getResources().getColor(R.color.item_doc_background);
-        mSelectedItemColor = context.getResources().getColor(R.color.item_doc_background_selected);
+        mGestureDetector = new ListeningGestureDetector(this.getContext(), new GestureListener());
 
-        GestureDetector.SimpleOnGestureListener listener =
-                new GestureDetector.SimpleOnGestureListener() {
-                    @Override
-                    public boolean onSingleTapUp(MotionEvent e) {
-                        return DirectoryFragment.this.onSingleTapUp(e);
-                    }
-                    @Override
-                    public boolean onDoubleTap(MotionEvent e) {
-                        Log.d(TAG, "Handling double tap.");
-                        return DirectoryFragment.this.onDoubleTap(e);
-                    }
-                };
-
-        final GestureDetector detector = new GestureDetector(this.getContext(), listener);
-        detector.setOnDoubleTapListener(listener);
-
-        mRecView.addOnItemTouchListener(
-                new OnItemTouchListener() {
-                    @Override
-                    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
-                        detector.onTouchEvent(e);
-                        return false;
-                    }
-
-                    @Override
-                    public void onTouchEvent(RecyclerView rv, MotionEvent e) {}
-
-                    @Override
-                    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
-                });
+        mRecView.addOnItemTouchListener(mGestureDetector);
 
         // 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.
         mSelectionManager = new MultiSelectManager(
                 mRecView,
+                mAdapter,
                 state.allowMultiple
                     ? MultiSelectManager.MODE_MULTIPLE
                     : MultiSelectManager.MODE_SINGLE);
         mSelectionManager.addCallback(new SelectionModeListener());
 
-        mModel = new Model(context, mAdapter);
+        mModel = new Model();
+        mModel.addUpdateListener(mAdapter);
         mModel.addUpdateListener(mModelUpdateListener);
 
         mType = getArguments().getInt(EXTRA_TYPE);
@@ -369,17 +266,20 @@
         mTuner = FragmentTuner.pick(state);
         mClipper = new DocumentClipper(context);
 
+        boolean hideGridTitles;
         if (mType == TYPE_RECENT_OPEN) {
             // Hide titles when showing recents for picking images/videos
-            mHideGridTitles = MimePredicate.mimeMatches(
+            hideGridTitles = MimePredicate.mimeMatches(
                     MimePredicate.VISUAL_MIMES, state.acceptMimes);
         } else {
-            mHideGridTitles = (doc != null) && doc.isGridTitlesHidden();
+            hideGridTitles = (doc != null) && doc.isGridTitlesHidden();
         }
+        GridDocumentHolder.setHideTitles(hideGridTitles);
 
         final ActivityManager am = (ActivityManager) context.getSystemService(
                 Context.ACTIVITY_SERVICE);
-        mSvelteRecents = am.isLowRamDevice() && (mType == TYPE_RECENT_OPEN);
+        boolean svelte = am.isLowRamDevice() && (mType == TYPE_RECENT_OPEN);
+        mIconHelper.setThumbnailsEnabled(!svelte);
 
         mCallbacks = new LoaderCallbacks<DirectoryResult>() {
             @Override
@@ -417,19 +317,12 @@
                 if (!isAdded()) return;
 
                 mModel.update(result);
-
-                // Push latest state up to UI
-                // TODO: if mode change was racing with us, don't overwrite it
-                if (result.mode != MODE_UNKNOWN) {
-                    state.derivedMode = result.mode;
-                }
                 state.derivedSortOrder = result.sortOrder;
-                ((BaseActivity) context).onStateChanged();
 
                 updateDisplayState();
 
                 // When launched into empty recents, show drawer
-                if (mType == TYPE_RECENT_OPEN && mModel.isEmpty() && !state.stackTouched &&
+                if (mType == TYPE_RECENT_OPEN && mModel.isEmpty() && !state.hasLocationChanged() &&
                         context instanceof DocumentsActivity) {
                     ((DocumentsActivity) context).setRootsDrawerOpen(true);
                 }
@@ -439,6 +332,9 @@
                 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);
                 }
 
@@ -453,8 +349,6 @@
 
         // Kick off loader at least once
         getLoaderManager().restartLoader(LOADER_ID, null, mCallbacks);
-
-        updateDisplayState();
     }
 
     @Override
@@ -470,42 +364,30 @@
             return;
         }
 
-        CopyService.start(getActivity(), getDisplayState().selectedDocumentsForCopy,
+        int operationType = data.getIntExtra(
+                FileOperationService.EXTRA_OPERATION,
+                FileOperationService.OPERATION_COPY);
+
+        FileOperations.start(
+                getActivity(),
+                getDisplayState().selectedDocumentsForCopy,
+                getDisplayState().stack.peek(),
                 (DocumentStack) data.getParcelableExtra(Shared.EXTRA_STACK),
-                data.getIntExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_COPY));
-    }
-
-    private int getEventAdapterPosition(MotionEvent e) {
-        View view = mRecView.findChildViewUnder(e.getX(), e.getY());
-        return view != null ? mRecView.getChildAdapterPosition(view) : RecyclerView.NO_POSITION;
-    }
-
-    private boolean onSingleTapUp(MotionEvent e) {
-        // Only respond to touch events.  Single-click mouse events are selection events and are
-        // handled by the selection manager.  Tap events that occur while the selection manager is
-        // active are also selection events.
-        if (Events.isTouchEvent(e) && !mSelectionManager.hasSelection()) {
-            int position = getEventAdapterPosition(e);
-            if (position != RecyclerView.NO_POSITION) {
-                return handleViewItem(position);
-            }
-        }
-        return false;
+                operationType);
     }
 
     protected boolean onDoubleTap(MotionEvent e) {
         if (Events.isMouseEvent(e)) {
-            Log.d(TAG, "Handling double tap from mouse.");
-            int position = getEventAdapterPosition(e);
-            if (position != RecyclerView.NO_POSITION) {
-                return handleViewItem(position);
+            String id = getModelId(e);
+            if (id != null) {
+                return handleViewItem(id);
             }
         }
         return false;
     }
 
-    private boolean handleViewItem(int position) {
-        final Cursor cursor = mModel.getItem(position);
+    private boolean handleViewItem(String id) {
+        final Cursor cursor = mModel.getItem(id);
         checkNotNull(cursor, "Cursor cannot be null.");
         final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
         final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
@@ -529,61 +411,25 @@
         state.dirState.put(mStateKey, container);
     }
 
-    @Override
-    public void onResume() {
-        super.onResume();
-        updateDisplayState();
-    }
-
     public void onDisplayStateChanged() {
         updateDisplayState();
     }
 
-    public void onUserSortOrderChanged() {
-        // Sort order change always triggers reload; we'll trigger state change
-        // on the flip side.
+    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);
     }
 
-    public void onUserModeChanged() {
-        final ContentResolver resolver = getActivity().getContentResolver();
-        final State state = getDisplayState();
-
-        final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
-        final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
-
-        if (root != null && doc != null) {
-            final Uri stateUri = RecentsProvider.buildState(
-                    root.authority, root.rootId, doc.documentId);
-            final ContentValues values = new ContentValues();
-            values.put(StateColumns.MODE, state.userMode);
-
-            new AsyncTask<Void, Void, Void>() {
-                @Override
-                protected Void doInBackground(Void... params) {
-                    resolver.insert(stateUri, values);
-                    return null;
-                }
-            }.execute();
-        }
-
-        // Mode change is just visual change; no need to kick loader, and
-        // deliver change event immediately.
-        state.derivedMode = state.userMode;
-        ((BaseActivity) getActivity()).onStateChanged();
-
+    public void onViewModeChanged() {
+        // Mode change is just visual change; no need to kick loader.
         updateDisplayState();
     }
 
     private void updateDisplayState() {
-        final State state = getDisplayState();
-
-        if (mLastMode == state.derivedMode && mLastShowSize == state.showSize) return;
-        mLastMode = state.derivedMode;
+        State state = getDisplayState();
         mLastShowSize = state.showSize;
-
         updateLayout(state.derivedMode);
-
         mRecView.setAdapter(mAdapter);
     }
 
@@ -592,35 +438,34 @@
      * classes as needed.
      */
     private void updateLayout(int mode) {
-        final int thumbSize;
-
         final LayoutManager layout;
         switch (mode) {
             case MODE_GRID:
-                thumbSize = getResources().getDimensionPixelSize(R.dimen.grid_width);
                 if (mGridLayout == null) {
-                    mGridLayout = new GridLayoutManager(getContext(), mColumnCount );
+                    mGridLayout = new GridLayoutManager(getContext(), mColumnCount);
+                    SpanSizeLookup lookup = mAdapter.createSpanSizeLookup();
+                    if (lookup != null) {
+                        mGridLayout.setSpanSizeLookup(lookup);
+                    }
                 }
                 layout = mGridLayout;
                 break;
             case MODE_LIST:
-                thumbSize = getResources().getDimensionPixelSize(R.dimen.icon_size);
                 if (mListLayout == null) {
                     mListLayout = new LinearLayoutManager(getContext());
                 }
                 layout = mListLayout;
                 break;
-            case MODE_UNKNOWN:
             default:
                 throw new IllegalArgumentException("Unsupported layout mode: " + mode);
         }
 
-        mRecView.setLayoutManager(layout);
-        // TODO: Once b/23691541 is resolved, use a listener within MultiSelectManager instead of
-        // imperatively calling this function.
-        mSelectionManager.handleLayoutChanged();
+        int pad = getDirectoryPadding(mode);
+        mRecView.setPadding(pad, pad, pad, pad);
         // setting layout manager automatically invalidates existing ViewHolders.
-        mThumbSize = new Point(thumbSize, thumbSize);
+        mRecView.setLayoutManager(layout);
+        mSelectionManager.handleLayoutChanged();  // RecyclerView doesn't do this for us
+        mIconHelper.setViewMode(mode);
     }
 
     private int calculateColumnCount() {
@@ -635,6 +480,24 @@
         return columnCount;
     }
 
+    private int getDirectoryPadding(int mode) {
+        switch (mode) {
+            case MODE_GRID:
+                return getResources().getDimensionPixelSize(
+                        R.dimen.grid_container_padding);
+            case MODE_LIST:
+                return getResources().getDimensionPixelSize(
+                        R.dimen.list_container_padding);
+            default:
+                throw new IllegalArgumentException("Unsupported layout mode: " + mode);
+        }
+    }
+
+    @Override
+    public int getColumnCount() {
+        return mColumnCount;
+    }
+
     /**
      * Manages the integration between our ActionMode and MultiSelectManager, initiating
      * ActionMode when there is a selection, canceling it when there is no selection,
@@ -646,12 +509,13 @@
         private Selection mSelected = new Selection();
         private ActionMode mActionMode;
         private int mNoDeleteCount = 0;
+        private int mNoRenameCount = -1;
         private Menu mMenu;
 
         @Override
-        public boolean onBeforeItemStateChange(int position, boolean selected) {
+        public boolean onBeforeItemStateChange(String modelId, boolean selected) {
             if (selected) {
-                final Cursor cursor = mModel.getItem(position);
+                final Cursor cursor = mModel.getItem(modelId);
                 checkNotNull(cursor, "Cursor cannot be null.");
                 final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
                 final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
@@ -661,14 +525,17 @@
         }
 
         @Override
-        public void onItemStateChanged(int position, boolean selected) {
-            final Cursor cursor = mModel.getItem(position);
+        public void onItemStateChanged(String modelId, boolean selected) {
+            final Cursor cursor = mModel.getItem(modelId);
             checkNotNull(cursor, "Cursor cannot be null.");
 
             final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
             if ((docFlags & Document.FLAG_SUPPORTS_DELETE) == 0) {
                 mNoDeleteCount += selected ? 1 : -1;
             }
+            if ((docFlags & Document.FLAG_SUPPORTS_RENAME) != 0) {
+                mNoRenameCount += selected ? 1 : -1;
+            }
         }
 
         @Override
@@ -707,6 +574,7 @@
             mSelectionManager.clearSelection();
             mSelected.clear();
             mNoDeleteCount = 0;
+            mNoRenameCount = -1;
         }
 
         @Override
@@ -724,10 +592,19 @@
             return true;
         }
 
+        boolean canRenameSelection() {
+            return mNoRenameCount == 0 && mSelectionManager.getSelection().size() == 1;
+        }
+
+        boolean canDeleteSelection() {
+            return mNoDeleteCount == 0;
+        }
+
         private void updateActionMenu() {
             checkNotNull(mMenu);
+
             // Delegate update logic to our owning action, since specialized logic is desired.
-            mTuner.updateActionMenu(mMenu, mType, mNoDeleteCount == 0);
+            mTuner.updateActionMenu(mMenu, mType, canDeleteSelection(), canRenameSelection());
             Menus.disableHiddenItems(mMenu);
         }
 
@@ -754,19 +631,20 @@
                     return true;
 
                 case R.id.menu_copy_to:
-                    transferDocuments(selection, CopyService.TRANSFER_MODE_COPY);
+                    transferDocuments(selection, FileOperationService.OPERATION_COPY);
                     mode.finish();
                     return true;
 
                 case R.id.menu_move_to:
                     // Exit selection mode first, so we avoid deselecting deleted documents.
                     mode.finish();
-                    transferDocuments(selection, CopyService.TRANSFER_MODE_MOVE);
+                    transferDocuments(selection, FileOperationService.OPERATION_MOVE);
                     return true;
 
                 case R.id.menu_copy_to_clipboard:
                     if (!selection.isEmpty()) {
                         copySelectionToClipboard(selection);
+                        mode.finish();
                     }
                     return true;
 
@@ -774,6 +652,11 @@
                     selectAllFiles();
                     return true;
 
+                case R.id.menu_rename:
+                    renameDocuments(selection);
+                    mode.finish();
+                    return true;
+
                 default:
                     if (DEBUG) Log.d(TAG, "Unhandled menu item selected: " + item);
                     return false;
@@ -781,14 +664,10 @@
         }
     }
 
-    private static void cancelThumbnailTask(View view) {
+    private void cancelThumbnailTask(View view) {
         final ImageView iconThumb = (ImageView) view.findViewById(R.id.icon_thumb);
         if (iconThumb != null) {
-            final ThumbnailAsyncTask oldTask = (ThumbnailAsyncTask) iconThumb.getTag();
-            if (oldTask != null) {
-                oldTask.preempt();
-                iconThumb.setTag(null);
-            }
+            mIconHelper.stopLoading(iconThumb);
         }
     }
 
@@ -851,13 +730,33 @@
     }
 
     private void deleteDocuments(final Selection selected) {
+
+        checkArgument(!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());
+
+                checkState(DELETE_JOB_DELAY > DELETE_UNDO_TIMEOUT);
+                String operationId = FileOperations.delete(
+                        getActivity(), docs, srcParent, getDisplayState().stack,
+                        DELETE_JOB_DELAY);
+                showDeleteSnackbar(hidden, operationId);
+            }
+        }.execute(selected);
+    }
+
+    private void showDeleteSnackbar(final SparseArray<String> hidden, final String jobId) {
+
         Context context = getActivity();
-        String message = Shared.getQuantityString(context, R.plurals.deleting, selected.size());
+        String message = Shared.getQuantityString(context, R.plurals.deleting, hidden.size());
 
-        mModel.markForDeletion(selected);
-
+        // 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, Snackbar.LENGTH_LONG)
+        Snackbars.makeSnackbar(activity, message, DELETE_UNDO_TIMEOUT)
                 .setAction(
                         R.string.undo,
                         new View.OnClickListener() {
@@ -869,20 +768,9 @@
                             @Override
                             public void onDismissed(Snackbar snackbar, int event) {
                                 if (event == Snackbar.Callback.DISMISS_EVENT_ACTION) {
-                                    mModel.undoDeletion();
-                                } else {
-                                    mModel.finalizeDeletion(
-                                            new Model.DeletionListener() {
-                                                @Override
-                                                public void onError() {
-                                                    Snackbars.makeSnackbar(
-                                                            activity,
-                                                            R.string.toast_failed_delete,
-                                                            Snackbar.LENGTH_LONG)
-                                                            .show();
-
-                                                }
-                                            });
+                                    // If the delete was cancelled, just unhide the files.
+                                    FileOperations.cancel(activity, jobId);
+                                    mAdapter.unhide(hidden);
                                 }
                             }
                         })
@@ -911,336 +799,94 @@
                     }
                 }
                 intent.putExtra(Shared.EXTRA_DIRECTORY_COPY, directoryCopy);
-                intent.putExtra(CopyService.EXTRA_TRANSFER_MODE, mode);
+                intent.putExtra(FileOperationService.EXTRA_OPERATION, mode);
                 startActivityForResult(intent, REQUEST_COPY_DESTINATION);
             }
         }.execute(selected);
     }
 
-    private State getDisplayState() {
+    private void renameDocuments(Selection selected) {
+        // Batch renaming not supported
+        // Rename option is only available in menu when 1 document selected
+        checkArgument(selected.size() == 1);
+
+        new GetDocumentsTask() {
+            @Override
+            void onDocumentsReady(List<DocumentInfo> docs) {
+                RenameDocumentFragment.show(getFragmentManager(), docs.get(0));
+            }
+        }.execute(selected);
+    }
+
+    @Override
+    public void initDocumentHolder(DocumentHolder holder) {
+        holder.addEventListener(mItemEventListener);
+        holder.addOnKeyListener(mSelectionManager);
+    }
+
+    @Override
+    public void onBindDocumentHolder(DocumentHolder holder, Cursor cursor) {
+        if (DEBUG_ENABLE_DND) {
+            setupDragAndDropOnDocumentView(holder.itemView, cursor);
+        }
+    }
+
+    @Override
+    public State getDisplayState() {
         return ((BaseActivity) getActivity()).getDisplayState();
     }
 
-    // Provide a reference to the views for each data item
-    // Complex data items may need more than one view per item, and
-    // you provide access to all the views for a data item in a view holder
-    private final class DocumentHolder
-            extends RecyclerView.ViewHolder
-            implements View.OnKeyListener
-    {
-        public String docId;  // The stable document id.
-        private ClickListener mClickListener;
-        private View.OnKeyListener mKeyListener;
-
-        public DocumentHolder(View view) {
-            super(view);
-            view.setOnKeyListener(this);
-        }
-
-        public void setSelected(boolean selected) {
-            itemView.setActivated(selected);
-            itemView.setBackgroundColor(selected ? mSelectedItemColor : mDefaultItemColor);
-        }
-
-        @Override
-        public boolean onKey(View v, int keyCode, KeyEvent event) {
-            // Intercept enter key-up events, and treat them as clicks.  Forward other events.
-            if (event.getAction() == KeyEvent.ACTION_UP &&
-                    keyCode == KeyEvent.KEYCODE_ENTER) {
-                if (mClickListener != null) {
-                    mClickListener.onClick(this);
-                }
-                return true;
-            } else if (mKeyListener != null) {
-                return mKeyListener.onKey(v, keyCode, event);
-            }
-            return false;
-        }
-
-        public void addClickListener(ClickListener listener) {
-            // Just handle one for now; switch to a list if necessary.
-            checkState(mClickListener == null);
-            mClickListener = listener;
-        }
-
-        public void addOnKeyListener(View.OnKeyListener listener) {
-            // Just handle one for now; switch to a list if necessary.
-            checkState(mKeyListener == null);
-            mKeyListener = listener;
-        }
+    @Override
+    public Model getModel() {
+        return mModel;
     }
 
-    interface ClickListener {
-        public void onClick(DocumentHolder doc);
+    @Override
+    public boolean isDocumentEnabled(String docMimeType, int docFlags) {
+        return mTuner.isDocumentEnabled(docMimeType, docFlags);
     }
 
-    void showEmptyView() {
+    private void showEmptyDirectory() {
+        showEmptyView(R.string.empty);
+    }
+
+    private void showNoResults(RootInfo root) {
+        CharSequence msg = getContext().getResources().getText(R.string.no_results);
+        showEmptyView(String.format(String.valueOf(msg), root.title));
+    }
+
+    // Shows an error indicating documents couldn't be queried.
+    private void showQueryError() {
+        showEmptyView(R.string.query_error);
+    }
+
+    private void showEmptyView(@StringRes int id) {
+        showEmptyView(getContext().getResources().getText(id));
+    }
+
+    private void showEmptyView(CharSequence msg) {
+        View content = mEmptyView.findViewById(R.id.content);
+        TextView msgView = (TextView) mEmptyView.findViewById(R.id.message);
+        msgView.setText(msg);
+
+        content.animate().cancel();  // cancel any ongoing animations
+
+        content.setAlpha(0);
         mEmptyView.setVisibility(View.VISIBLE);
         mRecView.setVisibility(View.GONE);
-        TextView msg = (TextView) mEmptyView.findViewById(R.id.message);
-        msg.setText(R.string.empty);
-        // No retry button for the empty view.
-        mEmptyView.findViewById(R.id.button_retry).setVisibility(View.GONE);
+
+        // fade in the content, so it looks purdy like
+        content.animate()
+                .alpha(1f)
+                .setDuration(EMPTY_REVEAL_DURATION)
+                .setListener(null);
     }
 
-    void showErrorView() {
-        mEmptyView.setVisibility(View.VISIBLE);
-        mRecView.setVisibility(View.GONE);
-        TextView msg = (TextView) mEmptyView.findViewById(R.id.message);
-        msg.setText(R.string.query_error);
-        // TODO: Enable this once the retry button does something.
-        mEmptyView.findViewById(R.id.button_retry).setVisibility(View.GONE);
-    }
-
-    void showRecyclerView() {
+    private void showDirectory() {
         mEmptyView.setVisibility(View.GONE);
         mRecView.setVisibility(View.VISIBLE);
     }
 
-    private final class DocumentsAdapter extends RecyclerView.Adapter<DocumentHolder> {
-
-        private final Context mContext;
-        private final LayoutInflater mInflater;
-
-        public DocumentsAdapter(Context context) {
-            mContext = context;
-            mInflater = LayoutInflater.from(context);
-        }
-
-        @Override
-        public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-            final State state = getDisplayState();
-            final LayoutInflater inflater = LayoutInflater.from(getContext());
-            View item = null;
-            switch (state.derivedMode) {
-                case MODE_GRID:
-                    item = inflater.inflate(R.layout.item_doc_grid, parent, false);
-                    break;
-                case MODE_LIST:
-                    item = inflater.inflate(R.layout.item_doc_list, parent, false);
-                    break;
-                case MODE_UNKNOWN:
-                default:
-                    throw new IllegalStateException("Unsupported layout mode.");
-            }
-
-            DocumentHolder holder = new DocumentHolder(item);
-            holder.addClickListener(mItemClickListener);
-            holder.addOnKeyListener(mSelectionManager);
-            return holder;
-        }
-
-        /**
-         * Deal with selection changed events by using a custom ItemAnimator that just changes the
-         * background color.  This works around focus issues (otherwise items lose focus when their
-         * selection state changes) but also optimizes change animations for selection.
-         */
-        @Override
-        public void onBindViewHolder(DocumentHolder holder, int position, List<Object> payload) {
-            final View itemView = holder.itemView;
-
-            if (payload.contains(MultiSelectManager.SELECTION_CHANGED_MARKER)) {
-                final boolean selected = isSelected(position);
-                itemView.setActivated(selected);
-                return;
-            } else {
-                onBindViewHolder(holder, position);
-            }
-        }
-
-        @Override
-        public void onBindViewHolder(DocumentHolder holder, int position) {
-
-            final Context context = getContext();
-            final State state = getDisplayState();
-            final RootsCache roots = DocumentsApplication.getRootsCache(context);
-            final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
-                    context, mThumbSize);
-
-            final Cursor cursor = mModel.getItem(position);
-            checkNotNull(cursor, "Cursor cannot be null.");
-
-            final String docAuthority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
-            final String docRootId = getCursorString(cursor, RootCursorWrapper.COLUMN_ROOT_ID);
-            final String docId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
-            final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
-            final String docDisplayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
-            final long docLastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED);
-            final int docIcon = getCursorInt(cursor, Document.COLUMN_ICON);
-            final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
-            final String docSummary = getCursorString(cursor, Document.COLUMN_SUMMARY);
-            final long docSize = getCursorLong(cursor, Document.COLUMN_SIZE);
-
-            holder.docId = docId;
-            final View itemView = holder.itemView;
-
-            holder.setSelected(isSelected(position));
-
-            final ImageView iconMime = (ImageView) itemView.findViewById(R.id.icon_mime);
-            final ImageView iconThumb = (ImageView) itemView.findViewById(R.id.icon_thumb);
-            final TextView title = (TextView) itemView.findViewById(android.R.id.title);
-            final ImageView icon1 = (ImageView) itemView.findViewById(android.R.id.icon1);
-            final TextView summary = (TextView) itemView.findViewById(android.R.id.summary);
-            final TextView date = (TextView) itemView.findViewById(R.id.date);
-            final TextView size = (TextView) itemView.findViewById(R.id.size);
-
-            final ThumbnailAsyncTask oldTask = (ThumbnailAsyncTask) iconThumb.getTag();
-            if (oldTask != null) {
-                oldTask.preempt();
-                iconThumb.setTag(null);
-            }
-
-            iconMime.animate().cancel();
-            iconThumb.animate().cancel();
-
-            final boolean supportsThumbnail = (docFlags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
-            final boolean allowThumbnail = (state.derivedMode == MODE_GRID)
-                    || MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, docMimeType);
-            final boolean showThumbnail = supportsThumbnail && allowThumbnail && !mSvelteRecents;
-
-            final boolean enabled = mTuner.isDocumentEnabled(docMimeType, docFlags);
-            final float iconAlpha = (state.derivedMode == MODE_LIST && !enabled) ? 0.5f : 1f;
-
-            boolean cacheHit = false;
-            if (showThumbnail) {
-                final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId);
-                final Bitmap cachedResult = thumbs.get(uri);
-                if (cachedResult != null) {
-                    iconThumb.setImageBitmap(cachedResult);
-                    cacheHit = true;
-                } else {
-                    iconThumb.setImageDrawable(null);
-                    // TODO: Hang this off DocumentHolder?
-                    final ThumbnailAsyncTask task = new ThumbnailAsyncTask(
-                            uri, iconMime, iconThumb, mThumbSize, iconAlpha);
-                    iconThumb.setTag(task);
-                    ProviderExecutor.forAuthority(docAuthority).execute(task);
-                }
-            }
-
-            // Always throw MIME icon into place, even when a thumbnail is being
-            // loaded in background.
-            if (cacheHit) {
-                iconMime.setAlpha(0f);
-                iconMime.setImageDrawable(null);
-                iconThumb.setAlpha(1f);
-            } else {
-                iconMime.setAlpha(1f);
-                iconThumb.setAlpha(0f);
-                iconThumb.setImageDrawable(null);
-                iconMime.setImageDrawable(
-                        getDocumentIcon(mContext, docAuthority, docId, docMimeType, docIcon, state));
-            }
-
-            if ((state.derivedMode == MODE_GRID) && mHideGridTitles) {
-                title.setVisibility(View.GONE);
-            } else {
-                title.setText(docDisplayName);
-                title.setVisibility(View.VISIBLE);
-            }
-
-            Drawable iconDrawable = null;
-            if (mType == TYPE_RECENT_OPEN) {
-                // We've already had to enumerate roots before any results can
-                // be shown, so this will never block.
-                final RootInfo root = roots.getRootBlocking(docAuthority, docRootId);
-                iconDrawable = root.loadIcon(mContext);
-
-                if (summary != null) {
-                    final boolean alwaysShowSummary = getResources()
-                            .getBoolean(R.bool.always_show_summary);
-                    if (alwaysShowSummary) {
-                        summary.setText(root.getDirectoryString());
-                        summary.setVisibility(View.VISIBLE);
-                    } else {
-                        if (iconDrawable != null && roots.isIconUniqueBlocking(root)) {
-                            // No summary needed if icon speaks for itself
-                            summary.setVisibility(View.INVISIBLE);
-                        } else {
-                            summary.setText(root.getDirectoryString());
-                            summary.setVisibility(View.VISIBLE);
-                            summary.setTextAlignment(TextView.TEXT_ALIGNMENT_TEXT_END);
-                        }
-                    }
-                }
-            } else {
-                // Directories showing thumbnails in grid mode get a little icon
-                // hint to remind user they're a directory.
-                if (Document.MIME_TYPE_DIR.equals(docMimeType) && state.derivedMode == MODE_GRID
-                        && showThumbnail) {
-                    iconDrawable = IconUtils.applyTintAttr(mContext, R.drawable.ic_doc_folder,
-                            android.R.attr.textColorPrimaryInverse);
-                }
-
-                if (summary != null) {
-                    if (docSummary != null) {
-                        summary.setText(docSummary);
-                        summary.setVisibility(View.VISIBLE);
-                    } else {
-                        summary.setVisibility(View.INVISIBLE);
-                    }
-                }
-            }
-
-            if (iconDrawable != null) {
-                icon1.setVisibility(View.VISIBLE);
-                icon1.setImageDrawable(iconDrawable);
-            } else {
-                icon1.setVisibility(View.GONE);
-            }
-
-            if (docLastModified == -1) {
-                date.setText(null);
-            } else {
-                date.setText(formatTime(mContext, docLastModified));
-            }
-
-            if (!state.showSize || Document.MIME_TYPE_DIR.equals(docMimeType) || docSize == -1) {
-                size.setVisibility(View.GONE);
-            } else {
-                size.setVisibility(View.VISIBLE);
-                size.setText(Formatter.formatFileSize(mContext, docSize));
-            }
-
-            setEnabledRecursive(itemView, enabled);
-
-            iconMime.setAlpha(iconAlpha);
-            iconThumb.setAlpha(iconAlpha);
-            icon1.setAlpha(iconAlpha);
-
-            if (DEBUG_ENABLE_DND) {
-                setupDragAndDropOnDocumentView(itemView, cursor);
-            }
-        }
-
-        @Override
-        public int getItemCount() {
-            return mModel.getItemCount();
-        }
-
-    }
-
-    private static String formatTime(Context context, long when) {
-        // TODO: DateUtils should make this easier
-        Time then = new Time();
-        then.set(when);
-        Time now = new Time();
-        now.setToNow();
-
-        int flags = DateUtils.FORMAT_NO_NOON | DateUtils.FORMAT_NO_MIDNIGHT
-                | DateUtils.FORMAT_ABBREV_ALL;
-
-        if (then.year != now.year) {
-            flags |= DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE;
-        } else if (then.yearDay != now.yearDay) {
-            flags |= DateUtils.FORMAT_SHOW_DATE;
-        } else {
-            flags |= DateUtils.FORMAT_SHOW_TIME;
-        }
-
-        return DateUtils.formatDateTime(context, when, flags);
-    }
-
     private String findCommonMimeType(List<String> mimeTypes) {
         String[] commonType = mimeTypes.get(0).split("/");
         if (commonType.length != 2) {
@@ -1265,19 +911,6 @@
         return commonType[0] + "/" + commonType[1];
     }
 
-    private void setEnabledRecursive(View v, boolean enabled) {
-        if (v == null) return;
-        if (v.isEnabled() == enabled) return;
-        v.setEnabled(enabled);
-
-        if (v instanceof ViewGroup) {
-            final ViewGroup vg = (ViewGroup) v;
-            for (int i = vg.getChildCount() - 1; i >= 0; i--) {
-                setEnabledRecursive(vg.getChildAt(i), enabled);
-            }
-        }
-    }
-
     private void copyFromClipboard() {
         new AsyncTask<Void, Void, List<DocumentInfo>>() {
 
@@ -1334,7 +967,7 @@
             tmpStack = curStack;
         }
 
-        CopyService.start(getActivity(), docs, tmpStack, CopyService.TRANSFER_MODE_COPY);
+        FileOperations.copy(getActivity(), docs, tmpStack);
     }
 
     private ClipData getClipDataFromDocuments(List<DocumentInfo> docs) {
@@ -1373,7 +1006,7 @@
                 Snackbars.makeSnackbar(activity,
                         activity.getResources().getQuantityString(
                                 R.plurals.clipboard_files_clipped, docs.size(), docs.size()),
-                                Snackbar.LENGTH_SHORT).show();
+                        Snackbar.LENGTH_SHORT).show();
             }
         }.execute(selection);
     }
@@ -1409,7 +1042,8 @@
     }
 
     public void selectAllFiles() {
-        boolean changed = mSelectionManager.setItemsSelected(0, mModel.getItemCount(), true);
+        // Only select things currently visible in the adapter.
+        boolean changed = mSelectionManager.setItemsSelected(mAdapter.getModelIds(), true);
         if (changed) {
             updateDisplayState();
         }
@@ -1428,11 +1062,7 @@
             view.setOnDragListener(mOnDragListener);
         }
 
-        // Temporary: attaching the listener to the title only.
-        // Attaching to the entire item conflicts with the item long click handler responsible
-        // for item selection.
-        final View title = view.findViewById(android.R.id.title);
-        title.setOnLongClickListener(mLongClickListener);
+        view.setOnLongClickListener(mLongClickListener);
     }
 
     private View.OnDragListener mOnDragListener = new View.OnDragListener() {
@@ -1452,10 +1082,10 @@
                     return true;
 
                 case DragEvent.ACTION_DROP:
-                    int dstPosition = mRecView.getChildAdapterPosition(getContainingItemView(v));
+                    String dstId = getModelId(v);
                     DocumentInfo dstDir = null;
-                    if (dstPosition != android.widget.AdapterView.INVALID_POSITION) {
-                        Cursor dstCursor = mModel.getItem(dstPosition);
+                    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.
@@ -1467,10 +1097,37 @@
         }
     };
 
-    private View getContainingItemView(View view) {
+    /**
+     * Gets the model ID for a given motion event (using the event position)
+     */
+    private String getModelId(MotionEvent e) {
+        View view = mRecView.findChildViewUnder(e.getX(), e.getY());
+        if (view == null) {
+            return null;
+        }
+        RecyclerView.ViewHolder vh = mRecView.getChildViewHolder(view);
+        if (vh instanceof DocumentHolder) {
+            return ((DocumentHolder) vh).modelId;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Gets the model ID for a given RecyclerView item.
+     * @param view A View that is a document item view, or a child of a document item view.
+     * @return The Model ID for the given document, or null if the given view is not associated with
+     *     a document item view.
+     */
+    private String getModelId(View view) {
         while (true) {
             if (view.getLayoutParams() instanceof RecyclerView.LayoutParams) {
-                return view;
+                RecyclerView.ViewHolder vh = mRecView.getChildViewHolder(view);
+                if (vh instanceof DocumentHolder) {
+                    return ((DocumentHolder) vh).modelId;
+                } else {
+                    return null;
+                }
             }
             ViewParent parent = view.getParent();
             if (parent == null || !(parent instanceof View)) {
@@ -1480,41 +1137,23 @@
         }
     }
 
-    private View.OnLongClickListener mLongClickListener = new View.OnLongClickListener() {
-        @Override
-        public boolean onLongClick(View v) {
-            final List<DocumentInfo> docs = getDraggableDocuments(v);
-            if (docs.isEmpty()) {
-                return false;
-            }
-            v.startDrag(
-                    getClipDataFromDocuments(docs),
-                    new DrawableShadowBuilder(getDragShadowIcon(docs)),
-                    null,
-                    View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ |
-                            View.DRAG_FLAG_GLOBAL_URI_WRITE
-            );
-            return true;
-        }
-    };
-
     private List<DocumentInfo> getDraggableDocuments(View currentItemView) {
-        int position = mRecView.getChildAdapterPosition(getContainingItemView(currentItemView));
-        if (position == android.widget.AdapterView.INVALID_POSITION) {
+        String modelId = getModelId(currentItemView);
+        if (modelId == null) {
             return Collections.EMPTY_LIST;
         }
 
         final List<DocumentInfo> selectedDocs =
                 mModel.getDocuments(mSelectionManager.getSelection());
         if (!selectedDocs.isEmpty()) {
-            if (!isSelected(position)) {
+            if (!isSelected(modelId)) {
                 // There is a selection that does not include the current item, drag nothing.
                 return Collections.EMPTY_LIST;
             }
             return selectedDocs;
         }
 
-        final Cursor cursor = mModel.getItem(position);
+        final Cursor cursor = mModel.getItem(modelId);
         checkNotNull(cursor, "Cursor cannot be null.");
         final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
 
@@ -1524,89 +1163,12 @@
     private Drawable getDragShadowIcon(List<DocumentInfo> docs) {
         if (docs.size() == 1) {
             final DocumentInfo doc = docs.get(0);
-            return getDocumentIcon(getActivity(), doc.authority, doc.documentId,
-                    doc.mimeType, doc.icon, getDisplayState());
+            return mIconHelper.getDocumentIcon(getActivity(), doc.authority, doc.documentId,
+                    doc.mimeType, doc.icon);
         }
         return getActivity().getDrawable(R.drawable.ic_doc_generic);
     }
 
-    public static Drawable getDocumentIcon(Context context, String docAuthority, String docId,
-            String docMimeType, int docIcon, State state) {
-        if (docIcon != 0) {
-            return IconUtils.loadPackageIcon(context, docAuthority, docIcon);
-        } else {
-            return IconUtils.loadMimeIcon(context, docMimeType, docAuthority, docId,
-                    state.derivedMode);
-        }
-    }
-
-    private static class ThumbnailAsyncTask extends AsyncTask<Uri, Void, Bitmap>
-            implements Preemptable {
-        private final Uri mUri;
-        private final ImageView mIconMime;
-        private final ImageView mIconThumb;
-        private final Point mThumbSize;
-        private final float mTargetAlpha;
-        private final CancellationSignal mSignal;
-
-        public ThumbnailAsyncTask(Uri uri, ImageView iconMime, ImageView iconThumb, Point thumbSize,
-                float targetAlpha) {
-            mUri = uri;
-            mIconMime = iconMime;
-            mIconThumb = iconThumb;
-            mThumbSize = thumbSize;
-            mTargetAlpha = targetAlpha;
-            mSignal = new CancellationSignal();
-        }
-
-        @Override
-        public void preempt() {
-            cancel(false);
-            mSignal.cancel();
-        }
-
-        @Override
-        protected Bitmap doInBackground(Uri... params) {
-            if (isCancelled()) return null;
-
-            final Context context = mIconThumb.getContext();
-            final ContentResolver resolver = context.getContentResolver();
-
-            ContentProviderClient client = null;
-            Bitmap result = null;
-            try {
-                client = DocumentsApplication.acquireUnstableProviderOrThrow(
-                        resolver, mUri.getAuthority());
-                result = DocumentsContract.getDocumentThumbnail(client, mUri, mThumbSize, mSignal);
-                if (result != null) {
-                    final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
-                            context, mThumbSize);
-                    thumbs.put(mUri, result);
-                }
-            } catch (Exception e) {
-                if (!(e instanceof OperationCanceledException)) {
-                    Log.w(TAG, "Failed to load thumbnail for " + mUri + ": " + e);
-                }
-            } finally {
-                ContentProviderClient.releaseQuietly(client);
-            }
-            return result;
-        }
-
-        @Override
-        protected void onPostExecute(Bitmap result) {
-            if (mIconThumb.getTag() == this && result != null) {
-                mIconThumb.setTag(null);
-                mIconThumb.setImageBitmap(result);
-
-                mIconMime.setAlpha(mTargetAlpha);
-                mIconMime.animate().alpha(0f).start();
-                mIconThumb.setAlpha(0f);
-                mIconThumb.animate().alpha(mTargetAlpha).start();
-            }
-        }
-    }
-
     private class DrawableShadowBuilder extends View.DragShadowBuilder {
 
         private final Drawable mShadow;
@@ -1653,322 +1215,27 @@
         abstract void onDocumentsReady(List<DocumentInfo> docs);
     }
 
-    boolean isSelected(int position) {
-        return mSelectionManager.getSelection().contains(position);
+    @Override
+    public boolean isSelected(String modelId) {
+        return mSelectionManager.getSelection().contains(modelId);
     }
 
-    /**
-     * The data model for the current loaded directory.
-     */
-    @VisibleForTesting
-    public static final class Model implements DocumentContext {
-        private RecyclerView.Adapter<?> mViewAdapter;
-        private Context mContext;
-        private int mCursorCount;
-        private boolean mIsLoading;
-        @GuardedBy("mPendingDelete")
-        private Boolean mPendingDelete = false;
-        @GuardedBy("mPendingDelete")
-        private SparseBooleanArray mMarkedForDeletion = new SparseBooleanArray();
-        private UpdateListener mUpdateListener;
-        @Nullable private Cursor mCursor;
-        @Nullable private String info;
-        @Nullable private String error;
-
-        Model(Context context, RecyclerView.Adapter<?> viewAdapter) {
-            mContext = context;
-            mViewAdapter = viewAdapter;
-        }
-
-        void update(DirectoryResult result) {
-            if (DEBUG) Log.i(TAG, "Updating model with new result set.");
-
-            if (result == null) {
-                mCursor = null;
-                mCursorCount = 0;
-                info = null;
-                error = null;
-                mIsLoading = false;
-                mUpdateListener.onModelUpdate(this);
-                return;
-            }
-
-            if (result.exception != null) {
-                Log.e(TAG, "Error while loading directory contents", result.exception);
-                mUpdateListener.onModelUpdateFailed(result.exception);
-                return;
-            }
-
-            mCursor = result.cursor;
-            mCursorCount = mCursor.getCount();
-
-            final Bundle extras = mCursor.getExtras();
-            if (extras != null) {
-                info = extras.getString(DocumentsContract.EXTRA_INFO);
-                error = extras.getString(DocumentsContract.EXTRA_ERROR);
-                mIsLoading = extras.getBoolean(DocumentsContract.EXTRA_LOADING, false);
-            }
-
-            mUpdateListener.onModelUpdate(this);
-        }
-
-        int getItemCount() {
-            synchronized(mPendingDelete) {
-                return mCursorCount - mMarkedForDeletion.size();
-            }
-        }
-
-        Cursor getItem(int position) {
-            synchronized(mPendingDelete) {
-                // Items marked for deletion are masked out of the UI.  To do this, for every marked
-                // item whose position is less than the requested item position, advance the requested
-                // position by 1.
-                final int originalPos = position;
-                final int size = mMarkedForDeletion.size();
-                for (int i = 0; i < size; ++i) {
-                    // It'd be more concise, but less efficient, to iterate over positions while calling
-                    // mMarkedForDeletion.get.  Instead, iterate over deleted entries.
-                    if (mMarkedForDeletion.keyAt(i) <= position && mMarkedForDeletion.valueAt(i)) {
-                        ++position;
-                    }
-                }
-
-                if (DEBUG && position != originalPos) {
-                    Log.d(TAG, "Item position adjusted for deletion.  Original: " + originalPos
-                            + "  Adjusted: " + position);
-                }
-
-                if (position >= mCursorCount) {
-                    throw new IndexOutOfBoundsException("Attempt to retrieve " + position + " of " +
-                            mCursorCount + " items");
-                }
-
-                mCursor.moveToPosition(position);
-                return mCursor;
-            }
-        }
-
-        private boolean isEmpty() {
-            return mCursorCount == 0;
-        }
-
-        private boolean isLoading() {
-            return mIsLoading;
-        }
-
-        List<DocumentInfo> getDocuments(Selection items) {
-            final int size = (items != null) ? items.size() : 0;
-
-            final List<DocumentInfo> docs =  new ArrayList<>(size);
-            for (int i = 0; i < size; i++) {
-                final Cursor cursor = getItem(items.get(i));
-                checkNotNull(cursor, "Cursor cannot be null.");
-                final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
-                docs.add(doc);
-            }
-            return docs;
+    private class ItemEventListener implements DocumentHolder.EventListener {
+        @Override
+        public boolean onActivate(DocumentHolder doc) {
+            handleViewItem(doc.modelId);
+            return true;
         }
 
         @Override
-        public Cursor getCursor() {
-            if (Looper.myLooper() != Looper.getMainLooper()) {
-                throw new IllegalStateException("Can't call getCursor from non-main thread.");
-            }
-            return mCursor;
-        }
-
-        List<DocumentInfo> getDocumentsMarkedForDeletion() {
-            synchronized (mPendingDelete) {
-                final int size = mMarkedForDeletion.size();
-                List<DocumentInfo> docs =  new ArrayList<>(size);
-
-                for (int i = 0; i < size; ++i) {
-                    final int position = mMarkedForDeletion.keyAt(i);
-                    checkState(position < mCursorCount);
-                    mCursor.moveToPosition(position);
-                    final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(mCursor);
-                    docs.add(doc);
-                }
-                return docs;
-            }
-        }
-
-        /**
-         * Marks the given files for deletion. This will remove them from the UI. Clients must then
-         * call either {@link #undoDeletion()} or {@link #finalizeDeletion()} to cancel or confirm
-         * the deletion, respectively. Only one deletion operation is allowed at a time.
-         *
-         * @param selected A selection representing the files to delete.
-         */
-        void markForDeletion(Selection selected) {
-            synchronized (mPendingDelete) {
-                mPendingDelete = true;
-                // Only one deletion operation at a time.
-                checkState(mMarkedForDeletion.size() == 0);
-                // There should never be more to delete than what exists.
-                checkState(mCursorCount >= selected.size());
-
-                int[] positions = selected.getAll();
-                Arrays.sort(positions);
-
-                // Walk backwards through the set, since we're removing positions.
-                // Otherwise, positions would change after the first modification.
-                for (int p = positions.length - 1; p >= 0; p--) {
-                    mMarkedForDeletion.append(positions[p], true);
-                    mViewAdapter.notifyItemRemoved(positions[p]);
-                    if (DEBUG) Log.d(TAG, "Scheduled " + positions[p] + " for delete.");
-                }
-            }
-        }
-
-        /**
-         * Cancels an ongoing deletion operation. All files currently marked for deletion will be
-         * unmarked, and restored in the UI.  See {@link #markForDeletion(Selection)}.
-         */
-        void undoDeletion() {
-            synchronized (mPendingDelete) {
-                // Iterate over deleted items, temporarily marking them false in the deletion list, and
-                // re-adding them to the UI.
-                final int size = mMarkedForDeletion.size();
-                for (int i = 0; i < size; ++i) {
-                    final int position = mMarkedForDeletion.keyAt(i);
-                    mMarkedForDeletion.put(position, false);
-                    mViewAdapter.notifyItemInserted(position);
-                }
-                resetDeleteData();
-            }
-        }
-
-        private void resetDeleteData() {
-            synchronized (mPendingDelete) {
-                mPendingDelete = false;
-                mMarkedForDeletion.clear();
-            }
-        }
-
-        /**
-         * Finalizes an ongoing deletion operation. All files currently marked for deletion will be
-         * deleted.  See {@link #markForDeletion(Selection)}.
-         *
-         * @param view The view which will be used to interact with the user (e.g. surfacing
-         * snackbars) for errors, info, etc.
-         */
-        void finalizeDeletion(DeletionListener listener) {
-            synchronized (mPendingDelete) {
-                if (mPendingDelete) {
-                    // Necessary to avoid b/25072545. Even when that's resolved, this
-                    // is a nice safe thing to day.
-                    mPendingDelete = false;
-                    final ContentResolver resolver = mContext.getContentResolver();
-                    DeleteFilesTask task = new DeleteFilesTask(resolver, listener);
-                    task.execute();
-                }
-            }
-        }
-
-        /**
-         * A Task which collects the DocumentInfo for documents that have been marked for deletion,
-         * and actually deletes them.
-         */
-        private class DeleteFilesTask extends AsyncTask<Void, Void, List<DocumentInfo>> {
-            private ContentResolver mResolver;
-            private DeletionListener mListener;
-
-            /**
-             * @param resolver A ContentResolver for performing the actual file deletions.
-             * @param errorCallback A Runnable that is executed in the event that one or more errors
-             *     occured while copying files.  Execution will occur on the UI thread.
-             */
-            public DeleteFilesTask(ContentResolver resolver, DeletionListener listener) {
-                mResolver = resolver;
-                mListener = listener;
-            }
-
-            @Override
-            protected List<DocumentInfo> doInBackground(Void... params) {
-                return getDocumentsMarkedForDeletion();
-            }
-
-            @Override
-            protected void onPostExecute(List<DocumentInfo> docs) {
-                boolean hadTrouble = false;
-                for (DocumentInfo doc : docs) {
-                    if (!doc.isDeleteSupported()) {
-                        Log.w(TAG, doc + " could not be deleted.  Skipping...");
-                        hadTrouble = true;
-                        continue;
-                    }
-
-                    ContentProviderClient client = null;
-                    try {
-                        if (DEBUG) Log.d(TAG, "Deleting: " + doc.displayName);
-                        client = DocumentsApplication.acquireUnstableProviderOrThrow(
-                            mResolver, doc.derivedUri.getAuthority());
-                        DocumentsContract.deleteDocument(client, doc.derivedUri);
-                    } catch (Exception e) {
-                        Log.w(TAG, "Failed to delete " + doc);
-                        hadTrouble = true;
-                    } finally {
-                        ContentProviderClient.releaseQuietly(client);
-                    }
-                }
-
-                if (hadTrouble) {
-                    // TODO show which files failed? b/23720103
-                    mListener.onError();
-                    if (DEBUG) Log.d(TAG, "Deletion task completed.  Some deletions failed.");
-                } else {
-                    if (DEBUG) Log.d(TAG, "Deletion task completed successfully.");
-                }
-                resetDeleteData();
-
-                mListener.onCompletion();
-            }
-        }
-
-        static class DeletionListener {
-            /**
-             * Called when deletion has completed (regardless of whether an error occurred).
-             */
-            void onCompletion() {}
-
-            /**
-             * Called at the end of a deletion operation that produced one or more errors.
-             */
-            void onError() {}
-        }
-
-        void addUpdateListener(UpdateListener listener) {
-            checkState(mUpdateListener == null);
-            mUpdateListener = listener;
-        }
-
-        static class UpdateListener {
-            /**
-             * Called when a successful update has occurred.
-             */
-            void onModelUpdate(Model model) {}
-
-            /**
-             * Called when an update has been attempted but failed.
-             */
-            void onModelUpdateFailed(Exception e) {}
+        public boolean onSelect(DocumentHolder doc) {
+            mSelectionManager.toggleSelection(doc.modelId);
+            mSelectionManager.setSelectionRangeBegin(doc.getAdapterPosition());
+            return true;
         }
     }
 
-    private class ItemClickListener implements ClickListener {
-        @Override
-        public void onClick(DocumentHolder doc) {
-            final int position = doc.getAdapterPosition();
-            if (mSelectionManager.hasSelection()) {
-                mSelectionManager.toggleSelection(position);
-            } else {
-                handleViewItem(position);
-            }
-        }
-    }
-
-    private class ModelUpdateListener extends Model.UpdateListener {
+    private final class ModelUpdateListener implements Model.UpdateListener {
         @Override
         public void onModelUpdate(Model model) {
             if (model.info != null || model.error != null) {
@@ -1980,16 +1247,185 @@
             mProgressBar.setVisibility(model.isLoading() ? View.VISIBLE : View.GONE);
 
             if (model.isEmpty()) {
-                showEmptyView();
+                if (getDisplayState().currentSearch != null) {
+                    showNoResults(getDisplayState().stack.root);
+                } else {
+                    showEmptyDirectory();
+                }
             } else {
-                showRecyclerView();
+                showDirectory();
                 mAdapter.notifyDataSetChanged();
             }
         }
 
         @Override
         public void onModelUpdateFailed(Exception e) {
-            showErrorView();
+            showQueryError();
         }
     }
+
+    private View.OnLongClickListener mLongClickListener = new View.OnLongClickListener() {
+        @Override
+        public boolean onLongClick(View v) {
+            if (mGestureDetector.mouseSpawnedLastEvent()) {
+                List<DocumentInfo> docs = getDraggableDocuments(v);
+                if (docs.isEmpty()) {
+                    return false;
+                }
+                v.startDrag(
+                        getClipDataFromDocuments(docs),
+                        new DrawableShadowBuilder(getDragShadowIcon(docs)),
+                        null,
+                        View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ |
+                                View.DRAG_FLAG_GLOBAL_URI_WRITE
+                );
+                return true;
+            }
+
+            return false;
+        }
+    };
+
+    // 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.
+    private static final class ListeningGestureDetector extends GestureDetector
+            implements OnItemTouchListener {
+
+        private int mLastTool = -1;
+
+        public ListeningGestureDetector(Context context, GestureListener listener) {
+            super(context, listener);
+            setOnDoubleTapListener(listener);
+        }
+
+        boolean mouseSpawnedLastEvent() {
+            return Events.isMouseType(mLastTool);
+        }
+
+        boolean touchSpawnedLastEvent() {
+            return Events.isTouchType(mLastTool);
+        }
+
+        @Override
+        public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
+            mLastTool = e.getToolType(0);
+            onTouchEvent(e);  // bounce this forward to our detecty heart
+            return false;
+        }
+
+        @Override
+        public void onTouchEvent(RecyclerView rv, MotionEvent e) {}
+
+        @Override
+        public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
+    }
+
+    /**
+     * The gesture listener for items in the list/grid view. Interprets gestures and sends the
+     * events to the target DocumentHolder, whence they are routed to the appropriate listener.
+     */
+    private class GestureListener extends GestureDetector.SimpleOnGestureListener {
+        @Override
+        public boolean onSingleTapUp(MotionEvent e) {
+            // Single tap logic:
+            // If the selection manager is active, it gets first whack at handling tap
+            // events. Otherwise, tap events are routed to the target DocumentHolder.
+            boolean handled = mSelectionManager.onSingleTapUp(
+                        new MotionInputEvent(e, mRecView));
+
+            if (handled) {
+                return handled;
+            }
+
+            // Give the DocumentHolder a crack at the event.
+            DocumentHolder holder = getTarget(e);
+            if (holder != null) {
+                handled = holder.onSingleTapUp(e);
+            }
+
+            return handled;
+        }
+
+        @Override
+        public void onLongPress(MotionEvent e) {
+            // Long-press events get routed directly to the selection manager. They can be
+            // changed to route through the DocumentHolder if necessary.
+            mSelectionManager.onLongPress(new MotionInputEvent(e, mRecView));
+        }
+
+        @Override
+        public boolean onDoubleTap(MotionEvent e) {
+            // Double-tap events are handled directly by the DirectoryFragment. They can be changed
+            // to route through the DocumentHolder if necessary.
+            return DirectoryFragment.this.onDoubleTap(e);
+        }
+
+        private @Nullable DocumentHolder getTarget(MotionEvent e) {
+            View childView = mRecView.findChildViewUnder(e.getX(), e.getY());
+            if (childView != null) {
+                return (DocumentHolder) mRecView.getChildViewHolder(childView);
+            } else {
+                return null;
+            }
+        }
+    }
+
+    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);
+    }
+
+    public static void showRecentsOpen(FragmentManager fm, int anim) {
+        show(fm, TYPE_RECENT_OPEN, null, null, null, anim);
+    }
+
+    private static void show(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);
+
+        final FragmentTransaction ft = fm.beginTransaction();
+        switch (anim) {
+            case ANIM_SIDE:
+                args.putBoolean(EXTRA_IGNORE_STATE, true);
+                break;
+            case ANIM_DOWN:
+                args.putBoolean(EXTRA_IGNORE_STATE, true);
+                ft.setCustomAnimations(R.animator.dir_down, R.animator.dir_frozen);
+                break;
+            case ANIM_UP:
+                ft.setCustomAnimations(R.animator.dir_frozen, R.animator.dir_up);
+                break;
+        }
+
+        final DirectoryFragment fragment = new DirectoryFragment();
+        fragment.setArguments(args);
+
+        ft.replace(R.id.container_directory, fragment);
+        ft.commitAllowingStateLoss();
+    }
+
+    private static String buildStateKey(RootInfo root, DocumentInfo doc) {
+        final StringBuilder builder = new StringBuilder();
+        builder.append(root != null ? root.authority : "null").append(';');
+        builder.append(root != null ? root.rootId : "null").append(';');
+        builder.append(doc != null ? doc.documentId : "null");
+        return builder.toString();
+    }
+
+    public static @Nullable DirectoryFragment get(FragmentManager fm) {
+        // TODO: deal with multiple directories shown at once
+        Fragment fragment = fm.findFragmentById(R.id.container_directory);
+        return fragment instanceof DirectoryFragment
+                ? (DirectoryFragment) fragment
+                : null;
+    }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java
new file mode 100644
index 0000000..8acf1af
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.internal.util.Preconditions.checkState;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.graphics.Rect;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.RecyclerView;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.documentsui.Events;
+import com.android.documentsui.R;
+import com.android.documentsui.State;
+
+public abstract class DocumentHolder
+        extends RecyclerView.ViewHolder
+        implements View.OnKeyListener {
+
+    public @Nullable String modelId;
+
+    final int mSelectedItemColor;
+    final int mDefaultItemColor;
+    final boolean mAlwaysShowSummary;
+    final Context mContext;
+
+    DocumentHolder.EventListener mEventListener;
+    private View.OnKeyListener mKeyListener;
+    private View mSelectionHotspot;
+
+    public DocumentHolder(Context context, ViewGroup parent, int layout) {
+        this(context, inflateLayout(context, parent, layout));
+    }
+
+    public DocumentHolder(Context context, View item) {
+        super(item);
+
+        itemView.setOnKeyListener(this);
+
+        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);
+
+        mSelectionHotspot = itemView.findViewById(R.id.icon_check);
+    }
+
+    /**
+     * Binds the view to the given item data.
+     * @param cursor
+     * @param modelId
+     * @param state
+     */
+    public abstract void bind(Cursor cursor, String modelId, State state);
+
+    public void setSelected(boolean selected) {
+        itemView.setActivated(selected);
+        itemView.setBackgroundColor(selected ? mSelectedItemColor : mDefaultItemColor);
+    }
+
+    @Override
+    public boolean onKey(View v, int keyCode, KeyEvent event) {
+        // Event listener should always be set.
+        checkNotNull(mEventListener);
+        // Intercept enter key-up events, and treat them as clicks.  Forward other events.
+        if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_ENTER) {
+            return mEventListener.onActivate(this);
+        } else if (mKeyListener != null) {
+            return mKeyListener.onKey(v, keyCode, event);
+        }
+        return false;
+    }
+
+    public void addEventListener(DocumentHolder.EventListener listener) {
+        // Just handle one for now; switch to a list if necessary.
+        checkState(mEventListener == null);
+        mEventListener = listener;
+    }
+
+    public void addOnKeyListener(View.OnKeyListener listener) {
+        // Just handle one for now; switch to a list if necessary.
+        checkState(mKeyListener == null);
+        mKeyListener = listener;
+    }
+
+    public void setEnabled(boolean enabled) {
+        setEnabledRecursive(itemView, enabled);
+    }
+
+    public boolean onSingleTapUp(MotionEvent event) {
+        if (Events.isMouseEvent(event)) {
+            // Mouse clicks select.
+            // TODO:  && input.isPrimaryButtonPressed(), but it is returning false.
+            if (mEventListener != null) {
+                return mEventListener.onSelect(this);
+            }
+        } else if (Events.isTouchEvent(event)) {
+            // Touch events select if they occur in the selection hotspot, otherwise they activate.
+            if (mEventListener == null) {
+                return false;
+            }
+
+            // Do everything in global coordinates - it makes things simpler.
+            Rect rect = new Rect();
+            mSelectionHotspot.getGlobalVisibleRect(rect);
+
+            // If the tap occurred within the icon rect, consider it a selection.
+            if (rect.contains((int)event.getRawX(), (int)event.getRawY())) {
+                return mEventListener.onSelect(this);
+            } else {
+                return mEventListener.onActivate(this);
+            }
+        }
+        return false;
+    }
+
+    static void setEnabledRecursive(View itemView, boolean enabled) {
+        if (itemView == null) return;
+        if (itemView.isEnabled() == enabled) return;
+        itemView.setEnabled(enabled);
+
+        if (itemView instanceof ViewGroup) {
+            final ViewGroup vg = (ViewGroup) itemView;
+            for (int i = vg.getChildCount() - 1; i >= 0; i--) {
+                setEnabledRecursive(vg.getChildAt(i), enabled);
+            }
+        }
+    }
+
+    private static View inflateLayout(Context context, ViewGroup parent, int layout) {
+        final LayoutInflater inflater = LayoutInflater.from(context);
+        return inflater.inflate(layout, parent, false);
+    }
+
+    /**
+     * Implement this in order to be able to respond to events coming from DocumentHolders.
+     */
+    interface EventListener {
+        /**
+         * @param doc The target DocumentHolder
+         * @return Whether the event was handled.
+         */
+        public boolean onActivate(DocumentHolder doc);
+
+        /**
+         * @param doc The target DocumentHolder
+         * @return Whether the event was handled.
+         */
+        public boolean onSelect(DocumentHolder doc);
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java
new file mode 100644
index 0000000..43c2f63
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.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.documentsui.dirlist;
+
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.provider.DocumentsContract.Document;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.util.SparseArray;
+
+import com.android.documentsui.State;
+
+import java.nio.channels.UnsupportedAddressTypeException;
+import java.util.List;
+
+/**
+ * DocumentsAdapter provides glue between a directory Model, and RecylcerView. We've
+ * abstracted this a bit in order to decompose some specialized support
+ * for adding dummy layout objects (@see SectionBreakDocumentsAdapter). Handling of the
+ * dummy layout objects was error prone when interspersed with the core mode / adapter code.
+ *
+ * @see ModelBackedDocumentsAdapter
+ * @see SectionBreakDocumentsAdapter
+ */
+abstract class DocumentsAdapter
+        extends RecyclerView.Adapter<DocumentHolder>
+        implements Model.UpdateListener {
+
+    // Payloads for notifyItemChange to distinguish between selection and other events.
+    static final String SELECTION_CHANGED_MARKER = "Selection-Changed";
+
+    /**
+     * Returns a list of model IDs of items currently in the adapter. Excludes items that are
+     * currently hidden (see {@link #hide(String...)}).
+     *
+     * @return A list of Model IDs.
+     */
+    abstract List<String> getModelIds();
+
+    /**
+     * Triggers item-change notifications by stable ID (as opposed to position).
+     * Passing an unrecognized ID will result in a warning in logcat, but no other error.
+     */
+    abstract void onItemSelectionChanged(String id);
+
+    /**
+     * @return The model ID of the item at the given adapter position.
+     */
+    abstract String getModelId(int position);
+
+    /**
+     * Hides a set of items from the associated RecyclerView.
+     *
+     * @param ids The Model IDs of the items to hide.
+     * @return A SparseArray that maps the hidden IDs to their old positions. This can be used
+     *         to {@link #unhide} the items if necessary.
+     */
+    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.
+     */
+    GridLayoutManager.SpanSizeLookup createSpanSizeLookup() {
+        throw new UnsupportedAddressTypeException();
+    }
+
+    static boolean isDirectory(Cursor cursor) {
+        final String mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+        return Document.MIME_TYPE_DIR.equals(mimeType);
+    }
+
+    boolean isDirectory(Model model, int position) {
+        String modelId = getModelIds().get(position);
+        Cursor cursor = model.getItem(modelId);
+        return isDirectory(cursor);
+    }
+
+    /**
+     * Environmental access for View adapter implementations.
+     */
+    interface Environment {
+        Context getContext();
+        int getColumnCount();
+        State getDisplayState();
+        boolean isSelected(String id);
+        Model getModel();
+        boolean isDocumentEnabled(String mimeType, int flags);
+        void initDocumentHolder(DocumentHolder holder);
+        void onBindDocumentHolder(DocumentHolder holder, Cursor cursor);
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
index ef6d2c9..a295ab2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
@@ -58,7 +58,8 @@
     }
 
 
-    public abstract void updateActionMenu(Menu menu, int dirType, boolean canDelete);
+    public abstract void updateActionMenu(Menu menu, int dirType, 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
@@ -129,7 +130,8 @@
         }
 
         @Override
-        public void updateActionMenu(Menu menu, int dirType, boolean canDelete) {
+        public void updateActionMenu(Menu menu, int dirType, boolean canDelete,
+                boolean canRename) {
 
             boolean copyEnabled = dirType != DirectoryFragment.TYPE_RECENT_OPEN;
             boolean moveEnabled =
@@ -141,6 +143,7 @@
             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(true);
             share.setVisible(false);
@@ -149,6 +152,7 @@
             copyTo.setEnabled(copyEnabled);
             moveTo.setVisible(moveEnabled);
             moveTo.setEnabled(moveEnabled);
+            rename.setVisible(false);
         }
     }
 
@@ -162,7 +166,8 @@
         }
 
         @Override
-        public void updateActionMenu(Menu menu, int dirType, boolean canDelete) {
+        public void updateActionMenu(Menu menu, int dirType, boolean canDelete,
+                boolean canRename) {
             checkArgument(dirType != DirectoryFragment.TYPE_RECENT_OPEN);
 
             boolean moveEnabled =
@@ -174,6 +179,7 @@
             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);
@@ -181,6 +187,7 @@
             copyTo.setEnabled(true);
             moveTo.setVisible(moveEnabled);
             moveTo.setEnabled(moveEnabled);
+            rename.setVisible(false);
         }
     }
 
@@ -194,12 +201,17 @@
         }
 
         @Override
-        public void updateActionMenu(Menu menu, int dirType, boolean canDelete) {
+        public void updateActionMenu(Menu menu, int dirType, 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);
 
+            MenuItem rename = menu.findItem(R.id.menu_rename);
+            rename.setVisible(true);
+            rename.setEnabled(canRename);
+
             menu.findItem(R.id.menu_share).setVisible(true);
             menu.findItem(R.id.menu_delete).setVisible(canDelete);
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java
new file mode 100644
index 0000000..e672327
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package 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;
+import android.provider.DocumentsContract.Document;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.documentsui.R;
+import com.android.documentsui.State;
+
+final class GridDirectoryHolder extends DocumentHolder {
+    final TextView mTitle;
+    private ImageView mIconCheck;
+    private ImageView mIconMime;
+
+    public GridDirectoryHolder(Context context, ViewGroup parent) {
+        super(context, parent, R.layout.item_dir_grid);
+
+        mTitle = (TextView) itemView.findViewById(android.R.id.title);
+        mIconMime = (ImageView) itemView.findViewById(R.id.icon_mime_sm);
+        mIconCheck = (ImageView) itemView.findViewById(R.id.icon_check);
+    }
+
+    @Override
+    public void setSelected(boolean selected) {
+        super.setSelected(selected);
+        float checkAlpha = selected ? 1f : 0f;
+
+        mIconCheck.animate().alpha(checkAlpha).start();
+        mIconMime.animate().alpha(1f - checkAlpha).start();
+    }
+
+    /**
+     * Bind this view to the given document for display.
+     * @param cursor Pointing to the item to be bound.
+     * @param modelId The model ID of the item.
+     * @param state Current display state.
+     */
+    public void bind(Cursor cursor, String modelId, State state) {
+        checkNotNull(cursor, "Cursor cannot be null.");
+
+        this.modelId = modelId;
+
+        final String docDisplayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
+        mTitle.setText(docDisplayName);
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
new file mode 100644
index 0000000..c4ac0f5
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.dirlist;
+
+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;
+import android.net.Uri;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.text.format.Formatter;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.documentsui.IconUtils;
+import com.android.documentsui.R;
+import com.android.documentsui.RootCursorWrapper;
+import com.android.documentsui.Shared;
+import com.android.documentsui.State;
+
+final class GridDocumentHolder extends DocumentHolder {
+    private static boolean mHideTitles;
+
+    final TextView mTitle;
+    final TextView mDate;
+    final TextView mSize;
+    final ImageView mIconMimeLg;
+    final ImageView mIconMimeSm;
+    final ImageView mIconThumb;
+    final ImageView mIconCheck;
+    final IconHelper mIconHelper;
+
+    public GridDocumentHolder(Context context, ViewGroup parent, IconHelper iconHelper) {
+        super(context, parent, R.layout.item_doc_grid);
+
+        mTitle = (TextView) itemView.findViewById(android.R.id.title);
+        mDate = (TextView) itemView.findViewById(R.id.date);
+        mSize = (TextView) itemView.findViewById(R.id.size);
+        mIconMimeLg = (ImageView) itemView.findViewById(R.id.icon_mime_lg);
+        mIconMimeSm = (ImageView) itemView.findViewById(R.id.icon_mime_sm);
+        mIconThumb = (ImageView) itemView.findViewById(R.id.icon_thumb);
+        mIconCheck = (ImageView) itemView.findViewById(R.id.icon_check);
+
+        mIconHelper = iconHelper;
+    }
+
+    @Override
+    public void setSelected(boolean selected) {
+        super.setSelected(selected);
+        float checkAlpha = selected ? 1f : 0f;
+
+        mIconCheck.animate().alpha(checkAlpha).start();
+        mIconMimeSm.animate().alpha(1f - checkAlpha).start();
+    }
+
+    /**
+     * Bind this view to the given document for display.
+     * @param cursor Pointing to the item to be bound.
+     * @param modelId The model ID of the item.
+     * @param state Current display state.
+     */
+    public void bind(Cursor cursor, String modelId, State state) {
+        this.modelId = modelId;
+
+        checkNotNull(cursor, "Cursor cannot be null.");
+
+        final String docAuthority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
+        final String docId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
+        final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+        final String docDisplayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
+        final long docLastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED);
+        final int docIcon = getCursorInt(cursor, Document.COLUMN_ICON);
+        final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
+        final long docSize = getCursorLong(cursor, Document.COLUMN_SIZE);
+
+        mIconHelper.stopLoading(mIconThumb);
+
+        mIconMimeLg.animate().cancel();
+        mIconMimeLg.setAlpha(1f);
+        mIconThumb.animate().cancel();
+        mIconThumb.setAlpha(0f);
+
+        mIconMimeSm.setImageDrawable(IconUtils.loadMimeIcon(mContext, docMimeType));
+
+        final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId);
+        mIconHelper.loadThumbnail(uri, docMimeType, docFlags, docIcon, mIconThumb, mIconMimeLg);
+
+        if (mHideTitles) {
+            mTitle.setVisibility(View.GONE);
+        } else {
+            mTitle.setText(docDisplayName);
+            mTitle.setVisibility(View.VISIBLE);
+        }
+
+        if (docLastModified == -1) {
+            mDate.setText(null);
+        } else {
+            mDate.setText(Shared.formatTime(mContext, docLastModified));
+        }
+
+        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));
+        }
+    }
+
+    /**
+     * 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/IconHelper.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java
new file mode 100644
index 0000000..c97c446
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.State.MODE_GRID;
+import static com.android.documentsui.State.MODE_LIST;
+import static com.android.documentsui.State.MODE_UNKNOWN;
+
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.CancellationSignal;
+import android.os.OperationCanceledException;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.util.Log;
+import android.widget.ImageView;
+
+import com.android.documentsui.DocumentsApplication;
+import com.android.documentsui.IconUtils;
+import com.android.documentsui.MimePredicate;
+import com.android.documentsui.ProviderExecutor;
+import com.android.documentsui.ProviderExecutor.Preemptable;
+import com.android.documentsui.R;
+import com.android.documentsui.State;
+import com.android.documentsui.State.ViewMode;
+import com.android.documentsui.ThumbnailCache;
+
+/**
+ * A class to assist with loading and managing the Images (i.e. thumbnails and icons) associated
+ * with items in the directory listing.
+ */
+public class IconHelper {
+    private static String TAG = "IconHelper";
+
+    private Context mContext;
+    private ThumbnailCache mCache;
+    private Point mThumbSize;
+    // The display mode (MODE_GRID, MODE_LIST, etc).
+    private int mMode;
+    private boolean mThumbnailsEnabled = true;
+
+    /**
+     * @param context
+     * @param mode MODE_GRID or MODE_LIST
+     */
+    public IconHelper(Context context, int mode) {
+        mContext = context;
+        setViewMode(mode);
+        mCache = DocumentsApplication.getThumbnailsCache(context, mThumbSize);
+    }
+
+    /**
+     * Enables or disables thumbnails. When thumbnails are disabled, mime icons (or custom icons, if
+     * specified by the document) are used instead.
+     *
+     * @param enabled
+     */
+    public void setThumbnailsEnabled(boolean enabled) {
+        mThumbnailsEnabled = enabled;
+    }
+
+    /**
+     * Sets the current display mode.  This affects the thumbnail sizes that are loaded.
+     * @param mode See {@link State.MODE_LIST} and {@link State.MODE_GRID}.
+     */
+    public void setViewMode(@ViewMode int mode) {
+        // TODO: Instead of exposing setMode, make the mode final, and make separate instances for
+        // grid/list.
+        int thumbSize;
+        switch (mode) {
+            case MODE_GRID:
+                thumbSize = mContext.getResources().getDimensionPixelSize(R.dimen.grid_width);
+                break;
+            case MODE_LIST:
+                thumbSize = mContext.getResources().getDimensionPixelSize(
+                        R.dimen.list_item_thumbnail_size);
+                break;
+            default:
+                throw new IllegalArgumentException("Unsupported layout mode: " + mode);
+        }
+        mMode = mode;
+        mThumbSize = new Point(thumbSize, thumbSize);
+    }
+
+    /**
+     * Cancels any ongoing load operations associated with the given ImageView.
+     * @param icon
+     */
+    public void stopLoading(ImageView icon) {
+        final LoaderTask oldTask = (LoaderTask) icon.getTag();
+        if (oldTask != null) {
+            oldTask.preempt();
+            icon.setTag(null);
+        }
+    }
+
+    /** Internal task for loading thumbnails asynchronously. */
+    private static class LoaderTask
+            extends AsyncTask<Uri, Void, Bitmap>
+            implements Preemptable {
+        private final Uri mUri;
+        private final ImageView mIconMime;
+        private final ImageView mIconThumb;
+        private final Point mThumbSize;
+        private final CancellationSignal mSignal;
+
+        public LoaderTask(Uri uri, ImageView iconMime, ImageView iconThumb,
+                Point thumbSize) {
+            mUri = uri;
+            mIconMime = iconMime;
+            mIconThumb = iconThumb;
+            mThumbSize = thumbSize;
+            mSignal = new CancellationSignal();
+            if (DEBUG) Log.d(TAG, "Starting icon loader task for " + mUri);
+        }
+
+        @Override
+        public void preempt() {
+            if (DEBUG) Log.d(TAG, "Icon loader task for " + mUri + " was cancelled.");
+            cancel(false);
+            mSignal.cancel();
+        }
+
+        @Override
+        protected Bitmap doInBackground(Uri... params) {
+            if (isCancelled())
+                return null;
+
+            final Context context = mIconThumb.getContext();
+            final ContentResolver resolver = context.getContentResolver();
+
+            ContentProviderClient client = null;
+            Bitmap result = null;
+            try {
+                client = DocumentsApplication.acquireUnstableProviderOrThrow(
+                        resolver, mUri.getAuthority());
+                result = DocumentsContract.getDocumentThumbnail(client, mUri, mThumbSize, mSignal);
+                if (result != null) {
+                    final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
+                            context, mThumbSize);
+                    thumbs.put(mUri, result);
+                }
+            } catch (Exception e) {
+                if (!(e instanceof OperationCanceledException)) {
+                    Log.w(TAG, "Failed to load thumbnail for " + mUri + ": " + e);
+                }
+            } finally {
+                ContentProviderClient.releaseQuietly(client);
+            }
+            return result;
+        }
+
+        @Override
+        protected void onPostExecute(Bitmap result) {
+            if (DEBUG) Log.d(TAG, "Loader task for " + mUri + " completed");
+
+            if (mIconThumb.getTag() == this && result != null) {
+                mIconThumb.setTag(null);
+                mIconThumb.setImageBitmap(result);
+
+                float alpha = mIconMime.getAlpha();
+                mIconMime.animate().alpha(0f).start();
+                mIconThumb.setAlpha(0f);
+                mIconThumb.animate().alpha(alpha).start();
+            }
+        }
+    }
+
+    /**
+     * Load thumbnails for a directory list item.
+     * @param uri The URI for the file being represented.
+     * @param mimeType The mime type of the file being represented.
+     * @param docFlags Flags for the file being represented.
+     * @param docIcon Custom icon (if any) for the file being requested.
+     * @param iconThumb The itemview's thumbnail icon.
+     * @param iconMime The itemview's mime icon.
+     * @return
+     */
+    public void loadThumbnail(Uri uri, String mimeType, int docFlags, int docIcon,
+            ImageView iconThumb, ImageView iconMime) {
+        boolean cacheHit = false;
+
+        final String docAuthority = uri.getAuthority();
+
+        final boolean supportsThumbnail = (docFlags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
+        final boolean allowThumbnail = (mMode == MODE_GRID)
+                || MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, mimeType);
+        final boolean showThumbnail = supportsThumbnail && allowThumbnail && mThumbnailsEnabled;
+        if (showThumbnail) {
+            final Bitmap cachedResult = mCache.get(uri);
+            if (cachedResult != null) {
+                iconThumb.setImageBitmap(cachedResult);
+                cacheHit = true;
+            } else {
+                iconThumb.setImageDrawable(null);
+                final LoaderTask task = new LoaderTask(uri, iconMime, iconThumb, mThumbSize);
+                iconThumb.setTag(task);
+                ProviderExecutor.forAuthority(docAuthority).execute(task);
+            }
+        }
+
+        if (cacheHit) {
+            iconMime.setImageDrawable(null);
+            iconMime.setAlpha(0f);
+            iconThumb.setAlpha(1f);
+        } else {
+            // Add a mime icon if the thumbnail is being loaded in the background.
+            iconThumb.setImageDrawable(null);
+            iconMime.setImageDrawable(getDocumentIcon(
+                    mContext, docAuthority, DocumentsContract.getDocumentId(uri), mimeType, docIcon));
+            iconMime.setAlpha(1f);
+            iconThumb.setAlpha(0f);
+        }
+    }
+
+    /**
+     * Gets a mime icon or package icon for a file.
+     * @param context
+     * @param authority The authority string of the file.
+     * @param id The document ID of the file.
+     * @param mimeType The mime type of the file.
+     * @param icon The custom icon (if any) of the file.
+     * @return
+     */
+    public Drawable getDocumentIcon(Context context, String authority, String id,
+            String mimeType, int icon) {
+        if (icon != 0) {
+            return IconUtils.loadPackageIcon(context, authority, icon);
+        } else {
+            return IconUtils.loadMimeIcon(context, mimeType, authority, id, mMode);
+        }
+    }
+
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
new file mode 100644
index 0000000..00ea27b
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.dirlist;
+
+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;
+import android.net.Uri;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.text.format.Formatter;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.documentsui.R;
+import com.android.documentsui.RootCursorWrapper;
+import com.android.documentsui.Shared;
+import com.android.documentsui.State;
+
+final class ListDocumentHolder extends DocumentHolder {
+    final TextView mTitle;
+    final TextView mSummary;
+    final TextView mDate;
+    final TextView mSize;
+    final ImageView mIconMime;
+    final ImageView mIconThumb;
+    final ImageView mIconCheck;
+    final IconHelper mIconHelper;
+
+    public ListDocumentHolder(Context context, ViewGroup parent, IconHelper iconHelper) {
+        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);
+        mIconMime = (ImageView) itemView.findViewById(R.id.icon_mime);
+        mIconThumb = (ImageView) itemView.findViewById(R.id.icon_thumb);
+        mIconCheck = (ImageView) itemView.findViewById(R.id.icon_check);
+
+        mIconHelper = iconHelper;
+    }
+
+    @Override
+    public void setSelected(boolean selected) {
+        super.setSelected(selected);
+        float checkAlpha = selected ? 1f : 0f;
+
+        mIconCheck.animate().alpha(checkAlpha).start();
+        mIconMime.animate().alpha(1f - checkAlpha).start();
+        mIconThumb.animate().alpha(1f - checkAlpha).start();
+    }
+
+    /**
+     * Bind this view to the given document for display.
+     * @param cursor Pointing to the item to be bound.
+     * @param modelId The model ID of the item.
+     * @param state Current display state.
+     */
+    @Override
+    public void bind(Cursor cursor, String modelId, State state) {
+        this.modelId = modelId;
+
+        checkNotNull(cursor, "Cursor cannot be null.");
+
+        final String docAuthority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
+        final String docId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
+        final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+        final String docDisplayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
+        final long docLastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED);
+        final int docIcon = getCursorInt(cursor, Document.COLUMN_ICON);
+        final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
+        final String docSummary = getCursorString(cursor, Document.COLUMN_SUMMARY);
+        final long docSize = getCursorLong(cursor, Document.COLUMN_SIZE);
+
+        mIconHelper.stopLoading(mIconThumb);
+
+        mIconMime.animate().cancel();
+        mIconMime.setAlpha(1f);
+        mIconThumb.animate().cancel();
+        mIconThumb.setAlpha(0f);
+
+        final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId);
+        mIconHelper.loadThumbnail(uri, docMimeType, docFlags, docIcon, mIconThumb, mIconMime);
+
+        mTitle.setText(docDisplayName);
+        mTitle.setVisibility(View.VISIBLE);
+
+        if (docSummary != null) {
+            mSummary.setText(docSummary);
+            mSummary.setVisibility(View.VISIBLE);
+        } else {
+            mSummary.setVisibility(View.INVISIBLE);
+        }
+
+        if (docLastModified == -1) {
+            mDate.setText(null);
+        } else {
+            mDate.setText(Shared.formatTime(mContext, docLastModified));
+        }
+
+        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
new file mode 100644
index 0000000..075b3ea
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static com.android.documentsui.Shared.DEBUG;
+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.os.Bundle;
+import android.os.Looper;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
+import android.util.Log;
+
+import com.android.documentsui.BaseActivity.SiblingProvider;
+import com.android.documentsui.DirectoryResult;
+import com.android.documentsui.RootCursorWrapper;
+import com.android.documentsui.dirlist.MultiSelectManager.Selection;
+import com.android.documentsui.model.DocumentInfo;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The data model for the current loaded directory.
+ */
+@VisibleForTesting
+public class Model implements SiblingProvider {
+    private static final String TAG = "Model";
+
+    private boolean mIsLoading;
+    private List<UpdateListener> mUpdateListeners = new ArrayList<>();
+    @Nullable private Cursor mCursor;
+    private int mCursorCount;
+    /** Maps Model ID to cursor positions, for looking up items by Model ID. */
+    private Map<String, Integer> mPositions = new HashMap<>();
+    /**
+     * 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 int mSortOrder = SORT_ORDER_DISPLAY_NAME;
+
+    @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;
+    }
+
+    private void notifyUpdateListeners() {
+        for (UpdateListener listener: mUpdateListeners) {
+            listener.onModelUpdate(this);
+        }
+    }
+
+    private void notifyUpdateListeners(Exception e) {
+        for (UpdateListener listener: mUpdateListeners) {
+            listener.onModelUpdateFailed(e);
+        }
+    }
+
+    void update(DirectoryResult result) {
+        if (DEBUG) Log.i(TAG, "Updating model with new result set.");
+
+        if (result == null) {
+            mCursor = null;
+            mCursorCount = 0;
+            mIds.clear();
+            mPositions.clear();
+            info = null;
+            error = null;
+            mIsLoading = false;
+            notifyUpdateListeners();
+            return;
+        }
+
+        if (result.exception != null) {
+            Log.e(TAG, "Error while loading directory contents", result.exception);
+            notifyUpdateListeners(result.exception);
+            return;
+        }
+
+        mCursor = result.cursor;
+        mCursorCount = mCursor.getCount();
+        mSortOrder = result.sortOrder;
+
+        updateModelData();
+
+        final Bundle extras = mCursor.getExtras();
+        if (extras != null) {
+            info = extras.getString(DocumentsContract.EXTRA_INFO);
+            error = extras.getString(DocumentsContract.EXTRA_ERROR);
+            mIsLoading = extras.getBoolean(DocumentsContract.EXTRA_LOADING, false);
+        }
+
+        notifyUpdateListeners();
+    }
+
+    @VisibleForTesting
+    int getItemCount() {
+        return mCursorCount;
+    }
+
+    /**
+     * Scan over the incoming cursor data, generate Model IDs for each row, and sort the IDs
+     * according to the current sort order.
+     */
+    private void updateModelData() {
+        int[] positions = new int[mCursorCount];
+        mIds.clear();
+        String[] stringValues = new String[mCursorCount];
+        long[] longValues = null;
+
+        if (mSortOrder == SORT_ORDER_LAST_MODIFIED || mSortOrder == SORT_ORDER_SIZE) {
+            longValues = new long[mCursorCount];
+        }
+
+        mCursor.moveToPosition(-1);
+        for (int pos = 0; pos < mCursorCount; ++pos) {
+            mCursor.moveToNext();
+            positions[pos] = pos;
+            mIds.add(createModelId(mCursor));
+
+            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] = DocumentInfo.DIR_PREFIX + displayName;
+                    } else {
+                        stringValues[pos] = displayName;
+                    }
+                    break;
+                case SORT_ORDER_LAST_MODIFIED:
+                    longValues[pos] = getLastModified(mCursor);
+                    stringValues[pos] = getCursorString(mCursor, Document.COLUMN_MIME_TYPE);
+                    break;
+                case SORT_ORDER_SIZE:
+                    longValues[pos] = getCursorLong(mCursor, Document.COLUMN_SIZE);
+                    stringValues[pos] = getCursorString(mCursor, Document.COLUMN_MIME_TYPE);
+                    break;
+            }
+        }
+
+        switch (mSortOrder) {
+            case SORT_ORDER_DISPLAY_NAME:
+                binarySort(stringValues, positions, mIds);
+                break;
+            case SORT_ORDER_LAST_MODIFIED:
+            case SORT_ORDER_SIZE:
+                binarySort(longValues, stringValues, positions, mIds);
+                break;
+        }
+
+        // Populate the positions.
+        mPositions.clear();
+        for (int i = 0; i < mCursorCount; ++i) {
+            mPositions.put(mIds.get(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().
+     *
+     * @param sortKey Data is sorted in ascending alphabetical order.
+     * @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) {
+        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);
+
+            int left = 0;
+            int right = start;
+
+            while (left < right) {
+                int mid = (left + right) >>> 1;
+
+                final String lhs = pivotValue;
+                final String rhs = sortKey[mid];
+                final int compare = DocumentInfo.compareToIgnoreCaseNullable(lhs, rhs);
+
+                if (compare < 0) {
+                    right = mid;
+                } else {
+                    left = mid + 1;
+                }
+            }
+
+            int n = start - left;
+            switch (n) {
+                case 2:
+                    positions[left + 2] = positions[left + 1];
+                    sortKey[left + 2] = sortKey[left + 1];
+                    ids.set(left + 2, ids.get(left + 1));
+                case 1:
+                    positions[left + 1] = positions[left];
+                    sortKey[left + 1] = sortKey[left];
+                    ids.set(left + 1, ids.get(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));
+                    }
+            }
+
+            positions[left] = pivotPosition;
+            sortKey[left] = pivotValue;
+            ids.set(left, pivotId);
+        }
+    }
+
+    /**
+     * Sorts model data. Takes four columns of index-corresponded data. The first column is the sort
+     * key, and the second is an array of mime types. The rows are first bucketed by mime type
+     * (directories vs documents) and then each bucket is sorted independently in descending
+     * 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 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) {
+        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);
+
+            int left = 0;
+            int right = start;
+
+            while (left < right) {
+                int mid = ((left + right) >>> 1);
+
+                // First bucket by mime type.  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) {
+                    compare = -1;
+                } else if (!lhsIsDir && rhsIsDir) {
+                    compare = 1;
+                } else {
+                    final long lhs = pivotValue;
+                    final long rhs = sortKey[mid];
+                    // Sort in descending numerical order. This matches legacy behaviour, which
+                    // yields largest or most recent items on top.
+                    compare = -Long.compare(lhs, rhs);
+                }
+
+                // If numerical comparison yields a tie, use document ID as a tie breaker.  This
+                // will yield stable results even if incoming items are continually shuffling and
+                // 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));
+                }
+
+                if (compare < 0) {
+                    right = mid;
+                } else {
+                    left = mid + 1;
+                }
+            }
+
+            int n = start - left;
+            switch (n) {
+                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));
+                case 1:
+                    positions[left + 1] = positions[left];
+                    sortKey[left + 1] = sortKey[left];
+                    mimeTypes[left + 1] = mimeTypes[left];
+                    ids.set(left + 1, ids.get(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));
+                    }
+            }
+
+            positions[left] = pivotPosition;
+            sortKey[left] = pivotValue;
+            mimeTypes[left] = pivotMime;
+            ids.set(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.
+     */
+    long getLastModified(Cursor cursor) {
+        long l = getCursorLong(mCursor, Document.COLUMN_LAST_MODIFIED);
+        return (l == -1) ? Long.MAX_VALUE : l;
+    }
+
+    @Nullable Cursor getItem(String modelId) {
+        Integer pos = mPositions.get(modelId);
+        if (pos != null) {
+            mCursor.moveToPosition(pos);
+            return mCursor;
+        }
+        return null;
+    }
+
+    boolean isEmpty() {
+        return mCursorCount == 0;
+    }
+
+    boolean isLoading() {
+        return mIsLoading;
+    }
+
+    List<DocumentInfo> getDocuments(Selection items) {
+        final int size = (items != null) ? items.size() : 0;
+
+        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);
+        }
+        return docs;
+    }
+
+    @Override
+    public Cursor getCursor() {
+        if (Looper.myLooper() != Looper.getMainLooper()) {
+            throw new IllegalStateException("Can't call getCursor from non-main thread.");
+        }
+        return mCursor;
+    }
+
+    void addUpdateListener(UpdateListener listener) {
+        mUpdateListeners.add(listener);
+    }
+
+    static interface UpdateListener {
+        /**
+         * Called when a successful update has occurred.
+         */
+        void onModelUpdate(Model model);
+
+        /**
+         * Called when an update has been attempted but failed.
+         */
+        void onModelUpdateFailed(Exception e);
+    }
+
+    /**
+     * @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() {
+        return mIds;
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
new file mode 100644
index 0000000..880da9c
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.State.MODE_GRID;
+import static com.android.documentsui.State.MODE_LIST;
+import static com.android.documentsui.model.DocumentInfo.getCursorInt;
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+
+import android.database.Cursor;
+import android.provider.DocumentsContract.Document;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.ViewGroup;
+
+import com.android.documentsui.State;
+
+import com.google.common.collect.Sets;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Adapts from dirlist.Model to something RecyclerView understands.
+ */
+final class ModelBackedDocumentsAdapter extends DocumentsAdapter {
+
+    private static final String TAG = "ModelBackedDocumentsAdapter";
+    public static final int ITEM_TYPE_DOCUMENT = 1;
+    public static final int ITEM_TYPE_DIRECTORY = 2;
+
+    // Provides access to information needed when creating and view holders. This
+    // isn't an ideal pattern (more transitive dependency stuff) but good enough for now.
+    private final Environment mEnv;
+    private final IconHelper mIconHelper;  // a transitive dependency of the holders.
+
+    /**
+     * An ordered list of model IDs. This is the data structure that determines what shows up in
+     * the UI, and where.
+     */
+    private List<String> mModelIds = new ArrayList<>();
+
+    // List of files that have been deleted. Some transient directory updates
+    // may happen while files are being deleted. During this time we don't
+    // want once-hidden files to be re-shown. We only remove
+    // items from this list when we get a model update where the model
+    // does not contain a corresponding id. This ensures hidden entries
+    // don't momentarily re-appear if we get intermediate updates from
+    // the file system.
+    private Set<String> mHiddenIds = new HashSet<>();
+
+    public ModelBackedDocumentsAdapter(Environment env, IconHelper iconHelper) {
+        mEnv = env;
+        mIconHelper = iconHelper;
+    }
+
+    @Override
+    public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        DocumentHolder holder = null;
+        final State state = mEnv.getDisplayState();
+        switch (state.derivedMode) {
+            case MODE_GRID:
+                switch (viewType) {
+                    case ITEM_TYPE_DIRECTORY:
+                        holder = new GridDirectoryHolder(mEnv.getContext(), parent);
+                        break;
+                    case ITEM_TYPE_DOCUMENT:
+                        holder = new GridDocumentHolder(mEnv.getContext(), parent, mIconHelper);
+                        break;
+                    default:
+                        throw new IllegalStateException("Unsupported layout type.");
+                }
+                break;
+            case MODE_LIST:
+                holder = new ListDocumentHolder(mEnv.getContext(), parent, mIconHelper);
+                break;
+            default:
+                throw new IllegalStateException("Unsupported layout mode.");
+        }
+
+        mEnv.initDocumentHolder(holder);
+        return holder;
+    }
+
+    @Override
+    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);
+        } else {
+            onBindViewHolder(holder, position);
+        }
+    }
+
+    @Override
+    public void onBindViewHolder(DocumentHolder holder, int position) {
+        String modelId = mModelIds.get(position);
+        Cursor cursor = mEnv.getModel().getItem(modelId);
+        holder.bind(cursor, modelId, mEnv.getDisplayState());
+
+        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));
+
+        mEnv.onBindDocumentHolder(holder, cursor);
+    }
+
+    @Override
+    public int getItemCount() {
+        return mModelIds.size();
+    }
+
+    @Override
+    public void onModelUpdate(Model model) {
+        if (DEBUG && mHiddenIds.size() > 0) {
+            Log.d(TAG, "Updating model with hidden ids: " + mHiddenIds);
+        }
+
+        List<String> modelIds = model.getModelIds();
+        mModelIds = new ArrayList<>(modelIds.size());
+        for (String id : modelIds) {
+            if (!mHiddenIds.contains(id)) {
+                mModelIds.add(id);
+            } else {
+                if (DEBUG) Log.d(TAG, "Omitting hidden id from model during update: " + id);
+            }
+        }
+
+        // Finally remove any hidden ids that aren't present in the model.
+        // This assumes that model updates represent a complete set of files.
+        mHiddenIds.retainAll(mModelIds);
+    }
+
+    @Override
+    public void onModelUpdateFailed(Exception e) {
+        Log.w(TAG, "Model update failed.", e);
+        mModelIds.clear();
+    }
+
+    @Override
+    public String getModelId(int adapterPosition) {
+        return mModelIds.get(adapterPosition);
+    }
+
+    @Override
+    public SparseArray<String> hide(String... ids) {
+        if (DEBUG) Log.d(TAG, "Hiding ids: " + ids);
+        Set<String> toHide = Sets.newHashSet(ids);
+
+        // Proceed backwards through the list of items, because each removal causes the
+        // positions of all subsequent items to change.
+        SparseArray<String> hiddenItems = new SparseArray<>();
+        for (int i = mModelIds.size() - 1; i >= 0; --i) {
+            String id = mModelIds.get(i);
+            if (toHide.contains(id)) {
+                mHiddenIds.add(id);
+                hiddenItems.put(i, mModelIds.remove(i));
+                notifyItemRemoved(i);
+            }
+        }
+
+        return hiddenItems;
+    }
+
+    @Override
+    public void unhide(SparseArray<String> ids) {
+        if (DEBUG) Log.d(TAG, "Un-iding 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;
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        return isDirectory(mEnv.getModel(), position)
+                ? ITEM_TYPE_DIRECTORY
+                : ITEM_TYPE_DOCUMENT;
+    }
+
+    @Override
+    public void onItemSelectionChanged(String id) {
+        int position = mModelIds.indexOf(id);
+
+        if (position >= 0) {
+            notifyItemChanged(position, SELECTION_CHANGED_MARKER);
+        } else {
+            Log.w(TAG, "Item change notification received for unknown item: " + id);
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
index 65e1a28..71e87cb 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
@@ -17,6 +17,8 @@
 package com.android.documentsui.dirlist;
 
 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;
@@ -28,15 +30,10 @@
 import android.support.annotation.VisibleForTesting;
 import android.support.v7.widget.GridLayoutManager;
 import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.Adapter;
-import android.support.v7.widget.RecyclerView.AdapterDataObserver;
-import android.support.v7.widget.RecyclerView.LayoutManager;
-import android.support.v7.widget.RecyclerView.OnScrollListener;
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
-import android.view.GestureDetector;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
@@ -46,8 +43,14 @@
 import com.android.documentsui.R;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * MultiSelectManager provides support traditional multi-item selection support to RecyclerView.
@@ -66,56 +69,32 @@
 
     private final Selection mSelection = new Selection();
 
-    // Only created when selection is cleared.
-    private Selection mIntermediateSelection;
-
-    private Range mRanger;
-    private SelectionEnvironment mEnvironment;
-
+    private final SelectionEnvironment mEnvironment;
+    private final DocumentsAdapter mAdapter;
     private final List<MultiSelectManager.Callback> mCallbacks = new ArrayList<>(1);
 
-    private Adapter<?> mAdapter;
+    private Range mRanger;
     private boolean mSingleSelect;
 
-    // Payloads for notifyItemChange to distinguish between selection and other events.
-    public static final String SELECTION_CHANGED_MARKER = "Selection-Changed";
-
     @Nullable private BandController mBandManager;
 
+
     /**
      * @param recyclerView
      * @param mode Selection mode
      */
-    public MultiSelectManager(final RecyclerView recyclerView, int mode) {
-        this(recyclerView.getAdapter(), new RuntimeSelectionEnvironment(recyclerView), mode);
+    public MultiSelectManager(
+            final RecyclerView recyclerView, DocumentsAdapter adapter, int mode) {
+        this(new RuntimeSelectionEnvironment(recyclerView), adapter, mode);
 
         if (mode == MODE_MULTIPLE) {
             mBandManager = new BandController();
         }
 
-        GestureDetector.SimpleOnGestureListener listener =
-                new GestureDetector.SimpleOnGestureListener() {
-                    @Override
-                    public boolean onSingleTapUp(MotionEvent e) {
-                        return MultiSelectManager.this.onSingleTapUp(
-                                new MotionInputEvent(e, recyclerView));
-                    }
-                    @Override
-                    public void onLongPress(MotionEvent e) {
-                        MultiSelectManager.this.onLongPress(
-                                new MotionInputEvent(e, recyclerView));
-                    }
-                };
-
-        final GestureDetector detector = new GestureDetector(recyclerView.getContext(), listener);
-        detector.setOnDoubleTapListener(listener);
-
         recyclerView.addOnItemTouchListener(
                 new RecyclerView.OnItemTouchListener() {
                     @Override
                     public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
-                        detector.onTouchEvent(e);
-
                         if (mBandManager != null) {
                             return mBandManager.handleEvent(new MotionInputEvent(e, recyclerView));
                         }
@@ -138,33 +117,42 @@
      * @hide
      */
     @VisibleForTesting
-    MultiSelectManager(Adapter<?> adapter, SelectionEnvironment environment, int mode) {
-        mAdapter = checkNotNull(adapter, "'adapter' cannot be null.");
+    MultiSelectManager(SelectionEnvironment environment, DocumentsAdapter adapter, int mode) {
         mEnvironment = checkNotNull(environment, "'environment' cannot be null.");
+        mAdapter = checkNotNull(adapter, "'adapter' cannot be null.");
         mSingleSelect = mode == MODE_SINGLE;
 
         mAdapter.registerAdapterDataObserver(
-                new AdapterDataObserver() {
+                new RecyclerView.AdapterDataObserver() {
+
+                    private List<String> mModelIds;
 
                     @Override
                     public void onChanged() {
+                        // TODO: This is causing b/22765812
                         mSelection.clear();
+                        mModelIds = mAdapter.getModelIds();
                     }
 
                     @Override
                     public void onItemRangeChanged(
-                            int positionStart, int itemCount, Object payload) {
+                            int startPosition, int itemCount, Object payload) {
                         // No change in position. Ignoring.
                     }
 
                     @Override
-                    public void onItemRangeInserted(int positionStart, int itemCount) {
-                        mSelection.expand(positionStart, itemCount);
+                    public void onItemRangeInserted(int startPosition, int itemCount) {
+                        mSelection.cancelProvisionalSelection();
                     }
 
                     @Override
-                    public void onItemRangeRemoved(int positionStart, int itemCount) {
-                        mSelection.collapse(positionStart, itemCount);
+                    public void onItemRangeRemoved(int startPosition, int itemCount) {
+                        checkState(startPosition >= 0);
+                        checkState(itemCount > 0);
+
+                        mSelection.cancelProvisionalSelection();
+                        // Remove any disappeared IDs from the selection.
+                        mSelection.intersect(mModelIds);
                     }
 
                     @Override
@@ -214,36 +202,22 @@
     }
 
     /**
-     * Causes item at {@code position} in adapter to be selected.
-     *
-     * @param position Adapter position
-     * @param selected
-     * @return True if the selection state of the item changed.
-     */
-    @VisibleForTesting
-    public boolean setItemSelected(int position, boolean selected) {
-        if (mSingleSelect && hasSelection()) {
-            clearSelectionQuietly();
-        }
-        return setItemsSelected(position, 1, selected);
-    }
-
-    /**
      * Sets the selected state of the specified items. Note that the callback will NOT
      * be consulted to see if an item can be selected.
      *
-     * @return True if the selection state of any of the items changed.
+     * @param ids
+     * @param selected
+     * @return
      */
-    public boolean setItemsSelected(int position, int length, boolean selected) {
+    public boolean setItemsSelected(Iterable<String> ids, boolean selected) {
         boolean changed = false;
-        for (int i = position; i < position + length; i++) {
-            boolean itemChanged = selected ? mSelection.add(i) : mSelection.remove(i);
+        for (String id: ids) {
+            boolean itemChanged = selected ? mSelection.add(id) : mSelection.remove(id);
             if (itemChanged) {
-                notifyItemStateChanged(i, selected);
+                notifyItemStateChanged(id, selected);
             }
             changed |= itemChanged;
         }
-
         notifySelectionChanged();
         return changed;
     }
@@ -271,15 +245,12 @@
         if (!hasSelection()) {
             return;
         }
-        if (mIntermediateSelection == null) {
-            mIntermediateSelection = new Selection();
-        }
-        getSelection(mIntermediateSelection);
+
+        Selection intermediateSelection = getSelection(new Selection());
         mSelection.clear();
 
-        for (int i = 0; i < mIntermediateSelection.size(); i++) {
-            int position = mIntermediateSelection.get(i);
-            notifyItemStateChanged(position, false);
+        for (String id: intermediateSelection.getAll()) {
+            notifyItemStateChanged(id, false);
         }
     }
 
@@ -298,11 +269,7 @@
     boolean onSingleTapUp(InputEvent input) {
         if (DEBUG) Log.d(TAG, "Processing tap event.");
         if (!hasSelection()) {
-            // if this is a mouse click on an item, start selection mode.
-            // TODO:  && input.isPrimaryButtonPressed(), but it is returning false.
-            if (input.isOverItem() && input.isMouseEvent()) {
-                toggleSelection(input.getItemPosition());
-            }
+            // No selection active - do nothing.
             return false;
         }
 
@@ -330,29 +297,42 @@
             // information about what has changed.
             notifySelectionChanged();
         } else {
-            toggleSelection(input.getItemPosition());
+            int position = input.getItemPosition();
+            toggleSelection(position);
+            setSelectionRangeBegin(position);
         }
     }
 
     /**
-     * Toggles the selection state at position. If an item does end up selected
-     * a new Ranger (range selection manager) at that point is created.
+     * A convenience method for toggling selection by adapter position.
      *
-     * @param position
+     * @param position Adapter position to toggle.
      */
-    public void toggleSelection(int position) {
+    private void toggleSelection(int position) {
         // Position may be special "no position" during certain
         // transitional phases. If so, skip handling of the event.
         if (position == RecyclerView.NO_POSITION) {
             if (DEBUG) Log.d(TAG, "Ignoring toggle for element with no position.");
             return;
         }
+        String id = mAdapter.getModelId(position);
+        if (id != null) {
+            toggleSelection(id);
+        }
+    }
 
+    /**
+     * Toggles selection on the item with the given model ID.
+     *
+     * @param modelId
+     */
+    public void toggleSelection(String modelId) {
+        checkNotNull(modelId);
         boolean changed = false;
-        if (mSelection.contains(position)) {
-            changed = attemptDeselect(position);
+        if (mSelection.contains(modelId)) {
+            changed = attemptDeselect(modelId);
         } else {
-            boolean canSelect = notifyBeforeItemStateChange(position, true);
+            boolean canSelect = notifyBeforeItemStateChange(modelId, true);
             if (!canSelect) {
                 return;
             }
@@ -365,8 +345,7 @@
             // an item to be selected.
             // By recreating Ranger at this point, we allow the user to create
             // multiple separate contiguous ranges with SHIFT+Click & Click.
-            selectAndNotify(position);
-            setSelectionFocusBegin(position);
+            selectAndNotify(modelId);
             changed = true;
         }
 
@@ -383,57 +362,68 @@
      * @throws IllegalStateException if {@code position} is not already be selected
      * @param position
      */
-    void setSelectionFocusBegin(int position) {
-        checkState(mSelection.contains(position));
-        mRanger = new Range(position);
+    void setSelectionRangeBegin(int position) {
+        if (position == RecyclerView.NO_POSITION) {
+            return;
+        }
+
+        if (mSelection.contains(mAdapter.getModelId(position))) {
+            mRanger = new Range(position);
+        }
     }
 
     /**
-     * Try to select all elements in range. Not that callbacks can cancel selection
-     * of specific items, so some or even all items may not reflect the desired
-     * state after the update is complete.
+     * Try to set selection state for all elements in range. Not that callbacks can cancel selection
+     * of specific items, so some or even all items may not reflect the desired state after the
+     * update is complete.
      *
-     * @param begin inclusive
-     * @param end inclusive
-     * @param selected
+     * @param begin Adapter position for range start (inclusive).
+     * @param end Adapter position for range end (inclusive).
+     * @param selected New selection state.
      */
     private void updateRange(int begin, int end, boolean selected) {
         checkState(end >= begin);
         for (int i = begin; i <= end; i++) {
+            String id = mAdapter.getModelId(i);
+            if (id == null) {
+                continue;
+            }
+
             if (selected) {
-                boolean canSelect = notifyBeforeItemStateChange(i, true);
+                boolean canSelect = notifyBeforeItemStateChange(id, true);
                 if (canSelect) {
                     if (mSingleSelect && hasSelection()) {
                         clearSelectionQuietly();
                     }
-                    selectAndNotify(i);
+                    selectAndNotify(id);
                 }
             } else {
-                attemptDeselect(i);
+                attemptDeselect(id);
             }
         }
     }
 
     /**
-     * @param position
+     * @param modelId
      * @return True if the update was applied.
      */
-    private boolean selectAndNotify(int position) {
-        boolean changed = mSelection.add(position);
+    private boolean selectAndNotify(String modelId) {
+        boolean changed = mSelection.add(modelId);
         if (changed) {
-            notifyItemStateChanged(position, true);
+            notifyItemStateChanged(modelId, true);
         }
         return changed;
     }
 
     /**
-     * @param position
+     * @param id
      * @return True if the update was applied.
      */
-    private boolean attemptDeselect(int position) {
-        if (notifyBeforeItemStateChange(position, false)) {
-            mSelection.remove(position);
-            notifyItemStateChanged(position, false);
+    private boolean attemptDeselect(String id) {
+        checkArgument(id != null);
+        if (notifyBeforeItemStateChange(id, false)) {
+            mSelection.remove(id);
+            notifyItemStateChanged(id, false);
             if (DEBUG) Log.d(TAG, "Selection after deselect: " + mSelection);
             return true;
         } else {
@@ -442,10 +432,10 @@
         }
     }
 
-    private boolean notifyBeforeItemStateChange(int position, boolean nextState) {
+    private boolean notifyBeforeItemStateChange(String id, boolean nextState) {
         int lastListener = mCallbacks.size() - 1;
         for (int i = lastListener; i > -1; i--) {
-            if (!mCallbacks.get(i).onBeforeItemStateChange(position, nextState)) {
+            if (!mCallbacks.get(i).onBeforeItemStateChange(id, nextState)) {
                 return false;
             }
         }
@@ -456,12 +446,13 @@
      * Notifies registered listeners when the selection status of a single item
      * (identified by {@code position}) changes.
      */
-    private void notifyItemStateChanged(int position, boolean selected) {
+    private void notifyItemStateChanged(String id, boolean selected) {
+        checkArgument(id != null);
         int lastListener = mCallbacks.size() - 1;
         for (int i = lastListener; i > -1; i--) {
-            mCallbacks.get(i).onItemStateChanged(position, selected);
+            mCallbacks.get(i).onItemStateChanged(id, selected);
         }
-        mAdapter.notifyItemChanged(position, SELECTION_CHANGED_MARKER);
+        mAdapter.onItemSelectionChanged(id);
     }
 
     /**
@@ -583,65 +574,40 @@
      */
     public static final class Selection {
 
-        // This class tracks selected positions by managing two arrays: the saved selection, and
-        // the total selection. Saved selections are those which have been completed by tapping an
-        // item or by completing a band select operation. Provisional selections are selections
-        // which have been temporarily created by an in-progress band select operation (once the
-        // user releases the mouse button during a band select operation, the selected items
-        // become saved). The total selection is the combination of both the saved selection and
-        // the provisional selection. Tracking both separately is necessary to ensure that saved
-        // selections do not become deselected when they are removed from the provisional selection;
-        // for example, if 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 SparseBooleanArray mSavedSelection;
-        private SparseBooleanArray mTotalSelection;
-
-        public Selection() {
-            mSavedSelection = new SparseBooleanArray();
-            mTotalSelection = new SparseBooleanArray();
-        }
+        // This class tracks selected items by managing two sets: the saved selection, and the total
+        // selection. Saved selections are those which have been completed by tapping an item or by
+        // completing a band select operation. Provisional selections are selections which have been
+        // temporarily created by an in-progress band select operation (once the user releases the
+        // mouse button during a band select operation, the selected items become saved). The total
+        // selection is the combination of both the saved selection and the provisional
+        // selection. Tracking both separately is necessary to ensure that saved selections do not
+        // become deselected when they are removed from the provisional selection; for example, if
+        // 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> mSavedSelection = new HashSet<>();
+        private Set<String> mTotalSelection = new HashSet<>();
 
         @VisibleForTesting
-        public Selection(int... positions) {
-            this();
-            for (int i = 0; i < positions.length; i++) {
-                add(positions[i]);
+        public Selection(String... ids) {
+            for (int i = 0; i < ids.length; i++) {
+                add(ids[i]);
             }
         }
 
         /**
-         * @param position
+         * @param id
          * @return true if the position is currently selected.
          */
-        public boolean contains(int position) {
-            return mTotalSelection.get(position);
-        }
-
-        /**
-         * Useful for iterating over selection. Please note that
-         * iteration should be done over a copy of the selection,
-         * not the live selection.
-         *
-         * @see #copyTo(MultiSelectManager.Selection)
-         *
-         * @param index
-         * @return the position value stored at specified index.
-         */
-        public int get(int index) {
-            return mTotalSelection.keyAt(index);
+        public boolean contains(@Nullable String id) {
+            return mTotalSelection.contains(id);
         }
 
         /**
          * Returns an unordered array of selected positions.
          */
-        public int[] getAll() {
-            final int size = size();
-            int[] positions = new int[size];
-            for (int i = 0; i < size; i++) {
-                positions[i] = get(i);
-            }
-            return positions;
+        public String[] getAll() {
+            return mTotalSelection.toArray(new String[0]);
         }
 
         /**
@@ -655,7 +621,7 @@
          * @return true if the selection is empty.
          */
         public boolean isEmpty() {
-            return mTotalSelection.size() == 0;
+            return mTotalSelection.isEmpty();
         }
 
         /**
@@ -666,37 +632,34 @@
          *     contain a value of true, and entries which were removed contain a value of false.
          */
         @VisibleForTesting
-        protected SparseBooleanArray setProvisionalSelection(
-                SparseBooleanArray provisionalSelection) {
-            SparseBooleanArray delta = new SparseBooleanArray();
+        protected Map<String, Boolean> setProvisionalSelection(Set<String> provisionalSelection) {
+            Map<String, Boolean> delta = new HashMap<>();
 
-            for (int i = 0; i < mTotalSelection.size(); i++) {
-                int position = mTotalSelection.keyAt(i);
-                if (!provisionalSelection.get(position) && !mSavedSelection.get(position)) {
-                    // Remove each item that used to be in the selection but is unsaved and not in
-                    // the new provisional selection.
-                    delta.put(position, false);
+            for (String id: mTotalSelection) {
+                // Mark each item that used to be in the selection but is unsaved and not in the new
+                // provisional selection.
+                if (!provisionalSelection.contains(id) && !mSavedSelection.contains(id)) {
+                    delta.put(id, false);
                 }
             }
 
-            for (int i = 0; i < provisionalSelection.size(); i++) {
-                int position = provisionalSelection.keyAt(i);
-                if (!mTotalSelection.get(position)) {
-                    // Add each item that was not previously in the selection but is in the
-                    // new provisional selection.
-                    delta.put(position, true);
+            for (String id: provisionalSelection) {
+                // Mark each item that was not previously in the selection but is in the new
+                // provisional selection.
+                if (!mTotalSelection.contains(id)) {
+                    delta.put(id, true);
                 }
             }
 
-            // Now, iterate through the changes and actually add/remove them to/from
-            // mCurrentSelection. This could not be done in the previous loops because changing the
-            // size of the selection mid-iteration changes iteration order erroneously.
-            for (int i = 0; i < delta.size(); i++) {
-                int position = delta.keyAt(i);
-                if (delta.get(position)) {
-                    mTotalSelection.put(position, true);
+            // Now, iterate through the changes and actually add/remove them to/from the current
+            // selection. This could not be done in the previous loops because changing the size of
+            // the selection mid-iteration changes iteration order erroneously.
+            for (Map.Entry<String, Boolean> entry: delta.entrySet()) {
+                String id = entry.getKey();
+                if (entry.getValue()) {
+                    mTotalSelection.add(id);
                 } else {
-                    mTotalSelection.delete(position);
+                    mTotalSelection.remove(id);
                 }
             }
 
@@ -710,7 +673,7 @@
          */
         @VisibleForTesting
         protected void applyProvisionalSelection() {
-            mSavedSelection = mTotalSelection.clone();
+            mSavedSelection = new HashSet<>(mTotalSelection);
         }
 
         /**
@@ -718,16 +681,16 @@
          * now deselected.
          */
         @VisibleForTesting
-        protected void cancelProvisionalSelection() {
-            mTotalSelection = mSavedSelection.clone();
+        void cancelProvisionalSelection() {
+            mTotalSelection = new HashSet<>(mSavedSelection);
         }
 
         /** @hide */
         @VisibleForTesting
-        boolean add(int position) {
-            if (!mTotalSelection.get(position)) {
-                mTotalSelection.put(position, true);
-                mSavedSelection.put(position, true);
+        boolean add(String id) {
+            if (!mTotalSelection.contains(id)) {
+                mTotalSelection.add(id);
+                mSavedSelection.add(id);
                 return true;
             }
             return false;
@@ -735,79 +698,32 @@
 
         /** @hide */
         @VisibleForTesting
-        boolean remove(int position) {
-            if (mTotalSelection.get(position)) {
-                mTotalSelection.delete(position);
-                mSavedSelection.delete(position);
+        boolean remove(String id) {
+            if (mTotalSelection.contains(id)) {
+                mTotalSelection.remove(id);
+                mSavedSelection.remove(id);
                 return true;
             }
             return false;
         }
 
-        /**
-         * Adjusts the selection range to reflect the existence of newly inserted values at
-         * the specified positions. This has the effect of adjusting all existing selected
-         * positions within the specified range accordingly. Note that this function discards any
-         * provisional selections which may have been applied.
-         *
-         * @param startPosition
-         * @param count
-         * @hide
-         */
-        @VisibleForTesting
-        void expand(int startPosition, int count) {
-            checkState(startPosition >= 0);
-            checkState(count > 0);
-            cancelProvisionalSelection();
-
-            for (int i = 0; i < mTotalSelection.size(); i++) {
-                int itemPosition = mTotalSelection.keyAt(i);
-                if (itemPosition >= startPosition) {
-                    mTotalSelection.setKeyAt(i, itemPosition + count);
-                    mSavedSelection.setKeyAt(i, itemPosition + count);
-                }
-            }
-        }
-
-        /**
-         * Adjusts the selection range to reflect the removal specified positions. This has
-         * the effect of adjusting all existing selected positions within the specified range
-         * accordingly. Note that this function discards any provisional selections which may have
-         * been applied.
-         *
-         * @param startPosition
-         * @param count The length of the range to collapse. Must be greater than 0.
-         * @hide
-         */
-        @VisibleForTesting
-        void collapse(int startPosition, int count) {
-            checkState(startPosition >= 0);
-            checkState(count > 0);
-
-            int endPosition = startPosition + count - 1;
-
-            SparseBooleanArray newSelection = new SparseBooleanArray();
-            for (int i = 0; i < mSavedSelection.size(); i++) {
-                int itemPosition = mSavedSelection.keyAt(i);
-                if (itemPosition < startPosition) {
-                    newSelection.append(itemPosition, true);
-                } else if (itemPosition > endPosition) {
-                    newSelection.append(itemPosition - count, true);
-                }
-            }
-            mSavedSelection = newSelection;
-            cancelProvisionalSelection();
-        }
-
         public void clear() {
             mSavedSelection.clear();
             mTotalSelection.clear();
         }
 
+        /**
+         * Trims this selection to be the intersection of itself with the set of given IDs.
+         */
+        public void intersect(Collection<String> ids) {
+            mSavedSelection.retainAll(ids);
+            mTotalSelection.retainAll(ids);
+        }
+
         @VisibleForTesting
         void copyFrom(Selection source) {
-            mSavedSelection = source.mSavedSelection.clone();
-            mTotalSelection = source.mTotalSelection.clone();
+            mSavedSelection = new HashSet<>(source.mSavedSelection);
+            mTotalSelection = new HashSet<>(source.mTotalSelection);
         }
 
         @Override
@@ -821,11 +737,11 @@
                     .append(mTotalSelection.size())
                     .append(", ")
                     .append("items=[");
-            for (int i=0; i < mTotalSelection.size(); i++) {
-                if (i > 0) {
+            for (Iterator<String> i = mTotalSelection.iterator(); i.hasNext(); ) {
+                buffer.append(i.next());
+                if (i.hasNext()) {
                     buffer.append(", ");
                 }
-                buffer.append(mTotalSelection.keyAt(i));
             }
             buffer.append("]}");
             return buffer.toString();
@@ -874,6 +790,10 @@
         int getChildCount();
         int getVisibleChildCount();
         void focusItem(int position);
+        /**
+         * Layout items are excluded from the GridModel.
+         */
+        boolean isLayoutItem(int adapterPosition);
     }
 
     /** Recycler view facade implementation backed by good ol' RecyclerView. */
@@ -884,8 +804,8 @@
 
         private boolean mIsOverlayShown = false;
 
-        RuntimeSelectionEnvironment(RecyclerView rv) {
-            mView = rv;
+        RuntimeSelectionEnvironment(RecyclerView view) {
+            mView = view;
             mBand = mView.getContext().getTheme().getDrawable(R.drawable.band_select_overlay);
         }
 
@@ -904,12 +824,12 @@
         }
 
         @Override
-        public void addOnScrollListener(OnScrollListener listener) {
+        public void addOnScrollListener(RecyclerView.OnScrollListener listener) {
             mView.addOnScrollListener(listener);
         }
 
         @Override
-        public void removeOnScrollListener(OnScrollListener listener) {
+        public void removeOnScrollListener(RecyclerView.OnScrollListener listener) {
             mView.removeOnScrollListener(listener);
         }
 
@@ -943,7 +863,7 @@
 
         @Override
         public int getColumnCount() {
-            LayoutManager layoutManager = mView.getLayoutManager();
+            RecyclerView.LayoutManager layoutManager = mView.getLayoutManager();
             if (layoutManager instanceof GridLayoutManager) {
                 return ((GridLayoutManager) layoutManager).getSpanCount();
             }
@@ -1005,20 +925,45 @@
             if (vh != null) {
                 vh.itemView.requestFocus();
             } else {
-                // Don't smooth scroll; that taxes the system unnecessarily and makes the scroll
-                // handling logic below more complicated.  See b/24865658.
-                mView.scrollToPosition(pos);
+                mView.smoothScrollToPosition(pos);
                 // Set a one-time listener to request focus when the scroll has completed.
                 mView.addOnScrollListener(
                     new RecyclerView.OnScrollListener() {
                         @Override
-                        public void onScrolled(RecyclerView view, int dx, int dy) {
-                            view.findViewHolderForAdapterPosition(pos).itemView.requestFocus();
-                            view.removeOnScrollListener(this);
+                        public void onScrollStateChanged (RecyclerView view, int newState) {
+                            if (newState == RecyclerView.SCROLL_STATE_IDLE) {
+                                // When scrolling stops, find the item and focus it.
+                                RecyclerView.ViewHolder vh =
+                                        view.findViewHolderForAdapterPosition(pos);
+                                if (vh != null) {
+                                    vh.itemView.requestFocus();
+                                } else {
+                                    // This might happen in weird corner cases, e.g. if the user is
+                                    // scrolling while a delete operation is in progress.  In that
+                                    // case, just don't attempt to focus the missing item.
+                                    Log.w(
+                                        TAG, "Unable to focus position " + pos + " after a scroll");
+                                }
+                                view.removeOnScrollListener(this);
+                            }
                         }
                     });
             }
         }
+
+        @Override
+        public boolean isLayoutItem(int pos) {
+            // The band selection model only operates on documents and directories. Exclude other
+            // types of adapter items (e.g. whitespace items like dividers).
+            RecyclerView.ViewHolder vh = mView.findViewHolderForAdapterPosition(pos);
+            switch (vh.getItemViewType()) {
+                case ITEM_TYPE_DOCUMENT:
+                case ITEM_TYPE_DIRECTORY:
+                    return false;
+                default:
+                    return true;
+            }
+        }
     }
 
     public interface Callback {
@@ -1029,17 +974,17 @@
          * @param selected <code>true</code> if the item is now selected, <code>false</code>
          *                if the item is now unselected.
          */
-        public void onItemStateChanged(int position, boolean selected);
+        public void onItemStateChanged(String id, boolean selected);
 
         /**
          * Called prior to an item changing state. Callbacks can cancel
          * the change at {@code position} by returning {@code false}.
          *
-         * @param position Adapter position of the item that was checked or unchecked
+         * @param id Adapter position of the item that was checked or unchecked
          * @param selected <code>true</code> if the item is to be selected, <code>false</code>
          *                if the item is to be unselected.
          */
-        public boolean onBeforeItemStateChange(int position, boolean selected);
+        public boolean onBeforeItemStateChange(String id, boolean selected);
 
         /**
          * Called immediately after completion of any set of changes.
@@ -1075,7 +1020,7 @@
             mModelBuilder = new Runnable() {
                 @Override
                 public void run() {
-                    mModel = new GridModel(mEnvironment);
+                    mModel = new GridModel(mEnvironment, mAdapter);
                     mModel.addOnSelectionChangedListener(BandController.this);
                 }
             };
@@ -1202,11 +1147,15 @@
             mSelection.applyProvisionalSelection();
             mModel.endSelection();
             int firstSelected = mModel.getPositionNearestOrigin();
-            if (!mSelection.contains(firstSelected)) {
-                Log.w(TAG, "First selected by band is NOT in selection!");
-                // Sadly this is really happening. Need to figure out what's going on.
-            } else if (firstSelected != GridModel.NOT_SET) {
-                setSelectionFocusBegin(firstSelected);
+            if (firstSelected != NOT_SET) {
+                if (mSelection.contains(mAdapter.getModelId(firstSelected))) {
+                    // TODO: firstSelected should really be lastSelected, we want to anchor the item
+                    // where the mouse-up occurred.
+                    setSelectionRangeBegin(firstSelected);
+                } else {
+                    // TODO: Check if this is really happening.
+                    Log.w(TAG, "First selected by band is NOT in selection!");
+                }
             }
 
             mModel = null;
@@ -1214,11 +1163,10 @@
         }
 
         @Override
-        public void onSelectionChanged(SparseBooleanArray updatedSelection) {
-            SparseBooleanArray delta = mSelection.setProvisionalSelection(updatedSelection);
-            for (int i = 0; i < delta.size(); i++) {
-                int position = delta.keyAt(i);
-                notifyItemStateChanged(position, delta.get(position));
+        public void onSelectionChanged(Set<String> updatedSelection) {
+            Map<String, Boolean> delta = mSelection.setProvisionalSelection(updatedSelection);
+            for (Map.Entry<String, Boolean> entry: delta.entrySet()) {
+                notifyItemStateChanged(entry.getKey(), entry.getValue());
             }
             notifySelectionChanged();
         }
@@ -1362,6 +1310,8 @@
         private static final int LOWER_RIGHT = LOWER | RIGHT;
 
         private final SelectionEnvironment mHelper;
+        private final DocumentsAdapter mAdapter;
+
         private final List<OnSelectionChangedListener> mOnSelectionChangedListeners =
                 new ArrayList<>();
 
@@ -1384,7 +1334,7 @@
 
         // Array passed to registered OnSelectionChangedListeners. One array is created and reused
         // throughout the lifetime of the object.
-        private final SparseBooleanArray mSelection = new SparseBooleanArray();
+        private final Set<String> mSelection = new HashSet<>();
 
         // The current pointer (in absolute positioning from the top of the view).
         private Point mPointer = null;
@@ -1399,8 +1349,9 @@
         // should expand from when Shift+click is used.
         private int mPositionNearestOrigin = NOT_SET;
 
-        GridModel(SelectionEnvironment helper) {
+        GridModel(SelectionEnvironment helper, DocumentsAdapter adapter) {
             mHelper = helper;
+            mAdapter = adapter;
             mHelper.addOnScrollListener(this);
         }
 
@@ -1476,10 +1427,10 @@
         private void recordVisibleChildren() {
             for (int i = 0; i < mHelper.getVisibleChildCount(); i++) {
                 int adapterPosition = mHelper.getAdapterPositionAt(i);
-                if (!mKnownPositions.get(adapterPosition)) {
+                if (!mHelper.isLayoutItem(adapterPosition) &&
+                        !mKnownPositions.get(adapterPosition)) {
                     mKnownPositions.put(adapterPosition, true);
-                    recordItemData(
-                            mHelper.getAbsoluteRectForChildViewAt(i), adapterPosition);
+                    recordItemData(mHelper.getAbsoluteRectForChildViewAt(i), adapterPosition);
                 }
             }
         }
@@ -1563,31 +1514,29 @@
          * @param rect Rectangle including all covered items.
          */
         private void updateSelection(Rect rect) {
-            int columnStartIndex =
+            int columnStart =
                     Collections.binarySearch(mColumnBounds, new Limits(rect.left, rect.left));
-            checkState(columnStartIndex >= 0);
-            int columnEndIndex = columnStartIndex;
+            checkState(columnStart >= 0);
+            int columnEnd = columnStart;
 
-            for (int i = columnStartIndex; i < mColumnBounds.size()
+            for (int i = columnStart; i < mColumnBounds.size()
                     && mColumnBounds.get(i).lowerLimit <= rect.right; i++) {
-                columnEndIndex = i;
+                columnEnd = i;
             }
 
-            SparseIntArray firstColumn =
-                    mColumns.get(mColumnBounds.get(columnStartIndex).lowerLimit);
-            int rowStartIndex = firstColumn.indexOfKey(rect.top);
-            if (rowStartIndex < 0) {
+            int rowStart = Collections.binarySearch(mRowBounds, new Limits(rect.top, rect.top));
+            if (rowStart < 0) {
                 mPositionNearestOrigin = NOT_SET;
                 return;
             }
 
-            int rowEndIndex = rowStartIndex;
-            for (int i = rowStartIndex;
-                    i < firstColumn.size() && firstColumn.keyAt(i) <= rect.bottom; i++) {
-                rowEndIndex = i;
+            int rowEnd = rowStart;
+            for (int i = rowStart; i < mRowBounds.size()
+                    && mRowBounds.get(i).lowerLimit <= rect.bottom; i++) {
+                rowEnd = i;
             }
 
-            updateSelection(columnStartIndex, columnEndIndex, rowStartIndex, rowEndIndex);
+            updateSelection(columnStart, columnEnd, rowStart, rowEnd);
         }
 
         /**
@@ -1596,17 +1545,30 @@
          */
         private void updateSelection(
                 int columnStartIndex, int columnEndIndex, int rowStartIndex, int rowEndIndex) {
+            if (DEBUG) Log.d(TAG, String.format("updateSelection: %d, %d, %d, %d",
+                    columnStartIndex, columnEndIndex, rowStartIndex, rowEndIndex));
+
             mSelection.clear();
             for (int column = columnStartIndex; column <= columnEndIndex; column++) {
                 SparseIntArray items = mColumns.get(mColumnBounds.get(column).lowerLimit);
                 for (int row = rowStartIndex; row <= rowEndIndex; row++) {
-                    int position = items.get(items.keyAt(row));
-                    mSelection.append(position, true);
-                    if (isPossiblePositionNearestOrigin(column, columnStartIndex, columnEndIndex,
-                            row, rowStartIndex, rowEndIndex)) {
-                        // If this is the position nearest the origin, record it now so that it
-                        // can be returned by endSelection() later.
-                        mPositionNearestOrigin = position;
+                    // The default return value for SparseIntArray.get is 0, which is a valid
+                    // position. Use a sentry value to prevent erroneously selecting item 0.
+                    final int rowKey = mRowBounds.get(row).lowerLimit;
+                    int position = items.get(rowKey, NOT_SET);
+                    if (position != NOT_SET) {
+                        String id = mAdapter.getModelId(position);
+                        if (id != null) {
+                            // The adapter inserts items for UI layout purposes that aren't associated
+                            // with files.  Those will have a null model ID.  Don't select them.
+                            mSelection.add(id);
+                        }
+                        if (isPossiblePositionNearestOrigin(column, columnStartIndex, columnEndIndex,
+                                row, rowStartIndex, rowEndIndex)) {
+                            // If this is the position nearest the origin, record it now so that it
+                            // can be returned by endSelection() later.
+                            mPositionNearestOrigin = position;
+                        }
                     }
                 }
             }
@@ -1643,7 +1605,7 @@
          * Listener for changes in which items have been band selected.
          */
         static interface OnSelectionChangedListener {
-            public void onSelectionChanged(SparseBooleanArray updatedSelection);
+            public void onSelectionChanged(Set<String> updatedSelection);
         }
 
         void addOnSelectionChangedListener(OnSelectionChangedListener listener) {
@@ -1959,32 +1921,41 @@
         // Here we unpack information from the event and pass it to an more
         // easily tested method....basically eliminating the need to synthesize
         // events and views and so on in our tests.
-        int position = findTargetPosition(view, keyCode);
-        if (position == RecyclerView.NO_POSITION) {
+        int endPos = findTargetPosition(view, keyCode);
+        if (endPos == RecyclerView.NO_POSITION) {
             // If there is no valid navigation target, don't handle the keypress.
             return false;
         }
 
-        return attemptChangePosition(position, event.isShiftPressed());
+        int startPos = mEnvironment.getAdapterPositionForChildView(view);
+
+        return changeFocus(startPos, endPos, event.isShiftPressed());
     }
 
+    /**
+     * @param startPosition The current focus position.
+     * @param targetPosition The adapter position to focus.
+     * @param extendSelection
+     */
     @VisibleForTesting
-    boolean attemptChangePosition(int targetPosition, boolean isShiftPressed) {
+    boolean changeFocus(int startPosition, int targetPosition, boolean extendSelection) {
         // Focus the new file.
         mEnvironment.focusItem(targetPosition);
 
-        if (isShiftPressed) {
-            if (!hasSelection()) {
-                // If there is no selection, start a selection when the user presses shift-arrow.
-                toggleSelection(targetPosition);
-            } else if (!mSingleSelect) {
-                mRanger.snapSelection(targetPosition);
-                notifySelectionChanged();
-            } else {
+        if (extendSelection) {
+            if (mSingleSelect) {
                 // We're in single select and have an existing selection.
                 // Our best guess as to what the user would expect is to advance the selection.
                 clearSelection();
                 toggleSelection(targetPosition);
+            } else {
+                if (!hasSelection()) {
+                    // No selection - start a selection when the user presses shift-arrow.
+                    toggleSelection(startPosition);
+                    setSelectionRangeBegin(startPosition);
+                }
+                mRanger.snapSelection(targetPosition);
+                notifySelectionChanged();
             }
         }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
new file mode 100644
index 0000000..71708c1
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static com.android.documentsui.Shared.TAG;
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
+import android.support.annotation.Nullable;
+import android.support.design.widget.Snackbar;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+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.model.DocumentInfo;
+import com.android.documentsui.R;
+import com.android.documentsui.Snackbars;
+/**
+ * Dialog to rename file or directory.
+ */
+class RenameDocumentFragment extends DialogFragment {
+    private static final String TAG_RENAME_DOCUMENT = "rename_document";
+    private DocumentInfo mDocument;
+
+    public static void show(FragmentManager fm, DocumentInfo document) {
+        final RenameDocumentFragment dialog = new RenameDocumentFragment();
+        dialog.mDocument = document;
+        dialog.show(fm, TAG_RENAME_DOCUMENT);
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        Context context = getActivity();
+        AlertDialog.Builder builder = new AlertDialog.Builder(context);
+        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);
+        editText.setText(mDocument.displayName);
+
+        builder.setTitle(R.string.menu_rename);
+        builder.setView(view);
+
+        builder.setPositiveButton(
+                android.R.string.ok,
+                new OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        renameDocuments(editText.getText().toString());
+                    }
+                });
+
+        builder.setNegativeButton(android.R.string.cancel, null);
+
+        final AlertDialog dialog = builder.create();
+
+        editText.setOnEditorActionListener(
+                new OnEditorActionListener() {
+                    @Override
+                    public boolean onEditorAction(
+                            TextView view, int actionId, @Nullable KeyEvent event) {
+                        if (event != null
+                                && event.getKeyCode() == KeyEvent.KEYCODE_ENTER
+                                && event.hasNoModifiers()) {
+                            renameDocuments(editText.getText().toString());
+                            dialog.dismiss();
+                            return true;
+                        }
+                        return false;
+                    }
+                });
+
+        return dialog;
+    }
+
+    private void renameDocuments(String newDisplayName) {
+        BaseActivity activity = (BaseActivity) getActivity();
+
+        new RenameDocumentsTask(activity, newDisplayName).execute(mDocument);
+    }
+
+    private class RenameDocumentsTask extends AsyncTask<DocumentInfo, Void, DocumentInfo> {
+        private final BaseActivity mActivity;
+        private final String mNewDisplayName;
+
+        public RenameDocumentsTask(BaseActivity activity, String newDisplayName) {
+            mActivity = activity;
+            mNewDisplayName = newDisplayName;
+        }
+
+        @Override
+        protected void onPreExecute() {
+            mActivity.setPending(true);
+        }
+
+        @Override
+        protected DocumentInfo doInBackground(DocumentInfo... document) {
+            checkArgument(document.length == 1);
+            final ContentResolver resolver = mActivity.getContentResolver();
+            ContentProviderClient client = null;
+
+            try {
+                client = DocumentsApplication.acquireUnstableProviderOrThrow(
+                        resolver, document[0].derivedUri.getAuthority());
+                Uri newUri = DocumentsContract.renameDocument(
+                        client, document[0].derivedUri, mNewDisplayName);
+                return DocumentInfo.fromUri(resolver, newUri);
+            } catch (Exception e) {
+                Log.w(TAG, "Failed to rename file", e);
+                return null;
+            } finally {
+                ContentProviderClient.releaseQuietly(client);
+            }
+        }
+
+        @Override
+        protected void onPostExecute(DocumentInfo result) {
+            if (result == null) {
+                Snackbars.makeSnackbar(mActivity, R.string.rename_error, Snackbar.LENGTH_SHORT)
+                        .show();
+            }
+
+            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
new file mode 100644
index 0000000..2485ad9
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static com.android.internal.util.Preconditions.checkArgument;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView.AdapterDataObserver;
+import android.util.SparseArray;
+import android.view.ViewGroup;
+import android.widget.Space;
+
+import com.android.documentsui.R;
+import com.android.documentsui.State;
+
+import java.util.List;
+
+/**
+ * Adapter wrapper that inserts a sort of line break item between directories and regular files.
+ * Only needs to be used in GRID mode...at this time.
+ */
+final class SectionBreakDocumentsAdapterWrapper extends DocumentsAdapter {
+
+    private static final String TAG = "SectionBreakDocumentsAdapterWrapper";
+    private static final int ITEM_TYPE_SECTION_BREAK = Integer.MAX_VALUE;
+
+    private final Environment mEnv;
+    private final DocumentsAdapter mDelegate;
+
+    private int mBreakPosition = -1;
+
+    SectionBreakDocumentsAdapterWrapper(Environment environment, DocumentsAdapter delegate) {
+        mEnv = environment;
+        mDelegate = delegate;
+
+        // Relay events published by our delegate to our listeners (presumably RecyclerView)
+        // with adjusted positions.
+        mDelegate.registerAdapterDataObserver(new EventRelay());
+    }
+
+    public GridLayoutManager.SpanSizeLookup createSpanSizeLookup() {
+        return new GridLayoutManager.SpanSizeLookup() {
+            @Override
+            public int getSpanSize(int position) {
+                // Make layout whitespace span the grid. This has the effect of breaking
+                // grid rows whenever layout whitespace is encountered.
+                if (getItemViewType(position) == ITEM_TYPE_SECTION_BREAK) {
+                    return mEnv.getColumnCount();
+                } else {
+                    return 1;
+                }
+            }
+        };
+    }
+
+    @Override
+    public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        if (viewType == ITEM_TYPE_SECTION_BREAK) {
+            return new EmptyDocumentHolder(mEnv.getContext());
+        } else {
+            return mDelegate.createViewHolder(parent, viewType);
+        }
+    }
+
+    @Override
+    public void onBindViewHolder(DocumentHolder holder, int p, List<Object> payload) {
+        if (holder.getItemViewType() != ITEM_TYPE_SECTION_BREAK) {
+            mDelegate.onBindViewHolder(holder, toDelegatePosition(p), payload);
+        } else {
+            ((EmptyDocumentHolder)holder).bind(mEnv.getDisplayState());
+        }
+    }
+
+    @Override
+    public void onBindViewHolder(DocumentHolder holder, int p) {
+        if (holder.getItemViewType() != ITEM_TYPE_SECTION_BREAK) {
+            mDelegate.onBindViewHolder(holder, toDelegatePosition(p));
+        } else {
+            ((EmptyDocumentHolder)holder).bind(mEnv.getDisplayState());
+        }
+    }
+
+    @Override
+    public int getItemCount() {
+        return mBreakPosition == -1
+                ? mDelegate.getItemCount()
+                : mDelegate.getItemCount() + 1;
+    }
+
+    @Override
+    public void onModelUpdate(Model model) {
+        mDelegate.onModelUpdate(model);
+        mBreakPosition = -1;
+
+        // Walk down the list of IDs till we encounter something that's not a directory, and
+        // insert a whitespace element - this introduces a visual break in the grid between
+        // folders and documents.
+        // TODO: This code makes assumptions about the model, namely, that it performs a
+        // bucketed sort where directories will always be ordered before other files. CBB.
+        List<String> modelIds = mDelegate.getModelIds();
+        for (int i = 0; i < modelIds.size(); i++) {
+            if (!isDirectory(model, i)) {
+                // If the break is the first thing in the list, then there are actually no
+                // directories. In that case, don't insert a break at all.
+                if (i > 0) {
+                    mBreakPosition = i;
+                }
+                break;
+            }
+        }
+    }
+
+    @Override
+    public void onModelUpdateFailed(Exception e) {
+        mDelegate.onModelUpdateFailed(e);
+    }
+
+    @Override
+    public int getItemViewType(int p) {
+        if (p == mBreakPosition) {
+            return ITEM_TYPE_SECTION_BREAK;
+        } else {
+            return mDelegate.getItemViewType(toDelegatePosition(p));
+        }
+    }
+
+    /**
+     * Returns the position of an item in the delegate, adjusting
+     * values that are greater than the break position.
+     *
+     * @param p Position within the view
+     * @return Position within the delegate
+     */
+    private int toDelegatePosition(int p) {
+        return (mBreakPosition != -1 && p > mBreakPosition) ? p - 1 : p;
+    }
+
+    /**
+     * Returns the position of an item in the view, adjusting
+     * values that are greater than the break position.
+     *
+     * @param p Position within the delegate
+     * @return Position within the view
+     */
+    private int toViewPosition(int p) {
+        // If position is greater than or equal to the break, increase by one.
+        return (mBreakPosition != -1 && p >= mBreakPosition) ? p + 1 : p;
+    }
+
+    @Override
+    public SparseArray<String> hide(String... ids) {
+        // NOTE: We hear about these changes and adjust break position
+        // in our AdapterDataObserver.
+        return mDelegate.hide(ids);
+    }
+
+    @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();
+    }
+
+    @Override
+    String getModelId(int p) {
+        return (p == mBreakPosition) ? null : mDelegate.getModelId(toDelegatePosition(p));
+    }
+
+    @Override
+    public void onItemSelectionChanged(String id) {
+        mDelegate.onItemSelectionChanged(id);
+    }
+
+    // Listener we add to our delegate. This allows us to relay events published
+    // by the delegate to our listeners (presumably RecyclerView) with adjusted positions.
+    private final class EventRelay extends AdapterDataObserver {
+        public void onChanged() {
+            throw new UnsupportedOperationException();
+        }
+
+        public void onItemRangeChanged(int positionStart, int itemCount) {
+            throw new UnsupportedOperationException();
+        }
+
+        public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
+            checkArgument(itemCount == 1);
+            notifyItemRangeChanged(toViewPosition(positionStart), itemCount, payload);
+        }
+
+        public void onItemRangeInserted(int positionStart, int itemCount) {
+            checkArgument(itemCount == 1);
+            if (positionStart < mBreakPosition) {
+                mBreakPosition++;
+            }
+            notifyItemRangeInserted(toViewPosition(positionStart), itemCount);
+        }
+
+        public void onItemRangeRemoved(int positionStart, int itemCount) {
+            checkArgument(itemCount == 1);
+            if (positionStart < mBreakPosition) {
+                mBreakPosition--;
+            }
+            notifyItemRangeRemoved(toViewPosition(positionStart), itemCount);
+        }
+
+        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    /**
+     * The most elegant transparent blank box that spans N rows ever conceived.
+     */
+    private static final class EmptyDocumentHolder extends DocumentHolder {
+        final int mVisibleHeight;
+
+        public EmptyDocumentHolder(Context context) {
+            super(context, new Space(context));
+
+            // Per UX spec, this puts a bigger gap between the folders and documents in the grid.
+            mVisibleHeight = context.getResources().getDimensionPixelSize(
+                    R.dimen.grid_item_margin);
+        }
+
+        public void bind(State state) {
+            bind(null, null, state);
+        }
+
+        @Override
+        public void bind(Cursor cursor, String modelId, State state) {
+            if (state.derivedMode == State.MODE_GRID) {
+                itemView.setMinimumHeight(mVisibleHeight);
+            } else {
+                itemView.setMinimumHeight(0);
+            }
+            return;
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
index 215c6e6..4b5499a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
@@ -239,6 +239,10 @@
         return (flags & Document.FLAG_SUPPORTS_DELETE) != 0;
     }
 
+    public boolean isRenameSupported() {
+        return (flags & Document.FLAG_SUPPORTS_RENAME) != 0;
+    }
+
     public boolean isGridTitlesHidden() {
         return (flags & Document.FLAG_DIR_HIDE_GRID_TITLES) != 0;
     }
@@ -255,10 +259,6 @@
         return (flags & Document.FLAG_VIRTUAL_DOCUMENT) != 0;
     }
 
-    public boolean isTypedDocument() {
-        return (flags & Document.FLAG_SUPPORTS_TYPED_DOCUMENT) != 0;
-    }
-
     public int hashCode() {
         return derivedUri.hashCode() + mimeType.hashCode();
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index 4caa891..12c0b8f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -174,7 +174,7 @@
             derivedIcon = R.drawable.ic_root_home;
             derivedType = TYPE_LOCAL;
         } else if (isExternalStorage()) {
-            derivedIcon = R.drawable.ic_root_sdcard;
+            derivedIcon = R.drawable.ic_root_smartphone;
             derivedType = TYPE_LOCAL;
         } else if (isDownloads()) {
             derivedIcon = R.drawable.ic_root_download;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
new file mode 100644
index 0000000..e5e66f8
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
@@ -0,0 +1,561 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static android.os.SystemClock.elapsedRealtime;
+import static android.provider.DocumentsContract.buildChildDocumentsUri;
+import static android.provider.DocumentsContract.buildDocumentUri;
+import static android.provider.DocumentsContract.getDocumentId;
+import static android.provider.DocumentsContract.isChildDocument;
+import static com.android.documentsui.OperationDialogFragment.DIALOG_TYPE_CONVERTED;
+import static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.model.DocumentInfo.getCursorLong;
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+import static com.android.documentsui.services.FileOperationService.EXTRA_DIALOG_TYPE;
+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;
+import android.app.Notification.Builder;
+import android.app.PendingIntent;
+import android.content.ContentProviderClient;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.webkit.MimeTypeMap;
+
+import com.android.documentsui.R;
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.services.FileOperationService.OpType;
+
+import libcore.io.IoUtils;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+class CopyJob extends Job {
+    private static final String TAG = "CopyJob";
+    private static final int PROGRESS_INTERVAL_MILLIS = 1000;
+    final List<DocumentInfo> mSrcs;
+    final ArrayList<DocumentInfo> convertedFiles = new ArrayList<>();
+
+    private long mStartTime = -1;
+    private long mBatchSize;
+    private long mBytesCopied;
+    private long mLastNotificationTime;
+    // Speed estimation
+    private long mBytesCopiedSample;
+    private long mSampleTime;
+    private long mSpeed;
+    private long mRemainingTime;
+
+    /**
+     * Copies files to a destination identified by {@code destination}.
+     * @see @link {@link Job} constructor for most param descriptions.
+     *
+     * @param srcs List of files to be copied.
+     */
+    CopyJob(Context service, Context appContext, Listener listener,
+            String id, DocumentStack stack, List<DocumentInfo> srcs) {
+        super(service, appContext, listener, OPERATION_COPY, id, stack);
+
+        checkArgument(!srcs.isEmpty());
+        this.mSrcs = srcs;
+    }
+
+    /**
+     * @see @link {@link Job} constructor for most param descriptions.
+     *
+     * @param srcs List of files to be copied.
+     */
+    CopyJob(Context service, Context appContext, Listener listener,
+            @OpType int opType, String id, DocumentStack destination, List<DocumentInfo> srcs) {
+        super(service, appContext, listener, opType, id, destination);
+
+        checkArgument(!srcs.isEmpty());
+        this.mSrcs = srcs;
+    }
+
+    @Override
+    Builder createProgressBuilder() {
+        return super.createProgressBuilder(
+                service.getString(R.string.copy_notification_title),
+                R.drawable.ic_menu_copy,
+                service.getString(android.R.string.cancel),
+                R.drawable.ic_cab_cancel);
+    }
+
+    @Override
+    public Notification getSetupNotification() {
+        return getSetupNotification(service.getString(R.string.copy_preparing));
+    }
+
+    public boolean shouldUpdateProgress() {
+        // Wait a while between updates :)
+        return elapsedRealtime() - mLastNotificationTime > PROGRESS_INTERVAL_MILLIS;
+    }
+
+    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 (mRemainingTime > 0) {
+            mProgressBuilder.setContentText(service.getString(msgId,
+                    DateUtils.formatDuration(mRemainingTime)));
+        } else {
+            mProgressBuilder.setContentText(null);
+        }
+
+        // Remember when we last returned progress so we can provide an answer
+        // in shouldUpdateProgress.
+        mLastNotificationTime = elapsedRealtime();
+        return mProgressBuilder.build();
+    }
+
+    public Notification getProgressNotification() {
+        return getProgressNotification(R.string.copy_remaining);
+    }
+
+    void onBytesCopied(long numBytes) {
+        this.mBytesCopied += numBytes;
+    }
+
+    /**
+     * Generates an estimate of the remaining time in the copy.
+     */
+    void updateRemainingTimeEstimate() {
+        long elapsedTime = elapsedRealtime() - mStartTime;
+
+        final long sampleDuration = elapsedTime - mSampleTime;
+        final long sampleSpeed = ((mBytesCopied - mBytesCopiedSample) * 1000) / sampleDuration;
+        if (mSpeed == 0) {
+            mSpeed = sampleSpeed;
+        } else {
+            mSpeed = ((3 * mSpeed) + sampleSpeed) / 4;
+        }
+
+        if (mSampleTime > 0 && mSpeed > 0) {
+            mRemainingTime = ((mBatchSize - mBytesCopied) * 1000) / mSpeed;
+        } else {
+            mRemainingTime = 0;
+        }
+
+        mSampleTime = elapsedTime;
+        mBytesCopiedSample = mBytesCopied;
+    }
+
+    @Override
+    Notification getFailureNotification() {
+        return getFailureNotification(
+                R.plurals.copy_error_notification_title, R.drawable.ic_menu_copy);
+    }
+
+    @Override
+    Notification getWarningNotification() {
+        final Intent navigateIntent = buildNavigateIntent();
+        navigateIntent.putExtra(EXTRA_DIALOG_TYPE, DIALOG_TYPE_CONVERTED);
+        navigateIntent.putExtra(EXTRA_OPERATION, operationType);
+
+        navigateIntent.putParcelableArrayListExtra(EXTRA_SRC_LIST, convertedFiles);
+
+        // TODO: Consider adding a dialog on tapping the notification with a list of
+        // converted files.
+        final Notification.Builder warningBuilder = new Notification.Builder(service)
+                .setContentTitle(service.getResources().getString(
+                        R.string.notification_copy_files_converted_title))
+                .setContentText(service.getString(
+                        R.string.notification_touch_for_details))
+                .setContentIntent(PendingIntent.getActivity(appContext, 0, navigateIntent,
+                        PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT))
+                .setCategory(Notification.CATEGORY_ERROR)
+                .setSmallIcon(R.drawable.ic_menu_copy)
+                .setAutoCancel(true);
+        return warningBuilder.build();
+    }
+
+    @Override
+    void start() throws RemoteException {
+        mStartTime = elapsedRealtime();
+
+        // client
+        mBatchSize = calculateSize(mSrcs);
+
+        DocumentInfo srcInfo;
+        DocumentInfo dstInfo;
+        for (int i = 0; i < mSrcs.size() && !isCanceled(); ++i) {
+            srcInfo = mSrcs.get(i);
+            dstInfo = stack.peek();
+
+            // Guard unsupported recursive operation.
+            if (dstInfo.equals(srcInfo) || isDescendentOf(srcInfo, dstInfo)) {
+                onFileFailed(srcInfo,
+                        "Skipping recursive operation on directory " + dstInfo.derivedUri + ".");
+                continue;
+            }
+
+            if (DEBUG) Log.d(TAG,
+                    "Copying " + srcInfo.displayName + " (" + srcInfo.derivedUri + ")"
+                    + " to " + dstInfo.displayName + " (" + dstInfo.derivedUri + ")");
+
+            processDocument(srcInfo, null, dstInfo);
+        }
+    }
+
+    @Override
+    boolean hasWarnings() {
+        return !convertedFiles.isEmpty();
+    }
+
+    /**
+     * Logs progress on the current copy operation. Displays/Updates the progress notification.
+     *
+     * @param bytesCopied
+     */
+    private void makeCopyProgress(long bytesCopied) {
+        onBytesCopied(bytesCopied);
+        if (shouldUpdateProgress()) {
+            updateRemainingTimeEstimate();
+            listener.onProgress(this);
+        }
+    }
+
+    /**
+     * Copies a the given document to the given location.
+     *
+     * @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
+     *
+     * 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 {
+
+        // TODO: When optimized copy kicks in, we'll not making any progress updates.
+        // For now. Local storage isn't using optimized copy.
+
+        // When copying within the same provider, try to use optimized copying.
+        // 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;
+                }
+                return true;
+            }
+        }
+
+        // If we couldn't do an optimized copy...we fall back to vanilla byte copy.
+        return byteCopyDocument(src, dstDirInfo);
+    }
+
+    boolean byteCopyDocument(DocumentInfo src, DocumentInfo dest)
+            throws RemoteException {
+        final String dstMimeType;
+        final String dstDisplayName;
+
+        if (DEBUG) Log.d(TAG, "Doing byte copy of document: " + src);
+        // 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, "*/*");
+            if (streamTypes != null && streamTypes.length > 0) {
+                dstMimeType = streamTypes[0];
+                final String extension = MimeTypeMap.getSingleton().
+                        getExtensionFromMimeType(dstMimeType);
+                dstDisplayName = src.displayName +
+                        (extension != null ? "." + extension : src.displayName);
+            } else {
+                onFileFailed(src, "Cannot copy virtual file. No streamable formats available.");
+                return false;
+            }
+        } else {
+            dstMimeType = src.mimeType;
+            dstDisplayName = src.displayName;
+        }
+
+        // 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);
+        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;
+        }
+
+        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;
+        }
+
+        final boolean success;
+        if (Document.MIME_TYPE_DIR.equals(src.mimeType)) {
+            success = copyDirectoryHelper(src, dstInfo);
+        } else {
+            success = copyFileHelper(src, dstInfo, dstMimeType);
+        }
+
+        return success;
+    }
+
+    /**
+     * Handles recursion into a directory and copying its contents. Note that in linux terms, this
+     * does the equivalent of "cp src/* dst", not "cp -r src dst".
+     *
+     * @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
+     */
+    private boolean copyDirectoryHelper(DocumentInfo srcDir, DocumentInfo destDir)
+            throws RemoteException {
+        // Recurse into directories. Copy children into the new subdirectory.
+        final String queryColumns[] = new String[] {
+                Document.COLUMN_DISPLAY_NAME,
+                Document.COLUMN_DOCUMENT_ID,
+                Document.COLUMN_MIME_TYPE,
+                Document.COLUMN_SIZE,
+                Document.COLUMN_FLAGS
+        };
+        Cursor cursor = null;
+        boolean success = true;
+        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);
+            }
+        } finally {
+            IoUtils.closeQuietly(cursor);
+        }
+
+        return success;
+    }
+
+    /**
+     * 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 mimeType Mime type for the target. Can be different than source for virtual files.
+     * @return True on success, false on error.
+     * @throws RemoteException
+     */
+    private boolean copyFileHelper(DocumentInfo src, DocumentInfo dest, String mimeType)
+            throws RemoteException {
+        CancellationSignal canceller = new CancellationSignal();
+        ParcelFileDescriptor srcFile = null;
+        ParcelFileDescriptor dstFile = null;
+        InputStream in = null;
+        OutputStream out = null;
+
+        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(
+                                src.derivedUri, mimeType, null, canceller);
+                srcFile = srcFileAsAsset.getParcelFileDescriptor();
+                in = new AssetFileDescriptor.AutoCloseInputStream(srcFileAsAsset);
+            } else {
+                srcFile = getClient(src).openFile(src.derivedUri, "r", canceller);
+                in = new ParcelFileDescriptor.AutoCloseInputStream(srcFile);
+            }
+
+            dstFile = getClient(dest).openFile(dest.derivedUri, "w", canceller);
+            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;
+                }
+                out.write(buffer, 0, len);
+                makeCopyProgress(len);
+            }
+
+            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);
+                }
+            }
+        } finally {
+            // 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;
+    }
+
+    /**
+     * Calculates the cumulative size of all the documents in the list. Directories are recursed
+     * into and totaled up.
+     *
+     * @param srcs
+     * @return Size in bytes.
+     * @throws RemoteException
+     */
+    private long calculateSize(List<DocumentInfo> srcs)
+            throws RemoteException {
+        long result = 0;
+
+        for (DocumentInfo src : srcs) {
+            if (src.isDirectory()) {
+                // Directories need to be recursed into.
+                result += calculateFileSizesRecursively(getClient(src), src.derivedUri);
+            } else {
+                result += src.size;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Calculates (recursively) the cumulative size of all the files under the given directory.
+     *
+     * @throws RemoteException
+     */
+    private static long calculateFileSizesRecursively(
+            ContentProviderClient client, Uri uri) throws RemoteException {
+        final String authority = uri.getAuthority();
+        final Uri queryUri = buildChildDocumentsUri(authority, getDocumentId(uri));
+        final String queryColumns[] = new String[] {
+                Document.COLUMN_DOCUMENT_ID,
+                Document.COLUMN_MIME_TYPE,
+                Document.COLUMN_SIZE
+        };
+
+        long result = 0;
+        Cursor cursor = null;
+        try {
+            cursor = client.query(queryUri, queryColumns, null, null, null);
+            while (cursor.moveToNext()) {
+                if (Document.MIME_TYPE_DIR.equals(
+                        getCursorString(cursor, Document.COLUMN_MIME_TYPE))) {
+                    // Recurse into directories.
+                    final Uri dirUri = buildDocumentUri(authority,
+                            getCursorString(cursor, Document.COLUMN_DOCUMENT_ID));
+                    result += calculateFileSizesRecursively(client, dirUri);
+                } else {
+                    // This may return -1 if the size isn't defined. Ignore those cases.
+                    long size = getCursorLong(cursor, Document.COLUMN_SIZE);
+                    result += size > 0 ? size : 0;
+                }
+            }
+        } finally {
+            IoUtils.closeQuietly(cursor);
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns true if {@code doc} is a descendant of {@code parentDoc}.
+     * @throws RemoteException
+     */
+    boolean isDescendentOf(DocumentInfo doc, DocumentInfo parent)
+            throws RemoteException {
+        if (parent.isDirectory() && doc.authority.equals(parent.authority)) {
+            return isChildDocument(getClient(doc), doc.derivedUri, parent.derivedUri);
+        }
+        return false;
+    }
+
+    private void onFileFailed(DocumentInfo file, String msg) {
+        Log.w(TAG, msg);
+        onFileFailed(file);
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder()
+                .append("CopyJob")
+                .append("{")
+                .append("id=" + id)
+                .append(", srcs=" + mSrcs)
+                .append(", destination=" + stack)
+                .append("}")
+                .toString();
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
new file mode 100644
index 0000000..24eb987
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.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.services;
+
+import static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.services.FileOperationService.OPERATION_DELETE;
+
+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.R;
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+
+import java.util.List;
+
+final class DeleteJob extends Job {
+
+    private static final String TAG = "DeleteJob";
+    private List<DocumentInfo> mSrcs;
+    final DocumentInfo mSrcParent;
+
+    /**
+     * Moves files to a destination identified by {@code destination}.
+     * Performs most work by delegating to CopyJob, then deleting
+     * a file after it has been copied.
+     *
+     * @see @link {@link Job} constructor for most param descriptions.
+     *
+     * @param srcs List of files to delete.
+     * @param srcParent Parent of all source files.
+     */
+    DeleteJob(Context service, Context appContext, Listener listener,
+            String id, DocumentStack stack, List<DocumentInfo> srcs, DocumentInfo srcParent) {
+        super(service, appContext, listener, OPERATION_DELETE, id, stack);
+        this.mSrcs = srcs;
+        this.mSrcParent = srcParent;
+    }
+
+    @Override
+    Builder createProgressBuilder() {
+        return super.createProgressBuilder(
+                service.getString(R.string.move_notification_title),
+                R.drawable.ic_menu_copy,
+                service.getString(android.R.string.cancel),
+                R.drawable.ic_cab_cancel);
+    }
+
+    @Override
+    public Notification getSetupNotification() {
+        return getSetupNotification(service.getString(R.string.delete_preparing));
+    }
+
+    @Override
+    Notification getFailureNotification() {
+        return getFailureNotification(
+                R.plurals.delete_error_notification_title, R.drawable.ic_menu_delete);
+    }
+
+    @Override
+    Notification getWarningNotification() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    void start() throws RemoteException {
+        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);
+                onFileFailed(doc);
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder()
+                .append("DeleteJob")
+                .append("{")
+                .append("id=" + id)
+                .append(", srcs=" + mSrcs)
+                .append(", srcParent=" + mSrcParent)
+                .append(", location=" + stack)
+                .append("}")
+                .toString();
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
new file mode 100644
index 0000000..3a025c2
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 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;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
+import android.util.Log;
+
+import com.android.documentsui.Shared;
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.services.Job.Factory;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.concurrent.GuardedBy;
+
+public class FileOperationService extends Service implements Job.Listener {
+
+    private static final int DEFAULT_DELAY = 0;
+    private static final int MAX_DELAY = 10 * 1000;  // ten seconds
+    private static final int POOL_SIZE = 2;  // "pool size", not *max* "pool size".
+    private static final int NOTIFICATION_ID_PROGRESS = 0;
+    private static final int NOTIFICATION_ID_FAILURE = 1;
+    private static final int NOTIFICATION_ID_WARNING = 2;
+
+    public static final String TAG = "FileOperationService";
+
+    public static final String EXTRA_JOB_ID = "com.android.documentsui.JOB_ID";
+    public static final String EXTRA_DELAY = "com.android.documentsui.DELAY";
+    public static final String EXTRA_OPERATION = "com.android.documentsui.OPERATION";
+    public static final String EXTRA_CANCEL = "com.android.documentsui.CANCEL";
+    public static final String EXTRA_SRC_LIST = "com.android.documentsui.SRC_LIST";
+    public static final String EXTRA_DIALOG_TYPE = "com.android.documentsui.DIALOG_TYPE";
+
+    // This extra is used only for moving and deleting. Currently it's not the case,
+    // but in the future those files may be from multiple different parents. In
+    // such case, this needs to be replaced with pairs of parent and child.
+    public static final String EXTRA_SRC_PARENT = "com.android.documentsui.SRC_PARENT";
+
+    public static final int OPERATION_UNKNOWN = -1;
+    public static final int OPERATION_COPY = 1;
+    public static final int OPERATION_MOVE = 2;
+    public static final int OPERATION_DELETE = 3;
+
+    @IntDef(flag = true, value = {
+            OPERATION_UNKNOWN,
+            OPERATION_COPY,
+            OPERATION_MOVE,
+            OPERATION_DELETE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface OpType {}
+
+    // TODO: Move it to a shared file when more operations are implemented.
+    public static final int FAILURE_COPY = 1;
+
+    // The executor and job factory are visible for testing and non-final
+    // so we'll have a way to inject test doubles from the test. It's
+    // a sub-optimal arrangement.
+    @VisibleForTesting ScheduledExecutorService executor;
+    @VisibleForTesting Factory jobFactory;
+
+    private PowerManager mPowerManager;
+    private PowerManager.WakeLock mWakeLock;  // the wake lock, if held.
+    private NotificationManager mNotificationManager;
+
+    @GuardedBy("mRunning")
+    private Map<String, JobRecord> mRunning = new HashMap<>();
+
+    private int mLastServiceId;
+
+    @Override
+    public void onCreate() {
+        // Allow tests to pre-set these with test doubles.
+        if (executor == null) {
+            executor = new ScheduledThreadPoolExecutor(POOL_SIZE);
+        }
+
+        if (jobFactory == null) {
+            jobFactory = Job.Factory.instance;
+        }
+
+        if (DEBUG) Log.d(TAG, "Created.");
+        mPowerManager = getSystemService(PowerManager.class);
+        mNotificationManager = getSystemService(NotificationManager.class);
+    }
+
+    @Override
+    public void onDestroy() {
+        if (DEBUG) Log.d(TAG, "Shutting down executor.");
+        List<Runnable> unfinished = executor.shutdownNow();
+        if (!unfinished.isEmpty()) {
+            Log.w(TAG, "Shutting down, but executor reports running jobs: " + unfinished);
+        }
+        executor = null;
+        if (DEBUG) Log.d(TAG, "Destroyed.");
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int serviceId) {
+        // TODO: Ensure we're not being called with retry or redeliver.
+        // checkArgument(flags == 0);  // retry and redeliver are not supported.
+
+        String jobId = intent.getStringExtra(EXTRA_JOB_ID);
+        @OpType int operationType = intent.getIntExtra(EXTRA_OPERATION, OPERATION_UNKNOWN);
+        checkArgument(jobId != null);
+
+        if (intent.hasExtra(EXTRA_CANCEL)) {
+            handleCancel(intent);
+        } else {
+            checkArgument(operationType != OPERATION_UNKNOWN);
+            handleOperation(intent, serviceId, jobId, operationType);
+        }
+
+        return START_NOT_STICKY;
+    }
+
+    private void handleOperation(Intent intent, int serviceId, String jobId, int operationType) {
+        if (DEBUG) Log.d(TAG, "onStartCommand: " + jobId + " with serviceId " + serviceId);
+
+        // Track the service supplied id so we can stop the service once we're out of work to do.
+        mLastServiceId = serviceId;
+
+        Job job = null;
+        synchronized (mRunning) {
+            if (mWakeLock == null) {
+                mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+            }
+
+            List<DocumentInfo> srcs = intent.getParcelableArrayListExtra(EXTRA_SRC_LIST);
+            DocumentInfo srcParent = intent.getParcelableExtra(EXTRA_SRC_PARENT);
+            DocumentStack stack = intent.getParcelableExtra(Shared.EXTRA_STACK);
+
+            job = createJob(operationType, jobId, srcs, srcParent, stack);
+
+            if (job == null) {
+                return;
+            }
+
+            mWakeLock.acquire();
+        }
+
+        checkState(job != null);
+        int delay = intent.getIntExtra(EXTRA_DELAY, DEFAULT_DELAY);
+        checkArgument(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);
+        mRunning.put(jobId, new JobRecord(job, future));
+    }
+
+    /**
+     * Cancels the operation corresponding to job id, identified in "EXTRA_JOB_ID".
+     *
+     * @param intent The cancellation intent.
+     */
+    private void handleCancel(Intent intent) {
+        checkArgument(intent.hasExtra(EXTRA_CANCEL));
+        String jobId = checkNotNull(intent.getStringExtra(EXTRA_JOB_ID));
+
+        if (DEBUG) Log.d(TAG, "handleCancel: " + jobId);
+
+        synchronized (mRunning) {
+            // Do nothing if the cancelled ID doesn't match the current job ID. This prevents racey
+            // cancellation requests from affecting unrelated copy jobs.  However, if the current job ID
+            // is null, the service most likely crashed and was revived by the incoming cancel intent.
+            // In that case, always allow the cancellation to proceed.
+            JobRecord record = mRunning.get(jobId);
+            if (record != null) {
+                record.job.cancel();
+
+                // If the job hasn't been started, cancel it and explicitly clean up.
+                // If it *has* been started, we wait for it to recognize this, then
+                // allow it stop working in an orderly fashion.
+                if (record.future.getDelay(TimeUnit.MILLISECONDS) > 0) {
+                    record.future.cancel(false);
+                    onFinished(record.job);
+                }
+            }
+        }
+
+        // Dismiss the progress notification here rather than in the copy loop. This preserves
+        // interactivity for the user in case the copy loop is stalled.
+        // Try to cancel it even if we don't have a job id...in case there is some sad
+        // orphan notification.
+        mNotificationManager.cancel(jobId, NOTIFICATION_ID_PROGRESS);
+
+        // TODO: Guarantee the job is being finalized
+    }
+
+    /**
+     * Creates a new job. Returns null if a job with {@code id} already exists.
+     * @return
+     */
+    @GuardedBy("mRunning")
+    private @Nullable Job createJob(
+            @OpType int operationType, String id, List<DocumentInfo> srcs, DocumentInfo srcParent,
+            DocumentStack stack) {
+
+        if (mRunning.containsKey(id)) {
+            Log.w(TAG, "Duplicate job id: " + id
+                    + ". Ignoring job request for srcs: " + srcs + ", stack: " + stack + ".");
+            return null;
+        }
+
+        Job job = null;
+        switch (operationType) {
+            case OPERATION_COPY:
+                job = jobFactory.createCopy(this, getApplicationContext(), this, id, stack, srcs);
+                break;
+            case OPERATION_MOVE:
+                job = jobFactory.createMove(this, getApplicationContext(), this, id, stack, srcs,
+                        srcParent);
+                break;
+            case OPERATION_DELETE:
+                job = jobFactory.createDelete(this, getApplicationContext(), this, id, stack, srcs,
+                        srcParent);
+                break;
+            default:
+                throw new UnsupportedOperationException();
+        }
+
+        return checkNotNull(job);
+    }
+
+    @GuardedBy("mRunning")
+    private void deleteJob(Job job) {
+        if (DEBUG) Log.d(TAG, "deleteJob: " + job.id);
+
+        JobRecord record = mRunning.remove(job.id);
+        checkArgument(record != null);
+        record.job.cleanup();
+
+        if (mRunning.isEmpty()) {
+            shutdown();
+        }
+    }
+
+    /**
+     * Most likely shuts down. Won't shut down if service has a pending
+     * message. Thread pool is deal with in onDestroy.
+     */
+    private void shutdown() {
+        if (DEBUG) Log.d(TAG, "Shutting down. Last serviceId was " + mLastServiceId);
+        mWakeLock.release();
+        mWakeLock = null;
+
+        // Turns out, for us, stopSelfResult always returns false in tests,
+        // so we can't guard executor shutdown. For this reason we move
+        // executor shutdown to #onDestroy.
+        boolean gonnaStop = stopSelfResult(mLastServiceId);
+        if (DEBUG) Log.d(TAG, "Stopping service: " + gonnaStop);
+        if (!gonnaStop) {
+            Log.w(TAG, "Service should be stopping, but reports otherwise.");
+        }
+    }
+
+    @VisibleForTesting
+    boolean holdsWakeLock() {
+        return mWakeLock != null && mWakeLock.isHeld();
+    }
+
+    @Override
+    public void onStart(Job job) {
+        if (DEBUG) Log.d(TAG, "onStart: " + job.id);
+        mNotificationManager.notify(job.id, NOTIFICATION_ID_PROGRESS, job.getSetupNotification());
+    }
+
+    @Override
+    public void onFinished(Job job) {
+        if (DEBUG) Log.d(TAG, "onFinished: " + job.id);
+
+        // Dismiss the ongoing copy notification when the copy is done.
+        mNotificationManager.cancel(job.id, NOTIFICATION_ID_PROGRESS);
+
+        if (job.hasFailures()) {
+            Log.e(TAG, "Job failed on files: " + job.failedFiles.size() + ".");
+            mNotificationManager.notify(
+                job.id, NOTIFICATION_ID_FAILURE, job.getFailureNotification());
+        }
+
+        if (job.hasWarnings()) {
+            if (DEBUG) Log.d(TAG, "Job finished with warnings.");
+            mNotificationManager.notify(
+                    job.id, NOTIFICATION_ID_WARNING, job.getWarningNotification());
+        }
+
+        synchronized (mRunning) {
+            deleteJob(job);
+        }
+    }
+
+    @Override
+    public void onProgress(CopyJob job) {
+        if (DEBUG) Log.d(TAG, "onProgress: " + job.id);
+        mNotificationManager.notify(
+                job.id, NOTIFICATION_ID_PROGRESS, job.getProgressNotification());
+    }
+
+    private static final class JobRecord {
+        private final Job job;
+        private final ScheduledFuture<?> future;
+
+        public JobRecord(Job job, ScheduledFuture<?> future) {
+            this.job = job;
+            this.future = future;
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;  // Boilerplate. See super#onBind
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java
new file mode 100644
index 0000000..9d017ee
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static android.os.SystemClock.elapsedRealtime;
+import static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.Shared.EXTRA_STACK;
+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;
+import static com.android.documentsui.services.FileOperationService.EXTRA_SRC_PARENT;
+import static com.android.documentsui.services.FileOperationService.OPERATION_COPY;
+import static com.android.documentsui.services.FileOperationService.OPERATION_DELETE;
+import static com.android.documentsui.services.FileOperationService.OPERATION_MOVE;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.os.Parcelable;
+import android.support.annotation.VisibleForTesting;
+import android.support.design.widget.Snackbar;
+import android.util.Log;
+
+import com.android.documentsui.R;
+import com.android.documentsui.Snackbars;
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.services.FileOperationService.OpType;
+
+import java.util.List;
+
+/**
+ * Helper functions for starting various file operations.
+ */
+public final class FileOperations {
+
+    private static final String TAG = "FileOperations";
+
+    private static final IdBuilder idBuilder = new IdBuilder();
+
+    private FileOperations() {}
+
+    public static String createJobId() {
+        return idBuilder.getNext();
+    }
+
+    /**
+     * Tries to start the activity. Returns the job id.
+     */
+    public static String start(
+            Activity activity, List<DocumentInfo> srcDocs,
+            DocumentStack stack, int operationType) {
+
+        if (DEBUG) Log.d(TAG, "Handling generic 'start' call.");
+
+        switch (operationType) {
+            case OPERATION_COPY:
+                return FileOperations.copy(activity, srcDocs, stack);
+            case OPERATION_MOVE:
+                throw new IllegalArgumentException("Moving requires providing the source parent.");
+            case OPERATION_DELETE:
+                throw new UnsupportedOperationException("Delete isn't currently supported.");
+            default:
+                throw new UnsupportedOperationException("Unknown operation: " + operationType);
+        }
+    }
+
+    /**
+     * Tries to start the activity. Returns the job id.
+     */
+    public static String start(
+            Activity activity, List<DocumentInfo> srcDocs, DocumentInfo srcParent,
+            DocumentStack stack, int operationType) {
+
+        if (DEBUG) Log.d(TAG, "Handling generic 'start' call.");
+
+        switch (operationType) {
+            case OPERATION_COPY:
+                return FileOperations.copy(activity, srcDocs, stack);
+            case OPERATION_MOVE:
+                return FileOperations.move(activity, srcDocs, srcParent, stack);
+            case OPERATION_DELETE:
+                throw new UnsupportedOperationException("Delete isn't currently supported.");
+            default:
+                throw new UnsupportedOperationException("Unknown operation: " + operationType);
+        }
+    }
+
+    @VisibleForTesting
+    public static void cancel(Activity activity, String jobId) {
+        if (DEBUG) Log.d(TAG, "Attempting to canceling operation: " + jobId);
+
+        Intent intent = new Intent(activity, FileOperationService.class);
+        intent.putExtra(EXTRA_CANCEL, true);
+        intent.putExtra(EXTRA_JOB_ID, jobId);
+
+        activity.startService(intent);
+    }
+
+    @VisibleForTesting
+    public static String copy(
+            Activity activity, List<DocumentInfo> srcDocs, DocumentStack destination) {
+        String jobId = createJobId();
+        if (DEBUG) Log.d(TAG, "Initiating 'copy' operation id: " + jobId);
+
+        Intent intent = createBaseIntent(OPERATION_COPY, activity, jobId, srcDocs, destination);
+
+        createSharedSnackBar(activity, R.plurals.copy_begin, srcDocs.size())
+                .show();
+
+        activity.startService(intent);
+
+        return jobId;
+    }
+
+    /**
+     * Starts the service for a move 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 srcParent Parent of all the source documents.
+     * @param destination The move destination stack.
+     */
+    public static String move(
+            Activity activity, List<DocumentInfo> srcDocs, DocumentInfo srcParent,
+            DocumentStack destination) {
+        String jobId = createJobId();
+        if (DEBUG) Log.d(TAG, "Initiating 'move' operation id: " + jobId);
+
+        Intent intent = createBaseIntent(OPERATION_MOVE, activity, jobId, srcDocs, srcParent,
+                destination);
+
+        createSharedSnackBar(activity, R.plurals.move_begin, srcDocs.size())
+                .show();
+
+        activity.startService(intent);
+
+        return jobId;
+    }
+
+    /**
+     * Starts the service for a move 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 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) {
+        String jobId = createJobId();
+        if (DEBUG) Log.d(TAG, "Initiating 'delete' operation id " + jobId
+                + " delayed by " + delay + " milliseconds.");
+
+        Intent intent = createBaseIntent(OPERATION_DELETE, activity, jobId, srcDocs, srcParent,
+                location);
+        intent.putExtra(EXTRA_DELAY, delay);
+        activity.startService(intent);
+
+        return jobId;
+    }
+
+    /**
+     * Starts the service for an 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.
+     * @return Id of the job.
+     */
+    public static Intent createBaseIntent(
+            @OpType int operationType, Context context, String jobId, List<DocumentInfo> srcDocs,
+            DocumentStack localeStack) {
+
+        Intent intent = new Intent(context, FileOperationService.class);
+        intent.putExtra(EXTRA_JOB_ID, jobId);
+        intent.putParcelableArrayListExtra(EXTRA_SRC_LIST, asArrayList(srcDocs));
+        intent.putExtra(EXTRA_STACK, (Parcelable) localeStack);
+        intent.putExtra(EXTRA_OPERATION, operationType);
+
+        return intent;
+    }
+
+    /**
+     * Starts the service for an 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 srcParent Parent of all the source documents.
+     * @return Id of the job.
+     */
+    public static Intent createBaseIntent(
+            @OpType int operationType, Context context, String jobId,
+            List<DocumentInfo> srcDocs, DocumentInfo srcParent, DocumentStack localeStack) {
+
+        Intent intent = new Intent(context, FileOperationService.class);
+        intent.putExtra(EXTRA_JOB_ID, jobId);
+        intent.putParcelableArrayListExtra(EXTRA_SRC_LIST, asArrayList(srcDocs));
+        intent.putExtra(EXTRA_SRC_PARENT, srcParent);
+        intent.putExtra(EXTRA_STACK, (Parcelable) localeStack);
+        intent.putExtra(EXTRA_OPERATION, operationType);
+
+        return intent;
+    }
+
+    private static Snackbar createSharedSnackBar(Activity activity, int contentId, int fileCount) {
+        Resources res = activity.getResources();
+        return Snackbars.makeSnackbar(
+                activity,
+                getQuantityString(activity, contentId, fileCount),
+                Snackbar.LENGTH_SHORT);
+    }
+
+    private static final class IdBuilder {
+
+        // Remember last job time so we can guard against collisions.
+        private long mLastJobTime;
+
+        // If we detect a collision, use subId to make distinct.
+        private int mSubId;
+
+        public synchronized String getNext() {
+            long time = elapsedRealtime();
+            if (time == mLastJobTime) {
+                mSubId++;
+            } else {
+                mSubId = 0;
+            }
+            mLastJobTime = time;
+            return String.valueOf(mLastJobTime) + "-" + String.valueOf(mSubId);
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
new file mode 100644
index 0000000..7b8011a
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static com.android.documentsui.DocumentsApplication.acquireUnstableProviderOrThrow;
+import static com.android.documentsui.services.FileOperationService.EXTRA_CANCEL;
+import static com.android.documentsui.services.FileOperationService.EXTRA_DIALOG_TYPE;
+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;
+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;
+import android.app.Notification;
+import android.app.Notification.Builder;
+import android.app.PendingIntent;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.provider.DocumentsContract;
+import android.util.Log;
+
+import com.android.documentsui.FilesActivity;
+import com.android.documentsui.OperationDialogFragment;
+import com.android.documentsui.R;
+import com.android.documentsui.Shared;
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.services.FileOperationService.OpType;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A mashup of work item and ui progress update factory. Used by {@link FileOperationService}
+ * to do work and show progress relating to this work.
+ */
+abstract public class Job implements Runnable {
+    private static final String TAG = "Job";
+    final Context service;
+    final Context appContext;
+    final Listener listener;
+
+    final @OpType int operationType;
+    final String id;
+    final DocumentStack stack;
+
+    final ArrayList<DocumentInfo> failedFiles = new ArrayList<>();
+    final Notification.Builder mProgressBuilder;
+
+    private final Map<String, ContentProviderClient> mClients = new HashMap<>();
+    private volatile boolean mCanceled;
+
+    /**
+     * A simple progressable job, much like an AsyncTask, but with support
+     * for providing various related notification, progress and navigation information.
+     * @param operationType
+     *
+     * @param service The service context in which this job is running.
+     * @param appContext The context of the invoking application. This is usually
+     *     just {@code getApplicationContext()}.
+     * @param listener
+     * @param id Arbitrary string ID
+     * @param stack The documents stack context relating to this request. This is the
+     *     destination in the Files app where the user will be take when the
+     *     navigation intent is invoked (presumably from notification).
+     */
+    Job(Context service, Context appContext, Listener listener,
+            @OpType int operationType, String id, DocumentStack stack) {
+
+        checkArgument(operationType != OPERATION_UNKNOWN);
+
+        this.service = service;
+        this.appContext = appContext;
+        this.listener = listener;
+        this.operationType = operationType;
+
+        this.id = id;
+        this.stack = stack;
+
+        mProgressBuilder = createProgressBuilder();
+    }
+
+    @Override
+    public final void run() {
+        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);
+        } finally {
+            listener.onFinished(this);
+        }
+    }
+
+    abstract void start() throws RemoteException;
+
+    abstract Notification getSetupNotification();
+    // TODO: Progress notification for deletes.
+    // abstract Notification getProgressNotification(long bytesCopied);
+    abstract Notification getFailureNotification();
+
+    abstract Notification getWarningNotification();
+
+    ContentProviderClient getClient(DocumentInfo doc) throws RemoteException {
+        ContentProviderClient client = mClients.get(doc.authority);
+        if (client == null) {
+            // Acquire content providers.
+            client = acquireUnstableProviderOrThrow(
+                    getContentResolver(),
+                    doc.authority);
+
+            mClients.put(doc.authority, client);
+        }
+
+        return checkNotNull(client);
+    }
+
+    final void cleanup() {
+        for (ContentProviderClient client : mClients.values()) {
+            ContentProviderClient.releaseQuietly(client);
+        }
+    }
+
+    final void cancel() {
+        mCanceled = true;
+    }
+
+    final boolean isCanceled() {
+        return mCanceled;
+    }
+
+    final ContentResolver getContentResolver() {
+        return service.getContentResolver();
+    }
+
+    void onFileFailed(DocumentInfo file) {
+        failedFiles.add(file);
+    }
+
+    final boolean hasFailures() {
+        return !failedFiles.isEmpty();
+    }
+
+    boolean hasWarnings() {
+        return false;
+    }
+
+    final boolean deleteDocument(DocumentInfo doc) {
+        try {
+            DocumentsContract.deleteDocument(getClient(doc), doc.derivedUri);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to delete file: " + doc.derivedUri, e);
+            return false;
+        }
+
+        return true;  // victory dance!
+    }
+
+    Notification getSetupNotification(String content) {
+        mProgressBuilder.setProgress(0, 0, true);
+        mProgressBuilder.setContentText(content);
+        return mProgressBuilder.build();
+    }
+
+    Notification getFailureNotification(@PluralsRes int titleId, @DrawableRes int icon) {
+        final Intent navigateIntent = buildNavigateIntent();
+        navigateIntent.putExtra(EXTRA_DIALOG_TYPE, OperationDialogFragment.DIALOG_TYPE_FAILURE);
+        navigateIntent.putExtra(EXTRA_OPERATION, operationType);
+
+        navigateIntent.putParcelableArrayListExtra(EXTRA_SRC_LIST, failedFiles);
+
+        final Notification.Builder errorBuilder = new Notification.Builder(service)
+                .setContentTitle(service.getResources().getQuantityString(titleId,
+                        failedFiles.size(), failedFiles.size()))
+                .setContentText(service.getString(R.string.notification_touch_for_details))
+                .setContentIntent(PendingIntent.getActivity(appContext, 0, navigateIntent,
+                        PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT))
+                .setCategory(Notification.CATEGORY_ERROR)
+                .setSmallIcon(icon)
+                .setAutoCancel(true);
+        return errorBuilder.build();
+    }
+
+    abstract Builder createProgressBuilder();
+
+    final Builder createProgressBuilder(
+            String title, @DrawableRes int icon,
+            String actionTitle, @DrawableRes int actionIcon) {
+        Notification.Builder progressBuilder = new Notification.Builder(service)
+                .setContentTitle(title)
+                .setContentIntent(
+                        PendingIntent.getActivity(appContext, 0, buildNavigateIntent(), 0))
+                .setCategory(Notification.CATEGORY_PROGRESS)
+                .setSmallIcon(icon)
+                .setOngoing(true);
+
+        final Intent cancelIntent = createCancelIntent();
+
+        progressBuilder.addAction(
+                actionIcon,
+                actionTitle,
+                PendingIntent.getService(
+                        service,
+                        0,
+                        cancelIntent,
+                        PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT));
+
+        return progressBuilder;
+    }
+
+    /**
+     * Creates an intent for navigating back to the destination directory.
+     */
+    Intent buildNavigateIntent() {
+        Intent intent = new Intent(service, FilesActivity.class);
+        intent.setAction(DocumentsContract.ACTION_BROWSE);
+        intent.putExtra(Shared.EXTRA_STACK, (Parcelable) stack);
+        return intent;
+    }
+
+    Intent createCancelIntent() {
+        final Intent cancelIntent = new Intent(service, FileOperationService.class);
+        cancelIntent.putExtra(EXTRA_CANCEL, true);
+        cancelIntent.putExtra(EXTRA_JOB_ID, id);
+        return cancelIntent;
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder()
+                .append("Job")
+                .append("{")
+                .append("id=" + id)
+                .append("}")
+                .toString();
+    }
+
+    /**
+     * Factory class that facilitates our testing FileOperationService.
+     */
+    static class Factory {
+
+        static final Factory instance = new Factory();
+
+        Job createCopy(Context service, Context appContext, Listener listener,
+                String id, DocumentStack stack, List<DocumentInfo> srcs) {
+            return new CopyJob(service, appContext, listener, id, stack, srcs);
+        }
+
+        Job createMove(Context service, Context appContext, Listener listener,
+                String id, DocumentStack stack, List<DocumentInfo> srcs,
+                DocumentInfo srcParent) {
+            return new MoveJob(service, appContext, listener, id, stack, srcs, srcParent);
+        }
+
+        Job createDelete(Context service, Context appContext, Listener listener,
+                String id, DocumentStack stack, List<DocumentInfo> srcs,
+                DocumentInfo srcParent) {
+            return new DeleteJob(service, appContext, listener, id, stack, srcs, srcParent);
+        }
+    }
+
+    /**
+     * Listener interface employed by the service that owns us as well as tests.
+     */
+    interface Listener {
+        void onStart(Job job);
+        void onFinished(Job job);
+        void onProgress(CopyJob job);
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
new file mode 100644
index 0000000..9b72077
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.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.documentsui.services;
+
+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;
+import android.util.Log;
+
+import com.android.documentsui.R;
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+
+import java.util.List;
+
+// TODO: Stop extending CopyJob.
+final class MoveJob extends CopyJob {
+
+    private static final String TAG = "MoveJob";
+    final DocumentInfo mSrcParent;
+
+    /**
+     * Moves files to a destination identified by {@code destination}.
+     * Performs most work by delegating to CopyJob, then deleting
+     * a file after it has been copied.
+     *
+     * @see @link {@link Job} constructor for most param descriptions.
+     *
+     * @param srcs List of files to be moved.
+     * @param srcParent Parent of all source files.
+     */
+    MoveJob(Context service, Context appContext, Listener listener,
+            String id, DocumentStack destination, List<DocumentInfo> srcs, DocumentInfo srcParent) {
+        super(service, appContext, listener, OPERATION_MOVE, id, destination, srcs);
+        this.mSrcParent = srcParent;
+    }
+
+    @Override
+    Builder createProgressBuilder() {
+        return super.createProgressBuilder(
+                service.getString(R.string.move_notification_title),
+                R.drawable.ic_menu_copy,
+                service.getString(android.R.string.cancel),
+                R.drawable.ic_cab_cancel);
+    }
+
+    @Override
+    public Notification getSetupNotification() {
+        return getSetupNotification(service.getString(R.string.move_preparing));
+    }
+
+    @Override
+    public Notification getProgressNotification() {
+        return getProgressNotification(R.string.copy_preparing);
+    }
+
+    @Override
+    Notification getFailureNotification() {
+        return getFailureNotification(
+                R.plurals.move_error_notification_title, R.drawable.ic_menu_copy);
+    }
+
+    boolean processDocument(DocumentInfo src, DocumentInfo srcParent, DocumentInfo dest)
+            throws RemoteException {
+
+        // TODO: When optimized move kicks in, we're not making any progress updates. FIX IT!
+
+        // When moving within the same provider, try to use optimized moving.
+        // 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;
+                }
+                return true;
+            }
+        }
+
+        // Moving virtual files by bytes is not supported. This is because, it would involve
+        // 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;
+        }
+
+        // If we couldn't do an optimized copy...we fall back to vanilla byte copy.
+        boolean copied = byteCopyDocument(src, dest);
+
+        // TODO: Replace deleteDocument() with removeDocument() once implemented.
+        return copied && !isCanceled() && deleteDocument(src);
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder()
+                .append("MoveJob")
+                .append("{")
+                .append("id=" + id)
+                .append(", srcs=" + mSrcs)
+                .append(", srcParent=" + mSrcParent)
+                .append(", destination=" + stack)
+                .append("}")
+                .toString();
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/CopyServiceTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/CopyServiceTest.java
deleted file mode 100644
index 079d599..0000000
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/CopyServiceTest.java
+++ /dev/null
@@ -1,551 +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 android.content.ContentProviderClient;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.content.Intent;
-import android.content.pm.ProviderInfo;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.provider.DocumentsContract;
-import android.test.MoreAsserts;
-import android.test.ServiceTestCase;
-import android.test.mock.MockContentResolver;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.util.Log;
-
-import com.android.documentsui.model.DocumentInfo;
-import com.android.documentsui.model.DocumentStack;
-import com.android.documentsui.model.RootInfo;
-
-import com.google.common.collect.Lists;
-
-import libcore.io.IoUtils;
-import libcore.io.Streams;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-@MediumTest
-public class CopyServiceTest extends ServiceTestCase<CopyService> {
-
-    public CopyServiceTest() {
-        super(CopyService.class);
-    }
-
-    private static String AUTHORITY = "com.android.documentsui.stubprovider";
-    private static String SRC_ROOT = StubProvider.ROOT_0_ID;
-    private static String DST_ROOT = StubProvider.ROOT_1_ID;
-    private static String TAG = "CopyTest";
-
-    private Context mContext;
-    private TestContentResolver mResolver;
-    private ContentProviderClient mClient;
-    private DocumentsProviderHelper mDocHelper;
-    private StubProvider mStorage;
-    private Context mSystemContext;
-    private CopyJobListener mListener;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mListener = new CopyJobListener();
-        setupTestContext();
-        mClient = mResolver.acquireContentProviderClient(AUTHORITY);
-
-        // Reset the stub provider's storage.
-        mStorage.clearCacheAndBuildRoots();
-
-        mDocHelper = new DocumentsProviderHelper(AUTHORITY, mClient);
-
-        assertDestFileCount(0);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        mClient.release();
-        super.tearDown();
-    }
-
-    public void testCopyFile() throws Exception {
-        String srcPath = "/test0.txt";
-        Uri testFile = mStorage.createFile(SRC_ROOT, srcPath, "text/plain",
-                "The five boxing wizards jump quickly".getBytes());
-
-        startService(createCopyIntent(Lists.newArrayList(testFile)));
-
-        // 2 operations: file creation, then writing data.
-        mResolver.waitForChanges(2);
-
-        // Verify that one file was copied; check file contents.
-        assertDestFileCount(1);
-        assertCopied(srcPath);
-    }
-
-    public void testMoveFile() throws Exception {
-        String srcPath = "/test0.txt";
-        String testContent = "The five boxing wizards jump quickly";
-        Uri testFile = mStorage.createFile(SRC_ROOT, srcPath, "text/plain", testContent.getBytes());
-
-        Intent moveIntent = createCopyIntent(Lists.newArrayList(testFile));
-        moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE);
-        startService(moveIntent);
-
-        // 3 operations: file creation, writing data, deleting original.
-        mResolver.waitForChanges(3);
-
-        // Verify that one file was moved; check file contents.
-        assertDestFileCount(1);
-        assertDoesNotExist(SRC_ROOT, srcPath);
-
-        byte[] dstContent = readFile(DST_ROOT, srcPath);
-        MoreAsserts.assertEquals("Moved file contents differ", testContent.getBytes(), dstContent);
-    }
-
-    public void testCopyMultipleFiles() throws Exception {
-        String testContent[] = {
-                "The five boxing wizards jump quickly",
-                "The quick brown fox jumps over the lazy dog",
-                "Jackdaws love my big sphinx of quartz"
-        };
-        String srcPaths[] = {
-                "/test0.txt",
-                "/test1.txt",
-                "/test2.txt"
-        };
-        List<Uri> testFiles = Lists.newArrayList(
-                mStorage.createFile(SRC_ROOT, srcPaths[0], "text/plain", testContent[0].getBytes()),
-                mStorage.createFile(SRC_ROOT, srcPaths[1], "text/plain", testContent[1].getBytes()),
-                mStorage.createFile(SRC_ROOT, srcPaths[2], "text/plain", testContent[2].getBytes()));
-
-        // Copy all the test files.
-        startService(createCopyIntent(testFiles));
-
-        // 3 file creations, 3 file writes.
-        mResolver.waitForChanges(6);
-
-        assertDestFileCount(3);
-        for (String path : srcPaths) {
-            assertCopied(path);
-        }
-    }
-
-    public void testCopyEmptyDir() throws Exception {
-        String srcPath = "/emptyDir";
-        Uri testDir = createTestDirectory(srcPath);
-
-        startService(createCopyIntent(Lists.newArrayList(testDir)));
-
-        // Just 1 operation: Directory creation.
-        mResolver.waitForChanges(1);
-
-        assertDestFileCount(1);
-
-        // Verify that the dst exists and is a directory.
-        File dst = mStorage.getFile(DST_ROOT, srcPath);
-        assertTrue(dst.isDirectory());
-    }
-
-    public void testNoCopyDirToSelf() throws Exception {
-        Uri testDir = createTestDirectory("/someDir");
-
-        Intent intent = createCopyIntent(Lists.newArrayList(testDir), testDir);
-        startService(intent);
-
-        getService().addFinishedListener(mListener);
-
-        mListener.waitForFinished();
-        mListener.assertFailedCount(1);
-        mListener.assertFileFailed("someDir");
-
-        assertDestFileCount(0);
-    }
-
-    public void testNoCopyDirToDescendent() throws Exception {
-        Uri testDir = createTestDirectory("/someDir");
-        Uri descDir = createTestDirectory("/someDir/theDescendent");
-
-        Intent intent = createCopyIntent(Lists.newArrayList(testDir), descDir);
-        startService(intent);
-
-        getService().addFinishedListener(mListener);
-
-        mListener.waitForFinished();
-        mListener.assertFailedCount(1);
-        mListener.assertFileFailed("someDir");
-
-        assertDestFileCount(0);
-    }
-
-    public void testMoveEmptyDir() throws Exception {
-        String srcPath = "/emptyDir";
-        Uri testDir = createTestDirectory(srcPath);
-
-        Intent moveIntent = createCopyIntent(Lists.newArrayList(testDir));
-        moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE);
-        startService(moveIntent);
-
-        // 2 operations: Directory creation, and removal of the original.
-        mResolver.waitForChanges(2);
-
-        assertDestFileCount(1);
-
-        // Verify that the dst exists and is a directory.
-        File dst = mStorage.getFile(DST_ROOT, srcPath);
-        assertTrue(dst.isDirectory());
-
-        // Verify that the src was cleaned up.
-        assertDoesNotExist(SRC_ROOT, srcPath);
-    }
-
-    public void testMovePopulatedDir() throws Exception {
-        String testContent[] = {
-                "The five boxing wizards jump quickly",
-                "The quick brown fox jumps over the lazy dog",
-                "Jackdaws love my big sphinx of quartz"
-        };
-        String srcDir = "/testdir";
-        String srcFiles[] = {
-                srcDir + "/test0.txt",
-                srcDir + "/test1.txt",
-                srcDir + "/test2.txt"
-        };
-        // Create test dir; put some files in it.
-        Uri testDir = createTestDirectory(srcDir);
-        mStorage.createFile(SRC_ROOT, srcFiles[0], "text/plain", testContent[0].getBytes());
-        mStorage.createFile(SRC_ROOT, srcFiles[1], "text/plain", testContent[1].getBytes());
-        mStorage.createFile(SRC_ROOT, srcFiles[2], "text/plain", testContent[2].getBytes());
-
-        Intent moveIntent = createCopyIntent(Lists.newArrayList(testDir));
-        moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE);
-        startService(moveIntent);
-
-        // dir creation, then creation and writing of 3 files, then removal of src dir and 3 src
-        // files.
-        mResolver.waitForChanges(11);
-
-        // Check the content of the moved files.
-        File dst = mStorage.getFile(DST_ROOT, srcDir);
-        assertTrue(dst.isDirectory());
-        for (int i = 0; i < testContent.length; ++i) {
-            byte[] dstContent = readFile(DST_ROOT, srcFiles[i]);
-            MoreAsserts.assertEquals("Copied file contents differ", testContent[i].getBytes(),
-                    dstContent);
-        }
-
-        // Check that the src files were removed.
-        assertDoesNotExist(SRC_ROOT, srcDir);
-        for (String srcFile : srcFiles) {
-            assertDoesNotExist(SRC_ROOT, srcFile);
-        }
-    }
-
-    public void testCopyFileWithReadErrors() throws Exception {
-        String srcPath = "/test0.txt";
-        Uri testFile = mStorage.createFile(SRC_ROOT, srcPath, "text/plain",
-                "The five boxing wizards jump quickly".getBytes());
-
-        mStorage.simulateReadErrorsForFile(testFile);
-
-        startService(createCopyIntent(Lists.newArrayList(testFile)));
-
-        // 3 operations: file creation, writing, then deletion (due to failed copy).
-        mResolver.waitForChanges(3);
-
-        // Verify that the failed copy was cleaned up.
-        assertDestFileCount(0);
-    }
-
-    public void testMoveFileWithReadErrors() throws Exception {
-        String srcPath = "/test0.txt";
-        Uri testFile = mStorage.createFile(SRC_ROOT, srcPath, "text/plain",
-                "The five boxing wizards jump quickly".getBytes());
-
-        mStorage.simulateReadErrorsForFile(testFile);
-
-        Intent moveIntent = createCopyIntent(Lists.newArrayList(testFile));
-        moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE);
-        startService(moveIntent);
-
-        try {
-            // There should be 3 operations: file creation, writing, then deletion (due to failed
-            // copy). Wait for 4, in case the CopyService also attempts to do extra stuff (like
-            // delete the src file). This should time out.
-            mResolver.waitForChanges(4);
-        } catch (TimeoutException e) {
-            // Success path
-            return;
-        } finally {
-            // Verify that the failed copy was cleaned up, and the src file wasn't removed.
-            assertDestFileCount(0);
-            assertExists(SRC_ROOT, srcPath);
-        }
-        // The asserts above didn't fail, but the CopyService did something unexpected.
-        fail("Extra file operations were detected");
-    }
-
-    public void testMoveDirectoryWithReadErrors() throws Exception {
-        String testContent[] = {
-                "The five boxing wizards jump quickly",
-                "The quick brown fox jumps over the lazy dog",
-                "Jackdaws love my big sphinx of quartz"
-        };
-        String srcDir = "/testdir";
-        String srcFiles[] = {
-                srcDir + "/test0.txt",
-                srcDir + "/test1.txt",
-                srcDir + "/test2.txt"
-        };
-        // Create test dir; put some files in it.
-        Uri testDir = createTestDirectory(srcDir);
-        mStorage.createFile(SRC_ROOT, srcFiles[0], "text/plain", testContent[0].getBytes());
-        Uri errFile = mStorage
-                .createFile(SRC_ROOT, srcFiles[1], "text/plain", testContent[1].getBytes());
-        mStorage.createFile(SRC_ROOT, srcFiles[2], "text/plain", testContent[2].getBytes());
-
-        mStorage.simulateReadErrorsForFile(errFile);
-
-        Intent moveIntent = createCopyIntent(Lists.newArrayList(testDir));
-        moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE);
-        startService(moveIntent);
-
-        // - dst dir creation,
-        // - creation and writing of 2 files, removal of 2 src files
-        // - creation and writing of 1 file, then removal of that file (due to error)
-        mResolver.waitForChanges(10);
-
-        // Check that both the src and dst dirs exist. The src dir shouldn't have been removed,
-        // because it should contain the one errFile.
-        assertTrue(mStorage.getFile(SRC_ROOT, srcDir).isDirectory());
-        assertTrue(mStorage.getFile(DST_ROOT, srcDir).isDirectory());
-
-        // Check the content of the moved files.
-        MoreAsserts.assertEquals("Copied file contents differ", testContent[0].getBytes(),
-                readFile(DST_ROOT, srcFiles[0]));
-        MoreAsserts.assertEquals("Copied file contents differ", testContent[2].getBytes(),
-                readFile(DST_ROOT, srcFiles[2]));
-
-        // Check that the src files were removed.
-        assertDoesNotExist(SRC_ROOT, srcFiles[0]);
-        assertDoesNotExist(SRC_ROOT, srcFiles[2]);
-
-        // Check that the error file was not copied over.
-        assertDoesNotExist(DST_ROOT, srcFiles[1]);
-        assertExists(SRC_ROOT, srcFiles[1]);
-    }
-
-    private Uri createTestDirectory(String dir) throws IOException {
-        return mStorage.createFile(
-                SRC_ROOT, dir, DocumentsContract.Document.MIME_TYPE_DIR, null);
-    }
-
-    private Intent createCopyIntent(List<Uri> srcs) throws Exception {
-        RootInfo root = mDocHelper.getRoot(DST_ROOT);
-        final Uri dst = DocumentsContract.buildDocumentUri(AUTHORITY, root.documentId);
-
-        return createCopyIntent(srcs, dst);
-    }
-
-    private Intent createCopyIntent(List<Uri> srcs, Uri dst) throws Exception {
-        final ArrayList<DocumentInfo> srcDocs = Lists.newArrayList();
-        for (Uri src : srcs) {
-            srcDocs.add(DocumentInfo.fromUri(mResolver, src));
-        }
-
-        DocumentStack stack = new DocumentStack();
-        stack.push(DocumentInfo.fromUri(mResolver, dst));
-        final Intent copyIntent = new Intent(mContext, CopyService.class);
-        copyIntent.putParcelableArrayListExtra(CopyService.EXTRA_SRC_LIST, srcDocs);
-        copyIntent.putExtra(Shared.EXTRA_STACK, (Parcelable) stack);
-
-        return copyIntent;
-    }
-
-    /**
-     * Returns a count of the files in the given directory.
-     */
-    private void assertDestFileCount(int expected) throws RemoteException {
-        RootInfo dest = mDocHelper.getRoot(DST_ROOT);
-        final Uri queryUri = DocumentsContract.buildChildDocumentsUri(AUTHORITY,
-                dest.documentId);
-        Cursor c = null;
-        int count = 0;
-        try {
-            c = mClient.query(queryUri, null, null, null, null);
-            count = c.getCount();
-        } finally {
-            IoUtils.closeQuietly(c);
-        }
-        assertEquals("Incorrect file count after copy", expected, count);
-    }
-
-    private void assertExists(String rootId, String path) throws Exception {
-        assertNotNull("An expected file was not found: " + path + " on root " + rootId,
-                mStorage.getFile(rootId, path));
-    }
-
-    private void assertDoesNotExist(String rootId, String path) throws Exception {
-        assertNull("Unexpected file found: " + path + " on root " + rootId,
-                mStorage.getFile(rootId, path));
-    }
-
-    private byte[] readFile(String rootId, String path) throws Exception {
-        File file = mStorage.getFile(rootId, path);
-        byte[] buf = null;
-        assertNotNull(file);
-
-        FileInputStream in = null;
-        try {
-            in = new FileInputStream(file);
-            buf = Streams.readFully(in);
-        } finally {
-            IoUtils.closeQuietly(in);
-        }
-        return buf;
-    }
-
-    private void assertCopied(String path) throws Exception {
-        MoreAsserts.assertEquals("Copied file contents differ", readFile(SRC_ROOT, path),
-                readFile(DST_ROOT, path));
-    }
-
-    /**
-     * Sets up a ContextWrapper that substitutes a stub NotificationManager. This allows the test to
-     * listen for notification events, to gauge copy progress.
-     *
-     * @throws FileNotFoundException
-     */
-    private void setupTestContext() throws FileNotFoundException {
-        mSystemContext = getSystemContext();
-
-        // Set up the context with the test content resolver.
-        mResolver = new TestContentResolver();
-        mContext = new ContextWrapper(mSystemContext) {
-            @Override
-            public ContentResolver getContentResolver() {
-                return mResolver;
-            }
-        };
-        setContext(mContext);
-
-        // Create a local stub provider and add it to the content resolver.
-        ProviderInfo info = new ProviderInfo();
-        info.authority = AUTHORITY;
-        info.exported = true;
-        info.grantUriPermissions = true;
-        info.readPermission = android.Manifest.permission.MANAGE_DOCUMENTS;
-        info.writePermission = android.Manifest.permission.MANAGE_DOCUMENTS;
-
-        mStorage = new StubProvider();
-        mStorage.attachInfo(mContext, info);
-        mResolver.addProvider(AUTHORITY, mStorage);
-    }
-
-    private final class CopyJobListener implements CopyService.TestOnlyListener {
-
-        final CountDownLatch latch = new CountDownLatch(1);
-        final List<DocumentInfo> failedDocs = new ArrayList<>();
-        @Override
-        public void onFinished(List<DocumentInfo> failed) {
-            failedDocs.addAll(failed);
-            latch.countDown();
-        }
-
-        public void assertFileFailed(String expectedName) {
-            for (DocumentInfo failed : failedDocs) {
-                if (expectedName.equals(failed.displayName)) {
-                    return;
-                }
-            }
-            fail("Couldn't find failed file: " + expectedName);
-        }
-
-        public void waitForFinished() throws InterruptedException {
-            latch.await(500, TimeUnit.MILLISECONDS);
-        }
-
-        public void assertFailedCount(int expected) {
-            assertEquals(expected, failedDocs.size());
-        }
-    }
-
-    /**
-     * A test resolver that enables this test suite to listen for notifications that mark when copy
-     * operations are done.
-     */
-    class TestContentResolver extends MockContentResolver {
-        private CountDownLatch mReadySignal;
-        private CountDownLatch mNotificationSignal;
-
-        public TestContentResolver() {
-            mReadySignal = new CountDownLatch(1);
-        }
-
-        /**
-         * Wait for the given number of files to be copied to destination. Times out after 1 sec.
-         */
-        public void waitForChanges(int count) throws Exception {
-            // Wait for no more than 1 second by default.
-            waitForChanges(count, 1000);
-        }
-
-        /**
-         * Wait for files to be copied to destination.
-         *
-         * @param count Number of files to wait for.
-         * @param timeOut Timeout in ms. TimeoutException will be thrown if this function times out.
-         */
-        public void waitForChanges(int count, int timeOut) throws Exception {
-            mNotificationSignal = new CountDownLatch(count);
-            // Signal that the test is now waiting for files.
-            mReadySignal.countDown();
-            if (!mNotificationSignal.await(timeOut, TimeUnit.MILLISECONDS)) {
-                throw new TimeoutException("Timed out waiting for file operations to complete.");
-            }
-        }
-
-        @Override
-        public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
-            // Wait until the test is ready to receive file notifications.
-            try {
-                mReadySignal.await();
-            } catch (InterruptedException e) {
-                Log.d(TAG, "Interrupted while waiting for file copy readiness");
-                Thread.currentThread().interrupt();
-            }
-            if (DocumentsContract.isDocumentUri(mContext, uri)) {
-                Log.d(TAG, "Notification: " + uri);
-                // Watch for document URI change notifications - this signifies the end of a copy.
-                mNotificationSignal.countDown();
-            }
-        }
-    };
-}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/DocumentsProviderHelper.java b/packages/DocumentsUI/tests/src/com/android/documentsui/DocumentsProviderHelper.java
index 7abc99c..467d97e 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/DocumentsProviderHelper.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/DocumentsProviderHelper.java
@@ -16,47 +16,69 @@
 
 package com.android.documentsui;
 
+import static android.provider.DocumentsContract.buildChildDocumentsUri;
+import static android.provider.DocumentsContract.buildDocumentUri;
+import static android.provider.DocumentsContract.buildRootsUri;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
+import static com.android.internal.util.Preconditions.checkArgument;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.fail;
 
 import android.content.ContentProviderClient;
 import android.database.Cursor;
 import android.net.Uri;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.ParcelFileDescriptor.AutoCloseInputStream;
+import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
 import android.os.RemoteException;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsContract.Root;
+import android.support.annotation.Nullable;
+import android.test.MoreAsserts;
+import android.text.TextUtils;
 
+import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.RootInfo;
 
+import com.google.android.collect.Lists;
+
 import libcore.io.IoUtils;
+import libcore.io.Streams;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Provides support for creation of documents in a test settings.
  */
 public class DocumentsProviderHelper {
 
-    private final ContentProviderClient mClient;
     private final String mAuthority;
+    private final ContentProviderClient mClient;
 
     public DocumentsProviderHelper(String authority, ContentProviderClient client) {
-        mClient = client;
+        checkArgument(!TextUtils.isEmpty(authority));
         mAuthority = authority;
+        mClient = client;
     }
 
-    public RootInfo getRoot(String id) throws RemoteException {
-        final Uri rootsUri = DocumentsContract.buildRootsUri(mAuthority);
-
+    public RootInfo getRoot(String documentId) throws RemoteException {
+        final Uri rootsUri = buildRootsUri(mAuthority);
         Cursor cursor = null;
         try {
             cursor = mClient.query(rootsUri, null, null, null, null);
             while (cursor.moveToNext()) {
-                if (id.equals(getCursorString(cursor, Root.COLUMN_ROOT_ID))) {
+                if (documentId.equals(getCursorString(cursor, Root.COLUMN_ROOT_ID))) {
                     return RootInfo.fromRootsCursor(mAuthority, cursor);
                 }
             }
-            throw new IllegalArgumentException("Can't find matching root for id=" + id);
+            throw new IllegalArgumentException("Can't find matching root for id=" + documentId);
         } catch (Exception e) {
-            throw new RuntimeException("Can't load root for id=" + id , e);
+            throw new RuntimeException("Can't load root for id=" + documentId , e);
         } finally {
             IoUtils.closeQuietly(cursor);
         }
@@ -67,22 +89,201 @@
             throw new IllegalArgumentException("Name and mimetype probably interposed.");
         }
         try {
-            return DocumentsContract.createDocument(mClient, parentUri, mimeType, name);
+            Uri uri = DocumentsContract.createDocument(mClient, parentUri, mimeType, name);
+            return uri;
         } catch (RemoteException e) {
             throw new RuntimeException("Couldn't create document: " + name + " with mimetype " + mimeType, e);
         }
     }
 
+    public Uri createDocument(String parentId, String mimeType, String name) {
+        Uri parentUri = buildDocumentUri(mAuthority, parentId);
+        return createDocument(parentUri, mimeType, name);
+    }
+
+    public Uri createDocument(RootInfo root, String mimeType, String name) {
+        return createDocument(root.documentId, mimeType, name);
+    }
+
     public Uri createFolder(Uri parentUri, String name) {
         return createDocument(parentUri, Document.MIME_TYPE_DIR, name);
     }
 
-    public Uri createDocument(RootInfo root, String mimeType, String name) {
-        Uri rootUri = DocumentsContract.buildDocumentUri(mAuthority, root.documentId);
-        return createDocument(rootUri, mimeType, name);
+    public Uri createFolder(String parentId, String name) {
+        Uri parentUri = buildDocumentUri(mAuthority, parentId);
+        return createDocument(parentUri, Document.MIME_TYPE_DIR, name);
     }
 
     public Uri createFolder(RootInfo root, String name) {
         return createDocument(root, Document.MIME_TYPE_DIR, name);
     }
+
+    public void writeDocument(Uri documentUri, byte[] contents)
+            throws RemoteException, IOException {
+        ParcelFileDescriptor file = mClient.openFile(documentUri, "w", null);
+        try (AutoCloseOutputStream out = new AutoCloseOutputStream(file)) {
+            out.write(contents, 0, contents.length);
+        }
+    }
+
+    public byte[] readDocument(Uri documentUri) throws RemoteException, IOException {
+        ParcelFileDescriptor file = mClient.openFile(documentUri, "r", null);
+        byte[] buf = null;
+        try (AutoCloseInputStream in = new AutoCloseInputStream(file)) {
+            buf = Streams.readFully(in);
+        }
+        return buf;
+    }
+
+    public void assertChildCount(Uri parentUri, int expected) throws Exception {
+        List<DocumentInfo> children = listChildren(parentUri);
+        assertEquals("Incorrect file count after copy", expected, children.size());
+    }
+
+    public void assertChildCount(String parentId, int expected) throws Exception {
+        List<DocumentInfo> children = listChildren(parentId);
+        assertEquals("Incorrect file count after copy", expected, children.size());
+    }
+
+    public void assertChildCount(RootInfo root, int expected) throws Exception {
+        assertChildCount(root.documentId, expected);
+    }
+
+    public void assertHasFile(Uri parentUri, String name) throws Exception {
+        List<DocumentInfo> children = listChildren(parentUri);
+        for (DocumentInfo child : children) {
+            if (name.equals(child.displayName) && !child.isDirectory()) {
+                return;
+            }
+        }
+        fail("Could not find file named=" + name + " in children " + children);
+    }
+
+    public void assertHasFile(String parentId, String name) throws Exception {
+        Uri parentUri = buildDocumentUri(mAuthority, parentId);
+        assertHasFile(parentUri, name);
+    }
+
+    public void assertHasFile(RootInfo root, String name) throws Exception {
+        assertHasFile(root.documentId, name);
+    }
+
+    public void assertHasDirectory(Uri parentUri, String name) throws Exception {
+        List<DocumentInfo> children = listChildren(parentUri);
+        for (DocumentInfo child : children) {
+            if (name.equals(child.displayName) && child.isDirectory()) {
+                return;
+            }
+        }
+        fail("Could not find name=" + name + " in children " + children);
+    }
+
+    public void assertHasDirectory(String parentId, String name) throws Exception {
+        Uri parentUri = buildDocumentUri(mAuthority, parentId);
+        assertHasDirectory(parentUri, name);
+    }
+
+    public void assertHasDirectory(RootInfo root, String name) throws Exception {
+        assertHasDirectory(root.documentId, name);
+    }
+
+    public void assertDoesNotExist(Uri parentUri, String name) throws Exception {
+        List<DocumentInfo> children = listChildren(parentUri);
+        for (DocumentInfo child : children) {
+            if (name.equals(child.displayName)) {
+                fail("Found name=" + name + " in children " + children);
+            }
+        }
+    }
+
+    public void assertDoesNotExist(String parentId, String name) throws Exception {
+        Uri parentUri = buildDocumentUri(mAuthority, parentId);
+        assertDoesNotExist(parentUri, name);
+    }
+
+    public void assertDoesNotExist(RootInfo root, String name) throws Exception {
+        assertDoesNotExist(root.getUri(), name);
+    }
+
+    public @Nullable DocumentInfo findFile(String parentId, String name)
+            throws Exception {
+        List<DocumentInfo> children = listChildren(parentId);
+        for (DocumentInfo child : children) {
+            if (name.equals(child.displayName)) {
+                return child;
+            }
+        }
+        return null;
+    }
+
+    public DocumentInfo findDocument(String parentId, String name) throws Exception {
+        List<DocumentInfo> children = listChildren(parentId);
+        for (DocumentInfo child : children) {
+            if (name.equals(child.displayName)) {
+                return child;
+            }
+        }
+        return null;
+    }
+
+    public DocumentInfo findDocument(Uri parentUri, String name) throws Exception {
+        List<DocumentInfo> children = listChildren(parentUri);
+        for (DocumentInfo child : children) {
+            if (name.equals(child.displayName)) {
+                return child;
+            }
+        }
+        return null;
+    }
+
+    public List<DocumentInfo> listChildren(Uri parentUri) throws Exception {
+        String id = DocumentsContract.getDocumentId(parentUri);
+        return listChildren(id);
+    }
+
+    public List<DocumentInfo> listChildren(String documentId) throws Exception {
+        Uri uri = buildChildDocumentsUri(mAuthority, documentId);
+        List<DocumentInfo> children = new ArrayList<>();
+        try (Cursor cursor = mClient.query(uri, null, null, null, null, null)) {
+            Cursor wrapper = new RootCursorWrapper(mAuthority, "totally-fake", cursor, 100);
+            while (wrapper.moveToNext()) {
+                children.add(DocumentInfo.fromDirectoryCursor(wrapper));
+            }
+        }
+        return children;
+    }
+
+    public void assertFileContents(Uri documentUri, byte[] expected) throws Exception {
+        MoreAsserts.assertEquals(
+                "Copied file contents differ",
+                expected, readDocument(documentUri));
+    }
+
+    public void assertFileContents(String parentId, String fileName, byte[] expected)
+            throws Exception {
+        DocumentInfo file = findFile(parentId, fileName);
+        assertNotNull(file);
+        assertFileContents(file.derivedUri, expected);
+    }
+
+    /**
+     * A helper method for StubProvider only. Won't work with other providers.
+     * @throws RemoteException
+     */
+    public Uri createVirtualFile(
+            RootInfo root, String path, String mimeType, byte[] content, String... streamTypes)
+                    throws RemoteException {
+
+        Bundle args = new Bundle();
+        args.putString(StubProvider.EXTRA_ROOT, root.rootId);
+        args.putString(StubProvider.EXTRA_PATH, path);
+        args.putString(Document.COLUMN_MIME_TYPE, mimeType);
+        args.putStringArrayList(StubProvider.EXTRA_STREAM_TYPES, Lists.newArrayList(streamTypes));
+        args.putByteArray(StubProvider.EXTRA_CONTENT, content);
+
+        Bundle result = mClient.call("createVirtualFile", null, args);
+        String documentId = result.getString(Document.COLUMN_DOCUMENT_ID);
+
+        return DocumentsContract.buildDocumentUri(mAuthority, documentId);
+    }
 }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java
new file mode 100644
index 0000000..6c9c5d9
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.DEFAULT_AUTHORITY;
+import static com.android.documentsui.StubProvider.ROOT_0_ID;
+import static com.android.documentsui.StubProvider.ROOT_1_ID;
+
+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.support.test.uiautomator.By;
+import android.support.test.uiautomator.Configurator;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.Until;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import com.android.documentsui.model.RootInfo;
+
+@LargeTest
+public class SearchViewUiTest extends InstrumentationTestCase {
+
+    private static final int TIMEOUT = 5000;
+    private static final String TAG = "SearchViewUiTest";
+    private static final String TARGET_PKG = "com.android.documentsui";
+    private static final String LAUNCHER_PKG = "com.android.launcher";
+
+    private UiBot mBot;
+    private UiDevice mDevice;
+    private Context mContext;
+    private ContentResolver mResolver;
+    private DocumentsProviderHelper mDocsHelper;
+    private ContentProviderClient mClient;
+    private RootInfo mRoot_0;
+    private RootInfo mRoot_1;
+
+    private UiObject mSearchView;
+    private UiObject mSearchTextField;
+    private UiObject mDocsList;
+    private UiObject mMessageTextView;
+    private UiObject mSearchIcon;
+
+    public void setUp() throws Exception {
+        // Initialize UiDevice instance.
+        Instrumentation instrumentation = getInstrumentation();
+
+        mDevice = UiDevice.getInstance(instrumentation);
+
+        Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_MOUSE);
+
+        // Start from the home screen.
+        mDevice.pressHome();
+        mDevice.wait(Until.hasObject(By.pkg(LAUNCHER_PKG).depth(0)), TIMEOUT);
+
+        // NOTE: Must be the "target" context, else security checks in content provider will fail.
+        mContext = instrumentation.getTargetContext();
+        mResolver = mContext.getContentResolver();
+
+        mClient = mResolver.acquireUnstableContentProviderClient(DEFAULT_AUTHORITY);
+        mDocsHelper = new DocumentsProviderHelper(DEFAULT_AUTHORITY, mClient);
+
+        // Launch app.
+        Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(TARGET_PKG);
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        mContext.startActivity(intent);
+        // Wait for the app to appear.
+        mDevice.wait(Until.hasObject(By.pkg(TARGET_PKG).depth(0)), TIMEOUT);
+        mDevice.waitForIdle();
+
+        mBot = new UiBot(mDevice, TIMEOUT);
+
+        resetStorage(); // Just incase a test failed and tearDown didn't happen.
+
+        initUiObjects();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        mDevice.pressBack();
+        resetStorage();
+        mClient.release();
+    }
+
+    private void resetStorage() throws RemoteException {
+        mClient.call("clear", null, null);
+        // TODO: Would be nice to have an event to wait on here.
+        mDevice.waitForIdle();
+    }
+
+    private void initTestFiles() throws RemoteException {
+        mRoot_0 = mDocsHelper.getRoot(ROOT_0_ID);
+        mRoot_1 = mDocsHelper.getRoot(ROOT_1_ID);
+
+        mDocsHelper.createDocument(mRoot_0, "text/plain", "file10.log");
+        mDocsHelper.createDocument(mRoot_0, "image/png", "file1.png");
+        mDocsHelper.createDocument(mRoot_0, "text/csv", "file2.csv");
+
+        mDocsHelper.createDocument(mRoot_1, "text/plain", "anotherFile0.log");
+        mDocsHelper.createDocument(mRoot_1, "text/plain", "poodles.text");
+    }
+
+    private void initUiObjects() {
+        mSearchView = mBot.findSearchView();
+        mSearchTextField = mBot.findSearchViewTextField();
+        mDocsList = mBot.findDocumentsList();
+        mMessageTextView = mBot.findMessageTextView();
+        mSearchIcon = mBot.findSearchViewIcon();
+    }
+
+    public void testSearchViewExpandsOnClick() throws Exception {
+        assertTrue(mSearchIcon.exists());
+        assertFalse(mSearchTextField.exists());
+
+        mSearchView.click();
+
+        assertTrue(mSearchTextField.exists());
+        assertTrue(mSearchTextField.isFocused());
+        assertFalse(mSearchIcon.exists());
+    }
+
+    public void testSearchViewCollapsesOnBack() throws Exception {
+        assertTrue(mSearchIcon.exists());
+        assertFalse(mSearchTextField.exists());
+
+        mSearchView.click();
+
+        mDevice.pressBack();
+
+        assertTrue(mSearchIcon.exists());
+        assertFalse(mSearchTextField.exists());
+    }
+
+    public void testSearchViewClearsTextOnBack() throws Exception {
+        assertTrue(mSearchIcon.exists());
+        assertFalse(mSearchTextField.exists());
+
+        String query = "file2";
+        mSearchView.click();
+        mSearchTextField.setText(query);
+
+        assertSearchTextField(true, query);
+
+        mDevice.pressBack();
+
+        assertTrue(mSearchIcon.exists());
+        assertFalse(mSearchTextField.exists());
+    }
+
+    public void testSearchFound() throws Exception {
+        initTestFiles();
+
+        mBot.openRoot(ROOT_0_ID);
+
+        assertDefaultTestDir0();
+
+        String query = "file1";
+        mSearchView.click();
+        mSearchTextField.setText(query);
+
+        assertTrue(mDocsList.exists());
+        assertSearchTextField(true, query);
+
+        mDevice.pressEnter();
+
+        assertTrue(mDocsList.exists());
+        assertEquals(2, mDocsList.getChildCount());
+        mBot.assertHasDocuments("file1.png", "file10.log");
+        assertSearchTextField(false, query);
+    }
+
+    public void testSearchFoundClearsOnBack() throws Exception {
+        initTestFiles();
+
+        mBot.openRoot(ROOT_0_ID);
+
+        assertDefaultTestDir0();
+
+        String query = "file1";
+        mSearchView.click();
+        mSearchTextField.setText(query);
+
+        mDevice.pressEnter();
+        mDevice.pressBack();
+
+        assertDefaultTestDir0();
+    }
+
+    public void testSearchNoResults() throws Exception {
+        initTestFiles();
+
+        mBot.openRoot(ROOT_0_ID);
+
+        assertDefaultTestDir0();
+
+        String query = "chocolate";
+        mSearchView.click();
+        mSearchTextField.setText(query);
+
+        mDevice.pressEnter();
+
+        assertFalse(mDocsList.exists());
+        assertTrue(mMessageTextView.exists());
+        String msg = String.valueOf(mContext.getString(R.string.no_results));
+        assertEquals(String.format(msg, "TEST_ROOT_0"), mMessageTextView.getText());
+        assertSearchTextField(false, query);
+    }
+
+    public void testSearchNoResultsClearsOnBack() throws Exception {
+        initTestFiles();
+
+        mBot.openRoot(ROOT_0_ID);
+
+        assertDefaultTestDir0();
+
+        String query = "chocolate";
+        mSearchView.click();
+        mSearchTextField.setText(query);
+
+        mDevice.pressEnter();
+        mDevice.pressBack();
+
+        assertDefaultTestDir0();
+    }
+
+    public void testSearchFoundClearsDirectoryChange() throws Exception {
+        initTestFiles();
+
+        mBot.openRoot(ROOT_0_ID);
+
+        assertDefaultTestDir0();
+
+        String query = "file1";
+        mSearchView.click();
+        mSearchTextField.setText(query);
+
+        mDevice.pressEnter();
+
+        mBot.openRoot(ROOT_1_ID);
+
+         assertDefaultTestDir1();
+
+         mBot.openRoot(ROOT_0_ID);
+
+         assertDefaultTestDir0();
+    }
+
+    private void assertDefaultTestDir0() throws UiObjectNotFoundException {
+        assertTrue(mSearchIcon.exists());
+        assertTrue(mDocsList.exists());
+        assertFalse(mSearchTextField.exists());
+        assertEquals(3, mDocsList.getChildCount());
+        mBot.assertHasDocuments("file2.csv", "file1.png", "file10.log");
+    }
+
+    private void assertDefaultTestDir1() throws UiObjectNotFoundException {
+        assertTrue(mSearchIcon.exists());
+        assertFalse(mSearchTextField.exists());
+        assertTrue(mDocsList.exists());
+        assertEquals(2, mDocsList.getChildCount());
+        mBot.assertHasDocuments("anotherFile0.log", "poodles.text");
+    }
+
+    private void assertSearchTextField(boolean isFocused, String query)
+            throws UiObjectNotFoundException {
+        assertFalse(mSearchIcon.exists());
+        assertTrue(mSearchTextField.exists());
+        assertEquals(isFocused, mSearchTextField.isFocused());
+        assertEquals(query, mSearchTextField.getText());
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/StateTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/StateTest.java
new file mode 100644
index 0000000..b74b985
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/StateTest.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.documentsui;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.documentsui.model.DocumentInfo;
+
+@SmallTest
+public class StateTest extends AndroidTestCase {
+    public void testPushDocument() {
+        final State state = new State();
+        final DocumentInfo infoFirst = new DocumentInfo();
+        infoFirst.displayName = "firstDirectory";
+        final DocumentInfo infoSecond = new DocumentInfo();
+        infoSecond.displayName = "secondDirectory";
+        assertFalse(state.hasLocationChanged());
+        state.pushDocument(infoFirst);
+        state.pushDocument(infoSecond);
+        assertTrue(state.hasLocationChanged());
+        assertEquals("secondDirectory", state.stack.getFirst().displayName);
+        state.popDocument();
+        assertEquals("firstDirectory", state.stack.getFirst().displayName);
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
index 7a75503..cc48786 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
@@ -44,10 +44,14 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+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;
 
 public class StubProvider extends DocumentsProvider {
 
@@ -55,11 +59,17 @@
     public static final String ROOT_0_ID = "TEST_ROOT_0";
     public static final String ROOT_1_ID = "TEST_ROOT_1";
 
+    public static final String EXTRA_SIZE = "com.android.documentsui.stubprovider.SIZE";
+    public static final String EXTRA_ROOT = "com.android.documentsui.stubprovider.ROOT";
+    public static final String EXTRA_PATH = "com.android.documentsui.stubprovider.PATH";
+    public static final String EXTRA_STREAM_TYPES
+            = "com.android.documentsui.stubprovider.STREAM_TYPES";
+    public static final String EXTRA_CONTENT = "com.android.documentsui.stubprovider.CONTENT";
+
     private static final String TAG = "StubProvider";
-    private static final String EXTRA_SIZE = "com.android.documentsui.stubprovider.SIZE";
-    private static final String EXTRA_ROOT = "com.android.documentsui.stubprovider.ROOT";
+
     private static final String STORAGE_SIZE_KEY = "documentsui.stubprovider.size";
-    private static int DEFAULT_ROOT_SIZE = 1024 * 1024 * 100; // 100 MB.
+    private static int DEFAULT_ROOT_SIZE = 1024 * 1024 * 100;  // 100 MB.
 
     private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
             Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_TITLE, Root.COLUMN_DOCUMENT_ID,
@@ -76,7 +86,7 @@
 
     private String mAuthority = DEFAULT_AUTHORITY;
     private SharedPreferences mPrefs;
-    private String mSimulateReadErrors;
+    private Set<String> mSimulateReadErrorIds = new HashSet<>();
 
     @Override
     public void attachInfo(Context context, ProviderInfo info) {
@@ -95,6 +105,7 @@
         Log.d(TAG, "Resetting storage.");
         removeChildrenRecursively(getContext().getCacheDir());
         mStorage.clear();
+        mSimulateReadErrorIds.clear();
 
         mPrefs = getContext().getSharedPreferences(
                 "com.android.documentsui.stubprovider.preferences", Context.MODE_PRIVATE);
@@ -105,7 +116,13 @@
 
         mRoots.clear();
         for (String rootId : rootIds) {
-            final RootInfo rootInfo = new RootInfo(rootId, getSize(rootId));
+            // Make a subdir in the cache dir for each root.
+            final File file = new File(getContext().getCacheDir(), rootId);
+            if (file.mkdir()) {
+                Log.i(TAG, "Created new root directory @ " + file.getPath());
+            }
+            final RootInfo rootInfo = new RootInfo(file, getSize(rootId));
+            mStorage.put(rootInfo.document.documentId, rootInfo.document);
             mRoots.put(rootId, rootInfo);
         }
     }
@@ -127,7 +144,8 @@
             final RootInfo info = entry.getValue();
             final RowBuilder row = result.newRow();
             row.add(Root.COLUMN_ROOT_ID, id);
-            row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_IS_CHILD);
+            row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_IS_CHILD
+                    | Root.FLAG_SUPPORTS_SEARCH);
             row.add(Root.COLUMN_TITLE, id);
             row.add(Root.COLUMN_DOCUMENT_ID, info.document.documentId);
             row.add(Root.COLUMN_AVAILABLE_BYTES, info.getRemainingCapacity());
@@ -188,7 +206,7 @@
                 created = file.createNewFile();
             } catch (IOException e) {
                 // We'll throw an FNF exception later :)
-                Log.e(TAG, "createnewFile operation failed for file: " + file, e);
+                Log.e(TAG, "createNewFile operation failed for file: " + file, e);
             }
             if (!created) {
                 throw new FileNotFoundException(
@@ -197,7 +215,8 @@
             Log.i(TAG, "Created new file: " + file);
         }
 
-        final StubDocument document = new StubDocument(file, mimeType, parent);
+        final StubDocument document = StubDocument.createRegularDocument(file, mimeType, parent);
+        mStorage.put(document.documentId, document);
         Log.d(TAG, "Created document " + document.documentId);
         notifyParentChanged(document.parentId);
         getContext().getContentResolver().notifyChange(
@@ -261,24 +280,47 @@
     }
 
     @Override
+    public Cursor querySearchDocuments(String rootId, String query, String[] projection)
+            throws FileNotFoundException {
+
+        StubDocument parentDocument = mRoots.get(rootId).document;
+        if (parentDocument == null || parentDocument.file.isFile()) {
+            throw new FileNotFoundException();
+        }
+
+        final MatrixCursor result = new MatrixCursor(
+                projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
+
+        for (File file : parentDocument.file.listFiles()) {
+            if (file.getName().toLowerCase().contains(query)) {
+                StubDocument document = mStorage.get(getDocumentIdForFile(file));
+                if (document != null) {
+                    includeDocument(result, document);
+                }
+            }
+        }
+        return result;
+    }
+
+    @Override
     public ParcelFileDescriptor openDocument(String docId, String mode, CancellationSignal signal)
             throws FileNotFoundException {
+
         final StubDocument document = mStorage.get(docId);
-        if (document == null || !document.file.isFile())
+        if (document == null || !document.file.isFile()) {
             throw new FileNotFoundException();
+        }
+        if ((document.flags & Document.FLAG_VIRTUAL_DOCUMENT) != 0) {
+            throw new IllegalStateException("Tried to open a virtual file.");
+        }
 
         if ("r".equals(mode)) {
-            ParcelFileDescriptor pfd = ParcelFileDescriptor.open(document.file,
-                    ParcelFileDescriptor.MODE_READ_ONLY);
-            if (docId.equals(mSimulateReadErrors)) {
-                pfd = new ParcelFileDescriptor(pfd) {
-                    @Override
-                    public void checkError() throws IOException {
-                        throw new IOException("Test error");
-                    }
-                };
+            if (mSimulateReadErrorIds.contains(docId)) {
+                Log.d(TAG, "Simulated errs enabled. Open in the wrong mode.");
+                return ParcelFileDescriptor.open(
+                        document.file, ParcelFileDescriptor.MODE_WRITE_ONLY);
             }
-            return pfd;
+            return ParcelFileDescriptor.open(document.file, ParcelFileDescriptor.MODE_READ_ONLY);
         }
         if ("w".equals(mode)) {
             return startWrite(document);
@@ -289,7 +331,11 @@
 
     @VisibleForTesting
     public void simulateReadErrorsForFile(Uri uri) {
-        mSimulateReadErrors = DocumentsContract.getDocumentId(uri);
+        simulateReadErrorsForFile(DocumentsContract.getDocumentId(uri));
+    }
+
+    public void simulateReadErrorsForFile(String id) {
+        mSimulateReadErrorIds.add(id);
     }
 
     @Override
@@ -298,6 +344,51 @@
         throw new FileNotFoundException();
     }
 
+    @Override
+    public AssetFileDescriptor openTypedDocument(
+            String docId, String mimeTypeFilter, Bundle opts, CancellationSignal signal)
+            throws FileNotFoundException {
+        final StubDocument document = mStorage.get(docId);
+        if (document == null || !document.file.isFile() || document.streamTypes == null) {
+            throw new FileNotFoundException();
+        }
+        for (final String mimeType : document.streamTypes) {
+            // Strict compare won't accept wildcards, but that's OK for tests, as DocumentsUI
+            // doesn't use them for getStreamTypes nor openTypedDocument.
+            if (mimeType.equals(mimeTypeFilter)) {
+                ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
+                            document.file, ParcelFileDescriptor.MODE_READ_ONLY);
+                if (mSimulateReadErrorIds.contains(docId)) {
+                    pfd = new ParcelFileDescriptor(pfd) {
+                        @Override
+                        public void checkError() throws IOException {
+                            throw new IOException("Test error");
+                        }
+                    };
+                }
+                return new AssetFileDescriptor(pfd, 0, document.file.length());
+            }
+        }
+        throw new IllegalArgumentException("Invalid MIME type filter for openTypedDocument().");
+    }
+
+    @Override
+    public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
+        final StubDocument document = mStorage.get(DocumentsContract.getDocumentId(uri));
+        if (document == null) {
+            throw new IllegalArgumentException(
+                    "The provided Uri is incorrect, or the file is gone.");
+        }
+        if (!"*/*".equals(mimeTypeFilter)) {
+            // Not used by DocumentsUI, so don't bother implementing it.
+            throw new UnsupportedOperationException();
+        }
+        if (document.streamTypes == null) {
+            return null;
+        }
+        return document.streamTypes.toArray(new String[document.streamTypes.size()]);
+    }
+
     private ParcelFileDescriptor startWrite(final StubDocument document)
             throws FileNotFoundException {
         ParcelFileDescriptor[] pipe;
@@ -372,11 +463,36 @@
             case "configure":
                 configure(arg, extras);
                 return null;
+            case "createVirtualFile":
+                return createVirtualFileFromBundle(extras);
+            case "simulateReadErrorsForFile":
+                simulateReadErrorsForFile(arg);
+                return null;
             default:
                 return super.call(method, arg, extras);
         }
     }
 
+    private Bundle createVirtualFileFromBundle(Bundle extras) {
+        try {
+            Uri uri = createVirtualFile(
+                    extras.getString(EXTRA_ROOT),
+                    extras.getString(EXTRA_PATH),
+                    extras.getString(Document.COLUMN_MIME_TYPE),
+                    extras.getStringArrayList(EXTRA_STREAM_TYPES),
+                    extras.getByteArray(EXTRA_CONTENT));
+
+            String documentId = DocumentsContract.getDocumentId(uri);
+            Bundle result = new Bundle();
+            result.putString(Document.COLUMN_DOCUMENT_ID, documentId);
+            return result;
+        } catch (IOException e) {
+            Log.e(TAG, "Couldn't create virtual file.");
+        }
+
+        return null;
+    }
+
     private void configure(String arg, Bundle extras) {
         Log.d(TAG, "Configure " + arg);
         String rootName = extras.getString(EXTRA_ROOT, ROOT_0_ID);
@@ -398,14 +514,7 @@
         row.add(Document.COLUMN_DISPLAY_NAME, document.file.getName());
         row.add(Document.COLUMN_SIZE, document.file.length());
         row.add(Document.COLUMN_MIME_TYPE, document.mimeType);
-        int flags = Document.FLAG_SUPPORTS_DELETE;
-        // TODO: Add support for renaming.
-        if (document.file.isDirectory()) {
-            flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
-        } else {
-            flags |= Document.FLAG_SUPPORTS_WRITE;
-        }
-        row.add(Document.COLUMN_FLAGS, flags);
+        row.add(Document.COLUMN_FLAGS, document.flags);
         row.add(Document.COLUMN_LAST_MODIFIED, document.file.lastModified());
     }
 
@@ -439,37 +548,31 @@
     }
 
     @VisibleForTesting
-    public Uri createFile(String rootId, String path, String mimeType, byte[] content)
+    public Uri createRegularFile(String rootId, String path, String mimeType, byte[] content)
             throws FileNotFoundException, IOException {
-        Log.d(TAG, "Creating test file " + rootId + ":" + path);
-        StubDocument root = mRoots.get(rootId).document;
-        if (root == null) {
-            throw new FileNotFoundException("No roots with the ID " + rootId + " were found");
-        }
-        File file = new File(root.file, path.substring(1));
-        StubDocument parent = mStorage.get(getDocumentIdForFile(file.getParentFile()));
+        final File file = createFile(rootId, path, mimeType, content);
+        final StubDocument parent = mStorage.get(getDocumentIdForFile(file.getParentFile()));
         if (parent == null) {
-            parent = mStorage.get(createFile(rootId, file.getParentFile().getPath(),
-                    DocumentsContract.Document.MIME_TYPE_DIR, null));
-            Log.d(TAG, "Created parent " + parent.documentId);
-        } else {
-            Log.d(TAG, "Found parent " + parent.documentId);
+            throw new FileNotFoundException("Parent not found.");
         }
+        final StubDocument document = StubDocument.createRegularDocument(file, mimeType, parent);
+        mStorage.put(document.documentId, document);
+        return DocumentsContract.buildDocumentUri(mAuthority,  document.documentId);
+    }
 
-        if (DocumentsContract.Document.MIME_TYPE_DIR.equals(mimeType)) {
-            if (!file.mkdirs()) {
-                throw new FileNotFoundException("Couldn't create directory " + file.getPath());
-            }
-        } else {
-            if (!file.createNewFile()) {
-                throw new FileNotFoundException("Couldn't create file " + file.getPath());
-            }
-            // Add content to the file.
-            FileOutputStream fout = new FileOutputStream(file);
-            fout.write(content);
-            fout.close();
+    @VisibleForTesting
+    public Uri createVirtualFile(
+            String rootId, String path, String mimeType, List<String> streamTypes, byte[] content)
+            throws FileNotFoundException, IOException {
+
+        final File file = createFile(rootId, path, mimeType, content);
+        final StubDocument parent = mStorage.get(getDocumentIdForFile(file.getParentFile()));
+        if (parent == null) {
+            throw new FileNotFoundException("Parent not found.");
         }
-        final StubDocument document = new StubDocument(file, mimeType, parent);
+        final StubDocument document = StubDocument.createVirtualDocument(
+                file, mimeType, streamTypes, parent);
+        mStorage.put(document.documentId, document);
         return DocumentsContract.buildDocumentUri(mAuthority,  document.documentId);
     }
 
@@ -489,21 +592,39 @@
         return found.file;
     }
 
-    final class RootInfo {
+    private File createFile(String rootId, String path, String mimeType, byte[] content)
+            throws FileNotFoundException, IOException {
+        Log.d(TAG, "Creating test file " + rootId + " : " + path);
+        StubDocument root = mRoots.get(rootId).document;
+        if (root == null) {
+            throw new FileNotFoundException("No roots with the ID " + rootId + " were found");
+        }
+        final File file = new File(root.file, path.substring(1));
+        if (DocumentsContract.Document.MIME_TYPE_DIR.equals(mimeType)) {
+            if (!file.mkdirs()) {
+                throw new FileNotFoundException("Couldn't create directory " + file.getPath());
+            }
+        } else {
+            if (!file.createNewFile()) {
+                throw new FileNotFoundException("Couldn't create file " + file.getPath());
+            }
+            try (final FileOutputStream fout = new FileOutputStream(file)) {
+                fout.write(content);
+            }
+        }
+        return file;
+    }
+
+    final static class RootInfo {
         public final String name;
         public final StubDocument document;
         public long capacity;
         public long size;
 
-        RootInfo(String name, long capacity) {
-            this.name = name;
+        RootInfo(File file, long capacity) {
+            this.name = file.getName();
             this.capacity = 1024 * 1024;
-            // Make a subdir in the cache dir for each root.
-            File file = new File(getContext().getCacheDir(), name);
-            if (file.mkdir()) {
-                Log.i(TAG, "Created new root directory @ " + file.getPath());
-            }
-            this.document = new StubDocument(file, Document.MIME_TYPE_DIR, this);
+            this.document = StubDocument.createRootDocument(file, this);
             this.capacity = capacity;
             this.size = 0;
         }
@@ -513,38 +634,69 @@
         }
     }
 
-    final class StubDocument {
+    final static class StubDocument {
         public final File file;
-        public final String mimeType;
         public final String documentId;
+        public final String mimeType;
+        public final List<String> streamTypes;
+        public final int flags;
         public final String parentId;
         public final RootInfo rootInfo;
 
-        StubDocument(File file, String mimeType, StubDocument parent) {
+        private StubDocument(
+                 File file, String mimeType, List<String> streamTypes, int flags,
+                 StubDocument parent) {
             this.file = file;
-            this.mimeType = mimeType;
             this.documentId = getDocumentIdForFile(file);
+            this.mimeType = mimeType;
+            this.streamTypes = streamTypes;
+            this.flags = flags;
             this.parentId = parent.documentId;
             this.rootInfo = parent.rootInfo;
-            mStorage.put(this.documentId, this);
         }
 
-        StubDocument(File file, String mimeType, RootInfo rootInfo) {
+        private StubDocument(File file, RootInfo rootInfo) {
             this.file = file;
-            this.mimeType = mimeType;
             this.documentId = getDocumentIdForFile(file);
+            this.mimeType = Document.MIME_TYPE_DIR;
+            this.streamTypes = new ArrayList<String>();
+            this.flags = Document.FLAG_DIR_SUPPORTS_CREATE | Document.FLAG_SUPPORTS_RENAME;
             this.parentId = null;
             this.rootInfo = rootInfo;
-            mStorage.put(this.documentId, this);
         }
+
+        public static StubDocument createRootDocument(File file, RootInfo rootInfo) {
+            return new StubDocument(file, rootInfo);
+        }
+
+        public static StubDocument createRegularDocument(
+                File file, String mimeType, StubDocument parent) {
+            int flags = Document.FLAG_SUPPORTS_DELETE;
+            if (file.isDirectory()) {
+                flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
+            } else {
+                flags |= Document.FLAG_SUPPORTS_WRITE;
+            }
+            return new StubDocument(file, mimeType, new ArrayList<String>(), flags, parent);
+        }
+
+        public static StubDocument createVirtualDocument(
+                File file, String mimeType, List<String> streamTypes, StubDocument parent) {
+            int flags = Document.FLAG_SUPPORTS_DELETE | Document.FLAG_SUPPORTS_WRITE
+                    | Document.FLAG_VIRTUAL_DOCUMENT;
+            return new StubDocument(file, mimeType, streamTypes, flags, parent);
+        }
+
         @Override
         public String toString() {
             return "StubDocument{"
                     + "path:" + file.getPath()
-                    + ", mimeType:" + mimeType
-                    + ", rootInfo:" + rootInfo
                     + ", documentId:" + documentId
+                    + ", mimeType:" + mimeType
+                    + ", streamTypes:" + streamTypes.toString()
+                    + ", flags:" + flags
                     + ", parentId:" + parentId
+                    + ", rootInfo:" + rootInfo
                     + "}";
         }
     }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java b/packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java
index 68cdf12..c4def8f 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java
@@ -187,4 +187,41 @@
         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 findDocumentsList() {
+        return findObject(
+                "com.android.documentsui:id/container_directory",
+                "com.android.documentsui:id/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");
+    }
+
 }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/DirectoryFragmentModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/DirectoryFragmentModelTest.java
deleted file mode 100644
index b250e5d..0000000
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/DirectoryFragmentModelTest.java
+++ /dev/null
@@ -1,162 +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.dirlist;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.database.Cursor;
-import android.database.MatrixCursor;
-import android.provider.DocumentsContract.Document;
-import android.support.v7.widget.RecyclerView;
-import android.test.AndroidTestCase;
-import android.test.mock.MockContentResolver;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.view.ViewGroup;
-
-import com.android.documentsui.DirectoryResult;
-import com.android.documentsui.dirlist.DirectoryFragment.Model;
-import com.android.documentsui.dirlist.MultiSelectManager.Selection;
-import com.android.documentsui.model.DocumentInfo;
-
-import java.util.List;
-
-@SmallTest
-public class DirectoryFragmentModelTest extends AndroidTestCase {
-
-    private static final int ITEM_COUNT = 5;
-    private static final String[] COLUMNS = new String[]{
-        Document.COLUMN_DOCUMENT_ID
-    };
-    private static Cursor cursor;
-
-    private Context mContext;
-    private Model model;
-
-    public void setUp() {
-        setupTestContext();
-
-        MatrixCursor c = new MatrixCursor(COLUMNS);
-        for (int i = 0; i < ITEM_COUNT; ++i) {
-            MatrixCursor.RowBuilder row = c.newRow();
-            row.add(COLUMNS[0], i);
-        }
-        cursor = c;
-
-        DirectoryResult r = new DirectoryResult();
-        r.cursor = cursor;
-
-        // Instantiate the model with a dummy view adapter and listener that (for now) do nothing.
-        model = new Model(mContext, new DummyAdapter());
-        model.addUpdateListener(new DummyListener());
-        model.update(r);
-    }
-
-    // Tests that the item count is correct.
-    public void testItemCount() {
-        assertEquals(ITEM_COUNT, model.getItemCount());
-    }
-
-    // Tests that the item count is correct after a deletion.
-    public void testItemCount_WithDeletion() {
-        // Simulate deleting 2 files.
-        delete(2, 4);
-
-        assertEquals(ITEM_COUNT - 2, model.getItemCount());
-    }
-
-    // Tests that the item count is correct after a deletion is undone.
-    public void testItemCount_WithUndoneDeletion() {
-        // Simulate deleting 2 files.
-        delete(0, 3);
-
-        // Undo the deletion
-        model.undoDeletion();
-        assertEquals(ITEM_COUNT, model.getItemCount());
-    }
-
-    // Tests that the right things are marked for deletion.
-    public void testMarkForDeletion() {
-        delete(1, 3);
-
-        List<DocumentInfo> docs = model.getDocumentsMarkedForDeletion();
-        assertEquals(2, docs.size());
-        assertEquals("1", docs.get(0).documentId);
-        assertEquals("3", docs.get(1).documentId);
-    }
-
-    // Tests the base case for Model.getItem.
-    public void testGetItem() {
-        for (int i = 0; i < ITEM_COUNT; ++i) {
-            Cursor c = model.getItem(i);
-            assertEquals(i, c.getPosition());
-        }
-    }
-
-    // Tests that Model.getItem returns the right items after a deletion.
-    public void testGetItem_WithDeletion() {
-        // Simulate deleting 2 files.
-        delete(2, 3);
-
-        List<DocumentInfo> docs = getDocumentInfo(0, 1, 2);
-        assertEquals("0", docs.get(0).documentId);
-        assertEquals("1", docs.get(1).documentId);
-        assertEquals("4", docs.get(2).documentId);
-    }
-
-    // Tests that Model.getItem returns the right items after a deletion is undone.
-    public void testGetItem_WithCancelledDeletion() {
-        delete(0, 1);
-        model.undoDeletion();
-
-        // Test that all documents are accounted for, in the right position.
-        for (int i = 0; i < ITEM_COUNT; ++i) {
-            assertEquals(Integer.toString(i), getDocumentInfo(i).get(0).documentId);
-        }
-    }
-
-    private void setupTestContext() {
-        final MockContentResolver resolver = new MockContentResolver();
-        mContext = new ContextWrapper(getContext()) {
-            @Override
-            public ContentResolver getContentResolver() {
-                return resolver;
-            }
-        };
-    }
-
-    private void delete(int... positions) {
-        model.markForDeletion(new Selection(positions));
-    }
-
-    private List<DocumentInfo> getDocumentInfo(int... positions) {
-        return model.getDocuments(new Selection(positions));
-    }
-
-    private static class DummyListener extends Model.UpdateListener {
-        public void onModelUpdate(Model model) {}
-        public void onModelUpdateFailed(Exception e) {}
-    }
-
-    private static class DummyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
-        public int getItemCount() { return 0; }
-        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {}
-        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-            return null;
-        }
-    }
-}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/DocumentHolderTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/DocumentHolderTest.java
new file mode 100644
index 0000000..16efc6e
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/DocumentHolderTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.content.Context;
+import android.database.Cursor;
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.MotionEvent.PointerCoords;
+import android.view.MotionEvent.PointerProperties;
+
+import com.android.documentsui.R;
+import com.android.documentsui.State;
+
+@SmallTest
+public class DocumentHolderTest extends AndroidTestCase {
+
+    DocumentHolder mHolder;
+    TestListener mListener;
+
+    public void setUp() throws Exception {
+        Context context = getContext();
+        LayoutInflater inflater = LayoutInflater.from(context);
+        mHolder = new DocumentHolder(getContext(), inflater.inflate(R.layout.item_doc_list, null)) {
+            @Override
+            public void bind(Cursor cursor, String modelId, State state) {}
+        };
+
+        mListener = new TestListener();
+        mHolder.addEventListener(mListener);
+
+        mHolder.itemView.requestLayout();
+        mHolder.itemView.invalidate();
+    }
+
+    public void testClickActivates() {
+        click();
+        mListener.assertSelected();
+    }
+
+    public void testTapActivates() {
+        tap();
+        mListener.assertActivated();
+    }
+
+    public void click() {
+        mHolder.onSingleTapUp(createEvent(MotionEvent.TOOL_TYPE_MOUSE));
+    }
+
+    public void tap() {
+        mHolder.onSingleTapUp(createEvent(MotionEvent.TOOL_TYPE_FINGER));
+    }
+
+    public MotionEvent createEvent(int tooltype) {
+        long time = SystemClock.uptimeMillis();
+
+        PointerProperties properties[] = new PointerProperties[] {
+                new PointerProperties()
+        };
+        properties[0].toolType = tooltype;
+
+        PointerCoords coords[] = new PointerCoords[] {
+                new PointerCoords()
+        };
+
+        Rect rect = new Rect();
+        mHolder.itemView.getHitRect(rect);
+        coords[0].x = rect.left;
+        coords[0].y = rect.top;
+
+        return MotionEvent.obtain(
+                time, // down time
+                time, // event time
+                MotionEvent.ACTION_UP, // action
+                1, // pointer count
+                properties, // pointer properties
+                coords, // pointer coords
+                0, // metastate
+                0, // button state
+                0, // xprecision
+                0, // yprecision
+                0, // deviceid
+                0, // edgeflags
+                0, // source
+                0 // flags
+                );
+    }
+
+    private class TestListener implements DocumentHolder.EventListener {
+        private boolean mActivated = false;
+        private boolean mSelected = false;
+
+        public void assertActivated() {
+            assertTrue(mActivated);
+            assertFalse(mSelected);
+        }
+
+        public void assertSelected() {
+            assertTrue(mSelected);
+            assertFalse(mActivated);
+        }
+
+        @Override
+        public boolean onActivate(DocumentHolder doc) {
+            mActivated = true;
+            return true;
+        }
+
+        @Override
+        public boolean onSelect(DocumentHolder doc) {
+            mSelected = true;
+            return true;
+        }
+
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java
new file mode 100644
index 0000000..2244be9
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.content.Context;
+import android.database.Cursor;
+import android.support.v7.widget.RecyclerView;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.SparseArray;
+import android.view.ViewGroup;
+
+import com.android.documentsui.State;
+
+import java.util.List;
+
+@SmallTest
+public class ModelBackedDocumentsAdapterTest extends AndroidTestCase {
+
+    private static final String AUTHORITY = "test_authority";
+    private static final String[] NAMES = new String[] {
+            "4",
+            "foo",
+            "1",
+            "bar",
+            "*(Ljifl;a",
+            "0",
+            "baz",
+            "2",
+            "3",
+            "%$%VD"
+    };
+
+    private TestModel mModel;
+    private ModelBackedDocumentsAdapter mAdapter;
+
+    public void setUp() {
+
+        final Context testContext = TestContext.createStorageTestContext(getContext(), AUTHORITY);
+        mModel = new TestModel(AUTHORITY);
+        mModel.update(NAMES);
+
+        DocumentsAdapter.Environment env = new TestEnvironment(testContext);
+
+        mAdapter = new ModelBackedDocumentsAdapter(
+                env, new IconHelper(testContext, State.MODE_GRID));
+        mAdapter.onModelUpdate(mModel);
+    }
+
+    // Tests that the item count is correct.
+    public void testItemCount() {
+        assertEquals(mModel.getItemCount(), mAdapter.getItemCount());
+    }
+
+    // Tests that the item count is correct.
+    public void testHide_ItemCount() {
+        List<String> ids = mModel.getModelIds();
+        mAdapter.hide(ids.get(0), ids.get(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;
+
+        private TestEnvironment(Context testContext) {
+            this.testContext = testContext;
+        }
+
+        @Override
+        public boolean isSelected(String id) {
+            return false;
+        }
+
+        @Override
+        public boolean isDocumentEnabled(String mimeType, int flags) {
+            return true;
+        }
+
+        @Override
+        public void initDocumentHolder(DocumentHolder holder) {}
+
+        @Override
+        public Model getModel() {
+            return mModel;
+        }
+
+        @Override
+        public State getDisplayState() {
+            return null;
+        }
+
+        @Override
+        public Context getContext() {
+            return testContext;
+        }
+
+        @Override
+        public int getColumnCount() {
+            return 4;
+        }
+
+        @Override
+        public void onBindDocumentHolder(DocumentHolder holder, Cursor cursor) {}
+    }
+
+    private static class DummyListener implements Model.UpdateListener {
+        public void onModelUpdate(Model model) {}
+        public void onModelUpdateFailed(Exception e) {}
+    }
+
+    private static class DummyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+        public int getItemCount() { return 0; }
+        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {}
+        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+            return null;
+        }
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
new file mode 100644
index 0000000..83299f0
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.content.ContentResolver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.provider.DocumentsContract.Document;
+import android.test.AndroidTestCase;
+import android.test.mock.MockContentResolver;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.documentsui.DirectoryResult;
+import com.android.documentsui.RootCursorWrapper;
+import com.android.documentsui.State;
+import com.android.documentsui.dirlist.MultiSelectManager.Selection;
+import com.android.documentsui.model.DocumentInfo;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+
+@SmallTest
+public class ModelTest extends AndroidTestCase {
+
+    private static final int ITEM_COUNT = 10;
+    private static final String AUTHORITY = "test_authority";
+
+    private static final String[] COLUMNS = new String[]{
+        RootCursorWrapper.COLUMN_AUTHORITY,
+        Document.COLUMN_DOCUMENT_ID,
+        Document.COLUMN_FLAGS,
+        Document.COLUMN_DISPLAY_NAME,
+        Document.COLUMN_SIZE,
+        Document.COLUMN_LAST_MODIFIED,
+        Document.COLUMN_MIME_TYPE
+    };
+
+    private static final String[] NAMES = new String[] {
+            "4",
+            "foo",
+            "1",
+            "bar",
+            "*(Ljifl;a",
+            "0",
+            "baz",
+            "2",
+            "3",
+            "%$%VD"
+        };
+
+    private Cursor cursor;
+    private Context context;
+    private Model model;
+    private TestContentProvider provider;
+
+    public void setUp() {
+        setupTestContext();
+
+        Random rand = new Random();
+
+        MatrixCursor c = new MatrixCursor(COLUMNS);
+        for (int i = 0; i < ITEM_COUNT; ++i) {
+            MatrixCursor.RowBuilder row = c.newRow();
+            row.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY);
+            row.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i));
+            row.add(Document.COLUMN_FLAGS, Document.FLAG_SUPPORTS_DELETE);
+            // Generate random document names and sizes. This forces the model's internal sort code
+            // to actually do something.
+            row.add(Document.COLUMN_DISPLAY_NAME, NAMES[i]);
+            row.add(Document.COLUMN_SIZE, rand.nextInt());
+        }
+        cursor = c;
+
+        DirectoryResult r = new DirectoryResult();
+        r.cursor = cursor;
+
+        // Instantiate the model with a dummy view adapter and listener that (for now) do nothing.
+        model = new Model();
+        model.addUpdateListener(new DummyListener());
+        model.update(r);
+    }
+
+    // Tests that the model is properly emptied out after a null update.
+    public void testNullUpdate() {
+        model.update(null);
+
+        assertTrue(model.isEmpty());
+        assertEquals(0, model.getItemCount());
+        assertEquals(0, model.getModelIds().size());
+    }
+
+    // Tests that the item count is correct.
+    public void testItemCount() {
+        assertEquals(ITEM_COUNT, model.getItemCount());
+    }
+
+    // Tests multiple authorities with clashing document IDs.
+    public void testModelIdIsUnique() {
+        MatrixCursor cIn = 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();
+            row0.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY0);
+            row0.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i));
+
+            MatrixCursor.RowBuilder row1 = cIn.newRow();
+            row1.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY1);
+            row1.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i));
+        }
+
+        // Update the model, then make sure it contains all the expected items.
+        DirectoryResult r = new DirectoryResult();
+        r.cursor = cIn;
+        model.update(r);
+
+        assertEquals(ITEM_COUNT * 2, model.getItemCount());
+        BitSet b0 = new BitSet(ITEM_COUNT);
+        BitSet b1 = new BitSet(ITEM_COUNT);
+
+        for (String id: model.getModelIds()) {
+            Cursor cOut = model.getItem(id);
+            String authority =
+                    DocumentInfo.getCursorString(cOut, RootCursorWrapper.COLUMN_AUTHORITY);
+            String docId = DocumentInfo.getCursorString(cOut, Document.COLUMN_DOCUMENT_ID);
+
+            switch (authority) {
+                case AUTHORITY0:
+                    b0.set(Integer.parseInt(docId));
+                    break;
+                case AUTHORITY1:
+                    b1.set(Integer.parseInt(docId));
+                    break;
+                default:
+                    fail("Unrecognized authority string");
+            }
+        }
+
+        assertEquals(ITEM_COUNT, b0.cardinality());
+        assertEquals(ITEM_COUNT, b1.cardinality());
+    }
+
+    // Tests the base case for Model.getItem.
+    public void testGetItem() {
+        List<String> ids = model.getModelIds();
+        assertEquals(ITEM_COUNT, ids.size());
+        for (int i = 0; i < ITEM_COUNT; ++i) {
+            Cursor c = model.getItem(ids.get(i));
+            assertEquals(i, c.getPosition());
+        }
+    }
+
+    // Tests sorting by item name.
+    public void testSort_names() {
+        BitSet seen = new BitSet(ITEM_COUNT);
+        List<String> names = new ArrayList<>();
+
+        DirectoryResult r = new DirectoryResult();
+        r.cursor = cursor;
+        r.sortOrder = State.SORT_ORDER_DISPLAY_NAME;
+        model.update(r);
+
+        for (String id: model.getModelIds()) {
+            Cursor c = model.getItem(id);
+            seen.set(c.getPosition());
+            names.add(DocumentInfo.getCursorString(c, Document.COLUMN_DISPLAY_NAME));
+        }
+
+        assertEquals(ITEM_COUNT, seen.cardinality());
+        for (int i = 0; i < names.size()-1; ++i) {
+            assertTrue(DocumentInfo.compareToIgnoreCaseNullable(names.get(i), names.get(i+1)) <= 0);
+        }
+    }
+
+    // Tests sorting by item size.
+    public void testSort_sizes() {
+        DirectoryResult r = new DirectoryResult();
+        r.cursor = cursor;
+        r.sortOrder = State.SORT_ORDER_SIZE;
+        model.update(r);
+
+        BitSet seen = new BitSet(ITEM_COUNT);
+        int previousSize = Integer.MAX_VALUE;
+        for (String id: model.getModelIds()) {
+            Cursor c = model.getItem(id);
+            seen.set(c.getPosition());
+            // Check sort order - descending numerical
+            int size = DocumentInfo.getCursorInt(c, Document.COLUMN_SIZE);
+            assertTrue(previousSize >= size);
+            previousSize = size;
+        }
+        // Check that all items were accounted for.
+        assertEquals(ITEM_COUNT, seen.cardinality());
+    }
+
+    // Tests that directories and files are properly bucketed when sorting by size
+    public void testSort_sizesWithBucketing() {
+        MatrixCursor c = new MatrixCursor(COLUMNS);
+
+        for (int i = 0; i < ITEM_COUNT; ++i) {
+            MatrixCursor.RowBuilder row = c.newRow();
+            row.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY);
+            row.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i));
+            row.add(Document.COLUMN_SIZE, i);
+            // Interleave directories and text files.
+            String mimeType =(i % 2 == 0) ? Document.MIME_TYPE_DIR : "text/*";
+            row.add(Document.COLUMN_MIME_TYPE, mimeType);
+        }
+
+        DirectoryResult r = new DirectoryResult();
+        r.cursor = c;
+        r.sortOrder = State.SORT_ORDER_SIZE;
+        model.update(r);
+
+        boolean seenAllDirs = false;
+        int previousSize = Integer.MAX_VALUE;
+        BitSet seen = new BitSet(ITEM_COUNT);
+        // Iterate over items in sort order. Once we've encountered a document (i.e. not a
+        // directory), all subsequent items must also be documents. That is, all directories are
+        // bucketed at the front of the list, sorted by size, followed by documents, sorted by size.
+        for (String id: model.getModelIds()) {
+            Cursor cOut = model.getItem(id);
+            seen.set(cOut.getPosition());
+
+            String mimeType = DocumentInfo.getCursorString(cOut, Document.COLUMN_MIME_TYPE);
+            if (seenAllDirs) {
+                assertFalse(Document.MIME_TYPE_DIR.equals(mimeType));
+            } else {
+                if (!Document.MIME_TYPE_DIR.equals(mimeType)) {
+                    seenAllDirs = true;
+                    // Reset the previous size seen, because documents are bucketed separately by
+                    // the sort.
+                    previousSize = Integer.MAX_VALUE;
+                }
+            }
+            // Check sort order - descending numerical
+            int size = DocumentInfo.getCursorInt(c, Document.COLUMN_SIZE);
+            assertTrue(previousSize >= size);
+            previousSize = size;
+        }
+
+        // Check that all items were accounted for.
+        assertEquals(ITEM_COUNT, seen.cardinality());
+    }
+
+    public void testSort_time() {
+        final int DL_COUNT = 3;
+        MatrixCursor c = new MatrixCursor(COLUMNS);
+        Set<String> currentDownloads = new HashSet<>();
+
+        // Add some files
+        for (int i = 0; i < ITEM_COUNT; i++) {
+            MatrixCursor.RowBuilder row = c.newRow();
+            row.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY);
+            row.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i));
+            row.add(Document.COLUMN_LAST_MODIFIED, System.currentTimeMillis());
+        }
+        // Add some current downloads (no timestamp)
+        for (int i = ITEM_COUNT; i < ITEM_COUNT + DL_COUNT; i++) {
+            MatrixCursor.RowBuilder row = c.newRow();
+            String id = Integer.toString(i);
+            row.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY);
+            row.add(Document.COLUMN_DOCUMENT_ID, id);
+            currentDownloads.add(Model.createModelId(AUTHORITY, id));
+        }
+
+        DirectoryResult r = new DirectoryResult();
+        r.cursor = c;
+        r.sortOrder = State.SORT_ORDER_LAST_MODIFIED;
+        model.update(r);
+
+        List<String> ids = model.getModelIds();
+
+        // Check that all items were accounted for
+        assertEquals(ITEM_COUNT + DL_COUNT, ids.size());
+
+        // Check that active downloads are sorted to the top.
+        for (int i = 0; i < DL_COUNT; i++) {
+            assertTrue(currentDownloads.contains(ids.get(i)));
+        }
+    }
+
+    private void setupTestContext() {
+        final MockContentResolver resolver = new MockContentResolver();
+        context = new ContextWrapper(getContext()) {
+            @Override
+            public ContentResolver getContentResolver() {
+                return resolver;
+            }
+        };
+        provider = new TestContentProvider();
+        resolver.addProvider(AUTHORITY, provider);
+    }
+
+    private Selection positionToSelection(int... positions) {
+        List<String> ids = model.getModelIds();
+        Selection s = new Selection();
+        // Construct a selection of the given positions.
+        for (int p: positions) {
+            s.add(ids.get(p));
+        }
+        return s;
+    }
+
+    private static class DummyListener implements Model.UpdateListener {
+        public void onModelUpdate(Model model) {}
+        public void onModelUpdateFailed(Exception e) {}
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
index b3d45ae..d3ef9aa 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
@@ -20,13 +20,10 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.SparseBooleanArray;
-import android.view.View;
-import android.view.ViewGroup;
 
 import com.android.documentsui.TestInputEvent;
 import com.android.documentsui.dirlist.MultiSelectManager.Selection;
-
-import org.mockito.Mockito;
+import com.google.common.collect.Lists;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -39,34 +36,39 @@
     private static final List<String> items;
     static {
         items = new ArrayList<String>();
-        items.add("aaa");
-        items.add("bbb");
-        items.add("ccc");
-        items.add("111");
-        items.add("222");
-        items.add("333");
+        for (int i = 0; i < 100; ++i) {
+            items.add(Integer.toString(i));
+        }
     }
 
     private MultiSelectManager mManager;
-    private TestAdapter mAdapter;
     private TestCallback mCallback;
     private TestSelectionEnvironment mEnv;
+    private TestDocumentsAdapter mAdapter;
 
     public void setUp() throws Exception {
-        mAdapter = new TestAdapter(items);
         mCallback = new TestCallback();
-        mEnv = new TestSelectionEnvironment();
-        mManager = new MultiSelectManager(mAdapter, mEnv, MultiSelectManager.MODE_MULTIPLE);
+        mEnv = new TestSelectionEnvironment(items);
+        mAdapter = new TestDocumentsAdapter(items);
+        mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_MULTIPLE);
         mManager.addCallback(mCallback);
     }
 
-    public void testMouseClick_StartsSelectionMode() {
-        click(7);
-        assertSelection(7);
+    public void testSelection() {
+        // Check selection.
+        mManager.toggleSelection(items.get(7));
+        assertSelection(items.get(7));
+        // Check deselection.
+        mManager.toggleSelection(items.get(7));
+        assertSelectionSize(0);
     }
 
-    public void testMouseClick_NotifiesSelectionChanged() {
-        click(7);
+    public void testSelection_NotifiesSelectionChanged() {
+        // Selection should notify.
+        mManager.toggleSelection(items.get(7));
+        mCallback.assertSelectionChanged();
+        // Deselection should notify.
+        mManager.toggleSelection(items.get(7));
         mCallback.assertSelectionChanged();
     }
 
@@ -84,21 +86,21 @@
     }
 
     public void testSetSelectionFocusBegin() {
-        mManager.setItemSelected(7, true);
-        mManager.setSelectionFocusBegin(7);
+        mManager.setItemsSelected(Lists.newArrayList(items.get(7)), true);
+        mManager.setSelectionRangeBegin(7);
         shiftClick(11);
         assertRangeSelection(7, 11);
     }
 
     public void testLongPress_StartsSelectionMode() {
         longPress(7);
-        assertSelection(7);
+        assertSelection(items.get(7));
     }
 
     public void testLongPress_SecondPressExtendsSelection() {
         longPress(7);
         longPress(99);
-        assertSelection(7, 99);
+        assertSelection(items.get(7), items.get(99));
     }
 
     public void testSingleTapUp_UnselectsSelectedItem() {
@@ -118,8 +120,7 @@
         longPress(99);
         tap(7);
         tap(13);
-        tap(129899);
-        assertSelection(7, 99, 13, 129899);
+        assertSelection(items.get(7), items.get(99), items.get(13));
     }
 
     public void testSingleTapUp_ShiftCreatesRangeSelection() {
@@ -172,28 +173,34 @@
         assertRangeSelection(0, 7);
     }
 
+    public void testKeyboardSelection() {
+        // This simulates shift-navigation.
+        keyToPosition(5, 10, true);
+        assertRangeSelection(5, 10);
+    }
+
     public void testSingleSelectMode() {
-        mManager = new MultiSelectManager(mAdapter, mEnv, MultiSelectManager.MODE_SINGLE);
+        mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE);
         mManager.addCallback(mCallback);
         longPress(20);
         tap(13);
-        assertSelection(13);
+        assertSelection(items.get(13));
     }
 
     public void testSingleSelectMode_ShiftTap() {
-        mManager = new MultiSelectManager(mAdapter, mEnv, MultiSelectManager.MODE_SINGLE);
+        mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE);
         mManager.addCallback(mCallback);
         longPress(13);
         shiftTap(20);
-        assertSelection(20);
+        assertSelection(items.get(20));
     }
 
     public void testSingleSelectMode_ShiftDoesNotExtendSelection() {
-        mManager = new MultiSelectManager(mAdapter, mEnv, MultiSelectManager.MODE_SINGLE);
+        mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE);
         mManager.addCallback(mCallback);
         longPress(20);
-        keyToPosition(22, true);
-        assertSelection(22);
+        keyToPosition(20, 22, true);
+        assertSelection(items.get(22));
     }
 
     public void testProvisionalSelection() {
@@ -203,26 +210,37 @@
         SparseBooleanArray provisional = new SparseBooleanArray();
         provisional.append(1, true);
         provisional.append(2, true);
-        s.setProvisionalSelection(provisional);
-        assertSelection(1, 2);
+        s.setProvisionalSelection(getItemIds(provisional));
+        assertSelection(items.get(1), items.get(2));
 
         provisional.delete(1);
         provisional.append(3, true);
-        s.setProvisionalSelection(provisional);
-        assertSelection(2, 3);
+        s.setProvisionalSelection(getItemIds(provisional));
+        assertSelection(items.get(2), items.get(3));
 
         s.applyProvisionalSelection();
-        assertSelection(2, 3);
+        assertSelection(items.get(2), items.get(3));
 
         provisional.clear();
         provisional.append(3, true);
         provisional.append(4, true);
-        s.setProvisionalSelection(provisional);
-        assertSelection(2, 3, 4);
+        s.setProvisionalSelection(getItemIds(provisional));
+        assertSelection(items.get(2), items.get(3), items.get(4));
 
         provisional.delete(3);
-        s.setProvisionalSelection(provisional);
-        assertSelection(2, 3, 4);
+        s.setProvisionalSelection(getItemIds(provisional));
+        assertSelection(items.get(2), items.get(3), items.get(4));
+    }
+
+    private static Set<String> getItemIds(SparseBooleanArray selection) {
+        Set<String> ids = new HashSet<>();
+
+        int count = selection.size();
+        for (int i = 0; i < count; ++i) {
+            ids.add(items.get(selection.keyAt(i)));
+        }
+
+        return ids;
     }
 
     private void longPress(int position) {
@@ -245,27 +263,27 @@
         mManager.onSingleTapUp(TestInputEvent.shiftClick(position));
     }
 
-    private void keyToPosition(int position, boolean shift) {
-        mManager.attemptChangePosition(position, shift);
+    private void keyToPosition(int startPos, int endPos, boolean shift) {
+        mManager.changeFocus(startPos, endPos, shift);
     }
 
-    private void assertSelected(int... expected) {
+    private void assertSelected(String... expected) {
         for (int i = 0; i < expected.length; i++) {
             Selection selection = mManager.getSelection();
             String err = String.format(
-                    "Selection %s does not contain %d", selection, expected[i]);
+                    "Selection %s does not contain %s", selection, expected[i]);
             assertTrue(err, selection.contains(expected[i]));
         }
     }
 
-    private void assertSelection(int... expected) {
+    private void assertSelection(String... expected) {
         assertSelectionSize(expected.length);
         assertSelected(expected);
     }
 
     private void assertRangeSelected(int begin, int end) {
         for (int i = begin; i <= end; i++) {
-            assertSelected(i);
+            assertSelected(items.get(i));
         }
     }
 
@@ -281,15 +299,15 @@
 
     private static final class TestCallback implements MultiSelectManager.Callback {
 
-        Set<Integer> ignored = new HashSet<>();
+        Set<String> ignored = new HashSet<>();
         private boolean mSelectionChanged = false;
 
         @Override
-        public void onItemStateChanged(int position, boolean selected) {}
+        public void onItemStateChanged(String modelId, boolean selected) {}
 
         @Override
-        public boolean onBeforeItemStateChange(int position, boolean selected) {
-            return !ignored.contains(position);
+        public boolean onBeforeItemStateChange(String modelId, boolean selected) {
+            return !ignored.contains(modelId);
         }
 
         @Override
@@ -301,33 +319,4 @@
             assertTrue(mSelectionChanged);
         }
     }
-
-    private static final class TestHolder extends RecyclerView.ViewHolder {
-        // each data item is just a string in this case
-        public TestHolder(View view) {
-            super(view);
-        }
-    }
-
-    private static final class TestAdapter extends RecyclerView.Adapter<TestHolder> {
-
-        private List<String> mItems;
-
-        public TestAdapter(List<String> items) {
-            mItems = items;
-        }
-
-        @Override
-        public TestHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-            return new TestHolder(Mockito.mock(ViewGroup.class));
-        }
-
-        @Override
-        public void onBindViewHolder(TestHolder holder, int position) {}
-
-        @Override
-        public int getItemCount() {
-            return mItems.size();
-        }
-    }
 }
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 c856b22..7920c50 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
@@ -16,16 +16,20 @@
 
 package com.android.documentsui.dirlist;
 
+import static com.android.documentsui.dirlist.MultiSelectManager.GridModel.NOT_SET;
+
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.support.v7.widget.RecyclerView.OnScrollListener;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
-import android.util.SparseBooleanArray;
 import android.view.View;
 
 import com.android.documentsui.dirlist.MultiSelectManager.GridModel;
 
+import java.util.ArrayList;
+import java.util.Set;
+
 @SmallTest
 public class MultiSelectManager_GridModelTest extends AndroidTestCase {
 
@@ -33,19 +37,32 @@
     private static final int CHILD_VIEW_EDGE_PX = 100;
     private static final int VIEWPORT_HEIGHT = 500;
 
-    private static GridModel model;
-    private static TestEnvironment env;
-    private static SparseBooleanArray lastSelection;
-    private static int viewWidth;
+    private GridModel model;
+    private TestEnvironment env;
+    private TestDocumentsAdapter adapter;
+    private Set<String> lastSelection;
+    private int viewWidth;
 
-    private static void setUp(int numChildren, int numColumns) {
+    private void initData(final int numChildren, int numColumns) {
         env = new TestEnvironment(numChildren, numColumns);
+        adapter = new TestDocumentsAdapter(new ArrayList<String>()) {
+            @Override
+            public String getModelId(int position) {
+                return Integer.toString(position);
+            }
+
+            @Override
+            public int getItemCount() {
+                return numChildren;
+            }
+        };
+
         viewWidth = VIEW_PADDING_PX + numColumns * (VIEW_PADDING_PX + CHILD_VIEW_EDGE_PX);
-        model = new GridModel(env);
+        model = new GridModel(env, adapter);
         model.addOnSelectionChangedListener(
                 new GridModel.OnSelectionChangedListener() {
                     @Override
-                    public void onSelectionChanged(SparseBooleanArray updatedSelection) {
+                    public void onSelectionChanged(Set<String> updatedSelection) {
                         lastSelection = updatedSelection;
                     }
                 });
@@ -59,123 +76,123 @@
     }
 
     public void testSelectionLeftOfItems() {
-        setUp(20, 5);
+        initData(20, 5);
         model.startSelection(new Point(0, 10));
         model.resizeSelection(new Point(1, 11));
-        assertSelected(new int[0]);
-        assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
+        assertSelected();
+        assertEquals(NOT_SET, model.getPositionNearestOrigin());
     }
 
     public void testSelectionRightOfItems() {
-        setUp(20, 4);
+        initData(20, 4);
         model.startSelection(new Point(viewWidth - 1, 10));
         model.resizeSelection(new Point(viewWidth - 2, 11));
-        assertSelected(new int[0]);
-        assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
+        assertSelected();
+        assertEquals(NOT_SET, model.getPositionNearestOrigin());
     }
 
     public void testSelectionAboveItems() {
-        setUp(20, 4);
+        initData(20, 4);
         model.startSelection(new Point(10, 0));
         model.resizeSelection(new Point(11, 1));
-        assertSelected(new int[0]);
-        assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
+        assertSelected();
+        assertEquals(NOT_SET, model.getPositionNearestOrigin());
     }
 
     public void testSelectionBelowItems() {
-        setUp(5, 4);
+        initData(5, 4);
         model.startSelection(new Point(10, VIEWPORT_HEIGHT - 1));
         model.resizeSelection(new Point(11, VIEWPORT_HEIGHT - 2));
-        assertSelected(new int[0]);
-        assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
+        assertSelected();
+        assertEquals(NOT_SET, model.getPositionNearestOrigin());
     }
 
     public void testVerticalSelectionBetweenItems() {
-        setUp(20, 4);
+        initData(20, 4);
         model.startSelection(new Point(106, 0));
         model.resizeSelection(new Point(107, 200));
-        assertSelected(new int[0]);
-        assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
+        assertSelected();
+        assertEquals(NOT_SET, model.getPositionNearestOrigin());
     }
 
     public void testHorizontalSelectionBetweenItems() {
-        setUp(20, 4);
+        initData(20, 4);
         model.startSelection(new Point(0, 105));
         model.resizeSelection(new Point(200, 106));
-        assertSelected(new int[0]);
-        assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
+        assertSelected();
+        assertEquals(NOT_SET, model.getPositionNearestOrigin());
     }
 
     public void testGrowingAndShrinkingSelection() {
-        setUp(20, 4);
+        initData(20, 4);
         model.startSelection(new Point(0, 0));
         model.resizeSelection(new Point(5, 5));
-        assertSelected(new int[] {0});
+        assertSelected(0);
         model.resizeSelection(new Point(109, 109));
-        assertSelected(new int[] {0});
+        assertSelected(0);
         model.resizeSelection(new Point(110, 109));
-        assertSelected(new int[] {0, 1});
+        assertSelected(0, 1);
         model.resizeSelection(new Point(110, 110));
-        assertSelected(new int[] {0, 1, 4, 5});
+        assertSelected(0, 1, 4, 5);
         model.resizeSelection(new Point(214, 214));
-        assertSelected(new int[] {0, 1, 4, 5});
+        assertSelected(0, 1, 4, 5);
         model.resizeSelection(new Point(215, 214));
-        assertSelected(new int[] {0, 1, 2, 4, 5, 6});
+        assertSelected(0, 1, 2, 4, 5, 6);
         model.resizeSelection(new Point(214, 214));
-        assertSelected(new int[] {0, 1, 4, 5});
+        assertSelected(0, 1, 4, 5);
         model.resizeSelection(new Point(110, 110));
-        assertSelected(new int[] {0, 1, 4, 5});
+        assertSelected(0, 1, 4, 5);
         model.resizeSelection(new Point(110, 109));
-        assertSelected(new int[] {0, 1});
+        assertSelected(0, 1);
         model.resizeSelection(new Point(109, 109));
-        assertSelected(new int[] {0});
+        assertSelected(0);
         model.resizeSelection(new Point(5, 5));
-        assertSelected(new int[] {0});
+        assertSelected(0);
         model.resizeSelection(new Point(0, 0));
-        assertSelected(new int[0]);
-        assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
+        assertSelected();
+        assertEquals(NOT_SET, model.getPositionNearestOrigin());
     }
 
     public void testSelectionMovingAroundOrigin() {
-        setUp(16, 4);
+        initData(16, 4);
         model.startSelection(new Point(210, 210));
         model.resizeSelection(new Point(viewWidth - 1, 0));
-        assertSelected(new int[] {2, 3, 6, 7});
+        assertSelected(2, 3, 6, 7);
         model.resizeSelection(new Point(0, 0));
-        assertSelected(new int[] {0, 1, 4, 5});
+        assertSelected(0, 1, 4, 5);
         model.resizeSelection(new Point(0, 420));
-        assertSelected(new int[] {8, 9, 12, 13});
+        assertSelected(8, 9, 12, 13);
         model.resizeSelection(new Point(viewWidth - 1, 420));
-        assertSelected(new int[] {10, 11, 14, 15});
+        assertSelected(10, 11, 14, 15);
         assertEquals(10, model.getPositionNearestOrigin());
     }
 
     public void testScrollingBandSelect() {
-        setUp(40, 4);
+        initData(40, 4);
         model.startSelection(new Point(0, 0));
         model.resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
-        assertSelected(new int[] {0, 4, 8, 12, 16});
+        assertSelected(0, 4, 8, 12, 16);
         scroll(CHILD_VIEW_EDGE_PX);
-        assertSelected(new int[] {0, 4, 8, 12, 16, 20});
+        assertSelected(0, 4, 8, 12, 16, 20);
         model.resizeSelection(new Point(200, VIEWPORT_HEIGHT - 1));
-        assertSelected(new int[] {0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21});
+        assertSelected(0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21);
         scroll(CHILD_VIEW_EDGE_PX);
-        assertSelected(new int[] {0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25});
+        assertSelected(0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25);
         scroll(-2 * CHILD_VIEW_EDGE_PX);
-        assertSelected(new int[] {0, 1, 4, 5, 8, 9, 12, 13, 16, 17});
+        assertSelected(0, 1, 4, 5, 8, 9, 12, 13, 16, 17);
         model.resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
-        assertSelected(new int[] {0, 4, 8, 12, 16});
+        assertSelected(0, 4, 8, 12, 16);
         assertEquals(0, model.getPositionNearestOrigin());
     }
 
-    private static void assertSelected(int[] selectedPositions) {
+    private void assertSelected(int... selectedPositions) {
         assertEquals(selectedPositions.length, lastSelection.size());
         for (int position : selectedPositions) {
-            assertTrue(lastSelection.get(position));
+            assertTrue(lastSelection.contains(Integer.toString(position)));
         }
     }
 
-    private static void scroll(int dy) {
+    private void scroll(int dy) {
         assertTrue(env.verticalOffset + VIEWPORT_HEIGHT + dy <= env.getTotalHeight());
         env.verticalOffset += dy;
         model.onScrolled(null, 0, dy);
@@ -246,7 +263,7 @@
 
         @Override
         public Rect getAbsoluteRectForChildViewAt(int index) {
-            int adapterPosition = getAdapterPositionAt(index);
+            int adapterPosition = (getFirstVisibleRowIndex() * mNumColumns) + index;
             int rowIndex = adapterPosition / mNumColumns;
             int columnIndex = adapterPosition % mNumColumns;
 
@@ -317,5 +334,10 @@
         public void focusItem(int i) {
             throw new UnsupportedOperationException();
         }
+
+        @Override
+        public boolean isLayoutItem(int adapterPosition) {
+            return false;
+        }
     }
 }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_SelectionTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_SelectionTest.java
index 030ac6c..444b2dc 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_SelectionTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_SelectionTest.java
@@ -20,33 +20,43 @@
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.documentsui.dirlist.MultiSelectManager.Selection;
+import com.google.common.collect.Sets;
+
+import java.util.HashSet;
+import java.util.Set;
 
 @SmallTest
 public class MultiSelectManager_SelectionTest extends AndroidTestCase {
 
     private Selection selection;
 
+    private String[] ids = new String[]{
+            "foo",
+            "43",
+            "auth|id=@53di*/f3#d"
+    };
+
     @Override
     public void setUp() throws Exception {
         selection = new Selection();
-        selection.add(3);
-        selection.add(5);
-        selection.add(9);
+        selection.add(ids[0]);
+        selection.add(ids[1]);
+        selection.add(ids[2]);
     }
 
     public void testAdd() {
         // We added in setUp.
         assertEquals(3, selection.size());
-        assertContains(3);
-        assertContains(5);
-        assertContains(9);
+        assertContains(ids[0]);
+        assertContains(ids[1]);
+        assertContains(ids[2]);
     }
 
     public void testRemove() {
-        selection.remove(3);
-        selection.remove(5);
+        selection.remove(ids[0]);
+        selection.remove(ids[2]);
         assertEquals(1, selection.size());
-        assertContains(9);
+        assertContains(ids[1]);
     }
 
     public void testClear() {
@@ -60,10 +70,10 @@
         assertTrue(selection.isEmpty());
     }
 
-    public void testSizeAndGet() {
+    public void testSize() {
         Selection other = new Selection();
         for (int i = 0; i < selection.size(); i++) {
-            other.add(selection.get(i));
+            other.add(ids[i]);
         }
         assertEquals(selection.size(), other.size());
     }
@@ -74,9 +84,9 @@
 
     public void testEqualsOther() {
         Selection other = new Selection();
-        other.add(3);
-        other.add(5);
-        other.add(9);
+        other.add(ids[0]);
+        other.add(ids[1]);
+        other.add(ids[2]);
         assertEquals(selection, other);
         assertEquals(selection.hashCode(), other.hashCode());
     }
@@ -90,65 +100,78 @@
 
     public void testNotEquals() {
         Selection other = new Selection();
-        other.add(789);
+        other.add("foobar");
         assertFalse(selection.equals(other));
     }
 
-    public void testExpandBefore() {
-        selection.expand(2, 10);
-        assertEquals(3, selection.size());
-        assertContains(13);
-        assertContains(15);
-        assertContains(19);
+    public void testIntersection_empty0() {
+        Selection testSelection = new Selection();
+        testSelection.intersect(new HashSet<String>());
+        assertTrue(testSelection.isEmpty());
     }
 
-    public void testExpandAfter() {
-        selection.expand(10, 10);
-        assertEquals(3, selection.size());
-        assertContains(3);
-        assertContains(5);
-        assertContains(9);
+    public void testIntersection_empty1() {
+        Selection testSelection = new Selection();
+        testSelection.intersect(Sets.newHashSet("foo"));
+        assertTrue(testSelection.isEmpty());
     }
 
-    public void testExpandSplit() {
-        selection.expand(5, 10);
-        assertEquals(3, selection.size());
-        assertContains(3);
-        assertContains(15);
-        assertContains(19);
+    public void testIntersection_empty2() {
+        assertFalse(selection.isEmpty());
+        selection.intersect(new HashSet<String>());
+        assertTrue(selection.isEmpty());
     }
 
-    public void testExpandEncompased() {
-        selection.expand(2, 10);
-        assertEquals(3, selection.size());
-        assertContains(13);
-        assertContains(15);
-        assertContains(19);
+    public void testIntersection_exclusive() {
+        String[] ids0 = new String[]{"foo", "bar", "baz"};
+        String[] ids1 = new String[]{"0", "1", "2"};
+
+        Selection testSelection = new Selection();
+        testSelection.add(ids0[0]);
+        testSelection.add(ids0[1]);
+        testSelection.add(ids0[2]);
+
+        Set<String> set = Sets.newHashSet(ids1);
+        testSelection.intersect(set);
+
+        assertTrue(testSelection.isEmpty());
     }
 
-    public void testCollapseBefore() {
-        selection.collapse(0, 2);
-        assertEquals(3, selection.size());
-        assertContains(1);
-        assertContains(3);
-        assertContains(7);
+    public void testIntersection_subset() {
+        String[] ids0 = new String[]{"foo", "bar", "baz"};
+        String[] ids1 = new String[]{"0", "baz", "1", "foo", "2"};
+
+        Selection testSelection = new Selection();
+        testSelection.add(ids0[0]);
+        testSelection.add(ids0[1]);
+        testSelection.add(ids0[2]);
+
+        testSelection.intersect(Sets.newHashSet(ids1));
+
+        assertTrue(testSelection.contains("foo"));
+        assertFalse(testSelection.contains("bar"));
+        assertTrue(testSelection.contains("baz"));
     }
 
-    public void testCollapseAfter() {
-        selection.collapse(10, 10);
-        assertEquals(3, selection.size());
-        assertContains(3);
-        assertContains(5);
-        assertContains(9);
+    public void testIntersection_all() {
+        String[] ids0 = new String[]{"foo", "bar", "baz"};
+        String[] ids1 = new String[]{"0", "baz", "1", "foo", "2", "bar"};
+
+        Selection testSelection = new Selection();
+        testSelection.add(ids0[0]);
+        testSelection.add(ids0[1]);
+        testSelection.add(ids0[2]);
+
+        Selection control = new Selection();
+        control.copyFrom(testSelection);
+
+        testSelection.intersect(Sets.newHashSet(ids1));
+
+        assertTrue(testSelection.equals(control));
     }
 
-    public void testCollapseAcross() {
-        selection.collapse(0, 10);
-        assertEquals(0, selection.size());
-    }
-
-    private void assertContains(int i) {
-        String err = String.format("Selection %s does not contain %d", selection, i);
-        assertTrue(err, selection.contains(i));
+    private void assertContains(String id) {
+        String err = String.format("Selection %s does not contain %s", selection, id);
+        assertTrue(err, selection.contains(id));
     }
 }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapperTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapperTest.java
new file mode 100644
index 0000000..7c324e7
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapperTest.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.content.Context;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.provider.DocumentsContract.Document;
+import android.support.v7.widget.RecyclerView;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.ViewGroup;
+
+import com.android.documentsui.DirectoryResult;
+import com.android.documentsui.RootCursorWrapper;
+import com.android.documentsui.State;
+
+@SmallTest
+public class SectionBreakDocumentsAdapterWrapperTest extends AndroidTestCase {
+
+    private static final String AUTHORITY = "test_authority";
+    private static final String[] NAMES = new String[] {
+            "4",
+            "foo",
+            "1",
+            "bar",
+            "*(Ljifl;a",
+            "0",
+            "baz",
+            "2",
+            "3",
+            "%$%VD"
+    };
+
+    private TestModel mModel;
+    private SectionBreakDocumentsAdapterWrapper mAdapter;
+
+    public void setUp() {
+
+        final Context testContext = TestContext.createStorageTestContext(getContext(), AUTHORITY);
+        DocumentsAdapter.Environment env = new TestEnvironment(testContext);
+
+        mModel = new TestModel(AUTHORITY);
+        mAdapter = new SectionBreakDocumentsAdapterWrapper(
+            env,
+            new ModelBackedDocumentsAdapter(
+                env, new IconHelper(testContext, State.MODE_GRID)));
+
+        mModel.addUpdateListener(mAdapter);
+    }
+
+    // Tests that the item count is correct for a directory containing only subdirs.
+    public void testItemCount_allDirs() {
+        MatrixCursor c = new MatrixCursor(TestModel.COLUMNS);
+
+        for (int i = 0; i < 5; ++i) {
+            MatrixCursor.RowBuilder row = c.newRow();
+            row.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY);
+            row.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i));
+            row.add(Document.COLUMN_SIZE, i);
+            row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR);
+        }
+        DirectoryResult r = new DirectoryResult();
+        r.cursor = c;
+        r.sortOrder = State.SORT_ORDER_SIZE;
+        mModel.update(r);
+
+        assertEquals(mModel.getItemCount(), mAdapter.getItemCount());
+    }
+
+    // Tests that the item count is correct for a directory containing only files.
+    public void testItemCount_allFiles() {
+        mModel.update(NAMES);
+        assertEquals(mModel.getItemCount(), mAdapter.getItemCount());
+    }
+
+    // Tests that the item count is correct for a directory containing files and subdirs.
+    public void testItemCount_mixed() {
+        MatrixCursor c = new MatrixCursor(TestModel.COLUMNS);
+
+        for (int i = 0; i < 5; ++i) {
+            MatrixCursor.RowBuilder row = c.newRow();
+            row.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY);
+            row.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i));
+            row.add(Document.COLUMN_SIZE, i);
+            String mimeType =(i < 2) ? Document.MIME_TYPE_DIR : "text/*";
+            row.add(Document.COLUMN_MIME_TYPE, mimeType);
+        }
+        DirectoryResult r = new DirectoryResult();
+        r.cursor = c;
+        r.sortOrder = State.SORT_ORDER_SIZE;
+        mModel.update(r);
+
+        assertEquals(mModel.getItemCount() + 1, mAdapter.getItemCount());
+    }
+
+    private final class TestEnvironment implements DocumentsAdapter.Environment {
+        private final Context testContext;
+
+        private TestEnvironment(Context testContext) {
+            this.testContext = testContext;
+        }
+
+        @Override
+        public boolean isSelected(String id) {
+            return false;
+        }
+
+        @Override
+        public boolean isDocumentEnabled(String mimeType, int flags) {
+            return true;
+        }
+
+        @Override
+        public void initDocumentHolder(DocumentHolder holder) {}
+
+        @Override
+        public Model getModel() {
+            return mModel;
+        }
+
+        @Override
+        public State getDisplayState() {
+            return null;
+        }
+
+        @Override
+        public Context getContext() {
+            return testContext;
+        }
+
+        @Override
+        public int getColumnCount() {
+            return 4;
+        }
+
+        @Override
+        public void onBindDocumentHolder(DocumentHolder holder, Cursor cursor) {}
+    }
+
+    private static class DummyListener implements Model.UpdateListener {
+        public void onModelUpdate(Model model) {}
+        public void onModelUpdateFailed(Exception e) {}
+    }
+
+    private static class DummyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+        public int getItemCount() { return 0; }
+        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {}
+        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+            return null;
+        }
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContentProvider.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContentProvider.java
new file mode 100644
index 0000000..c8d424f
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContentProvider.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.dirlist;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
+import android.test.mock.MockContentProvider;
+
+import com.android.documentsui.model.DocumentInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A very simple test double for ContentProvider. Useful in this package only.
+ */
+class TestContentProvider extends MockContentProvider {
+    List<Uri> mDeleted = new ArrayList<>();
+
+    @Override
+    public Bundle call(String method, String arg, Bundle extras) {
+        // Intercept and log delete method calls.
+        if (DocumentsContract.METHOD_DELETE_DOCUMENT.equals(method)) {
+            final Uri documentUri = extras.getParcelable(DocumentsContract.EXTRA_URI);
+            mDeleted.add(documentUri);
+            return new Bundle();
+        } else {
+            return super.call(method, arg, extras);
+        }
+    }
+
+    public void assertWasDeleted(DocumentInfo doc) {
+        ModelTest.assertTrue(mDeleted.contains(doc.derivedUri));
+    }
+}
\ No newline at end of file
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContext.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContext.java
new file mode 100644
index 0000000..714062d
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContext.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.dirlist;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.test.mock.MockContentResolver;
+
+public final class TestContext {
+
+    /**
+     * Returns a Context configured with test provider for authority.
+     */
+    static Context createStorageTestContext(Context context, String authority) {
+        final MockContentResolver testResolver = new MockContentResolver();
+        TestContentProvider provider = new TestContentProvider();
+        testResolver.addProvider(authority, provider);
+
+        return new ContextWrapper(context) {
+            @Override
+            public ContentResolver getContentResolver() {
+                return testResolver;
+            }
+        };
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestDocumentsAdapter.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestDocumentsAdapter.java
new file mode 100644
index 0000000..267f47d
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestDocumentsAdapter.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.util.SparseArray;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A skeletal {@link DocumentsAdapter} test double.
+ */
+public class TestDocumentsAdapter extends DocumentsAdapter {
+
+    List<String> mModelIds = new ArrayList<>();
+
+    public TestDocumentsAdapter(List<String> modelIds) {
+        mModelIds = modelIds;
+    }
+
+    @Override
+    public void onModelUpdate(Model model) {
+    }
+
+    @Override
+    public void onModelUpdateFailed(Exception e) {
+    }
+
+    @Override
+    List<String> getModelIds() {
+        return mModelIds;
+    }
+
+    @Override
+    void onItemSelectionChanged(String id) {
+    }
+
+    @Override
+    String getModelId(int position) {
+        return mModelIds.get(position);
+    }
+
+    @Override
+    public SparseArray<String> hide(String... ids) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    void unhide(SparseArray<String> ids) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void onBindViewHolder(DocumentHolder holder, int position) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getItemCount() {
+        return mModelIds.size();
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java
new file mode 100644
index 0000000..d8c29db
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.database.MatrixCursor;
+import android.provider.DocumentsContract.Document;
+
+import com.android.documentsui.DirectoryResult;
+import com.android.documentsui.RootCursorWrapper;
+
+import java.util.Random;
+
+public class TestModel extends Model {
+
+    static final String[] COLUMNS = new String[]{
+        RootCursorWrapper.COLUMN_AUTHORITY,
+        Document.COLUMN_DOCUMENT_ID,
+        Document.COLUMN_FLAGS,
+        Document.COLUMN_DISPLAY_NAME,
+        Document.COLUMN_SIZE,
+        Document.COLUMN_MIME_TYPE
+    };
+
+    private final String mAuthority;
+
+    public TestModel(String authority) {
+        super();
+        mAuthority = authority;
+    }
+
+    void update(String... names) {
+        Random rand = new Random();
+
+        MatrixCursor c = new MatrixCursor(COLUMNS);
+        for (int i = 0; i < names.length; i++) {
+            MatrixCursor.RowBuilder row = c.newRow();
+            row.add(RootCursorWrapper.COLUMN_AUTHORITY, mAuthority);
+            row.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i));
+            row.add(Document.COLUMN_FLAGS, Document.FLAG_SUPPORTS_DELETE);
+            // Generate random document names and sizes. This forces the model's internal sort code
+            // to actually do something.
+            row.add(Document.COLUMN_DISPLAY_NAME, names[i]);
+            row.add(Document.COLUMN_SIZE, rand.nextInt());
+        }
+
+        DirectoryResult r = new DirectoryResult();
+        r.cursor = c;
+        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));
+    }
+}
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 b4324a8..0e79561 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java
@@ -23,8 +23,13 @@
 
 import com.android.documentsui.dirlist.MultiSelectManager.SelectionEnvironment;
 
+import java.util.List;
+
 public class TestSelectionEnvironment implements SelectionEnvironment {
 
+    public TestSelectionEnvironment(List<String> items) {
+    }
+
     @Override
     public void showBand(Rect rect) {
     }
@@ -105,4 +110,9 @@
     @Override
     public void focusItem(int position) {
     }
+
+    @Override
+    public boolean isLayoutItem(int adapterPosition) {
+        return false;
+    }
 }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/AbstractCopyJobTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/AbstractCopyJobTest.java
new file mode 100644
index 0000000..eb8a061
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/AbstractCopyJobTest.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static com.google.common.collect.Lists.newArrayList;
+
+import android.net.Uri;
+import android.provider.DocumentsContract;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+
+import java.util.List;
+
+@MediumTest
+public abstract class AbstractCopyJobTest<T extends CopyJob> extends AbstractJobTest<T> {
+
+    public void runCopyFilesTest() throws Exception {
+        Uri testFile1 = mDocs.createDocument(mSrcRoot, "text/plain", "test1.txt");
+        mDocs.writeDocument(testFile1, HAM_BYTES);
+
+        Uri testFile2 = mDocs.createDocument(mSrcRoot, "text/plain", "test2.txt");
+        mDocs.writeDocument(testFile2, FRUITY_BYTES);
+
+        createJob(newArrayList(testFile1, testFile2)).run();
+        mJobListener.waitForFinished();
+
+        mDocs.assertChildCount(mDestRoot, 2);
+        mDocs.assertHasFile(mDestRoot, "test1.txt");
+        mDocs.assertHasFile(mDestRoot, "test2.txt");
+        mDocs.assertFileContents(mDestRoot.documentId, "test1.txt", HAM_BYTES);
+        mDocs.assertFileContents(mDestRoot.documentId, "test2.txt", FRUITY_BYTES);
+    }
+
+    public void runCopyVirtualTypedFileTest() throws Exception {
+        Uri testFile = mDocs.createVirtualFile(
+                mSrcRoot, "/virtual.sth", "virtual/mime-type",
+                FRUITY_BYTES, "application/pdf", "text/html");
+
+        createJob(newArrayList(testFile)).run();
+
+        mJobListener.waitForFinished();
+
+        mDocs.assertChildCount(mDestRoot, 1);
+        mDocs.assertHasFile(mDestRoot, "virtual.sth.pdf");  // copy should convert file to PDF.
+        mDocs.assertFileContents(mDestRoot.documentId, "virtual.sth.pdf", FRUITY_BYTES);
+    }
+
+    public void runCopyVirtualNonTypedFileTest() throws Exception {
+        Uri testFile = mDocs.createVirtualFile(
+                mSrcRoot, "/virtual.sth", "virtual/mime-type",
+                FRUITY_BYTES);
+
+        createJob(newArrayList(testFile)).run();
+
+        mJobListener.waitForFinished();
+        mJobListener.assertFailed();
+        mJobListener.assertFilesFailed(newArrayList("virtual.sth"));
+
+        mDocs.assertChildCount(mDestRoot, 0);
+    }
+
+    public void runCopyEmptyDirTest() throws Exception {
+        Uri testDir = mDocs.createFolder(mSrcRoot, "emptyDir");
+
+        createJob(newArrayList(testDir)).run();
+        mJobListener.waitForFinished();
+
+        mDocs.assertChildCount(mDestRoot, 1);
+        mDocs.assertHasDirectory(mDestRoot, "emptyDir");
+    }
+
+    public void runCopyDirRecursivelyTest() throws Exception {
+
+        Uri testDir1 = mDocs.createFolder(mSrcRoot, "dir1");
+        mDocs.createDocument(testDir1, "text/plain", "test1.txt");
+
+        Uri testDir2 = mDocs.createFolder(testDir1, "dir2");
+        mDocs.createDocument(testDir2, "text/plain", "test2.txt");
+
+        createJob(newArrayList(testDir1)).run();
+        mJobListener.waitForFinished();
+
+        DocumentInfo dir1Copy = mDocs.findDocument(mDestRoot.documentId, "dir1");
+
+        mDocs.assertChildCount(dir1Copy.derivedUri, 2);
+        mDocs.assertHasDirectory(dir1Copy.derivedUri, "dir2");
+        mDocs.assertHasFile(dir1Copy.derivedUri, "test1.txt");
+
+        DocumentInfo dir2Copy = mDocs.findDocument(dir1Copy.documentId, "dir2");
+        mDocs.assertChildCount(dir2Copy.derivedUri, 1);
+        mDocs.assertHasFile(dir2Copy.derivedUri, "test2.txt");
+    }
+
+    public void runNoCopyDirToSelfTest() throws Exception {
+        Uri testDir = mDocs.createFolder(mSrcRoot, "someDir");
+
+        createJob(newArrayList(testDir),
+                DocumentsContract.buildDocumentUri(AUTHORITY, mSrcRoot.documentId),
+                testDir).run();
+
+        mJobListener.waitForFinished();
+        mJobListener.assertFailed();
+        mJobListener.assertFilesFailed(newArrayList("someDir"));
+
+        mDocs.assertChildCount(mDestRoot, 0);
+    }
+
+    public void runNoCopyDirToDescendentTest() throws Exception {
+        Uri testDir = mDocs.createFolder(mSrcRoot, "someDir");
+        Uri destDir = mDocs.createFolder(testDir, "theDescendent");
+
+        createJob(newArrayList(testDir),
+                DocumentsContract.buildDocumentUri(AUTHORITY, mSrcRoot.documentId),
+                destDir).run();
+
+        mJobListener.waitForFinished();
+        mJobListener.assertFailed();
+        mJobListener.assertFilesFailed(newArrayList("someDir"));
+
+        mDocs.assertChildCount(mDestRoot, 0);
+    }
+
+    public void runCopyFileWithReadErrorsTest() throws Exception {
+        Uri testFile = mDocs.createDocument(mSrcRoot, "text/plain", "test1.txt");
+        mDocs.writeDocument(testFile, HAM_BYTES);
+
+        String testId = DocumentsContract.getDocumentId(testFile);
+        mClient.call("simulateReadErrorsForFile", testId, null);
+
+        createJob(newArrayList(testFile)).run();
+
+        mJobListener.waitForFinished();
+        mJobListener.assertFailed();
+        mJobListener.assertFilesFailed(newArrayList("test1.txt"));
+
+        mDocs.assertChildCount(mDestRoot, 0);
+    }
+
+    /**
+     * Creates a job with a stack consisting to the default source and destination.
+     * TODO: Clean up, as mDestRoot.documentInfo may not really be the parent of
+     * srcs.
+     */
+    final T createJob(List<Uri> srcs) throws Exception {
+        Uri srcParent = DocumentsContract.buildDocumentUri(AUTHORITY, mSrcRoot.documentId);
+        Uri destination = DocumentsContract.buildDocumentUri(AUTHORITY, mDestRoot.documentId);
+        return createJob(srcs, srcParent, destination);
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/AbstractJobTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/AbstractJobTest.java
new file mode 100644
index 0000000..e559503
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/AbstractJobTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static com.android.documentsui.StubProvider.ROOT_0_ID;
+import static com.android.documentsui.StubProvider.ROOT_1_ID;
+
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.Uri;
+import android.os.RemoteException;
+import android.provider.DocumentsContract;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import com.android.documentsui.DocumentsProviderHelper;
+import com.android.documentsui.StubProvider;
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.model.RootInfo;
+
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+@MediumTest
+public abstract class AbstractJobTest<T extends Job> extends AndroidTestCase {
+
+    static String AUTHORITY = StubProvider.DEFAULT_AUTHORITY;
+    static final byte[] HAM_BYTES = "ham and cheese".getBytes();
+    static final byte[] FRUITY_BYTES = "I love fruit cakes!".getBytes();
+
+    Context mContext;
+    ContentResolver mResolver;
+    ContentProviderClient mClient;
+    DocumentsProviderHelper mDocs;
+    TestJobListener mJobListener;
+    RootInfo mSrcRoot;
+    RootInfo mDestRoot;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mJobListener = new TestJobListener();
+
+        // NOTE: Must be the "target" context, else security checks in content provider will fail.
+        mContext = getContext();
+        mResolver = mContext.getContentResolver();
+
+        mClient = mResolver.acquireContentProviderClient(AUTHORITY);
+        mDocs = new DocumentsProviderHelper(AUTHORITY, mClient);
+
+        initTestFiles();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        resetStorage();
+        mClient.release();
+        super.tearDown();
+    }
+
+    private void resetStorage() throws RemoteException {
+        mClient.call("clear", null, null);
+    }
+
+    private void initTestFiles() throws RemoteException {
+        mSrcRoot = mDocs.getRoot(ROOT_0_ID);
+        mDestRoot = mDocs.getRoot(ROOT_1_ID);
+    }
+
+    final T createJob(List<Uri> srcs, Uri srcParent, Uri destination) throws Exception {
+        DocumentStack stack = new DocumentStack();
+        stack.push(DocumentInfo.fromUri(mResolver, destination));
+
+        List<DocumentInfo> srcDocs = Lists.newArrayList();
+        for (Uri src : srcs) {
+            srcDocs.add(DocumentInfo.fromUri(mResolver, src));
+        }
+
+        return createJob(srcDocs, DocumentInfo.fromUri(mResolver, srcParent), stack);
+    }
+
+    abstract T createJob(List<DocumentInfo> srcs, DocumentInfo srcParent, DocumentStack destination)
+            throws Exception;
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/CopyJobTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/CopyJobTest.java
new file mode 100644
index 0000000..543396e
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/CopyJobTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.services;
+
+import android.test.suitebuilder.annotation.MediumTest;
+
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+
+import java.util.List;
+
+@MediumTest
+public class CopyJobTest extends AbstractCopyJobTest<CopyJob> {
+
+    public void testCopyFiles() throws Exception {
+        runCopyFilesTest();
+    }
+
+    public void testCopyVirtualTypedFile() throws Exception {
+        runCopyVirtualTypedFileTest();
+    }
+
+    public void testCopyVirtualNonTypedFile() throws Exception {
+        runCopyVirtualNonTypedFileTest();
+    }
+
+    public void testCopyEmptyDir() throws Exception {
+        runCopyEmptyDirTest();
+    }
+
+    public void testCopyDirRecursively() throws Exception {
+        runCopyDirRecursivelyTest();
+    }
+
+    public void testNoCopyDirToSelf() throws Exception {
+        runNoCopyDirToSelfTest();
+    }
+
+    public void testNoCopyDirToDescendent() throws Exception {
+        runNoCopyDirToDescendentTest();
+    }
+
+    public void testCopyFileWithReadErrors() throws Exception {
+        runCopyFileWithReadErrorsTest();
+    }
+
+    @Override
+    // TODO: Stop passing srcParent here, as it's not used for copying.
+    CopyJob createJob(List<DocumentInfo> srcs, DocumentInfo srcParent, DocumentStack stack)
+            throws Exception {
+        return new CopyJob(
+                mContext, mContext, mJobListener, FileOperations.createJobId(), stack, srcs);
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/DeleteJobTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/DeleteJobTest.java
new file mode 100644
index 0000000..722df75
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/DeleteJobTest.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.documentsui.services;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+import android.net.Uri;
+import android.provider.DocumentsContract;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+
+import java.util.List;
+
+@MediumTest
+public class DeleteJobTest extends AbstractJobTest<DeleteJob> {
+
+    public void testDeleteFiles() throws Exception {
+        Uri testFile1 = mDocs.createDocument(mSrcRoot, "text/plain", "test1.txt");
+        mDocs.writeDocument(testFile1, HAM_BYTES);
+
+        Uri testFile2 = mDocs.createDocument(mSrcRoot, "text/plain", "test2.txt");
+        mDocs.writeDocument(testFile2, FRUITY_BYTES);
+
+        createJob(newArrayList(testFile1, testFile2),
+                DocumentsContract.buildDocumentUri(AUTHORITY, mSrcRoot.documentId)).run();
+        mJobListener.waitForFinished();
+
+        mDocs.assertChildCount(mSrcRoot, 0);
+    }
+
+    /**
+     * Creates a job with a stack consisting to the default src directory.
+     */
+    private final DeleteJob createJob(List<Uri> srcs, Uri srcParent) throws Exception {
+        Uri stack = DocumentsContract.buildDocumentUri(AUTHORITY, mSrcRoot.documentId);
+        return createJob(srcs, srcParent, stack);
+    }
+
+    @Override
+    // TODO: Remove inheritance, as stack is not used for deleting, nor srcParent.
+    DeleteJob createJob(List<DocumentInfo> srcs, DocumentInfo srcParent, DocumentStack stack)
+            throws Exception {
+        return new DeleteJob(
+                mContext, mContext, mJobListener, FileOperations.createJobId(), stack, srcs,
+                srcParent);
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/FileOperationServiceTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/FileOperationServiceTest.java
new file mode 100644
index 0000000..4d5392e
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/FileOperationServiceTest.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static com.android.documentsui.services.FileOperationService.OPERATION_COPY;
+import static com.android.documentsui.services.FileOperations.createBaseIntent;
+import static com.android.documentsui.services.FileOperations.createJobId;
+import static com.google.android.collect.Lists.newArrayList;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.test.ServiceTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.services.Job.Listener;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * TODO: Test progress updates.
+ */
+@MediumTest
+public class FileOperationServiceTest extends ServiceTestCase<FileOperationService> {
+
+    private static final DocumentInfo ALPHA_DOC = createDoc("alpha");
+    private static final DocumentInfo BETA_DOC = createDoc("alpha");
+    private static final DocumentInfo GAMMA_DOC = createDoc("gamma");
+    private static final DocumentInfo DELTA_DOC = createDoc("delta");
+
+    private FileOperationService mService;
+    private TestScheduledExecutorService mExecutor;
+    private TestJobFactory mJobFactory;
+
+    public FileOperationServiceTest() {
+        super(FileOperationService.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        setupService();  // must be called first for our test setup to work correctly.
+
+        mExecutor = new TestScheduledExecutorService();
+        mJobFactory = new TestJobFactory();
+
+        // Install test doubles.
+        mService = getService();
+
+        assertNull(mService.executor);
+        mService.executor = mExecutor;
+
+        assertNull(mService.jobFactory);
+        mService.jobFactory = mJobFactory;
+    }
+
+    public void testRunsJobs() throws Exception {
+        startService(createCopyIntent(newArrayList(ALPHA_DOC), BETA_DOC));
+        startService(createCopyIntent(newArrayList(GAMMA_DOC), DELTA_DOC));
+
+        mExecutor.runAll();
+        mJobFactory.assertAllJobsStarted();
+    }
+
+    public void testRunsJobs_AfterFailure() throws Exception {
+        startService(createCopyIntent(newArrayList(ALPHA_DOC), BETA_DOC));
+        startService(createCopyIntent(newArrayList(GAMMA_DOC), DELTA_DOC));
+
+        mJobFactory.jobs.get(0).fail(ALPHA_DOC);
+
+        mExecutor.runAll();
+        mJobFactory.assertAllJobsStarted();
+    }
+
+    public void testHoldsWakeLockWhileWorking() throws Exception {
+        startService(createCopyIntent(newArrayList(ALPHA_DOC), BETA_DOC));
+
+        assertTrue(mService.holdsWakeLock());
+    }
+
+    public void testReleasesWakeLock_AfterSuccess() throws Exception {
+        startService(createCopyIntent(newArrayList(ALPHA_DOC), BETA_DOC));
+
+        assertTrue(mService.holdsWakeLock());
+        mExecutor.runAll();
+        assertFalse(mService.holdsWakeLock());
+    }
+
+    public void testReleasesWakeLock_AfterFailure() throws Exception {
+        startService(createCopyIntent(newArrayList(ALPHA_DOC), BETA_DOC));
+
+        assertTrue(mService.holdsWakeLock());
+        mExecutor.runAll();
+        assertFalse(mService.holdsWakeLock());
+    }
+
+    public void testShutdownStopsExecutor_AfterSuccess() throws Exception {
+        startService(createCopyIntent(newArrayList(ALPHA_DOC), BETA_DOC));
+
+        mExecutor.assertAlive();
+
+        mExecutor.runAll();
+        shutdownService();
+
+        mExecutor.assertShutdown();
+    }
+
+    public void testShutdownStopsExecutor_AfterMixedFailures() throws Exception {
+        startService(createCopyIntent(newArrayList(ALPHA_DOC), BETA_DOC));
+        startService(createCopyIntent(newArrayList(GAMMA_DOC), DELTA_DOC));
+
+        mJobFactory.jobs.get(0).fail(ALPHA_DOC);
+
+        mExecutor.runAll();
+        shutdownService();
+
+        mExecutor.assertShutdown();
+    }
+
+    public void testShutdownStopsExecutor_AfterTotalFailure() throws Exception {
+        startService(createCopyIntent(newArrayList(ALPHA_DOC), BETA_DOC));
+        startService(createCopyIntent(newArrayList(GAMMA_DOC), DELTA_DOC));
+
+        mJobFactory.jobs.get(0).fail(ALPHA_DOC);
+        mJobFactory.jobs.get(1).fail(GAMMA_DOC);
+
+        mExecutor.runAll();
+        shutdownService();
+
+        mExecutor.assertShutdown();
+    }
+
+    private Intent createCopyIntent(ArrayList<DocumentInfo> files, DocumentInfo dest)
+            throws Exception {
+        DocumentStack stack = new DocumentStack();
+        stack.push(dest);
+
+        return createBaseIntent(OPERATION_COPY, getContext(), createJobId(), files, stack);
+    }
+
+    private static DocumentInfo createDoc(String name) {
+        // Doesn't need to be valid content Uri, just some urly looking thing.
+        Uri uri = new Uri.Builder()
+                .scheme("content")
+                .authority("com.android.documentsui.testing")
+                .path(name)
+                .build();
+
+        return createDoc(uri);
+    }
+
+    private static DocumentInfo createDoc(Uri destination) {
+        DocumentInfo destDoc = new DocumentInfo();
+        destDoc.derivedUri = destination;
+        return destDoc;
+    }
+
+    private final class TestJobFactory extends Job.Factory {
+
+        final List<TestJob> jobs = new ArrayList<>();
+
+        void assertAllJobsStarted() {
+            for (TestJob job : jobs) {
+                job.assertStarted();
+            }
+        }
+
+        @Override
+        Job createCopy(Context service, Context appContext, Listener listener, String id,
+                DocumentStack stack, List<DocumentInfo> srcs) {
+            TestJob job = new TestJob(service, appContext, listener, OPERATION_COPY, id, stack);
+            jobs.add(job);
+            return job;
+        }
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/MoveJobTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/MoveJobTest.java
new file mode 100644
index 0000000..749264a
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/MoveJobTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static com.google.common.collect.Lists.newArrayList;
+
+import android.net.Uri;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsContract;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+
+import java.util.List;
+
+@MediumTest
+public class MoveJobTest extends AbstractCopyJobTest<MoveJob> {
+
+    public void testMoveFiles() throws Exception {
+        runCopyFilesTest();
+
+        mDocs.assertChildCount(mSrcRoot, 0);
+    }
+
+    public void testMoveVirtualTypedFile() throws Exception {
+        mDocs.createFolder(mSrcRoot, "hello");
+        Uri testFile = mDocs.createVirtualFile(
+                mSrcRoot, "/hello/virtual.sth", "virtual/mime-type",
+                FRUITY_BYTES, "application/pdf", "text/html");
+        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 testMoveVirtualNonTypedFile() throws Exception {
+        runCopyVirtualNonTypedFileTest();
+
+        // Should have failed, source not deleted.
+        mDocs.assertChildCount(mSrcRoot, 1);
+    }
+
+    public void testMoveEmptyDir() throws Exception {
+        runCopyEmptyDirTest();
+
+        mDocs.assertChildCount(mSrcRoot, 0);
+    }
+
+    public void testMoveDirRecursively() throws Exception {
+        runCopyDirRecursivelyTest();
+
+        mDocs.assertChildCount(mSrcRoot, 0);
+    }
+
+    public void testNoMoveDirToSelf() throws Exception {
+        runNoCopyDirToSelfTest();
+
+        // should have failed, source not deleted
+        mDocs.assertChildCount(mSrcRoot, 1);
+    }
+
+    public void testNoMoveDirToDescendent() throws Exception {
+        runNoCopyDirToDescendentTest();
+
+        // should have failed, source not deleted
+        mDocs.assertChildCount(mSrcRoot, 1);
+    }
+
+    public void testMoveFileWithReadErrors() throws Exception {
+        runCopyFileWithReadErrorsTest();
+
+        // should have failed, source not deleted
+        mDocs.assertChildCount(mSrcRoot, 1);
+    }
+
+    // TODO: Add test cases for moving when multi-parented.
+
+    @Override
+    MoveJob createJob(List<DocumentInfo> srcs, DocumentInfo srcParent, DocumentStack stack)
+            throws Exception {
+        return new MoveJob(
+                mContext, mContext, mJobListener, FileOperations.createJobId(), stack, srcs,
+                srcParent);
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestContentResolver.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestContentResolver.java
new file mode 100644
index 0000000..8f39b14
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestContentResolver.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.documentsui.services;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.provider.DocumentsContract;
+import android.test.mock.MockContentResolver;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * A test resolver that enables this test suite to listen for notifications that mark when copy
+ * operations are done.
+ */
+class TestContentResolver extends MockContentResolver {
+
+    private static final String TAG = "TestContextResolver";
+
+    private CountDownLatch mReadySignal;
+    private CountDownLatch mNotificationSignal;
+    private Context mContext;
+
+    public TestContentResolver(Context context) {
+        mContext = context;
+        mReadySignal = new CountDownLatch(1);
+    }
+
+    /**
+     * Wait for the given number of files to be copied to destination. Times out after 1 sec.
+     */
+    public void waitForChanges(int count) throws Exception {
+        // Wait for no more than 1 second by default.
+        waitForChanges(count, 1000);
+    }
+
+    /**
+     * Wait for files to be copied to destination.
+     *
+     * @param count Number of files to wait for.
+     * @param timeOut Timeout in ms. TimeoutException will be thrown if this function times out.
+     */
+    public void waitForChanges(int count, int timeOut) throws Exception {
+        mNotificationSignal = new CountDownLatch(count);
+        // Signal that the test is now waiting for files.
+        mReadySignal.countDown();
+        if (!mNotificationSignal.await(timeOut, TimeUnit.MILLISECONDS)) {
+            throw new TimeoutException("Timed out waiting for file operations to complete.");
+        }
+    }
+
+    @Override
+    public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
+        // Wait until the test is ready to receive file notifications.
+        try {
+            mReadySignal.await();
+        } catch (InterruptedException e) {
+            Log.d(TAG, "Interrupted while waiting for file copy readiness");
+            Thread.currentThread().interrupt();
+        }
+        if (DocumentsContract.isDocumentUri(mContext, uri)) {
+            Log.d(TAG, "Notification: " + uri);
+            // Watch for document URI change notifications - this signifies the end of a copy.
+            mNotificationSignal.countDown();
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java
new file mode 100644
index 0000000..a1c6dab
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJob.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static junit.framework.Assert.assertTrue;
+
+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;
+import com.android.documentsui.model.DocumentStack;
+
+public class TestJob extends Job {
+
+    private boolean mStarted;
+
+    TestJob(
+            Context service, Context appContext, Listener listener,
+            int operationType, String id, DocumentStack stack) {
+        super(service, appContext, listener, operationType, id, stack);
+    }
+
+    @Override
+    void start() throws RemoteException {
+        mStarted = true;
+    }
+
+    void assertStarted() {
+        assertTrue(mStarted);
+    }
+
+    void fail(DocumentInfo doc) {
+        onFileFailed(doc);
+    }
+
+    @Override
+    Notification getSetupNotification() {
+        return getSetupNotification(service.getString(R.string.copy_preparing));
+    }
+
+    @Override
+    Notification getFailureNotification() {
+        // the "copy" stuff was just convenient and available :)
+        return getFailureNotification(
+                R.plurals.copy_error_notification_title, R.drawable.ic_menu_copy);
+    }
+
+    @Override
+    Notification getWarningNotification() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    Builder createProgressBuilder() {
+        // the "copy" stuff was just convenient and available :)
+        return super.createProgressBuilder(
+                service.getString(R.string.copy_notification_title),
+                R.drawable.ic_menu_copy,
+                service.getString(android.R.string.cancel),
+                R.drawable.ic_cab_cancel);
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJobListener.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJobListener.java
new file mode 100644
index 0000000..46b093d
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestJobListener.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.support.annotation.Nullable;
+
+import com.android.documentsui.model.DocumentInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class TestJobListener implements Job.Listener {
+
+    private final CountDownLatch latch = new CountDownLatch(1);
+    private final List<Job> progress = new ArrayList<>();
+    @Nullable private Job started;
+    @Nullable private Job finished;
+
+    @Override
+    public void onStart(Job job) {
+        started = job;
+    }
+
+    @Override
+    public void onFinished(Job job) {
+        this.finished = job;
+        latch.countDown();
+    }
+
+    @Override
+    public void onProgress(CopyJob job) {
+        progress.add(job);
+    }
+
+    public void assertStarted() {
+        if (started == null) {
+            fail("Job didn't start. onStart never called.");
+        }
+    }
+
+    public void assertFinished() {
+        if (finished == null) {
+            fail("Job didn't finish. onFinish never called.");
+        }
+    }
+
+    public void assertFailed() {
+        if (finished == null || !finished.hasFailures()) {
+            fail("Job didn't fail. onFailed never called.");
+        }
+    }
+
+    public void assertFilesFailed(ArrayList<String> names) {
+        if (finished == null || !finished.hasFailures()) {
+            fail("Can't test failed documetns. Job didn't fail.");
+        }
+
+        assertEquals(finished.failedFiles.size(), names.size());
+        for (String name : names) {
+            assertFileFailed(name);
+        }
+    }
+
+    public void assertFileFailed(String name) {
+        if (finished == null || !finished.hasFailures()) {
+            fail("Can't test failed documetns. Job didn't fail.");
+        }
+
+        for (DocumentInfo failed : finished.failedFiles) {
+            if (name.equals(failed.displayName)) {
+                return;
+            }
+        }
+        fail("Couldn't find failed file: " + name);
+    }
+
+    public void assertCanceled() {
+        if (finished == null) {
+            fail("Can't determine if job was canceled. Job didn't finish.");
+        }
+        if (!finished.isCanceled()) {
+            fail("Job wasn't canceled. Job#isCanceled returned false.");
+        }
+    }
+
+    public void assertMadeProgress() {
+        if (progress.isEmpty()) {
+            fail("Job made no progress. onProgress never called.");
+        }
+    }
+
+    public void waitForFinished() throws InterruptedException {
+        latch.await(500, TimeUnit.MILLISECONDS);
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestScheduledExecutorService.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestScheduledExecutorService.java
new file mode 100644
index 0000000..4d417cf
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/TestScheduledExecutorService.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Delayed;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public class TestScheduledExecutorService implements ScheduledExecutorService {
+
+    private List<TestFuture> scheduled = new ArrayList<>();
+    private boolean shutdown;
+
+    @Override
+    public void shutdown() {
+        this.shutdown = true;
+    }
+
+    @Override
+    public List<Runnable> shutdownNow() {
+        this.shutdown = true;
+        return new ArrayList<>();
+    }
+
+    void assertShutdown() {
+        if (!shutdown) {
+            fail("Executor wasn't shut down.");
+        }
+    }
+
+    @Override
+    public boolean isShutdown() {
+        return shutdown;
+    }
+
+    @Override
+    public boolean isTerminated() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T> Future<T> submit(Callable<T> task) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T> Future<T> submit(Runnable task, T result) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Future<?> submit(Runnable task) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
+            throws InterruptedException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout,
+            TimeUnit unit) throws InterruptedException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
+            throws InterruptedException, ExecutionException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
+            throws InterruptedException, ExecutionException, TimeoutException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void execute(Runnable command) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
+        TestFuture future = new TestFuture(command, delay, unit);
+        scheduled.add(future);
+        return future;
+    }
+
+    @Override
+    public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period,
+            TimeUnit unit) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay,
+            long delay, TimeUnit unit) {
+        throw new UnsupportedOperationException();
+    }
+
+    void runAll() {
+        for (TestFuture future : scheduled) {
+            future.runnable.run();
+        }
+    }
+
+    void run(int taskIndex) {
+        scheduled.get(taskIndex).runnable.run();
+    }
+
+    public void assertAlive() {
+        assertFalse(isShutdown());
+    }
+
+    static class TestFuture implements ScheduledFuture<Void> {
+
+        final Runnable runnable;
+        final long delay;
+        final TimeUnit unit;
+
+        public TestFuture(Runnable runnable, long delay, TimeUnit unit) {
+            this.runnable = runnable;
+            this.delay = delay;
+            this.unit = unit;
+        }
+
+        @Override
+        public long getDelay(TimeUnit unit) {
+            return 0;
+        }
+
+        @Override
+        public int compareTo(Delayed arg0) {
+            return 0;
+        }
+
+        @Override
+        public boolean cancel(boolean mayInterruptIfRunning) {
+            return false;
+        }
+
+        @Override
+        public boolean isCancelled() {
+            return false;
+        }
+
+        @Override
+        public boolean isDone() {
+            return false;
+        }
+
+        @Override
+        public Void get() throws InterruptedException, ExecutionException {
+            return null;
+        }
+
+        @Override
+        public Void get(long timeout, TimeUnit unit)
+                throws InterruptedException, ExecutionException, TimeoutException {
+            return null;
+        }
+    }
+}
diff --git a/packages/ExternalStorageProvider/Android.mk b/packages/ExternalStorageProvider/Android.mk
index db825ff4..ec6af2f 100644
--- a/packages/ExternalStorageProvider/Android.mk
+++ b/packages/ExternalStorageProvider/Android.mk
@@ -5,6 +5,7 @@
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-documents-archive
 LOCAL_PACKAGE_NAME := ExternalStorageProvider
 LOCAL_CERTIFICATE := platform
 LOCAL_PRIVILEGED_MODULE := true
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 2cedc72..1bfc19c 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -25,6 +25,7 @@
 import android.database.MatrixCursor.RowBuilder;
 import android.graphics.Point;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.FileObserver;
 import android.os.FileUtils;
@@ -39,6 +40,7 @@
 import android.provider.DocumentsContract.Root;
 import android.provider.DocumentsProvider;
 import android.provider.MediaStore;
+import android.support.provider.DocumentArchiveHelper;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.DebugUtils;
@@ -93,6 +95,7 @@
 
     private StorageManager mStorageManager;
     private Handler mHandler;
+    private DocumentArchiveHelper mArchiveHelper;
 
     private final Object mRootsLock = new Object();
 
@@ -106,6 +109,7 @@
     public boolean onCreate() {
         mStorageManager = (StorageManager) getContext().getSystemService(Context.STORAGE_SERVICE);
         mHandler = new Handler();
+        mArchiveHelper = new DocumentArchiveHelper(this, (char) 0);
 
         updateVolumes();
         return true;
@@ -231,7 +235,13 @@
         return projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION;
     }
 
+
     private String getDocIdForFile(File file) throws FileNotFoundException {
+        return getDocIdForFileMaybeCreate(file, false);
+    }
+
+    private String getDocIdForFileMaybeCreate(File file, boolean createNewDir)
+            throws FileNotFoundException {
         String path = file.getAbsolutePath();
 
         // Find the most-specific root path
@@ -263,6 +273,13 @@
             path = path.substring(rootPath.length() + 1);
         }
 
+        if (!file.exists() && createNewDir) {
+            Log.i(TAG, "Creating new directory " + file);
+            if (!file.mkdir()) {
+                Log.e(TAG, "Could not create directory " + file);
+            }
+        }
+
         return mostSpecificId + ':' + path;
     }
 
@@ -321,8 +338,12 @@
             }
         }
 
-        final String displayName = file.getName();
         final String mimeType = getTypeForFile(file);
+        if (mArchiveHelper.isSupportedArchiveType(mimeType)) {
+            flags |= Document.FLAG_ARCHIVE;
+        }
+
+        final String displayName = file.getName();
         if (mimeType.startsWith("image/")) {
             flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
         }
@@ -333,6 +354,7 @@
         row.add(Document.COLUMN_SIZE, file.length());
         row.add(Document.COLUMN_MIME_TYPE, mimeType);
         row.add(Document.COLUMN_FLAGS, flags);
+        row.add(DocumentArchiveHelper.COLUMN_LOCAL_FILE_PATH, file.getPath());
 
         // Only publish dates reasonably after epoch
         long lastModified = file.lastModified();
@@ -361,6 +383,10 @@
     @Override
     public boolean isChildDocument(String parentDocId, String docId) {
         try {
+            if (mArchiveHelper.isArchivedDocument(docId)) {
+                return mArchiveHelper.isChildDocument(parentDocId, docId);
+            }
+
             final File parent = getFileForDocId(parentDocId).getCanonicalFile();
             final File doc = getFileForDocId(docId).getCanonicalFile();
             return FileUtils.contains(parent, doc);
@@ -451,7 +477,8 @@
     }
 
     @Override
-    public String moveDocument(String sourceDocumentId, String targetParentDocumentId)
+    public String moveDocument(String sourceDocumentId, String sourceParentDocumentId,
+            String targetParentDocumentId)
             throws FileNotFoundException {
         final File before = getFileForDocId(sourceDocumentId);
         final File after = new File(getFileForDocId(targetParentDocumentId), before.getName());
@@ -468,6 +495,10 @@
     @Override
     public Cursor queryDocument(String documentId, String[] projection)
             throws FileNotFoundException {
+        if (mArchiveHelper.isArchivedDocument(documentId)) {
+            return mArchiveHelper.queryDocument(documentId, projection);
+        }
+
         final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
         includeFile(result, documentId, null);
         return result;
@@ -477,6 +508,11 @@
     public Cursor queryChildDocuments(
             String parentDocumentId, String[] projection, String sortOrder)
             throws FileNotFoundException {
+        if (mArchiveHelper.isArchivedDocument(parentDocumentId) ||
+                mArchiveHelper.isSupportedArchiveType(getDocumentType(parentDocumentId))) {
+            return mArchiveHelper.queryChildDocuments(parentDocumentId, projection, sortOrder);
+        }
+
         final File parent = getFileForDocId(parentDocumentId);
         final MatrixCursor result = new DirectoryCursor(
                 resolveDocumentProjection(projection), parentDocumentId, parent);
@@ -514,6 +550,10 @@
 
     @Override
     public String getDocumentType(String documentId) throws FileNotFoundException {
+        if (mArchiveHelper.isArchivedDocument(documentId)) {
+            return mArchiveHelper.getDocumentType(documentId);
+        }
+
         final File file = getFileForDocId(documentId);
         return getTypeForFile(file);
     }
@@ -522,6 +562,10 @@
     public ParcelFileDescriptor openDocument(
             String documentId, String mode, CancellationSignal signal)
             throws FileNotFoundException {
+        if (mArchiveHelper.isArchivedDocument(documentId)) {
+            return mArchiveHelper.openDocument(documentId, mode, signal);
+        }
+
         final File file = getFileForDocId(documentId);
         final File visibleFile = getFileForDocId(documentId, true);
 
@@ -550,6 +594,10 @@
     public AssetFileDescriptor openDocumentThumbnail(
             String documentId, Point sizeHint, CancellationSignal signal)
             throws FileNotFoundException {
+        if (mArchiveHelper.isArchivedDocument(documentId)) {
+            return mArchiveHelper.openDocumentThumbnail(documentId, sizeHint, signal);
+        }
+
         final File file = getFileForDocId(documentId);
         return DocumentsContract.openImageThumbnail(file);
     }
@@ -575,6 +623,34 @@
         }
     }
 
+    @Override
+    public Bundle call(String method, String arg, Bundle extras) {
+        Bundle bundle = super.call(method, arg, extras);
+        if (bundle == null && !TextUtils.isEmpty(method)) {
+            switch (method) {
+                case "getDocIdForFileCreateNewDir": {
+                    getContext().enforceCallingPermission(
+                            android.Manifest.permission.MANAGE_DOCUMENTS, null);
+                    if (TextUtils.isEmpty(arg)) {
+                        return null;
+                    }
+                    try {
+                        final String docId = getDocIdForFileMaybeCreate(new File(arg), true);
+                        bundle = new Bundle();
+                        bundle.putString("DOC_ID", docId);
+                    } catch (FileNotFoundException e) {
+                        Log.w(TAG, "file '" + arg + "' not found");
+                        return null;
+                    }
+                    break;
+                }
+                default:
+                    Log.w(TAG, "unknown method passed to call(): " + method);
+            }
+        }
+        return bundle;
+    }
+
     private static String getTypeForFile(File file) {
         if (file.isDirectory()) {
             return Document.MIME_TYPE_DIR;
diff --git a/packages/Keyguard/res/values-af/strings.xml b/packages/Keyguard/res/values-af/strings.xml
index efff2a8..1db5f61 100644
--- a/packages/Keyguard/res/values-af/strings.xml
+++ b/packages/Keyguard/res/values-af/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Voer weer die korrekte PUK-kode in. Herhaalde pogings sal die SIM permanent deaktiveer."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-kodes stem nie ooreen nie"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Te veel patroonpogings"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Jy het jou PIN <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd ingetik. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Jy het <xliff:g id="NUMBER_0">%d</xliff:g> keer jou wagwoord verkeerdelik getik. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Jy het die tablet <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd probeer ontsluit. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings sal hierdie tablet teruggestel word, wat al sy data sal uitvee."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Jy het die foon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd probeer ontsluit. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings sal hierdie foon teruggestel word, wat al sy data sal uitvee."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Jy het jou PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd ingetik. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%2$d</xliff:g> sekondes."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Jy het <xliff:g id="NUMBER_0">%1$d</xliff:g> keer jou wagwoord verkeerdelik getik. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%2$d</xliff:g> sekondes."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerdelik geteken. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%2$d</xliff:g> sekondes."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Jy het die tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nog <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal hierdie tablet teruggestel word, wat al sy data sal uitvee."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Jy het die foon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nog <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal hierdie foon teruggestel word, wat al sy data sal uitvee."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Jy het die tablet <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Hierdie tablet sal teruggestel word, wat al sy data sal uitvee."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Jy het die foon <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Hierdie foon sal teruggestel word, wat al sy data sal uitvee."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Jy het die tablet <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd probeer ontsluit. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings sal hierdie gebruiker verwyder word, wat alle gebruikerdata sal uitvee."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Jy het die foon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd probeer ontsluit. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings sal hierdie gebruiker verwyder word, wat alle gebruikerdata sal uitvee."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Jy het die tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nog <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal hierdie gebruiker verwyder word, wat alle gebruikerdata sal uitvee."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Jy het die foon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nog <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal hierdie gebruiker verwyder word, wat alle gebruikerdata sal uitvee."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Jy het die tablet <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Hierdie gebruiker sal verwyder word, wat alle gebruikerdata sal uitvee."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Jy het die foon <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Hierdie gebruiker sal verwyder word, wat alle gebruikerdata sal uitvee."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Jy het die tablet <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd probeer ontsluit. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings sal die werkprofiel verwyder word, wat alle profieldata sal uitvee."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Jy het die foon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd probeer ontsluit. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings sal die werkprofiel verwyder word, wat alle profieldata sal uitvee."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Jy het die tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nog <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal die werkprofiel verwyder word, wat alle profieldata sal uitvee."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Jy het die foon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nog <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal die werkprofiel verwyder word, wat alle profieldata sal uitvee."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Jy het die tablet <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Die werkprofiel sal verwyder word, wat alle profieldata sal uitvee."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Jy het die foon <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Die werkprofiel sal verwyder word, wat alle profieldata sal uitvee."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou tablet te ontsluit deur middel van \'n e-posrekening.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou foon te ontsluit deur middel van \'n e-posrekening.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou tablet te ontsluit deur middel van \'n e-posrekening.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%3$d</xliff:g> sekondes."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou foon te ontsluit deur middel van \'n e-posrekening.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%3$d</xliff:g> sekondes."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Verkeerde SIM PIN-kode, jy sal nou jou diensverskaffer moet kontak om jou toestel te ontsluit."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">Verkeerde SIM-PIN-kode. Jy het <xliff:g id="NUMBER_1">%d</xliff:g> pogings oor.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Vliegtuigmodus"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Patroon word vereis wanneer jy die toestel herbegin."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"PIN word vereis wanneer jy die toestel herbegin."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Wagwoord word vereis wanneer jy die toestel herbegin."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Patroon word vir bykomende sekuriteit vereis."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"PIN word vir bykomende sekuriteit vereis."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Wagwoord word vir bykomende sekuriteit vereis."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Patroon word vereis wanneer jy profiele wissel."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"PIN word vereis wanneer jy profiele wissel."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Wagwoord word vereis wanneer jy profiele wissel."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Wagwoord word vereis nadat toestel herbegin het"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Patroon word vir bykomende sekuriteit vereis"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"PIN word vir bykomende sekuriteit vereis"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Wagwoord word vir bykomende sekuriteit vereis"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Patroon word vereis wanneer jy profiele wissel"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"PIN word vereis wanneer jy profiele wissel"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Wagwoord word vereis wanneer jy profiele wissel"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">Toestel is <xliff:g id="NUMBER_1">%d</xliff:g> uur lank nie ontsluit nie. Bevestig patroon.</item>
       <item quantity="one">Toestel is <xliff:g id="NUMBER_0">%d</xliff:g> uur lank nie ontsluit nie. Bevestig patroon.</item>
diff --git a/packages/Keyguard/res/values-am/strings.xml b/packages/Keyguard/res/values-am/strings.xml
index 24f87ed..2b19d7a 100644
--- a/packages/Keyguard/res/values-am/strings.xml
+++ b/packages/Keyguard/res/values-am/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"ትክክለኛውን የPUK ኮድ እንደገና ያስገቡ። ተደጋጋሚ ሙከራዎች ሲም ካርዱን እስከመጨረሻው ያሰናክሉታል።"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ፒን ኮዶች አይገጣጠሙም"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"በጣም ብዙ የስርዓተ ጥለት ሙከራዎች"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ፒንዎን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ በትክክል አልተየቡም። \n\nበ<xliff:g id="NUMBER_1">%d</xliff:g> ሰኮንዶች ውስጥ እንደገና ይሞክሩ።"</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"የይለፍ ቃልዎን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ ትክክል ባልሆነ መንገድ ተይበዋል።\n\nበ<xliff:g id="NUMBER_1">%d</xliff:g> ሰኮንዶች ውስጥ እንደገና ይሞክሩ።"</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"የመክፈቻ ስርዓተ ጥለትዎን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ በትክክል አልሳሉትም። \n\n ከ<xliff:g id="NUMBER_1">%d</xliff:g> ሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"ጡባዊውን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ስልክ ዳግም ይጀመራል፣ ይህም ሁሉንም ውሂቡን ይሰርዛል።"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"ስልኩን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ስልክ ዳግም ይጀመራል፣ ይህም ሁሉንም ውሂቡን ይሰርዛል።"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ፒንዎን <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">"የመክፈቻ ስርዓተ ጥለትዎን <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">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ተጠቃሚ ይወገዳል፣ ይህም ሁሉንም የተጠቃሚ ውሂብ ይሰርዛል።"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"ስልኩን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ተጠቃሚ ይወገዳል፣ ይህም ሁሉንም የተጠቃሚ ውሂብ ይሰርዛል።"</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የስራ መገለጫው ይወገዳል፣ ይህም ሁሉንም የመገለጫ ውሂብ ይሰርዛል።"</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"ስልኩን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የስራ መገለጫው ይወገዳል፣ ይህም ሁሉንም የመገለጫ ውሂብ ይሰርዛል።"</string>
+    <string name="kg_failed_attempts_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">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ጡባዊ ቱኮዎን እንዲከፍቱ ይጠየቃሉ።\n\n ከ<xliff:g id="NUMBER_2">%d</xliff:g> ከሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ስልክዎን እንዲከፍቱ ይጠየቃሉ።\n\nእባክዎ ከ<xliff:g id="NUMBER_2">%d</xliff:g> ሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ጡባዊ ቱኮዎን እንዲከፍቱ ይጠየቃሉ።\n\n ከ<xliff:g id="NUMBER_2">%3$d</xliff:g> ከሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ስልክዎን እንዲከፍቱ ይጠየቃሉ።\n\nእባክዎ ከ<xliff:g id="NUMBER_2">%3$d</xliff:g> ሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"ልክ ያልሆነ የሲም ኮድ። አሁን መሳሪያዎን ለማስከፈት ድምጸ ተያያዥ ሞደምዎን ማግኘት አለብዎ።"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">ልክ ያልሆነ የሲም ፒን ኮድ፣ <xliff:g id="NUMBER_1">%d</xliff:g> ሙከራዎች ይቀርዎታል።</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ከአገልግሎት መስጫ ክልል ውጪ።"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"የግቤት ስልት አዝራር ቀይር"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"የአውሮፕላን ሁነታ"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"መሳሪያውን ዳግም በሚያስጀምሩ ጊዜ ስርዓተ ጥለት ያስፈልጋል።"</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"መሳሪያውን ዳግም በሚያስጀምሩ ጊዜ ፒን ያስፈልጋል።"</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"መሳሪያውን ዳግም በሚያስጀምሩ ጊዜ የይለፍ ቃል ያስፈልጋል።"</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"ለተጨማሪ ደህንነት ስርዓተ ጥለት ያስፈልጋል።"</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"ለተጨማሪ ደህንነት ፒን ያስፈልጋል።"</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"ለተጨማሪ ደህንነት የይለፍ ቃል ያስፈልጋል።"</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"መገለጫዎችን በሚቀይሩ ጊዜ ስርዓተ ጥለት ያስፈልጋል።"</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"መገለጫዎችን በሚቀይሩ ጊዜ ፒን ያስፈልጋል።"</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"መገለጫዎችን በሚቀይሩ ጊዜ የይለፍ ቃል ያስፈልጋል።"</string>
+    <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"መሣሪያ ዳግም ከጀመረ በኋላ ሥርዓተ ጥለት ያስፈልጋል"</string>
+    <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"መሣሪያ ዳግም ከጀመረ በኋላ ፒን ያስፈልጋል"</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">"ፒን ለተጨማሪ ደህንነት ያስፈልጋል"</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">"መገለጫዎችን በሚቀያይሯቸው ፒን ያስፈልጋል"</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="other">መሳሪያው ለ<xliff:g id="NUMBER_1">%d</xliff:g>ሰዓቶች አልተከፈተም ነበር። ስርዓተ ጥለት ያረጋግጡ።</item>
diff --git a/packages/Keyguard/res/values-ar/strings.xml b/packages/Keyguard/res/values-ar/strings.xml
index b326238..efaad1f 100644
--- a/packages/Keyguard/res/values-ar/strings.xml
+++ b/packages/Keyguard/res/values-ar/strings.xml
@@ -77,23 +77,23 @@
     <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">%d</xliff:g> مرة. \n\nأعد المحاولة خلال <xliff:g id="NUMBER_1">%d</xliff:g> ثانية."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"لقد كتبت كلمة المرور بشكل غير صحيح <xliff:g id="NUMBER_0">%d</xliff:g> مرة. \n\nأعد المحاولة خلال <xliff:g id="NUMBER_1">%d</xliff:g> ثانية."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"لقد رسمت نقش إلغاء التأمين بطريقة غير صحيحة <xliff:g id="NUMBER_0">%d</xliff:g> مرة. \n\nأعد المحاولة خلال <xliff:g id="NUMBER_1">%d</xliff:g> ثانية."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER_0">%d</xliff:g> من المرات. بعد <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستتم إعادة تعيين هذا الجهاز والتي بدورها تحذف جميع بياناته."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER_0">%d</xliff:g> من المرات. بعد <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستتم إعادة تعيين هذا الهاتف والتي بدورها تحذف جميع بياناته."</string>
+    <string name="kg_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">"لقد رسمت نقش إلغاء التأمين بطريقة غير صحيحة <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">%d</xliff:g> من المرات. بعد <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستتم إزالة هذا المستخدم والتي بدورها تحذف جميع بيانات المستخدم."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER_0">%d</xliff:g> من المرات. بعد <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستتم إزالة هذا المستخدم والتي بدورها تحذف جميع بيانات المستخدم."</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> من المرات. بعد <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستتم إزالة الملف الشخصي للعمل والتي بدورها تحذف جميع بيانات الملف الشخصي."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER_0">%d</xliff:g> من المرات. بعد <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستتم إزالة الملف الشخصي للعمل والتي بدورها تحذف جميع بيانات الملف الشخصي."</string>
+    <string name="kg_failed_attempts_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">"لقد رسمت نقش إلغاء التأمين بشكل غير صحيح <xliff:g id="NUMBER_0">%d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستطالَب بإلغاء تأمين الجهاز اللوحي باستخدام معلومات حساب بريد إلكتروني.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%d</xliff:g> ثانية."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"لقد رسمت نقش إلغاء التأمين بشكل غير صحيح <xliff:g id="NUMBER_0">%d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستُطالب بإلغاء تأمين الهاتف باستخدام حساب بريد إلكتروني لإلغاء تأمين الهاتف.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%d</xliff:g> ثانية."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"لقد رسمت نقش إلغاء التأمين بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة الأخرى، ستطالَب بإلغاء تأمين الجهاز اللوحي باستخدام معلومات حساب بريد إلكتروني.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"لقد رسمت نقش إلغاء التأمين بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة الأخرى، ستُطالب بإلغاء تأمين الهاتف باستخدام حساب بريد إلكتروني لإلغاء تأمين الهاتف.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"‏رمز \"رقم التعريف الشخصي\" لبطاقة SIM غير صحيح، ويلزمك الاتصال الآن بمشغّل شبكة الجوّال لإلغاء قفل الجهاز."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="zero">‏رمز رقم التعريف الشخصي لبطاقة SIM غير صحيح، ولم تتبق لديك أية محاولات (<xliff:g id="NUMBER_1">%d</xliff:g>).</item>
@@ -118,15 +118,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"لا تتوفر خدمة"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"زر تبديل طريقة الإدخال."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"وضع الطائرة"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"يجب رسم النقش عند إعادة تشغيل الجهاز."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"يجب إدخال رقم التعريف الشخصي عند إعادة تشغيل الجهاز."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"يجب إدخال كلمة المرور عند إعادة تشغيل الجهاز."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"يلزم إدخال النمط لمزيد من الأمان."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"يلزم إدخال رقم التعريف الشخصي لمزيد من الأمان."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"يلزم إدخال كلمة المرور لمزيد من الأمان."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"يجب رسم النقش عند تبديل الملفات الشخصية."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"يجب إدخال رقم التعريف الشخصي عند تبديل الملفات الشخصية."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"يجب إدخال كلمة المرور عند تبديل الملفات الشخصية."</string>
+    <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"يجب رسم النقش بعد إعادة تشغيل الجهاز."</string>
+    <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"يجب إدخال رقم التعريف الشخصي بعد إعادة تشغيل الجهاز."</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">"يجب إدخال رقم التعريف الشخصي لمزيد من الأمان."</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">"يجب إدخال رقم التعريف الشخصي عند تبديل الملفات الشخصية."</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="zero">لم يتم إلغاء تأمين الجهاز لمدة <xliff:g id="NUMBER_1">%d</xliff:g> من الساعات. تأكيد النقش.</item>
       <item quantity="two">لم يتم إلغاء تأمين الجهاز لمدة ساعتين (<xliff:g id="NUMBER_1">%d</xliff:g>). تأكيد النقش.</item>
diff --git a/packages/Keyguard/res/values-az-rAZ/strings.xml b/packages/Keyguard/res/values-az-rAZ/strings.xml
index 6e336be..4450c01 100644
--- a/packages/Keyguard/res/values-az-rAZ/strings.xml
+++ b/packages/Keyguard/res/values-az-rAZ/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Düzgün PUK kodu yenidən daxil edin. Təkrarlanan cəhdlər SIM\'i birdəfəlik sıradan çıxaracaq."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodları uyğun deyil"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Həddindən çox cəhd edildi!"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodunuzu <xliff:g id="NUMBER_0">%d</xliff:g> dəfə yanlış daxil etdiniz.\n\n <xliff:g id="NUMBER_1">%d</xliff:g> saniyə ərzində yenidən yoxlayın"</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Şifrənizi <xliff:g id="NUMBER_0">%d</xliff:g> dəfə yanlış daxil etdiniz. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> saniyə ərzində yenidən yoxlayın."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Modelinizi <xliff:g id="NUMBER_0">%d</xliff:g> dəfə yanlış çəkmisiniz.\n\n <xliff:g id="NUMBER_1">%d</xliff:g> saniyə ərzində yenidən yoxlayın"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Siz <xliff:g id="NUMBER_0">%d</xliff:g> dəfə planşetinizin kilidini açmaq üçün yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%d</xliff:g> uğursuz cəhddən sonra bu planşet ilkin vəziyyətinə bərpa olunacaq və ondakı bütün məlumatlar silinəcəkdir."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Siz <xliff:g id="NUMBER_0">%d</xliff:g> dəfə telefonunuzun kilidini açmaq üçün yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%d</xliff:g> uğursuz cəhddən sonra bu telefon ilkin vəziyyətinə bərpa olunacaq və ondakı bütün məlumatlar silinəcəkdir."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodunuzu <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış daxil etdiniz.\n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> saniyə ərzində yenidən yoxlayın"</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Şifrənizi <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış daxil etdiniz. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> saniyə ərzində yenidən yoxlayın."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Modelinizi <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz.\n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> saniyə ərzində yenidən yoxlayın"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Siz <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə planşetinizin kilidini açmaq üçün yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bu planşet ilkin vəziyyətinə bərpa olunacaq və ondakı bütün məlumatlar silinəcəkdir."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Siz <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə telefonunuzun kilidini açmaq üçün yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bu telefon ilkin vəziyyətinə bərpa olunacaq və ondakı bütün məlumatlar silinəcəkdir."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Siz <xliff:g id="NUMBER">%d</xliff:g> dəfə planşetinizin kilidini açmaq üçün yanlış cəhdlər etdiniz. Bu planşet ilkin vəziyyətinə bərpa olunacaq və ondakı bütün məlumatlar silinəcəkdir."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Siz <xliff:g id="NUMBER">%d</xliff:g> dəfə telefonunuzun kilidini açmaq üçün yanlış cəhdlər etdiniz. Bu telefon ilkin vəziyyətinə bərpa olunacaq və ondakı bütün məlumatlar silinəcəkdir."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Siz <xliff:g id="NUMBER_0">%d</xliff:g> dəfə planşetinizin kilidini açmaq üçün yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%d</xliff:g> uğursuz cəhddən sonra bütün istifadəçi məlumatlarını siləcək bu istifadəçi silinəcəkdir."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Siz <xliff:g id="NUMBER_0">%d</xliff:g> dəfə telefonunuzun kilidini açmaq üçün yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%d</xliff:g> uğursuz cəhddən sonra bütün istifadəçi məlumatlarını siləcək bu istifadəçi silinəcəkdir."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Siz <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə planşetinizin kilidini açmaq üçün yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bütün istifadəçi məlumatlarını siləcək bu istifadəçi silinəcəkdir."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Siz <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə telefonunuzun kilidini açmaq üçün yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bütün istifadəçi məlumatlarını siləcək bu istifadəçi silinəcəkdir."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Siz <xliff:g id="NUMBER">%d</xliff:g> dəfə planşetinizin kilidini açmaq üçün yanlış cəhdlər etdiniz. Bu istifadəçi və istifadəçi ilə bağlı bütün məlumatlar silinəcəkdir."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Siz <xliff:g id="NUMBER">%d</xliff:g> dəfə telefonunuzun kilidini açmaq üçün yanlış cəhdlər etdiniz. Bu istifadəçi və istifadəçi ilə bağlı bütün məlumatlar silinəcəkdir."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Siz <xliff:g id="NUMBER_0">%d</xliff:g> dəfə planşetinizin kilidini açmaq üçün yanlış cəhdlər etdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> uğursuz cəhddən sonra bütün profil məlumatlarını siləcək iş profili silinəcəkdir."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Siz <xliff:g id="NUMBER_0">%d</xliff:g> dəfə telefonunuzun kilidini açmaq üçün yanlış cəhdlər etdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> uğursuz cəhddən sonra bütün profil məlumatlarını siləcək iş profili silinəcəkdir."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Siz <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə planşetinizin kilidini açmaq üçün yanlış cəhdlər etdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bütün profil məlumatlarını siləcək iş profili silinəcəkdir."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Siz <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə telefonunuzun kilidini açmaq üçün yanlış cəhdlər etdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bütün profil məlumatlarını siləcək iş profili silinəcəkdir."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Siz <xliff:g id="NUMBER">%d</xliff:g> dəfə planşetinizin kilidini açmaq üçün yanlış cəhdlər etdiniz. Bütün profil məlumatlarınızı siləcək iş profili silinəcəkdir."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Siz <xliff:g id="NUMBER">%d</xliff:g> dəfə telefonunuzun kilidini açmaq üçün yanlış cəhdlər etdiniz. Bütün profil məlumatlarınızı siləcək iş profili silinəcəkdir."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Siz kilidi açmaq üçün şablonu <xliff:g id="NUMBER_0">%d</xliff:g> dəfə səhv çəkdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> daha uğursuz cəhddən sonra planşetinizin kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> saniyə ərzində bir daha yoxlayın."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Siz artıq modeli <xliff:g id="NUMBER_0">%d</xliff:g> dəfə yanlış daxil etmisiniz.<xliff:g id="NUMBER_1">%d</xliff:g> dəfə də yanlış daxil etsəniz, telefonun kilidinin açılması üçün elektron poçt ünvanınız tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> saniyə ərzində yenidən cəhd edin."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Siz kilidi açmaq üçün şablonu <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə səhv çəkdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> daha uğursuz cəhddən sonra planşetinizin kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə ərzində bir daha yoxlayın."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Siz artıq modeli <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış daxil etmisiniz.<xliff:g id="NUMBER_1">%2$d</xliff:g> dəfə də yanlış daxil etsəniz, telefonun kilidinin açılması üçün elektron poçt ünvanınız tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə ərzində yenidən cəhd edin."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Yanlış SIM PIN kodu  cihazınızın açılması üçün operatorunuzla indi əlaqə saxlamalısınız."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">Yanlış SIM PIN kodu, <xliff:g id="NUMBER_1">%d</xliff:g> cəhdiniz qalır.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Təyyarə rejimi"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Cihazı yenidən başladarkən nümunə kod tələb olunur."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Cihazı yenidən başladarkən PIN kod tələb olunur."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Cihazı yenidən başladarkən parol tələb olunur."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Əlavə təhlükəsizlik üçün model tələb olunur."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Əlavə təhlükəsizlik üçün PIN tələb olunur."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Əlavə təhlükəsizlik üçün parol tələb olunur."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Profillər arasında keçid edərkən nümunə kod tələb olunur."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Profillər arasında keçid edərkən PIN kod tələb olunur."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Profillər arasında keçid edərkən parol tələb olunur."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Cihaz yeniden başladıqdan sonra parol tələb olunur"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Əlavə təhlükəsizlik üçün qəlib tələb olunur"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Əlavə təhlükəsizlik üçün PIN tələb olunur"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Əlavə təhlükəsizlik üçün parol tələb olunur"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Profillər arasında keçid edərkən qəlib kod tələb olunur"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Profillər arasında keçid edərkən PIN kod tələb olunur"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Profillər arasında keçid edərkən parol tələb olunur"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">Cihaz <xliff:g id="NUMBER_1">%d</xliff:g> saat kiliddən çıxarılmayıb. Nümunə kodu təsdiq edin.</item>
       <item quantity="one">Cihaz <xliff:g id="NUMBER_0">%d</xliff:g> saat kiliddən çıxarılmayıb. Nümunə kodu təsdiq edin.</item>
diff --git a/packages/Keyguard/res/values-b+sr+Latn/strings.xml b/packages/Keyguard/res/values-b+sr+Latn/strings.xml
index a9a6b90..0eb4210 100644
--- a/packages/Keyguard/res/values-b+sr+Latn/strings.xml
+++ b/packages/Keyguard/res/values-b+sr+Latn/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Ponovo unesite ispravni 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 podudaraju"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Previše pokušaja unosa šablona"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Uneli ste netačni PIN <xliff:g id="NUMBER_0">%d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> sekunde(i)."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Uneli ste netačnu lozinku <xliff:g id="NUMBER_0">%d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> sekunde(i)."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> sekunde(i)."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%d</xliff:g> put(a). Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj(a), nakon čega se tablet resetuje i svi podaci sa njega brišu."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%d</xliff:g> put(a). Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj(a), nakon čega se telefon resetuje i svi podaci sa njega brišu."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Uneli ste netačni PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Uneli ste netačnu lozinku <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> put(a). Imate još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaj(a), nakon čega se tablet resetuje i svi podaci sa njega brišu."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> put(a). Imate još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaj(a), nakon čega se telefon resetuje i svi podaci sa njega brišu."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> put(a). Tablet će biti resetovan i svi podaci sa njega će biti izbrisani."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> put(a). Telefon će biti resetovan i svi podaci sa njega će biti izbrisani."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%d</xliff:g> put(a). Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj(a), nakon čega se ovaj korisnik uklanja i svi podaci korisnika brišu."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%d</xliff:g> put(a). Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj(a), nakon čega se ovaj korisnik uklanja i svi podaci korisnika brišu."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> put(a). Imate još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaj(a), nakon čega se ovaj korisnik uklanja i svi podaci korisnika brišu."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> put(a). Imate još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaj(a), nakon čega se ovaj korisnik uklanja i svi podaci korisnika brišu."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> put(a). Ovaj korisnik će biti uklonjen i svi podaci korisnika će biti izbrisani."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> put(a). Ovaj korisnik će biti uklonjen i svi podaci korisnika će biti izbrisani."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%d</xliff:g> put(a). Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj(a), nakon čega se poslovni profil uklanja i svi podaci sa profila brišu."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%d</xliff:g> put(a). Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj(a), nakon čega se poslovni profil uklanja i svi podaci sa profila brišu."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> put(a). Imate još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaj(a), nakon čega se poslovni profil uklanja i svi podaci sa profila brišu."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> put(a). Imate još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaj(a), nakon čega se poslovni profil uklanja i svi podaci sa profila brišu."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> put(a). Poslovni profil će biti uklonjen i svi podaci sa njega će biti izbrisani."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> put(a). Poslovni profil će biti uklonjen i svi podaci sa njega će biti izbrisani."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate tablet pomoću naloga e-pošte.\n\nPokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> sekunde(i)."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate telefon pomoću naloga e-pošte.\n\nPokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> sekunde(i)."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate tablet pomoću naloga e-pošte.\n\nPokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate telefon pomoću naloga e-pošte.\n\nPokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Netačan SIM PIN kôd. Sada morate da kontaktirate mobilnog operatera da biste otključali uređaj."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">Netačan SIM PIN kôd. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj.</item>
@@ -112,15 +112,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Režim rada u avionu"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Šablon je obavezan kada ponovo pokrećete uređaj."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"PIN je obavezan kada ponovo pokrećete uređaj."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Lozinka je obavezna kada ponovo pokrećete uređaj."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Potreban je šablon radi dodatne bezbednosti."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Potreban je PIN radi dodatne bezbednosti."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Potrebna je lozinka radi dodatne bezbednosti."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Šablon je obavezan kada prelazite sa jednog profila na drugi."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"PIN je obavezan kada prelazite sa jednog profila na drugi."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Lozinka je obavezna kada prelazite sa jednog profila na drugi."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Treba da uneste lozinku kada se uređaj ponovo pokrene"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Treba da unesete šablon radi dodatne bezbednosti"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Treba da unesete PIN radi dodatne bezbednosti"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Treba da unesete lozinku radi dodatne bezbednosti"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Treba da unesete šablon kada prelazite sa jednog profila na drugi"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Treba da unesete PIN kada prelazite sa jednog profila na drugi"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Treba da unesete lozinku kada prelazite sa jednog profila na drugi"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="one">Niste otključali uređaj <xliff:g id="NUMBER_1">%d</xliff:g> sat. Potvrdite šablon.</item>
       <item quantity="few">Niste otključali uređaj <xliff:g id="NUMBER_1">%d</xliff:g> sata. Potvrdite šablon.</item>
diff --git a/packages/Keyguard/res/values-bg/strings.xml b/packages/Keyguard/res/values-bg/strings.xml
index 7fbf46a..ae95c49 100644
--- a/packages/Keyguard/res/values-bg/strings.xml
+++ b/packages/Keyguard/res/values-bg/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Въведете отново правилния PUK код. Многократните опити ще деактивират за постоянно SIM картата."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ПИН кодовете не съвпадат"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Опитите за фигурата са твърде много"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Въведохте неправилно ПИН кода си <xliff:g id="NUMBER_0">%d</xliff:g> пъти. \n\nОпитайте отново след <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Въведохте неправилно паролата си <xliff:g id="NUMBER_0">%d</xliff:g> пъти. \n\nОпитайте отново след <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%d</xliff:g> пъти. \n\nОпитайте отново след <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Неправилно опитахте да отключите таблета <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита той ще бъде нулиран, при което ще се изтрият всичките му данни."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Неправилно опитахте да отключите телефона <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита той ще бъде нулиран, при което ще се изтрият всичките му данни."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Въведохте неправилно ПИН кода си <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">"Начертахте неправилно фигурата си за отключване <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">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита този потребител ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Неправилно опитахте да отключите телефона <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита този потребител ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита служебният потребителски профил ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Неправилно опитахте да отключите телефона <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита служебният потребителски профил ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
+    <string name="kg_failed_attempts_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">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита ще бъдете помолени да отключите таблета посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%d</xliff:g> секунди."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита ще бъдете помолени да отключите телефона посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%d</xliff:g> секунди."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита ще бъдете помолени да отключите таблета посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита ще бъдете помолени да отключите телефона посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Неправилен ПИН код за SIM картата – сега трябва да се свържете с оператора си, за да отключите устройството."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">Неправилен ПИН код за SIM картата – остават ви <xliff:g id="NUMBER_1">%d</xliff:g> опита.</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Няма покритие."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Бутон за превключване на метода на въвеждане."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Самолетен режим"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"При рестартиране на устройството ви се изисква фигура."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"При рестартиране на устройството ви се изисква ПИН код."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"При рестартиране на устройството ви се изисква парола."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"За допълнителна сигурност се изисква фигура."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"За допълнителна сигурност се изисква ПИН."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"За допълнителна сигурност се изисква парола."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"При превключване между потребителските профили се изисква фигура."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"При превключване между потребителските профили се изисква ПИН код."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"При превключване между потребителските профили се изисква парола."</string>
+    <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"След рестартиране на устройството се изисква фигура"</string>
+    <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"След рестартиране на устройството се изисква ПИН код"</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">"За допълнителна сигурност се изисква ПИН код"</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">"При превключване между потребителските профили се изисква ПИН код"</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="other">Устройството не е отключвано от <xliff:g id="NUMBER_1">%d</xliff:g> часа. Потвърдете фигурата.</item>
       <item quantity="one">Устройството не е отключвано от <xliff:g id="NUMBER_0">%d</xliff:g> час. Потвърдете фигурата.</item>
diff --git a/packages/Keyguard/res/values-bn-rBD/strings.xml b/packages/Keyguard/res/values-bn-rBD/strings.xml
index 83ca30e..1dd8af8 100644
--- a/packages/Keyguard/res/values-bn-rBD/strings.xml
+++ b/packages/Keyguard/res/values-bn-rBD/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"সঠিক PUK কোড পুনরায় লিখুন৷ বার বার প্রচেষ্টা করা হলে তা স্থায়ীভাবে সিমটিকে অক্ষম করে দেবে৷"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"পিন কোডগুলি মিলছে না"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"বিভিন্ন প্যাটার্নের সাহায্যে খুব বেশি বার প্রচেষ্টা করা হয়ে গেছে"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"আপনি আপনার পাসওয়ার্ড <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল টাইপ করেছেন৷ \n\n<xliff:g id="NUMBER_1">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"আপনি আপনার পাসওয়ার্ড <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল টাইপ করেছেন৷ \n\n<xliff:g id="NUMBER_1">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"আপনি আপনার আনলকের প্যাটার্ন আঁকার ক্ষেত্রে <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল করেছেন৷ \n\n<xliff:g id="NUMBER_1">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"আপনি <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল করে ট্যাবলেট আনলক করার চেষ্টা করেছেন৷ <xliff:g id="NUMBER_1">%d</xliff:g>টি অসফল প্রচেষ্টার পরে, এই ট্যাবলেটটিকে পুনরায় সেট করা হবে যা এটির সমস্ত ডেটা মুছে ফেলবে৷"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"আপনি <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল করে ফোন আনলক করার চেষ্টা করেছেন৷ <xliff:g id="NUMBER_1">%d</xliff:g>টি অসফল প্রচেষ্টার পরে, এই ফোনটিকে পুনরায় সেট করা হবে যা এটির সমস্ত ডেটা মুছে ফেলবে৷"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"আপনি আপনার পাসওয়ার্ড <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">"আপনি আপনার আনলকের প্যাটার্ন আঁকার ক্ষেত্রে <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">%d</xliff:g> বার ভুল করে ট্যাবলেট আনলক করার চেষ্টা করেছেন৷ <xliff:g id="NUMBER_1">%d</xliff:g>টি অসফল প্রচেষ্টার পরে, এই ব্যবহারকারীকে সরানো হবে যা সমস্ত ব্যবহারকারীর ডেটা মুছে ফেলবে৷"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"আপনি <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল করে ফোন আনলক করার চেষ্টা করেছেন৷ <xliff:g id="NUMBER_1">%d</xliff:g>টি অসফল প্রচেষ্টার পরে, এই ব্যবহারকারীকে সরানো হবে যা সমস্ত ব্যবহারকারীর ডেটা মুছে ফেলবে৷"</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> বার ভুল করে ট্যাবলেট আনলক করার চেষ্টা করেছেন৷ <xliff:g id="NUMBER_1">%d</xliff:g>টি অসফল প্রচেষ্টার পরে, কাজের প্রোফাইল সরানো হবে যা সমস্ত প্রোফাইল ডেটা মুছে ফেলবে৷"</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"আপনি <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল করে ফোন আনলক করার চেষ্টা করেছেন৷ <xliff:g id="NUMBER_1">%d</xliff:g>টি অসফল প্রচেষ্টার পরে, কাজের প্রোফাইল সরানো হবে যা সমস্ত প্রোফাইল ডেটা মুছে ফেলবে৷"</string>
+    <string name="kg_failed_attempts_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">"আপনি আপনার আনলকের প্যাটার্ন আঁকার ক্ষেত্রে <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল করেছেন৷ আর <xliff:g id="NUMBER_1">%d</xliff:g> বার অসফল প্রচেষ্টা করা হলে আপনাকে একটি ইমেল অ্যাকাউন্ট মারফত আপনার ট্যাবলেট আনলক করতে বলা হবে৷\n\n <xliff:g id="NUMBER_2">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"আপনি আপনার আনলকের প্যাটার্ন আঁকার ক্ষেত্রে <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল করেছেন৷ আর <xliff:g id="NUMBER_1">%d</xliff:g> বার অসফল প্রচেষ্টা করা হলে আপনাকে একটি ইমেল অ্যাকাউন্ট মারফত আপনার ফোন আনলক করতে বলা হবে৷\n\n <xliff:g id="NUMBER_2">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"আপনি আপনার আনলকের প্যাটার্ন আঁকার ক্ষেত্রে <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুল করেছেন৷ আর <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টা করা হলে আপনাকে একটি ইমেল অ্যাকাউন্ট মারফত আপনার ট্যাবলেট আনলক করতে বলা হবে৷\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"আপনি আপনার আনলকের প্যাটার্ন আঁকার ক্ষেত্রে <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুল করেছেন৷ আর <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টা করা হলে আপনাকে একটি ইমেল অ্যাকাউন্ট মারফত আপনার ফোন আনলক করতে বলা হবে৷\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"ভুল সিম পিন কোড, আপনার ডিভাইসটি আনলক করতে এখন আপনাকে অবশ্যই আপনার ক্যারিয়ারের সাথে যোগাযোগ করতে হবে৷"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">ভুল SIM পিন কোড, আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে৷</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"কোনো পরিষেবা নেই৷"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ইনপুট পদ্ধতির বোতাম পরিবর্তন করুন৷"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"বিমান মোড"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"যখন আপনি ডিভাইস পুনর্সূচনা করবেন তখন প্যাটার্নের প্রয়োজন হবে৷"</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"যখন আপনি ডিভাইস পুনর্সূচনা করবেন তখন পিন এর প্রয়োজন হবে৷"</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"যখন আপনি ডিভাইস পুনর্সূচনা করবেন তখন পাসওয়ার্ডের প্রয়োজন হবে৷"</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"অতিরিক্ত সুরক্ষার জন্য প্যাটার্ন প্রয়োজন৷"</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"অতিরিক্ত সুরক্ষার জন্য PIN প্রয়োজন৷"</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"অতিরিক্ত সুরক্ষার জন্য পাসওয়ার্ড প্রয়োজন৷"</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"যখন আপনি প্রোফাইলগুলি পাল্টাবেন তখন প্যাটার্নের প্রয়োজন হবে৷"</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"যখন আপনি প্রোফাইলগুলি পাল্টাবেন তখন পিন এর প্রয়োজন হবে৷"</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"যখন আপনি প্রোফাইলগুলি পাল্টাবেন তখন পাসওয়ার্ডের প্রয়োজন হবে৷"</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="other">ডিভাইস <xliff:g id="NUMBER_1">%d</xliff:g> ঘন্টার জন্য আনলক করা হয়নি। প্যাটার্ন নিশ্চিত করুন।</item>
diff --git a/packages/Keyguard/res/values-ca/strings.xml b/packages/Keyguard/res/values-ca/strings.xml
index 42ae52e..70e9fd1 100644
--- a/packages/Keyguard/res/values-ca/strings.xml
+++ b/packages/Keyguard/res/values-ca/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Torna a introduir el codi PUK correcte. Els intents repetits faran que es desactivi la SIM de manera permanent."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Els codis PIN no coincideixen"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Massa intents incorrectes"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Has escrit malament el PIN <xliff:g id="NUMBER_0">%d</xliff:g> vegades. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Has escrit malament la contrasenya <xliff:g id="NUMBER_0">%d</xliff:g> vegades. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Has dibuixat el patró de desbloqueig de manera incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> vegades. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Has provat de desbloquejar la tauleta incorrectament <xliff:g id="NUMBER_0">%d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%d</xliff:g> intents més. Si no ho fas bé, la tauleta es restablirà i se n\'esborraran totes les dades."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Has provat de desbloquejar el telèfon incorrectament <xliff:g id="NUMBER_0">%d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%d</xliff:g> intents més. Si no ho fas bé, el telèfon es restablirà i se n\'esborraran totes les dades."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Has escrit malament el PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%2$d</xliff:g> segons."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Has escrit malament la contrasenya <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%2$d</xliff:g> segons."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Has dibuixat el patró de desbloqueig de manera incorrecta <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%2$d</xliff:g> segons."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Has provat de desbloquejar la tauleta incorrectament <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%2$d</xliff:g> intents més. Si no ho fas bé, la tauleta es restablirà i se n\'esborraran totes les dades."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Has provat de desbloquejar el telèfon incorrectament <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%2$d</xliff:g> intents més. Si no ho fas bé, el telèfon es restablirà i se n\'esborraran totes les dades."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Has provat de desbloquejar la tauleta incorrectament <xliff:g id="NUMBER">%d</xliff:g> vegades. La tauleta es restablirà i se n\'esborraran totes les dades."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Has provat de desbloquejar el telèfon incorrectament <xliff:g id="NUMBER">%d</xliff:g> vegades. El telèfon es restablirà i se n\'esborraran totes les dades."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Has provat de desbloquejar la tauleta incorrectament <xliff:g id="NUMBER_0">%d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%d</xliff:g> intents més. Si no ho fas bé, l\'usuari se suprimirà, juntament amb totes les seves dades."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Has provat de desbloquejar el telèfon incorrectament <xliff:g id="NUMBER_0">%d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%d</xliff:g> intents més. Si no ho fas bé, l\'usuari se suprimirà, juntament amb totes les seves dades."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Has provat de desbloquejar la tauleta incorrectament <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%2$d</xliff:g> intents més. Si no ho fas bé, l\'usuari se suprimirà, juntament amb totes les seves dades."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Has provat de desbloquejar el telèfon incorrectament <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%2$d</xliff:g> intents més. Si no ho fas bé, l\'usuari se suprimirà, juntament amb totes les seves dades."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Has provat de desbloquejar la tauleta incorrectament <xliff:g id="NUMBER">%d</xliff:g> vegades. L\'usuari se suprimirà, juntament amb totes les seves dades."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Has provat de desbloquejar el telèfon incorrectament <xliff:g id="NUMBER">%d</xliff:g> vegades. L\'usuari se suprimirà, juntament amb totes les seves dades."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Has provat de desbloquejar la tauleta incorrectament <xliff:g id="NUMBER_0">%d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%d</xliff:g> intents més. Si no ho fas bé, el perfil professional se suprimirà, juntament amb totes les dades que contingui."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Has provat de desbloquejar el telèfon incorrectament <xliff:g id="NUMBER_0">%d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%d</xliff:g> intents més. Si no ho fas bé, el perfil professional se suprimirà, juntament amb totes les dades que contingui."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Has provat de desbloquejar la tauleta incorrectament <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%2$d</xliff:g> intents més. Si no ho fas bé, el perfil professional se suprimirà, juntament amb totes les dades que contingui."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Has provat de desbloquejar el telèfon incorrectament <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%2$d</xliff:g> intents més. Si no ho fas bé, el perfil professional se suprimirà, juntament amb totes les dades que contingui."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Has provat de desbloquejar la tauleta incorrectament <xliff:g id="NUMBER">%d</xliff:g> vegades. El perfil professional se suprimirà, juntament amb totes les dades que contingui."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Has provat de desbloquejar el telèfon incorrectament <xliff:g id="NUMBER">%d</xliff:g> vegades. El perfil professional se suprimirà, juntament amb totes les dades que contingui."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%d</xliff:g> vegades més, se\'t demanarà que desbloquegis la tauleta amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%d</xliff:g> segons."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%d</xliff:g> vegades més, se\'t demanarà que desbloquegis el telèfon amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%d</xliff:g> segons."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, se\'t demanarà que desbloquegis la tauleta amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%3$d</xliff:g> segons."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, se\'t demanarà que desbloquegis el telèfon amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%3$d</xliff:g> segons."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"El codi PIN de la SIM no és correcte. Has de contactar amb l\'operador de telefonia mòbil per desbloquejar el dispositiu."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">El codi PIN de la SIM no és correcte. Et queden <xliff:g id="NUMBER_1">%d</xliff:g> intents.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Mode d\'avió"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Cal introduir el patró en reiniciar el dispositiu."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Cal introduir el PIN en reiniciar el dispositiu."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Cal introduir la contrasenya en reiniciar el dispositiu."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"El patró és necessari per disposar de més seguretat."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"El PIN és necessari per disposar de més seguretat."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"La contrasenya és necessària per disposar de més seguretat."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Cal introduir el patró en canviar de perfil."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Cal introduir el PIN en canviar de perfil."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Cal introduir la contrasenya en canviar de perfil."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Cal introduir la contrasenya quan es reinicia el dispositiu"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Cal introduir el patró per disposar de més seguretat"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Cal introduir el PIN per disposar de més seguretat"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Cal introduir la contrasenya per disposar de més seguretat"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Cal introduir el patró en canviar de perfil"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Cal introduir el PIN en canviar de perfil"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Cal introduir la contrasenya en canviar de perfil"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">Fa <xliff:g id="NUMBER_1">%d</xliff:g> hores que no es desbloqueja el dispositiu. Confirma el patró.</item>
       <item quantity="one">Fa <xliff:g id="NUMBER_0">%d</xliff:g> hora que no es desbloqueja el dispositiu. Confirma el patró.</item>
diff --git a/packages/Keyguard/res/values-cs/strings.xml b/packages/Keyguard/res/values-cs/strings.xml
index 23e1420..96944cf 100644
--- a/packages/Keyguard/res/values-cs/strings.xml
+++ b/packages/Keyguard/res/values-cs/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Znovu zadejte správný kód PUK. Opakovanými pokusy SIM kartu trvale deaktivujete."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kódy PIN se neshodují."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Příliš mnoho pokusů o nakreslení gesta"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste zadali nesprávný kód PIN. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně zadali heslo. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste zadali nesprávné bezpečnostní gesto. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Již jste se <xliff:g id="NUMBER_0">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech bude tablet resetován, čímž se z něj smažou všechna data."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Již jste se <xliff:g id="NUMBER_0">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech bude telefon resetován, čímž se z něj smažou všechna data."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste zadali nesprávný kód PIN. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně zadali heslo. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste zadali nesprávné bezpečnostní gesto. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Již jste se <xliff:g id="NUMBER_0">%1$d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech bude tablet resetován, čímž se z něj smažou všechna data."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Již jste se <xliff:g id="NUMBER_0">%1$d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech bude telefon resetován, čímž se z něj smažou všechna data."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Tablet bude resetován, čímž z něj budou smazána všechna data."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Telefon bude resetován, čímž z něj budou smazána všechna data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Již jste se <xliff:g id="NUMBER_0">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech bude tento uživatel odstraněn, čímž se smažou všechna jeho data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Již jste se <xliff:g id="NUMBER_0">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech bude tento uživatel odstraněn, čímž se smažou všechna jeho data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Již jste se <xliff:g id="NUMBER_0">%1$d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech bude tento uživatel odstraněn, čímž se smažou všechna jeho data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Již jste se <xliff:g id="NUMBER_0">%1$d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech bude tento uživatel odstraněn, čímž se smažou všechna jeho data."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Uživatel bude odstraněn, čímž budou smazána všechna jeho data."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Uživatel bude odstraněn, čímž budou smazána všechna jeho data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Již jste se <xliff:g id="NUMBER_0">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech bude pracovní profil odstraněn, čímž se smažou všechna jeho data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Již jste se <xliff:g id="NUMBER_0">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech bude pracovní profil odstraněn, čímž se smažou všechna jeho data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Již jste se <xliff:g id="NUMBER_0">%1$d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech bude pracovní profil odstraněn, čímž se smažou všechna jeho data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Již jste se <xliff:g id="NUMBER_0">%1$d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech bude pracovní profil odstraněn, čímž se smažou všechna jeho data."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Pracovní profil bude odstraněn, čímž budou smazána všechna jeho data."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Pracovní profil bude odstraněn, čímž budou smazána všechna jeho data."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%d</xliff:g>dalších neúspěšných pokusech budete požádáni o odemčení tabletu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech budete požádáni o odemčení telefonu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%2$d</xliff:g>dalších neúspěšných pokusech budete požádáni o odemčení tabletu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech budete požádáni o odemčení telefonu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Zadali jste nesprávný kód PIN SIM karty. Nyní musíte za účelem odemknutí zařízení kontaktovat svého operátora."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="few">Zadali jste nesprávný kód PIN SIM karty. Máte ještě <xliff:g id="NUMBER_1">%d</xliff:g> pokusy.</item>
@@ -114,15 +114,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Režim Letadlo"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Po restartu zařízení je vyžadováno gesto."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Po restartu zařízení je vyžadován PIN."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Po restartu zařízení je vyžadováno heslo."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Za účelem zvýšení zabezpečení je vyžadováno gesto."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Za účelem zvýšení zabezpečení je vyžadován kód PIN."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Za účelem zvýšení zabezpečení je vyžadováno heslo."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Po přepnutí profilů je vyžadováno gesto."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Po přepnutí profilů je vyžadován PIN."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Po přepnutí profilů je vyžadováno heslo."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Po restartování zařízení je vyžadováno heslo"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Za účelem zvýšení zabezpečení je vyžadováno gesto"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Za účelem zvýšení zabezpečení je vyžadován kód PIN"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Za účelem zvýšení zabezpečení je vyžadováno heslo"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Po přepnutí profilů je vyžadováno gesto"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Po přepnutí profilů je vyžadován kód PIN"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Po přepnutí profilů je vyžadováno heslo"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="few">Zařízení již <xliff:g id="NUMBER_1">%d</xliff:g> hodiny nebylo odemknuto. Potvrďte gesto.</item>
       <item quantity="many">Zařízení již <xliff:g id="NUMBER_1">%d</xliff:g> hodiny nebylo odemknuto. Potvrďte gesto.</item>
diff --git a/packages/Keyguard/res/values-da/strings.xml b/packages/Keyguard/res/values-da/strings.xml
index 2c39241..5ce1ef0 100644
--- a/packages/Keyguard/res/values-da/strings.xml
+++ b/packages/Keyguard/res/values-da/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Indtast den korrekte PUK-kode. Gentagne forsøg vil permanent deaktivere SIM-kortet."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Pinkoderne stemmer ikke overens"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"For mange forsøg på at tegne mønstret korrekt"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har indtastet en forkert pinkode <xliff:g id="NUMBER_0">%d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har indtastet din adgangskode forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Du har forsøgt at låse tabletten forkert op <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%d</xliff:g> mislykkede forsøg nulstilles denne tablet, hvilket vil slette alle dens data."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Du har forsøgt at låse telefonen forkert op <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%d</xliff:g> mislykkede forsøg nulstilles denne telefon, hvilket vil slette alle dens data."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har indtastet en forkert pinkode <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har indtastet din adgangskode forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Du har forsøgt at låse tabletten forkert op <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg nulstilles denne tablet, hvilket vil slette alle dens data."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Du har forsøgt at låse telefonen forkert op <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg nulstilles denne telefon, hvilket vil slette alle dens data."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Du har forsøgt at låse tabletten forkert op <xliff:g id="NUMBER">%d</xliff:g> gange. Tabletten nulstilles, hvilket vil slette alle dens data."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Du har forsøgt at låse telefonen forkert op <xliff:g id="NUMBER">%d</xliff:g> gange. Telefonen nulstilles, hvilket vil slette alle dens data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Du har forsøgt at låse tabletten forkert op <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%d</xliff:g> mislykkede forsøg fjernes denne bruger, hvilket vil slette alle brugerdata."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Du har forsøgt at låse telefonen forkert op <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%d</xliff:g> mislykkede forsøg fjernes denne bruger, hvilket vil slette alle brugerdata."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Du har forsøgt at låse tabletten forkert op <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg fjernes denne bruger, hvilket vil slette alle brugerdata."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Du har forsøgt at låse telefonen forkert op <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg fjernes denne bruger, hvilket vil slette alle brugerdata."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Du har forsøgt at låse tabletten forkert op <xliff:g id="NUMBER">%d</xliff:g> gange. Brugeren fjernes, hvilket vil slette alle brugerdata."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Du har forsøgt at låse telefonen forkert op <xliff:g id="NUMBER">%d</xliff:g> gange. Brugeren fjernes, hvilket vil slette alle brugerdata."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Du har forsøgt at låse tabletten forkert op <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%d</xliff:g> mislykkede forsøg fjernes arbejdsprofilen, hvilket vil slette alle profildata."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Du har forsøgt at låse telefonen forkert op <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%d</xliff:g> mislykkede forsøg fjernes arbejdsprofilen, hvilket vil slette alle profildata."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Du har forsøgt at låse tabletten forkert op <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg fjernes arbejdsprofilen, hvilket vil slette alle profildata."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Du har forsøgt at låse telefonen forkert op <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg fjernes arbejdsprofilen, hvilket vil slette alle profildata."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Du har forsøgt at låse tabletten forkert op <xliff:g id="NUMBER">%d</xliff:g> gange. Arbejdsprofilen fjernes, hvilket vil slette alle profildata."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Du har forsøgt at låse telefonen forkert op <xliff:g id="NUMBER">%d</xliff:g> gange. Arbejdsprofilen fjernes, hvilket vil slette alle profildata."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg vil du blive bedt om at låse din tablet op ved hjælp af en e-mailkonto\n\n Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg til vil du blive bedt om at låse din telefon op ved hjælp af en e-mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%2$d</xliff:g> yderligere mislykkede forsøg vil du blive bedt om at låse din tablet op ved hjælp af en e-mailkonto\n\n Prøv igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%2$d</xliff:g> yderligere mislykkede forsøg til vil du blive bedt om at låse din telefon op ved hjælp af en e-mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Forkert pinkode til SIM-kort. Du skal nu kontakte dit mobilselskab for at låse din enhed op."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">Forkert pinkode til SIM-kort. Du har <xliff:g id="NUMBER_1">%d</xliff:g> forsøg tilbage.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Flytilstand"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Du skal indtaste et mønster, når du genstarter enheden."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Du skal indtaste en pinkode, når du genstarter enheden."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Du skal indtaste en adgangskode, når du genstarter enheden."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Der kræves et mønster som ekstra beskyttelse."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Der kræves en pinkode som ekstra beskyttelse."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Der kræves en adgangskode som ekstra beskyttelse."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Du skal indtaste et mønster, når du skifter profiler."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Du skal indtaste en pinkode, når du skifter profiler."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Du skal indtaste en adgangskode, når du skifter profiler."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Du skal indtaste en adgangskode efter genstart af enheden"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Der kræves et mønster som ekstra beskyttelse"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Der kræves en pinkode som ekstra beskyttelse"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Der kræves en adgangskode som ekstra beskyttelse"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Du skal indtaste et mønster, når du skifter profil"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Du skal indtaste en pinkode, når du skifter profil"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Du skal indtaste en adgangskode, når du skifter profil"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="one">Enheden blev sidst låst op for <xliff:g id="NUMBER_1">%d</xliff:g> timer siden. Bekræft mønsteret.</item>
       <item quantity="other">Enheden blev sidst låst op for <xliff:g id="NUMBER_1">%d</xliff:g> timer siden. Bekræft mønsteret.</item>
diff --git a/packages/Keyguard/res/values-de/strings.xml b/packages/Keyguard/res/values-de/strings.xml
index 737f533..f1fc198 100644
--- a/packages/Keyguard/res/values-de/strings.xml
+++ b/packages/Keyguard/res/values-de/strings.xml
@@ -22,7 +22,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"PIN-Code eingeben"</string>
-    <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Geben Sie den PUK-Code der SIM-Karte und den neuen PIN-Code ein."</string>
+    <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Gib den PUK-Code der SIM-Karte und den neuen PIN-Code ein."</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"PUK-Code der SIM-Karte"</string>
     <string name="keyguard_password_enter_pin_prompt" msgid="3201151840570492538">"Neuer PIN-Code der SIM-Karte"</string>
     <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Zur Passworteingabe berühren"</font></string>
@@ -39,10 +39,10 @@
     <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Keine SIM-Karte"</string>
     <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"Keine SIM-Karte im Tablet"</string>
     <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"Keine SIM-Karte im Telefon"</string>
-    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Legen Sie eine SIM-Karte ein."</string>
-    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM-Karte fehlt oder ist nicht lesbar. Bitte legen Sie eine SIM-Karte ein."</string>
+    <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Lege eine SIM-Karte ein."</string>
+    <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM-Karte fehlt oder ist nicht lesbar. Bitte lege eine SIM-Karte ein."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"SIM-Karte unbrauchbar"</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Ihre SIM-Karte wurde dauerhaft deaktiviert.\n Wenden Sie sich an Ihren Mobilfunkanbieter, um eine andere SIM-Karte zu erhalten."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Deine SIM-Karte wurde dauerhaft deaktiviert.\n Wende dich an deinen Mobilfunkanbieter, um eine andere SIM-Karte zu erhalten."</string>
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM-Karte ist gesperrt."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM-Karte ist gesperrt. PUK-Eingabe erforderlich."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"SIM-Karte wird entsperrt…"</string>
@@ -61,48 +61,48 @@
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Falsches Muster"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Falsches Passwort"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Falsche PIN"</string>
-    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Versuchen Sie es in <xliff:g id="NUMBER">%d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Versuche es in <xliff:g id="NUMBER">%d</xliff:g> Sekunden erneut."</string>
     <string name="kg_pattern_instructions" msgid="398978611683075868">"Muster zeichnen"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM-PIN eingeben"</string>
     <string name="kg_sim_pin_instructions_multi" msgid="7818515973197201434">"SIM-PIN für \"<xliff:g id="CARRIER">%1$s</xliff:g>\" eingeben"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"PIN eingeben"</string>
     <string name="kg_password_instructions" msgid="5753646556186936819">"Passwort eingeben"</string>
-    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Die SIM-Karte ist jetzt deaktiviert. Geben Sie den PUK-Code ein, um fortzufahren. Weitere Informationen erhalten Sie von Ihrem Mobilfunkanbieter."</string>
-    <string name="kg_puk_enter_puk_hint_multi" msgid="363822494559783025">"Die SIM-Karte \"<xliff:g id="CARRIER">%1$s</xliff:g>\" ist jetzt deaktiviert. Geben Sie den PUK-Code ein, um fortzufahren. Weitere Informationen erhalten Sie von Ihrem Mobilfunkanbieter."</string>
+    <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"Die SIM-Karte ist jetzt deaktiviert. Gib den PUK-Code ein, um fortzufahren. Weitere Informationen erhältst du von deinem Mobilfunkanbieter."</string>
+    <string name="kg_puk_enter_puk_hint_multi" msgid="363822494559783025">"Die SIM-Karte \"<xliff:g id="CARRIER">%1$s</xliff:g>\" ist jetzt deaktiviert. Gib den PUK-Code ein, um fortzufahren. Weitere Informationen erhältst du von deinem Mobilfunkanbieter."</string>
     <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Gewünschten PIN-Code eingeben"</string>
     <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Gewünschten PIN-Code bestätigen"</string>
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM-Karte wird entsperrt…"</string>
-    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Geben Sie eine 4- bis 8-stellige PIN ein."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Gib eine 4- bis 8-stellige PIN ein."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"Der PUK-Code muss mindestens 8 Ziffern betragen."</string>
-    <string name="kg_invalid_puk" msgid="3638289409676051243">"Geben Sie den richtigen PUK-Code ein. Bei wiederholten Versuchen wird die SIM-Karte dauerhaft deaktiviert."</string>
+    <string name="kg_invalid_puk" msgid="3638289409676051243">"Gib den richtigen PUK-Code ein. Bei wiederholten Versuchen wird die SIM-Karte dauerhaft deaktiviert."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-Codes stimmen nicht überein"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Zu viele Musterversuche"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Sie haben Ihre PIN <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch eingegeben.\n\nVersuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Sie haben Ihr Passwort <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch eingegeben.\n\nVersuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. \n\nVersuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Sie haben <xliff:g id="NUMBER_0">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen wird dieses Tablet zurückgesetzt. Dadurch werden alle Gerätedaten gelöscht."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Sie haben <xliff:g id="NUMBER_0">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen wird dieses Telefon zurückgesetzt. Dadurch werden alle Gerätedaten gelöscht."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Dieses Tablet wird nun zurückgesetzt und alle Gerätedaten werden gelöscht."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Dieses Telefon wird nun zurückgesetzt und alle Gerätedaten werden gelöscht."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Sie haben <xliff:g id="NUMBER_0">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen wird dieser Nutzer entfernt. Dadurch werden alle Nutzerdaten gelöscht."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Sie haben <xliff:g id="NUMBER_0">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen wird dieser Nutzer entfernt. Dadurch werden alle Nutzerdaten gelöscht."</string>
-    <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Dieser Nutzer wird nun entfernt und alle Nutzerdaten werden gelöscht."</string>
-    <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Dieser Nutzer wird nun entfernt und alle Nutzerdaten werden gelöscht."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Sie haben <xliff:g id="NUMBER_0">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen wird das Arbeitsprofil entfernt. Dadurch werden alle Profildaten gelöscht."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Sie haben <xliff:g id="NUMBER_0">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen wird das Arbeitsprofil entfernt. Dadurch werden alle Profildaten gelöscht."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Das Arbeitsprofil wird nun entfernt und alle Profildaten werden gelöscht."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Das Arbeitsprofil wird nun entfernt und alle Profildaten werden gelöscht."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Tablet mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
-    <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Falscher PIN-Code der SIM-Karte. Bitte wenden Sie sich an Ihren Mobilfunkanbieter, damit er Ihr Gerät entsperrt."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du hast deine PIN <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch eingegeben.\n\nVersuche es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du hast dein Passwort <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch eingegeben.\n\nVersuche es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. \n\nVersuche es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird dieses Tablet zurückgesetzt. Dadurch werden alle Gerätedaten gelöscht."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird dieses Telefon zurückgesetzt. Dadurch werden alle Gerätedaten gelöscht."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Dieses Tablet wird nun zurückgesetzt und alle Gerätedaten werden gelöscht."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Dieses Telefon wird nun zurückgesetzt und alle Gerätedaten werden gelöscht."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird dieser Nutzer entfernt. Dadurch werden alle Nutzerdaten gelöscht."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird dieser Nutzer entfernt. Dadurch werden alle Nutzerdaten gelöscht."</string>
+    <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Dieser Nutzer wird nun entfernt und alle Nutzerdaten werden gelöscht."</string>
+    <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Dieser Nutzer wird nun entfernt und alle Nutzerdaten werden gelöscht."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird das Arbeitsprofil entfernt. Dadurch werden alle Profildaten gelöscht."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird das Arbeitsprofil entfernt. Dadurch werden alle Profildaten gelöscht."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Das Arbeitsprofil wird nun entfernt und alle Profildaten werden gelöscht."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Das Arbeitsprofil wird nun entfernt und alle Profildaten werden gelöscht."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Tablet mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Telefon mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Falscher PIN-Code der SIM-Karte. Bitte wende dich an deinen Mobilfunkanbieter, damit er dein Gerät entsperrt."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
-      <item quantity="other">Falscher PIN-Code der SIM-Karte. Sie haben noch <xliff:g id="NUMBER_1">%d</xliff:g> Versuche.</item>
-      <item quantity="one">Falscher PIN-Code der SIM-Karte. Sie haben noch <xliff:g id="NUMBER_0">%d</xliff:g> Versuch, bevor Sie das Gerät von Ihrem Mobilfunkanbieter entsperren lassen müssen.</item>
+      <item quantity="other">Falscher PIN-Code der SIM-Karte. Du hast noch <xliff:g id="NUMBER_1">%d</xliff:g> Versuche.</item>
+      <item quantity="one">Falscher PIN-Code der SIM-Karte. Du hast noch <xliff:g id="NUMBER_0">%d</xliff:g> Versuch, bevor du das Gerät von deinem Mobilfunkanbieter entsperren lassen musst.</item>
     </plurals>
-    <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"Die SIM-Karte kann nicht verwendet werden. Bitte wenden Sie sich an Ihren Mobilfunkanbieter."</string>
+    <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"Die SIM-Karte kann nicht verwendet werden. Bitte wende dich an deinen Mobilfunkanbieter."</string>
     <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
-      <item quantity="other">Falscher PUK-Code der SIM-Karte. Sie haben noch <xliff:g id="NUMBER_1">%d</xliff:g> Versuche, bevor Ihre SIM-Karte endgültig gesperrt wird.</item>
-      <item quantity="one">Falscher PUK-Code der SIM-Karte. Sie haben noch <xliff:g id="NUMBER_0">%d</xliff:g> Versuch, bevor Ihre SIM-Karte endgültig gesperrt wird.</item>
+      <item quantity="other">Falscher PUK-Code der SIM-Karte. Du hast noch <xliff:g id="NUMBER_1">%d</xliff:g> Versuche, bevor deine SIM-Karte endgültig gesperrt wird.</item>
+      <item quantity="one">Falscher PUK-Code der SIM-Karte. Du hast noch <xliff:g id="NUMBER_0">%d</xliff:g> Versuch, bevor deine SIM-Karte endgültig gesperrt wird.</item>
     </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Fehler beim Entsperren mit der PIN der SIM-Karte"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Fehler beim Entsperren mithilfe des PUK-Codes der SIM-Karte"</string>
@@ -110,26 +110,26 @@
     <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="airplane_mode" msgid="3122107900897202805">"Flugmodus"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Beim Neustart des Geräts ist die Eingabe des Musters erforderlich."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Beim Neustart des Geräts ist die Eingabe der PIN erforderlich."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Beim Neustart des Geräts ist die Eingabe des Passworts erforderlich."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Zur Verbesserung der Sicherheit ist ein Muster erforderlich."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Zur Verbesserung der Sicherheit ist eine PIN erforderlich."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Zur Verbesserung der Sicherheit ist ein Passwort erforderlich."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Beim Profilwechsel ist die Eingabe des Musters erforderlich."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Beim Profilwechsel ist die Eingabe der PIN erforderlich."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Beim Profilwechsel ist die Eingabe des Passworts erforderlich."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Nach dem Neustart des Geräts ist die Eingabe des Passworts erforderlich."</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Zur Verbesserung der Sicherheit ist ein Muster erforderlich."</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Zur Verbesserung der Sicherheit ist eine PIN erforderlich."</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Zur Verbesserung der Sicherheit ist ein Passwort erforderlich."</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Beim Profilwechsel ist die Eingabe des Musters erforderlich."</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Beim Profilwechsel ist die Eingabe der PIN erforderlich."</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Beim Profilwechsel ist die Eingabe des Passworts erforderlich."</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
-      <item quantity="other">Das Gerät wurde seit <xliff:g id="NUMBER_1">%d</xliff:g> Stunden nicht mehr entsperrt. Bestätigen Sie das Muster.</item>
-      <item quantity="one">Das Gerät wurde seit <xliff:g id="NUMBER_0">%d</xliff:g> Stunde nicht mehr entsperrt. Bestätigen Sie das Muster.</item>
+      <item quantity="other">Das Gerät wurde seit <xliff:g id="NUMBER_1">%d</xliff:g> Stunden nicht mehr entsperrt. Bestätige das Muster.</item>
+      <item quantity="one">Das Gerät wurde seit <xliff:g id="NUMBER_0">%d</xliff:g> Stunde nicht mehr entsperrt. Bestätige das Muster.</item>
     </plurals>
     <plurals name="kg_prompt_reason_time_pin" formatted="false" msgid="2118758475374354849">
-      <item quantity="other">Das Gerät wurde seit <xliff:g id="NUMBER_1">%d</xliff:g> Stunden nicht mehr entsperrt. Bestätigen Sie die PIN.</item>
-      <item quantity="one">Das Gerät wurde seit <xliff:g id="NUMBER_0">%d</xliff:g> Stunde nicht mehr entsperrt. Bestätigen Sie die PIN.</item>
+      <item quantity="other">Das Gerät wurde seit <xliff:g id="NUMBER_1">%d</xliff:g> Stunden nicht mehr entsperrt. Bestätige die PIN.</item>
+      <item quantity="one">Das Gerät wurde seit <xliff:g id="NUMBER_0">%d</xliff:g> Stunde nicht mehr entsperrt. Bestätige die PIN.</item>
     </plurals>
     <plurals name="kg_prompt_reason_time_password" formatted="false" msgid="5132693663364913675">
-      <item quantity="other">Das Gerät wurde seit <xliff:g id="NUMBER_1">%d</xliff:g> Stunden nicht mehr entsperrt. Bestätigen Sie das Passwort.</item>
-      <item quantity="one">Das Gerät wurde seit <xliff:g id="NUMBER_0">%d</xliff:g> Stunde nicht mehr entsperrt. Bestätigen Sie das Passwort.</item>
+      <item quantity="other">Das Gerät wurde seit <xliff:g id="NUMBER_1">%d</xliff:g> Stunden nicht mehr entsperrt. Bestätige das Passwort.</item>
+      <item quantity="one">Das Gerät wurde seit <xliff:g id="NUMBER_0">%d</xliff:g> Stunde nicht mehr entsperrt. Bestätige das Passwort.</item>
     </plurals>
     <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Nicht erkannt"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-el/strings.xml b/packages/Keyguard/res/values-el/strings.xml
index b915275..535bee8 100644
--- a/packages/Keyguard/res/values-el/strings.xml
+++ b/packages/Keyguard/res/values-el/strings.xml
@@ -77,23 +77,23 @@
     <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">%d</xliff:g> φορές. \n\nΔοκιμάστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτερόλεπτα."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Έχετε πληκτρολογήσει τον κωδικό πρόσβασης εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φορές. \n\nΔοκιμάστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτερόλεπτα."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Σχεδιάσατε εσφαλμένα το μοτίβο ξεκλειδώματος <xliff:g id="NUMBER_0">%d</xliff:g> φορές. \n\nΔοκιμάστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτερόλετπα."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Δοκιμάσατε να ξεκλειδώσετε το tablet <xliff:g id="NUMBER_0">%d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ακόμα ανεπιτυχείς δοκιμές, αυτό το tablet θα ρυθμιστεί εκ νέου, και έτσι θα διαγραφούν όλα τα δεδομένα του."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER_0">%d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ακόμα ανεπιτυχείς δοκιμές, αυτό το τηλέφωνο θα ρυθμιστεί εκ νέου, και έτσι θα διαγραφούν όλα τα δεδομένα του."</string>
+    <string name="kg_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">"Σχεδιάσατε εσφαλμένα το μοτίβο ξεκλειδώματος <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">"Δοκιμάσατε να ξεκλειδώσετε το tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς δοκιμές, αυτό το tablet θα ρυθμιστεί εκ νέου, και έτσι θα διαγραφούν όλα τα δεδομένα του."</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">"Δοκιμάσατε να ξεκλειδώσετε αυτό το tablet <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Αυτό το tablet θα ρυθμιστεί εκ νέου, και έτσι θα διαγραφούν όλα τα δεδομένα του."</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">"Δοκιμάσατε να ξεκλειδώσετε το tablet <xliff:g id="NUMBER_0">%d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ακόμα ανεπιτυχείς δοκιμές, αυτός ο χρήστης θα καταργηθεί, και έτσι θα διαγραφούν όλα τα δεδομένα χρήστη."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER_0">%d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ακόμα ανεπιτυχείς δοκιμές, αυτός ο χρήστης θα καταργηθεί, και έτσι θα διαγραφούν όλα τα δεδομένα χρήστη."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Δοκιμάσατε να ξεκλειδώσετε το tablet <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">"Δοκιμάσατε να ξεκλειδώσετε το tablet <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">"Δοκιμάσατε να ξεκλειδώσετε το tablet <xliff:g id="NUMBER_0">%d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ακόμα ανεπιτυχείς δοκιμές, το προφίλ εργασίας θα καταργηθεί, και έτσι θα διαγραφούν όλα τα δεδομένα προφίλ."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER_0">%d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ακόμα ανεπιτυχείς δοκιμές, το προφίλ εργασίας θα καταργηθεί, και έτσι θα διαγραφούν όλα τα δεδομένα προφίλ."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Δοκιμάσατε να ξεκλειδώσετε το tablet <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">"Δοκιμάσατε να ξεκλειδώσετε το tablet <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Το προφίλ εργασίας θα καταργηθεί, και έτσι θα διαγραφούν όλα τα δεδομένα προφίλ."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Το προφίλ εργασίας θα καταργηθεί, και έτσι θα διαγραφούν όλα τα δεδομένα προφίλ."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το tablet σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε να συνδεθείτε ξανά σε <xliff:g id="NUMBER_2">%d</xliff:g> δευτερόλεπτα."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το τηλέφωνό σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε ξανά σε <xliff:g id="NUMBER_2">%d</xliff:g> δευτερόλεπτα."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το tablet σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε να συνδεθείτε ξανά σε <xliff:g id="NUMBER_2">%3$d</xliff:g> δευτερόλεπτα."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το τηλέφωνό σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\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="other">Λανθασμένος κωδικός PIN κάρτας SIM. Απομένουν άλλες <xliff:g id="NUMBER_1">%d</xliff:g> προσπάθειες. </item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Καμία υπηρεσία."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Κουμπί εναλλαγής μεθόδου εισόδου"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Λειτουργία πτήσης"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Απαιτείται μοτίβο κατά την επανεκκίνηση της συσκευής."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Απαιτείται PIN κατά την επανεκκίνηση της συσκευής."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Απαιτείται κωδικός πρόσβασης κατά την επανεκκίνηση της συσκευής."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Απαιτείται μοτίβο για πρόσθετη ασφάλεια."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Απαιτείται PIN για πρόσθετη ασφάλεια."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Απαιτείται κωδικός πρόσβασης για πρόσθετη ασφάλεια."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Απαιτείται μοτίβο κατά την εναλλαγή προφίλ."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Απαιτείται PIN κατά την εναλλαγή προφίλ."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Απαιτείται κωδικός πρόσβασης κατά την εναλλαγή προφίλ."</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="other">Η συσκευή δεν έχει ξεκλειδωθεί για <xliff:g id="NUMBER_1">%d</xliff:g> ώρες. Επιβεβαιώστε το μοτίβο.</item>
       <item quantity="one">Η συσκευή δεν έχει ξεκλειδωθεί για <xliff:g id="NUMBER_0">%d</xliff:g> ώρα. Επιβεβαιώστε το μοτίβο.</item>
diff --git a/packages/Keyguard/res/values-en-rAU/strings.xml b/packages/Keyguard/res/values-en-rAU/strings.xml
index 0979d9a..63b2137 100644
--- a/packages/Keyguard/res/values-en-rAU/strings.xml
+++ b/packages/Keyguard/res/values-en-rAU/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN codes do not match"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Too many pattern attempts"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This tablet will be reset, which will delete all its data."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This phone will be reset, which will delete all its data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This user will be removed, which will delete all user data."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This user will be removed, which will delete all user data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, the work profile will be removed, which will delete all profile data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, the work profile will be removed, which will delete all profile data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, the work profile will be removed, which will delete all profile data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, the work profile will be removed, which will delete all profile data."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Incorrect SIM PIN code; you must now contact your operator to unlock your device."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">Incorrect SIM PIN code, you have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Aeroplane mode"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Pattern required when you restart device."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"PIN required when you restart device."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Password required when you restart device."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Pattern required for additional security."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"PIN required for additional security."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Password required for additional security."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Pattern required when you switch profiles."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"PIN required when you switch profiles."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Password required when you switch profiles."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Password required after device restarts"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Pattern required for additional security"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"PIN required for additional security"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Password required for additional security"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Pattern required when you switch profiles"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"PIN required when you switch profiles"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Password required when you switch profiles"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">Device hasn\'t been unlocked for <xliff:g id="NUMBER_1">%d</xliff:g> hours. Confirm pattern.</item>
       <item quantity="one">Device hasn\'t been unlocked for <xliff:g id="NUMBER_0">%d</xliff:g> hour. Confirm pattern.</item>
diff --git a/packages/Keyguard/res/values-en-rGB/strings.xml b/packages/Keyguard/res/values-en-rGB/strings.xml
index 0979d9a..63b2137 100644
--- a/packages/Keyguard/res/values-en-rGB/strings.xml
+++ b/packages/Keyguard/res/values-en-rGB/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN codes do not match"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Too many pattern attempts"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This tablet will be reset, which will delete all its data."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This phone will be reset, which will delete all its data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This user will be removed, which will delete all user data."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This user will be removed, which will delete all user data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, the work profile will be removed, which will delete all profile data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, the work profile will be removed, which will delete all profile data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, the work profile will be removed, which will delete all profile data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, the work profile will be removed, which will delete all profile data."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Incorrect SIM PIN code; you must now contact your operator to unlock your device."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">Incorrect SIM PIN code, you have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Aeroplane mode"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Pattern required when you restart device."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"PIN required when you restart device."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Password required when you restart device."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Pattern required for additional security."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"PIN required for additional security."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Password required for additional security."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Pattern required when you switch profiles."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"PIN required when you switch profiles."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Password required when you switch profiles."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Password required after device restarts"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Pattern required for additional security"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"PIN required for additional security"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Password required for additional security"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Pattern required when you switch profiles"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"PIN required when you switch profiles"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Password required when you switch profiles"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">Device hasn\'t been unlocked for <xliff:g id="NUMBER_1">%d</xliff:g> hours. Confirm pattern.</item>
       <item quantity="one">Device hasn\'t been unlocked for <xliff:g id="NUMBER_0">%d</xliff:g> hour. Confirm pattern.</item>
diff --git a/packages/Keyguard/res/values-en-rIN/strings.xml b/packages/Keyguard/res/values-en-rIN/strings.xml
index 0979d9a..63b2137 100644
--- a/packages/Keyguard/res/values-en-rIN/strings.xml
+++ b/packages/Keyguard/res/values-en-rIN/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN codes do not match"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Too many pattern attempts"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This tablet will be reset, which will delete all its data."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This phone will be reset, which will delete all its data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This user will be removed, which will delete all user data."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This user will be removed, which will delete all user data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, the work profile will be removed, which will delete all profile data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, the work profile will be removed, which will delete all profile data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, the work profile will be removed, which will delete all profile data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, the work profile will be removed, which will delete all profile data."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Incorrect SIM PIN code; you must now contact your operator to unlock your device."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">Incorrect SIM PIN code, you have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Aeroplane mode"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Pattern required when you restart device."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"PIN required when you restart device."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Password required when you restart device."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Pattern required for additional security."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"PIN required for additional security."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Password required for additional security."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Pattern required when you switch profiles."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"PIN required when you switch profiles."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Password required when you switch profiles."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Password required after device restarts"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Pattern required for additional security"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"PIN required for additional security"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Password required for additional security"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Pattern required when you switch profiles"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"PIN required when you switch profiles"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Password required when you switch profiles"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">Device hasn\'t been unlocked for <xliff:g id="NUMBER_1">%d</xliff:g> hours. Confirm pattern.</item>
       <item quantity="one">Device hasn\'t been unlocked for <xliff:g id="NUMBER_0">%d</xliff:g> hour. Confirm pattern.</item>
diff --git a/packages/Keyguard/res/values-es-rUS/strings.xml b/packages/Keyguard/res/values-es-rUS/strings.xml
index 0becc66..cf903eb 100644
--- a/packages/Keyguard/res/values-es-rUS/strings.xml
+++ b/packages/Keyguard/res/values-es-rUS/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Vuelve a ingresar el código PUK correcto. Si ingresas un código incorrecto varias veces, se inhabilitará la tarjeta SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Los códigos PIN no coinciden."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Demasiados intentos incorrectos de ingresar el patrón"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Escribiste incorrectamente tu PIN <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Escribiste incorrectamente tu contraseña <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Intentaste desbloquear la tablet <xliff:g id="NUMBER_0">%d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se restablecerá la tablet y se perderán todos los datos."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER_0">%d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se restablecerá el teléfono y se perderán todos los datos."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Escribiste incorrectamente tu PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Escribiste incorrectamente tu contraseña <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Intentaste desbloquear la tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se restablecerá la tablet y se perderán todos los datos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se restablecerá el teléfono y se perderán todos los datos."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Intentaste desbloquear la tablet <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se restablecerá la tablet y se perderán todos los datos."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se restablecerá el teléfono y se perderán todos los datos."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Intentaste desbloquear la tablet <xliff:g id="NUMBER_0">%d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se eliminará el usuario y se perderán todos los datos de usuario."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER_0">%d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se eliminará el usuario y se perderán todos los datos de usuario."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Intentaste desbloquear la tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se eliminará el usuario y se perderán todos los datos de usuario."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se eliminará el usuario y se perderán todos los datos de usuario."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Intentaste desbloquear la tablet <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se eliminará el usuario y se perderán todos los datos de usuario."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se eliminará el usuario y se perderán todos los datos de usuario."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Intentaste desbloquear la tablet <xliff:g id="NUMBER_0">%d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se eliminará el perfil de trabajo y se perderán todos los datos de perfil."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER_0">%d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se eliminará el perfil de trabajo y se perderán todos los datos de perfil."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Intentaste desbloquear la tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se eliminará el perfil de trabajo y se perderán todos los datos de perfil."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se eliminará el perfil de trabajo y se perderán todos los datos de perfil."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Intentaste desbloquear la tablet <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se eliminará el perfil de trabajo y se perderán todos los datos de perfil."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se eliminará el perfil de trabajo y se perderán todos los datos de perfil."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu tablet mediante el uso de una cuenta de correo.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu dispositivo mediante el uso de una cuenta de correo.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu tablet mediante el uso de una cuenta de correo.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu dispositivo mediante el uso de una cuenta de correo.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"El código PIN de la tarjeta SIM es incorrecto. Debes comunicarte con el proveedor para desbloquear el dispositivo."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">El código PIN de la tarjeta SIM es incorrecto. Tienes <xliff:g id="NUMBER_1">%d</xliff:g> intentos más.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Modo de avión"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Se solicita el patrón al reiniciar el dispositivo."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Se solicita el PIN al reiniciar el dispositivo."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Se solicita la contraseña al reiniciar el dispositivo."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Por razones de seguridad, debe resolverse el patrón."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Por razones de seguridad, escribe el PIN."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Por razones de seguridad, ingresa la contraseña."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Se solicita el patrón al cambiar de perfil."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Se solicita el PIN al cambiar de perfil."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Se solicita la contraseña al cambiar de perfil."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Se requiere la contraseña después de reiniciar el dispositivo"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Se requiere el patrón por razones de seguridad"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Se requiere el PIN por razones de seguridad"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Se requiere la contraseña por razones de seguridad"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Se requiere el patrón al cambiar de perfil"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Se requiere el PIN al cambiar de perfil"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Se requiere la contraseña al cambiar de perfil"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">Hace <xliff:g id="NUMBER_1">%d</xliff:g> horas que no se desbloquea el dispositivo. Confirma el patrón.</item>
       <item quantity="one">Hace <xliff:g id="NUMBER_0">%d</xliff:g> hora que no se desbloquea el dispositivo. Confirma el patrón.</item>
diff --git a/packages/Keyguard/res/values-es/strings.xml b/packages/Keyguard/res/values-es/strings.xml
index 6f37d8b..a131cc1 100644
--- a/packages/Keyguard/res/values-es/strings.xml
+++ b/packages/Keyguard/res/values-es/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Vuelve a introducir el código PUK correcto. Si introduces un código incorrecto varias veces, se inhabilitará la tarjeta SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Los códigos PIN no coinciden."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Demasiados intentos incorrectos de crear el patrón"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Has introducido un código PIN incorrecto <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Has introducido una contraseña incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar tu patrón de desbloqueo. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Has intentado desbloquear el tablet de forma incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se restablecerá el tablet, lo que borrará todos sus datos."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se restablecerá el teléfono, lo que borrará todos sus datos."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Has introducido un código PIN incorrecto <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Has introducido una contraseña incorrecta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar tu patrón de desbloqueo. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Has intentado desbloquear el tablet de forma incorrecta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se restablecerá el tablet, lo que borrará todos sus datos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se restablecerá el teléfono, lo que borrará todos sus datos."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Has intentado desbloquear el tablet de forma incorrecta <xliff:g id="NUMBER">%d</xliff:g> veces. Este tablet se eliminará, lo que borrará todos sus datos."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER">%d</xliff:g> veces. Este teléfono se eliminará, lo que borrará todos sus datos."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Has intentado desbloquear el tablet de forma incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se eliminará a este usuario, lo que borrará todos sus datos."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se eliminará a este usuario, lo que borrará todos sus datos."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Has intentado desbloquear el tablet de forma incorrecta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se eliminará a este usuario, lo que borrará todos sus datos."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se eliminará a este usuario, lo que borrará todos sus datos."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Has intentado desbloquear el tablet de forma incorrecta <xliff:g id="NUMBER">%d</xliff:g> veces. Este usuario se eliminará, lo que borrará todos sus datos."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER">%d</xliff:g> veces. Este usuario se eliminará, lo que borrará todos sus datos."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Has intentado desbloquear el tablet de forma incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se eliminará el perfil de trabajo, lo que borrará todos sus datos."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se eliminará el perfil de trabajo, lo que borrará todos sus datos."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Has intentado desbloquear el tablet de forma incorrecta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se eliminará el perfil de trabajo, lo que borrará todos sus datos."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se eliminará el perfil de trabajo, lo que borrará todos sus datos."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Has intentado desbloquear el tablet de forma incorrecta <xliff:g id="NUMBER">%d</xliff:g> veces. El perfil de trabajo se eliminará, lo que borrará todos sus datos."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER">%d</xliff:g> veces. El perfil de trabajo se eliminará, lo que borrará todos sus datos."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el tablet.\n\n Inténtalo de nuevo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el teléfono.\n\n Inténtalo de nuevo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el tablet.\n\n Inténtalo de nuevo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el teléfono.\n\n Inténtalo de nuevo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Código PIN de la tarjeta SIM incorrecto. Debes ponerte en contacto con tu operador para desbloquear el dispositivo."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">Código PIN de la tarjeta SIM incorrecto. Te quedan <xliff:g id="NUMBER_1">%d</xliff:g> intentos.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Modo avión"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Se debe introducir el patrón cuando se reinicia el dispositivo."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Se debe introducir el PIN cuando se reinicia el dispositivo."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Se debe introducir la contraseña cuando se reinicia el dispositivo."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Es necesario introducir el patrón como medida de seguridad adicional."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Es necesario introducir el PIN como medida de seguridad adicional."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Es necesario introducir la contraseña como medida de seguridad adicional."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Se debe introducir el patrón cuando se cambia de perfil."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Se debe introducir el PIN cuando se cambia de perfil."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Se debe introducir la contraseña cuando se cambia de perfil."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Debes introducir la contraseña después de reiniciar el dispositivo"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Debes introducir el patrón como medida de seguridad adicional"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Debes introducir el PIN como medida de seguridad adicional"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Debes introducir la contraseña como medida de seguridad adicional"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Debes introducir el patrón cuando cambies de perfil"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Debes introducir el PIN cuando cambies de perfil"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Debes introducir la contraseña cuando cambies de perfil"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">El dispositivo no se ha desbloqueado durante <xliff:g id="NUMBER_1">%d</xliff:g> horas. Confirma el patrón.</item>
       <item quantity="one">El dispositivo no se ha desbloqueado durante <xliff:g id="NUMBER_0">%d</xliff:g> hora. Confirma el patrón.</item>
diff --git a/packages/Keyguard/res/values-et-rEE/strings.xml b/packages/Keyguard/res/values-et-rEE/strings.xml
index 89ffbde..47aadf0 100644
--- a/packages/Keyguard/res/values-et-rEE/strings.xml
+++ b/packages/Keyguard/res/values-et-rEE/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Sisestage uuesti õige PUK-kood. Korduvkatsete korral keelatakse SIM jäädavalt."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-koodid ei ole vastavuses"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Liiga palju mustrikatseid"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Olete PIN-koodi <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti sisestanud.\n\nProovige <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast uuesti."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Olete parooli <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti sisestanud. \n\nProovige uuesti <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti.\n\nProovige <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast uuesti."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Olete püüdnud <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti tahvelarvutit avada. Pärast <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset tahvelarvuti lähtestatakse ja kõik selle andmed kustutatakse."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Olete püüdnud <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti telefoni avada. Pärast <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset telefon lähtestatakse ja kõik selle andmed kustutatakse."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Olete PIN-koodi <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti sisestanud.\n\nProovige <xliff:g id="NUMBER_1">%2$d</xliff:g> sekundi pärast uuesti."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Olete parooli <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti sisestanud. \n\nProovige uuesti <xliff:g id="NUMBER_1">%2$d</xliff:g> sekundi pärast."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti.\n\nProovige <xliff:g id="NUMBER_1">%2$d</xliff:g> sekundi pärast uuesti."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti tahvelarvutit avada. Pärast <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset tahvelarvuti lähtestatakse ja kõik selle andmed kustutatakse."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti telefoni avada. Pärast <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset telefon lähtestatakse ja kõik selle andmed kustutatakse."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda valesti tahvelarvutit avada. Tahvelarvuti lähtestatakse ja kõik selle andmed kustutatakse."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda valesti telefoni avada. Telefon lähtestatakse ja kõik selle andmed kustutatakse."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Olete püüdnud <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti tahvelarvutit avada. Pärast <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset kasutaja eemaldatakse ja kõik kasutaja andmed kustutatakse."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Olete püüdnud <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti telefoni avada. Pärast <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset kasutaja eemaldatakse ja kõik kasutaja andmed kustutatakse."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti tahvelarvutit avada. Pärast <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset kasutaja eemaldatakse ja kõik kasutaja andmed kustutatakse."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti telefoni avada. Pärast <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset kasutaja eemaldatakse ja kõik kasutaja andmed kustutatakse."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda valesti tahvelarvutit avada. Kasutaja eemaldatakse ja kõik kasutaja andmed kustutatakse."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda valesti telefoni avada. Kasutaja eemaldatakse ja kõik kasutaja andmed kustutatakse."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Olete püüdnud <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti tahvelarvutit avada. Pärast <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset tööprofiil eemaldatakse ja kõik profiili andmed kustutatakse."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Olete püüdnud <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti telefoni avada. Pärast <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset tööprofiil eemaldatakse ja kõik profiili andmed kustutatakse."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti tahvelarvutit avada. Pärast <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset tööprofiil eemaldatakse ja kõik profiili andmed kustutatakse."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti telefoni avada. Pärast <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset tööprofiil eemaldatakse ja kõik profiili andmed kustutatakse."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda valesti tahvelarvutit avada. Tööprofiil eemaldatakse ja kõik profiili andmed kustutatakse."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda valesti telefoni avada. Tööprofiil eemaldatakse ja kõik profiili andmed kustutatakse."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset palutakse teil tahvelarvuti avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset palutakse teil telefon avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset palutakse teil tahvelarvuti avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundi pärast."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset palutakse teil telefon avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundi pärast."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Vale SIM-i PIN-kood, seadme avamiseks peate nüüd ühendust võtma oma operaatoriga."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">Vale SIM-kaardi PIN-kood, teil on jäänud veel <xliff:g id="NUMBER_1">%d</xliff:g> katset.</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Teenus puudub."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Sisestusmeetodi vahetamise nupp."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Lennukirežiim"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Seadme taaskäivitamisel on vaja mustrit."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Seadme taaskäivitamisel on vaja PIN-koodi."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Seadme taaskäivitamisel on vaja parooli."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Täiendava turvalisuse huvides on vaja sisestada muster."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Täiendava turvalisuse huvides on vaja sisestada PIN-kood."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Täiendava turvalisuse huvides on vaja sisestada parool."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Profiilide vahetamisel on vaja mustrit."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Profiilide vahetamisel on vaja PIN-koodi."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Profiilide vahetamisel on vaja parooli."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Pärast seadme taaskäivitamist tuleb sisestada parool"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Lisaturvalisuse huvides tuleb sisestada muster"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Lisaturvalisuse huvides tuleb sisestada PIN-kood"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Lisaturvalisuse huvides tuleb sisestada parool"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Profiilide vahetamisel tuleb sisestada muster"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Profiilide vahetamisel tuleb sisestada PIN-kood"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Profiilide vahetamisel tuleb sisestada parool"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">Seadet pole avatud <xliff:g id="NUMBER_1">%d</xliff:g> tundi. Kinnitage muster.</item>
       <item quantity="one">Seadet pole avatud <xliff:g id="NUMBER_0">%d</xliff:g> tund. Kinnitage muster.</item>
diff --git a/packages/Keyguard/res/values-eu-rES/strings.xml b/packages/Keyguard/res/values-eu-rES/strings.xml
index 3a740f6..1c834e9 100644
--- a/packages/Keyguard/res/values-eu-rES/strings.xml
+++ b/packages/Keyguard/res/values-eu-rES/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Idatzi berriro PUK kode zuzena. Hainbat saiakera oker eginez gero, betirako desgaituko da SIMa."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodeak ez datoz bat"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Eredua marrazteko saiakera gehiegi egin dira"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PINa oker idatzi duzu <xliff:g id="NUMBER_0">%d</xliff:g> aldiz. \n\nSaiatu berriro <xliff:g id="NUMBER_1">%d</xliff:g> segundo barru."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Pasahitza oker idatzi duzu <xliff:g id="NUMBER_0">%d</xliff:g> aldiz. \n\nSaiatu berriro <xliff:g id="NUMBER_1">%d</xliff:g> segundo barru."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%d</xliff:g> aldiz. \n\nSaiatu berriro <xliff:g id="NUMBER_1">%d</xliff:g> segundo barru."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"<xliff:g id="NUMBER_0">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%d</xliff:g> aldiz huts egiten baduzu, tableta berrezarri egingo da eta, ondorioz, datu guztiak ezabatuko dira."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"<xliff:g id="NUMBER_0">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%d</xliff:g> aldiz huts egiten baduzu, telefonoa berrezarri egingo da eta, ondorioz, datu guztiak ezabatuko dira."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PINa oker idatzi duzu <xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz. \n\nSaiatu berriro <xliff:g id="NUMBER_1">%2$d</xliff:g> segundo barru."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Pasahitza oker idatzi duzu <xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz. \n\nSaiatu berriro <xliff:g id="NUMBER_1">%2$d</xliff:g> segundo barru."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz. \n\nSaiatu berriro <xliff:g id="NUMBER_1">%2$d</xliff:g> segundo barru."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, tableta berrezarri egingo da eta, ondorioz, datu guztiak ezabatuko dira."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, telefonoa berrezarri egingo da eta, ondorioz, datu guztiak ezabatuko dira."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Tableta berrezarri egingo da eta, ondorioz, datu guztiak ezabatuko dira."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Telefonoa berrezarri egingo da eta, ondorioz, datu guztiak ezabatuko dira."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"<xliff:g id="NUMBER_0">%d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%d</xliff:g> aldiz huts egiten baduzu, erabiltzailea kendu egingo da eta, ondorioz, erabiltzailearen datu guztiak ezabatuko dira."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"<xliff:g id="NUMBER_0">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%d</xliff:g> aldiz huts egiten baduzu, erabiltzailea kendu egingo da eta, ondorioz, erabiltzailearen datu guztiak ezabatuko dira."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, erabiltzailea kendu egingo da eta, ondorioz, erabiltzailearen datu guztiak ezabatuko dira."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, erabiltzailea kendu egingo da eta, ondorioz, erabiltzailearen datu guztiak ezabatuko dira."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Erabiltzailea kendu egingo da eta, ondorioz, erabiltzailearen datu guztiak ezabatuko dira."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Erabiltzailea kendu egingo da eta, ondorioz, erabiltzailearen datu guztiak ezabatuko dira."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"<xliff:g id="NUMBER_0">%d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%d</xliff:g> aldiz huts egiten baduzu, laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"<xliff:g id="NUMBER_0">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%d</xliff:g> aldiz huts egiten baduzu, laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%d</xliff:g> aldiz. Beste <xliff:g id="NUMBER_1">%d</xliff:g> aldiz oker marrazten baduzu, tableta posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%d</xliff:g> segundo barru."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%d</xliff:g> aldiz. Beste <xliff:g id="NUMBER_1">%d</xliff:g> aldiz oker marrazten baduzu, telefonoa posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%d</xliff:g> segundo barru."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz oker marrazten baduzu, tableta posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%3$d</xliff:g> segundo barru."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz oker marrazten baduzu, telefonoa posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%3$d</xliff:g> segundo barru."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM txartelaren PIN kodea okerra da. Gailua desblokeatzeko, jarri operadorearekin harremanetan."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">SIM txartelaren PIN kodea okerra da. <xliff:g id="NUMBER_1">%d</xliff:g> saiakera geratzen zaizkizu gailua desblokeatzeko.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Hegaldi modua"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Gailua berrabiarazi duzunez, eredua marraztu behar duzu."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Gailua berrabiarazi duzunez, PIN kodea idatzi behar duzu."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Gailua berrabiarazi duzunez, pasahitza idatzi behar duzu."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Segurtasun handiagoa izateko, eredua behar da."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Segurtasun handiagoa izateko, PIN kodea behar da."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Segurtasun handiagoa izateko, pasahitza behar da."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Profilez aldatu duzunez, eredua marraztu behar duzu."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Profilez aldatu duzunez, PIN kodea idatzi behar duzu."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Profilez aldatu duzunez, pasahitza idatzi behar duzu."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Pasahitza idatzi beharko duzu gailua berrabiarazten denean"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Segurtasun handiagoa izateko, eredua behar da"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Segurtasun handiagoa izateko, PIN kodea behar da"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Segurtasun handiagoa izateko, pasahitza behar da"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Eredua marraztu beharko duzu profilez aldatzen baduzu"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"PIN kodea idatzi beharko duzu profilez aldatzen baduzu"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Pasahitza idatzi beharko duzu profilez aldatzen baduzu"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">Gailua ez da desblokeatu <xliff:g id="NUMBER_1">%d</xliff:g> orduz. Berretsi eredua.</item>
       <item quantity="one">Gailua ez da desblokeatu <xliff:g id="NUMBER_0">%d</xliff:g> orduz. Berretsi eredua.</item>
diff --git a/packages/Keyguard/res/values-fa/strings.xml b/packages/Keyguard/res/values-fa/strings.xml
index 975fe7f..166e0d9 100644
--- a/packages/Keyguard/res/values-fa/strings.xml
+++ b/packages/Keyguard/res/values-fa/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"پین کد صحیح را دوباره وارد کنید. تلاش‌های مکرر به‌طور دائم سیم کارت را غیرفعال خواهد کرد."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"پین کدها منطبق نیستند"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"‏تلاش‎های زیادی برای کشیدن الگو صورت گرفته است"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"پین خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه تایپ کردید. \n\nپس از <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"گذرواژه خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه تایپ کردید. \n\nپس از <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیدید. \n\nلطفاً پس از <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"<xliff:g id="NUMBER_0">%d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشته‌اید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق دیگر، این رایانه لوحی بازنشانی می‌شود که با آن کل اطلاعاتش حذف می‌شود."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"<xliff:g id="NUMBER_0">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشته‌اید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق دیگر، تلفن بازنشانی می‌شود که با آن کل اطلاعاتش حذف می‌شود."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"پین خود را <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">"الگوی بازگشایی قفل خود را <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">%d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشته‌اید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق دیگر، این کاربر حذف می‌شود که با آن کل اطلاعات کاربر حذف می‌شود."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"<xliff:g id="NUMBER_0">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشته‌اید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق دیگر، این کاربر حذف می‌شود که با آن کل اطلاعات کاربر حذف می‌شود."</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشته‌اید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق دیگر، نمایه کار حذف می‌شود که با آن کل اطلاعات نمایه حذف می‌شود."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"<xliff:g id="NUMBER_0">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشته‌اید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق دیگر، نمایه کار حذف می‌شود که با آن کل اطلاعات نمایه حذف می‌شود."</string>
+    <string name="kg_failed_attempts_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">"‏شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیده‎اید. بعد از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق، از شما خواسته می‎شود که با استفاده از یک حساب ایمیل قفل رایانه لوحی خود را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"‏شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیده‌اید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق، از شما خواسته می‎شود که با استفاده از یک حساب ایمیل قفل تلفن خود را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"‏شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‎اید. بعد از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته می‎شود که با استفاده از یک حساب ایمیل قفل رایانه لوحی خود را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"‏شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‌اید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته می‎شود که با استفاده از یک حساب ایمیل قفل تلفن خود را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"کد پین سیم کارت اشتباه است، اکنون برای گشودن قفل دستگاهتان باید با شرکت مخابراتی تماس بگیرید."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">کد پین سیم‌کارت اشتباه است، <xliff:g id="NUMBER_1">%d</xliff:g> بار دیگر می‌توانید تلاش کنید.</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"خدماتی وجود ندارد."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"کلید تغییر روش ورود متن."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"حالت هواپیما"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"هنگامی که دستگاه را راه‌اندازی مجدد می‌کنید الگو درخواست می‌شود."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"هنگامی که دستگاه را راه‌اندازی مجدد می‌کنید پین درخواست می‌شود."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"هنگامی که دستگاه را راه‌اندازی مجدد می‌کنید گذرواژه درخواست می‌شود."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"برای ایمنی بیشتر به الگو نیاز است."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"برای ایمنی بیشتر به پین نیاز است."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"برای ایمنی بیشتر به گذرواژه نیاز است."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"هنگامی که میان نمایه‌ها جابجا می‌شوید، الگو درخواست می‌شود."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"هنگامی که میان نمایه‌ها جابجا می‌شوید، پین درخواست می‌شود."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"هنگامی که میان نمایه‌ها جابجا می‌شوید، گذرواژه درخواست می‌شود."</string>
+    <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"بعد از بازنشانی دستگاه باید الگو وارد شود"</string>
+    <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"بعد از بازنشانی دستگاه باید پین وارد شود"</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">"برای ایمنی بیشتر باید پین وارد شود"</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">"بعد از تغییر نمایه‌ها باید پین وارد شود"</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="other">قفل دستگاه به مدت <xliff:g id="NUMBER_1">%d</xliff:g> ساعت باز نشده است. الگو را تأیید کنید.</item>
diff --git a/packages/Keyguard/res/values-fi/strings.xml b/packages/Keyguard/res/values-fi/strings.xml
index 94c8d62..bba241e 100644
--- a/packages/Keyguard/res/values-fi/strings.xml
+++ b/packages/Keyguard/res/values-fi/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Anna uudelleen oikea PUK-koodi. Jos teet liian monta yritystä, SIM-kortti poistetaan käytöstä pysyvästi."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-koodit eivät täsmää"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Liikaa kuvionpiirtoyrityksiä"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Olet kirjoittanut PIN-koodin väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Olet kirjoittanut salasanan väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Olet piirtänyt lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%d</xliff:g> epäonnistunutta yritystä, tämä tabletti nollataan ja kaikki sen tiedot poistetaan."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%d</xliff:g> epäonnistunutta yritystä, tämä puhelin nollataan ja kaikki sen tiedot poistetaan."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Olet kirjoittanut PIN-koodin väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Olet kirjoittanut salasanan väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Olet piirtänyt lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> epäonnistunutta yritystä, tämä tabletti nollataan ja kaikki sen tiedot poistetaan."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> epäonnistunutta yritystä, tämä puhelin nollataan ja kaikki sen tiedot poistetaan."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Tämä tabletti nollataan ja kaikki sen tiedot poistetaan."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Tämä puhelin nollataan ja kaikki sen tiedot poistetaan."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%d</xliff:g> epäonnistunutta yritystä, tämä käyttäjä ja kaikki käyttäjän tiedot poistetaan."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%d</xliff:g> epäonnistunutta yritystä, tämä käyttäjä ja kaikki käyttäjän tiedot poistetaan."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> epäonnistunutta yritystä, tämä käyttäjä ja kaikki käyttäjän tiedot poistetaan."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> epäonnistunutta yritystä, tämä käyttäjä ja kaikki käyttäjän tiedot poistetaan."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Tämä käyttäjä ja kaikki sen tiedot poistetaan."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Tämä käyttäjä ja kaikki sen tiedot poistetaan."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%d</xliff:g> epäonnistunutta yritystä, työprofiili ja kaikki sen tiedot poistetaan."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%d</xliff:g> epäonnistunutta yritystä, työprofiili ja kaikki sen tiedot poistetaan."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> epäonnistunutta yritystä, työprofiili ja kaikki sen tiedot poistetaan."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> epäonnistunutta yritystä, työprofiili ja kaikki sen tiedot poistetaan."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Työprofiili ja kaikki sen tiedot poistetaan."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Työprofiili ja kaikki sen tiedot poistetaan."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan tablet-laitteesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan puhelimesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> kertaa, sinua pyydetään poistamaan tablet-laitteesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> kertaa, sinua pyydetään poistamaan puhelimesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunnin kuluttua."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Virheellinen SIM-kortin PIN-koodi. Sinun on nyt otettava yhteys operaattoriin laitteen lukituksen avaamiseksi."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">Virheellinen SIM-kortin PIN-koodi. Sinulla on <xliff:g id="NUMBER_1">%d</xliff:g> yritystä jäljellä.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Lentokonetila"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Kuvio vaaditaan laitteen uudelleenkäynnistyksen yhteydessä."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"PIN-koodi vaaditaan laitteen uudelleenkäynnistyksen yhteydessä."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Salasana vaaditaan laitteen uudelleenkäynnistyksen yhteydessä."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Kuvio parantaa suojaustasi."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"PIN-koodi parantaa suojaustasi."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Salasana parantaa suojaustasi."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Kuvio vaaditaan profiilia vaihdettaessa."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"PIN-koodi vaaditaan profiilia vaihdettaessa."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Salasana vaaditaan profiilia vaihdettaessa."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Salasana vaaditaan laitteen uudelleenkäynnistyksen jälkeen."</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Kuvio vaaditaan suojauksen parantamiseksi."</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"PIN-koodi vaaditaan suojauksen parantamiseksi."</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Salasana vaaditaan suojauksen parantamiseksi."</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Kuvio vaaditaan profiilia vaihdettaessa."</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"PIN-koodi vaaditaan profiilia vaihdettaessa."</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Salasana vaaditaan profiilia vaihdettaessa."</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">Laitteen lukitusta ei ole avattu <xliff:g id="NUMBER_1">%d</xliff:g> tuntiin. Vahvista kuvio.</item>
       <item quantity="one">Laitteen lukitusta ei ole avattu <xliff:g id="NUMBER_0">%d</xliff:g> tuntiin. Vahvista kuvio.</item>
diff --git a/packages/Keyguard/res/values-fr-rCA/strings.xml b/packages/Keyguard/res/values-fr-rCA/strings.xml
index c8afb91..6b63e04 100644
--- a/packages/Keyguard/res/values-fr-rCA/strings.xml
+++ b/packages/Keyguard/res/values-fr-rCA/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Veuillez saisir de nouveau le code PUK correct. Des tentatives répétées désactivent définitivement la carte SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Les codes PIN ne correspondent pas."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Trop de tentatives."</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Vous avez saisi un NIP incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Vous avez saisi un mot de passe incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), cette tablette sera réinitialisée, ce qui entraînera la suppression de toutes les données qu\'elle contient."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), le téléphone sera réinitialisé, ce qui entraînera la suppression de toutes les données qu\'il contient."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Vous avez saisi un NIP incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Vous avez saisi un mot de passe incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%2$d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), cette tablette sera réinitialisée, ce qui entraînera la suppression de toutes les données qu\'elle contient."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%2$d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), le téléphone sera réinitialisé, ce qui entraînera la suppression de toutes les données qu\'il contient."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Cette tablette sera réinitialisée, ce qui entraîne la suppression de toutes les données qu\'elle contient."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Ce téléphone sera réinitialisé, ce qui entraîne la suppression de toutes les données qu\'il contient."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), cet utilisateur sera supprimé, ce qui entraînera la suppression de toutes ses données."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), cet utilisateur sera supprimé, ce qui entraînera la suppression de toutes ses données."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%2$d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), cet utilisateur sera supprimé, ce qui entraînera la suppression de toutes ses données."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%2$d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), cet utilisateur sera supprimé, ce qui entraînera la suppression de toutes ses données."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Cet utilisateur sera supprimé, ce qui entraîne la suppression de toutes ses données."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Cet utilisateur sera supprimé, ce qui entraîne la suppression de toutes ses données."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), le profil professionnel sera supprimé, ce qui entraînera la suppression de toutes ses données."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), le profil professionnel sera supprimé, ce qui entraînera la suppression de toutes ses données."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%2$d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), le profil professionnel sera supprimé, ce qui entraînera la suppression de toutes ses données."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%2$d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), le profil professionnel sera supprimé, ce qui entraînera la suppression de toutes ses données."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel sera supprimé, ce qui entraîne la suppression de toutes ses données."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel sera supprimé, ce qui entraîne la suppression de toutes ses données."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"NIP de carte SIM incorrect. Vous devez maintenant communiquer avec votre fournisseur de services pour déverrouiller votre appareil."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">Le NIP de la carte SIM incorrect. Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentative.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Mode Avion"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Veuillez entrer le motif au redémarrage de l\'appareil."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Veuillez entrer le NIP au redémarrage de l\'appareil."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Veuillez entrer le mot de passe au redémarrage de l\'appareil."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Motif requis pour plus de sécurité."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"NIP requis pour plus de sécurité."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Mot de passe requis pour plus de sécurité."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Veuillez tracer le motif lorsque vous changez de profil."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Veuillez entrer le NIP lorsque vous changez de profil."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Veuillez entrer le mot de passe lorsque vous changez de profil."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Le mot de passe est exigé après le redémarrage de l\'appareil"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Le motif est exigé pour plus de sécurité"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Le NIP est exigé pour plus de sécurité"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Le mot de passe est exigé pour plus de sécurité"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Le motif est exigé lorsque vous changez de profil"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Le NIP est exigé lorsque vous changez de profil"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Le mot de passe est exigé lorsque vous changez de profil"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="one">L\'appareil n\'a pas été déverrouillé depuis <xliff:g id="NUMBER_1">%d</xliff:g> heure. Confirmez le motif.</item>
       <item quantity="other">L\'appareil n\'a pas été déverrouillé depuis <xliff:g id="NUMBER_1">%d</xliff:g> heures. Confirmez le motif.</item>
diff --git a/packages/Keyguard/res/values-fr/strings.xml b/packages/Keyguard/res/values-fr/strings.xml
index afefc9a..73b9552 100644
--- a/packages/Keyguard/res/values-fr/strings.xml
+++ b/packages/Keyguard/res/values-fr/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Veuillez saisir de nouveau le code PUK correct. Des tentatives répétées désactivent définitivement la carte SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Les codes PIN ne correspondent pas."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Trop de tentatives."</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Vous avez saisi un code PIN incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Vous avez saisi un mot de passe incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, cette tablette sera réinitialisée et toutes les données qu\'elle contient seront supprimées."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, ce téléphone sera réinitialisé et toutes les données qu\'il contient seront supprimées."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Vous avez saisi un code PIN incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Vous avez saisi un mot de passe incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, cette tablette sera réinitialisée et toutes les données qu\'elle contient seront supprimées."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, ce téléphone sera réinitialisé et toutes les données qu\'il contient seront supprimées."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Cette tablette va être réinitialisée et toutes les données qu\'elle contient seront supprimées."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Ce téléphone va être réinitialisé et toutes les données qu\'il contient seront supprimées."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, ce compte utilisateur et toutes les données associées seront supprimés."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, ce compte utilisateur et toutes les données associées seront supprimés."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, ce compte utilisateur et toutes les données associées seront supprimés."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, ce compte utilisateur et toutes les données associées seront supprimés."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Ce compte utilisateur et toutes les données associées vont être supprimés."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Ce compte utilisateur et toutes les données associées vont être supprimés."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, le profil professionnel et toutes les données associées seront supprimés."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, le profil professionnel et toutes les données associées seront supprimés."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, le profil professionnel et toutes les données associées seront supprimés."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, le profil professionnel et toutes les données associées seront supprimés."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel et toutes les données associées vont être supprimés."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel et toutes les données associées vont être supprimés."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Code PIN de la carte SIM incorrect. Vous devez désormais contacter votre opérateur pour déverrouiller votre appareil."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">Code PIN de la carte SIM erroné. Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentative.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Mode Avion"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Veuillez saisir le schéma au redémarrage de l\'appareil."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Veuillez saisir le code d\'accès au redémarrage de l\'appareil."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Veuillez saisir le mot de passe au redémarrage de l\'appareil."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Veuillez saisir le schéma pour renforcer la sécurité."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Veuillez saisir le code d\'accès pour renforcer la sécurité."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Veuillez saisir le mot de passe pour renforcer la sécurité."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Veuillez saisir le schéma lorsque vous changez de profil."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Veuillez saisir le code d\'accès lorsque vous changez de profil."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Veuillez saisir le mot de passe lorsque vous changez de profil."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Veuillez saisir le mot de passe après le redémarrage de l\'appareil."</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Veuillez saisir le schéma pour renforcer la sécurité."</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Veuillez saisir le code d\'accès pour renforcer la sécurité."</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Veuillez saisir le mot de passe pour renforcer la sécurité."</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Veuillez saisir le schéma lorsque vous changez de profil."</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Veuillez saisir le code d\'accès lorsque vous changez de profil."</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Veuillez saisir le mot de passe lorsque vous changez de profil."</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="one">L\'appareil n\'a pas été déverrouillé depuis <xliff:g id="NUMBER_1">%d</xliff:g> heure. Confirmez le schéma.</item>
       <item quantity="other">L\'appareil n\'a pas été déverrouillé depuis <xliff:g id="NUMBER_1">%d</xliff:g> heures. Confirmez le schéma.</item>
diff --git a/packages/Keyguard/res/values-gl-rES/strings.xml b/packages/Keyguard/res/values-gl-rES/strings.xml
index 4713abf..05767c9 100644
--- a/packages/Keyguard/res/values-gl-rES/strings.xml
+++ b/packages/Keyguard/res/values-gl-rES/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Volve introducir o código PUK correcto. Se realizas intentos repetidos é posible que se desactive a tarxeta SIM permanentemente."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Os códigos PIN non coinciden"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Tentaches debuxar o padrón moitas veces"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Introduciches o PIN incorrectamente <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nTéntao de novo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Introduciches o contrasinal incorrectamente <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nTéntao de novo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Debuxaches incorrectamente o padrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nTéntao de novo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Tentaches desbloquear o tablet <xliff:g id="NUMBER_0">%d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos máis, restablecerase o tablet e, por conseguinte, eliminaranse todos os seus datos."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER_0">%d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos máis, restablecerase o teléfono e, por conseguinte, eliminaranse todos os seus datos."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Introduciches o PIN incorrectamente <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \n\nTéntao de novo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Introduciches o contrasinal incorrectamente <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \n\nTéntao de novo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Debuxaches incorrectamente o padrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \n\nTéntao de novo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Tentaches desbloquear o tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, restablecerase o tablet e, por conseguinte, eliminaranse todos os seus datos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, restablecerase o teléfono e, por conseguinte, eliminaranse todos os seus datos."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Tentaches desbloquear o tablet <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Restablecerase o tablet e, por conseguinte, eliminaranse todos os seus datos."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Restablecerase o teléfono e, por conseguinte, eliminaranse todos os seus datos."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Tentaches desbloquear o tablet <xliff:g id="NUMBER_0">%d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos máis, eliminarase este usuario e, por conseguinte, todos os datos do usuario."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER_0">%d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos máis, eliminarase este usuario e, por conseguinte, todos os datos do usuario."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Tentaches desbloquear o tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, eliminarase este usuario e, por conseguinte, todos os datos do usuario."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, eliminarase este usuario e, por conseguinte, todos os datos do usuario."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Tentaches desbloquear o tablet <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Eliminarase este usuario e, por conseguinte, todos os datos do usuario."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Eliminarase este usuario e, por conseguinte, todos os datos do usuario."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Tentaches desbloquear o tablet <xliff:g id="NUMBER_0">%d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos máis, eliminarase o perfil de traballo e, por conseguinte, todos os datos do perfil."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER_0">%d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos máis, eliminarase o perfil de traballo e, por conseguinte, todos os datos do perfil."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Tentaches desbloquear o tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, eliminarase o perfil de traballo e, por conseguinte, todos os datos do perfil."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, eliminarase o perfil de traballo e, por conseguinte, todos os datos do perfil."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Tentaches desbloquear o tablet <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Eliminarase o perfil de traballo e, por conseguinte, todos os datos do perfil."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Eliminarase o perfil de traballo e, por conseguinte, todos os datos do perfil."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Debuxaches o padrón de desbloqueo incorrectamente <xliff:g id="NUMBER_0">%d</xliff:g> veces. Se realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos máis, terás que desbloquear o tablet a través dunha unha conta de correo electrónico.\n\n Téntao de novo dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Debuxaches o padrón de desbloqueo incorrectamente <xliff:g id="NUMBER_0">%d</xliff:g> veces. Se realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos máis, terás que desbloquear o teléfono a través dunha conta de correo electrónico.\n\n Téntao de novo dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Debuxaches o padrón de desbloqueo incorrectamente <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, terás que desbloquear o tablet a través dunha unha conta de correo electrónico.\n\n Téntao de novo dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Debuxaches o padrón de desbloqueo incorrectamente <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, terás que desbloquear o teléfono a través dunha conta de correo electrónico.\n\n Téntao de novo dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"O código PIN da SIM non é correcto. Agora debes contactar co teu operador para desbloquear o dispositivo."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">O código PIN da SIM é incorrecto. Quédanche <xliff:g id="NUMBER_1">%d</xliff:g> intentos.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Modo avión"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"É necesario o padrón para reiniciar o dispositivo."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"É necesario o PIN para reiniciar o dispositivo."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"É necesario o contrasinal para reiniciar o dispositivo."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Necesítase o padrón para obter seguranza adicional."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Necesítase o PIN para obter seguranza adicional."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Necesítase o contrasinal para obter seguranza adicional."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"É necesario o padrón para cambiar os perfís."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"É necesario o PIN para cambiar os perfís."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"É necesario o contrasinal para cambiar os perfís."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"É necesario o contrasinal despois do reinicio do dispositivo"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"É necesario o padrón para obter seguranza adicional"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"É necesario o PIN para obter seguranza adicional"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"É necesario o contrasinal para obter seguranza adicional"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"É necesario o padrón para cambiar os perfís"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"É necesario o PIN para cambiar os perfís"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"É necesario o contrasinal para cambiar os perfís"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">O dispositivo non se desbloqueou durante <xliff:g id="NUMBER_1">%d</xliff:g> horas. Confirma o padrón.</item>
       <item quantity="one">O dispositivo non se desbloqueou durante <xliff:g id="NUMBER_0">%d</xliff:g> hora. Confirma o padrón.</item>
diff --git a/packages/Keyguard/res/values-gu-rIN/strings.xml b/packages/Keyguard/res/values-gu-rIN/strings.xml
index f74c8aa..1b346a2 100644
--- a/packages/Keyguard/res/values-gu-rIN/strings.xml
+++ b/packages/Keyguard/res/values-gu-rIN/strings.xml
@@ -77,23 +77,23 @@
     <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">"તમે <xliff:g id="NUMBER_0">%d</xliff:g> વખત ખોટી રીતે તમારો PIN લખ્યો છે. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> સેકંડમાં ફરીથી પ્રયાસ કરો."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"તમે <xliff:g id="NUMBER_0">%d</xliff:g> વખત ખોટી રીતે તમારો પાસવર્ડ લખ્યો છે. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> સેકંડમાં ફરીથી પ્રયાસ કરો."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"તમે <xliff:g id="NUMBER_0">%d</xliff:g> વખત ખોટી રીતે તમારી અનલૉક પેટર્ન દોરી. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> સેકંડમાં ફરીથી પ્રયાસ કરો."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"તમે ટેબ્લેટને અનલૉક કરવા માટે <xliff:g id="NUMBER_0">%d</xliff:g> વખત ખોટી રીતે પ્રયાસ કર્યો. <xliff:g id="NUMBER_1">%d</xliff:g> વધુ અસફળ પ્રયાસો પછી, આ ટેબ્લેટ ફરીથી સેટ કરવામાં આવશે, જે તેનો તમામ ડેટા કાઢી નાખશે."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"તમે ફોનને અનલૉક કરવા માટે <xliff:g id="NUMBER_0">%d</xliff:g> વખત ખોટી રીતે પ્રયાસ કર્યો. <xliff:g id="NUMBER_1">%d</xliff:g> વધુ અસફળ પ્રયાસ પછી, આ ફોન ફરીથી સેટ કરવામાં આવશે, જે તેનો તમામ ડેટા કાઢી નાખશે."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"તમે <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે તમારો PIN લખ્યો છે. \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">"તમે <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">%d</xliff:g> વખત ખોટી રીતે પ્રયાસ કર્યો. <xliff:g id="NUMBER_1">%d</xliff:g> વધુ અસફળ પ્રયાસો પછી, આ વપરાશકર્તાને દૂર કરવામાં આવશે, જે તમામ વપરાશકર્તા ડેટાને કાઢી નાખશે."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"તમે ફોનને અનલૉક કરવા માટે <xliff:g id="NUMBER_0">%d</xliff:g> વખત ખોટી રીતે પ્રયાસ કર્યો. <xliff:g id="NUMBER_1">%d</xliff:g> વધુ અસફળ પ્રયાસ પછી, આ વપરાશકર્તા દૂર કરવામાં આવશે, જે તમામ વપરાશકર્તા ડેટા કાઢી નાખશે."</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> વખત ખોટી રીતે પ્રયાસ કર્યો છે. હજી <xliff:g id="NUMBER_1">%d</xliff:g> અસફળ પ્રયાસ પછી, કાર્ય પ્રોફાઇલ દૂર કરવામાં આવશે, જે તમામ પ્રોફાઇલ ડેટાને કાઢી નાખશે."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"તમે ફોનને અનલૉક કરવાનો <xliff:g id="NUMBER_0">%d</xliff:g> વખત ખોટી રીતે પ્રયાસ કર્યો છે. હજી <xliff:g id="NUMBER_1">%d</xliff:g> અસફળ પ્રયાસ પછી, કાર્ય પ્રોફાઇલ દૂર કરવામાં આવશે, જે તમામ પ્રોફાઇલ ડેટાને કાઢી નાખશે."</string>
+    <string name="kg_failed_attempts_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">"તમે <xliff:g id="NUMBER_0">%d</xliff:g> વખત ખોટી રીતે અનલૉક પેટર્ન દોરી છે. વધુ <xliff:g id="NUMBER_1">%d</xliff:g> વખત અસફળ પ્રયાસો પછી, તમને એક ઇમેઇલ એકાઉન્ટનો ઉપયોગ કરીને તમારા ટેબ્લેટને અનલૉક કરવા માટે પૂછવામાં આવશે.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> સેકંડમાં ફરી પ્રયાસ કરો."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"તમે તમારી અનલૉક પેટર્ન <xliff:g id="NUMBER_0">%d</xliff:g> વખત ખોટી રીતે દોરી. હજી <xliff:g id="NUMBER_1">%d</xliff:g> અસફળ પ્રયાસ પછી, તમને ઇમેઇલ એકાઉન્ટનો ઉપયોગ કરીને ફોનને અનલૉક કરવાનું કહેવામાં આવશે.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> સેકંડમાં ફરીથી પ્રયાસ કરો."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"તમે <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે અનલૉક પેટર્ન દોરી છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> વખત અસફળ પ્રયાસો પછી, તમને એક ઇમેઇલ એકાઉન્ટનો ઉપયોગ કરીને તમારા ટેબ્લેટને અનલૉક કરવા માટે પૂછવામાં આવશે.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> સેકંડમાં ફરી પ્રયાસ કરો."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"તમે તમારી અનલૉક પેટર્ન <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે દોરી. હજી <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસ પછી, તમને ઇમેઇલ એકાઉન્ટનો ઉપયોગ કરીને ફોનને અનલૉક કરવાનું કહેવામાં આવશે.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> સેકંડમાં ફરીથી પ્રયાસ કરો."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"ખોટો SIM PIN કોડ, તમારે હવે તમારું ઉપકરણ અનલૉક કરવા માટે તમારા કેરિઅરનો સંપર્ક કરવો આવશ્યક છે."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">ખોટો SIM PIN કોડ, તમારી પાસે <xliff:g id="NUMBER_1">%d</xliff:g> પ્રયાસ બાકી છે.</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"કોઈ સેવા ."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ઇનપુટ પદ્ધતિ બટન સ્વિચ કરો."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"એરપ્લેન મોડ"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"જ્યારે તમે ઉપકરણ ફરીથી સેટ કરો ત્યારે પેટર્ન જરૂરી છે."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"જ્યારે તમે ઉપકરણ ફરીથી સેટ કરો ત્યારે PIN જરૂરી છે."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"જ્યારે તમે ઉપકરણ ફરીથી સેટ કરો ત્યારે પાસવર્ડ જરૂરી છે."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"વધારાની સુરક્ષા માટે પેટર્ન જરૂરી છે."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"વધારાની સુરક્ષા માટે PIN જરૂરી છે."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"વધારાની સુરક્ષા માટે પાસવર્ડ જરૂરી છે."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"જ્યારે તમે પ્રોફાઇલ્સ સ્વિચ કરો ત્યારે પેટર્ન જરૂરી છે."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"જ્યારે તમે પ્રોફાઇલ્સ સ્વિચ કરો ત્યારે PIN જરૂરી છે."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"જ્યારે તમે પ્રોફાઇલ્સ સ્વિચ કરો ત્યારે પાસવર્ડ જરૂરી છે."</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="other">ઉપકરણ <xliff:g id="NUMBER_1">%d</xliff:g> કલાક માટે અનલૉક કરવામાં આવ્યું નથી. પેટર્નની પુષ્ટિ કરો.</item>
diff --git a/packages/Keyguard/res/values-hi/strings.xml b/packages/Keyguard/res/values-hi/strings.xml
index 612d16c..47aefab 100644
--- a/packages/Keyguard/res/values-hi/strings.xml
+++ b/packages/Keyguard/res/values-hi/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"सही PUK कोड पुन: डालें. बार-बार प्रयास करने से सिम स्थायी रूप से अक्षम हो जाएगी."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"पिन कोड का मिलान नहीं होता"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"बहुत अधिक आकार प्रयास"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"आप अपना PIN <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से लिख चुके हैं. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"आप अपना पासवर्ड <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से लिख चुके हैं. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"आपने अपना अनलॉक आकार <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"आपने टैबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से प्रयास किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, इस टैबलेट को रीसेट कर दिया जाएगा, जिससे सभी उपयोगकर्ता डेटा हट जाएगा."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"आपने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से प्रयास किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, इस फ़ोन को रीसेट कर दिया जाएगा, जिससे सभी उपयोगकर्ता डेटा हट जाएगा."</string>
+    <string name="kg_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">"आपने अपना अनलॉक आकार <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">%d</xliff:g> बार गलत तरीके से प्रयास किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, इस उपयोगकर्ता को निकाल दिया जाएगा, जिससे सभी उपयोगकर्ता डेटा हट जाएगा."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"आपने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से प्रयास किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, इस उपयोगकर्ता को निकाल दिया जाएगा, जिससे सभी उपयोगकर्ता डेटा हट जाएगा."</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> बार गलत तरीके से प्रयास किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, कार्य प्रोफ़ाइल को निकाल दिया जाएगा, जिससे सभी प्रोफ़ाइल डेटा हट जाएगा."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"आपके डिवाइस ने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से प्रयास किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, कार्य प्रोफ़ाइल को निकाल दिया जाएगा, जिससे सभी प्रोफ़ाइल डेटा हट जाएगा."</string>
+    <string name="kg_failed_attempts_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">"आपने अपने अनलॉक आकार को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने टेबलेट को किसी ईमेल खाते के उपयोग से अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"आपने अपने अनलॉक आकार को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने फ़ोन को किसी ईमेल खाते का उपयोग करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"आपने अपने अनलॉक आकार को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने टेबलेट को किसी ईमेल खाते के उपयोग से अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"आपने अपने अनलॉक आकार को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने फ़ोन को किसी ईमेल खाते का उपयोग करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"गलत सिम PIN कोड अपने डिवाइस को अनलॉक करने के लिए अब आपको अपने वाहक से संपर्क करना होगा."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">गलत सिम PIN कोड, आपके पास <xliff:g id="NUMBER_1">%d</xliff:g> प्रयास शेष हैं.</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"कोई सेवा नहीं."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट पद्धति‍ बटन स्विच करें."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"हवाई जहाज़ मोड"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"डिवाइस को पुनः प्रारंभ करते समय पैटर्न की आवश्यकता होती है."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"डिवाइस को पुनः प्रारंभ करते समय पिन की आवश्यकता होती है."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"डिवाइस को पुनः प्रारंभ करते समय पासवर्ड की आवश्यकता होती है."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"अतिरिक्‍त सुरक्षा के लिए पैटर्न आवश्‍यक है."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"अतिरिक्‍त सुरक्षा के लिए पिन आवश्‍यक है."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"अतिरिक्‍त सुरक्षा के लिए पासवर्ड आवश्‍यक है."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"प्रोफ़ाइल में स्विच करते समय पैटर्न की आवश्यकता होती है."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"प्रोफ़ाइल में स्विच करते समय पिन की आवश्यकता होती है."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"प्रोफ़ाइल में स्विच करते समय पासवर्ड की आवश्यकता होती है."</string>
+    <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"डिवाइस के पुनः प्रारंभ होने पर पैटर्न की आवश्यकता होती है"</string>
+    <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"डिवाइस के पुनः प्रारंभ होने पर पिन की आवश्यकता होती है"</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">"अतिरिक्‍त सुरक्षा के लिए पिन आवश्‍यक है"</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">"प्रोफ़ाइल में स्विच करते समय पिन की आवश्यकता होती है"</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="other">डिवाइस <xliff:g id="NUMBER_1">%d</xliff:g> घंटे से अनलॉक नहीं किया गया है. पैटर्न की पुष्टि करें.</item>
diff --git a/packages/Keyguard/res/values-hr/strings.xml b/packages/Keyguard/res/values-hr/strings.xml
index d77176b..c65db7f 100644
--- a/packages/Keyguard/res/values-hr/strings.xml
+++ b/packages/Keyguard/res/values-hr/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Ponovo unesite ispravan PUK kôd. Ponovljeni pokušaji trajno će onemogućiti SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodovi nisu jednaki"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Previše pokušaja iscrtavanja obrasca"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Netočno ste napisali PIN <xliff:g id="NUMBER_0">%d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Netočno ste napisali zaporku <xliff:g id="NUMBER_0">%d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"<xliff:g id="NUMBER_0">%d</xliff:g> put/a ste neuspješno pokušali otključati tablet. Nakon još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja tablet će se vratiti na zadano, a time će se izbrisati i svi podaci na njemu."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"<xliff:g id="NUMBER_0">%d</xliff:g> put/a ste neuspješno pokušali otključati telefon. Nakon još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja telefon će se vratiti na zadano, a time će se izbrisati i svi podaci na njemu."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Netočno ste napisali PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Netočno ste napisali zaporku <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"<xliff:g id="NUMBER_0">%1$d</xliff:g> put/a ste neuspješno pokušali otključati tablet. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja tablet će se vratiti na zadano, a time će se izbrisati i svi podaci na njemu."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"<xliff:g id="NUMBER_0">%1$d</xliff:g> put/a ste neuspješno pokušali otključati telefon. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja telefon će se vratiti na zadano, a time će se izbrisati i svi podaci na njemu."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"<xliff:g id="NUMBER">%d</xliff:g> put/a ste neuspješno pokušali otključati tablet. Tablet će se vratiti na zadano, a time će se izbrisati i svi podaci na njemu."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"<xliff:g id="NUMBER">%d</xliff:g> put/a ste neuspješno pokušali otključati telefon. Telefon će se vratiti na zadano, a time će se izbrisati i svi podaci na njemu."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"<xliff:g id="NUMBER_0">%d</xliff:g> put/a ste neuspješno pokušali otključati tablet. Nakon još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja taj će se korisnik ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"<xliff:g id="NUMBER_0">%d</xliff:g> put/a ste neuspješno pokušali otključati telefon. Nakon još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja taj će se korisnik ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"<xliff:g id="NUMBER_0">%1$d</xliff:g> put/a ste neuspješno pokušali otključati tablet. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja taj će se korisnik ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"<xliff:g id="NUMBER_0">%1$d</xliff:g> put/a ste neuspješno pokušali otključati telefon. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja taj će se korisnik ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"<xliff:g id="NUMBER">%d</xliff:g> put/a ste neuspješno pokušali otključati tablet. Taj će se korisnik ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"<xliff:g id="NUMBER">%d</xliff:g> put/a ste neuspješno pokušali otključati telefon. Taj će se korisnik ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"<xliff:g id="NUMBER_0">%d</xliff:g> put/a ste neuspješno pokušali otključati tablet. Nakon još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"<xliff:g id="NUMBER_0">%d</xliff:g> put/a ste neuspješno pokušali otključati telefon. Nakon još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"<xliff:g id="NUMBER_0">%1$d</xliff:g> put/a ste neuspješno pokušali otključati tablet. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"<xliff:g id="NUMBER_0">%1$d</xliff:g> put/a ste neuspješno pokušali otključati telefon. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"<xliff:g id="NUMBER">%d</xliff:g> put/a ste neuspješno pokušali otključati tablet. Radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"<xliff:g id="NUMBER">%d</xliff:g> put/a ste neuspješno pokušali otključati telefon. Radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati tabletno računalo pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati telefon pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%2$d</xliff:g> morat ćete otključati tabletno računalo pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%2$d</xliff:g> morat ćete otključati telefon pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Netočan PIN kôd SIM kartice; sada morate kontaktirati svog mobilnog operatera da bi otključao vaš uređaj."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">Netočan PIN kôd SIM kartice; imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj.</item>
@@ -112,15 +112,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Način rada u zrakoplovu"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Za ponovno pokretanje uređaja morate unijeti uzorak."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Za ponovno pokretanje uređaja morate unijeti PIN."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Za ponovno pokretanje uređaja morate unijeti zaporku."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Unesite uzorak radi dodatne sigurnosti."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Unesite PIN radi dodatne sigurnosti."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Unesite zaporku radi dodatne sigurnosti."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Za promjenu profila morate unijeti uzorak."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Za promjenu profila morate unijeti PIN."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Za promjenu profila morate unijeti zaporku."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Nakon ponovnog pokretanja uređaja morate unijeti zaporku"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Unesite uzorak radi dodatne sigurnosti"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Unesite PIN radi dodatne sigurnosti"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Unesite zaporku radi dodatne sigurnosti"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Za promjenu profila morate unijeti uzorak"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Za promjenu profila morate unijeti PIN"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Za promjenu profila morate unijeti zaporku"</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 uzorak.</item>
       <item quantity="few">Uređaj nije bio otključan <xliff:g id="NUMBER_1">%d</xliff:g> sata. Potvrdite uzorak.</item>
diff --git a/packages/Keyguard/res/values-hu/strings.xml b/packages/Keyguard/res/values-hu/strings.xml
index 55cf24f..104735d 100644
--- a/packages/Keyguard/res/values-hu/strings.xml
+++ b/packages/Keyguard/res/values-hu/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Adja meg újra a helyes PUK kódot. Az ismételt próbálkozással véglegesen letiltja a SIM kártyát."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"A PIN kódok nem egyeznek."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Túl sok mintarajzolási próbálkozás"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül adta meg PIN kódját. \n\nPróbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül adta meg a jelszót. \n\nPróbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal rosszul rajzolta le feloldási mintát. \n\nPróbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. <xliff:g id="NUMBER_1">%d</xliff:g> további sikertelen kísérlet után a rendszer visszaállítja a táblagépet a gyári állapotba; ekkor az összes adat törlődik róla."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. <xliff:g id="NUMBER_1">%d</xliff:g> további sikertelen kísérlet után a rendszer visszaállítja a telefont a gyári állapotba; ekkor az összes adat törlődik róla."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül adta meg PIN kódját. \n\nPróbálja újra <xliff:g id="NUMBER_1">%2$d</xliff:g> másodperc múlva."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül adta meg a jelszót. \n\nPróbálja újra <xliff:g id="NUMBER_1">%2$d</xliff:g> másodperc múlva."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal rosszul rajzolta le feloldási mintát. \n\nPróbálja újra <xliff:g id="NUMBER_1">%2$d</xliff:g> másodperc múlva."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. <xliff:g id="NUMBER_1">%2$d</xliff:g> további sikertelen kísérlet után a rendszer visszaállítja a táblagépet a gyári állapotba; ekkor az összes adat törlődik róla."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. <xliff:g id="NUMBER_1">%2$d</xliff:g> további sikertelen kísérlet után a rendszer visszaállítja a telefont a gyári állapotba; ekkor az összes adat törlődik róla."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. A rendszer visszaállítja a táblagépet a gyári állapotba, és annak összes adata törlődik."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. A rendszer visszaállítja a telefont a gyári állapotba, és annak összes adata törlődik."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. <xliff:g id="NUMBER_1">%d</xliff:g> további sikertelen kísérlet után a rendszer eltávolítja ezt a felhasználót; ekkor összes felhasználói adata törlődni fog."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. <xliff:g id="NUMBER_1">%d</xliff:g> további sikertelen kísérlet után a rendszer eltávolítja ezt a felhasználót; ekkor összes felhasználói adata törlődni fog."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. <xliff:g id="NUMBER_1">%2$d</xliff:g> további sikertelen kísérlet után a rendszer eltávolítja ezt a felhasználót; ekkor összes felhasználói adata törlődni fog."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. <xliff:g id="NUMBER_1">%2$d</xliff:g> további sikertelen kísérlet után a rendszer eltávolítja ezt a felhasználót; ekkor összes felhasználói adata törlődni fog."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. A rendszer eltávolítja a felhasználót, és annak összes felhasználói adata törlődik."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. A rendszer eltávolítja a felhasználót, és annak összes felhasználói adata törlődik."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. <xliff:g id="NUMBER_1">%d</xliff:g> további sikertelen kísérlet után a rendszer eltávolítja munkahelyi profilját; ekkor összes profiladata törlődni fog."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. <xliff:g id="NUMBER_1">%d</xliff:g> további sikertelen kísérlet után a rendszer eltávolítja munkahelyi profilját; ekkor összes profiladata törlődni fog."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. <xliff:g id="NUMBER_1">%2$d</xliff:g> további sikertelen kísérlet után a rendszer eltávolítja munkahelyi profilját; ekkor összes profiladata törlődni fog."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. <xliff:g id="NUMBER_1">%2$d</xliff:g> további sikertelen kísérlet után a rendszer eltávolítja munkahelyi profilját; ekkor összes profiladata törlődni fog."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. A rendszer eltávolítja munkahelyi profilját, és összes profiladata törlődik."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. A rendszer eltávolítja munkahelyi profilját, és összes profiladata törlődik."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a táblagépét.\n\n Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a telefonját.\n\n Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a táblagépét.\n\n Kérjük, próbálja újra <xliff:g id="NUMBER_2">%3$d</xliff:g> másodperc múlva."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a telefonját.\n\n Kérjük, próbálja újra <xliff:g id="NUMBER_2">%3$d</xliff:g> másodperc múlva."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Helytelen PIN-kód a SIM kártyához; vegye fel a kapcsolatot szolgáltatójával az eszköz feloldásához."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">A SIM kártya PIN kódja helytelen. <xliff:g id="NUMBER_1">%d</xliff:g> próbálkozás maradt.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Repülős üzemmód"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Ha újraindítja az eszközt, meg kell adnia a mintát."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Ha újraindítja az eszközt, meg kell adnia a PIN kódot."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Ha újraindítja az eszközt, meg kell adnia a jelszót."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Minta szükséges a nagyobb biztonság érdekében."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"PIN-kód szükséges a nagyobb biztonság érdekében."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Jelszó szükséges a nagyobb biztonság érdekében."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Ha vált a profilok között, meg kell adnia a mintát."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Ha vált a profilok között, meg kell adnia a PIN kódot."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Ha vált a profilok között, meg kell adnia a jelszót."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Az eszköz újraindítását követően meg kell adni a jelszót"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Minta szükséges a nagyobb biztonság érdekében"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"PIN-kód szükséges a nagyobb biztonság érdekében"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Jelszó szükséges a nagyobb biztonság érdekében"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Ha vált a profilok között, meg kell adni a mintát"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Ha vált a profilok között, meg kell adni a PIN-kódot"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Ha vált a profilok között, meg kell adni a jelszót"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">Az eszköz zárolása <xliff:g id="NUMBER_1">%d</xliff:g> órája nem lett feloldva. Erősítse meg a mintát.</item>
       <item quantity="one">Az eszköz zárolása <xliff:g id="NUMBER_0">%d</xliff:g> órája nem lett feloldva. Erősítse meg a mintát.</item>
diff --git a/packages/Keyguard/res/values-hy-rAM/strings.xml b/packages/Keyguard/res/values-hy-rAM/strings.xml
index 7c771ca..0c70508 100644
--- a/packages/Keyguard/res/values-hy-rAM/strings.xml
+++ b/packages/Keyguard/res/values-hy-rAM/strings.xml
@@ -77,23 +77,23 @@
     <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">"Դուք <xliff:g id="NUMBER_0">%d</xliff:g> անգամ սխալ եք մուտքագրել ձեր PIN-ը: \n\nՓորձեք կրկին <xliff:g id="NUMBER_1">%d</xliff:g> վայրկյանից:"</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Դուք սխալ եք մուտքագրել ձեր գաղտնաբառը <xliff:g id="NUMBER_0">%d</xliff:g> անգամ: \n\nՓորձեք կրկին <xliff:g id="NUMBER_1">%d</xliff:g> վայրկյանից:"</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Դուք <xliff:g id="NUMBER_0">%d</xliff:g> անգամ սխալ եք հավաքել ձեր ապակողպման սխեման: \n\nՓորձեք կրկին <xliff:g id="NUMBER_1">%d</xliff:g> վայրկյանից:"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Դուք կատարել եք գրասալիկն ապակողպելու <xliff:g id="NUMBER_0">%d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%d</xliff:g> անհաջող փորձից հետո այս գրասալիկը կվերակայվի և բոլոր տվյալները կջնջվեն:"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER_0">%d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%d</xliff:g> անհաջող փորձից հետո այս հեռախոսը կվերակայվի և բոլոր տվյալները կջնջվեն:"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Դուք <xliff:g id="NUMBER_0">%1$d</xliff:g> անգամ սխալ եք մուտքագրել ձեր PIN-ը: \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">"Դուք <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">%d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%d</xliff:g> անհաջող փորձից հետո այս օգտվողը կհեռացվի և օգտվողի բոլոր տվյալները կջնջվեն:"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER_0">%d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%d</xliff:g> անհաջող փորձից հետո այս օգտվողը կհեռացվի և օգտվողի բոլոր տվյալները կջնջվեն:"</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%d</xliff:g> անհաջող փորձից հետո աշխատանքային պրոֆիլը կհեռացվի և պրոֆիլի բոլոր տվյալները կջնջվեն:"</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER_0">%d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%d</xliff:g> անհաջող փորձից հետո աշխատանքային պրոֆիլը կհեռացվի և պրոֆիլի բոլոր տվյալները կջնջվեն:"</string>
+    <string name="kg_failed_attempts_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">"Դուք սխալ եք հավաքել ձեր ապակողպման սխեման <xliff:g id="NUMBER_0">%d</xliff:g> անգամ: Եվս <xliff:g id="NUMBER_1">%d</xliff:g> անհաջող փորձից հետո ձեզանից կպահանջվի ապակողպել ձեր գրասալիկը` օգտագործելով էլփոստի հաշիվ:\n\n Փորձեք կրկին <xliff:g id="NUMBER_2">%d</xliff:g> վայրկյանից:"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Դուք <xliff:g id="NUMBER_0">%d</xliff:g> անգամ սխալ եք հավաքել ձեր ապակողպման նմուշը: <xliff:g id="NUMBER_1">%d</xliff:g> անգամից ավել անհաջող փորձերից հետո ձեզ կառաջարկվի ապակողպել ձեր հեռախոսը` օգտագործելով էլփոստի հաշիվ:\n\n Փորձեք կրկին <xliff:g id="NUMBER_2">%d</xliff:g> վայրկյանից:"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Դուք սխալ եք հավաքել ձեր ապակողպման սխեման <xliff:g id="NUMBER_0">%1$d</xliff:g> անգամ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո ձեզանից կպահանջվի ապակողպել ձեր գրասալիկը` օգտագործելով էլփոստի հաշիվ:\n\n Փորձեք կրկին <xliff:g id="NUMBER_2">%3$d</xliff:g> վայրկյանից:"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Դուք <xliff:g id="NUMBER_0">%1$d</xliff:g> անգամ սխալ եք հավաքել ձեր ապակողպման նմուշը: <xliff:g id="NUMBER_1">%2$d</xliff:g> անգամից ավել անհաջող փորձերից հետո ձեզ կառաջարկվի ապակողպել ձեր հեռախոսը` օգտագործելով էլփոստի հաշիվ:\n\n Փորձեք կրկին <xliff:g id="NUMBER_2">%3$d</xliff:g> վայրկյանից:"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Սխալ SIM PIN կոդի պատճառով պետք է դիմեք ձեր օպերատորին՝ սարքն արգելաբացելու համար:"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">SIM PIN կոդը սխալ է: Մնաց <xliff:g id="NUMBER_1">%d</xliff:g> փորձ:</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ծառայություն չկա:"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Միացնել մուտքագրման եղանակի կոճակը:"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Ինքնաթիռային ռեժիմ"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Սարքը վերագործարկելիս անհրաժեշտ է մուտքագրել ապակողպման նախշը:"</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Սարքը վերագործարկելիս անհրաժեշտ է մուտքագրել PIN կոդը:"</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Սարքը վերագործարկելիս անհրաժեշտ է մուտքագրել գաղտնաբառը:"</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Անվտանգության նկատառումներից ելնելով անհրաժեշտ է մուտքագրել նախշը:"</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Անվտանգության նկատառումներից ելնելով անհրաժեշտ է մուտքագրել PIN կոդը:"</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Անվտանգության նկատառումներից ելնելով անհրաժեշտ է մուտքագրել գաղտնաբառը:"</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Պրոֆիլները փոխարկելիս անհրաժեշտ է մուտքագրել ապակողպման նախշը:"</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Պրոֆիլները փոխարկելիս անհրաժեշտ է մուտքագրել PIN կոդը:"</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Պրոֆիլները փոխարկելիս անհրաժեշտ է մուտքագրել գաղտնաբառը:"</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="other">Սարքը չի ապակողպվել <xliff:g id="NUMBER_1">%d</xliff:g> ժամվա ընթացքում: Հաստատեք նախշը:</item>
diff --git a/packages/Keyguard/res/values-in/strings.xml b/packages/Keyguard/res/values-in/strings.xml
index dbe01e7..b409646 100644
--- a/packages/Keyguard/res/values-in/strings.xml
+++ b/packages/Keyguard/res/values-in/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Masukkan kembali kode PUK yang benar. Jika berulang kali gagal, SIM akan dinonaktifkan secara permanen."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kode PIN tidak cocok"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Terlalu banyak upaya pola"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah mengetik PIN. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah mengetik sandi. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Sudah <xliff:g id="NUMBER_0">%d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya yang tidak berhasil, tablet ini akan disetel ulang, sehingga semua datanya akan dihapus."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Sudah <xliff:g id="NUMBER_0">%d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya yang tidak berhasil, ponsel ini akan disetel ulang, sehingga semua datanya akan dihapus."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah mengetik PIN. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%2$d</xliff:g> detik."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah mengetik sandi. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%2$d</xliff:g> detik."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka kunci. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%2$d</xliff:g> detik."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, tablet ini akan disetel ulang, sehingga semua datanya akan dihapus."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, ponsel ini akan disetel ulang, sehingga semua datanya akan dihapus."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Tablet ini akan disetel ulang, sehingga menghapus semua datanya."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Ponsel ini akan disetel ulang, sehingga menghapus semua datanya."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Sudah <xliff:g id="NUMBER_0">%d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya yang tidak berhasil, pengguna ini akan dihapus, sehingga semua data pengguna akan dihapus."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Sudah <xliff:g id="NUMBER_0">%d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya yang tidak berhasil, pengguna ini akan dihapus, sehingga semua data pengguna akan dihapus."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, pengguna ini akan dihapus, sehingga semua data pengguna akan dihapus."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, pengguna ini akan dihapus, sehingga semua data pengguna akan dihapus."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Pengguna ini akan dihapus, sehingga menghapus semua data pengguna."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Pengguna ini akan dihapus, sehingga menghapus semua data pengguna."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Sudah <xliff:g id="NUMBER_0">%d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya yang tidak berhasil, profil kerja akan dihapus, sehingga semua data profil akan dihapus."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Sudah <xliff:g id="NUMBER_0">%d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya yang tidak berhasil, profil kerja akan dihapus, sehingga semua data profil akan dihapus."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, profil kerja akan dihapus, sehingga semua data profil akan dihapus."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, profil kerja akan dihapus, sehingga semua data profil akan dihapus."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Profil kerja akan dihapus, sehingga menghapus semua data profil."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Profil kerja akan dihapus, sehingga menghapus semua data profil."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci tablet menggunakan akun email.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci ponsel menggunakan akun email.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci tablet menggunakan akun email.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci ponsel menggunakan akun email.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Kode PIN SIM salah. Hubungi operator untuk membuka kunci perangkat."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">Kode PIN SIM salah, sisa <xliff:g id="NUMBER_1">%d</xliff:g> percobaan.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Mode pesawat"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Pola diperlukan jika Anda memulai ulang perangkat."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"PIN diperlukan jika Anda memulai ulang perangkat."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Sandi diperlukan jika Anda memulai ulang perangkat."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Pola diperlukan untuk keamanan tambahan."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"PIN diperlukan untuk keamanan tambahan."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Sandi diperlukan untuk keamanan tambahan."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Pola diperlukan jika Anda beralih profil."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"PIN diperlukan jika Anda beralih profil."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Sandi diperlukan jika Anda beralih profil."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Sandi diperlukan setelah perangkat dimulai ulang"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Pola diperlukan untuk keamanan tambahan"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"PIN diperlukan untuk keamanan tambahan"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Sandi diperlukan untuk keamanan tambahan"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Pola diperlukan jika Anda beralih profil"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"PIN diperlukan jika Anda beralih profil"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Sandi diperlukan jika Anda beralih profil"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">Perangkat belum dibuka kuncinya selama <xliff:g id="NUMBER_1">%d</xliff:g> jam. Konfirmasi pola.</item>
       <item quantity="one">Perangkat belum dibuka kuncinya selama <xliff:g id="NUMBER_0">%d</xliff:g> jam. Konfirmasi pola.</item>
diff --git a/packages/Keyguard/res/values-is-rIS/strings.xml b/packages/Keyguard/res/values-is-rIS/strings.xml
index 23e135b..53c33f0 100644
--- a/packages/Keyguard/res/values-is-rIS/strings.xml
+++ b/packages/Keyguard/res/values-is-rIS/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Prófaðu aftur að setja inn rétt PUK-númer. Endurteknar tilraunir gera SIM-kortið varanlega óvirkt."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-númerin stemma ekki"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Of margar tilraunir til að teikna mynstur"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Þú hefur slegið inn rangt PIN-númer <xliff:g id="NUMBER_0">%d</xliff:g> sinnum. \n\nReyndu aftur eftir <xliff:g id="NUMBER_1">%d</xliff:g> sekúndur."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Þú hefur slegið inn rangt aðgangsorð <xliff:g id="NUMBER_0">%d</xliff:g> sinnum. \n\nReyndu aftur eftir <xliff:g id="NUMBER_1">%d</xliff:g> sekúndur."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%d</xliff:g> sinnum. \n\nReyndu aftur eftir <xliff:g id="NUMBER_1">%d</xliff:g> sekúndur."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Þú hefur gert <xliff:g id="NUMBER_0">%d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Eftir <xliff:g id="NUMBER_1">%d</xliff:g> árangurslausar tilraunir í viðbót verður spjaldtölvan endurstillt, með þeim afleiðingum að öllum gögnum hennar verður eytt."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Þú hefur gert <xliff:g id="NUMBER_0">%d</xliff:g> árangurslausar tilraunir til að opna símann. Eftir <xliff:g id="NUMBER_1">%d</xliff:g> árangurslausar tilraunir í viðbót verður síminn endurstilltur, með þeim afleiðingum að öllum gögnum hans verður eytt."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Þú hefur slegið inn rangt PIN-númer <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. \n\nReyndu aftur eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> sekúndur."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Þú hefur slegið inn rangt aðgangsorð <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. \n\nReyndu aftur eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> sekúndur."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. \n\nReyndu aftur eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> sekúndur."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Þú hefur gert <xliff:g id="NUMBER_0">%1$d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður spjaldtölvan endurstillt, með þeim afleiðingum að öllum gögnum hennar verður eytt."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Þú hefur gert <xliff:g id="NUMBER_0">%1$d</xliff:g> árangurslausar tilraunir til að opna símann. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður síminn endurstilltur, með þeim afleiðingum að öllum gögnum hans verður eytt."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Spjaldtölvan verður endurstillt, með þeim afleiðingum að öllum gögnum hennar verður eytt."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna símann. Síminn verður endurstilltur, með þeim afleiðingum að öllum gögnum hans verður eytt."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Þú hefur gert <xliff:g id="NUMBER_0">%d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Eftir <xliff:g id="NUMBER_1">%d</xliff:g> árangurslausar tilraunir í viðbót verður notandinn fjarlægður með þeim afleiðingum að öllum notandagögnum verður eytt."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Þú hefur gert <xliff:g id="NUMBER_0">%d</xliff:g> árangurslausar tilraunir til að opna símann. Eftir <xliff:g id="NUMBER_1">%d</xliff:g> árangurslausar tilraunir í viðbót verður notandinn fjarlægður með þeim afleiðingum að öllum notandagögnum verður eytt."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Þú hefur gert <xliff:g id="NUMBER_0">%1$d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður notandinn fjarlægður með þeim afleiðingum að öllum notandagögnum verður eytt."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Þú hefur gert <xliff:g id="NUMBER_0">%1$d</xliff:g> árangurslausar tilraunir til að opna símann. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður notandinn fjarlægður með þeim afleiðingum að öllum notandagögnum verður eytt."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Notandinn verður fjarlægður, með þeim afleiðingum að öllum notandagögnum verður eytt."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna símann. Notandinn verður fjarlægður, með þeim afleiðingum að öllum notandagögnum verður eytt."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Þú hefur gert <xliff:g id="NUMBER_0">%d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Eftir <xliff:g id="NUMBER_1">%d</xliff:g> árangurslausar tilraunir í viðbót verður vinnusniðið fjarlægt með þeim afleiðingum að öllum gögnum þess verður eytt."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Þú hefur gert <xliff:g id="NUMBER_0">%d</xliff:g> árangurslausar tilraunir til að opna símann. Eftir <xliff:g id="NUMBER_1">%d</xliff:g> árangurslausar tilraunir í viðbót verður vinnusniðið fjarlægt með þeim afleiðingum að öllum gögnum þess verður eytt."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Þú hefur gert <xliff:g id="NUMBER_0">%1$d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður vinnusniðið fjarlægt með þeim afleiðingum að öllum gögnum þess verður eytt."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Þú hefur gert <xliff:g id="NUMBER_0">%1$d</xliff:g> árangurslausar tilraunir til að opna símann. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður vinnusniðið fjarlægt með þeim afleiðingum að öllum gögnum þess verður eytt."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Vinnusniðið verður fjarlægt, með þeim afleiðingum að öllum gögnum þess verður eytt."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna símann. Vinnusniðið verður fjarlægt, með þeim afleiðingum að öllum gögnum þess verður eytt."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%d</xliff:g> árangurslausar tilraunir í viðbót verður þú beðin(n) um að opna spjaldtölvuna með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%d</xliff:g> sekúndur."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%d</xliff:g> árangurslausar tilraunir í viðbót verður þú beðin(n) um að opna símann með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%d</xliff:g> sekúndur."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður þú beðin(n) um að opna spjaldtölvuna með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%3$d</xliff:g> sekúndur."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður þú beðin(n) um að opna símann með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%3$d</xliff:g> sekúndur."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Rangt PIN-númer SIM-korts. Þú þarft núna að hafa samband við símafyrirtækið þitt til að taka tækið úr lás."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">Rangt PIN-númer SIM-korts. Þú átt <xliff:g id="NUMBER_1">%d</xliff:g> tilraun eftir.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Flugstilling"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Mynsturs er krafist þegar þú endurræsir tækið."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"PIN-númers er krafist þegar þú endurræsir tækið."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Aðgangsorðs er krafist þegar þú endurræsir tækið."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Mynsturs er krafist af öryggisástæðum."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"PIN-númers er krafist af öryggisástæðum."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Aðgangsorðs er krafist af öryggisástæðum."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Mynsturs er krafist þegar þú skiptir um snið."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"PIN-númers er krafist þegar þú skiptir um snið."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Aðgangsorðs er krafist þegar þú skiptir um snið."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Aðgangsorðs er krafist þegar tækið er endurræst"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Mynsturs er krafist af öryggisástæðum"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"PIN-númers er krafist af öryggisástæðum"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Aðgangsorðs er krafist af öryggisástæðum"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Mynsturs er krafist þegar þú skiptir um snið"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"PIN-númers er krafist þegar þú skiptir um snið"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Aðgangsorðs er krafist þegar þú skiptir um snið"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="one">Tækið hefur ekki verið tekið úr lás í <xliff:g id="NUMBER_1">%d</xliff:g> klukkustund. Staðfestu mynstrið.</item>
       <item quantity="other">Tækið hefur ekki verið tekið úr lás í <xliff:g id="NUMBER_1">%d</xliff:g> klukkustundir. Staðfestu mynstrið.</item>
diff --git a/packages/Keyguard/res/values-it/strings.xml b/packages/Keyguard/res/values-it/strings.xml
index 98cb0b2..6ede2f9 100644
--- a/packages/Keyguard/res/values-it/strings.xml
+++ b/packages/Keyguard/res/values-it/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Inserisci di nuovo il codice PUK corretto. Ripetuti tentativi comportano la disattivazione definitiva della scheda SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"I codici PIN non corrispondono"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Troppi tentativi di inserimento della sequenza"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Hai digitato il tuo PIN <xliff:g id="NUMBER_0">%d</xliff:g> volte in modo errato. \n\nRiprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Hai digitato la tua password <xliff:g id="NUMBER_0">%d</xliff:g> volte in modo errato. \n\nRiprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. \n\nRiprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER_0">%d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, il tablet verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER_0">%d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, il telefono verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Hai digitato il tuo PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> volte in modo errato. \n\nRiprova tra <xliff:g id="NUMBER_1">%2$d</xliff:g> secondi."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Hai digitato la tua password <xliff:g id="NUMBER_0">%1$d</xliff:g> volte in modo errato. \n\nRiprova tra <xliff:g id="NUMBER_1">%2$d</xliff:g> secondi."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. \n\nRiprova tra <xliff:g id="NUMBER_1">%2$d</xliff:g> secondi."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER_0">%1$d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, il tablet verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER_0">%1$d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, il telefono verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il tablet verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il telefono verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER_0">%d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, questo utente verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER_0">%d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, questo utente verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER_0">%1$d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, questo utente verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER_0">%1$d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, questo utente verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Questo utente verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Questo utente verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER_0">%d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, il profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER_0">%d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, il profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER_0">%1$d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, il profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER_0">%1$d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, il profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il tablet con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il tablet con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%3$d</xliff:g> secondi."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%3$d</xliff:g> secondi."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Codice PIN della SIM errato. Devi contattare l\'operatore per sbloccare il dispositivo."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">Codice PIN della SIM errato. Hai ancora <xliff:g id="NUMBER_1">%d</xliff:g> tentativi a disposizione.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Modalità aereo"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Sequenza obbligatoria dopo il riavvio del dispositivo."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"PIN obbligatorio dopo il riavvio del dispositivo."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Password obbligatoria dopo il riavvio del dispositivo."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Pattern obbligatorio per una maggiore sicurezza."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"PIN obbligatorio per una maggiore sicurezza."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Password obbligatoria per una maggiore sicurezza."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Sequenza obbligatoria dopo aver cambiato profilo."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"PIN obbligatorio dopo aver cambiato profilo."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Password obbligatoria dopo aver cambiato profilo."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Password obbligatoria dopo il riavvio del dispositivo"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Sequenza obbligatoria per maggiore sicurezza"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"PIN obbligatorio per maggiore sicurezza"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Password obbligatoria per maggiore sicurezza"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Sequenza obbligatoria dopo aver cambiato profilo"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"PIN obbligatorio dopo aver cambiato profilo"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Password obbligatoria dopo aver cambiato profilo"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">Il dispositivo non viene sbloccato da <xliff:g id="NUMBER_1">%d</xliff:g> ore. Conferma la sequenza.</item>
       <item quantity="one">Il dispositivo non viene sbloccato da <xliff:g id="NUMBER_0">%d</xliff:g> ora. Conferma la sequenza.</item>
diff --git a/packages/Keyguard/res/values-iw/strings.xml b/packages/Keyguard/res/values-iw/strings.xml
index 7ffa676..43ff724 100644
--- a/packages/Keyguard/res/values-iw/strings.xml
+++ b/packages/Keyguard/res/values-iw/strings.xml
@@ -77,23 +77,23 @@
     <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">%d</xliff:g> פעמים. \n\nנסה שוב בעוד <xliff:g id="NUMBER_1">%d</xliff:g> שניות."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"הקלדת סיסמה שגויה <xliff:g id="NUMBER_0">%d</xliff:g> פעמים.\n\nנסה שוב בעוד <xliff:g id="NUMBER_1">%d</xliff:g> שניות."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"שרטטת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים. \n\nנסה שוב בעוד <xliff:g id="NUMBER_1">%d</xliff:g> שניות."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER_0">%d</xliff:g> פעמים באופן שגוי. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, טאבלט זה יאופס וכתוצאה מכך כל הנתונים שלו יימחקו."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER_0">%d</xliff:g> פעמים באופן שגוי. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, טלפון זה יאופס וכתוצאה מכך כל הנתונים שלו יימחקו."</string>
+    <string name="kg_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">"שרטטת את קו ביטול הנעילה באופן שגוי <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">%d</xliff:g> פעמים באופן שגוי. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, משתמש זה יוסר וכתוצאה מכך כל נתוני המשתמש יימחקו."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER_0">%d</xliff:g> פעמים באופן שגוי. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, משתמש זה יוסר וכתוצאה מכך כל נתוני המשתמש יימחקו."</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> פעמים באופן שגוי. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, פרופיל העבודה יוסר וכתוצאה מכך כל נתוני הפרופיל יימחקו."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER_0">%d</xliff:g> פעמים באופן שגוי. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, פרופיל העבודה יוסר וכתוצאה מכך כל נתוני הפרופיל יימחקו."</string>
+    <string name="kg_failed_attempts_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">"שרטטת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילת הטאבלט באמצעות חשבון אימייל‏.\n\nנסה שוב בעוד <xliff:g id="NUMBER_2">%d</xliff:g> שניות."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"שרטטת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילת הטלפון באמצעות חשבון אימייל‏.\n\nנסה שוב בעוד <xliff:g id="NUMBER_2">%d</xliff:g> שניות."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"שרטטת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילת הטאבלט באמצעות חשבון אימייל‏.\n\nנסה שוב בעוד <xliff:g id="NUMBER_2">%3$d</xliff:g> שניות."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"שרטטת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילת הטלפון באמצעות חשבון אימייל‏.\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="two">‏קוד PIN שגוי של כרטיס SIM. נותרו לך <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות.</item>
@@ -114,15 +114,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"אין קליטה."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"לחצן החלפת שיטת קלט."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"מצב טיסה"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"יש להזין את קו ביטול הנעילה לאחר אתחול המכשיר."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"‏יש להזין את ה-PIN לאחר אתחול המכשיר."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"יש להזין את הסיסמה לאחר אתחול המכשיר."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"יש להזין את קו ביטול הנעילה על מנת להגביר את רמת האבטחה."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"‏יש להזין PIN על מנת להגביר את רמת האבטחה."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"יש להזין סיסמה על מנת להגביר את רמת האבטחה."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"יש להזין את קו ביטול הנעילה בעת מעבר בין פרופילים."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"‏יש להזין את ה-PIN בעת מעבר בין פרופילים."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"יש להזין את הסיסמה בעת מעבר בין פרופילים."</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="two">נעילת המכשיר לא בוטלה במשך <xliff:g id="NUMBER_1">%d</xliff:g> שעות. אשר את קו ביטול הנעילה.</item>
       <item quantity="many">נעילת המכשיר לא בוטלה במשך <xliff:g id="NUMBER_1">%d</xliff:g> שעות. אשר את קו ביטול הנעילה.</item>
diff --git a/packages/Keyguard/res/values-ja/strings.xml b/packages/Keyguard/res/values-ja/strings.xml
index 3230beb..503e18e 100644
--- a/packages/Keyguard/res/values-ja/strings.xml
+++ b/packages/Keyguard/res/values-ja/strings.xml
@@ -77,23 +77,23 @@
     <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">%d</xliff:g>回間違えました。\n\n<xliff:g id="NUMBER_1">%d</xliff:g>秒後にもう一度お試しください。"</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"パスワードの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。\n\n<xliff:g id="NUMBER_1">%d</xliff:g>秒後にもう一度お試しください。"</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"ロック解除パターンの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。\n\n<xliff:g id="NUMBER_1">%d</xliff:g>秒後にもう一度お試しください。"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"タブレットのロック解除に<xliff:g id="NUMBER_0">%d</xliff:g>回失敗しました。あと<xliff:g id="NUMBER_1">%d</xliff:g>回失敗すると、このタブレットはリセットされ、データがすべて削除されます。"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"携帯電話のロック解除に<xliff:g id="NUMBER_0">%d</xliff:g>回失敗しました。あと<xliff:g id="NUMBER_1">%d</xliff:g>回失敗すると、この携帯電話はリセットされ、データがすべて削除されます。"</string>
+    <string name="kg_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">"ロック解除パターンの入力を<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">%d</xliff:g>回失敗しました。あと<xliff:g id="NUMBER_1">%d</xliff:g>回失敗すると、このユーザーは削除され、ユーザーのデータがすべて削除されます。"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"携帯電話のロック解除に<xliff:g id="NUMBER_0">%d</xliff:g>回失敗しました。あと<xliff:g id="NUMBER_1">%d</xliff:g>回失敗すると、このユーザーは削除され、ユーザーのデータがすべて削除されます。"</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g>回失敗しました。あと<xliff:g id="NUMBER_1">%d</xliff:g>回失敗すると、仕事用プロファイルが削除され、プロファイルのデータがすべて削除されます。"</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"スマートフォンのロック解除に<xliff:g id="NUMBER_0">%d</xliff:g>回失敗しました。あと<xliff:g id="NUMBER_1">%d</xliff:g>回失敗すると、仕事用プロファイルが削除され、プロファイルのデータがすべて削除されます。"</string>
+    <string name="kg_failed_attempts_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">"ロック解除パターンの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。あと<xliff:g id="NUMBER_1">%d</xliff:g>回間違えると、タブレットのロック解除にメールアカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%d</xliff:g>秒後にもう一度お試しください。"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ロック解除パターンの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。あと<xliff:g id="NUMBER_1">%d</xliff:g>回間違えると、携帯端末のロック解除にメールアカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%d</xliff:g>秒後にもう一度お試しください。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ロック解除パターンの入力を<xliff:g id="NUMBER_0">%1$d</xliff:g>回間違えました。あと<xliff:g id="NUMBER_1">%2$d</xliff:g>回間違えると、タブレットのロック解除にメールアカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g>秒後にもう一度お試しください。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ロック解除パターンの入力を<xliff:g id="NUMBER_0">%1$d</xliff:g>回間違えました。あと<xliff:g id="NUMBER_1">%2$d</xliff:g>回間違えると、携帯端末のロック解除にメールアカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g>秒後にもう一度お試しください。"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM PINコードが無効です。お使いの端末をロック解除するには携帯通信会社にお問い合わせいただく必要があります。"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">SIM PINコードが無効です。入力できるのはあと<xliff:g id="NUMBER_1">%d</xliff:g>回です。</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"通信サービスはありません。"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"入力方法の切り替えボタン。"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"機内モード"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"端末を再起動した時にはパターンが必要です。"</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"端末を再起動した時にはPINが必要です。"</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"端末を再起動した時にはパスワードが必要です。"</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"セキュリティを強化するため、パターンが必要です。"</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"セキュリティを強化するため、PINが必要です。"</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"セキュリティを強化するため、パスワードが必要です。"</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"プロファイルを切り替えるにはパターンが必要です。"</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"プロファイルを切り替えるにはPINが必要です。"</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"プロファイルを切り替えるにはパスワードが必要です。"</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="other">端末のロックが<xliff:g id="NUMBER_1">%d</xliff:g>時間、解除されていません。パターンを確認してください。</item>
       <item quantity="one">端末のロックが<xliff:g id="NUMBER_0">%d</xliff:g>時間、解除されていません。パターンを確認してください。</item>
diff --git a/packages/Keyguard/res/values-ka-rGE/strings.xml b/packages/Keyguard/res/values-ka-rGE/strings.xml
index c9b31cd..2fdd668 100644
--- a/packages/Keyguard/res/values-ka-rGE/strings.xml
+++ b/packages/Keyguard/res/values-ka-rGE/strings.xml
@@ -77,23 +77,23 @@
     <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">"თქვენ <xliff:g id="NUMBER_0">%d</xliff:g>-ჯერ არასწორად შეიყვანეთ PIN კოდი. \n\nსცადეთ ხელახლა <xliff:g id="NUMBER_1">%d</xliff:g> წამში."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"თქვენ <xliff:g id="NUMBER_0">%d</xliff:g>-ჯერ არასწორად დაბეჭდეთ თქვენი პაროლი. \n\nხელახლა სცადეთ <xliff:g id="NUMBER_1">%d</xliff:g> წამში."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"თქვენ <xliff:g id="NUMBER_0">%d</xliff:g>-ჯერ დახატეთ განბლოკვის ნიმუში. \n\nსცადეთ ხელახლა <xliff:g id="NUMBER_1">%d</xliff:g> წამში."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"თქვენ არასწორად სცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER_0">%d</xliff:g> ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი ცდის შემდეგ, ეს ტაბლეტი გადაიტვირთება, რაც წაშლის მის მთლიან მონაცემს."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"თქვენ არასწორად სცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER_0">%d</xliff:g> ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ეს ტელეფონი გადაიტვირთება, რაც წაშლის მის მთლიან მონაცემს."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"თქვენ <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ არასწორად შეიყვანეთ PIN კოდი. \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">"თქვენ <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">%d</xliff:g> ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ამოიშლება ეს მომხმარებელი და წაიშლება მომხმარებლის მთლიანი მონაცემი."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"თქვენ არასწორად სცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER_0">%d</xliff:g> ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ამოიშლება ეს მომხმარებელი და წაიშლება მომხმარებლის მთლიანი მონაცემი."</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ამოიშლება სამუშაო პროფილი და წაიშლება პროფილის მთლიანი მონაცემი."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"თქვენ არასწორად სცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER_0">%d</xliff:g> ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ამოიშლება სამუშაო პროფილი და წაიშლება მთლიანი პროფილის მონაცემი."</string>
+    <string name="kg_failed_attempts_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">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%d</xliff:g> ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი ცდის შემდეგ მოგთხოვთ ტაბლეტის განბლოკვას ელფოსტის ანგარიშის გამოყენებით.\n\n ხელახლა სცადეთ <xliff:g id="NUMBER_2">%d</xliff:g> წამში."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი ცდის შემდეგ, დაგჭირდებათ თქვენი ტელეფონის განბლოკვა ელფოსტის ანგარიშის გამოყენებით.\n\n ხელახლა სცადეთ <xliff:g id="NUMBER_2">%d</xliff:g> წამში."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%1$d</xliff:g> ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი ცდის შემდეგ მოგთხოვთ ტაბლეტის განბლოკვას ელფოსტის ანგარიშის გამოყენებით.\n\n ხელახლა სცადეთ <xliff:g id="NUMBER_2">%3$d</xliff:g> წამში."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი ცდის შემდეგ, დაგჭირდებათ თქვენი ტელეფონის განბლოკვა ელფოსტის ანგარიშის გამოყენებით.\n\n ხელახლა სცადეთ <xliff:g id="NUMBER_2">%3$d</xliff:g> წამში."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM-ის არასწორი PIN კოდი. თქვენ ახლა მოგიწევთ მოწყობილობის განსაბლოკად მიმართოთ ოპერატორს."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">SIM-ის PIN კოდი არასწორია. თქვენ დაგრჩათ <xliff:g id="NUMBER_1">%d</xliff:g> მცდელობა.</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"არ არის სერვისი."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"შეყვანის მეთოდის გადართვის ღილაკი."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"თვითმფრინავის რეჟიმი"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"ნიმუში საჭიროა მოწყობილობის გადატვირთვისას."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"PIN-კოდი საჭიროა მოწყობილობის გადატვირთვისას."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"პაროლი საჭიროა მოწყობილობის გადატვირთვისას."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"ნიმუშია საჭირო დამატებითი უსაფრთხოებისთვის."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"PIN-კოდია საჭირო დამატებითი უსაფრთხოებისთვის."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"პაროლია საჭირო დამატებითი უსაფრთხოებისთვის."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"ნიმუში საჭიროა პროფილების გადართვისას."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"PIN-კოდი საჭიროა პროფილების გადართვისას."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"პაროლი საჭიროა პროფილების გადართვისას."</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="other">მოწყობილობა არ განბლოკილა <xliff:g id="NUMBER_1">%d</xliff:g> საათის განმავლობაში. დაადასტურეთ ნიმუში.</item>
       <item quantity="one">მოწყობილობა არ განბლოკილა <xliff:g id="NUMBER_0">%d</xliff:g> საათის განმავლობაში. დაადასტურეთ ნიმუში.</item>
diff --git a/packages/Keyguard/res/values-kk-rKZ/strings.xml b/packages/Keyguard/res/values-kk-rKZ/strings.xml
index ea3992d..fd5cf93 100644
--- a/packages/Keyguard/res/values-kk-rKZ/strings.xml
+++ b/packages/Keyguard/res/values-kk-rKZ/strings.xml
@@ -77,23 +77,23 @@
     <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">%d</xliff:g> рет қате тердіңіз. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> секундтан кейін қайталаңыз."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Құпия сөзді <xliff:g id="NUMBER_0">%d</xliff:g> рет қате тердіңіз. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> секундтан кейін қайталаңыз."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Құлыпты ашу өрнегін <xliff:g id="NUMBER_0">%d</xliff:g> рет қате салдыңыз. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Планшет бекітпесін ашуға <xliff:g id="NUMBER_0">%d</xliff:g> рет дұрыс емес әрекет жасадыңыз. Тағы <xliff:g id="NUMBER_1">%d</xliff:g> сәтсіз әрекеттен кейін осы планшет қалпына келтіріліп, оның бүкіл деректері жойылады."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Телефон бекітпесін ашуға <xliff:g id="NUMBER_0">%d</xliff:g> рет дұрыс емес әрекет жасадыңыз. Тағы <xliff:g id="NUMBER_1">%d</xliff:g> сәтсіз әрекеттен кейін осы телефон қалпына келтіріліп, оның бүкіл деректері жойылады."</string>
+    <string name="kg_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">"Құлыпты ашу өрнегін <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">%d</xliff:g> рет дұрыс емес әрекет жасадыңыз. Тағы <xliff:g id="NUMBER_1">%d</xliff:g> сәтсіз әрекеттен кейін осы пайдаланушы жойылып, бүкіл пайдаланушы деректері жойылады."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Телефон бекітпесін ашуға <xliff:g id="NUMBER_0">%d</xliff:g> рет дұрыс емес әрекет жасадыңыз. Тағы <xliff:g id="NUMBER_1">%d</xliff:g> сәтсіз әрекеттен кейін осы пайдаланушы жойылып, бүкіл пайдаланушы деректері жойылады."</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> рет дұрыс емес әрекет жасадыңыз. Тағы <xliff:g id="NUMBER_1">%d</xliff:g> сәтсіз әрекеттен кейін жұмыс профилі жойылып, бүкіл профиль деректері жойылады."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Телефон бекітпесін ашуға <xliff:g id="NUMBER_0">%d</xliff:g> рет дұрыс емес әрекет жасадыңыз. Тағы <xliff:g id="NUMBER_1">%d</xliff:g> сәтсіз әрекеттен кейін жұмыс профилі жойылып, бүкіл профиль деректері жойылады."</string>
+    <string name="kg_failed_attempts_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">"Бекітпені ашу кескінін <xliff:g id="NUMBER_0">%d</xliff:g> рет қате сыздыңыз. After <xliff:g id="NUMBER_1">%d</xliff:g> сәтсіз әрекеттен кейін планшетіңізді есептік жазба арқылы ашу өтінішін аласыз.\n\n  <xliff:g id="NUMBER_2">%d</xliff:g> секундтан кейін қайта әрекеттеніңіз."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Бекітпені ашу кескінін <xliff:g id="NUMBER_0">%d</xliff:g> рет қате сыздыңыз. <xliff:g id="NUMBER_1">%d</xliff:g> сәтсіз әрекеттен кейін телефоныңызды есептік жазба арқылы ашу өтінішін аласыз. \n\n <xliff:g id="NUMBER_2">%d</xliff:g> секундтан кейін қайта әрекеттеніңіз."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Бекітпені ашу кескінін <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате сыздыңыз. After <xliff:g id="NUMBER_1">%2$d</xliff:g> сәтсіз әрекеттен кейін планшетіңізді есептік жазба арқылы ашу өтінішін аласыз.\n\n  <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін қайта әрекеттеніңіз."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Бекітпені ашу кескінін <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате сыздыңыз. <xliff:g id="NUMBER_1">%2$d</xliff:g> сәтсіз әрекеттен кейін телефоныңызды есептік жазба арқылы ашу өтінішін аласыз. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін қайта әрекеттеніңіз."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM PIN коды дұрыс емес, құрылғыны ашу үшін қызмет жабдықтаушыға  хабарласаңыз."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">SIM PIN коды дұрыс емес, <xliff:g id="NUMBER_1">%d</xliff:g> әрекет қалды.</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Қызмет көрсетілмейді."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Енгізу әдісі түймесін ауыстыру."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Ұшақ режимі"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Құрылғыны өшіріп, қайта қосқанда, өрнекті енгізу қажет."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Құрылғыны өшіріп, қайта қосқанда, PIN кодын енгізу қажет."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Құрылғыны өшіріп, қайта қосқанда, құпия сөзді енгізу қажет."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Қосымша қауіпсіздік үшін өрнек қажет."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Қосымша қауіпсіздік үшін PIN коды қажет."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Қосымша қауіпсіздік үшін құпия сөз қажет."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Профильдерді ауыстырғанда, өрнекті енгізу қажет."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Профильдерді ауыстырғанда, PIN кодын енгізу қажет."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Профильдерді ауыстырғанда, құпия сөзді енгізу қажет."</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="other">Құрылғы құлпы <xliff:g id="NUMBER_1">%d</xliff:g> сағат бойы ашылмады. Өрнекті растаңыз.</item>
       <item quantity="one">Құрылғы құлпы <xliff:g id="NUMBER_0">%d</xliff:g> сағат бойы ашылмады. Өрнекті растаңыз.</item>
diff --git a/packages/Keyguard/res/values-km-rKH/strings.xml b/packages/Keyguard/res/values-km-rKH/strings.xml
index 3803abf..2da8370 100644
--- a/packages/Keyguard/res/values-km-rKH/strings.xml
+++ b/packages/Keyguard/res/values-km-rKH/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"បញ្ចូល​កូដ PUK ម្ដង​ទៀត។ ការ​ព្យាយាម​ដដែល​ច្រើន​ដឹង​នឹង​បិទ​ស៊ីម​កាត​ជា​អចិន្ត្រៃយ៍។"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"កូដ PIN មិន​ដូច​គ្នា"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ព្យាយាម​លំនាំ​ច្រើន​ពេក"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"អ្នក​បាន​បញ្ចូល​កូដ PIN របស់​អ្នក​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%d</xliff:g> ដង។\n\n ព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈ​ពេល <xliff:g id="NUMBER_1">%d</xliff:g> វិនាទី។"</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"អ្នក​បាន​បញ្ចូល​ពាក្យ​សម្ងាត់​មិន​ត្រឹមត្រូវ <xliff:g id="NUMBER_0">%d</xliff:g> ដង។\n\nព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈ​ពេល <xliff:g id="NUMBER_1">%d</xliff:g> វិនាទី។"</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"អ្នក​បាន​​គូរ​លំនាំ​ដោះ​សោ​របស់​អ្នក​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%d</xliff:g> ដង។\n\nព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈ​ពេល <xliff:g id="NUMBER_1">%d</xliff:g> វិនាទី។"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើថេប្លេតរបស់អ្នក <xliff:g id="NUMBER_0">%d</xliff:g> ដង។ បន្ទាប់ពីការព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដងទៀត ថេប្លេតនេះនឹងត្រូវបានកំណត់ឡើងវិញ ដែលវានឹងលុបទិន្នន័យរបស់វាទាំងអស់។"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើទូរស័ព្ទរបស់អ្នក <xliff:g id="NUMBER_0">%d</xliff:g> ដង។ បន្ទាប់ពីការព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដងទៀត ទូរស័ព្ទនេះនឹងត្រូវបានកំណត់ឡើងវិញ ដែលវានឹងលុបទិន្នន័យរបស់វាទាំងអស់។"</string>
+    <string name="kg_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">"អ្នក​បាន​​គូរ​លំនាំ​ដោះ​សោ​របស់​អ្នក​មិន​ត្រឹមត្រូវ​ចំនួន <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">%d</xliff:g> ដង។ បន្ទាប់ពីការព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដងទៀត អ្នកប្រើនេះនឹងត្រូវបានដកចេញ ដែលវានឹងលុបទិន្នន័យអ្នកប្រើទាំងអស់។"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើទូរស័ព្ទរបស់អ្នក <xliff:g id="NUMBER_0">%d</xliff:g> ដង។ បន្ទាប់ពីការព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដងទៀត អ្នកប្រើនេះនឹងត្រូវបានដកចេញ ដែលវានឹងលុបទិន្នន័យអ្នកប្រើទាំងអស់។"</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> ដង។ បន្ទាប់ពីការព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដងទៀត ប្រវត្តិរូបការងាររបស់អ្នកនឹងត្រូវបានដកចេញ ដែលវានឹងលុបទិន្នន័យប្រវត្តិរូបទាំងអស់។"</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើទូរស័ព្ទរបស់អ្នក <xliff:g id="NUMBER_0">%d</xliff:g> ដង។ បន្ទាប់ពីការព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដងទៀត ប្រវត្តិរូបការងាររបស់អ្នកនឹងត្រូវបានដកចេញ ដែលវានឹងលុបទិន្នន័យប្រវត្តិរូបទាំងអស់។"</string>
+    <string name="kg_failed_attempts_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">"អ្នក​បាន​គូរ​លំនាំ​ដោះ​សោ​មិន​ត្រឹមត្រូវ <xliff:g id="NUMBER_0">%d</xliff:g> ដង។ បន្ទាប់​ពី​ការ​ព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដង​មិន​ជោគជ័យ អ្នក​នឹង​ត្រូវ​បាន​ស្នើ​ឲ្យ​ដោះ​សោ​កុំព្យូទ័រ​បន្ទះ​របស់​អ្នក ដោយ​ប្រើ​គណនី​អ៊ីមែល។\n\n ព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈ​ពេល <xliff:g id="NUMBER_2">%d</xliff:g> វិនាទី។"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"អ្នក​បាន​គូរ​លំនាំ​ដោះ​​សោ​របស់​អ្នក​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%d</xliff:g> ដង។ បន្ទាប់​ពី​ការ​ព្យាយាម​មិន​ជោគជ័យ​​ច្រើនជាង <xliff:g id="NUMBER_1">%d</xliff:g> ដង អ្នក​នឹង​ត្រូវ​បាន​​ស្នើ​ឲ្យ​ដោះ​សោ​ទូរស័ព្ទ​របស់​អ្នក​ដោយ​ប្រើ​គណនី​អ៊ីមែល។\n\n ព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈ​ពេល <xliff:g id="NUMBER_2">%d</xliff:g> វិនាទី។"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"អ្នក​បាន​គូរ​លំនាំ​ដោះ​សោ​មិន​ត្រឹមត្រូវ <xliff:g id="NUMBER_0">%1$d</xliff:g> ដង។ បន្ទាប់​ពី​ការ​ព្យាយាម <xliff:g id="NUMBER_1">%2$d</xliff:g> ដង​មិន​ជោគជ័យ អ្នក​នឹង​ត្រូវ​បាន​ស្នើ​ឲ្យ​ដោះ​សោ​កុំព្យូទ័រ​បន្ទះ​របស់​អ្នក ដោយ​ប្រើ​គណនី​អ៊ីមែល។\n\n ព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈ​ពេល <xliff:g id="NUMBER_2">%3$d</xliff:g> វិនាទី។"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"អ្នក​បាន​គូរ​លំនាំ​ដោះ​​សោ​របស់​អ្នក​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដង។ បន្ទាប់​ពី​ការ​ព្យាយាម​មិន​ជោគជ័យ​​ច្រើនជាង <xliff:g id="NUMBER_1">%2$d</xliff:g> ដង អ្នក​នឹង​ត្រូវ​បាន​​ស្នើ​ឲ្យ​ដោះ​សោ​ទូរស័ព្ទ​របស់​អ្នក​ដោយ​ប្រើ​គណនី​អ៊ីមែល។\n\n ព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈ​ពេល <xliff:g id="NUMBER_2">%3$d</xliff:g> វិនាទី។"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"លេខ​កូដ PIN ស៊ីម​មិន​ត្រឹមត្រូវ អ្នក​ត្រូវ​ទាក់ទង​ក្រុមហ៊ុន​បញ្ជូន​របស់​អ្នក​ឥឡូវ​នេះ ដើម្បី​ដោះ​សោ​ឧបករណ៍​របស់​អ្នក។"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">លេខកូដសម្ងាត់ស៊ីមមិនត្រឹមត្រូវ អ្នកនៅសល់ការព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដងទៀត</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"គ្មាន​សេវា​"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ប្ដូរ​ប៊ូតុង​វិធីសាស្ត្រ​បញ្ចូល។"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"របៀបក្នុងយន្តហោះ"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"តម្រូវឲ្យមានលំនាំនៅពេលដែលអ្នកចាប់ផ្តើមឧបករណ៍ឡើងវិញ។"</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"តម្រូវឲ្យមានកូដ PIN នៅពេលដែលអ្នកចាប់ផ្តើមឧបករណ៍ឡើងវិញ។"</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"តម្រូវឲ្យមានពាក្យសម្ងាត់នៅពេលដែលអ្នកចាប់ផ្តើមឧបករណ៍ឡើងវិញ។"</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"តម្រូវឲ្យមានលំនាំសម្រាប់សវុត្ថិភាពបន្ថែម"</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"តម្រូវឲ្យមានកូដ PIN សម្រាប់សុវត្ថិភាពបន្ថែម"</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"តម្រូវឲ្យមានពាក្យសម្ងាត់សម្រាប់សុវត្ថិភាពបន្ថែម"</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"តម្រូវឲ្យមានលំនាំនៅពេលដែលអ្នកប្តូរប្រវត្តិរូបរបស់អ្នក។"</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"តម្រូវឲ្យមានកូដ PIN នៅពេលដែលអ្នកប្តូរប្រវត្តិរូបរបស់អ្នក។"</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"តម្រូវឲ្យមានពាក្យសម្ងាត់នៅពេលដែលអ្នកប្តូរប្រវត្តិរូបរបស់អ្នក។"</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="other">ឧបករណ៍មិនបានដោះសោអស់រយៈពេល <xliff:g id="NUMBER_1">%d</xliff:g> ម៉ោងហើយ។ បញ្ជាប់លំនាំ។</item>
       <item quantity="one">ឧបករណ៍មិនបានដោះសោអស់រយៈពេល <xliff:g id="NUMBER_0">%d</xliff:g> ម៉ោងហើយ។ បញ្ជាក់លំនាំ។</item>
diff --git a/packages/Keyguard/res/values-kn-rIN/strings.xml b/packages/Keyguard/res/values-kn-rIN/strings.xml
index c3d2a61..31deb66 100644
--- a/packages/Keyguard/res/values-kn-rIN/strings.xml
+++ b/packages/Keyguard/res/values-kn-rIN/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"ಸರಿಯಾದ PUK ಕೋಡ್ ಅನ್ನು ಮರು-ನಮೂದಿಸಿ. ಸತತ ಪ್ರಯತ್ನಗಳು ಸಿಮ್‌ ಅನ್ನು ಶಾಶ್ವತವಾಗಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ಪಿನ್‌ ಕೋಡ್‍ಗಳು ಹೊಂದಾಣಿಕೆಯಾಗುತ್ತಿಲ್ಲ"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ಹಲವಾರು ಪ್ಯಾಟರ್ನ್ ಪ್ರಯತ್ನಗಳು"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ನಿಮ್ಮ ಪಿನ್‌ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಟೈಪ್ ಮಾಡಿರುವಿರಿ. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"ನಿಮ್ಮ ಪಾಸ್‍‍ವರ್ಡ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಟೈಪ್ ಮಾಡಿರುವಿರಿ. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"ನಿಮ್ಮ ಅನ್‍‍ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಚಿತ್ರಿಸಿರುವಿರಿ. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ. <xliff:g id="NUMBER_1">%d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲಾಗುತ್ತದೆ, ಇದು ಅದರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"ಫೋನ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ. <xliff:g id="NUMBER_1">%d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಫೋನ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲಾಗುತ್ತದೆ, ಇದು ಅದರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ನಿಮ್ಮ ಪಿನ್‌ ಅನ್ನು ನೀವು <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">"ನಿಮ್ಮ ಅನ್‍‍ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <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">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ. <xliff:g id="NUMBER_1">%d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಬಳಕೆದಾರರನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಈ ಮೂಲಕ ಬಳಕೆದಾರರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"ಫೋನ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ. <xliff:g id="NUMBER_1">%d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಬಳಕೆದಾರರನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಈ ಮೂಲಕ ಬಳಕೆದಾರರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ. <xliff:g id="NUMBER_1">%d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಪ್ರೊಫೈಲ್ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"ಫೋನ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ. <xliff:g id="NUMBER_1">%d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಪ್ರೊಫೈಲ್ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
+    <string name="kg_failed_attempts_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">"ನಿಮ್ಮ ಅನ್‍‍ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಡ್ರಾ ಮಾಡಿರುವಿರಿ. <xliff:g id="NUMBER_1">%d</xliff:g> ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ನಿಮ್ಮ ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿಕೊಂಡು ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್‌ಲಾಕ್ ಮಾಡುವಂತೆ ನಿಮ್ಮಲ್ಲಿ ಕೇಳಿಕೊಳ್ಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ನಿಮ್ಮ ಅನ್‍‍ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಡ್ರಾ ಮಾಡಿರುವಿರಿ. <xliff:g id="NUMBER_1">%d</xliff:g> ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ನಿಮ್ಮ ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿಕೊಂಡು ನಿಮ್ಮ ಫೋನ್ ಅನ್‌ಲಾಕ್ ಮಾಡುವಂತೆ ನಿಮ್ಮಲ್ಲಿ ಕೇಳಿಕೊಳ್ಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ನಿಮ್ಮ ಅನ್‍‍ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಡ್ರಾ ಮಾಡಿರುವಿರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ನಿಮ್ಮ ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿಕೊಂಡು ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್‌ಲಾಕ್ ಮಾಡುವಂತೆ ನಿಮ್ಮಲ್ಲಿ ಕೇಳಿಕೊಳ್ಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ನಿಮ್ಮ ಅನ್‍‍ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಡ್ರಾ ಮಾಡಿರುವಿರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ನಿಮ್ಮ ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿಕೊಂಡು ನಿಮ್ಮ ಫೋನ್ ಅನ್‌ಲಾಕ್ ಮಾಡುವಂತೆ ನಿಮ್ಮಲ್ಲಿ ಕೇಳಿಕೊಳ್ಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"ಸಿಮ್‌ ಪಿನ್‌ ಕೋಡ್ ತಪ್ಪಾಗಿದೆ, ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು ಈ ಕೂಡಲೇ ನಿಮ್ಮ ವಾಹಕವನ್ನು ಸಂಪರ್ಕಿಸಬೇಕು."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">ಸಿಮ್‌ ಪಿನ್ ಕೋಡ್‌ ತಪ್ಪಾಗಿದೆ, ನಿಮ್ಮಲ್ಲಿ <xliff:g id="NUMBER_1">%d</xliff:g> ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ.</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ಯಾವುದೇ ಸೇವೆಯಿಲ್ಲ."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ಇನ್‌ಪುಟ್ ವಿಧಾನ ಬದಲಿಸು ಬಟನ್."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"ಏರ್‌ಪ್ಲೇನ್ ಮೋಡ್"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"ನೀವು ಸಾಧನವನ್ನು ಮರುಪ್ರಾರಂಭಿಸಿದಾಗ ಪ್ಯಾಟರ್ನ್ ಅಗತ್ಯವಿರುತ್ತದೆ."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"ನೀವು ಸಾಧನವನ್ನು ಮರುಪ್ರಾರಂಭಿಸಿದಾಗ ಪಿನ್ ಅಗತ್ಯವಿರುತ್ತದೆ."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"ನೀವು ಸಾಧನವನ್ನು ಮರುಪ್ರಾರಂಭಿಸಿದಾಗ ಪಾಸ್‌ವರ್ಡ್ ಅಗತ್ಯವಿರುತ್ತದೆ."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"ಹೆಚ್ಚುವರಿ ಭದ್ರತೆಗೆ ಪ್ಯಾಟರ್ನ್ ಅಗತ್ಯವಿದೆ."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"ಹೆಚ್ಚುವರಿ ಭದ್ರತೆಗೆ ಪಿನ್ ಅಗತ್ಯವಿದೆ."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"ಹೆಚ್ಚುವರಿ ಭದ್ರತೆಗಾಗಿ ಪಾಸ್‌ವರ್ಡ್ ಅಗತ್ಯವಿದೆ."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"ನೀವು ಪ್ರೊಫೈಲ್ ಬದಲಾಯಿಸಿದಾಗ ಪ್ಯಾಟರ್ನ್ ಅಗತ್ಯವಿರುತ್ತದೆ."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"ನೀವು ಪ್ರೊಫೈಲ್ ಬದಲಾಯಿಸಿದಾಗ ಪಿನ್ ಅಗತ್ಯವಿರುತ್ತದೆ."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"ನೀವು ಪ್ರೊಫೈಲ್ ಬದಲಾಯಿಸಿದಾಗ ಪಾಸ್‌ವರ್ಡ್‌ ಅಗತ್ಯವಿರುತ್ತದೆ."</string>
+    <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"ಸಾಧನ ಮರುಪ್ರಾರಂಭಗೊಂಡ ನಂತರ ಪ್ಯಾಟರ್ನ್ ಅಗತ್ಯವಿರುತ್ತದೆ"</string>
+    <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"ಸಾಧನ ಮರುಪ್ರಾರಂಭಗೊಂಡ ನಂತರ ಪಿನ್ ಅಗತ್ಯವಿರುತ್ತದೆ"</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">"ಹೆಚ್ಚುವರಿ ಭದ್ರತೆಗೆ ಪಿನ್ ಅಗತ್ಯವಿದೆ"</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">"ನೀವು ಪ್ರೊಫೈಲ್‌ಗಳನ್ನು ಬದಲಾಯಿಸಿದಾಗ ಪಿನ್ ಅಗತ್ಯವಿರುತ್ತದೆ"</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="other">ಸಾಧನವನ್ನು <xliff:g id="NUMBER_1">%d</xliff:g> ಗಂಟೆಗಳ ಕಾಲ ಅನ್‌ಲಾಕ್‌ ಮಾಡಲಾಗಿಲ್ಲ. ನಮೂನೆಯನ್ನು ಖಚಿತಪಡಿಸಿ.</item>
diff --git a/packages/Keyguard/res/values-ko/strings.xml b/packages/Keyguard/res/values-ko/strings.xml
index 691f0a4..67d6acb 100644
--- a/packages/Keyguard/res/values-ko/strings.xml
+++ b/packages/Keyguard/res/values-ko/strings.xml
@@ -77,23 +77,23 @@
     <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">%d</xliff:g>회 잘못 입력했습니다. \n\n<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"비밀번호를 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 입력했습니다. \n\n<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. \n\n<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"태블릿 잠금 해제에 <xliff:g id="NUMBER_0">%d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%d</xliff:g>번 더 실패하면 이 태블릿은 재설정되며 모든 데이터가 삭제됩니다."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"휴대전화 잠금 해제에 <xliff:g id="NUMBER_0">%d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%d</xliff:g>번 더 실패하면 이 휴대전화는 재설정되며 모든 데이터가 삭제됩니다."</string>
+    <string name="kg_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">"잠금해제 패턴을 <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">%d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%d</xliff:g>번 더 실패하면 이 사용자는 삭제되며 모든 사용자 데이터가 삭제됩니다."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"휴대전화 잠금 해제에 <xliff:g id="NUMBER_0">%d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%d</xliff:g>번 더 실패하면 이 사용자는 삭제되며 모든 사용자 데이터가 삭제됩니다."</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%d</xliff:g>번 더 실패하면 직장 프로필이 삭제되고 모든 프로필 데이터가 삭제됩니다."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"휴대전화 잠금 해제에 <xliff:g id="NUMBER_0">%d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%d</xliff:g>번 더 실패하면 직장 프로필이 삭제되고 모든 프로필 데이터가 삭제됩니다."</string>
+    <string name="kg_failed_attempts_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">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%d</xliff:g>회 더 실패하면 이메일 계정을 사용하여 태블릿을 잠금해제해야 합니다.\n\n <xliff:g id="NUMBER_2">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%d</xliff:g>회 더 실패하면 이메일 계정을 사용하여 휴대전화를 잠금해제해야 합니다.\n\n <xliff:g id="NUMBER_2">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%1$d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>회 더 실패하면 이메일 계정을 사용하여 태블릿을 잠금해제해야 합니다.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g>초 후에 다시 시도해 주세요."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%1$d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>회 더 실패하면 이메일 계정을 사용하여 휴대전화를 잠금해제해야 합니다.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g>초 후에 다시 시도해 주세요."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM PIN 코드가 잘못되었습니다. 이동통신사에 문의하여 기기를 잠금 해제해야 합니다."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">SIM PIN 코드가 잘못되었습니다. <xliff:g id="NUMBER_1">%d</xliff:g>번 더 시도할 수 있습니다.</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"서비스 불가"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"입력 방법 버튼을 전환합니다."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"비행기 모드"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"기기를 다시 시작하려면 패턴이 필요합니다."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"기기를 다시 시작하려면 PIN이 필요합니다."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"기기를 다시 시작하려면 비밀번호가 필요합니다."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"보안 강화를 위해 패턴이 필요합니다."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"보안 강화를 위해 PIN이 필요합니다."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"보안 강화를 위해 비밀번호가 필요합니다."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"프로필을 전환하려면 패턴이 필요합니다."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"프로필을 전환하려면 PIN이 필요합니다."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"프로필을 전환하려면 비밀번호가 필요합니다."</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="other"><xliff:g id="NUMBER_1">%d</xliff:g>시간 이상 기기가 잠금 해제되지 않았습니다. 패턴을 확인하세요.</item>
       <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g>시간 이상 기기가 잠금 해제되지 않았습니다. 패턴을 확인하세요.</item>
diff --git a/packages/Keyguard/res/values-ky-rKG/strings.xml b/packages/Keyguard/res/values-ky-rKG/strings.xml
index fb5fbae..5403c71 100644
--- a/packages/Keyguard/res/values-ky-rKG/strings.xml
+++ b/packages/Keyguard/res/values-ky-rKG/strings.xml
@@ -77,23 +77,23 @@
     <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">%d</xliff:g> жолу туура эмес тердиңиз. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> секундадан кийин кайталаңыз."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Сиз сырсөзүңүздү <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес тердиңиз. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> секундадан кийин кайталаңыз."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Сиз бөгөттөн чыгаруу үлгүсүн <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес көрсөттүңүз. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> секундадан кийин кайталаңыз."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Планшеттин кулпусун ачууда <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Дагы <xliff:g id="NUMBER_1">%d</xliff:g> жолу туура эмес аракет кылсаңыз, бул планшет баштапкы абалга келтирилип, андагы бардык дайындар жок болот."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Телефондун кулпусун ачууда <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Дагы <xliff:g id="NUMBER_1">%d</xliff:g> жолу туура эмес аракет кылсаңыз, бул телефон баштапкы абалга келтирилип, андагы бардык дайындар жок болот."</string>
+    <string name="kg_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">"Сиз бөгөттөн чыгаруу үлгүсүн <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">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Дагы <xliff:g id="NUMBER_1">%d</xliff:g> жолу туура эмес аракет кылсаңыз, бул колдонуучу чыгарылып салынып, колдонуучунун бардык дайындары жок болот."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Телефондун кулпусун ачууда <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Дагы <xliff:g id="NUMBER_1">%d</xliff:g> жолу туура эмес аракет кылсаңыз, бул колдонуучу чыгарылып салынып, колдонуучунун бардык дайындары жок болот."</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Дагы <xliff:g id="NUMBER_1">%d</xliff:g> жолу туура эмес аракет кылсаңыз, жумуш профилиңиз чыгарылып салынып, профилдин бардык дайындары жок болот."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Телефондун кулпусун ачууда <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Дагы <xliff:g id="NUMBER_1">%d</xliff:g> жолу туура эмес аракет кылсаңыз, жумуш профилиңиз чыгарылып салынып, профилдин бардык дайындары жок болот."</string>
+    <string name="kg_failed_attempts_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">"Сиз бөгөттөн чыгаруу үлгүсүн <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес көрсөттүңүз. Дагы <xliff:g id="NUMBER_1">%d</xliff:g> ийгиликсиз аракеттен кийин, планшетиңизди эмейл эсебиңиз аркылуу бөгөттөн чыгаруу талап кылынат.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> секундадан кийин кайра аракеттениңиз."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Сиз бөгөттөн чыгаруу үлгүсүн <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес көрсөттүңүз. Дагы <xliff:g id="NUMBER_1">%d</xliff:g> ийгиликсиз аракеттен кийин, телефонуңузду эмейл эсебиңиз аркылуу бөгөттөн чыгаруу талап кылынат.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> секундадан кийин кайра аракеттениңиз."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Сиз бөгөттөн чыгаруу үлгүсүн <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес көрсөттүңүз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин, планшетиңизди эмейл эсебиңиз аркылуу бөгөттөн чыгаруу талап кылынат.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундадан кийин кайра аракеттениңиз."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Сиз бөгөттөн чыгаруу үлгүсүн <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес көрсөттүңүз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин, телефонуңузду эмейл эсебиңиз аркылуу бөгөттөн чыгаруу талап кылынат.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундадан кийин кайра аракеттениңиз."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM-карта PIN-коду туура эмес. Эми түзмөктү бөгөттөн чыгарыш үчүн операторуңузга кайрылышыңыз керек."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">SIM PIN-коду туура эмес, сизде <xliff:g id="NUMBER_1">%d</xliff:g> аракет калды.</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Байланыш жок."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Киргизүү ыкмасын которуу баскычы."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Учак режими"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Түзмөктү өчүрүп-күйгүзгөнүңүздө сүрөт үлгүсү керектелет."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Түзмөктү өчүрүп-күйгүзгөнүңүздө PIN керектелет."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Түзмөктү өчүрүп-күйгүзгөнүңүздө сырсөз керектелет."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Кошумча коопсуздук үчүн сүрөт үлгүсү керек."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Кошумча коопсуздук үчүн PIN код керек."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Кошумча коопсуздук үчүн сырсөз керек."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Профилдерди которгонуңузда сүрөт үлгүсү керектелет."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Профилдерди которгонуңузда PIN керектелет."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Профилдерди которгонуңузда сырсөз керектелет."</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="other">Түзмөктүн кулпусу <xliff:g id="NUMBER_1">%d</xliff:g> саат бою ачылган жок. Cүрөт үлгүсүн ырастаңыз.</item>
       <item quantity="one">Түзмөктүн кулпусу <xliff:g id="NUMBER_0">%d</xliff:g> саат бою ачылган жок. Cүрөт үлгүсүн ырастаңыз.</item>
diff --git a/packages/Keyguard/res/values-lo-rLA/strings.xml b/packages/Keyguard/res/values-lo-rLA/strings.xml
index b9b68692..e99b22d 100644
--- a/packages/Keyguard/res/values-lo-rLA/strings.xml
+++ b/packages/Keyguard/res/values-lo-rLA/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"ປ້ອນລະຫັດ PUK ທີ່ຖືກຕ້ອງຄືນໃໝ່. ການພະຍາຍາມໃສ່ຫຼາຍເທື່ອຈະເຮັດໃຫ້ຊິມກາດໃຊ້ບໍ່ໄດ້ຖາວອນ."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ລະຫັດ PIN ບໍ່ກົງກັນ"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ແຕ້ມຮູບແບບປົດລັອກຫຼາຍເກີນໄປ"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ທ່ານພິມລະຫັດ PIN​ ຂອງທ່ານຜິດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. \n\nກະລຸນາລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ວິນາທີ."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"ທ່ານພິມລະຫັດຜິດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. \n\nລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ວິນາທີ."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຂອງທ່ານຜິດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. \n\nກະລຸນາລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ວິນາທີ."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"ທ່ານ​ພະ​ຍາ​ຍາມ​ປົດ​ລ​ັອກ​ແທັບ​ເລັດ​ບໍ່​ຖືກ​ຕ້ອງ <xliff:g id="NUMBER_0">%d</xliff:g> ຄັ້ງ. ຫຼັງ​ຈາກ​ລອງ​ບໍ່​ສຳ​ເລັດ​ອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ຄັ້ງ, ແທັບ​ເລັດ​ນີ້​ຈະ​ຖືກ​ຕັ້ງ​ຄ່າ​ໃໝ່, ເຊິ່ງ​ຈະ​ລຶບ​ທຸກ​ຂໍ້​ມູນ​ຂອງ​ມັນ."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"ທ່ານ​ພະ​ຍາ​ຍາມ​ປົດ​ລ​ັອກ​ໂທ​ລະ​ສັບ​ບໍ່​ຖືກ​ຕ້ອງ <xliff:g id="NUMBER_0">%d</xliff:g> ຄັ້ງ. ຫຼັງ​ຈາກ​ລອງ​ບໍ່​ສຳ​ເລັດ​ອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ຄັ້ງ, ໂທ​ລະ​ສັບ​ນີ້​ຈະ​ຖືກ​ຕັ້ງ​ຄ່າ​ໃໝ່, ເຊິ່ງ​ຈະ​ລຶບ​ທຸກ​ຂໍ້​ມູນຂອງ​ມັນ."</string>
+    <string name="kg_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">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຂອງທ່ານຜິດ <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">%d</xliff:g> ຄັ້ງ. ຫຼັງ​ຈາກ​ລອງ​ບໍ່​ສຳ​ເລັດ​ອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ຄັ້ງ, ຜູ້​ໃຊ້​ນີ້​ຈະ​ຖືກ​ເອົາ​ອອກ​ໄປ, ເຊິ່ງ​ຈະ​ລຶບ​ທຸກ​ຂໍ້​ມູນຜູ້​ໃຊ້."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"ທ່ານ​ພະ​ຍາ​ຍາມ​ປົດ​ລ​ັອກ​ໂທ​ລະ​ສັບ​ບໍ່​ຖືກ​ຕ້ອງ <xliff:g id="NUMBER_0">%d</xliff:g> ຄັ້ງ. ຫຼັງ​ຈາກ​ລອງ​ບໍ່​ສຳ​ເລັດ​ອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ຄັ້ງ, ຜູ້​ໃຊ້​ນີ້ຈະ​ຖືກ​ເອົາ​ອອກ​ໄປ, ເຊິ່ງ​ຈະ​ລຶບ​ທຸກ​ຂໍ້​ມູນຜູ້​ໃຊ້."</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> ຄັ້ງ. ຫຼັງ​ຈາກ​ລອງ​ບໍ່​ສຳ​ເລັດ​ອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ຄັ້ງ, ໂປ​ຣ​ໄຟ​ລ໌​ບ່ອນ​ເຮັດ​ວຽກ​ຈະ​ຖືກ​ເອົາ​ອອກ​ໄປ, ເຊິ່ງ​ຈະ​ລຶບ​ທຸກ​ຂໍ້​ມູນ​ໂປ​ຣ​ໄຟ​ລ໌."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"ທ່ານ​ພະ​ຍາ​ຍາມ​ປົດ​ລ​ັອກ​ໂທ​ລະ​ສັບ​ບໍ່​ຖືກ​ຕ້ອງ <xliff:g id="NUMBER_0">%d</xliff:g> ຄັ້ງ. ຫຼັງ​ຈາກ​ລອງ​ບໍ່​ສຳ​ເລັດ​ອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ຄັ້ງ, ໂປ​ຣ​ໄຟ​ລ໌​ບ່ອນ​ເຮັດ​ວຽກ​ຈະ​ຖືກ​ເອົາ​ອອກ​ໄປ, ເຊິ່ງ​ຈະ​ລຶບ​ທຸກ​ຂໍ້​ມູນ​ໂປ​ຣ​ໄຟ​ລ໌."</string>
+    <string name="kg_failed_attempts_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">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຜິດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກແຕ້ມຜິດອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ເທື່ອ, ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກແທັບເລັດຂອງທ່ານ ດ້ວຍການເຂົ້າສູ່ລະບົບໂດຍໃຊ້ອີເມວຂອງທ່ານ.\n\n ກະລຸນາລອງໃໝ່ອີກຄັ້ງໃນອີກ <xliff:g id="NUMBER_2">%d</xliff:g> ວິນາທີ."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຂອງທ່ານຜິດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກຄວາມພະຍາຍາມອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ເທື່ອ ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກໂທລະສັບຂອງທ່ານດ້ວຍບັນຊີອີເມວ.\n\n ລອງໃໝ່ອີກຄັ້ງໃນ <xliff:g id="NUMBER_2">%d</xliff:g> ວິນາທີ."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຜິດ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກແຕ້ມຜິດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ເທື່ອ, ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກແທັບເລັດຂອງທ່ານ ດ້ວຍການເຂົ້າສູ່ລະບົບໂດຍໃຊ້ອີເມວຂອງທ່ານ.\n\n ກະລຸນາລອງໃໝ່ອີກຄັ້ງໃນອີກ <xliff:g id="NUMBER_2">%3$d</xliff:g> ວິນາທີ."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຂອງທ່ານຜິດ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກຄວາມພະຍາຍາມອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ເທື່ອ ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກໂທລະສັບຂອງທ່ານດ້ວຍບັນຊີອີເມວ.\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="other">ລະຫັດ SIM PIN ບໍ່ຖືກຕ້ອງ, ທ່ານຍັງພະຍາຍາມໄດ້ອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ຄັ້ງ.</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ບໍ່ມີບໍລິການ"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ປຸ່ມສະລັບຮູບແບບການປ້ອນຂໍ້ມູນ."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"ໂໝດໃນຍົນ"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"ຈຳເປັນຕ້ອງມີແບບຮູບ ເມື່ອທ່ານເລີ່ມລະບົບອຸປະກອນໃໝ່."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"ຈຳເປັນຕ້ອງມີ PIN ເມື່ອທ່ານເລີ່ມລະບົບອຸປະກອນໃໝ່."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"ຈຳເປັນຕ້ອງມີລະຫັດຜ່ານ ເມື່ອທ່ານເລີ່ມລະບົບອຸປະກອນໃໝ່."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"ຈຳ​ເປັນ​ຕ້ອງ​ມີ​ຮູບ​ແບບ​ສຳ​ລັບ​ຄວາມ​ປອດ​ໄພ​ເພີ່ມ​ເຕີມ."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"ຈຳ​ເປັນ​ຕ້ອງ​ມີ PIN ​ສຳ​ລັບ​ຄວາມ​ປອດ​ໄພ​ເພີ່ມ​ເຕີມ."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"ຈຳ​ເປັນ​ຕ້ອງ​ມີ​ລະ​ຫັດ​ຜ່ານ​ສຳ​ລັບ​ຄວາມ​ປອດ​ໄພ​ເພີ່ມ​ເຕີມ."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"ຈຳເປັນຕ້ອງມີແບບຮູບ ເມື່ອທ່ານປ່ຽນໂປຣໄຟລ໌."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"ຈຳເປັນຕ້ອງມີ PIN ເມື່ອທ່ານປ່ຽນໂປຣໄຟລ໌."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"ຈຳເປັນຕ້ອງມີລະຫັດຜ່ານ ເມື່ອທ່ານປ່ຽນໂປຣໄຟລ໌."</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="other">ອຸປະກອນບໍ່ໄດ້ຖືກປົດລັອກເປັນເວລາ <xliff:g id="NUMBER_1">%d</xliff:g> ຊົ່ວໂມງ. ຢືນ​ຢັນ​​ແບບຮູບ​.</item>
       <item quantity="one">ອຸປະກອນບໍ່ໄດ້ຖືກປົດລັອກເປັນເວລາ <xliff:g id="NUMBER_0">%d</xliff:g> ຊົ່ວໂມງ. ຢືນຢັນແບບຮູບ.</item>
diff --git a/packages/Keyguard/res/values-lt/strings.xml b/packages/Keyguard/res/values-lt/strings.xml
index d2bed32..fd83ece 100644
--- a/packages/Keyguard/res/values-lt/strings.xml
+++ b/packages/Keyguard/res/values-lt/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Pakartotinai įveskite tinkamą PUK kodą. Pakartotinai bandant SIM bus neleidžiama visam laikui."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodai neatitinka"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Per daug atrakinimo piešinių bandymų"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodą netinkamai įvedėte <xliff:g id="NUMBER_0">%d</xliff:g> k. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Neteisingai įvedėte slaptažodį <xliff:g id="NUMBER_0">%d</xliff:g> k. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"<xliff:g id="NUMBER_0">%d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkming. bandym. šis planšetinis kompiuteris bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"<xliff:g id="NUMBER_0">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkming. bandym. šis telefonas bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodą netinkamai įvedėte <xliff:g id="NUMBER_0">%1$d</xliff:g> k. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%2$d</xliff:g> sek."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Neteisingai įvedėte slaptažodį <xliff:g id="NUMBER_0">%1$d</xliff:g> k. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%2$d</xliff:g> sek."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%1$d</xliff:g> k. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%2$d</xliff:g> sek."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkming. bandym. šis planšetinis kompiuteris bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkming. bandym. šis telefonas bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Planšetinis kompiuteris bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Telefonas bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"<xliff:g id="NUMBER_0">%d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkming. bandym. šis naudotojas bus pašalintas ir visi naudotojo duomenys bus ištrinti."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"<xliff:g id="NUMBER_0">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkming. bandym. šis naudotojas bus pašalintas ir visi naudotojo duomenys bus ištrinti."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkming. bandym. šis naudotojas bus pašalintas ir visi naudotojo duomenys bus ištrinti."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkming. bandym. šis naudotojas bus pašalintas ir visi naudotojo duomenys bus ištrinti."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Naudotojas bus pašalintas ir visi naudotojo duomenys bus ištrinti."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Naudotojas bus pašalintas ir visi naudotojo duomenys bus ištrinti."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"<xliff:g id="NUMBER_0">%d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkming. bandym. darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"<xliff:g id="NUMBER_0">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkming. bandym. darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkming. bandym. darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkming. bandym. darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti planšetinį kompiuterį naudodami „Google“ prisijungimo duomenis.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami „Google“ prisijungimo duomenis.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%1$d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. būsite paprašyti atrakinti planšetinį kompiuterį naudodami „Google“ prisijungimo duomenis.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%1$d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami „Google“ prisijungimo duomenis.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Netinkamas SIM kortelės PIN kodas. Reikės susisiekti su operatoriumi, kad atrakintų įrenginį."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">Netinkamas SIM kortelės PIN kodas. Liko <xliff:g id="NUMBER_1">%d</xliff:g> bandymas.</item>
@@ -114,15 +114,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Lėktuvo režimas"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Iš naujo paleidus įrenginį reikalingas atrakinimo piešinys."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Iš naujo paleidus įrenginį reikalingas PIN kodas."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Iš naujo paleidus įrenginį reikalingas slaptažodis."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Norint užtikrinti papildomą saugumą būtinas atrakinimo piešinys."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Norint užtikrinti papildomą saugumą būtinas PIN kodas."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Norint užtikrinti papildomą saugumą būtinas slaptažodis."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Perjungiant profilius reikalingas atrakinimo piešinys."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Perjungiant profilius reikalingas PIN kodas."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Perjungiant profilius reikalingas slaptažodis."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Iš naujo paleidus įrenginį būtinas slaptažodis"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Norint užtikrinti papildomą saugumą būtinas atrakinimo piešinys"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Norint užtikrinti papildomą saugumą būtinas PIN kodas"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Norint užtikrinti papildomą saugumą būtinas slaptažodis"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Perjungiant profilius būtinas atrakinimo piešinys"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Perjungiant profilius būtinas PIN kodas"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Perjungiant profilius būtinas slaptažodis"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="one">Įrenginys nebuvo atrakintas <xliff:g id="NUMBER_1">%d</xliff:g> valandą. Patvirtinkite atrakinimo piešinį.</item>
       <item quantity="few">Įrenginys nebuvo atrakintas <xliff:g id="NUMBER_1">%d</xliff:g> valandas. Patvirtinkite atrakinimo piešinį.</item>
diff --git a/packages/Keyguard/res/values-lv/strings.xml b/packages/Keyguard/res/values-lv/strings.xml
index 20bfc06..5a35912 100644
--- a/packages/Keyguard/res/values-lv/strings.xml
+++ b/packages/Keyguard/res/values-lv/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Atkārtoti ievadiet pareizo PUK kodu. Ja vairākas reizes ievadīsiet to nepareizi, SIM karte tiks neatgriezeniski atspējota."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodi neatbilst."</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Pārāk daudz kombinācijas mēģinājumu"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Jūs nepareizi ievadījāt PIN <xliff:g id="NUMBER_0">%d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Jūs nepareizi ievadījāt paroli <xliff:g id="NUMBER_0">%d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Jūs <xliff:g id="NUMBER_0">%d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt planšetdatoru. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> nesekmīgiem mēģinājumiem šis planšetdators tiks atiestatīts, kā arī visi planšetdatora dati tiks dzēsti."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Jūs <xliff:g id="NUMBER_0">%d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt tālruni. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> nesekmīgiem mēģinājumiem šis tālrunis tiks atiestatīts, kā arī visi tālruņa dati tiks dzēsti."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Jūs nepareizi ievadījāt PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%2$d</xliff:g> sekundēm."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Jūs nepareizi ievadījāt paroli <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%2$d</xliff:g> sekundēm."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%2$d</xliff:g> sekundēm."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt planšetdatoru. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīgiem mēģinājumiem šis planšetdators tiks atiestatīts, kā arī visi planšetdatora dati tiks dzēsti."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt tālruni. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīgiem mēģinājumiem šis tālrunis tiks atiestatīts, kā arī visi tālruņa dati tiks dzēsti."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt planšetdatoru. Šis planšetdators tiks atiestatīts, kā arī visi planšetdatora dati tiks dzēsti."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt tālruni. Šis tālrunis tiks atiestatīts, kā arī visi tālruņa dati tiks dzēsti."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Jūs <xliff:g id="NUMBER_0">%d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt planšetdatoru. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> nesekmīgiem mēģinājumiem šis lietotājs tiks noņemts, kā arī visi lietotāja dati tiks dzēsti."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Jūs <xliff:g id="NUMBER_0">%d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt tālruni. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> nesekmīgiem mēģinājumiem šis lietotājs tiks noņemts, kā arī visi lietotāja dati tiks dzēsti."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt planšetdatoru. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīgiem mēģinājumiem šis lietotājs tiks noņemts, kā arī visi lietotāja dati tiks dzēsti."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt tālruni. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīgiem mēģinājumiem šis lietotājs tiks noņemts, kā arī visi lietotāja dati tiks dzēsti."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt planšetdatoru. Šis lietotājs tiks noņemts, kā arī visi lietotāja dati tiks dzēsti."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt tālruni. Šis lietotājs tiks noņemts, kā arī visi lietotāja dati tiks dzēsti."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Jūs <xliff:g id="NUMBER_0">%d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt planšetdatoru. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> nesekmīgiem mēģinājumiem darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Jūs <xliff:g id="NUMBER_0">%d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt tālruni. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> nesekmīgiem mēģinājumiem darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt planšetdatoru. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīgiem mēģinājumiem darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt tālruni. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīgiem mēģinājumiem darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt planšetdatoru. Darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt tālruni. Darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem planšetdators būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem tālrunis būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> neveiksmīgiem mēģinājumiem planšetdators būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundēm."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> neveiksmīgiem mēģinājumiem tālrunis būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundēm."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Nepareizs SIM kartes PIN kods. Lai atbloķētu ierīci, sazinieties ar mobilo sakaru operatoru."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="zero">Nepareizs SIM kartes PIN kods. Varat mēģināt vēl <xliff:g id="NUMBER_1">%d</xliff:g> reizes.</item>
@@ -112,15 +112,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Lidojuma režīms"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Restartējot ierīci, ir jāievada kombinācija."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Restartējot ierīci, ir jāievada PIN."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Restartējot ierīci, ir jāievada parole."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Papildu drošībai nepieciešama atbloķēšanas kombinācija."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Papildu drošībai nepieciešams PIN kods."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Papildu drošībai nepieciešama parole."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Mainot profilu, ir jāievada kombinācija."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Mainot profilu, ir jāievada PIN."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Mainot profilu, ir jāievada parole."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Pēc ierīces restartēšanas ir jāievada parole."</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Papildu drošībai ir nepieciešama atbloķēšanas kombinācija."</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Papildu drošībai ir nepieciešams PIN kods."</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Papildu drošībai ir nepieciešama parole."</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Pārslēdzot profilus, ir jāievada atbloķēšanas kombinācija."</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Pārslēdzot profilus, ir jāievada PIN kods."</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Pārslēdzot profilus, ir jāievada parole."</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="zero">Ierīce nav tikusi atbloķēta <xliff:g id="NUMBER_1">%d</xliff:g> stundas. Apstipriniet kombināciju.</item>
       <item quantity="one">Ierīce nav tikusi atbloķēta <xliff:g id="NUMBER_1">%d</xliff:g> stundu. Apstipriniet kombināciju.</item>
diff --git a/packages/Keyguard/res/values-mk-rMK/strings.xml b/packages/Keyguard/res/values-mk-rMK/strings.xml
index a06d4e4..a1e224d 100644
--- a/packages/Keyguard/res/values-mk-rMK/strings.xml
+++ b/packages/Keyguard/res/values-mk-rMK/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Повторно внесете го точниот ПУК код. Повторните обиди трајно ќе ја оневозможат СИМ картичката."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ПИН кодовите не се совпаѓаат"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Премногу обиди со шема"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Погрешно сте го впишале вашиот ПИН <xliff:g id="NUMBER_0">%d</xliff:g> пати. \n\nОбидете се повторно за <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Погрешно сте ја впишале вашата лозинка <xliff:g id="NUMBER_0">%d</xliff:g> пати. \n\nОбидете се повторно за <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Погрешно сте ја употребиле вашата шема за отклучување <xliff:g id="NUMBER_0">%d</xliff:g> пати. \n\nОбидете се повторно за <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER_0">%d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%d</xliff:g> неправилни обиди, таблетот ќе се ресетира, со што ќе се избришат сите негови податоци."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER_0">%d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%d</xliff:g> неправилни обиди, телефонот ќе се ресетира, со што ќе се избришат сите негови податоци."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Погрешно сте го впишале вашиот ПИН <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">"Погрешно сте ја употребиле вашата шема за отклучување <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">%d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%d</xliff:g> неправилни обиди, корисникот ќе се отстрани, со што ќе се избришат сите податоци на корисникот."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER_0">%d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%d</xliff:g> неправилни обиди, корисникот ќе се отстрани, со што ќе се избришат сите податоци на корисникот."</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%d</xliff:g> неправилни обиди, работниот профил ќе се отстрани, со што ќе се избришат сите податоци на профилот."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER_0">%d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%d</xliff:g> неправилни обиди, работниот профил ќе се отстрани, со што ќе се избришат сите податоци на профилот."</string>
+    <string name="kg_failed_attempts_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">"Погрешно сте ја употребиле вашата шема на отклучување <xliff:g id="NUMBER_0">%d</xliff:g> пати. По <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни обиди, ќе побараат од вас да го отклучите таблетот со користење сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%d</xliff:g> секунди."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Погрешно сте ја употребиле вашата шема на отклучување <xliff:g id="NUMBER_0">%d</xliff:g> пати. По <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни обиди, ќе побараат од вас да го отклучите телефонот со користење сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%d</xliff:g> секунди."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Погрешно сте ја употребиле вашата шема на отклучување <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, ќе побараат од вас да го отклучите таблетот со користење сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Погрешно сте ја употребиле вашата шема на отклучување <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, ќе побараат од вас да го отклучите телефонот со користење сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"ПИН кодот за СИМ картичката е неточен. Контактирате со вашиот оператор да го отклучи уредот."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">Погрешен ПИН-код за СИМ, ви преостанува уште <xliff:g id="NUMBER_1">%d</xliff:g> обид.</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Нема услуга."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Копче за префрање метод на внес."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Режим на работа во авион"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Потребна е шема кога го престартувате уредот."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Потребен е ПИН кога го престартувате уредот."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Потребна е лозинка кога го престартувате уредот."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Потребна е шема за дополнителна безбедност."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Потребен е ПИН за дополнителна безбедност."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Потребна е лозинка за дополнителна безбедност."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Потребна е шема кога променувате профили."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Потребен е ПИН кога променувате профили."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Потребна е лозинка кога променувате профили."</string>
+    <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Потребна е шема по рестартирање на уредот"</string>
+    <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Потребен е ПИН-код по рестартирање на уредот"</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">"Потребен е ПИН-код за дополнителна безбедност"</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">"Потребен е ПИН-код кога променувате профили"</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="other">Уредот не е отклучен за <xliff:g id="NUMBER_1">%d</xliff:g> часа. Потврдете ја шемата.</item>
diff --git a/packages/Keyguard/res/values-ml-rIN/strings.xml b/packages/Keyguard/res/values-ml-rIN/strings.xml
index a7d78f5..3a898d8 100644
--- a/packages/Keyguard/res/values-ml-rIN/strings.xml
+++ b/packages/Keyguard/res/values-ml-rIN/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"ശരിയായ PUK കോഡ് വീണ്ടും നൽകുക. ആവർത്തിച്ചുള്ള ശ്രമങ്ങൾ സിം ശാശ്വതമായി പ്രവർത്തനരഹിതമാക്കും."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"പിൻ കോഡുകൾ പൊരുത്തപ്പെടുന്നില്ല"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"വളരെയധികം പാറ്റേൺ ശ്രമങ്ങൾ"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"നിങ്ങളുടെ പിൻ <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി ടൈപ്പുചെയ്‌തു. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"നിങ്ങളുടെ പാസ്‌വേഡ് <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി ടൈപ്പുചെയ്‌തു. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"നിങ്ങളുടെ പാറ്റേൺ <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി വരച്ചു. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"നിങ്ങളുടെ ടാബ്‌ലെറ്റ് <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%d</xliff:g>-ൽ കൂടുതൽ പരാജയപ്പെട്ട ശ്രമങ്ങൾക്കുശേഷം, ഈ ടാബ്‌ലെറ്റ് പുനഃസജ്ജീകരിക്കുന്നതിനാൽ ഇതിന്റെ എല്ലാ വിവരങ്ങളും ഇല്ലാതാക്കും."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"നിങ്ങളുടെ ഫോൺ <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%d</xliff:g>-ൽ കൂടുതൽ പരാജയപ്പെട്ട ശ്രമങ്ങൾക്കുശേഷം, ഈ ഫോൺ പുനഃസജ്ജീകരിക്കുന്നതിനാൽ ഇതിന്റെ എല്ലാ വിവരങ്ങളും ഇല്ലാതാക്കും."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"നിങ്ങളുടെ പിൻ <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">"നിങ്ങളുടെ പാറ്റേൺ <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">%d</xliff:g> തവണ തെറ്റായി അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%d</xliff:g>-ൽ കൂടുതൽ പരാജയപ്പെട്ട ശ്രമങ്ങൾക്കുശേഷം, ഈ ഉപയോക്താവിനെ നീക്കംചെയ്യും, ഈ ഉപയോക്താവിനെ നീക്കംചെയ്യുന്നതിനാൽ എല്ലാ ഉപയോക്തൃ വിവരങ്ങളും ഇല്ലാതാക്കും."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"നിങ്ങളുടെ ഫോൺ <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%d</xliff:g>-ൽ കൂടുതൽ പരാജയപ്പെട്ട ശ്രമങ്ങൾക്കുശേഷം, ഈ ഉപയോക്താവിനെ നീക്കംചെയ്യുന്നതിനാൽ എല്ലാ ഉപയോക്തൃ വിവരങ്ങളും ഇല്ലാതാക്കും."</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> തവണ തെറ്റായി അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%d</xliff:g>-ൽ കൂടുതൽ പരാജയപ്പെട്ട ശ്രമങ്ങൾക്കുശേഷം, ഔദ്യോഗിക പ്രൊഫൈൽ നീക്കംചെയ്യുന്നതിനാൽ എല്ലാ പ്രൊഫൈൽ വിവരങ്ങളും ഇല്ലാതാക്കും."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"നിങ്ങളുടെ ഫോൺ <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%d</xliff:g>-ൽ കൂടുതൽ പരാജയപ്പെട്ട ശ്രമങ്ങൾക്കുശേഷം, ഔദ്യോഗിക പ്രൊഫൈൽ നീക്കംചെയ്യുന്നതിനാൽ എല്ലാ പ്രൊഫൈൽ വിവരങ്ങളും ഇല്ലാതാക്കും."</string>
+    <string name="kg_failed_attempts_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">"നിങ്ങളുടെ അൺലോക്ക് പാറ്റേൺ <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി വരച്ചു. <xliff:g id="NUMBER_1">%d</xliff:g> ശ്രമങ്ങൾ കൂടി വിജയിച്ചില്ലെങ്കിൽ, ഒരു ഇമെയിൽ അക്കൗണ്ട് ഉപയോഗിച്ച് ടാബ്‌ലെറ്റ് അൺലോക്ക് ചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> സെക്കൻഡിനുള്ള വീണ്ടും ശ്രമിക്കുക."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"നിങ്ങളുടെ അൺലോക്ക് പാറ്റേൺ <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി വരച്ചു. <xliff:g id="NUMBER_1">%d</xliff:g> ശ്രമങ്ങൾ കൂടി വിജയിച്ചില്ലെങ്കിൽ, ഒരു ഇമെയിൽ അക്കൗണ്ട് ഉപയോഗിച്ച് ഫോൺ അൺലോക്ക് ചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> സെക്കൻഡിനുള്ള വീണ്ടും ശ്രമിക്കുക."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"നിങ്ങളുടെ അൺലോക്ക് പാറ്റേൺ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി വരച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി വിജയിച്ചില്ലെങ്കിൽ, ഒരു ഇമെയിൽ അക്കൗണ്ട് ഉപയോഗിച്ച് ടാബ്‌ലെറ്റ് അൺലോക്ക് ചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> സെക്കൻഡിനുള്ള വീണ്ടും ശ്രമിക്കുക."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"നിങ്ങളുടെ അൺലോക്ക് പാറ്റേൺ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി വരച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി വിജയിച്ചില്ലെങ്കിൽ, ഒരു ഇമെയിൽ അക്കൗണ്ട് ഉപയോഗിച്ച് ഫോൺ അൺലോക്ക് ചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> സെക്കൻഡിനുള്ള വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"സിം പിൻ കോഡ് തെറ്റാണ്, നിങ്ങളുടെ ഉപകരണം അൺലോക്കുചെയ്യാൻ ഇപ്പോൾ നിങ്ങളുടെ കാരിയറുമായി ബന്ധപ്പെടണം."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">SIM PIN കോഡ് തെറ്റാണ്, നിങ്ങൾക്ക് <xliff:g id="NUMBER_1">%d</xliff:g> ശ്രമങ്ങൾ കൂടി ശേഷിക്കുന്നു.</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"സേവനമൊന്നുമില്ല."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ടൈപ്പുചെയ്യൽ രീതി ബട്ടൺ മാറുക."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"ഫ്ലൈറ്റ് മോഡ്"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"ഉപകരണം പുനഃരാരംഭിക്കുമ്പോൾ പാറ്റേൺ ആവശ്യമാണ്."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"ഉപകരണം പുനഃരാരംഭിക്കുമ്പോൾ PIN ആവശ്യമാണ്."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"ഉപകരണം പുനഃരാരംഭിക്കുമ്പോൾ പാസ്‌വേഡ് ആവശ്യമാണ്."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"അധിക സുരക്ഷയ്ക്ക് പാറ്റേൺ ആവശ്യമാണ്."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"അധിക സുരക്ഷയ്ക്ക് PIN ആവശ്യമാണ്."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"അധിക സുരക്ഷയ്ക്ക് പാസ്‌വേഡ് ആവശ്യമാണ്."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"പ്രൊഫൈലുകൾ തമ്മിൽ മാറുമ്പോൾ പാറ്റേൺ ആവശ്യമാണ്."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"പ്രൊഫൈലുകൾ തമ്മിൽ മാറുമ്പോൾ PIN ആവശ്യമാണ്."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"പ്രൊഫൈലുകൾ തമ്മിൽ മാറുമ്പോൾ പാസ്‌വേഡ് ആവശ്യമാണ്."</string>
+    <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"ഉപകരണം പുനരാരംഭിച്ചതിന് ശേഷം പാറ്റേൺ ആവശ്യമാണ്"</string>
+    <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"ഉപകരണം പുനരാരംഭിച്ചതിന് ശേഷം പിൻ ആവശ്യമാണ്"</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">"അധിക സുരക്ഷയ്ക്ക് പിൻ ആവശ്യമാണ്"</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">"പ്രൊഫൈലുകൾ തമ്മിൽ മാറുമ്പോൾ പിൻ ആവശ്യമാണ്"</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="other">ഉപകരണം <xliff:g id="NUMBER_1">%d</xliff:g> മണിക്കൂറായി അൺലോക്ക് ചെയ്തിട്ടില്ല. പാറ്റേൺ സ്ഥിരീകരിക്കുക.</item>
       <item quantity="one">ഉപകരണം <xliff:g id="NUMBER_0">%d</xliff:g> മണിക്കൂറായി അൺലോക്ക് ചെയ്തിട്ടില്ല. പാറ്റേൺ സ്ഥിരീകരിക്കുക.</item>
diff --git a/packages/Keyguard/res/values-mn-rMN/strings.xml b/packages/Keyguard/res/values-mn-rMN/strings.xml
index 495076a..410ec4b 100644
--- a/packages/Keyguard/res/values-mn-rMN/strings.xml
+++ b/packages/Keyguard/res/values-mn-rMN/strings.xml
@@ -77,23 +77,23 @@
     <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">%d</xliff:g> удаа буруу бичив. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> секундын дараа дахин оролдоно уу."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Та PIN кодоо <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу бичив. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> секундын дараа дахин оролдоно уу."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Та тайлах хээг <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу зурлаа. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> секундын дараа дахин оролдоно уу."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Та таблетын түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу оруулсан байна. <xliff:g id="NUMBER_1">%d</xliff:g>-с илүү удаа буруу хийвэл энэ таблетын тохиргоо дахин шинээр хийгдэх бөгөөд улмаар таблетын дээрх бүх мэдээлэл устах болно."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу оруулсан байна. <xliff:g id="NUMBER_1">%d</xliff:g>-с илүү удаа буруу хийвэл энэ утасны тохиргоо дахин шинээр хийгдэх бөгөөд улмаар утсан дээрх бүх мэдээлэл устах болно."</string>
+    <string name="kg_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">"Та 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_pattern_attempts_dialog_message" msgid="74089475965050805">"Та тайлах хээг <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">%d</xliff:g> удаа буруу хийсэн байна. <xliff:g id="NUMBER_1">%d</xliff:g>-с илүү удаа буруу хийвэл энэ хэрэглэгч устгагдах бөгөөд энэ нь улмаар хэрэглэгчийн бүх мэдээллийг устгах болно."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу хийсэн байна. <xliff:g id="NUMBER_1">%d</xliff:g>-с илүү удаа буруу хийвэл энэ хэрэглэгч устгагдах бөгөөд энэ нь улмаар хэрэглэгчийн бүх мэдээллийг устгах болно."</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> удаа буруу хийсэн байна. <xliff:g id="NUMBER_1">%d</xliff:g>-с илүү удаа буруу хийвэл ажлын профайл устгагдах бөгөөд энэ нь улмаар профайлын бүх мэдээллийг устгах болно."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу хийсэн байна. <xliff:g id="NUMBER_1">%d</xliff:g>-с илүү удаа буруу хийвэл ажлын профайл устгагдах бөгөөд энэ нь улмаар профайлын бүх мэдээллийг устгах болно."</string>
+    <string name="kg_failed_attempts_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">"Та тайлах хээг <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу зурлаа. <xliff:g id="NUMBER_1">%d</xliff:g> удаа дахин буруу оруулбал, та таблетаа тайлахын тулд имэйл акаунт шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> секундын дараа дахин оролдоно уу."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Та тайлах хээг <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу зурлаа. <xliff:g id="NUMBER_1">%d</xliff:g> удаа дахин буруу оруулбал, та утсаа тайлахын тулд имэйл акаунтаа ашиглах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> секундын дараа дахин оролдоно уу."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Та тайлах хээг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу зурлаа. <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа дахин буруу оруулбал, та таблетаа тайлахын тулд имэйл акаунт шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Та тайлах хээг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу зурлаа. <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа дахин буруу оруулбал, та утсаа тайлахын тулд имэйл акаунтаа ашиглах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"СИМ ПИН код буруу, та төхөөрөмжийн түгжээг тайлахын тулд оператор компанитай холбоо барих шаардлагатай."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">СИМ-ны ПИН код буруу байна. Та <xliff:g id="NUMBER_1">%d</xliff:g> удаа оролдлого хийх боломжтой байна.</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Үйлчилгээ байхгүй."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Оруулах аргыг сэлгэх товч."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Нислэгийн горим"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Төхөөрөмжийг дахин эхлүүлэхийн тулд зурган хээ шаардлагатай."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Төхөөрөмжийг дахин эхлүүлэхийн тулд PIN шаардлагатай."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Төхөөрөмжийг дахин эхлүүлэхийн тулд нууц үг шаардлагатай."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Аюулгүй байдлын үүднээс зурган түгжээ оруулах шаардлагатай."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Аюулгүй байдлын үүднээс PIN оруулах шаардлагатай."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Аюулгүй байдлын үүднээс нууц үг оруулах шаардлагатай."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Профайлыг солихын тулд зурган хээ шаардлагатай."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Профайлыг солихын тулд PIN шаардлагатай."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Профайлыг солих үед нууц үг шаардлагатай."</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="other">Төхөөрөмжийн түгжээг <xliff:g id="NUMBER_1">%d</xliff:g> цагийн турш тайлаагүй байна. Зурган хээг баталгаажуулна уу.</item>
       <item quantity="one">Төхөөрөмжийн түгжээг <xliff:g id="NUMBER_0">%d</xliff:g> цагийн турш тайлаагүй байна. Зурган хээг баталгаажуулна уу.</item>
diff --git a/packages/Keyguard/res/values-mr-rIN/strings.xml b/packages/Keyguard/res/values-mr-rIN/strings.xml
index da9863f..0418a7b 100644
--- a/packages/Keyguard/res/values-mr-rIN/strings.xml
+++ b/packages/Keyguard/res/values-mr-rIN/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"योग्य PUK कोड पुन्हा-प्रविष्ट करा. परत प्रयत्न करणे सिम कायमचे अक्षम करेल."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"पिन कोड जुळत नाहीत"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"बरेच नमुना प्रयत्न"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"आपण आपला पिन <xliff:g id="NUMBER_0">%d</xliff:g> वेळा अयोग्यरितीने टाइप केला आहे. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"आपण आपला संकेतशब्द <xliff:g id="NUMBER_0">%d</xliff:g> वेळा अयोग्यरितीने टाइप केला आहे. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"आपण आपला अनलॉक नमुना <xliff:g id="NUMBER_0">%d</xliff:g> वेळा अयोग्यरितीने काढला आहे. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"आपण अनलॉक करण्याचा <xliff:g id="NUMBER_0">%d</xliff:g> वेळा टॅब्लेट चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%d</xliff:g> अयशस्वी प्रयत्नांनंतर, हा टॅब्लेट रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"आपण फोन अनलॉक करण्याचा <xliff:g id="NUMBER_0">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%d</xliff:g> अयशस्वी प्रयत्नांनंतर, हा फोन रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"आपण आपला पिन <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">"आपण आपला अनलॉक नमुना <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">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%d</xliff:g> अयशस्वी प्रयत्नांनंतर, हा वापरकर्ता काढला जाईल, जे सर्व वापरकर्ता डेटा हटवेल."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"आपण फोन अनलॉक करण्याचा <xliff:g id="NUMBER_0">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%d</xliff:g> अयशस्वी प्रयत्नांनंतर, हा वापरकर्ता काढला जाईल, जे सर्व वापरकर्ता डेटा हटवेल."</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%d</xliff:g> अयशस्वी प्रयत्नांनंतर, कार्य प्रोफाईल काढले जाईल, जे सर्व प्रोफाईल डेटा हटवेल."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"आपण फोन अनलॉक करण्याचा <xliff:g id="NUMBER_0">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%d</xliff:g> अयशस्वी प्रयत्नांनंतर, कार्य प्रोफाईल काढले जाईल, जे सर्व प्रोफाईल डेटा हटवेल."</string>
+    <string name="kg_failed_attempts_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">"आपण आपला अनलॉक नमुना <xliff:g id="NUMBER_0">%d</xliff:g> वेळा अयोग्यपणे काढला आहे. आणखी <xliff:g id="NUMBER_1">%d</xliff:g> अयशस्वी प्रयत्नांनंतर, आपल्याला ईमेल खाते वापरून आपला टॅब्लेट अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"आपण आपला अनलॉक नमुना <xliff:g id="NUMBER_0">%d</xliff:g> वेळा अयोग्यपणे काढला आहे. आणखी <xliff:g id="NUMBER_1">%d</xliff:g> अयशस्वी प्रयत्नांनंतर, आपल्याला ईमेल खाते वापरून आपला फोन अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"आपण आपला अनलॉक नमुना <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यपणे काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, आपल्याला ईमेल खाते वापरून आपला टॅब्लेट अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"आपण आपला अनलॉक नमुना <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यपणे काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, आपल्याला ईमेल खाते वापरून आपला फोन अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"सिम पिन कोड चुकीचा आहे आपण आता आपले डिव्‍हाइस अनलॉक करण्‍यासाठी आपल्‍या वाहकाशी संपर्क साधावा."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">सिम पिन चुकीचा आहे, आपल्याकडे <xliff:g id="NUMBER_1">%d</xliff:g> प्रयत्न उर्वरित आहे.</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"सेवा नाही."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट पद्धत स्‍विच करा बटण."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"विमान मोड"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"आपण डिव्‍हाइस रीस्टार्ट करता तेव्‍हा नुमन्याची आवश्‍यकता असते."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"आपण डिव्‍हाइस रीस्टार्ट करता तेव्‍हा पिन ची आवश्‍यकता असते."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"आपण डिव्‍हाइस रीस्टार्ट करता तेव्‍हा संकेतशब्दाची आवश्‍यकता असते."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"अतिरिक्त सुरक्षिततेसाठी नमुना आवश्‍यक आहे."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"अतिरिक्त सुरक्षिततेसाठी पिन आवश्‍यक आहे."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"अतिरिक्त सुरक्षिततेसाठी संकेतशब्द आवश्‍यक आहे."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"आपण प्रोफाईल स्विच करता तेव्‍हा नमुन्याची आवश्‍यकता असते."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"आपण प्रोफाईल स्विच करता तेव्‍हा पिन ची आवश्‍यकता असते."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"आपण प्रोफाईल स्विच करता तेव्‍हा संकेतशब्दाची आवश्‍यकता असते."</string>
+    <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"डिव्‍हाइस रीस्टार्ट झाल्यावर नमुना आवश्‍यक आहे"</string>
+    <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"डिव्‍हाइस रीस्टार्ट झाल्यावर पिन आवश्‍यक आहे"</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">"अतिरिक्त सुरक्षिततेसाठी पिन आवश्‍यक आहे"</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">"आपण प्रोफाईल स्विच करता तेव्‍हा पिन आवश्‍यक आहे"</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="other">डिव्‍हाइस <xliff:g id="NUMBER_1">%d</xliff:g> तासांसाठी अनलॉक केले गेले नाही. नमुन्याची पुष्टी करा.</item>
diff --git a/packages/Keyguard/res/values-ms-rMY/strings.xml b/packages/Keyguard/res/values-ms-rMY/strings.xml
index 554aa12..e8c0bab 100644
--- a/packages/Keyguard/res/values-ms-rMY/strings.xml
+++ b/packages/Keyguard/res/values-ms-rMY/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Masukkan semula kod PIN yang betul. Percubaan berulang akan melumpuhkan SIM secara kekal."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kod PIN tidak sepadan"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Terlalu banyak percubaan melukis corak"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Anda telah menaip PIN yang salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Anda telah menaip kata laluan yang salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Anda telah tersilap melukis corak buka kunci anda sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang gagal, tablet ini akan ditetapkan semula sekali gus memadam semua data."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang gagal, telefon ini akan ditetapkan semula sekali gus memadam semua data."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Anda telah menaip PIN yang salah sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%2$d</xliff:g> saat."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Anda telah menaip kata laluan yang salah sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%2$d</xliff:g> saat."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Anda telah tersilap melukis corak buka kunci anda sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%2$d</xliff:g> saat."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, tablet ini akan ditetapkan semula sekali gus memadam semua data."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, telefon ini akan ditetapkan semula sekali gus memadam semua data."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Tablet ini akan ditetapkan semula sekali gus memadam semua datanya."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Telefon ini akan ditetapkan semula sekali gus memadam semua datanya."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang gagal, pengguna ini akan dialih keluar sekali gus memadam semua data pengguna."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang gagal, pengguna ini akan dialih keluar sekali gus memadam semua data pengguna."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, pengguna ini akan dialih keluar sekali gus memadam semua data pengguna."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, pengguna ini akan dialih keluar sekali gus memadam semua data pengguna."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Pengguna ini akan dialih keluar sekali gus memadam semua data pengguna."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Pengguna ini akan dialih keluar sekali gus memadam semua data pengguna."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang gagal, profil kerja anda akan dialih keluar sekali gus memadam semua data profil."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang gagal, profil kerja ini akan dialih keluar sekali gus memadam semua data profil."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, profil kerja anda akan dialih keluar sekali gus memadam semua data profil."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, profil kerja ini akan dialih keluar sekali gus memadam semua data profil."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Profil kerja ini akan dialih keluar sekali gu memadam semua data profil."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Profil kerja ini akan dialih keluar sekali gus memadam semua data profil."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah tersilap melukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci tablet anda menggunakan log masuk Google anda.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci telefon anda menggunakan log masuk Google anda.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah tersilap melukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci tablet anda menggunakan log masuk Google anda.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> saat."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci telefon anda menggunakan log masuk Google anda.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> saat."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Kod PIN SIM tidak betul, jadi anda harus menghubungi pembawa anda untuk membuka kunci peranti."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">Kod PIN SIM salah, anda ada <xliff:g id="NUMBER_1">%d</xliff:g> cubaan lagi.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Mod Pesawat"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Corak diperlukan apabila anda memulakan semula peranti."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"PIN diperlukan apabila anda memulakan semula peranti."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Kata laluan diperlukan apabila anda memulakan semula peranti."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Corak diperlukan untuk keselamatan tambahan."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"PIN diperlukan untuk keselamatan tambahan."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Kata laluan diperlukan untuk keselamatan tambahan."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Corak diperlukan apabila anda menukar profil."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"PIN diperlukan apabila anda menukar profil."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Kata laluan diperlukan apabila anda menukar profil."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Kata laluan diperlukan setelah peranti dimulakan semula"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Corak diperlukan untuk keselamatan tambahan"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"PIN diperlukan untuk keselamatan tambahan"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Kata laluan diperlukan untuk keselamatan tambahan"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Corak diperlukan apabila anda menukar profil"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"PIN diperlukan apabila anda menukar profil"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Kata laluan diperlukan apabila anda menukar profil"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">Peranti tidak dibuka kuncinya selama <xliff:g id="NUMBER_1">%d</xliff:g> jam. Sahkan corak.</item>
       <item quantity="one">Peranti tidak dibuka kuncinya selama <xliff:g id="NUMBER_0">%d</xliff:g> jam. Sahkan corak.</item>
diff --git a/packages/Keyguard/res/values-my-rMM/strings.xml b/packages/Keyguard/res/values-my-rMM/strings.xml
index 8cb4f32..86c6e78 100644
--- a/packages/Keyguard/res/values-my-rMM/strings.xml
+++ b/packages/Keyguard/res/values-my-rMM/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"ပင်နံပါတ် ပြန်ဖွင့်သည့် ကုဒ်ကို ပြန်လည် ရိုက်ထည့်ပါ.။ ထပ်ခါ ထပ်ခါ ကြိုးစားခြင်းသည် ဆင်းမ်ကဒ်ကို အသုံးပြုမရအောင် ဖြစ်နေနိုင်ပါသည်။"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ပင် နံပါတ် မတူညီပါ"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"မြောက်မြားစွာ ပုံစံဆွဲ သော့ဖွင့်မှု"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"သင် ပင် နံပါတ်ကို အမှားကို <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ရိုက်ထည့်ပြီးပါပြီ။ \n\n<xliff:g id="NUMBER_1">%d</xliff:g> စက္ကန့် အကြာတွင် ပြန်လည်ကြိုးစားပါ"</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"သင်သည် စကားဝှက်ကို  <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် မှားရိုက်ပြီးပါပြီ။ \n\n <xliff:g id="NUMBER_1">%d</xliff:g> စက္ကန့်အကြာ ပြန်လည်ကြိုးစားပါ"</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"သင် ပုံစံဆွဲ သော့ဖွင့်ခြင်းကို <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ်မြောက် မအောင်မြင်ပါ။ \n\n<xliff:g id="NUMBER_1">%d</xliff:g> စက္ကန့်အကြာတွင် ပြန်လည် ကြိုးစားပါ"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"တက်ဘလက်အား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ ဤတက်ဘလက်အား အစမှပြန်စဖွင့်မည်ဖြစ်ပြီး၊ ၎င်း၏ဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"ဖုန်းအား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ ဤဖုန်းအား အစမှပြန်စဖွင့်မည်ဖြစ်ပြီး၊ ၎င်း၏ဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"သင် ပင် နံပါတ်ကို အမှားကို <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">"သင် ပုံစံဆွဲ သော့ဖွင့်ခြင်းကို <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">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ ဤအသုံးပြုသူအား ဖယ်ထုတ်ခြင်းခံရမည်ဖြစ်ပြီး၊ အသုံးပြုသူဒေတာအားလုံး ပျက်သွားပါမည်။"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"ဖုန်းအား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ ဤအသုံးပြုသူအား ဖယ်ထုတ်ခြင်းခံရမည်ဖြစ်ပြီး၊ အသုံးပြုသူဒေတာအားလုံး ပျက်သွားပါမည်။"</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ သင့် အလုပ်ပရိုဖိုင်အား ဖယ်ထုတ်ခြင်းခံရမည်ဖြစ်ပြီး၊ ပရိုဖိုင်ဒေတာအားလုံး ပျက်သွားပါမည်။"</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"ဖုန်းအား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ သင့် အလုပ်ပရိုဖိုင်အား ဖယ်ထုတ်ခြင်းခံရမည်ဖြစ်ပြီး၊ ပရိုဖိုင်ဒေတာအားလုံး ပျက်သွားပါမည်။"</string>
+    <string name="kg_failed_attempts_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">"သင် ပုံဖော်၍သော့ဖွင့်ခြင်းကို  <xliff:g id="NUMBER_0">%d</xliff:g> အကြိမ် မှန်ကန်စွာ မပြုလုပ်နိုင်ပါ။  နောက်ထပ် <xliff:g id="NUMBER_1">%d</xliff:g> အကြိမ် မမှန်ကန်ပါက သင့်တက်ဘလက်အား အီးမေးလ်အသုံးပြု၍ သော့ဖွင့်ရန် တောင်းဆိုပါလိမ့်မည်။ \n\n <xliff:g id="NUMBER_2">%d</xliff:g> စက္ကန့်အကြာတွင် ပြန်လည် ကြိုးစားပါ"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"သင် ပုံဖော်၍သော့ဖွင့်ခြင်းကို <xliff:g id="NUMBER_0">%d</xliff:g> အကြိမ် မှန်ကန်စွာ မပြုလုပ်နိုင်ပါ။ နောက်ထပ် <xliff:g id="NUMBER_1">%d</xliff:g> အကြိမ် မမှန်ကန်ပါက သင့်ဖုန်းအား အီးမေးလ်အသုံးပြု၍ သော့ဖွင့်ရန် တောင်းဆိုပါလိမ့်မည်။ \n\n <xliff:g id="NUMBER_2">%d</xliff:g> စက္ကန့်အကြာတွင် ပြန်လည် ကြိုးစားပါ"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"သင် ပုံဖော်၍သော့ဖွင့်ခြင်းကို  <xliff:g id="NUMBER_0">%1$d</xliff:g> အကြိမ် မှန်ကန်စွာ မပြုလုပ်နိုင်ပါ။  နောက်ထပ် <xliff:g id="NUMBER_1">%2$d</xliff:g> အကြိမ် မမှန်ကန်ပါက သင့်တက်ဘလက်အား အီးမေးလ်အသုံးပြု၍ သော့ဖွင့်ရန် တောင်းဆိုပါလိမ့်မည်။ \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> စက္ကန့်အကြာတွင် ပြန်လည် ကြိုးစားပါ"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"သင် ပုံဖော်၍သော့ဖွင့်ခြင်းကို <xliff:g id="NUMBER_0">%1$d</xliff:g> အကြိမ် မှန်ကန်စွာ မပြုလုပ်နိုင်ပါ။ နောက်ထပ် <xliff:g id="NUMBER_1">%2$d</xliff:g> အကြိမ် မမှန်ကန်ပါက သင့်ဖုန်းအား အီးမေးလ်အသုံးပြု၍ သော့ဖွင့်ရန် တောင်းဆိုပါလိမ့်မည်။ \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> စက္ကန့်အကြာတွင် ပြန်လည် ကြိုးစားပါ"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"ဆင်းကဒ် လျှို့ဝှက် အမှတ် မှားယွင်းပါသည်, ဖုန်းလိုင်းဌာနကို ဆက်သွယ်ရမည် ဖြစ်ပါတယ်"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">ဆင်းမ်ကဒ်၏ ပင်နံပါတ် မှားနေပါသည်၊ သင့်တွင်<xliff:g id="NUMBER_1">%d</xliff:g> ခါ ကြိုးစားခွင့် ကျန်ပါသေးသည်။</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ဆားဗစ် မရှိပါ"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ထည့်သွင်းခြင်းခလုတ်အား ပြောင်းခြင်း"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"လေယာဉ်ပေါ်သုံးစနစ်"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"သင့် စက်ကိရိယာအား ပြန်စဖွင့်လျှင် ပုံစံ လို၏။"</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"သင့် စက်ကိရိယာအား ပြန်စဖွင့်လျှင် PIN လို၏။"</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"သင့် စက်ကိရိယာအား ပြန်စဖွင့်လျှင် စကားဝှက် လို၏။"</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"ပိုပြီး လုံခြုံရန် ပုံစံ လိုအပ်တယ်။"</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"ပိုပြီး လုံခြုံရန် ပင်နံပါတ် လိုအပ်တယ်။"</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"ပိုပြီး လုံခြုံရန် စကားဝှက် လိုအပ်တယ်။"</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"ပရိုဖိုင်းများ သင်ပြောင်းလျှင် ပုံစံ လို၏။"</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"ပရိုဖိုင်းများ သင်ပြောင်းလျှင် PIN လို၏။"</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"ပရိုဖိုင်းများ သင်ပြောင်းလျှင် စကားဝှက် လို၏။"</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="other">စက်ကိရိယာအား <xliff:g id="NUMBER_1">%d</xliff:g> နာရီကြာ သော့ပိတ်ထား၏။ ပုံစံအား အတည်ပြုပါ။</item>
       <item quantity="one">စက်ကိရိယာအား <xliff:g id="NUMBER_0">%d</xliff:g> နာရီကြာ သော့ပိတ်ထား၏။ ပုံစံအား အတည်ပြုပါ။</item>
diff --git a/packages/Keyguard/res/values-nb/strings.xml b/packages/Keyguard/res/values-nb/strings.xml
index 248f65d..a31c52c 100644
--- a/packages/Keyguard/res/values-nb/strings.xml
+++ b/packages/Keyguard/res/values-nb/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Skriv inn den korrekte PUK-koden på nytt. Gjentatte forsøk kommer til å deaktivere SIM-kortet."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-kodene stemmer ikke overens"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"For mange forsøk på tegning av mønster"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har oppgitt feil PIN-kode <xliff:g id="NUMBER_0">%d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har tastet inn passordet ditt feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har tegnet opplåsningsmønsteret ditt feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%d</xliff:g> mislykket forsøk til, tilbakestilles nettbrettet, noe som vil slette alle nettbrettets data."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%d</xliff:g> mislykket forsøk til, tilbakestilles telefonen, noe som vil slette alle telefonens data."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har oppgitt feil PIN-kode <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har tastet inn passordet ditt feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har tegnet opplåsningsmønsteret ditt feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykket forsøk til, tilbakestilles nettbrettet, noe som vil slette alle nettbrettets data."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykket forsøk til, tilbakestilles telefonen, noe som vil slette alle telefonens data."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER">%d</xliff:g> ganger. Dette nettbrettet blir nå tilbakestilt, og alle data blir slettet."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER">%d</xliff:g> ganger. Denne telefonen blir nå tilbakestilt, og alle data blir slettet.."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%d</xliff:g> mislykket forsøk til, fjernes brukeren, noe som vil slette alle brukerdata."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%d</xliff:g> mislykket forsøk til, fjernes brukeren, noe som vil slette alle brukerdata."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykket forsøk til, fjernes brukeren, noe som vil slette alle brukerdata."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykket forsøk til, fjernes brukeren, noe som vil slette alle brukerdata."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER">%d</xliff:g> ganger. Denne brukeren blir nå fjernet, og alle brukerdata blir slettet."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER">%d</xliff:g> ganger. Denne brukeren blir nå fjernet, og aller brukerdata blir slettet."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%d</xliff:g> mislykket forsøk til, fjernes arbeidsprofilen, noe som vil slette alle profildata."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%d</xliff:g> mislykket forsøk til, fjernes arbeidsprofilen, noe som vil slette alle profildata."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykket forsøk til, fjernes arbeidsprofilen, noe som vil slette alle profildata."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykket forsøk til, fjernes arbeidsprofilen, noe som vil slette alle profildata."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER">%d</xliff:g> ganger. Arbeidsprofilen blir fjernet, og alle profildata blir slettet."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER">%d</xliff:g> ganger. Arbeidsprofilen blir fjernet, og alle profildata blir slettet."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale forsøk, blir du bedt om å låse opp nettbrettet via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale forsøk, blir du bedt om å låse opp telefonen via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%2$d</xliff:g> gale forsøk, blir du bedt om å låse opp nettbrettet via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%2$d</xliff:g> gale forsøk, blir du bedt om å låse opp telefonen via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Feil PIN-kode for SIM-kortet. Du må nå kontakte operatøren din for å låse opp enheten."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">Feil PIN-kode for SIM-kortet. Du har <xliff:g id="NUMBER_1">%d</xliff:g> forsøk igjen.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Flymodus"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Du må tegne mønsteret ditt når du starter enheten på nytt."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Du må skrive inn PIN-koden din når du starter enheten på nytt."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Du må skrive inn passordet ditt når du starter enheten på nytt."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Mønsteret kreves for ekstra sikkerhet."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"PIN-koden kreves for ekstra sikkerhet."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Passordet kreves for ekstra sikkerhet."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Du må tegne mønsteret ditt når du bytter profil."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Du må skrive inn PIN-koden din når du bytter profil."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Du må skrive inn passordet ditt når du bytter profil."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Du må skrive inn passordet etter at enheten har startet på nytt"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Du må tegne mønsteret for ekstra sikkerhet"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Du må skrive inn PIN-koden for ekstra sikkerhet"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Du må skrive inn passordet for ekstra sikkerhet"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Du må tegne mønsteret når du bytter profil"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Du må skrive inn PIN-koden når du bytter profil"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Du må skrive inn passordet når du bytter profil"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">Enheten er ikke blitt låst opp de siste <xliff:g id="NUMBER_1">%d</xliff:g> timene. Bekreft mønsteret.</item>
       <item quantity="one">Enheten er ikke blitt låst opp den siste <xliff:g id="NUMBER_0">%d</xliff:g> timen. Bekreft mønsteret.</item>
diff --git a/packages/Keyguard/res/values-ne-rNP/strings.xml b/packages/Keyguard/res/values-ne-rNP/strings.xml
index 4a5907e0..5a3b7ec 100644
--- a/packages/Keyguard/res/values-ne-rNP/strings.xml
+++ b/packages/Keyguard/res/values-ne-rNP/strings.xml
@@ -77,23 +77,23 @@
     <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">%d</xliff:g> पटक टाइप गर्नु भएको छ। \n\n<xliff:g id="NUMBER_1">%d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"तपाईँले तपाईँक पासवर्ड <xliff:g id="NUMBER_0">%d</xliff:g> पटक गलत टाइप गर्नुभएको छ। \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"तपाईँले तपाईँको अनलक ढाँचा गलत तरिकाले <xliff:g id="NUMBER_0">%d</xliff:g> पटक खिच्नु भएको छ। \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकेन्डमा फेरि कोसिस गर्नुहोस्।"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"तपाईंले गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नु भएको छ<xliff:g id="NUMBER_0">%d</xliff:g>पटक।  <xliff:g id="NUMBER_1">%d</xliff:g> थप असफल प्रयासहरूपछि, यो ट्याब्लेट रिसेट हुनेछ जसले आफ्नो सम्पूर्ण डेटा मेट्नेछ।"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"तपाईंले गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नु भएको छ <xliff:g id="NUMBER_0">%d</xliff:g> पटक। पछि <xliff:g id="NUMBER_1">%d</xliff:g> थप असफल प्रयासहरूपछि, यो फोन  रिसेट हुनेछ जसले सम्पूर्ण डेटा मेटाउनेछ।।"</string>
+    <string name="kg_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">"तपाईँले तपाईँको अनलक ढाँचा गलत तरिकाले <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">%d</xliff:g> पटक।  <xliff:g id="NUMBER_1">%d</xliff:g> थप असफल प्रयासहरूपछि, यो प्रयोगकर्ता हटाइनेछ जसले सम्पूर्ण प्रयोगकर्ता डेटा मेट्नेछ।"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"तपाईंले गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नु भएको छ <xliff:g id="NUMBER_0">%d</xliff:g> पटक। <xliff:g id="NUMBER_1">%d</xliff:g> थप असफल प्रयासहरूपछि, यो प्रयोगकर्ता हटाइनेछ जसले  सबै प्रयोगकर्ता डेटा मेट्नेछ।"</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> पटक। <xliff:g id="NUMBER_1">%d</xliff:g> थप असफल प्रयासहरूपछि, काम प्रोफाइल हटाइनेछ जसले सबै प्रोफाइल डेटा मेट्नेछ।"</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"तपाईंले गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नु भएको छ <xliff:g id="NUMBER_0">%d</xliff:g> पटक। <xliff:g id="NUMBER_1">%d</xliff:g> थप असफल प्रयासहरूपछि , काम प्रोफाइल हटाइनेछ जसले सबै प्रोफाइल डेटा मेट्नेछ।"</string>
+    <string name="kg_failed_attempts_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">"तपाईंले गलत तरिकाले आफ्नो अनलक ढाँचा <xliff:g id="NUMBER_0">%d</xliff:g> पटक कोर्नुभयो। <xliff:g id="NUMBER_1">%d</xliff:g> विफल प्रयत्नहरू पछि, तपाईंलाई आफ्नो ट्याब्लेट इमेल खाता प्रयोग गरेर अनलक गर्न सोधिने छ।\n\n फेरि प्रयास गर्नुहोस् <xliff:g id="NUMBER_2">%d</xliff:g> सेकेन्डहरूमा।"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"तपाईँले आफ्नो अनलक ढाँचा गलत रूपमा <xliff:g id="NUMBER_0">%d</xliff:g> पटक तान्नु भएको छ। <xliff:g id="NUMBER_1">%d</xliff:g> धेरै असफल प्रयासहरूपछि, तपाईँलाई एउटा इमेल खाताको प्रयोग गरेर तपाईँको फोन अनलक गर्न सोधिने छ।\n\n फेरि <xliff:g id="NUMBER_2">%d</xliff:g> सेकेन्डमा प्रयास गर्नुहोस्।"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"तपाईंले गलत तरिकाले आफ्नो अनलक ढाँचा <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक कोर्नुभयो। <xliff:g id="NUMBER_1">%2$d</xliff:g> विफल प्रयत्नहरू पछि, तपाईंलाई आफ्नो ट्याब्लेट इमेल खाता प्रयोग गरेर अनलक गर्न सोधिने छ।\n\n फेरि प्रयास गर्नुहोस् <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डहरूमा।"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"तपाईँले आफ्नो अनलक ढाँचा गलत रूपमा <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक तान्नु भएको छ। <xliff:g id="NUMBER_1">%2$d</xliff:g> धेरै असफल प्रयासहरूपछि, तपाईँलाई एउटा इमेल खाताको प्रयोग गरेर तपाईँको फोन अनलक गर्न सोधिने छ।\n\n फेरि <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा प्रयास गर्नुहोस्।"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM PIN कोड गलत छ। अब तपाईंले अाफ्नो उपकरण खोल्नलाई तपाईंको वाहकसँग सम्पर्क गर्नै पर्दर।"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other"> गलत SIM PIN कोड, तपाईँ सँग <xliff:g id="NUMBER_1">%d</xliff:g> पटक प्रयास बाँकी छ।</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"कुनै सेवा छैन।"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट विधि बटन स्विच गर्नुहोस्।"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"हवाइजहाज मोड"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"यन्त्र पुन:सुरू गर्न तपाईँलाई ढाँचा चाहिन्छ।"</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"यन्त्र पुन:सुरू गर्न तपाईँलाई PIN चाहिन्छ।"</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"यन्त्र पुन:सुरू गर्न तपाईँलाई पासवर्ड चाहिन्छ।"</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"अतिरिक्त सुरक्षाको लागि ढाँचा आवश्यक छ।"</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"अतिरिक्त सुरक्षाको लागि PIN आवश्यक छ।"</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"अतिरिक्त सुरक्षाको लागि पासवर्ड आवश्यक छ।"</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"प्रोफाइल फेर्न तपाईँलाई ढाँचा चाहिन्छ।"</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"प्रोफाइल फेर्न तपाईँलाई PIN चाहिन्छ।"</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"प्रोफाइल फेर्न तपाईँलाई पासवर्ड चाहिन्छ।"</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="other"> यन्त्र <xliff:g id="NUMBER_1">%d</xliff:g> घन्टा देखि अनलक भएको छैन। ढाँचा पुष्टि गर्नुहोस्।</item>
       <item quantity="one"> यन्त्र <xliff:g id="NUMBER_0">%d</xliff:g> घन्टा देखि अनलक भएको छैन। ढाँचा पुष्टि गर्नुहोस्। </item>
diff --git a/packages/Keyguard/res/values-nl/strings.xml b/packages/Keyguard/res/values-nl/strings.xml
index 35caf77..8ded2e8 100644
--- a/packages/Keyguard/res/values-nl/strings.xml
+++ b/packages/Keyguard/res/values-nl/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Geef de juiste PUK-code opnieuw op. Bij herhaalde pogingen wordt de simkaart permanent uitgeschakeld."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Pincodes komen niet overeen"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Te veel patroonpogingen"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Je hebt je pincode <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getypt. \n\nProbeer het opnieuw over <xliff:g id="NUMBER_1">%d</xliff:g> seconden."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Je hebt je wachtwoord <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getypt. \n\nProbeer het opnieuw over <xliff:g id="NUMBER_1">%d</xliff:g> seconden."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. \n\nProbeer het opnieuw over <xliff:g id="NUMBER_1">%d</xliff:g> seconden."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Je hebt <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt deze tablet gereset, waardoor alle gegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Je hebt <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt deze telefoon gereset, waardoor alle gegevens worden verwijderd."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Je hebt je pincode <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getypt. \n\nProbeer het opnieuw over <xliff:g id="NUMBER_1">%2$d</xliff:g> seconden."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Je hebt je wachtwoord <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getypt. \n\nProbeer het opnieuw over <xliff:g id="NUMBER_1">%2$d</xliff:g> seconden."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. \n\nProbeer het opnieuw over <xliff:g id="NUMBER_1">%2$d</xliff:g> seconden."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Je hebt <xliff:g id="NUMBER_0">%1$d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt deze tablet gereset, waardoor alle gegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Je hebt <xliff:g id="NUMBER_0">%1$d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt deze telefoon gereset, waardoor alle gegevens worden verwijderd."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Deze tablet wordt gereset, waardoor alle gegevens worden verwijderd."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Deze telefoon wordt gereset, waardoor alle gegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Je hebt <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt deze gebruiker verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Je hebt <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt deze gebruiker verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Je hebt <xliff:g id="NUMBER_0">%1$d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt deze gebruiker verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Je hebt <xliff:g id="NUMBER_0">%1$d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt deze gebruiker verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Deze gebruiker wordt verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Deze gebruiker wordt verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Je hebt <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt het werkprofiel verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Je hebt <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt het werkprofiel verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Je hebt <xliff:g id="NUMBER_0">%1$d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt het werkprofiel verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Je hebt <xliff:g id="NUMBER_0">%1$d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt het werkprofiel verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Het werkprofiel wordt verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Het werkprofiel wordt verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd je tablet te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd je telefoon te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt u gevraagd je tablet te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%3$d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt u gevraagd je telefoon te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%3$d</xliff:g> seconden opnieuw."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Onjuiste pincode voor simkaart. U moet nu contact opnemen met je provider om je apparaat te ontgrendelen."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">Onjuiste pincode voor simkaart. Je hebt nog <xliff:g id="NUMBER_1">%d</xliff:g> pogingen over.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Vliegtuigmodus"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Patroon is vereist wanneer u het apparaat opnieuw opstart."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Pincode is vereist wanneer u het apparaat opnieuw opstart."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Wachtwoord is vereist wanneer u het apparaat opnieuw opstart."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Patroon vereist voor extra beveiliging."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Pincode vereist voor extra beveiliging."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Wachtwoord vereist voor extra beveiliging."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Patroon is vereist wanneer u schakelt tussen profielen."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Pincode is vereist wanneer u schakelt tussen profielen."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Wachtwoord is vereist wanneer u schakelt tussen profielen."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Wachtwoord vereist nadat het apparaat opnieuw is opgestart"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Patroon vereist voor extra beveiliging"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Pincode vereist voor extra beveiliging"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Wachtwoord vereist voor extra beveiliging"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Patroon is vereist wanneer je schakelt tussen profielen"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Pincode is vereist wanneer je schakelt tussen profielen"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Wachtwoord is vereist wanneer je schakelt tussen profielen"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">Apparaat is al <xliff:g id="NUMBER_1">%d</xliff:g> uur niet ontgrendeld. Bevestig het patroon.</item>
       <item quantity="one">Apparaat is al <xliff:g id="NUMBER_0">%d</xliff:g> uur niet ontgrendeld. Bevestig het patroon.</item>
diff --git a/packages/Keyguard/res/values-pa-rIN/strings.xml b/packages/Keyguard/res/values-pa-rIN/strings.xml
index 8486b63..e867df2 100644
--- a/packages/Keyguard/res/values-pa-rIN/strings.xml
+++ b/packages/Keyguard/res/values-pa-rIN/strings.xml
@@ -77,23 +77,23 @@
     <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">%d</xliff:g> ਵਾਰ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਟਾਈਪ ਕੀਤਾ ਹੈ। \n\n <xliff:g id="NUMBER_1">%d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%d</xliff:g> ਵਾਰ ਆਪਣਾ ਪਾਸਵਰਡ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਟਾਈਪ ਕੀਤਾ ਹੈ। \n\n <xliff:g id="NUMBER_1">%d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਨਲੌਕ ਪੈਟਰਨ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਡ੍ਰਾ ਕੀਤਾ ਹੈ। \n\n <xliff:g id="NUMBER_1">%d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%d</xliff:g> ਵਾਰ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੇਟ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ। <xliff:g id="NUMBER_1">%d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਹ ਟੈਬਲੇਟ ਰੀਸੈਟ ਕੀਤੀ ਜਾਏਗੀ, ਜੋ ਇਸਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾ ਦੇਵੇਗਾ।"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%d</xliff:g> ਵਾਰ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਫੋਨ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ। <xliff:g id="NUMBER_1">%d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਹ ਫੋਨ ਰੀਸੈਟ ਕੀਤਾ ਜਾਏਗਾ, ਜੋ ਇਸਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾ ਦੇਵੇਗਾ।"</string>
+    <string name="kg_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">"ਤੁਸੀਂ <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">%d</xliff:g> ਵਾਰ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੇਟ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ। <xliff:g id="NUMBER_1">%d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਸ ਉਪਭੋਗਤਾ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਜਾਏਗਾ, ਜੋ ਸਾਰਾ ਉਪਭੋਗਤਾ ਡਾਟਾ ਮਿਟਾ ਦੇਵੇਗਾ।"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"ਤੁਸੀਂ  <xliff:g id="NUMBER_0">%d</xliff:g> ਵਾਰ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਫੋਨ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ। <xliff:g id="NUMBER_1">%d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਸ ਉਪਭੋਗਤਾ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਜਾਏਗਾ, ਜੋ ਸਾਰਾ ਉਪਭੋਗਤਾ ਡਾਟਾ ਮਿਟਾ ਦੇਵੇਗਾ।"</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> ਵਾਰ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੇਟ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ। <xliff:g id="NUMBER_1">%d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਕੰਮ ਪ੍ਰੋਫਾਈਲ ਹਟਾ ਦਿੱਤੀ ਜਾਏਗੀ, ਜੋ ਸਾਰਾ ਪ੍ਰੋਫਾਈਲ ਡਾਟਾ ਮਿਟਾ ਦੇਵੇਗਾ।"</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%d</xliff:g> ਵਾਰ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਫੋਨ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ। <xliff:g id="NUMBER_1">%d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਕੰਮ ਪ੍ਰੋਫਾਈਲ ਹਟਾ ਦਿੱਤੀ ਜਾਏਗੀ, ਜੋ ਸਾਰਾ ਪ੍ਰੋਫਾਈਲ ਡਾਟਾ ਮਿਟਾ ਦੇਵੇਗਾ।"</string>
+    <string name="kg_failed_attempts_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">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਨਲੌਕ ਪੈਟਰਨ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਡ੍ਰਾ ਕੀਤਾ ਹੈ। <xliff:g id="NUMBER_1">%d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਨੂੰ ਇੱਕ ਈਮੇਲ ਖਾਤਾ ਵਰਤਦੇ ਹੋਏ ਆਪਣੀ ਟੈਬਲੇਟ ਅਨਲੌਕ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਏਗਾ।\n\n <xliff:g id="NUMBER_2">%d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਨਲੌਕ ਪੈਟਰਨ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਡ੍ਰਾ ਕੀਤਾ ਹੈ। <xliff:g id="NUMBER_1">%d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਨੂੰ ਇੱਕ ਈਮੇਲ ਖਾਤਾ ਵਰਤਦੇ ਹੋਏ ਆਪਣਾ ਫੋਨ ਅਨਲੌਕ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਏਗਾ।\n\n <xliff:g id="NUMBER_2">%d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਨਲੌਕ ਪੈਟਰਨ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਡ੍ਰਾ ਕੀਤਾ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਨੂੰ ਇੱਕ ਈਮੇਲ ਖਾਤਾ ਵਰਤਦੇ ਹੋਏ ਆਪਣੀ ਟੈਬਲੇਟ ਅਨਲੌਕ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਏਗਾ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਨਲੌਕ ਪੈਟਰਨ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਡ੍ਰਾ ਕੀਤਾ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਨੂੰ ਇੱਕ ਈਮੇਲ ਖਾਤਾ ਵਰਤਦੇ ਹੋਏ ਆਪਣਾ ਫੋਨ ਅਨਲੌਕ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਏਗਾ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"ਗ਼ਲਤ SIM PIN ਕੋਡ, ਹੁਣ ਤੁਹਾਨੂੰ ਆਪਣੀ ਡਿਵਾਈਸ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਲਈ ਆਪਣੇ ਕੈਰੀਅਰ ਨੂੰ ਸੰਪਰਕ ਕਰਨਾ ਪਵੇਗਾ।"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">ਗ਼ਲਤ SIM PIN ਕੋਡ, ਤੁਹਾਡੇ ਕੋਲ <xliff:g id="NUMBER_1">%d</xliff:g> ਕੋਸ਼ਿਸ਼ਾਂ ਬਾਕੀ ਹਨ।</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ਕੋਈ ਸੇਵਾ ਨਹੀਂ।"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ਇਨਪੁਟ ਵਿਧੀ ਬਟਨ ਸਵਿਚ ਕਰੋ।"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"ਏਅਰਪਲੇਨ ਮੋਡ"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"ਜਦੋਂ ਤੁਸੀਂ ਡਿਵਾਈਸ ਨੂੰ ਰੀਸਟਾਰਟ ਕਰਦੇ ਹੋ ਤਾਂ ਪੈਟਰਨ ਲੁੜੀਂਦਾ ਹੈ।"</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"ਜਦੋਂ ਤੁਸੀਂ ਡਿਵਾਈਸ ਨੂੰ ਰੀਸਟਾਰਟ ਕਰਦੇ ਹੋ ਤਾਂ PIN  ਲੁੜੀਂਦਾ ਹੈ।"</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"ਜਦੋਂ ਤੁਸੀਂ ਡਿਵਾਈਸ ਨੂੰ ਰੀਸਟਾਰਟ ਕਰਦੇ ਹੋ ਤਾਂ ਪਾਸਵਰਡ ਲੁੜੀਂਦਾ ਹੈ।"</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"ਵਾਧੂ ਸੁਰੱਖਿਆ ਲਈ ਪੈਟਰਨ ਲੁੜੀਂਦਾ ਹੈ।"</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"ਵਾਧੂ ਸੁਰੱਖਿਆ ਲਈ PIN ਲੁੜੀਂਦਾ ਹੈ।"</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"ਵਾਧੂ ਸੁਰੱਖਿਆ ਲਈ ਪਾਸਵਰਡ ਲੁੜੀਂਦਾ ਹੈ।"</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"ਜਦੋਂ ਤੁਸੀਂ ਪ੍ਰੋਫਾਈਲਾਂ ਸਵਿਚ ਕਰਦੇ ਹੋ ਤਾਂ ਪੈਟਰਨ ਲੁੜੀਂਦਾ ਹੈ।"</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"ਜਦੋਂ ਤੁਸੀਂ ਪ੍ਰੋਫਾਈਲਾਂ ਸਵਿਚ ਕਰਦੇ ਹੋ ਤਾਂ PIN ਲੁੜੀਂਦਾ ਹੈ।"</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"ਜਦੋਂ ਤੁਸੀਂ ਪ੍ਰੋਫਾਈਲਾਂ ਸਵਿਚ ਕਰਦੇ ਹੋ ਤਾਂ ਪਾਸਵਰਡ ਲੁੜੀਂਦਾ ਹੈ।"</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="other">ਡਿਵਾਈਸ <xliff:g id="NUMBER_1">%d</xliff:g> ਘੰਟਿਆਂ ਤੋਂ ਅਨਲੌਕ ਨਹੀਂ ਕੀਤੀ ਗਈ ਹੈ। ਪੈਟਰਨ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ।</item>
diff --git a/packages/Keyguard/res/values-pl/strings.xml b/packages/Keyguard/res/values-pl/strings.xml
index 04930c5..3bd9caf 100644
--- a/packages/Keyguard/res/values-pl/strings.xml
+++ b/packages/Keyguard/res/values-pl/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Ponownie podaj poprawny kod PUK. Nieudane próby spowodują trwałe wyłączenie karty SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kody PIN nie pasują"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Zbyt wiele prób narysowania wzoru"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Wpisałeś nieprawidłowy kod PIN <xliff:g id="NUMBER_0">%d</xliff:g> razy. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> wpisałeś nieprawidłowe hasło. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Narysowałeś nieprawidłowy wzór odblokowania <xliff:g id="NUMBER_0">%d</xliff:g> razy. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Próbowałeś <xliff:g id="NUMBER_0">%d</xliff:g> razy nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach tablet zostanie zresetowany, co spowoduje skasowanie z niego wszystkich danych."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Próbowałeś <xliff:g id="NUMBER_0">%d</xliff:g> razy nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach telefon zostanie zresetowany, co spowoduje skasowanie z niego wszystkich danych."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Wpisałeś nieprawidłowy kod PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> razy. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> wpisałeś nieprawidłowe hasło. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Narysowałeś nieprawidłowy wzór odblokowania <xliff:g id="NUMBER_0">%1$d</xliff:g> razy. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Próbowałeś <xliff:g id="NUMBER_0">%1$d</xliff:g> razy nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach tablet zostanie zresetowany, co spowoduje skasowanie z niego wszystkich danych."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Próbowałeś <xliff:g id="NUMBER_0">%1$d</xliff:g> razy nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach telefon zostanie zresetowany, co spowoduje skasowanie z niego wszystkich danych."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Próbowałeś <xliff:g id="NUMBER">%d</xliff:g> razy nieprawidłowo odblokować tablet. Zostanie on zresetowany, co spowoduje skasowanie z niego wszystkich danych."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Próbowałeś <xliff:g id="NUMBER">%d</xliff:g> razy nieprawidłowo odblokować telefon. Zostanie on zresetowany, co spowoduje skasowanie z niego wszystkich danych."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Próbowałeś <xliff:g id="NUMBER_0">%d</xliff:g> razy nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach ten użytkownik zostanie usunięty, co spowoduje skasowanie wszystkich jego danych."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Próbowałeś <xliff:g id="NUMBER_0">%d</xliff:g> razy nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach, ten użytkownik zostanie usunięty, co spowoduje skasowanie wszystkich jego danych."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Próbowałeś <xliff:g id="NUMBER_0">%1$d</xliff:g> razy nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach ten użytkownik zostanie usunięty, co spowoduje skasowanie wszystkich jego danych."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Próbowałeś <xliff:g id="NUMBER_0">%1$d</xliff:g> razy nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach, ten użytkownik zostanie usunięty, co spowoduje skasowanie wszystkich jego danych."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Próbowałeś <xliff:g id="NUMBER">%d</xliff:g> razy nieprawidłowo odblokować tablet. Ten użytkownik zostanie usunięty, co spowoduje skasowanie wszystkich jego danych."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Próbowałeś <xliff:g id="NUMBER">%d</xliff:g> razy nieprawidłowo odblokować telefon. Ten użytkownik zostanie usunięty, co spowoduje skasowanie wszystkich jego danych."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Próbowałeś <xliff:g id="NUMBER_0">%d</xliff:g> razy nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach profil do pracy zostanie usunięty, co spowoduje skasowanie wszystkich danych tego profilu."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Próbowałeś <xliff:g id="NUMBER_0">%d</xliff:g> razy nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach profil do pracy zostanie usunięty, co spowoduje skasowanie wszystkich danych tego profilu."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Próbowałeś <xliff:g id="NUMBER_0">%1$d</xliff:g> razy nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach profil do pracy zostanie usunięty, co spowoduje skasowanie wszystkich danych tego profilu."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Próbowałeś <xliff:g id="NUMBER_0">%1$d</xliff:g> razy nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach profil do pracy zostanie usunięty, co spowoduje skasowanie wszystkich danych tego profilu."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Próbowałeś <xliff:g id="NUMBER">%d</xliff:g> razy nieprawidłowo odblokować tablet. Profil do pracy zostanie usunięty, co spowoduje skasowanie wszystkich danych tego profilu."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Próbowałeś <xliff:g id="NUMBER">%d</xliff:g> razy nieprawidłowo odblokować telefon. Profil do pracy zostanie usunięty, co spowoduje skasowanie wszystkich danych tego profilu."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach konieczne będzie odblokowanie tabletu przy użyciu danych logowania na konto Google.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach konieczne będzie odblokowanie telefonu przy użyciu danych logowania na konto Google.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach konieczne będzie odblokowanie tabletu przy użyciu danych logowania na konto Google.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach konieczne będzie odblokowanie telefonu przy użyciu danych logowania na konto Google.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Nieprawidłowy kod PIN karty SIM. Musisz teraz skontaktować się z operatorem, by odblokował Twoje urządzenie."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="few">Nieprawidłowy kod PIN karty SIM. Masz jeszcze <xliff:g id="NUMBER_1">%d</xliff:g> próby.</item>
@@ -114,15 +114,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Tryb samolotowy"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Po ponownym uruchomieniu urządzenia wymagany jest wzór."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Po ponownym uruchomieniu urządzenia wymagany jest kod PIN."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Po ponownym uruchomieniu urządzenia wymagane jest hasło."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Dla dodatkowego bezpieczeństwa musisz narysować wzór."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Dla dodatkowego bezpieczeństwa musisz podać kod PIN."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Dla dodatkowego bezpieczeństwa musisz podać hasło."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Po przełączeniu profili wymagany jest wzór."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Po przełączeniu profili wymagany jest kod PIN."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Po przełączeniu profili wymagane jest hasło."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Po ponownym uruchomieniu urządzenia wymagane jest hasło"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Dla dodatkowego bezpieczeństwa musisz narysować wzór"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Dla dodatkowego bezpieczeństwa musisz podać kod PIN"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Dla dodatkowego bezpieczeństwa musisz podać hasło"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Po przełączeniu profili wymagany jest wzór"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Po przełączeniu profili wymagany jest kod PIN"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Po przełączeniu profili wymagane jest hasło"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="few">Urządzenie nie zostało odblokowane od <xliff:g id="NUMBER_1">%d</xliff:g> godzin. Potwierdź wzór.</item>
       <item quantity="many">Urządzenie nie zostało odblokowane od <xliff:g id="NUMBER_1">%d</xliff:g> godzin. Potwierdź wzór.</item>
diff --git a/packages/Keyguard/res/values-pt-rBR/strings.xml b/packages/Keyguard/res/values-pt-rBR/strings.xml
index 0ef07e5..4f1afab 100644
--- a/packages/Keyguard/res/values-pt-rBR/strings.xml
+++ b/packages/Keyguard/res/values-pt-rBR/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Introduza novamente o código PUK correto. Muitas tentativas malsucedidas desativarão permanentemente o SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Os códigos PIN não coincidem"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Muitas tentativas de padrão"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, este tablet será redefinido, o que excluirá todos os seus dados."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, este smartphone será redefinido, o que excluirá todos os seus dados."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas, este tablet será redefinido, o que excluirá todos os seus dados."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas, este smartphone será redefinido, o que excluirá todos os seus dados."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este tablet será redefinido, o que excluirá todos os seus dados."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este smartphone será redefinido, o que excluirá todos os seus dados."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, este usuário será removido, o que excluirá todos os dados do usuário."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, este usuário será removido, o que excluirá todos os dados do usuário."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas, este usuário será removido, o que excluirá todos os dados do usuário."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas, este usuário será removido, o que excluirá todos os dados do usuário."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este usuário será removido, o que excluirá todos os dados do usuário."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este usuário será removido, o que excluirá todos os dados do usuário."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas,o perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, o perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas,o perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas, o perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Código PIN do SIM incorreto. Entre em contato com a operadora para desbloquear o dispositivo."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">Código PIN do SIM incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Modo avião"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"O padrão é exigido quando você reinicia o dispositivo."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"O PIN é exigido quando você reinicia o dispositivo."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"A senha é exigida quando você reinicia o dispositivo."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"O padrão é necessário para aumentar a segurança."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"O PIN é necessário para aumentar a segurança."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"A senha é necessária para aumentar a segurança."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"O padrão é exigido quando você troca de perfil."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"O PIN é exigido quando você troca de perfil."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"A senha é exigida quando você troca de perfil."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"A senha é exigida após a reinicialização do dispositivo"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"O padrão é necessário para aumentar a segurança"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"O PIN é necessário para aumentar a segurança"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"A senha é necessária para aumentar a segurança"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"O padrão é exigido quando você troca de perfil"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"O PIN é exigido quando você troca de perfil"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"A senha é exigida quando você troca de perfil"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="one">O dispositivo não foi desbloqueado há <xliff:g id="NUMBER_1">%d</xliff:g> horas. Confirme o padrão.</item>
       <item quantity="other">O dispositivo não foi desbloqueado há <xliff:g id="NUMBER_1">%d</xliff:g> horas. Confirme o padrão.</item>
diff --git a/packages/Keyguard/res/values-pt-rPT/strings.xml b/packages/Keyguard/res/values-pt-rPT/strings.xml
index dda689c..49c2f16 100644
--- a/packages/Keyguard/res/values-pt-rPT/strings.xml
+++ b/packages/Keyguard/res/values-pt-rPT/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Volte a introduzir o código PUK correto. Demasiadas tentativas consecutivas irão desativar permanentemente o SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Os códigos PIN não correspondem"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Demasiadas tentativas para desenhar sequência"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Escreveu o PIN incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Escreveu a palavra-passe incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Desenhou a sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem êxito, este telemóvel será reposto, o que eliminará todos os seus dados."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem êxito, este telemóvel será reposto, o que eliminará todos os seus dados."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Escreveu o PIN incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Escreveu a palavra-passe incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Desenhou a sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, este telemóvel será reposto, o que eliminará todos os seus dados."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, este telemóvel será reposto, o que eliminará todos os seus dados."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER">%d</xliff:g> vezes. Este telemóvel será reposto, o que eliminará todos os seus dados."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER">%d</xliff:g> vezes. Este telemóvel será reposto, o que eliminará todos os seus dados."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem êxito, este utilizador será removido, o que eliminará todos os dados respetivos."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem êxito, este utilizador será removido, o que eliminará todos os dados respetivos."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, este utilizador será removido, o que eliminará todos os dados respetivos."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, este utilizador será removido, o que eliminará todos os dados respetivos."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER">%d</xliff:g> vezes. Este utilizador será removido, o que eliminará todos os dados respetivos."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER">%d</xliff:g> vezes. Este utilizador será removido, o que eliminará todos os dados respetivos."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem êxito, o perfil de trabalho será removido, o que eliminará todos os dados do perfil."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem êxito, o perfil de trabalho será removido, o que eliminará todos os dados do perfil."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, o perfil de trabalho será removido, o que eliminará todos os dados do perfil."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, o perfil de trabalho será removido, o que eliminará todos os dados do perfil."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que eliminará todos os dados do perfil."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que eliminará todos os dados do perfil."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o tablet através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o telemóvel através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o tablet através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o telemóvel através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Código PIN do cartão SIM incorreto. Tem de contactar o seu operador para desbloquear o dispositivo."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">Código PIN do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Modo de avião"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"É necessária a sequência quando reinicia o dispositivo."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"É necessário o PIN quando reinicia o dispositivo."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"É necessária a palavra-passe quando reinicia o dispositivo."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Para uma segurança adicional, é necessária uma sequência."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Para uma segurança adicional, é necessária um PIN."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Para uma segurança adicional, é necessária uma palavra-passe."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"É necessária a sequência quando muda de perfil."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"É necessário o PIN quando muda de perfil."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"É necessária a palavra-passe quando muda de perfil."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"É necessária uma palavra-passe após reiniciar o dispositivo"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Para segurança adicional, é necessário um padrão"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Para segurança adicional, é necessária um PIN"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Para segurança adicional, é necessária uma palavra-passe"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"É necessário um padrão quando muda de perfil"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"É necessário um PIN quando muda de perfil"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"É necessária uma palavra-passe quando muda de perfil"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_1">%d</xliff:g> horas. Confirme a sequência.</item>
       <item quantity="one">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_0">%d</xliff:g> hora. Confirme a sequência.</item>
diff --git a/packages/Keyguard/res/values-pt/strings.xml b/packages/Keyguard/res/values-pt/strings.xml
index 0ef07e5..4f1afab 100644
--- a/packages/Keyguard/res/values-pt/strings.xml
+++ b/packages/Keyguard/res/values-pt/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Introduza novamente o código PUK correto. Muitas tentativas malsucedidas desativarão permanentemente o SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Os códigos PIN não coincidem"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Muitas tentativas de padrão"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, este tablet será redefinido, o que excluirá todos os seus dados."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, este smartphone será redefinido, o que excluirá todos os seus dados."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas, este tablet será redefinido, o que excluirá todos os seus dados."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas, este smartphone será redefinido, o que excluirá todos os seus dados."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este tablet será redefinido, o que excluirá todos os seus dados."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este smartphone será redefinido, o que excluirá todos os seus dados."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, este usuário será removido, o que excluirá todos os dados do usuário."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, este usuário será removido, o que excluirá todos os dados do usuário."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas, este usuário será removido, o que excluirá todos os dados do usuário."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas, este usuário será removido, o que excluirá todos os dados do usuário."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este usuário será removido, o que excluirá todos os dados do usuário."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este usuário será removido, o que excluirá todos os dados do usuário."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas,o perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, o perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas,o perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas, o perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Código PIN do SIM incorreto. Entre em contato com a operadora para desbloquear o dispositivo."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">Código PIN do SIM incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Modo avião"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"O padrão é exigido quando você reinicia o dispositivo."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"O PIN é exigido quando você reinicia o dispositivo."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"A senha é exigida quando você reinicia o dispositivo."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"O padrão é necessário para aumentar a segurança."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"O PIN é necessário para aumentar a segurança."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"A senha é necessária para aumentar a segurança."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"O padrão é exigido quando você troca de perfil."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"O PIN é exigido quando você troca de perfil."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"A senha é exigida quando você troca de perfil."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"A senha é exigida após a reinicialização do dispositivo"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"O padrão é necessário para aumentar a segurança"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"O PIN é necessário para aumentar a segurança"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"A senha é necessária para aumentar a segurança"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"O padrão é exigido quando você troca de perfil"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"O PIN é exigido quando você troca de perfil"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"A senha é exigida quando você troca de perfil"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="one">O dispositivo não foi desbloqueado há <xliff:g id="NUMBER_1">%d</xliff:g> horas. Confirme o padrão.</item>
       <item quantity="other">O dispositivo não foi desbloqueado há <xliff:g id="NUMBER_1">%d</xliff:g> horas. Confirme o padrão.</item>
diff --git a/packages/Keyguard/res/values-ro/strings.xml b/packages/Keyguard/res/values-ro/strings.xml
index a017564..2b279ad 100644
--- a/packages/Keyguard/res/values-ro/strings.xml
+++ b/packages/Keyguard/res/values-ro/strings.xml
@@ -77,23 +77,23 @@
     <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">%d</xliff:g> ori.\n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Aţi introdus incorect parola de <xliff:g id="NUMBER_0">%d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Ați efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%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">%d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereușite, acest telefon va fi resetat, iar toate datele acestuia vor fi șterse."</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>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Acest telefon va fi resetat, iar toate datele acestuia vor fi șterse."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Ați efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereușite, acest utilizator va fi eliminat, iar toate datele utilizatorului vor fi șterse."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Ați efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereușite, acest utilizator va fi eliminat, iar toate datele utilizatorului vor fi șterse."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"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, acest utilizator va fi eliminat, iar toate datele utilizatorului vor fi șterse."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"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 utilizator va fi eliminat, iar toate datele utilizatorului vor fi șterse."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Acest utilizator va fi eliminat, iar toate datele utilizatorului vor fi șterse."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Acest utilizator va fi eliminat, iar toate datele utilizatorului vor fi șterse."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Ați efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%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_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Ați efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%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_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"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, profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string>
+    <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">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi tableta cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi telefonul cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_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>
@@ -112,15 +112,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Mod Avion"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Când reporniți dispozitivul este necesar să introduceți modelul."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Când reporniți dispozitivul este necesar să introduceți codul PIN."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Când reporniți dispozitivul este necesar să introduceți parola."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Pentru securitate suplimentară este necesar un șablon."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Pentru securitate suplimentară este necesar un cod PIN."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Pentru securitate suplimentară este necesară o parolă."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Când comutați între profiluri este necesar să introduceți modelul."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Când comutați între profiluri este necesar să introduceți codul PIN."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Când comutați între profiluri este necesar să introduceți parola."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Parola este necesară după repornirea dispozitivului"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Modelul este necesar pentru securitate suplimentară"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Codul PIN este necesar pentru securitate suplimentară"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Parola este necesară pentru securitate suplimentară"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Modelul este necesar când comutați între profiluri"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Codul PIN este necesar când comutați între profiluri"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Parola este necesară când comutați între profiluri"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="few">Dispozitivul nu a fost deblocat de <xliff:g id="NUMBER_1">%d</xliff:g> ore. Confirmați modelul.</item>
       <item quantity="other">Dispozitivul nu a fost deblocat de <xliff:g id="NUMBER_1">%d</xliff:g> de ore. Confirmați modelul.</item>
diff --git a/packages/Keyguard/res/values-ru/strings.xml b/packages/Keyguard/res/values-ru/strings.xml
index 226f566..2f03166 100644
--- a/packages/Keyguard/res/values-ru/strings.xml
+++ b/packages/Keyguard/res/values-ru/strings.xml
@@ -77,23 +77,23 @@
     <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">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали PIN-код. \n\nПовтор через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали пароль.\n\nПовтор через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали графический ключ.\n\nПовтор через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Количество неудачных попыток разблокировать планшетный ПК: <xliff:g id="NUMBER_0">%d</xliff:g>. Количество оставшихся попыток: <xliff:g id="NUMBER_1">%d</xliff:g>. Если они также будут неуспешными, настройки планшетного ПК будут сброшены, а все его данные – удалены."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Количество неудачных попыток разблокировать телефон: <xliff:g id="NUMBER_0">%d</xliff:g>. Количество оставшихся попыток: <xliff:g id="NUMBER_1">%d</xliff:g>. Если они также будут неуспешными, настройки телефона будут сброшены, а все его данные – удалены."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Вы <xliff:g id="NUMBER_0">%1$d</xliff:g> раз неверно указали PIN-код. \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">"Вы <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">%d</xliff:g>. Количество оставшихся попыток: <xliff:g id="NUMBER_1">%d</xliff:g>. Если они также будут неуспешными, аккаунт этого пользователя и все его данные будут удалены."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Количество неудачных попыток разблокировать телефон: <xliff:g id="NUMBER_0">%d</xliff:g>. Количество оставшихся попыток: <xliff:g id="NUMBER_1">%d</xliff:g>. Если они также будут неуспешными, аккаунт этого пользователя и все его данные будут удалены."</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g>. Количество оставшихся попыток: <xliff:g id="NUMBER_1">%d</xliff:g>. Если они также будут неуспешными, рабочий профиль и все его данные будут удалены."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Количество неудачных попыток разблокировать телефон: <xliff:g id="NUMBER_0">%d</xliff:g>. Количество оставшихся попыток: <xliff:g id="NUMBER_1">%d</xliff:g>. Если они также будут неуспешными, рабочий профиль и все его данные будут удалены."</string>
+    <string name="kg_failed_attempts_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">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали графический ключ. После <xliff:g id="NUMBER_1">%d</xliff:g> неверных попыток для разблокировки планшетного ПК потребуется войти в аккаунт Google.\n\nПовтор через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали графический ключ. После <xliff:g id="NUMBER_1">%d</xliff:g> неверных попыток для разблокировки телефона потребуется войти в аккаунт Google.\n\nПовтор через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Вы <xliff:g id="NUMBER_0">%1$d</xliff:g> раз неверно указали графический ключ. После <xliff:g id="NUMBER_1">%2$d</xliff:g> неверных попыток для разблокировки планшетного ПК потребуется войти в аккаунт 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">"Вы <xliff:g id="NUMBER_0">%1$d</xliff:g> раз неверно указали графический ключ. После <xliff:g id="NUMBER_1">%2$d</xliff:g> неверных попыток для разблокировки телефона потребуется войти в аккаунт 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-код. Осталась <xliff:g id="NUMBER_1">%d</xliff:g> попытка. После этого SIM-карта будет заблокирована и вам придется обратиться к оператору связи.</item>
@@ -114,15 +114,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Нет сигнала."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Кнопка переключения способа ввода."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Режим полета"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"После перезапуска устройства нужно ввести графический ключ."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"После перезапуска устройства нужно ввести PIN-код."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"После перезапуска устройства нужно ввести пароль."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"В качестве дополнительной меры безопасности введите графический ключ."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"В качестве дополнительной меры безопасности введите PIN-код."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"В качестве дополнительной меры безопасности введите пароль."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"После смены аккаунта нужно ввести графический ключ."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"После смены аккаунта нужно ввести PIN-код."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"После смены аккаунта нужно ввести пароль."</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>
diff --git a/packages/Keyguard/res/values-si-rLK/strings.xml b/packages/Keyguard/res/values-si-rLK/strings.xml
index 0afda24..82ef914 100644
--- a/packages/Keyguard/res/values-si-rLK/strings.xml
+++ b/packages/Keyguard/res/values-si-rLK/strings.xml
@@ -77,23 +77,23 @@
     <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">%d</xliff:g> වාරයක් වැරදියට ටයිප් කොට ඇත.\n\n තත්පර <xliff:g id="NUMBER_1">%d</xliff:g> ක් ඇතුළත නැවත උත්සාහ කරන්න."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"<xliff:g id="NUMBER_0">%d</xliff:g> වතාවක් ඔබගේ මුරපදය ඔබ වැරදියට ටයිප් කර ඇත. \n\nතත්පර <xliff:g id="NUMBER_1">%d</xliff:g> ට පසුව නැවත උත්සහ කරන්න."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"ඔබ <xliff:g id="NUMBER_0">%d</xliff:g> වාරයක් අගුළු ඇරීමේ රටාව වැරදියට ඇඳ ඇත. \n\nතත්පර <xliff:g id="NUMBER_1">%d</xliff:g> ක් ඇතුළත නැවත උත්සාහ කරන්න."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"ඔබ ඔබගේ ටැබ්ලටය අගුළු හැරීමට <xliff:g id="NUMBER_0">%d</xliff:g> වරක් වැරදි වශයෙන් උත්සාහ කර ඇත. අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%d</xliff:g> කින් පසුව, ටැබ්ලටය නැවත සකස් කෙරෙනු ඇති අතර, එමගින් සියලු දත්ත මකා දැමෙනු ඇත."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"ඔබ ඔබගේ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER_0">%d</xliff:g> වරක් වැරදි වශයෙන් උත්සාහ කර ඇත. අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%d</xliff:g> කින් පසුව, දුරකථනය නැවත සකස් කෙරෙනු ඇති අතර, එමගින් සියලු දත්ත මකා දැමෙනු ඇත."</string>
+    <string name="kg_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">"ඔබ <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">%d</xliff:g> වරක් වැරදි වශයෙන් උත්සාහ කර ඇත. අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%d</xliff:g> කින් පසුව, පරිශීලකයා ඉවත් වනු ඇති අතර, එමගින් සියලු පරිශීලක දත්ත මකා දැමෙනු ඇත."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"ඔබ ඔබගේ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER_0">%d</xliff:g> වරක් වැරදි වශයෙන් උත්සාහ කර ඇත. අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%d</xliff:g> කින් පසුව, පරිශීලකයා ඉවත් වනු ඇති අතර, එමගින් සියලු පරිශීලක දත්ත මකා දැමෙනු ඇත."</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> වරක් වැරදි වශයෙන් උත්සාහ කර ඇත. අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%d</xliff:g> කින් පසුව, කාර්යාල පැතිකඩ ඉවත් වනු ඇති අතර, එමගින් සියලු පැතිකඩ දත්ත මකා දැමෙනු ඇත."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"ඔබ ඔබගේ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER_0">%d</xliff:g> වරක් වැරදි වශයෙන් උත්සාහ කර ඇත. අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%d</xliff:g> කින් පසුව, කාර්යාල පැතිකඩ ඉවත් වනු ඇති අතර, එමගින් සියලු පැතිකඩ දත්ත මකා දැමෙනු ඇත."</string>
+    <string name="kg_failed_attempts_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">"ඔබ අගුළු ඇරිමේ රටාව <xliff:g id="NUMBER_0">%d</xliff:g> වතාවක් වැරදියට ඇඳ ඇත. තවත් අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%d</xliff:g> කින් පසුව, ඊ-තැපැල් ගිණුම භාවිතා කරමින් ඔබගේ ටැබ්ලටයේ අගුළු ඇරීමට ඔබට පවසනු ඇත.\n\n නැවත තත්පර <xliff:g id="NUMBER_2">%d</xliff:g> කින් උත්සාහ කරන්න."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ඔබ වැරදියට <xliff:g id="NUMBER_0">%d</xliff:g> වතාවක් ඔබගේ අගුළු හැරීමේ රටාව ඇඳ ඇත. අසාර්ථක උත්සහ කිරීම් <xliff:g id="NUMBER_1">%d</xliff:g> න් පසුව, ඔබගේ ඊ-තැපැල් ලිපිනය භාවිතයෙන් ඔබගේ දුරකථනය අගුළු හැරීමට ඔබගෙන් අසයි.\n\n තත්පර <xliff:g id="NUMBER_2">%d</xliff:g> න් පසුව නැවත උත්සහ කරන්න."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ඔබ අගුළු ඇරිමේ රටාව <xliff:g id="NUMBER_0">%1$d</xliff:g> වතාවක් වැරදියට ඇඳ ඇත. තවත් අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%2$d</xliff:g> කින් පසුව, ඊ-තැපැල් ගිණුම භාවිතා කරමින් ඔබගේ ටැබ්ලටයේ අගුළු ඇරීමට ඔබට පවසනු ඇත.\n\n නැවත තත්පර <xliff:g id="NUMBER_2">%3$d</xliff:g> කින් උත්සාහ කරන්න."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ඔබ වැරදියට <xliff:g id="NUMBER_0">%1$d</xliff:g> වතාවක් ඔබගේ අගුළු හැරීමේ රටාව ඇඳ ඇත. අසාර්ථක උත්සහ කිරීම් <xliff:g id="NUMBER_1">%2$d</xliff:g> න් පසුව, ඔබගේ ඊ-තැපැල් ලිපිනය භාවිතයෙන් ඔබගේ දුරකථනය අගුළු හැරීමට ඔබගෙන් අසයි.\n\n තත්පර <xliff:g id="NUMBER_2">%3$d</xliff:g> න් පසුව නැවත උත්සහ කරන්න."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"වැරදී SIM PIN කේතයකි, ඔබගේ දුරකතනයේ අඟුල හැරීමට ඔබගේ වාහකයා ඔබ දැන් සම්බන්ධ කරගත යුතුය."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">වැරදි SIM PIN කේතයකි, ඔබට උත්සාහයන් <xliff:g id="NUMBER_1">%d</xliff:g> ක් ඉතිරිව ඇත.</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"සේවාව නැත."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ආදාන ක්‍රමය මාරු කිරීමේ බොත්තම."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"ගුවන්යානා ප්‍රකාරය"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"ඔබ උපාංගය නැවත ආරම්භ කරන විට රටාව අවශ්‍යයි."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"ඔබ උපාංගය නැවත ආරම්භ කරන විට PIN අංකය අවශ්‍යයි."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"ඔබ උපාංගය නැවත ආරම්භ කරන විට මුරපදය අවශ්‍යයි."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"අමතර ආරක්ෂාව සඳහා රටාව අවශ්‍යයි."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"අමතර ආරක්ෂාව සඳහා PIN අංකය අවශ්‍යයි."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"අමතර ආරක්ෂාව සඳහා මුරපදය අවශ්‍යයි."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"ඔබ පැතිකඩවල් මාරු කරන විට රටාව අවශ්‍යයි."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"ඔබ පැතිකඩවල් මාරු කරන විට PIN අංකය අවශ්‍යයි."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"ඔබ පැතිකඩවල් මාරු කරන විට මුරපදය අවශ්‍යයි."</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="other">උපාංගය පැය <xliff:g id="NUMBER_1">%d</xliff:g>කට අගුලු හැර නැත. රටාව තහවුරු කරන්න.</item>
diff --git a/packages/Keyguard/res/values-sk/strings.xml b/packages/Keyguard/res/values-sk/strings.xml
index 4825e4a..72958ce 100644
--- a/packages/Keyguard/res/values-sk/strings.xml
+++ b/packages/Keyguard/res/values-sk/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Znova zadajte správny kód PUK. Opakované pokusy zakážu SIM kartu natrvalo."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kódy PIN sa nezhodujú"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Príliš veľa pokusov o nakreslenie vzoru"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste zadali nesprávny kód PIN. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste zadali nesprávne heslo. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste použili nesprávny bezpečnostný vzor. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Telefón ste sa pokúsili <xliff:g id="NUMBER_0">%d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%d</xliff:g>) bude tento tablet obnovený a všetky údaje, ktoré sú v ňom uložené, budú odstránené."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Telefón ste sa pokúsili <xliff:g id="NUMBER_0">%d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%d</xliff:g> ) bude tento telefón obnovený a všetky údaje, ktoré sú v ňom uložené, budú odstránené."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"<xliff:g id="NUMBER_0">%1$d</xliff:g>-krát ste zadali nesprávny kód PIN. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"<xliff:g id="NUMBER_0">%1$d</xliff:g>-krát ste zadali nesprávne heslo. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%1$d</xliff:g>-krát ste použili nesprávny bezpečnostný vzor. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Telefón ste sa pokúsili <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%2$d</xliff:g>) bude tento tablet obnovený a všetky údaje, ktoré sú v ňom uložené, budú odstránené."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Telefón ste sa pokúsili <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%2$d</xliff:g> ) bude tento telefón obnovený a všetky údaje, ktoré sú v ňom uložené, budú odstránené."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Tablet ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Tablet bude obnovený a všetky údaje, ktoré sú v ňom uložené, budú odstránené."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Telefón ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Telefón bude obnovený a všetky údaje, ktoré sú v ňom uložené, budú odstránené."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Tablet ste sa pokúsili <xliff:g id="NUMBER_0">%d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%d</xliff:g> ) bude tento používateľ odstránený a spolu s ním všetky jeho údaje."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Telefón ste sa pokúsili <xliff:g id="NUMBER_0">%d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%d</xliff:g>) bude tento používateľ odstránený a spolu s ním všetky jeho údaje."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Tablet ste sa pokúsili <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%2$d</xliff:g> ) bude tento používateľ odstránený a spolu s ním všetky jeho údaje."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Telefón ste sa pokúsili <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%2$d</xliff:g>) bude tento používateľ odstránený a spolu s ním všetky jeho údaje."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Tablet ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Používateľ bude odstránený a spolu s ním všetky jeho údaje."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Telefón ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Používateľ bude odstránený a spolu s ním všetky jeho údaje."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Tablet ste sa pokúsili <xliff:g id="NUMBER_0">%d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%d</xliff:g>) bude pracovný profil odstránený a spolu s ním všetky údaje profilu."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Telefón ste sa pokúsili <xliff:g id="NUMBER_0">%d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%d</xliff:g>) bude pracovný profil odstránený a spolu s ním všetky údaje profilu."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Tablet ste sa pokúsili <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%2$d</xliff:g>) bude pracovný profil odstránený a spolu s ním všetky údaje profilu."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Telefón ste sa pokúsili <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%2$d</xliff:g>) bude pracovný profil odstránený a spolu s ním všetky údaje profilu."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Tablet ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Pracovný profil bude odstránený spolu so všetkými údajmi."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Telefón ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Pracovný profil bude odstránený spolu so všetkými údajmi."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po ďalších <xliff:g id="NUMBER_1">%d</xliff:g> neúspešných pokusoch sa zobrazí výzva na odomknutie tabletu pomocou e-mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie telefónu pomocou e-mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%1$d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po ďalších <xliff:g id="NUMBER_1">%2$d</xliff:g> neúspešných pokusoch sa zobrazí výzva na odomknutie tabletu pomocou e-mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%1$d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie telefónu pomocou e-mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Nesprávny kód PIN SIM karty. Teraz musíte kontaktovať svojho operátora, aby vám odomkol zariadenie."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="few">Nesprávny kód PIN SIM karty. Zostávajú vám <xliff:g id="NUMBER_1">%d</xliff:g> pokusy.</item>
@@ -114,15 +114,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Režim v lietadle"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Pri reštartovaní zariadenia sa vyžaduje bezpečnostný vzor."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Pri reštartovaní zariadenia sa vyžaduje kód PIN."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Pri reštartovaní zariadenia sa vyžaduje heslo."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Na ďalšie zabezpečenie sa vyžaduje vzor."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Na ďalšie zabezpečenie sa vyžaduje kód PIN."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Na ďalšie zabezpečenie sa vyžaduje heslo."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Po prepnutí profilov sa vyžaduje bezpečnostný vzor."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Po prepnutí profilov sa vyžaduje kód PIN."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Po prepnutí profilov sa vyžaduje heslo."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Po reštartovaní zariadenia musíte zadať heslo"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Na ďalšie zabezpečenie musíte zadať bezpečnostný vzor"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Na ďalšie zabezpečenie musíte zadať kód PIN"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Na ďalšie zabezpečenie musíte zadať heslo"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Po prepnutí profilov musíte zadať bezpečnostný vzor"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Po prepnutí profilov musíte zadať kód PIN"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Po prepnutí profilov musíte zadať heslo"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="few">Zariadenie nebolo odomknuté <xliff:g id="NUMBER_1">%d</xliff:g> hodiny. Potvrďte vzor.</item>
       <item quantity="many">Zariadenie nebolo odomknuté <xliff:g id="NUMBER_1">%d</xliff:g> hodiny. Potvrďte vzor.</item>
diff --git a/packages/Keyguard/res/values-sl/strings.xml b/packages/Keyguard/res/values-sl/strings.xml
index 41dde2c..83a6e49 100644
--- a/packages/Keyguard/res/values-sl/strings.xml
+++ b/packages/Keyguard/res/values-sl/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Vnovič vnesite pravilno kodo PUK. Večkratni poskusi bodo trajno onemogočili kartico SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kodi PIN se ne ujemata"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Preveč poskusov vzorca"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat vnesli napačno. \n\nZnova poskusite čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Geslo ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat vnesli napačno. \n\nZnova poskusite čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Vzorec za odklepanje ste nepravilno narisali <xliff:g id="NUMBER_0">%d</xliff:g>-krat. \n\nPoskusite znova čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%d</xliff:g>-krat, bo ponastavljen, zaradi česar bodo izbrisani vsi podatki v njem."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%d</xliff:g>-krat, bo ponastavljen, zaradi česar bodo izbrisani vsi podatki v njem."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat vnesli napačno. \n\nZnova poskusite čez <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Geslo ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat vnesli napačno. \n\nZnova poskusite čez <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Vzorec za odklepanje ste nepravilno narisali <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. \n\nPoskusite znova čez <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, bo ponastavljen, zaradi česar bodo izbrisani vsi podatki v njem."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, bo ponastavljen, zaradi česar bodo izbrisani vsi podatki v njem."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat, zato bo ponastavljen, vsi podatki v njem pa bodo izbrisani."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat, zato bo ponastavljen, vsi podatki v njem pa bodo izbrisani."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%d</xliff:g>-krat, bo ta uporabnik odstranjen, zaradi česar bodo izbrisani vsi podatki uporabnika."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%d</xliff:g>-krat, bo ta uporabnik odstranjen, zaradi česar bodo izbrisani vsi podatki uporabnika."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, bo ta uporabnik odstranjen, zaradi česar bodo izbrisani vsi podatki uporabnika."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, bo ta uporabnik odstranjen, zaradi česar bodo izbrisani vsi podatki uporabnika."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat. Ta uporabnik bo odstranjen, zaradi česar bodo izbrisani vsi podatki uporabnika."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat. Ta uporabnik bo odstranjen, zaradi česar bodo izbrisani vsi podatki uporabnika."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%d</xliff:g>-krat, bo delovni profil odstranjen, zaradi česar bodo izbrisani vsi podatki profila."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%d</xliff:g>-krat, bo delovni profil odstranjen, zaradi česar bodo izbrisani vsi podatki profila."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, bo delovni profil odstranjen, zaradi česar bodo izbrisani vsi podatki profila."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, bo delovni profil odstranjen, zaradi česar bodo izbrisani vsi podatki profila."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat. Delovni profil bo odstranjen, zaradi česar bodo izbrisani vsi podatki profila."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat. Delovni profil bo odstranjen, zaradi česar bodo izbrisani vsi podatki profila."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da tablični računalnik odklenete z e-poštnim računom.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da odklenete telefon z Googlovimi podatki za prijavo.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešnih poskusih boste pozvani, da tablični računalnik odklenete z e-poštnim računom.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešnih poskusih boste pozvani, da odklenete telefon z Googlovimi podatki za prijavo.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Napačna koda PIN kartice SIM. Zdaj se boste morali za odklenitev naprave obrniti na operaterja."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">Napačna koda PIN kartice SIM. Na voljo imate še <xliff:g id="NUMBER_1">%d</xliff:g> poskus.</item>
@@ -114,15 +114,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Način za letalo"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Po vnovičnem zagonu je treba vnesti vzorec."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Po vnovičnem zagonu je treba vnesti kodo PIN."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Po vnovičnem zagonu je treba vnesti geslo."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Zaradi dodatne varnosti morate vnesti vzorec."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Zaradi dodatne varnosti morate vnesti kodo PIN."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Zaradi dodatne varnosti morate vnesti geslo."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Po preklopu profilov je treba vnesti vzorec."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Po preklopu profilov je treba vnesti kodo PIN."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Po preklopu profilov je treba vnesti geslo."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Po vnovičnem zagonu naprave je treba vnesti geslo"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Zaradi dodatne varnosti morate vnesti vzorec"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Zaradi dodatne varnosti morate vnesti kodo PIN"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Zaradi dodatne varnosti morate vnesti geslo"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Po preklopu profilov je treba vnesti vzorec"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Po preklopu profilov je treba vnesti kodo PIN"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Po preklopu profilov je treba vnesti geslo"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="one">Naprava ni bila odklenjena <xliff:g id="NUMBER_1">%d</xliff:g> uro. Potrdite vzorec.</item>
       <item quantity="two">Naprava ni bila odklenjena <xliff:g id="NUMBER_1">%d</xliff:g> uri. Potrdite vzorec.</item>
diff --git a/packages/Keyguard/res/values-sq-rAL/strings.xml b/packages/Keyguard/res/values-sq-rAL/strings.xml
index 31ed223..4cd2692 100644
--- a/packages/Keyguard/res/values-sq-rAL/strings.xml
+++ b/packages/Keyguard/res/values-sq-rAL/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Fut kodin e saktë PUK. Provat e përsëritura do ta çaktivizojnë përgjithmonë kartën SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kodet PIN nuk përputhen"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Shumë tentativa për motivin"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"E ke shkruar <xliff:g id="NUMBER_0">%d</xliff:g> herë gabimisht PIN-in tënd.\n\n Provo sërish për <xliff:g id="NUMBER_1">%d</xliff:g> sekonda."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"E ke shkruar <xliff:g id="NUMBER_0">%d</xliff:g> herë gabimisht fjalëkalimin.\n\nProvo sërish për <xliff:g id="NUMBER_1">%d</xliff:g> sekonda."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Ke tentuar <xliff:g id="NUMBER_0">%d</xliff:g> herë pa sukses për të vizatuar motivin tënd. \n\nProvo sërish për <xliff:g id="NUMBER_1">%d</xliff:g> sekonda."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Ke tentuar <xliff:g id="NUMBER_0">%d</xliff:g> herë pa sukses për ta shkyçur tabletin. Pas <xliff:g id="NUMBER_1">%d</xliff:g> tentativave të tjera të pasuksesshme, tableti do të rivendoset si në gjendjen e fabrikës dhe kjo do t\'i fshijë të gjitha të dhënat."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Ke tentuar <xliff:g id="NUMBER_0">%d</xliff:g> herë gabimisht për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%d</xliff:g> përpjekjeve të tjera të pasuksesshme, telefoni do të rivendoset dhe të gjitha të dhënat do të fshihen."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"E ke shkruar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë gabimisht PIN-in tënd.\n\n Provo sërish për <xliff:g id="NUMBER_1">%2$d</xliff:g> sekonda."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"E ke shkruar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë gabimisht fjalëkalimin.\n\nProvo sërish për <xliff:g id="NUMBER_1">%2$d</xliff:g> sekonda."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses për të vizatuar motivin tënd. \n\nProvo sërish për <xliff:g id="NUMBER_1">%2$d</xliff:g> sekonda."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses për ta shkyçur tabletin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, tableti do të rivendoset si në gjendjen e fabrikës dhe kjo do t\'i fshijë të gjitha të dhënat."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë gabimisht për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> përpjekjeve të tjera të pasuksesshme, telefoni do të rivendoset dhe të gjitha të dhënat do të fshihen."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur tabletin tënd. Ky tablet do të rivendoset dhe të gjitha të dhënat në të, do të fshihen."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur telefonin tënd. Ky telefon do të rivendoset dhe të gjitha të dhënat në të, do të fshihen."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Ke tentuar <xliff:g id="NUMBER_0">%d</xliff:g> herë pa sukses për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%d</xliff:g> tentativave të tjera të pasuksesshme, përdoruesi do të hiqet dhe të gjitha të dhënat e përdoruesit në të, do të fshihen."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Ke tentuar <xliff:g id="NUMBER_0">%d</xliff:g> herë pa sukses për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%d</xliff:g> tentativave të tjera të pasuksesshme, përdoruesi do të hiqet dhe të gjitha të dhënat e përdoruesit në të, do të fshihen."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, përdoruesi do të hiqet dhe të gjitha të dhënat e përdoruesit në të, do të fshihen."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, përdoruesi do të hiqet dhe të gjitha të dhënat e përdoruesit në të, do të fshihen."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur tabletin. Ky përdorues do të hiqet dhe kjo do t fshijë të gjitha të dhënat e përdoruesit."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur telefonin. Ky përdorues do të hiqet dhe kjo do t\'i fshijë të gjitha të dhënat e përdoruesit."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Ke tentuar <xliff:g id="NUMBER_0">%d</xliff:g> herë pa sukses për ta shkyçur tabletin. Pas <xliff:g id="NUMBER_1">%d</xliff:g> tentativave të tjera të pasuksesshme, profili i punës do të hiqet dhe të gjitha të dhënat në të do të fshihen."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Ke tentuar <xliff:g id="NUMBER_0">%d</xliff:g> herë pa sukses për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%d</xliff:g> tentativave të tjera të pasuksesshme, profili i punës do të hiqet dhe të gjitha të dhënat në të do të fshihen."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses për ta shkyçur tabletin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, profili i punës do të hiqet dhe të gjitha të dhënat në të do të fshihen."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, profili i punës do të hiqet dhe të gjitha të dhënat në të do të fshihen."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur tabletin. Profili i punës do të hiqet të gjitha të dhënat në të, do të fshihen."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur telefonin. Profili i punës do të hiqet të gjitha të dhënat në të, do të fshihen."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"E ke vizatuar gabimisht motivin tënd të shkyçjes <xliff:g id="NUMBER_0">%d</xliff:g> herë. Pas <xliff:g id="NUMBER_1">%d</xliff:g> tentativave të tjera të pasuksesshme do të të kërkohet ta shkyçësh tabletin duke përdorur një llogari mail-i.\n\n Provo sërish për <xliff:g id="NUMBER_2">%d</xliff:g> sekonda."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ke vizatuar <xliff:g id="NUMBER_0">%d</xliff:g> herë pa sukses motivin tënd. Pas <xliff:g id="NUMBER_1">%d</xliff:g> tentativave të tjera të pasuksesshme, do të të duhet ta shkyçësh telefonin duke përdorur një llogari mail-i.\n\n Provo sërish për <xliff:g id="NUMBER_2">%d</xliff:g> sekonda."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"E ke vizatuar gabimisht motivin tënd të shkyçjes <xliff:g id="NUMBER_0">%1$d</xliff:g> herë. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme do të të kërkohet ta shkyçësh tabletin duke përdorur një llogari mail-i.\n\n Provo sërish për <xliff:g id="NUMBER_2">%3$d</xliff:g> sekonda."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ke vizatuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses motivin tënd. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, do të të duhet ta shkyçësh telefonin duke përdorur një llogari mail-i.\n\n Provo sërish për <xliff:g id="NUMBER_2">%3$d</xliff:g> sekonda."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"PIN-i i kartës SIM është i pasaktë. Tani duhet të kontaktosh operatorin për ta shkyçur pajisjen tënde."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">PIN-i i kartës SIM është i pasaktë. Të kanë mbetur edhe <xliff:g id="NUMBER_1">%d</xliff:g> tentativa.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Modaliteti i aeroplanit"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Kërkohet motivi kur rinis pajisjen."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Kërkohet kodi PIN kur rinis pajisjen."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Kërkohet fjalëkalimi kur rinis pajisjen."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Kërkohet motivi për më shumë siguri."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Kërkohet kodi PIN për më shumë siguri."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Kërkohet fjalëkalimi për më shumë siguri."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Kërkohet motivi kur ndryshon profilet."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Kërkohet kodi PIN kur ndryshon profilet."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Kërkohet fjalëkalimi kur ndryshon profilet."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Kërkohet fjalëkalimi pas rinisjes së pajisjes"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Kërkohet motivi për më shumë siguri"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Kërkohet kodi PIN për më shumë siguri"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Kërkohet fjalëkalimi për më shumë siguri"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Kërkohet motivi kur ndryshon profilet"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Kërkohet kodi PIN kur ndryshon profilet"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Kërkohet fjalëkalimi kur ndryshon profilet"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">Pajisja nuk është shkyçur për <xliff:g id="NUMBER_1">%d</xliff:g> orë. Konfirmo motivin.</item>
       <item quantity="one">Pajisja nuk është shkyçur për <xliff:g id="NUMBER_0">%d</xliff:g> orë. Konfirmo motivin.</item>
diff --git a/packages/Keyguard/res/values-sr/strings.xml b/packages/Keyguard/res/values-sr/strings.xml
index feb18be..fa6bc09 100644
--- a/packages/Keyguard/res/values-sr/strings.xml
+++ b/packages/Keyguard/res/values-sr/strings.xml
@@ -77,23 +77,23 @@
     <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">%d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Унели сте нетачну лозинку <xliff:g id="NUMBER_0">%d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER_0">%d</xliff:g> пут(а). Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај(а), након чега се таблет ресетује и сви подаци са њега бришу."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%d</xliff:g> пут(а). Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај(а), након чега се телефон ресетује и сви подаци са њега бришу."</string>
+    <string name="kg_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">"Нацртали сте шаблон за откључавање нетачно <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">%d</xliff:g> пут(а). Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај(а), након чега се овај корисник уклања и сви подаци корисника бришу."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%d</xliff:g> пут(а). Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај(а), након чега се овај корисник уклања и сви подаци корисника бришу."</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> пут(а). Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај(а), након чега се пословни профил уклања и сви подаци са профила бришу."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%d</xliff:g> пут(а). Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај(а), након чега се пословни профил уклања и сви подаци са профила бришу."</string>
+    <string name="kg_failed_attempts_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">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу налога е-поште.\n\nПокушајте поново за <xliff:g id="NUMBER_2">%d</xliff:g> секунде(и)."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу налога е-поште.\n\nПокушајте поново за <xliff:g id="NUMBER_2">%d</xliff:g> секунде(и)."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу налога е-поште.\n\nПокушајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу налога е-поште.\n\nПокушајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Нетачан SIM PIN кôд. Сада морате да контактирате мобилног оператера да бисте откључали уређај."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">Нетачан SIM PIN кôд. Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај.</item>
@@ -112,15 +112,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Офлајн сте."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Дугме Промени метод уноса."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Режим рада у авиону"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Шаблон је обавезан када поново покрећете уређај."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"PIN је обавезан када поново покрећете уређај."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Лозинка је обавезна када поново покрећете уређај."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Потребан је шаблон ради додатне безбедности."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Потребан је PIN ради додатне безбедности."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Потребна је лозинка ради додатне безбедности."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Шаблон је обавезан када прелазите са једног профила на други."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"PIN је обавезан када прелазите са једног профила на други."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Лозинка је обавезна када прелазите са једног профила на други."</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>
diff --git a/packages/Keyguard/res/values-sv/strings.xml b/packages/Keyguard/res/values-sv/strings.xml
index 28bcf98..10b5991 100644
--- a/packages/Keyguard/res/values-sv/strings.xml
+++ b/packages/Keyguard/res/values-sv/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Ange rätt PUK-kod igen. Om försöken upprepas inaktiveras SIM-kortet permanent."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-koderna stämmer inte överens"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"För många försök med grafiskt lösenord"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> misslyckade försök till återställs surfplattan och all data raderas."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> misslyckade försök till återställs mobilen och all data raderas."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%2$d</xliff:g> misslyckade försök till återställs surfplattan och all data raderas."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%2$d</xliff:g> misslyckade försök till återställs mobilen och all data raderas."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Surfplattan återställs och all data raderas."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Mobilen återställs och all data raderas."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> misslyckade försök till tas användaren bort och all användardata raderas."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> misslyckade försök till tas användaren bort och all användardata raderas."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%2$d</xliff:g> misslyckade försök till tas användaren bort och all användardata raderas."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%2$d</xliff:g> misslyckade försök till tas användaren bort och all användardata raderas."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Användaren tas bort och all användardata raderas."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Användaren tas bort och all användardata raderas."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> misslyckade försök till tas jobbprofilen bort och all profildata raderas."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> misslyckade försök till tas jobbprofilen bort och all profildata raderas."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%2$d</xliff:g> misslyckade försök till tas jobbprofilen bort och all profildata raderas."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%2$d</xliff:g> misslyckade försök till tas jobbprofilen bort och all profildata raderas."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Jobbprofilen tas bort och all profildata raderas."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Jobbprofilen tas bort och all profildata raderas."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> försök ombeds du låsa upp surfplattan med ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> försök ombeds du låsa upp mobilen med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök ombeds du låsa upp surfplattan med ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök ombeds du låsa upp mobilen med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Du angav fel pinkod för SIM-kortet och måste nu kontakta operatören för att låsa upp enheten."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">Du angav fel pinkod för SIM-kortet. <xliff:g id="NUMBER_1">%d</xliff:g> försök återstår.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Flygplansläge"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Du måste ange grafiskt lösenord när du startar om enheten."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Du måste ange pinkod när du startar om enheten."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Du måste ange lösenord när du startar om enheten."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Mönster krävs för ytterligare säkerhet."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Pinkod krävs för ytterligare säkerhet."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Lösenord krävs för ytterligare säkerhet."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Du måste ange grafiskt lösenord när du byter profil."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Du måste ange pinkod när du byter profil."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Du måste ange lösenord när du byter profil."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Du måste ange lösenord när du startat om enheten"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Du måste ange grafiskt lösenord för ytterligare säkerhet"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Du måste ange pinkod för ytterligare säkerhet"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Du måste ange lösenord för ytterligare säkerhet"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Du måste ange grafiskt lösenord när du byter profil"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Du måste ange pinkod när du byter profil"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Du måste ange lösenord när du byter profil"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">Enheten har inte låsts upp på <xliff:g id="NUMBER_1">%d</xliff:g> timmar. Bekräfta det grafiska lösenordet.</item>
       <item quantity="one">Enheten har inte låsts upp på <xliff:g id="NUMBER_0">%d</xliff:g> timme. Bekräfta det grafiska lösenordet.</item>
diff --git a/packages/Keyguard/res/values-sw/strings.xml b/packages/Keyguard/res/values-sw/strings.xml
index bd8c68e..77eaf2a 100644
--- a/packages/Keyguard/res/values-sw/strings.xml
+++ b/packages/Keyguard/res/values-sw/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Ingiza upya msimbo sahihi wa PUK. Majaribio yanayorudiwa yatalemaza SIM kabisa."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Misimbo ya PIN haifanani"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Majaribio mengi mno ya mchoro"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Umeingiza nenosiri lako kwa makosa mara <xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Umeingiza nenosiri lako kwa makosa mara <xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Umechora ruwaza yako ya kufunga kwa makosa mara <xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Umekosea majaribio ya kufungua kompyuta kibao mara <xliff:g id="NUMBER_0">%d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%d</xliff:g>, kompyuta hii kibao itarejeshwa katika hali iliyotoka nayo kiwandani, hatua itakayofuta data yake yote."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Umekosea majaribio ya kufungua simu mara <xliff:g id="NUMBER_0">%d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%d</xliff:g>, simu hii itawekwa upya, hatua itakayofuta data yake yote."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Umeingiza nenosiri lako kwa makosa mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Umeingiza nenosiri lako kwa makosa mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Umechora ruwaza yako ya kufunga kwa makosa mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Umekosea majaribio ya kufungua kompyuta kibao mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%2$d</xliff:g>, kompyuta hii kibao itarejeshwa katika hali iliyotoka nayo kiwandani, hatua itakayofuta data yake yote."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Umekosea majaribio ya kufungua simu mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%2$d</xliff:g>, simu hii itawekwa upya, hatua itakayofuta data yake yote."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Umekosea majaribio ya kufungua kompyuta kibao mara <xliff:g id="NUMBER">%d</xliff:g>. Kompyuta hii kibao itarejeshwa katika hali iliyotoka nayo kiwandani, hatua itakayofuta data yake yote."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Umekosea majaribio ya kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g>. Simu hii itarejeshwa katika hali iliyotoka nayo kiwandani, hatua itakayofuta data yake yote."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Umekosea majaribio ya kufungua kompyuta kibao mara <xliff:g id="NUMBER_0">%d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%d</xliff:g>, mtumiaji huyu ataondolewa, hatua itakayofuta data yote ya mtumiaji."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Umekosea majaribio ya kufungua simu mara <xliff:g id="NUMBER_0">%d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%d</xliff:g>, wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Umekosea majaribio ya kufungua kompyuta kibao mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%2$d</xliff:g>, mtumiaji huyu ataondolewa, hatua itakayofuta data yote ya mtumiaji."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Umekosea majaribio ya kufungua simu mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%2$d</xliff:g>, wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Umekosea majaribio ya kufungua kompyuta kibao mara <xliff:g id="NUMBER">%d</xliff:g>. Mtumiaji huyu ataondolewa, hatua itakayofuta data yote ya mtumiaji."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Umekosea majaribio ya kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g>. Mtumiaji huyu ataondolewa, hatua itakayofuta data yote ya mtumiaji."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Umekosea majaribio ya kufungua kompyuta kibao mara <xliff:g id="NUMBER_0">%d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%d</xliff:g>, wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Umekosea majaribio ya kufungua simu mara <xliff:g id="NUMBER_0">%d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%d</xliff:g>, wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Umekosea majaribio ya kufungua kompyuta kibao mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%2$d</xliff:g>, wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Umekosea majaribio ya kufungua simu mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%2$d</xliff:g>, wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Umekosea majaribio ya kufungua kompyuta kibao mara <xliff:g id="NUMBER">%d</xliff:g>. Wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Umekosea majaribio ya kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g>. Wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Umekosea katika kuweka mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> bila kufaulu, utaombwa kufungua kompyuta yako ndogo kwa kutumia akaunti yako ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> yasiyofaulu, utaombwa kufungua simu yako kwa kutumia akaunti ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Umekosea katika kuweka mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%2$d</xliff:g> bila kufaulu, utaombwa kufungua kompyuta yako ndogo kwa kutumia akaunti yako ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%2$d</xliff:g> yasiyofaulu, utaombwa kufungua simu yako kwa kutumia akaunti ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Msimbo wa PIN ya SIM usiosahihi sasa lazima uwasiliane na mtoa huduma wako ili ufungue kifaa chako."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">Msimbo wa PIN ya SIM si sahihi, umebakisha majaribio <xliff:g id="NUMBER_1">%d</xliff:g>.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Hali ya ndegeni"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Mchoro unahitajika unapoanzisha kifaa upya."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"PIN inahitajika unapoanzisha kifaa upya."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Nenosiri linahitajika unapoanzisha kifaa upya."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Mchoro unatakikana ili kuongeza usalama."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"PIN inatakikana ili kuongeza usalama."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Nenosiri linahitajika ili kuongeza usalama."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Mchoro unahitajika unapobadili wasifu."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"PIN inahitajika unapobadili wasifu."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Nenosiri linahitajika unapobadili wasifu."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Nenosiri linahitajika baada ya kuanzisha kifaa upya"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Mchoro unatakikana ili kuongeza usalama"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"PIN inatakikana ili kuongeza usalama"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Nenosiri linatakikana ili kuongeza usalama"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Mchoro unahitajika unapobadili wasifu"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"PIN inahitajika unapobadili wasifu"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Nenosiri linahitajika unapobadili wasifu"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">Kifaa hakijafunguliwa kwa saa <xliff:g id="NUMBER_1">%d</xliff:g>. Thibitisha mchoro.</item>
       <item quantity="one">Kifaa hakijafunguliwa kwa saa <xliff:g id="NUMBER_0">%d</xliff:g>. Thibitisha mchoro.</item>
diff --git a/packages/Keyguard/res/values-ta-rIN/strings.xml b/packages/Keyguard/res/values-ta-rIN/strings.xml
index 32c93b0..5ddad8c 100644
--- a/packages/Keyguard/res/values-ta-rIN/strings.xml
+++ b/packages/Keyguard/res/values-ta-rIN/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"சரியான PUK குறியீட்டை மீண்டும் உள்ளிடவும். தொடர் முயற்சிகள் சிம் ஐ நிரந்தரமாக முடக்கிவிடும்."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"பின் குறியீடுகள் பொருந்தவில்லை"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"அதிகமான வடிவ முயற்சிகள்"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"உங்கள் பின்னை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக உள்ளிட்டீர்கள். \n\n<xliff:g id="NUMBER_1">%d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"உங்கள் கடவுச்சொல்லை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக உள்ளிட்டீர்கள். \n\n<xliff:g id="NUMBER_1">%d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"திறப்பதற்கான வடிவத்தை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக வரைந்துள்ளீர்கள். \n\n<xliff:g id="NUMBER_1">%d</xliff:g> வினாடிகளில் மீண்டும் முயற்சிக்கவும்."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக முயற்சித்துள்ளீர்கள். இன்னும் <xliff:g id="NUMBER_1">%d</xliff:g> முறை தவறாக முயற்சித்தால், டேப்லெட் மீட்டமைக்கப்படும், அத்துடன் இதன் எல்லா தரவும் நீக்கப்படும்."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"மொபைலைத் திறக்க, <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக முயற்சித்துள்ளீர்கள். இன்னும் <xliff:g id="NUMBER_1">%d</xliff:g> முறை தவறாக முயற்சித்தால் மொபைல் மீட்டமைக்கப்படும், அத்துடன் இதன் எல்லா தரவும் நீக்கப்படும்."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"உங்கள் பின்னை <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">"திறப்பதற்கான வடிவத்தை <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">%d</xliff:g> முறை தவறாக முயற்சித்துள்ளீர்கள். இன்னும் <xliff:g id="NUMBER_1">%d</xliff:g> முறை தவறாக முயற்சித்தால் இந்தப் பயனர் அகற்றப்படுவார், அத்துடன் அவரின் எல்லா தரவும் நீக்கப்படும்."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"மொபைலைத் திறக்க, <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக முயற்சித்துள்ளீர்கள். இன்னும் <xliff:g id="NUMBER_1">%d</xliff:g> முறை தவறாக முயற்சித்தால் இந்தப் பயனர் அகற்றப்படுவார், அத்துடன் அவரின் எல்லா தரவும் நீக்கப்படும்."</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> முறை தவறாக முயற்சித்துள்ளீர்கள். இன்னும் <xliff:g id="NUMBER_1">%d</xliff:g> முறை தவறாக முயற்சித்தால், பணி சுயவிவரம் அகற்றப்படும், அத்துடன் சுயவிவரத்தின் எல்லா தரவும் நீக்கப்படும்."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"மொபைலைத் திறக்க <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக முயற்சித்துள்ளீர்கள். இன்னும் <xliff:g id="NUMBER_1">%d</xliff:g> முறை தவறாக முயற்சித்தால் பணி சுயவிவரம் அகற்றப்படும், அத்துடன் சுயவிவரத்தின் எல்லா தரவும் நீக்கப்படும்."</string>
+    <string name="kg_failed_attempts_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">"திறப்பதற்கான வடிவத்தை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக வரைந்துள்ளீர்கள். மேலும் <xliff:g id="NUMBER_1">%d</xliff:g> தோல்வி முயற்சிகளுக்குப் பிறகு, மின்னஞ்சல் கணக்கைப் பயன்படுத்தி உங்கள் டேப்லெட்டைத் திறக்க கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> வினாடிகளில் மீண்டும் முயற்சிக்கவும்."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"திறப்பதற்கான வடிவத்தை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக வரைந்துள்ளீர்கள். மேலும் <xliff:g id="NUMBER_1">%d</xliff:g> தோல்வி முயற்சிகளுக்குப் பிறகு, மின்னஞ்சல் கணக்கைப் பயன்படுத்தி உங்கள் மொபைலைத் திறக்கக் கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"திறப்பதற்கான வடிவத்தை <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக வரைந்துள்ளீர்கள். மேலும் <xliff:g id="NUMBER_1">%2$d</xliff:g> தோல்வி முயற்சிகளுக்குப் பிறகு, மின்னஞ்சல் கணக்கைப் பயன்படுத்தி உங்கள் டேப்லெட்டைத் திறக்க கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> வினாடிகளில் மீண்டும் முயற்சிக்கவும்."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"திறப்பதற்கான வடிவத்தை <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக வரைந்துள்ளீர்கள். மேலும் <xliff:g id="NUMBER_1">%2$d</xliff:g> தோல்வி முயற்சிகளுக்குப் பிறகு, மின்னஞ்சல் கணக்கைப் பயன்படுத்தி உங்கள் மொபைலைத் திறக்கக் கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"சிம் பின் குறியீடு தவறானது, உங்கள் சாதனத்தின் தடையை நீக்க, உங்கள் மொபைல் நிறுவனத்தைத் தொடர்புகொள்ள வேண்டும்."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">சிம்மின் பின் குறியீடு தவறானது, உங்களிடம் <xliff:g id="NUMBER_1">%d</xliff:g> முயற்சிகள் மீதமுள்ளன.</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"சேவை இல்லை."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"உள்ளீட்டு முறையை மாற்றும் பொத்தான்."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"விமானப் பயன்முறை"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"சாதனத்தை மீண்டும் தொடங்கும் போது, வடிவம் தேவை."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"சாதனத்தை மீண்டும் தொடங்கும் போது, பின் தேவை."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"சாதனத்தை மீண்டும் தொடங்கும் போது, கடவுச்சொல் தேவை."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"கூடுதல் பாதுகாப்பிற்கு வடிவம் தேவை."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"கூடுதல் பாதுகாப்பிற்கு PIN தேவை."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"கூடுதல் பாதுகாப்பிற்குக் கடவுச்சொல் தேவை."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"சுயவிவரங்களுக்கு இடையே மாறும் போது, வடிவம் தேவை."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"சுயவிவரங்களுக்கு இடையே மாறும் போது, பின் தேவை."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"சுயவிவரங்களுக்கு இடையே மாறும் போது, கடவுச்சொல் தேவை."</string>
+    <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"சாதனத்தை மீண்டும் தொடங்கியதும் வடிவத்தை வரைய வேண்டும்"</string>
+    <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"சாதனத்தை மீண்டும் தொடங்கியதும் பின்னை உள்ளிட வேண்டும்"</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">"கூடுதல் பாதுகாப்பிற்குப் பின்னை உள்ளிட வேண்டும்"</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">"சுயவிவரங்களுக்கு இடையே மாறும் போது, பின்னை உள்ளிட வேண்டும்"</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="other"><xliff:g id="NUMBER_1">%d</xliff:g> மணிநேரமாகச் சாதனம் திறக்கப்படவில்லை. வடிவத்தை உறுதிப்படுத்தவும்.</item>
       <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> மணிநேரமாகச் சாதனம் திறக்கப்படவில்லை. வடிவத்தை உறுதிப்படுத்தவும்.</item>
diff --git a/packages/Keyguard/res/values-te-rIN/strings.xml b/packages/Keyguard/res/values-te-rIN/strings.xml
index e27f5a9..e10490c 100644
--- a/packages/Keyguard/res/values-te-rIN/strings.xml
+++ b/packages/Keyguard/res/values-te-rIN/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"సరైన PUK కోడ్‌ను మళ్లీ నమోదు చేయండి. పునరావృత ప్రయత్నాల వలన సిమ్ శాశ్వతంగా నిలిపివేయబడుతుంది."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"పిన్‌ కోడ్‌లు సరిపోలలేదు"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"చాలా ఎక్కువ నమూనా ప్రయత్నాలు చేసారు"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"మీరు మీ పిన్‌ను <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు తప్పుగా టైప్ చేసారు. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"మీరు మీ పాస్‌వర్డ్‌ను <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు తప్పుగా టైప్ చేసారు. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు తప్పుగా గీసారు. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%d</xliff:g> ప్రయత్నాలు విఫలమైతే, ఈ టాబ్లెట్ రీసెట్ చేయబడుతుంది, ఇందువల్ల ఇందులోని మొత్తం డేటా తొలగించబడుతుంది."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%d</xliff:g> ప్రయత్నాలు విఫలమైతే, ఈ ఫోన్ రీసెట్ చేయబడుతుంది, ఇందువల్ల ఇందులోని మొత్తం డేటా తొలగించబడుతుంది."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"మీరు మీ పిన్‌ను <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">"మీరు మీ అన్‌లాక్ నమూనాను <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">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%d</xliff:g> ప్రయత్నాలు విఫలమైతే, ఈ వినియోగదారు తీసివేయబడతారు, ఇందువల్ల మొత్తం వినియోగదారు డేటా తొలగించబడుతుంది."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%d</xliff:g> ప్రయత్నాలు విఫలమైతే, ఈ వినియోగదారు తీసివేయబడతారు, ఇందువల్ల మొత్తం వినియోగదారు డేటా తొలగించబడుతుంది."</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%d</xliff:g> ప్రయత్నాలు విఫలమైతే, కార్యాలయ ప్రొఫైల్ తీసివేయబడుతుంది, ఇందువల్ల మొత్తం ప్రొఫైల్ డేటా తొలగించబడుతుంది."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%d</xliff:g> ప్రయత్నాలు విఫలమైతే, కార్యాలయ ప్రొఫైల్ తీసివేయబడుతుంది, ఇందువల్ల మొత్తం ప్రొఫైల్ డేటా తొలగించబడుతుంది."</string>
+    <string name="kg_failed_attempts_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">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఇమెయిల్ ఖాతాను ఉపయోగించి మీ టాబ్లెట్‌ను అన్‌లాక్ చేయాల్సిందిగా మిమ్మల్ని అడుగుతారు.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఇమెయిల్ ఖాతాను ఉపయోగించి మీ ఫోన్‌ను అన్‌లాక్ చేయాల్సిందిగా మిమ్మల్ని అడుగుతారు.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఇమెయిల్ ఖాతాను ఉపయోగించి మీ టాబ్లెట్‌ను అన్‌లాక్ చేయాల్సిందిగా మిమ్మల్ని అడుగుతారు.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఇమెయిల్ ఖాతాను ఉపయోగించి మీ ఫోన్‌ను అన్‌లాక్ చేయాల్సిందిగా మిమ్మల్ని అడుగుతారు.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"సిమ్ పిన్ కోడ్ చెల్లదు, మీరు ఇప్పుడు మీ పరికరాన్ని అన్‌లాక్ చేయడానికి తప్పనిసరిగా మీ క్యారియర్‌ను సంప్రదించండి."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">SIM PIN కోడ్ చెల్లదు, మీకు <xliff:g id="NUMBER_1">%d</xliff:g> ప్రయత్నాలు మిగిలి ఉన్నాయి.</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"సేవ లేదు."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ఇన్‌పుట్ పద్ధతి మార్చే బటన్."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"ఎయిర్‌ప్లైన్ మోడ్"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"మీరు పరికరాన్ని పునఃప్రారంభించినప్పుడు నమూనా అవసరం."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"మీరు పరికరాన్ని పునఃప్రారంభించినప్పుడు PIN అవసరం."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"మీరు పరికరాన్ని పునఃప్రారంభించినప్పుడు పాస్‌వర్డ్ అవసరం."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"అదనపు భద్రత కోసం నమూనా అవసరం."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"అదనపు భద్రత కోసం PIN అవసరం."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"అదనపు భద్రత కోసం పాస్‌వర్డ్ అవసరం."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"మీరు ప్రొఫైల్‌లను మార్చినప్పుడు నమూనా అవసరం."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"మీరు ప్రొఫైల్‌లను మార్చినప్పుడు PIN అవసరం."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"మీరు ప్రొఫైల్‌లను మార్చినప్పుడు పాస్‌వర్డ్ అవసరం."</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="other">పరికరం <xliff:g id="NUMBER_1">%d</xliff:g> గంటల పాటు అన్‌లాక్ చేయబడలేదు. నమూనాను నిర్ధారించండి.</item>
       <item quantity="one">పరికరం <xliff:g id="NUMBER_0">%d</xliff:g> గంట పాటు అన్‌లాక్ చేయబడలేదు. నమూనాను నిర్ధారించండి.</item>
diff --git a/packages/Keyguard/res/values-th/strings.xml b/packages/Keyguard/res/values-th/strings.xml
index 2629bfd..d3fe71e 100644
--- a/packages/Keyguard/res/values-th/strings.xml
+++ b/packages/Keyguard/res/values-th/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"ใส่รหัส PUK ที่ถูกต้องอีกครั้ง การพยายามซ้ำหลายครั้งจะทำให้ซิมการ์ดถูกปิดใช้งานอย่างถาวร"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"รหัส PIN ไม่ตรง"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ลองหลายรูปแบบมากเกินไป"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"คุณพิมพ์ PIN ไม่ถูกต้องไป <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว \n\nโปรดลองอีกครั้งใน <xliff:g id="NUMBER_1">%d</xliff:g> วินาที"</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"คุณพิมพ์รหัสผ่านไม่ถูกต้องไป <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว \n\nโปรดลองอีกครั้งใน <xliff:g id="NUMBER_1">%d</xliff:g> วินาที"</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้องไป <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว \n\nโปรดลองอีกครั้งใน <xliff:g id="NUMBER_1">%d</xliff:g> วินาที"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะรีเซ็ตแท็บเล็ตเครื่องนี้ ซึ่งจะเป็นการลบข้อมูลทั้งหมดในเครื่อง"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะรีเซ็ตโทรศัพท์เครื่องนี้ ซึ่งจะเป็นการลบข้อมูลทั้งหมดในเครื่อง"</string>
+    <string name="kg_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">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้องไป <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">%d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะนำผู้ใช้รายนี้ออก ซึ่งจะเป็นการลบข้อมูลผู้ใช้ทั้งหมด"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะนำผู้ใช้รายนี้ออก ซึ่งจะเป็นการลบข้อมูลผู้ใช้ทั้งหมด"</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะนำโปรไฟล์งานออก ซึ่งจะเป็นการลบข้อมูลโปรไฟล์ทั้งหมด"</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะนำโปรไฟล์งานออก ซึ่งจะเป็นการลบข้อมูลโปรไฟล์ทั้งหมด"</string>
+    <string name="kg_failed_attempts_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">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว หากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกแท็บเล็ตโดยใช้บัญชีอีเมล\n\n โปรดลองอีกครั้งใน <xliff:g id="NUMBER_2">%d</xliff:g> วินาที"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว หากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกโทรศัพท์โดยใช้ับัญชีอีเมล\n\n โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_2">%d</xliff:g> วินาที"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้งแล้ว หากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกแท็บเล็ตโดยใช้บัญชีอีเมล\n\n โปรดลองอีกครั้งใน <xliff:g id="NUMBER_2">%3$d</xliff:g> วินาที"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้งแล้ว หากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกโทรศัพท์โดยใช้ับัญชีอีเมล\n\n โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_2">%3$d</xliff:g> วินาที"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"รหัส PIN ของซิมไม่ถูกต้อง ตอนนี้คุณต้องติดต่อผู้ให้บริการเพื่อปลดล็อกอุปกรณ์ของคุณ"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">รหัส PIN ของซิมไม่ถูกต้อง คุณพยายามได้อีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ไม่มีบริการ"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ปุ่มสลับวิธีการป้อนข้อมูล"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"โหมดบนเครื่องบิน"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"ต้องใช้รูปแบบเมื่อคุณรีสตาร์ทอุปกรณ์"</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"ต้องใช้ PIN เมื่อคุณรีสตาร์ทอุปกรณ์"</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"ต้องใช้รหัสผ่านเมื่อคุณรีสตาร์ทอุปกรณ์"</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"ต้องใช้รูปแบบเพื่อความปลอดภัยเพิ่มเติม"</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"ต้องใช้ PIN เพื่อความปลอดภัยเพิ่มเติม"</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"ต้องใช้รหัสผ่านเพื่อความปลอดภัยเพิ่มเติม"</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"ต้องใช้รูปแบบเมื่อคุณเปลี่ยนโปรไฟล์"</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"ต้องใช้ PIN เมื่อคุณเปลี่ยนโปรไฟล์"</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"ต้องใช้รหัสผ่านเมื่อคุณเปลี่ยนโปรไฟล์"</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="other">ไม่มีการปลดล็อกอุปกรณ์เป็นเวลา <xliff:g id="NUMBER_1">%d</xliff:g> ชั่วโมง ยืนยันรูปแบบ</item>
       <item quantity="one">ไม่มีการปลดล็อกอุปกรณ์เป็นเวลา <xliff:g id="NUMBER_0">%d</xliff:g> ชั่วโมง ยืนยันรูปแบบ </item>
diff --git a/packages/Keyguard/res/values-tl/strings.xml b/packages/Keyguard/res/values-tl/strings.xml
index 8bfc6a6..6e6adec 100644
--- a/packages/Keyguard/res/values-tl/strings.xml
+++ b/packages/Keyguard/res/values-tl/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Muling ilagay ang tamang PUK code. Permanenteng hindi pagaganahin ang SIM ng mga paulit-ulit na pagtatangka."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Hindi tumutugma ang mga PIN code"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Masyadong maraming pagtatangka sa pattern"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Na-type mo nang hindi tama ang iyong PIN nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Na-type mo nang hindi tama ang iyong password nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"<xliff:g id="NUMBER_0">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagsubok, ire-reset ang tablet na ito, na magiging dahilan upang ma-delete ang lahat ng data nito."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"<xliff:g id="NUMBER_0">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagsubok, ire-reset ang teleponong ito, na magiging dahilan upang ma-delete ang lahat ng data nito."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Na-type mo nang hindi tama ang iyong PIN nang <xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%2$d</xliff:g> (na) segundo."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Na-type mo nang hindi tama ang iyong password nang <xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%2$d</xliff:g> (na) segundo."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%2$d</xliff:g> (na) segundo."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, ire-reset ang tablet na ito, na magiging dahilan upang ma-delete ang lahat ng data nito."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, ire-reset ang teleponong ito, na magiging dahilan upang ma-delete ang lahat ng data nito."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Ire-reset ang tablet na ito, na magiging dahilan upang ma-delete ang lahat ng data nito."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Ire-reset ang teleponong ito, na magiging dahilan upang ma-delete ang lahat ng data nito."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"<xliff:g id="NUMBER_0">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagsubok, aalisin ang user na ito, na magiging dahilan upang ma-delete ang lahat ng data ng user."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"<xliff:g id="NUMBER_0">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagsubok, aalisin ang user na ito, na magiging dahilan upang ma-delete ang lahat ng data ng user."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, aalisin ang user na ito, na magiging dahilan upang ma-delete ang lahat ng data ng user."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, aalisin ang user na ito, na magiging dahilan upang ma-delete ang lahat ng data ng user."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Aalisin ang user na ito, na magiging dahilan upang ma-delete ang lahat ng data ng user."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Aalisin ang user na ito, na magiging dahilan upang ma-delete ang lahat ng data ng user."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"<xliff:g id="NUMBER_0">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagsubok, aalisin ang profile sa trabaho, na magiging dahilan upang ma-delete ang lahat ng data sa profile."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"<xliff:g id="NUMBER_0">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling passowrd. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagsubok, aalisin ang profile sa trabaho, na magiging dahilan upang ma-delete ang lahat ng data sa profile."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, aalisin ang profile sa trabaho, na magiging dahilan upang ma-delete ang lahat ng data sa profile."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling passowrd. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, aalisin ang profile sa trabaho, na magiging dahilan upang ma-delete ang lahat ng data sa profile."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Aalisin ang profile sa trabaho, na magiging dahilan upang ma-delete ang lahat ng data sa profile."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Aalisin ang profile sa trabaho, na magiging dahilan upang ma-delete ang lahat ng data sa profile."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang tablet mo gamit ang isang email account.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang telepono mo gamit ang isang email account.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang tablet mo gamit ang isang email account.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%3$d</xliff:g> (na) segundo."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang telepono mo gamit ang isang email account.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%3$d</xliff:g> (na) segundo."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Maling PIN code ng SIM, dapat ka nang makipag-ugnay sa iyong carrier upang i-unlock ang iyong device."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">Maling PIN code ng SIM, mayroon kang <xliff:g id="NUMBER_1">%d</xliff:g> natitirang pagsubok.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Airplane mode"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Kinakailangan ang pattern kapag ni-restart mo ang device."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Kinakailangan ang PIN kapag ni-restart mo ang device."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Kinakailangan ang password kapag ni-restart mo ang device."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Kinakailangan ang pattern para sa karagdagang seguridad."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Kinakailangan ang PIN para sa karagdagang seguridad."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Kinakailangan ang password para sa karagdagang seguridad."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Kinakailangan ang pattern kapag lumipat ka ng mga profile."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Kinakailangan ang PIN kapag lumipat ka ng mga profile."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Kinakailangan ang password kapag lumipat ka ng mga profile."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Kinakailangan ang password pagkatapos mag-restart ng device"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Kinakailangan ang pattern para sa karagdagang seguridad"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Kinakailangan ang PIN para sa karagdagang seguridad"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Kinakailangan ang password para sa karagdagang seguridad"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Kinakailangan ang pattern kapag nagpalit ka ng profile"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Kinakailangan ang PIN kapag nagpalit ka ng profile"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Kinakailangan ang password kapag nagpalit ka ng profile"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="one">Hindi na-unlock ang device sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> oras.. Kumpirmahin ang pattern.</item>
       <item quantity="other">Hindi na-unlock ang device sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> na oras. Kumpirmahin ang pattern.</item>
diff --git a/packages/Keyguard/res/values-tr/strings.xml b/packages/Keyguard/res/values-tr/strings.xml
index 1e8a589a..46c3d00 100644
--- a/packages/Keyguard/res/values-tr/strings.xml
+++ b/packages/Keyguard/res/values-tr/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Doğru PUK kodunu tekrar girin. Çok sayıda deneme yapılırsa SIM kart kalıcı olarak devre dışı bırakılır."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodları eşleşmiyor"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Çok fazla sayıda desen denemesi yapıldı"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodunuzu <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış girdiniz. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Şifrenizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış yazdınız. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Tabletin kilidini <xliff:g id="NUMBER_0">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız deneme daha yaparsanız bu tablet sıfırlanacak ve tüm verileri silinecektir."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Telefonun kilidini <xliff:g id="NUMBER_0">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız deneme daha yaparsanız bu telefon sıfırlanacak ve tüm verileri silinecektir."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodunuzu <xliff:g id="NUMBER_0">%1$d</xliff:g> kez yanlış girdiniz. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Şifrenizi <xliff:g id="NUMBER_0">%1$d</xliff:g> kez yanlış yazdınız. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%1$d</xliff:g> kez yanlış çizdiniz. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Tabletin kilidini <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız bu tablet sıfırlanacak ve tüm verileri silinecektir."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Telefonun kilidini <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız bu telefon sıfırlanacak ve tüm verileri silinecektir."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Tabletin kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. Bu tablet sıfırlanacak ve tüm verileri silinecektir."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Telefonun kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. Bu telefon sıfırlanacak ve tüm verileri silinecektir."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Tabletin kilidini <xliff:g id="NUMBER_0">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız deneme daha yaparsanız bu kullanıcı kaldırılacak ve tüm kullanıcı verileri silinecektir."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Telefonun kilidini <xliff:g id="NUMBER_0">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız deneme daha yaparsanız bu kullanıcı kaldırılacak ve tüm kullanıcı verileri silinecektir."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Tabletin kilidini <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız bu kullanıcı kaldırılacak ve tüm kullanıcı verileri silinecektir."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Telefonun kilidini <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız bu kullanıcı kaldırılacak ve tüm kullanıcı verileri silinecektir."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Tabletin kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. Bu kullanıcı kaldırılacak ve tüm kullanıcı verileri silinecektir."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Telefonun kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. Bu kullanıcı kaldırılacak ve tüm kullanıcı verileri silinecektir."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Tabletin kilidini <xliff:g id="NUMBER_0">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız deneme daha yaparsanız iş profili kaldırılacak ve tüm profil verileri silinecektir."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Telefonun kilidini <xliff:g id="NUMBER_0">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız deneme daha yaparsanız iş profili kaldırılacak ve tüm profil verileri silinecektir."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Tabletin kilidini <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız iş profili kaldırılacak ve tüm profil verileri silinecektir."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Telefonun kilidini <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız iş profili kaldırılacak ve tüm profil verileri silinecektir."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Tabletin kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. İş profili kaldırılacak ve tüm profil verileri silinecektir."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Telefonun kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. İş profili kaldırılacak ve tüm profil verileri silinecektir."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra, tabletinizi bir e-posta hesabı kullanarak açmanız istenir.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra telefonunuzu bir e-posta hesabı kullanarak açmanız istenir.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%1$d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız denemeden sonra, tabletinizi bir e-posta hesabı kullanarak açmanız istenir.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%1$d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız denemeden sonra telefonunuzu bir e-posta hesabı kullanarak açmanız istenir.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniye içinde tekrar deneyin."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Yanlış SIM PIN kodu. Cihazınızın kilidini açmak için artık operatörünüzle bağlantı kurmanız gerekiyor."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">Yanlış SIM PIN kodu, <xliff:g id="NUMBER_1">%d</xliff:g> deneme hakkınız kaldı.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Uçak modu"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Cihazı yeniden başlattığınızda desen gerekir."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Cihazı yeniden başlattığınızda PIN gerekir."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Cihazı yeniden başlattığınızda şifre gerekir."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Ek güvenlik için desen gerekiyor."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Ek güvenlik için PIN gerekiyor."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Ek güvenlik için şifre gerekiyor."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Profil değiştirdiğinizde desen gerekir."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Profil değiştirdiğinizde PIN gerekir."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Profil değiştirdiğinizde şifre gerekir."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Cihaz yeniden başladıktan sonra şifre gerekir"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Ek güvenlik için desen gerekir"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Ek güvenlik için PIN gerekir"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Ek güvenlik için şifre gerekir"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Profil değiştirdiğinizde desen gerekir"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Profil değiştirdiğinizde PIN gerekir"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Profil değiştirdiğinizde şifre gerekir"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">Cihazın kilidi son <xliff:g id="NUMBER_1">%d</xliff:g> saattir açılmadı. Deseni doğrulayın.</item>
       <item quantity="one">Cihazın kilidi son <xliff:g id="NUMBER_0">%d</xliff:g> saattir açılmadı. Deseni doğrulayın.</item>
diff --git a/packages/Keyguard/res/values-uk/strings.xml b/packages/Keyguard/res/values-uk/strings.xml
index dba0f6c..c1b742e 100644
--- a/packages/Keyguard/res/values-uk/strings.xml
+++ b/packages/Keyguard/res/values-uk/strings.xml
@@ -77,23 +77,23 @@
     <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">%d</xliff:g>. \n\nПовторіть спробу через <xliff:g id="NUMBER_1">%d</xliff:g> с."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Пароль неправильно введено стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. \n\nПовторіть спробу через <xliff:g id="NUMBER_1">%d</xliff:g> с."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. \n\nПовторіть спробу через <xliff:g id="NUMBER_1">%d</xliff:g> с."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER_0">%d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%d</xliff:g> У разі невдачі буде скинуто налаштування планшета й видалено всі його дані."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER_0">%d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%d</xliff:g> У разі невдачі буде скинуто налаштування телефона й видалено всі його дані."</string>
+    <string name="kg_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">"Ключ розблокування неправильно намальовано стільки разів: <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">%d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%d</xliff:g>. У разі невдачі буде видалено цього користувача й усі його дані."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER_0">%d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%d</xliff:g>. У разі невдачі буде видалено цього користувача й усі його дані."</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%d</xliff:g>. У разі невдачі буде видалено робочий профіль і всі його дані."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER_0">%d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%d</xliff:g>. У разі невдачі буде видалено робочий профіль і всі його дані."</string>
+    <string name="kg_failed_attempts_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">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%d</xliff:g>. У разі невдачі з’явиться запит розблокувати планшетний ПК за допомогою облікового запису електронної пошти.\n\n Повторіть спробу через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%d</xliff:g>. У разі невдачі з’явиться запит розблокувати телефон за допомогою облікового запису електронної пошти.\n\n Повторіть спробу через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі з’явиться запит розблокувати планшетний ПК за допомогою облікового запису електронної пошти.\n\n Повторіть спробу через <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі з’явиться запит розблокувати телефон за допомогою облікового запису електронної пошти.\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>
@@ -114,15 +114,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Зв’язку немає."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Кнопка перемикання методу введення."</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Режим польоту"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Після перезавантаження пристрою потрібно ввести ключ."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Після перезавантаження пристрою потрібно ввести PIN-код."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Після перезавантаження пристрою потрібно ввести пароль."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Введіть ключ. Це потрібно зробити з міркувань безпеки."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Введіть PIN-код. Це потрібно зробити з міркувань безпеки."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Введіть пароль. Це потрібно зробити з міркувань безпеки."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Після переходу в інший профіль потрібно ввести ключ."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Після переходу в інший профіль потрібно ввести PIN-код."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Після переходу в інший профіль потрібно ввести пароль."</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>
diff --git a/packages/Keyguard/res/values-ur-rPK/strings.xml b/packages/Keyguard/res/values-ur-rPK/strings.xml
index b6a993b..48986e6 100644
--- a/packages/Keyguard/res/values-ur-rPK/strings.xml
+++ b/packages/Keyguard/res/values-ur-rPK/strings.xml
@@ -77,23 +77,23 @@
     <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">"‏آپ نے <xliff:g id="NUMBER_0">%d</xliff:g> بار اپنا PIN غلط طریقے سے ٹائپ کیا ہے۔ \n\n <xliff:g id="NUMBER_1">%d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"آپ نے اپنا پاس ورڈ <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے ٹائپ کیا ہے۔ \n\n <xliff:g id="NUMBER_1">%d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ \n\n <xliff:g id="NUMBER_1">%d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%d</xliff:g> مزید ناکام کوششوں کے بعد، اس ٹیبلیٹ کو دوبارہ ترتیب دے دیا جائے گا، جس سے اس کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%d</xliff:g> مزید ناکام کوششوں کے بعد، اس فون کو دوبارہ ترتیب دے دیا جائے گا، جس سے اس کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"‏آپ نے <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اپنا PIN غلط طریقے سے ٹائپ کیا ہے۔ \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">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <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">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%d</xliff:g> مزید ناکام کوششوں کے بعد، اس صارف کو ہٹا دیا جائے گا، جس سے صارف کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%d</xliff:g> مزید ناکام کوششوں کے بعد، اس صارف کو ہٹا دیا جائے گا، جس سے صارف کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%d</xliff:g> مزید ناکام کوششوں کے بعد، دفتری پروفائل ہٹا دیا جائے گا، جس سے پروفائل کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%d</xliff:g> مزید ناکام کوششوں کے بعد، دفتری پروفائل ہٹا دیا جائے گا، جس سے پروفائل کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
+    <string name="kg_failed_attempts_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">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کرکے اپنا ٹیبلیٹ غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کرکے اپنا فون غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کرکے اپنا ٹیبلیٹ غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کرکے اپنا فون غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"‏غلط SIM PIN کوڈ اب آپ کو اپنا آلہ غیر مقفل کرنے کیلئے لازمی طور پر اپنے کیریئر سے رابطہ کرنا چاہئے۔"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">‏غلط SIM PIN کوڈ، آپ کے پاس <xliff:g id="NUMBER_1">%d</xliff:g> کوششیں بچی ہیں۔</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"کوئی سروس نہیں ہے۔"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"اندراج کا طریقہ سوئچ کرنے کا بٹن۔"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"ہوائی جہاز وضع"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"جب آپ آلہ کو دوبارہ شروع کرتے ہیں تو پیٹرن درکار ہوتا ہے۔"</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"‏جب آپ آلہ کو دوبارہ شروع کرتے ہیں تو PIN درکار ہوتا ہے۔"</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"جب آپ آلہ کو دوبارہ شروع کرتے ہیں تو پاسورڈ درکار ہوتا ہے۔"</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"اضافی سیکیورٹی کیلئے پیٹرن درکار ہے۔"</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"‏اضافی سیکیورٹی کیلئے PIN درکار ہے۔"</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"اضافی سیکیورٹی کیلئے پاسورڈ درکار ہے۔"</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"جب آپ پروفائل سوئچ کرتے ہیں تو پیٹرن درکار ہوتا ہے۔"</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"‏جب آپ پروفائل سوئچ کرتے ہیں تو PIN درکار ہوتا ہے۔"</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"جب آپ پروفائل سوئچ کرتے ہیں تو پاسورڈ درکار ہوتا ہے۔"</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="other">آلہ <xliff:g id="NUMBER_1">%d</xliff:g> گھنٹے سے غیر مقفل نہیں کیا گیا۔ پیٹرن کی تصدیق کریں۔</item>
       <item quantity="one">آلہ <xliff:g id="NUMBER_0">%d</xliff:g> گھنٹے سے غیر مقفل نہیں کیا گیا۔ پیٹرن کی تصدیق کریں۔</item>
diff --git a/packages/Keyguard/res/values-uz-rUZ/strings.xml b/packages/Keyguard/res/values-uz-rUZ/strings.xml
index eae5ff8..7e9f504 100644
--- a/packages/Keyguard/res/values-uz-rUZ/strings.xml
+++ b/packages/Keyguard/res/values-uz-rUZ/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"To‘g‘ri PUK kodni qayta kiriting. Qayta-qayta urinishlar SIM kartani butunlay o‘chirib qo‘yadi."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-kod mos kelmadi"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Chizmali parolni ochishga juda ko‘p urinildi"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Siz PIN-kodni <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri kiritdingiz. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> soniyadan so‘ng qayta urinib ko‘ring."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Siz parolni <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri kiritdingiz. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> soniyadan so‘ng qayta urinib ko‘ring."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Siz chizmali kalitni <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri kiritdingiz. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> soniyadan so‘ng qayta urinib ko‘ring."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu planshetda zavod sozlamalari qayta tiklanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu telefonda zavod sozlamalari qayta tiklanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Siz PIN-kodni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> soniyadan so‘ng qayta urinib ko‘ring."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Siz parolni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> soniyadan so‘ng qayta urinib ko‘ring."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Siz chizmali kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> soniyadan so‘ng qayta urinib ko‘ring."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu planshetda zavod sozlamalari qayta tiklanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu telefonda zavod sozlamalari qayta tiklanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ushbu planshetda zavod sozlamalari qayta tiklanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ushbu telefonda zavod sozlamalari qayta tiklanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu foydalanuvchi o‘chirib tashlanadi va undagi barcha foydalanuvchi ma’lumotlari ham o‘chib ketadi."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu foydalanuvchi o‘chirib tashlanadi va undagi barcha foydalanuvchi ma’lumotlari ham o‘chib ketadi."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu foydalanuvchi o‘chirib tashlanadi va undagi barcha foydalanuvchi ma’lumotlari ham o‘chib ketadi."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu foydalanuvchi o‘chirib tashlanadi va undagi barcha foydalanuvchi ma’lumotlari ham o‘chib ketadi."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ushbu foydalanuvchi o‘chirib tashlanadi va undagi barcha foydalanuvchi ma’lumotlari ham o‘chib ketadi."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ushbu foydalanuvchi o‘chirib tashlanadi va undagi barcha foydalanuvchi ma’lumotlari ham o‘chib ketadi."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ishchi profil o‘chirib tashlanadi va undagi barcha profil ma’lumotlari ham o‘chib ketadi."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ishchi profil o‘chirib tashlanadi va undagi barcha profil ma’lumotlari ham o‘chib ketadi."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ishchi profil o‘chirib tashlanadi va undagi barcha profil ma’lumotlari ham o‘chib ketadi."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ishchi profil o‘chirib tashlanadi va undagi barcha profil ma’lumotlari ham o‘chib ketadi."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ishchi profil o‘chirib tashlanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ishchi profil o‘chirib tashlanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Siz chizmali kalitni  <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri kiritdingiz. <xliff:g id="NUMBER_1">%d</xliff:g> marta muvaffaqiyatsiz urinishdan so‘ng, sizdan e-pochtangizdan foydalanib, planshet qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> soniyadan so‘ng yana urinib ko‘ring."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Siz chizmali kalitni <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri chizdingiz. <xliff:g id="NUMBER_1">%d</xliff:g> marta muvaffaqiyatsiz urinishdan so‘ng, sizdan e-pochtangizdan foydalanib, telefon qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> soniyadan so‘ng yana urinib ko‘ring."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Siz chizmali kalitni  <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan so‘ng, sizdan e-pochtangizdan foydalanib, planshet qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan so‘ng yana urinib ko‘ring."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Siz chizmali kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri chizdingiz. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan so‘ng, sizdan e-pochtangizdan foydalanib, telefon qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan so‘ng yana urinib ko‘ring."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM karta PIN kodi noto‘g‘ri. Qurilma qulfini ochish uchun aloqa operatoringiz bilan bog‘laning."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">SIM kartaning PIN kodi noto‘g‘ri. Sizda yana <xliff:g id="NUMBER_1">%d</xliff:g> ta urinish qoldi.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Parvoz rejimi"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Qurilmani o‘chirib yoqishda chizmali kalit talab qilinadi."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Qurilmani o‘chirib yoqishda PIN-kod talab qilinadi."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Qurilmani o‘chirib yoqishda parol talab qilinadi."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Qo‘shimcha xavfsizlik chorasi sifatida chizmali kalit talab qilinadi."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Qo‘shimcha xavfsizlik chorasi sifatida PIN-kod talab qilinadi."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Qo‘shimcha xavfsizlik chorasi sifatida parol talab qilinadi."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Profilni amlashtirishda chizmali kalit talab qilinadi."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Profilni amlashtirishda PIN-kod talab qilinadi."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Profilni amlashtirishda parol talab qilinadi."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Qurilma o‘chirib yoqilgandan so‘ng parol talab qilinadi"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Qo‘shimcha xavfsizlik chorasi sifatida chizmali kalit talab qilinadi"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Qo‘shimcha xavfsizlik chorasi sifatida PIN kod talab qilinadi"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Qo‘shimcha xavfsizlik chorasi sifatida parol talab qilinadi"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Profilni amlashtirishda chizmali kalit talab qilinadi"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Profilni amlashtirishda PIN kod talab qilinadi"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Profilni amlashtirishda parol talab qilinadi"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">Qurilma <xliff:g id="NUMBER_1">%d</xliff:g> soatdan beri qulfdan chiqarilgani yo‘q. Chizmali kalitni yana bir marta kiriting.</item>
       <item quantity="one">Qurilma <xliff:g id="NUMBER_0">%d</xliff:g> soatdan beri qulfdan chiqarilgani yo‘q. Chizmali kalitni yana bir marta kiriting.</item>
diff --git a/packages/Keyguard/res/values-vi/strings.xml b/packages/Keyguard/res/values-vi/strings.xml
index 0568998..6f81101 100644
--- a/packages/Keyguard/res/values-vi/strings.xml
+++ b/packages/Keyguard/res/values-vi/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Hãy nhập lại mã PUK chính xác. Nhiều lần lặp lại sẽ vô hiệu hóa vĩnh viễn thẻ SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Mã PIN không khớp"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Quá nhiều lần nhập hình"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần nhập sai mã PIN. \n\nHãy thử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần nhập sai mật khẩu. \n\nHãy thử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa. \n\nHãy thử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER_0">%d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần mở khóa không thành công nữa, máy tính bảng này sẽ được đặt lại, tức là tất cả dữ liệu của máy tính bảng sẽ bị xóa."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER_0">%d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần mở khóa không thành công nữa, điện thoại này sẽ được đặt lại, tức là tất cả dữ liệu của điện thoại sẽ bị xóa."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Bạn đã <xliff:g id="NUMBER_0">%1$d</xliff:g> lần nhập sai mã PIN. \n\nHãy thử lại sau <xliff:g id="NUMBER_1">%2$d</xliff:g> giây."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Bạn đã <xliff:g id="NUMBER_0">%1$d</xliff:g> lần nhập sai mật khẩu. \n\nHãy thử lại sau <xliff:g id="NUMBER_1">%2$d</xliff:g> giây."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Bạn đã <xliff:g id="NUMBER_0">%1$d</xliff:g> lần vẽ không chính xác hình mở khóa. \n\nHãy thử lại sau <xliff:g id="NUMBER_1">%2$d</xliff:g> giây."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần mở khóa không thành công nữa, máy tính bảng này sẽ được đặt lại, tức là tất cả dữ liệu của máy tính bảng sẽ bị xóa."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần mở khóa không thành công nữa, điện thoại này sẽ được đặt lại, tức là tất cả dữ liệu của điện thoại sẽ bị xóa."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER">%d</xliff:g> lần. Máy tính bảng này sẽ được đặt lại, tức là tất cả dữ liệu của máy tính bảng sẽ bị xóa."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER">%d</xliff:g> lần. Điện thoại này sẽ được đặt lại, tức là tất cả dữ liệu của điện thoại sẽ bị xóa."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER_0">%d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần mở khóa không thành công nữa, người dùng này sẽ bị xóa, tức là tất cả dữ liệu người dùng sẽ bị xóa."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER_0">%d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần mở khóa không thành công nữa, người dùng này sẽ bị xóa, tức là tất cả dữ liệu người dùng sẽ bị xóa."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần mở khóa không thành công nữa, người dùng này sẽ bị xóa, tức là tất cả dữ liệu người dùng sẽ bị xóa."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần mở khóa không thành công nữa, người dùng này sẽ bị xóa, tức là tất cả dữ liệu người dùng sẽ bị xóa."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER">%d</xliff:g> lần. Người dùng này sẽ bị xóa, tức là tất cả dữ liệu người dùng sẽ bị xóa."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER">%d</xliff:g> lần. Người dùng này sẽ bị xóa, tức là tất cả dữ liệu người dùng sẽ bị xóa."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER_0">%d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần mở khóa không thành công nữa, hồ sơ công việc sẽ bị xóa, tức là tất cả dữ liệu hồ sơ sẽ bị xóa."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER_0">%d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần mở khóa không thành công nữa, hồ sơ công việc sẽ bị xóa, tức là tất cả dữ liệu hồ sơ sẽ bị xóa."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần mở khóa không thành công nữa, hồ sơ công việc sẽ bị xóa, tức là tất cả dữ liệu hồ sơ sẽ bị xóa."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần mở khóa không thành công nữa, hồ sơ công việc sẽ bị xóa, tức là tất cả dữ liệu hồ sơ sẽ bị xóa."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER">%d</xliff:g> lần. Hồ sơ công việc sẽ bị xóa, tức là tất cả dữ liệu hồ sơ sẽ bị xóa."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER">%d</xliff:g> lần. Hồ sơ công việc sẽ bị xóa, tức là tất cả dữ liệu hồ sơ sẽ bị xóa."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa máy tính bảng bằng tài khoản email.\n\n Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa điện thoại bằng tài khoản email.\n\n Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Bạn đã <xliff:g id="NUMBER_0">%1$d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa máy tính bảng bằng tài khoản email.\n\n Vui lòng thử lại sau <xliff:g id="NUMBER_2">%3$d</xliff:g> giây."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Bạn đã <xliff:g id="NUMBER_0">%1$d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa điện thoại bằng tài khoản email.\n\n Vui lòng thử lại sau <xliff:g id="NUMBER_2">%3$d</xliff:g> giây."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Mã PIN của SIM không chính xác, bây giờ bạn phải liên hệ với nhà cung cấp dịch vụ để mở khóa thiết bị của bạn."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">Mã PIN của SIM không chính xác, bạn còn  <xliff:g id="NUMBER_1">%d</xliff:g> lần thử.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Chế độ trên máy bay"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Yêu cầu hình khi bạn khởi động lại thiết bị."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Yêu cầu mã PIN khi bạn khởi động lại thiết bị."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Yêu cầu mật khẩu khi bạn khởi động lại thiết bị."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Cần có mẫu hình để bảo mật thêm."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Cần có mã PIN để bảo mật thêm."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Cần có mật khẩu để bảo mật thêm."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Yêu cầu hình khi bạn chuyển đổi hồ sơ."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Yêu cầu mã PIN khi bạn chuyển đổi hồ sơ."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Yêu cầu mật khẩu khi bạn chuyển đổi hồ sơ."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Yêu cầu mật khẩu sau khi thiết bị khởi động lại"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Cần có hình mở khóa để bảo mật thêm"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Cần có mã PIN để bảo mật thêm"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Cần có mật khẩu để bảo mật thêm"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Yêu cầu hình mở khóa khi bạn chuyển đổi hồ sơ"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Yêu cầu mã PIN khi bạn chuyển đổi hồ sơ"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Yêu cầu mật khẩu khi bạn chuyển đổi hồ sơ"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="other">Thiết bị đã không được mở khóa trong <xliff:g id="NUMBER_1">%d</xliff:g> giờ. Xác nhận hình.</item>
       <item quantity="one">Thiết bị đã không được mở khóa trong <xliff:g id="NUMBER_0">%d</xliff:g> giờ. Xác nhận hình.</item>
diff --git a/packages/Keyguard/res/values-zh-rCN/strings.xml b/packages/Keyguard/res/values-zh-rCN/strings.xml
index c7b217c..2c86a7a 100644
--- a/packages/Keyguard/res/values-zh-rCN/strings.xml
+++ b/packages/Keyguard/res/values-zh-rCN/strings.xml
@@ -77,23 +77,23 @@
     <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">"您已经<xliff:g id="NUMBER_0">%d</xliff:g>次输错了PIN码。\n\n请在<xliff:g id="NUMBER_1">%d</xliff:g>秒后重试。"</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"您已连续 <xliff:g id="NUMBER_0">%d</xliff:g> 次输错密码。\n\n请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"您已连续 <xliff:g id="NUMBER_0">%d</xliff:g> 次画错解锁图案。\n\n请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地尝试解锁平板电脑。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,平板电脑将会被重置,这会删除其中的所有数据。"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地尝试解锁手机。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,手机将会被重置,这会删除其中的所有数据。"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"您已经<xliff:g id="NUMBER_0">%1$d</xliff:g>次输错了PIN码。\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">"您已连续 <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">%d</xliff:g> 次错误地尝试解锁平板电脑。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统将移除此用户,这会删除所有的用户数据。"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地尝试解锁手机。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统将移除此用户,这会删除所有的用户数据。"</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> 次错误地尝试解锁平板电脑。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统将移除此工作资料,这会删除所有的工作资料数据。"</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地尝试解锁手机。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统将移除此工作资料,这会删除所有的工作资料数据。"</string>
+    <string name="kg_failed_attempts_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">"您已连续 <xliff:g id="NUMBER_0">%d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁平板电脑。\n\n请在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒后重试。"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您已连续 <xliff:g id="NUMBER_0">%d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁手机。\n\n请在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒后重试。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您已连续 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁平板电脑。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您已连续 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁手机。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM卡PIN码不正确,您现在必须联系运营商为您解锁设备。"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">SIM 卡 PIN 码不正确,您还可尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次。</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"无服务。"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"输入法切换按钮。"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"飞行模式"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"重启设备后需要绘制图案。"</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"重启设备后需要输入 PIN 码。"</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"重启设备后需要输入密码。"</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"需要绘制解锁图案,以进一步确保安全。"</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"需要输入 PIN 码,以进一步确保安全。"</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"需要输入密码,以进一步确保安全。"</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"切换资料后需要绘制图案。"</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"切换资料后需要输入 PIN 码。"</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"切换资料后需要输入密码。"</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="other">设备已保持锁定状态达 <xliff:g id="NUMBER_1">%d</xliff:g> 小时。请确认解锁图案。</item>
       <item quantity="one">设备已保持锁定状态达 <xliff:g id="NUMBER_0">%d</xliff:g> 小时。请确认解锁图案。</item>
diff --git a/packages/Keyguard/res/values-zh-rHK/strings.xml b/packages/Keyguard/res/values-zh-rHK/strings.xml
index 542e1b8..f21dbca 100644
--- a/packages/Keyguard/res/values-zh-rHK/strings.xml
+++ b/packages/Keyguard/res/values-zh-rHK/strings.xml
@@ -77,23 +77,23 @@
     <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">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"您已輸入錯誤的密碼 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"您已 <xliff:g id="NUMBER_0">%d</xliff:g> 次錯誤解鎖平板電腦。如再解鎖失敗 <xliff:g id="NUMBER_1">%d</xliff:g> 次,平板電腦將被重設,平板電腦的所有資料將因此被刪除。"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"您已 <xliff:g id="NUMBER_0">%d</xliff:g> 次錯誤解鎖手機。如再解鎖失敗 <xliff:g id="NUMBER_1">%d</xliff:g> 次,手機將被重設,手機的所有資料將因此被刪除。"</string>
+    <string name="kg_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">"您已畫錯解鎖圖案 <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">%d</xliff:g> 次錯誤解鎖平板電腦。如再解鎖失敗 <xliff:g id="NUMBER_1">%d</xliff:g> 次,該使用者將被移除,所有使用者資料將因此被刪除。"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"您已 <xliff:g id="NUMBER_0">%d</xliff:g> 次錯誤解鎖手機。如再解鎖失敗 <xliff:g id="NUMBER_1">%d</xliff:g> 次,該使用者將被移除,所有使用者資料將因此被刪除。"</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> 次錯誤解鎖平板電腦。如再解鎖失敗 <xliff:g id="NUMBER_1">%d</xliff:g> 次,該工作設定檔將被移除,所有設定檔資料將因此被刪除。"</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"您已 <xliff:g id="NUMBER_0">%d</xliff:g> 次錯誤解鎖手機。如再解鎖失敗 <xliff:g id="NUMBER_1">%d</xliff:g> 次,該工作設定檔將被移除,所有設定檔資料將因此被刪除。"</string>
+    <string name="kg_failed_attempts_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">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解開上鎖的平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解開上鎖的手機。\n\n請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解開上鎖的平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解開上鎖的手機。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM PIN 碼不正確,您現在必須聯絡流動網絡供應商為您的裝置解鎖。"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">SIM PIN 碼不正確,您還有 <xliff:g id="NUMBER_1">%d</xliff:g> 次機會輸入。</item>
@@ -110,15 +110,15 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"沒有服務。"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"切換輸入法按鈕。"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"飛航模式"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"需要圖案方可重新啟動裝置。"</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"需要 PIN 方可重新啟動裝置。"</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"需要密碼方可重新啟動裝置。"</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"需要使用圖案以提高安全性。"</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"需要使用 PIN 以提高安全性。"</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"需要使用密碼以提高安全性。"</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"需要圖案方可切換設定檔。"</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"需要 PIN 方可切換設定檔。"</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"需要密碼方可切換設定檔。"</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="other">裝置在 <xliff:g id="NUMBER_1">%d</xliff:g> 小時後尚未解鎖,請確認圖案。</item>
       <item quantity="one">裝置在 <xliff:g id="NUMBER_0">%d</xliff:g> 小時後尚未解鎖,請確認圖案。</item>
diff --git a/packages/Keyguard/res/values-zh-rTW/strings.xml b/packages/Keyguard/res/values-zh-rTW/strings.xml
index 56d0573..0cb4b16 100644
--- a/packages/Keyguard/res/values-zh-rTW/strings.xml
+++ b/packages/Keyguard/res/values-zh-rTW/strings.xml
@@ -46,7 +46,7 @@
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM 卡處於鎖定狀態。"</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM 卡處於 PUK 鎖定狀態"</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"正在解除 SIM 卡鎖定..."</string>
-    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"圖形解鎖。"</string>
+    <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"圖案解鎖。"</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"PIN 解鎖。"</string>
     <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"密碼解鎖。"</string>
     <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"圖形區域。"</string>
@@ -77,23 +77,23 @@
     <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">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"您的密碼已輸錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER_0">%d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%d</xliff:g> 次機會。如果失敗次數超過限制,這台平板電腦將會重設,其中的所有資料也會一併遭到刪除。"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%d</xliff:g> 次機會。如果失敗次數超過限制,系統會重設您的手機,其中的所有資料也會一併遭到刪除。"</string>
+    <string name="kg_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">"您的解鎖圖案已畫錯 <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">%d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%d</xliff:g> 次機會。如果失敗次數超過限制,這位使用者將遭到移除,對方的所有使用者資料也會一併遭到刪除。"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%d</xliff:g> 次機會。如果失敗次數超過限制,這位使用者將遭到移除,對方的所有使用者資料也會一併遭到刪除。"</string>
+    <string name="kg_failed_attempts_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">%d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%d</xliff:g> 次機會。如果失敗次數超過限制,您的 Work 設定檔將遭到移除,所有設定檔資料也會一併遭到刪除。"</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%d</xliff:g> 次機會。如果失敗次數超過限制,您的 Work 設定檔將遭到移除,所有設定檔資料也會一併遭到刪除。"</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> 次機會。如果失敗次數超過限制,您的 Work 設定檔將遭到移除,所有設定檔資料也會一併遭到刪除。"</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> 次機會。如果失敗次數超過限制,您的 Work 設定檔將遭到移除,所有設定檔資料也會一併遭到刪除。"</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。您的 Work 設定檔將遭到移除,所有設定檔資料也會一併遭到刪除。"</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。您的 Work 設定檔將遭到移除,所有設定檔資料也會一併遭到刪除。"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統就會要求您透過電子郵件帳戶解除平板電腦的鎖定狀態。\n\n請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統就會要求您透過電子郵件帳戶解除手機的鎖定狀態。\n\n請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您的解鎖圖案已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統就會要求您透過電子郵件帳戶解除平板電腦的鎖定狀態。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您的解鎖圖案已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統就會要求您透過電子郵件帳戶解除手機的鎖定狀態。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM 卡的 PIN 碼輸入錯誤,您現在必須請行動通訊業者為裝置解鎖。"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="other">SIM 卡的 PIN 碼輸入錯誤,您還可以再試 <xliff:g id="NUMBER_1">%d</xliff:g> 次。</item>
@@ -110,18 +110,18 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"沒有服務。"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"切換輸入法按鈕。"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"飛航模式"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"重新啟動裝置時需要確認圖形。"</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"重新啟動裝置時需要確認 PIN 碼。"</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"重新啟動裝置時需要確認密碼。"</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"請輸入解鎖圖形,以進一步確保資訊安全。"</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"請輸入 PIN 碼,以進一步確保資訊安全。"</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"請輸入密碼,以進一步確保資訊安全。"</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"切換設定檔時需要確認圖形。"</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"切換設定檔時需要確認 PIN 碼。"</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"切換設定檔時需要確認密碼。"</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="other">裝置已有 <xliff:g id="NUMBER_1">%d</xliff:g> 小時未解鎖。請確認圖形。</item>
-      <item quantity="one">裝置已有 <xliff:g id="NUMBER_0">%d</xliff:g> 小時未解鎖。請確認圖形。</item>
+      <item quantity="other">裝置已有 <xliff:g id="NUMBER_1">%d</xliff:g> 小時未解鎖。請確認圖案。</item>
+      <item quantity="one">裝置已有 <xliff:g id="NUMBER_0">%d</xliff:g> 小時未解鎖。請確認圖案。</item>
     </plurals>
     <plurals name="kg_prompt_reason_time_pin" formatted="false" msgid="2118758475374354849">
       <item quantity="other">裝置已有 <xliff:g id="NUMBER_1">%d</xliff:g> 小時未解鎖。請確認 PIN 碼。</item>
diff --git a/packages/Keyguard/res/values-zu/strings.xml b/packages/Keyguard/res/values-zu/strings.xml
index c29619c..9e17dba 100644
--- a/packages/Keyguard/res/values-zu/strings.xml
+++ b/packages/Keyguard/res/values-zu/strings.xml
@@ -77,23 +77,23 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Faka kabusha ikhodi ye-PUK elungile. Imizamo ephindiwe izokhubaza unaphakade i-SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Iphinikhodi ayifani"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Kunemizamo eminingi kakhulu yephathini"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Ubhale iphinikhodi ykho ngendlela engafanele izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. \n\nZama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%d</xliff:g>."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Ubhale iphasiwedi yakho ngendlela engafanele <xliff:g id="NUMBER_0">%d</xliff:g> izikhathi. \n\nZama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%d</xliff:g>."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Udwebe iphathini yakho yokuvula ngendlela engafanele-<xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Zama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%d</xliff:g>"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%d</xliff:g> engaphumelelanga, le thebulethi izosethwa kabusha, okuzosusa yonke idatha yayo."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%d</xliff:g> engaphumelelanga, le foni izosethwa kabusha, okuzosusa yonke idatha yayo."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Ubhale iphinikhodi ykho ngendlela engafanele izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nZama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Ubhale iphasiwedi yakho ngendlela engafanele <xliff:g id="NUMBER_0">%1$d</xliff:g> izikhathi. \n\nZama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Udwebe iphathini yakho yokuvula ngendlela engafanele-<xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\n Zama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%2$d</xliff:g>"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%2$d</xliff:g> engaphumelelanga, le thebulethi izosethwa kabusha, okuzosusa yonke idatha yayo."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%2$d</xliff:g> engaphumelelanga, le foni izosethwa kabusha, okuzosusa yonke idatha yayo."</string>
     <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Le thebulethi izosethwa kabusha, okuzosusa yonke idatha yayo."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Le foni izosethwa kabusha, okuzosusa yonke idatha yayo."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%d</xliff:g> engaphumelelanga, lo msebenzisi uzosuswa, okuzosusa yonke idatha yomsebenzisi."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%d</xliff:g> engaphumelelanga, lo msebenzisi uzosuswa, okuzosusa yonke idatha yomsebenzisi."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%2$d</xliff:g> engaphumelelanga, lo msebenzisi uzosuswa, okuzosusa yonke idatha yomsebenzisi."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%2$d</xliff:g> engaphumelelanga, lo msebenzisi uzosuswa, okuzosusa yonke idatha yomsebenzisi."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Lo msebenzisi uzosuswa, okuzosusa yonke idatha yomsebenzisi."</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Lo msebenzisi uzosuswa, okuzosusa yonke idatha yomsebenzisi."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%d</xliff:g> engaphumelelanga, iphrofayela yomsebenzi izosuswa, okuzosusa yonke idatha yephrofayela."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%d</xliff:g> engaphumelelanga, iphrofayela yomsebenzi, izosuswa, okuzosusa yonke idatha yephrofayela."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%2$d</xliff:g> engaphumelelanga, iphrofayela yomsebenzi izosuswa, okuzosusa yonke idatha yephrofayela."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%2$d</xliff:g> engaphumelelanga, iphrofayela yomsebenzi, izosuswa, okuzosusa yonke idatha yephrofayela."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Iphrofayela yomsebenzi izosuswa, okuzosusa yonke idatha yephrofayela."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Iphrofayela yomsebenzi izosuswa, okuzosusa yonke idatha yephrofayela."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Udwebe ngokungalungile iphathini yakho yokuvula izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Emva <xliff:g id="NUMBER_1">%d</xliff:g> kweminye imizamo engaphumelelanga, uzocelwa ukuvula ithebhulethi yakho usebenzisa ukungena ngemvume kwi-Google.\n\n Sicela uzame futhi emuva kwamasekhondi angu-<xliff:g id="NUMBER_2">%d</xliff:g>"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ukulayisha ungenisa iphathini yakho yokuvula ngendlela engalungile izikhathi ezi-<xliff:g id="NUMBER_0">%d</xliff:g> Emva kweminye imizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g>, uzocelwa ukuvula ifoni yakho usebenzisa ukungena ngemvume ku-Google\n\n Zame futhi emumva kwengu- <xliff:g id="NUMBER_2">%d</xliff:g> amasekhondi."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Udwebe ngokungalungile iphathini yakho yokuvula izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Emva <xliff:g id="NUMBER_1">%2$d</xliff:g> kweminye imizamo engaphumelelanga, uzocelwa ukuvula ithebhulethi yakho usebenzisa ukungena ngemvume kwi-Google.\n\n Sicela uzame futhi emuva kwamasekhondi angu-<xliff:g id="NUMBER_2">%3$d</xliff:g>"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ukulayisha ungenisa iphathini yakho yokuvula ngendlela engalungile izikhathi ezi-<xliff:g id="NUMBER_0">%1$d</xliff:g> Emva kweminye imizamo engu-<xliff:g id="NUMBER_1">%2$d</xliff:g>, uzocelwa ukuvula ifoni yakho usebenzisa ukungena ngemvume ku-Google\n\n Zame futhi emumva kwengu- <xliff:g id="NUMBER_2">%3$d</xliff:g> amasekhondi."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Ikhodi yephinikhodi ye-SIM engalungile manje kumele uxhumane nenkampini yenethiwekhi yakho ukuvula idivayisi yakho."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
       <item quantity="one">Ikhodi engalungile yephinikhodi ye-SIM, unemizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g> esele.</item>
@@ -110,15 +110,15 @@
     <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="airplane_mode" msgid="3122107900897202805">"Isimo sendiza"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Iphethini iyadingeka uma uqalisa kabusha idivayisi."</string>
-    <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"Iphinikhodi iyadingeka uma uqalisa kabusha idivayisi."</string>
-    <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Iphasiwedi iyadingeka uma uqalisa kabusha idivayisi."</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Iphethini iyadingeka ngokuvikela okungeziwe."</string>
-    <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Iphinikhodi iyadingeka ngokuvikela okungeziwe."</string>
-    <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Iphasiwedi iyadingeka ngokuvikela okungeziwe."</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Iphethini iyadingeka uma ushintsha amaphrofayela."</string>
-    <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"Iphinikhodi iyadingeka uma ushintsha amaphrofayela."</string>
-    <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Iphasiwedi iyadingeka uma ushintsha amaphrofayela."</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>
+    <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Iphasiwedi iyadingeka ngemuva kokuqala kabusha kwedivayisi"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Kudingeka iphethini  ngokuvikeleka okungeziwe"</string>
+    <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Kudingeka iphinikhodi ngokuvikeleka okungeziwe"</string>
+    <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Iphasiwedi idingelwa ukuvikela okungeziwe"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Iphethini iyadingeka uma ushintsha amaphrofayela"</string>
+    <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Kudingeka iphinikhodi uma ushintsha amaphrofayela"</string>
+    <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Iphasiwedi iyadingeka uma ushintsha amaphrofayela"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="one">Idivayisi ayikavulwa ngamahora angu-<xliff:g id="NUMBER_1">%d</xliff:g>. Qinisekisa iphethini.</item>
       <item quantity="other">Idivayisi ayikavulwa ngamahora angu-<xliff:g id="NUMBER_1">%d</xliff:g>. Qinisekisa iphethini.</item>
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index d1e84f5..746457f 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -170,29 +170,29 @@
     <string name="kg_login_too_many_attempts">Too many pattern attempts</string>
     <!-- Message shown in dialog when max number of attempts are reached for PIN screen of keyguard -->
     <string name="kg_too_many_failed_pin_attempts_dialog_message">
-        You have incorrectly typed your PIN <xliff:g id="number">%d</xliff:g> times.
-        \n\nTry again in <xliff:g id="number">%d</xliff:g> seconds.
+        You have incorrectly typed your PIN <xliff:g id="number">%1$d</xliff:g> times.
+        \n\nTry again in <xliff:g id="number">%2$d</xliff:g> seconds.
     </string>
     <!-- Message shown in dialog when max number of attempts are reached for password screen of keyguard -->
     <string name="kg_too_many_failed_password_attempts_dialog_message">
-        You have incorrectly typed your password <xliff:g id="number">%d</xliff:g> times.
-        \n\nTry again in <xliff:g id="number">%d</xliff:g> seconds.
+        You have incorrectly typed your password <xliff:g id="number">%1$d</xliff:g> times.
+        \n\nTry again in <xliff:g id="number">%2$d</xliff:g> seconds.
     </string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message">
-        You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times.
-        \n\nTry again in <xliff:g id="number">%d</xliff:g> seconds.
+        You have incorrectly drawn your unlock pattern <xliff:g id="number">%1$d</xliff:g> times.
+        \n\nTry again in <xliff:g id="number">%2$d</xliff:g> seconds.
     </string>
 
     <!-- Message shown when user is almost at the limit of password attempts where the device will be wiped. [CHAR LIMIT=none] -->
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet">
-       You have incorrectly attempted to unlock the tablet <xliff:g id="number">%d</xliff:g> times.
-       After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+       You have incorrectly attempted to unlock the tablet <xliff:g id="number">%1$d</xliff:g> times.
+       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
        this tablet will be reset, which will delete all its data.
     </string>
     <!-- Message shown when user is almost at the limit of password attempts where the device will be wiped. [CHAR LIMIT=none] -->
     <string name="kg_failed_attempts_almost_at_wipe" product="default">
-       You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times.
-       After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+       You have incorrectly attempted to unlock the phone <xliff:g id="number">%1$d</xliff:g> times.
+       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
        this phone will be reset, which will delete all its data.
     </string>
     <!-- Message shown in dialog when user has exceeded the maximum attempts and the device will now be wiped [CHAR LIMIT=none] -->
@@ -208,14 +208,14 @@
 
     <!-- Message shown when user is almost at the limit of password attempts where the user will be removed. [CHAR LIMIT=none] -->
     <string name="kg_failed_attempts_almost_at_erase_user" product="tablet">
-       You have incorrectly attempted to unlock the tablet <xliff:g id="number">%d</xliff:g> times.
-       After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+       You have incorrectly attempted to unlock the tablet <xliff:g id="number">%1$d</xliff:g> times.
+       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
        this user will be removed, which will delete all user data.
     </string>
     <!-- Message shown when user is almost at the limit of password attempts where the user will be removed. [CHAR LIMIT=none] -->
     <string name="kg_failed_attempts_almost_at_erase_user" product="default">
-       You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times.
-       After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+       You have incorrectly attempted to unlock the phone <xliff:g id="number">%1$d</xliff:g> times.
+       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
        this user will be removed, which will delete all user data.
     </string>
     <!-- Message shown in dialog when user has exceeded the maximum attempts and the user will be removed. [CHAR LIMIT=none] -->
@@ -231,14 +231,14 @@
 
     <!-- Message shown when user is almost at the limit of password attempts where the profile will be removed. [CHAR LIMIT=none] -->
     <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet">
-       You have incorrectly attempted to unlock the tablet <xliff:g id="number">%d</xliff:g> times.
-       After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+       You have incorrectly attempted to unlock the tablet <xliff:g id="number">%1$d</xliff:g> times.
+       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
        the work profile will be removed, which will delete all profile data.
     </string>
     <!-- Message shown when user is almost at the limit of password attempts where the profile will be removed. [CHAR LIMIT=none] -->
     <string name="kg_failed_attempts_almost_at_erase_profile" product="default">
-       You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times.
-       After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+       You have incorrectly attempted to unlock the phone <xliff:g id="number">%1$d</xliff:g> times.
+       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
        the work profile will be removed, which will delete all profile data.
     </string>
     <!-- Message shown in dialog when user has exceeded the maximum attempts and the profile will be removed. [CHAR LIMIT=none] -->
@@ -255,18 +255,18 @@
     <!-- Message shown in dialog when user is almost at the limit where they will be
     locked out and may have to enter an alternate username/password to unlock the phone -->
     <string name="kg_failed_attempts_almost_at_login" product="tablet">
-       You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times.
-       After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+       You have incorrectly drawn your unlock pattern <xliff:g id="number">%1$d</xliff:g> times.
+       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
        you will be asked to unlock your tablet using an email account.\n\n
-       Try again in <xliff:g id="number">%d</xliff:g> seconds.
+       Try again in <xliff:g id="number">%3$d</xliff:g> seconds.
     </string>
     <!-- Message shown in dialog when user is almost at the limit where they will be
     locked out and may have to enter an alternate username/password to unlock the phone -->
     <string name="kg_failed_attempts_almost_at_login" product="default">
-       You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times.
-       After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+       You have incorrectly drawn your unlock pattern <xliff:g id="number">%1$d</xliff:g> times.
+       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
        you will be asked to unlock your phone using an email account.\n\n
-       Try again in <xliff:g id="number">%d</xliff:g> seconds.
+       Try again in <xliff:g id="number">%3$d</xliff:g> seconds.
     </string>
 
     <!-- Instructions telling the user that they entered the wrong SIM PIN for the last time.
@@ -308,31 +308,31 @@
     <string name="airplane_mode">Airplane mode</string>
 
     <!-- An explanation text that the pattern needs to be solved since the device has just been restarted. [CHAR LIMIT=80] -->
-    <string name="kg_prompt_reason_restart_pattern">Pattern required when you restart device.</string>
+    <string name="kg_prompt_reason_restart_pattern">Pattern required after device restarts</string>
 
     <!-- An explanation text that the pin needs to be entered since the device has just been restarted. [CHAR LIMIT=80] -->
-    <string name="kg_prompt_reason_restart_pin">PIN required when you restart device.</string>
+    <string name="kg_prompt_reason_restart_pin">PIN required after device restarts</string>
 
     <!-- An explanation text that the password needs to be entered since the device has just been restarted. [CHAR LIMIT=80] -->
-    <string name="kg_prompt_reason_restart_password">Password required when you restart device.</string>
+    <string name="kg_prompt_reason_restart_password">Password required after device restarts</string>
 
     <!-- An explanation text that the pattern needs to be solved since the user hasn't used strong authentication since quite some time. [CHAR LIMIT=80] -->
-    <string name="kg_prompt_reason_timeout_pattern">Pattern required for additional security.</string>
+    <string name="kg_prompt_reason_timeout_pattern">Pattern required for additional security</string>
 
     <!-- An explanation text that the pin needs to be entered since the user hasn't used strong authentication since quite some time. [CHAR LIMIT=80] -->
-    <string name="kg_prompt_reason_timeout_pin">PIN required for additional security.</string>
+    <string name="kg_prompt_reason_timeout_pin">PIN required for additional security</string>
 
     <!-- An explanation text that the password needs to be entered since the user hasn't used strong authentication since quite some time. [CHAR LIMIT=80] -->
-    <string name="kg_prompt_reason_timeout_password">Password required for additional security.</string>
+    <string name="kg_prompt_reason_timeout_password">Password required for additional security</string>
 
     <!-- An explanation text that the pattern needs to be solved since profiles have just been switched. [CHAR LIMIT=80] -->
-    <string name="kg_prompt_reason_switch_profiles_pattern">Pattern required when you switch profiles.</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern">Pattern required when you switch profiles</string>
 
     <!-- An explanation text that the pin needs to be entered since profiles have just been switched. [CHAR LIMIT=80] -->
-    <string name="kg_prompt_reason_switch_profiles_pin">PIN required when you switch profiles.</string>
+    <string name="kg_prompt_reason_switch_profiles_pin">PIN required when you switch profiles</string>
 
     <!-- An explanation text that the password needs to be entered since profiles have just been switched. [CHAR LIMIT=80] -->
-    <string name="kg_prompt_reason_switch_profiles_password">Password required when you switch profiles.</string>
+    <string name="kg_prompt_reason_switch_profiles_password">Password required when you switch profiles</string>
 
     <!-- An explanation text that the pattern needs to be solved since it hasn't been solved in a while. [CHAR LIMIT=80]-->
     <plurals name="kg_prompt_reason_time_pattern">
diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
index cbf22c0..40c11cf 100644
--- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
@@ -29,6 +29,7 @@
 import android.widget.Button;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.internal.telephony.IccCardConstants.State;
 import com.android.internal.widget.LockPatternUtils;
 
@@ -117,7 +118,7 @@
      * Shows the emergency dialer or returns the user to the existing call.
      */
     public void takeEmergencyCallAction() {
-        MetricsLogger.action(mContext, MetricsLogger.ACTION_EMERGENCY_CALL);
+        MetricsLogger.action(mContext, MetricsEvent.ACTION_EMERGENCY_CALL);
         // TODO: implement a shorter timeout once new PowerManager API is ready.
         // should be the equivalent to the old userActivity(EMERGENCY_CALL_TIMEOUT)
         mPowerManager.userActivity(SystemClock.uptimeMillis(), true);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index b03871a..64b443b 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -123,39 +123,45 @@
             mPendingLockCheck.cancel(false);
         }
 
+        final int userId = KeyguardUpdateMonitor.getCurrentUser();
         if (entry.length() <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) {
             // to avoid accidental lockout, only count attempts that are long enough to be a
             // real password. This may require some tweaking.
             setPasswordEntryInputEnabled(true);
-            onPasswordChecked(false /* matched */, 0, false /* not valid - too short */);
+            onPasswordChecked(userId, false /* matched */, 0, false /* not valid - too short */);
             return;
         }
 
         mPendingLockCheck = LockPatternChecker.checkPassword(
                 mLockPatternUtils,
                 entry,
-                KeyguardUpdateMonitor.getCurrentUser(),
+                userId,
                 new LockPatternChecker.OnCheckCallback() {
                     @Override
                     public void onChecked(boolean matched, int timeoutMs) {
                         setPasswordEntryInputEnabled(true);
                         mPendingLockCheck = null;
-                        onPasswordChecked(matched, timeoutMs, true /* isValidPassword */);
+                        onPasswordChecked(userId, matched, timeoutMs,
+                                true /* isValidPassword */);
                     }
                 });
     }
 
-    private void onPasswordChecked(boolean matched, int timeoutMs, boolean isValidPassword) {
+    private void onPasswordChecked(int userId, boolean matched, int timeoutMs,
+            boolean isValidPassword) {
+        boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId;
         if (matched) {
-            mDismissing = true;
-            mCallback.reportUnlockAttempt(true, 0);
-            mCallback.dismiss(true);
+            mCallback.reportUnlockAttempt(userId, true, 0);
+            if (dismissKeyguard) {
+                mDismissing = true;
+                mCallback.dismiss(true);
+            }
         } else {
             if (isValidPassword) {
-                mCallback.reportUnlockAttempt(false, timeoutMs);
+                mCallback.reportUnlockAttempt(userId, false, timeoutMs);
                 if (timeoutMs > 0) {
                     long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
-                            KeyguardUpdateMonitor.getCurrentUser(), timeoutMs);
+                            userId, timeoutMs);
                     handleAttemptLockout(deadline);
                 }
             }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
index 3a7e6d0..63dec8b 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
@@ -117,8 +117,10 @@
                 return R.string.kg_prompt_reason_restart_password;
             case PROMPT_REASON_TIMEOUT:
                 return R.string.kg_prompt_reason_timeout_password;
-            default:
+            case PROMPT_REASON_NONE:
                 return 0;
+            default:
+                return R.string.kg_prompt_reason_timeout_password;
         }
     }
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index 29b319f..be2701d 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -227,22 +227,23 @@
                 mPendingLockCheck.cancel(false);
             }
 
+            final int userId = KeyguardUpdateMonitor.getCurrentUser();
             if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {
                 mLockPatternView.enableInput();
-                onPatternChecked(false, 0, false /* not valid - too short */);
+                onPatternChecked(userId, false, 0, false /* not valid - too short */);
                 return;
             }
 
             mPendingLockCheck = LockPatternChecker.checkPattern(
                     mLockPatternUtils,
                     pattern,
-                    KeyguardUpdateMonitor.getCurrentUser(),
+                    userId,
                     new LockPatternChecker.OnCheckCallback() {
                         @Override
                         public void onChecked(boolean matched, int timeoutMs) {
                             mLockPatternView.enableInput();
                             mPendingLockCheck = null;
-                            onPatternChecked(matched, timeoutMs, true);
+                            onPatternChecked(userId, matched, timeoutMs, true);
                         }
                     });
             if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
@@ -250,18 +251,22 @@
             }
         }
 
-        private void onPatternChecked(boolean matched, int timeoutMs, boolean isValidPattern) {
+        private void onPatternChecked(int userId, boolean matched, int timeoutMs,
+                boolean isValidPattern) {
+            boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId;
             if (matched) {
-                mCallback.reportUnlockAttempt(true, 0);
-                mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
-                mCallback.dismiss(true);
+                mCallback.reportUnlockAttempt(userId, true, 0);
+                if (dismissKeyguard) {
+                    mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
+                    mCallback.dismiss(true);
+                }
             } else {
                 mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
                 if (isValidPattern) {
-                    mCallback.reportUnlockAttempt(false, timeoutMs);
+                    mCallback.reportUnlockAttempt(userId, false, timeoutMs);
                     if (timeoutMs > 0) {
                         long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
-                                KeyguardUpdateMonitor.getCurrentUser(), timeoutMs);
+                                userId, timeoutMs);
                         handleAttemptLockout(deadline);
                     }
                 }
@@ -334,7 +339,11 @@
                 mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_timeout_pattern,
                         true /* important */);
                 break;
+            case PROMPT_REASON_NONE:
+                break;
             default:
+                mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_timeout_pattern,
+                        true /* important */);
                 break;
         }
     }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
index f51e10f..cedd88d 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -103,8 +103,10 @@
                 return R.string.kg_prompt_reason_restart_pin;
             case PROMPT_REASON_TIMEOUT:
                 return R.string.kg_prompt_reason_timeout_pin;
-            default:
+            case PROMPT_REASON_NONE:
                 return 0;
+            default:
+                return R.string.kg_prompt_reason_timeout_pin;
         }
     }
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java
index 836c195..232d4d2 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java
@@ -36,11 +36,12 @@
 
     /**
      * Call to report an unlock attempt.
+     * @param userId id of the user whose unlock attempt is recorded.
      * @param success set to 'true' if user correctly entered security credentials.
      * @param timeoutMs timeout in milliseconds to wait before reattempting an unlock.
      *                  Only nonzero if 'success' is false
      */
-    void reportUnlockAttempt(boolean success, int timeoutMs);
+    void reportUnlockAttempt(int userId, boolean success, int timeoutMs);
 
     /**
      * Resets the keyguard view.
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index f45b9bd..409f6a7 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -205,7 +205,8 @@
 
         if (messageId != 0) {
             final String message = mContext.getString(messageId,
-                    KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(),
+                    KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(
+                            KeyguardUpdateMonitor.getCurrentUser()),
                     timeoutInSeconds);
             showDialog(null, message);
         }
@@ -249,16 +250,15 @@
         showDialog(null, message);
     }
 
-    private void reportFailedUnlockAttempt(int timeoutMs) {
+    private void reportFailedUnlockAttempt(int userId, int timeoutMs) {
         final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
-        final int failedAttempts = monitor.getFailedUnlockAttempts() + 1; // +1 for this time
+        final int failedAttempts = monitor.getFailedUnlockAttempts(userId) + 1; // +1 for this time
 
         if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
 
-        final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
         final DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager();
         final int failedAttemptsBeforeWipe =
-                dpm.getMaximumFailedPasswordsForWipe(null, currentUser);
+                dpm.getMaximumFailedPasswordsForWipe(null, userId);
 
         final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ?
                 (failedAttemptsBeforeWipe - failedAttempts)
@@ -268,9 +268,9 @@
             // N attempts. Once we get below the grace period, we post this dialog every time as a
             // clear warning until the deletion fires.
             // Check which profile has the strictest policy for failed password attempts
-            final int expiringUser = dpm.getProfileWithMinimumFailedPasswordsForWipe(currentUser);
+            final int expiringUser = dpm.getProfileWithMinimumFailedPasswordsForWipe(userId);
             int userType = USER_TYPE_PRIMARY;
-            if (expiringUser == currentUser) {
+            if (expiringUser == userId) {
                 // TODO: http://b/23522538
                 if (expiringUser != UserHandle.USER_SYSTEM) {
                     userType = USER_TYPE_SECONDARY_USER;
@@ -286,8 +286,8 @@
                 showWipeDialog(failedAttempts, userType);
             }
         }
-        monitor.reportFailedStrongAuthUnlockAttempt();
-        mLockPatternUtils.reportFailedPasswordAttempt(KeyguardUpdateMonitor.getCurrentUser());
+        monitor.reportFailedStrongAuthUnlockAttempt(userId);
+        mLockPatternUtils.reportFailedPasswordAttempt(userId);
         if (timeoutMs > 0) {
             showTimeoutDialog(timeoutMs);
         }
@@ -422,14 +422,13 @@
             return mIsVerifyUnlockOnly;
         }
 
-        public void reportUnlockAttempt(boolean success, int timeoutMs) {
+        public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
             KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
             if (success) {
                 monitor.clearFailedUnlockAttempts();
-                mLockPatternUtils.reportSuccessfulPasswordAttempt(
-                        KeyguardUpdateMonitor.getCurrentUser());
+                mLockPatternUtils.reportSuccessfulPasswordAttempt(userId);
             } else {
-                KeyguardSecurityContainer.this.reportFailedUnlockAttempt(timeoutMs);
+                KeyguardSecurityContainer.this.reportFailedUnlockAttempt(userId, timeoutMs);
             }
         }
 
@@ -445,7 +444,7 @@
         @Override
         public void userActivity() { }
         @Override
-        public void reportUnlockAttempt(boolean success, int timeoutMs) { }
+        public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { }
         @Override
         public boolean isVerifyUnlockOnly() { return false; }
         @Override
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java
index 38302fb..aa74940 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java
@@ -34,6 +34,26 @@
     int PROMPT_REASON_TIMEOUT = 2;
 
     /**
+     * Strong auth is required because a device admin requested it.
+     */
+    int PROMPT_REASON_DEVICE_ADMIN = 3;
+
+    /**
+     * Some auth is required because the user force locked.
+     */
+    int PROMPT_REASON_USER_REQUEST = 4;
+
+    /**
+     * Some auth is required because too many wrong credentials led to a lockout.
+     */
+    int PROMPT_REASON_AFTER_LOCKOUT = 5;
+
+    /**
+     * Some auth is required because a single wrong credential has been tried.
+     */
+    int PROMPT_REASON_WRONG_CREDENTIAL = 6;
+
+    /**
      * Interface back to keyguard to tell it when security
      * @param callback
      */
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 8102c34..a8419bf 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -188,7 +188,7 @@
 
     /** Tracks whether strong authentication hasn't been used since quite some time per user. */
     private ArraySet<Integer> mStrongAuthNotTimedOut = new ArraySet<>();
-    private final StrongAuthTracker mStrongAuthTracker = new StrongAuthTracker();
+    private final StrongAuthTracker mStrongAuthTracker;
 
     private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
             mCallbacks = Lists.newArrayList();
@@ -871,6 +871,9 @@
     }
 
     public class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
+        public StrongAuthTracker(Context context) {
+            super(context);
+        }
 
         public boolean isUnlockingWithFingerprintAllowed() {
             int userId = getCurrentUser();
@@ -981,6 +984,7 @@
         mSubscriptionManager = SubscriptionManager.from(context);
         mAlarmManager = context.getSystemService(AlarmManager.class);
         mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
+        mStrongAuthTracker = new StrongAuthTracker(context);
 
         // Since device can't be un-provisioned, we only need to register a content observer
         // to update mDeviceProvisioned when we are...
@@ -1552,12 +1556,12 @@
         mFailedAttempts.delete(sCurrentUser);
     }
 
-    public int getFailedUnlockAttempts() {
-        return mFailedAttempts.get(sCurrentUser, 0);
+    public int getFailedUnlockAttempts(int userId) {
+        return mFailedAttempts.get(userId, 0);
     }
 
-    public void reportFailedStrongAuthUnlockAttempt() {
-        mFailedAttempts.put(sCurrentUser, getFailedUnlockAttempts() + 1);
+    public void reportFailedStrongAuthUnlockAttempt(int userId) {
+        mFailedAttempts.put(userId, getFailedUnlockAttempts(userId) + 1);
     }
 
     public void clearFingerprintRecognized() {
diff --git a/packages/MtpDocumentsProvider/Android.mk b/packages/MtpDocumentsProvider/Android.mk
index 3c2fa36..b31b0b1 100644
--- a/packages/MtpDocumentsProvider/Android.mk
+++ b/packages/MtpDocumentsProvider/Android.mk
@@ -6,6 +6,8 @@
 LOCAL_PACKAGE_NAME := MtpDocumentsProvider
 LOCAL_CERTIFICATE := media
 LOCAL_PRIVILEGED_MODULE := true
+LOCAL_JNI_SHARED_LIBRARIES := libappfuse_jni
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 
 include $(BUILD_PACKAGE)
-include $(LOCAL_PATH)/tests/Android.mk
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/MtpDocumentsProvider/jni/Android.mk b/packages/MtpDocumentsProvider/jni/Android.mk
new file mode 100644
index 0000000..d545b14
--- /dev/null
+++ b/packages/MtpDocumentsProvider/jni/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    com_android_mtp_AppFuse.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libandroid_runtime \
+    libnativehelper \
+    liblog
+
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+LOCAL_MODULE := libappfuse_jni
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp b/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
new file mode 100644
index 0000000..2b44d51
--- /dev/null
+++ b/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
@@ -0,0 +1,479 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specic language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "AppFuseJNI"
+#include "utils/Log.h"
+
+#include <assert.h>
+#include <dirent.h>
+#include <inttypes.h>
+
+#include <linux/fuse.h>
+#include <sys/stat.h>
+
+#include <map>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "nativehelper/ScopedPrimitiveArray.h"
+#include "nativehelper/ScopedLocalRef.h"
+
+namespace {
+
+// The numbers came from sdcard.c.
+// Maximum number of bytes to write/read in one request/one reply.
+constexpr size_t MAX_WRITE = 256 * 1024;
+constexpr size_t MAX_READ = 128 * 1024;
+
+constexpr size_t NUM_MAX_HANDLES = 1024;
+
+// Largest possible request.
+// The request size is bounded by the maximum size of a FUSE_WRITE request
+// because it has the largest possible data payload.
+constexpr size_t MAX_REQUEST_SIZE = sizeof(struct fuse_in_header) +
+        sizeof(struct fuse_write_in) + (MAX_WRITE > MAX_READ ? MAX_WRITE : MAX_READ);
+
+static jclass app_fuse_class;
+static jmethodID app_fuse_get_file_size;
+static jmethodID app_fuse_read_object_bytes;
+static jfieldID app_fuse_buffer;
+
+// NOTE:
+// FuseRequest and FuseResponse shares the same buffer to save memory usage, so the handlers must
+// not access input buffer after writing data to output buffer.
+struct FuseRequest {
+    char buffer[MAX_REQUEST_SIZE];
+    FuseRequest() {}
+    const struct fuse_in_header& header() const {
+        return *(const struct fuse_in_header*) buffer;
+    }
+    void* data() {
+        return (buffer + sizeof(struct fuse_in_header));
+    }
+    size_t data_length() const {
+        return header().len - sizeof(struct fuse_in_header);
+    }
+};
+
+template<typename T>
+class FuseResponse {
+   size_t size_;
+   T* const buffer_;
+public:
+   FuseResponse(void* buffer) : size_(0), buffer_(static_cast<T*>(buffer)) {}
+
+   void prepare_buffer(size_t size = sizeof(T)) {
+       memset(buffer_, 0, size);
+       size_ = size;
+   }
+
+   void set_size(size_t size) {
+       size_ = size;
+   }
+
+   size_t size() const { return size_; }
+   T* data() const { return buffer_; }
+};
+
+class ScopedFd {
+    int mFd;
+
+public:
+    explicit ScopedFd(int fd) : mFd(fd) {}
+    ~ScopedFd() {
+        close(mFd);
+    }
+    operator int() {
+        return mFd;
+    }
+};
+
+/**
+ * Fuse implementation consists of handlers parsing FUSE commands.
+ */
+class AppFuse {
+    JNIEnv* env_;
+    jobject self_;
+
+    // Map between file handle and inode.
+    std::map<uint32_t, uint64_t> handles_;
+    uint32_t handle_counter_;
+
+public:
+    AppFuse(JNIEnv* env, jobject self) :
+        env_(env), self_(self), handle_counter_(0) {}
+
+    bool handle_fuse_request(int fd, FuseRequest* req) {
+        ALOGV("Request op=%d", req->header().opcode);
+        switch (req->header().opcode) {
+            // TODO: Handle more operations that are enough to provide seekable
+            // FD.
+            case FUSE_LOOKUP:
+                invoke_handler(fd, req, &AppFuse::handle_fuse_lookup);
+                return true;
+            case FUSE_INIT:
+                invoke_handler(fd, req, &AppFuse::handle_fuse_init);
+                return true;
+            case FUSE_GETATTR:
+                invoke_handler(fd, req, &AppFuse::handle_fuse_getattr);
+                return true;
+            case FUSE_FORGET:
+                return false;
+            case FUSE_OPEN:
+                invoke_handler(fd, req, &AppFuse::handle_fuse_open);
+                return true;
+            case FUSE_READ:
+                invoke_handler(fd, req, &AppFuse::handle_fuse_read);
+                return true;
+            case FUSE_RELEASE:
+                invoke_handler(fd, req, &AppFuse::handle_fuse_release);
+                return true;
+            case FUSE_FLUSH:
+                invoke_handler(fd, req, &AppFuse::handle_fuse_flush);
+                return true;
+            default: {
+                ALOGV("NOTIMPL op=%d uniq=%" PRIx64 " nid=%" PRIx64 "\n",
+                      req->header().opcode,
+                      req->header().unique,
+                      req->header().nodeid);
+                fuse_reply(fd, req->header().unique, -ENOSYS, NULL, 0);
+                return true;
+            }
+        }
+    }
+
+private:
+    int handle_fuse_lookup(const fuse_in_header& header,
+                           const char* name,
+                           FuseResponse<fuse_entry_out>* out) {
+        if (header.nodeid != 1) {
+            return -ENOENT;
+        }
+
+        const int n = atoi(name);
+        if (n == 0) {
+            return -ENOENT;
+        }
+
+        int64_t size = get_file_size(n);
+        if (size < 0) {
+            return -ENOENT;
+        }
+
+        out->prepare_buffer();
+        out->data()->nodeid = n;
+        out->data()->attr_valid = 10;
+        out->data()->entry_valid = 10;
+        out->data()->attr.ino = n;
+        out->data()->attr.mode = S_IFREG | 0777;
+        out->data()->attr.size = size;
+        return 0;
+    }
+
+    int handle_fuse_init(const fuse_in_header&,
+                         const fuse_init_in* in,
+                         FuseResponse<fuse_init_out>* out) {
+        // Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
+        // defined (fuse version 7.6). The structure is the same from 7.6 through
+        // 7.22. Beginning with 7.23, the structure increased in size and added
+        // new parameters.
+        if (in->major != FUSE_KERNEL_VERSION || in->minor < 6) {
+            ALOGE("Fuse kernel version mismatch: Kernel version %d.%d, "
+                  "Expected at least %d.6",
+                  in->major, in->minor, FUSE_KERNEL_VERSION);
+            return -1;
+        }
+
+        // Before writing |out|, we need to copy data from |in|.
+        const uint32_t minor = in->minor;
+        const uint32_t max_readahead = in->max_readahead;
+
+        // We limit ourselves to 15 because we don't handle BATCH_FORGET yet
+        size_t response_size = sizeof(fuse_init_out);
+#if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
+        // FUSE_KERNEL_VERSION >= 23.
+
+        // If the kernel only works on minor revs older than or equal to 22,
+        // then use the older structure size since this code only uses the 7.22
+        // version of the structure.
+        if (minor <= 22) {
+            response_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
+        }
+#endif
+        out->prepare_buffer(response_size);
+        out->data()->major = FUSE_KERNEL_VERSION;
+        out->data()->minor = std::min(minor, 15u);
+        out->data()->max_readahead = max_readahead;
+        out->data()->flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
+        out->data()->max_background = 32;
+        out->data()->congestion_threshold = 32;
+        out->data()->max_write = MAX_WRITE;
+
+        return 0;
+    }
+
+    int handle_fuse_getattr(const fuse_in_header& header,
+                            const fuse_getattr_in* /* in */,
+                            FuseResponse<fuse_attr_out>* out) {
+        out->prepare_buffer();
+        out->data()->attr_valid = 10;
+        out->data()->attr.ino = header.nodeid;
+        if (header.nodeid == 1) {
+            out->data()->attr.mode = S_IFDIR | 0777;
+            out->data()->attr.size = 0;
+        } else {
+            int64_t size = get_file_size(header.nodeid);
+            if (size < 0) {
+                return -ENOENT;
+            }
+            out->data()->attr.mode = S_IFREG | 0777;
+            out->data()->attr.size = size;
+        }
+
+        return 0;
+    }
+
+    int handle_fuse_open(const fuse_in_header& header,
+                         const fuse_open_in* /* in */,
+                         FuseResponse<fuse_open_out>* out) {
+        if (handles_.size() >= NUM_MAX_HANDLES) {
+            // Too many open files.
+            return -EMFILE;
+        }
+        uint32_t handle;
+        do {
+           handle = handle_counter_++;
+        } while (handles_.count(handle) != 0);
+        handles_.insert(std::make_pair(handle, header.nodeid));
+
+        out->prepare_buffer();
+        out->data()->fh = handle;
+        return 0;
+    }
+
+    int handle_fuse_read(const fuse_in_header& /* header */,
+                         const fuse_read_in* in,
+                         FuseResponse<void>* out) {
+        if (in->size > MAX_READ) {
+            return -EINVAL;
+        }
+        const std::map<uint32_t, uint64_t>::iterator it = handles_.find(in->fh);
+        if (it == handles_.end()) {
+            return -EBADF;
+        }
+        uint64_t offset = in->offset;
+        uint32_t size = in->size;
+
+        // Overwrite the size after writing data.
+        out->prepare_buffer(0);
+        const int64_t result = get_object_bytes(it->second, offset, size, out->data());
+        if (result < 0) {
+            return result;
+        }
+        out->set_size(result);
+        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;
+    }
+
+    int handle_fuse_flush(const fuse_in_header& /* header */,
+                          const void* /* in */,
+                          FuseResponse<void>* /* out */) {
+        return 0;
+    }
+
+    template <typename T, typename S>
+    void invoke_handler(int fd,
+                        FuseRequest* request,
+                        int (AppFuse::*handler)(const fuse_in_header&,
+                                                const T*,
+                                                FuseResponse<S>*)) {
+        FuseResponse<S> response(request->data());
+        const int reply_code = (this->*handler)(
+                request->header(),
+                static_cast<const T*>(request->data()),
+                &response);
+        fuse_reply(
+                fd,
+                request->header().unique,
+                reply_code,
+                request->data(),
+                response.size());
+    }
+
+    int64_t get_file_size(int inode) {
+        return static_cast<int64_t>(env_->CallLongMethod(
+                self_,
+                app_fuse_get_file_size,
+                static_cast<int>(inode)));
+    }
+
+    int64_t get_object_bytes(
+            int inode,
+            uint64_t offset,
+            uint32_t size,
+            void* buf) {
+        const jlong read_size = env_->CallLongMethod(
+                self_,
+                app_fuse_read_object_bytes,
+                static_cast<jint>(inode),
+                static_cast<jlong>(offset),
+                static_cast<jlong>(size));
+        if (read_size <= 0) {
+            return read_size;
+        }
+        ScopedLocalRef<jbyteArray> array(
+                env_, static_cast<jbyteArray>(env_->GetObjectField(self_, app_fuse_buffer)));
+        if (array.get() == nullptr) {
+            return -EFAULT;
+        }
+        ScopedByteArrayRO bytes(env_, array.get());
+        if (bytes.get() == nullptr) {
+            return -ENOMEM;
+        }
+        memcpy(buf, bytes.get(), read_size);
+        return read_size;
+    }
+
+    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.
+        if (reply_code != 0) {
+            reply_size = 0;
+        }
+
+        struct fuse_out_header hdr;
+        hdr.len = reply_size + sizeof(hdr);
+        hdr.error = reply_code;
+        hdr.unique = unique;
+
+        struct iovec vec[2];
+        vec[0].iov_base = &hdr;
+        vec[0].iov_len = sizeof(hdr);
+        vec[1].iov_base = reply_data;
+        vec[1].iov_len = reply_size;
+
+        const int res = writev(fd, vec, reply_size != 0 ? 2 : 1);
+        if (res < 0) {
+            ALOGE("*** REPLY FAILED *** %d\n", errno);
+        }
+    }
+};
+
+jboolean com_android_mtp_AppFuse_start_app_fuse_loop(
+        JNIEnv* env, jobject self, jint jfd) {
+    ScopedFd fd(static_cast<int>(jfd));
+    AppFuse appfuse(env, self);
+
+    ALOGD("Start fuse loop.");
+    while (true) {
+        FuseRequest request;
+
+        const ssize_t result = TEMP_FAILURE_RETRY(
+                read(fd, request.buffer, sizeof(request.buffer)));
+        if (result < 0) {
+            if (errno == ENODEV) {
+                ALOGE("Someone stole our marbles!\n");
+                return JNI_FALSE;
+            }
+            ALOGE("Failed to read bytes from FD: errno=%d\n", errno);
+            continue;
+        }
+
+        const size_t length = static_cast<size_t>(result);
+        if (length < sizeof(struct fuse_in_header)) {
+            ALOGE("request too short: len=%zu\n", length);
+            continue;
+        }
+
+        if (request.header().len != length) {
+            ALOGE("malformed header: len=%zu, hdr->len=%u\n",
+                  length, request.header().len);
+            continue;
+        }
+
+        if (!appfuse.handle_fuse_request(fd, &request)) {
+            return JNI_TRUE;
+        }
+    }
+}
+
+static const JNINativeMethod gMethods[] = {
+    {
+        "native_start_app_fuse_loop",
+        "(I)Z",
+        (void *) com_android_mtp_AppFuse_start_app_fuse_loop
+    }
+};
+
+}
+
+jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) {
+    JNIEnv* env = nullptr;
+    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+        ALOGE("ERROR: GetEnv failed\n");
+        return -1;
+
+    }
+    assert(env != nullptr);
+
+    jclass clazz = env->FindClass("com/android/mtp/AppFuse");
+    if (clazz == nullptr) {
+        ALOGE("Can't find com/android/mtp/AppFuse");
+        return -1;
+    }
+
+    app_fuse_class = static_cast<jclass>(env->NewGlobalRef(clazz));
+    if (app_fuse_class == nullptr) {
+        ALOGE("Can't obtain global reference for com/android/mtp/AppFuse");
+        return -1;
+    }
+
+    app_fuse_get_file_size = env->GetMethodID(
+            app_fuse_class, "getFileSize", "(I)J");
+    if (app_fuse_get_file_size == nullptr) {
+        ALOGE("Can't find getFileSize");
+        return -1;
+    }
+
+    app_fuse_read_object_bytes = env->GetMethodID(
+            app_fuse_class, "readObjectBytes", "(IJJ)J");
+    if (app_fuse_read_object_bytes == nullptr) {
+        ALOGE("Can't find readObjectBytes");
+        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 int result = android::AndroidRuntime::registerNativeMethods(
+            env, "com/android/mtp/AppFuse", gMethods, NELEM(gMethods));
+    if (result < 0) {
+        return -1;
+    }
+
+    return JNI_VERSION_1_4;
+}
diff --git a/packages/MtpDocumentsProvider/proguard.flags b/packages/MtpDocumentsProvider/proguard.flags
new file mode 100644
index 0000000..e660121
--- /dev/null
+++ b/packages/MtpDocumentsProvider/proguard.flags
@@ -0,0 +1,4 @@
+# Keeps methods that are invoked by JNI.
+-keepclassmembers class * {
+  @com.android.mtp.annotations.UsedByNative *;
+}
diff --git a/packages/MtpDocumentsProvider/res/values/strings.xml b/packages/MtpDocumentsProvider/res/values/strings.xml
index 7a4087b..43a420c 100644
--- a/packages/MtpDocumentsProvider/res/values/strings.xml
+++ b/packages/MtpDocumentsProvider/res/values/strings.xml
@@ -16,9 +16,13 @@
 
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Title of the external storage application [CHAR LIMIT=32] -->
-    <string name="app_label">MTP Storage</string>
+    <string name="app_label">Files</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] -->
     <string name="root_name"><xliff:g id="device_model" example="Nexus 9">%1$s</xliff:g> <xliff:g id="storage_name" example="Internal Storage">%2$s</xliff:g></string>
+    <!-- Title of notification showing Files app is accessing files in a MTP device. [CHAR LIMIT=60]-->
+    <string name="accessing_notification_title">Accessing files from <xliff:g id="device_model" example="Nexus 9">%1$s</xliff:g></string>
+    <!-- Description of notification showing Files app is accessing files in a MTP device. [CHAR LIMIT=60]-->
+    <string name="accessing_notification_description">Don\'t disconnect the device</string>
 </resources>
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java b/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
new file mode 100644
index 0000000..6a98405
--- /dev/null
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.annotation.WorkerThread;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.storage.StorageManager;
+import android.system.OsConstants;
+import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+import com.android.mtp.annotations.UsedByNative;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+public class AppFuse {
+    static {
+        System.loadLibrary("appfuse_jni");
+    }
+
+    /**
+     * Max read amount specified at the FUSE kernel implementation.
+     * The value is copied from sdcard.c.
+     */
+    static final int MAX_READ = 128 * 1024;
+
+    private final String mName;
+    private final Callback mCallback;
+
+    /**
+     * Buffer for read bytes request.
+     * Don't use the buffer from the out of AppFuseMessageThread.
+     */
+    private byte[] mBuffer = new byte[MAX_READ];
+
+    private Thread mMessageThread;
+    private ParcelFileDescriptor mDeviceFd;
+
+    AppFuse(String name, Callback callback) {
+        mName = name;
+        mCallback = callback;
+    }
+
+    void mount(StorageManager storageManager) throws IOException {
+        Preconditions.checkState(mDeviceFd == null);
+        mDeviceFd = storageManager.mountAppFuse(mName);
+        mMessageThread = new AppFuseMessageThread(mDeviceFd.dup().detachFd());
+        mMessageThread.start();
+    }
+
+    @VisibleForTesting
+    void close() {
+        try {
+            // Remote side of ParcelFileDescriptor is tracking the close of mDeviceFd, and unmount
+            // the corresponding fuse file system. The mMessageThread will receive FUSE_FORGET, and
+            // then terminate itself.
+            mDeviceFd.close();
+            mMessageThread.join();
+        } catch (IOException exp) {
+            Log.e(MtpDocumentsProvider.TAG, "Failed to close device FD.", exp);
+        } catch (InterruptedException exp) {
+            Log.e(MtpDocumentsProvider.TAG, "Failed to terminate message thread.", exp);
+        }
+    }
+
+    public ParcelFileDescriptor openFile(int i) throws FileNotFoundException {
+        return ParcelFileDescriptor.open(new File(
+                getMountPoint(),
+                Integer.toString(i)),
+                ParcelFileDescriptor.MODE_READ_ONLY);
+    }
+
+    File getMountPoint() {
+        return new File("/mnt/appfuse/" + Process.myUid() + "_" + mName);
+    }
+
+    static interface Callback {
+        /**
+         * Returns file size for the given inode.
+         * @param inode
+         * @return File size. Must not be negative.
+         * @throws FileNotFoundException
+         */
+        long getFileSize(int inode) throws FileNotFoundException;
+
+        /**
+         * Returns flie bytes for the give inode.
+         * @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
+         */
+        long readObjectBytes(int inode, long offset, long size, byte[] bytes) throws IOException;
+    }
+
+    @UsedByNative("com_android_mtp_AppFuse.cpp")
+    @WorkerThread
+    private long getFileSize(int inode) {
+        try {
+            return mCallback.getFileSize(inode);
+        } catch (FileNotFoundException e) {
+            return -OsConstants.ENOENT;
+        }
+    }
+
+    @UsedByNative("com_android_mtp_AppFuse.cpp")
+    @WorkerThread
+    private long readObjectBytes(int inode, long offset, long size) {
+        if (offset < 0 || size < 0 || size > MAX_READ) {
+            return -OsConstants.EINVAL;
+        }
+        try {
+            // 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;
+        }
+    }
+
+    private native boolean native_start_app_fuse_loop(int fd);
+
+    private class AppFuseMessageThread extends Thread {
+        /**
+         * File descriptor used by native loop.
+         * It's owned by native loop and does not need to close here.
+         */
+        private final int mRawFd;
+
+        AppFuseMessageThread(int fd) {
+            super("AppFuseMessageThread");
+            mRawFd = fd;
+        }
+
+        @Override
+        public void run() {
+            native_start_app_fuse_loop(mRawFd);
+        }
+    }
+}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java b/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
index cb49535e..ac47067 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
@@ -66,10 +66,13 @@
         database.beginTransaction();
         try {
             final ContentValues[] valuesList = new ContentValues[1];
+            final ContentValues[] extraValuesList = new ContentValues[1];
             valuesList[0] = new ContentValues();
-            MtpDatabase.getDeviceDocumentValues(valuesList[0], device);
+            extraValuesList[0] = new ContentValues();
+            MtpDatabase.getDeviceDocumentValues(valuesList[0], extraValuesList[0], device);
             final boolean changed = putDocuments(
                     valuesList,
+                    extraValuesList,
                     COLUMN_PARENT_DOCUMENT_ID + " IS NULL",
                     EMPTY_ARGS,
                     /* heuristic */ false,
@@ -88,7 +91,7 @@
      * @param roots List of root information.
      * @return If roots are added or removed from the database.
      */
-    synchronized boolean putRootDocuments(
+    synchronized boolean putStorageDocuments(
             String parentDocumentId, Resources resources, MtpRoot[] roots) {
         final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
         database.beginTransaction();
@@ -109,36 +112,21 @@
                     throw new Error("Unexpected map mode.");
             }
             final ContentValues[] valuesList = new ContentValues[roots.length];
+            final ContentValues[] extraValuesList = new ContentValues[roots.length];
             for (int i = 0; i < roots.length; i++) {
                 valuesList[i] = new ContentValues();
+                extraValuesList[i] = new ContentValues();
                 MtpDatabase.getStorageDocumentValues(
-                        valuesList[i], resources, parentDocumentId, roots[i]);
+                        valuesList[i], extraValuesList[i], resources, parentDocumentId, roots[i]);
             }
             final boolean changed = putDocuments(
                     valuesList,
+                    extraValuesList,
                     COLUMN_PARENT_DOCUMENT_ID + "=?",
                     strings(parentDocumentId),
                     heuristic,
                     mapColumn);
-            final ContentValues values = new ContentValues();
-            int i = 0;
-            for (final MtpRoot root : roots) {
-                // Use the same value for the root ID and the corresponding document ID.
-                final String documentId = valuesList[i++].getAsString(Document.COLUMN_DOCUMENT_ID);
-                // If it fails to insert/update documents, the document ID will be set with -1.
-                // In this case we don't insert/update root extra information neither.
-                if (documentId == null) {
-                    continue;
-                }
-                values.put(Root.COLUMN_ROOT_ID, documentId);
-                values.put(
-                        Root.COLUMN_FLAGS,
-                        Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE);
-                values.put(Root.COLUMN_AVAILABLE_BYTES, root.mFreeSpace);
-                values.put(Root.COLUMN_CAPACITY_BYTES, root.mMaxCapacity);
-                values.put(Root.COLUMN_MIME_TYPES, "");
-                database.replace(TABLE_ROOT_EXTRA, null, values);
-            }
+
             database.setTransactionSuccessful();
             return changed;
         } finally {
@@ -176,6 +164,7 @@
         }
         putDocuments(
                 valuesList,
+                null,
                 COLUMN_PARENT_DOCUMENT_ID + "=?",
                 strings(parentId),
                 heuristic,
@@ -257,6 +246,7 @@
      * rows. If the methods adds rows to database, it updates valueList with correct document ID.
      *
      * @param valuesList Values for documents to be stored in the database.
+     * @param rootExtraValuesList Values for root extra to be stored in the database.
      * @param selection SQL where closure to select rows that shares the same parent.
      * @param args Argument for selection SQL.
      * @param heuristic Whether the mapping mode is heuristic.
@@ -264,6 +254,7 @@
      */
     private boolean putDocuments(
             ContentValues[] valuesList,
+            @Nullable ContentValues[] rootExtraValuesList,
             String selection,
             String[] args,
             boolean heuristic,
@@ -272,7 +263,14 @@
         boolean added = false;
         database.beginTransaction();
         try {
-            for (final ContentValues values : valuesList) {
+            for (int i = 0; i < valuesList.length; i++) {
+                final ContentValues values = valuesList[i];
+                final ContentValues rootExtraValues;
+                if (rootExtraValuesList != null) {
+                    rootExtraValues = rootExtraValuesList[i];
+                } else {
+                    rootExtraValues = null;
+                }
                 final Cursor candidateCursor = database.query(
                         TABLE_DOCUMENTS,
                         strings(Document.COLUMN_DOCUMENT_ID),
@@ -290,25 +288,26 @@
                     final long rowId;
                     if (candidateCursor.getCount() == 0) {
                         rowId = database.insert(TABLE_DOCUMENTS, null, values);
-                        if (rowId == -1) {
-                            throw new SQLiteException("Failed to put a document into database.");
-                        }
                         added = true;
                     } else if (!heuristic) {
                         candidateCursor.moveToNext();
-                        final String documentId = candidateCursor.getString(0);
-                        rowId = database.update(
+                        rowId = candidateCursor.getLong(0);
+                        database.update(
                                 TABLE_DOCUMENTS,
                                 values,
                                 SELECTION_DOCUMENT_ID,
-                                strings(documentId));
+                                strings(rowId));
                     } else {
                         values.put(COLUMN_ROW_STATE, ROW_STATE_PENDING);
-                        rowId = database.insert(TABLE_DOCUMENTS, null, values);
+                        rowId = database.insertOrThrow(TABLE_DOCUMENTS, null, values);
                     }
                     // Document ID is a primary integer key of the table. So the returned row
                     // IDs should be same with the document ID.
                     values.put(Document.COLUMN_DOCUMENT_ID, rowId);
+                    if (rootExtraValues != null) {
+                        rootExtraValues.put(Root.COLUMN_ROOT_ID, rowId);
+                        database.replace(TABLE_ROOT_EXTRA, null, rootExtraValues);
+                    }
                 } finally {
                     candidateCursor.close();
                 }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
index 10941eb..112914e 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
@@ -23,6 +23,9 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.MatrixCursor;
+import android.database.MatrixCursor.RowBuilder;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteQueryBuilder;
@@ -106,17 +109,93 @@
      * @return Database cursor.
      */
     Cursor queryRoots(String[] columnNames) {
-        final SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
-        builder.setTables(JOIN_ROOTS);
-        builder.setProjectionMap(COLUMN_MAP_ROOTS);
-        return builder.query(
-                mDatabase,
-                columnNames,
-                COLUMN_ROW_STATE + " IN (?, ?) AND " + COLUMN_DOCUMENT_TYPE + " = ?",
-                strings(ROW_STATE_VALID, ROW_STATE_INVALIDATED, DOCUMENT_TYPE_STORAGE),
+        final String selection =
+                COLUMN_ROW_STATE + " IN (?, ?) AND " + COLUMN_DOCUMENT_TYPE + " = ?";
+        final Cursor deviceCursor = mDatabase.query(
+                TABLE_DOCUMENTS,
+                strings(COLUMN_DEVICE_ID),
+                selection,
+                strings(ROW_STATE_VALID, ROW_STATE_INVALIDATED, DOCUMENT_TYPE_DEVICE),
+                COLUMN_DEVICE_ID,
                 null,
                 null,
                 null);
+
+        try {
+            final SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
+            builder.setTables(JOIN_ROOTS);
+            builder.setProjectionMap(COLUMN_MAP_ROOTS);
+            final MatrixCursor result = new MatrixCursor(columnNames);
+            final ContentValues values = new ContentValues();
+
+            while (deviceCursor.moveToNext()) {
+                final int deviceId = deviceCursor.getInt(0);
+                final Cursor storageCursor = builder.query(
+                        mDatabase,
+                        columnNames,
+                        selection + " AND " + COLUMN_DEVICE_ID + " = ?",
+                        strings(ROW_STATE_VALID,
+                                ROW_STATE_INVALIDATED,
+                                DOCUMENT_TYPE_STORAGE,
+                                deviceId),
+                        null,
+                        null,
+                        null);
+                try {
+                    values.clear();
+                    if (storageCursor.getCount() == 1) {
+                        storageCursor.moveToNext();
+                        DatabaseUtils.cursorRowToContentValues(storageCursor, values);
+                    } else {
+                        final Cursor cursor = builder.query(
+                                mDatabase,
+                                columnNames,
+                                selection + " AND " + COLUMN_DEVICE_ID + " = ?",
+                                strings(ROW_STATE_VALID,
+                                        ROW_STATE_INVALIDATED,
+                                        DOCUMENT_TYPE_DEVICE,
+                                        deviceId),
+                                null,
+                                null,
+                                null);
+                        try {
+                            cursor.moveToNext();
+                            DatabaseUtils.cursorRowToContentValues(cursor, values);
+                        } finally {
+                            cursor.close();
+                        }
+
+                        long capacityBytes = 0;
+                        long availableBytes = 0;
+                        int capacityIndex = cursor.getColumnIndex(Root.COLUMN_CAPACITY_BYTES);
+                        int availableIndex = cursor.getColumnIndex(Root.COLUMN_AVAILABLE_BYTES);
+                        while (storageCursor.moveToNext()) {
+                            // If requested columnNames does not include COLUMN_XXX_BYTES, we don't
+                            // calculate corresponding values.
+                            if (capacityIndex != -1) {
+                                capacityBytes += cursor.getLong(capacityIndex);
+                            }
+                            if (availableIndex != -1) {
+                                availableBytes += cursor.getLong(availableIndex);
+                            }
+                        }
+                        values.put(Root.COLUMN_CAPACITY_BYTES, capacityBytes);
+                        values.put(Root.COLUMN_AVAILABLE_BYTES, availableBytes);
+                    }
+                } finally {
+                    storageCursor.close();
+                }
+
+                final RowBuilder row = result.newRow();
+                for (final String key : values.keySet()) {
+                    row.add(key, values.get(key));
+                }
+            }
+
+            return result;
+        } finally {
+            deviceCursor.close();
+        }
     }
 
     /**
@@ -380,7 +459,10 @@
         context.deleteDatabase(DATABASE_NAME);
     }
 
-    static void getDeviceDocumentValues(ContentValues values, MtpDeviceRecord device) {
+    static void getDeviceDocumentValues(
+            ContentValues values,
+            ContentValues extraValues,
+            MtpDeviceRecord device) {
         values.clear();
         values.put(COLUMN_DEVICE_ID, device.deviceId);
         values.putNull(COLUMN_STORAGE_ID);
@@ -394,11 +476,15 @@
         values.putNull(Document.COLUMN_LAST_MODIFIED);
         values.put(Document.COLUMN_ICON, R.drawable.ic_root_mtp);
         values.put(Document.COLUMN_FLAGS, 0);
-        long size = 0;
-        for (final MtpRoot root : device.roots) {
-            size += root.mMaxCapacity - root.mFreeSpace;
-        }
-        values.put(Document.COLUMN_SIZE, size);
+        values.putNull(Document.COLUMN_SIZE);
+
+        extraValues.clear();
+        extraValues.put(
+                Root.COLUMN_FLAGS,
+                Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE);
+        extraValues.putNull(Root.COLUMN_AVAILABLE_BYTES);
+        extraValues.putNull(Root.COLUMN_CAPACITY_BYTES);
+        extraValues.put(Root.COLUMN_MIME_TYPES, "");
     }
 
     /**
@@ -408,7 +494,11 @@
      * @param root Root to be converted {@link ContentValues}.
      */
     static void getStorageDocumentValues(
-            ContentValues values, Resources resources, String parentDocumentId, MtpRoot root) {
+            ContentValues values,
+            ContentValues extraValues,
+            Resources resources,
+            String parentDocumentId,
+            MtpRoot root) {
         values.clear();
         values.put(COLUMN_DEVICE_ID, root.mDeviceId);
         values.put(COLUMN_STORAGE_ID, root.mStorageId);
@@ -424,6 +514,13 @@
         values.put(Document.COLUMN_FLAGS, 0);
         values.put(Document.COLUMN_SIZE,
                 (int) Math.min(root.mMaxCapacity - root.mFreeSpace, Integer.MAX_VALUE));
+
+        extraValues.put(
+                Root.COLUMN_FLAGS,
+                Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE);
+        extraValues.put(Root.COLUMN_AVAILABLE_BYTES, root.mFreeSpace);
+        extraValues.put(Root.COLUMN_CAPACITY_BYTES, root.mMaxCapacity);
+        extraValues.put(Root.COLUMN_MIME_TYPES, "");
     }
 
     /**
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
index a233589..f252e0f 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
@@ -126,14 +126,14 @@
             Document.COLUMN_LAST_MODIFIED + " INTEGER," +
             Document.COLUMN_ICON + " INTEGER," +
             Document.COLUMN_FLAGS + " INTEGER NOT NULL," +
-            Document.COLUMN_SIZE + " INTEGER NOT NULL);";
+            Document.COLUMN_SIZE + " INTEGER);";
 
     static final String QUERY_CREATE_ROOT_EXTRA =
             "CREATE TABLE " + TABLE_ROOT_EXTRA + " (" +
             Root.COLUMN_ROOT_ID + " INTEGER PRIMARY KEY," +
             Root.COLUMN_FLAGS + " INTEGER NOT NULL," +
-            Root.COLUMN_AVAILABLE_BYTES + " INTEGER NOT NULL," +
-            Root.COLUMN_CAPACITY_BYTES + " INTEGER NOT NULL," +
+            Root.COLUMN_AVAILABLE_BYTES + " INTEGER," +
+            Root.COLUMN_CAPACITY_BYTES + " INTEGER," +
             Root.COLUMN_MIME_TYPES + " TEXT NOT NULL);";
 
     /**
@@ -145,18 +145,26 @@
         COLUMN_MAP_ROOTS = new HashMap<>();
         COLUMN_MAP_ROOTS.put(Root.COLUMN_ROOT_ID, TABLE_ROOT_EXTRA + "." + Root.COLUMN_ROOT_ID);
         COLUMN_MAP_ROOTS.put(Root.COLUMN_FLAGS, TABLE_ROOT_EXTRA + "." + Root.COLUMN_FLAGS);
-        COLUMN_MAP_ROOTS.put(Root.COLUMN_ICON, TABLE_DOCUMENTS + "." + Document.COLUMN_ICON);
         COLUMN_MAP_ROOTS.put(
-                Root.COLUMN_TITLE, TABLE_DOCUMENTS + "." + Document.COLUMN_DISPLAY_NAME);
-        COLUMN_MAP_ROOTS.put(Root.COLUMN_SUMMARY, TABLE_DOCUMENTS + "." + Document.COLUMN_SUMMARY);
+                Root.COLUMN_ICON,
+                TABLE_DOCUMENTS + "." + Document.COLUMN_ICON + " AS " + Root.COLUMN_ICON);
         COLUMN_MAP_ROOTS.put(
-                Root.COLUMN_DOCUMENT_ID, TABLE_DOCUMENTS + "." + Document.COLUMN_DOCUMENT_ID);
+                Root.COLUMN_TITLE,
+                TABLE_DOCUMENTS + "." + Document.COLUMN_DISPLAY_NAME + " AS " + Root.COLUMN_TITLE);
+        COLUMN_MAP_ROOTS.put(
+                Root.COLUMN_SUMMARY,
+                TABLE_DOCUMENTS + "." + Document.COLUMN_SUMMARY + " AS " + Root.COLUMN_SUMMARY);
+        COLUMN_MAP_ROOTS.put(
+                Root.COLUMN_DOCUMENT_ID,
+                TABLE_DOCUMENTS + "." + Document.COLUMN_DOCUMENT_ID +
+                " AS " + Root.COLUMN_DOCUMENT_ID);
         COLUMN_MAP_ROOTS.put(
                 Root.COLUMN_AVAILABLE_BYTES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_AVAILABLE_BYTES);
         COLUMN_MAP_ROOTS.put(
                 Root.COLUMN_CAPACITY_BYTES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_CAPACITY_BYTES);
         COLUMN_MAP_ROOTS.put(
                 Root.COLUMN_MIME_TYPES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_MIME_TYPES);
+        COLUMN_MAP_ROOTS.put(COLUMN_DEVICE_ID, COLUMN_DEVICE_ID);
     }
 
     private static String createJoinFromClosure(
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java
index 71df5c1..fa99a38 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java
@@ -16,16 +16,23 @@
 
 package com.android.mtp;
 
+import android.annotation.Nullable;
+
 class MtpDeviceRecord {
     public final int deviceId;
     public final String name;
     public final boolean opened;
     public final MtpRoot[] roots;
+    public final @Nullable int[] operationsSupported;
+    public final @Nullable int[] eventsSupported;
 
-    MtpDeviceRecord(int deviceId, String name, boolean opened, MtpRoot[] roots) {
+    MtpDeviceRecord(int deviceId, String name, boolean opened, MtpRoot[] roots,
+                    @Nullable int[] operationsSupported, @Nullable int[] eventsSupported) {
         this.deviceId = deviceId;
         this.name = name;
         this.opened = opened;
         this.roots = roots;
+        this.operationsSupported = operationsSupported;
+        this.eventsSupported = eventsSupported;
     }
 }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 57a68ba..6b5f16a 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -26,6 +26,7 @@
 import android.mtp.MtpObjectInfo;
 import android.os.CancellationSignal;
 import android.os.ParcelFileDescriptor;
+import android.os.storage.StorageManager;
 import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsContract.Root;
 import android.provider.DocumentsContract;
@@ -68,6 +69,7 @@
     private RootScanner mRootScanner;
     private Resources mResources;
     private MtpDatabase mDatabase;
+    private AppFuse mAppFuse;
 
     /**
      * Provides singleton instance to MtpDocumentsService.
@@ -85,23 +87,41 @@
         mDeviceToolkits = new HashMap<Integer, DeviceToolkit>();
         mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_FILE);
         mRootScanner = new RootScanner(mResolver, mResources, mMtpManager, mDatabase);
+        mAppFuse = new AppFuse(TAG, new AppFuseCallback());
+        // TODO: Mount AppFuse on demands.
+        try {
+            mAppFuse.mount(getContext().getSystemService(StorageManager.class));
+        } catch (IOException e) {
+            Log.e(TAG, "Failed to start app fuse.", e);
+            return false;
+        }
         resume();
         return true;
     }
 
     @VisibleForTesting
-    void onCreateForTesting(
+    boolean onCreateForTesting(
             Resources resources,
             MtpManager mtpManager,
             ContentResolver resolver,
-            MtpDatabase database) {
+            MtpDatabase database,
+            StorageManager storageManager) {
         mResources = resources;
         mMtpManager = mtpManager;
         mResolver = resolver;
         mDeviceToolkits = new HashMap<Integer, DeviceToolkit>();
         mDatabase = database;
         mRootScanner = new RootScanner(mResolver, mResources, mMtpManager, mDatabase);
+        mAppFuse = new AppFuse(TAG, new AppFuseCallback());
+        // TODO: Mount AppFuse on demands.
+        try {
+            mAppFuse.mount(storageManager);
+        } catch (IOException e) {
+            Log.e(TAG, "Failed to start app fuse.", e);
+            return false;
+        }
         resume();
+        return true;
     }
 
     @Override
@@ -147,16 +167,27 @@
         try {
             switch (mode) {
                 case "r":
-                    return getPipeManager(identifier).readDocument(mMtpManager, identifier);
+                    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);
-                default:
-                    // TODO: Add support for seekable files.
+                case "rw":
+                    // TODO: Add support for "rw" mode.
                     throw new UnsupportedOperationException(
-                            "The provider does not support seekable file.");
+                            "The provider does not support 'rw' mode.");
+                default:
+                    throw new IllegalArgumentException("Unknown mode for openDocument: " + mode);
             }
         } catch (IOException error) {
             throw new FileNotFoundException(error.getMessage());
@@ -245,7 +276,6 @@
     void closeDevice(int deviceId) throws IOException, InterruptedException {
         synchronized (mDeviceListLock) {
             closeDeviceInternal(deviceId);
-            mDatabase.removeDeviceRows(deviceId);
         }
         mRootScanner.resume();
     }
@@ -282,6 +312,7 @@
                 throw new RuntimeException(e);
             } finally {
                 mDatabase.close();
+                mAppFuse.close();
                 super.shutdown();
             }
         }
@@ -331,6 +362,21 @@
         return getDeviceToolkit(identifier.mDeviceId).mDocumentLoader;
     }
 
+    private long getFileSize(String documentId) throws FileNotFoundException {
+        final Cursor cursor = mDatabase.queryDocument(
+                documentId,
+                MtpDatabase.strings(Document.COLUMN_SIZE, Document.COLUMN_DISPLAY_NAME));
+        try {
+            if (cursor.moveToNext()) {
+                return cursor.getLong(0);
+            } else {
+                throw new FileNotFoundException();
+            }
+        } finally {
+            cursor.close();
+        }
+    }
+
     private static class DeviceToolkit {
         public final PipeManager mPipeManager;
         public final DocumentLoader mDocumentLoader;
@@ -340,4 +386,19 @@
             mDocumentLoader = new DocumentLoader(manager, resolver, database);
         }
     }
+
+    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);
+        }
+
+        @Override
+        public long getFileSize(int inode) throws FileNotFoundException {
+            return MtpDocumentsProvider.this.getFileSize(String.valueOf(inode));
+        }
+    }
 }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java
index b0cff83..5bede86 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java
@@ -37,7 +37,6 @@
     static final String ACTION_OPEN_DEVICE = "com.android.mtp.OPEN_DEVICE";
     static final String ACTION_CLOSE_DEVICE = "com.android.mtp.CLOSE_DEVICE";
     static final String EXTRA_DEVICE = "device";
-    private static final int FOREGROUND_NOTIFICATION_ID = 1;
 
     NotificationManager mNotificationManager;
 
@@ -67,6 +66,7 @@
                         break;
 
                     case ACTION_CLOSE_DEVICE:
+                        mNotificationManager.cancel(device.getDeviceId());
                         provider.closeDevice(device.getDeviceId());
                         break;
 
@@ -90,36 +90,40 @@
     private boolean updateForegroundState() {
         final MtpDocumentsProvider provider = MtpDocumentsProvider.getInstance();
         final int[] deviceIds = provider.getOpenedDeviceIds();
-        String message = null;
-        if (deviceIds.length != 0) {
-            // TODO: Localize the message.
-            // TODO: Add buttons "Open in Files" and "Open in Apps" if needed.
-            if (deviceIds.length > 1) {
-                message = deviceIds.length + " devices are being connected.";
-            } else {
+        int notificationId = 0;
+        Notification notification = null;
+        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 {
-                    message = provider.getDeviceName(deviceIds[0]) + " is being connected.";
-                } 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);
-                    }
+                    provider.closeDevice(deviceIds[0]);
+                } catch (IOException | InterruptedException closeError) {
+                    logErrorMessage(closeError);
                 }
             }
         }
-        if (message != null) {
-            final Notification notification = new Notification.Builder(this)
-                    .setContentTitle(message)
-                    .setSmallIcon(android.R.drawable.ic_menu_camera)
-                    .setCategory(Notification.CATEGORY_SYSTEM)
-                    .setPriority(Notification.PRIORITY_LOW)
-                    .build();
-            startForeground(FOREGROUND_NOTIFICATION_ID, notification);
+
+        if (notification != null) {
+            startForeground(notificationId, notification);
             return true;
         } else {
             stopForeground(true /* removeNotification */);
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 88cab8b..efe5ff1 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -24,6 +24,7 @@
 import android.hardware.usb.UsbManager;
 import android.mtp.MtpConstants;
 import android.mtp.MtpDevice;
+import android.mtp.MtpDeviceInfo;
 import android.mtp.MtpEvent;
 import android.mtp.MtpObjectInfo;
 import android.os.CancellationSignal;
@@ -123,9 +124,12 @@
             if (!isMtpDevice(device)) {
                 continue;
             }
-            final boolean opened = mDevices.get(device.getDeviceId()) != null;
+            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());
@@ -136,10 +140,17 @@
                     // 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, opened, roots));
+            devices.add(new MtpDeviceRecord(
+                    device.getDeviceId(), name, opened, roots, operationsSupported,
+                    eventsSupported));
         }
         return devices.toArray(new MtpDeviceRecord[devices.size()]);
     }
@@ -176,6 +187,15 @@
         }
     }
 
+    @VisibleForTesting
+    long getPartialObject(int deviceId, int objectHandle, long offset, long size, byte[] buffer)
+            throws IOException {
+        final MtpDevice device = getDevice(deviceId);
+        synchronized (device) {
+            return device.getPartialObject(objectHandle, offset, size, buffer);
+        }
+    }
+
     byte[] getThumbnail(int deviceId, int objectHandle) throws IOException {
         final MtpDevice device = getDevice(deviceId);
         synchronized (device) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java b/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
index e6c2726..15b8ef3 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
@@ -7,9 +7,6 @@
 import android.provider.DocumentsContract;
 import android.util.Log;
 
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.FutureTask;
@@ -105,7 +102,7 @@
         public void run() {
             Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
             int pollingCount = 0;
-            while (!Thread.interrupted()) {
+            while (true) {
                 boolean changed = false;
 
                 // Update devices.
@@ -127,7 +124,7 @@
                         continue;
                     }
                     mDatabase.getMapper().startAddingDocuments(documentId);
-                    if (mDatabase.getMapper().putRootDocuments(
+                    if (mDatabase.getMapper().putStorageDocuments(
                             documentId, mResources, device.roots)) {
                         changed = true;
                     }
@@ -147,8 +144,7 @@
                     Thread.sleep(pollingCount > SHORT_POLLING_TIMES ?
                         LONG_POLLING_INTERVAL : SHORT_POLLING_INTERVAL);
                 } catch (InterruptedException exp) {
-                    // The while condition handles the interrupted flag.
-                    continue;
+                    break;
                 }
             }
         }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/annotations/UsedByNative.java b/packages/MtpDocumentsProvider/src/com/android/mtp/annotations/UsedByNative.java
new file mode 100644
index 0000000..a7f295f
--- /dev/null
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/annotations/UsedByNative.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation that shows the method is used by JNI.
+ */
+@Target(ElementType.METHOD)
+public @interface UsedByNative {
+    /**
+     * JNI file name that uses the method.
+     */
+    String value();
+}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
new file mode 100644
index 0000000..c0973bd
--- /dev/null
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mtp;
+
+import android.os.ParcelFileDescriptor;
+import android.os.storage.StorageManager;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Arrays;
+
+@MediumTest
+public class AppFuseTest extends AndroidTestCase {
+    public void testMount() throws ErrnoException, IOException {
+        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
+        final AppFuse appFuse = new AppFuse("test", new TestCallback());
+        appFuse.mount(storageManager);
+        final File file = appFuse.getMountPoint();
+        assertTrue(file.isDirectory());
+        assertEquals(1, Os.stat(file.getPath()).st_ino);
+        appFuse.close();
+        assertTrue(1 != Os.stat(file.getPath()).st_ino);
+    }
+
+    public void testOpenFile() 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) {
+                            return 1024;
+                        }
+                        throw new FileNotFoundException();
+                    }
+                });
+        appFuse.mount(storageManager);
+        final ParcelFileDescriptor fd = appFuse.openFile(INODE);
+        fd.close();
+        appFuse.close();
+    }
+
+    public void testOpenFile_fileNotFound() 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);
+            fail();
+        } catch (Throwable t) {
+            assertTrue(t instanceof FileNotFoundException);
+        }
+        appFuse.close();
+    }
+
+    public void testReadFile() throws IOException {
+        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
+        final int fileInode = 10;
+        final byte[] fileBytes = new byte[] { 'a', 'b', 'c', 'd', 'e' };
+        final AppFuse appFuse = new AppFuse(
+                "test",
+                new TestCallback() {
+                    @Override
+                    public long getFileSize(int inode) throws FileNotFoundException {
+                        if (inode == fileInode) {
+                            return fileBytes.length;
+                        }
+                        return super.getFileSize(inode);
+                    }
+
+                    @Override
+                    public long readObjectBytes(int inode, long offset, long size, byte[] bytes)
+                            throws IOException {
+                        if (inode == fileInode) {
+                            int i = 0;
+                            while (i < size && i + offset < fileBytes.length)  {
+                                bytes[i] = fileBytes[(int) (i + offset)];
+                                i++;
+                            }
+                            return i;
+                        }
+                        return super.readObjectBytes(inode, offset, size, bytes);
+                    }
+                });
+        appFuse.mount(storageManager);
+        final ParcelFileDescriptor fd = appFuse.openFile(fileInode);
+        try (final ParcelFileDescriptor.AutoCloseInputStream stream =
+                new ParcelFileDescriptor.AutoCloseInputStream(fd)) {
+            final byte[] buffer = new byte[1024];
+            final int size = stream.read(buffer, 0, buffer.length);
+            assertEquals(5, size);
+        }
+        appFuse.close();
+    }
+
+    private static class TestCallback implements AppFuse.Callback {
+        @Override
+        public long getFileSize(int inode) throws FileNotFoundException {
+            throw new FileNotFoundException();
+        }
+
+        @Override
+        public long readObjectBytes(int inode, long offset, long size, byte[] bytes)
+                throws IOException {
+            throw new IOException();
+        }
+    }
+}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
index 7bd9a17..f37a55c 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
@@ -41,7 +41,7 @@
     public void setUp() {
         mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
         mDatabase.getMapper().startAddingDocuments("deviceDocId");
-        mDatabase.getMapper().putRootDocuments("deviceDocId", new TestResources(), new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("deviceDocId", new TestResources(), new MtpRoot[] {
                 new MtpRoot(0, 0, "Device", "Storage", 1000, 1000, "")
         });
         mDatabase.getMapper().stopAddingDocuments("deviceDocId");
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
index b745175..97ea717 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
@@ -74,9 +74,72 @@
         return cursor.getString(cursor.getColumnIndex(columnName));
     }
 
-    public void testPutRootDocuments() throws Exception {
+    public void testPutSingleStorageDocuments() throws Exception {
+        mDatabase.getMapper().startAddingDocuments(null);
+        mDatabase.getMapper().putDeviceDocument(
+                new MtpDeviceRecord(0, "Device", true, new MtpRoot[0], null, null));
+        mDatabase.getMapper().stopAddingDocuments(null);
+
+        mDatabase.getMapper().startAddingDocuments("1");
+        mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
+                new MtpRoot(0, 1, "Device", "Storage", 1000, 2000, "")
+        });
+        mDatabase.getMapper().stopAddingDocuments("1");
+
+        {
+            final Cursor cursor = mDatabase.queryRootDocuments(COLUMN_NAMES);
+            assertEquals(1, cursor.getCount());
+
+            cursor.moveToNext();
+            assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID));
+            assertEquals(1, getInt(cursor, COLUMN_STORAGE_ID));
+            assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE));
+            assertEquals(DocumentsContract.Document.MIME_TYPE_DIR, getString(cursor, COLUMN_MIME_TYPE));
+            assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
+            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(1000, getInt(cursor, COLUMN_SIZE));
+            assertEquals(
+                    MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE, getInt(cursor, COLUMN_DOCUMENT_TYPE));
+
+            cursor.close();
+        }
+
+        {
+            final Cursor cursor = mDatabase.queryRoots(new String [] {
+                    Root.COLUMN_ROOT_ID,
+                    Root.COLUMN_FLAGS,
+                    Root.COLUMN_ICON,
+                    Root.COLUMN_TITLE,
+                    Root.COLUMN_SUMMARY,
+                    Root.COLUMN_DOCUMENT_ID,
+                    Root.COLUMN_AVAILABLE_BYTES,
+                    Root.COLUMN_CAPACITY_BYTES
+            });
+            assertEquals(1, cursor.getCount());
+
+            cursor.moveToNext();
+            assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(
+                    Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE,
+                    getInt(cursor, Root.COLUMN_FLAGS));
+            assertEquals(R.drawable.ic_root_mtp, getInt(cursor, Root.COLUMN_ICON));
+            assertEquals("Device Storage", getString(cursor, Root.COLUMN_TITLE));
+            assertTrue(isNull(cursor, Root.COLUMN_SUMMARY));
+            assertEquals(2, getInt(cursor, Root.COLUMN_DOCUMENT_ID));
+            assertEquals(1000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
+            assertEquals(2000, getInt(cursor, Root.COLUMN_CAPACITY_BYTES));
+
+            cursor.close();
+        }
+    }
+
+    public void testPutStorageDocuments() throws Exception {
         mDatabase.getMapper().startAddingDocuments("deviceDocId");
-        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 1, "Device", "Storage", 1000, 2000, ""),
                 new MtpRoot(0, 2, "Device", "Storage", 2000, 4000, ""),
                 new MtpRoot(0, 3, "Device", "/@#%&<>Storage", 3000, 6000,"")
@@ -111,52 +174,6 @@
 
             cursor.close();
         }
-
-        {
-            final Cursor cursor = mDatabase.queryRoots(new String [] {
-                    Root.COLUMN_ROOT_ID,
-                    Root.COLUMN_FLAGS,
-                    Root.COLUMN_ICON,
-                    Root.COLUMN_TITLE,
-                    Root.COLUMN_SUMMARY,
-                    Root.COLUMN_DOCUMENT_ID,
-                    Root.COLUMN_AVAILABLE_BYTES,
-                    Root.COLUMN_CAPACITY_BYTES
-            });
-            assertEquals(3, cursor.getCount());
-
-            cursor.moveToNext();
-            assertEquals(1, cursor.getInt(0));
-            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
-            assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
-            assertEquals("Device Storage", cursor.getString(3));
-            assertTrue(cursor.isNull(4));
-            assertEquals(1, cursor.getInt(5));
-            assertEquals(1000, cursor.getInt(6));
-            assertEquals(2000, cursor.getInt(7));
-
-            cursor.moveToNext();
-            assertEquals(2, cursor.getInt(0));
-            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
-            assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
-            assertEquals("Device Storage", cursor.getString(3));
-            assertTrue(cursor.isNull(4));
-            assertEquals(2, cursor.getInt(5));
-            assertEquals(2000, cursor.getInt(6));
-            assertEquals(4000, cursor.getInt(7));
-
-            cursor.moveToNext();
-            assertEquals(3, cursor.getInt(0));
-            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
-            assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
-            assertEquals("Device /@#%&<>Storage", cursor.getString(3));
-            assertTrue(cursor.isNull(4));
-            assertEquals(3, cursor.getInt(5));
-            assertEquals(3000, cursor.getInt(6));
-            assertEquals(6000, cursor.getInt(7));
-
-            cursor.close();
-        }
     }
 
     private MtpObjectInfo createDocument(int objectHandle, String name, int format, int size) {
@@ -245,13 +262,9 @@
                 MtpDatabaseConstants.COLUMN_STORAGE_ID,
                 DocumentsContract.Document.COLUMN_DISPLAY_NAME
         };
-        final String[] rootColumns = new String[] {
-                Root.COLUMN_ROOT_ID,
-                Root.COLUMN_AVAILABLE_BYTES
-        };
 
         mDatabase.getMapper().startAddingDocuments("deviceDocId");
-        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 100, "Device", "Storage A", 1000, 0, ""),
                 new MtpRoot(0, 101, "Device", "Storage B", 1001, 0, "")
         });
@@ -270,18 +283,6 @@
             cursor.close();
         }
 
-        {
-            final Cursor cursor = mDatabase.queryRoots(rootColumns);
-            assertEquals(2, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
-            assertEquals(1000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
-            cursor.moveToNext();
-            assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
-            assertEquals(1001, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
-            cursor.close();
-        }
-
         mDatabase.getMapper().clearMapping();
 
         {
@@ -298,20 +299,8 @@
             cursor.close();
         }
 
-        {
-            final Cursor cursor = mDatabase.queryRoots(rootColumns);
-            assertEquals(2, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
-            assertEquals(1000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
-            cursor.moveToNext();
-            assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
-            assertEquals(1001, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
-            cursor.close();
-        }
-
         mDatabase.getMapper().startAddingDocuments("deviceDocId");
-        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 200, "Device", "Storage A", 2000, 0, ""),
                 new MtpRoot(0, 202, "Device", "Storage C", 2002, 0, "")
         });
@@ -334,21 +323,6 @@
             cursor.close();
         }
 
-        {
-            final Cursor cursor = mDatabase.queryRoots(rootColumns);
-            assertEquals(3, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
-            assertEquals(1000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
-            cursor.moveToNext();
-            assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
-            assertEquals(1001, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
-            cursor.moveToNext();
-            assertEquals(4, getInt(cursor, Root.COLUMN_ROOT_ID));
-            assertEquals(2002, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
-            cursor.close();
-        }
-
         mDatabase.getMapper().stopAddingDocuments("deviceDocId");
 
         {
@@ -364,18 +338,6 @@
             assertEquals("Device Storage C", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.close();
         }
-
-        {
-            final Cursor cursor = mDatabase.queryRoots(rootColumns);
-            assertEquals(2, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
-            assertEquals(2000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
-            cursor.moveToNext();
-            assertEquals(4, getInt(cursor, Root.COLUMN_ROOT_ID));
-            assertEquals(2002, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
-            cursor.close();
-        }
     }
 
     public void testRestoreIdForChildDocuments() throws Exception {
@@ -461,26 +423,33 @@
                 Root.COLUMN_ROOT_ID,
                 Root.COLUMN_AVAILABLE_BYTES
         };
-        mDatabase.getMapper().startAddingDocuments("deviceDocIdA");
-        mDatabase.getMapper().startAddingDocuments("deviceDocIdB");
-        mDatabase.getMapper().putRootDocuments("deviceDocIdA", resources, new MtpRoot[] {
-                new MtpRoot(0, 100, "Device", "Storage", 0, 0, "")
+        mDatabase.getMapper().startAddingDocuments(null);
+        mDatabase.getMapper().putDeviceDocument(
+                new MtpDeviceRecord(0, "Device A", true, new MtpRoot[0], null, null));
+        mDatabase.getMapper().putDeviceDocument(
+                new MtpDeviceRecord(1, "Device B", true, new MtpRoot[0], null, null));
+        mDatabase.getMapper().stopAddingDocuments(null);
+
+        mDatabase.getMapper().startAddingDocuments("1");
+        mDatabase.getMapper().startAddingDocuments("2");
+        mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
+                new MtpRoot(0, 100, "Device A", "Storage", 0, 0, "")
         });
-        mDatabase.getMapper().putRootDocuments("deviceDocIdB", resources, new MtpRoot[] {
-                new MtpRoot(1, 100, "Device", "Storage", 0, 0, "")
+        mDatabase.getMapper().putStorageDocuments("2", resources, new MtpRoot[] {
+                new MtpRoot(1, 100, "Device B", "Storage", 0, 0, "")
         });
 
         {
             final Cursor cursor = mDatabase.queryRootDocuments(columns);
             assertEquals(2, cursor.getCount());
             cursor.moveToNext();
-            assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
             assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID));
-            assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
+            assertEquals("Device A Storage", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.moveToNext();
-            assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID));
             assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID));
-            assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
+            assertEquals("Device B Storage", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.close();
         }
 
@@ -488,36 +457,36 @@
             final Cursor cursor = mDatabase.queryRoots(rootColumns);
             assertEquals(2, cursor.getCount());
             cursor.moveToNext();
-            assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(3, getInt(cursor, Root.COLUMN_ROOT_ID));
             assertEquals(0, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.moveToNext();
-            assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(4, getInt(cursor, Root.COLUMN_ROOT_ID));
             assertEquals(0, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.close();
         }
 
         mDatabase.getMapper().clearMapping();
 
-        mDatabase.getMapper().startAddingDocuments("deviceDocIdA");
-        mDatabase.getMapper().startAddingDocuments("deviceDocIdB");
-        mDatabase.getMapper().putRootDocuments("deviceDocIdA", resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("1");
+        mDatabase.getMapper().startAddingDocuments("2");
+        mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
                 new MtpRoot(0, 200, "Device", "Storage", 2000, 0, "")
         });
-        mDatabase.getMapper().putRootDocuments("deviceDocIdB", resources, new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("2", resources, new MtpRoot[] {
                 new MtpRoot(1, 300, "Device", "Storage", 3000, 0, "")
         });
-        mDatabase.getMapper().stopAddingDocuments("deviceDocIdA");
-        mDatabase.getMapper().stopAddingDocuments("deviceDocIdB");
+        mDatabase.getMapper().stopAddingDocuments("1");
+        mDatabase.getMapper().stopAddingDocuments("2");
 
         {
             final Cursor cursor = mDatabase.queryRootDocuments(columns);
             assertEquals(2, cursor.getCount());
             cursor.moveToNext();
-            assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(5, getInt(cursor, COLUMN_DOCUMENT_ID));
             assertEquals(200, getInt(cursor, COLUMN_STORAGE_ID));
             assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.moveToNext();
-            assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(6, getInt(cursor, COLUMN_DOCUMENT_ID));
             assertEquals(300, getInt(cursor, COLUMN_STORAGE_ID));
             assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.close();
@@ -527,10 +496,10 @@
             final Cursor cursor = mDatabase.queryRoots(rootColumns);
             assertEquals(2, cursor.getCount());
             cursor.moveToNext();
-            assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(5, getInt(cursor, Root.COLUMN_ROOT_ID));
             assertEquals(2000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.moveToNext();
-            assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(6, getInt(cursor, Root.COLUMN_ROOT_ID));
             assertEquals(3000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.close();
         }
@@ -591,29 +560,34 @@
                 Root.COLUMN_AVAILABLE_BYTES
         };
 
-        mDatabase.getMapper().startAddingDocuments("deviceDocId");
-        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments(null);
+        mDatabase.getMapper().putDeviceDocument(
+                new MtpDeviceRecord(0, "Device",  false,  new MtpRoot[0], null, null));
+        mDatabase.getMapper().stopAddingDocuments(null);
+
+        mDatabase.getMapper().startAddingDocuments("1");
+        mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
                 new MtpRoot(0, 100, "Device", "Storage", 0, 0, ""),
         });
         mDatabase.getMapper().clearMapping();
 
-        mDatabase.getMapper().startAddingDocuments("deviceDocId");
-        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("1");
+        mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
                 new MtpRoot(0, 200, "Device", "Storage", 2000, 0, ""),
         });
         mDatabase.getMapper().clearMapping();
 
-        mDatabase.getMapper().startAddingDocuments("deviceDocId");
-        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("1");
+        mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
                 new MtpRoot(0, 300, "Device", "Storage", 3000, 0, ""),
         });
-        mDatabase.getMapper().stopAddingDocuments("deviceDocId");
+        mDatabase.getMapper().stopAddingDocuments("1");
 
         {
             final Cursor cursor = mDatabase.queryRootDocuments(columns);
             assertEquals(1, cursor.getCount());
             cursor.moveToNext();
-            assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
             assertEquals(300, getInt(cursor, COLUMN_STORAGE_ID));
             assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.close();
@@ -622,7 +596,7 @@
             final Cursor cursor = mDatabase.queryRoots(rootColumns);
             assertEquals(1, cursor.getCount());
             cursor.moveToNext();
-            assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
             assertEquals(3000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.close();
         }
@@ -634,19 +608,15 @@
                 MtpDatabaseConstants.COLUMN_STORAGE_ID,
                 DocumentsContract.Document.COLUMN_DISPLAY_NAME
         };
-        final String[] rootColumns = new String[] {
-                Root.COLUMN_ROOT_ID,
-                Root.COLUMN_AVAILABLE_BYTES
-        };
 
         mDatabase.getMapper().startAddingDocuments("deviceDocId");
-        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 100, "Device", "Storage", 0, 0, ""),
         });
         mDatabase.getMapper().clearMapping();
 
         mDatabase.getMapper().startAddingDocuments("deviceDocId");
-        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 200, "Device", "Storage", 2000, 0, ""),
                 new MtpRoot(0, 201, "Device", "Storage", 2001, 0, ""),
         });
@@ -665,33 +635,27 @@
             assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.close();
         }
-        {
-            final Cursor cursor = mDatabase.queryRoots(rootColumns);
-            assertEquals(2, cursor.getCount());
-            cursor.moveToNext();
-            assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
-            assertEquals(2000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
-            cursor.moveToNext();
-            assertEquals(3, getInt(cursor, Root.COLUMN_ROOT_ID));
-            assertEquals(2001, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
-            cursor.close();
-        }
     }
 
     public void testReplaceExistingRoots() {
+        mDatabase.getMapper().startAddingDocuments(null);
+        mDatabase.getMapper().putDeviceDocument(
+                new MtpDeviceRecord(0, "Device", true, new MtpRoot[0], null, null));
+        mDatabase.getMapper().stopAddingDocuments(null);
+
         // The client code should be able to replace existing rows with new information.
         // Add one.
-        mDatabase.getMapper().startAddingDocuments("deviceDocId");
-        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("1");
+        mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
                 new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""),
         });
-        mDatabase.getMapper().stopAddingDocuments("deviceDocId");
+        mDatabase.getMapper().stopAddingDocuments("1");
         // Replace it.
-        mDatabase.getMapper().startAddingDocuments("deviceDocId");
-        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("1");
+        mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
                 new MtpRoot(0, 100, "Device", "Storage B", 1000, 1000, ""),
         });
-        mDatabase.getMapper().stopAddingDocuments("deviceDocId");
+        mDatabase.getMapper().stopAddingDocuments("1");
         {
             final String[] columns = new String[] {
                     DocumentsContract.Document.COLUMN_DOCUMENT_ID,
@@ -701,7 +665,7 @@
             final Cursor cursor = mDatabase.queryRootDocuments(columns);
             assertEquals(1, cursor.getCount());
             cursor.moveToNext();
-            assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+            assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
             assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID));
             assertEquals("Device Storage B", getString(cursor, COLUMN_DISPLAY_NAME));
             cursor.close();
@@ -709,12 +673,14 @@
         {
             final String[] columns = new String[] {
                     Root.COLUMN_ROOT_ID,
+                    Root.COLUMN_TITLE,
                     Root.COLUMN_AVAILABLE_BYTES
             };
             final Cursor cursor = mDatabase.queryRoots(columns);
             assertEquals(1, cursor.getCount());
             cursor.moveToNext();
-            assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
+            assertEquals("Device Storage B", getString(cursor, Root.COLUMN_TITLE));
             assertEquals(1000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
             cursor.close();
         }
@@ -723,8 +689,13 @@
     public void testFailToReplaceExisitingUnmappedRoots() {
         // The client code should not be able to replace rows before resolving 'unmapped' rows.
         // Add one.
-        mDatabase.getMapper().startAddingDocuments("deviceDocId");
-        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments(null);
+        mDatabase.getMapper().putDeviceDocument(
+                new MtpDeviceRecord(0, "Device", true, new MtpRoot[0], null, null));
+        mDatabase.getMapper().stopAddingDocuments(null);
+
+        mDatabase.getMapper().startAddingDocuments("1");
+        mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
                 new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""),
         });
         mDatabase.getMapper().clearMapping();
@@ -732,18 +703,19 @@
         assertEquals(1, oldCursor.getCount());
 
         // Add one.
-        mDatabase.getMapper().startAddingDocuments("deviceDocId");
-        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+        mDatabase.getMapper().startAddingDocuments("1");
+        mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
                 new MtpRoot(0, 101, "Device", "Storage B", 1000, 1000, ""),
         });
         // Add one more before resolving unmapped documents.
-        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
                 new MtpRoot(0, 102, "Device", "Storage B", 1000, 1000, ""),
         });
-        mDatabase.getMapper().stopAddingDocuments("deviceDocId");
+        mDatabase.getMapper().stopAddingDocuments("1");
 
         // Because the roots shares the same name, the roots should have new IDs.
-        final Cursor newCursor = mDatabase.queryRoots(strings(Root.COLUMN_ROOT_ID));
+        final Cursor newCursor = mDatabase.queryChildDocuments(
+                strings(Document.COLUMN_DOCUMENT_ID), "1");
         assertEquals(2, newCursor.getCount());
         oldCursor.moveToNext();
         newCursor.moveToNext();
@@ -755,9 +727,9 @@
         newCursor.close();
     }
 
-    public void testQueryDocument() {
+    public void testQueryDocuments() {
         mDatabase.getMapper().startAddingDocuments("deviceDocId");
-        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""),
         });
         mDatabase.getMapper().stopAddingDocuments("deviceDocId");
@@ -765,13 +737,61 @@
         final Cursor cursor = mDatabase.queryDocument("1", strings(Document.COLUMN_DISPLAY_NAME));
         assertEquals(1, cursor.getCount());
         cursor.moveToNext();
-        assertEquals("Device Storage A", cursor.getString(0));
+        assertEquals("Device Storage A", getString(cursor, Document.COLUMN_DISPLAY_NAME));
         cursor.close();
     }
 
+    public void testQueryRoots() {
+        // Add device document.
+        mDatabase.getMapper().startAddingDocuments(null);
+        mDatabase.getMapper().putDeviceDocument(
+                new MtpDeviceRecord(0, "Device", false, new MtpRoot[0], null, null));
+        mDatabase.getMapper().stopAddingDocuments(null);
+
+        // It the device does not have storages, it shows a device root.
+        {
+            final Cursor cursor = mDatabase.queryRoots(strings(Root.COLUMN_TITLE));
+            assertEquals(1, cursor.getCount());
+            cursor.moveToNext();
+            assertEquals("Device", cursor.getString(0));
+            cursor.close();
+        }
+
+        mDatabase.getMapper().startAddingDocuments("1");
+        mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
+                new MtpRoot(0, 100, "Device", "Storage A", 0, 0, "")
+        });
+        mDatabase.getMapper().stopAddingDocuments("1");
+
+        // It the device has single storage, it shows a storage root.
+        {
+            final Cursor cursor = mDatabase.queryRoots(strings(Root.COLUMN_TITLE));
+            assertEquals(1, cursor.getCount());
+            cursor.moveToNext();
+            assertEquals("Device Storage A", cursor.getString(0));
+            cursor.close();
+        }
+
+        mDatabase.getMapper().startAddingDocuments("1");
+        mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
+                new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""),
+                new MtpRoot(0, 101, "Device", "Storage B", 0, 0, "")
+        });
+        mDatabase.getMapper().stopAddingDocuments("1");
+
+        // It the device has multiple storages, it shows a device root.
+        {
+            final Cursor cursor = mDatabase.queryRoots(strings(Root.COLUMN_TITLE));
+            assertEquals(1, cursor.getCount());
+            cursor.moveToNext();
+            assertEquals("Device", cursor.getString(0));
+            cursor.close();
+        }
+    }
+
     public void testGetParentId() throws FileNotFoundException {
         mDatabase.getMapper().startAddingDocuments("deviceDocId");
-        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""),
         });
         mDatabase.getMapper().stopAddingDocuments("deviceDocId");
@@ -790,7 +810,7 @@
 
     public void testDeleteDocument() {
         mDatabase.getMapper().startAddingDocuments("deviceDocId");
-        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""),
         });
         mDatabase.getMapper().stopAddingDocuments("deviceDocId");
@@ -834,7 +854,7 @@
 
     public void testPutNewDocument() {
         mDatabase.getMapper().startAddingDocuments("deviceDocId");
-        mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+        mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] {
                 new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""),
         });
         mDatabase.getMapper().stopAddingDocuments("deviceDocId");
@@ -875,7 +895,7 @@
     public void testGetDocumentIdForDevice() {
         mDatabase.getMapper().startAddingDocuments(null);
         mDatabase.getMapper().putDeviceDocument(
-                new MtpDeviceRecord(100, "Device", true, new MtpRoot[0]));
+                new MtpDeviceRecord(100, "Device", true, new MtpRoot[0], null, null));
         mDatabase.getMapper().stopAddingDocuments(null);
         assertEquals("1", mDatabase.getDocumentIdForDevice(100));
     }
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index 884b1e2..7066f7d 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -20,18 +20,25 @@
 import android.mtp.MtpConstants;
 import android.mtp.MtpObjectInfo;
 import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+import android.os.storage.StorageManager;
 import android.provider.DocumentsContract.Root;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
 import android.provider.DocumentsContract;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Log;
 
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.concurrent.TimeoutException;
 
 import static com.android.mtp.MtpDatabase.strings;
 
-@SmallTest
+@MediumTest
 public class MtpDocumentsProviderTest extends AndroidTestCase {
     private final static Uri ROOTS_URI =
             DocumentsContract.buildRootsUri(MtpDocumentsProvider.AUTHORITY);
@@ -68,7 +75,9 @@
                             1024 /* free space */,
                             2048 /* total space */,
                             "" /* no volume identifier */)
-                }));
+                },
+                null,
+                null));
 
         mProvider.openDevice(0);
         mResolver.waitForNotification(ROOTS_URI, 1);
@@ -107,7 +116,9 @@
                             1024 /* free space */,
                             2048 /* total space */,
                             "" /* no volume identifier */)
-                }));
+                },
+                null,
+                null));
         mProvider.openDevice(0);
         mResolver.waitForNotification(ROOTS_URI, 1);
     }
@@ -127,7 +138,9 @@
                                 1024 /* free space */,
                                 2048 /* total space */,
                                 "" /* no volume identifier */)
-                }));
+                },
+                null,
+                null));
         mMtpManager.addValidDevice(new MtpDeviceRecord(
                 1,
                 "Device",
@@ -141,13 +154,15 @@
                             2048 /* free space */,
                             4096 /* total space */,
                             "Identifier B" /* no volume identifier */)
-                }));
+                },
+                null,
+                null));
 
         {
             mProvider.openDevice(0);
             mResolver.waitForNotification(ROOTS_URI, 1);
             final Cursor cursor = mProvider.queryRoots(null);
-            assertEquals(1, cursor.getCount());
+            assertEquals(2, cursor.getCount());
             cursor.moveToNext();
             assertEquals("3", cursor.getString(0));
             assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
@@ -175,8 +190,8 @@
 
     public void testQueryRoots_error() throws Exception {
         setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        mMtpManager.addValidDevice(
-                new MtpDeviceRecord(0, "Device", false /* unopened */, new MtpRoot[0]));
+        mMtpManager.addValidDevice(new MtpDeviceRecord(
+                0, "Device A", false /* unopened */, new MtpRoot[0], null, null));
         mMtpManager.addValidDevice(new MtpDeviceRecord(
                 1,
                 "Device",
@@ -190,14 +205,25 @@
                             2048 /* free space */,
                             4096 /* total space */,
                             "Identifier B" /* no volume identifier */)
-                }));
+                },
+                null,
+                null));
         {
             mProvider.openDevice(0);
             mProvider.openDevice(1);
             mResolver.waitForNotification(ROOTS_URI, 1);
 
             final Cursor cursor = mProvider.queryRoots(null);
-            assertEquals(1, cursor.getCount());
+            assertEquals(2, cursor.getCount());
+
+            cursor.moveToNext();
+            assertEquals("1", cursor.getString(0));
+            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
+            assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
+            assertEquals("Device A", cursor.getString(3));
+            assertEquals("1", cursor.getString(4));
+            assertEquals(0, cursor.getInt(5));
+
             cursor.moveToNext();
             assertEquals("3", cursor.getString(0));
             assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
@@ -402,10 +428,71 @@
                         MtpDocumentsProvider.AUTHORITY, "1")));
     }
 
+    public void testOpenDocument() throws Exception {
+        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
+        setupRoots(0, new MtpRoot[] {
+                new MtpRoot(0, 0, "Device", "Storage", 0, 0, "")
+        });
+        final byte[] bytes = "Hello world".getBytes();
+        setupDocuments(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, "1", new MtpObjectInfo[] {
+                new MtpObjectInfo.Builder()
+                        .setName("test.txt")
+                        .setObjectHandle(1)
+                        .setCompressedSize(bytes.length)
+                        .setParent(-1)
+                        .build()
+        });
+        mMtpManager.setImportFileBytes(0, 1, bytes);
+        try (final ParcelFileDescriptor fd = mProvider.openDocument("3", "r", null)) {
+            final byte[] readBytes = new byte[5];
+            assertEquals(6, Os.lseek(fd.getFileDescriptor(), 6, OsConstants.SEEK_SET));
+            assertEquals(5, Os.read(fd.getFileDescriptor(), readBytes, 0, 5));
+            assertTrue(Arrays.equals("world".getBytes(), readBytes));
+
+            assertEquals(0, Os.lseek(fd.getFileDescriptor(), 0, OsConstants.SEEK_SET));
+            assertEquals(5, Os.read(fd.getFileDescriptor(), readBytes, 0, 5));
+            assertTrue(Arrays.equals("Hello".getBytes(), readBytes));
+        }
+    }
+
+    public void testOpenDocument_shortBytes() throws Exception {
+        mMtpManager = new TestMtpManager(getContext()) {
+            @Override
+            MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
+                if (objectHandle == 1) {
+                    return new MtpObjectInfo.Builder(super.getObjectInfo(deviceId, objectHandle))
+                            .setObjectHandle(1).setCompressedSize(1024 * 1024).build();
+                }
+
+                return super.getObjectInfo(deviceId, objectHandle);
+            }
+        };
+        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
+        setupRoots(0, new MtpRoot[] {
+                new MtpRoot(0, 0, "Device", "Storage", 0, 0, "")
+        });
+        final byte[] bytes = "Hello world".getBytes();
+        setupDocuments(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, "1", new MtpObjectInfo[] {
+                new MtpObjectInfo.Builder()
+                        .setName("test.txt")
+                        .setObjectHandle(1)
+                        .setCompressedSize(bytes.length)
+                        .setParent(-1)
+                        .build()
+        });
+        mMtpManager.setImportFileBytes(0, 1, bytes);
+        try (final ParcelFileDescriptor fd = mProvider.openDocument("3", "r", null)) {
+            final byte[] readBytes = new byte[1024 * 1024];
+            assertEquals(11, Os.read(fd.getFileDescriptor(), readBytes, 0, readBytes.length));
+        }
+    }
+
     private void setupProvider(int flag) {
         mDatabase = new MtpDatabase(getContext(), flag);
         mProvider = new MtpDocumentsProvider();
-        mProvider.onCreateForTesting(mResources, mMtpManager, mResolver, mDatabase);
+        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
+        assertTrue(mProvider.onCreateForTesting(
+                mResources, mMtpManager, mResolver, mDatabase, storageManager));
     }
 
     private String[] getStrings(Cursor cursor) {
@@ -424,7 +511,7 @@
             throws InterruptedException, TimeoutException, IOException {
         final int changeCount = mResolver.getChangeCount(ROOTS_URI);
         mMtpManager.addValidDevice(
-                new MtpDeviceRecord(deviceId, "Device", false /* unopened */, roots));
+                new MtpDeviceRecord(deviceId, "Device", false /* unopened */, roots, null, 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/MtpManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
index ed617e7..9ebe4d1 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
@@ -19,23 +19,27 @@
 import android.content.Context;
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbManager;
+import android.mtp.MtpConstants;
+import android.mtp.MtpEvent;
+import android.mtp.MtpObjectInfo;
 import android.os.CancellationSignal;
 import android.os.OperationCanceledException;
+import android.os.ParcelFileDescriptor;
+import android.os.SystemClock;
 import android.test.InstrumentationTestCase;
 
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.concurrent.Callable;
 import java.util.concurrent.FutureTask;
 import java.util.concurrent.TimeUnit;
 
 @RealDeviceTest
 public class MtpManagerTest extends InstrumentationTestCase {
-
     private static final int TIMEOUT_MS = 1000;
     UsbManager mUsbManager;
     MtpManager mManager;
     UsbDevice mUsbDevice;
-    int mRequest;
 
     @Override
     public void setUp() throws Exception {
@@ -61,8 +65,9 @@
                     @Override
                     public Boolean call() throws IOException {
                         try {
-                            mManager.readEvent(mUsbDevice.getDeviceId(), signal);
-                            return false;
+                            while (true) {
+                                mManager.readEvent(mUsbDevice.getDeviceId(), signal);
+                            }
                         } catch (OperationCanceledException exception) {
                             return true;
                         }
@@ -70,11 +75,82 @@
                 });
         final Thread thread = new Thread(future);
         thread.start();
-        Thread.sleep(TIMEOUT_MS);
+        SystemClock.sleep(TIMEOUT_MS);
         signal.cancel();
         assertTrue(future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS));
     }
 
+    public void testOperationsSupported() {
+        final MtpDeviceRecord[] records = mManager.getDevices();
+        assertEquals(1, records.length);
+        assertNotNull(records[0].operationsSupported);
+        getInstrumentation().show(Arrays.toString(records[0].operationsSupported));
+    }
+
+    public void testEventsSupported() {
+        final MtpDeviceRecord[] records = mManager.getDevices();
+        assertEquals(1, records.length);
+        assertNotNull(records[0].eventsSupported);
+        getInstrumentation().show(Arrays.toString(records[0].eventsSupported));
+    }
+
+    public void testEventObjectAdded() throws Exception {
+        while (true) {
+            getInstrumentation().show("Please take a photo by using connected MTP device.");
+            final CancellationSignal signal = new CancellationSignal();
+            MtpEvent event = mManager.readEvent(mUsbDevice.getDeviceId(), signal);
+            if (event.getEventCode() != MtpConstants.EVENT_OBJECT_ADDED) {
+                continue;
+            }
+            assertTrue(event.getObjectHandle() != 0);
+            break;
+        }
+    }
+
+    public void testCreateDocumentAndGetPartialObject() throws Exception {
+        int storageId = 0;
+        for (final MtpDeviceRecord record : mManager.getDevices()) {
+            if (record.deviceId == mUsbDevice.getDeviceId()) {
+                storageId = record.roots[0].mStorageId;
+                break;
+            }
+        }
+        assertTrue("Valid storage not found.", storageId != 0);
+
+        final String testFileName = "MtpManagerTest_testFile.txt";
+        for (final int handle : mManager.getObjectHandles(
+                mUsbDevice.getDeviceId(), storageId, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN)) {
+            if (mManager.getObjectInfo(mUsbDevice.getDeviceId(), handle)
+                    .getName().equals(testFileName)) {
+                mManager.deleteDocument(mUsbDevice.getDeviceId(), handle);
+                break;
+            }
+        }
+
+        final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
+        final byte[] expectedBytes = "Hello Android!".getBytes("ascii");
+        try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
+                new ParcelFileDescriptor.AutoCloseOutputStream(fds[1])) {
+            stream.write(expectedBytes);
+        }
+        final int objectHandle = mManager.createDocument(
+                mUsbDevice.getDeviceId(),
+                new MtpObjectInfo.Builder()
+                        .setStorageId(storageId)
+                        .setName(testFileName)
+                        .setCompressedSize(expectedBytes.length)
+                        .setFormat(MtpConstants.FORMAT_TEXT)
+                        .build(),
+                fds[0]);
+        final byte[] bytes = new byte[100];
+        assertEquals(5, mManager.getPartialObject(
+                mUsbDevice.getDeviceId(), objectHandle, 0, 5, bytes));
+        assertEquals("Hello", new String(bytes, 0, 5, "ascii"));
+        assertEquals(8, mManager.getPartialObject(
+                mUsbDevice.getDeviceId(), objectHandle, 6, 100, bytes));
+        assertEquals("Android!", new String(bytes, 0, 8, "ascii"));
+    }
+
     private Context getContext() {
         return getInstrumentation().getContext();
     }
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
index bbd0a30..1aaeb60 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
@@ -76,7 +76,7 @@
                 result[i] = device;
             } else {
                 result[i] = new MtpDeviceRecord(
-                        device.deviceId, device.name, device.opened, new MtpRoot[0]);
+                        device.deviceId, device.name, device.opened, new MtpRoot[0], null, null);
             }
         }
         return result;
@@ -90,7 +90,7 @@
         }
         mDevices.put(
                 deviceId,
-                new MtpDeviceRecord(device.deviceId, device.name, true, device.roots));
+                new MtpDeviceRecord(device.deviceId, device.name, true, device.roots, null, null));
     }
 
     @Override
@@ -101,7 +101,7 @@
         }
         mDevices.put(
                 deviceId,
-                new MtpDeviceRecord(device.deviceId, device.name, false, device.roots));
+                new MtpDeviceRecord(device.deviceId, device.name, false, device.roots, null, null));
     }
 
     @Override
@@ -203,4 +203,21 @@
         }
         return Arrays.copyOf(result, count);
     }
+
+    @Override
+    byte[] getObject(int deviceId, int objectHandle, int expectedSize) throws IOException {
+        return mImportFileBytes.get(pack(deviceId, objectHandle));
+    }
+
+    @Override
+    long getPartialObject(int deviceId, int objectHandle, long offset, long size, byte[] buffer)
+            throws IOException {
+        final byte[] bytes = mImportFileBytes.get(pack(deviceId, objectHandle));
+        int i = 0;
+        while (i < size && i + offset < bytes.length) {
+            buffer[i] = bytes[(int) (i + offset)];
+            i++;
+        }
+        return i;
+    }
 }
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java
index 611e831..ffcc088 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java
@@ -16,27 +16,21 @@
 
 package com.android.mtp;
 
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbDeviceConnection;
 import android.hardware.usb.UsbManager;
+import android.os.SystemClock;
 
 import java.io.IOException;
 import java.util.HashMap;
-import java.util.concurrent.CountDownLatch;
+import java.util.Objects;
+
 import junit.framework.Assert;
 
 /**
  * Static utility methods for testing.
  */
 final class TestUtil {
-    private static final String ACTION_USB_PERMISSION =
-            "com.android.mtp.USB_PERMISSION";
-
     private TestUtil() {}
 
     /**
@@ -46,40 +40,34 @@
     static UsbDevice setupMtpDevice(
             TestResultInstrumentation instrumentation,
             UsbManager usbManager,
-            MtpManager manager) throws InterruptedException, IOException {
-        for (int i = 0; i < 2; i++) {
-            final UsbDevice device = findMtpDevice(instrumentation, usbManager);
-            manager.openDevice(device.getDeviceId());
+            MtpManager manager) {
+        while (true) {
             try {
+                final UsbDevice device = findMtpDevice(usbManager, manager);
                 waitForStorages(instrumentation, manager, device.getDeviceId());
                 return device;
             } catch (IOException exp) {
+                instrumentation.show(Objects.toString(exp.getMessage()));
+                SystemClock.sleep(1000);
                 // When the MTP device is Android, and it changes the USB device type from
                 // "Charging" to "MTP", the device ID will be updated. We need to find a device
                 // again.
                 continue;
             }
         }
-        throw new IOException("Failed to obtain MTP devices");
     }
 
     private static UsbDevice findMtpDevice(
-            TestResultInstrumentation instrumentation,
-            UsbManager usbManager) throws InterruptedException {
-        while (true) {
-            final HashMap<String,UsbDevice> devices = usbManager.getDeviceList();
-            if (devices.size() == 0) {
-                instrumentation.show("Wait for devices.");
-                Thread.sleep(1000);
-                continue;
-            }
-            final UsbDevice device = devices.values().iterator().next();
-            requestPermission(instrumentation, usbManager, device);
+            UsbManager usbManager,
+            MtpManager manager) throws IOException {
+        final HashMap<String,UsbDevice> devices = usbManager.getDeviceList();
+        if (devices.size() == 0) {
+            throw new IOException("Device not found.");
+        }
+        final UsbDevice device = devices.values().iterator().next();
+        // Tries to get ownership of the device in case that another application use it.
+        if (usbManager.hasPermission(device)) {
             final UsbDeviceConnection connection = usbManager.openDevice(device);
-            if (connection == null) {
-                Assert.fail("Cannot open USB connection.");
-                return null;
-            }
             for (int i = 0; i < device.getInterfaceCount(); i++) {
                 // Since the test runs real environment, we need to call claim interface with
                 // force = true to rob interfaces from other applications.
@@ -87,40 +75,15 @@
                 connection.releaseInterface(device.getInterface(i));
             }
             connection.close();
-            return device;
         }
-    }
-
-    private static void requestPermission(
-            final TestResultInstrumentation instrumentation,
-            UsbManager usbManager,
-            UsbDevice device) throws InterruptedException {
-        if (usbManager.hasPermission(device)) {
-            return;
-        }
-        final CountDownLatch latch = new CountDownLatch(1);
-        final BroadcastReceiver receiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                latch.countDown();
-                instrumentation.getTargetContext().unregisterReceiver(this);
-            }
-        };
-        instrumentation.getTargetContext().registerReceiver(
-                receiver, new IntentFilter(ACTION_USB_PERMISSION));
-        usbManager.requestPermission(device, PendingIntent.getBroadcast(
-                instrumentation.getTargetContext(),
-                0 /* requstCode */,
-                new Intent(ACTION_USB_PERMISSION),
-                0 /* flags */));
-        latch.await();
-        Assert.assertTrue(usbManager.hasPermission(device));
+        manager.openDevice(device.getDeviceId());
+        return device;
     }
 
     private static void waitForStorages(
             TestResultInstrumentation instrumentation,
             MtpManager manager,
-            int deviceId) throws InterruptedException, IOException {
+            int deviceId) throws IOException {
         while (true) {
             MtpDeviceRecord device = null;
             for (final MtpDeviceRecord deviceCandidate : manager.getDevices()) {
@@ -134,7 +97,7 @@
             }
             if (device.roots.length == 0) {
                 instrumentation.show("Wait for storages.");
-                Thread.sleep(1000);
+                SystemClock.sleep(1000);
                 continue;
             }
             return;
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index 5a6f1d1..af9d251 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -17,9 +17,7 @@
  */
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.printspooler"
-    android:versionName="1"
-    android:versionCode="1">
+    package="com.android.printspooler">
 
     <!-- Allows an application to call APIs that give it access to all print jobs
          on the device. Usually an app can access only the print jobs it created. -->
@@ -40,6 +38,8 @@
     <uses-permission android:name="com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS"/>
     <uses-permission android:name="android.permission.WAKE_LOCK"/>
     <uses-permission android:name="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"/>
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
 
     <application
         android:allowClearUserData="true"
diff --git a/packages/PrintSpooler/res/drawable/ic_info.xml b/packages/PrintSpooler/res/drawable/ic_info.xml
new file mode 100644
index 0000000..2ecd1c7
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable/ic_info.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:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z"
+        android:fillColor="#757575"/>
+</vector>
\ No newline at end of file
diff --git a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
index 4381a7a..e0efbc4 100644
--- a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
+++ b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
@@ -62,7 +62,7 @@
             android:ellipsize="end"
             android:textIsSelectable="false"
             android:visibility="gone"
-            android:textColor="?android:attr/textColorPrimary"
+            android:textColor="?android:attr/textColorSecondary"
             android:duplicateParentState="true">
         </TextView>
 
diff --git a/packages/PrintSpooler/res/layout/printer_list_item.xml b/packages/PrintSpooler/res/layout/printer_list_item.xml
index 7bc144a..50f44c2 100644
--- a/packages/PrintSpooler/res/layout/printer_list_item.xml
+++ b/packages/PrintSpooler/res/layout/printer_list_item.xml
@@ -38,6 +38,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:orientation="vertical"
+        android:layout_weight="1"
         android:duplicateParentState="true">
 
         <TextView
@@ -62,10 +63,20 @@
             android:ellipsize="end"
             android:textIsSelectable="false"
             android:visibility="gone"
-            android:textColor="?android:attr/textColorPrimary"
+            android:textColor="?android:attr/textColorSecondary"
             android:duplicateParentState="true">
         </TextView>
 
     </LinearLayout>
 
+    <ImageView
+        android:id="@+id/more_info"
+        android:layout_width="24dip"
+        android:layout_height="24dip"
+        android:layout_gravity="center_vertical"
+        android:contentDescription="@string/printer_info_desc"
+        android:src="@drawable/ic_info"
+        android:visibility="gone">
+    </ImageView>
+
 </LinearLayout>
diff --git a/packages/PrintSpooler/res/values-af/strings.xml b/packages/PrintSpooler/res/values-af/strings.xml
index f263af7..57ba2b6 100644
--- a/packages/PrintSpooler/res/values-af/strings.xml
+++ b/packages/PrintSpooler/res/values-af/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> drukkers gevind</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> drukker gevind</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Soek tans vir drukkers"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Geen drukdienste is geaktiveer nie"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Kanselleer tans <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Drukkerfout by <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Drukker het <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> geblokkeer"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g>-druktake</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g>-druktaak</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Kanselleer"</string>
     <string name="restart" msgid="2472034227037808749">"Herbegin"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Geen verbinding met drukker nie"</string>
diff --git a/packages/PrintSpooler/res/values-am/strings.xml b/packages/PrintSpooler/res/values-am/strings.xml
index a93e0a9..a2182fb 100644
--- a/packages/PrintSpooler/res/values-am/strings.xml
+++ b/packages/PrintSpooler/res/values-am/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"አታሚዎችን በመፈለግ ላይ"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"ምንም የህትመት አገልግሎቶች አልነቁም"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ን በመተው ላይ"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"የአታሚ ስህተት <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"አታሚ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ን አግዷል"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> የህትመት ስራ</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> የህትመት ስራ</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"ይቅር"</string>
     <string name="restart" msgid="2472034227037808749">"እንደገና ጀምር"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"ከአታሚ ጋር ምንም ግንኙነት የለም"</string>
diff --git a/packages/PrintSpooler/res/values-ar/strings.xml b/packages/PrintSpooler/res/values-ar/strings.xml
index c9a6a395..eab1339 100644
--- a/packages/PrintSpooler/res/values-ar/strings.xml
+++ b/packages/PrintSpooler/res/values-ar/strings.xml
@@ -63,6 +63,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"البحث عن طابعات"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"لم يتم تمكين أي خدمات طباعة"</string>
@@ -71,14 +74,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"جارٍ إلغاء <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"خطا في الطابعة <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"رفضت الطابعة <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="zero"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> مهمة طباعة</item>
-      <item quantity="two">مهمتا طباعة (<xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g>)</item>
-      <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> مهام طباعة</item>
-      <item quantity="many"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> مهمة طباعة</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> من مهام الطباعة</item>
-      <item quantity="one">مهمة طباعة واحدة (<xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g>)</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"إلغاء"</string>
     <string name="restart" msgid="2472034227037808749">"إعادة تشغيل"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"لا يوجد اتصال بالطابعة"</string>
diff --git a/packages/PrintSpooler/res/values-az-rAZ/strings.xml b/packages/PrintSpooler/res/values-az-rAZ/strings.xml
index 5aeb7bb..bff477d 100644
--- a/packages/PrintSpooler/res/values-az-rAZ/strings.xml
+++ b/packages/PrintSpooler/res/values-az-rAZ/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printer tapıldı</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printer tapıldı</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">"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_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>
@@ -67,10 +70,6 @@
     <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>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printer <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> işini blokladı"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> çap işi</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> çap işi</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Ləğv et"</string>
     <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>
diff --git a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
index 7484718..b28aa29 100644
--- a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
+++ b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
@@ -60,6 +60,9 @@
       <item quantity="few">Pronađena su <xliff:g id="COUNT_1">%1$s</xliff:g> štampača</item>
       <item quantity="other">Pronađeno je <xliff:g id="COUNT_1">%1$s</xliff:g> štampača</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">"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_searching_for_printers" msgid="6550424555079932867">"Pretraga štampača"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Nijedna usluga štampanja nije omogućena"</string>
@@ -68,11 +71,6 @@
     <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>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Štampač je blokirao <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one">Zadaci štampanja <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="few">Zadaci štampanja <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="other">Zadaci štampanja <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-    </plurals>
     <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 veze sa štampačem"</string>
diff --git a/packages/PrintSpooler/res/values-bg/strings.xml b/packages/PrintSpooler/res/values-bg/strings.xml
index 93feea5..e8de8ea 100644
--- a/packages/PrintSpooler/res/values-bg/strings.xml
+++ b/packages/PrintSpooler/res/values-bg/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"Търсене на принтери"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Няма активирани услуги за отпечатване"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"„<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“ се анулира"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Грешка в принтера при „<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Принтерът блокира при „<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other">Задания за отпечатване: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="one">Задание за отпечатване: <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Отказ"</string>
     <string name="restart" msgid="2472034227037808749">"Рестартиране"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Няма връзка с принтера"</string>
diff --git a/packages/PrintSpooler/res/values-bn-rBD/strings.xml b/packages/PrintSpooler/res/values-bn-rBD/strings.xml
index 0eed9aa..a1ca494 100644
--- a/packages/PrintSpooler/res/values-bn-rBD/strings.xml
+++ b/packages/PrintSpooler/res/values-bn-rBD/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"মুদ্রকগুলি অনুসন্ধান করা হচ্ছে"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"মুদ্রণ পরিষেবা সক্ষম নেই"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> বাতিল করা হচ্ছে"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> মুদ্রক ত্রুটি"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"মুদ্রক <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> অবরুদ্ধ করেছে"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> মুদ্রণ কার্যগুলি</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> মুদ্রণ কার্যগুলি</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"বাতিল করুন"</string>
     <string name="restart" msgid="2472034227037808749">"পুনর্সূচনা"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"মুদ্রকে কোনো সংযোগ নেই"</string>
diff --git a/packages/PrintSpooler/res/values-ca/strings.xml b/packages/PrintSpooler/res/values-ca/strings.xml
index 03d3060..aa6f992 100644
--- a/packages/PrintSpooler/res/values-ca/strings.xml
+++ b/packages/PrintSpooler/res/values-ca/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other">S\'han trobat <xliff:g id="COUNT_1">%1$s</xliff:g> impressores</item>
       <item quantity="one">S\'ha trobat <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item>
     </plurals>
+    <string name="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_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>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"S\'està cancel·lant <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Error d\'impressora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Impressora bloquejada <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tasques d\'impressió</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> tasca d\'impressió</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Cancel·la"</string>
     <string name="restart" msgid="2472034227037808749">"Reinicia"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"No hi ha connexió amb la impressora"</string>
diff --git a/packages/PrintSpooler/res/values-cs/strings.xml b/packages/PrintSpooler/res/values-cs/strings.xml
index 414abf9..4bc22d4 100644
--- a/packages/PrintSpooler/res/values-cs/strings.xml
+++ b/packages/PrintSpooler/res/values-cs/strings.xml
@@ -61,6 +61,9 @@
       <item quantity="other">Nalezené tiskárny: <xliff:g id="COUNT_1">%1$s</xliff:g></item>
       <item quantity="one">Nalezené tiskárny: <xliff:g id="COUNT_0">%1$s</xliff:g></item>
     </plurals>
+    <string name="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_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>
@@ -69,12 +72,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Rušení úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Chyba tiskárny u úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Tiskárna blokuje úlohu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="few">Tiskové úlohy: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="many">Tiskové úlohy: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="other">Tiskové úlohy: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="one">Tiskové úlohy: <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Zrušit"</string>
     <string name="restart" msgid="2472034227037808749">"Restartovat"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Nelze se připojit k tiskárně"</string>
diff --git a/packages/PrintSpooler/res/values-da/strings.xml b/packages/PrintSpooler/res/values-da/strings.xml
index 893c991..b8be624 100644
--- a/packages/PrintSpooler/res/values-da/strings.xml
+++ b/packages/PrintSpooler/res/values-da/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="one">Der blev fundet <xliff:g id="COUNT_1">%1$s</xliff:g> printere</item>
       <item quantity="other">Der blev fundet <xliff:g id="COUNT_1">%1$s</xliff:g> printere</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Søger efter printere"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Ingen udskrivningstjenester er aktiveret"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> annulleres"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Udskriften <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> mislykkedes"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printeren har blokeret <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g>-udskriftsjob</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g>-udskriftsjob</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Annuller"</string>
     <string name="restart" msgid="2472034227037808749">"Genstart"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Ingen forbindelse til printer"</string>
diff --git a/packages/PrintSpooler/res/values-de/strings.xml b/packages/PrintSpooler/res/values-de/strings.xml
index f6f53ea..bcb7e73 100644
--- a/packages/PrintSpooler/res/values-de/strings.xml
+++ b/packages/PrintSpooler/res/values-de/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> Drucker gefunden</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> Drucker gefunden</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Suche nach Druckern"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Keine Druckdienste aktiviert"</string>
@@ -67,17 +70,13 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> wird abgebrochen..."</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Druckerfehler <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Drucker hat <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> blockiert."</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other">Druckaufträge \"<xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g>\"</item>
-      <item quantity="one">Druckauftrag \"<xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g>\"</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Abbrechen"</string>
     <string name="restart" msgid="2472034227037808749">"Neu starten"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Keine Verbindung zum Drucker"</string>
     <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">"Ihr Dokument passiert bei der Übermittlung an den Drucker möglicherweise einen oder mehrere Server."</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">
     <item msgid="7602948745415174937">"Schwarz-weiß"</item>
     <item msgid="2762241247228983754">"Farbe"</item>
@@ -92,7 +91,7 @@
     <item msgid="3199660090246166812">"Querformat"</item>
   </string-array>
     <string name="print_write_error_message" msgid="5787642615179572543">"Fehler beim Schreiben in Datei"</string>
-    <string name="print_error_default_message" msgid="8602678405502922346">"Fehler. Bitte versuchen Sie es erneut."</string>
+    <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_preparing_preview" msgid="3939930735671364712">"Vorschau wird vorbereitet…"</string>
diff --git a/packages/PrintSpooler/res/values-el/strings.xml b/packages/PrintSpooler/res/values-el/strings.xml
index 10ddf62..d9a4aeb 100644
--- a/packages/PrintSpooler/res/values-el/strings.xml
+++ b/packages/PrintSpooler/res/values-el/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"Αναζήτηση για εκτυπωτές"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Δεν έχουν ενεργοποιηθεί υπηρεσίες εκτύπωσης"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Ακύρωση <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Σφάλμα εκτυπωτή <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Ο εκτυπωτής απέκλεισε <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> εργασίες εκτύπωσης</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> εργασία εκτύπωσης</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Ακύρωση"</string>
     <string name="restart" msgid="2472034227037808749">"Επανεκκίνηση"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Δεν υπάρχει σύνδεση με εκτυπωτή"</string>
diff --git a/packages/PrintSpooler/res/values-en-rAU/strings.xml b/packages/PrintSpooler/res/values-en-rAU/strings.xml
index a540ac5..d8a9437 100644
--- a/packages/PrintSpooler/res/values-en-rAU/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rAU/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printer found</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Searching for printers"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"No print services enabled"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelling <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Printer error <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printer blocked <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> print jobs</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> print job</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Cancel"</string>
     <string name="restart" msgid="2472034227037808749">"Restart"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"No connection to printer"</string>
diff --git a/packages/PrintSpooler/res/values-en-rGB/strings.xml b/packages/PrintSpooler/res/values-en-rGB/strings.xml
index a540ac5..d8a9437 100644
--- a/packages/PrintSpooler/res/values-en-rGB/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rGB/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printer found</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Searching for printers"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"No print services enabled"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelling <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Printer error <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printer blocked <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> print jobs</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> print job</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Cancel"</string>
     <string name="restart" msgid="2472034227037808749">"Restart"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"No connection to printer"</string>
diff --git a/packages/PrintSpooler/res/values-en-rIN/strings.xml b/packages/PrintSpooler/res/values-en-rIN/strings.xml
index a540ac5..d8a9437 100644
--- a/packages/PrintSpooler/res/values-en-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rIN/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printer found</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Searching for printers"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"No print services enabled"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelling <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Printer error <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printer blocked <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> print jobs</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> print job</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Cancel"</string>
     <string name="restart" msgid="2472034227037808749">"Restart"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"No connection to printer"</string>
diff --git a/packages/PrintSpooler/res/values-es-rUS/strings.xml b/packages/PrintSpooler/res/values-es-rUS/strings.xml
index 8929aa8..19cbee7 100644
--- a/packages/PrintSpooler/res/values-es-rUS/strings.xml
+++ b/packages/PrintSpooler/res/values-es-rUS/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other">Se encontraron <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras.</item>
       <item quantity="one">Se encontró <xliff:g id="COUNT_0">%1$s</xliff:g> impresora.</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Buscando impresoras"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"No hay servicios de impresión habilitados"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Error de impresora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"La impresora bloqueó <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>."</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other">Trabajos de impresión: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="one">Trabajo de impresión: <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Cancelar"</string>
     <string name="restart" msgid="2472034227037808749">"Reiniciar"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"No hay conexión con la impresora."</string>
@@ -93,7 +92,7 @@
   </string-array>
     <string name="print_write_error_message" msgid="5787642615179572543">"No se pudo escribir en el archivo."</string>
     <string name="print_error_default_message" msgid="8602678405502922346">"No funcionó. Vuelve a intentarlo."</string>
-    <string name="print_error_retry" msgid="1426421728784259538">"Reintentar"</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_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 7cfd92a..d13ccda 100644
--- a/packages/PrintSpooler/res/values-es/strings.xml
+++ b/packages/PrintSpooler/res/values-es/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other">Se han encontrado <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
       <item quantity="one">Se ha encontrado <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Buscando impresoras"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"No hay servicios de impresión habilitados"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Error de impresora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"La impresora ha bloqueado <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other">Trabajos de impresión <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="one">Trabajo de impresión <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Cancelar"</string>
     <string name="restart" msgid="2472034227037808749">"Volver a empezar"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"No hay conexión con la impresora"</string>
diff --git a/packages/PrintSpooler/res/values-et-rEE/strings.xml b/packages/PrintSpooler/res/values-et-rEE/strings.xml
index ee93bcf..f03eb37 100644
--- a/packages/PrintSpooler/res/values-et-rEE/strings.xml
+++ b/packages/PrintSpooler/res/values-et-rEE/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other">Leiti <xliff:g id="COUNT_1">%1$s</xliff:g> printerit</item>
       <item quantity="one">Leiti <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Printerite otsimine"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Ühtegi printimisteenust pole lubatud"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Prinditöö <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> tühistamine"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Printeri viga: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printer blokeeris töö <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> prinditööd</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> prinditöö</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Tühista"</string>
     <string name="restart" msgid="2472034227037808749">"Taaskäivita"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Printeriühendus puudub"</string>
diff --git a/packages/PrintSpooler/res/values-eu-rES/strings.xml b/packages/PrintSpooler/res/values-eu-rES/strings.xml
index 882e888..d4255e2 100644
--- a/packages/PrintSpooler/res/values-eu-rES/strings.xml
+++ b/packages/PrintSpooler/res/values-eu-rES/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> inprimagailu aurkitu dira</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> inprimagailu aurkitu da</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Inprimagailuak bilatzen"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Ez dago gaituta inprimatzeko zerbitzurik"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> bertan behera uzten"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Errorea <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> inprimatzean"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Inprimag. <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> blokeatu du"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> inprimatze-lanak</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> inprimatze-lana</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Utzi"</string>
     <string name="restart" msgid="2472034227037808749">"Berrabiarazi"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Inprimagailua ez dago konektatuta"</string>
diff --git a/packages/PrintSpooler/res/values-fa/strings.xml b/packages/PrintSpooler/res/values-fa/strings.xml
index 10743e7..907123c 100644
--- a/packages/PrintSpooler/res/values-fa/strings.xml
+++ b/packages/PrintSpooler/res/values-fa/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"درحال جستجوی چاپگرها"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"هیچ خدمات چاپی فعال نیست"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"در حال لغو <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"خطای چاپگر <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"چاپگر، کار <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> را مسدود کرد"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one">کار چاپ <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="other">کار چاپ <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"لغو"</string>
     <string name="restart" msgid="2472034227037808749">"راه‌اندازی مجدد"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"اتصال با چاپگر برقرار نیست"</string>
diff --git a/packages/PrintSpooler/res/values-fi/strings.xml b/packages/PrintSpooler/res/values-fi/strings.xml
index ee35c41..f57b884 100644
--- a/packages/PrintSpooler/res/values-fi/strings.xml
+++ b/packages/PrintSpooler/res/values-fi/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> tulostinta löydetty</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> tulostin löydetty</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Etsitään tulostimia"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Ei käytössä olevia tulostuspalveluita"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Peruutetaan työ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Tulostinvirhe työlle <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Tulostin esti työn <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tulostustyötä</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> tulostustyö</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Peruuta"</string>
     <string name="restart" msgid="2472034227037808749">"Käynnistä uudelleen"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Ei yhteyttä tulostimeen"</string>
diff --git a/packages/PrintSpooler/res/values-fr-rCA/strings.xml b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
index eb99441..949ba55 100644
--- a/packages/PrintSpooler/res/values-fr-rCA/strings.xml
+++ b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante trouvée</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante trouvées</item>
     </plurals>
+    <string name="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_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>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annulation de « <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> »…"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Erreur impression : « <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> »"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Impression de « <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> » bloquée"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tâche d\'impression</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tâches d\'impression</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Annuler"</string>
     <string name="restart" msgid="2472034227037808749">"Recommencer"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Aucune connexion à l\'imprimante"</string>
diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml
index c0eecfb..1fcc040 100644
--- a/packages/PrintSpooler/res/values-fr/strings.xml
+++ b/packages/PrintSpooler/res/values-fr/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante trouvée</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimantes trouvées</item>
     </plurals>
+    <string name="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_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>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annulation de \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" en cours…"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Erreur impression pour \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\""</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Impression de \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" bloquée"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tâche d\'impression</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tâches d\'impression</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Annuler"</string>
     <string name="restart" msgid="2472034227037808749">"Redémarrer"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Aucune connexion à l\'imprimante."</string>
diff --git a/packages/PrintSpooler/res/values-gl-rES/strings.xml b/packages/PrintSpooler/res/values-gl-rES/strings.xml
index b4a1ec6..2e60960 100644
--- a/packages/PrintSpooler/res/values-gl-rES/strings.xml
+++ b/packages/PrintSpooler/res/values-gl-rES/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other">Encontráronse <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
       <item quantity="one">Encontrouse <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
     </plurals>
+    <string name="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_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>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Erro da impresora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"A impresora bloqueou <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> traballos de impresión</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> traballo de impresión</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Cancelar"</string>
     <string name="restart" msgid="2472034227037808749">"Reiniciar"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Non hai conexión coa impresora"</string>
diff --git a/packages/PrintSpooler/res/values-gu-rIN/strings.xml b/packages/PrintSpooler/res/values-gu-rIN/strings.xml
index 8f77953..4ba969c 100644
--- a/packages/PrintSpooler/res/values-gu-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-gu-rIN/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"પ્રિન્ટર્સ માટે શોધી રહ્યું છે"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"કોઈ છાપ સેવાઓ સક્ષમ કરેલ નથી"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ને રદ કરી રહ્યું છે"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"પ્રિન્ટર ભૂલ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"પ્રિન્ટરે <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> અવરોધિત કર્યું"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> છાપ જોબ</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> છાપ જોબ</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"રદ કરો"</string>
     <string name="restart" msgid="2472034227037808749">"પુનઃપ્રારંભ કરો"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"પ્રિન્ટર માટે કોઈ કનેક્શન નથી"</string>
diff --git a/packages/PrintSpooler/res/values-hi/strings.xml b/packages/PrintSpooler/res/values-hi/strings.xml
index 4c11323..1061346 100644
--- a/packages/PrintSpooler/res/values-hi/strings.xml
+++ b/packages/PrintSpooler/res/values-hi/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"प्रिंटर खोज रहा है"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"कोई भी प्रिंट सेवा सक्षम नहीं है"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> रद्द हो रहा है"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिंटर त्रुटि <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"प्रिंटर अवरोधित <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> प्रिंट कार्य</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> प्रिंट कार्य</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"अभी नहीं"</string>
     <string name="restart" msgid="2472034227037808749">"पुन: आरंभ करें"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"प्रिंटर के लिए कोई कनेक्शन नहीं"</string>
diff --git a/packages/PrintSpooler/res/values-hr/strings.xml b/packages/PrintSpooler/res/values-hr/strings.xml
index 4cec3ba..4a7d29f 100644
--- a/packages/PrintSpooler/res/values-hr/strings.xml
+++ b/packages/PrintSpooler/res/values-hr/strings.xml
@@ -60,6 +60,9 @@
       <item quantity="few">Pronađena su <xliff:g id="COUNT_1">%1$s</xliff:g> pisača</item>
       <item quantity="other">Pronađeno je <xliff:g id="COUNT_1">%1$s</xliff:g> pisača</item>
     </plurals>
+    <string name="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_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>
@@ -68,11 +71,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Otkazivanje zadatka <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Pogreška pisača <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Pisač je blokirao <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> zadatak ispisa</item>
-      <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> zadatka ispisa</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> zadataka ispisa</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Odustani"</string>
     <string name="restart" msgid="2472034227037808749">"Ponovo pokreni"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Nema veze s pisačem"</string>
diff --git a/packages/PrintSpooler/res/values-hu/strings.xml b/packages/PrintSpooler/res/values-hu/strings.xml
index ac1ba6e..5aae2e4 100644
--- a/packages/PrintSpooler/res/values-hu/strings.xml
+++ b/packages/PrintSpooler/res/values-hu/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> nyomtató észlelve</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> nyomtató észlelve</item>
     </plurals>
+    <string name="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_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>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"A(z) <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> törlése"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Nyomtatási hiba: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"A(z) <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> letiltva."</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> nyomtatási feladat</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> nyomtatási feladat</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Mégse"</string>
     <string name="restart" msgid="2472034227037808749">"Újraindítás"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Nincs kapcsolat a nyomtatóval"</string>
diff --git a/packages/PrintSpooler/res/values-hy-rAM/strings.xml b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
index dda6745..179c384 100644
--- a/packages/PrintSpooler/res/values-hy-rAM/strings.xml
+++ b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"Տպիչների որոնում"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Ակտիվացված տպման ծառայություններ չկան"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>-ը չեղարկվում է"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Տպիչի սխալ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Տպիչն արգելափակել է <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>-ը"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> տպման աշխատանք</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> տպման աշխատանք</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Չեղարկել"</string>
     <string name="restart" msgid="2472034227037808749">"Վերագործարկել"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Տպիչի հետ կապ չկա"</string>
diff --git a/packages/PrintSpooler/res/values-in/strings.xml b/packages/PrintSpooler/res/values-in/strings.xml
index b203e2b..7286f7a 100644
--- a/packages/PrintSpooler/res/values-in/strings.xml
+++ b/packages/PrintSpooler/res/values-in/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printer ditemukan</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printer ditemukan</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Mencari printer"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Tidak ada layanan cetak yang aktif"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Membatalkan <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Ada kesalahan printer <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printer memblokir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other">Tugas cetak <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="one">Tugas cetak <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Batal"</string>
     <string name="restart" msgid="2472034227037808749">"Mulai Ulang"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Tidak ada sambungan ke printer"</string>
diff --git a/packages/PrintSpooler/res/values-is-rIS/strings.xml b/packages/PrintSpooler/res/values-is-rIS/strings.xml
index 6dfdabc..9ea49a9 100644
--- a/packages/PrintSpooler/res/values-is-rIS/strings.xml
+++ b/packages/PrintSpooler/res/values-is-rIS/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> prentari fannst</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> prentarar fundust</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Leitar að prentara"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Engin prentþjónusta er virk"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Hættir við <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Prentaravilla <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Prentari útilokaði <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> prentverk</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> prentverk</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Hætta við"</string>
     <string name="restart" msgid="2472034227037808749">"Endurræsa"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Engin tenging við prentara"</string>
diff --git a/packages/PrintSpooler/res/values-it/strings.xml b/packages/PrintSpooler/res/values-it/strings.xml
index fd5473a..c19d012 100644
--- a/packages/PrintSpooler/res/values-it/strings.xml
+++ b/packages/PrintSpooler/res/values-it/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> stampanti trovate</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> stampante trovata</item>
     </plurals>
+    <string name="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_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>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annullamento di <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Errore della stampante: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"La stampante ha bloccato <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> processi di stampa</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> processo di stampa</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Annulla"</string>
     <string name="restart" msgid="2472034227037808749">"Riavvia"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Nessun collegamento alla stampante"</string>
diff --git a/packages/PrintSpooler/res/values-iw/strings.xml b/packages/PrintSpooler/res/values-iw/strings.xml
index dd062a3..00bf27c 100644
--- a/packages/PrintSpooler/res/values-iw/strings.xml
+++ b/packages/PrintSpooler/res/values-iw/strings.xml
@@ -61,6 +61,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"מחפש מדפסות"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"לא הופעלו שירותי הדפסה"</string>
@@ -69,12 +72,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"מבטל את <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"שגיאת מדפסת ב-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"המדפסת חסמה את <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="two"> עבודות הדפסה <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="many"> עבודות הדפסה <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="other"> עבודות הדפסה <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="one"> עבודת הדפסה <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"בטל"</string>
     <string name="restart" msgid="2472034227037808749">"הפעל מחדש"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"אין חיבור למדפסת"</string>
diff --git a/packages/PrintSpooler/res/values-ja/strings.xml b/packages/PrintSpooler/res/values-ja/strings.xml
index 23e4809..e0fc79a 100644
--- a/packages/PrintSpooler/res/values-ja/strings.xml
+++ b/packages/PrintSpooler/res/values-ja/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"プリンタの検索中"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"使用できる印刷サービスがありません"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>をキャンセルしています"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"プリンタエラー: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>をブロックしました"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g>の印刷ジョブ</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g>の印刷ジョブ</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"キャンセル"</string>
     <string name="restart" msgid="2472034227037808749">"再試行"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"プリンタに接続されていません"</string>
diff --git a/packages/PrintSpooler/res/values-ka-rGE/strings.xml b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
index 9f86f05..ad1468a 100644
--- a/packages/PrintSpooler/res/values-ka-rGE/strings.xml
+++ b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"მიმდინარეობს პრინტერების ძიება"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"ბეჭდვის სერვისები გააქტიურებული არ არის"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"მიმდინარეობს <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>-ის გაუქმება"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"ბეჭდვის შეცდომა <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"პრინტერმა დაბლოკა <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ბეჭდვის დავალება</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> ბეჭდვის დავალება</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"გაუქმება"</string>
     <string name="restart" msgid="2472034227037808749">"გადატვირთვა"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"პრინტერთან კავშირი არ არის"</string>
diff --git a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
index 05c300e..d0337a6 100644
--- a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
+++ b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"Принтерлерді іздеу"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Басып шығару қызметтері қосылмаған"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> жұмысын тоқтатуда"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> принтер қателігі"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Принтер <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> жұмысын бөгеді"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> баспа тапсырмасы</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> баспа тапсырмасы</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Тоқтату"</string>
     <string name="restart" msgid="2472034227037808749">"Қайта бастау"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Принтермен байланыс жоқ"</string>
diff --git a/packages/PrintSpooler/res/values-km-rKH/strings.xml b/packages/PrintSpooler/res/values-km-rKH/strings.xml
index 0861e59..c9431e9 100644
--- a/packages/PrintSpooler/res/values-km-rKH/strings.xml
+++ b/packages/PrintSpooler/res/values-km-rKH/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"ស្វែងរក​ម៉ាស៊ីន​បោះពុម្ព"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"គ្មានការបើកដំណើរការសេវាបោះពុម្ពទេ"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"ការ​បោះបង់ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"កំហុស​ម៉ាស៊ីន​បោះពុម្ព <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"ម៉ាស៊ីន​បោះពុម្ព​បាន​ទប់ស្កាត់ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other">ការងារបោះពុម្ព <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="one">ការងារបោះពុម្ព <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"បោះបង់"</string>
     <string name="restart" msgid="2472034227037808749">"ចាប់ផ្ដើម​ឡើងវិញ"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"គ្មាន​​​ការ​ភ្ជាប់​ទៅ​ម៉ាស៊ីន​បោះពុម្ព​"</string>
diff --git a/packages/PrintSpooler/res/values-kn-rIN/strings.xml b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
index 71b098d..fc5149a 100644
--- a/packages/PrintSpooler/res/values-kn-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"ಪ್ರಿಂಟರ್‌‌ಗಳಿಗಾಗಿ ಹುಡುಕಲಾಗುತ್ತಿದೆ"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"ಯಾವುದೇ ಮುದ್ರಣ ಸೇವೆಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿಲ್ಲ"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ರದ್ದು ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"ಮುದ್ರಕ ದೋಷ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"ಮುದ್ರಕವು <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ನಿರ್ಬಂಧಿಸಿದೆ"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ಮುದ್ರಣ ಕಾರ್ಯಗಳು</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ಮುದ್ರಣ ಕಾರ್ಯಗಳು</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"ರದ್ದುಮಾಡು"</string>
     <string name="restart" msgid="2472034227037808749">"ಮರುಪ್ರಾರಂಭಿಸು"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"ಮುದ್ರಕಕ್ಕೆ ಸಂಪರ್ಕವಿಲ್ಲ"</string>
diff --git a/packages/PrintSpooler/res/values-ko/strings.xml b/packages/PrintSpooler/res/values-ko/strings.xml
index 451ab58..2faff1f 100644
--- a/packages/PrintSpooler/res/values-ko/strings.xml
+++ b/packages/PrintSpooler/res/values-ko/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"프린터 검색 중"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"사용 가능한 프린트 서비스 없음"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> 취소 중"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"프린터 오류: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"차단된 프린터: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> 인쇄 작업</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> 인쇄 작업</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"취소"</string>
     <string name="restart" msgid="2472034227037808749">"다시 시작"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"프린터와 연결되지 않음"</string>
diff --git a/packages/PrintSpooler/res/values-ky-rKG/strings.xml b/packages/PrintSpooler/res/values-ky-rKG/strings.xml
index 98da08c..a01e4a8 100644
--- a/packages/PrintSpooler/res/values-ky-rKG/strings.xml
+++ b/packages/PrintSpooler/res/values-ky-rKG/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"Принтерлер изделүүдө"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Принтер-кызматтары иштетилген эмес"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> токтотулууда"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Принтерде ката кетти: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Принтер бөгөттөдү: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> басуу тапшырмасы</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> басуу тапшырмасы</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Айнуу"</string>
     <string name="restart" msgid="2472034227037808749">"Кайра баштоо"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Принтер менен байланыш жок"</string>
diff --git a/packages/PrintSpooler/res/values-lo-rLA/strings.xml b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
index 2029fdf..b5d13b5 100644
--- a/packages/PrintSpooler/res/values-lo-rLA/strings.xml
+++ b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"ກຳລັງຊອກຫາເຄື່ອງພິມ"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"ບໍ່​ມີ​ການ​ບໍ​ລິ​ການ​ພິມ​ເປີດ​ໃຊ້​ງານ​ໄວ້"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"ກຳລັງຍົກເລີກ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"ເຄື່ອງພິມເກີດຂໍ້ຜິດພາດ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"ເຄື່ອງພິມຖືກບລອກ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ງານ​ພິມ</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> ງານ​ພິມ</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"ຍົກເລີກ"</string>
     <string name="restart" msgid="2472034227037808749">"ປິດເປີດໃໝ່"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"ບໍ່ມີການເຊື່ອມຕໍ່ຫາເຄື່ອງພິມ"</string>
diff --git a/packages/PrintSpooler/res/values-lt/strings.xml b/packages/PrintSpooler/res/values-lt/strings.xml
index 972abb5..3b8f143 100644
--- a/packages/PrintSpooler/res/values-lt/strings.xml
+++ b/packages/PrintSpooler/res/values-lt/strings.xml
@@ -61,6 +61,9 @@
       <item quantity="many">Rasta <xliff:g id="COUNT_1">%1$s</xliff:g> spausdintuvo</item>
       <item quantity="other">Rasta <xliff:g id="COUNT_1">%1$s</xliff:g> spausdintuvų</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Ieškoma spausdintuvų"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Neįgalinta jokių spausdinimo paslaugų"</string>
@@ -69,12 +72,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Atšaukiama: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Spausdintuvo klaida: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Spausdintuvas užblokavo: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> spausdinimo užduotis</item>
-      <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> spausdinimo užduotys</item>
-      <item quantity="many"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> spausdinimo užduoties</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> spausdinimo užduočių</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Atšaukti"</string>
     <string name="restart" msgid="2472034227037808749">"Paleisti iš naujo"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Nėra ryšio su spausdintuvu"</string>
diff --git a/packages/PrintSpooler/res/values-lv/strings.xml b/packages/PrintSpooler/res/values-lv/strings.xml
index f565b23..762d0bd 100644
--- a/packages/PrintSpooler/res/values-lv/strings.xml
+++ b/packages/PrintSpooler/res/values-lv/strings.xml
@@ -60,6 +60,9 @@
       <item quantity="one">Atrasts <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
       <item quantity="other">Atrasti <xliff:g id="COUNT_1">%1$s</xliff:g> printeri</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Printeru meklēšana"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Nav iespējots neviens drukas pakalpojums"</string>
@@ -68,11 +71,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Pārtrauc drukas darbu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>…"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Printera kļūda ar darbu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printeris bloķēja darbu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="zero"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> drukas darbi</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> drukas darbs</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> drukas darbi</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Atcelt"</string>
     <string name="restart" msgid="2472034227037808749">"Restartēt"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Nav savienojuma ar printeri"</string>
diff --git a/packages/PrintSpooler/res/values-mk-rMK/strings.xml b/packages/PrintSpooler/res/values-mk-rMK/strings.xml
index f5c06d1..de6d3e9 100644
--- a/packages/PrintSpooler/res/values-mk-rMK/strings.xml
+++ b/packages/PrintSpooler/res/values-mk-rMK/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"Пребарување печатачи"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Нема овозможени услуги за печатење"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> се откажува"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Грешка при печатење <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Печатачот го блокираше <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> работа за печатење</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> работи за печатење</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Откажи"</string>
     <string name="restart" msgid="2472034227037808749">"Рестартирај"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Нема поврзување со печатач"</string>
diff --git a/packages/PrintSpooler/res/values-ml-rIN/strings.xml b/packages/PrintSpooler/res/values-ml-rIN/strings.xml
index 2d45ce5..7a33e14 100644
--- a/packages/PrintSpooler/res/values-ml-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-ml-rIN/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"പ്രിന്ററുകൾക്കായി തിരയുന്നു"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"പ്രിന്റ് സേവനങ്ങളൊന്നും പ്രവർത്തനക്ഷമാക്കിയിട്ടില്ല"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> റദ്ദാക്കുന്നു"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"പ്രിന്റർ പിശക് <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"പ്രിന്റർ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> തടഞ്ഞു"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> പ്രിന്റ് ജോലികൾ</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> പ്രിന്റ് ജോലി</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"റദ്ദാക്കുക"</string>
     <string name="restart" msgid="2472034227037808749">"പുനരാരംഭിക്കുക"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"പ്രിന്ററിൽ കണക്ഷനൊന്നുമില്ല"</string>
diff --git a/packages/PrintSpooler/res/values-mn-rMN/strings.xml b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
index f2c7b73..c94e56d 100644
--- a/packages/PrintSpooler/res/values-mn-rMN/strings.xml
+++ b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"Принтер хайж байна"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Хэвлэх үйлчилгээг идэвхжүүлээгүй"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Цуцлаж байна <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Принтерийн алдаа <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Принтер хориглогдсон <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ажлыг хэвлэх</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> ажлыг хэвлэх</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Цуцлах"</string>
     <string name="restart" msgid="2472034227037808749">"Дахин эхлүүлэх"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Принтер холбогдоогүй байна"</string>
diff --git a/packages/PrintSpooler/res/values-mr-rIN/strings.xml b/packages/PrintSpooler/res/values-mr-rIN/strings.xml
index 1c079dc..ab25010 100644
--- a/packages/PrintSpooler/res/values-mr-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-mr-rIN/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"प्रिंटर शोधत आहे"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"कोणत्याही मुद्रण सेवा सक्षम केलेल्या नाहीत"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> रद्द करीत आहे"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिंटर त्रुटी <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"प्रिंटरने <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> अवरोधित केले"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> मुद्रण कार्य</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> मुद्रण कार्ये</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"रद्द करा"</string>
     <string name="restart" msgid="2472034227037808749">"रीस्टार्ट करा"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"प्रिंटरवर कोणतेही कनेक्‍शन नाही"</string>
diff --git a/packages/PrintSpooler/res/values-ms-rMY/strings.xml b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
index d6b5ea7..917ae8a 100644
--- a/packages/PrintSpooler/res/values-ms-rMY/strings.xml
+++ b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> pencetak ditemui</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> pencetak ditemui</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Mencari pencetak"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Perkhidmatan cetak tidak didayakan"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Membatalkan <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Ralat pencetak <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Pencetak disekat <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other">Kerja cetakan <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="one">Kerja cetakan <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Batal"</string>
     <string name="restart" msgid="2472034227037808749">"Mulakan semula"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Tiada sambungan ke pencetak"</string>
diff --git a/packages/PrintSpooler/res/values-my-rMM/strings.xml b/packages/PrintSpooler/res/values-my-rMM/strings.xml
index c3dc490..4d4c95b 100644
--- a/packages/PrintSpooler/res/values-my-rMM/strings.xml
+++ b/packages/PrintSpooler/res/values-my-rMM/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"စာထုတ်စက်များကို ရှာနေပါသည်"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"ပုံနှိပ်ထုတ်ယူရေး ဝန်ဆောင်မှုများ ဖွင့်မထားပါ"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ကို ပယ်ဖျက်နေပါသည်"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"စာထုတ်စက်မှ အမှား <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ကိုစာထုတ်စက်ကငြင်းလိုက်သည်"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> စာထုတ်စရာများ</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g>စာထုတ်စရာ</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"ပယ်ဖျက်"</string>
     <string name="restart" msgid="2472034227037808749">"အစက ပြန်စရန်"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"စာထုတ်စက်နဲ့ ဆက်သွယ်ထားမှု မရှိပါ"</string>
diff --git a/packages/PrintSpooler/res/values-nb/strings.xml b/packages/PrintSpooler/res/values-nb/strings.xml
index 945bbea..9efa5d1 100644
--- a/packages/PrintSpooler/res/values-nb/strings.xml
+++ b/packages/PrintSpooler/res/values-nb/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> skrivere ble funnet</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> skriver ble funnet</item>
     </plurals>
+    <string name="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_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>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Avbryter <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Skriverfeil <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Skriveren blokkerte <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> utskriftsjobber</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> utskriftsjobb</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Avbryt"</string>
     <string name="restart" msgid="2472034227037808749">"Start på nytt"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Ingen forbindelse med skriveren"</string>
diff --git a/packages/PrintSpooler/res/values-ne-rNP/strings.xml b/packages/PrintSpooler/res/values-ne-rNP/strings.xml
index 45bcc95..281a65d 100644
--- a/packages/PrintSpooler/res/values-ne-rNP/strings.xml
+++ b/packages/PrintSpooler/res/values-ne-rNP/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"प्रिन्टरहरू खोज्दै"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"कुनै पनि मुद्रण सेवाहरू सक्रिय छैनन्"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"रद्द गरिँदै <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिन्टर त्रुटि <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"प्रिन्टर ब्लक गरियो <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> कार्यहरू प्रिन्ट गर्नुहोस्</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> कार्य प्रिन्ट गर्नुहोस्</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"रद्द गर्नुहोस्"</string>
     <string name="restart" msgid="2472034227037808749">"पुनःस्टार्ट गर्नुहोस्"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"प्रिन्टरमा कुनै जडान छैन"</string>
diff --git a/packages/PrintSpooler/res/values-nl/strings.xml b/packages/PrintSpooler/res/values-nl/strings.xml
index 76c8656..eef9880 100644
--- a/packages/PrintSpooler/res/values-nl/strings.xml
+++ b/packages/PrintSpooler/res/values-nl/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printers gevonden</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printer gevonden</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Printers zoeken"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Geen afdrukservices ingeschakeld"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> annuleren"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Printerfout <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> geblokkeerd door printer"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> afdruktaken</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> afdruktaak</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Annuleren"</string>
     <string name="restart" msgid="2472034227037808749">"Opnieuw starten"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Geen verbinding met printer"</string>
diff --git a/packages/PrintSpooler/res/values-pa-rIN/strings.xml b/packages/PrintSpooler/res/values-pa-rIN/strings.xml
index 45fa460..7d7860c 100644
--- a/packages/PrintSpooler/res/values-pa-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-pa-rIN/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"ਪ੍ਰਿੰਟਰ ਖੋਜ ਰਿਹਾ ਹੈ"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"ਪ੍ਰਿੰਟ ਸੇਵਾਵਾਂ ਯੋਗ ਨਹੀਂ ਬਣਾਈਆਂ ਗਈਆਂ"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ਨੂੰ ਰੱਦ ਕਰ ਰਿਹਾ ਹੈ"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"ਪ੍ਰਿੰਟਰ ਅਸ਼ੁੱਧੀ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"ਪ੍ਰਿੰਟਰ ਬਲੌਕ ਕੀਤਾ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ਪ੍ਰਿੰਟ ਜੌਬਸ</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ਪ੍ਰਿੰਟ ਜੌਬਸ</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"ਰੱਦ ਕਰੋ"</string>
     <string name="restart" msgid="2472034227037808749">"ਰੀਸਟਾਰਟ ਕਰੋ"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"ਪ੍ਰਿੰਟਰ ਲਈ ਕੋਈ ਕਨੈਕਸ਼ਨ ਨਹੀਂ"</string>
diff --git a/packages/PrintSpooler/res/values-pl/strings.xml b/packages/PrintSpooler/res/values-pl/strings.xml
index df3ee924..6837edf 100644
--- a/packages/PrintSpooler/res/values-pl/strings.xml
+++ b/packages/PrintSpooler/res/values-pl/strings.xml
@@ -61,6 +61,9 @@
       <item quantity="other">Znaleziono <xliff:g id="COUNT_1">%1$s</xliff:g> drukarki</item>
       <item quantity="one">Znaleziono <xliff:g id="COUNT_0">%1$s</xliff:g> drukarkę</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Szukanie drukarek"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Brak włączonych usług drukowania"</string>
@@ -69,12 +72,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Anulowanie: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Błąd drukarki: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Drukarka zablokowała <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> zadania drukowania</item>
-      <item quantity="many"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> zadań drukowania</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> zadania drukowania</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> zadanie drukowania</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Anuluj"</string>
     <string name="restart" msgid="2472034227037808749">"Od nowa"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Brak połączenia z drukarką"</string>
diff --git a/packages/PrintSpooler/res/values-pt-rBR/strings.xml b/packages/PrintSpooler/res/values-pt-rBR/strings.xml
index 90da72b..c9713c9 100644
--- a/packages/PrintSpooler/res/values-pt-rBR/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rBR/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Procurando impressoras"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Nenhum serviço de impressão ativado"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Erro ao imprimir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"A impressora bloqueou <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one">Tarefas de impressão <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="other">Tarefas de impressão <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Cancelar"</string>
     <string name="restart" msgid="2472034227037808749">"Reiniciar"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Sem conexão com a impressora"</string>
diff --git a/packages/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
index 99bbd81..9fabc0f 100644
--- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> impressora encontrada</item>
     </plurals>
+    <string name="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_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>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"A cancelar <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Erro da impressora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"A impressora bloqueou <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tarefas de impressão</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> tarefa de impressão</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Cancelar"</string>
     <string name="restart" msgid="2472034227037808749">"Reiniciar"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Sem ligação à impressora"</string>
diff --git a/packages/PrintSpooler/res/values-pt/strings.xml b/packages/PrintSpooler/res/values-pt/strings.xml
index 90da72b..c9713c9 100644
--- a/packages/PrintSpooler/res/values-pt/strings.xml
+++ b/packages/PrintSpooler/res/values-pt/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Procurando impressoras"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Nenhum serviço de impressão ativado"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Erro ao imprimir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"A impressora bloqueou <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one">Tarefas de impressão <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="other">Tarefas de impressão <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Cancelar"</string>
     <string name="restart" msgid="2472034227037808749">"Reiniciar"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Sem conexão com a impressora"</string>
diff --git a/packages/PrintSpooler/res/values-ro/strings.xml b/packages/PrintSpooler/res/values-ro/strings.xml
index 4cfb8ab..7364eb0 100644
--- a/packages/PrintSpooler/res/values-ro/strings.xml
+++ b/packages/PrintSpooler/res/values-ro/strings.xml
@@ -60,6 +60,9 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> de imprimante găsite</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> imprimantă găsită</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Se caută imprimante"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Niciun serviciu de printare activat"</string>
@@ -68,11 +71,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Se anulează <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Eroare de printare: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printare blocată: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> activități de printare</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> de activități de printare</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> activitate de printare</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Anulați"</string>
     <string name="restart" msgid="2472034227037808749">"Reporniți"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Nu există conexiune la o imprimantă"</string>
diff --git a/packages/PrintSpooler/res/values-ru/strings.xml b/packages/PrintSpooler/res/values-ru/strings.xml
index fb49330..d3d0d3f 100644
--- a/packages/PrintSpooler/res/values-ru/strings.xml
+++ b/packages/PrintSpooler/res/values-ru/strings.xml
@@ -61,6 +61,9 @@
       <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="1205302482388937547">"Некоторые службы печати отключены."</string>
     <string name="choose_print_service" msgid="3740309762324459694">"Выберите службу печати"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Поиск принтеров…"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Службы печати недоступны"</string>
@@ -69,12 +72,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Отмена задания <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>…"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Ошибка задания \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\""</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Задание \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" заблокировано"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one">Задания печати: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="few">Задания печати: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="many">Задания печати: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="other">Задания печати: <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Отмена"</string>
     <string name="restart" msgid="2472034227037808749">"Повторить"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Нет связи с принтером"</string>
diff --git a/packages/PrintSpooler/res/values-si-rLK/strings.xml b/packages/PrintSpooler/res/values-si-rLK/strings.xml
index fb6f145..610442d 100644
--- a/packages/PrintSpooler/res/values-si-rLK/strings.xml
+++ b/packages/PrintSpooler/res/values-si-rLK/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"මුද්‍රණ යන්ත්‍ර සොයමින්"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"මුද්‍රණ සේවා සබල නැත"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"අවලංගු කෙරේ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"මුද්‍රණ දෝෂය <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"මුද්‍රණ යන්ත්‍රය <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> අවුරා ඇති"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one">මුද්‍රණ කාර්ය <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="other">මුද්‍රණ කාර්ය <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"අවලංගු කරන්න"</string>
     <string name="restart" msgid="2472034227037808749">"යළි අරඹන්න"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"මුද්‍රණ යන්ත්‍රය වෙත සම්බන්ධය නැත"</string>
diff --git a/packages/PrintSpooler/res/values-sk/strings.xml b/packages/PrintSpooler/res/values-sk/strings.xml
index 605237b..603d1d2 100644
--- a/packages/PrintSpooler/res/values-sk/strings.xml
+++ b/packages/PrintSpooler/res/values-sk/strings.xml
@@ -61,6 +61,9 @@
       <item quantity="other">Našlo sa <xliff:g id="COUNT_1">%1$s</xliff:g> tlačiarní</item>
       <item quantity="one">Našla sa <xliff:g id="COUNT_0">%1$s</xliff:g> tlačiareň</item>
     </plurals>
+    <string name="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_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>
@@ -69,12 +72,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Prebieha zrušenie úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Chyba tlačiarne – úloha <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Tlačiareň zablok. úlohu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tlačové úlohy</item>
-      <item quantity="many"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tlačovej úlohy</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tlačových úloh</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> tlačová úloha</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Zrušiť"</string>
     <string name="restart" msgid="2472034227037808749">"Spustiť znova"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Žiadne pripojenie k tlačiarni"</string>
diff --git a/packages/PrintSpooler/res/values-sl/strings.xml b/packages/PrintSpooler/res/values-sl/strings.xml
index 48d2e1d..4a08269 100644
--- a/packages/PrintSpooler/res/values-sl/strings.xml
+++ b/packages/PrintSpooler/res/values-sl/strings.xml
@@ -61,6 +61,9 @@
       <item quantity="few"><xliff:g id="COUNT_1">%1$s</xliff:g> najdeni tiskalniki</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> najdenih tiskalnikov</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Iskanje tiskalnikov"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Ni omogočenih tiskalnih storitev"</string>
@@ -69,12 +72,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Preklic: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Napaka tiskalnika: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Tiskalnik je blokiral <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tiskalno opravilo</item>
-      <item quantity="two"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tiskalni opravili</item>
-      <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tiskalna opravila</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> tiskalnih opravil</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Prekliči"</string>
     <string name="restart" msgid="2472034227037808749">"Začni znova"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Ni povezave s tiskalnikom"</string>
diff --git a/packages/PrintSpooler/res/values-sq-rAL/strings.xml b/packages/PrintSpooler/res/values-sq-rAL/strings.xml
index 5ba72ff..b0902ef 100644
--- a/packages/PrintSpooler/res/values-sq-rAL/strings.xml
+++ b/packages/PrintSpooler/res/values-sq-rAL/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other">U gjetën <xliff:g id="COUNT_1">%1$s</xliff:g> printerë</item>
       <item quantity="one">U gjet <xliff:g id="COUNT_0">%1$s</xliff:g> printer</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">"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_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>
@@ -67,10 +70,6 @@
     <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>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printeri bllokoi <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> punë për printim</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> punë për printim</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Anulo"</string>
     <string name="restart" msgid="2472034227037808749">"Rifillo"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Printeri nuk është i lidhur"</string>
diff --git a/packages/PrintSpooler/res/values-sr/strings.xml b/packages/PrintSpooler/res/values-sr/strings.xml
index 7a04b8d..feb2940 100644
--- a/packages/PrintSpooler/res/values-sr/strings.xml
+++ b/packages/PrintSpooler/res/values-sr/strings.xml
@@ -60,6 +60,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"Претрага штампача"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Ниједна услуга штампања није омогућена"</string>
@@ -68,11 +71,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Отказује се <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Грешка штампача <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Штампач је блокирао <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one">Задаци штампања <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="few">Задаци штампања <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="other">Задаци штампања <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Откажи"</string>
     <string name="restart" msgid="2472034227037808749">"Поново покрени"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Нема везе са штампачем"</string>
diff --git a/packages/PrintSpooler/res/values-sv/strings.xml b/packages/PrintSpooler/res/values-sv/strings.xml
index ec4ad30..cf398c7 100644
--- a/packages/PrintSpooler/res/values-sv/strings.xml
+++ b/packages/PrintSpooler/res/values-sv/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> skrivare hittades</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> skrivare hittades</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Söker efter skrivare"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Inga utskriftstjänster har aktiverats"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Avbryter <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Skrivarfel för <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Skrivaren har blockerat <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> utskriftsjobb</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> utskriftsjobb</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Avbryt"</string>
     <string name="restart" msgid="2472034227037808749">"Starta om"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Ingen anslutning till skrivaren"</string>
diff --git a/packages/PrintSpooler/res/values-sw/strings.xml b/packages/PrintSpooler/res/values-sw/strings.xml
index eed3356..7e00b70 100644
--- a/packages/PrintSpooler/res/values-sw/strings.xml
+++ b/packages/PrintSpooler/res/values-sw/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other">Printa <xliff:g id="COUNT_1">%1$s</xliff:g> zimepatikana</item>
       <item quantity="one">Printa <xliff:g id="COUNT_0">%1$s</xliff:g> imepatikana</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Inatafuta printa"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Huduma za kuchapisha hazijawashwa"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Inaghairi <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Hitilafu ya kuchapisha <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printa imefungwa <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other">Kazi ya kuchapisha ya <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="one">Kazi ya kuchapisha ya <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> </item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Ghairi"</string>
     <string name="restart" msgid="2472034227037808749">"Anzisha upya"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Hakuna muunganisho kwa printa"</string>
diff --git a/packages/PrintSpooler/res/values-ta-rIN/strings.xml b/packages/PrintSpooler/res/values-ta-rIN/strings.xml
index a9879c3..ae0b774 100644
--- a/packages/PrintSpooler/res/values-ta-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-ta-rIN/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"அச்சுப்பொறிகளைத் தேடுகிறது"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"அச்சுப் பொறிகள் இல்லை"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ஐ ரத்துசெய்கிறது"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"பிரிண்டர் பிழை <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"பிரிண்டர் <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ஐத் தடுத்தது"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> அச்சுப் பணிகள்</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> அச்சுப் பணி</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"ரத்துசெய்"</string>
     <string name="restart" msgid="2472034227037808749">"மீண்டும் தொடங்கு"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"அச்சுப்பொறியுடன் இணைக்கப்படவில்லை"</string>
diff --git a/packages/PrintSpooler/res/values-te-rIN/strings.xml b/packages/PrintSpooler/res/values-te-rIN/strings.xml
index 909cb90..5fd8d60 100644
--- a/packages/PrintSpooler/res/values-te-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-te-rIN/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"ప్రింటర్‌ల కోసం శోధిస్తోంది"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"ముద్రణ సేవలు ఏవీ ప్రారంభించలేదు"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ను రద్దు చేస్తోంది"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"ప్రింటర్ లోపం <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"ప్రింటర్ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ను బ్లాక్ చేసింది"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ముద్రణ జాబ్‌లు</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> ముద్రణ జాబ్</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"రద్దు చేయి"</string>
     <string name="restart" msgid="2472034227037808749">"పునఃప్రారంభించు"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"ప్రింటర్‌కు కనెక్షన్ లేదు"</string>
diff --git a/packages/PrintSpooler/res/values-th/strings.xml b/packages/PrintSpooler/res/values-th/strings.xml
index c33a759..ebd5e2a 100644
--- a/packages/PrintSpooler/res/values-th/strings.xml
+++ b/packages/PrintSpooler/res/values-th/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"กำลังค้นหาเครื่องพิมพ์"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"ไม่ได้เปิดใช้บริการพิมพ์"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"กำลังยกเลิก <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"ข้อผิดพลาดเครื่องพิมพ์ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"เครื่องพิมพ์ได้บล็อก <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> งานพิมพ์</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> งานพิมพ์</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"ยกเลิก"</string>
     <string name="restart" msgid="2472034227037808749">"เริ่มต้นใหม่"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"ไม่มีการเชื่อมต่อไปยังเครื่องพิมพ์"</string>
diff --git a/packages/PrintSpooler/res/values-tl/strings.xml b/packages/PrintSpooler/res/values-tl/strings.xml
index 545bda4..ebe869b 100644
--- a/packages/PrintSpooler/res/values-tl/strings.xml
+++ b/packages/PrintSpooler/res/values-tl/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> nakitang printer</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> na nakitang printer</item>
     </plurals>
+    <string name="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_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>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Kinakansela ang <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Error sa printer <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Naka-block ang Printer <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> ipi-print</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> na ipi-print</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Kanselahin"</string>
     <string name="restart" msgid="2472034227037808749">"I-restart"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Hindi nakakonekta sa printer"</string>
diff --git a/packages/PrintSpooler/res/values-tr/strings.xml b/packages/PrintSpooler/res/values-tr/strings.xml
index a13f2df..9cd42ab 100644
--- a/packages/PrintSpooler/res/values-tr/strings.xml
+++ b/packages/PrintSpooler/res/values-tr/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> yazıcı bulundu</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> yazıcı bulundu</item>
     </plurals>
+    <string name="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_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>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> iptal ediliyor"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Yazıcı hatası: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Yazıcı <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> işini engelledi"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> yazdırma işi</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> yazdırma işi</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"İptal"</string>
     <string name="restart" msgid="2472034227037808749">"Yeniden başlat"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Yazıcı bağlantısı yok"</string>
diff --git a/packages/PrintSpooler/res/values-uk/strings.xml b/packages/PrintSpooler/res/values-uk/strings.xml
index def21ab..1082147 100644
--- a/packages/PrintSpooler/res/values-uk/strings.xml
+++ b/packages/PrintSpooler/res/values-uk/strings.xml
@@ -61,6 +61,9 @@
       <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="1205302482388937547">"Деякі служби друку вимкнено."</string>
     <string name="choose_print_service" msgid="3740309762324459694">"Вибрати службу друку"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Пошук принтерів"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Немає служб друку"</string>
@@ -69,12 +72,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" скасовується"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Помилка завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\""</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" заблоковано"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> завдання друку</item>
-      <item quantity="few"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> завдання друку</item>
-      <item quantity="many"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> завдань друку</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> завдань друку</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Скасувати"</string>
     <string name="restart" msgid="2472034227037808749">"Перезапустити"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Немає з’єднання з принтером"</string>
diff --git a/packages/PrintSpooler/res/values-ur-rPK/strings.xml b/packages/PrintSpooler/res/values-ur-rPK/strings.xml
index c031aba..56f1093 100644
--- a/packages/PrintSpooler/res/values-ur-rPK/strings.xml
+++ b/packages/PrintSpooler/res/values-ur-rPK/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"پرنٹرز تلاش کر رہا ہے"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"کوئی پرنٹ سروس فعال نہیں"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> کو منسوخ کر رہا ہے"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"پرنٹر کی خرابی <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"پرنٹر نے <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> کو مسدود کر دیا"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> پرنٹ جابز</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> پرنٹ جاب</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"منسوخ کریں"</string>
     <string name="restart" msgid="2472034227037808749">"دوبارہ شروع کریں"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"پرنٹر کے ساتھ کوئی کنکشن نہیں ہے"</string>
diff --git a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
index 59dcca9..30b218e 100644
--- a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
+++ b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ta printer topildi</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> ta printer topildi</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Printerlar qidirilmoqda"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Hech qaysi chop etish xizmati yoqilmagan"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> bekor qilinmoqda"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Printerda xatolik: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printer <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ni taqiqladi"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> chop qilish vazifalari</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> chop qilish vazifasi</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Bekor qilish"</string>
     <string name="restart" msgid="2472034227037808749">"Qayta boshlash"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Printer ulanmagan"</string>
diff --git a/packages/PrintSpooler/res/values-vi/strings.xml b/packages/PrintSpooler/res/values-vi/strings.xml
index 0167823..32aaf63 100644
--- a/packages/PrintSpooler/res/values-vi/strings.xml
+++ b/packages/PrintSpooler/res/values-vi/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="other">Đã tìm thấy <xliff:g id="COUNT_1">%1$s</xliff:g> máy in</item>
       <item quantity="one">Đã tìm thấy <xliff:g id="COUNT_0">%1$s</xliff:g> máy in</item>
     </plurals>
+    <string name="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_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>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Hủy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Lỗi máy in <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Máy in đã chặn <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other">Lệnh in <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
-      <item quantity="one">Lệnh in <xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g></item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Hủy"</string>
     <string name="restart" msgid="2472034227037808749">"Bắt đầu lại"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Không có kết nối nào với máy in"</string>
diff --git a/packages/PrintSpooler/res/values-zh-rCN/strings.xml b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
index a74e994..42cf3b1 100644
--- a/packages/PrintSpooler/res/values-zh-rCN/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"正在搜索打印机"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"未启用任何打印服务"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"正在取消打印“<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>”"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"打印机在打印“<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>”时出错"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"打印机拒绝打印“<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>”"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other">“<xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g>”打印作业</item>
-      <item quantity="one">“<xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g>”打印作业</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"取消"</string>
     <string name="restart" msgid="2472034227037808749">"重新开始"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"未与打印机建立连接"</string>
diff --git a/packages/PrintSpooler/res/values-zh-rHK/strings.xml b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
index 35643f3..0a458ad 100644
--- a/packages/PrintSpooler/res/values-zh-rHK/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"正在搜尋打印機"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"沒有已啟用的列印服務"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"正在取消 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"打印機錯誤:<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"打印機已封鎖 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> 項列印工作</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> 項列印工作</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"取消"</string>
     <string name="restart" msgid="2472034227037808749">"重新開始"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"尚未與打印機連線"</string>
diff --git a/packages/PrintSpooler/res/values-zh-rTW/strings.xml b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
index 40c44ff..7a30011 100644
--- a/packages/PrintSpooler/res/values-zh-rTW/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
@@ -59,6 +59,9 @@
       <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="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_searching_for_printers" msgid="6550424555079932867">"正在搜尋印表機"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"未啟用任何列印服務"</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"正在取消 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"印表機發生錯誤:<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"印表機封鎖了 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> 個列印工作</item>
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> 個列印工作</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"取消"</string>
     <string name="restart" msgid="2472034227037808749">"重新開始"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"尚未與印表機建立連線"</string>
diff --git a/packages/PrintSpooler/res/values-zu/strings.xml b/packages/PrintSpooler/res/values-zu/strings.xml
index e0f6f34..f57b58c 100644
--- a/packages/PrintSpooler/res/values-zu/strings.xml
+++ b/packages/PrintSpooler/res/values-zu/strings.xml
@@ -59,6 +59,9 @@
       <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> amaphrinta atholakele</item>
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> amaphrinta atholakele</item>
     </plurals>
+    <string name="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_searching_for_printers" msgid="6550424555079932867">"Isesha amaphrinta"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Amasevisi ephrinta akavuliwe."</string>
@@ -67,10 +70,6 @@
     <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Ikhansela i-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="failed_notification_title_template" msgid="2256217208186530973">"Iphutha lephrinta ye-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
     <string name="blocked_notification_title_template" msgid="1175435827331588646">"Iphrinta engu-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ivinjelwe"</string>
-    <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
-      <item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> imisebenzi yokuphrinta</item>
-      <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> imisebenzi yokuphrinta</item>
-    </plurals>
     <string name="cancel" msgid="4373674107267141885">"Khansela"</string>
     <string name="restart" msgid="2472034227037808749">"Qala kabusha"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"Akukho ukuxhumana kuphrinta"</string>
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index 6d81788..76292a1 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -144,6 +144,15 @@
         <item quantity="other"><xliff:g id="count" example="2">%1$s</xliff:g> printers found</item>
     </plurals>
 
+    <!-- Template for an extended description of a printer. [CHAR LIMIT=50] -->
+    <string name="printer_extended_description_template"><xliff:g id="print_service_label" example="Canon Print Service">%1$s</xliff:g> - <xliff:g id="printer_description" example="Printer under the stairs">%2$s</xliff:g></string>
+
+    <!-- Description of printer info icon. [CHAR LIMIT=50] -->
+    <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] -->
@@ -172,12 +181,6 @@
     <!-- Template for the notification label for a blocked print job. [CHAR LIMIT=25] -->
     <string name="blocked_notification_title_template">Printer blocked <xliff:g id="print_job_name" example="foo.jpg">%1$s</xliff:g></string>
 
-    <!-- Template for the notification label for a composite (multiple items) print jobs notification. [CHAR LIMIT=25] -->
-    <plurals name="composite_notification_title_template">
-        <item quantity="one"><xliff:g id="print_job_name" example="foo.jpg">%1$d</xliff:g> print job</item>
-        <item quantity="other"><xliff:g id="print_job_name" example="foo.jpg">%1$d</xliff:g> print jobs</item>
-    </plurals>
-
     <!-- Label for the notification button for cancelling a print job. [CHAR LIMIT=25] -->
     <string name="cancel">Cancel</string>
 
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/CustomPrinterIconCache.java b/packages/PrintSpooler/src/com/android/printspooler/model/CustomPrinterIconCache.java
new file mode 100644
index 0000000..7274268
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/CustomPrinterIconCache.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.model;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.drawable.Icon;
+import android.print.PrinterId;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * A fixed size cache for custom printer icons. Old icons get removed with a last recently used
+ * policy.
+ */
+public class CustomPrinterIconCache {
+
+    private final static String LOG_TAG = "CustomPrinterIconCache";
+
+    /** Maximum number of icons in the cache */
+    private final static int MAX_SIZE = 1024;
+
+    /** Directory used to persist state and icons */
+    private final File mCacheDirectory;
+
+    /**
+     * Create a new icon cache.
+     */
+    public CustomPrinterIconCache(@NonNull File cacheDirectory) {
+        mCacheDirectory = new File(cacheDirectory, "icons");
+        if (!mCacheDirectory.exists()) {
+            mCacheDirectory.mkdir();
+        }
+    }
+
+    /**
+     * Return the file name to be used for the icon of a printer
+     *
+     * @param printerId the id of the printer
+     *
+     * @return The file to be used for the icon of the printer
+     */
+    private @Nullable File getIconFileName(@NonNull PrinterId printerId) {
+        StringBuffer sb = new StringBuffer(printerId.getServiceName().getPackageName());
+        sb.append("-");
+
+        try {
+            MessageDigest md = MessageDigest.getInstance("SHA-1");
+            md.update(
+                    (printerId.getServiceName().getClassName() + ":" + printerId.getLocalId())
+                            .getBytes("UTF-16"));
+            sb.append(String.format("%#040x", new java.math.BigInteger(1, md.digest())));
+        } catch (UnsupportedEncodingException|NoSuchAlgorithmException e) {
+            Log.e(LOG_TAG, "Could not compute custom printer icon file name", e);
+            return null;
+        }
+
+        return new File(mCacheDirectory, sb.toString());
+    }
+
+    /**
+     * Get the {@link Icon} to be used as a custom icon for the printer. If not available request
+     * the icon to be loaded.
+     *
+     * @param printerId the printer the icon belongs to
+     * @return the {@link Icon} if already available or null if icon is not loaded yet
+     */
+    public synchronized @Nullable Icon getIcon(@NonNull PrinterId printerId) {
+        Icon icon;
+
+        File iconFile = getIconFileName(printerId);
+        if (iconFile != null && iconFile.exists()) {
+            try (FileInputStream is = new FileInputStream(iconFile)) {
+                icon = Icon.createFromStream(is);
+            } catch (IOException e) {
+                icon = null;
+                Log.e(LOG_TAG, "Could not read icon from " + iconFile, e);
+            }
+
+            // Touch file so that it is the not likely to be removed
+            iconFile.setLastModified(System.currentTimeMillis());
+        } else {
+            icon = null;
+        }
+
+        return icon;
+    }
+
+    /**
+     * Remove old icons so that only between numFilesToKeep and twice as many icons are left.
+     *
+     * @param numFilesToKeep the number of icons to keep
+     */
+    public void removeOldFiles(int numFilesToKeep) {
+        File files[] = mCacheDirectory.listFiles();
+
+        // To reduce the number of shrink operations, let the cache grow to twice the max size
+        if (files.length > numFilesToKeep * 2) {
+            SortedMap<Long, File> sortedFiles = new TreeMap<>();
+
+            for (File f : files) {
+                sortedFiles.put(f.lastModified(), f);
+            }
+
+            while (sortedFiles.size() > numFilesToKeep) {
+                sortedFiles.remove(sortedFiles.firstKey());
+            }
+        }
+    }
+
+    /**
+     * Handle that a custom icon for a printer was loaded
+     *
+     * @param printerId the id of the printer the icon belongs to
+     * @param icon the icon that was loaded
+     */
+    public synchronized void onCustomPrinterIconLoaded(@NonNull PrinterId printerId,
+            @Nullable Icon icon) {
+        File iconFile = getIconFileName(printerId);
+
+        if (iconFile == null) {
+            return;
+        }
+
+        try (FileOutputStream os = new FileOutputStream(iconFile)) {
+            icon.writeToStream(os);
+        } catch (IOException e) {
+            Log.e(LOG_TAG, "Could not write icon for " + printerId + " to storage", e);
+        }
+
+        removeOldFiles(MAX_SIZE);
+    }
+
+    /**
+     * Clear all persisted and non-persisted state from this cache.
+     */
+    public synchronized void clear() {
+        for (File f : mCacheDirectory.listFiles()) {
+            f.delete();
+        }
+    }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
index 82fd512..0210693 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
@@ -40,6 +40,7 @@
 import android.print.PrintJobInfo;
 import android.print.PrintManager;
 import android.provider.Settings;
+import android.util.ArraySet;
 import android.util.Log;
 
 import com.android.printspooler.R;
@@ -61,13 +62,22 @@
 
     private static final String EXTRA_PRINT_JOB_ID = "EXTRA_PRINT_JOB_ID";
 
+    private static final String PRINT_JOB_NOTIFICATION_GROUP_KEY = "PRINT_JOB_NOTIFICATIONS";
+    private static final String PRINT_JOB_NOTIFICATION_SUMMARY = "PRINT_JOB_NOTIFICATIONS_SUMMARY";
+
     private final Context mContext;
     private final NotificationManager mNotificationManager;
 
+    /**
+     * Mapping from printJobIds to their notification Ids.
+     */
+    private final ArraySet<PrintJobId> mNotifications;
+
     public NotificationController(Context context) {
         mContext = context;
         mNotificationManager = (NotificationManager)
                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+        mNotifications = new ArraySet<>(0);
     }
 
     public void onUpdateNotifications(List<PrintJobInfo> printJobs) {
@@ -81,16 +91,44 @@
             }
         }
 
-        updateNotification(notifyPrintJobs);
+        updateNotifications(notifyPrintJobs);
     }
 
-    private void updateNotification(List<PrintJobInfo> printJobs) {
-        if (printJobs.size() <= 0) {
-            removeNotification();
-        } else if (printJobs.size() == 1) {
-            createSimpleNotification(printJobs.get(0));
-        } else {
+    /**
+     * Update notifications for the given print jobs, remove all other notifications.
+     *
+     * @param printJobs The print job that we want to create notifications for.
+     */
+    private void updateNotifications(List<PrintJobInfo> printJobs) {
+        ArraySet<PrintJobId> removedPrintJobs = new ArraySet<>(mNotifications);
+
+        final int numPrintJobs = printJobs.size();
+
+        // Create summary notification
+        if (numPrintJobs > 1) {
             createStackedNotification(printJobs);
+        } else {
+            mNotificationManager.cancel(PRINT_JOB_NOTIFICATION_SUMMARY, 0);
+        }
+
+        // Create per print job notification
+        for (int i = 0; i < numPrintJobs; i++) {
+            PrintJobInfo printJob = printJobs.get(i);
+            PrintJobId printJobId = printJob.getId();
+
+            removedPrintJobs.remove(printJobId);
+            mNotifications.add(printJobId);
+
+            createSimpleNotification(printJob);
+        }
+
+        // Remove notifications for print jobs that do not exist anymore
+        final int numRemovedPrintJobs = removedPrintJobs.size();
+        for (int i = 0; i < numRemovedPrintJobs; i++) {
+            PrintJobId removedPrintJob = removedPrintJobs.valueAt(i);
+
+            mNotificationManager.cancel(removedPrintJob.flattenToString(), 0);
+            mNotifications.remove(removedPrintJob);
         }
     }
 
@@ -148,7 +186,8 @@
                 .setOngoing(true)
                 .setShowWhen(true)
                 .setColor(mContext.getColor(
-                        com.android.internal.R.color.system_notification_accent_color));
+                        com.android.internal.R.color.system_notification_accent_color))
+                .setGroup(PRINT_JOB_NOTIFICATION_GROUP_KEY);
 
         if (firstAction != null) {
             builder.addAction(firstAction);
@@ -158,11 +197,14 @@
             builder.addAction(secondAction);
         }
 
-        if (printJob.getState() == PrintJobInfo.STATE_STARTED) {
+        if (printJob.getState() == PrintJobInfo.STATE_STARTED
+                || printJob.getState() == PrintJobInfo.STATE_QUEUED) {
             float progress = printJob.getProgress();
             if (progress >= 0) {
-                builder.setProgress(Integer.MAX_VALUE, (int)(Integer.MAX_VALUE * progress),
+                builder.setProgress(Integer.MAX_VALUE, (int) (Integer.MAX_VALUE * progress),
                         false);
+            } else {
+                builder.setProgress(Integer.MAX_VALUE, 0, true);
             }
         }
 
@@ -173,7 +215,7 @@
             builder.setContentText(printJob.getPrinterName());
         }
 
-        mNotificationManager.notify(0, builder.build());
+        mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build());
     }
 
     private void createPrintingNotification(PrintJobInfo printJob) {
@@ -201,33 +243,36 @@
                 .setContentIntent(createContentIntent(null))
                 .setWhen(System.currentTimeMillis())
                 .setOngoing(true)
-                .setShowWhen(true);
+                .setShowWhen(true)
+                .setGroup(PRINT_JOB_NOTIFICATION_GROUP_KEY)
+                .setGroupSummary(true);
 
         final int printJobCount = printJobs.size();
 
         InboxStyle inboxStyle = new InboxStyle();
-        inboxStyle.setBigContentTitle(String.format(mContext.getResources().getQuantityText(
-                R.plurals.composite_notification_title_template,
-                printJobCount).toString(), printJobCount));
 
+        int icon = com.android.internal.R.drawable.ic_print;
         for (int i = printJobCount - 1; i>= 0; i--) {
             PrintJobInfo printJob = printJobs.get(i);
-            if (i == printJobCount - 1) {
-                builder.setLargeIcon(((BitmapDrawable) mContext.getResources().getDrawable(
-                        computeNotificationIcon(printJob), null)).getBitmap());
-                builder.setSmallIcon(computeNotificationIcon(printJob));
-                builder.setContentTitle(computeNotificationTitle(printJob));
-                builder.setContentText(printJob.getPrinterName());
-            }
+
             inboxStyle.addLine(computeNotificationTitle(printJob));
+
+            // if any print job is in an error state show an error icon for the summary
+            if (printJob.getState() == PrintJobInfo.STATE_FAILED
+                    || printJob.getState() == PrintJobInfo.STATE_BLOCKED) {
+                icon = com.android.internal.R.drawable.ic_print_error;
+            }
         }
 
+        builder.setSmallIcon(icon);
+        builder.setLargeIcon(
+                ((BitmapDrawable) mContext.getResources().getDrawable(icon, null)).getBitmap());
         builder.setNumber(printJobCount);
         builder.setStyle(inboxStyle);
         builder.setColor(mContext.getColor(
                 com.android.internal.R.color.system_notification_accent_color));
 
-        mNotificationManager.notify(0, builder.build());
+        mNotificationManager.notify(PRINT_JOB_NOTIFICATION_SUMMARY, 0, builder.build());
     }
 
     private String computeNotificationTitle(PrintJobInfo printJob) {
@@ -261,10 +306,6 @@
         }
     }
 
-    private void removeNotification() {
-        mNotificationManager.cancel(0);
-    }
-
     private PendingIntent createContentIntent(PrintJobId printJobId) {
         Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS);
         if (printJobId != null) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
index ea6281d..ac97ad0 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
@@ -116,6 +116,7 @@
             });
             return;
         }
+        mCloseGuard.close();
 
         mState = STATE_DESTROYED;
         if (DEBUG) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
index 90eef83..18160ff 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
@@ -23,6 +23,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.drawable.Icon;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -109,6 +110,9 @@
 
     private NotificationController mNotificationController;
 
+    /** Cache for custom printer icons loaded from the print service */
+    private CustomPrinterIconCache mCustomIconCache;
+
     public static PrintSpoolerService peekInstance() {
         synchronized (sLock) {
             return sInstance;
@@ -123,6 +127,7 @@
 
         mPersistanceManager = new PersistenceManager();
         mNotificationController = new NotificationController(PrintSpoolerService.this);
+        mCustomIconCache = new CustomPrinterIconCache(getCacheDir());
 
         synchronized (mLock) {
             mPersistanceManager.readStateLocked();
@@ -135,6 +140,11 @@
     }
 
     @Override
+    public void onDestroy() {
+        super.onDestroy();
+    }
+
+    @Override
     public IBinder onBind(Intent intent) {
         return new PrintSpooler();
     }
@@ -703,6 +713,37 @@
         }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
     }
 
+    /**
+     * Handle that a custom icon for a printer was loaded.
+     *
+     * @param printerId the id of the printer the icon belongs to
+     * @param icon the icon that was loaded
+     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+     */
+    public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon) {
+        mCustomIconCache.onCustomPrinterIconLoaded(printerId, icon);
+    }
+
+    /**
+     * Get the custom icon for a printer. If the icon is not cached, the icon is
+     * requested asynchronously. Once it is available the printer is updated.
+     *
+     * @param printerId the id of the printer the icon should be loaded for
+     * @return the custom icon to be used for the printer or null if the icon is
+     *         not yet available
+     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+     */
+    public Icon getCustomPrinterIcon(PrinterId printerId) {
+        return mCustomIconCache.getIcon(printerId);
+    }
+
+    /**
+     * Clear the custom printer icon cache.
+     */
+    public void clearCustomPrinterIconCache() {
+        mCustomIconCache.clear();
+    }
+
     private final class PersistenceManager {
         private static final String PERSIST_FILE_NAME = "print_spooler_state.xml";
 
@@ -1262,7 +1303,7 @@
         }
 
         private void expect(XmlPullParser parser, int type, String tag)
-                throws IOException, XmlPullParserException {
+                throws XmlPullParserException {
             if (!accept(parser, type, tag)) {
                 throw new XmlPullParserException("Exepected event: " + type
                         + " and tag: " + tag + " but got event: " + parser.getEventType()
@@ -1279,7 +1320,7 @@
         }
 
         private boolean accept(XmlPullParser parser, int type, String tag)
-                throws IOException, XmlPullParserException {
+                throws XmlPullParserException {
             if (parser.getEventType() != type) {
                 return false;
             }
@@ -1375,9 +1416,9 @@
         }
 
         @Override
-        public void removeApprovedPrintService(ComponentName serviceToRemove) {
+        public void pruneApprovedPrintServices(List<ComponentName> servicesToKeep) {
             (new ApprovedPrintServices(PrintSpoolerService.this))
-                    .removeApprovedService(serviceToRemove);
+                    .pruneApprovedServices(servicesToKeep);
         }
 
         @Override
@@ -1395,5 +1436,38 @@
         public PrintSpoolerService getService() {
             return PrintSpoolerService.this;
         }
+
+        @Override
+        public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon,
+                IPrintSpoolerCallbacks callbacks, int sequence)
+                throws RemoteException {
+            try {
+                PrintSpoolerService.this.onCustomPrinterIconLoaded(printerId, icon);
+            } finally {
+                callbacks.onCustomPrinterIconCached(sequence);
+            }
+        }
+
+        @Override
+        public void getCustomPrinterIcon(PrinterId printerId, IPrintSpoolerCallbacks callbacks,
+                int sequence) throws RemoteException {
+            Icon icon = null;
+            try {
+                icon = PrintSpoolerService.this.getCustomPrinterIcon(printerId);
+            } finally {
+                callbacks.onGetCustomPrinterIconResult(icon, sequence);
+            }
+        }
+
+        @Override
+        public void clearCustomPrinterIconCache(IPrintSpoolerCallbacks callbacks,
+                int sequence) throws RemoteException {
+            try {
+                PrintSpoolerService.this.clearCustomPrinterIconCache();
+            } finally {
+                callbacks.customPrinterIconCacheCleared(sequence);
+            }
+        }
+
     }
 }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
index 1b6e9ce..684a1de 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
@@ -173,15 +173,19 @@
         if (DEBUG) {
             Log.i(LOG_TAG, "[CALLED] start()");
         }
-        if (mState != STATE_INITIAL) {
-            throw new IllegalStateException("Cannot start in state:" + stateToString(mState));
-        }
-        try {
-            mPrintDocumentAdapter.start();
-            mState = STATE_STARTED;
-        } catch (RemoteException re) {
-            Log.e(LOG_TAG, "Error calling start()", re);
-            mState = STATE_FAILED;
+        if (mState == STATE_FAILED) {
+            Log.w(LOG_TAG, "Failed before start.");
+        } else {
+            if (mState != STATE_INITIAL) {
+                throw new IllegalStateException("Cannot start in state:" + stateToString(mState));
+            }
+            try {
+                mPrintDocumentAdapter.start();
+                mState = STATE_STARTED;
+            } catch (RemoteException re) {
+                Log.e(LOG_TAG, "Error calling start()", re);
+                mState = STATE_FAILED;
+            }
         }
     }
 
@@ -870,7 +874,7 @@
         private final MutexFileProvider mFileProvider;
 
         private final IWriteResultCallback mRemoteResultCallback;
-        private final CommandDoneCallback mDoneCallback;
+        private final CommandDoneCallback mWriteDoneCallback;
 
         private final Context mContext;
         private final Handler mHandler;
@@ -885,7 +889,7 @@
             mPageCount = pageCount;
             mPages = Arrays.copyOf(pages, pages.length);
             mFileProvider = fileProvider;
-            mDoneCallback = callback;
+            mWriteDoneCallback = callback;
         }
 
         @Override
@@ -997,7 +1001,7 @@
             mCancellation = null;
 
             // Done.
-            mDoneCallback.onDone();
+            mWriteDoneCallback.onDone();
         }
 
         private void handleOnWriteFailed(CharSequence error, int sequence) {
@@ -1015,7 +1019,7 @@
             mCancellation = null;
 
             // Done.
-            mDoneCallback.onDone();
+            mWriteDoneCallback.onDone();
         }
 
         private void handleOnWriteCanceled(int sequence) {
@@ -1033,7 +1037,7 @@
             mCancellation = null;
 
             // Done.
-            mDoneCallback.onDone();
+            mWriteDoneCallback.onDone();
         }
 
         private final class WriteHandler extends Handler {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
index 80c28e0..46a2098 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
@@ -16,27 +16,38 @@
 
 package com.android.printspooler.ui;
 
+import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Loader;
 import android.content.pm.ServiceInfo;
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.location.LocationRequest;
 import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Looper;
+import android.os.SystemClock;
 import android.print.PrintManager;
 import android.print.PrinterDiscoverySession;
 import android.print.PrinterDiscoverySession.OnPrintersChangeListener;
 import android.print.PrinterId;
 import android.print.PrinterInfo;
 import android.printservice.PrintServiceInfo;
-import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.Xml;
 
 import com.android.internal.util.FastXmlSerializer;
 
+import libcore.io.IoUtils;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -49,18 +60,19 @@
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
-import libcore.io.IoUtils;
-
 /**
  * This class is responsible for loading printers by doing discovery
  * and merging the discovered printers with the previously used ones.
  */
-public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
+public final class FusedPrintersProvider extends Loader<List<PrinterInfo>>
+        implements LocationListener {
     private static final String LOG_TAG = "FusedPrintersProvider";
 
     private static final boolean DEBUG = false;
@@ -70,10 +82,22 @@
 
     private static final int MAX_FAVORITE_PRINTER_COUNT = 4;
 
+    /** Interval of location updated in ms */
+    private static final int LOCATION_UPDATE_MS = 30 * 1000;
+
+    /** Maximum acceptable age of the location in ms */
+    private static final int MAX_LOCATION_AGE_MS = 10 * 60 * 1000;
+
+    /** The worst accuracy that is considered usable in m */
+    private static final int MIN_LOCATION_ACCURACY = 50;
+
+    /** Maximum distance where a printer is still considered "near" */
+    private static final int MAX_PRINTER_DISTANCE = MIN_LOCATION_ACCURACY * 2;
+
     private final List<PrinterInfo> mPrinters =
             new ArrayList<>();
 
-    private final List<PrinterInfo> mFavoritePrinters =
+    private final List<Pair<PrinterInfo, Location>> mFavoritePrinters =
             new ArrayList<>();
 
     private final PersistenceManager mPersistenceManager;
@@ -84,33 +108,112 @@
 
     private boolean mPrintersUpdatedBefore;
 
+    /** Last known location, can be null or out of date */
+    private final Object mLocationLock;
+    private Location mLocation;
+
+    /** Location used when the printers were updated the last time */
+    private Location mLocationOfLastPrinterUpdate;
+
+    /** Reference to the system's location manager */
+    private final LocationManager mLocationManager;
+
+    /**
+     * Get a reference to the current location.
+     */
+    private Location getCurrentLocation() {
+        synchronized (mLocationLock) {
+            return mLocation;
+        }
+    }
+
     public FusedPrintersProvider(Context context) {
         super(context);
+        mLocationLock = new Object();
         mPersistenceManager = new PersistenceManager(context);
+        mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
     }
 
     public void addHistoricalPrinter(PrinterInfo printer) {
         mPersistenceManager.addPrinterAndWritePrinterHistory(printer);
     }
 
+    /**
+     * Add printer to dest, or if updatedPrinters add the updated printer. If the updated printer
+     * was added, remove it from updatedPrinters.
+     *
+     * @param dest The list the printers should be added to
+     * @param printer The printer to add
+     * @param updatedPrinters The printer to add
+     */
+    private void updateAndAddPrinter(List<PrinterInfo> dest, PrinterInfo printer,
+            Map<PrinterId, PrinterInfo> updatedPrinters) {
+        PrinterInfo updatedPrinter = updatedPrinters.remove(printer.getId());
+        if (updatedPrinter != null) {
+            dest.add(updatedPrinter);
+        } else {
+            dest.add(printer);
+        }
+    }
+
+    /**
+     * Compute the printers, order them appropriately and deliver the printers to the clients. We
+     * prefer printers that have been previously used (favorites) and printers that have been used
+     * previously close to the current location (near printers).
+     *
+     * @param discoveredPrinters All printers currently discovered by the print discovery session.
+     * @param favoritePrinters The ordered list of printers. The earlier in the list, the more
+     *            preferred.
+     */
     private void computeAndDeliverResult(Map<PrinterId, PrinterInfo> discoveredPrinters,
-            List<PrinterInfo> favoritePrinters) {
+            List<Pair<PrinterInfo, Location>> favoritePrinters) {
         List<PrinterInfo> printers = new ArrayList<>();
 
-        // Add the updated favorite printers.
+        // Store the printerIds that have already been added. We cannot compare the printerInfos in
+        // "printers" as they might have been taken from discoveredPrinters and the printerInfo does
+        // not equals() anymore
+        HashSet<PrinterId> alreadyAddedPrinter = new HashSet<>(MAX_FAVORITE_PRINTER_COUNT);
+
+        Location location = getCurrentLocation();
+
+        // Add the favorite printers that have last been used close to the current location
         final int favoritePrinterCount = favoritePrinters.size();
-        for (int i = 0; i < favoritePrinterCount; i++) {
-            PrinterInfo favoritePrinter = favoritePrinters.get(i);
-            PrinterInfo updatedPrinter = discoveredPrinters.remove(
-                    favoritePrinter.getId());
-            if (updatedPrinter != null) {
-                printers.add(updatedPrinter);
-            } else {
-                printers.add(favoritePrinter);
+        if (location != null) {
+            for (int i = 0; i < favoritePrinterCount; i++) {
+                // Only add a certain amount of favorite printers
+                if (printers.size() == MAX_FAVORITE_PRINTER_COUNT) {
+                    break;
+                }
+
+                PrinterInfo favoritePrinter = favoritePrinters.get(i).first;
+                Location printerLocation = favoritePrinters.get(i).second;
+
+                if (printerLocation != null
+                        && !alreadyAddedPrinter.contains(favoritePrinter.getId())) {
+                    if (printerLocation.distanceTo(location) <= MAX_PRINTER_DISTANCE) {
+                        updateAndAddPrinter(printers, favoritePrinter, discoveredPrinters);
+                        alreadyAddedPrinter.add(favoritePrinter.getId());
+                    }
+                }
             }
         }
 
-        // Add other updated printers.
+        // Add the other favorite printers
+        for (int i = 0; i < favoritePrinterCount; i++) {
+            // Only add a certain amount of favorite printers
+            if (printers.size() == MAX_FAVORITE_PRINTER_COUNT) {
+                break;
+            }
+
+            PrinterInfo favoritePrinter = favoritePrinters.get(i).first;
+            if (!alreadyAddedPrinter.contains(favoritePrinter.getId())) {
+                updateAndAddPrinter(printers, favoritePrinter, discoveredPrinters);
+                alreadyAddedPrinter.add(favoritePrinter.getId());
+            }
+        }
+
+        // Add other updated printers. Printers that have already been added have been removed from
+        // discoveredPrinters in the calls to updateAndAddPrinter
         final int printerCount = mPrinters.size();
         for (int i = 0; i < printerCount; i++) {
             PrinterInfo printer = mPrinters.get(i);
@@ -142,6 +245,21 @@
         if (DEBUG) {
             Log.i(LOG_TAG, "onStartLoading() " + FusedPrintersProvider.this.hashCode());
         }
+
+        mLocationManager.requestLocationUpdates(LocationRequest.create()
+                .setQuality(LocationRequest.POWER_LOW).setInterval(LOCATION_UPDATE_MS), this,
+                Looper.getMainLooper());
+
+        Location lastLocation = mLocationManager.getLastLocation();
+        if (lastLocation != null) {
+            onLocationChanged(lastLocation);
+        }
+
+        // Jumpstart location with a single forced update
+        Criteria oneTimeCriteria = new Criteria();
+        oneTimeCriteria.setAccuracy(Criteria.ACCURACY_FINE);
+        mLocationManager.requestSingleUpdate(oneTimeCriteria, this, Looper.getMainLooper());
+
         // The contract is that if we already have a valid,
         // result the we have to deliver it immediately.
         if (!mPrinters.isEmpty()) {
@@ -158,6 +276,8 @@
             Log.i(LOG_TAG, "onStopLoading() " + FusedPrintersProvider.this.hashCode());
         }
         onCancelLoad();
+
+        mLocationManager.removeUpdates(this);
     }
 
     @Override
@@ -188,34 +308,38 @@
                                 + " " + FusedPrintersProvider.this.hashCode());
                     }
 
-                    updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters);
+                    updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters,
+                            getCurrentLocation());
                 }
             });
             final int favoriteCount = mFavoritePrinters.size();
             List<PrinterId> printerIds = new ArrayList<>(favoriteCount);
             for (int i = 0; i < favoriteCount; i++) {
-                printerIds.add(mFavoritePrinters.get(i).getId());
+                printerIds.add(mFavoritePrinters.get(i).first.getId());
             }
             mDiscoverySession.startPrinterDiscovery(printerIds);
             List<PrinterInfo> printers = mDiscoverySession.getPrinters();
-            if (!printers.isEmpty()) {
-                updatePrinters(printers, mFavoritePrinters);
-            }
+
+            updatePrinters(printers, mFavoritePrinters, getCurrentLocation());
         }
     }
 
-    private void updatePrinters(List<PrinterInfo> printers, List<PrinterInfo> favoritePrinters) {
+    private void updatePrinters(List<PrinterInfo> printers,
+            List<Pair<PrinterInfo, Location>> favoritePrinters,
+            Location location) {
         if (mPrintersUpdatedBefore && mPrinters.equals(printers)
-                && mFavoritePrinters.equals(favoritePrinters)) {
+                && mFavoritePrinters.equals(favoritePrinters)
+                && Objects.equals(mLocationOfLastPrinterUpdate, location)) {
             return;
         }
 
+        mLocationOfLastPrinterUpdate = location;
         mPrintersUpdatedBefore = true;
 
         // Some of the found printers may have be a printer that is in the
-        // history but with its name changed. Hence, we try to update the
-        // printer to use its current name instead of the historical one.
-        mPersistenceManager.updatePrintersHistoricalNamesIfNeeded(printers);
+        // history but with its properties changed. Hence, we try to update the
+        // printer to use its current properties instead of the historical one.
+        mPersistenceManager.updateHistoricalPrintersIfNeeded(printers);
 
         Map<PrinterId, PrinterInfo> printersMap = new LinkedHashMap<>();
         final int printerCount = printers.size();
@@ -271,11 +395,65 @@
         onStopLoading();
     }
 
+    /**
+     * Check if the location is acceptable. This is to filter out excessively old or inaccurate
+     * location updates.
+     *
+     * @param location the location to check
+     * @return true iff the location is usable.
+     */
+    private boolean isLocationAcceptable(Location location) {
+        return location != null
+                && location.getElapsedRealtimeNanos() > SystemClock.elapsedRealtimeNanos()
+                        - MAX_LOCATION_AGE_MS * 1000_000L
+                && location.hasAccuracy()
+                && location.getAccuracy() < MIN_LOCATION_ACCURACY;
+    }
+
+    @Override
+    public void onLocationChanged(Location location) {
+        synchronized(mLocationLock) {
+            // We expect the user to not move too fast while printing. Hence prefer more accurate
+            // updates over more recent ones for LOCATION_UPDATE_MS. We add a 10% fudge factor here
+            // as the location provider might send an update slightly too early.
+            if (isLocationAcceptable(location)
+                    && !location.equals(mLocation)
+                    && (mLocation == null
+                            || location
+                                    .getElapsedRealtimeNanos() > mLocation.getElapsedRealtimeNanos()
+                                            + LOCATION_UPDATE_MS * 0.9 * 1000_000L
+                            || (!mLocation.hasAccuracy()
+                                    || location.getAccuracy() < mLocation.getAccuracy()))) {
+                // Other callers of updatePrinters might want to know the location, hence cache it
+                mLocation = location;
+
+                if (areHistoricalPrintersLoaded()) {
+                    updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters, mLocation);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onStatusChanged(String provider, int status, Bundle extras) {
+        // nothing to do
+    }
+
+    @Override
+    public void onProviderEnabled(String provider) {
+        // nothing to do
+    }
+
+    @Override
+    public void onProviderDisabled(String provider) {
+        // nothing to do
+    }
+
     public boolean areHistoricalPrintersLoaded() {
         return mPersistenceManager.mReadHistoryCompleted;
     }
 
-    public void setTrackedPrinter(PrinterId printerId) {
+    public void setTrackedPrinter(@Nullable PrinterId printerId) {
         if (isStarted() && mDiscoverySession != null
                 && mDiscoverySession.isPrinterDiscoveryStarted()) {
             if (mTrackedPrinter != null) {
@@ -294,7 +472,7 @@
     public boolean isFavoritePrinter(PrinterId printerId) {
         final int printerCount = mFavoritePrinters.size();
         for (int i = 0; i < printerCount; i++) {
-            PrinterInfo favoritePritner = mFavoritePrinters.get(i);
+            PrinterInfo favoritePritner = mFavoritePrinters.get(i).first;
             if (favoritePritner.getId().equals(printerId)) {
                 return true;
             }
@@ -303,28 +481,22 @@
     }
 
     public void forgetFavoritePrinter(PrinterId printerId) {
-        List<PrinterInfo> newFavoritePrinters = null;
+        final int favoritePrinterCount = mFavoritePrinters.size();
+        List<Pair<PrinterInfo, Location>> newFavoritePrinters = new ArrayList<>(
+                favoritePrinterCount - 1);
 
         // Remove the printer from the favorites.
-        final int favoritePrinterCount = mFavoritePrinters.size();
         for (int i = 0; i < favoritePrinterCount; i++) {
-            PrinterInfo favoritePrinter = mFavoritePrinters.get(i);
-            if (favoritePrinter.getId().equals(printerId)) {
-                newFavoritePrinters = new ArrayList<>();
-                newFavoritePrinters.addAll(mPrinters);
-                newFavoritePrinters.remove(i);
-                break;
+            if (!mFavoritePrinters.get(i).first.getId().equals(printerId)) {
+                newFavoritePrinters.add(mFavoritePrinters.get(i));
             }
         }
 
-        // If we removed a favorite printer, we have work to do.
-        if (newFavoritePrinters != null) {
-            // Remove the printer from history and persist the latter.
-            mPersistenceManager.removeHistoricalPrinterAndWritePrinterHistory(printerId);
+        // Remove the printer from history and persist the latter.
+        mPersistenceManager.removeHistoricalPrinterAndWritePrinterHistory(printerId);
 
-            // Recompute and deliver the printers.
-            updatePrinters(mDiscoverySession.getPrinters(), newFavoritePrinters);
-        }
+        // Recompute and deliver the printers.
+        updatePrinters(mDiscoverySession.getPrinters(), newFavoritePrinters, getCurrentLocation());
     }
 
     private final class PersistenceManager {
@@ -333,18 +505,22 @@
         private static final String TAG_PRINTERS = "printers";
 
         private static final String TAG_PRINTER = "printer";
+        private static final String TAG_LOCATION = "location";
         private static final String TAG_PRINTER_ID = "printerId";
 
         private static final String ATTR_LOCAL_ID = "localId";
         private static final String ATTR_SERVICE_NAME = "serviceName";
 
+        private static final String ATTR_LONGITUDE = "longitude";
+        private static final String ATTR_LATITUDE = "latitude";
+        private static final String ATTR_ACCURACY = "accuracy";
+
         private static final String ATTR_NAME = "name";
         private static final String ATTR_DESCRIPTION = "description";
-        private static final String ATTR_STATUS = "status";
 
         private final AtomicFile mStatePersistFile;
 
-        private List<PrinterInfo> mHistoricalPrinters = new ArrayList<>();
+        private List<Pair<PrinterInfo, Location>> mHistoricalPrinters = new ArrayList<>();
 
         private boolean mReadHistoryCompleted;
 
@@ -378,13 +554,13 @@
             mReadTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
         }
 
-        public void updatePrintersHistoricalNamesIfNeeded(List<PrinterInfo> printers) {
+        public void updateHistoricalPrintersIfNeeded(List<PrinterInfo> printers) {
             boolean writeHistory = false;
 
             final int printerCount = printers.size();
             for (int i = 0; i < printerCount; i++) {
                 PrinterInfo printer = printers.get(i);
-                writeHistory |= renamePrinterIfNeeded(printer);
+                writeHistory |= updateHistoricalPrinterIfNeeded(printer);
             }
 
             if (writeHistory) {
@@ -392,25 +568,57 @@
             }
         }
 
-        public boolean renamePrinterIfNeeded(PrinterInfo printer) {
-            boolean renamed = false;
+        /**
+         * Updates the historical printer state with the given printer.
+         *
+         * @param printer the printer to update
+         *
+         * @return true iff the historical printer list needs to be updated
+         */
+        public boolean updateHistoricalPrinterIfNeeded(PrinterInfo printer) {
+            boolean writeHistory = false;
             final int printerCount = mHistoricalPrinters.size();
             for (int i = 0; i < printerCount; i++) {
-                PrinterInfo historicalPrinter = mHistoricalPrinters.get(i);
-                if (historicalPrinter.getId().equals(printer.getId())
-                        && !TextUtils.equals(historicalPrinter.getName(), printer.getName())) {
-                    mHistoricalPrinters.set(i, printer);
-                    renamed = true;
+                PrinterInfo historicalPrinter = mHistoricalPrinters.get(i).first;
+
+                if (!historicalPrinter.getId().equals(printer.getId())) {
+                    continue;
+                }
+
+                // Overwrite the historical printer with the updated printer as some properties
+                // changed. We ignore the status as this is a volatile state.
+                if (historicalPrinter.equalsIgnoringStatus(printer)) {
+                    continue;
+                }
+
+                mHistoricalPrinters.set(i, new Pair<PrinterInfo, Location>(printer,
+                                mHistoricalPrinters.get(i).second));
+
+                // We only persist limited information in the printer history, hence check if
+                // we need to persist the update.
+                // @see PersistenceManager.WriteTask#doWritePrinterHistory
+                if (!historicalPrinter.getName().equals(printer.getName())) {
+                    if (Objects.equals(historicalPrinter.getDescription(),
+                            printer.getDescription())) {
+                        writeHistory = true;
+                    }
                 }
             }
-            return renamed;
+            return writeHistory;
         }
 
         public void addPrinterAndWritePrinterHistory(PrinterInfo printer) {
             if (mHistoricalPrinters.size() >= MAX_HISTORY_LENGTH) {
                 mHistoricalPrinters.remove(0);
             }
-            mHistoricalPrinters.add(printer);
+
+            Location location = getCurrentLocation();
+            if (!isLocationAcceptable(location)) {
+                location = null;
+            }
+
+            mHistoricalPrinters.add(new Pair<PrinterInfo, Location>(printer, location));
+
             writePrinterHistory();
         }
 
@@ -418,7 +626,7 @@
             boolean writeHistory = false;
             final int printerCount = mHistoricalPrinters.size();
             for (int i = printerCount - 1; i >= 0; i--) {
-                PrinterInfo historicalPrinter = mHistoricalPrinters.get(i);
+                PrinterInfo historicalPrinter = mHistoricalPrinters.get(i).first;
                 if (historicalPrinter.getId().equals(printerId)) {
                     mHistoricalPrinters.remove(i);
                     writeHistory = true;
@@ -439,63 +647,91 @@
             return mLastReadHistoryTimestamp != mStatePersistFile.getBaseFile().lastModified();
         }
 
-        private List<PrinterInfo> computeFavoritePrinters(List<PrinterInfo> printers) {
+        /**
+         * Sort the favorite printers by weight. If a printer is in the list multiple times for
+         * different locations, all instances are considered to have the accumulative weight. The
+         * actual favorite printers to display are computed in {@link #computeAndDeliverResult} as
+         * only at this time we know the location to use to determine if a printer is close enough
+         * to be preferred.
+         *
+         * @param printers The printers to sort.
+         * @return The sorted printers.
+         */
+        private List<Pair<PrinterInfo, Location>> sortFavoritePrinters(
+                List<Pair<PrinterInfo, Location>> printers) {
             Map<PrinterId, PrinterRecord> recordMap = new ArrayMap<>();
 
-            // Recompute the weights.
+            // Compute the weights.
             float currentWeight = 1.0f;
             final int printerCount = printers.size();
             for (int i = printerCount - 1; i >= 0; i--) {
-                PrinterInfo printer = printers.get(i);
-                // Aggregate weight for the same printer
-                PrinterRecord record = recordMap.get(printer.getId());
+                PrinterId printerId = printers.get(i).first.getId();
+                PrinterRecord record = recordMap.get(printerId);
                 if (record == null) {
-                    record = new PrinterRecord(printer);
-                    recordMap.put(printer.getId(), record);
+                    record = new PrinterRecord();
+                    recordMap.put(printerId, record);
                 }
+
+                record.printers.add(printers.get(i));
+
+                // Aggregate weight for the same printer
                 record.weight += currentWeight;
                 currentWeight *= WEIGHT_DECAY_COEFFICIENT;
             }
 
-            // Soft the favorite printers.
+            // Sort the favorite printers.
             List<PrinterRecord> favoriteRecords = new ArrayList<>(
                     recordMap.values());
             Collections.sort(favoriteRecords);
 
             // Write the favorites to the output.
-            final int favoriteCount = Math.min(favoriteRecords.size(),
-                    MAX_FAVORITE_PRINTER_COUNT);
-            List<PrinterInfo> favoritePrinters = new ArrayList<>(favoriteCount);
-            for (int i = 0; i < favoriteCount; i++) {
-                PrinterInfo printer = favoriteRecords.get(i).printer;
-                favoritePrinters.add(printer);
+            final int recordCount = favoriteRecords.size();
+            List<Pair<PrinterInfo, Location>> favoritePrinters = new ArrayList<>(printerCount);
+            for (int i = 0; i < recordCount; i++) {
+                favoritePrinters.addAll(favoriteRecords.get(i).printers);
             }
 
             return favoritePrinters;
         }
 
+        /**
+         * A set of printers with the same ID and the weight associated with them during
+         * {@link #sortFavoritePrinters}.
+         */
         private final class PrinterRecord implements Comparable<PrinterRecord> {
-            public final PrinterInfo printer;
+            /**
+             * The printers, all with the same ID, but potentially different properties or locations
+             */
+            public final List<Pair<PrinterInfo, Location>> printers;
+
+            /** The weight associated with the printers */
             public float weight;
 
-            public PrinterRecord(PrinterInfo printer) {
-                this.printer = printer;
+            /**
+             * Create a new record.
+             */
+            public PrinterRecord() {
+                printers = new ArrayList<>();
             }
 
+            /**
+             * Compare two records by weight.
+             */
             @Override
             public int compareTo(PrinterRecord another) {
                 return Float.floatToIntBits(another.weight) - Float.floatToIntBits(weight);
             }
         }
 
-        private final class ReadTask extends AsyncTask<Void, Void, List<PrinterInfo>> {
+        private final class ReadTask
+                extends AsyncTask<Void, Void, List<Pair<PrinterInfo, Location>>> {
             @Override
-            protected List<PrinterInfo> doInBackground(Void... args) {
+            protected List<Pair<PrinterInfo, Location>> doInBackground(Void... args) {
                return doReadPrinterHistory();
             }
 
             @Override
-            protected void onPostExecute(List<PrinterInfo> printers) {
+            protected void onPostExecute(List<Pair<PrinterInfo, Location>> printers) {
                 if (DEBUG) {
                     Log.i(LOG_TAG, "read history completed "
                             + FusedPrintersProvider.this.hashCode());
@@ -518,7 +754,8 @@
 
                 final int printerCount = printers.size();
                 for (int i = printerCount - 1; i >= 0; i--) {
-                    ComponentName printerServiceName = printers.get(i).getId().getServiceName();
+                    ComponentName printerServiceName = printers.get(i).first.getId()
+                            .getServiceName();
                     if (!enabledComponents.contains(printerServiceName)) {
                         printers.remove(i);
                     }
@@ -529,12 +766,13 @@
 
                 // Compute the favorite printers.
                 mFavoritePrinters.clear();
-                mFavoritePrinters.addAll(computeFavoritePrinters(mHistoricalPrinters));
+                mFavoritePrinters.addAll(sortFavoritePrinters(mHistoricalPrinters));
 
                 mReadHistoryCompleted = true;
 
                 // Deliver the printers.
-                updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters);
+                updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters,
+                        getCurrentLocation());
 
                 // We are done.
                 mReadTask = null;
@@ -544,12 +782,12 @@
             }
 
             @Override
-            protected void onCancelled(List<PrinterInfo> printerInfos) {
+            protected void onCancelled(List<Pair<PrinterInfo, Location>> printerInfos) {
                 // We are done.
                 mReadTask = null;
             }
 
-            private List<PrinterInfo> doReadPrinterHistory() {
+            private List<Pair<PrinterInfo, Location>> doReadPrinterHistory() {
                 final FileInputStream in;
                 try {
                     in = mStatePersistFile.openRead();
@@ -561,7 +799,7 @@
                     return new ArrayList<>();
                 }
                 try {
-                    List<PrinterInfo> printers = new ArrayList<>();
+                    List<Pair<PrinterInfo, Location>> printers = new ArrayList<>();
                     XmlPullParser parser = Xml.newPullParser();
                     parser.setInput(in, StandardCharsets.UTF_8.name());
                     parseState(parser, printers);
@@ -582,8 +820,9 @@
                 return Collections.emptyList();
             }
 
-            private void parseState(XmlPullParser parser, List<PrinterInfo> outPrinters)
-                    throws IOException, XmlPullParserException {
+            private void parseState(XmlPullParser parser,
+                    List<Pair<PrinterInfo, Location>> outPrinters)
+                            throws IOException, XmlPullParserException {
                 parser.next();
                 skipEmptyTextTags(parser);
                 expect(parser, XmlPullParser.START_TAG, TAG_PRINTERS);
@@ -601,8 +840,9 @@
                 expect(parser, XmlPullParser.END_TAG, TAG_PRINTERS);
             }
 
-            private boolean parsePrinter(XmlPullParser parser, List<PrinterInfo> outPrinters)
-                    throws IOException, XmlPullParserException {
+            private boolean parsePrinter(XmlPullParser parser,
+                    List<Pair<PrinterInfo, Location>> outPrinters)
+                            throws IOException, XmlPullParserException {
                 skipEmptyTextTags(parser);
                 if (!accept(parser, XmlPullParser.START_TAG, TAG_PRINTER)) {
                     return false;
@@ -610,7 +850,6 @@
 
                 String name = parser.getAttributeValue(null, ATTR_NAME);
                 String description = parser.getAttributeValue(null, ATTR_DESCRIPTION);
-                final int status = Integer.parseInt(parser.getAttributeValue(null, ATTR_STATUS));
 
                 parser.next();
 
@@ -625,11 +864,34 @@
                 expect(parser, XmlPullParser.END_TAG, TAG_PRINTER_ID);
                 parser.next();
 
-                PrinterInfo.Builder builder = new PrinterInfo.Builder(printerId, name, status);
+                skipEmptyTextTags(parser);
+                Location location;
+                if (accept(parser, XmlPullParser.START_TAG, TAG_LOCATION)) {
+                    location = new Location("");
+                    location.setLongitude(
+                            Double.parseDouble(parser.getAttributeValue(null, ATTR_LONGITUDE)));
+                    location.setLatitude(
+                            Double.parseDouble(parser.getAttributeValue(null, ATTR_LATITUDE)));
+                    location.setAccuracy(
+                            Float.parseFloat(parser.getAttributeValue(null, ATTR_ACCURACY)));
+                    parser.next();
+
+                    skipEmptyTextTags(parser);
+                    expect(parser, XmlPullParser.END_TAG, TAG_LOCATION);
+                    parser.next();
+                } else {
+                    location = null;
+                }
+
+                // If the printer is available the printer will be replaced by the one read from the
+                // discovery session, hence the only time when this object is used is when the
+                // printer is unavailable.
+                PrinterInfo.Builder builder = new PrinterInfo.Builder(printerId, name,
+                        PrinterInfo.STATUS_UNAVAILABLE);
                 builder.setDescription(description);
                 PrinterInfo printer = builder.build();
 
-                outPrinters.add(printer);
+                outPrinters.add(new Pair<PrinterInfo, Location>(printer, location));
 
                 if (DEBUG) {
                     Log.i(LOG_TAG, "[RESTORED] " + printer);
@@ -642,7 +904,7 @@
             }
 
             private void expect(XmlPullParser parser, int type, String tag)
-                    throws IOException, XmlPullParserException {
+                    throws XmlPullParserException {
                 if (!accept(parser, type, tag)) {
                     throw new XmlPullParserException("Exepected event: " + type
                             + " and tag: " + tag + " but got event: " + parser.getEventType()
@@ -659,7 +921,7 @@
             }
 
             private boolean accept(XmlPullParser parser, int type, String tag)
-                    throws IOException, XmlPullParserException {
+                    throws XmlPullParserException {
                 if (parser.getEventType() != type) {
                     return false;
                 }
@@ -674,14 +936,16 @@
             }
         }
 
-        private final class WriteTask extends AsyncTask<List<PrinterInfo>, Void, Void> {
+        private final class WriteTask
+                extends AsyncTask<List<Pair<PrinterInfo, Location>>, Void, Void> {
             @Override
-            protected Void doInBackground(List<PrinterInfo>... printers) {
+            protected Void doInBackground(
+                    @SuppressWarnings("unchecked") List<Pair<PrinterInfo, Location>>... printers) {
                 doWritePrinterHistory(printers[0]);
                 return null;
             }
 
-            private void doWritePrinterHistory(List<PrinterInfo> printers) {
+            private void doWritePrinterHistory(List<Pair<PrinterInfo, Location>> printers) {
                 FileOutputStream out = null;
                 try {
                     out = mStatePersistFile.startWrite();
@@ -693,14 +957,11 @@
 
                     final int printerCount = printers.size();
                     for (int i = 0; i < printerCount; i++) {
-                        PrinterInfo printer = printers.get(i);
+                        PrinterInfo printer = printers.get(i).first;
 
                         serializer.startTag(null, TAG_PRINTER);
 
                         serializer.attribute(null, ATTR_NAME, printer.getName());
-                        // Historical printers are always stored as unavailable.
-                        serializer.attribute(null, ATTR_STATUS, String.valueOf(
-                                PrinterInfo.STATUS_UNAVAILABLE));
                         String description = printer.getDescription();
                         if (description != null) {
                             serializer.attribute(null, ATTR_DESCRIPTION, description);
@@ -713,6 +974,18 @@
                                 .flattenToString());
                         serializer.endTag(null, TAG_PRINTER_ID);
 
+                        Location location = printers.get(i).second;
+                        if (location != null) {
+                            serializer.startTag(null, TAG_LOCATION);
+                            serializer.attribute(null, ATTR_LONGITUDE,
+                                    String.valueOf(location.getLongitude()));
+                            serializer.attribute(null, ATTR_LATITUDE,
+                                    String.valueOf(location.getLatitude()));
+                            serializer.attribute(null, ATTR_ACCURACY,
+                                    String.valueOf(location.getAccuracy()));
+                            serializer.endTag(null, TAG_LOCATION);
+                        }
+
                         serializer.endTag(null, TAG_PRINTER);
 
                         if (DEBUG) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
index 2757b81..606f4eb 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
@@ -52,7 +52,7 @@
 /**
  * This class represents the adapter for the pages in the print preview list.
  */
-public final class PageAdapter extends Adapter {
+public final class PageAdapter extends Adapter<ViewHolder> {
     private static final String LOG_TAG = "PageAdapter";
 
     private static final int MAX_PREVIEW_PAGES_BATCH = 50;
@@ -409,7 +409,7 @@
                 - horizontalPaddingAndMargins) / columnCount) + 0.5f);
 
         // Compute max page height.
-        final int pageContentDesiredHeight = (int) (((float) pageContentDesiredWidth
+        final int pageContentDesiredHeight = (int) ((pageContentDesiredWidth
                 / pageAspectRatio) + 0.5f);
 
         // If the page does not fit entirely in a vertical direction,
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 6521565..743df99 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -30,7 +30,6 @@
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
@@ -462,6 +461,7 @@
         }
     }
 
+    @Override
     public void onUpdateCanceled() {
         if (DEBUG) {
             Log.i(LOG_TAG, "onUpdateCanceled()");
@@ -1003,7 +1003,9 @@
         if (currMediaSize == null) {
             attributes.setMediaSize(defaults.getMediaSize());
         } else {
-            boolean foundCurrentMediaSize = false;
+            MediaSize newMediaSize = null;
+            boolean isPortrait = currMediaSize.isPortrait();
+
             // Try to find the current media size in the capabilities as
             // it may be in a different orientation.
             MediaSize currMediaSizePortrait = currMediaSize.asPortrait();
@@ -1011,14 +1013,21 @@
             for (int i = 0; i < mediaSizeCount; i++) {
                 MediaSize mediaSize = sortedMediaSizes.get(i);
                 if (currMediaSizePortrait.equals(mediaSize.asPortrait())) {
-                    attributes.setMediaSize(currMediaSize);
-                    foundCurrentMediaSize = true;
+                    newMediaSize = mediaSize;
                     break;
                 }
             }
             // If we did not find the current media size fall back to default.
-            if (!foundCurrentMediaSize) {
-                attributes.setMediaSize(defaults.getMediaSize());
+            if (newMediaSize == null) {
+                newMediaSize = defaults.getMediaSize();
+            }
+
+            if (newMediaSize != null) {
+                if (isPortrait) {
+                    attributes.setMediaSize(newMediaSize.asPortrait());
+                } else {
+                    attributes.setMediaSize(newMediaSize.asLandscape());
+                }
             }
         }
 
@@ -1738,8 +1747,9 @@
     }
 
     private void updatePageRangeOptions(int pageCount) {
+        @SuppressWarnings("unchecked")
         ArrayAdapter<SpinnerItem<Integer>> rangeOptionsSpinnerAdapter =
-                (ArrayAdapter) mRangeOptionsSpinner.getAdapter();
+                (ArrayAdapter<SpinnerItem<Integer>>) mRangeOptionsSpinner.getAdapter();
         rangeOptionsSpinnerAdapter.clear();
 
         final int[] rangeOptionsValues = getResources().getIntArray(
@@ -1928,6 +1938,7 @@
             this.label = label;
         }
 
+        @Override
         public String toString() {
             return label.toString();
         }
@@ -1962,7 +1973,7 @@
                                 && printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE)
                                 || (mPrinter.getCapabilities() == null
                                 && printer.getCapabilities() != null);
-                mPrinter.copyFrom(printer);
+                mPrinter = printer;
             }
 
             if (available) {
@@ -2187,7 +2198,7 @@
                 if (position == 0 && getPdfPrinter() != null) {
                     PrinterHolder printerHolder = (PrinterHolder) getItem(position);
                     title = printerHolder.printer.getName();
-                    icon = getResources().getDrawable(R.drawable.ic_menu_savetopdf);
+                    icon = getResources().getDrawable(R.drawable.ic_menu_savetopdf, null);
                 } else if (position == 1) {
                     title = getString(R.string.all_printers);
                 }
@@ -2195,20 +2206,16 @@
                 if (position == 1 && getPdfPrinter() != null) {
                     PrinterHolder printerHolder = (PrinterHolder) getItem(position);
                     title = printerHolder.printer.getName();
-                    icon = getResources().getDrawable(R.drawable.ic_menu_savetopdf);
+                    icon = getResources().getDrawable(R.drawable.ic_menu_savetopdf, null);
                 } else if (position == getCount() - 1) {
                     title = getString(R.string.all_printers);
                 } else {
                     PrinterHolder printerHolder = (PrinterHolder) getItem(position);
-                    title = printerHolder.printer.getName();
-                    try {
-                        PackageInfo packageInfo = getPackageManager().getPackageInfo(
-                                printerHolder.printer.getId().getServiceName().getPackageName(), 0);
-                        subtitle = packageInfo.applicationInfo.loadLabel(getPackageManager());
-                        icon = packageInfo.applicationInfo.loadIcon(getPackageManager());
-                    } catch (NameNotFoundException nnfe) {
-                        /* ignore */
-                    }
+                    PrinterInfo printInfo = printerHolder.printer;
+
+                    title = printInfo.getName();
+                    icon = printInfo.loadIcon(PrintActivity.this);
+                    subtitle = printInfo.getDescription();
                 }
             }
 
@@ -2396,7 +2403,7 @@
 
             mPrinterAvailabilityDetector.updatePrinter(newPrinterState);
 
-            oldPrinterState.copyFrom(newPrinterState);
+            mCurrentPrinter = newPrinterState;
 
             if ((isActive && gotCapab) || (becameActive && hasCapab)) {
                 if (hasCapab && capabChanged) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
index 8716fd2..ce54204 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
@@ -78,8 +78,8 @@
         mRecyclerView.setLayoutManager(mLayoutManger);
         mRecyclerView.setAdapter(mPageAdapter);
         mRecyclerView.setItemViewCacheSize(0);
-        mPreloadController = new PreloadController(mRecyclerView);
-        mRecyclerView.setOnScrollListener(mPreloadController);
+        mPreloadController = new PreloadController();
+        mRecyclerView.addOnScrollListener(mPreloadController);
 
         mContentView = (PrintContentView) activity.findViewById(R.id.options_content);
         mEmbeddedContentContainer = (EmbeddedContentContainer) activity.findViewById(
@@ -314,12 +314,9 @@
     }
 
     private final class PreloadController extends RecyclerView.OnScrollListener {
-        private final RecyclerView mRecyclerView;
-
         private int mOldScrollState;
 
-        public PreloadController(RecyclerView recyclerView) {
-            mRecyclerView = recyclerView;
+        public PreloadController() {
             mOldScrollState = mRecyclerView.getScrollState();
         }
 
@@ -371,7 +368,8 @@
                 View lastChild = layoutManager.getChildAt(layoutManager.getChildCount() - 1);
                 ViewHolder lastHolder = mRecyclerView.getChildViewHolder(lastChild);
 
-                return new PageRange(firstHolder.getPosition(), lastHolder.getPosition());
+                return new PageRange(firstHolder.getLayoutPosition(),
+                        lastHolder.getLayoutPosition());
             }
             return null;
         }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java
index cbc568a..6d60bb8 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java
@@ -16,6 +16,7 @@
 
 package com.android.printspooler.ui;
 
+import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.LoaderManager.LoaderCallbacks;
 import android.content.Loader;
@@ -89,7 +90,7 @@
         return false;
     }
 
-    public void setTrackedPrinter(PrinterId printerId) {
+    public void setTrackedPrinter(@Nullable PrinterId printerId) {
         FusedPrintersProvider provider = getPrinterProvider();
         if (provider != null) {
             provider.setTrackedPrinter(printerId);
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
index ab0b2f1..1aec253 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
@@ -27,6 +27,7 @@
 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;
@@ -51,6 +52,7 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
+import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityManager;
 import android.widget.AdapterView;
@@ -63,7 +65,9 @@
 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;
@@ -99,7 +103,8 @@
     private AnnounceFilterResult mAnnounceFilterResult;
 
     /** Monitor if new print services get enabled or disabled */
-    private ContentObserver mPrintServicesObserver;
+    private ContentObserver mPrintServicesDisabledObserver;
+    private PackageMonitor mPackageObserver;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -143,6 +148,14 @@
         });
 
         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();
+        }
     }
 
     @Override
@@ -243,28 +256,45 @@
      * Register listener for changes to the enabled print services.
      */
     private void registerServiceMonitor() {
-        mPrintServicesObserver = new ContentObserver(new Handler()) {
+        // 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.ENABLED_PRINT_SERVICES), false,
-                mPrintServicesObserver);
+                Settings.Secure.getUriFor(Settings.Secure.DISABLED_PRINT_SERVICES), false,
+                mPrintServicesDisabledObserver);
+
+        mPackageObserver.register(this, getMainLooper(), false);
     }
 
     /**
-     * Unregister {@link #mPrintServicesObserver listener for changes to the enabled print services}
-     * or nothing if the listener is not registered.
+     * Unregister the listeners for changes to the enabled print services.
      */
     private void unregisterServiceMonitorIfNeeded() {
-        if (mPrintServicesObserver != null) {
-            getContentResolver().unregisterContentObserver(mPrintServicesObserver);
-
-            mPrintServicesObserver = null;
-        }
+        getContentResolver().unregisterContentObserver(mPrintServicesDisabledObserver);
+        mPackageObserver.unregister();
     }
 
     @Override
@@ -587,20 +617,31 @@
 
             convertView.setEnabled(isActionable(position));
 
-            PrinterInfo printer = (PrinterInfo) getItem(position);
+            final PrinterInfo printer = (PrinterInfo) getItem(position);
 
             CharSequence title = printer.getName();
-            CharSequence subtitle = null;
-            Drawable icon = null;
+            Drawable icon = printer.loadIcon(SelectPrinterActivity.this);
 
+            CharSequence printServiceLabel;
             try {
-                PackageManager pm = getPackageManager();
-                PackageInfo packageInfo = pm.getPackageInfo(printer.getId()
-                        .getServiceName().getPackageName(), 0);
-                subtitle = packageInfo.applicationInfo.loadLabel(pm);
-                icon = packageInfo.applicationInfo.loadIcon(pm);
-            } catch (NameNotFoundException nnfe) {
-                /* ignore */
+                PackageInfo packageInfo = getPackageManager().getPackageInfo(
+                        printer.getId().getServiceName().getPackageName(), 0);
+
+                printServiceLabel = packageInfo.applicationInfo.loadLabel(getPackageManager());
+            } catch (NameNotFoundException e) {
+                printServiceLabel = null;
+            }
+
+            CharSequence description = printer.getDescription();
+
+            CharSequence subtitle;
+            if (TextUtils.isEmpty(printServiceLabel)) {
+                subtitle = description;
+            } else if (TextUtils.isEmpty(description)) {
+                subtitle = printServiceLabel;
+            } else {
+                subtitle = getString(R.string.printer_extended_description_template,
+                        printServiceLabel, description);
             }
 
             TextView titleView = (TextView) convertView.findViewById(R.id.title);
@@ -615,6 +656,20 @@
                 subtitleView.setVisibility(View.GONE);
             }
 
+            ImageView moreInfoView = (ImageView) convertView.findViewById(R.id.more_info);
+            if (printer.getInfoIntent() != null) {
+                moreInfoView.setVisibility(View.VISIBLE);
+                moreInfoView.setOnClickListener(new OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        try {
+                            startIntentSender(printer.getInfoIntent().getIntentSender(), null, 0, 0, 0);
+                        } catch (SendIntentException e) {
+                            Log.e(LOG_TAG, "Could not execute pending info intent: %s", e);
+                        }
+                    }
+                });
+            }
 
             ImageView iconView = (ImageView) convertView.findViewById(R.id.icon);
             if (icon != null) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/util/ApprovedPrintServices.java b/packages/PrintSpooler/src/com/android/printspooler/util/ApprovedPrintServices.java
index dd10567..f781159 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/util/ApprovedPrintServices.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/util/ApprovedPrintServices.java
@@ -23,6 +23,7 @@
 import android.printservice.PrintService;
 import android.util.ArraySet;
 
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -126,29 +127,32 @@
     }
 
     /**
-     * If a {@link PrintService} is approved, remove it from the list of approved services.
+     * Remove all approved {@link PrintService print services} that are not in the given set.
      *
-     * @param serviceToRemove The {@link ComponentName} of the {@link PrintService} to be removed
+     * @param serviceNamesToKeep The {@link ComponentName names } of the services to keep
      */
-    public void removeApprovedService(ComponentName serviceToRemove) {
+    public void pruneApprovedServices(List<ComponentName> serviceNamesToKeep) {
         synchronized (sLock) {
-            if (isApprovedService(serviceToRemove)) {
-                // Copy approved services.
-                ArraySet<String> approvedServices = new ArraySet<String>(
-                        mPreferences.getStringSet(APPROVED_SERVICES_PREFERENCE, null));
+            Set<String> approvedServices = getApprovedServices();
 
+            if (approvedServices == null) {
+                return;
+            }
+
+            Set<String> newApprovedServices = new ArraySet<>(approvedServices.size());
+
+            final int numServiceNamesToKeep = serviceNamesToKeep.size();
+            for(int i = 0; i < numServiceNamesToKeep; i++) {
+                String serviceToKeep = serviceNamesToKeep.get(i).flattenToShortString();
+                if (approvedServices.contains(serviceToKeep)) {
+                    newApprovedServices.add(serviceToKeep);
+                }
+            }
+
+            if (approvedServices.size() != newApprovedServices.size()) {
                 SharedPreferences.Editor editor = mPreferences.edit();
 
-                final int numApprovedServices = approvedServices.size();
-                for (int i = 0; i < numApprovedServices; i++) {
-                    if (approvedServices.valueAt(i)
-                            .equals(serviceToRemove.flattenToShortString())) {
-                        approvedServices.removeAt(i);
-                        break;
-                    }
-                }
-
-                editor.putStringSet(APPROVED_SERVICES_PREFERENCE, approvedServices);
+                editor.putStringSet(APPROVED_SERVICES_PREFERENCE, newApprovedServices);
                 editor.apply();
             }
         }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
index e6613fa..0bb4bfa 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
@@ -415,6 +415,7 @@
             onDragProgress(progress);
         }
 
+        @Override
         public void onViewReleased(View child, float velocityX, float velocityY) {
             final int childTop = child.getTop();
 
@@ -435,14 +436,17 @@
             invalidate();
         }
 
+        @Override
         public int getOrderedChildIndex(int index) {
             return getChildCount() - index - 1;
         }
 
+        @Override
         public int getViewVerticalDragRange(View child) {
             return mDraggableContent.getHeight();
         }
 
+        @Override
         public int clampViewPositionVertical(View child, int top, int dy) {
             final int staticOptionBottom = mStaticContent.getBottom();
             return Math.max(Math.min(top, getOpenedOptionsY()), getClosedOptionsY());
diff --git a/packages/SettingsLib/Android.mk b/packages/SettingsLib/Android.mk
index c860668..2189b55 100644
--- a/packages/SettingsLib/Android.mk
+++ b/packages/SettingsLib/Android.mk
@@ -3,9 +3,22 @@
 
 LOCAL_MODULE := SettingsLib
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-v4 \
+    android-support-v7-recyclerview \
+    android-support-v7-preference \
+    android-support-v7-appcompat \
+    android-support-v14-preference
 
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \
+    frameworks/support/v7/preference/res \
+    frameworks/support/v14/preference/res \
+    frameworks/support/v7/appcompat/res \
+    frameworks/support/v7/recyclerview/res
+
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+LOCAL_AAPT_FLAGS := --auto-add-overlay \
+    --extra-packages android.support.v7.preference:android.support.v14.preference:android.support.v17.preference:android.support.v7.appcompat:android.support.v7.recyclerview
+
 include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/packages/SettingsLib/res/drawable/ic_settings_lock_outline.xml b/packages/SettingsLib/res/drawable/ic_settings_lock_outline.xml
new file mode 100644
index 0000000..b3d7cf9
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_settings_lock_outline.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.
+-->
+
+<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/spinner_dropdown_restricted_item.xml b/packages/SettingsLib/res/layout/spinner_dropdown_restricted_item.xml
new file mode 100644
index 0000000..f7a9c9f
--- /dev/null
+++ b/packages/SettingsLib/res/layout/spinner_dropdown_restricted_item.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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@android:id/text1"
+        style="?android:attr/spinnerDropDownItemStyle"
+        android:singleLine="true"
+        android:layout_width="wrap_content"
+        android:layout_height="?android:attr/listPreferredItemHeightSmall"
+        android:ellipsize="marquee" />
\ No newline at end of file
diff --git a/packages/SettingsLib/res/layout/user_preference.xml b/packages/SettingsLib/res/layout/user_preference.xml
index 75031fd..aa07713 100644
--- a/packages/SettingsLib/res/layout/user_preference.xml
+++ b/packages/SettingsLib/res/layout/user_preference.xml
@@ -23,7 +23,7 @@
         android:orientation="horizontal" >
 
     <ImageView
-            android:id="@+android:id/icon"
+            android:id="@android:id/icon"
             android:layout_width="@dimen/user_icon_view_height"
             android:layout_height="@dimen/user_icon_view_height"
             android:layout_gravity="center"
@@ -32,12 +32,12 @@
             android:paddingTop="@dimen/user_spinner_padding" />
 
     <TextView
-            android:id="@+android:id/title"
+            android:id="@android:id/title"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:singleLine="true"
             android:layout_gravity="center"
-            android:labelFor="@+android:id/icon"
+            android:labelFor="@android:id/icon"
             android:ellipsize="marquee"
             android:fadingEdge="horizontal"
             android:paddingStart="@dimen/user_spinner_padding"
diff --git a/packages/SettingsLib/res/values-af/arrays.xml b/packages/SettingsLib/res/values-af/arrays.xml
index c886476..8720eb2 100644
--- a/packages/SettingsLib/res/values-af/arrays.xml
+++ b/packages/SettingsLib/res/values-af/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Gebruik altyd HDCP-kontrolering"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 K"</item>
-    <item msgid="505611754508988476">"256 K"</item>
-    <item msgid="6361286924268716397">"1 M"</item>
-    <item msgid="6405203239560695266">"4 M"</item>
-    <item msgid="3025431211013424097">"16 M"</item>
+    <item msgid="8665206199209698501">"Af"</item>
+    <item msgid="1593289376502312923">"64 K"</item>
+    <item msgid="487545340236145324">"256 K"</item>
+    <item msgid="2423528675294333831">"1 M"</item>
+    <item msgid="180883774509476541">"4 M"</item>
+    <item msgid="2803199102589126938">"16 M"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 K"</item>
-    <item msgid="3534782711045262344">"256 K"</item>
-    <item msgid="8085867209202153403">"1 M"</item>
+    <item msgid="6089470720451068364">"Af"</item>
+    <item msgid="4622460333038586791">"64 K"</item>
+    <item msgid="2212125625169582330">"256 K"</item>
+    <item msgid="1704946766699242653">"1 M"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 K per logbuffer"</item>
-    <item msgid="2822309747675758628">"256 K per logbuffer"</item>
-    <item msgid="6699306198357496731">"1 M per logbuffer"</item>
-    <item msgid="5748528643937500349">"4 M per logbuffer"</item>
-    <item msgid="1978629051085111592">"16 M per logbuffer"</item>
+    <item msgid="6921048829791179331">"Af"</item>
+    <item msgid="2969458029344750262">"64 K per logbuffer"</item>
+    <item msgid="1342285115665698168">"256 K per logbuffer"</item>
+    <item msgid="1314234299552254621">"1 M per logbuffer"</item>
+    <item msgid="3606047780792894151">"4 M per logbuffer"</item>
+    <item msgid="5431354956856655120">"16 M per logbuffer"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animasie af"</item>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 0d9d79c..e7ae858 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Laat enige program na ekstern geskryf word, ongeag manifeswaardes"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Verplig verstelbare groottes vir aktiwiteite"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Maak grootte van alle aktiwiteite verstelbaar vir veelvuldige vensters, ongeag manifeswaardes."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Aktiveer vormvrye-Windows"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktiveer steun vir eksperimentele vormvrye-Windows."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Werkskerm-rugsteunwagwoord"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Volle rekenaarrugsteune word nie tans beskerm nie"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Raak om die wagwoord vir volledige rekenaarrugsteune te verander of te verwyder"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Outomaties"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Kleurregstelling"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – sowat <xliff:g id="TIME">%2$s</xliff:g> oor"</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> tot vol"</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> tot vol op WS"</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> tot vol oor USB"</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> tot vol vanaf draadloos"</string>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Laai tans oor USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Laai tans draadloos"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-am/arrays.xml b/packages/SettingsLib/res/values-am/arrays.xml
index 324ee83..62e372b 100644
--- a/packages/SettingsLib/res/values-am/arrays.xml
+++ b/packages/SettingsLib/res/values-am/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"ሁልጊዜ የHDCP ምልከታ ተጠቀም"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 ኪባ"</item>
-    <item msgid="505611754508988476">"256 ኪባ"</item>
-    <item msgid="6361286924268716397">"1 ሜባ"</item>
-    <item msgid="6405203239560695266">"4 ሜባ"</item>
-    <item msgid="3025431211013424097">"16 ሜባ"</item>
+    <item msgid="8665206199209698501">"ጠፍቷል"</item>
+    <item msgid="1593289376502312923">"64 ኪባ"</item>
+    <item msgid="487545340236145324">"256 ኪባ"</item>
+    <item msgid="2423528675294333831">"1 ሜባ"</item>
+    <item msgid="180883774509476541">"4 ሜባ"</item>
+    <item msgid="2803199102589126938">"16 ሜባ"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 ኪባ"</item>
-    <item msgid="3534782711045262344">"256 ኪባ"</item>
-    <item msgid="8085867209202153403">"1 ሜባ"</item>
+    <item msgid="6089470720451068364">"ጠፍቷል"</item>
+    <item msgid="4622460333038586791">"64 ኪባ"</item>
+    <item msgid="2212125625169582330">"256 ኪባ"</item>
+    <item msgid="1704946766699242653">"1 ሜባ"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 ኪባ በምዝግብ ማስታወሻ ቋጥ"</item>
-    <item msgid="2822309747675758628">"256 ኪባ በምዝግብ ማስታወሻ ቋጥ"</item>
-    <item msgid="6699306198357496731">"1 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
-    <item msgid="5748528643937500349">"4 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
-    <item msgid="1978629051085111592">"16 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
+    <item msgid="6921048829791179331">"ጠፍቷል"</item>
+    <item msgid="2969458029344750262">"64 ኪባ በምዝግብ ማስታወሻ ቋጥ"</item>
+    <item msgid="1342285115665698168">"256 ኪባ በምዝግብ ማስታወሻ ቋጥ"</item>
+    <item msgid="1314234299552254621">"1 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
+    <item msgid="3606047780792894151">"4 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
+    <item msgid="5431354956856655120">"16 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"እነማ ጠፍቷል"</item>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 1c9b0a9..beac0a1 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"አንጸባራቂ እሴቶች ግምት ውስጥ ሳይገቡ ማንኛውም መተግበሪያ ወደ ውጫዊ ማከማቻ ለመጻፍ ብቁ ያደርጋል።"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"እንቅስቃሴዎች ዳግመኛ እንዲመጣጠኑ አስገድድ"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"የዝርዝር ሰነድ እሴቶች ምንም ይሁኑ ምን ለበርካታ መስኮቶች ሁሉንም እንቅስቃሴዎች ዳግም የሚመጣጠኑ እንዲሆኑ ያደርጋቸዋል።"</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"የነጻ ቅርጽ መስኮቶችን ያንቁ"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"የሙከራ ነጻ ቅርጽ መስኮቶች ድጋፍን ያነቃል።"</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="2731163425081172638">"ለዴስክቶፕ ሙሉ ምትኬዎች የይለፍ ቃል ለመለወጥ ወይም ለማስወገድ ንካ"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"ራስ-ሰር"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<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> በዩኤስቢ ላይ እስከሚሞላ ድረስ"</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="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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"በዩኤስቢ ሃይል በመሙላት ላይ"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"በገመድ አልባ ሃይል በመሙላት ላይ"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-ar/arrays.xml b/packages/SettingsLib/res/values-ar/arrays.xml
index 654759f..60eebeb 100644
--- a/packages/SettingsLib/res/values-ar/arrays.xml
+++ b/packages/SettingsLib/res/values-ar/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"‏استخدام التحقق من HDCP دومًا"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 كيلوبايت"</item>
-    <item msgid="505611754508988476">"256 كيلوبايت"</item>
-    <item msgid="6361286924268716397">"1 ميغابايت"</item>
-    <item msgid="6405203239560695266">"4 ميغابايت"</item>
-    <item msgid="3025431211013424097">"16 ميغابايت"</item>
+    <item msgid="8665206199209698501">"إيقاف"</item>
+    <item msgid="1593289376502312923">"64 كيلوبايت"</item>
+    <item msgid="487545340236145324">"256 كيلوبايت"</item>
+    <item msgid="2423528675294333831">"1 ميغابايت"</item>
+    <item msgid="180883774509476541">"4 ميغابايت"</item>
+    <item msgid="2803199102589126938">"16 ميغابايت"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 كيلوبايت"</item>
-    <item msgid="3534782711045262344">"256 كيلوبايت"</item>
-    <item msgid="8085867209202153403">"1 ميغابايت"</item>
+    <item msgid="6089470720451068364">"إيقاف"</item>
+    <item msgid="4622460333038586791">"64 كيلوبايت"</item>
+    <item msgid="2212125625169582330">"256 كيلوبايت"</item>
+    <item msgid="1704946766699242653">"1 ميغابايت"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 كيلوبايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
-    <item msgid="2822309747675758628">"256 كيلوبايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
-    <item msgid="6699306198357496731">"1 ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
-    <item msgid="5748528643937500349">"4 ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
-    <item msgid="1978629051085111592">"16 ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
+    <item msgid="6921048829791179331">"إيقاف"</item>
+    <item msgid="2969458029344750262">"64 كيلوبايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
+    <item msgid="1342285115665698168">"256 كيلوبايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
+    <item msgid="1314234299552254621">"1 ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
+    <item msgid="3606047780792894151">"4 ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
+    <item msgid="5431354956856655120">"16 ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"إيقاف الرسوم المتحركة"</item>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index fc11a6b..2386cb6 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"تأهيل أي تطبيق بحيث تتم كتابته على سعة تخزين خارجية، بغض النظر عن قيم البيان"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"فرض إمكانية تغيير على الأنشطة"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"لتمكين تغيير حجم جميع الأنشطة لتناسب تعدد النوافذ، بغض النظر عن قيم البيان."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"تمكين النوافذ الحرة"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"لتمكين إتاحة استخدام النوافذ الحرة التجريبية."</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="2731163425081172638">"المس لتغيير كلمة مرور النسخ الاحتياطية الكاملة لسطح المكتب أو إزالتها"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"تلقائيًا"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<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> حتى الاكتمال عبر USB"</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="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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"‏جارٍ الشحن عبر USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"جارٍ الشحن لاسلكيًا"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-az-rAZ/arrays.xml b/packages/SettingsLib/res/values-az-rAZ/arrays.xml
index c58b1c6..682b139 100644
--- a/packages/SettingsLib/res/values-az-rAZ/arrays.xml
+++ b/packages/SettingsLib/res/values-az-rAZ/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Həmişə HDCP yoxlama istifadə edin"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <item msgid="8665206199209698501">"Deaktiv"</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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <item msgid="6089470720451068364">"Deaktiv"</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="7346595473588765019">"hər jurnal buferinə 64K"</item>
-    <item msgid="2822309747675758628">"hər jurnal buferinə 256K"</item>
-    <item msgid="6699306198357496731">"hər jurnal buferinə 1M"</item>
-    <item msgid="5748528643937500349">"hər jurnal buferinə 4M"</item>
-    <item msgid="1978629051085111592">"hər jurnal buferinə 16M"</item>
+    <item msgid="6921048829791179331">"Deaktiv"</item>
+    <item msgid="2969458029344750262">"hər jurnal buferinə 64K"</item>
+    <item msgid="1342285115665698168">"hər jurnal buferinə 256K"</item>
+    <item msgid="1314234299552254621">"hər jurnal buferinə 1M"</item>
+    <item msgid="3606047780792894151">"hər jurnal buferinə 4M"</item>
+    <item msgid="5431354956856655120">"hər jurnal buferinə 16M"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animasiya deaktiv"</item>
diff --git a/packages/SettingsLib/res/values-az-rAZ/strings.xml b/packages/SettingsLib/res/values-az-rAZ/strings.xml
index 4a5ea37..273ea30 100644
--- a/packages/SettingsLib/res/values-az-rAZ/strings.xml
+++ b/packages/SettingsLib/res/values-az-rAZ/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Ölçü dəyişdirmək üçün məcburi fəaliyyətlər"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"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ü edir."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Freeform windows aktiv edin"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Sınaq üçün freeform windows aktiv edir"</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Masaüstü rezerv parolu"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Masaüstü tam rezervlər hazırda qorunmayıblar."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Masaüstünün tam rezevr kopyalanması üçün parolu dəyişmək və ya silmək üçün toxunun"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Avtomatik"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Rəng düzəlişi"</string>
     <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_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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB üzərindən qidalanır"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Naqilsiz qidalanır"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml b/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
index 8bdec32..4715cbf 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Uvek koristi HDCP proveru"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 kB"</item>
-    <item msgid="505611754508988476">"256 kB"</item>
-    <item msgid="6361286924268716397">"1 MB"</item>
-    <item msgid="6405203239560695266">"4 MB"</item>
-    <item msgid="3025431211013424097">"16 MB"</item>
+    <item msgid="8665206199209698501">"Isključeno"</item>
+    <item msgid="1593289376502312923">"64 kB"</item>
+    <item msgid="487545340236145324">"256 kB"</item>
+    <item msgid="2423528675294333831">"1 MB"</item>
+    <item msgid="180883774509476541">"4 MB"</item>
+    <item msgid="2803199102589126938">"16 MB"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 kB"</item>
-    <item msgid="3534782711045262344">"256 kB"</item>
-    <item msgid="8085867209202153403">"1 MB"</item>
+    <item msgid="6089470720451068364">"Isključeno"</item>
+    <item msgid="4622460333038586791">"64 kB"</item>
+    <item msgid="2212125625169582330">"256 kB"</item>
+    <item msgid="1704946766699242653">"1 MB"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 kB po baferu evidencije"</item>
-    <item msgid="2822309747675758628">"256 kB po baferu evidencije"</item>
-    <item msgid="6699306198357496731">"1 MB po baferu evidencije"</item>
-    <item msgid="5748528643937500349">"4 MB po baferu evidencije"</item>
-    <item msgid="1978629051085111592">"16 MB po baferu evidencije"</item>
+    <item msgid="6921048829791179331">"Isključeno"</item>
+    <item msgid="2969458029344750262">"64 kB po međumemoriji evidencije"</item>
+    <item msgid="1342285115665698168">"256 kB po međumemoriji evidencije"</item>
+    <item msgid="1314234299552254621">"1 MB po međumemoriji evidencije"</item>
+    <item msgid="3606047780792894151">"4 MB po međumemoriji evidencije"</item>
+    <item msgid="5431354956856655120">"16 MB po međumemoriji evidencije"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animacija je isključena"</item>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 676c618..4f95052 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Prinudno omogući promenu veličine aktivnosti"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Omogućava 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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Omogućava podršku za eksperimentalne prozore proizvoljnog formata."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Lozinka rezervne kopije za računar"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Rezervne kopije čitavog sistema trenutno nisu zaštićene"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Dodirnite da biste promenili ili uklonili lozinku za pravljenje rezervnih kopija čitavog sistema na računaru"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automatski"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Korekcija boja"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – preostalo oko <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> dok se ne napuni"</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> dok se ne napuni punjačem"</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> dok se ne napuni preko USB-a"</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> dok se ne napuni bežično"</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 preko punjača"</string>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Punjenje preko USB-a"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Bežično 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">"Puno"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-bg/arrays.xml b/packages/SettingsLib/res/values-bg/arrays.xml
index 277800d..42339ef 100644
--- a/packages/SettingsLib/res/values-bg/arrays.xml
+++ b/packages/SettingsLib/res/values-bg/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Винаги да се използва проверка с HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 КБ"</item>
-    <item msgid="505611754508988476">"256 КБ"</item>
-    <item msgid="6361286924268716397">"1 МБ"</item>
-    <item msgid="6405203239560695266">"4 МБ"</item>
-    <item msgid="3025431211013424097">"16 МБ"</item>
+    <item msgid="8665206199209698501">"Изключено"</item>
+    <item msgid="1593289376502312923">"64 КБ"</item>
+    <item msgid="487545340236145324">"256 КБ"</item>
+    <item msgid="2423528675294333831">"1 МБ"</item>
+    <item msgid="180883774509476541">"4 МБ"</item>
+    <item msgid="2803199102589126938">"16 МБ"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 КБ"</item>
-    <item msgid="3534782711045262344">"256 КБ"</item>
-    <item msgid="8085867209202153403">"1 МБ"</item>
+    <item msgid="6089470720451068364">"Изключено"</item>
+    <item msgid="4622460333038586791">"64 КБ"</item>
+    <item msgid="2212125625169582330">"256 КБ"</item>
+    <item msgid="1704946766699242653">"1 МБ"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"Рег. буфер – 64 КБ"</item>
-    <item msgid="2822309747675758628">"Рег. буфер – 256 КБ"</item>
-    <item msgid="6699306198357496731">"Рег. буфер – 1 МБ"</item>
-    <item msgid="5748528643937500349">"Рег. буфер – 4 МБ"</item>
-    <item msgid="1978629051085111592">"Рег. буфер – 16 МБ"</item>
+    <item msgid="6921048829791179331">"Изключено"</item>
+    <item msgid="2969458029344750262">"Рег. буфер – 64 КБ"</item>
+    <item msgid="1342285115665698168">"Рег. буфер – 256 КБ"</item>
+    <item msgid="1314234299552254621">"Рег. буфер – 1 МБ"</item>
+    <item msgid="3606047780792894151">"Рег. буфер – 4 МБ"</item>
+    <item msgid="5431354956856655120">"Рег. буфер – 16 МБ"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Анимацията е изключена"</item>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 8180261..74c58a5 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Позволява прилож. да се записват във външ. хранил. независимо от стойностите в манифеста"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Възможност за преоразмеряване на активностите"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Дава възможност за преоразмеряване на всички активности в режима за няколко прозореца независимо от стойностите в манифеста."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Активиране на прозорците в свободна форма"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Активира поддръжката за експерименталните прозорци в свободна форма."</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="2731163425081172638">"Докоснете, за да промените или премахнете паролата за пълни резервни копия на настолния компютър"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Автоматично"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<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> до пълно зареждане през USB"</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="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_usb" msgid="2207489369680923929">"Зареждане през USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Безжично зареждане"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-bn-rBD/arrays.xml b/packages/SettingsLib/res/values-bn-rBD/arrays.xml
index 7729a4d..b863934 100644
--- a/packages/SettingsLib/res/values-bn-rBD/arrays.xml
+++ b/packages/SettingsLib/res/values-bn-rBD/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"সর্বদা HDCP পরীক্ষণ ব্যবহার করুন"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"৬৪০০০"</item>
-    <item msgid="505611754508988476">"২৫৬০০০"</item>
-    <item msgid="6361286924268716397">"১০০০০০০"</item>
-    <item msgid="6405203239560695266">"৪০০০০০০"</item>
-    <item msgid="3025431211013424097">"১৬০০০০০০"</item>
+    <item msgid="8665206199209698501">"বন্ধ আছে"</item>
+    <item msgid="1593289376502312923">"৬৪K"</item>
+    <item msgid="487545340236145324">"২৫৬K"</item>
+    <item msgid="2423528675294333831">"১M"</item>
+    <item msgid="180883774509476541">"৪M"</item>
+    <item msgid="2803199102589126938">"১৬M"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"৬৪০০০"</item>
-    <item msgid="3534782711045262344">"২৫৬০০০"</item>
-    <item msgid="8085867209202153403">"১০০০০০০"</item>
+    <item msgid="6089470720451068364">"বন্ধ আছে"</item>
+    <item msgid="4622460333038586791">"৬৪K"</item>
+    <item msgid="2212125625169582330">"২৫৬K"</item>
+    <item msgid="1704946766699242653">"১M"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"লগ বাফার প্রতি 64K"</item>
-    <item msgid="2822309747675758628">"লগ বাফার প্রতি 256K"</item>
-    <item msgid="6699306198357496731">"লগ বাফার প্রতি 1M"</item>
-    <item msgid="5748528643937500349">"লগ বাফার প্রতি 4M"</item>
-    <item msgid="1978629051085111592">"লগ বাফার প্রতি 16M"</item>
+    <item msgid="6921048829791179331">"বন্ধ আছে"</item>
+    <item msgid="2969458029344750262">"লগ বাফার প্রতি ৬৪K"</item>
+    <item msgid="1342285115665698168">"লগ বাফার প্রতি ২৫৬K"</item>
+    <item msgid="1314234299552254621">"লগ বাফার প্রতি ১M"</item>
+    <item msgid="3606047780792894151">"লগ বাফার প্রতি ৪M"</item>
+    <item msgid="5431354956856655120">"লগ বাফার প্রতি ১৬M"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"অ্যানিমেশন বন্ধ করুন"</item>
diff --git a/packages/SettingsLib/res/values-bn-rBD/strings.xml b/packages/SettingsLib/res/values-bn-rBD/strings.xml
index 0e77871..9e42f71 100644
--- a/packages/SettingsLib/res/values-bn-rBD/strings.xml
+++ b/packages/SettingsLib/res/values-bn-rBD/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ম্যানিফেস্ট মানগুলি নির্বিশেষে যেকোনো অ্যাপ্লিকেশানকে বাহ্যিক সঞ্চয়স্থানে লেখার উপযুক্ত বানায়"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"আকার পরিবর্তনযোগ্য করার জন্য ক্রিয়াকলাপগুলিকে জোর করুন"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ম্যানিফেস্ট মানগুলির নির্বিশেষে মাল্টি-উইন্ডোর জন্য সমস্ত ক্রিয়াকলাপগুলিকে আকার পরিবর্তনযোগ্য করে তোলে৷"</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"ফ্রি-ফর্ম উইন্ডোগুলি সক্ষম করুন"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"পরীক্ষামূলক ফ্রি-ফর্ম উইন্ডোগুলির জন্য সহায়তা সক্ষম করুন৷"</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="2731163425081172638">"ডেস্কটপ পুরো ব্যাকআপের জন্য পাসওয়ার্ড পরিবর্তন বা মুছে ফেলার জন্য স্পর্শ করুন"</string>
@@ -273,8 +275,9 @@
     <string name="night_mode_no" msgid="9171772244775838901">"অক্ষম করা রয়েছে"</string>
     <string name="night_mode_yes" msgid="2218157265997633432">"সবসময় চালু"</string>
     <string name="night_mode_auto" msgid="7508348175804304327">"স্বয়ংক্রিয়"</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_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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_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_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_wireless" msgid="1829295708243159464">"<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_usb" msgid="2207489369680923929">"USB এর মাধ্যমে চার্জ হচ্ছে"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"তারবিহীনভাবে চার্জ হচ্ছে"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-ca/arrays.xml b/packages/SettingsLib/res/values-ca/arrays.xml
index ab80ccc..99c8a27 100644
--- a/packages/SettingsLib/res/values-ca/arrays.xml
+++ b/packages/SettingsLib/res/values-ca/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Utilitza sempre la comprovació HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 K"</item>
-    <item msgid="505611754508988476">"256 K"</item>
-    <item msgid="6361286924268716397">"1 M"</item>
-    <item msgid="6405203239560695266">"4 M"</item>
-    <item msgid="3025431211013424097">"16 M"</item>
+    <item msgid="8665206199209698501">"No"</item>
+    <item msgid="1593289376502312923">"64 K"</item>
+    <item msgid="487545340236145324">"256 K"</item>
+    <item msgid="2423528675294333831">"1 M"</item>
+    <item msgid="180883774509476541">"4 M"</item>
+    <item msgid="2803199102589126938">"16 M"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64.000"</item>
-    <item msgid="3534782711045262344">"256.000"</item>
-    <item msgid="8085867209202153403">"1.000.000"</item>
+    <item msgid="6089470720451068364">"No"</item>
+    <item msgid="4622460333038586791">"64 K"</item>
+    <item msgid="2212125625169582330">"256 K"</item>
+    <item msgid="1704946766699242653">"1 M"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 K/memòria intermèdia reg."</item>
-    <item msgid="2822309747675758628">"256 K/memòria intermèdia reg."</item>
-    <item msgid="6699306198357496731">"1 M/memòria intermèdia reg."</item>
-    <item msgid="5748528643937500349">"4 M/memòria intermèdia reg."</item>
-    <item msgid="1978629051085111592">"16 M/memòria intermèdia reg."</item>
+    <item msgid="6921048829791179331">"No"</item>
+    <item msgid="2969458029344750262">"64 K / memòria intermèdia reg."</item>
+    <item msgid="1342285115665698168">"256 K / memòria intermèdia reg."</item>
+    <item msgid="1314234299552254621">"1 M / memòria intermèdia reg."</item>
+    <item msgid="3606047780792894151">"4 M / memòria intermèdia reg."</item>
+    <item msgid="5431354956856655120">"16 M / memòria intermèdia reg."</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animació desactivada"</item>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 8553ed9..2f81098 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Força l\'ajust de la mida de les activitats"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Activa la compatibilitat amb les finestres de format lliure experimentals."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Contrasenya per a còpies d\'ordinador"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Les còpies de seguretat d\'ordinador completes no estan protegides"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toca per canviar o eliminar la contrasenya per a còpies de seguretat d\'ordinador completes"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automàtic"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Correcció del color"</string>
     <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_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_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_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_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_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="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_usb" msgid="2207489369680923929">"Càrrega per USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Càrrega sense fils"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-cs/arrays.xml b/packages/SettingsLib/res/values-cs/arrays.xml
index d46781a..8953485 100644
--- a/packages/SettingsLib/res/values-cs/arrays.xml
+++ b/packages/SettingsLib/res/values-cs/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Vždy používat kontrolu HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 kB"</item>
-    <item msgid="505611754508988476">"256 kB"</item>
-    <item msgid="6361286924268716397">"1 MB"</item>
-    <item msgid="6405203239560695266">"4 MB"</item>
-    <item msgid="3025431211013424097">"16 MB"</item>
+    <item msgid="8665206199209698501">"Vypnuto"</item>
+    <item msgid="1593289376502312923">"64 kB"</item>
+    <item msgid="487545340236145324">"256 kB"</item>
+    <item msgid="2423528675294333831">"1 MB"</item>
+    <item msgid="180883774509476541">"4 MB"</item>
+    <item msgid="2803199102589126938">"16 MB"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 kB"</item>
-    <item msgid="3534782711045262344">"256 kB"</item>
-    <item msgid="8085867209202153403">"1 MB"</item>
+    <item msgid="6089470720451068364">"Vypnuto"</item>
+    <item msgid="4622460333038586791">"64 kB"</item>
+    <item msgid="2212125625169582330">"256 kB"</item>
+    <item msgid="1704946766699242653">"1 MB"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 kB na vyrovnávací paměť protokolů"</item>
-    <item msgid="2822309747675758628">"256 kB na vyrovnávací paměť protokolů"</item>
-    <item msgid="6699306198357496731">"1 MB na vyrovnávací paměť protokolů"</item>
-    <item msgid="5748528643937500349">"4 MB na vyrovnávací paměť protokolů"</item>
-    <item msgid="1978629051085111592">"16 MB na vyrovnávací paměť protokolů"</item>
+    <item msgid="6921048829791179331">"Vypnuto"</item>
+    <item msgid="2969458029344750262">"64 kB na vyrovnávací paměť protokolů"</item>
+    <item msgid="1342285115665698168">"256 kB na vyrovnávací paměť protokolů"</item>
+    <item msgid="1314234299552254621">"1 MB na vyrovnávací paměť protokolů"</item>
+    <item msgid="3606047780792894151">"4 MB na vyrovnávací paměť protokolů"</item>
+    <item msgid="5431354956856655120">"16 MB na vyrovnávací paměť protokolů"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animace je vypnuta"</item>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 495f10f..f1c9e27 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Vynutit možnost změny velikosti aktivit"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Velikost všech aktivit bude možné změnit na několik oken (bez ohledu na hodnoty manifestu)."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Aktivovat okna s volným tvarem"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktivuje podporu experimentálních oken s volným tvarem."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Heslo pro zálohy v počítači"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Úplné zálohy v počítači nejsou v současné době chráněny"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Tuto možnost vyberte, chcete-li změnit nebo odebrat heslo pro úplné zálohy v počítači"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automatický"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Korekce barev"</string>
     <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_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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Nabíjení přes USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Bezdrátové nabíjení"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-da/arrays.xml b/packages/SettingsLib/res/values-da/arrays.xml
index 2935489..d700c05 100644
--- a/packages/SettingsLib/res/values-da/arrays.xml
+++ b/packages/SettingsLib/res/values-da/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Brug altid HDCP-kontrol"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 KB"</item>
-    <item msgid="505611754508988476">"256 KB"</item>
-    <item msgid="6361286924268716397">"1 MB"</item>
-    <item msgid="6405203239560695266">"4 MB"</item>
-    <item msgid="3025431211013424097">"16 MB"</item>
+    <item msgid="8665206199209698501">"Fra"</item>
+    <item msgid="1593289376502312923">"64 kB"</item>
+    <item msgid="487545340236145324">"256 kB"</item>
+    <item msgid="2423528675294333831">"1 MB"</item>
+    <item msgid="180883774509476541">"4 MB"</item>
+    <item msgid="2803199102589126938">"16 MB"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 kB"</item>
-    <item msgid="3534782711045262344">"256 kB"</item>
-    <item msgid="8085867209202153403">"1 MB"</item>
+    <item msgid="6089470720451068364">"Fra"</item>
+    <item msgid="4622460333038586791">"64 kB"</item>
+    <item msgid="2212125625169582330">"256 kB"</item>
+    <item msgid="1704946766699242653">"1 MB"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 KB pr. logbuffer"</item>
-    <item msgid="2822309747675758628">"256 KB pr. logbuffer"</item>
-    <item msgid="6699306198357496731">"1 MB pr. logbuffer"</item>
-    <item msgid="5748528643937500349">"4 MB pr. logbuffer"</item>
-    <item msgid="1978629051085111592">"16 MB pr. logbuffer"</item>
+    <item msgid="6921048829791179331">"Fra"</item>
+    <item msgid="2969458029344750262">"64 kB pr. logbuffer"</item>
+    <item msgid="1342285115665698168">"256 kB pr. logbuffer"</item>
+    <item msgid="1314234299552254621">"1 MB pr. logbuffer"</item>
+    <item msgid="3606047780792894151">"4 MB pr. logbuffer"</item>
+    <item msgid="5431354956856655120">"16 MB pr. logbuffer"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animation fra"</item>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 82654bc..90ea69a 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Tving aktiviteter til at kunne tilpasses"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Sørger for, 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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktiverer understøttelse af eksperimentelle vinduer i frit format."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Kode til lokal sikkerhedskopi"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Lokale fuldstændige sikkerhedskopieringer er i øjeblikket ikke beskyttet"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Tryk for at skifte eller fjerne adgangskoden til fuld lokal sikkerhedskopiering"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automatisk"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Korriger farver"</string>
     <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_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_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_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_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_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="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_usb" msgid="2207489369680923929">"Opladning via USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Trådløs opladning"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-de/arrays.xml b/packages/SettingsLib/res/values-de/arrays.xml
index d2a7f0d..a9c802d 100644
--- a/packages/SettingsLib/res/values-de/arrays.xml
+++ b/packages/SettingsLib/res/values-de/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"HDCP-Prüfung immer verwenden"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64.000"</item>
-    <item msgid="505611754508988476">"256.000"</item>
-    <item msgid="6361286924268716397">"1 Mio."</item>
-    <item msgid="6405203239560695266">"4 Mio."</item>
-    <item msgid="3025431211013424097">"16 Mio."</item>
+    <item msgid="8665206199209698501">"Aus"</item>
+    <item msgid="1593289376502312923">"64.000"</item>
+    <item msgid="487545340236145324">"256.000"</item>
+    <item msgid="2423528675294333831">"1 Mio."</item>
+    <item msgid="180883774509476541">"4 Mio."</item>
+    <item msgid="2803199102589126938">"16 Mio."</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64.000"</item>
-    <item msgid="3534782711045262344">"256.000"</item>
-    <item msgid="8085867209202153403">"1 Mio."</item>
+    <item msgid="6089470720451068364">"Aus"</item>
+    <item msgid="4622460333038586791">"64.000"</item>
+    <item msgid="2212125625169582330">"256.000"</item>
+    <item msgid="1704946766699242653">"1 Mio."</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64.000 pro Puffer"</item>
-    <item msgid="2822309747675758628">"256.000 pro Puffer"</item>
-    <item msgid="6699306198357496731">"1 Mio. pro Puffer"</item>
-    <item msgid="5748528643937500349">"4 Mio. pro Puffer"</item>
-    <item msgid="1978629051085111592">"16 Mio. pro Puffer"</item>
+    <item msgid="6921048829791179331">"Aus"</item>
+    <item msgid="2969458029344750262">"64.000 pro Puffer"</item>
+    <item msgid="1342285115665698168">"256.000 pro Puffer"</item>
+    <item msgid="1314234299552254621">"1 Mio. pro Puffer"</item>
+    <item msgid="3606047780792894151">"4 Mio. pro Puffer"</item>
+    <item msgid="5431354956856655120">"16 Mio. pro Puffer"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animation aus"</item>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index a2f750b..f768dc3 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -72,7 +72,7 @@
     <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Pairing durchführen"</string>
     <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"Pairing durchführen"</string>
     <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Abbrechen"</string>
-    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Über das Pairing kann auf Ihre Kontakte und auf Ihren Anrufverlauf zugegriffen werden, wenn eine Verbindung besteht."</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Über das Pairing kann auf deine Kontakte und auf deinen Anrufverlauf zugegriffen werden, wenn eine Verbindung besteht."</string>
     <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Pairing mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> war nicht möglich."</string>
     <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Pairing mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> war nicht möglich, weil die eingegebene PIN oder der Zugangscode falsch ist."</string>
     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Kommunikation mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ist nicht möglich."</string>
@@ -109,7 +109,7 @@
     <string name="tts_play_example_summary" msgid="8029071615047894486">"Kurzes Beispiel der Sprachsynthese abspielen"</string>
     <string name="tts_install_data_title" msgid="4264378440508149986">"Sprachdaten installieren"</string>
     <string name="tts_install_data_summary" msgid="5742135732511822589">"Sprachdaten für Sprachsynthese installieren"</string>
-    <string name="tts_engine_security_warning" msgid="8786238102020223650">"Dieses Sprachsynthesemodul kann den gesamten gesprochenen Text erfassen, einschließlich personenbezogener Daten wie Passwörter und Kreditkartennummern. Es ist Teil der App \"<xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>\". Möchten Sie dieses Sprachsynthesemodul aktivieren?"</string>
+    <string name="tts_engine_security_warning" msgid="8786238102020223650">"Dieses Sprachsynthesemodul kann den gesamten gesprochenen Text erfassen, einschließlich personenbezogener Daten wie Passwörter und Kreditkartennummern. Es ist Teil der App \"<xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>\". Möchtest du dieses Sprachsynthesemodul aktivieren?"</string>
     <string name="tts_engine_network_required" msgid="1190837151485314743">"Für diese Sprache ist zur Text-in-Sprache-Ausgabe eine aktive Netzwerkverbindung erforderlich."</string>
     <string name="tts_default_sample_string" msgid="4040835213373086322">"Dies ist ein Beispiel für Sprachsynthese."</string>
     <string name="tts_status_title" msgid="7268566550242584413">"Status der Standardsprache"</string>
@@ -179,10 +179,10 @@
     <string name="legacy_dhcp_client_summary" msgid="163383566317652040">"DHCP-Client von Lollipop statt des neuen Android-DHCP-Clients verwenden"</string>
     <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Die mobile Datennutzung bleibt auch dann aktiviert, wenn WLAN aktiviert ist. Dies dient einem schnelleren Wechsel zwischen Netzwerken."</string>
     <string name="adb_warning_title" msgid="6234463310896563253">"USB-Debugging zulassen?"</string>
-    <string name="adb_warning_message" msgid="7316799925425402244">"USB-Debugging ist nur für Entwicklungszwecke vorgesehen. Damit können Sie Daten zwischen Ihrem Computer und Ihrem Gerät kopieren, Apps auf Ihrem Gerät ohne Benachrichtigung installieren und Protokolldaten lesen."</string>
+    <string name="adb_warning_message" msgid="7316799925425402244">"USB-Debugging ist nur für Entwicklungszwecke vorgesehen. Damit kannst du Daten zwischen deinem Computer und deinem Gerät kopieren, Apps auf deinem Gerät ohne Benachrichtigung installieren und Protokolldaten lesen."</string>
     <string name="adb_keys_warning_message" msgid="5659849457135841625">"Zugriff auf USB-Debugging für alle zuvor autorisierten Computer aufheben?"</string>
     <string name="dev_settings_warning_title" msgid="7244607768088540165">"Entwicklungseinstellungen zulassen?"</string>
-    <string name="dev_settings_warning_message" msgid="2298337781139097964">"Diese Einstellungen sind ausschließlich für Entwicklungszwecke geeignet. Sie können Ihr Gerät und die darauf installierten Apps beschädigen oder zu unerwünschtem Verhalten führen."</string>
+    <string name="dev_settings_warning_message" msgid="2298337781139097964">"Diese Einstellungen sind ausschließlich für Entwicklungszwecke gedacht. Sie können dein Gerät und die darauf installierten Apps beschädigen oder zu unerwünschtem Verhalten führen."</string>
     <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Apps über USB bestätigen"</string>
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Überprüft installierte Apps über ADB/ADT auf schädliches Verhalten"</string>
     <string name="enable_terminal_title" msgid="95572094356054120">"Lokales Terminal"</string>
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Anpassen der Größe von Aktivitäten erzwingen"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Ermöglicht es, die Größe aller Aktivitäten an den Mehrfenstermodus anzupassen, unabhängig von den Manifestwerten."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Freiform-Fenster zulassen"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Unterstützt experimentelle Freiform-Fenster."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Desktop-Sicherungspasswort"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Vollständige Desktop-Sicherungen sind momentan nicht passwortgeschützt."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Zum Ändern oder Entfernen des Passworts für vollständige Desktop-Sicherungen berühren"</string>
@@ -275,11 +277,12 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automatisch"</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="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>
     <string name="title_convert_fbe" msgid="1263622876196444453">"Zu Dateiverschlüsselung wechseln"</string>
-    <string name="convert_to_fbe_warning" msgid="6139067817148865527">"Wechseln Sie von Datenpartitions- zu dateibasierter Verschlüsselung.\n !!Achtung!! Dadurch werden alle Ihre Daten gelöscht.\n Es handelt sich um eine Alphaversion, die möglicherweise nicht korrekt funktioniert.\n Wählen Sie \"Wischen und wechseln…\" aus, um fortzufahren."</string>
+    <string name="convert_to_fbe_warning" msgid="6139067817148865527">"Stelle von Datenpartitions- auf dateibasierte Verschlüsselung um.\n !!Achtung!! Dadurch werden alle deine Daten gelöscht.\n Es handelt sich um eine Alphaversion, die möglicherweise nicht korrekt funktioniert.\n Wähle \"Wischen und wechseln…\" aus, um fortzufahren."</string>
     <string name="button_convert_fbe" msgid="5152671181309826405">"Wischen und wechseln…"</string>
     <string name="picture_color_mode" msgid="4560755008730283695">"Farbmodus für Bilder"</string>
     <string name="picture_color_mode_desc" msgid="1141891467675548590">"sRGB verwenden"</string>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Farbkorrektur"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – noch etwa <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> – voll in <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> – bei Stromanschluss voll in <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> – über USB voll in <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> – bei kabellosem Laden voll in <xliff:g id="TIME">%2$s</xliff:g>"</string>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Laden über USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Kabelloses Laden"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-el/arrays.xml b/packages/SettingsLib/res/values-el/arrays.xml
index 2672eec..91f9d6a 100644
--- a/packages/SettingsLib/res/values-el/arrays.xml
+++ b/packages/SettingsLib/res/values-el/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Να χρησιμοποιείται πάντα έλεγχος HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 K"</item>
-    <item msgid="505611754508988476">"256 K"</item>
-    <item msgid="6361286924268716397">"1 M"</item>
-    <item msgid="6405203239560695266">"4 M"</item>
-    <item msgid="3025431211013424097">"16 M"</item>
+    <item msgid="8665206199209698501">"Ανενεργό"</item>
+    <item msgid="1593289376502312923">"64 K"</item>
+    <item msgid="487545340236145324">"256 K"</item>
+    <item msgid="2423528675294333831">"1 M"</item>
+    <item msgid="180883774509476541">"4 M"</item>
+    <item msgid="2803199102589126938">"16 M"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 K"</item>
-    <item msgid="3534782711045262344">"256 K"</item>
-    <item msgid="8085867209202153403">"1 M"</item>
+    <item msgid="6089470720451068364">"Ανενεργό"</item>
+    <item msgid="4622460333038586791">"64 K"</item>
+    <item msgid="2212125625169582330">"256 K"</item>
+    <item msgid="1704946766699242653">"1 M"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 K ανά μεγ.πρ.μν.καταγρ."</item>
-    <item msgid="2822309747675758628">"256 K ανά μεγ.πρ.μν.καταγρ."</item>
-    <item msgid="6699306198357496731">"1 Μ ανά μεγ.πρ.μν.καταγρ."</item>
-    <item msgid="5748528643937500349">"4 M ανά μεγ.πρ.μν.καταγρ."</item>
-    <item msgid="1978629051085111592">"16 M ανά μεγ.πρ.μν.καταγρ."</item>
+    <item msgid="6921048829791179331">"Ανενεργό"</item>
+    <item msgid="2969458029344750262">"64 K ανά πρ. μν. αρχ. καταγρ."</item>
+    <item msgid="1342285115665698168">"256 K ανά πρ. μν. αρχ. καταγρ."</item>
+    <item msgid="1314234299552254621">"1 Μ ανά προσ. μν. αρχ. καταγρ."</item>
+    <item msgid="3606047780792894151">"4 M ανά προσ. μν. αρχ. καταγρ."</item>
+    <item msgid="5431354956856655120">"16 M ανά πρ. μν. αρχ. καταγρ."</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Κινούμ.εικόνες απενεργοποιημένες"</item>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index d426616..dddd780 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Κάνει κάθε εφαρμογή κατάλληλη για εγγραφή σε εξωτερικό χώρο αποθήκευσης, ανεξάρτητα από τις τιμές του μανιφέστου"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Αναγκαστική δυνατότητα αλλαγής μεγέθους δραστηριοτήτων"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Να έχουν όλες οι δραστηριότητες δυνατότητα αλλαγής μεγέθους για την προβολή πολλαπλών παραθύρων, ανεξάρτητα από τις τιμές του μανιφέστου."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Ενεργοποίηση παραθύρων ελεύθερης μορφής"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ενεργοποιεί την υποστήριξη για πειραματικά παράθυρα ελεύθερης μορφής."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Εφ/κός κωδικός desktop"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Τα πλήρη αντίγραφα ασφαλείας επιφάνειας εργασίας δεν προστατεύονται αυτήν τη στιγμή"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Αγγίξτε για αλλαγή ή κατάργηση του κωδικού πρόσβασης για τα πλήρη αντίγραφα ασφαλείας επιφάνειας εργασίας"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Αυτόματο"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> για πλήρη φόρτιση με φορτιστή AC"</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> για πλήρη φόρτιση μέσω USB"</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="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_usb" msgid="2207489369680923929">"Φόρτιση μέσω USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Ασύρματη φόρτιση"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/arrays.xml b/packages/SettingsLib/res/values-en-rAU/arrays.xml
index 21340d8..05518900 100644
--- a/packages/SettingsLib/res/values-en-rAU/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rAU/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Always use HDCP checking"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 K"</item>
-    <item msgid="505611754508988476">"256 K"</item>
-    <item msgid="6361286924268716397">"1 M"</item>
-    <item msgid="6405203239560695266">"4 M"</item>
-    <item msgid="3025431211013424097">"16 M"</item>
+    <item msgid="8665206199209698501">"Off"</item>
+    <item msgid="1593289376502312923">"64 K"</item>
+    <item msgid="487545340236145324">"256 K"</item>
+    <item msgid="2423528675294333831">"1 M"</item>
+    <item msgid="180883774509476541">"4 M"</item>
+    <item msgid="2803199102589126938">"16 M"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 K"</item>
-    <item msgid="3534782711045262344">"256 K"</item>
-    <item msgid="8085867209202153403">"1 M"</item>
+    <item msgid="6089470720451068364">"Off"</item>
+    <item msgid="4622460333038586791">"64 K"</item>
+    <item msgid="2212125625169582330">"256 K"</item>
+    <item msgid="1704946766699242653">"1 M"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 K per log buffer"</item>
-    <item msgid="2822309747675758628">"256 K per log buffer"</item>
-    <item msgid="6699306198357496731">"1 M per log buffer"</item>
-    <item msgid="5748528643937500349">"4 M per log buffer"</item>
-    <item msgid="1978629051085111592">"16 M per log buffer"</item>
+    <item msgid="6921048829791179331">"Off"</item>
+    <item msgid="2969458029344750262">"64 K per log buffer"</item>
+    <item msgid="1342285115665698168">"256 K per log buffer"</item>
+    <item msgid="1314234299552254621">"1 M per log buffer"</item>
+    <item msgid="3606047780792894151">"4 M per log buffer"</item>
+    <item msgid="5431354956856655120">"16 M per log buffer"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animation off"</item>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index b8c8521..b938ace 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Force activities to be re-sizable"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Makes all activities re-sizable for multi-window, regardless of manifest values."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Enable freeform windows"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Enables support for experimental freeform windows."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Desktop backup password"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Desktop full backups aren\'t currently protected"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Touch to change or remove the password for desktop full backups"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automatic"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Colour correction"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – approx. <xliff:g id="TIME">%2$s</xliff:g> left"</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> until full"</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> until full on AC"</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> until full over USB"</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> until full from wireless"</string>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Charging over USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Charging wirelessly"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/arrays.xml b/packages/SettingsLib/res/values-en-rGB/arrays.xml
index 21340d8..05518900 100644
--- a/packages/SettingsLib/res/values-en-rGB/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rGB/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Always use HDCP checking"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 K"</item>
-    <item msgid="505611754508988476">"256 K"</item>
-    <item msgid="6361286924268716397">"1 M"</item>
-    <item msgid="6405203239560695266">"4 M"</item>
-    <item msgid="3025431211013424097">"16 M"</item>
+    <item msgid="8665206199209698501">"Off"</item>
+    <item msgid="1593289376502312923">"64 K"</item>
+    <item msgid="487545340236145324">"256 K"</item>
+    <item msgid="2423528675294333831">"1 M"</item>
+    <item msgid="180883774509476541">"4 M"</item>
+    <item msgid="2803199102589126938">"16 M"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 K"</item>
-    <item msgid="3534782711045262344">"256 K"</item>
-    <item msgid="8085867209202153403">"1 M"</item>
+    <item msgid="6089470720451068364">"Off"</item>
+    <item msgid="4622460333038586791">"64 K"</item>
+    <item msgid="2212125625169582330">"256 K"</item>
+    <item msgid="1704946766699242653">"1 M"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 K per log buffer"</item>
-    <item msgid="2822309747675758628">"256 K per log buffer"</item>
-    <item msgid="6699306198357496731">"1 M per log buffer"</item>
-    <item msgid="5748528643937500349">"4 M per log buffer"</item>
-    <item msgid="1978629051085111592">"16 M per log buffer"</item>
+    <item msgid="6921048829791179331">"Off"</item>
+    <item msgid="2969458029344750262">"64 K per log buffer"</item>
+    <item msgid="1342285115665698168">"256 K per log buffer"</item>
+    <item msgid="1314234299552254621">"1 M per log buffer"</item>
+    <item msgid="3606047780792894151">"4 M per log buffer"</item>
+    <item msgid="5431354956856655120">"16 M per log buffer"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animation off"</item>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index b8c8521..b938ace 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Force activities to be re-sizable"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Makes all activities re-sizable for multi-window, regardless of manifest values."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Enable freeform windows"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Enables support for experimental freeform windows."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Desktop backup password"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Desktop full backups aren\'t currently protected"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Touch to change or remove the password for desktop full backups"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automatic"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Colour correction"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – approx. <xliff:g id="TIME">%2$s</xliff:g> left"</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> until full"</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> until full on AC"</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> until full over USB"</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> until full from wireless"</string>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Charging over USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Charging wirelessly"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/arrays.xml b/packages/SettingsLib/res/values-en-rIN/arrays.xml
index 21340d8..05518900 100644
--- a/packages/SettingsLib/res/values-en-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rIN/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Always use HDCP checking"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 K"</item>
-    <item msgid="505611754508988476">"256 K"</item>
-    <item msgid="6361286924268716397">"1 M"</item>
-    <item msgid="6405203239560695266">"4 M"</item>
-    <item msgid="3025431211013424097">"16 M"</item>
+    <item msgid="8665206199209698501">"Off"</item>
+    <item msgid="1593289376502312923">"64 K"</item>
+    <item msgid="487545340236145324">"256 K"</item>
+    <item msgid="2423528675294333831">"1 M"</item>
+    <item msgid="180883774509476541">"4 M"</item>
+    <item msgid="2803199102589126938">"16 M"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 K"</item>
-    <item msgid="3534782711045262344">"256 K"</item>
-    <item msgid="8085867209202153403">"1 M"</item>
+    <item msgid="6089470720451068364">"Off"</item>
+    <item msgid="4622460333038586791">"64 K"</item>
+    <item msgid="2212125625169582330">"256 K"</item>
+    <item msgid="1704946766699242653">"1 M"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 K per log buffer"</item>
-    <item msgid="2822309747675758628">"256 K per log buffer"</item>
-    <item msgid="6699306198357496731">"1 M per log buffer"</item>
-    <item msgid="5748528643937500349">"4 M per log buffer"</item>
-    <item msgid="1978629051085111592">"16 M per log buffer"</item>
+    <item msgid="6921048829791179331">"Off"</item>
+    <item msgid="2969458029344750262">"64 K per log buffer"</item>
+    <item msgid="1342285115665698168">"256 K per log buffer"</item>
+    <item msgid="1314234299552254621">"1 M per log buffer"</item>
+    <item msgid="3606047780792894151">"4 M per log buffer"</item>
+    <item msgid="5431354956856655120">"16 M per log buffer"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animation off"</item>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index b8c8521..b938ace 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Force activities to be re-sizable"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Makes all activities re-sizable for multi-window, regardless of manifest values."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Enable freeform windows"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Enables support for experimental freeform windows."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Desktop backup password"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Desktop full backups aren\'t currently protected"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Touch to change or remove the password for desktop full backups"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automatic"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Colour correction"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – approx. <xliff:g id="TIME">%2$s</xliff:g> left"</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> until full"</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> until full on AC"</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> until full over USB"</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> until full from wireless"</string>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Charging over USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Charging wirelessly"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/arrays.xml b/packages/SettingsLib/res/values-es-rUS/arrays.xml
index 52992d5..1b7a9f0 100644
--- a/packages/SettingsLib/res/values-es-rUS/arrays.xml
+++ b/packages/SettingsLib/res/values-es-rUS/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Siempre utilizar comprobación HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 K"</item>
-    <item msgid="505611754508988476">"256 K"</item>
-    <item msgid="6361286924268716397">"1 M"</item>
-    <item msgid="6405203239560695266">"4 M"</item>
-    <item msgid="3025431211013424097">"16 M"</item>
+    <item msgid="8665206199209698501">"Desactivado"</item>
+    <item msgid="1593289376502312923">"64 K"</item>
+    <item msgid="487545340236145324">"256 K"</item>
+    <item msgid="2423528675294333831">"1 M"</item>
+    <item msgid="180883774509476541">"4 M"</item>
+    <item msgid="2803199102589126938">"16 M"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 K"</item>
-    <item msgid="3534782711045262344">"256 K"</item>
-    <item msgid="8085867209202153403">"1 M"</item>
+    <item msgid="6089470720451068364">"Desactivado"</item>
+    <item msgid="4622460333038586791">"64 K"</item>
+    <item msgid="2212125625169582330">"256 K"</item>
+    <item msgid="1704946766699242653">"1 M"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 K/búfer registro"</item>
-    <item msgid="2822309747675758628">"256 K/búfer registro"</item>
-    <item msgid="6699306198357496731">"1 M/búfer registro"</item>
-    <item msgid="5748528643937500349">"4 M/búfer registro"</item>
-    <item msgid="1978629051085111592">"16 M/búfer registro"</item>
+    <item msgid="6921048829791179331">"Desactivado"</item>
+    <item msgid="2969458029344750262">"64 K/búfer registro"</item>
+    <item msgid="1342285115665698168">"256 K/búfer registro"</item>
+    <item msgid="1314234299552254621">"1 M/búfer registro"</item>
+    <item msgid="3606047780792894151">"4 M/búfer registro"</item>
+    <item msgid="5431354956856655120">"16 M/búfer registro"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animación desactivada"</item>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 34ebef4..ea97ada 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Forzar actividades para que cambien de tamaño"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permite 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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Habilita la admisión de ventanas de forma libre experimentales."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Contraseñas"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Tus copias de seguridad de escritorio no están protegidas por contraseña."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toca para cambiar o eliminar la contraseña de las copias de seguridad completas de tu escritorio."</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automático"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Corrección de color"</string>
     <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_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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Carga con USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Carga inalámbrica"</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 realiza la carga"</string>
+    <string name="battery_info_status_full" msgid="2824614753861462808">"Cargado"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-es/arrays.xml b/packages/SettingsLib/res/values-es/arrays.xml
index 0493217..e4b661e 100644
--- a/packages/SettingsLib/res/values-es/arrays.xml
+++ b/packages/SettingsLib/res/values-es/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Utilizar siempre comprobación de HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 K"</item>
-    <item msgid="505611754508988476">"256 K"</item>
-    <item msgid="6361286924268716397">"1 M"</item>
-    <item msgid="6405203239560695266">"4 M"</item>
-    <item msgid="3025431211013424097">"16 M"</item>
+    <item msgid="8665206199209698501">"No"</item>
+    <item msgid="1593289376502312923">"64 K"</item>
+    <item msgid="487545340236145324">"256 K"</item>
+    <item msgid="2423528675294333831">"1 M"</item>
+    <item msgid="180883774509476541">"4 M"</item>
+    <item msgid="2803199102589126938">"16 M"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 K"</item>
-    <item msgid="3534782711045262344">"256 K"</item>
-    <item msgid="8085867209202153403">"1 M"</item>
+    <item msgid="6089470720451068364">"No"</item>
+    <item msgid="4622460333038586791">"64 K"</item>
+    <item msgid="2212125625169582330">"256 K"</item>
+    <item msgid="1704946766699242653">"1 M"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 K/búfer registro"</item>
-    <item msgid="2822309747675758628">"256 K/búfer registro"</item>
-    <item msgid="6699306198357496731">"1 M/búfer registro"</item>
-    <item msgid="5748528643937500349">"4 M/búfer registro"</item>
-    <item msgid="1978629051085111592">"16 M/búfer registro"</item>
+    <item msgid="6921048829791179331">"No"</item>
+    <item msgid="2969458029344750262">"64 K/búfer registro"</item>
+    <item msgid="1342285115665698168">"256 K/búfer registro"</item>
+    <item msgid="1314234299552254621">"1 M/búfer registro"</item>
+    <item msgid="3606047780792894151">"4 M/búfer registro"</item>
+    <item msgid="5431354956856655120">"16 M/búfer registro"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animación desactivada"</item>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index cedd582..901dc25 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Forzar el ajuste de tamaño de las actividades"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Permite utilizar ventanas de forma libre experimentales."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Contraseña para copias de ordenador"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Las copias de seguridad completas de ordenador no están protegidas"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Tocar para cambiar o quitar la contraseña para las copias de seguridad completas de ordenador"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automático"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Corrección del color"</string>
     <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_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_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_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_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_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="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_usb" msgid="2207489369680923929">"Cargando por USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Cargando de forma inalámbrica"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-et-rEE/arrays.xml b/packages/SettingsLib/res/values-et-rEE/arrays.xml
index 5bf13bb..9731983 100644
--- a/packages/SettingsLib/res/values-et-rEE/arrays.xml
+++ b/packages/SettingsLib/res/values-et-rEE/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Kasuta alati HDCP-kontrollimist"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 000"</item>
-    <item msgid="505611754508988476">"256 000"</item>
-    <item msgid="6361286924268716397">"1 000 000"</item>
-    <item msgid="6405203239560695266">"4 000 000"</item>
-    <item msgid="3025431211013424097">"16 000 000"</item>
+    <item msgid="8665206199209698501">"Väljas"</item>
+    <item msgid="1593289376502312923">"64 000"</item>
+    <item msgid="487545340236145324">"256 000"</item>
+    <item msgid="2423528675294333831">"1 000 000"</item>
+    <item msgid="180883774509476541">"4 000 000"</item>
+    <item msgid="2803199102589126938">"16 000 000"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 000"</item>
-    <item msgid="3534782711045262344">"256 000"</item>
-    <item msgid="8085867209202153403">"1 000 000"</item>
+    <item msgid="6089470720451068364">"Väljas"</item>
+    <item msgid="4622460333038586791">"64 000"</item>
+    <item msgid="2212125625169582330">"256 000"</item>
+    <item msgid="1704946766699242653">"1 000 000"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 k / logipuhver"</item>
-    <item msgid="2822309747675758628">"256 k / logipuhver"</item>
-    <item msgid="6699306198357496731">"1 mln / logipuhver"</item>
-    <item msgid="5748528643937500349">"4 mln / logipuhver"</item>
-    <item msgid="1978629051085111592">"16 mln / logipuhver"</item>
+    <item msgid="6921048829791179331">"Väljas"</item>
+    <item msgid="2969458029344750262">"64 000 / logipuhver"</item>
+    <item msgid="1342285115665698168">"256 000 / logipuhver"</item>
+    <item msgid="1314234299552254621">"1 000 000 / logipuhver"</item>
+    <item msgid="3606047780792894151">"4 000 000 / logipuhver"</item>
+    <item msgid="5431354956856655120">"16 000 000 / logipuhver"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animatsioon väljas"</item>
diff --git a/packages/SettingsLib/res/values-et-rEE/strings.xml b/packages/SettingsLib/res/values-et-rEE/strings.xml
index 714004e..970812a 100644
--- a/packages/SettingsLib/res/values-et-rEE/strings.xml
+++ b/packages/SettingsLib/res/values-et-rEE/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Lubab rakendusi kirjutada välisesse salvestusruumi olenemata manifesti väärtustest"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Muuda tegevuste suurused muudetavaks"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Muudab kõigi tegevuste suurused mitme aknaga vaates olenemata manifesti väärtustest muudetavaks."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Luba vabas vormis aknad"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Lubatakse katseliste vabas vormis akende tugi."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Arvutivarunduse parool"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Täielikud arvutivarundused pole praegu kaitstud"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Puudutage, et muuta või eemaldada täielike arvutivarunduste parool"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automaatne"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Värviparandus"</string>
     <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_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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Laadimine USB kaudu"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Juhtmevaba laadimine"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-eu-rES/arrays.xml b/packages/SettingsLib/res/values-eu-rES/arrays.xml
index 707ace5..b72b537 100644
--- a/packages/SettingsLib/res/values-eu-rES/arrays.xml
+++ b/packages/SettingsLib/res/values-eu-rES/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Erabili beti HDCP egiaztapena"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 K"</item>
-    <item msgid="505611754508988476">"256 K"</item>
-    <item msgid="6361286924268716397">"1 M"</item>
-    <item msgid="6405203239560695266">"4 M"</item>
-    <item msgid="3025431211013424097">"16 M"</item>
+    <item msgid="8665206199209698501">"Desaktibatuta"</item>
+    <item msgid="1593289376502312923">"64 K"</item>
+    <item msgid="487545340236145324">"256 K"</item>
+    <item msgid="2423528675294333831">"1 M"</item>
+    <item msgid="180883774509476541">"4 M"</item>
+    <item msgid="2803199102589126938">"16 M"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 K"</item>
-    <item msgid="3534782711045262344">"256 K"</item>
-    <item msgid="8085867209202153403">"1 M"</item>
+    <item msgid="6089470720451068364">"Desaktibatuta"</item>
+    <item msgid="4622460333038586791">"64 K"</item>
+    <item msgid="2212125625169582330">"256 K"</item>
+    <item msgid="1704946766699242653">"1 M"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 K erregistroen bufferreko"</item>
-    <item msgid="2822309747675758628">"256 K erregistroen bufferreko"</item>
-    <item msgid="6699306198357496731">"1 M erregistroen bufferreko"</item>
-    <item msgid="5748528643937500349">"4 M erregistroen bufferreko"</item>
-    <item msgid="1978629051085111592">"16 M erregistroen bufferreko"</item>
+    <item msgid="6921048829791179331">"Desaktibatuta"</item>
+    <item msgid="2969458029344750262">"64 K erregistroen bufferreko"</item>
+    <item msgid="1342285115665698168">"256 K erregistroen bufferreko"</item>
+    <item msgid="1314234299552254621">"1 M erregistroen bufferreko"</item>
+    <item msgid="3606047780792894151">"4 M erregistroen bufferreko"</item>
+    <item msgid="5431354956856655120">"16 M erregistroen bufferreko"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animazioa desaktibatuta"</item>
diff --git a/packages/SettingsLib/res/values-eu-rES/strings.xml b/packages/SettingsLib/res/values-eu-rES/strings.xml
index 7f47bf3..64a1410 100644
--- a/packages/SettingsLib/res/values-eu-rES/strings.xml
+++ b/packages/SettingsLib/res/values-eu-rES/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"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="4508217476997182216">"Manifestuan jartzen duena jartzen duela ere, jarduera guztien tamaina doitzeko aukera ematen du, hainbat leihotan erabili ahal izan daitezen."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Gaitu estilo libreko leihoak"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Estilo libreko leiho esperimentalak onartzen ditu."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Tokiko babeskop. pasahitza"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Une honetan, ordenagailuko babeskopia osoak ez daude babestuta."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Ukitu ordenagailuko babeskopia osoak egiteko pasahitza aldatzeko edo kentzeko"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automatikoa"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Kolore-zuzenketa"</string>
     <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_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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB bidez kargatzen"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Hari gabe kargatzen"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-fa/arrays.xml b/packages/SettingsLib/res/values-fa/arrays.xml
index d75280b..1b4e335 100644
--- a/packages/SettingsLib/res/values-fa/arrays.xml
+++ b/packages/SettingsLib/res/values-fa/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"‏همیشه از بررسی HDCP استفاده شود"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"۶۴ کیلوبایت"</item>
-    <item msgid="505611754508988476">"۲۵۶ کیلوبایت"</item>
-    <item msgid="6361286924268716397">"۱ مگابایت"</item>
-    <item msgid="6405203239560695266">"۴ مگابایت"</item>
-    <item msgid="3025431211013424097">"۱۶ مگابایت"</item>
+    <item msgid="8665206199209698501">"خاموش"</item>
+    <item msgid="1593289376502312923">"۶۴ هزار"</item>
+    <item msgid="487545340236145324">"۲۵۶ هزار"</item>
+    <item msgid="2423528675294333831">"۱ میلیون"</item>
+    <item msgid="180883774509476541">"۴ میلیون"</item>
+    <item msgid="2803199102589126938">"۱۶ میلیون"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"۶۴ کیلوبایت"</item>
-    <item msgid="3534782711045262344">"۲۵۶ کیلوبایت"</item>
-    <item msgid="8085867209202153403">"۱ مگابایت"</item>
+    <item msgid="6089470720451068364">"خاموش"</item>
+    <item msgid="4622460333038586791">"۶۴ هزار"</item>
+    <item msgid="2212125625169582330">"۲۵۶ هزار"</item>
+    <item msgid="1704946766699242653">"۱ میلیون"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"‏۶۴K در حافظه موقت ثبت"</item>
-    <item msgid="2822309747675758628">"‏۲۵۶Kدر حافظه موقت ثبت"</item>
-    <item msgid="6699306198357496731">"‏۱Mدر حافظه موقت ثبت"</item>
-    <item msgid="5748528643937500349">"‏۴M در حافظه موقت ثبت"</item>
-    <item msgid="1978629051085111592">"‏۱۶M در حافظه موقت ثبت"</item>
+    <item msgid="6921048829791179331">"خاموش"</item>
+    <item msgid="2969458029344750262">"۶۴ هزار در هر بافر گزارش"</item>
+    <item msgid="1342285115665698168">"۲۵۶ هزار در هر بافر گزارش"</item>
+    <item msgid="1314234299552254621">"۱ میلیون در هر بافر گزارش"</item>
+    <item msgid="3606047780792894151">"۴ میلیون در هر بافر گزارش"</item>
+    <item msgid="5431354956856655120">"۱۶ میلیون در هر بافر گزارش"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"پویانمایی خاموش"</item>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 1f8b575..5380651 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"بدون توجه به مقادیر مانیفست، هر برنامه‌ای را برای نوشتن در حافظه خارجی واجد شرایط می‌کند"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"اجبار فعالیت‌ها به قابل تغییر اندازه بودن"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"بدون درنظر گرفتن مقادیر مانیفست، همه فعالیت‌ها را برای چندپنجره قابل تغییر اندازه می‌کند."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"فعال کردن پنجره‌های آزاد"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"پشتیبانی برای پنجره‌های آزاد آزمایشی را امکان‌پذیر می‌کند"</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="2731163425081172638">"برای تغییر یا حذف گذرواژه برای نسخه‌های پشتیبان کامل دسک‌تاپ لمس کنید"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"خودکار"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<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> تا شارژ کامل از طریق USB"</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="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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"‏شارژ از طریق USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"شارژ به صورت بی‌سیم"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-fi/arrays.xml b/packages/SettingsLib/res/values-fi/arrays.xml
index 40d0787..15e6e40 100644
--- a/packages/SettingsLib/res/values-fi/arrays.xml
+++ b/packages/SettingsLib/res/values-fi/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Käytä aina HDCP-tarkistusta"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 kt"</item>
-    <item msgid="505611754508988476">"256 kt"</item>
-    <item msgid="6361286924268716397">"1 Mt"</item>
-    <item msgid="6405203239560695266">"4 Mt"</item>
-    <item msgid="3025431211013424097">"16 Mt"</item>
+    <item msgid="8665206199209698501">"Ei käytössä"</item>
+    <item msgid="1593289376502312923">"64 kt"</item>
+    <item msgid="487545340236145324">"256 kt"</item>
+    <item msgid="2423528675294333831">"1 Mt"</item>
+    <item msgid="180883774509476541">"4 Mt"</item>
+    <item msgid="2803199102589126938">"16 Mt"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 kt"</item>
-    <item msgid="3534782711045262344">"256 kt"</item>
-    <item msgid="8085867209202153403">"1 Mt"</item>
+    <item msgid="6089470720451068364">"Ei käytössä"</item>
+    <item msgid="4622460333038586791">"64 kt"</item>
+    <item msgid="2212125625169582330">"256 kt"</item>
+    <item msgid="1704946766699242653">"1 Mt"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 kt / lokipuskuri"</item>
-    <item msgid="2822309747675758628">"256 kt / lokipuskuri"</item>
-    <item msgid="6699306198357496731">"1 Mt / lokipuskuri"</item>
-    <item msgid="5748528643937500349">"4 Mt / lokipuskuri"</item>
-    <item msgid="1978629051085111592">"16 Mt / lokipuskuri"</item>
+    <item msgid="6921048829791179331">"Ei käytössä"</item>
+    <item msgid="2969458029344750262">"64 kt / lokipuskuri"</item>
+    <item msgid="1342285115665698168">"256 kt / lokipuskuri"</item>
+    <item msgid="1314234299552254621">"1 Mt / lokipuskuri"</item>
+    <item msgid="3606047780792894151">"4 Mt / lokipuskuri"</item>
+    <item msgid="5431354956856655120">"16 Mt / lokipuskuri"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animaatio pois käytöstä"</item>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index e4b4b93..4b555ac 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Mahdollistaa sovellusten tallentamisen ulkoiseen tall.tilaan luettelosta 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="4508217476997182216">"Pakottaa kaikki toiminnot hyväksymään koon muuttamisen rinnakkaisnäkymään luettelon arvoista riippumatta."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Ota käyttöön vapaamuotoiset ikkunat"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ottaa käyttöön kokeellisten vapaamuotoisten ikkunoiden tuen."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Varmuuskop. salasana"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Tietokoneen kaikkien tietojen varmuuskopiointia ei ole tällä hetkellä suojattu"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Muuta tai vaihda tietokoneen kaikkien tietojen varmuuskopioinnin salasana koskettamalla"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automaattinen"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Värikorjaus"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – noin <xliff:g id="TIME">%2$s</xliff:g> jäljellä"</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> kunnes täynnä"</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> kunnes täynnä (laturilataus)"</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> kunnes täynnä (USB-lataus)"</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> kunnes täynnä (WiFi-lataus)"</string>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB-lataus"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Langaton lataus"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/arrays.xml b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
index 714dbe4..ab48103 100644
--- a/packages/SettingsLib/res/values-fr-rCA/arrays.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Toujours utiliser la vérification HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 ko"</item>
-    <item msgid="505611754508988476">"256 ko"</item>
-    <item msgid="6361286924268716397">"1 Mo"</item>
-    <item msgid="6405203239560695266">"4 Mo"</item>
-    <item msgid="3025431211013424097">"16 Mo"</item>
+    <item msgid="8665206199209698501">"Désactivé"</item>
+    <item msgid="1593289376502312923">"64 ko"</item>
+    <item msgid="487545340236145324">"256 ko"</item>
+    <item msgid="2423528675294333831">"1 Mo"</item>
+    <item msgid="180883774509476541">"4 Mo"</item>
+    <item msgid="2803199102589126938">"16 Mo"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 ko"</item>
-    <item msgid="3534782711045262344">"256 ko"</item>
-    <item msgid="8085867209202153403">"1 Mo"</item>
+    <item msgid="6089470720451068364">"Désactivé"</item>
+    <item msgid="4622460333038586791">"64 ko"</item>
+    <item msgid="2212125625169582330">"256 ko"</item>
+    <item msgid="1704946766699242653">"1 Mo"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"1 ko/tampon journal"</item>
-    <item msgid="2822309747675758628">"256 Ko/tampon journal"</item>
-    <item msgid="6699306198357496731">"1 Mo/tampon journal"</item>
-    <item msgid="5748528643937500349">"4 Mo/tampon journal"</item>
-    <item msgid="1978629051085111592">"16 Mo/tampon journal"</item>
+    <item msgid="6921048829791179331">"Désactivé"</item>
+    <item msgid="2969458029344750262">"64 ko/tampon journal"</item>
+    <item msgid="1342285115665698168">"256 Ko/tampon journal"</item>
+    <item msgid="1314234299552254621">"1 Mo/tampon journal"</item>
+    <item msgid="3606047780792894151">"4 Mo/tampon journal"</item>
+    <item msgid="5431354956856655120">"16 Mo/tampon journal"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animation désactivée"</item>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 66c54a1..96d2e7b 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Permet enreg. d\'applis sur espace stockage externe"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Forcer les activités à être redimensionnables"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Active la compatibilité avec les fenêtres de forme libre expérimentales."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Mot de passe sauvegarde PC"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Les sauvegardes complètes sur PC ne sont pas protégées actuellement."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Appuyez pour modifier ou supprimer le mot de passe utilisé pour les sauvegardes complètes sur PC."</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automatique"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Correction des couleurs"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> %% – Temps restant : environ <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> %% (chargée à 100 %% dans <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> %% (charge complète sur c.a. dans <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> %% (chargée à 100 %% par USB dans <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> %% (chargée à 100 %% avec chargeur sans fil dans <xliff:g id="TIME">%2$s</xliff:g>)"</string>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"En charge par USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"En charge sans fil"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-fr/arrays.xml b/packages/SettingsLib/res/values-fr/arrays.xml
index a8bed69..1cfd3d4 100644
--- a/packages/SettingsLib/res/values-fr/arrays.xml
+++ b/packages/SettingsLib/res/values-fr/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Toujours utiliser la vérification HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 Ko"</item>
-    <item msgid="505611754508988476">"256 Ko"</item>
-    <item msgid="6361286924268716397">"1 Mo"</item>
-    <item msgid="6405203239560695266">"4 Mo"</item>
-    <item msgid="3025431211013424097">"16 Mo"</item>
+    <item msgid="8665206199209698501">"Désactivé"</item>
+    <item msgid="1593289376502312923">"64 Ko"</item>
+    <item msgid="487545340236145324">"256 Ko"</item>
+    <item msgid="2423528675294333831">"1 Mo"</item>
+    <item msgid="180883774509476541">"4 Mo"</item>
+    <item msgid="2803199102589126938">"16 Mo"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 Ko"</item>
-    <item msgid="3534782711045262344">"256 Ko"</item>
-    <item msgid="8085867209202153403">"1 Mo"</item>
+    <item msgid="6089470720451068364">"Désactivé"</item>
+    <item msgid="4622460333038586791">"64 Ko"</item>
+    <item msgid="2212125625169582330">"256 Ko"</item>
+    <item msgid="1704946766699242653">"1 Mo"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 Ko/tampon journal"</item>
-    <item msgid="2822309747675758628">"256 Ko/tampon journal"</item>
-    <item msgid="6699306198357496731">"1 Mo/tampon journal"</item>
-    <item msgid="5748528643937500349">"4 Mo/tampon journal"</item>
-    <item msgid="1978629051085111592">"16 Mo/tampon journal"</item>
+    <item msgid="6921048829791179331">"Désactivé"</item>
+    <item msgid="2969458029344750262">"64 Ko par tampon journal"</item>
+    <item msgid="1342285115665698168">"256 Ko par tampon journal"</item>
+    <item msgid="1314234299552254621">"1 Mo par tampon journal"</item>
+    <item msgid="3606047780792894151">"4 Mo par tampon journal"</item>
+    <item msgid="5431354956856655120">"16 Mo par tampon journal"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animation désactivée"</item>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index e56940a..6dabba8 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Forcer possibilité de redimensionner les activités"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Active la compatibilité avec les fenêtres de forme libre expérimentales."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Mot de passe sauvegarde PC"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Les sauvegardes complètes sur PC ne sont pas protégées actuellement."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Appuyez pour modifier ou supprimer le mot de passe utilisé pour les sauvegardes complètes sur PC."</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automatique"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Correction couleur"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – Temps restant : <xliff:g id="TIME">%2$s</xliff:g> environ"</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> (chargée à 100 %% dans <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> (chargée à 100 %% sur secteur dans <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> (chargée à 100 %% via USB dans <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> (chargée à 100 %% sans fil dans <xliff:g id="TIME">%2$s</xliff:g>)"</string>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"En charge via USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"En charge sans fil"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-gl-rES/arrays.xml b/packages/SettingsLib/res/values-gl-rES/arrays.xml
index 606e6f6..01b8fdf 100644
--- a/packages/SettingsLib/res/values-gl-rES/arrays.xml
+++ b/packages/SettingsLib/res/values-gl-rES/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Utilizar sempre a comprobación HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 K"</item>
-    <item msgid="505611754508988476">"256 K"</item>
-    <item msgid="6361286924268716397">"1 M"</item>
-    <item msgid="6405203239560695266">"4 M"</item>
-    <item msgid="3025431211013424097">"16 M"</item>
+    <item msgid="8665206199209698501">"Desactivado"</item>
+    <item msgid="1593289376502312923">"64 K"</item>
+    <item msgid="487545340236145324">"256 K"</item>
+    <item msgid="2423528675294333831">"1 M"</item>
+    <item msgid="180883774509476541">"4 M"</item>
+    <item msgid="2803199102589126938">"16 M"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 K"</item>
-    <item msgid="3534782711045262344">"256 K"</item>
-    <item msgid="8085867209202153403">"1 M"</item>
+    <item msgid="6089470720451068364">"Desactivado"</item>
+    <item msgid="4622460333038586791">"64 K"</item>
+    <item msgid="2212125625169582330">"256 K"</item>
+    <item msgid="1704946766699242653">"1 M"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"Búfer 64 K rexistro"</item>
-    <item msgid="2822309747675758628">"Búfer 256 K rexist."</item>
-    <item msgid="6699306198357496731">"Búfer 1 M rexistro"</item>
-    <item msgid="5748528643937500349">"Búfer 4 M rexistro"</item>
-    <item msgid="1978629051085111592">"Búfer 16 M rexistro"</item>
+    <item msgid="6921048829791179331">"Desactivado"</item>
+    <item msgid="2969458029344750262">"64 K por búfer de rexistro"</item>
+    <item msgid="1342285115665698168">"256 K por búfer de rexistro"</item>
+    <item msgid="1314234299552254621">"1 M por búfer de rexistro"</item>
+    <item msgid="3606047780792894151">"4 M por búfer de rexistro"</item>
+    <item msgid="5431354956856655120">"16 M por búfer de rexistro"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animación desactivada"</item>
diff --git a/packages/SettingsLib/res/values-gl-rES/strings.xml b/packages/SettingsLib/res/values-gl-rES/strings.xml
index 9bcf770..d3773f6 100644
--- a/packages/SettingsLib/res/values-gl-rES/strings.xml
+++ b/packages/SettingsLib/res/values-gl-rES/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Forzar o axuste do tamaño das actividades"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permite axustar o tamaño de todas as actividades para o modo de varias ventás, 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="2252563497485436534">"Activa a compatibilidade con ventás de forma libre experimentais."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Contrasinal para copias"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"As copias de seguridade de ordenador completas non están protexidas"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toca para cambiar ou eliminar o contrasinal para as copias de seguranza completas do escritorio"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automático"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Corrección da cor"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - faltan aproximadamente <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 a carga"</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 a carga con CA"</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 a carga con USB"</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 a carga co modo sen fíos"</string>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Cargando por USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Cargando sen fíos"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-gu-rIN/arrays.xml b/packages/SettingsLib/res/values-gu-rIN/arrays.xml
index c7d62c5..92cbb2d 100644
--- a/packages/SettingsLib/res/values-gu-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-gu-rIN/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"હંમેશા HDCP તપાસનો ઉપયોગ કરો"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <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="7346595473588765019">"લૉગ બફર દીઠ 64K"</item>
-    <item msgid="2822309747675758628">"લૉગ દીઠ 256K બફર"</item>
-    <item msgid="6699306198357496731">"લૉગ બફર દીઠ 1M"</item>
-    <item msgid="5748528643937500349">"લૉગ બફર દીઠ 4M"</item>
-    <item msgid="1978629051085111592">"પ્રતિ લૉગ બફર 16M"</item>
+    <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>
diff --git a/packages/SettingsLib/res/values-gu-rIN/strings.xml b/packages/SettingsLib/res/values-gu-rIN/strings.xml
index 6dff8fa..9e2ec7e 100644
--- a/packages/SettingsLib/res/values-gu-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-gu-rIN/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"મેનિફેસ્ટ મૂલ્યોને ધ્યાનમાં લીધા સિવાય, કોઈપણ એપ્લિકેશનને બાહ્ય સ્ટોરેજ પર લખાવા માટે લાયક બનાવે છે"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"પ્રવૃત્તિઓને ફરીથી કદ યોગ્ય થવા માટે ફરજ પાડો"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"તમામ પ્રવૃત્તિઓને મલ્ટી-વિંડો માટે ફરીથી કદ બદલી શકે તેવી બનાવે છે, મેનીફેસ્ટ મુલ્યોને ધ્યાનમાં લીધા સિવાય."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"ફ્રિફોર્મ વિંડોઝ સક્ષમ કરો"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"પ્રાયોગિક ફ્રિફોર્મ વિંડોઝ માટે સમર્થનને સક્ષમ કરે છે."</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="2731163425081172638">"ડેસ્કટૉપ સંપૂર્ણ બેકઅપ્સ માટેનો પાસવર્ડ બદલવા અથવા દૂર કરવા માટે ટચ કરો"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"સ્વચલિત"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_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_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_wireless" msgid="1829295708243159464">"<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_usb" msgid="2207489369680923929">"USB થી ચાર્જિંગ"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"વાયરલેસથી ચાર્જિંગ"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-hi/arrays.xml b/packages/SettingsLib/res/values-hi/arrays.xml
index 883e997..8aa98a1f 100644
--- a/packages/SettingsLib/res/values-hi/arrays.xml
+++ b/packages/SettingsLib/res/values-hi/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"हमेशा HDCP जांच का उपयोग करें"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <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="7346595473588765019">"64K प्रति लॉग बफ़र"</item>
-    <item msgid="2822309747675758628">"256K प्रति लॉग बफ़र"</item>
-    <item msgid="6699306198357496731">"1M प्रति लॉग बफ़र"</item>
-    <item msgid="5748528643937500349">"4M प्रति लॉग बफ़र"</item>
-    <item msgid="1978629051085111592">"16M प्रति लॉग बफ़र"</item>
+    <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>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 9ce83fa..b6b8eac 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"इससे कोई भी ऐप मेनिफेस्‍ट मान अनदेखा करके, बाहरी मेमोरी पर लिखने योग्‍य बन जाता है"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"आकार बदले जाने के लिए गतिविधियों को बाध्य करें"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"एकाधिक-विंडो के लिए सभी गतिविधियों के आकार को बदले जाने योग्य बनाता है, चाहे मेनिफेस्ट मान कुछ भी हों."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"फ़्रीफ़ॉर्म विंडो सक्षम करें"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"प्रयोगात्मक फ़्रीफ़ॉर्म विंडो का समर्थन सक्षम करती है."</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="2731163425081172638">"डेस्कटॉप के पूर्ण बैकअप के पासवर्ड को बदलने या निकालने के लिए स्‍पर्श करें."</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"स्वचालित"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> AC पर पूरी होने तक"</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> USB पर पूरी होने तक"</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="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_usb" msgid="2207489369680923929">"USB पर चार्ज हो रही"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"वायरलेस रूप से चार्ज हो रही"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-hr/arrays.xml b/packages/SettingsLib/res/values-hr/arrays.xml
index d51f82d..db460c7 100644
--- a/packages/SettingsLib/res/values-hr/arrays.xml
+++ b/packages/SettingsLib/res/values-hr/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Uvijek upotrebljavaj HDCP provjeru"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 KB"</item>
-    <item msgid="505611754508988476">"256 KB"</item>
-    <item msgid="6361286924268716397">"1 MB"</item>
-    <item msgid="6405203239560695266">"4 MB"</item>
-    <item msgid="3025431211013424097">"16 MB"</item>
+    <item msgid="8665206199209698501">"Isključeno"</item>
+    <item msgid="1593289376502312923">"64 KB"</item>
+    <item msgid="487545340236145324">"256 KB"</item>
+    <item msgid="2423528675294333831">"1 MB"</item>
+    <item msgid="180883774509476541">"4 MB"</item>
+    <item msgid="2803199102589126938">"16 MB"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 KB"</item>
-    <item msgid="3534782711045262344">"256 KB"</item>
-    <item msgid="8085867209202153403">"1 MB"</item>
+    <item msgid="6089470720451068364">"Isključeno"</item>
+    <item msgid="4622460333038586791">"64 KB"</item>
+    <item msgid="2212125625169582330">"256 KB"</item>
+    <item msgid="1704946766699242653">"1 MB"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 KB po međusprem."</item>
-    <item msgid="2822309747675758628">"256 KB po međuspr."</item>
-    <item msgid="6699306198357496731">"1 MB po međusprem."</item>
-    <item msgid="5748528643937500349">"4 MB po međusprem."</item>
-    <item msgid="1978629051085111592">"16 MB po međusprem."</item>
+    <item msgid="6921048829791179331">"Isključeno"</item>
+    <item msgid="2969458029344750262">"64 KB po međusprem. zapisnika"</item>
+    <item msgid="1342285115665698168">"256 KB po međusprem. zapisnika"</item>
+    <item msgid="1314234299552254621">"1 MB po međusprem. zapisnika"</item>
+    <item msgid="3606047780792894151">"4 MB po međusprem. zapisnika"</item>
+    <item msgid="5431354956856655120">"16 MB po međusprem. zapisnika"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animacija isključena"</item>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index dd02171..69b71fe 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Aplikacije se mogu zapisivati u vanjsku pohranu neovisno o manifestu"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Nametni mogućnost promjene veličine za aktivnosti"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Veličina svih aktivnosti može se mijenjati za više prozora, neovisno o vrijednostima manifesta."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Omogući prozore slobodnog oblika"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Omogućuje podršku za eksperimentalne prozore slobodnog oblika."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Zaporka sigurnosne kopije"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Potpune sigurnosne kopije na stolnom računalu trenutačno nisu zaštićene"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Odaberite za promjenu ili uklanjanje zaporke u potpunim sigurnosnim kopijama na stolnom računalu"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automatska"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Korekcija boje"</string>
     <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_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_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_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_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_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="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_usb" msgid="2207489369680923929">"Punjenje putem USB-a"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Bežično 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>
 </resources>
diff --git a/packages/SettingsLib/res/values-hu/arrays.xml b/packages/SettingsLib/res/values-hu/arrays.xml
index 03c9ed7..0d201b5 100644
--- a/packages/SettingsLib/res/values-hu/arrays.xml
+++ b/packages/SettingsLib/res/values-hu/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Mindig használjon HDCP ellenőrzést"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 KB"</item>
-    <item msgid="505611754508988476">"256 KB"</item>
-    <item msgid="6361286924268716397">"1 MB"</item>
-    <item msgid="6405203239560695266">"4 MB"</item>
-    <item msgid="3025431211013424097">"16 MB"</item>
+    <item msgid="8665206199209698501">"Ki"</item>
+    <item msgid="1593289376502312923">"64 KB"</item>
+    <item msgid="487545340236145324">"256 KB"</item>
+    <item msgid="2423528675294333831">"1 MB"</item>
+    <item msgid="180883774509476541">"4 MB"</item>
+    <item msgid="2803199102589126938">"16 MB"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 KB"</item>
-    <item msgid="3534782711045262344">"256 KB"</item>
-    <item msgid="8085867209202153403">"1 MB"</item>
+    <item msgid="6089470720451068364">"Ki"</item>
+    <item msgid="4622460333038586791">"64 KB"</item>
+    <item msgid="2212125625169582330">"256 KB"</item>
+    <item msgid="1704946766699242653">"1 MB"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 KB/naplópuffer"</item>
-    <item msgid="2822309747675758628">"256 KB/naplópuffer"</item>
-    <item msgid="6699306198357496731">"1 MB/naplópuffer"</item>
-    <item msgid="5748528643937500349">"4 MB/naplópuffer"</item>
-    <item msgid="1978629051085111592">"16 MB/naplópuffer"</item>
+    <item msgid="6921048829791179331">"Ki"</item>
+    <item msgid="2969458029344750262">"64 KB/naplópuffer"</item>
+    <item msgid="1342285115665698168">"256 KB/naplópuffer"</item>
+    <item msgid="1314234299552254621">"1 MB/naplópuffer"</item>
+    <item msgid="3606047780792894151">"4 MB/naplópuffer"</item>
+    <item msgid="5431354956856655120">"16 MB/naplópuffer"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animáció ki"</item>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 9b3a386..26d65fb 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Lehetővé teszi, hogy külső tárhelyre lehessen írni"</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="4508217476997182216">"Lehetővé teszi, hogy az összes tevékenység átméretezhető legyen 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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Engedélyezi a kísérleti jellegű, szabad formájú ablakok támogatását."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Asztali mentés jelszava"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Az asztali teljes biztonsági mentések jelenleg nem védettek."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Érintse meg, ha módosítaná vagy eltávolítaná a jelszót az asztali teljes mentésekhez"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automatikus"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Színkorrekció"</string>
     <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_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_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_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_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_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="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_usb" msgid="2207489369680923929">"USB-s 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_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>
 </resources>
diff --git a/packages/SettingsLib/res/values-hy-rAM/arrays.xml b/packages/SettingsLib/res/values-hy-rAM/arrays.xml
index 41143de..0755a8a 100644
--- a/packages/SettingsLib/res/values-hy-rAM/arrays.xml
+++ b/packages/SettingsLib/res/values-hy-rAM/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Միշտ օգտագործել HDCP ստուգումը"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64ԿԲ"</item>
-    <item msgid="505611754508988476">"256ԿԲ"</item>
-    <item msgid="6361286924268716397">"1ՄԲ"</item>
-    <item msgid="6405203239560695266">"4ՄԲ"</item>
-    <item msgid="3025431211013424097">"16ՄԲ"</item>
+    <item msgid="8665206199209698501">"Անջատված է"</item>
+    <item msgid="1593289376502312923">"64ԿԲ"</item>
+    <item msgid="487545340236145324">"256ԿԲ"</item>
+    <item msgid="2423528675294333831">"1ՄԲ"</item>
+    <item msgid="180883774509476541">"4ՄԲ"</item>
+    <item msgid="2803199102589126938">"16ՄԲ"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64ԿԲ"</item>
-    <item msgid="3534782711045262344">"256ԿԲ"</item>
-    <item msgid="8085867209202153403">"1ՄԲ"</item>
+    <item msgid="6089470720451068364">"Անջատված է"</item>
+    <item msgid="4622460333038586791">"64ԿԲ"</item>
+    <item msgid="2212125625169582330">"256ԿԲ"</item>
+    <item msgid="1704946766699242653">"1ՄԲ"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"Պահնակ՝ առավ. 64ԿԲ"</item>
-    <item msgid="2822309747675758628">"Պահնակ՝ առավ. 256ԿԲ"</item>
-    <item msgid="6699306198357496731">"Պահնակ՝ առավ. 1ՄԲ"</item>
-    <item msgid="5748528643937500349">"Պահնակ՝ առավ. 4ՄԲ"</item>
-    <item msgid="1978629051085111592">"Պահնակ՝ առավ. 16ՄԲ"</item>
+    <item msgid="6921048829791179331">"Անջատված է"</item>
+    <item msgid="2969458029344750262">"Պահնակ՝ առավ. 64ԿԲ"</item>
+    <item msgid="1342285115665698168">"Պահնակ՝ առավ. 256ԿԲ"</item>
+    <item msgid="1314234299552254621">"Պահնակ՝ առավ. 1ՄԲ"</item>
+    <item msgid="3606047780792894151">"Պահնակ՝ առավ. 4ՄԲ"</item>
+    <item msgid="5431354956856655120">"Պահնակ՝ առավ. 16ՄԲ"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Անջատել շարժապատկերը"</item>
diff --git a/packages/SettingsLib/res/values-hy-rAM/strings.xml b/packages/SettingsLib/res/values-hy-rAM/strings.xml
index 27db9fe..0caa981 100644
--- a/packages/SettingsLib/res/values-hy-rAM/strings.xml
+++ b/packages/SettingsLib/res/values-hy-rAM/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Թույլ է տալիս պահել հավելվածը արտաքին սարքում՝ մանիֆեստի արժեքներից անկախ"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Ստիպել, որ ակտիվությունների չափերը լինեն փոփոխելի"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Բոլոր ակտիվությունների չափերը բազմապատուհան ռեժիմի համար դարձնել փոփոխելի՝ մանիֆեստի արժեքներից անկախ:"</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Ակտիվացնել կամայական ձևի պատուհանները"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ակտիվացնում է կամայական ձևի փորձնական պատուհանների աջակցումը:"</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="2731163425081172638">"Աշխատասեղանի ամբողջական պահուստավորման համար ընտրել փոխել կամ հեռացնել գաղտնաբառը"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Ավտոմատ"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<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> մինչև լրիվ լիցքավորումը USB-ով"</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="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_usb" msgid="2207489369680923929">"Լիցքավորում USB-ով"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Անլար լիցքավորում"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml
index 5aadc13..166efd5 100644
--- a/packages/SettingsLib/res/values-in/arrays.xml
+++ b/packages/SettingsLib/res/values-in/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Selalu gunakan pemeriksaan HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 K"</item>
-    <item msgid="505611754508988476">"256 K"</item>
-    <item msgid="6361286924268716397">"1 M"</item>
-    <item msgid="6405203239560695266">"4 M"</item>
-    <item msgid="3025431211013424097">"16 M"</item>
+    <item msgid="8665206199209698501">"Nonaktif"</item>
+    <item msgid="1593289376502312923">"64 K"</item>
+    <item msgid="487545340236145324">"256 K"</item>
+    <item msgid="2423528675294333831">"1 M"</item>
+    <item msgid="180883774509476541">"4 M"</item>
+    <item msgid="2803199102589126938">"16 M"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 K"</item>
-    <item msgid="3534782711045262344">"256 K"</item>
-    <item msgid="8085867209202153403">"1 M"</item>
+    <item msgid="6089470720451068364">"Nonaktif"</item>
+    <item msgid="4622460333038586791">"64 K"</item>
+    <item msgid="2212125625169582330">"256 K"</item>
+    <item msgid="1704946766699242653">"1 M"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 K/penyangga log"</item>
-    <item msgid="2822309747675758628">"256 K/penyangga log"</item>
-    <item msgid="6699306198357496731">"1 M/penyangga log"</item>
-    <item msgid="5748528643937500349">"4 M/penyangga log"</item>
-    <item msgid="1978629051085111592">"16 M/penyangga log"</item>
+    <item msgid="6921048829791179331">"Nonaktif"</item>
+    <item msgid="2969458029344750262">"64 K/penyangga log"</item>
+    <item msgid="1342285115665698168">"256 K/penyangga log"</item>
+    <item msgid="1314234299552254621">"1 M/penyangga log"</item>
+    <item msgid="3606047780792894151">"4 M/penyangga log"</item>
+    <item msgid="5431354956856655120">"16 M/penyangga log"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animasi mati"</item>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 0cea206..7aba923 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Membuat semua aplikasi dapat ditulis ke penyimpanan eksterna"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Paksa aktivitas agar ukurannya dapat diubah"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Membuat 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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Mengaktifkan dukungan untuk jendela eksperimental berformat bebas."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Sandi cadangan desktop"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Saat ini cadangan desktop penuh tidak dilindungi"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Sentuh guna mengubah atau menghapus sandi untuk cadangan lengkap desktop"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Otomatis"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Koreksi warna"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - kira-kira tersisa. <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> sampai penuh"</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> sampai penuh pada AC"</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> sampai penuh melalui USB"</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> sampai penuh dari nirkabel"</string>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Isi daya lewat USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Isi daya nirkabel"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-is-rIS/arrays.xml b/packages/SettingsLib/res/values-is-rIS/arrays.xml
index bbc7aec6..6024e30 100644
--- a/packages/SettingsLib/res/values-is-rIS/arrays.xml
+++ b/packages/SettingsLib/res/values-is-rIS/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Nota alltaf HDCP-eftirlit"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 k"</item>
-    <item msgid="505611754508988476">"256 k"</item>
-    <item msgid="6361286924268716397">"1 M"</item>
-    <item msgid="6405203239560695266">"4 M"</item>
-    <item msgid="3025431211013424097">"16 M"</item>
+    <item msgid="8665206199209698501">"Slökkt"</item>
+    <item msgid="1593289376502312923">"64 k"</item>
+    <item msgid="487545340236145324">"256 k"</item>
+    <item msgid="2423528675294333831">"1 M"</item>
+    <item msgid="180883774509476541">"4 M"</item>
+    <item msgid="2803199102589126938">"16 M"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 k"</item>
-    <item msgid="3534782711045262344">"256 k"</item>
-    <item msgid="8085867209202153403">"1 M"</item>
+    <item msgid="6089470720451068364">"Slökkt"</item>
+    <item msgid="4622460333038586791">"64 k"</item>
+    <item msgid="2212125625169582330">"256 k"</item>
+    <item msgid="1704946766699242653">"1 M"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 k/biðminni"</item>
-    <item msgid="2822309747675758628">"256 k/biðminni"</item>
-    <item msgid="6699306198357496731">"1 M/biðminni"</item>
-    <item msgid="5748528643937500349">"4 M/biðminni"</item>
-    <item msgid="1978629051085111592">"16 M/biðminni"</item>
+    <item msgid="6921048829791179331">"Slökkt"</item>
+    <item msgid="2969458029344750262">"64 k/biðminni"</item>
+    <item msgid="1342285115665698168">"256 k/biðminni"</item>
+    <item msgid="1314234299552254621">"1 M/biðminni"</item>
+    <item msgid="3606047780792894151">"4 M/biðminni"</item>
+    <item msgid="5431354956856655120">"16 M/biðminni"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Slökkt á hreyfiáhrifum"</item>
diff --git a/packages/SettingsLib/res/values-is-rIS/strings.xml b/packages/SettingsLib/res/values-is-rIS/strings.xml
index b3509ca..a534db6 100644
--- a/packages/SettingsLib/res/values-is-rIS/strings.xml
+++ b/packages/SettingsLib/res/values-is-rIS/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Þvinga breytanlega stærð virkni"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Gerir 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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Kveikir á stuðningi við glugga með frjálsu sniði á tilraunastigi."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Aðgangsorð tölvuafritunar"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Heildarafritun á tölvu er ekki varin sem stendur."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Snertu til að breyta eða fjarlægja aðgangsorðið fyrir heildarafritun á tölvu"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Sjálfvirkt"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Litaleiðrétting"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – u.þ.b. <xliff:g id="TIME">%2$s</xliff:g> eftir"</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> í fulla hleðslu"</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> í fulla hleðslu með hleðslutæki"</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> í fulla hleðslu í gegnum USB"</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> í fulla hleðslu þráðlaust"</string>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Hleður um USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Hleður þráðlaust"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-it/arrays.xml b/packages/SettingsLib/res/values-it/arrays.xml
index 686d61d..d64ec06 100644
--- a/packages/SettingsLib/res/values-it/arrays.xml
+++ b/packages/SettingsLib/res/values-it/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Usa sempre la verifica HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 kB"</item>
-    <item msgid="505611754508988476">"256 kB"</item>
-    <item msgid="6361286924268716397">"1 MB"</item>
-    <item msgid="6405203239560695266">"4 MB"</item>
-    <item msgid="3025431211013424097">"16 MB"</item>
+    <item msgid="8665206199209698501">"Non attiva"</item>
+    <item msgid="1593289376502312923">"64 kB"</item>
+    <item msgid="487545340236145324">"256 kB"</item>
+    <item msgid="2423528675294333831">"1 MB"</item>
+    <item msgid="180883774509476541">"4 MB"</item>
+    <item msgid="2803199102589126938">"16 MB"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 kB"</item>
-    <item msgid="3534782711045262344">"256 kB"</item>
-    <item msgid="8085867209202153403">"1 MB"</item>
+    <item msgid="6089470720451068364">"Non attiva"</item>
+    <item msgid="4622460333038586791">"64 kB"</item>
+    <item msgid="2212125625169582330">"256 kB"</item>
+    <item msgid="1704946766699242653">"1 MB"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 kB/buffer log"</item>
-    <item msgid="2822309747675758628">"256 kB/buffer log"</item>
-    <item msgid="6699306198357496731">"1 MB/buffer log"</item>
-    <item msgid="5748528643937500349">"4 MB/buffer log"</item>
-    <item msgid="1978629051085111592">"16 MB/buffer log"</item>
+    <item msgid="6921048829791179331">"Non attiva"</item>
+    <item msgid="2969458029344750262">"64 kB/buffer log"</item>
+    <item msgid="1342285115665698168">"256 kB/buffer log"</item>
+    <item msgid="1314234299552254621">"1 MB/buffer log"</item>
+    <item msgid="3606047780792894151">"4 MB/buffer log"</item>
+    <item msgid="5431354956856655120">"16 MB/buffer log"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animazione disattivata"</item>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 9f897f7..eedfa33 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Imponi formato modificabile alle attività"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Rende 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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Attiva il supporto per le finestre a forma libera sperimentali."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Password di backup desktop"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"I backup desktop completi non sono attualmente protetti."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Tocca per modificare o rimuovere la password per i backup desktop completi"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automatico"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Correzione del colore"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – Tempo rimanente: <xliff:g id="TIME">%2$s</xliff:g> circa"</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> alla carica completa"</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> alla carica completa tramite CA"</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> alla carica completa tramite USB"</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> lla carica completa con wireless"</string>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"In carica tramite USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"In carica, wireless"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-iw/arrays.xml b/packages/SettingsLib/res/values-iw/arrays.xml
index 24a40b9..01127c6 100644
--- a/packages/SettingsLib/res/values-iw/arrays.xml
+++ b/packages/SettingsLib/res/values-iw/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"‏תמיד השתמש בבדיקת HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"‎256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"‎256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <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="7346595473588765019">"‏64K לכל מאגר יומן"</item>
-    <item msgid="2822309747675758628">"‏256K לכל מאגר יומן"</item>
-    <item msgid="6699306198357496731">"‏1M לכל מאגר יומן"</item>
-    <item msgid="5748528643937500349">"‏4M לכל מאגר יומן"</item>
-    <item msgid="1978629051085111592">"‏16M לכל מאגר יומן"</item>
+    <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>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 2d44612..eb26eaf 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -190,7 +190,7 @@
     <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">"בחר אפליקציה לניפוי"</string>
+    <string name="debug_app" msgid="8349591734751384446">"בחר אפליקציה לניפוי באגים"</string>
     <string name="debug_app_not_set" msgid="718752499586403499">"לא הוגדרה אפליקציה לניפוי"</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>
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"מאפשר כתיבה של כל אפליקציה באחסון חיצוני, ללא התחשבות בערכי המניפסט"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"אלץ יכולת קביעת גודל של הפעילויות"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"מאפשר יכולת קביעת גודל של כל הפעילויות לריבוי חלונות, ללא קשר לערך המניפסט."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"הפעל את האפשרות לשנות את הגודל והמיקום של החלונות"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"מפעיל תמיכה בתכונה הניסיונית של שינוי הגודל והמיקום של החלונות."</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="2731163425081172638">"גע כדי לשנות או להסיר את הסיסמה עבור גיבויים מלאים בשולחן העבודה"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"באופן אוטומטי"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<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> עד למילוי ב-USB"</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="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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"‏טוען ב-USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"טוען באופן אלחוטי"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-ja/arrays.xml b/packages/SettingsLib/res/values-ja/arrays.xml
index 6307a10..3426b5c 100644
--- a/packages/SettingsLib/res/values-ja/arrays.xml
+++ b/packages/SettingsLib/res/values-ja/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"HDCPチェックを常に使用する"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <item msgid="8665206199209698501">"OFF"</item>
+    <item msgid="1593289376502312923">"64 K"</item>
+    <item msgid="487545340236145324">"256 K"</item>
+    <item msgid="2423528675294333831">"1 M"</item>
+    <item msgid="180883774509476541">"4 M"</item>
+    <item msgid="2803199102589126938">"16 M"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <item msgid="6089470720451068364">"OFF"</item>
+    <item msgid="4622460333038586791">"64 K"</item>
+    <item msgid="2212125625169582330">"256 K"</item>
+    <item msgid="1704946766699242653">"1 M"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64K/ログバッファ"</item>
-    <item msgid="2822309747675758628">"256K/ログバッファ"</item>
-    <item msgid="6699306198357496731">"1M/ログバッファ"</item>
-    <item msgid="5748528643937500349">"4M/ログバッファ"</item>
-    <item msgid="1978629051085111592">"16M/ログバッファ"</item>
+    <item msgid="6921048829791179331">"OFF"</item>
+    <item msgid="2969458029344750262">"64 K / ログバッファ"</item>
+    <item msgid="1342285115665698168">"256 K / ログバッファ"</item>
+    <item msgid="1314234299552254621">"1 M / ログバッファ"</item>
+    <item msgid="3606047780792894151">"4 M / ログバッファ"</item>
+    <item msgid="5431354956856655120">"16 M / ログバッファ"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"アニメーションオフ"</item>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 81a5eaf..dfa7456 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"マニフェストの値に関係なく、すべてのアプリを外部ストレージに書き込めるようになります"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"アクティビティをサイズ変更可能にする"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"マニフェストの値に関係なく、マルチウィンドウですべてのアクティビティのサイズを変更できるようになります。"</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"フリーフォーム ウィンドウの有効化"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"テスト段階のフリーフォーム ウィンドウのサポートを有効にします。"</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"PCバックアップパスワード"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"デスクトップのフルバックアップは現在保護されていません"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"デスクトップのフルバックアップ用のパスワードを変更または削除する場合にタップします"</string>
@@ -263,9 +265,9 @@
     <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="6768756967594202411">"無効。タップすると切り替わります。"</string>
-    <string name="inactive_app_active_summary" msgid="4512911571954375968">"有効。タップすると切り替わります。"</string>
+    <string name="inactive_apps_title" msgid="1317817863508274533">"休止中のアプリ"</string>
+    <string name="inactive_app_inactive_summary" msgid="6768756967594202411">"休止中。タップすると切り替わります。"</string>
+    <string name="inactive_app_active_summary" msgid="4512911571954375968">"実行中。タップすると切り替わります。"</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>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"自動"</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="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>
@@ -291,4 +294,20 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - フル充電まで<xliff:g id="TIME">%2$s</xliff:g>(AC)"</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>(USB)"</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="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_usb" msgid="2207489369680923929">"USBで充電しています"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"無線で充電しています"</string>
+    <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 />
 </resources>
diff --git a/packages/SettingsLib/res/values-ka-rGE/arrays.xml b/packages/SettingsLib/res/values-ka-rGE/arrays.xml
index ac627a2..4b6f78b 100644
--- a/packages/SettingsLib/res/values-ka-rGE/arrays.xml
+++ b/packages/SettingsLib/res/values-ka-rGE/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"ყოველთვის გამოიყენე HDCP შემოწმება"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <item msgid="8665206199209698501">"გამორთული"</item>
+    <item msgid="1593289376502312923">"64 კბაიტი"</item>
+    <item msgid="487545340236145324">"256 კბაიტი"</item>
+    <item msgid="2423528675294333831">"1 მბაიტი"</item>
+    <item msgid="180883774509476541">"4 მბაიტი"</item>
+    <item msgid="2803199102589126938">"16 მბაიტი"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <item msgid="6089470720451068364">"გამორთული"</item>
+    <item msgid="4622460333038586791">"64 კბაიტი"</item>
+    <item msgid="2212125625169582330">"256 კბაიტი"</item>
+    <item msgid="1704946766699242653">"1 მბაიტი"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64K / ჟურნ. ბუფერზე"</item>
-    <item msgid="2822309747675758628">"256K/ჟურნ. ბუფერზე"</item>
-    <item msgid="6699306198357496731">"1M / ჟურნ. ბუფერზე"</item>
-    <item msgid="5748528643937500349">"4M / ჟურნ. ბუფერზე"</item>
-    <item msgid="1978629051085111592">"16M / ჟურნ. ბუფერზე"</item>
+    <item msgid="6921048829791179331">"გამორთული"</item>
+    <item msgid="2969458029344750262">"64 კბაიტი / ჟურნალის ბუფერი"</item>
+    <item msgid="1342285115665698168">"256 კბაიტი / ჟურნალის ბუფერი"</item>
+    <item msgid="1314234299552254621">"1 მბაიტი / ჟურნალის ბუფერი"</item>
+    <item msgid="3606047780792894151">"4 მბაიტი / ჟურნალის ბუფერი"</item>
+    <item msgid="5431354956856655120">"16 მბაიტი / ჟურნალის ბუფერი"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"ანიმაციის გამორთვა"</item>
diff --git a/packages/SettingsLib/res/values-ka-rGE/strings.xml b/packages/SettingsLib/res/values-ka-rGE/strings.xml
index e2dfd7e..0f0428f 100644
--- a/packages/SettingsLib/res/values-ka-rGE/strings.xml
+++ b/packages/SettingsLib/res/values-ka-rGE/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"აპები ჩაიწერ. გარე მეხს.-ზე აღწ. ფაილის მნიშვნ. მიუხედ."</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"ზომაცვლადი აქტივობების იძულება"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"მანიფესტის მნიშვნელობების მიუხედავად, ყველა აქტივობას მრავალი ფანჯრის რეჟიმისთვის ზომაცვლადად აქცევს."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"თავისუფალი ფორმის მქონე ფანჯრების ჩართვა"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ჩართავს თავისუფალი ფორმის მქონე ფანჯრების მხარდაჭერის ექსპერიმენტულ ფუნქციას"</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="2731163425081172638">"შეეხეთ დესკტოპის სრული სარეზერვო ასლების პაროლის შესაცვლელად ან წასაშლელად"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"ავტომატური"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"დაახლ. <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_ac" msgid="3969186192576594254">"<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> USB-თი სრულ დატენვამდე"</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="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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"დატენვა USB-ზე"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"დატენვა უსადენოდ"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-kk-rKZ/arrays.xml b/packages/SettingsLib/res/values-kk-rKZ/arrays.xml
index b994eb7..43afb2f 100644
--- a/packages/SettingsLib/res/values-kk-rKZ/arrays.xml
+++ b/packages/SettingsLib/res/values-kk-rKZ/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Әрқашан HDCP (жоғары кең жолақты сандық мазмұн қорғаушы) тексерулерін қолданыңыз"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 КБ"</item>
-    <item msgid="505611754508988476">"256 КБ"</item>
-    <item msgid="6361286924268716397">"1 МБ"</item>
-    <item msgid="6405203239560695266">"4 МБ"</item>
-    <item msgid="3025431211013424097">"16 МБ"</item>
+    <item msgid="8665206199209698501">"Өшірулі"</item>
+    <item msgid="1593289376502312923">"64 КБ"</item>
+    <item msgid="487545340236145324">"256 КБ"</item>
+    <item msgid="2423528675294333831">"1 МБ"</item>
+    <item msgid="180883774509476541">"4 МБ"</item>
+    <item msgid="2803199102589126938">"16 МБ"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 КБ"</item>
-    <item msgid="3534782711045262344">"256 КБ"</item>
-    <item msgid="8085867209202153403">"1 МБ"</item>
+    <item msgid="6089470720451068364">"Өшірулі"</item>
+    <item msgid="4622460333038586791">"64 КБ"</item>
+    <item msgid="2212125625169582330">"256 КБ"</item>
+    <item msgid="1704946766699242653">"1 МБ"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"Әр журнал буферіне 64 КБ"</item>
-    <item msgid="2822309747675758628">"Әр журнал буферіне 256 КБ"</item>
-    <item msgid="6699306198357496731">"Әр журнал буферіне 1 МБ"</item>
-    <item msgid="5748528643937500349">"Әр журнал буферіне 4 МБ"</item>
-    <item msgid="1978629051085111592">"Әр журнал буферіне 16 МБ"</item>
+    <item msgid="6921048829791179331">"Өшірулі"</item>
+    <item msgid="2969458029344750262">"Әр журнал буферіне 64 КБ"</item>
+    <item msgid="1342285115665698168">"Әр журнал буферіне 256 КБ"</item>
+    <item msgid="1314234299552254621">"Әр журнал буферіне 1 МБ"</item>
+    <item msgid="3606047780792894151">"Әр журнал буферіне 4 МБ"</item>
+    <item msgid="5431354956856655120">"Әр журнал буферіне 16 МБ"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Aнимация өшірілген"</item>
diff --git a/packages/SettingsLib/res/values-kk-rKZ/strings.xml b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
index 2dbc375..2f2ffbc 100644
--- a/packages/SettingsLib/res/values-kk-rKZ/strings.xml
+++ b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Манифест мәндеріне қарамастан кез келген қолданбаны сыртқы жадқа жазуға жарамды етеді"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Әрекеттерді өлшемін өзгертуге болатын етуге мәжбүрлеу"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Манифест мәндеріне қарамастан барлық әрекеттерді бірнеше терезе үшін өлшемін өзгертуге болатын етеді."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Еркін пішіндегі терезелерді қосу"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Эксперименттік еркін пішіндегі терезелерді қолдауды қосады."</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="2731163425081172638">"Жұмыс үстелінің толық сақтық көшірмесінің кілтсөзін өзгерту немесе жою үшін түртіңіз"</string>
@@ -273,10 +275,9 @@
     <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 select_webview_provider_title (4628592979751918907) -->
-    <skip />
-    <!-- no translation found for select_webview_provider_dialog_title (4370551378720004872) -->
-    <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">"Таңдалған веб-көріністі енгізу өшірілген және пайдалану үшін оны қосу керек. Оны қосу керек пе?"</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>
@@ -293,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<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_wireless" msgid="1829295708243159464">"<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">"Айнымалы токпен зар."</string>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB арқылы зарядтау"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Сымсыз зарядтау"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-km-rKH/arrays.xml b/packages/SettingsLib/res/values-km-rKH/arrays.xml
index 50c1299..63921bc 100644
--- a/packages/SettingsLib/res/values-km-rKH/arrays.xml
+++ b/packages/SettingsLib/res/values-km-rKH/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"ប្រើ​ការ​ពិនិត្យ HDCP ជា​និច្ច"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <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="7346595473588765019">"64K per log buffer"</item>
-    <item msgid="2822309747675758628">"256K per log buffer"</item>
-    <item msgid="6699306198357496731">"1M per log buffer"</item>
-    <item msgid="5748528643937500349">"4M per log buffer"</item>
-    <item msgid="1978629051085111592">"16M per log buffer"</item>
+    <item msgid="6921048829791179331">"បិទ"</item>
+    <item msgid="2969458029344750262">"64K per log buffer"</item>
+    <item msgid="1342285115665698168">"256K per log buffer"</item>
+    <item msgid="1314234299552254621">"1M per log buffer"</item>
+    <item msgid="3606047780792894151">"4M per log buffer"</item>
+    <item msgid="5431354956856655120">"16M per log buffer"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"បិទ​ចលនា"</item>
diff --git a/packages/SettingsLib/res/values-km-rKH/strings.xml b/packages/SettingsLib/res/values-km-rKH/strings.xml
index 0186a68..6feb93d 100644
--- a/packages/SettingsLib/res/values-km-rKH/strings.xml
+++ b/packages/SettingsLib/res/values-km-rKH/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ធ្វើឲ្យកម្មវិធីទាំងឡាយមានសិទ្ធិសរសេរទៅកាន់ឧបករណ៍ផ្ទុកខាងក្រៅ ដោយមិនគិតពីតម្លៃជាក់លាក់"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"បង្ខំឲ្យសកម្មភាពអាចប្តូរទំហំបាន"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"កំណត់ឲ្យសកម្មភាពទាំងអស់អាចប្តូរទំហំបានសម្រាប់ពហុផ្ទាំងវិនដូ ដោយមិនគិតពីតម្លៃមេនីហ្វេសឡើយ។"</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"បើកដំណើរការផ្ទាំងវិនដូទម្រង់សេរី"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"បើកដំណើរការគាំទ្រផ្ទាំងវិនដូទម្រង់សេរីសាកល្បង"</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="2731163425081172638">"ប៉ះ ដើម្បី​ប្ដូរ ឬ​លុប​ពាក្យ​សម្ងាត់​សម្រាប់​ការ​បម្រុងទុក​ពេញលេញ​លើ​ផ្ទៃតុ"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"ស្វ័យប្រវត្តិ"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<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> រហូត​ដល់​ពេញ​តាមយូអេសប៊ី"</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="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_usb" msgid="2207489369680923929">"បញ្ចូលថ្មតាមយូអេសប៊ី"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"បញ្ចូលថ្មដោយ​​ឥតខ្សែ"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-kn-rIN/arrays.xml b/packages/SettingsLib/res/values-kn-rIN/arrays.xml
index fe04d28..e1e69f7 100644
--- a/packages/SettingsLib/res/values-kn-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-kn-rIN/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"HDCP ಪರಿಶೀಲನೆಯನ್ನು ಯಾವಾಗಲೂ ಬಳಸು"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <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="7346595473588765019">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್‌ಗೆ 64K"</item>
-    <item msgid="2822309747675758628">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್‌ಗೆ 256K"</item>
-    <item msgid="6699306198357496731">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್‌ಗೆ 1M"</item>
-    <item msgid="5748528643937500349">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್‌ಗೆ 4M"</item>
-    <item msgid="1978629051085111592">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್‌ಗೆ 16M"</item>
+    <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>
diff --git a/packages/SettingsLib/res/values-kn-rIN/strings.xml b/packages/SettingsLib/res/values-kn-rIN/strings.xml
index 56f4006..948c665315 100644
--- a/packages/SettingsLib/res/values-kn-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-kn-rIN/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳನ್ನು ಪರಿಗಣಿಸದೇ, ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಬಾಹ್ಯ ಸಂಗ್ರಹಣೆಗೆ ಬರೆಯಲು ಅರ್ಹಗೊಳಿಸುತ್ತದೆ"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"ಚಟುವಟಿಕೆಗಳನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸುವಂತೆ ಒತ್ತಾಯ ಮಾಡಿ"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳನ್ನು ಪರಿಗಣಿಸದೇ, ಬಹು-ವಿಂಡೊಗೆ ಎಲ್ಲಾ ಚಟುವಟಿಕೆಗಳನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸುವಂತೆ ಮಾಡುತ್ತದೆ."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"ಮುಕ್ತಸ್ವರೂಪದ ವಿಂಡೊಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ಪ್ರಾಯೋಗಿಕ ಮುಕ್ತಸ್ವರೂಪದ ವಿಂಡೊಗಳಿಗೆ ಬೆಂಬಲವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ."</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="2731163425081172638">"ಡೆಸ್ಕ್‌ಟಾಪ್‌ನ ಪೂರ್ಣ ಬ್ಯಾಕಪ್‌ಗಳಿಗೆ ಪಾಸ್‌ವರ್ಡ್‌ ಅನ್ನು ಬದಲಾಯಿಸಲು ಅಥವಾ ತೆಗೆದುಹಾಕಲು ಸ್ಪರ್ಶಿಸಿ"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"ಸ್ವಯಂಚಾಲಿತ"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"ಸುಮಾರು <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_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> AC ನಲ್ಲಿ ಪೂರ್ಣವಾಗುವವರೆಗೆ"</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> USB ಮೂಲಕ ಪೂರ್ಣವಾಗುವವರೆಗೆ"</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="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_usb" msgid="2207489369680923929">"USB ಮೂಲಕ ಚಾರ್ಜ್‌"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"ನಿಸ್ತಂತುವಾಗಿ ಚಾರ್ಜ್‌"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-ko/arrays.xml b/packages/SettingsLib/res/values-ko/arrays.xml
index a8d548f..3e8867e 100644
--- a/packages/SettingsLib/res/values-ko/arrays.xml
+++ b/packages/SettingsLib/res/values-ko/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"항상 HDCP 확인 사용"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <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="7346595473588765019">"로그 버퍼당 64K"</item>
-    <item msgid="2822309747675758628">"로그 버퍼당 256K"</item>
-    <item msgid="6699306198357496731">"로그 버퍼당 1M"</item>
-    <item msgid="5748528643937500349">"로그 버퍼당 4M"</item>
-    <item msgid="1978629051085111592">"로그 버퍼당 16M"</item>
+    <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>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 6ad3efd..ae82263 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"매니페스트 값에 관계없이 앱을 외부 저장소에 작성"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"활동의 크기가 조정 가능하도록 설정"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"모든 활동을 매니페스트 값에 관계없이 멀티 윈도우용으로 크기 조정 가능하도록 설정"</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"자유 형식 창 사용"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"자유 형식 창(베타) 지원 사용"</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="2731163425081172638">"데스크톱 전체 백업에 대한 비밀번호를 변경하거나 삭제하려면 터치하세요."</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"자동"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> 후 충전 완료(AC 전원)"</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> 후 충전 완료(USB)"</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="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_usb" msgid="2207489369680923929">"충전 중(USB)"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"충전 중(무선)"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-ky-rKG/arrays.xml b/packages/SettingsLib/res/values-ky-rKG/arrays.xml
index 7ec569e..34c713e 100644
--- a/packages/SettingsLib/res/values-ky-rKG/arrays.xml
+++ b/packages/SettingsLib/res/values-ky-rKG/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Ар дайым HDCP текшерүү колдонулсун"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1 M"</item>
-    <item msgid="6405203239560695266">"4 M"</item>
-    <item msgid="3025431211013424097">"16 M"</item>
+    <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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <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="7346595473588765019">"64 K каттоо буфери үчүн"</item>
-    <item msgid="2822309747675758628">"256 K каттоо буфери үчүн"</item>
-    <item msgid="6699306198357496731">"1 M каттоо буфери үчүн"</item>
-    <item msgid="5748528643937500349">"4 M каттоо буфери үчүн"</item>
-    <item msgid="1978629051085111592">"16 M каттоо буфери үчүн"</item>
+    <item msgid="6921048829791179331">"Өчүк"</item>
+    <item msgid="2969458029344750262">"Буфер: 64КБ ашпашы керек"</item>
+    <item msgid="1342285115665698168">"Буфер: 256КБ ашпашы керек"</item>
+    <item msgid="1314234299552254621">"Буфер: 1М ашпашы керек"</item>
+    <item msgid="3606047780792894151">"Буфер: 4М ашпашы керек"</item>
+    <item msgid="5431354956856655120">"Буфер: 16М ашпашы керек"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Анимацияны өчүрүү"</item>
diff --git a/packages/SettingsLib/res/values-ky-rKG/strings.xml b/packages/SettingsLib/res/values-ky-rKG/strings.xml
index bf37ac4..fcd7b8f 100644
--- a/packages/SettingsLib/res/values-ky-rKG/strings.xml
+++ b/packages/SettingsLib/res/values-ky-rKG/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Манифест маанилерине карабастан бардык колдонмолорду тышкы сактагычка сактоого уруксат берет"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Аракеттердин өлчөмүн өзгөртүүнү мажбурлоо"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Манифест маанилерине карабастан бардык аракеттерди мульти-терезеге өлчөмү өзгөртүлгүдөй кылат."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Эркин формадагы терезелерди түзүүнү иштетүү"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Эркин формадагы терезелерди түзүү боюнча сынамык функцияны иштетүү"</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="2731163425081172638">"Тийип, компүтердеги толук бэкаптын сырсөзүн өзгөртүңүз же жок кылыңыз"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Автоматтык"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> AC аркылуу толгончо"</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> USB аркылуу толгончо"</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="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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB\'ден кубатталууда"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Зымсыз кубатталууда"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-lo-rLA/arrays.xml b/packages/SettingsLib/res/values-lo-rLA/arrays.xml
index 6422174..312ecc0 100644
--- a/packages/SettingsLib/res/values-lo-rLA/arrays.xml
+++ b/packages/SettingsLib/res/values-lo-rLA/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"ໃຊ້ການກວດສອບ HDCP ສະເໝີ"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <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="7346595473588765019">"ບັບ​ເຟີ 64K ​ຕໍ່​ລັອກ"</item>
-    <item msgid="2822309747675758628">"ບັບ​ເຟີ 256K ​ຕໍ່​ລັອກ"</item>
-    <item msgid="6699306198357496731">"ບັບ​ເຟີ 1M ​ຕໍ່​ລັອກ"</item>
-    <item msgid="5748528643937500349">"ບັບ​ເຟີ 4M ​ຕໍ່​ລັອກ"</item>
-    <item msgid="1978629051085111592">"ບັບ​ເຟີ 16M ​ຕໍ່​ລັອກ"</item>
+    <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>
diff --git a/packages/SettingsLib/res/values-lo-rLA/strings.xml b/packages/SettingsLib/res/values-lo-rLA/strings.xml
index 9e6a4b7..c29b9ab 100644
--- a/packages/SettingsLib/res/values-lo-rLA/strings.xml
+++ b/packages/SettingsLib/res/values-lo-rLA/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ເຮັດ​ໃຫ້ທຸກແອັບ​ມີ​ສິດ​ໄດ້ຮັບການຂຽນ​ໃສ່​ບ່ອນ​ຈັດ​ເກັບ​ພາຍນອກ, ໂດຍ​ບໍ່​ຄຳ​ນຶງ​ເຖິງ​ຄ່າ​ທີ່​ຈະ​ແຈ້ງ"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"ບັງ​ຄັງ​ໃຫ້​ກິດ​ຈະ​ກຳ​ປ່ຽນ​ຂະ​ໜາດ​ໄດ້"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ເຮັດ​ໃຫ້​ທຸກ​ກິດ​ຈະ​ກຳ​ປ່ຽນ​ຂະ​ໜາດ​ໄດ້​ສຳ​ລັບ​ຫຼາຍ​ໜ້າ​ຕ່າງ, ໂດຍ​ບໍ່​ຄຳ​ນຶງ​ເຖິງ​ຄ່າ​ທີ່​ຈະ​ແຈ້ງ."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"ເປີດໃຊ້ໜ້າຕ່າງຮູບແບບອິດສະຫຼະ"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ເປີດໃຊ້ການຮອງຮັບໜ້າຕ່າງຮູບແບບອິດສະຫຼະທີ່ທົດລອງໃຊ້."</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="2731163425081172638">"ແຕະເພື່ອປ່ຽນ ຫຼືລຶບລະຫັດຂອງການສຳຮອງຂໍ້ມູນເຕັມຮູບແບບໃນເດັກສະທັອບ"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"ອັດຕະໂນມັດ"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ​ຈຶ່ງ​ຈະ​ເຕັມ​ໂດຍສາກ​ດ້ວຍ​ໄຟ AC"</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> ຈຶ່ງ​ຈະ​ເຕັມ​ໂດຍສາກ​ດ້ວຍ USB"</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="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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"ກຳ​ລັງ​ສາກ​ຜ່ານ USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"ກຳ​ລັງ​ສາກ​ໄຮ້​ສາຍ"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-lt/arrays.xml b/packages/SettingsLib/res/values-lt/arrays.xml
index 0d20a8a..76ae3fb 100644
--- a/packages/SettingsLib/res/values-lt/arrays.xml
+++ b/packages/SettingsLib/res/values-lt/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Visada naudoti HDCP tikrinimą"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 KB"</item>
-    <item msgid="505611754508988476">"256 KB"</item>
-    <item msgid="6361286924268716397">"1 MB"</item>
-    <item msgid="6405203239560695266">"4 MB"</item>
-    <item msgid="3025431211013424097">"16 MB"</item>
+    <item msgid="8665206199209698501">"Išjungta"</item>
+    <item msgid="1593289376502312923">"64 KB"</item>
+    <item msgid="487545340236145324">"256 KB"</item>
+    <item msgid="2423528675294333831">"1 MB"</item>
+    <item msgid="180883774509476541">"4 MB"</item>
+    <item msgid="2803199102589126938">"16 MB"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 KB"</item>
-    <item msgid="3534782711045262344">"256 KB"</item>
-    <item msgid="8085867209202153403">"1 MB"</item>
+    <item msgid="6089470720451068364">"Išjungta"</item>
+    <item msgid="4622460333038586791">"64 KB"</item>
+    <item msgid="2212125625169582330">"256 KB"</item>
+    <item msgid="1704946766699242653">"1 MB"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 KB žurn. bufer."</item>
-    <item msgid="2822309747675758628">"256 KB žurn. bufer."</item>
-    <item msgid="6699306198357496731">"1 MB žurn. bufer."</item>
-    <item msgid="5748528643937500349">"4 MB žurn. bufer."</item>
-    <item msgid="1978629051085111592">"16 MB žurn. bufer."</item>
+    <item msgid="6921048829791179331">"Išjungta"</item>
+    <item msgid="2969458029344750262">"64 KB žurnalo buferis"</item>
+    <item msgid="1342285115665698168">"256 KB žurnalo buferis"</item>
+    <item msgid="1314234299552254621">"1 MB žurnalo buferis"</item>
+    <item msgid="3606047780792894151">"4 MB žurnalo buferis"</item>
+    <item msgid="5431354956856655120">"16 MB žurnalo buferis"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animacija išjungta"</item>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 2019646..a75c24e 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Vis. pr. gal. įr. į vid. saug. nepais. apr. vert."</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="4508217476997182216">"Nustatoma, 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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Įgalinamas eksperimentinių laisvos formos langų palaikymas."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Viet. atsrg. kop. slapt."</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Šiuo metu visos vietinės atsarginės kopijos neapsaugotos"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Jei norite pakeisti ar pašalinti visų vietinių atsarginių kopijų slaptažodį, palieskite"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automatinė"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Spalvų taisymas"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – liko maždaug <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> iki visiško įkrovimo"</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> iki visiško įkrovimo naud. kint. sr."</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> iki visiško įkrovimo naudojant USB"</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> iki visiško įkrovimo belaid. ryš."</string>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Įkraunama naud. USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Įkraunama be laidų"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-lv/arrays.xml b/packages/SettingsLib/res/values-lv/arrays.xml
index a033d1b..03aff8c 100644
--- a/packages/SettingsLib/res/values-lv/arrays.xml
+++ b/packages/SettingsLib/res/values-lv/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Vienmēr izmantot HDCP pārbaudi"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 KB"</item>
-    <item msgid="505611754508988476">"256 KB"</item>
-    <item msgid="6361286924268716397">"1 MB"</item>
-    <item msgid="6405203239560695266">"4 MB"</item>
-    <item msgid="3025431211013424097">"16 MB"</item>
+    <item msgid="8665206199209698501">"Izslēgts"</item>
+    <item msgid="1593289376502312923">"64 KB"</item>
+    <item msgid="487545340236145324">"256 KB"</item>
+    <item msgid="2423528675294333831">"1 MB"</item>
+    <item msgid="180883774509476541">"4 MB"</item>
+    <item msgid="2803199102589126938">"16 MB"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 KB"</item>
-    <item msgid="3534782711045262344">"256 KB"</item>
-    <item msgid="8085867209202153403">"1 MB"</item>
+    <item msgid="6089470720451068364">"Izslēgts"</item>
+    <item msgid="4622460333038586791">"64 KB"</item>
+    <item msgid="2212125625169582330">"256 KB"</item>
+    <item msgid="1704946766699242653">"1 MB"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 KB žurn. buferis"</item>
-    <item msgid="2822309747675758628">"256 KB žurn. buf."</item>
-    <item msgid="6699306198357496731">"1 MB žurn. buferis"</item>
-    <item msgid="5748528643937500349">"4 MB žurn. buferis"</item>
-    <item msgid="1978629051085111592">"16 MB žurn. buferis"</item>
+    <item msgid="6921048829791179331">"Izslēgts"</item>
+    <item msgid="2969458029344750262">"64 KB vienam žurnāla buferim"</item>
+    <item msgid="1342285115665698168">"256 KB vienam žurnāla buferim"</item>
+    <item msgid="1314234299552254621">"1 MB vienam žurnāla buferim"</item>
+    <item msgid="3606047780792894151">"4 MB vienam žurnāla buferim"</item>
+    <item msgid="5431354956856655120">"16 MB vienam žurnāla buferim"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animācija ir izslēgta"</item>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 2f9a83b..23aa537 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Pielāgot darbības"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Pielāgo 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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Iespējo eksperimentālo brīvās formas logu atbalstu."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Datora dublējuma parole"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Darbvirsmas pilnie dublējumi pašlaik nav aizsargāti."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Pieskarieties, lai mainītu vai noņemtu paroli pilniem darbvirsmas dublējumiem."</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automātiski"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Krāsu korekcija"</string>
     <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_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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB uzlāde"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Bezvadu uzlāde"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-mk-rMK/arrays.xml b/packages/SettingsLib/res/values-mk-rMK/arrays.xml
index c97b577..588c21a 100644
--- a/packages/SettingsLib/res/values-mk-rMK/arrays.xml
+++ b/packages/SettingsLib/res/values-mk-rMK/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Секогаш користи ХДЦП проверка"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 K"</item>
-    <item msgid="505611754508988476">"256 K"</item>
-    <item msgid="6361286924268716397">"1 M"</item>
-    <item msgid="6405203239560695266">"4 M"</item>
-    <item msgid="3025431211013424097">"16 M"</item>
+    <item msgid="8665206199209698501">"Исклучено"</item>
+    <item msgid="1593289376502312923">"64.000"</item>
+    <item msgid="487545340236145324">"256.000"</item>
+    <item msgid="2423528675294333831">"1 M"</item>
+    <item msgid="180883774509476541">"4 M"</item>
+    <item msgid="2803199102589126938">"16 M"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64.000"</item>
-    <item msgid="3534782711045262344">"256.000"</item>
-    <item msgid="8085867209202153403">"1 M"</item>
+    <item msgid="6089470720451068364">"Исклучено"</item>
+    <item msgid="4622460333038586791">"64.000"</item>
+    <item msgid="2212125625169582330">"256.000"</item>
+    <item msgid="1704946766699242653">"1 M"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 K/меѓумеморија"</item>
-    <item msgid="2822309747675758628">"256 K/меѓумеморија"</item>
-    <item msgid="6699306198357496731">"1 M/меѓумеморија"</item>
-    <item msgid="5748528643937500349">"4 M/меѓумеморија"</item>
-    <item msgid="1978629051085111592">"16 M/меѓумеморија"</item>
+    <item msgid="6921048829791179331">"Исклучено"</item>
+    <item msgid="2969458029344750262">"64 K/меѓумеморија"</item>
+    <item msgid="1342285115665698168">"256 K/меѓумеморија"</item>
+    <item msgid="1314234299552254621">"1 M/меѓумеморија"</item>
+    <item msgid="3606047780792894151">"4 M/меѓумеморија"</item>
+    <item msgid="5431354956856655120">"16 M/меѓумеморија"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Без анимација"</item>
diff --git a/packages/SettingsLib/res/values-mk-rMK/strings.xml b/packages/SettingsLib/res/values-mk-rMK/strings.xml
index e01d00c..32d276e 100644
--- a/packages/SettingsLib/res/values-mk-rMK/strings.xml
+++ b/packages/SettingsLib/res/values-mk-rMK/strings.xml
@@ -97,7 +97,7 @@
     <string name="running_process_item_user_label" msgid="3129887865552025943">"Корисник: <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">"Подесувања на текст-во-говор"</string>
+    <string name="tts_settings" msgid="8186971894801348327">"Поставки на текст-во-говор"</string>
     <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>
@@ -117,7 +117,7 @@
     <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_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>
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Запишува апл. во надв.меморија, незав. од манифест"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Принуди ги активностите да ја менуваат големината"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Ги прави сите активности да бидат со променлива големина за мултипрозорец, без разлика на вредностите на манифестот."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Овозможи прозорци со слободна форма"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Овозможува поддршка за експериментални прозорци со слободна форма."</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="2731163425081172638">"Допрете за да се промени или отстрани лозинката за целосна резервна копија на работната површина"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Автоматски"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до целосно полна на AC"</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> до целосно полна преку USB"</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="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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Полнење преку УСБ"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Безжично полнење"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-ml-rIN/arrays.xml b/packages/SettingsLib/res/values-ml-rIN/arrays.xml
index 404b20a..f04cc65 100644
--- a/packages/SettingsLib/res/values-ml-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-ml-rIN/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"എല്ലായ്‌പ്പോഴും HDCP പരിശോധന ഉപയോഗിക്കുക"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <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="7346595473588765019">"ഓരോ ലോഗ് ബഫറിനും 64K"</item>
-    <item msgid="2822309747675758628">"ഓരോ ലോഗ് ബഫറിനും 256K"</item>
-    <item msgid="6699306198357496731">"ഓരോ ലോഗ് ബഫറിനും 1M"</item>
-    <item msgid="5748528643937500349">"ഓരോ ലോഗ് ബഫറിനും 4M"</item>
-    <item msgid="1978629051085111592">"ഓരോ ലോഗ് ബഫറിനും 16M"</item>
+    <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>
diff --git a/packages/SettingsLib/res/values-ml-rIN/strings.xml b/packages/SettingsLib/res/values-ml-rIN/strings.xml
index f00103f..9684b7b 100644
--- a/packages/SettingsLib/res/values-ml-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ml-rIN/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, ബാഹ്യ സ്റ്റോറേജിലേക്ക് എഴുതപ്പെടുന്നതിന് ഏതൊരു ആപ്പിനെയും യോഗ്യമാക്കുന്നു"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"വലിപ്പം മാറ്റാൻ പ്രവർത്തനങ്ങളെ നിർബന്ധിക്കുക"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, എല്ലാ പ്രവർത്തനങ്ങളെയും മൾട്ടി-വിൻഡോയ്ക്കായി വലിപ്പം മാറ്റുന്നു."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"ഫ്രീഫോം വിൻഡോകൾ പ്രവർത്തനക്ഷമമാക്കുക"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"പരീക്ഷണാത്മക ഫ്രീഫോം വിൻഡോകൾക്കുള്ള പിന്തുണ പ്രവർത്തനക്ഷമമാക്കുന്നു."</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="2731163425081172638">"ഡെസ്‌ക്‌ടോപ്പ് പൂർണ്ണ ബാക്കപ്പുകൾക്കായി പാസ്‌വേഡുകൾ മാറ്റാനോ നീക്കംചെയ്യാനോ സ്‌പർശിക്കുക"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"ഓട്ടോമാറ്റിക്"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_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_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_wireless" msgid="1829295708243159464">"<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_usb" msgid="2207489369680923929">"USB-യിലൂടെ ചാർജ്ജുചെയ്യുന്നു"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"വയർലെസ്സ് കണക്ഷനിലൂടെ ചാർജ്ജുചെയ്യുന്നു"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-mn-rMN/arrays.xml b/packages/SettingsLib/res/values-mn-rMN/arrays.xml
index c4c6d28..c4bbbcb 100644
--- a/packages/SettingsLib/res/values-mn-rMN/arrays.xml
+++ b/packages/SettingsLib/res/values-mn-rMN/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Байнга HDCP шалгахыг ашиглах"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1М"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <item msgid="8665206199209698501">"Идэвхгүй"</item>
+    <item msgid="1593289376502312923">"64000"</item>
+    <item msgid="487545340236145324">"256000"</item>
+    <item msgid="2423528675294333831">"1 сая"</item>
+    <item msgid="180883774509476541">"4 сая"</item>
+    <item msgid="2803199102589126938">"16 сая"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1М"</item>
+    <item msgid="6089470720451068364">"Идэвхгүй"</item>
+    <item msgid="4622460333038586791">"64000"</item>
+    <item msgid="2212125625169582330">"256000"</item>
+    <item msgid="1704946766699242653">"1 сая"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"лог буфер бүрт 64K"</item>
-    <item msgid="2822309747675758628">"лог буфер бүрт 256K"</item>
-    <item msgid="6699306198357496731">"лог буфер бүрт 1M"</item>
-    <item msgid="5748528643937500349">"лог буфер бүрт 4M"</item>
-    <item msgid="1978629051085111592">"лог буфер бүрт 16M"</item>
+    <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>
diff --git a/packages/SettingsLib/res/values-mn-rMN/strings.xml b/packages/SettingsLib/res/values-mn-rMN/strings.xml
index cc0e7cb..a3f9dfa 100644
--- a/packages/SettingsLib/res/values-mn-rMN/strings.xml
+++ b/packages/SettingsLib/res/values-mn-rMN/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Манифест утгыг нь үл хамааран дурын апп-ыг гадаад санах ойд бичих боломжтой болгодог"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Үйл ажиллагааны хэмжээг өөрчилж болохуйц болгох"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Тодорхойлогч файлын утгыг үл хамааран, бүх үйл ажиллагааг олон цонхонд хэмжээг нь өөрчилж болохуйц болгох."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Чөлөөт хэлбэрийн цонхыг идэвхжүүлэх"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Туршилтын чөлөөт хэлбэрийн цонхны дэмжлэгийг идэвхжүүлдэг."</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="2731163425081172638">"Десктоп дээрх бүрэн нөөшлөлтийн нууц үгийг өөрчлөх буюу арилгахын тулд хүрнэ үү"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Автоматаар"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"АС-р дүүртэл <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">"USB-р дүүртэл <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="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_usb" msgid="2207489369680923929">"USB-р цэнэглэж байна"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Кабльгүйгээр цэнэглэж байна"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-mr-rIN/arrays.xml b/packages/SettingsLib/res/values-mr-rIN/arrays.xml
index 70c1157..2f07389 100644
--- a/packages/SettingsLib/res/values-mr-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-mr-rIN/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"नेहमी HDCP तपासणी वापरा"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <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="7346595473588765019">"प्रति लॉग बफर 64K"</item>
-    <item msgid="2822309747675758628">"प्रति लॉग बफर 256K"</item>
-    <item msgid="6699306198357496731">"प्रति लॉग बफर 1M"</item>
-    <item msgid="5748528643937500349">"प्रति लॉग बफर 4M"</item>
-    <item msgid="1978629051085111592">"प्रति लॉग बफर 16M"</item>
+    <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>
diff --git a/packages/SettingsLib/res/values-mr-rIN/strings.xml b/packages/SettingsLib/res/values-mr-rIN/strings.xml
index b939ca0..804fab0 100644
--- a/packages/SettingsLib/res/values-mr-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-mr-rIN/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"मॅनिफेस्ट मूल्यांकडे दुर्लक्ष करून, कोणत्याही अॅपला बाह्य संचयनावर लेखन केले जाण्‍यासाठी पात्र बनविते"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"क्र‍ियाकलापाचा आकार बदलण्यायोग्य होण्याची सक्ती करा"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"मॅनिफेस्ट मूल्यांकडे दुर्लक्ष करून, एकाधिक-विंडोसाठी सर्व क्रियाकलापांचा आकार बदलण्यायोग्य करा"</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"freeform विंडो सक्षम करा"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"प्रायोगिक मुक्तस्वरूपाच्या विंडोसाठी समर्थन सक्षम करते."</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="2731163425081172638">"डेस्कटॉपच्या पूर्ण बॅकअपसाठी असलेला संकेतशब्द बदलण्यासाठी किंवा काढून टाकण्यासाठी स्पर्श करा"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"स्वयंचलित"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> AC वरून पूर्ण होण्यात"</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> USB वरून पूर्ण होण्यात"</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="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_usb" msgid="2207489369680923929">"USB वरून चार्ज करीत आहे"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"वायरलेस वरून चार्ज करीत आहे"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-ms-rMY/arrays.xml b/packages/SettingsLib/res/values-ms-rMY/arrays.xml
index 320fa9b..49f0f28 100644
--- a/packages/SettingsLib/res/values-ms-rMY/arrays.xml
+++ b/packages/SettingsLib/res/values-ms-rMY/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Sentiasa gunakan penyemakan HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <item msgid="8665206199209698501">"Mati"</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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <item msgid="6089470720451068364">"Mati"</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="7346595473588765019">"64K per penimbal log"</item>
-    <item msgid="2822309747675758628">"256K per penimbal log"</item>
-    <item msgid="6699306198357496731">"1M per penimbal log"</item>
-    <item msgid="5748528643937500349">"4M per penimbal log"</item>
-    <item msgid="1978629051085111592">"16M per penimbal log"</item>
+    <item msgid="6921048829791179331">"Mati"</item>
+    <item msgid="2969458029344750262">"64K per penimbal log"</item>
+    <item msgid="1342285115665698168">"256K per penimbal log"</item>
+    <item msgid="1314234299552254621">"1M per penimbal log"</item>
+    <item msgid="3606047780792894151">"4M per penimbal log"</item>
+    <item msgid="5431354956856655120">"16M per penimbal log"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animasi dimatikan"</item>
diff --git a/packages/SettingsLib/res/values-ms-rMY/strings.xml b/packages/SettingsLib/res/values-ms-rMY/strings.xml
index 2e67752..7020409 100644
--- a/packages/SettingsLib/res/values-ms-rMY/strings.xml
+++ b/packages/SettingsLib/res/values-ms-rMY/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Paksa aktiviti supaya boleh diubah saiz"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Menjadikan semua aktiviti boleh diubah saiz untuk berbilang tetingkap, tanpa mengambil kira nilai manifes."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Dayakan tetingkap bentuk bebas"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Mendayakan sokongan untuk tetingkap bentuk bebas percubaan."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Kata laluan sandaran komputer meja"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Sandaran penuh komputer meja tidak dilindungi pada masa ini"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Sentuh untuk menukar atau mengalih keluar kata laluan untuk sandaran penuh komputer meja"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automatik"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Pembetulan warna"</string>
     <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_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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Mengecas melalui USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Mengecas tanpa wayar"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-my-rMM/arrays.xml b/packages/SettingsLib/res/values-my-rMM/arrays.xml
index 71b35ad..ad3a59f 100644
--- a/packages/SettingsLib/res/values-my-rMM/arrays.xml
+++ b/packages/SettingsLib/res/values-my-rMM/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"HDCP checkingအားအမြဲသုံးပါ"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <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="524799395770610154">"၆၄K"</item>
-    <item msgid="3534782711045262344">"၂၅၆K"</item>
-    <item msgid="8085867209202153403">"၁M"</item>
+    <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="7346595473588765019">"64K လော့ ဘာဖားတွက်"</item>
-    <item msgid="2822309747675758628">"256K လော့ ဘာဖားတွက်"</item>
-    <item msgid="6699306198357496731">"1M လော့ ဘာဖားတွက်"</item>
-    <item msgid="5748528643937500349">"4M လော့ ဘာဖားတွက်"</item>
-    <item msgid="1978629051085111592">"16M လော့ ဘာဖားတွက်"</item>
+    <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>
diff --git a/packages/SettingsLib/res/values-my-rMM/strings.xml b/packages/SettingsLib/res/values-my-rMM/strings.xml
index 002aed1..e40da23 100644
--- a/packages/SettingsLib/res/values-my-rMM/strings.xml
+++ b/packages/SettingsLib/res/values-my-rMM/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ပြနေတဲ့ တန်ဖိုး ဘယ်လိုပဲရှိနေနေ၊ ဘယ် appကို မဆို အပြင် သိုလှောင်ခန်းသို့ ရေးသားခွင့် ပေးတယ်"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"လုပ်ဆောင်ချက်များ ဆိုက်ညှိရနိုင်ရန် လုပ်ခိုင်းပါ"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"မန်နီးဖက်စ် တန်ဖိုးမရွေး၊ လုပ်ဆောင်ချက် အားလုံး ဆိုက်ညှိရနိုင်အောင် လုပ်ပေးပါ။"</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"အခမဲ့ပုံစံ ဝင်းဒိုးကို ဖွင့်ပါ"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"စမ်းသပ်မှု အခမဲ့ပုံစံ ဝင်းဒိုးများအတွက် ပံ့ပိုးမှုကို ဖွင့်ပါ။"</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Desktop အရန်စကားဝှက်"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"အလုပ်ခုံတွင် အရန်သိမ်းဆည်းခြင်းများကို လောလောဆယ် မကာကွယ်နိုင်ပါ။"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"အလုပ်ခုံ တွင် အရန်သိမ်းဆည်းခြင်းအပြည့်လုပ်ရန် အတွက် စကားဝှက်ဖယ်ရန် သို့ ပြောင်းရန် တို့ထိပါ။"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"အလိုအလျောက်"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<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> USB ဖြင့် အပြည့်အထိ"</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="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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USBဖြင့် အားသွင်းနေ"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"ကြိုးမဲ့ အားသွင်းနေ"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-nb/arrays.xml b/packages/SettingsLib/res/values-nb/arrays.xml
index 0877f5c..8311db3 100644
--- a/packages/SettingsLib/res/values-nb/arrays.xml
+++ b/packages/SettingsLib/res/values-nb/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Bruk alltid HDCP-kontroll"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 kB"</item>
-    <item msgid="505611754508988476">"256 kB"</item>
-    <item msgid="6361286924268716397">"1 MB"</item>
-    <item msgid="6405203239560695266">"4 MB"</item>
-    <item msgid="3025431211013424097">"16 MB"</item>
+    <item msgid="8665206199209698501">"Av"</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="524799395770610154">"64 000"</item>
-    <item msgid="3534782711045262344">"256 000"</item>
-    <item msgid="8085867209202153403">"1 million"</item>
+    <item msgid="6089470720451068364">"Av"</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="7346595473588765019">"64 kB pr loggbuffer"</item>
-    <item msgid="2822309747675758628">"256 kB pr buffer"</item>
-    <item msgid="6699306198357496731">"1 MB pr loggbuffer"</item>
-    <item msgid="5748528643937500349">"4 MB pr loggbuffer"</item>
-    <item msgid="1978629051085111592">"16 MB pr loggbuffer"</item>
+    <item msgid="6921048829791179331">"Av"</item>
+    <item msgid="2969458029344750262">"64K per loggbuffer"</item>
+    <item msgid="1342285115665698168">"256K per loggbuffer"</item>
+    <item msgid="1314234299552254621">"1M per loggbuffer"</item>
+    <item msgid="3606047780792894151">"4M per loggbuffer"</item>
+    <item msgid="5431354956856655120">"16M per loggbuffer"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animasjon av"</item>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index a496a21..e39cf30 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Tving aktiviteter til å kunne endre størrelse"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Dette gjør at alle aktivitene kan endre størrelse for flervindusmodus, uavhengig av manifestverdier."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Slå på vinduer i fritt format"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Slår på støtte for vinduer i eksperimentelt fritt format."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Passord for sikkerhetskopiering på datamaskin"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Fullstendig sikkerhetskopiering på datamaskin beskyttes ikke for øyeblikket."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Trykk for å endre eller fjerne passordet for fullstendige sikkerhetskopier på datamaskinen"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automatisk"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Fargekorrigering"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – ca. <xliff:g id="TIME">%2$s</xliff:g> igjen"</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> – fulladet om <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> –  fulladet om <xliff:g id="TIME">%2$s</xliff:g> med vekselstrøm"</string>
+    <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>
+    <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>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Lader via USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Lader trådløst"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-ne-rNP/arrays.xml b/packages/SettingsLib/res/values-ne-rNP/arrays.xml
index 99ec881..7468982 100644
--- a/packages/SettingsLib/res/values-ne-rNP/arrays.xml
+++ b/packages/SettingsLib/res/values-ne-rNP/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"सधैँ HDCP जाँच प्रयोग गर्नुहोस्"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <item msgid="8665206199209698501">"निष्क्रिय गर्नुहोस्"</item>
+    <item msgid="1593289376502312923">"६४के"</item>
+    <item msgid="487545340236145324">"२५६के"</item>
+    <item msgid="2423528675294333831">"१एम"</item>
+    <item msgid="180883774509476541">"४एम"</item>
+    <item msgid="2803199102589126938">"१६एम"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"६४K"</item>
-    <item msgid="3534782711045262344">"२५६K"</item>
-    <item msgid="8085867209202153403">"१ मेगा पिक्सेल"</item>
+    <item msgid="6089470720451068364">"निष्क्रिय गर्नुहोस्"</item>
+    <item msgid="4622460333038586791">"६४के"</item>
+    <item msgid="2212125625169582330">"२५६के"</item>
+    <item msgid="1704946766699242653">"१एम"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64K प्रति लग बफर"</item>
-    <item msgid="2822309747675758628">"256K प्रति लग बफर"</item>
-    <item msgid="6699306198357496731">"1M प्रति लग बफर"</item>
-    <item msgid="5748528643937500349">"4M प्रति लग बफर"</item>
-    <item msgid="1978629051085111592">"16M प्रति लग बफर"</item>
+    <item msgid="6921048829791179331">"निष्क्रिय गर्नुहोस्"</item>
+    <item msgid="2969458029344750262">"६४के प्रति लग बफर"</item>
+    <item msgid="1342285115665698168">"२५६के प्रति लग बफर"</item>
+    <item msgid="1314234299552254621">"१एम प्रति लग बफर"</item>
+    <item msgid="3606047780792894151">"४एम प्रति लग बफर"</item>
+    <item msgid="5431354956856655120">"१६एम प्रति लग बफर"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"सजीविकरण बन्द"</item>
diff --git a/packages/SettingsLib/res/values-ne-rNP/strings.xml b/packages/SettingsLib/res/values-ne-rNP/strings.xml
index 5c85c25..b8beecf 100644
--- a/packages/SettingsLib/res/values-ne-rNP/strings.xml
+++ b/packages/SettingsLib/res/values-ne-rNP/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"म्यानिफेेस्टको उपेक्षा गरी, कुनै पनि अनुप्रयोगलाई बाह्य भण्डारणमा लेख्न योग्य बनाउँछ"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"गतिविधिहरू रिसाइज गर्नको लागि बाध्य गर्नुहोस्"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"म्यानिफेेस्ट मानहरूको ख्याल नगरी, बहु-विन्डोको लागि सबै रिसाइज गर्न सकिने गतिविधिहरू बनाउँछ।"</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"फ्रिफर्म विन्डोहरू सक्रिय गर्नुहोस्"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"प्रयोगात्मक फ्रिफर्म विन्डोहरूका लागि समर्थनलाई सक्रिय गर्छ।"</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="2731163425081172638">"डेस्कटप पूर्ण ब्याकअपको लागि पासवर्ड बदल्न वा हटाउन छुनुहोस्"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"स्वचालित"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> AC मा पूर्ण नभए सम्म"</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> USB मा पूर्ण नभए सम्म"</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="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_usb" msgid="2207489369680923929">"USB मा चार्ज गर्दै"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"बिना तार चार्ज गर्दै"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-nl/arrays.xml b/packages/SettingsLib/res/values-nl/arrays.xml
index 7f76bba..48b135d 100644
--- a/packages/SettingsLib/res/values-nl/arrays.xml
+++ b/packages/SettingsLib/res/values-nl/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"HDCP-controle altijd gebruiken"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <item msgid="8665206199209698501">"Uit"</item>
+    <item msgid="1593289376502312923">"64 K"</item>
+    <item msgid="487545340236145324">"256 K"</item>
+    <item msgid="2423528675294333831">"1 M"</item>
+    <item msgid="180883774509476541">"4 M"</item>
+    <item msgid="2803199102589126938">"16 M"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <item msgid="6089470720451068364">"Uit"</item>
+    <item msgid="4622460333038586791">"64 K"</item>
+    <item msgid="2212125625169582330">"256 K"</item>
+    <item msgid="1704946766699242653">"1 M"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64K per logbuffer"</item>
-    <item msgid="2822309747675758628">"256K per logbuffer"</item>
-    <item msgid="6699306198357496731">"1M per logbuffer"</item>
-    <item msgid="5748528643937500349">"4M per logbuffer"</item>
-    <item msgid="1978629051085111592">"16M per logbuffer"</item>
+    <item msgid="6921048829791179331">"Uit"</item>
+    <item msgid="2969458029344750262">"64 K per logbuffer"</item>
+    <item msgid="1342285115665698168">"256 K per logbuffer"</item>
+    <item msgid="1314234299552254621">"1 M per logbuffer"</item>
+    <item msgid="3606047780792894151">"4 M per logbuffer"</item>
+    <item msgid="5431354956856655120">"16 M per logbuffer"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animatie uit"</item>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 1afa444..4873ac3 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Formaat activiteiten geforceerd aanpasbaar maken"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Hiermee wordt het formaat van alle activiteiten aanpasbaar gemaakt, ongeacht de manifestwaarden."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Vensters met vrije vorm inschakelen"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Schakelt ondersteuning in voor vensters met experimentele vrije vorm."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Wachtwoord desktopback-up"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Volledige back-ups naar desktops zijn momenteel niet beveiligd"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Raak dit aan om het wachtwoord voor volledige back-ups naar desktops te wijzigen of te verwijderen"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automatisch"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Kleurcorrectie"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ca. <xliff:g id="TIME">%2$s</xliff:g> resterend"</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> tot vol"</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> tot vol via wisselstroom"</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> tot vol via USB"</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> tot vol via draadloos"</string>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Opladen via USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Draadloos opladen"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-pa-rIN/arrays.xml b/packages/SettingsLib/res/values-pa-rIN/arrays.xml
index fa624a0..d644da6 100644
--- a/packages/SettingsLib/res/values-pa-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-pa-rIN/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"ਹਮੇਸਾਂ HDCP ਜਾਂਚ ਵਰਤੋ"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <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="7346595473588765019">"64K ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
-    <item msgid="2822309747675758628">"256K ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
-    <item msgid="6699306198357496731">"1M ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
-    <item msgid="5748528643937500349">"4M ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
-    <item msgid="1978629051085111592">"16M ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
+    <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>
diff --git a/packages/SettingsLib/res/values-pa-rIN/strings.xml b/packages/SettingsLib/res/values-pa-rIN/strings.xml
index ad3d3ed..61f187d 100644
--- a/packages/SettingsLib/res/values-pa-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-pa-rIN/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ਇੱਕ ਐਪ ਨੂੰ ਬਾਹਰਲੀ ਸਟੋਰੇਜ ਤੇ ਲਿਖਣ ਦੇ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ, ਮੈਨੀਫੈਸਟ ਵੈਲਯੂਜ ਤੇ ਵਿਚਾਰ ਕੀਤੇ ਬਿਨਾਂ"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"ਮੁੜ-ਆਕਾਰ ਬਦਲਣ ਲਈ ਸਰਗਰਮੀਆਂ \'ਤੇ ਜ਼ੋਰ ਦਿਓ"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ਮਲਟੀ-ਵਿੰਡੋ ਲਈ ਸਾਰੀਆਂ ਸਰਗਰਮੀਆਂ ਨੂੰ ਮੁੜ-ਆਕਾਰ ਵਿੱਚ ਲਿਆਉਂਦੀ ਹੈ, ਚਾਹੇ ਮੈਨੀਫੈਸਟ ਵੈਲਯੂਜ਼ ਕੁਝ ਵੀ ਹੋਣ।"</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"freeform windows ਨੂੰ ਯੋਗ ਬਣਾਓ"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ਪ੍ਰਯੋਗਾਤਮਕ freeform windows ਲਈ ਸਮਰਥਨ ਨੂੰ ਯੋਗ ਬਣਾਉਂਦੀ ਹੈ।"</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="2731163425081172638">"ਡੈਸਕਟੌਪ ਪੂਰੇ ਬੈਕਅਪਸ ਲਈ ਪਾਸਵਰਡ ਬਦਲਣ ਜਾਂ ਹਟਾਉਣ ਲਈ ਛੋਹਵੋ"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"ਆਟੋਮੈਟਿਕ"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> AC ਤੇ ਪੂਰਾ ਹੋਣ ਤੱਕ"</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> USB ਤੇ ਪੂਰਾ ਹੋਣ ਤੱਕ"</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="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_usb" msgid="2207489369680923929">"USB ਤੇ ਚਾਰਜਿੰਗ"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"ਵਾਇਰਲੈਸ ਤੌਰ ਤੇ ਚਾਰਜਿੰਗ"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-pl/arrays.xml b/packages/SettingsLib/res/values-pl/arrays.xml
index 8df26cd..3b3e95d 100644
--- a/packages/SettingsLib/res/values-pl/arrays.xml
+++ b/packages/SettingsLib/res/values-pl/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Zawsze używaj sprawdzania HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 KB"</item>
-    <item msgid="505611754508988476">"256 KB"</item>
-    <item msgid="6361286924268716397">"1 MB"</item>
-    <item msgid="6405203239560695266">"4 MB"</item>
-    <item msgid="3025431211013424097">"16 MB"</item>
+    <item msgid="8665206199209698501">"Wył."</item>
+    <item msgid="1593289376502312923">"64 KB"</item>
+    <item msgid="487545340236145324">"256 KB"</item>
+    <item msgid="2423528675294333831">"1 MB"</item>
+    <item msgid="180883774509476541">"4 MB"</item>
+    <item msgid="2803199102589126938">"16 MB"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 KB"</item>
-    <item msgid="3534782711045262344">"256 KB"</item>
-    <item msgid="8085867209202153403">"1 MB"</item>
+    <item msgid="6089470720451068364">"Wył."</item>
+    <item msgid="4622460333038586791">"64 KB"</item>
+    <item msgid="2212125625169582330">"256 KB"</item>
+    <item msgid="1704946766699242653">"1 MB"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 KB/bufor dziennika"</item>
-    <item msgid="2822309747675758628">"256 KB/bufor dziennika"</item>
-    <item msgid="6699306198357496731">"1 MB/bufor dziennika"</item>
-    <item msgid="5748528643937500349">"4 MB/bufor dziennika"</item>
-    <item msgid="1978629051085111592">"16 MB/bufor dziennika"</item>
+    <item msgid="6921048829791179331">"Wył."</item>
+    <item msgid="2969458029344750262">"64 KB/bufor dziennika"</item>
+    <item msgid="1342285115665698168">"256 KB/bufor dziennika"</item>
+    <item msgid="1314234299552254621">"1 MB/bufor dziennika"</item>
+    <item msgid="3606047780792894151">"4 MB/bufor dziennika"</item>
+    <item msgid="5431354956856655120">"16 MB/bufor dziennika"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animacja wyłączona"</item>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index d58070e..9e0abfa 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Wymuś zmianę rozmiaru okien aktywności"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Umożliwia 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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Włącza obsługę eksperymentalnej funkcji dowolnego rozmiaru okien."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Hasło kopii zapasowej"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Pełne kopie zapasowe na komputerze nie są obecnie chronione"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Wybierz, aby zmienić lub usunąć hasło pełnych kopii zapasowych na komputerze stacjonarnym."</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automatycznie"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Korekcja kolorów"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – zostało ok. <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 pełnego naładowania"</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 pełnego naładowania z gniazdka"</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 pełnego naładowania przez USB"</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 pełnego naładowania bezprzewodowo"</string>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Ładowanie przez USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Ład. bezprzewodowe"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/arrays.xml b/packages/SettingsLib/res/values-pt-rBR/arrays.xml
index d8be251..0d94a6d 100644
--- a/packages/SettingsLib/res/values-pt-rBR/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Sempre usar a verificação HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 K"</item>
-    <item msgid="505611754508988476">"256 K"</item>
-    <item msgid="6361286924268716397">"1 M"</item>
-    <item msgid="6405203239560695266">"4 M"</item>
-    <item msgid="3025431211013424097">"16 M"</item>
+    <item msgid="8665206199209698501">"Desativado"</item>
+    <item msgid="1593289376502312923">"64 K"</item>
+    <item msgid="487545340236145324">"256 K"</item>
+    <item msgid="2423528675294333831">"1 M"</item>
+    <item msgid="180883774509476541">"4 M"</item>
+    <item msgid="2803199102589126938">"16 M"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 K"</item>
-    <item msgid="3534782711045262344">"256 K"</item>
-    <item msgid="8085867209202153403">"1 M"</item>
+    <item msgid="6089470720451068364">"Desativado"</item>
+    <item msgid="4622460333038586791">"64 K"</item>
+    <item msgid="2212125625169582330">"256 K"</item>
+    <item msgid="1704946766699242653">"1 M"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64K/buffer de log"</item>
-    <item msgid="2822309747675758628">"256K/buffer de log"</item>
-    <item msgid="6699306198357496731">"1M/buffer de log"</item>
-    <item msgid="5748528643937500349">"4M/buffer de log"</item>
-    <item msgid="1978629051085111592">"16M/buffer de log"</item>
+    <item msgid="6921048829791179331">"Desativado"</item>
+    <item msgid="2969458029344750262">"64 K/buffer de log"</item>
+    <item msgid="1342285115665698168">"256 K/buffer de log"</item>
+    <item msgid="1314234299552254621">"1 M/buffer de log"</item>
+    <item msgid="3606047780792894151">"4 M/buffer de log"</item>
+    <item msgid="5431354956856655120">"16 M/buffer de log"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animação desligada"</item>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 3b28043..db6b326 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Forçar atividades a serem redimensionáveis"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Torna 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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ativa a compatibilidade com janelas de forma livre experimentais."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Senha do backup local"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Os backups completos do computador não estão protegidos no momento"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toque para alterar ou remover a senha de backups completos do desktop"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automático"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Correção de cor"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - cerca de <xliff:g id="TIME">%2$s</xliff:g> restantes"</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> até concluir"</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> até concluir em CA"</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> até concluir via USB"</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> até concluir sem fio"</string>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Carregamento via USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Carregamento sem fio"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/arrays.xml b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
index 693430c..6e84fce 100644
--- a/packages/SettingsLib/res/values-pt-rPT/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Utilizar sempre a verificação HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 K"</item>
-    <item msgid="505611754508988476">"256 K"</item>
-    <item msgid="6361286924268716397">"1 M"</item>
-    <item msgid="6405203239560695266">"4 M"</item>
-    <item msgid="3025431211013424097">"16 M"</item>
+    <item msgid="8665206199209698501">"Desativado"</item>
+    <item msgid="1593289376502312923">"64 K"</item>
+    <item msgid="487545340236145324">"256 K"</item>
+    <item msgid="2423528675294333831">"1 M"</item>
+    <item msgid="180883774509476541">"4 M"</item>
+    <item msgid="2803199102589126938">"16 M"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 K"</item>
-    <item msgid="3534782711045262344">"256 K"</item>
-    <item msgid="8085867209202153403">"1 M"</item>
+    <item msgid="6089470720451068364">"Desativado"</item>
+    <item msgid="4622460333038586791">"64 K"</item>
+    <item msgid="2212125625169582330">"256 K"</item>
+    <item msgid="1704946766699242653">"1 M"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"Mem. int. 64K p rg."</item>
-    <item msgid="2822309747675758628">"Mem. int. 256K p rg"</item>
-    <item msgid="6699306198357496731">"Mem. int. 1M p reg."</item>
-    <item msgid="5748528643937500349">"Mem. int. 4M p reg."</item>
-    <item msgid="1978629051085111592">"Mem. int. 16M p. rg"</item>
+    <item msgid="6921048829791179331">"Desativado"</item>
+    <item msgid="2969458029344750262">"64 K por buffer de registo"</item>
+    <item msgid="1342285115665698168">"256 K por buffer de registo"</item>
+    <item msgid="1314234299552254621">"1 M por buffer de registo"</item>
+    <item msgid="3606047780792894151">"4 M por buffer de registo"</item>
+    <item msgid="5431354956856655120">"16 M por buffer de registo"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animação desativada"</item>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index c5f94cb..2f25ae2 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Forçar as atividades a serem redimensionáveis"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Torna 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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ativa a compatibilidade com janelas de forma livre experimentais."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Palavra-passe cópia do comp."</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"As cópias de segurança completas no ambiente de trabalho não estão atualmente protegidas"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toque para alterar ou remover a palavra-passe para cópias de segurança completas no ambiente de trabalho"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automático"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Correção da cor"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – resta(m) aprox. <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> até ficar completa"</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> até ficar completa através de CA"</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> até ficar completa através de USB"</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> até ficar compl. por rede s/ fios"</string>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"A carregar por USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"A carregar sem fios"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt/arrays.xml b/packages/SettingsLib/res/values-pt/arrays.xml
index d8be251..0d94a6d 100644
--- a/packages/SettingsLib/res/values-pt/arrays.xml
+++ b/packages/SettingsLib/res/values-pt/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Sempre usar a verificação HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 K"</item>
-    <item msgid="505611754508988476">"256 K"</item>
-    <item msgid="6361286924268716397">"1 M"</item>
-    <item msgid="6405203239560695266">"4 M"</item>
-    <item msgid="3025431211013424097">"16 M"</item>
+    <item msgid="8665206199209698501">"Desativado"</item>
+    <item msgid="1593289376502312923">"64 K"</item>
+    <item msgid="487545340236145324">"256 K"</item>
+    <item msgid="2423528675294333831">"1 M"</item>
+    <item msgid="180883774509476541">"4 M"</item>
+    <item msgid="2803199102589126938">"16 M"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 K"</item>
-    <item msgid="3534782711045262344">"256 K"</item>
-    <item msgid="8085867209202153403">"1 M"</item>
+    <item msgid="6089470720451068364">"Desativado"</item>
+    <item msgid="4622460333038586791">"64 K"</item>
+    <item msgid="2212125625169582330">"256 K"</item>
+    <item msgid="1704946766699242653">"1 M"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64K/buffer de log"</item>
-    <item msgid="2822309747675758628">"256K/buffer de log"</item>
-    <item msgid="6699306198357496731">"1M/buffer de log"</item>
-    <item msgid="5748528643937500349">"4M/buffer de log"</item>
-    <item msgid="1978629051085111592">"16M/buffer de log"</item>
+    <item msgid="6921048829791179331">"Desativado"</item>
+    <item msgid="2969458029344750262">"64 K/buffer de log"</item>
+    <item msgid="1342285115665698168">"256 K/buffer de log"</item>
+    <item msgid="1314234299552254621">"1 M/buffer de log"</item>
+    <item msgid="3606047780792894151">"4 M/buffer de log"</item>
+    <item msgid="5431354956856655120">"16 M/buffer de log"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animação desligada"</item>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 3b28043..db6b326 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Forçar atividades a serem redimensionáveis"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Torna 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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ativa a compatibilidade com janelas de forma livre experimentais."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Senha do backup local"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Os backups completos do computador não estão protegidos no momento"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toque para alterar ou remover a senha de backups completos do desktop"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automático"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Correção de cor"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - cerca de <xliff:g id="TIME">%2$s</xliff:g> restantes"</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> até concluir"</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> até concluir em CA"</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> até concluir via USB"</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> até concluir sem fio"</string>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Carregamento via USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Carregamento sem fio"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-ro/arrays.xml b/packages/SettingsLib/res/values-ro/arrays.xml
index f75154f..141f877 100644
--- a/packages/SettingsLib/res/values-ro/arrays.xml
+++ b/packages/SettingsLib/res/values-ro/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Utilizează întotdeauna verificarea HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <item msgid="8665206199209698501">"Dezactivată"</item>
+    <item msgid="1593289376502312923">"64 KB"</item>
+    <item msgid="487545340236145324">"256 KB"</item>
+    <item msgid="2423528675294333831">"1 MB"</item>
+    <item msgid="180883774509476541">"4 MB"</item>
+    <item msgid="2803199102589126938">"16 MB"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 K"</item>
-    <item msgid="3534782711045262344">"256 K"</item>
-    <item msgid="8085867209202153403">"1 M"</item>
+    <item msgid="6089470720451068364">"Dezactivată"</item>
+    <item msgid="4622460333038586791">"64 KB"</item>
+    <item msgid="2212125625169582330">"256 KB"</item>
+    <item msgid="1704946766699242653">"1 MB"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64K/tampon jurnal"</item>
-    <item msgid="2822309747675758628">"256K/tampon jurnal"</item>
-    <item msgid="6699306198357496731">"1M/tampon jurnal"</item>
-    <item msgid="5748528643937500349">"4M/tampon jurnal"</item>
-    <item msgid="1978629051085111592">"16M/tampon jurnal"</item>
+    <item msgid="6921048829791179331">"Dezactivată"</item>
+    <item msgid="2969458029344750262">"64 KB/zonă-tampon de înregistrări în jurnal"</item>
+    <item msgid="1342285115665698168">"256 KB/zonă-tampon de înregistrări în jurnal"</item>
+    <item msgid="1314234299552254621">"1 MB/zonă-tampon de înregistrări în jurnal"</item>
+    <item msgid="3606047780792894151">"4 MB/zonă-tampon de înregistrări în jurnal"</item>
+    <item msgid="5431354956856655120">"16 MB/zonă-tampon de înregistrări în jurnal"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animație dezactivată"</item>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index c76faf0..e6a45a7 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Forțați redimensionarea activităților"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permite 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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Activează compatibilitatea pentru ferestrele experimentale cu formă liberă."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Parolă copie rez. desktop"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"În prezent, copiile de rezervă complete pe desktop nu sunt protejate"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Atingeţi pentru a modifica sau pentru a elimina parola pentru copiile de rezervă complete pe desktop"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automat"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Corecția culorii"</string>
     <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_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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Se încarcă prin USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Se încarcă fără fir"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-ru/arrays.xml b/packages/SettingsLib/res/values-ru/arrays.xml
index c8c789e..78965ac 100644
--- a/packages/SettingsLib/res/values-ru/arrays.xml
+++ b/packages/SettingsLib/res/values-ru/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Всегда использовать проверку HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 КБ"</item>
-    <item msgid="505611754508988476">"256 КБ"</item>
-    <item msgid="6361286924268716397">"1 МБ"</item>
-    <item msgid="6405203239560695266">"4 МБ"</item>
-    <item msgid="3025431211013424097">"16 МБ"</item>
+    <item msgid="8665206199209698501">"Выкл."</item>
+    <item msgid="1593289376502312923">"64 КБ"</item>
+    <item msgid="487545340236145324">"256 КБ"</item>
+    <item msgid="2423528675294333831">"1 МБ"</item>
+    <item msgid="180883774509476541">"4 МБ"</item>
+    <item msgid="2803199102589126938">"16 МБ"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 КБ"</item>
-    <item msgid="3534782711045262344">"256 КБ"</item>
-    <item msgid="8085867209202153403">"1 МБ"</item>
+    <item msgid="6089470720451068364">"Выкл."</item>
+    <item msgid="4622460333038586791">"64 КБ"</item>
+    <item msgid="2212125625169582330">"256 КБ"</item>
+    <item msgid="1704946766699242653">"1 МБ"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"Буфер: макс. 64 КБ"</item>
-    <item msgid="2822309747675758628">"Буфер: макс. 256 КБ"</item>
-    <item msgid="6699306198357496731">"Буфер: макс. 1 МБ"</item>
-    <item msgid="5748528643937500349">"Буфер: макс. 4 МБ"</item>
-    <item msgid="1978629051085111592">"Буфер: макс. 16 МБ"</item>
+    <item msgid="6921048829791179331">"Выкл."</item>
+    <item msgid="2969458029344750262">"Буфер: макс. 64 КБ"</item>
+    <item msgid="1342285115665698168">"Буфер: макс. 256 КБ"</item>
+    <item msgid="1314234299552254621">"Буфер: макс. 1 МБ"</item>
+    <item msgid="3606047780792894151">"Буфер: макс. 4 МБ"</item>
+    <item msgid="5431354956856655120">"Буфер: макс. 16 МБ"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Без анимации"</item>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index f1cd182..2bb3fdb3 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Разрешает сохранение приложений на внешние накопители независимо от значения манифеста"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Изменение размера в многооконном режиме"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Позволяет менять размер в многооконном режиме (независимо от значений манифеста)"</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Разрешить создание окон произвольной формы"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Включить экспериментальную функцию создания окон произвольной формы"</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="2731163425081172638">"Изменить или удалить пароль для резервного копирования"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Автоматическое переключение"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<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> до полной зарядки (через USB)"</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="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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Зарядка через USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Беспроводная зарядка"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-si-rLK/arrays.xml b/packages/SettingsLib/res/values-si-rLK/arrays.xml
index 564ecee..ab30e45 100644
--- a/packages/SettingsLib/res/values-si-rLK/arrays.xml
+++ b/packages/SettingsLib/res/values-si-rLK/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"සැමවිටම HDCP පිරික්සුම භාවිතා කරන්න"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <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="7346595473588765019">"ලොග අන්තරාවකට 64K"</item>
-    <item msgid="2822309747675758628">"ලොග අන්තරාවකට 256K"</item>
-    <item msgid="6699306198357496731">"ලොග අන්තරාවකට 1M"</item>
-    <item msgid="5748528643937500349">"ලොග අන්තරාවකට 4M"</item>
-    <item msgid="1978629051085111592">"ලොග අන්තරාවකට 16M"</item>
+    <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>
diff --git a/packages/SettingsLib/res/values-si-rLK/strings.xml b/packages/SettingsLib/res/values-si-rLK/strings.xml
index eb13ce4..bd9426c 100644
--- a/packages/SettingsLib/res/values-si-rLK/strings.xml
+++ b/packages/SettingsLib/res/values-si-rLK/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"මැනිෆෙස්ට් අගයන් නොසලකා, ඕනෑම යෙදුමක් අභ්‍යන්තර ගබඩාවට ලිවීමට සුදුසුකම් ලබා දෙයි"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"ක්‍රියාකාරකම් ප්‍රතිප්‍රමාණ කළ හැකි බවට බල කරන්න"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"මැනිෆෙස්ට් අගයන් නොසලකා, සියලු ක්‍රියාකාරකම් බහු-කවුළු සඳහා ප්‍රතිප්‍රමාණ කළ හැකි බවට පත් කරයි."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"අනියම් හැඩැති කවුළු සබල කරන්න"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"පරීක්ෂණාත්මක අනියම් හැඩැති කවුළු සඳහා සහාය සබල කරයි."</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="2731163425081172638">"ඩෙස්ක්ටොප් සම්පූර්ණ උපස්ථ සඳහා මුරපදය වෙනස් කිරීමට හෝ ඉවත් කිරීමට ස්පර්ශ කරන්න"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"ස්වයංක්‍රීය"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"AC හි <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">"USB හරහ <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="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_usb" msgid="2207489369680923929">"USB හරහා ආරෝපණය වෙමින්"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"රැහැන් රහිතව ආරෝපණය වෙමින්"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-sk/arrays.xml b/packages/SettingsLib/res/values-sk/arrays.xml
index ec33e63..9a56e78 100644
--- a/packages/SettingsLib/res/values-sk/arrays.xml
+++ b/packages/SettingsLib/res/values-sk/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Vždy používať kontrolu HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 kB"</item>
-    <item msgid="505611754508988476">"256 kB"</item>
-    <item msgid="6361286924268716397">"1 MB"</item>
-    <item msgid="6405203239560695266">"4 MB"</item>
-    <item msgid="3025431211013424097">"16 MB"</item>
+    <item msgid="8665206199209698501">"Vypnuté"</item>
+    <item msgid="1593289376502312923">"64 kB"</item>
+    <item msgid="487545340236145324">"256 kB"</item>
+    <item msgid="2423528675294333831">"1 MB"</item>
+    <item msgid="180883774509476541">"4 MB"</item>
+    <item msgid="2803199102589126938">"16 MB"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 kB"</item>
-    <item msgid="3534782711045262344">"256 kB"</item>
-    <item msgid="8085867209202153403">"1 MB"</item>
+    <item msgid="6089470720451068364">"Vypnuté"</item>
+    <item msgid="4622460333038586791">"64 kB"</item>
+    <item msgid="2212125625169582330">"256 kB"</item>
+    <item msgid="1704946766699242653">"1 MB"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 kB na vyrovn. pamäť denníka"</item>
-    <item msgid="2822309747675758628">"256 kB na vyrovn. pamäť denníka"</item>
-    <item msgid="6699306198357496731">"1 MB na vyrovn. pamäť denníka"</item>
-    <item msgid="5748528643937500349">"4 MB na vyrovn. pamäť denníka"</item>
-    <item msgid="1978629051085111592">"16 MB na vyrovn. pamäť denníka"</item>
+    <item msgid="6921048829791179331">"Vypnuté"</item>
+    <item msgid="2969458029344750262">"64 kB na vyrov. pamäť denníka"</item>
+    <item msgid="1342285115665698168">"256 kB na vyrov. pamäť denníka"</item>
+    <item msgid="1314234299552254621">"1 MB na vyrov. pam. denníka"</item>
+    <item msgid="3606047780792894151">"4 MB na vyrov. pamäť denníka"</item>
+    <item msgid="5431354956856655120">"16 MB na vyrov. pamäť denníka"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animácia je vypnutá"</item>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index b5b6d2a..8df02ea 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Vynútiť možnosť zmeny veľkosti aktivít"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Povolenie podpory pre experimentálne okná s voľným tvarom."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Heslo pre zálohy v počítači"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Úplné zálohy na počítači nie sú momentálne chránené"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Dotykom zmeníte alebo odstránite heslo pre úplné zálohy do počítača"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automatický"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Úprava farieb"</string>
     <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_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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Nabíjanie cez USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Bezdrôtové nabíjanie"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-sl/arrays.xml b/packages/SettingsLib/res/values-sl/arrays.xml
index 253f113..11b2bab 100644
--- a/packages/SettingsLib/res/values-sl/arrays.xml
+++ b/packages/SettingsLib/res/values-sl/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Vedno uporabi preverjanje HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 K"</item>
-    <item msgid="505611754508988476">"256 K"</item>
-    <item msgid="6361286924268716397">"1 M"</item>
-    <item msgid="6405203239560695266">"4 M"</item>
-    <item msgid="3025431211013424097">"16 M"</item>
+    <item msgid="8665206199209698501">"Izklopljeno"</item>
+    <item msgid="1593289376502312923">"64 K"</item>
+    <item msgid="487545340236145324">"256 K"</item>
+    <item msgid="2423528675294333831">"1 M"</item>
+    <item msgid="180883774509476541">"4 M"</item>
+    <item msgid="2803199102589126938">"16 M"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 K"</item>
-    <item msgid="3534782711045262344">"256 K"</item>
-    <item msgid="8085867209202153403">"1 M"</item>
+    <item msgid="6089470720451068364">"Izklopljeno"</item>
+    <item msgid="4622460333038586791">"64 K"</item>
+    <item msgid="2212125625169582330">"256 K"</item>
+    <item msgid="1704946766699242653">"1 M"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 K/medpom. dnevn."</item>
-    <item msgid="2822309747675758628">"256 K/medpom. dnev."</item>
-    <item msgid="6699306198357496731">"1 M/medpom. dnevn."</item>
-    <item msgid="5748528643937500349">"4 M/medpom. dnevn."</item>
-    <item msgid="1978629051085111592">"16 M/medpom. dnevn."</item>
+    <item msgid="6921048829791179331">"Izklopljeno"</item>
+    <item msgid="2969458029344750262">"64 K/medpomnilnik dnevnika"</item>
+    <item msgid="1342285115665698168">"256 K/medpomnilnik dnevnika"</item>
+    <item msgid="1314234299552254621">"1 M/medpomnilnik dnevnika"</item>
+    <item msgid="3606047780792894151">"4 M/medpomnilnik dnevnika"</item>
+    <item msgid="5431354956856655120">"16 M/medpomnilnik dnevnika"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animacija je izključena"</item>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index cb107d7..57495e6 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Vsili povečanje velikosti za aktivnosti"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Omogočanje podpore za poskusna okna svobodne oblike"</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Geslo za varn. kop. rač."</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Popolne varnostne kopije namizja trenutno niso zaščitene"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Dotaknite se, če želite spremeniti ali odstraniti geslo za popolno varnostno kopiranje namizja."</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Samodejno"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Popravljanje barv"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – še približno <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 napolnjenosti"</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 napolnjenosti prek napajalnika"</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 napolnjenosti prek USB-ja"</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 napolnjenosti prek brezž. pol."</string>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Polnj. prek USB-ja"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Brezžično polnjenje"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-sq-rAL/arrays.xml b/packages/SettingsLib/res/values-sq-rAL/arrays.xml
index 7473f16..0f0efb8 100644
--- a/packages/SettingsLib/res/values-sq-rAL/arrays.xml
+++ b/packages/SettingsLib/res/values-sq-rAL/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Përdor gjithmonë kontrollin e HDCP-së"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1 M"</item>
-    <item msgid="6405203239560695266">"4 M"</item>
-    <item msgid="3025431211013424097">"16 M"</item>
+    <item msgid="8665206199209698501">"Joaktiv"</item>
+    <item msgid="1593289376502312923">"64 mijë"</item>
+    <item msgid="487545340236145324">"256 mijë"</item>
+    <item msgid="2423528675294333831">"1 milion"</item>
+    <item msgid="180883774509476541">"4 milionë"</item>
+    <item msgid="2803199102589126938">"16 milionë"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1 M"</item>
+    <item msgid="6089470720451068364">"Joaktiv"</item>
+    <item msgid="4622460333038586791">"64 mijë"</item>
+    <item msgid="2212125625169582330">"256 mijë"</item>
+    <item msgid="1704946766699242653">"1 milion"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 mijë / memorie regjistrimi"</item>
-    <item msgid="2822309747675758628">"256K për çdo memorie të përkohshme"</item>
-    <item msgid="6699306198357496731">"1 M për memorien e regjistrit"</item>
-    <item msgid="5748528643937500349">"4 M për memorien e regjistrit"</item>
-    <item msgid="1978629051085111592">"16 M për memorien e regjistrit"</item>
+    <item msgid="6921048829791179331">"Joaktiv"</item>
+    <item msgid="2969458029344750262">"64 mijë/memorie regjistrimi"</item>
+    <item msgid="1342285115665698168">"256 mijë/memorie regjistrimi"</item>
+    <item msgid="1314234299552254621">"1 milion/memorie regjistrimi"</item>
+    <item msgid="3606047780792894151">"4 milionë/memorie regjistrimi"</item>
+    <item msgid="5431354956856655120">"16 milionë/memorie regjistrimi"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animacioni është i çaktivizuar"</item>
diff --git a/packages/SettingsLib/res/values-sq-rAL/strings.xml b/packages/SettingsLib/res/values-sq-rAL/strings.xml
index c176f18..1835b39 100644
--- a/packages/SettingsLib/res/values-sq-rAL/strings.xml
+++ b/packages/SettingsLib/res/values-sq-rAL/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Detyro madhësinë e ndryshueshme për aktivitetet"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Bën 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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktivizon mbështetjen për dritaret eksperimentale me formë të lirë."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Fjalëkalimi rezervë i kompjuterit"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Rezervimet e plota në kompjuter nuk janë të mbrojtura aktualisht"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Prek për të ndryshuar ose hequr fjalëkalimin për rezervime të plota të desktopit"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automatike"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Korrigjimi i ngjyrës"</string>
     <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_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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Po ngarkohet me USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Po ngarkohet me valë"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-sr/arrays.xml b/packages/SettingsLib/res/values-sr/arrays.xml
index cd44e15..2389339 100644
--- a/packages/SettingsLib/res/values-sr/arrays.xml
+++ b/packages/SettingsLib/res/values-sr/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Увек користи HDCP проверу"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 kB"</item>
-    <item msgid="505611754508988476">"256 kB"</item>
-    <item msgid="6361286924268716397">"1 MB"</item>
-    <item msgid="6405203239560695266">"4 MB"</item>
-    <item msgid="3025431211013424097">"16 MB"</item>
+    <item msgid="8665206199209698501">"Искључено"</item>
+    <item msgid="1593289376502312923">"64 kB"</item>
+    <item msgid="487545340236145324">"256 kB"</item>
+    <item msgid="2423528675294333831">"1 MB"</item>
+    <item msgid="180883774509476541">"4 MB"</item>
+    <item msgid="2803199102589126938">"16 MB"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 kB"</item>
-    <item msgid="3534782711045262344">"256 kB"</item>
-    <item msgid="8085867209202153403">"1 MB"</item>
+    <item msgid="6089470720451068364">"Искључено"</item>
+    <item msgid="4622460333038586791">"64 kB"</item>
+    <item msgid="2212125625169582330">"256 kB"</item>
+    <item msgid="1704946766699242653">"1 MB"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 kB по баферу евиденције"</item>
-    <item msgid="2822309747675758628">"256 kB по баферу евиденције"</item>
-    <item msgid="6699306198357496731">"1 MB по баферу евиденције"</item>
-    <item msgid="5748528643937500349">"4 MB по баферу евиденције"</item>
-    <item msgid="1978629051085111592">"16 MB по баферу евиденције"</item>
+    <item msgid="6921048829791179331">"Искључено"</item>
+    <item msgid="2969458029344750262">"64 kB по међумеморији евиденције"</item>
+    <item msgid="1342285115665698168">"256 kB по међумеморији евиденције"</item>
+    <item msgid="1314234299552254621">"1 MB по међумеморији евиденције"</item>
+    <item msgid="3606047780792894151">"4 MB по међумеморији евиденције"</item>
+    <item msgid="5431354956856655120">"16 MB по међумеморији евиденције"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Анимација је искључена"</item>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 6b66094..c39682a 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Омогућава уписивање свих апликација у спољну меморију, без обзира на вредности манифеста"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Принудно омогући промену величине активности"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Омогућава промену величине свих активности за режим са више прозора, без обзира на вредности манифеста."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Омогући прозоре произвољног формата"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Омогућава подршку за експерименталне прозоре произвољног формата."</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="2731163425081172638">"Додирните да бисте променили или уклонили лозинку за прављење резервних копија читавог система на рачунару"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Аутоматски"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<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> док се не напуни преко USB-а"</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="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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Пуњење преко USB-а"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Бежично пуњење"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-sv/arrays.xml b/packages/SettingsLib/res/values-sv/arrays.xml
index 54537f4..cbc7dde 100644
--- a/packages/SettingsLib/res/values-sv/arrays.xml
+++ b/packages/SettingsLib/res/values-sv/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Använd alltid HDCP-kontroll"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 kB"</item>
-    <item msgid="505611754508988476">"256 kB"</item>
-    <item msgid="6361286924268716397">"1 MB"</item>
-    <item msgid="6405203239560695266">"4 MB"</item>
-    <item msgid="3025431211013424097">"16 MB"</item>
+    <item msgid="8665206199209698501">"Av"</item>
+    <item msgid="1593289376502312923">"64 kB"</item>
+    <item msgid="487545340236145324">"256 kB"</item>
+    <item msgid="2423528675294333831">"1 MB"</item>
+    <item msgid="180883774509476541">"4 MB"</item>
+    <item msgid="2803199102589126938">"16 MB"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 kB"</item>
-    <item msgid="3534782711045262344">"256 kB"</item>
-    <item msgid="8085867209202153403">"1 MB"</item>
+    <item msgid="6089470720451068364">"Av"</item>
+    <item msgid="4622460333038586791">"64 kB"</item>
+    <item msgid="2212125625169582330">"256 kB"</item>
+    <item msgid="1704946766699242653">"1 MB"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 kB/loggbuffert"</item>
-    <item msgid="2822309747675758628">"256 kB/loggbuffert"</item>
-    <item msgid="6699306198357496731">"1 MB/loggbuffert"</item>
-    <item msgid="5748528643937500349">"4 MB/loggbuffert"</item>
-    <item msgid="1978629051085111592">"16 MB/loggbuffert"</item>
+    <item msgid="6921048829791179331">"Av"</item>
+    <item msgid="2969458029344750262">"64 kB/loggbuffert"</item>
+    <item msgid="1342285115665698168">"256 kB/loggbuffert"</item>
+    <item msgid="1314234299552254621">"1 MB/loggbuffert"</item>
+    <item msgid="3606047780792894151">"4 MB/loggbuffert"</item>
+    <item msgid="5431354956856655120">"16 MB/loggbuffert"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animering avstängd"</item>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 40e1593..1bdf6b2 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Appen 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="4508217476997182216">"Detta 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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktiverar stöd för experimentella frihandsfönster."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Lösenord för säkerhetskopia av datorn"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"De fullständiga säkerhetskopiorna av datorn är för närvarande inte skyddade"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Tryck om du vill ändra eller ta bort lösenordet för fullständig säkerhetskopiering av datorn"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Automatiskt"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Färgkorrigering"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – ca <xliff:g id="TIME">%2$s</xliff:g> kvar"</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> till fulladdat"</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> till fulladdat via laddare"</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> till fulladdat via USB"</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> till fulladdat via trådlös laddning"</string>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Laddas via USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Laddas trådlöst"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-sw/arrays.xml b/packages/SettingsLib/res/values-sw/arrays.xml
index 450e385..8593fd5 100644
--- a/packages/SettingsLib/res/values-sw/arrays.xml
+++ b/packages/SettingsLib/res/values-sw/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Kila wakati tumia ukakuaji wa HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"K64"</item>
-    <item msgid="505611754508988476">"K256"</item>
-    <item msgid="6361286924268716397">"M1"</item>
-    <item msgid="6405203239560695266">"M4"</item>
-    <item msgid="3025431211013424097">"M16"</item>
+    <item msgid="8665206199209698501">"Imezimwa"</item>
+    <item msgid="1593289376502312923">"K64"</item>
+    <item msgid="487545340236145324">"K256"</item>
+    <item msgid="2423528675294333831">"M1"</item>
+    <item msgid="180883774509476541">"M4"</item>
+    <item msgid="2803199102589126938">"M16"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"K64"</item>
-    <item msgid="3534782711045262344">"K256"</item>
-    <item msgid="8085867209202153403">"M1"</item>
+    <item msgid="6089470720451068364">"Imezimwa"</item>
+    <item msgid="4622460333038586791">"K64"</item>
+    <item msgid="2212125625169582330">"K256"</item>
+    <item msgid="1704946766699242653">"M1"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"K64 kwa kumbukumbu"</item>
-    <item msgid="2822309747675758628">"K256 kwa kumbukumbu"</item>
-    <item msgid="6699306198357496731">"M1 kwa kumbukumbu"</item>
-    <item msgid="5748528643937500349">"M4 kwa kumbukumbu"</item>
-    <item msgid="1978629051085111592">"M16 kwa kumbukumbu"</item>
+    <item msgid="6921048829791179331">"Imezimwa"</item>
+    <item msgid="2969458029344750262">"K64 kwa kila akiba ya kumbukumbu"</item>
+    <item msgid="1342285115665698168">"K256 kwa kila akiba ya kumbukumbu"</item>
+    <item msgid="1314234299552254621">"M1 kwa kila akiba ya kumbukumbu"</item>
+    <item msgid="3606047780792894151">"M4 kwa kila akiba ya kumbukumbu"</item>
+    <item msgid="5431354956856655120">"M16 kwa kila akiba ya kumbukumbu"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Haiwani imezimwa"</item>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index a014e1d..9cf0db7 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Huweka programu kwenye hifadhi ya nje, bila kujali maelezo"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Lazimisha shughuli ziweze kubadilishwa ukubwa"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Fanya shughuli zote ziweze kubadilishwa ukubwa kwa ajili ya dirisha nyingi, bila kujali thamani za faili ya maelezo."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Washa madirisha yenye muundo huru"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Huwasha uwezo wa kutumia madirisha ya majaribio yenye muundo huru."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Nenosiri la hifadhi rudufu ya eneo kazi"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Hifadhi rudufu kamili za eneo kazi hazijalindwa kwa sasa"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Gusa ili ubadilishe au uondoe nenosiri la hifadhi rudufu kamili za eneo kazi"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Otomatiki"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Usahihishaji wa rangi"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - imesalia takriban <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> - imesalia <xliff:g id="TIME">%2$s</xliff:g> hadi ijae"</string>
+    <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>
+    <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>
+    <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>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Inachaji kupitia USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Inachaji bila kutumia waya"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-ta-rIN/arrays.xml b/packages/SettingsLib/res/values-ta-rIN/arrays.xml
index ad42159..18deff3 100644
--- a/packages/SettingsLib/res/values-ta-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-ta-rIN/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"HDCP சரிபார்ப்பை எப்போதும் பயன்படுத்து"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <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="7346595473588765019">"64K / லாக் பஃபர்"</item>
-    <item msgid="2822309747675758628">"256K / லாக் பஃபர்"</item>
-    <item msgid="6699306198357496731">"1M / லாக் பஃபர்"</item>
-    <item msgid="5748528643937500349">"4M / லாக் பஃபர்"</item>
-    <item msgid="1978629051085111592">"16M / லாக் பஃபர்"</item>
+    <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>
diff --git a/packages/SettingsLib/res/values-ta-rIN/strings.xml b/packages/SettingsLib/res/values-ta-rIN/strings.xml
index 4f6ea57..c21db5b 100644
--- a/packages/SettingsLib/res/values-ta-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ta-rIN/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"மேனிஃபெஸ்ட் மதிப்புகளை பொருட்படுத்தாமல், எந்தப் பயன்பாட்டையும் வெளிப்புற சேமிப்பிடத்தில் எழுத அனுமதிக்கும்"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"செயல்பாடுகளை அளவுமாறக்கூடியதாக அமை"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"மேனிஃபெஸ்ட் மதிப்புகளைப் பொருட்படுத்தாமல், பல சாளரத்திற்கு எல்லா செயல்பாடுகளையும் அளவுமாறக்கூடியதாக அமைக்கும்."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"குறிப்பிட்ட வடிவமில்லாத சாளரங்களை இயக்கு"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"பரிசோதனைக்குரிய குறிப்பிட்ட வடிவமில்லாத சாளரங்களுக்கான ஆதரவை இயக்கும்."</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="2731163425081172638">"டெஸ்க்டாப்பின் முழுமையான காப்புப்பிரதிகளுக்கான கடவுச்சொல்லை மாற்றுவதற்கு அல்லது அகற்றுவதற்குத் தொடவும்"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"தானியங்கு"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"தோராயம்: <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_ac" msgid="3969186192576594254">"முழு AC சார்ஜிற்கு: <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">"முழு USB சார்ஜிற்கு: <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="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_usb" msgid="2207489369680923929">"USB மூலம் சார்ஜாகிறது"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"வயர்லெஸில் சார்ஜாகிறது"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-te-rIN/arrays.xml b/packages/SettingsLib/res/values-te-rIN/arrays.xml
index 9287aba..3ba0dc7 100644
--- a/packages/SettingsLib/res/values-te-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-te-rIN/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"ఎప్పటికీ HDCP తనిఖీని ఉపయోగించు"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <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="7346595473588765019">"లాగ్ బఫర్‌కి 64K"</item>
-    <item msgid="2822309747675758628">"లాగ్ బఫర్‌కి 256K"</item>
-    <item msgid="6699306198357496731">"లాగ్ బఫర్‌కి 1M"</item>
-    <item msgid="5748528643937500349">"లాగ్ బఫర్‌కి 4M"</item>
-    <item msgid="1978629051085111592">"లాగ్ బఫర్‌కి 16M"</item>
+    <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>
diff --git a/packages/SettingsLib/res/values-te-rIN/strings.xml b/packages/SettingsLib/res/values-te-rIN/strings.xml
index a6d2140..04f0ca0 100644
--- a/packages/SettingsLib/res/values-te-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-te-rIN/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ఏ అనువర్తనాన్ని అయినా మానిఫెస్ట్ విలువలతో సంబంధం లేకుండా బాహ్య నిల్వలో వ్రాయగలిగేలా అనుమతిస్తుంది"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"కార్యాచరణలను పరిమాణం మార్చగలిగేలా నిర్బంధించు"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"మానిఫెస్ట్ విలువలతో సంబంధం లేకుండా అన్ని కార్యాచరణలను బహుళ విండోల్లో సరిపోయేటట్లు పరిమాణం మార్చగలిగేలా చేస్తుంది."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"స్వతంత్ర రూప విండోలను ప్రారంభించండి"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ప్రయోగాత్మక స్వతంత్ర రూప విండోలకు మద్దతును ప్రారంభిస్తుంది."</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="2731163425081172638">"డెస్క్‌టాప్ పూర్తి బ్యాకప్‌ల కోసం పాస్‌వర్డ్‌ను మార్చడానికి లేదా తీసివేయడానికి తాకండి"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"స్వయంచాలకం"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_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_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_wireless" msgid="1829295708243159464">"<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_usb" msgid="2207489369680923929">"USB ద్వారా ఛార్జ్ అవుతోంది"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"వైర్‌లెస్‌ ద్వారా ఛార్జ్ అవుతోంది"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-th/arrays.xml b/packages/SettingsLib/res/values-th/arrays.xml
index 43d2739..4282975 100644
--- a/packages/SettingsLib/res/values-th/arrays.xml
+++ b/packages/SettingsLib/res/values-th/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"ใช้การตรวจสอบ HDCP เสมอ"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 K"</item>
-    <item msgid="505611754508988476">"256 K"</item>
-    <item msgid="6361286924268716397">"1 M"</item>
-    <item msgid="6405203239560695266">"4 M"</item>
-    <item msgid="3025431211013424097">"16 M"</item>
+    <item msgid="8665206199209698501">"ปิด"</item>
+    <item msgid="1593289376502312923">"64 K"</item>
+    <item msgid="487545340236145324">"256 K"</item>
+    <item msgid="2423528675294333831">"1 M"</item>
+    <item msgid="180883774509476541">"4 M"</item>
+    <item msgid="2803199102589126938">"16 M"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 K"</item>
-    <item msgid="3534782711045262344">"256 K"</item>
-    <item msgid="8085867209202153403">"1 M"</item>
+    <item msgid="6089470720451068364">"ปิด"</item>
+    <item msgid="4622460333038586791">"64 K"</item>
+    <item msgid="2212125625169582330">"256 K"</item>
+    <item msgid="1704946766699242653">"1 M"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"64 K ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
-    <item msgid="2822309747675758628">"256 K ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
-    <item msgid="6699306198357496731">"1 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
-    <item msgid="5748528643937500349">"4 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
-    <item msgid="1978629051085111592">"16 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
+    <item msgid="6921048829791179331">"ปิด"</item>
+    <item msgid="2969458029344750262">"64 K ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
+    <item msgid="1342285115665698168">"256 K ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
+    <item msgid="1314234299552254621">"1 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
+    <item msgid="3606047780792894151">"4 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
+    <item msgid="5431354956856655120">"16 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"ปิดภาพเคลื่อนไหว"</item>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index de2f33d..acde81e 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ให้สามารถเขียนแอปต่างๆ ไปยังที่เก็บภายนอกได้ โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"บังคับให้กิจกรรมปรับขนาดได้"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ทำให้กิจกรรมทั้งหมดปรับขนาดได้สำหรับหน้าต่างหลายบาน โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"เปิดใช้หน้าต่างรูปแบบอิสระ"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"เปิดการสนับสนุนหน้าต่างรูปแบบอิสระแบบทดลอง"</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="2731163425081172638">"แตะเพื่อเปลี่ยนหรือลบรหัสผ่านสำหรับการสำรองข้อมูลเต็มรูปแบบในเดสก์ท็อป"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"อัตโนมัติ"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> จนกว่าจะเต็มเมื่อชาร์จผ่าน AC"</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> จนกว่าจะเต็มเมื่อชาร์จผ่าน USB"</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="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_usb" msgid="2207489369680923929">"กำลังชาร์จผ่าน USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"กำลังชาร์จแบบไร้สาย"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-tl/arrays.xml b/packages/SettingsLib/res/values-tl/arrays.xml
index c7cf6d2..a7fb68c 100644
--- a/packages/SettingsLib/res/values-tl/arrays.xml
+++ b/packages/SettingsLib/res/values-tl/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Palaging gumamit ng pagsusuring HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <item msgid="8665206199209698501">"I-off"</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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <item msgid="6089470720451068364">"I-off"</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="7346595473588765019">"64K kada log buffer"</item>
-    <item msgid="2822309747675758628">"256K kada log buffer"</item>
-    <item msgid="6699306198357496731">"1M kada log buffer"</item>
-    <item msgid="5748528643937500349">"4M kada log buffer"</item>
-    <item msgid="1978629051085111592">"16M kada log buffer"</item>
+    <item msgid="6921048829791179331">"I-off"</item>
+    <item msgid="2969458029344750262">"64K kada log buffer"</item>
+    <item msgid="1342285115665698168">"256K kada log buffer"</item>
+    <item msgid="1314234299552254621">"1M kada log buffer"</item>
+    <item msgid="3606047780792894151">"4M kada log buffer"</item>
+    <item msgid="5431354956856655120">"16M kada log buffer"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Naka-off ang animation"</item>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 231079b..7e856e85 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Sapilitang gawing resizable ang mga aktibidad"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Gawing resizable para sa multi-window ang lahat ng aktibidad, anuman ang mga manifest value."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"I-enable ang mga freeform window"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ine-enable ang suporta para sa mga pang-eksperimentong freeform window."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Password ng pag-backup ng desktop"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Kasalukuyang hindi pinoprotektahan ang mga buong pag-backup ng desktop"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Pindutin upang baguhin o alisin ang password para sa mga buong pag-backup ng desktop"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Awtomatiko"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Pagtatama ng kulay"</string>
     <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_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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Nagcha-charge sa USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Wireless nag-charge"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-tr/arrays.xml b/packages/SettingsLib/res/values-tr/arrays.xml
index 9326903..0bae437 100644
--- a/packages/SettingsLib/res/values-tr/arrays.xml
+++ b/packages/SettingsLib/res/values-tr/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"HDCP denetimini her zaman kullan"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 KB"</item>
-    <item msgid="505611754508988476">"256 KB"</item>
-    <item msgid="6361286924268716397">"1 MB"</item>
-    <item msgid="6405203239560695266">"4 MB"</item>
-    <item msgid="3025431211013424097">"16 MB"</item>
+    <item msgid="8665206199209698501">"Kapalı"</item>
+    <item msgid="1593289376502312923">"64 KB"</item>
+    <item msgid="487545340236145324">"256 KB"</item>
+    <item msgid="2423528675294333831">"1 MB"</item>
+    <item msgid="180883774509476541">"4 MB"</item>
+    <item msgid="2803199102589126938">"16 MB"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 KB"</item>
-    <item msgid="3534782711045262344">"256 KB"</item>
-    <item msgid="8085867209202153403">"1 MB"</item>
+    <item msgid="6089470720451068364">"Kapalı"</item>
+    <item msgid="4622460333038586791">"64 KB"</item>
+    <item msgid="2212125625169582330">"256 KB"</item>
+    <item msgid="1704946766699242653">"1 MB"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"Günlük arabelleği başına 64 KB"</item>
-    <item msgid="2822309747675758628">"Günlük arabelleği başına 256 KB"</item>
-    <item msgid="6699306198357496731">"Günlük arabelleği başına 1 MB"</item>
-    <item msgid="5748528643937500349">"Günlük arabelleği başına 4 MB"</item>
-    <item msgid="1978629051085111592">"Günlük arabelleği başına 16 MB"</item>
+    <item msgid="6921048829791179331">"Kapalı"</item>
+    <item msgid="2969458029344750262">"Günlük arabelleği başına 64 KB"</item>
+    <item msgid="1342285115665698168">"Günlük arabelleği başına 256 KB"</item>
+    <item msgid="1314234299552254621">"Günlük arabelleği başına 1 MB"</item>
+    <item msgid="3606047780792894151">"Günlük arabelleği başına 4 MB"</item>
+    <item msgid="5431354956856655120">"Günlük arabelleği başına 16 MB"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animasyon kapalı"</item>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index c44d7f8..8577f7d 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Etkinlikleri yeniden boyutlandırılabilmeye zorla"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Manifest değerlerinden bağımsız olarak, tüm etkinlikleri birden fazla pencerede yeniden boyutlandırılabilir hale getirir."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Serbest biçimli pencereleri etkinleştir"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Deneysel serbest biçimli pencereleri etkinleştirir."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Masaüstü yedekleme şifresi"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Masaüstü tam yedeklemeleri şu an korunmuyor"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Masaüstü tam yedeklemelerinin şifresini değiştirmek veya kaldırmak için dokunun"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Otomatik"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Renk düzeltme"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - yaklaşık <xliff:g id="TIME">%2$s</xliff:g> kaldı"</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> - tam şarj olmasına <xliff:g id="TIME">%2$s</xliff:g> var"</string>
+    <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>
+    <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>
+    <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>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"USB ile şarj oluyor"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Kablosuz şarj oluyor"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-uk/arrays.xml b/packages/SettingsLib/res/values-uk/arrays.xml
index 6cccc8c..0786ac3 100644
--- a/packages/SettingsLib/res/values-uk/arrays.xml
+++ b/packages/SettingsLib/res/values-uk/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Завжди використовувати перевірку HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 Кб"</item>
-    <item msgid="505611754508988476">"256 Кб"</item>
-    <item msgid="6361286924268716397">"1 Мб"</item>
-    <item msgid="6405203239560695266">"4 Мб"</item>
-    <item msgid="3025431211013424097">"16 Мб"</item>
+    <item msgid="8665206199209698501">"Вимкнено"</item>
+    <item msgid="1593289376502312923">"64 Кб"</item>
+    <item msgid="487545340236145324">"256 Кб"</item>
+    <item msgid="2423528675294333831">"1 Мб"</item>
+    <item msgid="180883774509476541">"4 Мб"</item>
+    <item msgid="2803199102589126938">"16 Мб"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 Кб"</item>
-    <item msgid="3534782711045262344">"256 Кб"</item>
-    <item msgid="8085867209202153403">"1 Мб"</item>
+    <item msgid="6089470720451068364">"Вимкнено"</item>
+    <item msgid="4622460333038586791">"64 Кб"</item>
+    <item msgid="2212125625169582330">"256 Кб"</item>
+    <item msgid="1704946766699242653">"1 Мб"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"Буфер: макс. 64 Кб"</item>
-    <item msgid="2822309747675758628">"Буфер: макс. 256 Кб"</item>
-    <item msgid="6699306198357496731">"Буфер: макс. 1 Мб"</item>
-    <item msgid="5748528643937500349">"Буфер: макс. 4 Мб"</item>
-    <item msgid="1978629051085111592">"Буфер: макс. 16 Мб"</item>
+    <item msgid="6921048829791179331">"Вимкнено"</item>
+    <item msgid="2969458029344750262">"Буфер журналу: 64 Кб"</item>
+    <item msgid="1342285115665698168">"Буфер журналу: 256 Кб"</item>
+    <item msgid="1314234299552254621">"Буфер журналу: 1 Мб"</item>
+    <item msgid="3606047780792894151">"Буфер журналу: 4 Мб"</item>
+    <item msgid="5431354956856655120">"Буфер журналу: 16 Мб"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Анімацію вимкнено"</item>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index d5dbe90..3e89cce 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Додатки можна записувати на зовнішню пам’ять незалежно від значень маніфесту"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Примусово масштабувати активність"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Активність масштабуватиметься на кілька вікон, незалежно від значень у файлі маніфесту."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Увімкнути вікна довільного формату"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Увімкнуться експериментальні вікна довільного формату."</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="2731163425081172638">"Торкніться, щоб змінити чи видалити пароль для повного резервного копіювання на комп’ютер"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Автоматично"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<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> до повного зарядження через USB"</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="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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Заряджання через USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Заряджання без дроту"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-ur-rPK/arrays.xml b/packages/SettingsLib/res/values-ur-rPK/arrays.xml
index 80fb750..e1fe269 100644
--- a/packages/SettingsLib/res/values-ur-rPK/arrays.xml
+++ b/packages/SettingsLib/res/values-ur-rPK/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"‏ہمیشہ HDCP چیکنگ استعمال کریں"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <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="7346595473588765019">"‏64K فی لاگ بفر"</item>
-    <item msgid="2822309747675758628">"‏256K فی لاگ بفر"</item>
-    <item msgid="6699306198357496731">"‏1M فی لاگ بفر"</item>
-    <item msgid="5748528643937500349">"‏4M فی لاگ بفر"</item>
-    <item msgid="1978629051085111592">"‏16M فی لاگ بفر"</item>
+    <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>
diff --git a/packages/SettingsLib/res/values-ur-rPK/strings.xml b/packages/SettingsLib/res/values-ur-rPK/strings.xml
index 4c9c178..a565ab7 100644
--- a/packages/SettingsLib/res/values-ur-rPK/strings.xml
+++ b/packages/SettingsLib/res/values-ur-rPK/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"‏manifest اقدار سے قطع نظر، کسی بھی ایپ کو بیرونی اسٹوریج پر لکھے جانے کا اہل بناتا ہے"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"سرگرمیوں کو ری سائز ایبل بنائیں"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"‏manifest اقدار سے قطع نظر، ملٹی ونڈو کیلئے تمام سرگرمیوں کو ری سائز ایبل بناتا ہے۔"</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"‏freeform ونڈوز فعال کریں"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"‏تجرباتی freeform ونڈوز کے لئے سپورٹ فعال کرتا ہے۔"</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="2731163425081172638">"ڈیسک ٹاپ کے مکمل بیک اپس کیلئے پاس ورڈ کو تبدیل کرنے یا ہٹانے کیلئے ٹچ کریں"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"خودکار"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"‏‎<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_ac" msgid="3969186192576594254">"‏‎<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> AC‎ پر پورا ہونے تک"</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> USB‎ پر پورا ہونے تک"</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="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_usb" msgid="2207489369680923929">"‏‫USB پر چارج ہورہی ہے"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"وائرلیس چارجنگ"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-uz-rUZ/arrays.xml b/packages/SettingsLib/res/values-uz-rUZ/arrays.xml
index a84c5d5..53d4db7 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/arrays.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Har doim HDCP tekshiruvidan foydalanilsin"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64 KB"</item>
-    <item msgid="505611754508988476">"256 KB"</item>
-    <item msgid="6361286924268716397">"1 MB"</item>
-    <item msgid="6405203239560695266">"4 MB"</item>
-    <item msgid="3025431211013424097">"16 MB"</item>
+    <item msgid="8665206199209698501">"O‘chiq"</item>
+    <item msgid="1593289376502312923">"64 KB"</item>
+    <item msgid="487545340236145324">"256 KB"</item>
+    <item msgid="2423528675294333831">"1 MB"</item>
+    <item msgid="180883774509476541">"4 MB"</item>
+    <item msgid="2803199102589126938">"16 MB"</item>
   </string-array>
   <string-array name="select_logd_size_lowram_titles">
-    <item msgid="524799395770610154">"64 KB"</item>
-    <item msgid="3534782711045262344">"256 KB"</item>
-    <item msgid="8085867209202153403">"1 MB"</item>
+    <item msgid="6089470720451068364">"O‘chiq"</item>
+    <item msgid="4622460333038586791">"64 KB"</item>
+    <item msgid="2212125625169582330">"256 KB"</item>
+    <item msgid="1704946766699242653">"1 MB"</item>
   </string-array>
   <string-array name="select_logd_size_summaries">
-    <item msgid="7346595473588765019">"Bufer: maks. 64 KB"</item>
-    <item msgid="2822309747675758628">"Bufer: maks. 256 KB"</item>
-    <item msgid="6699306198357496731">"Bufer: maks. 1 MB"</item>
-    <item msgid="5748528643937500349">"Bufer: maks. 4 MB"</item>
-    <item msgid="1978629051085111592">"Bufer: maks. 16 MB"</item>
+    <item msgid="6921048829791179331">"O‘chiq"</item>
+    <item msgid="2969458029344750262">"Bufer: maks. 64 KB"</item>
+    <item msgid="1342285115665698168">"Bufer: maks. 256 KB"</item>
+    <item msgid="1314234299552254621">"Bufer: maks. 1 MB"</item>
+    <item msgid="3606047780792894151">"Bufer: maks. 4 MB"</item>
+    <item msgid="5431354956856655120">"Bufer: maks. 16 MB"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Animatsiya o‘chiq"</item>
diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
index d138a28..246287a 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Harakatlarni moslashuvchan o‘lchamga keltirish"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Manifest qiymatidan qat’i nazar barcha harakatlarni ko‘p oynali rejimga moslashtiradi."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Erkin shakldagi oynalarni yoqish"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Tajribaviy erkin shakldagi oynalar ta’minotini yoqadi"</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="2731163425081172638">"Ish stoli to\'liq zaxira nusxalari parolini o‘zgartirish yoki o‘chirish uchun bu yerni bosing."</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Avtomatik"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Rangni tuzatish"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – taxminan <xliff:g id="TIME">%2$s</xliff:g> qoldi"</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>, to‘lguncha"</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>, o‘zgaruvchan tok orqali to‘lguncha"</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>, USB orqali to‘lguncha"</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>, simsiz quvvatlash orqali to‘lguncha"</string>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Quvvat olmoqda (USB)"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Simsiz quvvat olmoqda"</string>
+    <string name="battery_info_status_discharging" msgid="310932812698268588">"Quvvatlantirilmayapti"</string>
+    <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Quvvatlanmayapti"</string>
+    <string name="battery_info_status_full" msgid="2824614753861462808">"To‘la"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-vi/arrays.xml b/packages/SettingsLib/res/values-vi/arrays.xml
index 7c3181f..b03d847 100644
--- a/packages/SettingsLib/res/values-vi/arrays.xml
+++ b/packages/SettingsLib/res/values-vi/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Luôn sử dụng kiểm tra HDCP"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <item msgid="8665206199209698501">"Tắt"</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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <item msgid="6089470720451068364">"Tắt"</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="7346595473588765019">"64K/lần tải nhật ký"</item>
-    <item msgid="2822309747675758628">"256K/lần tải nhật ký"</item>
-    <item msgid="6699306198357496731">"1M/lần tải nhật ký"</item>
-    <item msgid="5748528643937500349">"4M/lần tải nhật ký"</item>
-    <item msgid="1978629051085111592">"16M/lần tải nhật ký"</item>
+    <item msgid="6921048829791179331">"Tắt"</item>
+    <item msgid="2969458029344750262">"64K/lần tải nhật ký"</item>
+    <item msgid="1342285115665698168">"256K/lần tải nhật ký"</item>
+    <item msgid="1314234299552254621">"1M/lần tải nhật ký"</item>
+    <item msgid="3606047780792894151">"4M/lần tải nhật ký"</item>
+    <item msgid="5431354956856655120">"16M/lần tải nhật ký"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Tắt hình động"</item>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 7ab8b02..f07c8a0 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -247,6 +247,8 @@
     <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_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="4508217476997182216">"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>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Bật tính năng hỗ trợ cửa sổ dạng tự do thử nghiệm."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Mật khẩu sao lưu của máy tính"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Sao lưu toàn bộ máy tính hiện không được bảo vệ"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Chạm để thay đổi hoặc xóa mật khẩu dành cho bộ sao lưu toàn bộ tới máy tính"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Tự động"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Sửa màu"</string>
     <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_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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Sạc qua USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Sạc không dây"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/arrays.xml b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
index 1378aaa..d1d8937 100644
--- a/packages/SettingsLib/res/values-zh-rCN/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"始终使用 HDCP 检查"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <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="7346595473588765019">"每个日志缓冲区64K"</item>
-    <item msgid="2822309747675758628">"每个日志缓冲区256K"</item>
-    <item msgid="6699306198357496731">"每个日志缓冲区1M"</item>
-    <item msgid="5748528643937500349">"每个日志缓冲区4M"</item>
-    <item msgid="1978629051085111592">"每个日志缓冲区16M"</item>
+    <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>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 509ff88..5c4f733 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"允许将任何应用写入外部存储设备(无论清单值是什么)"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"强制将活动设为可调整大小"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"将所有活动设为可配合多窗口环境调整大小(无论清单值是什么)。"</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"启用可自由调整的窗口"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"启用可自由调整的窗口这一实验性功能。"</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="2731163425081172638">"触摸可更改或删除用于桌面完整备份的密码"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"自动"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<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>充满(USB充电)"</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="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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"正在通过USB充电"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"正在无线充电"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/arrays.xml b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
index f15caff..a7b0031 100644
--- a/packages/SettingsLib/res/values-zh-rHK/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"永遠使用 HDCP 檢查"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <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="7346595473588765019">"每個記錄緩衝區 64K"</item>
-    <item msgid="2822309747675758628">"每個記錄緩衝區 256K"</item>
-    <item msgid="6699306198357496731">"每個記錄緩衝區 1M"</item>
-    <item msgid="5748528643937500349">"每個記錄緩衝區 4M"</item>
-    <item msgid="1978629051085111592">"每個記錄緩衝區 16M"</item>
+    <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>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index f323667..952b198 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"允許將所有應用程式寫入到外部儲存完間 (所有資訊清單值)"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"強制可變更活動尺寸"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"在任何資訊清單值下,允許為多個視窗變更所有活動的尺寸。"</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"啟用自由形態視窗"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"啟用實驗版自由形態視窗的支援功能。"</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="2731163425081172638">"輕觸即可更改或移除桌上電腦完整備份的密碼"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"自動"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<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> 後完成充電 (透過 USB 充電)"</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="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_usb" msgid="2207489369680923929">"正在透過 USB 充電"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"正在透過無線方式充電"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/arrays.xml b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
index 50bde80..32a2065 100644
--- a/packages/SettingsLib/res/values-zh-rTW/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"一律使用 HDCP 檢查"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <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="7346595473588765019">"每個紀錄緩衝區 64K"</item>
-    <item msgid="2822309747675758628">"每個紀錄緩衝區 256K"</item>
-    <item msgid="6699306198357496731">"每個紀錄緩衝區 1M"</item>
-    <item msgid="5748528643937500349">"每個紀錄緩衝區 4M"</item>
-    <item msgid="1978629051085111592">"每個紀錄緩衝區 16M"</item>
+    <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>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index c6ad832..f66f093 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"允許將任何應用程式寫入外部儲存空間 (無論資訊清單值為何)"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"將活動強制設為可調整大小"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"將所有活動設為可配合多重視窗環境調整大小 (無論資訊清單值為何)。"</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"啟用自由形式視窗"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"啟用實驗版自由形式視窗的支援功能。"</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="2731163425081172638">"輕觸即可變更或移除電腦完整備份的密碼"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"自動"</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="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>
@@ -291,4 +294,18 @@
     <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_discharging_duration" msgid="1605929174734600590">"<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_ac" msgid="3969186192576594254">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>後充飽 (AC)"</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>後充飽 (USB)"</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="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_usb" msgid="2207489369680923929">"正在透過 USB 充電"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"正在透過無線方式充電"</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>
 </resources>
diff --git a/packages/SettingsLib/res/values-zu/arrays.xml b/packages/SettingsLib/res/values-zu/arrays.xml
index eaadce6..2bb849f 100644
--- a/packages/SettingsLib/res/values-zu/arrays.xml
+++ b/packages/SettingsLib/res/values-zu/arrays.xml
@@ -59,23 +59,26 @@
     <item msgid="45075631231212732">"Sebenzisa njalo ukuhlola kwe-HDPC"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
-    <item msgid="3100534874529240291">"64K"</item>
-    <item msgid="505611754508988476">"256K"</item>
-    <item msgid="6361286924268716397">"1M"</item>
-    <item msgid="6405203239560695266">"4M"</item>
-    <item msgid="3025431211013424097">"16M"</item>
+    <item msgid="8665206199209698501">"Valiwe"</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="524799395770610154">"64K"</item>
-    <item msgid="3534782711045262344">"256K"</item>
-    <item msgid="8085867209202153403">"1M"</item>
+    <item msgid="6089470720451068364">"Valiwe"</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="7346595473588765019">"64K ngebhafa yelogu ngayinye"</item>
-    <item msgid="2822309747675758628">"256K ngebhafa yelogu ngayinye"</item>
-    <item msgid="6699306198357496731">"1M ngebhafa yelogu ngayinye"</item>
-    <item msgid="5748528643937500349">"4M ngebhafa yelogu ngayinye"</item>
-    <item msgid="1978629051085111592">"16M ngebhafa yelogu ngayinye"</item>
+    <item msgid="6921048829791179331">"Valiwe"</item>
+    <item msgid="2969458029344750262">"64K ngebhafa yelogu ngayinye"</item>
+    <item msgid="1342285115665698168">"256K ngebhafa yelogu ngayinye"</item>
+    <item msgid="1314234299552254621">"1M ngebhafa yelogu ngayi"</item>
+    <item msgid="3606047780792894151">"4M ngebhafa yelogu ngayinye"</item>
+    <item msgid="5431354956856655120">"16M ngebhafa yelogu ngayinye"</item>
   </string-array>
   <string-array name="window_animation_scale_entries">
     <item msgid="8134156599370824081">"Isithombe esinyakazayo sivliwe"</item>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index cb3670f..f42abbc 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -247,6 +247,8 @@
     <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_resizable_activities" msgid="8615764378147824985">"Imisebenzi yamandla izonikezwa usayizi omusha"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Yenza yonke imisebenzi ibe nosayizi abasha kuwindi lokuningi, ngokunganaki amanani we-manifest."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Nika amandla amawindi e-freeform"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Inika amandla usekelo lwamawindi okuhlola e-freeform."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Iphasiwedi yokusekela ngokulondoloza ye-Desktop"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Ukusekela ngokulondoloza okugcwele kwe-Desktop akuvikelekile okwamanje."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Khetha ukushintsha noma ukususa iphasiwedi yokwenziwa kwezipele ngokugcwele kwideskithophu"</string>
@@ -275,6 +277,7 @@
     <string name="night_mode_auto" msgid="7508348175804304327">"Okuzenzakalelayo"</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="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>
@@ -291,4 +294,18 @@
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Ukulungiswa kombala"</string>
     <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_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - isilinganiso esingu-<xliff:g id="TIME">%2$s</xliff:g> esisele"</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> kuze igcwale"</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> kuze igcwale ku-AC"</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> kuze igcwale ngaphezulu kwe-USB"</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> kuze igcwale kusukela kokungenantambo"</string>
+    <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>
+    <string name="battery_info_status_charging_usb" msgid="2207489369680923929">"Iyashaja ngaphezulu kwe-USB"</string>
+    <string name="battery_info_status_charging_wireless" msgid="3574032603735446573">"Iyashaja ngaphandle kwentambo"</string>
+    <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>
 </resources>
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 4e88c1c..1bce7f9 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -102,6 +102,7 @@
 
     <!-- Titles for logd limit size selection preference. [CHAR LIMIT=14] -->
     <string-array name="select_logd_size_titles">
+        <item>Off</item>
         <item>64K</item>
         <item>256K</item>
         <item>1M</item>
@@ -111,6 +112,7 @@
 
     <!-- Titles for logd limit size lowram selection preference. [CHAR LIMIT=14] -->
     <string-array name="select_logd_size_lowram_titles">
+        <item>Off</item>
         <item>64K</item>
         <item>256K</item>
         <item>1M</item>
@@ -118,6 +120,7 @@
 
     <!-- Values for logd limit size selection preference. -->
     <string-array name="select_logd_size_values" translatable="false" >
+        <item>32768</item>
         <item>65536</item>
         <item>262144</item>
         <item>1048576</item>
@@ -125,8 +128,9 @@
         <item>16777216</item>
     </string-array>
 
-    <!-- Summaries for logd limit size selection preference. [CHAR LIMIT=30]-->
+    <!-- Summaries for logd limit size selection preference. [CHAR LIMIT=50]-->
     <string-array name="select_logd_size_summaries" >
+        <item>Off</item>
         <item>64K per log buffer</item>
         <item>256K per log buffer</item>
         <item>1M per log buffer</item>
diff --git a/packages/SettingsLib/res/values/attrs.xml b/packages/SettingsLib/res/values/attrs.xml
new file mode 100644
index 0000000..3e1fc4a
--- /dev/null
+++ b/packages/SettingsLib/res/values/attrs.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>
+    <declare-styleable name="RestrictedPreference">
+        <attr name="userRestriction" format="string" />
+        <attr name="useAdminDisabledSummary" format="boolean" />
+    </declare-styleable>
+    <declare-styleable name="WifiEncryptionState">
+        <attr name="state_encrypted" format="boolean" />
+    </declare-styleable>
+    <attr name="wifi_signal" format="reference" />
+
+</resources>
diff --git a/packages/SettingsLib/res/values/colors.xml b/packages/SettingsLib/res/values/colors.xml
new file mode 100644
index 0000000..c090468
--- /dev/null
+++ b/packages/SettingsLib/res/values/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="disabled_text_color">#66000000</color> <!-- 38% black -->
+</resources>
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index d7c78f6..811751c 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -31,4 +31,11 @@
     <dimen name="user_spinner_padding">4dp</dimen>
     <dimen name="user_spinner_padding_sides">20dp</dimen>
     <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="wifi_preference_badge_padding">8dip</dimen>
+
 </resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 7e22881..d3c8416 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -624,6 +624,11 @@
     <!-- UI debug setting: force allow on external summary [CHAR LIMIT=150] -->
     <string name="force_resizable_activities_summary">Makes all activities resizable for multi-window, regardless of manifest values.</string>
 
+    <!-- UI debug setting: enable freeform window support [CHAR LIMIT=50] -->
+    <string name="enable_freeform_support">Enable freeform windows</string>
+    <!-- UI debug setting: enable freeform window support summary [CHAR LIMIT=150] -->
+    <string name="enable_freeform_support_summary">Enables support for experimental freeform windows.</string>
+
     <!-- Local (desktop) backup password menu title [CHAR LIMIT=25] -->
     <string name="local_backup_password_title">Desktop backup password</string>
     <!-- Summary text of the "local backup password" setting when the user has not supplied a password -->
@@ -679,6 +684,8 @@
     <string name="select_webview_provider_title">WebView implementation</string>
     <!-- Developer settings: select WebView provider dialog title -->
     <string name="select_webview_provider_dialog_title">Set WebView implementation</string>
+    <!-- Developer settings: confirmation dialog text for the WebView provider selection dialog -->
+    <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 screen, convert userdata to file encryption option name -->
     <string name="convert_to_file_encryption">Convert to file encryption</string>
@@ -721,4 +728,44 @@
     <!-- Summary shown for color space correction preference when its value is overridden by another preference [CHAR LIMIT=35] -->
     <string name="daltonizer_type_overridden">Overridden by <xliff:g id="title" example="Simulate color space">%1$s</xliff:g></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 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] 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] 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] 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>
+
+    <!-- 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>
+    <!-- [CHAR_LIMIT=20] Battery use screen.  Battery status shown in chart label when charging from an unknown source.  -->
+    <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 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 use screen.  Battery status shown in chart label when charging over a wireless connection.  -->
+    <string name="battery_info_status_charging_wireless">Charging wirelessly</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 -->
+    <string name="battery_info_status_not_charging">Not 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_full">Full</string>
+
+    <!-- Summary for settings preference disabled by administrator [CHAR LIMIT=50] -->
+    <string name="disabled_by_admin_summary_text">Disabled by administrator</string>
+
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java b/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.java
new file mode 100644
index 0000000..d81bdeb
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/BatteryInfo.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.settingslib;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.AsyncTask;
+import android.os.BatteryManager;
+import android.os.BatteryStats;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.text.format.Formatter;
+import com.android.internal.os.BatteryStatsHelper;
+
+public class BatteryInfo {
+
+    public String mChargeLabelString;
+    public int mBatteryLevel;
+    public boolean mDischarging = true;
+    public long remainingTimeUs = 0;
+
+    public interface Callback {
+        void onBatteryInfoLoaded(BatteryInfo info);
+    }
+
+    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.mBatteryLevel = Utils.getBatteryLevel(batteryBroadcast);
+        String batteryPercentString = Utils.formatPercentage(info.mBatteryLevel);
+        if (batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) == 0) {
+            final long drainTime = stats.computeBatteryTimeRemaining(elapsedRealtimeUs);
+            if (drainTime > 0) {
+                info.remainingTimeUs = drainTime;
+                String timeString = Formatter.formatShortElapsedTime(context,
+                        drainTime / 1000);
+                info.mChargeLabelString = context.getResources().getString(
+                        R.string.power_discharging_duration, batteryPercentString, timeString);
+            } else {
+                info.mChargeLabelString = batteryPercentString;
+            }
+        } else {
+            final long chargeTime = stats.computeChargeTimeRemaining(elapsedRealtimeUs);
+            final String statusLabel = Utils.getBatteryStatus(
+                    context.getResources(), 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.mChargeLabelString = context.getResources().getString(
+                        resId, batteryPercentString, timeString);
+            } else {
+                info.mChargeLabelString = context.getResources().getString(
+                        R.string.power_charging, batteryPercentString, statusLabel);
+            }
+        }
+        return info;
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedDropDownPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedDropDownPreference.java
new file mode 100644
index 0000000..c2f885d
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedDropDownPreference.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.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
new file mode 100644
index 0000000..e63130d
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockImageSpan.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.settingslib;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.drawable.Drawable;
+import android.text.style.ImageSpan;
+
+/**
+ * An extension of ImageSpan which adds a padding before the image.
+ */
+public class RestrictedLockImageSpan extends ImageSpan {
+    private Context mContext;
+    private final float mExtraPadding;
+    private final Drawable mRestrictedPadlock;
+
+    public RestrictedLockImageSpan(Context context) {
+        // we are overriding getDrawable, so passing null to super class here.
+        super((Drawable) null);
+
+        mContext = context;
+        mExtraPadding = mContext.getResources().getDimensionPixelSize(
+                R.dimen.restricted_lock_icon_padding);
+        mRestrictedPadlock = RestrictedLockUtils.getRestrictedPadlock(mContext);
+    }
+
+    @Override
+    public Drawable getDrawable() {
+        return mRestrictedPadlock;
+    }
+
+    @Override
+    public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y,
+            int bottom, Paint paint) {
+        Drawable drawable = getDrawable();
+        canvas.save();
+
+        // Add extra padding before the padlock.
+        float transX = x + mExtraPadding;
+        float transY = bottom - drawable.getBounds().bottom - paint.getFontMetricsInt().descent;
+
+        canvas.translate(transX, transY);
+        drawable.draw(canvas);
+        canvas.restore();
+    }
+
+    @Override
+    public int getSize(Paint paint, CharSequence text, int start, int end,
+            Paint.FontMetricsInt fontMetrics) {
+        int size = super.getSize(paint, text, start, end, fontMetrics);
+        size += 2 * mExtraPadding;
+        return size;
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
new file mode 100644
index 0000000..210682f
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -0,0 +1,586 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib;
+
+import android.app.AppGlobals;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.UserInfo;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.text.Spanned;
+import android.text.SpannableStringBuilder;
+import android.text.style.ForegroundColorSpan;
+import android.text.style.ImageSpan;
+import android.view.MenuItem;
+import android.widget.TextView;
+
+import com.android.internal.widget.LockPatternUtils;
+
+import java.util.List;
+
+/**
+ * Utility class to host methods usable in adding a restricted padlock icon and showing admin
+ * support message dialog.
+ */
+public class RestrictedLockUtils {
+    /**
+     * @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);
+        final int iconSize = context.getResources().getDimensionPixelSize(
+                R.dimen.restricted_lock_icon_size);
+        restrictedPadlock.setBounds(0, 0, iconSize, iconSize);
+        return restrictedPadlock;
+    }
+
+    /**
+     * Checks if a restriction is enforced on a user and returns the enforced admin and
+     * admin userId.
+     *
+     * @param userRestriction Restriction to check
+     * @param userId User which we need to check if restriction is enforced on.
+     * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
+     * or {@code null} If the restriction is not set. If the restriction is set by both device owner
+     * and profile owner, then the admin component will be set to {@code null} and userId to
+     * {@link UserHandle#USER_NULL}.
+     */
+    public static EnforcedAdmin checkIfRestrictionEnforced(Context context,
+            String userRestriction, int userId) {
+        DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+        if (dpm == null) {
+            return null;
+        }
+        ComponentName deviceOwner = dpm.getDeviceOwnerComponentOnAnyUser();
+        int deviceOwnerUserId = dpm.getDeviceOwnerUserId();
+        boolean enforcedByDeviceOwner = false;
+        if (deviceOwner != null && deviceOwnerUserId != UserHandle.USER_NULL) {
+            Bundle enforcedRestrictions = dpm.getUserRestrictions(deviceOwner, deviceOwnerUserId);
+            if (enforcedRestrictions != null
+                    && enforcedRestrictions.getBoolean(userRestriction, false)) {
+                enforcedByDeviceOwner = true;
+            }
+        }
+
+        ComponentName profileOwner = null;
+        boolean enforcedByProfileOwner = false;
+        if (userId != UserHandle.USER_NULL) {
+            profileOwner = dpm.getProfileOwnerAsUser(userId);
+            if (profileOwner != null) {
+                Bundle enforcedRestrictions = dpm.getUserRestrictions(profileOwner, userId);
+                if (enforcedRestrictions != null
+                        && enforcedRestrictions.getBoolean(userRestriction, false)) {
+                    enforcedByProfileOwner = true;
+                }
+            }
+        }
+
+        if (!enforcedByDeviceOwner && !enforcedByProfileOwner) {
+            return null;
+        }
+
+        EnforcedAdmin admin = null;
+        if (enforcedByDeviceOwner && enforcedByProfileOwner) {
+            admin = new EnforcedAdmin();
+        } else if (enforcedByDeviceOwner) {
+            admin = new EnforcedAdmin(deviceOwner, deviceOwnerUserId);
+        } else {
+            admin = new EnforcedAdmin(profileOwner, userId);
+        }
+        return admin;
+    }
+
+    /**
+     * Checks if keyguard features are disabled by policy.
+     *
+     * @param keyguardFeatures Could be any of keyguard features that can be
+     * disabled by {@link android.app.admin.DevicePolicyManager#setKeyguardDisabledFeatures}.
+     * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
+     * or {@code null} If the notification features are not disabled. If the restriction is set by
+     * multiple admins, then the admin component will be set to {@code null} and userId to
+     * {@link UserHandle#USER_NULL}.
+     */
+    public static EnforcedAdmin checkIfKeyguardFeaturesDisabled(Context context,
+            int keyguardFeatures) {
+        final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+        if (dpm == null) {
+            return null;
+        }
+        final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
+        EnforcedAdmin enforcedAdmin = null;
+        final int userId = UserHandle.myUserId();
+        if (um.getUserInfo(userId).isManagedProfile()) {
+            final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId);
+            if (admins == null) {
+                return null;
+            }
+            for (ComponentName admin : admins) {
+                if ((dpm.getKeyguardDisabledFeatures(admin, userId) & keyguardFeatures) != 0) {
+                    if (enforcedAdmin == null) {
+                        enforcedAdmin = new EnforcedAdmin(admin, userId);
+                    } else {
+                        return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
+                    }
+                }
+            }
+        } else {
+            // Consider all admins for this user and the profiles that are visible from this
+            // user that do not use a separate work challenge.
+            for (UserInfo userInfo : um.getProfiles(userId)) {
+                final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userInfo.id);
+                if (admins == null) {
+                    return null;
+                }
+                final boolean isSeparateProfileChallengeEnabled =
+                        lockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id);
+                for (ComponentName admin : admins) {
+                    if (!isSeparateProfileChallengeEnabled) {
+                        if ((dpm.getKeyguardDisabledFeatures(admin, userInfo.id)
+                                    & keyguardFeatures) != 0) {
+                            if (enforcedAdmin == null) {
+                                enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
+                            } else {
+                                return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
+                            }
+                            // This same admins could have set policies both on the managed profile
+                            // and on the parent. So, if the admin has set the policy on the
+                            // managed profile here, we don't need to further check if that admin
+                            // has set policy on the parent admin.
+                            continue;
+                        }
+                    }
+                    if (userInfo.isManagedProfile()) {
+                        // If userInfo.id is a managed profile, we also need to look at
+                        // the policies set on the parent.
+                        DevicePolicyManager parentDpm = dpm.getParentProfileInstance(userInfo);
+                        if ((parentDpm.getKeyguardDisabledFeatures(admin, userInfo.id)
+                                & keyguardFeatures) != 0) {
+                            if (enforcedAdmin == null) {
+                                enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
+                            } else {
+                                return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return enforcedAdmin;
+    }
+
+    public static EnforcedAdmin checkIfUninstallBlocked(Context context,
+            String packageName, int userId) {
+        EnforcedAdmin allAppsControlDisallowedAdmin = checkIfRestrictionEnforced(context,
+                UserManager.DISALLOW_APPS_CONTROL, userId);
+        if (allAppsControlDisallowedAdmin != null) {
+            return allAppsControlDisallowedAdmin;
+        }
+        EnforcedAdmin allAppsUninstallDisallowedAdmin = checkIfRestrictionEnforced(context,
+                UserManager.DISALLOW_UNINSTALL_APPS, userId);
+        if (allAppsUninstallDisallowedAdmin != null) {
+            return allAppsUninstallDisallowedAdmin;
+        }
+        IPackageManager ipm = AppGlobals.getPackageManager();
+        try {
+            if (ipm.getBlockUninstallForUser(packageName, userId)) {
+                DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
+                        Context.DEVICE_POLICY_SERVICE);
+                if (dpm == null) {
+                    return null;
+                }
+                ComponentName admin = dpm.getProfileOwner();
+                if (admin == null) {
+                    admin = dpm.getDeviceOwnerComponentOnCallingUser();
+                }
+                return new EnforcedAdmin(admin, UserHandle.myUserId());
+            }
+        } catch (RemoteException e) {
+            // Nothing to do
+        }
+        return null;
+    }
+
+    /**
+     * Check if an application is suspended.
+     *
+     * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
+     * or {@code null} if the application is not suspended.
+     */
+    public static EnforcedAdmin checkIfApplicationIsSuspended(Context context, String packageName,
+            int userId) {
+        IPackageManager ipm = AppGlobals.getPackageManager();
+        try {
+            ApplicationInfo ai = ipm.getApplicationInfo(packageName, 0, userId);
+            if (ai != null && ((ai.flags & ApplicationInfo.FLAG_SUSPENDED) != 0)) {
+                return getProfileOrDeviceOwnerOnCallingUser(context);
+            }
+        } catch (RemoteException e) {
+            // Nothing to do
+        }
+        return null;
+    }
+
+    /**
+     * Check if account management for a specific type of account is disabled by admin.
+     * Only a profile or device owner can disable account management. So, we check if account
+     * management is disabled and return profile or device owner on the calling user.
+     *
+     * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
+     * or {@code null} if the account management is not disabled.
+     */
+    public static EnforcedAdmin checkIfAccountManagementDisabled(Context context,
+            String accountType) {
+        if (accountType == null) {
+            return null;
+        }
+        DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+        if (dpm == null) {
+            return null;
+        }
+        boolean isAccountTypeDisabled = false;
+        String[] disabledTypes = dpm.getAccountTypesWithManagementDisabled();
+        for (String type : disabledTypes) {
+            if (accountType.equals(type)) {
+                isAccountTypeDisabled = true;
+                break;
+            }
+        }
+        if (!isAccountTypeDisabled) {
+            return null;
+        }
+        return getProfileOrDeviceOwnerOnCallingUser(context);
+    }
+
+    /**
+     * Checks if {@link android.app.admin.DevicePolicyManager#setAutoTimeRequired} is enforced
+     * on the device.
+     *
+     * @return EnforcedAdmin Object containing the device owner component and
+     * userId the device owner is running as, or {@code null} setAutoTimeRequired is not enforced.
+     */
+    public static EnforcedAdmin checkIfAutoTimeRequired(Context context) {
+        DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+        if (dpm == null || !dpm.getAutoTimeRequired()) {
+            return null;
+        }
+        ComponentName adminComponent = dpm.getDeviceOwnerComponentOnCallingUser();
+        return new EnforcedAdmin(adminComponent, UserHandle.myUserId());
+    }
+
+    /**
+     * Checks if an admin has enforced minimum password quality requirements on the device.
+     *
+     * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
+     * or {@code null} if no quality requirements are set. If the requirements are set by
+     * multiple device admins, then the admin component will be set to {@code null} and userId to
+     * {@link UserHandle#USER_NULL}.
+     *
+     */
+    public static EnforcedAdmin checkIfPasswordQualityIsSet(Context context) {
+        final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+        if (dpm == null) {
+            return null;
+        }
+        boolean isDisabledByMultipleAdmins = false;
+        ComponentName adminComponent = null;
+        List<ComponentName> admins = dpm.getActiveAdmins();
+        int quality;
+        if (admins != null) {
+            for (ComponentName admin : admins) {
+                quality = dpm.getPasswordQuality(admin);
+                if (quality >= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+                    if (adminComponent == null) {
+                        adminComponent = admin;
+                    } else {
+                        isDisabledByMultipleAdmins = true;
+                        break;
+                    }
+                }
+            }
+        }
+        EnforcedAdmin enforcedAdmin = null;
+        if (adminComponent != null) {
+            if (!isDisabledByMultipleAdmins) {
+                enforcedAdmin = new EnforcedAdmin(adminComponent, UserHandle.myUserId());
+            } else {
+                enforcedAdmin = new EnforcedAdmin();
+            }
+        }
+        return enforcedAdmin;
+    }
+
+    /**
+     * Checks if any admin has set maximum time to lock.
+     *
+     * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
+     * or {@code null} if no admin has set this restriction. If multiple admins has set this, then
+     * the admin component will be set to {@code null} and userId to {@link UserHandle#USER_NULL}
+     */
+    public static EnforcedAdmin checkIfMaximumTimeToLockIsSet(Context context) {
+        final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+        LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
+        EnforcedAdmin enforcedAdmin = null;
+        final int userId = UserHandle.myUserId();
+        if (lockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
+            // If the user has a separate challenge, only consider the admins in that user.
+            final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId);
+            if (admins == null) {
+                return null;
+            }
+            for (ComponentName admin : admins) {
+                if (dpm.getMaximumTimeToLock(admin, userId) > 0) {
+                    if (enforcedAdmin == null) {
+                        enforcedAdmin = new EnforcedAdmin(admin, userId);
+                    } else {
+                        return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
+                    }
+                }
+            }
+        } else {
+            // Return all admins for this user and the profiles that are visible from this
+            // user that do not use a separate work challenge.
+            final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
+            for (UserInfo userInfo : um.getProfiles(userId)) {
+                final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userInfo.id);
+                if (admins == null) {
+                    return null;
+                }
+                final boolean isSeparateProfileChallengeEnabled =
+                        lockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id);
+                for (ComponentName admin : admins) {
+                    if (!isSeparateProfileChallengeEnabled) {
+                        if (dpm.getMaximumTimeToLock(admin, userInfo.id) > 0) {
+                            if (enforcedAdmin == null) {
+                                enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
+                            } else {
+                                return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
+                            }
+                            // This same admins could have set policies both on the managed profile
+                            // and on the parent. So, if the admin has set the policy on the
+                            // managed profile here, we don't need to further check if that admin
+                            // has set policy on the parent admin.
+                            continue;
+                        }
+                    }
+                    if (userInfo.isManagedProfile()) {
+                        // If userInfo.id is a managed profile, we also need to look at
+                        // the policies set on the parent.
+                        DevicePolicyManager parentDpm = dpm.getParentProfileInstance(userInfo);
+                        if (parentDpm.getMaximumTimeToLock(admin, userInfo.id) > 0) {
+                            if (enforcedAdmin == null) {
+                                enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
+                            } else {
+                                return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return enforcedAdmin;
+    }
+
+    public static EnforcedAdmin getProfileOrDeviceOwnerOnCallingUser(Context context) {
+        final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+        if (dpm == null) {
+            return null;
+        }
+        ComponentName adminComponent = dpm.getDeviceOwnerComponentOnCallingUser();
+        if (adminComponent != null) {
+            return new EnforcedAdmin(adminComponent, UserHandle.myUserId());
+        }
+        adminComponent = dpm.getProfileOwner();
+        if (adminComponent != null) {
+            return new EnforcedAdmin(adminComponent, UserHandle.myUserId());
+        }
+        return null;
+    }
+
+    /**
+     * Set the menu item as disabled by admin by adding a restricted padlock at the end of the
+     * text and set the click listener which will send an intent to show the admin support details
+     * dialog. If the admin is null, remove the padlock and disabled color span. When the admin is
+     * null, we also set the OnMenuItemClickListener to null, so if you want to set a custom
+     * OnMenuItemClickListener, set it after calling this method.
+     */
+    public static void setMenuItemAsDisabledByAdmin(final Context context,
+            final MenuItem item, final EnforcedAdmin admin) {
+        SpannableStringBuilder sb = new SpannableStringBuilder(item.getTitle());
+        removeExistingRestrictedSpans(sb);
+
+        if (admin != null) {
+            final int disabledColor = context.getColor(R.color.disabled_text_color);
+            sb.setSpan(new ForegroundColorSpan(disabledColor), 0, sb.length(),
+                    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+            ImageSpan image = new RestrictedLockImageSpan(context);
+            sb.append(" ", image, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+            item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+                @Override
+                public boolean onMenuItemClick(MenuItem item) {
+                    sendShowAdminSupportDetailsIntent(context, admin);
+                    return true;
+                }
+            });
+        } else {
+            item.setOnMenuItemClickListener(null);
+        }
+        item.setTitle(sb);
+    }
+
+    private static void removeExistingRestrictedSpans(SpannableStringBuilder sb) {
+        final int length = sb.length();
+        RestrictedLockImageSpan[] imageSpans = sb.getSpans(length - 1, length,
+                RestrictedLockImageSpan.class);
+        for (ImageSpan span : imageSpans) {
+            final int start = sb.getSpanStart(span);
+            final int end = sb.getSpanEnd(span);
+            sb.removeSpan(span);
+            sb.delete(start, end);
+        }
+        ForegroundColorSpan[] colorSpans = sb.getSpans(0, length, ForegroundColorSpan.class);
+        for (ForegroundColorSpan span : colorSpans) {
+            sb.removeSpan(span);
+        }
+    }
+
+    /**
+     * Send the intent to trigger the {@link android.settings.ShowAdminSupportDetailsDialog}.
+     */
+    public static void sendShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) {
+        final Intent intent = getShowAdminSupportDetailsIntent(context, admin);
+        int adminUserId = UserHandle.myUserId();
+        if (admin.userId != UserHandle.USER_NULL) {
+            adminUserId = admin.userId;
+        }
+        context.startActivityAsUser(intent, new UserHandle(adminUserId));
+    }
+
+    public static Intent getShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) {
+        final Intent intent = new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
+        if (admin != null) {
+            if (admin.component != null) {
+                intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, admin.component);
+            }
+            int adminUserId = UserHandle.myUserId();
+            if (admin.userId != UserHandle.USER_NULL) {
+                adminUserId = admin.userId;
+            }
+            intent.putExtra(Intent.EXTRA_USER_ID, adminUserId);
+        }
+        return intent;
+    }
+
+    public static void setTextViewPadlock(Context context,
+            TextView textView, boolean showPadlock) {
+        final SpannableStringBuilder sb = new SpannableStringBuilder(textView.getText());
+        removeExistingRestrictedSpans(sb);
+        if (showPadlock) {
+            final ImageSpan image = new RestrictedLockImageSpan(context);
+            sb.append(" ", image, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        }
+        textView.setText(sb);
+    }
+
+    /**
+     * Takes a {@link android.widget.TextView} and applies an alpha so that the text looks like
+     * disabled and appends a padlock to the text. This assumes that there are no
+     * ForegroundColorSpans and RestrictedLockImageSpans used on the TextView.
+     */
+    public static void setTextViewAsDisabledByAdmin(Context context,
+            TextView textView, boolean disabled) {
+        final SpannableStringBuilder sb = new SpannableStringBuilder(textView.getText());
+        removeExistingRestrictedSpans(sb);
+        if (disabled) {
+            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.setText(sb);
+    }
+
+    public static class EnforcedAdmin {
+        public ComponentName component = null;
+        public int userId = UserHandle.USER_NULL;
+
+        // We use this to represent the case where a policy is enforced by multiple admins.
+        public final static EnforcedAdmin MULTIPLE_ENFORCED_ADMIN = new EnforcedAdmin();
+
+        public EnforcedAdmin(ComponentName component, int userId) {
+            this.component = component;
+            this.userId = userId;
+        }
+
+        public EnforcedAdmin(EnforcedAdmin other) {
+            if (other == null) {
+                throw new IllegalArgumentException();
+            }
+            this.component = other.component;
+            this.userId = other.userId;
+        }
+
+        public EnforcedAdmin() {}
+
+        @Override
+        public boolean equals(Object object) {
+            if (object == this) return true;
+            if (!(object instanceof EnforcedAdmin)) return false;
+            EnforcedAdmin other = (EnforcedAdmin) object;
+            if (userId != other.userId) {
+                return false;
+            }
+            if ((component == null && other == null) ||
+                    (component != null && component.equals(other))) {
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public String toString() {
+            return "EnforcedAdmin{component=" + component + ",userId=" + userId + "}";
+        }
+
+        public void copyTo(EnforcedAdmin other) {
+            if (other == null) {
+                throw new IllegalArgumentException();
+            }
+            other.component = component;
+            other.userId = userId;
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
new file mode 100644
index 0000000..810f6eb
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.os.UserHandle;
+import android.support.v4.content.res.TypedArrayUtils;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceManager;
+import android.support.v7.preference.PreferenceViewHolder;
+import android.util.AttributeSet;
+
+import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
+/**
+ * Preference class that supports being disabled by a user restriction
+ * set by a device admin.
+ */
+public class RestrictedPreference extends Preference {
+    RestrictedPreferenceHelper mHelper;
+
+    public RestrictedPreference(Context context, AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        mHelper = new RestrictedPreferenceHelper(context, this, attrs);
+    }
+
+    public RestrictedPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public RestrictedPreference(Context context, AttributeSet attrs) {
+        this(context, attrs, TypedArrayUtils.getAttr(context, R.attr.preferenceStyle,
+                android.R.attr.preferenceStyle));
+    }
+
+    public RestrictedPreference(Context context) {
+        this(context, null);
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+        mHelper.onBindViewHolder(holder);
+    }
+
+    @Override
+    public void performClick() {
+        if (!mHelper.performClick()) {
+            super.performClick();
+        }
+    }
+
+    public void useAdminDisabledSummary(boolean useSummary) {
+        mHelper.useAdminDisabledSummary(useSummary);
+    }
+
+    @Override
+    protected void onAttachedToHierarchy(PreferenceManager preferenceManager) {
+        mHelper.onAttachedToHierarchy();
+        super.onAttachedToHierarchy(preferenceManager);
+    }
+
+    public void checkRestrictionAndSetDisabled(String userRestriction) {
+        mHelper.checkRestrictionAndSetDisabled(userRestriction, UserHandle.myUserId());
+    }
+
+    public void checkRestrictionAndSetDisabled(String userRestriction, int userId) {
+        mHelper.checkRestrictionAndSetDisabled(userRestriction, userId);
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        if (enabled && isDisabledByAdmin()) {
+            mHelper.setDisabledByAdmin(null);
+            return;
+        }
+        super.setEnabled(enabled);
+    }
+
+    public void setDisabledByAdmin(EnforcedAdmin admin) {
+        if (mHelper.setDisabledByAdmin(admin)) {
+            notifyChanged();
+        }
+    }
+
+    public boolean isDisabledByAdmin() {
+        return mHelper.isDisabledByAdmin();
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
new file mode 100644
index 0000000..9bd4eb1
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+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;
+import android.widget.TextView;
+
+import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
+/**
+ * Helper class for managing settings preferences that can be disabled
+ * by device admins via user restrictions.
+ */
+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;
+    private String mAttrUserRestriction = null;
+    private boolean mUseAdminDisabledSummary = false;
+
+    public RestrictedPreferenceHelper(Context context, Preference preference,
+            AttributeSet attrs) {
+        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);
+            final TypedValue userRestriction =
+                    attributes.peekValue(R.styleable.RestrictedPreference_userRestriction);
+            CharSequence data = null;
+            if (userRestriction != null && userRestriction.type == TypedValue.TYPE_STRING) {
+                if (userRestriction.resourceId != 0) {
+                    data = context.getText(userRestriction.resourceId);
+                } else {
+                    data = userRestriction.string;
+                }
+            }
+            mAttrUserRestriction = data == null ? null : data.toString();
+
+            final TypedValue useAdminDisabledSummary =
+                    attributes.peekValue(R.styleable.RestrictedPreference_useAdminDisabledSummary);
+            if (useAdminDisabledSummary != null) {
+                mUseAdminDisabledSummary =
+                        (useAdminDisabledSummary.type == TypedValue.TYPE_INT_BOOLEAN
+                                && useAdminDisabledSummary.data != 0);
+            }
+        }
+    }
+
+    /**
+     * 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 (mUseAdminDisabledSummary) {
+            final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
+            if (summaryView != null) {
+                if (mDisabledByAdmin) {
+                    summaryView.setText(R.string.disabled_by_admin_summary_text);
+                    summaryView.setVisibility(View.VISIBLE);
+                } else {
+                    summaryView.setVisibility(View.GONE);
+                }
+            }
+        }
+    }
+
+    public void useAdminDisabledSummary(boolean useSummary) {
+        mUseAdminDisabledSummary = useSummary;
+    }
+
+    /**
+     * Check if the preference is disabled if so handle the click by informing the user.
+     *
+     * @return true if the method handled the click.
+     */
+    public boolean performClick() {
+        if (mDisabledByAdmin) {
+            RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, mEnforcedAdmin);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Disable / enable if we have been passed the restriction in the xml.
+     */
+    public void onAttachedToHierarchy() {
+        if (mAttrUserRestriction != null) {
+            checkRestrictionAndSetDisabled(mAttrUserRestriction, UserHandle.myUserId());
+        }
+    }
+
+    /**
+     * Set the user restriction that is used to disable this preference.
+     *
+     * @param userRestriction constant from {@link android.os.UserManager}
+     * @param userId user to check the restriction for.
+     */
+    public void checkRestrictionAndSetDisabled(String userRestriction, int userId) {
+        EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
+                userRestriction, userId);
+        setDisabledByAdmin(admin);
+    }
+
+    /**
+     * Disable this preference based on the enforce admin.
+     *
+     * @param EnforcedAdmin Details of the admin who enforced the restriction. If it
+     * is {@code null}, then this preference will be enabled. Otherwise, it will be disabled.
+     * @return true if the disabled state was changed.
+     */
+    public boolean setDisabledByAdmin(EnforcedAdmin admin) {
+        final boolean disabled = (admin != null ? true : false);
+        mEnforcedAdmin = (disabled ? admin : null);
+        if (mDisabledByAdmin != disabled) {
+            mDisabledByAdmin = disabled;
+            mPreference.setEnabled(!disabled);
+            return true;
+        }
+        return false;
+    }
+
+    public boolean isDisabledByAdmin() {
+        return mDisabledByAdmin;
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
new file mode 100644
index 0000000..6cae8aa
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.os.UserHandle;
+import android.support.v4.content.res.TypedArrayUtils;
+import android.support.v7.preference.PreferenceManager;
+import android.support.v7.preference.PreferenceViewHolder;
+import android.support.v14.preference.SwitchPreference;
+import android.util.AttributeSet;
+
+import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
+/**
+ * Version of SwitchPreference that can be disabled by a device admin
+ * using a user restriction.
+ */
+public class RestrictedSwitchPreference extends SwitchPreference {
+    RestrictedPreferenceHelper mHelper;
+
+    public RestrictedSwitchPreference(Context context, AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        mHelper = new RestrictedPreferenceHelper(context, this, attrs);
+    }
+
+    public RestrictedSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public RestrictedSwitchPreference(Context context, AttributeSet attrs) {
+        this(context, attrs, TypedArrayUtils.getAttr(context, R.attr.switchPreferenceStyle,
+                android.R.attr.switchPreferenceStyle));
+    }
+
+    public RestrictedSwitchPreference(Context context) {
+        this(context, null);
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+        mHelper.onBindViewHolder(holder);
+    }
+
+    @Override
+    public void performClick() {
+        if (!mHelper.performClick()) {
+            super.performClick();
+        }
+    }
+
+    public void useAdminDisabledSummary(boolean useSummary) {
+        mHelper.useAdminDisabledSummary(useSummary);
+    }
+
+    @Override
+    protected void onAttachedToHierarchy(PreferenceManager preferenceManager) {
+        mHelper.onAttachedToHierarchy();
+        super.onAttachedToHierarchy(preferenceManager);
+    }
+
+    public void checkRestrictionAndSetDisabled(String userRestriction) {
+        mHelper.checkRestrictionAndSetDisabled(userRestriction, UserHandle.myUserId());
+    }
+
+    public void checkRestrictionAndSetDisabled(String userRestriction, int userId) {
+        mHelper.checkRestrictionAndSetDisabled(userRestriction, userId);
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        if (enabled && isDisabledByAdmin()) {
+            mHelper.setDisabledByAdmin(null);
+            return;
+        }
+        super.setEnabled(enabled);
+    }
+
+    public void setDisabledByAdmin(EnforcedAdmin admin) {
+        if (mHelper.setDisabledByAdmin(admin)) {
+            notifyChanged();
+        }
+    }
+
+    public boolean isDisabledByAdmin() {
+        return mHelper.isDisabledByAdmin();
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
new file mode 100644
index 0000000..1859207
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.content.Intent;
+import android.content.SharedPreferences;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Xml;
+import android.view.InflateException;
+import com.android.settingslib.drawer.Tile;
+import com.android.settingslib.drawer.TileUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class SuggestionParser {
+
+    private static final String TAG = "SuggestionParser";
+
+    // If defined, only returns this suggestion if the feature is supported.
+    public static final String META_DATA_REQUIRE_FEATURE = "com.android.settings.require_feature";
+
+    /**
+     * Allows suggestions to appear after a certain number of days, and to re-appear if dismissed.
+     * For instance:
+     * 0,10
+     * Will appear immediately, but if the user removes it, it will come back after 10 days.
+     *
+     * Another example:
+     * 10,30
+     * Will only show up after 10 days, and then again after 30.
+     */
+    public static final String META_DATA_DISMISS_CONTROL = "com.android.settings.dismiss";
+
+    // Shared prefs keys for storing dismissed state.
+    // Index into current dismissed state.
+    private static final String DISMISS_INDEX = "_dismiss_index";
+    private static final String SETUP_TIME = "_setup_time";
+    private static final String IS_DISMISSED = "_is_dismissed";
+
+    private static final long MILLIS_IN_DAY = 24 * 60 * 60 * 1000;
+
+    private final Context mContext;
+    private final List<SuggestionCategory> mSuggestionList;
+    private final ArrayMap<Pair<String, String>, Tile> addCache = new ArrayMap<>();
+    private final SharedPreferences mSharedPrefs;
+
+    public SuggestionParser(Context context, SharedPreferences sharedPrefs, int orderXml) {
+        mContext = context;
+        mSuggestionList = (List<SuggestionCategory>) new SuggestionOrderInflater(mContext)
+                .parse(orderXml);
+        mSharedPrefs = sharedPrefs;
+    }
+
+    public List<Tile> getSuggestions() {
+        List<Tile> suggestions = new ArrayList<>();
+        final int N = mSuggestionList.size();
+        for (int i = 0; i < N; i++) {
+            readSuggestions(mSuggestionList.get(i), suggestions);
+        }
+        return suggestions;
+    }
+
+    /**
+     * Dismisses a suggestion, returns true if the suggestion has no more dismisses left and should
+     * be disabled.
+     */
+    public boolean dismissSuggestion(Tile suggestion) {
+        String keyBase = suggestion.intent.getComponent().flattenToShortString();
+        int index = mSharedPrefs.getInt(keyBase + DISMISS_INDEX, 0);
+        String dismissControl = suggestion.metaData.getString(META_DATA_DISMISS_CONTROL);
+        if (dismissControl == null || parseDismissString(dismissControl).length == index) {
+            return true;
+        }
+        mSharedPrefs.edit()
+                .putBoolean(keyBase + IS_DISMISSED, true)
+                .commit();
+        return false;
+    }
+
+    private void readSuggestions(SuggestionCategory category, List<Tile> suggestions) {
+        int countBefore = suggestions.size();
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(category.category);
+        if (category.pkg != null) {
+            intent.setPackage(category.pkg);
+        }
+        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))) {
+                suggestions.remove(i--);
+            }
+        }
+        if (!category.multiple && suggestions.size() > (countBefore + 1)) {
+            // If there are too many, remove them all and only re-add the one with the highest
+            // priority.
+            Tile item = suggestions.remove(suggestions.size() - 1);
+            while (suggestions.size() > countBefore) {
+                Tile last = suggestions.remove(suggestions.size() - 1);
+                if (last.priority > item.priority) {
+                    item = last;
+                }
+            }
+            suggestions.add(item);
+        }
+    }
+
+    private boolean isAvailable(Tile suggestion) {
+        String featureRequired = suggestion.metaData.getString(META_DATA_REQUIRE_FEATURE);
+        if (featureRequired != null) {
+            return mContext.getPackageManager().hasSystemFeature(featureRequired);
+        }
+        return true;
+    }
+
+    private boolean isDismissed(Tile suggestion) {
+        Object dismissObj = suggestion.metaData.get(META_DATA_DISMISS_CONTROL);
+        if (dismissObj == null) {
+            return false;
+        }
+        String dismissControl = String.valueOf(dismissObj);
+        String keyBase = suggestion.intent.getComponent().flattenToShortString();
+        if (!mSharedPrefs.contains(keyBase + SETUP_TIME)) {
+            mSharedPrefs.edit()
+                    .putLong(keyBase + SETUP_TIME, System.currentTimeMillis())
+                    .commit();
+        }
+        // Default to dismissed, so that we can have suggestions that only first appear after
+        // some number of days.
+        if (!mSharedPrefs.getBoolean(keyBase + IS_DISMISSED, true)) {
+            return false;
+        }
+        int index = mSharedPrefs.getInt(keyBase + DISMISS_INDEX, 0);
+        int currentDismiss = parseDismissString(dismissControl)[index];
+        long time = getEndTime(mSharedPrefs.getLong(keyBase + SETUP_TIME, 0), currentDismiss);
+        if (System.currentTimeMillis() >= time) {
+            // Dismiss timeout has passed, undismiss it.
+            mSharedPrefs.edit()
+                    .putBoolean(keyBase + IS_DISMISSED, false)
+                    .putInt(keyBase + DISMISS_INDEX, index + 1)
+                    .commit();
+            return false;
+        }
+        return true;
+    }
+
+    private long getEndTime(long startTime, int daysDelay) {
+        long days = daysDelay * MILLIS_IN_DAY;
+        return startTime + days;
+    }
+
+    private int[] parseDismissString(String dismissControl) {
+        String[] dismissStrs = dismissControl.split(",");
+        int[] dismisses = new int[dismissStrs.length];
+        for (int i = 0; i < dismissStrs.length; i++) {
+            dismisses[i] = Integer.parseInt(dismissStrs[i]);
+        }
+        return dismisses;
+    }
+
+    private static class SuggestionCategory {
+        public String category;
+        public String pkg;
+        public boolean multiple;
+    }
+
+    private static class SuggestionOrderInflater {
+        private static final String TAG_LIST = "optional-steps";
+        private static final String TAG_ITEM = "step";
+
+        private static final String ATTR_CATEGORY = "category";
+        private static final String ATTR_PACKAGE = "package";
+        private static final String ATTR_MULTIPLE = "multiple";
+
+        private final Context mContext;
+
+        public SuggestionOrderInflater(Context context) {
+            mContext = context;
+        }
+
+        public Object parse(int resource) {
+            XmlPullParser parser = mContext.getResources().getXml(resource);
+            final AttributeSet attrs = Xml.asAttributeSet(parser);
+            try {
+                // Look for the root node.
+                int type;
+                do {
+                    type = parser.next();
+                } while (type != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT);
+
+                if (type != XmlPullParser.START_TAG) {
+                    throw new InflateException(parser.getPositionDescription()
+                            + ": No start tag found!");
+                }
+
+                // Temp is the root that was found in the xml
+                Object xmlRoot = onCreateItem(parser.getName(), attrs);
+
+                // Inflate all children under temp
+                rParse(parser, xmlRoot, attrs);
+                return xmlRoot;
+            } catch (XmlPullParserException | IOException e) {
+                Log.w(TAG, "Problem parser resource " + resource, e);
+                return null;
+            }
+        }
+
+        /**
+         * Recursive method used to descend down the xml hierarchy and instantiate
+         * items, instantiate their children.
+         */
+        private void rParse(XmlPullParser parser, Object parent, final AttributeSet attrs)
+                throws XmlPullParserException, IOException {
+            final int depth = parser.getDepth();
+
+            int type;
+            while (((type = parser.next()) != XmlPullParser.END_TAG ||
+                    parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
+                if (type != XmlPullParser.START_TAG) {
+                    continue;
+                }
+
+                final String name = parser.getName();
+
+                Object item = onCreateItem(name, attrs);
+                onAddChildItem(parent, item);
+                rParse(parser, item, attrs);
+            }
+        }
+
+        protected void onAddChildItem(Object parent, Object child) {
+            if (parent instanceof List<?> && child instanceof SuggestionCategory) {
+                ((List<SuggestionCategory>) parent).add((SuggestionCategory) child);
+            } else {
+                throw new IllegalArgumentException("Parent was not a list");
+            }
+        }
+
+        protected Object onCreateItem(String name, AttributeSet attrs) {
+            if (name.equals(TAG_LIST)) {
+                return new ArrayList<SuggestionCategory>();
+            } else if (name.equals(TAG_ITEM)) {
+                SuggestionCategory category = new SuggestionCategory();
+                category.category = attrs.getAttributeValue(null, ATTR_CATEGORY);
+                category.pkg = attrs.getAttributeValue(null, ATTR_PACKAGE);
+                String multiple = attrs.getAttributeValue(null, ATTR_MULTIPLE);
+                category.multiple = !TextUtils.isEmpty(multiple) && Boolean.parseBoolean(multiple);
+                return category;
+            } else {
+                throw new IllegalArgumentException("Unknown item " + name);
+            }
+        }
+    }
+}
+
diff --git a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
index 66233b8..f5a2aae 100644
--- a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
@@ -29,12 +29,6 @@
 
 public class TetherUtil {
 
-    // Types of tethering.
-    public static final int TETHERING_INVALID   = -1;
-    public static final int TETHERING_WIFI      = 0;
-    public static final int TETHERING_USB       = 1;
-    public static final int TETHERING_BLUETOOTH = 2;
-
     // Extras used for communicating with the TetherService.
     public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
     public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
@@ -43,14 +37,6 @@
      * Tells the service to run a provision check now.
      */
     public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
-    /**
-     * Enables wifi tethering if the provision check is successful. Used by
-     * QS to enable tethering.
-     */
-    public static final String EXTRA_ENABLE_WIFI_TETHER = "extraEnableWifiTether";
-
-    public static ComponentName TETHER_SERVICE = ComponentName.unflattenFromString(Resources
-            .getSystem().getString(com.android.internal.R.string.config_wifi_tether_enable));
 
     public static boolean setWifiTethering(boolean enable, Context context) {
         final WifiManager wifiManager =
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 621a09cd..fa2226d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -1,17 +1,25 @@
 package com.android.settingslib;
 
 import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
+import android.content.pm.Signature;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.drawable.Drawable;
 import android.net.ConnectivityManager;
+import android.os.BatteryManager;
 import android.os.UserManager;
-
 import com.android.internal.util.UserIcons;
 import com.android.settingslib.drawable.CircleFramedDrawable;
 
-public final class Utils {
+import java.text.NumberFormat;
+
+public class Utils {
 
     /**
      * Return string resource that best describes combination of tethering
@@ -81,4 +89,86 @@
         return CircleFramedDrawable.getInstance(context, UserIcons.convertToBitmap(
                 UserIcons.getDefaultUserIcon(user.id, /* light= */ false)));
     }
+
+    /** Formats the ratio of amount/total as a percentage. */
+    public static String formatPercentage(long amount, long total) {
+        return formatPercentage(((double) amount) / total);
+    }
+
+    /** Formats an integer from 0..100 as a percentage. */
+    public static String formatPercentage(int percentage) {
+        return formatPercentage(((double) percentage) / 100.0);
+    }
+
+    /** Formats a double from 0.0..1.0 as a percentage. */
+    private static String formatPercentage(double percentage) {
+      return NumberFormat.getPercentInstance().format(percentage);
+    }
+
+    public static int getBatteryLevel(Intent batteryChangedIntent) {
+        int level = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
+        int scale = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 100);
+        return (level * 100) / scale;
+    }
+
+    public static String getBatteryStatus(Resources res, Intent batteryChangedIntent) {
+        final Intent intent = batteryChangedIntent;
+
+        int plugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
+        int status = intent.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;
+            } else if (plugType == BatteryManager.BATTERY_PLUGGED_USB) {
+                resId = R.string.battery_info_status_charging_usb;
+            } else if (plugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
+                resId = R.string.battery_info_status_charging_wireless;
+            } else {
+                resId = R.string.battery_info_status_charging;
+            }
+            statusString = res.getString(resId);
+        } else if (status == BatteryManager.BATTERY_STATUS_DISCHARGING) {
+            statusString = res.getString(R.string.battery_info_status_discharging);
+        } else if (status == BatteryManager.BATTERY_STATUS_NOT_CHARGING) {
+            statusString = res.getString(R.string.battery_info_status_not_charging);
+        } else if (status == BatteryManager.BATTERY_STATUS_FULL) {
+            statusString = res.getString(R.string.battery_info_status_full);
+        } else {
+            statusString = res.getString(R.string.battery_info_status_unknown);
+        }
+
+        return statusString;
+    }
+
+    /**
+     * Determine whether a package is a "system package", in which case certain things (like
+     * disabling notifications or disabling the package altogether) should be disallowed.
+     */
+    public static boolean isSystemPackage(PackageManager pm, PackageInfo pkg) {
+        if (sSystemSignature == null) {
+            sSystemSignature = new Signature[]{ getSystemSignature(pm) };
+        }
+        return sSystemSignature[0] != null && sSystemSignature[0].equals(getFirstSignature(pkg));
+    }
+
+    private static Signature[] sSystemSignature;
+
+    private static Signature getFirstSignature(PackageInfo pkg) {
+        if (pkg != null && pkg.signatures != null && pkg.signatures.length > 0) {
+            return pkg.signatures[0];
+        }
+        return null;
+    }
+
+    private static Signature getSystemSignature(PackageManager pm) {
+        try {
+            final PackageInfo sys = pm.getPackageInfo("android", PackageManager.GET_SIGNATURES);
+            return getFirstSignature(sys);
+        } catch (NameNotFoundException e) {
+        }
+        return null;
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
index 344bf62..f6d9134 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
@@ -38,7 +38,7 @@
         String packageName = appEntry.info.packageName;
         boolean hasPreferred = hasPreferredActivities(pm, packageName)
                 || hasUsbDefaults(usbManager, packageName);
-        int status = pm.getIntentVerificationStatus(packageName, UserHandle.myUserId());
+        int status = pm.getIntentVerificationStatusAsUser(packageName, UserHandle.myUserId());
         // consider a visible current link-handling state to be any explicitly designated behavior
         boolean hasDomainURLsPreference =
                 status != PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index e6fe447..d353f31 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -316,7 +316,7 @@
         synchronized (mEntriesMap) {
             AppEntry entry = mEntriesMap.get(userId).get(packageName);
             if (entry != null) {
-                mPm.getPackageSizeInfo(packageName, userId, mBackgroundHandler.mStatsObserver);
+                mPm.getPackageSizeInfoAsUser(packageName, userId, mBackgroundHandler.mStatsObserver);
             }
             if (DEBUG_LOCKING) Log.v(TAG, "...requestSize releasing lock");
         }
@@ -906,7 +906,7 @@
                                     entry.sizeLoadStart = now;
                                     mCurComputingSizePkg = entry.info.packageName;
                                     mCurComputingSizeUserId = UserHandle.getUserId(entry.info.uid);
-                                    mPm.getPackageSizeInfo(mCurComputingSizePkg,
+                                    mPm.getPackageSizeInfoAsUser(mCurComputingSizePkg,
                                             mCurComputingSizeUserId, mStatsObserver);
                                 }
                                 if (DEBUG_LOCKING) Log.v(TAG, "MSG_LOAD_SIZES releasing: now computing");
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
new file mode 100755
index 0000000..77f2e19
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.BluetoothA2dpSink;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.settingslib.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+final class A2dpSinkProfile implements LocalBluetoothProfile {
+    private static final String TAG = "A2dpSinkProfile";
+    private static boolean V = true;
+
+    private BluetoothA2dpSink mService;
+    private boolean mIsProfileReady;
+
+    private final LocalBluetoothAdapter mLocalAdapter;
+    private final CachedBluetoothDeviceManager mDeviceManager;
+
+    static final ParcelUuid[] SRC_UUIDS = {
+        BluetoothUuid.AudioSource,
+        BluetoothUuid.AdvAudioDist,
+    };
+
+    static final String NAME = "A2DPSink";
+    private final LocalBluetoothProfileManager mProfileManager;
+
+    // Order of this profile in device profiles list
+    private static final int ORDINAL = 5;
+
+    // These callbacks run on the main thread.
+    private final class A2dpSinkServiceListener
+            implements BluetoothProfile.ServiceListener {
+
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            if (V) Log.d(TAG,"Bluetooth service connected");
+            mService = (BluetoothA2dpSink) proxy;
+            // We just bound to the service, so refresh the UI for any connected A2DP devices.
+            List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+            while (!deviceList.isEmpty()) {
+                BluetoothDevice nextDevice = deviceList.remove(0);
+                CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+                // we may add a new device here, but generally this should not happen
+                if (device == null) {
+                    Log.w(TAG, "A2dpSinkProfile found new device: " + nextDevice);
+                    device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
+                }
+                device.onProfileStateChanged(A2dpSinkProfile.this, BluetoothProfile.STATE_CONNECTED);
+                device.refresh();
+            }
+            mIsProfileReady=true;
+        }
+
+        public void onServiceDisconnected(int profile) {
+            if (V) Log.d(TAG,"Bluetooth service disconnected");
+            mIsProfileReady=false;
+        }
+    }
+
+    public boolean isProfileReady() {
+        return mIsProfileReady;
+    }
+
+    A2dpSinkProfile(Context context, LocalBluetoothAdapter adapter,
+            CachedBluetoothDeviceManager deviceManager,
+            LocalBluetoothProfileManager profileManager) {
+        mLocalAdapter = adapter;
+        mDeviceManager = deviceManager;
+        mProfileManager = profileManager;
+        mLocalAdapter.getProfileProxy(context, new A2dpSinkServiceListener(),
+                BluetoothProfile.A2DP_SINK);
+    }
+
+    public boolean isConnectable() {
+        return true;
+    }
+
+    public boolean isAutoConnectable() {
+        return true;
+    }
+
+    public List<BluetoothDevice> getConnectedDevices() {
+        if (mService == null) return new ArrayList<BluetoothDevice>(0);
+        return mService.getDevicesMatchingConnectionStates(
+              new int[] {BluetoothProfile.STATE_CONNECTED,
+                         BluetoothProfile.STATE_CONNECTING,
+                         BluetoothProfile.STATE_DISCONNECTING});
+    }
+
+    public boolean connect(BluetoothDevice device) {
+        if (mService == null) return false;
+        List<BluetoothDevice> 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(src);
+            }
+        }
+        return mService.connect(device);
+    }
+
+    public boolean disconnect(BluetoothDevice device) {
+        if (mService == null) return false;
+        // Downgrade priority as user is disconnecting the headset.
+        if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){
+            mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+        }
+        return mService.disconnect(device);
+    }
+
+    public int getConnectionStatus(BluetoothDevice device) {
+        if (mService == null) {
+            return BluetoothProfile.STATE_DISCONNECTED;
+        }
+        return mService.getConnectionState(device);
+    }
+
+    public boolean isPreferred(BluetoothDevice device) {
+        if (mService == null) return false;
+        return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+    }
+
+    public int getPreferred(BluetoothDevice device) {
+        if (mService == null) return BluetoothProfile.PRIORITY_OFF;
+        return mService.getPriority(device);
+    }
+
+    public void setPreferred(BluetoothDevice device, boolean preferred) {
+        if (mService == null) return;
+        if (preferred) {
+            if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
+                mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+            }
+        } else {
+            mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+        }
+    }
+
+    boolean isA2dpPlaying() {
+        if (mService == null) return false;
+        List<BluetoothDevice> srcs = mService.getConnectedDevices();
+        if (!srcs.isEmpty()) {
+            if (mService.isA2dpPlaying(srcs.get(0))) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public String toString() {
+        return NAME;
+    }
+
+    public int getOrdinal() {
+        return ORDINAL;
+    }
+
+    public int getNameResource(BluetoothDevice device) {
+        // we need to have same string in UI for even SINK Media Audio.
+        return R.string.bluetooth_profile_a2dp;
+    }
+
+    public int getSummaryResourceForDevice(BluetoothDevice device) {
+        int state = getConnectionStatus(device);
+        switch (state) {
+            case BluetoothProfile.STATE_DISCONNECTED:
+                return R.string.bluetooth_a2dp_profile_summary_use_for;
+
+            case BluetoothProfile.STATE_CONNECTED:
+                return R.string.bluetooth_a2dp_profile_summary_connected;
+
+            default:
+                return Utils.getConnectionStateSummary(state);
+        }
+    }
+
+    public int getDrawableResource(BluetoothClass btClass) {
+        return R.drawable.ic_bt_headphones_a2dp;
+    }
+
+    protected void finalize() {
+        if (V) Log.d(TAG, "finalize()");
+        if (mService != null) {
+            try {
+                BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.A2DP_SINK,
+                                                                       mService);
+                mService = null;
+            }catch (Throwable t) {
+                Log.w(TAG, "Error cleaning up A2DP proxy", t);
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index d994841..7ee53a2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -851,7 +851,8 @@
 
                 case BluetoothProfile.STATE_DISCONNECTED:
                     if (profile.isProfileReady()) {
-                        if (profile instanceof A2dpProfile) {
+                        if ((profile instanceof A2dpProfile)||
+                            (profile instanceof A2dpSinkProfile)){
                             a2dpNotConnected = true;
                         } else if (profile instanceof HeadsetProfile) {
                             headsetNotConnected = true;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
old mode 100644
new mode 100755
index f935f31..9c5abf3
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
@@ -162,6 +162,10 @@
                 if (a2dp != null && a2dp.isA2dpPlaying()) {
                     return;
                 }
+                A2dpSinkProfile a2dpSink = mProfileManager.getA2dpSinkProfile();
+                if ((a2dpSink != null) && (a2dpSink.isA2dpPlaying())){
+                    return;
+                }
             }
 
             if (mAdapter.startDiscovery()) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
old mode 100644
new mode 100755
index 8f5e1f1..b05e34c
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -17,6 +17,7 @@
 package com.android.settingslib.bluetooth;
 
 import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothA2dpSink;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothMap;
@@ -73,6 +74,7 @@
     private final BluetoothEventManager mEventManager;
 
     private A2dpProfile mA2dpProfile;
+    private A2dpSinkProfile mA2dpSinkProfile;
     private HeadsetProfile mHeadsetProfile;
     private MapProfile mMapProfile;
     private final HidProfile mHidProfile;
@@ -136,10 +138,10 @@
      * @param uuids
      */
     void updateLocalProfiles(ParcelUuid[] uuids) {
-        // A2DP
+        // A2DP SRC
         if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSource)) {
             if (mA2dpProfile == null) {
-                if(DEBUG) Log.d(TAG, "Adding local A2DP profile");
+                if(DEBUG) Log.d(TAG, "Adding local A2DP SRC profile");
                 mA2dpProfile = new A2dpProfile(mContext, mLocalAdapter, mDeviceManager, this);
                 addProfile(mA2dpProfile, A2dpProfile.NAME,
                         BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
@@ -148,6 +150,17 @@
             Log.w(TAG, "Warning: A2DP profile was previously added but the UUID is now missing.");
         }
 
+        if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSink)) {
+            if (mA2dpSinkProfile == null) {
+                if(DEBUG) Log.d(TAG, "Adding local A2DP Sink profile");
+                mA2dpSinkProfile = new A2dpSinkProfile(mContext, mLocalAdapter, mDeviceManager, this);
+                addProfile(mA2dpSinkProfile, A2dpSinkProfile.NAME,
+                        BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED);
+            }
+        } else if (mA2dpSinkProfile != null) {
+            Log.w(TAG, "Warning: A2DP Sink profile was previously added but the UUID is now missing.");
+        }
+
         // Headset / Handsfree
         if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree_AG) ||
             BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP_AG)) {
@@ -288,6 +301,10 @@
         if (profile != null) {
             return profile.isProfileReady();
         }
+        profile = mA2dpSinkProfile;
+        if (profile != null) {
+            return profile.isProfileReady();
+        }
         return false;
     }
 
@@ -295,6 +312,13 @@
         return mA2dpProfile;
     }
 
+    A2dpSinkProfile getA2dpSinkProfile() {
+        if ((mA2dpSinkProfile != null)&&(mA2dpSinkProfile.isProfileReady()))
+        return mA2dpSinkProfile;
+        else
+            return null;
+    }
+
     public HeadsetProfile getHeadsetProfile() {
         return mHeadsetProfile;
     }
@@ -345,6 +369,12 @@
             removedProfiles.remove(mA2dpProfile);
         }
 
+        if (BluetoothUuid.containsAnyUuid(uuids, A2dpSinkProfile.SRC_UUIDS) &&
+                mA2dpSinkProfile != null) {
+                profiles.add(mA2dpSinkProfile);
+                removedProfiles.remove(mA2dpSinkProfile);
+            }
+
         if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush) &&
             mOppProfile != null) {
             profiles.add(mOppProfile);
diff --git a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
index 7b5bfb5..26e8303 100644
--- a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.res.XmlResourceParser;
+import android.icu.text.TimeZoneNames;
 import android.text.BidiFormatter;
 import android.text.TextDirectionHeuristics;
 import android.text.TextUtils;
@@ -26,20 +27,18 @@
 
 import com.android.settingslib.R;
 
-import libcore.icu.TimeZoneNames;
-
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.TimeZone;
-import java.util.TreeSet;
 
 public class ZoneGetter {
     private static final String TAG = "ZoneGetter";
@@ -56,7 +55,8 @@
     public static String getTimeZoneOffsetAndName(TimeZone tz, Date now) {
         Locale locale = Locale.getDefault();
         String gmtString = getGmtOffsetString(locale, tz, now);
-        String zoneNameString = getZoneLongName(locale, tz, now);
+        TimeZoneNames timeZoneNames = TimeZoneNames.getInstance(locale);
+        String zoneNameString = getZoneLongName(timeZoneNames, tz, now);
         if (zoneNameString == null) {
             return gmtString;
         }
@@ -68,6 +68,7 @@
     public static List<Map<String, Object>> getZonesList(Context context) {
         final Locale locale = Locale.getDefault();
         final Date now = new Date();
+        final TimeZoneNames timeZoneNames = TimeZoneNames.getInstance(locale);
 
         // The display name chosen for each zone entry depends on whether the zone is one associated
         // with the country of the user's chosen locale. For "local" zones we prefer the "long name"
@@ -85,25 +86,41 @@
         // selecting the wrong olson ids.
 
         // Get the list of olson ids to display to the user.
-        List<String> olsonIdsToDisplay = readTimezonesToDisplay(context);
+        List<String> olsonIdsToDisplayList = readTimezonesToDisplay(context);
+
+        // Store the information we are going to need more than once.
+        final int zoneCount = olsonIdsToDisplayList.size();
+        final String[] olsonIdsToDisplay = new String[zoneCount];
+        final TimeZone[] timeZones = new TimeZone[zoneCount];
+        final String[] gmtOffsetStrings = new String[zoneCount];
+        for (int i = 0; i < zoneCount; i++) {
+            String olsonId = olsonIdsToDisplayList.get(i);
+            olsonIdsToDisplay[i] = olsonId;
+            TimeZone tz = TimeZone.getTimeZone(olsonId);
+            timeZones[i] = tz;
+            gmtOffsetStrings[i] = getGmtOffsetString(locale, tz, now);
+        }
 
         // Create a lookup of local zone IDs.
-        Set<String> localZoneIds = new TreeSet<String>();
-        for (String olsonId : TimeZoneNames.forLocale(locale)) {
+        Set<String> localZoneIds = new HashSet<String>();
+        for (String olsonId : libcore.icu.TimeZoneNames.forLocale(locale)) {
             localZoneIds.add(olsonId);
         }
 
-        // Work out whether the long names for the local entries that we would show by default would
-        // be ambiguous.
-        Set<String> localZoneNames = new TreeSet<String>();
-        boolean localLongNamesAreAmbiguous = false;
-        for (String olsonId : olsonIdsToDisplay) {
+        // Work out whether the display names we would show by default would be ambiguous.
+        Set<String> localZoneNames = new HashSet<String>();
+        boolean useExemplarLocationForLocalNames = false;
+        for (int i = 0; i < zoneCount; i++) {
+            String olsonId = olsonIdsToDisplay[i];
             if (localZoneIds.contains(olsonId)) {
-                TimeZone tz = TimeZone.getTimeZone(olsonId);
-                String zoneLongName = getZoneLongName(locale, tz, now);
-                boolean longNameIsUnique = localZoneNames.add(zoneLongName);
-                if (!longNameIsUnique) {
-                    localLongNamesAreAmbiguous = true;
+                TimeZone tz = timeZones[i];
+                String displayName = getZoneLongName(timeZoneNames, tz, now);
+                if (displayName == null) {
+                    displayName = gmtOffsetStrings[i];
+                }
+                boolean nameIsUnique = localZoneNames.add(displayName);
+                if (!nameIsUnique) {
+                    useExemplarLocationForLocalNames = true;
                     break;
                 }
             }
@@ -111,15 +128,27 @@
 
         // Generate the list of zone entries to return.
         List<Map<String, Object>> zones = new ArrayList<Map<String, Object>>();
-        for (String olsonId : olsonIdsToDisplay) {
-            final TimeZone tz = TimeZone.getTimeZone(olsonId);
-            // Exemplar location display is the default. The only time we intend to display the long
-            // name is when the olsonId is local AND long names are not ambiguous.
-            boolean isLocalZoneId = localZoneIds.contains(olsonId);
-            boolean preferLongName = isLocalZoneId && !localLongNamesAreAmbiguous;
-            String displayName = getZoneDisplayName(locale, tz, now, preferLongName);
+        for (int i = 0; i < zoneCount; i++) {
+            String olsonId = olsonIdsToDisplay[i];
+            TimeZone tz = timeZones[i];
+            String gmtOffsetString = gmtOffsetStrings[i];
 
-            String gmtOffsetString = getGmtOffsetString(locale, tz, now);
+            boolean isLocalZoneId = localZoneIds.contains(olsonId);
+            boolean preferLongName = isLocalZoneId && !useExemplarLocationForLocalNames;
+            String displayName;
+            if (preferLongName) {
+                displayName = getZoneLongName(timeZoneNames, tz, now);
+            } else {
+                displayName = timeZoneNames.getExemplarLocationName(tz.getID());
+                if (displayName == null || displayName.isEmpty()) {
+                    // getZoneExemplarLocation can return null. Fall back to the long name.
+                    displayName = getZoneLongName(timeZoneNames, tz, now);
+                }
+            }
+            if (displayName == null  || displayName.isEmpty()) {
+                displayName = gmtOffsetString;
+            }
+
             int offsetMillis = tz.getOffset(now.getTime());
             Map<String, Object> displayEntry =
                     createDisplayEntry(tz, gmtOffsetString, displayName, offsetMillis);
@@ -138,30 +167,6 @@
         return map;
     }
 
-    /**
-     * Returns a name for the specific zone. If {@code preferLongName} is {@code true} then the
-     * long display name for the timezone will be used, otherwise the exemplar location will be
-     * preferred.
-     */
-    private static String getZoneDisplayName(Locale locale, TimeZone tz, Date now,
-            boolean preferLongName) {
-        String zoneNameString;
-        if (preferLongName) {
-            zoneNameString = getZoneLongName(locale, tz, now);
-        } else {
-            zoneNameString = getZoneExemplarLocation(locale, tz);
-            if (zoneNameString == null || zoneNameString.isEmpty()) {
-                // getZoneExemplarLocation can return null.
-                zoneNameString = getZoneLongName(locale, tz, now);
-            }
-        }
-        return zoneNameString;
-    }
-
-    private static String getZoneExemplarLocation(Locale locale, TimeZone tz) {
-        return TimeZoneNames.getExemplarLocation(locale.toString(), tz.getID());
-    }
-
     private static List<String> readTimezonesToDisplay(Context context) {
         List<String> olsonIds = new ArrayList<String>();
         try (XmlResourceParser xrp = context.getResources().getXml(R.xml.timezones)) {
@@ -193,10 +198,15 @@
         return olsonIds;
     }
 
-    private static String getZoneLongName(Locale locale, TimeZone tz, Date now) {
-        boolean daylight = tz.inDaylightTime(now);
-        // This returns a name if it can, or will fall back to GMT+0X:00 format.
-        return tz.getDisplayName(daylight, TimeZone.LONG, locale);
+    /**
+     * Returns the long name for the timezone for the given locale at the time specified.
+     * Can return {@code null}.
+     */
+    private static String getZoneLongName(TimeZoneNames names, TimeZone tz, Date now) {
+        TimeZoneNames.NameType nameType =
+                tz.inDaylightTime(now) ? TimeZoneNames.NameType.LONG_DAYLIGHT
+                : TimeZoneNames.NameType.LONG_STANDARD;
+        return names.getDisplayName(tz.getID(), nameType, now.getTime());
     }
 
     private static String getGmtOffsetString(Locale locale, TimeZone tz, Date now) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
index 9790e64..3b818c8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
@@ -422,7 +422,7 @@
                     ActivityManager.getCurrentUser(), currentProfiles, finished, count);
             for (UserInfo user : users) {
                 for (ApplicationInfo app : volumeApps) {
-                    packageManager.getPackageSizeInfo(app.packageName, user.id, observer);
+                    packageManager.getPackageSizeInfoAsUser(app.packageName, user.id, observer);
                 }
             }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java b/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java
index 0f322cf..53be0e6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java
@@ -43,22 +43,22 @@
     /**
      * List of the category's children
      */
-    public List<DashboardTile> tiles = new ArrayList<DashboardTile>();
+    public List<Tile> tiles = new ArrayList<Tile>();
 
 
     public DashboardCategory() {
         // Empty
     }
 
-    public void addTile(DashboardTile tile) {
+    public void addTile(Tile tile) {
         tiles.add(tile);
     }
 
-    public void addTile(int n, DashboardTile tile) {
+    public void addTile(int n, Tile tile) {
         tiles.add(n, tile);
     }
 
-    public void removeTile(DashboardTile tile) {
+    public void removeTile(Tile tile) {
         tiles.remove(tile);
     }
 
@@ -70,7 +70,7 @@
         return tiles.size();
     }
 
-    public DashboardTile getTile(int n) {
+    public Tile getTile(int n) {
         return tiles.get(n);
     }
 
@@ -89,7 +89,7 @@
         dest.writeInt(count);
 
         for (int n = 0; n < count; n++) {
-            DashboardTile tile = tiles.get(n);
+            Tile tile = tiles.get(n);
             tile.writeToParcel(dest, flags);
         }
     }
@@ -102,7 +102,7 @@
         final int count = in.readInt();
 
         for (int n = 0; n < count; n++) {
-            DashboardTile tile = DashboardTile.CREATOR.createFromParcel(in);
+            Tile tile = Tile.CREATOR.createFromParcel(in);
             tiles.add(tile);
         }
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardTile.java b/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardTile.java
deleted file mode 100644
index 347e9f7..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardTile.java
+++ /dev/null
@@ -1,149 +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.settingslib.drawer;
-
-import android.content.Intent;
-import android.graphics.drawable.Icon;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.UserHandle;
-import android.text.TextUtils;
-
-import java.util.ArrayList;
-
-/**
- * Description of a single dashboard tile that the user can select.
- */
-public class DashboardTile implements Parcelable {
-
-    /**
-     * Title of the tile that is shown to the user.
-     * @attr ref android.R.styleable#PreferenceHeader_title
-     */
-    public CharSequence title;
-
-    /**
-     * Optional summary describing what this tile controls.
-     * @attr ref android.R.styleable#PreferenceHeader_summary
-     */
-    public CharSequence summary;
-
-    /**
-     * Optional icon to show for this tile.
-     * @attr ref android.R.styleable#PreferenceHeader_icon
-     */
-    public Icon icon;
-
-    /**
-     * Intent to launch when the preference is selected.
-     */
-    public Intent intent;
-
-    /**
-     * Optional list of user handles which the intent should be launched on.
-     */
-    public ArrayList<UserHandle> userHandle = new ArrayList<>();
-
-    /**
-     * Optional additional data for use by subclasses of the activity
-     */
-    public Bundle extras;
-
-    /**
-     * Category in which the tile should be placed.
-     */
-    public String category;
-
-    /**
-     * Priority of the intent filter that created this tile, used for display ordering.
-     */
-    public int priority;
-
-    /**
-     * The metaData from the activity that defines this tile.
-     */
-    public Bundle metaData;
-
-    public DashboardTile() {
-        // Empty
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        TextUtils.writeToParcel(title, dest, flags);
-        TextUtils.writeToParcel(summary, dest, flags);
-        if (icon != null) {
-            dest.writeByte((byte) 1);
-            icon.writeToParcel(dest, flags);
-        } else {
-            dest.writeByte((byte) 0);
-        }
-        if (intent != null) {
-            dest.writeByte((byte) 1);
-            intent.writeToParcel(dest, flags);
-        } else {
-            dest.writeByte((byte) 0);
-        }
-        final int N = userHandle.size();
-        dest.writeInt(N);
-        for (int i = 0; i < N; i++) {
-            userHandle.get(i).writeToParcel(dest, flags);
-        }
-        dest.writeBundle(extras);
-        dest.writeString(category);
-        dest.writeInt(priority);
-        dest.writeBundle(metaData);
-    }
-
-    public void readFromParcel(Parcel in) {
-        title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-        summary = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-        if (in.readByte() != 0) {
-            icon = Icon.CREATOR.createFromParcel(in);
-        }
-        if (in.readByte() != 0) {
-            intent = Intent.CREATOR.createFromParcel(in);
-        }
-        final int N = in.readInt();
-        for (int i = 0; i < N; i++) {
-            userHandle.add(UserHandle.CREATOR.createFromParcel(in));
-        }
-        extras = in.readBundle();
-        category = in.readString();
-        priority = in.readInt();
-        metaData = in.readBundle();
-    }
-
-    DashboardTile(Parcel in) {
-        readFromParcel(in);
-    }
-
-    public static final Creator<DashboardTile> CREATOR = new Creator<DashboardTile>() {
-        public DashboardTile createFromParcel(Parcel source) {
-            return new DashboardTile(source);
-        }
-        public DashboardTile[] newArray(int size) {
-            return new DashboardTile[size];
-        }
-    };
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/ProfileSelectDialog.java b/packages/SettingsLib/src/com/android/settingslib/drawer/ProfileSelectDialog.java
index 793e877d..dc6002d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/ProfileSelectDialog.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/ProfileSelectDialog.java
@@ -30,9 +30,9 @@
 
     private static final String ARG_SELECTED_TILE = "selectedTile";
 
-    private DashboardTile mSelectedTile;
+    private Tile mSelectedTile;
 
-    public static void show(FragmentManager manager, DashboardTile tile) {
+    public static void show(FragmentManager manager, Tile tile) {
         ProfileSelectDialog dialog = new ProfileSelectDialog();
         Bundle args = new Bundle();
         args.putParcelable(ARG_SELECTED_TILE, tile);
@@ -61,6 +61,8 @@
     @Override
     public void onClick(DialogInterface dialog, int which) {
         UserHandle user = mSelectedTile.userHandle.get(which);
+        // Show menu on top level items.
+        mSelectedTile.intent.putExtra(SettingsDrawerActivity.EXTRA_SHOW_MENU, true);
         getActivity().startActivityAsUser(mSelectedTile.intent, user);
         ((SettingsDrawerActivity) getActivity()).onProfileTileOpen();
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index 102e47a..56c4edb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -48,14 +48,17 @@
     protected static final boolean DEBUG_TIMING = false;
     private static final String TAG = "SettingsDrawerActivity";
 
+    static final String EXTRA_SHOW_MENU = "show_drawer_menu";
+
     private static List<DashboardCategory> sDashboardCategories;
-    private static HashMap<Pair<String, String>, DashboardTile> sTileCache;
+    private static HashMap<Pair<String, String>, Tile> sTileCache;
 
     private final PackageReceiver mPackageReceiver = new PackageReceiver();
     private final List<CategoryListener> mCategoryListeners = new ArrayList<>();
 
     private SettingsDrawerAdapter mDrawerAdapter;
     private DrawerLayout mDrawerLayout;
+    private boolean mShowingMenu;
 
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -94,7 +97,7 @@
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
-        if (mDrawerLayout != null && item.getItemId() == android.R.id.home
+        if (mShowingMenu && mDrawerLayout != null && item.getItemId() == android.R.id.home
                 && mDrawerAdapter.getCount() != 0) {
             openDrawer();
             return true;
@@ -116,6 +119,9 @@
 
             new CategoriesUpdater().execute();
         }
+        if (getIntent() != null && getIntent().getBooleanExtra(EXTRA_SHOW_MENU, false)) {
+            showMenuIcon();
+        }
     }
 
     @Override
@@ -171,13 +177,17 @@
         mDrawerAdapter.updateCategories();
         if (mDrawerAdapter.getCount() != 0) {
             mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
-            getActionBar().setHomeAsUpIndicator(R.drawable.ic_menu);
-            getActionBar().setDisplayHomeAsUpEnabled(true);
         } else {
             mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
         }
     }
 
+    public void showMenuIcon() {
+        mShowingMenu = true;
+        getActionBar().setHomeAsUpIndicator(R.drawable.ic_menu);
+        getActionBar().setDisplayHomeAsUpEnabled(true);
+    }
+
     public List<DashboardCategory> getDashboardCategories() {
         if (sDashboardCategories == null) {
             sTileCache = new HashMap<>();
@@ -194,7 +204,7 @@
         }
     }
 
-    public boolean openTile(DashboardTile tile) {
+    public boolean openTile(Tile tile) {
         closeDrawer();
         if (tile == null) {
             return false;
@@ -204,14 +214,18 @@
             ProfileSelectDialog.show(getFragmentManager(), tile);
             return false;
         } else if (numUserHandles == 1) {
+            // Show menu on top level items.
+            tile.intent.putExtra(EXTRA_SHOW_MENU, true);
             startActivityAsUser(tile.intent, tile.userHandle.get(0));
         } else {
+            // Show menu on top level items.
+            tile.intent.putExtra(EXTRA_SHOW_MENU, true);
             startActivity(tile.intent);
         }
         return true;
     }
 
-    protected void onTileClicked(DashboardTile tile) {
+    protected void onTileClicked(Tile tile) {
         if (openTile(tile)) {
             finish();
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
index 24c6ae8..72f1c566 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
@@ -48,7 +48,7 @@
             mItems.add(category);
             for (int j = 0; j < dashboardCategory.tiles.size(); j++) {
                 Item tile = new Item();
-                DashboardTile dashboardTile = dashboardCategory.tiles.get(j);
+                Tile dashboardTile = dashboardCategory.tiles.get(j);
                 tile.label = dashboardTile.title;
                 tile.icon = dashboardTile.icon;
                 tile.tile = dashboardTile;
@@ -58,7 +58,7 @@
         notifyDataSetChanged();
     }
 
-    public DashboardTile getTile(int position) {
+    public Tile getTile(int position) {
         return mItems.get(position).tile;
     }
 
@@ -101,6 +101,6 @@
     private static class Item {
         public Icon icon;
         public CharSequence label;
-        public DashboardTile tile;
+        public Tile tile;
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
new file mode 100644
index 0000000..b16cd08
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
@@ -0,0 +1,149 @@
+/**
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.drawer;
+
+import android.content.Intent;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+
+/**
+ * Description of a single dashboard tile that the user can select.
+ */
+public class Tile implements Parcelable {
+
+    /**
+     * Title of the tile that is shown to the user.
+     * @attr ref android.R.styleable#PreferenceHeader_title
+     */
+    public CharSequence title;
+
+    /**
+     * Optional summary describing what this tile controls.
+     * @attr ref android.R.styleable#PreferenceHeader_summary
+     */
+    public CharSequence summary;
+
+    /**
+     * Optional icon to show for this tile.
+     * @attr ref android.R.styleable#PreferenceHeader_icon
+     */
+    public Icon icon;
+
+    /**
+     * Intent to launch when the preference is selected.
+     */
+    public Intent intent;
+
+    /**
+     * Optional list of user handles which the intent should be launched on.
+     */
+    public ArrayList<UserHandle> userHandle = new ArrayList<>();
+
+    /**
+     * Optional additional data for use by subclasses of the activity
+     */
+    public Bundle extras;
+
+    /**
+     * Category in which the tile should be placed.
+     */
+    public String category;
+
+    /**
+     * Priority of the intent filter that created this tile, used for display ordering.
+     */
+    public int priority;
+
+    /**
+     * The metaData from the activity that defines this tile.
+     */
+    public Bundle metaData;
+
+    public Tile() {
+        // Empty
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        TextUtils.writeToParcel(title, dest, flags);
+        TextUtils.writeToParcel(summary, dest, flags);
+        if (icon != null) {
+            dest.writeByte((byte) 1);
+            icon.writeToParcel(dest, flags);
+        } else {
+            dest.writeByte((byte) 0);
+        }
+        if (intent != null) {
+            dest.writeByte((byte) 1);
+            intent.writeToParcel(dest, flags);
+        } else {
+            dest.writeByte((byte) 0);
+        }
+        final int N = userHandle.size();
+        dest.writeInt(N);
+        for (int i = 0; i < N; i++) {
+            userHandle.get(i).writeToParcel(dest, flags);
+        }
+        dest.writeBundle(extras);
+        dest.writeString(category);
+        dest.writeInt(priority);
+        dest.writeBundle(metaData);
+    }
+
+    public void readFromParcel(Parcel in) {
+        title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+        summary = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+        if (in.readByte() != 0) {
+            icon = Icon.CREATOR.createFromParcel(in);
+        }
+        if (in.readByte() != 0) {
+            intent = Intent.CREATOR.createFromParcel(in);
+        }
+        final int N = in.readInt();
+        for (int i = 0; i < N; i++) {
+            userHandle.add(UserHandle.CREATOR.createFromParcel(in));
+        }
+        extras = in.readBundle();
+        category = in.readString();
+        priority = in.readInt();
+        metaData = in.readBundle();
+    }
+
+    Tile(Parcel in) {
+        readFromParcel(in);
+    }
+
+    public static final Creator<Tile> CREATOR = new Creator<Tile>() {
+        public Tile createFromParcel(Parcel source) {
+            return new Tile(source);
+        }
+        public Tile[] newArray(int size) {
+            return new Tile[size];
+        }
+    };
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index 6b36680..2dfdfda 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -1,13 +1,18 @@
 /*
  * Copyright (C) 2015 The Android Open Source Project
  *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
  *      http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under 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
  */
-
 package com.android.settingslib.drawer;
 
 import android.app.ActivityManager;
@@ -108,9 +113,9 @@
     private static final String SETTING_PKG = "com.android.settings";
 
     public static List<DashboardCategory> getCategories(Context context,
-            HashMap<Pair<String, String>, DashboardTile> cache) {
+            HashMap<Pair<String, String>, Tile> cache) {
         final long startTime = System.currentTimeMillis();
-        ArrayList<DashboardTile> tiles = new ArrayList<>();
+        ArrayList<Tile> tiles = new ArrayList<>();
         UserManager userManager = UserManager.get(context);
         for (UserHandle user : userManager.getUserProfiles()) {
             // TODO: Needs much optimization, too many PM queries going on here.
@@ -125,7 +130,7 @@
             getTilesForAction(context, user, EXTRA_SETTINGS_ACTION, cache, null, tiles, false);
         }
         HashMap<String, DashboardCategory> categoryMap = new HashMap<>();
-        for (DashboardTile tile : tiles) {
+        for (Tile tile : tiles) {
             DashboardCategory category = categoryMap.get(tile.category);
             if (category == null) {
                 category = createCategory(context, tile.category);
@@ -170,30 +175,34 @@
     }
 
     private static void getTilesForAction(Context context,
-            UserHandle user, String action, Map<Pair<String, String>, DashboardTile> addedCache,
-            String defaultCategory, ArrayList<DashboardTile> outTiles, boolean requireSettings) {
-        PackageManager pm = context.getPackageManager();
+            UserHandle user, String action, Map<Pair<String, String>, Tile> addedCache,
+            String defaultCategory, ArrayList<Tile> outTiles, boolean requireSettings) {
         Intent intent = new Intent(action);
+        if (requireSettings) {
+            intent.setPackage(SETTING_PKG);
+        }
+        getTilesForIntent(context, user, intent, addedCache, defaultCategory, outTiles,
+                requireSettings, true);
+    }
+
+    public static void getTilesForIntent(Context context, UserHandle user, Intent intent,
+            Map<Pair<String, String>, Tile> addedCache, String defaultCategory, List<Tile> outTiles,
+            boolean usePriority, boolean checkCategory) {
+        PackageManager pm = context.getPackageManager();
         List<ResolveInfo> results = pm.queryIntentActivitiesAsUser(intent,
                 PackageManager.GET_META_DATA, user.getIdentifier());
         for (ResolveInfo resolved : results) {
-            if (requireSettings) {
-                if (!SETTING_PKG.equals(resolved.activityInfo.applicationInfo.packageName)) {
-                    continue;
-                }
-            } else {
-                if (!resolved.system) {
-                    // Do not allow any app to add to settings, only system ones.
-                    continue;
-                }
+            if (!resolved.system) {
+                // Do not allow any app to add to settings, only system ones.
+                continue;
             }
             ActivityInfo activityInfo = resolved.activityInfo;
             Bundle metaData = activityInfo.metaData;
             String categoryKey = defaultCategory;
-            if (((metaData == null) || !metaData.containsKey(EXTRA_CATEGORY_KEY))
+            if (checkCategory && ((metaData == null) || !metaData.containsKey(EXTRA_CATEGORY_KEY))
                     && categoryKey == null) {
-                Log.w(LOG_TAG, "Found " + resolved.activityInfo.name + " for action "
-                        + action + " missing metadata "
+                Log.w(LOG_TAG, "Found " + resolved.activityInfo.name + " for intent "
+                        + intent + " missing metadata "
                         + (metaData == null ? "" : EXTRA_CATEGORY_KEY));
                 continue;
             } else {
@@ -201,13 +210,13 @@
             }
             Pair<String, String> key = new Pair<String, String>(activityInfo.packageName,
                     activityInfo.name);
-            DashboardTile tile = addedCache.get(key);
+            Tile tile = addedCache.get(key);
             if (tile == null) {
-                tile = new DashboardTile();
+                tile = new Tile();
                 tile.intent = new Intent().setClassName(
                         activityInfo.packageName, activityInfo.name);
                 tile.category = categoryKey;
-                tile.priority = requireSettings ? resolved.priority : 0;
+                tile.priority = usePriority ? resolved.priority : 0;
                 tile.metaData = activityInfo.metaData;
                 updateTileData(context, tile, activityInfo, activityInfo.applicationInfo,
                         pm);
@@ -234,7 +243,7 @@
         return null;
     }
 
-    private static boolean updateTileData(Context context, DashboardTile tile,
+    private static boolean updateTileData(Context context, Tile tile,
             ActivityInfo activityInfo, ApplicationInfo applicationInfo, PackageManager pm) {
         if (applicationInfo.isSystemApp()) {
             int icon = 0;
@@ -252,10 +261,18 @@
                         icon = metaData.getInt(META_DATA_PREFERENCE_ICON);
                     }
                     if (metaData.containsKey(META_DATA_PREFERENCE_TITLE)) {
-                        title = metaData.getString(META_DATA_PREFERENCE_TITLE);
+                        if (metaData.get(META_DATA_PREFERENCE_TITLE) instanceof Integer) {
+                            title = res.getString(metaData.getInt(META_DATA_PREFERENCE_TITLE));
+                        } else {
+                            title = metaData.getString(META_DATA_PREFERENCE_TITLE);
+                        }
                     }
                     if (metaData.containsKey(META_DATA_PREFERENCE_SUMMARY)) {
-                        summary = metaData.getString(META_DATA_PREFERENCE_SUMMARY);
+                        if (metaData.get(META_DATA_PREFERENCE_SUMMARY) instanceof Integer) {
+                            summary = res.getString(metaData.getInt(META_DATA_PREFERENCE_SUMMARY));
+                        } else {
+                            summary = metaData.getString(META_DATA_PREFERENCE_SUMMARY);
+                        }
                     }
                 }
             } catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) {
@@ -285,10 +302,10 @@
         return false;
     }
 
-    private static final Comparator<DashboardTile> TILE_COMPARATOR =
-            new Comparator<DashboardTile>() {
+    private static final Comparator<Tile> TILE_COMPARATOR =
+            new Comparator<Tile>() {
         @Override
-        public int compare(DashboardTile lhs, DashboardTile rhs) {
+        public int compare(Tile lhs, Tile rhs) {
             return rhs.priority - lhs.priority;
         }
     };
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
new file mode 100644
index 0000000..e53dd2f
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.net;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.INetworkStatsService;
+import android.net.INetworkStatsSession;
+import android.net.NetworkPolicy;
+import android.net.NetworkPolicyManager;
+import android.net.NetworkStatsHistory;
+import android.net.NetworkTemplate;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.text.format.DateUtils;
+import android.text.format.Time;
+import android.util.Log;
+
+import java.util.Date;
+import java.util.Locale;
+
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
+import static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
+import static android.telephony.TelephonyManager.SIM_STATE_READY;
+import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
+import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
+
+public class DataUsageController {
+    private static final String TAG = "DataUsageController";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    public static final long DEFAULT_WARNING_LEVEL = 2L * 1024 * 1024 * 1024;
+    private static final int FIELDS = FIELD_RX_BYTES | FIELD_TX_BYTES;
+    private static final StringBuilder PERIOD_BUILDER = new StringBuilder(50);
+    private static final java.util.Formatter PERIOD_FORMATTER = new java.util.Formatter(
+            PERIOD_BUILDER, Locale.getDefault());
+
+    private final Context mContext;
+    private final TelephonyManager mTelephonyManager;
+    private final ConnectivityManager mConnectivityManager;
+    private final INetworkStatsService mStatsService;
+    private final NetworkPolicyManager mPolicyManager;
+
+    private INetworkStatsSession mSession;
+    private Callback mCallback;
+    private NetworkNameProvider mNetworkController;
+
+    public DataUsageController(Context context) {
+        mContext = context;
+        mTelephonyManager = TelephonyManager.from(context);
+        mConnectivityManager = ConnectivityManager.from(context);
+        mStatsService = INetworkStatsService.Stub.asInterface(
+                ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+        mPolicyManager = NetworkPolicyManager.from(mContext);
+    }
+
+    public void setNetworkController(NetworkNameProvider networkController) {
+        mNetworkController = networkController;
+    }
+
+    private INetworkStatsSession getSession() {
+        if (mSession == null) {
+            try {
+                mSession = mStatsService.openSession();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to open stats session", e);
+            } catch (RuntimeException e) {
+                Log.w(TAG, "Failed to open stats session", e);
+            }
+        }
+        return mSession;
+    }
+
+    public void setCallback(Callback callback) {
+        mCallback = callback;
+    }
+
+    private DataUsageInfo warn(String msg) {
+        Log.w(TAG, "Failed to get data usage, " + msg);
+        return null;
+    }
+
+    private static Time addMonth(Time t, int months) {
+        final Time rt = new Time(t);
+        rt.set(t.monthDay, t.month + months, t.year);
+        rt.normalize(false);
+        return rt;
+    }
+
+    public DataUsageInfo getDataUsageInfo() {
+        final String subscriberId = getActiveSubscriberId(mContext);
+        if (subscriberId == null) {
+            return warn("no subscriber id");
+        }
+        NetworkTemplate template = NetworkTemplate.buildTemplateMobileAll(subscriberId);
+        template = NetworkTemplate.normalize(template, mTelephonyManager.getMergedSubscriberIds());
+
+        return getDataUsageInfo(template);
+    }
+
+    public DataUsageInfo getWifiDataUsageInfo() {
+        NetworkTemplate template = NetworkTemplate.buildTemplateWifiWildcard();
+        return getDataUsageInfo(template);
+    }
+
+    public DataUsageInfo getDataUsageInfo(NetworkTemplate template) {
+        final INetworkStatsSession session = getSession();
+        if (session == null) {
+            return warn("no stats session");
+        }
+        final NetworkPolicy policy = findNetworkPolicy(template);
+        try {
+            final NetworkStatsHistory history = session.getHistoryForNetwork(template, FIELDS);
+            final long now = System.currentTimeMillis();
+            final long start, end;
+            if (policy != null && policy.cycleDay > 0) {
+                // period = determined from cycleDay
+                if (DEBUG) Log.d(TAG, "Cycle day=" + policy.cycleDay + " tz="
+                        + policy.cycleTimezone);
+                final Time nowTime = new Time(policy.cycleTimezone);
+                nowTime.setToNow();
+                final Time policyTime = new Time(nowTime);
+                policyTime.set(policy.cycleDay, policyTime.month, policyTime.year);
+                policyTime.normalize(false);
+                if (nowTime.after(policyTime)) {
+                    start = policyTime.toMillis(false);
+                    end = addMonth(policyTime, 1).toMillis(false);
+                } else {
+                    start = addMonth(policyTime, -1).toMillis(false);
+                    end = policyTime.toMillis(false);
+                }
+            } else {
+                // period = last 4 wks
+                end = now;
+                start = now - DateUtils.WEEK_IN_MILLIS * 4;
+            }
+            final long callStart = System.currentTimeMillis();
+            final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null);
+            final long callEnd = System.currentTimeMillis();
+            if (DEBUG) Log.d(TAG, String.format("history call from %s to %s now=%s took %sms: %s",
+                    new Date(start), new Date(end), new Date(now), callEnd - callStart,
+                    historyEntryToString(entry)));
+            if (entry == null) {
+                return warn("no entry data");
+            }
+            final long totalBytes = entry.rxBytes + entry.txBytes;
+            final DataUsageInfo usage = new DataUsageInfo();
+            usage.startDate = start;
+            usage.usageLevel = totalBytes;
+            usage.period = formatDateRange(start, end);
+            if (policy != null) {
+                usage.limitLevel = policy.limitBytes > 0 ? policy.limitBytes : 0;
+                usage.warningLevel = policy.warningBytes > 0 ? policy.warningBytes : 0;
+            } else {
+                usage.warningLevel = DEFAULT_WARNING_LEVEL;
+            }
+            if (usage != null && mNetworkController != null) {
+                usage.carrier = mNetworkController.getMobileDataNetworkName();
+            }
+            return usage;
+        } catch (RemoteException e) {
+            return warn("remote call failed");
+        }
+    }
+
+    private NetworkPolicy findNetworkPolicy(NetworkTemplate template) {
+        if (mPolicyManager == null || template == null) return null;
+        final NetworkPolicy[] policies = mPolicyManager.getNetworkPolicies();
+        if (policies == null) return null;
+        final int N = policies.length;
+        for (int i = 0; i < N; i++) {
+            final NetworkPolicy policy = policies[i];
+            if (policy != null && template.equals(policy.template)) {
+                return policy;
+            }
+        }
+        return null;
+    }
+
+    private static String historyEntryToString(NetworkStatsHistory.Entry entry) {
+        return entry == null ? null : new StringBuilder("Entry[")
+                .append("bucketDuration=").append(entry.bucketDuration)
+                .append(",bucketStart=").append(entry.bucketStart)
+                .append(",activeTime=").append(entry.activeTime)
+                .append(",rxBytes=").append(entry.rxBytes)
+                .append(",rxPackets=").append(entry.rxPackets)
+                .append(",txBytes=").append(entry.txBytes)
+                .append(",txPackets=").append(entry.txPackets)
+                .append(",operations=").append(entry.operations)
+                .append(']').toString();
+    }
+
+    public void setMobileDataEnabled(boolean enabled) {
+        Log.d(TAG, "setMobileDataEnabled: enabled=" + enabled);
+        mTelephonyManager.setDataEnabled(enabled);
+        if (mCallback != null) {
+            mCallback.onMobileDataEnabled(enabled);
+        }
+    }
+
+    public boolean isMobileDataSupported() {
+        // require both supported network and ready SIM
+        return mConnectivityManager.isNetworkSupported(TYPE_MOBILE)
+                && mTelephonyManager.getSimState() == SIM_STATE_READY;
+    }
+
+    public boolean isMobileDataEnabled() {
+        return mTelephonyManager.getDataEnabled();
+    }
+
+    private static String getActiveSubscriberId(Context context) {
+        final TelephonyManager tele = TelephonyManager.from(context);
+        final String actualSubscriberId = tele.getSubscriberId(
+                SubscriptionManager.getDefaultDataSubscriptionId());
+        return actualSubscriberId;
+    }
+
+    private String formatDateRange(long start, long end) {
+        final int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_MONTH;
+        synchronized (PERIOD_BUILDER) {
+            PERIOD_BUILDER.setLength(0);
+            return DateUtils.formatDateRange(mContext, PERIOD_FORMATTER, start, end, flags, null)
+                    .toString();
+        }
+    }
+
+    public interface NetworkNameProvider {
+        String getMobileDataNetworkName();
+    }
+
+    public static class DataUsageInfo {
+        public String carrier;
+        public String period;
+        public long startDate;
+        public long limitLevel;
+        public long warningLevel;
+        public long usageLevel;
+    }
+
+    public interface Callback {
+        void onMobileDataEnabled(boolean enabled);
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/MobileDataController.java b/packages/SettingsLib/src/com/android/settingslib/net/MobileDataController.java
deleted file mode 100644
index 642b60e..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/net/MobileDataController.java
+++ /dev/null
@@ -1,249 +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.settingslib.net;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.INetworkStatsService;
-import android.net.INetworkStatsSession;
-import android.net.NetworkPolicy;
-import android.net.NetworkPolicyManager;
-import android.net.NetworkStatsHistory;
-import android.net.NetworkTemplate;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.text.format.DateUtils;
-import android.text.format.Time;
-import android.util.Log;
-
-import java.util.Date;
-import java.util.Locale;
-
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
-import static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
-import static android.telephony.TelephonyManager.SIM_STATE_READY;
-import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
-import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
-
-public class MobileDataController {
-    private static final String TAG = "MobileDataController";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
-    private static final long DEFAULT_WARNING_LEVEL = 2L * 1024 * 1024 * 1024;
-    private static final int FIELDS = FIELD_RX_BYTES | FIELD_TX_BYTES;
-    private static final StringBuilder PERIOD_BUILDER = new StringBuilder(50);
-    private static final java.util.Formatter PERIOD_FORMATTER = new java.util.Formatter(
-            PERIOD_BUILDER, Locale.getDefault());
-
-    private final Context mContext;
-    private final TelephonyManager mTelephonyManager;
-    private final ConnectivityManager mConnectivityManager;
-    private final INetworkStatsService mStatsService;
-    private final NetworkPolicyManager mPolicyManager;
-
-    private INetworkStatsSession mSession;
-    private Callback mCallback;
-    private NetworkNameProvider mNetworkController;
-
-    public MobileDataController(Context context) {
-        mContext = context;
-        mTelephonyManager = TelephonyManager.from(context);
-        mConnectivityManager = ConnectivityManager.from(context);
-        mStatsService = INetworkStatsService.Stub.asInterface(
-                ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
-        mPolicyManager = NetworkPolicyManager.from(mContext);
-    }
-
-    public void setNetworkController(NetworkNameProvider networkController) {
-        mNetworkController = networkController;
-    }
-
-    private INetworkStatsSession getSession() {
-        if (mSession == null) {
-            try {
-                mSession = mStatsService.openSession();
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed to open stats session", e);
-            } catch (RuntimeException e) {
-                Log.w(TAG, "Failed to open stats session", e);
-            }
-        }
-        return mSession;
-    }
-
-    public void setCallback(Callback callback) {
-        mCallback = callback;
-    }
-
-    private DataUsageInfo warn(String msg) {
-        Log.w(TAG, "Failed to get data usage, " + msg);
-        return null;
-    }
-
-    private static Time addMonth(Time t, int months) {
-        final Time rt = new Time(t);
-        rt.set(t.monthDay, t.month + months, t.year);
-        rt.normalize(false);
-        return rt;
-    }
-
-    public DataUsageInfo getDataUsageInfo() {
-        final String subscriberId = getActiveSubscriberId(mContext);
-        if (subscriberId == null) {
-            return warn("no subscriber id");
-        }
-        final INetworkStatsSession session = getSession();
-        if (session == null) {
-            return warn("no stats session");
-        }
-        NetworkTemplate template = NetworkTemplate.buildTemplateMobileAll(subscriberId);
-        template = NetworkTemplate.normalize(template, mTelephonyManager.getMergedSubscriberIds());
-
-        final NetworkPolicy policy = findNetworkPolicy(template);
-        try {
-            final NetworkStatsHistory history = mSession.getHistoryForNetwork(template, FIELDS);
-            final long now = System.currentTimeMillis();
-            final long start, end;
-            if (policy != null && policy.cycleDay > 0) {
-                // period = determined from cycleDay
-                if (DEBUG) Log.d(TAG, "Cycle day=" + policy.cycleDay + " tz="
-                        + policy.cycleTimezone);
-                final Time nowTime = new Time(policy.cycleTimezone);
-                nowTime.setToNow();
-                final Time policyTime = new Time(nowTime);
-                policyTime.set(policy.cycleDay, policyTime.month, policyTime.year);
-                policyTime.normalize(false);
-                if (nowTime.after(policyTime)) {
-                    start = policyTime.toMillis(false);
-                    end = addMonth(policyTime, 1).toMillis(false);
-                } else {
-                    start = addMonth(policyTime, -1).toMillis(false);
-                    end = policyTime.toMillis(false);
-                }
-            } else {
-                // period = last 4 wks
-                end = now;
-                start = now - DateUtils.WEEK_IN_MILLIS * 4;
-            }
-            final long callStart = System.currentTimeMillis();
-            final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null);
-            final long callEnd = System.currentTimeMillis();
-            if (DEBUG) Log.d(TAG, String.format("history call from %s to %s now=%s took %sms: %s",
-                    new Date(start), new Date(end), new Date(now), callEnd - callStart,
-                    historyEntryToString(entry)));
-            if (entry == null) {
-                return warn("no entry data");
-            }
-            final long totalBytes = entry.rxBytes + entry.txBytes;
-            final DataUsageInfo usage = new DataUsageInfo();
-            usage.usageLevel = totalBytes;
-            usage.period = formatDateRange(start, end);
-            if (policy != null) {
-                usage.limitLevel = policy.limitBytes > 0 ? policy.limitBytes : 0;
-                usage.warningLevel = policy.warningBytes > 0 ? policy.warningBytes : 0;
-            } else {
-                usage.warningLevel = DEFAULT_WARNING_LEVEL;
-            }
-            if (usage != null && mNetworkController != null) {
-                usage.carrier = mNetworkController.getMobileDataNetworkName();
-            }
-            return usage;
-        } catch (RemoteException e) {
-            return warn("remote call failed");
-        }
-    }
-
-    private NetworkPolicy findNetworkPolicy(NetworkTemplate template) {
-        if (mPolicyManager == null || template == null) return null;
-        final NetworkPolicy[] policies = mPolicyManager.getNetworkPolicies();
-        if (policies == null) return null;
-        final int N = policies.length;
-        for (int i = 0; i < N; i++) {
-            final NetworkPolicy policy = policies[i];
-            if (policy != null && template.equals(policy.template)) {
-                return policy;
-            }
-        }
-        return null;
-    }
-
-    private static String historyEntryToString(NetworkStatsHistory.Entry entry) {
-        return entry == null ? null : new StringBuilder("Entry[")
-                .append("bucketDuration=").append(entry.bucketDuration)
-                .append(",bucketStart=").append(entry.bucketStart)
-                .append(",activeTime=").append(entry.activeTime)
-                .append(",rxBytes=").append(entry.rxBytes)
-                .append(",rxPackets=").append(entry.rxPackets)
-                .append(",txBytes=").append(entry.txBytes)
-                .append(",txPackets=").append(entry.txPackets)
-                .append(",operations=").append(entry.operations)
-                .append(']').toString();
-    }
-
-    public void setMobileDataEnabled(boolean enabled) {
-        Log.d(TAG, "setMobileDataEnabled: enabled=" + enabled);
-        mTelephonyManager.setDataEnabled(enabled);
-        if (mCallback != null) {
-            mCallback.onMobileDataEnabled(enabled);
-        }
-    }
-
-    public boolean isMobileDataSupported() {
-        // require both supported network and ready SIM
-        return mConnectivityManager.isNetworkSupported(TYPE_MOBILE)
-                && mTelephonyManager.getSimState() == SIM_STATE_READY;
-    }
-
-    public boolean isMobileDataEnabled() {
-        return mTelephonyManager.getDataEnabled();
-    }
-
-    private static String getActiveSubscriberId(Context context) {
-        final TelephonyManager tele = TelephonyManager.from(context);
-        final String actualSubscriberId = tele.getSubscriberId(
-                SubscriptionManager.getDefaultDataSubId());
-        return actualSubscriberId;
-    }
-
-    private String formatDateRange(long start, long end) {
-        final int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_MONTH;
-        synchronized (PERIOD_BUILDER) {
-            PERIOD_BUILDER.setLength(0);
-            return DateUtils.formatDateRange(mContext, PERIOD_FORMATTER, start, end, flags, null)
-                    .toString();
-        }
-    }
-
-    public interface NetworkNameProvider {
-        String getMobileDataNetworkName();
-    }
-
-    public static class DataUsageInfo {
-        public String carrier;
-        public String period;
-        public long limitLevel;
-        public long warningLevel;
-        public long usageLevel;
-    }
-
-    public interface Callback {
-        void onMobileDataEnabled(boolean enabled);
-    }
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
new file mode 100644
index 0000000..f1beb10
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.users;
+
+import android.app.AppGlobals;
+import android.appwidget.AppWidgetManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodManager;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class AppRestrictionsHelper {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "AppRestrictionsHelper";
+
+    private final Context mContext;
+    private final PackageManager mPackageManager;
+    private final IPackageManager mIPm;
+    private final UserManager mUserManager;
+    private final UserHandle mUser;
+    private final boolean mRestrictedProfile;
+
+    HashMap<String,Boolean> mSelectedPackages = new HashMap<>();
+    private List<SelectableAppInfo> mVisibleApps;
+
+    public AppRestrictionsHelper(Context context, UserHandle user) {
+        mContext = context;
+        mPackageManager = context.getPackageManager();
+        mIPm = AppGlobals.getPackageManager();
+        mUser = user;
+        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        mRestrictedProfile = mUserManager.getUserInfo(mUser.getIdentifier()).isRestricted();
+    }
+
+    public void setPackageSelected(String packageName, boolean selected) {
+        mSelectedPackages.put(packageName, selected);
+    }
+
+    public boolean isPackageSelected(String packageName) {
+        return mSelectedPackages.get(packageName);
+    }
+
+    public List<SelectableAppInfo> getVisibleApps() {
+        return mVisibleApps;
+    }
+
+    public void applyUserAppsStates(OnDisableUiForPackageListener listener) {
+        final int userId = mUser.getIdentifier();
+        if (!mUserManager.getUserInfo(userId).isRestricted() && userId != UserHandle.myUserId()) {
+            Log.e(TAG, "Cannot apply application restrictions on another user!");
+            return;
+        }
+        for (Map.Entry<String,Boolean> entry : mSelectedPackages.entrySet()) {
+            String packageName = entry.getKey();
+            boolean enabled = entry.getValue();
+            applyUserAppState(packageName, enabled, listener);
+        }
+    }
+
+    public void applyUserAppState(String packageName, boolean enabled,
+            OnDisableUiForPackageListener listener) {
+        final int userId = mUser.getIdentifier();
+        if (enabled) {
+            // Enable selected apps
+            try {
+                ApplicationInfo info = mIPm.getApplicationInfo(packageName,
+                        PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
+                if (info == null || !info.enabled
+                        || (info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
+                    mIPm.installExistingPackageAsUser(packageName, mUser.getIdentifier());
+                    if (DEBUG) {
+                        Log.d(TAG, "Installing " + packageName);
+                    }
+                }
+                if (info != null && (info.privateFlags&ApplicationInfo.PRIVATE_FLAG_HIDDEN) != 0
+                        && (info.flags&ApplicationInfo.FLAG_INSTALLED) != 0) {
+                    listener.onDisableUiForPackage(packageName);
+                    mIPm.setApplicationHiddenSettingAsUser(packageName, false, userId);
+                    if (DEBUG) {
+                        Log.d(TAG, "Unhiding " + packageName);
+                    }
+                }
+            } catch (RemoteException re) {
+                // Ignore
+            }
+        } else {
+            // Blacklist all other apps, system or downloaded
+            try {
+                ApplicationInfo info = mIPm.getApplicationInfo(packageName, 0, userId);
+                if (info != null) {
+                    if (mRestrictedProfile) {
+                        mIPm.deletePackageAsUser(packageName, null, mUser.getIdentifier(),
+                                PackageManager.DELETE_SYSTEM_APP);
+                        if (DEBUG) {
+                            Log.d(TAG, "Uninstalling " + packageName);
+                        }
+                    } else {
+                        listener.onDisableUiForPackage(packageName);
+                        mIPm.setApplicationHiddenSettingAsUser(packageName, true, userId);
+                        if (DEBUG) {
+                            Log.d(TAG, "Hiding " + packageName);
+                        }
+                    }
+                }
+            } catch (RemoteException re) {
+                // Ignore
+            }
+        }
+    }
+
+    public void fetchAndMergeApps() {
+        mVisibleApps = new ArrayList<>();
+        final PackageManager pm = mPackageManager;
+        final IPackageManager ipm = mIPm;
+
+        final HashSet<String> excludePackages = new HashSet<>();
+        addSystemImes(excludePackages);
+
+        // Add launchers
+        Intent launcherIntent = new Intent(Intent.ACTION_MAIN);
+        launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+        addSystemApps(mVisibleApps, launcherIntent, excludePackages);
+
+        // Add widgets
+        Intent widgetIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+        addSystemApps(mVisibleApps, widgetIntent, excludePackages);
+
+        List<ApplicationInfo> installedApps = pm.getInstalledApplications(
+                PackageManager.MATCH_UNINSTALLED_PACKAGES);
+        for (ApplicationInfo app : installedApps) {
+            // If it's not installed, skip
+            if ((app.flags & ApplicationInfo.FLAG_INSTALLED) == 0) continue;
+
+            if ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0
+                    && (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0) {
+                // Downloaded app
+                SelectableAppInfo info = new SelectableAppInfo();
+                info.packageName = app.packageName;
+                info.appName = app.loadLabel(pm);
+                info.activityName = info.appName;
+                info.icon = app.loadIcon(pm);
+                mVisibleApps.add(info);
+            } else {
+                try {
+                    PackageInfo pi = pm.getPackageInfo(app.packageName, 0);
+                    // If it's a system app that requires an account and doesn't see restricted
+                    // accounts, mark for removal. It might get shown in the UI if it has an icon
+                    // but will still be marked as false and immutable.
+                    if (mRestrictedProfile
+                            && pi.requiredAccountType != null && pi.restrictedAccountType == null) {
+                        mSelectedPackages.put(app.packageName, false);
+                    }
+                } catch (PackageManager.NameNotFoundException re) {
+                    // Skip
+                }
+            }
+        }
+
+        // Get the list of apps already installed for the user
+        List<ApplicationInfo> userApps = null;
+        try {
+            ParceledListSlice<ApplicationInfo> listSlice = ipm.getInstalledApplications(
+                    PackageManager.MATCH_UNINSTALLED_PACKAGES, mUser.getIdentifier());
+            if (listSlice != null) {
+                userApps = listSlice.getList();
+            }
+        } catch (RemoteException re) {
+            // Ignore
+        }
+
+        if (userApps != null) {
+            for (ApplicationInfo app : userApps) {
+                if ((app.flags & ApplicationInfo.FLAG_INSTALLED) == 0) continue;
+
+                if ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0
+                        && (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0) {
+                    // Downloaded app
+                    SelectableAppInfo info = new SelectableAppInfo();
+                    info.packageName = app.packageName;
+                    info.appName = app.loadLabel(pm);
+                    info.activityName = info.appName;
+                    info.icon = app.loadIcon(pm);
+                    mVisibleApps.add(info);
+                }
+            }
+        }
+
+        // Sort the list of visible apps
+        Collections.sort(mVisibleApps, new AppLabelComparator());
+
+        // Remove dupes
+        Set<String> dedupPackageSet = new HashSet<String>();
+        for (int i = mVisibleApps.size() - 1; i >= 0; i--) {
+            SelectableAppInfo info = mVisibleApps.get(i);
+            if (DEBUG) Log.i(TAG, info.toString());
+            String both = info.packageName + "+" + info.activityName;
+            if (!TextUtils.isEmpty(info.packageName)
+                    && !TextUtils.isEmpty(info.activityName)
+                    && dedupPackageSet.contains(both)) {
+                mVisibleApps.remove(i);
+            } else {
+                dedupPackageSet.add(both);
+            }
+        }
+
+        // Establish master/slave relationship for entries that share a package name
+        HashMap<String,SelectableAppInfo> packageMap = new HashMap<String,SelectableAppInfo>();
+        for (SelectableAppInfo info : mVisibleApps) {
+            if (packageMap.containsKey(info.packageName)) {
+                info.masterEntry = packageMap.get(info.packageName);
+            } else {
+                packageMap.put(info.packageName, info);
+            }
+        }
+    }
+
+    /**
+     * Find all pre-installed input methods that are marked as default
+     * and add them to an exclusion list so that they aren't
+     * presented to the user for toggling.
+     * Don't add non-default ones, as they may include other stuff that we
+     * don't need to auto-include.
+     * @param excludePackages the set of package names to append to
+     */
+    private void addSystemImes(Set<String> excludePackages) {
+        InputMethodManager imm = (InputMethodManager)
+                mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
+        List<InputMethodInfo> imis = imm.getInputMethodList();
+        for (InputMethodInfo imi : imis) {
+            try {
+                if (imi.isDefault(mContext) && isSystemPackage(imi.getPackageName())) {
+                    excludePackages.add(imi.getPackageName());
+                }
+            } catch (Resources.NotFoundException rnfe) {
+                // Not default
+            }
+        }
+    }
+
+    /**
+     * Add system apps that match an intent to the list, excluding any packages in the exclude list.
+     * @param visibleApps list of apps to append the new list to
+     * @param intent the intent to match
+     * @param excludePackages the set of package names to be excluded, since they're required
+     */
+    private void addSystemApps(List<SelectableAppInfo> visibleApps, Intent intent,
+            Set<String> excludePackages) {
+        final PackageManager pm = mPackageManager;
+        List<ResolveInfo> launchableApps = pm.queryIntentActivities(intent,
+                PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.MATCH_UNINSTALLED_PACKAGES);
+        for (ResolveInfo app : launchableApps) {
+            if (app.activityInfo != null && app.activityInfo.applicationInfo != null) {
+                final String packageName = app.activityInfo.packageName;
+                int flags = app.activityInfo.applicationInfo.flags;
+                if ((flags & ApplicationInfo.FLAG_SYSTEM) != 0
+                        || (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
+                    // System app
+                    // Skip excluded packages
+                    if (excludePackages.contains(packageName)) continue;
+                    int enabled = pm.getApplicationEnabledSetting(packageName);
+                    if (enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
+                            || enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
+                        // Check if the app is already enabled for the target user
+                        ApplicationInfo targetUserAppInfo = getAppInfoForUser(packageName,
+                                0, mUser);
+                        if (targetUserAppInfo == null
+                                || (targetUserAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
+                            continue;
+                        }
+                    }
+                    SelectableAppInfo info = new SelectableAppInfo();
+                    info.packageName = app.activityInfo.packageName;
+                    info.appName = app.activityInfo.applicationInfo.loadLabel(pm);
+                    info.icon = app.activityInfo.loadIcon(pm);
+                    info.activityName = app.activityInfo.loadLabel(pm);
+                    if (info.activityName == null) info.activityName = info.appName;
+
+                    visibleApps.add(info);
+                }
+            }
+        }
+    }
+
+    private boolean isSystemPackage(String packageName) {
+        try {
+            final PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
+            if (pi.applicationInfo == null) return false;
+            final int flags = pi.applicationInfo.flags;
+            if ((flags & ApplicationInfo.FLAG_SYSTEM) != 0
+                    || (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
+                return true;
+            }
+        } catch (PackageManager.NameNotFoundException nnfe) {
+            // Missing package?
+        }
+        return false;
+    }
+
+    private ApplicationInfo getAppInfoForUser(String packageName, int flags, UserHandle user) {
+        try {
+            return mIPm.getApplicationInfo(packageName, flags, user.getIdentifier());
+        } catch (RemoteException re) {
+            return null;
+        }
+    }
+
+    public interface OnDisableUiForPackageListener {
+        void onDisableUiForPackage(String packageName);
+    }
+
+    public static class SelectableAppInfo {
+        public String packageName;
+        public CharSequence appName;
+        public CharSequence activityName;
+        public Drawable icon;
+        public SelectableAppInfo masterEntry;
+
+        @Override
+        public String toString() {
+            return packageName + ": appName=" + appName + "; activityName=" + activityName
+                    + "; icon=" + icon + "; masterEntry=" + masterEntry;
+        }
+    }
+
+    private static class AppLabelComparator implements Comparator<SelectableAppInfo> {
+
+        @Override
+        public int compare(SelectableAppInfo lhs, SelectableAppInfo rhs) {
+            String lhsLabel = lhs.activityName.toString();
+            String rhsLabel = rhs.activityName.toString();
+            return lhsLabel.toLowerCase().compareTo(rhsLabel.toLowerCase());
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index cff8c23..5b8ed28 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -37,6 +37,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.support.annotation.NonNull;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.TextUtils;
@@ -104,7 +105,8 @@
     private static final int PSK_WPA2 = 2;
     private static final int PSK_WPA_WPA2 = 3;
 
-    private static final int VISIBILITY_OUTDATED_AGE_IN_MILLI = 20000;
+    public static final int SIGNAL_LEVELS = 4;
+
     private final Context mContext;
 
     private String ssid;
@@ -167,7 +169,7 @@
     }
 
     @Override
-    public int compareTo(AccessPoint other) {
+    public int compareTo(@NonNull AccessPoint other) {
         // Active one goes first.
         if (isActive() && !other.isActive()) return -1;
         if (!isActive() && other.isActive()) return 1;
@@ -182,8 +184,9 @@
         if (networkId == WifiConfiguration.INVALID_NETWORK_ID
                 && other.networkId != WifiConfiguration.INVALID_NETWORK_ID) return 1;
 
-        // Sort by signal strength.
-        int difference = WifiManager.compareSignalLevel(other.mRssi, mRssi);
+        // Sort by signal strength, bucketed by level
+        int difference = WifiManager.calculateSignalLevel(other.mRssi, SIGNAL_LEVELS)
+                - WifiManager.calculateSignalLevel(mRssi, SIGNAL_LEVELS);
         if (difference != 0) {
             return difference;
         }
@@ -234,10 +237,13 @@
     }
 
     public boolean matches(WifiConfiguration config) {
-        if (config.isPasspoint() && mConfig != null && mConfig.isPasspoint())
+        if (config.isPasspoint() && mConfig != null && mConfig.isPasspoint()) {
             return config.FQDN.equals(mConfig.providerFriendlyName);
-        else
-            return ssid.equals(removeDoubleQuotes(config.SSID)) && security == getSecurity(config);
+        } else {
+            return ssid.equals(removeDoubleQuotes(config.SSID))
+                    && security == getSecurity(config)
+                    && (mConfig == null || mConfig.shared == config.shared);
+        }
     }
 
     public WifiConfiguration getConfig() {
@@ -257,7 +263,7 @@
         if (mRssi == Integer.MAX_VALUE) {
             return -1;
         }
-        return WifiManager.calculateSignalLevel(mRssi, 4);
+        return WifiManager.calculateSignalLevel(mRssi, SIGNAL_LEVELS);
     }
 
     public int getRssi() {
@@ -394,33 +400,20 @@
             summary.append(String.format(format, mConfig.providerFriendlyName));
         } else if (mConfig != null && mConfig.hasNoInternetAccess()) {
             summary.append(mContext.getString(R.string.wifi_no_internet));
-        } else if (mConfig != null && ((mConfig.status == WifiConfiguration.Status.DISABLED &&
-                mConfig.disableReason != WifiConfiguration.DISABLED_UNKNOWN_REASON)
-               || mConfig.autoJoinStatus
-                >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE)) {
-            if (mConfig.autoJoinStatus
-                    >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) {
-                if (mConfig.disableReason == WifiConfiguration.DISABLED_DHCP_FAILURE) {
-                    summary.append(mContext.getString(R.string.wifi_disabled_network_failure));
-                } else if (mConfig.disableReason == WifiConfiguration.DISABLED_AUTH_FAILURE) {
+        } else if (mConfig != null && !mConfig.getNetworkSelectionStatus().isNetworkEnabled()) {
+            WifiConfiguration.NetworkSelectionStatus networkStatus =
+                    mConfig.getNetworkSelectionStatus();
+            switch (networkStatus.getNetworkSelectionDisableReason()) {
+                case WifiConfiguration.NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE:
                     summary.append(mContext.getString(R.string.wifi_disabled_password_failure));
-                } else {
-                    summary.append(mContext.getString(R.string.wifi_disabled_wifi_failure));
-                }
-            } else {
-                switch (mConfig.disableReason) {
-                    case WifiConfiguration.DISABLED_AUTH_FAILURE:
-                        summary.append(mContext.getString(R.string.wifi_disabled_password_failure));
-                        break;
-                    case WifiConfiguration.DISABLED_DHCP_FAILURE:
-                    case WifiConfiguration.DISABLED_DNS_FAILURE:
-                        summary.append(mContext.getString(R.string.wifi_disabled_network_failure));
-                        break;
-                    case WifiConfiguration.DISABLED_UNKNOWN_REASON:
-                    case WifiConfiguration.DISABLED_ASSOCIATION_REJECT:
-                        summary.append(mContext.getString(R.string.wifi_disabled_generic));
-                        break;
-                }
+                    break;
+                case WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE:
+                case WifiConfiguration.NetworkSelectionStatus.DISABLED_DNS_FAILURE:
+                    summary.append(mContext.getString(R.string.wifi_disabled_network_failure));
+                    break;
+                case WifiConfiguration.NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION:
+                    summary.append(mContext.getString(R.string.wifi_disabled_generic));
+                    break;
             }
         } else if (mRssi == Integer.MAX_VALUE) { // Wifi out of range
             summary.append(mContext.getString(R.string.wifi_not_in_range));
@@ -437,11 +430,11 @@
                 summary.append(" f=" + Integer.toString(mInfo.getFrequency()));
             }
             summary.append(" " + getVisibilityStatus());
-            if (mConfig != null && mConfig.autoJoinStatus > 0) {
-                summary.append(" (" + mConfig.autoJoinStatus);
-                if (mConfig.blackListTimestamp > 0) {
+            if (mConfig != null && !mConfig.getNetworkSelectionStatus().isNetworkEnabled()) {
+                summary.append(" (" + mConfig.getNetworkSelectionStatus().getNetworkStatusString());
+                if (mConfig.getNetworkSelectionStatus().getDisableTime() > 0) {
                     long now = System.currentTimeMillis();
-                    long diff = (now - mConfig.blackListTimestamp)/1000;
+                    long diff = (now - mConfig.getNetworkSelectionStatus().getDisableTime()) / 1000;
                     long sec = diff%60; //seconds
                     long min = (diff/60)%60; //minutes
                     long hour = (min/60)%60; //hours
@@ -452,17 +445,19 @@
                 }
                 summary.append(")");
             }
-            if (mConfig != null && mConfig.numIpConfigFailures > 0) {
-                summary.append(" ipf=").append(mConfig.numIpConfigFailures);
-            }
-            if (mConfig != null && mConfig.numConnectionFailures > 0) {
-                summary.append(" cf=").append(mConfig.numConnectionFailures);
-            }
-            if (mConfig != null && mConfig.numAuthFailures > 0) {
-                summary.append(" authf=").append(mConfig.numAuthFailures);
-            }
-            if (mConfig != null && mConfig.numNoInternetAccessReports > 0) {
-                summary.append(" noInt=").append(mConfig.numNoInternetAccessReports);
+
+            if (mConfig != null) {
+                WifiConfiguration.NetworkSelectionStatus networkStatus =
+                        mConfig.getNetworkSelectionStatus();
+                for (int index = WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE;
+                        index < WifiConfiguration.NetworkSelectionStatus
+                        .NETWORK_SELECTION_DISABLED_MAX; index++) {
+                    if (networkStatus.getDisableReasonCounter(index) != 0) {
+                        summary.append(" " + WifiConfiguration.NetworkSelectionStatus
+                                .getNetworkDisableReasonString(index) + "="
+                                + networkStatus.getDisableReasonCounter(index));
+                    }
+                }
             }
         }
         return summary.toString();
@@ -508,10 +503,6 @@
         Map<String, ScanResult> list = mScanResultCache.snapshot();
         // TODO: sort list by RSSI or age
         for (ScanResult result : list.values()) {
-            if (result.seen == 0)
-                continue;
-
-            if (result.autoJoinStatus != ScanResult.ENABLED) numBlackListed++;
 
             if (result.frequency >= LOWER_FREQ_5GHZ
                     && result.frequency <= HIGHER_FREQ_5GHZ) {
@@ -525,8 +516,6 @@
                 num24 = num24 + 1;
             }
 
-            // Ignore results seen, older than 20 seconds
-            if (now - result.seen > VISIBILITY_OUTDATED_AGE_IN_MILLI) continue;
 
             if (result.frequency >= LOWER_FREQ_5GHZ
                     && result.frequency <= HIGHER_FREQ_5GHZ) {
@@ -539,12 +528,6 @@
                     if (bssid != null && result.BSSID.equals(bssid)) scans5GHz.append("*");
                     scans5GHz.append("=").append(result.frequency);
                     scans5GHz.append(",").append(result.level);
-                    if (result.autoJoinStatus != 0) {
-                        scans5GHz.append(",st=").append(result.autoJoinStatus);
-                    }
-                    if (result.numIpConfigFailures != 0) {
-                        scans5GHz.append(",ipf=").append(result.numIpConfigFailures);
-                    }
                     scans5GHz.append("}");
                     n5++;
                 }
@@ -559,12 +542,6 @@
                     if (bssid != null && result.BSSID.equals(bssid)) scans24GHz.append("*");
                     scans24GHz.append("=").append(result.frequency);
                     scans24GHz.append(",").append(result.level);
-                    if (result.autoJoinStatus != 0) {
-                        scans24GHz.append(",st=").append(result.autoJoinStatus);
-                    }
-                    if (result.numIpConfigFailures != 0) {
-                        scans24GHz.append(",ipf=").append(result.numIpConfigFailures);
-                    }
                     scans24GHz.append("}");
                     n24++;
                 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
new file mode 100644
index 0000000..284827b
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settingslib.wifi;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.StateListDrawable;
+import android.net.wifi.WifiConfiguration;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceViewHolder;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.widget.TextView;
+
+import com.android.settingslib.R;
+
+public class AccessPointPreference extends Preference {
+
+    private static final int[] STATE_SECURED = {
+            R.attr.state_encrypted
+    };
+    private static final int[] STATE_NONE = {};
+
+    private static int[] wifi_signal_attributes = { R.attr.wifi_signal };
+
+    private final StateListDrawable mWifiSld;
+    private final int mBadgePadding;
+    private final UserBadgeCache mBadgeCache;
+
+    private TextView mTitleView;
+    private boolean mForSavedNetworks = false;
+    private AccessPoint mAccessPoint;
+    private Drawable mBadge;
+    private int mLevel;
+    private CharSequence mContentDescription;
+
+    static final int[] WIFI_CONNECTION_STRENGTH = {
+            R.string.accessibility_wifi_one_bar,
+            R.string.accessibility_wifi_two_bars,
+            R.string.accessibility_wifi_three_bars,
+            R.string.accessibility_wifi_signal_full
+    };
+
+    // Used for dummy pref.
+    public AccessPointPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mWifiSld = null;
+        mBadgePadding = 0;
+        mBadgeCache = null;
+    }
+
+    public AccessPointPreference(AccessPoint accessPoint, Context context, UserBadgeCache cache,
+            boolean forSavedNetworks) {
+        super(context);
+        mBadgeCache = cache;
+        mAccessPoint = accessPoint;
+        mForSavedNetworks = forSavedNetworks;
+        mAccessPoint.setTag(this);
+        mLevel = -1;
+
+        mWifiSld = (StateListDrawable) context.getTheme()
+                .obtainStyledAttributes(wifi_signal_attributes).getDrawable(0);
+
+        // Distance from the end of the title at which this AP's user badge should sit.
+        mBadgePadding = context.getResources()
+                .getDimensionPixelSize(R.dimen.wifi_preference_badge_padding);
+        refresh();
+    }
+
+    public AccessPoint getAccessPoint() {
+        return mAccessPoint;
+    }
+
+    @Override
+    public void onBindViewHolder(final PreferenceViewHolder view) {
+        super.onBindViewHolder(view);
+        if (mAccessPoint == null) {
+            // Used for dummy pref.
+            return;
+        }
+        Drawable drawable = getIcon();
+        if (drawable != null) {
+            drawable.setLevel(mLevel);
+        }
+
+        mTitleView = (TextView) view.findViewById(com.android.internal.R.id.title);
+        if (mTitleView != null) {
+            // Attach to the end of the title view
+            mTitleView.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, mBadge, null);
+            mTitleView.setCompoundDrawablePadding(mBadgePadding);
+        }
+        view.itemView.setContentDescription(mContentDescription);
+    }
+
+    protected void updateIcon(int level, Context context) {
+        if (level == -1) {
+            setIcon(null);
+        } else {
+            if (getIcon() == null) {
+                // To avoid a drawing race condition, we first set the state (SECURE/NONE) and then
+                // set the icon (drawable) to that state's drawable.
+                // If sld is null then we are indexing and therefore do not have access to
+                // (nor need to display) the drawable.
+                if (mWifiSld != null) {
+                    mWifiSld.setState((mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE)
+                            ? STATE_SECURED
+                            : STATE_NONE);
+                    Drawable drawable = mWifiSld.getCurrent();
+                    if (!mForSavedNetworks) {
+                        setIcon(drawable);
+                    } else {
+                        setIcon(null);
+                    }
+                }
+            }
+        }
+    }
+
+    protected void updateBadge(Context context) {
+        WifiConfiguration config = mAccessPoint.getConfig();
+        if (config != null) {
+            // Fetch badge (may be null)
+            // Get the badge using a cache since the PM will ask the UserManager for the list
+            // of profiles every time otherwise.
+            mBadge = mBadgeCache.getUserBadge(config.creatorUid);
+        }
+    }
+
+    /**
+     * Updates the title and summary; may indirectly call notifyChanged().
+     */
+    public void refresh() {
+        if (mForSavedNetworks) {
+            setTitle(mAccessPoint.getConfigName());
+        } else {
+            setTitle(mAccessPoint.getSsid());
+        }
+
+        final Context context = getContext();
+        int level = mAccessPoint.getLevel();
+        if (level != mLevel) {
+            mLevel = level;
+            updateIcon(mLevel, context);
+            notifyChanged();
+        }
+        updateBadge(context);
+
+        setSummary(mForSavedNetworks ? mAccessPoint.getSavedNetworkSummary()
+                : mAccessPoint.getSettingsSummary());
+
+        mContentDescription = getTitle();
+        if (getSummary() != null) {
+            mContentDescription = TextUtils.concat(mContentDescription, ",", getSummary());
+        }
+        if (level >= 0 && level < WIFI_CONNECTION_STRENGTH.length) {
+            mContentDescription = TextUtils.concat(mContentDescription, ",",
+                    getContext().getString(WIFI_CONNECTION_STRENGTH[level]));
+        }
+    }
+
+    @Override
+    protected void notifyChanged() {
+        if (Looper.getMainLooper() != Looper.myLooper()) {
+            // Let our BG thread callbacks call setTitle/setSummary.
+            postNotifyChanged();
+        } else {
+            super.notifyChanged();
+        }
+    }
+
+    public void onLevelChanged() {
+        postNotifyChanged();
+    }
+
+    private void postNotifyChanged() {
+        if (mTitleView != null) {
+            mTitleView.post(mNotifyChanged);
+        } // Otherwise we haven't been bound yet, and don't need to update.
+    }
+
+    private final Runnable mNotifyChanged = new Runnable() {
+        @Override
+        public void run() {
+            notifyChanged();
+        }
+    };
+
+    public static class UserBadgeCache {
+        private final SparseArray<Drawable> mBadges = new SparseArray<>();
+        private final PackageManager mPm;
+
+        public UserBadgeCache(PackageManager pm) {
+            mPm = pm;
+        }
+
+        private Drawable getUserBadge(int userId) {
+            int index = mBadges.indexOfKey(userId);
+            if (index < 0) {
+                Drawable badge = mPm.getUserBadgeForDensity(new UserHandle(userId), 0 /* dpi */);
+                mBadges.put(userId, badge);
+                return badge;
+            }
+            return mBadges.valueAt(index);
+        }
+    }
+}
diff --git a/packages/SettingsProvider/res/values-bs-rBA/defaults.xml b/packages/SettingsProvider/res/values-bs-rBA/defaults.xml
new file mode 100644
index 0000000..5650077
--- /dev/null
+++ b/packages/SettingsProvider/res/values-bs-rBA/defaults.xml
@@ -0,0 +1,27 @@
+<?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">
+    <!-- no translation found for def_device_name (6309317409634339402) -->
+    <skip />
+    <!-- no translation found for def_device_name_simple (9037785625140748221) -->
+    <skip />
+    <string name="def_nfc_payment_component" msgid="5861297439873026958"></string>
+</resources>
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 6680d88..51d8ca0 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -25,6 +25,7 @@
     <!-- Comma-separated list of bluetooth, wifi, and cell. -->
     <string name="def_airplane_mode_radios" translatable="false">cell,bluetooth,wifi,nfc,wimax</string>
     <string name="airplane_mode_toggleable_radios" translatable="false">bluetooth,wifi,nfc</string>
+    <string name="def_bluetooth_disabled_profiles" translatable="false">0</string>
     <bool name="def_auto_time">true</bool>
     <bool name="def_auto_time_zone">true</bool>
     <bool name="def_accelerometer_rotation">true</bool>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index d4e428e..7338a9c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -116,6 +116,12 @@
             // cleaned up automatically when the user is deleted.
             File databaseFile = new File(
                     Environment.getUserSystemDirectory(userHandle), DATABASE_NAME);
+            // If databaseFile doesn't exist, database can be kept in memory. It's safe because the
+            // database will be migrated and disposed of immediately after onCreate finishes
+            if (!databaseFile.exists()) {
+                Log.i(TAG, "No previous database file exists - running in in-memory mode");
+                return null;
+            }
             return databaseFile.getPath();
         }
     }
@@ -130,8 +136,16 @@
         return mValidTables.contains(name);
     }
 
+    private boolean isInMemory() {
+        return getDatabaseName() == null;
+    }
+
     public void dropDatabase() {
         close();
+        // No need to remove files if db is in memory
+        if (isInMemory()) {
+            return;
+        }
         File databaseFile = mContext.getDatabasePath(getDatabaseName());
         if (databaseFile.exists()) {
             databaseFile.delete();
@@ -145,6 +159,10 @@
 
     public void backupDatabase() {
         close();
+        // No need to backup files if db is in memory
+        if (isInMemory()) {
+            return;
+        }
         File databaseFile = mContext.getDatabasePath(getDatabaseName());
         if (!databaseFile.exists()) {
             return;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index e12e3a5..d89abf42 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -229,22 +229,33 @@
     }
 
     private boolean isAlreadyConfiguredCriticalAccessibilitySetting(String name) {
-        // These are the critical accessibility settings that are required for a
-        // blind user to be able to interact with the device. If these settings are
+        // These are the critical accessibility settings that are required for users with
+        // accessibility needs to be able to interact with the device. If these settings are
         // already configured, we will not overwrite them. If they are already set,
-        // it means that the user has performed a global gesture to enable accessibility
-        // and definitely needs these features working after the restore.
-        if (Settings.Secure.ACCESSIBILITY_ENABLED.equals(name)
-                || Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION.equals(name)
-                || Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD.equals(name)
-                || Settings.Secure.TOUCH_EXPLORATION_ENABLED.equals(name)) {
-            return Settings.Secure.getInt(mContext.getContentResolver(), name, 0) != 0;
-        } else if (Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES.equals(name)
-                || Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES.equals(name)) {
-            return !TextUtils.isEmpty(Settings.Secure.getString(
-                    mContext.getContentResolver(), name));
+        // it means that the user has performed a global gesture to enable accessibility or set
+        // these settings in the Accessibility portion of the Setup Wizard, and definitely needs
+        // these features working after the restore.
+        switch (name) {
+            case Settings.Secure.ACCESSIBILITY_ENABLED:
+            case Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION:
+            case Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD:
+            case Settings.Secure.TOUCH_EXPLORATION_ENABLED:
+            case Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED:
+            case Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED:
+            case Settings.Secure.UI_NIGHT_MODE:
+                return Settings.Secure.getInt(mContext.getContentResolver(), name, 0) != 0;
+            case Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES:
+            case Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES:
+            case Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX:
+            case Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER:
+            case Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE:
+                return !TextUtils.isEmpty(Settings.Secure.getString(
+                        mContext.getContentResolver(), name));
+            case Settings.System.FONT_SCALE:
+                return Settings.System.getFloat(mContext.getContentResolver(), name, 1.0f) != 1.0f;
+            default:
+                return false;
         }
-        return false;
     }
 
     private void setAutoRestore(boolean enabled) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 7365e66..57d495f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1010,6 +1010,11 @@
                 break;
 
             default:
+                if (setting != null && setting.startsWith(Settings.Global.DATA_ROAMING)) {
+                    if ("0".equals(value)) return false;
+                    restriction = UserManager.DISALLOW_DATA_ROAMING;
+                    break;
+                }
                 return false;
         }
 
@@ -1890,7 +1895,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 123;
+            private static final int SETTINGS_VERSION = 124;
 
             private final int mUserId;
 
@@ -2060,6 +2065,16 @@
                     }
                     currentVersion = 123;
                 }
+
+                if (currentVersion == 123) {
+                    final SettingsState globalSettings = getGlobalSettingsLocked();
+                    String defaultDisabledProfiles = (getContext().getResources().getString(
+                            R.string.def_bluetooth_disabled_profiles));
+                    globalSettings.insertSettingLocked(Settings.Global.BLUETOOTH_DISABLED_PROFILES,
+                            defaultDisabledProfiles, SettingsState.SYSTEM_PACKAGE_NAME);
+                    currentVersion = 124;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 // Return the current version.
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/WiFiConfigurationSerializer.java b/packages/SettingsProvider/src/com/android/providers/settings/WiFiConfigurationSerializer.java
index f9f1d3f..2317dbc 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/WiFiConfigurationSerializer.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/WiFiConfigurationSerializer.java
@@ -48,6 +48,23 @@
      */
     private static int STATE_VERSION = 1;
 
+    /**
+     * write the Network selecton status to Byte Array
+     */
+    private static void writeNetworkSelectionStatus(WifiConfiguration config, DataOutputStream dest)
+            throws IOException {
+        WifiConfiguration.NetworkSelectionStatus status = config.getNetworkSelectionStatus();
+
+        dest.writeInt(status.getNetworkSelectionStatus());
+        dest.writeInt(status.getNetworkSelectionDisableReason());
+        for (int index = WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE;
+                index < WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX;
+                index++) {
+            dest.writeInt(status.getDisableReasonCounter(index));
+        }
+        dest.writeLong(status.getDisableTime());
+        writeString(dest, status.getNetworkSelectionBSSID());
+    }
 
     /**
      * Marshals a WifiConfig object into a byte-array.
@@ -64,12 +81,11 @@
                 out.writeInt(STATE_VERSION);
                 out.writeInt(wifiConfig.networkId);
                 out.writeInt(wifiConfig.status);
-                out.writeInt(wifiConfig.disableReason);
+                writeNetworkSelectionStatus(wifiConfig, out);
                 writeString(out, wifiConfig.SSID);
                 writeString(out, wifiConfig.BSSID);
                 out.writeInt(wifiConfig.apBand);
                 out.writeInt(wifiConfig.apChannel);
-                writeString(out, wifiConfig.autoJoinBSSID);
                 writeString(out, wifiConfig.FQDN);
                 writeString(out, wifiConfig.providerFriendlyName);
                 out.writeInt(wifiConfig.roamingConsortiumIds.length);
@@ -98,7 +114,6 @@
 
                 writeString(out, wifiConfig.dhcpServer);
                 writeString(out, wifiConfig.defaultGwMacAddress);
-                out.writeInt(wifiConfig.autoJoinStatus);
                 out.writeInt(wifiConfig.selfAdded ? 1 : 0);
                 out.writeInt(wifiConfig.didSelfAdd ? 1 : 0);
                 out.writeInt(wifiConfig.validatedInternetAccess ? 1 : 0);
@@ -108,14 +123,9 @@
                 out.writeInt(wifiConfig.lastUpdateUid);
                 writeString(out, wifiConfig.creatorName);
                 writeString(out, wifiConfig.lastUpdateName);
-                out.writeLong(wifiConfig.blackListTimestamp);
                 out.writeLong(wifiConfig.lastConnectionFailure);
                 out.writeLong(wifiConfig.lastRoamingFailure);
                 out.writeInt(wifiConfig.lastRoamingFailureReason);
-                out.writeLong(wifiConfig.roamingFailureBlackListTimeMilli);
-                out.writeLong(wifiConfig.numConnectionFailures);
-                out.writeLong(wifiConfig.numIpConfigFailures);
-                out.writeInt(wifiConfig.numAuthFailures);
                 out.writeInt(wifiConfig.numScorerOverride);
                 out.writeInt(wifiConfig.numScorerOverrideAndSwitchedNetwork);
                 out.writeInt(wifiConfig.numAssociation);
@@ -126,8 +136,6 @@
                 out.writeInt(wifiConfig.numTicksAtBadRSSI);
                 out.writeInt(wifiConfig.numTicksAtNotHighRSSI);
                 out.writeInt(wifiConfig.numUserTriggeredJoinAttempts);
-                out.writeInt(wifiConfig.autoJoinUseAggressiveJoinAttemptThreshold);
-                out.writeInt(wifiConfig.autoJoinBailedDueToLowRssi ? 1 : 0);
                 out.writeInt(wifiConfig.userApproved);
                 out.writeInt(wifiConfig.numNoInternetAccessReports);
                 out.writeInt(wifiConfig.noInternetAccessExpected ? 1 : 0);
@@ -140,6 +148,23 @@
     }
 
     /**
+     *
+     */
+    private static void readNetworkSelectionStatusFromByteArray(DataInputStream in,
+            WifiConfiguration config, int version) throws IOException {
+        WifiConfiguration.NetworkSelectionStatus status = config.getNetworkSelectionStatus();
+        status.setNetworkSelectionStatus(in.readInt());
+        status.setNetworkSelectionDisableReason(in.readInt());
+        for (int index = WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE;
+                index < WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX;
+                index++) {
+            status.setDisableReasonCounter(index, in.readInt());
+        }
+        status.setDisableTime(in.readLong());
+        status.setNetworkSelectionBSSID(readString(in, version));
+    }
+
+    /**
      * Unmarshals a byte array into a WifiConfig Object
      *
      * @param data - marshalled WifiConfig Object
@@ -157,12 +182,11 @@
 
             config.networkId = in.readInt();
             config.status = in.readInt();
-            config.disableReason = in.readInt();
+            readNetworkSelectionStatusFromByteArray(in, config, version);
             config.SSID = readString(in, version);
             config.BSSID = readString(in, version);
             config.apBand = in.readInt();
             config.apChannel = in.readInt();
-            config.autoJoinBSSID = readString(in, version);
             config.FQDN = readString(in, version);
             config.providerFriendlyName = readString(in, version);
             int numRoamingConsortiumIds = in.readInt();
@@ -195,7 +219,6 @@
 
             config.dhcpServer = readString(in, version);
             config.defaultGwMacAddress = readString(in, version);
-            config.autoJoinStatus = in.readInt();
             config.selfAdded = in.readInt() != 0;
             config.didSelfAdd = in.readInt() != 0;
             config.validatedInternetAccess = in.readInt() != 0;
@@ -205,14 +228,10 @@
             config.lastUpdateUid = in.readInt();
             config.creatorName = readString(in, version);
             config.lastUpdateName = readString(in, version);
-            config.blackListTimestamp = in.readLong();
             config.lastConnectionFailure = in.readLong();
             config.lastRoamingFailure = in.readLong();
             config.lastRoamingFailureReason = in.readInt();
             config.roamingFailureBlackListTimeMilli = in.readLong();
-            config.numConnectionFailures = in.readInt();
-            config.numIpConfigFailures = in.readInt();
-            config.numAuthFailures = in.readInt();
             config.numScorerOverride = in.readInt();
             config.numScorerOverrideAndSwitchedNetwork = in.readInt();
             config.numAssociation = in.readInt();
@@ -223,8 +242,6 @@
             config.numTicksAtBadRSSI = in.readInt();
             config.numTicksAtNotHighRSSI = in.readInt();
             config.numUserTriggeredJoinAttempts = in.readInt();
-            config.autoJoinUseAggressiveJoinAttemptThreshold = in.readInt();
-            config.autoJoinBailedDueToLowRssi = in.readInt() != 0;
             config.userApproved = in.readInt();
             config.numNoInternetAccessReports = in.readInt();
             config.noInternetAccessExpected = in.readInt() != 0;
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 25346ac..7416fb5 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -107,6 +107,8 @@
     <uses-permission android:name="android.permission.REGISTER_CONNECTION_MANAGER" />
     <uses-permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION" />
     <uses-permission android:name="android.permission.GET_APP_OPS_STATS" />
+    <uses-permission android:name="android.permission.VIBRATE" />
+    <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
 
     <application android:label="@string/app_label"
                  android:forceDeviceEncrypted="true"
@@ -149,6 +151,14 @@
             </intent-filter>
         </receiver>
 
+        <receiver
+            android:name=".RemoteBugreportReceiver"
+            android:permission="android.permission.DUMP">
+            <intent-filter>
+                <action android:name="android.intent.action.REMOTE_BUGREPORT_FINISHED" />
+            </intent-filter>
+        </receiver>
+
         <service
             android:name=".BugreportProgressService"
             android:exported="false"/>
diff --git a/packages/Shell/res/layout/dialog_bugreport_info.xml b/packages/Shell/res/layout/dialog_bugreport_info.xml
new file mode 100644
index 0000000..5d1e9f9
--- /dev/null
+++ b/packages/Shell/res/layout/dialog_bugreport_info.xml
@@ -0,0 +1,43 @@
+<?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:orientation="vertical"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+    <EditText
+        android:id="@+id/name"
+        android:maxLength="30"
+        android:singleLine="true"
+        android:inputType="textNoSuggestions"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:hint="@string/bugreport_info_name"/>
+    <EditText
+        android:id="@+id/title"
+        android:maxLength="80"
+        android:singleLine="true"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:hint="@string/bugreport_info_title"/>
+    <EditText
+        android:id="@+id/description"
+        android:singleLine="false"
+        android:inputType="textMultiLine"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:hint="@string/bugreport_info_description"/>
+</LinearLayout>
diff --git a/packages/Shell/res/values-af/strings.xml b/packages/Shell/res/values-af/strings.xml
index 8c4de4e..b9a7c24 100644
--- a/packages/Shell/res/values-af/strings.xml
+++ b/packages/Shell/res/values-af/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Tuisskerm"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Foutverslag word tans gegenereer"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Foutverslag vasgevang"</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="3559904746859400732">"Raak om jou foutverslag te deel"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Foutverslae"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Foutverslaglêer kon nie gelees word nie"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"naamloos"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Besonderhede"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skermkiekie"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Skermkiekie suksesvol geneem."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Kon nie skermkiekie neem nie."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Foutverslagbesonderhede"</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>
 </resources>
diff --git a/packages/Shell/res/values-am/strings.xml b/packages/Shell/res/values-am/strings.xml
index 415f3ec..7c5519e 100644
--- a/packages/Shell/res/values-am/strings.xml
+++ b/packages/Shell/res/values-am/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"ቀፎ"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"የሳንካ ሪፓርት እየመነጨ ነው"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"የሳንካ ሪፖርት ተይዟል"</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="3559904746859400732">"የሳንካ ሪፖርትዎን ለማጋራት ይንክኩ"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"የሳንካ ሪፖርቶች የግል መረጃን ጨምሮ ከበርካታ የስርዓቱ ምዝግብ ማስታወሻዎች የመጣ ውሂብን ይዟል። የሳንካ ሪፖርቶች ለሚያምኗቸው መተግበሪያዎችን እና ሰዎችን ብቻ ያጋሩ።"</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"ቅጽበታዊ ገጽ እይታ በስኬት ተነስቷል።"</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ቅጽበታዊ ገጽ እይታ ሊነሳ አይችልም"</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"የሳንካ ሪፖርት ዝርዝሮች"</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>
 </resources>
diff --git a/packages/Shell/res/values-ar/strings.xml b/packages/Shell/res/values-ar/strings.xml
index 79d615e..b1079319 100644
--- a/packages/Shell/res/values-ar/strings.xml
+++ b/packages/Shell/res/values-ar/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"جارٍ إنشاء تقرير الخطأ"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"تم الحصول على تقرير الأخطاء"</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="3559904746859400732">"المس لمشاركة تقرير الأخطاء"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"تحتوي تقارير الأخطاء على بيانات من ملفات سجلات النظام المتنوعة، بما في ذلك معلومات شخصية وخاصة. لا تشارك تقارير الأخطاء إلا مع التطبيقات والأشخاص الموثوق بهم."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"تم التقاط لقطة الشاشة بنجاح."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"تعذر التقاط لقطة الشاشة."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"تفاصيل تقرير الخطأ"</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>
 </resources>
diff --git a/packages/Shell/res/values-az-rAZ/strings.xml b/packages/Shell/res/values-az-rAZ/strings.xml
index 176b009..d01ae2a 100644
--- a/packages/Shell/res/values-az-rAZ/strings.xml
+++ b/packages/Shell/res/values-az-rAZ/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Bug hesabat yaradıldı"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Baq raport alındı"</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="3559904746859400732">"Xətanı şikayətini paylaşmaq üçün toxunun"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Baq hesabatları"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Baq hesabat faylı oxunmur"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"adsız"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Detallar"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"displey görüntüsü"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Displey görüntüsü uğurla çəkildi."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Displey görüntüsü əlçatan deyil."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Baq hesabat 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>
 </resources>
diff --git a/packages/Shell/res/values-b+sr+Latn/strings.xml b/packages/Shell/res/values-b+sr+Latn/strings.xml
index db1ebff..f39dbcb 100644
--- a/packages/Shell/res/values-b+sr+Latn/strings.xml
+++ b/packages/Shell/res/values-b+sr+Latn/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Izveštaj o grešci se generiše"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Izveštaj o grešci je snimljen"</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="3559904746859400732">"Dodirnite da biste delili izveštaj o grešci"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Izveštaji o greškama"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Datoteka izveštaja o grešci ne može da se pročita"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"neimenovano"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Detalji"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Snimci ekrana"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Snimanje ekrana je uspelo."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snimanje ekrana nije uspelo."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalji izveštaja o grešci"</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>
 </resources>
diff --git a/packages/Shell/res/values-bg/strings.xml b/packages/Shell/res/values-bg/strings.xml
index a470998..068bcd3 100644
--- a/packages/Shell/res/values-bg/strings.xml
+++ b/packages/Shell/res/values-bg/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Команден ред"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Сигналът за програмна грешка се генерира"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Отчетът за програмни грешки е записан"</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="3559904746859400732">"Докоснете, за да споделите отчета си за програмни грешки"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Отчетите за програмни грешки съдържат данни от различни регистрационни файлове на системата, включително лична и поверителна информация. Споделяйте ги само с приложения и хора, на които имате доверие."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"Екранната снимка бе направена успешно."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Екранната снимка не можа да бъде направена."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Подробности за сигнала за програмна грешка"</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>
 </resources>
diff --git a/packages/Shell/res/values-bn-rBD/strings.xml b/packages/Shell/res/values-bn-rBD/strings.xml
index afa3a46..e484b47 100644
--- a/packages/Shell/res/values-bn-rBD/strings.xml
+++ b/packages/Shell/res/values-bn-rBD/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"শেল"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"ত্রুটির প্রতিবেদন তৈরি করা হচ্ছে"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"ত্রুটির প্রতিবেদন নেওয়া হয়েছে"</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="3559904746859400732">"আপনার ত্রুটির প্রতিবেদন ভাগ করতে স্পর্শ করুন"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"ত্রুটির প্রতিবেদনগুলিতে থাকা ডেটা, সিস্টেমের বিভিন্ন লগ ফাইলগুলি থেকে আসে, যাতে ব্যক্তিগত এবং গোপনীয় তথ্য অন্তর্ভুক্ত থাকে৷ আপনি বিশ্বাস করেন শুধুমাত্র এমন অ্যাপ্লিকেশান এবং ব্যক্তিদের সাথে ত্রুটির প্রতিবেদনগুলি ভাগ করুন৷"</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"স্ক্রীনশট সফলভাবে নেওয়া হয়েছে৷"</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"স্ক্রীনশট নেওয়া যায়নি৷"</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ত্রুটি প্রতিবেদনের বিবরণ"</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>
 </resources>
diff --git a/packages/Shell/res/values-bs-rBA/strings.xml b/packages/Shell/res/values-bs-rBA/strings.xml
new file mode 100644
index 0000000..55a9341
--- /dev/null
+++ b/packages/Shell/res/values-bs-rBA/strings.xml
@@ -0,0 +1,57 @@
+<?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">
+    <!-- no translation found for app_label (3701846017049540910) -->
+    <skip />
+    <!-- no translation found for bugreport_in_progress_title (7409917338223386637) -->
+    <skip />
+    <!-- no translation found for bugreport_finished_title (2293711546892863898) -->
+    <skip />
+    <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>
+    <!-- no translation found for bugreport_finished_text (8389172248433597683) -->
+    <skip />
+    <!-- no translation found for bugreport_finished_text (3559904746859400732) -->
+    <skip />
+    <!-- no translation found for bugreport_confirm (5130698467795669780) -->
+    <skip />
+    <!-- no translation found for bugreport_confirm_repeat (4926842460688645058) -->
+    <skip />
+    <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+    <skip />
+    <!-- no translation found for bugreport_unreadable_text (586517851044535486) -->
+    <skip />
+    <!-- no translation found for bugreport_unnamed (2800582406842092709) -->
+    <skip />
+    <!-- no translation found for bugreport_info_action (2158204228510576227) -->
+    <skip />
+    <!-- no translation found for bugreport_screenshot_action (8677781721940614995) -->
+    <skip />
+    <!-- no translation found for bugreport_screenshot_taken (7175343181767429088) -->
+    <skip />
+    <!-- no translation found for bugreport_screenshot_failed (5853049140806834601) -->
+    <skip />
+    <!-- no translation found for bugreport_info_dialog_title (3113549839798564645) -->
+    <skip />
+    <!-- no translation found for bugreport_info_name (4414036021935139527) -->
+    <skip />
+    <!-- no translation found for bugreport_info_title (5599558206004371052) -->
+    <skip />
+    <!-- no translation found for bugreport_info_description (4117088998733546784) -->
+    <skip />
+</resources>
diff --git a/packages/Shell/res/values-ca/strings.xml b/packages/Shell/res/values-ca/strings.xml
index 188da67..14c21da 100644
--- a/packages/Shell/res/values-ca/strings.xml
+++ b/packages/Shell/res/values-ca/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Protecció"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"S\'està generant l\'informe d\'errors"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"S\'ha registrat l\'informe d\'error"</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="3559904746859400732">"Toca aquí per compartir el teu informe d\'error."</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Informes d\'error"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"No s\'ha pogut llegir el fitxer de l\'informe d\'errors"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"sense nom"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Detalls"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captura de pantalla"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"La captura de pantalla s\'ha fet correctament."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"No s\'ha pogut fer la captura de pantalla."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalls de l\'informe d\'errors"</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>
 </resources>
diff --git a/packages/Shell/res/values-cs/strings.xml b/packages/Shell/res/values-cs/strings.xml
index fdc8023..19a4453 100644
--- a/packages/Shell/res/values-cs/strings.xml
+++ b/packages/Shell/res/values-cs/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Vytváří se zpráva o chybě"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Bylo vytvořeno chybové hlášení"</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="3559904746859400732">"Chybové hlášení můžete sdílet klepnutím."</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Zprávy o chybách"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Soubor chybové zprávy nelze načíst"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"bez názvu"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Podrobnosti"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Snímek obrazovky"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Snímek obrazovky byl úspěšně pořízen."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snímek obrazovky se nepodařilo pořídit."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Podrobnosti zprávy o chybě"</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>
 </resources>
diff --git a/packages/Shell/res/values-da/strings.xml b/packages/Shell/res/values-da/strings.xml
index 0502655..a03276a 100644
--- a/packages/Shell/res/values-da/strings.xml
+++ b/packages/Shell/res/values-da/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Fejlrapport genereres"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Fejlrapporten er registreret"</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="3559904746859400732">"Tryk for at dele din fejlrapport"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Fejlrapporter"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Fejlrapportfilen kunne ikke læses"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"ikke navngivet"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Oplysninger"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skærmbillede"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Der blev taget et skærmbillede."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Der kunne ikke tages et skærmbillede."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Fejlrapportoplysninger"</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>
 </resources>
diff --git a/packages/Shell/res/values-de/strings.xml b/packages/Shell/res/values-de/strings.xml
index 13c1c96..4f5e6c5 100644
--- a/packages/Shell/res/values-de/strings.xml
+++ b/packages/Shell/res/values-de/strings.xml
@@ -19,11 +19,21 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Fehlerbericht wird generiert"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Fehlerbericht erfasst"</string>
-    <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Wischen Sie nach links, um Ihren Fehlerbericht zu teilen."</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="3559904746859400732">"Tippen, um Fehlerbericht zu teilen"</string>
-    <string name="bugreport_confirm" msgid="5130698467795669780">"Fehlerberichte enthalten Daten aus verschiedenen Protokolldateien des Systems, darunter auch personenbezogene und private Daten. Teilen Sie Fehlerberichte nur mit Apps und Personen, denen Sie vertrauen."</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>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Fehlerberichtdatei konnte nicht gelesen werden."</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"Unbenannt"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Details"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot wurde aufgenommen."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot konnte nicht aufgenommen werden."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Details des Fehlerberichts"</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>
 </resources>
diff --git a/packages/Shell/res/values-el/strings.xml b/packages/Shell/res/values-el/strings.xml
index aa03bec..71debd7 100644
--- a/packages/Shell/res/values-el/strings.xml
+++ b/packages/Shell/res/values-el/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Κέλυφος"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Δημιουργείται αναφορά σφάλματος"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Η λήψη της αναφοράς ήταν επιτυχής"</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="3559904746859400732">"Αγγίξτε για να μοιραστείτε τη αναφορά σφαλμάτων"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Οι αναφορές σφαλμάτων περιέχουν δεδομένα από τα διάφορα αρχεία καταγραφής του συστήματος, συμπεριλαμβανομένων προσωπικών και ιδιωτικών πληροφοριών. Να μοιράζεστε αναφορές σφαλμάτων μόνο με εφαρμογές και άτομα που εμπιστεύεστε."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"Η λήψη του στιγμιότυπου οθόνης ολοκληρώθηκε με επιτυχία."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Δεν ήταν δυνατή η λήψη του στιγμιότυπου οθόνης."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Λεπτομέρειες αναφοράς σφαλμάτων"</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>
 </resources>
diff --git a/packages/Shell/res/values-en-rAU/strings.xml b/packages/Shell/res/values-en-rAU/strings.xml
index a9247d2..a1bd979 100644
--- a/packages/Shell/res/values-en-rAU/strings.xml
+++ b/packages/Shell/res/values-en-rAU/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Bug report is being generated"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Bug report captured"</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="3559904746859400732">"Touch to share your bug report"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Bug reports"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Bug report file could not be read"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"unnamed"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Details"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot taken successfully."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot could not be taken."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Bug report 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>
 </resources>
diff --git a/packages/Shell/res/values-en-rGB/strings.xml b/packages/Shell/res/values-en-rGB/strings.xml
index a9247d2..a1bd979 100644
--- a/packages/Shell/res/values-en-rGB/strings.xml
+++ b/packages/Shell/res/values-en-rGB/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Bug report is being generated"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Bug report captured"</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="3559904746859400732">"Touch to share your bug report"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Bug reports"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Bug report file could not be read"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"unnamed"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Details"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot taken successfully."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot could not be taken."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Bug report 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>
 </resources>
diff --git a/packages/Shell/res/values-en-rIN/strings.xml b/packages/Shell/res/values-en-rIN/strings.xml
index a9247d2..a1bd979 100644
--- a/packages/Shell/res/values-en-rIN/strings.xml
+++ b/packages/Shell/res/values-en-rIN/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Bug report is being generated"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Bug report captured"</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="3559904746859400732">"Touch to share your bug report"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Bug reports"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Bug report file could not be read"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"unnamed"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Details"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot taken successfully."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot could not be taken."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Bug report 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>
 </resources>
diff --git a/packages/Shell/res/values-es-rUS/strings.xml b/packages/Shell/res/values-es-rUS/strings.xml
index ab2dd63..f86fea0 100644
--- a/packages/Shell/res/values-es-rUS/strings.xml
+++ b/packages/Shell/res/values-es-rUS/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"El informe de errores se está generando"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Informe de errores capturado"</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="3559904746859400732">"Toca para compartir tu informe de errores."</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Informes de errores"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"No se pudo leer el archivo de informe de errores"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"sin nombre"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Detalles"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captura de pantalla"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Se tomó la captura de pantalla correctamente."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"No se pudo tomar la captura de pantalla."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalles del informe de errores"</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>
 </resources>
diff --git a/packages/Shell/res/values-es/strings.xml b/packages/Shell/res/values-es/strings.xml
index d32f012..8f6cdeb 100644
--- a/packages/Shell/res/values-es/strings.xml
+++ b/packages/Shell/res/values-es/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Se está generando el informe de errores"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Informe de error registrado"</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="3559904746859400732">"Toca para compartir tu informe de error"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Informes de error"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"No se ha podido leer el archivo del informe de errores"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"sin nombre"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Detalles"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captura de pantalla"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"La captura de pantalla se ha realizado correctamente."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"No se puede realizar la captura de pantalla."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalles del informe de errores"</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>
 </resources>
diff --git a/packages/Shell/res/values-et-rEE/strings.xml b/packages/Shell/res/values-et-rEE/strings.xml
index 3edefa4..3ebd56d 100644
--- a/packages/Shell/res/values-et-rEE/strings.xml
+++ b/packages/Shell/res/values-et-rEE/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Kest"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Veaaruande loomine"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Veaaruanne jäädvustati"</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="3559904746859400732">"Veaaruande jagamiseks puudutage"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Veaaruanded"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Veaaruande faili ei õnnestunud lugeda"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"nimeta"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Üksikasjad"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Ekraanipilt"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Ekraanipildi tegemine õnnestus."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekraanipilti ei saanud teha."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Veaaruande ü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>
 </resources>
diff --git a/packages/Shell/res/values-eu-rES/strings.xml b/packages/Shell/res/values-eu-rES/strings.xml
index c592f50..93fdb60 100644
--- a/packages/Shell/res/values-eu-rES/strings.xml
+++ b/packages/Shell/res/values-eu-rES/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell-interfazea"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Sortzen ari gara akatsen txostena"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Akatsen txostena jaso 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="3559904746859400732">"Akatsen txostena partekatzeko, ukitu"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Akatsen txostenek sistemaren erregistro-fitxategietako datuak dauzkate, informazio pertsonala eta pribatua barne. Akatsen txostenak partekatzen badituzu, partekatu soilik aplikazio eta pertsona fidagarriekin."</string>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Akatsen txostenak"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Ezin izan da irakurri akatsen txostena"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"izengabea"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Xehetasunak"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Pantaila-argazkia"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Atera da pantaila-argazkia."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ezin izan da atera pantaila-argazkia."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Akatsen 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>
 </resources>
diff --git a/packages/Shell/res/values-fa/strings.xml b/packages/Shell/res/values-fa/strings.xml
index 409fd53..c4ec8b4 100644
--- a/packages/Shell/res/values-fa/strings.xml
+++ b/packages/Shell/res/values-fa/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"گزارش اشکال در حال ایجاد شدن است"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"گزارش اشکال دریافت شد"</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="3559904746859400732">"جهت اشتراک‌گذاری گزارش اشکال خود لمس کنید"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"گزارش‌های اشکال حاوی داده‌هایی از فایل‌های گزارش مختلف در سیستم هستند، شامل اطلاعات شخصی و خصوصی. گزارش‌های اشکال را فقط با افراد و برنامه‌های مورد اعتماد خود به اشتراک بگذارید."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"عکس صفحه‌نمایش با موفقیت گرفته شد."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"نمی‌توان عکس صفحه‌نمایش گرفت."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"جزئیات گزارش اشکال"</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>
 </resources>
diff --git a/packages/Shell/res/values-fi/strings.xml b/packages/Shell/res/values-fi/strings.xml
index bfa920a..0fc4b77 100644
--- a/packages/Shell/res/values-fi/strings.xml
+++ b/packages/Shell/res/values-fi/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Komentotulkki"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Luodaan virheraporttia"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Virheraportti tallennettu"</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="3559904746859400732">"Jaa virheraportti koskettamalla tätä"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Virheraportit"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Virheraporttitiedostoa ei voi lukea."</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"nimetön"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Tietoja"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Kuvakaappaus"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Kuvakaappaus tallennettu."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Kuvakaappauksen tallentaminen epäonnistui."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Virheraportin 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>
 </resources>
diff --git a/packages/Shell/res/values-fr-rCA/strings.xml b/packages/Shell/res/values-fr-rCA/strings.xml
index 4dc4482..d2ef54c 100644
--- a/packages/Shell/res/values-fr-rCA/strings.xml
+++ b/packages/Shell/res/values-fr-rCA/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Le rapport de bogue est en cours de création"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Rapport de bogue enregistré"</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="3559904746859400732">"Appuyer ici pour partager votre rapport de bogue"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Rapports de bogues"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Impossible de lire le fichier du rapport de bogue"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"sans nom"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Détails"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Saisie d\'écran"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"La saisie d\'écran a réussi."</string>
+    <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="3113549839798564645">"Détails du rapport de bogue"</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>
 </resources>
diff --git a/packages/Shell/res/values-fr/strings.xml b/packages/Shell/res/values-fr/strings.xml
index a3e4f7d..ca135ed 100644
--- a/packages/Shell/res/values-fr/strings.xml
+++ b/packages/Shell/res/values-fr/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Le rapport de bug est en cours de création."</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Rapport de bug enregistré"</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="3559904746859400732">"Appuyez ici pour partager le rapport de bug"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Rapports d\'erreur"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Impossible de lire le fichier de rapport de bug."</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"sans nom"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Détails"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captures d\'écran"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"La capture d\'écran a bien été effectuée."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Impossible d\'effectuer une capture d\'écran."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Détails du rapport de bug"</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>
 </resources>
diff --git a/packages/Shell/res/values-gl-rES/strings.xml b/packages/Shell/res/values-gl-rES/strings.xml
index 8b28caa..612d346 100644
--- a/packages/Shell/res/values-gl-rES/strings.xml
+++ b/packages/Shell/res/values-gl-rES/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Estase xerando o informe de erro"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Informe de erros rexistrado"</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="3559904746859400732">"Toca aquí para compartir o teu informe de erros"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Informes de erros"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Non se puido ler o ficheiro de informe de erros"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"sen nome"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Detalles"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captura de pantalla"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"A captura de pantalla realizouse correctamente."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Non se puido realizar a captura de pantalla."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalles do informe de erros"</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>
 </resources>
diff --git a/packages/Shell/res/values-gu-rIN/strings.xml b/packages/Shell/res/values-gu-rIN/strings.xml
index 91b1362..7baefe7 100644
--- a/packages/Shell/res/values-gu-rIN/strings.xml
+++ b/packages/Shell/res/values-gu-rIN/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"શેલ"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"બગ રિપોર્ટ જનરેટ કરવામાં આવી રહી છે"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"બગ રિપોર્ટ કેપ્ચર કરી"</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="3559904746859400732">"તમારી બગ રિપોર્ટ શેર કરવા માટે ટચ કરો"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"બગ રિપોર્ટ્સ વ્યક્તિગત અને ખાનગી માહિતી સહિત, સિસ્ટમની વિભિન્ન લૉગ ફાઇલોનો ડેટા ધરાવે છે. બગ રિપોર્ટ્સ ફક્ત તમે વિશ્વાસ કરતા હો તે એપ્લિકેશનો અને લોકો સાથે જ શેર કરો."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"સ્ક્રીનશોટ સફળતાપૂર્વક લેવાયો."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"સ્ક્રીનશોટ લઇ શકાયો નથી."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"બગ રિપોર્ટની વિગતો"</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>
 </resources>
diff --git a/packages/Shell/res/values-hi/strings.xml b/packages/Shell/res/values-hi/strings.xml
index 595ec7f..c21213e 100644
--- a/packages/Shell/res/values-hi/strings.xml
+++ b/packages/Shell/res/values-hi/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"शेल"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"बग रिपोर्ट जेनरेट हो रही है"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"बग रिपोर्ट कैप्चर कर ली गई"</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="3559904746859400732">"अपनी बग रिपोर्ट साझा करने के लिए स्पर्श करें"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"बग रिपोर्ट में व्यक्तिगत और निजी जानकारी सहित, सिस्टम की विभिन्न लॉग फ़ाइलों का डेटा होता है. बग रिपोर्ट केवल विश्वसनीय ऐप्स  और व्यक्तियों से ही साझा करें."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"स्क्रीनशॉट सफलतापूर्वक लिया गया."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रीनशॉट नहीं लिया जा सका."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"बग रिपोर्ट के विवरण"</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>
 </resources>
diff --git a/packages/Shell/res/values-hr/strings.xml b/packages/Shell/res/values-hr/strings.xml
index 1957bdb..810ad3a 100644
--- a/packages/Shell/res/values-hr/strings.xml
+++ b/packages/Shell/res/values-hr/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Ljuska"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Generira se izvješće o programskoj pogrešci"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Prijava programske pogreške snimljena je"</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="3559904746859400732">"Dodirnite za dijeljenje prijave programske pogreške"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Izvj. o prog. pogreš."</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Izvješće o programskoj pogrešci nije pročitano"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"bez naziva"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Pojedinosti"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Snimka zaslona"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Zaslon je snimljen."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snimanje zaslona nije uspjelo."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Pojedinosti izvješća o programskoj pogrešci"</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>
 </resources>
diff --git a/packages/Shell/res/values-hu/strings.xml b/packages/Shell/res/values-hu/strings.xml
index 74b4aba..b78fc61 100644
--- a/packages/Shell/res/values-hu/strings.xml
+++ b/packages/Shell/res/values-hu/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Héj"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Hibajelentés létrehozása folyamatban"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Programhiba-jelentés rögzítve"</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="3559904746859400732">"Érintse meg a programhiba-jelentés megosztásához"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Hibajelentések"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"A hibajelentési fájlt nem sikerült beolvasni"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"névtelen"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Részletek"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Képernyőkép"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Sikerült elkészíteni a képernyőképet."</string>
+    <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="3113549839798564645">"Hibajelentés 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>
 </resources>
diff --git a/packages/Shell/res/values-hy-rAM/strings.xml b/packages/Shell/res/values-hy-rAM/strings.xml
index 317cb0b..4912d54 100644
--- a/packages/Shell/res/values-hy-rAM/strings.xml
+++ b/packages/Shell/res/values-hy-rAM/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Խեցի"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Վրիպակի զեկույցը ստեղծվում է"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Վրիպակի զեկույց է ստացվել"</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="3559904746859400732">"Հպեք` ձեր վրիպակի մասին զեկույցը տարածելու համար"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Վրիպակի զեկույցները պարունակում են տվյալներ համակարգի տարբեր մուտքի ֆայլերից, այդ թվում նաև անհատական ​​և գաղտնի տեղեկություններ: Վրիպակի զեկույցները կիսեք միայն այն հավելվածների և մարդկանց հետ, որոնց վստահում եք:"</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"Էկրանի պատկերը հաջողությամբ ստացվեց:"</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Չհաջողվեց ստանալ էկրանի պատկերը:"</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Վրիպակի զեկույցի մանրամասները"</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>
 </resources>
diff --git a/packages/Shell/res/values-in/strings.xml b/packages/Shell/res/values-in/strings.xml
index 57d4c73..e774de9 100644
--- a/packages/Shell/res/values-in/strings.xml
+++ b/packages/Shell/res/values-in/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Kerangka"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Laporan bug sedang dibuat"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Laporan bug tercatat"</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="3559904746859400732">"Sentuh untuk membagikan laporan bug Anda"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Laporan bug"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"File laporan bug tidak dapat dibaca"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"tanpa nama"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Detail"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Tangkapan layar"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Tangkapan layar berhasil diambil."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Tangkapan layar tidak dapat diambil."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detail laporan bug"</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>
 </resources>
diff --git a/packages/Shell/res/values-is-rIS/strings.xml b/packages/Shell/res/values-is-rIS/strings.xml
index 39605db..d175b4f 100644
--- a/packages/Shell/res/values-is-rIS/strings.xml
+++ b/packages/Shell/res/values-is-rIS/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Skipanalína"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Verið er að búa til villutilkynningu"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Villutilkynning útbúin"</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="3559904746859400732">"Snertu til að deila villutilkynningunni"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Villutilkynningar"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Ekki var hægt að lesa úr villuskýrslunni"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"án heitis"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Nánar"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skjámynd"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Tókst að taka skjámynd."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekki tókst að taka skjámynd."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Upplýsingar um villutilkynningu"</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>
 </resources>
diff --git a/packages/Shell/res/values-it/strings.xml b/packages/Shell/res/values-it/strings.xml
index 10ba7dd..a954b0c 100644
--- a/packages/Shell/res/values-it/strings.xml
+++ b/packages/Shell/res/values-it/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Generazione segnalazione di bug in corso"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Segnalazione di bug acquisita"</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="3559904746859400732">"Tocca per condividere la segnalazione di bug"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Rapporti sui bug"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Impossibile leggere il file relativo alla segnalazione di bug"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"senza nome"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Dettagli"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot acquisito."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Impossibile acquisire lo screenshot."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Dettagli della segnalazione di bug"</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>
 </resources>
diff --git a/packages/Shell/res/values-iw/strings.xml b/packages/Shell/res/values-iw/strings.xml
index 5b0cb26..40bd73b 100644
--- a/packages/Shell/res/values-iw/strings.xml
+++ b/packages/Shell/res/values-iw/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"מעטפת"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"מופק דוח על באג"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"דוח הבאגים צולם"</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="3559904746859400732">"גע כדי לשתף את דוח הבאגים שלך"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"דוחות על באגים כוללים נתונים מקובצי היומן השונים במערכת, כולל מידע אישי ופרטי. שתף דוחות באגים רק עם אפליקציות ואנשים שאתה סומך עליהם."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"צילום המסך בוצע בהצלחה."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"לא ניתן היה לצלם מסך."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"פרטי דוח על באג"</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>
 </resources>
diff --git a/packages/Shell/res/values-ja/strings.xml b/packages/Shell/res/values-ja/strings.xml
index fd4a150..f0183b5 100644
--- a/packages/Shell/res/values-ja/strings.xml
+++ b/packages/Shell/res/values-ja/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"シェル"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"バグレポートを生成しています"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"バグレポートが記録されました"</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="3559904746859400732">"バグレポートを共有するにはタップします"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"バグレポートには、個人の非公開情報など、システムのさまざまなログファイルのデータが含まれます。共有する場合は信頼するアプリとユーザーのみを選択してください。"</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"スクリーンショットを撮影しました。"</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"スクリーンショットを撮影できませんでした。"</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"バグレポートの詳細"</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>
 </resources>
diff --git a/packages/Shell/res/values-ka-rGE/strings.xml b/packages/Shell/res/values-ka-rGE/strings.xml
index 802f944..a7ad694 100644
--- a/packages/Shell/res/values-ka-rGE/strings.xml
+++ b/packages/Shell/res/values-ka-rGE/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"გარეკანი"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"მიმდინარეობს ხარვეზის შესახებ ანგარიშის გენერირება"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"ანგარიში ხარვეზების შესახებ შექმნილია"</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="3559904746859400732">"შეეხეთ თქვენი ხარვეზების ანგარიშის გასაზიარებლად"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"ხარვეზის ანგარიშები მოიცავს მონაცემებს სხვადასხვა სისტემური ჟურნალის ფაილებიდან, მათ შორის პირად და კონფიდენციალურ ინფორმაციას."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"ეკრანის ანაბეჭდი გადაღებულია წარმატებით."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ეკრანის ანაბეჭდის გადაღება ვერ მოხერხდა."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ხარვეზის შესახებ ანგარიშის დეტალები"</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>
 </resources>
diff --git a/packages/Shell/res/values-kk-rKZ/strings.xml b/packages/Shell/res/values-kk-rKZ/strings.xml
index 2825342..25a3879 100644
--- a/packages/Shell/res/values-kk-rKZ/strings.xml
+++ b/packages/Shell/res/values-kk-rKZ/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Қабыршық"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Қате туралы есеп жасалып жатыр"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Вирус туралы баянат қабылданды"</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="3559904746859400732">"Бөліс үшін, вирус туралы баянатты түртіңіз."</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Вирус туралы баянатта жүйеде тіркелген әртүрлі файлдар туралы деректер болады, оған жеке және құпия ақпарат та кіреді. Вирус баянаттарын сенімді қолданбалар және сенімді адамдармен ғана бөлісіңіз."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"Скриншот сәтті түсірілді."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Скриншот түсіру мүмкін болмады."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Қате туралы есептің мәліметтері"</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>
 </resources>
diff --git a/packages/Shell/res/values-km-rKH/strings.xml b/packages/Shell/res/values-km-rKH/strings.xml
index 966cec0..844c317 100644
--- a/packages/Shell/res/values-km-rKH/strings.xml
+++ b/packages/Shell/res/values-km-rKH/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"សែល"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"របាយការណ៍កំហុសកំពុងត្រូវបានបង្កើត"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"បាន​ចាប់​យក​របាយការណ៍​កំហុស"</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="3559904746859400732">"ប៉ះ​ ដើម្បី​ចែក​រំលែក​របាយការណ៍​កំហុស​របស់​អ្នក"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"របាយការណ៍​កំហុស​រួមមាន​ឯកសារ​កំណត់​ហេតុ​ផ្សេងៗ​របស់​ប្រព័ន្ធ រួមមាន​ព័ត៌មាន​ផ្ទាល់ខ្លួន និង​ឯកជន។ ចែករំលែក​របាយការណ៍​កំហុស​ជា​មួយ​កម្មវិធី និង​មនុស្ស​ដែល​អ្នក​ទុក​ចិត្ត។"</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"បានថតរូបថតអេក្រង់ដោយជោគជ័យ"</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"មិនអាចថតរូបថតអេក្រង់បានទេ"</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ព័ត៌មានលម្អិតពីរបាយការណ៍កំហុស"</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>
 </resources>
diff --git a/packages/Shell/res/values-kn-rIN/strings.xml b/packages/Shell/res/values-kn-rIN/strings.xml
index 6da5319..a3c9b95 100644
--- a/packages/Shell/res/values-kn-rIN/strings.xml
+++ b/packages/Shell/res/values-kn-rIN/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"ಶೆಲ್"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"ದೋಷ ವರದಿಯನ್ನು ರಚಿಸಲಾಗುತ್ತಿದೆ"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"ದೋಷದ ವರದಿಯನ್ನು ಸೆರೆಹಿಡಿಯಲಾಗಿದೆ"</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="3559904746859400732">"ನಿಮ್ಮ ದೋಷದ ವರದಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಲು ಸ್ಪರ್ಶಿಸಿ"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"ವೈಯಕ್ತಿಕ ಮತ್ತು ಖಾಸಗಿ ಮಾಹಿತಿಯು ಸೇರಿದಂತೆ, ಸಿಸ್ಟಂನ ಹಲವಾರು ಲಾಗ್ ಫೈಲ್‌ಗಳಿಂದ ಡೇಟಾವನ್ನು ದೋಷದ ವರದಿಗಳು ಒಳಗೊಂಡಿವೆ. ನೀವು ನಂಬುವಂತಹ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ಜನರೊಂದಿಗೆ ಮಾತ್ರ ದೋಷದ ವರದಿಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳಿ."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ಯಶಸ್ವಿಯಾಗಿ ತೆಗೆದುಕೊಳ್ಳಲಾಗಿದೆ."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ತೆಗೆದುಕೊಳ್ಳಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ಬಗ್ ವರದಿ ವಿವರಗಳು"</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>
 </resources>
diff --git a/packages/Shell/res/values-ko/strings.xml b/packages/Shell/res/values-ko/strings.xml
index 5e96e6d..912d940 100644
--- a/packages/Shell/res/values-ko/strings.xml
+++ b/packages/Shell/res/values-ko/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"셸"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"버그 신고 생성 중"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"버그 신고서 캡처됨"</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="3559904746859400732">"버그 신고서를 공유하려면 터치하세요."</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"버그 신고서는 시스템의 다양한 로그 파일 데이터(예: 개인 및 비공개 정보)를 포함합니다. 신뢰할 수 있는 앱과 사용자에게만 버그 신고서를 공유하세요."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"스크린샷을 찍었습니다."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"스크린샷을 찍을 수 없습니다."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"버그 신고 세부정보"</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>
 </resources>
diff --git a/packages/Shell/res/values-ky-rKG/strings.xml b/packages/Shell/res/values-ky-rKG/strings.xml
index c5b4144..8ad785c 100644
--- a/packages/Shell/res/values-ky-rKG/strings.xml
+++ b/packages/Shell/res/values-ky-rKG/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Командалык кабык"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Мүчүлүштүктөр тууралуу билдирүү түзүлүүдө"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Ката тууралуу билдирүү түзүлдү"</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="3559904746859400732">"Ката тууралуу билдирүүңүздү жөнөтүш үчүн, тийиңиз"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Ката тууралуу билдирүүлөр системанын ар кандай лог файлдарынын берилиштерин камтыйт, аларга өздүк жана купуя маалыматтар дагы кирет. Ката тууралуу билдирүүлөрдү сиз ишенген колдонмолор жана адамдар менен гана бөлүшүңүз."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"Скриншот ийгиликтүү тартылды."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Скриншот тартылбай койду."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Мүчүлүштүктөр жөнүндө кабардын чоо-жайы"</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>
 </resources>
diff --git a/packages/Shell/res/values-lo-rLA/strings.xml b/packages/Shell/res/values-lo-rLA/strings.xml
index 0346688..d159254 100644
--- a/packages/Shell/res/values-lo-rLA/strings.xml
+++ b/packages/Shell/res/values-lo-rLA/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"ກຳລັງສ້າງລາຍງານບັນຫາ"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"ລາຍງານຈຸດບົກພ່ອງຖືກເກັບກຳແລ້ວ"</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="3559904746859400732">"ແຕະເພື່ອສົ່ງການລາຍງານປັນຫາຂອງທ່ານ"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"ການລາຍງານຂໍ້ຜິດພາດປະກອບມີ ຂໍ້ມູນຈາກໄຟລ໌ບັນທຶກຂອງລະບົບຫຼາຍໄຟລ໌, ຮວມທັງຂໍ້ມູນສ່ວນໂຕນຳ. ທ່ານຕ້ອງແບ່ງປັນລາຍງານຂໍ້ຜິດພາດໃຫ້ແອັບຯ ແລະຄົນທີ່ທ່ານເຊື່ອຖືໄດ້ເທົ່ານັ້ນ."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"ຖ່າຍພາບໜ້າຈໍສຳເລັດແລ້ວ."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ບໍ່ສາມາດຖ່າຍພາບໜ້າຈໍໄດ້."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ລາຍ​ລະ​ອຽດ​ການລາຍງານບັນຫາ"</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>
 </resources>
diff --git a/packages/Shell/res/values-lt/strings.xml b/packages/Shell/res/values-lt/strings.xml
index 84066c0..0c069c6 100644
--- a/packages/Shell/res/values-lt/strings.xml
+++ b/packages/Shell/res/values-lt/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Apvalkalas"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Pranešimas apie riktą generuojamas"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Riktų ataskaita užfiksuota"</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="3559904746859400732">"Palieskite, kad bendrintumėte riktų ataskaitą"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Riktų ataskaitos"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Nepavyko sukurti pranešimo apie riktą failo"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"be pavadinimo"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Informacija"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Ekrano kopija"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Ekrano kopija sėkmingai padaryta."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nepavyko padaryti ekrano kopijos."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Išsami pranešimo apie riktą informacija"</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>
 </resources>
diff --git a/packages/Shell/res/values-lv/strings.xml b/packages/Shell/res/values-lv/strings.xml
index 95d168c..1baa343 100644
--- a/packages/Shell/res/values-lv/strings.xml
+++ b/packages/Shell/res/values-lv/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Aizsargs"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Notiek kļūdas pārskata izveide"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Izveidots kļūdu pārskats"</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="3559904746859400732">"Pieskarieties, lai kopīgotu kļūdu pārskatu."</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Kļūdu ziņojumi"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Nevarēja nolasīt kļūdas pārskata failu."</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"bez nosaukuma"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Detalizēta informācija"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Ekrānuzņēmums"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Ekrānuzņēmums ir veikts sekmīgi."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nevarēja veikt ekrānuzņēmumu."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Kļūdas pārskata 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>
 </resources>
diff --git a/packages/Shell/res/values-mk-rMK/strings.xml b/packages/Shell/res/values-mk-rMK/strings.xml
index 0f3ed5a..efbec8e 100644
--- a/packages/Shell/res/values-mk-rMK/strings.xml
+++ b/packages/Shell/res/values-mk-rMK/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Обвивка"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Се генерира извештајот за грешки"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Извештајот за грешка е снимен"</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="3559904746859400732">"Допри да се сподели твојот извештај за грешка"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Извештаите за грешка содржат податоци од разни датотеки за евиденција на системот, вклучувајќи лични и приватни информации. Извештаите за грешка споделувајте ги само со апликации и луѓе на коишто им верувате."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"Успешно е направена слика од екранот."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не може да се направи слика од екранот."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Детали на извештајот за грешка"</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>
 </resources>
diff --git a/packages/Shell/res/values-ml-rIN/strings.xml b/packages/Shell/res/values-ml-rIN/strings.xml
index 290c10b..82cfd6d 100644
--- a/packages/Shell/res/values-ml-rIN/strings.xml
+++ b/packages/Shell/res/values-ml-rIN/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"ഷെൽ"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"ബഗ് റിപ്പോർട്ട് സൃഷ്ടിച്ചുകൊണ്ടിരിക്കുന്നു"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"ബഗ് റിപ്പോർട്ട് ക്യാപ്‌ചർ ചെയ്‌തു"</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="3559904746859400732">"നിങ്ങളുടെ ബഗ് റിപ്പോർട്ട് പങ്കിടാൻ സ്‌പർശിക്കുക"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"വ്യക്തിഗതവും സ്വകാര്യവുമായ വിവരങ്ങൾ ഉൾപ്പെടെ, സിസ്റ്റത്തിന്റെ നിരവധി ലോഗ് ഫയലുകളിൽ നിന്നുള്ള ഡാറ്റ, ബഗ് റിപ്പോർട്ടുകളിൽ അടങ്ങിയിരിക്കുന്നു. നിങ്ങൾ വിശ്വസിക്കുന്ന അപ്ലിക്കേഷനുകൾക്കും ആളുകൾക്കും മാത്രം ബഗ് റിപ്പോർട്ടുകൾ പങ്കിടുക."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"സ്ക്രീൻഷോട്ട് എടുത്തു."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"സ്ക്രീൻഷോട്ട് എടുക്കാൻ കഴിഞ്ഞില്ല."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ബഗ് റിപ്പോർട്ട് വിശദാംശങ്ങൾ"</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>
 </resources>
diff --git a/packages/Shell/res/values-mn-rMN/strings.xml b/packages/Shell/res/values-mn-rMN/strings.xml
index 8f6a2b0..856803d 100644
--- a/packages/Shell/res/values-mn-rMN/strings.xml
+++ b/packages/Shell/res/values-mn-rMN/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Шел"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Алдааны тайланг үүсгэсэн"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Алдааны мэдээлэл хүлээн авав"</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="3559904746859400732">"Та алдааны мэдэгдлийг хуваалцах бол хүрнэ үү"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Алдааны репорт нь хувийн болон нууц мэдээлэл зэргийг агуулсан системийн төрөл бүрийн лог файлын датаг агуулна. Алдааны репортыг зөвхөн итгэлтэй апп болон хүмүүст хуваалцана уу."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"Дэлгэцийн зургийг амжилттай авлаа."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Дэлгэцийн зураг авах боломжгүй."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Алдааны дэлгэрэнгүй тайлан"</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>
 </resources>
diff --git a/packages/Shell/res/values-mr-rIN/strings.xml b/packages/Shell/res/values-mr-rIN/strings.xml
index 40d7a9c..763eec6 100644
--- a/packages/Shell/res/values-mr-rIN/strings.xml
+++ b/packages/Shell/res/values-mr-rIN/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"शेल"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"दोष अहवाल तयार केला जात आहे"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"दोष अहवाल कॅप्‍चर केला"</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="3559904746859400732">"आपला दोष अहवाल सामायिक करण्‍यासाठी स्‍पर्श करा"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"दोष अहवालांमध्‍ये वैयक्तिक आणि खाजगी माहितीसह, सिस्‍टमच्‍या अनेक लॉग फायलींमधील डेटा असतो. केवळ आपला विश्वास असलेल्‍या अ‍ॅप्‍स आणि लोकांसह दोष अहवाल सामायिक करा."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"स्क्रीनशॉट यशस्वीपणे घेतला."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रीनशॉट घेणे शक्य झाले नाही."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"दोष अहवाल तपशील"</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>
 </resources>
diff --git a/packages/Shell/res/values-ms-rMY/strings.xml b/packages/Shell/res/values-ms-rMY/strings.xml
index db8b5dc..1afe430 100644
--- a/packages/Shell/res/values-ms-rMY/strings.xml
+++ b/packages/Shell/res/values-ms-rMY/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Laporan pepijat sedang dijana"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Laporan pepijat telah ditangkap"</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="3559904746859400732">"Sentuh untuk berkongsi laporan pepijat anda"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Laporan pepijat"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Fail laporan pepijat tidak dapat dibaca"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"tidak bernama"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Butiran"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Tangkapan skrin"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Tangkapan skrin berjaya diambil."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Tangkapan skrin tidak dapat diambil."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Butiran laporan pepijat"</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>
 </resources>
diff --git a/packages/Shell/res/values-my-rMM/strings.xml b/packages/Shell/res/values-my-rMM/strings.xml
index 77ca5bf..e941111 100644
--- a/packages/Shell/res/values-my-rMM/strings.xml
+++ b/packages/Shell/res/values-my-rMM/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"အခွံ"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"ချွတ်ယွင်းမှု အစီရင်ခံစာကို ထုတ်ပေးနေသည်"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"အမှားအယွင်းမှတ်တမ်းကို အောင်မြင်စွာ သိမ်းဆည်းပြီး"</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="3559904746859400732">"အမှားအယွင်း မှတ်တမ်းကို မျှဝေရန် ထိလိုက်ပါ"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"အမှားအယွင်း မှတ်တမ်းမှာ ပါရှိသော အချက်အလက်များမှာ ကိုယ်ရေးကိုယ်တာ နဲ့ လုံခြုံရေး အချက်အလက်များပါဝင်သော စနစ်မှ ပြုလုပ်မှု မှတ်တမ်းများ ဖြစ်ပါသည်၊ အမှားအယွင်း မှတ်တမ်းများကို ယုံကြည်ရသော အပလီကေးရှင်းများနဲ့ လူများကိုသာ ပေးဝေပြသမှု လုပ်ပါရန်။"</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"မျက်နှာပြင် လျှပ်တစ်ပြက်ပုံကို အောင်မြင်စွာ ရိုက်ပြီးပြီ။"</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"မျက်နှာပြင် လျှပ်တစ်ပြက်ပုံ မရိုက်နိုင်ပါ"</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ချွတ်ယွင်းချက်အစီရင်ခံစာ အသေးစိတ်များ"</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>
 </resources>
diff --git a/packages/Shell/res/values-nb/strings.xml b/packages/Shell/res/values-nb/strings.xml
index 14a873c..87b3530 100644
--- a/packages/Shell/res/values-nb/strings.xml
+++ b/packages/Shell/res/values-nb/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Kommandoliste"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Feilrapporten blir generert"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Feilrapporten er lagret"</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="3559904746859400732">"Trykk for å dele feilrapporten din"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Feilrapporter"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Feilrapportfilen kunne ikke leses"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"uten navn"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Detaljer"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skjermdump"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Skjermdumpen er tatt."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Skjermdumpen kunne ikke tas."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detaljer om feilrapporten"</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>
 </resources>
diff --git a/packages/Shell/res/values-ne-rNP/strings.xml b/packages/Shell/res/values-ne-rNP/strings.xml
index 03aef3c..5b68ece 100644
--- a/packages/Shell/res/values-ne-rNP/strings.xml
+++ b/packages/Shell/res/values-ne-rNP/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"सेल"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"बग रिपोर्ट उत्पन्न भइरहेको छ"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"बग प्रतिवेदन समातियो"</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="3559904746859400732">"तपाईंको बग रिपोर्ट साझेदारी गर्न छुनुहोस्"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"बग रिपोर्टहरूमा प्रणालीका विभिन्न लग फाइलहरूबाट व्यक्तिगत तथा नीजि सूचनासहितको डेटा रहन्छ।  बग रिपोर्टहरू अनुप्रयोगहरू र तपाईँले विश्वास गरेका व्यक्तिहरूसँग मात्र साझेदारी गर्नुहोस्।"</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"स्क्रिनशट सफलतापूर्वक लिइयो।"</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रिनशट लिन सकिएन।"</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"बग रिपोर्टको विवरण"</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>
 </resources>
diff --git a/packages/Shell/res/values-nl/strings.xml b/packages/Shell/res/values-nl/strings.xml
index 9bfce94..dd67ccd 100644
--- a/packages/Shell/res/values-nl/strings.xml
+++ b/packages/Shell/res/values-nl/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Bugrapport wordt gegenereerd"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Foutenrapport vastgelegd"</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="3559904746859400732">"Raak aan om je foutenrapport te delen"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Foutenrapporten"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Bestand met bugrapport kan niet worden gelezen"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"naamloos"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Details"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot is gemaakt."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot kan niet worden gemaakt."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Details van bugrapport"</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>
 </resources>
diff --git a/packages/Shell/res/values-pa-rIN/strings.xml b/packages/Shell/res/values-pa-rIN/strings.xml
index cf6df17..96addbf 100644
--- a/packages/Shell/res/values-pa-rIN/strings.xml
+++ b/packages/Shell/res/values-pa-rIN/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"ਸ਼ੈਲ"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"ਬੱਗ ਰਿਪੋਰਟ ਸਿਰਜੀ ਜਾ ਰਹੀ ਹੈ"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"ਬਗ ਰਿਪੋਰਟ ਕੈਪਚਰ ਕੀਤੀ"</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="3559904746859400732">"ਆਪਣੀ ਬਗ ਰਿਪੋਰਟ ਸ਼ੇਅਰ ਕਰਨ ਲਈ ਛੋਹਵੋ"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"ਬਗ ਰਿਪੋਰਟਾਂ ਵਿੱਚ ਸਿਸਟਮ ਦੀਆਂ ਭਿੰਨ ਲੌਗ ਫਾਈਲਾਂ ਦਾ ਡਾਟਾ ਹੁੰਦਾ ਹੈ, ਨਿੱਜੀ ਅਤੇ ਪ੍ਰਾਈਵੇਟ ਜਾਣਕਾਰੀ ਸਮੇਤ। ਕੇਵਲ ਉਹਨਾਂ ਐਪਸ ਅਤੇ ਲੋਕਾਂ ਨਾਲ ਬਗ ਰਿਪੋਰਟਾਂ ਸ਼ੇਅਰ ਕਰੋ, ਜਿਹਨਾਂ ਤੇ ਤੁਸੀਂ ਭਰੋਸਾ ਕਰਦੇ ਹੋ।"</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸਫਲਤਾਪੂਰਵਕ ਲਿਆ ਗਿਆ।"</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਨਹੀਂ ਲਿਆ ਜਾ ਸਕਿਆ।"</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ਬੱਗ ਰਿਪੋਰਟ ਵੇਰਵੇ"</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>
 </resources>
diff --git a/packages/Shell/res/values-pl/strings.xml b/packages/Shell/res/values-pl/strings.xml
index 0c8a6b4..7a67ac6 100644
--- a/packages/Shell/res/values-pl/strings.xml
+++ b/packages/Shell/res/values-pl/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Powłoka"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Trwa generowanie raportu o błędzie"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Raport o błędach został zapisany"</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="3559904746859400732">"Kliknij, by udostępnić raport o błędach"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Raporty o błędach"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Nie można odczytać raportu o błędzie"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"bez nazwy"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Szczegóły"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Zrzut ekranu"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Zrobiono zrzut ekranu."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nie udało się zrobić zrzutu ekranu."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Szczegóły zgłoszenia błędu"</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>
 </resources>
diff --git a/packages/Shell/res/values-pt-rBR/strings.xml b/packages/Shell/res/values-pt-rBR/strings.xml
index b194ecc..471e959 100644
--- a/packages/Shell/res/values-pt-rBR/strings.xml
+++ b/packages/Shell/res/values-pt-rBR/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Um relatório do bug está sendo gerado"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Relatório de bugs capturado"</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="3559904746859400732">"Toque para compartilhar seu relatório de bugs"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Relatórios de bugs"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Não foi possível ler o arquivo de relatório de bug"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"sem nome"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Detalhes"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Capturas de tela"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Captura de tela concluída."</string>
+    <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="3113549839798564645">"Detalhes do relatório do bug"</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>
 </resources>
diff --git a/packages/Shell/res/values-pt-rPT/strings.xml b/packages/Shell/res/values-pt-rPT/strings.xml
index 757538c..ed78f55 100644
--- a/packages/Shell/res/values-pt-rPT/strings.xml
+++ b/packages/Shell/res/values-pt-rPT/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"O relatório de erro está a ser criado"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Relatório de erros capturado"</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="3559904746859400732">"Toque para partilhar o relatório de erros"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Relatórios de erros"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Não foi possível ler o ficheiro de relatório de erro"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"sem nome"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Detalhes"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captura de ecrã"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Captura de ecrã tirada com êxito."</string>
+    <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="3113549839798564645">"Detalhes do relatório de erro"</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>
 </resources>
diff --git a/packages/Shell/res/values-pt/strings.xml b/packages/Shell/res/values-pt/strings.xml
index b194ecc..471e959 100644
--- a/packages/Shell/res/values-pt/strings.xml
+++ b/packages/Shell/res/values-pt/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Um relatório do bug está sendo gerado"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Relatório de bugs capturado"</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="3559904746859400732">"Toque para compartilhar seu relatório de bugs"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Relatórios de bugs"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Não foi possível ler o arquivo de relatório de bug"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"sem nome"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Detalhes"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Capturas de tela"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Captura de tela concluída."</string>
+    <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="3113549839798564645">"Detalhes do relatório do bug"</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>
 </resources>
diff --git a/packages/Shell/res/values-ro/strings.xml b/packages/Shell/res/values-ro/strings.xml
index 132f21f..af67bc6 100644
--- a/packages/Shell/res/values-ro/strings.xml
+++ b/packages/Shell/res/values-ro/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Se generează raportul de eroare"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Raportul despre erori a fost creat"</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="3559904746859400732">"Atingeți pentru a permite accesul la raportul despre erori"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Rapoarte de erori"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Fișierul cu raportul de eroare nu a putut fi citit"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"fără nume"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Detalii"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captură de ecran"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Captura de ecran a fost făcută."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Captura de ecran nu a putut fi făcută."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalii privind raportul de eroare"</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>
 </resources>
diff --git a/packages/Shell/res/values-ru/strings.xml b/packages/Shell/res/values-ru/strings.xml
index 5dc5953..a5e2bd2 100644
--- a/packages/Shell/res/values-ru/strings.xml
+++ b/packages/Shell/res/values-ru/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Оболочка"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Создание отчета об ошибке…"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Отчет об ошибке сохранен"</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="3559904746859400732">"Нажмите, чтобы отправить отчет об ошибках"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Отчеты об ошибках содержат данные различных системных журналов и могут включать личную информацию. Рекомендуем открывать к ним доступ только лицам и приложениям, заслуживающим доверие."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"Скриншот готов"</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не удалось сделать скриншот"</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Детали отчета об ошибке"</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>
 </resources>
diff --git a/packages/Shell/res/values-si-rLK/strings.xml b/packages/Shell/res/values-si-rLK/strings.xml
index c846f87..866c0f7 100644
--- a/packages/Shell/res/values-si-rLK/strings.xml
+++ b/packages/Shell/res/values-si-rLK/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"ෂෙල්"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"දෝෂ වාර්තාවක් ජනනය කරමින් පවතී"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"දෝෂ වාර්තාව ලබාගන්නා ලදි"</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="3559904746859400732">"ඔබගේ දෝෂ වාර්තාව බෙදා ගැනීමට ස්පර්ශ කරන්න"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"පුද්ගලික සහ පෞද්ගලික තොරතුරු ඇතුළත්ව පද්ධතියේ විවිධ ලොග් ගොනු වල දත්ත දෝෂ වාර්තාවේ අඩංගු වේ. ඔබට විශ්වාසවන්ත යෙදුම් සහ පුද්ගලයින් සමඟ පමණක් දෝෂ වාර්තා බෙදා ගන්න."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"සාර්ථකව තිර රුවක් ගන්නා ලදී."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"තිර රුවක් ගත නොහැකි විය."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"දෝෂ වාර්තා විස්තර"</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>
 </resources>
diff --git a/packages/Shell/res/values-sk/strings.xml b/packages/Shell/res/values-sk/strings.xml
index b395d1a..f207480 100644
--- a/packages/Shell/res/values-sk/strings.xml
+++ b/packages/Shell/res/values-sk/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Prostredie"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Generuje sa hlásenie chyby"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Hlásenie o chybách bolo vytvorené"</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="3559904746859400732">"Hlásenie o chybách môžete zdielať klepnutím"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Hlásenia chýb"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Súbor s hlásením chyby sa nepodarilo prečítať"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"bez názvu"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Podrobnosti"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Snímka obrazovky"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Snímka obrazovky bola zaznamenaná."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snímku obrazovky sa nepodarilo zaznamenať."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Podrobnosti hlásenia chyby"</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>
 </resources>
diff --git a/packages/Shell/res/values-sl/strings.xml b/packages/Shell/res/values-sl/strings.xml
index 91041e1..c249961 100644
--- a/packages/Shell/res/values-sl/strings.xml
+++ b/packages/Shell/res/values-sl/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Lupina"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Poročilo o napakah se pripravlja"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Poročilo o napaki je posneto"</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="3559904746859400732">"Dotaknite se, če želite deliti sporočilo o napaki z drugimi"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Poročila o napakah"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Datoteke s poročilom o napakah ni bilo mogoče prebrati"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"neimenovano"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Podrobnosti"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Posnetek zaslona"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Posnetek zaslon je bil uspešno ustvarjen."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Posnetka zaslon ni bilo mogoče ustvariti."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Podrobnosti o poročilu o napakah"</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>
 </resources>
diff --git a/packages/Shell/res/values-sq-rAL/strings.xml b/packages/Shell/res/values-sq-rAL/strings.xml
index e91aa09..8a306b3 100644
--- a/packages/Shell/res/values-sq-rAL/strings.xml
+++ b/packages/Shell/res/values-sq-rAL/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Guaska"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Po krijohet raporti i defekteve në kod"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Raporti i defektit në kod u regjistrua"</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="3559904746859400732">"Prek për të ndarë raportin e defektit në kod"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Raportet e gabimeve"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Skedari i raportimit të defektit në kod nuk mund të lexohej."</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"e paemërtuar"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Detajet"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Pamja e ekranit"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Pamja e ekranit u realizua me sukses."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Pamja e ekranit nuk mund të realizohej."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detajet e raportimit të gabimeve në kod"</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>
 </resources>
diff --git a/packages/Shell/res/values-sr/strings.xml b/packages/Shell/res/values-sr/strings.xml
index 1be47da..9bff65c 100644
--- a/packages/Shell/res/values-sr/strings.xml
+++ b/packages/Shell/res/values-sr/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Извештај о грешци се генерише"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Извештај о грешци је снимљен"</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="3559904746859400732">"Додирните да бисте делили извештај о грешци"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Извештаји о грешкама садрже податке из различитих системских датотека евиденције, укључујући личне и приватне податке. Делите извештаје о грешкама само са апликацијама и људима у које имате поверења."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"Снимање екрана је успело."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Снимање екрана није успело."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Детаљи извештаја о грешци"</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>
 </resources>
diff --git a/packages/Shell/res/values-sv/strings.xml b/packages/Shell/res/values-sv/strings.xml
index 9f5b5f0..fb962bf 100644
--- a/packages/Shell/res/values-sv/strings.xml
+++ b/packages/Shell/res/values-sv/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Skal"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Felrapporten genereras"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Felrapporten har skapats"</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="3559904746859400732">"Tryck om du vill dela felrapporten"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Felrapporter"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Det gick inte att läsa felrapporten"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"namnlös"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Information"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skärmdump"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"En skärmdump har tagits."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Det gick inte att ta skrämdump."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Information för felrapporten"</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>
 </resources>
diff --git a/packages/Shell/res/values-sw/strings.xml b/packages/Shell/res/values-sw/strings.xml
index 422ca81..de46414 100644
--- a/packages/Shell/res/values-sw/strings.xml
+++ b/packages/Shell/res/values-sw/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Ganda"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Inatayarisha ripoti ya hitilafu"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Ripoti ya hitilafu imenaswa"</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="3559904746859400732">"Gusa ili ushiriki ripoti yako ya hitilafu"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Ripoti za hitilafu"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Faili ya ripoti ya hitilafu haikusomwa"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"Isiyo na jina"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Maelezo"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Picha ya skrini"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Imepiga picha ya skrini."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Haikupiga picha ya skrini."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Maelezo kuhusu ripoti ya hitilafu"</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>
 </resources>
diff --git a/packages/Shell/res/values-ta-rIN/strings.xml b/packages/Shell/res/values-ta-rIN/strings.xml
index 31daf54..15c7014 100644
--- a/packages/Shell/res/values-ta-rIN/strings.xml
+++ b/packages/Shell/res/values-ta-rIN/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"ஷெல்"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"பிழை அறிக்கை உருவாக்கப்படுகிறது"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"பிழை அறிக்கைகள் படமெடுக்கப்பட்டன"</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="3559904746859400732">"உங்கள் பிழை அறிக்கையைப் பகிர, தொடவும்"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"பிழை அறிக்கைகளில், சொந்த வாழ்க்கை மற்றும் தனிப்பட்ட தகவல் உள்பட கணினியின் பல்வேறு பதிவுகளில் உள்ள தரவு இருக்கும். நீங்கள் நம்பும் பயன்பாடுகள் மற்றும் நபர்களுடன் மட்டும் பிழை அறிக்கைகளைப் பகிரவும்."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"ஸ்கிரீன் ஷாட் எடுக்கப்பட்டது."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ஸ்கிரீன் ஷாட்டை எடுக்க முடியவில்லை."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"பிழை அறிக்கை விவரங்கள்"</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>
 </resources>
diff --git a/packages/Shell/res/values-te-rIN/strings.xml b/packages/Shell/res/values-te-rIN/strings.xml
index 34ab6f2..c84ec9a 100644
--- a/packages/Shell/res/values-te-rIN/strings.xml
+++ b/packages/Shell/res/values-te-rIN/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"షెల్"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"బగ్ నివేదిక ఉత్పాదించబడుతోంది"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"బగ్ నివేదిక క్యాప్చర్ చేయబడింది"</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="3559904746859400732">"మీ బగ్ నివేదికను భాగస్వామ్యం చేయడానికి తాకండి"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"బగ్ నివేదికలు వ్యక్తిగతమైన మరియు రహస్యమైన సమాచారంతో సహా సిస్టమ్ యొక్క విభిన్న లాగ్ ఫైల్‌ల్లోని డేటాను కలిగి ఉంటాయి. కనుక బగ్ నివేదికలను మీరు విశ్వసించే అనువర్తనాలు మరియు వ్యక్తులతో మాత్రమే భాగస్వామ్యం చేయండి."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"స్క్రీన్‌షాట్ విజయవంతంగా తీయబడింది."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"స్క్రీన్‌షాట్‌ను తీయడం సాధ్యపడలేదు."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"బగ్ నివేదిక వివరాలు"</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>
 </resources>
diff --git a/packages/Shell/res/values-th/strings.xml b/packages/Shell/res/values-th/strings.xml
index 2d9a65e..f29978e 100644
--- a/packages/Shell/res/values-th/strings.xml
+++ b/packages/Shell/res/values-th/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"กำลังสร้างรายงานข้อบกพร่อง"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"จับภาพรายงานข้อบกพร่องแล้ว"</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="3559904746859400732">"แตะเพื่อแชร์รายงานข้อบกพร่องของคุณ"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"รายงานข้อบกพร่องมีข้อมูลจากไฟล์บันทึกต่างๆ ของระบบ รวมถึงข้อมูลส่วนตัว แชร์รายงานข้อบกพร่องกับแอปและบุคคลที่คุณไว้ใจเท่านั้น"</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"จับภาพหน้าจอสำเร็จแล้ว"</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ไม่สามารถจับภาพหน้าจอได้"</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"รายละเอียดรายงานข้อบกพร่อง"</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>
 </resources>
diff --git a/packages/Shell/res/values-tl/strings.xml b/packages/Shell/res/values-tl/strings.xml
index 8fead8f..c12191a 100644
--- a/packages/Shell/res/values-tl/strings.xml
+++ b/packages/Shell/res/values-tl/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Binubuo na ang ulat ng bug"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Na-capture ang ulat ng bug"</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="3559904746859400732">"Pindutin upang ibahagi ang iyong ulat ng bug"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Mga ulat sa bug"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Hindi mabasa ang file ng pag-uulat ng bug"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"walang pangalan"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Mga Detalye"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Nakunan ng screenshot."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Hindi makunan ng screenshot."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Mga detalye ng ulat ng bug"</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>
 </resources>
diff --git a/packages/Shell/res/values-tr/strings.xml b/packages/Shell/res/values-tr/strings.xml
index e1d30cc..3f562d7 100644
--- a/packages/Shell/res/values-tr/strings.xml
+++ b/packages/Shell/res/values-tr/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Kabuk"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Hata raporu oluşturuluyor"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Hata raporu kaydedildi"</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="3559904746859400732">"Hata raporunuzu paylaşmak için dokunun"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Hata raporları, kişisel ve özel bilgiler dahil olmak üzere sistemin çeşitli günlük dosyalarından veriler içerir. Hata raporlarını sadece güvendiğiniz uygulamalar ve kişilerle paylaşın."</string>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Hata raporları"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Hata raporu dosyası okunamadı"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"adsız"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Ayrıntılar"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Ekran görüntüsü"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Ekran görüntüsü başarıyla alındı."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekran görüntüsü alınamadı."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Hata raporu 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>
 </resources>
diff --git a/packages/Shell/res/values-uk/strings.xml b/packages/Shell/res/values-uk/strings.xml
index f1396cb..93e6511 100644
--- a/packages/Shell/res/values-uk/strings.xml
+++ b/packages/Shell/res/values-uk/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Оболонка"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Генерується повідомлення про помилку"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Звіт про помилки створено"</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="3559904746859400732">"Торкніться, щоб надіслати звіт про помилки"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Звіти про помилки містять дані з різних файлів журналу системи, зокрема особисті та конфіденційні. Надсилайте звіт про помилки лише тим, кому довіряєте."</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"Знімок екрана зроблено."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не вдалося зробити знімок екрана."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Деталі повідомлення про помилку"</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>
 </resources>
diff --git a/packages/Shell/res/values-ur-rPK/strings.xml b/packages/Shell/res/values-ur-rPK/strings.xml
index 412d230..52a45a0 100644
--- a/packages/Shell/res/values-ur-rPK/strings.xml
+++ b/packages/Shell/res/values-ur-rPK/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"شیل"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"بگ رپورٹ تخلیق ہو رہی ہے"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"بَگ رپورٹ کیپچر کر لی گئی"</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="3559904746859400732">"اپنی بَگ رپورٹ کا اشتراک کرنے کیلئے ٹچ کریں"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"بَگ رپورٹس میں سسٹم کی مختلف لاگ فائلوں سے ڈیٹا شامل ہوتا ہے، بشمول ذاتی اور نجی معلومات۔ بَگ رپورٹس کا اشتراک صرف اپنے بھروسے مند ایپس اور لوگوں کے ساتھ کریں۔"</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"اسکرین شاٹ کامیابی سے لے لیا گیا۔"</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"سکرین شاٹ نہیں لیا جا سکا۔"</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"بگ رپورٹ کی تفصیلات"</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>
 </resources>
diff --git a/packages/Shell/res/values-uz-rUZ/strings.xml b/packages/Shell/res/values-uz-rUZ/strings.xml
index ca46d2a..56e0965 100644
--- a/packages/Shell/res/values-uz-rUZ/strings.xml
+++ b/packages/Shell/res/values-uz-rUZ/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Terminal"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Xatoliklar hisoboti tayyorlanmoqda"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Xatolik hisobotini yozib olindi"</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="3559904746859400732">"Xatolik hisobotini bo‘lishish uchun barmog‘ingizni tegizing."</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Xatoliklar hisoboti"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Xatoliklar hisoboti faylini o‘qib bo‘lmadi"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"nomsiz"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Tafsilotlar"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skrinshot"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Skrinshot tayyor."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Skrinshot olib bo‘lmadi."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Xatoliklar hisoboti 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>
 </resources>
diff --git a/packages/Shell/res/values-vi/strings.xml b/packages/Shell/res/values-vi/strings.xml
index ec4364e..2642b89 100644
--- a/packages/Shell/res/values-vi/strings.xml
+++ b/packages/Shell/res/values-vi/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Báo cáo lỗi đang được tạo"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Báo cáo lỗi đã được chụp"</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="3559904746859400732">"Chạm để chia sẻ báo cáo lỗi của bạn"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Báo cáo lỗi"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Không thể đọc tệp báo cáo lỗi"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"chưa được đặt tên"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Chi tiết"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Ảnh chụp màn hình"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Đã chụp ảnh màn hình thành công."</string>
+    <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="3113549839798564645">"Chi tiết báo cáo lỗi"</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>
 </resources>
diff --git a/packages/Shell/res/values-zh-rCN/strings.xml b/packages/Shell/res/values-zh-rCN/strings.xml
index 5a8e5f7..c933961 100644
--- a/packages/Shell/res/values-zh-rCN/strings.xml
+++ b/packages/Shell/res/values-zh-rCN/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"正在生成错误报告"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"已抓取错误报告"</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="3559904746859400732">"触摸即可分享您的错误报告"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"错误报告包含的数据来自于系统的各个日志文件,其中包含个人信息和隐私信息。请务必只与您信任的应用和用户分享错误报告。"</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"已成功截图。"</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"无法截图。"</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"错误报告详细信息"</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>
 </resources>
diff --git a/packages/Shell/res/values-zh-rHK/strings.xml b/packages/Shell/res/values-zh-rHK/strings.xml
index 7e57cc4..7a35eef 100644
--- a/packages/Shell/res/values-zh-rHK/strings.xml
+++ b/packages/Shell/res/values-zh-rHK/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"命令介面"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"正在產生錯誤報告"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"已擷取錯誤報告"</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="3559904746859400732">"輕觸即可分享您的錯誤報告"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"錯誤報告中有來自系統各個記錄檔案的資料,包括個人和私人資料。請只與您信任的應用程式和使用者分享錯誤報告。"</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"成功拍攝螢幕擷取畫面。"</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"無法擷取螢幕畫面。"</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"錯誤報告詳情"</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>
 </resources>
diff --git a/packages/Shell/res/values-zh-rTW/strings.xml b/packages/Shell/res/values-zh-rTW/strings.xml
index e495d4a..ec66878 100644
--- a/packages/Shell/res/values-zh-rTW/strings.xml
+++ b/packages/Shell/res/values-zh-rTW/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"殼層"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"正在產生錯誤報告"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"已擷取錯誤報告"</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="3559904746859400732">"輕觸即可分享您的錯誤報告"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"錯誤報告的資料來自系統各個紀錄檔,包括個人和私密資訊。請務必只與您信任的應用程式和使用者分享錯誤報告。"</string>
@@ -26,4 +28,12 @@
     <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="7175343181767429088">"已成功拍攝螢幕擷取畫面。"</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"無法拍攝螢幕擷取畫面。"</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"錯誤報告詳細資料"</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>
 </resources>
diff --git a/packages/Shell/res/values-zu/strings.xml b/packages/Shell/res/values-zu/strings.xml
index 91f2951..c264224 100644
--- a/packages/Shell/res/values-zu/strings.xml
+++ b/packages/Shell/res/values-zu/strings.xml
@@ -19,6 +19,8 @@
     <string name="app_label" msgid="3701846017049540910">"I-Shell"</string>
     <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Kukhiqizwa umbiko wesiphazamisi"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Umbiko wesiphazamisi uthwetshuliwe"</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="3559904746859400732">"Thinta ukuze wabelane ngombiko wakho wesiphazamisi"</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>
@@ -26,4 +28,12 @@
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Imibiko yeziphazamiso"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Ifayela lombiko wesiphazamso alikwazanga ukufundwa"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"awunikiwe igama"</string>
+    <string name="bugreport_info_action" msgid="2158204228510576227">"Imininingwane"</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Isithombe-skrini"</string>
+    <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Isithombe-skrini sithathwe ngempumelelo."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Isithombe-skrini asikwazanga ukuthathwa."</string>
+    <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Imininingwane yombiko wesiphazamisi"</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>
 </resources>
diff --git a/packages/Shell/res/values/strings.xml b/packages/Shell/res/values/strings.xml
index 5c25576..d992bc3 100644
--- a/packages/Shell/res/values/strings.xml
+++ b/packages/Shell/res/values/strings.xml
@@ -21,6 +21,10 @@
     <string name="bugreport_in_progress_title">Bug report is being generated</string>
     <!-- Title of notification indicating a bugreport has been successfully captured. [CHAR LIMIT=50] -->
     <string name="bugreport_finished_title">Bug report captured</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] -->
+    <string name="bugreport_updating_wait">Please wait\u2026</string>
 
     <!-- Text of notification indicating that swipe left will share the captured bugreport. [CHAR LIMIT=100] -->
     <string name="bugreport_finished_text" product="watch">Swipe left to share your bug report</string>
@@ -42,4 +46,27 @@
     <!-- Title for bug reports received from dumpstate without a name. [CHAR LIMIT=30]-->
     <string name="bugreport_unnamed">unnamed</string>
 
+    <!-- Title of the notification action that opens the dialog for the user-defined bug report details. -->
+    <string name="bugreport_info_action">Details</string>
+
+    <!-- Title of the notification action that takes aditional screenshots. -->
+    <string name="bugreport_screenshot_action">Screenshot</string>
+
+    <!-- Toast message sent when the a screenshot for the bug report was taken successfully. -->
+    <string name="bugreport_screenshot_taken">Screenshot taken succesfully.</string>
+    <!-- Toast message sent when the a screenshot for the bug report was not taken due to an error. -->
+    <string name="bugreport_screenshot_failed">Screenshot could not be taken.</string>
+
+    <!--  Title of the dialog asking for user-defined bug report details like name, title, and description. -->
+    <string name="bugreport_info_dialog_title">Bug report details</string>
+
+    <!-- Text of the hint asking for 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
+         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
+         what the bug report is about. [CHAR LIMIT=NONE] -->
+    <string name="bugreport_info_description">Detailed description</string>
 </resources>
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index e902589..5b83796 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -16,10 +16,12 @@
 
 package com.android.shell;
 
+import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
 import static com.android.shell.BugreportPrefs.STATE_SHOW;
 import static com.android.shell.BugreportPrefs.getWarningState;
 
 import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
@@ -27,18 +29,24 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
 import java.text.NumberFormat;
 import java.util.ArrayList;
-import java.util.Date;
+import java.util.Enumeration;
+import java.util.List;
 import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
 import java.util.zip.ZipOutputStream;
 
 import libcore.io.Streams;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.google.android.collect.Lists;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
+import android.annotation.SuppressLint;
+import android.app.AlertDialog;
 import android.app.Notification;
 import android.app.Notification.Action;
 import android.app.NotificationManager;
@@ -46,6 +54,8 @@
 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;
 import android.net.Uri;
@@ -55,14 +65,22 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.Process;
 import android.os.SystemProperties;
+import android.os.Vibrator;
 import android.support.v4.content.FileProvider;
+import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.util.Log;
 import android.util.Patterns;
 import android.util.SparseArray;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.View.OnFocusChangeListener;
+import android.view.inputmethod.EditorInfo;
+import android.widget.Button;
+import android.widget.EditText;
 import android.widget.Toast;
 
 /**
@@ -91,7 +109,7 @@
  * </ol>
  */
 public class BugreportProgressService extends Service {
-    static final String TAG = "Shell";
+    private static final String TAG = "BugreportProgressService";
     private static final boolean DEBUG = false;
 
     private static final String AUTHORITY = "com.android.shell";
@@ -99,23 +117,44 @@
     // External intents sent by dumpstate.
     static final String INTENT_BUGREPORT_STARTED = "android.intent.action.BUGREPORT_STARTED";
     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";
     static final String INTENT_BUGREPORT_SHARE = "android.intent.action.BUGREPORT_SHARE";
+    static final String INTENT_BUGREPORT_INFO_LAUNCH =
+            "android.intent.action.BUGREPORT_INFO_LAUNCH";
+    static final String INTENT_BUGREPORT_SCREENSHOT =
+            "android.intent.action.BUGREPORT_SCREENSHOT";
 
     static final String EXTRA_BUGREPORT = "android.intent.extra.BUGREPORT";
     static final String EXTRA_SCREENSHOT = "android.intent.extra.SCREENSHOT";
     static final String EXTRA_PID = "android.intent.extra.PID";
     static final String EXTRA_MAX = "android.intent.extra.MAX";
     static final String EXTRA_NAME = "android.intent.extra.NAME";
+    static final String EXTRA_TITLE = "android.intent.extra.TITLE";
+    static final String EXTRA_DESCRIPTION = "android.intent.extra.DESCRIPTION";
     static final String EXTRA_ORIGINAL_INTENT = "android.intent.extra.ORIGINAL_INTENT";
+    static final String EXTRA_INFO = "android.intent.extra.INFO";
 
     private static final int MSG_SERVICE_COMMAND = 1;
     private static final int MSG_POLL = 2;
+    private static final int MSG_DELAYED_SCREENSHOT = 3;
+    private static final int MSG_SCREENSHOT_REQUEST = 4;
+    private static final int MSG_SCREENSHOT_RESPONSE = 5;
+
+    /**
+     * Delay before a screenshot is taken.
+     * <p>
+     * Should be at least 3 seconds, otherwise its toast might show up in the screenshot.
+     */
+    static final int SCREENSHOT_DELAY_SECONDS = 3;
 
     /** Polling frequency, in milliseconds. */
-    static final long POLLING_FREQUENCY = 2000;
+    static final long POLLING_FREQUENCY = 2 * DateUtils.SECOND_IN_MILLIS;
 
     /** How long (in ms) a dumpstate process will be monitored if it didn't show progress. */
     private static final long INACTIVITY_TIMEOUT = 3 * DateUtils.MINUTE_IN_MILLIS;
@@ -124,35 +163,62 @@
     private static final String DUMPSTATE_PREFIX = "dumpstate.";
     private static final String PROGRESS_SUFFIX = ".progress";
     private static final String MAX_SUFFIX = ".max";
+    private static final String NAME_SUFFIX = ".name";
 
-    /** System property (and value) used for stop dumpstate. */
+    /** System property (and value) used to stop dumpstate. */
+    // TODO: should call ActiveManager API instead
     private static final String CTL_STOP = "ctl.stop";
     private static final String BUGREPORT_SERVICE = "bugreportplus";
 
+    /**
+     * Directory on Shell's data storage where screenshots will be stored.
+     * <p>
+     * Must be a path supported by its FileProvider.
+     */
+    private static final String SCREENSHOT_DIR = "bugreports";
+
     /** Managed dumpstate processes (keyed by pid) */
     private final SparseArray<BugreportInfo> mProcesses = new SparseArray<>();
 
-    private Looper mServiceLooper;
-    private ServiceHandler mServiceHandler;
+    private Context mContext;
+    private ServiceHandler mMainHandler;
+    private ScreenshotHandler mScreenshotHandler;
+
+    private final BugreportInfoDialog mInfoDialog = new BugreportInfoDialog();
+
+    private File mScreenshotsDir;
+
+    /**
+     * Flag indicating whether a screenshot is being taken.
+     * <p>
+     * This is the only state that is shared between the 2 handlers and hence must have synchronized
+     * access.
+     */
+    private boolean mTakingScreenshot;
 
     @Override
     public void onCreate() {
-        HandlerThread thread = new HandlerThread("BugreportProgressServiceThread",
-                Process.THREAD_PRIORITY_BACKGROUND);
-        thread.start();
+        mContext = getApplicationContext();
+        mMainHandler = new ServiceHandler("BugreportProgressServiceMainThread");
+        mScreenshotHandler = new ScreenshotHandler("BugreportProgressServiceScreenshotThread");
 
-        mServiceLooper = thread.getLooper();
-        mServiceHandler = new ServiceHandler(mServiceLooper);
+        mScreenshotsDir = new File(new ContextWrapper(mContext).getFilesDir(), SCREENSHOT_DIR);
+        if (!mScreenshotsDir.exists()) {
+            Log.i(TAG, "Creating directory " + mScreenshotsDir + " to store temporary screenshots");
+            if (!mScreenshotsDir.mkdir()) {
+                Log.w(TAG, "Could not create directory " + mScreenshotsDir);
+            }
+        }
     }
 
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
         if (intent != null) {
             // Handle it in a separate thread.
-            Message msg = mServiceHandler.obtainMessage();
+            final Message msg = mMainHandler.obtainMessage();
             msg.what = MSG_SERVICE_COMMAND;
             msg.obj = intent;
-            mServiceHandler.sendMessage(msg);
+            mMainHandler.sendMessage(msg);
         }
 
         // If service is killed it cannot be recreated because it would not know which
@@ -167,29 +233,31 @@
 
     @Override
     public void onDestroy() {
-        mServiceLooper.quit();
+        mMainHandler.getLooper().quit();
+        mScreenshotHandler.getLooper().quit();
         super.onDestroy();
     }
 
     @Override
     protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
-        synchronized (mProcesses) {
-            final int size = mProcesses.size();
-            if (size == 0) {
-                writer.printf("No monitored processes");
-                return;
-            }
-            writer.printf("Monitored dumpstate processes\n");
-            writer.printf("-----------------------------\n");
-            for (int i = 0; i < size; i++) {
-              writer.printf("%s\n", mProcesses.valueAt(i));
-            }
+        final int size = mProcesses.size();
+        if (size == 0) {
+            writer.printf("No monitored processes");
+            return;
+        }
+        writer.printf("Monitored dumpstate processes\n");
+        writer.printf("-----------------------------\n");
+        for (int i = 0; i < size; i++) {
+            writer.printf("%s\n", mProcesses.valueAt(i));
         }
     }
 
+    /**
+     * Main thread used to handle all requests but taking screenshots.
+     */
     private final class ServiceHandler extends Handler {
-        public ServiceHandler(Looper looper) {
-            super(looper);
+        public ServiceHandler(String name) {
+            super(newLooper(name));
         }
 
         @Override
@@ -199,6 +267,16 @@
                 return;
             }
 
+            if (msg.what == MSG_DELAYED_SCREENSHOT) {
+                takeScreenshot(msg.arg1, msg.arg2);
+                return;
+            }
+
+            if (msg.what == MSG_SCREENSHOT_RESPONSE) {
+                handleScreenshotResponse(msg);
+                return;
+            }
+
             if (msg.what != MSG_SERVICE_COMMAND) {
                 // Sanity check.
                 Log.e(TAG, "Invalid message type: " + msg.what);
@@ -242,8 +320,14 @@
                     }
                     onBugreportFinished(pid, intent);
                     break;
+                case INTENT_BUGREPORT_INFO_LAUNCH:
+                    launchBugreportInfoDialog(pid);
+                    break;
+                case INTENT_BUGREPORT_SCREENSHOT:
+                    takeScreenshot(pid, true);
+                    break;
                 case INTENT_BUGREPORT_SHARE:
-                    shareBugreport(pid);
+                    shareBugreport(pid, (BugreportInfo) intent.getParcelableExtra(EXTRA_INFO));
                     break;
                 case INTENT_BUGREPORT_CANCEL:
                     cancel(pid);
@@ -266,6 +350,32 @@
     }
 
     /**
+     * Separate thread used only to take screenshots so it doesn't block the main thread.
+     */
+    private final class ScreenshotHandler extends Handler {
+        public ScreenshotHandler(String name) {
+            super(newLooper(name));
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what != MSG_SCREENSHOT_REQUEST) {
+                Log.e(TAG, "Invalid message type: " + msg.what);
+                return;
+            }
+            handleScreenshotRequest(msg);
+        }
+    }
+
+    private BugreportInfo getInfo(int pid) {
+        final BugreportInfo info = mProcesses.get(pid);
+        if (info == null) {
+            Log.w(TAG, "Not monitoring process with PID " + pid);
+        }
+        return info;
+    }
+
+    /**
      * Creates the {@link BugreportInfo} for a process and issue a system notification to
      * indicate its progress.
      *
@@ -284,14 +394,14 @@
             return false;
         }
 
-        final BugreportInfo info = new BugreportInfo(getApplicationContext(), pid, name, max);
-        synchronized (mProcesses) {
-            if (mProcesses.indexOfKey(pid) >= 0) {
-                Log.w(TAG, "PID " + pid + " already watched");
-            } else {
-                mProcesses.put(info.pid, info);
-            }
+        final BugreportInfo info = new BugreportInfo(mContext, pid, name, max);
+        if (mProcesses.indexOfKey(pid) >= 0) {
+            Log.w(TAG, "PID " + pid + " already watched");
+        } else {
+            mProcesses.put(info.pid, info);
         }
+        // Take initial screenshot.
+        takeScreenshot(pid, false);
         updateProgress(info);
         return true;
     }
@@ -305,19 +415,35 @@
             return;
         }
 
-        final Context context = getApplicationContext();
         final NumberFormat nf = NumberFormat.getPercentInstance();
         nf.setMinimumFractionDigits(2);
         nf.setMaximumFractionDigits(2);
         final String percentText = nf.format((double) info.progress / info.max);
-        final Action cancelAction = new Action.Builder(null, context.getString(
-                com.android.internal.R.string.cancel), newCancelIntent(context, info)).build();
+        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_PID, info.pid);
+        final Action infoAction = new Action.Builder(null,
+                mContext.getString(R.string.bugreport_info_action),
+                PendingIntent.getService(mContext, info.pid, infoIntent,
+                        PendingIntent.FLAG_UPDATE_CURRENT)).build();
+        final Intent screenshotIntent = new Intent(mContext, BugreportProgressService.class);
+        screenshotIntent.setAction(INTENT_BUGREPORT_SCREENSHOT);
+        screenshotIntent.putExtra(EXTRA_PID, info.pid);
+        PendingIntent screenshotPendingIntent = mTakingScreenshot ? null : PendingIntent
+                .getService(mContext, info.pid, screenshotIntent,
+                        PendingIntent.FLAG_UPDATE_CURRENT);
+        final Action screenshotAction = new Action.Builder(null,
+                mContext.getString(R.string.bugreport_screenshot_action),
+                screenshotPendingIntent).build();
 
-        final String title = context.getString(R.string.bugreport_in_progress_title);
+        final String title = mContext.getString(R.string.bugreport_in_progress_title);
+
         final String name =
-                info.name != null ? info.name : context.getString(R.string.bugreport_unnamed);
+                info.name != null ? info.name : mContext.getString(R.string.bugreport_unnamed);
 
-        final Notification notification = new Notification.Builder(context)
+        final Notification notification = new Notification.Builder(mContext)
                 .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
                 .setContentTitle(title)
                 .setTicker(title)
@@ -326,12 +452,20 @@
                 .setProgress(info.max, info.progress, false)
                 .setOngoing(true)
                 .setLocalOnly(true)
-                .setColor(context.getColor(
+                .setColor(mContext.getColor(
                         com.android.internal.R.color.system_notification_accent_color))
+                .addAction(infoAction)
+                .addAction(screenshotAction)
                 .addAction(cancelAction)
                 .build();
 
-        NotificationManager.from(context).notify(TAG, info.pid, notification);
+        if (info.finished) {
+            Log.w(TAG, "Not sending progress notification because bugreport has finished already ("
+                    + info + ")");
+            return;
+        }
+        Log.v(TAG, "Sending 'Progress' notification for pid " + info.pid + ": " + percentText);
+        NotificationManager.from(mContext).notify(TAG, info.pid, notification);
     }
 
     /**
@@ -341,31 +475,36 @@
         final Intent intent = new Intent(INTENT_BUGREPORT_CANCEL);
         intent.setClass(context, BugreportProgressService.class);
         intent.putExtra(EXTRA_PID, info.pid);
-        return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+        return PendingIntent.getService(context, info.pid, intent,
+                PendingIntent.FLAG_UPDATE_CURRENT);
     }
 
     /**
      * Finalizes the progress on a given bugreport and cancel its notification.
      */
     private void stopProgress(int pid) {
-        synchronized (mProcesses) {
-            if (mProcesses.indexOfKey(pid) < 0) {
-                Log.w(TAG, "PID not watched: " + pid);
-            } else {
-                mProcesses.remove(pid);
-            }
-            stopSelfWhenDone();
+        if (mProcesses.indexOfKey(pid) < 0) {
+            Log.w(TAG, "PID not watched: " + pid);
+        } else {
+            Log.d(TAG, "Removing PID " + pid);
+            mProcesses.remove(pid);
         }
-        if (DEBUG) Log.v(TAG, "stopProgress(" + pid + "): cancel notification");
-        NotificationManager.from(getApplicationContext()).cancel(TAG, pid);
+        stopSelfWhenDone();
+        Log.v(TAG, "stopProgress(" + pid + "): cancel notification");
+        NotificationManager.from(mContext).cancel(TAG, pid);
     }
 
     /**
      * Cancels a bugreport upon user's request.
      */
     private void cancel(int pid) {
-        Log.i(TAG, "Cancelling PID " + pid + " on user's request");
-        SystemProperties.set(CTL_STOP, BUGREPORT_SERVICE);
+        Log.v(TAG, "cancel: pid=" + pid);
+        final BugreportInfo info = getInfo(pid);
+        if (info != null && !info.finished) {
+            Log.i(TAG, "Cancelling bugreport service (pid=" + pid + ") on user's request");
+            setSystemProperty(CTL_STOP, BUGREPORT_SERVICE);
+            deleteScreenshots(info);
+        }
         stopProgress(pid);
     }
 
@@ -375,54 +514,193 @@
      * @return whether it should keep polling.
      */
     private boolean pollProgress() {
-        synchronized (mProcesses) {
-            final int total = mProcesses.size();
-            if (total == 0) {
-                Log.d(TAG, "No process to poll progress.");
+        final int total = mProcesses.size();
+        if (total == 0) {
+            Log.d(TAG, "No process to poll progress.");
+        }
+        int activeProcesses = 0;
+        for (int i = 0; i < total; i++) {
+            final int pid = mProcesses.keyAt(i);
+            final BugreportInfo info = mProcesses.valueAt(i);
+            if (info.finished) {
+                if (DEBUG) Log.v(TAG, "Skipping finished process " + pid);
+                continue;
             }
-            int activeProcesses = 0;
-            for (int i = 0; i < total; i++) {
-                final int pid = mProcesses.keyAt(i);
+            activeProcesses++;
+            final String progressKey = DUMPSTATE_PREFIX + pid + PROGRESS_SUFFIX;
+            final int progress = SystemProperties.getInt(progressKey, 0);
+            if (progress == 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;
+
+            if (progressChanged || maxChanged) {
+                if (progressChanged) {
+                    if (DEBUG) Log.v(TAG, "Updating progress for PID " + pid + " from "
+                            + info.progress + " to " + progress);
+                    info.progress = progress;
+                }
+                if (maxChanged) {
+                    Log.i(TAG, "Updating max progress for PID " + pid + " from " + info.max
+                            + " to " + max);
+                    info.max = max;
+                }
+                info.lastUpdate = System.currentTimeMillis();
+                updateProgress(info);
+            } else {
+                long inactiveTime = System.currentTimeMillis() - info.lastUpdate;
+                if (inactiveTime >= INACTIVITY_TIMEOUT) {
+                    Log.w(TAG, "No progress update for process " + pid + " since "
+                            + info.getFormattedLastUpdate());
+                    stopProgress(info.pid);
+                }
+            }
+        }
+        if (DEBUG) Log.v(TAG, "pollProgress() total=" + total + ", actives=" + activeProcesses);
+        return activeProcesses > 0;
+    }
+
+    /**
+     * Fetches a {@link BugreportInfo} for a given process and launches a dialog where the user can
+     * change its values.
+     */
+    private void launchBugreportInfoDialog(int pid) {
+        // Copy values so it doesn't lock mProcesses while UI is being updated
+        final String name, title, description;
+        final BugreportInfo info = getInfo(pid);
+        if (info == null) {
+            return;
+        }
+        name = info.name;
+        title = info.title;
+        description = info.description;
+
+        collapseNotificationBar();
+        mInfoDialog.initialize(mContext, pid, name, title, description);
+    }
+
+    /**
+     * Starting point for taking a screenshot.
+     * <p>
+     * If {@code delayed} is set, it first display a toast message and waits
+     * {@link #SCREENSHOT_DELAY_SECONDS} seconds before taking it, otherwise it takes the screenshot
+     * right away.
+     * <p>
+     * Typical usage is delaying when taken from the notification action, and taking it right away
+     * upon receiving a {@link #INTENT_BUGREPORT_STARTED}.
+     */
+    private void takeScreenshot(int pid, boolean delayed) {
+        setTakingScreenshot(true);
+        if (delayed) {
+            collapseNotificationBar();
+            final String msg = mContext.getResources()
+                    .getQuantityString(com.android.internal.R.plurals.bugreport_countdown,
+                            SCREENSHOT_DELAY_SECONDS, SCREENSHOT_DELAY_SECONDS);
+            Log.i(TAG, msg);
+            // Show a toast just once, otherwise it might be captured in the screenshot.
+            Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
+
+            takeScreenshot(pid, SCREENSHOT_DELAY_SECONDS);
+        } else {
+            takeScreenshot(pid, 0);
+        }
+    }
+
+    /**
+     * Takes a screenshot after {@code delay} seconds.
+     */
+    private void takeScreenshot(int pid, int delay) {
+        if (delay > 0) {
+            Log.d(TAG, "Taking screenshot for " + pid + " in " + delay + " seconds");
+            final Message msg = mMainHandler.obtainMessage();
+            msg.what = MSG_DELAYED_SCREENSHOT;
+            msg.arg1 = pid;
+            msg.arg2 = delay - 1;
+            mMainHandler.sendMessageDelayed(msg, DateUtils.SECOND_IN_MILLIS);
+            return;
+        }
+
+        // It's time to take the screenshot: let the proper thread handle it
+        final BugreportInfo info = getInfo(pid);
+        if (info == null) {
+            return;
+        }
+        final String screenshotPath =
+                new File(mScreenshotsDir, info.getPathNextScreenshot()).getAbsolutePath();
+
+        final Message requestMsg = new Message();
+        requestMsg.what = MSG_SCREENSHOT_REQUEST;
+        requestMsg.arg1 = pid;
+        requestMsg.obj = screenshotPath;
+        mScreenshotHandler.sendMessage(requestMsg);
+    }
+
+    /**
+     * Sets the internal {@code mTakingScreenshot} state and updates all notifications so their
+     * SCREENSHOT button is enabled or disabled accordingly.
+     */
+    private void setTakingScreenshot(boolean flag) {
+        synchronized (BugreportProgressService.this) {
+            mTakingScreenshot = flag;
+            for (int i = 0; i < mProcesses.size(); i++) {
                 final BugreportInfo info = mProcesses.valueAt(i);
                 if (info.finished) {
-                    if (DEBUG) Log.v(TAG, "Skipping finished process " + pid);
+                    Log.d(TAG, "Not updating progress because share notification was already sent");
                     continue;
                 }
-                activeProcesses++;
-                final String progressKey = DUMPSTATE_PREFIX + pid + PROGRESS_SUFFIX;
-                final int progress = SystemProperties.getInt(progressKey, 0);
-                if (progress == 0) {
-                    Log.v(TAG, "System property " + progressKey + " is not set yet");
-                    continue;
-                }
-                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;
-
-                if (progressChanged || maxChanged) {
-                    if (progressChanged) {
-                        if (DEBUG) Log.v(TAG, "Updating progress for PID " + pid + " from "
-                                + info.progress + " to " + progress);
-                        info.progress = progress;
-                    }
-                    if (maxChanged) {
-                        Log.i(TAG, "Updating max progress for PID " + pid + " from " + info.max
-                                + " to " + max);
-                        info.max = max;
-                    }
-                    info.lastUpdate = System.currentTimeMillis();
-                    updateProgress(info);
-                } else {
-                    long inactiveTime = System.currentTimeMillis() - info.lastUpdate;
-                    if (inactiveTime >= INACTIVITY_TIMEOUT) {
-                        Log.w(TAG, "No progress update for process " + pid + " since "
-                                + info.getFormattedLastUpdate());
-                        stopProgress(info.pid);
-                    }
-                }
+                updateProgress(info);
             }
-            if (DEBUG) Log.v(TAG, "pollProgress() total=" + total + ", actives=" + activeProcesses);
-            return activeProcesses > 0;
+        }
+    }
+
+    private void handleScreenshotRequest(Message requestMsg) {
+        String screenshotFile = (String) requestMsg.obj;
+        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);
+    }
+
+    private void handleScreenshotResponse(Message resultMsg) {
+        final boolean taken = resultMsg.arg2 != 0;
+        final BugreportInfo info = getInfo(resultMsg.arg1);
+        if (info == null) {
+            return;
+        }
+        final File screenshotFile = new File((String) resultMsg.obj);
+
+        final int msgId;
+        if (taken) {
+            info.addScreenshot(screenshotFile);
+            if (info.finished) {
+                Log.d(TAG, "Screenshot finished after bugreport; updating share notification");
+                info.renameScreenshots(mScreenshotsDir);
+                sendBugreportNotification(mContext, info);
+            }
+            msgId = R.string.bugreport_screenshot_taken;
+        } else {
+            // TODO: try again using Framework APIs instead of relying on screencap.
+            msgId = R.string.bugreport_screenshot_failed;
+        }
+        final String msg = mContext.getString(msgId);
+        Log.d(TAG, msg);
+        Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
+    }
+
+    /**
+     * Deletes all screenshots taken for a given bugreport.
+     */
+    private void deleteScreenshots(BugreportInfo info) {
+        for (File file : info.screenshotFiles) {
+            Log.i(TAG, "Deleting screenshot file " + file);
+            file.delete();
         }
     }
 
@@ -430,34 +708,37 @@
      * Finishes the service when it's not monitoring any more processes.
      */
     private void stopSelfWhenDone() {
-        synchronized (mProcesses) {
-            if (mProcesses.size() > 0) {
-                if (DEBUG) Log.v(TAG, "Staying alive, waiting for pids " + mProcesses);
-                return;
-            }
-            Log.v(TAG, "No more pids to handle, shutting down");
-            stopSelf();
+        if (mProcesses.size() > 0) {
+            if (DEBUG) Log.v(TAG, "Staying alive, waiting for pids " + mProcesses);
+            return;
         }
+        Log.v(TAG, "No more pids to handle, shutting down");
+        stopSelf();
     }
 
+    /**
+     * Handles the BUGREPORT_FINISHED intent sent by {@code dumpstate}.
+     */
     private void onBugreportFinished(int pid, Intent intent) {
-        final Context context = getApplicationContext();
-        BugreportInfo info;
-        synchronized (mProcesses) {
-            info = mProcesses.get(pid);
-            if (info == null) {
-                // Happens when BUGREPORT_FINISHED was received without a BUGREPORT_STARTED
-                Log.v(TAG, "Creating info for untracked pid " + pid);
-                info = new BugreportInfo(context, pid);
-                mProcesses.put(pid, info);
-            }
-            info.bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT);
-            info.screenshotFile = getFileExtra(intent, EXTRA_SCREENSHOT);
+        mInfoDialog.onBugreportFinished(pid);
+        BugreportInfo info = getInfo(pid);
+        if (info == null) {
+            // Happens when BUGREPORT_FINISHED was received without a BUGREPORT_STARTED first.
+            Log.v(TAG, "Creating info for untracked pid " + pid);
+            info = new BugreportInfo(mContext, pid);
+            mProcesses.put(pid, info);
         }
+        info.renameScreenshots(mScreenshotsDir);
+        info.bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT);
+        final File screenshot = getFileExtra(intent, EXTRA_SCREENSHOT);
+        if (screenshot != null) {
+            info.addScreenshot(screenshot);
+        }
+        info.finished = true;
 
-        final Configuration conf = context.getResources().getConfiguration();
+        final Configuration conf = mContext.getResources().getConfiguration();
         if ((conf.uiMode & Configuration.UI_MODE_TYPE_MASK) != Configuration.UI_MODE_TYPE_WATCH) {
-            triggerLocalNotification(context, info);
+            triggerLocalNotification(mContext, info);
         }
     }
 
@@ -467,11 +748,11 @@
      * (usually by triggering it on another connected device); we don't need to display the
      * notification in this case.
      */
-    private static void triggerLocalNotification(final Context context, final BugreportInfo info) {
+    private void triggerLocalNotification(final Context context, final BugreportInfo info) {
         if (!info.bugreportFile.exists() || !info.bugreportFile.canRead()) {
             Log.e(TAG, "Could not read bugreport file " + info.bugreportFile);
-            Toast.makeText(context, context.getString(R.string.bugreport_unreadable_text),
-                    Toast.LENGTH_LONG).show();
+            Toast.makeText(context, R.string.bugreport_unreadable_text, Toast.LENGTH_LONG).show();
+            stopProgress(info.pid);
             return;
         }
 
@@ -494,25 +775,36 @@
     /**
      * Build {@link Intent} that can be used to share the given bugreport.
      */
-    private static Intent buildSendIntent(Context context, Uri bugreportUri, Uri screenshotUri) {
+    private static Intent buildSendIntent(Context context, BugreportInfo info) {
+        // Files are kept on private storage, so turn into Uris that we can
+        // grant temporary permissions for.
+        final Uri bugreportUri = getUri(context, info.bugreportFile);
+
         final Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
         final String mimeType = "application/vnd.android.bugreport";
         intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
         intent.addCategory(Intent.CATEGORY_DEFAULT);
         intent.setType(mimeType);
 
-        intent.putExtra(Intent.EXTRA_SUBJECT, bugreportUri.getLastPathSegment());
+        final String subject = info.title != null ? info.title : bugreportUri.getLastPathSegment();
+        intent.putExtra(Intent.EXTRA_SUBJECT, subject);
 
         // EXTRA_TEXT should be an ArrayList, but some clients are expecting a single String.
         // So, to avoid an exception on Intent.migrateExtraStreamToClipData(), we need to manually
         // create the ClipData object with the attachments URIs.
-        String messageBody = String.format("Build info: %s\nSerial number:%s",
-                SystemProperties.get("ro.build.description"), SystemProperties.get("ro.serialno"));
-        intent.putExtra(Intent.EXTRA_TEXT, messageBody);
+        final StringBuilder messageBody = new StringBuilder("Build info: ")
+            .append(SystemProperties.get("ro.build.description"))
+            .append("\nSerial number: ")
+            .append(SystemProperties.get("ro.serialno"));
+        if (!TextUtils.isEmpty(info.description)) {
+            messageBody.append("\nDescription: ").append(info.description);
+        }
+        intent.putExtra(Intent.EXTRA_TEXT, messageBody.toString());
         final ClipData clipData = new ClipData(null, new String[] { mimeType },
                 new ClipData.Item(null, null, null, bugreportUri));
         final ArrayList<Uri> attachments = Lists.newArrayList(bugreportUri);
-        if (screenshotUri != null) {
+        for (File screenshot : info.screenshotFiles) {
+            final Uri screenshotUri = getUri(context, screenshot);
             clipData.addItem(new ClipData.Item(null, null, null, screenshotUri));
             attachments.add(screenshotUri);
         }
@@ -531,48 +823,44 @@
      * Shares the bugreport upon user's request by issuing a {@link Intent#ACTION_SEND_MULTIPLE}
      * intent, but issuing a warning dialog the first time.
      */
-    private void shareBugreport(int pid) {
-        final Context context = getApplicationContext();
-        final BugreportInfo info;
-        synchronized (mProcesses) {
-            info = mProcesses.get(pid);
-            if (info == null) {
-                // Should not happen, so log if it does...
-                Log.e(TAG, "INTERNAL ERROR: no info for PID " + pid + ": " + mProcesses);
-                return;
-            }
+    private void shareBugreport(int pid, BugreportInfo sharedInfo) {
+        BugreportInfo info = getInfo(pid);
+        if (info == null) {
+            // Service was terminated but notification persisted
+            info = sharedInfo;
+            Log.d(TAG, "shareBugreport(): no info for PID " + pid + " on managed processes ("
+                    + mProcesses + "), using info from intent instead (" + info + ")");
         }
-        // Files are kept on private storage, so turn into Uris that we can
-        // grant temporary permissions for.
-        final Uri bugreportUri = getUri(context, info.bugreportFile);
-        final Uri screenshotUri = getUri(context, info.screenshotFile);
 
-        final Intent sendIntent = buildSendIntent(context, bugreportUri, screenshotUri);
+        addDetailsToZipFile(info);
+
+        final Intent sendIntent = buildSendIntent(mContext, info);
         final Intent notifIntent;
 
         // Send through warning dialog by default
-        if (getWarningState(context, STATE_SHOW) == STATE_SHOW) {
-            notifIntent = buildWarningIntent(context, sendIntent);
+        if (getWarningState(mContext, STATE_SHOW) == STATE_SHOW) {
+            notifIntent = buildWarningIntent(mContext, sendIntent);
         } else {
             notifIntent = sendIntent;
         }
         notifIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
         // Send the share intent...
-        context.startActivity(notifIntent);
+        mContext.startActivity(notifIntent);
 
         // ... and stop watching this process.
         stopProgress(pid);
     }
 
     /**
-     * Sends a notitication indicating the bugreport has finished so use can share it.
+     * Sends a notification indicating the bugreport has finished so use can share it.
      */
     private static void sendBugreportNotification(Context context, BugreportInfo info) {
         final Intent shareIntent = new Intent(INTENT_BUGREPORT_SHARE);
         shareIntent.setClass(context, BugreportProgressService.class);
         shareIntent.setAction(INTENT_BUGREPORT_SHARE);
         shareIntent.putExtra(EXTRA_PID, info.pid);
+        shareIntent.putExtra(EXTRA_INFO, info);
 
         final String title = context.getString(R.string.bugreport_finished_title);
         final Notification.Builder builder = new Notification.Builder(context)
@@ -580,17 +868,41 @@
                 .setContentTitle(title)
                 .setTicker(title)
                 .setContentText(context.getString(R.string.bugreport_finished_text))
-                .setContentIntent(PendingIntent.getService(context, 0, shareIntent,
-                        PendingIntent.FLAG_CANCEL_CURRENT))
+                .setContentIntent(PendingIntent.getService(context, info.pid, shareIntent,
+                        PendingIntent.FLAG_UPDATE_CURRENT))
                 .setDeleteIntent(newCancelIntent(context, info))
                 .setLocalOnly(true)
                 .setColor(context.getColor(
                         com.android.internal.R.color.system_notification_accent_color));
 
+        if (!TextUtils.isEmpty(info.name)) {
+            builder.setContentInfo(info.name);
+        }
+
+        Log.v(TAG, "Sending 'Share' notification for pid " + info.pid + ": " + title);
         NotificationManager.from(context).notify(TAG, info.pid, builder.build());
     }
 
     /**
+     * Sends a notification indicating the bugreport is being updated so the user can wait until it
+     * finishes - at this point there is nothing to be done other than waiting, hence it has no
+     * pending action.
+     */
+    private static void sendBugreportBeingUpdatedNotification(Context context, int pid) {
+        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)
+                .setContentTitle(title)
+                .setTicker(title)
+                .setContentText(context.getString(R.string.bugreport_updating_wait))
+                .setLocalOnly(true)
+                .setColor(context.getColor(
+                        com.android.internal.R.color.system_notification_accent_color));
+        Log.v(TAG, "Sending 'Updating zip' notification for pid " + pid + ": " + title);
+        NotificationManager.from(context).notify(TAG, pid, builder.build());
+    }
+
+    /**
      * Sends a zipped bugreport notification.
      */
     private static void sendZippedBugreportNotification(final Context context,
@@ -598,7 +910,7 @@
         new AsyncTask<Void, Void, Void>() {
             @Override
             protected Void doInBackground(Void... params) {
-                info.bugreportFile = zipBugreport(info.bugreportFile);
+                zipBugreport(info);
                 sendBugreportNotification(context, info);
                 return null;
             }
@@ -609,35 +921,103 @@
      * Zips a bugreport file, returning the path to the new file (or to the
      * original in case of failure).
      */
-    private static File zipBugreport(File bugreportFile) {
-        String bugreportPath = bugreportFile.getAbsolutePath();
-        String zippedPath = bugreportPath.replace(".txt", ".zip");
+    private static void zipBugreport(BugreportInfo info) {
+        final String bugreportPath = info.bugreportFile.getAbsolutePath();
+        final String zippedPath = bugreportPath.replace(".txt", ".zip");
         Log.v(TAG, "zipping " + bugreportPath + " as " + zippedPath);
-        File bugreportZippedFile = new File(zippedPath);
-        try (InputStream is = new FileInputStream(bugreportFile);
+        final File bugreportZippedFile = new File(zippedPath);
+        try (InputStream is = new FileInputStream(info.bugreportFile);
                 ZipOutputStream zos = new ZipOutputStream(
                         new BufferedOutputStream(new FileOutputStream(bugreportZippedFile)))) {
-            ZipEntry entry = new ZipEntry(bugreportFile.getName());
-            entry.setTime(bugreportFile.lastModified());
-            zos.putNextEntry(entry);
-            int totalBytes = Streams.copy(is, zos);
-            Log.v(TAG, "size of original bugreport: " + totalBytes + " bytes");
-            zos.closeEntry();
-            // Delete old file;
-            boolean deleted = bugreportFile.delete();
+            addEntry(zos, info.bugreportFile.getName(), is);
+            // Delete old file
+            final boolean deleted = info.bugreportFile.delete();
             if (deleted) {
                 Log.v(TAG, "deleted original bugreport (" + bugreportPath + ")");
             } else {
                 Log.e(TAG, "could not delete original bugreport (" + bugreportPath + ")");
             }
-            return bugreportZippedFile;
+            info.bugreportFile = bugreportZippedFile;
         } catch (IOException e) {
             Log.e(TAG, "exception zipping file " + zippedPath, e);
-            return bugreportFile; // Return original.
         }
     }
 
     /**
+     * Adds the user-provided info into the bugreport zip file.
+     * <p>
+     * If user provided a title, it will be saved into a {@code title.txt} entry; similarly, the
+     * description will be saved on {@code description.txt}.
+     */
+    private void addDetailsToZipFile(BugreportInfo info) {
+        if (info.bugreportFile == null) {
+            // One possible reason is a bug in the Parcelization code.
+            Log.e(TAG, "INTERNAL ERROR: no bugreportFile on " + info);
+            return;
+        }
+        if (TextUtils.isEmpty(info.title) && TextUtils.isEmpty(info.description)) {
+            Log.d(TAG, "Not touching zip file since neither title nor description are set");
+            return;
+        }
+
+        // It's not possible to add a new entry into an existing file, so we need to create a new
+        // zip, copy all entries, then rename it.
+        sendBugreportBeingUpdatedNotification(mContext, info.pid); // ...and that takes time
+        final File dir = info.bugreportFile.getParentFile();
+        final File tmpZip = new File(dir, "tmp-" + info.bugreportFile.getName());
+        Log.d(TAG, "Writing temporary zip file (" + tmpZip + ") with title and/or description");
+        try (ZipFile oldZip = new ZipFile(info.bugreportFile);
+                ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(tmpZip))) {
+
+            // First copy contents from original zip.
+            Enumeration<? extends ZipEntry> entries = oldZip.entries();
+            while (entries.hasMoreElements()) {
+                final ZipEntry entry = entries.nextElement();
+                final String entryName = entry.getName();
+                if (!entry.isDirectory()) {
+                    addEntry(zos, entryName, entry.getTime(), oldZip.getInputStream(entry));
+                } else {
+                    Log.w(TAG, "skipping directory entry: " + entryName);
+                }
+            }
+
+            // Then add the user-provided info.
+            addEntry(zos, "title.txt", info.title);
+            addEntry(zos, "description.txt", info.description);
+        } catch (IOException e) {
+            Log.e(TAG, "exception zipping file " + tmpZip, e);
+            return;
+        }
+
+        if (!tmpZip.renameTo(info.bugreportFile)) {
+            Log.e(TAG, "Could not rename " + tmpZip + " to " + info.bugreportFile);
+        }
+    }
+
+    private static void addEntry(ZipOutputStream zos, String entry, String text)
+            throws IOException {
+        if (DEBUG) Log.v(TAG, "adding entry '" + entry + "': " + text);
+        if (!TextUtils.isEmpty(text)) {
+            addEntry(zos, entry, new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)));
+        }
+    }
+
+    private static void addEntry(ZipOutputStream zos, String entryName, InputStream is)
+            throws IOException {
+        addEntry(zos, entryName, System.currentTimeMillis(), is);
+    }
+
+    private static void addEntry(ZipOutputStream zos, String entryName, long timestamp,
+            InputStream is) throws IOException {
+        final ZipEntry entry = new ZipEntry(entryName);
+        entry.setTime(timestamp);
+        zos.putNextEntry(entry);
+        final int totalBytes = Streams.copy(is, zos);
+        if (DEBUG) Log.v(TAG, "size of '" + entryName + "' entry: " + totalBytes + " bytes");
+        zos.closeEntry();
+    }
+
+    /**
      * Find the best matching {@link Account} based on build properties.
      */
     private static Account findSendToAccount(Context context) {
@@ -671,7 +1051,7 @@
         return foundAccount;
     }
 
-    private static Uri getUri(Context context, File file) {
+    static Uri getUri(Context context, File file) {
         return file != null ? FileProvider.getUriForFile(context, AUTHORITY, file) : null;
     }
 
@@ -684,10 +1064,266 @@
         }
     }
 
+    private static boolean setSystemProperty(String key, String value) {
+        try {
+            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);
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Updates the system property used by {@code dumpstate} to rename the final bugreport files.
+     */
+    private boolean setBugreportNameProperty(int pid, String name) {
+        Log.d(TAG, "Updating bugreport name to " + name);
+        final String key = DUMPSTATE_PREFIX + pid + NAME_SUFFIX;
+        return setSystemProperty(key, name);
+    }
+
+    /**
+     * Updates the user-provided details of a bugreport.
+     */
+    private void updateBugreportInfo(int pid, String name, String title, String description) {
+        final BugreportInfo info = getInfo(pid);
+        if (info == null) {
+            return;
+        }
+        info.title = title;
+        info.description = description;
+        if (name != null && !info.name.equals(name)) {
+            info.name = name;
+            updateProgress(info);
+        }
+    }
+
+    private void collapseNotificationBar() {
+        sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+    }
+
+    private static Looper newLooper(String name) {
+        final HandlerThread thread = new HandlerThread(name, THREAD_PRIORITY_BACKGROUND);
+        thread.start();
+        return thread.getLooper();
+    }
+
+    /**
+     * 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) {
+                return true;
+            }
+            Log.e(TAG, "screencap (" + screencap.command() + ") failed: " + exitValue);
+        } catch (IOException e) {
+            Log.e(TAG, "screencap (" + screencap.command() + ") failed", e);
+        } catch (InterruptedException e) {
+            Log.w(TAG, "Thread interrupted while screencap still running");
+            Thread.currentThread().interrupt();
+        }
+        return false;
+    }
+
+    /**
+     * Checks whether a character is valid on bugreport names.
+     */
+    @VisibleForTesting
+    static boolean isValid(char c) {
+        return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')
+                || c == '_' || c == '-';
+    }
+
+    /**
+     * Helper class encapsulating the UI elements and logic used to display a dialog where user
+     * can change the details of a bugreport.
+     */
+    private final class BugreportInfoDialog {
+        private EditText mInfoName;
+        private EditText mInfoTitle;
+        private EditText mInfoDescription;
+        private AlertDialog mDialog;
+        private Button mOkButton;
+        private int mPid;
+
+        /**
+         * Last "committed" value of the bugreport name.
+         * <p>
+         * Once initially set, it's only updated when user clicks the OK button.
+         */
+        private String mSavedName;
+
+        /**
+         * Last value of the bugreport name as entered by the user.
+         * <p>
+         * Every time it's changed the equivalent system property is changed as well, but if the
+         * user clicks CANCEL, the old value (stored on {@code mSavedName} is restored.
+         * <p>
+         * This logic handles the corner-case scenario where {@code dumpstate} finishes after the
+         * user changed the name but didn't clicked OK yet (for example, because the user is typing
+         * the description). The only drawback is that if the user changes the name while
+         * {@code dumpstate} is running but clicks CANCEL after it finishes, then the final name
+         * will be the one that has been canceled. But when {@code dumpstate} finishes the {code
+         * name} UI is disabled and the old name restored anyways, so the user will be "alerted" of
+         * such drawback.
+         */
+        private String mTempName;
+
+        /**
+         * Sets its internal state and displays the dialog.
+         */
+        private void initialize(Context context, int pid, String name, String title,
+                String description) {
+            // First initializes singleton.
+            if (mDialog == null) {
+                @SuppressLint("InflateParams")
+                // It's ok pass null ViewRoot on AlertDialogs.
+                final View view = View.inflate(context, R.layout.dialog_bugreport_info, null);
+
+                mInfoName = (EditText) view.findViewById(R.id.name);
+                mInfoTitle = (EditText) view.findViewById(R.id.title);
+                mInfoDescription = (EditText) view.findViewById(R.id.description);
+
+                mInfoName.setOnFocusChangeListener(new OnFocusChangeListener() {
+
+                    @Override
+                    public void onFocusChange(View v, boolean hasFocus) {
+                        if (hasFocus) {
+                            return;
+                        }
+                        sanitizeName();
+                    }
+                });
+
+                mDialog = new AlertDialog.Builder(context)
+                        .setView(view)
+                        .setTitle(context.getString(R.string.bugreport_info_dialog_title))
+                        .setCancelable(false)
+                        .setPositiveButton(context.getString(com.android.internal.R.string.ok),
+                                null)
+                        .setNegativeButton(context.getString(com.android.internal.R.string.cancel),
+                                new DialogInterface.OnClickListener()
+                                {
+                                    @Override
+                                    public void onClick(DialogInterface dialog, int id)
+                                    {
+                                        if (!mTempName.equals(mSavedName)) {
+                                            // Must restore dumpstate's name since it was changed
+                                            // before user clicked OK.
+                                            setBugreportNameProperty(mPid, mSavedName);
+                                        }
+                                    }
+                                })
+                        .create();
+
+                mDialog.getWindow().setAttributes(
+                        new WindowManager.LayoutParams(
+                                WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG));
+
+            }
+
+            // Then set fields.
+            mSavedName = mTempName = name;
+            mPid = pid;
+            if (!TextUtils.isEmpty(name)) {
+                mInfoName.setText(name);
+            }
+            if (!TextUtils.isEmpty(title)) {
+                mInfoTitle.setText(title);
+            }
+            if (!TextUtils.isEmpty(description)) {
+                mInfoDescription.setText(description);
+            }
+
+            // And finally display it.
+            mDialog.show();
+
+            // TODO: in a traditional AlertDialog, when the positive button is clicked the
+            // dialog is always closed, but we need to validate the name first, so we need to
+            // get a reference to it, which is only available after it's displayed.
+            // It would be cleaner to use a regular dialog instead, but let's keep this
+            // workaround for now and change it later, when we add another button to take
+            // extra screenshots.
+            if (mOkButton == null) {
+                mOkButton = mDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+                mOkButton.setOnClickListener(new View.OnClickListener() {
+
+                    @Override
+                    public void onClick(View view) {
+                        sanitizeName();
+                        final String name = mInfoName.getText().toString();
+                        final String title = mInfoTitle.getText().toString();
+                        final String description = mInfoDescription.getText().toString();
+
+                        updateBugreportInfo(mPid, name, title, description);
+                        mDialog.dismiss();
+                    }
+                });
+            }
+        }
+
+        /**
+         * Sanitizes the user-provided value for the {@code name} field, automatically replacing
+         * invalid characters if necessary.
+         */
+        private void sanitizeName() {
+            String name = mInfoName.getText().toString();
+            if (name.equals(mTempName)) {
+                if (DEBUG) Log.v(TAG, "name didn't change, no need to sanitize: " + name);
+                return;
+            }
+            final StringBuilder safeName = new StringBuilder(name.length());
+            boolean changed = false;
+            for (int i = 0; i < name.length(); i++) {
+                final char c = name.charAt(i);
+                if (isValid(c)) {
+                    safeName.append(c);
+                } else {
+                    changed = true;
+                    safeName.append('_');
+                }
+            }
+            if (changed) {
+                Log.v(TAG, "changed invalid name '" + name + "' to '" + safeName + "'");
+                name = safeName.toString();
+                mInfoName.setText(name);
+            }
+            mTempName = name;
+
+            // Must update system property for the cases where dumpstate finishes
+            // while the user is still entering other fields (like title or
+            // description)
+            setBugreportNameProperty(mPid, name);
+        }
+
+       /**
+         * Notifies the dialog that the bugreport has finished so it disables the {@code name}
+         * field.
+         * <p>Once the bugreport is finished dumpstate has already generated the final files, so
+         * changing the name would have no effect.
+         */
+        private void onBugreportFinished(int pid) {
+            if (mInfoName != null) {
+                mInfoName.setEnabled(false);
+                mInfoName.setText(mSavedName);
+            }
+        }
+
+    }
+
     /**
      * Information about a bugreport process while its in progress.
      */
-    private static final class BugreportInfo {
+    private static final class BugreportInfo implements Parcelable {
         private final Context context;
 
         /**
@@ -704,6 +1340,18 @@
         String name;
 
         /**
+         * User-provided, one-line summary of the bug; when set, will be used as the subject
+         * of the {@link Intent#ACTION_SEND_MULTIPLE} intent.
+         */
+        String title;
+
+        /**
+         * User-provided, detailed description of the bugreport; when set, will be added to the body
+         * of the {@link Intent#ACTION_SEND_MULTIPLE} intent.
+         */
+        String description;
+
+        /**
          * Maximum progress of the bugreport generation.
          */
         int max;
@@ -719,14 +1367,19 @@
         long lastUpdate = System.currentTimeMillis();
 
         /**
+         * Time of the last progress update when Parcel was created.
+         */
+        String formattedLastUpdate;
+
+        /**
          * Path of the main bugreport file.
          */
         File bugreportFile;
 
         /**
-         * Path of the screenshot file.
+         * Path of the screenshot files.
          */
-        File screenshotFile;
+        List<File> screenshotFiles = new ArrayList<>(1);
 
         /**
          * Whether dumpstate sent an intent informing it has finished.
@@ -734,6 +1387,11 @@
         boolean finished;
 
         /**
+         * Internal counter used to name screenshot files.
+         */
+        int screenshotCounter;
+
+        /**
          * Constructor for tracked bugreports - typically called upon receiving BUGREPORT_STARTED.
          */
         BugreportInfo(Context context, int pid, String name, int max) {
@@ -752,7 +1410,51 @@
             this.finished = true;
         }
 
+        /**
+         * Gets the name for next screenshot file.
+         */
+        String getPathNextScreenshot() {
+            screenshotCounter ++;
+            return "screenshot-" + pid + "-" + screenshotCounter + ".png";
+        }
+
+        /**
+         * Saves the location of a taken screenshot so it can be sent out at the end.
+         */
+        void addScreenshot(File screenshot) {
+            screenshotFiles.add(screenshot);
+        }
+
+        /**
+         * Rename all screenshots files so that they contain the user-generated name instead of pid.
+         */
+        void renameScreenshots(File screenshotDir) {
+            if (TextUtils.isEmpty(name)) {
+                return;
+            }
+            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 File newFile;
+                if (!newName.equals(oldName)) {
+                    final File renamedFile = new File(screenshotDir, newName);
+                    newFile = oldFile.renameTo(renamedFile) ? renamedFile : oldFile;
+                } else {
+                    Log.w(TAG, "Name didn't change: " + oldName); // Shouldn't happen.
+                    newFile = oldFile;
+                }
+                renamedFiles.add(newFile);
+            }
+            screenshotFiles = renamedFiles;
+        }
+
         String getFormattedLastUpdate() {
+            if (context == null) {
+                // Restored from Parcel
+                return formattedLastUpdate == null ?
+                        Long.toString(lastUpdate) : formattedLastUpdate;
+            }
             return DateUtils.formatDateTime(context, lastUpdate,
                     DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME);
         }
@@ -761,9 +1463,79 @@
         public String toString() {
             final float percent = ((float) progress * 100 / max);
             return "pid: " + pid + ", name: " + name + ", finished: " + finished
-                    + "\n\tfile: " + bugreportFile + "\n\tscreenshot: " + screenshotFile
+                    + "\n\ttitle: " + title + "\n\tdescription: " + description
+                    + "\n\tfile: " + bugreportFile + "\n\tscreenshots: " + screenshotFiles
                     + "\n\tprogress: " + progress + "/" + max + "(" + percent + ")"
                     + "\n\tlast_update: " + getFormattedLastUpdate();
         }
+
+        // Parcelable contract
+        protected BugreportInfo(Parcel in) {
+            context = null;
+            pid = in.readInt();
+            name = in.readString();
+            title = in.readString();
+            description = in.readString();
+            max = in.readInt();
+            progress = in.readInt();
+            lastUpdate = in.readLong();
+            formattedLastUpdate = in.readString();
+            bugreportFile = readFile(in);
+
+            int screenshotSize = in.readInt();
+            for (int i = 1; i <= screenshotSize; i++) {
+                  screenshotFiles.add(readFile(in));
+            }
+
+            finished = in.readInt() == 1;
+            screenshotCounter = in.readInt();
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(pid);
+            dest.writeString(name);
+            dest.writeString(title);
+            dest.writeString(description);
+            dest.writeInt(max);
+            dest.writeInt(progress);
+            dest.writeLong(lastUpdate);
+            dest.writeString(getFormattedLastUpdate());
+            writeFile(dest, bugreportFile);
+
+            dest.writeInt(screenshotFiles.size());
+            for (File screenshotFile : screenshotFiles) {
+                writeFile(dest, screenshotFile);
+            }
+
+            dest.writeInt(finished ? 1 : 0);
+            dest.writeInt(screenshotCounter);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        private void writeFile(Parcel dest, File file) {
+            dest.writeString(file == null ? null : file.getPath());
+        }
+
+        private File readFile(Parcel in) {
+            final String path = in.readString();
+            return path == null ? null : new File(path);
+        }
+
+        public static final Parcelable.Creator<BugreportInfo> CREATOR =
+                new Parcelable.Creator<BugreportInfo>() {
+            public BugreportInfo createFromParcel(Parcel source) {
+                return new BugreportInfo(source);
+            }
+
+            public BugreportInfo[] newArray(int size) {
+                return new BugreportInfo[size];
+            }
+        };
+
     }
 }
diff --git a/packages/Shell/src/com/android/shell/BugreportReceiver.java b/packages/Shell/src/com/android/shell/BugreportReceiver.java
index b818343..9afa900 100644
--- a/packages/Shell/src/com/android/shell/BugreportReceiver.java
+++ b/packages/Shell/src/com/android/shell/BugreportReceiver.java
@@ -19,7 +19,6 @@
 import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT;
 import static com.android.shell.BugreportProgressService.EXTRA_ORIGINAL_INTENT;
 import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_FINISHED;
-import static com.android.shell.BugreportProgressService.TAG;
 import static com.android.shell.BugreportProgressService.getFileExtra;
 
 import java.io.File;
@@ -37,6 +36,7 @@
  * {@link Intent#ACTION_SEND_MULTIPLE}.
  */
 public class BugreportReceiver extends BroadcastReceiver {
+    private static final String TAG = "BugreportReceiver";
 
     /**
      * Always keep the newest 8 bugreport files; 4 reports and 4 screenshots are
@@ -52,7 +52,7 @@
     @Override
     public void onReceive(Context context, Intent intent) {
         // Clean up older bugreports in background
-        cleanupOldFiles(intent);
+        cleanupOldFiles(this, intent, INTENT_BUGREPORT_FINISHED, MIN_KEEP_COUNT, MIN_KEEP_AGE);
 
         // Delegate intent handling to service.
         Intent serviceIntent = new Intent(context, BugreportProgressService.class);
@@ -60,8 +60,9 @@
         context.startService(serviceIntent);
     }
 
-    private void cleanupOldFiles(Intent intent) {
-        if (!INTENT_BUGREPORT_FINISHED.equals(intent.getAction())) {
+    static void cleanupOldFiles(BroadcastReceiver br, Intent intent, String expectedAction,
+            final int minCount, final long minAge) {
+        if (!expectedAction.equals(intent.getAction())) {
             return;
         }
         final File bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT);
@@ -69,12 +70,15 @@
             Log.e(TAG, "Not deleting old files because file " + bugreportFile + " doesn't exist");
             return;
         }
-        final PendingResult result = goAsync();
+        final PendingResult result = br.goAsync();
         new AsyncTask<Void, Void, Void>() {
             @Override
             protected Void doInBackground(Void... params) {
-                FileUtils.deleteOlderFiles(
-                        bugreportFile.getParentFile(), MIN_KEEP_COUNT, MIN_KEEP_AGE);
+                try {
+                    FileUtils.deleteOlderFiles(bugreportFile.getParentFile(), minCount, minAge);
+                } catch (RuntimeException e) {
+                    Log.e(TAG, "RuntimeException deleting old files", e);
+                }
                 result.finish();
                 return null;
             }
diff --git a/packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java b/packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java
new file mode 100644
index 0000000..6f783a1
--- /dev/null
+++ b/packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.shell;
+
+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.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.UserHandle;
+
+/**
+ * Receiver that handles finished remote bugreports, by re-sending
+ * the intent with appended bugreport zip file URI.
+ *
+ * <p> Remote bugreport never contains a screenshot.
+ */
+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 zip file */
+    private static final int MIN_KEEP_COUNT = 1;
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        cleanupOldFiles(this, intent, INTENT_REMOTE_BUGREPORT_FINISHED, MIN_KEEP_COUNT, 0);
+
+        final File bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT);
+        final Uri bugreportUri = getUri(context, bugreportFile);
+        final String bugreportHash = intent.getStringExtra(EXTRA_REMOTE_BUGREPORT_HASH);
+
+        final Intent newIntent = new Intent(INTENT_REMOTE_BUGREPORT_DISPATCH);
+        newIntent.setDataAndType(bugreportUri, BUGREPORT_MIMETYPE);
+        newIntent.putExtra(EXTRA_REMOTE_BUGREPORT_HASH, bugreportHash);
+        context.sendBroadcastAsUser(newIntent, UserHandle.SYSTEM,
+                android.Manifest.permission.DUMP);
+    }
+}
diff --git a/packages/Shell/tests/Android.mk b/packages/Shell/tests/Android.mk
index 62a37bc..1e0eaac 100644
--- a/packages/Shell/tests/Android.mk
+++ b/packages/Shell/tests/Android.mk
@@ -8,9 +8,7 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-# TODO: update and/or remove
 LOCAL_STATIC_JAVA_LIBRARIES := ub-uiautomator
-#LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 mockito-target ub-uiautomator
 
 LOCAL_PACKAGE_NAME := ShellTests
 LOCAL_INSTRUMENTATION_FOR := Shell
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index 1f4d749..5908d02 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -25,6 +25,7 @@
 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.SCREENSHOT_DELAY_SECONDS;
 
 import java.io.BufferedOutputStream;
 import java.io.BufferedWriter;
@@ -35,7 +36,10 @@
 import java.io.InputStream;
 import java.io.OutputStreamWriter;
 import java.io.Writer;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 import java.util.zip.ZipOutputStream;
@@ -56,9 +60,12 @@
 import android.support.test.uiautomator.UiObject;
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
 import android.util.Log;
 
 import com.android.shell.ActionSendMultipleConsumerActivity.CustomActionSendMultipleListener;
+import com.android.shell.BugreportProgressService;
 
 /**
  * Integration tests for {@link BugreportReceiver}.
@@ -83,6 +90,9 @@
     // Timeout for UI operations, in milliseconds.
     private static final int TIMEOUT = (int) BugreportProgressService.POLLING_FREQUENCY * 4;
 
+    // Timeout for when waiting for a screenshot to finish.
+    private static final int SAFE_SCREENSHOT_DELAY = SCREENSHOT_DELAY_SECONDS + 10;
+
     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";
@@ -94,7 +104,18 @@
     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 String NAME = "BUG, Y U NO REPORT?";
+    private static final String NEW_NAME = "Bug_Forrest_Bug";
+    private static final String TITLE = "Wimbugdom Champion 2015";
+
+    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 Integer NO_PID = null;
+
+    private String mDescription;
 
     private String mPlainTextPath;
     private String mZipPath;
@@ -106,6 +127,7 @@
 
     @Override
     protected void setUp() throws Exception {
+        Log.i(TAG, "#### setup() on " + getName());
         Instrumentation instrumentation = getInstrumentation();
         mContext = instrumentation.getTargetContext();
         mUiBot = new UiBot(UiDevice.getInstance(instrumentation), TIMEOUT);
@@ -120,12 +142,20 @@
         createTextFile(mScreenshotPath, SCREENSHOT_CONTENT);
         createZipFile(mZipPath, BUGREPORT_FILE, BUGREPORT_CONTENT);
 
+        // Creates a multi-line description.
+        StringBuilder sb = new StringBuilder();
+        for (int i = 1; i <= 20; i++) {
+            sb.append("All work and no play makes Shell a dull app!\n");
+        }
+        mDescription = sb.toString();
+
         BugreportPrefs.setWarningState(mContext, BugreportPrefs.STATE_HIDE);
     }
 
-    public void testFullWorkflow() throws Exception {
+    public void testProgress() throws Exception {
         resetProperties();
         sendBugreportStarted(1000);
+        waitForScreenshotButtonEnabled(true);
 
         assertProgressNotification(NAME, "0.00%");
 
@@ -140,7 +170,204 @@
 
         Bundle extras =
                 sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT);
+        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, ZIP_FILE,
+                NAME, NO_TITLE, NO_DESCRIPTION, 1, true);
+
+        assertServiceNotRunning();
+    }
+
+    public void testProgress_takeExtraScreenshot() throws Exception {
+        takeExtraScreenshotTest(false);
+    }
+
+    public void testProgress_takeExtraScreenshotServiceDiesAfterScreenshotTaken() throws Exception {
+        takeExtraScreenshotTest(true);
+    }
+
+    private void takeExtraScreenshotTest(boolean serviceDies) throws Exception {
+        resetProperties();
+        sendBugreportStarted(1000);
+
+        waitForScreenshotButtonEnabled(true);
+        takeScreenshot();
+        assertScreenshotButtonEnabled(false);
+        waitForScreenshotButtonEnabled(true);
+
+        sendBugreportFinished(PID, mPlainTextPath, mScreenshotPath);
+
+        if (serviceDies) {
+            waitShareNotification();
+            killService();
+        }
+
+        Bundle extras = acceptBugreportAndGetSharedIntent();
+        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, ZIP_FILE,
+                NAME, NO_TITLE, NO_DESCRIPTION, 2, true);
+
+        assertServiceNotRunning();
+    }
+
+    public void testScreenshotFinishesAfterBugreport() throws Exception {
+        screenshotFinishesAfterBugreportTest(false);
+    }
+
+    public void testScreenshotFinishesAfterBugreportAndServiceDiesBeforeSharing() throws Exception {
+        screenshotFinishesAfterBugreportTest(true);
+    }
+
+    private void screenshotFinishesAfterBugreportTest(boolean serviceDies) throws Exception {
+        resetProperties();
+
+        sendBugreportStarted(1000);
+        sendBugreportFinished(PID, mPlainTextPath, NO_SCREENSHOT);
+        waitShareNotification();
+
+        // 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);
+
+        if (serviceDies) {
+            killService();
+        }
+
+        Bundle extras = acceptBugreportAndGetSharedIntent();
+        assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, PID, ZIP_FILE,
+                NAME, NO_TITLE, NO_DESCRIPTION, 1, true);
+
+        assertServiceNotRunning();
+    }
+
+    public void testProgress_changeDetailsInvalidInput() throws Exception {
+
+        resetProperties();
+        sendBugreportStarted(1000);
+        waitForScreenshotButtonEnabled(true);
+
+        DetailsUi detailsUi = new DetailsUi(mUiBot);
+
+        // Check initial name.
+        String actualName = detailsUi.nameField.getText().toString();
+        assertEquals("Wrong value on field 'name'", NAME, actualName);
+
+        // Change name - it should have changed system property once focus is changed.
+        detailsUi.nameField.setText(NEW_NAME);
+        detailsUi.focusAwayFromName();
+        assertPropertyValue(NAME_PROPERTY, NEW_NAME);
+
+        // Cancel the dialog to make sure property was restored.
+        detailsUi.clickCancel();
+        assertPropertyValue(NAME_PROPERTY, NAME);
+
+        // Now try to set an invalid name.
+        detailsUi.reOpen();
+        detailsUi.nameField.setText("/etc/passwd");
+        detailsUi.clickOk();
+        assertPropertyValue(NAME_PROPERTY, "_etc_passwd");
+
+        // Finally, make the real changes.
+        detailsUi.reOpen();
+        detailsUi.nameField.setText(NEW_NAME);
+        detailsUi.titleField.setText(TITLE);
+        detailsUi.descField.setText(mDescription);
+
+        detailsUi.clickOk();
+
+        assertPropertyValue(NAME_PROPERTY, NEW_NAME);
+        assertProgressNotification(NEW_NAME, "0.00%");
+
+        Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath,
+                mScreenshotPath);
+        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, TITLE,
+                NEW_NAME, TITLE, mDescription, 1, true);
+
+        assertServiceNotRunning();
+    }
+
+    public void testProgress_changeDetailsPlainBugreport() throws Exception {
+        changeDetailsTest(true);
+    }
+
+    public void testProgress_changeDetailsZippedBugreport() throws Exception {
+        changeDetailsTest(false);
+    }
+
+    public void changeDetailsTest(boolean plainText) throws Exception {
+
+        resetProperties();
+        sendBugreportStarted(1000);
+        waitForScreenshotButtonEnabled(true);
+
+        DetailsUi detailsUi = new DetailsUi(mUiBot);
+
+        // Check initial name.
+        String actualName = detailsUi.nameField.getText().toString();
+        assertEquals("Wrong value on field 'name'", NAME, actualName);
+
+        // Change fields.
+        detailsUi.reOpen();
+        detailsUi.nameField.setText(NEW_NAME);
+        detailsUi.titleField.setText(TITLE);
+        detailsUi.descField.setText(mDescription);
+
+        detailsUi.clickOk();
+
+        assertPropertyValue(NAME_PROPERTY, NEW_NAME);
+        assertProgressNotification(NEW_NAME, "0.00%");
+
+        Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID,
+                plainText? mPlainTextPath : mZipPath, mScreenshotPath);
+        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, TITLE,
+                NEW_NAME, TITLE, mDescription, 1, true);
+
+        assertServiceNotRunning();
+    }
+
+    /**
+     * Tests the scenario where the initial screenshot and dumpstate are finished while the user
+     * is changing the info in the details screen.
+     */
+    public void testProgress_bugreportAndScreenshotFinishedWhileChangingDetails() throws Exception {
+        bugreportFinishedWhileChangingDetailsTest(false);
+    }
+
+    /**
+     * Tests the scenario where dumpstate is finished while the user is changing the info in the
+     * details screen, but the initial screenshot finishes afterwards.
+     */
+    public void testProgress_bugreportFinishedWhileChangingDetails() throws Exception {
+        bugreportFinishedWhileChangingDetailsTest(true);
+    }
+
+    private void bugreportFinishedWhileChangingDetailsTest(boolean waitScreenshot) throws Exception {
+        resetProperties();
+        sendBugreportStarted(1000);
+        if (waitScreenshot) {
+            waitForScreenshotButtonEnabled(true);
+        }
+
+        DetailsUi detailsUi = new DetailsUi(mUiBot);
+
+        // Finish the bugreport while user's still typing the name.
+        detailsUi.nameField.setText(NEW_NAME);
+        sendBugreportFinished(PID, mPlainTextPath, mScreenshotPath);
+
+        // Wait until the share notification is received...
+        mUiBot.getNotification(mContext.getString(R.string.bugreport_finished_title));
+        // ...then close notification bar.
+        mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+
+        // Make sure UI was updated properly.
+        assertFalse("didn't disable name on UI", detailsUi.nameField.isEnabled());
+        assertEquals("didn't revert name on UI", NAME, detailsUi.nameField.getText().toString());
+
+        // Finish changing other fields.
+        detailsUi.titleField.setText(TITLE);
+        detailsUi.descField.setText(mDescription);
+        detailsUi.clickOk();
+
+        // Finally, share bugreport.
+        Bundle extras = acceptBugreportAndGetSharedIntent();
+        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, TITLE,
+                NAME, TITLE, mDescription, 1, true);
 
         assertServiceNotRunning();
     }
@@ -150,7 +377,7 @@
         BugreportPrefs.setWarningState(mContext, BugreportPrefs.STATE_SHOW);
 
         // Send notification and click on share.
-        sendBugreportFinished(null, mPlainTextPath, null);
+        sendBugreportFinished(NO_PID, mPlainTextPath, null);
         acceptBugreport();
 
         // Handle the warning
@@ -165,13 +392,20 @@
         // Share the bugreport.
         mUiBot.chooseActivity(UI_NAME);
         Bundle extras = mListener.getExtras();
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, null);
+        assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
 
         // Make sure it's hidden now.
         int newState = BugreportPrefs.getWarningState(mContext, BugreportPrefs.STATE_UNKNOWN);
         assertEquals("Didn't change state", BugreportPrefs.STATE_HIDE, newState);
     }
 
+    public void testShareBugreportAfterServiceDies() throws Exception {
+        sendBugreportFinished(NO_PID, mPlainTextPath, NO_SCREENSHOT);
+        killService();
+        Bundle extras = acceptBugreportAndGetSharedIntent();
+        assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
+    }
+
     public void testBugreportFinished_plainBugreportAndScreenshot() throws Exception {
         Bundle extras = sendBugreportFinishedAndGetSharedIntent(mPlainTextPath, mScreenshotPath);
         assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT);
@@ -183,13 +417,13 @@
     }
 
     public void testBugreportFinished_plainBugreportAndNoScreenshot() throws Exception {
-        Bundle extras = sendBugreportFinishedAndGetSharedIntent(mPlainTextPath, null);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, null);
+        Bundle extras = sendBugreportFinishedAndGetSharedIntent(mPlainTextPath, NO_SCREENSHOT);
+        assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
     }
 
     public void testBugreportFinished_zippedBugreportAndNoScreenshot() throws Exception {
-        Bundle extras = sendBugreportFinishedAndGetSharedIntent(mZipPath, null);
-        assertActionSendMultiple(extras, BUGREPORT_CONTENT, null);
+        Bundle extras = sendBugreportFinishedAndGetSharedIntent(mZipPath, NO_SCREENSHOT);
+        assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
     }
 
     private void cancelExistingNotifications() {
@@ -202,16 +436,20 @@
     }
 
     private void assertProgressNotification(String name, String percent) {
-        // TODO: it current looks for 3 distinct objects, without taking advantage of their
+        // TODO: it currently looks for 3 distinct objects, without taking advantage of their
         // relationship.
-        String title = mContext.getString(R.string.bugreport_in_progress_title);
-        Log.v(TAG, "Looking for progress notification title: '" + title+ "'");
-        mUiBot.getNotification(title);
+        openProgressNotification();
         Log.v(TAG, "Looking for progress notification details: '" + name + "-" + percent + "'");
         mUiBot.getObject(name);
         mUiBot.getObject(percent);
     }
 
+    private void openProgressNotification() {
+        String title = mContext.getString(R.string.bugreport_in_progress_title);
+        Log.v(TAG, "Looking for progress notification title: '" + title + "'");
+        mUiBot.getNotification(title);
+    }
+
     void resetProperties() {
         // TODO: call method to remove property instead
         SystemProperties.set(PROGRESS_PROPERTY, "0");
@@ -221,8 +459,9 @@
     /**
      * Sends a "bugreport started" intent with the default values.
      */
-    private void sendBugreportStarted(int max) {
+    private void sendBugreportStarted(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_MAX, max);
@@ -262,6 +501,13 @@
     }
 
     /**
+     * Waits for the notification to share the finished bugreport.
+     */
+    private void waitShareNotification() {
+        mUiBot.getNotification(mContext.getString(R.string.bugreport_finished_title));
+    }
+
+    /**
      * Accepts the notification to share the finished bugreport.
      */
     private void acceptBugreport() {
@@ -270,10 +516,10 @@
 
     /**
      * Sends a "bugreport finished" intent.
-     *
      */
     private void sendBugreportFinished(Integer pid, String bugreportPath, String screenshotPath) {
         Intent intent = new Intent(INTENT_BUGREPORT_FINISHED);
+        intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
         if (pid != null) {
             intent.putExtra(EXTRA_PID, pid);
         }
@@ -288,41 +534,103 @@
     }
 
     /**
-     * Asserts the proper ACTION_SEND_MULTIPLE intent was sent.
+     * Asserts the proper {@link Intent#ACTION_SEND_MULTIPLE} intent was sent.
      */
     private void assertActionSendMultiple(Bundle extras, String bugreportContent,
             String screenshotContent) throws IOException {
+        assertActionSendMultiple(extras, bugreportContent, screenshotContent, PID, ZIP_FILE,
+                NO_NAME, NO_TITLE, NO_DESCRIPTION, 0, false);
+    }
+
+    /**
+     * Asserts the proper {@link Intent#ACTION_SEND_MULTIPLE} intent was sent.
+     *
+     * @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 pid emulated dumpstate pid
+     * @param name expected subject
+     * @param name bugreport name as provided by the user (or received by dumpstate)
+     * @param title bugreport name as provided by the user
+     * @param description bugreport description as provided by the user
+     * @param numberScreenshots expected number of screenshots taken by Shell.
+     * @param renamedScreenshots whether the screenshots are expected to be renamed
+     */
+    private void assertActionSendMultiple(Bundle extras, String bugreportContent,
+            String screenshotContent, int pid, String subject,
+            String name, String title, String description,
+            int numberScreenshots, boolean renamedScreenshots) throws IOException {
         String body = extras.getString(Intent.EXTRA_TEXT);
         assertContainsRegex("missing build info",
                 SystemProperties.get("ro.build.description"), body);
         assertContainsRegex("missing serial number",
                 SystemProperties.get("ro.serialno"), body);
+        if (description != null) {
+            assertContainsRegex("missing description", description, body);
+        }
 
-        assertEquals("wrong subject", ZIP_FILE, extras.getString(Intent.EXTRA_SUBJECT));
+        assertEquals("wrong subject", subject, extras.getString(Intent.EXTRA_SUBJECT));
 
         List<Uri> attachments = extras.getParcelableArrayList(Intent.EXTRA_STREAM);
-        int expectedSize = screenshotContent != null ? 2 : 1;
-        assertEquals("wrong number of attachments", expectedSize, attachments.size());
+        int expectedNumberScreenshots = numberScreenshots;
+        if (screenshotContent != null) {
+            expectedNumberScreenshots ++; // Add screenshot received by dumpstate
+        }
+        int expectedSize = expectedNumberScreenshots + 1; // All screenshots plus the bugreport file
+        assertEquals("wrong number of attachments (" + attachments + ")",
+                expectedSize, attachments.size());
 
         // Need to interact through all attachments, since order is not guaranteed.
-        Uri zipUri = null, screenshotUri = null;
+        Uri zipUri = null;
+        List<Uri> screenshotUris = new ArrayList<>(expectedNumberScreenshots);
         for (Uri attachment : attachments) {
             if (attachment.getPath().endsWith(".zip")) {
                 zipUri = attachment;
             }
             if (attachment.getPath().endsWith(".png")) {
-                screenshotUri = attachment;
+                screenshotUris.add(attachment);
             }
         }
         assertNotNull("did not get .zip attachment", zipUri);
         assertZipContent(zipUri, BUGREPORT_FILE, BUGREPORT_CONTENT);
-
-        if (screenshotContent != null) {
-            assertNotNull("did not get .png attachment", screenshotUri);
-            assertContent(screenshotUri, SCREENSHOT_CONTENT);
-        } else {
-            assertNull("should not have .png attachment", screenshotUri);
+        if (!TextUtils.isEmpty(title)) {
+            assertZipContent(zipUri, "title.txt", title);
         }
+        if (!TextUtils.isEmpty(description)) {
+            assertZipContent(zipUri, "description.txt", description);
+        }
+
+        // URI of the screenshot taken by dumpstate.
+        Uri externalScreenshotUri = null;
+        SortedSet<String> internalScreenshotNames = new TreeSet<>();
+        for (Uri screenshotUri : screenshotUris) {
+            String screenshotName = screenshotUri.getLastPathSegment();
+            if (screenshotName.endsWith(SCREENSHOT_FILE)) {
+                externalScreenshotUri = screenshotUri;
+            } else {
+                internalScreenshotNames.add(screenshotName);
+            }
+        }
+        // Check external screenshot
+        if (screenshotContent != null) {
+            assertNotNull("did not get .png attachment for external screenshot",
+                    externalScreenshotUri);
+            assertContent(externalScreenshotUri, SCREENSHOT_CONTENT);
+        } else {
+            assertNull("should not have .png attachment for external screenshot",
+                    externalScreenshotUri);
+        }
+        // Check internal screenshots.
+        SortedSet<String> expectedNames = new TreeSet<>();
+        for (int i = 1 ; i <= numberScreenshots; i++) {
+            String prefix = renamedScreenshots  ? name : Integer.toString(pid);
+            String expectedName = "screenshot-" + prefix + "-" + i + ".png";
+            expectedNames.add(expectedName);
+        }
+        // Ideally we should use MoreAsserts, but the error message in case of failure is not
+        // really useful.
+        assertEquals("wrong names for internal screenshots",
+                expectedNames, internalScreenshotNames);
     }
 
     private void assertContent(Uri uri, String expectedContent) throws IOException {
@@ -355,11 +663,25 @@
         fail("Did not find entry '" + entryName + "' on file '" + uri + "'");
     }
 
+    private void assertPropertyValue(String key, String expectedValue) {
+        String actualValue = SystemProperties.get(key);
+        assertEquals("Wrong value for property '" + key + "'", expectedValue, actualValue);
+    }
+
     private void assertServiceNotRunning() {
         String service = BugreportProgressService.class.getName();
         assertFalse("Service '" + service + "' is still running", isServiceRunning(service));
     }
 
+    private void killService() {
+        waitForService(true);
+        Log.v(TAG, "Stopping service");
+        boolean stopped = mContext.stopService(new Intent(mContext, BugreportProgressService.class));
+        Log.d(TAG, "stopService returned " + stopped);
+        waitForService(false);
+        assertServiceNotRunning();  // Sanity check.
+    }
+
     private boolean isServiceRunning(String name) {
         ActivityManager manager = (ActivityManager) mContext
                 .getSystemService(Context.ACTIVITY_SERVICE);
@@ -371,6 +693,33 @@
         return false;
     }
 
+    private void waitForService(boolean expectRunning) {
+        String service = BugreportProgressService.class.getName();
+        boolean actualRunning;
+        for (int i = 1; i <= 5; i++) {
+            actualRunning = isServiceRunning(service);
+            Log.d(TAG, "Attempt " + i + " to check status of service '"
+                    + service + "': expected=" + expectRunning + ", actual= " + actualRunning);
+            if (actualRunning == expectRunning) {
+                return;
+            }
+            try {
+                Thread.sleep(DateUtils.SECOND_IN_MILLIS);
+            } catch (InterruptedException e) {
+                Log.w(TAG, "thread interrupted");
+                Thread.currentThread().interrupt();
+            }
+        }
+        if (!expectRunning) {
+            // Typically happens when service is waiting for a screenshot to finish.
+            Log.w(TAG, "Service didn't stop; try to kill it again");
+            killService();
+            return;
+        }
+
+        fail("Service status didn't change to " + expectRunning);
+    }
+
     private static void createTextFile(String path, String content) throws IOException {
         Log.v(TAG, "createFile(" + path + ")");
         try (Writer writer = new BufferedWriter(new OutputStreamWriter(
@@ -402,4 +751,96 @@
         Log.v(TAG, "Path for '" + file + "': " + path);
         return path;
     }
+
+    /**
+     * Gets the notification button used to take a screenshot.
+     */
+    private UiObject getScreenshotButton() {
+        openProgressNotification();
+        return mUiBot.getVisibleObject(
+                mContext.getString(R.string.bugreport_screenshot_action).toUpperCase());
+    }
+
+    /**
+     * Takes a screenshot using the system notification.
+     */
+    private void takeScreenshot() throws Exception {
+        UiObject screenshotButton = getScreenshotButton();
+        mUiBot.click(screenshotButton, "screenshot_button");
+    }
+
+    private UiObject waitForScreenshotButtonEnabled(boolean expectedEnabled) throws Exception {
+        UiObject screenshotButton = getScreenshotButton();
+        int maxAttempts = SAFE_SCREENSHOT_DELAY;
+        int i = 0;
+        do {
+            boolean enabled = screenshotButton.isEnabled();
+            if (enabled == expectedEnabled) {
+                return screenshotButton;
+            }
+            i++;
+            Log.v(TAG, "Sleeping for 1 second while waiting for screenshot.enable to be "
+                    + expectedEnabled + " (attempt " + i + ")");
+            Thread.sleep(DateUtils.SECOND_IN_MILLIS);
+        } while (i <= maxAttempts);
+        fail("screenshot.enable didn't change to " + expectedEnabled + " in " + maxAttempts + "s");
+        return screenshotButton;
+    }
+
+    private void assertScreenshotButtonEnabled(boolean expectedEnabled) throws Exception {
+        UiObject screenshotButton = getScreenshotButton();
+        assertEquals("wrong state for screenshot button ", expectedEnabled,
+                screenshotButton.isEnabled());
+    }
+
+    /**
+     * Helper class containing the UiObjects present in the bugreport info dialog.
+     */
+    private final class DetailsUi {
+
+        final UiObject detailsButton;
+        final UiObject nameField;
+        final UiObject titleField;
+        final UiObject descField;
+        final UiObject okButton;
+        final UiObject cancelButton;
+
+        /**
+         * Gets the UI objects by opening the progress notification and clicking DETAILS.
+         */
+        DetailsUi(UiBot uiBot) {
+            openProgressNotification();
+            detailsButton = mUiBot.getVisibleObject(
+                    mContext.getString(R.string.bugreport_info_action).toUpperCase());
+            mUiBot.click(detailsButton, "details_button");
+            // TODO: unhardcode resource ids
+            nameField = mUiBot.getVisibleObjectById("com.android.shell:id/name");
+            titleField = mUiBot.getVisibleObjectById("com.android.shell:id/title");
+            descField = mUiBot.getVisibleObjectById("com.android.shell:id/description");
+            okButton = mUiBot.getObjectById("android:id/button1");
+            cancelButton = mUiBot.getObjectById("android:id/button2");
+        }
+
+        /**
+         * Takes focus away from the name field so it can be validated.
+         */
+        void focusAwayFromName() {
+            mUiBot.click(titleField, "title_field"); // Change focus.
+            mUiBot.pressBack(); // Dismiss keyboard.
+        }
+
+        void reOpen() {
+            openProgressNotification();
+            mUiBot.click(detailsButton, "details_button");
+
+        }
+
+        void clickOk() {
+            mUiBot.click(okButton, "details_ok_button");
+        }
+
+        void clickCancel() {
+            mUiBot.click(cancelButton, "details_cancel_button");
+        }
+    }
 }
diff --git a/packages/Shell/tests/src/com/android/shell/UiBot.java b/packages/Shell/tests/src/com/android/shell/UiBot.java
index c871727..384c3da 100644
--- a/packages/Shell/tests/src/com/android/shell/UiBot.java
+++ b/packages/Shell/tests/src/com/android/shell/UiBot.java
@@ -79,6 +79,17 @@
     }
 
     /**
+     * Gets an object that might not yet be available in current UI.
+     *
+     * @param id Object's fully-qualified resource id (like {@code android:id/button1})
+     */
+    public UiObject getObjectById(String id) {
+        boolean gotIt = mDevice.wait(Until.hasObject(By.res(id)), mTimeout);
+        assertTrue("object with id '(" + id + "') not visible yet", gotIt);
+        return getVisibleObjectById(id);
+    }
+
+    /**
      * Gets an object which is guaranteed to be present in the current UI.
      *
      * @param text Object's text as displayed by the UI.
@@ -90,6 +101,18 @@
     }
 
     /**
+     * Gets an object which is guaranteed to be present in the current UI.
+     *
+     * @param text Object's text as displayed by the UI.
+     */
+    public UiObject getVisibleObjectById(String id) {
+        UiObject uiObject = mDevice.findObject(new UiSelector().resourceId(id));
+        assertTrue("could not find object with id '" + id+ "'", uiObject.exists());
+        return uiObject;
+    }
+
+
+    /**
      * Clicks on a UI element.
      *
      * @param uiObject UI element to be clicked.
@@ -151,4 +174,8 @@
             click(activity, name);
         }
     }
+
+    public void pressBack() {
+        mDevice.pressBack();
+    }
 }
diff --git a/packages/Shell/tests/src/com/android/shell/UtilitiesTest.java b/packages/Shell/tests/src/com/android/shell/UtilitiesTest.java
new file mode 100644
index 0000000..51b7ba8
--- /dev/null
+++ b/packages/Shell/tests/src/com/android/shell/UtilitiesTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.shell;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+import static com.android.shell.BugreportProgressService.isValid;
+
+@SmallTest
+public class UtilitiesTest extends TestCase {
+
+    public void testIsValidChar_valid() {
+        String validChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+        for (int i = 0; i < validChars.length(); i++) {
+            char c = validChars.charAt(i);
+            assertTrue("char '" + c + "' should be valid", isValid(c));
+        }
+    }
+
+    public void testIsValidChar_invalid() {
+        String validChars = "/.<>;:'\'\"\\+=*&^%$#@!`~áéíóúãñÂÊÎÔÛ";
+        for (int i = 0; i < validChars.length(); i++) {
+            char c = validChars.charAt(i);
+            assertFalse("char '" + c + "' should not be valid", isValid(c));
+        }
+    }
+}
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index eb63e5d..88313bb 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -8,7 +8,13 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     Keyguard \
-    android-support-v7-recyclerview
+    android-support-v7-recyclerview \
+    android-support-v7-preference \
+    android-support-v7-appcompat \
+    android-support-v14-preference \
+    android-support-v17-leanback \
+    framework-protos
+
 LOCAL_JAVA_LIBRARIES := telephony-common
 
 LOCAL_PACKAGE_NAME := SystemUI
@@ -22,10 +28,15 @@
 LOCAL_RESOURCE_DIR := \
     frameworks/base/packages/Keyguard/res \
     $(LOCAL_PATH)/res \
-    frameworks/support/v7/recyclerview/res
+    frameworks/support/v7/preference/res \
+    frameworks/support/v14/preference/res \
+    frameworks/support/v7/appcompat/res \
+    frameworks/support/v7/recyclerview/res \
+    frameworks/support/v17/leanback/res
 
 LOCAL_AAPT_FLAGS := --auto-add-overlay \
-     --extra-packages com.android.keyguard:android.support.v7.recyclerview
+    --extra-packages com.android.keyguard:android.support.v7.recyclerview:android.support.v7.preference:android.support.v14.preference:android.support.v7.appcompat \
+    --extra-packages android.support.v17.leanback
 
 ifneq ($(SYSTEM_UI_INCREMENTAL_BUILDS),)
     LOCAL_PROGUARD_ENABLED := disabled
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 51b84f5..2713fb5 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -58,6 +58,7 @@
     <uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG" />
     <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
     <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+    <uses-permission android:name="android.permission.TETHER_PRIVILEGED" />
     <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
     <uses-permission android:name="android.permission.CONTROL_VPN" />
     <uses-permission android:name="android.permission.PEERS_MAC_ADDRESS"/>
@@ -139,6 +140,21 @@
     <!-- Adding Quick Settings tiles -->
     <uses-permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE" />
 
+    <!-- Block notifications inline notifications -->
+    <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
+
+    <!-- Access battery information -->
+    <uses-permission android:name="android.permission.BATTERY_STATS" />
+
+    <!-- DevicePolicyManager get user restrictions -->
+    <uses-permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS" />
+
+    <!-- Needed for passing extras with intent ACTION_SHOW_ADMIN_SUPPORT_DETAILS -->
+    <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
+
+    <!-- TV picture-in-picture -->
+    <uses-permission android:name="android.permission.RECEIVE_MEDIA_RESOURCE_USAGE" />
+
     <application
         android:name=".SystemUIApplication"
         android:persistent="true"
@@ -186,7 +202,7 @@
         <activity android:name=".tuner.TunerActivity"
                   android:enabled="false"
                   android:icon="@drawable/tuner"
-                  android:theme="@android:style/Theme.Material.Settings"
+                  android:theme="@style/TunerSettings"
                   android:label="@string/system_ui_tuner"
                   android:process=":tuner"
                   android:exported="true">
@@ -213,7 +229,21 @@
                   android:resumeWhilePausing="true"
                   android:screenOrientation="behind"
                   android:resizeableActivity="true"
-                  android:configChanges="orientation|screenSize|smallestScreenSize"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+                  android:theme="@style/RecentsTheme.Wallpaper">
+            <intent-filter>
+                <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".recents.tv.RecentsTvActivity"
+                  android:label="@string/accessibility_desc_recent_apps"
+                  android:exported="false"
+                  android:launchMode="singleInstance"
+                  android:excludeFromRecents="true"
+                  android:stateNotNeeded="true"
+                  android:resumeWhilePausing="true"
+                  android:screenOrientation="behind"
                   android:theme="@style/RecentsTheme.Wallpaper">
             <intent-filter>
                 <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
@@ -299,6 +329,27 @@
             android:launchMode="singleTop"
             android:excludeFromRecents="true" />
 
+        <!-- started from PipUI -->
+        <activity
+            android:name="com.android.systemui.tv.pip.PipMenuActivity"
+            android:exported="true"
+            android:theme="@style/PipTheme"
+            android:launchMode="singleTop"
+            android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
+            android:resizeable="true"
+            android:supportsPictureInPicture="true"
+            androidprv:alwaysFocusable="true"
+            android:excludeFromRecents="true" />
+        <activity
+            android:name="com.android.systemui.tv.pip.PipOverlayActivity"
+            android:exported="true"
+            android:theme="@style/PipTheme"
+            android:launchMode="singleTop"
+            android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
+            android:resizeable="true"
+            android:supportsPictureInPicture="true"
+            android:excludeFromRecents="true" />
+
         <!-- platform logo easter egg activity -->
         <activity
             android:name=".DessertCase"
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index 75e7959..d0c2d29 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -10,8 +10,10 @@
   public void setGlowScale(float);
 }
 
+-keep class com.android.systemui.statusbar.car.CarStatusBar
 -keep class com.android.systemui.statusbar.phone.PhoneStatusBar
 -keep class com.android.systemui.statusbar.tv.TvStatusBar
+-keep class com.android.systemui.SystemUIFactory
 
 -keepclassmembers class ** {
     public void onBusEvent(**);
@@ -27,3 +29,10 @@
     public float getTaskProgress();
     public void setTaskProgress(float);
 }
+
+-keepclasseswithmembers class * {
+    public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+-keep class ** extends android.support.v14.preference.PreferenceFragment
+-keep class com.android.systemui.tuner.*
diff --git a/packages/SystemUI/res/color/qs_tile_text.xml b/packages/SystemUI/res/color/qs_tile_text.xml
new file mode 100644
index 0000000..90e0bce
--- /dev/null
+++ b/packages/SystemUI/res/color/qs_tile_text.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false" android:color="@color/qs_tile_disabled_color" />
+    <item android:color="#B3FFFFFF" /> <!-- 70% white -->
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/color/qs_user_detail_name.xml b/packages/SystemUI/res/color/qs_user_detail_name.xml
index 57f7e65..35c7a4f 100644
--- a/packages/SystemUI/res/color/qs_user_detail_name.xml
+++ b/packages/SystemUI/res/color/qs_user_detail_name.xml
@@ -18,5 +18,6 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_activated="true" android:color="@color/current_user_border_color" />
+    <item android:state_enabled="false" android:color="@color/qs_tile_disabled_color" />
     <item android:color="#66ffffff" /> <!-- 40% white -->
 </selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_carmode.png
new file mode 100644
index 0000000..6242084
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_carmode.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_carmode.png
new file mode 100644
index 0000000..1b37a47
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_carmode.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_carmode.png
new file mode 100644
index 0000000..9e05758
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_carmode.png
new file mode 100644
index 0000000..2fcfdde
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_carmode.png
new file mode 100644
index 0000000..48708a5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_carmode.png
new file mode 100644
index 0000000..3d73184
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_carmode.png
new file mode 100644
index 0000000..786935d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_carmode.png
new file mode 100644
index 0000000..e4bd4bc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_carmode.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_carmode.png
new file mode 100644
index 0000000..94ccf79
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_carmode.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_carmode.png
new file mode 100644
index 0000000..980bbbc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_carmode.png
new file mode 100644
index 0000000..201be3b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_carmode.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_carmode.png
new file mode 100644
index 0000000..2770d62
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_carmode.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_carmode.png
new file mode 100644
index 0000000..8ac6493
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_carmode.png
new file mode 100644
index 0000000..8e3678b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_carmode.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_carmode.png
new file mode 100644
index 0000000..6c7cb05
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_carmode.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_carmode.png
new file mode 100644
index 0000000..ea2b108
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_carmode.png
new file mode 100644
index 0000000..3e11023
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_carmode.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_carmode.png
new file mode 100644
index 0000000..fe8213d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_carmode.png
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
new file mode 100644
index 0000000..f3be2ee
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_carmode.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_carmode.png
new file mode 100644
index 0000000..c117efd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_carmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/brightness_mirror_background.xml b/packages/SystemUI/res/drawable/brightness_mirror_background.xml
index fadfe63..e901e40 100644
--- a/packages/SystemUI/res/drawable/brightness_mirror_background.xml
+++ b/packages/SystemUI/res/drawable/brightness_mirror_background.xml
@@ -16,9 +16,4 @@
   -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
     <solid android:color="@color/system_primary_color" />
-    <corners
-        android:topLeftRadius="@dimen/notification_material_rounded_rect_radius"
-        android:topRightRadius="@dimen/notification_material_rounded_rect_radius"
-        android:bottomLeftRadius="@dimen/notification_material_rounded_rect_radius"
-        android:bottomRightRadius="@dimen/notification_material_rounded_rect_radius"/>
 </shape>
diff --git a/packages/SystemUI/res/drawable/car_ic_arrow.xml b/packages/SystemUI/res/drawable/car_ic_arrow.xml
new file mode 100644
index 0000000..9d292cc
--- /dev/null
+++ b/packages/SystemUI/res/drawable/car_ic_arrow.xml
@@ -0,0 +1,27 @@
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48.0dp"
+        android:height="48.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M14.0,20.0l10.0,10.0 10.0,-10.0z"/>
+    <path
+        android:pathData="M0 0h48v48H0z"
+        android:fillColor="#00000000"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/clipboard_empty.xml b/packages/SystemUI/res/drawable/clipboard_empty.xml
new file mode 100644
index 0000000..14a5ad2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/clipboard_empty.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="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M19.0,2.0l-4.18,0.0C14.0,0.84 13.3,0.0 12.0,0.0c-1.3,0.0 -2.0,0.84 -2.82,2.0L5.0,2.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,16.0c0.0,1.0 0.9,2.0 2.0,2.0l14.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L21.0,4.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0zm-7.0,0.0c0.55,0.0 1.0,0.45 1.0,1.0s-0.45,1.0 -1.0,1.0 -1.0,-0.45 -1.0,-1.0 0.45,-1.0 1.0,-1.0zm7.0,18.0L5.0,20.0L5.0,4.0l2.0,0.0l0.0,3.0l10.0,0.0L17.0,4.0l2.0,0.0l0.0,16.0z" />
+</vector>
+
diff --git a/packages/SystemUI/res/drawable/clipboard_full.xml b/packages/SystemUI/res/drawable/clipboard_full.xml
new file mode 100644
index 0000000..2d46870
--- /dev/null
+++ b/packages/SystemUI/res/drawable/clipboard_full.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="24.0dp"
+    android:height="24.0dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M19.0,2.0l-4.18,0.0C14.0,0.84 13.3,0.0 12.0,0.0c-1.3,0.0 -2.0,0.84 -2.82,2.0L5.0,2.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,16.0c0.0,1.0 0.9,2.0 2.0,2.0l14.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L21.0,4.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0zm-7.0,0.0c0.55,0.0 1.0,0.45 1.0,1.0s-0.45,1.0 -1.0,1.0 -1.0,-0.45 -1.0,-1.0 0.45,-1.0 1.0,-1.0zm7.0,18.0L5.0,20.0L5.0,4.0l2.0,0.0l0.0,3.0l10.0,0.0L17.0,4.0l2.0,0.0l0.0,16.0z M 6,8 l 12,0 l 0,11 l -12,0 l 0,-11z" />
+</vector>
+
diff --git a/packages/SystemUI/res/drawable/docked_divider_handle.xml b/packages/SystemUI/res/drawable/docked_divider_handle.xml
deleted file mode 100644
index 84c0343..0000000
--- a/packages/SystemUI/res/drawable/docked_divider_handle.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT 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">
-    <size android:height="@dimen/docked_divider_handle_height"
-        android:width="@dimen/docked_divider_handle_width" />
-    <corners android:radius="1dp" />
-    <solid android:color="@color/docked_divider_handle" />
-</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_colorize.xml b/packages/SystemUI/res/drawable/ic_colorize.xml
new file mode 100644
index 0000000..79fd6d9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_colorize.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="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M20.71,5.63l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0.0l-3.12,3.12 -1.93,-1.91 -1.41,1.41 1.42,1.42L3.0,16.25L3.0,21.0l4.75,0.0l8.92,-8.92 1.42,1.42 1.41,-1.41 -1.92,-1.92 3.12,-3.12c0.4,0.0 0.4,-1.0 0.01,-1.42zM6.92,19.0L5.0,17.08l8.06,-8.06 1.92,1.92L6.92,19.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_data_saver.xml b/packages/SystemUI/res/drawable/ic_data_saver.xml
new file mode 100644
index 0000000..426238c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_data_saver.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="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        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"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_data_saver_off.xml b/packages/SystemUI/res/drawable/ic_data_saver_off.xml
new file mode 100644
index 0000000..0713548
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_data_saver_off.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="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <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"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_drag_handle.xml b/packages/SystemUI/res/drawable/ic_drag_handle.xml
new file mode 100644
index 0000000..9b319f1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_drag_handle.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.
+-->
+<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:fillColor="#FFFFFFFF"
+        android:pathData="M20.0,9.0L4.0,9.0l0.0,2.0l16.0,0.0L20.0,9.0zM4.0,15.0l16.0,0.0l0.0,-2.0L4.0,13.0l0.0,2.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_headset.xml b/packages/SystemUI/res/drawable/ic_headset.xml
new file mode 100644
index 0000000..58759f9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_headset.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.
+-->
+<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="48.0"
+        android:viewportHeight="48.0">
+        <path
+            android:fillColor="#FFFFFFFF"
+            android:pathData="M24.0,2.0C14.06,2.0 6.0,10.06 6.0,20.0l0.0,14.0c0.0,3.31 2.69,6.0 6.0,6.0l6.0,0.0L18.0,24.0l-8.0,0.0l0.0,-4.0c0.0,-7.73 6.27,-14.0 14.0,-14.0s14.0,6.27 14.0,14.0l0.0,4.0l-8.0,0.0l0.0,16.0l6.0,0.0c3.31,0.0 6.0,-2.69 6.0,-6.0L42.0,20.0c0.0,-9.94 -8.06,-18.0 -18.0,-18.0z"/>
+    </vector>
+</inset>
diff --git a/packages/SystemUI/res/drawable/ic_headset_mic.xml b/packages/SystemUI/res/drawable/ic_headset_mic.xml
new file mode 100644
index 0000000..5d02120
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_headset_mic.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.
+-->
+<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="48.0"
+        android:viewportHeight="48.0">
+        <path
+            android:fillColor="#FFFFFFFF"
+            android:pathData="M24.0,2.0C14.06,2.0 6.0,10.06 6.0,20.0l0.0,14.0c0.0,3.31 2.69,6.0 6.0,6.0l6.0,0.0L18.0,24.0l-8.0,0.0l0.0,-4.0c0.0,-7.73 6.27,-14.0 14.0,-14.0s14.0,6.27 14.0,14.0l0.0,4.0l-8.0,0.0l0.0,16.0l8.0,0.0l0.0,2.0L24.0,42.0l0.0,4.0l12.0,0.0c3.31,0.0 6.0,-2.69 6.0,-6.0L42.0,20.0c0.0,-9.94 -8.06,-18.0 -18.0,-18.0z"/>
+    </vector>
+</inset>
diff --git a/packages/SystemUI/res/drawable/ic_history.xml b/packages/SystemUI/res/drawable/ic_history.xml
new file mode 100644
index 0000000..e936864
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_history.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.
+-->
+<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="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89 .07 .14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7
+7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13
+21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54 .72 -1.21-3.5-2.08V8H12z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml b/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
new file mode 100644
index 0000000..b4144a3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_data_disabled.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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="40.0"
+        android:viewportHeight="40.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M19.0,6.41L17.59,5.0 12.0,10.59 6.41,5.0 5.0,6.41 10.59,12.0 5.0,17.59 6.41,19.0 12.0,13.41 17.59,19.0 19.0,17.59 13.41,12.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_width.xml b/packages/SystemUI/res/drawable/ic_width.xml
new file mode 100644
index 0000000..a302c81
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_width.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="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M7.77,6.76L6.23,5.4 0.82,12.0l5.41,6.52 1.54,-1.28L3.42,12.0l4.35,-5.24z
+        M17.77,5.48l-1.54,1.28L20.58,12.0l-4.35,5.24 1.54,1.28L23.18,12.0l-5.41,-6.52z"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M2.0,13.0l20.0,0.0l0.0,-2.0l-20.0,0.0l0.0,2.0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/notification_material_bg.xml b/packages/SystemUI/res/drawable/notification_material_bg.xml
index 6a0277f..ae45663 100644
--- a/packages/SystemUI/res/drawable/notification_material_bg.xml
+++ b/packages/SystemUI/res/drawable/notification_material_bg.xml
@@ -20,7 +20,6 @@
     <item>
         <shape>
             <solid android:color="@color/notification_material_background_color" />
-            <corners android:radius="@dimen/notification_material_rounded_rect_radius" />
         </shape>
     </item>
 </ripple>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/notification_material_bg_dim.xml b/packages/SystemUI/res/drawable/notification_material_bg_dim.xml
index 6581942..b6a8b70 100644
--- a/packages/SystemUI/res/drawable/notification_material_bg_dim.xml
+++ b/packages/SystemUI/res/drawable/notification_material_bg_dim.xml
@@ -18,7 +18,6 @@
     <item>
         <shape>
             <solid android:color="@color/notification_material_background_dimmed_color" />
-            <corners android:radius="@dimen/notification_material_rounded_rect_radius" />
         </shape>
     </item>
 </ripple>
diff --git a/packages/SystemUI/res/drawable/qs_background_primary.xml b/packages/SystemUI/res/drawable/qs_background_primary.xml
index 686df2c..1bf7d4c 100644
--- a/packages/SystemUI/res/drawable/qs_background_primary.xml
+++ b/packages/SystemUI/res/drawable/qs_background_primary.xml
@@ -13,10 +13,8 @@
      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="@dimen/notification_material_rounded_rect_radius_negative">
+<inset xmlns:android="http://schemas.android.com/apk/res/android">
     <shape>
         <solid android:color="@color/system_primary_color"/>
-        <corners android:radius="@dimen/notification_material_rounded_rect_radius"/>
     </shape>
 </inset>
diff --git a/packages/SystemUI/res/drawable/qs_background_secondary.xml b/packages/SystemUI/res/drawable/qs_background_secondary.xml
index 3662e5a..31c0162 100644
--- a/packages/SystemUI/res/drawable/qs_background_secondary.xml
+++ b/packages/SystemUI/res/drawable/qs_background_secondary.xml
@@ -17,7 +17,5 @@
     <solid android:color="@color/system_secondary_color" />
     <corners
         android:topLeftRadius="0dp"
-        android:topRightRadius="0dp"
-        android:bottomLeftRadius="@dimen/notification_material_rounded_rect_radius"
-        android:bottomRightRadius="@dimen/notification_material_rounded_rect_radius"/>
+        android:topRightRadius="0dp" />
 </shape>
diff --git a/packages/SystemUI/res/drawable/recents_dismiss_all_history.xml b/packages/SystemUI/res/drawable/recents_dismiss_all_history.xml
new file mode 100644
index 0000000..6a417e6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_dismiss_all_history.xml
@@ -0,0 +1,54 @@
+<!--
+Copyright (C) 2016 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="16dp"
+    android:width="28dp"
+    android:viewportHeight="48"
+    android:viewportWidth="72" >
+    <group
+        android:name="dismiss_all"
+        android:translateX="48"
+        android:translateY="6" >
+        <group
+            android:name="3"
+            android:translateX="-24"
+            android:translateY="36" >
+            <path
+                android:name="rectangle_path_1_2"
+                android:pathData="M -24.0,-6.0 l 48.0,0 l 0,12.0 l -48.0,0 Z"
+                android:fillColor="#FFFFFFFF"
+                android:fillAlpha="1" />
+        </group>
+        <group
+            android:name="2"
+            android:translateX="-12"
+            android:translateY="18" >
+            <path
+                android:name="rectangle_path_1_1"
+                android:pathData="M -24.0,-6.0 l 48.0,0 l 0,12.0 l -48.0,0 Z"
+                android:fillColor="#FFFFFFFF"
+                android:fillAlpha="1" />
+        </group>
+        <group
+            android:name="1" >
+            <path
+                android:name="rectangle_path_1"
+                android:pathData="M -24.0,-6.0 l 48.0,0 l 0,12.0 l -48.0,0 Z"
+                android:fillColor="#FFFFFFFF"
+                android:fillAlpha="1" />
+        </group>
+    </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/recents_info_dark.xml b/packages/SystemUI/res/drawable/recents_info_dark.xml
new file mode 100644
index 0000000..b1a2242
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_info_dark.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48.0dp"
+        android:height="48.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="@color/recents_task_bar_dark_icon_color"
+        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"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/recents_info_light.xml b/packages/SystemUI/res/drawable/recents_info_light.xml
new file mode 100644
index 0000000..bc58c3b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_info_light.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48.0dp"
+        android:height="48.0dp"
+        android:viewportWidth="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/stat_sys_auto_rotate_landscape.xml b/packages/SystemUI/res/drawable/stat_sys_auto_rotate_landscape.xml
new file mode 100644
index 0000000..ba0709e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_auto_rotate_landscape.xml
@@ -0,0 +1,66 @@
+<?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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:insetLeft="2.5dp"
+    android:insetRight="2.5dp">
+    <vector
+        android:height="17dp"
+        android:width="17dp"
+        android:viewportHeight="48"
+        android:viewportWidth="48" >
+        <group
+            android:name="ic_screen_rotation_48px_outlines"
+            android:translateX="24"
+            android:translateY="24" >
+            <group
+                android:name="ic_screen_rotation_48px_outlines_pivot"
+                android:translateX="-24.15"
+                android:translateY="-24.25" >
+                <group
+                    android:name="arrows"
+                    android:translateX="24.1"
+                    android:translateY="24.1" >
+                    <group
+                        android:name="arrows_pivot"
+                        android:translateX="-24.1"
+                        android:translateY="-24.1" >
+                        <path
+                            android:name="arrow_top"
+                            android:pathData="M 33.1499938965,5.25 c 6.5,3.10000610352 11.1999969482,9.40000915527 11.8999938965,17.0 c 0.0,0.0 3.00001525879,0.0 3.00001525879,0.0 c -1.00001525879,-12.3000030518 -11.3000030518,-22.0 -23.9000091553,-22.0 c -0.399993896484,0.0 -0.899993896484,0.0 -1.30000305176,0.100006103516 c 0.0,0.0 7.60000610352,7.59999084473 7.60000610352,7.59999084473 c 0.0,0.0 2.69999694824,-2.69999694824 2.69999694824,-2.69999694824 Z"
+                            android:fillColor="#FFFFFFFF"
+                            android:fillAlpha="1" />
+                        <path
+                            android:name="arrow_bottom"
+                            android:pathData="M 15.1499938965,43.25 c -6.5,-3.09999084473 -11.1999969482,-9.5 -11.8999938965,-17.0 c 0.0,0.0 -3.0,0.0 -3.0,0.0 c 1.0,12.3000030518 11.299987793,22.0 23.8999938965,22.0 c 0.399993896484,0.0 0.899993896484,0.0 1.30000305176,-0.0999908447266 c 0.0,0.0 -7.60000610352,-7.60000610352 -7.60000610352,-7.60000610352 c 0.0,0.0 -2.69999694824,2.69999694824 -2.69999694824,2.69999694824 Z"
+                            android:fillColor="#FFFFFFFF"
+                            android:fillAlpha="1" />
+                    </group>
+                </group>
+                <group
+                    android:name="device"
+                    android:translateX="24.14999"
+                    android:translateY="24.25" >
+                    <path
+                        android:name="body"
+                        android:pathData="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
+                        android:fillColor="#FFFFFFFF"
+                        android:fillAlpha="1" />
+                </group>
+            </group>
+        </group>
+    </vector>
+</inset>
diff --git a/packages/SystemUI/res/drawable/stat_sys_auto_rotate_portrait.xml b/packages/SystemUI/res/drawable/stat_sys_auto_rotate_portrait.xml
new file mode 100644
index 0000000..46a1f35
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_auto_rotate_portrait.xml
@@ -0,0 +1,66 @@
+<?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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:insetLeft="2.5dp"
+    android:insetRight="2.5dp">
+    <vector
+        android:height="17dp"
+        android:width="17dp"
+        android:viewportHeight="48"
+        android:viewportWidth="48" >
+        <group
+            android:name="icon"
+            android:translateX="24"
+            android:translateY="24" >
+            <group
+                android:name="icon_pivot"
+                android:translateX="-24.15"
+                android:translateY="-24.25" >
+                <group
+                    android:name="arrows"
+                    android:translateX="24.1"
+                    android:translateY="24.1" >
+                    <group
+                        android:name="arrows_pivot"
+                        android:translateX="-24.1"
+                        android:translateY="-24.1" >
+                        <path
+                            android:name="arrow_top"
+                            android:pathData="M 33.1499938965,5.25 c 6.5,3.10000610352 11.1999969482,9.40000915527 11.8999938965,17.0 c 0.0,0.0 3.00001525879,0.0 3.00001525879,0.0 c -1.00001525879,-12.3000030518 -11.3000030518,-22.0 -23.9000091553,-22.0 c -0.399993896484,0.0 -0.899993896484,0.0 -1.30000305176,0.100006103516 c 0.0,0.0 7.60000610352,7.59999084473 7.60000610352,7.59999084473 c 0.0,0.0 2.69999694824,-2.69999694824 2.69999694824,-2.69999694824 Z"
+                            android:fillColor="#FFFFFFFF"
+                            android:fillAlpha="1" />
+                        <path
+                            android:name="arrow_bottom"
+                            android:pathData="M 15.1499938965,43.25 c -6.5,-3.09999084473 -11.1999969482,-9.5 -11.8999938965,-17.0 c 0.0,0.0 -3.0,0.0 -3.0,0.0 c 1.0,12.3000030518 11.299987793,22.0 23.8999938965,22.0 c 0.399993896484,0.0 0.899993896484,0.0 1.30000305176,-0.0999908447266 c 0.0,0.0 -7.60000610352,-7.60000610352 -7.60000610352,-7.60000610352 c 0.0,0.0 -2.69999694824,2.69999694824 -2.69999694824,2.69999694824 Z"
+                            android:fillColor="#FFFFFFFF"
+                            android:fillAlpha="1" />
+                    </group>
+                </group>
+                <group
+                    android:name="device"
+                    android:translateX="24.14999"
+                    android:translateY="24.25" >
+                    <path
+                        android:name="device_1"
+                        android:pathData="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
+                        android:fillColor="#FFFFFFFF"
+                        android:fillAlpha="1" />
+                </group>
+            </group>
+        </group>
+    </vector>
+</inset>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml b/packages/SystemUI/res/drawable/stat_sys_data_disabled.xml
new file mode 100644
index 0000000..4e2a024
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_data_disabled.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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="17.0dp"
+        android:height="17.0dp"
+        android:viewportWidth="40.0"
+        android:viewportHeight="40.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M19.0,6.41L17.59,5.0 12.0,10.59 6.41,5.0 5.0,6.41 10.59,12.0 5.0,17.59 6.41,19.0 12.0,13.41 17.59,19.0 19.0,17.59 13.41,12.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_rotate_landscape.xml b/packages/SystemUI/res/drawable/stat_sys_rotate_landscape.xml
new file mode 100644
index 0000000..58ed7e6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_rotate_landscape.xml
@@ -0,0 +1,70 @@
+<?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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:insetLeft="2.5dp"
+    android:insetRight="2.5dp">
+    <vector
+        android:height="17dp"
+        android:width="17dp"
+        android:viewportHeight="48"
+        android:viewportWidth="48" >
+        <group
+            android:name="ic_screen_rotation_48px_outlines"
+            android:translateX="24"
+            android:translateY="24" >
+            <group
+                android:name="ic_screen_rotation_48px_outlines_pivot"
+                android:translateX="-24.15"
+                android:translateY="-24.25" >
+                <group
+                    android:name="arrows"
+                    android:translateX="24.1"
+                    android:translateY="24.1"
+                    android:scaleX="0.9"
+                    android:scaleY="0.9"
+                    android:rotation="-135" >
+                    <group
+                        android:name="arrows_pivot"
+                        android:translateX="-24.1"
+                        android:translateY="-24.1" >
+                        <path
+                            android:name="arrow_top"
+                            android:pathData="M 33.1499938965,5.25 c 6.5,3.10000610352 11.1999969482,9.40000915527 11.8999938965,17.0 c 0.0,0.0 3.00001525879,0.0 3.00001525879,0.0 c -1.00001525879,-12.3000030518 -11.3000030518,-22.0 -23.9000091553,-22.0 c -0.399993896484,0.0 -0.899993896484,0.0 -1.30000305176,0.100006103516 c 0.0,0.0 7.60000610352,7.59999084473 7.60000610352,7.59999084473 c 0.0,0.0 2.69999694824,-2.69999694824 2.69999694824,-2.69999694824 Z"
+                            android:fillColor="#FFFFFFFF"
+                            android:fillAlpha="0" />
+                        <path
+                            android:name="arrow_bottom"
+                            android:pathData="M 15.1499938965,43.25 c -6.5,-3.09999084473 -11.1999969482,-9.5 -11.8999938965,-17.0 c 0.0,0.0 -3.0,0.0 -3.0,0.0 c 1.0,12.3000030518 11.299987793,22.0 23.8999938965,22.0 c 0.399993896484,0.0 0.899993896484,0.0 1.30000305176,-0.0999908447266 c 0.0,0.0 -7.60000610352,-7.60000610352 -7.60000610352,-7.60000610352 c 0.0,0.0 -2.69999694824,2.69999694824 -2.69999694824,2.69999694824 Z"
+                            android:fillColor="#FFFFFFFF"
+                            android:fillAlpha="0" />
+                    </group>
+                </group>
+                <group
+                    android:name="device"
+                    android:translateX="24.14999"
+                    android:translateY="24.25"
+                    android:rotation="-45" >
+                    <path
+                        android:name="body"
+                        android:pathData="M -3.34053039551,-22.9980926514 c -1.3207244873,-1.3207244873 -3.46876525879,-1.26383972168 -4.74829101563,0.125762939453 c 0.0,0.0 -14.8512420654,14.7411804199 -14.8512420654,14.7411804199 c -1.39259338379,1.392578125 -1.44947814941,3.54061889648 -0.125762939453,4.74827575684 c 0.0,0.0 26.4143981934,26.4144134521 26.4143981934,26.4144134521 c 1.3207244873,1.3207244873 3.46876525879,1.26382446289 4.74829101562,-0.125762939453 c 0.0,0.0 14.7381896973,-14.7381896973 14.7381896973,-14.7381896973 c 1.392578125,-1.39259338379 1.44947814941,-3.54061889648 0.125762939453,-4.74829101562 c 0.0,0.0 -26.3013458252,-26.417388916 -26.3013458252,-26.417388916 Z M 2.87156677246,16.9857940674 c 0.0,0.0 -19.7573547363,-19.7573699951 -19.7573547363,-19.7573699951 c 0.0,0.0 14.0142059326,-14.2142181396 14.0142059326,-14.2142181396 c 0.0,0.0 19.7573699951,19.7573699951 19.7573699951,19.7573699951 c 0.0,0.0 -14.0142211914,14.2142181396 -14.0142211914,14.2142181396 Z"
+                        android:fillColor="#FFFFFFFF"
+                        android:fillAlpha="1" />
+                </group>
+            </group>
+        </group>
+    </vector>
+</inset>
diff --git a/packages/SystemUI/res/drawable/stat_sys_rotate_portrait.xml b/packages/SystemUI/res/drawable/stat_sys_rotate_portrait.xml
new file mode 100644
index 0000000..b63ffe0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_rotate_portrait.xml
@@ -0,0 +1,70 @@
+<?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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:insetLeft="2.5dp"
+    android:insetRight="2.5dp">
+    <vector
+        android:height="17dp"
+        android:width="17dp"
+        android:viewportHeight="48"
+        android:viewportWidth="48" >
+        <group
+            android:name="icon"
+            android:translateX="24"
+            android:translateY="24" >
+            <group
+                android:name="icon_pivot"
+                android:translateX="-24.15"
+                android:translateY="-24.25" >
+                <group
+                    android:name="arrows"
+                    android:translateX="24.1"
+                    android:translateY="24.1"
+                    android:scaleX="0.9"
+                    android:scaleY="0.9"
+                    android:rotation="-221" >
+                    <group
+                        android:name="arrows_pivot"
+                        android:translateX="-24.1"
+                        android:translateY="-24.1" >
+                        <path
+                            android:name="arrow_top"
+                            android:pathData="M 33.1499938965,5.25 c 6.5,3.10000610352 11.1999969482,9.40000915527 11.8999938965,17.0 c 0.0,0.0 3.00001525879,0.0 3.00001525879,0.0 c -1.00001525879,-12.3000030518 -11.3000030518,-22.0 -23.9000091553,-22.0 c -0.399993896484,0.0 -0.899993896484,0.0 -1.30000305176,0.100006103516 c 0.0,0.0 7.60000610352,7.59999084473 7.60000610352,7.59999084473 c 0.0,0.0 2.69999694824,-2.69999694824 2.69999694824,-2.69999694824 Z"
+                            android:fillColor="#FFFFFFFF"
+                            android:fillAlpha="0" />
+                        <path
+                            android:name="arrow_bottom"
+                            android:pathData="M 15.1499938965,43.25 c -6.5,-3.09999084473 -11.1999969482,-9.5 -11.8999938965,-17.0 c 0.0,0.0 -3.0,0.0 -3.0,0.0 c 1.0,12.3000030518 11.299987793,22.0 23.8999938965,22.0 c 0.399993896484,0.0 0.899993896484,0.0 1.30000305176,-0.0999908447266 c 0.0,0.0 -7.60000610352,-7.60000610352 -7.60000610352,-7.60000610352 c 0.0,0.0 -2.69999694824,2.69999694824 -2.69999694824,2.69999694824 Z"
+                            android:fillColor="#FFFFFFFF"
+                            android:fillAlpha="0" />
+                    </group>
+                </group>
+                <group
+                    android:name="device"
+                    android:translateX="24.14999"
+                    android:translateY="24.25"
+                    android:rotation="-135" >
+                    <path
+                        android:name="device_1"
+                        android:pathData="M -3.34053039551,-22.9980926514 c -1.3207244873,-1.3207244873 -3.46876525879,-1.26383972168 -4.74829101563,0.125762939453 c 0.0,0.0 -14.8512420654,14.7411804199 -14.8512420654,14.7411804199 c -1.39259338379,1.392578125 -1.44947814941,3.54061889648 -0.125762939453,4.74827575684 c 0.0,0.0 26.4143981934,26.4144134521 26.4143981934,26.4144134521 c 1.3207244873,1.3207244873 3.46876525879,1.26382446289 4.74829101562,-0.125762939453 c 0.0,0.0 14.7381896973,-14.7381896973 14.7381896973,-14.7381896973 c 1.392578125,-1.39259338379 1.44947814941,-3.54061889648 0.125762939453,-4.74829101562 c 0.0,0.0 -26.3013458252,-26.417388916 -26.3013458252,-26.417388916 Z M 2.87156677246,16.9857940674 c 0.0,0.0 -19.7573547363,-19.7573699951 -19.7573547363,-19.7573699951 c 0.0,0.0 14.0142059326,-14.2142181396 14.0142059326,-14.2142181396 c 0.0,0.0 19.7573699951,19.7573699951 19.7573699951,19.7573699951 c 0.0,0.0 -14.0142211914,14.2142181396 -14.0142211914,14.2142181396 Z"
+                        android:fillColor="#FFFFFFFF"
+                        android:fillAlpha="1" />
+                </group>
+            </group>
+        </group>
+    </vector>
+</inset>
diff --git a/packages/SystemUI/res/drawable/switchbar_background.xml b/packages/SystemUI/res/drawable/switchbar_background.xml
new file mode 100644
index 0000000..8d97c46
--- /dev/null
+++ b/packages/SystemUI/res/drawable/switchbar_background.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.
+-->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="?android:attr/colorControlHighlight">
+    <item android:drawable="@color/switch_bar_background" />
+</ripple>
+
diff --git a/packages/SystemUI/res/drawable/volume_dialog_background.xml b/packages/SystemUI/res/drawable/volume_dialog_background.xml
index f09c01b..e98bfb8 100644
--- a/packages/SystemUI/res/drawable/volume_dialog_background.xml
+++ b/packages/SystemUI/res/drawable/volume_dialog_background.xml
@@ -14,9 +14,5 @@
      limitations under the License.
 -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android" >
-
     <solid android:color="@color/system_primary_color" />
-
-    <corners android:radius="@dimen/notification_material_rounded_rect_radius" />
-
 </shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-land/nav_bar_tuner.xml b/packages/SystemUI/res/layout-land/nav_bar_tuner.xml
new file mode 100644
index 0000000..a430b73
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/nav_bar_tuner.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"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal">
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:elevation="4dp"
+        android:paddingTop="12dp"
+        android:paddingBottom="12dp"
+        android:paddingStart="8dp"
+        android:paddingEnd="8dp"
+        android:background="@android:color/white"
+        android:gravity="center"
+        android:orientation="vertical">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/preview"
+            android:paddingStart="8dp"
+            android:paddingEnd="8dp"
+            android:textColor="?android:attr/colorAccent"
+            android:textAppearance="?android:attr/textAppearanceMedium" />
+
+        <FrameLayout
+            android:id="@+id/nav_preview_frame"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+    </LinearLayout>
+
+    <android.support.v7.widget.RecyclerView
+        android:id="@android:id/list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout-sw600dp-land/nav_bar_tuner.xml b/packages/SystemUI/res/layout-sw600dp-land/nav_bar_tuner.xml
new file mode 100644
index 0000000..5479157
--- /dev/null
+++ b/packages/SystemUI/res/layout-sw600dp-land/nav_bar_tuner.xml
@@ -0,0 +1,57 @@
+<?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:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:elevation="4dp"
+        android:paddingTop="8dp"
+        android:paddingBottom="8dp"
+        android:paddingStart="12dp"
+        android:paddingEnd="12dp"
+        android:layout_gravity="bottom"
+        android:background="@android:color/white"
+        android:gravity="center"
+        android:orientation="vertical">
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/preview"
+            android:paddingTop="8dp"
+            android:paddingBottom="8dp"
+            android:textColor="?android:attr/colorAccent"
+            android:textAppearance="?android:attr/textAppearanceLarge" />
+
+        <FrameLayout
+            android:id="@+id/nav_preview_frame"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+    </LinearLayout>
+
+    <android.support.v7.widget.RecyclerView
+        android:id="@android:id/list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
deleted file mode 100644
index 1fcb2df..0000000
--- a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
+++ /dev/null
@@ -1,322 +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.
--->
-
-<!--  navigation bar for sw600dp (small tablets) -->
-<com.android.systemui.statusbar.phone.NavigationBarView
-    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="match_parent"
-    android:background="@drawable/system_bar_background"
-    >
-
-    <FrameLayout android:id="@+id/rot0"
-        android:layout_height="match_parent"
-        android:layout_width="match_parent"
-        >
-
-        <LinearLayout
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            android:orientation="horizontal"
-            android:clipChildren="false"
-            android:clipToPadding="false"
-            android:id="@+id/nav_buttons"
-            android:animateLayoutChanges="true"
-            >
-
-            <!-- navigation controls -->
-            <View
-                android:layout_width="@dimen/navigation_extra_key_width"
-                android:layout_height="match_parent"
-                android:layout_weight="0"
-                android:layout_marginStart="2dp"
-                android:visibility="invisible"
-                />
-            <Space
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
-                android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_back"
-                android:scaleType="centerInside"
-                systemui:keyCode="4"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_back"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
-                android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_home"
-                android:scaleType="centerInside"
-                systemui:keyCode="3"
-                systemui:keyRepeat="true"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_home"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
-                android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_recent"
-                android:scaleType="centerInside"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_recent"
-                />
-            <Space
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                />
-            <FrameLayout
-                android:layout_width="@dimen/navigation_extra_key_width"
-                android:layout_height="match_parent"
-                android:layout_weight="0"
-                android:layout_marginEnd="2dp" >
-                <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
-                    android:layout_width="@dimen/navigation_extra_key_width"
-                    android:layout_height="match_parent"
-                    android:src="@drawable/ic_sysbar_menu"
-                    android:scaleType="centerInside"
-                    android:layout_marginEnd="2dp"
-                    systemui:keyCode="82"
-                    android:visibility="invisible"
-                    android:contentDescription="@string/accessibility_menu"
-                    />
-                <com.android.systemui.statusbar.policy.KeyButtonView
-                    android:id="@+id/ime_switcher"
-                    android:layout_width="@dimen/navigation_extra_key_width"
-                    android:layout_height="match_parent"
-                    android:layout_marginEnd="2dp"
-                    android:scaleType="centerInside"
-                    android:src="@drawable/ic_ime_switcher_default"
-                    android:visibility="invisible"
-                    android:contentDescription="@string/accessibility_ime_switch_button" />
-            </FrameLayout>
-        </LinearLayout>
-
-        <!-- lights out layout to match exactly -->
-        <LinearLayout
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            android:orientation="horizontal"
-            android:id="@+id/lights_out"
-            android:visibility="gone"
-            >
-            <Space
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                />
-            <ImageView
-                android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
-                android:layout_height="match_parent"
-                android:layout_marginStart="40dp"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_back"
-                />
-            <ImageView
-                android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_large"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_home"
-                />
-            <ImageView
-                android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
-                android:layout_marginEnd="40dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_recent"
-                />
-            <Space
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                />
-        </LinearLayout>
-
-        <com.android.systemui.statusbar.policy.DeadZone
-            android:id="@+id/deadzone"
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            systemui:minSize="@dimen/navigation_bar_deadzone_size"
-            systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"
-            systemui:holdTime="@integer/navigation_bar_deadzone_hold"
-            systemui:decayTime="@integer/navigation_bar_deadzone_decay"
-            systemui:orientation="horizontal"
-            android:layout_gravity="top"
-            />
-    </FrameLayout>
-
-    <FrameLayout android:id="@+id/rot90"
-        android:layout_height="match_parent"
-        android:layout_width="match_parent"
-        android:visibility="gone"
-        android:paddingTop="0dp"
-        >
-
-        <LinearLayout
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            android:orientation="horizontal"
-            android:clipChildren="false"
-            android:clipToPadding="false"
-            android:id="@+id/nav_buttons"
-            android:animateLayoutChanges="true"
-            >
-
-            <!-- navigation controls -->
-            <View
-                android:layout_width="@dimen/navigation_extra_key_width"
-                android:layout_height="match_parent"
-                android:layout_weight="0"
-                android:layout_marginStart="2dp"
-                android:visibility="invisible"
-                />
-            <Space
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
-                android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_back"
-                android:scaleType="centerInside"
-                systemui:keyCode="4"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_back"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
-                android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_home"
-                android:scaleType="centerInside"
-                systemui:keyCode="3"
-                systemui:keyRepeat="true"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_home"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
-                android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_recent"
-                android:scaleType="centerInside"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_recent"
-                />
-            <Space
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                />
-            <FrameLayout
-                android:layout_width="@dimen/navigation_extra_key_width"
-                android:layout_height="match_parent"
-                android:layout_marginEnd="2dp"
-                android:layout_weight="0" >
-                <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
-                    android:layout_width="@dimen/navigation_extra_key_width"
-                    android:layout_height="match_parent"
-                    android:layout_marginEnd="2dp"
-                    android:src="@drawable/ic_sysbar_menu"
-                    android:scaleType="centerInside"
-                    systemui:keyCode="82"
-                    android:visibility="invisible"
-                    android:contentDescription="@string/accessibility_menu" />
-                <com.android.systemui.statusbar.policy.KeyButtonView
-                    android:id="@+id/ime_switcher"
-                    android:layout_width="@dimen/navigation_extra_key_width"
-                    android:layout_height="match_parent"
-                    android:layout_marginEnd="2dp"
-                    android:src="@drawable/ic_ime_switcher_default"
-                    android:visibility="invisible"
-                    android:contentDescription="@string/accessibility_ime_switch_button"
-                    android:scaleType="centerInside" />
-            </FrameLayout>
-        </LinearLayout>
-
-        <!-- lights out layout to match exactly -->
-        <LinearLayout
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            android:orientation="horizontal"
-            android:id="@+id/lights_out"
-            android:visibility="gone"
-            >
-            <Space
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                />
-            <ImageView
-                android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
-                android:layout_height="match_parent"
-                android:layout_marginStart="40dp"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_back"
-                />
-            <ImageView
-                android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_large"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_home"
-                />
-            <ImageView
-                android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
-                android:layout_marginEnd="40dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_recent"
-                />
-            <Space
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                />
-        </LinearLayout>
-
-        <!-- On tablets in landscape the navbar is on the bottom, so use a
-             horizontal dead zone. -->
-        <com.android.systemui.statusbar.policy.DeadZone
-            android:id="@+id/deadzone"
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            systemui:minSize="@dimen/navigation_bar_deadzone_size"
-            systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"
-            systemui:holdTime="@integer/navigation_bar_deadzone_hold"
-            systemui:decayTime="@integer/navigation_bar_deadzone_decay"
-            systemui:orientation="horizontal"
-            android:layout_gravity="top"
-            />
-    </FrameLayout>
-</com.android.systemui.statusbar.phone.NavigationBarView>
diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml b/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml
new file mode 100644
index 0000000..38265f6
--- /dev/null
+++ b/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml
@@ -0,0 +1,74 @@
+<?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"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <FrameLayout
+        android:id="@+id/nav_buttons"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <LinearLayout
+            android:id="@+id/ends_group"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="horizontal" />
+
+        <LinearLayout
+            android:id="@+id/center_group"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center"
+            android:orientation="horizontal" />
+
+    </FrameLayout>
+
+    <FrameLayout
+        android:id="@+id/lights_out"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <LinearLayout
+            android:id="@+id/ends_group_lightsout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="horizontal" />
+
+        <LinearLayout
+            android:id="@+id/center_group_lightsout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center"
+            android:orientation="horizontal" />
+
+    </FrameLayout>
+
+    <com.android.systemui.statusbar.policy.DeadZone
+        android:id="@+id/deadzone"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:layout_gravity="top"
+        systemui:minSize="@dimen/navigation_bar_deadzone_size"
+        systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"
+        systemui:holdTime="@integer/navigation_bar_deadzone_hold"
+        systemui:decayTime="@integer/navigation_bar_deadzone_decay"
+        systemui:orientation="horizontal"
+        />
+
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/assist_orb.xml b/packages/SystemUI/res/layout/assist_orb.xml
index ab0a0a5..0036ed6 100644
--- a/packages/SystemUI/res/layout/assist_orb.xml
+++ b/packages/SystemUI/res/layout/assist_orb.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
 **
 ** Copyright 2012, The Android Open Source Project
 **
diff --git a/packages/SystemUI/res/layout/back.xml b/packages/SystemUI/res/layout/back.xml
new file mode 100644
index 0000000..d256622
--- /dev/null
+++ b/packages/SystemUI/res/layout/back.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.
+-->
+
+<com.android.systemui.statusbar.policy.KeyButtonView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/back"
+    android:layout_width="@dimen/navigation_key_width"
+    android:layout_height="match_parent"
+    android:layout_weight="0"
+    android:src="@drawable/ic_sysbar_back"
+    systemui:keyCode="4"
+    android:scaleType="center"
+    android:contentDescription="@string/accessibility_back"
+    android:paddingStart="@dimen/navigation_key_padding"
+    android:paddingEnd="@dimen/navigation_key_padding"
+    />
+
diff --git a/packages/SystemUI/res/layout/battery_detail.xml b/packages/SystemUI/res/layout/battery_detail.xml
new file mode 100644
index 0000000..ea4db4b
--- /dev/null
+++ b/packages/SystemUI/res/layout/battery_detail.xml
@@ -0,0 +1,64 @@
+<?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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingTop="16dp"
+    android:background="?android:attr/selectableItemBackground"
+    android:clickable="true">
+
+    <ImageView
+        android:id="@android:id/icon"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:scaleType="fitCenter"
+        android:adjustViewBounds="true"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentStart="true"
+        android:layout_marginStart="16dp"
+        android:layout_marginEnd="32dp" />
+
+    <TextView
+        android:id="@android:id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_toStartOf="@android:id/toggle"
+        android:layout_toEndOf="@android:id/icon"
+        android:textAppearance="@style/TextAppearance.QS.DetailItemPrimary"
+        android:text="@string/battery_detail_switch_title" />
+
+    <TextView
+        android:id="@android:id/summary"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@android:id/title"
+        android:layout_toStartOf="@android:id/toggle"
+        android:layout_toEndOf="@android:id/icon"
+        android:textAppearance="@style/TextAppearance.QS.DetailItemSecondary"
+        android:text="@string/battery_detail_switch_summary" />
+
+    <Switch
+        android:id="@android:id/toggle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentEnd="true"
+        android:layout_alignParentTop="true"
+        android:layout_marginEnd="16dp"
+        android:clickable="false"
+        android:textAppearance="@style/TextAppearance.QS.DetailHeader" />
+
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml b/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
new file mode 100644
index 0000000..b7e666f
--- /dev/null
+++ b/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
@@ -0,0 +1,38 @@
+<?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 -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:gravity="top|center_horizontal"
+    android:layout_width="180dp"
+    android:layout_height="wrap_content">
+
+    <ImageView android:id="@+id/user_avatar"
+               android:padding="10dp"
+               android:layout_gravity="center"
+               android:layout_width="@dimen/car_fullscreen_user_pod_image_avatar_width"
+               android:layout_height="@dimen/car_fullscreen_user_pod_image_avatar_height" />
+
+    <TextView android:id="@+id/user_name"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:textSize="@dimen/car_fullscreen_user_pod_text_size"
+              android:textColor="@color/qs_user_detail_name"
+              android:gravity="center_horizontal" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml b/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
new file mode 100644
index 0000000..6e4b213
--- /dev/null
+++ b/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+             android:fitsSystemWindows="true"
+             android:layout_width="match_parent"
+             android:layout_height="match_parent"
+             android:visibility="gone">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/car_lockscreen_disclaimer_title"
+            android:textSize="@dimen/car_lockscreen_disclaimer_title_size"
+            android:paddingStart="@dimen/car_lockscreen_disclaimer_title_padding_start"
+            android:paddingTop="@dimen/car_lockscreen_disclaimer_title_padding_top" />
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:text="@string/car_lockscreen_disclaimer_text"
+            android:textSize="@dimen/car_lockscreen_disclaimer_text_size"
+            android:paddingStart="@dimen/car_lockscreen_disclaimer_text_padding_start"
+            android:paddingEnd="@dimen/car_lockscreen_disclaimer_text_padding_end"
+            android:paddingTop="@dimen/car_lockscreen_disclaimer_text_padding_top" />
+        <com.android.systemui.statusbar.car.UserGridView
+            android:id="@+id/user_grid"
+            android:layout_gravity="center"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:stretchMode="columnWidth">
+        </com.android.systemui.statusbar.car.UserGridView>
+    </LinearLayout>
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/car_navigation_bar.xml b/packages/SystemUI/res/layout/car_navigation_bar.xml
new file mode 100644
index 0000000..f7f673d
--- /dev/null
+++ b/packages/SystemUI/res/layout/car_navigation_bar.xml
@@ -0,0 +1,51 @@
+<?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.
+*/
+-->
+
+<com.android.systemui.statusbar.car.CarNavigationBarView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    android:background="@drawable/system_bar_background">
+
+    <!-- phone.NavigationBarView has rot0 and rot90 but we expect the car head unit to have a fixed
+         rotation so skip this level of the heirarchy.
+    -->
+    <LinearLayout
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:orientation="horizontal"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:id="@+id/nav_buttons"
+        android:animateLayoutChanges="true">
+
+        <!-- Buttons get populated here from a car_arrays.xml. -->
+    </LinearLayout>
+
+    <!-- lights out layout to match exactly -->
+    <LinearLayout
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:orientation="horizontal"
+        android:id="@+id/lights_out"
+        android:visibility="gone">
+        <!-- Must match nav_buttons. -->
+    </LinearLayout>
+
+</com.android.systemui.statusbar.car.CarNavigationBarView>
diff --git a/packages/SystemUI/res/layout/car_navigation_button.xml b/packages/SystemUI/res/layout/car_navigation_button.xml
new file mode 100644
index 0000000..7677646
--- /dev/null
+++ b/packages/SystemUI/res/layout/car_navigation_button.xml
@@ -0,0 +1,44 @@
+<?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.
+*/
+-->
+
+<com.android.systemui.statusbar.car.CarNavigationButton
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_height="match_parent"
+        android:layout_width="wrap_content"
+        android:orientation="horizontal"
+        android:background="?android:attr/selectableItemBackground">
+    <com.android.keyguard.AlphaOptimizedImageButton
+            android:id="@+id/car_nav_button_icon"
+            android:layout_height="match_parent"
+            android:layout_width="@dimen/car_navigation_button_width"
+            android:layout_centerInParent="true"
+            android:animateLayoutChanges="true"
+            android:scaleType="fitCenter">
+    </com.android.keyguard.AlphaOptimizedImageButton>
+
+    <com.android.keyguard.AlphaOptimizedImageButton
+            android:id="@+id/car_nav_button_more_icon"
+            android:layout_height="match_parent"
+            android:layout_width="wrap_content"
+            android:layout_centerVertical="true"
+            android:layout_toRightOf="@+id/car_nav_button_icon"
+            android:animateLayoutChanges="true"
+            android:scaleType="fitCenter">
+    </com.android.keyguard.AlphaOptimizedImageButton>
+</com.android.systemui.statusbar.car.CarNavigationButton>
diff --git a/packages/SystemUI/res/layout/clipboard.xml b/packages/SystemUI/res/layout/clipboard.xml
new file mode 100644
index 0000000..441d6737
--- /dev/null
+++ b/packages/SystemUI/res/layout/clipboard.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.
+-->
+<com.android.systemui.tuner.ClipboardView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="@dimen/navigation_side_padding"
+    android:layout_height="match_parent"
+    android:layout_weight="0"
+    android:scaleType="center"
+    android:contentDescription="@string/clipboard"
+    />
+
diff --git a/packages/SystemUI/res/layout/color_matrix_settings.xml b/packages/SystemUI/res/layout/color_matrix_settings.xml
new file mode 100644
index 0000000..3725e78
--- /dev/null
+++ b/packages/SystemUI/res/layout/color_matrix_settings.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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <include layout="@layout/switch_bar" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/custom_key.xml b/packages/SystemUI/res/layout/custom_key.xml
new file mode 100644
index 0000000..0b5cb72
--- /dev/null
+++ b/packages/SystemUI/res/layout/custom_key.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.
+-->
+<com.android.systemui.statusbar.policy.KeyButtonView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="@dimen/navigation_side_padding"
+    android:layout_height="match_parent"
+    android:layout_weight="0"
+    android:scaleType="center"
+    android:tint="@android:color/white"
+    android:contentDescription="@string/accessibility_key" />
+
diff --git a/packages/SystemUI/res/layout/docked_stack_divider.xml b/packages/SystemUI/res/layout/docked_stack_divider.xml
index 22ed216..7ea5027 100644
--- a/packages/SystemUI/res/layout/docked_stack_divider.xml
+++ b/packages/SystemUI/res/layout/docked_stack_divider.xml
@@ -24,10 +24,9 @@
         android:id="@+id/docked_divider_background"
         android:background="@color/docked_divider_background"/>
 
-    <ImageButton
+    <com.android.systemui.stackdivider.DividerHandleView
         style="@style/DockedDividerHandle"
         android:id="@+id/docked_divider_handle"
-        android:background="@null"
-        android:src="@drawable/docked_divider_handle"/>
+        android:background="@null"/>
 
 </com.android.systemui.stackdivider.DividerView>
diff --git a/packages/SystemUI/res/layout/fullscreen_user_pod.xml b/packages/SystemUI/res/layout/fullscreen_user_pod.xml
deleted file mode 100644
index 12f0a80..0000000
--- a/packages/SystemUI/res/layout/fullscreen_user_pod.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.
--->
-
-<!--  LinearLayout -->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:gravity="top|center_horizontal"
-    android:layout_width="180dp"
-    android:layout_height="wrap_content">
-
-    <ImageView android:id="@+id/user_avatar"
-               android:padding="10dp"
-               android:layout_gravity="center"
-               android:layout_width="160dp"
-               android:layout_height="160dp" />
-
-    <TextView android:id="@+id/user_name"
-              android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:textSize="@dimen/qs_detail_item_secondary_text_size"
-              android:textColor="@color/qs_user_detail_name"
-              android:gravity="center_horizontal" />
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/fullscreen_user_switcher.xml b/packages/SystemUI/res/layout/fullscreen_user_switcher.xml
deleted file mode 100644
index 46c1896..0000000
--- a/packages/SystemUI/res/layout/fullscreen_user_switcher.xml
+++ /dev/null
@@ -1,36 +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.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-             android:fitsSystemWindows="true"
-             android:layout_width="match_parent"
-             android:layout_height="match_parent"
-             android:visibility="gone">
-    <com.android.systemui.statusbar.UserGridView
-        android:id="@+id/user_grid"
-        android:layout_gravity="center"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:paddingStart="10dp"
-        android:paddingEnd="10dp"
-        android:columnWidth="180dp"
-        android:verticalSpacing="10dp"
-        android:horizontalSpacing="10dp"
-        android:stretchMode="columnWidth"
-        android:gravity="center">
-    </com.android.systemui.statusbar.UserGridView>
-</FrameLayout>
diff --git a/packages/SystemUI/res/layout/home.xml b/packages/SystemUI/res/layout/home.xml
new file mode 100644
index 0000000..f11592d
--- /dev/null
+++ b/packages/SystemUI/res/layout/home.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.
+-->
+<com.android.systemui.statusbar.policy.KeyButtonView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/home"
+    android:layout_width="@dimen/navigation_key_width"
+    android:layout_height="match_parent"
+    android:layout_weight="0"
+    android:src="@drawable/ic_sysbar_home"
+    systemui:keyCode="3"
+    android:scaleType="center"
+    android:contentDescription="@string/accessibility_home"
+    android:paddingStart="@dimen/navigation_key_padding"
+    android:paddingEnd="@dimen/navigation_key_padding"
+    />
+
diff --git a/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml b/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml
new file mode 100644
index 0000000..5a6553f
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcut_app_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
+  -->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/keyboard_shortcuts_keyword_wrapper"
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="24dp"
+        android:paddingEnd="24dp"
+        android:paddingBottom="8dp">
+    <TextView
+            android:id="@+id/keyboard_shortcuts_keyword"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingEnd="12dp"
+            android:background="@android:color/white"
+            android:textColor="#D9000000"
+            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: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"/>
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml
new file mode 100644
index 0000000..80a478a
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.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
+  -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="match_parent"
+          android:layout_height="match_parent"
+          android:textSize="14sp"
+          android:paddingStart="24dp"
+          android:paddingTop="20dp"
+          android:paddingEnd="24dp"
+          android:paddingBottom="13dp" />
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_container.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_container.xml
new file mode 100644
index 0000000..fa07eb1
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_container.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"
+              android:orientation="horizontal"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content">
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml
new file mode 100644
index 0000000..5002c12
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.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
+  -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:layout_marginStart="4dp"
+          android:padding="4dp"
+          android:background="#EEEEEE"
+          android:textColor="#8C000000"
+          android:singleLine="true"
+          android:textSize="14sp"/>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
new file mode 100644
index 0000000..77b1264
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_view.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:id="@+id/keyboard_shortcuts_wrapper"
+        android:layout_width="488dp"
+        android:layout_height="wrap_content"
+        android:focusable="true">
+    <ScrollView
+            android:id="@+id/keyboard_shortcuts_scroll_view"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_weight="1">
+        <LinearLayout
+                android:id="@+id/keyboard_shortcuts_container"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"/>
+    </ScrollView>
+    <View
+            android:layout_width="match_parent"
+            android:layout_height="1dp"
+            android:background="?android:attr/listDivider"/>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_wrapper.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_wrapper.xml
new file mode 100644
index 0000000..802acfe
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_wrapper.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"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content">
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
index 2e67376..c6e453a 100644
--- a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
+++ b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
@@ -43,4 +43,4 @@
             sysui:frameWidth="@dimen/keyguard_user_switcher_border_thickness"
             sysui:framePadding="6dp"
             sysui:activeFrameColor="@color/current_user_border_color" />
-</com.android.systemui.qs.tiles.UserDetailItemView>
\ No newline at end of file
+</com.android.systemui.qs.tiles.UserDetailItemView>
diff --git a/packages/SystemUI/res/layout/menu_ime.xml b/packages/SystemUI/res/layout/menu_ime.xml
new file mode 100644
index 0000000..90b74d0
--- /dev/null
+++ b/packages/SystemUI/res/layout/menu_ime.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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="@dimen/navigation_side_padding"
+    android:layout_height="match_parent"
+    android:layout_weight="0"
+    >
+    <com.android.systemui.statusbar.policy.KeyButtonView
+        android:id="@+id/menu"
+        android:layout_width="@dimen/navigation_extra_key_width"
+        android:layout_height="match_parent"
+        android:layout_marginEnd="2dp"
+        android:src="@drawable/ic_sysbar_menu"
+        android:scaleType="centerInside"
+        systemui:keyCode="82"
+        android:visibility="invisible"
+        android:contentDescription="@string/accessibility_menu"
+        />
+    <com.android.systemui.statusbar.policy.KeyButtonView
+        android:id="@+id/ime_switcher"
+        android:layout_width="@dimen/navigation_extra_key_width"
+        android:layout_height="match_parent"
+        android:layout_marginEnd="2dp"
+        android:src="@drawable/ic_ime_switcher_default"
+        android:visibility="invisible"
+        android:contentDescription="@string/accessibility_ime_switch_button"
+        android:scaleType="centerInside"
+        />
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml
index 6ae5cf3..a20ec8e 100644
--- a/packages/SystemUI/res/layout/mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/mobile_signal_group.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
 **
 ** Copyright 2011, The Android Open Source Project
 **
diff --git a/packages/SystemUI/res/layout/nav_bar_tuner.xml b/packages/SystemUI/res/layout/nav_bar_tuner.xml
new file mode 100644
index 0000000..5479157
--- /dev/null
+++ b/packages/SystemUI/res/layout/nav_bar_tuner.xml
@@ -0,0 +1,57 @@
+<?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:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:elevation="4dp"
+        android:paddingTop="8dp"
+        android:paddingBottom="8dp"
+        android:paddingStart="12dp"
+        android:paddingEnd="12dp"
+        android:layout_gravity="bottom"
+        android:background="@android:color/white"
+        android:gravity="center"
+        android:orientation="vertical">
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/preview"
+            android:paddingTop="8dp"
+            android:paddingBottom="8dp"
+            android:textColor="?android:attr/colorAccent"
+            android:textAppearance="?android:attr/textAppearanceLarge" />
+
+        <FrameLayout
+            android:id="@+id/nav_preview_frame"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+    </LinearLayout>
+
+    <android.support.v7.widget.RecyclerView
+        android:id="@android:id/list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/nav_bar_tuner_inflater.xml b/packages/SystemUI/res/layout/nav_bar_tuner_inflater.xml
new file mode 100644
index 0000000..b237633
--- /dev/null
+++ b/packages/SystemUI/res/layout/nav_bar_tuner_inflater.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.
+-->
+<com.android.systemui.tuner.PreviewNavInflater
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:background="@android:color/black"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/navigation_bar_size">
+
+    <include android:id="@+id/rot0" layout="@layout/navigation_layout" />
+
+    <include android:id="@+id/rot90" layout="@layout/navigation_layout_rot90" />
+
+</com.android.systemui.tuner.PreviewNavInflater>
diff --git a/packages/SystemUI/res/layout/nav_control_widget.xml b/packages/SystemUI/res/layout/nav_control_widget.xml
new file mode 100644
index 0000000..51dd68f
--- /dev/null
+++ b/packages/SystemUI/res/layout/nav_control_widget.xml
@@ -0,0 +1,62 @@
+<?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:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="wrap_content"
+    android:layout_height="match_parent"
+    android:paddingTop="8dp"
+    android:paddingBottom="8dp"
+    android:gravity="center"
+    android:orientation="horizontal">
+
+    <ImageView
+        android:id="@+id/width"
+        android:layout_width="48dp"
+        android:layout_height="wrap_content"
+        android:src="@drawable/ic_width"
+        android:clickable="true"
+        android:tint="?android:attr/textColorPrimary" />
+
+    <View
+        android:layout_width="1dp"
+        android:layout_height="match_parent"
+        android:background="?android:attr/listDivider" />
+
+    <ImageView
+        android:id="@+id/close"
+        android:layout_width="48dp"
+        android:layout_height="wrap_content"
+        android:src="@drawable/ic_close"
+        android:clickable="true"
+        android:tint="?android:attr/textColorPrimary" />
+
+    <View
+        android:layout_width="1dp"
+        android:layout_height="match_parent"
+        android:background="?android:attr/listDivider" />
+
+    <ImageView
+        android:id="@+id/drag"
+        android:layout_width="48dp"
+        android:layout_height="wrap_content"
+        android:src="@drawable/ic_drag_handle"
+        android:clickable="true"
+        android:tint="?android:attr/textColorPrimary" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/nav_key_space.xml b/packages/SystemUI/res/layout/nav_key_space.xml
new file mode 100644
index 0000000..3986841
--- /dev/null
+++ b/packages/SystemUI/res/layout/nav_key_space.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.
+*/
+-->
+
+<Space xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="@dimen/navigation_side_padding"
+    android:layout_height="match_parent"
+    android:layout_weight="0"
+    >
+</Space>
diff --git a/packages/SystemUI/res/layout/nav_width_view.xml b/packages/SystemUI/res/layout/nav_width_view.xml
new file mode 100644
index 0000000..6a72faf
--- /dev/null
+++ b/packages/SystemUI/res/layout/nav_width_view.xml
@@ -0,0 +1,26 @@
+<?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.
+*/
+-->
+
+<SeekBar
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/seekbar"
+    android:layout_height="wrap_content"
+    android:layout_width="match_parent"
+    android:paddingTop="12dp"
+    android:paddingBottom="4dp" />
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index d58664f..36e937d 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
 **
 ** Copyright 2011, The Android Open Source Project
 **
@@ -23,309 +22,17 @@
     xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:layout_height="match_parent"
     android:layout_width="match_parent"
-    android:background="@drawable/system_bar_background"
-    >
+    android:background="@drawable/system_bar_background">
 
-    <FrameLayout android:id="@+id/rot0"
-        android:layout_height="match_parent"
+    <com.android.systemui.statusbar.phone.NavigationBarInflaterView
+        android:id="@+id/navigation_inflater"
         android:layout_width="match_parent"
-        >
+        android:layout_height="match_parent">
 
-        <LinearLayout
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            android:orientation="horizontal"
-            android:clipChildren="false"
-            android:clipToPadding="false"
-            android:id="@+id/nav_buttons"
-            android:animateLayoutChanges="true"
-            >
+        <include android:id="@+id/rot0" layout="@layout/navigation_layout" />
 
-            <!-- navigation controls -->
-            <View
-                android:layout_width="@dimen/navigation_side_padding"
-                android:layout_height="match_parent"
-                android:layout_weight="0"
-                android:visibility="invisible"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
-                android:layout_width="@dimen/navigation_key_width"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_back"
-                systemui:keyCode="4"
-                android:layout_weight="0"
-                android:scaleType="center"
-                android:contentDescription="@string/accessibility_back"
-                />
-            <View
-                android:layout_width="0dp"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                android:visibility="invisible"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
-                android:layout_width="@dimen/navigation_key_width"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_home"
-                systemui:keyCode="3"
-                systemui:keyRepeat="false"
-                android:layout_weight="0"
-                android:scaleType="center"
-                android:contentDescription="@string/accessibility_home"
-                />
-            <View
-                android:layout_width="0dp"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                android:visibility="invisible"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
-                android:layout_width="@dimen/navigation_key_width"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_recent"
-                android:layout_weight="0"
-                android:scaleType="center"
-                android:contentDescription="@string/accessibility_recent"
-                />
-            <FrameLayout
-                android:layout_width="@dimen/navigation_side_padding"
-                android:layout_height="match_parent"
-                android:layout_weight="0" >
-                <com.android.systemui.statusbar.policy.KeyButtonView
-                    android:id="@+id/menu"
-                    android:layout_width="@dimen/navigation_extra_key_width"
-                    android:layout_height="match_parent"
-                    android:contentDescription="@string/accessibility_menu"
-                    android:src="@drawable/ic_sysbar_menu"
-                    android:visibility="invisible"
-                    android:scaleType="centerInside"
-                    android:layout_gravity="end"
-                    systemui:keyCode="82" />
+        <include android:id="@+id/rot90" layout="@layout/navigation_layout_rot90" />
 
-                <com.android.systemui.statusbar.policy.KeyButtonView
-                    android:id="@+id/ime_switcher"
-                    android:layout_width="@dimen/navigation_extra_key_width"
-                    android:layout_height="match_parent"
-                    android:contentDescription="@string/accessibility_ime_switch_button"
-                    android:scaleType="centerInside"
-                    android:src="@drawable/ic_ime_switcher_default"
-                    android:visibility="invisible"
-                    android:layout_gravity="end" />
-            </FrameLayout>
-
-        </LinearLayout>
-
-        <!-- lights out layout to match exactly -->
-        <LinearLayout
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            android:orientation="horizontal"
-            android:id="@+id/lights_out"
-            android:visibility="gone"
-            >
-            <ImageView
-                android:layout_width="@dimen/navigation_key_width"
-                android:layout_height="match_parent"
-                android:layout_marginStart="@dimen/navigation_side_padding"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_back"
-                />
-            <View
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                android:visibility="invisible"
-                />
-            <ImageView
-                android:layout_width="@dimen/navigation_key_width"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_large"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_home"
-                />
-            <View
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                android:visibility="invisible"
-                />
-            <ImageView
-                android:layout_width="@dimen/navigation_key_width"
-                android:layout_marginEnd="@dimen/navigation_side_padding"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_recent"
-                />
-        </LinearLayout>
-
-        <com.android.systemui.statusbar.policy.DeadZone
-            android:id="@+id/deadzone"
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            systemui:minSize="@dimen/navigation_bar_deadzone_size"
-            systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"
-            systemui:holdTime="@integer/navigation_bar_deadzone_hold"
-            systemui:decayTime="@integer/navigation_bar_deadzone_decay"
-            systemui:orientation="horizontal"
-            android:layout_gravity="top"
-            />
-    </FrameLayout>
-
-    <FrameLayout android:id="@+id/rot90"
-        android:layout_height="match_parent"
-        android:layout_width="match_parent"
-        android:visibility="gone"
-        android:paddingTop="0dp"
-        >
-
-        <LinearLayout
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            android:orientation="vertical"
-            android:clipChildren="false"
-            android:clipToPadding="false"
-            android:id="@+id/nav_buttons"
-            android:animateLayoutChanges="true"
-            >
-
-            <!-- navigation controls -->
-            <FrameLayout
-                android:layout_weight="0"
-                android:layout_width="match_parent"
-                android:layout_height="@dimen/navigation_side_padding" >
-                <com.android.systemui.statusbar.policy.KeyButtonView
-                    android:id="@+id/ime_switcher"
-                    android:layout_width="match_parent"
-                    android:layout_height="@dimen/navigation_extra_key_width"
-                    android:contentDescription="@string/accessibility_ime_switch_button"
-                    android:scaleType="centerInside"
-                    android:src="@drawable/ic_ime_switcher_default"
-                    android:layout_gravity="top"
-                    android:visibility="invisible" />
-
-                <com.android.systemui.statusbar.policy.KeyButtonView
-                    android:id="@+id/menu"
-                    android:layout_width="match_parent"
-                    android:layout_height="40dp"
-                    android:contentDescription="@string/accessibility_menu"
-                    android:src="@drawable/ic_sysbar_menu"
-                    android:scaleType="centerInside"
-                    android:layout_gravity="top"
-                    android:visibility="invisible"
-                    systemui:keyCode="82" />
-            </FrameLayout>
-
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
-                android:layout_height="@dimen/navigation_key_width"
-                android:layout_width="match_parent"
-                android:src="@drawable/ic_sysbar_recent"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_recent"
-                />
-            <View
-                android:layout_height="match_parent"
-                android:layout_width="match_parent"
-                android:layout_weight="1"
-                android:visibility="invisible"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
-                android:layout_height="@dimen/navigation_key_width"
-                android:layout_width="match_parent"
-                android:src="@drawable/ic_sysbar_home"
-                android:scaleType="center"
-                systemui:keyCode="3"
-                systemui:keyRepeat="false"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_home"
-                />
-            <View
-                android:layout_height="match_parent"
-                android:layout_width="match_parent"
-                android:layout_weight="1"
-                android:visibility="invisible"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
-                android:layout_height="@dimen/navigation_key_width"
-                android:layout_width="match_parent"
-                android:src="@drawable/ic_sysbar_back"
-                android:scaleType="center"
-                systemui:keyCode="4"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_back"
-                />
-            <View
-                android:layout_height="@dimen/navigation_side_padding"
-                android:layout_width="match_parent"
-                android:layout_weight="0"
-                android:visibility="invisible"
-                />
-        </LinearLayout>
-
-        <!-- lights out layout to match exactly -->
-        <LinearLayout
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            android:orientation="vertical"
-            android:id="@+id/lights_out"
-            android:visibility="gone"
-            >
-            <ImageView
-                android:layout_height="@dimen/navigation_key_width"
-                android:layout_marginTop="@dimen/navigation_side_padding"
-                android:layout_width="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_recent"
-                />
-            <View
-                android:layout_height="match_parent"
-                android:layout_width="match_parent"
-                android:layout_weight="1"
-                android:visibility="invisible"
-                />
-            <ImageView
-                android:layout_height="@dimen/navigation_key_width"
-                android:layout_width="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_large"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_home"
-                />
-            <View
-                android:layout_height="match_parent"
-                android:layout_width="match_parent"
-                android:layout_weight="1"
-                android:visibility="invisible"
-                />
-            <ImageView
-                android:layout_height="@dimen/navigation_key_width"
-                android:layout_marginBottom="@dimen/navigation_side_padding"
-                android:layout_width="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_back"
-                />
-        </LinearLayout>
-
-        <com.android.systemui.statusbar.policy.DeadZone
-            android:id="@+id/deadzone"
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            systemui:minSize="@dimen/navigation_bar_deadzone_size"
-            systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"
-            systemui:holdTime="@integer/navigation_bar_deadzone_hold"
-            systemui:decayTime="@integer/navigation_bar_deadzone_decay"
-            systemui:orientation="vertical"
-            android:layout_gravity="top"
-            />
-    </FrameLayout>
+    </com.android.systemui.statusbar.phone.NavigationBarInflaterView>
 
 </com.android.systemui.statusbar.phone.NavigationBarView>
diff --git a/packages/SystemUI/res/layout/navigation_bar_with_apps.xml b/packages/SystemUI/res/layout/navigation_bar_with_apps.xml
deleted file mode 100644
index ac95b5e..0000000
--- a/packages/SystemUI/res/layout/navigation_bar_with_apps.xml
+++ /dev/null
@@ -1,331 +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.
--->
-
-<!-- Navigation bar with app shortcuts. See also navigation_bar.xml. -->
-<com.android.systemui.statusbar.phone.NavigationBarView
-    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="match_parent"
-    android:background="@drawable/system_bar_background"
-    >
-
-    <!-- Portrait layout. -->
-    <FrameLayout android:id="@+id/rot0"
-        android:layout_height="match_parent"
-        android:layout_width="match_parent"
-        >
-
-        <LinearLayout
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            android:orientation="horizontal"
-            android:clipChildren="false"
-            android:clipToPadding="false"
-            android:id="@+id/nav_buttons"
-            android:animateLayoutChanges="true"
-            >
-
-            <!-- Back button is flush left. -->
-            <com.android.systemui.statusbar.policy.KeyButtonView
-                android:id="@+id/back"
-                android:layout_width="64dp"
-                android:paddingStart="4dp"
-                android:paddingEnd="4dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_back"
-                android:scaleType="centerInside"
-                systemui:keyCode="4"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_back"
-                />
-
-            <com.android.systemui.statusbar.policy.KeyButtonView
-                android:id="@+id/home"
-                android:layout_width="64dp"
-                android:paddingStart="4dp"
-                android:paddingEnd="4dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_home"
-                android:scaleType="centerInside"
-                systemui:keyCode="3"
-                systemui:keyRepeat="true"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_home"
-                />
-
-            <!-- Container for the app shelf. -->
-            <LinearLayout
-                android:id="@+id/app_shelf"
-                android:orientation="horizontal"
-                android:layout_height="match_parent"
-                android:layout_width="0dp"
-                android:layout_weight="1"
-                >
-                <com.android.systemui.statusbar.phone.NavigationBarApps
-                    android:id="@+id/navigation_bar_apps"
-                    android:layout_width="wrap_content"
-                    android:layout_height="match_parent"
-                    />
-            </LinearLayout>
-
-            <FrameLayout
-                android:layout_width="@dimen/navigation_extra_key_width"
-                android:layout_height="match_parent"
-                android:layout_weight="0"
-                android:layout_marginEnd="2dp" >
-                <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
-                    android:layout_width="@dimen/navigation_extra_key_width"
-                    android:layout_height="match_parent"
-                    android:src="@drawable/ic_sysbar_menu"
-                    android:scaleType="centerInside"
-                    android:layout_marginEnd="2dp"
-                    systemui:keyCode="82"
-                    android:visibility="invisible"
-                    android:contentDescription="@string/accessibility_menu"
-                    />
-                <com.android.systemui.statusbar.policy.KeyButtonView
-                    android:id="@+id/ime_switcher"
-                    android:layout_width="@dimen/navigation_extra_key_width"
-                    android:layout_height="match_parent"
-                    android:layout_marginEnd="2dp"
-                    android:scaleType="centerInside"
-                    android:src="@drawable/ic_ime_switcher_default"
-                    android:visibility="invisible"
-                    android:contentDescription="@string/accessibility_ime_switch_button" />
-            </FrameLayout>
-
-            <!-- Recents always at the far right. -->
-            <com.android.systemui.statusbar.policy.KeyButtonView
-                android:id="@+id/recent_apps"
-                android:layout_width="64dp"
-                android:paddingStart="4dp"
-                android:paddingEnd="4dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_recent"
-                android:scaleType="centerInside"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_recent"
-                />
-        </LinearLayout>
-
-        <!-- lights out layout to match exactly -->
-        <LinearLayout
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            android:orientation="horizontal"
-            android:id="@+id/lights_out"
-            android:visibility="gone"
-            >
-            <ImageView
-                android:layout_width="64dp"
-                android:paddingStart="4dp"
-                android:paddingEnd="4dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:scaleType="center"
-                android:layout_weight="0"
-                />
-            <ImageView
-                android:layout_width="64dp"
-                android:paddingStart="4dp"
-                android:paddingEnd="4dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_large"
-                android:scaleType="center"
-                android:layout_weight="0"
-                />
-            <Space
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                />
-            <ImageView
-                android:layout_width="64dp"
-                android:paddingStart="4dp"
-                android:paddingEnd="4dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:scaleType="center"
-                android:layout_weight="0"
-                />
-        </LinearLayout>
-
-        <com.android.systemui.statusbar.policy.DeadZone
-            android:id="@+id/deadzone"
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            systemui:minSize="@dimen/navigation_bar_deadzone_size"
-            systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"
-            systemui:holdTime="@integer/navigation_bar_deadzone_hold"
-            systemui:decayTime="@integer/navigation_bar_deadzone_decay"
-            systemui:orientation="horizontal"
-            android:layout_gravity="top"
-            />
-    </FrameLayout>
-
-    <!-- Landscape layout. -->
-    <FrameLayout android:id="@+id/rot90"
-        android:layout_height="match_parent"
-        android:layout_width="match_parent"
-        android:visibility="gone"
-        android:paddingTop="0dp"
-        >
-
-        <LinearLayout
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            android:orientation="horizontal"
-            android:clipChildren="false"
-            android:clipToPadding="false"
-            android:id="@+id/nav_buttons"
-            android:animateLayoutChanges="true"
-            >
-
-            <!-- Back button is flush left. -->
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
-                android:layout_width="64dp"
-                android:paddingStart="4dp"
-                android:paddingEnd="4dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_back"
-                android:scaleType="centerInside"
-                systemui:keyCode="4"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_back"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
-                android:layout_width="64dp" android:paddingStart="4dp" android:paddingEnd="4dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_home"
-                android:scaleType="centerInside"
-                systemui:keyCode="3"
-                systemui:keyRepeat="true"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_home"
-                />
-
-            <!-- Container for the app shelf. -->
-            <LinearLayout
-                android:id="@+id/app_shelf"
-                android:orientation="horizontal"
-                android:layout_height="match_parent"
-                android:layout_width="0dp"
-                android:layout_weight="1"
-                >
-                <com.android.systemui.statusbar.phone.NavigationBarApps
-                    android:id="@+id/navigation_bar_apps"
-                    android:layout_width="wrap_content"
-                    android:layout_height="match_parent"
-                    />
-            </LinearLayout>
-
-            <FrameLayout
-                android:layout_width="@dimen/navigation_extra_key_width"
-                android:layout_height="match_parent"
-                android:layout_marginEnd="2dp"
-                android:layout_weight="0"
-                android:visibility="gone" >
-                <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
-                    android:layout_width="@dimen/navigation_extra_key_width"
-                    android:layout_height="match_parent"
-                    android:layout_marginEnd="2dp"
-                    android:src="@drawable/ic_sysbar_menu"
-                    android:scaleType="centerInside"
-                    systemui:keyCode="82"
-                    android:visibility="invisible"
-                    android:contentDescription="@string/accessibility_menu" />
-                <com.android.systemui.statusbar.policy.KeyButtonView
-                    android:id="@+id/ime_switcher"
-                    android:layout_width="@dimen/navigation_extra_key_width"
-                    android:layout_height="match_parent"
-                    android:layout_marginEnd="2dp"
-                    android:src="@drawable/ic_ime_switcher_default"
-                    android:visibility="invisible"
-                    android:contentDescription="@string/accessibility_ime_switch_button"
-                    android:scaleType="centerInside" />
-            </FrameLayout>
-
-            <!-- Recents always at the far right. -->
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
-                android:layout_width="64dp"
-                android:paddingStart="4dp"
-                android:paddingEnd="4dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_recent"
-                android:scaleType="centerInside"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_recent"
-                />
-        </LinearLayout>
-
-        <!-- lights out layout to match exactly -->
-        <LinearLayout
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            android:orientation="horizontal"
-            android:id="@+id/lights_out"
-            android:visibility="gone"
-            >
-            <ImageView
-                android:layout_width="64dp"
-                android:paddingStart="4dp"
-                android:paddingEnd="4dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:scaleType="center"
-                android:layout_weight="0"
-                />
-            <ImageView
-                android:layout_width="64dp"
-                android:paddingStart="4dp"
-                android:paddingEnd="4dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_large"
-                android:scaleType="center"
-                android:layout_weight="0"
-                />
-            <Space
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                />
-            <ImageView
-                android:layout_width="64dp"
-                android:paddingStart="4dp"
-                android:paddingEnd="4dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:scaleType="center"
-                android:layout_weight="0"
-                />
-        </LinearLayout>
-
-        <com.android.systemui.statusbar.policy.DeadZone
-            android:id="@+id/deadzone"
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            systemui:minSize="@dimen/navigation_bar_deadzone_size"
-            systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"
-            systemui:holdTime="@integer/navigation_bar_deadzone_hold"
-            systemui:decayTime="@integer/navigation_bar_deadzone_decay"
-            systemui:orientation="horizontal"
-            android:layout_gravity="top"
-            />
-    </FrameLayout>
-</com.android.systemui.statusbar.phone.NavigationBarView>
diff --git a/packages/SystemUI/res/layout/navigation_layout.xml b/packages/SystemUI/res/layout/navigation_layout.xml
new file mode 100644
index 0000000..f9a3653
--- /dev/null
+++ b/packages/SystemUI/res/layout/navigation_layout.xml
@@ -0,0 +1,75 @@
+<?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"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <FrameLayout
+        android:id="@+id/nav_buttons"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <LinearLayout
+            android:id="@+id/ends_group"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="horizontal" />
+
+        <LinearLayout
+            android:id="@+id/center_group"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center"
+            android:orientation="horizontal" />
+
+    </FrameLayout>
+
+    <FrameLayout
+        android:id="@+id/lights_out"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <LinearLayout
+            android:id="@+id/ends_group_lightsout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="horizontal" />
+
+        <LinearLayout
+            android:id="@+id/center_group_lightsout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center"
+            android:orientation="horizontal" />
+
+    </FrameLayout>
+
+    <com.android.systemui.statusbar.policy.DeadZone
+        android:id="@+id/deadzone"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:layout_gravity="top"
+        systemui:minSize="@dimen/navigation_bar_deadzone_size"
+        systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"
+        systemui:holdTime="@integer/navigation_bar_deadzone_hold"
+        systemui:decayTime="@integer/navigation_bar_deadzone_decay"
+        systemui:orientation="horizontal"
+        />
+
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/navigation_layout_rot90.xml b/packages/SystemUI/res/layout/navigation_layout_rot90.xml
new file mode 100644
index 0000000..df32911
--- /dev/null
+++ b/packages/SystemUI/res/layout/navigation_layout_rot90.xml
@@ -0,0 +1,75 @@
+<?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"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <FrameLayout
+        android:id="@+id/nav_buttons"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <com.android.systemui.statusbar.phone.ReverseLinearLayout
+            android:id="@+id/ends_group"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="vertical" />
+
+        <com.android.systemui.statusbar.phone.ReverseLinearLayout
+            android:id="@+id/center_group"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center"
+            android:orientation="vertical" />
+
+    </FrameLayout>
+
+    <FrameLayout
+        android:id="@+id/lights_out"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <com.android.systemui.statusbar.phone.ReverseLinearLayout
+            android:id="@+id/ends_group_lightsout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="vertical" />
+
+        <com.android.systemui.statusbar.phone.ReverseLinearLayout
+            android:id="@+id/center_group_lightsout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center"
+            android:orientation="vertical" />
+
+    </FrameLayout>
+
+    <com.android.systemui.statusbar.policy.DeadZone
+        android:id="@+id/deadzone"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:layout_gravity="top"
+        systemui:minSize="@dimen/navigation_bar_deadzone_size"
+        systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"
+        systemui:holdTime="@integer/navigation_bar_deadzone_hold"
+        systemui:decayTime="@integer/navigation_bar_deadzone_decay"
+        systemui:orientation="vertical"
+        />
+
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/notification_children_divider.xml b/packages/SystemUI/res/layout/notification_children_divider.xml
index 53273cf..dad7cea 100644
--- a/packages/SystemUI/res/layout/notification_children_divider.xml
+++ b/packages/SystemUI/res/layout/notification_children_divider.xml
@@ -19,5 +19,5 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/notification_more_divider"
     android:layout_width="match_parent"
-    android:layout_height="@dimen/notification_children_divider_height"
+    android:layout_height="@dimen/notification_divider_height"
     android:background="#61000000" />
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index c9dbc79..e550d9c 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -24,100 +24,59 @@
         android:clickable="true"
         android:gravity="top|start"
         android:orientation="vertical"
+        android:paddingStart="@*android:dimen/notification_content_margin_start"
         android:paddingEnd="8dp"
-        android:background="@color/notification_guts_text_color" >
+        android:background="@color/notification_guts_bg_color" >
 
     <!-- header -->
-    <FrameLayout
+    <LinearLayout
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingStart="@*android:dimen/notification_content_margin_start"
-            android:paddingTop="8dp"
-            android:paddingBottom="16dp" >
+            android:layout_height="30dp"
+            android:paddingTop="9dp"
+            android:paddingEnd="8dp"
+            android:id="@+id/notification_guts_header"
+            android:orientation="horizontal"
+            android:layout_gravity="center_vertical|start">
 
-        <LinearLayout
+        <ImageView
+                android:id="@android:id/icon"
+                android:layout_width="18dp"
+                android:layout_height="18dp"
+                android:layout_marginEnd="6dp"
+                android:src="@android:drawable/arrow_down_float" />
+        <TextView
+                android:id="@+id/pkgname"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:id="@+id/notification_guts_header"
-                android:orientation="vertical"
-                android:layout_gravity="center_vertical|start"
-                android:layout_marginEnd="52dp">
-
-                <LinearLayout
-                        android:id="@+id/notification_guts_app_details"
-                        android:orientation="horizontal"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:clipChildren="false"
-                        android:layout_gravity="start|top"
-                        android:gravity="center_vertical"
-                        >
-
-                    <ImageView
-                            android:id="@android:id/icon"
-                            android:layout_width="18dp"
-                            android:layout_height="18dp"
-                            android:layout_marginEnd="3dp"
-                            android:src="@android:drawable/arrow_down_float" />
-                    <TextView
-                            android:id="@+id/pkgname"
-                            android:layout_width="wrap_content"
-                            android:layout_height="wrap_content"
-                            android:textAppearance="@android:style/TextAppearance.Material.Notification.Info"
-                            android:layout_marginStart="3dp"
-                            android:layout_marginEnd="4dp"
-                            android:textColor="@color/notification_guts_title_color" />
-                    <TextView
-                            android:layout_width="wrap_content"
-                            android:layout_height="wrap_content"
-                            android:id="@+id/debug_info"
-                            android:layout_weight="0"
-                            android:textAppearance="@android:style/TextAppearance.Material.Notification.Time"
-                            android:layout_gravity="bottom|start"
-                            android:visibility="gone"
-                            android:textColor="#ffffff" />
-                </LinearLayout>
-
-                <TextView
-                        android:id="@+id/topic_details"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:textAppearance="@android:style/TextAppearance.Material.Notification.Title"
-                        android:textColor="@color/notification_guts_text_color"
-                        android:layout_alignParentBottom="true"
-                        android:layout_alignParentStart="true" />
-            </LinearLayout>
-
-        <ImageButton style="@android:style/Widget.Material.Light.Button.Borderless.Small"
-                android:id="@+id/notification_inspect_item"
-                android:layout_width="52dp"
-                android:layout_height="match_parent"
+                style="@style/TextAppearance.NotificationGuts.Header" />
+        <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/debug_info"
                 android:layout_weight="0"
-                android:gravity="center"
-                android:layout_gravity="center_vertical|end"
-                android:contentDescription="@string/status_bar_notification_inspect_item_title"
-                android:src="@drawable/ic_settings" />
-    </FrameLayout>
+                style="@style/TextAppearance.NotificationGuts.Header"
+                android:layout_gravity="bottom|start"
+                android:visibility="gone" />
+    </LinearLayout>
     <!-- Importance slider -->
     <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:gravity="center_vertical"
-            android:paddingStart="@*android:dimen/notification_content_margin_start"
             android:orientation="vertical"
             android:clickable="false"
             android:focusable="false"
-            android:paddingBottom="8dip">
+            android:paddingBottom="8dip"
+            android:paddingEnd="8dp" >
         <TextView
                 android:id="@+id/title"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:singleLine="true"
-                android:textAppearance="@android:style/TextAppearance.Material.Subhead"
-                android:textColor="@color/notification_guts_text_color"
+                style="@style/TextAppearance.NotificationGuts.Primary"
                 android:ellipsize="marquee"
                 android:fadingEdge="horizontal"
-                android:text="@*android:string/notification_importance_title"/>
+                android:paddingBottom="2dp"/>
 
         <TextView
                 android:id="@+id/summary"
@@ -125,42 +84,99 @@
                 android:layout_height="wrap_content"
                 android:layout_alignStart="@android:id/title"
                 android:textAlignment="viewStart"
-                android:textAppearance="@android:style/TextAppearance.Material.Body1"
-                android:textColor="@color/notification_guts_title_color"
+                style="@style/TextAppearance.NotificationGuts.Secondary"
                 android:maxLines="3"
-                android:minLines="2" />
+                android:minLines="2"
+                android:paddingBottom="4dp" />
 
         <FrameLayout
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:paddingTop="6dp" >
+                android:layout_height="48dp"
+                android:paddingTop="8dp" >
 
             <ImageView
                     android:id="@+id/low_importance"
-                    android:src="@android:drawable/ic_menu_close_clear_cancel"
+                    android:src="@*android:drawable/ic_notification_block"
                     android:layout_gravity="center_vertical|start"
                     android:layout_width="24dp"
-                    android:layout_height="24dp" />
+                    android:layout_height="24dp"
+                    android:tint="@color/notification_guts_icon_tint"/>
 
             <SeekBar
                     android:id="@+id/seekbar"
-                    android:layout_marginStart="24dp"
-                    android:layout_marginEnd="24dp"
+                    android:layout_marginStart="56dp"
+                    android:layout_marginEnd="56dp"
                     android:layout_gravity="center_vertical"
                     android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
+                    android:layout_height="48dp"
                     android:focusable="true"
                     android:background="#00ffffff"
-                    android:thumbTint="@android:color/white"
-                    android:progressTint="@android:color/white" />
+                    android:progressBackgroundTint="@color/notification_guts_secondary_slider_color"
+                    android:thumbTint="@color/notification_guts_slider_color"
+                    android:progressTint="@color/notification_guts_slider_color"
+                    style="@android:style/Widget.Material.SeekBar.Discrete"
+                    android:tickMarkTint="@android:color/black" />
 
             <ImageView
                     android:id="@+id/max_importance"
-                    android:src="@android:drawable/ic_popup_reminder"
+                    android:src="@*android:drawable/ic_notification_alert"
                     android:layout_gravity="center_vertical|end"
                     android:layout_width="24dp"
-                    android:layout_height="24dp"/>
+                    android:layout_height="24dp"
+                    android:tint="@color/notification_guts_icon_tint" />
 
         </FrameLayout>
+
+        <RadioGroup
+                    android:id="@+id/apply_to"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content" >
+            <RadioButton android:id="@+id/apply_to_topic"
+                         android:layout_width="wrap_content"
+                         android:layout_height="48dp"
+                         style="@style/TextAppearance.NotificationGuts.Primary"
+                         android:visibility="gone"
+                         android:buttonTint="#858383"
+            />
+            <RadioButton android:id="@+id/apply_to_app"
+                         android:layout_width="wrap_content"
+                         android:layout_height="48dp"
+                         android:text="@string/apply_to_app"
+                         style="@style/TextAppearance.NotificationGuts.Primary"
+                         android:visibility="gone"
+                         android:buttonTint="#858383"
+            />
+        </RadioGroup>
+    </LinearLayout>
+    <!-- buttons -->
+    <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="end"
+            android:paddingBottom="8dp" >
+
+        <TextView
+            android:id="@+id/more_settings"
+            android:text="@string/notification_more_settings"
+            android:layout_width="wrap_content"
+            android:layout_height="48dp"
+            style="@style/TextAppearance.NotificationGuts.Button"
+            android:background="@drawable/btn_borderless_rect"
+            android:gravity="center"
+            android:paddingEnd="8dp"
+            android:paddingStart="8dp"
+            android:focusable="true" />
+
+        <TextView
+            android:id="@+id/done"
+            android:text="@string/notification_done"
+            android:layout_width="wrap_content"
+            android:layout_height="48dp"
+            style="@style/TextAppearance.NotificationGuts.Button"
+            android:background="@drawable/btn_borderless_rect"
+            android:gravity="center"
+            android:layout_marginStart="8dp"
+            android:layout_marginEnd="8dp"
+            android:focusable="true"/>
     </LinearLayout>
 </com.android.systemui.statusbar.NotificationGuts>
diff --git a/packages/SystemUI/res/layout/notification_icon_area.xml b/packages/SystemUI/res/layout/notification_icon_area.xml
new file mode 100644
index 0000000..c5b4e84
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_icon_area.xml
@@ -0,0 +1,35 @@
+<?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.keyguard.AlphaOptimizedLinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/notification_icon_area_inner"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" >
+    <com.android.systemui.statusbar.StatusBarIconView
+        android:id="@+id/moreIcon"
+        android:layout_width="@dimen/status_bar_icon_size"
+        android:layout_height="match_parent"
+        android:src="@drawable/stat_notify_more"
+        android:visibility="gone" />
+    <com.android.systemui.statusbar.phone.IconMerger
+        android:id="@+id/notificationIcons"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_alignParentStart="true"
+        android:gravity="center_vertical"
+        android:orientation="horizontal"/>
+</com.android.keyguard.AlphaOptimizedLinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/notification_public_default.xml b/packages/SystemUI/res/layout/notification_public_default.xml
deleted file mode 100644
index 044ba09..0000000
--- a/packages/SystemUI/res/layout/notification_public_default.xml
+++ /dev/null
@@ -1,74 +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
-  -->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/status_bar_latest_event_content"
-    android:layout_width="match_parent"
-    android:layout_height="64dp"
-    >
-    <ImageView android:id="@+id/icon"
-        android:layout_width="40dp"
-        android:layout_height="40dp"
-        android:layout_marginTop="12dp"
-        android:layout_marginStart="12dp"
-        android:layout_marginEnd="12dp"
-        android:scaleType="centerInside"
-        />
-    <DateTimeView android:id="@+id/time"
-        android:textAppearance="@android:style/TextAppearance.Material.Notification.Time"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginEnd="8dp"
-        android:layout_alignParentEnd="true"
-        android:layout_alignBaseline="@+id/title"
-        android:singleLine="true"
-        android:gravity="center"
-        android:paddingStart="8dp"
-        android:visibility="gone"
-        />
-    <TextView android:id="@+id/title"
-        android:textAppearance="@android:style/TextAppearance.Material.Notification.Title"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_toEndOf="@id/icon"
-        android:layout_toStartOf="@id/time"
-        android:singleLine="true"
-        android:ellipsize="marquee"
-        android:fadingEdge="horizontal"
-        />
-    <ImageView android:id="@+id/profile_badge_line3"
-        android:layout_width="@*android:dimen/notification_badge_size"
-        android:layout_height="@*android:dimen/notification_badge_size"
-        android:layout_below="@id/title"
-        android:layout_marginStart="4dp"
-        android:layout_marginEnd="8dp"
-        android:layout_alignParentEnd="true"
-        android:scaleType="fitCenter"
-        android:visibility="gone"
-        />
-    <TextView android:id="@+id/text"
-        android:textAppearance="@android:style/TextAppearance.Material.Notification"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignStart="@id/title"
-        android:layout_below="@id/title"
-        android:layout_toStartOf="@id/profile_badge_line3"
-        android:singleLine="true"
-        android:ellipsize="marquee"
-        android:fadingEdge="horizontal"
-        />
-</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/preference_matrix.xml b/packages/SystemUI/res/layout/preference_matrix.xml
new file mode 100644
index 0000000..1f6066e
--- /dev/null
+++ b/packages/SystemUI/res/layout/preference_matrix.xml
@@ -0,0 +1,104 @@
+<?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="wrap_content"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:paddingTop="8dp"
+    android:paddingBottom="8dp"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:id="@+id/r_group"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="4dp"
+        android:paddingBottom="4dp"
+        android:orientation="horizontal">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/color_modification_r"
+            android:gravity="center"
+            android:textAppearance="?android:attr/textAppearanceMedium" />
+
+        <SeekBar android:id="@*android:id/seekbar"
+            android:layout_marginStart="16dp"
+            android:layout_gravity="center_vertical"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/g_group"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="4dp"
+        android:paddingBottom="4dp"
+        android:orientation="horizontal">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/color_modification_g"
+            android:gravity="center"
+            android:textAppearance="?android:attr/textAppearanceMedium" />
+
+        <SeekBar android:id="@*android:id/seekbar"
+            android:layout_marginStart="16dp"
+            android:layout_gravity="center_vertical"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/b_group"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="4dp"
+        android:paddingBottom="4dp"
+        android:orientation="horizontal">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/color_modification_b"
+            android:gravity="center"
+            android:textAppearance="?android:attr/textAppearanceMedium" />
+
+        <SeekBar android:id="@*android:id/seekbar"
+            android:layout_marginStart="16dp"
+            android:layout_gravity="center_vertical"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1" />
+    </LinearLayout>
+
+    <Button
+        android:id="@+id/apply"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="end"
+        android:text="@string/color_apply" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/preference_widget_settings.xml b/packages/SystemUI/res/layout/preference_widget_settings.xml
new file mode 100644
index 0000000..082a295
--- /dev/null
+++ b/packages/SystemUI/res/layout/preference_widget_settings.xml
@@ -0,0 +1,44 @@
+<?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_height="wrap_content"
+    android:layout_width="wrap_content">
+
+    <RadioButton
+        android:id="@+id/radio_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="4dp"
+        android:clickable="false"
+        android:focusable="false" />
+
+    <View
+        android:layout_width="1dp"
+        android:layout_height="match_parent"
+        android:background="?android:attr/listDivider" />
+
+    <ImageView
+        android:id="@+id/widget_icon"
+        android:layout_width="50dp"
+        android:layout_height="24dp"
+        android:tint="@android:color/black"
+        android:src="@drawable/ic_settings"
+        android:layout_gravity="center_vertical" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/preference_widget_switch.xml b/packages/SystemUI/res/layout/preference_widget_switch.xml
new file mode 100644
index 0000000..49610de
--- /dev/null
+++ b/packages/SystemUI/res/layout/preference_widget_switch.xml
@@ -0,0 +1,44 @@
+<?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_height="wrap_content"
+    android:layout_width="wrap_content">
+
+    <RadioButton
+        android:id="@+id/radio_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:clickable="false"
+        android:focusable="false"
+        android:layout_marginEnd="4dp" />
+
+    <View
+        android:layout_width="1dp"
+        android:layout_height="match_parent"
+        android:background="?android:attr/listDivider" />
+
+    <Switch
+        android:id="@*android:id/switch_widget"
+        android:layout_width="50dp"
+        android:layout_height="wrap_content"
+        android:focusable="false"
+        android:clickable="false"
+        android:background="@null" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/qs_customize_layout.xml b/packages/SystemUI/res/layout/qs_customize_layout.xml
index 91cf894..0b8e02f 100644
--- a/packages/SystemUI/res/layout/qs_customize_layout.xml
+++ b/packages/SystemUI/res/layout/qs_customize_layout.xml
@@ -21,14 +21,6 @@
     android:layout_height="wrap_content"
     android:orientation="vertical">
 
-    <com.android.systemui.qs.QuickTileLayout
-        android:id="@+id/quick_tile_layout"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/qs_quick_actions_height"
-        android:orientation="horizontal"
-        android:paddingStart="@dimen/qs_quick_actions_padding"
-        android:paddingEnd="@dimen/qs_quick_actions_padding" />
-
     <view
         class="com.android.systemui.qs.PagedTileLayout$TilePage"
         android:id="@+id/tile_page"
diff --git a/packages/SystemUI/res/layout/qs_customize_panel.xml b/packages/SystemUI/res/layout/qs_customize_panel.xml
index f430fa5..e56431b 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel.xml
@@ -87,9 +87,7 @@
             android:id="@+id/quick_settings_panel"
             android:background="#0000"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="@dimen/notification_side_padding"
-            android:layout_marginRight="@dimen/notification_side_padding" />
+            android:layout_height="wrap_content" />
 
     </com.android.systemui.tuner.AutoScrollView>
 
diff --git a/packages/SystemUI/res/layout/qs_detail_item.xml b/packages/SystemUI/res/layout/qs_detail_item.xml
index 6facb71..ccdddf7 100644
--- a/packages/SystemUI/res/layout/qs_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_detail_item.xml
@@ -60,6 +60,7 @@
         android:clickable="true"
         android:focusable="true"
         android:scaleType="center"
+        android:contentDescription="@*android:string/media_route_controller_disconnect"
         android:src="@drawable/ic_qs_cancel" />
 
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
index 6c236ea..127bddd 100644
--- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
+++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
@@ -20,29 +20,6 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content">
 
-    <view
-        class="com.android.systemui.qs.PagedTileLayout$FirstPage"
-        android:id="@+id/first_page"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical">
-
-        <com.android.systemui.qs.QuickTileLayout
-            android:id="@+id/quick_tile_layout"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/qs_quick_actions_height"
-            android:orientation="horizontal"
-            android:paddingLeft="@dimen/qs_quick_actions_padding"
-            android:paddingRight="@dimen/qs_quick_actions_padding" />
-
-        <view
-            class="com.android.systemui.qs.PagedTileLayout$TilePage"
-            android:id="@+id/tile_page"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
-
-    </view>
-
     <com.android.systemui.qs.PageIndicator
         android:id="@+id/page_indicator"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/qs_tile_label.xml b/packages/SystemUI/res/layout/qs_tile_label.xml
new file mode 100644
index 0000000..603ebbf
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_tile_label.xml
@@ -0,0 +1,41 @@
+<?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: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" />
+     <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" />
+</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 af22f03..a22c360 100644
--- a/packages/SystemUI/res/layout/qs_user_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml
@@ -40,12 +40,25 @@
             systemui:framePadding="6dp"
             systemui:activeFrameColor="@color/current_user_border_color"/>
 
-    <TextView
-            android:id="@+id/user_name"
+    <LinearLayout
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:textSize="@dimen/qs_detail_item_secondary_text_size"
-            android:textColor="@color/qs_user_detail_name"
-            android:gravity="center_horizontal" />
+            android:layout_height="wrap_content">
+        <TextView
+                android:id="@+id/user_name"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textSize="@dimen/qs_detail_item_secondary_text_size"
+                android:textColor="@color/qs_user_detail_name"
+                android:gravity="center_horizontal" />
+        <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_marginLeft="@dimen/restricted_padlock_pading"
+                android:baselineAlignBottom="true"
+                android:scaleType="centerInside"
+                android:visibility="gone" />
+    </LinearLayout>
 
 </com.android.systemui.qs.tiles.UserDetailItemView>
\ No newline at end of file
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 a995ec7..6784695 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -23,8 +23,6 @@
     android:layout_width="@dimen/notification_panel_width"
     android:layout_height="@dimen/status_bar_header_height"
     android:layout_gravity="@integer/notification_panel_layout_gravity"
-    android:paddingStart="@dimen/notification_side_padding"
-    android:paddingEnd="@dimen/notification_side_padding"
     android:clipChildren="false"
     android:clipToPadding="false"
     android:baselineAligned="false"
@@ -70,6 +68,18 @@
 
         </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
 
+        <com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch"
+            android:layout_width="48dp"
+            android:layout_height="48dp"
+            android:layout_alignParentEnd="true"
+            android:background="@drawable/ripple_drawable" >
+            <ImageView android:id="@+id/multi_user_avatar"
+                android:layout_width="@dimen/multi_user_avatar_expanded_size"
+                android:layout_height="@dimen/multi_user_avatar_expanded_size"
+                android:layout_gravity="center"
+                android:scaleType="centerInside"/>
+        </com.android.systemui.statusbar.phone.MultiUserSwitch>
+
         <ImageView
             android:layout_width="48dp"
             android:layout_height="48dp"
@@ -96,14 +106,14 @@
     <LinearLayout
         android:id="@+id/date_time_group"
         android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
+        android:layout_height="28dp"
         android:layout_alignParentStart="true"
         android:layout_alignParentTop="true"
         android:orientation="horizontal">
 
         <include layout="@layout/split_clock_view"
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
+            android:layout_height="match_parent"
             android:layout_marginStart="16dp"
             android:layout_marginTop="2dp"
             android:id="@+id/clock" />
@@ -111,28 +121,28 @@
         <com.android.systemui.statusbar.policy.DateView
             android:id="@+id/date"
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
+            android:layout_height="match_parent"
             android:layout_marginStart="6dp"
             android:layout_marginTop="8dp"
-            android:layout_alignParentTop="true"
             android:drawableStart="@drawable/header_dot"
             android:drawablePadding="6dp"
             android:singleLine="true"
             android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
             android:textSize="@dimen/qs_time_collapsed_size"
+            android:gravity="top"
             systemui:datePattern="@string/abbrev_wday_month_day_no_year_alarm" />
 
         <com.android.systemui.statusbar.AlphaOptimizedButton
             android:id="@+id/alarm_status"
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignParentTop="true"
+            android:layout_height="match_parent"
+            android:layout_marginTop="8dp"
             android:drawablePadding="6dp"
             android:drawableStart="@drawable/ic_access_alarms_small"
             android:textColor="#64ffffff"
             android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
-            android:minHeight="36dp"
             android:paddingStart="6dp"
+            android:gravity="top"
             android:background="?android:attr/selectableItemBackground"
             android:visibility="gone" />
     </LinearLayout>
diff --git a/packages/SystemUI/res/layout/recent_apps.xml b/packages/SystemUI/res/layout/recent_apps.xml
new file mode 100644
index 0000000..eb8ee43c
--- /dev/null
+++ b/packages/SystemUI/res/layout/recent_apps.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.
+-->
+
+<com.android.systemui.statusbar.policy.KeyButtonView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/recent_apps"
+    android:layout_width="@dimen/navigation_key_width"
+    android:layout_height="match_parent"
+    android:layout_weight="0"
+    android:src="@drawable/ic_sysbar_recent"
+    android:scaleType="center"
+    android:contentDescription="@string/accessibility_recent"
+    android:paddingStart="@dimen/navigation_key_padding"
+    android:paddingEnd="@dimen/navigation_key_padding"
+    />
+
diff --git a/packages/SystemUI/res/layout/recents.xml b/packages/SystemUI/res/layout/recents.xml
index 16ff14c..186aaf6 100644
--- a/packages/SystemUI/res/layout/recents.xml
+++ b/packages/SystemUI/res/layout/recents.xml
@@ -17,14 +17,6 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
-    <!-- Status Bar Scrim View -->
-    <ImageView
-        android:id="@+id/status_bar_scrim"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_horizontal|top"
-        android:scaleType="fitXY"
-        android:src="@drawable/recents_status_gradient" />
 
     <!-- Recents View -->
     <com.android.systemui.recents.views.RecentsView
@@ -33,12 +25,6 @@
         android:layout_height="match_parent">
     </com.android.systemui.recents.views.RecentsView>
 
-    <!-- History View -->
-    <ViewStub android:id="@+id/history_view_stub"
-           android:layout="@layout/recents_history"
-           android:layout_width="match_parent"
-           android:layout_height="match_parent" />
-
     <!-- Nav Bar Scrim View -->
     <ImageView
         android:id="@+id/nav_bar_scrim"
diff --git a/packages/SystemUI/res/layout/recents_empty.xml b/packages/SystemUI/res/layout/recents_empty.xml
index 4b68e77..b2c0331 100644
--- a/packages/SystemUI/res/layout/recents_empty.xml
+++ b/packages/SystemUI/res/layout/recents_empty.xml
@@ -24,5 +24,4 @@
     android:textColor="#ffffffff"
     android:text="@string/recents_empty_message"
     android:fontFamily="sans-serif"
-    android:background="#80000000"
     android:visibility="gone" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_history.xml b/packages/SystemUI/res/layout/recents_history.xml
index b65a5c5..dc2da72 100644
--- a/packages/SystemUI/res/layout/recents_history.xml
+++ b/packages/SystemUI/res/layout/recents_history.xml
@@ -17,7 +17,6 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="#99000000"
     android:orientation="vertical">
     <android.support.v7.widget.RecyclerView
         android:id="@+id/list"
diff --git a/packages/SystemUI/res/layout/recents_history_button.xml b/packages/SystemUI/res/layout/recents_history_button.xml
index 8c96fc6..538bad1 100644
--- a/packages/SystemUI/res/layout/recents_history_button.xml
+++ b/packages/SystemUI/res/layout/recents_history_button.xml
@@ -15,15 +15,24 @@
 -->
 <TextView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:id="@+id/button"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
     android:gravity="start|center_vertical"
-    android:text="@string/recents_show_history_button_label"
+    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" />
\ No newline at end of file
+    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
new file mode 100644
index 0000000..05f0979
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_history_clear_all_button.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.
+-->
+<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
index 6d6a9ee..13c7dbe 100644
--- a/packages/SystemUI/res/layout/recents_history_date.xml
+++ b/packages/SystemUI/res/layout/recents_history_date.xml
@@ -15,10 +15,12 @@
 -->
 <TextView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:theme="@android:style/Theme.Material"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:padding="12dp"
+    android:paddingStart="4dp"
+    android:paddingEnd="4dp"
+    android:paddingTop="12dp"
+    android:paddingBottom="12dp"
     android:gravity="start"
     android:textSize="14sp"
     android:textColor="#009688"
diff --git a/packages/SystemUI/res/layout/recents_history_task.xml b/packages/SystemUI/res/layout/recents_history_task.xml
index b9de156..e92c24a 100644
--- a/packages/SystemUI/res/layout/recents_history_task.xml
+++ b/packages/SystemUI/res/layout/recents_history_task.xml
@@ -13,15 +13,30 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<TextView
+<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:theme="@android:style/Theme.Material"
     android:layout_width="match_parent"
     android:layout_height="48dp"
-    android:paddingLeft="32dp"
-    android:gravity="start|center_vertical"
-    android:textSize="14sp"
-    android:textColor="#FFFFFF"
-    android:fontFamily="sans-serif-medium"
-    android:background="?android:selectableItemBackground"
-    android:alpha="1" />
\ No newline at end of file
+    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
new file mode 100644
index 0000000..b4543bd
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_on_tv.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.
+-->
+<com.android.systemui.recents.tv.views.RecentsTvView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/recents_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:clipChildren="false"
+    android:clipToPadding="false" >
+
+    <com.android.systemui.recents.tv.views.TaskStackHorizontalGridView
+        android:id="@+id/task_list"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        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"/>
+
+</com.android.systemui.recents.tv.views.RecentsTvView>
+
diff --git a/packages/SystemUI/res/layout/recents_task_card_view.xml b/packages/SystemUI/res/layout/recents_task_card_view.xml
new file mode 100644
index 0000000..fa1daad
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_task_card_view.xml
@@ -0,0 +1,77 @@
+<?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.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index 2b82b05..c813818 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -34,9 +34,11 @@
             android:layout_gravity="bottom|right"
             android:layout_marginRight="15dp"
             android:layout_marginBottom="15dp"
-            android:translationZ="2dp"
+            android:translationZ="4dp"
             android:contentDescription="@string/recents_lock_to_app_button_label"
-            android:background="@drawable/recents_lock_to_task_button_bg">
+            android:background="@drawable/recents_lock_to_task_button_bg"
+            android:visibility="invisible"
+            android:alpha="0">
             <ImageView
                 android:layout_width="@dimen/recents_lock_to_app_icon_size"
                 android:layout_height="@dimen/recents_lock_to_app_icon_size"
diff --git a/packages/SystemUI/res/layout/recents_task_view_header.xml b/packages/SystemUI/res/layout/recents_task_view_header.xml
index b8caf23..5c67f80 100644
--- a/packages/SystemUI/res/layout/recents_task_view_header.xml
+++ b/packages/SystemUI/res/layout/recents_task_view_header.xml
@@ -1,12 +1,13 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+     Copyright (C) 2014 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at
-  
+
           http://www.apache.org/licenses/LICENSE-2.0
-  
+
      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -20,16 +21,14 @@
     android:layout_height="@dimen/recents_task_bar_height"
     android:layout_gravity="top|center_horizontal">
     <com.android.systemui.recents.views.FixedSizeImageView
-        android:id="@+id/application_icon"
+        android:id="@+id/icon"
         android:contentDescription="@string/recents_app_info_button_label"
-        android:layout_width="@dimen/recents_task_view_application_icon_size"
-        android:layout_height="@dimen/recents_task_view_application_icon_size"
-        android:layout_marginStart="8dp"
+        android:layout_width="@dimen/recents_task_view_header_icon_width"
+        android:layout_height="@dimen/recents_task_view_header_icon_height"
         android:layout_gravity="center_vertical|start"
-        android:padding="8dp"
-        android:background="@drawable/recents_button_bg" />
+        android:padding="9dp" />
     <TextView
-        android:id="@+id/activity_description"
+        android:id="@+id/title"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical|start"
@@ -45,22 +44,36 @@
         android:fadingEdge="horizontal" />
     <com.android.systemui.recents.views.FixedSizeImageView
         android:id="@+id/move_task"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:layout_marginEnd="52dp"
+        android:layout_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_gravity="center_vertical|end"
-        android:padding="12dp"
+        android:padding="15dp"
         android:background="@drawable/recents_button_bg"
         android:src="@drawable/star"
         android:visibility="gone" />
     <com.android.systemui.recents.views.FixedSizeImageView
         android:id="@+id/dismiss_task"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:layout_marginEnd="4dp"
+        android:layout_width="@dimen/recents_task_view_header_button_width"
+        android:layout_height="@dimen/recents_task_view_header_button_height"
         android:layout_gravity="center_vertical|end"
-        android:padding="12dp"
+        android:padding="15dp"
         android:background="@drawable/recents_button_bg"
         android:visibility="invisible"
         android:src="@drawable/recents_dismiss_light" />
+
+    <!-- The progress indicator shows if auto-paging is enabled -->
+    <ViewStub android:id="@+id/focus_timer_indicator_stub"
+               android:inflatedId="@+id/focus_timer_indicator"
+               android:layout="@layout/recents_task_view_header_progress_bar"
+               android:layout_width="match_parent"
+               android:layout_height="5dp"
+               android:layout_gravity="bottom" />
+
+    <!-- The app overlay shows as the user long-presses on the app icon -->
+    <ViewStub android:id="@+id/app_overlay_stub"
+               android:inflatedId="@+id/app_overlay"
+               android:layout="@layout/recents_task_view_header_overlay"
+               android:layout_width="match_parent"
+               android:layout_height="match_parent" />
 </com.android.systemui.recents.views.TaskViewHeader>
diff --git a/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml b/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml
new file mode 100644
index 0000000..dabfc80
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml
@@ -0,0 +1,50 @@
+<?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">
+    <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_gravity="center_vertical|start"
+        android:padding="9dp" />
+    <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"
+        android:fontFamily="sans-serif-medium"
+        android:singleLine="true"
+        android:maxLines="2"
+        android:ellipsize="marquee"
+        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_gravity="center_vertical|end"
+        android:padding="15dp"
+        android:background="@drawable/recents_button_bg"
+        android:src="@drawable/recents_info_light" />
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_task_view_header_progress_bar.xml b/packages/SystemUI/res/layout/recents_task_view_header_progress_bar.xml
new file mode 100644
index 0000000..f352632
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_task_view_header_progress_bar.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.
+-->
+<ProgressBar
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    style="?android:attr/progressBarStyleHorizontal"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:indeterminateOnly="false"
+    android:visibility="invisible" />
\ 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 83cfc76..cce07bd 100644
--- a/packages/SystemUI/res/layout/remote_input.xml
+++ b/packages/SystemUI/res/layout/remote_input.xml
@@ -23,16 +23,16 @@
         android:id="@+id/remote_input"
         android:layout_height="match_parent"
         android:layout_width="match_parent"
-        android:paddingStart="16dp"
-        android:paddingEnd="12dp"
-        android:paddingBottom="4dp"
-        android:paddingTop="2dp">
+        android:paddingEnd="12dp">
 
     <view class="com.android.systemui.statusbar.policy.RemoteInputView$RemoteEditText"
             android:id="@+id/remote_input_text"
             android:layout_height="match_parent"
             android:layout_width="0dp"
             android:layout_weight="1"
+            android:paddingTop="2dp"
+            android:paddingBottom="4dp"
+            android:paddingStart="16dp"
             android:paddingEnd="12dp"
             android:gravity="start|center_vertical"
             android:textAppearance="?android:attr/textAppearance"
@@ -47,7 +47,9 @@
     <FrameLayout
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_gravity="center_vertical">
+            android:layout_gravity="center_vertical"
+            android:paddingTop="2dp"
+            android:paddingBottom="4dp">
 
         <ImageButton
                 android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index f8bd6fd..c634cd6 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
 **
 ** Copyright 2011, The Android Open Source Project
 **
@@ -78,7 +77,7 @@
     </FrameLayout>
     <View
         android:id="@+id/wifi_signal_spacer"
-        android:layout_width="4dp"
+        android:layout_width="@dimen/status_bar_wifi_signal_spacer_width"
         android:layout_height="4dp"
         android:visibility="gone"
         />
@@ -113,7 +112,7 @@
     </FrameLayout>
     <View
         android:id="@+id/wifi_airplane_spacer"
-        android:layout_width="4dp"
+        android:layout_width="@dimen/status_bar_airplane_spacer_width"
         android:layout_height="4dp"
         android:visibility="gone"
         />
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index a5b3a83..39c16d7 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
 **
 ** Copyright 2006, The Android Open Source Project
 **
@@ -48,34 +47,14 @@
         android:orientation="horizontal"
         >
 
+        <!-- The alpha of this area is controlled from both PhoneStatusBarTransitions and
+             PhoneStatusBar (DISABLE_NOTIFICATION_ICONS). -->
         <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
             android:id="@+id/notification_icon_area"
             android:layout_width="0dip"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            android:orientation="horizontal"
-            >
-            <!-- The alpha of this area is both controlled from PhoneStatusBarTransitions and
-                 PhoneStatusBar (DISABLE_NOTIFICATION_ICONS), so we need two views here. -->
-            <com.android.keyguard.AlphaOptimizedLinearLayout
-                android:id="@+id/notification_icon_area_inner"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                >
-                <com.android.systemui.statusbar.StatusBarIconView android:id="@+id/moreIcon"
-                    android:layout_width="@dimen/status_bar_icon_size"
-                    android:layout_height="match_parent"
-                    android:src="@drawable/stat_notify_more"
-                    android:visibility="gone"
-                    />
-                <com.android.systemui.statusbar.phone.IconMerger android:id="@+id/notificationIcons"
-                    android:layout_width="match_parent"
-                    android:layout_height="match_parent"
-                    android:layout_alignParentStart="true"
-                    android:gravity="center_vertical"
-                    android:orientation="horizontal"/>
-            </com.android.keyguard.AlphaOptimizedLinearLayout>
-        </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
+            android:orientation="horizontal" />
 
         <com.android.keyguard.AlphaOptimizedLinearLayout android:id="@+id/system_icon_area"
             android:layout_width="wrap_content"
@@ -91,7 +70,8 @@
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
                 android:singleLine="true"
-                android:paddingStart="7dp"
+                android:paddingStart="@dimen/status_bar_clock_starting_padding"
+                android:paddingEnd="@dimen/status_bar_clock_end_padding"
                 android:gravity="center_vertical|start"
                 />
         </com.android.keyguard.AlphaOptimizedLinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index bfa13e2..89abe2d 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
 **
 ** Copyright 2006, The Android Open Source Project
 **
@@ -56,20 +55,13 @@
                     layout="@layout/qs_panel"
                     android:layout_marginTop="@dimen/status_bar_header_height_expanded"
                     android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_marginLeft="@dimen/notification_side_padding"
-                    android:layout_marginRight="@dimen/notification_side_padding"/>
+                    android:layout_height="wrap_content" />
 
                 <!-- A view to reserve space for the collapsed stack -->
                 <!-- Layout height: notification_min_height + bottom_stack_peek_amount -->
                 <View
                     android:id="@+id/reserve_notification_space"
                     android:layout_height="@dimen/min_stack_height"
-                    android:layout_width="match_parent"
-                    android:layout_marginTop="@dimen/notifications_top_padding" />
-
-                <View
-                    android:layout_height="@dimen/notification_side_padding"
                     android:layout_width="match_parent" />
             </LinearLayout>
         </com.android.systemui.statusbar.phone.ObservableScrollView>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 5eca471..dd75dbf 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -23,8 +23,6 @@
     android:layout_width="@dimen/notification_panel_width"
     android:layout_height="@dimen/status_bar_header_height"
     android:layout_gravity="@integer/notification_panel_layout_gravity"
-    android:paddingStart="@dimen/notification_side_padding"
-    android:paddingEnd="@dimen/notification_side_padding"
     android:baselineAligned="false"
     android:elevation="4dp"
     android:background="@drawable/notification_header_bg"
diff --git a/packages/SystemUI/res/layout/status_bar_no_recent_apps.xml b/packages/SystemUI/res/layout/status_bar_no_recent_apps.xml
index 1675773..adfaed13 100644
--- a/packages/SystemUI/res/layout/status_bar_no_recent_apps.xml
+++ b/packages/SystemUI/res/layout/status_bar_no_recent_apps.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
 **
 ** Copyright 2011, The Android Open Source Project
 **
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 0cea7ae..62fdd42 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -65,7 +65,7 @@
         android:id="@+id/notification_guts_stub"
         android:inflatedId="@+id/notification_guts"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_height="wrap_content"
         />
 
 </com.android.systemui.statusbar.ExpandableNotificationRow>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml b/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml
deleted file mode 100644
index e220a16..0000000
--- a/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml
+++ /dev/null
@@ -1,30 +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
-  -->
-
-<!-- Extends FrameLayout -->
-<com.android.systemui.statusbar.SpeedBumpView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="@dimen/speed_bump_height"
-    android:visibility="gone"
-    >
-    <com.android.systemui.statusbar.AlphaOptimizedView
-        android:id="@+id/speedbump_line"
-        android:layout_width="match_parent"
-        android:layout_height="1dp"
-        android:background="#6fdddddd"
-        android:layout_gravity="center_vertical"/>
-</com.android.systemui.statusbar.SpeedBumpView>
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 7ac9c41..3dca77d 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -65,8 +65,6 @@
                  android:layout_width="@dimen/notification_panel_width"
                  android:layout_height="wrap_content"
                  android:layout_gravity="@integer/notification_panel_layout_gravity"
-                 android:paddingLeft="@dimen/notification_side_padding"
-                 android:paddingRight="@dimen/notification_side_padding"
                  android:visibility="invisible">
         <FrameLayout
                 android:layout_width="match_parent"
@@ -80,20 +78,14 @@
     </FrameLayout>
 
     <ViewStub android:id="@+id/fullscreen_user_switcher_stub"
-              android:layout="@layout/fullscreen_user_switcher"
+              android:layout="@layout/car_fullscreen_user_switcher"
               android:layout_width="match_parent"
               android:layout_height="match_parent"/>
 
-    <com.android.systemui.statusbar.phone.PanelHolder
-        android:id="@+id/panel_holder"
+    <include layout="@layout/status_bar_expanded"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:background="@color/transparent" >
-        <include layout="@layout/status_bar_expanded"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:visibility="gone" />
-    </com.android.systemui.statusbar.phone.PanelHolder>
+        android:visibility="gone" />
 
     <com.android.systemui.statusbar.ScrimView android:id="@+id/scrim_in_front"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/switch_bar.xml b/packages/SystemUI/res/layout/switch_bar.xml
new file mode 100644
index 0000000..f98de96
--- /dev/null
+++ b/packages/SystemUI/res/layout/switch_bar.xml
@@ -0,0 +1,48 @@
+<?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:id="@+id/switch_bar"
+    android:layout_width="match_parent"
+    android:layout_height="?android:attr/actionBarSize"
+    android:background="@drawable/switchbar_background"
+    android:paddingStart="16dp"
+    android:paddingEnd="16dp"
+    android:clickable="true"
+    android:gravity="center">
+
+    <TextView android:id="@+id/switch_text"
+        android:layout_height="wrap_content"
+        android:layout_width="0dp"
+        android:layout_weight="1"
+        android:layout_gravity="center_vertical"
+        android:paddingStart="48dp"
+        android:maxLines="2"
+        android:ellipsize="end"
+        android:textAppearance="@android:style/TextAppearance.Material.Title"
+        android:textColor="?android:attr/textColorPrimaryInverse"
+        android:textAlignment="viewStart"
+        android:text="@string/switch_bar_on" />
+
+    <Switch
+        android:id="@android:id/switch_widget"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:background="@null"
+        android:theme="@style/ThemeOverlay.SwitchBar" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/system_icons.xml b/packages/SystemUI/res/layout/system_icons.xml
index 943e846..e9448db 100644
--- a/packages/SystemUI/res/layout/system_icons.xml
+++ b/packages/SystemUI/res/layout/system_icons.xml
@@ -30,11 +30,11 @@
         android:id="@+id/signal_cluster"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginStart="2.5dp"/>
+        android:layout_marginStart="@dimen/signal_cluster_margin_start"/>
 
     <!-- battery must be padded below to match assets -->
     <com.android.systemui.BatteryMeterView android:id="@+id/battery"
-        android:layout_height="14.5dp"
-        android:layout_width="9.5dp"
+        android:layout_height="@dimen/status_bar_battery_icon_height"
+        android:layout_width="@dimen/status_bar_battery_icon_width"
         android:layout_marginBottom="@dimen/battery_margin_bottom"/>
 </LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/tv_pip_menu.xml b/packages/SystemUI/res/layout/tv_pip_menu.xml
new file mode 100644
index 0000000..a638d17
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_pip_menu.xml
@@ -0,0 +1,61 @@
+<?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.
+*/
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <FrameLayout
+        android:layout_alignParentEnd="true"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:paddingStart="10dp"
+        android:paddingEnd="10dp"
+        android:background="#88FFFFFF">
+        <LinearLayout
+            android:orientation="vertical"
+            android:layout_gravity="center_vertical"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" >
+
+            <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" />
+        </LinearLayout>
+    </FrameLayout>
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/tv_pip_overlay.xml b/packages/SystemUI/res/layout/tv_pip_overlay.xml
new file mode 100644
index 0000000..e8691b5
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_pip_overlay.xml
@@ -0,0 +1,33 @@
+<?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">
+    <TextView
+        android:id="@+id/guide_overlay"
+        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" />
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 7617ed4..34796cd 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -19,8 +19,6 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:layout_marginBottom="@dimen/volume_dialog_margin_bottom"
-    android:layout_marginLeft="@dimen/notification_side_padding"
-    android:layout_marginRight="@dimen/notification_side_padding"
     android:background="@drawable/volume_dialog_background"
     android:translationZ="4dp" >
 
@@ -46,6 +44,9 @@
         <!-- volume rows added and removed here! :-) -->
 
         <include layout="@layout/volume_zen_footer" />
+
+        <!-- Only shown from Tuner setting -->
+        <include layout="@layout/zen_mode_panel" />
     </LinearLayout>
 
-</RelativeLayout>
\ No newline at end of file
+</RelativeLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 0cc09e7..f1000ff 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -331,6 +331,8 @@
     <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>
@@ -364,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Batteryspaarder is aan"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Verminder werkverrigting en agtergronddata"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Skakel batterybespaarder af"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Inhoud versteek"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sal alles begin vasvang wat op jou skerm gewys word."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Moenie weer wys nie"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Vee alles uit"</string>
@@ -449,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Geblokkeer"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Battery (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</string>
+    <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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-af/strings_car.xml b/packages/SystemUI/res/values-af/strings_car.xml
new file mode 100644
index 0000000..7c6f609
--- /dev/null
+++ b/packages/SystemUI/res/values-af/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">"Ry veilig"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Bly heeltemal bewus van bestuurtoestande en gehoorsaam toepaslike wette altyd. Rigtingaanwysings sal dalk onakkuraat, onvolledig, gevaarlik, ontoepaslik of verbode wees of behels dat administratiewe gebiede oorgesteek word. Besigheidsinligting sal dalk ook onakkuraat of onvolledig wees. Data is nie intyds nie en liggingakkuraatheid kan nie gewaarborg word nie. Moenie jou mobiele toestel hanteer of programme wat nie vir Android Auto bedoel is, gebruik terwyl jy bestuur nie."</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..afb7fec
--- /dev/null
+++ b/packages/SystemUI/res/values-af/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Kanselleer"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Hou HOME om PIP te beheer"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index a6c1376..fa8dc9d 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"ተጨማሪ"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> ተጨማሪ"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"ይዘቶች ተደብቀዋል"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"የታገዱ"</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_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_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="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="3476715163685592453">"ባትሪ (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings_car.xml b/packages/SystemUI/res/values-am/strings_car.xml
new file mode 100644
index 0000000..8550c42
--- /dev/null
+++ b/packages/SystemUI/res/values-am/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-am/strings_tv.xml b/packages/SystemUI/res/values-am/strings_tv.xml
new file mode 100644
index 0000000..0184601
--- /dev/null
+++ b/packages/SystemUI/res/values-am/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"ይቅር"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIPን ለመቆጣጠር መነሻን ተጭነው ይያዙ"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index bb8602b..10853bf 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -305,8 +305,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"المزيد"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> أخرى"</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,6 +335,8 @@
     <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>
@@ -369,7 +370,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"المحتويات مخفية"</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>
@@ -454,4 +454,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"تم الحظر"</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_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_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="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="3476715163685592453">"البطارية (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings_car.xml b/packages/SystemUI/res/values-ar/strings_car.xml
new file mode 100644
index 0000000..0f315a4
--- /dev/null
+++ b/packages/SystemUI/res/values-ar/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-ar/strings_tv.xml b/packages/SystemUI/res/values-ar/strings_tv.xml
new file mode 100644
index 0000000..28329d5
--- /dev/null
+++ b/packages/SystemUI/res/values-ar/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"‏إغلاق 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_cancel" msgid="5173898361050559462">"إلغاء"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"‏اضغط مع الاستمرار على \"الرئيسية\" للتحكم في PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index f6a5f0f..00b78b2 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"Daha çox"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> Daha çox"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Enerji qənaəti aktivdir"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Performansı azaldır və arxa fon datasını məhdudlaşdırır"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Enerjiyə qənaət rejimini deaktiv edin"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Məzmun gizlidir"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ekranınızda olan hər şeyin şəklini çəkəcək."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Daha göstərmə"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Hamısını silin"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Bloklanmış"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Enerji (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</string>
+    <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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings_car.xml b/packages/SystemUI/res/values-az-rAZ/strings_car.xml
new file mode 100644
index 0000000..9ac7ce0
--- /dev/null
+++ b/packages/SystemUI/res/values-az-rAZ/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">"Təhlükəsiz sürün"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Yol şəraitindən tam xəbərdar olun və hər zaman tətbiq olunan qaydalara riayət edin. İstiqamətlər qeyri-dəqiq, natamam, təhlükəli, uyğun olmayan, qadağan edilmiş və ya inzibati sahələrə keçid ilə nəticələnə bilər. Biznes məlumatı da qeyri-dəqiq və ya natamam ola bilər. Data real vaxtda deyil və məkan dəqiqliyinə zəmanət verilmir. Avtomobil idarə edərkən mobil cihazınızı elinizə almayın və ya Android Avto üçün nəzərdə tutulmamış tətbiqlərdən istifadə etməyin."</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..8f3be27
--- /dev/null
+++ b/packages/SystemUI/res/values-az-rAZ/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Ləğv edin"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIP idarə etmək üçün ƏSAS düyməni basıb saxlayın"</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 f14b644..4b3f157 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -302,8 +302,7 @@
     <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>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Još"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"Još <xliff:g id="NUMBER">%d</xliff:g>"</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>
@@ -333,6 +332,8 @@
     <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>
@@ -366,7 +367,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Štednja baterije je uključena"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Smanjuje performanse i pozadinske podatke"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Isključi štednju baterije"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Sadržaj je sakriven"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> će početi da snima sve što se prikazuje na ekranu."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ne prikazuj ponovo"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Obriši sve"</string>
@@ -451,4 +451,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Blokirana"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Baterija (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings_car.xml b/packages/SystemUI/res/values-b+sr+Latn/strings_car.xml
new file mode 100644
index 0000000..f45af7c
--- /dev/null
+++ b/packages/SystemUI/res/values-b+sr+Latn/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">"Vozite bezbedno"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Uvek vodite računa o uslovima vožnje i uvek poštujte primenjive zakone. Uputstva mogu da budu netačna, nepotpuna, opasna, neprikladna ili zabranjena, odnosno da podrazumevaju prelazak između administrativnih oblasti. I podaci o preduzeću mogu da budu netačni ili nepotpuni. Podaci ne nastaju u realnom vremenu i ne možemo da garantujemo preciznost lokacije. Nemojte da upotrebljavate mobilni uređaj niti da koristite aplikacije koje nisu namenjene za Android Auto tokom vožnje."</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..7d35b20
--- /dev/null
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Otkaži"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Zadržite taster za POČETNI EKRAN da biste kontrolisali PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index fcbbeef..a5fdd8e 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"Още"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"Още <xliff:g id="NUMBER">%d</xliff:g>"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"Скрито съдържание"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Блокирано"</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_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_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="color_apply" msgid="9212602012641034283">"Прилагане"</string>
+    <string name="color_revert_title" msgid="4746666545480534663">"Потвърждаване на настройките"</string>
+    <string name="color_revert_message" msgid="9116001069397996691">"Някои настройки за цветовете могат да направят това устройство неизползваемо. За да ги потвърдите, кликнете върху „OK“. В противен случай те ще бъдат нулирани след 10 секунди."</string>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Батерия (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings_car.xml b/packages/SystemUI/res/values-bg/strings_car.xml
new file mode 100644
index 0000000..bd9fe79
--- /dev/null
+++ b/packages/SystemUI/res/values-bg/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-bg/strings_tv.xml b/packages/SystemUI/res/values-bg/strings_tv.xml
new file mode 100644
index 0000000..82c2d08
--- /dev/null
+++ b/packages/SystemUI/res/values-bg/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"Затваряне на режима „Картина в картина“"</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_cancel" msgid="5173898361050559462">"Отказ"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Задръжте „HOME“, за да контролирате режима „Картина в картина“"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 48d3f46..d6f5868 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"আরো"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"আরো <xliff:g id="NUMBER">%d</xliff:g>টি"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"লুকানো বিষয়বস্তু"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"অবরুদ্ধ"</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_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_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="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="3476715163685592453">"ব্যাটারি (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings_car.xml b/packages/SystemUI/res/values-bn-rBD/strings_car.xml
new file mode 100644
index 0000000..d8a8732
--- /dev/null
+++ b/packages/SystemUI/res/values-bn-rBD/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-bn-rBD/strings_tv.xml b/packages/SystemUI/res/values-bn-rBD/strings_tv.xml
new file mode 100644
index 0000000..15d0e82
--- /dev/null
+++ b/packages/SystemUI/res/values-bn-rBD/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"বাতিল করুন"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIP নিয়ন্ত্রণ করতে HOME ধরে রাখুন"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-bs-rBA/strings_car.xml b/packages/SystemUI/res/values-bs-rBA/strings_car.xml
new file mode 100644
index 0000000..744eea8
--- /dev/null
+++ b/packages/SystemUI/res/values-bs-rBA/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">"Vozite sigurno"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Uvijek budite upoznati s uslovima za vožnju i poštujte važeće zakone. Upute za kretanje mogu biti netačne, nepotpune, opasne, neprikladne, zabranjene ili takve da obuhvataju prelaženje preko administrativnih područja. Poslovne informacije takođe mogu biti netačne ili nepotpune. Podaci nisu u realnom vremenu, a tačnost lokacije se ne može garantirati. U vožnji nemojte rukovati mobilnim uređajem ili koristiti aplikacije koje nisu namijenjene za Android Auto."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index a83404c..714b750 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -331,6 +331,8 @@
     <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>
@@ -364,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Estalvi de bateria activat"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Redueix el rendiment i l\'ús de les dades en segon pla."</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactiva l\'estalvi de bateria"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Contingut amagat"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> començarà a enregistrar tot el que es mostri a la pantalla."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"No ho tornis a mostrar"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Esborra-ho tot"</string>
@@ -449,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Bloquejades"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Bateria (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings_car.xml b/packages/SystemUI/res/values-ca/strings_car.xml
new file mode 100644
index 0000000..efcac23
--- /dev/null
+++ b/packages/SystemUI/res/values-ca/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">"Condueix amb precaució"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Estigues al cas de la conducció i respecta sempre les lleis aplicables. Les indicacions poden ser inexactes, perilloses, inadequades o incompletes, o bé poden comportar maniobres prohibides o que creuis circumscripcions territorials. La informació de les empreses també pot ser inexacta o incompleta. No s\'ofereixen dades en temps real i no es pot garantir la precisió de les ubicacions. Mentre condueixes, no utilitzis el dispositiu mòbil ni cap aplicació que no estigui destinada a Android Auto."</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..8daa867
--- /dev/null
+++ b/packages/SystemUI/res/values-ca/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Cancel·la"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Mantén premut el botó INICI per controlar PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 7895951..dcd42e0 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -303,8 +303,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"vyhledat"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikaci <xliff:g id="APP">%s</xliff:g> nelze spustit."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Další"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"ještě <xliff:g id="NUMBER">%d</xliff:g>"</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>
@@ -334,6 +333,8 @@
     <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>
@@ -367,7 +368,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Režim Úspora baterie je zapnutý."</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Omezuje výkon a data na pozadí"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Vypnout úsporu baterie"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Skrytý obsah"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikace <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> začne zaznamenávat vše, co je zobrazeno na obrazovce."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Tuto zprávu příště nezobrazovat"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Smazat vše"</string>
@@ -452,4 +452,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Blokováno"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Baterie (<xliff:g id="ID_1">%1$d</xliff:g> %%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings_car.xml b/packages/SystemUI/res/values-cs/strings_car.xml
new file mode 100644
index 0000000..d5e3324
--- /dev/null
+++ b/packages/SystemUI/res/values-cs/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">"Řiďte bezpečně"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Věnujte plnou pozornost řízení a dodržujte platné předpisy. Trasy mohou být nepřesné, neúplné, nebezpečné, nevhodné, zakázané nebo mohou zahrnovat překročení hranic. Informace o firmách mohou být také nepřesné nebo neúplné. Data se neaktualizují v reálném čase a přesnost polohy nelze zaručit. Mobilní zařízení ani aplikace určené pro Android Auto nepoužívejte za jízdy."</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..8675c78
--- /dev/null
+++ b/packages/SystemUI/res/values-cs/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Zrušit"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Chcete-li funkci PIP ovládat, podržte tlačítko PLOCHA"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index e69d069..835ce69 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"Mere"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> mere"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Batterisparefunktion er slået til"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reducerer ydeevne og baggrundsdata"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Deaktiver batterisparefunktion"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Indholdet er skjult"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vil begynde at optage alt, hvad der vises på din skærm."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Vis ikke igen"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Ryd alt"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Blokeret"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Batteri (<xliff:g id="ID_1">%1$d</xliff:g> %%)"</string>
+    <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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings_car.xml b/packages/SystemUI/res/values-da/strings_car.xml
new file mode 100644
index 0000000..6a421da
--- /dev/null
+++ b/packages/SystemUI/res/values-da/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">"Kør forsigtigt"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Vær opmærksom på køreforholdene, og overhold altid færdselsloven. Rutevejledningen kan være unøjagtig, ufuldstændig, farlig, upassende, forbudt eller involvere krydsning af forbudte områder. Virksomhedsoplysninger kan også være unøjagtige eller ufuldstændige. Data er ikke i realtid, og placeringers nøjagtighed kan ikke garanteres. Håndter ikke din mobilenhed, og brug ikke apps, der ikke er beregnet til Android Auto, mens du kører."</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..a40e34c
--- /dev/null
+++ b/packages/SystemUI/res/values-da/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Annuller"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Hold HOME-knappen nede for at styre PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index dc62e65..4888c23 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -23,7 +23,7 @@
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Löschen"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Aus Liste entfernen"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"App-Info"</string>
-    <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Hier sehen Sie Ihre zuletzt geöffneten Apps."</string>
+    <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Hier siehst du deine zuletzt geöffneten Apps."</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Kürzlich geöffnete Apps schließen"</string>
     <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
       <item quantity="other">%d Bildschirme in der Übersicht</item>
@@ -35,9 +35,9 @@
     <string name="battery_low_title" msgid="6456385927409742437">"Akku ist schwach"</string>
     <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> verbleibend"</string>
     <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> verbleibend. Der Energiesparmodus ist aktiviert."</string>
-    <string name="invalid_charger" msgid="4549105996740522523">"USB-Aufladung wird nicht unterstützt.\nVerwenden Sie das mitgelieferte Aufladegerät."</string>
+    <string name="invalid_charger" msgid="4549105996740522523">"USB-Aufladung wird nicht unterstützt.\nVerwende das mitgelieferte Aufladegerät."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Laden per USB wird nicht unterstützt."</string>
-    <string name="invalid_charger_text" msgid="5474997287953892710">"Verwenden Sie nur das im Lieferumfang enthaltene Ladegerät."</string>
+    <string name="invalid_charger_text" msgid="5474997287953892710">"Verwende nur das im Lieferumfang enthaltene Ladegerät."</string>
     <string name="battery_low_why" msgid="4553600287639198111">"Einstellungen"</string>
     <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Energiesparmodus aktivieren?"</string>
     <string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Aktivieren"</string>
@@ -64,7 +64,7 @@
     <string name="usb_debugging_message" msgid="2220143855912376496">"Der Fingerabdruck des RSA-Schlüssels für diesen Computer lautet: \n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="303335496705863070">"Von diesem Computer immer zulassen"</string>
     <string name="usb_debugging_secondary_user_title" msgid="6353808721761220421">"USB-Debugging nicht zulässig"</string>
-    <string name="usb_debugging_secondary_user_message" msgid="8572228137833020196">"Der momentan auf diesem Gerät angemeldete Nutzer kann das USB-Debugging nicht aktivieren. Wechseln Sie zu einem Administratorkonto, um diese Funktion nutzen zu können."</string>
+    <string name="usb_debugging_secondary_user_message" msgid="8572228137833020196">"Der momentan auf diesem Gerät angemeldete Nutzer kann das USB-Debugging nicht aktivieren. Wechsle zu einem Administratorkonto, um diese Funktion nutzen zu können."</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom auf Bildschirmgröße"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Auf Bildschirmgröße anpassen"</string>
     <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Screenshot wird gespeichert..."</string>
@@ -73,7 +73,7 @@
     <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/Ihr Unternehmen lässt dies nicht zu."</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="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>
@@ -222,7 +222,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-Daten pausiert"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilfunkdaten pausiert"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Daten pausiert"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Da Ihr festgelegtes Datenlimit erreicht wurde, hat das Gerät die Datennutzung für den Rest dieses Zeitraums pausiert.\n\nWenn Sie diese fortsetzen, können möglicherweise Kosten bei Ihrem Mobilfunkanbieter entstehen."</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Da dein festgelegtes Datenlimit erreicht wurde, hat das Gerät die Datennutzung für den Rest dieses Zeitraums pausiert.\n\nWenn du die Nutzung fortsetzt, entstehen möglicherweise Kosten bei deinem Mobilfunkanbieter."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Fortsetzen"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Keine Internetverbindung"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN verbunden"</string>
@@ -295,14 +295,13 @@
     <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 sehen Sie Ihre zuletzt geöffneten Apps."</string>
+    <string name="recents_empty_message" msgid="8682129509540827999">"Hier siehst du deine zuletzt geöffneten Apps."</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>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Mehr"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> weitere"</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>
@@ -314,9 +313,9 @@
     <string name="description_target_search" msgid="3091587249776033139">"Suche"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Zum <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> nach oben schieben"</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Zum <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> nach links schieben"</string>
-    <string name="zen_priority_introduction" msgid="3070506961866919502">"Klingeltöne und die Vibration werden deaktiviert, außer für Weckrufe, Erinnerungen, Termine sowie Anrufe von zuvor von Ihnen festgelegten Personen."</string>
+    <string name="zen_priority_introduction" msgid="3070506961866919502">"Klingeltöne und die Vibration werden deaktiviert, außer für Weckrufe, Erinnerungen, Termine sowie Anrufe von zuvor von dir festgelegten Personen."</string>
     <string name="zen_priority_customize_button" msgid="7948043278226955063">"Anpassen"</string>
-    <string name="zen_silence_introduction_voice" msgid="2284540992298200729">"Hierdurch werden alle Klingeltöne und Vibrationsalarme stummgeschaltet, auch für Weckrufe, Musik, Videos und Spiele. Anrufe können Sie jedoch weiterhin tätigen."</string>
+    <string name="zen_silence_introduction_voice" msgid="2284540992298200729">"Hierdurch werden alle Klingeltöne und Vibrationsalarme stummgeschaltet, auch für Weckrufe, Musik, Videos und Spiele. Anrufe kannst du jedoch weiterhin tätigen."</string>
     <string name="zen_silence_introduction" msgid="3137882381093271568">"Hierdurch werden alle Klingeltöne und Vibrationsalarme stummgeschaltet, auch für Weckrufe, Musik, Videos und Spiele."</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">"Weniger dringende Benachrichtigungen unten"</string>
@@ -332,6 +331,8 @@
     <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>
@@ -348,7 +349,7 @@
     <string name="guest_exit_guest_dialog_message" msgid="4155503224769676625">"Alle Apps und Daten in dieser Sitzung werden gelöscht."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7402231963862520531">"Entfernen"</string>
     <string name="guest_wipe_session_title" msgid="6419439912885956132">"Willkommen zurück im Gastmodus"</string>
-    <string name="guest_wipe_session_message" msgid="8476238178270112811">"Möchten Sie Ihre Sitzung fortsetzen?"</string>
+    <string name="guest_wipe_session_message" msgid="8476238178270112811">"Möchtest du deine Sitzung fortsetzen?"</string>
     <string name="guest_wipe_session_wipe" msgid="5065558566939858884">"Von vorn"</string>
     <string name="guest_wipe_session_dontwipe" msgid="1401113462524894716">"Ja, weiter"</string>
     <string name="guest_notification_title" msgid="1585278533840603063">"Gastnutzer"</string>
@@ -358,15 +359,14 @@
     <string name="user_logout_notification_text" msgid="3350262809611876284">"Aktuellen Nutzer abmelden"</string>
     <string name="user_logout_notification_action" msgid="1195428991423425062">"Nutzer abmelden"</string>
     <string name="user_add_user_title" msgid="4553596395824132638">"Neuen Nutzer hinzufügen?"</string>
-    <string name="user_add_user_message_short" msgid="2161624834066214559">"Wenn Sie einen neuen Nutzer hinzufügen, muss dieser seinen Bereich einrichten.\n\nJeder Nutzer kann Apps für alle anderen Nutzer aktualisieren."</string>
+    <string name="user_add_user_message_short" msgid="2161624834066214559">"Wenn du einen neuen Nutzer hinzufügst, muss dieser seinen Bereich einrichten.\n\nJeder Nutzer kann Apps für alle anderen Nutzer aktualisieren."</string>
     <string name="user_remove_user_title" msgid="4681256956076895559">"Nutzer entfernen?"</string>
     <string name="user_remove_user_message" msgid="1453218013959498039">"Alle Apps und Daten dieses Nutzers werden gelöscht."</string>
     <string name="user_remove_user_remove" msgid="7479275741742178297">"Entfernen"</string>
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Energiesparmodus ist aktiviert"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduzierung der Leistung und Hintergrunddaten"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Energiesparmodus deaktivieren"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Inhalte ausgeblendet"</string>
-    <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> nimmt alle auf Ihrem Bildschirm angezeigten Aktivitäten auf."</string>
+    <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> nimmt alle auf deinem Bildschirm angezeigten Aktivitäten auf."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Nicht erneut anzeigen"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Alle löschen"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Jetzt starten"</string>
@@ -379,17 +379,17 @@
     <string name="monitoring_title" msgid="169206259253048106">"Netzwerküberwachung"</string>
     <string name="disable_vpn" msgid="4435534311510272506">"VPN deaktivieren"</string>
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPN-Verbindung trennen"</string>
-    <string name="monitoring_description_device_owned" msgid="5780988291898461883">"Ihr Gerät wird verwaltet von <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nIhr Administrator kann die zu Ihrem Gerät gehörigen Einstellungen, Unternehmenszugriffsrechte, Apps und Daten überwachen und verwalten, einschließlich der Standortinformationen Ihres Geräts. Weitere Informationen erhalten Sie bei Ihrem Administrator."</string>
-    <string name="monitoring_description_vpn" msgid="4445150119515393526">"Sie haben einer App gestattet, eine VPN-Verbindung einzurichten.\n\nDiese App kann Ihr Gerät und Ihre Netzwerkaktivitäten überwachen, einschließlich E-Mails, Apps und Websites."</string>
-    <string name="monitoring_description_vpn_device_owned" msgid="3090670777499161246">"Ihr Gerät wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet.\n\nIhr Administrator kann die zu Ihrem Gerät gehörigen Einstellungen, Unternehmenszugriffsrechte, Apps und Daten überwachen und verwalten, einschließlich der Standortinformationen Ihres Geräts.\n\nSie sind zudem mit einem VPN verbunden, das Ihre persönliche Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites.\n\nWeitere Informationen erhalten Sie bei Ihrem Administrator."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Ihr Arbeitsprofil wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet.\n\nIhr Administrator kann Ihre Netzwerkaktivität überwachen, einschließlich E-Mails, Apps und Websites.\n\nWeitere Informationen erhalten Sie bei Ihrem Administrator.\n\nSie sind zudem mit einem VPN verbunden, das Ihre persönliche Netzwerkaktivität überwachen kann."</string>
+    <string name="monitoring_description_device_owned" msgid="5780988291898461883">"Dein Gerät wird verwaltet von <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nDein Administrator kann die zu deinem Gerät gehörigen Einstellungen, Unternehmenszugriffsrechte, Apps und Daten überwachen und verwalten, einschließlich der Standortinformationen deines Geräts. Weitere Informationen erhältst du bei deinem Administrator."</string>
+    <string name="monitoring_description_vpn" msgid="4445150119515393526">"Du hast einer App gestattet, eine VPN-Verbindung einzurichten.\n\nDiese App kann dein Gerät und deine Netzwerkaktivitäten überwachen, einschließlich E-Mails, Apps und Websites."</string>
+    <string name="monitoring_description_vpn_device_owned" msgid="3090670777499161246">"Dein Gerät wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet.\n\nDein Administrator kann die zu deinem Gerät gehörigen Einstellungen, Unternehmenszugriffsrechte, Apps und Daten überwachen und verwalten, einschließlich der Standortinformationen deines Geräts.\n\nDu bist außerdem mit einem VPN verbunden, das deine persönliche Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites.\n\nWeitere Informationen erhältst du bei deinem Administrator."</string>
+    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Dein Arbeitsprofil wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet.\n\nDein Administrator kann deine Netzwerkaktivität überwachen, einschließlich E-Mails, Apps und Websites.\n\nWeitere Informationen erhältst du bei deinem Administrator.\n\nDu bist außerdem mit einem VPN verbunden, das deine persönliche Netzwerkaktivität überwachen kann."</string>
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
-    <string name="monitoring_description_app" msgid="6259179342284742878">"Sie sind mit der App <xliff:g id="APPLICATION">%1$s</xliff:g> verbunden, die Ihre Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites."</string>
-    <string name="monitoring_description_app_personal" msgid="484599052118316268">"Sie sind mit der App <xliff:g id="APPLICATION">%1$s</xliff:g> verbunden, die Ihre persönliche Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Ihr Arbeitsprofil wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet. Das Profil ist mit der App <xliff:g id="APPLICATION">%2$s</xliff:g> verbunden, die Ihre geschäftlichen Netzwerkaktivitäten überwachen kann, einschließlich E-Mails, Apps und Websites.\n\nWeitere Informationen erhalten Sie von Ihrem Administrator."</string>
-    <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Ihr Arbeitsprofil wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet. Das Profil ist mit der App <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> verbunden, die Ihre geschäftliche Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites.\n\nSie sind außerdem mit der App <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> verbunden, die Ihre persönliche Netzwerkaktivität überwachen kann."</string>
-    <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Ihr Gerät wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet.\n\nIhr Administrator kann die zu Ihrem Gerät gehörigen Einstellungen, Unternehmenszugriffsrechte, Apps und Daten überwachen und verwalten, einschließlich der Standortinformationen Ihres Geräts.\n\nSie sind mit der App <xliff:g id="APPLICATION">%2$s</xliff:g> verbunden, die Ihre persönlichen Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites.\n\nWeitere Informationen erhalten Sie bei Ihrem Administrator."</string>
-    <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Das Gerät bleibt gesperrt, bis Sie es manuell entsperren."</string>
+    <string name="monitoring_description_app" msgid="6259179342284742878">"Du bist mit der App <xliff:g id="APPLICATION">%1$s</xliff:g> verbunden, die deine Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites."</string>
+    <string name="monitoring_description_app_personal" msgid="484599052118316268">"Du bist mit der App <xliff:g id="APPLICATION">%1$s</xliff:g> verbunden, die deine persönliche Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites."</string>
+    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Dein Arbeitsprofil wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet. Das Profil ist mit der App <xliff:g id="APPLICATION">%2$s</xliff:g> verbunden, die deine geschäftlichen Netzwerkaktivitäten überwachen kann, einschließlich E-Mails, Apps und Websites.\n\nWeitere Informationen erhältst du von deinem Administrator."</string>
+    <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Dein Arbeitsprofil wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet. Das Profil ist mit der App <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> verbunden, die deine geschäftliche Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites.\n\nDu bist außerdem mit der App <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> verbunden, die deine persönliche Netzwerkaktivität überwachen kann."</string>
+    <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Dein Gerät wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet.\n\nDein Administrator kann die zu deinem Gerät gehörigen Einstellungen, Unternehmenszugriffsrechte, Apps und Daten überwachen und verwalten, einschließlich der Standortinformationen deines Geräts.\n\nDu bist außerdem mit der App <xliff:g id="APPLICATION">%2$s</xliff:g> verbunden, die deine persönliche Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites.\n\nWeitere Informationen erhältst du bei deinem Administrator."</string>
+    <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Das Gerät bleibt gesperrt, bis du es manuell entsperrst."</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Benachrichtigungen schneller erhalten"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"Vor dem Entsperren anzeigen"</string>
     <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Nein danke"</string>
@@ -399,11 +399,11 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Maximieren"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Minimieren"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Bildschirm ist fixiert"</string>
-    <string name="screen_pinning_description" msgid="3577937698406151604">"Der Bildschirm wird solange angezeigt, bis Sie die Fixierung aufheben. Berühren und halten Sie \"Zurück\", wenn Sie die Fixierung aufheben möchten."</string>
+    <string name="screen_pinning_description" msgid="3577937698406151604">"Der Bildschirm wird so lange angezeigt, bis du die Fixierung aufhebst. Berühre und halte \"Zurück\", wenn du die Fixierung aufheben möchtest."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nein danke"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ausblenden?"</string>
-    <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Sie wird wieder eingeblendet, wenn Sie sie in den Einstellungen erneut aktivieren."</string>
+    <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Sie wird wieder eingeblendet, wenn du sie in den Einstellungen erneut aktivierst."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ausblenden"</string>
     <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> will die Lautstärke regeln."</string>
     <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Zulassen"</string>
@@ -411,7 +411,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> regelt die Lautstärke."</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Zum Wiederherstellen des Originals hier tippen"</string>
     <string name="group_summary_concadenation" msgid="6846402378100148789">"\", \" "</string>
-    <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Sie verwenden Ihr Arbeitsprofil."</string>
+    <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Du verwendest dein Arbeitsprofil."</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"System UI Tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Eingebettete Akku-Prozentzahl anzeigen"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Prozentzahl für Akkustand in Statusleistensymbol anzeigen, wenn das Gerät nicht geladen wird"</string>
@@ -427,7 +427,7 @@
     <string name="status_bar_airplane" msgid="7057575501472249002">"Flugmodus"</string>
     <string name="add_tile" msgid="2995389510240786221">"Kachel hinzufügen"</string>
     <string name="broadcast_tile" msgid="3894036511763289383">"Broadcast-Kachel"</string>
-    <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"Sie erhalten einen lautlosen Weckruf <xliff:g id="WHEN">%1$s</xliff:g>, wenn Sie ihn nicht vorher ausschalten."</string>
+    <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"Du erhältst einen lautlosen Weckruf <xliff:g id="WHEN">%1$s</xliff:g>, wenn du ihn nicht vorher ausschaltest."</string>
     <string name="zen_alarm_warning" msgid="444533119582244293">"Lautloser Weckruf <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="alarm_template" msgid="3980063409350522735">"um <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="alarm_template_far" msgid="4242179982586714810">"am <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -435,13 +435,13 @@
     <string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"Hotspot"</string>
     <string name="accessibility_managed_profile" msgid="6613641363112584120">"Arbeitsprofil"</string>
     <string name="tuner_warning_title" msgid="7094689930793031682">"Für einige ein Vergnügen, aber nicht für alle"</string>
-    <string name="tuner_warning" msgid="8730648121973575701">"Mit System UI Tuner erhalten Sie zusätzliche Möglichkeiten, die Android-Benutzeroberfläche anzupassen. Achtung: Diese Testfunktionen können sich ändern, abstürzen oder in zukünftigen Versionen verschwinden."</string>
+    <string name="tuner_warning" msgid="8730648121973575701">"Mit System UI Tuner erhältst du zusätzliche Möglichkeiten, die Android-Benutzeroberfläche anzupassen. Achtung: Diese Testfunktionen können sich ändern, abstürzen oder in zukünftigen Versionen verschwinden."</string>
     <string name="tuner_persistent_warning" msgid="8597333795565621795">"Achtung: Diese Testfunktionen können sich ändern, abstürzen oder in zukünftigen Versionen verschwinden."</string>
     <string name="got_it" msgid="2239653834387972602">"OK"</string>
     <string name="tuner_toast" msgid="603429811084428439">"Herzlichen Glückwunsch! System UI Tuner wurde \"Einstellungen\" hinzugefügt."</string>
     <string name="remove_from_settings" msgid="8389591916603406378">"Aus \"Einstellungen\" entfernen"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"System UI Tuner aus \"Einstellungen\" entfernen und die Verwendung von allen zugehörigen Funktionen beenden?"</string>
-    <string name="activity_not_found" msgid="348423244327799974">"Die App ist nicht auf Ihrem Gerät installiert."</string>
+    <string name="activity_not_found" msgid="348423244327799974">"Die App ist nicht auf deinem Gerät installiert."</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Uhrsekunden anzeigen"</string>
     <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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Blockiert"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Akku (<xliff:g id="ID_1">%1$d</xliff:g> %%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings_car.xml b/packages/SystemUI/res/values-de/strings_car.xml
new file mode 100644
index 0000000..5b5920e
--- /dev/null
+++ b/packages/SystemUI/res/values-de/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">"Sicher fahren"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Achte stets auf die Straßenverhältnisse und halte dich an die geltenden Gesetze. Routen können unter Umständen fehlerhaft, unvollständig, gefährlich, ungeeignet oder verboten sein oder das Überqueren von Verwaltungsgrenzen erfordern. Informationen zum Unternehmen können ebenfalls fehlerhaft oder unvollständig sein. Die Datenübertragung erfolgt nicht in Echtzeit und die Genauigkeit der Standortangaben kann nicht gewährleistet werden. Bediene während der Fahrt nicht dein Mobilgerät und verwende keine Apps, die du nicht über Android Auto steuern kannst."</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..66e3e01
--- /dev/null
+++ b/packages/SystemUI/res/values-de/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Abbrechen"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Halte STARTSEITE gedrückt, um das PiP zu steuern."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 9cfad85..882e5fa 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"Περισσότερα"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> ακόμα"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"Κρυφό περιεχόμενο"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Αποκλεισμένες"</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_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_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="color_apply" msgid="9212602012641034283">"Εφαρμογή"</string>
+    <string name="color_revert_title" msgid="4746666545480534663">"Επιβεβαίωση ρυθμίσεων"</string>
+    <string name="color_revert_message" msgid="9116001069397996691">"Ορισμένες ρυθμίσεις χρωμάτων μπορεί να μην επιτρέπουν τη χρήση αυτής της συσκευής. Κάντε κλικ στην επιλογή OK για να επιβεβαιώσετε αυτές τις ρυθμίσεις χρωμάτων, διαφορετικά θα γίνει επαναφορά αυτών των ρυθμίσεων μετά από 10 δευτερόλεπτα."</string>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Μπαταρία (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings_car.xml b/packages/SystemUI/res/values-el/strings_car.xml
new file mode 100644
index 0000000..e960713
--- /dev/null
+++ b/packages/SystemUI/res/values-el/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-el/strings_tv.xml b/packages/SystemUI/res/values-el/strings_tv.xml
new file mode 100644
index 0000000..7239386
--- /dev/null
+++ b/packages/SystemUI/res/values-el/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"Κλείσιμο 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_cancel" msgid="5173898361050559462">"Ακύρωση"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Κρατήστε το πλήκτρο HOME πατημένο για να ελέγξετε το PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 30a333a..6ded945 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -331,6 +331,8 @@
     <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>
@@ -364,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Battery saver is on"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduces performance and background data"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Turn off battery saver"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will start capturing everything that\'s displayed on your screen."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Clear all"</string>
@@ -449,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Blocked"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Battery (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</string>
+    <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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings_car.xml b/packages/SystemUI/res/values-en-rAU/strings_car.xml
new file mode 100644
index 0000000..81089ba
--- /dev/null
+++ b/packages/SystemUI/res/values-en-rAU/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">"Drive safely"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Stay fully aware of driving conditions and always obey applicable laws. Directions may be inaccurate, incomplete, dangerous, not suitable, prohibited or involve crossing administrative areas. Business information may also be inaccurate or incomplete. Data is not real time and location accuracy cannot be guaranteed. Do not handle your mobile device or use apps not intended for Android Auto while driving."</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..76576dd
--- /dev/null
+++ b/packages/SystemUI/res/values-en-rAU/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Cancel"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Hold HOME to control PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 30a333a..6ded945 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -331,6 +331,8 @@
     <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>
@@ -364,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Battery saver is on"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduces performance and background data"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Turn off battery saver"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will start capturing everything that\'s displayed on your screen."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Clear all"</string>
@@ -449,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Blocked"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Battery (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</string>
+    <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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings_car.xml b/packages/SystemUI/res/values-en-rGB/strings_car.xml
new file mode 100644
index 0000000..81089ba
--- /dev/null
+++ b/packages/SystemUI/res/values-en-rGB/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">"Drive safely"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Stay fully aware of driving conditions and always obey applicable laws. Directions may be inaccurate, incomplete, dangerous, not suitable, prohibited or involve crossing administrative areas. Business information may also be inaccurate or incomplete. Data is not real time and location accuracy cannot be guaranteed. Do not handle your mobile device or use apps not intended for Android Auto while driving."</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..76576dd
--- /dev/null
+++ b/packages/SystemUI/res/values-en-rGB/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Cancel"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Hold HOME to control PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 30a333a..6ded945 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -331,6 +331,8 @@
     <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>
@@ -364,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Battery saver is on"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduces performance and background data"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Turn off battery saver"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will start capturing everything that\'s displayed on your screen."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Clear all"</string>
@@ -449,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Blocked"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Battery (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</string>
+    <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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings_car.xml b/packages/SystemUI/res/values-en-rIN/strings_car.xml
new file mode 100644
index 0000000..81089ba
--- /dev/null
+++ b/packages/SystemUI/res/values-en-rIN/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">"Drive safely"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Stay fully aware of driving conditions and always obey applicable laws. Directions may be inaccurate, incomplete, dangerous, not suitable, prohibited or involve crossing administrative areas. Business information may also be inaccurate or incomplete. Data is not real time and location accuracy cannot be guaranteed. Do not handle your mobile device or use apps not intended for Android Auto while driving."</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..76576dd
--- /dev/null
+++ b/packages/SystemUI/res/values-en-rIN/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Cancel"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Hold HOME to control PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 3ff2492..0cdb4c6 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"No se pudo iniciar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Más"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> más"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Ahorro de batería activado"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce el rendimiento y el uso de datos en segundo plano."</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactivar el ahorro de batería"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Contenidos ocultos"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> comenzará la captura de todo lo que se muestre en la pantalla."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"No volver a mostrar"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Borrar todo"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Bloqueada"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Batería (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings_car.xml b/packages/SystemUI/res/values-es-rUS/strings_car.xml
new file mode 100644
index 0000000..647236a
--- /dev/null
+++ b/packages/SystemUI/res/values-es-rUS/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">"Conducir de forma segura"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Permanece atento a la situación de conducción y cumple siempre con las leyes vigentes. Es posible que las indicaciones sean imprecisas, inadecuadas o peligrosas, que estén incompletas, que sugieran maniobras prohibidas o que impliquen atravesar áreas administrativas. La información de las empresas también puede ser imprecisa o estar incompleta. Los datos no se proporcionan en tiempo real ni se puede garantizar la precisión de las ubicaciones. No uses tu dispositivo móvil ni apps no diseñadas para Android Auto mientras conduces."</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..9b0a055
--- /dev/null
+++ b/packages/SystemUI/res/values-es-rUS/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Cancelar"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Mantén presionado el botón INICIO para controlar PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 662422b..cd5c95a 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"No se ha podido iniciar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Más"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> más"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Ahorro de batería activado"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce el rendimiento y el envío de datos en segundo plano"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactivar ahorro de batería"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Contenidos ocultos"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> empezará a capturar todo lo que aparezca en la pantalla."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"No volver a mostrar"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Borrar todo"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Bloqueado"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Batería (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings_car.xml b/packages/SystemUI/res/values-es/strings_car.xml
new file mode 100644
index 0000000..e19ca78
--- /dev/null
+++ b/packages/SystemUI/res/values-es/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">"Conduce de forma segura"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Permanece atento a la conducción y respeta siempre las normas de tráfico. Las indicaciones pueden ser inexactas, incompletas, peligrosas o inadecuadas o dar lugar a maniobras prohibidas o al cruce de zonas regionales diferentes. La información sobre empresas también puede ser inexacta o estar incompleta. No se ofrecen datos en tiempo real ni se puede garantizar la exactitud de las ubicaciones. No utilices el dispositivo móvil ni aplicaciones que no estén destinadas a Android Auto mientras conduces."</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..b9649f9
--- /dev/null
+++ b/packages/SystemUI/res/values-es/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Cancelar"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Mantén pulsado el botón INICIO para controlar PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 0fc88c4..52fc39e 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"Rohkem"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"Veel <xliff:g id="NUMBER">%d</xliff:g>"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Akusäästja on sisse lülitatud"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Vähendab jõudlust ja taustaandmeid"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Akusäästja väljalülitamine"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Sisu on peidetud"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> hakkab jäädvustama kõike, mida ekraanil kuvatakse."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ära kuva uuesti"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Tühjenda kõik"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Blokeeritud"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Aku (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</string>
+    <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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings_car.xml b/packages/SystemUI/res/values-et-rEE/strings_car.xml
new file mode 100644
index 0000000..c41385a
--- /dev/null
+++ b/packages/SystemUI/res/values-et-rEE/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">"Sõitke turvaliselt"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Olge teadlik sõidutingimustest ja järgige alati kohaldatavaid seadusi. Juhised võivad olla ebatäpsed, mittetäielikud, ohtlikud, sobimatud, keelatud või hõlmata kattuvaid administratiivpiirkondi. Ka ettevõtteteave võib olla ebatäpne või mittetäielik. Andmed pole reaalajas ja asukoha täpsust ei saa garanteerida. Ärge kasutage auto juhtimisel mobiilseadet ega rakendusi, mis pole mõeldud teenuse Android Auto jaoks."</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..8af5984
--- /dev/null
+++ b/packages/SystemUI/res/values-et-rEE/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Tühista"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIP juhtimiseks hoidke all nuppu AVAEKRAAN"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index 3b06137..06a43f6 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"bilatu"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Ezin izan da hasi <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Gehiago"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"Beste <xliff:g id="NUMBER">%d</xliff:g>"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Bateria aurrezlea aktibatuta dago"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Errendimendua eta atzeko planoko datuak murrizten ditu"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desaktibatu bateria aurrezteko aukera"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Edukiak ezkutatuta daude"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aplikazioak pantailan bistaratzen den guztia grabatuko du."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ez erakutsi berriro"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Garbitu guztiak"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Blokeatuta"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Bateria (%% <xliff:g id="ID_1">%1$d</xliff:g>)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings_car.xml b/packages/SystemUI/res/values-eu-rES/strings_car.xml
new file mode 100644
index 0000000..c4371f7
--- /dev/null
+++ b/packages/SystemUI/res/values-eu-rES/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">"Gidatu zentzuz"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Egon erne errepidera begira eta gorde lege aplikagarri oro. Agian jarraibideak ez dira guztiz zehatzak, osatuak edo egokiak izango; arriskutsuak izan daitezke edo debekatuta dagoen zerbait egitea edo mugak zeharkatzea proposa diezazukete. Baliteke enpresei buruzko informazioa ere guztiz zehatza edo osatua ez izatea. Datuak ez dira une-unekoak eta ezin da bermatu kokapenaren zehaztasuna. Gidatu bitartean, ez erabili gailu mugikorrik edo Android Auto zerbitzuarekin erabiltzeko egina ez dagoen aplikaziorik."</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..be2053e
--- /dev/null
+++ b/packages/SystemUI/res/values-eu-rES/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"Itxi pantaila txikia"</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_cancel" msgid="5173898361050559462">"Utzi"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Eduki sakatuta hasierako botoia pantaila txikia kontrolatzeko"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index b8c4256..0af19ba 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"بیشتر"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> مورد دیگر"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"محتواها پنهان هستند"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"مسدود شده"</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_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_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="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="3476715163685592453">"باتری (<xliff:g id="ID_1">%1$d</xliff:g>٪٪)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings_car.xml b/packages/SystemUI/res/values-fa/strings_car.xml
new file mode 100644
index 0000000..e8433fa
--- /dev/null
+++ b/packages/SystemUI/res/values-fa/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-fa/strings_tv.xml b/packages/SystemUI/res/values-fa/strings_tv.xml
new file mode 100644
index 0000000..b7c4e61
--- /dev/null
+++ b/packages/SystemUI/res/values-fa/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"‏بستن 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_cancel" msgid="5173898361050559462">"لغو"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"‏نگه‌داشتن HOME برای کنترل PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index a32232f..327e1df 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"haku"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Sovelluksen <xliff:g id="APP">%s</xliff:g> käynnistäminen epäonnistui."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Lisää"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"+<xliff:g id="NUMBER">%d</xliff:g> lisää"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Virransäästö on käytössä"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Rajoittaa suorituskykyä ja taustatiedonsiirtoa"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Poista virransäästö käytöstä"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Sisältö piilotettu"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> alkaa tallentaa kaiken näytölläsi näkyvän."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Älä näytä uudelleen"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Poista kaikki"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Estetyt"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Akku (<xliff:g id="ID_1">%1$d</xliff:g> %%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings_car.xml b/packages/SystemUI/res/values-fi/strings_car.xml
new file mode 100644
index 0000000..fc94b90
--- /dev/null
+++ b/packages/SystemUI/res/values-fi/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">"Aja varovasti"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Tarkkaile huolellisesti ajo-olosuhteita ja noudata aina voimassa olevia lakeja. Reittiohjeet saattavat olla epätarkkoja, epätäydellisiä, vaarallisia, epäsopivia, kiellettyjä tai kulkea hallintoalueiden läpi. Myös yritystiedot voivat olla epätarkkoja tai epätäydellisiä. Tietoja ei päivitetä reaaliajassa eikä sijaintien tarkkuutta taata. Älä käytä ajon aikana mobiililaitettasi tai sovelluksia, joita ei ole suunniteltu Android Autolle."</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..d39c37f
--- /dev/null
+++ b/packages/SystemUI/res/values-fi/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Peruuta"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Hallinnoi PIP-tilaa painamalla Aloitusnäyttö-painiketta pitkään."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 5b55188..7ebb5ab 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Impossible de lancer <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Plus"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> autres"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"La fonction Économie d\'énergie est activée"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Réduire les performances et de fond"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Désactiver l\'économiseur d\'énergie"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Contenus masqués"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> commencer à enregistrer tout ce qui s\'affiche sur votre écran."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ne plus afficher"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Tout effacer"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Bloquée"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Pile (<xliff:g id="ID_1">%1$d</xliff:g> %%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings_car.xml b/packages/SystemUI/res/values-fr-rCA/strings_car.xml
new file mode 100644
index 0000000..209773b
--- /dev/null
+++ b/packages/SystemUI/res/values-fr-rCA/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">"Conduire en toute sécurité"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Tenez compte des conditions de la route et respectez toujours les lois en vigueur. Les itinéraires peuvent être incorrects, incomplets, dangereux, inappropriés ou interdits, et ils peuvent traverser des zones administratives. Les renseignements sur les entreprises peuvent également être incorrects ou incomplets. Les données ne sont pas fournies en temps réel, et la précision de la localisation n\'est pas garantie. Ne manipulez pas votre appareil mobile et n\'utilisez pas d\'applications non conçues pour Android Auto lorsque vous conduisez."</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..c06e492
--- /dev/null
+++ b/packages/SystemUI/res/values-fr-rCA/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"Fermer le mode PIP"</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_cancel" msgid="5173898361050559462">"Annuler"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Maintenez enfoncée la touche ACCUEIL gérer le mode PIP."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index dd2d5f4..d16f680 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Impossible de lancer <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Plus"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> autres"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"L\'économiseur de batterie est activé"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Limite les performances et les données en arrière-plan."</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Désactiver l\'économiseur de batterie"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Contenus masqués"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> va commencer à capturer tous les contenus affichés à l\'écran."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ne plus afficher"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Tout effacer"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Bloquées"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Batterie (<xliff:g id="ID_1">%1$d</xliff:g> %%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings_car.xml b/packages/SystemUI/res/values-fr/strings_car.xml
new file mode 100644
index 0000000..d42586e
--- /dev/null
+++ b/packages/SystemUI/res/values-fr/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">"Soyez prudent sur la route"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Tenez compte des conditions de conduite et respectez toujours les lois en vigueur. Les itinéraires peuvent être incorrects, incomplets, dangereux, inappropriés ou interdits, et traverser des frontières administratives. Les informations sur les établissements peuvent également être incorrectes ou incomplètes. Les données ne sont pas fournies en temps réel, et la précision de la localisation n\'est pas garantie. Ne manipulez pas votre appareil mobile et n\'utilisez pas d\'applications non conçues pour Android Auto lorsque vous conduisez."</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..bf7306e
--- /dev/null
+++ b/packages/SystemUI/res/values-fr/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"Fermer le 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_cancel" msgid="5173898361050559462">"Annuler"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Appuyez de manière prolongée sur \"ACCUEIL\" pour contrôler le mode PIP."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 22ac72e..fad6b43 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Non foi posible iniciar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Máis"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> máis"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"O aforro de batería está activado"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce o rendemento e os datos en segundo plano"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactivar o aforro de batería"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Contido oculto"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> comezará a capturar todo o que apareza na túa pantalla."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Non mostrar outra vez"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Eliminar todas"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Bloqueada"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Batería (<xliff:g id="ID_1">%1$d</xliff:g> %%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings_car.xml b/packages/SystemUI/res/values-gl-rES/strings_car.xml
new file mode 100644
index 0000000..bb3f8eb
--- /dev/null
+++ b/packages/SystemUI/res/values-gl-rES/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">"Conduce de forma segura"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Ten moi en conta as condicións de condución e respecta sempre as leis aplicables. É posible que as indicacións sexan imprecisas, incompletas, perigosas, inadecuadas, estean prohibidas ou que impliquen atravesar áreas administrativas. A información das empresas tamén pode ser imprecisa ou estar incompleta. Os datos non se proporcionan en tempo real e non se garante a precisión da localización. Non manipules o teu dispositivo móbil nin utilices aplicacións que non estean deseñadas para Android Auto mentres conduces."</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..857911d
--- /dev/null
+++ b/packages/SystemUI/res/values-gl-rES/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Cancelar"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Manter premido INICIO para controlar PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index d72529e..576c332 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -331,6 +331,8 @@
     <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>
@@ -364,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"સામગ્રીઓ છુપાવેલ છે"</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>
@@ -449,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"અવરોધિત"</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_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_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="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="3476715163685592453">"બૅટરી (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings_car.xml b/packages/SystemUI/res/values-gu-rIN/strings_car.xml
new file mode 100644
index 0000000..b22b688
--- /dev/null
+++ b/packages/SystemUI/res/values-gu-rIN/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-gu-rIN/strings_tv.xml b/packages/SystemUI/res/values-gu-rIN/strings_tv.xml
new file mode 100644
index 0000000..fbb9a4f
--- /dev/null
+++ b/packages/SystemUI/res/values-gu-rIN/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"રદ કરો"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIP નિયંત્રિત કરવા માટે હોમ પકડી રાખો"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 9a3ab2b..5d97aa6 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -331,6 +331,8 @@
     <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>
@@ -364,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"छिपी हुई सामग्री"</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>
@@ -449,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"अवरोधित"</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_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_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="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="3476715163685592453">"बैटरी (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings_car.xml b/packages/SystemUI/res/values-hi/strings_car.xml
new file mode 100644
index 0000000..a643bd8
--- /dev/null
+++ b/packages/SystemUI/res/values-hi/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-hi/strings_tv.xml b/packages/SystemUI/res/values-hi/strings_tv.xml
new file mode 100644
index 0000000..780725d
--- /dev/null
+++ b/packages/SystemUI/res/values-hi/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"अभी नहीं"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIP को नियंत्रित करने के लिए होम पर रुकें"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 1ed890c..d96c308 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -302,8 +302,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"pretraži"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikacija <xliff:g id="APP">%s</xliff:g> nije pokrenuta."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Više"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"Još <xliff:g id="NUMBER">%d</xliff:g>"</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>
@@ -333,6 +332,8 @@
     <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>
@@ -366,7 +367,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Štednja baterije je uključena"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Smanjuje količinu rada i pozadinske podatke"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Isključi uštedu baterije"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Sadržaj je skriven"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> počet će snimati sve što se prikazuje na zaslonu."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ne prikazuj ponovo"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Izbriši sve"</string>
@@ -451,4 +451,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Blokirano"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Baterija (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</string>
+    <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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings_car.xml b/packages/SystemUI/res/values-hr/strings_car.xml
new file mode 100644
index 0000000..034bd71d
--- /dev/null
+++ b/packages/SystemUI/res/values-hr/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">"Vozite sigurno"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Pažljivo pratite promet i uvijek se pridržavajte primjenjivih zakona. Upute mogu biti neprecizne, nepotpune, opasne, neprikladne, zabranjene ili mogu uključivati prelazak administrativnih granica. Podaci o tvrtkama također mogu biti neprecizni i nepotpuni. Podaci nisu u stvarnom vremenu i preciznost lokacije nije zajamčena. Tijekom vožnje ne rukujte mobilnim uređajem i ne upotrebljavajte aplikacije koje nisu namijenjene za Android Auto."</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..e87d880
--- /dev/null
+++ b/packages/SystemUI/res/values-hr/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Odustani"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Držite POČETNI ZASLON da biste kontrolirali PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 8978152..0f4c31b 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"Továbbiak"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> további"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Akkumulátorkímélő mód bekapcsolva"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Csökkenti a teljesítményt és a háttéradatok használatát"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Akkumulátorkímélő mód kikapcsolása"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Tartalom elrejtve"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"A(z) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> alkalmazás rögzíteni fog mindent, ami megjelenik a képernyőn."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ne jelenjen meg többé"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Az összes törlése"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Letiltva"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Akkumulátor (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</string>
+    <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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings_car.xml b/packages/SystemUI/res/values-hu/strings_car.xml
new file mode 100644
index 0000000..688d88b
--- /dev/null
+++ b/packages/SystemUI/res/values-hu/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">"Vezessen óvatosan"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Mindig legyen teljes mértékben tisztában a vezetési körülményekkel, és a vonatkozó törvényeket tartsa be! Az útvonaltervek pontatlanok, hiányosak, veszélyesek, nem megfelelők vagy tiltottak lehetnek, illetve a közforgalom számára nem használható utakat érinthetnek. Az üzleti információk is pontatlanok vagy hiányosak lehetnek. Az adatok nem valós idejűek, ezért nem garantálhatjuk a helyadatok pontosságát. Vezetés közben ne kezelje mobileszközét, illetve ne használjon olyan alkalmazásokat az Android Auto rendszerrel, amelyeket nem ahhoz terveztek."</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..73ba98d
--- /dev/null
+++ b/packages/SystemUI/res/values-hu/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"Kép a képben (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_cancel" msgid="5173898361050559462">"Mégse"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Tartsa nyomva a KEZDŐKÉPERNYŐ gombot a PIP funkció vezérléséhez"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index c201b09..d135933 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"Ավելին"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"ևս <xliff:g id="NUMBER">%d</xliff:g>"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"Բովանդակությունը թաքցված է"</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>
@@ -435,12 +435,12 @@
     <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_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="tuner_toast" msgid="603429811084428439">"Համակարգի ՕՄ-ի ընդունիչը ավելացվել է կարգավորումներին"</string>
     <string name="remove_from_settings" msgid="8389591916603406378">"Հեռացնել կարգավորումներից"</string>
-    <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Հեռացնե՞լ Համակարգի ՕՄ-ի կարգավորիչը կարգավորումներից և չօգտվել այլևս նրա գործառույթներից:"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Արգելափակված"</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_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_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="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="3476715163685592453">"Մարտկոց (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings_car.xml b/packages/SystemUI/res/values-hy-rAM/strings_car.xml
new file mode 100644
index 0000000..4f214f7
--- /dev/null
+++ b/packages/SystemUI/res/values-hy-rAM/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-hy-rAM/strings_tv.xml b/packages/SystemUI/res/values-hy-rAM/strings_tv.xml
new file mode 100644
index 0000000..8113f09
--- /dev/null
+++ b/packages/SystemUI/res/values-hy-rAM/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"Փակել 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_cancel" msgid="5173898361050559462">"Չեղարկել"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIP-ն կառավարելու համար սեղմած պահեք HOME կոճակը"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index ce44227..6335c5d 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -331,6 +331,8 @@
     <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>
@@ -364,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Penghemat baterai aktif"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Mengurangi kinerja dan data latar belakang"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Nonaktifkan penghemat baterai"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Konten tersembunyi"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> akan mulai menangkap apa saja yang ditampilkan pada layar Anda."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Jangan tampilkan lagi"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Hapus semua"</string>
@@ -449,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Diblokir"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Baterai (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings_car.xml b/packages/SystemUI/res/values-in/strings_car.xml
new file mode 100644
index 0000000..cc23ecf
--- /dev/null
+++ b/packages/SystemUI/res/values-in/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">"Hati-hati saat berkendara"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Tetap perhatikan keadaan saat mengemudi dan selalu patuhi peraturan yang berlaku. Petunjuk arah mungkin tidak akurat, tidak lengkap, berbahaya, tidak cocok, terlarang, atau dapat melewati wilayah administratif. Informasi bisnis juga mungkin tidak akurat atau tidak lengkap. Data tidak dalam waktu nyata dan keakuratan lokasi tidak dijamin. Jangan menggunakan perangkat seluler atau aplikasi yang tidak berkaitan dengan Android Auto saat mengemudi."</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..b889231
--- /dev/null
+++ b/packages/SystemUI/res/values-in/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Batal"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Tahan LAYAR UTAMA untuk mengontrol PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index cb35e83..76f5389 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"leita"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Ekki var hægt að ræsa <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Meira"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> í viðbót"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Kveikt er á rafhlöðusparnaði"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Dregur úr afköstum og bakgrunnsgögnum"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Slökkva á rafhlöðusparnaði"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Innihald falið"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> mun fanga allt sem birtist á skjánum."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ekki sýna þetta aftur"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Hreinsa allt"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Útilokuð"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Rafhlaða (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings_car.xml b/packages/SystemUI/res/values-is-rIS/strings_car.xml
new file mode 100644
index 0000000..65117be
--- /dev/null
+++ b/packages/SystemUI/res/values-is-rIS/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">"Aktu varlega"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Vertu vakandi fyrir akstursskilyrðum hverju sinni og farðu ævinlega eftir gildandi lögum. Leiðarlýsing kann að vera ónákvæm, ófullkomin, ekki við hæfi, bönnuð eða fela í sér ferðir um opinber svæði. Upplýsingar um fyrirtæki kunna einnig að vera ónákvæmar eða ófullkomnar. Gögn eru ekki í rauntíma og ekki er hægt að tryggja nákvæmni staðsetningarupplýsinga. Ekki handleika fartækið þitt meðan á akstri stendur eða nota forrit sem ekki eru hugsuð fyrir Android Auto."</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..d91605e
--- /dev/null
+++ b/packages/SystemUI/res/values-is-rIS/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"Loka PIP"</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_cancel" msgid="5173898361050559462">"Hætta við"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Haltu HOME-lyklinum niðri til að stjórna PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 147752d..cfcd42c 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Impossibile avviare <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Altro"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"Altre attività: <xliff:g id="NUMBER">%d</xliff:g>"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Risparmio energetico attivo"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Riduce le prestazioni e i dati in background"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Disattiva risparmio energetico"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Contenuti nascosti"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> inizierà ad acquisire tutto ciò che è visualizzato sul tuo schermo."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Non mostrare più"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Cancella tutto"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Bloccata"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Batteria (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings_car.xml b/packages/SystemUI/res/values-it/strings_car.xml
new file mode 100644
index 0000000..ae26c9e
--- /dev/null
+++ b/packages/SystemUI/res/values-it/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">"Guida in modo sicuro"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"È necessario essere sempre pienamente coscienti delle condizioni di guida e rispettare le leggi vigenti. Le indicazioni stradali potrebbero essere imprecise, incomplete, pericolose, non adatte, vietate o implicare l\'attraversamento di confini. Anche le informazioni sulle attività commerciali potrebbero essere imprecise o incomplete. I dati non vengono forniti in tempo reale e non è possibile garantire la precisione della geolocalizzazione. Non maneggiare il dispositivo mobile e non utilizzare app non progettate per Android Auto durante la guida."</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..0279e45
--- /dev/null
+++ b/packages/SystemUI/res/values-it/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"Chiudi visualizzazione 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_cancel" msgid="5173898361050559462">"Annulla"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Tieni premuto HOME per controllare la visualizzazione PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 70bea55..6fd3456 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -303,8 +303,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"עוד"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> נוספות"</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,6 +333,8 @@
     <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>
@@ -367,7 +368,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"התוכן מוסתר"</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>
@@ -452,4 +452,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"חסום"</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_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_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="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="3476715163685592453">"סוללה (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings_car.xml b/packages/SystemUI/res/values-iw/strings_car.xml
new file mode 100644
index 0000000..8d62258
--- /dev/null
+++ b/packages/SystemUI/res/values-iw/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-iw/strings_tv.xml b/packages/SystemUI/res/values-iw/strings_tv.xml
new file mode 100644
index 0000000..a1bebb9
--- /dev/null
+++ b/packages/SystemUI/res/values-iw/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"‏סגור 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_cancel" msgid="5173898361050559462">"ביטול"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"‏המשך ללחוץ על HOME כדי לשלוט ב-PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index d91c3b5..189fcd9 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"もっと見る"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"他 <xliff:g id="NUMBER">%d</xliff:g> 件"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"バッテリーセーバーがON"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"パフォーマンスとバックグラウンドデータを制限します"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"バッテリーセーバーをOFFにします"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"コンテンツが非表示"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"ブロック中"</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_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_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="color_apply" msgid="9212602012641034283">"適用"</string>
+    <string name="color_revert_title" msgid="4746666545480534663">"設定の確認"</string>
+    <string name="color_revert_message" msgid="9116001069397996691">"一部の色設定を適用すると、この端末を使用できなくなることがあります。この色設定を確認するには、[OK] をクリックしてください。確認しない場合、10 秒後に設定はリセットされます。"</string>
+    <string name="battery_panel_title" msgid="3476715163685592453">"バッテリー(<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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 />
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings_car.xml b/packages/SystemUI/res/values-ja/strings_car.xml
new file mode 100644
index 0000000..667de81
--- /dev/null
+++ b/packages/SystemUI/res/values-ja/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-ja/strings_tv.xml b/packages/SystemUI/res/values-ja/strings_tv.xml
new file mode 100644
index 0000000..08a5a1c
--- /dev/null
+++ b/packages/SystemUI/res/values-ja/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"キャンセル"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"[ホーム] を押し続けると PIP を制御できます"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 51405cb..07390f5 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"მეტი"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"კიდევ <xliff:g id="NUMBER">%d</xliff:g>"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"შიგთავსი დამალულია"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"დაბლოკილი"</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_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_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="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="3476715163685592453">"ბატარეა (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings_car.xml b/packages/SystemUI/res/values-ka-rGE/strings_car.xml
new file mode 100644
index 0000000..c8e17dd
--- /dev/null
+++ b/packages/SystemUI/res/values-ka-rGE/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-ka-rGE/strings_tv.xml b/packages/SystemUI/res/values-ka-rGE/strings_tv.xml
new file mode 100644
index 0000000..83db37b
--- /dev/null
+++ b/packages/SystemUI/res/values-ka-rGE/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"გაუქმება"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIP-ის სამართავად, ხანგრძლივად დააჭირეთ მთავარ ღილაკს"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index cde4dd8..02e773c 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"Қосымша"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> Қосымша"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"Мазмұн жасырылған"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Бөгелген"</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_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_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="color_apply" msgid="9212602012641034283">"Қолдану"</string>
+    <string name="color_revert_title" msgid="4746666545480534663">"Параметрлерді растау"</string>
+    <string name="color_revert_message" msgid="9116001069397996691">"Кейбір түс параметрлері бұл құрылғыны пайдалану мүмкін емес етуі мүмкін. Бұл түс параметрлерін растау үшін OK түймесін басыңыз, әйтпесе параметрлер 10 секундтан кейін ысырылады."</string>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Батарея (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings_car.xml b/packages/SystemUI/res/values-kk-rKZ/strings_car.xml
new file mode 100644
index 0000000..056b75c
--- /dev/null
+++ b/packages/SystemUI/res/values-kk-rKZ/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-kk-rKZ/strings_tv.xml b/packages/SystemUI/res/values-kk-rKZ/strings_tv.xml
new file mode 100644
index 0000000..6339f42
--- /dev/null
+++ b/packages/SystemUI/res/values-kk-rKZ/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Бас тарту"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIP басқару үшін «Негізгі бет» түймесін ұстап тұрыңыз"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index c5e0f85..513a5b8 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"ច្រើនទៀត"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> ទៀត"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"បាន​លាក់​មាតិកា"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"បានរារាំង"</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_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_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="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="3476715163685592453">"ថ្ម (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings_car.xml b/packages/SystemUI/res/values-km-rKH/strings_car.xml
new file mode 100644
index 0000000..9648a5fb
--- /dev/null
+++ b/packages/SystemUI/res/values-km-rKH/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-km-rKH/strings_tv.xml b/packages/SystemUI/res/values-km-rKH/strings_tv.xml
new file mode 100644
index 0000000..6e6172c
--- /dev/null
+++ b/packages/SystemUI/res/values-km-rKH/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"បិទ 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_cancel" msgid="5173898361050559462">"បោះបង់"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"សង្កត់ប៊ូតុងដើម ដើម្បីគ្រប់គ្រង PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index 6e76b61..a64fe5a 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"ಇನ್ನಷ್ಟು"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> ಇನ್ನಷ್ಟು"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"ವಿಷಯಗಳನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</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_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_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="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="3476715163685592453">"ಬ್ಯಾಟರಿ (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings_car.xml b/packages/SystemUI/res/values-kn-rIN/strings_car.xml
new file mode 100644
index 0000000..e8e99c4
--- /dev/null
+++ b/packages/SystemUI/res/values-kn-rIN/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-kn-rIN/strings_tv.xml b/packages/SystemUI/res/values-kn-rIN/strings_tv.xml
new file mode 100644
index 0000000..c2a7095
--- /dev/null
+++ b/packages/SystemUI/res/values-kn-rIN/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"ರದ್ದುಮಾಡು"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIP ನಿಯಂತ್ರಿಸಲು HOME ಹೋಲ್ಡ್‌ ಮಾಡಿ"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 04fba52..30a9422 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"더보기"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g>개 더보기"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"숨겨진 콘텐츠"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"차단됨"</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_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_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="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="3476715163685592453">"배터리(<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings_car.xml b/packages/SystemUI/res/values-ko/strings_car.xml
new file mode 100644
index 0000000..e18e587
--- /dev/null
+++ b/packages/SystemUI/res/values-ko/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-ko/strings_tv.xml b/packages/SystemUI/res/values-ko/strings_tv.xml
new file mode 100644
index 0000000..158f4ad
--- /dev/null
+++ b/packages/SystemUI/res/values-ko/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"취소"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIP를 제어하려면 홈을 누르세요."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 254843c..873cf37 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"Дагы"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"Дагы <xliff:g id="NUMBER">%d</xliff:g>"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"Мазмундар жашырылган"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Бөгөттөлгөн"</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_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_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="color_apply" msgid="9212602012641034283">"Колдонуу"</string>
+    <string name="color_revert_title" msgid="4746666545480534663">"Жөндөөлөрдү ырастоо"</string>
+    <string name="color_revert_message" msgid="9116001069397996691">"Айрым түс жөндөөлөрү бул түзмөктү колдонулгус кылып коюшу мүмкүн. Бул түс жөндөөлөрүн ырастоо үчүн OK баскычын чыкылдатыңыз, болбосо бул жөндөөлөр 10 секунддан кийин баштапкы абалына келтирилет."</string>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Батарея (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings_car.xml b/packages/SystemUI/res/values-ky-rKG/strings_car.xml
new file mode 100644
index 0000000..1d99ff2
--- /dev/null
+++ b/packages/SystemUI/res/values-ky-rKG/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-ky-rKG/strings_tv.xml b/packages/SystemUI/res/values-ky-rKG/strings_tv.xml
new file mode 100644
index 0000000..c54d0d2
--- /dev/null
+++ b/packages/SystemUI/res/values-ky-rKG/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Жокко чыгаруу"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIP көзөмөлдөө үчүн БАШКЫ БЕТ баскычын кармап туруңуз"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
index 43e7bac..e0affa1 100644
--- a/packages/SystemUI/res/values-land/config.xml
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -38,4 +38,6 @@
          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>
+
+    <integer name="quick_settings_num_columns">4</integer>
 </resources>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 456391d..c75a89f 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -24,5 +24,5 @@
     <integer name="notification_panel_layout_gravity">@integer/standard_notification_panel_layout_gravity</integer>
 
     <dimen name="docked_divider_handle_width">2dp</dimen>
-    <dimen name="docked_divider_handle_height">24dp</dimen>
+    <dimen name="docked_divider_handle_height">16dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-land/styles.xml b/packages/SystemUI/res/values-land/styles.xml
index 96d8fb8..b711faa 100644
--- a/packages/SystemUI/res/values-land/styles.xml
+++ b/packages/SystemUI/res/values-land/styles.xml
@@ -20,7 +20,7 @@
     </style>
 
     <style name="DockedDividerBackground">
-        <item name="android:layout_width">12dp</item>
+        <item name="android:layout_width">10dp</item>
         <item name="android:layout_height">match_parent</item>
         <item name="android:layout_gravity">center_horizontal</item>
     </style>
@@ -28,7 +28,7 @@
     <style name="DockedDividerHandle">
         <item name="android:layout_gravity">center_vertical</item>
         <item name="android:layout_width">48dp</item>
-        <item name="android:layout_height">64dp</item>
+        <item name="android:layout_height">96dp</item>
     </style>
 
 </resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 91aee1c..7a85446 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"ເພີ່ມເຕີມ"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> ເພີ່ມເຕີມ"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"ເນື້ອຫາ​ຖືກ​ເຊື່ອງ​ໄວ້"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"ບລັອກໄວ້​ແລ້ວ"</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_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_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="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="3476715163685592453">"ແບັດເຕີຣີ (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings_car.xml b/packages/SystemUI/res/values-lo-rLA/strings_car.xml
new file mode 100644
index 0000000..3388f54
--- /dev/null
+++ b/packages/SystemUI/res/values-lo-rLA/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-lo-rLA/strings_tv.xml b/packages/SystemUI/res/values-lo-rLA/strings_tv.xml
new file mode 100644
index 0000000..289d4e2
--- /dev/null
+++ b/packages/SystemUI/res/values-lo-rLA/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"ປິດ 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_cancel" msgid="5173898361050559462">"ຍົກເລີກ"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"ກົດຄ້າງປຸ່ມ HOME ເພື່ອຄວບຄຸມ PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 488405f..c9a5959 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -303,8 +303,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"paieška"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Nepavyko paleisti <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Daugiau"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"Dar <xliff:g id="NUMBER">%d</xliff:g>"</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>
@@ -334,6 +333,8 @@
     <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>
@@ -367,7 +368,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Akumuliatoriaus tausojimo priemonė įjungta"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Sumažinamas našumas ir foninių duomenų naudojimas"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Išjungti Akumuliatoriaus tausojimo priemonę"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Turinys paslėptas"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"„<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>“ pradės fiksuoti viską, kas rodoma jūsų ekrane."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Daugiau neberodyti"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Viską išvalyti"</string>
@@ -452,4 +452,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Užblokuota"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Akumuliatorius (<xliff:g id="ID_1">%1$d</xliff:g> %%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings_car.xml b/packages/SystemUI/res/values-lt/strings_car.xml
new file mode 100644
index 0000000..03d656a
--- /dev/null
+++ b/packages/SystemUI/res/values-lt/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">"Vairuokite saugiai"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Visada atsižvelkite į vairavimo sąlygas ir laikykitės galiojančių įstatymų. Nuorodos gali būti netikslios, neužbaigtos, pavojingos, netinkamos, draudžiamos ar nukreipiančios per administracines sritis. Įmonių informacija taip pat gali būti netiksli ar neužbaigta. Duomenys nėra teikiami realiuoju laiku ir vietovių tikslumo negalima garantuoti. Vairuodami nenaudokite mobiliojo įrenginio ar programų, kurios nėra skirtos „Android Auto“."</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..b9719c4
--- /dev/null
+++ b/packages/SystemUI/res/values-lt/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Atšaukti"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Jei norite valdyti PIP, palaikykite paspaudę mygtuką HOME"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index da976e8..5e115a8 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -302,8 +302,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"Meklēt"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Nevarēja palaist lietotni <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Vairāk"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"Vēl <xliff:g id="NUMBER">%d</xliff:g>"</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>
@@ -333,6 +332,8 @@
     <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>
@@ -366,7 +367,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Ieslēgts akumulatora enerģijas taupīšanas režīms"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Samazina veiktspēju un fona datus"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Izslēgt akumulatora jaudas taupīšanu"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Saturs paslēpts"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sāks uzņemt visu, kas tiks rādīts jūsu ekrānā."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Vairs nerādīt"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Dzēst visu"</string>
@@ -451,4 +451,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Bloķēts"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Akumulators (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings_car.xml b/packages/SystemUI/res/values-lv/strings_car.xml
new file mode 100644
index 0000000..0171624
--- /dev/null
+++ b/packages/SystemUI/res/values-lv/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">"Droša braukšana"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Pievērsiet visu uzmanību braukšanas apstākļiem un vienmēr ievērojiet piemērojamos tiesību aktus. Norādes var būt neprecīzas, nepilnīgas, bīstamas, nepiemērotas, aizliegtas vai var ietvert administratīvo teritoriju šķērsošanu. Arī uzņēmumu informācija var būt neprecīza vai nepilnīga. Dati netiek nodrošināti reāllaikā, un netiek garantēta atrašanās vietu precizitāte. Vadot transportlīdzekli, nelietojiet mobilo ierīci rokās un neizmantojiet lietotnes, kas nav paredzētas pakalpojumam Android Auto."</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..1c42520
--- /dev/null
+++ b/packages/SystemUI/res/values-lv/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"Aizvērt attēlu attēlā"</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_cancel" msgid="5173898361050559462">"Atcelt"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Turiet nospiestu taustiņu HOME, lai kontrolētu attēlu attēlā"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 191dd78..348d679 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -42,7 +42,7 @@
     <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_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>
@@ -151,7 +151,7 @@
     <string name="accessibility_no_sims" msgid="3957997018324995781">"Нема СИМ-картичка"</string>
     <string name="accessibility_carrier_network_change_mode" msgid="4017301580441304305">"Променување на мрежата на операторот."</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Батерија <xliff:g id="NUMBER">%d</xliff:g> проценти."</string>
-    <string name="accessibility_settings_button" msgid="799583911231893380">"Подесувања на систем."</string>
+    <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">"ГПС е овозможен."</string>
@@ -260,7 +260,7 @@
     <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_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>
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"Повеќе"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"Уште <xliff:g id="NUMBER">%d</xliff:g>"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"Содржините се скриени"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Блокирано"</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_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_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="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="3476715163685592453">"Батерија (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings_car.xml b/packages/SystemUI/res/values-mk-rMK/strings_car.xml
new file mode 100644
index 0000000..f5ed824
--- /dev/null
+++ b/packages/SystemUI/res/values-mk-rMK/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-mk-rMK/strings_tv.xml b/packages/SystemUI/res/values-mk-rMK/strings_tv.xml
new file mode 100644
index 0000000..ce7a13a
--- /dev/null
+++ b/packages/SystemUI/res/values-mk-rMK/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"Затвори ја слика во слика"</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_cancel" msgid="5173898361050559462">"Откажи"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Задржете ја Почетна страница за да ја контролирате Слика во слика"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index c57b9ff7..a393e42 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"കൂടുതൽ"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> എണ്ണം കൂടി"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"കോൺടാക്‌റ്റുകൾ മറച്ചു"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"ബ്ലോക്കുചെയ്തു"</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_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_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="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="3476715163685592453">"ബാറ്ററി (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings_car.xml b/packages/SystemUI/res/values-ml-rIN/strings_car.xml
new file mode 100644
index 0000000..b53029c
--- /dev/null
+++ b/packages/SystemUI/res/values-ml-rIN/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-ml-rIN/strings_tv.xml b/packages/SystemUI/res/values-ml-rIN/strings_tv.xml
new file mode 100644
index 0000000..4bb15fb
--- /dev/null
+++ b/packages/SystemUI/res/values-ml-rIN/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"റദ്ദാക്കുക"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIP നിയന്ത്രിക്കാൻ ഹോം പിടിക്കുക"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 5797dc7..9b45994 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -299,8 +299,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"Илүү"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> Илүү"</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>
@@ -330,6 +329,8 @@
     <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>
@@ -363,7 +364,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"Контентыг нуусан"</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,4 +448,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Блоклосон"</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_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_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="color_apply" msgid="9212602012641034283">"Хэрэгжүүлэх"</string>
+    <string name="color_revert_title" msgid="4746666545480534663">"Тохиргоог баталгаажуулах"</string>
+    <string name="color_revert_message" msgid="9116001069397996691">"Зарим өнгөний тохиргоо энэ төхөөрөмжийг ашиглах боломжгүй болгож болзошгүй. OK товчлуурыг дарж эдгээр өнгөний тохиргоог зөвшөөрөхгүй бол энэ тохиргоо нь 10 секундын дараа шинэчлэгдэх болно."</string>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Тэжээл (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings_car.xml b/packages/SystemUI/res/values-mn-rMN/strings_car.xml
new file mode 100644
index 0000000..d48580f
--- /dev/null
+++ b/packages/SystemUI/res/values-mn-rMN/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 Автод зориулаагүй апп-г бүү ашиглаарай."</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..04df731
--- /dev/null
+++ b/packages/SystemUI/res/values-mn-rMN/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Цуцлах"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIP-г удирдахын тулд HOME-г дарна уу"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 2d460d9..9329909 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"अधिक"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"आणखी <xliff:g id="NUMBER">%d</xliff:g>"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"लपविलेली सामग्री"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"अवरोधित केले"</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_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_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="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="3476715163685592453">"बॅटरी (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings_car.xml b/packages/SystemUI/res/values-mr-rIN/strings_car.xml
new file mode 100644
index 0000000..7dc5d17
--- /dev/null
+++ b/packages/SystemUI/res/values-mr-rIN/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-mr-rIN/strings_tv.xml b/packages/SystemUI/res/values-mr-rIN/strings_tv.xml
new file mode 100644
index 0000000..021f34c
--- /dev/null
+++ b/packages/SystemUI/res/values-mr-rIN/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"रद्द करा"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIP नियंत्रित करण्‍यासाठी मुख्‍यपृष्‍ठ धरून ठेवा"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 3fc1d05..a4e90c0 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"cari"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Tidak dapat memulakan <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Lagi"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> Lagi"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Penjimat bateri dihidupkan"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Mengurangkan prestasi dan data latar belakang"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Matikan penjimat bateri"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Kandungan tersembunyi"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> akan mula mengabadikan semua yang dipaparkan pada skrin anda.."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Jangan tunjukkan lagi"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Kosongkan semua"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Disekat"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Bateri (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings_car.xml b/packages/SystemUI/res/values-ms-rMY/strings_car.xml
new file mode 100644
index 0000000..392530a
--- /dev/null
+++ b/packages/SystemUI/res/values-ms-rMY/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">"Pandu dengan selamat"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Pastikan anda sentiasa sedar sepenuhnya akan keadaan pemanduan dan mematuhi undang-undang yang dikenakan pada sepanjang masa. Arah mungkin tidak tepat, tidak lengkap, berbahaya, tidak sesuai, dilarang atau melibatkan lintasan kawasan pentadbiran. Maklumat perniagaan juga mungkin tidak tepat atau tidak lengkap. Data bukan masa sebenar dan ketepatan lokasi tidak dapat dijamin. Jangan kendalikan peranti mudah alih anda atau gunakan apl yang bukan untuk Android Auto semasa memandu."</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..850910b
--- /dev/null
+++ b/packages/SystemUI/res/values-ms-rMY/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Batal"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Tahan kekunci HOME untuk mengawal PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 69dcc77..cfcc15ab 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"နောက်ထပ်"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"နောက်ထပ် <xliff:g id="NUMBER">%d</xliff:g> ခု"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"အကြောင်းအရာများ ဝှက်ထား"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"ပိတ်ဆို့ထားသည်"</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_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_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="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="3476715163685592453">"ဘက်ထရီ ( <xliff:g id="ID_1">%1$d</xliff:g> %%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings_car.xml b/packages/SystemUI/res/values-my-rMM/strings_car.xml
new file mode 100644
index 0000000..dd41713
--- /dev/null
+++ b/packages/SystemUI/res/values-my-rMM/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-my-rMM/strings_tv.xml b/packages/SystemUI/res/values-my-rMM/strings_tv.xml
new file mode 100644
index 0000000..98d05a9
--- /dev/null
+++ b/packages/SystemUI/res/values-my-rMM/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"ဖျက်သိမ်းပါ"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIP ကို ​​ထိန်းချုပ်ရန် HOME ကို ကိုင်ထားပါ"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 94653cf..377642b 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"Søk"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Kunne ikke starte <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Mer"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> til"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Batterisparing er på"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduserer ytelsen og begrenser bakgrunnsdataene"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Slå av batterisparing"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Innholdet er skjult"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tar opp alt som vies på skjermen din."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ikke vis igjen"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Fjern alt"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Blokkert"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Batteri (<xliff:g id="ID_1">%1$d</xliff:g> %%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings_car.xml b/packages/SystemUI/res/values-nb/strings_car.xml
new file mode 100644
index 0000000..421420e
--- /dev/null
+++ b/packages/SystemUI/res/values-nb/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">"Kjør forsiktig"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Ha full oversikt over kjøreforhold, og følg alltid gjeldende lov og rett. Veibeskrivelser kan være unøyaktige, ufullstendige, farlige, upassende, forbudte eller de kan involvere kjøring på administrative områder. Bedriftsinformasjon kan også være unøyaktig eller ufullstendig. Data er ikke i sanntid, og posisjonsnøyaktighet kan ikke garanteres. Ikke bruk mobilenheten din eller apper som ikke er ment for Android Auto, mens du kjører."</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..ba191a4
--- /dev/null
+++ b/packages/SystemUI/res/values-nb/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Avbryt"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Hold inne STARTSIDEN for å kontrollere PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index bc4f1a9..2a15c87 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -331,6 +331,8 @@
     <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>
@@ -364,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"लुकेका सामाग्रीहरू"</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>
@@ -449,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"रोकियो"</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_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_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="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="3476715163685592453">"ब्याट्री (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings_car.xml b/packages/SystemUI/res/values-ne-rNP/strings_car.xml
new file mode 100644
index 0000000..1a4f8ef9
--- /dev/null
+++ b/packages/SystemUI/res/values-ne-rNP/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 स्वतःको लागि लक्षित नगरिएका अनुप्रयोगहरूको प्रयोग गर्ने नगर्नुहोस्।"</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..09cc01d
--- /dev/null
+++ b/packages/SystemUI/res/values-ne-rNP/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"रद्द गर्नुहोस्"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIP नियन्त्रण गर्न HOME थिचिरहनुहोस्"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 62cef0f..3e91b5c 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"Meer"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"Nog <xliff:g id="NUMBER">%d</xliff:g> andere"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Accubesparing is ingeschakeld"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Vermindert de prestaties en achtergrondgegevens"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Accubesparing uitschakelen"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Inhoud verborgen"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> gaat alles vastleggen dat wordt weergegeven op je scherm."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Niet opnieuw weergeven"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Alles wissen"</string>
@@ -407,7 +407,7 @@
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Verbergen"</string>
     <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> wil het volumedialoogvenster zijn."</string>
     <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Toestaan"</string>
-    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Afwijzen"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Weigeren"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> is het volumedialoogvenster"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Tik hierop om het origineel te herstellen."</string>
     <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Geblokkeerd"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Accu (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</string>
+    <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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings_car.xml b/packages/SystemUI/res/values-nl/strings_car.xml
new file mode 100644
index 0000000..be66e01
--- /dev/null
+++ b/packages/SystemUI/res/values-nl/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">"Rijd veilig"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Blijf je volledig bewust van de rijomstandigheden en houd je altijd aan de wet. Aanwijzingen kunnen onnauwkeurig, onvolledig, gevaarlijk, ongeschikt of verboden zijn of het doorkruisen van overheidszones vereisen. Bedrijfsinformatie kan ook onnauwkeurg of onvolledig zijn. De gegevens worden niet in realtime verstrekt en de nauwkeurigheid van een locatie kan niet worden gegarandeerd. Bedien tijdens het rijden je mobiele apparaat niet en gebruik geen apps die niet bedoeld zijn voor Android Auto."</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..59c711d
--- /dev/null
+++ b/packages/SystemUI/res/values-nl/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Annuleren"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Houd HOME ingedrukt om PIP te bedienen"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index d7fe0a1..1c98369 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"ਹੋਰ"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> ਹੋਰ"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"ਸਮੱਗਰੀਆਂ ਲੁਕਾਈਆਂ ਗਈਆਂ"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"ਬਲੌਕ ਕੀਤਾ"</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_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_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="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="3476715163685592453">"ਬੈਟਰੀ (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings_car.xml b/packages/SystemUI/res/values-pa-rIN/strings_car.xml
new file mode 100644
index 0000000..ac38625d
--- /dev/null
+++ b/packages/SystemUI/res/values-pa-rIN/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-pa-rIN/strings_tv.xml b/packages/SystemUI/res/values-pa-rIN/strings_tv.xml
new file mode 100644
index 0000000..26cc94a
--- /dev/null
+++ b/packages/SystemUI/res/values-pa-rIN/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"ਰੱਦ ਕਰੋ"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIP ਨੂੰ ਕੰਟਰੋਲ ਕਰਨ ਲਈ ਹੋਮ ਨੂੰ ਹੋਲਡ ਕਰੋ"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 360e15d..fde806b 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -303,8 +303,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"szukaj"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Nie udało się uruchomić aplikacji <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Więcej"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"i jeszcze <xliff:g id="NUMBER">%d</xliff:g>"</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>
@@ -334,6 +333,8 @@
     <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>
@@ -367,7 +368,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Oszczędzanie baterii jest włączone"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Zmniejsza wydajność i ogranicza dane w tle"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Wyłącz oszczędzanie baterii"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Treści ukryte"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> będzie zapisywać wszystko, co wyświetli się na ekranie."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Nie pokazuj ponownie"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Usuń wszystkie"</string>
@@ -452,4 +452,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Zablokowane"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Bateria (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings_car.xml b/packages/SystemUI/res/values-pl/strings_car.xml
new file mode 100644
index 0000000..d6e02d6
--- /dev/null
+++ b/packages/SystemUI/res/values-pl/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">"Jedź bezpiecznie"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Uważnie obserwuj warunki na drodze i zawsze przestrzegaj obowiązującego prawa. Wskazówki mogą być niedokładne, niekompletne, niebezpieczne, nieprzydatne lub niezgodne z prawem, mogą też obejmować przekraczanie obszarów administracyjnych. Informacje o firmach również mogą być niedokładne lub niekompletne. Dane nie są podawane w czasie rzeczywistym. Nie ma gwarancji, że dane o lokalizacji są dokładne. Podczas prowadzenia samochodu nie obsługuj urządzenia mobilnego ani nie używaj aplikacji nieprzeznaczonych na Android Auto."</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..270ef86
--- /dev/null
+++ b/packages/SystemUI/res/values-pl/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Anuluj"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Przytrzymaj przycisk STRONA GŁÓWNA, by sterować PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 1a3212e..38a6b79 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Não foi possível iniciar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Mais"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"Mais <xliff:g id="NUMBER">%d</xliff:g>"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"A Economia de bateria está ativada"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduz o desempenho e os dados em segundo plano"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desativar a economia de bateria"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Conteúdo oculto"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> começará a capturar tudo o que for exibido na tela."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Não mostrar novamente"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Limpar tudo"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Bloqueadas"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Bateria (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings_car.xml b/packages/SystemUI/res/values-pt-rBR/strings_car.xml
new file mode 100644
index 0000000..072f614
--- /dev/null
+++ b/packages/SystemUI/res/values-pt-rBR/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">"Dirija com segurança"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Mantenha-se atento às condições de direção e sempre obedeça às leis aplicáveis. As instruções podem ser imprecisas, incompletas, perigosas, inadequadas, proibidas ou envolver o cruzamento de áreas administrativas. As informações comerciais também podem ser imprecisas ou incompletas. Os dados não são exibidos em tempo real, e a precisão da localização não pode ser garantida. Enquanto dirige, não manuseie seu dispositivo móvel nem use apps que não tenham sido criados para o Android Auto."</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..131507c
--- /dev/null
+++ b/packages/SystemUI/res/values-pt-rBR/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Cancelar"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Mantenha \"PÁGINA INICIAL\" pressionado para controlar o PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index c95242f..7e66dcf 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"Mais"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"Mais <xliff:g id="NUMBER">%d</xliff:g>"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"A poupança de bateria está ligada"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduz o desempenho e os dados de segundo plano"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desativar a poupança de bateria"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Conteúdo oculto"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"O(a) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vai começar a captar tudo o que é apresentado no ecrã."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Não mostrar de novo"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Limpar tudo"</string>
@@ -427,7 +427,7 @@
     <string name="status_bar_airplane" msgid="7057575501472249002">"Modo de avião"</string>
     <string name="add_tile" msgid="2995389510240786221">"Adicionar mosaico"</string>
     <string name="broadcast_tile" msgid="3894036511763289383">"Mosaico de transmissão"</string>
-    <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"Só vai ouvir o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g> se desativar esta funcionalidade antes dessa hora"</string>
+    <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"Só vai ouvir o próximo alarme (<xliff:g id="WHEN">%1$s</xliff:g>) se desativar esta funcionalidade antes dessa hora"</string>
     <string name="zen_alarm_warning" msgid="444533119582244293">"Não vai ouvir o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="alarm_template" msgid="3980063409350522735">"às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="alarm_template_far" msgid="4242179982586714810">"em <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Bloqueado"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Bateria (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</string>
+    <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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings_car.xml b/packages/SystemUI/res/values-pt-rPT/strings_car.xml
new file mode 100644
index 0000000..e53774b7
--- /dev/null
+++ b/packages/SystemUI/res/values-pt-rPT/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">"Conduza com segurança"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Mantenha-se completamente atento às condições de condução e respeite sempre as leis aplicáveis. As direções podem ser imprecisas, incompletas, perigosas, inadequadas, proibidas ou envolver a travessia de zonas administrativas. Os dados das empresas também podem ser imprecisos ou incompletos. Os dados não são fornecidos em tempo real e não é possível garantir a precisão da localização. Não manuseie o dispositivo móvel nem utilize aplicações não destinadas ao Android Auto durante a condução."</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..e0ca35d
--- /dev/null
+++ b/packages/SystemUI/res/values-pt-rPT/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Cancelar"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Prima sem soltar a tecla HOME para controlar o PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 1a3212e..38a6b79 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Não foi possível iniciar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Mais"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"Mais <xliff:g id="NUMBER">%d</xliff:g>"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"A Economia de bateria está ativada"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduz o desempenho e os dados em segundo plano"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desativar a economia de bateria"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Conteúdo oculto"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> começará a capturar tudo o que for exibido na tela."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Não mostrar novamente"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Limpar tudo"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Bloqueadas"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Bateria (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings_car.xml b/packages/SystemUI/res/values-pt/strings_car.xml
new file mode 100644
index 0000000..072f614
--- /dev/null
+++ b/packages/SystemUI/res/values-pt/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">"Dirija com segurança"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Mantenha-se atento às condições de direção e sempre obedeça às leis aplicáveis. As instruções podem ser imprecisas, incompletas, perigosas, inadequadas, proibidas ou envolver o cruzamento de áreas administrativas. As informações comerciais também podem ser imprecisas ou incompletas. Os dados não são exibidos em tempo real, e a precisão da localização não pode ser garantida. Enquanto dirige, não manuseie seu dispositivo móvel nem use apps que não tenham sido criados para o Android Auto."</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..131507c
--- /dev/null
+++ b/packages/SystemUI/res/values-pt/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Cancelar"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Mantenha \"PÁGINA INICIAL\" pressionado para controlar o PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 3f0b2a4..e045fc8 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -56,7 +56,7 @@
     <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_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>
@@ -302,8 +302,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"căutare"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> nu a putut porni."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Mai mult"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"Încă <xliff:g id="NUMBER">%d</xliff:g>"</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>
@@ -333,6 +332,8 @@
     <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>
@@ -366,7 +367,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Economisirea bateriei este activată"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce performanța și datele de fundal"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Dezactivați economisirea bateriei"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Conținutul este ascuns"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> va începe să captureze tot ceea ce se afișează pe ecran."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Nu se mai afișează"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Ștergeți toate notificările"</string>
@@ -451,4 +451,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Blocate"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Baterie (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings_car.xml b/packages/SystemUI/res/values-ro/strings_car.xml
new file mode 100644
index 0000000..54d8585
--- /dev/null
+++ b/packages/SystemUI/res/values-ro/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">"Conduceți atent"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Aflați mereu condițiile de trafic și respectați întotdeauna legislația aplicabilă. Indicațiile de orientare pot fi inexacte, incomplete, periculoase, neadecvate, interzise sau pot implica trecerea prin zone administrative. Informațiile despre companii pot fi, de asemenea, inexacte sau incomplete. Datele nu sunt în timp real și nu se poate garanta exactitatea locației. Nu manipulați dispozitivul mobil și nu folosiți aplicații neconcepute pentru Android Auto când sunteți la volan."</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..b3cd663
--- /dev/null
+++ b/packages/SystemUI/res/values-ro/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"Î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_cancel" msgid="5173898361050559462">"Anulați"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Pentru a controla PIP, atingeți lung ECRAN DE PORNIRE"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index b92dadc..d9f7a9b 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -303,8 +303,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"Ещё"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"Ещё <xliff:g id="NUMBER">%d</xliff:g>"</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,6 +333,8 @@
     <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>
@@ -367,7 +368,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"Содержимое скрыто"</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>
@@ -452,4 +452,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Блокировка"</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_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_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="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="3476715163685592453">"Батарея (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings_car.xml b/packages/SystemUI/res/values-ru/strings_car.xml
new file mode 100644
index 0000000..cbdb8d7
--- /dev/null
+++ b/packages/SystemUI/res/values-ru/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-ru/strings_tv.xml b/packages/SystemUI/res/values-ru/strings_tv.xml
new file mode 100644
index 0000000..35ecb1c
--- /dev/null
+++ b/packages/SystemUI/res/values-ru/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"Выйти из режима \"Кадр в кадре\""</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_cancel" msgid="5173898361050559462">"Отмена"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Управляйте режимом \"Кадр в кадре\", удерживая кнопку ГЛАВНАЯ"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index 4a18f6e..69514d4 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"තවත්"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"තව <xliff:g id="NUMBER">%d</xliff:g>"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"සැඟවුණු සම්බන්ධතා"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"අවහිර කරන ලදි"</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_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_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="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="3476715163685592453">"බැටරිය (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings_car.xml b/packages/SystemUI/res/values-si-rLK/strings_car.xml
new file mode 100644
index 0000000..549e89b
--- /dev/null
+++ b/packages/SystemUI/res/values-si-rLK/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-si-rLK/strings_tv.xml b/packages/SystemUI/res/values-si-rLK/strings_tv.xml
new file mode 100644
index 0000000..b3beef3
--- /dev/null
+++ b/packages/SystemUI/res/values-si-rLK/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"අවලංගු කරන්න"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIP පාලනය කිරීමට HOME අල්ලාගෙන සිටින්න"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 51a61fe..9ef3d47 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -303,8 +303,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"hľadať"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikáciu <xliff:g id="APP">%s</xliff:g> sa nepodarilo spustiť"</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Viac"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"Ďalšie (<xliff:g id="NUMBER">%d</xliff:g>)"</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>
@@ -334,6 +333,8 @@
     <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>
@@ -367,7 +368,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Šetrič batérie je zapnutý"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Obmedzí výkonnosť a prenos údajov na pozadí"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Vypnúť šetrič batérie"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Skrytý obsah"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikácia <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> začne zaznamenávať všetok obsah zobrazený na vašej obrazovke."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Nabudúce nezobrazovať"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Vymazať všetko"</string>
@@ -452,4 +452,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Zablokované"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Batéria (<xliff:g id="ID_1">%1$d</xliff:g> %%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings_car.xml b/packages/SystemUI/res/values-sk/strings_car.xml
new file mode 100644
index 0000000..bd9410d
--- /dev/null
+++ b/packages/SystemUI/res/values-sk/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">"Jazdite bezpečne"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Zachovajte si úplný prehľad o jazdných podmienkach a vždy dodržiavajte príslušné zákony. Trasy môžu byť nepresné, neúplné, nebezpečné, nevhodné, zakázané alebo môžu zahŕňať cestu cez rôzne správne oblasti. Obchodné informácie môžu byť tiež nepresné alebo neúplné. Údaje nie sú aktualizované v reálnom čase a presnosť polohy nemôžeme zaručiť. Počas jazdy nemanipulujte s mobilným zariadením ani nepoužívajte aplikácie, ktoré nie sú určené pre funkciu Android Auto."</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..24c42d1
--- /dev/null
+++ b/packages/SystemUI/res/values-sk/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Zrušiť"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Ak chcete ovládať režim PIP, podržte tlačidlo plochy"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index cdfa2e9..9fda17b 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -303,8 +303,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"Več"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"In še <xliff:g id="NUMBER">%d</xliff:g>"</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>
@@ -334,6 +333,8 @@
     <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>
@@ -367,7 +368,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Varčevanje z energijo akumulatorja je vklopljeno"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Omeji zmogljivost delovanja in prenos podatkov v ozadju"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Izklop varčevanja z energijo akumulatorja"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Vsebina je skrita"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> bo začela zajemati vse, kar je prikazano na zaslonu."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Tega ne prikaži več"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Izbriši vse"</string>
@@ -452,4 +452,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Blokirano"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Akumulator (<xliff:g id="ID_1">%1$d</xliff:g> %%)"</string>
+    <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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings_car.xml b/packages/SystemUI/res/values-sl/strings_car.xml
new file mode 100644
index 0000000..0102799
--- /dev/null
+++ b/packages/SystemUI/res/values-sl/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">"Varna vožnja"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Bodite pozorni na vozne razmere in vselej upoštevajte veljavno zakonodajo. Navodila za pot so morda nenatančna, nepopolna, nevarna, neprimerna ali prepovedana oziroma vključujejo prečkanje upravnih območij. Prav tako nenatančni ali nepopolni so lahko podatki o podjetjih. Podatki niso sprotni in natančnosti lociranja ni mogoče zagotoviti. Med vožnjo ne uporabljajte mobilne naprave ali aplikacij, ki niso namenjene za Android Auto."</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..28e9d98
--- /dev/null
+++ b/packages/SystemUI/res/values-sl/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Prekliči"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Pridržite tipko HOME za upravljanje načina PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index ed0ad1e..a43ac7e 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"Më shumë"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> të tjera"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Kursimi i baterisë është i aktivizuar"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Pakëson veprimtarinë dhe të dhënat në sfond"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Çaktivizo kursimin e baterisë"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Përmbajtjet janë të fshehura"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> do të fillojë të regjistrojë çdo gjë që shfaqet në ekran."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Mos e shfaq sërish"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Pastroji të gjitha"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"I bllokuar"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Bateria (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</string>
+    <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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings_car.xml b/packages/SystemUI/res/values-sq-rAL/strings_car.xml
new file mode 100644
index 0000000..2e63877
--- /dev/null
+++ b/packages/SystemUI/res/values-sq-rAL/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">"Drejtoje makinën në mënyrë të sigurt"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Ji plotësisht i vetëdijshëm për kushtet e lëvizjes me makinë dhe respekto gjithmonë ligjet përkatëse. Udhëzimet mund të jenë të pasakta, jo të plota, të rrezikshme, të papërshtatshme, të ndaluara ose mund të përfshijnë kalimin në zona administrative. Informacionet e biznesit mund të jenë po ashtu të pasakta ose jo të plota. Të dhënat nuk janë në kohë reale dhe saktësia e vendndodhjes nuk mund të garantohet. Gjatë drejtimit të makinës mos e përdor pajisjen celulare ose mos përdor aplikacionet që nuk janë të planifikuara për Android Auto."</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..31298a4
--- /dev/null
+++ b/packages/SystemUI/res/values-sq-rAL/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Anulo"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Mbaj shtypur HOME për të kontrolluar PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 26c966a..765df27 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -302,8 +302,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"Још"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"Још <xliff:g id="NUMBER">%d</xliff:g>"</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,6 +332,8 @@
     <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,7 +367,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"Садржај је сакривен"</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>
@@ -451,4 +451,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Блокирана"</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_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_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="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="3476715163685592453">"Батерија (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings_car.xml b/packages/SystemUI/res/values-sr/strings_car.xml
new file mode 100644
index 0000000..7f99120
--- /dev/null
+++ b/packages/SystemUI/res/values-sr/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-sr/strings_tv.xml b/packages/SystemUI/res/values-sr/strings_tv.xml
new file mode 100644
index 0000000..3c6b59e
--- /dev/null
+++ b/packages/SystemUI/res/values-sr/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"Затвори 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_cancel" msgid="5173898361050559462">"Откажи"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Задржите тастер за ПОЧЕТНИ ЕКРАН да бисте контролисали PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index f1d691e..c76d1d3 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"sök"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Det gick inte att starta appen <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Mer"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> till"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Batterisparläget har aktiverats"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Minskar prestanda och bakgrundsdata"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Inaktivera batterisparläget"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Innehåll har dolts"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tar en bild av allt som visas på skärmen."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Visa inte igen"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Rensa alla"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Blockerad"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Batteri (<xliff:g id="ID_1">%1$d</xliff:g> %%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings_car.xml b/packages/SystemUI/res/values-sv/strings_car.xml
new file mode 100644
index 0000000..0c03fb6
--- /dev/null
+++ b/packages/SystemUI/res/values-sv/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">"Kör försiktigt"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Håll koll på trafik- och körförhållanden och följ gällande lagar. Det kan hända att vägbeskrivningen inte stämmer, att den är ofullständig, farlig, olämplig, förbjuden eller att den innebär att du måste korsa en administrativ enhet. Det kan även hända att företagsuppgifter är felaktiga eller ofullständiga. Uppgifter visas inte i realtid och det går inte att garantera att platsen är korrekt. Hantera inte din mobila enhet och använd inte appar som inte är ämnade för Android Auto medan du kör."</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..b36c19f
--- /dev/null
+++ b/packages/SystemUI/res/values-sv/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Avbryt"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Håll ned HOME om du vill styra PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 4101ba7..031e2b1 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"tafuta"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Haikuweza kuanzisha <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Zaidi"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"Nyingine <xliff:g id="NUMBER">%d</xliff:g>"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Kiokoa betri kimewashwa"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Hupunguza utendaji na data ya chini chini"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Zima kiokoa betri"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Maudhui yamefichwa"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> itaanza kupiga picha kila kitu kinachoonyeshwa kwenye skrini yako."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Usionyeshe tena"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Futa zote"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Amezuiwa"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Betri (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings_car.xml b/packages/SystemUI/res/values-sw/strings_car.xml
new file mode 100644
index 0000000..e4bb25c
--- /dev/null
+++ b/packages/SystemUI/res/values-sw/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">"Endesha gari kwa usalama"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Jifahamishe kikamilifu kuhusu masharti ya kuendesha gari na utii kila wakati sheria zilizopo. Huenda maelekezo yasiwe sahihi, hayajakamilika, ni hatari, hayafai, hayaruhusiwi au yanahusisha kuvuka maeneo ya kiutawala. Huenda pia maelezo ya biashara yasiwe sahihi au hayajakamilika. Data si ya wakati halisi na hatuwezi kukupa hakikisho kuhusu usahihi wa mahali. Usitumie kifaa chako cha mkononi au programu zisizo za Android Auto wakati unapoendesha gari."</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..fc0f414
--- /dev/null
+++ b/packages/SystemUI/res/values-sw/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Ghairi"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Shikilia kitufe cha HOME ili udhibiti PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-sw600dp-land/config.xml b/packages/SystemUI/res/values-sw600dp-land/config.xml
index f9b01c8..7e8d802 100644
--- a/packages/SystemUI/res/values-sw600dp-land/config.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/config.xml
@@ -18,4 +18,6 @@
     <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
          card. -->
     <integer name="keyguard_max_notification_count">3</integer>
+
+    <integer name="quick_settings_num_columns">3</integer>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index f084bc2..be5b856 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -34,4 +34,7 @@
          In sw600dp we want the buttons centered so this fills the space,
          (screen_pinning_request_width - 3 * screen_pinning_request_button_width) / 2 -->
     <dimen name="screen_pinning_request_side_width">2dp</dimen>
+
+    <dimen name="navigation_key_width">162dp</dimen>
+    <dimen name="navigation_key_padding">42dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 6795da4..db4da10 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -35,11 +35,15 @@
 
     <!-- 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">-4</item>
+    <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>
+
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 49dbac2..71f92fd 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -90,4 +90,7 @@
     <dimen name="screen_pinning_request_side_width">8dp</dimen>
 
     <dimen name="fab_margin">24dp</dimen>
+
+    <dimen name="navigation_key_width">128dp</dimen>
+    <dimen name="navigation_key_padding">25dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index e3bed08..b64ef74 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"மேலும்"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"மேலும் <xliff:g id="NUMBER">%d</xliff:g>"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"மறைந்துள்ள உள்ளடக்கம்"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"தடுக்கப்பட்டது"</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_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_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="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="3476715163685592453">"பேட்டரி (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings_car.xml b/packages/SystemUI/res/values-ta-rIN/strings_car.xml
new file mode 100644
index 0000000..b40ba76
--- /dev/null
+++ b/packages/SystemUI/res/values-ta-rIN/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-ta-rIN/strings_tv.xml b/packages/SystemUI/res/values-ta-rIN/strings_tv.xml
new file mode 100644
index 0000000..3f15396
--- /dev/null
+++ b/packages/SystemUI/res/values-ta-rIN/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"ரத்துசெய்"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIPஐக் கட்டுப்படுத்த, முகப்பைப் பிடித்திருக்கவும்"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index e725d95..1e953d8 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -331,6 +331,8 @@
     <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>
@@ -364,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"కంటెంట్‌లు దాచబడ్డాయి"</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>
@@ -449,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"బ్లాక్ చేయబడింది"</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_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_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="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="3476715163685592453">"బ్యాటరీ (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-te-rIN/strings_car.xml b/packages/SystemUI/res/values-te-rIN/strings_car.xml
new file mode 100644
index 0000000..6f60b3a
--- /dev/null
+++ b/packages/SystemUI/res/values-te-rIN/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-te-rIN/strings_tv.xml b/packages/SystemUI/res/values-te-rIN/strings_tv.xml
new file mode 100644
index 0000000..a3148ddf
--- /dev/null
+++ b/packages/SystemUI/res/values-te-rIN/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"రద్దు చేయి"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIPని నియంత్రించడానికి HOMEని నొక్కి ఉంచండి"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index a60157f..c09b50f 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"เพิ่มเติม"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"อีก <xliff:g id="NUMBER">%d</xliff:g> งาน"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"เนื้อหาถูกซ่อนไว้"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"บล็อกแล้ว"</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_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_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="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="3476715163685592453">"แบตเตอรี่ (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings_car.xml b/packages/SystemUI/res/values-th/strings_car.xml
new file mode 100644
index 0000000..b40584a
--- /dev/null
+++ b/packages/SystemUI/res/values-th/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-th/strings_tv.xml b/packages/SystemUI/res/values-th/strings_tv.xml
new file mode 100644
index 0000000..5921a18
--- /dev/null
+++ b/packages/SystemUI/res/values-th/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"ปิด 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_cancel" msgid="5173898361050559462">"ยกเลิก"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"กดค้างที่ HOME เพื่อควบคุม PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index a19c94d..e76b40c 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"maghanap"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Hindi masimulan <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Higit pa"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> Pa"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Naka-on ang tagatipid ng baterya"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Binabawasan ang pagganap at data sa background"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"I-off ang pagtitipid ng baterya"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Nakatago ang mga content"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"Sisimulan ng i-capture ng <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ang lahat ng ipinapakita sa iyong screen."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Huwag ipakitang muli"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"I-clear lahat"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Na-block"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Baterya (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings_car.xml b/packages/SystemUI/res/values-tl/strings_car.xml
new file mode 100644
index 0000000..6bb04ab
--- /dev/null
+++ b/packages/SystemUI/res/values-tl/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">"Magmaneho nang ligtas"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Manatiling lubos na nakakaalam sa mga kundisyon sa pagmamaneho at palaging sumunod sa mga naaangkop na batas. Ang mga direksyon ay maaaring hindi tumpak, hindi kumpleto, mapanganib, hindi naaangkop, ipinagbabawal o kinasasangkutan ng pagtawid sa mga administratibong lugar. Maaari ding hindi tumpak o hindi kumpleto ang impormasyon ng negosyo. Hindi real-time ang data at hindi magagarantiya ang katumpakan ng lokasyon. Huwag gamitin ang iyong mobile device o gumamit ng mga app na hindi ginawa para sa Android Auto habang nagmamaneho."</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..7940251
--- /dev/null
+++ b/packages/SystemUI/res/values-tl/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Kanselahin"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Pindutin nang matagal ang HOME upang kontrolin ang PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index f210783..a16adfd 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ara"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> başlatılamadı."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Diğer"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> Tane Daha"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Pil tasarrufu açık"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Performansı ve arka plan verilerini azaltır"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Pil tasarrufunu kapat"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"İçerik gizlendi"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>, ekranınızda görüntülenen her şeyi kaydetmeye başlayacak."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Bir daha gösterme"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Tümü temizle"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Engellendi"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Pil (%%<xliff:g id="ID_1">%1$d</xliff:g>)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings_car.xml b/packages/SystemUI/res/values-tr/strings_car.xml
new file mode 100644
index 0000000..72018e2
--- /dev/null
+++ b/packages/SystemUI/res/values-tr/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">"Güvenli bir şekilde sürün"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Sürüş koşullarına karşı dikkatli olun ve geçerli yasalara her zaman uyun. Yol tarifi yanlış, eksik, tehlikeli, uygunsuz, yasak olabilir veya idari bölgelerden geçişleri içerebilir. İşletme bilgileri de yanlış veya eksik olabilir. Veriler gerçek zamanlı değildir ve konum doğruluğu garanti edilemez. Sürüş sırasında mobil cihazınızı veya Android Auto için geliştirilmemiş uygulamaları kullanmayın."</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..69ed9c8
--- /dev/null
+++ b/packages/SystemUI/res/values-tr/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"İptal"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIP\'yi kontrol etmek için ANA EKRAN düğmesini basılı tutun"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 8a1ec97..1c0e04e 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -333,6 +333,8 @@
     <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,7 +368,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"Вміст сховано"</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>
@@ -451,4 +452,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Заблоковано"</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_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_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="color_apply" msgid="9212602012641034283">"Застосувати"</string>
+    <string name="color_revert_title" msgid="4746666545480534663">"Підтвердити налаштування"</string>
+    <string name="color_revert_message" msgid="9116001069397996691">"Деякі налаштування кольорів можуть зробити цей пристрій непридатним для використання. Натисніть OK, щоб підтвердити налаштування, інакше їх буде скинуто через 10 секунд."</string>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Акумулятор (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings_car.xml b/packages/SystemUI/res/values-uk/strings_car.xml
new file mode 100644
index 0000000..4fda0ab
--- /dev/null
+++ b/packages/SystemUI/res/values-uk/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-uk/strings_tv.xml b/packages/SystemUI/res/values-uk/strings_tv.xml
new file mode 100644
index 0000000..d36c5bc
--- /dev/null
+++ b/packages/SystemUI/res/values-uk/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"Закрити 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_cancel" msgid="5173898361050559462">"Скасувати"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Щоб керувати PIP, утримуйте кнопку \"ГОЛОВНИЙ ЕКРАН\""</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index ea7a780..67b52fd 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"مزید"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> مزید"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"مواد مخفی ہیں"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"مسدود کردہ"</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_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_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="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="3476715163685592453">"بیٹری (%%<xliff:g id="ID_1">%1$d</xliff:g>)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings_car.xml b/packages/SystemUI/res/values-ur-rPK/strings_car.xml
new file mode 100644
index 0000000..151ca09
--- /dev/null
+++ b/packages/SystemUI/res/values-ur-rPK/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-ur-rPK/strings_tv.xml b/packages/SystemUI/res/values-ur-rPK/strings_tv.xml
new file mode 100644
index 0000000..b7af745
--- /dev/null
+++ b/packages/SystemUI/res/values-ur-rPK/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"‏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_cancel" msgid="5173898361050559462">"منسوخ کریں"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"‏pip کو کنٹرول کرنے کیلئے ہوم دبا کے رکھیں"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 249de95..dd91bad 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"qidirish"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"“<xliff:g id="APP">%s</xliff:g>” ilovasini ishga tushirib bo‘lmadi."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Ko‘proq"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> ta"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"Kontent yashirildi"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Bloklangan"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Quvvat (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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="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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings_car.xml b/packages/SystemUI/res/values-uz-rUZ/strings_car.xml
new file mode 100644
index 0000000..610dc1f
--- /dev/null
+++ b/packages/SystemUI/res/values-uz-rUZ/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">"Xavfsiz haydash"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Harakat xavfsizligi va amaldagi qonunchilikka doim rioya qiling. Yo‘l ko‘rsatmalari noaniq, chala, xavfli, mos emas, taqiqlangan yoki ma’muriy hududlarni kesib o‘tadigan bo‘lishi mumkin. Biznes ma’lumotlari ham noaniq yoki chala bo‘lishi mumkin. Ma’lumotlar real vaqt rejimida bo‘lmasligi hamda joylashuv ma’lumotining aniqligi kafolatlanmaydi. Avtomobilni haydash mobaynida Android Auto xizmati bilan bog‘liq bo‘lmagan hollarda mobil qurilma yoki ilovalardan foydalanmang."</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..7a1b69c
--- /dev/null
+++ b/packages/SystemUI/res/values-uz-rUZ/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"PIP’ni yopish"</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_cancel" msgid="5173898361050559462">"Bekor qilish"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"PIP’ni boshqarish uchun BOSHIGA tugmasini bosing"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 4d08000..a95e312 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"tìm kiếm"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Không thể khởi động <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Thêm"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> tác vụ khác"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Trình tiết kiệm pin đang bật"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Giảm hiệu suất và dữ liệu nền"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Tắt trình tiết kiệm pin"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Nội dung bị ẩn"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sẽ bắt đầu chụp mọi thứ hiển thị trên màn hình."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Không hiển thị lại"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Xóa tất cả"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Bị chặn"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Pin (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings_car.xml b/packages/SystemUI/res/values-vi/strings_car.xml
new file mode 100644
index 0000000..2aee7d5
--- /dev/null
+++ b/packages/SystemUI/res/values-vi/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">"Lái xe an toàn"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Luôn biết rõ điều kiện lái xe và luôn tuân thủ luật pháp hiện hành. Chỉ đường có thể không chính xác, không hoàn chỉnh, nguy hiểm, không thích hợp, bị cấm hoặc bao gồm tuyến đường giao các khu vực hành chính. Thông tin doanh nghiệp cũng có thể không chính xác hoặc không hoàn chỉnh. Dữ liệu không ở thời gian thực và không thể đảm bảo độ chính xác của vị trí. Không sử dụng thiết bị di động của bạn hoặc sử dụng ứng dụng không dành cho Android Auto trong khi lái xe."</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..ae5f6da
--- /dev/null
+++ b/packages/SystemUI/res/values-vi/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"Đó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_cancel" msgid="5173898361050559462">"Hủy"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Giữ HOME để điều khiển PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index e30320d..e276fb5 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -77,7 +77,7 @@
     <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>
-    <string name="installer_cd_button_title" msgid="2312667578562201583">"安装适用于Mac的Android文件传输应用"</string>
+    <string name="installer_cd_button_title" msgid="2312667578562201583">"安装适用于 Mac 的 Android 文件传输应用"</string>
     <string name="accessibility_back" msgid="567011538994429120">"返回"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"主屏幕"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"菜单"</string>
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"更多"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"还有 <xliff:g id="NUMBER">%d</xliff:g> 项"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"内容已隐藏"</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>
@@ -415,7 +415,7 @@
     <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="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>
@@ -431,7 +431,7 @@
     <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_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>
@@ -444,10 +444,59 @@
     <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="qs_rearrange" msgid="8060918697551068765">"重新排列快捷设置"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"在快捷设置中显示亮度栏"</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="blocked_importance" msgid="5198578988978234161">"屏蔽"</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_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_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="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="3476715163685592453">"电池 (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings_car.xml b/packages/SystemUI/res/values-zh-rCN/strings_car.xml
new file mode 100644
index 0000000..6a5a4e8
--- /dev/null
+++ b/packages/SystemUI/res/values-zh-rCN/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-zh-rCN/strings_tv.xml b/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
new file mode 100644
index 0000000..25d3ff0
--- /dev/null
+++ b/packages/SystemUI/res/values-zh-rCN/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"关闭 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_cancel" msgid="5173898361050559462">"取消"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"按住主屏幕图标即可控制 PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 94548ba..86f78e4 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"更多"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"還有 <xliff:g id="NUMBER">%d</xliff:g> 項"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"內容已隱藏"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"已封鎖"</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_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_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="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="3476715163685592453">"電池電量 (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings_car.xml b/packages/SystemUI/res/values-zh-rHK/strings_car.xml
new file mode 100644
index 0000000..18f9e50
--- /dev/null
+++ b/packages/SystemUI/res/values-zh-rHK/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-zh-rHK/strings_tv.xml b/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
new file mode 100644
index 0000000..1b46b64
--- /dev/null
+++ b/packages/SystemUI/res/values-zh-rHK/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"關閉 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_cancel" msgid="5173898361050559462">"取消"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"按住主按鈕即可控制 PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index c4035e1..00eb788 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <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_show_history_button_label" msgid="7062088196449747245">"更多"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"還有 <xliff:g id="NUMBER">%d</xliff:g> 項"</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,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <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="notification_hidden_text" msgid="1135169301897151909">"內容已隱藏"</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>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"封鎖"</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_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_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="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="3476715163685592453">"電池 (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings_car.xml b/packages/SystemUI/res/values-zh-rTW/strings_car.xml
new file mode 100644
index 0000000..5e18309
--- /dev/null
+++ b/packages/SystemUI/res/values-zh-rTW/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-zh-rTW/strings_tv.xml b/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
new file mode 100644
index 0000000..8a085b0
--- /dev/null
+++ b/packages/SystemUI/res/values-zh-rTW/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"關閉子母畫面"</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_cancel" msgid="5173898361050559462">"取消"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"按住「主畫面」圖示即可控制子母畫面"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 87b6aaf..08dc7cc 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  -->
@@ -301,8 +301,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"sesha"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Ayikwazanga ukuqala i-<xliff:g id="APP">%s</xliff:g>."</string>
     <string name="recents_show_history_button_label" msgid="7062088196449747245">"Okuningi"</string>
-    <!-- no translation found for recents_history_label_format (6337155608055062429) -->
-    <skip />
+    <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> Okuningi"</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>
@@ -332,6 +331,8 @@
     <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>
@@ -365,7 +366,6 @@
     <string name="battery_saver_notification_title" msgid="237918726750955859">"Isilondolozi sebhethri sivuliwe"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Sehlisa ukusebenza nedatha yasemuva"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Vala isilondolozi sebhethri"</string>
-    <string name="notification_hidden_text" msgid="1135169301897151909">"Okuqukethwe kufihliwe"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> izoqala ukuthwebula yonke into eboniswa kusikrini sakho."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Ungabonisi futhi"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Sula konke"</string>
@@ -450,4 +450,53 @@
     <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="blocked_importance" msgid="5198578988978234161">"Kuvinjelwe"</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_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_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="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>
+    <string name="battery_panel_title" msgid="3476715163685592453">"Ibhethri (<xliff:g id="ID_1">%1$d</xliff:g>%%)"</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_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="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>
+    <!-- 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 />
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings_car.xml b/packages/SystemUI/res/values-zu/strings_car.xml
new file mode 100644
index 0000000..83301ac
--- /dev/null
+++ b/packages/SystemUI/res/values-zu/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">"Shayela ngokuqophelela"</string>
+    <string name="car_lockscreen_disclaimer_text" msgid="3061224684092952864">"Hlala wazi ngokugcwele izimo zokushayela uphinde uthobele yonke imithetho esebenzayo. Izikhombisi-ndlela kungenzeka azilungile, aziphelele, ziyingozi, azifanelekile, zivinjiwe, noma zifaka ukweqa izindawo zokulawula. Ulwazi lwebhizinisi kungenzeka lungalungi noma lungapheleli. Idatha akuyona isikhathi sangempela, futhi ukunemba kwendawo akukwazi ukuqinisekiswa. Ungaphathi idivayisi yakho yeselula noma usebenzise izinhlelo zokusebenza ezihloselwe i-Android Auto ngenkathi ushayela."</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..17764f4
--- /dev/null
+++ b/packages/SystemUI/res/values-zu/strings_tv.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="pip_exit" msgid="6423523158795119008">"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_cancel" msgid="5173898361050559462">"Khansela"</string>
+    <string name="pip_hold_home" msgid="883546189749854120">"Bamba okuthi Ekhaya ukuze ulawule i-PIP"</string>
+</resources>
diff --git a/packages/SystemUI/res/values/arrays.xml b/packages/SystemUI/res/values/arrays.xml
index 6102aa6..bf0cba2 100644
--- a/packages/SystemUI/res/values/arrays.xml
+++ b/packages/SystemUI/res/values/arrays.xml
@@ -37,4 +37,18 @@
         <item>157</item><item>334</item>
         <item>0</item>  <item>334</item>
     </array>
+    <array name="batterymeter_plus_points">
+        <item>3</item><item>0</item>
+        <item>5</item><item>0</item>
+        <item>5</item><item>3</item>
+        <item>8</item><item>3</item>
+        <item>8</item><item>5</item>
+        <item>5</item><item>5</item>
+        <item>5</item><item>8</item>
+        <item>3</item><item>8</item>
+        <item>3</item><item>5</item>
+        <item>0</item><item>5</item>
+        <item>0</item><item>3</item>
+        <item>3</item><item>3</item>
+    </array>
 </resources>
diff --git a/packages/SystemUI/res/values/arrays_car.xml b/packages/SystemUI/res/values/arrays_car.xml
new file mode 100644
index 0000000..8c760fc
--- /dev/null
+++ b/packages/SystemUI/res/values/arrays_car.xml
@@ -0,0 +1,30 @@
+<?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>
+    <!-- These should be overriden in an overlay. The default implementation is empty.
+         There needs to be correspondence per index between these arrays, which means that if there
+         isn't a longpress action associated with a shortcut item, put in an empty item to make
+         sure everything lines up.
+    -->
+    <array name="car_facet_icons" />
+    <array name="car_facet_intent_uris" />
+    <array name="car_facet_longpress_intent_uris" />
+    <array name="car_facet_package_filters"/>
+    <array name="car_facet_category_filters"/>
+</resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 955efb5..19bc755 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -28,9 +28,6 @@
     <declare-styleable name="NotificationLinearLayout">
         <attr name="insetLeft" format="dimension" />
     </declare-styleable>
-    <declare-styleable name="NotificationRowLayout">
-        <attr name="rowHeight" format="dimension" />
-    </declare-styleable>
     <declare-styleable name="RecentsPanelView">
         <attr name="recentItemLayout" format="reference" />
     </declare-styleable>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 76c08f6..9bb6dc6 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -36,7 +36,6 @@
     <color name="system_warning_color">#fff4511e</color><!-- deep orange 600 -->
     <color name="qs_text">#FFFFFFFF</color>
     <color name="qs_tile_divider">#29ffffff</color><!-- 16% white -->
-    <color name="qs_tile_text">#B3FFFFFF</color><!-- 70% white -->
     <color name="qs_subhead">#99FFFFFF</color><!-- 60% white -->
     <color name="qs_detail_empty">#24B0BEC5</color><!-- 14% blue grey 200 -->
     <color name="qs_detail_button">#FFB0BEC5</color><!-- 100% blue grey 200 -->
@@ -48,6 +47,7 @@
     <color name="data_usage_graph_warning">#FFFFFFFF</color>
     <color name="status_bar_clock_color">#FFFFFFFF</color>
     <color name="qs_user_detail_icon_muted">#FFFFFFFF</color> <!-- not so muted after all -->
+    <color name="qs_tile_disabled_color">#9E9E9E</color> <!-- 38% black -->
 
     <!-- Tint color for the content on the notification overflow card. -->
     <color name="keyguard_overflow_content_color">#ff686868</color>
@@ -62,14 +62,12 @@
     <color name="recents_task_bar_light_icon_color">#ffeeeeee</color>
     <!-- The recents task bar dark dismiss icon color to be drawn on top of light backgrounds. -->
     <color name="recents_task_bar_dark_icon_color">#99000000</color>
-    <!-- The recents task bar highlight color. -->
-    <color name="recents_task_bar_highlight_color">#28ffffff</color>
     <!-- The lock to task button background color. -->
     <color name="recents_task_view_lock_to_app_button_background_color">#ffe6e6e6</color>
     <!-- The lock to task button foreground color. -->
     <color name="recents_task_view_lock_to_app_button_color">#ff666666</color>
     <!-- The background color for the freeform workspace. -->
-    <color name="recents_freeform_workspace_bg_color">#66000000</color>
+    <color name="recents_freeform_workspace_bg_color">#33FFFFFF</color>
 
     <color name="keyguard_affordance">#ffffffff</color>
 
@@ -77,17 +75,16 @@
     <color name="notification_legacy_background_color">#ff1a1a1a</color>
 
     <!-- The color of the material notification background -->
-    <color name="notification_material_background_color">#fffafafa</color>
+    <color name="notification_material_background_color">#ffffffff</color>
 
     <!-- The color of the material notification background when dimmed -->
-    <color name="notification_material_background_dimmed_color">#d4ffffff</color>
+    <color name="notification_material_background_dimmed_color">#ccffffff</color>
 
     <!-- The color of the material notification background when low priority -->
-    <color name="notification_material_background_low_priority_color">#ffe0e0e0</color>
+    <color name="notification_material_background_low_priority_color">#fff5f5f5</color>
 
-    <!-- The color of the material notification background for media notifications when no custom
-         color is specified -->
-    <color name="notification_material_background_media_default_color">#ff424242</color>
+    <!-- The background color of the notification shade -->
+    <color name="notification_shade_background_color">#ffeeeeee</color>
 
     <!-- The color of the ripples on the untinted notifications -->
     <color name="notification_ripple_untinted_color">#28000000</color>
@@ -102,10 +99,11 @@
     <color name="current_user_border_color">@color/system_accent_color</color>
 
     <!-- The "inside" of a notification, reached via longpress -->
-    <color name="notification_guts_bg_color">@*android:color/material_deep_teal_500</color>
-    <color name="notification_guts_title_color">#B2DFDB</color>
-    <color name="notification_guts_text_color">#FFFFFFFF</color>
-    <color name="notification_guts_btn_color">#FFFFFFFF</color>
+    <color name="notification_guts_bg_color">#eeeeee</color>
+    <color name="notification_guts_slider_color">@*android:color/material_deep_teal_500</color>
+    <color name="notification_guts_secondary_slider_color">#858383</color>
+    <color name="notification_guts_icon_tint">#8a000000</color>
+    <color name="notification_guts_disabled_icon_tint">#4d000000</color>
 
     <color name="assist_orb_color">#ffffff</color>
 
@@ -149,4 +147,16 @@
 
     <color name="default_remote_input_background">@*android:color/notification_default_color</color>
     <color name="remote_input_hint">#4dffffff</color>
+
+    <color name="qs_tile_tint_unavailable">#40ffffff</color>
+    <color name="qs_tile_tint_inactive">#4dffffff</color>
+    <color name="qs_tile_tint_active">#ffffffff</color>
+
+    <color name="switch_bar_background">#ff37474f</color>
+    <color name="switch_accent_color">#ff7fcac3</color>
+
+    <!-- Keyboard shortcuts colors -->
+    <color name="ksh_system_group_color">#ff00bcd4</color>
+    <color name="ksh_application_group_color">#fff44336</color>
+    <color name="ksh_dialog_background_color">#ffffffff</color>
 </resources>
diff --git a/packages/SystemUI/res/values/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml
new file mode 100644
index 0000000..6f4c983
--- /dev/null
+++ b/packages/SystemUI/res/values/colors_tv.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.
+ */
+-->
+<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>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 40e8b50..6df31ff 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -147,6 +147,9 @@
     <!-- The duration for animating the task decorations in after transitioning from an app. -->
     <integer name="recents_task_enter_from_app_duration">200</integer>
 
+    <!-- The duration for animating the task decorations in after transitioning from an app. -->
+    <integer name="recents_task_enter_from_affiliated_app_duration">125</integer>
+
     <!-- The duration for animating the task decorations out before transitioning to an app. -->
     <integer name="recents_task_exit_to_app_duration">125</integer>
 
@@ -172,11 +175,17 @@
     <integer name="recents_nav_bar_scrim_enter_duration">400</integer>
 
     <!-- The animation duration for animating the removal of a task view. -->
-    <integer name="recents_animate_task_view_remove_duration">250</integer>
+    <integer name="recents_animate_task_view_remove_duration">175</integer>
 
     <!-- The animation duration for scrolling the stack to a particular item. -->
     <integer name="recents_animate_task_stack_scroll_duration">200</integer>
 
+    <!-- The animation duration for scrolling the stack to a particular item. -->
+    <integer name="recents_auto_advance_duration">750</integer>
+
+    <!-- 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>
 
@@ -189,9 +198,13 @@
     <!-- Svelte specific logic, see RecentsConfiguration.SVELTE_* constants. -->
     <integer name="recents_svelte_level">0</integer>
 
+    <!-- In multi-window, determines whether the stack where recents lives should grow from
+         the smallest position when being launched. -->
+    <bool name="recents_grow_in_multiwindow">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">-4</item>
+    <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
@@ -279,5 +292,11 @@
     <!-- Whether to show the full screen user switcher. -->
     <bool name="config_enableFullscreenUserSwitcher">false</bool>
 
+    <!-- SystemUIFactory component -->
+    <string name="config_systemUIFactoryComponent" translatable="false">com.android.systemui.SystemUIFactory</string>
+
+    <!-- Nav bar button default ordering/layout -->
+    <string name="config_navBarLayout" translatable="false">space,back;home;recent,menu_ime</string>
+
 </resources>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 4f070d6..32d09e8 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -33,9 +33,30 @@
     <!-- Height of notification icons in the status bar -->
     <dimen name="status_bar_icon_size">@*android:dimen/status_bar_icon_size</dimen>
 
-    <!-- The font size for the clock -->
+    <!-- Height of the battery icon in the status bar. -->
+    <dimen name="status_bar_battery_icon_height">14.5dp</dimen>
+
+    <!-- Width of the battery icon in the status bar. -->
+    <dimen name="status_bar_battery_icon_width">9.5dp</dimen>
+
+    <!-- The font size for the clock in the status bar. -->
     <dimen name="status_bar_clock_size">14sp</dimen>
 
+    <!-- The starting padding for the clock in the status bar. -->
+    <dimen name="status_bar_clock_starting_padding">7dp</dimen>
+
+    <!-- The end padding for the clock in the status bar. -->
+    <dimen name="status_bar_clock_end_padding">0dp</dimen>
+
+    <!-- Spacing after the wifi signals that is present if there are any icons following it. -->
+    <dimen name="status_bar_wifi_signal_spacer_width">4dp</dimen>
+
+    <!-- Spacing before the airplane mode icon if there are any icons preceding it. -->
+    <dimen name="status_bar_airplane_spacer_width">4dp</dimen>
+
+    <!-- The amount to scale each of the status bar icons by. A value of 1 means no scaling. -->
+    <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">84dp</dimen>
 
@@ -49,11 +70,14 @@
     <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">140dp</dimen>
+    <dimen name="notification_max_heads_up_height">141dp</dimen>
 
     <!-- Height of a the summary ("more card") notification on keyguard. -->
     <dimen name="notification_summary_height">44dp</dimen>
 
+    <!-- Minimum layouted height of a notification in the statusbar-->
+    <dimen name="min_notification_layout_height">48dp</dimen>
+
     <!-- size at which Notification icons will be drawn in the status bar -->
     <dimen name="status_bar_icon_drawing_size">17dip</dimen>
 
@@ -63,15 +87,17 @@
     <!-- gap on either side of status bar notification icons -->
     <dimen name="status_bar_icon_padding">0dp</dimen>
 
-    <!-- half the distance between notifications in the panel -->
-    <dimen name="notification_divider_height">2dp</dimen>
-
     <!-- The padding on the global screenshot background image -->
     <dimen name="global_screenshot_bg_padding">20dp</dimen>
 
     <!-- The width of the view containing navigation buttons -->
     <dimen name="navigation_key_width">70dp</dimen>
 
+    <dimen name="navigation_key_padding">0dp</dimen>
+
+    <dimen name="navigation_key_width_sw600dp_land">162dp</dimen>
+    <dimen name="navigation_key_padding_sw600dp_land">42dp</dimen>
+
     <!-- The width of the view containing the menu/ime navigation bar icons -->
     <dimen name="navigation_extra_key_width">36dp</dimen>
 
@@ -108,9 +134,11 @@
 
     <!-- Width for the notification panel and related windows -->
     <dimen name="match_parent">-1px</dimen>
-    <dimen name="standard_notification_panel_width">416dp</dimen><!-- includes notification_side_padding on each side -->
+    <dimen name="standard_notification_panel_width">416dp</dimen>
     <dimen name="notification_panel_width">@dimen/match_parent</dimen>
 
+    <dimen name="volume_dialog_panel_width">@dimen/standard_notification_panel_width</dimen>
+
     <!-- Gravity for the notification panel -->
     <integer name="standard_notification_panel_layout_gravity">0x31</integer><!-- top|center_horizontal -->
     <integer name="notification_panel_layout_gravity">0x37</integer><!-- fill_horizontal|top -->
@@ -131,9 +159,7 @@
     <dimen name="pull_span_min">25dp</dimen>
 
     <dimen name="qs_tile_height">88dp</dimen>
-    <dimen name="qs_new_tile_height">100dp</dimen>
-    <dimen name="qs_quick_actions_height">88dp</dimen>
-    <dimen name="qs_quick_actions_padding">25dp</dimen>
+    <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">44.5dp</dimen>
@@ -164,6 +190,8 @@
     <dimen name="segmented_button_spacing">0dp</dimen>
     <dimen name="borderless_button_radius">2dp</dimen>
 
+    <dimen name="restricted_padlock_pading">4dp</dimen>
+
     <!-- How far the expanded QS panel peeks from the header in collapsed state. -->
     <dimen name="qs_peek_height">0dp</dimen>
 
@@ -188,26 +216,31 @@
     <!-- Default distance from each snap target that GlowPadView considers a "hit" -->
     <dimen name="glowpadview_inner_radius">15dip</dimen>
 
-    <!-- The size of the application icon in the recents task view. -->
-    <dimen name="recents_task_view_application_icon_size">48dp</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 min translation in the Z index for the last task. -->
-    <dimen name="recents_task_view_z_min">20dp</dimen>
+    <dimen name="recents_task_view_z_min">16dp</dimen>
 
     <!-- The max translation in the Z index for the last task. -->
-    <dimen name="recents_task_view_z_max">80dp</dimen>
+    <dimen name="recents_task_view_z_max">48dp</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">1.5dp</dimen>
+    <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">64dp</dimen>
+    <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>
@@ -245,6 +278,9 @@
     <!-- 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 top stack -->
     <dimen name="top_stack_peek_amount">12dp</dimen>
 
@@ -261,17 +297,14 @@
     <!-- The height of the area before the top stack in which the notifications slow down -->
     <dimen name="top_stack_slow_down_length">12dp</dimen>
 
-    <!-- The side padding of the notifications-->
-    <dimen name="notification_side_padding">8dp</dimen>
-
     <!-- Z distance between notifications if they are in the stack -->
-    <dimen name="z_distance_between_notifications">1dp</dimen>
+    <dimen name="z_distance_between_notifications">0.5dp</dimen>
 
-    <!-- The padding between the individual notification cards when dimmed. -->
-    <dimen name="notification_padding_dimmed">0dp</dimen>
+    <!-- The height of the divider between the individual notifications. -->
+    <dimen name="notification_divider_height">0.5dp</dimen>
 
-    <!-- The padding between the individual notification cards. -->
-    <dimen name="notification_padding">2dp</dimen>
+    <!-- The height of the divider between the individual notifications when the notification wants it to be increased. This is currently the case for notification groups -->
+    <dimen name="notification_divider_height_increased">6dp</dimen>
 
     <!-- The minimum amount of top overscroll to go to the quick settings. -->
     <dimen name="min_top_overscroll_to_qs">36dp</dimen>
@@ -291,8 +324,6 @@
     <!-- Falsing threshold used when dismissing notifications from the lockscreen. -->
     <dimen name="swipe_helper_falsing_threshold">70dp</dimen>
 
-    <dimen name="notifications_top_padding">4dp</dimen>
-    
     <!-- Minimum distance the user has to drag down to go to the full shade. -->
     <dimen name="keyguard_drag_down_min_distance">100dp</dimen>
 
@@ -337,21 +368,12 @@
          phone hints. -->
     <dimen name="edge_tap_area_width">48dp</dimen>
 
-    <!-- radius of the corners of the material rounded rect background -->
-    <dimen name="notification_material_rounded_rect_radius">2dp</dimen>
-
-    <!-- radius of the corners of the material rounded rect background but negative-->
-    <dimen name="notification_material_rounded_rect_radius_negative">-2dp</dimen>
-
     <!-- The padding between notification children when collapsed -->
     <dimen name="notification_children_padding">4dp</dimen>
 
     <!-- The padding on top of the first notification to the children container -->
     <dimen name="notification_children_container_top_padding">8dp</dimen>
 
-    <!-- The height of the divider between the notfication children -->
-    <dimen name="notification_children_divider_height">1dp</dimen>
-
     <!-- The vertical distance from which the notification appear when children are expanded -->
     <dimen name="notification_appear_distance">140dp</dimen>
 
@@ -503,13 +525,16 @@
 
     <!-- The maximum width of the navigation bar ripples. -->
     <dimen name="key_button_ripple_max_width">95dp</dimen>
-    
+
     <!-- Inset shadow for FakeShadowDrawable. It is used to avoid gaps between the card
          and the shadow. -->
     <dimen name="fake_shadow_inset">1dp</dimen>
 
     <dimen name="fake_shadow_size">8dp</dimen>
 
+    <!-- Starting margin before the signal cluster -->
+    <dimen name="signal_cluster_margin_start">2.5dp</dimen>
+
     <!-- Padding between signal cluster and battery icon -->
     <dimen name="signal_cluster_battery_padding">7dp</dimen>
 
@@ -577,9 +602,8 @@
     <dimen name="qs_header_neg_padding">-8dp</dimen>
 
     <!-- How high we lift the divider when touching -->
-    <dimen name="docked_stack_divider_lift_elevation">6dp</dimen>
+    <dimen name="docked_stack_divider_lift_elevation">4dp</dimen>
 
-    <dimen name="docked_divider_handle_width">24dp</dimen>
+    <dimen name="docked_divider_handle_width">16dp</dimen>
     <dimen name="docked_divider_handle_height">2dp</dimen>
-
 </resources>
diff --git a/packages/SystemUI/res/values/dimens_car.xml b/packages/SystemUI/res/values/dimens_car.xml
new file mode 100644
index 0000000..04402b7
--- /dev/null
+++ b/packages/SystemUI/res/values/dimens_car.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>
+    <dimen name="car_lockscreen_disclaimer_title_size">48sp</dimen>
+    <dimen name="car_lockscreen_disclaimer_title_padding_start">96dp</dimen>
+    <dimen name="car_lockscreen_disclaimer_title_padding_top">82dp</dimen>
+    <dimen name="car_lockscreen_disclaimer_text_size">28sp</dimen>
+    <dimen name="car_lockscreen_disclaimer_text_padding_start">96dp</dimen>
+    <dimen name="car_lockscreen_disclaimer_text_padding_end">96dp</dimen>
+    <dimen name="car_lockscreen_disclaimer_text_padding_top">8dp</dimen>
+    <dimen name="car_lockscreen_user_grid_view_padding_start">10dp</dimen>
+    <dimen name="car_lockscreen_user_grid_view_padding_end">10dp</dimen>
+    <dimen name="car_fullscreen_user_pod_image_avatar_width">128dp</dimen>
+    <dimen name="car_fullscreen_user_pod_image_avatar_height">128dp</dimen>
+    <dimen name="car_fullscreen_user_pod_text_size">24sp</dimen>
+    <dimen name="car_navigation_button_width">64dp</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values/dimens_tv.xml b/packages/SystemUI/res/values/dimens_tv.xml
new file mode 100644
index 0000000..77605bd
--- /dev/null
+++ b/packages/SystemUI/res/values/dimens_tv.xml
@@ -0,0 +1,34 @@
+<?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>
+    <!-- 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>
+
+    <!-- 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_card_spacing">8dip</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
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 13128b7..87aedab 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -18,28 +18,28 @@
 <resources>
     <item type="id" name="translation_y_animator_tag"/>
     <item type="id" name="translation_z_animator_tag"/>
-    <item type="id" name="scale_animator_tag"/>
     <item type="id" name="alpha_animator_tag"/>
     <item type="id" name="top_inset_animator_tag"/>
     <item type="id" name="height_animator_tag"/>
+    <item type="id" name="shadow_alpha_animator_tag"/>
     <item type="id" name="translation_y_animator_end_value_tag"/>
     <item type="id" name="translation_z_animator_end_value_tag"/>
-    <item type="id" name="scale_animator_end_value_tag"/>
     <item type="id" name="alpha_animator_end_value_tag"/>
     <item type="id" name="top_inset_animator_end_value_tag"/>
     <item type="id" name="height_animator_end_value_tag"/>
+    <item type="id" name="shadow_alpha_animator_end_value_tag"/>
     <item type="id" name="translation_y_animator_start_value_tag"/>
     <item type="id" name="translation_z_animator_start_value_tag"/>
-    <item type="id" name="scale_animator_start_value_tag"/>
     <item type="id" name="alpha_animator_start_value_tag"/>
     <item type="id" name="top_inset_animator_start_value_tag"/>
     <item type="id" name="height_animator_start_value_tag"/>
+    <item type="id" name="shadow_alpha_animator_start_value_tag"/>
     <item type="id" name="doze_saved_filter_tag"/>
     <item type="id" name="qs_icon_tag"/>
     <item type="id" name="scrim"/>
     <item type="id" name="scrim_target"/>
-    <item type="id" name="hun_scrim_alpha_start"/>
-    <item type="id" name="hun_scrim_alpha_end"/>
+    <item type="id" name="scrim_alpha_start"/>
+    <item type="id" name="scrim_alpha_end"/>
     <item type="id" name="notification_power"/>
     <item type="id" name="notification_screenshot"/>
     <item type="id" name="notification_hidden"/>
@@ -50,6 +50,11 @@
 
     <!-- For notification icons for which targetSdk < L, this caches whether the icon is grayscale -->
     <item type="id" name="icon_is_grayscale" />
+    <item type="id" name="clip_children_tag" />
+    <item type="id" name="clip_children_set_tag" />
+    <item type="id" name="clip_to_padding_tag" />
+    <item type="id" name="image_icon_tag" />
+    <item type="id" name="contains_transformed_view" />
     <item type="id" name="is_clicked_heads_up_tag" />
 </resources>
 
diff --git a/packages/SystemUI/res/values/integers_tv.xml b/packages/SystemUI/res/values/integers_tv.xml
new file mode 100644
index 0000000..bfd8f8b
--- /dev/null
+++ b/packages/SystemUI/res/values/integers_tv.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>
+    <integer name="item_scale_anim_duration">150</integer>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/internal.xml b/packages/SystemUI/res/values/internal.xml
index 67685ee..e0d3cd2 100644
--- a/packages/SystemUI/res/values/internal.xml
+++ b/packages/SystemUI/res/values/internal.xml
@@ -17,6 +17,7 @@
 <resources>
     <dimen name="status_bar_height">@*android:dimen/status_bar_height</dimen>
     <dimen name="navigation_bar_height">@*android:dimen/navigation_bar_height</dimen>
+    <dimen name="navigation_bar_height_car_mode">@*android:dimen/navigation_bar_height_car_mode</dimen>
     <color name="screen_pinning_primary_text">@*android:color/primary_text_default_material_light</color>
 </resources>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index f71a71a..32da3c6 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3,16 +3,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 -->
@@ -359,6 +359,9 @@
     <!-- Content description of the data connection with no SIM for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_no_sim">No SIM.</string>
 
+    <!-- Content description of the cell data being disabled. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_cell_data_off">Cellular Data Off</string>
+
     <!-- Content description of the bluetooth tethering icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_bluetooth_tether">Bluetooth tethering.</string>
 
@@ -712,9 +715,9 @@
     <!-- Recents: Launch error string. [CHAR LIMIT=NONE] -->
     <string name="recents_launch_error_message">Could not start <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
     <!-- Recents: Show history string. [CHAR LIMIT=NONE] -->
-    <string name="recents_show_history_button_label">More</string>
-    <!-- Recents: A format string to set the number of availabe historical tasks in recents. [CHAR LIMIT=NONE] -->
-    <string name="recents_history_label_format"><xliff:g id="number">%d</xliff:g> More</string>
+    <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: MultiStack add stack split horizontal radio button. [CHAR LIMIT=NONE] -->
     <string name="recents_multistack_add_stack_dialog_split_horizontal">Split Horizontal</string>
@@ -805,6 +808,12 @@
     <!-- Interruption level: Alarms only.  Optimized for narrow two-line display. [CHAR LIMIT=40] -->
     <string name="interruption_level_alarms_twoline">Alarms\nonly</string>
 
+    <!-- Interruption level: All interruptions. [CHAR LIMIT=40] -->
+    <string name="interruption_level_all">All</string>
+
+    <!-- Interruption level: All interruptions.  Optimized for narrow two-line display. [CHAR LIMIT=40] -->
+    <string name="interruption_level_all_twoline">All\n</string>
+
     <!-- Indication on the keyguard that is shown when the device is charging. [CHAR LIMIT=40]-->
     <string name="keyguard_indication_charging_time">Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
 
@@ -906,9 +915,6 @@
     <!-- Battery saver notification action text. [CHAR LIMIT=60] -->
     <string name="battery_saver_notification_action_text">Turn off battery saver</string>
 
-    <!-- Text shown in place of notification contents when the notification is hidden on a secure lockscreen -->
-    <string name="notification_hidden_text">Contents hidden</string>
-
     <!-- Media projection permission dialog warning text. [CHAR LIMIT=NONE] -->
     <string name="media_projection_dialog_text"><xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> will start capturing everything that\'s displayed on your screen.</string>
 
@@ -1201,4 +1207,197 @@
     <!-- 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>
+    <!-- Notification importance title, blocked status-->
+    <string name="blocked_importance">Blocked</string>
+    <!-- Notification importance title, low status-->
+    <string name="low_importance">Low importance</string>
+    <!-- Notification importance title, normal status-->
+    <string name="default_importance">Normal importance</string>
+    <!-- Notification importance title, high status-->
+    <string name="high_importance">High importance</string>
+    <!-- Notification importance title, max status-->
+    <string name="max_importance">Urgent importance</string>
+
+    <!-- [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: low importance level description -->
+    <string name="notification_importance_low">Silently show at the bottom of the notification list</string>
+
+    <!-- [CHAR LIMIT=100] Notification Importance slider: normal importance level description -->
+    <string name="notification_importance_default">Silently show these notifications</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>
+
+    <!-- [CHAR LIMIT=100] Notification Importance slider: max importance level description -->
+    <string name="notification_importance_max">Peek onto the screen and make 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>
+
+    <!-- Label for no color transform [CHAR LIMIT=30] -->
+    <string name="color_matrix_none">Normal colors</string>
+
+    <!-- Label for night color transform [CHAR LIMIT=30] -->
+    <string name="color_matrix_night">Night colors</string>
+
+    <!-- Label for custom color transform [CHAR LIMIT=30] -->
+    <string name="color_matrix_custom">Custom colors</string>
+
+    <!-- Label for auto color transforms [CHAR LIMIT=30] -->
+    <string name="color_matrix_auto">Auto</string>
+
+    <!-- Label for unknown color transform [CHAR LIMIT=30] -->
+    <string name="color_matrix_unknown">Unknown colors</string>
+
+    <!-- Title for color transform [CHAR LIMIT=30] -->
+    <string name="color_transform">Color modification</string>
+
+    <!-- Title for setting to show Quick Settings tile [CHAR LIMIT=60] -->
+    <string name="color_matrix_show_qs">Show Quick Settings tile</string>
+
+    <!-- Title for switch to enable custom color transform [CHAR LIMIT=60] -->
+    <string name="color_enable_custom">Enable custom transform</string>
+
+    <!-- Button to apply settings [CHAR LIMIT=30] -->
+    <string name="color_apply">Apply</string>
+
+    <!-- Title of warning dialog about bad color settings. [CHAR LIMIT=30] -->
+    <string name="color_revert_title">Confirm settings</string>
+
+    <!-- Message warning user about custom color settings [CHAR LIMIT=NONE] -->
+    <string name="color_revert_message">Some color settings can make this
+        device unusable. Click OK to confirm these color settings,
+        otherwise these settings will reset after 10 seconds.</string>
+
+    <string name="color_modification_r" translatable="false">R</string>
+    <string name="color_modification_g" translatable="false">G</string>
+    <string name="color_modification_b" translatable="false">B</string>
+
+    <!-- Title of the battery settings detail panel [CHAR LIMIT=20] -->
+    <string name="battery_panel_title">Battery (<xliff:g name="pattery_percent" example="52">%1$d</xliff:g>%%)</string>
+
+    <!-- Summary of battery saver not available [CHAR LIMIT=NONE] -->
+    <string name="battery_detail_charging_summary">Battery Saver not available during charging</string>
+
+    <!-- Title of switch for battery saver [CHAR LIMIT=NONE] -->
+    <string name="battery_detail_switch_title">Battery Saver</string>
+
+    <!-- Summary of switch for battery saver [CHAR LIMIT=NONE] -->
+    <string name="battery_detail_switch_summary">Reduces performance and background data</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. -->
+    <string name="keyboard_shortcut_group_system_home">Home</string>
+    <!-- User visible title for the the keyboard shortcut that takes the user to the recents screen. -->
+    <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>
+
+    <!-- SysUI Tuner: Option to show full do not disturb panel in volume [CHAR LIMIT=60] -->
+    <string name="tuner_full_zen_title">Show do not disturb in volume</string>
+    <!-- SysUI Tuner: Summary of option to show full do not disturb panel in volume [CHAR LIMIT=NONE] -->
+    <string name="tuner_full_zen_summary">Allow full control of do not disturb in the volume dialog.</string>
+
+    <!-- SysUI Tuner: Label for screen about volume and do not disturb settings [CHAR LIMIT=60] -->
+    <string name="volume_and_do_not_disturb">Volume and Do not disturb</string>
+
+    <!-- SysUI Tuner: Switch to control volume down behavior [CHAR LIMIT=60] -->
+    <string name="volume_down_silent">Enter do not disturb on volume down</string>
+
+    <!-- SysUI Tuner: Switch to control volume up behavior [CHAR LIMIT=60] -->
+    <string name="volume_up_silent">Exit do not disturb on volume up</string>
+
+    <!-- Name of the battery icon in status bar [CHAR LIMIT=30] -->
+    <string name="battery">Battery</string>
+
+    <!-- Name of the clock in status bar [CHAR LIMIT=30] -->
+    <string name="clock">Clock</string>
+
+    <!-- Name of the headset in status bar [CHAR LIMIT=30] -->
+    <string name="headset">Headset</string>
+
+    <!-- Accessibility description of headphones icon [CHAR LIMIT=NONE] -->
+    <string name="accessibility_status_bar_headphones">Headphones connected</string>
+
+    <!-- Accessibility description of headset icon [CHAR LIMIT=NONE] -->
+    <string name="accessibility_status_bar_headset">Headset connected</string>
+
+    <!-- Explanation of the status bar section of the tuner [CHAR LIMIT=NONE] -->
+    <string name="tuner_status_bar_explanation">Enable or disable icons from being shown in the status bar.</string>
+
+    <!-- Label for quick settings tile for data saver [CHAR LIMIT=30] -->
+    <string name="data_saver">Data Saver</string>
+
+    <!-- Accessibility description for data saver being on [CHAR LIMIT=NONE] -->
+    <string name="accessibility_data_saver_on">Data Saver is on</string>
+
+    <!-- Accessibility description for data saver being off [CHAR LIMIT=NONE] -->
+    <string name="accessibility_data_saver_off">Data Saver is off</string>
+
+    <!-- Label for feature switch [CHAR LIMIT=30] -->
+    <string name="switch_bar_on">On</string>
+
+    <!-- SysUI Tuner: Button that leads to the navigation bar customization screen [CHAR LIMIT=60] -->
+    <string name="nav_bar">Navigation bar</string>
+
+    <!-- SysUI Tuner: Group of buttons that show on the start of the screen [CHAR LIMIT=30] -->
+    <string name="start">Start</string>
+    <!-- SysUI Tuner: Group of buttons that show on the center of the screen [CHAR LIMIT=30] -->
+    <string name="center">Center</string>
+    <!-- SysUI Tuner: Group of buttons that show on the end of the screen [CHAR LIMIT=30] -->
+    <string name="end">End</string>
+    <!-- SysUI Tuner: Name of space used in custom navigation bar layouts [CHAR LIMIT=30] -->
+    <string name="space">Spacer</string>
+    <!-- SysUI Tuner: Name of Combination Menu / Keyboard Switcher button [CHAR LIMIT=30] -->
+    <string name="menu_ime">Menu / Keyboard Switcher</string>
+    <!-- SysUI Tuner: Title for dialog to add a button [CHAR LIMIT=30] -->
+    <string name="select_button">Select button to add</string>
+    <!-- SysUI Tuner: Button to add a button [CHAR LIMIT=30] -->
+    <string name="add_button">Add button</string>
+    <!-- SysUI Tuner: Save the current settings [CHAR LIMIT=30] -->
+    <string name="save">Save</string>
+    <!-- SysUI Tuner: Reset to default settings [CHAR LIMIT=30] -->
+    <string name="reset">Reset</string>
+
+    <!-- SysUI Tuner: Title of no home warning dialog [CHAR LIMIT=30] -->
+    <string name="no_home_title">No home button found</string>
+    <!-- SysUI Tuner: Message of no home warning dialog [CHAR LIMIT=NONE] -->
+    <string name="no_home_message">A home button is required to be able to navigate this device. Please add a home button before saving.</string>
+
+    <!-- SysUI Tuner: Adjust button width dialog title [CHAR LIMIT=60] -->
+    <string name="adjust_button_width">Adjust button width</string>
+
+    <!-- SysUI Tuner: Nav bar button that holds the clipboard [CHAR LIMIT=30] -->
+    <string name="clipboard">Clipboard</string>
+
+    <!-- SysUI Tuner: Description of nav bar button that holds the clipboard [CHAR LIMIT=NONE] -->
+    <string name="clipboard_description">The Clipboard allows items to be dragged directly to the clipboard. Items can also be dragged directly out of the clipboard when present.</string>
+
+    <!-- SysUI Tuner: Accessibility description for custom nav key [CHAR LIMIT=NONE] -->
+    <string name="accessibility_key">Custom navigation button</string>
+
+    <!-- SysUI Tuner: Nav bar button that emulates a keycode [CHAR LIMIT=30] -->
+    <string name="keycode">Keycode</string>
+
+    <!-- SysUI Tuner: Description of nav bar button that emulates a keycode [CHAR LIMIT=NONE] -->
+    <string name="keycode_description">Keycode buttons allow keyboard keys to
+        be added to the Navigation Bar. When pressed they emulate the selected
+        keyboard key. First the key must be selected for the button, followed
+        by an image to be shown on the button.</string>
+
+    <!-- SysUI Tuner: Title of dialog to select which key to emulate [CHAR LIMIT=60] -->
+    <string name="select_keycode">Select Keyboard Button</string>
+
+    <!-- SysUI Tuner: Label for preview area in navigation bar tuner [CHAR LIMIT=NONE] -->
+    <string name="preview">Preview</string>
+
 </resources>
diff --git a/packages/SystemUI/res/values/strings_car.xml b/packages/SystemUI/res/values/strings_car.xml
new file mode 100644
index 0000000..882773a
--- /dev/null
+++ b/packages/SystemUI/res/values/strings_car.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>
+    <string name="car_lockscreen_disclaimer_title">Drive safely</string>
+    <string name="car_lockscreen_disclaimer_text">
+        Stay fully aware of driving conditions and always obey applicable laws. Directions may be
+        inaccurate, incomplete, dangerous, not suitable, prohibited, or involve crossing
+        administrative areas. Business information may also be inaccurate or incomplete. Data is
+        not real-time, and location accuracy cannot be guaranteed. Do not handle your mobile device
+        or use apps not intended for Android Auto while driving.
+    </string>
+
+</resources>
diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
new file mode 100644
index 0000000..c64327d
--- /dev/null
+++ b/packages/SystemUI/res/values/strings_tv.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">
+    <!-- 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>
+</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 47ad6dc..9931ab9 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -20,7 +20,7 @@
         <item name="android:windowAnimationStyle">@style/Animation.RecentsActivity</item>
     </style>
 
-    <style name="RecentsTheme" parent="@android:style/Theme.Material.Light">
+    <style name="RecentsTheme" parent="@android:style/Theme.Material">
         <!-- NoTitle -->
         <item name="android:windowNoTitle">true</item>
         <!-- Misc -->
@@ -237,12 +237,6 @@
         <item name="android:gravity">center</item>
     </style>
 
-    <style name="TextAppearance.Material.Notification.Parenthetical"
-           parent="@*android:style/TextAppearance.Material.Notification">
-        <item name="android:textStyle">italic</item>
-        <item name="android:textColor">#60000000</item>
-    </style>
-
     <style name="TextAppearance.Material.Notification.HeaderTitle"
         parent="@*android:style/TextAppearance.Material.Notification.Info">
     </style>
@@ -305,14 +299,55 @@
 
     <style name="DockedDividerBackground">
         <item name="android:layout_width">match_parent</item>
-        <item name="android:layout_height">12dp</item>
+        <item name="android:layout_height">10dp</item>
         <item name="android:layout_gravity">center_vertical</item>
     </style>
 
     <style name="DockedDividerHandle">
         <item name="android:layout_gravity">center_horizontal</item>
-        <item name="android:layout_width">64dp</item>
+        <item name="android:layout_width">96dp</item>
         <item name="android:layout_height">48dp</item>
     </style>
 
+    <style name="TunerSettings" parent="@android:style/Theme.Material.Settings">
+        <item name="android:windowActionBar">false</item>
+        <item name="preferenceTheme">@style/TunerPreferenceTheme</item>
+    </style>
+
+    <style name="TunerPreferenceTheme" parent="@android:style/Theme.Material.Settings">
+        <item name="@dropdownPreferenceStyle">@style/Preference.DropDown.Material</item>
+    </style>
+
+    <style name="TextAppearance.NotificationGuts">
+        <item name="android:textSize">14sp</item>
+        <item name="android:fontFamily">sans-serif-medium</item>
+        <item name="android:textColor">@android:color/black</item>
+    </style>
+
+    <style name="TextAppearance.NotificationGuts.Header">
+        <item name="android:alpha">.38</item>
+        <item name="android:textSize">12sp</item>
+    </style>
+
+    <style name="TextAppearance.NotificationGuts.Secondary">
+        <item name="android:alpha">.54</item>
+    </style>
+
+    <style name="TextAppearance.NotificationGuts.Primary">
+        <item name="android:alpha">.87</item>
+        <item name="android:textSize">16sp</item>
+    </style>
+
+    <style name="TextAppearance.NotificationGuts.Button">
+        <item name="android:textSize">14sp</item>
+        <item name="android:textAllCaps">true</item>
+        <item name="android:fontFamily">sans-serif-medium</item>
+        <item name="android:gravity">center</item>
+        <item name="android:textColor">@*android:color/material_deep_teal_500</item>
+    </style>
+
+    <style name="ThemeOverlay.SwitchBar" parent="@android:style/ThemeOverlay">
+        <item name="android:colorAccent">@color/switch_accent_color</item>
+    </style>
+
 </resources>
diff --git a/packages/SystemUI/res/values/styles_tv.xml b/packages/SystemUI/res/values/styles_tv.xml
new file mode 100644
index 0000000..3f0caab
--- /dev/null
+++ b/packages/SystemUI/res/values/styles_tv.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.
+ */
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+    <style name="PipTheme" parent="@android:style/Theme.Translucent.NoTitleBar.Fullscreen">
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:backgroundDimEnabled">false</item>
+     </style>
+</resources>
diff --git a/packages/SystemUI/res/values/values_tv.xml b/packages/SystemUI/res/values/values_tv.xml
new file mode 100644
index 0000000..45cdc07
--- /dev/null
+++ b/packages/SystemUI/res/values/values_tv.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 xmlns:android="http://schemas.android.com/apk/res/android">
+    <item format="float" type="raw" name="unselected_scale">1.0</item>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index 43359b3..febe518 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -24,8 +24,29 @@
         sysui:defValue="true" />
 
     <PreferenceScreen
+        android:key="status_bar"
         android:title="@string/status_bar" >
 
+        <Preference
+            android:selectable="false"
+            android:summary="@string/tuner_status_bar_explanation" />
+
+        <com.android.systemui.tuner.StatusBarSwitch
+            android:key="rotate"
+            android:title="@string/status_bar_settings_auto_rotation" />
+
+        <com.android.systemui.tuner.StatusBarSwitch
+            android:key="headset"
+            android:title="@string/headset" />
+
+        <com.android.systemui.tuner.StatusBarSwitch
+            android:key="managed_profile"
+            android:title="@string/status_bar_work" />
+
+        <!-- ime -->
+        <!-- sync_failing -->
+        <!-- sync_active -->
+
         <com.android.systemui.tuner.StatusBarSwitch
             android:key="cast"
             android:title="@string/quick_settings_cast_title" />
@@ -38,17 +59,19 @@
             android:key="bluetooth"
             android:title="@string/quick_settings_bluetooth_label" />
 
+        <!-- nfc -->
+        <!-- tty -->
+        <!-- speakerphone -->
+
         <com.android.systemui.tuner.StatusBarSwitch
             android:key="zen"
             android:title="@string/quick_settings_dnd_label" />
 
-        <com.android.systemui.tuner.StatusBarSwitch
-            android:key="alarm_clock"
-            android:title="@string/status_bar_alarm" />
+        <!-- mute -->
 
         <com.android.systemui.tuner.StatusBarSwitch
-            android:key="managed_profile"
-            android:title="@string/status_bar_work" />
+            android:key="volume"
+            android:title="@*android:string/volume_unknown" />
 
         <com.android.systemui.tuner.StatusBarSwitch
             android:key="wifi"
@@ -66,10 +89,27 @@
             android:key="airplane"
             android:title="@string/status_bar_airplane" />
 
+        <!-- other weird signal stuff -->
+
+        <com.android.systemui.tuner.StatusBarSwitch
+            android:key="battery"
+            android:title="@string/battery" />
+
+        <com.android.systemui.tuner.StatusBarSwitch
+            android:key="alarm_clock"
+            android:title="@string/status_bar_alarm" />
+
+        <!-- secure -->
+
+        <com.android.systemui.tuner.StatusBarSwitch
+            android:key="clock"
+            android:title="@string/clock" />
+
     </PreferenceScreen>
 
 
     <PreferenceScreen
+        android:key="overview"
         android:title="@string/overview" >
 
         <com.android.systemui.tuner.TunerSwitch
@@ -78,7 +118,7 @@
             android:summary="@string/overview_initial_state_paging_desc" />
 
         <com.android.systemui.tuner.TunerSwitch
-            android:key="overview_fast_toggle"
+            android:key="overview_fast_toggle_via_button"
             android:title="@string/overview_fast_toggle_via_button"
             android:summary="@string/overview_fast_toggle_via_button_desc" />
 
@@ -97,7 +137,39 @@
 
     <Preference
         android:key="demo_mode"
-        android:title="@string/demo_mode" />
+        android:title="@string/demo_mode"
+        android:fragment="com.android.systemui.tuner.DemoModeFragment" />
+
+    <Preference
+        android:key="color_transform"
+        android:title="@string/color_transform"
+        android:fragment="com.android.systemui.tuner.ColorMatrixFragment" />
+
+    <PreferenceScreen
+        android:key="volume_and_do_not_disturb"
+        android:title="@string/volume_and_do_not_disturb">
+
+        <com.android.systemui.tuner.TunerSwitch
+            android:key="sysui_show_full_zen"
+            android:title="@string/tuner_full_zen_title"
+            android:summary="@string/tuner_full_zen_summary" />
+
+        <com.android.systemui.tuner.TunerSwitch
+            android:key="sysui_volume_down_silent"
+            android:title="@string/volume_down_silent"
+            sysui:defValue="true" />
+
+        <com.android.systemui.tuner.TunerSwitch
+            android:key="sysui_volume_up_silent"
+            android:title="@string/volume_up_silent"
+            sysui:defValue="true" />
+
+    </PreferenceScreen>
+
+    <Preference
+        android:key="nav_bar"
+        android:title="@string/nav_bar"
+        android:fragment="com.android.systemui.tuner.NavBarTuner" />
 
     <!-- Warning, this goes last. -->
     <Preference
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
index 3eb1271..38ae345 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
@@ -49,7 +49,8 @@
     private float mButtonHeightFraction;
     private float mSubpixelSmoothingLeft;
     private float mSubpixelSmoothingRight;
-    private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint;
+    private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint,
+            mPlusPaint;
     private float mTextHeight, mWarningTextHeight;
     private int mIconTint = Color.WHITE;
 
@@ -60,10 +61,13 @@
     private int mChargeColor;
     private final float[] mBoltPoints;
     private final Path mBoltPath = new Path();
+    private final float[] mPlusPoints;
+    private final Path mPlusPath = new Path();
 
     private final RectF mFrame = new RectF();
     private final RectF mButtonFrame = new RectF();
     private final RectF mBoltFrame = new RectF();
+    private final RectF mPlusFrame = new RectF();
 
     private final Path mShapePath = new Path();
     private final Path mClipPath = new Path();
@@ -141,6 +145,9 @@
         mBoltPaint.setColor(context.getColor(R.color.batterymeter_bolt_color));
         mBoltPoints = loadBoltPoints(res);
 
+        mPlusPaint = new Paint(mBoltPaint);
+        mPlusPoints = loadPlusPoints(res);
+
         mDarkModeBackgroundColor =
                 context.getColor(R.color.dark_mode_icon_color_dual_tone_background);
         mDarkModeFillColor = context.getColor(R.color.dark_mode_icon_color_dual_tone_fill);
@@ -187,8 +194,8 @@
     }
 
     @Override
-    public void onPowerSaveChanged() {
-        mPowerSaveEnabled = mBatteryController.isPowerSave();
+    public void onPowerSaveChanged(boolean isPowerSave) {
+        mPowerSaveEnabled = isPowerSave;
         invalidateSelf();
     }
 
@@ -207,6 +214,21 @@
         return ptsF;
     }
 
+    private static float[] loadPlusPoints(Resources res) {
+        final int[] pts = res.getIntArray(R.array.batterymeter_plus_points);
+        int maxX = 0, maxY = 0;
+        for (int i = 0; i < pts.length; i += 2) {
+            maxX = Math.max(maxX, pts[i]);
+            maxY = Math.max(maxY, pts[i + 1]);
+        }
+        final float[] ptsF = new float[pts.length];
+        for (int i = 0; i < pts.length; i += 2) {
+            ptsF[i] = (float)pts[i] / maxX;
+            ptsF[i + 1] = (float)pts[i + 1] / maxY;
+        }
+        return ptsF;
+    }
+
     @Override
     public void setBounds(int left, int top, int right, int bottom) {
         super.setBounds(left, top, right, bottom);
@@ -328,9 +350,9 @@
 
         if (mPluggedIn) {
             // define the bolt shape
-            final float bl = mFrame.left + mFrame.width() / 4.5f;
+            final float bl = mFrame.left + mFrame.width() / 4f;
             final float bt = mFrame.top + mFrame.height() / 6f;
-            final float br = mFrame.right - mFrame.width() / 7f;
+            final float br = mFrame.right - mFrame.width() / 4f;
             final float bb = mFrame.bottom - mFrame.height() / 10f;
             if (mBoltFrame.left != bl || mBoltFrame.top != bt
                     || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
@@ -358,6 +380,39 @@
                 // otherwise cut the bolt out of the overall shape
                 mShapePath.op(mBoltPath, Path.Op.DIFFERENCE);
             }
+        } else if (mPowerSaveEnabled) {
+            // define the plus shape
+            final float pw = mFrame.width() * 2 / 3;
+            final float pl = mFrame.left + (mFrame.width() - pw) / 2;
+            final float pt = mFrame.top + (mFrame.height() - pw) / 2;
+            final float pr = mFrame.right - (mFrame.width() - pw) / 2;
+            final float pb = mFrame.bottom - (mFrame.height() - pw) / 2;
+            if (mPlusFrame.left != pl || mPlusFrame.top != pt
+                    || mPlusFrame.right != pr || mPlusFrame.bottom != pb) {
+                mPlusFrame.set(pl, pt, pr, pb);
+                mPlusPath.reset();
+                mPlusPath.moveTo(
+                        mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),
+                        mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
+                for (int i = 2; i < mPlusPoints.length; i += 2) {
+                    mPlusPath.lineTo(
+                            mPlusFrame.left + mPlusPoints[i] * mPlusFrame.width(),
+                            mPlusFrame.top + mPlusPoints[i + 1] * mPlusFrame.height());
+                }
+                mPlusPath.lineTo(
+                        mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),
+                        mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
+            }
+
+            float boltPct = (mPlusFrame.bottom - levelTop) / (mPlusFrame.bottom - mPlusFrame.top);
+            boltPct = Math.min(Math.max(boltPct, 0), 1);
+            if (boltPct <= BOLT_LEVEL_THRESHOLD) {
+                // draw the bolt if opaque
+                c.drawPath(mPlusPath, mPlusPaint);
+            } else {
+                // otherwise cut the bolt out of the overall shape
+                mShapePath.op(mPlusPath, Path.Op.DIFFERENCE);
+            }
         }
 
         // compute percentage text
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 6cb8da4..b4f63eb 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -18,13 +18,19 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.os.Handler;
+import android.util.ArraySet;
 import android.util.AttributeSet;
+import android.view.View;
 import android.widget.ImageView;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.tuner.TunerService;
 
-public class BatteryMeterView extends ImageView implements BatteryController.BatteryStateChangeCallback {
+public class BatteryMeterView extends ImageView implements
+        BatteryController.BatteryStateChangeCallback, TunerService.Tunable {
 
     private final BatteryMeterDrawable mDrawable;
+    private final String mSlotBattery;
     private BatteryController mBatteryController;
 
     public BatteryMeterView(Context context) {
@@ -45,6 +51,8 @@
         mDrawable = new BatteryMeterDrawable(context, new Handler(), frameColor);
         atts.recycle();
 
+        mSlotBattery = context.getString(
+                com.android.internal.R.string.status_bar_battery);
         setImageDrawable(mDrawable);
     }
 
@@ -54,10 +62,19 @@
     }
 
     @Override
+    public void onTuningChanged(String key, String newValue) {
+        if (StatusBarIconController.ICON_BLACKLIST.equals(key)) {
+            ArraySet<String> icons = StatusBarIconController.getIconBlacklist(newValue);
+            setVisibility(icons.contains(mSlotBattery) ? View.GONE : View.VISIBLE);
+        }
+    }
+
+    @Override
     public void onAttachedToWindow() {
         super.onAttachedToWindow();
         mBatteryController.addStateChangedCallback(this);
         mDrawable.startListening();
+        TunerService.get(getContext()).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
     }
 
     @Override
@@ -65,6 +82,7 @@
         super.onDetachedFromWindow();
         mBatteryController.removeStateChangedCallback(this);
         mDrawable.stopListening();
+        TunerService.get(getContext()).removeTunable(this);
     }
 
     @Override
@@ -74,7 +92,7 @@
     }
 
     @Override
-    public void onPowerSaveChanged() {
+    public void onPowerSaveChanged(boolean isPowerSave) {
 
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
index 7f6cda0..001d1f2 100644
--- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
@@ -32,7 +32,7 @@
     /**
      * Docks the top-most task and opens recents.
      */
-    void dockTopTask(boolean draggingInRecents, int stackCreateMode, Rect initialBounds);
+    boolean dockTopTask(int dragMode, int stackCreateMode, Rect initialBounds);
 
     /**
      * Called during a drag-from-navbar-in gesture.
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 870e0af..6b74652 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -30,11 +30,9 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
 
 import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.statusbar.Interpolators;
 
 public class SwipeHelper implements Gefingerpoken {
     static final String TAG = "com.android.systemui.SwipeHelper";
@@ -48,9 +46,6 @@
     public static final int X = 0;
     public static final int Y = 1;
 
-    private static LinearInterpolator sLinearInterpolator = new LinearInterpolator();
-    private final Interpolator mFastOutLinearInInterpolator;
-
     private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec
     private int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms
     private int MAX_ESCAPE_ANIMATION_DURATION = 400; // ms
@@ -72,6 +67,7 @@
     private FalsingManager mFalsingManager;
 
     private float mInitialTouchPos;
+    private float mPerpendicularInitialTouchPos;
     private boolean mDragging;
     private View mCurrView;
     private View mCurrAnimView;
@@ -86,6 +82,7 @@
     final private int[] mTmpPos = new int[2];
     private int mFalsingThreshold;
     private boolean mTouchAboveFalsingThreshold;
+    private boolean mDisableHwLayers;
 
     public SwipeHelper(int swipeDirection, Callback callback, Context context) {
         mCallback = callback;
@@ -96,8 +93,6 @@
         mPagingTouchSlop = ViewConfiguration.get(context).getScaledPagingTouchSlop();
 
         mLongPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f); // extra long-press!
-        mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
-                android.R.interpolator.fast_out_linear_in);
         mFalsingThreshold = context.getResources().getDimensionPixelSize(
                 R.dimen.swipe_helper_falsing_threshold);
         mFalsingManager = FalsingManager.getInstance(context);
@@ -115,10 +110,18 @@
         mPagingTouchSlop = pagingTouchSlop;
     }
 
+    public void setDisableHardwareLayers(boolean disableHwLayers) {
+        mDisableHwLayers = disableHwLayers;
+    }
+
     private float getPos(MotionEvent ev) {
         return mSwipeDirection == X ? ev.getX() : ev.getY();
     }
 
+    private float getPerpendicularPos(MotionEvent ev) {
+        return mSwipeDirection == X ? ev.getY() : ev.getX();
+    }
+
     private float getTranslation(View v) {
         return mSwipeDirection == X ? v.getTranslationX() : v.getTranslationY();
     }
@@ -130,7 +133,7 @@
 
     private ObjectAnimator createTranslationAnimation(View v, float newPos) {
         ObjectAnimator anim = ObjectAnimator.ofFloat(v,
-                mSwipeDirection == X ? "translationX" : "translationY", newPos);
+                mSwipeDirection == X ? View.TRANSLATION_X : View.TRANSLATION_Y, newPos);
         return anim;
     }
 
@@ -147,7 +150,7 @@
         }
     }
 
-    private float getSize(View v) {
+    protected float getSize(View v) {
         return mSwipeDirection == X ? v.getMeasuredWidth() :
                 v.getMeasuredHeight();
     }
@@ -178,10 +181,12 @@
         if (!mCallback.updateSwipeProgress(animView, dismissable, swipeProgress)) {
             if (FADE_OUT_DURING_SWIPE && dismissable) {
                 float alpha = swipeProgress;
-                if (alpha != 0f && alpha != 1f) {
-                    animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-                } else {
-                    animView.setLayerType(View.LAYER_TYPE_NONE, null);
+                if (!mDisableHwLayers) {
+                    if (alpha != 0f && alpha != 1f) {
+                        animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+                    } else {
+                        animView.setLayerType(View.LAYER_TYPE_NONE, null);
+                    }
                 }
                 animView.setAlpha(getSwipeProgressForOffset(animView));
             }
@@ -240,6 +245,7 @@
                     mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView);
                     mVelocityTracker.addMovement(ev);
                     mInitialTouchPos = getPos(ev);
+                    mPerpendicularInitialTouchPos = getPerpendicularPos(ev);
 
                     if (mLongPressListener != null) {
                         if (mWatchLongPress == null) {
@@ -271,8 +277,11 @@
                 if (mCurrView != null && !mLongPressSent) {
                     mVelocityTracker.addMovement(ev);
                     float pos = getPos(ev);
+                    float perpendicularPos = getPerpendicularPos(ev);
                     float delta = pos - mInitialTouchPos;
-                    if (Math.abs(delta) > mPagingTouchSlop) {
+                    float deltaPerpendicular = perpendicularPos - mPerpendicularInitialTouchPos;
+                    if (Math.abs(delta) > mPagingTouchSlop
+                            && Math.abs(delta) > Math.abs(deltaPerpendicular)) {
                         mCallback.onBeginDrag(mCurrView);
                         mDragging = true;
                         mInitialTouchPos = getPos(ev) - getTranslation(mCurrAnimView);
@@ -280,7 +289,6 @@
                         removeLongPressCallback();
                     }
                 }
-
                 break;
 
             case MotionEvent.ACTION_UP:
@@ -345,12 +353,14 @@
             duration = fixedDuration;
         }
 
-        animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+        if (!mDisableHwLayers) {
+            animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+        }
         ObjectAnimator anim = createTranslationAnimation(animView, newPos);
         if (useAccelerateInterpolator) {
-            anim.setInterpolator(mFastOutLinearInInterpolator);
+            anim.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
         } else {
-            anim.setInterpolator(sLinearInterpolator);
+            anim.setInterpolator(Interpolators.LINEAR);
         }
         anim.setDuration(duration);
         if (delay > 0) {
@@ -358,11 +368,14 @@
         }
         anim.addListener(new AnimatorListenerAdapter() {
             public void onAnimationEnd(Animator animation) {
+                updateSwipeProgressFromOffset(animView, canAnimViewBeDismissed);
                 mCallback.onChildDismissed(view);
                 if (endAction != null) {
                     endAction.run();
                 }
-                animView.setLayerType(View.LAYER_TYPE_NONE, null);
+                if (!mDisableHwLayers) {
+                    animView.setLayerType(View.LAYER_TYPE_NONE, null);
+                }
             }
         });
         anim.addUpdateListener(new AnimatorUpdateListener() {
@@ -370,9 +383,17 @@
                 updateSwipeProgressFromOffset(animView, canAnimViewBeDismissed);
             }
         });
+        prepareDismissAnimation(animView, anim);
         anim.start();
     }
 
+    /**
+     * Called to update the dismiss animation.
+     */
+    protected void prepareDismissAnimation(View view, Animator anim) {
+        // Do nothing
+    }
+
     public void snapChild(final View view, float velocity) {
         final View animView = mCallback.getChildContentView(view);
         final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(animView);
@@ -390,9 +411,17 @@
                 mCallback.onChildSnappedBack(animView);
             }
         });
+        prepareSnapBackAnimation(animView, anim);
         anim.start();
     }
 
+    /**
+     * Called to update the snap back animation.
+     */
+    protected void prepareSnapBackAnimation(View view, Animator anim) {
+        // Do nothing
+    }
+
     public boolean onTouchEvent(MotionEvent ev) {
         if (mLongPressSent) {
             return true;
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 19e299254..472648a 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -54,6 +54,7 @@
             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
     };
 
     /**
@@ -80,6 +81,8 @@
         // the theme set there.
         setTheme(R.style.systemui_theme);
 
+        SystemUIFactory.createFromConfig(this);
+
         if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
             IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
             filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
new file mode 100644
index 0000000..681b39e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.content.Context;
+import android.util.Log;
+import android.view.ViewGroup;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.statusbar.phone.KeyguardBouncer;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.phone.StatusBarWindowManager;
+
+/**
+ * Class factory to provide customizable SystemUI components.
+ */
+public class SystemUIFactory {
+    private static final String TAG = "SystemUIFactory";
+
+    static SystemUIFactory mFactory;
+
+    public static SystemUIFactory getInstance() {
+        return mFactory;
+    }
+
+    public static void createFromConfig(Context context) {
+        final String clsName = context.getString(R.string.config_systemUIFactoryComponent);
+        if (clsName == null || clsName.length() == 0) {
+            throw new RuntimeException("No SystemUIFactory component configured");
+        }
+
+        try {
+            Class<?> cls = null;
+            cls = context.getClassLoader().loadClass(clsName);
+            mFactory = (SystemUIFactory) cls.newInstance();
+        } catch (Throwable t) {
+            Log.w(TAG, "Error creating SystemUIFactory component: " + clsName, t);
+            throw new RuntimeException(t);
+        }
+    }
+
+    public SystemUIFactory() {}
+
+    public StatusBarKeyguardViewManager createStatusBarKeyguardViewManager(Context context,
+            ViewMediatorCallback viewMediatorCallback, LockPatternUtils lockPatternUtils) {
+        return new StatusBarKeyguardViewManager(context, viewMediatorCallback, lockPatternUtils);
+    }
+
+    public KeyguardBouncer createKeyguardBouncer(Context context, ViewMediatorCallback callback,
+            LockPatternUtils lockPatternUtils, StatusBarWindowManager windowManager,
+            ViewGroup container) {
+        return new KeyguardBouncer(context, callback, lockPatternUtils, windowManager, container);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java b/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
index c9ba885..25f8bb0 100644
--- a/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
@@ -24,8 +24,8 @@
 import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Paint;
 import android.view.View;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
+
+import com.android.systemui.statusbar.Interpolators;
 
 import java.util.ArrayList;
 
@@ -35,7 +35,6 @@
 public class ViewInvertHelper {
 
     private final Paint mDarkPaint = new Paint();
-    private final Interpolator mLinearOutSlowInInterpolator;
     private final ColorMatrix mMatrix = new ColorMatrix();
     private final ColorMatrix mGrayscaleMatrix = new ColorMatrix();
     private final long mFadeDuration;
@@ -46,8 +45,6 @@
         addTarget(v);
     }
     public ViewInvertHelper(Context context, long fadeDuration) {
-        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
-                android.R.interpolator.linear_out_slow_in);
         mFadeDuration = fadeDuration;
     }
 
@@ -89,7 +86,7 @@
             }
         });
         animator.setDuration(mFadeDuration);
-        animator.setInterpolator(mLinearOutSlowInInterpolator);
+        animator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
         animator.setStartDelay(delay);
         animator.start();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
index c3a8f2e..92cd027 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.assist;
 
-import com.android.systemui.R;
-
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
@@ -35,6 +33,9 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AnimationUtils;
 
+import com.android.systemui.R;
+import com.android.systemui.statusbar.Interpolators;
+
 /**
  * Visually discloses that contextual data was provided to an assistant.
  */
@@ -120,13 +121,11 @@
                     R.interpolator.assist_disclosure_trace));
             mAlphaInAnimator = ValueAnimator.ofInt(0, 255).setDuration(ALPHA_IN_ANIMATION_DURATION);
             mAlphaInAnimator.addUpdateListener(this);
-            mAlphaInAnimator.setInterpolator(AnimationUtils.loadInterpolator(mContext,
-                    android.R.interpolator.fast_out_slow_in));
+            mAlphaInAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
             mAlphaOutAnimator = ValueAnimator.ofInt(255, 0).setDuration(
                     ALPHA_OUT_ANIMATION_DURATION);
             mAlphaOutAnimator.addUpdateListener(this);
-            mAlphaOutAnimator.setInterpolator(AnimationUtils.loadInterpolator(mContext,
-                    android.R.interpolator.fast_out_linear_in));
+            mAlphaOutAnimator.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
             mAnimator = new AnimatorSet();
             mAnimator.play(mAlphaInAnimator).with(mTracingAnimator);
             mAnimator.play(mAlphaInAnimator).before(mAlphaOutAnimator);
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java
index 67017db..34770c4 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java
@@ -20,19 +20,15 @@
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.View;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 
 import com.android.systemui.R;
+import com.android.systemui.statusbar.Interpolators;
 
 public class AssistOrbContainer extends FrameLayout {
 
     private static final long EXIT_START_DELAY = 150;
 
-    private final Interpolator mLinearOutSlowInInterpolator;
-    private final Interpolator mFastOutLinearInInterpolator;
-
     private View mScrim;
     private View mNavbarScrim;
     private AssistOrbView mOrb;
@@ -49,10 +45,6 @@
 
     public AssistOrbContainer(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
-                android.R.interpolator.linear_out_slow_in);
-        mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
-                android.R.interpolator.fast_out_slow_in);
     }
 
     @Override
@@ -109,12 +101,12 @@
                         .alpha(1f)
                         .setDuration(300)
                         .setStartDelay(0)
-                        .setInterpolator(mLinearOutSlowInInterpolator);
+                        .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
                 mNavbarScrim.animate()
                         .alpha(1f)
                         .setDuration(300)
                         .setStartDelay(0)
-                        .setInterpolator(mLinearOutSlowInInterpolator);
+                        .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
             }
         });
     }
@@ -132,12 +124,12 @@
                 .alpha(0f)
                 .setDuration(250)
                 .setStartDelay(EXIT_START_DELAY)
-                .setInterpolator(mFastOutLinearInInterpolator);
+                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
         mNavbarScrim.animate()
                 .alpha(0f)
                 .setDuration(250)
                 .setStartDelay(EXIT_START_DELAY)
-                .setInterpolator(mFastOutLinearInInterpolator)
+                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
                 .withEndAction(endRunnable);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbView.java b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbView.java
index a3372a8..2d933f6 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbView.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbView.java
@@ -27,13 +27,13 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewOutlineProvider;
-import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.view.animation.OvershootInterpolator;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 
 import com.android.systemui.R;
+import com.android.systemui.statusbar.Interpolators;
 
 public class AssistOrbView extends FrameLayout {
 
@@ -43,8 +43,6 @@
     private final Paint mBackgroundPaint = new Paint();
     private final Rect mCircleRect = new Rect();
     private final Rect mStaticRect = new Rect();
-    private final Interpolator mAppearInterpolator;
-    private final Interpolator mDisappearInterpolator;
     private final Interpolator mOvershootInterpolator = new OvershootInterpolator();
 
     private boolean mClipToOutline;
@@ -117,10 +115,6 @@
                 R.dimen.assist_orb_travel_distance);
         mMaxElevation = context.getResources().getDimensionPixelSize(
                 R.dimen.assist_orb_elevation);
-        mAppearInterpolator = AnimationUtils.loadInterpolator(mContext,
-                android.R.interpolator.linear_out_slow_in);
-        mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext,
-                android.R.interpolator.fast_out_linear_in);
         mBackgroundPaint.setAntiAlias(true);
         mBackgroundPaint.setColor(getResources().getColor(R.color.assist_orb_color));
     }
@@ -256,8 +250,8 @@
     }
 
     public void startExitAnimation(long delay) {
-        animateCircleSize(0, 200, delay, mDisappearInterpolator);
-        animateOffset(0, 200, delay, mDisappearInterpolator);
+        animateCircleSize(0, 200, delay, Interpolators.FAST_OUT_LINEAR_IN);
+        animateOffset(0, 200, delay, Interpolators.FAST_OUT_LINEAR_IN);
     }
 
     public void startEnterAnimation() {
@@ -266,7 +260,7 @@
             @Override
             public void run() {
                 animateCircleSize(mCircleMinSize, 300, 0 /* delay */, mOvershootInterpolator);
-                animateOffset(mStaticOffset, 400, 0 /* delay */, mAppearInterpolator);
+                animateOffset(mStaticOffset, 400, 0 /* delay */, Interpolators.LINEAR_OUT_SLOW_IN);
             }
         });
     }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
index 27d4c0e..c7e5ea4 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
@@ -35,6 +35,10 @@
 public class HumanInteractionClassifier extends Classifier {
     private static final String HIC_ENABLE = "HIC_enable";
     private static final float FINGER_DISTANCE = 0.1f;
+
+    /** Default value for the HIC_ENABLE setting: 1 - enabled, 0 - disabled */
+    private static final int HIC_ENABLE_DEFAULT = 1;
+
     private static HumanInteractionClassifier sInstance = null;
 
     private final Handler mHandler = new Handler();
@@ -101,9 +105,9 @@
     }
 
     private void updateConfiguration() {
-        mEnableClassifier = Build.IS_DEBUGGABLE && 0 != Settings.Global.getInt(
+        mEnableClassifier = 0 != Settings.Global.getInt(
                 mContext.getContentResolver(),
-                HIC_ENABLE, 0);
+                HIC_ENABLE, HIC_ENABLE_DEFAULT);
     }
 
     public void setType(int type) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
index d931856..481b9180 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
@@ -70,17 +70,19 @@
     // time for us to receive the signal that it's starting.
     private static final long BLUETOOTH_START_DELAY_MILLIS = 10 * 1000;
 
+    // We will be scanning up to 30 seconds, after which we'll stop.
+    private static final long BLUETOOTH_SCAN_TIMEOUT_MILLIS = 30 * 1000;
+
     private static final int STATE_NOT_ENABLED = -1;
     private static final int STATE_UNKNOWN = 0;
     private static final int STATE_WAITING_FOR_BOOT_COMPLETED = 1;
     private static final int STATE_WAITING_FOR_TABLET_MODE_EXIT = 2;
     private static final int STATE_WAITING_FOR_DEVICE_DISCOVERY = 3;
     private static final int STATE_WAITING_FOR_BLUETOOTH = 4;
-    private static final int STATE_WAITING_FOR_STATE_PAIRED = 5;
-    private static final int STATE_PAIRING = 6;
-    private static final int STATE_PAIRED = 7;
-    private static final int STATE_USER_CANCELLED = 8;
-    private static final int STATE_DEVICE_NOT_FOUND = 9;
+    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 MSG_INIT = 0;
     private static final int MSG_ON_BOOT_COMPLETED = 1;
@@ -92,6 +94,7 @@
     private static final int MSG_ON_BLE_SCAN_FAILED = 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 volatile KeyboardHandler mHandler;
     private volatile KeyboardUIHandler mUIHandler;
@@ -107,6 +110,7 @@
     private long mBootCompletedTime;
 
     private int mInTabletMode = InputManager.SWITCH_STATE_UNKNOWN;
+    private int mScanAttempt = 0;
     private ScanCallback mScanCallback;
     private BluetoothDialog mDialog;
 
@@ -328,6 +332,9 @@
             .build();
         mScanCallback = new KeyboardScanCallback();
         scanner.startScan(Arrays.asList(filter), settings, mScanCallback);
+
+        Message abortMsg = mHandler.obtainMessage(MSG_BLE_ABORT_SCAN, ++mScanAttempt, 0);
+        mHandler.sendMessageDelayed(abortMsg, BLUETOOTH_SCAN_TIMEOUT_MILLIS);
     }
 
     private void stopScanning() {
@@ -338,6 +345,19 @@
     }
 
     // Should only be called on the handler thread
+    private void bleAbortScanInternal(int scanAttempt) {
+        if (mState == STATE_WAITING_FOR_DEVICE_DISCOVERY && scanAttempt == mScanAttempt) {
+            if (DEBUG) {
+                Slog.d(TAG, "Bluetooth scan timed out");
+            }
+            stopScanning();
+            // FIXME: should we also try shutting off bluetooth if we enabled
+            // it in the first place?
+            mState = STATE_DEVICE_NOT_FOUND;
+        }
+    }
+
+    // Should only be called on the handler thread
     private void onDeviceAddedInternal(CachedBluetoothDevice d) {
         if (mState == STATE_WAITING_FOR_DEVICE_DISCOVERY && d.getName().equals(mKeyboardName)) {
             stopScanning();
@@ -425,6 +445,12 @@
                     } else {
                         mState = STATE_USER_CANCELLED;
                     }
+                    break;
+                }
+                case MSG_BLE_ABORT_SCAN: {
+                    int scanAttempt = msg.arg1;
+                    bleAbortScanInternal(scanAttempt);
+                    break;
                 }
                 case MSG_ON_BLUETOOTH_STATE_CHANGED: {
                     int bluetoothState = msg.arg1;
@@ -555,8 +581,6 @@
                 return "STATE_WAITING_FOR_DEVICE_DISCOVERY";
             case STATE_WAITING_FOR_BLUETOOTH:
                 return "STATE_WAITING_FOR_BLUETOOTH";
-            case STATE_WAITING_FOR_STATE_PAIRED:
-                return "STATE_WAITING_FOR_STATE_PAIRED";
             case STATE_PAIRING:
                 return "STATE_PAIRING";
             case STATE_PAIRED:
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 443778e..958572f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -69,6 +69,7 @@
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.SystemUI;
+import com.android.systemui.SystemUIFactory;
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.statusbar.phone.FingerprintUnlockController;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
@@ -82,6 +83,10 @@
 import java.util.List;
 
 import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
 
 /**
  * Mediates requests related to the keyguard.  This includes queries about the
@@ -474,10 +479,12 @@
 
     ViewMediatorCallback mViewMediatorCallback = new ViewMediatorCallback() {
 
+        @Override
         public void userActivity() {
             KeyguardViewMediator.this.userActivity();
         }
 
+        @Override
         public void keyguardDone(boolean strongAuth) {
             if (!mKeyguardDonePending) {
                 KeyguardViewMediator.this.keyguardDone(true /* authenticated */);
@@ -487,6 +494,7 @@
             }
         }
 
+        @Override
         public void keyguardDoneDrawing() {
             mHandler.sendEmptyMessage(KEYGUARD_DONE_DRAWING);
         }
@@ -545,14 +553,28 @@
         @Override
         public int getBouncerPromptReason() {
             int currentUser = ActivityManager.getCurrentUser();
-            if ((mUpdateMonitor.getUserTrustIsManaged(currentUser)
-                    || mUpdateMonitor.isUnlockWithFingerprintPossible(currentUser))
-                    && !mUpdateMonitor.getStrongAuthTracker().hasUserAuthenticatedSinceBoot()) {
+            boolean trust = mTrustManager.isTrustUsuallyManaged(currentUser);
+            boolean fingerprint = mUpdateMonitor.isUnlockWithFingerprintPossible(currentUser);
+            boolean any = trust || fingerprint;
+            KeyguardUpdateMonitor.StrongAuthTracker strongAuthTracker =
+                    mUpdateMonitor.getStrongAuthTracker();
+            int strongAuth = strongAuthTracker.getStrongAuthForUser(currentUser);
+
+            if (any && !strongAuthTracker.hasUserAuthenticatedSinceBoot()) {
                 return KeyguardSecurityView.PROMPT_REASON_RESTART;
-            } else if (mUpdateMonitor.isUnlockWithFingerprintPossible(currentUser)
-                    && mUpdateMonitor.hasFingerprintUnlockTimedOut(currentUser)) {
+            } else if (fingerprint && mUpdateMonitor.hasFingerprintUnlockTimedOut(currentUser)) {
                 return KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
+            } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW) != 0) {
+                return KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
+            } else if (trust && (strongAuth & SOME_AUTH_REQUIRED_AFTER_USER_REQUEST) != 0) {
+                return KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
+            } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_LOCKOUT) != 0) {
+                return KeyguardSecurityView.PROMPT_REASON_AFTER_LOCKOUT;
+            } else if (trust && (strongAuth & SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL) != 0) {
+                return KeyguardSecurityView.PROMPT_REASON_WRONG_CREDENTIAL;
             }
+
+
             return KeyguardSecurityView.PROMPT_REASON_NONE;
         }
     };
@@ -588,8 +610,9 @@
         updateInputRestrictedLocked();
         mTrustManager.reportKeyguardShowingChanged();
 
-        mStatusBarKeyguardViewManager = new StatusBarKeyguardViewManager(mContext,
-                mViewMediatorCallback, mLockPatternUtils);
+        mStatusBarKeyguardViewManager =
+                SystemUIFactory.getInstance().createStatusBarKeyguardViewManager(mContext,
+                        mViewMediatorCallback, mLockPatternUtils);
         final ContentResolver cr = mContext.getContentResolver();
 
         mDeviceInteractive = mPM.isInteractive();
@@ -741,8 +764,7 @@
 
         long timeout;
 
-        UserInfo user = UserManager.get(mContext).getUserInfo(userId);
-        if ((!user.isManagedProfile() && LockPatternUtils.isSeparateWorkChallengeEnabled())
+        if ((mLockPatternUtils.isSeparateProfileChallengeEnabled(userId))
                 || policyTimeout <= 0) {
             timeout = lockAfterTimeout;
         } else {
@@ -782,9 +804,9 @@
     private void doKeyguardLaterLockedForChildProfiles() {
         UserManager um = UserManager.get(mContext);
         List<UserInfo> profiles = um.getEnabledProfiles(UserHandle.myUserId());
-        if (LockPatternUtils.isSeparateWorkChallengeEnabled() && profiles.size() > 1) {
+        if (profiles.size() > 1) {
             for (UserInfo info : profiles) {
-                if (info.id != UserHandle.myUserId() && info.isManagedProfile()) {
+                if (mLockPatternUtils.isSeparateProfileChallengeEnabled(info.id)) {
                     long userTimeout = getLockTimeout(info.id);
                     long userWhen = SystemClock.elapsedRealtime() + userTimeout;
                     Intent lockIntent = new Intent(DELAYED_LOCK_PROFILE_ACTION);
@@ -1248,7 +1270,9 @@
                 if (DEBUG) Log.d(TAG, "received DELAYED_KEYGUARD_ACTION with seq = "
                         + sequence + ", mDelayedShowingSequence = " + mDelayedShowingSequence);
                 synchronized (KeyguardViewMediator.this) {
-                    doKeyguardLocked(null);
+                    if (mDelayedShowingSequence == sequence) {
+                        doKeyguardLocked(null);
+                    }
                 }
             } else if (DELAYED_LOCK_PROFILE_ACTION.equals(intent.getAction())) {
                 int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, 0);
@@ -1346,6 +1370,9 @@
      * @see #KEYGUARD_DONE
      */
     private void handleKeyguardDone(boolean authenticated) {
+        if (mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
+            mLockPatternUtils.getDevicePolicyManager().reportKeyguardDismissed();
+        }
         if (DEBUG) Log.d(TAG, "handleKeyguardDone");
         synchronized (this) {
             resetKeyguardDonePendingLocked();
@@ -1457,6 +1484,9 @@
      * @see #SHOW
      */
     private void handleShow(Bundle options) {
+        if (mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
+            mLockPatternUtils.getDevicePolicyManager().reportKeyguardSecured();
+        }
         synchronized (KeyguardViewMediator.this) {
             if (!mSystemReady) {
                 if (DEBUG) Log.d(TAG, "ignoring handleShow because system is not ready.");
@@ -1698,6 +1728,7 @@
         mHandler.removeMessages(KEYGUARD_DONE_PENDING_TIMEOUT);
     }
 
+    @Override
     public void onBootCompleted() {
         mUpdateMonitor.dispatchBootCompleted();
         synchronized (this) {
@@ -1731,10 +1762,15 @@
     public void onActivityDrawn() {
         mHandler.sendEmptyMessage(ON_ACTIVITY_DRAWN);
     }
+
     public ViewMediatorCallback getViewMediatorCallback() {
         return mViewMediatorCallback;
     }
 
+    public LockPatternUtils getLockPatternUtils() {
+        return mLockPatternUtils;
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.print("  mSystemReady: "); pw.println(mSystemReady);
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 19b65f7..ea1c9bf 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -52,7 +52,6 @@
 
     private static final int SHOWING_NOTHING = 0;
     private static final int SHOWING_WARNING = 1;
-    private static final int SHOWING_SAVER = 2;
     private static final int SHOWING_INVALID_CHARGER = 3;
     private static final String[] SHOWING_STRINGS = {
         "SHOWING_NOTHING",
@@ -63,7 +62,6 @@
 
     private static final String ACTION_SHOW_BATTERY_SETTINGS = "PNW.batterySettings";
     private static final String ACTION_START_SAVER = "PNW.startSaver";
-    private static final String ACTION_STOP_SAVER = "PNW.stopSaver";
     private static final String ACTION_DISMISSED_WARNING = "PNW.dismissedWarning";
 
     private static final AudioAttributes AUDIO_ATTRIBUTES = new AudioAttributes.Builder()
@@ -77,7 +75,6 @@
     private final Handler mHandler = new Handler();
     private final Receiver mReceiver = new Receiver();
     private final Intent mOpenBatterySettings = settings(Intent.ACTION_POWER_USAGE_SUMMARY);
-    private final Intent mOpenSaverSettings = settings(Settings.ACTION_BATTERY_SAVER_SETTINGS);
 
     private int mBatteryLevel;
     private int mBucket;
@@ -86,7 +83,6 @@
 
     private long mBucketDroppedNegativeTimeMs;
 
-    private boolean mSaver;
     private boolean mWarning;
     private boolean mPlaySound;
     private boolean mInvalidCharger;
@@ -101,7 +97,6 @@
 
     @Override
     public void dump(PrintWriter pw) {
-        pw.print("mSaver="); pw.println(mSaver);
         pw.print("mWarning="); pw.println(mWarning);
         pw.print("mPlaySound="); pw.println(mPlaySound);
         pw.print("mInvalidCharger="); pw.println(mInvalidCharger);
@@ -121,27 +116,15 @@
         mScreenOffTime = screenOffTime;
     }
 
-    @Override
-    public void showSaverMode(boolean mode) {
-        mSaver = mode;
-        if (mSaver && mSaverConfirmation != null) {
-            mSaverConfirmation.dismiss();
-        }
-        updateNotification();
-    }
-
     private void updateNotification() {
         if (DEBUG) Slog.d(TAG, "updateNotification mWarning=" + mWarning + " mPlaySound="
-                + mPlaySound + " mSaver=" + mSaver + " mInvalidCharger=" + mInvalidCharger);
+                + mPlaySound + " mInvalidCharger=" + mInvalidCharger);
         if (mInvalidCharger) {
             showInvalidChargerNotification();
             mShowing = SHOWING_INVALID_CHARGER;
         } else if (mWarning) {
             showWarningNotification();
             mShowing = SHOWING_WARNING;
-        } else if (mSaver) {
-            showSaverNotification();
-            mShowing = SHOWING_SAVER;
         } else {
             mNoMan.cancelAsUser(TAG_NOTIFICATION, R.id.notification_power, UserHandle.ALL);
             mShowing = SHOWING_NOTHING;
@@ -165,8 +148,7 @@
     }
 
     private void showWarningNotification() {
-        final int textRes = mSaver ? R.string.battery_low_percent_format_saver_started
-                : R.string.battery_low_percent_format;
+        final int textRes = R.string.battery_low_percent_format;
         final String percentage = NumberFormat.getPercentInstance().format((double) mBatteryLevel / 100.0);
         final Notification.Builder nb = new Notification.Builder(mContext)
                 .setSmallIcon(R.drawable.ic_power_low)
@@ -184,13 +166,9 @@
         if (hasBatterySettings()) {
             nb.setContentIntent(pendingBroadcast(ACTION_SHOW_BATTERY_SETTINGS));
         }
-        if (!mSaver) {
-            nb.addAction(0,
-                    mContext.getString(R.string.battery_saver_start_action),
-                    pendingBroadcast(ACTION_START_SAVER));
-        } else {
-            addStopSaverAction(nb);
-        }
+        nb.addAction(0,
+                mContext.getString(R.string.battery_saver_start_action),
+                pendingBroadcast(ACTION_START_SAVER));
         if (mPlaySound) {
             attachLowBatterySound(nb);
             mPlaySound = false;
@@ -199,35 +177,6 @@
         mNoMan.notifyAsUser(TAG_NOTIFICATION, R.id.notification_power, n, UserHandle.ALL);
     }
 
-    private void showSaverNotification() {
-        final Notification.Builder nb = new Notification.Builder(mContext)
-                .setSmallIcon(R.drawable.ic_power_saver)
-                .setContentTitle(mContext.getString(R.string.battery_saver_notification_title))
-                .setContentText(mContext.getString(R.string.battery_saver_notification_text))
-                .setOngoing(true)
-                .setShowWhen(false)
-                .setVisibility(Notification.VISIBILITY_PUBLIC)
-                .setColor(mContext.getColor(
-                        com.android.internal.R.color.battery_saver_mode_color));
-        addStopSaverAction(nb);
-        if (hasSaverSettings()) {
-            nb.setContentIntent(pendingActivity(mOpenSaverSettings));
-        }
-        mNoMan.notifyAsUser(TAG_NOTIFICATION, R.id.notification_power, nb.build(), UserHandle.ALL);
-    }
-
-    private void addStopSaverAction(Notification.Builder nb) {
-        nb.addAction(0,
-                mContext.getString(R.string.battery_saver_notification_action_text),
-                pendingBroadcast(ACTION_STOP_SAVER));
-    }
-
-    private void dismissSaverNotification() {
-        if (mSaver) Slog.i(TAG, "dismissing saver notification");
-        mSaver = false;
-        updateNotification();
-    }
-
     private PendingIntent pendingActivity(Intent intent) {
         return PendingIntent.getActivityAsUser(mContext,
                 0, intent, 0, null, UserHandle.CURRENT);
@@ -272,10 +221,6 @@
         return mOpenBatterySettings.resolveActivity(mContext.getPackageManager()) != null;
     }
 
-    private boolean hasSaverSettings() {
-        return mOpenSaverSettings.resolveActivity(mContext.getPackageManager()) != null;
-    }
-
     @Override
     public void showLowBatteryWarning(boolean playSound) {
         Slog.i(TAG,
@@ -367,7 +312,6 @@
             IntentFilter filter = new IntentFilter();
             filter.addAction(ACTION_SHOW_BATTERY_SETTINGS);
             filter.addAction(ACTION_START_SAVER);
-            filter.addAction(ACTION_STOP_SAVER);
             filter.addAction(ACTION_DISMISSED_WARNING);
             mContext.registerReceiverAsUser(this, UserHandle.ALL, filter,
                     android.Manifest.permission.STATUS_BAR_SERVICE, mHandler);
@@ -383,10 +327,6 @@
             } else if (action.equals(ACTION_START_SAVER)) {
                 dismissLowBatteryNotification();
                 showStartSaverConfirmation();
-            } else if (action.equals(ACTION_STOP_SAVER)) {
-                dismissSaverNotification();
-                dismissLowBatteryNotification();
-                setSaverMode(false);
             } else if (action.equals(ACTION_DISMISSED_WARNING)) {
                 dismissLowBatteryWarning();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 9459740..522d533 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -76,10 +76,6 @@
         mReceiver.init();
     }
 
-    private void setSaverMode(boolean mode) {
-        mWarnings.showSaverMode(mode);
-    }
-
     void updateBatteryWarningLevels() {
         int critLevel = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_criticalBatteryWarningLevel);
@@ -141,11 +137,6 @@
             filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING);
             filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
             mContext.registerReceiver(this, filter, null, mHandler);
-            updateSaverMode();
-        }
-
-        private void updateSaverMode() {
-            setSaverMode(mPowerManager.isPowerSaveMode());
         }
 
         @Override
@@ -210,10 +201,6 @@
                 mScreenOffTime = -1;
             } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                 mWarnings.userSwitched();
-            } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
-                updateSaverMode();
-            } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGING.equals(action)) {
-                setSaverMode(intent.getBooleanExtra(PowerManager.EXTRA_POWER_SAVE_MODE, false));
             } else {
                 Slog.w(TAG, "unknown intent: " + intent);
             }
@@ -251,7 +238,6 @@
 
     public interface WarningsUI {
         void update(int batteryLevel, int bucket, long screenOffTime);
-        void showSaverMode(boolean mode);
         void dismissLowBatteryWarning();
         void showLowBatteryWarning(boolean playSound);
         void dismissInvalidChargerWarning();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index ca4a03a..6bc8b50 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -6,8 +6,6 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.LinearLayout;
-
 import com.android.internal.widget.PagerAdapter;
 import com.android.internal.widget.ViewPager;
 import com.android.systemui.R;
@@ -25,7 +23,6 @@
     private final ArrayList<TileRecord> mTiles = new ArrayList<TileRecord>();
     private final ArrayList<TilePage> mPages = new ArrayList<TilePage>();
 
-    private FirstPage mFirstPage;
     private PageIndicator mPageIndicator;
 
     private int mNumPages;
@@ -59,38 +56,38 @@
         mPageIndicator = (PageIndicator) findViewById(R.id.page_indicator);
         ((LayoutParams) mPageIndicator.getLayoutParams()).isDecor = true;
 
-        mFirstPage = (FirstPage) findViewById(R.id.first_page);
-        removeView(mFirstPage); // We don't actually want this on the view yet, just inflated.
-        mPages.add(mFirstPage.mTilePage);
+        mPages.add((TilePage) LayoutInflater.from(mContext)
+                .inflate(R.layout.qs_paged_page, this, false));
     }
 
     @Override
     public int getOffsetTop(TileRecord tile) {
-        if (tile.tileView.getParent() == mFirstPage.mTilePage) {
-            return mFirstPage.getTop() + mFirstPage.mTilePage.getTop();
-        }
-        return ((ViewGroup) tile.tileView.getParent()).getTop();
+        return ((ViewGroup) tile.tileView.getParent()).getTop() + getTop();
     }
 
     @Override
     public void addTile(TileRecord tile) {
         mTiles.add(tile);
-        distributeTiles();
+        postDistributeTiles();
     }
 
     @Override
     public void removeTile(TileRecord tile) {
         if (mTiles.remove(tile)) {
-            distributeTiles();
+            postDistributeTiles();
         }
     }
 
+    private void postDistributeTiles() {
+        removeCallbacks(mDistribute);
+        post(mDistribute);
+    }
+
     private void distributeTiles() {
         if (DEBUG) Log.d(TAG, "Distributing tiles");
-        mFirstPage.mQuickQuickTiles.removeAllViews();
         final int NP = mPages.size();
         for (int i = 0; i < NP; i++) {
-            mPages.get(i).clear();
+            mPages.get(i).removeAllViews();
         }
         int index = 0;
         final int NT = mTiles.size();
@@ -115,10 +112,15 @@
     }
 
     @Override
-    public void updateResources() {
+    public boolean updateResources() {
+        boolean changed = false;
         for (int i = 0; i < mPages.size(); i++) {
-            mPages.get(i).updateResources();
+            changed |= mPages.get(i).updateResources();
         }
+        if (changed) {
+            distributeTiles();
+        }
+        return changed;
     }
 
     @Override
@@ -137,32 +139,12 @@
         setMeasuredDimension(getMeasuredWidth(), maxHeight + mPageIndicator.getMeasuredHeight());
     }
 
-    public static class FirstPage extends LinearLayout {
-        private LinearLayout mQuickQuickTiles;
-        private TilePage mTilePage;
-
-        public FirstPage(Context context, AttributeSet attrs) {
-            super(context, attrs);
-        }
-
+    private final Runnable mDistribute = new Runnable() {
         @Override
-        protected void onFinishInflate() {
-            super.onFinishInflate();
-            mQuickQuickTiles = (LinearLayout) findViewById(R.id.quick_tile_layout);
-            mQuickQuickTiles.setVisibility(View.GONE);
-            mTilePage = (TilePage) findViewById(R.id.tile_page);
-            // Less rows on first page, because it needs room for the quick tiles.
-            mTilePage.mMaxRows = 3;
+        public void run() {
+            distributeTiles();
         }
-
-        @Override
-        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-            // The ViewPager will try to make us taller, don't do it unless we need to.
-            heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec),
-                    MeasureSpec.AT_MOST);
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        }
-    }
+    };
 
     public static class TilePage extends TileLayout {
         private int mMaxRows = 3;
@@ -172,21 +154,19 @@
             updateResources();
         }
 
+        @Override
+        public boolean updateResources() {
+            if (super.updateResources()) {
+                mMaxRows = mColumns != 3 ? 2 : 3;
+                return true;
+            }
+            return false;
+        }
+
         public void setMaxRows(int maxRows) {
             mMaxRows = maxRows;
         }
 
-        @Override
-        protected int getCellHeight() {
-            return mContext.getResources().getDimensionPixelSize(R.dimen.qs_new_tile_height);
-        }
-
-        private void clear() {
-            if (DEBUG) Log.d(TAG, "Clearing page");
-            removeAllViews();
-            mRecords.clear();
-        }
-
         public boolean isFull() {
             return mRecords.size() >= mColumns * mMaxRows;
         }
@@ -201,7 +181,7 @@
 
         public Object instantiateItem(ViewGroup container, int position) {
             if (DEBUG) Log.d(TAG, "Instantiating " + position);
-            ViewGroup view = position == 0 ? mFirstPage : mPages.get(position);
+            ViewGroup view = mPages.get(position);
             container.addView(view);
             return view;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
index b56ad76..7651ae8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
@@ -75,12 +75,17 @@
             iv.setTag(R.id.qs_icon_tag, state.icon);
             if (d instanceof Animatable) {
                 Animatable a = (Animatable) d;
-                if (state.icon instanceof QSTile.AnimationIcon && !iv.isShown()) {
+                a.start();
+                if (!iv.isShown()) {
                     a.stop(); // skip directly to end state
                 }
             }
         }
-
+        if (state.disabledByPolicy) {
+            iv.setColorFilter(getContext().getColor(R.color.qs_tile_disabled_color));
+        } else {
+            iv.clearColorFilter();
+        }
     }
 
     protected int getIconMeasureMode() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 16fd9eb..8979023 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -34,7 +34,9 @@
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
+
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile.DetailAdapter;
@@ -245,7 +247,7 @@
     public void setExpanded(boolean expanded) {
         if (mExpanded == expanded) return;
         mExpanded = expanded;
-        MetricsLogger.visibility(mContext, MetricsLogger.QS_PANEL, mExpanded);
+        MetricsLogger.visibility(mContext, MetricsEvent.QS_PANEL, mExpanded);
         if (!mExpanded) {
             closeDetail();
         } else {
@@ -329,16 +331,19 @@
                     drawTile(r, state);
                 }
             }
+
             @Override
             public void onShowDetail(boolean show) {
                 QSPanel.this.showDetail(show, r);
             }
+
             @Override
             public void onToggleStateChanged(boolean state) {
                 if (mDetailRecord == r) {
                     fireToggleStateChanged(state);
                 }
             }
+
             @Override
             public void onScanStateChanged(boolean state) {
                 r.scanState = state;
@@ -352,7 +357,7 @@
                 announceForAccessibility(announcement);
             }
         };
-        r.tile.setCallback(callback);
+        r.tile.addCallback(callback);
         final View.OnClickListener click = new View.OnClickListener() {
             @Override
             public void onClick(View v) {
@@ -415,6 +420,9 @@
     }
 
     protected void handleShowDetail(Record r, boolean show) {
+        if (show && !mExpanded) {
+            mHost.animateExpandQS();
+        }
         if (r instanceof TileRecord) {
             handleShowDetailTile((TileRecord) r, show);
         } else {
@@ -466,7 +474,7 @@
             MetricsLogger.visible(mContext, detailAdapter.getMetricsCategory());
             announceForAccessibility(mContext.getString(
                     R.string.accessibility_quick_settings_detail,
-                    mContext.getString(detailAdapter.getTitle())));
+                    detailAdapter.getTitle()));
             setDetailRecord(r);
             listener = mHideGridContentWhenDone;
             if (r instanceof TileRecord && visibleDiff) {
@@ -492,7 +500,7 @@
         int newVis = visible ? VISIBLE : INVISIBLE;
         mQsContainer.setVisibility(newVis);
         if (mGridContentVisible != visible) {
-            MetricsLogger.visibility(mContext, MetricsLogger.QS_PANEL, newVis);
+            MetricsLogger.visibility(mContext, MetricsEvent.QS_PANEL, newVis);
         }
         mGridContentVisible = visible;
     }
@@ -551,8 +559,6 @@
     public static final class TileRecord extends Record {
         public QSTile<?> tile;
         public QSTileBaseView tileView;
-        public int row;
-        public int col;
         public boolean scanState;
         public boolean openingDetail;
     }
@@ -601,6 +607,6 @@
         void addTile(TileRecord tile);
         void removeTile(TileRecord tile);
         int getOffsetTop(TileRecord tile);
-        void updateResources();
+        boolean updateResources();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 39f0c55..35000d3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -16,11 +16,10 @@
 
 package com.android.systemui.qs;
 
+import android.app.ActivityManager;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.drawable.Animatable;
-import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.Looper;
@@ -30,12 +29,30 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.android.settingslib.RestrictedLockUtils;
 import com.android.systemui.qs.QSTile.State;
-import com.android.systemui.statusbar.policy.*;
+import com.android.systemui.qs.external.TileServices;
+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.DisplayController;
+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.Listenable;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.policy.ZenModeController;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Objects;
 
+import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
 /**
  * Base quick-settings tile, extend this to create a new tile.
  *
@@ -52,7 +69,7 @@
     protected final H mHandler;
     protected final Handler mUiHandler = new Handler(Looper.getMainLooper());
 
-    private Callback mCallback;
+    private final ArrayList<Callback> mCallbacks = new ArrayList<>();
     protected TState mState = newTileState();
     private TState mTmpState = newTileState();
     private boolean mAnnounceNextStateChange;
@@ -66,9 +83,8 @@
     /**
      * Declare the category of this tile.
      *
-     * Categories are defined in {@link com.android.internal.logging.MetricsLogger}
-     * or if there is no relevant existing category you may define one in
-     * {@link com.android.systemui.qs.QSTile}.
+     * Categories are defined in {@link com.android.internal.logging.MetricsProto.MetricsEvent}
+     * by editing frameworks/base/proto/src/metrics_constants.proto.
      */
     abstract public int getMetricsCategory();
 
@@ -99,7 +115,7 @@
     }
 
     public interface DetailAdapter {
-        int getTitle();
+        CharSequence getTitle();
         Boolean getToggleState();
         View createDetailView(Context context, View convertView, ViewGroup parent);
         Intent getSettingsIntent();
@@ -109,8 +125,12 @@
 
     // safe to call from any thread
 
-    public void setCallback(Callback callback) {
-        mHandler.obtainMessage(H.SET_CALLBACK, callback).sendToTarget();
+    public void addCallback(Callback callback) {
+        mHandler.obtainMessage(H.ADD_CALLBACK, callback).sendToTarget();
+    }
+
+    public void removeCallbacks() {
+        mHandler.sendEmptyMessage(H.REMOVE_CALLBACKS);
     }
 
     public void click() {
@@ -167,11 +187,15 @@
 
     // call only on tile worker looper
 
-    private void handleSetCallback(Callback callback) {
-        mCallback = callback;
+    private void handleAddCallback(Callback callback) {
+        mCallbacks.add(callback);
         handleRefreshState(null);
     }
 
+    private void handleRemoveCallbacks() {
+        mCallbacks.clear();
+    }
+
     protected void handleSecondaryClick() {
         // Default to normal click.
         handleClick();
@@ -196,12 +220,14 @@
 
     private void handleStateChanged() {
         boolean delayAnnouncement = shouldAnnouncementBeDelayed();
-        if (mCallback != null) {
-            mCallback.onStateChanged(mState);
+        if (mCallbacks.size() != 0) {
+            for (int i = 0; i < mCallbacks.size(); i++) {
+                mCallbacks.get(i).onStateChanged(mState);
+            }
             if (mAnnounceNextStateChange && !delayAnnouncement) {
                 String announcement = composeChangeAnnouncement();
                 if (announcement != null) {
-                    mCallback.onAnnouncementRequested(announcement);
+                    mCallbacks.get(0).onAnnouncementRequested(announcement);
                 }
             }
         }
@@ -217,20 +243,20 @@
     }
 
     private void handleShowDetail(boolean show) {
-        if (mCallback != null) {
-            mCallback.onShowDetail(show);
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            mCallbacks.get(i).onShowDetail(show);
         }
     }
 
     private void handleToggleStateChanged(boolean state) {
-        if (mCallback != null) {
-            mCallback.onToggleStateChanged(state);
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            mCallbacks.get(i).onToggleStateChanged(state);
         }
     }
 
     private void handleScanStateChanged(boolean state) {
-        if (mCallback != null) {
-            mCallback.onScanStateChanged(state);
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            mCallbacks.get(i).onScanStateChanged(state);
         }
     }
 
@@ -240,11 +266,23 @@
 
     protected void handleDestroy() {
         setListening(false);
-        mCallback = null;
+        mCallbacks.clear();
+    }
+
+    protected void checkIfRestrictionEnforced(State state, String userRestriction) {
+        EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
+                userRestriction, ActivityManager.getCurrentUser());
+        if (admin != null) {
+            state.disabledByPolicy = true;
+            state.enforcedAdmin = admin;
+        } else {
+            state.disabledByPolicy = false;
+            state.enforcedAdmin = null;
+        }
     }
 
     protected final class H extends Handler {
-        private static final int SET_CALLBACK = 1;
+        private static final int ADD_CALLBACK = 1;
         private static final int CLICK = 2;
         private static final int SECONDARY_CLICK = 3;
         private static final int LONG_CLICK = 4;
@@ -255,6 +293,7 @@
         private static final int SCAN_STATE_CHANGED = 9;
         private static final int DESTROY = 10;
         private static final int CLEAR_STATE = 11;
+        private static final int REMOVE_CALLBACKS = 12;
 
         private H(Looper looper) {
             super(looper);
@@ -264,13 +303,22 @@
         public void handleMessage(Message msg) {
             String name = null;
             try {
-                if (msg.what == SET_CALLBACK) {
-                    name = "handleSetCallback";
-                    handleSetCallback((QSTile.Callback)msg.obj);
+                if (msg.what == ADD_CALLBACK) {
+                    name = "handleAddCallback";
+                    handleAddCallback((QSTile.Callback) msg.obj);
+                } else if (msg.what == REMOVE_CALLBACKS) {
+                    name = "handleRemoveCallbacks";
+                    handleRemoveCallbacks();
                 } else if (msg.what == CLICK) {
                     name = "handleClick";
-                    mAnnounceNextStateChange = true;
-                    handleClick();
+                    if (mState.disabledByPolicy) {
+                        Intent intent = RestrictedLockUtils.getShowAdminSupportDetailsIntent(
+                                mContext, mState.enforcedAdmin);
+                        mHost.startActivityDismissingKeyguard(intent);
+                    } else {
+                        mAnnounceNextStateChange = true;
+                        handleClick();
+                    }
                 } else if (msg.what == SECONDARY_CLICK) {
                     name = "handleSecondaryClick";
                     handleSecondaryClick();
@@ -323,6 +371,7 @@
         void startRunnableDismissingKeyguard(Runnable runnable);
         void warn(String message, Throwable t);
         void collapsePanels();
+        void animateExpandQS();
         void openPanels();
         Looper getLooper();
         Context getContext();
@@ -340,8 +389,11 @@
         UserSwitcherController getUserSwitcherController();
         UserInfoController getUserInfoController();
         BatteryController getBatteryController();
+        TileServices getTileServices();
+        DisplayController getDisplayController();
         void removeTile(String tileSpec);
 
+
         public interface Callback {
             void onTilesChanged();
         }
@@ -389,11 +441,7 @@
 
         @Override
         public Drawable getDrawable(Context context) {
-            Drawable d = context.getDrawable(mResId);
-            if (d instanceof Animatable) {
-                ((Animatable) d).start();
-            }
-            return d;
+            return context.getDrawable(mResId);
         }
 
         @Override
@@ -408,41 +456,14 @@
     }
 
     protected class AnimationIcon extends ResourceIcon {
-        private boolean mAllowAnimation;
-
         public AnimationIcon(int resId) {
             super(resId);
         }
 
-        public void setAllowAnimation(boolean allowAnimation) {
-            mAllowAnimation = allowAnimation;
-        }
-
         @Override
         public Drawable getDrawable(Context context) {
             // workaround: get a clean state for every new AVD
-            final AnimatedVectorDrawable d = (AnimatedVectorDrawable) context.getDrawable(mResId)
-                    .getConstantState().newDrawable();
-            d.start();
-            if (mAllowAnimation) {
-                mAllowAnimation = false;
-            } else {
-                d.stop(); // skip directly to end state
-            }
-            return d;
-        }
-    }
-
-    protected enum UserBoolean {
-        USER_TRUE(true, true),
-        USER_FALSE(true, false),
-        BACKGROUND_TRUE(false, true),
-        BACKGROUND_FALSE(false, false);
-        public final boolean value;
-        public final boolean userInitiated;
-        private UserBoolean(boolean userInitiated, boolean value) {
-            this.value = value;
-            this.userInitiated = userInitiated;
+            return context.getDrawable(mResId).getConstantState().newDrawable();
         }
     }
 
@@ -452,6 +473,8 @@
         public CharSequence contentDescription;
         public CharSequence dualLabelContentDescription;
         public boolean autoMirrorDrawable = true;
+        public boolean disabledByPolicy;
+        public EnforcedAdmin enforcedAdmin;
 
         public boolean copyTo(State other) {
             if (other == null) throw new IllegalArgumentException();
@@ -461,12 +484,22 @@
                     || !Objects.equals(other.contentDescription, contentDescription)
                     || !Objects.equals(other.autoMirrorDrawable, autoMirrorDrawable)
                     || !Objects.equals(other.dualLabelContentDescription,
-                    dualLabelContentDescription);
+                    dualLabelContentDescription)
+                    || !Objects.equals(other.disabledByPolicy, disabledByPolicy)
+                    || !Objects.equals(other.enforcedAdmin, enforcedAdmin);
             other.icon = icon;
             other.label = label;
             other.contentDescription = contentDescription;
             other.dualLabelContentDescription = dualLabelContentDescription;
             other.autoMirrorDrawable = autoMirrorDrawable;
+            other.disabledByPolicy = disabledByPolicy;
+            if (enforcedAdmin == null) {
+                other.enforcedAdmin = null;
+            } else if (other.enforcedAdmin == null) {
+                other.enforcedAdmin = new EnforcedAdmin(enforcedAdmin);
+            } else {
+                enforcedAdmin.copyTo(other.enforcedAdmin);
+            }
             return changed;
         }
 
@@ -482,6 +515,8 @@
             sb.append(",contentDescription=").append(contentDescription);
             sb.append(",dualLabelContentDescription=").append(dualLabelContentDescription);
             sb.append(",autoMirrorDrawable=").append(autoMirrorDrawable);
+            sb.append(",disabledByPolicy=").append(disabledByPolicy);
+            sb.append(",enforcedAdmin=").append(enforcedAdmin);
             return sb.append(']');
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileServiceWrapper.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileServiceWrapper.java
deleted file mode 100644
index a5e1fd5..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileServiceWrapper.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.android.systemui.qs;
-
-import android.os.IBinder;
-import android.service.quicksettings.IQSTileService;
-import android.service.quicksettings.Tile;
-import android.util.Log;
-
-
-public class QSTileServiceWrapper implements IQSTileService {
-    private static final String TAG = "IQSTileServiceWrapper";
-
-    private final IQSTileService mService;
-    
-    public QSTileServiceWrapper(IQSTileService service) {
-        mService = service;
-    }
-
-    @Override
-    public IBinder asBinder() {
-        return mService.asBinder();
-    }
-
-    @Override
-    public void setQSTile(Tile tile) {
-        try {
-            mService.setQSTile(tile);
-        } catch (Exception e) {
-            Log.d(TAG, "Caught exception from QSTileService", e);
-        }
-    }
-
-    @Override
-    public void onTileAdded() {
-        try {
-            mService.onTileAdded();
-        } catch (Exception e) {
-            Log.d(TAG, "Caught exception from QSTileService", e);
-        }
-    }
-
-    @Override
-    public void onTileRemoved() {
-        try {
-            mService.onTileRemoved();
-        } catch (Exception e) {
-            Log.d(TAG, "Caught exception from QSTileService", e);
-        }
-    }
-
-    @Override
-    public void onStartListening() {
-        try {
-            mService.onStartListening();
-        } catch (Exception e) {
-            Log.d(TAG, "Caught exception from QSTileService", e);
-        }
-    }
-
-    @Override
-    public void onStopListening() {
-        try {
-            mService.onStopListening();
-        } catch (Exception e) {
-            Log.d(TAG, "Caught exception from QSTileService", e);
-        }
-    }
-
-    @Override
-    public void onClick(IBinder token) {
-        try {
-            mService.onClick(token);
-        } catch (Exception e) {
-            Log.d(TAG, "Caught exception from QSTileService", e);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 41ac4d9..664ca39 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -19,32 +19,33 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.graphics.Typeface;
 import android.util.MathUtils;
-import android.util.TypedValue;
 import android.view.Gravity;
+import android.view.LayoutInflater;
 import android.view.View;
+import android.widget.ImageView;
 import android.widget.TextView;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
 
 /** View that represents a standard quick settings tile. **/
 public class QSTileView extends QSTileBaseView {
-    private static final Typeface CONDENSED = Typeface.create("sans-serif-condensed",
-            Typeface.NORMAL);
-
     protected final Context mContext;
+    private QSIconView mIconView;
     private final int mTileSpacingPx;
     private int mTilePaddingTopPx;
 
     private TextView mLabel;
+    private ImageView mPadLock;
 
     public QSTileView(Context context, QSIconView icon) {
         super(context, icon);
 
         mContext = context;
+        mIconView = icon;
         final Resources res = context.getResources();
         mTileSpacingPx = res.getDimensionPixelSize(R.dimen.qs_tile_spacing);
+
         setClipChildren(false);
 
         setClickable(true);
@@ -76,16 +77,10 @@
 
     private void createLabel() {
         final Resources res = mContext.getResources();
-        mLabel = new TextView(mContext);
-        mLabel.setTextColor(mContext.getColor(R.color.qs_tile_text));
-        mLabel.setGravity(Gravity.CENTER_HORIZONTAL);
-        mLabel.setMinLines(2);
-        mLabel.setPadding(0, 0, 0, 0);
-        mLabel.setTypeface(CONDENSED);
-        mLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX,
-                res.getDimensionPixelSize(R.dimen.qs_tile_text_size));
-        mLabel.setClickable(false);
-        addView(mLabel);
+        View view = LayoutInflater.from(mContext).inflate(R.layout.qs_tile_label, null);
+        mLabel = (TextView) view.findViewById(R.id.tile_label);
+        mPadLock = (ImageView) view.findViewById(R.id.restricted_padlock);
+        addView(view);
     }
 
     public void init(OnClickListener clickPrimary, OnLongClickListener longClick) {
@@ -96,5 +91,7 @@
     protected void handleStateChanged(QSTile.State state) {
         super.handleStateChanged(state);
         mLabel.setText(state.label);
+        mLabel.setEnabled(!state.disabledByPolicy);
+        mPadLock.setVisibility(state.disabledByPolicy ? View.VISIBLE : View.GONE);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index bda4675..b391c1e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -49,20 +49,19 @@
         mQsContainer.addView((View) mTileLayout, 1 /* Between brightness and footer */);
     }
 
+    @Override
+    protected void createCustomizePanel() {
+        // No customizing from the header.
+    }
+
     public void setQSPanelAndHeader(QSPanel fullPanel, View header) {
         mFullPanel = fullPanel;
         mHeader = header;
     }
 
     @Override
-    protected void handleShowDetail(QSPanel.Record r, boolean show) {
-        if (show) {
-            mHeader.performClick();
-            mFullPanel.showDetail(show, r);
-        } else {
-            // Not sure how we would end up here...
-            super.handleShowDetail(r, show);
-        }
+    protected void showDetail(boolean show, Record r) {
+        // Do nothing, will be handled by the QSPanel.
     }
 
     @Override
@@ -146,8 +145,9 @@
         }
 
         @Override
-        public void updateResources() {
+        public boolean updateResources() {
             // No resources here.
+            return false;
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index ff11177..59a394f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -5,7 +5,6 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
-
 import com.android.systemui.R;
 import com.android.systemui.qs.QSPanel.QSTileLayout;
 import com.android.systemui.qs.QSPanel.TileRecord;
@@ -21,6 +20,7 @@
     protected int mColumns;
     private int mCellWidth;
     private int mCellHeight;
+    private int mCellMargin;
 
     protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
 
@@ -54,52 +54,33 @@
         super.removeAllViews();
     }
 
-    public void updateResources() {
+    public boolean updateResources() {
         final Resources res = mContext.getResources();
         final int columns = Math.max(1, res.getInteger(R.integer.quick_settings_num_columns));
-        mCellHeight = getCellHeight();
-        mCellWidth = (int) (mCellHeight * TILE_ASPECT);
+        mCellHeight = mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_height);
+        mCellMargin = res.getDimensionPixelSize(R.dimen.qs_tile_margin);
         if (mColumns != columns) {
             mColumns = columns;
             postInvalidate();
+            return true;
         }
-    }
-
-    protected int getCellHeight() {
-        return mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_height);
+        return false;
     }
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int numTiles = mRecords.size();
         final int width = MeasureSpec.getSize(widthMeasureSpec);
-        int r = -1;
-        int c = -1;
-        int rows = 0;
-        for (TileRecord record : mRecords) {
-            if (record.tileView.getVisibility() == GONE) continue;
-            // wrap to next column if we've reached the max # of columns
-            // also don't allow dual + single tiles on the same row
-            if (r == -1 || c == (mColumns - 1)) {
-                r++;
-                c = 0;
-            } else {
-                c++;
-            }
-            record.row = r;
-            record.col = c;
-            rows = r + 1;
-        }
+        final int rows = (numTiles + mColumns - 1) / mColumns;
+        mCellWidth = (width - (mCellMargin * (mColumns + 1))) / mColumns;
 
         View previousView = this;
         for (TileRecord record : mRecords) {
             if (record.tileView.getVisibility() == GONE) continue;
-            final int cw = mCellWidth;
-            final int ch = mCellHeight;
-            record.tileView.measure(exactly(cw), exactly(ch));
+            record.tileView.measure(exactly(mCellWidth), exactly(mCellHeight));
             previousView = record.tileView.updateAccessibilityOrder(previousView);
         }
-        int h = rows == 0 ? 0 : getRowTop(rows);
-        setMeasuredDimension(width, h);
+        setMeasuredDimension(width, (mCellHeight + mCellMargin) * rows + mCellMargin);
     }
 
     private static int exactly(int size) {
@@ -110,37 +91,32 @@
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         final int w = getWidth();
         boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
-        for (TileRecord record : mRecords) {
-            if (record.tileView.getVisibility() == GONE) continue;
-            final int cols = getColumnCount(record.row);
-            final int cw = mCellWidth;
-            final int extra = (w - cw * cols) / (cols + 1);
-            int left = record.col * cw + (record.col + 1) * extra;
-            final int top = getRowTop(record.row);
+        int row = 0;
+        int column = 0;
+        for (int i = 0; i < mRecords.size(); i++, column++) {
+            if (column == mColumns) {
+                row++;
+                column -= mColumns;
+            }
+            TileRecord record = mRecords.get(i);
+            int left = getColumnStart(column);
+            final int top = getRowTop(row);
             int right;
-            int tileWith = record.tileView.getMeasuredWidth();
             if (isRtl) {
                 right = w - left;
-                left = right - tileWith;
+                left = right - mCellWidth;
             } else {
-                right = left + tileWith;
+                right = left + mCellWidth;
             }
             record.tileView.layout(left, top, right, top + record.tileView.getMeasuredHeight());
         }
     }
 
     private int getRowTop(int row) {
-        if (row <= 0) return 0;
-        return row * mCellHeight;
+        return row * (mCellHeight + mCellMargin) + mCellMargin;
     }
 
-    private int getColumnCount(int row) {
-        int cols = 0;
-        for (TileRecord record : mRecords) {
-            if (record.tileView.getVisibility() == GONE) continue;
-            if (record.row == row) cols++;
-        }
-        return cols;
+    private int getColumnStart(int column) {
+        return column * (mCellWidth + mCellMargin) + mCellMargin;
     }
-
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/BlankCustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/customize/BlankCustomTile.java
index 95ff611..36bed0d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/BlankCustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/BlankCustomTile.java
@@ -19,8 +19,11 @@
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
+import android.graphics.drawable.Drawable;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 
 public class BlankCustomTile extends QSTile<QSTile.State> {
@@ -72,7 +75,9 @@
         try {
             PackageManager pm = mContext.getPackageManager();
             ServiceInfo info = pm.getServiceInfo(mComponent, 0);
-            state.icon = new DrawableIcon(info.loadIcon(pm));
+            Drawable drawable = info.loadIcon(pm);
+            drawable.setTint(mContext.getColor(R.color.qs_tile_tint_active));
+            state.icon = new DrawableIcon(drawable);
             state.label = info.loadLabel(pm).toString();
             state.contentDescription = state.label;
         } catch (Exception e) {
@@ -81,6 +86,6 @@
 
     @Override
     public int getMetricsCategory() {
-        return MetricsLogger.QS_INTENT;
+        return MetricsEvent.QS_INTENT;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
index 87c2973..eab4dca 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
@@ -16,32 +16,28 @@
 package com.android.systemui.qs.customize;
 
 import android.app.ActivityManager;
-import android.app.Service;
 import android.content.ClipData;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.IBinder;
+import android.os.Handler;
 import android.os.UserHandle;
 import android.provider.Settings.Secure;
-import android.service.quicksettings.IQSTileService;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
-
 import com.android.systemui.R;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.QSTileServiceWrapper;
-import com.android.systemui.qs.tiles.CustomTile;
+import com.android.systemui.qs.external.CustomTile;
+import com.android.systemui.qs.external.TileLifecycleManager;
 import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.tuner.TunerService;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -52,8 +48,9 @@
 public class CustomQSPanel extends QSPanel {
     
     private static final String TAG = "CustomQSPanel";
+    private static final boolean DEBUG = false;
 
-    private List<String> mSavedTiles;
+    private List<String> mSavedTiles = Collections.emptyList();
     private ArrayList<String> mStash;
     private List<String> mTiles = new ArrayList<>();
 
@@ -67,17 +64,30 @@
         ((NonPagedTileLayout) mTileLayout).setCustomQsPanel(this);
         removeView(mFooter.getView());
 
+        if (DEBUG) Log.d(TAG, "new CustomQSPanel", new Throwable());
         TunerService.get(mContext).addTunable(this, QSTileHost.TILES_SETTING);
     }
 
     @Override
+    protected void showDetail(boolean show, Record r) {
+        // No detail here.
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        // Don't allow the super to unregister the tunable.
+    }
+
+    @Override
     public void onTuningChanged(String key, String newValue) {
         if (key.equals(QS_SHOW_BRIGHTNESS)) {
             // No Brightness for you.
             super.onTuningChanged(key, "0");
         }
         if (QSTileHost.TILES_SETTING.equals(key)) {
-            mSavedTiles = QSTileHost.loadTileSpecs(mContext, newValue);
+            mSavedTiles = Collections.unmodifiableList(
+                    QSTileHost.loadTileSpecs(mContext, newValue));
+            if (DEBUG) Log.d(TAG, "New saved tiles " + TextUtils.join(",", mSavedTiles));
         }
     }
 
@@ -106,6 +116,7 @@
     }
 
     public void setSavedTiles() {
+        if (DEBUG) Log.d(TAG, "setSavedTiles " + TextUtils.join(",", mSavedTiles));
         setTiles(mSavedTiles);
     }
 
@@ -114,47 +125,26 @@
             String tileSpec = mSavedTiles.get(i);
             if (!tileSpec.startsWith(CustomTile.PREFIX)) continue;
             if (!mTiles.contains(tileSpec)) {
-                mContext.bindServiceAsUser(
-                        new Intent().setComponent(CustomTile.getComponentFromSpec(tileSpec)),
-                        new ServiceConnection() {
-                            @Override
-                            public void onServiceDisconnected(ComponentName name) {
-                            }
-
-                            @Override
-                            public void onServiceConnected(ComponentName name, IBinder service) {
-                                QSTileServiceWrapper wrapper = new QSTileServiceWrapper(
-                                        IQSTileService.Stub.asInterface(service));
-                                wrapper.onStopListening();
-                                wrapper.onTileRemoved();
-                                mContext.unbindService(this);
-                            }
-                        }, Service.BIND_AUTO_CREATE,
-                        new UserHandle(ActivityManager.getCurrentUser()));
+                Intent intent = new Intent().setComponent(CustomTile.getComponentFromSpec(tileSpec));
+                TileLifecycleManager lifecycleManager = new TileLifecycleManager(new Handler(),
+                        mContext, intent, new UserHandle(ActivityManager.getCurrentUser()));
+                lifecycleManager.onStopListening();
+                lifecycleManager.onTileRemoved();
+                lifecycleManager.flushMessagesAndUnbind();
             }
         }
         for (int i = 0; i < mTiles.size(); i++) {
             String tileSpec = mTiles.get(i);
             if (!tileSpec.startsWith(CustomTile.PREFIX)) continue;
             if (!mSavedTiles.contains(tileSpec)) {
-                mContext.bindServiceAsUser(
-                        new Intent().setComponent(CustomTile.getComponentFromSpec(tileSpec)),
-                        new ServiceConnection() {
-                            @Override
-                            public void onServiceDisconnected(ComponentName name) {
-                            }
-
-                            @Override
-                            public void onServiceConnected(ComponentName name, IBinder service) {
-                                QSTileServiceWrapper wrapper = new QSTileServiceWrapper(
-                                        IQSTileService.Stub.asInterface(service));
-                                wrapper.onTileAdded();
-                                mContext.unbindService(this);
-                            }
-                        }, Service.BIND_AUTO_CREATE,
-                        new UserHandle(ActivityManager.getCurrentUser()));
+                Intent intent = new Intent().setComponent(CustomTile.getComponentFromSpec(tileSpec));
+                TileLifecycleManager lifecycleManager = new TileLifecycleManager(new Handler(),
+                        mContext, intent, new UserHandle(ActivityManager.getCurrentUser()));
+                lifecycleManager.onTileAdded();
+                lifecycleManager.flushMessagesAndUnbind();
             }
         }
+        if (DEBUG) Log.d(TAG, "saveCurrentTiles " + mTiles);
         Secure.putStringForUser(getContext().getContentResolver(), QSTileHost.TILES_SETTING,
                 TextUtils.join(",", mTiles), ActivityManager.getCurrentUser());
     }
@@ -173,30 +163,37 @@
     }
 
     private void setTilesInternal() {
+        if (DEBUG) Log.d(TAG, "Set tiles internal");
         for (int i = 0; i < mCurrentTiles.size(); i++) {
             mCurrentTiles.get(i).destroy();
         }
         mCurrentTiles.clear();
         for (int i = 0; i < mTiles.size(); i++) {
             if (mTiles.get(i).startsWith(CustomTile.PREFIX)) {
-                mCurrentTiles.add(BlankCustomTile.create(mHost, mTiles.get(i)));
+                QSTile<?> tile = BlankCustomTile.create(mHost, mTiles.get(i));
+                tile.setTileSpec(mTiles.get(i));
+                mCurrentTiles.add(tile);
             } else {
                 QSTile<?> tile = mHost.createTile(mTiles.get(i));
                 if (tile != null) {
+                    tile.setTileSpec(mTiles.get(i));
                     mCurrentTiles.add(tile);
+                } else {
+                    if (DEBUG) Log.d(TAG, "Skipping " + mTiles.get(i));
                 }
             }
-            mCurrentTiles.get(mCurrentTiles.size() - 1).setTileSpec(mTiles.get(i));
         }
         super.setTiles(mCurrentTiles);
     }
 
     public void addTile(String spec) {
+        if (DEBUG) Log.d(TAG, "addTile " + spec);
         mTiles.add(spec);
         setTilesInternal();
     }
 
     public void moveTo(String from, String to) {
+        if (DEBUG) Log.d(TAG, "moveTo " + from + " " + to);
         int fromIndex = mTiles.indexOf(from);
         if (fromIndex < 0) {
             Log.e(TAG, "Unknown from tile " + from);
@@ -220,6 +217,7 @@
     }
 
     public void setTiles(List<String> tiles) {
+        if (DEBUG) Log.d(TAG, "Set tiles " + TextUtils.join(",", tiles));
         mTiles = new ArrayList<>(tiles);
         setTilesInternal();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java
index 3acbed8..8f0d194 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java
@@ -31,7 +31,6 @@
 import com.android.systemui.qs.QSPanel.QSTileLayout;
 import com.android.systemui.qs.QSPanel.TileRecord;
 import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.QuickTileLayout;
 
 import java.util.ArrayList;
 
@@ -42,7 +41,6 @@
  */
 public class NonPagedTileLayout extends LinearLayout implements QSTileLayout, OnTouchListener {
 
-    private QuickTileLayout mQuickTiles;
     private final ArrayList<TilePage> mPages = new ArrayList<>();
     private final ArrayList<TileRecord> mTiles = new ArrayList<TileRecord>();
     private CustomQSPanel mPanel;
@@ -58,8 +56,6 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mQuickTiles = (QuickTileLayout) findViewById(R.id.quick_tile_layout);
-        mQuickTiles.setVisibility(View.GONE);
         TilePage page = (PagedTileLayout.TilePage) findViewById(R.id.tile_page);
         page.setMaxRows(3 /* First page only gets 3 */);
         mPages.add(page);
@@ -95,7 +91,6 @@
     }
 
     private void distributeTiles() {
-        mQuickTiles.removeAllViews();
         final int NP = mPages.size();
         for (int i = 0; i < NP; i++) {
             mPages.get(i).removeAllViews();
@@ -124,7 +119,8 @@
     }
 
     @Override
-    public void updateResources() {
+    public boolean updateResources() {
+        return false;
     }
 
     @Override
@@ -133,24 +129,20 @@
             case DragEvent.ACTION_DRAG_LOCATION:
                 float x = event.getX();
                 float y = event.getY();
-                if (contains(mQuickTiles, x, y)) {
-                    // TODO: Reset to pre-drag state.
-                } else {
-                    final int NP = mPages.size();
-                    for (int i = 0; i < NP; i++) {
-                        TilePage page = mPages.get(i);
-                        if (contains(page, x, y)) {
-                            x -= page.getLeft();
-                            y -= page.getTop();
-                            final int NC = page.getChildCount();
-                            for (int j = 0; j < NC; j++) {
-                                View child = page.getChildAt(j);
-                                if (contains(child, x, y)) {
-                                    mPanel.tileSelected((QSTile<?>) child.getTag(), mCurrentClip);
-                                }
+                final int NP = mPages.size();
+                for (int i = 0; i < NP; i++) {
+                    TilePage page = mPages.get(i);
+                    if (contains(page, x, y)) {
+                        x -= page.getLeft();
+                        y -= page.getTop();
+                        final int NC = page.getChildCount();
+                        for (int j = 0; j < NC; j++) {
+                            View child = page.getChildAt(j);
+                            if (contains(child, x, y)) {
+                                mPanel.tileSelected((QSTile<?>) child.getTag(), mCurrentClip);
                             }
-                            break;
                         }
+                        break;
                     }
                 }
                 break;
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 4a7d67f..cc4ce70 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -45,7 +45,6 @@
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
-import com.android.systemui.tuner.QSPagingSwitch;
 
 import java.util.ArrayList;
 
@@ -145,7 +144,8 @@
 
     private void reset() {
         ArrayList<String> tiles = new ArrayList<>();
-        for (String tile : QSPagingSwitch.QS_PAGE_TILES.split(",")) {
+        String defTiles = mContext.getString(R.string.quick_settings_tiles_default);
+        for (String tile : defTiles.split(",")) {
             tiles.add(tile);
         }
         mQsPanel.setTiles(tiles);
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 6706c7a..3748a30 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -37,13 +37,11 @@
 import android.widget.GridLayout;
 import android.widget.ImageView;
 import android.widget.TextView;
-
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.QSTile.Icon;
-import com.android.systemui.qs.tiles.CustomTile;
+import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.statusbar.phone.QSTileHost;
-import com.android.systemui.tuner.QSPagingSwitch;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -74,8 +72,10 @@
             }
             mCurrentTiles = tileSpecs;
             final TileGroup group = new TileGroup("com.android.settings", mContext);
-            // TODO: Pull this list from a more authoritative place.
-            String[] possibleTiles = QSPagingSwitch.QS_PAGE_TILES.split(",");
+            boolean hasColorMod = host.getDisplayController().isEnabled();
+            String possible = mContext.getString(R.string.quick_settings_tiles_default)
+                    + ",hotspot,inversion,saver" + (hasColorMod ? ",colors" : "");
+            String[] possibleTiles = possible.split(",");
             for (int i = 0; i < possibleTiles.length; i++) {
                 final String spec = possibleTiles[i];
                 if (spec.startsWith("q")) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
new file mode 100644
index 0000000..886531a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.external;
+
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.graphics.drawable.Drawable;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.service.quicksettings.IQSTileService;
+import android.service.quicksettings.Tile;
+import android.service.quicksettings.TileService;
+import android.text.SpannableStringBuilder;
+import android.text.style.ForegroundColorSpan;
+import android.util.Log;
+import android.view.IWindowManager;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.phone.QSTileHost;
+
+public class CustomTile extends QSTile<QSTile.State> {
+    public static final String PREFIX = "custom(";
+
+    private static final boolean DEBUG = false;
+
+    // We don't want to thrash binding and unbinding if the user opens and closes the panel a lot.
+    // So instead we have a period of waiting.
+    private static final long UNBIND_DELAY = 30000;
+
+    private final ComponentName mComponent;
+    private final Tile mTile;
+    private final IWindowManager mWindowManager;
+    private final IBinder mToken = new Binder();
+    private final IQSTileService mService;
+    private final TileServiceManager mServiceManager;
+
+    private boolean mListening;
+    private boolean mBound;
+    private boolean mIsTokenGranted;
+    private boolean mIsShowingDialog;
+
+    private CustomTile(QSTileHost host, String action) {
+        super(host);
+        mWindowManager = WindowManagerGlobal.getWindowManagerService();
+        mComponent = ComponentName.unflattenFromString(action);
+        mServiceManager = host.getTileServices().getTileWrapper(this);
+        mService = mServiceManager.getTileService();
+        mTile = new Tile(mComponent);
+        try {
+            PackageManager pm = mContext.getPackageManager();
+            ServiceInfo info = pm.getServiceInfo(mComponent, 0);
+            mTile.setIcon(android.graphics.drawable.Icon
+                    .createWithResource(mComponent.getPackageName(), info.icon));
+            mTile.setLabel(info.loadLabel(pm));
+        } catch (Exception e) {
+        }
+        try {
+            mService.setQSTile(mTile);
+        } catch (RemoteException e) {
+            // Called through wrapper, won't happen here.
+        }
+    }
+
+    public ComponentName getComponent() {
+        return mComponent;
+    }
+
+    public Tile getQsTile() {
+        return mTile;
+    }
+
+    public void updateState(Tile tile) {
+        mTile.setIcon(tile.getIcon());
+        mTile.setLabel(tile.getLabel());
+        mTile.setContentDescription(tile.getContentDescription());
+        mTile.setState(tile.getState());
+    }
+
+    public void onDialogShown() {
+        mIsShowingDialog = true;
+    }
+
+    @Override
+    public void setListening(boolean listening) {
+        if (mListening == listening) return;
+        mListening = listening;
+        try {
+            if (listening) {
+                if (mServiceManager.getType() == TileService.TILE_MODE_PASSIVE) {
+                    mServiceManager.setBindRequested(true);
+                    mService.onStartListening();
+                }
+            } else {
+                mService.onStopListening();
+                if (mIsTokenGranted && !mIsShowingDialog) {
+                    try {
+                        if (DEBUG) Log.d(TAG, "Removing token");
+                        mWindowManager.removeWindowToken(mToken);
+                    } catch (RemoteException e) {
+                    }
+                    mIsTokenGranted = false;
+                }
+                mIsShowingDialog = false;
+                mServiceManager.setBindRequested(false);
+            }
+        } catch (RemoteException e) {
+            // Called through wrapper, won't happen here.
+        }
+    }
+
+    @Override
+    protected void handleDestroy() {
+        super.handleDestroy();
+        if (mIsTokenGranted) {
+            try {
+                if (DEBUG) Log.d(TAG, "Removing token");
+                mWindowManager.removeWindowToken(mToken);
+            } catch (RemoteException e) {
+            }
+        }
+        mHost.getTileServices().freeService(this, mServiceManager);
+    }
+
+    @Override
+    protected State newTileState() {
+        return new State();
+    }
+
+    @Override
+    protected void handleUserSwitch(int newUserId) {
+        super.handleUserSwitch(newUserId);
+    }
+
+    @Override
+    protected void handleClick() {
+        if (mTile.getState() == Tile.STATE_UNAVAILABLE) {
+            return;
+        }
+        try {
+            if (DEBUG) Log.d(TAG, "Adding token");
+            mWindowManager.addWindowToken(mToken, WindowManager.LayoutParams.TYPE_QS_DIALOG);
+            mIsTokenGranted = true;
+        } catch (RemoteException e) {
+        }
+        try {
+            if (mServiceManager.getType() == TileService.TILE_MODE_ACTIVE) {
+                mServiceManager.setBindRequested(true);
+                mService.onStartListening();
+            }
+            mService.onClick(mToken);
+        } catch (RemoteException e) {
+            // Called through wrapper, won't happen here.
+        }
+        MetricsLogger.action(mContext, getMetricsCategory(), mComponent.getPackageName());
+    }
+
+    @Override
+    protected void handleLongClick() {
+    }
+
+    @Override
+    protected void handleUpdateState(State state, Object arg) {
+        Drawable drawable = mTile.getIcon().loadDrawable(mContext);
+        int color = mContext.getColor(getColor(mTile.getState()));
+        drawable.setTint(color);
+        state.icon = new DrawableIcon(drawable);
+        state.label = mTile.getLabel();
+        if (mTile.getState() == Tile.STATE_UNAVAILABLE) {
+            state.label = new SpannableStringBuilder().append(state.label,
+                    new ForegroundColorSpan(color),
+                    SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE);
+        }
+        if (mTile.getContentDescription() != null) {
+            state.contentDescription = mTile.getContentDescription();
+        } else {
+            state.contentDescription = state.label;
+        }
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsEvent.QS_CUSTOM;
+    }
+
+    public void startUnlockAndRun() {
+        mHost.startRunnableDismissingKeyguard(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    mService.onUnlockComplete();
+                } catch (RemoteException e) {
+                }
+            }
+        });
+    }
+
+    private static int getColor(int state) {
+        switch (state) {
+            case Tile.STATE_UNAVAILABLE:
+                return R.color.qs_tile_tint_unavailable;
+            case Tile.STATE_INACTIVE:
+                return R.color.qs_tile_tint_inactive;
+            case Tile.STATE_ACTIVE:
+                return R.color.qs_tile_tint_active;
+        }
+        return 0;
+    }
+
+    public static ComponentName getComponentFromSpec(String spec) {
+        final String action = spec.substring(PREFIX.length(), spec.length() - 1);
+        if (action.isEmpty()) {
+            throw new IllegalArgumentException("Empty custom tile spec action");
+        }
+        return ComponentName.unflattenFromString(action);
+    }
+
+    public static QSTile<?> create(QSTileHost host, String spec) {
+        if (spec == null || !spec.startsWith(PREFIX) || !spec.endsWith(")")) {
+            throw new IllegalArgumentException("Bad custom tile spec: " + spec);
+        }
+        final String action = spec.substring(PREFIX.length(), spec.length() - 1);
+        if (action.isEmpty()) {
+            throw new IllegalArgumentException("Empty custom tile spec action");
+        }
+        return new CustomTile(host, action);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
new file mode 100644
index 0000000..3830ac5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.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.qs.external;
+
+import android.os.IBinder;
+import android.service.quicksettings.IQSService;
+import android.service.quicksettings.IQSTileService;
+import android.service.quicksettings.Tile;
+import android.util.Log;
+
+
+public class QSTileServiceWrapper {
+    private static final String TAG = "IQSTileServiceWrapper";
+
+    private final IQSTileService mService;
+
+    public QSTileServiceWrapper(IQSTileService service) {
+        mService = service;
+    }
+
+    public IBinder asBinder() {
+        return mService.asBinder();
+    }
+
+    public boolean setQSTile(Tile tile) {
+        try {
+            mService.setQSTile(tile);
+            return true;
+        } catch (Exception e) {
+            Log.d(TAG, "Caught exception from TileService", e);
+            return false;
+        }
+    }
+
+    public boolean onTileAdded() {
+        try {
+            mService.onTileAdded();
+            return true;
+        } catch (Exception e) {
+            Log.d(TAG, "Caught exception from TileService", e);
+            return false;
+        }
+    }
+
+    public boolean onTileRemoved() {
+        try {
+            mService.onTileRemoved();
+            return true;
+        } catch (Exception e) {
+            Log.d(TAG, "Caught exception from TileService", e);
+            return false;
+        }
+    }
+
+    public boolean onStartListening() {
+        try {
+            mService.onStartListening();
+            return true;
+        } catch (Exception e) {
+            Log.d(TAG, "Caught exception from TileService", e);
+            return false;
+        }
+    }
+
+    public boolean onStopListening() {
+        try {
+            mService.onStopListening();
+            return true;
+        } catch (Exception e) {
+            Log.d(TAG, "Caught exception from TileService", e);
+            return false;
+        }
+    }
+
+    public boolean onClick(IBinder token) {
+        try {
+            mService.onClick(token);
+            return true;
+        } catch (Exception e) {
+            Log.d(TAG, "Caught exception from TileService", e);
+            return false;
+        }
+    }
+
+    public boolean setQSService(IQSService service) {
+        try {
+            mService.setQSService(service);
+            return true;
+        } catch (Exception e) {
+            Log.d(TAG, "Caught exception from TileService", e);
+            return false;
+        }
+    }
+
+    public boolean onUnlockComplete() {
+        try {
+            mService.onUnlockComplete();
+            return true;
+        } catch (Exception e) {
+            Log.d(TAG, "Caught exception from TileService", e);
+            return false;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
new file mode 100644
index 0000000..4977d80
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -0,0 +1,379 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.external;
+
+import android.app.AppGlobals;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.quicksettings.IQSService;
+import android.service.quicksettings.IQSTileService;
+import android.service.quicksettings.Tile;
+import android.support.annotation.VisibleForTesting;
+import android.util.ArraySet;
+import android.util.Log;
+import libcore.util.Objects;
+
+import java.util.Set;
+
+/**
+ * Manages the lifecycle of a TileService.
+ * <p>
+ * Will keep track of all calls on the IQSTileService interface and will relay those calls to the
+ * TileService as soon as it is bound.  It will only bind to the service when it is allowed to
+ * ({@link #setBindService(boolean)}) and when the service is available.
+ */
+public class TileLifecycleManager extends BroadcastReceiver implements
+        IQSTileService, ServiceConnection, IBinder.DeathRecipient {
+    public static final boolean DEBUG = false;
+
+    private static final String TAG = "TileLifecycleManager";
+
+    private static final int MSG_ON_ADDED = 0;
+    private static final int MSG_ON_REMOVED = 1;
+    private static final int MSG_ON_CLICK = 2;
+    private static final int MSG_ON_UNLOCK_COMPLETE = 3;
+
+    // Bind retry control.
+    private static final int MAX_BIND_RETRIES = 5;
+    private static final int BIND_RETRY_DELAY = 1000;
+
+    private final Context mContext;
+    private final Handler mHandler;
+    private final Intent mIntent;
+    private final UserHandle mUser;
+
+    private Set<Integer> mQueuedMessages = new ArraySet<>();
+    private QSTileServiceWrapper mWrapper;
+    private boolean mListening;
+    private Tile mTile;
+    private IBinder mClickBinder;
+
+    private int mBindTryCount;
+    private boolean mBound;
+    @VisibleForTesting
+    boolean mReceiverRegistered;
+    private IQSService mService;
+    private boolean mUnbindImmediate;
+
+    public TileLifecycleManager(Handler handler, Context context, Intent intent, UserHandle user) {
+        mContext = context;
+        mHandler = handler;
+        mIntent = intent;
+        mUser = user;
+    }
+
+    public ComponentName getComponent() {
+        return mIntent.getComponent();
+    }
+
+    public boolean hasPendingClick() {
+        synchronized (mQueuedMessages) {
+            return mQueuedMessages.contains(MSG_ON_CLICK);
+        }
+    }
+
+    /**
+     * Binds just long enough to send any queued messages, then unbinds.
+     */
+    public void flushMessagesAndUnbind() {
+        mUnbindImmediate = true;
+        setBindService(true);
+    }
+
+    public void setBindService(boolean bind) {
+        mBound = bind;
+        if (bind) {
+            if (mBindTryCount == MAX_BIND_RETRIES) {
+                // Too many failures, give up on this tile until an update.
+                startPackageListening();
+                return;
+            }
+            if (!checkComponentState()) {
+                return;
+            }
+            if (DEBUG) Log.d(TAG, "Binding service " + mIntent);
+            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);
+            // Give it another chance next time it needs to be bound, out of kindness.
+            mBindTryCount = 0;
+            mWrapper = null;
+            mContext.unbindService(this);
+        }
+    }
+
+    @Override
+    public void onServiceConnected(ComponentName name, IBinder service) {
+        if (DEBUG) Log.d(TAG, "onServiceConnected " + name);
+        // Got a connection, set the binding count to 0.
+        mBindTryCount = 0;
+        mWrapper = new QSTileServiceWrapper(Stub.asInterface(service));
+        try {
+            service.linkToDeath(this, 0);
+        } catch (RemoteException e) {
+        }
+        setQSService(mService);
+        setQSTile(mTile);
+        handlePendingMessages();
+    }
+
+    @Override
+    public void onServiceDisconnected(ComponentName name) {
+        if (DEBUG) Log.d(TAG, "onServiceDisconnected " + name);
+        mWrapper = null;
+    }
+
+    private void handlePendingMessages() {
+        // This ordering is laid out manually to make sure we preserve the TileService
+        // lifecycle.
+        ArraySet<Integer> queue;
+        synchronized (mQueuedMessages) {
+            queue = new ArraySet<>(mQueuedMessages);
+            mQueuedMessages.clear();
+        }
+        if (queue.contains(MSG_ON_ADDED)) {
+            if (DEBUG) Log.d(TAG, "Handling pending onAdded");
+            onTileAdded();
+        }
+        if (mListening) {
+            if (DEBUG) Log.d(TAG, "Handling pending onStartListening");
+            onStartListening();
+        }
+        if (queue.contains(MSG_ON_CLICK)) {
+            if (DEBUG) Log.d(TAG, "Handling pending onClick");
+            if (!mListening) {
+                Log.w(TAG, "Managed to get click on non-listening state...");
+                // Skipping click since lost click privileges.
+            } else {
+                onClick(mClickBinder);
+            }
+        }
+        if (queue.contains(MSG_ON_UNLOCK_COMPLETE)) {
+            if (DEBUG) Log.d(TAG, "Handling pending onUnlockComplete");
+            if (!mListening) {
+                Log.w(TAG, "Managed to get unlock on non-listening state...");
+                // Skipping unlock since lost click privileges.
+            } else {
+                onUnlockComplete();
+            }
+        }
+        if (queue.contains(MSG_ON_REMOVED)) {
+            if (DEBUG) Log.d(TAG, "Handling pending onRemoved");
+            if (mListening) {
+                Log.w(TAG, "Managed to get remove in listening state...");
+                onStopListening();
+            }
+            onTileRemoved();
+        }
+        if (mUnbindImmediate) {
+            mUnbindImmediate = false;
+            setBindService(false);
+        }
+    }
+
+    public void handleDestroy() {
+        if (DEBUG) Log.d(TAG, "handleDestroy");
+        if (mReceiverRegistered) {
+            stopPackageListening();
+        }
+    }
+
+    private void handleDeath() {
+        if (mWrapper == null) return;
+        mWrapper = null;
+        if (!mBound) return;
+        if (DEBUG) Log.d(TAG, "handleDeath");
+        if (checkComponentState()) {
+            mHandler.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    if (mBound) {
+                        // Retry binding.
+                        setBindService(true);
+                    }
+                }
+            }, BIND_RETRY_DELAY);
+        }
+    }
+
+    @Override
+    public void setQSTile(Tile tile) {
+        if (DEBUG) Log.d(TAG, "setQSTile " + tile);
+        mTile = tile;
+        if (mWrapper != null && !mWrapper.setQSTile(tile)) {
+            handleDeath();
+        }
+    }
+
+    private boolean checkComponentState() {
+        PackageManager pm = mContext.getPackageManager();
+        if (!isPackageAvailable(pm) || !isComponentAvailable(pm)) {
+            startPackageListening();
+            return false;
+        }
+        return true;
+    }
+
+    private void startPackageListening() {
+        if (DEBUG) Log.d(TAG, "startPackageListening");
+        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        filter.addDataScheme("package");
+        mContext.registerReceiverAsUser(this, mUser, filter, null, mHandler);
+        mReceiverRegistered = true;
+    }
+
+    private void stopPackageListening() {
+        if (DEBUG) Log.d(TAG, "stopPackageListening");
+        mContext.unregisterReceiver(this);
+        mReceiverRegistered = false;
+    }
+
+    @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;
+        }
+        stopPackageListening();
+        if (mBound) {
+            // Trying to bind again will check the state of the package before bothering to bind.
+            if (DEBUG) Log.d(TAG, "Trying to rebind");
+            setBindService(true);
+        }
+    }
+
+    private boolean isComponentAvailable(PackageManager pm) {
+        String packageName = mIntent.getComponent().getPackageName();
+        try {
+            ServiceInfo si = AppGlobals.getPackageManager().getServiceInfo(mIntent.getComponent(),
+                    0, mUser.getIdentifier());
+            if (DEBUG && si == null) Log.d(TAG, "Can't find component " + mIntent.getComponent());
+            return si != null;
+        } catch (RemoteException e) {
+            // Shouldn't happen.
+        }
+        return false;
+    }
+
+    private boolean isPackageAvailable(PackageManager pm) {
+        String packageName = mIntent.getComponent().getPackageName();
+        try {
+            pm.getPackageInfoAsUser(packageName, 0, mUser.getIdentifier());
+            return true;
+        } catch (PackageManager.NameNotFoundException e) {
+            if (DEBUG) Log.d(TAG, "Package not available: " + packageName, e);
+            else Log.d(TAG, "Package not available: " + packageName);
+        }
+        return false;
+    }
+
+    private void queueMessage(int message) {
+        synchronized (mQueuedMessages) {
+            mQueuedMessages.add(message);
+        }
+    }
+
+    @Override
+    public void setQSService(IQSService service) {
+        mService = service;
+        if (mWrapper == null || !mWrapper.setQSService(service)) {
+            handleDeath();
+        }
+    }
+
+    @Override
+    public void onTileAdded() {
+        if (DEBUG) Log.d(TAG, "onTileAdded");
+        if (mWrapper == null || !mWrapper.onTileAdded()) {
+            queueMessage(MSG_ON_ADDED);
+            handleDeath();
+        }
+    }
+
+    @Override
+    public void onTileRemoved() {
+        if (DEBUG) Log.d(TAG, "onTileRemoved");
+        if (mWrapper == null || !mWrapper.onTileRemoved()) {
+            queueMessage(MSG_ON_REMOVED);
+            handleDeath();
+        }
+    }
+
+    @Override
+    public void onStartListening() {
+        if (DEBUG) Log.d(TAG, "onStartListening");
+        mListening = true;
+        if (mWrapper != null && !mWrapper.onStartListening()) {
+            handleDeath();
+        }
+    }
+
+    @Override
+    public void onStopListening() {
+        if (DEBUG) Log.d(TAG, "onStopListening");
+        mListening = false;
+        if (mWrapper != null && !mWrapper.onStopListening()) {
+            handleDeath();
+        }
+    }
+
+    @Override
+    public void onClick(IBinder iBinder) {
+        if (DEBUG) Log.d(TAG, "onClick " + iBinder);
+        if (mWrapper == null || !mWrapper.onClick(iBinder)) {
+            mClickBinder = iBinder;
+            queueMessage(MSG_ON_CLICK);
+            handleDeath();
+        }
+    }
+
+    @Override
+    public void onUnlockComplete() {
+        if (DEBUG) Log.d(TAG, "onUnlockComplete");
+        if (mWrapper == null || !mWrapper.onUnlockComplete()) {
+            queueMessage(MSG_ON_UNLOCK_COMPLETE);
+            handleDeath();
+        }
+    }
+
+    @Override
+    public IBinder asBinder() {
+        return mWrapper != null ? mWrapper.asBinder() : null;
+    }
+
+    @Override
+    public void binderDied() {
+        if (DEBUG) Log.d(TAG, "binderDeath");
+        handleDeath();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
new file mode 100644
index 0000000..2f77a30
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.external;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.service.quicksettings.IQSTileService;
+import android.service.quicksettings.TileService;
+import android.support.annotation.VisibleForTesting;
+import android.util.Log;
+
+/**
+ * Manages the priority which lets {@link TileServices} make decisions about which tiles
+ * to bind.  Also holds on to and manages the {@link TileLifecycleManager}, informing it
+ * of when it is allowed to bind based on decisions frome the {@link TileServices}.
+ */
+public class TileServiceManager {
+
+    private static final long MIN_BIND_TIME = 5000;
+    private static final long UNBIND_DELAY = 30000;
+
+    public static final boolean DEBUG = true;
+
+    private static final String TAG = "TileServiceManager";
+
+    @VisibleForTesting
+    static final String PREFS_FILE = "CustomTileModes";
+
+    private final TileServices mServices;
+    private final TileLifecycleManager mStateManager;
+    private final Handler mHandler;
+    private boolean mBindRequested;
+    private boolean mBindAllowed;
+    private boolean mBound;
+    private int mPriority;
+    private boolean mJustBound;
+    private long mLastUpdate;
+    private int mType;
+
+    TileServiceManager(TileServices tileServices, Handler handler, ComponentName component) {
+        this(tileServices, handler, new TileLifecycleManager(handler,
+                tileServices.getContext(), new Intent().setComponent(component),
+                new UserHandle(ActivityManager.getCurrentUser())));
+    }
+
+    @VisibleForTesting
+    TileServiceManager(TileServices tileServices, Handler handler,
+            TileLifecycleManager tileLifecycleManager) {
+        mServices = tileServices;
+        mHandler = handler;
+        mStateManager = tileLifecycleManager;
+        mType = tileServices.getContext().getSharedPreferences(PREFS_FILE, 0)
+                .getInt(tileLifecycleManager.getComponent().flattenToString(),
+                        TileService.TILE_MODE_UNSET);
+        mStateManager.setQSService(tileServices);
+        if (mType == TileService.TILE_MODE_UNSET) {
+            bindService();
+            mStateManager.onTileAdded();
+        }
+    }
+
+    public int getType() {
+        return mType;
+    }
+
+    public void setType(int type) {
+        mServices.getContext().getSharedPreferences(PREFS_FILE, 0).edit()
+                .putInt(mStateManager.getComponent().flattenToString(), type).commit();
+        mType = type;
+        mServices.recalculateBindAllowance();
+    }
+
+    public IQSTileService getTileService() {
+        return mStateManager;
+    }
+
+    public void setBindRequested(boolean bindRequested) {
+        if (mBindRequested == bindRequested) return;
+        mBindRequested = bindRequested;
+        if (mBindAllowed && mBindRequested && !mBound) {
+            mHandler.removeCallbacks(mUnbind);
+            bindService();
+        } else {
+            mServices.recalculateBindAllowance();
+        }
+        if (mBound && !mBindRequested) {
+            mHandler.postDelayed(mUnbind, UNBIND_DELAY);
+        }
+    }
+
+    public void setLastUpdate(long lastUpdate) {
+        mLastUpdate = lastUpdate;
+        if (mBound && mType == TileService.TILE_MODE_ACTIVE) {
+            mStateManager.onStopListening();
+            setBindRequested(false);
+        }
+        mServices.recalculateBindAllowance();
+    }
+
+    public void handleDestroy() {
+        mStateManager.handleDestroy();
+    }
+
+    public void setBindAllowed(boolean allowed) {
+        if (mBindAllowed == allowed) return;
+        mBindAllowed = allowed;
+        if (!mBindAllowed && mBound) {
+            unbindService();
+        } else if (mBindAllowed && mBindRequested && !mBound) {
+            bindService();
+        }
+    }
+
+    private void bindService() {
+        if (mBound) {
+            Log.e(TAG, "Service already bound");
+            return;
+        }
+        mBound = true;
+        mJustBound = true;
+        mHandler.postDelayed(mJustBoundOver, MIN_BIND_TIME);
+        mStateManager.setBindService(true);
+    }
+
+    private void unbindService() {
+        if (!mBound) {
+            Log.e(TAG, "Service not bound");
+            return;
+        }
+        mBound = false;
+        mJustBound = false;
+        mStateManager.setBindService(false);
+    }
+
+    public void calculateBindPriority(long currentTime) {
+        if (mStateManager.hasPendingClick()) {
+            // Pending click is the most important thing, need to put this service at the top of
+            // the list to be bound.
+            mPriority = Integer.MAX_VALUE;
+        } else if (mJustBound) {
+            // If we just bound, lets not thrash on binding/unbinding too much, this is second most
+            // important.
+            mPriority = Integer.MAX_VALUE - 1;
+        } else if (!mBindRequested) {
+            // Don't care about binding right now, put us last.
+            mPriority = Integer.MIN_VALUE;
+        } else {
+            // Order based on whether this was just updated.
+            long timeSinceUpdate = currentTime - mLastUpdate;
+            // Fit compare into integer space for simplicity. Make sure to leave MAX_VALUE and
+            // MAX_VALUE - 1 for the more important states above.
+            if (timeSinceUpdate > Integer.MAX_VALUE - 2) {
+                mPriority = Integer.MAX_VALUE - 2;
+            } else {
+                mPriority = (int) timeSinceUpdate;
+            }
+        }
+    }
+
+    public int getBindPriority() {
+        return mPriority;
+    }
+
+    private final Runnable mUnbind = new Runnable() {
+        @Override
+        public void run() {
+            if (mBound && !mBindRequested) {
+                unbindService();
+            }
+        }
+    };
+
+    @VisibleForTesting
+    final Runnable mJustBoundOver = new Runnable() {
+        @Override
+        public void run() {
+            mJustBound = false;
+            mServices.recalculateBindAllowance();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
new file mode 100644
index 0000000..44d8776
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.external;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Icon;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.quicksettings.IQSService;
+import android.service.quicksettings.Tile;
+import android.service.quicksettings.TileService;
+import android.util.ArrayMap;
+import android.util.Log;
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+/**
+ * Runs the day-to-day operations of which tiles should be bound and when.
+ */
+public class TileServices extends IQSService.Stub {
+    static final int DEFAULT_MAX_BOUND = 3;
+    static final int REDUCED_MAX_BOUND = 1;
+
+    private final ArrayMap<CustomTile, TileServiceManager> mServices = new ArrayMap<>();
+    private final ArrayMap<ComponentName, CustomTile> mTiles = new ArrayMap<>();
+    private final Context mContext;
+    private final Handler mHandler;
+    private final Handler mMainHandler;
+    private final QSTileHost mHost;
+
+    private int mMaxBound = DEFAULT_MAX_BOUND;
+
+    public TileServices(QSTileHost host, Looper looper) {
+        mHost = host;
+        mContext = mHost.getContext();
+        mContext.registerReceiver(mRequestListeningReceiver,
+                new IntentFilter(TileService.ACTION_REQUEST_LISTENING));
+        mHandler = new Handler(looper);
+        mMainHandler = new Handler(Looper.getMainLooper());
+    }
+
+    public Context getContext() {
+        return mContext;
+    }
+
+    public TileServiceManager getTileWrapper(CustomTile tile) {
+        ComponentName component = tile.getComponent();
+        TileServiceManager service = onCreateTileService(component);
+        synchronized (mServices) {
+            mServices.put(tile, service);
+            mTiles.put(component, tile);
+        }
+        return service;
+    }
+
+    protected TileServiceManager onCreateTileService(ComponentName component) {
+        return new TileServiceManager(this, mHandler, component);
+    }
+
+    public void freeService(CustomTile tile, TileServiceManager service) {
+        synchronized (mServices) {
+            service.setBindAllowed(false);
+            mServices.remove(tile);
+            mTiles.remove(tile.getComponent());
+            final String slot = tile.getComponent().getClassName();
+            mMainHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mHost.getIconController().removeIcon(slot);
+                }
+            });
+        }
+    }
+
+    public void setMemoryPressure(boolean memoryPressure) {
+        mMaxBound = memoryPressure ? REDUCED_MAX_BOUND : DEFAULT_MAX_BOUND;
+        recalculateBindAllowance();
+    }
+
+    public void recalculateBindAllowance() {
+        final ArrayList<TileServiceManager> services;
+        synchronized (mServices) {
+            services = new ArrayList<>(mServices.values());
+        }
+        final int N = services.size();
+        if (N > mMaxBound) {
+            long currentTime = System.currentTimeMillis();
+            // Precalculate the priority of services for binding.
+            for (int i = 0; i < N; i++) {
+                services.get(i).calculateBindPriority(currentTime);
+            }
+            // Sort them so we can bind the most important first.
+            Collections.sort(services, SERVICE_SORT);
+        }
+        int i;
+        // Allow mMaxBound items to bind.
+        for (i = 0; i < mMaxBound && i < N; i++) {
+            services.get(i).setBindAllowed(true);
+        }
+        // The rest aren't allowed to bind for now.
+        while (i < N) {
+            services.get(i).setBindAllowed(false);
+            i++;
+        }
+    }
+
+    private void verifyCaller(String packageName) {
+        try {
+            int uid = mContext.getPackageManager().getPackageUidAsUser(packageName,
+                    Binder.getCallingUserHandle().getIdentifier());
+            if (Binder.getCallingUid() != uid) {
+                throw new SecurityException("Component outside caller's uid");
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new SecurityException(e);
+        }
+    }
+
+    private void requestListening(ComponentName component) {
+        synchronized (mServices) {
+            CustomTile customTile = getTileForComponent(component);
+            if (customTile == null) {
+                Log.d("TileServices", "Couldn't find tile for " + component);
+                return;
+            }
+            TileServiceManager service = mServices.get(customTile);
+            if (service.getType() != TileService.TILE_MODE_ACTIVE) {
+                return;
+            }
+            service.setBindRequested(true);
+            try {
+                service.getTileService().onStartListening();
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    @Override
+    public void setTileMode(ComponentName component, int mode) {
+        verifyCaller(component.getPackageName());
+        CustomTile customTile = getTileForComponent(component);
+        if (customTile != null) {
+            synchronized (mServices) {
+                mServices.get(customTile).setType(mode);
+            }
+        }
+    }
+
+    @Override
+    public void updateQsTile(Tile tile) {
+        ComponentName componentName = tile.getComponentName();
+        verifyCaller(componentName.getPackageName());
+        CustomTile customTile = getTileForComponent(componentName);
+        if (customTile != null) {
+            synchronized (mServices) {
+                mServices.get(customTile).setLastUpdate(System.currentTimeMillis());
+            }
+            customTile.updateState(tile);
+            customTile.refreshState();
+        }
+    }
+
+    @Override
+    public void onShowDialog(Tile tile) {
+        ComponentName componentName = tile.getComponentName();
+        verifyCaller(componentName.getPackageName());
+        CustomTile customTile = getTileForComponent(componentName);
+        if (customTile != null) {
+            customTile.onDialogShown();
+            mHost.collapsePanels();
+        }
+    }
+
+    @Override
+    public void onStartActivity(Tile tile) {
+        ComponentName componentName = tile.getComponentName();
+        verifyCaller(componentName.getPackageName());
+        CustomTile customTile = getTileForComponent(componentName);
+        if (customTile != null) {
+            mHost.collapsePanels();
+        }
+    }
+
+    @Override
+    public void updateStatusIcon(Tile tile, Icon icon, String contentDescription) {
+        final ComponentName componentName = tile.getComponentName();
+        String packageName = componentName.getPackageName();
+        verifyCaller(packageName);
+        CustomTile customTile = getTileForComponent(componentName);
+        if (customTile != null) {
+            try {
+                UserHandle userHandle = getCallingUserHandle();
+                PackageInfo info = mContext.getPackageManager().getPackageInfoAsUser(packageName, 0,
+                        userHandle.getIdentifier());
+                if (info.applicationInfo.isSystemApp()) {
+                    final StatusBarIcon statusIcon = icon != null
+                            ? new StatusBarIcon(userHandle, packageName, icon, 0, 0,
+                                    contentDescription)
+                            : null;
+                    mMainHandler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            StatusBarIconController iconController = mHost.getIconController();
+                            iconController.setIcon(componentName.getClassName(), statusIcon);
+                            iconController.setExternalIcon(componentName.getClassName());
+                        }
+                    });
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+            }
+        }
+    }
+
+    @Override
+    public void startUnlockAndRun(Tile tile) {
+        ComponentName componentName = tile.getComponentName();
+        verifyCaller(componentName.getPackageName());
+        CustomTile customTile = getTileForComponent(componentName);
+        if (customTile != null) {
+            customTile.startUnlockAndRun();
+        }
+    }
+
+    @Override
+    public boolean isLocked() {
+        KeyguardMonitor keyguardMonitor = mHost.getKeyguardMonitor();
+        return keyguardMonitor.isShowing();
+    }
+
+    @Override
+    public boolean isSecure() {
+        KeyguardMonitor keyguardMonitor = mHost.getKeyguardMonitor();
+        return keyguardMonitor.isSecure() && keyguardMonitor.isShowing();
+    }
+
+    private CustomTile getTileForComponent(ComponentName component) {
+        synchronized (mServices) {
+            return mTiles.get(component);
+        }
+    }
+
+    private final BroadcastReceiver mRequestListeningReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (TileService.ACTION_REQUEST_LISTENING.equals(intent.getAction())) {
+                requestListening(
+                        (ComponentName) intent.getParcelableExtra(TileService.EXTRA_COMPONENT));
+            }
+        }
+    };
+
+    private static final Comparator<TileServiceManager> SERVICE_SORT =
+            new Comparator<TileServiceManager>() {
+        @Override
+        public int compare(TileServiceManager left, TileServiceManager right) {
+            return -Integer.compare(left.getBindPriority(), right.getBindPriority());
+        }
+    };
+}
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 fc802dd..d78d6ff 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -24,6 +24,7 @@
 import android.provider.Settings.Global;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.qs.GlobalSetting;
 import com.android.systemui.qs.QSTile;
@@ -58,8 +59,6 @@
     public void handleClick() {
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
         setEnabled(!mState.value);
-        mEnable.setAllowAnimation(true);
-        mDisable.setAllowAnimation(true);
     }
 
     private void setEnabled(boolean enabled) {
@@ -87,7 +86,7 @@
 
     @Override
     public int getMetricsCategory() {
-        return MetricsLogger.QS_AIRPLANEMODE;
+        return MetricsEvent.QS_AIRPLANEMODE;
     }
 
     @Override
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 84eac65..fd8857d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -19,7 +19,14 @@
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
-import com.android.internal.logging.MetricsLogger;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Checkable;
+import android.widget.ImageView;
+import android.widget.TextView;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.settingslib.BatteryInfo;
 import com.android.systemui.BatteryMeterDrawable;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
@@ -31,8 +38,11 @@
 
     private final BatteryMeterDrawable mDrawable;
     private final BatteryController mBatteryController;
+    private final BatteryDetail mBatteryDetail = new BatteryDetail();
 
     private int mLevel;
+    private boolean mPowerSave;
+    private boolean mCharging;
 
     public BatteryTile(Host host) {
         super(host);
@@ -48,8 +58,13 @@
     }
 
     @Override
+    public DetailAdapter getDetailAdapter() {
+        return mBatteryDetail;
+    }
+
+    @Override
     public int getMetricsCategory() {
-        return MetricsLogger.QS_BATTERY_TILE;
+        return MetricsEvent.QS_BATTERY_TILE;
     }
 
     @Override
@@ -64,8 +79,16 @@
     }
 
     @Override
+    public void setDetailListening(boolean listening) {
+        super.setDetailListening(listening);
+        if (!listening) {
+            mBatteryDetail.mCurrentView = null;
+        }
+    }
+
+    @Override
     protected void handleClick() {
-        mHost.startActivityDismissingKeyguard(new Intent(Intent.ACTION_POWER_USAGE_SUMMARY));
+        showDetail(true);
     }
 
     @Override
@@ -85,11 +108,98 @@
     @Override
     public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
         mLevel = level;
+        mCharging = charging;
         refreshState((Integer) level);
+        if (mBatteryDetail.mCurrentView != null) {
+            mBatteryDetail.bindView();
+        }
     }
 
     @Override
-    public void onPowerSaveChanged() {
+    public void onPowerSaveChanged(boolean isPowerSave) {
+        mPowerSave = isPowerSave;
+        if (mBatteryDetail.mCurrentView != null) {
+            mBatteryDetail.bindView();
+        }
+    }
 
+    private final class BatteryDetail implements DetailAdapter, View.OnClickListener {
+        private final BatteryMeterDrawable mDrawable = new BatteryMeterDrawable(mHost.getContext(),
+                new Handler(), mHost.getContext().getColor(R.color.batterymeter_frame_color));
+        private View mCurrentView;
+
+        @Override
+        public CharSequence getTitle() {
+            return mContext.getString(R.string.battery_panel_title, mLevel);
+        }
+
+        @Override
+        public Boolean getToggleState() {
+            return null;
+        }
+
+        @Override
+        public View createDetailView(Context context, View convertView, ViewGroup parent) {
+            if (convertView == null) {
+                convertView = LayoutInflater.from(mContext).inflate(R.layout.battery_detail, parent,
+                        false);
+            }
+            mCurrentView = convertView;
+            bindView();
+            return convertView;
+        }
+
+        private void bindView() {
+            mDrawable.onBatteryLevelChanged(100, false, false);
+            mDrawable.onPowerSaveChanged(true);
+            ((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 && mCharging) {
+                            ((TextView) mCurrentView.findViewById(android.R.id.title)).setText(
+                                    info.mChargeLabelString);
+                        }
+                    }
+                });
+                ((TextView) mCurrentView.findViewById(android.R.id.summary)).setText(
+                        R.string.battery_detail_charging_summary);
+                mCurrentView.setClickable(false);
+                mCurrentView.findViewById(android.R.id.icon).setVisibility(View.INVISIBLE);
+                mCurrentView.findViewById(android.R.id.toggle).setVisibility(View.INVISIBLE);
+            } else {
+                ((TextView) mCurrentView.findViewById(android.R.id.title)).setText(
+                        R.string.battery_detail_switch_title);
+                ((TextView) mCurrentView.findViewById(android.R.id.summary)).setText(
+                        R.string.battery_detail_switch_summary);
+                mCurrentView.setClickable(true);
+                mCurrentView.findViewById(android.R.id.icon).setVisibility(View.VISIBLE);
+                mCurrentView.findViewById(android.R.id.toggle).setVisibility(View.VISIBLE);
+                mCurrentView.setOnClickListener(this);
+            }
+        }
+
+        @Override
+        public void onClick(View v) {
+            mBatteryController.setPowerSaveMode(!mPowerSave);
+        }
+
+        @Override
+        public Intent getSettingsIntent() {
+            return new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
+        }
+
+        @Override
+        public void setToggleState(boolean state) {
+            // No toggle state.
+        }
+
+        @Override
+        public int getMetricsCategory() {
+            return MetricsEvent.QS_BATTERY_DETAIL;
+        }
     }
 }
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 cfc09a0..dbb7423 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -24,7 +24,9 @@
 import android.text.TextUtils;
 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.bluetooth.CachedBluetoothDevice;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSDetailItems;
@@ -76,6 +78,10 @@
 
     @Override
     protected void handleClick() {
+        if (!mController.canConfigBluetooth()) {
+            mHost.startActivityDismissingKeyguard(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
+            return;
+        }
         if (!mState.value) {
             mState.value = true;
             mController.setBluetoothEnabled(true);
@@ -127,7 +133,7 @@
 
     @Override
     public int getMetricsCategory() {
-        return MetricsLogger.QS_BLUETOOTH;
+        return MetricsEvent.QS_BLUETOOTH;
     }
 
     @Override
@@ -165,8 +171,8 @@
         private QSDetailItems mItems;
 
         @Override
-        public int getTitle() {
-            return R.string.quick_settings_bluetooth_label;
+        public CharSequence getTitle() {
+            return mContext.getString(R.string.quick_settings_bluetooth_label);
         }
 
         @Override
@@ -181,14 +187,14 @@
 
         @Override
         public void setToggleState(boolean state) {
-            MetricsLogger.action(mContext, MetricsLogger.QS_BLUETOOTH_TOGGLE, state);
+            MetricsLogger.action(mContext, MetricsEvent.QS_BLUETOOTH_TOGGLE, state);
             mController.setBluetoothEnabled(state);
             showDetail(false);
         }
 
         @Override
         public int getMetricsCategory() {
-            return MetricsLogger.QS_BLUETOOTH_DETAILS;
+            return MetricsEvent.QS_BLUETOOTH_DETAILS;
         }
 
         @Override
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 a8e139c..18eb7a1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -23,7 +23,9 @@
 import android.view.View;
 import android.view.View.OnAttachStateChangeListener;
 import android.view.ViewGroup;
+
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSDetailItems;
 import com.android.systemui.qs.QSDetailItems.Item;
@@ -125,7 +127,7 @@
 
     @Override
     public int getMetricsCategory() {
-        return MetricsLogger.QS_CAST;
+        return MetricsEvent.QS_CAST;
     }
 
     @Override
@@ -160,8 +162,8 @@
         private QSDetailItems mItems;
 
         @Override
-        public int getTitle() {
-            return R.string.quick_settings_cast_title;
+        public CharSequence getTitle() {
+            return mContext.getString(R.string.quick_settings_cast_title);
         }
 
         @Override
@@ -181,7 +183,7 @@
 
         @Override
         public int getMetricsCategory() {
-            return MetricsLogger.QS_CAST_DETAILS;
+            return MetricsEvent.QS_CAST_DETAILS;
         }
 
         @Override
@@ -255,7 +257,7 @@
         @Override
         public void onDetailItemClick(Item item) {
             if (item == null || item.tag == null) return;
-            MetricsLogger.action(mContext, MetricsLogger.QS_CAST_SELECT);
+            MetricsLogger.action(mContext, MetricsEvent.QS_CAST_SELECT);
             final CastDevice device = (CastDevice) item.tag;
             mController.startCasting(device);
         }
@@ -263,7 +265,7 @@
         @Override
         public void onDetailItemDisconnect(Item item) {
             if (item == null || item.tag == null) return;
-            MetricsLogger.action(mContext, MetricsLogger.QS_CAST_DISCONNECT);
+            MetricsLogger.action(mContext, MetricsEvent.QS_CAST_DISCONNECT);
             final CastDevice device = (CastDevice) item.tag;
             mController.stopCasting(device);
         }
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 6c7b337..aacdbc9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -23,8 +23,10 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+
 import com.android.internal.logging.MetricsLogger;
-import com.android.settingslib.net.MobileDataController;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.settingslib.net.DataUsageController;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSIconView;
 import com.android.systemui.qs.QSTile;
@@ -39,7 +41,7 @@
             "com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity"));
 
     private final NetworkController mController;
-    private final MobileDataController mDataController;
+    private final DataUsageController mDataController;
     private final CellularDetailAdapter mDetailAdapter;
 
     private final CellSignalCallback mSignalCallback = new CellSignalCallback();
@@ -89,7 +91,7 @@
     protected void handleSecondaryClick() {
         boolean dataEnabled = mDataController.isMobileDataSupported()
                 && mDataController.isMobileDataEnabled();
-        MetricsLogger.action(mContext, MetricsLogger.QS_CELLULAR_TOGGLE, !dataEnabled);
+        MetricsLogger.action(mContext, MetricsEvent.QS_CELLULAR_TOGGLE, !dataEnabled);
         mDataController.setMobileDataEnabled(!dataEnabled);
     }
 
@@ -131,7 +133,7 @@
 
     @Override
     public int getMetricsCategory() {
-        return MetricsLogger.QS_CELLULAR;
+        return MetricsEvent.QS_CELLULAR;
     }
 
     // Remove the period from the network name
@@ -223,8 +225,8 @@
     private final class CellularDetailAdapter implements DetailAdapter {
 
         @Override
-        public int getTitle() {
-            return R.string.quick_settings_cellular_detail_title;
+        public CharSequence getTitle() {
+            return mContext.getString(R.string.quick_settings_cellular_detail_title);
         }
 
         @Override
@@ -241,13 +243,13 @@
 
         @Override
         public void setToggleState(boolean state) {
-            MetricsLogger.action(mContext, MetricsLogger.QS_CELLULAR_TOGGLE, state);
+            MetricsLogger.action(mContext, MetricsEvent.QS_CELLULAR_TOGGLE, state);
             mDataController.setMobileDataEnabled(state);
         }
 
         @Override
         public int getMetricsCategory() {
-            return MetricsLogger.QS_DATAUSAGEDETAIL;
+            return MetricsEvent.QS_DATAUSAGEDETAIL;
         }
 
         @Override
@@ -255,7 +257,7 @@
             final DataUsageDetailView v = (DataUsageDetailView) (convertView != null
                     ? convertView
                     : LayoutInflater.from(mContext).inflate(R.layout.data_usage, parent, false));
-            final MobileDataController.DataUsageInfo info = mDataController.getDataUsageInfo();
+            final DataUsageController.DataUsageInfo info = mDataController.getDataUsageInfo();
             if (info == null) return v;
             v.bind(info);
             return v;
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 f73ee35..6e843e9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -17,7 +17,9 @@
 package com.android.systemui.qs.tiles;
 
 import android.provider.Settings.Secure;
+
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.SecureSetting;
@@ -71,8 +73,6 @@
     protected void handleClick() {
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
         mSetting.setValue(mState.value ? 0 : 1);
-        mEnable.setAllowAnimation(true);
-        mDisable.setAllowAnimation(true);
     }
 
     @Override
@@ -86,7 +86,7 @@
 
     @Override
     public int getMetricsCategory() {
-        return MetricsLogger.QS_COLORINVERSION;
+        return MetricsEvent.QS_COLORINVERSION;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomTile.java
deleted file mode 100644
index bb74f34..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomTile.java
+++ /dev/null
@@ -1,236 +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.qs.tiles;
-
-import android.app.ActivityManager;
-import android.app.Service;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.content.pm.ServiceInfo;
-import android.graphics.drawable.Drawable;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.service.quicksettings.IQSTileService;
-import android.service.quicksettings.Tile;
-import android.util.Log;
-import android.view.IWindowManager;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
-import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.QSTileServiceWrapper;
-import com.android.systemui.statusbar.phone.QSTileHost;
-
-public class CustomTile extends QSTile<QSTile.State> {
-    public static final String PREFIX = "custom(";
-
-    private static final boolean DEBUG = false;
-
-    // We don't want to thrash binding and unbinding if the user opens and closes the panel a lot.
-    // So instead we have a period of waiting.
-    private static final long UNBIND_DELAY = 30000;
-
-    private final ComponentName mComponent;
-    private final Tile mTile;
-    private final IWindowManager mWindowManager;
-    private final IBinder mToken = new Binder();
-
-    private QSTileServiceWrapper mService;
-    private boolean mListening;
-    private boolean mBound;
-    private boolean mIsTokenGranted;
-    private boolean mIsShowingDialog;
-
-    private CustomTile(QSTileHost host, String action) {
-        super(host);
-        mWindowManager = WindowManagerGlobal.getWindowManagerService();
-        mComponent = ComponentName.unflattenFromString(action);
-        mTile = new Tile(mComponent, host);
-        try {
-            PackageManager pm = mContext.getPackageManager();
-            ServiceInfo info = pm.getServiceInfo(mComponent, 0);
-            mTile.setIcon(android.graphics.drawable.Icon
-                    .createWithResource(mComponent.getPackageName(), info.icon));
-            mTile.setLabel(info.loadLabel(pm));
-        } catch (Exception e) {
-        }
-    }
-
-    public ComponentName getComponent() {
-        return mComponent;
-    }
-
-    public Tile getQsTile() {
-        return mTile;
-    }
-
-    public void updateState(Tile tile) {
-        mTile.setIcon(tile.getIcon());
-        mTile.setLabel(tile.getLabel());
-        mTile.setContentDescription(tile.getContentDescription());
-    }
-
-    public void onDialogShown() {
-        mIsShowingDialog = true;
-    }
-
-    @Override
-    public void setListening(boolean listening) {
-        if (mListening == listening) return;
-        mListening = listening;
-        if (listening) {
-            mHandler.removeCallbacks(mUnbind);
-            if (!mBound) {
-                // TODO: Guarantee re-bind on user-switch.
-                mContext.bindServiceAsUser(new Intent().setComponent(mComponent),
-                        mServiceConnection, Service.BIND_AUTO_CREATE,
-                        new UserHandle(ActivityManager.getCurrentUser()));
-                mBound = true;
-            } else {
-                if (mService != null) {
-                    mService.onStartListening();
-                } else {
-                    Log.d(TAG, "Can't start service listening");
-                }
-            }
-        } else {
-            if (mService != null) {
-                mService.onStopListening();
-            }
-            if (mIsTokenGranted && !mIsShowingDialog) {
-                try {
-                    if (DEBUG) Log.d(TAG, "Removing token");
-                    mWindowManager.removeWindowToken(mToken);
-                } catch (RemoteException e) {
-                }
-                mIsTokenGranted = false;
-            }
-            mIsShowingDialog = false;
-            mHandler.postDelayed(mUnbind, UNBIND_DELAY);
-        }
-    }
-
-    @Override
-    protected void handleDestroy() {
-        super.handleDestroy();
-        mHandler.removeCallbacks(mUnbind);
-        if (mIsTokenGranted) {
-            try {
-                if (DEBUG) Log.d(TAG, "Removing token");
-                mWindowManager.removeWindowToken(mToken);
-            } catch (RemoteException e) {
-            }
-        }
-        mUnbind.run();
-    }
-
-    @Override
-    protected State newTileState() {
-        return new State();
-    }
-
-    @Override
-    protected void handleUserSwitch(int newUserId) {
-        super.handleUserSwitch(newUserId);
-    }
-
-    @Override
-    protected void handleClick() {
-        if (mService != null) {
-            try {
-                if (DEBUG) Log.d(TAG, "Adding token");
-                mWindowManager.addWindowToken(mToken, WindowManager.LayoutParams.TYPE_QS_DIALOG);
-                mIsTokenGranted = true;
-            } catch (RemoteException e) {
-            }
-            mService.onClick(mToken);
-        } else {
-            Log.e(TAG, "Click with no service " + getTileSpec());
-        }
-        MetricsLogger.action(mContext, getMetricsCategory(), mComponent.getPackageName());
-    }
-
-    @Override
-    protected void handleLongClick() {
-    }
-
-    @Override
-    protected void handleUpdateState(State state, Object arg) {
-        Drawable drawable = mTile.getIcon().loadDrawable(mContext);
-        drawable.setTint(mContext.getColor(android.R.color.white));
-        state.icon = new DrawableIcon(drawable);
-        state.label = mTile.getLabel();
-        if (mTile.getContentDescription() != null) {
-            state.contentDescription = mTile.getContentDescription();
-        } else {
-            state.contentDescription = state.label;
-        }
-    }
-
-    @Override
-    public int getMetricsCategory() {
-        return MetricsLogger.QS_INTENT;
-    }
-
-    private final ServiceConnection mServiceConnection = new ServiceConnection() {
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            mService = new QSTileServiceWrapper(IQSTileService.Stub.asInterface(service));
-            if (mListening) {
-                mService.setQSTile(mTile);
-                mService.onStartListening();
-            } else {
-                mService.onStopListening();
-            }
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-        }
-    };
-
-    private final Runnable mUnbind = new Runnable() {
-        @Override
-        public void run() {
-            mContext.unbindService(mServiceConnection);
-            mBound = false;
-        }
-    };
-
-    public static ComponentName getComponentFromSpec(String spec) {
-        final String action = spec.substring(PREFIX.length(), spec.length() - 1);
-        if (action.isEmpty()) {
-            throw new IllegalArgumentException("Empty custom tile spec action");
-        }
-        return ComponentName.unflattenFromString(action);
-    }
-
-    public static QSTile<?> create(QSTileHost host, String spec) {
-        if (spec == null || !spec.startsWith(PREFIX) || !spec.endsWith(")")) {
-            throw new IllegalArgumentException("Bad custom tile spec: " + spec);
-        }
-        final String action = spec.substring(PREFIX.length(), spec.length() - 1);
-        if (action.isEmpty()) {
-            throw new IllegalArgumentException("Empty custom tile spec action");
-        }
-        return new CustomTile(host, action);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
new file mode 100644
index 0000000..1aeb0fe
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.DataSaverController;
+
+public class DataSaverTile extends QSTile<QSTile.BooleanState> implements
+        DataSaverController.Listener{
+
+    private final DataSaverController mDataSaverController;
+
+    public DataSaverTile(Host host) {
+        super(host);
+        mDataSaverController = host.getNetworkController().getDataSaverController();
+    }
+
+    @Override
+    protected BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    public void setListening(boolean listening) {
+        if (listening) {
+            mDataSaverController.addListener(this);
+        } else {
+            mDataSaverController.remListener(this);
+        }
+    }
+
+    @Override
+    protected void handleClick() {
+        mState.value = !mDataSaverController.isDataSaverEnabled();
+        mDataSaverController.setDataSaverEnabled(mState.value);
+        refreshState(mState.value);
+    }
+
+    @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.icon = ResourceIcon.get(state.value ? R.drawable.ic_data_saver
+                : R.drawable.ic_data_saver_off);
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsEvent.QS_DATA_SAVER;
+    }
+
+    @Override
+    public void onDataSaverChanged(boolean isDataSaving) {
+        refreshState(isDataSaving);
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
index d814b1c2..2be43c0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
@@ -23,7 +23,7 @@
 import android.view.View;
 import android.widget.LinearLayout;
 import android.widget.TextView;
-import com.android.settingslib.net.MobileDataController;
+import com.android.settingslib.net.DataUsageController;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
 import com.android.systemui.qs.DataUsageGraph;
@@ -59,7 +59,7 @@
                 R.dimen.qs_data_usage_text_size);
     }
 
-    public void bind(MobileDataController.DataUsageInfo info) {
+    public void bind(DataUsageController.DataUsageInfo info) {
         final Resources res = mContext.getResources();
         final int titleId;
         final long bytes;
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 d96f735..1f9f1c4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -22,6 +22,7 @@
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.view.LayoutInflater;
@@ -29,7 +30,9 @@
 import android.view.View.OnAttachStateChangeListener;
 import android.view.ViewGroup;
 import android.widget.Toast;
+
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.SysUIToast;
@@ -99,16 +102,6 @@
 
     @Override
     public void handleClick() {
-        if (mController.isVolumeRestricted()) {
-            // Collapse the panels, so the user can see the toast.
-            mHost.collapsePanels();
-            SysUIToast.makeText(mContext, mContext.getString(
-                    com.android.internal.R.string.error_message_change_not_allowed),
-                    Toast.LENGTH_LONG).show();
-            return;
-        }
-        mDisable.setAllowAnimation(true);
-        mDisableTotalSilence.setAllowAnimation(true);
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
         if (mState.value) {
             mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
@@ -125,6 +118,8 @@
         final boolean newValue = zen != Global.ZEN_MODE_OFF;
         final boolean valueChanged = state.value != newValue;
         state.value = newValue;
+        state.disabledByPolicy = mController.isVolumeRestricted();
+        checkIfRestrictionEnforced(state, UserManager.DISALLOW_ADJUST_VOLUME);
         switch (zen) {
             case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
                 state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
@@ -161,7 +156,7 @@
 
     @Override
     public int getMetricsCategory() {
-        return MetricsLogger.QS_DND;
+        return MetricsEvent.QS_DND;
     }
 
     @Override
@@ -220,8 +215,8 @@
     private final class DndDetailAdapter implements DetailAdapter, OnAttachStateChangeListener {
 
         @Override
-        public int getTitle() {
-            return R.string.quick_settings_dnd_label;
+        public CharSequence getTitle() {
+            return mContext.getString(R.string.quick_settings_dnd_label);
         }
 
         @Override
@@ -236,7 +231,7 @@
 
         @Override
         public void setToggleState(boolean state) {
-            MetricsLogger.action(mContext, MetricsLogger.QS_DND_TOGGLE, state);
+            MetricsLogger.action(mContext, MetricsEvent.QS_DND_TOGGLE, state);
             if (!state) {
                 mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
                 showDetail(false);
@@ -245,7 +240,7 @@
 
         @Override
         public int getMetricsCategory() {
-            return MetricsLogger.QS_DND_DETAILS;
+            return MetricsEvent.QS_DND_DETAILS;
         }
 
         @Override
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 12c1298..1d9f15b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -17,7 +17,9 @@
 package com.android.systemui.qs.tiles;
 
 import android.app.ActivityManager;
+
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.FlashlightController;
@@ -64,7 +66,7 @@
         }
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
         boolean newState = !mState.value;
-        refreshState(newState ? UserBoolean.USER_TRUE : UserBoolean.USER_FALSE);
+        refreshState(newState);
         mFlashlightController.setFlashlight(newState);
     }
 
@@ -73,8 +75,8 @@
         // TODO: Flashlight available handling...
 //        state.visible = mFlashlightController.isAvailable();
         state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label);
-        if (arg instanceof UserBoolean) {
-            boolean value = ((UserBoolean) arg).value;
+        if (arg instanceof Boolean) {
+            boolean value = (Boolean) arg;
             if (value == state.value) {
                 return;
             }
@@ -83,7 +85,6 @@
             state.value = mFlashlightController.isEnabled();
         }
         final AnimationIcon icon = state.value ? mEnable : mDisable;
-        icon.setAllowAnimation(arg instanceof UserBoolean && ((UserBoolean) arg).userInitiated);
         state.icon = icon;
         int onOrOffId = state.value
                 ? R.string.accessibility_quick_settings_flashlight_on
@@ -93,7 +94,7 @@
 
     @Override
     public int getMetricsCategory() {
-        return MetricsLogger.QS_FLASHLIGHT;
+        return MetricsEvent.QS_FLASHLIGHT;
     }
 
     @Override
@@ -107,12 +108,12 @@
 
     @Override
     public void onFlashlightChanged(boolean enabled) {
-        refreshState(enabled ? UserBoolean.BACKGROUND_TRUE : UserBoolean.BACKGROUND_FALSE);
+        refreshState(enabled);
     }
 
     @Override
     public void onFlashlightError() {
-        refreshState(UserBoolean.BACKGROUND_FALSE);
+        refreshState(false);
     }
 
     @Override
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 250d567..2f37943 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -16,7 +16,10 @@
 
 package com.android.systemui.qs.tiles;
 
+import android.os.UserManager;
+
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.HotspotController;
@@ -59,14 +62,14 @@
         final boolean isEnabled = (Boolean) mState.value;
         MetricsLogger.action(mContext, getMetricsCategory(), !isEnabled);
         mController.setHotspotEnabled(!isEnabled);
-        mEnable.setAllowAnimation(true);
-        mDisable.setAllowAnimation(true);
     }
 
     @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
         state.label = mContext.getString(R.string.quick_settings_hotspot_label);
 
+        state.disabledByPolicy = mController.isTetheringAllowed();
+        checkIfRestrictionEnforced(state, UserManager.DISALLOW_CONFIG_TETHERING);
         if (arg instanceof Boolean) {
             state.value = (boolean) arg;
         } else {
@@ -77,7 +80,7 @@
 
     @Override
     public int getMetricsCategory() {
-        return MetricsLogger.QS_HOTSPOT;
+        return MetricsEvent.QS_HOTSPOT;
     }
 
     @Override
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 0883445..e1dc9f2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
@@ -30,6 +30,7 @@
 import android.util.Log;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.qs.QSTile;
 
 import java.util.Arrays;
@@ -155,7 +156,7 @@
 
     @Override
     public int getMetricsCategory() {
-        return MetricsLogger.QS_INTENT;
+        return MetricsEvent.QS_INTENT;
     }
 
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
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 08540f6..8328897 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -16,7 +16,10 @@
 
 package com.android.systemui.qs.tiles;
 
+import android.os.UserManager;
+
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -67,8 +70,6 @@
                     mHost.openPanels();
                     MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled);
                     mController.setLocationEnabled(!wasEnabled);
-                    mEnable.setAllowAnimation(true);
-                    mDisable.setAllowAnimation(true);
                 }
             });
             return;
@@ -76,8 +77,6 @@
         final boolean wasEnabled = (Boolean) mState.value;
         MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled);
         mController.setLocationEnabled(!wasEnabled);
-        mEnable.setAllowAnimation(true);
-        mDisable.setAllowAnimation(true);
     }
 
     @Override
@@ -88,6 +87,8 @@
         // bug is fixed, this should be reverted to only hiding it on secure lock screens:
         // state.visible = !(mKeyguard.isSecure() && mKeyguard.isShowing());
         state.value = locationEnabled;
+        state.disabledByPolicy = mController.isUserLocationRestricted();
+        checkIfRestrictionEnforced(state, UserManager.DISALLOW_SHARE_LOCATION);
         if (locationEnabled) {
             state.icon = mEnable;
             state.label = mContext.getString(R.string.quick_settings_location_label);
@@ -103,7 +104,7 @@
 
     @Override
     public int getMetricsCategory() {
-        return MetricsLogger.QS_LOCATION;
+        return MetricsEvent.QS_LOCATION;
     }
 
     @Override
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 d85cf60..f920d48 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -16,9 +16,11 @@
 
 package com.android.systemui.qs.tiles;
 
+import android.content.Context;
 import android.content.res.Configuration;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.RotationLockController;
@@ -63,15 +65,14 @@
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
         final boolean newState = !mState.value;
         mController.setRotationLocked(newState);
-        refreshState(newState ? UserBoolean.USER_TRUE : UserBoolean.USER_FALSE);
+        refreshState(newState);
     }
 
     @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
         if (mController == null) return;
-        final boolean rotationLocked = arg != null ? ((UserBoolean) arg).value
+        final boolean rotationLocked = arg != null ? (Boolean) arg
                 : mController.isRotationLocked();
-        final boolean userInitiated = arg != null ? ((UserBoolean) arg).userInitiated : false;
         // TODO: Handle accessibility rotation lock and whatnot.
 //        state.visible = mController.isRotationLockAffordanceVisible();
         if (state.value == rotationLocked && state.contentDescription != null) {
@@ -79,30 +80,28 @@
             return;
         }
         state.value = rotationLocked;
-        final boolean portrait = isCurrentOrientationLockPortrait();
-        final AnimationIcon icon;
+        final boolean portrait = isCurrentOrientationLockPortrait(mController, mContext);
         if (rotationLocked) {
             final int label = portrait ? R.string.quick_settings_rotation_locked_portrait_label
                     : R.string.quick_settings_rotation_locked_landscape_label;
             state.label = mContext.getString(label);
-            icon = portrait ? mAutoToPortrait : mAutoToLandscape;
+            state.icon = portrait ? mAutoToPortrait : mAutoToLandscape;
         } else {
             state.label = mContext.getString(R.string.quick_settings_rotation_unlocked_label);
-            icon = portrait ? mPortraitToAuto : mLandscapeToAuto;
+            state.icon = portrait ? mPortraitToAuto : mLandscapeToAuto;
         }
-        icon.setAllowAnimation(userInitiated);
-        state.icon = icon;
         state.contentDescription = getAccessibilityString(rotationLocked,
                 R.string.accessibility_rotation_lock_on_portrait,
                 R.string.accessibility_rotation_lock_on_landscape,
                 R.string.accessibility_rotation_lock_off);
     }
 
-    private boolean isCurrentOrientationLockPortrait() {
-        int lockOrientation = mController.getRotationLockOrientation();
+    public static boolean isCurrentOrientationLockPortrait(RotationLockController controller,
+            Context context) {
+        int lockOrientation = controller.getRotationLockOrientation();
         if (lockOrientation == Configuration.ORIENTATION_UNDEFINED) {
             // Freely rotating device; use current rotation
-            return mContext.getResources().getConfiguration().orientation
+            return context.getResources().getConfiguration().orientation
                     != Configuration.ORIENTATION_LANDSCAPE;
         } else {
             return lockOrientation != Configuration.ORIENTATION_LANDSCAPE;
@@ -111,7 +110,7 @@
 
     @Override
     public int getMetricsCategory() {
-        return MetricsLogger.QS_ROTATIONLOCK;
+        return MetricsEvent.QS_ROTATIONLOCK;
     }
 
     /**
@@ -127,7 +126,8 @@
             int idWhenOff) {
         int stringID;
         if (locked) {
-            stringID = isCurrentOrientationLockPortrait() ? idWhenPortrait: idWhenLandscape;
+            stringID = isCurrentOrientationLockPortrait(mController, mContext) ? idWhenPortrait
+                    : idWhenLandscape;
         } else {
             stringID = idWhenOff;
         }
@@ -145,8 +145,7 @@
     private final RotationLockControllerCallback mCallback = new RotationLockControllerCallback() {
         @Override
         public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
-            refreshState(rotationLocked ? UserBoolean.BACKGROUND_TRUE
-                    : UserBoolean.BACKGROUND_FALSE);
+            refreshState(rotationLocked);
         }
     };
 }
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 21c5c96..167c611 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
@@ -43,6 +43,7 @@
     private TextView mName;
     private Typeface mRegularTypeface;
     private Typeface mActivatedTypeface;
+    private View mRestrictedPadlock;
 
     public UserDetailItemView(Context context) {
         this(context, null);
@@ -59,6 +60,7 @@
     public UserDetailItemView(Context context, AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+
         final TypedArray a = context.obtainStyledAttributes(
                 attrs, R.styleable.UserDetailItemView, defStyleAttr, defStyleRes);
         final int N = a.getIndexCount();
@@ -95,6 +97,12 @@
         mAvatar.setDrawable(picture);
     }
 
+    public void setDisabledByAdmin(boolean disabled) {
+        mRestrictedPadlock.setVisibility(disabled ? View.VISIBLE : View.GONE);
+        mName.setEnabled(!disabled);
+        mAvatar.setDisabled(disabled);
+    }
+
     @Override
     protected void onFinishInflate() {
         mAvatar = (UserAvatarView) findViewById(R.id.user_picture);
@@ -106,6 +114,7 @@
             mActivatedTypeface = mName.getTypeface();
         }
         updateTypeface();
+        mRestrictedPadlock = findViewById(R.id.restricted_padlock);
     }
 
     @Override
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 d4f54b6..2c8a478 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -16,17 +16,19 @@
 
 package com.android.systemui.qs.tiles;
 
-import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.R;
-import com.android.systemui.qs.PseudoGridView;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
-
 import android.content.Context;
+import android.content.Intent;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 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.R;
+import com.android.systemui.qs.PseudoGridView;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
 /**
  * Quick settings detail view for user switching.
  */
@@ -55,11 +57,13 @@
     public static class Adapter extends UserSwitcherController.BaseUserAdapter
             implements OnClickListener {
 
-        private Context mContext;
+        private final Context mContext;
+        private final UserSwitcherController mController;
 
         public Adapter(Context context, UserSwitcherController controller) {
             super(controller);
             mContext = context;
+            mController = controller;
         }
 
         @Override
@@ -77,6 +81,7 @@
                 v.bind(name, item.picture);
             }
             v.setActivated(item.isCurrent);
+            v.setDisabledByAdmin(item.isDisabledByAdmin);
             v.setTag(item);
             return v;
         }
@@ -85,8 +90,14 @@
         public void onClick(View view) {
             UserSwitcherController.UserRecord tag =
                     (UserSwitcherController.UserRecord) view.getTag();
-            MetricsLogger.action(mContext, MetricsLogger.QS_SWITCH_USER);
-            switchTo(tag);
+            if (tag.isDisabledByAdmin) {
+                final Intent intent = RestrictedLockUtils.getShowAdminSupportDetailsIntent(
+                        mContext, tag.enforcedAdmin);
+                mController.startActivity(intent);
+            } else {
+                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 d29cae4..6eb0646 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
@@ -18,7 +18,7 @@
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.util.Pair;
-import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -52,7 +52,7 @@
 
     @Override
     public int getMetricsCategory() {
-        return MetricsLogger.QS_USER_TILE;
+        return MetricsEvent.QS_USER_TILE;
     }
 
     @Override
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 48b4096..42296f2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -24,7 +24,9 @@
 import android.util.Log;
 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.wifi.AccessPoint;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSDetailItems;
@@ -162,7 +164,7 @@
 
     @Override
     public int getMetricsCategory() {
-        return MetricsLogger.QS_WIFI;
+        return MetricsEvent.QS_WIFI;
     }
 
     @Override
@@ -240,8 +242,8 @@
         private AccessPoint[] mAccessPoints;
 
         @Override
-        public int getTitle() {
-            return R.string.quick_settings_wifi_label;
+        public CharSequence getTitle() {
+            return mContext.getString(R.string.quick_settings_wifi_label);
         }
 
         public Intent getSettingsIntent() {
@@ -256,14 +258,14 @@
         @Override
         public void setToggleState(boolean state) {
             if (DEBUG) Log.d(TAG, "setToggleState " + state);
-            MetricsLogger.action(mContext, MetricsLogger.QS_WIFI_TOGGLE, state);
+            MetricsLogger.action(mContext, MetricsEvent.QS_WIFI_TOGGLE, state);
             mController.setWifiEnabled(state);
             showDetail(false);
         }
 
         @Override
         public int getMetricsCategory() {
-            return MetricsLogger.QS_WIFI_DETAILS;
+            return MetricsEvent.QS_WIFI_DETAILS;
         }
 
         @Override
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 07915f8..508490f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -24,7 +24,9 @@
 import android.content.pm.UserInfo;
 import android.os.UserHandle;
 import android.os.UserManager;
+
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 
@@ -47,6 +49,7 @@
         super(host);
         mUserManager = UserManager.get(mContext);
         mProfiles = new LinkedList<UserInfo>();
+        reloadManagedProfiles(UserHandle.USER_CURRENT);
     }
 
     @Override
@@ -93,12 +96,7 @@
     }
 
     private void refreshQuietModeState(boolean backgroundRefresh) {
-        if (backgroundRefresh) {
-            refreshState(isWorkModeEnabled() ? UserBoolean.BACKGROUND_TRUE
-                    : UserBoolean.BACKGROUND_FALSE);
-        } else {
-            refreshState(isWorkModeEnabled() ? UserBoolean.USER_TRUE : UserBoolean.USER_FALSE);
-        }
+        refreshState(isWorkModeEnabled());
     }
 
     @Override
@@ -108,33 +106,27 @@
             return;
         }
 
-        final boolean userInitialized;
-        if (arg instanceof UserBoolean) {
-            state.value = ((UserBoolean) arg).value;
-            userInitialized = ((UserBoolean) arg).userInitiated;
+        if (arg instanceof Boolean) {
+            state.value = (Boolean) arg;
         } else {
             state.value = isWorkModeEnabled();
-            userInitialized = false;
         }
 
-        final AnimationIcon icon;
         state.label = mContext.getString(R.string.quick_settings_work_mode_label);
         if (state.value) {
-            icon = mEnable;
+            state.icon = mEnable;
             state.contentDescription =  mContext.getString(
                     R.string.accessibility_quick_settings_work_mode_on);
         } else {
-            icon = mDisable;
+            state.icon = mDisable;
             state.contentDescription =  mContext.getString(
                     R.string.accessibility_quick_settings_work_mode_off);
         }
-        icon.setAllowAnimation(userInitialized);
-        state.icon = icon;
     }
 
     @Override
     public int getMetricsCategory() {
-        return MetricsLogger.QS_WORKMODE;
+        return MetricsEvent.QS_WORKMODE;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index c08fb05..070b395 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;
+        public static final int DismissSourceHistorySwipeGesture = 3;
     }
 
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ExitRecentsWindowFirstAnimationFrameEvent.java b/packages/SystemUI/src/com/android/systemui/recents/ExitRecentsWindowFirstAnimationFrameEvent.java
deleted file mode 100644
index 8ae8c53..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/ExitRecentsWindowFirstAnimationFrameEvent.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;
-
-import com.android.systemui.recents.events.EventBus;
-
-/**
- * Event sent when the exit animation is started.
- *
- * This is sent so parts of UI can synchronize on this event and adjust their appearance. An example
- * of that is hiding the tasks when the launched application window becomes visible.
- */
-public class ExitRecentsWindowFirstAnimationFrameEvent extends EventBus.Event {
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
index b36b95a..37085c7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
+++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.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 system user to callback to the secondary users in
@@ -29,6 +31,8 @@
     void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
     void toggleRecents();
     void onConfigurationChanged();
+    void dockTopTask(int topTaskId, int dragMode, int stackCreateMode,
+            in Rect initialBounds);
     void onDraggingInRecents(float distanceFromTop);
     void onDraggingInRecentsEnded(float velocity);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
index 6b49195..cb8f0e7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
+++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
@@ -26,4 +26,7 @@
 
     void updateRecentsVisibility(boolean visible);
     void startScreenPinning();
+    void sendRecentsDrawnEvent();
+    void sendDockingTopTaskEvent(int dragMode);
+    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 b81c23a..b8310f2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -16,7 +16,9 @@
 
 package com.android.systemui.recents;
 
+import android.app.ActivityManager;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
@@ -35,8 +37,11 @@
 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.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;
 
@@ -205,7 +210,7 @@
     public void showRecents(boolean triggeredFromAltTab, View statusBarView) {
         // Ensure the device has been provisioned before allowing the user to interact with
         // recents
-        if (!isDeviceProvisioned()) {
+        if (!isUserSetup()) {
             return;
         }
 
@@ -242,7 +247,7 @@
     public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
         // Ensure the device has been provisioned before allowing the user to interact with
         // recents
-        if (!isDeviceProvisioned()) {
+        if (!isUserSetup()) {
             return;
         }
 
@@ -277,7 +282,7 @@
     public void toggleRecents(Display display, int layoutDirection, View statusBarView) {
         // Ensure the device has been provisioned before allowing the user to interact with
         // recents
-        if (!isDeviceProvisioned()) {
+        if (!isUserSetup()) {
             return;
         }
 
@@ -312,7 +317,7 @@
     public void preloadRecents() {
         // Ensure the device has been provisioned before allowing the user to interact with
         // recents
-        if (!isDeviceProvisioned()) {
+        if (!isUserSetup()) {
             return;
         }
 
@@ -340,7 +345,7 @@
     public void cancelPreloadingRecents() {
         // Ensure the device has been provisioned before allowing the user to interact with
         // recents
-        if (!isDeviceProvisioned()) {
+        if (!isUserSetup()) {
             return;
         }
 
@@ -365,11 +370,41 @@
     }
 
     @Override
-    public void dockTopTask(boolean draggingInRecents, int stackCreateMode, Rect initialBounds) {
-        mImpl.dockTopTask(draggingInRecents, stackCreateMode,initialBounds);
-        if (draggingInRecents) {
-            mDraggingInRecentsCurrentUser = sSystemServicesProxy.getCurrentUser();
+    public boolean dockTopTask(int dragMode, int stackCreateMode, Rect initialBounds) {
+        // Ensure the device has been provisioned before allowing the user to interact with
+        // recents
+        if (!isUserSetup()) {
+            return false;
         }
+
+        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 (mSystemUserCallbacks != null) {
+                    IRecentsNonSystemUserCallbacks callbacks =
+                            mSystemUserCallbacks.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);
+                    }
+                }
+            }
+            mDraggingInRecentsCurrentUser = currentUser;
+            return true;
+        }
+        return false;
     }
 
     @Override
@@ -422,7 +457,7 @@
     public void showNextAffiliatedTask() {
         // Ensure the device has been provisioned before allowing the user to interact with
         // recents
-        if (!isDeviceProvisioned()) {
+        if (!isUserSetup()) {
             return;
         }
 
@@ -433,7 +468,7 @@
     public void showPrevAffiliatedTask() {
         // Ensure the device has been provisioned before allowing the user to interact with
         // recents
-        if (!isDeviceProvisioned()) {
+        if (!isUserSetup()) {
             return;
         }
 
@@ -506,6 +541,54 @@
         }
     }
 
+    public final void onBusEvent(final RecentsDrawnEvent event) {
+        int processUser = sSystemServicesProxy.getProcessUser();
+        if (!sSystemServicesProxy.isSystemUser(processUser)) {
+            postToSystemUser(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        mCallbacksToSystemUser.sendRecentsDrawnEvent();
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                }
+            });
+        }
+    }
+
+    public final void onBusEvent(final DockingTopTaskEvent event) {
+        int processUser = sSystemServicesProxy.getProcessUser();
+        if (!sSystemServicesProxy.isSystemUser(processUser)) {
+            postToSystemUser(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        mCallbacksToSystemUser.sendDockingTopTaskEvent(event.dragMode);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                }
+            });
+        }
+    }
+
+    public final void onBusEvent(final RecentsActivityStartingEvent event) {
+        int processUser = sSystemServicesProxy.getProcessUser();
+        if (!sSystemServicesProxy.isSystemUser(processUser)) {
+            postToSystemUser(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        mCallbacksToSystemUser.sendLaunchRecentsEvent();
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                }
+            });
+        }
+    }
+
     /**
      * Attempts to register with the system user.
      */
@@ -515,7 +598,8 @@
             @Override
             public void run() {
                 try {
-                    mCallbacksToSystemUser.registerNonSystemUserCallbacks(mImpl, processUser);
+                    mCallbacksToSystemUser.registerNonSystemUserCallbacks(
+                            new RecentsImplProxy(mImpl), processUser);
                 } catch (RemoteException e) {
                     Log.e(TAG, "Failed to register", e);
                 }
@@ -559,11 +643,12 @@
     }
 
     /**
-     * @return whether this device is provisioned.
+     * @return whether this device is provisioned and the current user is set up.
      */
-    private boolean isDeviceProvisioned() {
-        return Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.DEVICE_PROVISIONED, 0) != 0;
+    private boolean isUserSetup() {
+        ContentResolver cr = mContext.getContentResolver();
+        return (Settings.Global.getInt(cr, Settings.Global.DEVICE_PROVISIONED, 0) != 0) &&
+                (Settings.Secure.getInt(cr, Settings.Secure.USER_SETUP_COMPLETE, 0) != 0);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 9f0ac35..c3b794d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -5,7 +5,7 @@
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -34,28 +34,34 @@
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.View;
-import android.view.ViewStub;
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
+
 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.DebugFlagsChangedEvent;
+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.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.ToggleRecentsEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
 import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
-import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
+import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
+import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
 import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
 import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
 import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
@@ -63,9 +69,7 @@
 import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent;
-import com.android.systemui.recents.history.RecentsHistoryView;
 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.model.RecentsPackageMonitor;
 import com.android.systemui.recents.model.RecentsTaskLoadPlan;
@@ -74,9 +78,7 @@
 import com.android.systemui.recents.model.TaskStack;
 import com.android.systemui.recents.views.RecentsView;
 import com.android.systemui.recents.views.SystemBarScrimViews;
-import com.android.systemui.recents.views.ViewAnimation;
-
-import java.util.ArrayList;
+import com.android.systemui.statusbar.BaseStatusBar;
 
 /**
  * The main Recents activity that is started from AlternateRecentsComponent.
@@ -99,8 +101,6 @@
     // Top level views
     private RecentsView mRecentsView;
     private SystemBarScrimViews mScrimViews;
-    private ViewStub mHistoryViewStub;
-    private RecentsHistoryView mHistoryView;
 
     // Search AppWidget
     private AppWidgetProviderInfo mSearchWidgetInfo;
@@ -111,25 +111,24 @@
     private FinishRecentsRunnable mFinishLaunchHomeRunnable;
 
     // The trigger to automatically launch the current task
-    private DozeTrigger mIterateTrigger = new DozeTrigger(500, new Runnable() {
-        @Override
-        public void run() {
-            dismissRecentsToFocusedTask();
-        }
-    });
+    private int mFocusTimerDuration;
+    private DozeTrigger mIterateTrigger;
+    private final UserInteractionEvent mUserInteractionEvent = new UserInteractionEvent();
 
     /**
      * A common Runnable to finish Recents by launching Home with an animation depending on the
-     * last activity launch state.  Generally we always launch home when we exit Recents rather than
+     * 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 {
+
         Intent mLaunchIntent;
+        ActivityOptions mOpts;
 
         /**
          * Creates a finish runnable that starts the specified intent.
          */
-        public FinishRecentsRunnable(Intent launchIntent) {
+        public FinishRecentsRunnable(Intent launchIntent, ActivityOptions opts) {
             mLaunchIntent = launchIntent;
         }
 
@@ -138,13 +137,16 @@
             try {
                 RecentsActivityLaunchState launchState =
                         Recents.getConfiguration().getLaunchState();
-                ActivityOptions 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);
+                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);
+                }
                 startActivityAsUser(mLaunchIntent, opts.toBundle(), UserHandle.CURRENT);
             } catch (Exception e) {
                 Log.e(TAG, getString(R.string.recents_launch_error_message, "Home"), e);
@@ -185,7 +187,7 @@
         RecentsConfiguration config = Recents.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
         if (!plan.hasTasks()) {
-            loader.preloadTasks(plan, launchState.launchedFromHome);
+            loader.preloadTasks(plan, -1, launchState.launchedFromHome);
         }
         RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
         loadOpts.runningTaskId = launchState.launchedToTaskId;
@@ -196,28 +198,15 @@
         TaskStack stack = plan.getTaskStack();
         mRecentsView.setTaskStack(stack);
 
-        // Mark the task that is the launch target
-        int launchTaskIndexInStack = 0;
-        if (launchState.launchedToTaskId != -1) {
-            ArrayList<Task> tasks = stack.getStackTasks();
-            int taskCount = tasks.size();
-            for (int j = 0; j < taskCount; j++) {
-                Task t = tasks.get(j);
-                if (t.key.id == launchState.launchedToTaskId) {
-                    t.isLaunchTarget = true;
-                    launchTaskIndexInStack = tasks.size() - j - 1;
-                    break;
-                }
-            }
-        }
-
         // Animate the SystemUI scrims into view
-        boolean hasStatusBarScrim = stack.getStackTaskCount() > 0;
-        boolean animateStatusBarScrim = launchState.launchedFromHome;
-        boolean hasNavBarScrim = (stack.getStackTaskCount() > 0) && !config.hasTransposedNavBar;
+        Task launchTarget = stack.getLaunchTarget();
+        int taskCount = stack.getTaskCount();
+        int launchTaskIndexInStack = launchTarget != null
+                ? stack.indexOfStackTask(launchTarget)
+                : 0;
+        boolean hasNavBarScrim = (taskCount > 0) && !config.hasTransposedNavBar;
         boolean animateNavBarScrim = true;
-        mScrimViews.prepareEnterRecentsAnimation(hasStatusBarScrim, animateStatusBarScrim, hasNavBarScrim,
-                animateNavBarScrim);
+        mScrimViews.prepareEnterRecentsAnimation(hasNavBarScrim, animateNavBarScrim);
 
         // Keep track of whether we launched from the nav bar button or via alt-tab
         if (launchState.launchedWithAltTab) {
@@ -234,7 +223,6 @@
             MetricsLogger.count(this, "overview_source_home", 1);
         }
         // Keep track of the total stack task count
-        int taskCount = stack.getStackTaskCount();
         MetricsLogger.histogram(this, "overview_task_count", taskCount);
     }
 
@@ -242,12 +230,8 @@
      * Dismisses the history view back into the stack view.
      */
     boolean dismissHistory() {
-        // Try and hide the history view first
-        if (mHistoryView != null && mHistoryView.isVisible()) {
-            ReferenceCountedTrigger t = new ReferenceCountedTrigger(this);
-            t.increment();
-            EventBus.getDefault().send(new HideHistoryEvent(true /* animate */, t));
-            t.decrement();
+        if (mRecentsView.isHistoryVisible()) {
+            EventBus.getDefault().send(new HideHistoryEvent(true /* animate */));
             return true;
         }
         return false;
@@ -274,7 +258,7 @@
             // If we have a focused Task, launch that Task now
             if (mRecentsView.launchPreviousTask()) return true;
             // If none of the other cases apply, then just go Home
-            dismissRecentsToHome(true);
+            dismissRecentsToHome(true /* animateTaskViews */);
         }
         return false;
     }
@@ -288,7 +272,7 @@
             // If we have a focused Task, launch that Task now
             if (mRecentsView.launchFocusedTask()) return true;
             // If none of the other cases apply, then just go Home
-            dismissRecentsToHome(true);
+            dismissRecentsToHome(true /* animateTaskViews */);
             return true;
         }
         return false;
@@ -297,21 +281,33 @@
     /**
      * Dismisses Recents directly to Home without checking whether it is currently visible.
      */
-    void dismissRecentsToHome(boolean animated) {
-        if (animated) {
-            ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(this,
-                    null, mFinishLaunchHomeRunnable, null);
-            mRecentsView.startExitToHomeAnimation(
-                    new ViewAnimation.TaskViewExitContext(exitTrigger));
-        } else {
-            mFinishLaunchHomeRunnable.run();
-        }
+    void dismissRecentsToHome(boolean animateTaskViews) {
+        dismissRecentsToHome(animateTaskViews, null);
     }
 
-    /** Dismisses Recents directly to Home without transition animation. */
-    void dismissRecentsToHomeWithoutTransitionAnimation() {
-        finish();
-        overridePendingTransition(0, 0);
+    /**
+     * Dismisses Recents directly to Home without checking whether it is currently visible.
+     *
+     * @param overrideAnimation If not null, will override the default animation that is based on
+     *                          how Recents was launched.
+     */
+    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 Runnable() {
+            @Override
+            public void run() {
+                Recents.getSystemServices().sendCloseSystemWindows(
+                        BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
+            }
+        });
+        EventBus.getDefault().send(dismissEvent);
     }
 
     /** Dismisses Recents directly to Home if we currently aren't transitioning. */
@@ -344,7 +340,7 @@
         EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
 
         // Initialize the widget host (the host id is static and does not change)
-        if (!RecentsDebugFlags.Static.DisableSearchBar) {
+        if (RecentsDebugFlags.Static.EnableSearchBar) {
             mAppWidgetHost = new RecentsAppWidgetHost(this, RecentsAppWidgetHost.HOST_ID);
         }
         mPackageMonitor = new RecentsPackageMonitor();
@@ -356,27 +352,34 @@
         mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
                 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
                 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
-        mHistoryViewStub = (ViewStub) findViewById(R.id.history_view_stub);
         mScrimViews = new SystemBarScrimViews(this);
         getWindow().getAttributes().privateFlags |=
                 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
 
+        mFocusTimerDuration = getResources().getInteger(R.integer.recents_auto_advance_duration);
+        mIterateTrigger = new DozeTrigger(mFocusTimerDuration, new Runnable() {
+            @Override
+            public void run() {
+                dismissRecentsToFocusedTask();
+            }
+        });
+
         // 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);
+        mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent, null);
 
         // Bind the search app widget when we first start up
-        if (!RecentsDebugFlags.Static.DisableSearchBar) {
+        if (RecentsDebugFlags.Static.EnableSearchBar) {
             mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost);
         }
 
         // 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.DisableSearchBar) {
+        if (RecentsDebugFlags.Static.EnableSearchBar) {
             filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
         }
         registerReceiver(mSystemBroadcastReceiver, filter);
@@ -410,7 +413,18 @@
         SystemServicesProxy ssp = Recents.getSystemServices();
         EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, true));
 
-        MetricsLogger.visible(this, MetricsLogger.OVERVIEW_ACTIVITY);
+        MetricsLogger.visible(this, MetricsEvent.OVERVIEW_ACTIVITY);
+
+        mRecentsView.getViewTreeObserver().addOnPreDrawListener(
+                new ViewTreeObserver.OnPreDrawListener() {
+
+            @Override
+            public boolean onPreDraw() {
+                mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
+                EventBus.getDefault().post(new RecentsDrawnEvent());
+                return true;
+            }
+        });
     }
 
     @Override
@@ -436,11 +450,8 @@
 
         // Reset some states
         mIgnoreAltTabRelease = false;
-        if (mHistoryView != null) {
-            ReferenceCountedTrigger t = new ReferenceCountedTrigger(this);
-            t.increment();
-            EventBus.getDefault().send(new HideHistoryEvent(false /* animate */, t));
-            t.decrement();
+        if (mRecentsView.isHistoryVisible()) {
+            EventBus.getDefault().send(new HideHistoryEvent(false /* animate */));
         }
 
         // Notify that recents is now hidden
@@ -460,7 +471,7 @@
         launchState.launchedHasConfigurationChanged = false;
         launchState.launchedViaDragGesture = false;
 
-        MetricsLogger.hidden(this, MetricsLogger.OVERVIEW_ACTIVITY);
+        MetricsLogger.hidden(this, MetricsEvent.OVERVIEW_ACTIVITY);
     }
 
     @Override
@@ -479,7 +490,7 @@
         mPackageMonitor.unregister();
 
         // Stop listening for widget package changes if there was one bound
-        if (!RecentsDebugFlags.Static.DisableSearchBar) {
+        if (RecentsDebugFlags.Static.EnableSearchBar) {
             mAppWidgetHost.stopListening();
         }
 
@@ -501,19 +512,14 @@
     @Override
     protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
-        outState.putBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE,
-                (mHistoryView != null) && mHistoryView.isVisible());
+        outState.putBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE, mRecentsView.isHistoryVisible());
     }
 
     @Override
     protected void onRestoreInstanceState(Bundle savedInstanceState) {
         super.onRestoreInstanceState(savedInstanceState);
         if (savedInstanceState.getBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE, false)) {
-            ReferenceCountedTrigger postHideStackAnimationTrigger =
-                    new ReferenceCountedTrigger(this);
-            postHideStackAnimationTrigger.increment();
-            EventBus.getDefault().send(new ShowHistoryEvent(postHideStackAnimationTrigger));
-            postHideStackAnimationTrigger.decrement();
+            EventBus.getDefault().send(new ShowHistoryEvent());
         }
     }
 
@@ -526,6 +532,22 @@
     }
 
     @Override
+    public void onMultiWindowModeChanged(boolean multiWindowMode) {
+        super.onMultiWindowModeChanged(multiWindowMode);
+        if (!multiWindowMode) {
+            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: {
@@ -538,7 +560,8 @@
                     if (backward) {
                         EventBus.getDefault().send(new FocusPreviousTaskViewEvent());
                     } else {
-                        EventBus.getDefault().send(new FocusNextTaskViewEvent());
+                        EventBus.getDefault().send(
+                                new FocusNextTaskViewEvent(0 /* timerIndicatorDuration */));
                     }
                     mLastTabKeyEventTime = SystemClock.elapsedRealtime();
 
@@ -550,7 +573,8 @@
                 return true;
             }
             case KeyEvent.KEYCODE_DPAD_UP: {
-                EventBus.getDefault().send(new FocusNextTaskViewEvent());
+                EventBus.getDefault().send(
+                        new FocusNextTaskViewEvent(0 /* timerIndicatorDuration */));
                 return true;
             }
             case KeyEvent.KEYCODE_DPAD_DOWN: {
@@ -559,12 +583,14 @@
             }
             case KeyEvent.KEYCODE_DEL:
             case KeyEvent.KEYCODE_FORWARD_DEL: {
-                EventBus.getDefault().send(new DismissFocusedTaskViewEvent());
+                if (event.getRepeatCount() <= 0) {
+                    EventBus.getDefault().send(new DismissFocusedTaskViewEvent());
 
-                // Keep track of deletions by keyboard
-                MetricsLogger.histogram(this, "overview_task_dismissed_source",
-                        Constants.Metrics.DismissSourceKeyboard);
-                return true;
+                    // Keep track of deletions by keyboard
+                    MetricsLogger.histogram(this, "overview_task_dismissed_source",
+                            Constants.Metrics.DismissSourceKeyboard);
+                    return true;
+                }
             }
             default:
                 break;
@@ -574,7 +600,7 @@
 
     @Override
     public void onUserInteraction() {
-        EventBus.getDefault().send(new UserInteractionEvent());
+        EventBus.getDefault().send(mUserInteractionEvent);
     }
 
     @Override
@@ -589,7 +615,7 @@
         if (!dismissHistory()) {
             RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
             if (launchState.launchedFromHome) {
-                dismissRecentsToHome(true);
+                dismissRecentsToHome(true /* animateTaskViews */);
             } else {
                 dismissRecentsToLaunchTargetTaskOrHome();
             }
@@ -598,18 +624,26 @@
 
     public final void onBusEvent(IterateRecentsEvent event) {
         if (!dismissHistory()) {
-            // Focus the next task
-            EventBus.getDefault().send(new FocusNextTaskViewEvent());
+            final RecentsDebugFlags debugFlags = Recents.getDebugFlags();
 
             // Start dozing after the recents button is clicked
-            RecentsDebugFlags debugFlags = Recents.getDebugFlags();
+            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();
                 }
             }
+
+            // Focus the next task
+            EventBus.getDefault().send(new FocusNextTaskViewEvent(timerIndicatorDuration));
+
+            MetricsLogger.action(this, MetricsEvent.ACTION_OVERVIEW_PAGE);
         }
     }
 
@@ -625,21 +659,19 @@
             }
         } else if (event.triggeredFromHomeKey) {
             // Otherwise, dismiss Recents to Home
-            if (mHistoryView != null && mHistoryView.isVisible()) {
-                ReferenceCountedTrigger t = new ReferenceCountedTrigger(this);
-                t.increment();
-                t.addLastDecrementRunnable(new Runnable() {
-                    @Override
-                    public void run() {
-                        dismissRecentsToHome(true /* animated */);
-                    }
-                });
-                EventBus.getDefault().send(new HideHistoryEvent(true, t));
-                t.decrement();
+            if (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 /* animated */);
+                dismissRecentsToHome(true /* animateTaskViews */);
             }
+
+            // Cancel any pending dozes
+            EventBus.getDefault().send(mUserInteractionEvent);
         } else {
             // Do nothing
         }
@@ -647,12 +679,9 @@
 
     public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
         // Try and start the enter animation (or restart it on configuration changed)
-        ReferenceCountedTrigger t = new ReferenceCountedTrigger(this);
-        ViewAnimation.TaskViewEnterContext ctx = new ViewAnimation.TaskViewEnterContext(t);
-        ctx.postAnimationTrigger.increment();
-        if (mSearchWidgetInfo != null) {
-            if (!RecentsDebugFlags.Static.DisableSearchBar) {
-                ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
+        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
@@ -663,8 +692,21 @@
                 });
             }
         }
-        mRecentsView.startEnterRecentsAnimation(ctx);
-        ctx.postAnimationTrigger.decrement();
+    }
+
+    public final void onBusEvent(EnterRecentsTaskStackAnimationCompletedEvent event) {
+        RecentsDebugFlags debugFlags = Recents.getDebugFlags();
+        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+        if (!launchState.launchedWithAltTab && debugFlags.isFastToggleRecentsEnabled() &&
+                RecentsDebugFlags.Static.EnableFastToggleTimeoutOnEnter) {
+            mIterateTrigger.setDozeDuration(
+                    getResources().getInteger(R.integer.recents_auto_advance_duration));
+            if (!mIterateTrigger.isDozing()) {
+                mIterateTrigger.startDozing();
+            } else {
+                mIterateTrigger.poke();
+            }
+        }
     }
 
     public final void onBusEvent(EnterRecentsWindowLastAnimationFrameEvent event) {
@@ -703,13 +745,13 @@
         intent.setComponent(intent.resolveActivity(getPackageManager()));
         TaskStackBuilder.create(this)
                 .addNextIntentWithParentStack(intent).startActivities(null,
-                new UserHandle(event.task.key.userId));
+                        new UserHandle(event.task.key.userId));
 
         // Keep track of app-info invocations
         MetricsLogger.count(this, "overview_app_info", 1);
     }
 
-    public final void onBusEvent(DismissTaskViewEvent event) {
+    public final void onBusEvent(DeleteTaskDataEvent event) {
         // Remove any stored data from the loader
         RecentsTaskLoader loader = Recents.getTaskLoader();
         loader.deleteTaskData(event.task, false);
@@ -725,7 +767,7 @@
             mRecentsView.showEmptyView();
         } else {
             // Just go straight home (no animation necessary because there are no more task views)
-            dismissRecentsToHome(false /* animated */);
+            dismissRecentsToHome(false /* animateTaskViews */);
         }
 
         // Keep track of all-deletions
@@ -738,7 +780,7 @@
 
     public final void onBusEvent(LaunchTaskFailedEvent event) {
         // Return to Home
-        dismissRecentsToHome(true);
+        dismissRecentsToHome(true /* animateTaskViews */);
 
         MetricsLogger.count(this, "overview_task_launch_failed", 1);
     }
@@ -758,21 +800,6 @@
         mIgnoreAltTabRelease = true;
     }
 
-    public final void onBusEvent(ShowHistoryEvent event) {
-        if (mHistoryView == null) {
-            mHistoryView = (RecentsHistoryView) mHistoryViewStub.inflate();
-            // 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(mRecentsView.getSystemInsets());
-        }
-        mHistoryView.show(mRecentsView.getTaskStack(), event.postHideStackAnimationTrigger);
-    }
-
-    public final void onBusEvent(HideHistoryEvent event) {
-        mHistoryView.hide(event.animate, event.postHideHistoryAnimationTrigger);
-    }
-
     private void refreshSearchWidgetView() {
         if (mSearchWidgetInfo != null) {
             SystemServicesProxy ssp = Recents.getSystemServices();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
index 4ab0740..0afa1f6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -52,27 +52,12 @@
      * Returns the task to focus given the current launch state.
      */
     public int getInitialFocusTaskIndex(int numTasks) {
-        RecentsDebugFlags flags = Recents.getDebugFlags();
-        if (launchedWithAltTab) {
-            if (launchedFromAppWithThumbnail) {
-                // If alt-tabbing from another app, focus the next task
-                return numTasks - 2;
-            } else {
-                // If alt-tabbing from home, focus the first task
-                return numTasks - 1;
-            }
+        if (launchedFromAppWithThumbnail) {
+            // If coming from another app, focus the next task
+            return numTasks - 2;
         } else {
-            if (launchedFromHome) {
-                return numTasks - 1;
-            } else {
-                if (flags.isFastToggleRecentsEnabled() || !flags.isInitialStatePaging()) {
-                    // If we are not fast-toggling or are starting in the non-focused mode, then
-                    // we should assume the front most task has focus
-                    return numTasks - 1;
-                } else {
-                    return numTasks - 2;
-                }
-            }
+            // If coming from home, focus the first task
+            return numTasks - 1;
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 7547570f..61780f8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Rect;
-import android.provider.Settings;
 import com.android.systemui.R;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 
@@ -74,9 +73,6 @@
     public int svelteLevel;
     public int searchBarSpaceHeightPx;
 
-    /** Dev options and global settings */
-    public boolean lockToAppEnabled;
-
     public RecentsConfiguration(Context context) {
         // Load only resources that can not change after the first load either through developer
         // settings or via multi window
@@ -106,12 +102,7 @@
     /**
      * Updates the configuration based on the current state of the system
      */
-    void update(Context context, SystemServicesProxy ssp, Rect windowRect) {
-        // Only update resources that can change after the first load, either through developer
-        // settings or via multi window
-        lockToAppEnabled = !ssp.hasFreeformWorkspaceSupport() &&
-                ssp.getSystemSetting(context, Settings.System.LOCK_TO_APP_ENABLED) != 0;
-
+    void update(Rect windowRect) {
         // Recompute some values based on the given state, since we can not rely on the resource
         // system to get certain values.
         boolean isLandscape = windowRect.width() > windowRect.height();
@@ -148,7 +139,7 @@
         } 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, searchBarBounds.bottom + top,
+            taskStackBounds.set(windowBounds.left, windowBounds.top + searchBarBounds.bottom + top,
                     windowBounds.right - rightInset, windowBounds.bottom);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
index 40c84ba..49f2ab0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.DebugFlagsChangedEvent;
+import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.tuner.TunerService;
 
 /**
@@ -26,28 +27,35 @@
  */
 public class RecentsDebugFlags implements TunerService.Tunable {
 
-    private static final String KEY_FAST_TOGGLE = "overview_fast_toggle_via_button";
-    private static final String KEY_INITIAL_STATE_PAGING = "overview_initial_state_paging";
-
     public static class Static {
         // Enables debug drawing for the transition thumbnail
         public static final boolean EnableTransitionThumbnailDebugMode = false;
-        // This disables the search bar integration
-        public static final boolean DisableSearchBar = true;
+        // 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 simulated task affiliations
-        public static final boolean EnableSimulatedTaskGroups = false;
-        // Defines the number of mock task affiliations per group
-        public static final int TaskAffiliationsGroupCount = 12;
+        // Enables the task affiliations
+        public static final boolean EnableAffiliatedTaskGroups = true;
+        // Overrides the Tuner flags and enables the fast toggle and timeout
+        public static final boolean EnableFastToggleTimeoutOverride = true;
+        // Enables toggling the fast-toggle timeout immediately after entering Recents
+        public static final boolean EnableFastToggleTimeoutOnEnter = true;
+
         // Enables us to create mock recents tasks
-        public static final boolean EnableSystemServicesProxy = false;
+        public static final boolean EnableMockTasks = false;
         // Defines the number of mock recents packages to create
-        public static final int SystemServicesProxyMockPackageCount = 3;
+        public static final int MockTasksPackageCount = 3;
         // Defines the number of mock recents tasks to create
-        public static final int SystemServicesProxyMockTaskCount = 100;
+        public static final int MockTaskCount = 100;
+        // Enables the simulated task affiliations
+        public static final boolean EnableMockTaskGroups = false;
+        // Defines the number of mock task affiliations per group
+        public static final int MockTaskGroupsTaskCount = 12;
     }
 
+    private static final String KEY_FAST_TOGGLE = "overview_fast_toggle_via_button";
+    private static final String KEY_INITIAL_STATE_PAGING = "overview_initial_state_paging";
+
     private boolean mFastToggleRecents;
     private boolean mInitialStatePaging;
 
@@ -65,6 +73,15 @@
      * @return whether we are enabling fast toggling.
      */
     public boolean isFastToggleRecentsEnabled() {
+        // These checks EnableFastToggleTimeoutOverride
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (ssp.hasFreeformWorkspaceSupport() || ssp.hasDockedTask() ||
+                ssp.isTouchExplorationEnabled()) {
+            return false;
+        }
+        if (Static.EnableFastToggleTimeoutOverride) {
+            return true;
+        }
         return mFastToggleRecents;
     }
 
@@ -72,6 +89,9 @@
      * @return whether the initial stack state is paging.
      */
     public boolean isInitialStatePaging() {
+        if (Static.EnableFastToggleTimeoutOnEnter) {
+            return true;
+        }
         return mInitialStatePaging;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 0678aae..d1301cf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -19,9 +19,12 @@
 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;
@@ -40,9 +43,11 @@
 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.EnterRecentsWindowLastAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
 import com.android.systemui.recents.events.activity.IterateRecentsEvent;
+import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
 import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
@@ -60,6 +65,8 @@
 import com.android.systemui.recents.views.TaskStackView;
 import com.android.systemui.recents.views.TaskViewHeader;
 import com.android.systemui.recents.views.TaskViewTransform;
+import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 
 import java.util.ArrayList;
@@ -70,12 +77,9 @@
  * An implementation of the Recents component for the current user.  For secondary users, this can
  * be called remotely from the system user.
  */
-public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements
-        ActivityOptions.OnAnimationFinishedListener {
+public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener {
 
     private final static String TAG = "RecentsImpl";
-    private final static boolean DEBUG = false;
-
     // The minimum amount of time between each recents button press that we will handle
     private final static int MIN_TOGGLE_DELAY_MS = 350;
     // The duration within which the user releasing the alt tab (from when they pressed alt tab)
@@ -85,7 +89,10 @@
 
     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
      * task stacks and update recents accordingly.
@@ -104,11 +111,17 @@
             mHandler.post(this);
         }
 
+        @Override
+        public void onActivityPinned() {
+        }
+
+        @Override
+        public void onPinnedActivityRestartAttempt() {
+        }
+
         /** Preloads the next task */
         public void run() {
-            // TODO: Temporarily skip this if multi stack is enabled
-            /*
-            RecentsConfiguration config = RecentsConfiguration.getInstance();
+            RecentsConfiguration config = Recents.getConfiguration();
             if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
                 RecentsTaskLoader loader = Recents.getTaskLoader();
                 SystemServicesProxy ssp = Recents.getSystemServices();
@@ -116,7 +129,7 @@
 
                 // Load the next task only if we aren't svelte
                 RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
-                loader.preloadTasks(plan, true);
+                loader.preloadTasks(plan, -1, true /* isTopTaskHome */);
                 RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
                 // This callback is made when a new activity is launched and the old one is paused
                 // so ignore the current activity and try and preload the thumbnail for the
@@ -130,7 +143,6 @@
                 launchOpts.onlyLoadPausedActivities = true;
                 loader.loadTasks(mContext, plan, launchOpts);
             }
-            */
         }
     }
 
@@ -180,8 +192,6 @@
         mContext = context;
         mHandler = new Handler();
         mAppWidgetHost = new RecentsAppWidgetHost(mContext, RecentsAppWidgetHost.HOST_ID);
-        Resources res = mContext.getResources();
-        LayoutInflater inflater = LayoutInflater.from(mContext);
 
         // Initialize the static foreground thread
         ForegroundThread.get();
@@ -192,34 +202,37 @@
         ssp.registerTaskStackListener(mTaskStackListener);
 
         // Initialize the static configuration resources
-        mStatusBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
-        mNavBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height);
-        mNavBarWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
-        mTaskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
-        mDummyStackView = new TaskStackView(mContext, new TaskStack());
-        mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header,
-                null, false);
-        reloadHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */);
+        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.
         RecentsTaskLoader loader = Recents.getTaskLoader();
         RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
-        loader.preloadTasks(plan, true /* isTopTaskHome */);
+        loader.preloadTasks(plan, -1, true /* isTopTaskHome */);
         RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
-        launchOpts.numVisibleTasks = loader.getApplicationIconCacheSize();
+        launchOpts.numVisibleTasks = loader.getIconCacheSize();
         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;
-        reloadHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */);
+        updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */);
     }
 
-    @Override
     public void onConfigurationChanged() {
+        reloadHeaderBarLayout();
+        updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */);
         // Don't reuse task stack views if the configuration changes
         mCanReuseTaskStackViews = false;
         Recents.getConfiguration().updateOnConfigurationChange();
@@ -251,7 +264,6 @@
         }
     }
 
-    @Override
     public void showRecents(boolean triggeredFromAltTab, boolean draggingInRecents,
             boolean animate, boolean reloadTasks) {
         mTriggeredFromAltTab = triggeredFromAltTab;
@@ -294,7 +306,6 @@
         }
     }
 
-    @Override
     public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
         if (mBootCompleted) {
             if (triggeredFromAltTab && mFastAltTabTrigger.isDozing()) {
@@ -315,7 +326,6 @@
         }
     }
 
-    @Override
     public void toggleRecents() {
         // Skip this toggle if we are already waiting to trigger recents via alt-tab
         if (mFastAltTabTrigger.isDozing()) {
@@ -332,7 +342,6 @@
             if (topTask != null && ssp.isRecentsTopMost(topTask, isTopTaskHome)) {
                 RecentsConfiguration config = Recents.getConfiguration();
                 RecentsActivityLaunchState launchState = config.getLaunchState();
-                RecentsDebugFlags flags = Recents.getDebugFlags();
                 if (!launchState.launchedWithAltTab) {
                     // Notify recents to move onto the next task
                     EventBus.getDefault().post(new IterateRecentsEvent());
@@ -360,6 +369,9 @@
 
                 // Otherwise, start the recents activity
                 startRecentsActivity(topTask, isTopTaskHome.value, true /* animate */);
+
+                // Only close the other system windows if we are actually showing recents
+                ssp.sendCloseSystemWindows(BaseStatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS);
                 mLastToggleTime = SystemClock.elapsedRealtime();
             }
         } catch (ActivityNotFoundException e) {
@@ -367,7 +379,6 @@
         }
     }
 
-    @Override
     public void preloadRecents() {
         // Preload only the raw task list into a new load plan (which will be consumed by the
         // RecentsActivity) only if there is a task to animate to.
@@ -378,9 +389,9 @@
         sInstanceLoadPlan = loader.createLoadPlan(mContext);
         if (topTask != null && !ssp.isRecentsTopMost(topTask, topTaskHome)) {
             sInstanceLoadPlan.preloadRawTasks(topTaskHome.value);
-            loader.preloadTasks(sInstanceLoadPlan, topTaskHome.value);
+            loader.preloadTasks(sInstanceLoadPlan, topTask.id, topTaskHome.value);
             TaskStack stack = sInstanceLoadPlan.getTaskStack();
-            if (stack.getStackTaskCount() > 0) {
+            if (stack.getTaskCount() > 0) {
                 // We try and draw the thumbnail transition bitmap in parallel before
                 // toggle/show recents is called
                 preCacheThumbnailTransitionBitmapAsync(topTask, stack, mDummyStackView);
@@ -388,17 +399,14 @@
         }
     }
 
-    @Override
     public void cancelPreloadingRecents() {
         // Do nothing
     }
 
-    @Override
     public void onDraggingInRecents(float distanceFromTop) {
         EventBus.getDefault().sendOntoMainThread(new DraggingInRecentsEvent(distanceFromTop));
     }
 
-    @Override
     public void onDraggingInRecentsEnded(float velocity) {
         EventBus.getDefault().sendOntoMainThread(new DraggingInRecentsEndedEvent(velocity));
     }
@@ -410,11 +418,11 @@
         SystemServicesProxy ssp = Recents.getSystemServices();
         RecentsTaskLoader loader = Recents.getTaskLoader();
         RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
-        loader.preloadTasks(plan, true /* isTopTaskHome */);
+        loader.preloadTasks(plan, -1, true /* isTopTaskHome */);
         TaskStack focusedStack = plan.getTaskStack();
 
         // Return early if there are no tasks in the focused stack
-        if (focusedStack == null || focusedStack.getStackTaskCount() == 0) return;
+        if (focusedStack == null || focusedStack.getTaskCount() == 0) return;
 
         ActivityManager.RunningTaskInfo runningTask = ssp.getTopMostTask();
         // Return early if there is no running task
@@ -452,7 +460,7 @@
         }
 
         // Launch the task
-        ssp.startActivityFromRecents(mContext, toTask.key.id, toTask.activityLabel, launchOpts);
+        ssp.startActivityFromRecents(mContext, toTask.key.id, toTask.title, launchOpts);
     }
 
     /**
@@ -462,11 +470,11 @@
         SystemServicesProxy ssp = Recents.getSystemServices();
         RecentsTaskLoader loader = Recents.getTaskLoader();
         RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
-        loader.preloadTasks(plan, true /* isTopTaskHome */);
+        loader.preloadTasks(plan, -1, true /* isTopTaskHome */);
         TaskStack focusedStack = plan.getTaskStack();
 
         // Return early if there are no tasks in the focused stack
-        if (focusedStack == null || focusedStack.getStackTaskCount() == 0) return;
+        if (focusedStack == null || focusedStack.getTaskCount() == 0) return;
 
         ActivityManager.RunningTaskInfo runningTask = ssp.getTopMostTask();
         // Return early if there is no running task (can't determine affiliated tasks in this case)
@@ -524,7 +532,7 @@
         MetricsLogger.count(mContext, "overview_affiliated_task_launch", 1);
 
         // Launch the task
-        ssp.startActivityFromRecents(mContext, toTask.key.id, toTask.activityLabel, launchOpts);
+        ssp.startActivityFromRecents(mContext, toTask.key.id, toTask.title, launchOpts);
     }
 
     public void showNextAffiliatedTask() {
@@ -539,14 +547,14 @@
         showRelativeAffiliatedTask(false);
     }
 
-    public void dockTopTask(boolean draggingInRecents, int stackCreateMode, Rect initialBounds) {
+    public void dockTopTask(int topTaskId, int dragMode,
+            int stackCreateMode, Rect initialBounds) {
         SystemServicesProxy ssp = Recents.getSystemServices();
-        ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
-        if (topTask != null && !SystemServicesProxy.isHomeStack(topTask.stackId)) {
-            ssp.moveTaskToDockedStack(topTask.id, stackCreateMode, initialBounds);
-            showRecents(false /* triggeredFromAltTab */, draggingInRecents, false /* animate */,
-                    true /* reloadTasks*/);
-        }
+        ssp.moveTaskToDockedStack(topTaskId, stackCreateMode, initialBounds);
+        showRecents(false /* triggeredFromAltTab */,
+                dragMode == NavigationBarGestureHelper.DRAG_MODE_RECENTS, false /* animate */,
+                true /* reloadTasks*/);
+        EventBus.getDefault().send(new DockingTopTaskEvent(dragMode));
     }
 
     /**
@@ -559,6 +567,26 @@
     }
 
     /**
+     * Reloads all the layouts for the header bar transition.
+     */
+    private void reloadHeaderBarLayout() {
+        Resources res = mContext.getResources();
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+
+        mStatusBarHeight = res.getDimensionPixelSize(
+                com.android.internal.R.dimen.status_bar_height);
+        mNavBarHeight = res.getDimensionPixelSize(
+                com.android.internal.R.dimen.navigation_bar_height);
+        mNavBarWidth = res.getDimensionPixelSize(
+                com.android.internal.R.dimen.navigation_bar_width);
+        mTaskBarHeight = res.getDimensionPixelSize(
+                R.dimen.recents_task_bar_height);
+        mDummyStackView = new TaskStackView(mContext, new TaskStack());
+        mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header,
+                null, false);
+    }
+
+    /**
      * 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.
      *
@@ -566,15 +594,16 @@
      *                               is not already bound (can be expensive)
      * @param stack the stack to initialize the stack layout with
      */
-    private void reloadHeaderBarLayout(boolean tryAndBindSearchWidget, TaskStack stack) {
+    private void updateHeaderBarLayout(boolean tryAndBindSearchWidget,
+            TaskStack stack) {
         RecentsConfiguration config = Recents.getConfiguration();
         SystemServicesProxy ssp = Recents.getSystemServices();
         Rect windowRect = ssp.getWindowRect();
 
         // Update the configuration for the current state
-        config.update(mContext, ssp, ssp.getWindowRect());
+        config.update(windowRect);
 
-        if (!RecentsDebugFlags.Static.DisableSearchBar && tryAndBindSearchWidget) {
+        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
@@ -631,13 +660,13 @@
         preloadIcon(topTask);
 
         // Update the header bar if necessary
-        reloadHeaderBarLayout(false /* tryAndBindSearchWidget */, stack);
+        updateHeaderBarLayout(false /* tryAndBindSearchWidget */, stack);
 
         // Update the destination rect
         mDummyStackView.updateLayoutForStack(stack);
         final Task toTask = new Task();
         final TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
-                topTask.id, toTask);
+                toTask);
         ForegroundThread.getHandler().postAtFrontOfQueue(new Runnable() {
             @Override
             public void run() {
@@ -707,7 +736,7 @@
             // Update the destination rect
             Task toTask = new Task();
             TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
-                    topTask.id, toTask);
+                    toTask);
             RectF toTaskRect = toTransform.rect;
             Bitmap thumbnail = getThumbnailBitmap(topTask, toTask, toTransform);
             if (thumbnail != null) {
@@ -740,31 +769,20 @@
      * Returns the transition rect for the given task id.
      */
     private TaskViewTransform getThumbnailTransitionTransform(TaskStack stack,
-            TaskStackView stackView, int runningTaskId, Task runningTaskOut) {
+            TaskStackView stackView, Task runningTaskOut) {
         // Find the running task in the TaskStack
-        Task task = null;
-        ArrayList<Task> tasks = stack.getStackTasks();
-        if (runningTaskId != -1) {
-            // Otherwise, try and find the task with the
-            int taskCount = tasks.size();
-            for (int i = taskCount - 1; i >= 0; i--) {
-                Task t = tasks.get(i);
-                if (t.key.id == runningTaskId) {
-                    task = t;
-                    runningTaskOut.copyFrom(t);
-                    break;
-                }
-            }
-        }
-        if (task == null) {
+        Task launchTask = stack.getLaunchTarget();
+        if (launchTask != null) {
+            runningTaskOut.copyFrom(launchTask);
+        } else {
             // If no task is specified or we can not find the task just use the front most one
-            task = tasks.get(tasks.size() - 1);
-            runningTaskOut.copyFrom(task);
+            launchTask = stack.getStackFrontMostTask(true /* includeFreeform */);
+            runningTaskOut.copyFrom(launchTask);
         }
 
         // Get the transform for the running task
         stackView.getScroller().setStackScrollToInitialState();
-        mTmpTransform = stackView.getStackAlgorithm().getStackTransform(task,
+        mTmpTransform = stackView.getStackAlgorithm().getStackTransform(launchTask,
                 stackView.getScroller().getStackScroll(), mTmpTransform, null);
         return mTmpTransform;
     }
@@ -776,8 +794,10 @@
         if (toTransform != null && toTask.key != null) {
             Bitmap thumbnail;
             synchronized (mHeaderBarLock) {
-                int toHeaderWidth = (int) (mHeaderBar.getMeasuredWidth() * toTransform.scale);
+                int toHeaderWidth = (int) toTransform.rect.width();
                 int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale);
+                mHeaderBar.onTaskViewSizeChanged((int) toTransform.rect.width(),
+                        (int) toTransform.rect.height());
                 thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight,
                         Bitmap.Config.ARGB_8888);
                 if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
@@ -810,12 +830,12 @@
             sInstanceLoadPlan = loader.createLoadPlan(mContext);
         }
         if (mReloadTasks || mTriggeredFromAltTab || !sInstanceLoadPlan.hasTasks()) {
-            loader.preloadTasks(sInstanceLoadPlan, isTopTaskHome);
+            loader.preloadTasks(sInstanceLoadPlan, topTask.id, isTopTaskHome);
         }
         TaskStack stack = sInstanceLoadPlan.getTaskStack();
 
         // Update the header bar if necessary
-        reloadHeaderBarLayout(false /* tryAndBindSearchWidget */, stack);
+        updateHeaderBarLayout(false /* tryAndBindSearchWidget */, stack);
 
         // Prepare the dummy stack for the transition
         mDummyStackView.updateLayoutForStack(stack);
@@ -829,7 +849,7 @@
             return;
         }
 
-        boolean hasRecentTasks = stack.getStackTaskCount() > 0;
+        boolean hasRecentTasks = stack.getTaskCount() > 0;
         boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks;
 
         if (useThumbnailTransition) {
@@ -848,11 +868,19 @@
         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 (!RecentsDebugFlags.Static.DisableSearchBar && hasRecentTasks) {
+            if (hasRecentTasks) {
                 SystemServicesProxy ssp = Recents.getSystemServices();
                 String homeActivityPackage = ssp.getHomeActivityPackageName();
-                String searchWidgetPackage = Prefs.getString(mContext,
-                        Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE, null);
+                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) &&
@@ -891,16 +919,18 @@
         launchState.launchedViaDragGesture = mDraggingInRecents;
 
         Intent intent = new Intent();
-        intent.setClassName(RECENTS_PACKAGE, RECENTS_ACTIVITY);
+        intent.setClassName(RECENTS_PACKAGE, mRecentsIntentActivityName);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
                 | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
+
         if (opts != null) {
             mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
         } else {
             mContext.startActivityAsUser(intent, UserHandle.CURRENT);
         }
         mCanReuseTaskStackViews = true;
+        EventBus.getDefault().send(new RecentsActivityStartingEvent());
     }
 
     /**** OnAnimationFinishedListener Implementation ****/
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
new file mode 100644
index 0000000..86ec98a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.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.systemui.recents;
+
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+
+import com.android.internal.os.SomeArgs;
+
+/**
+ * A proxy class which directs all methods from {@link IRecentsNonSystemUserCallbacks} to
+ * {@link RecentsImpl} and makes sure they are called from the main thread.
+ */
+public class RecentsImplProxy extends IRecentsNonSystemUserCallbacks.Stub {
+
+    private static final int MSG_PRELOAD_RECENTS = 1;
+    private static final int MSG_CANCEL_PRELOADING_RECENTS = 2;
+    private static final int MSG_SHOW_RECENTS = 3;
+    private static final int MSG_HIDE_RECENTS = 4;
+    private static final int MSG_TOGGLE_RECENTS = 5;
+    private static final int MSG_ON_CONFIGURATION_CHANGED = 6;
+    private static final int MSG_DOCK_TOP_TASK = 7;
+    private static final int MSG_ON_DRAGGING_IN_RECENTS = 8;
+    private static final int MSG_ON_DRAGGING_IN_RECENTS_ENDED = 9;
+
+    private RecentsImpl mImpl;
+
+    public RecentsImplProxy(RecentsImpl recentsImpl) {
+        mImpl = recentsImpl;
+    }
+
+    @Override
+    public void preloadRecents() throws RemoteException {
+        mHandler.sendEmptyMessage(MSG_PRELOAD_RECENTS);
+    }
+
+    @Override
+    public void cancelPreloadingRecents() throws RemoteException {
+        mHandler.sendEmptyMessage(MSG_CANCEL_PRELOADING_RECENTS);
+    }
+
+    @Override
+    public void showRecents(boolean triggeredFromAltTab, boolean draggingInRecents, boolean animate,
+            boolean reloadTasks) throws RemoteException {
+        SomeArgs args = SomeArgs.obtain();
+        args.argi1 = triggeredFromAltTab ? 1 : 0;
+        args.argi2 = draggingInRecents ? 1 : 0;
+        args.argi3 = animate ? 1 : 0;
+        args.argi4 = reloadTasks ? 1 : 0;
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_SHOW_RECENTS, args));
+    }
+
+    @Override
+    public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey)
+            throws RemoteException {
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_HIDE_RECENTS, triggeredFromAltTab ? 1 :0,
+                triggeredFromHomeKey ? 1 : 0));
+    }
+
+    @Override
+    public void toggleRecents() throws RemoteException {
+        mHandler.sendEmptyMessage(MSG_TOGGLE_RECENTS);
+    }
+
+    @Override
+    public void onConfigurationChanged() throws RemoteException {
+        mHandler.sendEmptyMessage(MSG_ON_CONFIGURATION_CHANGED);
+    }
+
+    @Override
+    public void dockTopTask(int topTaskId, int dragMode, int stackCreateMode,
+            Rect initialBounds) throws RemoteException {
+        SomeArgs args = SomeArgs.obtain();
+        args.argi1 = topTaskId;
+        args.argi2 = dragMode;
+        args.argi3 = stackCreateMode;
+        args.arg1 = initialBounds;
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_DOCK_TOP_TASK, args));
+    }
+
+    @Override
+    public void onDraggingInRecents(float distanceFromTop) throws RemoteException {
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_DRAGGING_IN_RECENTS, distanceFromTop));
+    }
+
+    @Override
+    public void onDraggingInRecentsEnded(float velocity) throws RemoteException {
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_DRAGGING_IN_RECENTS_ENDED, velocity));
+    }
+
+    private final Handler mHandler = new Handler() {
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_PRELOAD_RECENTS:
+                    mImpl.preloadRecents();
+                    break;
+                case MSG_CANCEL_PRELOADING_RECENTS:
+                    mImpl.cancelPreloadingRecents();
+                    break;
+                case MSG_SHOW_RECENTS:
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    mImpl.showRecents(args.argi1 != 0, args.argi2 != 0, args.argi3 != 0,
+                            args.argi4 != 0);
+                    break;
+                case MSG_HIDE_RECENTS:
+                    mImpl.hideRecents(msg.arg1 != 0, msg.arg2 != 0);
+                    break;
+                case MSG_TOGGLE_RECENTS:
+                    mImpl.toggleRecents();
+                    break;
+                case MSG_ON_CONFIGURATION_CHANGED:
+                    mImpl.onConfigurationChanged();
+                    break;
+                case MSG_DOCK_TOP_TASK:
+                    args = (SomeArgs) msg.obj;
+                    mImpl.dockTopTask(args.argi1, args.argi2, args.argi3 = 0,
+                            (Rect) args.arg1);
+                    break;
+                case MSG_ON_DRAGGING_IN_RECENTS:
+                    mImpl.onDraggingInRecents((Float) msg.obj);
+                    break;
+                case MSG_ON_DRAGGING_IN_RECENTS_ENDED:
+                    mImpl.onDraggingInRecentsEnded((Float) msg.obj);
+                    break;
+                default:
+                    super.handleMessage(msg);
+            }
+            super.handleMessage(msg);
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
index fb21500..ae0051c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
@@ -22,6 +22,11 @@
 import android.util.Log;
 import android.util.SparseArray;
 
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
+import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
+import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
+
 /**
  * An implementation of the system user's Recents interface to be called remotely by secondary
  * users.
@@ -70,4 +75,19 @@
     public void startScreenPinning() {
         mImpl.onStartScreenPinning(mContext);
     }
+
+    @Override
+    public void sendRecentsDrawnEvent() {
+        EventBus.getDefault().post(new RecentsDrawnEvent());
+    }
+
+    @Override
+    public void sendDockingTopTaskEvent(int dragMode) throws RemoteException {
+        EventBus.getDefault().post(new DockingTopTaskEvent(dragMode));
+    }
+
+    @Override
+    public void sendLaunchRecentsEvent() throws RemoteException {
+        EventBus.getDefault().post(new RecentsActivityStartingEvent());
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
index d72218f..212c7f4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
@@ -27,6 +27,7 @@
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.MutableBoolean;
+import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 
 import java.lang.ref.WeakReference;
 import java.lang.reflect.Constructor;
@@ -220,6 +221,20 @@
         // Only accessible from derived events
         protected Event() {}
 
+        /**
+         * Called by the EventBus prior to dispatching this event to any subscriber of this event.
+         */
+        void onPreDispatch() {
+            // Do nothing
+        }
+
+        /**
+         * Called by the EventBus after dispatching this event to every subscriber of this event.
+         */
+        void onPostDispatch() {
+            // Do nothing
+        }
+
         @Override
         protected Object clone() throws CloneNotSupportedException {
             Event evt = (Event) super.clone();
@@ -230,6 +245,73 @@
     }
 
     /**
+     * An event that represents an animated state change, which allows subscribers to coordinate
+     * callbacks which happen after the animation has taken place.
+     *
+     * Internally, it is guaranteed that increment() and decrement() will be called before and the
+     * after the event is dispatched.
+     */
+    public static class AnimatedEvent extends Event {
+
+        private final ReferenceCountedTrigger mTrigger = new ReferenceCountedTrigger();
+
+        // Only accessible from derived events
+        protected AnimatedEvent() {}
+
+        /**
+         * Returns the reference counted trigger that coordinates the animations for this event.
+         */
+        public ReferenceCountedTrigger getAnimationTrigger() {
+            return mTrigger;
+        }
+
+        /**
+         * Adds a callback that is guaranteed to be called after the state has changed regardless of
+         * whether an actual animation took place.
+         */
+        public void addPostAnimationCallback(Runnable r) {
+            mTrigger.addLastDecrementRunnable(r);
+        }
+
+        @Override
+        void onPreDispatch() {
+            mTrigger.increment();
+        }
+
+        @Override
+        void onPostDispatch() {
+            mTrigger.decrement();
+        }
+
+        @Override
+        protected Object clone() throws CloneNotSupportedException {
+            throw new CloneNotSupportedException();
+        }
+    }
+
+    /**
+     * An event that can be reusable, only used for situations where we want to reduce memory
+     * allocations when events are sent frequently (ie. on scroll).
+     */
+    public static class ReusableEvent extends Event {
+
+        private int mDispatchCount;
+
+        protected ReusableEvent() {}
+
+        @Override
+        void onPostDispatch() {
+            super.onPostDispatch();
+            mDispatchCount++;
+        }
+
+        @Override
+        protected Object clone() throws CloneNotSupportedException {
+            throw new CloneNotSupportedException();
+        }
+    }
+
+    /**
      * An inter-process event super class that allows us to track user state across subscriber
      * invocations.
      */
@@ -602,8 +684,6 @@
 
     /**
      * Registers a new subscriber.
-     *
-     * @return return whether or not this
      */
     private void registerSubscriber(Object subscriber, int priority,
             MutableBoolean hasInterprocessEventsChangedOut) {
@@ -706,9 +786,17 @@
         if (eventHandlers == null) {
             return;
         }
+
+        // Prepare this event
+        boolean hasPostedEvent = false;
+        event.onPreDispatch();
+
         // We need to clone the list in case a subscriber unregisters itself during traversal
+        // TODO: Investigate whether we can skip the object creation here
         eventHandlers = (ArrayList<EventHandler>) eventHandlers.clone();
-        for (final EventHandler eventHandler : eventHandlers) {
+        int eventHandlerCount = eventHandlers.size();
+        for (int i = 0; i < eventHandlerCount; i++) {
+            final EventHandler eventHandler = eventHandlers.get(i);
             if (eventHandler.subscriber.getReference() != null) {
                 if (event.requiresPost) {
                     mHandler.post(new Runnable() {
@@ -717,11 +805,24 @@
                             processEvent(eventHandler, event);
                         }
                     });
+                    hasPostedEvent = true;
                 } else {
                     processEvent(eventHandler, event);
                 }
             }
         }
+
+        // Clean up after this event, deferring until all subscribers have been called
+        if (hasPostedEvent) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    event.onPostDispatch();
+                }
+            });
+        } else {
+            event.onPostDispatch();
+        }
     }
 
     /**
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
new file mode 100644
index 0000000..98c0a69
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ClearHistoryEvent.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.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/DismissRecentsToHomeAnimationStarted.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DismissRecentsToHomeAnimationStarted.java
index 5f3e830..e7be858 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DismissRecentsToHomeAnimationStarted.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DismissRecentsToHomeAnimationStarted.java
@@ -21,6 +21,11 @@
 /**
  * This is sent when the task animation when dismissing Recents starts.
  */
-public class DismissRecentsToHomeAnimationStarted extends EventBus.Event {
-    // Simple event
+public class DismissRecentsToHomeAnimationStarted extends EventBus.AnimatedEvent {
+
+    public final boolean animated;
+
+    public DismissRecentsToHomeAnimationStarted(boolean animated) {
+        this.animated = animated;
+    }
 }
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
new file mode 100644
index 0000000..264c2c4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockingTopTaskEvent.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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/EnterRecentsTaskStackAnimationCompletedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsTaskStackAnimationCompletedEvent.java
new file mode 100644
index 0000000..ee0df87
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsTaskStackAnimationCompletedEvent.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.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This is sent when the in-app animations into Recents completes.
+ */
+public class EnterRecentsTaskStackAnimationCompletedEvent extends EventBus.AnimatedEvent {
+    // Simple event
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowAnimationCompletedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowAnimationCompletedEvent.java
index b31f320..918875a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowAnimationCompletedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowAnimationCompletedEvent.java
@@ -23,6 +23,6 @@
  * we can start in-app animations so that they don't conflict with the window transition into
  * Recents.
  */
-public class EnterRecentsWindowAnimationCompletedEvent extends EventBus.Event {
+public class EnterRecentsWindowAnimationCompletedEvent extends EventBus.AnimatedEvent {
     // Simple event
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ExitRecentsWindowFirstAnimationFrameEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ExitRecentsWindowFirstAnimationFrameEvent.java
new file mode 100644
index 0000000..fa806eb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ExitRecentsWindowFirstAnimationFrameEvent.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Event sent when the exit animation is started.
+ *
+ * This is sent so parts of UI can synchronize on this event and adjust their appearance. An example
+ * of that is hiding the tasks when the launched application window becomes visible.
+ */
+public class ExitRecentsWindowFirstAnimationFrameEvent extends EventBus.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
index 3412852..bacf3bd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java
@@ -17,7 +17,6 @@
 package com.android.systemui.recents.events.activity;
 
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 
 /**
  * This is sent when the history view will be closed.
@@ -25,14 +24,8 @@
 public class HideHistoryEvent extends EventBus.Event {
 
     public final boolean animate;
-    public final ReferenceCountedTrigger postHideHistoryAnimationTrigger;
 
-    /**
-     * @param postHideHistoryAnimationTrigger the trigger that gets called when all the history animations are finished
-     *                                        when transitioning from the history view
-     */
-    public HideHistoryEvent(boolean animate, ReferenceCountedTrigger postHideHistoryAnimationTrigger) {
+    public HideHistoryEvent(boolean animate) {
         this.animate = animate;
-        this.postHideHistoryAnimationTrigger = postHideHistoryAnimationTrigger;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
index 457d81e..21b9301 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
@@ -22,7 +22,7 @@
 import com.android.systemui.recents.views.TaskView;
 
 /**
- * This is sent to launch a task from Recents.
+ * This event is sent to request that a particular task is launched.
  */
 public class LaunchTaskEvent extends EventBus.Event {
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskStartedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskStartedEvent.java
new file mode 100644
index 0000000..3925ab1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskStartedEvent.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.views.TaskView;
+
+/**
+ * This event is sent following {@link LaunchTaskEvent} after the call to the system is made to
+ * start the task.
+ */
+public class LaunchTaskStartedEvent extends EventBus.AnimatedEvent {
+
+    public final TaskView taskView;
+    public final boolean screenPinningRequested;
+
+    public LaunchTaskStartedEvent(TaskView taskView, boolean screenPinningRequested) {
+        this.taskView = taskView;
+        this.screenPinningRequested = screenPinningRequested;
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/RecentsActivityStartingEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/RecentsActivityStartingEvent.java
new file mode 100644
index 0000000..a2ecfe2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/RecentsActivityStartingEvent.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.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Called after recents activity is being started, i.e. startActivity has just been called.
+ */
+public class RecentsActivityStartingEvent extends EventBus.Event{
+
+}
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
index 7042537..ae803ea 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryButtonEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryButtonEvent.java
@@ -22,5 +22,11 @@
  * This is sent when the history view button should be shown.
  */
 public class ShowHistoryButtonEvent extends EventBus.Event {
-    // Simple 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
index c91752e..469f336 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java
@@ -17,20 +17,12 @@
 package com.android.systemui.recents.events.activity;
 
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 
 /**
  * This is sent when the history view button is clicked.
  */
 public class ShowHistoryEvent extends EventBus.Event {
 
-    public final ReferenceCountedTrigger postHideStackAnimationTrigger;
+    // Simple event
 
-    /**
-     * @param postHideStackAnimationTrigger the trigger that gets called when all the task animations are finished when
-     *                                      transitioning to the history view
-     */
-    public ShowHistoryEvent(ReferenceCountedTrigger postHideStackAnimationTrigger) {
-        this.postHideStackAnimationTrigger = postHideStackAnimationTrigger;
-    }
 }
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
new file mode 100644
index 0000000..7579cd8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.model.TaskStack;
+
+/**
+ * This is sent by the activity whenever the task stach has changed.
+ */
+public class TaskStackUpdatedEvent extends EventBus.Event {
+
+    /**
+     * A new TaskStack instance representing the latest stack state.
+     */
+    public final TaskStack stack;
+
+    public TaskStackUpdatedEvent(TaskStack stack) {
+        this.stack = stack;
+    }
+}
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
new file mode 100644
index 0000000..aaf77af
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ToggleHistoryEvent.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.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/ui/DeleteTaskDataEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DeleteTaskDataEvent.java
new file mode 100644
index 0000000..4ed0270
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DeleteTaskDataEvent.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.ui;
+
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.model.Task;
+
+/**
+ * This is sent when the data associated with a given {@link Task} should be deleted from the
+ * system.
+ */
+public class DeleteTaskDataEvent extends EventBus.Event {
+
+    public final Task task;
+
+    public DeleteTaskDataEvent(Task task) {
+        this.task = task;
+    }
+}
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 968890a..1165f4e 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
@@ -21,15 +21,15 @@
 import com.android.systemui.recents.views.TaskView;
 
 /**
- * This is sent when a {@link TaskView} has been dismissed.
+ * This event is sent to request that the given {@link TaskView} is dismissed.
  */
-public class DismissTaskViewEvent extends EventBus.Event {
+public class DismissTaskViewEvent extends EventBus.AnimatedEvent {
 
-    public final Task task;
     public final TaskView taskView;
+    public final Task task;
 
-    public DismissTaskViewEvent(Task task, TaskView taskView) {
-        this.task = task;
+    public DismissTaskViewEvent(TaskView taskView, Task task) {
         this.taskView = taskView;
+        this.task = task;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/RecentsDrawnEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/RecentsDrawnEvent.java
new file mode 100644
index 0000000..5483166
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/RecentsDrawnEvent.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.systemui.recents.events.ui;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Fired when recents was launched and has drawn its first frame.
+ */
+public class RecentsDrawnEvent extends EventBus.Event {
+
+}
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
new file mode 100644
index 0000000..863f40b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResetBackgroundScrimEvent.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.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/StackViewScrolledEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/StackViewScrolledEvent.java
index cb5011a..ad9feb6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/StackViewScrolledEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/StackViewScrolledEvent.java
@@ -16,16 +16,21 @@
 
 package com.android.systemui.recents.events.ui;
 
+import android.util.MutableInt;
 import com.android.systemui.recents.events.EventBus;
 
 /**
  * This is sent whenever a new scroll gesture happens on a stack view.
  */
-public class StackViewScrolledEvent extends EventBus.Event {
+public class StackViewScrolledEvent extends EventBus.ReusableEvent {
 
-    public final int yMovement;
+    public final MutableInt yMovement;
 
-    public StackViewScrolledEvent(int yMovement) {
-        this.yMovement = yMovement;
+    public StackViewScrolledEvent() {
+        yMovement = new MutableInt(0);
+    }
+
+    public void updateY(int y) {
+        yMovement.value = y;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java
new file mode 100644
index 0000000..7bd0958
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package 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;
+
+/**
+ * This event is sent when a {@link TaskView} has been dismissed and is no longer visible.
+ */
+public class TaskViewDismissedEvent extends EventBus.Event {
+
+    public final Task task;
+    public final TaskView taskView;
+
+    public TaskViewDismissedEvent(Task task, TaskView taskView) {
+        this.task = task;
+        this.taskView = taskView;
+    }
+}
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
new file mode 100644
index 0000000..fdd4c67
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/UpdateBackgroundScrimEvent.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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/UserInteractionEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/UserInteractionEvent.java
index 6e6cd84..39e4c1d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/UserInteractionEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/UserInteractionEvent.java
@@ -21,6 +21,6 @@
 /**
  * This is sent whenever the user interacts with the activity.
  */
-public class UserInteractionEvent extends EventBus.Event {
-    // Simple event
+public class UserInteractionEvent extends EventBus.ReusableEvent {
+    // Simple Event
 }
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 21321f2..b85ddac 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
@@ -25,6 +25,7 @@
  */
 public class DragDropTargetChangedEvent extends EventBus.Event {
 
+    // The task that is currently being dragged
     public final Task task;
     public final DropTarget dropTarget;
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java
index 3deeb47..73c282f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java
@@ -17,7 +17,6 @@
 package com.android.systemui.recents.events.ui.dragndrop;
 
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.views.DropTarget;
 import com.android.systemui.recents.views.TaskView;
@@ -25,18 +24,15 @@
 /**
  * This event is sent whenever a drag ends.
  */
-public class DragEndEvent extends EventBus.Event {
+public class DragEndEvent extends EventBus.AnimatedEvent {
 
     public final Task task;
     public final TaskView taskView;
     public final DropTarget dropTarget;
-    public final ReferenceCountedTrigger postAnimationTrigger;
 
-    public DragEndEvent(Task task, TaskView taskView, DropTarget dropTarget,
-            ReferenceCountedTrigger postAnimationTrigger) {
+    public DragEndEvent(Task task, TaskView taskView, DropTarget dropTarget) {
         this.task = task;
         this.taskView = taskView;
         this.dropTarget = dropTarget;
-        this.postAnimationTrigger = postAnimationTrigger;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/DismissFocusedTaskViewEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/DismissFocusedTaskViewEvent.java
index 9f3e9d5..df74018 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/DismissFocusedTaskViewEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/DismissFocusedTaskViewEvent.java
@@ -17,9 +17,10 @@
 package com.android.systemui.recents.events.ui.focus;
 
 import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.views.TaskView;
 
 /**
- * Dismisses the currently focused task view.
+ * This event is sent to request that the currently focused {@link TaskView} is dismissed.
  */
 public class DismissFocusedTaskViewEvent extends EventBus.Event {
     // Simple event
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java
index 171ab5e..a1e4957 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java
@@ -22,5 +22,10 @@
  * Focuses the next task view in the stack.
  */
 public class FocusNextTaskViewEvent extends EventBus.Event {
-    // Simple event
+
+    public final int timerIndicatorDuration;
+
+    public FocusNextTaskViewEvent(int timerIndicatorDuration) {
+        this.timerIndicatorDuration = timerIndicatorDuration;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
index 06265bd..e288878 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
@@ -20,14 +20,26 @@
 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.TaskViewAnimation;
 
 import java.util.ArrayList;
 import java.util.Calendar;
@@ -49,28 +61,53 @@
     static final int TASK_ROW_VIEW_TYPE = 1;
 
     /**
-     * View holder implementation.
+     * View holder implementation. The {@param TaskCallbacks} are only called for TaskRow view
+     * holders.
      */
-    public static class ViewHolder extends RecyclerView.ViewHolder {
-        public View mContent;
+    public static class ViewHolder extends RecyclerView.ViewHolder implements Task.TaskCallbacks {
+        public final View content;
 
         public ViewHolder(View v) {
             super(v);
-            mContent = v;
+            content = v;
+        }
+
+        @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.
      */
-    private interface Row {
+    interface Row {
         int getViewType();
     }
 
     /**
      * A date row.
      */
-    private static class DateRow implements Row {
+    static class DateRow implements Row {
 
         public final String date;
 
@@ -87,21 +124,24 @@
     /**
      * A task row.
      */
-    private static class TaskRow implements Row, View.OnClickListener {
+    static class TaskRow implements Row, View.OnClickListener {
 
-        public final String description;
-        private final int mTaskId;
+        public final Task task;
+        public final int dateKey;
 
-        public TaskRow(Task task) {
-            mTaskId = task.key.id;
-            description = task.activityLabel;
+        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(), mTaskId, description,
+            ssp.startActivityFromRecents(v.getContext(), task.key.id, task.title,
                     ActivityOptions.makeBasic());
+
+            MetricsLogger.action(v.getContext(), MetricsEvent.ACTION_OVERVIEW_SELECT,
+                    task.key.getComponent().toString());
         }
 
         @Override
@@ -112,8 +152,9 @@
 
     private Context mContext;
     private LayoutInflater mLayoutInflater;
-    private final List<Task> mTasks = new ArrayList<>();
     private final List<Row> mRows = new ArrayList<>();
+    private final SparseIntArray mTaskRowCount = new SparseIntArray();
+    private TaskStack mStack;
 
     public RecentsHistoryAdapter(Context context) {
         mLayoutInflater = LayoutInflater.from(context);
@@ -122,52 +163,82 @@
     /**
      * Updates this adapter with the given tasks.
      */
-    public void updateTasks(Context context, List<Task> tasks) {
+    public void updateTasks(Context context, TaskStack stack) {
         mContext = context;
-        mTasks.clear();
-        mTasks.addAll(tasks);
+        mStack = stack;
 
         final Locale l = context.getResources().getConfiguration().locale;
         final String dateFormatStr = DateFormat.getBestDateTimePattern(l, "EEEEMMMMd");
-        final List<Task> tasksMostRecent = new ArrayList<>(tasks);
+        final List<Task> tasksMostRecent = new ArrayList<>(stack.getHistoricalTasks());
         Collections.reverse(tasksMostRecent);
-        int prevDayKey = -1;
+        int prevDateKey = -1;
+        int taskCount = tasksMostRecent.size();
         mRows.clear();
-        for (Task task : tasksMostRecent) {
+        mTaskRowCount.clear();
+        Calendar cal = Calendar.getInstance(l);
+        for (int i = 0; i < taskCount; i++) {
+            Task task = tasksMostRecent.get(i);
             if (task.isFreeformTask()) {
                 continue;
             }
 
-            Calendar cal = Calendar.getInstance(l);
             cal.setTimeInMillis(task.key.lastActiveTime);
-            int dayKey = Objects.hash(cal.get(Calendar.YEAR), cal.get(Calendar.DAY_OF_YEAR));
-            if (dayKey != prevDayKey) {
-                prevDayKey = dayKey;
+            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));
+            mRows.add(new TaskRow(task, dateKey));
+            mTaskRowCount.put(dateKey, mTaskRowCount.get(dateKey, 0) + 1);
         }
         notifyDataSetChanged();
     }
 
     /**
-     * Removes historical tasks beloning to the specified package and user.
+     * 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) {
-        boolean packagesRemoved = false;
-        for (int i = mTasks.size() - 1; i >= 0; i--) {
-            Task task = mTasks.get(i);
-            String taskPackage = task.key.getComponent().getPackageName();
-            if (task.key.userId == userId && taskPackage.equals(packageName)) {
-                mTasks.remove(i);
-                packagesRemoved = true;
+        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 (packagesRemoved) {
-            updateTasks(mContext, new ArrayList<Task>(mTasks));
+        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, TaskViewAnimation.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) {
@@ -184,25 +255,63 @@
 
     @Override
     public void onBindViewHolder(ViewHolder holder, int position) {
+        RecentsTaskLoader loader = Recents.getTaskLoader();
+
         Row row = mRows.get(position);
-        int viewType = mRows.get(position).getViewType();
+        int viewType = row.getViewType();
         switch (viewType) {
             case DATE_ROW_VIEW_TYPE: {
-                TextView tv = (TextView) holder.mContent;
+                TextView tv = (TextView) holder.content;
                 tv.setText(((DateRow) row).date);
                 break;
             }
             case TASK_ROW_VIEW_TYPE: {
-                TextView tv = (TextView) holder.mContent;
                 TaskRow taskRow = (TaskRow) row;
-                tv.setText(taskRow.description);
-                tv.setOnClickListener(taskRow);
+                taskRow.task.addCallback(holder);
+                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);
+                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);
+                taskRow.task.removeCallback(holder);
+            }
+        }
+    }
+
+    @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, TaskViewAnimation.IMMEDIATE);
+        removeTaskRow(position);
+        if (mRows.isEmpty()) {
+            dismissHistory();
+        }
+    }
+
+    @Override
     public int getItemCount() {
         return mRows.size();
     }
@@ -211,4 +320,37 @@
     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
new file mode 100644
index 0000000..a91ea7e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package 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.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);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
index 1163f14..96b5cac 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
@@ -16,45 +16,50 @@
 
 package com.android.systemui.recents.history;
 
-import android.content.ComponentName;
+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.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.LinearLayout;
+
+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.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.misc.ReferenceCountedTrigger;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.Task;
+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.TaskView;
-
-import java.util.ArrayList;
-import java.util.HashSet;
+import com.android.systemui.recents.views.AnimateableViewBounds;
 
 /**
  * A list of the recent tasks that are not in the stack.
  */
-public class RecentsHistoryView extends LinearLayout {
+public class RecentsHistoryView extends LinearLayout
+        implements ValueAnimator.AnimatorUpdateListener {
 
-    private static final String TAG = "RecentsHistoryView";
-    private static final boolean DEBUG = false;
+    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 Interpolator mFastOutSlowInInterpolator;
     private Interpolator mFastOutLinearInInterpolator;
@@ -77,69 +82,101 @@
         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);
         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
                 com.android.internal.R.interpolator.fast_out_slow_in);
         mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
                 com.android.internal.R.interpolator.fast_out_linear_in);
+        mViewBounds = new AnimateableViewBounds(this, 0);
+        setOutlineProvider(mViewBounds);
     }
 
     /**
      * Updates this history view with the recent tasks, and then shows it.
      */
-    public void show(TaskStack stack, ReferenceCountedTrigger postHideAnimationTrigger) {
+    public void show(TaskStack stack, int stackHeight, View clearAllButton) {
         setVisibility(View.VISIBLE);
         setAlpha(0f);
-        postHideAnimationTrigger.addLastDecrementRunnable(new Runnable() {
-            @Override
-            public void run() {
-                animate()
-                        .alpha(1f)
-                        .setDuration(mHistoryTransitionDuration)
-                        .setInterpolator(mFastOutSlowInInterpolator)
-                        .withLayer()
-                        .start();
-            }
-        });
-        mAdapter.updateTasks(getContext(), stack.getHistoricalTasks());
+        setTranslationY(-stackHeight * TRANSLATION_Y_PCT);
+        animate()
+                .alpha(1f)
+                .translationY(0f)
+                .setDuration(mHistoryTransitionDuration)
+                .setInterpolator(mFastOutSlowInInterpolator)
+                .setUpdateListener(this)
+                .start();
+        clearAllButton.setVisibility(View.VISIBLE);
+        clearAllButton.setAlpha(0f);
+        clearAllButton.animate()
+                .alpha(1f)
+                .setDuration(mHistoryTransitionDuration)
+                .setInterpolator(mFastOutSlowInInterpolator)
+                .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, final ReferenceCountedTrigger postAnimationTrigger) {
+    public void hide(boolean animate, int stackHeight, final View clearAllButton) {
         if (animate) {
             animate()
                     .alpha(0f)
+                    .translationY(-stackHeight * TRANSLATION_Y_PCT)
                     .setDuration(mHistoryTransitionDuration)
                     .setInterpolator(mFastOutLinearInInterpolator)
+                    .setUpdateListener(this)
                     .withEndAction(new Runnable() {
                         @Override
                         public void run() {
                             setVisibility(View.INVISIBLE);
-                            if (postAnimationTrigger != null) {
-                                postAnimationTrigger.decrement();
-                            }
+                        }
+                    })
+                    .start();
+            clearAllButton.animate()
+                    .alpha(0f)
+                    .translationY(0f)
+                    .setDuration(mHistoryTransitionDuration)
+                    .setInterpolator(mFastOutSlowInInterpolator)
+                    .withEndAction(new Runnable() {
+                        @Override
+                        public void run() {
+                            clearAllButton.setVisibility(View.INVISIBLE);
                         }
                     })
                     .withLayer()
                     .start();
-            if (postAnimationTrigger != null) {
-                postAnimationTrigger.increment();
-            }
         } 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.left, systemInsets.top, systemInsets.right, systemInsets.bottom);
+        mSystemInsets.set(systemInsets);
+        requestLayout();
+    }
+
+    /**
+     * Updates the header height to account for the history button bar.
+     */
+    public void setHeaderHeight(int height) {
+        mHeaderHeight = height;
         requestLayout();
     }
 
@@ -156,6 +193,8 @@
         mRecyclerView = (RecyclerView) findViewById(R.id.list);
         mRecyclerView.setAdapter(mAdapter);
         mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+        ItemTouchHelper touchHelper = new ItemTouchHelper(mItemTouchHandler);
+        touchHelper.attachToRecyclerView(mRecyclerView);
     }
 
     @Override
@@ -172,7 +211,7 @@
         int stackHeightPadding = mContext.getResources().getDimensionPixelSize(
                 R.dimen.recents_stack_top_padding);
         mRecyclerView.setPadding(stackWidthPadding + mSystemInsets.left,
-                stackHeightPadding + mSystemInsets.top,
+                stackHeightPadding + mSystemInsets.top + mHeaderHeight,
                 stackWidthPadding + mSystemInsets.right, mSystemInsets.bottom);
 
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -180,7 +219,6 @@
 
     @Override
     protected void onAttachedToWindow() {
-        SystemServicesProxy ssp = Recents.getSystemServices();
         EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
         super.onAttachedToWindow();
     }
@@ -197,9 +235,25 @@
         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 dc8f547..244c0df 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
@@ -64,6 +64,13 @@
     }
 
     /**
+     * Updates the duration that we have to wait until dozing triggers.
+     */
+    public void setDozeDuration(int duration) {
+        mDozeDurationMilliseconds = duration;
+    }
+
+    /**
      * Poke this dozer to wake it up if it is dozing, delaying the onSleepRunnable from being
      * called for a for the doze duration.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/RectFEvaluator.java b/packages/SystemUI/src/com/android/systemui/recents/misc/RectFEvaluator.java
new file mode 100644
index 0000000..72511de
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/RectFEvaluator.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.systemui.recents.misc;
+
+import android.animation.TypeEvaluator;
+import android.graphics.RectF;
+
+/**
+ * This evaluator can be used to perform type interpolation between <code>RectF</code> values.
+ */
+public class RectFEvaluator implements TypeEvaluator<RectF> {
+
+    private RectF mRect = new RectF();
+
+    /**
+     * This function returns the result of linearly interpolating the start and
+     * end Rect values, with <code>fraction</code> representing the proportion
+     * between the start and end values. The calculation is a simple parametric
+     * calculation on each of the separate components in the Rect objects
+     * (left, top, right, and bottom).
+     *
+     * <p>The object returned will be the <code>reuseRect</code> passed into the constructor.</p>
+     *
+     * @param fraction   The fraction from the starting to the ending values
+     * @param startValue The start Rect
+     * @param endValue   The end Rect
+     * @return A linear interpolation between the start and end values, given the
+     *         <code>fraction</code> parameter.
+     */
+    @Override
+    public RectF evaluate(float fraction, RectF startValue, RectF endValue) {
+        float left = startValue.left + ((endValue.left - startValue.left) * fraction);
+        float top = startValue.top + ((endValue.top - startValue.top) * fraction);
+        float right = startValue.right + ((endValue.right - startValue.right) * fraction);
+        float bottom = startValue.bottom + ((endValue.bottom - startValue.bottom) * fraction);
+        mRect.set(left, top, right, bottom);
+        return mRect;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java
index b06539a..2637d88 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java
@@ -18,8 +18,6 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.content.Context;
-import android.util.Log;
 
 import java.util.ArrayList;
 
@@ -29,12 +27,9 @@
  */
 public class ReferenceCountedTrigger {
 
-    private static final String TAG = "ReferenceCountedTrigger";
-
-    Context mContext;
     int mCount;
-    ArrayList<Runnable> mFirstIncRunnables = new ArrayList<Runnable>();
-    ArrayList<Runnable> mLastDecRunnables = new ArrayList<Runnable>();
+    ArrayList<Runnable> mFirstIncRunnables = new ArrayList<>();
+    ArrayList<Runnable> mLastDecRunnables = new ArrayList<>();
     Runnable mErrorRunnable;
 
     // Convenience runnables
@@ -51,13 +46,12 @@
         }
     };
 
-    public ReferenceCountedTrigger(Context context) {
-        this(context, null, null, null);
+    public ReferenceCountedTrigger() {
+        this(null, null, null);
     }
 
-    public ReferenceCountedTrigger(Context context, Runnable firstIncRunnable,
-                                   Runnable lastDecRunnable, Runnable errorRunanable) {
-        mContext = context;
+    public ReferenceCountedTrigger(Runnable firstIncRunnable, Runnable lastDecRunnable,
+            Runnable errorRunanable) {
         if (firstIncRunnable != null) mFirstIncRunnables.add(firstIncRunnable);
         if (lastDecRunnable != null) mLastDecRunnables.add(lastDecRunnable);
         mErrorRunnable = errorRunanable;
@@ -81,22 +75,14 @@
 
     /** Adds a runnable to the last-decrement runnables list. */
     public void addLastDecrementRunnable(Runnable r) {
-        // To ensure that the last decrement always calls, we increment and decrement after setting
-        // the last decrement runnable
-        boolean ensureLastDecrement = (mCount == 0);
-        if (ensureLastDecrement) increment();
         mLastDecRunnables.add(r);
-        if (ensureLastDecrement) decrement();
     }
 
     /** Decrements the ref count */
     public void decrement() {
         mCount--;
-        if (mCount == 0 && !mLastDecRunnables.isEmpty()) {
-            int numRunnables = mLastDecRunnables.size();
-            for (int i = 0; i < numRunnables; i++) {
-                mLastDecRunnables.get(i).run();
-            }
+        if (mCount == 0) {
+            flushLastDecrementRunnables();
         } else if (mCount < 0) {
             if (mErrorRunnable != null) {
                 mErrorRunnable.run();
@@ -106,16 +92,33 @@
         }
     }
 
-    /** Convenience method to decrement this trigger as a runnable. */
-    public Runnable decrementAsRunnable() {
-        return mDecrementRunnable;
+    /**
+     * Runs and clears all the last-decrement runnables now.
+     */
+    public void flushLastDecrementRunnables() {
+        if (!mLastDecRunnables.isEmpty()) {
+            int numRunnables = mLastDecRunnables.size();
+            for (int i = 0; i < numRunnables; i++) {
+                mLastDecRunnables.get(i).run();
+            }
+        }
+        mLastDecRunnables.clear();
     }
-    /** Convenience method to decrement this trigger as a animator listener. */
+
+    /**
+     * Convenience method to decrement this trigger as a animator listener.  This listener is
+     * guarded to prevent being called back multiple times, and will trigger a decrement once and
+     * only once.
+     */
     public Animator.AnimatorListener decrementOnAnimationEnd() {
         return new AnimatorListenerAdapter() {
+            private boolean hasEnded;
+
             @Override
             public void onAnimationEnd(Animator animation) {
+                if (hasEnded) return;
                 decrement();
+                hasEnded = true;
             }
         };
     }
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 5888b30..aa006d1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -30,6 +30,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
@@ -43,6 +44,7 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
@@ -57,8 +59,10 @@
 import android.util.MutableBoolean;
 import android.util.Pair;
 import android.view.Display;
-import android.view.IDockDividerVisibilityListener;
+import android.view.IDockedStackListener;
+import android.view.View;
 import android.view.WindowManager;
+import android.view.WindowManager.KeyboardShortcutsReceiver;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityManager;
 import com.android.internal.app.AssistUtils;
@@ -77,7 +81,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.HOME_STACK_ID;
-import static android.app.ActivityManager.StackId.INVALID_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
@@ -127,7 +132,9 @@
         mDisplay = mWm.getDefaultDisplay();
         mRecentsPackage = context.getPackageName();
         mHasFreeformWorkspaceSupport =
-                mPm.hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT);
+                mPm.hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT) ||
+                        Settings.Global.getInt(context.getContentResolver(),
+                                DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
 
         // Get the dummy thumbnail width/heights
         Resources res = context.getResources();
@@ -145,7 +152,7 @@
         // Resolve the assist intent
         mAssistComponent = mAssistUtils.getAssistComponentForUser(UserHandle.myUserId());
 
-        if (RecentsDebugFlags.Static.EnableSystemServicesProxy) {
+        if (RecentsDebugFlags.Static.EnableMockTasks) {
             // Create a dummy icon
             mDummyIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
             mDummyIcon.eraseColor(0xFF999999);
@@ -158,20 +165,20 @@
         if (mAm == null) return null;
 
         // If we are mocking, then create some recent tasks
-        if (RecentsDebugFlags.Static.EnableSystemServicesProxy) {
+        if (RecentsDebugFlags.Static.EnableMockTasks) {
             ArrayList<ActivityManager.RecentTaskInfo> tasks =
                     new ArrayList<ActivityManager.RecentTaskInfo>();
-            int count = Math.min(numLatestTasks, RecentsDebugFlags.Static.SystemServicesProxyMockTaskCount);
+            int count = Math.min(numLatestTasks, RecentsDebugFlags.Static.MockTaskCount);
             for (int i = 0; i < count; i++) {
                 // Create a dummy component name
-                int packageIndex = i % RecentsDebugFlags.Static.SystemServicesProxyMockPackageCount;
+                int packageIndex = i % RecentsDebugFlags.Static.MockTasksPackageCount;
                 ComponentName cn = new ComponentName("com.android.test" + packageIndex,
                         "com.android.test" + i + ".Activity");
                 String description = "" + i + " - " +
                         Long.toString(Math.abs(new Random().nextLong()), 36);
                 // Create the recent task info
                 ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
-                rti.id = rti.persistentId = i;
+                rti.id = rti.persistentId = rti.affiliatedTaskId = i;
                 rti.baseIntent = new Intent();
                 rti.baseIntent.setComponent(cn);
                 rti.description = description;
@@ -193,6 +200,8 @@
         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_PINNED_STACK_TASKS |
                 ActivityManager.RECENT_IGNORE_UNAVAILABLE |
                 ActivityManager.RECENT_INCLUDE_PROFILES |
                 ActivityManager.RECENT_WITH_EXCLUDED, userId);
@@ -258,8 +267,9 @@
             ComponentName topActivity = topTask.topActivity;
 
             // Check if the front most activity is recents
-            if (topActivity.getPackageName().equals(RecentsImpl.RECENTS_PACKAGE) &&
-                    topActivity.getClassName().equals(RecentsImpl.RECENTS_ACTIVITY)) {
+            if ((topActivity.getPackageName().equals(RecentsImpl.RECENTS_PACKAGE) &&
+                    (topActivity.getClassName().equals(RecentsImpl.RECENTS_ACTIVITY) ||
+                    topActivity.getClassName().equals(RecentsImpl.RECENTS_TV_ACTIVITY)))) {
                 if (isHomeTopMost != null) {
                     isHomeTopMost.value = false;
                 }
@@ -301,13 +311,16 @@
     }
 
     /** Docks a task to the side of the screen and starts it. */
-    public void startTaskInDockedMode(int taskId, int createMode) {
+    public void startTaskInDockedMode(Context context, View view, int taskId, int createMode) {
         if (mIam == null) return;
 
         try {
-            final ActivityOptions options = ActivityOptions.makeBasic();
+            // 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);
             options.setDockCreateMode(createMode);
-            mIam.startActivityFromRecents(taskId, DOCKED_STACK_ID, options.toBundle());
+            options.setLaunchStackId(DOCKED_STACK_ID);
+            mIam.startActivityFromRecents(taskId, options.toBundle());
         } catch (RemoteException e) {
             e.printStackTrace();
         }
@@ -345,6 +358,13 @@
     }
 
     /**
+     * Returns whether the given stack id is the pinned stack id.
+     */
+    public static boolean isPinnedStack(int stackId){
+        return stackId == PINNED_STACK_ID;
+    }
+
+    /**
      * Returns whether the given stack id is the docked stack id.
      */
     public static boolean isDockedStack(int stackId) {
@@ -359,7 +379,7 @@
     }
 
     /**
-     * @return whether there are any docked tasks.
+     * @return whether there are any docked tasks for the current user.
      */
     public boolean hasDockedTask() {
         if (mIam == null) return false;
@@ -370,7 +390,16 @@
         } catch (RemoteException e) {
             e.printStackTrace();
         }
-        return stackInfo != null;
+
+        if (stackInfo != null) {
+            int userId = getCurrentUser();
+            boolean hasUserTask = false;
+            for (int i = stackInfo.taskUserIds.length - 1; i >= 0 && !hasUserTask; i--) {
+                hasUserTask = (stackInfo.taskUserIds[i] == userId);
+            }
+            return hasUserTask;
+        }
+        return false;
     }
 
     /**
@@ -404,7 +433,7 @@
         if (mAm == null) return null;
 
         // If we are mocking, then just return a dummy thumbnail
-        if (RecentsDebugFlags.Static.EnableSystemServicesProxy) {
+        if (RecentsDebugFlags.Static.EnableMockTasks) {
             Bitmap thumbnail = Bitmap.createBitmap(mDummyThumbnailWidth, mDummyThumbnailHeight,
                     Bitmap.Config.ARGB_8888);
             thumbnail.eraseColor(0xff333333);
@@ -462,7 +491,7 @@
 
         try {
             mIam.positionTaskInStack(taskId, stackId, 0);
-        } catch (RemoteException e) {
+        } catch (RemoteException | IllegalArgumentException e) {
             e.printStackTrace();
         }
     }
@@ -470,7 +499,7 @@
     /** Moves a task to the front with the specified activity options. */
     public void moveTaskToFront(int taskId, ActivityOptions opts) {
         if (mAm == null) return;
-        if (RecentsDebugFlags.Static.EnableSystemServicesProxy) return;
+        if (RecentsDebugFlags.Static.EnableMockTasks) return;
 
         if (opts != null) {
             mAm.moveTaskToFront(taskId, ActivityManager.MOVE_TASK_WITH_HOME,
@@ -483,7 +512,7 @@
     /** Removes the task */
     public void removeTask(final int taskId) {
         if (mAm == null) return;
-        if (RecentsDebugFlags.Static.EnableSystemServicesProxy) return;
+        if (RecentsDebugFlags.Static.EnableMockTasks) return;
 
         // Remove the task.
         BackgroundThread.getHandler().post(new Runnable() {
@@ -495,6 +524,18 @@
     }
 
     /**
+     * Sends a message to close other system windows.
+     */
+    public void sendCloseSystemWindows(String reason) {
+        if (ActivityManagerNative.isSystemReady()) {
+            try {
+                mIam.closeSystemDialogs(reason);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /**
      * Returns the activity info for a given component name.
      *
      * @param cn The component name of the activity.
@@ -502,7 +543,7 @@
      */
     public ActivityInfo getActivityInfo(ComponentName cn, int userId) {
         if (mIpm == null) return null;
-        if (RecentsDebugFlags.Static.EnableSystemServicesProxy) return new ActivityInfo();
+        if (RecentsDebugFlags.Static.EnableMockTasks) return new ActivityInfo();
 
         try {
             return mIpm.getActivityInfo(cn, PackageManager.GET_META_DATA, userId);
@@ -519,7 +560,7 @@
      */
     public ActivityInfo getActivityInfo(ComponentName cn) {
         if (mPm == null) return null;
-        if (RecentsDebugFlags.Static.EnableSystemServicesProxy) return new ActivityInfo();
+        if (RecentsDebugFlags.Static.EnableMockTasks) return new ActivityInfo();
 
         try {
             return mPm.getActivityInfo(cn, PackageManager.GET_META_DATA);
@@ -529,39 +570,46 @@
         }
     }
 
-    /** Returns the activity label */
-    public String getActivityLabel(ActivityInfo info) {
+    /**
+     * Returns the activity label, badging if necessary.
+     */
+    public String getBadgedActivityLabel(ActivityInfo info, int userId) {
         if (mPm == null) return null;
 
         // If we are mocking, then return a mock label
-        if (RecentsDebugFlags.Static.EnableSystemServicesProxy) {
-            return "Recent Task";
+        if (RecentsDebugFlags.Static.EnableMockTasks) {
+            return "Recent Task: " + userId;
         }
 
-        return info.loadLabel(mPm).toString();
+        return getBadgedLabel(info.loadLabel(mPm).toString(), userId);
     }
 
-    /** Returns the application label */
-    public String getApplicationLabel(Intent baseIntent, int userId) {
+    /**
+     * Returns the application label, badging if necessary.
+     */
+    public String getBadgedApplicationLabel(ApplicationInfo appInfo, int userId) {
         if (mPm == null) return null;
 
         // If we are mocking, then return a mock label
-        if (RecentsDebugFlags.Static.EnableSystemServicesProxy) {
-            return "Recent Task";
+        if (RecentsDebugFlags.Static.EnableMockTasks) {
+            return "Recent Task App: " + userId;
         }
 
-        ResolveInfo ri = mPm.resolveActivityAsUser(baseIntent, 0, userId);
-        CharSequence label = (ri != null) ? ri.loadLabel(mPm) : null;
-        return (label != null) ? label.toString() : null;
+        return getBadgedLabel(appInfo.loadLabel(mPm).toString(), userId);
     }
 
-    /** Returns the content description for a given task */
-    public String getContentDescription(Intent baseIntent, int userId, String activityLabel,
-            Resources res) {
-        String applicationLabel = getApplicationLabel(baseIntent, userId);
-        if (applicationLabel == null) {
-            return getBadgedLabel(activityLabel, userId);
+    /**
+     * Returns the content description for a given task, badging it if necessary.  The content
+     * description joins the app and activity labels.
+     */
+    public String getBadgedContentDescription(ActivityInfo info, int userId, Resources res) {
+        // If we are mocking, then return a mock label
+        if (RecentsDebugFlags.Static.EnableMockTasks) {
+            return "Recent Task Content Description: " + userId;
         }
+
+        String activityLabel = info.loadLabel(mPm).toString();
+        String applicationLabel = info.applicationInfo.loadLabel(mPm).toString();
         String badgedApplicationLabel = getBadgedLabel(applicationLabel, userId);
         return applicationLabel.equals(activityLabel) ? badgedApplicationLabel
                 : res.getString(R.string.accessibility_recents_task_header,
@@ -572,11 +620,11 @@
      * Returns the activity icon for the ActivityInfo for a user, badging if
      * necessary.
      */
-    public Drawable getActivityIcon(ActivityInfo info, int userId) {
+    public Drawable getBadgedActivityIcon(ActivityInfo info, int userId) {
         if (mPm == null) return null;
 
         // If we are mocking, then return a mock label
-        if (RecentsDebugFlags.Static.EnableSystemServicesProxy) {
+        if (RecentsDebugFlags.Static.EnableMockTasks) {
             return new ColorDrawable(0xFF666666);
         }
 
@@ -585,9 +633,47 @@
     }
 
     /**
+     * Returns the application icon for the ApplicationInfo for a user, badging if
+     * necessary.
+     */
+    public Drawable getBadgedApplicationIcon(ApplicationInfo appInfo, int userId) {
+        if (mPm == null) return null;
+
+        // If we are mocking, then return a mock label
+        if (RecentsDebugFlags.Static.EnableMockTasks) {
+            return new ColorDrawable(0xFF666666);
+        }
+
+        Drawable icon = appInfo.loadIcon(mPm);
+        return getBadgedIcon(icon, userId);
+    }
+
+    /**
+     * Returns the task description icon, loading and badging it if it necessary.
+     */
+    public Drawable getBadgedTaskDescriptionIcon(ActivityManager.TaskDescription taskDescription,
+            int userId, Resources res) {
+
+        // If we are mocking, then return a mock label
+        if (RecentsDebugFlags.Static.EnableMockTasks) {
+            return new ColorDrawable(0xFF666666);
+        }
+
+        Bitmap tdIcon = taskDescription.getInMemoryIcon();
+        if (tdIcon == null) {
+            tdIcon = ActivityManager.TaskDescription.loadTaskDescriptionIcon(
+                    taskDescription.getIconFilename(), userId);
+        }
+        if (tdIcon != null) {
+            return getBadgedIcon(new BitmapDrawable(res, tdIcon), userId);
+        }
+        return null;
+    }
+
+    /**
      * Returns the given icon for a user, badging if necessary.
      */
-    public Drawable getBadgedIcon(Drawable icon, int userId) {
+    private Drawable getBadgedIcon(Drawable icon, int userId) {
         if (userId != UserHandle.myUserId()) {
             icon = mPm.getUserBadgedIcon(icon, new UserHandle(userId));
         }
@@ -597,7 +683,7 @@
     /**
      * Returns the given label for a user, badging if necessary.
      */
-    public String getBadgedLabel(String label, int userId) {
+    private String getBadgedLabel(String label, int userId) {
         if (userId != UserHandle.myUserId()) {
             label = mPm.getUserBadgedLabel(label, new UserHandle(userId)).toString();
         }
@@ -607,9 +693,9 @@
     /** Returns the package name of the home activity. */
     public String getHomeActivityPackageName() {
         if (mPm == null) return null;
-        if (RecentsDebugFlags.Static.EnableSystemServicesProxy) return null;
+        if (RecentsDebugFlags.Static.EnableMockTasks) return null;
 
-        ArrayList<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>();
+        ArrayList<ResolveInfo> homeActivities = new ArrayList<>();
         ComponentName defaultHomeActivity = mPm.getHomeActivities(homeActivities);
         if (defaultHomeActivity != null) {
             return defaultHomeActivity.getPackageName();
@@ -697,7 +783,7 @@
     /**
      * Returns the first Recents widget from the same package as the global assist activity.
      */
-    private AppWidgetProviderInfo resolveSearchAppWidget() {
+    public AppWidgetProviderInfo resolveSearchAppWidget() {
         if (mAssistComponent == null) return null;
         List<AppWidgetProviderInfo> widgets = mAwm.getInstalledProviders(
                 AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX);
@@ -739,6 +825,19 @@
     }
 
     /**
+     * Returns whether the current task is in screen-pinning mode.
+     */
+    public boolean isScreenPinningActive() {
+        if (mIam == null) return false;
+
+        try {
+            return mIam.isInLockTaskMode();
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
      * Returns a global setting.
      */
     public int getGlobalSetting(Context context, String setting) {
@@ -811,8 +910,7 @@
             ActivityOptions options) {
         if (mIam != null) {
             try {
-                mIam.startActivityFromRecents(
-                        taskId, INVALID_STACK_ID, options == null ? null : options.toBundle());
+                mIam.startActivityFromRecents(taskId, options == null ? null : options.toBundle());
                 return true;
             } catch (Exception e) {
                 Log.e(TAG, context.getString(R.string.recents_launch_error_message, taskName), e);
@@ -854,14 +952,45 @@
         }
     }
 
-    public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) {
+    public void registerDockedStackListener(IDockedStackListener listener) {
         if (mWm == null) return;
 
         try {
-            WindowManagerGlobal.getWindowManagerService().registerDockDividerVisibilityListener(
-                    listener);
+            WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(listener);
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
+
+    /**
+     * Calculates the size of the dock divider in the current orientation.
+     */
+    public int getDockedDividerSize(Context context) {
+        Resources res = context.getResources();
+        int dividerWindowWidth = res.getDimensionPixelSize(
+                com.android.internal.R.dimen.docked_stack_divider_thickness);
+        int dividerInsets = res.getDimensionPixelSize(
+                com.android.internal.R.dimen.docked_stack_divider_insets);
+        return dividerWindowWidth - 2 * dividerInsets;
+    }
+
+    public void requestKeyboardShortcuts(Context context, KeyboardShortcutsReceiver receiver) {
+        mWm.requestAppKeyboardShortcuts(receiver);
+    }
+
+    public void focusPinnedStack() {
+        try {
+            mIam.setFocusedStack(PINNED_STACK_ID);
+        } catch (RemoteException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void focusHomeStack() {
+        try {
+            mIam.setFocusedStack(HOME_STACK_ID);
+        } catch (RemoteException e) {
+            e.printStackTrace();
+        }
+    }
 }
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 2bf2ccb..f3c4cc3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
@@ -18,13 +18,49 @@
 
 import android.animation.Animator;
 import android.graphics.Color;
+import android.graphics.Rect;
 import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.util.ArraySet;
+import android.util.IntProperty;
+import android.util.Property;
 import android.view.View;
 import android.view.ViewParent;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.views.TaskViewTransform;
+
+import java.util.Collections;
+import java.util.List;
 
 /* Common code */
 public class Utilities {
 
+    public static final Property<Drawable, Integer> DRAWABLE_ALPHA =
+            new IntProperty<Drawable>("drawableAlpha") {
+                @Override
+                public void setValue(Drawable object, int alpha) {
+                    object.setAlpha(alpha);
+                }
+
+                @Override
+                public Integer get(Drawable object) {
+                    return object.getAlpha();
+                }
+            };
+
+    public static final Property<Drawable, Rect> DRAWABLE_RECT =
+            new Property<Drawable, Rect>(Rect.class, "drawableBounds") {
+                @Override
+                public void set(Drawable object, Rect bounds) {
+                    object.setBounds(bounds);
+                }
+
+                @Override
+                public Rect get(Drawable object) {
+                    return object.getBounds();
+                }
+            };
+
     /**
      * @return the first parent walking up the view hierarchy that has the given class type.
      *
@@ -41,6 +77,28 @@
         return null;
     }
 
+    /**
+     * Initializes the {@param setOut} with the given object.
+     */
+    public static <T> ArraySet<T> objectToSet(T obj, ArraySet<T> setOut) {
+        setOut.clear();
+        if (obj != null) {
+            setOut.add(obj);
+        }
+        return setOut;
+    }
+
+    /**
+     * Replaces the contents of {@param setOut} with the contents of the {@param array}.
+     */
+    public static <T> ArraySet<T> arrayToSet(T[] array, ArraySet<T> setOut) {
+        setOut.clear();
+        if (array != null) {
+            Collections.addAll(setOut, array);
+        }
+        return setOut;
+    }
+
     /** Scales a rect about its centroid */
     public static void scaleRectAboutCenter(RectF r, float scale) {
         if (scale != 1.0f) {
@@ -97,4 +155,22 @@
             animator.cancel();
         }
     }
+
+    /**
+     * Updates {@param transforms} to be the same size as {@param tasks}.
+     */
+    public static void matchTaskListSize(List<Task> tasks, List<TaskViewTransform> transforms) {
+        // We can reuse the task transforms where possible to reduce object allocation
+        int taskTransformCount = transforms.size();
+        int taskCount = tasks.size();
+        if (taskTransformCount < taskCount) {
+            // If there are less transforms than tasks, then add as many transforms as necessary
+            for (int i = taskTransformCount; i < taskCount; i++) {
+                transforms.add(new TaskViewTransform());
+            }
+        } else if (taskTransformCount > taskCount) {
+            // If there are more transforms than tasks, then just subset the transform list
+            transforms.subList(taskCount, taskTransformCount).clear();
+        }
+    }
 }
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 dae6e94..3029acf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -22,11 +22,14 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
+import android.os.Debug;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.ArraySet;
-import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
 import com.android.systemui.Prefs;
+import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.RecentsDebugFlags;
@@ -34,6 +37,7 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Formatter;
 import java.util.List;
 
 
@@ -47,9 +51,6 @@
  */
 public class RecentsTaskLoadPlan {
 
-    private static String TAG = "RecentsTaskLoadPlan";
-    private static boolean DEBUG = false;
-
     private static int MIN_NUM_TASKS = 5;
     private static int SESSION_BEGIN_TIME = 1000 /* ms/s */ * 60 /* s/min */ * 60 /* min/hr */ *
             6 /* hrs */;
@@ -95,7 +96,7 @@
     }
 
     /**
-     * An optimization to preload the raw list of tasks.  The raw tasks are saved in least-recent
+     * An optimization to preload the raw list of tasks. The raw tasks are saved in least-recent
      * to most-recent order.
      */
     public synchronized void preloadRawTasks(boolean isTopTaskHome) {
@@ -107,17 +108,10 @@
 
         // Since the raw tasks are given in most-recent to least-recent order, we need to reverse it
         Collections.reverse(mRawTasks);
-
-        if (DEBUG) {
-            Log.d(TAG, "preloadRawTasks, tasks: " + mRawTasks.size());
-            for (ActivityManager.RecentTaskInfo info : mRawTasks) {
-                Log.d(TAG, "  " + info.baseIntent + ", " + info.lastActiveTime);
-            }
-        }
     }
 
     /**
-     * Preloads the list of recent tasks from the system.  After this call, the TaskStack will
+     * Preloads the list of recent tasks from the system. After this call, the TaskStack will
      * have a list of all the recent tasks with their metadata, not including icons or
      * thumbnails which were not cached and have to be loaded.
      *
@@ -125,70 +119,73 @@
      * - least-recent to most-recent stack tasks
      * - least-recent to most-recent freeform tasks
      */
-    public synchronized void preloadPlan(RecentsTaskLoader loader, boolean isTopTaskHome) {
-        if (DEBUG) Log.d(TAG, "preloadPlan");
-
-        RecentsDebugFlags debugFlags = Recents.getDebugFlags();
-        RecentsConfiguration config = Recents.getConfiguration();
-        SystemServicesProxy ssp = Recents.getSystemServices();
+    public synchronized void preloadPlan(RecentsTaskLoader loader, int topTaskId,
+            boolean isTopTaskHome) {
         Resources res = mContext.getResources();
-        ArrayList<Task> freeformTasks = new ArrayList<>();
-        ArrayList<Task> stackTasks = new ArrayList<>();
+        ArrayList<Task> allTasks = new ArrayList<>();
         if (mRawTasks == null) {
             preloadRawTasks(isTopTaskHome);
         }
 
+        SparseArray<Task.TaskKey> affiliatedTasks = new SparseArray<>();
+        SparseIntArray affiliatedTaskCounts = new SparseIntArray();
+        String dismissDescFormat = mContext.getString(
+                R.string.accessibility_recents_item_will_be_dismissed);
+        Formatter dismissDescFormatter = new Formatter();
         long lastStackActiveTime = Prefs.getLong(mContext,
                 Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, 0);
+        if (RecentsDebugFlags.Static.EnableMockTasks) {
+            lastStackActiveTime = 0;
+        }
         long newLastStackActiveTime = -1;
         int taskCount = mRawTasks.size();
         for (int i = 0; i < taskCount; i++) {
             ActivityManager.RecentTaskInfo t = mRawTasks.get(i);
 
+            // Affiliated tasks are returned in a specific order from ActivityManager but without a
+            // lastActiveTime since it hasn't yet been started. However, we later sort the task list
+            // by lastActiveTime, which rearranges the tasks. For now, we need to workaround this
+            // by updating the lastActiveTime of this task to the lastActiveTime of the task it is
+            // affiliated with, in the same order that we encounter it in the original list (just
+            // its index in the task group for the task it is affiliated with).
+            if (t.persistentId != t.affiliatedTaskId) {
+                t.lastActiveTime = affiliatedTasks.get(t.affiliatedTaskId).lastActiveTime +
+                        affiliatedTaskCounts.get(t.affiliatedTaskId, 0) + 1;
+            }
+
             // Compose the task key
             Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, t.stackId, t.baseIntent,
                     t.userId, t.firstActiveTime, t.lastActiveTime);
 
             // This task is only shown in the stack if it statisfies the historical time or min
             // number of tasks constraints. Freeform tasks are also always shown.
-            boolean isStackTask = true;
             boolean isFreeformTask = SystemServicesProxy.isFreeformStack(t.stackId);
-            isStackTask = isFreeformTask || (!isHistoricalTask(t) ||
-                    (t.lastActiveTime >= lastStackActiveTime &&
-                            i >= (taskCount - MIN_NUM_TASKS)));
+            boolean isStackTask = isFreeformTask || (!isHistoricalTask(t) ||
+                    (t.lastActiveTime >= lastStackActiveTime && i >= (taskCount - MIN_NUM_TASKS)));
+            boolean isLaunchTarget = taskKey.id == topTaskId;
             if (isStackTask && newLastStackActiveTime < 0) {
                 newLastStackActiveTime = t.lastActiveTime;
             }
 
-            // Load the label, icon, and color
-            String activityLabel = loader.getAndUpdateActivityLabel(taskKey, t.taskDescription,
-                    ssp);
-            String contentDescription = loader.getAndUpdateContentDescription(taskKey,
-                    activityLabel, ssp, res);
-            Drawable activityIcon = isStackTask
-                    ? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, ssp, res, false)
+            // Load the title, icon, and color
+            String title = loader.getAndUpdateActivityTitle(taskKey, t.taskDescription);
+            String contentDescription = loader.getAndUpdateContentDescription(taskKey, res);
+            String dismissDescription = dismissDescFormatter.format(dismissDescFormat,
+                    contentDescription).toString();
+            Drawable icon = isStackTask
+                    ? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, res, false)
                     : null;
+            Bitmap thumbnail = loader.getAndUpdateThumbnail(taskKey, false);
             int activityColor = loader.getActivityPrimaryColor(t.taskDescription);
 
-            Bitmap icon = t.taskDescription != null
-                    ? t.taskDescription.getInMemoryIcon() : null;
-            String iconFilename = t.taskDescription != null
-                    ? t.taskDescription.getIconFilename() : null;
-
             // Add the task to the stack
-            Task task = new Task(taskKey, t.affiliatedTaskId, t.affiliatedTaskColor, activityLabel,
-                    contentDescription, activityIcon, activityColor, (i == (taskCount - 1)),
-                    config.lockToAppEnabled, !isStackTask, icon, iconFilename, t.bounds);
-            task.thumbnail = loader.getAndUpdateThumbnail(taskKey, ssp, false);
-            if (DEBUG) {
-                Log.d(TAG, activityLabel + " bounds: " + t.bounds);
-            }
+            Task task = new Task(taskKey, t.affiliatedTaskId, t.affiliatedTaskColor, icon,
+                    thumbnail, title, contentDescription, dismissDescription, activityColor,
+                    !isStackTask, isLaunchTarget, t.bounds, t.taskDescription);
 
-            if (task.isFreeformTask()) {
-                freeformTasks.add(task);
-            } else {
-                stackTasks.add(task);
-            }
+            allTasks.add(task);
+            affiliatedTaskCounts.put(taskKey.id, affiliatedTaskCounts.get(taskKey.id, 0) + 1);
+            affiliatedTasks.put(taskKey.id, taskKey);
         }
         if (newLastStackActiveTime != -1) {
             Prefs.putLong(mContext, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME,
@@ -196,11 +193,8 @@
         }
 
         // Initialize the stacks
-        ArrayList<Task> allTasks = new ArrayList<>();
-        allTasks.addAll(stackTasks);
-        allTasks.addAll(freeformTasks);
         mStack = new TaskStack();
-        mStack.setTasks(allTasks);
+        mStack.setTasks(allTasks, false /* notifyStackChanges */);
         mStack.createAffiliatedGroupings(mContext);
     }
 
@@ -209,19 +203,13 @@
      */
     public synchronized void executePlan(Options opts, RecentsTaskLoader loader,
             TaskResourceLoadQueue loadQueue) {
-        if (DEBUG) Log.d(TAG, "executePlan, # tasks: " + opts.numVisibleTasks +
-                ", # thumbnails: " + opts.numVisibleTaskThumbnails +
-                ", running task id: " + opts.runningTaskId);
-
         RecentsConfiguration config = Recents.getConfiguration();
-        SystemServicesProxy ssp = Recents.getSystemServices();
         Resources res = mContext.getResources();
 
         // Iterate through each of the tasks and load them according to the load conditions.
         ArrayList<Task> tasks = mStack.getStackTasks();
         int taskCount = tasks.size();
         for (int i = 0; i < taskCount; i++) {
-            ActivityManager.RecentTaskInfo t = mRawTasks.get(i);
             Task task = tasks.get(i);
             Task.TaskKey taskKey = task.key;
 
@@ -235,17 +223,15 @@
             }
 
             if (opts.loadIcons && (isRunningTask || isVisibleTask)) {
-                if (task.activityIcon == null) {
-                    if (DEBUG) Log.d(TAG, "\tLoading icon: " + taskKey);
-                    task.activityIcon = loader.getAndUpdateActivityIcon(taskKey, t.taskDescription,
-                            ssp, res, true);
+                if (task.icon == null) {
+                    task.icon = loader.getAndUpdateActivityIcon(taskKey, task.taskDescription,
+                            res, true);
                 }
             }
             if (opts.loadThumbnails && (isRunningTask || isVisibleThumbnail)) {
                 if (task.thumbnail == null || isRunningTask) {
-                    if (DEBUG) Log.d(TAG, "\tLoading thumbnail: " + taskKey);
                     if (config.svelteLevel <= RecentsConfiguration.SVELTE_LIMIT_CACHE) {
-                        task.thumbnail = loader.getAndUpdateThumbnail(taskKey, ssp, true);
+                        task.thumbnail = loader.getAndUpdateThumbnail(taskKey, true);
                     } else if (config.svelteLevel == RecentsConfiguration.SVELTE_DISABLE_CACHE) {
                         loadQueue.addTask(task);
                     }
@@ -264,7 +250,7 @@
     /** Returns whether there are any tasks in any stacks. */
     public boolean hasTasks() {
         if (mStack != null) {
-            return mStack.getStackTaskCount() > 0;
+            return mStack.getTaskCount() > 0;
         }
         return false;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index 965e7a67..5c77d8a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -93,23 +93,23 @@
     Handler mMainThreadHandler;
 
     TaskResourceLoadQueue mLoadQueue;
-    TaskKeyLruCache<Drawable> mApplicationIconCache;
+    TaskKeyLruCache<Drawable> mIconCache;
     TaskKeyLruCache<Bitmap> mThumbnailCache;
     Bitmap mDefaultThumbnail;
-    BitmapDrawable mDefaultApplicationIcon;
+    BitmapDrawable mDefaultIcon;
 
     boolean mCancelled;
     boolean mWaitingOnLoadQueue;
 
     /** Constructor, creates a new loading thread that loads task resources in the background */
     public BackgroundTaskLoader(TaskResourceLoadQueue loadQueue,
-            TaskKeyLruCache<Drawable> applicationIconCache, TaskKeyLruCache<Bitmap> thumbnailCache,
-            Bitmap defaultThumbnail, BitmapDrawable defaultApplicationIcon) {
+            TaskKeyLruCache<Drawable> iconCache, TaskKeyLruCache<Bitmap> thumbnailCache,
+            Bitmap defaultThumbnail, BitmapDrawable defaultIcon) {
         mLoadQueue = loadQueue;
-        mApplicationIconCache = applicationIconCache;
+        mIconCache = iconCache;
         mThumbnailCache = thumbnailCache;
         mDefaultThumbnail = defaultThumbnail;
-        mDefaultApplicationIcon = defaultApplicationIcon;
+        mDefaultIcon = defaultIcon;
         mMainThreadHandler = new Handler();
         mLoadThread = new HandlerThread("Recents-TaskResourceLoader",
                 android.os.Process.THREAD_PRIORITY_BACKGROUND);
@@ -163,30 +163,30 @@
                     // Load the next item from the queue
                     final Task t = mLoadQueue.nextTask();
                     if (t != null) {
-                        Drawable cachedIcon = mApplicationIconCache.get(t.key);
+                        Drawable cachedIcon = mIconCache.get(t.key);
                         Bitmap cachedThumbnail = mThumbnailCache.get(t.key);
 
-                        // Load the application icon if it is stale or we haven't cached one yet
+                        // Load the icon if it is stale or we haven't cached one yet
                         if (cachedIcon == null) {
-                            cachedIcon = getTaskDescriptionIcon(t.key, t.icon, t.iconFilename, ssp,
-                                    mContext.getResources());
+                            cachedIcon = ssp.getBadgedTaskDescriptionIcon(t.taskDescription,
+                                    t.key.userId, mContext.getResources());
 
                             if (cachedIcon == null) {
                                 ActivityInfo info = ssp.getActivityInfo(
                                         t.key.getComponent(), t.key.userId);
                                 if (info != null) {
                                     if (DEBUG) Log.d(TAG, "Loading icon: " + t.key);
-                                    cachedIcon = ssp.getActivityIcon(info, t.key.userId);
+                                    cachedIcon = ssp.getBadgedActivityIcon(info, t.key.userId);
                                 }
                             }
 
                             if (cachedIcon == null) {
-                                cachedIcon = mDefaultApplicationIcon;
+                                cachedIcon = mDefaultIcon;
                             }
 
                             // At this point, even if we can't load the icon, we will set the
                             // default icon.
-                            mApplicationIconCache.put(t.key, cachedIcon);
+                            mIconCache.put(t.key, cachedIcon);
                         }
                         // Load the thumbnail if it is stale or we haven't cached one yet
                         if (cachedThumbnail == null) {
@@ -234,18 +234,6 @@
             }
         }
     }
-
-    Drawable getTaskDescriptionIcon(Task.TaskKey taskKey, Bitmap iconBitmap, String iconFilename,
-            SystemServicesProxy ssp, Resources res) {
-        Bitmap tdIcon = iconBitmap != null
-                ? iconBitmap
-                : ActivityManager.TaskDescription.loadTaskDescriptionIcon(iconFilename,
-                        taskKey.userId);
-        if (tdIcon != null) {
-            return ssp.getBadgedIcon(new BitmapDrawable(res, tdIcon), taskKey.userId);
-        }
-        return null;
-    }
 }
 
 /**
@@ -262,7 +250,7 @@
     // active time.  Instead, we rely on the RecentsPackageMonitor to keep us informed whenever a
     // package in the cache has been updated, so that we may remove it.
     private final LruCache<ComponentName, ActivityInfo> mActivityInfoCache;
-    private final TaskKeyLruCache<Drawable> mApplicationIconCache;
+    private final TaskKeyLruCache<Drawable> mIconCache;
     private final TaskKeyLruCache<Bitmap> mThumbnailCache;
     private final TaskKeyLruCache<String> mActivityLabelCache;
     private final TaskKeyLruCache<String> mContentDescriptionCache;
@@ -275,7 +263,7 @@
     private int mNumVisibleThumbnailsLoaded;
 
     int mDefaultTaskBarBackgroundColor;
-    BitmapDrawable mDefaultApplicationIcon;
+    BitmapDrawable mDefaultIcon;
     Bitmap mDefaultThumbnail;
 
     public RecentsTaskLoader(Context context) {
@@ -295,22 +283,22 @@
         mDefaultThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
         mDefaultThumbnail.setHasAlpha(false);
         mDefaultThumbnail.eraseColor(0xFFffffff);
-        mDefaultApplicationIcon = new BitmapDrawable(context.getResources(), icon);
+        mDefaultIcon = new BitmapDrawable(context.getResources(), icon);
 
         // Initialize the proxy, cache and loaders
         int numRecentTasks = ActivityManager.getMaxRecentTasksStatic();
         mLoadQueue = new TaskResourceLoadQueue();
-        mApplicationIconCache = new TaskKeyLruCache<>(iconCacheSize);
+        mIconCache = new TaskKeyLruCache<>(iconCacheSize);
         mThumbnailCache = new TaskKeyLruCache<>(thumbnailCacheSize);
         mActivityLabelCache = new TaskKeyLruCache<>(numRecentTasks);
         mContentDescriptionCache = new TaskKeyLruCache<>(numRecentTasks);
         mActivityInfoCache = new LruCache(numRecentTasks);
-        mLoader = new BackgroundTaskLoader(mLoadQueue, mApplicationIconCache, mThumbnailCache,
-                mDefaultThumbnail, mDefaultApplicationIcon);
+        mLoader = new BackgroundTaskLoader(mLoadQueue, mIconCache, mThumbnailCache,
+                mDefaultThumbnail, mDefaultIcon);
     }
 
     /** Returns the size of the app icon cache. */
-    public int getApplicationIconCacheSize() {
+    public int getIconCacheSize() {
         return mMaxIconCacheSize;
     }
 
@@ -326,8 +314,8 @@
     }
 
     /** Preloads recents tasks using the specified plan to store the output. */
-    public void preloadTasks(RecentsTaskLoadPlan plan, boolean isTopTaskHome) {
-        plan.preloadPlan(this, isTopTaskHome);
+    public void preloadTasks(RecentsTaskLoadPlan plan, int topTaskId, boolean isTopTaskHome) {
+        plan.preloadPlan(this, topTaskId, isTopTaskHome);
     }
 
     /** Begins loading the heavy task data according to the specified options. */
@@ -346,35 +334,46 @@
         }
     }
 
-    /** Acquires the task resource data directly from the pool. */
-    public void loadTaskData(Task t) {
-        Drawable applicationIcon = mApplicationIconCache.getAndInvalidateIfModified(t.key);
-        Bitmap thumbnail = mThumbnailCache.getAndInvalidateIfModified(t.key);
+    /**
+     * Acquires the task resource data directly from the cache, loading if necessary.
+     *
+     * @param fetchAndInvalidateThumbnails If set, will try loading thumbnails, invalidating them
+     *                                     in the cache and loading if necessary. Otherwise, do not
+     *                                     load the thumbnail unless the icon also has to be loaded.
+     */
+    public void loadTaskData(Task t, boolean fetchAndInvalidateThumbnails) {
+        Drawable icon = mIconCache.getAndInvalidateIfModified(t.key);
+        Bitmap thumbnail = mDefaultThumbnail;
+        if (fetchAndInvalidateThumbnails) {
+            thumbnail = mThumbnailCache.getAndInvalidateIfModified(t.key);
+        }
 
         // Grab the thumbnail/icon from the cache, if either don't exist, then trigger a reload and
         // use the default assets in their place until they load
-        boolean requiresLoad = (applicationIcon == null) || (thumbnail == null);
-        applicationIcon = applicationIcon != null ? applicationIcon : mDefaultApplicationIcon;
+        boolean requiresLoad = (icon == null) || (thumbnail == null);
+        icon = icon != null ? icon : mDefaultIcon;
         if (requiresLoad) {
             mLoadQueue.addTask(t);
         }
-        t.notifyTaskDataLoaded(thumbnail == mDefaultThumbnail ? null : thumbnail, applicationIcon);
+        t.notifyTaskDataLoaded(thumbnail == mDefaultThumbnail ? null : thumbnail, icon);
     }
 
     /** Releases the task resource data back into the pool. */
     public void unloadTaskData(Task t) {
         mLoadQueue.removeTask(t);
-        t.notifyTaskDataUnloaded(null, mDefaultApplicationIcon);
+        t.notifyTaskDataUnloaded(null, mDefaultIcon);
     }
 
     /** Completely removes the resource data from the pool. */
     public void deleteTaskData(Task t, boolean notifyTaskDataUnloaded) {
         mLoadQueue.removeTask(t);
         mThumbnailCache.remove(t.key);
-        mApplicationIconCache.remove(t.key);
+        mIconCache.remove(t.key);
+        mActivityLabelCache.remove(t.key);
+        mContentDescriptionCache.remove(t.key);
         mActivityInfoCache.remove(t.key.getComponent());
         if (notifyTaskDataUnloaded) {
-            t.notifyTaskDataUnloaded(null, mDefaultApplicationIcon);
+            t.notifyTaskDataUnloaded(null, mDefaultIcon);
         }
     }
 
@@ -396,14 +395,14 @@
                 } else if (config.svelteLevel >= RecentsConfiguration.SVELTE_DISABLE_CACHE) {
                     mThumbnailCache.evictAll();
                 }
-                mApplicationIconCache.trimToSize(Math.max(mNumVisibleTasksLoaded,
+                mIconCache.trimToSize(Math.max(mNumVisibleTasksLoaded,
                         mMaxIconCacheSize / 2));
                 break;
             case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
             case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
                 // We are leaving recents, so trim the data a bit
                 mThumbnailCache.trimToSize(Math.max(1, mMaxThumbnailCacheSize / 2));
-                mApplicationIconCache.trimToSize(Math.max(1, mMaxIconCacheSize / 2));
+                mIconCache.trimToSize(Math.max(1, mMaxIconCacheSize / 2));
                 mActivityInfoCache.trimToSize(Math.max(1,
                         ActivityManager.getMaxRecentTasksStatic() / 2));
                 break;
@@ -411,7 +410,7 @@
             case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
                 // We are going to be low on memory
                 mThumbnailCache.trimToSize(Math.max(1, mMaxThumbnailCacheSize / 4));
-                mApplicationIconCache.trimToSize(Math.max(1, mMaxIconCacheSize / 4));
+                mIconCache.trimToSize(Math.max(1, mMaxIconCacheSize / 4));
                 mActivityInfoCache.trimToSize(Math.max(1,
                         ActivityManager.getMaxRecentTasksStatic() / 4));
                 break;
@@ -419,7 +418,7 @@
             case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
                 // We are low on memory, so release everything
                 mThumbnailCache.evictAll();
-                mApplicationIconCache.evictAll();
+                mIconCache.evictAll();
                 mActivityInfoCache.evictAll();
                 // The cache is small, only clear the label cache when we are critical
                 mActivityLabelCache.evictAll();
@@ -433,8 +432,9 @@
     /**
      * Returns the cached task label if the task key is not expired, updating the cache if it is.
      */
-    String getAndUpdateActivityLabel(Task.TaskKey taskKey, ActivityManager.TaskDescription td,
-                                     SystemServicesProxy ssp) {
+    String getAndUpdateActivityTitle(Task.TaskKey taskKey, ActivityManager.TaskDescription td) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+
         // Return the task description label if it exists
         if (td != null && td.getLabel() != null) {
             return td.getLabel();
@@ -445,9 +445,9 @@
             return label;
         }
         // All short paths failed, load the label from the activity info and cache it
-        ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey, ssp);
+        ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey);
         if (activityInfo != null) {
-            label = ssp.getActivityLabel(activityInfo);
+            label = ssp.getBadgedActivityLabel(activityInfo, taskKey.userId);
             mActivityLabelCache.put(taskKey, label);
             return label;
         }
@@ -460,20 +460,19 @@
      * Returns the cached task content description if the task key is not expired, updating the
      * cache if it is.
      */
-    String getAndUpdateContentDescription(Task.TaskKey taskKey, String activityLabel,
-            SystemServicesProxy ssp, Resources res) {
+    String getAndUpdateContentDescription(Task.TaskKey taskKey, Resources res) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+
         // Return the cached content description if it exists
         String label = mContentDescriptionCache.getAndInvalidateIfModified(taskKey);
         if (label != null) {
             return label;
         }
-        // If the given activity label is empty, don't compute or cache the content description
-        if (activityLabel.isEmpty()) {
-            return "";
-        }
 
-        label = ssp.getContentDescription(taskKey.baseIntent, taskKey.userId, activityLabel, res);
-        if (label != null) {
+        // All short paths failed, load the label from the activity info and cache it
+        ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey);
+        if (activityInfo != null) {
+            label = ssp.getBadgedContentDescription(activityInfo, taskKey.userId, res);
             mContentDescriptionCache.put(taskKey, label);
             return label;
         }
@@ -486,28 +485,29 @@
      * Returns the cached task icon if the task key is not expired, updating the cache if it is.
      */
     Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey, ActivityManager.TaskDescription td,
-            SystemServicesProxy ssp, Resources res, boolean loadIfNotCached) {
+            Resources res, boolean loadIfNotCached) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+
         // Return the cached activity icon if it exists
-        Drawable icon = mApplicationIconCache.getAndInvalidateIfModified(taskKey);
+        Drawable icon = mIconCache.getAndInvalidateIfModified(taskKey);
         if (icon != null) {
             return icon;
         }
 
         if (loadIfNotCached) {
             // Return and cache the task description icon if it exists
-            icon = mLoader.getTaskDescriptionIcon(taskKey, td.getInMemoryIcon(),
-                    td.getIconFilename(), ssp, res);
+            icon = ssp.getBadgedTaskDescriptionIcon(td, taskKey.userId, res);
             if (icon != null) {
-                mApplicationIconCache.put(taskKey, icon);
+                mIconCache.put(taskKey, icon);
                 return icon;
             }
 
             // Load the icon from the activity info and cache it
-            ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey, ssp);
+            ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey);
             if (activityInfo != null) {
-                icon = ssp.getActivityIcon(activityInfo, taskKey.userId);
+                icon = ssp.getBadgedActivityIcon(activityInfo, taskKey.userId);
                 if (icon != null) {
-                    mApplicationIconCache.put(taskKey, icon);
+                    mIconCache.put(taskKey, icon);
                     return icon;
                 }
             }
@@ -519,8 +519,9 @@
     /**
      * Returns the cached thumbnail if the task key is not expired, updating the cache if it is.
      */
-    Bitmap getAndUpdateThumbnail(Task.TaskKey taskKey, SystemServicesProxy ssp,
-            boolean loadIfNotCached) {
+    Bitmap getAndUpdateThumbnail(Task.TaskKey taskKey, boolean loadIfNotCached) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+
         // Return the cached thumbnail if it exists
         Bitmap thumbnail = mThumbnailCache.getAndInvalidateIfModified(taskKey);
         if (thumbnail != null) {
@@ -543,7 +544,8 @@
     }
 
     /**
-     * Returns the task's primary color.
+     * Returns the task's primary color if possible, defaulting to the default color if there is
+     * no specified primary color.
      */
     int getActivityPrimaryColor(ActivityManager.TaskDescription td) {
         if (td != null && td.getPrimaryColor() != 0) {
@@ -556,7 +558,8 @@
      * Returns the activity info for the given task key, retrieving one from the system if the
      * task key is expired.
      */
-    private ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey, SystemServicesProxy ssp) {
+    private ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
         ComponentName cn = taskKey.getComponent();
         ActivityInfo activityInfo = mActivityInfoCache.get(cn);
         if (activityInfo == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 3aed3f3..193bd17 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.recents.model;
 
+import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.graphics.Bitmap;
@@ -26,6 +27,7 @@
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.Utilities;
 
+import java.util.ArrayList;
 import java.util.Objects;
 
 
@@ -36,7 +38,7 @@
     /* Task callbacks */
     public interface TaskCallbacks {
         /* Notifies when a task has been bound */
-        public void onTaskDataLoaded();
+        public void onTaskDataLoaded(Task task);
         /* Notifies when a task has been unbound */
         public void onTaskDataUnloaded();
         /* Notifies when a task's stack id has changed. */
@@ -52,6 +54,8 @@
         public long firstActiveTime;
         public long lastActiveTime;
 
+        private int mHashCode;
+
         public TaskKey(int id, int stackId, Intent intent, int userId, long firstActiveTime,
                 long lastActiveTime) {
             this.id = id;
@@ -60,6 +64,12 @@
             this.userId = userId;
             this.firstActiveTime = firstActiveTime;
             this.lastActiveTime = lastActiveTime;
+            updateHashCode();
+        }
+
+        public void setStackId(int stackId) {
+            this.stackId = stackId;
+            updateHashCode();
         }
 
         public ComponentName getComponent() {
@@ -77,7 +87,7 @@
 
         @Override
         public int hashCode() {
-            return Objects.hash(id, stackId, userId);
+            return mHashCode;
         }
 
         @Override
@@ -88,85 +98,119 @@
                     + "lat: " + lastActiveTime + ", "
                     + getComponent().getPackageName();
         }
+
+        private void updateHashCode() {
+            mHashCode = Objects.hash(id, stackId, userId);
+        }
     }
 
     public TaskKey key;
+
+    /**
+     * The group will be computed separately from the initialization of the task
+     */
     public TaskGrouping group;
-    // The taskAffiliationId is the task id of the parent task or itself if it is not affiliated with any task
-    public int taskAffiliationId;
-    public int taskAffiliationColor;
-    public boolean isLaunchTarget;
-    public Drawable applicationIcon;
-    public Drawable activityIcon;
+    /**
+     * The affiliationTaskId is the task id of the parent task or itself if it is not affiliated
+     * with any task.
+     */
+    public int affiliationTaskId;
+    public int affiliationColor;
+
+    /**
+     * The icon is the task description icon (if provided), which falls back to the activity icon,
+     * which can then fall back to the application icon.
+     */
+    public Drawable icon;
+    public Bitmap thumbnail;
+    public String title;
     public String contentDescription;
-    public String activityLabel;
+    public String dismissDescription;
     public int colorPrimary;
     public boolean useLightOnPrimaryColor;
-    public Bitmap thumbnail;
-    public boolean lockToThisTask;
-    public boolean lockToTaskEnabled;
-    public boolean isHistorical;
-    public Bitmap icon;
-    public String iconFilename;
+
+    /**
+     * The bounds of the task, used only if it is a freeform task.
+     */
     public Rect bounds;
 
-    private TaskCallbacks mCb;
+    /**
+     * The task description for this task, only used to reload task icons.
+     */
+    public ActivityManager.TaskDescription taskDescription;
+
+    /**
+     * The state isLaunchTarget will be set for the correct task upon launching Recents.
+     */
+    public boolean isLaunchTarget;
+    public boolean isHistorical;
+
+    private ArrayList<TaskCallbacks> mCallbacks = new ArrayList<>();
 
     public Task() {
         // Do nothing
     }
 
-    public Task(TaskKey key, int taskAffiliation, int taskAffiliationColor,
-                String activityTitle, String contentDescription, Drawable activityIcon,
-                int colorPrimary, boolean lockToThisTask, boolean lockToTaskEnabled,
-                boolean isHistorical, Bitmap icon, String iconFilename, Rect bounds) {
-        boolean isInAffiliationGroup = (taskAffiliation != key.id);
-        boolean hasAffiliationGroupColor = isInAffiliationGroup && (taskAffiliationColor != 0);
+    public Task(TaskKey key, int affiliationTaskId, int affiliationColor, Drawable icon,
+                Bitmap thumbnail, String title, String contentDescription,
+                String dismissDescription, int colorPrimary, boolean isHistorical,
+                boolean isLaunchTarget, Rect bounds,
+                ActivityManager.TaskDescription taskDescription) {
+        boolean isInAffiliationGroup = (affiliationTaskId != key.id);
+        boolean hasAffiliationGroupColor = isInAffiliationGroup && (affiliationColor != 0);
         this.key = key;
-        this.taskAffiliationId = taskAffiliation;
-        this.taskAffiliationColor = taskAffiliationColor;
-        this.activityLabel = activityTitle;
+        this.affiliationTaskId = affiliationTaskId;
+        this.affiliationColor = affiliationColor;
+        this.icon = icon;
+        this.thumbnail = thumbnail;
+        this.title = title;
         this.contentDescription = contentDescription;
-        this.activityIcon = activityIcon;
-        this.colorPrimary = hasAffiliationGroupColor ? taskAffiliationColor : colorPrimary;
+        this.dismissDescription = dismissDescription;
+        this.colorPrimary = hasAffiliationGroupColor ? affiliationColor : colorPrimary;
         this.useLightOnPrimaryColor = Utilities.computeContrastBetweenColors(this.colorPrimary,
                 Color.WHITE) > 3f;
-        this.lockToThisTask = lockToTaskEnabled && lockToThisTask;
-        this.lockToTaskEnabled = lockToTaskEnabled;
-        this.isHistorical = isHistorical;
-        this.icon = icon;
-        this.iconFilename = iconFilename;
         this.bounds = bounds;
+        this.taskDescription = taskDescription;
+        this.isLaunchTarget = isLaunchTarget;
+        this.isHistorical = isHistorical;
     }
 
     /** Copies the other task. */
     public void copyFrom(Task o) {
         this.key = o.key;
-        this.taskAffiliationId = o.taskAffiliationId;
-        this.taskAffiliationColor = o.taskAffiliationColor;
-        this.activityLabel = o.activityLabel;
+        this.group = o.group;
+        this.affiliationTaskId = o.affiliationTaskId;
+        this.affiliationColor = o.affiliationColor;
+        this.icon = o.icon;
+        this.thumbnail = o.thumbnail;
+        this.title = o.title;
         this.contentDescription = o.contentDescription;
-        this.activityIcon = o.activityIcon;
+        this.dismissDescription = o.dismissDescription;
         this.colorPrimary = o.colorPrimary;
         this.useLightOnPrimaryColor = o.useLightOnPrimaryColor;
-        this.lockToThisTask = o.lockToThisTask;
-        this.lockToTaskEnabled = o.lockToTaskEnabled;
-        this.isHistorical = o.isHistorical;
-        this.icon = o.icon;
-        this.iconFilename = o.iconFilename;
         this.bounds = o.bounds;
+        this.isLaunchTarget = o.isLaunchTarget;
+        this.isHistorical = o.isHistorical;
     }
 
-    /** Set the callbacks */
-    public void setCallbacks(TaskCallbacks cb) {
-        mCb = cb;
+    /**
+     * Add a callback.
+     */
+    public void addCallback(TaskCallbacks cb) {
+        if (!mCallbacks.contains(cb)) {
+            mCallbacks.add(cb);
+        }
+    }
+
+    /**
+     * Remove a callback.
+     */
+    public void removeCallback(TaskCallbacks cb) {
+        mCallbacks.remove(cb);
     }
 
     /** Set the grouping */
     public void setGroup(TaskGrouping group) {
-        if (group != null && this.group != null) {
-            throw new RuntimeException("This task is already assigned to a group.");
-        }
         this.group = group;
     }
 
@@ -174,9 +218,10 @@
      * Updates the stack id of this task.
      */
     public void setStackId(int stackId) {
-        key.stackId = stackId;
-        if (mCb != null) {
-            mCb.onTaskStackIdChanged();
+        key.setStackId(stackId);
+        int callbackCount = mCallbacks.size();
+        for (int i = 0; i < callbackCount; i++) {
+            mCallbacks.get(i).onTaskStackIdChanged();
         }
     }
 
@@ -190,19 +235,20 @@
 
     /** Notifies the callback listeners that this task has been loaded */
     public void notifyTaskDataLoaded(Bitmap thumbnail, Drawable applicationIcon) {
-        this.applicationIcon = applicationIcon;
+        this.icon = applicationIcon;
         this.thumbnail = thumbnail;
-        if (mCb != null) {
-            mCb.onTaskDataLoaded();
+        int callbackCount = mCallbacks.size();
+        for (int i = 0; i < callbackCount; i++) {
+            mCallbacks.get(i).onTaskDataLoaded(this);
         }
     }
 
     /** Notifies the callback listeners that this task has been unloaded */
     public void notifyTaskDataUnloaded(Bitmap defaultThumbnail, Drawable defaultApplicationIcon) {
-        applicationIcon = defaultApplicationIcon;
+        icon = defaultApplicationIcon;
         thumbnail = defaultThumbnail;
-        if (mCb != null) {
-            mCb.onTaskDataUnloaded();
+        for (int i = mCallbacks.size() - 1; i >= 0; i--) {
+            mCallbacks.get(i).onTaskDataUnloaded();
         }
     }
 
@@ -210,7 +256,7 @@
      * Returns whether this task is affiliated with another task.
      */
     public boolean isAffiliatedTask() {
-        return key.id != taskAffiliationId;
+        return key.id != affiliationTaskId;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskGrouping.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskGrouping.java
index 288f07c..2109376 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskGrouping.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskGrouping.java
@@ -1,7 +1,8 @@
 package com.android.systemui.recents.model;
 
+import android.util.ArrayMap;
+
 import java.util.ArrayList;
-import java.util.HashMap;
 
 /** Represents a grouping of tasks witihin a stack. */
 public class TaskGrouping {
@@ -11,7 +12,7 @@
 
     Task.TaskKey mFrontMostTaskKey;
     ArrayList<Task.TaskKey> mTaskKeys = new ArrayList<Task.TaskKey>();
-    HashMap<Task.TaskKey, Integer> mTaskKeyIndices = new HashMap<Task.TaskKey, Integer>();
+    ArrayMap<Task.TaskKey, Integer> mTaskKeyIndices = new ArrayMap<>();
 
     /** Creates a group with a specified affiliation. */
     public TaskGrouping(int affiliation) {
@@ -94,9 +95,9 @@
             return;
         }
 
+        int taskCount = mTaskKeys.size();
         mFrontMostTaskKey = mTaskKeys.get(mTaskKeys.size() - 1);
         mTaskKeyIndices.clear();
-        int taskCount = mTaskKeys.size();
         for (int i = 0; i < taskCount; i++) {
             Task.TaskKey k = mTaskKeys.get(i);
             mTaskKeyIndices.put(k, i);
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 5d07b10..66eeac6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -16,27 +16,37 @@
 
 package com.android.systemui.recents.model;
 
+import android.animation.Animator;
+import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.RectEvaluator;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.ColorDrawable;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.SparseArray;
+import android.view.animation.Interpolator;
+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.TaskViewAnimation;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Random;
 
@@ -44,6 +54,11 @@
 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;
 
 
 /**
@@ -59,17 +74,14 @@
  */
 class FilteredTaskList {
 
-    private static final String TAG = "FilteredTaskList";
-    private static final boolean DEBUG = false;
-
     ArrayList<Task> mTasks = new ArrayList<>();
     ArrayList<Task> mFilteredTasks = new ArrayList<>();
-    HashMap<Task.TaskKey, Integer> mTaskIndices = new HashMap<>();
+    ArrayMap<Task.TaskKey, Integer> mTaskIndices = new ArrayMap<>();
     TaskFilter mFilter;
 
     /** Sets the task filter, saving the current touch state */
     boolean setFilter(TaskFilter filter) {
-        ArrayList<Task> prevFilteredTasks = new ArrayList<Task>(mFilteredTasks);
+        ArrayList<Task> prevFilteredTasks = new ArrayList<>(mFilteredTasks);
         mFilter = filter;
         updateFilteredTasks();
         if (!prevFilteredTasks.equals(mFilteredTasks)) {
@@ -180,8 +192,8 @@
 
     /** Updates the mapping of tasks to indices. */
     private void updateFilteredTaskIndices() {
-        mTaskIndices.clear();
         int taskCount = mFilteredTasks.size();
+        mTaskIndices.clear();
         for (int i = 0; i < taskCount; i++) {
             Task t = mFilteredTasks.get(i);
             mTaskIndices.put(t.key, i);
@@ -206,12 +218,21 @@
 
     /** Task stack callbacks */
     public interface TaskStackCallbacks {
-        /* Notifies when a task has been removed from the stack */
-        void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
-            Task newFrontMostTask);
+        /**
+         * Notifies when a new task has been added to the stack.
+         */
+        void onStackTaskAdded(TaskStack stack, Task newTask);
 
-        /* Notifies when a task has been removed from the history */
-        void onHistoryTaskRemoved(TaskStack stack, Task removedTask);
+        /**
+         * Notifies when a task has been removed from the stack.
+         */
+        void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
+            Task newFrontMostTask, TaskViewAnimation animation);
+
+        /**
+         * Notifies when a task has been removed from the history.
+         */
+        void onHistoryTaskRemoved(TaskStack stack, Task removedTask, TaskViewAnimation animation);
     }
 
     /**
@@ -220,30 +241,36 @@
     public static class DockState implements DropTarget {
 
         private static final int DOCK_AREA_ALPHA = 192;
-        public static final DockState NONE = new DockState(-1, 96, null, null);
-        public static final DockState LEFT = new DockState(
+        public static final DockState NONE = new DockState(DOCKED_INVALID, -1, 80, null, null, null);
+        public static final DockState LEFT = new DockState(DOCKED_LEFT,
                 DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA,
-                new RectF(0, 0, 0.25f, 1), new RectF(0, 0, 0.25f, 1));
-        public static final DockState TOP = new DockState(
+                new RectF(0, 0, 0.125f, 1), new RectF(0, 0, 0.125f, 1),
+                new RectF(0, 0, 0.5f, 1));
+        public static final DockState TOP = new DockState(DOCKED_TOP,
                 DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA,
-                new RectF(0, 0, 1, 0.25f), new RectF(0, 0, 1, 0.25f));
-        public static final DockState RIGHT = new DockState(
+                new RectF(0, 0, 1, 0.125f), new RectF(0, 0, 1, 0.125f),
+                new RectF(0, 0, 1, 0.5f));
+        public static final DockState RIGHT = new DockState(DOCKED_RIGHT,
                 DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA,
-                new RectF(0.75f, 0, 1, 1), new RectF(0.75f, 0, 1, 1));
-        public static final DockState BOTTOM = new DockState(
+                new RectF(0.875f, 0, 1, 1), new RectF(0.875f, 0, 1, 1),
+                new RectF(0.5f, 0, 1, 1));
+        public static final DockState BOTTOM = new DockState(DOCKED_BOTTOM,
                 DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA,
-                new RectF(0, 0.75f, 1, 1), new RectF(0, 0.75f, 1, 1));
+                new RectF(0, 0.875f, 1, 1), new RectF(0, 0.875f, 1, 1),
+                new RectF(0, 0.5f, 1, 1));
 
         @Override
-        public boolean acceptsDrop(int x, int y, int width, int height) {
-            return touchAreaContainsPoint(width, height, x, y);
+        public boolean acceptsDrop(int x, int y, int width, int height, boolean isCurrentTarget) {
+            return isCurrentTarget
+                    ? areaContainsPoint(expandedTouchDockArea, width, height, x, y)
+                    : areaContainsPoint(touchArea, width, height, x, y);
         }
 
         // Represents the view state of this dock state
         public class ViewState {
             public final int dockAreaAlpha;
             public final ColorDrawable dockAreaOverlay;
-            private ObjectAnimator dockAreaOverlayAnimator;
+            private AnimatorSet dockAreaOverlayAnimator;
 
             private ViewState(int alpha) {
                 dockAreaAlpha = alpha;
@@ -252,56 +279,130 @@
             }
 
             /**
-             * Creates a new alpha animation.
+             * Creates a new bounds and alpha animation.
              */
-            public void startAlphaAnimation(int alpha, int duration) {
+            public void startAnimation(Rect bounds, int alpha, int duration,
+                    Interpolator interpolator, boolean animateAlpha, boolean animateBounds) {
+                if (dockAreaOverlayAnimator != null) {
+                    dockAreaOverlayAnimator.cancel();
+                }
+
+                ArrayList<Animator> animators = new ArrayList<>();
                 if (dockAreaOverlay.getAlpha() != alpha) {
-                    if (dockAreaOverlayAnimator != null) {
-                        dockAreaOverlayAnimator.cancel();
+                    if (animateAlpha) {
+                        animators.add(ObjectAnimator.ofInt(dockAreaOverlay,
+                                Utilities.DRAWABLE_ALPHA, dockAreaOverlay.getAlpha(), alpha));
+                    } else {
+                        dockAreaOverlay.setAlpha(alpha);
                     }
-                    dockAreaOverlayAnimator = ObjectAnimator.ofInt(dockAreaOverlay, "alpha", alpha);
+                }
+                if (bounds != null && !dockAreaOverlay.getBounds().equals(bounds)) {
+                    if (animateBounds) {
+                        PropertyValuesHolder prop = PropertyValuesHolder.ofObject(
+                                Utilities.DRAWABLE_RECT, new RectEvaluator(new Rect()),
+                                dockAreaOverlay.getBounds(), bounds);
+                        animators.add(ObjectAnimator.ofPropertyValuesHolder(dockAreaOverlay, prop));
+                    } else {
+                        dockAreaOverlay.setBounds(bounds);
+                    }
+                }
+                if (!animators.isEmpty()) {
+                    dockAreaOverlayAnimator = new AnimatorSet();
+                    dockAreaOverlayAnimator.playTogether(animators);
                     dockAreaOverlayAnimator.setDuration(duration);
+                    dockAreaOverlayAnimator.setInterpolator(interpolator);
                     dockAreaOverlayAnimator.start();
                 }
             }
         }
 
+        public final int dockSide;
         public final int createMode;
         public final ViewState viewState;
-        private final RectF dockArea;
         private final RectF touchArea;
+        private final RectF dockArea;
+        private final RectF expandedTouchDockArea;
 
         /**
          * @param createMode used to pass to ActivityManager to dock the task
          * @param touchArea the area in which touch will initiate this dock state
          * @param dockArea the visible dock area
+         * @param expandedTouchDockArea the areain which touch will continue to dock after entering
+         *                              the initial touch area.  This is also the new dock area to
+         *                              draw.
          */
-        DockState(int createMode, int dockAreaAlpha, RectF touchArea, RectF dockArea) {
+        DockState(int dockSide, int createMode, int dockAreaAlpha, RectF touchArea, RectF dockArea,
+                  RectF expandedTouchDockArea) {
+            this.dockSide = dockSide;
             this.createMode = createMode;
             this.viewState = new ViewState(dockAreaAlpha);
             this.dockArea = dockArea;
             this.touchArea = touchArea;
+            this.expandedTouchDockArea = expandedTouchDockArea;
         }
 
         /**
-         * Returns whether {@param x} and {@param y} are contained in the touch area scaled to the
+         * Returns whether {@param x} and {@param y} are contained in the area scaled to the
          * given {@param width} and {@param height}.
          */
-        public boolean touchAreaContainsPoint(int width, int height, float x, float y) {
-            int left = (int) (touchArea.left * width);
-            int top = (int) (touchArea.top * height);
-            int right = (int) (touchArea.right * width);
-            int bottom = (int) (touchArea.bottom * height);
+        public boolean areaContainsPoint(RectF area, int width, int height, float x, float y) {
+            int left = (int) (area.left * width);
+            int top = (int) (area.top * height);
+            int right = (int) (area.right * width);
+            int bottom = (int) (area.bottom * height);
             return x >= left && y >= top && x <= right && y <= bottom;
         }
 
         /**
          * Returns the docked task bounds with the given {@param width} and {@param height}.
          */
-        public Rect getDockedBounds(int width, int height) {
+        public Rect getPreDockedBounds(int width, int height) {
             return new Rect((int) (dockArea.left * width), (int) (dockArea.top * height),
                     (int) (dockArea.right * width), (int) (dockArea.bottom * height));
         }
+
+        /**
+         * Returns the expanded docked task bounds with the given {@param width} and
+         * {@param height}.
+         */
+        public Rect getDockedBounds(int width, int height, int dividerSize, Rect insets,
+                Resources res) {
+            // Calculate the 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, dockSide, newWindowBounds,
+                    width, height, dividerSize);
+            return newWindowBounds;
+        }
+
+        /**
+         * Returns the task stack bounds with the given {@param width} and
+         * {@param height}.
+         */
+        public Rect getDockedTaskStackBounds(int width, int height, int dividerSize, Rect insets,
+                Resources res) {
+            RecentsConfiguration config = Recents.getConfiguration();
+
+            // 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,
+                    dividerSize);
+
+            // Calculate the task stack bounds from the new window bounds
+            Rect searchBarSpaceBounds = new Rect();
+            Rect taskStackBounds = new Rect();
+            config.getTaskStackBounds(newWindowBounds, insets.top, insets.right,
+                    searchBarSpaceBounds, taskStackBounds);
+            return taskStackBounds;
+        }
     }
 
     // A comparator that sorts tasks by their last active time
@@ -312,15 +413,30 @@
         }
     };
 
+    // A comparator that sorts tasks by their last active time and freeform state
+    private Comparator<Task> FREEFORM_LAST_ACTIVE_TIME_COMPARATOR = new Comparator<Task>() {
+        @Override
+        public int compare(Task o1, Task o2) {
+            if (o1.isFreeformTask() && !o2.isFreeformTask()) {
+                return 1;
+            } else if (o2.isFreeformTask() && !o1.isFreeformTask()) {
+                return -1;
+            }
+            return Long.compare(o1.key.lastActiveTime, o2.key.lastActiveTime);
+        }
+    };
+
+
     // The task offset to apply to a task id as a group affiliation
     static final int IndividualTaskIdOffset = 1 << 16;
 
+    ArrayList<Task> mRawTaskList = new ArrayList<>();
     FilteredTaskList mStackTaskList = new FilteredTaskList();
     FilteredTaskList mHistoryTaskList = new FilteredTaskList();
     TaskStackCallbacks mCb;
 
     ArrayList<TaskGrouping> mGroups = new ArrayList<>();
-    HashMap<Integer, TaskGrouping> mAffinitiesGroups = new HashMap<>();
+    ArrayMap<Integer, TaskGrouping> mAffinitiesGroups = new ArrayMap<>();
 
     public TaskStack() {
         // Ensure that we only show non-docked tasks
@@ -328,28 +444,28 @@
             @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.taskAffiliationId);
+                    // 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 && !SystemServicesProxy.isDockedStack(t.key.stackId);
+                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.taskAffiliationId);
+                    // 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 && !SystemServicesProxy.isDockedStack(t.key.stackId);
+                return t.isHistorical;
             }
         });
     }
@@ -397,58 +513,121 @@
         taskList.remove(t);
         // Remove it from the group as well, and if it is empty, remove the group
         TaskGrouping group = t.group;
-        group.removeTask(t);
-        if (group.getTaskCount() == 0) {
-            removeGroup(group);
-        }
-        // Update the lock-to-app state
-        t.lockToThisTask = false;
-    }
-
-    /** Removes a task */
-    public void removeTask(Task t) {
-        if (mStackTaskList.contains(t)) {
-            boolean wasFrontMostTask = (getStackFrontMostTask() == t);
-            int removedTaskIndex = indexOfStackTask(t);
-            removeTaskImpl(mStackTaskList, t);
-            Task newFrontMostTask = getStackFrontMostTask();
-            if (newFrontMostTask != null && newFrontMostTask.lockToTaskEnabled) {
-                newFrontMostTask.lockToThisTask = true;
-            }
-            if (mCb != null) {
-                // Notify that a task has been removed
-                mCb.onStackTaskRemoved(this, t, wasFrontMostTask, newFrontMostTask);
-            }
-        } else if (mHistoryTaskList.contains(t)) {
-            removeTaskImpl(mHistoryTaskList, t);
-            if (mCb != null) {
-                // Notify that a task has been removed
-                mCb.onHistoryTaskRemoved(this, t);
+        if (group != null) {
+            group.removeTask(t);
+            if (group.getTaskCount() == 0) {
+                removeGroup(group);
             }
         }
     }
 
     /**
-     * Sets a few tasks in one go, without calling any callbacks.
+     * Removes a task from the stack, with an additional {@param animation} hint to the callbacks on
+     * how they should update themselves.
      */
-    public void setTasks(List<Task> tasks) {
+    public void removeTask(Task t, TaskViewAnimation animation) {
+        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);
+            }
+        }
+        mRawTaskList.remove(t);
+    }
+
+    /**
+     * 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) {
+        // 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<>();
+
+        // Disable notifications if there are no callbacks
+        if (mCb == null) {
+            notifyStackChanges = false;
+        }
+
+        // Remove any tasks that no longer exist
+        int taskCount = mRawTaskList.size();
+        for (int i = 0; i < taskCount; i++) {
+            Task task = mRawTaskList.get(i);
+            if (!newTasksMap.containsKey(task.key)) {
+                if (notifyStackChanges) {
+                    mCb.onStackTaskRemoved(this, task, i == (taskCount - 1), null,
+                            TaskViewAnimation.IMMEDIATE);
+                }
+            }
+            task.setGroup(null);
+        }
+
+        // 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));
+            }
+        }
+
+        // Sort all the tasks to ensure they are ordered correctly
+        Collections.sort(newTasks, FREEFORM_LAST_ACTIVE_TIME_COMPARATOR);
+
+        // Filter out the historical tasks from this new list
         ArrayList<Task> stackTasks = new ArrayList<>();
         ArrayList<Task> historyTasks = new ArrayList<>();
-        for (Task task : tasks) {
+        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(stackTasks);
         mHistoryTaskList.set(historyTasks);
+        mRawTaskList.clear();
+        mRawTaskList.addAll(newTasks);
+        mGroups.clear();
+        mAffinitiesGroups.clear();
     }
 
-    /** Gets the front task */
-    public Task getStackFrontMostTask() {
-        if (mStackTaskList.size() == 0) return null;
-        return mStackTaskList.getTasks().get(mStackTaskList.size() - 1);
+    /**
+     * Gets the front-most task in the stack.
+     */
+    public Task getStackFrontMostTask(boolean includeFreeformTasks) {
+        ArrayList<Task> stackTasks = mStackTaskList.getTasks();
+        if (stackTasks.isEmpty()) {
+            return null;
+        }
+        for (int i = stackTasks.size() - 1; i >= 0; i--) {
+            Task task = stackTasks.get(i);
+            if (!task.isFreeformTask() || includeFreeformTasks) {
+                return task;
+            }
+        }
+        return null;
     }
 
     /** Gets the task keys */
@@ -479,6 +658,22 @@
     }
 
     /**
+     * Returns the set of "freeform" tasks in the stack.
+     */
+    public ArrayList<Task> getFreeformTasks() {
+        ArrayList<Task> freeformTasks = new ArrayList<>();
+        ArrayList<Task> tasks = mStackTaskList.getTasks();
+        int taskCount = tasks.size();
+        for (int i = 0; i < taskCount; i++) {
+            Task task = tasks.get(i);
+            if (task.isFreeformTask()) {
+                freeformTasks.add(task);
+            }
+        }
+        return freeformTasks;
+    }
+
+    /**
      * Computes a set of all the active and historical tasks ordered by their last active time.
      */
     public ArrayList<Task> computeAllTasksList() {
@@ -490,16 +685,32 @@
     }
 
     /**
-     * Returns the number of tasks in the active stack.
+     * Returns the number of stack and freeform tasks.
      */
-    public int getStackTaskCount() {
+    public int getTaskCount() {
         return mStackTaskList.size();
     }
 
     /**
-     * Returns the number of freeform tasks in the active stack.
+     * Returns the number of stack tasks.
      */
-    public int getStackTaskFreeformCount() {
+    public int getStackTaskCount() {
+        ArrayList<Task> tasks = mStackTaskList.getTasks();
+        int stackCount = 0;
+        int taskCount = tasks.size();
+        for (int i = 0; i < taskCount; i++) {
+            Task task = tasks.get(i);
+            if (!task.isFreeformTask()) {
+                stackCount++;
+            }
+        }
+        return stackCount;
+    }
+
+    /**
+     * Returns the number of freeform tasks.
+     */
+    public int getFreeformTaskCount() {
         ArrayList<Task> tasks = mStackTaskList.getTasks();
         int freeformCount = 0;
         int taskCount = tasks.size();
@@ -565,8 +776,8 @@
      * Temporary: This method will simulate affiliation groups by
      */
     public void createAffiliatedGroupings(Context context) {
-        if (RecentsDebugFlags.Static.EnableSimulatedTaskGroups) {
-            HashMap<Task.TaskKey, Task> taskMap = new HashMap<Task.TaskKey, Task>();
+        if (RecentsDebugFlags.Static.EnableMockTaskGroups) {
+            ArrayMap<Task.TaskKey, Task> taskMap = new ArrayMap<>();
             // Sort all tasks by increasing firstActiveTime of the task
             ArrayList<Task> tasks = mStackTaskList.getTasks();
             Collections.sort(tasks, new Comparator<Task>() {
@@ -581,7 +792,7 @@
             String prevPackage = "";
             int prevAffiliation = -1;
             Random r = new Random();
-            int groupCountDown = RecentsDebugFlags.Static.TaskAffiliationsGroupCount;
+            int groupCountDown = RecentsDebugFlags.Static.MockTaskGroupsTaskCount;
             for (int i = 0; i < taskCount; i++) {
                 Task t = tasks.get(i);
                 String packageName = t.key.getComponent().getPackageName();
@@ -596,7 +807,7 @@
                     addGroup(group);
                     prevAffiliation = affiliation;
                     prevPackage = packageName;
-                    groupCountDown = RecentsDebugFlags.Static.TaskAffiliationsGroupCount;
+                    groupCountDown = RecentsDebugFlags.Static.MockTaskGroupsTaskCount;
                 }
                 group.addTask(t);
                 taskMap.put(t.key, t);
@@ -605,7 +816,7 @@
             Collections.sort(mGroups, new Comparator<TaskGrouping>() {
                 @Override
                 public int compare(TaskGrouping taskGrouping, TaskGrouping taskGrouping2) {
-                    return (int) (taskGrouping.latestActiveTimeInGroup -
+                    return Long.compare(taskGrouping.latestActiveTimeInGroup,
                             taskGrouping2.latestActiveTimeInGroup);
                 }
             });
@@ -618,7 +829,7 @@
                 Collections.sort(group.mTaskKeys, new Comparator<Task.TaskKey>() {
                     @Override
                     public int compare(Task.TaskKey taskKey, Task.TaskKey taskKey2) {
-                        return (int) (taskKey.firstActiveTime - taskKey2.firstActiveTime);
+                        return Long.compare(taskKey.firstActiveTime, taskKey2.firstActiveTime);
                     }
                 });
                 ArrayList<Task.TaskKey> groupTasks = group.mTaskKeys;
@@ -631,18 +842,23 @@
             mStackTaskList.set(tasks);
         } else {
             // Create the task groups
-            HashMap<Task.TaskKey, Task> tasksMap = new HashMap<>();
+            ArrayMap<Task.TaskKey, Task> tasksMap = new ArrayMap<>();
             ArrayList<Task> tasks = mStackTaskList.getTasks();
             int taskCount = tasks.size();
             for (int i = 0; i < taskCount; i++) {
                 Task t = tasks.get(i);
                 TaskGrouping group;
-                int affiliation = t.taskAffiliationId > 0 ? t.taskAffiliationId :
-                        IndividualTaskIdOffset + t.key.id;
-                if (mAffinitiesGroups.containsKey(affiliation)) {
-                    group = getGroupWithAffiliation(affiliation);
+                if (RecentsDebugFlags.Static.EnableAffiliatedTaskGroups) {
+                    int affiliation = t.affiliationTaskId > 0 ? t.affiliationTaskId :
+                            IndividualTaskIdOffset + t.key.id;
+                    if (mAffinitiesGroups.containsKey(affiliation)) {
+                        group = getGroupWithAffiliation(affiliation);
+                    } else {
+                        group = new TaskGrouping(affiliation);
+                        addGroup(group);
+                    }
                 } else {
-                    group = new TaskGrouping(affiliation);
+                    group = new TaskGrouping(t.key.id);
                     addGroup(group);
                 }
                 group.addTask(t);
@@ -658,7 +874,7 @@
                 // Ignore the groups that only have one task
                 if (taskCount <= 1) continue;
                 // Calculate the group color distribution
-                int affiliationColor = tasksMap.get(group.mTaskKeys.get(0)).taskAffiliationColor;
+                int affiliationColor = tasksMap.get(group.mTaskKeys.get(0)).affiliationColor;
                 float alphaStep = (1f - minAlpha) / taskCount;
                 float alpha = 1f;
                 for (int j = 0; j < taskCount; j++) {
@@ -675,12 +891,12 @@
      * Computes the components of tasks in this stack that have been removed as a result of a change
      * in the specified package.
      */
-    public HashSet<ComponentName> computeComponentsRemoved(String packageName, int userId) {
+    public ArraySet<ComponentName> computeComponentsRemoved(String packageName, int userId) {
         // Identify all the tasks that should be removed as a result of the package being removed.
         // Using a set to ensure that we callback once per unique component.
         SystemServicesProxy ssp = Recents.getSystemServices();
-        HashSet<ComponentName> existingComponents = new HashSet<>();
-        HashSet<ComponentName> removedComponents = new HashSet<>();
+        ArraySet<ComponentName> existingComponents = new ArraySet<>();
+        ArraySet<ComponentName> removedComponents = new ArraySet<>();
         ArrayList<Task.TaskKey> taskKeys = getTaskKeys();
         for (Task.TaskKey t : taskKeys) {
             // Skip if this doesn't apply to the current user
@@ -714,4 +930,17 @@
         }
         return str;
     }
-}
\ No newline at end of file
+
+    /**
+     * Given a list of tasks, returns a map of each task's key to the task.
+     */
+    private ArrayMap<Task.TaskKey, Task> createTaskKeyMapFromList(List<Task> tasks) {
+        ArrayMap<Task.TaskKey, Task> map = new ArrayMap<>(tasks.size());
+        int taskCount = tasks.size();
+        for (int i = 0; i < taskCount; i++) {
+            Task task = tasks.get(i);
+            map.put(task.key, task);
+        }
+        return map;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
new file mode 100644
index 0000000..6593169
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -0,0 +1,451 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.Activity;
+import android.app.ActivityOptions;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewTreeObserver.OnPreDrawListener;
+import android.view.WindowManager;
+import com.android.systemui.R;
+import com.android.systemui.recents.*;
+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.EnterRecentsWindowAnimationCompletedEvent;
+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;
+import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
+import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
+import com.android.systemui.recents.events.ui.UserInteractionEvent;
+import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.RecentsPackageMonitor;
+import com.android.systemui.recents.model.RecentsTaskLoadPlan;
+import com.android.systemui.recents.model.RecentsTaskLoader;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.tv.views.RecentsTvView;
+import com.android.systemui.recents.tv.views.TaskStackHorizontalViewAdapter;
+import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.tv.pip.PipManager;
+
+import java.util.ArrayList;
+/**
+ * The main TV recents activity started by the RecentsImpl.
+ */
+public class RecentsTvActivity extends Activity implements OnPreDrawListener {
+    private final static String TAG = "RecentsTvActivity";
+    private final static boolean DEBUG = false;
+
+    public final static int EVENT_BUS_PRIORITY = Recents.EVENT_BUS_PRIORITY + 1;
+
+    private boolean mFinishedOnStartup;
+    private RecentsPackageMonitor mPackageMonitor;
+    private long mLastTabKeyEventTime;
+    private boolean mIgnoreAltTabRelease;
+
+    private RecentsTvView mRecentsView;
+    private TaskStackHorizontalViewAdapter mTaskStackViewAdapter;
+    private FinishRecentsRunnable mFinishLaunchHomeRunnable;
+
+
+    /**
+     * A common Runnable to finish Recents by launching Home with an animation depending on the
+     * 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 {
+        Intent mLaunchIntent;
+
+        /**
+         * Creates a finish runnable that starts the specified intent.
+         */
+        public FinishRecentsRunnable(Intent launchIntent) {
+            mLaunchIntent = launchIntent;
+        }
+
+        @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);
+                startActivityAsUser(mLaunchIntent, opts.toBundle(), UserHandle.CURRENT);
+            } catch (Exception e) {
+                Log.e(TAG, getString(R.string.recents_launch_error_message, "Home"), e);
+            }
+        }
+    }
+
+    private void updateRecentsTasks() {
+        RecentsTaskLoader loader = Recents.getTaskLoader();
+        RecentsTaskLoadPlan plan = RecentsImpl.consumeInstanceLoadPlan();
+        if (plan == null) {
+            plan = loader.createLoadPlan(this);
+        }
+
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
+        if (!plan.hasTasks()) {
+            loader.preloadTasks(plan, -1, launchState.launchedFromHome);
+        }
+        TaskStack stack = plan.getTaskStack();
+        RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
+        loadOpts.runningTaskId = launchState.launchedToTaskId;
+        loadOpts.numVisibleTasks = stack.getStackTaskCount();
+        loadOpts.numVisibleTaskThumbnails = stack.getStackTaskCount();
+        loader.loadTasks(this, plan, loadOpts);
+
+
+        mRecentsView.setTaskStack(stack);
+        if (mTaskStackViewAdapter == null) {
+            mTaskStackViewAdapter = new TaskStackHorizontalViewAdapter(stack.getStackTasks());
+            mRecentsView.setTaskStackViewAdapter(mTaskStackViewAdapter);
+        } else {
+            mTaskStackViewAdapter.setNewStackTasks(stack.getStackTasks());
+        }
+
+        if (launchState.launchedToTaskId != -1) {
+            ArrayList<Task> tasks = stack.getStackTasks();
+            int taskCount = tasks.size();
+            for (int i = 0; i < taskCount; i++) {
+                Task t = tasks.get(i);
+                if (t.key.id == launchState.launchedToTaskId) {
+                    t.isLaunchTarget = true;
+                    break;
+                }
+            }
+        }
+    }
+
+    boolean dismissRecentsToLaunchTargetTaskOrHome() {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+            // If we have a focused Task, launch that Task now
+            if (mRecentsView.launchPreviousTask()) return true;
+            // If none of the other cases apply, then just go Home
+            dismissRecentsToHome(true /* animateTaskViews */);
+        }
+        return false;
+    }
+
+    boolean dismissRecentsToFocusedTaskOrHome() {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+            // If we have a focused Task, launch that Task now
+            if (mRecentsView.launchFocusedTask()) return true;
+            // If none of the other cases apply, then just go Home
+            dismissRecentsToHome(true /* animateTaskViews */);
+            return true;
+        }
+        return false;
+    }
+
+    void dismissRecentsToHome(boolean animateTaskViews) {
+        DismissRecentsToHomeAnimationStarted dismissEvent =
+                new DismissRecentsToHomeAnimationStarted(animateTaskViews);
+        dismissEvent.addPostAnimationCallback(mFinishLaunchHomeRunnable);
+        dismissEvent.addPostAnimationCallback(new Runnable() {
+            @Override
+            public void run() {
+                Recents.getSystemServices().sendCloseSystemWindows(
+                        BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
+            }
+        });
+        EventBus.getDefault().send(dismissEvent);
+    }
+
+    boolean dismissRecentsToHomeIfVisible(boolean animated) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+            // Return to Home
+            dismissRecentsToHome(animated);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mFinishedOnStartup = false;
+
+        // In the case that the activity starts up before the Recents component has initialized
+        // (usually when debugging/pushing the SysUI apk), just finish this activity.
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (ssp == null) {
+            mFinishedOnStartup = true;
+            finish();
+            return;
+        }
+
+        // Register this activity with the event bus
+        EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
+
+        mPackageMonitor = new RecentsPackageMonitor();
+        mPackageMonitor.register(this);
+
+        // Set the Recents layout
+        setContentView(R.layout.recents_on_tv);
+
+        mRecentsView = (RecentsTvView) findViewById(R.id.recents_view);
+        mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
+                View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
+                View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+
+        getWindow().getAttributes().privateFlags |=
+                WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
+
+        // 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);
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        setIntent(intent);
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+
+        // Update the recent tasks
+        updateRecentsTasks();
+
+        // 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
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
+        boolean wasLaunchedByAm = !launchState.launchedFromHome &&
+                !launchState.launchedFromAppWithThumbnail;
+        if (launchState.launchedHasConfigurationChanged || wasLaunchedByAm) {
+            EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
+        }
+
+        // Notify that recents is now visible
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, true));
+    }
+
+    @Override
+    public void onEnterAnimationComplete() {
+        super.onEnterAnimationComplete();
+        EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
+    }
+
+    @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));
+
+        // 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
+        // wait on the system to send a signal that was never queued.
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
+        launchState.launchedFromHome = false;
+        launchState.launchedFromSearchHome = false;
+        launchState.launchedFromAppWithThumbnail = false;
+        launchState.launchedToTaskId = -1;
+        launchState.launchedWithAltTab = false;
+        launchState.launchedHasConfigurationChanged = false;
+        launchState.launchedViaDragGesture = false;
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+
+        // In the case that the activity finished on startup, just skip the unregistration below
+        if (mFinishedOnStartup) {
+            return;
+        }
+
+        // Unregister any broadcast receivers for the task loader
+        mPackageMonitor.unregister();
+
+        EventBus.getDefault().unregister(this);
+    }
+
+    @Override
+    public void onTrimMemory(int level) {
+        RecentsTaskLoader loader = Recents.getTaskLoader();
+        if (loader != null) {
+            loader.onTrimMemory(level);
+        }
+    }
+
+    @Override
+    public void onMultiWindowModeChanged(boolean multiWindowMode) {
+        super.onMultiWindowModeChanged(multiWindowMode);
+        if (!multiWindowMode) {
+            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_DPAD_UP: {
+                SystemServicesProxy ssp = Recents.getSystemServices();
+                PipManager.getInstance().showPipMenu();
+                ssp.focusPinnedStack();
+                return true;
+            }
+            case KeyEvent.KEYCODE_DPAD_DOWN: {
+                SystemServicesProxy ssp = Recents.getSystemServices();
+                PipManager.getInstance().showPipOverlay(false);
+                ssp.focusHomeStack();
+                return true;
+            }
+            case KeyEvent.KEYCODE_DEL:
+            case KeyEvent.KEYCODE_FORWARD_DEL: {
+                EventBus.getDefault().send(new DismissFocusedTaskViewEvent());
+                return true;
+            }
+            default:
+                break;
+        }
+        return super.onKeyDown(keyCode, event);
+    }
+
+    @Override
+    public void onUserInteraction() {
+        EventBus.getDefault().send(new UserInteractionEvent());
+    }
+
+    @Override
+    public void onBackPressed() {
+        // Back behaves like the recents button so just trigger a toggle event
+        EventBus.getDefault().send(new ToggleRecentsEvent());
+    }
+
+    /**** EventBus events ****/
+
+    public final void onBusEvent(ToggleRecentsEvent event) {
+        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+        if (launchState.launchedFromHome) {
+            dismissRecentsToHome(true /* animateTaskViews */);
+        } else {
+            dismissRecentsToLaunchTargetTaskOrHome();
+        }
+    }
+
+    public final void onBusEvent(HideRecentsEvent event) {
+        if (event.triggeredFromAltTab) {
+            // If we are hiding from releasing Alt-Tab, dismiss Recents to the focused app
+            if (!mIgnoreAltTabRelease) {
+                dismissRecentsToFocusedTaskOrHome();
+            }
+        } else if (event.triggeredFromHomeKey) {
+                dismissRecentsToHome(true /* animateTaskViews */);
+        } else {
+            // Do nothing
+        }
+    }
+
+    public final void onBusEvent(EnterRecentsWindowLastAnimationFrameEvent event) {
+        EventBus.getDefault().send(new UpdateFreeformTaskViewVisibilityEvent(true));
+        mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
+        mRecentsView.invalidate();
+    }
+
+    public final void onBusEvent(CancelEnterRecentsWindowAnimationEvent event) {
+        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+        int launchToTaskId = launchState.launchedToTaskId;
+        if (launchToTaskId != -1 &&
+                (event.launchTask == null || launchToTaskId != event.launchTask.key.id)) {
+            SystemServicesProxy ssp = Recents.getSystemServices();
+            ssp.cancelWindowTransition(launchState.launchedToTaskId);
+            ssp.cancelThumbnailTransition(getTaskId());
+        }
+    }
+
+    public final void onBusEvent(DeleteTaskDataEvent event) {
+        // Remove any stored data from the loader
+        RecentsTaskLoader loader = Recents.getTaskLoader();
+        loader.deleteTaskData(event.task, false);
+
+        // Remove the task from activity manager
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        ssp.removeTask(event.task.key.id);
+    }
+
+    public final void onBusEvent(AllTaskViewsDismissedEvent event) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (ssp.hasDockedTask()) {
+            mRecentsView.showEmptyView();
+        } else {
+            // Just go straight home (no animation necessary because there are no more task views)
+            dismissRecentsToHome(false /* animateTaskViews */);
+        }
+    }
+
+    public final void onBusEvent(LaunchTaskFailedEvent event) {
+        // Return to Home
+        dismissRecentsToHome(true /* animateTaskViews */);
+    }
+
+    @Override
+    public boolean onPreDraw() {
+        mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
+        // We post to make sure that this information is delivered after this traversals is
+        // finished.
+        mRecentsView.post(new Runnable() {
+            @Override
+            public void run() {
+                Recents.getSystemServices().endProlongedAnimations();
+            }
+        });
+        return true;
+    }
+}
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
new file mode 100644
index 0000000..8212c73
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.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.systemui.recents.tv.animations;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.content.res.Resources;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.Interpolator;
+import com.android.systemui.R;
+
+public class ViewFocusAnimator implements View.OnFocusChangeListener {
+    private final float mUnselectedScale;
+    private final float mSelectedScaleDelta;
+    private final float mUnselectedZ;
+    private final float mSelectedZDelta;
+    private final int mAnimDuration;
+    private final Interpolator mFocusInterpolator;
+
+    protected View mTargetView;
+    private float mFocusProgress;
+
+    ObjectAnimator mFocusAnimation;
+
+    public ViewFocusAnimator(View view) {
+        mTargetView = view;
+        final Resources res = view.getResources();
+
+        mTargetView.setOnFocusChangeListener(this);
+
+        TypedValue out = new TypedValue();
+        res.getValue(R.raw.unselected_scale, out, true);
+        mUnselectedScale = out.getFloat();
+        mSelectedScaleDelta = res.getFraction(R.fraction.lb_focus_zoom_factor_medium, 1, 1) -
+                mUnselectedScale;
+
+        mUnselectedZ = res.getDimensionPixelOffset(R.dimen.recents_tv_unselected_item_z);
+        mSelectedZDelta = res.getDimensionPixelOffset(R.dimen.recents_tv_selected_item_z_delta);
+
+        mAnimDuration = res.getInteger(R.integer.item_scale_anim_duration);
+
+        mFocusInterpolator = new AccelerateDecelerateInterpolator();
+
+        mFocusAnimation = ObjectAnimator.ofFloat(this, "focusProgress", 0.0f);
+        mFocusAnimation.setDuration(mAnimDuration);
+        mFocusAnimation.setInterpolator(mFocusInterpolator);
+
+        setFocusProgress(0.0f);
+
+        mFocusAnimation.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mTargetView.setHasTransientState(true);
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mTargetView.setHasTransientState(false);
+            }
+        });
+    }
+
+    public void setFocusProgress(float level) {
+        mFocusProgress = level;
+
+        float scale = mUnselectedScale + (level * mSelectedScaleDelta);
+        float z = mUnselectedZ + (level * mSelectedZDelta);
+
+        mTargetView.setScaleX(scale);
+        mTargetView.setScaleY(scale);
+        mTargetView.setZ(z);
+    }
+
+    public float getFocusProgress() {
+        return mFocusProgress;
+    }
+
+    public void animateFocus(boolean focused) {
+        if (mFocusAnimation.isStarted()) {
+            mFocusAnimation.cancel();
+        }
+
+        float target = focused ? 1.0f : 0.0f;
+
+        if (getFocusProgress() != target) {
+            mFocusAnimation.setFloatValues(getFocusProgress(), target);
+            mFocusAnimation.start();
+        }
+    }
+
+    public void setFocusImmediate(boolean focused) {
+        if (mFocusAnimation.isStarted()) {
+            mFocusAnimation.cancel();
+        }
+
+        float target = focused ? 1.0f : 0.0f;
+
+        setFocusProgress(target);
+    }
+
+    @Override
+    public void onFocusChange(View v, boolean hasFocus) {
+        if (v != mTargetView) {
+            return;
+        }
+        changeSize(hasFocus);
+    }
+
+    protected void changeSize(boolean hasFocus) {
+        ViewGroup.LayoutParams lp = mTargetView.getLayoutParams();
+        int width = lp.width;
+        int height = lp.height;
+
+        if (width < 0 && height < 0) {
+            mTargetView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+            height = mTargetView.getMeasuredHeight();
+        }
+
+        if (mTargetView.isAttachedToWindow() && mTargetView.hasWindowFocus() &&
+                mTargetView.getVisibility() == View.VISIBLE) {
+            animateFocus(hasFocus);
+        } else {
+            setFocusImmediate(hasFocus);
+        }
+    }
+}
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
new file mode 100644
index 0000000..c4d5b2b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.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 com.android.systemui.recents.tv.views;
+
+import android.content.Context;
+import android.graphics.Rect;
+
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowInsets;
+import android.widget.FrameLayout;
+import com.android.internal.logging.MetricsLogger;
+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.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.component.RecentsVisibilityChangedEvent;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+
+/**
+ * Top level layout of recents for TV. This will show the TaskStacks using a HorizontalGridView.
+ */
+public class RecentsTvView extends FrameLayout {
+
+    private static final String TAG = "RecentsTvView";
+    private static final boolean DEBUG = false;
+
+    private TaskStack mStack;
+    private TaskStackHorizontalGridView mTaskStackHorizontalView;
+    private View mEmptyView;
+    private boolean mAwaitingFirstLayout = true;
+    private Rect mSystemInsets = new Rect();
+
+
+    public RecentsTvView(Context context) {
+        this(context, null);
+    }
+
+    public RecentsTvView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public RecentsTvView(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public RecentsTvView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+
+        setWillNotDraw(false);
+
+        LayoutInflater inflater = LayoutInflater.from(context);
+        mEmptyView = inflater.inflate(R.layout.recents_empty, this, false);
+        addView(mEmptyView);
+    }
+
+    public void setTaskStack(TaskStack stack) {
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
+        mStack = stack;
+
+        if (mTaskStackHorizontalView != null) {
+            mTaskStackHorizontalView.reset();
+            mTaskStackHorizontalView.setStack(stack);
+        } else {
+            mTaskStackHorizontalView = (TaskStackHorizontalGridView) findViewById(R.id.task_list);
+            mTaskStackHorizontalView.setStack(stack);
+        }
+
+
+        if (stack.getStackTaskCount() > 0) {
+            hideEmptyView();
+        } else {
+            showEmptyView();
+        }
+
+        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);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /** Launches the task that recents was launched from if possible */
+    public boolean launchPreviousTask() {
+        if (mTaskStackHorizontalView != null) {
+            TaskStack stack = mTaskStackHorizontalView.getStack();
+            Task task = stack.getLaunchTarget();
+            if (task != null) {
+                SystemServicesProxy ssp = Recents.getSystemServices();
+                ssp.startActivityFromRecents(getContext(), task.key.id, task.title, null);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /** Launches a given task. */
+    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;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Hides the task stack and shows the empty view.
+     */
+    public void showEmptyView() {
+        mEmptyView.setVisibility(View.VISIBLE);
+        mEmptyView.bringToFront();
+    }
+
+    /**
+     * Shows the task stack and hides the empty view.
+     */
+    public void hideEmptyView() {
+        mEmptyView.setVisibility(View.INVISIBLE);
+    }
+
+    /**
+     * Returns the last known system insets.
+     */
+    public Rect getSystemInsets() {
+        return mSystemInsets;
+    }
+
+    @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);
+    }
+
+    /**
+     * 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());
+        requestLayout();
+        return insets;
+    }
+
+    /**** EventBus Events ****/
+
+    public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
+        // If we are going home, cancel the previous task's window transition
+        EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null));
+    }
+
+    public final void onBusEvent(TaskStackUpdatedEvent event) {
+        mStack.setTasks(event.stack.computeAllTasksList(), true /* notifyStackChanges */);
+        mStack.createAffiliatedGroupings(getContext());
+    }
+
+
+    public final void onBusEvent(RecentsVisibilityChangedEvent event) {
+        if (!event.visible) {
+            // Reset the view state
+            mAwaitingFirstLayout = true;
+        }
+    }
+
+
+    public void setTaskStackViewAdapter(TaskStackHorizontalViewAdapter taskStackViewAdapter) {
+        if(mTaskStackHorizontalView != null) {
+            mTaskStackHorizontalView.setAdapter(taskStackViewAdapter);
+        }
+    }
+}
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
new file mode 100644
index 0000000..b36a228
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.content.Context;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import com.android.systemui.R;
+import com.android.systemui.recents.tv.animations.ViewFocusAnimator;
+import com.android.systemui.recents.model.Task;
+
+public class TaskCardView extends RelativeLayout {
+
+    private ImageView mThumbnailView;
+    private TextView mTitleTextView;
+    private TextView mContentTextView;
+    private ImageView mBadgeView;
+    private Task mTask;
+
+    private ViewFocusAnimator mViewFocusAnimator;
+
+    public TaskCardView(Context context) {
+        this(context, null);
+    }
+
+    public TaskCardView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public TaskCardView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mViewFocusAnimator = new ViewFocusAnimator(this);
+    }
+
+    @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);
+    }
+
+    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;
+    }
+}
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
new file mode 100644
index 0000000..b505d65
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.support.v17.leanback.widget.HorizontalGridView;
+import android.util.AttributeSet;
+import android.content.Context;
+import android.view.View;
+import com.android.systemui.R;
+import com.android.systemui.recents.RecentsActivity;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.model.TaskStack.TaskStackCallbacks;
+import com.android.systemui.recents.views.TaskViewAnimation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Horizontal Grid View Implementation to show the Task Stack for TV.
+ */
+public class TaskStackHorizontalGridView extends HorizontalGridView implements TaskStackCallbacks{
+
+    private TaskStack mStack;
+    private ArrayList<TaskCardView> mTaskViews = new ArrayList<>();
+    private Task mFocusedTask;
+
+
+    public TaskStackHorizontalGridView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
+        setItemMargin((int) getResources().getDimension(R.dimen.recents_tv_gird_card_spacing));
+        setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+        super.onAttachedToWindow();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        EventBus.getDefault().unregister(this);
+    }
+    /**
+     * Resets this view for reuse.
+     */
+    public void reset() {
+        // Reset the focused task
+        resetFocusedTask(getFocusedTask());
+        requestLayout();
+    }
+
+    /**
+     * @param task - Task to reset
+     */
+    private void resetFocusedTask(Task task) {
+        if (task != null) {
+            TaskCardView tv = getChildViewForTask(task);
+            if (tv != null) {
+                tv.requestFocus();
+            }
+        }
+        mFocusedTask = null;
+    }
+
+    /**
+     * Sets the task stack.
+     * @param stack
+     */
+    public void setStack(TaskStack stack) {
+        //Set new stack
+        mStack = stack;
+        if (mStack != null) {
+            mStack.setCallbacks(this);
+        }
+        //Layout with new stack
+        requestLayout();
+    }
+
+    /**
+     * @return Returns the task stack.
+     */
+    public TaskStack getStack() {
+        return mStack;
+    }
+
+    /**
+     * @return - The focused task.
+     */
+    public Task getFocusedTask() {
+        return mFocusedTask;
+    }
+
+    /**
+     * @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);
+            if (tv.getTask() == task) {
+                return tv;
+            }
+        }
+        return null;
+    }
+
+    public List<TaskCardView> getTaskViews() {
+        return mTaskViews;
+    }
+
+    @Override
+    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, TaskViewAnimation animation) {
+        getAdapter().notifyItemRemoved(stack.getStackTasks().indexOf(removedTask));
+        if (mFocusedTask == removedTask) {
+            resetFocusedTask(removedTask);
+        }
+        // If there are no remaining tasks, then just close recents
+        if (mStack.getStackTaskCount() == 0) {
+            boolean shouldFinishActivity = (mStack.getStackTaskCount() == 0);
+            if (shouldFinishActivity) {
+                EventBus.getDefault().send(new AllTaskViewsDismissedEvent());
+            }
+        }
+    }
+
+    @Override
+    public void onHistoryTaskRemoved(TaskStack stack, Task removedTask, TaskViewAnimation animation) {
+        //No history task on tv
+    }
+}
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
new file mode 100644
index 0000000..0ee7b49
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.app.Activity;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import com.android.systemui.R;
+import com.android.systemui.recents.model.Task;
+import android.support.v7.widget.RecyclerView;
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TaskStackHorizontalViewAdapter extends
+        RecyclerView.Adapter<TaskStackHorizontalViewAdapter.ViewHolder> {
+
+    private static final String TAG = "TaskStackHorizontalViewAdapter";
+    private List<Task> mTaskList;
+
+    static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
+        private TaskCardView mTaskCardView;
+        private Task mTask;
+        public ViewHolder(View v) {
+            super(v);
+            if(v instanceof TaskCardView) {
+                mTaskCardView = (TaskCardView) v;
+            }
+        }
+
+        public void init(Task task) {
+            mTaskCardView.init(task);
+            mTask = task;
+            mTaskCardView.setOnClickListener(this);
+        }
+
+        @Override
+        public void onClick(View v) {
+            try {
+                ActivityManagerNative.getDefault().startActivityFromRecents(mTask.key.id, null);
+                ((Activity)(v.getContext())).finish();
+            } catch (Exception e) {
+                Log.e(TAG, v.getContext()
+                        .getString(R.string.recents_launch_error_message, mTask.title), e);
+            }
+
+        }
+    }
+
+    public TaskStackHorizontalViewAdapter(List tasks) {
+        mTaskList = new ArrayList<>(tasks);
+    }
+
+    public void setNewStackTasks(List tasks) {
+        mTaskList.clear();
+        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);
+        ViewHolder viewHolder = new ViewHolder(view);
+        return viewHolder;
+    }
+
+    @Override
+    public void onBindViewHolder(ViewHolder holder, int position) {
+        holder.init(mTaskList.get(position));
+    }
+
+    @Override
+    public int getItemCount() {
+        return mTaskList.size();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
index c0b8a9d..5842095 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
@@ -18,8 +18,6 @@
 
 import android.graphics.Outline;
 import android.graphics.Rect;
-import android.util.IntProperty;
-import android.util.Property;
 import android.view.View;
 import android.view.ViewOutlineProvider;
 
@@ -29,23 +27,11 @@
     View mSourceView;
     Rect mClipRect = new Rect();
     Rect mClipBounds = new Rect();
+    Rect mLastClipBounds = new Rect();
     int mCornerRadius;
     float mAlpha = 1f;
     final float mMinAlpha = 0.25f;
 
-    public static final Property<AnimateableViewBounds, Integer> CLIP_BOTTOM =
-            new IntProperty<AnimateableViewBounds>("clipBottom") {
-                @Override
-                public void setValue(AnimateableViewBounds object, int clip) {
-                    object.setClipBottom(clip, false /* force */);
-                }
-
-                @Override
-                public Integer get(AnimateableViewBounds object) {
-                    return object.getClipBottom();
-                }
-            };
-
     public AnimateableViewBounds(View source, int cornerRadius) {
         mSourceView = source;
         mCornerRadius = cornerRadius;
@@ -62,26 +48,42 @@
     @Override
     public void getOutline(View view, Outline outline) {
         outline.setAlpha(mMinAlpha + mAlpha / (1f - mMinAlpha));
-        outline.setRoundRect(mClipRect.left, mClipRect.top,
-                mSourceView.getWidth() - mClipRect.right,
-                mSourceView.getHeight() - mClipRect.bottom,
-                mCornerRadius);
+        if (mCornerRadius > 0) {
+            outline.setRoundRect(mClipRect.left, mClipRect.top,
+                    mSourceView.getWidth() - mClipRect.right,
+                    mSourceView.getHeight() - mClipRect.bottom,
+                    mCornerRadius);
+        } else {
+            outline.setRect(mClipRect.left, mClipRect.top,
+                    mSourceView.getWidth() - mClipRect.right,
+                    mSourceView.getHeight() - mClipRect.bottom);
+        }
     }
 
     /** Sets the view outline alpha. */
     void setAlpha(float alpha) {
         if (Float.compare(alpha, mAlpha) != 0) {
             mAlpha = alpha;
+            // TODO, If both clip and alpha change in the same frame, only invalidate once
             mSourceView.invalidateOutline();
         }
     }
 
+    /** Sets the top clip. */
+    public void setClipTop(int top) {
+        mClipRect.top = top;
+        updateClipBounds();
+    }
+
+    /** Returns the top clip. */
+    public int getClipTop() {
+        return mClipRect.top;
+    }
+
     /** Sets the bottom clip. */
-    public void setClipBottom(int bottom, boolean force) {
-        if (bottom != mClipRect.bottom || force) {
-            mClipRect.bottom = bottom;
-            updateClipBounds();
-        }
+    public void setClipBottom(int bottom) {
+        mClipRect.bottom = bottom;
+        updateClipBounds();
     }
 
     /** Returns the bottom clip. */
@@ -93,7 +95,11 @@
         mClipBounds.set(Math.max(0, mClipRect.left), Math.max(0, mClipRect.top),
                 mSourceView.getWidth() - Math.max(0, mClipRect.right),
                 mSourceView.getHeight() - Math.max(0, mClipRect.bottom));
-        mSourceView.setClipBounds(mClipBounds);
-        mSourceView.invalidateOutline();
+        if (!mLastClipBounds.equals(mClipBounds)) {
+            mSourceView.setClipBounds(mClipBounds);
+            // TODO, If both clip and alpha change in the same frame, only invalidate once
+            mSourceView.invalidateOutline();
+            mLastClipBounds.set(mClipBounds);
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/DropTarget.java b/packages/SystemUI/src/com/android/systemui/recents/views/DropTarget.java
index 8ae00a7..3ad368c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/DropTarget.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/DropTarget.java
@@ -25,5 +25,5 @@
      * Returns whether this target can accept this drop.  The x,y are relative to the top level
      * RecentsView, and the width/height are of the RecentsView.
      */
-    boolean acceptsDrop(int x, int y, int width, int height);
+    boolean acceptsDrop(int x, int y, int width, int height, boolean isCurrentTarget);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeFrameLayout.java b/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeFrameLayout.java
new file mode 100644
index 0000000..9f2b00a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeFrameLayout.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.views;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+/**
+ * This is an optimized FrameLayout whose layout is completely directed by its parent, and as a
+ * result, does not propagate <code>requestLayout()</code> up the view hierarchy. Instead, it will
+ * relayout its children with the last known layout bounds when a layout is requested from a child
+ * view.
+ */
+public class FixedSizeFrameLayout extends FrameLayout {
+
+    private final Rect mLayoutBounds = new Rect();
+
+    public FixedSizeFrameLayout(Context context) {
+        super(context);
+    }
+
+    public FixedSizeFrameLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public FixedSizeFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public FixedSizeFrameLayout(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    protected final void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        measureContents(MeasureSpec.getSize(widthMeasureSpec),
+                MeasureSpec.getSize(heightMeasureSpec));
+    }
+
+    @Override
+    protected final void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        mLayoutBounds.set(left, top, right, bottom);
+        layoutContents(mLayoutBounds, changed);
+    }
+
+    @Override
+    public final void requestLayout() {
+        // The base ViewGroup constructor attempts to call requestLayout() before this class's
+        // members are initialized so we should just propagate in that case
+        if (mLayoutBounds == null || mLayoutBounds.isEmpty()) {
+            super.requestLayout();
+        } else {
+            // If we are already laid out, then just reuse the same bounds to layout the children
+            // (but not itself)
+            // TODO: Investigate whether we should coalesce these to the next frame if needed
+            measureContents(getMeasuredWidth(), getMeasuredHeight());
+            layoutContents(mLayoutBounds, false);
+        }
+    }
+
+    /**
+     * Measures the contents of this fixed layout.
+     */
+    protected void measureContents(int width, int height) {
+        super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
+                MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
+    }
+
+    /**
+     * Lays out the contents of this fixed layout.
+     */
+    protected void layoutContents(Rect bounds, boolean changed) {
+        super.onLayout(changed, bounds.left, bounds.top, bounds.right, bounds.bottom);
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeImageView.java b/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeImageView.java
index 3f5d0a8..f5ab01f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeImageView.java
@@ -23,13 +23,13 @@
 import android.widget.ImageView;
 
 /**
- * This is an optimized ImageView that does not trigger a requestLayout() or invalidate() when
- * setting the image to Null.
+ * This is an optimized ImageView that does not trigger a <code>requestLayout()</code> or
+ * <code>invalidate()</code> when setting the image to <code>null</code>.
  */
 public class FixedSizeImageView extends ImageView {
 
-    boolean mAllowRelayout = true;
-    boolean mAllowInvalidate = true;
+    private boolean mAllowRelayout = true;
+    private boolean mAllowInvalidate = true;
 
     public FixedSizeImageView(Context context) {
         this(context, null);
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 2351aa3..491c4c2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
@@ -16,13 +16,13 @@
 
 package com.android.systemui.recents.views;
 
-import android.graphics.Rect;
+import android.content.Context;
 import android.graphics.RectF;
-import android.util.Log;
+import android.util.ArrayMap;
+import com.android.systemui.R;
 import com.android.systemui.recents.model.Task;
 
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
 
 /**
@@ -30,11 +30,16 @@
  */
 public class FreeformWorkspaceLayoutAlgorithm {
 
-    private static final String TAG = "FreeformWorkspaceLayoutAlgorithm";
-    private static final boolean DEBUG = false;
-
     // Optimization, allows for quick lookup of task -> rect
-    private HashMap<Task.TaskKey, RectF> mTaskRectMap = new HashMap<>();
+    private ArrayMap<Task.TaskKey, RectF> mTaskRectMap = new ArrayMap<>();
+
+    private int mTaskPadding;
+
+    public FreeformWorkspaceLayoutAlgorithm(Context context) {
+        // This is applied to the edges of each task
+        mTaskPadding = context.getResources().getDimensionPixelSize(
+                R.dimen.recents_freeform_workspace_task_padding) / 2;
+    }
 
     /**
      * Updates the layout for each of the freeform workspace tasks.  This is called after the stack
@@ -117,6 +122,7 @@
                     rowLeft = defaultRowLeft;
                 }
                 RectF rect = new RectF(rowLeft, rowTop, rowLeft + width, rowTop + rowHeight);
+                rect.inset(mTaskPadding, mTaskPadding);
                 rowLeft += width;
                 mTaskRectMap.put(task.key, rect);
             }
@@ -140,35 +146,15 @@
     public TaskViewTransform getTransform(Task task, TaskViewTransform transformOut,
             TaskStackLayoutAlgorithm stackLayout) {
         if (mTaskRectMap.containsKey(task.key)) {
-            final Rect taskRect = stackLayout.mTaskRect;
             final RectF ffRect = mTaskRectMap.get(task.key);
 
             transformOut.scale = 1f;
             transformOut.alpha = 1f;
             transformOut.translationZ = stackLayout.mMaxTranslationZ;
-            if (task.thumbnail != null) {
-                if (task.bounds == null) {
-                    // This is a stack task that has no freeform thumbnail, so keep the same bitmap
-                    // scale as it had in the stack
-                    transformOut.thumbnailScale = (float) taskRect.width() /
-                            task.thumbnail.getWidth();
-                } else {
-                    // This is a freeform rect so fit the bitmap to the task bounds
-                    transformOut.thumbnailScale = Math.min(
-                            ffRect.width() / task.thumbnail.getWidth(),
-                            ffRect.height() / task.thumbnail.getHeight());
-                }
-            } else {
-                transformOut.thumbnailScale = 1f;
-            }
             transformOut.rect.set(ffRect);
             transformOut.rect.offset(stackLayout.mFreeformRect.left, stackLayout.mFreeformRect.top);
             transformOut.visible = true;
             transformOut.p = 1f;
-
-            if (DEBUG) {
-                Log.d(TAG, "getTransform: " + task.key + ", " + transformOut);
-            }
             return transformOut;
         }
         return null;
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 96b1a41..b363ed5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -32,15 +32,15 @@
 import android.view.IAppTransitionAnimationSpecsFuture;
 import android.view.WindowManagerGlobal;
 import com.android.internal.annotations.GuardedBy;
-import com.android.systemui.recents.ExitRecentsWindowFirstAnimationFrameEvent;
 import com.android.systemui.recents.Recents;
 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.ExitRecentsWindowFirstAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent;
+import com.android.systemui.recents.events.activity.LaunchTaskStartedEvent;
 import com.android.systemui.recents.events.activity.LaunchTaskSucceededEvent;
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
-import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
@@ -90,7 +90,7 @@
      */
     public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task,
             final TaskStackView stackView, final TaskView taskView,
-            final boolean lockToTask, final Rect bounds, int destinationStack) {
+            final boolean screenPinningRequested, final Rect bounds, int destinationStack) {
         final ActivityOptions opts = ActivityOptions.makeBasic();
         if (bounds != null) {
             opts.setLaunchBounds(bounds.isEmpty() ? null : bounds);
@@ -109,7 +109,7 @@
                     EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
                     EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
 
-                    if (lockToTask) {
+                    if (screenPinningRequested) {
                         // Request screen pinning after the animation runs
                         mHandler.postDelayed(mStartScreenPinningRunnable, 350);
                     }
@@ -131,16 +131,19 @@
             // task views, and we can launch immediately
             startTaskActivity(stack, task, taskView, opts, transitionFuture, animStartedListener);
         } else {
+            LaunchTaskStartedEvent launchStartedEvent = new LaunchTaskStartedEvent(taskView,
+                    screenPinningRequested);
             if (task.group != null && !task.group.isFrontMostTask(task)) {
-                stackView.startLaunchTaskAnimation(taskView, new Runnable() {
+                launchStartedEvent.addPostAnimationCallback(new Runnable() {
                     @Override
                     public void run() {
                         startTaskActivity(stack, task, taskView, opts, transitionFuture,
                                 animStartedListener);
                     }
-                }, lockToTask);
+                });
+                EventBus.getDefault().send(launchStartedEvent);
             } else {
-                stackView.startLaunchTaskAnimation(taskView, null, lockToTask);
+                EventBus.getDefault().send(launchStartedEvent);
                 startTaskActivity(stack, task, taskView, opts, transitionFuture,
                         animStartedListener);
             }
@@ -157,17 +160,17 @@
             ActivityOptions opts, IAppTransitionAnimationSpecsFuture transitionFuture,
             final ActivityOptions.OnAnimationStartedListener animStartedListener) {
         SystemServicesProxy ssp = Recents.getSystemServices();
-        if (ssp.startActivityFromRecents(mContext, task.key.id, task.activityLabel, opts)) {
+        if (ssp.startActivityFromRecents(mContext, task.key.id, 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.getStackTaskCount() - taskIndex - 1;
+                taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
             }
             EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront));
         } else {
             // Dismiss the task if we fail to launch it
-            EventBus.getDefault().send(new DismissTaskViewEvent(task, taskView));
+            taskView.dismissTask();
 
             // Keep track of failed launches
             EventBus.getDefault().send(new LaunchTaskFailedEvent());
@@ -286,7 +289,7 @@
                     //       never happen)
                     specs.add(composeOffscreenAnimationSpec(t, offscreenTaskRect));
                 } else {
-                    layoutAlgorithm.getStackTransform(task, stackScroll, mTmpTransform, null);
+                    layoutAlgorithm.getStackTransform(t, stackScroll, mTmpTransform, null);
                     specs.add(composeAnimationSpec(tv, mTmpTransform, true /* addHeaderBitmap */));
                 }
             }
@@ -311,7 +314,7 @@
         Bitmap b = null;
         if (addHeaderBitmap) {
             float scale = transform.scale;
-            int fromHeaderWidth = (int) (taskView.mHeaderView.getMeasuredWidth() * scale);
+            int fromHeaderWidth = (int) (transform.rect.width());
             int fromHeaderHeight = (int) (taskView.mHeaderView.getMeasuredHeight() * scale);
             b = Bitmap.createBitmap(fromHeaderWidth, fromHeaderHeight,
                     Bitmap.Config.ARGB_8888);
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 21c08d1..b59ff30 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -16,10 +16,15 @@
 
 package com.android.systemui.recents.views;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
 import android.content.Context;
-import android.content.res.Resources;
 import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Outline;
 import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.util.ArraySet;
@@ -27,13 +32,16 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewOutlineProvider;
 import android.view.ViewPropertyAnimator;
 import android.view.WindowInsets;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
-import com.android.internal.logging.MetricsLogger;
 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.RecentsActivity;
@@ -42,26 +50,33 @@
 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.CancelEnterRecentsWindowAnimationEvent;
-import com.android.systemui.recents.events.activity.DebugFlagsChangedEvent;
+import com.android.systemui.recents.events.activity.ClearHistoryEvent;
 import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
+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.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.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.stackdivider.WindowManagerProxy;
 import com.android.systemui.statusbar.FlingAnimationUtils;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -74,8 +89,9 @@
  */
 public class RecentsView extends FrameLayout {
 
-    private static final String TAG = "RecentsView";
-    private static final boolean DEBUG = false;
+    private static final int DOCK_AREA_OVERLAY_TRANSITION_DURATION = 135;
+    private static final int DEFAULT_UPDATE_SCRIM_DURATION = 200;
+    private static final float DEFAULT_SCRIM_ALPHA = 0.33f;
 
     private final Handler mHandler;
 
@@ -83,19 +99,20 @@
     private TaskStackView mTaskStackView;
     private RecentsAppWidgetHostView mSearchBar;
     private TextView mHistoryButton;
+    private TextView mHistoryClearAllButton;
     private View mEmptyView;
+    private RecentsHistoryView mHistoryView;
+
     private boolean mAwaitingFirstLayout = true;
     private boolean mLastTaskLaunchedWasFreeform;
     private Rect mSystemInsets = new Rect();
+    private int mDividerSize;
+
+    private ColorDrawable mBackgroundScrim = new ColorDrawable(Color.BLACK);
+    private Animator mBackgroundScrimAnimator;
 
     private RecentsTransitionHelper mTransitionHelper;
     private RecentsViewTouchHandler mTouchHandler;
-    private TaskStack.DockState[] mVisibleDockStates = {
-            TaskStack.DockState.LEFT,
-            TaskStack.DockState.TOP,
-            TaskStack.DockState.RIGHT,
-            TaskStack.DockState.BOTTOM,
-    };
 
     private final Interpolator mFastOutSlowInInterpolator;
     private final Interpolator mFastOutLinearInInterpolator;
@@ -115,31 +132,41 @@
 
     public RecentsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        Resources res = context.getResources();
         setWillNotDraw(false);
+
+        SystemServicesProxy ssp = Recents.getSystemServices();
         mHandler = new Handler();
         mTransitionHelper = new RecentsTransitionHelper(getContext(), mHandler);
         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
                 com.android.internal.R.interpolator.fast_out_slow_in);
         mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
                 com.android.internal.R.interpolator.fast_out_linear_in);
+        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);
         mHistoryButton = (TextView) inflater.inflate(R.layout.recents_history_button, this, false);
         mHistoryButton.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                ReferenceCountedTrigger postHideStackAnimationTrigger = new ReferenceCountedTrigger(v.getContext());
-                postHideStackAnimationTrigger.increment();
-                EventBus.getDefault().send(new ShowHistoryEvent(postHideStackAnimationTrigger));
-                postHideStackAnimationTrigger.decrement();
+                EventBus.getDefault().send(new ToggleHistoryEvent());
             }
         });
         addView(mHistoryButton);
+        mHistoryButton.setClipToOutline(true);
+        mHistoryButton.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);
         addView(mEmptyView);
+
+        setBackground(mBackgroundScrim);
     }
 
     /** Set/get the bsp root node */
@@ -147,14 +174,11 @@
         RecentsConfiguration config = Recents.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
         mStack = stack;
-        // Disable reusing task stack views until the visibility bug is fixed. b/25998134
-        if (false && launchState.launchedReuseTaskStackViews) {
+        if (launchState.launchedReuseTaskStackViews) {
             if (mTaskStackView != null) {
                 // If onRecentsHidden is not triggered, we need to the stack view again here
                 mTaskStackView.reset();
                 mTaskStackView.setStack(stack);
-                removeView(mTaskStackView);
-                addView(mTaskStackView);
             } else {
                 mTaskStackView = new TaskStackView(getContext(), stack);
                 addView(mTaskStackView);
@@ -167,8 +191,17 @@
             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.launchedFromAppWithThumbnail || mStack.getTaskCount() == 0) {
+            mBackgroundScrim.setAlpha((int) (DEFAULT_SCRIM_ALPHA * 255));
+        } else {
+            mBackgroundScrim.setAlpha(0);
+        }
+
         // Update the top level view's visibilities
-        if (stack.getStackTaskCount() > 0) {
+        if (stack.getTaskCount() > 0) {
             hideEmptyView();
         } else {
             showEmptyView();
@@ -186,6 +219,13 @@
     }
 
     /**
+     * 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() {
@@ -218,7 +258,6 @@
     /** Launches the focused task from the first stack if possible */
     public boolean launchFocusedTask() {
         if (mTaskStackView != null) {
-            TaskStack stack = mTaskStackView.getStack();
             Task task = mTaskStackView.getFocusedTask();
             if (task != null) {
                 TaskView taskView = mTaskStackView.getChildViewForTask(task);
@@ -248,7 +287,6 @@
     /** Launches a given task. */
     public boolean launchTask(Task task, Rect taskBounds, int destinationStack) {
         if (mTaskStackView != null) {
-            TaskStack stack = mTaskStackView.getStack();
             // Iterate the stack views and try and find the given task.
             List<TaskView> taskViews = mTaskStackView.getTaskViews();
             int taskViewCount = taskViews.size();
@@ -264,39 +302,6 @@
         return false;
     }
 
-    /** Requests all task stacks to start their enter-recents animation */
-    public void startEnterRecentsAnimation(ViewAnimation.TaskViewEnterContext ctx) {
-        // We have to increment/decrement the post animation trigger in case there are no children
-        // to ensure that it runs
-        ctx.postAnimationTrigger.increment();
-        if (mTaskStackView != null) {
-            mTaskStackView.startEnterRecentsAnimation(ctx);
-        }
-        ctx.postAnimationTrigger.decrement();
-    }
-
-    /** Requests all task stacks to start their exit-recents animation */
-    public void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
-        // We have to increment/decrement the post animation trigger in case there are no children
-        // to ensure that it runs
-        ctx.postAnimationTrigger.increment();
-        if (mTaskStackView != null) {
-            mTaskStackView.startExitToHomeAnimation(ctx);
-        }
-        ctx.postAnimationTrigger.decrement();
-
-        // Hide the history button
-        int taskViewExitToHomeDuration = getResources().getInteger(
-                R.integer.recents_task_exit_to_home_duration);
-        hideHistoryButton(taskViewExitToHomeDuration);
-
-        // If we are going home, cancel the previous task's window transition
-        EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null));
-
-        // Notify sof the exit animation
-        EventBus.getDefault().send(new DismissRecentsToHomeAnimationStarted());
-    }
-
     /** Adds the search bar */
     public void setSearchBar(RecentsAppWidgetHostView searchBar) {
         // Remove the previous search bar if one exists
@@ -319,7 +324,7 @@
      * Hides the task stack and shows the empty view.
      */
     public void showEmptyView() {
-        if (!RecentsDebugFlags.Static.DisableSearchBar && (mSearchBar != null)) {
+        if (RecentsDebugFlags.Static.EnableSearchBar && (mSearchBar != null)) {
             mSearchBar.setVisibility(View.INVISIBLE);
         }
         mTaskStackView.setVisibility(View.INVISIBLE);
@@ -334,7 +339,7 @@
     public void hideEmptyView() {
         mEmptyView.setVisibility(View.INVISIBLE);
         mTaskStackView.setVisibility(View.VISIBLE);
-        if (!RecentsDebugFlags.Static.DisableSearchBar && (mSearchBar != null)) {
+        if (RecentsDebugFlags.Static.EnableSearchBar && (mSearchBar != null)) {
             mSearchBar.setVisibility(View.VISIBLE);
         }
         mTaskStackView.bringToFront();
@@ -344,17 +349,10 @@
         mHistoryButton.bringToFront();
     }
 
-    /**
-     * Returns the last known system insets.
-     */
-    public Rect getSystemInsets() {
-        return mSystemInsets;
-    }
-
     @Override
     protected void onAttachedToWindow() {
         EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
-        EventBus.getDefault().register(mTouchHandler, RecentsActivity.EVENT_BUS_PRIORITY + 1);
+        EventBus.getDefault().register(mTouchHandler, RecentsActivity.EVENT_BUS_PRIORITY + 2);
         super.onAttachedToWindow();
     }
 
@@ -392,17 +390,28 @@
             mTaskStackView.measure(widthMeasureSpec, heightMeasureSpec);
         }
 
-        // Measure the empty view
-        measureChild(mEmptyView, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
-                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+        // 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));
+        }
 
-        // Measure the history button with the full space above the stack, but width-constrained
-        // to the stack
+        // 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.EXACTLY),
-                MeasureSpec.makeMeasureSpec(historyButtonRect.height(),
-                        MeasureSpec.EXACTLY));
+                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));
+        }
 
         setMeasuredDimension(width, height);
     }
@@ -429,13 +438,41 @@
         }
 
         // Layout the empty view
-        mEmptyView.layout(left, top, right, bottom);
+        if (mEmptyView.getVisibility() != GONE) {
+            mEmptyView.layout(left, top, right, bottom);
+        }
 
-        // Layout the history button left-aligned with the stack, but offset from the top of the
-        // view
+        // 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;
-        mHistoryButton.layout(historyButtonRect.left, historyButtonRect.top,
-                historyButtonRect.right, historyButtonRect.bottom);
+        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 (mAwaitingFirstLayout) {
             mAwaitingFirstLayout = false;
@@ -471,8 +508,9 @@
     @Override
     protected void dispatchDraw(Canvas canvas) {
         super.dispatchDraw(canvas);
-        for (int i = mVisibleDockStates.length - 1; i >= 0; i--) {
-            Drawable d = mVisibleDockStates[i].viewState.dockAreaOverlay;
+        ArrayList<TaskStack.DockState> visDockStates = mTouchHandler.getVisibleDockStates();
+        for (int i = visDockStates.size() - 1; i >= 0; i--) {
+            Drawable d = visDockStates.get(i).viewState.dockAreaOverlay;
             if (d.getAlpha() > 0) {
                 d.draw(canvas);
             }
@@ -481,8 +519,9 @@
 
     @Override
     protected boolean verifyDrawable(Drawable who) {
-        for (int i = mVisibleDockStates.length - 1; i >= 0; i--) {
-            Drawable d = mVisibleDockStates[i].viewState.dockAreaOverlay;
+        ArrayList<TaskStack.DockState> visDockStates = mTouchHandler.getVisibleDockStates();
+        for (int i = visDockStates.size() - 1; i >= 0; i--) {
+            Drawable d = visDockStates.get(i).viewState.dockAreaOverlay;
             if (d == who) {
                 return true;
             }
@@ -498,52 +537,88 @@
                 event.screenPinningRequested, event.targetTaskBounds, event.targetTaskStack);
     }
 
+    public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
+        // Hide the history button
+        int taskViewExitToHomeDuration = getResources().getInteger(
+                R.integer.recents_task_exit_to_home_duration);
+        hideHistoryButton(taskViewExitToHomeDuration, false /* translate */);
+        animateBackgroundScrim(0f, taskViewExitToHomeDuration);
+    }
+
     public final void onBusEvent(DragStartEvent event) {
         updateVisibleDockRegions(mTouchHandler.getDockStatesForCurrentOrientation(),
-                TaskStack.DockState.NONE.viewState.dockAreaAlpha);
+                true /* isDefaultDockState */, TaskStack.DockState.NONE.viewState.dockAreaAlpha,
+                true /* animateAlpha */, false /* animateBounds */);
     }
 
     public final void onBusEvent(DragDropTargetChangedEvent event) {
         if (event.dropTarget == null || !(event.dropTarget instanceof TaskStack.DockState)) {
             updateVisibleDockRegions(mTouchHandler.getDockStatesForCurrentOrientation(),
-                    TaskStack.DockState.NONE.viewState.dockAreaAlpha);
+                    true /* isDefaultDockState */, TaskStack.DockState.NONE.viewState.dockAreaAlpha,
+                    true /* animateAlpha */, true /* animateBounds */);
         } else {
             final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
-            updateVisibleDockRegions(new TaskStack.DockState[] {dockState}, -1);
+            updateVisibleDockRegions(new TaskStack.DockState[] {dockState},
+                    false /* isDefaultDockState */, -1, true /* animateAlpha */,
+                    true /* animateBounds */);
         }
     }
 
     public final void onBusEvent(final DragEndEvent event) {
-        // Animate the overlay alpha back to 0
-        updateVisibleDockRegions(null, -1);
-
         // Handle the case where we drop onto a dock region
         if (event.dropTarget instanceof TaskStack.DockState) {
             final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
 
-            // Remove the task after it is docked
-            event.taskView.animate()
-                    .alpha(0f)
-                    .setDuration(150)
-                    .setInterpolator(mFastOutLinearInInterpolator)
-                    .setUpdateListener(null)
-                    .setListener(null)
-                    .withEndAction(new Runnable() {
-                        @Override
-                        public void run() {
-                            mTaskStackView.getStack().removeTask(event.task);
-                        }
-                    })
-                    .withLayer()
-                    .start();
+            // Hide the dock region
+            updateVisibleDockRegions(null, false /* isDefaultDockState */, -1,
+                    false /* animateAlpha */, false /* animateBounds */);
 
-            // Dock the task and launch it
-            SystemServicesProxy ssp = Recents.getSystemServices();
-            ssp.startTaskInDockedMode(event.task.key.id, dockState.createMode);
-            launchTask(event.task, null, INVALID_STACK_ID);
+            TaskStackLayoutAlgorithm stackLayout = mTaskStackView.getStackAlgorithm();
+            TaskStackViewScroller stackScroller = mTaskStackView.getScroller();
+            TaskViewTransform tmpTransform = new TaskViewTransform();
 
-            MetricsLogger.action(mContext,
-                    MetricsLogger.ACTION_WINDOW_DOCK_DRAG_DROP);
+            // We translated the view but we need to animate it back from the current layout-space
+            // rect to its final layout-space rect
+            int x = (int) event.taskView.getTranslationX();
+            int y = (int) event.taskView.getTranslationY();
+            Rect taskViewRect = new Rect(event.taskView.getLeft(), event.taskView.getTop(),
+                    event.taskView.getRight(), event.taskView.getBottom());
+            taskViewRect.offset(x, y);
+            event.taskView.setTranslationX(0);
+            event.taskView.setTranslationY(0);
+            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 TaskViewAnimation(125, PhoneStatusBar.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);
+
+                                    // Animate the stack accordingly
+                                    TaskViewAnimation stackAnim = new TaskViewAnimation(
+                                            TaskStackView.DEFAULT_SYNC_STACK_DURATION,
+                                            mFastOutSlowInInterpolator);
+                                    mTaskStackView.getStack().removeTask(event.task, stackAnim);
+                                }
+                            }));
+
+            MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP);
+        } else {
+            // Animate the overlay alpha back to 0
+            updateVisibleDockRegions(null, true /* isDefaultDockState */, -1,
+                    true /* animateAlpha */, false /* animateBounds */);
         }
     }
 
@@ -572,114 +647,26 @@
         animator.start();
     }
 
-    public final void onBusEvent(ShowHistoryEvent event) {
-        // Hide the history button when the history view is shown
-        hideHistoryButton(getResources().getInteger(R.integer.recents_history_transition_duration),
-                event.postHideStackAnimationTrigger);
-        event.postHideStackAnimationTrigger.addLastDecrementRunnable(new Runnable() {
-            @Override
-            public void run() {
-                setAlpha(0f);
-            }
-        });
+    public final void onBusEvent(TaskStackUpdatedEvent event) {
+        mStack.setTasks(event.stack.computeAllTasksList(), true /* notifyStackChanges */);
+        mStack.createAffiliatedGroupings(getContext());
     }
 
-    public final void onBusEvent(HideHistoryEvent event) {
-        // Show the history button when the history view is hidden
-        setAlpha(1f);
-        showHistoryButton(getResources().getInteger(R.integer.recents_history_transition_duration),
-                event.postHideHistoryAnimationTrigger);
-    }
-
-    public final void onBusEvent(ShowHistoryButtonEvent event) {
-        showHistoryButton(150);
-    }
-
-    public final void onBusEvent(HideHistoryButtonEvent event) {
-        hideHistoryButton(100);
-    }
-
-    /**
-     * Shows the history button.
-     */
-    private void showHistoryButton(final int duration) {
-        ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger(getContext());
-        postAnimationTrigger.increment();
-        showHistoryButton(duration, postAnimationTrigger);
-        postAnimationTrigger.decrement();
-    }
-
-    private void showHistoryButton(final int duration,
-            final ReferenceCountedTrigger postHideHistoryAnimationTrigger) {
-        mHistoryButton.setVisibility(View.VISIBLE);
-        mHistoryButton.setAlpha(0f);
-        mHistoryButton.setText(getContext().getString(R.string.recents_history_label_format,
-                mStack.getHistoricalTasks().size()));
-        postHideHistoryAnimationTrigger.addLastDecrementRunnable(new Runnable() {
-            @Override
-            public void run() {
-                mHistoryButton.animate()
-                        .alpha(1f)
-                        .setDuration(duration)
-                        .setInterpolator(mFastOutSlowInInterpolator)
-                        .withLayer()
-                        .start();
-            }
-        });
-    }
-
-    /**
-     * Hides the history button.
-     */
-    private void hideHistoryButton(int duration) {
-        ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger(getContext());
-        postAnimationTrigger.increment();
-        hideHistoryButton(duration, postAnimationTrigger);
-        postAnimationTrigger.decrement();
-    }
-
-    private void hideHistoryButton(int duration,
-            final ReferenceCountedTrigger postHideStackAnimationTrigger) {
-        mHistoryButton.animate()
-                .alpha(0f)
-                .setDuration(duration)
-                .setInterpolator(mFastOutLinearInInterpolator)
-                .withEndAction(new Runnable() {
-                    @Override
-                    public void run() {
-                        mHistoryButton.setVisibility(View.INVISIBLE);
-                        postHideStackAnimationTrigger.decrement();
-                    }
-                })
-                .withLayer()
-                .start();
-        postHideStackAnimationTrigger.increment();
-    }
-
-    /**
-     * Updates the dock region to match the specified dock state.
-     */
-    private void updateVisibleDockRegions(TaskStack.DockState[] newDockStates, int overrideAlpha) {
-        ArraySet<TaskStack.DockState> newDockStatesSet = new ArraySet<>();
-        if (newDockStates != null) {
-            for (TaskStack.DockState dockState : newDockStates) {
-                newDockStatesSet.add(dockState);
-            }
+    public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
+        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+        if (!launchState.launchedFromAppWithThumbnail && mStack.getTaskCount() > 0) {
+            int taskViewEnterFromHomeDuration = getResources().getInteger(
+                    R.integer.recents_task_enter_from_home_duration);
+            animateBackgroundScrim(DEFAULT_SCRIM_ALPHA, taskViewEnterFromHomeDuration);
         }
-        for (TaskStack.DockState dockState : mVisibleDockStates) {
-            TaskStack.DockState.ViewState viewState = dockState.viewState;
-            if (newDockStates == null || !newDockStatesSet.contains(dockState)) {
-                // This is no longer visible, so hide it
-                viewState.startAlphaAnimation(0, 150);
-            } else {
-                // This state is now visible, update the bounds and show it
-                int alpha = (overrideAlpha != -1 ? overrideAlpha : viewState.dockAreaAlpha);
-                viewState.dockAreaOverlay.setBounds(
-                        dockState.getDockedBounds(getMeasuredWidth(), getMeasuredHeight()));
-                viewState.dockAreaOverlay.setCallback(this);
-                viewState.startAlphaAnimation(alpha, 150);
-            }
-        }
+    }
+
+    public final void onBusEvent(UpdateBackgroundScrimEvent event) {
+        animateBackgroundScrim(event.alpha, DEFAULT_UPDATE_SCRIM_DURATION);
+    }
+
+    public final void onBusEvent(ResetBackgroundScrimEvent event) {
+        animateBackgroundScrim(DEFAULT_SCRIM_ALPHA, DEFAULT_UPDATE_SCRIM_DURATION);
     }
 
     public final void onBusEvent(RecentsVisibilityChangedEvent event) {
@@ -687,6 +674,216 @@
             // Reset the view state
             mAwaitingFirstLayout = true;
             mLastTaskLaunchedWasFreeform = false;
+            hideHistoryButton(0, false /* translate */);
         }
     }
+
+    public final void onBusEvent(ToggleHistoryEvent event) {
+        if (mHistoryView != null && mHistoryView.isVisible()) {
+            EventBus.getDefault().send(new HideHistoryEvent(true /* animate */));
+        } else {
+            EventBus.getDefault().send(new ShowHistoryEvent());
+        }
+    }
+
+    public final void onBusEvent(ShowHistoryEvent event) {
+        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(mFastOutSlowInInterpolator)
+                    .withEndAction(new Runnable() {
+                        @Override
+                        public void run() {
+                            mEmptyView.setVisibility(View.INVISIBLE);
+                        }
+                    })
+                    .start();
+        }
+
+        mHistoryView.show(mStack, stackRect.height(), mHistoryClearAllButton);
+    }
+
+    public final void onBusEvent(HideHistoryEvent event) {
+        // 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(mFastOutSlowInInterpolator)
+                    .start();
+        }
+
+        mHistoryView.hide(event.animate, stackRect.height(), mHistoryClearAllButton);
+    }
+
+    public final void onBusEvent(ShowHistoryButtonEvent event) {
+        showHistoryButton(150, event.translate);
+    }
+
+    public final void onBusEvent(HideHistoryButtonEvent event) {
+        hideHistoryButton(100, true /* translate */);
+    }
+
+    /**
+     * Shows the history button.
+     */
+    private void showHistoryButton(final int duration, final boolean translate) {
+        final ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger();
+        if (mHistoryButton.getVisibility() == View.INVISIBLE) {
+            mHistoryButton.setVisibility(View.VISIBLE);
+            mHistoryButton.setAlpha(0f);
+            if (translate) {
+                mHistoryButton.setTranslationY(-mHistoryButton.getMeasuredHeight() * 0.25f);
+            } else {
+                mHistoryButton.setTranslationY(0f);
+            }
+            postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
+                @Override
+                public void run() {
+                    if (translate) {
+                        mHistoryButton.animate()
+                            .translationY(0f);
+                    }
+                    mHistoryButton.animate()
+                            .alpha(1f)
+                            .setDuration(duration)
+                            .setInterpolator(mFastOutSlowInInterpolator)
+                            .withLayer()
+                            .start();
+                }
+            });
+        }
+        postAnimationTrigger.flushLastDecrementRunnables();
+    }
+
+    /**
+     * Hides the history button.
+     */
+    private void hideHistoryButton(int duration, boolean translate) {
+        final ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger();
+        hideHistoryButton(duration, translate, postAnimationTrigger);
+        postAnimationTrigger.flushLastDecrementRunnables();
+    }
+
+    /**
+     * Hides the history button.
+     */
+    private void hideHistoryButton(int duration, boolean translate,
+            final ReferenceCountedTrigger postAnimationTrigger) {
+        if (mHistoryButton.getVisibility() == View.VISIBLE) {
+            if (translate) {
+                mHistoryButton.animate()
+                    .translationY(-mHistoryButton.getMeasuredHeight() * 0.25f);
+            }
+            mHistoryButton.animate()
+                    .alpha(0f)
+                    .setDuration(duration)
+                    .setInterpolator(mFastOutSlowInInterpolator)
+                    .withEndAction(new Runnable() {
+                        @Override
+                        public void run() {
+                            mHistoryButton.setVisibility(View.INVISIBLE);
+                            postAnimationTrigger.decrement();
+                        }
+                    })
+                    .withLayer()
+                    .start();
+            postAnimationTrigger.increment();
+        }
+    }
+
+    /**
+     * Updates the dock region to match the specified dock state.
+     */
+    private void updateVisibleDockRegions(TaskStack.DockState[] newDockStates,
+            boolean isDefaultDockState, int overrideAlpha, boolean animateAlpha,
+            boolean animateBounds) {
+        ArraySet<TaskStack.DockState> newDockStatesSet = Utilities.arrayToSet(newDockStates,
+                new ArraySet<TaskStack.DockState>());
+        ArrayList<TaskStack.DockState> visDockStates = mTouchHandler.getVisibleDockStates();
+        for (int i = visDockStates.size() - 1; i >= 0; i--) {
+            TaskStack.DockState dockState = visDockStates.get(i);
+            TaskStack.DockState.ViewState viewState = dockState.viewState;
+            if (newDockStates == null || !newDockStatesSet.contains(dockState)) {
+                // This is no longer visible, so hide it
+                viewState.startAnimation(null, 0, DOCK_AREA_OVERLAY_TRANSITION_DURATION,
+                        PhoneStatusBar.ALPHA_OUT, animateAlpha, animateBounds);
+            } else {
+                // This state is now visible, update the bounds and show it
+                int alpha = (overrideAlpha != -1 ? overrideAlpha : viewState.dockAreaAlpha);
+                Rect bounds = isDefaultDockState
+                        ? dockState.getPreDockedBounds(getMeasuredWidth(), getMeasuredHeight())
+                        : dockState.getDockedBounds(getMeasuredWidth(), getMeasuredHeight(),
+                        mDividerSize, mSystemInsets, getResources());
+                if (viewState.dockAreaOverlay.getCallback() != this) {
+                    viewState.dockAreaOverlay.setCallback(this);
+                    viewState.dockAreaOverlay.setBounds(bounds);
+                }
+                viewState.startAnimation(bounds, alpha, DOCK_AREA_OVERLAY_TRANSITION_DURATION,
+                        PhoneStatusBar.ALPHA_IN, animateAlpha, animateBounds);
+            }
+        }
+    }
+
+    /**
+     * Animates the background scrim to the given {@param alpha}.
+     */
+    private void animateBackgroundScrim(float alpha, int duration) {
+        Utilities.cancelAnimationWithoutCallbacks(mBackgroundScrimAnimator);
+        int alphaInt = (int) (alpha * 255);
+        mBackgroundScrimAnimator = ObjectAnimator.ofInt(mBackgroundScrim, Utilities.DRAWABLE_ALPHA,
+                mBackgroundScrim.getAlpha(), alphaInt);
+        mBackgroundScrimAnimator.setDuration(duration);
+        mBackgroundScrimAnimator.setInterpolator(alphaInt > mBackgroundScrim.getAlpha()
+                ? PhoneStatusBar.ALPHA_OUT
+                : PhoneStatusBar.ALPHA_IN);
+        mBackgroundScrimAnimator.start();
+    }
 }
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 37a0194..d8698ee 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -19,6 +19,7 @@
 import android.content.res.Configuration;
 import android.graphics.Point;
 import android.view.MotionEvent;
+import android.view.ViewConfiguration;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.events.EventBus;
@@ -26,7 +27,6 @@
 import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragStartInitializeDropTargetsEvent;
-import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
@@ -58,9 +58,6 @@
  */
 public class RecentsViewTouchHandler {
 
-    private static final String TAG = "RecentsViewTouchHandler";
-    private static final boolean DEBUG = false;
-
     private RecentsView mRv;
 
     private Task mDragTask;
@@ -68,13 +65,17 @@
 
     private Point mTaskViewOffset = new Point();
     private Point mDownPos = new Point();
-    private boolean mDragging;
+    private boolean mDragRequested;
+    private boolean mIsDragging;
+    private float mDragSlop;
 
     private DropTarget mLastDropTarget;
     private ArrayList<DropTarget> mDropTargets = new ArrayList<>();
+    private ArrayList<TaskStack.DockState> mVisibleDockStates = new ArrayList<>();
 
     public RecentsViewTouchHandler(RecentsView rv) {
         mRv = rv;
+        mDragSlop = ViewConfiguration.get(rv.getContext()).getScaledTouchSlop();
     }
 
     /**
@@ -97,16 +98,23 @@
         return dockStates;
     }
 
+    /**
+     * Returns the set of visible dock states for this current drag.
+     */
+    public ArrayList<TaskStack.DockState> getVisibleDockStates() {
+        return mVisibleDockStates;
+    }
+
     /** Touch preprocessing for handling below */
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         handleTouchEvent(ev);
-        return mDragging;
+        return mDragRequested;
     }
 
     /** Handles touch events once we have intercepted them */
     public boolean onTouchEvent(MotionEvent ev) {
         handleTouchEvent(ev);
-        return mDragging;
+        return mDragRequested;
     }
 
     /**** Events ****/
@@ -114,7 +122,9 @@
     public final void onBusEvent(DragStartEvent event) {
         SystemServicesProxy ssp = Recents.getSystemServices();
         mRv.getParent().requestDisallowInterceptTouchEvent(true);
-        mDragging = true;
+        mDragRequested = true;
+        // We defer starting the actual drag handling until the user moves past the drag slop
+        mIsDragging = false;
         mDragTask = event.task;
         mTaskView = event.taskView;
         mDropTargets.clear();
@@ -128,12 +138,13 @@
         mTaskView.setTranslationX(x);
         mTaskView.setTranslationY(y);
 
-        RecentsConfiguration config = Recents.getConfiguration();
-        if (!ssp.hasDockedTask()) {
+        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);
             }
         }
 
@@ -142,7 +153,7 @@
     }
 
     public final void onBusEvent(DragEndEvent event) {
-        mDragging = false;
+        mDragRequested = false;
         mDragTask = null;
         mTaskView = null;
         mLastDropTarget = null;
@@ -150,7 +161,6 @@
 
     /**
      * Handles dragging touch events
-     * @param ev
      */
     private void handleTouchEvent(MotionEvent ev) {
         int action = ev.getAction();
@@ -159,25 +169,45 @@
                 mDownPos.set((int) ev.getX(), (int) ev.getY());
                 break;
             case MotionEvent.ACTION_MOVE: {
-                if (mDragging) {
-                    int width = mRv.getMeasuredWidth();
-                    int height = mRv.getMeasuredHeight();
-                    float evX = ev.getX();
-                    float evY = ev.getY();
-                    float x = evX - mTaskViewOffset.x;
-                    float y = evY - mTaskViewOffset.y;
+                float evX = ev.getX();
+                float evY = ev.getY();
+                float x = evX - mTaskViewOffset.x;
+                float y = evY - mTaskViewOffset.y;
 
-                    DropTarget currentDropTarget = null;
-                    for (DropTarget target : mDropTargets) {
-                        if (target.acceptsDrop((int) evX, (int) evY, width, height)) {
-                            currentDropTarget = target;
-                            break;
-                        }
+                if (mDragRequested) {
+                    if (!mIsDragging) {
+                        mIsDragging = Math.hypot(evX - mDownPos.x, evY - mDownPos.y) > mDragSlop;
                     }
-                    if (mLastDropTarget != currentDropTarget) {
-                        mLastDropTarget = currentDropTarget;
-                        EventBus.getDefault().send(new DragDropTargetChangedEvent(mDragTask,
-                                currentDropTarget));
+                    if (mIsDragging) {
+                        int width = mRv.getMeasuredWidth();
+                        int height = mRv.getMeasuredHeight();
+
+                        DropTarget currentDropTarget = null;
+
+                        // Give priority to the current drop target to retain the touch handling
+                        if (mLastDropTarget != null) {
+                            if (mLastDropTarget.acceptsDrop((int) evX, (int) evY, width, height,
+                                    true /* isCurrentTarget */)) {
+                                currentDropTarget = mLastDropTarget;
+                            }
+                        }
+
+                        // Otherwise, find the next target to handle this event
+                        if (currentDropTarget == null) {
+                            for (DropTarget target : mDropTargets) {
+                                if (target.acceptsDrop((int) evX, (int) evY, width, height,
+                                        false /* isCurrentTarget */)) {
+                                    currentDropTarget = target;
+                                    break;
+                                }
+                            }
+                        }
+                        if (mLastDropTarget != currentDropTarget) {
+                            mLastDropTarget = currentDropTarget;
+                            EventBus.getDefault().send(new DragDropTargetChangedEvent(mDragTask,
+                                    currentDropTarget));
+                        }
+
                     }
 
                     mTaskView.setTranslationX(x);
@@ -187,13 +217,9 @@
             }
             case MotionEvent.ACTION_UP:
             case MotionEvent.ACTION_CANCEL: {
-                if (mDragging) {
-                    ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger(
-                            mRv.getContext());
-                    postAnimationTrigger.increment();
+                if (mDragRequested) {
                     EventBus.getDefault().send(new DragEndEvent(mDragTask, mTaskView,
-                            mLastDropTarget, postAnimationTrigger));
-                    postAnimationTrigger.decrement();
+                            mLastDropTarget));
                     break;
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
deleted file mode 100644
index b7c1de3..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
+++ /dev/null
@@ -1,403 +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.views;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.os.Build;
-import android.util.DisplayMetrics;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
-
-/**
- * This class facilitates swipe to dismiss. It defines an interface to be implemented by the
- * by the class hosting the views that need to swiped, and, using this interface, handles touch
- * events and translates / fades / animates the view as it is dismissed.
- */
-public class SwipeHelper {
-    static final String TAG = "SwipeHelper";
-    private static final boolean SLOW_ANIMATIONS = false; // DEBUG;
-    private static final boolean CONSTRAIN_SWIPE = true;
-    private static final boolean FADE_OUT_DURING_SWIPE = true;
-    private static final boolean DISMISS_IF_SWIPED_FAR_ENOUGH = true;
-
-    public static final int X = 0;
-    public static final int Y = 1;
-
-    private static LinearInterpolator sLinearInterpolator = new LinearInterpolator();
-    private Interpolator mLinearOutSlowInInterpolator;
-
-    private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec
-    private int DEFAULT_ESCAPE_ANIMATION_DURATION = 75; // ms
-    private int MAX_ESCAPE_ANIMATION_DURATION = 150; // ms
-    private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 250; // ms
-
-    public static float ALPHA_FADE_START = 0.15f; // fraction of thumbnail width
-                                                 // where fade starts
-    static final float ALPHA_FADE_END = 0.65f; // fraction of thumbnail width
-                                              // beyond which alpha->0
-    private float mMinAlpha = 0f;
-
-    private float mPagingTouchSlop;
-    Callback mCallback;
-    private int mSwipeDirection;
-    private VelocityTracker mVelocityTracker;
-
-    private float mInitialTouchPos;
-    private boolean mDragging;
-    private float mSnapBackTranslationX;
-
-    private View mCurrView;
-    private boolean mCanCurrViewBeDimissed;
-    private float mDensityScale;
-
-    public boolean mAllowSwipeTowardsStart = true;
-    public boolean mAllowSwipeTowardsEnd = true;
-    private boolean mRtl;
-
-    public SwipeHelper(Context context, int swipeDirection, Callback callback, float densityScale,
-            float pagingTouchSlop) {
-        mCallback = callback;
-        mSwipeDirection = swipeDirection;
-        mVelocityTracker = VelocityTracker.obtain();
-        mDensityScale = densityScale;
-        mPagingTouchSlop = pagingTouchSlop;
-        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
-                com.android.internal.R.interpolator.linear_out_slow_in);
-    }
-
-    public void setDensityScale(float densityScale) {
-        mDensityScale = densityScale;
-    }
-
-    public void setSnapBackTranslationX(float translationX) {
-        mSnapBackTranslationX = translationX;
-    }
-
-    public void setPagingTouchSlop(float pagingTouchSlop) {
-        mPagingTouchSlop = pagingTouchSlop;
-    }
-
-    public void cancelOngoingDrag() {
-        if (mDragging) {
-            if (mCurrView != null) {
-                mCallback.onDragCancelled(mCurrView);
-                setTranslation(mCurrView, 0);
-                mCallback.onSnapBackCompleted(mCurrView);
-                mCurrView = null;
-            }
-            mDragging = false;
-        }
-    }
-
-    public void resetTranslation(View v) {
-        setTranslation(v, 0);
-    }
-
-    private float getPos(MotionEvent ev) {
-        return mSwipeDirection == X ? ev.getX() : ev.getY();
-    }
-
-    private float getTranslation(View v) {
-        return mSwipeDirection == X ? v.getTranslationX() : v.getTranslationY();
-    }
-
-    private float getVelocity(VelocityTracker vt) {
-        return mSwipeDirection == X ? vt.getXVelocity() :
-                vt.getYVelocity();
-    }
-
-    private ObjectAnimator createTranslationAnimation(View v, float newPos) {
-        ObjectAnimator anim = ObjectAnimator.ofFloat(v,
-                mSwipeDirection == X ? View.TRANSLATION_X : View.TRANSLATION_Y, newPos);
-        return anim;
-    }
-
-    private float getPerpendicularVelocity(VelocityTracker vt) {
-        return mSwipeDirection == X ? vt.getYVelocity() :
-                vt.getXVelocity();
-    }
-
-    private void setTranslation(View v, float translate) {
-        if (mSwipeDirection == X) {
-            v.setTranslationX(translate);
-        } else {
-            v.setTranslationY(translate);
-        }
-    }
-
-    private float getSize(View v) {
-        final DisplayMetrics dm = v.getContext().getResources().getDisplayMetrics();
-        return mSwipeDirection == X ? dm.widthPixels : dm.heightPixels;
-    }
-
-    public void setMinAlpha(float minAlpha) {
-        mMinAlpha = minAlpha;
-    }
-
-    float getAlphaForOffset(View view) {
-        float viewSize = getSize(view);
-        final float fadeSize = ALPHA_FADE_END * viewSize;
-        float result = 1.0f;
-        float pos = getTranslation(view);
-        if (pos >= viewSize * ALPHA_FADE_START) {
-            result = 1.0f - (pos - viewSize * ALPHA_FADE_START) / fadeSize;
-        } else if (pos < viewSize * (1.0f - ALPHA_FADE_START)) {
-            result = 1.0f + (viewSize * ALPHA_FADE_START + pos) / fadeSize;
-        }
-        result = Math.min(result, 1.0f);
-        result = Math.max(result, 0f);
-        return Math.max(mMinAlpha, result);
-    }
-
-    /**
-     * Determines whether the given view has RTL layout.
-     */
-    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
-    public static boolean isLayoutRtl(View view) {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
-            return View.LAYOUT_DIRECTION_RTL == view.getLayoutDirection();
-        } else {
-            return false;
-        }
-    }
-
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        final int action = ev.getAction();
-
-        switch (action) {
-            case MotionEvent.ACTION_DOWN:
-                mDragging = false;
-                mCurrView = mCallback.getChildAtPosition(ev);
-                mVelocityTracker.clear();
-                if (mCurrView != null) {
-                    mRtl = isLayoutRtl(mCurrView);
-                    mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView);
-                    mVelocityTracker.addMovement(ev);
-                    mInitialTouchPos = getPos(ev);
-                } else {
-                    mCanCurrViewBeDimissed = false;
-                }
-                break;
-            case MotionEvent.ACTION_MOVE:
-                if (mCurrView != null) {
-                    mVelocityTracker.addMovement(ev);
-                    float pos = getPos(ev);
-                    float delta = pos - mInitialTouchPos;
-                    if (Math.abs(delta) > mPagingTouchSlop) {
-                        mCallback.onBeginDrag(mCurrView);
-                        mDragging = true;
-                        mInitialTouchPos = pos - getTranslation(mCurrView);
-                    }
-                }
-                break;
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-                mDragging = false;
-                mCurrView = null;
-                break;
-        }
-        return mDragging;
-    }
-
-    /**
-     * @param view The view to be dismissed
-     * @param velocity The desired pixels/second speed at which the view should move
-     */
-    private void dismissChild(final View view, float velocity) {
-        final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
-        float newPos;
-        if (velocity < 0
-                || (velocity == 0 && getTranslation(view) < 0)
-                // if we use the Menu to dismiss an item in landscape, animate up
-                || (velocity == 0 && getTranslation(view) == 0 && mSwipeDirection == Y)) {
-            newPos = -getSize(view);
-        } else {
-            newPos = getSize(view);
-        }
-        int duration = MAX_ESCAPE_ANIMATION_DURATION;
-        if (velocity != 0) {
-            duration = Math.min(duration,
-                                (int) (Math.abs(newPos - getTranslation(view)) *
-                                        1000f / Math.abs(velocity)));
-        } else {
-            duration = DEFAULT_ESCAPE_ANIMATION_DURATION;
-        }
-
-        ValueAnimator anim = createTranslationAnimation(view, newPos);
-        anim.setInterpolator(sLinearInterpolator);
-        anim.setDuration(duration);
-        anim.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mCallback.onChildDismissed(view);
-                if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
-                    view.setAlpha(1.f);
-                }
-            }
-        });
-        anim.addUpdateListener(new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
-                    view.setAlpha(getAlphaForOffset(view));
-                }
-            }
-        });
-        anim.start();
-    }
-
-    private void snapChild(final View view, float velocity) {
-        final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
-        ValueAnimator anim = createTranslationAnimation(view, mSnapBackTranslationX);
-        int duration = SNAP_ANIM_LEN;
-        anim.setDuration(duration);
-        anim.setInterpolator(mLinearOutSlowInInterpolator);
-        anim.addUpdateListener(new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
-                    view.setAlpha(getAlphaForOffset(view));
-                }
-                mCallback.onSwipeChanged(mCurrView, view.getTranslationX());
-            }
-        });
-        anim.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
-                    view.setAlpha(1.0f);
-                }
-                mCallback.onSnapBackCompleted(view);
-            }
-        });
-        anim.start();
-    }
-
-    public boolean onTouchEvent(MotionEvent ev) {
-        if (!mDragging) {
-            if (!onInterceptTouchEvent(ev)) {
-                return mCanCurrViewBeDimissed;
-            }
-        }
-
-        mVelocityTracker.addMovement(ev);
-        final int action = ev.getAction();
-        switch (action) {
-            case MotionEvent.ACTION_OUTSIDE:
-            case MotionEvent.ACTION_MOVE:
-                if (mCurrView != null) {
-                    float delta = getPos(ev) - mInitialTouchPos;
-                    setSwipeAmount(delta);
-                    mCallback.onSwipeChanged(mCurrView, delta);
-                }
-                break;
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-                if (mCurrView != null) {
-                    endSwipe(mVelocityTracker);
-                }
-                break;
-        }
-        return true;
-    }
-
-    private void setSwipeAmount(float amount) {
-        // don't let items that can't be dismissed be dragged more than
-        // maxScrollDistance
-        if (CONSTRAIN_SWIPE
-                && (!isValidSwipeDirection(amount) || !mCallback.canChildBeDismissed(mCurrView))) {
-            float size = getSize(mCurrView);
-            float maxScrollDistance = 0.15f * size;
-            if (Math.abs(amount) >= size) {
-                amount = amount > 0 ? maxScrollDistance : -maxScrollDistance;
-            } else {
-                amount = maxScrollDistance * (float) Math.sin((amount/size)*(Math.PI/2));
-            }
-        }
-        setTranslation(mCurrView, amount);
-        if (FADE_OUT_DURING_SWIPE && mCanCurrViewBeDimissed) {
-            float alpha = getAlphaForOffset(mCurrView);
-            mCurrView.setAlpha(alpha);
-        }
-    }
-
-    private boolean isValidSwipeDirection(float amount) {
-        if (mSwipeDirection == X) {
-            if (mRtl) {
-                return (amount <= 0) ? mAllowSwipeTowardsEnd : mAllowSwipeTowardsStart;
-            } else {
-                return (amount <= 0) ? mAllowSwipeTowardsStart : mAllowSwipeTowardsEnd;
-            }
-        }
-
-        // Vertical swipes are always valid.
-        return true;
-    }
-
-    private void endSwipe(VelocityTracker velocityTracker) {
-        velocityTracker.computeCurrentVelocity(1000 /* px/sec */);
-        float velocity = getVelocity(velocityTracker);
-        float perpendicularVelocity = getPerpendicularVelocity(velocityTracker);
-        float escapeVelocity = SWIPE_ESCAPE_VELOCITY * mDensityScale;
-        float translation = getTranslation(mCurrView);
-        // Decide whether to dismiss the current view
-        boolean childSwipedFarEnough = DISMISS_IF_SWIPED_FAR_ENOUGH &&
-                Math.abs(translation) > 0.6 * getSize(mCurrView);
-        boolean childSwipedFastEnough = (Math.abs(velocity) > escapeVelocity) &&
-                (Math.abs(velocity) > Math.abs(perpendicularVelocity)) &&
-                (velocity > 0) == (translation > 0);
-
-        boolean dismissChild = mCallback.canChildBeDismissed(mCurrView)
-                && isValidSwipeDirection(translation)
-                && (childSwipedFastEnough || childSwipedFarEnough);
-
-        if (dismissChild) {
-            // flingadingy
-            dismissChild(mCurrView, childSwipedFastEnough ? velocity : 0f);
-        } else {
-            // snappity
-            mCallback.onDragCancelled(mCurrView);
-            snapChild(mCurrView, velocity);
-        }
-    }
-
-    public interface Callback {
-        View getChildAtPosition(MotionEvent ev);
-
-        boolean canChildBeDismissed(View v);
-
-        void onBeginDrag(View v);
-
-        void onSwipeChanged(View v, float delta);
-
-        void onChildDismissed(View v);
-
-        void onSnapBackCompleted(View v);
-
-        void onDragCancelled(View v);
-    }
-}
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 f84eb53..2254dfc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -22,9 +22,6 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsActivityLaunchState;
-import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
 
@@ -33,12 +30,9 @@
 
     Context mContext;
 
-    View mStatusBarScrimView;
     View mNavBarScrimView;
 
     boolean mHasNavBarScrim;
-    boolean mShouldAnimateStatusBarScrim;
-    boolean mHasStatusBarScrim;
     boolean mShouldAnimateNavBarScrim;
 
     int mNavBarScrimEnterDuration;
@@ -48,7 +42,6 @@
 
     public SystemBarScrimViews(Activity activity) {
         mContext = activity;
-        mStatusBarScrimView = activity.findViewById(R.id.status_bar_scrim);
         mNavBarScrimView = activity.findViewById(R.id.nav_bar_scrim);
         mNavBarScrimEnterDuration = activity.getResources().getInteger(
                 R.integer.recents_nav_bar_scrim_enter_duration);
@@ -62,19 +55,12 @@
      * Prepares the scrim views for animating when entering Recents. This will be called before
      * the first draw.
      */
-    public void prepareEnterRecentsAnimation(boolean hasStatusBarScrim, boolean animateStatusBarScrim,
-            boolean hasNavBarScrim, boolean animateNavBarScrim) {
-        RecentsConfiguration config = Recents.getConfiguration();
-        RecentsActivityLaunchState launchState = config.getLaunchState();
-        mHasNavBarScrim = hasStatusBarScrim;
-        mShouldAnimateStatusBarScrim = animateStatusBarScrim;
-        mHasStatusBarScrim = hasNavBarScrim;
+    public void prepareEnterRecentsAnimation(boolean hasNavBarScrim, boolean animateNavBarScrim) {
+        mHasNavBarScrim = hasNavBarScrim;
         mShouldAnimateNavBarScrim = animateNavBarScrim;
 
         mNavBarScrimView.setVisibility(mHasNavBarScrim && !mShouldAnimateNavBarScrim ?
                 View.VISIBLE : View.INVISIBLE);
-        mStatusBarScrimView.setVisibility(mHasStatusBarScrim && !mShouldAnimateStatusBarScrim ?
-                View.VISIBLE : View.INVISIBLE);
     }
 
     /**** EventBus events ****/
@@ -83,20 +69,6 @@
      * Starts animating the scrim views when entering Recents.
      */
     public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
-        if (mHasStatusBarScrim && mShouldAnimateStatusBarScrim) {
-            mStatusBarScrimView.setTranslationY(-mStatusBarScrimView.getMeasuredHeight());
-            mStatusBarScrimView.animate()
-                    .translationY(0)
-                    .setDuration(mNavBarScrimEnterDuration)
-                    .setInterpolator(mQuintOutInterpolator)
-                    .withStartAction(new Runnable() {
-                        @Override
-                        public void run() {
-                            mStatusBarScrimView.setVisibility(View.VISIBLE);
-                        }
-                    })
-                    .start();
-        }
         if (mHasNavBarScrim && mShouldAnimateNavBarScrim) {
             mNavBarScrimView.setTranslationY(mNavBarScrimView.getMeasuredHeight());
             mNavBarScrimView.animate()
@@ -120,14 +92,6 @@
     public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
         int taskViewExitToAppDuration = mContext.getResources().getInteger(
                 R.integer.recents_task_exit_to_app_duration);
-        if (mHasStatusBarScrim && mShouldAnimateStatusBarScrim) {
-            mStatusBarScrimView.animate()
-                    .translationY(-mStatusBarScrimView.getMeasuredHeight())
-                    .setStartDelay(0)
-                    .setDuration(taskViewExitToAppDuration)
-                    .setInterpolator(mFastOutSlowInInterpolator)
-                    .start();
-        }
         if (mHasNavBarScrim && mShouldAnimateNavBarScrim) {
             mNavBarScrimView.animate()
                     .translationY(mNavBarScrimView.getMeasuredHeight())
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
new file mode 100644
index 0000000..d550d83
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.views;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.RectF;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsActivityLaunchState;
+import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.misc.ReferenceCountedTrigger;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+
+import java.util.List;
+
+/**
+ * A helper class to create task view animations for {@link TaskView}s in a {@link TaskStackView},
+ * but not the contents of the {@link TaskView}s.
+ */
+public class TaskStackAnimationHelper {
+
+    /**
+     * Callbacks from the helper to coordinate view-content animations with view animations.
+     */
+    public interface Callbacks {
+        /**
+         * Callback to prepare for the start animation for the launch target {@link TaskView}.
+         */
+        void onPrepareLaunchTargetForEnterAnimation();
+
+        /**
+         * Callback to start the animation for the launch target {@link TaskView}.
+         */
+        void onStartLaunchTargetEnterAnimation(int duration, boolean screenPinningEnabled,
+                ReferenceCountedTrigger postAnimationTrigger);
+
+        /**
+         * Callback to start the animation for the launch target {@link TaskView} when it is
+         * launched from Recents.
+         */
+        void onStartLaunchTargetLaunchAnimation(int duration, boolean screenPinningRequested,
+                ReferenceCountedTrigger postAnimationTrigger);
+    }
+
+    private TaskStackView mStackView;
+
+    private Interpolator mFastOutSlowInInterpolator;
+    private Interpolator mFastOutLinearInInterpolator;
+    private Interpolator mQuintOutInterpolator;
+
+    private TaskViewTransform mTmpTransform = new TaskViewTransform();
+
+    public TaskStackAnimationHelper(Context context, TaskStackView stackView) {
+        mStackView = stackView;
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_slow_in);
+        mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_linear_in);
+        mQuintOutInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.decelerate_quint);
+    }
+
+    /**
+     * Prepares the stack views and puts them in their initial animation state while visible, before
+     * the in-app enter animations start (after the window-transition completes).
+     */
+    public void prepareForEnterAnimation() {
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
+        Resources res = mStackView.getResources();
+
+        TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm();
+        TaskStackViewScroller stackScroller = mStackView.getScroller();
+        TaskStack stack = mStackView.getStack();
+        Task launchTargetTask = stack.getLaunchTarget();
+
+        // Break early if there are no tasks
+        if (stack.getTaskCount() == 0) {
+            return;
+        }
+
+        int offscreenY = stackLayout.mStackRect.bottom;
+        int taskViewAffiliateGroupEnterOffset = res.getDimensionPixelSize(
+                R.dimen.recents_task_view_affiliate_group_enter_offset);
+
+        // Prepare each of the task views for their enter animation from front to back
+        List<TaskView> taskViews = mStackView.getTaskViews();
+        for (int i = taskViews.size() - 1; i >= 0; i--) {
+            TaskView tv = taskViews.get(i);
+            Task task = tv.getTask();
+            boolean currentTaskOccludesLaunchTarget = (launchTargetTask != null &&
+                    launchTargetTask.group.isTaskAboveTask(task, launchTargetTask));
+            boolean hideTask = (launchTargetTask != null &&
+                    launchTargetTask.isFreeformTask() && task.isFreeformTask());
+
+            // Get the current transform for the task, which will be used to position it offscreen
+            stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform,
+                    null);
+
+            if (hideTask) {
+                tv.setVisibility(View.INVISIBLE);
+            } else if (launchState.launchedHasConfigurationChanged) {
+                // Just load the views as-is
+            } else if (launchState.launchedFromAppWithThumbnail) {
+                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);
+                    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.offsetTo(bounds.left, offscreenY);
+                tv.setLeftTopRightBottom((int) bounds.left, (int) bounds.top, (int) bounds.right,
+                        (int) bounds.bottom);
+            }
+        }
+    }
+
+    /**
+     * Starts the in-app enter animation, which animates the {@link TaskView}s to their final places
+     * depending on how Recents was triggered.
+     */
+    public void startEnterAnimation(final ReferenceCountedTrigger postAnimationTrigger) {
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
+        Resources res = mStackView.getResources();
+
+        TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm();
+        TaskStackViewScroller stackScroller = mStackView.getScroller();
+        TaskStack stack = mStackView.getStack();
+        Task launchTargetTask = stack.getLaunchTarget();
+
+        // Break early if there are no tasks
+        if (stack.getTaskCount() == 0) {
+            return;
+        }
+
+        int taskViewEnterFromAppDuration = res.getInteger(
+                R.integer.recents_task_enter_from_app_duration);
+        int taskViewEnterFromAffiliatedAppDuration = res.getInteger(
+                R.integer.recents_task_enter_from_affiliated_app_duration);
+        int taskViewEnterFromHomeDuration = res.getInteger(
+                R.integer.recents_task_enter_from_home_duration);
+        int taskViewEnterFromHomeStaggerDelay = res.getInteger(
+                R.integer.recents_task_enter_from_home_stagger_delay);
+
+        // Create enter animations for each of the views from front to back
+        List<TaskView> taskViews = mStackView.getTaskViews();
+        int taskViewCount = taskViews.size();
+        for (int i = taskViewCount - 1; i >= 0; i--) {
+            final TaskView tv = taskViews.get(i);
+            Task task = tv.getTask();
+            boolean currentTaskOccludesLaunchTarget = false;
+            if (launchTargetTask != null) {
+                currentTaskOccludesLaunchTarget = launchTargetTask.group.isTaskAboveTask(task,
+                        launchTargetTask);
+            }
+
+            // Get the current transform for the task, which will be updated to the final transform
+            // to animate to depending on how recents was invoked
+            stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform,
+                    null);
+
+            if (launchState.launchedFromAppWithThumbnail) {
+                if (task.isLaunchTarget) {
+                    tv.onStartLaunchTargetEnterAnimation(taskViewEnterFromAppDuration,
+                            mStackView.mScreenPinningEnabled, postAnimationTrigger);
+                } else {
+                    // Animate the task up if it was occluding the launch target
+                    if (currentTaskOccludesLaunchTarget) {
+                        TaskViewAnimation taskAnimation = new TaskViewAnimation(
+                                taskViewEnterFromAffiliatedAppDuration, PhoneStatusBar.ALPHA_IN,
+                                new AnimatorListenerAdapter() {
+                                    @Override
+                                    public void onAnimationEnd(Animator animation) {
+                                        postAnimationTrigger.decrement();
+                                        tv.setClipViewInStack(false);
+                                    }
+                                });
+                        postAnimationTrigger.increment();
+                        mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
+                    }
+                }
+
+            } else if (launchState.launchedFromHome) {
+                // Animate the tasks up
+                int frontIndex = (taskViewCount - i - 1);
+                int delay = frontIndex * taskViewEnterFromHomeStaggerDelay;
+                int duration = taskViewEnterFromHomeDuration +
+                        frontIndex * taskViewEnterFromHomeStaggerDelay;
+
+                TaskViewAnimation taskAnimation = new TaskViewAnimation(delay,
+                        duration, mQuintOutInterpolator,
+                        postAnimationTrigger.decrementOnAnimationEnd());
+                postAnimationTrigger.increment();
+                mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
+            }
+        }
+    }
+
+    /**
+     * Starts an in-app animation to hide all the task views so that we can transition back home.
+     */
+    public void startExitToHomeAnimation(boolean animated,
+            ReferenceCountedTrigger postAnimationTrigger) {
+        Resources res = mStackView.getResources();
+        TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm();
+        TaskStackViewScroller stackScroller = mStackView.getScroller();
+        TaskStack stack = mStackView.getStack();
+
+        // Break early if there are no tasks
+        if (stack.getTaskCount() == 0) {
+            return;
+        }
+
+        int offscreenY = stackLayout.mStackRect.bottom;
+        int taskViewExitToHomeDuration = res.getInteger(
+                R.integer.recents_task_exit_to_home_duration);
+
+        // Create the animations for each of the tasks
+        List<TaskView> taskViews = mStackView.getTaskViews();
+        int taskViewCount = taskViews.size();
+        for (int i = 0; i < taskViewCount; i++) {
+            TaskView tv = taskViews.get(i);
+            Task task = tv.getTask();
+            TaskViewAnimation taskAnimation = new TaskViewAnimation(
+                    animated ? taskViewExitToHomeDuration : 0, mFastOutLinearInInterpolator,
+                    postAnimationTrigger.decrementOnAnimationEnd());
+            postAnimationTrigger.increment();
+
+            stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform,
+                    null);
+            mTmpTransform.rect.offsetTo(mTmpTransform.rect.left, offscreenY);
+            mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
+        }
+    }
+
+    /**
+     * Starts the animation for the launching task view, hiding any tasks that might occlude the
+     * window transition for the launching task.
+     */
+    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);
+
+        Task launchingTask = launchingTaskView.getTask();
+        List<TaskView> taskViews = mStackView.getTaskViews();
+        int taskViewCount = taskViews.size();
+        for (int i = 0; i < taskViewCount; i++) {
+            TaskView tv = taskViews.get(i);
+            Task task = tv.getTask();
+            boolean currentTaskOccludesLaunchTarget = (launchingTask != null &&
+                    launchingTask.group.isTaskAboveTask(task, launchingTask));
+
+            if (tv == launchingTaskView) {
+                tv.setClipViewInStack(false);
+                tv.onStartLaunchTargetLaunchAnimation(taskViewExitToAppDuration,
+                        screenPinningRequested, postAnimationTrigger);
+            } else if (currentTaskOccludesLaunchTarget) {
+                // Animate this task out of view
+                TaskViewAnimation taskAnimation = new TaskViewAnimation(
+                        taskViewExitToAppDuration, PhoneStatusBar.ALPHA_OUT,
+                        postAnimationTrigger.decrementOnAnimationEnd());
+                postAnimationTrigger.increment();
+
+                stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform,
+                        null);
+                mTmpTransform.alpha = 0f;
+                mTmpTransform.rect.offset(0, taskViewAffiliateGroupEnterOffset);
+                mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
+            }
+        }
+    }
+
+    /**
+     * Starts the delete animation for the specified {@link TaskView}.
+     */
+    public void startDeleteTaskAnimation(Task deleteTask, 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);
+
+        // Disabling clipping with the stack while the view is animating away
+        deleteTaskView.setClipViewInStack(false);
+
+        // Compose the new animation and transform and star the animation
+        TaskViewAnimation taskAnimation = new TaskViewAnimation(taskViewRemoveAnimDuration,
+                PhoneStatusBar.ALPHA_OUT, new AnimatorListenerAdapter() {
+            @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.alpha = 0f;
+        mTmpTransform.rect.offset(taskViewRemoveAnimTranslationXPx, 0);
+        mStackView.updateTaskViewToTransform(deleteTaskView, mTmpTransform, taskAnimation);
+    }
+
+    /**
+     * Starts the animation to hide the {@link TaskView}s when the history is shown.
+     */
+    public void startShowHistoryAnimation(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;
+
+        List<TaskView> taskViews = mStackView.getTaskViews();
+        int taskViewCount = taskViews.size();
+        for (int i = taskViewCount - 1; i >= 0; i--) {
+            TaskView tv = taskViews.get(i);
+            Task task = tv.getTask();
+            TaskViewAnimation taskAnimation = new TaskViewAnimation(startDelayIncr * i,
+                    historyTransitionDuration, mFastOutSlowInInterpolator,
+                    postAnimationTrigger.decrementOnAnimationEnd());
+            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);
+            TaskViewAnimation taskAnimation = new TaskViewAnimation(startDelayIncr * i,
+                    historyTransitionDuration, mFastOutSlowInInterpolator);
+            stackLayout.getStackTransform(tv.getTask(), stackScroller.getStackScroll(),
+                    mTmpTransform, null);
+            mTmpTransform.alpha = 1f;
+            mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
+        }
+    }
+}
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 de944fc..bb37c04 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -21,8 +21,9 @@
 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.Log;
 import android.util.Property;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
@@ -38,7 +39,6 @@
 import com.android.systemui.recents.model.TaskStack;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 
 /**
  * Used to describe a visible range that can be normalized to [0, 1].
@@ -103,9 +103,6 @@
  */
 public class TaskStackLayoutAlgorithm {
 
-    private static final String TAG = "TaskStackViewLayoutAlgorithm";
-    private static final boolean DEBUG = false;
-
     // The scale factor to apply to the user movement in the stack to unfocus it
     private static final float UNFOCUS_MULTIPLIER = 0.8f;
 
@@ -113,12 +110,16 @@
     public static final float STATE_FOCUSED = 1f;
     public static final float STATE_UNFOCUSED = 0f;
 
+    public interface TaskStackLayoutAlgorithmCallbacks {
+        void onFocusStateChanged(float prevFocusState, float curFocusState);
+    }
+
     /**
      * The various stack/freeform states.
      */
     public static class StackState {
 
-        public static final StackState FREEFORM_ONLY = new StackState(1f, 0);
+        public static final StackState FREEFORM_ONLY = new StackState(1f, 255);
         public static final StackState STACK_ONLY = new StackState(0f, 0);
         public static final StackState SPLIT = new StackState(0.5f, 255);
 
@@ -130,7 +131,7 @@
          *                          allocate to the freeform workspace
          * @param freeformBackgroundAlpha the background alpha for the freeform workspace
          */
-        StackState(float freeformHeightPct, int freeformBackgroundAlpha) {
+        private StackState(float freeformHeightPct, int freeformBackgroundAlpha) {
             this.freeformHeightPct = freeformHeightPct;
             this.freeformBackgroundAlpha = freeformBackgroundAlpha;
         }
@@ -141,9 +142,8 @@
         public static StackState getStackStateForStack(TaskStack stack) {
             SystemServicesProxy ssp = Recents.getSystemServices();
             boolean hasFreeformWorkspaces = ssp.hasFreeformWorkspaceSupport();
-            int taskCount = stack.getStackTaskCount();
-            int freeformCount = stack.getStackTaskFreeformCount();
-            int stackCount = taskCount - freeformCount;
+            int freeformCount = stack.getFreeformTaskCount();
+            int stackCount = stack.getStackTaskCount();
             if (hasFreeformWorkspaces && stackCount > 0 && freeformCount > 0) {
                 return SPLIT;
             } else if (hasFreeformWorkspaces && freeformCount > 0) {
@@ -212,9 +212,9 @@
     }
 
     Context mContext;
-    private TaskStackView mStackView;
     private Interpolator mLinearOutSlowInInterpolator;
     private StackState mState = StackState.SPLIT;
+    private TaskStackLayoutAlgorithmCallbacks mCb;
 
     // The task bounds (untransformed) for layout.  This rect is anchored at mTaskRoot.
     public Rect mTaskRect = new Rect();
@@ -275,14 +275,19 @@
     int mMaxTranslationZ;
 
     // Optimization, allows for quick lookup of task -> index
-    private HashMap<Task.TaskKey, Integer> mTaskIndexMap = new HashMap<>();
+    private ArrayMap<Task.TaskKey, Integer> mTaskIndexMap = new ArrayMap<>();
 
     // The freeform workspace layout
     FreeformWorkspaceLayoutAlgorithm mFreeformLayoutAlgorithm;
 
-    public TaskStackLayoutAlgorithm(Context context, TaskStackView stackView) {
+    // The transform to place TaskViews at the front and back of the stack respectively
+    TaskViewTransform mBackOfStackTransform = new TaskViewTransform();
+    TaskViewTransform mFrontOfStackTransform = new TaskViewTransform();
+
+    public TaskStackLayoutAlgorithm(Context context, TaskStackLayoutAlgorithmCallbacks cb) {
         Resources res = context.getResources();
-        mStackView = stackView;
+        mContext = context;
+        mCb = cb;
 
         mFocusedRange = new Range(res.getFloat(R.integer.recents_layout_focused_range_min),
                 res.getFloat(R.integer.recents_layout_focused_range_max));
@@ -293,8 +298,7 @@
 
         mMinTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
         mMaxTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_max);
-        mContext = context;
-        mFreeformLayoutAlgorithm = new FreeformWorkspaceLayoutAlgorithm();
+        mFreeformLayoutAlgorithm = new FreeformWorkspaceLayoutAlgorithm(context);
         mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
                 com.android.internal.R.interpolator.linear_out_slow_in);
     }
@@ -317,8 +321,12 @@
      * Sets the focused state.
      */
     public void setFocusState(float focusState) {
+        float prevFocusState = mFocusState;
         mFocusState = focusState;
-        mStackView.requestSynchronizeStackViewsWithModel();
+        updateFrontBackTransforms();
+        if (mCb != null) {
+            mCb.onFocusStateChanged(prevFocusState, focusState);
+        }
     }
 
     /**
@@ -333,7 +341,6 @@
      * including the search bar.
      */
     public void initialize(Rect taskStackBounds, StackState state) {
-        RecentsDebugFlags debugFlags = Recents.getDebugFlags();
         RecentsConfiguration config = Recents.getConfiguration();
         int widthPadding = (int) (config.taskStackWidthPaddingPct * taskStackBounds.width());
         int heightPadding = mContext.getResources().getDimensionPixelSize(
@@ -347,6 +354,7 @@
         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,
                 mStackRect.right, mStackRect.top + mFocusedPeekHeight);
 
@@ -369,21 +377,14 @@
         mUnfocusedCurveInterpolator = new FreePathInterpolator(mUnfocusedCurve);
         mFocusedCurve = constructFocusedCurve();
         mFocusedCurveInterpolator = new FreePathInterpolator(mFocusedCurve);
-
-        if (DEBUG) {
-            Log.d(TAG, "initialize");
-            Log.d(TAG, "\tmFreeformRect: " + mFreeformRect);
-            Log.d(TAG, "\tmStackRect: " + mStackRect);
-            Log.d(TAG, "\tmTaskRect: " + mTaskRect);
-            Log.d(TAG, "\tmSystemInsets: " + mSystemInsets);
-        }
+        updateFrontBackTransforms();
     }
 
     /**
      * Computes the minimum and maximum scroll progress values and the progress values for each task
      * in the stack.
      */
-    void update(TaskStack stack) {
+    void update(TaskStack stack, ArraySet<Task.TaskKey> ignoreTasksSet) {
         SystemServicesProxy ssp = Recents.getSystemServices();
 
         // Clear the progress map
@@ -403,6 +404,9 @@
         ArrayList<Task> stackTasks = new ArrayList<>();
         for (int i = 0; i < tasks.size(); i++) {
             Task task = tasks.get(i);
+            if (ignoreTasksSet.contains(task.key)) {
+                continue;
+            }
             if (task.isFreeformTask()) {
                 freeformTasks.add(task);
             } else {
@@ -441,28 +445,27 @@
             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) {
                 RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
                 if (launchState.launchedFromHome) {
-                    mInitialScrollP = Math.max(mMinScrollP, mNumStackTasks - 1);
+                    mInitialScrollP = Math.max(mMinScrollP, Math.min(mMaxScrollP, launchTaskIndex));
                 } else {
-                    mInitialScrollP = Math.max(mMinScrollP, mNumStackTasks - 2);
+                    mInitialScrollP = Math.max(mMinScrollP, Math.min(mMaxScrollP,
+                            launchTaskIndex - 1));
                 }
             } else {
                 float offsetPct = (float) (mTaskRect.height() / 2) / mStackRect.height();
                 float normX = mUnfocusedCurveInterpolator.getX(offsetPct);
-                mInitialScrollP = (mNumStackTasks - 1) - mUnfocusedRange.getAbsoluteX(normX);
+                mInitialScrollP = Math.max(mMinScrollP, Math.min(mMaxScrollP,
+                        launchTaskIndex - mUnfocusedRange.getAbsoluteX(normX)));
             }
         }
-
-        if (DEBUG) {
-            Log.d(TAG, "mNumStackTasks: " + mNumStackTasks);
-            Log.d(TAG, "mNumFreeformTasks: " + mNumFreeformTasks);
-            Log.d(TAG, "mMinScrollP: " + mMinScrollP);
-            Log.d(TAG, "mMaxScrollP: " + mMaxScrollP);
-        }
     }
 
     /**
@@ -472,7 +475,7 @@
         Utilities.cancelAnimationWithoutCallbacks(mFocusStateAnimator);
         if (mFocusState > STATE_UNFOCUSED) {
             float delta = (float) yMovement / (UNFOCUS_MULTIPLIER * mStackRect.height());
-            mFocusState -= Math.min(mFocusState, Math.abs(delta));
+            setFocusState(mFocusState - Math.min(mFocusState, Math.abs(delta)));
         }
     }
 
@@ -498,27 +501,23 @@
         RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
         RecentsDebugFlags debugFlags = Recents.getDebugFlags();
         if (launchState.launchedWithAltTab || debugFlags.isInitialStatePaging()) {
-            return 1f;
+            return STATE_FOCUSED;
         }
-        return 0f;
+        return STATE_UNFOCUSED;
     }
 
     /**
-     * Returns the task progress that would put the task just off the back of the stack.
+     * Returns the TaskViewTransform that would put the task just off the back of the stack.
      */
-    public float getStackBackTaskProgress(float stackScroll) {
-        float min = mUnfocusedRange.relativeMin +
-                mFocusState * (mFocusedRange.relativeMin - mUnfocusedRange.relativeMin);
-        return stackScroll + min;
+    public TaskViewTransform getBackOfStackTransform() {
+        return mBackOfStackTransform;
     }
 
     /**
-     * Returns the task progress that would put the task just off the front of the stack.
+     * Returns the TaskViewTransform that would put the task just off the front of the stack.
      */
-    public float getStackFrontTaskProgress(float stackScroll) {
-        float max = mUnfocusedRange.relativeMax +
-                mFocusState * (mFocusedRange.relativeMax - mUnfocusedRange.relativeMax);
-        return stackScroll + max;
+    public TaskViewTransform getFrontOfStackTransform() {
+        return mFrontOfStackTransform;
     }
 
     /**
@@ -571,7 +570,8 @@
 
             boolean isFrontMostTaskInGroup = task.group == null || task.group.isFrontMostTask(task);
             if (isFrontMostTaskInGroup) {
-                getStackTransform(taskProgress, mInitialScrollP, tmpTransform, null);
+                getStackTransform(taskProgress, mInitialScrollP, tmpTransform, null,
+                        false /* ignoreSingleTaskCase */);
                 float screenY = tmpTransform.rect.top;
                 boolean hasVisibleThumbnail = (prevScreenY - screenY) > taskBarHeight;
                 if (hasVisibleThumbnail) {
@@ -613,21 +613,22 @@
                 transformOut.reset();
                 return transformOut;
             }
-            getStackTransform(mTaskIndexMap.get(task.key), stackScroll, transformOut,
-                    frontTransform);
-            if (task.thumbnail != null) {
-                transformOut.thumbnailScale = (float) mTaskRect.width() / task.thumbnail.getWidth();
-            }
-            if (DEBUG) {
-                Log.d(TAG, "getTransform: " + task.key + ", " + transformOut);
-            }
-            return transformOut;
+            return getStackTransform(mTaskIndexMap.get(task.key), stackScroll, transformOut,
+                    frontTransform, false /* ignoreSingleTaskCase */);
         }
     }
 
-    /** Update/get the transform */
+    /**
+     * Update/get the transform.
+     *
+     * @param ignoreSingleTaskCase When set, will ensure that the transform computed does not take
+     *                             into account the special single-task case.  This is only used
+     *                             internally to ensure that we can calculate the transform for any
+     *                             position in the stack.
+     */
     public TaskViewTransform getStackTransform(float taskProgress, float stackScroll,
-            TaskViewTransform transformOut, TaskViewTransform frontTransform) {
+            TaskViewTransform transformOut, TaskViewTransform frontTransform,
+            boolean ignoreSingleTaskCase) {
         SystemServicesProxy ssp = Recents.getSystemServices();
 
         // Compute the focused and unfocused offset
@@ -657,7 +658,7 @@
         int y;
         float z;
         float relP;
-        if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1) {
+        if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1 && !ignoreSingleTaskCase) {
             // When there is exactly one task, then decouple the task from the stack and just move
             // in screen space
             p = (mMinScrollP - stackScroll) / mNumStackTasks;
@@ -673,7 +674,11 @@
             y += (mStackRect.top - mTaskRect.top);
             z = Math.max(mMinTranslationZ, Math.min(mMaxTranslationZ,
                     mMinTranslationZ + (p * (mMaxTranslationZ - mMinTranslationZ))));
-            relP = unfocusedP;
+            if (mNumStackTasks == 1) {
+                relP = 1f;
+            } else {
+                relP = Math.min(mMaxScrollP, unfocusedP);
+            }
         }
 
         // Fill out the transform
@@ -685,7 +690,6 @@
         Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
         transformOut.visible = (transformOut.rect.top < mStackRect.bottom) &&
                 (frontTransform == null || transformOut.rect.top != frontTransform.rect.top);
-        transformOut.thumbnailScale = 1f;
         transformOut.p = relP;
         return transformOut;
     }
@@ -770,4 +774,23 @@
         p.cubicTo(0.5f, 1f - peekHeightPct, cpoint2X, cpoint2Y, 1f, 0f);
         return p;
     }
+
+    /**
+     * Updates the current transforms that would put a TaskView at the front and back of the stack.
+     */
+    private void updateFrontBackTransforms() {
+        // Return early if we have not yet initialized
+        if (mStackRect.isEmpty()) {
+            return;
+        }
+
+        float min = mUnfocusedRange.relativeMin +
+                mFocusState * (mFocusedRange.relativeMin - mUnfocusedRange.relativeMin);
+        float max = mUnfocusedRange.relativeMax +
+                mFocusState * (mFocusedRange.relativeMax - mUnfocusedRange.relativeMax);
+        getStackTransform(min, 0f, mBackOfStackTransform, null, true /* ignoreSingleTaskCase */);
+        getStackTransform(max, 0f, mFrontOfStackTransform, null, true /* ignoreSingleTaskCase */);
+        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 4e75d5a..79f6381 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -23,14 +23,14 @@
 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;
 import android.os.Parcelable;
-import android.util.IntProperty;
-import android.util.Log;
-import android.util.Property;
+import android.provider.Settings;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.MutableBoolean;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -47,18 +47,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.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.IterateRecentsEvent;
 import com.android.systemui.recents.events.activity.LaunchTaskEvent;
+import com.android.systemui.recents.events.activity.LaunchTaskStartedEvent;
 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.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
+import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
 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;
 import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent;
@@ -69,15 +74,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.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
@@ -88,11 +91,9 @@
 /* The visual representation of a task stack view */
 public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCallbacks,
         TaskView.TaskViewCallbacks, TaskStackViewScroller.TaskStackViewScrollerCallbacks,
+        TaskStackLayoutAlgorithm.TaskStackLayoutAlgorithmCallbacks,
         ViewPool.ViewPoolConsumer<TaskView, Task> {
 
-    private final static String TAG = "TaskStackView";
-    private final static boolean DEBUG = false;
-
     private final static String KEY_SAVED_STATE_SUPER = "saved_instance_state_super";
     private final static String KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE =
             "saved_instance_state_layout_focused_state";
@@ -103,51 +104,49 @@
     private static final float SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD = 0.3f;
     private static final float HIDE_HISTORY_BUTTON_SCROLL_THRESHOLD = 0.3f;
 
-    public static final Property<Drawable, Integer> DRAWABLE_ALPHA =
-            new IntProperty<Drawable>("drawableAlpha") {
-                @Override
-                public void setValue(Drawable object, int alpha) {
-                    object.setAlpha(alpha);
-                }
+    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;
 
-                @Override
-                public Integer get(Drawable object) {
-                    return object.getAlpha();
-                }
-            };
+    private static final ArraySet<Task.TaskKey> EMPTY_TASK_SET = new ArraySet<>();
 
     TaskStack mStack;
     TaskStackLayoutAlgorithm mLayoutAlgorithm;
     TaskStackViewScroller mStackScroller;
     TaskStackViewTouchHandler mTouchHandler;
+    TaskStackAnimationHelper mAnimationHelper;
     GradientDrawable mFreeformWorkspaceBackground;
     ObjectAnimator mFreeformWorkspaceBackgroundAnimator;
     ViewPool<TaskView, Task> mViewPool;
+
+    ArrayList<TaskView> mTaskViews = new ArrayList<>();
     ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<>();
+    ArraySet<Task.TaskKey> mIgnoreTasks = new ArraySet<>();
+    TaskViewAnimation mDeferredTaskViewLayoutAnimation = null;
+
     DozeTrigger mUIDozeTrigger;
     Task mFocusedTask;
-    // Optimizations
-    int mStackViewsAnimationDuration;
+
     int mTaskCornerRadiusPx;
-    boolean mStackViewsDirty = true;
-    boolean mStackViewsClipDirty = true;
+    private int mDividerSize;
+    private int mStartTimerIndicatorDuration;
+
+    boolean mTaskViewsClipDirty = true;
     boolean mAwaitingFirstLayout = true;
     boolean mEnterAnimationComplete = false;
-    boolean mStartEnterAnimationRequestedAfterLayout;
-    ViewAnimation.TaskViewEnterContext mStartEnterAnimationContext;
+    boolean mTouchExplorationEnabled;
+    boolean mScreenPinningEnabled;
 
-    Rect mTaskStackBounds = new Rect();
+    // The stable stack bounds are the full bounds that we were measured with from RecentsView
+    Rect mStableStackBounds = new Rect();
+    // The current stack bounds are dynamic and may change as the user drags and drops
+    Rect mStackBounds = new Rect();
     int[] mTmpVisibleRange = new int[2];
     Rect mTmpRect = new Rect();
-    RectF mTmpTaskRect = new RectF();
-    TaskViewTransform mTmpStackBackTransform = new TaskViewTransform();
-    TaskViewTransform mTmpStackFrontTransform = new TaskViewTransform();
-    HashMap<Task, TaskView> mTmpTaskViewMap = new HashMap<>();
-    ArrayList<TaskView> mTaskViews = new ArrayList<>();
-    List<TaskView> mImmutableTaskViews = new ArrayList<>();
+    ArrayMap<Task.TaskKey, TaskView> mTmpTaskViewMap = new ArrayMap<>();
     List<TaskView> mTmpTaskViews = new ArrayList<>();
+    TaskViewTransform mTmpTransform = new TaskViewTransform();
     LayoutInflater mInflater;
-    boolean mTouchExplorationEnabled;
 
     Interpolator mFastOutSlowInInterpolator;
 
@@ -156,22 +155,35 @@
             new ValueAnimator.AnimatorUpdateListener() {
                 @Override
                 public void onAnimationUpdate(ValueAnimator animation) {
-                    requestUpdateStackViewsClip();
+                    if (!mTaskViewsClipDirty) {
+                        mTaskViewsClipDirty = true;
+                        invalidate();
+                    }
                 }
             };
 
     // The drop targets for a task drag
     private DropTarget mFreeformWorkspaceDropTarget = new DropTarget() {
         @Override
-        public boolean acceptsDrop(int x, int y, int width, int height) {
-            return mLayoutAlgorithm.mFreeformRect.contains(x, y);
+        public boolean acceptsDrop(int x, int y, int width, int height, boolean isCurrentTarget) {
+            // This drop target has a fixed bounds and should be checked last, so just fall through
+            // if it is the current target
+            if (!isCurrentTarget) {
+                return mLayoutAlgorithm.mFreeformRect.contains(x, y);
+            }
+            return false;
         }
     };
 
     private DropTarget mStackDropTarget = new DropTarget() {
         @Override
-        public boolean acceptsDrop(int x, int y, int width, int height) {
-            return mLayoutAlgorithm.mStackRect.contains(x, y);
+        public boolean acceptsDrop(int x, int y, int width, int height, boolean isCurrentTarget) {
+            // This drop target has a fixed bounds and should be checked last, so just fall through
+            // if it is the current target
+            if (!isCurrentTarget) {
+                return mLayoutAlgorithm.mStackRect.contains(x, y);
+            }
+            return false;
         }
     };
 
@@ -185,13 +197,14 @@
         mViewPool = new ViewPool<>(context, this);
         mInflater = LayoutInflater.from(context);
         mLayoutAlgorithm = new TaskStackLayoutAlgorithm(context, this);
-        mStackScroller = new TaskStackViewScroller(context, mLayoutAlgorithm);
-        mStackScroller.setCallbacks(this);
+        mStackScroller = new TaskStackViewScroller(context, this, mLayoutAlgorithm);
         mTouchHandler = new TaskStackViewTouchHandler(context, this, mStackScroller);
+        mAnimationHelper = new TaskStackAnimationHelper(context, this);
         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
                 com.android.internal.R.interpolator.fast_out_slow_in);
         mTaskCornerRadiusPx = res.getDimensionPixelSize(
                 R.dimen.recents_task_view_rounded_corners_radius);
+        mDividerSize = ssp.getDockedDividerSize(context);
 
         int taskBarDismissDozeDelaySeconds = getResources().getInteger(
                 R.integer.recents_task_bar_dismiss_delay_seconds);
@@ -213,15 +226,15 @@
                 R.drawable.recents_freeform_workspace_bg);
         mFreeformWorkspaceBackground.setCallback(this);
         if (ssp.hasFreeformWorkspaceSupport()) {
-            setBackgroundColor(getContext().getColor(R.color.recents_freeform_workspace_bg_color));
+            mFreeformWorkspaceBackground.setColor(
+                    getContext().getColor(R.color.recents_freeform_workspace_bg_color));
         }
     }
 
     @Override
     protected void onAttachedToWindow() {
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        mTouchExplorationEnabled = ssp.isTouchExplorationEnabled();
         EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
+        readSystemFlags();
         super.onAttachedToWindow();
     }
 
@@ -257,12 +270,11 @@
                 mTaskViews.add((TaskView) v);
             }
         }
-        mImmutableTaskViews = Collections.unmodifiableList(mTaskViews);
     }
 
     /** Gets the list of task views */
     List<TaskView> getTaskViews() {
-        return mImmutableTaskViews;
+        return mTaskViews;
     }
 
     /**
@@ -321,86 +333,106 @@
 
         // Reset the stack state
         mStack.reset();
-        mStackViewsDirty = true;
-        mStackViewsClipDirty = true;
+        mTaskViewsClipDirty = true;
         mAwaitingFirstLayout = true;
         mEnterAnimationComplete = false;
-        if (mUIDozeTrigger != null) {
-            mUIDozeTrigger.stopDozing();
-            mUIDozeTrigger.resetTrigger();
-        }
+        mUIDozeTrigger.stopDozing();
+        mUIDozeTrigger.resetTrigger();
         mStackScroller.reset();
         mLayoutAlgorithm.reset();
+        readSystemFlags();
         requestLayout();
     }
 
-    /** Requests that the views be synchronized with the model */
-    void requestSynchronizeStackViewsWithModel() {
-        requestSynchronizeStackViewsWithModel(0);
-    }
-    void requestSynchronizeStackViewsWithModel(int duration) {
-        if (!mStackViewsDirty) {
-            invalidate();
-            mStackViewsDirty = true;
-        }
-        if (mAwaitingFirstLayout) {
-            // Skip the animation if we are awaiting first layout
-            mStackViewsAnimationDuration = 0;
-        } else {
-            mStackViewsAnimationDuration = Math.max(mStackViewsAnimationDuration, duration);
-        }
-    }
-
-    /** Requests that the views clipping be updated. */
-    void requestUpdateStackViewsClip() {
-        if (!mStackViewsClipDirty) {
-            invalidate();
-            mStackViewsClipDirty = true;
-        }
-    }
-
     /** Returns the stack algorithm for this task stack. */
     public TaskStackLayoutAlgorithm getStackAlgorithm() {
         return mLayoutAlgorithm;
     }
 
     /**
-     * Gets the stack transforms of a list of tasks, and returns the visible range of tasks.
-     * This call ignores freeform tasks.
+     * Adds a task to the ignored set.
      */
-    private boolean updateStackTransforms(ArrayList<TaskViewTransform> taskTransforms,
-                                       ArrayList<Task> tasks,
-                                       float stackScroll,
-                                       int[] visibleRangeOut) {
-        int taskTransformCount = taskTransforms.size();
+    void addIgnoreTask(Task task) {
+        mIgnoreTasks.add(task.key);
+    }
+
+    /**
+     * Removes a task from the ignored set.
+     */
+    void removeIgnoreTask(Task task) {
+        mIgnoreTasks.remove(task.key);
+    }
+
+    /**
+     * Returns whether the specified {@param task} is ignored.
+     */
+    boolean isIgnoredTask(Task task) {
+        return mIgnoreTasks.contains(task.key);
+    }
+
+    /**
+     * Computes the task transforms at the current stack scroll for all visible tasks. If a valid
+     * target stack scroll is provided (ie. is different than {@param curStackScroll}), then the
+     * visible range includes all tasks at the target stack scroll. This is useful for ensure that
+     * all views necessary for a transition or animation will be visible at the start.
+     *
+     * This call ignores freeform tasks.
+     *
+     * @param taskTransforms The set of task view transforms to reuse, this list will be sized to
+     *                       match the size of {@param tasks}
+     * @param tasks The set of tasks for which to generate transforms
+     * @param curStackScroll The current stack scroll
+     * @param targetStackScroll The stack scroll that we anticipate we are going to be scrolling to.
+     *                          The range of the union of the visible views at the current and
+     *                          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.
+     */
+    boolean computeVisibleTaskTransforms(ArrayList<TaskViewTransform> taskTransforms,
+            ArrayList<Task> tasks, float curStackScroll, float targetStackScroll,
+            int[] visibleRangeOut, ArraySet<Task.TaskKey> ignoreTasksSet) {
         int taskCount = tasks.size();
         int frontMostVisibleIndex = -1;
         int backMostVisibleIndex = -1;
+        boolean useTargetStackScroll = Float.compare(curStackScroll, targetStackScroll) != 0;
 
         // We can reuse the task transforms where possible to reduce object allocation
-        if (taskTransformCount < taskCount) {
-            // If there are less transforms than tasks, then add as many transforms as necessary
-            for (int i = taskTransformCount; i < taskCount; i++) {
-                taskTransforms.add(new TaskViewTransform());
-            }
-        } else if (taskTransformCount > taskCount) {
-            // If there are more transforms than tasks, then just subset the transform list
-            taskTransforms.subList(0, taskCount);
-        }
+        Utilities.matchTaskListSize(tasks, taskTransforms);
 
         // Update the stack transforms
         TaskViewTransform frontTransform = null;
+        TaskViewTransform frontTransformAtTarget = null;
+        TaskViewTransform transform = null;
+        TaskViewTransform transformAtTarget = null;
         for (int i = taskCount - 1; i >= 0; i--) {
             Task task = tasks.get(i);
+
+            // Calculate the current and (if necessary) the target transform for the task
+            transform = mLayoutAlgorithm.getStackTransform(task, curStackScroll,
+                    taskTransforms.get(i), frontTransform);
+            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
+                // TODO: Optimize this
+                transformAtTarget = mLayoutAlgorithm.getStackTransform(task,
+                        targetStackScroll, new TaskViewTransform(), frontTransformAtTarget);
+                if (transformAtTarget.visible) {
+                    transform.copyFrom(transformAtTarget);
+                }
+            }
+
+            // For ignore tasks, only calculate the stack transform and skip the calculation of the
+            // visible stack indices
+            if (ignoreTasksSet.contains(task.key)) {
+                continue;
+            }
+
+            // For freeform tasks, only calculate the stack transform and skip the calculation of
+            // the visible stack indices
             if (task.isFreeformTask()) {
                 continue;
             }
 
-            TaskViewTransform transform = mLayoutAlgorithm.getStackTransform(task, stackScroll,
-                    taskTransforms.get(i), frontTransform);
-            if (DEBUG) {
-                Log.d(TAG, "updateStackTransform: " + i + ", " + transform.visible);
-            }
             if (transform.visible) {
                 if (frontMostVisibleIndex < 0) {
                     frontMostVisibleIndex = i;
@@ -417,7 +449,9 @@
                     break;
                 }
             }
+
             frontTransform = transform;
+            frontTransformAtTarget = transformAtTarget;
         }
         if (visibleRangeOut != null) {
             visibleRangeOut[0] = frontMostVisibleIndex;
@@ -426,158 +460,275 @@
         return frontMostVisibleIndex != -1 && backMostVisibleIndex != -1;
     }
 
-    /** Synchronizes the views with the model */
-    boolean synchronizeStackViewsWithModel() {
-        if (mStackViewsDirty) {
-            // Get all the task transforms
-            ArrayList<Task> tasks = mStack.getStackTasks();
-            float stackScroll = mStackScroller.getStackScroll();
-            int[] visibleStackRange = mTmpVisibleRange;
-            boolean isValidVisibleStackRange = updateStackTransforms(mCurrentTaskTransforms, tasks,
-                    stackScroll, visibleStackRange);
-            boolean hasStackBackTransform = false;
-            boolean hasStackFrontTransform = false;
-            if (DEBUG) {
-                Log.d(TAG, "visibleRange: " + visibleStackRange[0] + " to " + visibleStackRange[1]);
+    /**
+     * Binds the visible {@link TaskView}s at the given target scroll.
+     *
+     * @see #bindVisibleTaskViews(float, ArraySet<Task.TaskKey>)
+     */
+    void bindVisibleTaskViews(float targetStackScroll) {
+        bindVisibleTaskViews(targetStackScroll, mIgnoreTasks);
+    }
+
+    /**
+     * Synchronizes the set of children {@link TaskView}s to match the visible set of tasks in the
+     * current {@link TaskStack}. This call does not continue on to update their position to the
+     * computed {@link TaskViewTransform}s of the visible range, but only ensures that they will
+     * be added/removed from the view hierarchy and placed in the correct Z order and initial
+     * position (if not currently on screen).
+     *
+     * @param targetStackScroll If provided, will ensure that the set of visible {@link TaskView}s
+     *                          includes those visible at the current stack scroll, and all at the
+     *                          target stack scroll.
+     * @param ignoreTasksSet The set of tasks to ignore in this rebinding of the visible
+     *                       {@link TaskView}s
+     */
+    void bindVisibleTaskViews(float targetStackScroll, ArraySet<Task.TaskKey> ignoreTasksSet) {
+        final int[] visibleStackRange = mTmpVisibleRange;
+
+        // Get all the task transforms
+        final ArrayList<Task> tasks = mStack.getStackTasks();
+        final boolean isValidVisibleRange = computeVisibleTaskTransforms(mCurrentTaskTransforms,
+                tasks, mStackScroller.getStackScroll(), targetStackScroll, visibleStackRange,
+                ignoreTasksSet);
+
+        // Return all the invisible children to the pool
+        mTmpTaskViewMap.clear();
+        List<TaskView> taskViews = getTaskViews();
+        int lastFocusedTaskIndex = -1;
+        int taskViewCount = taskViews.size();
+        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;
             }
 
-            // Return all the invisible children to the pool
-            mTmpTaskViewMap.clear();
-            List<TaskView> taskViews = getTaskViews();
-            int lastFocusedTaskIndex = -1;
-            int taskViewCount = taskViews.size();
-            for (int i = taskViewCount - 1; i >= 0; i--) {
-                TaskView tv = taskViews.get(i);
-                Task task = tv.getTask();
-                int taskIndex = mStack.indexOfStackTask(task);
-                if (task.isFreeformTask() ||
-                        visibleStackRange[1] <= taskIndex && taskIndex <= visibleStackRange[0]) {
-                    mTmpTaskViewMap.put(task, tv);
-                } else {
-                    if (mTouchExplorationEnabled) {
-                        lastFocusedTaskIndex = taskIndex;
-                        resetFocusedTask(task);
-                    }
-                    if (DEBUG) {
-                        Log.d(TAG, "returning to pool: " + task.key);
-                    }
-                    mViewPool.returnViewToPool(tv);
+            if (task.isFreeformTask() ||
+                    visibleStackRange[1] <= taskIndex && taskIndex <= visibleStackRange[0]) {
+                mTmpTaskViewMap.put(task.key, tv);
+            } else {
+                if (mTouchExplorationEnabled) {
+                    lastFocusedTaskIndex = taskIndex;
+                    resetFocusedTask(task);
                 }
+                mViewPool.returnViewToPool(tv);
             }
-
-            // Pick up all the freeform tasks
-            int firstVisStackIndex = isValidVisibleStackRange ? visibleStackRange[0] : 0;
-            for (int i = mStack.getStackTaskCount() - 1; i >= firstVisStackIndex; i--) {
-                Task task = tasks.get(i);
-                if (!task.isFreeformTask()) {
-                    continue;
-                }
-                TaskViewTransform transform = mLayoutAlgorithm.getStackTransform(task, stackScroll,
-                        mCurrentTaskTransforms.get(i), null);
-                TaskView tv = mTmpTaskViewMap.get(task);
-                if (tv == null) {
-                    if (DEBUG) {
-                        Log.d(TAG, "picking up from pool: " + task.key);
-                    }
-                    tv = mViewPool.pickUpViewFromPool(task, task);
-                } else {
-                    // Reattach it in the right z order
-                    int taskIndex = mStack.indexOfStackTask(task);
-                    int insertIndex = findTaskViewInsertIndex(task, taskIndex);
-                    if (insertIndex != getTaskViews().indexOf(tv)){
-                        detachViewFromParent(tv);
-                        attachViewToParent(tv, insertIndex, tv.getLayoutParams());
-                    }
-                }
-
-                // Animate the task into place
-                tv.updateViewPropertiesToTaskTransform(transform, 0,
-                        mStackViewsAnimationDuration, mFastOutSlowInInterpolator,
-                        mRequestUpdateClippingListener);
-
-                // Update the task views list after adding the new task view
-                updateTaskViewsList();
-            }
-
-            // Pick up all the newly visible children and update all the existing children
-            for (int i = visibleStackRange[0];
-                    isValidVisibleStackRange && i >= visibleStackRange[1]; i--) {
-                Task task = tasks.get(i);
-                TaskViewTransform transform = mCurrentTaskTransforms.get(i);
-                TaskView tv = mTmpTaskViewMap.get(task);
-
-                if (tv == null) {
-                    tv = mViewPool.pickUpViewFromPool(task, task);
-                    if (mStackViewsAnimationDuration > 0) {
-                        // For items in the list, put them in start animating them from the
-                        // approriate ends of the list where they are expected to appear
-                        if (Float.compare(transform.p, 0f) <= 0) {
-                            if (!hasStackBackTransform) {
-                                hasStackBackTransform = true;
-                                mLayoutAlgorithm.getStackTransform(
-                                        mLayoutAlgorithm.getStackBackTaskProgress(0f), 0f,
-                                        mTmpStackBackTransform, null);
-                            }
-                            tv.updateViewPropertiesToTaskTransform(mTmpStackBackTransform, 0, 0,
-                                    mFastOutSlowInInterpolator, mRequestUpdateClippingListener);
-                        } else {
-                            if (!hasStackFrontTransform) {
-                                hasStackFrontTransform = true;
-                                mLayoutAlgorithm.getStackTransform(
-                                        mLayoutAlgorithm.getStackFrontTaskProgress(0f), 0f,
-                                        mTmpStackFrontTransform, null);
-                            }
-                            tv.updateViewPropertiesToTaskTransform(mTmpStackFrontTransform, 0, 0,
-                                    mFastOutSlowInInterpolator, mRequestUpdateClippingListener);
-                        }
-                    }
-                }
-
-                // Animate the task into place, the clip for stack tasks will be calculated in
-                // clipTaskViews()
-                tv.updateViewPropertiesToTaskTransform(transform,
-                        tv.getViewBounds().getClipBottom(), mStackViewsAnimationDuration,
-                        mFastOutSlowInInterpolator, mRequestUpdateClippingListener);
-            }
-
-            // 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 /* animated */,
-                            true /* requestViewFocus */);
-                } else {
-                    setFocusedTask(visibleStackRange[0], false /* animated */,
-                            true /* requestViewFocus */);
-                }
-            }
-
-            // Reset the request-synchronize params
-            mStackViewsAnimationDuration = 0;
-            mStackViewsDirty = false;
-            mStackViewsClipDirty = true;
-            return true;
         }
-        return false;
+
+        // Pick up all the newly visible children
+        int lastVisStackIndex = isValidVisibleRange ? visibleStackRange[1] : 0;
+        for (int i = tasks.size() - 1; i >= lastVisStackIndex; i--) {
+            Task task = tasks.get(i);
+            TaskViewTransform transform = mCurrentTaskTransforms.get(i);
+
+            // Skip ignored tasks
+            if (ignoreTasksSet.contains(task.key)) {
+                continue;
+            }
+
+            // Skip the invisible non-freeform stack tasks
+            if (i > visibleStackRange[0] && !task.isFreeformTask()) {
+                continue;
+            }
+
+            TaskView tv = mTmpTaskViewMap.get(task.key);
+            if (tv == null) {
+                tv = mViewPool.pickUpViewFromPool(task, task);
+                if (task.isFreeformTask()) {
+                    tv.updateViewPropertiesToTaskTransform(transform, TaskViewAnimation.IMMEDIATE,
+                            mRequestUpdateClippingListener);
+                } else {
+                    if (Float.compare(transform.p, 0f) <= 0) {
+                        tv.updateViewPropertiesToTaskTransform(
+                                mLayoutAlgorithm.getBackOfStackTransform(),
+                                TaskViewAnimation.IMMEDIATE, mRequestUpdateClippingListener);
+                    } else {
+                        tv.updateViewPropertiesToTaskTransform(
+                                mLayoutAlgorithm.getFrontOfStackTransform(),
+                                TaskViewAnimation.IMMEDIATE, mRequestUpdateClippingListener);
+                    }
+                }
+            } else {
+                // Reattach it in the right z order
+                final int taskIndex = mStack.indexOfStackTask(task);
+                final int insertIndex = findTaskViewInsertIndex(task, taskIndex);
+                if (insertIndex != getTaskViews().indexOf(tv)){
+                    detachViewFromParent(tv);
+                    attachViewToParent(tv, insertIndex, tv.getLayoutParams());
+                    updateTaskViewsList();
+                }
+            }
+        }
+
+        // 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 */,
+                        true /* requestViewFocus */);
+            } else {
+                setFocusedTask(visibleStackRange[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(TaskViewAnimation, ArraySet<Task.TaskKey>)
+     */
+    void relayoutTaskViews(TaskViewAnimation animation) {
+        relayoutTaskViews(animation, mIgnoreTasks);
+    }
+
+    /**
+     * 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.
+     *
+     * @param ignoreTasksSet the set of tasks to ignore in the relayout
+     */
+    void relayoutTaskViews(TaskViewAnimation animation, ArraySet<Task.TaskKey> ignoreTasksSet) {
+        // 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);
+
+        // 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);
+
+            if (ignoreTasksSet.contains(tv.getTask().key)) {
+                continue;
+            }
+
+            updateTaskViewToTransform(tv, transform, animation);
+        }
+    }
+
+    /**
+     * Posts an update to synchronize the {@link TaskView}s with the stack on the next frame.
+     */
+    void relayoutTaskViewsOnNextFrame(TaskViewAnimation animation) {
+        mDeferredTaskViewLayoutAnimation = animation;
+        invalidate();
+    }
+
+    /**
+     * Called to update a specific {@link TaskView} to a given {@link TaskViewTransform} with a
+     * given set of {@link TaskViewAnimation} properties.
+     */
+    public void updateTaskViewToTransform(TaskView taskView, TaskViewTransform transform,
+            TaskViewAnimation animation) {
+        taskView.updateViewPropertiesToTaskTransform(transform, animation,
+                mRequestUpdateClippingListener);
+    }
+
+    /**
+     * Returns the current task transforms of all tasks, falling back to the stack layout if there
+     * is no {@link TaskView} for the task.
+     */
+    public void getCurrentTaskTransforms(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);
+            TaskView tv = getChildViewForTask(task);
+            if (tv != null) {
+                transform.fillIn(tv);
+            } else {
+                mLayoutAlgorithm.getStackTransform(task, mStackScroller.getStackScroll(),
+                        transform, null);
+            }
+            transform.visible = true;
+        }
+    }
+
+    /**
+     * Returns the task transforms for all the tasks in the stack if the stack was at the given
+     * {@param stackScroll}.
+     */
+    public void getLayoutTaskTransforms(float stackScroll, 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, transform, null);
+            transform.visible = true;
+        }
+    }
+
+    /**
+     * Cancels all {@link TaskView} animations.
+     *
+     * @see #cancelAllTaskViewAnimations(ArraySet<Task.TaskKey>)
+     */
+    void cancelAllTaskViewAnimations() {
+        cancelAllTaskViewAnimations(mIgnoreTasks);
+    }
+
+    /**
+     * Cancels all {@link TaskView} animations.
+     *
+     * @param ignoreTasksSet The set of tasks to continue running their animations.
+     */
+    void cancelAllTaskViewAnimations(ArraySet<Task.TaskKey> ignoreTasksSet) {
+        List<TaskView> taskViews = getTaskViews();
+        for (int i = taskViews.size() - 1; i >= 0; i--) {
+            final TaskView tv = taskViews.get(i);
+            if (!ignoreTasksSet.contains(tv.getTask().key)) {
+                tv.cancelTransformAnimation();
+            }
+        }
     }
 
     /**
      * Updates the clip for each of the task views from back to front.
      */
-    void clipTaskViews(boolean forceUpdate) {
+    private void clipTaskViews() {
         RecentsConfiguration config = Recents.getConfiguration();
 
         // Update the clip on each task child
         List<TaskView> taskViews = getTaskViews();
         TaskView tmpTv = null;
+        TaskView prevVisibleTv = null;
         int taskViewCount = taskViews.size();
         for (int i = 0; i < taskViewCount; i++) {
             TaskView tv = taskViews.get(i);
             TaskView frontTv = null;
             int clipBottom = 0;
+
+            if (mIgnoreTasks.contains(tv.getTask().key)) {
+                // For each of the ignore tasks, update the translationZ of its TaskView to be
+                // between the translationZ of the tasks immediately underneath it
+                if (prevVisibleTv != null) {
+                    tv.setTranslationZ(Math.max(tv.getTranslationZ(),
+                            prevVisibleTv.getTranslationZ() + 0.1f));
+                }
+            }
+
             if (i < (taskViewCount - 1) && tv.shouldClipViewInStack()) {
                 // Find the next view to clip against
                 for (int j = i + 1; j < taskViewCount; j++) {
                     tmpTv = taskViews.get(j);
+
                     if (tmpTv.shouldClipViewInStack()) {
                         frontTv = tmpTv;
                         break;
@@ -596,27 +747,41 @@
                     }
                 }
             }
-            tv.getViewBounds().setClipBottom(clipBottom, forceUpdate);
+            tv.getViewBounds().setClipBottom(clipBottom);
             if (!config.useHardwareLayers) {
                 tv.mThumbnailView.updateThumbnailVisibility(clipBottom - tv.getPaddingBottom());
             }
+            prevVisibleTv = tv;
         }
-        mStackViewsClipDirty = false;
+        mTaskViewsClipDirty = false;
     }
 
-    /** Updates the min and max virtual scroll bounds */
-    void updateLayout(boolean boundScrollToNewMinMax) {
-        // Compute the min and max scroll values
-        mLayoutAlgorithm.update(mStack);
+    /**
+     * Updates the layout algorithm min and max virtual scroll bounds.
+     *
+     * @see #updateLayoutAlgorithm(boolean, ArraySet<Task.TaskKey>)
+     */
+    void updateLayoutAlgorithm(boolean boundScrollToNewMinMax) {
+        updateLayoutAlgorithm(boundScrollToNewMinMax, mIgnoreTasks);
+    }
 
-        // Update the freeform workspace
+    /**
+     * Updates the min and max virtual scroll bounds.
+     *
+     * @param ignoreTasksSet the set of tasks to ignore in the relayout
+     */
+    void updateLayoutAlgorithm(boolean boundScrollToNewMinMax,
+            ArraySet<Task.TaskKey> ignoreTasksSet) {
+        // Compute the min and max scroll values
+        mLayoutAlgorithm.update(mStack, ignoreTasksSet);
+
+        // Update the freeform workspace background
         SystemServicesProxy ssp = Recents.getSystemServices();
         if (ssp.hasFreeformWorkspaceSupport()) {
             mTmpRect.set(mLayoutAlgorithm.mFreeformRect);
             mFreeformWorkspaceBackground.setBounds(mTmpRect);
         }
 
-        // Debug logging
         if (boundScrollToNewMinMax) {
             mStackScroller.boundScroll();
         }
@@ -632,8 +797,9 @@
      *
      * @return whether or not the stack will scroll as a part of this focus change
      */
-    private boolean setFocusedTask(int taskIndex, boolean scrollToTask, final boolean animated) {
-        return setFocusedTask(taskIndex, scrollToTask, animated, true);
+    private boolean setFocusedTask(int taskIndex, boolean scrollToTask,
+            final boolean requestViewFocus) {
+        return setFocusedTask(taskIndex, scrollToTask, requestViewFocus, 0);
     }
 
     /**
@@ -641,47 +807,65 @@
      *
      * @return whether or not the stack will scroll as a part of this focus change
      */
-    private boolean setFocusedTask(int taskIndex, boolean scrollToTask, final boolean animated,
-            final boolean requestViewFocus) {
+    private boolean setFocusedTask(int taskIndex, boolean scrollToTask,
+            final boolean requestViewFocus, final int timerIndicatorDuration) {
         // Find the next task to focus
-        int newFocusedTaskIndex = mStack.getStackTaskCount() > 0 ?
-                Math.max(0, Math.min(mStack.getStackTaskCount() - 1, taskIndex)) : -1;
+        int newFocusedTaskIndex = mStack.getTaskCount() > 0 ?
+                Math.max(0, Math.min(mStack.getTaskCount() - 1, taskIndex)) : -1;
         final Task newFocusedTask = (newFocusedTaskIndex != -1) ?
                 mStack.getStackTasks().get(newFocusedTaskIndex) : null;
 
         // Reset the last focused task state if changed
         if (mFocusedTask != null) {
+            // Cancel the timer indicator, if applicable
+            if (timerIndicatorDuration > 0) {
+                final TaskView tv = getChildViewForTask(mFocusedTask);
+                if (tv != null) {
+                    tv.getHeaderView().cancelFocusTimerIndicator();
+                }
+            }
+
             resetFocusedTask(mFocusedTask);
         }
 
         boolean willScroll = false;
+
         mFocusedTask = newFocusedTask;
+
         if (newFocusedTask != null) {
+            // Start the timer indicator, if applicable
+            if (timerIndicatorDuration > 0) {
+                final TaskView tv = getChildViewForTask(mFocusedTask);
+                if (tv != null) {
+                    tv.getHeaderView().startFocusTimerIndicator(timerIndicatorDuration);
+                } else {
+                    // The view is null; set a flag for later
+                    mStartTimerIndicatorDuration = timerIndicatorDuration;
+                }
+            }
+
             Runnable focusTaskRunnable = new Runnable() {
                 @Override
                 public void run() {
-                    TaskView tv = getChildViewForTask(newFocusedTask);
+                    final TaskView tv = getChildViewForTask(newFocusedTask);
                     if (tv != null) {
-                        tv.setFocusedState(true, animated, requestViewFocus);
+                        tv.setFocusedState(true, requestViewFocus);
                     }
                 }
             };
 
             if (scrollToTask) {
+                // Cancel any running enter animations at this point when we scroll or change focus
+                if (!mEnterAnimationComplete) {
+                    cancelAllTaskViewAnimations();
+                }
+
                 // TODO: Center the newly focused task view, only if not freeform
                 float newScroll = mLayoutAlgorithm.getStackScrollForTask(newFocusedTask);
                 if (Float.compare(newScroll, mStackScroller.getStackScroll()) != 0) {
                     mStackScroller.animateScroll(mStackScroller.getStackScroll(), newScroll,
                             focusTaskRunnable);
                     willScroll = true;
-
-                    // Cancel any running enter animations at this point when we scroll as well
-                    if (!mEnterAnimationComplete) {
-                        final List<TaskView> taskViews = getTaskViews();
-                        for (TaskView tv : taskViews) {
-                            tv.cancelEnterRecentsAnimation();
-                        }
-                    }
                 } else {
                     focusTaskRunnable.run();
                 }
@@ -717,10 +901,29 @@
      * @param animated determines whether to actually draw the highlight along with the change in
      *                            focus.
      * @param cancelWindowAnimations if set, will attempt to cancel window animations if a scroll
-     *                               happens
+     *                               happens.
      */
     public void setRelativeFocusedTask(boolean forward, boolean stackTasksOnly, boolean animated,
                                        boolean cancelWindowAnimations) {
+        setRelativeFocusedTask(forward, stackTasksOnly, animated, cancelWindowAnimations, 0);
+    }
+
+    /**
+     * Sets the focused task relative to the currently focused task.
+     *
+     * @param forward whether to go to the next task in the stack (along the curve) or the previous
+     * @param stackTasksOnly if set, will ensure that the traversal only goes along stack tasks, and
+     *                       if the currently focused task is not a stack task, will set the focus
+     *                       to the first visible stack task
+     * @param animated determines whether to actually draw the highlight along with the change in
+     *                            focus.
+     * @param cancelWindowAnimations if set, will attempt to cancel window animations if a scroll
+     *                               happens.
+     * @param timerIndicatorDuration the duration to initialize the auto-advance timer indicator
+     */
+    public void setRelativeFocusedTask(boolean forward, boolean stackTasksOnly, boolean animated,
+                                       boolean cancelWindowAnimations,
+                                       int timerIndicatorDuration) {
         int newIndex = mStack.indexOfStackTask(mFocusedTask);
         if (mFocusedTask != null) {
             if (stackTasksOnly) {
@@ -744,7 +947,7 @@
             } else {
                 // No restrictions, lets just move to the new task (looping forward/backwards if
                 // necessary)
-                int taskCount = mStack.getStackTaskCount();
+                int taskCount = mStack.getTaskCount();
                 newIndex = (newIndex + (forward ? -1 : 1) + taskCount) % taskCount;
             }
         } else {
@@ -755,7 +958,8 @@
             }
         }
         if (newIndex != -1) {
-            boolean willScroll = setFocusedTask(newIndex, true, animated);
+            boolean willScroll = setFocusedTask(newIndex, true /* scrollToTask */,
+                    true /* requestViewFocus */, timerIndicatorDuration);
             if (willScroll && cancelWindowAnimations) {
                 // As we iterate to the next/previous task, cancel any current/lagging window
                 // transition animations
@@ -771,7 +975,7 @@
         if (task != null) {
             TaskView tv = getChildViewForTask(task);
             if (tv != null) {
-                tv.setFocusedState(false, false /* animated */, false /* requestViewFocus */);
+                tv.setFocusedState(false, false /* requestViewFocus */);
             }
         }
         mFocusedTask = null;
@@ -794,9 +998,9 @@
             TaskView frontMostTask = taskViews.get(taskViewCount - 1);
             event.setFromIndex(mStack.indexOfStackTask(backMostTask.getTask()));
             event.setToIndex(mStack.indexOfStackTask(frontMostTask.getTask()));
-            event.setContentDescription(frontMostTask.getTask().activityLabel);
+            event.setContentDescription(frontMostTask.getTask().title);
         }
-        event.setItemCount(mStack.getStackTaskCount());
+        event.setItemCount(mStack.getTaskCount());
         event.setScrollY(mStackScroller.mScroller.getCurrY());
         event.setMaxScrollY(mStackScroller.progressToScrollRange(mLayoutAlgorithm.mMaxScrollP));
     }
@@ -812,7 +1016,7 @@
             if (focusedTaskIndex > 0) {
                 info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
             }
-            if (focusedTaskIndex < mStack.getStackTaskCount() - 1) {
+            if (focusedTaskIndex < mStack.getTaskCount() - 1) {
                 info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
             }
         }
@@ -876,22 +1080,18 @@
 
     @Override
     public void computeScroll() {
-        mStackScroller.computeScroll();
-        // Synchronize the views
-        synchronizeStackViewsWithModel();
-        clipTaskViews(false /* forceUpdate */);
-        // Notify accessibility
-        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED);
-    }
-
-    /** Computes the stack and task rects */
-    public void computeRects(Rect taskStackBounds) {
-        // Compute the rects in the stack algorithm
-        mLayoutAlgorithm.initialize(taskStackBounds,
-                TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
-
-        // Update the scroll bounds
-        updateLayout(false);
+        if (mStackScroller.computeScroll()) {
+            // Notify accessibility
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED);
+        }
+        if (mDeferredTaskViewLayoutAnimation != null) {
+            relayoutTaskViews(mDeferredTaskViewLayoutAnimation);
+            mTaskViewsClipDirty = true;
+            mDeferredTaskViewLayoutAnimation = null;
+        }
+        if (mTaskViewsClipDirty) {
+            clipTaskViews();
+        }
     }
 
     /**
@@ -900,20 +1100,37 @@
      */
     public void updateLayoutForStack(TaskStack stack) {
         mStack = stack;
-        updateLayout(false);
+        updateLayoutAlgorithm(false /* boundScroll */, EMPTY_TASK_SET);
     }
 
     /**
-     * Computes the maximum number of visible tasks and thumbnails.  Requires that
+     * Computes the maximum number of visible tasks and thumbnails. Requires that
      * updateLayoutForStack() is called first.
      */
     public TaskStackLayoutAlgorithm.VisibilityReport computeStackVisibilityReport() {
         return mLayoutAlgorithm.computeStackVisibilityReport(mStack.getStackTasks());
     }
 
+    /**
+     * Updates the expected task stack bounds for this stack view.
+     */
     public void setTaskStackBounds(Rect taskStackBounds, Rect systemInsets) {
-        mTaskStackBounds.set(taskStackBounds);
-        mLayoutAlgorithm.setSystemInsets(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;
+        }
+        if (!systemInsets.equals(mLayoutAlgorithm.mSystemInsets)) {
+            mLayoutAlgorithm.setSystemInsets(systemInsets);
+            requiresLayout = true;
+        }
+        if (requiresLayout) {
+            requestLayout();
+        }
     }
 
     /**
@@ -925,16 +1142,18 @@
         int width = MeasureSpec.getSize(widthMeasureSpec);
         int height = MeasureSpec.getSize(heightMeasureSpec);
 
-        // Compute our stack/task rects
-        computeRects(mTaskStackBounds);
+        // Compute the rects in the stack algorithm
+        mLayoutAlgorithm.initialize(mStackBounds,
+                TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
+        updateLayoutAlgorithm(false /* boundScroll */, EMPTY_TASK_SET);
 
-        // If this is the first layout, then scroll to the front of the stack and synchronize the
-        // stack views immediately to load all the views
+        // 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();
-            requestSynchronizeStackViewsWithModel();
-            synchronizeStackViewsWithModel();
         }
+        // Rebind all the views, including the ignore ones
+        bindVisibleTaskViews(mStackScroller.getStackScroll(), EMPTY_TASK_SET);
 
         // Measure each of the TaskViews
         mTmpTaskViews.clear();
@@ -984,54 +1203,26 @@
                     taskRect.right + mTmpRect.right, taskRect.bottom + mTmpRect.bottom);
         }
 
-        if (mAwaitingFirstLayout) {
-            mAwaitingFirstLayout = false;
-            onFirstLayout();
-        }
-
-        requestSynchronizeStackViewsWithModel();
         if (changed) {
             if (mStackScroller.isScrollOutOfBounds()) {
                 mStackScroller.boundScroll();
             }
-            synchronizeStackViewsWithModel();
-            requestUpdateStackViewsClip();
-            clipTaskViews(true /* forceUpdate */);
+        }
+        // Relayout all of the task views including the ignored ones
+        relayoutTaskViews(TaskViewAnimation.IMMEDIATE, EMPTY_TASK_SET);
+        clipTaskViews();
+
+        if (mAwaitingFirstLayout || !mEnterAnimationComplete) {
+            mAwaitingFirstLayout = false;
+            onFirstLayout();
+            return;
         }
     }
 
     /** Handler for the first layout. */
     void onFirstLayout() {
-        int offscreenY = mLayoutAlgorithm.mStackRect.bottom;
-
-        // Find the launch target task
-        Task launchTargetTask = mStack.getLaunchTarget();
-        List<TaskView> taskViews = getTaskViews();
-        int taskViewCount = taskViews.size();
-
-        // Prepare the first view for its enter animation
-        for (int i = taskViewCount - 1; i >= 0; i--) {
-            TaskView tv = taskViews.get(i);
-            Task task = tv.getTask();
-            boolean hideTask = false;
-            boolean occludesLaunchTarget = false;
-            if (launchTargetTask != null) {
-                occludesLaunchTarget = launchTargetTask.group.isTaskAboveTask(task,
-                        launchTargetTask);
-                hideTask = SystemServicesProxy.isFreeformStack(launchTargetTask.key.stackId) &&
-                        SystemServicesProxy.isFreeformStack(task.key.stackId);
-            }
-            tv.prepareEnterRecentsAnimation(task.isLaunchTarget, hideTask, occludesLaunchTarget,
-                    offscreenY);
-        }
-
-        // If the enter animation started already and we haven't completed a layout yet, do the
-        // enter animation now
-        if (mStartEnterAnimationRequestedAfterLayout) {
-            startEnterRecentsAnimation(mStartEnterAnimationContext);
-            mStartEnterAnimationRequestedAfterLayout = false;
-            mStartEnterAnimationContext = null;
-        }
+        // Setup the view for the enter animation
+        mAnimationHelper.prepareForEnterAnimation();
 
         // Animate in the freeform workspace
         animateFreeformWorkspaceBackgroundAlpha(
@@ -1040,126 +1231,48 @@
 
         // Set the task focused state without requesting view focus, and leave the focus animations
         // until after the enter-animation
+        Task launchTask = mStack.getLaunchTarget();
         RecentsConfiguration config = Recents.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
-        int focusedTaskIndex = launchState.getInitialFocusTaskIndex(mStack.getStackTaskCount());
+        int focusedTaskIndex = launchState.getInitialFocusTaskIndex(mStack.getTaskCount());
         if (focusedTaskIndex != -1) {
-            setFocusedTask(focusedTaskIndex, false /* scrollToTask */, false /* animated */,
+            setFocusedTask(focusedTaskIndex, false /* scrollToTask */,
                     false /* requestViewFocus */);
         }
 
         // Update the history button visibility
         if (shouldShowHistoryButton() &&
                 mStackScroller.getStackScroll() < SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD) {
-            EventBus.getDefault().send(new ShowHistoryButtonEvent());
+            EventBus.getDefault().send(new ShowHistoryButtonEvent(false /* translate */));
         } else {
             EventBus.getDefault().send(new HideHistoryButtonEvent());
         }
-
-        // Start dozing
-        mUIDozeTrigger.startDozing();
     }
 
-    /** Requests this task stacks to start it's enter-recents animation */
-    public void startEnterRecentsAnimation(ViewAnimation.TaskViewEnterContext ctx) {
-        // If we are still waiting to layout, then just defer until then
-        if (mAwaitingFirstLayout) {
-            mStartEnterAnimationRequestedAfterLayout = true;
-            mStartEnterAnimationContext = ctx;
-            return;
-        }
+    public boolean isTouchPointInView(float x, float y, TaskView tv) {
+        mTmpRect.set(tv.getLeft(), tv.getTop(), tv.getRight(), tv.getBottom());
+        mTmpRect.offset((int) tv.getTranslationX(), (int) tv.getTranslationY());
+        return mTmpRect.contains((int) x, (int) y);
+    }
 
-        if (mStack.getStackTaskCount() > 0) {
-            // Find the launch target task
-            Task launchTargetTask = mStack.getLaunchTarget();
-            List<TaskView> taskViews = getTaskViews();
-            int taskViewCount = taskViews.size();
+    /**
+     * Returns a non-ignored task in the {@param tasks} list that can be used as an achor when
+     * calculating the scroll position before and after a layout change.
+     */
+    public Task findAnchorTask(List<Task> tasks, MutableBoolean isFrontMostTask) {
+        for (int i = tasks.size() - 1; i >= 0; i--) {
+            Task task = tasks.get(i);
 
-            // Animate all the task views into view
-            for (int i = taskViewCount - 1; i >= 0; i--) {
-                TaskView tv = taskViews.get(i);
-                Task task = tv.getTask();
-                ctx.currentTaskTransform = new TaskViewTransform();
-                ctx.currentStackViewIndex = i;
-                ctx.currentStackViewCount = taskViewCount;
-                ctx.currentTaskRect = mLayoutAlgorithm.mTaskRect;
-                ctx.currentTaskOccludesLaunchTarget = (launchTargetTask != null) &&
-                        launchTargetTask.group.isTaskAboveTask(task, launchTargetTask);
-                ctx.updateListener = mRequestUpdateClippingListener;
-                mLayoutAlgorithm.getStackTransform(task, mStackScroller.getStackScroll(),
-                        ctx.currentTaskTransform, null);
-                tv.startEnterRecentsAnimation(ctx);
-            }
-
-            // Add a runnable to the post animation ref counter to clear all the views
-            ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
-                @Override
-                public void run() {
-                    // Poke the dozer to restart the trigger after the animation completes
-                    mUIDozeTrigger.poke();
-
-                    // Update the focused state here -- since we only set the focused task without
-                    // requesting view focus in onFirstLayout(), actually request view focus and
-                    // animate the focused state if we are alt-tabbing now, after the window enter
-                    // animation is completed
-                    if (mFocusedTask != null) {
-                        RecentsConfiguration config = Recents.getConfiguration();
-                        RecentsActivityLaunchState launchState = config.getLaunchState();
-                        setFocusedTask(mStack.indexOfStackTask(mFocusedTask),
-                                false /* scrollToTask */, launchState.launchedWithAltTab);
-                    }
+            // Ignore deleting tasks
+            if (mIgnoreTasks.contains(task.key)) {
+                if (i == tasks.size() - 1) {
+                    isFrontMostTask.value = true;
                 }
-            });
-        }
-    }
-
-    /** Requests this task stack to start it's exit-recents animation. */
-    public void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
-        // Stop any scrolling
-        mStackScroller.stopScroller();
-        mStackScroller.stopBoundScrollAnimation();
-        // Animate all the task views out of view
-        ctx.offscreenTranslationY = mLayoutAlgorithm.mStackRect.bottom;
-        // Dismiss the freeform workspace background
-        int taskViewExitToHomeDuration = getResources().getInteger(
-                R.integer.recents_task_exit_to_home_duration);
-        animateFreeformWorkspaceBackgroundAlpha(0, taskViewExitToHomeDuration,
-                mFastOutSlowInInterpolator);
-
-        List<TaskView> taskViews = getTaskViews();
-        int taskViewCount = taskViews.size();
-        for (int i = 0; i < taskViewCount; i++) {
-            TaskView tv = taskViews.get(i);
-            tv.startExitToHomeAnimation(ctx);
-        }
-    }
-
-    /** Animates a task view in this stack as it launches. */
-    public void startLaunchTaskAnimation(TaskView tv, Runnable r, boolean lockToTask) {
-        Task launchTargetTask = tv.getTask();
-        List<TaskView> taskViews = getTaskViews();
-        int taskViewCount = taskViews.size();
-        for (int i = 0; i < taskViewCount; i++) {
-            TaskView t = taskViews.get(i);
-            if (t == tv) {
-                t.setClipViewInStack(false);
-                t.startLaunchTaskAnimation(r, true, true, lockToTask);
-            } else {
-                boolean occludesLaunchTarget = launchTargetTask.group.isTaskAboveTask(t.getTask(),
-                        launchTargetTask);
-                t.startLaunchTaskAnimation(null, false, occludesLaunchTarget, lockToTask);
+                continue;
             }
+            return task;
         }
-    }
-
-    public boolean isTransformedTouchPointInView(float x, float y, TaskView tv) {
-        final float[] point = new float[2];
-        point[0] = x;
-        point[1] = y;
-        transformPointToViewLocal(point, tv);
-        x = point[0];
-        y = point[1];
-        return (0 <= x) && (x < tv.getWidth()) && (0 <= y) && (y < tv.getHeight());
+        return null;
     }
 
     @Override
@@ -1187,11 +1300,14 @@
      * Launches the freeform tasks.
      */
     public boolean launchFreeformTasks() {
-        Task frontTask = mStack.getStackFrontMostTask();
-        if (frontTask != null && frontTask.isFreeformTask()) {
-            EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(frontTask),
-                    frontTask, null, INVALID_STACK_ID, false));
-            return true;
+        ArrayList<Task> tasks = mStack.getFreeformTasks();
+        if (!tasks.isEmpty()) {
+            Task frontTask = tasks.get(tasks.size() - 1);
+            if (frontTask != null && frontTask.isFreeformTask()) {
+                EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(frontTask),
+                        frontTask, null, INVALID_STACK_ID, false));
+                return true;
+            }
         }
         return false;
     }
@@ -1199,88 +1315,58 @@
     /**** TaskStackCallbacks Implementation ****/
 
     @Override
+    public void onStackTaskAdded(TaskStack stack, Task newTask) {
+        // Update the min/max scroll and animate other task views into their new positions
+        updateLayoutAlgorithm(true /* boundScroll */);
+
+        // Animate all the tasks into place
+        relayoutTaskViews(new TaskViewAnimation(DEFAULT_SYNC_STACK_DURATION,
+                mFastOutSlowInInterpolator));
+    }
+
+    /**
+     * We expect that the {@link TaskView} associated with the removed task is already hidden.
+     */
+    @Override
     public void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
-            Task newFrontMostTask) {
+            Task newFrontMostTask, TaskViewAnimation animation) {
         if (mFocusedTask == removedTask) {
             resetFocusedTask(removedTask);
         }
 
-        if (!removedTask.isFreeformTask()) {
-            // Remove the view associated with this task, we can't rely on updateTransforms
-            // to work here because the task is no longer in the list
-            TaskView tv = getChildViewForTask(removedTask);
-            if (tv != null) {
-                mViewPool.returnViewToPool(tv);
-            }
-
-            // Get the stack scroll of the task to anchor to (since we are removing something, the
-            // front most task will be our anchor task)
-            Task anchorTask = null;
-            float prevAnchorTaskScroll = 0;
-            boolean pullStackForward = stack.getStackTaskCount() > 0;
-            if (pullStackForward) {
-                anchorTask = mStack.getStackFrontMostTask();
-                prevAnchorTaskScroll = mLayoutAlgorithm.getStackScrollForTask(anchorTask);
-            }
-
-            // Update the min/max scroll and animate other task views into their new positions
-            updateLayout(true);
-
-            if (wasFrontMostTask) {
-                // Since the max scroll progress is offset from the bottom of the stack, just scroll
-                // to ensure that the new front most task is now fully visible
-                mStackScroller.setStackScroll(mLayoutAlgorithm.mMaxScrollP);
-            } else if (pullStackForward) {
-                // Otherwise, offset the scroll by the movement of the anchor task
-                float anchorTaskScroll = mLayoutAlgorithm.getStackScrollForTask(anchorTask);
-                float stackScrollOffset = (anchorTaskScroll - prevAnchorTaskScroll);
-                if (mLayoutAlgorithm.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;
-                }
-                mStackScroller.setStackScroll(mStackScroller.getStackScroll() + stackScrollOffset);
-                mStackScroller.boundScroll();
-            }
-
-            // Animate all the tasks into place
-            requestSynchronizeStackViewsWithModel(200);
-        } else {
-            // Remove the view associated with this task, we can't rely on updateTransforms
-            // to work here because the task is no longer in the list
-            TaskView tv = getChildViewForTask(removedTask);
-            if (tv != null) {
-                mViewPool.returnViewToPool(tv);
-            }
-
-            // Update the min/max scroll and animate other task views into their new positions
-            updateLayout(true);
-
-            // Animate all the tasks into place
-            requestSynchronizeStackViewsWithModel(200);
+        // Remove the view associated with this task, we can't rely on updateTransforms
+        // to work here because the task is no longer in the list
+        TaskView tv = getChildViewForTask(removedTask);
+        if (tv != null) {
+            mViewPool.returnViewToPool(tv);
         }
 
-        // Update the new front most task
-        if (newFrontMostTask != null) {
+        // Remove the task from the ignored set
+        removeIgnoreTask(removedTask);
+
+        // If requested, relayout with the given animation
+        if (animation != null) {
+            updateLayoutAlgorithm(true /* boundScroll */);
+            relayoutTaskViews(animation);
+        }
+
+        // Update the new front most task's action button
+        if (mScreenPinningEnabled && newFrontMostTask != null) {
             TaskView frontTv = getChildViewForTask(newFrontMostTask);
             if (frontTv != null) {
-                frontTv.onTaskBound(newFrontMostTask);
-                frontTv.fadeInActionButton(getResources().getInteger(
-                        R.integer.recents_task_enter_from_app_duration));
+                frontTv.showActionButton(true /* fadeIn */, DEFAULT_SYNC_STACK_DURATION);
             }
         }
 
         // If there are no remaining tasks, then just close recents
-        if (mStack.getStackTaskCount() == 0) {
-            boolean shouldFinishActivity = (mStack.getStackTaskCount() == 0);
-            if (shouldFinishActivity) {
-                EventBus.getDefault().send(new AllTaskViewsDismissedEvent());
-            }
+        if (mStack.getTaskCount() == 0) {
+            EventBus.getDefault().send(new AllTaskViewsDismissedEvent());
         }
     }
 
     @Override
-    public void onHistoryTaskRemoved(TaskStack stack, Task removedTask) {
+    public void onHistoryTaskRemoved(TaskStack stack, Task removedTask,
+            TaskViewAnimation animation) {
         // To be implemented
     }
 
@@ -1293,41 +1379,27 @@
 
     @Override
     public void prepareViewToEnterPool(TaskView tv) {
-        Task task = tv.getTask();
+        final Task task = tv.getTask();
 
         // Report that this tasks's data is no longer being used
         Recents.getTaskLoader().unloadTaskData(task);
 
+        // Reset the view properties and view state
+        tv.resetViewProperties();
+        tv.setFocusedState(false, false /* requestViewFocus */);
+        tv.setClipViewInStack(false);
+        if (mScreenPinningEnabled) {
+            tv.hideActionButton(false /* fadeOut */, 0 /* duration */, false /* scaleDown */, null);
+        }
+
         // Detach the view from the hierarchy
         detachViewFromParent(tv);
         // Update the task views list after removing the task view
         updateTaskViewsList();
-
-        // Reset the view properties
-        tv.resetViewProperties();
-
-        // Reset the focused view state
-        tv.setFocusedState(false, false /* animated */, false /* requestViewFocus */);
-
-        // Reset the clip state of the task view
-        tv.setClipViewInStack(false);
     }
 
     @Override
     public void prepareViewToLeavePool(TaskView tv, Task task, boolean isNewView) {
-        // It is possible for a view to be returned to the view pool before it is laid out,
-        // which means that we will need to relayout the view when it is first used next.
-        boolean requiresRelayout = tv.getWidth() <= 0 && !isNewView;
-
-        // 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);
-
-        // If the doze trigger has already fired, then update the state for this task view
-        tv.setNoUserInteractionState();
-
         // Find the index where this task should be placed in the stack
         int taskIndex = mStack.indexOfStackTask(task);
         int insertIndex = findTaskViewInsertIndex(task, taskIndex);
@@ -1337,19 +1409,36 @@
             addView(tv, insertIndex);
         } else {
             attachViewToParent(tv, insertIndex, tv.getLayoutParams());
-            if (requiresRelayout) {
-                tv.requestLayout();
-            }
         }
         // 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 */);
+
+        // If the doze trigger has already fired, then update the state for this task view
+        tv.setNoUserInteractionState();
+
         // Set the new state for this view, including the callbacks and view clipping
         tv.setCallbacks(this);
         tv.setTouchEnabled(true);
         tv.setClipViewInStack(true);
         if (mFocusedTask == task) {
-            tv.setFocusedState(true, false /* animated */, false /* requestViewFocus */);
+            tv.setFocusedState(true, false /* requestViewFocus */);
+            if (mStartTimerIndicatorDuration > 0) {
+                // The timer indicator couldn't be started before, so start it now
+                tv.getHeaderView().startFocusTimerIndicator(mStartTimerIndicatorDuration);
+                mStartTimerIndicatorDuration = 0;
+            }
+        }
+
+        // Restore the action button visibility if it is the front most task view
+        if (mScreenPinningEnabled && tv.getTask() ==
+                mStack.getStackFrontMostTask(false /* includeFreeform */)) {
+            tv.showActionButton(false /* fadeIn */, 0 /* fadeInDuration */);
         }
     }
 
@@ -1362,24 +1451,40 @@
 
     @Override
     public void onTaskViewClipStateChanged(TaskView tv) {
-        requestUpdateStackViewsClip();
+        if (!mTaskViewsClipDirty) {
+            mTaskViewsClipDirty = true;
+            invalidate();
+        }
+    }
+
+    /**** TaskStackLayoutAlgorithm.TaskStackLayoutAlgorithmCallbacks ****/
+
+    @Override
+    public void onFocusStateChanged(float prevFocusState, float curFocusState) {
+        if (mDeferredTaskViewLayoutAnimation == null) {
+            mUIDozeTrigger.poke();
+            relayoutTaskViewsOnNextFrame(TaskViewAnimation.IMMEDIATE);
+        }
     }
 
     /**** TaskStackViewScroller.TaskStackViewScrollerCallbacks ****/
 
     @Override
-    public void onScrollChanged(float prevScroll, float curScroll) {
+    public void onScrollChanged(float prevScroll, float curScroll, TaskViewAnimation animation) {
         mUIDozeTrigger.poke();
-        requestSynchronizeStackViewsWithModel();
-        postInvalidateOnAnimation();
+        if (animation != null) {
+            relayoutTaskViewsOnNextFrame(animation);
+        }
 
-        if (shouldShowHistoryButton() &&
-                prevScroll > SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD &&
-                curScroll <= SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD) {
-            EventBus.getDefault().send(new ShowHistoryButtonEvent());
-        } else if (prevScroll < HIDE_HISTORY_BUTTON_SCROLL_THRESHOLD &&
-                curScroll >= HIDE_HISTORY_BUTTON_SCROLL_THRESHOLD) {
-            EventBus.getDefault().send(new HideHistoryButtonEvent());
+        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());
+            }
         }
     }
 
@@ -1387,7 +1492,7 @@
 
     public final void onBusEvent(PackagesChangedEvent event) {
         // Compute which components need to be removed
-        HashSet<ComponentName> removedComponents = mStack.computeComponentsRemoved(
+        ArraySet<ComponentName> removedComponents = mStack.computeComponentsRemoved(
                 event.packageName, event.userId);
 
         // For other tasks, just remove them directly if they no longer exist
@@ -1398,15 +1503,10 @@
                 final TaskView tv = getChildViewForTask(t);
                 if (tv != null) {
                     // For visible children, defer removing the task until after the animation
-                    tv.startDeleteTaskAnimation(new Runnable() {
-                        @Override
-                        public void run() {
-                            removeTaskViewFromStack(tv);
-                        }
-                    }, 0);
+                    tv.dismissTask();
                 } else {
                     // Otherwise, remove the task from the stack immediately
-                    mStack.removeTask(t);
+                    mStack.removeTask(t, TaskViewAnimation.IMMEDIATE);
                 }
             }
         }
@@ -1417,16 +1517,24 @@
         mUIDozeTrigger.stopDozing();
     }
 
-    public final void onBusEvent(DismissTaskViewEvent event) {
-        removeTaskViewFromStack(event.taskView);
+    public final void onBusEvent(LaunchTaskStartedEvent event) {
+        mAnimationHelper.startLaunchTaskAnimation(event.taskView, event.screenPinningRequested,
+                event.getAnimationTrigger());
     }
 
-    public final void onBusEvent(FocusNextTaskViewEvent event) {
-        setRelativeFocusedTask(true, false /* stackTasksOnly */, true /* animated */);
-    }
+    public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
+        // Stop any scrolling
+        mStackScroller.stopScroller();
+        mStackScroller.stopBoundScrollAnimation();
 
-    public final void onBusEvent(FocusPreviousTaskViewEvent event) {
-        setRelativeFocusedTask(false, false /* stackTasksOnly */, true /* animated */);
+        // Start the task animations
+        mAnimationHelper.startExitToHomeAnimation(event.animated, event.getAnimationTrigger());
+
+        // Dismiss the freeform workspace background
+        int taskViewExitToHomeDuration = getResources().getInteger(
+                R.integer.recents_task_exit_to_home_duration);
+        animateFreeformWorkspaceBackgroundAlpha(0, taskViewExitToHomeDuration,
+                mFastOutSlowInInterpolator);
     }
 
     public final void onBusEvent(DismissFocusedTaskViewEvent event) {
@@ -1439,9 +1547,37 @@
         }
     }
 
+    public final void onBusEvent(final DismissTaskViewEvent event) {
+        // For visible children, defer removing the task until after the animation
+        mAnimationHelper.startDeleteTaskAnimation(event.task, event.taskView,
+                event.getAnimationTrigger());
+    }
+
+    public final void onBusEvent(TaskViewDismissedEvent event) {
+        removeTaskViewFromStack(event.taskView, event.task);
+        EventBus.getDefault().send(new DeleteTaskDataEvent(event.task));
+    }
+
+    public final void onBusEvent(FocusNextTaskViewEvent event) {
+        setRelativeFocusedTask(true, false /* stackTasksOnly */, true /* animated */, false,
+                event.timerIndicatorDuration);
+    }
+
+    public final void onBusEvent(FocusPreviousTaskViewEvent event) {
+        setRelativeFocusedTask(false, false /* stackTasksOnly */, true /* animated */);
+    }
+
     public final void onBusEvent(UserInteractionEvent event) {
         // Poke the doze trigger on user interaction
         mUIDozeTrigger.poke();
+
+        RecentsDebugFlags debugFlags = Recents.getDebugFlags();
+        if (debugFlags.isFastToggleRecentsEnabled() && mFocusedTask != null) {
+            TaskView tv = getChildViewForTask(mFocusedTask);
+            if (tv != null) {
+                tv.getHeaderView().cancelFocusTimerIndicator();
+            }
+        }
     }
 
     public final void onBusEvent(RecentsVisibilityChangedEvent event) {
@@ -1456,6 +1592,15 @@
             mStackScroller.animateScroll(mStackScroller.getStackScroll(),
                     mLayoutAlgorithm.mInitialScrollP, null);
         }
+
+        // Enlarge the dragged view slightly
+        float finalScale = event.taskView.getScaleX() * DRAG_SCALE_FACTOR;
+        mLayoutAlgorithm.getStackTransform(event.task, getScroller().getStackScroll(),
+                mTmpTransform, null);
+        mTmpTransform.scale = finalScale;
+        mTmpTransform.translationZ = mLayoutAlgorithm.mMaxTranslationZ + 1;
+        updateTaskViewToTransform(event.taskView, mTmpTransform,
+                new TaskViewAnimation(DRAG_SCALE_DURATION, mFastOutSlowInInterpolator));
     }
 
     public final void onBusEvent(DragStartInitializeDropTargetsEvent event) {
@@ -1467,7 +1612,29 @@
     }
 
     public final void onBusEvent(DragDropTargetChangedEvent event) {
-        // TODO: Animate the freeform workspace background etc.
+        TaskViewAnimation animation = new TaskViewAnimation(250, mFastOutSlowInInterpolator);
+        if (event.dropTarget instanceof TaskStack.DockState) {
+            // Calculate the new task stack bounds that matches the window size that Recents will
+            // have after the drop
+            addIgnoreTask(event.task);
+            final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
+            mStackBounds.set(dockState.getDockedTaskStackBounds(getMeasuredWidth(),
+                    getMeasuredHeight(), mDividerSize, mLayoutAlgorithm.mSystemInsets,
+                    getResources()));
+            mLayoutAlgorithm.initialize(mStackBounds,
+                    TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
+            updateLayoutAlgorithm(true /* boundScroll */);
+        } 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
+            mStackBounds.set(mStableStackBounds);
+            removeIgnoreTask(event.task);
+            mLayoutAlgorithm.initialize(mStackBounds,
+                    TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
+            updateLayoutAlgorithm(true /* boundScroll */);
+            addIgnoreTask(event.task);
+        }
+        relayoutTaskViews(animation);
     }
 
     public final void onBusEvent(final DragEndEvent event) {
@@ -1481,20 +1648,19 @@
                 (!isFreeformTask && event.dropTarget == mFreeformWorkspaceDropTarget) ||
                         (isFreeformTask && event.dropTarget == mStackDropTarget);
 
-        event.postAnimationTrigger.increment();
         if (hasChangedStacks) {
             // Move the task to the right position in the stack (ie. the front of the stack if
-            // freeform or the front of the stack if fullscreen).  Note, we MUST move the tasks
+            // freeform or the front of the stack if fullscreen). Note, we MUST move the tasks
             // before we update their stack ids, otherwise, the keys will have changed.
             if (event.dropTarget == mFreeformWorkspaceDropTarget) {
                 mStack.moveTaskToStack(event.task, FREEFORM_WORKSPACE_STACK_ID);
             } else if (event.dropTarget == mStackDropTarget) {
                 mStack.moveTaskToStack(event.task, FULLSCREEN_WORKSPACE_STACK_ID);
             }
-            updateLayout(true);
+            updateLayoutAlgorithm(true /* boundScroll */);
 
             // Move the task to the new stack in the system after the animation completes
-            event.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
+            event.addPostAnimationCallback(new Runnable() {
                 @Override
                 public void run() {
                     SystemServicesProxy ssp = Recents.getSystemServices();
@@ -1502,8 +1668,6 @@
                 }
             });
         }
-        event.taskView.animate()
-                .withEndAction(event.postAnimationTrigger.decrementAsRunnable());
 
         // We translated the view but we need to animate it back from the current layout-space rect
         // to its final layout-space rect
@@ -1517,12 +1681,20 @@
         event.taskView.setLeftTopRightBottom(taskViewRect.left, taskViewRect.top,
                 taskViewRect.right, taskViewRect.bottom);
 
-        // Animate the tack view back into position
-        requestSynchronizeStackViewsWithModel(250);
+        // Animate all the TaskViews back into position
+        mLayoutAlgorithm.getStackTransform(event.task, getScroller().getStackScroll(),
+                mTmpTransform, null);
+        event.getAnimationTrigger().increment();
+        relayoutTaskViews(new TaskViewAnimation(DEFAULT_SYNC_STACK_DURATION,
+                mFastOutSlowInInterpolator));
+        updateTaskViewToTransform(event.taskView, mTmpTransform,
+                new TaskViewAnimation(DEFAULT_SYNC_STACK_DURATION, mFastOutSlowInInterpolator,
+                        event.getAnimationTrigger().decrementOnAnimationEnd()));
+        removeIgnoreTask(event.task);
     }
 
     public final void onBusEvent(StackViewScrolledEvent event) {
-        mLayoutAlgorithm.updateFocusStateOnScroll(event.yMovement);
+        mLayoutAlgorithm.updateFocusStateOnScroll(event.yMovement.value);
     }
 
     public final void onBusEvent(IterateRecentsEvent event) {
@@ -1530,11 +1702,52 @@
             // Cancel the previous task's window transition before animating the focused state
             EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null));
         }
-        mLayoutAlgorithm.animateFocusState(mLayoutAlgorithm.getDefaultFocusState());
     }
 
     public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
         mEnterAnimationComplete = true;
+
+        if (mStack.getTaskCount() > 0) {
+            // Start the task enter animations
+            mAnimationHelper.startEnterAnimation(event.getAnimationTrigger());
+
+            // Add a runnable to the post animation ref counter to clear all the views
+            event.addPostAnimationCallback(new Runnable() {
+                @Override
+                public void run() {
+                    // Start the dozer to trigger to trigger any UI that shows after a timeout
+                    mUIDozeTrigger.startDozing();
+
+                    // Update the focused state here -- since we only set the focused task without
+                    // requesting view focus in onFirstLayout(), actually request view focus and
+                    // animate the focused state if we are alt-tabbing now, after the window enter
+                    // animation is completed
+                    if (mFocusedTask != null) {
+                        RecentsConfiguration config = Recents.getConfiguration();
+                        RecentsActivityLaunchState launchState = config.getLaunchState();
+                        setFocusedTask(mStack.indexOfStackTask(mFocusedTask),
+                                false /* scrollToTask */, launchState.launchedWithAltTab);
+                    }
+
+                    EventBus.getDefault().send(new EnterRecentsTaskStackAnimationCompletedEvent());
+                }
+            });
+        }
+    }
+
+    public final void onBusEvent(EnterRecentsTaskStackAnimationCompletedEvent event) {
+        RecentsDebugFlags debugFlags = Recents.getDebugFlags();
+        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+        if (!launchState.launchedWithAltTab && debugFlags.isFastToggleRecentsEnabled() &&
+                RecentsDebugFlags.Static.EnableFastToggleTimeoutOnEnter) {
+            if (mFocusedTask != null) {
+                int timerIndicatorDuration = getResources().getInteger(
+                        R.integer.recents_auto_advance_duration);
+                int focusedTaskIndex = mStack.indexOfStackTask(mFocusedTask);
+                setFocusedTask(focusedTaskIndex, false /* scrollToTask */,
+                        false /* requestViewFocus */, timerIndicatorDuration);
+            }
+        }
     }
 
     public final void onBusEvent(UpdateFreeformTaskViewVisibilityEvent event) {
@@ -1543,70 +1756,40 @@
         for (int i = 0; i < taskViewCount; i++) {
             TaskView tv = taskViews.get(i);
             Task task = tv.getTask();
-            if (SystemServicesProxy.isFreeformStack(task.key.stackId)) {
+            if (task.isFreeformTask()) {
                 tv.setVisibility(event.visible ? View.VISIBLE : View.INVISIBLE);
             }
         }
     }
 
     public final void onBusEvent(ShowHistoryEvent event) {
-        // The history view's animation will be deferred until all the stack task views are animated
-        // away
-        int historyTransitionDuration =
-                getResources().getInteger(R.integer.recents_history_transition_duration);
-        List<TaskView> taskViews = getTaskViews();
-        int taskViewCount = taskViews.size();
-        for (int i = taskViewCount - 1; i >= 0; i--) {
-            TaskView tv = taskViews.get(i);
-            tv.animate()
-                    .alpha(0f)
-                    .setDuration(historyTransitionDuration)
-                    .setUpdateListener(null)
-                    .setListener(null)
-                    .withLayer()
-                    .withEndAction(event.postHideStackAnimationTrigger.decrementAsRunnable())
-                    .start();
-            event.postHideStackAnimationTrigger.increment();
-        }
+        ReferenceCountedTrigger postAnimTrigger = new ReferenceCountedTrigger();
+        postAnimTrigger.addLastDecrementRunnable(new Runnable() {
+            @Override
+            public void run() {
+                setVisibility(View.INVISIBLE);
+            }
+        });
+        mAnimationHelper.startShowHistoryAnimation(postAnimTrigger);
     }
 
     public final void onBusEvent(HideHistoryEvent event) {
-        // The stack task view animations will be deferred until the history view has been animated
-        // away
-        final int historyTransitionDuration =
-                getResources().getInteger(R.integer.recents_history_transition_duration);
-        List<TaskView> taskViews = getTaskViews();
-        int taskViewCount = taskViews.size();
-        for (int i = taskViewCount - 1; i >= 0; i--) {
-            final TaskView tv = taskViews.get(i);
-            event.postHideHistoryAnimationTrigger.addLastDecrementRunnable(new Runnable() {
-                @Override
-                public void run() {
-                    tv.animate()
-                            .alpha(1f)
-                            .setDuration(historyTransitionDuration)
-                            .setUpdateListener(null)
-                            .setListener(null)
-                            .withLayer()
-                            .start();
-                }
-            });
-        }
+        setVisibility(View.VISIBLE);
+        mAnimationHelper.startHideHistoryAnimation();
     }
 
     /**
      * 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 = tv.getTask();
-
+    private void removeTaskViewFromStack(TaskView tv, Task task) {
         // Announce for accessibility
         tv.announceForAccessibility(getContext().getString(
-                R.string.accessibility_recents_item_dismissed, tv.getTask().activityLabel));
+                R.string.accessibility_recents_item_dismissed, task.title));
 
         // Remove the task from the stack
-        mStack.removeTask(task);
+        mStack.removeTask(task, new TaskViewAnimation(DEFAULT_SYNC_STACK_DURATION,
+                mFastOutSlowInInterpolator));
     }
 
     /**
@@ -1620,14 +1803,14 @@
 
         Utilities.cancelAnimationWithoutCallbacks(mFreeformWorkspaceBackgroundAnimator);
         mFreeformWorkspaceBackgroundAnimator = ObjectAnimator.ofInt(mFreeformWorkspaceBackground,
-                DRAWABLE_ALPHA, mFreeformWorkspaceBackground.getAlpha(), targetAlpha);
+                Utilities.DRAWABLE_ALPHA, mFreeformWorkspaceBackground.getAlpha(), targetAlpha);
         mFreeformWorkspaceBackgroundAnimator.setDuration(duration);
         mFreeformWorkspaceBackgroundAnimator.setInterpolator(interpolator);
         mFreeformWorkspaceBackgroundAnimator.start();
     }
 
     /**
-     * Returns the insert index for the task in the current set of task views.  If the given task
+     * Returns the insert index for the task in the current set of task views. If the given task
      * is already in the task view list, then this method returns the insert index assuming it
      * is first removed at the previous index.
      *
@@ -1661,4 +1844,14 @@
     private boolean shouldShowHistoryButton() {
         return !mStack.getHistoricalTasks().isEmpty();
     }
+
+    /**
+     * Reads current system flags related to accessibility and screen pinning.
+     */
+    private void readSystemFlags() {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        mTouchExplorationEnabled = ssp.isTouchExplorationEnabled();
+        mScreenPinningEnabled = ssp.getSystemSetting(getContext(),
+                Settings.System.LOCK_TO_APP_ENABLED) != 0;
+    }
 }
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 56942a8..4ec051f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -20,7 +20,9 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.content.Context;
+import android.util.FloatProperty;
 import android.util.Log;
+import android.util.Property;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.OverScroller;
@@ -34,9 +36,27 @@
     private static final boolean DEBUG = false;
 
     public interface TaskStackViewScrollerCallbacks {
-        void onScrollChanged(float prevScroll, float curScroll);
+        void onScrollChanged(float prevScroll, float curScroll, TaskViewAnimation animation);
     }
 
+    /**
+     * A Property wrapper around the <code>stackScroll</code> functionality handled by the
+     * {@link #setStackScroll(float)} and
+     * {@link #getStackScroll()} methods.
+     */
+    private static final Property<TaskStackViewScroller, Float> STACK_SCROLL =
+            new FloatProperty<TaskStackViewScroller>("stackScroll") {
+                @Override
+                public void setValue(TaskStackViewScroller object, float value) {
+                    object.setStackScroll(value);
+                }
+
+                @Override
+                public Float get(TaskStackViewScroller object) {
+                    return object.getStackScroll();
+                }
+            };
+
     Context mContext;
     TaskStackLayoutAlgorithm mLayoutAlgorithm;
     TaskStackViewScrollerCallbacks mCb;
@@ -51,13 +71,14 @@
 
     private Interpolator mLinearOutSlowInInterpolator;
 
-    public TaskStackViewScroller(Context context, TaskStackLayoutAlgorithm layoutAlgorithm) {
+    public TaskStackViewScroller(Context context, TaskStackViewScrollerCallbacks cb,
+            TaskStackLayoutAlgorithm layoutAlgorithm) {
         mContext = context;
+        mCb = cb;
         mScroller = new OverScroller(context);
         mLayoutAlgorithm = layoutAlgorithm;
         mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
                 com.android.internal.R.interpolator.linear_out_slow_in);
-        setStackScroll(getStackScroll());
     }
 
     /** Resets the task scroller. */
@@ -65,22 +86,27 @@
         mStackScrollP = 0f;
     }
 
-    /** Sets the callbacks */
-    void setCallbacks(TaskStackViewScrollerCallbacks cb) {
-        mCb = cb;
-    }
-
     /** Gets the current stack scroll */
     public float getStackScroll() {
         return mStackScrollP;
     }
 
-    /** Sets the current stack scroll */
+    /**
+     * Sets the current stack scroll immediately.
+     */
     public void setStackScroll(float s) {
+        setStackScroll(s, TaskViewAnimation.IMMEDIATE);
+    }
+
+    /**
+     * Sets the current stack scroll, but indicates to the callback the preferred animation to
+     * update to this new scroll.
+     */
+    public void setStackScroll(float s, TaskViewAnimation animation) {
         float prevStackScroll = mStackScrollP;
         mStackScrollP = s;
         if (mCb != null) {
-            mCb.onScrollChanged(prevStackScroll, mStackScrollP);
+            mCb.onScrollChanged(prevStackScroll, mStackScrollP, animation);
         }
     }
 
@@ -142,6 +168,7 @@
 
     /** Animates the stack scroll into bounds */
     ObjectAnimator animateBoundScroll() {
+        // TODO: Take duration for snap back
         float curScroll = getStackScroll();
         float newScroll = getBoundedStackScroll(curScroll);
         if (Float.compare(newScroll, curScroll) != 0) {
@@ -162,7 +189,7 @@
         stopBoundScrollAnimation();
 
         mFinalAnimatedScroll = newScroll;
-        mScrollAnimator = ObjectAnimator.ofFloat(this, "stackScroll", curScroll, newScroll);
+        mScrollAnimator = ObjectAnimator.ofFloat(this, STACK_SCROLL, curScroll, newScroll);
         mScrollAnimator.setDuration(mContext.getResources().getInteger(
                 R.integer.recents_animate_task_stack_scroll_duration));
         mScrollAnimator.setInterpolator(mLinearOutSlowInInterpolator);
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 1a6f129..7019444 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -16,38 +16,49 @@
 
 package com.android.systemui.recents.views;
 
+import android.animation.Animator;
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Rect;
-import android.util.Log;
+import android.util.ArrayMap;
+import android.util.MutableBoolean;
 import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewParent;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
+import com.android.systemui.SwipeHelper;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
-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.misc.RectFEvaluator;
 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.statusbar.FlingAnimationUtils;
 
+import java.util.ArrayList;
 import java.util.List;
 
-/* Handles touch events for a TaskStackView. */
+/**
+ * Handles touch events for a TaskStackView.
+ */
 class TaskStackViewTouchHandler implements SwipeHelper.Callback {
 
-    private static final String TAG = "TaskStackViewTouchHandler";
-    private static final boolean DEBUG = false;
+    private static final int INACTIVE_POINTER_ID = -1;
 
-    private static int INACTIVE_POINTER_ID = -1;
+    private static final RectFEvaluator RECT_EVALUATOR = new RectFEvaluator();
+    private static final Interpolator STACK_TRANSFORM_INTERPOLATOR =
+            new PathInterpolator(0.73f, 0.33f, 0.42f, 0.85f);
 
     Context mContext;
     TaskStackView mSv;
@@ -71,6 +82,16 @@
     // Used to calculate when a tap is outside a task view rectangle.
     final int mWindowTouchSlop;
 
+    private final StackViewScrolledEvent mStackViewScrolledEvent = new StackViewScrolledEvent();
+
+    // The current and final set of task transforms, sized to match the list of tasks in the stack
+    private ArrayList<Task> mCurrentTasks = new ArrayList<>();
+    private ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<>();
+    private ArrayList<TaskViewTransform> mFinalTaskTransforms = new ArrayList<>();
+    private ArrayMap<View, Animator> mSwipeHelperAnimations = new ArrayMap<>();
+    private TaskViewTransform mTmpTransform = new TaskViewTransform();
+    private float mTargetStackScroll;
+
     SwipeHelper mSwipeHelper;
     boolean mInterceptedBySwipeHelper;
 
@@ -79,19 +100,32 @@
         Resources res = context.getResources();
         ViewConfiguration configuration = ViewConfiguration.get(context);
         mContext = context;
+        mSv = sv;
+        mScroller = scroller;
         mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
         mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
         mScrollTouchSlop = configuration.getScaledTouchSlop();
         mWindowTouchSlop = configuration.getScaledWindowTouchSlop();
-        mSv = sv;
-        mScroller = scroller;
         mFlingAnimUtils = new FlingAnimationUtils(context, 0.2f);
-
-        float densityScale = res.getDisplayMetrics().density;
         mOverscrollSize = res.getDimensionPixelSize(R.dimen.recents_stack_overscroll);
-        mSwipeHelper = new SwipeHelper(context, SwipeHelper.X, this, densityScale,
-                configuration.getScaledPagingTouchSlop());
-        mSwipeHelper.setMinAlpha(1f);
+        mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, context) {
+            @Override
+            protected float getSize(View v) {
+                return mSv.getWidth();
+            }
+
+            @Override
+            protected void prepareDismissAnimation(View v, Animator anim) {
+                mSwipeHelperAnimations.put(v, anim);
+            }
+
+            @Override
+            protected void prepareSnapBackAnimation(View v, Animator anim) {
+                anim.setInterpolator(mSv.mFastOutSlowInInterpolator);
+                mSwipeHelperAnimations.put(v, anim);
+            }
+        };
+        mSwipeHelper.setDisableHardwareLayers(true);
     }
 
     /** Velocity tracker helpers */
@@ -109,21 +143,6 @@
         }
     }
 
-    /** Returns the view at the specified coordinates */
-    TaskView findViewAtPoint(int x, int y) {
-        List<TaskView> taskViews = mSv.getTaskViews();
-        int taskViewCount = taskViews.size();
-        for (int i = taskViewCount - 1; i >= 0; i--) {
-            TaskView tv = taskViews.get(i);
-            if (tv.getVisibility() == View.VISIBLE) {
-                if (mSv.isTransformedTouchPointInView(x, y, tv)) {
-                    return tv;
-                }
-            }
-        }
-        return null;
-    }
-
     /** Touch preprocessing for handling below */
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         // Pass through to swipe helper if we are swiping
@@ -169,6 +188,15 @@
                 mScroller.stopBoundScrollAnimation();
                 Utilities.cancelAnimationWithoutCallbacks(mScrollFlingAnimator);
 
+                // Finish any existing task animations from the delete
+                mSv.cancelAllTaskViewAnimations();
+                // Finish any of the swipe helper animations
+                ArrayMap<View, Animator> existingAnimators = new ArrayMap<>(mSwipeHelperAnimations);
+                for (int i = 0; i < existingAnimators.size(); i++) {
+                    existingAnimators.get(existingAnimators.keyAt(i)).end();
+                }
+                mSwipeHelperAnimations.clear();
+
                 // Initialize the velocity tracker
                 initOrResetVelocityTracker();
                 mVelocityTracker.addMovement(ev);
@@ -187,8 +215,11 @@
             case MotionEvent.ACTION_MOVE: {
                 int activePointerIndex = ev.findPointerIndex(mActivePointerId);
                 int y = (int) ev.getY(activePointerIndex);
+                int x = (int) ev.getX(activePointerIndex);
                 if (!mIsScrolling) {
-                    if (Math.abs(y - mDownY) > mScrollTouchSlop) {
+                    int yDiff = Math.abs(y - mDownY);
+                    int xDiff = Math.abs(x - mDownX);
+                    if (Math.abs(y - mDownY) > mScrollTouchSlop && yDiff > xDiff) {
                         mIsScrolling = true;
 
                         // Disallow parents from intercepting touch events
@@ -204,10 +235,8 @@
                     float deltaP = layoutAlgorithm.getDeltaPForY(mDownY, y);
                     float curScrollP = mDownScrollP + deltaP;
                     mScroller.setStackScroll(curScrollP);
-                    if (DEBUG) {
-                        Log.d(TAG, "scroll: " + curScrollP);
-                    }
-                    EventBus.getDefault().send(new StackViewScrolledEvent(y - mLastY));
+                    mStackViewScrolledEvent.updateY(y - mLastY);
+                    EventBus.getDefault().send(mStackViewScrolledEvent);
                 }
 
                 mLastY = y;
@@ -295,6 +324,7 @@
             Rect freeformRect = mSv.mLayoutAlgorithm.mFreeformRect;
             if (freeformRect.top <= y && y <= freeformRect.bottom) {
                 if (mSv.launchFreeformTasks()) {
+                    // TODO: Animate Recents away as we launch the freeform tasks
                     return;
                 }
             }
@@ -331,18 +361,25 @@
 
     @Override
     public View getChildAtPosition(MotionEvent ev) {
-        return findViewAtPoint((int) ev.getX(), (int) ev.getY());
+        TaskView tv = findViewAtPoint((int) ev.getX(), (int) ev.getY());
+        if (tv != null && canChildBeDismissed(tv)) {
+            return tv;
+        }
+        return null;
     }
 
     @Override
     public boolean canChildBeDismissed(View v) {
-        return true;
+        // Disallow dismissing an already dismissed task
+        TaskView tv = (TaskView) v;
+        return !mSwipeHelperAnimations.containsKey(v) &&
+                (mSv.getStack().indexOfStackTask(tv.getTask()) != -1);
     }
 
     @Override
     public void onBeginDrag(View v) {
         TaskView tv = (TaskView) v;
-        mSwipeHelper.setSnapBackTranslationX(tv.getTranslationX());
+
         // Disable clipping with the stack while we are swiping
         tv.setClipViewInStack(false);
         // Disallow touch events from this task view
@@ -352,38 +389,188 @@
         if (parent != null) {
             parent.requestDisallowInterceptTouchEvent(true);
         }
+
+        // Add this task to the set of tasks we are deleting
+        mSv.addIgnoreTask(tv.getTask());
+
+        // Determine if we are animating the other tasks while dismissing this task
+        mCurrentTasks = mSv.getStack().getStackTasks();
+        MutableBoolean isFrontMostTask = new MutableBoolean(false);
+        Task anchorTask = mSv.findAnchorTask(mCurrentTasks, isFrontMostTask);
+        TaskStackViewScroller stackScroller = mSv.getScroller();
+        if (anchorTask != null) {
+            // Get the current set of task transforms
+            mSv.getCurrentTaskTransforms(mCurrentTasks, mCurrentTaskTransforms);
+
+            // Get the stack scroll of the task to anchor to (since we are removing something, the
+            // front most task will be our anchor task)
+            float prevAnchorTaskScroll = 0;
+            boolean pullStackForward = mCurrentTasks.size() > 0;
+            if (pullStackForward) {
+                prevAnchorTaskScroll = mSv.getStackAlgorithm().getStackScrollForTask(anchorTask);
+            }
+
+            // Calculate where the views would be without the deleting tasks
+            mSv.updateLayoutAlgorithm(false /* boundScroll */);
+
+            float newStackScroll = stackScroller.getStackScroll();
+            if (isFrontMostTask.value) {
+                // Bound the stack scroll to pull tasks forward if necessary
+                newStackScroll = stackScroller.getBoundedStackScroll(newStackScroll);
+            } else if (pullStackForward) {
+                // Otherwise, offset the scroll by the movement of the anchor task
+                float anchorTaskScroll = mSv.getStackAlgorithm().getStackScrollForTask(anchorTask);
+                float stackScrollOffset = (anchorTaskScroll - prevAnchorTaskScroll);
+                if (mSv.getStackAlgorithm().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;
+                }
+                newStackScroll = stackScroller.getBoundedStackScroll(stackScroller.getStackScroll()
+                        + stackScrollOffset);
+            }
+
+            // Pick up the newly visible views, not including the deleting tasks
+            mSv.bindVisibleTaskViews(newStackScroll);
+
+            // Get the final set of task transforms (with task removed)
+            mSv.getLayoutTaskTransforms(newStackScroll, mCurrentTasks, mFinalTaskTransforms);
+
+            // Set the target to scroll towards upon dismissal
+            mTargetStackScroll = newStackScroll;
+
+            /*
+             * Post condition: All views that will be visible as a part of the gesture are retrieved
+             *                 and at their initial positions.  The stack is still at the current
+             *                 scroll, but the layout is updated without the task currently being
+             *                 dismissed.
+             */
+        }
     }
 
     @Override
-    public void onSwipeChanged(View v, float delta) {
-        // Do nothing
+    public boolean updateSwipeProgress(View v, boolean dismissable, float swipeProgress) {
+        updateTaskViewTransforms(getDismissFraction(v));
+        return true;
     }
 
+    /**
+     * Called after the {@link TaskView} is finished animating away.
+     */
     @Override
     public void onChildDismissed(View v) {
         TaskView tv = (TaskView) v;
+
         // Re-enable clipping with the stack (we will reuse this view)
         tv.setClipViewInStack(true);
         // Re-enable touch events from this task view
         tv.setTouchEnabled(true);
+        // Update the scroll to the final scroll position from onBeginDrag()
+        mSv.getScroller().setStackScroll(mTargetStackScroll, null);
         // Remove the task view from the stack
-        EventBus.getDefault().send(new DismissTaskViewEvent(tv.getTask(), tv));
+        EventBus.getDefault().send(new TaskViewDismissedEvent(tv.getTask(), tv));
+        // Stop tracking this deletion animation
+        mSwipeHelperAnimations.remove(v);
         // Keep track of deletions by keyboard
         MetricsLogger.histogram(tv.getContext(), "overview_task_dismissed_source",
                 Constants.Metrics.DismissSourceSwipeGesture);
     }
 
+    /**
+     * Called after the {@link TaskView} is finished animating back into the list.
+     * onChildDismissed() calls.
+     */
     @Override
-    public void onSnapBackCompleted(View v) {
+    public void onChildSnappedBack(View v) {
         TaskView tv = (TaskView) v;
+
         // Re-enable clipping with the stack
         tv.setClipViewInStack(true);
         // Re-enable touch events from this task view
         tv.setTouchEnabled(true);
+
+        // Stop tracking this deleting task, and update the layout to include this task again.  The
+        // stack scroll does not need to be reset, since the scroll has not actually changed in
+        // onBeginDrag().
+        mSv.removeIgnoreTask(tv.getTask());
+        mSv.updateLayoutAlgorithm(false /* boundScroll */);
+        mSwipeHelperAnimations.remove(v);
     }
 
     @Override
     public void onDragCancelled(View v) {
         // Do nothing
     }
+
+    @Override
+    public View getChildContentView(View v) {
+        return v;
+    }
+
+    @Override
+    public boolean isAntiFalsingNeeded() {
+        return false;
+    }
+
+    @Override
+    public float getFalsingThresholdFactor() {
+        return 0;
+    }
+
+    /**
+     * Interpolates the non-deleting tasks to their final transforms from their current transforms.
+     */
+    private void updateTaskViewTransforms(float dismissFraction) {
+        List<TaskView> taskViews = mSv.getTaskViews();
+        int taskViewCount = taskViews.size();
+        for (int i = 0; i < taskViewCount; i++) {
+            TaskView tv = taskViews.get(i);
+            Task task = tv.getTask();
+
+            if (mSv.isIgnoredTask(task)) {
+                continue;
+            }
+
+            int taskIndex = mCurrentTasks.indexOf(task);
+            TaskViewTransform fromTransform = mCurrentTaskTransforms.get(taskIndex);
+            TaskViewTransform toTransform = mFinalTaskTransforms.get(taskIndex);
+
+            mTmpTransform.copyFrom(fromTransform);
+            // We only really need to interpolate the bounds, progress and translation
+            mTmpTransform.rect.set(RECT_EVALUATOR.evaluate(dismissFraction, fromTransform.rect,
+                    toTransform.rect));
+            mTmpTransform.p = fromTransform.p + (toTransform.p - fromTransform.p) * dismissFraction;
+            mTmpTransform.translationZ = fromTransform.translationZ +
+                    (toTransform.translationZ - fromTransform.translationZ) * dismissFraction;
+
+            mSv.updateTaskViewToTransform(tv, mTmpTransform, TaskViewAnimation.IMMEDIATE);
+        }
+    }
+
+    /** Returns the view at the specified coordinates */
+    private TaskView findViewAtPoint(int x, int y) {
+        List<Task> tasks = mSv.getStack().getStackTasks();
+        int taskCount = tasks.size();
+        for (int i = taskCount - 1; i >= 0; i--) {
+            TaskView tv = mSv.getChildViewForTask(tasks.get(i));
+            if (tv != null && tv.getVisibility() == View.VISIBLE) {
+                if (mSv.isTouchPointInView(x, y, tv)) {
+                    return tv;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the fraction which we should interpolate the other task views based on the dismissal
+     * of this given task.
+     *
+     * TODO: We can interpolate this to adjust when the other tasks should respond to the dismissal
+     */
+    private float getDismissFraction(View v) {
+        float fraction = Math.min(1f, Math.abs(v.getTranslationX() / mSv.getWidth()));
+        return STACK_TRANSFORM_INTERPOLATOR.getInterpolation(fraction);
+    }
 }
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 ab51d5f..5a4064a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -17,7 +17,6 @@
 package com.android.systemui.recents.views;
 
 import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
@@ -31,46 +30,81 @@
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.util.Log;
+import android.util.FloatProperty;
+import android.util.IntProperty;
+import android.util.Property;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewOutlineProvider;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
-import android.widget.FrameLayout;
 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.events.EventBus;
 import com.android.systemui.recents.events.activity.LaunchTaskEvent;
 import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
+import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
+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.statusbar.phone.PhoneStatusBar;
 
+import java.util.ArrayList;
+
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 
-/* A task view */
-public class TaskView extends FrameLayout implements Task.TaskCallbacks,
-        View.OnClickListener, View.OnLongClickListener {
-
-    private final static String TAG = "TaskView";
-    private final static boolean DEBUG = false;
+/**
+ * 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
+ * the view hierarchy, but not upwards from any of its children (the TaskView will relayout itself
+ * with the previous bounds if any child requests layout).
+ */
+public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks,
+        TaskStackAnimationHelper.Callbacks, View.OnClickListener, View.OnLongClickListener {
 
     /** The TaskView callbacks */
     interface TaskViewCallbacks {
         void onTaskViewClipStateChanged(TaskView tv);
     }
 
+    /**
+     * 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, Integer> DIM =
+            new IntProperty<TaskView>("dim") {
+                @Override
+                public void setValue(TaskView tv, int dim) {
+                    tv.setDim(dim);
+                }
+
+                @Override
+                public Integer get(TaskView tv) {
+                    return tv.getDim();
+                }
+            };
+
+    public static final Property<TaskView, Float> TASK_PROGRESS =
+            new FloatProperty<TaskView>("taskProgress") {
+                @Override
+                public void setValue(TaskView tv, float p) {
+                    tv.setTaskProgress(p);
+                }
+
+                @Override
+                public Float get(TaskView tv) {
+                    return tv.getTaskProgress();
+                }
+            };
+
     float mTaskProgress;
-    ObjectAnimator mTaskProgressAnimator;
     float mMaxDimScale;
     int mDimAlpha;
     AccelerateInterpolator mDimInterpolator = new AccelerateInterpolator(3f);
@@ -80,9 +114,11 @@
 
     Task mTask;
     boolean mTaskDataLoaded;
-    boolean mClipViewInStack;
+    boolean mClipViewInStack = true;
     AnimateableViewBounds mViewBounds;
-    private AnimatorSet mClipAnimation;
+
+    private AnimatorSet mTransformAnimation;
+    private ArrayList<Animator> mTmpAnimators = new ArrayList<>();
 
     View mContent;
     TaskViewThumbnail mThumbnailView;
@@ -93,18 +129,6 @@
     Point mDownTouchPos = new Point();
 
     Interpolator mFastOutSlowInInterpolator;
-    Interpolator mFastOutLinearInInterpolator;
-    Interpolator mQuintOutInterpolator;
-
-    // Optimizations
-    ValueAnimator.AnimatorUpdateListener mUpdateDimListener =
-            new ValueAnimator.AnimatorUpdateListener() {
-                @Override
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    setTaskProgress((Float) animation.getAnimatedValue());
-                }
-            };
-
 
     public TaskView(Context context) {
         this(context, null);
@@ -123,21 +147,15 @@
         RecentsConfiguration config = Recents.getConfiguration();
         Resources res = context.getResources();
         mMaxDimScale = res.getInteger(R.integer.recents_max_task_stack_view_dim) / 255f;
-        mClipViewInStack = true;
         mViewBounds = new AnimateableViewBounds(this, res.getDimensionPixelSize(
                 R.dimen.recents_task_view_rounded_corners_radius));
         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
                 com.android.internal.R.interpolator.fast_out_slow_in);
-        mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
-                com.android.internal.R.interpolator.fast_out_linear_in);
-        mQuintOutInterpolator = AnimationUtils.loadInterpolator(context,
-                com.android.internal.R.interpolator.decelerate_quint);
-        setTaskProgress(getTaskProgress());
-        setDim(getDim());
         if (config.fakeShadows) {
             setBackground(new FakeShadowDrawable(res, config));
         }
         setOutlineProvider(mViewBounds);
+        setOnLongClickListener(this);
     }
 
     /** Set callback */
@@ -175,16 +193,25 @@
             public void getOutline(View view, Outline outline) {
                 // Set the outline to match the FAB background
                 outline.setOval(0, 0, mActionButtonView.getWidth(), mActionButtonView.getHeight());
+                outline.setAlpha(0.35f);
             }
         });
+        mActionButtonView.setOnClickListener(this);
         mActionButtonTranslationZ = mActionButtonView.getTranslationZ();
     }
 
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
-        mHeaderView.onTaskViewSizeChanged(w, h);
-        mThumbnailView.onTaskViewSizeChanged(w, h);
+        if (w > 0 && h > 0) {
+            mHeaderView.onTaskViewSizeChanged(w, h);
+            mThumbnailView.onTaskViewSizeChanged(w, h);
+        }
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
     }
 
     @Override
@@ -195,330 +222,78 @@
         return super.onInterceptTouchEvent(ev);
     }
 
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        int width = MeasureSpec.getSize(widthMeasureSpec);
-        int height = MeasureSpec.getSize(heightMeasureSpec);
 
+    @Override
+    protected void measureContents(int width, int height) {
         int widthWithoutPadding = width - mPaddingLeft - mPaddingRight;
         int heightWithoutPadding = height - mPaddingTop - mPaddingBottom;
-        int taskBarHeight = getResources().getDimensionPixelSize(R.dimen.recents_task_bar_height);
 
         // Measure the content
         mContent.measure(MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(heightWithoutPadding, MeasureSpec.EXACTLY));
 
-        // Measure the bar view, and action button
-        mHeaderView.measure(MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
-                MeasureSpec.makeMeasureSpec(taskBarHeight, MeasureSpec.EXACTLY));
-        mActionButtonView.measure(
-                MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.AT_MOST),
-                MeasureSpec.makeMeasureSpec(heightWithoutPadding, MeasureSpec.AT_MOST));
-        // Measure the thumbnail to be square
-        mThumbnailView.measure(
-                MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
-                MeasureSpec.makeMeasureSpec(heightWithoutPadding, MeasureSpec.EXACTLY));
+        // Optimization: Prevent overdraw of the thumbnail under the header view
         mThumbnailView.updateClipToTaskBar(mHeaderView);
 
         setMeasuredDimension(width, height);
-        invalidateOutline();
     }
 
-    /** Synchronizes this view's properties with the task's transform */
-    void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform, int clipBottom,
-            int duration, Interpolator interpolator,
-            ValueAnimator.AnimatorUpdateListener updateCallback) {
+    void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform,
+            TaskViewAnimation toAnimation, ValueAnimator.AnimatorUpdateListener updateCallback) {
         RecentsConfiguration config = Recents.getConfiguration();
-        Utilities.cancelAnimationWithoutCallbacks(mClipAnimation);
+        Utilities.cancelAnimationWithoutCallbacks(mTransformAnimation);
 
-        // Apply the transform
-        toTransform.applyToTaskView(this, duration, interpolator, false,
-                !config.fakeShadows, updateCallback);
-
-        // Update the clipping
-        if (duration > 0) {
-            mClipAnimation = new AnimatorSet();
-            mClipAnimation.playTogether(
-                    ObjectAnimator.ofInt(mViewBounds, AnimateableViewBounds.CLIP_BOTTOM,
-                            mViewBounds.getClipBottom(), clipBottom),
-                    ObjectAnimator.ofInt(this, TaskViewTransform.LEFT, getLeft(),
-                            (int) toTransform.rect.left),
-                    ObjectAnimator.ofInt(this, TaskViewTransform.TOP, getTop(),
-                            (int) toTransform.rect.top),
-                    ObjectAnimator.ofInt(this, TaskViewTransform.RIGHT, getRight(),
-                            (int) toTransform.rect.right),
-                    ObjectAnimator.ofInt(this, TaskViewTransform.BOTTOM, getBottom(),
-                            (int) toTransform.rect.bottom),
-                    ObjectAnimator.ofFloat(mThumbnailView, TaskViewThumbnail.BITMAP_SCALE,
-                            mThumbnailView.getBitmapScale(), toTransform.thumbnailScale));
-            mClipAnimation.setStartDelay(toTransform.startDelay);
-            mClipAnimation.setDuration(duration);
-            mClipAnimation.setInterpolator(interpolator);
-            mClipAnimation.start();
+        // Compose the animations for the transform
+        mTmpAnimators.clear();
+        toTransform.applyToTaskView(this, mTmpAnimators, toAnimation, !config.fakeShadows);
+        if (toAnimation.isImmediate()) {
+            if (Float.compare(getTaskProgress(), toTransform.p) != 0) {
+                setTaskProgress(toTransform.p);
+            }
+            // Manually call back to the animator listener and update callback
+            if (toAnimation.listener != null) {
+                toAnimation.listener.onAnimationEnd(null);
+            }
+            if (updateCallback != null) {
+                updateCallback.onAnimationUpdate(null);
+            }
         } else {
-            mViewBounds.setClipBottom(clipBottom, false /* forceUpdate */);
-            mThumbnailView.setBitmapScale(toTransform.thumbnailScale);
-            setLeftTopRightBottom((int) toTransform.rect.left, (int) toTransform.rect.top,
-                    (int) toTransform.rect.right, (int) toTransform.rect.bottom);
-        }
-        if (!config.useHardwareLayers) {
-            mThumbnailView.updateThumbnailVisibility(clipBottom - getPaddingBottom());
-        }
+            if (Float.compare(getTaskProgress(), toTransform.p) != 0) {
+                mTmpAnimators.add(ObjectAnimator.ofFloat(this, TASK_PROGRESS, getTaskProgress(),
+                        toTransform.p));
+            }
+            if (updateCallback != null) {
+                ValueAnimator updateCallbackAnim = ValueAnimator.ofInt(0, 1);
+                updateCallbackAnim.addUpdateListener(updateCallback);
+                mTmpAnimators.add(updateCallbackAnim);
+            }
 
-        // Update the task progress
-        Utilities.cancelAnimationWithoutCallbacks(mTaskProgressAnimator);
-        if (duration <= 0) {
-            setTaskProgress(toTransform.p);
-        } else {
-            mTaskProgressAnimator = ObjectAnimator.ofFloat(this, "taskProgress", toTransform.p);
-            mTaskProgressAnimator.setDuration(duration);
-            mTaskProgressAnimator.addUpdateListener(mUpdateDimListener);
-            mTaskProgressAnimator.start();
+            // Create the animator
+            mTransformAnimation = toAnimation.createAnimator(mTmpAnimators);
+            mTransformAnimation.start();
         }
     }
 
     /** Resets this view's properties */
     void resetViewProperties() {
+        Utilities.cancelAnimationWithoutCallbacks(mTransformAnimation);
         setDim(0);
         setVisibility(View.VISIBLE);
         getViewBounds().reset();
+        getHeaderView().reset();
         TaskViewTransform.reset(this);
-        if (mActionButtonView != null) {
-            mActionButtonView.setScaleX(1f);
-            mActionButtonView.setScaleY(1f);
-            mActionButtonView.setAlpha(1f);
-            mActionButtonView.setTranslationZ(mActionButtonTranslationZ);
-        }
-    }
 
-    /** Prepares this task view for the enter-recents animations.  This is called earlier in the
-     * first layout because the actual animation into recents may take a long time. */
-    void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask, boolean hideTask,
-            boolean occludesLaunchTarget, int offscreenY) {
-        RecentsConfiguration config = Recents.getConfiguration();
-        RecentsActivityLaunchState launchState = config.getLaunchState();
-        int initialDim = getDim();
-        if (hideTask) {
-            setVisibility(View.INVISIBLE);
-        } else if (launchState.launchedHasConfigurationChanged) {
-            // Just load the views as-is
-        } else if (launchState.launchedFromAppWithThumbnail) {
-            if (isTaskViewLaunchTargetTask) {
-                // Set the dim to 0 so we can animate it in
-                initialDim = 0;
-                // Hide the action button
-                mActionButtonView.setAlpha(0f);
-            } else if (occludesLaunchTarget) {
-                // Move the task view off screen (below) so we can animate it in
-                setTranslationY(offscreenY);
-            }
-
-        } else if (launchState.launchedFromHome) {
-            // Move the task view off screen (below) so we can animate it in
-            setTranslationY(offscreenY);
-            setTranslationZ(0);
-            setScaleX(1f);
-            setScaleY(1f);
-        }
-        // Apply the current dim
-        setDim(initialDim);
-    }
-
-    /** Animates this task view as it enters recents */
-    void startEnterRecentsAnimation(final ViewAnimation.TaskViewEnterContext ctx) {
-        RecentsConfiguration config = Recents.getConfiguration();
-        RecentsActivityLaunchState launchState = config.getLaunchState();
-        Resources res = mContext.getResources();
-        final TaskViewTransform transform = ctx.currentTaskTransform;
-        final int taskViewEnterFromAppDuration = res.getInteger(
-                R.integer.recents_task_enter_from_app_duration);
-        final int taskViewEnterFromHomeDuration = res.getInteger(
-                R.integer.recents_task_enter_from_home_duration);
-        final int taskViewEnterFromHomeStaggerDelay = res.getInteger(
-                R.integer.recents_task_enter_from_home_stagger_delay);
-        final int taskViewAffiliateGroupEnterOffset = res.getDimensionPixelSize(
-                R.dimen.recents_task_view_affiliate_group_enter_offset);
-
-        if (launchState.launchedFromAppWithThumbnail) {
-            if (mTask.isLaunchTarget) {
-                // Immediately start the dim animation
-                animateDimToProgress(taskViewEnterFromAppDuration,
-                        ctx.postAnimationTrigger.decrementOnAnimationEnd());
-                ctx.postAnimationTrigger.increment();
-
-                // Animate the action button in
-                fadeInActionButton(taskViewEnterFromAppDuration);
-            } else {
-                // Animate the task up if it was occluding the launch target
-                if (ctx.currentTaskOccludesLaunchTarget) {
-                    setTranslationY(taskViewAffiliateGroupEnterOffset);
-                    setAlpha(0f);
-                    animate().alpha(1f)
-                            .translationY(0)
-                            .setUpdateListener(null)
-                            .setListener(new AnimatorListenerAdapter() {
-                                private boolean hasEnded;
-
-                                // We use the animation listener instead of withEndAction() to
-                                // ensure that onAnimationEnd() is called when the animator is
-                                // cancelled
-                                @Override
-                                public void onAnimationEnd(Animator animation) {
-                                    if (hasEnded) return;
-                                    ctx.postAnimationTrigger.decrement();
-                                    hasEnded = true;
-                                }
-                            })
-                            .setInterpolator(mFastOutSlowInInterpolator)
-                            .setDuration(taskViewEnterFromHomeDuration)
-                            .start();
-                    ctx.postAnimationTrigger.increment();
-                }
-            }
-
-        } else if (launchState.launchedFromHome) {
-            // Animate the tasks up
-            int frontIndex = (ctx.currentStackViewCount - ctx.currentStackViewIndex - 1);
-            int delay = frontIndex * taskViewEnterFromHomeStaggerDelay;
-
-            setScaleX(transform.scale);
-            setScaleY(transform.scale);
-            if (!config.fakeShadows) {
-                animate().translationZ(transform.translationZ);
-            }
-            animate()
-                    .translationY(0)
-                    .setStartDelay(delay)
-                    .setUpdateListener(ctx.updateListener)
-                    .setListener(new AnimatorListenerAdapter() {
-                        private boolean hasEnded;
-
-                        // We use the animation listener instead of withEndAction() to ensure that
-                        // onAnimationEnd() is called when the animator is cancelled
-                        @Override
-                        public void onAnimationEnd(Animator animation) {
-                            if (hasEnded) return;
-                            ctx.postAnimationTrigger.decrement();
-                            hasEnded = true;
-                        }
-                    })
-                    .setInterpolator(mQuintOutInterpolator)
-                    .setDuration(taskViewEnterFromHomeDuration +
-                            frontIndex * taskViewEnterFromHomeStaggerDelay)
-                    .start();
-            ctx.postAnimationTrigger.increment();
-        }
-    }
-
-    public void cancelEnterRecentsAnimation() {
-        animate().cancel();
-    }
-
-    public void fadeInActionButton(int duration) {
-        // Hide the action button
+        mActionButtonView.setScaleX(1f);
+        mActionButtonView.setScaleY(1f);
         mActionButtonView.setAlpha(0f);
-
-        // Animate the action button in
-        mActionButtonView.animate().alpha(1f)
-                .setDuration(duration)
-                .setInterpolator(PhoneStatusBar.ALPHA_IN)
-                .start();
+        mActionButtonView.setTranslationZ(mActionButtonTranslationZ);
     }
 
-    /** Animates this task view as it leaves recents by pressing home. */
-    void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
-        int taskViewExitToHomeDuration = getResources().getInteger(
-                R.integer.recents_task_exit_to_home_duration);
-        animate()
-                .translationY(ctx.offscreenTranslationY)
-                .setStartDelay(0)
-                .setUpdateListener(null)
-                .setListener(null)
-                .setInterpolator(mFastOutLinearInInterpolator)
-                .setDuration(taskViewExitToHomeDuration)
-                .withEndAction(ctx.postAnimationTrigger.decrementAsRunnable())
-                .start();
-        ctx.postAnimationTrigger.increment();
-    }
-
-    /** Animates this task view as it exits recents */
-    void startLaunchTaskAnimation(final Runnable postAnimRunnable, boolean isLaunchingTask,
-            boolean occludesLaunchTarget, boolean lockToTask) {
-        final int taskViewExitToAppDuration = mContext.getResources().getInteger(
-                R.integer.recents_task_exit_to_app_duration);
-        final int taskViewAffiliateGroupEnterOffset = mContext.getResources().getDimensionPixelSize(
-                R.dimen.recents_task_view_affiliate_group_enter_offset);
-
-        if (isLaunchingTask) {
-            // Animate the dim
-            if (mDimAlpha > 0) {
-                ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", 0);
-                anim.setDuration(taskViewExitToAppDuration);
-                anim.setInterpolator(mFastOutLinearInInterpolator);
-                anim.start();
-            }
-
-            // Animate the action button away
-            if (!lockToTask) {
-                float toScale = 0.9f;
-                mActionButtonView.animate()
-                        .scaleX(toScale)
-                        .scaleY(toScale);
-            }
-            mActionButtonView.animate()
-                    .alpha(0f)
-                    .setStartDelay(0)
-                    .setDuration(taskViewExitToAppDuration)
-                    .setInterpolator(mFastOutLinearInInterpolator)
-                    .withEndAction(postAnimRunnable)
-                    .start();
-        } else {
-            // Hide the dismiss button
-            mHeaderView.startLaunchTaskDismissAnimation(postAnimRunnable);
-            // If this is another view in the task grouping and is in front of the launch task,
-            // animate it away first
-            if (occludesLaunchTarget) {
-                animate().alpha(0f)
-                    .translationY(getTranslationY() + taskViewAffiliateGroupEnterOffset)
-                    .setStartDelay(0)
-                    .setUpdateListener(null)
-                    .setListener(null)
-                    .setInterpolator(mFastOutLinearInInterpolator)
-                    .setDuration(taskViewExitToAppDuration)
-                    .start();
-            }
-        }
-    }
-
-    /** Animates the deletion of this task view */
-    void startDeleteTaskAnimation(final Runnable r, int delay) {
-        int taskViewRemoveAnimDuration = getResources().getInteger(
-                R.integer.recents_animate_task_view_remove_duration);
-        int taskViewRemoveAnimTranslationXPx = getResources().getDimensionPixelSize(
-                R.dimen.recents_task_view_remove_anim_translation_x);
-
-        // Disabling clipping with the stack while the view is animating away
-        setClipViewInStack(false);
-
-        animate().translationX(taskViewRemoveAnimTranslationXPx)
-            .alpha(0f)
-            .setStartDelay(delay)
-            .setUpdateListener(null)
-            .setListener(null)
-            .setInterpolator(mFastOutSlowInInterpolator)
-            .setDuration(taskViewRemoveAnimDuration)
-            .withEndAction(new Runnable() {
-                @Override
-                public void run() {
-                    if (r != null) {
-                        r.run();
-                    }
-
-                    // Re-enable clipping with the stack (we will reuse this view)
-                    setClipViewInStack(true);
-                }
-            })
-            .start();
+    /**
+     * Cancels any current transform animations.
+     */
+    public void cancelTransformAnimation() {
+        Utilities.cancelAnimationWithoutCallbacks(mTransformAnimation);
     }
 
     /** Enables/disables handling touch on this task view. */
@@ -545,12 +320,14 @@
     void dismissTask() {
         // Animate out the view and call the callback
         final TaskView tv = this;
-        startDeleteTaskAnimation(new Runnable() {
+        DismissTaskViewEvent dismissEvent = new DismissTaskViewEvent(tv, mTask);
+        dismissEvent.addPostAnimationCallback(new Runnable() {
             @Override
             public void run() {
-                EventBus.getDefault().send(new DismissTaskViewEvent(mTask, tv));
+                EventBus.getDefault().send(new TaskViewDismissedEvent(mTask, tv));
             }
-        }, 0);
+        });
+        EventBus.getDefault().send(dismissEvent);
     }
 
     /**
@@ -582,6 +359,10 @@
         updateDimFromTaskProgress();
     }
 
+    public TaskViewHeader getHeaderView() {
+        return mHeaderView;
+    }
+
     /** Returns the current task progress. */
     public float getTaskProgress() {
         return mTaskProgress;
@@ -601,12 +382,8 @@
             }
         } else {
             float dimAlpha = mDimAlpha / 255.0f;
-            if (mThumbnailView != null) {
-                mThumbnailView.setDimAlpha(dimAlpha);
-            }
-            if (mHeaderView != null) {
-                mHeaderView.setDimAlpha(dim);
-            }
+            mThumbnailView.setDimAlpha(dimAlpha);
+            mHeaderView.setDimAlpha(dimAlpha);
         }
     }
 
@@ -616,18 +393,18 @@
     }
 
     /** Animates the dim to the task progress. */
-    void animateDimToProgress(int duration, Animator.AnimatorListener postAnimRunnable) {
+    void animateDimToProgress(int duration, Animator.AnimatorListener animListener) {
         // Animate the dim into view as well
         int toDim = getDimFromTaskProgress();
         if (toDim != getDim()) {
-            ObjectAnimator anim = ObjectAnimator.ofInt(TaskView.this, "dim", toDim);
+            ObjectAnimator anim = ObjectAnimator.ofInt(this, DIM, getDim(), toDim);
             anim.setDuration(duration);
-            if (postAnimRunnable != null) {
-                anim.addListener(postAnimRunnable);
+            if (animListener != null) {
+                anim.addListener(animListener);
             }
             anim.start();
         } else {
-            postAnimRunnable.onAnimationEnd(null);
+            animListener.onAnimationEnd(null);
         }
     }
 
@@ -645,19 +422,10 @@
         setDim(getDimFromTaskProgress());
     }
 
-    /**** View focus state ****/
-
     /**
      * Explicitly sets the focused state of this task.
      */
-    public void setFocusedState(boolean isFocused, boolean animated, boolean requestViewFocus) {
-        if (DEBUG) {
-            Log.d(TAG, "setFocusedState: " + mTask.activityLabel + " focused: " + isFocused +
-                    " animated: " + animated + " requestViewFocus: " + requestViewFocus +
-                    " isFocused(): " + isFocused() +
-                    " isAccessibilityFocused(): " + isAccessibilityFocused());
-        }
-
+    public void setFocusedState(boolean isFocused, boolean requestViewFocus) {
         SystemServicesProxy ssp = Recents.getSystemServices();
         if (isFocused) {
             if (requestViewFocus && !isFocused()) {
@@ -673,45 +441,125 @@
         }
     }
 
-    /**** TaskCallbacks Implementation ****/
+    /**
+     * Shows the action button.
+     * @param fadeIn whether or not to animate the action button in.
+     * @param fadeInDuration the duration of the action button animation, only used if
+     *                       {@param fadeIn} is true.
+     */
+    public void showActionButton(boolean fadeIn, int fadeInDuration) {
+        mActionButtonView.setVisibility(View.VISIBLE);
 
-    /** Binds this task view to the task */
-    public void onTaskBound(Task t) {
-        mTask = t;
-        mTask.setCallbacks(this);
+        if (fadeIn && mActionButtonView.getAlpha() < 1f) {
+            mActionButtonView.animate()
+                    .alpha(1f)
+                    .scaleX(1f)
+                    .scaleY(1f)
+                    .setDuration(fadeInDuration)
+                    .setInterpolator(PhoneStatusBar.ALPHA_IN)
+                    .start();
+        } else {
+            mActionButtonView.setScaleX(1f);
+            mActionButtonView.setScaleY(1f);
+            mActionButtonView.setAlpha(1f);
+            mActionButtonView.setTranslationZ(mActionButtonTranslationZ);
+        }
+    }
 
-        // Hide the action button if lock to app is disabled for this view
-        int lockButtonVisibility = (!t.lockToTaskEnabled || !t.lockToThisTask) ? GONE : VISIBLE;
-        if (mActionButtonView.getVisibility() != lockButtonVisibility) {
-            mActionButtonView.setVisibility(lockButtonVisibility);
-            requestLayout();
+    /**
+     * Immediately hides the action button.
+     *
+     * @param fadeOut whether or not to animate the action button out.
+     */
+    public void hideActionButton(boolean fadeOut, int fadeOutDuration, boolean scaleDown,
+            final Animator.AnimatorListener animListener) {
+        if (fadeOut && mActionButtonView.getAlpha() > 0f) {
+            if (scaleDown) {
+                float toScale = 0.9f;
+                mActionButtonView.animate()
+                        .scaleX(toScale)
+                        .scaleY(toScale);
+            }
+            mActionButtonView.animate()
+                    .alpha(0f)
+                    .setDuration(fadeOutDuration)
+                    .setInterpolator(PhoneStatusBar.ALPHA_OUT)
+                    .withEndAction(new Runnable() {
+                        @Override
+                        public void run() {
+                            if (animListener != null) {
+                                animListener.onAnimationEnd(null);
+                            }
+                            mActionButtonView.setVisibility(View.INVISIBLE);
+                        }
+                    })
+                    .start();
+        } else {
+            mActionButtonView.setAlpha(0f);
+            mActionButtonView.setVisibility(View.INVISIBLE);
+            if (animListener != null) {
+                animListener.onAnimationEnd(null);
+            }
+        }
+    }
+
+    /**** TaskStackAnimationHelper.Callbacks Implementation ****/
+
+    @Override
+    public void onPrepareLaunchTargetForEnterAnimation() {
+        // These values will be animated in when onStartLaunchTargetEnterAnimation() is called
+        setDim(0);
+        mActionButtonView.setAlpha(0f);
+    }
+
+    @Override
+    public void onStartLaunchTargetEnterAnimation(int duration, boolean screenPinningEnabled,
+            ReferenceCountedTrigger postAnimationTrigger) {
+        postAnimationTrigger.increment();
+        animateDimToProgress(duration, postAnimationTrigger.decrementOnAnimationEnd());
+
+        if (screenPinningEnabled) {
+            showActionButton(true /* fadeIn */, duration /* fadeInDuration */);
         }
     }
 
     @Override
-    public void onTaskDataLoaded() {
-        if (mThumbnailView != null && mHeaderView != null) {
-            // Bind each of the views to the new task data
-            mThumbnailView.rebindToTask(mTask);
-            mHeaderView.rebindToTask(mTask);
-
-            // Rebind any listeners
-            mActionButtonView.setOnClickListener(this);
-            setOnLongClickListener(this);
+    public void onStartLaunchTargetLaunchAnimation(int duration, boolean screenPinningRequested,
+            ReferenceCountedTrigger postAnimationTrigger) {
+        if (mDimAlpha > 0) {
+            ObjectAnimator anim = ObjectAnimator.ofInt(this, DIM, getDim(), 0);
+            anim.setDuration(duration);
+            anim.setInterpolator(PhoneStatusBar.ALPHA_OUT);
+            anim.start();
         }
+
+        postAnimationTrigger.increment();
+        hideActionButton(true /* fadeOut */, duration,
+                !screenPinningRequested /* scaleDown */,
+                postAnimationTrigger.decrementOnAnimationEnd());
+    }
+
+    /**** TaskCallbacks Implementation ****/
+
+    public void onTaskBound(Task t) {
+        mTask = t;
+        mTask.addCallback(this);
+    }
+
+    @Override
+    public void onTaskDataLoaded(Task task) {
+        // Bind each of the views to the new task data
+        mThumbnailView.rebindToTask(mTask);
+        mHeaderView.rebindToTask(mTask);
         mTaskDataLoaded = true;
     }
 
     @Override
     public void onTaskDataUnloaded() {
-        if (mThumbnailView != null && mHeaderView != null) {
-            // Unbind each of the views from the task data and remove the task callback
-            mTask.setCallbacks(null);
-            mThumbnailView.unbindFromTask();
-            mHeaderView.unbindFromTask();
-            // Unbind any listeners
-            mActionButtonView.setOnClickListener(null);
-        }
+        // Unbind each of the views from the task data and remove the task callback
+        mTask.removeCallback(this);
+        mThumbnailView.unbindFromTask();
+        mHeaderView.unbindFromTask();
         mTaskDataLoaded = false;
     }
 
@@ -747,17 +595,6 @@
             // Start listening for drag events
             setClipViewInStack(false);
 
-            // Enlarge the view slightly
-            final float finalScale = getScaleX() * 1.05f;
-            animate()
-                    .scaleX(finalScale)
-                    .scaleY(finalScale)
-                    .setDuration(175)
-                    .setUpdateListener(null)
-                    .setListener(null)
-                    .setInterpolator(mFastOutSlowInInterpolator)
-                    .start();
-
             mDownTouchPos.x += ((1f - getScaleX()) * getWidth()) / 2;
             mDownTouchPos.y += ((1f - getScaleY()) * getHeight()) / 2;
 
@@ -772,7 +609,7 @@
 
     public final void onBusEvent(DragEndEvent event) {
         if (!(event.dropTarget instanceof TaskStack.DockState)) {
-            event.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
+            event.addPostAnimationCallback(new Runnable() {
                 @Override
                 public void run() {
                     // Animate the drag view back from where it is, to the view location, then after
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAnimation.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAnimation.java
new file mode 100644
index 0000000..74b16d0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAnimation.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.recents.views;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+
+import java.util.List;
+
+/**
+ * The animation properties to animate a {@link TaskView} to a given {@link TaskViewTransform}.
+ */
+public class TaskViewAnimation {
+
+    public static final TaskViewAnimation IMMEDIATE = new TaskViewAnimation(0,
+            new LinearInterpolator());
+
+    public final int startDelay;
+    public final int duration;
+    public final Interpolator interpolator;
+    public final Animator.AnimatorListener listener;
+
+    public TaskViewAnimation(int duration, Interpolator interpolator) {
+        this(0 /* startDelay */, duration, interpolator, null);
+    }
+
+    public TaskViewAnimation(int duration, Interpolator interpolator,
+            Animator.AnimatorListener listener) {
+        this(0 /* startDelay */, duration, interpolator, listener);
+    }
+
+    public TaskViewAnimation(int startDelay, int duration, Interpolator interpolator) {
+        this(startDelay, duration, interpolator, null);
+    }
+
+    public TaskViewAnimation(int startDelay, int duration, Interpolator interpolator,
+            Animator.AnimatorListener listener) {
+        this.startDelay = startDelay;
+        this.duration = duration;
+        this.interpolator = interpolator;
+        this.listener = listener;
+    }
+
+    /**
+     * Creates a new {@link AnimatorSet} that will animate the given animators with the current
+     * animation properties.
+     */
+    public AnimatorSet createAnimator(List<Animator> animators) {
+        AnimatorSet anim = new AnimatorSet();
+        anim.setStartDelay(startDelay);
+        anim.setDuration(duration);
+        anim.setInterpolator(interpolator);
+        if (listener != null) {
+            anim.addListener(listener);
+        }
+        anim.playTogether(animators);
+        return anim;
+    }
+
+    /**
+     * Returns whether this animation has any duration.
+     */
+    public boolean isImmediate() {
+        return duration <= 0;
+    }
+}
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 0271ccd..36760f7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -5,7 +5,7 @@
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,24 +16,32 @@
 
 package com.android.systemui.recents.views;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.annotation.Nullable;
+import android.content.ComponentName;
 import android.content.Context;
-import android.content.res.ColorStateList;
+import android.content.pm.ActivityInfo;
+import android.content.res.Resources;
 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.PorterDuffXfermode;
 import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.GradientDrawable;
-import android.graphics.drawable.RippleDrawable;
+import android.os.CountDownTimer;
+import android.support.v4.graphics.ColorUtils;
 import android.util.AttributeSet;
 import android.view.View;
+import android.view.ViewAnimationUtils;
+import android.view.ViewStub;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
+import android.widget.ProgressBar;
 import android.widget.TextView;
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
@@ -50,38 +58,116 @@
 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 
-
 /* The task bar view */
 public class TaskViewHeader extends FrameLayout
         implements View.OnClickListener, View.OnLongClickListener {
 
+    private static final float HIGHLIGHT_LIGHTNESS_INCREMENT = 0.125f;
+    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;
+
+    /**
+     * A color drawable that draws a slight highlight at the top to help it stand out.
+     */
+    private class HighlightColorDrawable extends Drawable {
+
+        private Paint mHighlightPaint = new Paint();
+        private Paint mBackgroundPaint = new Paint();
+
+        public HighlightColorDrawable() {
+            mBackgroundPaint.setColor(Color.argb(255, 0, 0, 0));
+            mBackgroundPaint.setAntiAlias(true);
+            mHighlightPaint.setColor(Color.argb(255, 255, 255, 255));
+            mHighlightPaint.setAntiAlias(true);
+        }
+
+        public void setColorAndDim(int color, float dimAlpha) {
+            mBackgroundPaint.setColor(color);
+
+            ColorUtils.colorToHSL(color, mTmpHSL);
+            // TODO: Consider using the saturation of the color to adjust the lightness as well
+            mTmpHSL[2] = Math.min(1f,
+                    mTmpHSL[2] + HIGHLIGHT_LIGHTNESS_INCREMENT * (1.0f - dimAlpha));
+            mHighlightPaint.setColor(ColorUtils.HSLToColor(mTmpHSL));
+
+            invalidateSelf();
+        }
+
+        @Override
+        public void setColorFilter(@Nullable ColorFilter colorFilter) {
+            // Do nothing
+        }
+
+        @Override
+        public void setAlpha(int alpha) {
+            // Do nothing
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            // Draw the highlight at the top edge (but put the bottom edge just out of view)
+            canvas.drawRoundRect(0, 0, mTaskViewRect.width(),
+                    2 * Math.max(mHighlightHeight, mCornerRadius),
+                    mCornerRadius, mCornerRadius, mHighlightPaint);
+
+            // Draw the background with the rounded corners
+            canvas.drawRoundRect(0, mHighlightHeight, mTaskViewRect.width(),
+                    getHeight() + mCornerRadius,
+                    mCornerRadius, mCornerRadius, mBackgroundPaint);
+        }
+
+        @Override
+        public int getOpacity() {
+            return PixelFormat.OPAQUE;
+        }
+    }
+
     Task mTask;
 
     // Header views
+    ImageView mIconView;
+    TextView mTitleView;
     ImageView mMoveTaskButton;
     ImageView mDismissButton;
-    ImageView mApplicationIcon;
-    TextView mActivityDescription;
-    int mMoveTaskTargetStackId = INVALID_STACK_ID;
+    ViewStub mAppOverlayViewStub;
+    FrameLayout mAppOverlayView;
+    ImageView mAppIconView;
+    ImageView mAppInfoView;
+    TextView mAppTitleView;
+    ViewStub mFocusTimerIndicatorStub;
+    ProgressBar mFocusTimerIndicator;
 
     // Header drawables
     Rect mTaskViewRect = new Rect();
     int mCornerRadius;
     int mHighlightHeight;
+    float mDimAlpha;
     Drawable mLightDismissDrawable;
     Drawable mDarkDismissDrawable;
-    RippleDrawable mBackground;
-    GradientDrawable mBackgroundColorDrawable;
-    String mDismissContentDescription;
+    Drawable mLightFreeformIcon;
+    Drawable mDarkFreeformIcon;
+    Drawable mLightFullscreenIcon;
+    Drawable mDarkFullscreenIcon;
+    Drawable mLightInfoIcon;
+    Drawable mDarkInfoIcon;
+    int mTaskBarViewLightTextColor;
+    int mTaskBarViewDarkTextColor;
+    int mMoveTaskTargetStackId = INVALID_STACK_ID;
 
-    // Static highlight that we draw at the top of each view
-    static Paint sHighlightPaint;
+    // Header background
+    private HighlightColorDrawable mBackground;
+    private HighlightColorDrawable mOverlayBackground;
+    private float[] mTmpHSL = new float[3];
 
     // Header dim, which is only used when task view hardware layers are not used
-    Paint mDimLayerPaint = new Paint();
+    private Paint mDimLayerPaint = new Paint();
 
     Interpolator mFastOutSlowInInterpolator;
     Interpolator mFastOutLinearInInterpolator;
+    Interpolator mLinearOutSlowInInterpolator;
+
+    private CountDownTimer mFocusTimerCountDown;
 
     public TaskViewHeader(Context context) {
         this(context, null);
@@ -100,55 +186,55 @@
         setWillNotDraw(false);
 
         // Load the dismiss resources
-        mDimLayerPaint.setColor(Color.argb(0, 0, 0, 0));
+        Resources res = context.getResources();
         mLightDismissDrawable = context.getDrawable(R.drawable.recents_dismiss_light);
         mDarkDismissDrawable = context.getDrawable(R.drawable.recents_dismiss_dark);
-        mDismissContentDescription =
-                context.getString(R.string.accessibility_recents_item_will_be_dismissed);
-        mCornerRadius = getResources().getDimensionPixelSize(
-                R.dimen.recents_task_view_rounded_corners_radius);
-        mHighlightHeight = getResources().getDimensionPixelSize(
-                R.dimen.recents_task_view_highlight);
+        mCornerRadius = res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius);
+        mHighlightHeight = res.getDimensionPixelSize(R.dimen.recents_task_view_highlight);
+        mTaskBarViewLightTextColor = context.getColor(R.color.recents_task_bar_light_text_color);
+        mTaskBarViewDarkTextColor = context.getColor(R.color.recents_task_bar_dark_text_color);
+        mLightFreeformIcon = context.getDrawable(R.drawable.recents_move_task_freeform_light);
+        mDarkFreeformIcon = context.getDrawable(R.drawable.recents_move_task_freeform_dark);
+        mLightFullscreenIcon = context.getDrawable(R.drawable.recents_move_task_fullscreen_light);
+        mDarkFullscreenIcon = context.getDrawable(R.drawable.recents_move_task_fullscreen_dark);
+        mLightInfoIcon = context.getDrawable(R.drawable.recents_info_light);
+        mDarkInfoIcon = context.getDrawable(R.drawable.recents_info_dark);
+
         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
                 com.android.internal.R.interpolator.fast_out_slow_in);
         mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
                 com.android.internal.R.interpolator.fast_out_linear_in);
+        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.linear_out_slow_in);
 
-        // Configure the highlight paint
-        if (sHighlightPaint == null) {
-            sHighlightPaint = new Paint();
-            sHighlightPaint.setStyle(Paint.Style.STROKE);
-            sHighlightPaint.setStrokeWidth(mHighlightHeight);
-            sHighlightPaint.setColor(context.getColor(R.color.recents_task_bar_highlight_color));
-            sHighlightPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
-            sHighlightPaint.setAntiAlias(true);
-        }
+        // Configure the background and dim
+        mBackground = new HighlightColorDrawable();
+        mBackground.setColorAndDim(Color.argb(255, 0, 0, 0), 0f);
+        setBackground(mBackground);
+        mOverlayBackground = new HighlightColorDrawable();
+        mDimLayerPaint.setColor(Color.argb(255, 0, 0, 0));
+        mDimLayerPaint.setAntiAlias(true);
+    }
+
+    /**
+     * Resets this header along with the TaskView.
+     */
+    public void reset() {
+        hideAppOverlay(true /* immediate */);
     }
 
     @Override
     protected void onFinishInflate() {
         // Initialize the icon and description views
-        mApplicationIcon = (ImageView) findViewById(R.id.application_icon);
-        mApplicationIcon.setOnLongClickListener(this);
-        mActivityDescription = (TextView) findViewById(R.id.activity_description);
+        mIconView = (ImageView) findViewById(R.id.icon);
+        mIconView.setClickable(false);
+        mIconView.setOnLongClickListener(this);
+        mTitleView = (TextView) findViewById(R.id.title);
         mDismissButton = (ImageView) findViewById(R.id.dismiss_task);
         mDismissButton.setOnClickListener(this);
         mMoveTaskButton = (ImageView) findViewById(R.id.move_task);
-
-        // Hide the backgrounds if they are ripple drawables
-        if (mApplicationIcon.getBackground() instanceof RippleDrawable) {
-            mApplicationIcon.setBackground(null);
-        }
-
-        mBackgroundColorDrawable = (GradientDrawable) getContext().getDrawable(
-                R.drawable.recents_task_view_header_bg_color);
-        // Copy the ripple drawable since we are going to be manipulating it
-        mBackground = (RippleDrawable)
-                getContext().getDrawable(R.drawable.recents_task_view_header_bg);
-        mBackground = (RippleDrawable) mBackground.mutate().getConstantState().newDrawable();
-        mBackground.setColor(ColorStateList.valueOf(0));
-        mBackground.setDrawableByLayerId(mBackground.getId(0), mBackgroundColorDrawable);
-        setBackground(mBackground);
+        mFocusTimerIndicatorStub = (ViewStub) findViewById(R.id.focus_timer_indicator_stub);
+        mAppOverlayViewStub = (ViewStub) findViewById(R.id.app_overlay_stub);
     }
 
     /**
@@ -156,10 +242,14 @@
      * to match the frame changes.
      */
     public void onTaskViewSizeChanged(int width, int height) {
+        // TODO: Optimize this path
         mTaskViewRect.set(0, 0, width, height);
         boolean updateMoveTaskButton = mMoveTaskButton.getVisibility() != View.GONE;
-        int appIconWidth = mApplicationIcon.getMeasuredWidth();
-        int activityDescWidth = mActivityDescription.getMeasuredWidth();
+        boolean isFreeformTask = (mTask != null) && mTask.isFreeformTask();
+        int appIconWidth = mIconView.getMeasuredWidth();
+        int activityDescWidth = (mTask != null)
+                ? (int) mTitleView.getPaint().measureText(mTask.title)
+                : mTitleView.getMeasuredWidth();
         int dismissIconWidth = mDismissButton.getMeasuredWidth();
         int moveTaskIconWidth = mMoveTaskButton.getVisibility() == View.VISIBLE
                 ? mMoveTaskButton.getMeasuredWidth()
@@ -167,27 +257,28 @@
 
         // Priority-wise, we show the activity icon first, the dismiss icon if there is room, the
         // move-task icon if there is room, and then finally, the activity label if there is room
-        if (width < (appIconWidth + dismissIconWidth)) {
-            mActivityDescription.setVisibility(View.INVISIBLE);
+        if (isFreeformTask && width < (appIconWidth + dismissIconWidth)) {
+            mTitleView.setVisibility(View.INVISIBLE);
             if (updateMoveTaskButton) {
                 mMoveTaskButton.setVisibility(View.INVISIBLE);
             }
             mDismissButton.setVisibility(View.INVISIBLE);
-        } else if (width < (appIconWidth + dismissIconWidth + moveTaskIconWidth)) {
-            mActivityDescription.setVisibility(View.INVISIBLE);
+        } else if (isFreeformTask && width < (appIconWidth + dismissIconWidth +
+                moveTaskIconWidth)) {
+            mTitleView.setVisibility(View.INVISIBLE);
             if (updateMoveTaskButton) {
                 mMoveTaskButton.setVisibility(View.INVISIBLE);
             }
             mDismissButton.setVisibility(View.VISIBLE);
-        } else if (width < (appIconWidth + dismissIconWidth + moveTaskIconWidth +
+        } else if (isFreeformTask && width < (appIconWidth + dismissIconWidth + moveTaskIconWidth +
                 activityDescWidth)) {
-            mActivityDescription.setVisibility(View.INVISIBLE);
+            mTitleView.setVisibility(View.INVISIBLE);
             if (updateMoveTaskButton) {
                 mMoveTaskButton.setVisibility(View.VISIBLE);
             }
             mDismissButton.setVisibility(View.VISIBLE);
         } else {
-            mActivityDescription.setVisibility(View.VISIBLE);
+            mTitleView.setVisibility(View.VISIBLE);
             if (updateMoveTaskButton) {
                 mMoveTaskButton.setVisibility(View.VISIBLE);
             }
@@ -201,31 +292,81 @@
     }
 
     @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        onTaskViewSizeChanged(mTaskViewRect.width(), mTaskViewRect.height());
+    protected void dispatchDraw(Canvas canvas) {
+        super.dispatchDraw(canvas);
+
+        // Draw the dim layer with the rounded corners
+        canvas.drawRoundRect(0, 0, mTaskViewRect.width(), getHeight() + mCornerRadius,
+                mCornerRadius, mCornerRadius, mDimLayerPaint);
     }
 
-    @Override
-    protected void onDraw(Canvas canvas) {
-        // Draw the highlight at the top edge (but put the bottom edge just out of view)
-        float offset = (float) Math.ceil(mHighlightHeight / 2f);
-        float radius = mCornerRadius;
-        int count = canvas.save(Canvas.CLIP_SAVE_FLAG);
-        canvas.clipRect(0, 0, mTaskViewRect.width(), getMeasuredHeight());
-        canvas.drawRoundRect(-offset, 0f, (float) mTaskViewRect.width() + offset,
-                getMeasuredHeight() + radius, radius, radius, sHighlightPaint);
-        canvas.restoreToCount(count);
+    /** Starts the focus timer. */
+    public void startFocusTimerIndicator(int duration) {
+        if (mFocusTimerIndicator == null) {
+            return;
+        }
+
+        mFocusTimerIndicator.setVisibility(View.VISIBLE);
+        mFocusTimerIndicator.setMax(duration);
+        mFocusTimerIndicator.setProgress(duration);
+        if (mFocusTimerCountDown != null) {
+            mFocusTimerCountDown.cancel();
+        }
+        mFocusTimerCountDown = new CountDownTimer(duration,
+                FOCUS_INDICATOR_INTERVAL_MS) {
+            public void onTick(long millisUntilFinished) {
+                mFocusTimerIndicator.setProgress((int) millisUntilFinished);
+            }
+
+            public void onFinish() {
+                // Do nothing
+            }
+        }.start();
+    }
+
+    /** Cancels the focus timer. */
+    public void cancelFocusTimerIndicator() {
+        if (mFocusTimerIndicator == null) {
+            return;
+        }
+
+        if (mFocusTimerCountDown != null) {
+            mFocusTimerCountDown.cancel();
+            mFocusTimerIndicator.setProgress(0);
+            mFocusTimerIndicator.setVisibility(View.INVISIBLE);
+        }
+    }
+
+    /** Returns the secondary color for a primary color. */
+    int getSecondaryColor(int primaryColor, boolean useLightOverlayColor) {
+        int overlayColor = useLightOverlayColor ? Color.WHITE : Color.BLACK;
+        return Utilities.getColorWithOverlay(primaryColor, overlayColor, 0.8f);
     }
 
     /**
      * Sets the dim alpha, only used when we are not using hardware layers.
      * (see RecentsConfiguration.useHardwareLayers)
      */
-    void setDimAlpha(int alpha) {
-        mDimLayerPaint.setColor(Color.argb(alpha, 0, 0, 0));
+    void setDimAlpha(float dimAlpha) {
+        mDimAlpha = dimAlpha;
+        updateBackgroundColor(dimAlpha);
         invalidate();
     }
 
+    /**
+     * Updates the background and highlight colors for this header.
+     */
+    private void updateBackgroundColor(float dimAlpha) {
+        if (mTask != null) {
+            mBackground.setColorAndDim(mTask.colorPrimary, dimAlpha);
+            // TODO: Consider using the saturation of the color to adjust the lightness as well
+            ColorUtils.colorToHSL(mTask.colorPrimary, mTmpHSL);
+            mTmpHSL[2] = Math.min(1f, mTmpHSL[2] + OVERLAY_LIGHTNESS_INCREMENT * (1.0f - dimAlpha));
+            mOverlayBackground.setColorAndDim(ColorUtils.HSLToColor(mTmpHSL), dimAlpha);
+            mDimLayerPaint.setAlpha((int) (dimAlpha * 255));
+        }
+    }
+
     /** Binds the bar view to the task */
     public void rebindToTask(Task t) {
         SystemServicesProxy ssp = Recents.getSystemServices();
@@ -233,82 +374,64 @@
 
         // If an activity icon is defined, then we use that as the primary icon to show in the bar,
         // otherwise, we fall back to the application icon
-        if (t.activityIcon != null) {
-            mApplicationIcon.setImageDrawable(t.activityIcon);
-        } else if (t.applicationIcon != null) {
-            mApplicationIcon.setImageDrawable(t.applicationIcon);
+        updateBackgroundColor(mDimAlpha);
+        if (t.icon != null) {
+            mIconView.setImageDrawable(t.icon);
         }
-        if (!mActivityDescription.getText().toString().equals(t.activityLabel)) {
-            mActivityDescription.setText(t.activityLabel);
+        if (!mTitleView.getText().toString().equals(t.title)) {
+            mTitleView.setText(t.title);
         }
-        mActivityDescription.setContentDescription(t.contentDescription);
-
-        // Try and apply the system ui tint
-        int existingBgColor = (getBackground() instanceof ColorDrawable) ?
-                ((ColorDrawable) getBackground()).getColor() : 0;
-        if (existingBgColor != t.colorPrimary) {
-            mBackgroundColorDrawable.setColor(t.colorPrimary);
-        }
-
-        int taskBarViewLightTextColor = getResources().getColor(
-                R.color.recents_task_bar_light_text_color);
-        int taskBarViewDarkTextColor = getResources().getColor(
-                R.color.recents_task_bar_dark_text_color);
-        mActivityDescription.setTextColor(t.useLightOnPrimaryColor ?
-                taskBarViewLightTextColor : taskBarViewDarkTextColor);
+        mTitleView.setContentDescription(t.contentDescription);
+        mTitleView.setTextColor(t.useLightOnPrimaryColor ?
+                mTaskBarViewLightTextColor : mTaskBarViewDarkTextColor);
         mDismissButton.setImageDrawable(t.useLightOnPrimaryColor ?
                 mLightDismissDrawable : mDarkDismissDrawable);
-        mDismissButton.setContentDescription(String.format(mDismissContentDescription,
-                t.contentDescription));
+        mDismissButton.setContentDescription(t.dismissDescription);
 
         // When freeform workspaces are enabled, then update the move-task button depending on the
         // current task
         if (ssp.hasFreeformWorkspaceSupport()) {
             if (t.isFreeformTask()) {
                 mMoveTaskTargetStackId = FULLSCREEN_WORKSPACE_STACK_ID;
-                mMoveTaskButton.setImageResource(t.useLightOnPrimaryColor
-                        ? R.drawable.recents_move_task_fullscreen_light
-                        : R.drawable.recents_move_task_fullscreen_dark);
+                mMoveTaskButton.setImageDrawable(t.useLightOnPrimaryColor
+                        ? mLightFullscreenIcon
+                        : mDarkFullscreenIcon);
             } else {
                 mMoveTaskTargetStackId = FREEFORM_WORKSPACE_STACK_ID;
-                mMoveTaskButton.setImageResource(t.useLightOnPrimaryColor
-                        ? R.drawable.recents_move_task_freeform_light
-                        : R.drawable.recents_move_task_freeform_dark);
+                mMoveTaskButton.setImageDrawable(t.useLightOnPrimaryColor
+                        ? mLightFreeformIcon
+                        : mDarkFreeformIcon);
             }
-            mMoveTaskButton.setVisibility(View.VISIBLE);
+            if (mMoveTaskButton.getVisibility() != View.VISIBLE) {
+                mMoveTaskButton.setVisibility(View.VISIBLE);
+            }
             mMoveTaskButton.setOnClickListener(this);
         }
 
+        if (Recents.getDebugFlags().isFastToggleRecentsEnabled()) {
+            if (mFocusTimerIndicator == null) {
+                mFocusTimerIndicator = (ProgressBar) mFocusTimerIndicatorStub.inflate();
+            }
+            mFocusTimerIndicator.getProgressDrawable()
+                    .setColorFilter(
+                            getSecondaryColor(t.colorPrimary, t.useLightOnPrimaryColor),
+                            PorterDuff.Mode.SRC_IN);
+        }
+
         // In accessibility, a single click on the focused app info button will show it
         if (ssp.isTouchExplorationEnabled()) {
-            mApplicationIcon.setOnClickListener(this);
+            mIconView.setOnClickListener(this);
         }
     }
 
     /** Unbinds the bar view from the task */
     void unbindFromTask() {
         mTask = null;
-        mApplicationIcon.setImageDrawable(null);
-        mApplicationIcon.setOnClickListener(null);
+        mIconView.setImageDrawable(null);
+        mIconView.setOnClickListener(null);
         mMoveTaskButton.setOnClickListener(null);
     }
 
-    /** Animates this task bar dismiss button when launching a task. */
-    void startLaunchTaskDismissAnimation(final Runnable postAnimationRunanble) {
-        if (mDismissButton.getVisibility() == View.VISIBLE) {
-            int taskViewExitToAppDuration = mContext.getResources().getInteger(
-                    R.integer.recents_task_exit_to_app_duration);
-            mDismissButton.animate().cancel();
-            mDismissButton.animate()
-                    .alpha(0f)
-                    .setStartDelay(0)
-                    .setInterpolator(mFastOutSlowInInterpolator)
-                    .setDuration(taskViewExitToAppDuration)
-                    .withEndAction(postAnimationRunanble)
-                    .start();
-        }
-    }
-
     /** Animates this task bar if the user does not interact with the stack after a certain time. */
     void startNoUserInteractionAnimation() {
         if (mDismissButton.getVisibility() != View.VISIBLE) {
@@ -324,7 +447,10 @@
         }
     }
 
-    /** Mark this task view that the user does has not interacted with the stack after a certain time. */
+    /**
+     * Mark this task view that the user does has not interacted with the stack after a certain
+     * time.
+     */
     void setNoUserInteractionState() {
         if (mDismissButton.getVisibility() != View.VISIBLE) {
             mDismissButton.animate().cancel();
@@ -333,7 +459,10 @@
         }
     }
 
-    /** Resets the state tracking that the user has not interacted with the stack after a certain time. */
+    /**
+     * Resets the state tracking that the user has not interacted with the stack after a certain
+     * time.
+     */
     void resetNoUserInteractionState() {
         mDismissButton.setVisibility(View.INVISIBLE);
     }
@@ -347,19 +476,13 @@
     }
 
     @Override
-    protected void dispatchDraw(Canvas canvas) {
-        super.dispatchDraw(canvas);
-
-        // Draw the dim layer with the rounded corners
-        canvas.drawRoundRect(0, 0, mTaskViewRect.width(), getHeight(),
-                mCornerRadius, mCornerRadius, mDimLayerPaint);
-    }
-
-    @Override
     public void onClick(View v) {
-        if (v == mApplicationIcon) {
-            // In accessibility, a single click on the focused app info button will show it
-            EventBus.getDefault().send(new ShowApplicationInfoEvent(mTask));
+        if (v == mIconView) {
+            SystemServicesProxy ssp = Recents.getSystemServices();
+            if (ssp.isTouchExplorationEnabled()) {
+                // In accessibility, a single click on the focused app info button will show it
+                EventBus.getDefault().send(new ShowApplicationInfoEvent(mTask));
+            }
         } else if (v == mDismissButton) {
             TaskView tv = Utilities.findParent(this, TaskView.class);
             tv.dismissTask();
@@ -374,15 +497,95 @@
                     : new Rect();
             EventBus.getDefault().send(new LaunchTaskEvent(tv, mTask, bounds,
                     mMoveTaskTargetStackId, false));
+        } else if (v == mAppInfoView) {
+            EventBus.getDefault().send(new ShowApplicationInfoEvent(mTask));
+        } else if (v == mAppIconView) {
+            hideAppOverlay(false /* immediate */);
         }
     }
 
     @Override
     public boolean onLongClick(View v) {
-        if (v == mApplicationIcon) {
-            EventBus.getDefault().send(new ShowApplicationInfoEvent(mTask));
+        if (v == mIconView) {
+            showAppOverlay();
+            return true;
+        } else if (v == mAppIconView) {
+            hideAppOverlay(false /* immediate */);
             return true;
         }
         return false;
     }
+
+    /**
+     * Shows the application overlay.
+     */
+    private void showAppOverlay() {
+        // Skip early if the task is invalid
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        ComponentName cn = mTask.key.getComponent();
+        int userId = mTask.key.userId;
+        ActivityInfo activityInfo = ssp.getActivityInfo(cn, userId);
+        if (activityInfo == null) {
+            return;
+        }
+
+        // Inflate the overlay if necessary
+        if (mAppOverlayView == null) {
+            mAppOverlayView = (FrameLayout) mAppOverlayViewStub.inflate();
+            mAppOverlayView.setBackground(mOverlayBackground);
+            mAppIconView = (ImageView) mAppOverlayView.findViewById(R.id.app_icon);
+            mAppIconView.setOnClickListener(this);
+            mAppIconView.setOnLongClickListener(this);
+            mAppInfoView = (ImageView) mAppOverlayView.findViewById(R.id.app_info);
+            mAppInfoView.setOnClickListener(this);
+            mAppTitleView = (TextView) mAppOverlayView.findViewById(R.id.app_title);
+        }
+
+        // Update the overlay contents for the current app
+        mAppTitleView.setText(ssp.getBadgedApplicationLabel(activityInfo.applicationInfo, userId));
+        mAppTitleView.setTextColor(mTask.useLightOnPrimaryColor ?
+                mTaskBarViewLightTextColor : mTaskBarViewDarkTextColor);
+        mAppIconView.setImageDrawable(ssp.getBadgedApplicationIcon(activityInfo.applicationInfo,
+                userId));
+        mAppInfoView.setImageDrawable(mTask.useLightOnPrimaryColor
+                ? mLightInfoIcon
+                : mDarkInfoIcon);
+        mAppOverlayView.setVisibility(View.VISIBLE);
+
+        int x = mIconView.getLeft() + mIconView.getWidth() / 2;
+        int y = mIconView.getTop() + mIconView.getHeight() / 2;
+        Animator revealAnim = ViewAnimationUtils.createCircularReveal(mAppOverlayView, x, y, 0,
+                getWidth());
+        revealAnim.setDuration(OVERLAY_REVEAL_DURATION);
+        revealAnim.setInterpolator(mLinearOutSlowInInterpolator);
+        revealAnim.start();
+    }
+
+    /**
+     * Hide the application overlay.
+     */
+    private void hideAppOverlay(boolean immediate) {
+        // Skip if we haven't even loaded the overlay yet
+        if (mAppOverlayView == null) {
+            return;
+        }
+
+        if (immediate) {
+            mAppOverlayView.setVisibility(View.GONE);
+        } else {
+            int x = mIconView.getLeft() + mIconView.getWidth() / 2;
+            int y = mIconView.getTop() + mIconView.getHeight() / 2;
+            Animator revealAnim = ViewAnimationUtils.createCircularReveal(mAppOverlayView, x, y,
+                    getWidth(), 0);
+            revealAnim.setDuration(OVERLAY_REVEAL_DURATION);
+            revealAnim.setInterpolator(mLinearOutSlowInInterpolator);
+            revealAnim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mAppOverlayView.setVisibility(View.GONE);
+                }
+            });
+            revealAnim.start();
+        }
+    }
 }
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 37d8cd6..c3a0ac9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -27,8 +27,6 @@
 import android.graphics.Rect;
 import android.graphics.Shader;
 import android.util.AttributeSet;
-import android.util.FloatProperty;
-import android.util.Property;
 import android.view.View;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
@@ -42,26 +40,15 @@
  */
 public class TaskViewThumbnail extends View {
 
-    public static final Property<TaskViewThumbnail, Float> BITMAP_SCALE =
-            new FloatProperty<TaskViewThumbnail>("bitmapScale") {
-                @Override
-                public void setValue(TaskViewThumbnail object, float scale) {
-                    object.setBitmapScale(scale);
-                }
-
-                @Override
-                public Float get(TaskViewThumbnail object) {
-                    return object.getBitmapScale();
-                }
-            };
+    private Task mTask;
 
     // Drawing
+    Rect mThumbnailRect = new Rect();
     Rect mTaskViewRect = new Rect();
     int mCornerRadius;
     float mDimAlpha;
     Matrix mScaleMatrix = new Matrix();
     Paint mDrawPaint = new Paint();
-    float mBitmapScale = 1f;
     BitmapShader mBitmapShader;
     LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0);
 
@@ -104,7 +91,13 @@
      * to match the frame changes.
      */
     public void onTaskViewSizeChanged(int width, int height) {
+        // Return early if the bounds have not changed
+        if (mTaskViewRect.width() == width && mTaskViewRect.height() == height) {
+            return;
+        }
+
         mTaskViewRect.set(0, 0, width, height);
+        updateThumbnailScale();
         invalidate();
     }
 
@@ -125,10 +118,14 @@
             mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP,
                     Shader.TileMode.CLAMP);
             mDrawPaint.setShader(mBitmapShader);
+            mThumbnailRect.set(0, 0, bm.getWidth(), bm.getHeight());
+            updateThumbnailScale();
         } else {
             mBitmapShader = null;
             mDrawPaint.setShader(null);
+            mThumbnailRect.setEmpty();
         }
+        invalidate();
     }
 
     /** Updates the paint to draw the thumbnail. */
@@ -150,12 +147,23 @@
     }
 
     /**
-     * Sets the scale of the bitmap relative to this view.
+     * Updates the scale of the bitmap relative to this view.
      */
-    public void setBitmapScale(float scale) {
+    public void updateThumbnailScale() {
         if (mBitmapShader != null) {
-            mBitmapScale = scale;
-            mScaleMatrix.setScale(mBitmapScale, mBitmapScale);
+            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();
+            } 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(
+                        (float) mTaskViewRect.width() / mThumbnailRect.width(),
+                        (float) mTaskViewRect.height() / mThumbnailRect.height());
+            }
+            mScaleMatrix.setScale(thumbnailScale, thumbnailScale);
             mBitmapShader.setLocalMatrix(mScaleMatrix);
         }
         if (!mInvisible) {
@@ -163,10 +171,6 @@
         }
     }
 
-    public float getBitmapScale() {
-        return mBitmapScale;
-    }
-
     /** Updates the clip rect based on the given task bar. */
     void updateClipToTaskBar(View taskBar) {
         mTaskBar = taskBar;
@@ -184,7 +188,6 @@
             if (!mInvisible) {
                 updateThumbnailPaintFilter();
             }
-            invalidate();
         }
     }
 
@@ -199,6 +202,7 @@
 
     /** Binds the thumbnail view to the task */
     void rebindToTask(Task t) {
+        mTask = t;
         if (t.thumbnail != null) {
             setThumbnail(t.thumbnail);
         } else {
@@ -208,6 +212,7 @@
 
     /** Unbinds the thumbnail view from the task */
     void unbindFromTask() {
+        mTask = null;
         setThumbnail(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 3ee50ac..85b7c82 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -16,16 +16,19 @@
 
 package com.android.systemui.recents.views;
 
-import android.animation.ValueAnimator;
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
 import android.graphics.RectF;
 import android.util.IntProperty;
 import android.util.Property;
 import android.view.View;
-import android.view.ViewPropertyAnimator;
-import android.view.animation.Interpolator;
 
+import java.util.ArrayList;
 
-/* The transform state for a task view */
+/**
+ * The visual properties for a {@link TaskView}.
+ */
 public class TaskViewTransform {
 
     public static final Property<View, Integer> LEFT =
@@ -80,33 +83,50 @@
                 }
             };
 
-    // TODO: Move this out of the transform
-    public int startDelay = 0;
-
     public float translationZ = 0;
     public float scale = 1f;
     public float alpha = 1f;
-    public float thumbnailScale = 1f;
 
     public boolean visible = false;
-    float p = 0f;
+
+    // This is the relative task progress of this task, relative to the stack scroll at which this
+    // transform was computed
+    public float p = 0f;
 
     // This is a window-space rect used for positioning the task in the stack and freeform workspace
     public RectF rect = new RectF();
 
-    public TaskViewTransform() {
-        // Do nothing
+    /**
+     * Fills int this transform from the state of the given TaskView.
+     */
+    public void fillIn(TaskView tv) {
+        translationZ = tv.getTranslationZ();
+        scale = tv.getScaleX();
+        alpha = tv.getAlpha();
+        visible = true;
+        p = tv.getTaskProgress();
+        rect.set(tv.getLeft(), tv.getTop(), tv.getRight(), tv.getBottom());
+    }
+
+    /**
+     * Copies the transform state from another {@link TaskViewTransform}.
+     */
+    public void copyFrom(TaskViewTransform other) {
+        translationZ = other.translationZ;
+        scale = other.scale;
+        alpha = other.alpha;
+        visible = other.visible;
+        p = other.p;
+        rect.set(other.rect);
     }
 
     /**
      * Resets the current transform.
      */
     public void reset() {
-        startDelay = 0;
         translationZ = 0;
         scale = 1f;
         alpha = 1f;
-        thumbnailScale = 1f;
         visible = false;
         rect.setEmpty();
         p = 0f;
@@ -116,50 +136,31 @@
     public boolean hasAlphaChangedFrom(float v) {
         return (Float.compare(alpha, v) != 0);
     }
+
     public boolean hasScaleChangedFrom(float v) {
         return (Float.compare(scale, v) != 0);
     }
+
     public boolean hasTranslationZChangedFrom(float v) {
         return (Float.compare(translationZ, v) != 0);
     }
 
-    /** Applies this transform to a view. */
-    public void applyToTaskView(TaskView v, int duration, Interpolator interp, boolean allowLayers,
-            boolean allowShadows, ValueAnimator.AnimatorUpdateListener updateCallback) {
-        // Check to see if any properties have changed, and update the task view
-        if (duration > 0) {
-            ViewPropertyAnimator anim = v.animate();
-            boolean requiresLayers = false;
+    public boolean hasRectChangedFrom(View v) {
+        return ((int) rect.left != v.getLeft()) || ((int) rect.right != v.getRight()) ||
+                ((int) rect.top != v.getTop()) || ((int) rect.bottom != v.getBottom());
+    }
 
-            // Animate to the final state
-            if (allowShadows && hasTranslationZChangedFrom(v.getTranslationZ())) {
-                anim.translationZ(translationZ);
-            }
-            if (hasScaleChangedFrom(v.getScaleX())) {
-                anim.scaleX(scale)
-                    .scaleY(scale);
-                requiresLayers = true;
-            }
-            if (hasAlphaChangedFrom(v.getAlpha())) {
-                // Use layers if we animate alpha
-                anim.alpha(alpha);
-                requiresLayers = true;
-            }
-            if (requiresLayers && allowLayers) {
-                anim.withLayer();
-            }
-            if (updateCallback != null) {
-                anim.setUpdateListener(updateCallback);
-            } else {
-                anim.setUpdateListener(null);
-            }
-            anim.setListener(null);
-            anim.setStartDelay(startDelay)
-                    .setDuration(duration)
-                    .setInterpolator(interp)
-                    .start();
-        } else {
-            // Set the changed properties
+    /**
+     * Applies this transform to a view.
+     */
+    public void applyToTaskView(TaskView v, ArrayList<Animator> animators,
+            TaskViewAnimation taskAnimation, boolean allowShadows) {
+        // Return early if not visible
+        if (!visible) {
+            return;
+        }
+
+        if (taskAnimation.isImmediate()) {
             if (allowShadows && hasTranslationZChangedFrom(v.getTranslationZ())) {
                 v.setTranslationZ(translationZ);
             }
@@ -170,29 +171,42 @@
             if (hasAlphaChangedFrom(v.getAlpha())) {
                 v.setAlpha(alpha);
             }
+            if (hasRectChangedFrom(v)) {
+                v.setLeftTopRightBottom((int) rect.left, (int) rect.top, (int) rect.right,
+                        (int) rect.bottom);
+            }
+        } else {
+            if (allowShadows && hasTranslationZChangedFrom(v.getTranslationZ())) {
+                animators.add(ObjectAnimator.ofFloat(v, View.TRANSLATION_Z, v.getTranslationZ(),
+                        translationZ));
+            }
+            if (hasScaleChangedFrom(v.getScaleX())) {
+                animators.add(ObjectAnimator.ofPropertyValuesHolder(v,
+                        PropertyValuesHolder.ofFloat(View.SCALE_X, v.getScaleX(), scale),
+                        PropertyValuesHolder.ofFloat(View.SCALE_Y, v.getScaleX(), scale)));
+            }
+            if (hasAlphaChangedFrom(v.getAlpha())) {
+                animators.add(ObjectAnimator.ofFloat(v, View.ALPHA, v.getAlpha(), alpha));
+            }
+            if (hasRectChangedFrom(v)) {
+                animators.add(ObjectAnimator.ofPropertyValuesHolder(v,
+                        PropertyValuesHolder.ofInt(LEFT, v.getLeft(), (int) rect.left),
+                        PropertyValuesHolder.ofInt(TOP, v.getTop(), (int) rect.top),
+                        PropertyValuesHolder.ofInt(RIGHT, v.getRight(), (int) rect.right),
+                        PropertyValuesHolder.ofInt(BOTTOM, v.getBottom(), (int) rect.bottom)));
+            }
         }
     }
 
     /** Reset the transform on a view. */
     public static void reset(TaskView v) {
-        // Cancel any running animations and reset the translation in case something else (like a
-        // dismiss animation) changes it
-        v.animate().cancel();
         v.setTranslationX(0f);
         v.setTranslationY(0f);
         v.setTranslationZ(0f);
         v.setScaleX(1f);
         v.setScaleY(1f);
         v.setAlpha(1f);
-        v.getViewBounds().setClipBottom(0, false /* forceUpdate */);
+        v.getViewBounds().setClipBottom(0);
         v.setLeftTopRightBottom(0, 0, 0, 0);
-        v.mThumbnailView.setBitmapScale(1f);
-    }
-
-    @Override
-    public String toString() {
-        return "TaskViewTransform delay: " + startDelay + " z: " + translationZ +
-                " scale: " + scale + " alpha: " + alpha + " visible: " + visible +
-                " rect: " + rect + " p: " + p;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java b/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
deleted file mode 100644
index e1d80fd..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.views;
-
-import android.animation.ValueAnimator;
-import android.graphics.Rect;
-import com.android.systemui.recents.misc.ReferenceCountedTrigger;
-
-/* Common code related to view animations */
-public class ViewAnimation {
-
-    /* The animation context for a task view animation into Recents */
-    public static class TaskViewEnterContext {
-        // A trigger to run some logic when all the animations complete.  This works around the fact
-        // that it is difficult to coordinate ViewPropertyAnimators
-        public ReferenceCountedTrigger postAnimationTrigger;
-        // An update listener to notify as the enter animation progresses (used for the home transition)
-        ValueAnimator.AnimatorUpdateListener updateListener;
-
-        // These following properties are updated for each task view we start the enter animation on
-
-        // Whether or not the current task occludes the launch target
-        boolean currentTaskOccludesLaunchTarget;
-        // The task rect for the current stack
-        Rect currentTaskRect;
-        // The transform of the current task view
-        TaskViewTransform currentTaskTransform;
-        // The view index of the current task view
-        int currentStackViewIndex;
-        // The total number of task views
-        int currentStackViewCount;
-
-        public TaskViewEnterContext(ReferenceCountedTrigger t) {
-            postAnimationTrigger = t;
-        }
-    }
-
-    /* The animation context for a task view animation out of Recents */
-    public static class TaskViewExitContext {
-        // A trigger to run some logic when all the animations complete.  This works around the fact
-        // that it is difficult to coordinate ViewPropertyAnimators
-        ReferenceCountedTrigger postAnimationTrigger;
-
-        // The translationY to apply to a TaskView to move it off the bottom of the task stack
-        int offscreenTranslationY;
-
-        public TaskViewExitContext(ReferenceCountedTrigger t) {
-            postAnimationTrigger = t;
-        }
-    }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
index 77c27fa..d5131be 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
@@ -31,6 +31,7 @@
 import android.widget.ImageView;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 
 import java.util.ArrayList;
 
@@ -205,7 +206,7 @@
         if (!mAutomatic) {
             final int val = value + mMinimumBacklight;
             if (stopTracking) {
-                MetricsLogger.action(mContext, MetricsLogger.ACTION_BRIGHTNESS, val);
+                MetricsLogger.action(mContext, MetricsEvent.ACTION_BRIGHTNESS, val);
             }
             setBrightness(val);
             if (!tracking) {
@@ -220,7 +221,7 @@
         } else {
             final float adj = value / (BRIGHTNESS_ADJ_RESOLUTION / 2f) - 1;
             if (stopTracking) {
-                MetricsLogger.action(mContext, MetricsLogger.ACTION_BRIGHTNESS_AUTO, value);
+                MetricsLogger.action(mContext, MetricsEvent.ACTION_BRIGHTNESS_AUTO, value);
             }
             setBrightnessAdj(adj);
             if (!tracking) {
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
index cef4d34..4952234 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
@@ -25,6 +25,7 @@
 import android.widget.ImageView;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 
 /** A dialog that provides controls for adjusting the screen brightness. */
@@ -53,13 +54,13 @@
     protected void onStart() {
         super.onStart();
         mBrightnessController.registerCallbacks();
-        MetricsLogger.visible(this, MetricsLogger.BRIGHTNESS_DIALOG);
+        MetricsLogger.visible(this, MetricsEvent.BRIGHTNESS_DIALOG);
     }
 
     @Override
     protected void onStop() {
         super.onStop();
-        MetricsLogger.hidden(this, MetricsLogger.BRIGHTNESS_DIALOG);
+        MetricsLogger.hidden(this, MetricsEvent.BRIGHTNESS_DIALOG);
         mBrightnessController.unregisterCallbacks();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 6ff7a3e..189e651 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -17,7 +17,8 @@
 package com.android.systemui.stackdivider;
 
 import android.content.res.Configuration;
-import android.view.IDockDividerVisibilityListener;
+import android.os.RemoteException;
+import android.view.IDockedStackListener;
 import android.view.LayoutInflater;
 import android.view.View;
 
@@ -49,7 +50,7 @@
         putComponent(Divider.class, this);
         mDockDividerVisibilityListener = new DockDividerVisibilityListener();
         SystemServicesProxy ssp = Recents.getSystemServices();
-        ssp.registerDockDividerVisibilityListener(mDockDividerVisibilityListener);
+        ssp.registerDockedStackListener(mDockDividerVisibilityListener);
     }
 
     @Override
@@ -94,10 +95,15 @@
         });
     }
 
-    class DockDividerVisibilityListener extends IDockDividerVisibilityListener.Stub {
+    class DockDividerVisibilityListener extends IDockedStackListener.Stub {
+
         @Override
-        public void onDockDividerVisibilityChanged(boolean visible) {
+        public void onDividerVisibilityChanged(boolean visible) throws RemoteException {
             updateVisibility(visible);
         }
+
+        @Override
+        public void onDockedStackExistsChanged(boolean exists) throws RemoteException {
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
new file mode 100644
index 0000000..5ef56f3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.util.Property;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.ImageButton;
+
+import com.android.systemui.R;
+
+/**
+ * View for the handle in the docked stack divider.
+ */
+public class DividerHandleView extends ImageButton {
+
+    private final static Property<DividerHandleView, Integer> WIDTH_PROPERTY
+            = new Property<DividerHandleView, Integer>(Integer.class, "width") {
+
+        @Override
+        public Integer get(DividerHandleView object) {
+            return object.mCurrentWidth;
+        }
+
+        @Override
+        public void set(DividerHandleView object, Integer value) {
+            object.mCurrentWidth = value;
+            object.invalidate();
+        }
+    };
+
+    private final static Property<DividerHandleView, Integer> HEIGHT_PROPERTY
+            = new Property<DividerHandleView, Integer>(Integer.class, "height") {
+
+        @Override
+        public Integer get(DividerHandleView object) {
+            return object.mCurrentHeight;
+        }
+
+        @Override
+        public void set(DividerHandleView object, Integer value) {
+            object.mCurrentHeight = value;
+            object.invalidate();
+        }
+    };
+
+    private final Paint mPaint = new Paint();
+    private final int mWidth;
+    private final int mHeight;
+    private final int mCircleDiameter;
+    private final Interpolator mFastOutSlowInInterpolator;
+    private int mCurrentWidth;
+    private int mCurrentHeight;
+    private AnimatorSet mAnimator;
+
+    public DividerHandleView(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        mPaint.setColor(getResources().getColor(R.color.docked_divider_handle, null));
+        mPaint.setAntiAlias(true);
+        mWidth = getResources().getDimensionPixelSize(R.dimen.docked_divider_handle_width);
+        mHeight = getResources().getDimensionPixelSize(R.dimen.docked_divider_handle_height);
+        mCurrentWidth = mWidth;
+        mCurrentHeight = mHeight;
+        mCircleDiameter = (mWidth + mHeight) / 3;
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
+                android.R.interpolator.fast_out_slow_in);
+    }
+
+    public void setTouching(boolean touching, boolean animate) {
+        if (mAnimator != null) {
+            mAnimator.cancel();
+            mAnimator = null;
+        }
+        if (!animate) {
+            if (touching) {
+                mCurrentWidth = mCircleDiameter;
+                mCurrentHeight = mCircleDiameter;
+            } else {
+                mCurrentWidth = mWidth;
+                mCurrentHeight = mHeight;
+            }
+            invalidate();
+        } else {
+            animateToTarget(touching ? mCircleDiameter : mWidth,
+                    touching ? mCircleDiameter : mHeight, touching);
+        }
+    }
+
+    private void animateToTarget(int targetWidth, int targetHeight, boolean touching) {
+        ObjectAnimator widthAnimator = ObjectAnimator.ofInt(this, WIDTH_PROPERTY,
+                mCurrentWidth, targetWidth);
+        ObjectAnimator heightAnimator = ObjectAnimator.ofInt(this, HEIGHT_PROPERTY,
+                mCurrentHeight, targetHeight);
+        mAnimator = new AnimatorSet();
+        mAnimator.playTogether(widthAnimator, heightAnimator);
+        mAnimator.setDuration(touching
+                ? DividerView.TOUCH_ANIMATION_DURATION
+                : DividerView.TOUCH_RELEASE_ANIMATION_DURATION);
+        mAnimator.setInterpolator(touching
+                ? DividerView.TOUCH_RESPONSE_INTERPOLATOR
+                : mFastOutSlowInInterpolator);
+        mAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mAnimator = null;
+            }
+        });
+        mAnimator.start();
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        int left = getWidth() / 2 - mCurrentWidth / 2;
+        int top = getHeight() / 2 - mCurrentHeight / 2;
+        int radius = Math.min(mCurrentWidth, mCurrentHeight) / 2;
+        canvas.drawRoundRect(left, top, left + mCurrentWidth, top + mCurrentHeight,
+                radius, radius, mPaint);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java
deleted file mode 100644
index 69e90cc..0000000
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java
+++ /dev/null
@@ -1,130 +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.stackdivider;
-
-import android.content.Context;
-import android.util.DisplayMetrics;
-import android.view.DisplayInfo;
-
-import com.android.systemui.statusbar.FlingAnimationUtils;
-
-import java.util.ArrayList;
-
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-
-/**
- * Calculates the snap targets and the snap position given a position and a velocity. All positions
- * here are to be interpreted as the left/top edge of the divider rectangle.
- */
-public class DividerSnapAlgorithm {
-
-    private final Context mContext;
-    private final FlingAnimationUtils mFlingAnimationUtils;
-    private final int mDividerSize;
-    private final ArrayList<SnapTarget> mTargets;
-
-    /** The first target which is still splitting the screen */
-    private final SnapTarget mFirstSplitTarget;
-
-    /** The last target which is still splitting the screen */
-    private final SnapTarget mLastSplitTarget;
-
-    private final SnapTarget mDismissStartTarget;
-    private final SnapTarget mDismissEndTarget;
-
-    public DividerSnapAlgorithm(Context ctx, FlingAnimationUtils flingAnimationUtils,
-            int dividerSize, boolean isHorizontalDivision) {
-        mContext = ctx;
-        mFlingAnimationUtils = flingAnimationUtils;
-        mDividerSize = dividerSize;
-        mTargets = calculateTargets(isHorizontalDivision);
-        mFirstSplitTarget = mTargets.get(1);
-        mLastSplitTarget = mTargets.get(mTargets.size() - 2);
-        mDismissStartTarget = mTargets.get(0);
-        mDismissEndTarget = mTargets.get(mTargets.size() - 1);
-    }
-
-    public SnapTarget calculateSnapTarget(int position, float velocity) {
-        if (Math.abs(velocity) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
-            return snap(position);
-        }
-        if (position < mFirstSplitTarget.position && velocity < 0) {
-            return mDismissStartTarget;
-        }
-        if (position > mLastSplitTarget.position && velocity > 0) {
-            return mDismissEndTarget;
-        }
-        if (velocity < 0) {
-            return mFirstSplitTarget;
-        } else {
-            return mLastSplitTarget;
-        }
-    }
-
-    private SnapTarget snap(int position) {
-        int minIndex = -1;
-        int minDistance = Integer.MAX_VALUE;
-        int size = mTargets.size();
-        for (int i = 0; i < size; i++) {
-            int distance = Math.abs(position - mTargets.get(i).position);
-            if (distance < minDistance) {
-                minIndex = i;
-                minDistance = distance;
-            }
-        }
-        return mTargets.get(minIndex);
-    }
-
-    private ArrayList<SnapTarget> calculateTargets(boolean isHorizontalDivision) {
-        ArrayList<SnapTarget> targets = new ArrayList<>();
-        DisplayMetrics info = mContext.getResources().getDisplayMetrics();
-        int dividerMax = isHorizontalDivision
-                ? info.heightPixels
-                : info.widthPixels;
-
-        // TODO: Better calculation
-        targets.add(new SnapTarget(-mDividerSize, SnapTarget.FLAG_DISMISS_START));
-        targets.add(new SnapTarget((int) (0.38f * dividerMax) - mDividerSize / 2,
-                SnapTarget.FLAG_NONE));
-        targets.add(new SnapTarget(dividerMax / 2 - mDividerSize / 2, SnapTarget.FLAG_NONE));
-        targets.add(new SnapTarget((int) (0.62f * dividerMax) - mDividerSize / 2,
-                SnapTarget.FLAG_NONE));
-        targets.add(new SnapTarget(dividerMax, SnapTarget.FLAG_DISMISS_END));
-        return targets;
-    }
-
-    /**
-     * Represents a snap target for the divider.
-     */
-    public static class SnapTarget {
-        public static final int FLAG_NONE = 0;
-
-        /** If the divider reaches this value, the left/top task should be dismissed. */
-        public static final int FLAG_DISMISS_START = 1;
-
-        /** If the divider reaches this value, the right/bottom task should be dismissed */
-        public static final int FLAG_DISMISS_END = 2;
-
-        public final int position;
-        public final int flag;
-
-        public SnapTarget(int position, int flag) {
-            this.position = position;
-            this.flag = flag;
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index c01f170..dca7fd9 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -21,6 +21,7 @@
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.annotation.Nullable;
+import android.app.ActivityManager.StackId;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Rect;
@@ -34,18 +35,26 @@
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.View.OnTouchListener;
+import android.view.ViewConfiguration;
 import android.view.ViewTreeObserver.InternalInsetsInfo;
 import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
+import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
 import android.widget.FrameLayout;
-import android.widget.ImageButton;
 
+import com.android.internal.policy.DividerSnapAlgorithm;
+import com.android.internal.policy.DockedDividerUtils;
 import com.android.systemui.R;
-import com.android.systemui.stackdivider.DividerSnapAlgorithm.SnapTarget;
+import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
+import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
+import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
 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;
@@ -56,15 +65,41 @@
 public class DividerView extends FrameLayout implements OnTouchListener,
         OnComputeInternalInsetsListener {
 
+    static final long TOUCH_ANIMATION_DURATION = 150;
+    static final long TOUCH_RELEASE_ANIMATION_DURATION = 200;
+    static final Interpolator TOUCH_RESPONSE_INTERPOLATOR =
+            new PathInterpolator(0.3f, 0f, 0.1f, 1f);
+
     private static final String TAG = "DividerView";
 
-    private ImageButton mHandle;
+    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 PathInterpolator SLOWDOWN_INTERPOLATOR =
+            new PathInterpolator(0.5f, 1f, 0.5f, 1f);
+    private static final PathInterpolator DIM_INTERPOLATOR =
+            new PathInterpolator(.23f, .87f, .52f, -0.11f);
+
+    private DividerHandleView mHandle;
     private View mBackground;
     private int mStartX;
     private int mStartY;
     private int mStartPosition;
     private int mDockSide;
     private final int[] mTempInt2 = new int[2];
+    private boolean mMoving;
+    private int mTouchSlop;
 
     private int mDividerInsets;
     private int mDisplayWidth;
@@ -73,15 +108,24 @@
     private int mDividerSize;
     private int mTouchElevation;
 
-    private final Rect mTmpRect = new Rect();
+    private final Rect mDockedRect = new Rect();
+    private final Rect mDockedTaskRect = new Rect();
+    private final Rect mOtherTaskRect = new Rect();
+    private final Rect mOtherRect = new Rect();
+    private final Rect mDockedInsetRect = new Rect();
+    private final Rect mOtherInsetRect = new Rect();
     private final Rect mLastResizeRect = new Rect();
     private final WindowManagerProxy mWindowManagerProxy = WindowManagerProxy.getInstance();
     private Interpolator mFastOutSlowInInterpolator;
-    private final Interpolator mTouchResponseInterpolator =
-            new PathInterpolator(0.3f, 0f, 0.1f, 1f);
     private DividerWindowManager mWindowManager;
     private VelocityTracker mVelocityTracker;
     private FlingAnimationUtils mFlingAnimationUtils;
+    private DividerSnapAlgorithm mSnapAlgorithm;
+    private final Rect mStableInsets = new Rect();
+
+    private boolean mAnimateAfterRecentsDrawn;
+    private boolean mGrowAfterRecentsDrawn;
+    private boolean mGrowRecents;
 
     public DividerView(Context context) {
         super(context);
@@ -103,7 +147,7 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mHandle = (ImageButton) findViewById(R.id.docked_divider_handle);
+        mHandle = (DividerHandleView) findViewById(R.id.docked_divider_handle);
         mBackground = findViewById(R.id.docked_divider_background);
         mHandle.setOnTouchListener(this);
         mDividerWindowWidth = getResources().getDimensionPixelSize(
@@ -113,8 +157,10 @@
         mDividerSize = mDividerWindowWidth - 2 * mDividerInsets;
         mTouchElevation = getResources().getDimensionPixelSize(
                 R.dimen.docked_stack_divider_lift_elevation);
+        mGrowRecents = getResources().getBoolean(R.bool.recents_grow_in_multiwindow);
         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
                 android.R.interpolator.fast_out_slow_in);
+        mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
         mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.3f);
         updateDisplayInfo();
         boolean landscape = getResources().getConfiguration().orientation
@@ -124,6 +170,25 @@
         getViewTreeObserver().addOnComputeInternalInsetsListener(this);
     }
 
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        EventBus.getDefault().register(this);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        EventBus.getDefault().unregister(this);
+    }
+
+    @Override
+    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+        mStableInsets.set(insets.getStableInsetLeft(), insets.getStableInsetTop(),
+                insets.getStableInsetRight(), insets.getStableInsetBottom());
+        return super.onApplyWindowInsets(insets);
+    }
+
     public void setWindowManager(DividerWindowManager windowManager) {
         mWindowManager = windowManager;
     }
@@ -132,24 +197,56 @@
         return mWindowManagerProxy;
     }
 
-    public boolean startDragging() {
+    public boolean startDragging(boolean animate, boolean touching) {
+        if (touching) {
+            mHandle.setTouching(true, animate);
+        }
         mDockSide = mWindowManagerProxy.getDockSide();
+        getSnapAlgorithm();
         if (mDockSide != WindowManager.DOCKED_INVALID) {
             mWindowManagerProxy.setResizing(true);
             mWindowManager.setSlippery(false);
-            liftBackground();
+            if (touching) {
+                liftBackground();
+            }
             return true;
         } else {
             return false;
         }
     }
 
-    public void stopDragging(int position, float velocity) {
-        fling(position, velocity);
+    public void stopDragging(int position, float velocity, boolean avoidDismissStart) {
+        mHandle.setTouching(false, true /* animate */);
+        fling(position, velocity, avoidDismissStart);
         mWindowManager.setSlippery(true);
         releaseBackground();
     }
 
+    public void stopDragging(int position, SnapTarget target, long duration,
+            Interpolator interpolator) {
+        mHandle.setTouching(false, true /* animate */);
+        flingTo(position, target, duration, interpolator);
+        mWindowManager.setSlippery(true);
+        releaseBackground();
+    }
+
+    public DividerSnapAlgorithm getSnapAlgorithm() {
+        if (mSnapAlgorithm == null) {
+            mSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(), mDisplayWidth,
+                    mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets);
+        }
+        return mSnapAlgorithm;
+    }
+
+    public int getCurrentPosition() {
+        getLocationOnScreen(mTempInt2);
+        if (isHorizontalDivision()) {
+            return mTempInt2[1] + mDividerInsets;
+        } else {
+            return mTempInt2[0] + mDividerInsets;
+        }
+    }
+
     @Override
     public boolean onTouch(View v, MotionEvent event) {
         convertToScreenCoordinates(event);
@@ -160,20 +257,27 @@
                 mVelocityTracker.addMovement(event);
                 mStartX = (int) event.getX();
                 mStartY = (int) event.getY();
-                getLocationOnScreen(mTempInt2);
-                boolean result = startDragging();
-                if (isHorizontalDivision()) {
-                    mStartPosition = mTempInt2[1] + mDividerInsets;
-                } else {
-                    mStartPosition = mTempInt2[0] + mDividerInsets;
-                }
+                boolean result = startDragging(true /* animate */, true /* touching */);
+                mStartPosition = getCurrentPosition();
+                mMoving = false;
                 return result;
             case MotionEvent.ACTION_MOVE:
                 mVelocityTracker.addMovement(event);
                 int x = (int) event.getX();
                 int y = (int) event.getY();
-                if (mDockSide != WindowManager.DOCKED_INVALID) {
-                    resizeStack(calculatePosition(x, y));
+                boolean exceededTouchSlop =
+                        isHorizontalDivision() && Math.abs(y - mStartY) > mTouchSlop
+                                || (!isHorizontalDivision() && Math.abs(x - mStartX) > mTouchSlop);
+                if (!mMoving && exceededTouchSlop) {
+                    mStartX = x;
+                    mStartY = y;
+                    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);
                 }
                 break;
             case MotionEvent.ACTION_UP:
@@ -186,7 +290,8 @@
                 mVelocityTracker.computeCurrentVelocity(1000);
                 int position = calculatePosition(x, y);
                 stopDragging(position, isHorizontalDivision() ? mVelocityTracker.getYVelocity()
-                        : mVelocityTracker.getXVelocity());
+                        : mVelocityTracker.getXVelocity(), false /* avoidDismissStart */);
+                mMoving = false;
                 break;
         }
         return true;
@@ -196,15 +301,33 @@
         event.setLocation(event.getRawX(), event.getRawY());
     }
 
-    private void fling(int position, float velocity) {
-        final SnapTarget snapTarget = new DividerSnapAlgorithm(getContext(), mFlingAnimationUtils,
-                mDividerSize, isHorizontalDivision()).calculateSnapTarget(position, velocity);
+    private void fling(int position, float velocity, boolean avoidDismissStart) {
+        SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position, velocity);
+        if (avoidDismissStart && snapTarget == mSnapAlgorithm.getDismissStartTarget()) {
+            snapTarget = mSnapAlgorithm.getFirstSplitTarget();
+        }
+        ValueAnimator anim = getFlingAnimator(position, snapTarget);
+        mFlingAnimationUtils.apply(anim, position, snapTarget.position, velocity);
+        anim.start();
+    }
 
+    private void flingTo(int position, SnapTarget target, long duration,
+            Interpolator interpolator) {
+        ValueAnimator anim = getFlingAnimator(position, target);
+        anim.setDuration(duration);
+        anim.setInterpolator(interpolator);
+        anim.start();
+    }
+
+    private ValueAnimator getFlingAnimator(int position, final SnapTarget snapTarget) {
         ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position);
         anim.addUpdateListener(new AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
-                resizeStack((Integer) animation.getAnimatedValue());
+                resizeStack((Integer) animation.getAnimatedValue(),
+                        animation.getAnimatedFraction() == 1f
+                                ? TASK_POSITION_SAME
+                                : snapTarget.position, snapTarget);
             }
         });
         anim.addListener(new AnimatorListenerAdapter() {
@@ -215,8 +338,7 @@
                 mDockSide = WindowManager.DOCKED_INVALID;
             }
         });
-        mFlingAnimationUtils.apply(anim, position, snapTarget.position, velocity);
-        anim.start();
+        return anim;
     }
 
     private void commitSnapFlags(SnapTarget target) {
@@ -236,38 +358,43 @@
         } else {
             mWindowManagerProxy.maximizeDockedStack();
         }
+        mWindowManagerProxy.setResizeDimLayer(false, -1, 0f);
     }
 
     private void liftBackground() {
         if (isHorizontalDivision()) {
-            mBackground.animate().scaleY(1.5f);
+            mBackground.animate().scaleY(1.4f);
         } else {
-            mBackground.animate().scaleX(1.5f);
+            mBackground.animate().scaleX(1.4f);
         }
         mBackground.animate()
-                .setInterpolator(mTouchResponseInterpolator)
-                .setDuration(150)
-                .translationZ(mTouchElevation);
+                .setInterpolator(TOUCH_RESPONSE_INTERPOLATOR)
+                .setDuration(TOUCH_ANIMATION_DURATION)
+                .translationZ(mTouchElevation)
+                .start();
 
         // Lift handle as well so it doesn't get behind the background, even though it doesn't
         // cast shadow.
         mHandle.animate()
-                .setInterpolator(mTouchResponseInterpolator)
-                .setDuration(150)
-                .translationZ(mTouchElevation);
+                .setInterpolator(TOUCH_RESPONSE_INTERPOLATOR)
+                .setDuration(TOUCH_ANIMATION_DURATION)
+                .translationZ(mTouchElevation)
+                .start();
     }
 
     private void releaseBackground() {
         mBackground.animate()
                 .setInterpolator(mFastOutSlowInInterpolator)
-                .setDuration(200)
+                .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
                 .translationZ(0)
                 .scaleX(1f)
-                .scaleY(1f);
+                .scaleY(1f)
+                .start();
         mHandle.animate()
                 .setInterpolator(mFastOutSlowInInterpolator)
-                .setDuration(200)
-                .translationZ(0);
+                .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
+                .translationZ(0)
+                .start();
     }
 
     @Override
@@ -284,6 +411,7 @@
         display.getDisplayInfo(info);
         mDisplayWidth = info.logicalWidth;
         mDisplayHeight = info.logicalHeight;
+        mSnapAlgorithm = null;
     }
 
     private int calculatePosition(int touchX, int touchY) {
@@ -302,47 +430,226 @@
         return mStartPosition + touchY - mStartY;
     }
 
-    public void calculateBoundsForPosition(int position, int dockSide, Rect outRect) {
-        outRect.set(0, 0, mDisplayWidth, mDisplayHeight);
-        switch (dockSide) {
-            case WindowManager.DOCKED_LEFT:
-                outRect.right = position;
-                break;
-            case WindowManager.DOCKED_TOP:
-                outRect.bottom = position;
-                break;
-            case WindowManager.DOCKED_RIGHT:
-                outRect.left = position + mDividerWindowWidth - 2 * mDividerInsets;
-                break;
-            case WindowManager.DOCKED_BOTTOM:
-                outRect.top = position + mDividerWindowWidth - 2 * mDividerInsets;
-                break;
-        }
-        if (outRect.left > outRect.right) {
-            outRect.left = outRect.right;
-        }
-        if (outRect.top > outRect.bottom) {
-            outRect.top = outRect.bottom;
-        }
-        if (outRect.right < outRect.left) {
-            outRect.right = outRect.left;
-        }
-        if (outRect.bottom < outRect.top) {
-            outRect.bottom = outRect.top;
-        }
+    private void alignTopLeft(Rect containingRect, Rect rect) {
+        int width = rect.width();
+        int height = rect.height();
+        rect.set(containingRect.left, containingRect.top,
+                containingRect.left + width, containingRect.top + height);
     }
 
-    public void resizeStack(int position) {
-        calculateBoundsForPosition(position, mDockSide, mTmpRect);
-        if (mTmpRect.equals(mLastResizeRect)) {
+    private void alignBottomRight(Rect containingRect, Rect rect) {
+        int width = rect.width();
+        int height = rect.height();
+        rect.set(containingRect.right - width, containingRect.bottom - height,
+                containingRect.right, containingRect.bottom);
+    }
+
+    public void calculateBoundsForPosition(int position, int dockSide, Rect outRect) {
+        DockedDividerUtils.calculateBoundsForPosition(position, dockSide, outRect, mDisplayWidth,
+                mDisplayHeight, mDividerSize);
+    }
+
+    public void resizeStack(int position, int taskPosition, SnapTarget taskSnapTarget) {
+        calculateBoundsForPosition(position, mDockSide, mDockedRect);
+
+        if (mDockedRect.equals(mLastResizeRect)) {
             return;
         }
 
         // Make sure shadows are updated
         mBackground.invalidate();
 
-        mLastResizeRect.set(mTmpRect);
-        mWindowManagerProxy.resizeDockedStack(mTmpRect);
+        mLastResizeRect.set(mDockedRect);
+        if (taskPosition != TASK_POSITION_SAME) {
+            calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
+                    mOtherRect);
+            int dockSideInverted = DockedDividerUtils.invertDockSide(mDockSide);
+            int taskPositionDocked =
+                    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);
+            alignTopLeft(mDockedRect, mDockedTaskRect);
+            alignTopLeft(mOtherRect, mOtherTaskRect);
+            mDockedInsetRect.set(mDockedTaskRect);
+            mOtherInsetRect.set(mOtherTaskRect);
+            if (dockSideTopLeft(mDockSide)) {
+                alignTopLeft(mDockedRect, mDockedInsetRect);
+                alignBottomRight(mOtherRect, mOtherInsetRect);
+            } else {
+                alignBottomRight(mDockedRect, mDockedInsetRect);
+                alignTopLeft(mOtherRect, mOtherInsetRect);
+            }
+            applyDismissingParallax(mDockedTaskRect, mDockSide, taskSnapTarget, position,
+                    taskPositionDocked);
+            applyDismissingParallax(mOtherTaskRect, dockSideInverted, taskSnapTarget, position,
+                    taskPositionOther);
+            mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, mDockedInsetRect,
+                    mOtherTaskRect, mOtherInsetRect);
+        } else {
+            mWindowManagerProxy.resizeDockedStack(mDockedRect, null, null, null, null);
+        }
+        float fraction = mSnapAlgorithm.calculateDismissingFraction(position);
+        fraction = Math.max(0, Math.min(fraction, 1f));
+        fraction = DIM_INTERPOLATOR.getInterpolation(fraction);
+        mWindowManagerProxy.setResizeDimLayer(fraction != 0f,
+                getStackIdForDismissTarget(mSnapAlgorithm.getClosestDismissTarget(position)),
+                fraction);
+    }
+
+    /**
+     * 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.
+     */
+    private int restrictDismissingTaskPosition(int taskPosition, int dockSide,
+            SnapTarget snapTarget) {
+        if (snapTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(dockSide)) {
+            return mSnapAlgorithm.getFirstSplitTarget().position;
+        } else if (snapTarget.flag == SnapTarget.FLAG_DISMISS_END
+                && dockSideBottomRight(dockSide)) {
+            return mSnapAlgorithm.getLastSplitTarget().position;
+        } else {
+            return taskPosition;
+        }
+    }
+
+    /**
+     * Applies a parallax to the task when dismissing.
+     */
+    private void applyDismissingParallax(Rect taskRect, int dockSide, SnapTarget snapTarget,
+            int position, int taskPosition) {
+        float fraction = Math.min(1, Math.max(0,
+                mSnapAlgorithm.calculateDismissingFraction(position)));
+        SnapTarget dismissTarget = null;
+        SnapTarget splitTarget = null;
+        if ((snapTarget.flag == SnapTarget.FLAG_DISMISS_START
+                || snapTarget == mSnapAlgorithm.getFirstSplitTarget())
+                && dockSideTopLeft(dockSide)) {
+            dismissTarget = mSnapAlgorithm.getDismissStartTarget();
+            splitTarget = mSnapAlgorithm.getFirstSplitTarget();
+        } else if ((snapTarget.flag == SnapTarget.FLAG_DISMISS_END
+                || snapTarget == mSnapAlgorithm.getLastSplitTarget())
+                && dockSideBottomRight(dockSide)) {
+            dismissTarget = mSnapAlgorithm.getDismissEndTarget();
+            splitTarget = mSnapAlgorithm.getLastSplitTarget();
+        }
+        if (dismissTarget != null && fraction > 0f
+                && isDismissing(splitTarget, position, dockSide)) {
+            fraction = calculateParallaxDismissingFraction(fraction);
+            int offsetPosition = (int) (taskPosition +
+                    fraction * (dismissTarget.position - splitTarget.position));
+            int width = taskRect.width();
+            int height = taskRect.height();
+            switch (dockSide) {
+                case WindowManager.DOCKED_LEFT:
+                    taskRect.left = offsetPosition - width;
+                    taskRect.right = offsetPosition;
+                    break;
+                case WindowManager.DOCKED_RIGHT:
+                    taskRect.left = offsetPosition + mDividerSize;
+                    taskRect.right = offsetPosition + width + mDividerSize;
+                    break;
+                case WindowManager.DOCKED_TOP:
+                    taskRect.top = offsetPosition - height;
+                    taskRect.bottom = offsetPosition;
+                    break;
+                case WindowManager.DOCKED_BOTTOM:
+                    taskRect.top = offsetPosition + mDividerSize;
+                    taskRect.bottom = offsetPosition + height + mDividerSize;
+                    break;
+            }
+        }
+    }
+
+    /**
+     * @return for a specified {@code fraction}, this returns an adjusted value that simulates a
+     *         slowing down parallax effect
+     */
+    private static float calculateParallaxDismissingFraction(float fraction) {
+        return SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f;
+    }
+
+    private static boolean isDismissing(SnapTarget snapTarget, int position, int dockSide) {
+        if (dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT) {
+            return position < snapTarget.position;
+        } else {
+            return position > snapTarget.position;
+        }
+    }
+
+    private int getStackIdForDismissTarget(SnapTarget dismissTarget) {
+        if (dismissTarget.flag == SnapTarget.FLAG_DISMISS_START &&
+                (mDockSide == WindowManager.DOCKED_LEFT || mDockSide == WindowManager.DOCKED_TOP)) {
+            return StackId.DOCKED_STACK_ID;
+        } else {
+            return StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+        }
+    }
+
+    /**
+     * @return true if and only if {@code dockSide} is top or left
+     */
+    private static boolean dockSideTopLeft(int dockSide) {
+        return dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT;
+    }
+
+    /**
+     * @return true if and only if {@code dockSide} is bottom or right
+     */
+    private static boolean dockSideBottomRight(int dockSide) {
+        return dockSide == WindowManager.DOCKED_BOTTOM || dockSide == WindowManager.DOCKED_RIGHT;
     }
 
     @Override
@@ -353,4 +660,33 @@
         inoutInfo.touchableRegion.op(mBackground.getLeft(), mBackground.getTop(),
                 mBackground.getRight(), mBackground.getBottom(), Op.UNION);
     }
+
+    public final void onBusEvent(RecentsActivityStartingEvent recentsActivityStartingEvent) {
+        if (mGrowRecents && getWindowManagerProxy().getDockSide() == WindowManager.DOCKED_TOP
+                && getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position) {
+            mGrowAfterRecentsDrawn = true;
+            startDragging(false /* animate */, false /* touching */);
+        }
+    }
+
+    public final void onBusEvent(DockingTopTaskEvent dockingEvent) {
+        if (dockingEvent.dragMode == NavigationBarGestureHelper.DRAG_MODE_NONE) {
+            mGrowAfterRecentsDrawn = false;
+            mAnimateAfterRecentsDrawn = true;
+            startDragging(false /* animate */, false /* touching */);
+        }
+    }
+
+    public final void onBusEvent(RecentsDrawnEvent drawnEvent) {
+        if (mAnimateAfterRecentsDrawn) {
+            mAnimateAfterRecentsDrawn = false;
+            stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(), 250,
+                    TOUCH_RESPONSE_INTERPOLATOR);
+        }
+        if (mGrowAfterRecentsDrawn) {
+            mGrowAfterRecentsDrawn = false;
+            stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(), 250,
+                    TOUCH_RESPONSE_INTERPOLATOR);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
index 2251874..2294d40 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
@@ -26,6 +26,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
 import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
 import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 
 /**
@@ -50,6 +51,10 @@
                         | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY,
                 PixelFormat.TRANSLUCENT);
         mLp.setTitle(WINDOW_TITLE);
+        mLp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION;
+        view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
         mWindowManager.addView(view, mLp);
         mView = view;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index ef47d8d..24ab506 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -40,18 +40,41 @@
     private static final WindowManagerProxy sInstance = new WindowManagerProxy();
 
     @GuardedBy("mResizeRect")
-    private final Rect mResizeRect = new Rect();
-    private final Rect mTmpRect = new Rect();
+    private final Rect mDockedRect = new Rect();
+    private final Rect mTempDockedTaskRect = new Rect();
+    private final Rect mTempDockedInsetRect = new Rect();
+    private final Rect mTempOtherTaskRect = new Rect();
+    private final Rect mTempOtherInsetRect = new Rect();
+
+    private final Rect mTmpRect1 = new Rect();
+    private final Rect mTmpRect2 = new Rect();
+    private final Rect mTmpRect3 = new Rect();
+    private final Rect mTmpRect4 = new Rect();
+    private final Rect mTmpRect5 = new Rect();
+
+    private boolean mDimLayerVisible;
+    private int mDimLayerTargetStack;
+    private float mDimLayerAlpha;
+
     private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
 
     private final Runnable mResizeRunnable = new Runnable() {
         @Override
         public void run() {
-            synchronized (mResizeRect) {
-                mTmpRect.set(mResizeRect);
+            synchronized (mDockedRect) {
+                mTmpRect1.set(mDockedRect);
+                mTmpRect2.set(mTempDockedTaskRect);
+                mTmpRect3.set(mTempDockedInsetRect);
+                mTmpRect4.set(mTempOtherTaskRect);
+                mTmpRect5.set(mTempOtherInsetRect);
             }
             try {
-                ActivityManagerNative.getDefault().resizeStack(DOCKED_STACK_ID, mTmpRect, true);
+                ActivityManagerNative.getDefault()
+                        .resizeDockedStack(mTmpRect1,
+                                mTmpRect2.isEmpty() ? null : mTmpRect2,
+                                mTmpRect3.isEmpty() ? null : mTmpRect3,
+                                mTmpRect4.isEmpty() ? null : mTmpRect4,
+                                mTmpRect5.isEmpty() ? null : mTmpRect5);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed to resize stack: " + e);
             }
@@ -62,7 +85,8 @@
         @Override
         public void run() {
             try {
-                ActivityManagerNative.getDefault().moveTasksToFullscreenStack(DOCKED_STACK_ID);
+                ActivityManagerNative.getDefault().moveTasksToFullscreenStack(
+                        DOCKED_STACK_ID, false /* onTop */);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed to remove stack: " + e);
             }
@@ -73,7 +97,20 @@
         @Override
         public void run() {
             try {
-                ActivityManagerNative.getDefault().resizeStack(DOCKED_STACK_ID, null, true);
+                ActivityManagerNative.getDefault().resizeStack(DOCKED_STACK_ID, null, true, false,
+                        false);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to resize stack: " + e);
+            }
+        }
+    };
+
+    private final Runnable mDimLayerRunnable = new Runnable() {
+        @Override
+        public void run() {
+            try {
+                WindowManagerGlobal.getWindowManagerService().setResizeDimLayer(mDimLayerVisible,
+                        mDimLayerTargetStack, mDimLayerAlpha);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed to resize stack: " + e);
             }
@@ -87,9 +124,30 @@
         return sInstance;
     }
 
-    public void resizeDockedStack(Rect rect) {
-        synchronized (mResizeRect) {
-            mResizeRect.set(rect);
+    public void resizeDockedStack(Rect docked, Rect tempDockedTaskRect, Rect tempDockedInsetRect,
+            Rect tempOtherTaskRect, Rect tempOtherInsetRect) {
+        synchronized (mDockedRect) {
+            mDockedRect.set(docked);
+            if (tempDockedTaskRect != null) {
+                mTempDockedTaskRect.set(tempDockedTaskRect);
+            } else {
+                mTempDockedTaskRect.setEmpty();
+            }
+            if (tempDockedInsetRect != null) {
+                mTempDockedInsetRect.set(tempDockedInsetRect);
+            } else {
+                mTempDockedInsetRect.setEmpty();
+            }
+            if (tempOtherTaskRect != null) {
+                mTempOtherTaskRect.set(tempOtherTaskRect);
+            } else {
+                mTempOtherTaskRect.setEmpty();
+            }
+            if (tempOtherInsetRect != null) {
+                mTempOtherInsetRect.set(tempOtherInsetRect);
+            } else {
+                mTempOtherInsetRect.setEmpty();
+            }
         }
         mExecutor.execute(mResizeRunnable);
     }
@@ -123,4 +181,11 @@
         }
         return DOCKED_INVALID;
     }
+
+    public void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
+        mDimLayerVisible = visible;
+        mDimLayerTargetStack = targetStackId;
+        mDimLayerAlpha = alpha;
+        mExecutor.execute(mDimLayerRunnable);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index da3cd54..01bfcea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -19,6 +19,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
+import android.animation.TimeAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.Canvas;
@@ -28,13 +29,12 @@
 import android.view.View;
 import android.view.ViewAnimationUtils;
 import android.view.ViewConfiguration;
-import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
 import android.view.animation.PathInterpolator;
 
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 /**
  * Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer}
@@ -107,11 +107,8 @@
 
     private OnActivatedListener mOnActivatedListener;
 
-    private final Interpolator mLinearOutSlowInInterpolator;
-    protected final Interpolator mFastOutSlowInInterpolator;
     private final Interpolator mSlowOutFastInInterpolator;
     private final Interpolator mSlowOutLinearInInterpolator;
-    private final Interpolator mLinearInterpolator;
     private Interpolator mCurrentAppearInterpolator;
     private Interpolator mCurrentAlphaInterpolator;
 
@@ -132,16 +129,37 @@
     private FalsingManager mFalsingManager;
     private boolean mTrackTouch;
 
+    private float mNormalBackgroundVisibilityAmount;
+    private ValueAnimator mFadeInFromDarkAnimator;
+    private ValueAnimator.AnimatorUpdateListener mBackgroundVisibilityUpdater
+            = new ValueAnimator.AnimatorUpdateListener() {
+        @Override
+        public void onAnimationUpdate(ValueAnimator animation) {
+            setNormalBackgroundVisibilityAmount(mBackgroundNormal.getAlpha());
+        }
+    };
+    private AnimatorListenerAdapter mFadeInEndListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            super.onAnimationEnd(animation);
+            mFadeInFromDarkAnimator = null;
+            updateOutlineAlpha();
+        }
+    };
+    private ValueAnimator.AnimatorUpdateListener mUpdateOutlineListener
+            = new ValueAnimator.AnimatorUpdateListener() {
+        @Override
+        public void onAnimationUpdate(ValueAnimator animation) {
+            updateOutlineAlpha();
+        }
+    };
+    private float mShadowAlpha = 1.0f;
+
     public ActivatableNotificationView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
-        mFastOutSlowInInterpolator =
-                AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
         mSlowOutFastInInterpolator = new PathInterpolator(0.8f, 0.0f, 0.6f, 1.0f);
-        mLinearOutSlowInInterpolator =
-                AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in);
         mSlowOutLinearInInterpolator = new PathInterpolator(0.8f, 0.0f, 1.0f, 1.0f);
-        mLinearInterpolator = new LinearInterpolator();
         setClipChildren(false);
         setClipToPadding(false);
         mLegacyColor = context.getColor(R.color.notification_legacy_background_color);
@@ -166,6 +184,7 @@
         mBackgroundDimmed.setCustomBackground(R.drawable.notification_material_bg_dim);
         updateBackground();
         updateBackgroundTint();
+        updateOutlineAlpha();
     }
 
     private final Runnable mTapTimeoutRunnable = new Runnable() {
@@ -176,26 +195,31 @@
     };
 
     @Override
-    public boolean dispatchTouchEvent(MotionEvent event) {
-        if (mDimmed && !mActivated) {
-            return handleTouchEventDimmed(event);
-        } else {
-            return super.dispatchTouchEvent(event);
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (mDimmed && !mActivated
+                && ev.getActionMasked() == MotionEvent.ACTION_DOWN && disallowSingleClick(ev)) {
+            return true;
         }
+        return super.onInterceptTouchEvent(ev);
+    }
+
+    protected boolean disallowSingleClick(MotionEvent ev) {
+        return false;
     }
 
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         boolean result;
-        if (mDimmed && mActivated) {
+        if (mDimmed) {
+            boolean wasActivated = mActivated;
             result = handleTouchEventDimmed(event);
+            if (wasActivated && result && event.getAction() == MotionEvent.ACTION_UP) {
+                mFalsingManager.onNotificationDoubleTap();
+                removeCallbacks(mTapTimeoutRunnable);
+            }
         } else {
             result = super.onTouchEvent(event);
         }
-        if (mActivated && result && event.getAction() == MotionEvent.ACTION_UP) {
-            mFalsingManager.onNotificationDoubleTap();
-            removeCallbacks(mTapTimeoutRunnable);
-        }
         return result;
     }
 
@@ -267,7 +291,7 @@
         }
     }
 
-    private void startActivateAnimation(boolean reverse) {
+    private void startActivateAnimation(final boolean reverse) {
         if (!isAttachedToWindow()) {
             return;
         }
@@ -286,8 +310,8 @@
         Interpolator interpolator;
         Interpolator alphaInterpolator;
         if (!reverse) {
-            interpolator = mLinearOutSlowInInterpolator;
-            alphaInterpolator = mLinearOutSlowInInterpolator;
+            interpolator = Interpolators.LINEAR_OUT_SLOW_IN;
+            alphaInterpolator = Interpolators.LINEAR_OUT_SLOW_IN;
         } else {
             interpolator = ACTIVATE_INVERSE_INTERPOLATOR;
             alphaInterpolator = ACTIVATE_INVERSE_ALPHA_INTERPOLATOR;
@@ -312,6 +336,16 @@
         mBackgroundNormal.animate()
                 .alpha(reverse ? 0f : 1f)
                 .setInterpolator(alphaInterpolator)
+                .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                    @Override
+                    public void onAnimationUpdate(ValueAnimator animation) {
+                        float animatedFraction = animation.getAnimatedFraction();
+                        if (reverse) {
+                            animatedFraction = 1.0f - animatedFraction;
+                        }
+                        setNormalBackgroundVisibilityAmount(animatedFraction);
+                    }
+                })
                 .setDuration(ACTIVATE_ANIMATION_LENGTH);
     }
 
@@ -372,8 +406,27 @@
         } else {
             updateBackground();
         }
-        setOutlineAlpha(dark ? 0f : 1f);
-     }
+        updateOutlineAlpha();
+    }
+
+    private void updateOutlineAlpha() {
+        if (mDark) {
+            setOutlineAlpha(0f);
+            return;
+        }
+        float alpha = NotificationStackScrollLayout.BACKGROUND_ALPHA_DIMMED;
+        alpha = (alpha + (1.0f - alpha) * mNormalBackgroundVisibilityAmount);
+        alpha *= mShadowAlpha;
+        if (mFadeInFromDarkAnimator != null) {
+            alpha *= mFadeInFromDarkAnimator.getAnimatedFraction();
+        }
+        setOutlineAlpha(alpha);
+    }
+
+    public void setNormalBackgroundVisibilityAmount(float normalBackgroundVisibilityAmount) {
+        mNormalBackgroundVisibilityAmount = normalBackgroundVisibilityAmount;
+        updateOutlineAlpha();
+    }
 
     public void setShowingLegacyBackground(boolean showing) {
         mShowingLegacyBackground = showing;
@@ -426,7 +479,7 @@
                 .scaleY(1f)
                 .setDuration(DARK_ANIMATION_LENGTH)
                 .setStartDelay(delay)
-                .setInterpolator(mLinearOutSlowInInterpolator)
+                .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
                 .setListener(new AnimatorListenerAdapter() {
                     @Override
                     public void onAnimationCancel(Animator animation) {
@@ -436,7 +489,15 @@
                         background.setAlpha(1f);
                     }
                 })
+                .setUpdateListener(mBackgroundVisibilityUpdater)
                 .start();
+        mFadeInFromDarkAnimator = TimeAnimator.ofFloat(0.0f, 1.0f);
+        mFadeInFromDarkAnimator.setDuration(DARK_ANIMATION_LENGTH);
+        mFadeInFromDarkAnimator.setStartDelay(delay);
+        mFadeInFromDarkAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+        mFadeInFromDarkAnimator.addListener(mFadeInEndListener);
+        mFadeInFromDarkAnimator.addUpdateListener(mUpdateOutlineListener);
+        mFadeInFromDarkAnimator.start();
     }
 
     /**
@@ -469,7 +530,7 @@
         mBackgroundNormal.setAlpha(startAlpha);
         mBackgroundAnimator =
                 ObjectAnimator.ofFloat(mBackgroundNormal, View.ALPHA, startAlpha, endAlpha);
-        mBackgroundAnimator.setInterpolator(mFastOutSlowInInterpolator);
+        mBackgroundAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
         mBackgroundAnimator.setDuration(duration);
         mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
@@ -482,6 +543,7 @@
                 mBackgroundAnimator = null;
             }
         });
+        mBackgroundAnimator.addUpdateListener(mBackgroundVisibilityUpdater);
         mBackgroundAnimator.start();
     }
 
@@ -499,6 +561,8 @@
             mBackgroundNormal.setAlpha(1f);
             removeCallbacks(mTapTimeoutRunnable);
         }
+        setNormalBackgroundVisibilityAmount(
+                mBackgroundNormal.getVisibility() == View.VISIBLE ? 1.0f : 0.0f);
     }
 
     protected boolean shouldHideBackground() {
@@ -572,16 +636,16 @@
         float targetValue;
         if (isAppearing) {
             mCurrentAppearInterpolator = mSlowOutFastInInterpolator;
-            mCurrentAlphaInterpolator = mLinearOutSlowInInterpolator;
+            mCurrentAlphaInterpolator = Interpolators.LINEAR_OUT_SLOW_IN;
             targetValue = 1.0f;
         } else {
-            mCurrentAppearInterpolator = mFastOutSlowInInterpolator;
+            mCurrentAppearInterpolator = Interpolators.FAST_OUT_SLOW_IN;
             mCurrentAlphaInterpolator = mSlowOutLinearInInterpolator;
             targetValue = 0.0f;
         }
         mAppearAnimator = ValueAnimator.ofFloat(mAppearAnimationFraction,
                 targetValue);
-        mAppearAnimator.setInterpolator(mLinearInterpolator);
+        mAppearAnimator.setInterpolator(Interpolators.LINEAR);
         mAppearAnimator.setDuration(
                 (long) (duration * Math.abs(mAppearAnimationFraction - targetValue)));
         mAppearAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@@ -608,8 +672,6 @@
                     onFinishedRunnable.run();
                 }
                 if (!mWasCancelled) {
-                    mAppearAnimationFraction = -1;
-                    setOutlineRect(null);
                     enableAppearDrawing(false);
                 }
             }
@@ -630,6 +692,7 @@
     private void cancelAppearAnimation() {
         if (mAppearAnimator != null) {
             mAppearAnimator.cancel();
+            mAppearAnimator = null;
         }
     }
 
@@ -735,6 +798,8 @@
             mDrawingAppearAnimation = enable;
             if (!enable) {
                 setContentAlpha(1.0f);
+                mAppearAnimationFraction = -1;
+                setOutlineRect(null);
             }
             invalidate();
         }
@@ -766,6 +831,19 @@
         return getBgColor() == otherView.getBgColor();
     }
 
+    @Override
+    public float getShadowAlpha() {
+        return mShadowAlpha;
+    }
+
+    @Override
+    public void setShadowAlpha(float shadowAlpha) {
+        if (shadowAlpha != mShadowAlpha) {
+            mShadowAlpha = shadowAlpha;
+            updateOutlineAlpha();
+        }
+    }
+
     public interface OnActivatedListener {
         void onActivated(ActivatableNotificationView view);
         void onActivationReset(ActivatableNotificationView view);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 6d4dc872..4edb976 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -16,14 +16,11 @@
 
 package com.android.systemui.statusbar;
 
-import static  android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_MAX;
-
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.TimeInterpolator;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
-import android.app.INotificationManager;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -80,18 +77,15 @@
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.AnimationUtils;
-import android.widget.DateTimeView;
-import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.RemoteViews;
-import android.widget.SeekBar;
 import android.widget.TextView;
 import android.widget.Toast;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.statusbar.StatusBarIconList;
 import com.android.internal.util.NotificationColorUtil;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
@@ -110,11 +104,13 @@
 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.StackStateAnimator;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 
+import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_MAX;
 import static com.android.keyguard.KeyguardHostView.OnDismissAction;
 
 public abstract class BaseStatusBar extends SystemUI implements
@@ -125,9 +121,6 @@
     public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     public static final boolean MULTIUSER_DEBUG = false;
 
-    // STOPSHIP disable once we resolve b/18102199
-    private static final boolean NOTIFICATION_CLICK_DEBUG = true;
-
     public static final boolean ENABLE_REMOTE_INPUT =
             SystemProperties.getBoolean("debug.enable_remote_input", true);
     public static final boolean ENABLE_CHILD_NOTIFICATIONS
@@ -140,15 +133,14 @@
     protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
     protected static final int MSG_SHOW_NEXT_AFFILIATED_TASK = 1024;
     protected static final int MSG_SHOW_PREV_AFFILIATED_TASK = 1025;
-    protected static final int MSG_SHOW_KEYBOARD_SHORTCUTS_MENU = 1026;
+    protected static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU = 1026;
 
     protected static final boolean ENABLE_HEADS_UP = true;
-    // scores above this threshold should be displayed in heads up mode.
-    protected static final int INTERRUPTION_THRESHOLD = 10;
     protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
 
-    // Should match the value in PhoneWindowManager
+    // 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";
 
     private static final String BANNER_ACTION_CANCEL =
             "com.android.systemui.statusbar.banner_action_cancel";
@@ -196,16 +188,12 @@
 
     protected DevicePolicyManager mDevicePolicyManager;
     protected IDreamManager mDreamManager;
-    PowerManager mPowerManager;
+    protected PowerManager mPowerManager;
     protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
-    protected int mRowMinHeightLegacy;
-    protected int mRowMinHeight;
-    protected int mRowMaxHeight;
 
     // public mode, private notifications, etc
     private boolean mLockscreenPublicMode = false;
     private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
-    private NotificationColorUtil mNotificationColorUtil;
 
     private UserManager mUserManager;
 
@@ -233,7 +221,7 @@
     // which notification is currently being longpress-examined by the user
     private NotificationGuts mNotificationGutsExposed;
 
-    private TimeInterpolator mLinearOutSlowIn, mFastOutLinearIn;
+    private KeyboardShortcuts mKeyboardShortcuts;
 
     /**
      * The {@link StatusBarState} of the status bar.
@@ -355,9 +343,6 @@
                 ViewGroup actionGroup = (ViewGroup) parent;
                 index = actionGroup.indexOfChild(view);
             }
-            if (NOTIFICATION_CLICK_DEBUG) {
-                Log.d(TAG, "Clicked on button " + index + " for " + key);
-            }
             try {
                 mBarService.onNotificationActionClick(key, index);
             } catch (RemoteException e) {
@@ -615,8 +600,6 @@
         mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService(
                 Context.DEVICE_POLICY_SERVICE);
 
-        mNotificationColorUtil = NotificationColorUtil.getInstance(mContext);
-
         mNotificationData = new NotificationData(this);
 
         mAccessibilityManager = (AccessibilityManager)
@@ -655,19 +638,15 @@
 
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
 
-        mLinearOutSlowIn = AnimationUtils.loadInterpolator(mContext,
-                android.R.interpolator.linear_out_slow_in);
-        mFastOutLinearIn = AnimationUtils.loadInterpolator(mContext,
-                android.R.interpolator.fast_out_linear_in);
-
         // Connect in to the status bar manager service
-        StatusBarIconList iconList = new StatusBarIconList();
-        mCommandQueue = new CommandQueue(this, iconList);
+        mCommandQueue = new CommandQueue(this);
 
         int[] switches = new int[8];
         ArrayList<IBinder> binders = new ArrayList<IBinder>();
+        ArrayList<String> iconSlots = new ArrayList<>();
+        ArrayList<StatusBarIcon> icons = new ArrayList<>();
         try {
-            mBarService.registerStatusBar(mCommandQueue, iconList, switches, binders);
+            mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders);
         } catch (RemoteException ex) {
             // If the system process isn't there we're doomed anyway.
         }
@@ -682,14 +661,10 @@
         setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);
 
         // Set up the initial icon state
-        int N = iconList.size();
+        int N = iconSlots.size();
         int viewIndex = 0;
-        for (int i=0; i<N; i++) {
-            StatusBarIcon icon = iconList.getIcon(i);
-            if (icon != null) {
-                addIcon(iconList.getSlot(i), i, viewIndex, icon);
-                viewIndex++;
-            }
+        for (int i=0; i < N; i++) {
+            setIcon(iconSlots.get(i), icons.get(i));
         }
 
         // Set up the initial notification state.
@@ -705,7 +680,7 @@
         if (DEBUG) {
             Log.d(TAG, String.format(
                     "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
-                   iconList.size(),
+                   icons.size(),
                    switches[0],
                    switches[1],
                    switches[2],
@@ -947,7 +922,7 @@
         final StatusBarNotification sbn = row.getStatusBarNotification();
         PackageManager pmUser = getPackageManagerForUser(mContext, sbn.getUser().getIdentifier());
         row.setTag(sbn.getPackageName());
-        final View guts = row.getGuts();
+        final NotificationGuts guts = row.getGuts();
         final String pkg = sbn.getPackageName();
         String appname = pkg;
         Drawable pkgicon = null;
@@ -969,91 +944,34 @@
         ((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(pkgicon);
         ((TextView) row.findViewById(R.id.pkgname)).setText(appname);
 
-        bindTopicImportance(sbn, row);
-
-        final View settingsButton = guts.findViewById(R.id.notification_inspect_item);
+        final View settingsButton = guts.findViewById(R.id.more_settings);
         if (appUid >= 0) {
             final int appUidF = appUid;
             settingsButton.setOnClickListener(new View.OnClickListener() {
                 public void onClick(View v) {
-                    MetricsLogger.action(mContext, MetricsLogger.ACTION_NOTE_INFO);
+                    MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_INFO);
                     startAppNotificationSettingsActivity(pkg, appUidF);
                 }
             });
         } else {
             settingsButton.setVisibility(View.GONE);
         }
-    }
 
-    private void bindTopicImportance(final StatusBarNotification sbn,
-            ExpandableNotificationRow row) {
-        final INotificationManager sINM = INotificationManager.Stub.asInterface(
-                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
-        final Notification.Topic topic = sbn.getNotification().getTopic() == null
-                ? new Notification.Topic(Notification.TOPIC_DEFAULT, mContext.getString(
-                        com.android.internal.R.string.default_notification_topic_label))
-                : sbn.getNotification().getTopic();
-
-        ((TextView) row.findViewById(R.id.topic_details)).setText(topic.getLabel());
-        final TextView topicSummary = ((TextView) row.findViewById(R.id.summary));
-        int importance = mNotificationData.getImportance(sbn.getKey());
-        SeekBar seekBar = (SeekBar) row.findViewById(R.id.seekbar);
-        seekBar.setMax(4);
-        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+        row.findViewById(R.id.done).setOnClickListener(new View.OnClickListener() {
             @Override
-            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-                topicSummary.setText(getProgressSummary(progress));
-                if (fromUser) {
-                    try {
-                        sINM.setTopicImportance(sbn.getPackageName(), sbn.getUid(), topic,
-                                progress);
-                    } catch (RemoteException e) {
-                        // :(
-                    }
-                }
-            }
-
-            @Override
-            public void onStartTrackingTouch(SeekBar seekBar) {
-                // no-op
-            }
-
-            @Override
-            public void onStopTrackingTouch(SeekBar seekBar) {
-                // no-op
-            }
-
-            private String getProgressSummary(int progress) {
-                switch (progress) {
-                    case NotificationListenerService.Ranking.IMPORTANCE_NONE:
-                        return mContext.getString(
-                                com.android.internal.R.string.notification_importance_blocked);
-                    case NotificationListenerService.Ranking.IMPORTANCE_LOW:
-                        return mContext.getString(
-                                com.android.internal.R.string.notification_importance_low);
-                    case NotificationListenerService.Ranking.IMPORTANCE_DEFAULT:
-                        return mContext.getString(
-                                com.android.internal.R.string.notification_importance_default);
-                    case NotificationListenerService.Ranking.IMPORTANCE_HIGH:
-                        return mContext.getString(
-                                com.android.internal.R.string.notification_importance_high);
-                    case NotificationListenerService.Ranking.IMPORTANCE_MAX:
-                        return mContext.getString(
-                                com.android.internal.R.string.notification_importance_max);
-                    default:
-                        return "";
-                }
+            public void onClick(View v) {
+                guts.saveImportance(sbn);
+                dismissPopups();
             }
         });
-        seekBar.setProgress(importance);
+
+        guts.bindImportance(sbn, row, mNotificationData.getImportance(sbn.getKey()));
     }
 
     protected SwipeHelper.LongPressListener getNotificationLongClicker() {
         return new SwipeHelper.LongPressListener() {
             @Override
-            public boolean onLongPress(View v, int x, int y) {
-                dismissPopups();
-
+            public boolean onLongPress(View v, final int x, final int y) {
                 if (!(v instanceof ExpandableNotificationRow)) {
                     return false;
                 }
@@ -1074,42 +992,58 @@
 
                 // Already showing?
                 if (guts.getVisibility() == View.VISIBLE) {
-                    Log.e(TAG, "Trying to show notification guts, but already visible");
+                    dismissPopups(x, y);
                     return false;
                 }
 
-                MetricsLogger.action(mContext, MetricsLogger.ACTION_NOTE_CONTROLS);
-                guts.setVisibility(View.VISIBLE);
+                MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_CONTROLS);
 
-                final double horz = Math.max(guts.getWidth() - x, x);
-                final double vert = Math.max(guts.getActualHeight() - y, y);
-                final float r = (float) Math.hypot(horz, vert);
-                final Animator a
-                        = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r);
-                a.setDuration(400);
-                a.setInterpolator(mLinearOutSlowIn);
-                a.start();
-
-                mNotificationGutsExposed = guts;
-
+                // ensure that it's layouted but not visible until actually laid out
+                guts.setVisibility(View.INVISIBLE);
+                // Post to ensure the the guts are properly layed out.
+                guts.post(new Runnable() {
+                    public void run() {
+                        dismissPopups();
+                        guts.setVisibility(View.VISIBLE);
+                        final double horz = Math.max(guts.getWidth() - x, x);
+                        final double vert = Math.max(guts.getHeight() - y, y);
+                        final float r = (float) Math.hypot(horz, vert);
+                        final Animator a
+                                = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r);
+                        a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+                        a.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+                        a.start();
+                        guts.setExposed(true);
+                        mStackScroller.onHeightChanged(null, true /* needsAnimation */);
+                        mNotificationGutsExposed = guts;
+                    }
+                });
                 return true;
             }
         };
     }
 
     public void dismissPopups() {
+        dismissPopups(-1, -1);
+    }
+
+    private void dismissPopups(int x, int y) {
         if (mNotificationGutsExposed != null) {
             final NotificationGuts v = mNotificationGutsExposed;
             mNotificationGutsExposed = null;
 
             if (v.getWindowToken() == null) return;
-
-            final int x = (v.getLeft() + v.getRight()) / 2;
-            final int y = (v.getTop() + v.getActualHeight() / 2);
+            if (x == -1 || y == -1) {
+                x = (v.getLeft() + v.getRight()) / 2;
+                y = (v.getTop() + v.getHeight() / 2);
+            }
+            final double horz = Math.max(v.getWidth() - x, x);
+            final double vert = Math.max(v.getHeight() - y, y);
+            final float r = (float) Math.hypot(horz, vert);
             final Animator a = ViewAnimationUtils.createCircularReveal(v,
-                    x, y, x, 0);
-            a.setDuration(200);
-            a.setInterpolator(mFastOutLinearIn);
+                    x, y, r, 0);
+            a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+            a.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
             a.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
@@ -1118,6 +1052,8 @@
                 }
             });
             a.start();
+            v.setExposed(false);
+            mStackScroller.onHeightChanged(null, true /* needsAnimation */);
         }
     }
 
@@ -1156,8 +1092,8 @@
     }
 
     @Override
-    public void showKeyboardShortcutsMenu() {
-        int msg = MSG_SHOW_KEYBOARD_SHORTCUTS_MENU;
+    public void toggleKeyboardShortcutsMenu() {
+        int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
         mHandler.removeMessages(msg);
         mHandler.sendEmptyMessage(msg);
     }
@@ -1180,7 +1116,7 @@
          return new H();
     }
 
-    static void sendCloseSystemWindows(Context context, String reason) {
+    protected void sendCloseSystemWindows(String reason) {
         if (ActivityManagerNative.isSystemReady()) {
             try {
                 ActivityManagerNative.getDefault().closeSystemDialogs(reason);
@@ -1215,7 +1151,7 @@
 
     protected void showRecents(boolean triggeredFromAltTab) {
         if (mRecents != null) {
-            sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS);
+            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
             mRecents.showRecents(triggeredFromAltTab, getStatusBarView());
         }
     }
@@ -1228,7 +1164,6 @@
 
     protected void toggleRecents() {
         if (mRecents != null) {
-            sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS);
             mRecents.toggleRecents(mDisplay, mLayoutDirection, getStatusBarView());
         }
     }
@@ -1239,8 +1174,8 @@
         }
     }
 
-    protected void showKeyboardShortcuts() {
-        Toast.makeText(mContext, "Show keyboard shortcuts screen", Toast.LENGTH_LONG).show();
+    protected void toggleKeyboardShortcuts() {
+        getKeyboardShortcuts().toggleKeyboardShortcuts();
     }
 
     protected void cancelPreloadingRecents() {
@@ -1290,10 +1225,7 @@
             final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
                     mContext.getContentResolver(),
                     Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
-            final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
-                    userHandle);
-            final boolean allowedByDpm = (dpmFlags
-                    & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
+            final boolean allowedByDpm = adminAllowsUnredactedNotifications(userHandle);
             final boolean allowed = allowedByUser && allowedByDpm;
             mUsersAllowingPrivateNotifications.append(userHandle, allowed);
             return allowed;
@@ -1302,6 +1234,15 @@
         return mUsersAllowingPrivateNotifications.get(userHandle);
     }
 
+    private boolean adminAllowsUnredactedNotifications(int userHandle) {
+        if (userHandle == UserHandle.USER_ALL) {
+            return true;
+        }
+        final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
+                    userHandle);
+        return (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
+    }
+
     /**
      * 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
@@ -1325,18 +1266,22 @@
     }
 
     /**
-     * Called when the size of the notification panel changes
+     * Called when the notification panel layouts
      */
-    public void onPanelHeightChanged() {
+    public void onPanelLaidOut() {
         if (mState == StatusBarState.KEYGUARD) {
             // Since the number of notifications is determined based on the height of the view, we
             // need to update them.
-            updateRowStates();
+            int maxBefore = getMaxKeyguardNotifications(false /* recompute */);
+            int maxNotifications = getMaxKeyguardNotifications(true /* recompute */);
+            if (maxBefore != maxNotifications) {
+                updateRowStates();
+            }
         }
     }
 
     @Override
-    public void onExpandClicked(View clickedView, boolean nowExpanded) {
+    public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
     }
 
     protected class H extends Handler {
@@ -1363,8 +1308,8 @@
              case MSG_SHOW_PREV_AFFILIATED_TASK:
                   showRecentsPreviousAffiliatedTask();
                   break;
-             case MSG_SHOW_KEYBOARD_SHORTCUTS_MENU:
-                  showKeyboardShortcuts();
+             case MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU:
+                  toggleKeyboardShortcuts();
                   break;
             }
         }
@@ -1419,6 +1364,7 @@
                     parent, false);
             row.setExpansionLogger(this, entry.notification.getKey());
             row.setGroupManager(mGroupManager);
+            row.setHeadsUpManager(mHeadsUpManager);
             row.setRemoteInputController(mRemoteInputController);
             row.setOnExpandClickListener(this);
         }
@@ -1445,6 +1391,7 @@
         View contentViewLocal = null;
         View bigContentViewLocal = null;
         View headsUpContentViewLocal = null;
+        View publicViewLocal = null;
         try {
             contentViewLocal = contentView.apply(
                     sbn.getPackageContext(mContext),
@@ -1462,6 +1409,11 @@
                         contentContainer,
                         mOnClickHandler);
             }
+            if (publicContentView != null) {
+                publicViewLocal = publicContentView.apply(
+                        sbn.getPackageContext(mContext),
+                        contentContainerPublic, mOnClickHandler);
+            }
         }
         catch (RuntimeException e) {
             final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
@@ -1481,25 +1433,9 @@
             headsUpContentViewLocal.setIsRootNamespace(true);
             contentContainer.setHeadsUpChild(headsUpContentViewLocal);
         }
-
-        // now the public version
-        View publicViewLocal = null;
-        if (publicContentView != null) {
-            try {
-                publicViewLocal = publicContentView.apply(
-                        sbn.getPackageContext(mContext),
-                        contentContainerPublic, mOnClickHandler);
-
-                if (publicViewLocal != null) {
-                    publicViewLocal.setIsRootNamespace(true);
-                    contentContainerPublic.setContractedChild(publicViewLocal);
-                }
-            }
-            catch (RuntimeException e) {
-                final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
-                Log.e(TAG, "couldn't inflate public view for notification " + ident, e);
-                publicViewLocal = null;
-            }
+        if (publicViewLocal != null) {
+            publicViewLocal.setIsRootNamespace(true);
+            contentContainerPublic.setContractedChild(publicViewLocal);
         }
 
         // Extract target SDK version.
@@ -1509,65 +1445,7 @@
         } catch (NameNotFoundException ex) {
             Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
         }
-
-        if (publicViewLocal == null) {
-            // Add a basic notification template
-            publicViewLocal = LayoutInflater.from(mContext).inflate(
-                    R.layout.notification_public_default,
-                    contentContainerPublic, false);
-            publicViewLocal.setIsRootNamespace(true);
-
-            final TextView title = (TextView) publicViewLocal.findViewById(R.id.title);
-            try {
-                title.setText(pmUser.getApplicationLabel(
-                        pmUser.getApplicationInfo(entry.notification.getPackageName(), 0)));
-            } catch (NameNotFoundException e) {
-                title.setText(entry.notification.getPackageName());
-            }
-
-            final ImageView icon = (ImageView) publicViewLocal.findViewById(R.id.icon);
-            final ImageView profileBadge = (ImageView) publicViewLocal.findViewById(
-                    R.id.profile_badge_line3);
-
-            final StatusBarIcon ic = new StatusBarIcon(
-                    entry.notification.getUser(),
-                    entry.notification.getPackageName(),
-                    entry.notification.getNotification().getSmallIcon(),
-                    entry.notification.getNotification().iconLevel,
-                    entry.notification.getNotification().number,
-                    entry.notification.getNotification().tickerText);
-
-            Drawable iconDrawable = StatusBarIconView.getIcon(mContext, ic);
-            icon.setImageDrawable(iconDrawable);
-
-            if (profileBadge != null) {
-                Drawable profileDrawable = mContext.getPackageManager().getUserBadgeForDensity(
-                        entry.notification.getUser(), 0);
-                if (profileDrawable != null) {
-                    profileBadge.setImageDrawable(profileDrawable);
-                    profileBadge.setVisibility(View.VISIBLE);
-                } else {
-                    profileBadge.setVisibility(View.GONE);
-                }
-            }
-
-            final View privateTime = contentViewLocal.findViewById(com.android.internal.R.id.time);
-            final DateTimeView time = (DateTimeView) publicViewLocal.findViewById(R.id.time);
-            if (privateTime != null && privateTime.getVisibility() == View.VISIBLE) {
-                time.setVisibility(View.VISIBLE);
-                time.setTime(entry.notification.getNotification().when);
-            }
-
-            final TextView text = (TextView) publicViewLocal.findViewById(R.id.text);
-            if (text != null) {
-                text.setText(R.string.notification_hidden_text);
-                text.setTextAppearance(mContext,
-                        R.style.TextAppearance_Material_Notification_Parenthetical);
-            }
-
-            contentContainerPublic.setContractedChild(publicViewLocal);
-            entry.autoRedacted = true;
-        }
+        entry.autoRedacted = entry.notification.getNotification().publicVersion == null;
 
         if (MULTIUSER_DEBUG) {
             TextView debug = (TextView) row.findViewById(R.id.debug_info);
@@ -1612,8 +1490,14 @@
 
             for (int i = 0; i < numActions; i++) {
                 Notification.Action action = actions.get(i);
+                if (action == null) {
+                    continue;
+                }
                 RemoteInput[] remoteInputs = action.getRemoteInputs();
-                for (RemoteInput ri : action.getRemoteInputs()) {
+                if (remoteInputs == null) {
+                    continue;
+                }
+                for (RemoteInput ri : remoteInputs) {
                     if (ri.getAllowFreeFormInput()) {
                         viableAction = action;
                         break;
@@ -1632,6 +1516,14 @@
         }
     }
 
+    protected KeyboardShortcuts getKeyboardShortcuts() {
+        if (mKeyboardShortcuts == null) {
+            mKeyboardShortcuts = new KeyboardShortcuts(mContext);
+        }
+
+        return mKeyboardShortcuts;
+    }
+
     public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
         if (!isDeviceProvisioned()) return;
 
@@ -1714,9 +1606,6 @@
                 }
             });
 
-            if (NOTIFICATION_CLICK_DEBUG) {
-                Log.d(TAG, "Clicked on content of " + notificationKey);
-            }
             final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
             final boolean afterKeyguardGone = intent.isActivity()
                     && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
@@ -2071,8 +1960,9 @@
                     + " alertAgain=" + alertAgain);
         }
 
+        final StatusBarNotification oldNotification = entry.notification;
         entry.notification = notification;
-        mGroupManager.onEntryUpdated(entry, entry.notification);
+        mGroupManager.onEntryUpdated(entry, oldNotification);
 
         boolean updateSuccessful = false;
         if (applyInPlace) {
@@ -2098,7 +1988,8 @@
             }
             catch (RuntimeException e) {
                 // It failed to apply cleanly.
-                Log.w(TAG, "Couldn't reapply views for package " + n.contentView.getPackage(), e);
+                Log.w(TAG, "Couldn't reapply views for package " +
+                        notification.getPackageName(), e);
             }
         }
         if (!updateSuccessful) {
@@ -2162,6 +2053,21 @@
         entry.row.resetHeight();
     }
 
+    protected void updatePublicContentView(Entry entry,
+            StatusBarNotification sbn) {
+        final RemoteViews publicContentView = entry.cachedPublicContentView;
+        if (publicContentView != null && entry.getPublicContentView() != 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);
+        }
+    }
+
     protected void notifyHeadsUpScreenOff() {
         maybeEscalateHeadsUp();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index deedae0..cc26223 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -21,10 +21,8 @@
 import android.os.IBinder;
 import android.os.Message;
 import android.util.Pair;
-
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.statusbar.StatusBarIconList;
 
 /**
  * This class takes the functions from IStatusBar that come in on
@@ -65,7 +63,7 @@
     private static final int MSG_ASSIST_DISCLOSURE          = 22 << MSG_SHIFT;
     private static final int MSG_START_ASSIST               = 23 << MSG_SHIFT;
     private static final int MSG_CAMERA_LAUNCH_GESTURE      = 24 << MSG_SHIFT;
-    private static final int MSG_SHOW_KEYBOARD_SHORTCUTS    = 25 << MSG_SHIFT;
+    private static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS  = 25 << MSG_SHIFT;
 
     public static final int FLAG_EXCLUDE_NONE = 0;
     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -76,7 +74,7 @@
 
     private static final String SHOW_IME_SWITCHER_KEY = "showImeSwitcherKey";
 
-    private StatusBarIconList mList;
+    private final Object mLock = new Object();
     private Callbacks mCallbacks;
     private Handler mHandler = new H();
 
@@ -84,10 +82,8 @@
      * These methods are called back on the main thread.
      */
     public interface Callbacks {
-        public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon);
-        public void updateIcon(String slot, int index, int viewIndex,
-                StatusBarIcon old, StatusBarIcon icon);
-        public void removeIcon(String slot, int index, int viewIndex);
+        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);
@@ -100,7 +96,7 @@
         public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
         public void toggleRecentApps();
         public void preloadRecentApps();
-        public void showKeyboardShortcutsMenu();
+        public void toggleKeyboardShortcutsMenu();
         public void cancelPreloadRecentApps();
         public void setWindowState(int window, int state);
         public void buzzBeepBlinked();
@@ -115,57 +111,55 @@
         public void onCameraLaunchGestureDetected(int source);
     }
 
-    public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
+    public CommandQueue(Callbacks callbacks) {
         mCallbacks = callbacks;
-        mList = list;
     }
 
-    public void setIcon(int index, StatusBarIcon icon) {
-        synchronized (mList) {
-            int what = MSG_ICON | index;
-            mHandler.removeMessages(what);
-            mHandler.obtainMessage(what, OP_SET_ICON, 0, icon.clone()).sendToTarget();
+    public void setIcon(String slot, StatusBarIcon icon) {
+        synchronized (mLock) {
+            // don't coalesce these
+            mHandler.obtainMessage(MSG_ICON, OP_SET_ICON, 0,
+                    new Pair<String, StatusBarIcon>(slot, icon)).sendToTarget();
         }
     }
 
-    public void removeIcon(int index) {
-        synchronized (mList) {
-            int what = MSG_ICON | index;
-            mHandler.removeMessages(what);
-            mHandler.obtainMessage(what, OP_REMOVE_ICON, 0, null).sendToTarget();
+    public void removeIcon(String slot) {
+        synchronized (mLock) {
+            // don't coalesce these
+            mHandler.obtainMessage(MSG_ICON, OP_REMOVE_ICON, 0, slot).sendToTarget();
         }
     }
 
     public void disable(int state1, int state2) {
-        synchronized (mList) {
+        synchronized (mLock) {
             mHandler.removeMessages(MSG_DISABLE);
             mHandler.obtainMessage(MSG_DISABLE, state1, state2, null).sendToTarget();
         }
     }
 
     public void animateExpandNotificationsPanel() {
-        synchronized (mList) {
+        synchronized (mLock) {
             mHandler.removeMessages(MSG_EXPAND_NOTIFICATIONS);
             mHandler.sendEmptyMessage(MSG_EXPAND_NOTIFICATIONS);
         }
     }
 
     public void animateCollapsePanels() {
-        synchronized (mList) {
+        synchronized (mLock) {
             mHandler.removeMessages(MSG_COLLAPSE_PANELS);
             mHandler.sendEmptyMessage(MSG_COLLAPSE_PANELS);
         }
     }
 
     public void animateExpandSettingsPanel(String subPanel) {
-        synchronized (mList) {
+        synchronized (mLock) {
             mHandler.removeMessages(MSG_EXPAND_SETTINGS);
             mHandler.obtainMessage(MSG_EXPAND_SETTINGS, subPanel).sendToTarget();
         }
     }
 
     public void setSystemUiVisibility(int vis, int mask) {
-        synchronized (mList) {
+        synchronized (mLock) {
             // Don't coalesce these, since it might have one time flags set such as
             // STATUS_BAR_UNHIDE which might get lost.
             mHandler.obtainMessage(MSG_SET_SYSTEMUI_VISIBILITY, vis, mask, null).sendToTarget();
@@ -173,7 +167,7 @@
     }
 
     public void topAppWindowChanged(boolean menuVisible) {
-        synchronized (mList) {
+        synchronized (mLock) {
             mHandler.removeMessages(MSG_TOP_APP_WINDOW_CHANGED);
             mHandler.obtainMessage(MSG_TOP_APP_WINDOW_CHANGED, menuVisible ? 1 : 0, 0,
                     null).sendToTarget();
@@ -182,7 +176,7 @@
 
     public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
             boolean showImeSwitcher) {
-        synchronized (mList) {
+        synchronized (mLock) {
             mHandler.removeMessages(MSG_SHOW_IME_BUTTON);
             Message m = mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, vis, backDisposition, token);
             m.getData().putBoolean(SHOW_IME_SWITCHER_KEY, showImeSwitcher);
@@ -191,7 +185,7 @@
     }
 
     public void showRecentApps(boolean triggeredFromAltTab) {
-        synchronized (mList) {
+        synchronized (mLock) {
             mHandler.removeMessages(MSG_SHOW_RECENT_APPS);
             mHandler.obtainMessage(MSG_SHOW_RECENT_APPS,
                     triggeredFromAltTab ? 1 : 0, 0, null).sendToTarget();
@@ -199,7 +193,7 @@
     }
 
     public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
-        synchronized (mList) {
+        synchronized (mLock) {
             mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
             mHandler.obtainMessage(MSG_HIDE_RECENT_APPS,
                     triggeredFromAltTab ? 1 : 0, triggeredFromHomeKey ? 1 : 0,
@@ -208,83 +202,83 @@
     }
 
     public void toggleRecentApps() {
-        synchronized (mList) {
+        synchronized (mLock) {
             mHandler.removeMessages(MSG_TOGGLE_RECENT_APPS);
             mHandler.obtainMessage(MSG_TOGGLE_RECENT_APPS, 0, 0, null).sendToTarget();
         }
     }
 
     public void preloadRecentApps() {
-        synchronized (mList) {
+        synchronized (mLock) {
             mHandler.removeMessages(MSG_PRELOAD_RECENT_APPS);
             mHandler.obtainMessage(MSG_PRELOAD_RECENT_APPS, 0, 0, null).sendToTarget();
         }
     }
 
     public void cancelPreloadRecentApps() {
-        synchronized (mList) {
+        synchronized (mLock) {
             mHandler.removeMessages(MSG_CANCEL_PRELOAD_RECENT_APPS);
             mHandler.obtainMessage(MSG_CANCEL_PRELOAD_RECENT_APPS, 0, 0, null).sendToTarget();
         }
     }
 
     @Override
-    public void showKeyboardShortcutsMenu() {
-        synchronized (mList) {
-            mHandler.removeMessages(MSG_SHOW_KEYBOARD_SHORTCUTS);
-            mHandler.obtainMessage(MSG_SHOW_KEYBOARD_SHORTCUTS).sendToTarget();
+    public void toggleKeyboardShortcutsMenu() {
+        synchronized (mLock) {
+            mHandler.removeMessages(MSG_TOGGLE_KEYBOARD_SHORTCUTS);
+            mHandler.obtainMessage(MSG_TOGGLE_KEYBOARD_SHORTCUTS).sendToTarget();
         }
     }
 
     public void setWindowState(int window, int state) {
-        synchronized (mList) {
+        synchronized (mLock) {
             // don't coalesce these
             mHandler.obtainMessage(MSG_SET_WINDOW_STATE, window, state, null).sendToTarget();
         }
     }
 
     public void buzzBeepBlinked() {
-        synchronized (mList) {
+        synchronized (mLock) {
             mHandler.removeMessages(MSG_BUZZ_BEEP_BLINKED);
             mHandler.sendEmptyMessage(MSG_BUZZ_BEEP_BLINKED);
         }
     }
 
     public void notificationLightOff() {
-        synchronized (mList) {
+        synchronized (mLock) {
             mHandler.sendEmptyMessage(MSG_NOTIFICATION_LIGHT_OFF);
         }
     }
 
     public void notificationLightPulse(int argb, int onMillis, int offMillis) {
-        synchronized (mList) {
+        synchronized (mLock) {
             mHandler.obtainMessage(MSG_NOTIFICATION_LIGHT_PULSE, onMillis, offMillis, argb)
                     .sendToTarget();
         }
     }
 
     public void showScreenPinningRequest() {
-        synchronized (mList) {
+        synchronized (mLock) {
             mHandler.sendEmptyMessage(MSG_SHOW_SCREEN_PIN_REQUEST);
         }
     }
 
     public void appTransitionPending() {
-        synchronized (mList) {
+        synchronized (mLock) {
             mHandler.removeMessages(MSG_APP_TRANSITION_PENDING);
             mHandler.sendEmptyMessage(MSG_APP_TRANSITION_PENDING);
         }
     }
 
     public void appTransitionCancelled() {
-        synchronized (mList) {
+        synchronized (mLock) {
             mHandler.removeMessages(MSG_APP_TRANSITION_PENDING);
             mHandler.sendEmptyMessage(MSG_APP_TRANSITION_PENDING);
         }
     }
 
     public void appTransitionStarting(long startTime, long duration) {
-        synchronized (mList) {
+        synchronized (mLock) {
             mHandler.removeMessages(MSG_APP_TRANSITION_STARTING);
             mHandler.obtainMessage(MSG_APP_TRANSITION_STARTING, Pair.create(startTime, duration))
                     .sendToTarget();
@@ -292,14 +286,14 @@
     }
 
     public void showAssistDisclosure() {
-        synchronized (mList) {
+        synchronized (mLock) {
             mHandler.removeMessages(MSG_ASSIST_DISCLOSURE);
             mHandler.obtainMessage(MSG_ASSIST_DISCLOSURE).sendToTarget();
         }
     }
 
     public void startAssist(Bundle args) {
-        synchronized (mList) {
+        synchronized (mLock) {
             mHandler.removeMessages(MSG_START_ASSIST);
             mHandler.obtainMessage(MSG_START_ASSIST, args).sendToTarget();
         }
@@ -307,7 +301,7 @@
 
     @Override
     public void onCameraLaunchGestureDetected(int source) {
-        synchronized (mList) {
+        synchronized (mLock) {
             mHandler.removeMessages(MSG_CAMERA_LAUNCH_GESTURE);
             mHandler.obtainMessage(MSG_CAMERA_LAUNCH_GESTURE, source, 0).sendToTarget();
         }
@@ -318,27 +312,14 @@
             final int what = msg.what & MSG_MASK;
             switch (what) {
                 case MSG_ICON: {
-                    final int index = msg.what & INDEX_MASK;
-                    final int viewIndex = mList.getViewIndex(index);
                     switch (msg.arg1) {
                         case OP_SET_ICON: {
-                            StatusBarIcon icon = (StatusBarIcon)msg.obj;
-                            StatusBarIcon old = mList.getIcon(index);
-                            if (old == null) {
-                                mList.setIcon(index, icon);
-                                mCallbacks.addIcon(mList.getSlot(index), index, viewIndex, icon);
-                            } else {
-                                mList.setIcon(index, icon);
-                                mCallbacks.updateIcon(mList.getSlot(index), index, viewIndex,
-                                        old, icon);
-                            }
+                            Pair<String, StatusBarIcon> p = (Pair<String, StatusBarIcon>) msg.obj;
+                            mCallbacks.setIcon(p.first, p.second);
                             break;
                         }
                         case OP_REMOVE_ICON:
-                            if (mList.getIcon(index) != null) {
-                                mList.removeIcon(index);
-                                mCallbacks.removeIcon(mList.getSlot(index), index, viewIndex);
-                            }
+                            mCallbacks.removeIcon((String) msg.obj);
                             break;
                     }
                     break;
@@ -380,8 +361,8 @@
                 case MSG_CANCEL_PRELOAD_RECENT_APPS:
                     mCallbacks.cancelPreloadRecentApps();
                     break;
-                case MSG_SHOW_KEYBOARD_SHORTCUTS:
-                    mCallbacks.showKeyboardShortcutsMenu();
+                case MSG_TOGGLE_KEYBOARD_SHORTCUTS:
+                    mCallbacks.toggleKeyboardShortcutsMenu();
                     break;
                 case MSG_SET_WINDOW_STATE:
                     mCallbacks.setWindowState(msg.arg1, msg.arg2);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
new file mode 100644
index 0000000..24cd948
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.view.View;
+
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+
+/**
+ * A helper to fade views in and out.
+ */
+public class CrossFadeHelper {
+    public static final long ANIMATION_DURATION_LENGTH = 210;
+
+    public static void fadeOut(final View view, final Runnable endRunnable) {
+        view.animate().cancel();
+        view.animate()
+                .alpha(0f)
+                .setDuration(ANIMATION_DURATION_LENGTH)
+                .setInterpolator(Interpolators.ALPHA_OUT)
+                .withEndAction(new Runnable() {
+                    @Override
+                    public void run() {
+                        if (endRunnable != null) {
+                            endRunnable.run();
+                        }
+                        view.setVisibility(View.INVISIBLE);
+                    }
+                });
+        if (view.hasOverlappingRendering()) {
+            view.animate().withLayer();
+        }
+
+    }
+
+    public static void fadeIn(final View view) {
+        view.animate().cancel();
+        if (view.getVisibility() == View.INVISIBLE) {
+            view.setAlpha(0.0f);
+            view.setVisibility(View.VISIBLE);
+        }
+        view.animate()
+                .alpha(1f)
+                .setDuration(ANIMATION_DURATION_LENGTH)
+                .setInterpolator(Interpolators.ALPHA_IN)
+                .withEndAction(null);
+        if (view.hasOverlappingRendering()) {
+            view.animate().withLayer();
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index 8570198..5c83f5f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -24,8 +24,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
+
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
@@ -53,7 +52,6 @@
     private final int[] mTemp2 = new int[2];
     private boolean mDraggedFarEnough;
     private ExpandableView mStartingChild;
-    private Interpolator mInterpolator;
     private float mLastHeight;
     private FalsingManager mFalsingManager;
 
@@ -61,8 +59,6 @@
             DragDownCallback dragDownCallback) {
         mMinDragDistance = context.getResources().getDimensionPixelSize(
                 R.dimen.keyguard_drag_down_min_distance);
-        mInterpolator =
-                AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
         mCallback = callback;
         mDragDownCallback = dragDownCallback;
@@ -187,7 +183,7 @@
         }
         ObjectAnimator anim = ObjectAnimator.ofInt(child, "actualHeight",
                 child.getActualHeight(), child.getMinHeight());
-        anim.setInterpolator(mInterpolator);
+        anim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
         anim.setDuration(SPRING_BACK_ANIMATION_LENGTH_MS);
         anim.addListener(new AnimatorListenerAdapter() {
             @Override
@@ -200,7 +196,7 @@
 
     private void cancelExpansion() {
         ValueAnimator anim = ValueAnimator.ofFloat(mLastHeight, 0);
-        anim.setInterpolator(mInterpolator);
+        anim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
         anim.setDuration(SPRING_BACK_ANIMATION_LENGTH_MS);
         anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
             @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 874b76a..6fae3ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -28,16 +28,18 @@
 import android.view.MotionEvent;
 import android.view.NotificationHeaderView;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.ViewStub;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.LinearInterpolator;
 import android.widget.Chronometer;
 import android.widget.ImageView;
 import android.widget.RemoteViews;
 
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.statusbar.notification.NotificationViewWrapper;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
 import com.android.systemui.statusbar.stack.StackScrollState;
 import com.android.systemui.statusbar.stack.StackStateAnimator;
@@ -49,13 +51,11 @@
 
     private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
     private static final int COLORED_DIVIDER_ALPHA = 0x7B;
-    private final LinearInterpolator mLinearInterpolator = new LinearInterpolator();
     private final int mNotificationMinHeightLegacy;
     private final int mMaxHeadsUpHeightLegacy;
     private final int mMaxHeadsUpHeight;
     private final int mNotificationMinHeight;
     private final int mNotificationMaxHeight;
-    private int mRowMinHeight;
 
     /** Does this row contain layouts that can adapt to row expansion */
     private boolean mExpandable;
@@ -63,6 +63,11 @@
     private boolean mHasUserChangedExpansion;
     /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
     private boolean mUserExpanded;
+
+    /**
+     * Has this notification been expanded while it was pinned
+     */
+    private boolean mExpandedWhenPinned;
     /** Is the user touching this row */
     private boolean mUserLocked;
     /** Are we showing the "public" version */
@@ -107,6 +112,7 @@
     private boolean mIsSystemChildExpanded;
     private boolean mIsPinned;
     private FalsingManager mFalsingManager;
+    private HeadsUpManager mHeadsUpManager;
     private NotificationHeaderUtil mHeaderUtil = new NotificationHeaderUtil(this);
 
     private boolean mJustClicked;
@@ -117,16 +123,21 @@
     private OnClickListener mExpandClickListener = new OnClickListener() {
         @Override
         public void onClick(View v) {
-            if (mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
+            if (!mShowingPublic && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
                 mGroupManager.toggleGroupExpansion(mStatusBarNotification);
-                mOnExpandClickListener.onExpandClicked(ExpandableNotificationRow.this,
+                mOnExpandClickListener.onExpandClicked(mEntry,
                         mGroupManager.isGroupExpanded(mStatusBarNotification));
             } else {
-                boolean nowExpanded = !isExpanded();
-                setUserExpanded(nowExpanded);
+                boolean nowExpanded;
+                if (isPinned()) {
+                    nowExpanded = !mExpandedWhenPinned;
+                    mExpandedWhenPinned = nowExpanded;
+                } else {
+                    nowExpanded = !isExpanded();
+                    setUserExpanded(nowExpanded);
+                }
                 notifyHeightChanged(true);
-                mOnExpandClickListener.onExpandClicked(ExpandableNotificationRow.this,
-                        nowExpanded);
+                mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
             }
         }
     };
@@ -212,6 +223,8 @@
             mNotificationParent.updateChildrenHeaderAppearance();
         }
         onChildrenCountChanged();
+        // The public layouts expand button is always visible
+        mPublicLayout.updateExpandButtons(true);
         updateLimits();
     }
 
@@ -226,10 +239,9 @@
                 != com.android.internal.R.id.status_bar_latest_event_content;
         int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
                 : mMaxHeadsUpHeight;
-        mRowMinHeight = minHeight;
         mMaxViewHeight = mNotificationMaxHeight;
-        mPrivateLayout.setHeights(mRowMinHeight, headsUpheight);
-        mPublicLayout.setHeights(mRowMinHeight, headsUpheight);
+        mPrivateLayout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
+        mPublicLayout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
     }
 
     public StatusBarNotification getStatusBarNotification() {
@@ -306,6 +318,16 @@
     }
 
     @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (event.getActionMasked() != MotionEvent.ACTION_DOWN
+                || !isChildInGroup() || isGroupExpanded()) {
+            return super.onTouchEvent(event);
+        } else {
+            return false;
+        }
+    }
+
+    @Override
     protected boolean shouldHideBackground() {
         return super.shouldHideBackground() || mShowNoBackground;
     }
@@ -361,9 +383,9 @@
     }
 
     public void startChildAnimation(StackScrollState finalState,
-            StackStateAnimator stateAnimator, boolean withDelays, long delay, long duration) {
+            StackStateAnimator stateAnimator, long delay, long duration) {
         if (mIsSummaryWithChildren) {
-            mChildrenContainer.startAnimationToState(finalState, stateAnimator, withDelays, delay,
+            mChildrenContainer.startAnimationToState(finalState, stateAnimator, delay,
                     duration);
         }
     }
@@ -389,6 +411,12 @@
      */
     public void setPinned(boolean pinned) {
         mIsPinned = pinned;
+        if (pinned) {
+            setIconAnimationRunning(true);
+            mExpandedWhenPinned = false;
+        } else if (mExpandedWhenPinned) {
+            setUserExpanded(true);
+        }
         setChronometerRunning(mLastChronometerRunning);
     }
 
@@ -396,11 +424,22 @@
         return mIsPinned;
     }
 
-    public int getHeadsUpHeight() {
+    /**
+     * @param atLeastMinHeight should the value returned be at least the minimum height.
+     *                         Used to avoid cyclic calls
+     * @return the height of the heads up notification when pinned
+     */
+    public int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
         if (mIsSummaryWithChildren) {
             return mChildrenContainer.getIntrinsicHeight();
         }
-        return mHeadsUpHeight;
+        if(mExpandedWhenPinned) {
+            return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
+        } else if (atLeastMinHeight) {
+            return Math.max(getMinHeight(), mHeadsUpHeight);
+        } else {
+            return mHeadsUpHeight;
+        }
     }
 
     /**
@@ -464,6 +503,10 @@
         mOnExpandClickListener = onExpandClickListener;
     }
 
+    public void setHeadsUpManager(HeadsUpManager headsUpManager) {
+        mHeadsUpManager = headsUpManager;
+    }
+
     public interface ExpansionLogger {
         public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
     }
@@ -489,7 +532,6 @@
     @Override
     public void reset() {
         super.reset();
-        mRowMinHeight = 0;
         final boolean wasExpanded = isExpanded();
         mMaxViewHeight = 0;
         mExpandable = false;
@@ -518,16 +560,13 @@
     }
 
     @Override
-    protected boolean filterMotionEvent(MotionEvent event) {
-        return mIsHeadsUp || super.filterMotionEvent(event);
-    }
-
-    @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
         mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
+        mPublicLayout.setContainingNotification(this);
         mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
         mPrivateLayout.setExpandClickListener(mExpandClickListener);
+        mPrivateLayout.setContainingNotification(this);
         mPublicLayout.setExpandClickListener(mExpandClickListener);
         mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
         mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
@@ -558,12 +597,16 @@
     }
 
     private void updateChildrenVisibility() {
-        if (mChildrenContainer == null) {
-            return;
+        mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
+                : INVISIBLE);
+        if (mChildrenContainer != null) {
+            mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
+                    : INVISIBLE);
         }
-        mChildrenContainer.setVisibility(mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
-        mNotificationHeader.setVisibility(mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
-        mPrivateLayout.setVisibility(!mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
+        if (mNotificationHeader != null) {
+            mNotificationHeader.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
+                    : INVISIBLE);
+        }
         // The limits might have changed if the view suddenly became a group or vice versa
         updateLimits();
     }
@@ -607,6 +650,12 @@
         mPrivateLayout.updateExpandButtons(isExpandable());
     }
 
+    @Override
+    public void setClipToActualHeight(boolean clipToActualHeight) {
+        super.setClipToActualHeight(clipToActualHeight || isUserLocked());
+        getShowingLayout().setClipToActualHeight(clipToActualHeight || isUserLocked());
+    }
+
     /**
      * @return whether the user has changed the expansion state
      */
@@ -715,7 +764,7 @@
         if (expand && mExpandable) {
             setActualHeight(mMaxExpandHeight);
         } else {
-            setActualHeight(mRowMinHeight);
+            setActualHeight(getMinHeight());
         }
     }
 
@@ -724,21 +773,26 @@
         if (isUserLocked()) {
             return getActualHeight();
         }
-        boolean inExpansionState = isExpanded();
-        if (mSensitive && mHideSensitiveForIntrinsicHeight) {
-            return mRowMinHeight;
+        if (mGuts != null && mGuts.areGutsExposed()) {
+            return mGuts.getHeight();
+        } else if ((isChildInGroup() && !isGroupExpanded())) {
+            return mPrivateLayout.getMinHeight();
+        } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
+            return getMinHeight();
         } else if (mIsSummaryWithChildren && !mOnKeyguard) {
             return mChildrenContainer.getIntrinsicHeight();
         } else if (mIsHeadsUp) {
-            if (inExpansionState) {
-                return Math.max(mMaxExpandHeight, mHeadsUpHeight);
+            if (isPinned()) {
+                return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
+            } else if (isExpanded()) {
+                return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
             } else {
-                return Math.max(mRowMinHeight, mHeadsUpHeight);
+                return Math.max(getMinHeight(), mHeadsUpHeight);
             }
-        } else if (!inExpansionState || (isChildInGroup() && !isGroupExpanded())) {
-            return getMinHeight();
-        } else {
+        } else if (isExpanded()) {
             return getMaxExpandHeight();
+        } else {
+            return getMinHeight();
         }
     }
 
@@ -820,6 +874,12 @@
         }
     }
 
+    @Override
+    public void notifyHeightChanged(boolean needsAnimation) {
+        super.notifyHeightChanged(needsAnimation);
+        getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
+    }
+
     public void setSensitive(boolean sensitive) {
         mSensitive = sensitive;
     }
@@ -845,8 +905,7 @@
             mPublicLayout.setAlpha(1f);
             mPrivateLayout.setAlpha(1f);
             mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
-            mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? View.VISIBLE
-                    : View.INVISIBLE);
+            updateChildrenVisibility();
         } else {
             animateShowingPublic(delay, duration);
         }
@@ -857,27 +916,35 @@
     }
 
     private void animateShowingPublic(long delay, long duration) {
-        final View source = mShowingPublic ? mPrivateLayout : mPublicLayout;
-        View target = mShowingPublic ? mPublicLayout : mPrivateLayout;
-        source.setVisibility(View.VISIBLE);
-        target.setVisibility(View.VISIBLE);
-        target.setAlpha(0f);
-        source.animate().cancel();
-        target.animate().cancel();
-        source.animate()
-                .alpha(0f)
-                .setStartDelay(delay)
-                .setDuration(duration)
-                .withEndAction(new Runnable() {
-                    @Override
-                    public void run() {
-                        source.setVisibility(View.INVISIBLE);
-                    }
-                });
-        target.animate()
-                .alpha(1f)
-                .setStartDelay(delay)
-                .setDuration(duration);
+        View[] privateViews = mIsSummaryWithChildren ?
+                new View[] {mChildrenContainer, mNotificationHeader}
+                : new View[] {mPrivateLayout};
+        View[] publicViews = new View[] {mPublicLayout};
+        View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
+        View[] shownChildren = mShowingPublic ? publicViews : privateViews;
+        for (final View hiddenView : hiddenChildren) {
+            hiddenView.setVisibility(View.VISIBLE);
+            hiddenView.animate().cancel();
+            hiddenView.animate()
+                    .alpha(0f)
+                    .setStartDelay(delay)
+                    .setDuration(duration)
+                    .withEndAction(new Runnable() {
+                        @Override
+                        public void run() {
+                            hiddenView.setVisibility(View.INVISIBLE);
+                        }
+                    });
+        }
+        for (View showView : shownChildren) {
+            showView.setVisibility(View.VISIBLE);
+            showView.setAlpha(0f);
+            showView.animate().cancel();
+            showView.animate()
+                    .alpha(1f)
+                    .setStartDelay(delay)
+                    .setDuration(duration);
+        }
     }
 
     private void updateVetoButton() {
@@ -956,6 +1023,13 @@
 
     @Override
     public int getMinHeight() {
+        if (mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
+                return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
+        } else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
+            return mChildrenContainer.getMinHeight();
+        } else if (mIsHeadsUp) {
+            return mHeadsUpHeight;
+        }
         NotificationContentView showingLayout = getShowingLayout();
         return showingLayout.getMinHeight();
     }
@@ -963,17 +1037,12 @@
     @Override
     public int getMinExpandHeight() {
         if (mIsSummaryWithChildren && !mOnKeyguard) {
-            return mChildrenContainer.getMinHeight();
+            return mChildrenContainer.getMinExpandHeight();
         }
         return getMinHeight();
     }
 
     @Override
-    protected boolean shouldLimitViewHeight() {
-        return !mIsSummaryWithChildren;
-    }
-
-    @Override
     public void setClipTopAmount(int clipTopAmount) {
         super.setClipTopAmount(clipTopAmount);
         mPrivateLayout.setClipTopAmount(clipTopAmount);
@@ -998,7 +1067,7 @@
             addView(mNotificationHeader, indexOfChild(mChildrenContainer) + 1);
         } else {
             header.reapply(getContext(), mNotificationHeader);
-            mNotificationHeaderWrapper.notifyContentUpdated();
+            mNotificationHeaderWrapper.notifyContentUpdated(mEntry.notification);
         }
         updateHeaderExpandButton();
         updateChildrenHeaderAppearance();
@@ -1056,6 +1125,22 @@
         mLoggingKey = key;
     }
 
+    @Override
+    public boolean needsIncreasedPadding() {
+        return mIsSummaryWithChildren && isGroupExpanded();
+    }
+
+    @Override
+    protected boolean disallowSingleClick(MotionEvent event) {
+        float x = event.getX();
+        float y = event.getY();
+        NotificationHeaderView header = getNotificationHeader();
+        if (header != null) {
+            return header.isInTouchRect(x, y);
+        }
+        return super.disallowSingleClick(event);
+    }
+
     private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
         final boolean nowExpanded = isExpanded();
         if (wasExpanded != nowExpanded && mLogger != null) {
@@ -1064,6 +1149,6 @@
     }
 
     public interface OnExpandClickListener {
-        void onExpandClicked(View clickedView, boolean nowExpanded);
+        void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index a6fc4bb..44c6a5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -24,22 +24,17 @@
 import android.view.View;
 import android.view.ViewOutlineProvider;
 
-import com.android.systemui.R;
-
 /**
  * Like {@link ExpandableView}, but setting an outline for the height and clipping.
  */
 public abstract class ExpandableOutlineView extends ExpandableView {
 
     private final Rect mOutlineRect = new Rect();
-    protected final int mRoundedRectCornerRadius;
     private boolean mCustomOutline;
-    private float mOutlineAlpha = 1f;
+    private float mOutlineAlpha = -1f;
 
     public ExpandableOutlineView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mRoundedRectCornerRadius = getResources().getDimensionPixelSize(
-                R.dimen.notification_material_rounded_rect_radius);
         setOutlineProvider(new ViewOutlineProvider() {
             @Override
             public void getOutline(View view, Outline outline) {
@@ -49,7 +44,7 @@
                             getWidth(),
                             Math.max(getActualHeight(), mClipTopAmount));
                 } else {
-                    outline.setRoundRect(mOutlineRect, mRoundedRectCornerRadius);
+                    outline.setRect(mOutlineRect);
                 }
                 outline.setAlpha(mOutlineAlpha);
             }
@@ -69,8 +64,10 @@
     }
 
     protected void setOutlineAlpha(float alpha) {
-        mOutlineAlpha = alpha;
-        invalidateOutline();
+        if (alpha != mOutlineAlpha) {
+            mOutlineAlpha = alpha;
+            invalidateOutline();
+        }
     }
 
     protected void setOutlineRect(RectF rect) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 59cbd40..a0fb34a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -20,10 +20,10 @@
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
+
 import com.android.systemui.R;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
@@ -45,7 +45,7 @@
     private static Rect mClipRect = new Rect();
     private boolean mWillBeGone;
     private int mMinClipTopAmount = 0;
-    private boolean mMeasuredTooHigh;
+    private boolean mClipToActualHeight = true;
 
     public ExpandableView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -55,13 +55,10 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        boolean limitViewHeight = shouldLimitViewHeight();
         final int givenSize = MeasureSpec.getSize(heightMeasureSpec);
-        int ownMaxHeight = limitViewHeight ? mMaxViewHeight : Integer.MAX_VALUE;
+        int ownMaxHeight = Integer.MAX_VALUE;
         int heightMode = MeasureSpec.getMode(heightMeasureSpec);
-        boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY;
-        if (hasFixedHeight) {
-            // We have a height set in our layout, so we want to be at most as big as given
+        if (heightMode != MeasureSpec.UNSPECIFIED && givenSize != 0) {
             ownMaxHeight = Math.min(givenSize, ownMaxHeight);
         }
         int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST);
@@ -77,7 +74,7 @@
             if (layoutParams.height != ViewGroup.LayoutParams.MATCH_PARENT) {
                 if (layoutParams.height >= 0) {
                     // An actual height is set
-                    childHeightSpec = layoutParams.height > ownMaxHeight && limitViewHeight
+                    childHeightSpec = layoutParams.height > ownMaxHeight
                         ? MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.EXACTLY)
                         : MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
                 }
@@ -90,7 +87,8 @@
                 mMatchParentViews.add(child);
             }
         }
-        int ownHeight = hasFixedHeight ? ownMaxHeight : Math.min(ownMaxHeight, maxChildHeight);
+        int ownHeight = heightMode == MeasureSpec.EXACTLY
+                ? givenSize : Math.min(ownMaxHeight, maxChildHeight);
         newHeightSpec = MeasureSpec.makeMeasureSpec(ownHeight, MeasureSpec.EXACTLY);
         for (View child : mMatchParentViews) {
             child.measure(getChildMeasureSpec(
@@ -100,11 +98,6 @@
         mMatchParentViews.clear();
         int width = MeasureSpec.getSize(widthMeasureSpec);
         setMeasuredDimension(width, ownHeight);
-        mMeasuredTooHigh = heightMode != MeasureSpec.UNSPECIFIED && ownHeight > givenSize;
-    }
-
-    protected boolean shouldLimitViewHeight() {
-        return true;
     }
 
     @Override
@@ -133,26 +126,11 @@
     }
 
     @Override
-    public boolean dispatchGenericMotionEvent(MotionEvent ev) {
-        if (filterMotionEvent(ev)) {
-            return super.dispatchGenericMotionEvent(ev);
-        }
-        return false;
-    }
-
-    @Override
-    public boolean dispatchTouchEvent(MotionEvent ev) {
-        if (filterMotionEvent(ev)) {
-            return super.dispatchTouchEvent(ev);
-        }
-        return false;
-    }
-
-    protected boolean filterMotionEvent(MotionEvent event) {
-        return event.getActionMasked() != MotionEvent.ACTION_DOWN
-                && event.getActionMasked() != MotionEvent.ACTION_HOVER_ENTER
-                && event.getActionMasked() != MotionEvent.ACTION_HOVER_MOVE
-                || event.getY() > mClipTopAmount && event.getY() < mActualHeight;
+    public boolean pointInView(float localX, float localY, float slop) {
+        float top = mClipTopAmount;
+        float bottom = mActualHeight;
+        return localX >= -slop && localY >= top - slop && localX < ((mRight - mLeft) + slop) &&
+                localY < (bottom + slop);
     }
 
     /**
@@ -349,12 +327,21 @@
     }
 
     private void updateClipping() {
-        int top = mClipTopOptimization;
-        if (top >= getActualHeight()) {
-            top = getActualHeight() - 1;
+        if (mClipToActualHeight) {
+            int top = mClipTopOptimization;
+            if (top >= getActualHeight()) {
+                top = getActualHeight() - 1;
+            }
+            mClipRect.set(0, top, getWidth(), getActualHeight());
+            setClipBounds(mClipRect);
+        } else {
+            setClipBounds(null);
         }
-        mClipRect.set(0, top, getWidth(), getActualHeight());
-        setClipBounds(mClipRect);
+    }
+
+    public void setClipToActualHeight(boolean clipToActualHeight) {
+        mClipToActualHeight = clipToActualHeight;
+        updateClipping();
     }
 
     public int getClipTopOptimization() {
@@ -397,7 +384,19 @@
 
     @Override
     public boolean hasOverlappingRendering() {
-        return super.hasOverlappingRendering() && !mMeasuredTooHigh;
+        // Otherwise it will be clipped
+        return super.hasOverlappingRendering() && getActualHeight() <= getHeight();
+    }
+
+    public float getShadowAlpha() {
+        return 0.0f;
+    }
+
+    public void setShadowAlpha(float shadowAlpha) {
+    }
+
+    public boolean needsIncreasedPadding() {
+        return false;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
index 0fa088b..c4ffd7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
@@ -19,7 +19,6 @@
 import android.animation.Animator;
 import android.content.Context;
 import android.view.ViewPropertyAnimator;
-import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
 
@@ -41,8 +40,6 @@
     private static final float LINEAR_OUT_SLOW_IN_START_GRADIENT = 1.0f / LINEAR_OUT_SLOW_IN_X2;
 
     private Interpolator mLinearOutSlowIn;
-    private Interpolator mFastOutSlowIn;
-    private Interpolator mFastOutLinearIn;
 
     private float mMinVelocityPxPerSecond;
     private float mMaxLengthSeconds;
@@ -53,10 +50,6 @@
     public FlingAnimationUtils(Context ctx, float maxLengthSeconds) {
         mMaxLengthSeconds = maxLengthSeconds;
         mLinearOutSlowIn = new PathInterpolator(0, 0, LINEAR_OUT_SLOW_IN_X2, 1);
-        mFastOutSlowIn
-                = AnimationUtils.loadInterpolator(ctx, android.R.interpolator.fast_out_slow_in);
-        mFastOutLinearIn
-                = AnimationUtils.loadInterpolator(ctx, android.R.interpolator.fast_out_linear_in);
         mMinVelocityPxPerSecond
                 = MIN_VELOCITY_DP_PER_SECOND * ctx.getResources().getDisplayMetrics().density;
         mHighVelocityPxPerSecond
@@ -150,7 +143,7 @@
 
             // Just use a normal interpolator which doesn't take the velocity into account.
             durationSeconds = maxLengthSeconds;
-            mAnimatorProperties.interpolator = mFastOutSlowIn;
+            mAnimatorProperties.interpolator = Interpolators.FAST_OUT_SLOW_IN;
         }
         mAnimatorProperties.duration = (long) (durationSeconds * 1000);
         return mAnimatorProperties;
@@ -223,7 +216,7 @@
 
             // Just use a normal interpolator which doesn't take the velocity into account.
             durationSeconds = maxLengthSeconds;
-            mAnimatorProperties.interpolator = mFastOutLinearIn;
+            mAnimatorProperties.interpolator = Interpolators.FAST_OUT_LINEAR_IN;
         }
         mAnimatorProperties.duration = (long) (durationSeconds * 1000);
         return mAnimatorProperties;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/Interpolators.java b/packages/SystemUI/src/com/android/systemui/statusbar/Interpolators.java
new file mode 100644
index 0000000..5979468
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/Interpolators.java
@@ -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 com.android.systemui.statusbar;
+
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+import android.view.animation.PathInterpolator;
+
+/**
+ * Utility class to receive interpolators from
+ */
+public class Interpolators {
+    public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+    public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
+    public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
+    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_DECELERATE = new AccelerateDecelerateInterpolator();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
new file mode 100644
index 0000000..25e9a7a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.TypedValue;
+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.ViewGroup.LayoutParams;
+import android.view.Window;
+import android.view.WindowManager.KeyboardShortcutsReceiver;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static android.content.Context.LAYOUT_INFLATER_SERVICE;
+import static android.graphics.Color.WHITE;
+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 final Handler mHandler = new Handler(Looper.getMainLooper());
+    private final Context mContext;
+    private final OnClickListener dialogCloseListener =  new DialogInterface.OnClickListener() {
+        public void onClick(DialogInterface dialog, int id) {
+            dismissKeyboardShortcutsDialog();
+        }
+    };
+
+    private Dialog mKeyboardShortcutsDialog;
+
+    public KeyboardShortcuts(Context context) {
+        this.mContext = context;
+    }
+
+    public void toggleKeyboardShortcuts() {
+        if (mKeyboardShortcutsDialog == null) {
+            Recents.getSystemServices().requestKeyboardShortcuts(mContext,
+                new KeyboardShortcutsReceiver() {
+                    @Override
+                    public void onKeyboardShortcutsReceived(
+                            final List<KeyboardShortcutGroup> result) {
+                        KeyboardShortcutGroup systemGroup = new KeyboardShortcutGroup(
+                            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));
+                        systemGroup.addItem(new KeyboardShortcutInfo(
+                            mContext.getString(R.string.keyboard_shortcut_group_system_back),
+                            SYSTEM_BACK_BASE_CHARACTER, 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));
+                        result.add(systemGroup);
+                        showKeyboardShortcutsDialog(result);
+                    }
+                });
+        } else {
+            dismissKeyboardShortcutsDialog();
+        }
+    }
+
+    public void dismissKeyboardShortcutsDialog() {
+        if (mKeyboardShortcutsDialog != null) {
+            mKeyboardShortcutsDialog.dismiss();
+            mKeyboardShortcutsDialog = null;
+        }
+    }
+
+    private void showKeyboardShortcutsDialog(
+            final List<KeyboardShortcutGroup> keyboardShortcutGroups) {
+        // Need to post on the main thread.
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                // TODO: break all this code out into a handleShowKeyboard...
+                // Might add more things posted; should consider adding a custom handler so
+                // you can send the keyboardShortcutsGroups as part of the message.
+                AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
+                LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
+                        LAYOUT_INFLATER_SERVICE);
+                final View keyboardShortcutsView = inflater.inflate(
+                        R.layout.keyboard_shortcuts_view, null);
+                DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
+                ScrollView scrollView = (ScrollView) keyboardShortcutsView.findViewById(
+                        R.id.keyboard_shortcuts_scroll_view);
+                // TODO: find a better way to set the height.
+                scrollView.setLayoutParams(new LinearLayout.LayoutParams(
+                        LayoutParams.WRAP_CONTENT,
+                        (int) (dm.heightPixels * dm.density)));
+
+                populateKeyboardShortcuts((LinearLayout) keyboardShortcutsView.findViewById(
+                        R.id.keyboard_shortcuts_container), keyboardShortcutGroups);
+                dialogBuilder.setView(keyboardShortcutsView);
+                dialogBuilder.setPositiveButton(R.string.quick_settings_done, dialogCloseListener);
+                mKeyboardShortcutsDialog = dialogBuilder.create();
+                mKeyboardShortcutsDialog.setCanceledOnTouchOutside(true);
+
+                // Setup window.
+                Window keyboardShortcutsWindow = mKeyboardShortcutsDialog.getWindow();
+                keyboardShortcutsWindow.setType(TYPE_SYSTEM_DIALOG);
+                keyboardShortcutsWindow.setBackgroundDrawable(
+                        mContext.getDrawable(R.color.ksh_dialog_background_color));
+                keyboardShortcutsWindow.setGravity(TOP);
+                mKeyboardShortcutsDialog.show();
+            }
+        });
+    }
+
+    private void populateKeyboardShortcuts(LinearLayout keyboardShortcutsLayout,
+            List<KeyboardShortcutGroup> keyboardShortcutGroups) {
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+        final int keyboardShortcutGroupsSize = keyboardShortcutGroups.size();
+        for (int i = 0; i < keyboardShortcutGroupsSize; i++) {
+            KeyboardShortcutGroup group = keyboardShortcutGroups.get(i);
+            TextView categoryTitle = (TextView) inflater.inflate(
+                    R.layout.keyboard_shortcuts_category_title, keyboardShortcutsLayout, false);
+            categoryTitle.setText(group.getLabel());
+            categoryTitle.setTextColor(group.isSystemGroup()
+                    ? mContext.getColor(R.color.ksh_system_group_color)
+                    : mContext.getColor(R.color.ksh_application_group_color));
+            keyboardShortcutsLayout.addView(categoryTitle);
+
+            LinearLayout shortcutWrapper = (LinearLayout) inflater.inflate(
+                    R.layout.keyboard_shortcuts_wrapper, null);
+            final int itemsSize = group.getItems().size();
+            for (int j = 0; j < itemsSize; j++) {
+                KeyboardShortcutInfo info = group.getItems().get(j);
+                View shortcutView = inflater.inflate(R.layout.keyboard_shortcut_app_item, null);
+                TextView textView = (TextView) shortcutView
+                        .findViewById(R.id.keyboard_shortcuts_keyword);
+                textView.setText(info.getLabel());
+
+                List<String> shortcutKeys = getHumanReadableShortcutKeys(info);
+                final int shortcutKeysSize = shortcutKeys.size();
+                for (int k = 0; k < shortcutKeysSize; k++) {
+                    String shortcutKey = shortcutKeys.get(k);
+                    TextView shortcutKeyView = (TextView) inflater.inflate(
+                            R.layout.keyboard_shortcuts_key_view, null);
+                    shortcutKeyView.setText(shortcutKey);
+                    LinearLayout shortcutItemsContainer = (LinearLayout) shortcutView
+                            .findViewById(R.id.keyboard_shortcuts_item_container);
+                    shortcutItemsContainer.addView(shortcutKeyView);
+                }
+                shortcutWrapper.addView(shortcutView);
+            }
+
+            // TODO: merge container and wrapper into one xml file - wrapper is always a child of
+            // container.
+            LinearLayout shortcutsContainer = (LinearLayout) inflater.inflate(
+                    R.layout.keyboard_shortcuts_container, null);
+            shortcutsContainer.addView(shortcutWrapper);
+            keyboardShortcutsLayout.addView(shortcutsContainer);
+        }
+    }
+
+    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());
+        return shortcutKeys;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 8058933..841b9d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -33,13 +33,11 @@
 import android.view.RenderNodeAnimator;
 import android.view.View;
 import android.view.ViewAnimationUtils;
-import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.ImageView;
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.KeyguardAffordanceHelper;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
 
 /**
  * An ImageView which does not have overlapping renderings commands and therefore does not need a
@@ -55,8 +53,6 @@
 
     private final int mMinBackgroundRadius;
     private final Paint mCirclePaint;
-    private final Interpolator mAppearInterpolator;
-    private final Interpolator mDisappearInterpolator;
     private final int mInverseColor;
     private final int mNormalColor;
     private final ArgbEvaluator mColorInterpolator;
@@ -136,10 +132,6 @@
         mInverseColor = 0xff000000;
         mMinBackgroundRadius = mContext.getResources().getDimensionPixelSize(
                 R.dimen.keyguard_affordance_min_background_radius);
-        mAppearInterpolator = AnimationUtils.loadInterpolator(mContext,
-                android.R.interpolator.linear_out_slow_in);
-        mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext,
-                android.R.interpolator.fast_out_linear_in);
         mColorInterpolator = new ArgbEvaluator();
         mFlingAnimationUtils = new FlingAnimationUtils(mContext, 0.3f);
     }
@@ -261,7 +253,7 @@
             RenderNodeAnimator animator = new RenderNodeAnimator(mHwCirclePaint,
                     RenderNodeAnimator.PAINT_ALPHA, 255);
             animator.setTarget(this);
-            animator.setInterpolator(PhoneStatusBar.ALPHA_IN);
+            animator.setInterpolator(Interpolators.ALPHA_IN);
             animator.setDuration(250);
             animator.start();
         }
@@ -282,7 +274,7 @@
         RenderNodeAnimator animator = new RenderNodeAnimator(mHwCirclePaint,
                 RenderNodeAnimator.PAINT_ALPHA, 0);
         animator.setDuration(duration);
-        animator.setInterpolator(PhoneStatusBar.ALPHA_OUT);
+        animator.setInterpolator(Interpolators.ALPHA_OUT);
         animator.setTarget(this);
         animator.start();
     }
@@ -352,8 +344,8 @@
             cancelAnimator(mPreviewClipper);
             ValueAnimator animator = getAnimatorToRadius(circleRadius);
             Interpolator interpolator = circleRadius == 0.0f
-                    ? mDisappearInterpolator
-                    : mAppearInterpolator;
+                    ? Interpolators.FAST_OUT_LINEAR_IN
+                    : Interpolators.LINEAR_OUT_SLOW_IN;
             animator.setInterpolator(interpolator);
             long duration = 250;
             if (!slowAnimation) {
@@ -438,8 +430,8 @@
             animator.addListener(mScaleEndListener);
             if (interpolator == null) {
                 interpolator = imageScale == 0.0f
-                        ? mDisappearInterpolator
-                        : mAppearInterpolator;
+                        ? Interpolators.FAST_OUT_LINEAR_IN
+                        : Interpolators.LINEAR_OUT_SLOW_IN;
             }
             animator.setInterpolator(interpolator);
             if (duration == -1) {
@@ -501,8 +493,8 @@
             animator.addListener(mAlphaEndListener);
             if (interpolator == null) {
                 interpolator = alpha == 0.0f
-                        ? mDisappearInterpolator
-                        : mAppearInterpolator;
+                        ? Interpolators.FAST_OUT_LINEAR_IN
+                        : Interpolators.LINEAR_OUT_SLOW_IN;
             }
             animator.setInterpolator(interpolator);
             if (duration == -1) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 6d90329..3da8098 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -20,10 +20,8 @@
 import android.app.RemoteInput;
 import android.content.Context;
 import android.graphics.Outline;
-import android.graphics.Paint;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
+import android.os.Build;
 import android.service.notification.StatusBarNotification;
 import android.util.AttributeSet;
 import android.view.NotificationHeaderView;
@@ -31,13 +29,13 @@
 import android.view.ViewGroup;
 import android.view.ViewOutlineProvider;
 import android.view.ViewTreeObserver;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
 import android.widget.FrameLayout;
 
 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.NotificationCustomViewWrapper;
+import com.android.systemui.statusbar.notification.NotificationViewWrapper;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.policy.RemoteInputView;
 
@@ -48,16 +46,22 @@
  */
 public class NotificationContentView extends FrameLayout {
 
-    private static final long ANIMATION_DURATION_LENGTH = 170;
     private static final int VISIBLE_TYPE_CONTRACTED = 0;
     private static final int VISIBLE_TYPE_EXPANDED = 1;
     private static final int VISIBLE_TYPE_HEADSUP = 2;
     private static final int VISIBLE_TYPE_SINGLELINE = 3;
 
     private final Rect mClipBounds = new Rect();
-    private final int mRoundRectRadius;
-    private final Interpolator mLinearInterpolator = new LinearInterpolator();
-    private final boolean mRoundRectClippingEnabled;
+    private final int mMinContractedHeight;
+    private final OnLayoutChangeListener mLayoutUpdater = new OnLayoutChangeListener() {
+        @Override
+        public void onLayoutChange(View v, int left, int top, int right, int bottom,
+                int oldLeft,
+                int oldTop, int oldRight, int oldBottom) {
+            selectLayout(false /* animate */, false /* force */);
+        }
+    };
+
 
     private View mContractedChild;
     private View mExpandedChild;
@@ -73,13 +77,13 @@
     private int mUnrestrictedContentHeight;
     private int mVisibleType = VISIBLE_TYPE_CONTRACTED;
     private boolean mDark;
-    private final Paint mFadePaint = new Paint();
     private boolean mAnimate;
     private boolean mIsHeadsUp;
     private boolean mShowingLegacyBackground;
     private boolean mIsChildInGroup;
     private int mSmallHeight;
     private int mHeadsUpHeight;
+    private int mNotificationMaxHeight;
     private StatusBarNotification mStatusBarNotification;
     private NotificationGroupManager mGroupManager;
     private RemoteInputController mRemoteInputController;
@@ -94,30 +98,24 @@
         }
     };
 
-    private final ViewOutlineProvider mOutlineProvider = new ViewOutlineProvider() {
-        @Override
-        public void getOutline(View view, Outline outline) {
-            outline.setRoundRect(0, 0, view.getWidth(), mUnrestrictedContentHeight,
-                    mRoundRectRadius);
-        }
-    };
     private OnClickListener mExpandClickListener;
+    private boolean mBeforeN;
+    private boolean mExpandable;
+    private boolean mClipToActualHeight = true;
+    private ExpandableNotificationRow mContainingNotification;
 
     public NotificationContentView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mHybridViewManager = new HybridNotificationViewManager(getContext(), this);
-        mFadePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
-        mRoundRectRadius = getResources().getDimensionPixelSize(
-                R.dimen.notification_material_rounded_rect_radius);
-        mRoundRectClippingEnabled = getResources().getBoolean(
-                R.bool.config_notifications_round_rect_clipping);
+        mMinContractedHeight = getResources().getDimensionPixelSize(
+                R.dimen.min_notification_layout_height);
         reset(true);
-        setOutlineProvider(mOutlineProvider);
     }
 
-    public void setHeights(int smallHeight, int headsUpMaxHeight) {
+    public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight) {
         mSmallHeight = smallHeight;
         mHeadsUpHeight = headsUpMaxHeight;
+        mNotificationMaxHeight = maxHeight;
     }
 
     @Override
@@ -131,13 +129,23 @@
         }
         int maxChildHeight = 0;
         if (mContractedChild != null) {
-            int size = Math.min(maxSize, mSmallHeight);
-            mContractedChild.measure(widthMeasureSpec,
-                    MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY));
-            maxChildHeight = Math.max(maxChildHeight, mContractedChild.getMeasuredHeight());
+            int heightSpec;
+            if (shouldContractedBeFixedSize()) {
+                int size = Math.min(maxSize, mSmallHeight);
+                heightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
+            } else {
+                heightSpec = MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.AT_MOST);
+            }
+            mContractedChild.measure(widthMeasureSpec, heightSpec);
+            int measuredHeight = mContractedChild.getMeasuredHeight();
+            if (measuredHeight < mMinContractedHeight) {
+                heightSpec = MeasureSpec.makeMeasureSpec(mMinContractedHeight, MeasureSpec.EXACTLY);
+                mContractedChild.measure(widthMeasureSpec, heightSpec);
+            }
+            maxChildHeight = Math.max(maxChildHeight, measuredHeight);
         }
         if (mExpandedChild != null) {
-            int size = maxSize;
+            int size = Math.min(maxSize, mNotificationMaxHeight);
             ViewGroup.LayoutParams layoutParams = mExpandedChild.getLayoutParams();
             if (layoutParams.height >= 0) {
                 // An actual height is set
@@ -170,6 +178,10 @@
         setMeasuredDimension(width, ownHeight);
     }
 
+    private boolean shouldContractedBeFixedSize() {
+        return mBeforeN && mContractedWrapper instanceof NotificationCustomViewWrapper;
+    }
+
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
@@ -218,38 +230,41 @@
     public void setContractedChild(View child) {
         if (mContractedChild != null) {
             mContractedChild.animate().cancel();
+            mContractedChild.removeOnLayoutChangeListener(mLayoutUpdater);
             removeView(mContractedChild);
         }
         addView(child);
         mContractedChild = child;
+        mContractedChild.addOnLayoutChangeListener(mLayoutUpdater);
         mContractedWrapper = NotificationViewWrapper.wrap(getContext(), child);
         selectLayout(false /* animate */, true /* force */);
         mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */);
-        updateRoundRectClipping();
     }
 
     public void setExpandedChild(View child) {
         if (mExpandedChild != null) {
             mExpandedChild.animate().cancel();
+            mExpandedChild.removeOnLayoutChangeListener(mLayoutUpdater);
             removeView(mExpandedChild);
         }
         addView(child);
         mExpandedChild = child;
+        mExpandedChild.addOnLayoutChangeListener(mLayoutUpdater);
         mExpandedWrapper = NotificationViewWrapper.wrap(getContext(), child);
         selectLayout(false /* animate */, true /* force */);
-        updateRoundRectClipping();
     }
 
     public void setHeadsUpChild(View child) {
         if (mHeadsUpChild != null) {
             mHeadsUpChild.animate().cancel();
+            mHeadsUpChild.removeOnLayoutChangeListener(mLayoutUpdater);
             removeView(mHeadsUpChild);
         }
         addView(child);
         mHeadsUpChild = child;
+        mHeadsUpChild.addOnLayoutChangeListener(mLayoutUpdater);
         mHeadsUpWrapper = NotificationViewWrapper.wrap(getContext(), child);
         selectLayout(false /* animate */, true /* force */);
-        updateRoundRectClipping();
     }
 
     @Override
@@ -292,14 +307,14 @@
         } else if (mIsHeadsUp && mHeadsUpChild != null) {
             return mHeadsUpChild.getHeight();
         }
-        return mSmallHeight;
+        return mContractedChild.getHeight();
     }
 
     public int getMinHeight() {
         if (mIsChildInGroup && !isGroupExpanded()) {
             return mSingleLineView.getHeight();
         } else {
-            return mSmallHeight;
+            return mContractedChild.getHeight();
         }
     }
 
@@ -312,30 +327,18 @@
         updateClipping();
     }
 
-    private void updateRoundRectClipping() {
-        boolean enabled = needsRoundRectClipping();
-        setClipToOutline(enabled);
-    }
-
-    private boolean needsRoundRectClipping() {
-        if (!mRoundRectClippingEnabled) {
-            return false;
-        }
-        boolean needsForContracted = mContractedChild != null
-                && mContractedChild.getVisibility() == View.VISIBLE
-                && mContractedWrapper.needsRoundRectClipping();
-        boolean needsForExpanded = mExpandedChild != null
-                && mExpandedChild.getVisibility() == View.VISIBLE
-                && mExpandedWrapper.needsRoundRectClipping();
-        boolean needsForHeadsUp = mExpandedChild != null
-                && mExpandedChild.getVisibility() == View.VISIBLE
-                && mExpandedWrapper.needsRoundRectClipping();
-        return needsForContracted || needsForExpanded || needsForHeadsUp;
-    }
-
     private void updateClipping() {
-        mClipBounds.set(0, mClipTopAmount, getWidth(), mContentHeight);
-        setClipBounds(mClipBounds);
+        if (mClipToActualHeight) {
+            mClipBounds.set(0, mClipTopAmount, getWidth(), mContentHeight);
+            setClipBounds(mClipBounds);
+        } else {
+            setClipBounds(null);
+        }
+    }
+
+    public void setClipToActualHeight(boolean clipToActualHeight) {
+        mClipToActualHeight = clipToActualHeight;
+        updateClipping();
     }
 
     private void selectLayout(boolean animate, boolean force) {
@@ -348,7 +351,7 @@
                     || (visibleType == VISIBLE_TYPE_HEADSUP && mHeadsUpChild != null)
                     || (visibleType == VISIBLE_TYPE_SINGLELINE && mSingleLineView != null)
                     || visibleType == VISIBLE_TYPE_CONTRACTED)) {
-                runSwitchAnimation(visibleType);
+                animateToVisibleType(visibleType);
             } else {
                 updateViewVisibilities(visibleType);
             }
@@ -358,55 +361,49 @@
 
     private void updateViewVisibilities(int visibleType) {
         boolean contractedVisible = visibleType == VISIBLE_TYPE_CONTRACTED;
-        mContractedChild.setVisibility(contractedVisible ? View.VISIBLE : View.INVISIBLE);
-        mContractedChild.setAlpha(contractedVisible ? 1f : 0f);
-        mContractedChild.setLayerType(LAYER_TYPE_NONE, null);
+        mContractedWrapper.setVisible(contractedVisible);
         if (mExpandedChild != null) {
             boolean expandedVisible = visibleType == VISIBLE_TYPE_EXPANDED;
-            mExpandedChild.setVisibility(expandedVisible ? View.VISIBLE : View.INVISIBLE);
-            mExpandedChild.setAlpha(expandedVisible ? 1f : 0f);
-            mExpandedChild.setLayerType(LAYER_TYPE_NONE, null);
+            mExpandedWrapper.setVisible(expandedVisible);
         }
         if (mHeadsUpChild != null) {
             boolean headsUpVisible = visibleType == VISIBLE_TYPE_HEADSUP;
-            mHeadsUpChild.setVisibility(headsUpVisible ? View.VISIBLE : View.INVISIBLE);
-            mHeadsUpChild.setAlpha(headsUpVisible ? 1f : 0f);
-            mHeadsUpChild.setLayerType(LAYER_TYPE_NONE, null);
+            mHeadsUpWrapper.setVisible(headsUpVisible);
         }
         if (mSingleLineView != null) {
             boolean singleLineVisible = visibleType == VISIBLE_TYPE_SINGLELINE;
-            mSingleLineView.setVisibility(singleLineVisible ? View.VISIBLE : View.INVISIBLE);
-            mSingleLineView.setAlpha(singleLineVisible ? 1f : 0f);
-            mSingleLineView.setLayerType(LAYER_TYPE_NONE, null);
+            mSingleLineView.setVisible(singleLineVisible);
         }
-        setLayerType(LAYER_TYPE_NONE, null);
-        updateRoundRectClipping();
     }
 
-    private void runSwitchAnimation(int visibleType) {
-        View shownView = getViewForVisibleType(visibleType);
-        View hiddenView = getViewForVisibleType(mVisibleType);
-        shownView.setVisibility(View.VISIBLE);
-        hiddenView.setVisibility(View.VISIBLE);
-        shownView.setLayerType(LAYER_TYPE_HARDWARE, mFadePaint);
-        hiddenView.setLayerType(LAYER_TYPE_HARDWARE, mFadePaint);
-        setLayerType(LAYER_TYPE_HARDWARE, null);
-        hiddenView.animate()
-                .alpha(0f)
-                .setDuration(ANIMATION_DURATION_LENGTH)
-                .setInterpolator(mLinearInterpolator)
-                .withEndAction(null); // In case we have multiple changes in one frame.
-        shownView.animate()
-                .alpha(1f)
-                .setDuration(ANIMATION_DURATION_LENGTH)
-                .setInterpolator(mLinearInterpolator)
-                .withEndAction(new Runnable() {
-                    @Override
-                    public void run() {
-                        updateViewVisibilities(mVisibleType);
-                    }
-                });
-        updateRoundRectClipping();
+    private void animateToVisibleType(int visibleType) {
+        final TransformableView shownView = getTransformableViewForVisibleType(visibleType);
+        final TransformableView hiddenView = getTransformableViewForVisibleType(mVisibleType);
+        shownView.transformFrom(hiddenView);
+        getViewForVisibleType(visibleType).setVisibility(View.VISIBLE);
+        hiddenView.transformTo(shownView, new Runnable() {
+            @Override
+            public void run() {
+                hiddenView.setVisible(false);
+            }
+        });
+    }
+
+    /**
+     * @param visibleType one of the static enum types in this view
+     * @return the corresponding transformable view according to the given visible type
+     */
+    private TransformableView getTransformableViewForVisibleType(int visibleType) {
+        switch (visibleType) {
+            case VISIBLE_TYPE_EXPANDED:
+                return mExpandedWrapper;
+            case VISIBLE_TYPE_HEADSUP:
+                return mHeadsUpWrapper;
+            case VISIBLE_TYPE_SINGLELINE:
+                return mSingleLineView;
+            default:
+                return mContractedWrapper;
+        }
     }
 
     /**
@@ -432,20 +429,22 @@
     private int calculateVisibleType() {
         boolean noExpandedChild = mExpandedChild == null;
 
-        if (!noExpandedChild && mContentHeight == mExpandedChild.getHeight()) {
+        int viewHeight = Math.min(mContentHeight, mContainingNotification.getIntrinsicHeight());
+        if (!noExpandedChild && viewHeight == mExpandedChild.getHeight()) {
             return VISIBLE_TYPE_EXPANDED;
         }
+        if (mIsChildInGroup && !isGroupExpanded()) {
+            return VISIBLE_TYPE_SINGLELINE;
+        }
 
         if (mIsHeadsUp && mHeadsUpChild != null) {
-            if (mContentHeight <= mHeadsUpChild.getHeight() || noExpandedChild) {
+            if (viewHeight <= mHeadsUpChild.getHeight() || noExpandedChild) {
                 return VISIBLE_TYPE_HEADSUP;
             } else {
                 return VISIBLE_TYPE_EXPANDED;
             }
         } else {
-            if (mIsChildInGroup && !isGroupExpanded()) {
-                return VISIBLE_TYPE_SINGLELINE;
-            } else if (mContentHeight <= mSmallHeight || noExpandedChild) {
+            if (viewHeight <= mContractedChild.getHeight() || noExpandedChild) {
                 return VISIBLE_TYPE_CONTRACTED;
             } else {
                 return VISIBLE_TYPE_EXPANDED;
@@ -460,8 +459,17 @@
     public void setDark(boolean dark, boolean fade, long delay) {
         if (mDark == dark || mContractedChild == null) return;
         mDark = dark;
-        mContractedWrapper.setDark(dark && !mShowingLegacyBackground, fade, delay);
-        if (mSingleLineView != null) {
+        dark = dark && !mShowingLegacyBackground;
+        if (mVisibleType == VISIBLE_TYPE_CONTRACTED || !dark) {
+            mContractedWrapper.setDark(dark, fade, delay);
+        }
+        if (mVisibleType == VISIBLE_TYPE_EXPANDED || (mExpandedChild != null && !dark)) {
+            mExpandedWrapper.setDark(dark, fade, delay);
+        }
+        if (mVisibleType == VISIBLE_TYPE_HEADSUP || (mHeadsUpChild != null && !dark)) {
+            mHeadsUpWrapper.setDark(dark, fade, delay);
+        }
+        if (mSingleLineView != null && (mVisibleType == VISIBLE_TYPE_SINGLELINE || !dark)) {
             mSingleLineView.setDark(dark, fade, delay);
         }
     }
@@ -469,6 +477,7 @@
     public void setHeadsUp(boolean headsUp) {
         mIsHeadsUp = headsUp;
         selectLayout(false /* animate */, true /* force */);
+        updateExpandButtons(mExpandable);
     }
 
     @Override
@@ -490,20 +499,20 @@
 
     public void onNotificationUpdated(NotificationData.Entry entry) {
         mStatusBarNotification = entry.notification;
+        mBeforeN = entry.targetSdk < Build.VERSION_CODES.N;
         updateSingleLineView();
         applyRemoteInput(entry);
         selectLayout(false /* animate */, true /* force */);
         if (mContractedChild != null) {
-            mContractedWrapper.notifyContentUpdated();
+            mContractedWrapper.notifyContentUpdated(entry.notification);
             mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */);
         }
         if (mExpandedChild != null) {
-            mExpandedWrapper.notifyContentUpdated();
+            mExpandedWrapper.notifyContentUpdated(entry.notification);
         }
         if (mHeadsUpChild != null) {
-            mHeadsUpWrapper.notifyContentUpdated();
+            mHeadsUpWrapper.notifyContentUpdated(entry.notification);
         }
-        updateRoundRectClipping();
     }
 
     private void updateSingleLineView() {
@@ -587,6 +596,13 @@
     }
 
     public void updateExpandButtons(boolean expandable) {
+        mExpandable = expandable;
+        // if the expanded child has the same height as the collapsed one we hide it.
+        if (mExpandedChild != null && mExpandedChild.getHeight() != 0 &&
+                ((mIsHeadsUp && mExpandedChild.getHeight() == mHeadsUpChild.getHeight()) ||
+                (!mIsHeadsUp && mExpandedChild.getHeight() == mContractedChild.getHeight()))) {
+            expandable = false;
+        }
         if (mExpandedChild != null) {
             mExpandedWrapper.updateExpandability(expandable, mExpandClickListener);
         }
@@ -611,4 +627,12 @@
         }
         return header;
     }
+
+    public void setContainingNotification(ExpandableNotificationRow containingNotification) {
+        mContainingNotification = containingNotification;
+    }
+
+    public void requestSelectLayout(boolean needsAnimation) {
+        selectLayout(needsAnimation, false);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationCustomViewWrapper.java
deleted file mode 100644
index 6fd341b..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationCustomViewWrapper.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar;
-
-import android.view.View;
-
-import com.android.systemui.ViewInvertHelper;
-import com.android.systemui.statusbar.phone.NotificationPanelView;
-
-/**
- * Wraps a notification containing a custom view.
- */
-public class NotificationCustomViewWrapper extends NotificationViewWrapper {
-
-    private final ViewInvertHelper mInvertHelper;
-
-    protected NotificationCustomViewWrapper(View view) {
-        super(view);
-        mInvertHelper = new ViewInvertHelper(view, NotificationPanelView.DOZE_ANIMATION_DURATION);
-    }
-
-    @Override
-    public void setDark(boolean dark, boolean fade, long delay) {
-        if (fade) {
-            mInvertHelper.fade(dark, delay);
-        } else {
-            mInvertHelper.update(dark);
-        }
-    }
-
-    @Override
-    public boolean needsRoundRectClipping() {
-        return true;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index c458d21..3cc1ab9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -115,17 +115,14 @@
                         updatedNotificationBuilder.makeBigContentView();
                 final RemoteViews newHeadsUpContentView =
                         updatedNotificationBuilder.makeHeadsUpContentView();
-                final Notification updatedPublicNotification = updatedNotification.publicVersion;
-                final RemoteViews newPubContentView = (updatedPublicNotification != null)
-                        ? Notification.Builder.recoverBuilder(
-                                ctx, updatedPublicNotification).makeContentView()
-                        : null;
+                final RemoteViews newPublicNotification
+                        = updatedNotificationBuilder.makePublicContentView();
 
                 applyInPlace = compareRemoteViews(cachedContentView, newContentView)
                         && compareRemoteViews(cachedBigContentView, newBigContentView)
                         && compareRemoteViews(cachedHeadsUpContentView, newHeadsUpContentView)
-                        && compareRemoteViews(cachedPublicContentView, newPubContentView);
-                cachedPublicContentView = newPubContentView;
+                        && compareRemoteViews(cachedPublicContentView, newPublicNotification);
+                cachedPublicContentView = newPublicNotification;
                 cachedHeadsUpContentView = newHeadsUpContentView;
                 cachedBigContentView = newBigContentView;
                 cachedContentView = newContentView;
@@ -136,14 +133,8 @@
                 cachedContentView = builder.makeContentView();
                 cachedBigContentView = builder.makeBigContentView();
                 cachedHeadsUpContentView = builder.makeHeadsUpContentView();
+                cachedPublicContentView = builder.makePublicContentView();
 
-                final Notification publicNotification =
-                        notification.getNotification().publicVersion;
-                if (publicNotification != null) {
-                    final Notification.Builder publicBuilder
-                            = Notification.Builder.recoverBuilder(ctx, publicNotification);
-                    cachedPublicContentView = publicBuilder.makeContentView();
-                }
                 applyInPlace = false;
             }
             return applyInPlace;
@@ -301,6 +292,15 @@
         return false;
     }
 
+    public boolean shouldSuppressScreenOn(String key) {
+        if (mRankingMap != null) {
+            mRankingMap.getRanking(key, mTmpRanking);
+            return (mTmpRanking.getSuppressedVisualEffects()
+                    & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON) != 0;
+        }
+        return false;
+    }
+
     public int getImportance(String key) {
         if (mRankingMap != null) {
             mRankingMap.getRanking(key, mTmpRanking);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index 0081496..5abd1d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -16,13 +16,26 @@
 
 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;
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
 import android.util.AttributeSet;
-import android.widget.FrameLayout;
+import android.view.View;
+import android.widget.ImageView;
 import android.widget.LinearLayout;
+import android.widget.RadioButton;
+import android.widget.SeekBar;
+import android.widget.TextView;
 
+import com.android.settingslib.Utils;
 import com.android.systemui.R;
 
 /**
@@ -33,6 +46,11 @@
     private Drawable mBackground;
     private int mClipTopAmount;
     private int mActualHeight;
+    private boolean mExposed;
+    private RadioButton mApplyToTopic;
+    private SeekBar mSeekBar;
+    private Notification.Topic mTopic;
+    private INotificationManager mINotificationManager;
 
     public NotificationGuts(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -83,6 +101,118 @@
         }
     }
 
+    void bindImportance(final StatusBarNotification sbn, final ExpandableNotificationRow row,
+            final int importance) {
+        mINotificationManager = INotificationManager.Stub.asInterface(
+                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+        mTopic = sbn.getNotification().getTopic() == null
+                ? new Notification.Topic(Notification.TOPIC_DEFAULT, mContext.getString(
+                com.android.internal.R.string.default_notification_topic_label))
+                : sbn.getNotification().getTopic();
+        boolean doesAppUseTopics = false;
+        try {
+            doesAppUseTopics =
+                    mINotificationManager.doesAppUseTopics(sbn.getPackageName(), sbn.getUid());
+        } catch (RemoteException e) {}
+        final boolean appUsesTopics = doesAppUseTopics;
+
+        mApplyToTopic = (RadioButton) row.findViewById(R.id.apply_to_topic);
+        if (appUsesTopics) {
+            mApplyToTopic.setChecked(true);
+        }
+        final View applyToApp = row.findViewById(R.id.apply_to_app);
+        final TextView topicSummary = ((TextView) row.findViewById(R.id.summary));
+        final TextView topicTitle = ((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.
+        }
+        if (systemApp) {
+            ((ImageView) row.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_NONE;
+        mSeekBar.setMax(NotificationListenerService.Ranking.IMPORTANCE_MAX);
+        mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+            @Override
+            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                if (progress < minProgress) {
+                    seekBar.setProgress(minProgress);
+                    progress = minProgress;
+                }
+                updateTitleAndSummary(progress);
+                if (fromUser) {
+                    if (appUsesTopics) {
+                        mApplyToTopic.setVisibility(View.VISIBLE);
+                        mApplyToTopic.setText(
+                                mContext.getString(R.string.apply_to_topic, mTopic.getLabel()));
+                        applyToApp.setVisibility(View.VISIBLE);
+                    }
+                }
+            }
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {
+                // no-op
+            }
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {
+                // no-op
+            }
+
+            private void updateTitleAndSummary(int progress) {
+                switch (progress) {
+                    case NotificationListenerService.Ranking.IMPORTANCE_NONE:
+                        topicSummary.setText(mContext.getString(
+                                R.string.notification_importance_blocked));
+                        topicTitle.setText(mContext.getString(R.string.blocked_importance));
+                        break;
+                    case NotificationListenerService.Ranking.IMPORTANCE_LOW:
+                        topicSummary.setText(mContext.getString(
+                                R.string.notification_importance_low));
+                        topicTitle.setText(mContext.getString(R.string.low_importance));
+                        break;
+                    case NotificationListenerService.Ranking.IMPORTANCE_DEFAULT:
+                        topicSummary.setText(mContext.getString(
+                                R.string.notification_importance_default));
+                        topicTitle.setText(mContext.getString(R.string.default_importance));
+                        break;
+                    case NotificationListenerService.Ranking.IMPORTANCE_HIGH:
+                        topicSummary.setText(mContext.getString(
+                                R.string.notification_importance_high));
+                        topicTitle.setText(mContext.getString(R.string.high_importance));
+                        break;
+                    case NotificationListenerService.Ranking.IMPORTANCE_MAX:
+                        topicSummary.setText(mContext.getString(
+                                R.string.notification_importance_max));
+                        topicTitle.setText(mContext.getString(R.string.max_importance));
+                        break;
+                }
+            }
+        });
+        mSeekBar.setProgress(importance);
+    }
+
+    void saveImportance(final StatusBarNotification sbn) {
+        int progress = mSeekBar.getProgress();
+        try {
+            mINotificationManager.setImportance(sbn.getPackageName(), sbn.getUid(),
+                    mApplyToTopic.isChecked() ? mTopic : null, progress);
+        } catch (RemoteException e) {
+            // :(
+        }
+    }
+
     public void setActualHeight(int actualHeight) {
         mActualHeight = actualHeight;
         invalidate();
@@ -103,4 +233,12 @@
         // Prevents this view from creating a layer when alpha is animating.
         return false;
     }
+
+    public void setExposed(boolean exposed) {
+        mExposed = exposed;
+    }
+
+    public boolean areGutsExposed() {
+        return mExposed;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
index 859a330..98a37f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
@@ -110,6 +110,25 @@
                 sIconExtractor,
                 sGreyComparator,
                 mGreyApplicator));
+        mComparators.add(new HeaderProcessor(mRow,
+                com.android.internal.R.id.profile_badge,
+                null /* Extractor */,
+                new ViewComparator() {
+                    @Override
+                    public boolean compare(View parent, View child, Object parentData,
+                            Object childData) {
+                        return parent.getVisibility() == View.VISIBLE;
+                    }
+
+                    @Override
+                    public boolean isEmpty(View view) {
+                        if (view instanceof ImageView) {
+                            return ((ImageView) view).getDrawable() == null;
+                        }
+                        return false;
+                    }
+                },
+                sVisibilityApplicator));
         mComparators.add(HeaderProcessor.forTextView(mRow,
                 com.android.internal.R.id.app_name_text));
         mComparators.add(HeaderProcessor.forTextView(mRow,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderViewWrapper.java
deleted file mode 100644
index ddad2e0..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderViewWrapper.java
+++ /dev/null
@@ -1,239 +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;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
-import android.graphics.drawable.Drawable;
-import android.view.NotificationHeaderView;
-import android.view.View;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-import android.widget.ImageView;
-
-import com.android.systemui.R;
-import com.android.systemui.ViewInvertHelper;
-import com.android.systemui.statusbar.phone.NotificationPanelView;
-
-import java.util.ArrayList;
-
-/**
- * Wraps a notification header view.
- */
-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;
-    private final int mIconDarkColor = 0xffffffff;
-    protected final Interpolator mLinearOutSlowInInterpolator;
-    protected final ViewInvertHelper mInvertHelper;
-
-    protected int mColor;
-    private ImageView mIcon;
-
-    private ImageView mExpandButton;
-    private NotificationHeaderView mNotificationHeader;
-
-    protected NotificationHeaderViewWrapper(Context ctx, View view) {
-        super(view);
-        mIconDarkAlpha = ctx.getResources().getInteger(R.integer.doze_small_icon_alpha);
-        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(ctx,
-                android.R.interpolator.linear_out_slow_in);
-        mInvertHelper = new ViewInvertHelper(ctx, NotificationPanelView.DOZE_ANIMATION_DURATION);
-        resolveHeaderViews();
-    }
-
-    protected void resolveHeaderViews() {
-        mIcon = (ImageView) mView.findViewById(com.android.internal.R.id.icon);
-        mExpandButton = (ImageView) mView.findViewById(com.android.internal.R.id.expand_button);
-        mColor = resolveColor(mExpandButton);
-        mNotificationHeader = (NotificationHeaderView) mView.findViewById(
-                com.android.internal.R.id.notification_header);
-        for (int i = 0; i < mNotificationHeader.getChildCount(); i++) {
-            View child = mNotificationHeader.getChildAt(i);
-            if (child != mIcon) {
-                mInvertHelper.addTarget(child);
-            }
-        }
-    }
-
-    private int resolveColor(ImageView icon) {
-        if (icon != null && icon.getDrawable() != null) {
-            ColorFilter filter = icon.getDrawable().getColorFilter();
-            if (filter instanceof PorterDuffColorFilter) {
-                return ((PorterDuffColorFilter) filter).getColor();
-            }
-        }
-        return 0;
-    }
-
-    @Override
-    public void notifyContentUpdated() {
-        mInvertHelper.clearTargets();
-        // Reinspect the notification.
-        resolveHeaderViews();
-    }
-
-    @Override
-    public void setDark(boolean dark, boolean fade, long delay) {
-        if (fade) {
-            mInvertHelper.fade(dark, delay);
-        } else {
-            mInvertHelper.update(dark);
-        }
-        if (mIcon != null) {
-            boolean hadColorFilter = mNotificationHeader.getOriginalIconColor()
-                    != NotificationHeaderView.NO_COLOR;
-            if (fade) {
-                if (hadColorFilter) {
-                    fadeIconColorFilter(mIcon, dark, delay);
-                    fadeIconAlpha(mIcon, dark, delay);
-                } else {
-                    fadeGrayscale(mIcon, dark, delay);
-                }
-            } else {
-                if (hadColorFilter) {
-                    updateIconColorFilter(mIcon, dark);
-                    updateIconAlpha(mIcon, dark);
-                } else {
-                    updateGrayscale(mIcon, dark);
-                }
-            }
-        }
-    }
-
-    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(mLinearOutSlowInInterpolator);
-        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
-            public void onAnimationUpdate(ValueAnimator animation) {
-                updateIconColorFilter(target, (Float) animation.getAnimatedValue());
-            }
-        }, dark, delay, null /* listener */);
-    }
-
-    private void fadeIconAlpha(final ImageView target, boolean dark, long delay) {
-        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                float t = (float) animation.getAnimatedValue();
-                target.setImageAlpha((int) (255 * (1f - t) + mIconDarkAlpha * t));
-            }
-        }, dark, delay, null /* listener */);
-    }
-
-    protected void fadeGrayscale(final ImageView target, final boolean dark, long delay) {
-        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                updateGrayscaleMatrix((float) animation.getAnimatedValue());
-                target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
-            }
-        }, dark, delay, new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if (!dark) {
-                    target.setColorFilter(null);
-                }
-            }
-        });
-    }
-
-    private void updateIconColorFilter(ImageView target, boolean dark) {
-        updateIconColorFilter(target, dark ? 1f : 0f);
-    }
-
-    private void updateIconColorFilter(ImageView target, float intensity) {
-        int color = interpolateColor(mColor, mIconDarkColor, intensity);
-        mIconColorFilter.setColor(color);
-        Drawable iconDrawable = target.getDrawable();
-
-        // Also, the notification might have been modified during the animation, so background
-        // might be null here.
-        if (iconDrawable != null) {
-            iconDrawable.mutate().setColorFilter(mIconColorFilter);
-        }
-    }
-
-    private void updateIconAlpha(ImageView target, boolean dark) {
-        target.setImageAlpha(dark ? mIconDarkAlpha : 255);
-    }
-
-    protected void updateGrayscale(ImageView target, boolean dark) {
-        if (dark) {
-            updateGrayscaleMatrix(1f);
-            target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
-        } else {
-            target.setColorFilter(null);
-        }
-    }
-
-    @Override
-    public void updateExpandability(boolean expandable, View.OnClickListener onClickListener) {
-        mExpandButton.setVisibility(expandable ? View.VISIBLE : View.GONE);
-        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);
-        int gSource = Color.green(source);
-        int bSource = Color.blue(source);
-        int aTarget = Color.alpha(target);
-        int rTarget = Color.red(target);
-        int gTarget = Color.green(target);
-        int bTarget = Color.blue(target);
-        return Color.argb(
-                (int) (aSource * (1f - t) + aTarget * t),
-                (int) (rSource * (1f - t) + rTarget * t),
-                (int) (gSource * (1f - t) + gTarget * t),
-                (int) (bSource * (1f - t) + bTarget * t));
-    }
-
-    @Override
-    public NotificationHeaderView getNotificationHeader() {
-        return mNotificationHeader;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
deleted file mode 100644
index 77e8c55..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar;
-
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.graphics.Color;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.ProgressBar;
-
-/**
- * Wraps a notification view inflated from a template.
- */
-public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapper {
-
-    private static final int mDarkProgressTint = 0xffffffff;
-
-    protected ImageView mPicture;
-    private ProgressBar mProgressBar;
-
-    protected NotificationTemplateViewWrapper(Context ctx, View view) {
-        super(ctx, view);
-        resolveTemplateViews();
-    }
-
-    private void resolveTemplateViews() {
-        View mainColumn = mView.findViewById(com.android.internal.R.id.notification_main_column);
-        mPicture = (ImageView) mView.findViewById(com.android.internal.R.id.right_icon);
-        final View progress = mView.findViewById(com.android.internal.R.id.progress);
-        if (progress instanceof ProgressBar) {
-            mProgressBar = (ProgressBar) progress;
-        } else {
-            // It's still a viewstub
-            mProgressBar = null;
-        }
-        if (mainColumn != null) {
-            mInvertHelper.addTarget(mainColumn);
-        }
-    }
-
-    @Override
-    public void notifyContentUpdated() {
-        super.notifyContentUpdated();
-
-        // Reinspect the notification.
-        resolveTemplateViews();
-    }
-
-    @Override
-    public void setDark(boolean dark, boolean fade, long delay) {
-        super.setDark(dark, fade, delay);
-        setPictureGrayscale(dark, fade, delay);
-        setProgressBarDark(dark, fade, delay);
-    }
-
-    private void setProgressBarDark(boolean dark, boolean fade, long delay) {
-        if (mProgressBar != null) {
-            if (fade) {
-                fadeProgressDark(mProgressBar, dark, delay);
-            } else {
-                updateProgressDark(mProgressBar, dark);
-            }
-        }
-    }
-
-    private void fadeProgressDark(final ProgressBar target, final boolean dark, long delay) {
-        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                float t = (float) animation.getAnimatedValue();
-                updateProgressDark(target, t);
-            }
-        }, dark, delay, null /* listener */);
-    }
-
-    private void updateProgressDark(ProgressBar target, float intensity) {
-        int color = interpolateColor(mColor, mDarkProgressTint, intensity);
-        target.getIndeterminateDrawable().mutate().setTint(color);
-        target.getProgressDrawable().mutate().setTint(color);
-    }
-
-    private void updateProgressDark(ProgressBar target, boolean dark) {
-        updateProgressDark(target, dark ? 1f : 0f);
-    }
-
-    protected void setPictureGrayscale(boolean grayscale, boolean fade, long delay) {
-        if (mPicture != null) {
-            if (fade) {
-                fadeGrayscale(mPicture, grayscale, delay);
-            } else {
-                updateGrayscale(mPicture, grayscale);
-            }
-        }
-    }
-
-    private static int interpolateColor(int source, int target, float t) {
-        int aSource = Color.alpha(source);
-        int rSource = Color.red(source);
-        int gSource = Color.green(source);
-        int bSource = Color.blue(source);
-        int aTarget = Color.alpha(target);
-        int rTarget = Color.red(target);
-        int gTarget = Color.green(target);
-        int bTarget = Color.blue(target);
-        return Color.argb(
-                (int) (aSource * (1f - t) + aTarget * t),
-                (int) (rSource * (1f - t) + rTarget * t),
-                (int) (gSource * (1f - t) + gTarget * t),
-                (int) (bSource * (1f - t) + bTarget * t));
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
deleted file mode 100644
index 61499de..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
+++ /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
- */
-
-package com.android.systemui.statusbar;
-
-import android.content.Context;
-import android.view.NotificationHeaderView;
-import android.view.View;
-
-/**
- * Wraps the actual notification content view; used to implement behaviors which are different for
- * the individual templates and custom views.
- */
-public abstract class NotificationViewWrapper {
-
-    protected final View mView;
-
-    public static NotificationViewWrapper wrap(Context ctx, View v) {
-        if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) {
-            return new NotificationTemplateViewWrapper(ctx, v);
-        } else if (v instanceof NotificationHeaderView) {
-            return new NotificationHeaderViewWrapper(ctx, v);
-        } else {
-            return new NotificationCustomViewWrapper(v);
-        }
-    }
-
-    protected NotificationViewWrapper(View view) {
-        mView = view;
-    }
-
-    /**
-     * In dark mode, we draw as little as possible, assuming a black background.
-     *
-     * @param dark whether we should display ourselves in dark mode
-     * @param fade whether to animate the transition if the mode changes
-     * @param delay if fading, the delay of the animation
-     */
-    public abstract void setDark(boolean dark, boolean fade, long delay);
-
-    /**
-     * Notifies this wrapper that the content of the view might have changed.
-     */
-    public void notifyContentUpdated() {};
-
-    /**
-     * @return true if this template might need to be clipped with a round rect to make it look
-     *         nice, false otherwise
-     */
-    public boolean needsRoundRectClipping() {
-        return false;
-    }
-
-    /**
-     * Update the appearance of the expand button.
-     *
-     * @param expandable should this view be expandable
-     * @param onClickListener the listener to invoke when the expand affordance is clicked on
-     */
-    public void updateExpandability(boolean expandable, View.OnClickListener onClickListener) {}
-
-    /**
-     * @return the notification header if it exists
-     */
-    public NotificationHeaderView getNotificationHeader() {
-        return null;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index f243b00..d7e47c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -30,11 +30,11 @@
 public class RemoteInputController {
 
     private final ArrayList<WeakReference<NotificationData.Entry>> mRemoteInputs = new ArrayList<>();
-    private final StatusBarWindowManager mStatusBarWindowManager;
+    private final ArrayList<Callback> mCallbacks = new ArrayList<>(3);
     private final HeadsUpManager mHeadsUpManager;
 
     public RemoteInputController(StatusBarWindowManager sbwm, HeadsUpManager headsUpManager) {
-        mStatusBarWindowManager = sbwm;
+        addCallback(sbwm);
         mHeadsUpManager = headsUpManager;
     }
 
@@ -59,8 +59,12 @@
     }
 
     private void apply(NotificationData.Entry entry) {
-        mStatusBarWindowManager.setRemoteInputActive(isRemoteInputActive());
         mHeadsUpManager.setRemoteInputActive(entry, isRemoteInputActive(entry));
+        boolean remoteInputActive = isRemoteInputActive();
+        int N = mCallbacks.size();
+        for (int i = 0; i < N; i++) {
+            mCallbacks.get(i).onRemoteInputActive(remoteInputActive);
+        }
     }
 
     /**
@@ -99,4 +103,12 @@
     }
 
 
+    public void addCallback(Callback callback) {
+        Preconditions.checkNotNull(callback);
+        mCallbacks.add(callback);
+    }
+
+    public interface Callback {
+        void onRemoteInputActive(boolean active);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScalingDrawableWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScalingDrawableWrapper.java
new file mode 100644
index 0000000..24277e6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScalingDrawableWrapper.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.systemui.statusbar;
+
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.DrawableWrapper;
+
+/**
+ * An extension of {@link DrawableWrapper} that will take a given Drawable and scale it by
+ * the given factor.
+ */
+class ScalingDrawableWrapper extends DrawableWrapper {
+    private float mScaleFactor;
+
+    public ScalingDrawableWrapper(Drawable drawable, float scaleFactor) {
+        super(drawable);
+        mScaleFactor = scaleFactor;
+    }
+
+    @Override
+    public int getIntrinsicWidth() {
+        return (int) (super.getIntrinsicWidth() * mScaleFactor);
+    }
+
+    @Override
+    public int getIntrinsicHeight() {
+        return (int) (super.getIntrinsicHeight() * mScaleFactor);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
index 682676b..dba7130 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -22,7 +22,10 @@
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Paint;
 import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.animation.Interpolator;
@@ -32,11 +35,14 @@
  */
 public class ScrimView extends View
 {
+    private final Paint mPaint = new Paint();
     private int mScrimColor;
     private boolean mIsEmpty = true;
     private boolean mDrawAsSrc;
     private float mViewAlpha = 1.0f;
     private ValueAnimator mAlphaAnimator;
+    private Rect mExcludedRect = new Rect();
+    private boolean mHasExcludedArea;
     private ValueAnimator.AnimatorUpdateListener mAlphaUpdateListener
             = new ValueAnimator.AnimatorUpdateListener() {
         @Override
@@ -51,6 +57,7 @@
             mAlphaAnimator = null;
         }
     };
+    private Runnable mChangeRunnable;
 
     public ScrimView(Context context) {
         this(context, null);
@@ -72,15 +79,43 @@
     protected void onDraw(Canvas canvas) {
         if (mDrawAsSrc || (!mIsEmpty && mViewAlpha > 0f)) {
             PorterDuff.Mode mode = mDrawAsSrc ? PorterDuff.Mode.SRC : PorterDuff.Mode.SRC_OVER;
-            int color = mScrimColor;
-            color = Color.argb((int) (Color.alpha(color) * mViewAlpha), Color.red(color),
-                    Color.green(color), Color.blue(color));
-            canvas.drawColor(color, mode);
+            int color = getScrimColorWithAlpha();
+            if (!mHasExcludedArea) {
+                canvas.drawColor(color, mode);
+            } else {
+                mPaint.setColor(color);
+                if (mExcludedRect.top > 0) {
+                    canvas.drawRect(0, 0, getWidth(), mExcludedRect.top, mPaint);
+                }
+                if (mExcludedRect.left > 0) {
+                    canvas.drawRect(0,  mExcludedRect.top, mExcludedRect.left, mExcludedRect.bottom,
+                            mPaint);
+                }
+                if (mExcludedRect.right < getWidth()) {
+                    canvas.drawRect(mExcludedRect.right,
+                            mExcludedRect.top,
+                            getWidth(),
+                            mExcludedRect.bottom,
+                            mPaint);
+                }
+                if (mExcludedRect.bottom < getHeight()) {
+                    canvas.drawRect(0,  mExcludedRect.bottom, getWidth(), getHeight(), mPaint);
+                }
+            }
         }
     }
 
+    public int getScrimColorWithAlpha() {
+        int color = mScrimColor;
+        color = Color.argb((int) (Color.alpha(color) * mViewAlpha), Color.red(color),
+                Color.green(color), Color.blue(color));
+        return color;
+    }
+
     public void setDrawAsSrc(boolean asSrc) {
         mDrawAsSrc = asSrc;
+        mPaint.setXfermode(new PorterDuffXfermode(mDrawAsSrc ? PorterDuff.Mode.SRC
+                : PorterDuff.Mode.SRC_OVER));
         invalidate();
     }
 
@@ -89,6 +124,9 @@
             mIsEmpty = Color.alpha(color) == 0;
             mScrimColor = color;
             invalidate();
+            if (mChangeRunnable != null) {
+                mChangeRunnable.run();
+            }
         }
     }
 
@@ -105,8 +143,13 @@
         if (mAlphaAnimator != null) {
             mAlphaAnimator.cancel();
         }
-        mViewAlpha = alpha;
-        invalidate();
+        if (alpha != mViewAlpha) {
+            mViewAlpha = alpha;
+            invalidate();
+            if (mChangeRunnable != null) {
+                mChangeRunnable.run();
+            }
+        }
     }
 
     public void animateViewAlpha(float alpha, long durationOut, Interpolator interpolator) {
@@ -120,4 +163,24 @@
         mAlphaAnimator.setDuration(durationOut);
         mAlphaAnimator.start();
     }
+
+    public void setExcludedArea(Rect area) {
+        if (area == null) {
+            mHasExcludedArea = false;
+            invalidate();
+            return;
+        }
+
+        int left = Math.max(area.left, 0);
+        int top = Math.max(area.top, 0);
+        int right = Math.min(area.right, getWidth());
+        int bottom = Math.min(area.bottom, getHeight());
+        mExcludedRect.set(left, top, right, bottom);
+        mHasExcludedArea = left < right && top < bottom;
+        invalidate();
+    }
+
+    public void setChangeRunnable(Runnable changeRunnable) {
+        mChangeRunnable = changeRunnable;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index cc30882..6801e5f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -16,16 +16,18 @@
 
 package com.android.systemui.statusbar;
 
+import android.annotation.DrawableRes;
 import android.content.Context;
 import android.content.res.ColorStateList;
+import android.content.res.Resources;
 import android.graphics.Color;
-import android.graphics.PorterDuff;
 import android.graphics.drawable.Animatable;
 import android.graphics.drawable.Drawable;
 import android.telephony.SubscriptionInfo;
 import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -86,10 +88,11 @@
     View mWifiSignalSpacer;
     LinearLayout mMobileSignalGroup;
 
-    private int mWideTypeIconStartPadding;
-    private int mSecondaryTelephonyPadding;
-    private int mEndPadding;
-    private int mEndPaddingNothingVisible;
+    private final int mWideTypeIconStartPadding;
+    private final int mSecondaryTelephonyPadding;
+    private final int mEndPadding;
+    private final int mEndPaddingNothingVisible;
+    private final float mIconScaleFactor;
 
     private boolean mBlockAirplane;
     private boolean mBlockMobile;
@@ -106,6 +109,17 @@
 
     public SignalClusterView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+
+        Resources res = getResources();
+        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);
+        mEndPaddingNothingVisible = res.getDimensionPixelSize(
+                R.dimen.no_signal_cluster_battery_padding);
+
+        TypedValue typedValue = new TypedValue();
+        res.getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true);
+        mIconScaleFactor = typedValue.getFloat();
     }
 
     @Override
@@ -146,19 +160,6 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mWideTypeIconStartPadding = getContext().getResources().getDimensionPixelSize(
-                R.dimen.wide_type_icon_start_padding);
-        mSecondaryTelephonyPadding = getContext().getResources().getDimensionPixelSize(
-                R.dimen.secondary_telephony_padding);
-        mEndPadding = getContext().getResources().getDimensionPixelSize(
-                R.dimen.signal_cluster_battery_padding);
-        mEndPaddingNothingVisible = getContext().getResources().getDimensionPixelSize(
-                R.dimen.no_signal_cluster_battery_padding);
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
 
         mVpn            = (ImageView) findViewById(R.id.vpn);
         mEthernetGroup  = (ViewGroup) findViewById(R.id.ethernet_combo);
@@ -174,6 +175,32 @@
         mWifiAirplaneSpacer =         findViewById(R.id.wifi_airplane_spacer);
         mWifiSignalSpacer =           findViewById(R.id.wifi_signal_spacer);
         mMobileSignalGroup = (LinearLayout) findViewById(R.id.mobile_signal_group);
+
+        maybeScaleVpnAndNoSimsIcons();
+    }
+
+    /**
+     * Extracts the icon off of the VPN and no sims views and maybe scale them by
+     * {@link #mIconScaleFactor}. Note that the other icons are not scaled here because they are
+     * dynamic. As such, they need to be scaled each time the icon changes in {@link #apply()}.
+     */
+    private void maybeScaleVpnAndNoSimsIcons() {
+        if (mIconScaleFactor == 1.f) {
+            return;
+        }
+
+        mVpn.setImageDrawable(new ScalingDrawableWrapper(mVpn.getDrawable(), mIconScaleFactor));
+
+        mNoSims.setImageDrawable(
+                new ScalingDrawableWrapper(mNoSims.getDrawable(), mIconScaleFactor));
+        mNoSimsDark.setImageDrawable(
+                new ScalingDrawableWrapper(mNoSimsDark.getDrawable(), mIconScaleFactor));
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
         for (PhoneState state : mPhoneStates) {
             mMobileSignalGroup.addView(state.mMobileGroup);
         }
@@ -185,14 +212,7 @@
 
     @Override
     protected void onDetachedFromWindow() {
-        mVpn            = null;
-        mEthernetGroup  = null;
-        mEthernet       = null;
-        mWifiGroup      = null;
-        mWifi           = null;
-        mAirplane       = null;
         mMobileSignalGroup.removeAllViews();
-        mMobileSignalGroup = null;
         TunerService.get(mContext).removeTunable(this);
 
         super.onDetachedFromWindow();
@@ -351,10 +371,13 @@
 
         for (PhoneState state : mPhoneStates) {
             if (state.mMobile != null) {
+                state.maybeStopAnimatableDrawable(state.mMobile);
                 state.mMobile.setImageDrawable(null);
+                state.mLastMobileStrengthId = -1;
             }
             if (state.mMobileType != null) {
                 state.mMobileType.setImageDrawable(null);
+                state.mLastMobileTypeId = -1;
             }
         }
 
@@ -380,8 +403,8 @@
 
         if (mEthernetVisible) {
             if (mLastEthernetIconId != mEthernetIconId) {
-                mEthernet.setImageResource(mEthernetIconId);
-                mEthernetDark.setImageResource(mEthernetIconId);
+                setIconForView(mEthernet, mEthernetIconId);
+                setIconForView(mEthernetDark, mEthernetIconId);
                 mLastEthernetIconId = mEthernetIconId;
             }
             mEthernetGroup.setContentDescription(mEthernetDescription);
@@ -394,11 +417,10 @@
                 String.format("ethernet: %s",
                     (mEthernetVisible ? "VISIBLE" : "GONE")));
 
-
         if (mWifiVisible) {
             if (mWifiStrengthId != mLastWifiStrengthId) {
-                mWifi.setImageResource(mWifiStrengthId);
-                mWifiDark.setImageResource(mWifiStrengthId);
+                setIconForView(mWifi, mWifiStrengthId);
+                setIconForView(mWifiDark, mWifiStrengthId);
                 mLastWifiStrengthId = mWifiStrengthId;
             }
             mWifiGroup.setContentDescription(mWifiDescription);
@@ -425,7 +447,7 @@
 
         if (mIsAirplaneMode) {
             if (mLastAirplaneIconId != mAirplaneIconId) {
-                mAirplane.setImageResource(mAirplaneIconId);
+                setIconForView(mAirplane, mAirplaneIconId);
                 mLastAirplaneIconId = mAirplaneIconId;
             }
             mAirplane.setContentDescription(mAirplaneContentDescription);
@@ -453,6 +475,21 @@
         setPaddingRelative(0, 0, anythingVisible ? mEndPadding : mEndPaddingNothingVisible, 0);
     }
 
+    /**
+     * Sets the given drawable id on the view. This method will also scale the icon by
+     * {@link #mIconScaleFactor} if appropriate.
+     */
+    private void setIconForView(ImageView imageView, @DrawableRes int iconId) {
+        // Using the imageView's context to retrieve the Drawable so that theme is preserved.
+        Drawable icon = imageView.getContext().getDrawable(iconId);
+
+        if (mIconScaleFactor == 1.f) {
+            imageView.setImageDrawable(icon);
+        } else {
+            imageView.setImageDrawable(new ScalingDrawableWrapper(icon, mIconScaleFactor));
+        }
+    }
+
     public void setIconTint(int tint, float darkIntensity) {
         boolean changed = tint != mIconTint || darkIntensity != mDarkIntensity;
         mIconTint = tint;
@@ -486,6 +523,8 @@
         private final int mSubId;
         private boolean mMobileVisible = false;
         private int mMobileStrengthId = 0, mMobileTypeId = 0;
+        private int mLastMobileStrengthId = -1;
+        private int mLastMobileTypeId = -1;
         private boolean mIsMobileTypeIconWide;
         private String mMobileDescription, mMobileTypeDescription;
 
@@ -508,25 +547,16 @@
 
         public boolean apply(boolean isSecondaryIcon) {
             if (mMobileVisible && !mIsAirplaneMode) {
-                mMobile.setImageResource(mMobileStrengthId);
-                Drawable mobileDrawable = mMobile.getDrawable();
-                if (mobileDrawable instanceof Animatable) {
-                    Animatable ad = (Animatable) mobileDrawable;
-                    if (!ad.isRunning()) {
-                        ad.start();
-                    }
+                if (mLastMobileStrengthId != mMobileStrengthId) {
+                    updateAnimatableIcon(mMobile, mMobileStrengthId);
+                    updateAnimatableIcon(mMobileDark, mMobileStrengthId);
+                    mLastMobileStrengthId = mMobileStrengthId;
                 }
 
-                mMobileDark.setImageResource(mMobileStrengthId);
-                Drawable mobileDarkDrawable = mMobileDark.getDrawable();
-                if (mobileDarkDrawable instanceof Animatable) {
-                    Animatable ad = (Animatable) mobileDarkDrawable;
-                    if (!ad.isRunning()) {
-                        ad.start();
-                    }
+                if (mLastMobileTypeId != mMobileTypeId) {
+                    mMobileType.setImageResource(mMobileTypeId);
+                    mLastMobileTypeId = mMobileTypeId;
                 }
-
-                mMobileType.setImageResource(mMobileTypeId);
                 mMobileGroup.setContentDescription(mMobileTypeDescription
                         + " " + mMobileDescription);
                 mMobileGroup.setVisibility(View.VISIBLE);
@@ -550,6 +580,32 @@
             return mMobileVisible;
         }
 
+        private void updateAnimatableIcon(ImageView view, int resId) {
+            maybeStopAnimatableDrawable(view);
+            view.setImageResource(resId);
+            maybeStartAnimatableDrawable(view);
+        }
+
+        private void maybeStopAnimatableDrawable(ImageView view) {
+            Drawable drawable = view.getDrawable();
+            if (drawable instanceof Animatable) {
+                Animatable ad = (Animatable) drawable;
+                if (ad.isRunning()) {
+                    ad.stop();
+                }
+            }
+        }
+
+        private void maybeStartAnimatableDrawable(ImageView view) {
+            Drawable drawable = view.getDrawable();
+            if (drawable instanceof Animatable) {
+                Animatable ad = (Animatable) drawable;
+                if (!ad.isRunning()) {
+                    ad.start();
+                }
+            }
+        }
+
         public void populateAccessibilityEvent(AccessibilityEvent event) {
             if (mMobileVisible && mMobileGroup != null
                     && mMobileGroup.getContentDescription() != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
deleted file mode 100644
index 1fc8744..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-import com.android.systemui.R;
-
-/**
- * The view representing the separation between important and less important notifications
- */
-public class SpeedBumpView extends ExpandableView {
-
-    private final int mSpeedBumpHeight;
-    private AlphaOptimizedView mLine;
-    private boolean mIsVisible = true;
-    private final Interpolator mFastOutSlowInInterpolator;
-
-    public SpeedBumpView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mSpeedBumpHeight = getResources()
-                .getDimensionPixelSize(R.dimen.speed_bump_height);
-        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
-                android.R.interpolator.fast_out_slow_in);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mLine = (AlphaOptimizedView) findViewById(R.id.speedbump_line);
-    }
-
-    @Override
-    protected int getInitialHeight() {
-        return mSpeedBumpHeight;
-    }
-
-    @Override
-    public int getIntrinsicHeight() {
-        return mSpeedBumpHeight;
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        mLine.setPivotX(mLine.getWidth() / 2);
-        mLine.setPivotY(mLine.getHeight() / 2);
-        setOutlineProvider(null);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        measureChildren(widthMeasureSpec, heightMeasureSpec);
-        int height = mSpeedBumpHeight;
-        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height);
-    }
-
-    @Override
-    public boolean isTransparent() {
-        return true;
-    }
-
-    public void performVisibilityAnimation(boolean nowVisible, long delay) {
-        animateDivider(nowVisible, delay, null /* onFinishedRunnable */);
-    }
-
-    /**
-     * Animate the divider to a new visibility.
-     *
-     * @param nowVisible should it now be visible
-     * @param delay the delay after the animation should start
-     * @param onFinishedRunnable A runnable which should be run when the animation is
-     *        finished.
-     */
-    public void animateDivider(boolean nowVisible, long delay, Runnable onFinishedRunnable) {
-        if (nowVisible != mIsVisible) {
-            // Animate dividers
-            float endValue = nowVisible ? 1.0f : 0.0f;
-            mLine.animate()
-                    .alpha(endValue)
-                    .setStartDelay(delay)
-                    .scaleX(endValue)
-                    .scaleY(endValue)
-                    .setInterpolator(mFastOutSlowInInterpolator)
-                    .withEndAction(onFinishedRunnable);
-            mIsVisible = nowVisible;
-        } else {
-            if (onFinishedRunnable != null) {
-                onFinishedRunnable.run();
-            }
-        }
-    }
-
-    public void setInvisible() {
-        mLine.setAlpha(0.0f);
-        mLine.setScaleX(0.0f);
-        mLine.setScaleY(0.0f);
-        mIsVisible = false;
-    }
-
-    @Override
-    public void performRemoveAnimation(long duration, float translationDirection,
-            Runnable onFinishedRunnable) {
-        // TODO: Use duration
-        performVisibilityAnimation(false, 0 /* delay */);
-    }
-
-    @Override
-    public void performAddAnimation(long delay, long duration) {
-        // TODO: Use duration
-        performVisibilityAnimation(true, delay);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
index 2f66c41..c836637 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
@@ -21,8 +21,6 @@
 import android.view.View;
 import android.view.animation.Interpolator;
 
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
-
 /**
  * A common base class for all views in the notification stack scroller which don't have a
  * background.
@@ -80,9 +78,9 @@
             float endValue = nowVisible ? 1.0f : 0.0f;
             Interpolator interpolator;
             if (nowVisible) {
-                interpolator = PhoneStatusBar.ALPHA_IN;
+                interpolator = Interpolators.ALPHA_IN;
             } else {
-                interpolator = PhoneStatusBar.ALPHA_OUT;
+                interpolator = Interpolators.ALPHA_OUT;
             }
             mAnimating = true;
             mContent.animate()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index db2415a..5a7cf86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -24,14 +24,15 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
+import android.graphics.drawable.ScaleDrawable;
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.TypedValue;
+import android.view.Gravity;
 import android.view.ViewDebug;
 import android.view.accessibility.AccessibilityEvent;
-import android.widget.ImageView;
-
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.systemui.R;
 
@@ -76,7 +77,7 @@
             setScaleY(scale);
         }
 
-        setScaleType(ImageView.ScaleType.CENTER);
+        setScaleType(ScaleType.CENTER);
     }
 
     public void setNotification(Notification notification) {
@@ -191,12 +192,24 @@
      * @return Drawable for this item, or null if the package or item could not
      *         be found
      */
-    public static Drawable getIcon(Context context, StatusBarIcon icon) {
-        int userId = icon.user.getIdentifier();
+    public static Drawable getIcon(Context context, StatusBarIcon statusBarIcon) {
+        int userId = statusBarIcon.user.getIdentifier();
         if (userId == UserHandle.USER_ALL) {
             userId = UserHandle.USER_SYSTEM;
         }
-        return icon.icon.loadDrawableAsUser(context, userId);
+
+        Drawable icon = statusBarIcon.icon.loadDrawableAsUser(context, userId);
+
+        TypedValue typedValue = new TypedValue();
+        context.getResources().getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true);
+        float scaleFactor = typedValue.getFloat();
+
+        // No need to scale the icon, so return it as is.
+        if (scaleFactor == 1.f) {
+            return icon;
+        }
+
+        return new ScalingDrawableWrapper(icon, scaleFactor);
     }
 
     public StatusBarIcon getStatusBarIcon() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java
new file mode 100644
index 0000000..38b6497
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 com.android.systemui.statusbar.notification.TransformState;
+
+/**
+ * A view that can be transformed to and from.
+ */
+public interface TransformableView {
+    int TRANSFORMING_VIEW_HEADER = 0;
+    int TRANSFORMING_VIEW_TITLE = 1;
+    int TRANSFORMING_VIEW_TEXT = 2;
+    int TRANSFORMING_VIEW_IMAGE = 3;
+    int TRANSFORMING_VIEW_PROGRESS = 4;
+
+    /**
+     * 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
+     */
+    TransformState getCurrentState(int fadingView);
+
+    /**
+     * Transform to the given view
+     * @param notification the view to transform to
+     */
+    void transformTo(TransformableView notification, Runnable endRunnable);
+
+    /**
+     * Transform to this view from the given view
+     * @param notification the view to transform from
+     */
+    void transformFrom(TransformableView notification);
+
+    /**
+     * 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/UserGridView.java b/packages/SystemUI/src/com/android/systemui/statusbar/UserGridView.java
deleted file mode 100644
index 32caf9f..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/UserGridView.java
+++ /dev/null
@@ -1,190 +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;
-
-import android.content.Context;
-import android.content.DialogInterface;
-import android.os.UserHandle;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.GridView;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
-import com.android.systemui.statusbar.phone.SystemUIDialog;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
-
-public class UserGridView extends GridView {
-
-    private PhoneStatusBar mStatusBar;
-    private UserSwitcherController mUserSwitcherController;
-    private Adapter mAdapter;
-    private int mPendingUserId = UserHandle.USER_NULL;
-
-    public UserGridView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public void init(PhoneStatusBar statusBar, UserSwitcherController userSwitcherController) {
-        mStatusBar = statusBar;
-        mUserSwitcherController = userSwitcherController;
-        mAdapter = new Adapter(mUserSwitcherController);
-        setAdapter(mAdapter);
-
-        setOnItemClickListener(new OnItemClickListener() {
-            @Override
-            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-                mPendingUserId = UserHandle.USER_NULL;
-                UserSwitcherController.UserRecord record = mAdapter.getItem(position);
-                if (record == null) {
-                    return;
-                }
-
-                if (record.isGuest || record.isAddUser) {
-                    mUserSwitcherController.switchTo(record);
-                    return;
-                }
-
-                if (record.isCurrent) {
-                    showOfflineAuthUi();
-                } else {
-                    mPendingUserId = record.info.id;
-                    mUserSwitcherController.switchTo(record);
-                }
-            }
-        });
-
-        setOnItemLongClickListener(new OnItemLongClickListener() {
-            @Override
-            public boolean onItemLongClick(AdapterView<?> parent,
-                    View view, int position, long id) {
-                UserSwitcherController.UserRecord record = mAdapter.getItem(position);
-                if (record == null || record.isAddUser) {
-                    return false;
-                }
-                if (record.isGuest) {
-                    if (record.isCurrent) {
-                        mUserSwitcherController.switchTo(record);
-                    }
-                    return true;
-                }
-
-                new RemoveUserDialog(getContext(), record.info.id).show();
-                return true;
-            }
-        });
-    }
-
-    public void onUserSwitched(int newUserId) {
-        if (mPendingUserId == newUserId) {
-            // Bring up security view after user switch is completed.
-            post(new Runnable() {
-                @Override
-                public void run() {
-                    showOfflineAuthUi();
-                }
-            });
-        }
-        mPendingUserId = UserHandle.USER_NULL;
-    }
-
-    private void showOfflineAuthUi() {
-        // TODO: Show keyguard UI in-place.
-        mStatusBar.executeRunnableDismissingKeyguard(null, null, true, true);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
-        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
-        if (widthMode == MeasureSpec.UNSPECIFIED) {
-            setNumColumns(AUTO_FIT);
-        } else {
-            int columnWidth = Math.max(1, getRequestedColumnWidth());
-            int itemCount = getAdapter() == null ? 0 : getAdapter().getCount();
-            int numColumns = Math.max(1, Math.min(itemCount, widthSize / columnWidth));
-            setNumColumns(numColumns);
-        }
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-    }
-
-    private final class Adapter extends UserSwitcherController.BaseUserAdapter {
-        public Adapter(UserSwitcherController controller) {
-            super(controller);
-        }
-
-        @Override
-        public View getView(int position, View convertView, ViewGroup parent) {
-            if (convertView == null) {
-                LayoutInflater inflater = (LayoutInflater)getContext().getSystemService
-                        (Context.LAYOUT_INFLATER_SERVICE);
-                convertView = inflater.inflate(R.layout.fullscreen_user_pod, null);
-            }
-            UserSwitcherController.UserRecord record = getItem(position);
-
-            TextView nameView = (TextView) convertView.findViewById(R.id.user_name);
-            if (record != null) {
-                nameView.setText(getName(getContext(), record));
-                convertView.setActivated(record.isCurrent);
-            } else {
-                nameView.setText("Unknown");
-            }
-
-            ImageView iconView = (ImageView) convertView.findViewById(R.id.user_avatar);
-            if (record == null || record.picture == null) {
-                iconView.setImageDrawable(getDrawable(getContext(), record));
-            } else {
-                iconView.setImageBitmap(record.picture);
-            }
-
-            return convertView;
-        }
-    }
-
-    private final class RemoveUserDialog extends SystemUIDialog implements
-            DialogInterface.OnClickListener {
-
-        private final int mUserId;
-
-        public RemoveUserDialog(Context context, int userId) {
-            super(context);
-            setTitle(R.string.user_remove_user_title);
-            setMessage(context.getString(R.string.user_remove_user_message));
-            setButton(DialogInterface.BUTTON_NEGATIVE,
-                    context.getString(android.R.string.cancel), this);
-            setButton(DialogInterface.BUTTON_POSITIVE,
-                    context.getString(R.string.user_remove_user_remove), this);
-            setCanceledOnTouchOutside(false);
-            mUserId = userId;
-        }
-
-        @Override
-        public void onClick(DialogInterface dialog, int which) {
-            if (which == BUTTON_NEGATIVE) {
-                cancel();
-            } else {
-                dismiss();
-                mUserSwitcherController.removeUserId(mUserId);
-            }
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
new file mode 100644
index 0000000..63ff5aa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.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 com.android.systemui.statusbar;
+
+import android.os.Handler;
+import android.util.ArrayMap;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.TransformState;
+
+import java.util.Stack;
+
+/**
+ * A view that can be transformed to and from.
+ */
+public class ViewTransformationHelper implements TransformableView {
+
+    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<>();
+
+    public void addTransformedView(int key, View transformedView) {
+        mTransformedViews.put(key, transformedView);
+    }
+
+    public void reset() {
+        mTransformedViews.clear();
+    }
+
+    public void setCustomTransformation(CustomTransformation transformation, int viewType) {
+        mCustomTransformations.put(viewType, transformation);
+    }
+
+    @Override
+    public TransformState getCurrentState(int fadingView) {
+        View view = mTransformedViews.get(fadingView);
+        if (view != null && view.getVisibility() != View.GONE) {
+            return TransformState.createFrom(view);
+        }
+        return null;
+    }
+
+    @Override
+    public void transformTo(TransformableView notification, Runnable endRunnable) {
+        Runnable runnable = endRunnable;
+        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.recycle();
+                    runnable = null;
+                    continue;
+                }
+                TransformState otherState = notification.getCurrentState(viewType);
+                if (otherState != null) {
+                    boolean run = ownState.transformViewTo(otherState, runnable);
+                    otherState.recycle();
+                    if (run) {
+                        runnable = null;
+                    }
+                } else {
+                    // there's no other view available
+                    CrossFadeHelper.fadeOut(mTransformedViews.get(viewType), runnable);
+                    runnable = null;
+                }
+                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) {
+        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.recycle();
+                    continue;
+                }
+                TransformState otherState = notification.getCurrentState(viewType);
+                if (otherState != null) {
+                    ownState.transformViewFrom(otherState);
+                    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));
+                }
+                ownState.recycle();
+            }
+        }
+    }
+
+    @Override
+    public void setVisible(boolean visible) {
+        for (Integer viewType : mTransformedViews.keySet()) {
+            TransformState ownState = getCurrentState(viewType);
+            if (ownState != null) {
+                ownState.setVisible(visible);
+                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
+     */
+    public void addRemainingTransformTypes(View viewRoot) {
+        // lets now tag the right views
+        int numValues = mTransformedViews.size();
+        for (int i = 0; i < numValues; i++) {
+            View view = mTransformedViews.valueAt(i);
+            while (view != viewRoot.getParent()) {
+                view.setTag(TAG_CONTAINS_TRANSFORMED_VIEW, true);
+                view = (View) view.getParent();
+            }
+        }
+        Stack<View> stack = new Stack<>();
+        // Add the right views now
+        stack.push(viewRoot);
+        while (!stack.isEmpty()) {
+            View child = stack.pop();
+            if (child.getVisibility() == View.GONE) {
+                continue;
+            }
+            Boolean containsView = (Boolean) child.getTag(TAG_CONTAINS_TRANSFORMED_VIEW);
+            if (containsView == null) {
+                // This one is unhandled, let's add it to our list.
+                int id = child.getId();
+                if (id != View.NO_ID) {
+                    // We only fade views with an id
+                    addTransformedView(id, child);
+                    continue;
+                }
+            }
+            child.setTag(TAG_CONTAINS_TRANSFORMED_VIEW, null);
+            if (child instanceof ViewGroup && !mTransformedViews.containsValue(child)){
+                ViewGroup group = (ViewGroup) child;
+                for (int i = 0; i < group.getChildCount(); i++) {
+                    stack.push(group.getChildAt(i));
+                }
+            }
+        }
+    }
+
+    public interface CustomTransformation {
+        /**
+         * Transform a state to the given view
+         * @param ownState the state to transform
+         * @param notification the view to transform to
+         * @return whether a custom transformation is performed
+         */
+        boolean transformTo(TransformState ownState, TransformableView notification,
+                Runnable endRunnable);
+
+        /**
+         * Transform to this state from the given view
+         * @param ownState the state to transform to
+         * @param notification the view to transform from
+         * @return whether a custom transformation is performed
+         */
+        boolean transformFrom(TransformState ownState, TransformableView notification);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
new file mode 100644
index 0000000..eb30120
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.car;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.support.v4.util.SimpleArrayMap;
+import android.view.View;
+import android.widget.LinearLayout;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.ActivityStarter;
+
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A controller to populate data for CarNavigationBarView and handle user interactions.
+ * <p/>
+ * Each button inside the navigation bar is defined by data in arrays_car.xml. OEMs can customize
+ * the navigation buttons by updating arrays_car.xml appropriately in an overlay.
+ */
+class CarNavigationBarController {
+    private static final String EXTRA_FACET_CATEGORIES = "categories";
+    private static final String EXTRA_FACET_PACKAGES = "packages";
+    private static final String EXTRA_FACET_ID = "filter_id";
+    private static final String EXTRA_FACET_LAUNCH_PICKER = "launch_picker";
+
+    // Each facet of the navigation bar maps to a set of package names or categories defined in
+    // arrays_car.xml. Package names for a given facet are delimited by ";"
+    private static final String FACET_FILTER_DEMILITER = ";";
+
+    private Context mContext;
+    private CarNavigationBarView mNavBar;
+    private ActivityStarter mActivityStarter;
+
+    // Set of categories each facet will filter on.
+    private List<String[]> mFacetCategories = new ArrayList<String[]>();
+    // Set of package names each facet will filter on.
+    private List<String[]> mFacetPackages = new ArrayList<String[]>();
+
+    private SimpleArrayMap<String, Integer> mFacetCategoryMap
+            = new SimpleArrayMap<String, Integer>();
+    private SimpleArrayMap<String, Integer> mFacetPackageMap
+            = new SimpleArrayMap<String, Integer>();
+
+    private List<Intent> mIntents;
+    private List<Intent> mLongPressIntents;
+
+    private List<CarNavigationButton> mNavButtons = new ArrayList<CarNavigationButton>();
+
+    private int mCurrentFacetIndex;
+    private String mCurrentPackageName;
+
+    public CarNavigationBarController(Context context,
+                                      CarNavigationBarView navBar,
+                                      ActivityStarter activityStarter) {
+        mContext = context;
+        mNavBar = navBar;
+        mActivityStarter = activityStarter;
+        bind();
+    }
+
+    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)) {
+            setCurrentFacet(mFacetPackageMap.get(packageName));
+        }
+
+        // Check if the package matches any of the categories for the facets
+        String category = getPackageCategory(packageName);
+        if (category != null) {
+            setCurrentFacet(mFacetCategoryMap.get(category));
+        }
+    }
+
+    private void bind() {
+        // Read up arrays_car.xml and populate the navigation bar here.
+        Resources r = mContext.getResources();
+        TypedArray icons = r.obtainTypedArray(R.array.car_facet_icons);
+        TypedArray intents = r.obtainTypedArray(R.array.car_facet_intent_uris);
+        TypedArray longpressIntents =
+                r.obtainTypedArray(R.array.car_facet_longpress_intent_uris);
+        TypedArray facetPackageNames = r.obtainTypedArray(R.array.car_facet_package_filters);
+
+        TypedArray facetCategories = r.obtainTypedArray(R.array.car_facet_category_filters);
+
+        if (icons.length() != intents.length()
+                || icons.length() != longpressIntents.length()
+                || icons.length() != facetPackageNames.length()
+                || icons.length() != facetCategories.length()) {
+            throw new RuntimeException("car_facet array lengths do not match");
+        }
+
+        mIntents = createEmptyIntentList(icons.length());
+        mLongPressIntents = createEmptyIntentList(icons.length());
+
+        for (int i = 0; i < icons.length(); i++) {
+            Drawable icon = icons.getDrawable(i);
+            try {
+                mIntents.set(i,
+                        Intent.parseUri(intents.getString(i), Intent.URI_INTENT_SCHEME));
+
+                String longpressUri = longpressIntents.getString(i);
+                boolean hasLongpress = !longpressUri.isEmpty();
+                if (hasLongpress) {
+                    mLongPressIntents.set(i,
+                            Intent.parseUri(longpressUri, Intent.URI_INTENT_SCHEME));
+                }
+
+                CarNavigationButton button = createNavButton(icon, i, hasLongpress);
+                mNavButtons.add(button);
+                mNavBar.addButton(button,
+                        createNavButton(icon, i, hasLongpress) /* lightsOutButton */);
+
+                initFacetFilterMaps(i,
+                        facetPackageNames.getString(i).split(FACET_FILTER_DEMILITER),
+                        facetCategories.getString(i).split(FACET_FILTER_DEMILITER));
+            } catch (URISyntaxException e) {
+                throw new RuntimeException("Malformed intent uri", e);
+            }
+        }
+    }
+
+    private void initFacetFilterMaps(int id, String[] packageNames, String[] categories) {
+        mFacetCategories.add(categories);
+        for (int i = 0; i < categories.length; i++) {
+            mFacetCategoryMap.put(categories[i], id);
+        }
+
+        mFacetPackages.add(packageNames);
+        for (int i = 0; i < packageNames.length; i++) {
+            mFacetPackageMap.put(packageNames[i], id);
+        }
+    }
+
+    private String getPackageCategory(String packageName) {
+        PackageManager pm = mContext.getPackageManager();
+        int size = mFacetCategories.size();
+        // For each facet, check if the given package name matches one of its categories
+        for (int i = 0; i < size; i++) {
+            String[] categories = mFacetCategories.get(i);
+            for (int j = 0; j < categories.length; j++) {
+                String category = categories[j];
+                Intent intent = new Intent();
+                intent.setPackage(packageName);
+                intent.setAction(Intent.ACTION_MAIN);
+                intent.addCategory(category);
+                List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
+                if (list.size() > 0) {
+                    // Cache this package name into facetPackageMap, so we won't have to query
+                    // all categories next time this package name shows up.
+                    mFacetPackageMap.put(packageName, mFacetCategoryMap.get(category));
+                    return category;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Helper method to check if a given facet has multiple packages associated with it.
+     * This can be resource defined package names or package names filtered by facet category.
+     */
+    private boolean facetHasMultiplePackages(int index) {
+        PackageManager pm = mContext.getPackageManager();
+
+        // Check if the packages defined for the filter actually exists on the device
+        String[] packages = mFacetPackages.get(index);
+        if (packages.length > 1) {
+            int count = 0;
+            for (int i = 0; i < packages.length; i++) {
+                count += pm.getLaunchIntentForPackage(packages[i]) != null ? 1 : 0;
+                if (count > 1) {
+                    return true;
+                }
+            }
+        }
+
+        // If there weren't multiple packages defined for the facet, check the categories
+        // and see if they resolve to multiple package names
+        String categories[] = mFacetCategories.get(index);
+
+        int count = 0;
+        for (int i = 0; i < categories.length; i++) {
+            String category = categories[i];
+            Intent intent = new Intent();
+            intent.setAction(Intent.ACTION_MAIN);
+            intent.addCategory(category);
+            count += pm.queryIntentActivities(intent, 0).size();
+            if (count > 1) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void setCurrentFacet(int index) {
+        if (index == mCurrentFacetIndex) {
+            return;
+        }
+
+        if (mNavButtons.get(mCurrentFacetIndex) != null) {
+            mNavButtons.get(mCurrentFacetIndex)
+                    .setSelected(false /* selected */, false /* showMoreIcon */);
+        }
+
+        if (mNavButtons.get(index) != null) {
+            mNavButtons.get(index).setSelected(true /* selected */,
+                    facetHasMultiplePackages(index)  /* showMoreIcon */);
+        }
+        mCurrentFacetIndex = index;
+    }
+
+    private CarNavigationButton createNavButton(Drawable icon, final int id,
+                                                boolean longClickEnabled) {
+        CarNavigationButton button = (CarNavigationButton) View.inflate(mContext,
+                R.layout.car_navigation_button, null);
+        button.setResources(icon);
+        LinearLayout.LayoutParams lp =
+                new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 1);
+        button.setLayoutParams(lp);
+
+        button.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                onFacetClicked(id);
+            }
+        });
+
+        if (longClickEnabled) {
+            button.setLongClickable(true);
+            button.setOnLongClickListener(new View.OnLongClickListener() {
+                @Override
+                public boolean onLongClick(View v) {
+                    onFacetLongClicked(id);
+                    return true;
+                }
+            });
+        } else {
+            button.setLongClickable(false);
+        }
+
+        return button;
+    }
+
+    private void startActivity(Intent intent) {
+        if (mActivityStarter != null && intent != null) {
+            mActivityStarter.startActivity(intent, true);
+        }
+    }
+
+    private void onFacetClicked(int index) {
+        Intent intent = mIntents.get(index);
+        String packageName = intent.getPackage();
+
+        if (packageName == null) {
+            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.
+        // This value can be used to determine which facet was selected
+        intent.putExtra(EXTRA_FACET_ID, Integer.toString(index));
+
+        // If the current facet is clicked, we want to launch the picker by default
+        // rather than the "preferred/last run" app.
+        intent.putExtra(EXTRA_FACET_LAUNCH_PICKER, index == mCurrentFacetIndex);
+
+        setCurrentFacet(index);
+        startActivity(intent);
+    }
+
+    private void onFacetLongClicked(int index) {
+        setCurrentFacet(index);
+        startActivity(mLongPressIntents.get(index));
+    }
+
+    private List<Intent> createEmptyIntentList(int size) {
+        return Arrays.asList(new Intent[size]);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
new file mode 100644
index 0000000..efc3646
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.car;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.R.color;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.ImageView.ScaleType;
+import android.widget.LinearLayout;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.NavigationBarView;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * A custom navigation bar for the automotive use case.
+ * <p>
+ * The navigation bar in the automotive use case is more like a list of shortcuts, rendered
+ * in a linear layout.
+ */
+class CarNavigationBarView extends NavigationBarView {
+    private LinearLayout mNavButtons;
+    private LinearLayout mLightsOutButtons;
+
+    public CarNavigationBarView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public void onFinishInflate() {
+        mNavButtons = (LinearLayout) findViewById(R.id.nav_buttons);
+        mLightsOutButtons = (LinearLayout) findViewById(R.id.lights_out);
+    }
+
+    public void addButton(CarNavigationButton button, CarNavigationButton lightsOutButton){
+        mNavButtons.addView(button);
+        mLightsOutButtons.addView(lightsOutButton);
+    }
+
+    @Override
+    public void setDisabledFlags(int disabledFlags, boolean force) {
+        // TODO: Populate.
+    }
+
+    @Override
+    public void reorient() {
+        // We expect the car head unit to always have a fixed rotation so we ignore this. The super
+        // class implentation expects mRotatedViews to be populated, so if you call into it, there
+        // is a possibility of a NullPointerException.
+    }
+
+    @Override
+    public View getCurrentView() {
+        return this;
+    }
+
+    @Override
+    public void setNavigationIconHints(int hints, boolean force) {
+        // We do not need to set the navigation icon hints for a vehicle
+        // Calling setNavigationIconHints in the base class will result in a NPE as the car
+        // navigation bar does not have a back button.
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
new file mode 100644
index 0000000..504f059
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.car;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.widget.RelativeLayout;
+import com.android.keyguard.AlphaOptimizedImageButton;
+import com.android.systemui.R;
+
+/**
+ * A wrapper view for a car navigation facet, which includes a button icon and a drop down icon.
+ */
+public class CarNavigationButton extends RelativeLayout {
+    private static final float SELECTED_ALPHA = 1;
+    private static final float UNSELECTED_ALPHA = 0.7f;
+
+    private AlphaOptimizedImageButton mIcon;
+    private AlphaOptimizedImageButton mMoreIcon;
+
+    public CarNavigationButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public void onFinishInflate() {
+        super.onFinishInflate();
+        mIcon = (AlphaOptimizedImageButton) findViewById(R.id.car_nav_button_icon);
+        mIcon.setClickable(false);
+        mIcon.setBackgroundColor(android.R.color.transparent);
+        mIcon.setAlpha(UNSELECTED_ALPHA);
+
+        mMoreIcon = (AlphaOptimizedImageButton) findViewById(R.id.car_nav_button_more_icon);
+        mMoreIcon.setClickable(false);
+        mMoreIcon.setBackgroundColor(android.R.color.transparent);
+        mMoreIcon.setVisibility(INVISIBLE);
+        mMoreIcon.setImageDrawable(getContext().getDrawable(R.drawable.car_ic_arrow));
+        mMoreIcon.setAlpha(UNSELECTED_ALPHA);
+    }
+
+    public void setResources(Drawable icon) {
+        mIcon.setImageDrawable(icon);
+    }
+
+    public void setSelected(boolean selected, boolean showMoreIcon) {
+        if (selected) {
+            mMoreIcon.setVisibility(showMoreIcon ? VISIBLE : INVISIBLE);
+            mMoreIcon.setAlpha(SELECTED_ALPHA);
+            mIcon.setAlpha(SELECTED_ALPHA);
+        } else {
+            mMoreIcon.setVisibility(INVISIBLE);
+            mIcon.setAlpha(UNSELECTED_ALPHA);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
new file mode 100644
index 0000000..e20936b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.car;
+
+import android.app.ActivityManager;
+import android.app.ITaskStackListener;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.view.ViewStub;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+
+/**
+ * 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;
+    private FullscreenUserSwitcher mFullscreenUserSwitcher;
+
+    @Override
+    public void start() {
+        super.start();
+        mHandler = new Handler();
+        mTaskStackListener = new TaskStackListenerImpl(mHandler);
+        mSystemServicesProxy = new SystemServicesProxy(mContext);
+        mSystemServicesProxy.registerTaskStackListener(mTaskStackListener);
+    }
+
+    @Override
+    protected void addNavigationBar() {
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
+                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
+                WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
+                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
+                        | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
+                PixelFormat.TRANSLUCENT);
+        lp.setTitle("CarNavigationBar");
+        lp.windowAnimations = 0;
+        mWindowManager.addView(mNavigationBarView, lp);
+    }
+
+    @Override
+    protected void createNavigationBarView(Context context) {
+        if (mNavigationBarView != null) {
+            return;
+        }
+        mCarNavigationBar =
+                (CarNavigationBarView) View.inflate(context, R.layout.car_navigation_bar, null);
+        mController = new CarNavigationBarController(context, mCarNavigationBar,
+                this /* ActivityStarter*/);
+        mNavigationBarView = mCarNavigationBar;
+    }
+
+    @Override
+    protected void repositionNavigationBar() {
+        // The navigation bar for a vehicle will not need to be repositioned, as it is always
+        // set at the bottom.
+    }
+
+    /**
+     * An implementation of ITaskStackListener, 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 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
+    protected void createUserSwitcher() {
+        if (mUserSwitcherController.useFullscreenUserSwitcher()) {
+            mFullscreenUserSwitcher = new FullscreenUserSwitcher(this, mUserSwitcherController,
+                    (ViewStub) mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub));
+        } else {
+            super.createUserSwitcher();
+        }
+    }
+
+    @Override
+    public void userSwitched(int newUserId) {
+        super.userSwitched(newUserId);
+        if (mFullscreenUserSwitcher != null) {
+            mFullscreenUserSwitcher.onUserSwitched(newUserId);
+        }
+    }
+
+    @Override
+    public void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) {
+        super.updateKeyguardState(goingToFullShade, fromShadeLocked);
+        if (mFullscreenUserSwitcher != null) {
+            if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
+                mFullscreenUserSwitcher.show();
+            } else {
+                mFullscreenUserSwitcher.hide();
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
new file mode 100644
index 0000000..3025092
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.car;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.view.View;
+import android.view.ViewStub;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+
+/**
+ * Manages the fullscreen user switcher.
+ */
+public class FullscreenUserSwitcher {
+
+    private View mContainer;
+    private UserGridView mUserGridView;
+    private UserSwitcherController mUserSwitcherController;
+
+    public FullscreenUserSwitcher(PhoneStatusBar statusBar,
+            UserSwitcherController userSwitcherController,
+            ViewStub containerStub) {
+        mUserSwitcherController = userSwitcherController;
+        mContainer = containerStub.inflate();
+        mUserGridView = (UserGridView) mContainer.findViewById(R.id.user_grid);
+        mUserGridView.init(statusBar, mUserSwitcherController);
+    }
+
+    public void onUserSwitched(int newUserId) {
+        mUserGridView.onUserSwitched(newUserId);
+    }
+
+    public void show() {
+        mContainer.setVisibility(View.VISIBLE);
+    }
+
+    public void hide() {
+        mContainer.setVisibility(View.GONE);
+    }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
new file mode 100644
index 0000000..28f4e05
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.car;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.UserHandle;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.GridView;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+
+public class UserGridView extends GridView {
+
+    private PhoneStatusBar mStatusBar;
+    private UserSwitcherController mUserSwitcherController;
+    private Adapter mAdapter;
+    private int mPendingUserId = UserHandle.USER_NULL;
+
+    public UserGridView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public void init(PhoneStatusBar statusBar, UserSwitcherController userSwitcherController) {
+        mStatusBar = statusBar;
+        mUserSwitcherController = userSwitcherController;
+        mAdapter = new Adapter(mUserSwitcherController);
+        setAdapter(mAdapter);
+
+        setOnItemClickListener(new OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                mPendingUserId = UserHandle.USER_NULL;
+                UserSwitcherController.UserRecord record = mAdapter.getItem(position);
+                if (record == null) {
+                    return;
+                }
+
+                if (record.isGuest || record.isAddUser) {
+                    mUserSwitcherController.switchTo(record);
+                    return;
+                }
+
+                if (record.isCurrent) {
+                    showOfflineAuthUi();
+                } else {
+                    mPendingUserId = record.info.id;
+                    mUserSwitcherController.switchTo(record);
+                }
+            }
+        });
+
+        setOnItemLongClickListener(new OnItemLongClickListener() {
+            @Override
+            public boolean onItemLongClick(AdapterView<?> parent,
+                    View view, int position, long id) {
+                UserSwitcherController.UserRecord record = mAdapter.getItem(position);
+                if (record == null || record.isAddUser) {
+                    return false;
+                }
+                if (record.isGuest) {
+                    if (record.isCurrent) {
+                        mUserSwitcherController.switchTo(record);
+                    }
+                    return true;
+                }
+
+                new RemoveUserDialog(getContext(), record.info.id).show();
+                return true;
+            }
+        });
+    }
+
+    public void onUserSwitched(int newUserId) {
+        if (mPendingUserId == newUserId) {
+            // Bring up security view after user switch is completed.
+            post(new Runnable() {
+                @Override
+                public void run() {
+                    showOfflineAuthUi();
+                }
+            });
+        }
+        mPendingUserId = UserHandle.USER_NULL;
+    }
+
+    private void showOfflineAuthUi() {
+        // TODO: Show keyguard UI in-place.
+        mStatusBar.executeRunnableDismissingKeyguard(null, null, true, true);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+        if (widthMode == MeasureSpec.UNSPECIFIED) {
+            setNumColumns(AUTO_FIT);
+        } else {
+            int columnWidth = Math.max(1, getRequestedColumnWidth());
+            int itemCount = getAdapter() == null ? 0 : getAdapter().getCount();
+            int numColumns = Math.max(1, Math.min(itemCount, widthSize / columnWidth));
+            setNumColumns(numColumns);
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    private final class Adapter extends UserSwitcherController.BaseUserAdapter {
+        public Adapter(UserSwitcherController controller) {
+            super(controller);
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            if (convertView == null) {
+                LayoutInflater inflater = (LayoutInflater)getContext().getSystemService
+                        (Context.LAYOUT_INFLATER_SERVICE);
+                convertView = inflater.inflate(R.layout.car_fullscreen_user_pod, null);
+            }
+            UserSwitcherController.UserRecord record = getItem(position);
+
+            TextView nameView = (TextView) convertView.findViewById(R.id.user_name);
+            if (record != null) {
+                nameView.setText(getName(getContext(), record));
+                convertView.setActivated(record.isCurrent);
+            } else {
+                nameView.setText("Unknown");
+            }
+
+            ImageView iconView = (ImageView) convertView.findViewById(R.id.user_avatar);
+            if (record == null || record.picture == null) {
+                iconView.setImageDrawable(getDrawable(getContext(), record));
+            } else {
+                iconView.setImageBitmap(record.picture);
+            }
+
+            return convertView;
+        }
+    }
+
+    private final class RemoveUserDialog extends SystemUIDialog implements
+            DialogInterface.OnClickListener {
+
+        private final int mUserId;
+
+        public RemoveUserDialog(Context context, int userId) {
+            super(context);
+            setTitle(R.string.user_remove_user_title);
+            setMessage(context.getString(R.string.user_remove_user_message));
+            setButton(DialogInterface.BUTTON_NEGATIVE,
+                    context.getString(android.R.string.cancel), this);
+            setButton(DialogInterface.BUTTON_POSITIVE,
+                    context.getString(R.string.user_remove_user_remove), this);
+            setCanceledOnTouchOutside(false);
+            mUserId = userId;
+        }
+
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+            if (which == BUTTON_NEGATIVE) {
+                cancel();
+            } else {
+                dismiss();
+                mUserSwitcherController.removeUserId(mUserId);
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
new file mode 100644
index 0000000..bf291d3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.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.systemui.statusbar.notification;
+
+import android.util.Pools;
+import android.view.NotificationHeaderView;
+import android.view.View;
+
+import com.android.systemui.statusbar.CrossFadeHelper;
+
+/**
+ * A transform state of a text view.
+*/
+public class HeaderTransformState extends TransformState {
+
+    private static Pools.SimplePool<HeaderTransformState> sInstancePool
+            = new Pools.SimplePool<>(40);
+    private View mExpandButton;
+
+    @Override
+    public void initFrom(View view) {
+        super.initFrom(view);
+        if (view instanceof NotificationHeaderView) {
+            NotificationHeaderView header = (NotificationHeaderView) view;
+            mExpandButton = header.getExpandButton();
+        }
+    }
+
+    @Override
+    public boolean transformViewTo(TransformState otherState, Runnable endRunnable) {
+        // 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.
+        if (!(mTransformedView instanceof NotificationHeaderView)) {
+            return false;
+        }
+        NotificationHeaderView header = (NotificationHeaderView) mTransformedView;
+        int childCount = header.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View headerChild = header.getChildAt(i);
+            if (headerChild.getVisibility() == View.GONE) {
+                continue;
+            }
+            if (headerChild != mExpandButton) {
+                headerChild.setVisibility(View.INVISIBLE);
+            } else {
+                CrossFadeHelper.fadeOut(mExpandButton, endRunnable);
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public void transformViewFrom(TransformState otherState) {
+        // 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.
+        if (!(mTransformedView instanceof NotificationHeaderView)) {
+            return;
+        }
+        NotificationHeaderView header = (NotificationHeaderView) mTransformedView;
+        header.setVisibility(View.VISIBLE);
+        header.setAlpha(1.0f);
+        int childCount = header.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View headerChild = header.getChildAt(i);
+            if (headerChild.getVisibility() == View.GONE) {
+                continue;
+            }
+            if (headerChild != mExpandButton) {
+                headerChild.setVisibility(View.VISIBLE);
+            } else {
+                CrossFadeHelper.fadeIn(mExpandButton);
+            }
+        }
+        return;
+    }
+
+    public static HeaderTransformState obtain() {
+        HeaderTransformState instance = sInstancePool.acquire();
+        if (instance != null) {
+            return instance;
+        }
+        return new HeaderTransformState();
+    }
+
+    @Override
+    public void recycle() {
+        super.recycle();
+        sInstancePool.release(this);
+    }
+
+    @Override
+    protected void reset() {
+        super.reset();
+        mExpandButton = null;
+    }
+
+    public void setVisible(boolean visible) {
+        super.setVisible(visible);
+        if (!(mTransformedView instanceof NotificationHeaderView)) {
+            return;
+        }
+        NotificationHeaderView header = (NotificationHeaderView) mTransformedView;
+        int childCount = header.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View headerChild = header.getChildAt(i);
+            if (headerChild.getVisibility() == View.GONE) {
+                continue;
+            }
+            headerChild.animate().cancel();
+            headerChild.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+            if (headerChild == mExpandButton) {
+                headerChild.setAlpha(visible ? 1.0f : 0.0f);
+            }
+        }
+    }
+
+    @Override
+    public void prepareFadeIn() {
+        super.prepareFadeIn();
+        if (!(mTransformedView instanceof NotificationHeaderView)) {
+            return;
+        }
+        NotificationHeaderView header = (NotificationHeaderView) mTransformedView;
+        int childCount = header.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View headerChild = header.getChildAt(i);
+            if (headerChild.getVisibility() == View.GONE) {
+                continue;
+            }
+            headerChild.animate().cancel();
+            headerChild.setVisibility(View.VISIBLE);
+            headerChild.setAlpha(1.0f);
+        }
+    }
+}
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 5fb6fec..5eed5ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
@@ -18,18 +18,29 @@
 
 import android.annotation.Nullable;
 import android.content.Context;
+import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.AttributeSet;
+import android.view.View;
 import android.widget.TextView;
 
 import com.android.keyguard.AlphaOptimizedLinearLayout;
 import com.android.systemui.R;
 import com.android.systemui.ViewInvertHelper;
+import com.android.systemui.statusbar.CrossFadeHelper;
+import com.android.systemui.statusbar.TransformableView;
+import com.android.systemui.statusbar.ViewTransformationHelper;
 import com.android.systemui.statusbar.phone.NotificationPanelView;
 
+import java.util.ArrayList;
+
 /**
  * A hybrid view which may contain information about one ore more notifications.
  */
-public class HybridNotificationView extends AlphaOptimizedLinearLayout {
+public class HybridNotificationView extends AlphaOptimizedLinearLayout
+        implements TransformableView {
+
+    private ViewTransformationHelper mTransformationHelper;
 
     protected TextView mTitleView;
     protected TextView mTextView;
@@ -58,6 +69,39 @@
         mTitleView = (TextView) findViewById(R.id.notification_title);
         mTextView = (TextView) findViewById(R.id.notification_text);
         mInvertHelper = new ViewInvertHelper(this, NotificationPanelView.DOZE_ANIMATION_DURATION);
+        mTransformationHelper = new ViewTransformationHelper();
+        mTransformationHelper.setCustomTransformation(
+                new ViewTransformationHelper.CustomTransformation() {
+                    @Override
+                    public boolean transformTo(TransformState ownState, TransformableView notification,
+                            Runnable endRunnable) {
+                        // We want to transform to the same y location as the title
+                        TransformState otherState = notification.getCurrentState(
+                                TRANSFORMING_VIEW_TITLE);
+                        CrossFadeHelper.fadeOut(mTextView, endRunnable);
+                        if (otherState != null) {
+                            ownState.animateViewVerticalTo(otherState, endRunnable);
+                            otherState.recycle();
+                        }
+                        return true;
+                    }
+
+                    @Override
+                    public boolean transformFrom(TransformState ownState,
+                            TransformableView notification) {
+                        // We want to transform from the same y location as the title
+                        TransformState otherState = notification.getCurrentState(
+                                TRANSFORMING_VIEW_TITLE);
+                        CrossFadeHelper.fadeIn(mTextView);
+                        if (otherState != null) {
+                            ownState.animateViewVerticalFrom(otherState);
+                            otherState.recycle();
+                        }
+                        return true;
+                    }
+                }, TRANSFORMING_VIEW_TEXT);
+        mTransformationHelper.addTransformedView(TRANSFORMING_VIEW_TITLE, mTitleView);
+        mTransformationHelper.addTransformedView(TRANSFORMING_VIEW_TEXT, mTextView);
     }
 
     public void bind(CharSequence title) {
@@ -66,11 +110,38 @@
 
     public void bind(CharSequence title, CharSequence text) {
         mTitleView.setText(title);
+        if (TextUtils.isEmpty(title)) {
+            mTitleView.setVisibility(GONE);
+        }
         mTextView.setText(text);
+        if (TextUtils.isEmpty(text)) {
+            mTextView.setVisibility(GONE);
+        }
         requestLayout();
     }
 
     public void setDark(boolean dark, boolean fade, long delay) {
         mInvertHelper.setInverted(dark, fade, delay);
     }
+
+    @Override
+    public TransformState getCurrentState(int fadingView) {
+        return mTransformationHelper.getCurrentState(fadingView);
+    }
+
+    @Override
+    public void transformTo(TransformableView notification, Runnable endRunnable) {
+        mTransformationHelper.transformTo(notification, endRunnable);
+    }
+
+    @Override
+    public void transformFrom(TransformableView notification) {
+        mTransformationHelper.transformFrom(notification);
+    }
+
+    @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
index b8adf5b..285d53f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationViewManager.java
@@ -52,16 +52,10 @@
 
     public HybridNotificationView bindFromNotification(HybridNotificationView reusableView,
             Notification notification) {
-        CharSequence titleText = resolveTitle(notification);
-        if (titleText == null) {
-            if (reusableView != null) {
-                mParent.removeView(reusableView);
-            }
-            return null;
-        }
         if (reusableView == null) {
             reusableView = inflateHybridView();
         }
+        CharSequence titleText = resolveTitle(notification);
         CharSequence contentText = resolveText(notification);
         reusableView.bind(titleText, contentText);
         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
new file mode 100644
index 0000000..e891a97
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.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.statusbar.notification;
+
+import android.graphics.drawable.Icon;
+import android.util.Pools;
+import android.view.View;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+
+/**
+ * A transform state of a image view.
+*/
+public class ImageTransformState extends TransformState {
+
+    public static final int ICON_TAG = R.id.image_icon_tag;
+    private static Pools.SimplePool<ImageTransformState> sInstancePool
+            = new Pools.SimplePool<>(40);
+    private Icon mIcon;
+
+    @Override
+    public void initFrom(View view) {
+        super.initFrom(view);
+        if (view instanceof ImageView) {
+            mIcon = (Icon) view.getTag(ICON_TAG);
+        }
+    }
+
+    @Override
+    protected boolean sameAs(TransformState otherState) {
+        if (otherState instanceof ImageTransformState) {
+            return mIcon != null && mIcon.sameAs(((ImageTransformState) otherState).getIcon());
+        }
+        return super.sameAs(otherState);
+    }
+
+    public Icon getIcon() {
+        return mIcon;
+    }
+
+    public static ImageTransformState obtain() {
+        ImageTransformState instance = sInstancePool.acquire();
+        if (instance != null) {
+            return instance;
+        }
+        return new ImageTransformState();
+    }
+
+    @Override
+    protected boolean animateScale() {
+        return true;
+    }
+
+    @Override
+    public void recycle() {
+        super.recycle();
+        sInstancePool.release(this);
+    }
+
+    @Override
+    protected void reset() {
+        super.reset();
+        mIcon = null;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java
new file mode 100644
index 0000000..ce9540b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.service.notification.StatusBarNotification;
+import android.view.View;
+
+/**
+ * Wraps a notification containing a big picture template
+ */
+public class NotificationBigPictureTemplateViewWrapper extends NotificationTemplateViewWrapper {
+
+    protected NotificationBigPictureTemplateViewWrapper(Context ctx, View view) {
+        super(ctx, view);
+    }
+
+    @Override
+    public void notifyContentUpdated(StatusBarNotification notification) {
+        super.notifyContentUpdated(notification);
+        updateImageTag(notification);
+    }
+
+    private void updateImageTag(StatusBarNotification notification) {
+        final Bundle extras = notification.getNotification().extras;
+        Icon overRiddenIcon = extras.getParcelable(Notification.EXTRA_LARGE_ICON_BIG);
+        if (overRiddenIcon != null) {
+            mPicture.setTag(ImageTransformState.ICON_TAG, overRiddenIcon);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
new file mode 100644
index 0000000..60c1911
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import android.view.View;
+
+import com.android.systemui.ViewInvertHelper;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
+
+/**
+ * Wraps a notification containing a custom view.
+ */
+public class NotificationCustomViewWrapper extends NotificationViewWrapper {
+
+    private final ViewInvertHelper mInvertHelper;
+
+    protected NotificationCustomViewWrapper(View view) {
+        super(view);
+        mInvertHelper = new ViewInvertHelper(view, NotificationPanelView.DOZE_ANIMATION_DURATION);
+    }
+
+    @Override
+    public void setDark(boolean dark, boolean fade, long delay) {
+        if (dark == mDark) {
+            return;
+        }
+        super.setDark(dark, fade, delay);
+        if (fade) {
+            mInvertHelper.fade(dark, delay);
+        } else {
+            mInvertHelper.update(dark);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
new file mode 100644
index 0000000..85f789c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.Drawable;
+import android.service.notification.StatusBarNotification;
+import android.util.ArrayMap;
+import android.view.NotificationHeaderView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+import com.android.systemui.ViewInvertHelper;
+import com.android.systemui.statusbar.Interpolators;
+import com.android.systemui.statusbar.TransformableView;
+import com.android.systemui.statusbar.ViewTransformationHelper;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
+
+import java.util.Collection;
+import java.util.Stack;
+
+/**
+ * Wraps a notification header view.
+ */
+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;
+    private final int mIconDarkColor = 0xffffffff;
+    protected final ViewInvertHelper mInvertHelper;
+
+    protected final ViewTransformationHelper mTransformationHelper;
+
+    protected int mColor;
+    private ImageView mIcon;
+
+    private ImageView mExpandButton;
+    private NotificationHeaderView mNotificationHeader;
+
+    protected NotificationHeaderViewWrapper(Context ctx, View view) {
+        super(view);
+        mIconDarkAlpha = ctx.getResources().getInteger(R.integer.doze_small_icon_alpha);
+        mInvertHelper = new ViewInvertHelper(ctx, NotificationPanelView.DOZE_ANIMATION_DURATION);
+        mTransformationHelper = new ViewTransformationHelper();
+        resolveHeaderViews();
+        updateInvertHelper();
+    }
+
+    protected void resolveHeaderViews() {
+        mIcon = (ImageView) mView.findViewById(com.android.internal.R.id.icon);
+        mExpandButton = (ImageView) mView.findViewById(com.android.internal.R.id.expand_button);
+        mColor = resolveColor(mExpandButton);
+        mNotificationHeader = (NotificationHeaderView) mView.findViewById(
+                com.android.internal.R.id.notification_header);
+    }
+
+    private int resolveColor(ImageView icon) {
+        if (icon != null && icon.getDrawable() != null) {
+            ColorFilter filter = icon.getDrawable().getColorFilter();
+            if (filter instanceof PorterDuffColorFilter) {
+                return ((PorterDuffColorFilter) filter).getColor();
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    public void notifyContentUpdated(StatusBarNotification notification) {
+        super.notifyContentUpdated(notification);
+        // Reinspect the notification.
+        resolveHeaderViews();
+        updateInvertHelper();
+        updateTransformedTypes();
+        addRemainingTransformTypes();
+        updateCropToPaddingForImageViews();
+    }
+
+    /**
+     * Adds the remaining TransformTypes to the TransformHelper. This is done to make sure that each
+     * child is faded automatically and doesn't have to be manually added.
+     * The keys used for the views are the ids.
+     */
+    private void addRemainingTransformTypes() {
+        mTransformationHelper.addRemainingTransformTypes(mView);
+    }
+
+    /**
+     * Since we are deactivating the clipping when transforming the ImageViews don't get clipped
+     * anymore during these transitions. We can avoid that by using
+     * {@link ImageView#setCropToPadding(boolean)} on all ImageViews.
+     */
+    private void updateCropToPaddingForImageViews() {
+        Stack<View> stack = new Stack<>();
+        stack.push(mView);
+        while (!stack.isEmpty()) {
+            View child = stack.pop();
+            if (child instanceof ImageView) {
+                ((ImageView) child).setCropToPadding(true);
+            } else if (child instanceof ViewGroup){
+                ViewGroup group = (ViewGroup) child;
+                for (int i = 0; i < group.getChildCount(); i++) {
+                    stack.push(group.getChildAt(i));
+                }
+            }
+        }
+    }
+
+    protected void updateInvertHelper() {
+        mInvertHelper.clearTargets();
+        for (int i = 0; i < mNotificationHeader.getChildCount(); i++) {
+            View child = mNotificationHeader.getChildAt(i);
+            if (child != mIcon) {
+                mInvertHelper.addTarget(child);
+            }
+        }
+    }
+
+    protected void updateTransformedTypes() {
+        mTransformationHelper.reset();
+        mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_HEADER, mNotificationHeader);
+    }
+
+    @Override
+    public void setDark(boolean dark, boolean fade, long delay) {
+        if (dark == mDark) {
+            return;
+        }
+        super.setDark(dark, fade, delay);
+        if (fade) {
+            mInvertHelper.fade(dark, delay);
+        } else {
+            mInvertHelper.update(dark);
+        }
+        if (mIcon != null) {
+            boolean hadColorFilter = mNotificationHeader.getOriginalIconColor()
+                    != NotificationHeaderView.NO_COLOR;
+            if (fade) {
+                if (hadColorFilter) {
+                    fadeIconColorFilter(mIcon, dark, delay);
+                    fadeIconAlpha(mIcon, dark, delay);
+                } else {
+                    fadeGrayscale(mIcon, dark, delay);
+                }
+            } else {
+                if (hadColorFilter) {
+                    updateIconColorFilter(mIcon, dark);
+                    updateIconAlpha(mIcon, dark);
+                } else {
+                    updateGrayscale(mIcon, dark);
+                }
+            }
+        }
+    }
+
+    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
+            public void onAnimationUpdate(ValueAnimator animation) {
+                updateIconColorFilter(target, (Float) animation.getAnimatedValue());
+            }
+        }, dark, delay, null /* listener */);
+    }
+
+    private void fadeIconAlpha(final ImageView target, boolean dark, long delay) {
+        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float t = (float) animation.getAnimatedValue();
+                target.setImageAlpha((int) (255 * (1f - t) + mIconDarkAlpha * t));
+            }
+        }, dark, delay, null /* listener */);
+    }
+
+    protected void fadeGrayscale(final ImageView target, final boolean dark, long delay) {
+        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                updateGrayscaleMatrix((float) animation.getAnimatedValue());
+                target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
+            }
+        }, dark, delay, new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (!dark) {
+                    target.setColorFilter(null);
+                }
+            }
+        });
+    }
+
+    private void updateIconColorFilter(ImageView target, boolean dark) {
+        updateIconColorFilter(target, dark ? 1f : 0f);
+    }
+
+    private void updateIconColorFilter(ImageView target, float intensity) {
+        int color = interpolateColor(mColor, mIconDarkColor, intensity);
+        mIconColorFilter.setColor(color);
+        Drawable iconDrawable = target.getDrawable();
+
+        // Also, the notification might have been modified during the animation, so background
+        // might be null here.
+        if (iconDrawable != null) {
+            iconDrawable.mutate().setColorFilter(mIconColorFilter);
+        }
+    }
+
+    private void updateIconAlpha(ImageView target, boolean dark) {
+        target.setImageAlpha(dark ? mIconDarkAlpha : 255);
+    }
+
+    protected void updateGrayscale(ImageView target, boolean dark) {
+        if (dark) {
+            updateGrayscaleMatrix(1f);
+            target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
+        } else {
+            target.setColorFilter(null);
+        }
+    }
+
+    @Override
+    public void updateExpandability(boolean expandable, View.OnClickListener onClickListener) {
+        mExpandButton.setVisibility(expandable ? View.VISIBLE : View.GONE);
+        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);
+        int gSource = Color.green(source);
+        int bSource = Color.blue(source);
+        int aTarget = Color.alpha(target);
+        int rTarget = Color.red(target);
+        int gTarget = Color.green(target);
+        int bTarget = Color.blue(target);
+        return Color.argb(
+                (int) (aSource * (1f - t) + aTarget * t),
+                (int) (rSource * (1f - t) + rTarget * t),
+                (int) (gSource * (1f - t) + gTarget * t),
+                (int) (bSource * (1f - t) + bTarget * t));
+    }
+
+    @Override
+    public NotificationHeaderView getNotificationHeader() {
+        return mNotificationHeader;
+    }
+
+    @Override
+    public TransformState getCurrentState(int fadingView) {
+        return mTransformationHelper.getCurrentState(fadingView);
+    }
+
+    @Override
+    public void transformTo(TransformableView notification, Runnable endRunnable) {
+        mTransformationHelper.transformTo(notification, endRunnable);
+    }
+
+    @Override
+    public void transformFrom(TransformableView notification) {
+        mTransformationHelper.transformFrom(notification);
+    }
+
+    @Override
+    public void setVisible(boolean visible) {
+        super.setVisible(visible);
+        mTransformationHelper.setVisible(visible);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
new file mode 100644
index 0000000..9910dee
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Color;
+import android.service.notification.StatusBarNotification;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.android.systemui.statusbar.CrossFadeHelper;
+import com.android.systemui.statusbar.Interpolators;
+import com.android.systemui.statusbar.TransformableView;
+import com.android.systemui.statusbar.ViewTransformationHelper;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
+
+/**
+ * Wraps a notification view inflated from a template.
+ */
+public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapper {
+
+    private static final int mDarkProgressTint = 0xffffffff;
+
+    protected ImageView mPicture;
+    private ProgressBar mProgressBar;
+    private TextView mTitle;
+    private TextView mText;
+
+    protected NotificationTemplateViewWrapper(Context ctx, View view) {
+        super(ctx, view);
+        mTransformationHelper.setCustomTransformation(
+                new ViewTransformationHelper.CustomTransformation() {
+                    @Override
+                    public boolean transformTo(TransformState ownState,
+                            TransformableView notification, final Runnable endRunnable) {
+                        if (!(notification instanceof HybridNotificationView)) {
+                            return false;
+                        }
+                        TransformState otherState = notification.getCurrentState(
+                                TRANSFORMING_VIEW_TITLE);
+                        CrossFadeHelper.fadeOut(mText, endRunnable);
+                        if (otherState != null) {
+                            int[] otherStablePosition = otherState.getLaidOutLocationOnScreen();
+                            int[] ownPosition = ownState.getLaidOutLocationOnScreen();
+                            mText.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(mText,
+                                                    false);
+                                        }
+                                    });
+                            TransformState.setClippingDeactivated(mText, true);
+                            otherState.recycle();
+                        }
+                        return true;
+                    }
+
+                    @Override
+                    public boolean transformFrom(TransformState ownState,
+                            TransformableView notification) {
+                        if (!(notification instanceof HybridNotificationView)) {
+                            return false;
+                        }
+                        TransformState otherState = notification.getCurrentState(
+                                TRANSFORMING_VIEW_TITLE);
+                        boolean isVisible = mText.getVisibility() == View.VISIBLE;
+                        CrossFadeHelper.fadeIn(mText);
+                        if (otherState != null) {
+                            int[] otherStablePosition = otherState.getLaidOutLocationOnScreen();
+                            int[] ownStablePosition = ownState.getLaidOutLocationOnScreen();
+                            if (!isVisible) {
+                                mText.setTranslationY((otherStablePosition[1]
+                                        + otherState.getTransformedView().getHeight()
+                                        - ownStablePosition[1]) * 0.33f);
+                            }
+                            mText.animate()
+                                    .translationY(0)
+                                    .setDuration(
+                                            StackStateAnimator.ANIMATION_DURATION_STANDARD)
+                                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+                                    .withEndAction(new Runnable() {
+                                        @Override
+                                        public void run() {
+                                            TransformState.setClippingDeactivated(mText,
+                                                    false);
+                                        }
+                                    });
+                            TransformState.setClippingDeactivated(mText, true);
+                            otherState.recycle();
+                        }
+                        return true;
+                    }
+                }, TRANSFORMING_VIEW_TEXT);
+    }
+
+    private void resolveTemplateViews(StatusBarNotification notification) {
+        mPicture = (ImageView) mView.findViewById(com.android.internal.R.id.right_icon);
+        mPicture.setTag(ImageTransformState.ICON_TAG,
+                notification.getNotification().getLargeIcon());
+        mTitle = (TextView) mView.findViewById(com.android.internal.R.id.title);
+        mText = (TextView) mView.findViewById(com.android.internal.R.id.text);
+        final View progress = mView.findViewById(com.android.internal.R.id.progress);
+        if (progress instanceof ProgressBar) {
+            mProgressBar = (ProgressBar) progress;
+        } else {
+            // It's still a viewstub
+            mProgressBar = null;
+        }
+    }
+
+    @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.
+        resolveTemplateViews(notification);
+        super.notifyContentUpdated(notification);
+    }
+
+    @Override
+    protected void updateInvertHelper() {
+        super.updateInvertHelper();
+        View mainColumn = mView.findViewById(com.android.internal.R.id.notification_main_column);
+        if (mainColumn != null) {
+            mInvertHelper.addTarget(mainColumn);
+        }
+    }
+
+    @Override
+    protected void updateTransformedTypes() {
+        // This also clears the existing types
+        super.updateTransformedTypes();
+        if (mTitle != null) {
+            mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TITLE, mTitle);
+        }
+        if (mText != null) {
+            mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TEXT, mText);
+        }
+        if (mPicture != null) {
+            mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_IMAGE, mPicture);
+        }
+        if (mProgressBar != null) {
+            mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_PROGRESS, mProgressBar);
+        }
+    }
+
+    @Override
+    public void setDark(boolean dark, boolean fade, long delay) {
+        if (dark == mDark) {
+            return;
+        }
+        super.setDark(dark, fade, delay);
+        setPictureGrayscale(dark, fade, delay);
+        setProgressBarDark(dark, fade, delay);
+    }
+
+    private void setProgressBarDark(boolean dark, boolean fade, long delay) {
+        if (mProgressBar != null) {
+            if (fade) {
+                fadeProgressDark(mProgressBar, dark, delay);
+            } else {
+                updateProgressDark(mProgressBar, dark);
+            }
+        }
+    }
+
+    private void fadeProgressDark(final ProgressBar target, final boolean dark, long delay) {
+        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float t = (float) animation.getAnimatedValue();
+                updateProgressDark(target, t);
+            }
+        }, dark, delay, null /* listener */);
+    }
+
+    private void updateProgressDark(ProgressBar target, float intensity) {
+        int color = interpolateColor(mColor, mDarkProgressTint, intensity);
+        target.getIndeterminateDrawable().mutate().setTint(color);
+        target.getProgressDrawable().mutate().setTint(color);
+    }
+
+    private void updateProgressDark(ProgressBar target, boolean dark) {
+        updateProgressDark(target, dark ? 1f : 0f);
+    }
+
+    protected void setPictureGrayscale(boolean grayscale, boolean fade, long delay) {
+        if (mPicture != null) {
+            if (fade) {
+                fadeGrayscale(mPicture, grayscale, delay);
+            } else {
+                updateGrayscale(mPicture, grayscale);
+            }
+        }
+    }
+
+    private static int interpolateColor(int source, int target, float t) {
+        int aSource = Color.alpha(source);
+        int rSource = Color.red(source);
+        int gSource = Color.green(source);
+        int bSource = Color.blue(source);
+        int aTarget = Color.alpha(target);
+        int rTarget = Color.red(target);
+        int gTarget = Color.green(target);
+        int bTarget = Color.blue(target);
+        return Color.argb(
+                (int) (aSource * (1f - t) + aTarget * t),
+                (int) (rSource * (1f - t) + rTarget * t),
+                (int) (gSource * (1f - t) + gTarget * t),
+                (int) (bSource * (1f - t) + bTarget * t));
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
new file mode 100644
index 0000000..f50b976
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import android.content.Context;
+import android.service.notification.StatusBarNotification;
+import android.view.NotificationHeaderView;
+import android.view.View;
+
+import com.android.systemui.statusbar.CrossFadeHelper;
+import com.android.systemui.statusbar.TransformableView;
+
+/**
+ * Wraps the actual notification content view; used to implement behaviors which are different for
+ * the individual templates and custom views.
+ */
+public abstract class NotificationViewWrapper implements TransformableView {
+
+    protected final View mView;
+    protected boolean mDark;
+
+    public static NotificationViewWrapper wrap(Context ctx, View v) {
+        if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) {
+            if ("bigPicture".equals(v.getTag())) {
+                return new NotificationBigPictureTemplateViewWrapper(ctx, v);
+            }
+            return new NotificationTemplateViewWrapper(ctx, v);
+        } else if (v instanceof NotificationHeaderView) {
+            return new NotificationHeaderViewWrapper(ctx, v);
+        } else {
+            return new NotificationCustomViewWrapper(v);
+        }
+    }
+
+    protected NotificationViewWrapper(View view) {
+        mView = view;
+    }
+
+    /**
+     * In dark mode, we draw as little as possible, assuming a black background.
+     *
+     * @param dark whether we should display ourselves in dark mode
+     * @param fade whether to animate the transition if the mode changes
+     * @param delay if fading, the delay of the animation
+     */
+    public void setDark(boolean dark, boolean fade, long delay) {
+        mDark = dark;
+    }
+
+    /**
+     * Notifies this wrapper that the content of the view might have changed.
+     * @param notification
+     */
+    public void notifyContentUpdated(StatusBarNotification notification) {
+        mDark = false;
+    };
+
+    /**
+     * Update the appearance of the expand button.
+     *
+     * @param expandable should this view be expandable
+     * @param onClickListener the listener to invoke when the expand affordance is clicked on
+     */
+    public void updateExpandability(boolean expandable, View.OnClickListener onClickListener) {}
+
+    /**
+     * @return the notification header if it exists
+     */
+    public NotificationHeaderView getNotificationHeader() {
+        return null;
+    }
+
+    @Override
+    public TransformState getCurrentState(int fadingView) {
+        return null;
+    }
+
+    @Override
+    public void transformTo(TransformableView notification, Runnable endRunnable) {
+        // By default we are fading out completely
+        CrossFadeHelper.fadeOut(mView, endRunnable);
+    }
+
+    @Override
+    public void transformFrom(TransformableView notification) {
+        // By default we are fading in completely
+        CrossFadeHelper.fadeIn(mView);
+    }
+
+    @Override
+    public void setVisible(boolean visible) {
+        mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ProgressTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ProgressTransformState.java
new file mode 100644
index 0000000..bf78194
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ProgressTransformState.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.systemui.statusbar.notification;
+
+import android.util.Pools;
+
+/**
+ * A transform state of a progress view.
+*/
+public class ProgressTransformState extends TransformState {
+
+    private static Pools.SimplePool<ProgressTransformState> sInstancePool
+            = new Pools.SimplePool<>(40);
+
+    @Override
+    protected boolean sameAs(TransformState otherState) {
+        if (otherState instanceof ProgressTransformState) {
+            return true;
+        }
+        return super.sameAs(otherState);
+    }
+
+    public static ProgressTransformState obtain() {
+        ProgressTransformState instance = sInstancePool.acquire();
+        if (instance != null) {
+            return instance;
+        }
+        return new ProgressTransformState();
+    }
+
+    @Override
+    public void recycle() {
+        super.recycle();
+        sInstancePool.release(this);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
new file mode 100644
index 0000000..5ab441d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.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.systemui.statusbar.notification;
+
+import android.text.TextUtils;
+import android.util.Pools;
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * A transform state of a mText view.
+*/
+public class TextViewTransformState extends TransformState {
+
+    private static Pools.SimplePool<TextViewTransformState> sInstancePool
+            = new Pools.SimplePool<>(40);
+    private CharSequence mText;
+
+    @Override
+    public void initFrom(View view) {
+        super.initFrom(view);
+        if (view instanceof TextView) {
+            TextView txt = (TextView) view;
+            mText = txt.getText();
+        }
+    }
+
+    @Override
+    protected boolean sameAs(TransformState otherState) {
+        if (otherState instanceof TextViewTransformState) {
+            TextViewTransformState otherTvs = (TextViewTransformState) otherState;
+            return TextUtils.equals(otherTvs.mText, mText);
+        }
+        return super.sameAs(otherState);
+    }
+
+    public static TextViewTransformState obtain() {
+        TextViewTransformState instance = sInstancePool.acquire();
+        if (instance != null) {
+            return instance;
+        }
+        return new TextViewTransformState();
+    }
+
+    @Override
+    public void recycle() {
+        super.recycle();
+        sInstancePool.release(this);
+    }
+
+    @Override
+    protected void reset() {
+        super.reset();
+        mText = 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
new file mode 100644
index 0000000..3e1c40a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.util.ArraySet;
+import android.util.Pools;
+import android.view.NotificationHeaderView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.CrossFadeHelper;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.Interpolators;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
+
+/**
+ * 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 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 Pools.SimplePool<TransformState> sInstancePool = new Pools.SimplePool<>(40);
+
+    protected View mTransformedView;
+    private int[] mOwnPosition = new int[2];
+
+    public void initFrom(View view) {
+        mTransformedView = view;
+    }
+
+    /**
+     * Transforms the {@link #mTransformedView} from the given transformviewstate
+     * @param otherState the state to transform from
+     */
+    public void transformViewFrom(TransformState otherState) {
+        mTransformedView.animate().cancel();
+        if (sameAs(otherState)) {
+            // We have the same content, lets show ourselves
+            mTransformedView.setAlpha(1.0f);
+            mTransformedView.setVisibility(View.VISIBLE);
+        } else {
+            CrossFadeHelper.fadeIn(mTransformedView);
+        }
+        animateViewFrom(otherState);
+    }
+
+    public void animateViewFrom(TransformState otherState) {
+        animateViewFrom(otherState, ANIMATE_ALL);
+    }
+
+    public void animateViewVerticalFrom(TransformState otherState) {
+        animateViewFrom(otherState, ANIMATE_Y);
+    }
+
+    private void animateViewFrom(TransformState otherState, int animationFlags) {
+        final View transformedView = mTransformedView;
+        // 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 (otherView.getHeight() != transformedView.getHeight()) {
+                float scaleY = (otherView.getHeight() * otherView.getScaleY()
+                        / (float) transformedView.getHeight());
+                transformedView.setScaleY(scaleY);
+                transformedView.setPivotY(0);
+                transformedView.animate().scaleY(1.0f);
+            }
+        }
+        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() {
+        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
+     * @return whether an animation was started
+     */
+    public boolean transformViewTo(TransformState otherState, final Runnable endRunnable) {
+        mTransformedView.animate().cancel();
+        if (sameAs(otherState)) {
+            // We have the same text, lets show ourselfs
+            mTransformedView.setAlpha(0.0f);
+            mTransformedView.setVisibility(View.INVISIBLE);
+            return false;
+        } else {
+            CrossFadeHelper.fadeOut(mTransformedView, endRunnable);
+        }
+        animateViewTo(otherState, endRunnable);
+        return true;
+    }
+
+    public void animateViewTo(TransformState otherState, Runnable endRunnable) {
+        animateViewTo(otherState, endRunnable, ANIMATE_ALL);
+    }
+
+    public void animateViewVerticalTo(TransformState otherState, Runnable endRunnable) {
+        animateViewTo(otherState, endRunnable, ANIMATE_Y);
+    }
+
+    private void animateViewTo(TransformState otherState, final Runnable endRunnable,
+            int animationFlags) {
+        // lets animate the positions correctly
+        int[] otherStablePosition = otherState.getLaidOutLocationOnScreen();
+        int[] ownPosition = getLaidOutLocationOnScreen();
+        final View transformedView = mTransformedView;
+        if ((animationFlags & ANIMATE_X) != 0) {
+            transformedView.animate()
+                    .translationX(otherStablePosition[0] - ownPosition[0]);
+        }
+        if ((animationFlags & ANIMATE_Y) != 0) {
+            transformedView.animate()
+                    .translationY(otherStablePosition[1] - ownPosition[1]);
+        }
+        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);
+    }
+
+    public static void setClippingDeactivated(final View transformedView, boolean deactivated) {
+        ViewGroup view = (ViewGroup) transformedView.getParent();
+        while (true) {
+            ArraySet<View> clipSet = (ArraySet<View>) view.getTag(CLIP_CLIPPING_SET);
+            if (clipSet == null) {
+                clipSet = new ArraySet<>();
+                view.setTag(CLIP_CLIPPING_SET, clipSet);
+            }
+            Boolean clipChildren = (Boolean) view.getTag(CLIP_CHILDREN_TAG);
+            if (clipChildren == null) {
+                clipChildren = view.getClipChildren();
+                view.setTag(CLIP_CHILDREN_TAG, clipChildren);
+            }
+            Boolean clipToPadding = (Boolean) view.getTag(CLIP_TO_PADDING);
+            if (clipToPadding == null) {
+                clipToPadding = view.getClipToPadding();
+                view.setTag(CLIP_TO_PADDING, clipToPadding);
+            }
+            ExpandableNotificationRow row = view instanceof ExpandableNotificationRow
+                    ? (ExpandableNotificationRow) view
+                    : null;
+            if (!deactivated) {
+                clipSet.remove(transformedView);
+                if (clipSet.isEmpty()) {
+                    view.setClipChildren(clipChildren);
+                    view.setClipToPadding(clipToPadding);
+                    view.setTag(CLIP_CLIPPING_SET, null);
+                    if (row != null) {
+                        row.setClipToActualHeight(true);
+                    }
+                }
+            } else {
+                clipSet.add(transformedView);
+                view.setClipChildren(false);
+                view.setClipToPadding(false);
+                if (row != null && row.isChildInGroup()) {
+                    // We still want to clip to the parent's height
+                    row.setClipToActualHeight(false);
+                }
+            }
+            if (row != null && !row.isChildInGroup()) {
+                return;
+            }
+            final ViewParent parent = view.getParent();
+            if (parent instanceof ViewGroup) {
+                view = (ViewGroup) parent;
+            } else {
+                return;
+            }
+        }
+    }
+
+    public int[] getLaidOutLocationOnScreen() {
+        int[] location = getLocationOnScreen();
+        location[0] -= mTransformedView.getTranslationX();
+        location[1] -= mTransformedView.getTranslationY();
+        return location;
+    }
+
+    public int[] getLocationOnScreen() {
+        mTransformedView.getLocationOnScreen(mOwnPosition);
+        return mOwnPosition;
+    }
+
+    protected boolean sameAs(TransformState otherState) {
+        return false;
+    }
+
+    public static TransformState createFrom(View view) {
+        if (view instanceof TextView) {
+            TextViewTransformState result = TextViewTransformState.obtain();
+            result.initFrom(view);
+            return result;
+        }
+        if (view instanceof NotificationHeaderView) {
+            HeaderTransformState result = HeaderTransformState.obtain();
+            result.initFrom(view);
+            return result;
+        }
+        if (view instanceof ImageView) {
+            ImageTransformState result = ImageTransformState.obtain();
+            result.initFrom(view);
+            return result;
+        }
+        if (view instanceof ProgressBar) {
+            ProgressTransformState result = ProgressTransformState.obtain();
+            result.initFrom(view);
+            return result;
+        }
+        TransformState result = obtain();
+        result.initFrom(view);
+        return result;
+    }
+
+    public void recycle() {
+        reset();
+        if (getClass() == TransformState.class) {
+            sInstancePool.release(this);
+        }
+    }
+
+    protected void reset() {
+        mTransformedView = null;
+    }
+
+    public void setVisible(boolean visible) {
+        mTransformedView.animate().cancel();
+        mTransformedView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+        mTransformedView.setAlpha(visible ? 1.0f : 0.0f);
+        if (visible) {
+            mTransformedView.setTranslationX(0);
+            mTransformedView.setTranslationY(0);
+            mTransformedView.setScaleX(1.0f);
+            mTransformedView.setScaleY(1.0f);
+        }
+    }
+
+    public void prepareFadeIn() {
+    }
+
+    public static TransformState obtain() {
+        TransformState instance = sInstancePool.acquire();
+        if (instance != null) {
+            return instance;
+        }
+        return new TransformState();
+    }
+
+    public View getTransformedView() {
+        return mTransformedView;
+    }
+}
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 a3f404a..37e5558 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -32,6 +32,7 @@
 import android.view.animation.LinearInterpolator;
 
 import com.android.systemui.R;
+import com.android.systemui.statusbar.Interpolators;
 
 public class BarTransitions {
     private static final boolean DEBUG = false;
@@ -124,7 +125,6 @@
         private final int mTransparent;
         private final int mWarning;
         private final Drawable mGradient;
-        private final TimeInterpolator mInterpolator;
 
         private int mMode = -1;
         private boolean mAnimating;
@@ -152,7 +152,6 @@
                 mWarning = context.getColor(com.android.internal.R.color.battery_saver_mode_color);
             }
             mGradient = context.getDrawable(gradientResourceId);
-            mInterpolator = new LinearInterpolator();
         }
 
         @Override
@@ -222,7 +221,8 @@
                     mGradientAlpha = targetGradientAlpha;
                 } else {
                     final float t = (now - mStartTime) / (float)(mEndTime - mStartTime);
-                    final float v = Math.max(0, Math.min(mInterpolator.getInterpolation(t), 1));
+                    final float v = Math.max(0, Math.min(
+                            Interpolators.LINEAR.getInterpolation(t), 1));
                     mGradientAlpha = (int)(v * targetGradientAlpha + mGradientAlphaStart * (1 - v));
                     mColor = Color.argb(
                           (int)(v * Color.alpha(targetColor) + Color.alpha(mColorStart) * (1 - v)),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
new file mode 100644
index 0000000..aea9e1e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import com.android.systemui.statusbar.policy.KeyButtonView;
+
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.widget.ImageView;
+
+import java.util.ArrayList;
+
+/**
+ * Dispatches common view calls to multiple views.  This is used to handle
+ * multiples of the same nav bar icon appearing.
+ */
+public class ButtonDispatcher {
+
+    private final ArrayList<View> mViews = new ArrayList<>();
+
+    private final int mId;
+
+    private View.OnClickListener mClickListener;
+    private View.OnTouchListener mTouchListener;
+    private View.OnLongClickListener mLongClickListener;
+    private Boolean mLongClickable;
+    private Integer mAlpha;
+    private Integer mVisibility = -1;
+    private int mImageResource = -1;
+    private Drawable mImageDrawable;
+    private View mCurrentView;
+
+    public ButtonDispatcher(int id) {
+        mId = id;
+    }
+
+    void clear() {
+        mViews.clear();
+    }
+
+    void addView(View view) {
+        mViews.add(view);
+        view.setOnClickListener(mClickListener);
+        view.setOnTouchListener(mTouchListener);
+        view.setOnLongClickListener(mLongClickListener);
+        if (mLongClickable != null) {
+            view.setLongClickable(mLongClickable);
+        }
+        if (mAlpha != null) {
+            view.setAlpha(mAlpha);
+        }
+        if (mVisibility != null) {
+            view.setVisibility(mVisibility);
+        }
+        if (mImageResource > 0) {
+            ((ImageView) view).setImageResource(mImageResource);
+        } else if (mImageDrawable != null) {
+            ((ImageView) view).setImageDrawable(mImageDrawable);
+        }
+    }
+
+    public int getId() {
+        return mId;
+    }
+
+    public int getVisibility() {
+        return mVisibility != null ? mVisibility : View.VISIBLE;
+    }
+
+    public float getAlpha() {
+        return mAlpha != null ? mAlpha : 1;
+    }
+
+    public void setImageDrawable(Drawable drawable) {
+        mImageDrawable = drawable;
+        mImageResource = -1;
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            ((ImageView) mViews.get(i)).setImageDrawable(mImageDrawable);
+        }
+    }
+
+    public void setImageResource(int resource) {
+        mImageResource = resource;
+        mImageDrawable = null;
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            ((ImageView) mViews.get(i)).setImageResource(mImageResource);
+        }
+    }
+
+    public void setVisibility(int visibility) {
+        if (mVisibility == visibility) return;
+        mVisibility = visibility;
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            mViews.get(i).setVisibility(mVisibility);
+        }
+    }
+
+    public void abortCurrentGesture() {
+        // This seems to be an instantaneous thing, so not going to persist it.
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            ((KeyButtonView) mViews.get(i)).abortCurrentGesture();
+        }
+    }
+
+    public void setAlpha(int alpha) {
+        mAlpha = alpha;
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            mViews.get(i).setAlpha(alpha);
+        }
+    }
+
+    public void setOnClickListener(View.OnClickListener clickListener) {
+        mClickListener = clickListener;
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            mViews.get(i).setOnClickListener(mClickListener);
+        }
+    }
+
+    public void setOnTouchListener(View.OnTouchListener touchListener) {
+        mTouchListener = touchListener;
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            mViews.get(i).setOnTouchListener(mTouchListener);
+        }
+    }
+
+    public void setLongClickable(boolean isLongClickable) {
+        mLongClickable = isLongClickable;
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            mViews.get(i).setLongClickable(mLongClickable);
+        }
+    }
+
+    public void setOnLongClickListener(View.OnLongClickListener longClickListener) {
+        mLongClickListener = longClickListener;
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            mViews.get(i).setOnLongClickListener(mLongClickListener);
+        }
+    }
+
+    public View getCurrentView() {
+        return mCurrentView;
+    }
+
+    public void setCurrentView(View currentView) {
+        mCurrentView = currentView.findViewById(mId);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index 4f57906..a444934 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -83,7 +83,7 @@
             if (location != null) {
                 int iconId = location.equals("show") ? LocationControllerImpl.LOCATION_STATUS_ICON_ID
                         : 0;
-                updateSlot(LocationControllerImpl.LOCATION_STATUS_ICON_PLACEHOLDER, null, iconId);
+                updateSlot("location", null, iconId);
             }
             String alarm = args.getString("alarm");
             if (alarm != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 3ff69c9..b5dba18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -23,11 +23,11 @@
 import android.content.Context;
 import android.os.Handler;
 import android.util.Log;
-import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
+import com.android.systemui.statusbar.Interpolators;
 
 /**
  * Controller which handles all the doze animations of the scrims.
@@ -37,10 +37,6 @@
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private final DozeParameters mDozeParameters;
-    private final Interpolator mPulseInInterpolator = PhoneStatusBar.ALPHA_OUT;
-    private final Interpolator mPulseInInterpolatorPickup;
-    private final Interpolator mPulseOutInterpolator = PhoneStatusBar.ALPHA_IN;
-    private final Interpolator mDozeAnimationInterpolator;
     private final Handler mHandler = new Handler();
     private final ScrimController mScrimController;
 
@@ -55,8 +51,6 @@
     public DozeScrimController(ScrimController scrimController, Context context) {
         mScrimController = scrimController;
         mDozeParameters = new DozeParameters(context);
-        mDozeAnimationInterpolator = mPulseInInterpolatorPickup =
-                AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in);
     }
 
     public void setDozing(boolean dozing, boolean animate) {
@@ -70,9 +64,11 @@
             cancelPulsing();
             if (animate) {
                 startScrimAnimation(false /* inFront */, 0f /* target */,
-                        NotificationPanelView.DOZE_ANIMATION_DURATION, mDozeAnimationInterpolator);
+                        NotificationPanelView.DOZE_ANIMATION_DURATION,
+                        Interpolators.LINEAR_OUT_SLOW_IN);
                 startScrimAnimation(true /* inFront */, 0f /* target */,
-                        NotificationPanelView.DOZE_ANIMATION_DURATION, mDozeAnimationInterpolator);
+                        NotificationPanelView.DOZE_ANIMATION_DURATION,
+                        Interpolators.LINEAR_OUT_SLOW_IN);
             } else {
                 abortAnimations();
                 mScrimController.setDozeBehindAlpha(0f);
@@ -116,7 +112,7 @@
             final boolean pickup = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
             startScrimAnimation(true /* inFront */, 0f,
                     mDozeParameters.getPulseInDuration(pickup),
-                    pickup ? mPulseInInterpolatorPickup : mPulseInInterpolator,
+                    pickup ? Interpolators.LINEAR_OUT_SLOW_IN : Interpolators.ALPHA_OUT,
                     mPulseInFinished);
         }
     }
@@ -266,7 +262,7 @@
             if (DEBUG) Log.d(TAG, "Pulse out, mDozing=" + mDozing);
             if (!mDozing) return;
             startScrimAnimation(true /* inFront */, 1f, mDozeParameters.getPulseOutDuration(),
-                    mPulseOutInterpolator, mPulseOutFinished);
+                    Interpolators.ALPHA_IN, mPulseOutFinished);
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/GetActivityIconTask.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/GetActivityIconTask.java
deleted file mode 100644
index d2bec7c..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/GetActivityIconTask.java
+++ /dev/null
@@ -1,113 +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.phone;
-
-import android.app.AppGlobals;
-import android.content.pm.ActivityInfo;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Typeface;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.AsyncTask;
-import android.os.RemoteException;
-import android.util.Slog;
-import android.widget.ImageView;
-
-/**
- * Retrieves the icon for an activity and sets it as the Drawable on an ImageView. The ImageView
- * is hidden if the activity isn't recognized or if there is no icon.
- */
-class GetActivityIconTask extends AsyncTask<AppButtonData, Void, Drawable> {
-    private final static String TAG = "GetActivityIconTask";
-
-    private final PackageManager mPackageManager;
-
-    // The ImageView that will receive the icon.
-    private final ImageView mImageView;
-
-    public GetActivityIconTask(PackageManager packageManager, ImageView imageView) {
-        mPackageManager = packageManager;
-        mImageView = imageView;
-    }
-
-    @Override
-    protected Drawable doInBackground(AppButtonData... params) {
-        if (params.length != 1) {
-            throw new IllegalArgumentException("Expected one parameter");
-        }
-        AppButtonData buttonData = params[0];
-        AppInfo appInfo = buttonData.appInfo;
-        try {
-            IPackageManager mPM = AppGlobals.getPackageManager();
-            ActivityInfo ai = mPM.getActivityInfo(
-                    appInfo.getComponentName(),
-                    0,
-                    appInfo.getUser().getIdentifier());
-
-            if (ai == null) {
-                Slog.w(TAG, "Icon not found for " + appInfo);
-                return null;
-            }
-
-            Drawable unbadgedIcon = ai.loadIcon(mPackageManager);
-            Drawable badgedIcon =
-                    mPackageManager.getUserBadgedIcon(unbadgedIcon, appInfo.getUser());
-
-            if (NavigationBarApps.DEBUG) {
-                // Draw pinned indicator and number of running tasks.
-                Bitmap bitmap = Bitmap.createBitmap(
-                        badgedIcon.getIntrinsicWidth(),
-                        badgedIcon.getIntrinsicHeight(),
-                        Bitmap.Config.ARGB_8888);
-                Canvas canvas = new Canvas(bitmap);
-                badgedIcon.setBounds(
-                        0, 0, badgedIcon.getIntrinsicWidth(), badgedIcon.getIntrinsicHeight());
-                badgedIcon.draw(canvas);
-                Paint paint = new Paint();
-                paint.setStyle(Paint.Style.FILL);
-                if (buttonData.pinned) {
-                    paint.setColor(Color.WHITE);
-                    canvas.drawCircle(10, 10, 10, paint);
-                }
-                if (buttonData.tasks != null && buttonData.tasks.size() > 0) {
-                    paint.setColor(Color.BLACK);
-                    canvas.drawCircle(60, 30, 30, paint);
-                    paint.setColor(Color.WHITE);
-                    paint.setTextSize(50);
-                    paint.setTypeface(Typeface.create("sans-serif", Typeface.BOLD));
-                    canvas.drawText(Integer.toString(buttonData.tasks.size()), 50, 50, paint);
-                }
-                badgedIcon = new BitmapDrawable(null, bitmap);
-            }
-
-            return  badgedIcon;
-        } catch (RemoteException e) {
-            Slog.w(TAG, "Icon not found for " + appInfo, e);
-            return null;
-        }
-    }
-
-    @Override
-    protected void onPostExecute(Drawable icon) {
-        mImageView.setImageDrawable(icon);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index df8c7fa..e7064e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -43,7 +43,6 @@
     private boolean mCollapseSnoozes;
     private NotificationPanelView mPanel;
     private ExpandableNotificationRow mPickedChild;
-    private final int mNotificationsTopPadding;
 
     public HeadsUpTouchHelper(HeadsUpManager headsUpManager,
             NotificationStackScrollLayout stackScroller,
@@ -54,8 +53,6 @@
         Context context = stackScroller.getContext();
         final ViewConfiguration configuration = ViewConfiguration.get(context);
         mTouchSlop = configuration.getScaledTouchSlop();
-        mNotificationsTopPadding = context.getResources()
-                .getDimensionPixelSize(R.dimen.notifications_top_padding);
     }
 
     public boolean isTrackingHeadsUp() {
@@ -80,10 +77,6 @@
                 mInitialTouchX = x;
                 setTrackingHeadsUp(false);
                 ExpandableView child = mStackScroller.getChildAtRawPosition(x, y);
-                if (child == null && y < mNotificationsTopPadding) {
-                    // We should also allow drags from the margin above the heads up
-                    child = mStackScroller.getChildAtRawPosition(x, y + mNotificationsTopPadding);
-                }
                 mTouchingHeadsUpView = false;
                 if (child instanceof ExpandableNotificationRow) {
                     mPickedChild = (ExpandableNotificationRow) child;
@@ -110,12 +103,11 @@
                     mInitialTouchX = x;
                     mInitialTouchY = y;
                     int expandedHeight = mPickedChild.getActualHeight();
+                    mHeadsUpManager.unpinAll();
                     mPanel.setPanelScrimMinFraction((float) expandedHeight
                             / mPanel.getMaxPanelHeight());
-                    mPanel.startExpandMotion(x, y, true /* startTracking */, expandedHeight
-                            + mNotificationsTopPadding);
+                    mPanel.startExpandMotion(x, y, true /* startTracking */, expandedHeight);
                     mPanel.clearNotificattonEffects();
-                    mHeadsUpManager.unpinAll();
                     return true;
                 }
                 break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index 41adeb5..c220efe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -24,12 +24,11 @@
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewConfiguration;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
 
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.statusbar.FlingAnimationUtils;
+import com.android.systemui.statusbar.Interpolators;
 import com.android.systemui.statusbar.KeyguardAffordanceView;
 
 /**
@@ -60,8 +59,6 @@
     private KeyguardAffordanceView mLeftIcon;
     private KeyguardAffordanceView mCenterIcon;
     private KeyguardAffordanceView mRightIcon;
-    private Interpolator mAppearInterpolator;
-    private Interpolator mDisappearInterpolator;
     private Animator mSwipeAnimator;
     private FalsingManager mFalsingManager;
     private int mMinBackgroundRadius;
@@ -107,10 +104,6 @@
         mHintGrowAmount =
                 mContext.getResources().getDimensionPixelSize(R.dimen.hint_grow_amount_sideways);
         mFlingAnimationUtils = new FlingAnimationUtils(mContext, 0.4f);
-        mAppearInterpolator = AnimationUtils.loadInterpolator(mContext,
-                android.R.interpolator.linear_out_slow_in);
-        mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext,
-                android.R.interpolator.fast_out_linear_in);
         mFalsingManager = FalsingManager.getInstance(mContext);
     }
 
@@ -272,7 +265,7 @@
                 }
             }
         });
-        animator.setInterpolator(mAppearInterpolator);
+        animator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
         animator.setDuration(HINT_PHASE1_DURATION);
         animator.start();
         mSwipeAnimator = animator;
@@ -292,7 +285,7 @@
                 onFinishedListener.run();
             }
         });
-        animator.setInterpolator(mDisappearInterpolator);
+        animator.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
         animator.setDuration(HINT_PHASE2_DURATION);
         animator.setStartDelay(HINT_CIRCLE_OPEN_DURATION);
         animator.start();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 14176a6..94d3829 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -58,6 +58,7 @@
 import com.android.systemui.R;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.Interpolators;
 import com.android.systemui.statusbar.KeyguardAffordanceView;
 import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.policy.AccessibilityController;
@@ -111,7 +112,6 @@
     private AccessibilityController mAccessibilityController;
     private PhoneStatusBar mPhoneStatusBar;
 
-    private final Interpolator mLinearOutSlowInInterpolator;
     private boolean mUserSetupComplete;
     private boolean mPrewarmBound;
     private Messenger mPrewarmMessenger;
@@ -146,8 +146,6 @@
     public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        mLinearOutSlowInInterpolator =
-                AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in);
     }
 
     private AccessibilityDelegate mAccessibilityDelegate = new AccessibilityDelegate() {
@@ -600,7 +598,7 @@
         mIndicationText.setAlpha(0f);
         mIndicationText.animate()
                 .alpha(1f)
-                .setInterpolator(mLinearOutSlowInInterpolator)
+                .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
                 .setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
     }
 
@@ -610,7 +608,7 @@
         element.animate()
                 .alpha(1f)
                 .translationY(0f)
-                .setInterpolator(mLinearOutSlowInInterpolator)
+                .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
                 .setStartDelay(delay)
                 .setDuration(DOZE_ANIMATION_ELEMENT_DURATION);
     }
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 99436a1..347ba3d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -41,13 +41,13 @@
  */
 public class KeyguardBouncer {
 
-    private Context mContext;
-    private ViewMediatorCallback mCallback;
-    private LockPatternUtils mLockPatternUtils;
-    private ViewGroup mContainer;
+    protected Context mContext;
+    protected ViewMediatorCallback mCallback;
+    protected LockPatternUtils mLockPatternUtils;
+    protected ViewGroup mContainer;
     private StatusBarWindowManager mWindowManager;
-    private KeyguardHostView mKeyguardView;
-    private ViewGroup mRoot;
+    protected KeyguardHostView mKeyguardView;
+    protected ViewGroup mRoot;
     private boolean mShowingSoon;
     private int mBouncerPromptReason;
     private FalsingManager mFalsingManager;
@@ -134,7 +134,7 @@
     public void hide(boolean destroyView) {
         mFalsingManager.onBouncerHidden();
         cancelShowRunnable();
-         if (mKeyguardView != null) {
+        if (mKeyguardView != null) {
             mKeyguardView.cancelDismissAction();
             mKeyguardView.cleanUp();
         }
@@ -184,13 +184,13 @@
         mBouncerPromptReason = mCallback.getBouncerPromptReason();
     }
 
-    private void ensureView() {
+    protected void ensureView() {
         if (mRoot == null) {
             inflateView();
         }
     }
 
-    private void inflateView() {
+    protected void inflateView() {
         removeView();
         mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null);
         mKeyguardView = (KeyguardHostView) mRoot.findViewById(R.id.keyguard_host_view);
@@ -201,7 +201,7 @@
         mRoot.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME);
     }
 
-    private void removeView() {
+    protected void removeView() {
         if (mRoot != null && mRoot.getParent() == mContainer) {
             mContainer.removeView(mRoot);
             mRoot = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index b93fc76..e67aa84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -23,14 +23,13 @@
 import android.util.TypedValue;
 import android.view.View;
 import android.view.ViewTreeObserver;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
 import android.widget.ImageView;
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.Interpolators;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 import com.android.systemui.statusbar.policy.UserInfoController;
@@ -58,7 +57,6 @@
     private KeyguardUserSwitcher mKeyguardUserSwitcher;
 
     private int mSystemIconsSwitcherHiddenExpandedMargin;
-    private Interpolator mFastOutSlowInInterpolator;
 
     public KeyguardStatusBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -73,8 +71,6 @@
         mBatteryLevel = (TextView) findViewById(R.id.battery_level);
         mCarrierLabel = (TextView) findViewById(R.id.keyguard_carrier_text);
         loadDimens();
-        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
-                android.R.interpolator.fast_out_slow_in);
         updateUserSwitcher();
     }
 
@@ -166,7 +162,7 @@
     }
 
     @Override
-    public void onPowerSaveChanged() {
+    public void onPowerSaveChanged(boolean isPowerSave) {
         // could not care less
     }
 
@@ -199,7 +195,7 @@
                         .translationX(0)
                         .setDuration(400)
                         .setStartDelay(userSwitcherHiding ? 300 : 0)
-                        .setInterpolator(mFastOutSlowInInterpolator)
+                        .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
                         .start();
                 if (userSwitcherHiding) {
                     getOverlay().add(mMultiUserSwitch);
@@ -207,7 +203,7 @@
                             .alpha(0f)
                             .setDuration(300)
                             .setStartDelay(0)
-                            .setInterpolator(PhoneStatusBar.ALPHA_OUT)
+                            .setInterpolator(Interpolators.ALPHA_OUT)
                             .withEndAction(new Runnable() {
                                 @Override
                                 public void run() {
@@ -223,7 +219,7 @@
                             .alpha(1f)
                             .setDuration(300)
                             .setStartDelay(200)
-                            .setInterpolator(PhoneStatusBar.ALPHA_IN);
+                            .setInterpolator(Interpolators.ALPHA_IN);
                 }
                 return true;
             }
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 71267cd..8717a15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -65,6 +65,10 @@
         setUserSwitcherController(qsPanel.getHost().getUserSwitcherController());
     }
 
+    public boolean hasMultipleUsers() {
+        return mUserListener.getCount() != 0;
+    }
+
     public void setUserSwitcherController(UserSwitcherController userSwitcherController) {
         mUserSwitcherController = userSwitcherController;
         registerListener();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
deleted file mode 100644
index 58c9722..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
+++ /dev/null
@@ -1,1115 +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.phone;
-
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-
-import android.animation.LayoutTransition;
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.ActivityManager.RecentTaskInfo;
-import android.app.ActivityManagerNative;
-import android.app.ActivityOptions;
-import android.app.IActivityManager;
-import android.app.ITaskStackListener;
-import android.content.BroadcastReceiver;
-import android.content.ClipData;
-import android.content.ClipDescription;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.DragEvent;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.PopupMenu;
-import android.widget.Toast;
-
-import com.android.internal.content.PackageMonitor;
-import com.android.systemui.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Container for application icons that appear in the navigation bar. Their appearance is similar
- * to the launcher hotseat. Clicking an icon launches or activates the associated activity. A long
- * click will trigger a drag to allow the icons to be reordered. As an icon is dragged the other
- * icons shift to make space for it to be dropped. These layout changes are animated.
- * Navigation bar contains both pinned and unpinned apps: pinned in the left part, unpinned in the
- * right part, with no separator in between.
- */
-class NavigationBarApps extends LinearLayout
-        implements NavigationBarAppsModel.OnAppsChangedListener {
-    public final static boolean DEBUG = false;
-    private final static String TAG = "NavigationBarApps";
-
-    /**
-     * Intent extra to store user serial number.
-     */
-    static final String EXTRA_PROFILE = "profile";
-
-    // There are separate NavigationBarApps view instances for landscape vs. portrait, but they
-    // share the data model.
-    private static NavigationBarAppsModel sAppsModel;
-
-    private final PackageManager mPackageManager;
-    private final UserManager mUserManager;
-    private final LayoutInflater mLayoutInflater;
-    private final AppPackageMonitor mAppPackageMonitor;
-    private final WindowManager mWindowManager;
-
-
-    // This view has two roles:
-    // 1) If the drag started outside the pinned apps list, it is a placeholder icon with a null
-    // tag.
-    // 2) If the drag started inside the pinned apps list, it is the icon for the app being dragged
-    // with the associated AppInfo tag.
-    // The icon is set invisible for the duration of the drag, creating a visual space for a drop.
-    // When the user is not dragging this member is null.
-    private ImageView mDragView;
-
-    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-                int currentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
-                onUserSwitched(currentUserId);
-            } else if (Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
-                UserHandle removedProfile = intent.getParcelableExtra(Intent.EXTRA_USER);
-                onManagedProfileRemoved(removedProfile);
-            }
-        }
-    };
-
-    // Layout params for the window that contains the anchor for the popup menus.
-    // We need to create a window for a popup menu because the NavBar window is too narrow and can't
-    // contain the menu.
-    private final WindowManager.LayoutParams mPopupAnchorLayoutParams;
-    // View that contains the anchor for popup menus. The view occupies the whole screen, and
-    // has a child that will be moved to make the menu to appear where we need it.
-    private final ViewGroup mPopupAnchor;
-    private final PopupMenu mPopupMenu;
-
-    /**
-     * True if popup menu code is busy with a popup operation.
-     * Attempting  to show a popup menu or to add menu items while it's returning true will
-     * corrupt/crash the app.
-     */
-    private boolean mIsPopupInUse = false;
-    private final int [] mClickedIconLocation = new int[2];
-
-    public NavigationBarApps(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        if (sAppsModel == null) {
-            sAppsModel = new NavigationBarAppsModel(context);
-        }
-        mPackageManager = context.getPackageManager();
-        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
-        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-        mLayoutInflater = LayoutInflater.from(context);
-        mAppPackageMonitor = new AppPackageMonitor();
-
-        // Dragging an icon removes and adds back the dragged icon. Use the layout transitions to
-        // trigger animation. By default all transitions animate, so turn off the unneeded ones.
-        LayoutTransition transition = new LayoutTransition();
-        // Don't trigger on disappear. Adding the view will trigger the layout animation.
-        transition.disableTransitionType(LayoutTransition.DISAPPEARING);
-        // Don't animate the dragged icon itself.
-        transition.disableTransitionType(LayoutTransition.APPEARING);
-        // When an icon is dragged off the shelf, start sliding the other icons over immediately
-        // to match the parent view's animation.
-        transition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);
-        transition.setStagger(LayoutTransition.CHANGE_DISAPPEARING, 0);
-        setLayoutTransition(transition);
-
-        TaskStackListener taskStackListener = new TaskStackListener();
-        IActivityManager iam = ActivityManagerNative.getDefault();
-        try {
-            iam.registerTaskStackListener(taskStackListener);
-        } catch (RemoteException e) {
-            Slog.e(TAG, "registerTaskStackListener failed", e);
-        }
-
-        mPopupAnchorLayoutParams =
-                new WindowManager.LayoutParams(
-                        ViewGroup.LayoutParams.MATCH_PARENT,
-                        ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
-                        WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY,
-                        WindowManager.LayoutParams.FLAG_FULLSCREEN
-                                | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
-                                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
-                        PixelFormat.TRANSLUCENT);
-        mPopupAnchorLayoutParams.setTitle("ShelfMenuAnchor");
-
-        mPopupAnchor = (ViewGroup) mLayoutInflater.inflate(R.layout.shelf_menu_anchor, null);
-
-        ImageView anchorButton =
-                (ImageView) mPopupAnchor.findViewById(R.id.shelf_menu_anchor_anchor);
-        mPopupMenu = new PopupMenu(context, anchorButton);
-    }
-
-    // Monitor that catches events like "app uninstalled".
-    private class AppPackageMonitor extends PackageMonitor {
-        @Override
-        public void onPackageRemoved(String packageName, int uid) {
-            postUnpinIfUnlauncheable(packageName, new UserHandle(getChangingUserId()));
-            super.onPackageRemoved(packageName, uid);
-        }
-
-        @Override
-        public void onPackageModified(String packageName) {
-            postUnpinIfUnlauncheable(packageName, new UserHandle(getChangingUserId()));
-            super.onPackageModified(packageName);
-        }
-
-        @Override
-        public void onPackagesAvailable(String[] packages) {
-            if (isReplacing()) {
-                UserHandle user = new UserHandle(getChangingUserId());
-
-                for (String packageName : packages) {
-                    postUnpinIfUnlauncheable(packageName, user);
-                }
-            }
-            super.onPackagesAvailable(packages);
-        }
-
-        @Override
-        public void onPackagesUnavailable(String[] packages) {
-            if (!isReplacing()) {
-                UserHandle user = new UserHandle(getChangingUserId());
-
-                for (String packageName : packages) {
-                    postUnpinIfUnlauncheable(packageName, user);
-                }
-            }
-            super.onPackagesUnavailable(packages);
-        }
-    }
-
-    private void postUnpinIfUnlauncheable(final String packageName, final UserHandle user) {
-        // This method doesn't necessarily get called in the main thread. Redirect the call into
-        // the main thread.
-        post(new Runnable() {
-            @Override
-            public void run() {
-                if (!isAttachedToWindow()) return;
-                unpinIfUnlauncheable(packageName, user);
-            }
-        });
-    }
-
-    private void unpinIfUnlauncheable(String packageName, UserHandle user) {
-        // Unpin icons for all apps that match a package that perhaps became unlauncheable.
-        boolean appsWereUnpinned = false;
-        for(int i = getChildCount() - 1; i >= 0; --i) {
-            View child = getChildAt(i);
-            AppButtonData appButtonData = (AppButtonData)child.getTag();
-            if (appButtonData == null) continue;  // Skip the drag placeholder.
-
-            if (!appButtonData.pinned) continue;
-
-            AppInfo appInfo = appButtonData.appInfo;
-            if (!appInfo.getUser().equals(user)) continue;
-
-            ComponentName appComponentName = appInfo.getComponentName();
-            if (!appComponentName.getPackageName().equals(packageName)) continue;
-
-            if (sAppsModel.resolveApp(appInfo) != null) {
-                continue;
-            }
-
-            appButtonData.pinned = false;
-            appsWereUnpinned = true;
-
-            if (appButtonData.isEmpty()) {
-                removeViewAt(i);
-            }
-        }
-        if (appsWereUnpinned) {
-            savePinnedApps();
-        }
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-      super.onAttachedToWindow();
-        // When an icon is dragged out of the pinned area this view's width changes, which causes
-        // the parent container's layout to change and the divider and recents icons to shift left.
-        // Animate the parent's CHANGING transition.
-        ViewGroup parent = (ViewGroup) getParent();
-        LayoutTransition transition = new LayoutTransition();
-        transition.disableTransitionType(LayoutTransition.APPEARING);
-        transition.disableTransitionType(LayoutTransition.DISAPPEARING);
-        transition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
-        transition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
-        transition.enableTransitionType(LayoutTransition.CHANGING);
-        parent.setLayoutTransition(transition);
-
-        sAppsModel.setCurrentUser(ActivityManager.getCurrentUser());
-        recreatePinnedAppButtons();
-        updateRecentApps();
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_USER_SWITCHED);
-        filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
-        mContext.registerReceiver(mBroadcastReceiver, filter);
-
-        mAppPackageMonitor.register(mContext, null, UserHandle.ALL, true);
-        sAppsModel.addOnAppsChangedListener(this);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mContext.unregisterReceiver(mBroadcastReceiver);
-        mAppPackageMonitor.unregister();
-        sAppsModel.removeOnAppsChangedListener(this);
-    }
-
-    @Override
-    protected void onVisibilityChanged(View changedView, int visibility) {
-        super.onVisibilityChanged(changedView, visibility);
-        if (mIsPopupInUse && !isShown()) {
-            // Hide the popup if current view became invisible.
-            shutdownPopupMenu();
-        }
-    }
-
-    private void addAppButton(AppButtonData appButtonData) {
-        ImageView button = createAppButton();
-        updateApp(button, appButtonData);
-        addView(button);
-    }
-
-    private List<AppInfo> getPinnedApps() {
-        List<AppInfo> apps = new ArrayList<AppInfo>();
-        int childCount = getChildCount();
-        for (int i = 0; i != childCount; ++i) {
-            View child = getChildAt(i);
-            AppButtonData appButtonData = (AppButtonData)child.getTag();
-            if (appButtonData == null) continue;  // Skip the drag placeholder.
-            if(!appButtonData.pinned) continue;
-            apps.add(appButtonData.appInfo);
-        }
-        return apps;
-    }
-
-    /**
-     * Creates an ImageView icon for each pinned app. Removes any existing icons. May be called
-     * to synchronize the current view with the shared data mode.
-     */
-    private void recreatePinnedAppButtons() {
-        // Remove any existing icon buttons.
-        removeAllViews();
-
-        List<AppInfo> apps = sAppsModel.getApps();
-        int appCount = apps.size();
-        for (int i = 0; i < appCount; i++) {
-            AppInfo app = apps.get(i);
-            addAppButton(new AppButtonData(app, true /* pinned */));
-        }
-    }
-
-    /**
-     * Saves pinned apps stored in app icons into the data model.
-     */
-    private void savePinnedApps() {
-        sAppsModel.setApps(getPinnedApps());
-    }
-
-    /**
-     * Creates a new ImageView for an app, inflated from R.layout.navigation_bar_app_item.
-     */
-    private ImageView createAppButton() {
-        ImageView button = (ImageView) mLayoutInflater.inflate(
-                R.layout.navigation_bar_app_item, this, false /* attachToRoot */);
-        button.setOnHoverListener(new AppHoverListener());
-        button.setOnClickListener(new AppClickListener());
-        button.setOnContextClickListener(new AppContextClickListener());
-        // TODO: Ripple effect. Use either KeyButtonRipple or the default ripple background.
-        button.setOnLongClickListener(new AppLongClickListener());
-        button.setOnDragListener(new AppIconDragListener());
-        return button;
-    }
-
-    private class AppLongClickListener implements View.OnLongClickListener {
-        @Override
-        public boolean onLongClick(View v) {
-            mDragView = (ImageView) v;
-            AppButtonData appButtonData = (AppButtonData) v.getTag();
-            startAppDrag(mDragView, appButtonData.appInfo);
-            return true;
-        }
-    }
-
-    /**
-     * Returns the human-readable name for an activity's package or null.
-     * TODO: Cache the labels, perhaps in an LruCache.
-     */
-    @Nullable
-    private CharSequence getAppLabel(AppInfo appInfo) {
-        NavigationBarAppsModel.ResolvedApp resolvedApp = sAppsModel.resolveApp(appInfo);
-        if (resolvedApp == null) return null;
-
-        CharSequence unbadgedLabel = resolvedApp.ri.loadLabel(mPackageManager);
-        return mUserManager.getBadgedLabelForUser(unbadgedLabel, appInfo.getUser());
-    }
-
-    /** Helper function to start dragging an app icon (either pinned or recent). */
-    static void startAppDrag(ImageView icon, AppInfo appInfo) {
-        // The drag data is an Intent to launch the activity.
-        Intent mainIntent = Intent.makeMainActivity(appInfo.getComponentName());
-        UserManager userManager =
-                (UserManager) icon.getContext().getSystemService(Context.USER_SERVICE);
-        long userSerialNumber = userManager.getSerialNumberForUser(appInfo.getUser());
-        mainIntent.putExtra(EXTRA_PROFILE, userSerialNumber);
-        ClipData dragData = ClipData.newIntent("", mainIntent);
-        // Use the ImageView to create the shadow.
-        View.DragShadowBuilder shadow = new AppIconDragShadowBuilder(icon);
-        // Use a global drag because the icon might be dragged into the launcher.
-        icon.startDrag(dragData, shadow, null /* myLocalState */, View.DRAG_FLAG_GLOBAL);
-    }
-
-    @Override
-    public boolean dispatchDragEvent(DragEvent event) {
-        // ACTION_DRAG_ENTERED is handled by each individual app icon drag listener.
-        boolean childHandled = super.dispatchDragEvent(event);
-
-        // Other drag types are handled once per drag by this view. This is handled explicitly
-        // because attaching a DragListener to this ViewGroup does not work -- the DragListener in
-        // the children consumes the drag events.
-        boolean handled = false;
-        switch (event.getAction()) {
-            case DragEvent.ACTION_DRAG_STARTED:
-                handled = onDragStarted(event);
-                break;
-            case DragEvent.ACTION_DRAG_ENDED:
-                handled = onDragEnded();
-                break;
-            case DragEvent.ACTION_DROP:
-                handled = onDrop(event);
-                break;
-            case DragEvent.ACTION_DRAG_EXITED:
-                handled = onDragExited();
-                break;
-        }
-
-        return handled || childHandled;
-    }
-
-    /** Returns true if a drag should be handled. */
-    private static boolean canAcceptDrag(DragEvent event) {
-        // Poorly behaved apps might not provide a clip description.
-        if (event.getClipDescription() == null) {
-            return false;
-        }
-        // The event must contain an intent.
-        return event.getClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_INTENT);
-    }
-
-    /**
-     * Sets up for a drag. Runs once per drag operation. Returns true if the data represents
-     * an app shortcut and will be accepted for a drop.
-     */
-    private boolean onDragStarted(DragEvent event) {
-        if (DEBUG) Slog.d(TAG, "onDragStarted");
-
-        // Ensure that an app shortcut is being dragged.
-        if (!canAcceptDrag(event)) {
-            return false;
-        }
-
-        // If there are no pinned apps this view will be collapsed, but the user still needs some
-        // empty space to use as a drag target.
-        if (getChildCount() == 0) {
-            mDragView = createPlaceholderDragView(0);
-        }
-
-        // If this is an existing icon being reordered, hide the app icon. The drag shadow will
-        // continue to draw.
-        if (mDragView != null) {
-            mDragView.setVisibility(View.INVISIBLE);
-        }
-
-        // Listen for the drag end event.
-        return true;
-    }
-
-    /**
-     * Creates a blank icon-sized View to create an empty space during a drag.
-     */
-    private ImageView createPlaceholderDragView(int index) {
-        ImageView button = createAppButton();
-        addView(button, index);
-        return button;
-    }
-
-    /**
-     * Returns initial index for a new app that doesn't exist in Shelf.
-     * Such apps get created by dragging them into Shelf from other apps or by dragging from Shelf
-     * and then back, or by removing from shelf as an intermediate step of pinning an app via menu.
-     * @param indexHint Initial proposed position for the item.
-     * @param isAppPinned True if the app being dragged is pinned.
-     */
-    int getNewAppIndex(int indexHint, boolean isAppPinned) {
-        int i;
-        if (isAppPinned) {
-            // For a pinned app, find the rightmost position to the left of the target that has a
-            // pinned app. We'll insert to the right of that position.
-            for (i = indexHint; i > 0; --i) {
-                View v = getChildAt(i - 1);
-                AppButtonData targetButtonData = (AppButtonData) v.getTag();
-                if (targetButtonData.pinned) break;
-            }
-        } else {
-            // For an unpinned app, find the leftmost position to the right of the target that has
-            // an unpinned app. We'll insert to the left of that position.
-            int childCount = getChildCount();
-            for (i = indexHint; i < childCount; ++i) {
-                View v = getChildAt(i);
-                AppButtonData targetButtonData = (AppButtonData) v.getTag();
-                if (!targetButtonData.pinned) break;
-            }
-        }
-        return i;
-    }
-
-    /**
-     * Handles a drag entering an existing icon. Not implemented in the drag listener because it
-     * needs to use LinearLayout/ViewGroup methods.
-     */
-    private void onDragEnteredIcon(View target) {
-        if (DEBUG) Slog.d(TAG, "onDragEntered " + indexOfChild(target));
-
-        int targetIndex = indexOfChild(target);
-
-        // If the drag didn't start from an existing shelf icon, add an invisible placeholder to
-        // create empty space for the user to drag into.
-        if (mDragView == null) {
-            mDragView = createPlaceholderDragView(getNewAppIndex(targetIndex, true));
-            return;
-        }
-
-        // If the user is dragging on top of the original icon location, do nothing.
-        if (target == mDragView) {
-            return;
-        }
-
-        // "Move" the dragged app by removing it and adding it back at the target location.
-        AppButtonData targetButtonData = (AppButtonData) target.getTag();
-        int dragViewIndex = indexOfChild(mDragView);
-        AppButtonData dragViewButtonData = (AppButtonData) mDragView.getTag();
-        // Calculating whether the dragged app is pinned. If the app came from outside if the shelf,
-        // in which case dragViewButtonData == null, it's a new app that we'll pin. Otherwise, the
-        // button data is defined, and we look whether that existing app is pinned.
-        boolean isAppPinned = dragViewButtonData == null || dragViewButtonData.pinned;
-
-        if (dragViewIndex == -1) {
-            // Drag view exists, but is not a child, which means that the drag has started at or
-            // already visited shelf, then left it, and now is entering it again.
-            targetIndex = getNewAppIndex(targetIndex, isAppPinned);
-        } else if (dragViewIndex < targetIndex) {
-            // The dragged app is currently at the left of the view where the drag is.
-            // We shouldn't allow moving a pinned app to the right of the unpinned app.
-            if (!targetButtonData.pinned && isAppPinned) return;
-        } else {
-            // The dragged app is currently at the right of the view where the drag is.
-            // We shouldn't allow moving a unpinned app to the left of the pinned app.
-            if (targetButtonData.pinned && !isAppPinned) return;
-        }
-
-        // This works, but is subtle:
-        // * If dragViewIndex > targetIndex then the dragged app is moving from right to left and
-        //   the dragged app will be added in front of the target.
-        // * If dragViewIndex < targetIndex then the dragged app is moving from left to right.
-        //   Removing the drag view will shift the later views one position to the left. Adding
-        //   the view at targetIndex will therefore place the app *after* the target.
-        removeView(mDragView);
-        addView(mDragView, targetIndex);
-    }
-
-    private boolean onDrop(DragEvent event) {
-        if (DEBUG) Slog.d(TAG, "onDrop");
-
-        // An earlier drag event might have canceled the drag. If so, there is nothing to do.
-        if (mDragView == null) {
-            return true;
-        }
-
-        boolean dragResult = true;
-        AppInfo appInfo = getAppFromDragEvent(event);
-        if (appInfo == null) {
-            // This wasn't a valid drop. Clean up the placeholder.
-            removePlaceholderDragViewIfNeeded();
-            dragResult = false;
-        } else if (mDragView.getTag() == null) {
-            // This is a drag that adds a new app. Convert the placeholder to a real icon.
-            updateApp(mDragView, new AppButtonData(appInfo, true /* pinned */));
-        }
-        endDrag();
-        return dragResult;
-    }
-
-    /** Cleans up at the end of a drag. */
-    private void endDrag() {
-        // An earlier drag event might have canceled the drag. If so, there is nothing to do.
-        if (mDragView == null) return;
-
-        mDragView.setVisibility(View.VISIBLE);
-        mDragView = null;
-        savePinnedApps();
-        // Add recent tasks to the info of the potentially added app.
-        updateRecentApps();
-    }
-
-    /** Returns an app info from a DragEvent, or null if the data wasn't valid. */
-    private AppInfo getAppFromDragEvent(DragEvent event) {
-        ClipData data = event.getClipData();
-        if (data == null) {
-            return null;
-        }
-        if (data.getItemCount() != 1) {
-            return null;
-        }
-        ClipData.Item item = data.getItemAt(0);
-        if (item == null) {
-            return null;
-        }
-        Intent intent = item.getIntent();
-        if (intent == null) {
-            return null;
-        }
-        long userSerialNumber = intent.getLongExtra(EXTRA_PROFILE, -1);
-        if (userSerialNumber == -1) {
-            return null;
-        }
-        UserHandle appUser = mUserManager.getUserForSerialNumber(userSerialNumber);
-        if (appUser == null) {
-            return null;
-        }
-        ComponentName componentName = intent.getComponent();
-        if (componentName == null) {
-            return null;
-        }
-        AppInfo appInfo = new AppInfo(componentName, appUser);
-        if (sAppsModel.resolveApp(appInfo) == null) {
-            return null;
-        }
-        return appInfo;
-    }
-
-    /** Updates the app at a given view index. */
-    private void updateApp(ImageView button, AppButtonData appButtonData) {
-        CharSequence appLabel = getAppLabel(appButtonData.appInfo);
-        button.setContentDescription(appLabel);
-
-        button.setTag(appButtonData);
-        new GetActivityIconTask(mPackageManager, button).execute(appButtonData);
-    }
-
-    /** Removes the empty placeholder view. */
-    private void removePlaceholderDragViewIfNeeded() {
-        // If the drag has ended already there is nothing to do.
-        if (mDragView == null) {
-            return;
-        }
-        removeView(mDragView);
-    }
-
-    /** Cleans up at the end of the drag. */
-    private boolean onDragEnded() {
-        if (DEBUG) Slog.d(TAG, "onDragEnded");
-        // If the icon wasn't already dropped into the app list then remove the placeholder.
-        removePlaceholderDragViewIfNeeded();
-        endDrag();
-        return true;
-    }
-
-    /** Handles the dragged icon exiting the bounds of this view during the drag. */
-    private boolean onDragExited() {
-        if (DEBUG) Slog.d(TAG, "onDragExited");
-        // Remove the placeholder. It will be added again if the user drags the icon back over
-        // the shelf.
-        removePlaceholderDragViewIfNeeded();
-        return true;
-    }
-
-    /** Drag listener for individual app icons. */
-    private class AppIconDragListener implements View.OnDragListener {
-        @Override
-        public boolean onDrag(View v, DragEvent event) {
-            switch (event.getAction()) {
-                case DragEvent.ACTION_DRAG_STARTED: {
-                    // Every button listens for drag events in order to detect enter/exit.
-                    return canAcceptDrag(event);
-                }
-                case DragEvent.ACTION_DRAG_ENTERED: {
-                    // Forward to NavigationBarApps.
-                    onDragEnteredIcon(v);
-                    return false;
-                }
-            }
-            return false;
-        }
-    }
-
-    /**
-     * Brings the menu popup to closed state.
-     * Can be called at any stage of the asynchronous process of showing a menu.
-     */
-    private void shutdownPopupMenu() {
-        mWindowManager.removeView(mPopupAnchor);
-        mPopupMenu.dismiss();
-    }
-
-    /**
-     * Shows already prepopulated popup menu using appIcon for anchor location.
-     */
-    private void showPopupMenu(ImageView appIcon) {
-        // Movable view inside the popup anchor view. It serves as the actual anchor for the
-        // menu.
-        final ImageView anchorButton =
-                (ImageView) mPopupAnchor.findViewById(R.id.shelf_menu_anchor_anchor);
-        // Set same drawable as for the clicked button to have same size.
-        anchorButton.setImageDrawable(appIcon.getDrawable());
-
-        // Move the anchor button to the position of the app button.
-        appIcon.getLocationOnScreen(mClickedIconLocation);
-        anchorButton.setTranslationX(mClickedIconLocation[0]);
-        anchorButton.setTranslationY(mClickedIconLocation[1]);
-
-        final OnAttachStateChangeListener onAttachStateChangeListener =
-                new OnAttachStateChangeListener() {
-                    @Override
-                    public void onViewAttachedToWindow(View v) {
-                        mPopupMenu.show();
-                    }
-
-                    @Override
-                    public void onViewDetachedFromWindow(View v) {}
-                };
-        anchorButton.addOnAttachStateChangeListener(onAttachStateChangeListener);
-
-        mPopupMenu.setOnDismissListener(new PopupMenu.OnDismissListener() {
-            @Override
-            public void onDismiss(PopupMenu menu) {
-                // FYU: thorough testing for closing menu either by the user or via
-                // shutdownPopupMenu() called at various moments of the menu creation, revealed that
-                // 'onDismiss' is guaranteed to be called after each invocation of showPopupMenu.
-                mWindowManager.removeView(mPopupAnchor);
-                anchorButton.removeOnAttachStateChangeListener(onAttachStateChangeListener);
-                mPopupMenu.setOnDismissListener(null);
-                mPopupMenu.getMenu().clear();
-                mIsPopupInUse = false;
-            }
-        });
-
-        mWindowManager.addView(mPopupAnchor, mPopupAnchorLayoutParams);
-        mIsPopupInUse = true;
-    }
-
-    private void activateTask(int taskPersistentId) {
-        // Launch or bring the activity to front.
-        final IActivityManager iAm = ActivityManagerNative.getDefault();
-        try {
-            iAm.startActivityFromRecents(taskPersistentId, INVALID_STACK_ID, null /* options */);
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Exception when activating a recent task", e);
-        } catch (IllegalArgumentException e) {
-            Slog.e(TAG, "Exception when activating a recent task", e);
-        }
-    }
-
-    /**
-     * Adds to the popup menu items for activating each of tasks in the specified list.
-     */
-    private void populateLaunchMenu(AppButtonData appButtonData) {
-        Menu menu = mPopupMenu.getMenu();
-        int taskCount = appButtonData.getTaskCount();
-        for (int i = 0; i < taskCount; ++i) {
-            final RecentTaskInfo taskInfo = appButtonData.tasks.get(i);
-            MenuItem item = menu.add(getActivityForTask(taskInfo).flattenToShortString());
-            item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
-                @Override
-                public boolean onMenuItemClick(MenuItem item) {
-                    activateTask(taskInfo.persistentId);
-                    return true;
-                }
-            });
-        }
-    }
-
-    /**
-     * Shows a task selection menu for clicked or hovered-over apps that have more than 1 running
-     * tasks.
-     */
-    void maybeShowLaunchMenu(ImageView appIcon) {
-        if (mIsPopupInUse) return;
-        AppButtonData appButtonData = (AppButtonData) appIcon.getTag();
-        if (appButtonData.getTaskCount() <= 1) return;
-
-        populateLaunchMenu(appButtonData);
-        showPopupMenu(appIcon);
-    }
-
-    /**
-     * A listener for hovering over an app icon.
-     */
-    private class AppHoverListener implements View.OnHoverListener {
-        private final long DELAY_MILLIS = 1000;
-        private Runnable mShowMenuCallback;
-
-        @Override
-        public boolean onHover(final View v, MotionEvent event) {
-            if (mShowMenuCallback == null) {
-                mShowMenuCallback = new Runnable() {
-                    @Override
-                    public void run() {
-                        maybeShowLaunchMenu((ImageView) v);
-                    }
-                };
-            }
-
-            switch (event.getAction()) {
-                case MotionEvent.ACTION_HOVER_ENTER:
-                    postDelayed(mShowMenuCallback, DELAY_MILLIS);
-                    break;
-                case MotionEvent.ACTION_HOVER_EXIT:
-                    removeCallbacks(mShowMenuCallback);
-                    break;
-            }
-            return false;
-        }
-    }
-
-    /**
-     * A click listener that launches an activity.
-     */
-    private class AppClickListener implements View.OnClickListener {
-        private void launchApp(AppInfo appInfo, View anchor) {
-            NavigationBarAppsModel.ResolvedApp resolvedApp = sAppsModel.resolveApp(appInfo);
-            if (resolvedApp == null) {
-                Toast.makeText(
-                        getContext(), R.string.activity_not_found, Toast.LENGTH_SHORT).show();
-                return;
-            }
-
-            Intent launchIntent = resolvedApp.launchIntent;
-
-            // Play a scale-up animation while launching the activity.
-            // TODO: Consider playing a different animation, or no animation, if the activity is
-            // already open in a visible window. In that case we should move the task to front
-            // with minimal animation, perhaps using ActivityManager.moveTaskToFront().
-            Rect sourceBounds = new Rect();
-            anchor.getBoundsOnScreen(sourceBounds);
-            ActivityOptions opts =
-                    ActivityOptions.makeScaleUpAnimation(
-                            anchor, 0, 0, anchor.getWidth(), anchor.getHeight());
-            Bundle optsBundle = opts.toBundle();
-            launchIntent.setSourceBounds(sourceBounds);
-
-            mContext.startActivityAsUser(launchIntent, optsBundle, appInfo.getUser());
-        }
-
-        @Override
-        public void onClick(View v) {
-            AppButtonData appButtonData = (AppButtonData) v.getTag();
-
-            if (appButtonData.getTaskCount() == 0) {
-                launchApp(appButtonData.appInfo, v);
-            } else {
-                // Activate latest task.
-                activateTask(appButtonData.tasks.get(0).persistentId);
-
-                maybeShowLaunchMenu((ImageView) v);
-            }
-        }
-    }
-
-    /**
-     * Context click listener that shows app's context menu.
-     */
-    private class AppContextClickListener implements View.OnContextClickListener {
-        void updateState(ImageView appIcon) {
-            savePinnedApps();
-            if (DEBUG) {
-                AppButtonData appButtonData = (AppButtonData) appIcon.getTag();
-                new GetActivityIconTask(mPackageManager, appIcon).execute(appButtonData);
-            }
-        }
-
-        /**
-         * Adds to the popup menu items for pinning and unpinning the app in the shelf.
-         */
-        void populateContextMenu(final ImageView appIcon) {
-            final AppButtonData appButtonData = (AppButtonData) appIcon.getTag();
-            Menu menu = mPopupMenu.getMenu();
-            if (appButtonData.pinned) {
-                menu.add("Unpin").
-                        setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
-                            @Override
-                            public boolean onMenuItemClick(MenuItem item) {
-                                appButtonData.pinned = false;
-                                removeView(appIcon);
-                                if (!appButtonData.isEmpty()) {
-                                    // If the app has running tasks, re-add it to the end of shelf
-                                    // after unpinning.
-                                    addView(appIcon);
-                                }
-                                updateState(appIcon);
-                                return true;
-                            }
-                        });
-            } else {
-                menu.add("Pin").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
-                    @Override
-                    public boolean onMenuItemClick(MenuItem item) {
-                        appButtonData.pinned = true;
-                        removeView(appIcon);
-                        // Re-add the pinned icon to the end of the pinned list.
-                        addView(appIcon, getNewAppIndex(getChildCount(), true));
-                        updateState(appIcon);
-                        return true;
-                    }
-                });
-            }
-        }
-
-        @Override
-        public boolean onContextClick(View v) {
-            if (mIsPopupInUse) return true;
-            ImageView appIcon = (ImageView) v;
-            populateContextMenu(appIcon);
-            showPopupMenu(appIcon);
-            return true;
-        }
-    }
-
-    private void onUserSwitched(int currentUserId) {
-        sAppsModel.setCurrentUser(currentUserId);
-        recreatePinnedAppButtons();
-    }
-
-    private void onManagedProfileRemoved(UserHandle removedProfile) {
-        // Unpin apps from the removed profile.
-        boolean itemsWereUnpinned = false;
-        for(int i = getChildCount() - 1; i >= 0; --i) {
-            View view = getChildAt(i);
-            AppButtonData appButtonData = (AppButtonData)view.getTag();
-            if (appButtonData == null) return;  // Skip the drag placeholder.
-            if (!appButtonData.pinned) continue;
-            if (!appButtonData.appInfo.getUser().equals(removedProfile)) continue;
-
-            appButtonData.pinned = false;
-            itemsWereUnpinned = true;
-            if (appButtonData.isEmpty()) {
-                removeViewAt(i);
-            }
-        }
-        if (itemsWereUnpinned) {
-            savePinnedApps();
-        }
-    }
-
-    /**
-     * Returns app data for a button that matches the provided app info, if it exists, or null
-     * otherwise.
-     */
-    private AppButtonData findAppButtonData(AppInfo appInfo) {
-        int size = getChildCount();
-        for (int i = 0; i < size; ++i) {
-            View view = getChildAt(i);
-            AppButtonData appButtonData = (AppButtonData)view.getTag();
-            if (appButtonData == null) continue;  // Skip the drag placeholder.
-            if (appButtonData.appInfo.equals(appInfo)) {
-                return appButtonData;
-            }
-        }
-        return null;
-    }
-
-    private void updateTasks(List<RecentTaskInfo> tasks) {
-        // Remove tasks from all app buttons.
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            View view = getChildAt(i);
-            AppButtonData appButtonData = (AppButtonData)view.getTag();
-            if (appButtonData == null) return;  // Skip the drag placeholder.
-            appButtonData.clearTasks();
-        }
-
-        // Re-add tasks to app buttons, adding new buttons if needed.
-        int size = tasks.size();
-        for (int i = 0; i != size; ++i) {
-            RecentTaskInfo task = tasks.get(i);
-            AppInfo taskAppInfo = taskToAppInfo(task);
-            if (taskAppInfo == null) continue;
-            AppButtonData appButtonData = findAppButtonData(taskAppInfo);
-            if (appButtonData == null) {
-                appButtonData = new AppButtonData(taskAppInfo, false);
-                addAppButton(appButtonData);
-            }
-            appButtonData.addTask(task);
-        }
-
-        // Remove unpinned apps that now have no tasks.
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            View view = getChildAt(i);
-            AppButtonData appButtonData = (AppButtonData)view.getTag();
-            if (appButtonData == null) return;  // Skip the drag placeholder.
-            if (appButtonData.isEmpty()) {
-                removeViewAt(i);
-            }
-        }
-
-        if (DEBUG) {
-            for (int i = getChildCount() - 1; i >= 0; --i) {
-                View view = getChildAt(i);
-                AppButtonData appButtonData = (AppButtonData)view.getTag();
-                if (appButtonData == null) return;  // Skip the drag placeholder.
-                new GetActivityIconTask(mPackageManager, (ImageView )view).execute(appButtonData);
-
-            }
-        }
-    }
-
-    private void updateRecentApps() {
-        ActivityManager activityManager =
-                (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
-        // TODO: Should this be getRunningTasks?
-        List<RecentTaskInfo> recentTasks = activityManager.getRecentTasksForUser(
-                ActivityManager.getMaxAppRecentsLimitStatic(),
-                ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS |
-                        ActivityManager.RECENT_IGNORE_UNAVAILABLE |
-                        ActivityManager.RECENT_INCLUDE_PROFILES,
-                UserHandle.USER_CURRENT);
-        if (DEBUG) Slog.d(TAG, "Got recents " + recentTasks.size());
-        updateTasks(recentTasks);
-    }
-
-    private static ComponentName getActivityForTask(RecentTaskInfo task) {
-        // If the task was started from an alias, return the actual activity component that was
-        // initially started.
-        if (task.origActivity != null) {
-            return task.origActivity;
-        }
-        // Prefer the first activity of the task.
-        if (task.baseActivity != null) {
-            return task.baseActivity;
-        }
-        // Then goes the activity that started the task.
-        if (task.realActivity != null) {
-            return task.realActivity;
-        }
-        // This should not happen, but fall back to the base intent's activity component name.
-        return task.baseIntent.getComponent();
-    }
-
-    private ComponentName getLaunchComponentForPackage(String packageName, int userId) {
-        // This code is based on ApplicationPackageManager.getLaunchIntentForPackage.
-        PackageManager packageManager = mContext.getPackageManager();
-
-        // First see if the package has an INFO activity; the existence of
-        // such an activity is implied to be the desired front-door for the
-        // overall package (such as if it has multiple launcher entries).
-        Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
-        intentToResolve.addCategory(Intent.CATEGORY_INFO);
-        intentToResolve.setPackage(packageName);
-        List<ResolveInfo> ris = packageManager.queryIntentActivitiesAsUser(
-                intentToResolve, 0, userId);
-
-        // Otherwise, try to find a main launcher activity.
-        if (ris == null || ris.size() <= 0) {
-            // reuse the intent instance
-            intentToResolve.removeCategory(Intent.CATEGORY_INFO);
-            intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
-            intentToResolve.setPackage(packageName);
-            ris = packageManager.queryIntentActivitiesAsUser(intentToResolve, 0, userId);
-        }
-        if (ris == null || ris.size() <= 0) {
-            Slog.i(TAG, "Failed to build intent for " + packageName);
-            return null;
-        }
-        return new ComponentName(ris.get(0).activityInfo.packageName,
-                ris.get(0).activityInfo.name);
-    }
-
-    private AppInfo taskToAppInfo(RecentTaskInfo task) {
-        ComponentName componentName = getActivityForTask(task);
-        UserHandle taskUser = new UserHandle(task.userId);
-        AppInfo appInfo = new AppInfo(componentName, taskUser);
-
-        if (sAppsModel.resolveApp(appInfo) == null) {
-            // If task's activity is not launcheable, fall back to a launch component of the
-            // task's package.
-            ComponentName component = getLaunchComponentForPackage(
-                    componentName.getPackageName(), task.userId);
-
-            if (component == null) {
-                return null;
-            }
-
-            appInfo = new AppInfo(component, taskUser);
-        }
-
-        return appInfo;
-    }
-
-    /**
-     * A listener that updates the app buttons whenever the recents task stack changes.
-     */
-    private class TaskStackListener extends ITaskStackListener.Stub {
-        @Override
-        public void onTaskStackChanged() throws RemoteException {
-            // Post the message back to the UI thread.
-            post(new Runnable() {
-                @Override
-                public void run() {
-                    if (isAttachedToWindow()) {
-                        updateRecentApps();
-                    }
-                }
-            });
-        }
-    }
-
-    @Override
-    public void onPinnedAppsChanged() {
-        if (getPinnedApps().equals(sAppsModel.getApps())) return;
-        recreatePinnedAppButtons();
-        updateRecentApps();
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java
deleted file mode 100644
index 76a9798..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java
+++ /dev/null
@@ -1,364 +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.phone;
-
-import android.app.AppGlobals;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.ActivityInfo;
-import android.content.pm.IPackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.UserInfo;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Slog;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Data model and controller for app icons appearing in the navigation bar. The data is stored on
- * disk in SharedPreferences. Each icon has a separate pref entry consisting of a flattened
- * ComponentName.
- */
-class NavigationBarAppsModel {
-    public interface OnAppsChangedListener {
-        void onPinnedAppsChanged();
-    }
-
-    public class ResolvedApp {
-        Intent launchIntent;
-        ResolveInfo ri;
-    }
-
-    private final static String TAG = "NavigationBarAppsModel";
-
-    // Default number of apps to load initially.
-    private final static int NUM_INITIAL_APPS = 4;
-
-    // Preferences file name.
-    private final static String SHARED_PREFERENCES_NAME = "com.android.systemui.navbarapps";
-
-    // Preference name for the version of the other preferences.
-    private final static String VERSION_PREF = "version";
-
-    // Current version number for preferences.
-    private final static int CURRENT_VERSION = 3;
-
-    // Preference name for the number of app icons.
-    private final static String APP_COUNT_PREF = "app_count";
-
-    // Preference name prefix for each app's info. The actual pref has an integer appended to it.
-    private final static String APP_PREF_PREFIX = "app_";
-
-    // User serial number prefix for each app's info. The actual pref has an integer appended to it.
-    private final static String APP_USER_PREFIX = "app_user_";
-
-    // Character separating current user serial number from the user-specific part of a pref.
-    // Example "22|app_user_2" - when logged as user with serial 22, we'll use this pref for the
-    // user serial of the third app of the logged-in user.
-    private final static char USER_SEPARATOR = '|';
-
-    private final Context mContext;
-    private final UserManager mUserManager;
-    private final SharedPreferences mPrefs;
-
-    // Apps are represented as an ordered list of app infos.
-    private List<AppInfo> mApps = new ArrayList<AppInfo>();
-
-    private List<OnAppsChangedListener> mOnAppsChangedListeners =
-            new ArrayList<OnAppsChangedListener>();
-
-    // Id of the current user.
-    private int mCurrentUserId = -1;
-
-    // Serial number of the current user.
-    private long mCurrentUserSerialNumber = -1;
-
-    public NavigationBarAppsModel(Context context) {
-        mContext = context;
-        mPrefs = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
-        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
-
-        int version = mPrefs.getInt(VERSION_PREF, -1);
-        if (version != CURRENT_VERSION) {
-            // Since the data format changed, clean everything.
-            SharedPreferences.Editor edit = mPrefs.edit();
-            edit.clear();
-            edit.putInt(VERSION_PREF, CURRENT_VERSION);
-            edit.apply();
-        }
-    }
-
-    @VisibleForTesting
-    protected IPackageManager getPackageManager() {
-        return AppGlobals.getPackageManager();
-    }
-
-    // Returns a resolved app info for a given app info, or null if the app info is unlauncheable.
-    public ResolvedApp resolveApp(AppInfo appInfo) {
-        ComponentName component = appInfo.getComponentName();
-        int appUserId = appInfo.getUser().getIdentifier();
-
-        if (mCurrentUserId != appUserId) {
-            // Check if app user is a profile of current user and the app user is enabled.
-            UserInfo appUserInfo = mUserManager.getUserInfo(appUserId);
-            UserInfo currentUserInfo = mUserManager.getUserInfo(mCurrentUserId);
-            if (appUserInfo == null || currentUserInfo == null
-                    || appUserInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID
-                    || appUserInfo.profileGroupId != currentUserInfo.profileGroupId
-                    || !appUserInfo.isEnabled()) {
-                Slog.e(TAG, "User " + appUserId +
-                        " is is not a profile of the current user, or is disabled.");
-                return null;
-            }
-        }
-
-        // This code is based on LauncherAppsService.startActivityAsUser code.
-        Intent launchIntent = new Intent(Intent.ACTION_MAIN);
-        launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-        launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        launchIntent.setPackage(component.getPackageName());
-
-        try {
-            ActivityInfo info = getPackageManager().getActivityInfo(component, 0, appUserId);
-            if (info == null) {
-                Slog.e(TAG, "Activity " + component + " is not installed.");
-                return null;
-            }
-
-            if (!info.exported) {
-                Slog.e(TAG, "Activity " + component + " doesn't have 'exported' attribute.");
-                return null;
-            }
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Failed to get activity info for " + component, e);
-            return null;
-        }
-
-        // Check that the component actually has Intent.CATEGORY_LAUNCHER
-        // as calling startActivityAsUser ignores the category and just
-        // resolves based on the component if present.
-        List<ResolveInfo> apps = mContext.getPackageManager().queryIntentActivitiesAsUser(launchIntent,
-                0 /* flags */, appUserId);
-        final int size = apps.size();
-        for (int i = 0; i < size; ++i) {
-            ResolveInfo ri = apps.get(i);
-            ActivityInfo activityInfo = ri.activityInfo;
-            if (activityInfo.packageName.equals(component.getPackageName()) &&
-                    activityInfo.name.equals(component.getClassName())) {
-                // Found an activity with category launcher that matches
-                // this component so ok to launch.
-                launchIntent.setComponent(component);
-                ResolvedApp resolvedApp = new ResolvedApp();
-                resolvedApp.launchIntent = launchIntent;
-                resolvedApp.ri = ri;
-                return resolvedApp;
-            }
-        }
-
-        Slog.i(TAG, "Activity doesn't have category Intent.CATEGORY_LAUNCHER " + component);
-        return null;
-    }
-
-    public void addOnAppsChangedListener(OnAppsChangedListener listener) {
-        mOnAppsChangedListeners.add(listener);
-    }
-
-    public void removeOnAppsChangedListener(OnAppsChangedListener listener) {
-        mOnAppsChangedListeners.remove(listener);
-    }
-
-    /**
-     * Reinitializes the model for a new user.
-     */
-    public void setCurrentUser(int userId) {
-        mCurrentUserId = userId;
-        mCurrentUserSerialNumber = mUserManager.getSerialNumberForUser(new UserHandle(userId));
-
-        mApps.clear();
-
-        int appCount = mPrefs.getInt(userPrefixed(APP_COUNT_PREF), -1);
-        if (appCount >= 0) {
-            loadAppsFromPrefs(appCount);
-        } else {
-            // We switched to this user for the first time ever. This is a good opportunity to clean
-            // prefs for users deleted in the past.
-            removePrefsForDeletedUsers();
-
-            addDefaultApps();
-        }
-    }
-
-    /**
-     * Removes prefs for users that don't exist on the device.
-     */
-    private void removePrefsForDeletedUsers() {
-        // Build a set of string representations of serial numbers of the device users.
-        final List<UserInfo> users = mUserManager.getUsers();
-        final int userCount = users.size();
-
-        final Set<String> userSerials = new HashSet<String> ();
-
-        for (int i = 0; i < userCount; ++i) {
-            userSerials.add(Long.toString(users.get(i).serialNumber));
-        }
-
-        // Walk though all prefs and delete ones which user is not in the string set.
-        final Map<String, ?> allPrefs = mPrefs.getAll();
-        final SharedPreferences.Editor edit = mPrefs.edit();
-
-        for (Map.Entry<String, ?> pref : allPrefs.entrySet()) {
-            final String key = pref.getKey();
-            if (key.equals(VERSION_PREF)) continue;
-
-            final int userSeparatorPos = key.indexOf(USER_SEPARATOR);
-
-            if (userSeparatorPos < 0) {
-                // Removing anomalous pref with no user.
-                edit.remove(key);
-                continue;
-            }
-
-            final String prefUserSerial = key.substring(0, userSeparatorPos);
-
-            if (!userSerials.contains(prefUserSerial)) {
-                // Removes pref for a not existing user.
-                edit.remove(key);
-                continue;
-            }
-        }
-
-        edit.apply();
-    }
-
-    /** Returns the list of apps. */
-    public List<AppInfo> getApps() {
-        return mApps;
-    }
-
-    /** Sets the list of apps and saves it. */
-    public void setApps(List<AppInfo> apps) {
-        mApps = apps;
-        savePrefs();
-
-        int size = mOnAppsChangedListeners.size();
-        for (int i = 0; i < size; ++i) {
-            mOnAppsChangedListeners.get(i).onPinnedAppsChanged();
-        }
-    }
-
-    /** Saves the current model to disk. */
-    private void savePrefs() {
-        SharedPreferences.Editor edit = mPrefs.edit();
-        int appCount = mApps.size();
-        edit.putInt(userPrefixed(APP_COUNT_PREF), appCount);
-        for (int i = 0; i < appCount; i++) {
-            final AppInfo appInfo = mApps.get(i);
-            String componentNameString = appInfo.getComponentName().flattenToString();
-            edit.putString(prefNameForApp(i), componentNameString);
-            long userSerialNumber = mUserManager.getSerialNumberForUser(appInfo.getUser());
-            edit.putLong(prefUserForApp(i), userSerialNumber);
-        }
-        // Start an asynchronous disk write.
-        edit.apply();
-    }
-
-    /** Loads AppInfo from prefs. Returns null if something is wrong. */
-    private AppInfo loadAppFromPrefs(int index) {
-        String prefValue = mPrefs.getString(prefNameForApp(index), null);
-        if (prefValue == null) {
-            Slog.w(TAG, "Couldn't find pref " + prefNameForApp(index));
-            return null;
-        }
-        ComponentName componentName = ComponentName.unflattenFromString(prefValue);
-        if (componentName == null) {
-            Slog.w(TAG, "Invalid component name " + prefValue);
-            return null;
-        }
-        long userSerialNumber = mPrefs.getLong(prefUserForApp(index), -1);
-        if (userSerialNumber == -1) {
-            Slog.w(TAG, "Couldn't find pref " + prefUserForApp(index));
-            return null;
-        }
-        UserHandle appUser = mUserManager.getUserForSerialNumber(userSerialNumber);
-        if (appUser == null) {
-            Slog.w(TAG, "No user for serial " + userSerialNumber);
-            return null;
-        }
-        AppInfo appInfo = new AppInfo(componentName, appUser);
-        if (resolveApp(appInfo) == null) {
-            return null;
-        }
-        return appInfo;
-    }
-
-    /** Loads the list of apps from SharedPreferences. */
-    private void loadAppsFromPrefs(int appCount) {
-        for (int i = 0; i < appCount; i++) {
-            AppInfo appInfo = loadAppFromPrefs(i);
-            if (appInfo != null) {
-                mApps.add(appInfo);
-            }
-        }
-
-        if (appCount != mApps.size()) savePrefs();
-    }
-
-    /** Adds the first few apps from the owner profile. Used for demo purposes. */
-    private void addDefaultApps() {
-        // Get a list of all app activities.
-        final Intent queryIntent = new Intent(Intent.ACTION_MAIN, null);
-        queryIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-
-        final List<ResolveInfo> apps = mContext.getPackageManager().queryIntentActivitiesAsUser(
-                queryIntent, 0 /* flags */, mCurrentUserId);
-        final int appCount = apps.size();
-        for (int i = 0; i < NUM_INITIAL_APPS && i < appCount; i++) {
-            ResolveInfo ri = apps.get(i);
-            ComponentName componentName = new ComponentName(
-                    ri.activityInfo.packageName, ri.activityInfo.name);
-            mApps.add(new AppInfo(componentName, new UserHandle(mCurrentUserId)));
-        }
-
-        savePrefs();
-    }
-
-    /** Returns a pref prefixed with the serial number of the current user. */
-    private String userPrefixed(String pref) {
-        return Long.toString(mCurrentUserSerialNumber) + USER_SEPARATOR + pref;
-    }
-
-    /** Returns the pref name for the app at a given index. */
-    private String prefNameForApp(int index) {
-        return userPrefixed(APP_PREF_PREFIX + Integer.toString(index));
-    }
-
-    /** Returns the pref name for the app's user at a given index. */
-    private String prefUserForApp(int index) {
-        return userPrefixed(APP_USER_PREFIX + Integer.toString(index));
-    }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 79bd626..786e64d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -23,12 +23,15 @@
 import android.view.GestureDetector;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
+import android.view.View;
 import android.view.ViewConfiguration;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.stackdivider.Divider;
+import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
 import com.android.systemui.tuner.TunerService;
 
 import static android.view.WindowManager.*;
@@ -40,20 +43,25 @@
         implements TunerService.Tunable {
 
     private static final String KEY_DOCK_WINDOW_GESTURE = "overview_nav_bar_gesture";
+    /**
+     * When dragging from the navigation bar, we drag in recents.
+     */
+    public static final int DRAG_MODE_NONE = -1;
 
     /**
      * When dragging from the navigation bar, we drag in recents.
      */
-    private static final int DRAG_MODE_RECENTS = 0;
+    public static final int DRAG_MODE_RECENTS = 0;
 
     /**
      * When dragging from the navigation bar, we drag the divider.
      */
-    private static final int DRAG_MODE_DIVIDER = 1;
+    public static final int DRAG_MODE_DIVIDER = 1;
 
     private RecentsComponent mRecentsComponent;
     private Divider mDivider;
     private Context mContext;
+    private NavigationBarView mNavigationBarView;
     private boolean mIsVertical;
     private boolean mIsRTL;
 
@@ -62,6 +70,7 @@
     private final int mMinFlingVelocity;
     private int mTouchDownX;
     private int mTouchDownY;
+    private boolean mDownOnRecents;
     private VelocityTracker mVelocityTracker;
 
     private boolean mDockWindowEnabled;
@@ -78,9 +87,11 @@
         TunerService.get(context).addTunable(this, KEY_DOCK_WINDOW_GESTURE);
     }
 
-    public void setComponents(RecentsComponent recentsComponent, Divider divider) {
+    public void setComponents(RecentsComponent recentsComponent, Divider divider,
+            NavigationBarView navigationBarView) {
         mRecentsComponent = recentsComponent;
         mDivider = divider;
+        mNavigationBarView = navigationBarView;
     }
 
     public void setBarState(boolean isVertical, boolean isRTL) {
@@ -156,6 +167,18 @@
         mDockWindowTouchSlopExceeded = false;
         mTouchDownX = (int) event.getX();
         mTouchDownY = (int) event.getY();
+
+        if (mNavigationBarView != null) {
+            View recentsButton = mNavigationBarView.getRecentsButton().getCurrentView();
+            if (recentsButton != null) {
+                mDownOnRecents = mTouchDownX >= recentsButton.getLeft()
+                        && mTouchDownX <= recentsButton.getRight()
+                        && mTouchDownY >= recentsButton.getTop()
+                        && mTouchDownY <= recentsButton.getBottom();
+            } else {
+                mDownOnRecents = false;
+            }
+        }
     }
 
     private boolean handleDragActionMoveEvent(MotionEvent event) {
@@ -164,16 +187,19 @@
         int y = (int) event.getY();
         int xDiff = Math.abs(x - mTouchDownX);
         int yDiff = Math.abs(y - mTouchDownY);
+        if (mDivider == null || mRecentsComponent == null) {
+            return false;
+        }
         if (!mDockWindowTouchSlopExceeded) {
             boolean touchSlopExceeded = !mIsVertical
                     ? yDiff > mScrollTouchSlop && yDiff > xDiff
                     : xDiff > mScrollTouchSlop && xDiff > yDiff;
-            if (touchSlopExceeded && mDivider.getView().getWindowManagerProxy().getDockSide()
-                    == DOCKED_INVALID) {
-                mDragMode = calculateDragMode();
+            if (mDownOnRecents && touchSlopExceeded
+                    && mDivider.getView().getWindowManagerProxy().getDockSide() == DOCKED_INVALID) {
                 Rect initialBounds = null;
+                int dragMode = calculateDragMode();
                 int createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
-                if (mDragMode == DRAG_MODE_DIVIDER) {
+                if (dragMode == DRAG_MODE_DIVIDER) {
                     initialBounds = new Rect();
                     mDivider.getView().calculateBoundsForPosition(mIsVertical
                                     ? (int) event.getRawX()
@@ -182,24 +208,28 @@
                                     ? DOCKED_TOP
                                     : DOCKED_LEFT,
                             initialBounds);
-                } else if (mDragMode == DRAG_MODE_RECENTS && mTouchDownX
+                } else if (dragMode == DRAG_MODE_RECENTS && mTouchDownX
                         < mContext.getResources().getDisplayMetrics().widthPixels / 2) {
                     createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
                 }
-                mRecentsComponent.dockTopTask(mDragMode == DRAG_MODE_RECENTS, createMode,
-                        initialBounds);
-                if (mDragMode == DRAG_MODE_DIVIDER) {
-                    mDivider.getView().startDragging();
+                boolean docked = mRecentsComponent.dockTopTask(dragMode, createMode, initialBounds);
+                if (docked) {
+                    mDragMode = dragMode;
+                    if (mDragMode == DRAG_MODE_DIVIDER) {
+                        mDivider.getView().startDragging(false /* animate */, true /* touching*/);
+                    }
+                    mDockWindowTouchSlopExceeded = true;
+                    MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_SWIPE);
+
+                    return true;
                 }
-                mDockWindowTouchSlopExceeded = true;
-                MetricsLogger.action(mContext,
-                        MetricsLogger.ACTION_WINDOW_DOCK_SWIPE);
-                return true;
             }
         } else {
             if (mDragMode == DRAG_MODE_DIVIDER) {
-                mDivider.getView().resizeStack(
-                        !mIsVertical ? (int) event.getRawY() : (int) event.getRawX());
+                int position = !mIsVertical ? (int) event.getRawY() : (int) event.getRawX();
+                SnapTarget snapTarget = mDivider.getView().getSnapAlgorithm()
+                        .calculateSnapTarget(position, 0f /* velocity */, false /* hardDismiss */);
+                mDivider.getView().resizeStack(position, snapTarget.position, snapTarget);
             } else if (mDragMode == DRAG_MODE_RECENTS) {
                 mRecentsComponent.onDraggingInRecents(event.getRawY());
             }
@@ -210,14 +240,15 @@
     private void handleDragActionUpEvent(MotionEvent event) {
         mVelocityTracker.addMovement(event);
         mVelocityTracker.computeCurrentVelocity(1000);
-        if (mDockWindowTouchSlopExceeded) {
+        if (mDockWindowTouchSlopExceeded && mDivider != null && mRecentsComponent != null) {
             if (mDragMode == DRAG_MODE_DIVIDER) {
                 mDivider.getView().stopDragging(mIsVertical
                                 ? (int) event.getRawX()
                                 : (int) event.getRawY(),
                         mIsVertical
                                 ? mVelocityTracker.getXVelocity()
-                                : mVelocityTracker.getYVelocity());
+                                : mVelocityTracker.getYVelocity(),
+                        true /* avoidDismissStart */);
             } else if (mDragMode == DRAG_MODE_RECENTS) {
                 mRecentsComponent.onDraggingInRecentsEnded(mVelocityTracker.getYVelocity());
             }
@@ -250,7 +281,7 @@
         float absVelY = Math.abs(velocityY);
         boolean isValidFling = absVelX > mMinFlingVelocity &&
                 mIsVertical ? (absVelY > absVelX) : (absVelX > absVelY);
-        if (isValidFling) {
+        if (isValidFling && mRecentsComponent != null) {
             boolean showNext;
             if (!mIsRTL) {
                 showNext = mIsVertical ? (velocityY < 0) : (velocityX < 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
new file mode 100644
index 0000000..6cfd715
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.Space;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.KeyButtonView;
+import com.android.systemui.tuner.TunerService;
+
+import java.io.File;
+import java.util.Objects;
+
+public class NavigationBarInflaterView extends FrameLayout implements TunerService.Tunable {
+
+    private static final String TAG = "NavBarInflater";
+
+    public static final String NAV_BAR_VIEWS = "sysui_nav_bar";
+
+    public static final String MENU_IME = "menu_ime";
+    public static final String BACK = "back";
+    public static final String HOME = "home";
+    public static final String RECENT = "recent";
+    public static final String NAVSPACE = "space";
+    public static final String CLIPBOARD = "clipboard";
+    public static final String KEY = "key";
+
+    public static final String GRAVITY_SEPARATOR = ";";
+    public static final String BUTTON_SEPARATOR = ",";
+
+    public static final String SIZE_MOD_START = "[";
+    public static final String SIZE_MOD_END = "]";
+
+    public static final String KEY_CODE_START = "(";
+    public static final String KEY_IMAGE_DELIM = ":";
+    public static final String KEY_CODE_END = ")";
+
+    protected final LayoutInflater mLayoutInflater;
+    protected final LayoutInflater mLandscapeInflater;
+
+    protected FrameLayout mRot0;
+    protected FrameLayout mRot90;
+
+    private SparseArray<ButtonDispatcher> mButtonDispatchers;
+    private String mCurrentLayout;
+
+    public NavigationBarInflaterView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mLayoutInflater = LayoutInflater.from(context);
+        Configuration landscape = new Configuration();
+        landscape.setTo(context.getResources().getConfiguration());
+        landscape.orientation = Configuration.ORIENTATION_LANDSCAPE;
+        mLandscapeInflater = LayoutInflater.from(context.createConfigurationContext(landscape));
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mRot0 = (FrameLayout) findViewById(R.id.rot0);
+        mRot90 = (FrameLayout) findViewById(R.id.rot90);
+        clearViews();
+        inflateLayout(getDefaultLayout());
+    }
+
+    protected String getDefaultLayout() {
+        return mContext.getString(R.string.config_navBarLayout);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        TunerService.get(getContext()).addTunable(this, NAV_BAR_VIEWS);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        TunerService.get(getContext()).removeTunable(this);
+        super.onDetachedFromWindow();
+    }
+
+    @Override
+    public void onTuningChanged(String key, String newValue) {
+        if (NAV_BAR_VIEWS.equals(key)) {
+            if (newValue == null) {
+                newValue = getDefaultLayout();
+            }
+            if (!Objects.equals(mCurrentLayout, newValue)) {
+                clearViews();
+                inflateLayout(newValue);
+            }
+        }
+    }
+
+    public void setButtonDispatchers(SparseArray<ButtonDispatcher> buttonDisatchers) {
+        mButtonDispatchers = buttonDisatchers;
+        for (int i = 0; i < buttonDisatchers.size(); i++) {
+            initiallyFill(buttonDisatchers.valueAt(i));
+        }
+    }
+
+    private void initiallyFill(ButtonDispatcher buttonDispatcher) {
+        addAll(buttonDispatcher, (ViewGroup) mRot0.findViewById(R.id.ends_group));
+        addAll(buttonDispatcher, (ViewGroup) mRot0.findViewById(R.id.center_group));
+        addAll(buttonDispatcher, (ViewGroup) mRot90.findViewById(R.id.ends_group));
+        addAll(buttonDispatcher, (ViewGroup) mRot90.findViewById(R.id.center_group));
+    }
+
+    private void addAll(ButtonDispatcher buttonDispatcher, ViewGroup parent) {
+        for (int i = 0; i < parent.getChildCount(); i++) {
+            // Need to manually search for each id, just in case each group has more than one
+            // of a single id.  It probably mostly a waste of time, but shouldn't take long
+            // and will only happen once.
+            if (parent.getChildAt(i).getId() == buttonDispatcher.getId()) {
+                buttonDispatcher.addView(parent.getChildAt(i));
+            } else if (parent.getChildAt(i) instanceof ViewGroup) {
+                addAll(buttonDispatcher, (ViewGroup) parent.getChildAt(i));
+            }
+        }
+    }
+
+    protected void inflateLayout(String newLayout) {
+        mCurrentLayout = newLayout;
+        String[] sets = newLayout.split(GRAVITY_SEPARATOR, 3);
+        String[] start = sets[0].split(BUTTON_SEPARATOR);
+        String[] center = sets[1].split(BUTTON_SEPARATOR);
+        String[] end = sets[2].split(BUTTON_SEPARATOR);
+        inflateButtons(start, (ViewGroup) mRot0.findViewById(R.id.ends_group),
+                (ViewGroup) mRot0.findViewById(R.id.ends_group_lightsout), false);
+        inflateButtons(start, (ViewGroup) mRot90.findViewById(R.id.ends_group),
+                (ViewGroup) mRot90.findViewById(R.id.ends_group_lightsout), true);
+
+        inflateButtons(center, (ViewGroup) mRot0.findViewById(R.id.center_group),
+                (ViewGroup) mRot0.findViewById(R.id.center_group_lightsout), false);
+        inflateButtons(center, (ViewGroup) mRot90.findViewById(R.id.center_group),
+                (ViewGroup) mRot90.findViewById(R.id.center_group_lightsout), true);
+
+        addGravitySpacer((LinearLayout) mRot0.findViewById(R.id.ends_group));
+        addGravitySpacer((LinearLayout) mRot90.findViewById(R.id.ends_group));
+
+        inflateButtons(end, (ViewGroup) mRot0.findViewById(R.id.ends_group),
+                (ViewGroup) mRot0.findViewById(R.id.ends_group_lightsout), false);
+        inflateButtons(end, (ViewGroup) mRot90.findViewById(R.id.ends_group),
+                (ViewGroup) mRot90.findViewById(R.id.ends_group_lightsout), true);
+    }
+
+    private void addGravitySpacer(LinearLayout layout) {
+        layout.addView(new Space(mContext), new LinearLayout.LayoutParams(0, 0, 1));
+    }
+
+    private void inflateButtons(String[] buttons, ViewGroup parent, ViewGroup lightsOutParent,
+            boolean landscape) {
+        for (int i = 0; i < buttons.length; i++) {
+            copyToLightsout(inflateButton(buttons[i], parent, landscape), lightsOutParent);
+        }
+    }
+
+    private void copyToLightsout(View view, ViewGroup lightsOutParent) {
+        if (view == null) return;
+
+        if (view instanceof FrameLayout) {
+            // The only ViewGroup we support in here is a FrameLayout, so copy those manually.
+            FrameLayout original = (FrameLayout) view;
+            FrameLayout layout = new FrameLayout(view.getContext());
+            for (int i = 0; i < original.getChildCount(); i++) {
+                copyToLightsout(original.getChildAt(i), layout);
+            }
+            lightsOutParent.addView(layout, copy(view.getLayoutParams()));
+        } else if (view instanceof Space) {
+            lightsOutParent.addView(new Space(view.getContext()), copy(view.getLayoutParams()));
+        } else {
+            lightsOutParent.addView(generateLightsOutView(view), copy(view.getLayoutParams()));
+        }
+    }
+
+    private View generateLightsOutView(View view) {
+        ImageView imageView = new ImageView(view.getContext());
+        // Copy everything we can about the original view.
+        imageView.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(),
+                view.getPaddingBottom());
+        imageView.setContentDescription(view.getContentDescription());
+        imageView.setId(view.getId());
+        // Only home gets a big dot, everything else will be little.
+        imageView.setImageResource(view.getId() == R.id.home
+                ? R.drawable.ic_sysbar_lights_out_dot_large
+                : R.drawable.ic_sysbar_lights_out_dot_small);
+        return imageView;
+    }
+
+    private ViewGroup.LayoutParams copy(ViewGroup.LayoutParams layoutParams) {
+        if (layoutParams instanceof LinearLayout.LayoutParams) {
+            return new LinearLayout.LayoutParams(layoutParams.width, layoutParams.height,
+                    ((LinearLayout.LayoutParams) layoutParams).weight);
+        }
+        return new LayoutParams(layoutParams.width, layoutParams.height);
+    }
+
+    @Nullable
+    protected View inflateButton(String buttonSpec, ViewGroup parent, boolean landscape) {
+        LayoutInflater inflater = landscape ? mLandscapeInflater : mLayoutInflater;
+        float size = extractSize(buttonSpec);
+        String button = extractButton(buttonSpec);
+        View v = null;
+        if (HOME.equals(button)) {
+            v = inflater.inflate(R.layout.home, parent, false);
+            if (landscape && isSw600Dp()) {
+                setupLandButton(v);
+            }
+        } else if (BACK.equals(button)) {
+            v = inflater.inflate(R.layout.back, parent, false);
+            if (landscape && isSw600Dp()) {
+                setupLandButton(v);
+            }
+        } else if (RECENT.equals(button)) {
+            v = inflater.inflate(R.layout.recent_apps, parent, false);
+            if (landscape && isSw600Dp()) {
+                setupLandButton(v);
+            }
+        } else if (MENU_IME.equals(button)) {
+            v = inflater.inflate(R.layout.menu_ime, parent, false);
+        } else if (NAVSPACE.equals(button)) {
+            v = inflater.inflate(R.layout.nav_key_space, parent, false);
+        } else if (CLIPBOARD.equals(button)) {
+            v = inflater.inflate(R.layout.clipboard, parent, false);
+        } else if (button.startsWith(KEY)) {
+            String uri = extractImage(button);
+            int code = extractKeycode(button);
+            v = inflater.inflate(R.layout.custom_key, parent, false);
+            ((KeyButtonView) v).setCode(code);
+            if (uri != null) {
+                ((KeyButtonView) v).loadAsync(uri);
+            }
+        } else {
+            return null;
+        }
+
+        if (size != 0) {
+            ViewGroup.LayoutParams params = v.getLayoutParams();
+            params.width = (int) (params.width * size);
+        }
+        parent.addView(v);
+        addToDispatchers(v);
+        return v;
+    }
+
+    public static String extractImage(String buttonSpec) {
+        if (!buttonSpec.contains(KEY_IMAGE_DELIM)) {
+            return null;
+        }
+        final int start = buttonSpec.indexOf(KEY_IMAGE_DELIM);
+        String subStr = buttonSpec.substring(start + 1, buttonSpec.indexOf(KEY_CODE_END));
+        return subStr;
+    }
+
+    public static int extractKeycode(String buttonSpec) {
+        if (!buttonSpec.contains(KEY_CODE_START)) {
+            return 1;
+        }
+        final int start = buttonSpec.indexOf(KEY_CODE_START);
+        String subStr = buttonSpec.substring(start + 1, buttonSpec.indexOf(KEY_IMAGE_DELIM));
+        return Integer.parseInt(subStr);
+    }
+
+    public static float extractSize(String buttonSpec) {
+        if (!buttonSpec.contains(SIZE_MOD_START)) {
+            return 1;
+        }
+        final int sizeStart = buttonSpec.indexOf(SIZE_MOD_START);
+        String sizeStr = buttonSpec.substring(sizeStart + 1, buttonSpec.indexOf(SIZE_MOD_END));
+        return Float.parseFloat(sizeStr);
+    }
+
+    public static String extractButton(String buttonSpec) {
+        if (!buttonSpec.contains(SIZE_MOD_START)) {
+            return buttonSpec;
+        }
+        return buttonSpec.substring(0, buttonSpec.indexOf(SIZE_MOD_START));
+    }
+
+    private void addToDispatchers(View v) {
+        if (mButtonDispatchers != null) {
+            final int indexOfKey = mButtonDispatchers.indexOfKey(v.getId());
+            if (indexOfKey >= 0) {
+                mButtonDispatchers.valueAt(indexOfKey).addView(v);
+            }
+        }
+    }
+
+    private boolean isSw600Dp() {
+        Configuration configuration = mContext.getResources().getConfiguration();
+        return (configuration.smallestScreenWidthDp >= 600);
+    }
+
+    /**
+     * This manually sets the width of sw600dp landscape buttons because despite
+     * overriding the configuration from the overridden resources aren't loaded currently.
+     */
+    private void setupLandButton(View v) {
+        Resources res = mContext.getResources();
+        v.getLayoutParams().width = res.getDimensionPixelOffset(
+                R.dimen.navigation_key_width_sw600dp_land);
+        int padding = res.getDimensionPixelOffset(R.dimen.navigation_key_padding_sw600dp_land);
+        v.setPadding(padding, v.getPaddingTop(), padding, v.getPaddingBottom());
+    }
+
+    private void clearViews() {
+        if (mButtonDispatchers != null) {
+            for (int i = 0; i < mButtonDispatchers.size(); i++) {
+                mButtonDispatchers.valueAt(i).clear();
+            }
+        }
+        clearAllChildren((ViewGroup) mRot0.findViewById(R.id.nav_buttons));
+        clearAllChildren((ViewGroup) mRot0.findViewById(R.id.lights_out));
+        clearAllChildren((ViewGroup) mRot90.findViewById(R.id.nav_buttons));
+        clearAllChildren((ViewGroup) mRot90.findViewById(R.id.lights_out));
+    }
+
+    private void clearAllChildren(ViewGroup group) {
+        for (int i = 0; i < group.getChildCount(); i++) {
+            ((ViewGroup) group.getChildAt(i)).removeAllViews();
+        }
+    }
+}
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 cddb1fc..d86629f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -21,6 +21,7 @@
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
+import android.annotation.Nullable;
 import android.app.ActivityManagerNative;
 import android.app.StatusBarManager;
 import android.content.Context;
@@ -34,23 +35,22 @@
 import android.os.RemoteException;
 import android.util.AttributeSet;
 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;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
 import android.view.inputmethod.InputMethodManager;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
 import android.widget.LinearLayout;
-
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.policy.DeadZone;
-import com.android.systemui.statusbar.policy.KeyButtonView;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -67,7 +67,6 @@
     View mCurrentView = null;
     View[] mRotatedViews = new View[4];
 
-    int mBarSize;
     boolean mVertical;
     boolean mScreenOn;
 
@@ -76,6 +75,9 @@
     int mNavigationIconHints = 0;
 
     private Drawable mBackIcon, mBackLandIcon, mBackAltIcon, mBackAltLandIcon;
+    private Drawable mBackCarModeIcon, mBackLandCarModeIcon;
+    private Drawable mBackAltCarModeIcon, mBackAltLandCarModeIcon;
+    private Drawable mHomeDefaultIcon, mHomeCarModeIcon;
     private Drawable mRecentIcon;
     private Drawable mRecentLandIcon;
 
@@ -94,6 +96,9 @@
     private boolean mIsLayoutRtl;
     private boolean mLayoutTransitionsEnabled = true;
     private boolean mWakeAndUnlocking;
+    private boolean mCarMode = false;
+
+    private final SparseArray<ButtonDispatcher> mButtonDisatchers = new SparseArray<>();
 
     private class NavTransitionListener implements TransitionListener {
         private boolean mBackTransitioning;
@@ -126,12 +131,14 @@
         }
 
         public void onBackAltCleared() {
+            ButtonDispatcher backButton = getBackButton();
+
             // When dismissing ime during unlock, force the back button to run the same appearance
             // animation as home (if we catch this condition early enough).
-            if (!mBackTransitioning && getBackButton().getVisibility() == VISIBLE
+            if (!mBackTransitioning && backButton.getVisibility() == VISIBLE
                     && mHomeAppearing && getHomeButton().getAlpha() == 0) {
                 getBackButton().setAlpha(0);
-                ValueAnimator a = ObjectAnimator.ofFloat(getBackButton(), "alpha", 0, 1);
+                ValueAnimator a = ObjectAnimator.ofFloat(backButton, "alpha", 0, 1);
                 a.setStartDelay(mStartDelay);
                 a.setDuration(mDuration);
                 a.setInterpolator(mInterpolator);
@@ -155,8 +162,8 @@
                     final String how = "" + m.obj;
                     final int w = getWidth();
                     final int h = getHeight();
-                    final int vw = mCurrentView.getWidth();
-                    final int vh = mCurrentView.getHeight();
+                    final int vw = getCurrentView().getWidth();
+                    final int vh = getCurrentView().getHeight();
 
                     if (h != vh || w != vw) {
                         Log.w(TAG, String.format(
@@ -174,18 +181,23 @@
     public NavigationBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
-        mDisplay = ((WindowManager)context.getSystemService(
+        mDisplay = ((WindowManager) context.getSystemService(
                 Context.WINDOW_SERVICE)).getDefaultDisplay();
 
         final Resources res = getContext().getResources();
-        mBarSize = res.getDimensionPixelSize(R.dimen.navigation_bar_size);
         mVertical = false;
         mShowMenu = false;
         mGestureHelper = new NavigationBarGestureHelper(context);
 
-        getIcons(res);
+        getIcons(context);
 
         mBarTransitions = new NavigationBarTransitions(this);
+
+        mButtonDisatchers.put(R.id.back, new ButtonDispatcher(R.id.back));
+        mButtonDisatchers.put(R.id.home, new ButtonDispatcher(R.id.home));
+        mButtonDisatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps));
+        mButtonDisatchers.put(R.id.menu, new ButtonDispatcher(R.id.menu));
+        mButtonDisatchers.put(R.id.ime_switcher, new ButtonDispatcher(R.id.ime_switcher));
     }
 
     public BarTransitions getBarTransitions() {
@@ -193,7 +205,7 @@
     }
 
     public void setComponents(RecentsComponent recentsComponent, Divider divider) {
-        mGestureHelper.setComponents(recentsComponent, divider);
+        mGestureHelper.setComponents(recentsComponent, divider, this);
     }
 
     public void setOnVerticalChangedListener(OnVerticalChangedListener onVerticalChangedListener) {
@@ -227,42 +239,54 @@
         return mCurrentView;
     }
 
-    public View getRecentsButton() {
-        return mCurrentView.findViewById(R.id.recent_apps);
+    public View[] getAllViews() {
+        return mRotatedViews;
     }
 
-    public View getMenuButton() {
-        return mCurrentView.findViewById(R.id.menu);
+    public ButtonDispatcher getRecentsButton() {
+        return mButtonDisatchers.get(R.id.recent_apps);
     }
 
-    public View getBackButton() {
-        return mCurrentView.findViewById(R.id.back);
+    public ButtonDispatcher getMenuButton() {
+        return mButtonDisatchers.get(R.id.menu);
     }
 
-    public KeyButtonView getHomeButton() {
-        return (KeyButtonView) mCurrentView.findViewById(R.id.home);
+    public ButtonDispatcher getBackButton() {
+        return mButtonDisatchers.get(R.id.back);
     }
 
-    public View getImeSwitchButton() {
-        return mCurrentView.findViewById(R.id.ime_switcher);
+    public ButtonDispatcher getHomeButton() {
+        return mButtonDisatchers.get(R.id.home);
     }
 
-    public View getAppShelf() {
-        return mCurrentView.findViewById(R.id.app_shelf);
+    public ButtonDispatcher getImeSwitchButton() {
+        return mButtonDisatchers.get(R.id.ime_switcher);
     }
 
-    private void getIcons(Resources res) {
-        mBackIcon = res.getDrawable(R.drawable.ic_sysbar_back);
+    private void getCarModeIcons(Context ctx) {
+        mBackCarModeIcon = ctx.getDrawable(R.drawable.ic_sysbar_back_carmode);
+        mBackLandCarModeIcon = mBackCarModeIcon;
+        mBackAltCarModeIcon = ctx.getDrawable(R.drawable.ic_sysbar_back_ime_carmode);
+        mBackAltLandCarModeIcon = mBackAltCarModeIcon;
+        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 = res.getDrawable(R.drawable.ic_sysbar_back_ime);
+        mBackAltIcon = ctx.getDrawable(R.drawable.ic_sysbar_back_ime);
         mBackAltLandIcon = mBackAltIcon;
-        mRecentIcon = res.getDrawable(R.drawable.ic_sysbar_recent);
+
+        mHomeDefaultIcon = ctx.getDrawable(R.drawable.ic_sysbar_home);
+
+        mRecentIcon = ctx.getDrawable(R.drawable.ic_sysbar_recent);
         mRecentLandIcon = mRecentIcon;
+        getCarModeIcons(ctx);
     }
 
     @Override
     public void setLayoutDirection(int layoutDirection) {
-        getIcons(getContext().getResources());
+        getIcons(getContext());
 
         super.setLayoutDirection(layoutDirection);
     }
@@ -276,6 +300,18 @@
         setNavigationIconHints(hints, false);
     }
 
+    private Drawable getBackIconWithAlt(boolean carMode, boolean landscape) {
+        return landscape
+                ? carMode ? mBackAltLandCarModeIcon : mBackAltLandIcon
+                : carMode ? mBackAltCarModeIcon : mBackAltIcon;
+    }
+
+    private Drawable getBackIcon(boolean carMode, boolean landscape) {
+        return landscape
+                ? carMode ? mBackLandCarModeIcon : mBackLandIcon
+                : carMode ? mBackCarModeIcon : mBackIcon;
+    }
+
     public void setNavigationIconHints(int hints, boolean force) {
         if (!force && hints == mNavigationIconHints) return;
         final boolean backAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
@@ -290,18 +326,30 @@
 
         mNavigationIconHints = hints;
 
-        ((ImageView)getBackButton()).setImageDrawable(backAlt
-                ? (mVertical ? mBackAltLandIcon : mBackAltIcon)
-                : (mVertical ? mBackLandIcon : mBackIcon));
+        // We have to replace or restore the back and home button icons when exiting or entering
+        // carmode, respectively. Recents are not available in CarMode in nav bar so change
+        // to recent icon is not required.
+        Drawable backIcon = (backAlt)
+                ? getBackIconWithAlt(mCarMode, mVertical)
+                : getBackIcon(mCarMode, mVertical);
 
-        ((ImageView)getRecentsButton()).setImageDrawable(mVertical ? mRecentLandIcon : mRecentIcon);
+        getBackButton().setImageDrawable(backIcon);
+
+        getRecentsButton().setImageDrawable(
+                mVertical ? mRecentLandIcon : mRecentIcon);
+
+        if (mCarMode) {
+            getHomeButton().setImageDrawable(mHomeCarModeIcon);
+        } else {
+            getHomeButton().setImageDrawable(mHomeDefaultIcon);
+        }
 
         final boolean showImeButton = ((hints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
         getImeSwitchButton().setVisibility(showImeButton ? View.VISIBLE : View.INVISIBLE);
+
         // Update menu button in case the IME state has changed.
         setMenuVisibility(mShowMenu, true);
 
-
         setDisabledFlags(mDisabledFlags, true);
     }
 
@@ -324,7 +372,7 @@
             setSlippery(disableHome && disableRecent && disableBack && disableSearch);
         }
 
-        ViewGroup navButtons = (ViewGroup) mCurrentView.findViewById(R.id.nav_buttons);
+        ViewGroup navButtons = (ViewGroup) getCurrentView().findViewById(R.id.nav_buttons);
         if (navButtons != null) {
             LayoutTransition lt = navButtons.getLayoutTransition();
             if (lt != null) {
@@ -339,15 +387,9 @@
             disableRecent = false;
         }
 
-        getBackButton()   .setVisibility(disableBack       ? View.INVISIBLE : View.VISIBLE);
-        getHomeButton()   .setVisibility(disableHome       ? View.INVISIBLE : View.VISIBLE);
-        getRecentsButton().setVisibility(disableRecent     ? View.INVISIBLE : View.VISIBLE);
-
-        // The app shelf, if it exists, follows the visibility of the home button.
-        View appShelf = getAppShelf();
-        if (appShelf != null) {
-            appShelf.setVisibility(disableHome ? View.INVISIBLE : View.VISIBLE);
-        }
+        getBackButton().setVisibility(disableBack      ? View.INVISIBLE : View.VISIBLE);
+        getHomeButton().setVisibility(disableHome      ? View.INVISIBLE : View.VISIBLE);
+        getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
     }
 
     private boolean inLockTask() {
@@ -358,12 +400,6 @@
         }
     }
 
-    private void setVisibleOrGone(View view, boolean visible) {
-        if (view != null) {
-            view.setVisibility(visible ? VISIBLE : GONE);
-        }
-    }
-
     public void setLayoutTransitionsEnabled(boolean enabled) {
         mLayoutTransitionsEnabled = enabled;
         updateLayoutTransitionsEnabled();
@@ -377,7 +413,7 @@
 
     private void updateLayoutTransitionsEnabled() {
         boolean enabled = !mWakeAndUnlocking && mLayoutTransitionsEnabled;
-        ViewGroup navButtons = (ViewGroup) mCurrentView.findViewById(R.id.nav_buttons);
+        ViewGroup navButtons = (ViewGroup) getCurrentView().findViewById(R.id.nav_buttons);
         LayoutTransition lt = navButtons.getLayoutTransition();
         if (lt != null) {
             if (enabled) {
@@ -438,6 +474,7 @@
         // Only show Menu if IME switcher not shown.
         final boolean shouldShow = mShowMenu &&
                 ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) == 0);
+
         getMenuButton().setVisibility(shouldShow ? View.VISIBLE : View.INVISIBLE);
     }
 
@@ -451,10 +488,41 @@
         mRotatedViews[Surface.ROTATION_270] = mRotatedViews[Surface.ROTATION_90];
 
         mCurrentView = mRotatedViews[Surface.ROTATION_0];
+        for (int i = 0; i < mButtonDisatchers.size(); i++) {
+            mButtonDisatchers.valueAt(i).setCurrentView(mCurrentView);
+        }
+        ((NavigationBarInflaterView) findViewById(R.id.navigation_inflater)).setButtonDispatchers(
+                mButtonDisatchers);
 
         getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
 
         updateRTLOrder();
+
+        try {
+            WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(new Stub() {
+                @Override
+                public void onDividerVisibilityChanged(boolean visible) throws RemoteException {
+                }
+
+                @Override
+                public void onDockedStackExistsChanged(final boolean exists) throws RemoteException {
+                    mHandler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            updateRecentsIcon(exists);
+                        }
+                    });
+                }
+            });
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed registering docked stack exists listener", e);
+        }
+    }
+
+    private void updateRecentsIcon(boolean dockedStackExists) {
+        getRecentsButton().setImageResource(dockedStackExists
+                ? R.drawable.ic_sysbar_docked
+                : R.drawable.ic_sysbar_recent);
     }
 
     public boolean isVertical() {
@@ -468,6 +536,9 @@
         }
         mCurrentView = mRotatedViews[rot];
         mCurrentView.setVisibility(View.VISIBLE);
+        for (int i = 0; i < mButtonDisatchers.size(); i++) {
+            mButtonDisatchers.valueAt(i).setCurrentView(mCurrentView);
+        }
         updateLayoutTransitionsEnabled();
 
         getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
@@ -518,8 +589,33 @@
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
+        boolean uiCarModeChanged = updateCarMode(newConfig);
         updateRTLOrder();
         updateTaskSwitchHelper();
+        if (uiCarModeChanged) {
+            // uiMode changed either from carmode or to carmode.
+            // replace the nav bar button icons based on which mode
+            // we are switching to.
+            setNavigationIconHints(mNavigationIconHints, true);
+        }
+    }
+
+    /**
+     * If the configuration changed, update the carmode and return that it was updated.
+     */
+    private boolean updateCarMode(Configuration newConfig) {
+        boolean uiCarModeChanged = false;
+        if (newConfig != null) {
+            int uiMode = newConfig.uiMode & Configuration.UI_MODE_TYPE_MASK;
+            if (mCarMode && uiMode != Configuration.UI_MODE_TYPE_CAR) {
+                mCarMode = false;
+                uiCarModeChanged = true;
+            } else if (uiMode == Configuration.UI_MODE_TYPE_CAR) {
+                mCarMode = true;
+                uiCarModeChanged = true;
+            }
+        }
+        return uiCarModeChanged;
     }
 
     /**
@@ -533,33 +629,16 @@
 
             // We swap all children of the 90 and 270 degree layouts, since they are vertical
             View rotation90 = mRotatedViews[Surface.ROTATION_90];
-            swapChildrenOrderIfVertical(rotation90.findViewById(R.id.nav_buttons));
-            adjustExtraKeyGravity(rotation90, isLayoutRtl);
+            swapChildrenOrderIfVertical(rotation90);
 
             View rotation270 = mRotatedViews[Surface.ROTATION_270];
             if (rotation90 != rotation270) {
-                swapChildrenOrderIfVertical(rotation270.findViewById(R.id.nav_buttons));
-                adjustExtraKeyGravity(rotation270, isLayoutRtl);
+                swapChildrenOrderIfVertical(rotation270);
             }
             mIsLayoutRtl = isLayoutRtl;
         }
     }
 
-    private void adjustExtraKeyGravity(View navBar, boolean isLayoutRtl) {
-        View menu = navBar.findViewById(R.id.menu);
-        View imeSwitcher = navBar.findViewById(R.id.ime_switcher);
-        if (menu != null) {
-            FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) menu.getLayoutParams();
-            lp.gravity = isLayoutRtl ? Gravity.BOTTOM : Gravity.TOP;
-            menu.setLayoutParams(lp);
-        }
-        if (imeSwitcher != null) {
-            FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) imeSwitcher.getLayoutParams();
-            lp.gravity = isLayoutRtl ? Gravity.BOTTOM : Gravity.TOP;
-            imeSwitcher.setLayoutParams(lp);
-        }
-    }
-
     /**
      * Swaps the children order of a LinearLayout if it's orientation is Vertical
      *
@@ -569,6 +648,11 @@
         if (group instanceof LinearLayout) {
             LinearLayout linearLayout = (LinearLayout) group;
             if (linearLayout.getOrientation() == VERTICAL) {
+                if ((linearLayout.getGravity() & Gravity.TOP) != 0) {
+                    linearLayout.setGravity(Gravity.BOTTOM);
+                } else if ((linearLayout.getGravity() & Gravity.BOTTOM) != 0) {
+                    linearLayout.setGravity(Gravity.TOP);
+                }
                 int childCount = linearLayout.getChildCount();
                 ArrayList<View> childList = new ArrayList<>(childCount);
                 for (int i = 0; i < childCount; i++) {
@@ -579,6 +663,11 @@
                     linearLayout.addView(childList.get(i));
                 }
             }
+        } else if (group instanceof ViewGroup) {
+            ViewGroup viewGroup = (ViewGroup) group;
+            for (int i = 0; i < viewGroup.getChildCount(); i++) {
+                swapChildrenOrderIfVertical(viewGroup.getChildAt(i));
+            }
         }
     }
 
@@ -666,13 +755,12 @@
         pw.println("    }");
     }
 
-    private static void dumpButton(PrintWriter pw, String caption, View button) {
+    private static void dumpButton(PrintWriter pw, String caption, ButtonDispatcher button) {
         pw.print("      " + caption + ": ");
         if (button == null) {
             pw.print("null");
         } else {
-            pw.print(PhoneStatusBar.viewInfo(button)
-                    + " " + visibilityToString(button.getVisibility())
+            pw.print(visibilityToString(button.getVisibility())
                     + " alpha=" + button.getAlpha()
                     );
         }
@@ -682,4 +770,5 @@
     public interface OnVerticalChangedListener {
         void onVerticalChanged(boolean isVertical);
     }
+
 }
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 f6fc259..3130eb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -16,12 +16,13 @@
 
 package com.android.systemui.statusbar.phone;
 
-import android.app.Notification;
 import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
 
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import java.util.HashMap;
 import java.util.HashSet;
@@ -29,18 +30,19 @@
 /**
  * A class to handle notifications and their corresponding groups.
  */
-public class NotificationGroupManager {
+public class NotificationGroupManager implements HeadsUpManager.OnHeadsUpChangedListener {
 
     private final HashMap<String, NotificationGroup> mGroupMap = new HashMap<>();
     private OnGroupChangeListener mListener;
     private int mBarState = -1;
+    private ArraySet<String> mHeadsUpedEntries = new ArraySet<>();
 
     public void setOnGroupChangeListener(OnGroupChangeListener listener) {
         mListener = listener;
     }
 
     public boolean isGroupExpanded(StatusBarNotification sbn) {
-        NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
+        NotificationGroup group = mGroupMap.get(getGroupKey(sbn));
         if (group == null) {
             return false;
         }
@@ -48,7 +50,7 @@
     }
 
     public void setGroupExpanded(StatusBarNotification sbn, boolean expanded) {
-        NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
+        NotificationGroup group = mGroupMap.get(getGroupKey(sbn));
         if (group == null) {
             return;
         }
@@ -75,8 +77,7 @@
      */
     private void onEntryRemovedInternal(NotificationData.Entry removed,
             final StatusBarNotification sbn) {
-        Notification notif = sbn.getNotification();
-        String groupKey = sbn.getGroupKey();
+        String groupKey = getGroupKey(sbn);
         final NotificationGroup group = mGroupMap.get(groupKey);
         if (group == null) {
             // When an app posts 2 different notifications as summary of the same group, then a
@@ -85,7 +86,7 @@
             // the close future. See b/23676310 for reference.
             return;
         }
-        if (notif.isGroupChild()) {
+        if (isGroupChild(sbn)) {
             group.children.remove(removed);
         } else {
             group.summary = null;
@@ -97,16 +98,16 @@
         }
     }
 
-    public void onEntryAdded(NotificationData.Entry added) {
-        StatusBarNotification sbn = added.notification;
-        Notification notif = sbn.getNotification();
-        String groupKey = sbn.getGroupKey();
+    public void onEntryAdded(final NotificationData.Entry added) {
+        final StatusBarNotification sbn = added.notification;
+        boolean isGroupChild = isGroupChild(sbn);
+        String groupKey = getGroupKey(sbn);
         NotificationGroup group = mGroupMap.get(groupKey);
         if (group == null) {
             group = new NotificationGroup();
             mGroupMap.put(groupKey, group);
         }
-        if (notif.isGroupChild()) {
+        if (isGroupChild) {
             group.children.add(added);
         } else {
             group.summary = added;
@@ -119,17 +120,17 @@
 
     public void onEntryUpdated(NotificationData.Entry entry,
             StatusBarNotification oldNotification) {
-        if (mGroupMap.get(oldNotification.getGroupKey()) != null) {
+        if (mGroupMap.get(getGroupKey(oldNotification)) != null) {
             onEntryRemovedInternal(entry, oldNotification);
         }
         onEntryAdded(entry);
     }
 
     public boolean isVisible(StatusBarNotification sbn) {
-        if (!sbn.getNotification().isGroupChild()) {
+        if (!isGroupChild(sbn)) {
             return true;
         }
-        NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
+        NotificationGroup group = mGroupMap.get(getGroupKey(sbn));
         if (group != null && (group.expanded || group.summary == null)) {
             return true;
         }
@@ -137,10 +138,10 @@
     }
 
     public boolean hasGroupChildren(StatusBarNotification sbn) {
-        if (!sbn.getNotification().isGroupSummary()) {
+        if (!isGroupSummary(sbn)) {
             return false;
         }
-        NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
+        NotificationGroup group = mGroupMap.get(getGroupKey(sbn));
         if (group == null) {
             return false;
         }
@@ -165,10 +166,10 @@
      * @return whether a given notification is a child in a group which has a summary
      */
     public boolean isChildInGroupWithSummary(StatusBarNotification sbn) {
-        if (!sbn.getNotification().isGroupChild()) {
+        if (!isGroupChild(sbn)) {
             return false;
         }
-        NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
+        NotificationGroup group = mGroupMap.get(getGroupKey(sbn));
         if (group == null || group.summary == null) {
             return false;
         }
@@ -179,10 +180,10 @@
      * @return whether a given notification is a summary in a group which has children
      */
     public boolean isSummaryOfGroup(StatusBarNotification sbn) {
-        if (!sbn.getNotification().isGroupSummary()) {
+        if (!isGroupSummary(sbn)) {
             return false;
         }
-        NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
+        NotificationGroup group = mGroupMap.get(getGroupKey(sbn));
         if (group == null) {
             return false;
         }
@@ -190,24 +191,88 @@
     }
 
     public ExpandableNotificationRow getGroupSummary(StatusBarNotification sbn) {
-        NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
+        NotificationGroup group = mGroupMap.get(getGroupKey(sbn));
         return group == null ? null
                 : group.summary == null ? null
                 : group.summary.row;
     }
 
-    public void onEntryHeadsUped(NotificationData.Entry headsUp) {
-        // TODO: handle this nicely
-    }
-
     public void toggleGroupExpansion(StatusBarNotification sbn) {
-        NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
+        NotificationGroup group = mGroupMap.get(getGroupKey(sbn));
         if (group == null) {
             return;
         }
         setGroupExpanded(group, !group.expanded);
     }
 
+    private boolean isIsolated(StatusBarNotification sbn) {
+        return mHeadsUpedEntries.contains(sbn.getKey()) && sbn.getNotification().isGroupChild();
+    }
+
+    private boolean isGroupSummary(StatusBarNotification sbn) {
+        if (isIsolated(sbn)) {
+            return true;
+        }
+        return sbn.getNotification().isGroupSummary();
+    }
+    private boolean isGroupChild(StatusBarNotification sbn) {
+        if (isIsolated(sbn)) {
+            return false;
+        }
+        return sbn.getNotification().isGroupChild();
+    }
+
+    private String getGroupKey(StatusBarNotification sbn) {
+        if (isIsolated(sbn)) {
+            return sbn.getKey();
+        }
+        return sbn.getGroupKey();
+    }
+
+    @Override
+    public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
+    }
+
+    @Override
+    public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
+    }
+
+    @Override
+    public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
+    }
+
+    @Override
+    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();
+                }
+            }
+        } 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();
+                }
+            }
+        }
+    }
+
     public static class NotificationGroup {
         public final HashSet<NotificationData.Entry> children = new HashSet<>();
         public NotificationData.Entry summary;
@@ -230,5 +295,10 @@
          * @param group the group created
          */
         void onGroupCreatedFromChildren(NotificationGroup group);
+
+        /**
+         * The isolation of a child has changed i.e it's group changes.
+         */
+        void onChildIsolationChanged();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
new file mode 100644
index 0000000..405ef05
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -0,0 +1,151 @@
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import com.android.internal.util.NotificationColorUtil;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.notification.NotificationUtils;
+
+import java.util.ArrayList;
+
+/**
+ * A controller for the space in the status bar to the left of the system icons. This area is
+ * normally reserved for notifications.
+ */
+public class NotificationIconAreaController {
+    private final NotificationColorUtil mNotificationColorUtil;
+
+    private int mIconSize;
+    private int mIconHPadding;
+    private int mIconTint = Color.WHITE;
+
+    private PhoneStatusBar mPhoneStatusBar;
+    protected View mNotificationIconArea;
+    private IconMerger mNotificationIcons;
+    private ImageView mMoreIcon;
+
+    public NotificationIconAreaController(Context context, PhoneStatusBar phoneStatusBar) {
+        mPhoneStatusBar = phoneStatusBar;
+        mNotificationColorUtil = NotificationColorUtil.getInstance(context);
+
+        initializeNotificationAreaViews(context);
+    }
+
+    /**
+     * Initializes the views that will represent the notification area.
+     */
+    protected void initializeNotificationAreaViews(Context context) {
+        Resources res = context.getResources();
+        mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
+        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));
+
+        mNotificationIcons =
+                (IconMerger) mNotificationIconArea.findViewById(R.id.notificationIcons);
+        mNotificationIcons.setOverflowIndicator(mMoreIcon);
+    }
+
+    /**
+     * Returns the view that represents the notification area.
+     */
+    public View getNotificationInnerAreaView() {
+        return mNotificationIconArea;
+    }
+
+    /**
+     * Sets the color that should be used to tint any icons in the notification area. If this
+     * method is not called, the default tint is {@link Color#WHITE}.
+     */
+    public void setIconTint(int iconTint) {
+        mIconTint = iconTint;
+        mMoreIcon.setImageTintList(ColorStateList.valueOf(mIconTint));
+        applyNotificationIconsTint();
+    }
+
+    /**
+     * 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());
+
+        ArrayList<NotificationData.Entry> activeNotifications =
+                notificationData.getActiveNotifications();
+        final int size = activeNotifications.size();
+        ArrayList<StatusBarIconView> toShow = new ArrayList<>(size);
+
+        // 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 (!PhoneStatusBar.isTopLevelChild(ent)) {
+                continue;
+            }
+            toShow.add(ent.icon);
+        }
+
+        ArrayList<View> toRemove = new ArrayList<>();
+        for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
+            View child = mNotificationIcons.getChildAt(i);
+            if (!toShow.contains(child)) {
+                toRemove.add(child);
+            }
+        }
+
+        final int toRemoveCount = toRemove.size();
+        for (int i = 0; i < toRemoveCount; i++) {
+            mNotificationIcons.removeView(toRemove.get(i));
+        }
+
+        for (int i = 0; i < toShow.size(); i++) {
+            View v = toShow.get(i);
+            if (v.getParent() == null) {
+                mNotificationIcons.addView(v, i, params);
+            }
+        }
+
+        // Re-sort notification icons
+        final int childCount = mNotificationIcons.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View actual = mNotificationIcons.getChildAt(i);
+            StatusBarIconView expected = toShow.get(i);
+            if (actual == expected) {
+                continue;
+            }
+            mNotificationIcons.removeView(expected);
+            mNotificationIcons.addView(expected, i);
+        }
+
+        applyNotificationIconsTint();
+    }
+
+    /**
+     * Applies {@link #mIconTint} to the notification icons.
+     */
+    private void applyNotificationIconsTint() {
+        for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
+            StatusBarIconView v = (StatusBarIconView) mNotificationIcons.getChildAt(i);
+            boolean isPreL = Boolean.TRUE.equals(v.getTag(R.id.icon_is_pre_L));
+            boolean colorize = !isPreL || NotificationUtils.isGrayscale(v, mNotificationColorUtil);
+            if (colorize) {
+                v.setImageTintList(ColorStateList.valueOf(mIconTint));
+            }
+        }
+    }
+}
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 42fd872..8e89efd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -39,11 +39,11 @@
 import android.view.ViewTreeObserver;
 import android.view.WindowInsets;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
 import android.widget.FrameLayout;
 import android.widget.TextView;
+
 import com.android.internal.logging.MetricsLogger;
 import com.android.keyguard.KeyguardStatusView;
 import com.android.systemui.DejankUtils;
@@ -57,6 +57,7 @@
 import com.android.systemui.statusbar.ExpandableView;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 import com.android.systemui.statusbar.GestureRecorder;
+import com.android.systemui.statusbar.Interpolators;
 import com.android.systemui.statusbar.KeyguardAffordanceView;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.StatusBarState;
@@ -104,7 +105,6 @@
     private View mQsNavbarScrim;
     private NotificationsQuickSettingsContainer mNotificationContainerParent;
     private NotificationStackScrollLayout mNotificationStackScroller;
-    private int mNotificationTopPadding;
     private boolean mAnimateNextTopPaddingChange;
 
     private int mTrackingPointer;
@@ -151,9 +151,6 @@
     private int mUnlockMoveDistance;
     private float mEmptyDragAmount;
 
-    private Interpolator mFastOutSlowInInterpolator;
-    private Interpolator mFastOutLinearInterpolator;
-    private Interpolator mDozeAnimationInterpolator;
     private ObjectAnimator mClockAnimator;
     private int mClockAnimationTarget = -1;
     private int mTopPaddingAdjustment;
@@ -253,12 +250,6 @@
         mNotificationStackScroller.setOverscrollTopChangedListener(this);
         mNotificationStackScroller.setOnEmptySpaceClickListener(this);
         mNotificationStackScroller.setScrollView(mScrollView);
-        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
-                android.R.interpolator.fast_out_slow_in);
-        mFastOutLinearInterpolator = AnimationUtils.loadInterpolator(getContext(),
-                android.R.interpolator.fast_out_linear_in);
-        mDozeAnimationInterpolator = AnimationUtils.loadInterpolator(getContext(),
-                android.R.interpolator.linear_out_slow_in);
         mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area);
         mQsNavbarScrim = findViewById(R.id.qs_navbar_scrim);
         mAfforanceHelper = new KeyguardAffordanceHelper(this, getContext());
@@ -281,8 +272,6 @@
     @Override
     protected void loadDimens() {
         super.loadDimens();
-        mNotificationTopPadding = getResources().getDimensionPixelSize(
-                R.dimen.notifications_top_padding);
         mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.4f);
         mStatusBarMinHeight = getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.status_bar_height);
@@ -371,7 +360,7 @@
         }
         mQsSizeChangeAnimator = ValueAnimator.ofInt(oldHeight, newHeight);
         mQsSizeChangeAnimator.setDuration(300);
-        mQsSizeChangeAnimator.setInterpolator(mFastOutSlowInInterpolator);
+        mQsSizeChangeAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
         mQsSizeChangeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
@@ -400,8 +389,8 @@
         if (mStatusBarState != StatusBarState.KEYGUARD) {
             int bottom = mHeader.getCollapsedHeight();
             stackScrollerPadding = mStatusBarState == StatusBarState.SHADE
-                    ? bottom + mQsPeekHeight + mNotificationTopPadding
-                    : mKeyguardStatusBar.getHeight() + mNotificationTopPadding;
+                    ? bottom + mQsPeekHeight
+                    : mKeyguardStatusBar.getHeight();
             mTopPaddingAdjustment = 0;
         } else {
             mClockPositionAlgorithm.setup(
@@ -433,8 +422,8 @@
     public int computeMaxKeyguardNotifications(int maximum) {
         float minPadding = mClockPositionAlgorithm.getMinStackScrollerPadding(getHeight(),
                 mKeyguardStatusView.getHeight());
-        int keyguardPadding = getResources().getDimensionPixelSize(
-                R.dimen.notification_padding_dimmed);
+        int notificationPadding = Math.max(1, getResources().getDimensionPixelSize(
+                R.dimen.notification_divider_height));
         final int overflowheight = getResources().getDimensionPixelSize(
                 R.dimen.notification_summary_height);
         float bottomStackSize = mNotificationStackScroller.getKeyguardBottomStackSize();
@@ -446,7 +435,7 @@
             if (!(child instanceof ExpandableNotificationRow)) {
                 continue;
             }
-            availableSpace -= child.getMinHeight() + keyguardPadding;
+            availableSpace -= child.getMinHeight() + notificationPadding;
             if (availableSpace >= 0 && count < maximum) {
                 count++;
             } else {
@@ -471,7 +460,7 @@
                 }
                 mClockAnimator = ObjectAnimator
                         .ofFloat(mKeyguardStatusView, View.Y, mClockAnimationTarget);
-                mClockAnimator.setInterpolator(mFastOutSlowInInterpolator);
+                mClockAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
                 mClockAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
                 mClockAnimator.addListener(new AnimatorListenerAdapter() {
                     @Override
@@ -1107,7 +1096,7 @@
                     .translationY(0f)
                     .setStartDelay(delay)
                     .setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE)
-                    .setInterpolator(mFastOutSlowInInterpolator)
+                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
                     .start();
             mQsContainer.setY(-mQsContainer.getHeight());
             mQsContainerAnimator = ObjectAnimator.ofFloat(mQsContainer, View.TRANSLATION_Y,
@@ -1116,7 +1105,7 @@
                             - mQsContainer.getTop());
             mQsContainerAnimator.setStartDelay(delay);
             mQsContainerAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
-            mQsContainerAnimator.setInterpolator(mFastOutSlowInInterpolator);
+            mQsContainerAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
             mQsContainerAnimator.addListener(mAnimateHeaderSlidingInListener);
             mQsContainerAnimator.start();
             mQsContainer.addOnLayoutChangeListener(mQsContainerAnimatorUpdater);
@@ -1138,7 +1127,7 @@
         mHeader.animate().y(-mHeader.getHeight())
                 .setStartDelay(0)
                 .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
-                .setInterpolator(mFastOutSlowInInterpolator)
+                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
                 .setListener(new AnimatorListenerAdapter() {
                     @Override
                     public void onAnimationEnd(Animator animation) {
@@ -1152,7 +1141,7 @@
                 .y(-mQsContainer.getHeight())
                 .setStartDelay(0)
                 .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
-                .setInterpolator(mFastOutSlowInInterpolator)
+                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
                 .start();
     }
 
@@ -1174,7 +1163,7 @@
         anim.setDuration(mStatusBar.isKeyguardFadingAway()
                 ? mStatusBar.getKeyguardFadingAwayDuration() / 2
                 : StackStateAnimator.ANIMATION_DURATION_STANDARD);
-        anim.setInterpolator(mDozeAnimationInterpolator);
+        anim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
         anim.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
@@ -1199,7 +1188,7 @@
         ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
         anim.addUpdateListener(mStatusBarAnimateAlphaListener);
         anim.setDuration(duration);
-        anim.setInterpolator(mDozeAnimationInterpolator);
+        anim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
         anim.start();
     }
 
@@ -1218,7 +1207,7 @@
                     .alpha(0f)
                     .setStartDelay(mStatusBar.getKeyguardFadingAwayDelay())
                     .setDuration(mStatusBar.getKeyguardFadingAwayDuration() / 2)
-                    .setInterpolator(PhoneStatusBar.ALPHA_OUT)
+                    .setInterpolator(Interpolators.ALPHA_OUT)
                     .withEndAction(mAnimateKeyguardBottomAreaInvisibleEndRunnable)
                     .start();
         } else if (statusBarState == StatusBarState.KEYGUARD
@@ -1245,7 +1234,7 @@
                     .alpha(0f)
                     .setStartDelay(0)
                     .setDuration(160)
-                    .setInterpolator(PhoneStatusBar.ALPHA_OUT)
+                    .setInterpolator(Interpolators.ALPHA_OUT)
                     .withEndAction(mAnimateKeyguardStatusViewInvisibleEndRunnable);
             if (keyguardFadingAway) {
                 mKeyguardStatusView.animate()
@@ -1263,7 +1252,7 @@
                     .alpha(1f)
                     .setStartDelay(0)
                     .setDuration(320)
-                    .setInterpolator(PhoneStatusBar.ALPHA_IN)
+                    .setInterpolator(Interpolators.ALPHA_IN)
                     .withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable);
         } else if (statusBarState == StatusBarState.KEYGUARD) {
             mKeyguardStatusView.animate().cancel();
@@ -1318,7 +1307,6 @@
         mHeader.setExpansion(getHeaderExpansionFraction());
         setQsTranslation(height);
         requestScrollerTopPaddingUpdate(false /* animate */);
-        updateNotificationScrim(height);
         if (mKeyguardShowing) {
             updateHeaderKeyguard();
         }
@@ -1355,12 +1343,6 @@
         }
     }
 
-    private void updateNotificationScrim(float height) {
-        int startDistance = mQsMinExpansionHeight + mNotificationScrimWaitDistance;
-        float progress = (height - startDistance) / (mQsMaxExpansionHeight - startDistance);
-        progress = Math.max(0.0f, Math.min(progress, 1.0f));
-    }
-
     private float getHeaderExpansionFraction() {
         if (!mKeyguardShowing) {
             return getQsExpansionFraction();
@@ -1387,8 +1369,7 @@
             // on Keyguard, maxQs denotes the top padding from the quick settings panel. We need to
             // take the maximum and linearly interpolate with the panel expansion for a nice motion.
             int maxNotifications = mClockPositionResult.stackScrollerPadding
-                    - mClockPositionResult.stackScrollerPaddingAdjustment
-                    - mNotificationTopPadding;
+                    - mClockPositionResult.stackScrollerPaddingAdjustment;
             int maxQs = getTempQsMaxExpansion();
             int max = mStatusBarState == StatusBarState.KEYGUARD
                     ? Math.max(maxNotifications, maxQs)
@@ -1402,7 +1383,7 @@
             // We can only do the smoother transition on Keyguard when we also are not collapsing
             // from a scrolled quick settings.
             return interpolate(getQsExpansionFraction(),
-                    mNotificationStackScroller.getIntrinsicPadding() - mNotificationTopPadding,
+                    mNotificationStackScroller.getIntrinsicPadding(),
                     mQsMaxExpansionHeight);
         } else {
             return mQsExpansionHeight;
@@ -1632,15 +1613,13 @@
             maxQsHeight = (int) mQsSizeChangeAnimator.getAnimatedValue();
         }
         float totalHeight = Math.max(
-                maxQsHeight + mNotificationStackScroller.getNotificationTopPadding(),
-                mStatusBarState == StatusBarState.KEYGUARD
+                maxQsHeight, mStatusBarState == StatusBarState.KEYGUARD
                         ? mClockPositionResult.stackScrollerPadding - mTopPaddingAdjustment
                         : 0)
                 + notificationHeight;
         if (totalHeight > mNotificationStackScroller.getHeight()) {
             float fullyCollapsedHeight = maxQsHeight
                     + mNotificationStackScroller.getMinStackHeight()
-                    + mNotificationStackScroller.getNotificationTopPadding()
                     - getScrollViewScrollY();
             totalHeight = Math.max(fullyCollapsedHeight, mNotificationStackScroller.getHeight());
         }
@@ -1687,14 +1666,14 @@
             boolean active = getMaxPanelHeight() - getExpandedHeight() > mUnlockMoveDistance;
             KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon();
             if (active && !mUnlockIconActive && mTracking) {
-                lockIcon.setImageAlpha(1.0f, true, 150, mFastOutLinearInterpolator, null);
+                lockIcon.setImageAlpha(1.0f, true, 150, Interpolators.FAST_OUT_LINEAR_IN, null);
                 lockIcon.setImageScale(LOCK_ICON_ACTIVE_SCALE, true, 150,
-                        mFastOutLinearInterpolator);
+                        Interpolators.FAST_OUT_LINEAR_IN);
             } else if (!active && mUnlockIconActive && mTracking) {
                 lockIcon.setImageAlpha(lockIcon.getRestingAlpha(), true /* animate */,
-                        150, mFastOutLinearInterpolator, null);
+                        150, Interpolators.FAST_OUT_LINEAR_IN, null);
                 lockIcon.setImageScale(1.0f, true, 150,
-                        mFastOutLinearInterpolator);
+                        Interpolators.FAST_OUT_LINEAR_IN);
             }
             mUnlockIconActive = active;
         }
@@ -1734,7 +1713,7 @@
         float translation = stackTranslation / HEADER_RUBBERBAND_FACTOR;
         if (mHeadsUpManager.hasPinnedHeadsUp() || mIsExpansionFromHeadsUp) {
             translation = mNotificationStackScroller.getTopPadding() + stackTranslation
-                    - mNotificationTopPadding - mQsMinExpansionHeight;
+                    - mQsMinExpansionHeight;
         }
         return Math.min(0, translation);
     }
@@ -1899,8 +1878,8 @@
         if (!expand && (mStatusBar.getBarState() == StatusBarState.KEYGUARD
                 || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED)) {
             KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon();
-            lockIcon.setImageAlpha(0.0f, true, 100, mFastOutLinearInterpolator, null);
-            lockIcon.setImageScale(2.0f, true, 100, mFastOutLinearInterpolator);
+            lockIcon.setImageAlpha(0.0f, true, 100, Interpolators.FAST_OUT_LINEAR_IN, null);
+            lockIcon.setImageScale(2.0f, true, 100, Interpolators.FAST_OUT_LINEAR_IN);
         }
     }
 
@@ -2040,12 +2019,12 @@
      */
     private void startHighlightIconAnimation(final KeyguardAffordanceView icon) {
         icon.setImageAlpha(1.0f, true, KeyguardAffordanceHelper.HINT_PHASE1_DURATION,
-                mFastOutSlowInInterpolator, new Runnable() {
+                Interpolators.FAST_OUT_SLOW_IN, new Runnable() {
                     @Override
                     public void run() {
                         icon.setImageAlpha(icon.getRestingAlpha(),
                                 true /* animate */, KeyguardAffordanceHelper.HINT_PHASE1_DURATION,
-                                mFastOutSlowInInterpolator, null);
+                                Interpolators.FAST_OUT_SLOW_IN, null);
                     }
                 });
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index e1a400d..f2c57e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -23,8 +23,6 @@
 import android.view.View;
 import android.widget.FrameLayout;
 
-import java.util.ArrayList;
-
 public abstract class PanelBar extends FrameLayout {
     public static final boolean DEBUG = false;
     public static final String TAG = PanelBar.class.getSimpleName();
@@ -39,14 +37,10 @@
     public static final int STATE_OPENING = 1;
     public static final int STATE_OPEN = 2;
 
-    PanelHolder mPanelHolder;
-    ArrayList<PanelView> mPanels = new ArrayList<PanelView>();
-    PanelView mTouchingPanel;
+    PanelView mPanel;
     private int mState = STATE_CLOSED;
     private boolean mTracking;
 
-    float mPanelExpandedFractionSum;
-
     public void go(int state) {
         if (DEBUG) LOG("go state: %d -> %d", mState, state);
         mState = state;
@@ -61,55 +55,28 @@
         super.onFinishInflate();
     }
 
-    public void addPanel(PanelView pv) {
-        mPanels.add(pv);
+    public void setPanel(PanelView pv) {
+        mPanel = pv;
         pv.setBar(this);
     }
 
-    public void setPanelHolder(PanelHolder ph) {
-        if (ph == null) {
-            Log.e(TAG, "setPanelHolder: null PanelHolder", new Throwable());
-            return;
-        }
-        ph.setBar(this);
-        mPanelHolder = ph;
-        final int N = ph.getChildCount();
-        for (int i=0; i<N; i++) {
-            final View v = ph.getChildAt(i);
-            if (v != null && v instanceof PanelView) {
-                addPanel((PanelView) v);
-            }
-        }
-    }
-
     public void setBouncerShowing(boolean showing) {
         int important = showing ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
                 : IMPORTANT_FOR_ACCESSIBILITY_AUTO;
 
         setImportantForAccessibility(important);
 
-        if (mPanelHolder != null) {
-            mPanelHolder.setImportantForAccessibility(important);
-        }
+        if (mPanel != null) mPanel.setImportantForAccessibility(important);
     }
 
-    public float getBarHeight() {
-        return getMeasuredHeight();
-    }
-
-    public PanelView selectPanelForTouch(MotionEvent touch) {
-        final int N = mPanels.size();
-        return mPanels.get((int)(N * touch.getX() / getMeasuredWidth()));
-    }
-
-    public boolean panelsEnabled() {
+    public boolean panelEnabled() {
         return true;
     }
 
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         // Allow subclasses to implement enable/disable semantics
-        if (!panelsEnabled()) {
+        if (!panelEnabled()) {
             if (event.getAction() == MotionEvent.ACTION_DOWN) {
                 Log.v(TAG, String.format("onTouch: all panels disabled, ignoring touch at (%d,%d)",
                         (int) event.getX(), (int) event.getY()));
@@ -117,14 +84,12 @@
             return false;
         }
 
-        // figure out which panel needs to be talked to here
         if (event.getAction() == MotionEvent.ACTION_DOWN) {
-            final PanelView panel = selectPanelForTouch(event);
+            final PanelView panel = mPanel;
             if (panel == null) {
                 // panel is not there, so we'll eat the gesture
                 Log.v(TAG, String.format("onTouch: no panel for touch at (%d,%d)",
                         (int) event.getX(), (int) event.getY()));
-                mTouchingPanel = null;
                 return true;
             }
             boolean enabled = panel.isEnabled();
@@ -135,90 +100,65 @@
                 Log.v(TAG, String.format(
                         "onTouch: panel (%s) is disabled, ignoring touch at (%d,%d)",
                         panel, (int) event.getX(), (int) event.getY()));
-                mTouchingPanel = null;
                 return true;
             }
-            startOpeningPanel(panel);
         }
-        final boolean result = mTouchingPanel != null
-                ? mTouchingPanel.onTouchEvent(event)
-                : true;
-        return result;
-    }
-
-    // called from PanelView when self-expanding, too
-    public void startOpeningPanel(PanelView panel) {
-        if (DEBUG) LOG("startOpeningPanel: " + panel);
-        mTouchingPanel = panel;
-        mPanelHolder.setSelectedPanel(mTouchingPanel);
-        for (PanelView pv : mPanels) {
-            if (pv != panel) {
-                pv.collapse(false /* delayed */, 1.0f /* speedUpFactor */);
-            }
-        }
+        return mPanel == null || mPanel.onTouchEvent(event);
     }
 
     public abstract void panelScrimMinFractionChanged(float minFraction);
 
     /**
-     * @param panel the panel which changed its expansion state
      * @param frac the fraction from the expansion in [0, 1]
      * @param expanded whether the panel is currently expanded; this is independent from the
      *                 fraction as the panel also might be expanded if the fraction is 0
      */
-    public void panelExpansionChanged(PanelView panel, float frac, boolean expanded) {
+    public void panelExpansionChanged(float frac, boolean expanded) {
         boolean fullyClosed = true;
-        PanelView fullyOpenedPanel = null;
-        if (SPEW) LOG("panelExpansionChanged: start state=%d panel=%s", mState, panel.getName());
-        mPanelExpandedFractionSum = 0f;
-        for (PanelView pv : mPanels) {
-            pv.setVisibility(expanded ? View.VISIBLE : View.INVISIBLE);
-            // adjust any other panels that may be partially visible
-            if (expanded) {
-                if (mState == STATE_CLOSED) {
-                    go(STATE_OPENING);
-                    onPanelPeeked();
-                }
-                fullyClosed = false;
-                final float thisFrac = pv.getExpandedFraction();
-                mPanelExpandedFractionSum += thisFrac;
-                if (SPEW) LOG("panelExpansionChanged:  -> %s: f=%.1f", pv.getName(), thisFrac);
-                if (panel == pv) {
-                    if (thisFrac == 1f) fullyOpenedPanel = panel;
-                }
+        boolean fullyOpened = false;
+        if (SPEW) LOG("panelExpansionChanged: start state=%d", mState);
+        PanelView pv = mPanel;
+        pv.setVisibility(expanded ? View.VISIBLE : View.INVISIBLE);
+        // adjust any other panels that may be partially visible
+        if (expanded) {
+            if (mState == STATE_CLOSED) {
+                go(STATE_OPENING);
+                onPanelPeeked();
             }
+            fullyClosed = false;
+            final float thisFrac = pv.getExpandedFraction();
+            if (SPEW) LOG("panelExpansionChanged:  -> %s: f=%.1f", pv.getName(), thisFrac);
+            fullyOpened = thisFrac >= 1f;
         }
-        mPanelExpandedFractionSum /= mPanels.size();
-        if (fullyOpenedPanel != null && !mTracking) {
+        if (fullyOpened && !mTracking) {
             go(STATE_OPEN);
-            onPanelFullyOpened(fullyOpenedPanel);
+            onPanelFullyOpened();
         } else if (fullyClosed && !mTracking && mState != STATE_CLOSED) {
             go(STATE_CLOSED);
-            onAllPanelsCollapsed();
+            onPanelCollapsed();
         }
 
         if (SPEW) LOG("panelExpansionChanged: end state=%d [%s%s ]", mState,
-                (fullyOpenedPanel!=null)?" fullyOpened":"", fullyClosed?" fullyClosed":"");
+                fullyOpened?" fullyOpened":"", fullyClosed?" fullyClosed":"");
     }
 
-    public void collapseAllPanels(boolean animate, boolean delayed, float speedUpFactor) {
+    public void collapsePanel(boolean animate, boolean delayed, float speedUpFactor) {
         boolean waiting = false;
-        for (PanelView pv : mPanels) {
-            if (animate && !pv.isFullyCollapsed()) {
-                pv.collapse(delayed, speedUpFactor);
-                waiting = true;
-            } else {
-                pv.resetViews();
-                pv.setExpandedFraction(0); // just in case
-                pv.cancelPeek();
-            }
+        PanelView pv = mPanel;
+        if (animate && !pv.isFullyCollapsed()) {
+            pv.collapse(delayed, speedUpFactor);
+            waiting = true;
+        } else {
+            pv.resetViews();
+            pv.setExpandedFraction(0); // just in case
+            pv.cancelPeek();
         }
-        if (DEBUG) LOG("collapseAllPanels: animate=%s waiting=%s", animate, waiting);
+        if (DEBUG) LOG("collapsePanel: animate=%s waiting=%s", animate, waiting);
         if (!waiting && mState != STATE_CLOSED) {
             // it's possible that nothing animated, so we replicate the termination
             // conditions of panelExpansionChanged here
             go(STATE_CLOSED);
-            onAllPanelsCollapsed();
+            onPanelCollapsed();
         }
     }
 
@@ -226,19 +166,19 @@
         if (DEBUG) LOG("onPanelPeeked");
     }
 
-    public void onAllPanelsCollapsed() {
-        if (DEBUG) LOG("onAllPanelsCollapsed");
+    public void onPanelCollapsed() {
+        if (DEBUG) LOG("onPanelCollapsed");
     }
 
-    public void onPanelFullyOpened(PanelView openPanel) {
+    public void onPanelFullyOpened() {
         if (DEBUG) LOG("onPanelFullyOpened");
     }
 
-    public void onTrackingStarted(PanelView panel) {
+    public void onTrackingStarted() {
         mTracking = true;
     }
 
-    public void onTrackingStopped(PanelView panel, boolean expand) {
+    public void onTrackingStopped(boolean expand) {
         mTracking = false;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java
deleted file mode 100644
index d7f34d5..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.util.EventLog;
-import android.view.MotionEvent;
-import android.widget.FrameLayout;
-
-import com.android.systemui.EventLogTags;
-
-public class PanelHolder extends FrameLayout {
-    public static final boolean DEBUG_GESTURES = true;
-
-    private int mSelectedPanelIndex = -1;
-    private PanelBar mBar;
-
-    public PanelHolder(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        setChildrenDrawingOrderEnabled(true);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        setChildrenDrawingOrderEnabled(true);
-    }
-
-    public int getPanelIndex(PanelView pv) {
-        final int N = getChildCount();
-        for (int i=0; i<N; i++) {
-            final PanelView v = (PanelView) getChildAt(i);
-            if (pv == v) return i;
-        }
-        return -1;
-    }
-
-    public void setSelectedPanel(PanelView pv) {
-        mSelectedPanelIndex = getPanelIndex(pv);
-    }
-
-    @Override
-    protected int getChildDrawingOrder(int childCount, int i) {
-        if (mSelectedPanelIndex == -1) {
-            return i;
-        } else {
-            if (i == childCount - 1) {
-                return mSelectedPanelIndex;
-            } else if (i >= mSelectedPanelIndex) {
-                return i + 1;
-            } else {
-                return i;
-            }
-        }
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        if (DEBUG_GESTURES) {
-            if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
-                EventLog.writeEvent(EventLogTags.SYSUI_PANELHOLDER_TOUCH,
-                        event.getActionMasked(), (int) event.getX(), (int) event.getY());
-            }
-        }
-        return false;
-    }
-
-    public void setBar(PanelBar panelBar) {
-        mBar = panelBar;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 5e54ba7..f036d04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -29,7 +29,6 @@
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
 import android.view.ViewTreeObserver;
-import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 
@@ -39,6 +38,7 @@
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.statusbar.FlingAnimationUtils;
+import com.android.systemui.statusbar.Interpolators;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
@@ -58,7 +58,6 @@
 
     private float mPeekHeight;
     private float mHintDistance;
-    private int mEdgeTapAreaWidth;
     private float mInitialOffsetOnTouch;
     private boolean mCollapsedAndHeadsUpOnDown;
     private float mExpandedFraction = 0;
@@ -82,7 +81,6 @@
     private boolean mMotionAborted;
     private boolean mUpwardsWhenTresholdReached;
     private boolean mAnimatingOnDown;
-    private int mLayoutHeight = 0;
 
     private ValueAnimator mHeightAnimator;
     private ObjectAnimator mPeekAnimator;
@@ -102,8 +100,6 @@
     private float mInitialTouchX;
     private boolean mTouchDisabled;
 
-    private Interpolator mLinearOutSlowInInterpolator;
-    private Interpolator mFastOutSlowInInterpolator;
     private Interpolator mBounceInterpolator;
     protected KeyguardBottomAreaView mKeyguardBottomArea;
 
@@ -163,7 +159,7 @@
         }
         mPeekAnimator = ObjectAnimator.ofFloat(this, "expandedHeight", mPeekHeight)
                 .setDuration(250);
-        mPeekAnimator.setInterpolator(mLinearOutSlowInInterpolator);
+        mPeekAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
         mPeekAnimator.addListener(new AnimatorListenerAdapter() {
             private boolean mCancelled;
 
@@ -189,10 +185,6 @@
     public PanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mFlingAnimationUtils = new FlingAnimationUtils(context, 0.6f);
-        mFastOutSlowInInterpolator =
-                AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
-        mLinearOutSlowInInterpolator =
-                AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in);
         mBounceInterpolator = new BounceInterpolator();
         mFalsingManager = FalsingManager.getInstance(context);
     }
@@ -202,7 +194,6 @@
         final ViewConfiguration configuration = ViewConfiguration.get(getContext());
         mTouchSlop = configuration.getScaledTouchSlop();
         mHintDistance = res.getDimension(R.dimen.hint_move_distance);
-        mEdgeTapAreaWidth = res.getDimensionPixelSize(R.dimen.edge_tap_area_width);
         mUnlockFalsingThreshold = res.getDimensionPixelSize(R.dimen.unlock_falsing_threshold);
     }
 
@@ -434,7 +425,7 @@
 
     protected void onTrackingStopped(boolean expand) {
         mTracking = false;
-        mBar.onTrackingStopped(PanelView.this, expand);
+        mBar.onTrackingStopped(expand);
         notifyBarPanelExpansionChanged();
     }
 
@@ -442,7 +433,7 @@
         endClosing();
         mTracking = true;
         mCollapseAfterPeek = false;
-        mBar.onTrackingStarted(PanelView.this);
+        mBar.onTrackingStarted();
         notifyExpandingStarted();
         notifyBarPanelExpansionChanged();
     }
@@ -717,10 +708,7 @@
     @Override
     protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        if (mLayoutHeight != getHeight()) {
-            mLayoutHeight = getHeight();
-            mStatusBar.onPanelHeightChanged();
-        }
+        mStatusBar.onPanelLaidOut();
         requestPanelHeightUpdate();
         mHasLayoutedSinceDown = true;
         if (mUpdateFlingOnLayout) {
@@ -895,7 +883,6 @@
                                 != mStatusBar.getStatusBarHeight()) {
                             getViewTreeObserver().removeOnGlobalLayoutListener(this);
                             if (animate) {
-                                mBar.startOpeningPanel(PanelView.this);
                                 notifyExpandingStarted();
                                 fling(0, true /* expand */);
                             } else {
@@ -958,7 +945,7 @@
         float target = Math.max(0, getMaxPanelHeight() - mHintDistance);
         ValueAnimator animator = createHeightAnimator(target);
         animator.setDuration(250);
-        animator.setInterpolator(mFastOutSlowInInterpolator);
+        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
         animator.addListener(new AnimatorListenerAdapter() {
             private boolean mCancelled;
 
@@ -982,7 +969,7 @@
         mKeyguardBottomArea.getIndicationView().animate()
                 .translationY(-mHintDistance)
                 .setDuration(250)
-                .setInterpolator(mFastOutSlowInInterpolator)
+                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
                 .withEndAction(new Runnable() {
                     @Override
                     public void run() {
@@ -1027,7 +1014,7 @@
     }
 
     protected void notifyBarPanelExpansionChanged() {
-        mBar.panelExpansionChanged(this, mExpandedFraction, mExpandedFraction > 0f || mPeekPending
+        mBar.panelExpansionChanged(mExpandedFraction, mExpandedFraction > 0f || mPeekPending
                 || mPeekAnimator != null || mInstantExpanding || isPanelVisibleBecauseOfHeadsUp()
                 || mTracking || mHeightAnimator != null);
     }
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 80fcba60e..a6ebab3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -47,6 +47,7 @@
 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;
@@ -81,22 +82,19 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.ThreadedRenderer;
-import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.ViewStub;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
-import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
-import android.view.animation.PathInterpolator;
 import android.widget.ImageView;
 import android.widget.TextView;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.keyguard.KeyguardHostView.OnDismissAction;
@@ -116,6 +114,8 @@
 import com.android.systemui.keyguard.KeyguardViewMediator;
 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.DockingTopTaskEvent;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.ActivatableNotificationView;
 import com.android.systemui.statusbar.BackDropView;
@@ -126,6 +126,7 @@
 import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.GestureRecorder;
+import com.android.systemui.statusbar.Interpolators;
 import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.NotificationData.Entry;
@@ -133,7 +134,6 @@
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.SignalClusterView;
-import com.android.systemui.statusbar.SpeedBumpView;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
 import com.android.systemui.statusbar.policy.AccessibilityController;
@@ -143,7 +143,6 @@
 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
 import com.android.systemui.statusbar.policy.CastControllerImpl;
 import com.android.systemui.statusbar.policy.FlashlightController;
-import com.android.systemui.statusbar.policy.FullscreenUserSwitcher;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.HotspotControllerImpl;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -152,7 +151,6 @@
 import com.android.systemui.statusbar.policy.NetworkControllerImpl;
 import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.PreviewInflater;
-import com.android.systemui.statusbar.policy.RemoteInputView;
 import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
 import com.android.systemui.statusbar.policy.SecurityControllerImpl;
 import com.android.systemui.statusbar.policy.UserInfoController;
@@ -272,7 +270,7 @@
     // These are no longer handled by the policy, because we need custom strategies for them
     BluetoothControllerImpl mBluetoothController;
     SecurityControllerImpl mSecurityController;
-    BatteryController mBatteryController;
+    protected BatteryController mBatteryController;
     LocationControllerImpl mLocationController;
     NetworkControllerImpl mNetworkController;
     HotspotControllerImpl mHotspotController;
@@ -283,12 +281,11 @@
     VolumeComponent mVolumeComponent;
     KeyguardUserSwitcher mKeyguardUserSwitcher;
     FlashlightController mFlashlightController;
-    UserSwitcherController mUserSwitcherController;
+    protected UserSwitcherController mUserSwitcherController;
     NextAlarmController mNextAlarmController;
-    KeyguardMonitor mKeyguardMonitor;
+    protected KeyguardMonitor mKeyguardMonitor;
     BrightnessMirrorController mBrightnessMirrorController;
     AccessibilityController mAccessibilityController;
-    FullscreenUserSwitcher mFullscreenUserSwitcher;
     FingerprintUnlockController mFingerprintUnlockController;
 
     int mNaturalBarHeight = -1;
@@ -296,10 +293,10 @@
     Display mDisplay;
     Point mCurrentDisplaySize = new Point();
 
-    StatusBarWindowView mStatusBarWindow;
+    protected StatusBarWindowView mStatusBarWindow;
     PhoneStatusBarView mStatusBarView;
     private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
-    private StatusBarWindowManager mStatusBarWindowManager;
+    protected StatusBarWindowManager mStatusBarWindowManager;
     private UnlockMethodCache mUnlockMethodCache;
     private DozeServiceHost mDozeServiceHost;
     private boolean mWakeUpComingFromTouch;
@@ -345,7 +342,6 @@
 
     // Tracking finger for opening/closing.
     boolean mTracking;
-    VelocityTracker mVelocityTracker;
 
     int[] mAbsPos = new int[2];
     ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>();
@@ -427,8 +423,8 @@
     private int mMaxKeyguardNotifications;
 
     private ViewMediatorCallback mKeyguardViewMediatorCallback;
-    private ScrimController mScrimController;
-    private DozeScrimController mDozeScrimController;
+    protected ScrimController mScrimController;
+    protected DozeScrimController mDozeScrimController;
 
     private final Runnable mAutohide = new Runnable() {
         @Override
@@ -442,12 +438,10 @@
     private boolean mWaitingForKeyguardExit;
     private boolean mDozing;
     private boolean mDozingRequested;
-    private boolean mScrimSrcModeEnabled;
+    protected boolean mScrimSrcModeEnabled;
 
-    private Interpolator mLinearInterpolator = new LinearInterpolator();
-    private Interpolator mBackdropInterpolator = new AccelerateDecelerateInterpolator();
-    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 ALPHA_IN = Interpolators.ALPHA_IN;
+    public static final Interpolator ALPHA_OUT = Interpolators.ALPHA_OUT;
 
     private BackDropView mBackdrop;
     private ImageView mBackdropFront, mBackdropBack;
@@ -499,7 +493,6 @@
 
     private final ShadeUpdates mShadeUpdates = new ShadeUpdates();
 
-    private int mDrawCount;
     private Runnable mLaunchTransitionEndRunnable;
     private boolean mLaunchTransitionFadingAway;
     private ExpandableNotificationRow mDraggedDownRow;
@@ -637,8 +630,9 @@
         addNavigationBar();
 
         // Lastly, call to the icon policy to install/update all the icons.
-        mIconPolicy = new PhoneStatusBarPolicy(mContext, mCastController, mHotspotController,
-                mUserInfoController, mBluetoothController);
+        mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController, mCastController,
+                mHotspotController, mUserInfoController, mBluetoothController,
+                mRotationLockController);
         mIconPolicy.setCurrentUserSetup(mUserSetup);
         mSettingsObserver.onChange(false); // set up
 
@@ -674,13 +668,10 @@
     protected PhoneStatusBarView makeStatusBarView() {
         final Context context = mContext;
 
-        Resources res = context.getResources();
-
         updateDisplaySize(); // populates mDisplayMetrics
         updateResources();
 
-        mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
-                R.layout.super_status_bar, null);
+        inflateStatusBarWindow(context);
         mStatusBarWindow.setService(this);
         mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() {
             @Override
@@ -695,16 +686,14 @@
             }
         });
 
-        mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
-        mStatusBarView.setBar(this);
-
-        PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder);
-        mStatusBarView.setPanelHolder(holder);
-
         mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
                 R.id.notification_panel);
         mNotificationPanel.setStatusBar(this);
 
+        mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
+        mStatusBarView.setBar(this);
+        mStatusBarView.setPanel(mNotificationPanel);
+
         if (!ActivityManager.isHighEndGfx()) {
             mStatusBarWindow.setBackground(null);
             mNotificationPanel.setBackground(new FastColorDrawable(context.getColor(
@@ -715,6 +704,7 @@
         mHeadsUpManager.setBar(this);
         mHeadsUpManager.addListener(this);
         mHeadsUpManager.addListener(mNotificationPanel);
+        mHeadsUpManager.addListener(mGroupManager);
         mNotificationPanel.setHeadsUpManager(mHeadsUpManager);
         mNotificationData.setHeadsUpManager(mHeadsUpManager);
 
@@ -728,32 +718,7 @@
             boolean showNav = mWindowManagerService.hasNavigationBar();
             if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
             if (showNav) {
-                // Optionally show app shortcuts in the nav bar "shelf" area.
-                if (shouldShowAppShelf()) {
-                    mNavigationBarView = (NavigationBarView) View.inflate(
-                            context, R.layout.navigation_bar_with_apps, null);
-                } else {
-                    mNavigationBarView = (NavigationBarView) View.inflate(
-                            context, R.layout.navigation_bar, null);
-                }
-                mNavigationBarView.setDisabledFlags(mDisabled1);
-                mNavigationBarView.setComponents(mRecents, getComponent(Divider.class));
-                mNavigationBarView.setOnVerticalChangedListener(
-                        new NavigationBarView.OnVerticalChangedListener() {
-                    @Override
-                    public void onVerticalChanged(boolean isVertical) {
-                        if (mAssistManager != null) {
-                            mAssistManager.onConfigurationChanged();
-                        }
-                        mNotificationPanel.setQsScrimEnabled(!isVertical);
-                    }
-                });
-                mNavigationBarView.setOnTouchListener(new View.OnTouchListener() {
-                    @Override
-                    public boolean onTouch(View v, MotionEvent event) {
-                        checkUserAutohide(v, event);
-                        return false;
-                    }});
+                createNavigationBarView(context);
             }
         } catch (RemoteException ex) {
             // no window manager? good luck with that
@@ -779,9 +744,7 @@
         mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
         mStackScroller.setOverflowContainer(mKeyguardIconOverflowContainer);
 
-        SpeedBumpView speedBump = (SpeedBumpView) LayoutInflater.from(mContext).inflate(
-                        R.layout.status_bar_notification_speed_bump, mStackScroller, false);
-        mStackScroller.setSpeedBumpView(speedBump);
+
         mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
                 R.layout.status_bar_no_notifications, mStackScroller, false);
         mStackScroller.setEmptyShadeView(mEmptyShadeView);
@@ -790,7 +753,7 @@
         mDismissView.setOnButtonClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                MetricsLogger.action(mContext, MetricsLogger.ACTION_DISMISS_ALL_NOTES);
+                MetricsLogger.action(mContext, MetricsEvent.ACTION_DISMISS_ALL_NOTES);
                 clearAllNotifications();
             }
         });
@@ -842,10 +805,10 @@
         mBatteryController = new BatteryController(mContext);
         mBatteryController.addStateChangedCallback(new BatteryStateChangeCallback() {
             @Override
-            public void onPowerSaveChanged() {
+            public void onPowerSaveChanged(boolean isPowerSave) {
                 mHandler.post(mCheckBarModes);
                 if (mDozeServiceHost != null) {
-                    mDozeServiceHost.firePowerSaveChanged(mBatteryController.isPowerSave());
+                    mDozeServiceHost.firePowerSaveChanged(isPowerSave);
                 }
             }
             @Override
@@ -866,23 +829,11 @@
             mZenModeController = mVolumeComponent.getZenController();
         }
         mCastController = new CastControllerImpl(mContext);
-        final SignalClusterView signalCluster =
-                (SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster);
-        final SignalClusterView signalClusterKeyguard =
-                (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster);
-        final SignalClusterView signalClusterQs =
-                (SignalClusterView) mHeader.findViewById(R.id.signal_cluster);
-        mNetworkController.addSignalCallback(signalCluster);
-        mNetworkController.addSignalCallback(signalClusterKeyguard);
-        signalCluster.setSecurityController(mSecurityController);
-        signalCluster.setNetworkController(mNetworkController);
-        signalClusterKeyguard.setSecurityController(mSecurityController);
-        signalClusterKeyguard.setNetworkController(mNetworkController);
-        if (signalClusterQs != null) {
-            mNetworkController.addSignalCallback(signalClusterQs);
-            signalClusterQs.setSecurityController(mSecurityController);
-            signalClusterQs.setNetworkController(mNetworkController);
-        }
+
+        initSignalCluster(mStatusBarView);
+        initSignalCluster(mKeyguardStatusBar);
+        initSignalCluster(mHeader);
+
         final boolean isAPhone = mNetworkController.hasVoiceCallingFeature();
         if (isAPhone) {
             mNetworkController.addEmergencyListener(mHeader);
@@ -898,17 +849,8 @@
         mKeyguardMonitor = new KeyguardMonitor(mContext);
         if (UserManager.get(mContext).isUserSwitcherEnabled()) {
             mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor,
-                    mHandler);
-            if (mUserSwitcherController.useFullscreenUserSwitcher()) {
-                mFullscreenUserSwitcher = new FullscreenUserSwitcher(this, mUserSwitcherController,
-                        (ViewStub) mStatusBarWindow.findViewById(
-                                R.id.fullscreen_user_switcher_stub));
-            } else {
-                // Fullscreen user switcher does not show keyguard. Hence no KeyguardUserSwitcher.
-                mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
-                        (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher),
-                        mKeyguardStatusBar, mNotificationPanel, mUserSwitcherController);
-            }
+                    mHandler, this);
+            createUserSwitcher();
         }
 
         // Set up the quick settings tile panel
@@ -919,7 +861,7 @@
                     mNetworkController, mZenModeController, mHotspotController,
                     mCastController, mFlashlightController,
                     mUserSwitcherController, mUserInfoController, mKeyguardMonitor,
-                    mSecurityController, mBatteryController);
+                    mSecurityController, mBatteryController, mIconController);
             mQSPanel.setHost(qsh);
             mQSPanel.setTiles(qsh.getTiles());
             mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
@@ -979,19 +921,52 @@
         return mStatusBarView;
     }
 
-    /** Returns true if the app shelf should be shown in the nav bar. */
-    private boolean shouldShowAppShelf() {
-        // Allow adb to override the default shelf behavior:
-        // adb shell settings put system demo_app_shelf 0  # Zero forces it off.
-        // adb shell settings put system demo_app_shelf 1  # Non-zero forces it on.
-        final int DEFAULT = -1;
-        final int shelfOverride =
-                Settings.System.getInt(mContext.getContentResolver(), "demo_app_shelf", DEFAULT);
-        if (shelfOverride != DEFAULT) {
-            return shelfOverride != 0;
+    protected void createUserSwitcher() {
+        mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
+                (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher),
+                mKeyguardStatusBar, mNotificationPanel, mUserSwitcherController);
+    }
+
+    protected void inflateStatusBarWindow(Context context) {
+        mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
+                R.layout.super_status_bar, null);
+    }
+
+    protected void createNavigationBarView(Context context) {
+        inflateNavigationBarView(context);
+        mNavigationBarView.setDisabledFlags(mDisabled1);
+        mNavigationBarView.setComponents(mRecents, getComponent(Divider.class));
+        mNavigationBarView.setOnVerticalChangedListener(
+                new NavigationBarView.OnVerticalChangedListener() {
+            @Override
+            public void onVerticalChanged(boolean isVertical) {
+                if (mAssistManager != null) {
+                    mAssistManager.onConfigurationChanged();
+                }
+                mNotificationPanel.setQsScrimEnabled(!isVertical);
+            }
+        });
+        mNavigationBarView.setOnTouchListener(new View.OnTouchListener() {
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                checkUserAutohide(v, event);
+                return false;
+            }});
+    }
+
+    protected void inflateNavigationBarView(Context context) {
+        mNavigationBarView = (NavigationBarView) View.inflate(
+                context, R.layout.navigation_bar, null);
+    }
+
+    protected void initSignalCluster(View containerView) {
+        SignalClusterView signalCluster =
+                (SignalClusterView) containerView.findViewById(R.id.signal_cluster);
+        if (signalCluster != null) {
+            mNetworkController.addSignalCallback(signalCluster);
+            signalCluster.setSecurityController(mSecurityController);
+            signalCluster.setNetworkController(mNetworkController);
         }
-        // Otherwise default to the platform feature.
-        return FREEFORM_WINDOW_MANAGEMENT;
     }
 
     private void clearAllNotifications() {
@@ -1075,17 +1050,18 @@
         }
     }
 
-    private void startKeyguard() {
+    protected void startKeyguard() {
         KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
         mFingerprintUnlockController = new FingerprintUnlockController(mContext,
                 mStatusBarWindowManager, mDozeScrimController, keyguardViewMediator,
                 mScrimController, this);
         mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
-                mStatusBarWindow, mStatusBarWindowManager, mScrimController,
+                getBouncerContainer(), mStatusBarWindowManager, mScrimController,
                 mFingerprintUnlockController);
         mKeyguardIndicationController.setStatusBarKeyguardViewManager(
                 mStatusBarKeyguardViewManager);
         mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
+        mRemoteInputController.addCallback(mStatusBarKeyguardViewManager);
         mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
     }
 
@@ -1098,6 +1074,10 @@
         return mStatusBarWindow;
     }
 
+    protected ViewGroup getBouncerContainer() {
+        return mStatusBarWindow;
+    }
+
     public int getStatusBarHeight() {
         if (mNaturalBarHeight < 0) {
             final Resources res = mContext.getResources();
@@ -1126,12 +1106,26 @@
         @Override
         public boolean onLongClick(View v) {
             if (mRecents != null) {
-                mRecents.dockTopTask(false /* draggingInRecents */,
+                Point realSize = new Point();
+                mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY)
+                        .getRealSize(realSize);
+                Rect initialBounds;
+
+                // Hack level over 9000: Make it one pixel smaller so activity manager doesn't
+                // dismiss it immediately again. Remove once b/26777526 is fixed.
+                if (mContext.getResources().getConfiguration().orientation
+                        == Configuration.ORIENTATION_LANDSCAPE) {
+                    initialBounds = new Rect(0, 0, realSize.x - 1, realSize.y);
+                } else {
+                    initialBounds = new Rect(0, 0, realSize.x, realSize.y - 1);
+                }
+                boolean docked = mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
                         ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT,
-                        null /* initialBounds */);
-                MetricsLogger.action(mContext,
-                        MetricsLogger.ACTION_WINDOW_DOCK_LONGPRESS);
-                return true;
+                        initialBounds);
+                if (docked) {
+                    MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS);
+                    return true;
+                }
             }
             return false;
         }
@@ -1144,7 +1138,7 @@
             if (shouldDisableNavbarGestures()) {
                 return false;
             }
-            MetricsLogger.action(mContext, MetricsLogger.ACTION_ASSIST_LONG_PRESS);
+            MetricsLogger.action(mContext, MetricsEvent.ACTION_ASSIST_LONG_PRESS);
             mAssistManager.startAssist(new Bundle() /* args */);
             awakenDreams();
             if (mNavigationBarView != null) {
@@ -1179,19 +1173,25 @@
     private void prepareNavigationBarView() {
         mNavigationBarView.reorient();
 
-        mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
-        mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener);
-        mNavigationBarView.getRecentsButton().setLongClickable(true);
-        mNavigationBarView.getRecentsButton().setOnLongClickListener(mRecentsLongClickListener);
-        mNavigationBarView.getBackButton().setLongClickable(true);
-        mNavigationBarView.getBackButton().setOnLongClickListener(mLongPressBackListener);
-        mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener);
-        mNavigationBarView.getHomeButton().setOnLongClickListener(mLongPressHomeListener);
+        ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton();
+        recentsButton.setOnClickListener(mRecentsClickListener);
+        recentsButton.setOnTouchListener(mRecentsPreloadOnTouchListener);
+        recentsButton.setLongClickable(true);
+        recentsButton.setOnLongClickListener(mRecentsLongClickListener);
+
+        ButtonDispatcher backButton = mNavigationBarView.getBackButton();
+        backButton.setLongClickable(true);
+        backButton.setOnLongClickListener(mLongPressBackListener);
+
+        ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
+        homeButton.setOnTouchListener(mHomeActionListener);
+        homeButton.setOnLongClickListener(mLongPressHomeListener);
+
         mAssistManager.onConfigurationChanged();
     }
 
     // For small-screen devices (read: phones) that lack hardware navigation buttons
-    private void addNavigationBar() {
+    protected void addNavigationBar() {
         if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView);
         if (mNavigationBarView == null) return;
 
@@ -1200,7 +1200,7 @@
         mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams());
     }
 
-    private void repositionNavigationBar() {
+    protected void repositionNavigationBar() {
         if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return;
 
         prepareNavigationBarView();
@@ -1234,17 +1234,14 @@
         return lp;
     }
 
-    public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
-        mIconController.addSystemIcon(slot, index, viewIndex, icon);
+    @Override
+    public void setIcon(String slot, StatusBarIcon icon) {
+        mIconController.setIcon(slot, icon);
     }
 
-    public void updateIcon(String slot, int index, int viewIndex,
-            StatusBarIcon old, StatusBarIcon icon) {
-        mIconController.updateSystemIcon(slot, index, viewIndex, old, icon);
-    }
-
-    public void removeIcon(String slot, int index, int viewIndex) {
-        mIconController.removeSystemIcon(slot, index, viewIndex);
+    @Override
+    public void removeIcon(String slot) {
+        mIconController.removeIcon(slot);
     }
 
     public UserHandle getCurrentUserHandle() {
@@ -1269,19 +1266,26 @@
         }
 
         if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) {
-            // Stop screensaver if the notification has a full-screen intent.
-            // (like an incoming phone call)
-            awakenDreams();
+            if (shouldSupressFullScreenIntent(notification.getKey())) {
+                if (DEBUG) {
+                    Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + notification.getKey());
+                }
+            } else {
+                // Stop screensaver if the notification has a full-screen intent.
+                // (like an incoming phone call)
+                awakenDreams();
 
-            // not immersive & a full-screen alert should be shown
-            if (DEBUG) Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
-            try {
-                EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
-                        notification.getKey());
-                notification.getNotification().fullScreenIntent.send();
-                shadeEntry.notifyFullScreenIntentLaunched();
-                MetricsLogger.count(mContext, "note_fullscreen", 1);
-            } catch (PendingIntent.CanceledException e) {
+                // not immersive & a full-screen alert should be shown
+                if (DEBUG)
+                    Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
+                try {
+                    EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
+                            notification.getKey());
+                    notification.getNotification().fullScreenIntent.send();
+                    shadeEntry.notifyFullScreenIntentLaunched();
+                    MetricsLogger.count(mContext, "note_fullscreen", 1);
+                } catch (PendingIntent.CanceledException e) {
+                }
             }
         }
         addNotificationViews(shadeEntry, ranking);
@@ -1289,6 +1293,14 @@
         setAreThereNotifications();
     }
 
+    private boolean shouldSupressFullScreenIntent(String key) {
+        if (mPowerManager.isInteractive()) {
+            return mNotificationData.shouldSuppressPeek(key);
+        } else {
+            return mNotificationData.shouldSuppressScreenOn(key);
+        }
+    }
+
     @Override
     protected void updateNotificationRanking(RankingMap ranking) {
         mNotificationData.updateRanking(ranking);
@@ -1361,6 +1373,9 @@
             boolean sensitivePackage = packageHasVisibilityOverride(ent.notification.getKey());
             boolean sensitive = (sensitiveNote && hideSensitive) || sensitivePackage;
             boolean showingPublic = sensitive && isLockscreenPublicMode();
+            if (showingPublic) {
+                updatePublicContentView(ent, ent.notification);
+            }
             ent.row.setSensitive(sensitive);
             if (ent.autoRedacted && ent.legacy) {
                 // TODO: Also fade this? Or, maybe easier (and better), provide a dark redacted form
@@ -1387,16 +1402,21 @@
 
         }
 
-        ArrayList<View> toRemove = new ArrayList<>();
+        ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
         for (int i=0; i< mStackScroller.getChildCount(); i++) {
             View child = mStackScroller.getChildAt(i);
             if (!toShow.contains(child) && child instanceof ExpandableNotificationRow) {
-                toRemove.add(child);
+                toRemove.add((ExpandableNotificationRow) child);
             }
         }
 
-        for (View remove : toRemove) {
+        for (ExpandableNotificationRow remove : toRemove) {
+            if (mGroupManager.isChildInGroupWithSummary(remove.getStatusBarNotification())) {
+                // we are only transfering this notification to its parent, don't generate an animation
+                mStackScroller.setChildTransferInProgress(true);
+            }
             mStackScroller.removeView(remove);
+            mStackScroller.setChildTransferInProgress(false);
         }
         for (int i=0; i<toShow.size(); i++) {
             View v = toShow.get(i);
@@ -1552,6 +1572,10 @@
         mIconController.updateNotificationIcons(mNotificationData);
     }
 
+    public void requestNotificationUpdate() {
+        updateNotifications();
+    }
+
     @Override
     protected void updateRowStates() {
         super.updateRowStates();
@@ -1838,7 +1862,7 @@
                             // if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in
                             // libhwui.
                             .alpha(0.002f)
-                            .setInterpolator(mBackdropInterpolator)
+                            .setInterpolator(Interpolators.ACCELERATE_DECELERATE)
                             .setDuration(300)
                             .setStartDelay(0)
                             .withEndAction(new Runnable() {
@@ -1857,7 +1881,7 @@
                                 // behind.
                                 .setDuration(mKeyguardFadingAwayDuration / 2)
                                 .setStartDelay(mKeyguardFadingAwayDelay)
-                                .setInterpolator(mLinearInterpolator)
+                                .setInterpolator(Interpolators.LINEAR)
                                 .start();
                     }
                 }
@@ -2269,7 +2293,7 @@
             mStatusBarWindowManager.setStatusBarFocusable(false);
 
             mStatusBarWindow.cancelExpandHelper();
-            mStatusBarView.collapseAllPanels(true /* animate */, delayed, speedUpFactor);
+            mStatusBarView.collapsePanel(true /* animate */, delayed, speedUpFactor);
         }
     }
 
@@ -2318,7 +2342,7 @@
 
     public void animateCollapseQuickSettings() {
         if (mState == StatusBarState.SHADE) {
-            mStatusBarView.collapseAllPanels(true, false /* delayed */, 1.0f /* speedUpFactor */);
+            mStatusBarView.collapsePanel(true, false /* delayed */, 1.0f /* speedUpFactor */);
         }
     }
 
@@ -2331,7 +2355,7 @@
         }
 
         // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
-        mStatusBarView.collapseAllPanels(/*animate=*/ false, false /* delayed*/,
+        mStatusBarView.collapsePanel(/*animate=*/ false, false /* delayed*/,
                 1.0f /* speedUpFactor */);
 
         mNotificationPanel.closeQs();
@@ -2423,7 +2447,7 @@
             mStatusBarWindowState = state;
             if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state));
             if (!showing && mState == StatusBarState.SHADE) {
-                mStatusBarView.collapseAllPanels(false /* animate */, false /* delayed */,
+                mStatusBarView.collapsePanel(false /* animate */, false /* delayed */,
                         1.0f /* speedUpFactor */);
             }
         }
@@ -2980,6 +3004,7 @@
             if (DEBUG) Log.v(TAG, "onReceive: " + intent);
             String action = intent.getAction();
             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
+                getKeyboardShortcuts().dismissKeyboardShortcutsDialog();
                 if (isCurrentProfile(getSendingUserId())) {
                     int flags = CommandQueue.FLAG_EXCLUDE_NONE;
                     String reason = intent.getStringExtra("reason");
@@ -3084,9 +3109,6 @@
         setControllerUsers();
         clearCurrentMediaNotification();
         updateMediaMetaData(true);
-        if (mFullscreenUserSwitcher != null) {
-            mFullscreenUserSwitcher.onUserSwitched(newUserId);
-        }
     }
 
     private void setControllerUsers() {
@@ -3711,7 +3733,7 @@
                         .isSecure(mCurrentUserId));
     }
 
-    private void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) {
+    protected void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) {
         if (mState == StatusBarState.KEYGUARD) {
             mKeyguardIndicationController.setVisible(true);
             mNotificationPanel.resetViews();
@@ -3735,17 +3757,11 @@
             mScrimController.setKeyguardShowing(false);
             mIconPolicy.setKeyguardShowing(false);
         }
-        if (mFullscreenUserSwitcher != null) {
-            if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
-                mFullscreenUserSwitcher.show();
-            } else {
-                mFullscreenUserSwitcher.hide();
-            }
-        }
+
         mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade);
         updateDozingState();
         updatePublicMode();
-        updateStackScrollerState(goingToFullShade);
+        updateStackScrollerState(goingToFullShade, fromShadeLocked);
         updateNotifications();
         checkBarModes();
         updateMediaMetaData(false);
@@ -3766,11 +3782,11 @@
                         != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING, animate);
     }
 
-    public void updateStackScrollerState(boolean goingToFullShade) {
+    public void updateStackScrollerState(boolean goingToFullShade, boolean fromShadeLocked) {
         if (mStackScroller == null) return;
         boolean onKeyguard = mState == StatusBarState.KEYGUARD;
         mStackScroller.setHideSensitive(isLockscreenPublicMode(), goingToFullShade);
-        mStackScroller.setDimmed(onKeyguard, false /* animate */);
+        mStackScroller.setDimmed(onKeyguard, fromShadeLocked /* animate */);
         mStackScroller.setExpandingEnabled(!onKeyguard);
         ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild();
         mStackScroller.setActivatedChild(null);
@@ -4013,9 +4029,10 @@
     }
 
     @Override
-    public void onExpandClicked(View clickedView, boolean nowExpanded) {
+    public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
+        mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
         if (mState == StatusBarState.KEYGUARD && nowExpanded) {
-            goToLockedShade(clickedView);
+            goToLockedShade(clickedEntry.row);
         }
     }
 
@@ -4120,32 +4137,6 @@
         return false;
     }
 
-    // Recents
-
-    @Override
-    protected void showRecents(boolean triggeredFromAltTab) {
-        // Set the recents visibility flag
-        mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
-        notifyUiVisibilityChanged(mSystemUiVisibility);
-        super.showRecents(triggeredFromAltTab);
-    }
-
-    @Override
-    protected void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
-        // Unset the recents visibility flag
-        mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE;
-        notifyUiVisibilityChanged(mSystemUiVisibility);
-        super.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
-    }
-
-    @Override
-    protected void toggleRecents() {
-        // Toggle the recents visibility flag
-        mSystemUiVisibility ^= View.RECENT_APPS_VISIBLE;
-        notifyUiVisibilityChanged(mSystemUiVisibility);
-        super.toggleRecents();
-    }
-
     public void updateRecentsVisibility(boolean visible) {
         // Update the recents visibility flag
         if (visible) {
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 b89cd22..37d61b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -20,7 +20,6 @@
 import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
 import android.app.AlarmManager.AlarmClockInfo;
-import android.app.StatusBarManager;
 import android.app.SynchronousUserSwitchObserver;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -35,16 +34,17 @@
 import android.provider.Settings.Global;
 import android.telecom.TelecomManager;
 import android.util.Log;
-
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.systemui.R;
 import com.android.systemui.qs.tiles.DndTile;
+import com.android.systemui.qs.tiles.RotationLockTile;
 import com.android.systemui.statusbar.policy.BluetoothController;
 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.HotspotController;
+import com.android.systemui.statusbar.policy.RotationLockController;
 import com.android.systemui.statusbar.policy.UserInfoController;
 
 /**
@@ -52,27 +52,30 @@
  * 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 {
+public class PhoneStatusBarPolicy implements Callback, RotationLockController.RotationLockControllerCallback {
     private static final String TAG = "PhoneStatusBarPolicy";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    private static final String SLOT_CAST = "cast";
-    private static final String SLOT_HOTSPOT = "hotspot";
-    private static final String SLOT_BLUETOOTH = "bluetooth";
-    private static final String SLOT_TTY = "tty";
-    private static final String SLOT_ZEN = "zen";
-    private static final String SLOT_VOLUME = "volume";
-    private static final String SLOT_ALARM_CLOCK = "alarm_clock";
-    private static final String SLOT_MANAGED_PROFILE = "managed_profile";
+    private final String mSlotCast;
+    private final String mSlotHotspot;
+    private final String mSlotBluetooth;
+    private final String mSlotTty;
+    private final String mSlotZen;
+    private final String mSlotVolume;
+    private final String mSlotAlarmClock;
+    private final String mSlotManagedProfile;
+    private final String mSlotRotate;
+    private final String mSlotHeadset;
 
     private final Context mContext;
-    private final StatusBarManager mService;
     private final Handler mHandler = new Handler();
     private final CastController mCast;
     private final HotspotController mHotspot;
     private final AlarmManager mAlarmManager;
     private final UserInfoController mUserInfoController;
     private final UserManager mUserManager;
+    private final StatusBarIconController mIconController;
+    private final RotationLockController mRotationLockController;
 
     // Assume it's all good unless we hear otherwise.  We don't always seem
     // to get broadcasts that it *is* there.
@@ -91,55 +94,40 @@
     private boolean mKeyguardVisible = true;
     private BluetoothController mBluetooth;
 
-    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (action.equals(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)) {
-                updateAlarm();
-            }
-            else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) ||
-                    action.equals(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)) {
-                updateVolumeZen();
-            }
-            else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
-                updateSimState(intent);
-            }
-            else if (action.equals(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED)) {
-                updateTTY(intent);
-            }
-            else if (action.equals(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED)) {
-                updateQuietState();
-                updateManagedProfile();
-            }
-        }
-    };
-
-    private Runnable mRemoveCastIconRunnable = new Runnable() {
-        @Override
-        public void run() {
-            if (DEBUG) Log.v(TAG, "updateCast: hiding icon NOW");
-            mService.setIconVisibility(SLOT_CAST, false);
-        }
-    };
-
-    public PhoneStatusBarPolicy(Context context, CastController cast, HotspotController hotspot,
-            UserInfoController userInfoController, BluetoothController bluetooth) {
+    public PhoneStatusBarPolicy(Context context, StatusBarIconController iconController,
+            CastController cast, HotspotController hotspot, UserInfoController userInfoController,
+            BluetoothController bluetooth, RotationLockController rotationLockController) {
         mContext = context;
+        mIconController = iconController;
         mCast = cast;
         mHotspot = hotspot;
         mBluetooth = bluetooth;
         mBluetooth.addStateChangedCallback(this);
-        mService = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
         mUserInfoController = userInfoController;
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        mRotationLockController = rotationLockController;
+
+        mSlotCast = context.getString(com.android.internal.R.string.status_bar_cast);
+        mSlotHotspot = context.getString(com.android.internal.R.string.status_bar_hotspot);
+        mSlotBluetooth = context.getString(com.android.internal.R.string.status_bar_bluetooth);
+        mSlotTty = context.getString(com.android.internal.R.string.status_bar_tty);
+        mSlotZen = context.getString(com.android.internal.R.string.status_bar_zen);
+        mSlotVolume = context.getString(com.android.internal.R.string.status_bar_volume);
+        mSlotAlarmClock = context.getString(com.android.internal.R.string.status_bar_alarm_clock);
+        mSlotManagedProfile = context.getString(
+                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);
+
+        mRotationLockController.addRotationLockControllerCallback(this);
 
         // listen for broadcasts
         IntentFilter filter = new IntentFilter();
         filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
         filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
         filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
+        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);
@@ -153,40 +141,40 @@
         }
 
         // TTY status
-        mService.setIcon(SLOT_TTY,  R.drawable.stat_sys_tty_mode, 0, null);
-        mService.setIconVisibility(SLOT_TTY, false);
+        mIconController.setIcon(mSlotTty,  R.drawable.stat_sys_tty_mode, null);
+        mIconController.setIconVisibility(mSlotTty, false);
 
         // bluetooth status
         updateBluetooth();
 
         // Alarm clock
-        mService.setIcon(SLOT_ALARM_CLOCK, R.drawable.stat_sys_alarm, 0, null);
-        mService.setIconVisibility(SLOT_ALARM_CLOCK, false);
+        mIconController.setIcon(mSlotAlarmClock, R.drawable.stat_sys_alarm, null);
+        mIconController.setIconVisibility(mSlotAlarmClock, false);
 
         // zen
-        mService.setIcon(SLOT_ZEN, R.drawable.stat_sys_zen_important, 0, null);
-        mService.setIconVisibility(SLOT_ZEN, false);
+        mIconController.setIcon(mSlotZen, R.drawable.stat_sys_zen_important, null);
+        mIconController.setIconVisibility(mSlotZen, false);
 
         // volume
-        mService.setIcon(SLOT_VOLUME, R.drawable.stat_sys_ringer_vibrate, 0, null);
-        mService.setIconVisibility(SLOT_VOLUME, false);
+        mIconController.setIcon(mSlotVolume, R.drawable.stat_sys_ringer_vibrate, null);
+        mIconController.setIconVisibility(mSlotVolume, false);
         updateVolumeZen();
 
         // cast
-        mService.setIcon(SLOT_CAST, R.drawable.stat_sys_cast, 0, null);
-        mService.setIconVisibility(SLOT_CAST, false);
+        mIconController.setIcon(mSlotCast, R.drawable.stat_sys_cast, null);
+        mIconController.setIconVisibility(mSlotCast, false);
         mCast.addCallback(mCastCallback);
 
         // hotspot
-        mService.setIcon(SLOT_HOTSPOT, R.drawable.stat_sys_hotspot, 0,
+        mIconController.setIcon(mSlotHotspot, R.drawable.stat_sys_hotspot,
                 mContext.getString(R.string.accessibility_status_bar_hotspot));
-        mService.setIconVisibility(SLOT_HOTSPOT, mHotspot.isHotspotEnabled());
+        mIconController.setIconVisibility(mSlotHotspot, mHotspot.isHotspotEnabled());
         mHotspot.addCallback(mHotspotCallback);
 
         // managed profile
-        mService.setIcon(SLOT_MANAGED_PROFILE, R.drawable.stat_sys_managed_profile_status, 0,
+        mIconController.setIcon(mSlotManagedProfile, R.drawable.stat_sys_managed_profile_status,
                 mContext.getString(R.string.accessibility_managed_profile));
-        mService.setIconVisibility(SLOT_MANAGED_PROFILE, mManagedProfileIconVisible);
+        mIconController.setIconVisibility(mSlotManagedProfile, mManagedProfileIconVisible);
     }
 
     public void setZenMode(int zen) {
@@ -198,32 +186,27 @@
         final AlarmClockInfo alarm = mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);
         final boolean hasAlarm = alarm != null && alarm.getTriggerTime() > 0;
         final boolean zenNone = mZen == Global.ZEN_MODE_NO_INTERRUPTIONS;
-        mService.setIcon(SLOT_ALARM_CLOCK, zenNone ? R.drawable.stat_sys_alarm_dim
-                : R.drawable.stat_sys_alarm, 0, null);
-        mService.setIconVisibility(SLOT_ALARM_CLOCK, mCurrentUserSetup && hasAlarm);
+        mIconController.setIcon(mSlotAlarmClock, zenNone ? R.drawable.stat_sys_alarm_dim
+                : R.drawable.stat_sys_alarm, null);
+        mIconController.setIconVisibility(mSlotAlarmClock, mCurrentUserSetup && hasAlarm);
     }
 
     private final void updateSimState(Intent intent) {
         String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
         if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
             mSimState = IccCardConstants.State.ABSENT;
-        }
-        else if (IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR.equals(stateExtra)) {
+        } else if (IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR.equals(stateExtra)) {
             mSimState = IccCardConstants.State.CARD_IO_ERROR;
-        }
-        else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
+        } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
             mSimState = IccCardConstants.State.READY;
-        }
-        else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
+        } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
             final String lockedReason =
                     intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
             if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
                 mSimState = IccCardConstants.State.PIN_REQUIRED;
-            }
-            else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
+            } else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
                 mSimState = IccCardConstants.State.PUK_REQUIRED;
-            }
-            else {
+            } else {
                 mSimState = IccCardConstants.State.NETWORK_LOCKED;
             }
         } else {
@@ -270,18 +253,18 @@
         }
 
         if (zenVisible) {
-            mService.setIcon(SLOT_ZEN, zenIconId, 0, zenDescription);
+            mIconController.setIcon(mSlotZen, zenIconId, zenDescription);
         }
         if (zenVisible != mZenVisible) {
-            mService.setIconVisibility(SLOT_ZEN, zenVisible);
+            mIconController.setIconVisibility(mSlotZen, zenVisible);
             mZenVisible = zenVisible;
         }
 
         if (volumeVisible) {
-            mService.setIcon(SLOT_VOLUME, volumeIconId, 0, volumeDescription);
+            mIconController.setIcon(mSlotVolume, volumeIconId, volumeDescription);
         }
         if (volumeVisible != mVolumeVisible) {
-            mService.setIconVisibility(SLOT_VOLUME, volumeVisible);
+            mIconController.setIconVisibility(mSlotVolume, volumeVisible);
             mVolumeVisible = volumeVisible;
         }
         updateAlarm();
@@ -310,8 +293,8 @@
             }
         }
 
-        mService.setIcon(SLOT_BLUETOOTH, iconId, 0, contentDescription);
-        mService.setIconVisibility(SLOT_BLUETOOTH, bluetoothEnabled);
+        mIconController.setIcon(mSlotBluetooth, iconId, contentDescription);
+        mIconController.setIconVisibility(mSlotBluetooth, bluetoothEnabled);
     }
 
     private final void updateTTY(Intent intent) {
@@ -324,13 +307,13 @@
         if (enabled) {
             // TTY is on
             if (DEBUG) Log.v(TAG, "updateTTY: set TTY on");
-            mService.setIcon(SLOT_TTY, R.drawable.stat_sys_tty_mode, 0,
+            mIconController.setIcon(mSlotTty, R.drawable.stat_sys_tty_mode,
                     mContext.getString(R.string.accessibility_tty_enabled));
-            mService.setIconVisibility(SLOT_TTY, true);
+            mIconController.setIconVisibility(mSlotTty, true);
         } else {
             // TTY is off
             if (DEBUG) Log.v(TAG, "updateTTY: set TTY off");
-            mService.setIconVisibility(SLOT_TTY, false);
+            mIconController.setIconVisibility(mSlotTty, false);
         }
     }
 
@@ -346,9 +329,9 @@
         if (DEBUG) Log.v(TAG, "updateCast: isCasting: " + isCasting);
         mHandler.removeCallbacks(mRemoveCastIconRunnable);
         if (isCasting) {
-            mService.setIcon(SLOT_CAST, R.drawable.stat_sys_cast, 0,
+            mIconController.setIcon(mSlotCast, R.drawable.stat_sys_cast,
                     mContext.getString(R.string.accessibility_casting));
-            mService.setIconVisibility(SLOT_CAST, true);
+            mIconController.setIconVisibility(mSlotCast, true);
         } else {
             // don't turn off the screen-record icon for a few seconds, just to make sure the user
             // has seen it
@@ -392,17 +375,19 @@
         final boolean showIcon;
         if (mManagedProfileFocused && !mKeyguardVisible) {
             showIcon = true;
-            mService.setIcon(SLOT_MANAGED_PROFILE, R.drawable.stat_sys_managed_profile_status, 0,
+            mIconController.setIcon(mSlotManagedProfile,
+                    R.drawable.stat_sys_managed_profile_status,
                     mContext.getString(R.string.accessibility_managed_profile));
         } else if (mManagedProfileInQuietMode) {
             showIcon = true;
-            mService.setIcon(SLOT_MANAGED_PROFILE, R.drawable.stat_sys_managed_profile_status_off, 0,
+            mIconController.setIcon(mSlotManagedProfile,
+                    R.drawable.stat_sys_managed_profile_status_off,
                     mContext.getString(R.string.accessibility_managed_profile));
         } else {
             showIcon = false;
         }
         if (mManagedProfileIconVisible != showIcon) {
-            mService.setIconVisibility(SLOT_MANAGED_PROFILE, showIcon);
+            mIconController.setIconVisibility(mSlotManagedProfile, showIcon);
             mManagedProfileIconVisible = showIcon;
         }
     }
@@ -431,7 +416,7 @@
     private final HotspotController.Callback mHotspotCallback = new HotspotController.Callback() {
         @Override
         public void onHotspotChanged(boolean enabled) {
-            mService.setIconVisibility(SLOT_HOTSPOT, enabled);
+            mIconController.setIconVisibility(mSlotHotspot, enabled);
         }
     };
 
@@ -457,4 +442,69 @@
         updateAlarm();
         updateQuietState();
     }
+
+    @Override
+    public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
+        boolean portrait = RotationLockTile.isCurrentOrientationLockPortrait(
+                mRotationLockController, mContext);
+        if (rotationLocked) {
+            if (portrait) {
+                mIconController.setIcon(mSlotRotate, R.drawable.stat_sys_rotate_portrait,
+                        mContext.getString(R.string.accessibility_rotation_lock_on_portrait));
+            } else {
+                mIconController.setIcon(mSlotRotate, R.drawable.stat_sys_rotate_landscape,
+                        mContext.getString(R.string.accessibility_rotation_lock_on_landscape));
+            }
+        } else {
+            mIconController.setIcon(mSlotRotate, portrait
+                    ? R.drawable.stat_sys_auto_rotate_portrait
+                    : R.drawable.stat_sys_auto_rotate_landscape,
+                    mContext.getString(R.string.accessibility_rotation_lock_off));
+        }
+    }
+
+    private void updateHeadsetPlug(Intent intent) {
+        boolean connected = intent.getIntExtra("state", 0) != 0;
+        boolean hasMic = intent.getIntExtra("microphone", 0) != 0;
+        if (connected) {
+            String contentDescription = mContext.getString(hasMic
+                    ? R.string.accessibility_status_bar_headset
+                    : R.string.accessibility_status_bar_headphones);
+            mIconController.setIcon(mSlotHeadset, hasMic ? R.drawable.ic_headset_mic
+                    : R.drawable.ic_headset, contentDescription);
+            mIconController.setIconVisibility(mSlotHeadset, true);
+        } else {
+            mIconController.setIconVisibility(mSlotHeadset, false);
+        }
+    }
+
+    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)) {
+                updateAlarm();
+            } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) ||
+                    action.equals(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)) {
+                updateVolumeZen();
+            } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
+                updateSimState(intent);
+            } else if (action.equals(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED)) {
+                updateTTY(intent);
+            } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED)) {
+                updateQuietState();
+                updateManagedProfile();
+            } else if (action.equals(AudioManager.ACTION_HEADSET_PLUG)) {
+                updateHeadsetPlug(intent);
+            }
+        }
+    };
+
+    private Runnable mRemoveCastIconRunnable = new Runnable() {
+        @Override
+        public void run() {
+            if (DEBUG) Log.v(TAG, "updateCast: hiding icon NOW");
+            mIconController.setIconVisibility(mSlotCast, false);
+        }
+    };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index c0887ca..902fd3d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.phone;
 
 import android.content.Context;
-import android.content.res.Resources;
 import android.util.AttributeSet;
 import android.util.EventLog;
 import android.view.MotionEvent;
@@ -26,7 +25,6 @@
 
 import com.android.systemui.DejankUtils;
 import com.android.systemui.EventLogTags;
-import com.android.systemui.R;
 
 public class PhoneStatusBarView extends PanelBar {
     private static final String TAG = "PhoneStatusBarView";
@@ -35,8 +33,7 @@
 
     PhoneStatusBar mBar;
 
-    PanelView mLastFullyOpenedPanel = null;
-    PanelView mNotificationPanel;
+    boolean mIsFullyOpenedPanel = false;
     private final PhoneStatusBarTransitions mBarTransitions;
     private ScrimController mScrimController;
     private float mMinFraction;
@@ -51,7 +48,6 @@
     public PhoneStatusBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
-        Resources res = getContext().getResources();
         mBarTransitions = new PhoneStatusBarTransitions(this);
     }
 
@@ -73,15 +69,7 @@
     }
 
     @Override
-    public void addPanel(PanelView pv) {
-        super.addPanel(pv);
-        if (pv.getId() == R.id.notification_panel) {
-            mNotificationPanel = pv;
-        }
-    }
-
-    @Override
-    public boolean panelsEnabled() {
+    public boolean panelEnabled() {
         return mBar.panelsEnabled();
     }
 
@@ -101,25 +89,17 @@
     }
 
     @Override
-    public PanelView selectPanelForTouch(MotionEvent touch) {
-        // No double swiping. If either panel is open, nothing else can be pulled down.
-        return mNotificationPanel.getExpandedHeight() > 0
-                ? null
-                : mNotificationPanel;
-    }
-
-    @Override
     public void onPanelPeeked() {
         super.onPanelPeeked();
         mBar.makeExpandedVisible(false);
     }
 
     @Override
-    public void onAllPanelsCollapsed() {
-        super.onAllPanelsCollapsed();
+    public void onPanelCollapsed() {
+        super.onPanelCollapsed();
         // Close the status bar in the next frame so we can show the end of the animation.
         DejankUtils.postAfterTraversal(mHideExpandedRunnable);
-        mLastFullyOpenedPanel = null;
+        mIsFullyOpenedPanel = false;
     }
 
     public void removePendingHideExpandedRunnables() {
@@ -127,12 +107,12 @@
     }
 
     @Override
-    public void onPanelFullyOpened(PanelView openPanel) {
-        super.onPanelFullyOpened(openPanel);
-        if (openPanel != mLastFullyOpenedPanel) {
-            openPanel.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+    public void onPanelFullyOpened() {
+        super.onPanelFullyOpened();
+        if (!mIsFullyOpenedPanel) {
+            mPanel.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
         }
-        mLastFullyOpenedPanel = openPanel;
+        mIsFullyOpenedPanel = true;
     }
 
     @Override
@@ -151,8 +131,8 @@
     }
 
     @Override
-    public void onTrackingStarted(PanelView panel) {
-        super.onTrackingStarted(panel);
+    public void onTrackingStarted() {
+        super.onTrackingStarted();
         mBar.onTrackingStarted();
         mScrimController.onTrackingStarted();
     }
@@ -164,8 +144,8 @@
     }
 
     @Override
-    public void onTrackingStopped(PanelView panel, boolean expand) {
-        super.onTrackingStopped(panel, expand);
+    public void onTrackingStopped(boolean expand) {
+        super.onTrackingStopped(expand);
         mBar.onTrackingStopped(expand);
     }
 
@@ -184,19 +164,22 @@
     public void panelScrimMinFractionChanged(float minFraction) {
         if (mMinFraction != minFraction) {
             mMinFraction = minFraction;
+            if (minFraction != 0.0f) {
+                mScrimController.animateNextChange();
+            }
             updateScrimFraction();
         }
     }
 
     @Override
-    public void panelExpansionChanged(PanelView panel, float frac, boolean expanded) {
-        super.panelExpansionChanged(panel, frac, expanded);
+    public void panelExpansionChanged(float frac, boolean expanded) {
+        super.panelExpansionChanged(frac, expanded);
         mPanelFraction = frac;
         updateScrimFraction();
     }
 
     private void updateScrimFraction() {
-        float scrimFraction = Math.max(mPanelFraction - mMinFraction / (1.0f - mMinFraction), 0);
+        float scrimFraction = Math.max(mPanelFraction, mMinFraction);
         mScrimController.setPanelExpansion(scrimFraction);
     }
 }
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 7f27ba7..b8cd7fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -18,30 +18,27 @@
 
 import android.app.ActivityManager;
 import android.app.PendingIntent;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
-import android.os.Binder;
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Process;
-import android.os.RemoteException;
 import android.provider.Settings;
-import android.service.quicksettings.IQSService;
-import android.service.quicksettings.Tile;
 import android.text.TextUtils;
 import android.util.Log;
+import android.view.View;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.external.CustomTile;
+import com.android.systemui.qs.external.TileServices;
 import com.android.systemui.qs.tiles.AirplaneModeTile;
 import com.android.systemui.qs.tiles.BatteryTile;
 import com.android.systemui.qs.tiles.BluetoothTile;
 import com.android.systemui.qs.tiles.CastTile;
 import com.android.systemui.qs.tiles.CellularTile;
 import com.android.systemui.qs.tiles.ColorInversionTile;
-import com.android.systemui.qs.tiles.CustomTile;
+import com.android.systemui.qs.tiles.DataSaverTile;
 import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.qs.tiles.FlashlightTile;
 import com.android.systemui.qs.tiles.HotspotTile;
@@ -54,6 +51,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.DisplayController;
 import com.android.systemui.statusbar.policy.FlashlightController;
 import com.android.systemui.statusbar.policy.HotspotController;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -64,6 +62,7 @@
 import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.tuner.ColorMatrixTile;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
 
@@ -75,7 +74,7 @@
 import java.util.Map;
 
 /** Platform implementation of the quick settings tile host **/
-public final class QSTileHost extends IQSService.Stub implements QSTile.Host, Tunable {
+public final class QSTileHost implements QSTile.Host, Tunable {
     private static final String TAG = "QSTileHost";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -99,16 +98,21 @@
     private final KeyguardMonitor mKeyguard;
     private final SecurityController mSecurity;
     private final BatteryController mBattery;
+    private final StatusBarIconController mIconController;
+    private final TileServices mServices;
 
     private final List<Callback> mCallbacks = new ArrayList<>();
+    private final DisplayController mDisplayController;
+    private View mHeader;
 
     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) {
+                      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) {
         mContext = context;
         mStatusBar = statusBar;
         mBluetooth = bluetooth;
@@ -124,15 +128,23 @@
         mKeyguard = keyguard;
         mSecurity = security;
         mBattery = battery;
+        mIconController = iconController;
+        mDisplayController = new DisplayController(mContext);
 
         final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName(),
                 Process.THREAD_PRIORITY_BACKGROUND);
         ht.start();
         mLooper = ht.getLooper();
 
+        mServices = new TileServices(this, mLooper);
+
         TunerService.get(mContext).addTunable(this, TILES_SETTING);
     }
 
+    public void setHeaderView(View view) {
+        mHeader = view;
+    }
+
     public PhoneStatusBar getPhoneStatusBar() {
         return mStatusBar;
     }
@@ -171,6 +183,11 @@
         // already logged
     }
 
+    public void animateExpandQS() {
+        // TODO: Better path to animated panel expansion.
+        mHeader.performClick();
+    }
+
     @Override
     public void collapsePanels() {
         mStatusBar.postAnimateCollapsePanels();
@@ -255,6 +272,18 @@
         return mSecurity;
     }
 
+    public TileServices getTileServices() {
+        return mServices;
+    }
+
+    public StatusBarIconController getIconController() {
+        return mIconController;
+    }
+
+    public DisplayController getDisplayController() {
+        return mDisplayController;
+    }
+
     @Override
     public void onTuningChanged(String key, String newValue) {
         if (!TILES_SETTING.equals(key)) {
@@ -274,6 +303,7 @@
             if (mTiles.containsKey(tileSpec)) {
                 QSTile<?> tile = mTiles.get(tileSpec);
                 if (DEBUG) Log.d(TAG, "Adding " + tile);
+                tile.removeCallbacks();
                 newTiles.put(tileSpec, tile);
             } else {
                 if (DEBUG) Log.d(TAG, "Creating tile: " + tileSpec);
@@ -305,50 +335,6 @@
                 TextUtils.join(",", specs), ActivityManager.getCurrentUser());
     }
 
-    @Override
-    public void updateQsTile(Tile tile) throws RemoteException {
-        verifyCaller(tile.getComponentName().getPackageName());
-        CustomTile customTile = getTileForComponent(tile.getComponentName());
-        if (customTile != null) {
-            customTile.updateState(tile);
-            customTile.refreshState();
-        }
-    }
-
-    @Override
-    public void onShowDialog(Tile tile) throws RemoteException {
-        verifyCaller(tile.getComponentName().getPackageName());
-        CustomTile customTile = getTileForComponent(tile.getComponentName());
-        if (customTile != null) {
-            customTile.onDialogShown();
-            collapsePanels();
-        }
-    }
-
-    private void verifyCaller(String packageName) {
-        try {
-            int uid = mContext.getPackageManager().getPackageUid(packageName,
-                    Binder.getCallingUserHandle().getIdentifier());
-            if (Binder.getCallingUid() != uid) {
-                throw new SecurityException("Component outside caller's uid");
-            }
-        } catch (NameNotFoundException e) {
-            throw new SecurityException(e);
-        }
-    }
-
-    private CustomTile getTileForComponent(ComponentName component) {
-        // TODO: Build map for easier lookup.
-        for (QSTile<?> qsTile : mTiles.values()) {
-            if (qsTile instanceof CustomTile) {
-                if (((CustomTile) qsTile).getComponent().equals(component)) {
-                    return (CustomTile) qsTile;
-                }
-            }
-        }
-        return null;
-    }
-
     public QSTile<?> createTile(String tileSpec) {
         if (tileSpec.equals("wifi")) return WifiTile.isSupported(this)
                 ? new WifiTile(this) : null;
@@ -368,10 +354,16 @@
         else if (tileSpec.equals("hotspot")) return new HotspotTile(this);
         else if (tileSpec.equals("user")) return new UserTile(this);
         else if (tileSpec.equals("battery")) return new BatteryTile(this);
+        else if (tileSpec.equals("saver")) return new DataSaverTile(this);
+        else if (tileSpec.equals(ColorMatrixTile.COLOR_MATRIX_SPEC))
+            return new ColorMatrixTile(this);
         // Intent tiles.
         else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec);
         else if (tileSpec.startsWith(CustomTile.PREFIX)) return CustomTile.create(this,tileSpec);
-        else throw new IllegalArgumentException("Bad tile spec: " + tileSpec);
+        else {
+            Log.w(TAG, "Bad tile spec: " + tileSpec);
+            return null;
+        }
     }
 
     public static List<String> loadTileSpecs(Context context, String tileList) {
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 1372cca..f18c341 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -22,9 +22,9 @@
 import android.content.Intent;
 import android.graphics.Rect;
 import android.graphics.drawable.Animatable;
+import android.graphics.drawable.Drawable;
 import android.graphics.drawable.RippleDrawable;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
@@ -71,6 +71,8 @@
     private QuickQSPanel mHeaderQsPanel;
     private boolean mShowEmergencyCallsOnly;
     private float mDateTimeTranslation;
+    private MultiUserSwitch mMultiUserSwitch;
+    private ImageView mMultiUserAvatar;
 
     public QuickStatusBarHeader(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -101,6 +103,9 @@
         mQsDetailHeaderSwitch = (Switch) mQsDetailHeader.findViewById(android.R.id.toggle);
         mQsDetailHeaderProgress = (ImageView) findViewById(R.id.qs_detail_header_progress);
 
+        mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch);
+        mMultiUserAvatar = (ImageView) mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
+
         // 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);
@@ -135,7 +140,6 @@
     @Override
     public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
         mNextAlarm = nextAlarm;
-        Log.d(TAG, "Got alarm update " + (nextAlarm != null));
         if (nextAlarm != null) {
             mAlarmStatus.setText(KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm));
         }
@@ -175,14 +179,18 @@
                 ? View.VISIBLE : View.INVISIBLE);
         mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility(
                 TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE);
+        mMultiUserSwitch.setVisibility(mMultiUserSwitch.hasMultipleUsers() ? View.VISIBLE
+                : View.GONE);
+    }
+
+    private boolean hasMultiUsers() {
+        return false;
     }
 
     private void updateListeners() {
         if (mListening) {
-            Log.d(TAG, "Listening for Alarms");
             mNextAlarmController.addStateChangedCallback(this);
         } else {
-            Log.d(TAG, "Not listening for Alarms");
             mNextAlarmController.removeStateChangedCallback(this);
         }
     }
@@ -198,26 +206,20 @@
         setupHost(qsPanel.getHost());
         if (mQsPanel != null) {
             mQsPanel.setCallback(mQsPanelCallback);
+            mMultiUserSwitch.setQsPanel(qsPanel);
         }
     }
 
-    public void setupHost(QSTileHost host) {
-        final QSTileHost myHost = new QSTileHost(host.getContext(), host.getPhoneStatusBar(),
-                host.getBluetoothController(), host.getLocationController(),
-                host.getRotationLockController(), host.getNetworkController(),
-                host.getZenModeController(), host.getHotspotController(),
-                host.getCastController(), host.getFlashlightController(),
-                host.getUserSwitcherController(), host.getUserInfoController(),
-                host.getKeyguardMonitor(), host.getSecurityController(),
-                host.getBatteryController());
+    public void setupHost(final QSTileHost host) {
+        host.setHeaderView(this);
         mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
-        mHeaderQsPanel.setHost(myHost);
+        mHeaderQsPanel.setHost(host);
         mHeaderQsPanel.setMaxTiles(5);
-        mHeaderQsPanel.setTiles(myHost.getTiles());
-        myHost.addCallback(new QSTile.Host.Callback() {
+        mHeaderQsPanel.setTiles(host.getTiles());
+        host.addCallback(new QSTile.Host.Callback() {
             @Override
             public void onTilesChanged() {
-                mHeaderQsPanel.setTiles(myHost.getTiles());
+                mHeaderQsPanel.setTiles(host.getTiles());
             }
         });
     }
@@ -265,7 +267,12 @@
 
     @Override
     public void setUserInfoController(UserInfoController userInfoController) {
-        // Don't care.
+        userInfoController.addListener(new UserInfoController.OnUserInfoChangedListener() {
+            @Override
+            public void onUserInfoChanged(String name, Drawable picture) {
+                mMultiUserAvatar.setImageDrawable(picture);
+            }
+        });
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java
new file mode 100644
index 0000000..da16954
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+/**
+ * Automatically reverses the order of children as they are added.
+ * Also reverse the width and height values of layout params
+ */
+public class ReverseLinearLayout extends LinearLayout {
+
+    public ReverseLinearLayout(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public void addView(View child) {
+        reversParams(child.getLayoutParams());
+        super.addView(child, 0);
+    }
+
+    @Override
+    public void addView(View child, ViewGroup.LayoutParams params) {
+        reversParams(params);
+        super.addView(child, 0, params);
+    }
+
+    private void reversParams(ViewGroup.LayoutParams params) {
+        if (params == null) {
+            return;
+        }
+        int width = params.width;
+        params.width = params.height;
+        params.height = width;
+    }
+
+}
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 b9e9292..f310c2c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -22,6 +22,7 @@
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.Color;
+import android.graphics.Rect;
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.view.animation.DecelerateInterpolator;
@@ -52,8 +53,8 @@
     private static final float SCRIM_IN_FRONT_ALPHA = 0.75f;
     private static final int TAG_KEY_ANIM = R.id.scrim;
     private static final int TAG_KEY_ANIM_TARGET = R.id.scrim_target;
-    private static final int TAG_HUN_START_ALPHA = R.id.hun_scrim_alpha_start;
-    private static final int TAG_HUN_END_ALPHA = R.id.hun_scrim_alpha_end;
+    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;
     private final ScrimView mScrimInFront;
@@ -164,6 +165,10 @@
         scheduleUpdate();
     }
 
+    public void animateNextChange() {
+        mAnimateChange = true;
+    }
+
     public void setDozing(boolean dozing) {
         if (mDozing != dozing) {
             mDozing = dozing;
@@ -271,21 +276,7 @@
     }
 
     private void setScrimColor(View scrim, float alpha) {
-        ValueAnimator runningAnim = (ValueAnimator) scrim.getTag(TAG_KEY_ANIM);
-        Float target = (Float) scrim.getTag(TAG_KEY_ANIM_TARGET);
-        if (runningAnim != null && target != null) {
-            if (alpha != target) {
-                runningAnim.cancel();
-            } else {
-                return;
-            }
-        }
-        if (mAnimateChange) {
-            startScrimAnimation(scrim, alpha);
-        } else {
-            setCurrentScrimAlpha(scrim, alpha);
-            updateScrimColor(scrim);
-        }
+        updateScrim(mAnimateChange, scrim, alpha, getCurrentScrimAlpha(scrim));
     }
 
     private float getDozeAlpha(View scrim) {
@@ -428,41 +419,44 @@
     }
 
     private void updateHeadsUpScrim(boolean animate) {
-        float alpha = calculateHeadsUpAlpha();
-        ValueAnimator previousAnimator = StackStateAnimator.getChildTag(mHeadsUpScrim,
+        updateScrim(animate, mHeadsUpScrim, calculateHeadsUpAlpha(), mCurrentHeadsUpAlpha);
+    }
+
+    private void updateScrim(boolean animate, View scrim, float alpha, float currentAlpha) {
+        ValueAnimator previousAnimator = StackStateAnimator.getChildTag(scrim,
                 TAG_KEY_ANIM);
         float animEndValue = -1;
         if (previousAnimator != null) {
-            if (animate || alpha == mCurrentHeadsUpAlpha) {
+            if (animate || alpha == currentAlpha) {
                 previousAnimator.cancel();
             } else {
-                animEndValue = StackStateAnimator.getChildTag(mHeadsUpScrim, TAG_HUN_END_ALPHA);
+                animEndValue = StackStateAnimator.getChildTag(scrim, TAG_END_ALPHA);
             }
         }
-        if (alpha != mCurrentHeadsUpAlpha && alpha != animEndValue) {
+        if (alpha != currentAlpha && alpha != animEndValue) {
             if (animate) {
-                startScrimAnimation(mHeadsUpScrim, alpha);
-                mHeadsUpScrim.setTag(TAG_HUN_START_ALPHA, mCurrentHeadsUpAlpha);
-                mHeadsUpScrim.setTag(TAG_HUN_END_ALPHA, alpha);
+                startScrimAnimation(scrim, alpha);
+                scrim.setTag(TAG_START_ALPHA, currentAlpha);
+                scrim.setTag(TAG_END_ALPHA, alpha);
             } else {
                 if (previousAnimator != null) {
-                    float previousStartValue = StackStateAnimator.getChildTag(mHeadsUpScrim,
-                            TAG_HUN_START_ALPHA);
-                    float previousEndValue = StackStateAnimator.getChildTag(mHeadsUpScrim,
-                           TAG_HUN_END_ALPHA);
+                    float previousStartValue = StackStateAnimator.getChildTag(scrim,
+                            TAG_START_ALPHA);
+                    float previousEndValue = StackStateAnimator.getChildTag(scrim,
+                            TAG_END_ALPHA);
                     // we need to increase all animation keyframes of the previous animator by the
                     // relative change to the end value
                     PropertyValuesHolder[] values = previousAnimator.getValues();
                     float relativeDiff = alpha - previousEndValue;
                     float newStartValue = previousStartValue + relativeDiff;
                     values[0].setFloatValues(newStartValue, alpha);
-                    mHeadsUpScrim.setTag(TAG_HUN_START_ALPHA, newStartValue);
-                    mHeadsUpScrim.setTag(TAG_HUN_END_ALPHA, alpha);
+                    scrim.setTag(TAG_START_ALPHA, newStartValue);
+                    scrim.setTag(TAG_END_ALPHA, alpha);
                     previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
                 } else {
                     // update the alpha directly
-                    setCurrentScrimAlpha(mHeadsUpScrim, alpha);
-                    updateScrimColor(mHeadsUpScrim);
+                    setCurrentScrimAlpha(scrim, alpha);
+                    updateScrimColor(scrim);
                 }
             }
         }
@@ -504,4 +498,16 @@
     public void dontAnimateBouncerChangesUntilNextFrame() {
         mDontAnimateBouncerChanges = true;
     }
+
+    public void setExcludedBackgroundArea(Rect area) {
+        mScrimBehind.setExcludedArea(area);
+    }
+
+    public int getScrimBehindColor() {
+        return mScrimBehind.getScrimColorWithAlpha();
+    }
+
+    public void setScrimBehindChangeRunnable(Runnable changeRunnable) {
+        mScrimBehind.setChangeRunnable(changeRunnable);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
index 512af1b..7247b57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
@@ -26,7 +26,9 @@
 import android.view.ViewConfiguration;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
+
 import com.android.keyguard.AlphaOptimizedImageButton;
+import com.android.systemui.statusbar.Interpolators;
 
 public class SettingsButton extends AlphaOptimizedImageButton {
 
@@ -157,8 +159,7 @@
         performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
         mUpToSpeed = true;
         mAnimator = ObjectAnimator.ofFloat(this, View.ROTATION, 0, 360);
-        mAnimator.setInterpolator(AnimationUtils.loadInterpolator(mContext,
-                android.R.interpolator.linear));
+        mAnimator.setInterpolator(Interpolators.LINEAR);
         mAnimator.setDuration(FULL_SPEED_LENGTH);
         mAnimator.setRepeatCount(Animation.INFINITE);
         mAnimator.start();
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 3d21f44..d2f1ca9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -419,7 +419,7 @@
     }
 
     @Override
-    public void onPowerSaveChanged() {
+    public void onPowerSaveChanged(boolean isPowerSave) {
         // could not care less
     }
 
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 d5b980e..c6537e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -20,29 +20,30 @@
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.ColorStateList;
+import android.content.res.Resources;
 import android.graphics.Color;
+import android.graphics.drawable.Icon;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.ArraySet;
+import android.util.TypedValue;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.util.NotificationColorUtil;
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.Interpolators;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.SignalClusterView;
 import com.android.systemui.statusbar.StatusBarIconView;
-import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
 
@@ -54,7 +55,7 @@
  * limited to: notification icons, signal cluster, additional status icons, and clock in the status
  * bar.
  */
-public class StatusBarIconController implements Tunable {
+public class StatusBarIconController extends StatusBarIconList implements Tunable {
 
     public static final long DEFAULT_TINT_ANIMATION_DURATION = 120;
 
@@ -62,18 +63,16 @@
 
     private Context mContext;
     private PhoneStatusBar mPhoneStatusBar;
-    private Interpolator mLinearOutSlowIn;
-    private Interpolator mFastOutSlowIn;
     private DemoStatusIcons mDemoStatusIcons;
-    private NotificationColorUtil mNotificationColorUtil;
 
     private LinearLayout mSystemIconArea;
     private LinearLayout mStatusIcons;
     private SignalClusterView mSignalCluster;
     private LinearLayout mStatusIconsKeyguard;
-    private IconMerger mNotificationIcons;
-    private View mNotificationIconArea;
-    private ImageView mMoreIcon;
+
+    private NotificationIconAreaController mNotificationIconAreaController;
+    private View mNotificationIconAreaInner;
+
     private BatteryMeterView mBatteryMeterView;
     private TextView mClock;
 
@@ -109,21 +108,25 @@
             PhoneStatusBar phoneStatusBar) {
         mContext = context;
         mPhoneStatusBar = phoneStatusBar;
-        mNotificationColorUtil = NotificationColorUtil.getInstance(context);
         mSystemIconArea = (LinearLayout) statusBar.findViewById(R.id.system_icon_area);
         mStatusIcons = (LinearLayout) statusBar.findViewById(R.id.statusIcons);
         mSignalCluster = (SignalClusterView) statusBar.findViewById(R.id.signal_cluster);
-        mNotificationIconArea = statusBar.findViewById(R.id.notification_icon_area_inner);
-        mNotificationIcons = (IconMerger) statusBar.findViewById(R.id.notificationIcons);
-        mMoreIcon = (ImageView) statusBar.findViewById(R.id.moreIcon);
-        mNotificationIcons.setOverflowIndicator(mMoreIcon);
+
+        mNotificationIconAreaController =
+                new NotificationIconAreaController(context, phoneStatusBar);
+        mNotificationIconAreaInner =
+                mNotificationIconAreaController.getNotificationInnerAreaView();
+
+        ViewGroup notificationIconArea =
+                (ViewGroup) statusBar.findViewById(R.id.notification_icon_area);
+        notificationIconArea.addView(mNotificationIconAreaInner);
+
         mStatusIconsKeyguard = (LinearLayout) keyguardStatusBar.findViewById(R.id.statusIcons);
+
         mBatteryMeterView = (BatteryMeterView) statusBar.findViewById(R.id.battery);
+        maybeScaleBatteryMeterView(context);
+
         mClock = (TextView) statusBar.findViewById(R.id.clock);
-        mLinearOutSlowIn = AnimationUtils.loadInterpolator(mContext,
-                android.R.interpolator.linear_out_slow_in);
-        mFastOutSlowIn = AnimationUtils.loadInterpolator(mContext,
-                android.R.interpolator.fast_out_slow_in);
         mDarkModeIconColorSingleTone = context.getColor(R.color.dark_mode_icon_color_single_tone);
         mLightModeIconColorSingleTone = context.getColor(R.color.light_mode_icon_color_single_tone);
         mHandler = new Handler();
@@ -132,6 +135,30 @@
         TunerService.get(mContext).addTunable(this, ICON_BLACKLIST);
     }
 
+    /**
+     * Looks up the scale factor for status bar icons and scales the battery view by that amount
+     * if appropriate.
+     */
+    private void maybeScaleBatteryMeterView(Context context) {
+        Resources res = context.getResources();
+        TypedValue typedValue = new TypedValue();
+
+        res.getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true);
+        float iconScaleFactor = typedValue.getFloat();
+
+        if (iconScaleFactor == 1.f) {
+            return;
+        }
+
+        float batteryHeight = res.getDimension(R.dimen.status_bar_battery_icon_height);
+        float batteryWidth = res.getDimension(R.dimen.status_bar_battery_icon_width);
+
+        LinearLayout.LayoutParams scaledLayoutParams = new LinearLayout.LayoutParams(
+                (int) (batteryWidth * iconScaleFactor), (int) (batteryHeight * iconScaleFactor));
+
+        mBatteryMeterView.setLayoutParams(scaledLayoutParams);
+    }
+
     @Override
     public void onTuningChanged(String key, String newValue) {
         if (!ICON_BLACKLIST.equals(key)) {
@@ -146,28 +173,36 @@
         }
         // Remove all the icons.
         for (int i = views.size() - 1; i >= 0; i--) {
-            removeSystemIcon(views.get(i).getSlot(), i, i);
+            removeIcon(views.get(i).getSlot());
         }
         // Add them all back
         for (int i = 0; i < views.size(); i++) {
-            addSystemIcon(views.get(i).getSlot(), i, i, views.get(i).getStatusBarIcon());
+            setIcon(views.get(i).getSlot(), views.get(i).getStatusBarIcon());
         }
-    };
+    }
 
     public void updateResources() {
         mIconSize = mContext.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.status_bar_icon_size);
         mIconHPadding = mContext.getResources().getDimensionPixelSize(
                 R.dimen.status_bar_icon_padding);
+        defineSlots(mContext.getResources().getStringArray(
+                com.android.internal.R.array.config_statusBarIcons));
         FontSizeUtils.updateFontSize(mClock, R.dimen.status_bar_clock_size);
     }
 
-    public void addSystemIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
+    private void addSystemIcon(int index, StatusBarIcon icon) {
+        String slot = getSlot(index);
+        int viewIndex = getViewIndex(index);
         boolean blocked = mIconBlacklist.contains(slot);
         StatusBarIconView view = new StatusBarIconView(mContext, slot, null, blocked);
         view.set(icon);
-        mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(
-                ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize));
+
+        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
+        lp.setMargins(mIconHPadding, 0, mIconHPadding, 0);
+        mStatusIcons.addView(view, viewIndex, lp);
+
         view = new StatusBarIconView(mContext, slot, null, blocked);
         view.set(icon);
         mStatusIconsKeyguard.addView(view, viewIndex, new LinearLayout.LayoutParams(
@@ -175,8 +210,77 @@
         applyIconTint();
     }
 
-    public void updateSystemIcon(String slot, int index, int viewIndex,
-            StatusBarIcon old, StatusBarIcon icon) {
+    public void setIcon(String slot, int resourceId, CharSequence contentDescription) {
+        int index = getSlotIndex(slot);
+        StatusBarIcon icon = getIcon(index);
+        if (icon == null) {
+            icon = new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(),
+                    Icon.createWithResource(mContext, resourceId), 0, 0, contentDescription);
+            setIcon(slot, icon);
+        } else {
+            icon.icon = Icon.createWithResource(mContext, resourceId);
+            icon.contentDescription = contentDescription;
+            handleSet(index, icon);
+        }
+    }
+
+    public void setExternalIcon(String slot) {
+        int viewIndex = getViewIndex(getSlotIndex(slot));
+        ImageView imageView = (ImageView) mStatusIcons.getChildAt(viewIndex);
+        imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
+        imageView.setAdjustViewBounds(true);
+        imageView = (ImageView) mStatusIconsKeyguard.getChildAt(viewIndex);
+        imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
+        imageView.setAdjustViewBounds(true);
+    }
+
+    public void setIcon(String slot, StatusBarIcon icon) {
+        setIcon(getSlotIndex(slot), icon);
+    }
+
+    public void removeIcon(String slot) {
+        int index = getSlotIndex(slot);
+        removeIcon(index);
+    }
+
+    public void setIconVisibility(String slot, boolean visibility) {
+        int index = getSlotIndex(slot);
+        StatusBarIcon icon = getIcon(index);
+        if (icon == null || icon.visible == visibility) {
+            return;
+        }
+        icon.visible = visibility;
+        handleSet(index, icon);
+    }
+
+    @Override
+    public void removeIcon(int index) {
+        if (getIcon(index) == null) {
+            return;
+        }
+        super.removeIcon(index);
+        int viewIndex = getViewIndex(index);
+        mStatusIcons.removeViewAt(viewIndex);
+        mStatusIconsKeyguard.removeViewAt(viewIndex);
+    }
+
+    @Override
+    public void setIcon(int index, StatusBarIcon icon) {
+        if (icon == null) {
+            removeIcon(index);
+            return;
+        }
+        boolean isNew = getIcon(index) == null;
+        super.setIcon(index, icon);
+        if (isNew) {
+            addSystemIcon(index, icon);
+        } else {
+            handleSet(index, icon);
+        }
+    }
+
+    private void handleSet(int index, StatusBarIcon icon) {
+        int viewIndex = getViewIndex(index);
         StatusBarIconView view = (StatusBarIconView) mStatusIcons.getChildAt(viewIndex);
         view.set(icon);
         view = (StatusBarIconView) mStatusIconsKeyguard.getChildAt(viewIndex);
@@ -184,66 +288,8 @@
         applyIconTint();
     }
 
-    public void removeSystemIcon(String slot, int index, int viewIndex) {
-        mStatusIcons.removeViewAt(viewIndex);
-        mStatusIconsKeyguard.removeViewAt(viewIndex);
-    }
-
     public void updateNotificationIcons(NotificationData notificationData) {
-        final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
-                mIconSize + 2*mIconHPadding, mPhoneStatusBar.getStatusBarHeight());
-
-        ArrayList<NotificationData.Entry> activeNotifications =
-                notificationData.getActiveNotifications();
-        final int N = activeNotifications.size();
-        ArrayList<StatusBarIconView> toShow = new ArrayList<>(N);
-
-        // Filter out ambient notifications and notification children.
-        for (int i = 0; i < N; i++) {
-            NotificationData.Entry ent = activeNotifications.get(i);
-            if (notificationData.isAmbient(ent.key)
-                    && !NotificationData.showNotificationEvenIfUnprovisioned(ent.notification)) {
-                continue;
-            }
-            if (!PhoneStatusBar.isTopLevelChild(ent)) {
-                continue;
-            }
-            toShow.add(ent.icon);
-        }
-
-        ArrayList<View> toRemove = new ArrayList<>();
-        for (int i=0; i<mNotificationIcons.getChildCount(); i++) {
-            View child = mNotificationIcons.getChildAt(i);
-            if (!toShow.contains(child)) {
-                toRemove.add(child);
-            }
-        }
-
-        final int toRemoveCount = toRemove.size();
-        for (int i = 0; i < toRemoveCount; i++) {
-            mNotificationIcons.removeView(toRemove.get(i));
-        }
-
-        for (int i=0; i<toShow.size(); i++) {
-            View v = toShow.get(i);
-            if (v.getParent() == null) {
-                mNotificationIcons.addView(v, i, params);
-            }
-        }
-
-        // Resort notification icons
-        final int childCount = mNotificationIcons.getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View actual = mNotificationIcons.getChildAt(i);
-            StatusBarIconView expected = toShow.get(i);
-            if (actual == expected) {
-                continue;
-            }
-            mNotificationIcons.removeView(expected);
-            mNotificationIcons.addView(expected, i);
-        }
-
-        applyNotificationIconsTint();
+        mNotificationIconAreaController.updateNotificationIcons(notificationData);
     }
 
     public void hideSystemIconArea(boolean animate) {
@@ -255,11 +301,11 @@
     }
 
     public void hideNotificationIconArea(boolean animate) {
-        animateHide(mNotificationIconArea, animate);
+        animateHide(mNotificationIconAreaInner, animate);
     }
 
     public void showNotificationIconArea(boolean animate) {
-        animateShow(mNotificationIconArea, animate);
+        animateShow(mNotificationIconAreaInner, animate);
     }
 
     public void setClockVisibility(boolean visible) {
@@ -296,7 +342,7 @@
                 .alpha(0f)
                 .setDuration(160)
                 .setStartDelay(0)
-                .setInterpolator(PhoneStatusBar.ALPHA_OUT)
+                .setInterpolator(Interpolators.ALPHA_OUT)
                 .withEndAction(new Runnable() {
                     @Override
                     public void run() {
@@ -318,7 +364,7 @@
         v.animate()
                 .alpha(1f)
                 .setDuration(320)
-                .setInterpolator(PhoneStatusBar.ALPHA_IN)
+                .setInterpolator(Interpolators.ALPHA_IN)
                 .setStartDelay(50)
 
                 // We need to clean up any pending end action from animateHide if we call
@@ -330,7 +376,7 @@
         if (mPhoneStatusBar.isKeyguardFadingAway()) {
             v.animate()
                     .setDuration(mPhoneStatusBar.getKeyguardFadingAwayDuration())
-                    .setInterpolator(mLinearOutSlowIn)
+                    .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
                     .setStartDelay(mPhoneStatusBar.getKeyguardFadingAwayDelay())
                     .start();
         }
@@ -367,7 +413,7 @@
         });
         mTintAnimator.setDuration(duration);
         mTintAnimator.setStartDelay(delay);
-        mTintAnimator.setInterpolator(mFastOutSlowIn);
+        mTintAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
         mTintAnimator.start();
     }
 
@@ -375,6 +421,7 @@
         mDarkIntensity = darkIntensity;
         mIconTint = (int) ArgbEvaluator.getInstance().evaluate(darkIntensity,
                 mLightModeIconColorSingleTone, mDarkModeIconColorSingleTone);
+        mNotificationIconAreaController.setIconTint(mIconTint);
         applyIconTint();
     }
 
@@ -392,21 +439,8 @@
             v.setImageTintList(ColorStateList.valueOf(mIconTint));
         }
         mSignalCluster.setIconTint(mIconTint, mDarkIntensity);
-        mMoreIcon.setImageTintList(ColorStateList.valueOf(mIconTint));
         mBatteryMeterView.setDarkIntensity(mDarkIntensity);
         mClock.setTextColor(mIconTint);
-        applyNotificationIconsTint();
-    }
-
-    private void applyNotificationIconsTint() {
-        for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
-            StatusBarIconView v = (StatusBarIconView) mNotificationIcons.getChildAt(i);
-            boolean isPreL = Boolean.TRUE.equals(v.getTag(R.id.icon_is_pre_L));
-            boolean colorize = !isPreL || NotificationUtils.isGrayscale(v, mNotificationColorUtil);
-            if (colorize) {
-                v.setImageTintList(ColorStateList.valueOf(mIconTint));
-            }
-        }
     }
 
     public void appTransitionPending() {
@@ -443,12 +477,13 @@
 
     public static ArraySet<String> getIconBlacklist(String blackListStr) {
         ArraySet<String> ret = new ArraySet<String>();
-        if (blackListStr != null) {
-            String[] blacklist = blackListStr.split(",");
-            for (String slot : blacklist) {
-                if (!TextUtils.isEmpty(slot)) {
-                    ret.add(slot);
-                }
+        if (blackListStr == null) {
+            blackListStr = "rotate,headset";
+        }
+        String[] blacklist = blackListStr.split(",");
+        for (String slot : blacklist) {
+            if (!TextUtils.isEmpty(slot)) {
+                ret.add(slot);
             }
         }
         return ret;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java
new file mode 100644
index 0000000..62d6b76
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import com.android.internal.statusbar.StatusBarIcon;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+public class StatusBarIconList {
+    private ArrayList<String> mSlots = new ArrayList<>();
+    private ArrayList<StatusBarIcon> mIcons = new ArrayList<>();
+
+    public void defineSlots(String[] slots) {
+        final int N = slots.length;
+        for (int i=0; i < N; i++) {
+            mSlots.add(slots[i]);
+            mIcons.add(null);
+        }
+    }
+
+    public int getSlotIndex(String slot) {
+        final int N = mSlots.size();
+        for (int i=0; i<N; i++) {
+            if (slot.equals(mSlots.get(i))) {
+                return i;
+            }
+        }
+        // Auto insert new items at the beginning.
+        mSlots.add(0, slot);
+        mIcons.add(0, null);
+        return 0;
+    }
+
+    public int size() {
+        return mSlots.size();
+    }
+
+    public void setIcon(int index, StatusBarIcon icon) {
+        mIcons.set(index, icon);
+    }
+
+    public void removeIcon(int index) {
+        mIcons.set(index, null);
+    }
+
+    public String getSlot(int index) {
+        return mSlots.get(index);
+    }
+
+    public StatusBarIcon getIcon(int index) {
+        return mIcons.get(index);
+    }
+
+    public int getViewIndex(int index) {
+        int count = 0;
+        for (int i = 0; i < index; i++) {
+            if (mIcons.get(i) != null) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    public void dump(PrintWriter pw) {
+        final int N = mSlots.size();
+        pw.println("Icon list:");
+        for (int i=0; i<N; i++) {
+            pw.printf("  %2d: (%s) %s\n", i, mSlots.get(i), mIcons.get(i));
+        }
+    }
+}
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 05f6e57..7a05b8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -30,7 +30,9 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.SystemUIFactory;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.RemoteInputController;
 
 import static com.android.keyguard.KeyguardHostView.OnDismissAction;
 
@@ -40,7 +42,7 @@
  * which is in turn, reported to this class by the current
  * {@link com.android.keyguard.KeyguardViewBase}.
  */
-public class StatusBarKeyguardViewManager {
+public class StatusBarKeyguardViewManager implements RemoteInputController.Callback {
 
     // When hiding the Keyguard with timing supplied from WindowManager, better be early than late.
     private static final long HIDE_TIMING_CORRECTION_MS = -3 * 16;
@@ -53,11 +55,11 @@
 
     private static String TAG = "StatusBarKeyguardViewManager";
 
-    private final Context mContext;
+    protected final Context mContext;
 
-    private LockPatternUtils mLockPatternUtils;
-    private ViewMediatorCallback mViewMediatorCallback;
-    private PhoneStatusBar mPhoneStatusBar;
+    protected LockPatternUtils mLockPatternUtils;
+    protected ViewMediatorCallback mViewMediatorCallback;
+    protected PhoneStatusBar mPhoneStatusBar;
     private ScrimController mScrimController;
     private FingerprintUnlockController mFingerprintUnlockController;
 
@@ -66,15 +68,18 @@
 
     private boolean mDeviceInteractive = false;
     private boolean mScreenTurnedOn;
-    private KeyguardBouncer mBouncer;
-    private boolean mShowing;
-    private boolean mOccluded;
+    protected KeyguardBouncer mBouncer;
+    protected boolean mShowing;
+    protected boolean mOccluded;
+    protected boolean mRemoteInputActive;
 
-    private boolean mFirstUpdate = true;
-    private boolean mLastShowing;
-    private boolean mLastOccluded;
+    protected boolean mFirstUpdate = true;
+    protected boolean mLastShowing;
+    protected boolean mLastOccluded;
     private boolean mLastBouncerShowing;
     private boolean mLastBouncerDismissible;
+    protected boolean mLastRemoteInputActive;
+
     private OnDismissAction mAfterKeyguardGoneAction;
     private boolean mDeviceWillWakeUp;
     private boolean mDeferScrimFadeOut;
@@ -95,8 +100,8 @@
         mStatusBarWindowManager = statusBarWindowManager;
         mScrimController = scrimController;
         mFingerprintUnlockController = fingerprintUnlockController;
-        mBouncer = new KeyguardBouncer(mContext, mViewMediatorCallback, mLockPatternUtils,
-                mStatusBarWindowManager, container);
+        mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
+                mViewMediatorCallback, mLockPatternUtils, mStatusBarWindowManager, container);
     }
 
     /**
@@ -114,7 +119,7 @@
      * Shows the notification keyguard or the bouncer depending on
      * {@link KeyguardBouncer#needsFullscreenBouncer()}.
      */
-    private void showBouncerOrKeyguard() {
+    protected void showBouncerOrKeyguard() {
         if (mBouncer.needsFullscreenBouncer()) {
 
             // The keyguard might be showing (already). So we need to hide it.
@@ -199,6 +204,12 @@
         mPhoneStatusBar.onScreenTurnedOn();
     }
 
+    @Override
+    public void onRemoteInputActive(boolean active) {
+        mRemoteInputActive = active;
+        updateStates();
+    }
+
     public void onScreenTurnedOff() {
         mScreenTurnedOn = false;
     }
@@ -423,24 +434,26 @@
         }
     };
 
-    private void updateStates() {
+    protected void updateStates() {
         int vis = mContainer.getSystemUiVisibility();
         boolean showing = mShowing;
         boolean occluded = mOccluded;
         boolean bouncerShowing = mBouncer.isShowing();
         boolean bouncerDismissible = !mBouncer.isFullscreenBouncer();
+        boolean remoteInputActive = mRemoteInputActive;
 
-        if ((bouncerDismissible || !showing) != (mLastBouncerDismissible || !mLastShowing)
+        if ((bouncerDismissible || !showing || remoteInputActive) !=
+                (mLastBouncerDismissible || !mLastShowing || mLastRemoteInputActive)
                 || mFirstUpdate) {
-            if (bouncerDismissible || !showing) {
+            if (bouncerDismissible || !showing || remoteInputActive) {
                 mContainer.setSystemUiVisibility(vis & ~View.STATUS_BAR_DISABLE_BACK);
             } else {
                 mContainer.setSystemUiVisibility(vis | View.STATUS_BAR_DISABLE_BACK);
             }
         }
 
-        boolean navBarVisible = (!(showing && !occluded) || bouncerShowing);
-        boolean lastNavBarVisible = (!(mLastShowing && !mLastOccluded) || mLastBouncerShowing);
+        boolean navBarVisible = isNavBarVisible();
+        boolean lastNavBarVisible = getLastNavBarVisible();
         if (navBarVisible != lastNavBarVisible || mFirstUpdate) {
             if (mPhoneStatusBar.getNavigationBarView() != null) {
                 if (navBarVisible) {
@@ -477,10 +490,25 @@
         mLastOccluded = occluded;
         mLastBouncerShowing = bouncerShowing;
         mLastBouncerDismissible = bouncerDismissible;
+        mLastRemoteInputActive = remoteInputActive;
 
         mPhoneStatusBar.onKeyguardViewManagerStatesUpdated();
     }
 
+    /**
+     * @return Whether the navigation bar should be made visible based on the current state.
+     */
+    protected boolean isNavBarVisible() {
+        return !(mShowing && !mOccluded) || mBouncer.isShowing() || mRemoteInputActive;
+    }
+
+    /**
+     * @return Whether the navigation bar was made visible based on the last known state.
+     */
+    protected boolean getLastNavBarVisible() {
+        return !(mLastShowing && !mLastOccluded) || mLastBouncerShowing || mLastRemoteInputActive;
+    }
+
     public boolean onMenuPressed() {
         return mBouncer.onMenuPressed();
     }
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 abe51ac..382de19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -30,6 +30,7 @@
 import com.android.keyguard.R;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.StatusBarState;
 
 import java.io.FileDescriptor;
@@ -39,7 +40,7 @@
 /**
  * Encapsulates all logic for the status bar window state management.
  */
-public class StatusBarWindowManager {
+public class StatusBarWindowManager implements RemoteInputController.Callback {
 
     private final Context mContext;
     private final WindowManager mWindowManager;
@@ -133,6 +134,12 @@
             mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
             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;
+        }
     }
 
     private void applyHeight(State state) {
@@ -292,7 +299,8 @@
         apply(mCurrentState);
     }
 
-    public void setRemoteInputActive(boolean remoteInputActive) {
+    @Override
+    public void onRemoteInputActive(boolean remoteInputActive) {
         mCurrentState.remoteInputActive = remoteInputActive;
         apply(mCurrentState);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java
index 56c1e10..1aae496 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar.phone;
 
-import com.android.systemui.R;
-
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
@@ -31,10 +29,11 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 
+import com.android.systemui.R;
+import com.android.systemui.statusbar.Interpolators;
+
 public class TrustDrawable extends Drawable {
 
     private static final long ENTERING_FROM_UNSET_START_DELAY = 200;
@@ -69,10 +68,6 @@
 
     private final Animator mVisibleAnimator;
 
-    private final Interpolator mLinearOutSlowInInterpolator;
-    private final Interpolator mFastOutSlowInInterpolator;
-    private final Interpolator mAccelerateDecelerateInterpolator;
-
     public TrustDrawable(Context context) {
         Resources r = context.getResources();
         mInnerRadiusVisibleMin = r.getDimension(R.dimen.trust_circle_inner_radius_visible_min);
@@ -83,12 +78,6 @@
 
         mCurInnerRadius = mInnerRadiusEnter;
 
-        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(
-                context, android.R.interpolator.linear_out_slow_in);
-        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(
-                context, android.R.interpolator.fast_out_slow_in);
-        mAccelerateDecelerateInterpolator = new AccelerateDecelerateInterpolator();
-
         mVisibleAnimator = makeVisibleAnimator();
 
         mPaint = new Paint();
@@ -212,19 +201,19 @@
     private Animator makeVisibleAnimator() {
         return makeAnimators(mInnerRadiusVisibleMax, mInnerRadiusVisibleMin,
                 ALPHA_VISIBLE_MAX, ALPHA_VISIBLE_MIN, VISIBLE_DURATION,
-                mAccelerateDecelerateInterpolator,
+                Interpolators.ACCELERATE_DECELERATE,
                 true /* repeating */, false /* stateUpdateListener */);
     }
 
     private Animator makeEnterAnimator(float radius, int alpha) {
         return makeAnimators(radius, mInnerRadiusVisibleMax,
-                alpha, ALPHA_VISIBLE_MAX, ENTER_DURATION, mLinearOutSlowInInterpolator,
+                alpha, ALPHA_VISIBLE_MAX, ENTER_DURATION, Interpolators.LINEAR_OUT_SLOW_IN,
                 false /* repeating */, true /* stateUpdateListener */);
     }
 
     private Animator makeExitAnimator(float radius, int alpha) {
         return makeAnimators(radius, mInnerRadiusExit,
-                alpha, 0, EXIT_DURATION, mFastOutSlowInInterpolator,
+                alpha, 0, EXIT_DURATION, Interpolators.FAST_OUT_SLOW_IN,
                 false /* repeating */, true /* stateUpdateListener */);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
index 101a5f3..fd3c96e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
@@ -23,6 +23,9 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Shader;
@@ -41,6 +44,7 @@
     private float mFramePadding;
     private Bitmap mBitmap;
     private Drawable mDrawable;
+    private boolean mIsDisabled;
 
     private final Paint mFramePaint = new Paint();
     private final Paint mBitmapPaint = new Paint();
@@ -170,6 +174,7 @@
         float halfW = getWidth() / 2f;
         float halfH = getHeight() / 2f;
         float halfSW = Math.min(halfH, halfW);
+        updateDrawableIfDisabled();
         if (mBitmap != null && mScale > 0) {
             int saveCount = canvas.getSaveCount();
             canvas.save();
@@ -239,4 +244,31 @@
             mDrawable.setState(getDrawableState());
         }
     }
+
+    public void setDisabled(boolean disabled) {
+        if (mIsDisabled == disabled) {
+            return;
+        }
+        mIsDisabled = disabled;
+        invalidate();
+    }
+
+    private void updateDrawableIfDisabled() {
+        int disabledColor = getContext().getColor(R.color.qs_tile_disabled_color);
+        PorterDuffColorFilter filter = new PorterDuffColorFilter(disabledColor,
+                PorterDuff.Mode.SRC_ATOP);
+        if (mBitmap != null) {
+            if (mIsDisabled) {
+                mBitmapPaint.setColorFilter(filter);
+            } else {
+                mBitmapPaint.setColorFilter(null);
+            }
+        } else if (mDrawable != null) {
+            if (mIsDisabled) {
+                mDrawable.setColorFilter(filter);
+            } else {
+                mDrawable.setColorFilter(null);
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index 5071df0..bb3e116 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -70,9 +70,14 @@
         pw.print("  mPowerSave="); pw.println(mPowerSave);
     }
 
+    public void setPowerSaveMode(boolean powerSave) {
+        mPowerManager.setPowerSaveMode(powerSave);
+    }
+
     public void addStateChangedCallback(BatteryStateChangeCallback cb) {
         mChangeCallbacks.add(cb);
         cb.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
+        cb.onPowerSaveChanged(mPowerSave);
     }
 
     public void removeStateChangedCallback(BatteryStateChangeCallback cb) {
@@ -158,12 +163,12 @@
     private void firePowerSaveChanged() {
         final int N = mChangeCallbacks.size();
         for (int i = 0; i < N; i++) {
-            mChangeCallbacks.get(i).onPowerSaveChanged();
+            mChangeCallbacks.get(i).onPowerSaveChanged(mPowerSave);
         }
     }
 
     public interface BatteryStateChangeCallback {
         void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging);
-        void onPowerSaveChanged();
+        void onPowerSaveChanged(boolean isPowerSave);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
index 8fa9c7e..e7e2ac2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -33,6 +33,7 @@
     Collection<CachedBluetoothDevice> getDevices();
     void connect(CachedBluetoothDevice device);
     void disconnect(CachedBluetoothDevice device);
+    boolean canConfigBluetooth();
 
     public interface Callback {
         void onBluetoothStateChange(boolean enabled);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index a04edf7..6439bea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -16,11 +16,14 @@
 
 package com.android.systemui.statusbar.policy;
 
+import android.app.ActivityManager;
 import android.bluetooth.BluetoothAdapter;
 import android.content.Context;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.Log;
 
 import com.android.settingslib.bluetooth.BluetoothCallback;
@@ -39,6 +42,8 @@
 
     private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
     private final LocalBluetoothManager mLocalBluetoothManager;
+    private final UserManager mUserManager;
+    private final int mCurrentUser;
 
     private boolean mEnabled;
     private int mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
@@ -54,6 +59,14 @@
             onBluetoothStateChanged(
                     mLocalBluetoothManager.getBluetoothAdapter().getBluetoothState());
         }
+        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        mCurrentUser = ActivityManager.getCurrentUser();
+    }
+
+    @Override
+    public boolean canConfigBluetooth() {
+        return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_BLUETOOTH,
+                UserHandle.of(mCurrentUser));
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
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 0340984..59d54ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -16,15 +16,15 @@
 
 package com.android.systemui.statusbar.policy;
 
-import com.android.systemui.R;
-import com.android.systemui.statusbar.ScrimView;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
-import com.android.systemui.statusbar.phone.StatusBarWindowView;
-
 import android.view.View;
 import android.view.ViewPropertyAnimator;
 import android.widget.FrameLayout;
 
+import com.android.systemui.R;
+import com.android.systemui.statusbar.Interpolators;
+import com.android.systemui.statusbar.ScrimView;
+import com.android.systemui.statusbar.phone.StatusBarWindowView;
+
 /**
  * Controls showing and hiding of the brightness mirror.
  */
@@ -35,25 +35,25 @@
 
     private final ScrimView mScrimBehind;
     private final View mBrightnessMirror;
-    private final View mPanelHolder;
+    private final View mNotificationPanel;
     private final int[] mInt2Cache = new int[2];
 
     public BrightnessMirrorController(StatusBarWindowView statusBarWindow) {
         mScrimBehind = (ScrimView) statusBarWindow.findViewById(R.id.scrim_behind);
         mBrightnessMirror = statusBarWindow.findViewById(R.id.brightness_mirror);
-        mPanelHolder = statusBarWindow.findViewById(R.id.panel_holder);
+        mNotificationPanel = statusBarWindow.findViewById(R.id.notification_panel);
     }
 
     public void showMirror() {
         mBrightnessMirror.setVisibility(View.VISIBLE);
-        mScrimBehind.animateViewAlpha(0.0f, TRANSITION_DURATION_OUT, PhoneStatusBar.ALPHA_OUT);
-        outAnimation(mPanelHolder.animate())
+        mScrimBehind.animateViewAlpha(0.0f, TRANSITION_DURATION_OUT, Interpolators.ALPHA_OUT);
+        outAnimation(mNotificationPanel.animate())
                 .withLayer();
     }
 
     public void hideMirror() {
-        mScrimBehind.animateViewAlpha(1.0f, TRANSITION_DURATION_IN, PhoneStatusBar.ALPHA_IN);
-        inAnimation(mPanelHolder.animate())
+        mScrimBehind.animateViewAlpha(1.0f, TRANSITION_DURATION_IN, Interpolators.ALPHA_IN);
+        inAnimation(mNotificationPanel.animate())
                 .withLayer()
                 .withEndAction(new Runnable() {
             @Override
@@ -66,12 +66,12 @@
     private ViewPropertyAnimator outAnimation(ViewPropertyAnimator a) {
         return a.alpha(0.0f)
                 .setDuration(TRANSITION_DURATION_OUT)
-                .setInterpolator(PhoneStatusBar.ALPHA_OUT);
+                .setInterpolator(Interpolators.ALPHA_OUT);
     }
     private ViewPropertyAnimator inAnimation(ViewPropertyAnimator a) {
         return a.alpha(1.0f)
                 .setDuration(TRANSITION_DURATION_IN)
-                .setInterpolator(PhoneStatusBar.ALPHA_IN);
+                .setInterpolator(Interpolators.ALPHA_IN);
     }
 
 
@@ -103,10 +103,5 @@
         lp.gravity = mBrightnessMirror.getResources().getInteger(
                 R.integer.notification_panel_layout_gravity);
         mBrightnessMirror.setLayoutParams(lp);
-
-        int padding = mBrightnessMirror.getResources().getDimensionPixelSize(
-                R.dimen.notification_side_padding);
-        mBrightnessMirror.setPadding(padding, mBrightnessMirror.getPaddingTop(),
-                padding, mBrightnessMirror.getPaddingBottom());
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 896bd62..7054bb8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -31,15 +31,16 @@
 import android.text.format.DateFormat;
 import android.text.style.CharacterStyle;
 import android.text.style.RelativeSizeSpan;
+import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.view.Display;
+import android.view.View;
 import android.widget.TextView;
-
 import com.android.systemui.DemoMode;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
-
 import libcore.icu.LocaleData;
 
 import java.text.SimpleDateFormat;
@@ -87,7 +88,6 @@
         } finally {
             a.recycle();
         }
-        TunerService.get(context).addTunable(this, CLOCK_SECONDS);
     }
 
     @Override
@@ -106,6 +106,8 @@
 
             getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter,
                     null, getHandler());
+            TunerService.get(getContext()).addTunable(this, CLOCK_SECONDS,
+                    StatusBarIconController.ICON_BLACKLIST);
         }
 
         // NOTE: It's safe to do these after registering the receiver since the receiver always runs
@@ -125,6 +127,7 @@
         if (mAttached) {
             getContext().unregisterReceiver(mIntentReceiver);
             mAttached = false;
+            TunerService.get(getContext()).removeTunable(this);
         }
     }
 
@@ -157,8 +160,13 @@
 
     @Override
     public void onTuningChanged(String key, String newValue) {
-        mShowSeconds = newValue != null && Integer.parseInt(newValue) != 0;
-        updateShowSeconds();
+        if (CLOCK_SECONDS.equals(key)) {
+            mShowSeconds = newValue != null && Integer.parseInt(newValue) != 0;
+            updateShowSeconds();
+        } else if (StatusBarIconController.ICON_BLACKLIST.equals(key)) {
+            ArraySet<String> list = StatusBarIconController.getIconBlacklist(newValue);
+            setVisibility(list.contains("clock") ? View.GONE : View.VISIBLE);
+        }
     }
 
     private void updateShowSeconds() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.java
new file mode 100644
index 0000000..186e8b5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverController.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 com.android.systemui.statusbar.policy;
+
+import android.content.Context;
+import android.net.INetworkPolicyListener;
+import android.net.NetworkPolicyManager;
+import android.os.Handler;
+import android.os.RemoteException;
+
+import java.util.ArrayList;
+
+public class DataSaverController {
+
+    private final Handler mHandler = new Handler();
+    private final ArrayList<Listener> mListeners = new ArrayList<>();
+    private final NetworkPolicyManager mPolicyManager;
+
+    public DataSaverController(Context context) {
+        mPolicyManager = NetworkPolicyManager.from(context);
+    }
+
+    private void handleRestrictBackgroundChanged(boolean isDataSaving) {
+        final int N = mListeners.size();
+        for (int i = 0; i < N; i++) {
+            mListeners.get(i).onDataSaverChanged(isDataSaving);
+        }
+    }
+
+    public void addListener(Listener listener) {
+        mListeners.add(listener);
+        if (mListeners.size() == 1) {
+            mPolicyManager.registerListener(mPolicyListener);
+        }
+        listener.onDataSaverChanged(isDataSaverEnabled());
+    }
+
+    public void remListener(Listener listener) {
+        mListeners.remove(listener);
+        if (mListeners.size() == 0) {
+            mPolicyManager.unregisterListener(mPolicyListener);
+        }
+    }
+
+    public boolean isDataSaverEnabled() {
+        return mPolicyManager.getRestrictBackground();
+    }
+
+    public void setDataSaverEnabled(boolean enabled) {
+        mPolicyManager.setRestrictBackground(enabled);
+    }
+
+    private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
+        @Override
+        public void onUidRulesChanged(int i, int i1) throws RemoteException {
+        }
+
+        @Override
+        public void onMeteredIfacesChanged(String[] strings) throws RemoteException {
+        }
+
+        @Override
+        public void onRestrictBackgroundChanged(final boolean isDataSaving) throws RemoteException {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    handleRestrictBackgroundChanged(isDataSaving);
+                }
+            });
+        }
+    };
+
+    public interface Listener {
+        void onDataSaverChanged(boolean isDataSaving);
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DisplayController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DisplayController.java
new file mode 100644
index 0000000..e5d244f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DisplayController.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Configuration;
+import android.provider.Settings;
+import com.android.systemui.R;
+import com.android.systemui.tuner.TunerService;
+import libcore.util.Objects;
+
+import java.util.ArrayList;
+
+public class DisplayController implements TunerService.Tunable {
+
+    public static final String COLOR_MATRIX_CUSTOM_ENABLED = "tuner_color_custom_enabled";
+    public static final String COLOR_MATRIX_CUSTOM_VALUES = "tuner_color_custom_values";
+
+    public static final String COLOR_STATE = "sysui_color_matrix_state";
+
+    public static final int COLOR_STATE_DISABLED = 0;
+    public static final int COLOR_STATE_ENABLED = 1;
+    public static final int COLOR_STATE_AUTO = 2;
+
+    public static final String AUTO_STRING = "auto_mode";
+    public static final String NONE_STRING = "none";
+
+    public static final int AUTO_INDEX = 2;
+    public static final int CUSTOM_INDEX = 3;
+
+    // Night mode ~= 3400 K
+    private static final float[] NIGHT_VALUES = new float[] {
+        1, 0,     0,     0,
+        0, .754f, 0,     0,
+        0, 0,     .516f, 0,
+        0, 0,     0,     1,
+    };
+    public static final float[] IDENTITY_MATRIX = new float[] {
+        1, 0, 0, 0,
+        0, 1, 0, 0,
+        0, 0, 1, 0,
+        0, 0, 0, 1,
+    };
+
+    private final ArrayList<Listener> mListeners = new ArrayList<>();
+
+    private final Context mContext;
+
+    private String mCurrentValue;
+    private boolean mListening;
+
+    public DisplayController(Context context) {
+        mContext = context;
+        TunerService.get(mContext).addTunable(this, COLOR_STATE,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX);
+    }
+
+    public void addListener(Listener listener) {
+        mListeners.add(listener);
+        listener.onCurrentMatrixChanged();
+    }
+
+    public void removeListener(Listener listener) {
+        mListeners.remove(listener);
+    }
+
+    public boolean isEnabled() {
+        return TunerService.get(mContext).getValue(COLOR_STATE, COLOR_STATE_DISABLED)
+                != COLOR_STATE_DISABLED;
+    }
+
+    public boolean isAuto() {
+        return mListening;
+    }
+
+    public void setAuto(boolean auto) {
+        TunerService.get(mContext).setValue(COLOR_STATE, auto ? COLOR_STATE_AUTO
+                : COLOR_STATE_DISABLED);
+    }
+
+    public boolean isCustomSet() {
+        return isCustomEnabled() && Objects.equal(getCurrentMatrix(), getCustomValues());
+    }
+
+    public String getCurrentMatrix() {
+        return mCurrentValue;
+    }
+
+    public String getCustomValues() {
+        return TunerService.get(mContext).getValue(COLOR_MATRIX_CUSTOM_VALUES);
+    }
+
+    public boolean isCustomEnabled() {
+        return TunerService.get(mContext).getValue(COLOR_MATRIX_CUSTOM_ENABLED, 0) != 0;
+    }
+
+    @Override
+    public void onTuningChanged(String key, String newValue) {
+        if (Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX.equals(key)) {
+            mCurrentValue = newValue;
+            for (int i = 0; i < mListeners.size(); i++) {
+                mListeners.get(i).onCurrentMatrixChanged();
+            }
+        } else if (COLOR_STATE.equals(key)) {
+            final boolean listening = newValue != null
+                    && Integer.parseInt(newValue) == COLOR_STATE_AUTO;
+            if (listening && !mListening) {
+                mListening = true;
+                mContext.registerReceiver(mReceiver,
+                        new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
+                updateNightMode();
+            } else if (!listening && mListening) {
+                mListening = false;
+                mContext.unregisterReceiver(mReceiver);
+            }
+            for (int i = 0; i < mListeners.size(); i++) {
+                mListeners.get(i).onCurrentMatrixChanged();
+            }
+        }
+    }
+
+    private void updateNightMode() {
+        final int uiMode = mContext.getResources().getConfiguration().uiMode;
+        final boolean isNightMode = (uiMode & Configuration.UI_MODE_NIGHT_MASK)
+                == Configuration.UI_MODE_NIGHT_YES;
+        String value = null;
+        if (isNightMode) {
+            value = toString(NIGHT_VALUES);
+        }
+        TunerService.get(mContext).setValue(Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
+                value);
+    }
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_CONFIGURATION_CHANGED.equals(intent.getAction())) {
+                updateNightMode();
+            }
+        }
+    };
+
+    public interface Listener {
+        void onCurrentMatrixChanged();
+    }
+
+    public static String[] getColorTransforms(Context context) {
+        return new String[] {
+                NONE_STRING,
+                toString(NIGHT_VALUES),
+                AUTO_STRING, // Blank spot for auto values
+                null, // Blank spot for custom values
+        };
+    }
+
+    public static CharSequence[] getColorTitles(Context context) {
+        // TODO: Move to string array resource.
+        return new CharSequence[]{
+                context.getString(R.string.color_matrix_none),
+                context.getString(R.string.color_matrix_night),
+                context.getString(R.string.color_matrix_auto),
+                context.getString(R.string.color_matrix_custom),
+        };
+    }
+
+    public static String toString(float[] values) {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < values.length; i++) {
+            if (builder.length() != 0) {
+                builder.append(',');
+            }
+            builder.append(values[i]);
+        }
+        return builder.toString();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FullscreenUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FullscreenUserSwitcher.java
deleted file mode 100644
index fd8852e..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FullscreenUserSwitcher.java
+++ /dev/null
@@ -1,58 +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.policy;
-
-import android.content.Context;
-import android.provider.Settings;
-import android.view.View;
-import android.view.ViewStub;
-
-import com.android.systemui.R;
-import com.android.systemui.statusbar.UserGridView;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
-
-/**
- * Manages the fullscreen user switcher.
- */
-public class FullscreenUserSwitcher {
-
-    private View mContainer;
-    private UserGridView mUserGridView;
-    private UserSwitcherController mUserSwitcherController;
-
-    public FullscreenUserSwitcher(PhoneStatusBar statusBar,
-            UserSwitcherController userSwitcherController,
-            ViewStub containerStub) {
-        mUserSwitcherController = userSwitcherController;
-        mContainer = containerStub.inflate();
-        mUserGridView = (UserGridView) mContainer.findViewById(R.id.user_grid);
-        mUserGridView.init(statusBar, mUserSwitcherController);
-    }
-
-    public void onUserSwitched(int newUserId) {
-        mUserGridView.onUserSwitched(newUserId);
-    }
-
-    public void show() {
-        mContainer.setVisibility(View.VISIBLE);
-    }
-
-    public void hide() {
-        mContainer.setVisibility(View.GONE);
-    }
-}
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index 5cfd174..f065522 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -84,7 +84,6 @@
 
     private final View mStatusBarWindowView;
     private final int mStatusBarHeight;
-    private final int mNotificationsTopPadding;
     private final Context mContext;
     private final NotificationGroupManager mGroupManager;
     private PhoneStatusBar mBar;
@@ -138,8 +137,6 @@
         mGroupManager = groupManager;
         mStatusBarHeight = resources.getDimensionPixelSize(
                 com.android.internal.R.dimen.status_bar_height);
-        mNotificationsTopPadding = context.getResources()
-                .getDimensionPixelSize(R.dimen.notifications_top_padding);
     }
 
     private void updateTouchableRegionListener() {
@@ -190,7 +187,6 @@
         if (alert) {
             HeadsUpEntry headsUpEntry = mHeadsUpEntries.get(headsUp.key);
             headsUpEntry.updateEntry();
-            mGroupManager.onEntryHeadsUped(headsUp);
             setEntryPinned(headsUpEntry, shouldHeadsUpBecomePinned(headsUp));
         }
     }
@@ -378,23 +374,29 @@
             return;
         }
         if (mHasPinnedNotification) {
-            int minX = Integer.MAX_VALUE;
+            int minX = 0;
             int maxX = 0;
-            int minY = Integer.MAX_VALUE;
             int maxY = 0;
             for (HeadsUpEntry entry : mSortedEntries) {
                 ExpandableNotificationRow row = entry.entry.row;
                 if (row.isPinned()) {
+                    if (row.isChildInGroup()) {
+                        final ExpandableNotificationRow groupSummary
+                                = mGroupManager.getGroupSummary(row.getStatusBarNotification());
+                        if (groupSummary != null) {
+                            row = groupSummary;
+                        }
+                    }
                     row.getLocationOnScreen(mTmpTwoArray);
-                    minX = Math.min(minX, mTmpTwoArray[0]);
-                    minY = Math.min(minY, 0);
-                    maxX = Math.max(maxX, mTmpTwoArray[0] + row.getWidth());
-                    maxY = Math.max(maxY, row.getHeadsUpHeight());
+                    minX = mTmpTwoArray[0];
+                    maxX = mTmpTwoArray[0] + row.getWidth();
+                    maxY = row.getIntrinsicHeight();
+                    break;
                 }
             }
 
             info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
-            info.touchableRegion.set(minX, minY, maxX, maxY + mNotificationsTopPadding);
+            info.touchableRegion.set(minX, 0, maxX, maxY);
         } else if (mHeadsUpGoingAway || mWaitingOnCollapseWhenGoingAway) {
             info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
             info.touchableRegion.set(0, 0, mStatusBarWindowView.getWidth(), mStatusBarHeight);
@@ -449,6 +451,8 @@
         for (String key : mHeadsUpEntries.keySet()) {
             HeadsUpEntry entry = mHeadsUpEntries.get(key);
             setEntryPinned(entry, false /* isPinned */);
+            // maybe it got un sticky
+            entry.updateEntry(false /* updatePostTime */);
         }
     }
 
@@ -471,6 +475,10 @@
         mTrackingHeadsUp = trackingHeadsUp;
     }
 
+    public boolean isTrackingHeadsUp() {
+        return mTrackingHeadsUp;
+    }
+
     public void setIsExpanded(boolean isExpanded) {
         if (isExpanded != mIsExpanded) {
             mIsExpanded = isExpanded;
@@ -483,9 +491,25 @@
         }
     }
 
-    public int getTopHeadsUpHeight() {
+    /**
+     * @return the height of the top heads up notification when pinned. This is different from the
+     *         intrinsic height, which also includes whether the notification is system expanded and
+     *         is mainly used when dragging down from a heads up notification.
+     */
+    public int getTopHeadsUpPinnedHeight() {
         HeadsUpEntry topEntry = getTopEntry();
-        return topEntry != null ? topEntry.entry.row.getHeadsUpHeight() : 0;
+        if (topEntry == null || topEntry.entry == null) {
+            return 0;
+        }
+        ExpandableNotificationRow row = topEntry.entry.row;
+        if (row.isChildInGroup()) {
+            final ExpandableNotificationRow groupSummary
+                    = mGroupManager.getGroupSummary(row.getStatusBarNotification());
+            if (groupSummary != null) {
+                row = groupSummary;
+            }
+        }
+        return row.getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
     }
 
     /**
@@ -559,6 +583,22 @@
     }
 
     /**
+     * Set an entry to be expanded and therefore stick in the heads up area if it's pinned
+     * until it's collapsed again.
+     */
+    public void setExpanded(NotificationData.Entry entry, boolean expanded) {
+        HeadsUpEntry headsUpEntry = mHeadsUpEntries.get(entry.key);
+        if (headsUpEntry != null && headsUpEntry.expanded != expanded) {
+            headsUpEntry.expanded = expanded;
+            if (expanded) {
+                headsUpEntry.removeAutoRemovalCallbacks();
+            } else {
+                headsUpEntry.updateEntry(false /* updatePostTime */);
+            }
+        }
+    }
+
+    /**
      * This represents a notification and how long it is in a heads up mode. It also manages its
      * lifecycle automatically when created.
      */
@@ -568,6 +608,7 @@
         public long earliestRemovaltime;
         private Runnable mRemoveHeadsUpRunnable;
         public boolean remoteInputActive;
+        public boolean expanded;
 
         public void setEntry(final NotificationData.Entry entry) {
             this.entry = entry;
@@ -602,7 +643,7 @@
             if (mEntriesToRemoveAfterExpand.contains(entry)) {
                 mEntriesToRemoveAfterExpand.remove(entry);
             }
-            if (!hasFullScreenIntent(entry) && !mRemoteInputActive) {
+            if (!isSticky()) {
                 long finishTime = postTime + mHeadsUpNotificationDecay;
                 long removeDelay = Math.max(finishTime - currentTime, mMinimumDisplayTime);
                 mHandler.postDelayed(mRemoveHeadsUpRunnable, removeDelay);
@@ -610,6 +651,11 @@
             mSortedEntries.add(HeadsUpEntry.this);
         }
 
+        private boolean isSticky() {
+            return (entry.row.isPinned() && expanded)
+                    || remoteInputActive || hasFullScreenIntent(entry);
+        }
+
         @Override
         public int compareTo(HeadsUpEntry o) {
             boolean selfFullscreen = hasFullScreenIntent(entry);
@@ -642,6 +688,8 @@
             removeAutoRemovalCallbacks();
             entry = null;
             mRemoveHeadsUpRunnable = null;
+            expanded = false;
+            remoteInputActive = false;
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
index 7ca91a5..b036936 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
@@ -22,6 +22,7 @@
     boolean isHotspotEnabled();
     boolean isHotspotSupported();
     void setHotspotEnabled(boolean enabled);
+    boolean isTetheringAllowed();
 
     public interface Callback {
         void onHotspotChanged(boolean enabled);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 41aeac9..61d26c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -16,12 +16,15 @@
 
 package com.android.systemui.statusbar.policy;
 
+import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.net.ConnectivityManager;
 import android.net.wifi.WifiManager;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.Log;
 
 import com.android.settingslib.TetherUtil;
@@ -34,21 +37,22 @@
 
     private static final String TAG = "HotspotController";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-    private static final Intent TETHER_SERVICE_INTENT = new Intent()
-            .putExtra(TetherUtil.EXTRA_ADD_TETHER_TYPE, TetherUtil.TETHERING_WIFI)
-            .putExtra(TetherUtil.EXTRA_SET_ALARM, true)
-            .putExtra(TetherUtil.EXTRA_RUN_PROVISION, true)
-            .putExtra(TetherUtil.EXTRA_ENABLE_WIFI_TETHER, true)
-            .setComponent(TetherUtil.TETHER_SERVICE);
 
     private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
     private final Receiver mReceiver = new Receiver();
+    private final ConnectivityManager mConnectivityManager;
     private final Context mContext;
+    private final UserManager mUserManager;
+    private final int mCurrentUser;
 
     private int mHotspotState;
 
     public HotspotControllerImpl(Context context) {
         mContext = context;
+        mConnectivityManager = (ConnectivityManager) context.getSystemService(
+                Context.CONNECTIVITY_SERVICE);
+        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        mCurrentUser = ActivityManager.getCurrentUser();
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -72,6 +76,7 @@
         return null;
     }
 
+    @Override
     public void addCallback(Callback callback) {
         if (callback == null || mCallbacks.contains(callback)) return;
         if (DEBUG) Log.d(TAG, "addCallback " + callback);
@@ -79,6 +84,7 @@
         mReceiver.setListening(!mCallbacks.isEmpty());
     }
 
+    @Override
     public void removeCallback(Callback callback) {
         if (callback == null) return;
         if (DEBUG) Log.d(TAG, "removeCallback " + callback);
@@ -97,12 +103,29 @@
     }
 
     @Override
+    public boolean isTetheringAllowed() {
+        return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING,
+                UserHandle.of(mCurrentUser));
+    }
+
+    static final class OnStartTetheringCallback extends
+            ConnectivityManager.OnStartTetheringCallback {
+        @Override
+        public void onTetheringStarted() {}
+        @Override
+        public void onTetheringFailed() {
+          // TODO: Show error.
+        }
+    }
+
+    @Override
     public void setHotspotEnabled(boolean enabled) {
-        // Call provisioning app which is called when enabling Tethering from Settings
-        if (enabled && TetherUtil.isProvisioningNeeded(mContext)) {
-            mContext.startServiceAsUser(TETHER_SERVICE_INTENT, UserHandle.CURRENT);
+        if (enabled) {
+            OnStartTetheringCallback callback = new OnStartTetheringCallback();
+            mConnectivityManager.startTethering(
+                    ConnectivityManager.TETHERING_WIFI, false, callback);
         } else {
-            TetherUtil.setWifiTethering(enabled, mContext);
+            mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
index 3f63b5f..d739d6c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
@@ -32,7 +32,7 @@
 import android.view.animation.Interpolator;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.Interpolators;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -59,7 +59,6 @@
     private int mMaxWidth;
 
     private final Interpolator mInterpolator = new LogInterpolator();
-    private final Interpolator mAlphaExitInterpolator = PhoneStatusBar.ALPHA_OUT;
     private boolean mSupportHardware;
     private final View mTargetView;
 
@@ -225,7 +224,7 @@
 
     private void exitSoftware() {
         ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(this, "glowAlpha", mGlowAlpha, 0f);
-        alphaAnimator.setInterpolator(mAlphaExitInterpolator);
+        alphaAnimator.setInterpolator(Interpolators.ALPHA_OUT);
         alphaAnimator.setDuration(ANIMATION_DURATION_FADE);
         alphaAnimator.addListener(mAnimatorListener);
         alphaAnimator.start();
@@ -331,7 +330,7 @@
         final RenderNodeAnimator opacityAnim = new RenderNodeAnimator(mPaintProp,
                 RenderNodeAnimator.PAINT_ALPHA, 0);
         opacityAnim.setDuration(ANIMATION_DURATION_FADE);
-        opacityAnim.setInterpolator(mAlphaExitInterpolator);
+        opacityAnim.setInterpolator(Interpolators.ALPHA_OUT);
         opacityAnim.addListener(mAnimatorListener);
         opacityAnim.setTarget(mTargetView);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index ba284c9..6e7cf19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -20,8 +20,12 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
 import android.hardware.input.InputManager;
 import android.media.AudioManager;
+import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.util.AttributeSet;
@@ -99,6 +103,24 @@
         setBackground(new KeyButtonRipple(context, this));
     }
 
+    public void setCode(int code) {
+        mCode = code;
+    }
+
+    public void loadAsync(String uri) {
+        new AsyncTask<String, Void, Drawable>() {
+            @Override
+            protected Drawable doInBackground(String... params) {
+                return Icon.createWithContentUri(params[0]).loadDrawable(mContext);
+            }
+
+            @Override
+            protected void onPostExecute(Drawable drawable) {
+                setImageDrawable(drawable);
+            }
+        }.execute(uri);
+    }
+
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
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 5cf6156..0959b0c 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,7 @@
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.database.DataSetObserver;
+import android.graphics.Interpolator;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -33,9 +34,9 @@
 import com.android.settingslib.animation.AppearAnimationUtils;
 import com.android.systemui.R;
 import com.android.systemui.qs.tiles.UserDetailItemView;
+import com.android.systemui.statusbar.Interpolators;
 import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
 import com.android.systemui.statusbar.phone.NotificationPanelView;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
 
 /**
  * Manages the user switcher on the Keyguard.
@@ -73,8 +74,7 @@
             mAdapter.registerDataSetObserver(mDataSetObserver);
             mUserSwitcherController = userSwitcherController;
             mAppearAnimationUtils = new AppearAnimationUtils(context, 400, -0.5f, 0.5f,
-                    AnimationUtils.loadInterpolator(
-                            context, android.R.interpolator.fast_out_slow_in));
+                    Interpolators.FAST_OUT_SLOW_IN);
             mUserSwitcherContainer.setKeyguardUserSwitcher(this);
         } else {
             mUserSwitcherContainer = null;
@@ -158,7 +158,7 @@
         mAnimating = true;
         mBgAnimator = ObjectAnimator.ofInt(mBackground, "alpha", 0, 255);
         mBgAnimator.setDuration(400);
-        mBgAnimator.setInterpolator(PhoneStatusBar.ALPHA_IN);
+        mBgAnimator.setInterpolator(Interpolators.ALPHA_IN);
         mBgAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
@@ -174,7 +174,7 @@
         mUserSwitcher.animate()
                 .alpha(0f)
                 .setDuration(300)
-                .setInterpolator(PhoneStatusBar.ALPHA_OUT)
+                .setInterpolator(Interpolators.ALPHA_OUT)
                 .withEndAction(new Runnable() {
                     @Override
                     public void run() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
index 29a8981..401943e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
@@ -21,6 +21,7 @@
     boolean setLocationEnabled(boolean enabled);
     void addSettingsChangedCallback(LocationSettingsChangeCallback cb);
     void removeSettingsChangedCallback(LocationSettingsChangeCallback cb);
+    boolean isUserLocationRestricted();
 
     /**
      * A callback for change in location settings (the user has enabled/disabled location).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 0917528..436a40d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -43,7 +43,6 @@
 public class LocationControllerImpl extends BroadcastReceiver implements LocationController {
     // The name of the placeholder corresponding to the location request status icon.
     // This string corresponds to config_statusBarIcons in core/res/res/values/config.xml.
-    public static final String LOCATION_STATUS_ICON_PLACEHOLDER = "location";
     public static final int LOCATION_STATUS_ICON_ID = R.drawable.stat_sys_location;
 
     private static final int[] mHighPowerRequestAppOpArray
@@ -53,15 +52,18 @@
 
     private AppOpsManager mAppOpsManager;
     private StatusBarManager mStatusBarManager;
+    private final int mCurrentUser;
 
     private boolean mAreActiveLocationRequests;
 
     private ArrayList<LocationSettingsChangeCallback> mSettingsChangeCallbacks =
             new ArrayList<LocationSettingsChangeCallback>();
     private final H mHandler = new H();
+    public final String mSlotLocation;
 
     public LocationControllerImpl(Context context, Looper bgLooper) {
         mContext = context;
+        mSlotLocation = mContext.getString(com.android.internal.R.string.status_bar_location);
 
         // Register to listen for changes in location settings.
         IntentFilter filter = new IntentFilter();
@@ -72,6 +74,7 @@
         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
         mStatusBarManager
                 = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
+        mCurrentUser = ActivityManager.getCurrentUser();
 
         // Examine the current location state and initialize the status view.
         updateActiveLocationRequests();
@@ -102,10 +105,6 @@
      * @return true if attempt to change setting was successful.
      */
     public boolean setLocationEnabled(boolean enabled) {
-        int currentUserId = ActivityManager.getCurrentUser();
-        if (isUserLocationRestricted(currentUserId)) {
-            return false;
-        }
         final ContentResolver cr = mContext.getContentResolver();
         // When enabling location, a user consent dialog will pop up, and the
         // setting won't be fully enabled until the user accepts the agreement.
@@ -114,7 +113,7 @@
         // QuickSettings always runs as the owner, so specifically set the settings
         // for the current foreground user.
         return Settings.Secure
-                .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, currentUserId);
+                .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, mCurrentUser);
     }
 
     /**
@@ -132,11 +131,10 @@
     /**
      * Returns true if the current user is restricted from using location.
      */
-    private boolean isUserLocationRestricted(int userId) {
+    public boolean isUserLocationRestricted() {
         final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        return um.hasUserRestriction(
-                UserManager.DISALLOW_SHARE_LOCATION,
-                new UserHandle(userId));
+        return um.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION,
+                UserHandle.of(mCurrentUser));
     }
 
     /**
@@ -173,10 +171,10 @@
     // Updates the status view based on the current state of location requests.
     private void refreshViews() {
         if (mAreActiveLocationRequests) {
-            mStatusBarManager.setIcon(LOCATION_STATUS_ICON_PLACEHOLDER, LOCATION_STATUS_ICON_ID,
+            mStatusBarManager.setIcon(mSlotLocation, LOCATION_STATUS_ICON_ID,
                     0, mContext.getString(R.string.accessibility_location_active));
         } else {
-            mStatusBarManager.removeIcon(LOCATION_STATUS_ICON_PLACEHOLDER);
+            mStatusBarManager.removeIcon(mSlotLocation);
         }
     }
 
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 b65bf43..8fd4d9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -206,7 +206,8 @@
 
         // Show icon in QS when we are connected or need to show roaming.
         boolean showDataIcon = mCurrentState.dataConnected
-                || mCurrentState.iconGroup == TelephonyIcons.ROAMING;
+                || mCurrentState.iconGroup == TelephonyIcons.ROAMING
+                || mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED;
         IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode,
                 getCurrentIconId(), contentDescription);
 
@@ -227,7 +228,8 @@
                         && !mCurrentState.carrierNetworkChangeMode
                         && mCurrentState.activityOut;
         showDataIcon &= mCurrentState.isDefault
-                || mCurrentState.iconGroup == TelephonyIcons.ROAMING;
+                || mCurrentState.iconGroup == TelephonyIcons.ROAMING
+                || mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED;
         int typeIcon = showDataIcon ? icons.mDataType : 0;
         mCallbackHandler.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
                 activityIn, activityOut, dataContentDescription, description, icons.mIsWide,
@@ -385,6 +387,8 @@
             mCurrentState.iconGroup = TelephonyIcons.CARRIER_NETWORK_CHANGE;
         } else if (isRoaming()) {
             mCurrentState.iconGroup = TelephonyIcons.ROAMING;
+        } else if (isDataDisabled()) {
+            mCurrentState.iconGroup = TelephonyIcons.DATA_DISABLED;
         }
         if (isEmergencyOnly() != mCurrentState.isEmergency) {
             mCurrentState.isEmergency = isEmergencyOnly();
@@ -399,6 +403,10 @@
         notifyListenersIfNecessary();
     }
 
+    private boolean isDataDisabled() {
+        return !mPhone.getDataEnabled(mSubscriptionInfo.getSubscriptionId());
+    }
+
     @VisibleForTesting
     void setActivity(int activity) {
         mCurrentState.activityIn = activity == TelephonyManager.DATA_ACTIVITY_INOUT
@@ -440,6 +448,7 @@
                         + " dataState=" + state.getDataRegState());
             }
             mServiceState = state;
+            mDataNetType = state.getDataNetworkType();
             updateTelephony();
         }
 
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 f8c72b3..755a5b3 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,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.telephony.SubscriptionInfo;
-import com.android.settingslib.net.MobileDataController;
+import com.android.settingslib.net.DataUsageController;
 import com.android.settingslib.wifi.AccessPoint;
 
 import java.util.List;
@@ -32,7 +32,8 @@
     void setWifiEnabled(boolean enabled);
     void onUserSwitched(int newUserId);
     AccessPointController getAccessPointController();
-    MobileDataController getMobileDataController();
+    DataUsageController getMobileDataController();
+    DataSaverController getDataSaverController();
 
     public interface SignalCallback {
         void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
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 909f497..107a904 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -40,7 +40,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
-import com.android.settingslib.net.MobileDataController;
+import com.android.settingslib.net.DataUsageController;
 import com.android.systemui.DemoMode;
 import com.android.systemui.R;
 
@@ -59,7 +59,7 @@
 
 /** Platform implementation of the network controller. **/
 public class NetworkControllerImpl extends BroadcastReceiver
-        implements NetworkController, DemoMode, MobileDataController.NetworkNameProvider {
+        implements NetworkController, DemoMode, DataUsageController.NetworkNameProvider {
     // debug
     static final String TAG = "NetworkController";
     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -78,6 +78,7 @@
     private final SubscriptionManager mSubscriptionManager;
     private final boolean mHasMobileDataFeature;
     private final SubscriptionDefaults mSubDefaults;
+    private final DataSaverController mDataSaverController;
     private Config mConfig;
 
     // Subcontrollers.
@@ -94,7 +95,7 @@
     // SIM for most actions.  This may be null if there aren't any SIMs around.
     private MobileSignalController mDefaultSignalController;
     private final AccessPointControllerImpl mAccessPoints;
-    private final MobileDataController mMobileDataController;
+    private final DataUsageController mDataUsageController;
 
     private boolean mInetCondition; // Used for Logging and demo.
 
@@ -139,7 +140,7 @@
                 SubscriptionManager.from(context), Config.readConfig(context), bgLooper,
                 new CallbackHandler(),
                 new AccessPointControllerImpl(context, bgLooper),
-                new MobileDataController(context),
+                new DataUsageController(context),
                 new SubscriptionDefaults());
         mReceiverHandler.post(mRegisterListeners);
     }
@@ -150,12 +151,13 @@
             SubscriptionManager subManager, Config config, Looper bgLooper,
             CallbackHandler callbackHandler,
             AccessPointControllerImpl accessPointController,
-            MobileDataController mobileDataController,
+            DataUsageController dataUsageController,
             SubscriptionDefaults defaultsHandler) {
         mContext = context;
         mConfig = config;
         mReceiverHandler = new Handler(bgLooper);
         mCallbackHandler = callbackHandler;
+        mDataSaverController = new DataSaverController(context);
 
         mSubscriptionManager = subManager;
         mSubDefaults = defaultsHandler;
@@ -171,10 +173,10 @@
 
         mLocale = mContext.getResources().getConfiguration().locale;
         mAccessPoints = accessPointController;
-        mMobileDataController = mobileDataController;
-        mMobileDataController.setNetworkController(this);
-        // TODO: Find a way to move this into MobileDataController.
-        mMobileDataController.setCallback(new MobileDataController.Callback() {
+        mDataUsageController = dataUsageController;
+        mDataUsageController.setNetworkController(this);
+        // TODO: Find a way to move this into DataUsageController.
+        mDataUsageController.setCallback(new DataUsageController.Callback() {
             @Override
             public void onMobileDataEnabled(boolean enabled) {
                 mCallbackHandler.setMobileDataEnabled(enabled);
@@ -189,6 +191,10 @@
         updateAirplaneMode(true /* force callback */);
     }
 
+    public DataSaverController getDataSaverController() {
+        return mDataSaverController;
+    }
+
     private void registerListeners() {
         for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
             mobileSignalController.registerListener();
@@ -236,8 +242,8 @@
     }
 
     @Override
-    public MobileDataController getMobileDataController() {
-        return mMobileDataController;
+    public DataUsageController getMobileDataController() {
+        return mDataUsageController;
     }
 
     public void addEmergencyListener(EmergencyListener listener) {
@@ -811,11 +817,11 @@
 
     public static class SubscriptionDefaults {
         public int getDefaultVoiceSubId() {
-            return SubscriptionManager.getDefaultVoiceSubId();
+            return SubscriptionManager.getDefaultVoiceSubscriptionId();
         }
 
         public int getDefaultDataSubId() {
-            return SubscriptionManager.getDefaultDataSubId();
+            return SubscriptionManager.getDefaultDataSubscriptionId();
         }
     }
 
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 65053f3..61a9851 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -26,6 +26,7 @@
 import android.app.RemoteInput;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.text.Editable;
@@ -174,8 +175,8 @@
     }
 
     public void focus() {
-        mEditText.setInnerFocusable(true);
         mController.addRemoteInput(mEntry);
+        mEditText.setInnerFocusable(true);
         mEditText.mShowImeOnInputConnection = true;
         mEditText.setText(mEntry.remoteInputText);
         mEditText.setSelection(mEditText.getText().length());
@@ -257,6 +258,20 @@
         }
 
         @Override
+        public boolean requestRectangleOnScreen(Rect r) {
+            r.top = mScrollY;
+            r.bottom = mScrollY + (mBottom - mTop);
+            return super.requestRectangleOnScreen(r);
+        }
+
+        @Override
+        public void getFocusedRect(Rect r) {
+            super.getFocusedRect(r);
+            r.top = mScrollY;
+            r.bottom = mScrollY + (mBottom - mTop);
+        }
+
+        @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/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index 83e0446..6ff8f77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -208,6 +208,8 @@
     static final int ICON_CARRIER_NETWORK_CHANGE =
             R.drawable.stat_sys_signal_carrier_network_change_animation;
 
+    static final int ICON_DATA_DISABLED = R.drawable.stat_sys_data_disabled;
+
     static final int QS_ICON_LTE = R.drawable.ic_qs_signal_lte;
     static final int QS_ICON_3G = R.drawable.ic_qs_signal_3g;
     static final int QS_ICON_4G = R.drawable.ic_qs_signal_4g;
@@ -215,6 +217,8 @@
     static final int QS_ICON_CARRIER_NETWORK_CHANGE =
             R.drawable.ic_qs_signal_carrier_network_change_animation;
 
+    static final int QS_ICON_DATA_DISABLED = R.drawable.ic_qs_data_disabled;
+
     static final MobileIconGroup CARRIER_NETWORK_CHANGE = new MobileIconGroup(
             "CARRIER_NETWORK_CHANGE",
             TelephonyIcons.TELEPHONY_CARRIER_NETWORK_CHANGE,
@@ -373,5 +377,20 @@
             false,
             TelephonyIcons.QS_DATA_R
             );
+
+    static final MobileIconGroup DATA_DISABLED = new MobileIconGroup(
+            "DataDisabled",
+            TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH,
+            TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+            0, 0,
+            TelephonyIcons.TELEPHONY_NO_NETWORK,
+            TelephonyIcons.QS_TELEPHONY_NO_NETWORK,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+            R.string.accessibility_cell_data_off,
+            TelephonyIcons.ICON_DATA_DISABLED,
+            false,
+            TelephonyIcons.QS_ICON_DATA_DISABLED
+            );
 }
 
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 b010761..f5869b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -22,7 +22,9 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -33,6 +35,7 @@
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -46,13 +49,15 @@
 import android.view.ViewGroup;
 import android.widget.BaseAdapter;
 
-import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.internal.util.UserIcons;
+import com.android.settingslib.RestrictedLockUtils;
 import com.android.systemui.BitmapHelper;
 import com.android.systemui.GuestResumeSessionReceiver;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.tiles.UserDetailView;
+import com.android.systemui.statusbar.phone.ActivityStarter;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 
 import java.io.FileDescriptor;
@@ -61,6 +66,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
 /**
  * Keeps a list of all users on the device for user switching.
  */
@@ -88,6 +95,7 @@
             = new GuestResumeSessionReceiver();
     private final KeyguardMonitor mKeyguardMonitor;
     private final Handler mHandler;
+    private final ActivityStarter mActivityStarter;
 
     private ArrayList<UserRecord> mUsers = new ArrayList<>();
     private Dialog mExitGuestDialog;
@@ -99,11 +107,12 @@
     private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2);
 
     public UserSwitcherController(Context context, KeyguardMonitor keyguardMonitor,
-            Handler handler) {
+            Handler handler, ActivityStarter activityStarter) {
         mContext = context;
         mGuestResumeSessionReceiver.register(context);
         mKeyguardMonitor = keyguardMonitor;
         mHandler = handler;
+        mActivityStarter = activityStarter;
         mUserManager = UserManager.get(context);
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_ADDED);
@@ -206,25 +215,23 @@
                     }
                 }
 
-                boolean systemCanCreateUsers = !mUserManager.hasUserRestriction(
-                                UserManager.DISALLOW_ADD_USER, UserHandle.SYSTEM);
                 boolean currentUserCanCreateUsers = currentUserInfo != null
                         && (currentUserInfo.isAdmin()
-                                || currentUserInfo.id == UserHandle.USER_SYSTEM)
-                        && systemCanCreateUsers;
-                boolean anyoneCanCreateUsers = systemCanCreateUsers && addUsersWhenLocked;
-                boolean canCreateGuest = (currentUserCanCreateUsers || anyoneCanCreateUsers)
+                                || currentUserInfo.id == UserHandle.USER_SYSTEM);
+                boolean canCreateGuest = (currentUserCanCreateUsers || addUsersWhenLocked)
                         && guestRecord == null;
-                boolean canCreateUser = (currentUserCanCreateUsers || anyoneCanCreateUsers)
+                boolean canCreateUser = (currentUserCanCreateUsers || addUsersWhenLocked)
                         && mUserManager.canAddMoreUsers();
                 boolean createIsRestricted = !addUsersWhenLocked;
 
                 if (!mSimpleUserSwitcher) {
                     if (guestRecord == null) {
                         if (canCreateGuest) {
-                            records.add(new UserRecord(null /* info */, null /* picture */,
+                            guestRecord = new UserRecord(null /* info */, null /* picture */,
                                     true /* isGuest */, false /* isCurrent */,
-                                    false /* isAddUser */, createIsRestricted));
+                                    false /* isAddUser */, createIsRestricted);
+                            checkIfAddUserDisallowed(guestRecord);
+                            records.add(guestRecord);
                         }
                     } else {
                         int index = guestRecord.isCurrent ? 0 : records.size();
@@ -233,9 +240,11 @@
                 }
 
                 if (!mSimpleUserSwitcher && canCreateUser) {
-                    records.add(new UserRecord(null /* info */, null /* picture */,
+                    UserRecord addUserRecord = new UserRecord(null /* info */, null /* picture */,
                             false /* isGuest */, false /* isCurrent */, true /* isAddUser */,
-                            createIsRestricted));
+                            createIsRestricted);
+                    checkIfAddUserDisallowed(addUserRecord);
+                    records.add(addUserRecord);
                 }
 
                 return records;
@@ -289,6 +298,14 @@
         return mContext.getResources().getBoolean(R.bool.config_enableFullscreenUserSwitcher);
     }
 
+    public void logoutCurrentUser() {
+        int currentUser = ActivityManager.getCurrentUser();
+        if (currentUser != UserHandle.USER_SYSTEM) {
+            switchToUserId(UserHandle.USER_SYSTEM);
+            stopUserId(currentUser);
+        }
+    }
+
     public void removeUserId(int userId) {
         if (userId == UserHandle.USER_SYSTEM) {
             Log.w(TAG, "User " + userId + " could not removed.");
@@ -331,6 +348,19 @@
         switchToUserId(id);
     }
 
+    public void switchTo(int userId) {
+        final int count = mUsers.size();
+        for (int i = 0; i < count; ++i) {
+            UserRecord record = mUsers.get(i);
+            if (record.info != null && record.info.id == userId) {
+                switchTo(record);
+                return;
+            }
+        }
+
+        Log.e(TAG, "Couldn't switch to user, id=" + userId);
+    }
+
     private void switchToUserId(int id) {
         try {
             pauseRefreshUsers();
@@ -395,11 +425,7 @@
                 }
                 return;
             } else if (ACTION_LOGOUT_USER.equals(intent.getAction())) {
-                int currentUser = ActivityManager.getCurrentUser();
-                if (currentUser != UserHandle.USER_SYSTEM) {
-                    switchToUserId(UserHandle.USER_SYSTEM);
-                    stopUserId(currentUser);
-                }
+                logoutCurrentUser();
             } else if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
                 if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) {
                     mExitGuestDialog.cancel();
@@ -594,6 +620,22 @@
         }
     }
 
+    private void checkIfAddUserDisallowed(UserRecord record) {
+        EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
+                UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser());
+        if (admin != null) {
+            record.isDisabledByAdmin = true;
+            record.enforcedAdmin = admin;
+        } else {
+            record.isDisabledByAdmin = false;
+            record.enforcedAdmin = null;
+        }
+    }
+
+    public void startActivity(Intent intent) {
+        mActivityStarter.startActivity(intent, true);
+    }
+
     public static final class UserRecord {
         public final UserInfo info;
         public final Bitmap picture;
@@ -602,6 +644,8 @@
         public final boolean isAddUser;
         /** If true, the record is only visible to the owner and only when unlocked. */
         public final boolean isRestricted;
+        public boolean isDisabledByAdmin;
+        public EnforcedAdmin enforcedAdmin;
 
         public UserRecord(UserInfo info, Bitmap picture, boolean isGuest, boolean isCurrent,
                 boolean isAddUser, boolean isRestricted) {
@@ -634,6 +678,10 @@
             if (isCurrent) sb.append(" <isCurrent>");
             if (picture != null) sb.append(" <hasPicture>");
             if (isRestricted) sb.append(" <isRestricted>");
+            if (isDisabledByAdmin) {
+                sb.append(" <isDisabledByAdmin>");
+                sb.append(" enforcedAdmin=" + enforcedAdmin);
+            }
             sb.append(')');
             return sb.toString();
         }
@@ -643,8 +691,8 @@
         private final Intent USER_SETTINGS_INTENT = new Intent("android.settings.USER_SETTINGS");
 
         @Override
-        public int getTitle() {
-            return R.string.quick_settings_user_title;
+        public CharSequence getTitle() {
+            return mContext.getString(R.string.quick_settings_user_title);
         }
 
         @Override
@@ -676,7 +724,7 @@
 
         @Override
         public int getMetricsCategory() {
-            return MetricsLogger.QS_USERDETAIL;
+            return MetricsEvent.QS_USERDETAIL;
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index 3a97be6..a3f571e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -155,13 +155,7 @@
     }
 
     public int getInnerHeight() {
-        return mLayoutHeight - mTopPadding - getTopHeadsUpPushIn();
-    }
-
-    private int getTopHeadsUpPushIn() {
-        ExpandableNotificationRow topHeadsUpEntry = getTopHeadsUpEntry();
-        return topHeadsUpEntry != null ? topHeadsUpEntry.getHeadsUpHeight()
-                - topHeadsUpEntry.getMinHeight(): 0;
+        return mLayoutHeight - mTopPadding;
     }
 
     public boolean isShadeExpanded() {
@@ -180,11 +174,6 @@
         return mMaxHeadsUpTranslation;
     }
 
-    public ExpandableNotificationRow getTopHeadsUpEntry() {
-        HeadsUpManager.HeadsUpEntry topEntry = mHeadsUpManager.getTopEntry();
-        return topEntry == null ? null : topEntry.entry.row;
-    }
-
     public void setDismissAllInProgress(boolean dismissAllInProgress) {
         mDismissAllInProgress = dismissAllInProgress;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
index 56f6564..561b18a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
@@ -25,12 +25,12 @@
     boolean animateAlpha;
     boolean animateY;
     boolean animateZ;
-    boolean animateScale;
     boolean animateHeight;
     boolean animateTopInset;
     boolean animateDimmed;
     boolean animateDark;
     boolean animateHideSensitive;
+    public boolean animateShadowAlpha;
     boolean hasDelays;
     boolean hasGoToFullShadeEvent;
     boolean hasDarkEvent;
@@ -57,11 +57,6 @@
         return this;
     }
 
-    public AnimationFilter animateScale() {
-        animateScale = true;
-        return this;
-    }
-
     public AnimationFilter animateHeight() {
         animateHeight = true;
         return this;
@@ -87,6 +82,11 @@
         return this;
     }
 
+    public AnimationFilter animateShadowAlpha() {
+        animateShadowAlpha = true;
+        return this;
+    }
+
     /**
      * Combines multiple filters into {@code this} filter, using or as the operand .
      *
@@ -118,12 +118,12 @@
         animateAlpha |= filter.animateAlpha;
         animateY |= filter.animateY;
         animateZ |= filter.animateZ;
-        animateScale |= filter.animateScale;
         animateHeight |= filter.animateHeight;
         animateTopInset |= filter.animateTopInset;
         animateDimmed |= filter.animateDimmed;
         animateDark |= filter.animateDark;
         animateHideSensitive |= filter.animateHideSensitive;
+        animateShadowAlpha |= filter.animateShadowAlpha;
         hasDelays |= filter.hasDelays;
     }
 
@@ -131,8 +131,8 @@
         animateAlpha = false;
         animateY = false;
         animateZ = false;
-        animateScale = false;
         animateHeight = false;
+        animateShadowAlpha = false;
         animateTopInset = false;
         animateDimmed = false;
         animateDark = false;
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 beaa3ad..409dac1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -24,6 +24,7 @@
 
 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.HybridNotificationView;
 import com.android.systemui.statusbar.notification.HybridNotificationViewManager;
@@ -56,6 +57,7 @@
     private ExpandableNotificationRow mNotificationParent;
     private HybridNotificationView mGroupOverflowContainer;
     private ViewState mGroupOverFlowState;
+    private int mRealHeight;
 
     public NotificationChildrenContainer(Context context) {
         this(context, null);
@@ -74,8 +76,8 @@
         super(context, attrs, defStyleAttr, defStyleRes);
         mChildPadding = getResources().getDimensionPixelSize(
                 R.dimen.notification_children_padding);
-        mDividerHeight = getResources().getDimensionPixelSize(
-                R.dimen.notification_children_divider_height);
+        mDividerHeight = Math.max(1, getResources().getDimensionPixelSize(
+                R.dimen.notification_divider_height));
         mMaxNotificationHeight = getResources().getDimensionPixelSize(
                 R.dimen.notification_max_height);
         mNotificationAppearDistance = getResources().getDimensionPixelSize(
@@ -111,8 +113,8 @@
         int heightMode = MeasureSpec.getMode(heightMeasureSpec);
         boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY;
         boolean isHeightLimited = heightMode == MeasureSpec.AT_MOST;
+        int size = MeasureSpec.getSize(heightMeasureSpec);
         if (hasFixedHeight || isHeightLimited) {
-            int size = MeasureSpec.getSize(heightMeasureSpec);
             ownMaxHeight = Math.min(ownMaxHeight, size);
         }
         int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST);
@@ -133,9 +135,19 @@
         if (mGroupOverflowContainer != null) {
             mGroupOverflowContainer.measure(widthMeasureSpec, newHeightSpec);
         }
+        mRealHeight = height;
+        if (heightMode != MeasureSpec.UNSPECIFIED) {
+            height = Math.min(height, size);
+        }
         setMeasuredDimension(width, height);
     }
 
+    @Override
+    public boolean pointInView(float localX, float localY, float slop) {
+        return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) &&
+                localY < (mRealHeight + slop);
+    }
+
     /**
      * Add a child notification to this view.
      *
@@ -159,8 +171,15 @@
         mChildren.remove(row);
         removeView(row);
 
-        View divider = mDividers.remove(childIndex);
+        final View divider = mDividers.remove(childIndex);
         removeView(divider);
+        getOverlay().add(divider);
+        CrossFadeHelper.fadeOut(divider, new Runnable() {
+            @Override
+            public void run() {
+                getOverlay().remove(divider);
+            }
+        });
 
         row.setSystemChildExpanded(false);
         updateGroupOverflow();
@@ -305,7 +324,6 @@
             childState.dark = parentState.dark;
             childState.hideSensitive = parentState.hideSensitive;
             childState.belowSpeedBump = parentState.belowSpeedBump;
-            childState.scale =  1.0f;
             childState.clipTopAmount = 0;
             childState.topOverLap = 0;
             boolean visible = i <= lastVisibleIndex;
@@ -365,58 +383,25 @@
      * @param state the new state we animate to
      */
     public void prepareExpansionChanged(StackScrollState state) {
-        if (true) {
-            // TODO: do something that makes sense
-            return;
-        }
-        int childCount = mChildren.size();
-        StackViewState sourceState = new StackViewState();
-        ViewState dividerState = new ViewState();
-        for (int i = 0; i < childCount; i++) {
-            ExpandableNotificationRow child = mChildren.get(i);
-            StackViewState viewState = state.getViewStateForView(child);
-            sourceState.copyFrom(viewState);
-            sourceState.alpha = 0;
-            sourceState.yTranslation += mNotificationAppearDistance;
-            state.applyState(child, sourceState);
-
-            // layout the divider
-            View divider = mDividers.get(i);
-            dividerState.initFrom(divider);
-            dividerState.yTranslation = viewState.yTranslation - mDividerHeight
-                    + mNotificationAppearDistance;
-            dividerState.alpha = 0;
-            state.applyViewState(divider, dividerState);
-
-        }
+        // TODO: do something that makes sense, like placing the invisible views correctly
+        return;
     }
 
     public void startAnimationToState(StackScrollState state, StackStateAnimator stateAnimator,
-            boolean withDelays, long baseDelay, long duration) {
+            long baseDelay, long duration) {
         int childCount = mChildren.size();
         ViewState tmpState = new ViewState();
-        int delayIndex = 0;
-        int maxAllowChildCount = getMaxAllowedVisibleChildren(true /* likeCollapsed */);
         for (int i = childCount - 1; i >= 0; i--) {
             ExpandableNotificationRow child = mChildren.get(i);
             StackViewState viewState = state.getViewStateForView(child);
-            int difference = Math.min(StackStateAnimator.DELAY_EFFECT_MAX_INDEX_DIFFERENCE_CHILDREN,
-                    delayIndex);
-            long delay = withDelays
-                    ? difference * StackStateAnimator.ANIMATION_DELAY_PER_ELEMENT_EXPAND_CHILDREN
-                    : 0;
-            delay = (long) (delay * (mChildrenExpanded ? 1.0f : 0.5f) + baseDelay);
-            stateAnimator.startStackAnimations(child, viewState, state, -1, delay);
+            stateAnimator.startStackAnimations(child, viewState, state, -1, baseDelay);
 
             // layout the divider
             View divider = mDividers.get(i);
             tmpState.initFrom(divider);
             tmpState.yTranslation = viewState.yTranslation - mDividerHeight;
             tmpState.alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;
-            stateAnimator.startViewAnimations(divider, tmpState, delay, duration);
-            if (i < maxAllowChildCount) {
-                delayIndex++;
-            }
+            stateAnimator.startViewAnimations(divider, tmpState, baseDelay, duration);
         }
         if (mGroupOverflowContainer != null) {
             stateAnimator.startViewAnimations(mGroupOverflowContainer, mGroupOverFlowState,
@@ -452,6 +437,10 @@
     }
 
     public int getMinHeight() {
+        return getIntrinsicHeight(NUMBER_OF_CHILDREN_WHEN_COLLAPSED);
+    }
+
+    public int getMinExpandHeight() {
         return getIntrinsicHeight(getMaxAllowedVisibleChildren(true /* forceCollapsed */));
     }
 
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 2ce19a2..60dca99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -16,12 +16,22 @@
 
 package com.android.systemui.statusbar.stack;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.TimeAnimator;
+import android.animation.ValueAnimator;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.PointF;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Pair;
@@ -32,6 +42,7 @@
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import android.widget.OverScroller;
 
 import com.android.systemui.ExpandHelper;
@@ -43,9 +54,8 @@
 import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
-import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.Interpolators;
 import com.android.systemui.statusbar.NotificationOverflowContainer;
-import com.android.systemui.statusbar.SpeedBumpView;
 import com.android.systemui.statusbar.StackScrollerDecorView;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -64,6 +74,7 @@
         implements SwipeHelper.Callback, ExpandHelper.Callback, ScrollAdapter,
         ExpandableView.OnHeightChangedListener, NotificationGroupManager.OnGroupChangeListener {
 
+    public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
     private static final String TAG = "NotificationStackScrollLayout";
     private static final boolean DEBUG = false;
     private static final float RUBBER_BAND_FACTOR_NORMAL = 0.35f;
@@ -79,6 +90,7 @@
     private SwipeHelper mSwipeHelper;
     private boolean mSwipingInProgress;
     private int mCurrentStackHeight = Integer.MAX_VALUE;
+    private final Paint mBackgroundPaint = new Paint();
 
     /**
      * mCurrentStackHeight is the actual stack height, mLastSetStackHeight is the stack height set
@@ -103,22 +115,20 @@
     private float mInitialTouchX;
     private float mInitialTouchY;
 
-    private int mSidePaddings;
     private Paint mDebugPaint;
     private int mContentHeight;
     private int mCollapsedSize;
     private int mBottomStackSlowDownHeight;
     private int mBottomStackPeekSize;
     private int mPaddingBetweenElements;
-    private int mPaddingBetweenElementsDimmed;
-    private int mPaddingBetweenElementsNormal;
+    private int mIncreasedPaddingBetweenElements;
     private int mTopPadding;
     private int mCollapseSecondCardPadding;
 
     /**
      * The algorithm which calculates the properties for our children
      */
-    private StackScrollAlgorithm mStackScrollAlgorithm;
+    private final StackScrollAlgorithm mStackScrollAlgorithm;
 
     /**
      * The current State this Layout is in
@@ -138,6 +148,7 @@
     private final StackStateAnimator mStateAnimator = new StackStateAnimator(this);
     private boolean mAnimationsEnabled;
     private boolean mChangePositionInProgress;
+    private boolean mChildTransferInProgress;
 
     /**
      * The raw amount of the overScroll on the top, which is not rubber-banded.
@@ -162,7 +173,6 @@
     private boolean mGoToFullShadeNeedsAnimation;
     private boolean mIsExpanded = true;
     private boolean mChildrenUpdateRequested;
-    private SpeedBumpView mSpeedBumpView;
     private boolean mIsExpansionChanging;
     private boolean mPanelTracking;
     private boolean mExpandingNotification;
@@ -182,7 +192,6 @@
      */
     private float mMinTopOverScrollToEscape;
     private int mIntrinsicPadding;
-    private int mNotificationTopPadding;
     private float mStackTranslation;
     private float mTopPaddingOverflow;
     private boolean mDontReportNextOverScroll;
@@ -233,6 +242,45 @@
     private NotificationOverflowContainer mOverflowContainer;
     private final ArrayList<Pair<ExpandableNotificationRow, Boolean>> mTmpList = new ArrayList<>();
     private FalsingManager mFalsingManager;
+    private boolean mAnimationRunning;
+    private ViewTreeObserver.OnPreDrawListener mBackgroundUpdater
+            = new ViewTreeObserver.OnPreDrawListener() {
+        @Override
+        public boolean onPreDraw() {
+            // if it needs animation
+            if (!mNeedsAnimation && !mChildrenUpdateRequested) {
+                updateBackground();
+            }
+            return true;
+        }
+    };
+    private Rect mBackgroundBounds = new Rect();
+    private Rect mStartAnimationRect = new Rect();
+    private Rect mEndAnimationRect = new Rect();
+    private Rect mCurrentBounds = new Rect(-1, -1, -1, -1);
+    private boolean mAnimateNextBackgroundBottom;
+    private boolean mAnimateNextBackgroundTop;
+    private ObjectAnimator mBottomAnimator = null;
+    private ObjectAnimator mTopAnimator = null;
+    private ActivatableNotificationView mFirstVisibleBackgroundChild = null;
+    private ActivatableNotificationView mLastVisibleBackgroundChild = null;
+    private int mBgColor;
+    private float mDimAmount;
+    private ValueAnimator mDimAnimator;
+    private Animator.AnimatorListener mDimEndListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mDimAnimator = null;
+        }
+    };
+    private ValueAnimator.AnimatorUpdateListener mDimUpdateListener
+            = new ValueAnimator.AnimatorUpdateListener() {
+
+        @Override
+        public void onAnimationUpdate(ValueAnimator animation) {
+            setDimAmount((Float) animation.getAnimatedValue());
+        }
+    };
 
     public NotificationStackScrollLayout(Context context) {
         this(context, null);
@@ -249,6 +297,7 @@
     public NotificationStackScrollLayout(Context context, AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+        mBgColor = context.getColor(R.color.notification_shade_background_color);
         int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height);
         int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_max_height);
         mExpandHelper = new ExpandHelper(getContext(), this,
@@ -258,19 +307,22 @@
 
         mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, getContext());
         mSwipeHelper.setLongPressListener(mLongPressListener);
+        mStackScrollAlgorithm = new StackScrollAlgorithm(context);
         initView(context);
+        setWillNotDraw(false);
         if (DEBUG) {
-            setWillNotDraw(false);
             mDebugPaint = new Paint();
             mDebugPaint.setColor(0xffff0000);
             mDebugPaint.setStrokeWidth(2);
             mDebugPaint.setStyle(Paint.Style.STROKE);
         }
         mFalsingManager = FalsingManager.getInstance(context);
+        mBackgroundPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
     }
 
     @Override
     protected void onDraw(Canvas canvas) {
+        canvas.drawRect(0, mCurrentBounds.top, getWidth(), mCurrentBounds.bottom, mBackgroundPaint);
         if (DEBUG) {
             int y = mTopPadding;
             canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
@@ -286,6 +338,20 @@
         }
     }
 
+    private void updateBackgroundDimming() {
+        float alpha = BACKGROUND_ALPHA_DIMMED + (1 - BACKGROUND_ALPHA_DIMMED) * (1.0f - mDimAmount);
+        // We need to manually blend in the background color
+        int scrimColor = mScrimController.getScrimBehindColor();
+        // SRC_OVER blending Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc
+        float alphaInv = 1 - alpha;
+        int color = Color.argb((int) (alpha * 255 + alphaInv * Color.alpha(scrimColor)),
+                (int) (Color.red(mBgColor) + alphaInv * Color.red(scrimColor)),
+                (int) (Color.green(mBgColor) + alphaInv * Color.green(scrimColor)),
+                (int) (Color.blue(mBgColor) + alphaInv * Color.blue(scrimColor)));
+        mBackgroundPaint.setColor(color);
+        invalidate();
+    }
+
     private void initView(Context context) {
         mScroller = new OverScroller(getContext());
         setFocusable(true);
@@ -296,37 +362,23 @@
         mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
         mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
         mOverflingDistance = configuration.getScaledOverflingDistance();
-
-        mSidePaddings = context.getResources()
-                .getDimensionPixelSize(R.dimen.notification_side_padding);
         mCollapsedSize = context.getResources()
                 .getDimensionPixelSize(R.dimen.notification_min_height);
         mBottomStackPeekSize = context.getResources()
                 .getDimensionPixelSize(R.dimen.bottom_stack_peek_amount);
-        mStackScrollAlgorithm = new StackScrollAlgorithm(context);
-        mStackScrollAlgorithm.setDimmed(mAmbientState.isDimmed());
-        mPaddingBetweenElementsDimmed = context.getResources()
-                .getDimensionPixelSize(R.dimen.notification_padding_dimmed);
-        mPaddingBetweenElementsNormal = context.getResources()
-                .getDimensionPixelSize(R.dimen.notification_padding);
-        updatePadding(mAmbientState.isDimmed());
+        mStackScrollAlgorithm.initView(context);
+        mPaddingBetweenElements = Math.max(1, context.getResources()
+                .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);
-        mNotificationTopPadding = getResources().getDimensionPixelSize(
-                R.dimen.notifications_top_padding);
         mCollapseSecondCardPadding = getResources().getDimensionPixelSize(
                 R.dimen.notification_collapse_second_card_padding);
     }
 
-    private void updatePadding(boolean dimmed) {
-        mPaddingBetweenElements = dimmed && mStackScrollAlgorithm.shouldScaleDimmed()
-                ? mPaddingBetweenElementsDimmed
-                : mPaddingBetweenElementsNormal;
-        mBottomStackSlowDownHeight = mStackScrollAlgorithm.getBottomStackSlowDownLength();
-        updateContentHeight();
-        notifyHeightChangeListener(null);
-    }
-
     private void notifyHeightChangeListener(ExpandableView view) {
         if (mOnHeightChangedListener != null) {
             mOnHeightChangedListener.onHeightChanged(view, false /* needsAnimation */);
@@ -336,10 +388,7 @@
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        int mode = MeasureSpec.getMode(widthMeasureSpec);
-        int size = MeasureSpec.getSize(widthMeasureSpec);
-        int childMeasureSpec = MeasureSpec.makeMeasureSpec(size - 2 * mSidePaddings, mode);
-        measureChildren(childMeasureSpec, heightMeasureSpec);
+        measureChildren(widthMeasureSpec, heightMeasureSpec);
     }
 
     @Override
@@ -363,32 +412,21 @@
         updateContentHeight();
         clampScrollPosition();
         if (mRequestViewResizeAnimationOnLayout) {
-            requestAnimationOnViewResize();
+            requestAnimationOnViewResize(null);
             mRequestViewResizeAnimationOnLayout = false;
         }
         requestChildrenUpdate();
+        updateFirstAndLastBackgroundViews();
     }
 
-    private void requestAnimationOnViewResize() {
-        if (mIsExpanded && mAnimationsEnabled) {
+    private void requestAnimationOnViewResize(ExpandableNotificationRow row) {
+        if (mAnimationsEnabled && (mIsExpanded || row != null && row.isPinned())) {
             mNeedViewResizeAnimation = true;
             mNeedsAnimation = true;
         }
     }
 
     public void updateSpeedBumpIndex(int newIndex) {
-        int currentIndex = indexOfChild(mSpeedBumpView);
-
-        // If we are currently layouted before the new speed bump index, we have to decrease it.
-        boolean validIndex = newIndex > 0;
-        if (newIndex > getChildCount() - 1) {
-            validIndex = false;
-            newIndex = -1;
-        }
-        if (validIndex && currentIndex != newIndex) {
-            changeViewPosition(mSpeedBumpView, newIndex);
-        }
-        updateSpeedBump(validIndex);
         mAmbientState.setSpeedBumpIndex(newIndex);
     }
 
@@ -495,27 +533,28 @@
         int stackHeight;
         float paddingOffset;
         boolean trackingHeadsUp = mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp();
-        int normalUnfoldPositionStart = trackingHeadsUp ? mHeadsUpManager.getTopHeadsUpHeight()
+        int normalUnfoldPositionStart = trackingHeadsUp
+                ? mHeadsUpManager.getTopHeadsUpPinnedHeight()
                 : minStackHeight;
         if (newStackHeight - mTopPadding - mTopPaddingOverflow >= normalUnfoldPositionStart
                 || getNotGoneChildCount() == 0) {
             paddingOffset = mTopPaddingOverflow;
             stackHeight = newStackHeight;
         } else {
-
-            // We did not reach the position yet where we actually start growing,
-            // so we translate the stack upwards.
-            int 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);
+            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 - mHeadsUpManager.getTopHeadsUpHeight());
+                translationY = (int) (height - normalUnfoldPositionStart);
             }
             paddingOffset = translationY - mTopPadding;
             stackHeight = (int) (height - (translationY - mTopPadding));
@@ -684,8 +723,7 @@
         for (int childIdx = 0; childIdx < count; childIdx++) {
             ExpandableView slidingChild = (ExpandableView) getChildAt(childIdx);
             if (slidingChild.getVisibility() == GONE
-                    || slidingChild instanceof StackScrollerDecorView
-                    || slidingChild == mSpeedBumpView) {
+                    || slidingChild instanceof StackScrollerDecorView) {
                 continue;
             }
             float childTop = slidingChild.getTranslationY();
@@ -712,8 +750,7 @@
         for (int childIdx = 0; childIdx < count; childIdx++) {
             ExpandableView slidingChild = (ExpandableView) getChildAt(childIdx);
             if (slidingChild.getVisibility() == GONE
-                    || slidingChild instanceof StackScrollerDecorView
-                    || slidingChild == mSpeedBumpView) {
+                    || slidingChild instanceof StackScrollerDecorView) {
                 continue;
             }
             float childTop = slidingChild.getTranslationY();
@@ -729,7 +766,10 @@
                 if (slidingChild instanceof ExpandableNotificationRow) {
                     ExpandableNotificationRow row = (ExpandableNotificationRow) slidingChild;
                     if (!mIsExpanded && row.isHeadsUp() && row.isPinned()
-                            && mHeadsUpManager.getTopEntry().entry.row != row) {
+                            && mHeadsUpManager.getTopEntry().entry.row != row
+                            && mGroupManager.getGroupSummary(
+                                mHeadsUpManager.getTopEntry().entry.row.getStatusBarNotification())
+                                != row) {
                         continue;
                     }
                     return row.getViewAtPosition(touchY - childTop);
@@ -1338,7 +1378,7 @@
     /**
      * @return the first child which has visibility unequal to GONE
      */
-    private ExpandableView getFirstChildNotGone() {
+    public ExpandableView getFirstChildNotGone() {
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
@@ -1407,22 +1447,251 @@
 
     private void updateContentHeight() {
         int height = 0;
+        boolean previousNeedsIncreasedPaddings = false;
         for (int i = 0; i < getChildCount(); i++) {
-            View child = getChildAt(i);
-            if (child.getVisibility() != View.GONE) {
+            ExpandableView expandableView = (ExpandableView) getChildAt(i);
+            if (expandableView.getVisibility() != View.GONE) {
+                boolean needsIncreasedPaddings = expandableView.needsIncreasedPadding();
                 if (height != 0) {
-                    // add the padding before this element
-                    height += mPaddingBetweenElements;
+                    int padding = needsIncreasedPaddings || previousNeedsIncreasedPaddings
+                            ? mIncreasedPaddingBetweenElements
+                            : mPaddingBetweenElements;
+                    height += padding;
                 }
-                if (child instanceof ExpandableView) {
-                    ExpandableView expandableView = (ExpandableView) child;
-                    height += expandableView.getIntrinsicHeight();
-                }
+                previousNeedsIncreasedPaddings = needsIncreasedPaddings;
+                height += expandableView.getIntrinsicHeight();
             }
         }
         mContentHeight = height + mTopPadding;
     }
 
+    private void updateBackground() {
+        if (mAmbientState.isDark()) {
+            return;
+        }
+        updateBackgroundBounds();
+        if (!mCurrentBounds.equals(mBackgroundBounds)) {
+            if (mAnimateNextBackgroundTop || mAnimateNextBackgroundBottom || areBoundsAnimating()) {
+                startBackgroundAnimation();
+            } else {
+                mCurrentBounds.set(mBackgroundBounds);
+                applyCurrentBackgroundBounds();
+            }
+        } else {
+            if (mBottomAnimator != null) {
+                mBottomAnimator.cancel();
+            }
+            if (mTopAnimator != null) {
+                mTopAnimator.cancel();
+            }
+        }
+        mAnimateNextBackgroundBottom = false;
+        mAnimateNextBackgroundTop = false;
+    }
+
+    private boolean areBoundsAnimating() {
+        return mBottomAnimator != null || mTopAnimator != null;
+    }
+
+    private void startBackgroundAnimation() {
+        startBottomAnimation();
+        startTopAnimation();
+    }
+
+    private void startTopAnimation() {
+        int previousEndValue = mEndAnimationRect.top;
+        int newEndValue = mBackgroundBounds.top;
+        ObjectAnimator previousAnimator = mTopAnimator;
+        if (previousAnimator != null && previousEndValue == newEndValue) {
+            return;
+        }
+        if (!mAnimateNextBackgroundTop) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                int previousStartValue = mStartAnimationRect.top;
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                values[0].setIntValues(previousStartValue, newEndValue);
+                mStartAnimationRect.top = previousStartValue;
+                mEndAnimationRect.top = newEndValue;
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                setBackgroundTop(newEndValue);
+                return;
+            }
+        }
+        if (previousAnimator != null) {
+            previousAnimator.cancel();
+        }
+        ObjectAnimator animator = ObjectAnimator.ofInt(this, "backgroundTop",
+                mCurrentBounds.top, newEndValue);
+        Interpolator interpolator = Interpolators.FAST_OUT_SLOW_IN;
+        animator.setInterpolator(interpolator);
+        animator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+        // remove the tag when the animation is finished
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mStartAnimationRect.top = -1;
+                mEndAnimationRect.top = -1;
+                mTopAnimator = null;
+            }
+        });
+        animator.start();
+        mStartAnimationRect.top = mCurrentBounds.top;
+        mEndAnimationRect.top = newEndValue;
+        mTopAnimator = animator;
+    }
+
+    private void startBottomAnimation() {
+        int previousStartValue = mStartAnimationRect.bottom;
+        int previousEndValue = mEndAnimationRect.bottom;
+        int newEndValue = mBackgroundBounds.bottom;
+        ObjectAnimator previousAnimator = mBottomAnimator;
+        if (previousAnimator != null && previousEndValue == newEndValue) {
+            return;
+        }
+        if (!mAnimateNextBackgroundBottom) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                values[0].setIntValues(previousStartValue, newEndValue);
+                mStartAnimationRect.bottom = previousStartValue;
+                mEndAnimationRect.bottom = newEndValue;
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                setBackgroundBottom(newEndValue);
+                return;
+            }
+        }
+        if (previousAnimator != null) {
+            previousAnimator.cancel();
+        }
+        ObjectAnimator animator = ObjectAnimator.ofInt(this, "backgroundBottom",
+                mCurrentBounds.bottom, newEndValue);
+        Interpolator interpolator = Interpolators.FAST_OUT_SLOW_IN;
+        animator.setInterpolator(interpolator);
+        animator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+        // remove the tag when the animation is finished
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mStartAnimationRect.bottom = -1;
+                mEndAnimationRect.bottom = -1;
+                mBottomAnimator = null;
+            }
+        });
+        animator.start();
+        mStartAnimationRect.bottom = mCurrentBounds.bottom;
+        mEndAnimationRect.bottom = newEndValue;
+        mBottomAnimator = animator;
+    }
+
+    private void setBackgroundTop(int top) {
+        mCurrentBounds.top = top;
+        applyCurrentBackgroundBounds();
+    }
+
+    public void setBackgroundBottom(int bottom) {
+        mCurrentBounds.bottom = bottom;
+        applyCurrentBackgroundBounds();
+    }
+
+    private void applyCurrentBackgroundBounds() {
+        mScrimController.setExcludedBackgroundArea(mCurrentBounds);
+        invalidate();
+    }
+
+    /**
+     * Update the background bounds to the new desired bounds
+     */
+    private void updateBackgroundBounds() {
+        mBackgroundBounds.left = (int) getX();
+        mBackgroundBounds.right = (int) (getX() + getWidth());
+        if (!mIsExpanded) {
+            mBackgroundBounds.top = 0;
+            mBackgroundBounds.bottom = 0;
+        }
+        ActivatableNotificationView firstView = mFirstVisibleBackgroundChild;
+        int top = 0;
+        if (firstView != null) {
+            int finalTranslationY = (int) StackStateAnimator.getFinalTranslationY(firstView);
+            if (mAnimateNextBackgroundTop
+                    || mTopAnimator == null && mCurrentBounds.top == finalTranslationY
+                    || mTopAnimator != null && mEndAnimationRect.top == finalTranslationY) {
+                // we're ending up at the same location as we are now, lets just skip the animation
+                top = finalTranslationY;
+            } else {
+                top = (int) firstView.getTranslationY();
+            }
+        }
+        ActivatableNotificationView lastView = mLastVisibleBackgroundChild;
+        int bottom = 0;
+        if (lastView != null) {
+            int finalTranslationY = (int) StackStateAnimator.getFinalTranslationY(lastView);
+            int finalHeight = StackStateAnimator.getFinalActualHeight(lastView);
+            int finalBottom = finalTranslationY + finalHeight;
+            finalBottom = Math.min(finalBottom, getHeight());
+            if (mAnimateNextBackgroundBottom
+                    || mBottomAnimator == null && mCurrentBounds.bottom == finalBottom
+                    || mBottomAnimator != null && mEndAnimationRect.bottom == finalBottom) {
+                // we're ending up at the same location as we are now, lets just skip the animation
+                bottom = finalBottom;
+            } else {
+                bottom = (int) (lastView.getTranslationY() + lastView.getActualHeight());
+                bottom = Math.min(bottom, getHeight());
+            }
+        }
+        mBackgroundBounds.top = Math.max(0, top);
+        mBackgroundBounds.bottom = Math.min(getHeight(), bottom);
+    }
+
+    private ActivatableNotificationView getFirstPinnedHeadsUp() {
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = getChildAt(i);
+            if (child.getVisibility() != View.GONE
+                    && child instanceof ExpandableNotificationRow) {
+                ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+                if (row.isPinned()) {
+                    return row;
+                }
+            }
+        }
+        return null;
+    }
+
+    private ActivatableNotificationView getLastChildWithBackground() {
+        int childCount = getChildCount();
+        for (int i = childCount - 1; i >= 0; i--) {
+            View child = getChildAt(i);
+            if (child.getVisibility() != View.GONE
+                    && child instanceof ActivatableNotificationView) {
+                return (ActivatableNotificationView) child;
+            }
+        }
+        return null;
+    }
+
+    private ActivatableNotificationView getFirstChildWithBackground() {
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = getChildAt(i);
+            if (child.getVisibility() != View.GONE
+                    && child instanceof ActivatableNotificationView) {
+                return (ActivatableNotificationView) child;
+            }
+        }
+        return null;
+    }
+
     /**
      * Fling the scroll view
      *
@@ -1484,7 +1753,7 @@
      */
     public void updateTopPadding(float qsHeight, int scrollY, boolean animate,
             boolean ignoreIntrinsicPadding) {
-        float start = qsHeight - scrollY + mNotificationTopPadding;
+        float start = qsHeight - scrollY;
         float stackHeight = getHeight() - start;
         int minStackHeight = getMinStackHeight();
         if (stackHeight <= minStackHeight) {
@@ -1500,13 +1769,9 @@
         setStackHeight(mLastSetStackHeight);
     }
 
-    public int getNotificationTopPadding() {
-        return mNotificationTopPadding;
-    }
-
     public int getMinStackHeight() {
         final ExpandableView firstChild = getFirstChildNotGone();
-        final int firstChildMinHeight = firstChild != null ? (int) firstChild.getMinHeight()
+        final int firstChildMinHeight = firstChild != null ? firstChild.getMinHeight()
                 : mCollapsedSize;
         return firstChildMinHeight + mBottomStackPeekSize + mCollapseSecondCardPadding;
     }
@@ -1628,12 +1893,16 @@
         }
     }
 
+    public void setChildTransferInProgress(boolean childTransferInProgress) {
+        mChildTransferInProgress = childTransferInProgress;
+    }
+
     @Override
     public void onViewRemoved(View child) {
         super.onViewRemoved(child);
         // we only call our internal methods if this is actually a removal and not just a
         // notification which becomes a child notification
-        if (!isChildInGroup(child)) {
+        if (!mChildTransferInProgress) {
             onViewRemovedInternal(child);
         }
     }
@@ -1646,7 +1915,7 @@
         }
         ((ExpandableView) child).setOnHeightChangedListener(null);
         mCurrentStackScrollState.removeViewStateForView(child);
-        updateScrollStateForRemovedChild(child);
+        updateScrollStateForRemovedChild((ExpandableView) child);
         boolean animationGenerated = generateRemoveAnimation(child);
         if (animationGenerated && !mSwipedOutViews.contains(child)) {
             // Add this view to an overlay in order to ensure that it will still be temporary
@@ -1745,9 +2014,12 @@
      *
      * @param removedChild the removed child
      */
-    private void updateScrollStateForRemovedChild(View removedChild) {
+    private void updateScrollStateForRemovedChild(ExpandableView removedChild) {
         int startingPosition = getPositionInLinearLayout(removedChild);
-        int childHeight = getIntrinsicHeight(removedChild) + mPaddingBetweenElements;
+        int padding = removedChild.needsIncreasedPadding()
+                ? mIncreasedPaddingBetweenElements :
+                mPaddingBetweenElements;
+        int childHeight = getIntrinsicHeight(removedChild) + padding;
         int endPosition = startingPosition + childHeight;
         if (endPosition <= mOwnScrollY) {
             // This child is fully scrolled of the top, so we have to deduct its height from the
@@ -1770,16 +2042,25 @@
 
     private int getPositionInLinearLayout(View requestedChild) {
         int position = 0;
+        boolean previousNeedsIncreasedPaddings = false;
         for (int i = 0; i < getChildCount(); i++) {
-            View child = getChildAt(i);
+            ExpandableView child = (ExpandableView) getChildAt(i);
+            boolean notGone = child.getVisibility() != View.GONE;
+            if (notGone) {
+                boolean needsIncreasedPaddings = child.needsIncreasedPadding();
+                if (position != 0) {
+                    int padding = needsIncreasedPaddings || previousNeedsIncreasedPaddings
+                            ? mIncreasedPaddingBetweenElements :
+                            mPaddingBetweenElements;
+                    position += padding;
+                }
+                previousNeedsIncreasedPaddings = needsIncreasedPaddings;
+            }
             if (child == requestedChild) {
                 return position;
             }
-            if (child.getVisibility() != View.GONE) {
+            if (notGone) {
                 position += getIntrinsicHeight(child);
-                if (i < getChildCount()-1) {
-                    position += mPaddingBetweenElements;
-                }
             }
         }
         return 0;
@@ -1791,6 +2072,20 @@
         onViewAddedInternal(child);
     }
 
+    private void updateFirstAndLastBackgroundViews() {
+        ActivatableNotificationView firstChild = getFirstChildWithBackground();
+        ActivatableNotificationView lastChild = getLastChildWithBackground();
+        if (mAnimationsEnabled && mIsExpanded) {
+            mAnimateNextBackgroundTop = firstChild != mFirstVisibleBackgroundChild;
+            mAnimateNextBackgroundBottom = lastChild != mLastVisibleBackgroundChild;
+        } else {
+            mAnimateNextBackgroundTop = false;
+            mAnimateNextBackgroundBottom = false;
+        }
+        mFirstVisibleBackgroundChild = firstChild;
+        mLastVisibleBackgroundChild = lastChild;
+    }
+
     private void onViewAddedInternal(View child) {
         updateHideSensitiveForChild(child);
         mStackScrollAlgorithm.notifyChildrenChanged(this);
@@ -1901,7 +2196,9 @@
         if (!mAnimationEvents.isEmpty() || isCurrentlyAnimating()) {
             mStateAnimator.startAnimationForEvents(mAnimationEvents, mCurrentStackScrollState,
                     mGoToFullShadeDelay);
+            setAnimationRunning(true);
             mAnimationEvents.clear();
+            updateBackground();
         } else {
             applyCurrentState();
         }
@@ -2337,7 +2634,10 @@
         clampScrollPosition();
         notifyHeightChangeListener(view);
         if (needsAnimation) {
-            requestAnimationOnViewResize();
+            ExpandableNotificationRow row = view instanceof ExpandableNotificationRow
+                    ? (ExpandableNotificationRow) view
+                    : null;
+            requestAnimationOnViewResize(row);
         }
         requestChildrenUpdate();
     }
@@ -2384,6 +2684,7 @@
     }
 
     public void onChildAnimationFinished() {
+        setAnimationRunning(false);
         requestChildrenUpdate();
         runAnimationFinishedRunnables();
         clearViewOverlays();
@@ -2406,16 +2707,38 @@
      * See {@link AmbientState#setDimmed}.
      */
     public void setDimmed(boolean dimmed, boolean animate) {
-        mStackScrollAlgorithm.setDimmed(dimmed);
         mAmbientState.setDimmed(dimmed);
-        updatePadding(dimmed);
         if (animate && mAnimationsEnabled) {
             mDimmedNeedsAnimation = true;
             mNeedsAnimation =  true;
+            animateDimmed(dimmed);
+        } else {
+            setDimAmount(dimmed ? 1.0f : 0.0f);
         }
         requestChildrenUpdate();
     }
 
+    private void setDimAmount(float dimAmount) {
+        mDimAmount = dimAmount;
+        updateBackgroundDimming();
+    }
+
+    private void animateDimmed(boolean dimmed) {
+        if (mDimAnimator != null) {
+            mDimAnimator.cancel();
+        }
+        float target = dimmed ? 1.0f : 0.0f;
+        if (target == mDimAmount) {
+            return;
+        }
+        mDimAnimator = TimeAnimator.ofFloat(mDimAmount, target);
+        mDimAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_DIMMED_ACTIVATED);
+        mDimAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+        mDimAnimator.addListener(mDimEndListener);
+        mDimAnimator.addUpdateListener(mDimUpdateListener);
+        mDimAnimator.start();
+    }
+
     public void setHideSensitive(boolean hideSensitive, boolean animate) {
         if (hideSensitive != mAmbientState.isHideSensitive()) {
             int childCount = getChildCount();
@@ -2454,30 +2777,10 @@
             mListener.onChildLocationsChanged(this);
         }
         runAnimationFinishedRunnables();
-    }
-
-    public void setSpeedBumpView(SpeedBumpView speedBumpView) {
-        mSpeedBumpView = speedBumpView;
-        addView(speedBumpView);
-    }
-
-    private void updateSpeedBump(boolean visible) {
-        boolean notGoneBefore = mSpeedBumpView.getVisibility() != GONE;
-        if (visible != notGoneBefore) {
-            int newVisibility = visible ? VISIBLE : GONE;
-            mSpeedBumpView.setVisibility(newVisibility);
-            if (visible) {
-                // Make invisible to ensure that the appear animation is played.
-                mSpeedBumpView.setInvisible();
-            } else {
-                // TODO: This doesn't really work, because the view is already set to GONE above.
-                generateRemoveAnimation(mSpeedBumpView);
-            }
-        }
+        updateBackground();
     }
 
     public void goToFullShade(long delay) {
-        updateSpeedBump(true /* visibility */);
         mDismissView.setInvisible();
         mEmptyShadeView.setInvisible();
         mGoToFullShadeNeedsAnimation = true;
@@ -2521,6 +2824,14 @@
             mNeedsAnimation =  true;
         }
         requestChildrenUpdate();
+        if (dark) {
+            setWillNotDraw(!DEBUG);
+            mScrimController.setExcludedBackgroundArea(null);
+        } else {
+            updateBackground();
+            setWillNotDraw(false);
+            // TODO: fade in background
+        }
     }
 
     private int findDarkAnimationOriginIndex(@Nullable PointF screenLocation) {
@@ -2719,7 +3030,7 @@
     }
 
     public int getDismissViewHeight() {
-        int height = mDismissView.getHeight() + mPaddingBetweenElementsNormal;
+        int height = mDismissView.getHeight() + mPaddingBetweenElements;
 
         // Hack: Accommodate for additional distance when we only have one notification and the
         // dismiss all button.
@@ -2801,7 +3112,7 @@
 
     @Override
     public void onGroupExpansionChanged(ExpandableNotificationRow changedRow, boolean expanded) {
-        boolean animated = mAnimationsEnabled && mIsExpanded;
+        boolean animated = mAnimationsEnabled && (mIsExpanded || changedRow.isPinned());
         if (animated) {
             mExpandedGroupView = changedRow;
             mNeedsAnimation = true;
@@ -2812,13 +3123,12 @@
 
     @Override
     public void onGroupCreatedFromChildren(NotificationGroupManager.NotificationGroup group) {
-        for (NotificationData.Entry entry : group.children) {
-            ExpandableNotificationRow row = entry.row;
-            if (indexOfChild(row) != -1) {
-                removeView(row);
-                group.summary.row.addChildNotification(row);
-            }
-        }
+        mPhoneStatusBar.requestNotificationUpdate();
+    }
+
+    @Override
+    public void onChildIsolationChanged() {
+        mPhoneStatusBar.requestNotificationUpdate();
     }
 
     public void generateChildOrderChangedEvent() {
@@ -2836,7 +3146,6 @@
     public void setHeadsUpManager(HeadsUpManager headsUpManager) {
         mHeadsUpManager = headsUpManager;
         mAmbientState.setHeadsUpManager(headsUpManager);
-        mStackScrollAlgorithm.setHeadsUpManager(headsUpManager);
     }
 
     public void generateHeadsUpAnimation(ExpandableNotificationRow row, boolean isHeadsUp) {
@@ -2871,6 +3180,12 @@
 
     public void setScrimController(ScrimController scrimController) {
         mScrimController = scrimController;
+        mScrimController.setScrimBehindChangeRunnable(new Runnable() {
+            @Override
+            public void run() {
+                updateBackgroundDimming();
+            }
+        });
     }
 
     public void forceNoOverlappingRendering(boolean force) {
@@ -2882,6 +3197,17 @@
         return !mForceNoOverlappingRendering && super.hasOverlappingRendering();
     }
 
+    public void setAnimationRunning(boolean animationRunning) {
+        if (animationRunning != mAnimationRunning) {
+            if (animationRunning) {
+                getViewTreeObserver().addOnPreDrawListener(mBackgroundUpdater);
+            } else {
+                getViewTreeObserver().removeOnPreDrawListener(mBackgroundUpdater);
+            }
+            mAnimationRunning = animationRunning;
+        }
+    }
+
     /**
      * A listener that is notified when some child locations might have changed.
      */
@@ -2927,7 +3253,7 @@
 
                 // ANIMATION_TYPE_ADD
                 new AnimationFilter()
-                        .animateAlpha()
+                        .animateShadowAlpha()
                         .animateHeight()
                         .animateTopInset()
                         .animateY()
@@ -2936,7 +3262,7 @@
 
                 // ANIMATION_TYPE_REMOVE
                 new AnimationFilter()
-                        .animateAlpha()
+                        .animateShadowAlpha()
                         .animateHeight()
                         .animateTopInset()
                         .animateY()
@@ -2945,7 +3271,7 @@
 
                 // ANIMATION_TYPE_REMOVE_SWIPED_OUT
                 new AnimationFilter()
-                        .animateAlpha()
+                        .animateShadowAlpha()
                         .animateHeight()
                         .animateTopInset()
                         .animateY()
@@ -2954,37 +3280,35 @@
 
                 // ANIMATION_TYPE_TOP_PADDING_CHANGED
                 new AnimationFilter()
-                        .animateAlpha()
+                        .animateShadowAlpha()
                         .animateHeight()
                         .animateTopInset()
                         .animateY()
                         .animateDimmed()
-                        .animateScale()
                         .animateZ(),
 
                 // ANIMATION_TYPE_START_DRAG
                 new AnimationFilter()
-                        .animateAlpha(),
+                        .animateShadowAlpha(),
 
                 // ANIMATION_TYPE_SNAP_BACK
                 new AnimationFilter()
-                        .animateAlpha()
+                        .animateShadowAlpha()
                         .animateHeight(),
 
                 // ANIMATION_TYPE_ACTIVATED_CHILD
                 new AnimationFilter()
-                        .animateScale()
-                        .animateAlpha(),
+                        .animateZ(),
 
                 // ANIMATION_TYPE_DIMMED
                 new AnimationFilter()
                         .animateY()
-                        .animateScale()
                         .animateDimmed(),
 
                 // ANIMATION_TYPE_CHANGE_POSITION
                 new AnimationFilter()
-                        .animateAlpha()
+                        .animateAlpha() // maybe the children change positions
+                        .animateShadowAlpha()
                         .animateHeight()
                         .animateTopInset()
                         .animateY()
@@ -2997,12 +3321,11 @@
 
                 // ANIMATION_TYPE_GO_TO_FULL_SHADE
                 new AnimationFilter()
-                        .animateAlpha()
+                        .animateShadowAlpha()
                         .animateHeight()
                         .animateTopInset()
                         .animateY()
                         .animateDimmed()
-                        .animateScale()
                         .animateZ()
                         .hasDelays(),
 
@@ -3012,7 +3335,7 @@
 
                 // ANIMATION_TYPE_VIEW_RESIZE
                 new AnimationFilter()
-                        .animateAlpha()
+                        .animateShadowAlpha()
                         .animateHeight()
                         .animateTopInset()
                         .animateY()
@@ -3021,6 +3344,7 @@
                 // ANIMATION_TYPE_GROUP_EXPANSION_CHANGED
                 new AnimationFilter()
                         .animateAlpha()
+                        .animateShadowAlpha()
                         .animateHeight()
                         .animateTopInset()
                         .animateY()
@@ -3028,7 +3352,7 @@
 
                 // ANIMATION_TYPE_HEADS_UP_APPEAR
                 new AnimationFilter()
-                        .animateAlpha()
+                        .animateShadowAlpha()
                         .animateHeight()
                         .animateTopInset()
                         .animateY()
@@ -3036,7 +3360,7 @@
 
                 // ANIMATION_TYPE_HEADS_UP_DISAPPEAR
                 new AnimationFilter()
-                        .animateAlpha()
+                        .animateShadowAlpha()
                         .animateHeight()
                         .animateTopInset()
                         .animateY()
@@ -3044,7 +3368,7 @@
 
                 // ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
                 new AnimationFilter()
-                        .animateAlpha()
+                        .animateShadowAlpha()
                         .animateHeight()
                         .animateTopInset()
                         .animateY()
@@ -3053,7 +3377,7 @@
 
                 // ANIMATION_TYPE_HEADS_UP_OTHER
                 new AnimationFilter()
-                        .animateAlpha()
+                        .animateShadowAlpha()
                         .animateHeight()
                         .animateTopInset()
                         .animateY()
@@ -3062,8 +3386,8 @@
                 // ANIMATION_TYPE_EVERYTHING
                 new AnimationFilter()
                         .animateAlpha()
+                        .animateShadowAlpha()
                         .animateDark()
-                        .animateScale()
                         .animateDimmed()
                         .animateHideSensitive()
                         .animateHeight()
@@ -3114,7 +3438,7 @@
                 StackStateAnimator.ANIMATION_DURATION_STANDARD,
 
                 // ANIMATION_TYPE_GROUP_EXPANSION_CHANGED
-                StackStateAnimator.ANIMATION_DURATION_EXPAND_CLICKED,
+                StackStateAnimator.ANIMATION_DURATION_STANDARD,
 
                 // ANIMATION_TYPE_HEADS_UP_APPEAR
                 StackStateAnimator.ANIMATION_DURATION_HEADS_UP_APPEAR,
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 59b446b..f6959f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.stack;
 
 import android.content.Context;
-import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
@@ -25,9 +24,9 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 
 /**
@@ -42,15 +41,13 @@
     private static final int MAX_ITEMS_IN_BOTTOM_STACK = 3;
     private static final int MAX_ITEMS_IN_TOP_STACK = 3;
 
-    public static final float DIMMED_SCALE = 0.98f;
-
     private int mPaddingBetweenElements;
+    private int mIncreasedPaddingBetweenElements;
     private int mCollapsedSize;
     private int mTopStackPeekSize;
     private int mBottomStackPeekSize;
     private int mZDistanceBetweenElements;
     private int mZBasicHeight;
-    private int mRoundedRectCornerRadius;
 
     private StackIndentationFunctor mTopStackIndentationFunctor;
     private StackIndentationFunctor mBottomStackIndentationFunctor;
@@ -62,27 +59,22 @@
     private ExpandableView mFirstChildWhileExpanding;
     private boolean mExpandedOnStart;
     private int mTopStackTotalSize;
-    private int mPaddingBetweenElementsDimmed;
-    private int mPaddingBetweenElementsNormal;
-    private int mNotificationsTopPadding;
     private int mBottomStackSlowDownLength;
     private int mTopStackSlowDownLength;
     private int mCollapseSecondCardPadding;
-    private boolean mIsSmallScreen;
-    private int mMaxNotificationHeight;
-    private boolean mScaleDimmed;
-    private HeadsUpManager mHeadsUpManager;
+    private ExpandableView mFirstChild;
     private int mFirstChildMinHeight;
 
     public StackScrollAlgorithm(Context context) {
-        initConstants(context);
-        updatePadding(false);
+        initView(context);
     }
 
-    private void updatePadding(boolean dimmed) {
-        mPaddingBetweenElements = dimmed && mScaleDimmed
-                ? mPaddingBetweenElementsDimmed
-                : mPaddingBetweenElementsNormal;
+    public void initView(Context context) {
+        initConstants(context);
+        updatePadding();
+    }
+
+    private void updatePadding() {
         mTopStackTotalSize = mTopStackSlowDownLength + mPaddingBetweenElements
                 + mTopStackPeekSize;
         mTopStackIndentationFunctor = new PiecewiseLinearIndentationFunctor(
@@ -102,37 +94,25 @@
     }
 
     private void initConstants(Context context) {
-        mPaddingBetweenElementsDimmed = context.getResources()
-                .getDimensionPixelSize(R.dimen.notification_padding_dimmed);
-        mPaddingBetweenElementsNormal = context.getResources()
-                .getDimensionPixelSize(R.dimen.notification_padding);
-        mNotificationsTopPadding = context.getResources()
-                .getDimensionPixelSize(R.dimen.notifications_top_padding);
+        mPaddingBetweenElements = Math.max(1, context.getResources()
+                .getDimensionPixelSize(R.dimen.notification_divider_height));
+        mIncreasedPaddingBetweenElements = context.getResources()
+                .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
         mCollapsedSize = context.getResources()
                 .getDimensionPixelSize(R.dimen.notification_min_height);
-        mMaxNotificationHeight = context.getResources()
-                .getDimensionPixelSize(R.dimen.notification_max_height);
         mTopStackPeekSize = context.getResources()
                 .getDimensionPixelSize(R.dimen.top_stack_peek_amount);
         mBottomStackPeekSize = context.getResources()
                 .getDimensionPixelSize(R.dimen.bottom_stack_peek_amount);
-        mZDistanceBetweenElements = context.getResources()
-                .getDimensionPixelSize(R.dimen.z_distance_between_notifications);
+        mZDistanceBetweenElements = Math.max(1, context.getResources()
+                .getDimensionPixelSize(R.dimen.z_distance_between_notifications));
         mZBasicHeight = (MAX_ITEMS_IN_BOTTOM_STACK + 1) * mZDistanceBetweenElements;
         mBottomStackSlowDownLength = context.getResources()
                 .getDimensionPixelSize(R.dimen.bottom_stack_slow_down_length);
         mTopStackSlowDownLength = context.getResources()
                 .getDimensionPixelSize(R.dimen.top_stack_slow_down_length);
-        mRoundedRectCornerRadius = context.getResources().getDimensionPixelSize(
-                R.dimen.notification_material_rounded_rect_radius);
         mCollapseSecondCardPadding = context.getResources().getDimensionPixelSize(
                 R.dimen.notification_collapse_second_card_padding);
-        mScaleDimmed = context.getResources().getDisplayMetrics().densityDpi
-                >= DisplayMetrics.DENSITY_420;
-    }
-
-    public boolean shouldScaleDimmed() {
-        return mScaleDimmed;
     }
 
     public void getStackScrollState(AmbientState ambientState, StackScrollState resultState) {
@@ -149,6 +129,7 @@
         algorithmState.scrolledPixelsTop = 0;
         algorithmState.itemsInBottomStack = 0.0f;
         algorithmState.partialInBottom = 0.0f;
+        mFirstChildMinHeight = mFirstChild == null ? 0 : mFirstChild.getMinHeight();
         float bottomOverScroll = ambientState.getOverScrollAmount(false /* onTop */);
 
         int scrollY = ambientState.getScrollY();
@@ -158,7 +139,7 @@
         scrollY = Math.max(0, scrollY);
         algorithmState.scrollY = (int) (scrollY + mFirstChildMinHeight + bottomOverScroll);
 
-        updateVisibleChildren(resultState, algorithmState);
+        initAlgorithmState(resultState, algorithmState);
 
         // Phase 1:
         findNumberOfItemsInTopStackAndUpdateState(resultState, algorithmState, ambientState);
@@ -211,8 +192,8 @@
         for (int i = 0; i < childCount; i++) {
             ExpandableView child = algorithmState.visibleChildren.get(i);
             StackViewState state = resultState.getViewStateForView(child);
-            float newYTranslation = state.yTranslation + state.height * (1f - state.scale) / 2f;
-            float newHeight = state.height * state.scale;
+            float newYTranslation = state.yTranslation;
+            float newHeight = state.height;
             // apply clipping and shadow
             float newNotificationEnd = newYTranslation + newHeight;
 
@@ -224,16 +205,6 @@
             } else {
                 clipHeight = newNotificationEnd - previousNotificationEnd;
                 clipHeight = Math.max(0.0f, clipHeight);
-                if (clipHeight != 0.0f) {
-
-                    // In the unlocked shade we have to clip a little bit higher because of the rounded
-                    // corners of the notifications, but only if we are not fully overlapped by
-                    // the top card.
-                    float clippingCorrection = state.dimmed
-                            ? 0
-                            : mRoundedRectCornerRadius * state.scale;
-                    clipHeight += clippingCorrection;
-                }
             }
 
             updateChildClippingAndBackground(state, newHeight, clipHeight,
@@ -251,7 +222,7 @@
                 } else {
                     previousNotificationIsSwiped = ambientState.getDraggedViews().contains(child);
                     previousNotificationEnd = newNotificationEnd;
-                    previousNotificationStart = newYTranslation + state.clipTopAmount * state.scale;
+                    previousNotificationStart = newYTranslation + state.clipTopAmount;
                 }
             }
         }
@@ -275,13 +246,13 @@
             float clipHeight, float backgroundHeight) {
         if (realHeight > clipHeight) {
             // Rather overlap than create a hole.
-            state.topOverLap = (int) Math.floor((realHeight - clipHeight) / state.scale);
+            state.topOverLap = (int) Math.floor(realHeight - clipHeight);
         } else {
             state.topOverLap = 0;
         }
         if (realHeight > backgroundHeight) {
             // Rather overlap than create a hole.
-            state.clipTopAmount = (int) Math.floor((realHeight - backgroundHeight) / state.scale);
+            state.clipTopAmount = (int) Math.floor(realHeight - backgroundHeight);
         } else {
             state.clipTopAmount = 0;
         }
@@ -304,9 +275,6 @@
             childViewState.dark = dark;
             childViewState.hideSensitive = hideSensitive;
             boolean isActivatedChild = activatedChild == child;
-            childViewState.scale = !mScaleDimmed || !dimmed || isActivatedChild
-                    ? 1.0f
-                    : DIMMED_SCALE;
             if (dimmed && isActivatedChild) {
                 childViewState.zTranslation += 2.0f * mZDistanceBetweenElements;
             }
@@ -330,7 +298,8 @@
                             nextChild);
                     // The child below the dragged one must be fully visible
                     if (ambientState.isShadeExpanded()) {
-                        viewState.alpha = 1;
+                        viewState.shadowAlpha = 1;
+                        viewState.hidden = false;
                     }
                 }
 
@@ -343,19 +312,28 @@
     }
 
     /**
-     * Update the visible children on the state.
+     * Initialize the algorithm state like updating the visible children.
      */
-    private void updateVisibleChildren(StackScrollState resultState,
+    private void initAlgorithmState(StackScrollState resultState,
             StackScrollAlgorithmState state) {
         ViewGroup hostView = resultState.getHostView();
         int childCount = hostView.getChildCount();
         state.visibleChildren.clear();
         state.visibleChildren.ensureCapacity(childCount);
+        state.increasedPaddingSet.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);
+                    if (lastView != null) {
+                        state.increasedPaddingSet.add(lastView);
+                    }
+                }
                 if (v instanceof ExpandableNotificationRow) {
                     ExpandableNotificationRow row = (ExpandableNotificationRow) v;
 
@@ -373,6 +351,7 @@
                         }
                     }
                 }
+                lastView = v;
             }
         }
     }
@@ -409,23 +388,21 @@
         // How far in is the element currently transitioning into the bottom stack.
         float yPositionInScrollView = 0.0f;
 
-        // If we have a heads-up higher than the collapsed height we need to add the difference to
-        // the padding of all other elements, i.e push in the top stack slightly.
-        ExpandableNotificationRow topHeadsUpEntry = ambientState.getTopHeadsUpEntry();
-
         int childCount = algorithmState.visibleChildren.size();
         int numberOfElementsCompletelyIn = algorithmState.partialInTop == 1.0f
                 ? algorithmState.lastTopStackIndex
                 : (int) algorithmState.itemsInTopStack;
+        int paddingAfterChild;
         for (int i = 0; i < childCount; i++) {
             ExpandableView child = algorithmState.visibleChildren.get(i);
             StackViewState childViewState = resultState.getViewStateForView(child);
             childViewState.location = StackViewState.LOCATION_UNKNOWN;
-            int childHeight = getMaxAllowedChildHeight(child, ambientState);
+            paddingAfterChild = getPaddingAfterChild(algorithmState, child);
+            int childHeight = getMaxAllowedChildHeight(child);
             int minHeight = child.getMinHeight();
             float yPositionInScrollViewAfterElement = yPositionInScrollView
                     + childHeight
-                    + mPaddingBetweenElements;
+                    + paddingAfterChild;
             float scrollOffset = yPositionInScrollView - algorithmState.scrollY +
                     mFirstChildMinHeight;
 
@@ -440,20 +417,20 @@
 
             // The y position after this element
             float nextYPosition = currentYPosition + childHeight +
-                    mPaddingBetweenElements;
+                    paddingAfterChild;
 
             if (i <= algorithmState.lastTopStackIndex) {
                 // Case 1:
                 // We are in the top Stack
-                updateStateForTopStackChild(algorithmState,
+                updateStateForTopStackChild(algorithmState, child,
                         numberOfElementsCompletelyIn, i, childHeight, childViewState, scrollOffset);
                 clampPositionToTopStackEnd(childViewState, childHeight);
 
                 // check if we are overlapping with the bottom stack
-                if (childViewState.yTranslation + childHeight + mPaddingBetweenElements
+                if (childViewState.yTranslation + childHeight + paddingAfterChild
                         >= bottomStackStart && !mIsExpansionChanging && i != 0) {
                     // we just collapse this element slightly
-                    int newSize = (int) Math.max(bottomStackStart - mPaddingBetweenElements -
+                    int newSize = (int) Math.max(bottomStackStart - paddingAfterChild -
                             childViewState.yTranslation, minHeight);
                     childViewState.height = newSize;
                     updateStateForChildTransitioningInBottom(algorithmState, bottomStackStart,
@@ -469,7 +446,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);
+                            bottomStackStart, childViewState, minHeight, ambientState, child);
                 } else {
                     // According to the regular scroll view we are currently translating out of /
                     // into the bottom of the screen
@@ -486,7 +463,8 @@
 
             // The first card is always rendered.
             if (i == 0) {
-                childViewState.alpha = 1.0f;
+                childViewState.hidden = false;
+                childViewState.shadowAlpha = 1.0f;
                 childViewState.yTranslation = Math.max(
                         mFirstChildMinHeight - algorithmState.scrollY, 0);
                 if (childViewState.yTranslation + childViewState.height
@@ -500,20 +478,22 @@
             if (childViewState.location == StackViewState.LOCATION_UNKNOWN) {
                 Log.wtf(LOG_TAG, "Failed to assign location for child " + i);
             }
-            currentYPosition = childViewState.yTranslation + childHeight + mPaddingBetweenElements;
+            currentYPosition = childViewState.yTranslation + childHeight + paddingAfterChild;
             yPositionInScrollView = yPositionInScrollViewAfterElement;
 
-            if (ambientState.isShadeExpanded() && topHeadsUpEntry != null
-                    && child != topHeadsUpEntry) {
-                childViewState.yTranslation += topHeadsUpEntry.getHeadsUpHeight() -
-                        mFirstChildMinHeight;
-            }
             childViewState.yTranslation += ambientState.getTopPadding()
                     + ambientState.getStackTranslation();
         }
         updateHeadsUpStates(resultState, algorithmState, ambientState);
     }
 
+    private int getPaddingAfterChild(StackScrollAlgorithmState algorithmState,
+            ExpandableView child) {
+        return algorithmState.increasedPaddingSet.contains(child)
+                ? mIncreasedPaddingBetweenElements
+                : mPaddingBetweenElements;
+    }
+
     private void updateHeadsUpStates(StackScrollState resultState,
             StackScrollAlgorithmState algorithmState, AmbientState ambientState) {
         int childCount = algorithmState.visibleChildren.size();
@@ -532,24 +512,19 @@
             StackViewState childState = resultState.getViewStateForView(row);
             boolean isTopEntry = topHeadsUpEntry == row;
             if (mIsExpanded) {
-                if (isTopEntry) {
-                    childState.height += row.getHeadsUpHeight() - mFirstChildMinHeight;
-                }
-                childState.height = Math.max(childState.height, row.getHeadsUpHeight());
                 // Ensure that the heads up is always visible even when scrolled off from the bottom
                 float bottomPosition = ambientState.getMaxHeadsUpTranslation() - childState.height;
                 childState.yTranslation = Math.min(childState.yTranslation,
                         bottomPosition);
             }
             if (row.isPinned()) {
-                childState.yTranslation = Math.max(childState.yTranslation,
-                        mNotificationsTopPadding);
-                childState.height = row.getHeadsUpHeight();
+                childState.yTranslation = Math.max(childState.yTranslation, 0);
+                childState.height = Math.max(row.getIntrinsicHeight(), childState.height);
                 if (!isTopEntry) {
                     // Ensure that a headsUp doesn't vertically extend further than the heads-up at
                     // the top most z-position
                     StackViewState topState = resultState.getViewStateForView(topHeadsUpEntry);
-                    childState.height = row.getHeadsUpHeight();
+                    childState.height = row.getIntrinsicHeight();
                     childState.yTranslation = topState.yTranslation + topState.height
                             - childState.height;
                 }
@@ -607,16 +582,8 @@
                 mFirstChildMinHeight - childHeight);
     }
 
-    private int getMaxAllowedChildHeight(View child, AmbientState ambientState) {
-        if (child instanceof ExpandableNotificationRow) {
-            ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-            if (ambientState == null && row.isHeadsUp()
-                    || ambientState != null && ambientState.getTopHeadsUpEntry() == child) {
-                int extraSize = row.getIntrinsicHeight() - row.getHeadsUpHeight();
-                return mFirstChildMinHeight + extraSize;
-            }
-            return row.getIntrinsicHeight();
-        } else if (child instanceof ExpandableView) {
+    private int getMaxAllowedChildHeight(View child) {
+        if (child instanceof ExpandableView) {
             ExpandableView expandableView = (ExpandableView) child;
             return expandableView.getIntrinsicHeight();
         }
@@ -630,7 +597,7 @@
         // This is the transitioning element on top of bottom stack, calculate how far we are in.
         algorithmState.partialInBottom = 1.0f - (
                 (transitioningPositionStart - currentYPosition) / (childHeight +
-                        mPaddingBetweenElements));
+                        getPaddingAfterChild(algorithmState, child)));
 
         // the offset starting at the transitionPosition of the bottom stack
         float offset = mBottomStackIndentationFunctor.getValue(algorithmState.partialInBottom);
@@ -638,12 +605,12 @@
         int newHeight = childHeight;
         if (childHeight > child.getMinHeight()) {
             newHeight = (int) Math.max(Math.min(transitioningPositionStart + offset -
-                    mPaddingBetweenElements - currentYPosition, childHeight),
+                    getPaddingAfterChild(algorithmState, child) - currentYPosition, childHeight),
                     child.getMinHeight());
             childViewState.height = newHeight;
         }
         childViewState.yTranslation = transitioningPositionStart + offset - newHeight
-                - mPaddingBetweenElements;
+                - getPaddingAfterChild(algorithmState, child);
 
         // We want at least to be at the end of the top stack when collapsing
         clampPositionToTopStackEnd(childViewState, newHeight);
@@ -652,22 +619,23 @@
 
     private void updateStateForChildFullyInBottomStack(StackScrollAlgorithmState algorithmState,
             float transitioningPositionStart, StackViewState childViewState,
-            int minHeight, AmbientState ambientState) {
+            int minHeight, AmbientState ambientState, ExpandableView child) {
         float currentYPosition;
         algorithmState.itemsInBottomStack += 1.0f;
         if (algorithmState.itemsInBottomStack < MAX_ITEMS_IN_BOTTOM_STACK) {
             // We are visually entering the bottom stack
             currentYPosition = transitioningPositionStart
                     + mBottomStackIndentationFunctor.getValue(algorithmState.itemsInBottomStack)
-                    - mPaddingBetweenElements;
+                    - getPaddingAfterChild(algorithmState, child);
             childViewState.location = StackViewState.LOCATION_BOTTOM_STACK_PEEKING;
         } else {
             // we are fully inside the stack
             if (algorithmState.itemsInBottomStack > MAX_ITEMS_IN_BOTTOM_STACK + 2) {
-                childViewState.alpha = 0.0f;
+                childViewState.hidden = true;
+                childViewState.shadowAlpha = 0.0f;
             } else if (algorithmState.itemsInBottomStack
                     > MAX_ITEMS_IN_BOTTOM_STACK + 1) {
-                childViewState.alpha = 1.0f - algorithmState.partialInBottom;
+                childViewState.shadowAlpha = 1.0f - algorithmState.partialInBottom;
             }
             childViewState.location = StackViewState.LOCATION_BOTTOM_STACK_HIDDEN;
             currentYPosition = ambientState.getInnerHeight();
@@ -678,7 +646,7 @@
     }
 
     private void updateStateForTopStackChild(StackScrollAlgorithmState algorithmState,
-            int numberOfElementsCompletelyIn, int i, int childHeight,
+            ExpandableView child, int numberOfElementsCompletelyIn, int i, int childHeight,
             StackViewState childViewState, float scrollOffset) {
 
 
@@ -689,10 +657,11 @@
         if (paddedIndex >= 0) {
 
             // We are currently visually entering the top stack
-            float distanceToStack = (childHeight + mPaddingBetweenElements)
+            float distanceToStack = (childHeight + getPaddingAfterChild(algorithmState, child))
                     - algorithmState.scrolledPixelsTop;
             if (i == algorithmState.lastTopStackIndex
-                    && distanceToStack > (mTopStackTotalSize + mPaddingBetweenElements)) {
+                    && distanceToStack > (mTopStackTotalSize
+                    + getPaddingAfterChild(algorithmState, child))) {
 
                 // Child is currently translating into stack but not yet inside slow down zone.
                 // Handle it like the regular scrollview.
@@ -702,7 +671,8 @@
                 float numItemsBefore;
                 if (i == algorithmState.lastTopStackIndex) {
                     numItemsBefore = 1.0f
-                            - (distanceToStack / (mTopStackTotalSize + mPaddingBetweenElements));
+                            - (distanceToStack / (mTopStackTotalSize
+                            + getPaddingAfterChild(algorithmState, child)));
                 } else {
                     numItemsBefore = algorithmState.itemsInTopStack - i;
                 }
@@ -714,10 +684,11 @@
             childViewState.location = StackViewState.LOCATION_TOP_STACK_PEEKING;
         } else {
             if (paddedIndex == -1) {
-                childViewState.alpha = 1.0f - algorithmState.partialInTop;
+                childViewState.shadowAlpha = 1.0f - algorithmState.partialInTop;
             } else {
                 // We are hidden behind the top card and faded out, so we can hide ourselves.
-                childViewState.alpha = 0.0f;
+                childViewState.hidden = true;
+                childViewState.shadowAlpha = 0.0f;
             }
             childViewState.yTranslation = mFirstChildMinHeight - childHeight;
             childViewState.location = StackViewState.LOCATION_TOP_STACK_HIDDEN;
@@ -738,15 +709,15 @@
         // The y Position if the element would be in a regular scrollView
         float yPositionInScrollView = 0.0f;
         int childCount = algorithmState.visibleChildren.size();
-
         // find the number of elements in the top stack.
         for (int i = 0; i < childCount; i++) {
             ExpandableView child = algorithmState.visibleChildren.get(i);
             StackViewState childViewState = resultState.getViewStateForView(child);
-            int childHeight = getMaxAllowedChildHeight(child, ambientState);
+            int childHeight = getMaxAllowedChildHeight(child);
+            int paddingAfterChild = getPaddingAfterChild(algorithmState, child);
             float yPositionInScrollViewAfterElement = yPositionInScrollView
                     + childHeight
-                    + mPaddingBetweenElements;
+                    + paddingAfterChild;
             if (yPositionInScrollView < algorithmState.scrollY) {
                 if (i == 0 && algorithmState.scrollY <= mFirstChildMinHeight) {
 
@@ -774,7 +745,7 @@
                     algorithmState.scrolledPixelsTop = algorithmState.scrollY
                             - yPositionInScrollView;
                     algorithmState.partialInTop = (algorithmState.scrolledPixelsTop) / (childHeight
-                            + mPaddingBetweenElements);
+                            + paddingAfterChild);
 
                     // Our element can be expanded, so this can get negative
                     algorithmState.partialInTop = Math.max(0.0f, algorithmState.partialInTop);
@@ -783,7 +754,7 @@
                     if (i == 0) {
                         // If it is expanded we have to collapse it to a new size
                         float newSize = yPositionInScrollViewAfterElement
-                                - mPaddingBetweenElements
+                                - paddingAfterChild
                                 - algorithmState.scrollY + mFirstChildMinHeight;
                         newSize = Math.max(mFirstChildMinHeight, newSize);
                         algorithmState.itemsInTopStack = 1.0f;
@@ -864,13 +835,6 @@
                 // current height or the end value of the animation.
                 mFirstChildMaxHeight = StackStateAnimator.getFinalActualHeight(
                         mFirstChildWhileExpanding);
-                if (mFirstChildWhileExpanding instanceof ExpandableNotificationRow) {
-                    ExpandableNotificationRow row =
-                            (ExpandableNotificationRow) mFirstChildWhileExpanding;
-                    if (row.isHeadsUp()) {
-                        mFirstChildMaxHeight += mFirstChildMinHeight - row.getHeadsUpHeight();
-                    }
-                }
             } else {
                 updateFirstChildMaxSizeToMaxHeight();
             }
@@ -892,7 +856,7 @@
                                 int oldBottom) {
                             if (mFirstChildWhileExpanding != null) {
                                 mFirstChildMaxHeight = getMaxAllowedChildHeight(
-                                        mFirstChildWhileExpanding, null);
+                                        mFirstChildWhileExpanding);
                             } else {
                                 mFirstChildMaxHeight = 0;
                             }
@@ -900,7 +864,7 @@
                         }
                     });
         } else {
-            mFirstChildMaxHeight = getMaxAllowedChildHeight(mFirstChildWhileExpanding, null);
+            mFirstChildMaxHeight = getMaxAllowedChildHeight(mFirstChildWhileExpanding);
         }
     }
 
@@ -933,10 +897,7 @@
     }
 
     public void notifyChildrenChanged(final NotificationStackScrollLayout hostView) {
-        int firstItemMinHeight = hostView.getFirstItemMinHeight();
-        if (firstItemMinHeight != mFirstChildMinHeight) {
-            mFirstChildMinHeight = firstItemMinHeight;
-        }
+        mFirstChild = hostView.getFirstChildNotGone();
         if (mIsExpansionChanging) {
             hostView.post(new Runnable() {
                 @Override
@@ -947,20 +908,12 @@
         }
     }
 
-    public void setDimmed(boolean dimmed) {
-        updatePadding(dimmed);
-    }
-
     public void onReset(ExpandableView view) {
         if (view.equals(mFirstChildWhileExpanding)) {
             updateFirstChildMaxSizeToMaxHeight();
         }
     }
 
-    public void setHeadsUpManager(HeadsUpManager headsUpManager) {
-        mHeadsUpManager = headsUpManager;
-    }
-
     class StackScrollAlgorithmState {
 
         /**
@@ -1002,6 +955,11 @@
          * The children from the host view which are not gone.
          */
         public final ArrayList<ExpandableView> visibleChildren = new ArrayList<ExpandableView>();
+
+        /**
+         * The children from the host that need an increased padding after them.
+         */
+        public final HashSet<ExpandableView> increasedPaddingSet = new HashSet<>();
     }
 
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index e155d70..1fedc1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -25,7 +25,6 @@
 import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
-import com.android.systemui.statusbar.SpeedBumpView;
 
 import java.util.HashMap;
 import java.util.List;
@@ -83,8 +82,10 @@
         // initialize with the default values of the view
         viewState.height = view.getIntrinsicHeight();
         viewState.gone = view.getVisibility() == View.GONE;
-        viewState.alpha = 1;
+        viewState.alpha = 1f;
+        viewState.shadowAlpha = 1f;
         viewState.notGoneIndex = -1;
+        viewState.hidden = false;
     }
 
     public StackViewState getViewStateForView(View requestedView) {
@@ -107,9 +108,7 @@
             if (!applyState(child, state)) {
                 continue;
             }
-            if(child instanceof SpeedBumpView) {
-                performSpeedBumpAnimation(i, (SpeedBumpView) child, state, 0);
-            } else if (child instanceof DismissView) {
+            if (child instanceof DismissView) {
                 DismissView dismissView = (DismissView) child;
                 boolean visible = state.topOverLap < mClearAllTopPadding;
                 dismissView.performVisibilityAnimation(visible && !dismissView.willBeGone());
@@ -146,6 +145,14 @@
             view.setActualHeight(newHeight, false /* notifyListeners */);
         }
 
+        float shadowAlpha = view.getShadowAlpha();
+        float newShadowAlpha = state.shadowAlpha;
+
+        // apply shadowAlpha
+        if (shadowAlpha != newShadowAlpha) {
+            view.setShadowAlpha(newShadowAlpha);
+        }
+
         // apply dimming
         view.setDimmed(state.dimmed, false /* animate */);
 
@@ -183,12 +190,10 @@
         float yTranslation = view.getTranslationY();
         float xTranslation = view.getTranslationX();
         float zTranslation = view.getTranslationZ();
-        float scale = view.getScaleX();
         float newAlpha = state.alpha;
         float newYTranslation = state.yTranslation;
         float newZTranslation = state.zTranslation;
-        float newScale = state.scale;
-        boolean becomesInvisible = newAlpha == 0.0f;
+        boolean becomesInvisible = newAlpha == 0.0f || state.hidden;
         if (alpha != newAlpha && xTranslation == 0) {
             // apply layer type
             boolean becomesFullyVisible = newAlpha == 1.0f;
@@ -225,34 +230,5 @@
         if (zTranslation != newZTranslation) {
             view.setTranslationZ(newZTranslation);
         }
-
-        // apply scale
-        if (scale != newScale) {
-            view.setScaleX(newScale);
-            view.setScaleY(newScale);
-        }
     }
-
-    public void performSpeedBumpAnimation(int i, SpeedBumpView speedBump, StackViewState state,
-            long delay) {
-        View nextChild = getNextChildNotGone(i);
-        if (nextChild != null) {
-            float lineEnd = state.yTranslation + state.height / 2;
-            StackViewState nextState = getViewStateForView(nextChild);
-            boolean startIsAboveNext = nextState.yTranslation > lineEnd;
-            speedBump.animateDivider(startIsAboveNext, delay, null /* onFinishedRunnable */);
-        }
-    }
-
-    private View getNextChildNotGone(int childIndex) {
-        int childCount = mHostView.getChildCount();
-        for (int i = childIndex + 1; i < childCount; i++) {
-            View child = mHostView.getChildAt(i);
-            if (child.getVisibility() != View.GONE) {
-                return child;
-            }
-        }
-        return null;
-    }
-
 }
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 b4ab48a..e75e8e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -22,13 +22,12 @@
 import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
 import android.view.View;
-import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
-import com.android.systemui.statusbar.SpeedBumpView;
+import com.android.systemui.statusbar.Interpolators;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import java.util.ArrayList;
@@ -43,39 +42,35 @@
     public static final int ANIMATION_DURATION_STANDARD = 360;
     public static final int ANIMATION_DURATION_GO_TO_FULL_SHADE = 448;
     public static final int ANIMATION_DURATION_APPEAR_DISAPPEAR = 464;
-    public static final int ANIMATION_DURATION_EXPAND_CLICKED = 360;
     public static final int ANIMATION_DURATION_DIMMED_ACTIVATED = 220;
     public static final int ANIMATION_DURATION_HEADS_UP_APPEAR = 650;
     public static final int ANIMATION_DURATION_HEADS_UP_DISAPPEAR = 230;
     public static final int ANIMATION_DELAY_PER_ELEMENT_INTERRUPTING = 80;
-    public static final int ANIMATION_DELAY_PER_ELEMENT_EXPAND_CHILDREN = 54;
     public static final int ANIMATION_DELAY_PER_ELEMENT_MANUAL = 32;
     public static final int ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE = 48;
     public static final int ANIMATION_DELAY_PER_ELEMENT_DARK = 24;
     public static final int DELAY_EFFECT_MAX_INDEX_DIFFERENCE = 2;
-    public static final int DELAY_EFFECT_MAX_INDEX_DIFFERENCE_CHILDREN = 3;
     public static final int ANIMATION_DELAY_HEADS_UP = 120;
 
     private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
     private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag;
-    private static final int TAG_ANIMATOR_SCALE = R.id.scale_animator_tag;
     private static final int TAG_ANIMATOR_ALPHA = R.id.alpha_animator_tag;
     private static final int TAG_ANIMATOR_HEIGHT = R.id.height_animator_tag;
     private static final int TAG_ANIMATOR_TOP_INSET = R.id.top_inset_animator_tag;
+    private static final int TAG_ANIMATOR_SHADOW_ALPHA = R.id.shadow_alpha_animator_tag;
     private static final int TAG_END_TRANSLATION_Y = R.id.translation_y_animator_end_value_tag;
     private static final int TAG_END_TRANSLATION_Z = R.id.translation_z_animator_end_value_tag;
-    private static final int TAG_END_SCALE = R.id.scale_animator_end_value_tag;
     private static final int TAG_END_ALPHA = R.id.alpha_animator_end_value_tag;
     private static final int TAG_END_HEIGHT = R.id.height_animator_end_value_tag;
     private static final int TAG_END_TOP_INSET = R.id.top_inset_animator_end_value_tag;
+    private static final int TAG_END_SHADOW_ALPHA = R.id.shadow_alpha_animator_end_value_tag;
     private static final int TAG_START_TRANSLATION_Y = R.id.translation_y_animator_start_value_tag;
     private static final int TAG_START_TRANSLATION_Z = R.id.translation_z_animator_start_value_tag;
-    private static final int TAG_START_SCALE = R.id.scale_animator_start_value_tag;
     private static final int TAG_START_ALPHA = R.id.alpha_animator_start_value_tag;
     private static final int TAG_START_HEIGHT = R.id.height_animator_start_value_tag;
     private static final int TAG_START_TOP_INSET = R.id.top_inset_animator_start_value_tag;
+    private static final int TAG_START_SHADOW_ALPHA = R.id.shadow_alpha_animator_start_value_tag;
 
-    private final Interpolator mFastOutSlowInInterpolator;
     private final Interpolator mHeadsUpAppearInterpolator;
     private final int mGoToFullShadeAppearingTranslation;
     private final StackViewState mTmpState = new StackViewState();
@@ -102,8 +97,6 @@
 
     public StackStateAnimator(NotificationStackScrollLayout hostLayout) {
         mHostLayout = hostLayout;
-        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(hostLayout.getContext(),
-                android.R.interpolator.fast_out_slow_in);
         mGoToFullShadeAppearingTranslation =
                 hostLayout.getContext().getResources().getDimensionPixelSize(
                         R.dimen.go_to_full_shade_appearing_translation);
@@ -203,7 +196,6 @@
      */
     public void startStackAnimations(final ExpandableView child, StackViewState viewState,
             StackScrollState finalState, int i, long fixedDelay) {
-        final float alpha = viewState.alpha;
         boolean wasAdded = mNewAddChildren.contains(child);
         long duration = mCurrentLength;
         if (wasAdded && mAnimationFilter.hasGoToFullShadeEvent) {
@@ -215,14 +207,14 @@
         }
         boolean yTranslationChanging = child.getTranslationY() != viewState.yTranslation;
         boolean zTranslationChanging = child.getTranslationZ() != viewState.zTranslation;
-        boolean scaleChanging = child.getScaleX() != viewState.scale;
-        boolean alphaChanging = alpha != child.getAlpha();
+        boolean alphaChanging = viewState.alpha != child.getAlpha();
         boolean heightChanging = viewState.height != child.getActualHeight();
+        boolean shadowAlphaChanging = viewState.shadowAlpha != child.getShadowAlpha();
         boolean darkChanging = viewState.dark != child.isDark();
         boolean topInsetChanging = viewState.clipTopAmount != child.getClipTopAmount();
         boolean hasDelays = mAnimationFilter.hasDelays;
-        boolean isDelayRelevant = yTranslationChanging || zTranslationChanging || scaleChanging ||
-                alphaChanging || heightChanging || topInsetChanging || darkChanging;
+        boolean isDelayRelevant = yTranslationChanging || zTranslationChanging || alphaChanging
+                || heightChanging || topInsetChanging || darkChanging || shadowAlphaChanging;
         long delay = 0;
         if (fixedDelay != -1) {
             delay = fixedDelay;
@@ -237,6 +229,11 @@
             startHeightAnimation(child, viewState, duration, delay);
         }
 
+        // start shadow alpha animation
+        if (shadowAlphaChanging) {
+            startShadowAlphaAnimation(child, viewState, duration, delay);
+        }
+
         // start top inset animation
         if (topInsetChanging) {
             startInsetAnimation(child, viewState, duration, delay);
@@ -258,13 +255,9 @@
         if (wasAdded) {
             child.performAddAnimation(delay, mCurrentLength);
         }
-        if (child instanceof SpeedBumpView) {
-            finalState.performSpeedBumpAnimation(i, (SpeedBumpView) child, viewState,
-                    delay + duration);
-        } else if (child instanceof ExpandableNotificationRow) {
+        if (child instanceof ExpandableNotificationRow) {
             ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-            row.startChildAnimation(finalState, this, child == mChildExpandingView, delay,
-                    duration);
+            row.startChildAnimation(finalState, this, delay, duration);
         }
     }
 
@@ -279,13 +272,12 @@
     public void startViewAnimations(View child, ViewState viewState, long delay, long duration) {
         boolean wasVisible = child.getVisibility() == View.VISIBLE;
         final float alpha = viewState.alpha;
-        if (!wasVisible && alpha != 0 && !viewState.gone) {
+        if (!wasVisible && alpha != 0 && !viewState.gone && !viewState.hidden) {
             child.setVisibility(View.VISIBLE);
         }
         boolean yTranslationChanging = child.getTranslationY() != viewState.yTranslation;
         boolean zTranslationChanging = child.getTranslationZ() != viewState.zTranslation;
-        boolean scaleChanging = child.getScaleX() != viewState.scale;
-        float childAlpha = child.getVisibility() == View.INVISIBLE ? 0.0f : child.getAlpha();
+        float childAlpha = child.getAlpha();
         boolean alphaChanging = viewState.alpha != childAlpha;
         if (child instanceof ExpandableView) {
             // We don't want views to change visibility when they are animating to GONE
@@ -302,11 +294,6 @@
             startZTranslationAnimation(child, viewState, duration, delay);
         }
 
-        // start scale animation
-        if (scaleChanging) {
-            startScaleAnimation(child, viewState, duration);
-        }
-
         // start alpha animation
         if (alphaChanging && child.getTranslationX() == 0) {
             startAlphaAnimation(child, viewState, duration, delay);
@@ -388,6 +375,64 @@
         return (long) (index * ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE);
     }
 
+    private void startShadowAlphaAnimation(final ExpandableView child,
+            StackViewState viewState, long duration, long delay) {
+        Float previousStartValue = getChildTag(child, TAG_START_SHADOW_ALPHA);
+        Float previousEndValue = getChildTag(child, TAG_END_SHADOW_ALPHA);
+        float newEndValue = viewState.shadowAlpha;
+        if (previousEndValue != null && previousEndValue == newEndValue) {
+            return;
+        }
+        ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_SHADOW_ALPHA);
+        if (!mAnimationFilter.animateShadowAlpha) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                float relativeDiff = newEndValue - previousEndValue;
+                float newStartValue = previousStartValue + relativeDiff;
+                values[0].setFloatValues(newStartValue, newEndValue);
+                child.setTag(TAG_START_SHADOW_ALPHA, newStartValue);
+                child.setTag(TAG_END_SHADOW_ALPHA, newEndValue);
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                child.setShadowAlpha(newEndValue);
+                return;
+            }
+        }
+
+        ValueAnimator animator = ValueAnimator.ofFloat(child.getShadowAlpha(), newEndValue);
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                child.setShadowAlpha((float) animation.getAnimatedValue());
+            }
+        });
+        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+        long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
+        animator.setDuration(newDuration);
+        if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
+            animator.setStartDelay(delay);
+        }
+        animator.addListener(getGlobalAnimationFinishedListener());
+        // remove the tag when the animation is finished
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                child.setTag(TAG_ANIMATOR_SHADOW_ALPHA, null);
+                child.setTag(TAG_START_SHADOW_ALPHA, null);
+                child.setTag(TAG_END_SHADOW_ALPHA, null);
+            }
+        });
+        startAnimator(animator);
+        child.setTag(TAG_ANIMATOR_SHADOW_ALPHA, animator);
+        child.setTag(TAG_START_SHADOW_ALPHA, child.getShadowAlpha());
+        child.setTag(TAG_END_SHADOW_ALPHA, newEndValue);
+    }
+
     private void startHeightAnimation(final ExpandableView child,
             StackViewState viewState, long duration, long delay) {
         Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT);
@@ -425,7 +470,7 @@
                         false /* notifyListeners */);
             }
         });
-        animator.setInterpolator(mFastOutSlowInInterpolator);
+        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
         long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
         animator.setDuration(newDuration);
         if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
@@ -483,7 +528,7 @@
                 child.setClipTopAmount((int) animation.getAnimatedValue());
             }
         });
-        animator.setInterpolator(mFastOutSlowInInterpolator);
+        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
         long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
         animator.setDuration(newDuration);
         if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
@@ -538,7 +583,7 @@
 
         ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.ALPHA,
                 child.getAlpha(), newEndValue);
-        animator.setInterpolator(mFastOutSlowInInterpolator);
+        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
         // Handle layer type
         child.setLayerType(View.LAYER_TYPE_HARDWARE, null);
         animator.addListener(new AnimatorListenerAdapter() {
@@ -609,7 +654,7 @@
 
         ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Z,
                 child.getTranslationZ(), newEndValue);
-        animator.setInterpolator(mFastOutSlowInInterpolator);
+        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
         long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
         animator.setDuration(newDuration);
         if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
@@ -663,7 +708,7 @@
         ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Y,
                 child.getTranslationY(), newEndValue);
         Interpolator interpolator = mHeadsUpAppearChildren.contains(child) ?
-                mHeadsUpAppearInterpolator :mFastOutSlowInInterpolator;
+                mHeadsUpAppearInterpolator :Interpolators.FAST_OUT_SLOW_IN;
         animator.setInterpolator(interpolator);
         long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
         animator.setDuration(newDuration);
@@ -687,60 +732,6 @@
         child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
     }
 
-    private void startScaleAnimation(final View child,
-            ViewState viewState, long duration) {
-        Float previousStartValue = getChildTag(child, TAG_START_SCALE);
-        Float previousEndValue = getChildTag(child, TAG_END_SCALE);
-        float newEndValue = viewState.scale;
-        if (previousEndValue != null && previousEndValue == newEndValue) {
-            return;
-        }
-        ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_SCALE);
-        if (!mAnimationFilter.animateScale) {
-            // just a local update was performed
-            if (previousAnimator != null) {
-                // we need to increase all animation keyframes of the previous animator by the
-                // relative change to the end value
-                PropertyValuesHolder[] values = previousAnimator.getValues();
-                float relativeDiff = newEndValue - previousEndValue;
-                float newStartValue = previousStartValue + relativeDiff;
-                values[0].setFloatValues(newStartValue, newEndValue);
-                values[1].setFloatValues(newStartValue, newEndValue);
-                child.setTag(TAG_START_SCALE, newStartValue);
-                child.setTag(TAG_END_SCALE, newEndValue);
-                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
-                return;
-            } else {
-                // no new animation needed, let's just apply the value
-                child.setScaleX(newEndValue);
-                child.setScaleY(newEndValue);
-            }
-        }
-
-        PropertyValuesHolder holderX =
-                PropertyValuesHolder.ofFloat(View.SCALE_X, child.getScaleX(), newEndValue);
-        PropertyValuesHolder holderY =
-                PropertyValuesHolder.ofFloat(View.SCALE_Y, child.getScaleY(), newEndValue);
-        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(child, holderX, holderY);
-        animator.setInterpolator(mFastOutSlowInInterpolator);
-        long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
-        animator.setDuration(newDuration);
-        animator.addListener(getGlobalAnimationFinishedListener());
-        // remove the tag when the animation is finished
-        animator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                child.setTag(TAG_ANIMATOR_SCALE, null);
-                child.setTag(TAG_START_SCALE, null);
-                child.setTag(TAG_END_SCALE, null);
-            }
-        });
-        startAnimator(animator);
-        child.setTag(TAG_ANIMATOR_SCALE, animator);
-        child.setTag(TAG_START_SCALE, child.getScaleX());
-        child.setTag(TAG_END_SCALE, newEndValue);
-    }
-
     private void startAnimator(ValueAnimator animator) {
         mAnimatorSet.add(animator);
         animator.start();
@@ -898,7 +889,7 @@
                     event.animationType == NotificationStackScrollLayout
                             .AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK) {
                 mHeadsUpDisappearChildren.add(changingView);
-                if (mHostLayout.indexOfChild(changingView) == -1) {
+                if (changingView.getParent() == null) {
                     // This notification was actually removed, so we need to add it to the overlay
                     mHostLayout.getOverlay().add(changingView);
                     mTmpState.initFrom(changingView);
@@ -938,7 +929,7 @@
                         isRubberbanded);
             }
         });
-        overScrollAnimator.setInterpolator(mFastOutSlowInInterpolator);
+        overScrollAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
         overScrollAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
@@ -980,6 +971,22 @@
         }
     }
 
+    /**
+     * Get the end value of the height animation running on a view or the actualHeight
+     * if no animation is running.
+     */
+    public static float getFinalTranslationY(ExpandableView view) {
+        if (view == null) {
+            return 0;
+        }
+        ValueAnimator yAnimator = getChildTag(view, TAG_ANIMATOR_TRANSLATION_Y);
+        if (yAnimator == null) {
+            return view.getTranslationY();
+        } else {
+            return getChildTag(view, TAG_END_TRANSLATION_Y);
+        }
+    }
+
     public void setHeadsUpAppearHeightBottom(int headsUpAppearHeightBottom) {
         mHeadsUpAppearHeightBottom = headsUpAppearHeightBottom;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
index 55ef440..41824ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
@@ -42,6 +42,7 @@
     public boolean dark;
     public boolean hideSensitive;
     public boolean belowSpeedBump;
+    public float shadowAlpha;
 
     /**
      * The amount which the view should be clipped from the top. This is calculated to
@@ -74,6 +75,7 @@
             StackViewState svs = (StackViewState) viewState;
             height = svs.height;
             dimmed = svs.dimmed;
+            shadowAlpha = svs.shadowAlpha;
             dark = svs.dark;
             hideSensitive = svs.hideSensitive;
             belowSpeedBump = svs.belowSpeedBump;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
index 3e538df..5beaac3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
@@ -29,21 +29,21 @@
     public float yTranslation;
     public float zTranslation;
     public boolean gone;
-    public float scale;
+    public boolean hidden;
 
     public void copyFrom(ViewState viewState) {
         alpha = viewState.alpha;
         yTranslation = viewState.yTranslation;
         zTranslation = viewState.zTranslation;
         gone = viewState.gone;
-        scale = viewState.scale;
+        hidden = viewState.hidden;
     }
 
     public void initFrom(View view) {
-        alpha = view.getVisibility() == View.INVISIBLE ? 0.0f : view.getAlpha();
+        alpha = view.getAlpha();
         yTranslation = view.getTranslationY();
         zTranslation = view.getTranslationZ();
         gone = view.getVisibility() == View.GONE;
-        scale = view.getScaleX();
+        hidden = false;
     }
 }
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 44b41c5..0406ae3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -33,16 +33,11 @@
 public class TvStatusBar extends BaseStatusBar {
 
     @Override
-    public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
+    public void setIcon(String slot, StatusBarIcon icon) {
     }
 
     @Override
-    public void updateIcon(String slot, int index, int viewIndex, StatusBarIcon old,
-            StatusBarIcon icon) {
-    }
-
-    @Override
-    public void removeIcon(String slot, int index, int viewIndex) {
+    public void removeIcon(String slot) {
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ClipboardView.java b/packages/SystemUI/src/com/android/systemui/tuner/ClipboardView.java
new file mode 100644
index 0000000..63ed912
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ClipboardView.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 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.tuner;
+
+import com.android.systemui.R;
+
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.ClipboardManager.OnPrimaryClipChangedListener;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.DragEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.ImageView;
+
+public class ClipboardView extends ImageView implements OnPrimaryClipChangedListener {
+
+    private static final int TARGET_COLOR = 0x4dffffff;
+    private final ClipboardManager mClipboardManager;
+    private ClipData mCurrentClip;
+
+    public ClipboardView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mClipboardManager = context.getSystemService(ClipboardManager.class);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        startListening();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        stopListening();
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN && mCurrentClip != null) {
+            startPocketDrag();
+        }
+        return super.onTouchEvent(ev);
+    }
+
+    @Override
+    public boolean onDragEvent(DragEvent event) {
+        switch (event.getAction()) {
+            case DragEvent.ACTION_DRAG_ENTERED:
+                setBackgroundDragTarget(true);
+                break;
+            case DragEvent.ACTION_DROP:
+                mClipboardManager.setPrimaryClip(event.getClipData());
+            case DragEvent.ACTION_DRAG_EXITED:
+            case DragEvent.ACTION_DRAG_ENDED:
+                setBackgroundDragTarget(false);
+                break;
+        }
+        return true;
+    }
+
+    private void setBackgroundDragTarget(boolean isTarget) {
+        setBackgroundColor(isTarget ? TARGET_COLOR : 0);
+    }
+
+    public void startPocketDrag() {
+        startDragAndDrop(mCurrentClip, new View.DragShadowBuilder(this), null,
+                View.DRAG_FLAG_GLOBAL);
+    }
+
+    public void startListening() {
+        mClipboardManager.addPrimaryClipChangedListener(this);
+        onPrimaryClipChanged();
+    }
+
+    public void stopListening() {
+        mClipboardManager.removePrimaryClipChangedListener(this);
+    }
+
+    @Override
+    public void onPrimaryClipChanged() {
+        mCurrentClip = mClipboardManager.getPrimaryClip();
+        setImageResource(mCurrentClip != null
+                ? R.drawable.clipboard_full : R.drawable.clipboard_empty);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java
new file mode 100644
index 0000000..dfacd03
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java
@@ -0,0 +1,341 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.tuner;
+
+import android.annotation.Nullable;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.provider.Settings;
+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.PreferenceViewHolder;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.SeekBar;
+import android.widget.Switch;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.policy.DisplayController;
+
+import java.util.Objects;
+
+public class ColorMatrixFragment extends PreferenceFragment implements TunerService.Tunable {
+
+    private static final String TAG = "ColorMatrixFragment";
+
+    private static final long RESET_DELAY = 10000;
+
+    private boolean mCustomEnabled;
+    private DropDownPreference mSelectPreference;
+    private String mCurrentValue;
+    private String mCustomValues;
+    private SwitchPreference mEnableCustomPreference;
+    private MatrixPreference mCustomPreference;
+    private int mState;
+    private Switch mSwitch;
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        Context context = getContext();
+        TunerService.get(context).addTunable(this, DisplayController.COLOR_MATRIX_CUSTOM_ENABLED,
+                DisplayController.COLOR_MATRIX_CUSTOM_VALUES, DisplayController.COLOR_STATE,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX);
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        final View view = LayoutInflater.from(getContext()).inflate(
+                R.layout.color_matrix_settings, container, false);
+        ((ViewGroup) view).addView(super.onCreateView(inflater, container, savedInstanceState));
+        return view;
+    }
+
+    @Override
+    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+        final Context context = getPreferenceManager().getContext();
+        setPreferenceScreen(getPreferenceManager().createPreferenceScreen(context));
+
+        mSelectPreference = new DropDownPreference(context);
+        mSelectPreference.setTitle(R.string.color_transform);
+        mSelectPreference.setSummary("%s");
+        mSelectPreference.setOnPreferenceChangeListener(
+                new Preference.OnPreferenceChangeListener() {
+            @Override
+            public boolean onPreferenceChange(Preference preference, Object newValue) {
+                if (Objects.equals(newValue, DisplayController.AUTO_STRING)) {
+                    Settings.Secure.putInt(context.getContentResolver(),
+                            DisplayController.COLOR_STATE,
+                            DisplayController.COLOR_STATE_AUTO);
+                    return true;
+                }
+                if (Objects.equals(newValue, DisplayController.NONE_STRING)) {
+                    Settings.Secure.putString(context.getContentResolver(),
+                            Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, null);
+                    return true;
+                }
+                Settings.Secure.putInt(context.getContentResolver(),
+                        DisplayController.COLOR_STATE,
+                        DisplayController.COLOR_STATE_ENABLED);
+                final String value = (String) newValue;
+                Settings.Secure.putString(context.getContentResolver(),
+                        Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
+                        value);
+                return true;
+            }
+        });
+        getPreferenceScreen().addPreference(mSelectPreference);
+
+        mEnableCustomPreference = new SwitchPreference(context);
+        mEnableCustomPreference.setTitle(R.string.color_enable_custom);
+        mEnableCustomPreference.setOnPreferenceChangeListener(
+                new Preference.OnPreferenceChangeListener() {
+            @Override
+            public boolean onPreferenceChange(Preference preference, Object newValue) {
+                boolean enabled = (Boolean) newValue;
+                if (!enabled && Objects.equals(mCurrentValue, mCustomValues)) {
+                    Settings.Secure.putString(context.getContentResolver(),
+                            Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, null);
+                }
+                Settings.Secure.putInt(context.getContentResolver(),
+                        DisplayController.COLOR_MATRIX_CUSTOM_ENABLED, enabled ? 1 : 0);
+                return true;
+            }
+        });
+        getPreferenceScreen().addPreference(mEnableCustomPreference);
+
+        mCustomPreference = new MatrixPreference(context);
+        getPreferenceScreen().addPreference(mCustomPreference);
+    }
+
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        View switchBar = view.findViewById(R.id.switch_bar);
+        mSwitch = (Switch) switchBar.findViewById(android.R.id.switch_widget);
+        mSwitch.setChecked(mState != DisplayController.COLOR_STATE_DISABLED);
+        switchBar.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                int newState = mState != DisplayController.COLOR_STATE_DISABLED
+                        ? DisplayController.COLOR_STATE_DISABLED
+                        : DisplayController.COLOR_STATE_ENABLED;
+                ContentResolver contentResolver = getContext().getContentResolver();
+                if (newState == DisplayController.COLOR_STATE_DISABLED) {
+                    String tiles = Settings.Secure.getString(contentResolver,
+                            QSTileHost.TILES_SETTING);
+                    if (tiles != null) {
+                        if (tiles.contains(",colors")) {
+                            tiles = tiles.replace(",colors", "");
+                        } else if (tiles.contains("colors,")) {
+                            tiles = tiles.replace("colors,", "");
+                        }
+                        Settings.Secure.putString(contentResolver, QSTileHost.TILES_SETTING,
+                                tiles);
+                    }
+                }
+                Settings.Secure.putInt(contentResolver,
+                        DisplayController.COLOR_STATE, newState);
+            }
+        });
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        TunerService.get(getContext()).removeTunable(this);
+    }
+
+    @Override
+    public void onTuningChanged(String key, String newValue) {
+        if (DisplayController.COLOR_MATRIX_CUSTOM_ENABLED.equals(key)) {
+            mCustomEnabled = newValue != null && Integer.parseInt(newValue) != 0;
+            mEnableCustomPreference.setChecked(mCustomEnabled);
+            mCustomPreference.setEnabled(mCustomEnabled
+                    && mState != DisplayController.COLOR_STATE_DISABLED);
+            updateSelectOptions();
+        } else if (DisplayController.COLOR_MATRIX_CUSTOM_VALUES.equals(key)) {
+            mCustomValues = newValue;
+            if (mCustomValues == null) {
+                mCustomValues = DisplayController.toString(DisplayController.IDENTITY_MATRIX);
+            }
+            mCustomPreference.setValues(mCustomValues);
+            updateSelectOptions();
+        } else if (DisplayController.COLOR_STATE.equals(key)) {
+            mState = newValue != null ? Integer.parseInt(newValue) : 0;
+            if (mSwitch != null) {
+                mSwitch.setChecked(mState != DisplayController.COLOR_STATE_DISABLED);
+            }
+            mSelectPreference.setEnabled(mState != DisplayController.COLOR_STATE_DISABLED);
+            mEnableCustomPreference.setEnabled(mState != DisplayController.COLOR_STATE_DISABLED);
+            mCustomPreference.setEnabled(mCustomEnabled
+                    && mState != DisplayController.COLOR_STATE_DISABLED);
+        } else {
+            mCurrentValue = newValue;
+            updateSelectOptions();
+        }
+    }
+
+    private void updateSelectOptions() {
+        final int N = DisplayController.CUSTOM_INDEX + (mCustomEnabled ? 1 : 0);
+        String[] values = new String[N];
+        CharSequence[] names = new CharSequence[N];
+        CharSequence[] totalNames = DisplayController.getColorTitles(getContext());
+        String[] entries = DisplayController.getColorTransforms(getContext());
+        entries[DisplayController.CUSTOM_INDEX] = mCustomValues != null ? mCustomValues : "";
+        for (int i = 0; i < N; i++) {
+            values[i] = entries[i];
+            names[i] = totalNames[i];
+        }
+        mSelectPreference.setEntries(names);
+        mSelectPreference.setEntryValues(values);
+        int index = 0;
+        if (mState == DisplayController.COLOR_STATE_AUTO) {
+            index = DisplayController.AUTO_INDEX;
+        } else if (mCustomValues != null && Objects.equals(mCurrentValue, mCustomValues)) {
+            index = DisplayController.CUSTOM_INDEX;
+        } else if (Objects.equals(mCurrentValue, entries[1])) {
+            index = 1;
+        }
+        mSelectPreference.setValueIndex(index);
+        mSelectPreference.setSummary("%s");
+        return;
+    }
+
+    private void startRevertTimer() {
+        getView().postDelayed(mResetColorMatrix, RESET_DELAY);
+    }
+
+    private void onApply() {
+        Settings.Secure.putString(getContext().getContentResolver(),
+                DisplayController.COLOR_MATRIX_CUSTOM_VALUES, mCurrentValue);
+        getView().removeCallbacks(mResetColorMatrix);
+    }
+
+    private void onRevert() {
+        getView().removeCallbacks(mResetColorMatrix);
+        mResetColorMatrix.run();
+    }
+
+    private final Runnable mResetColorMatrix = new Runnable() {
+        @Override
+        public void run() {
+            ((DialogFragment) getFragmentManager().findFragmentByTag("RevertWarning")).dismiss();
+            Settings.Secure.putString(getContext().getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, null);
+        }
+    };
+
+    private class MatrixPreference extends Preference implements View.OnClickListener {
+        private float[] mValues;
+
+        public MatrixPreference(Context context) {
+            super(context);
+            setLayoutResource(R.layout.preference_matrix);
+        }
+
+        public void setValues(String customValues) {
+            String[] strValues = customValues.split(",");
+            mValues = new float[strValues.length];
+            for (int i = 0; i < mValues.length; i++) {
+                mValues[i] = Float.parseFloat(strValues[i]);
+            }
+            notifyChanged();
+        }
+
+        @Override
+        public void onBindViewHolder(PreferenceViewHolder holder) {
+            super.onBindViewHolder(holder);
+            bindView(holder.findViewById(R.id.r_group), 0);
+            bindView(holder.findViewById(R.id.g_group), 5);
+            bindView(holder.findViewById(R.id.b_group), 10);
+            holder.findViewById(R.id.apply).setOnClickListener(this);
+        }
+
+        private void bindView(View view, final int index) {
+            SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
+            seekBar.setMax(1000);
+            seekBar.setProgress((int) (1000 * mValues[index]));
+            seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+                @Override
+                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                    mValues[index] = progress / 1000f;
+                }
+
+                @Override
+                public void onStartTrackingTouch(SeekBar seekBar) {
+                }
+
+                @Override
+                public void onStopTrackingTouch(SeekBar seekBar) {
+                }
+            });
+        }
+
+        @Override
+        public void onClick(View v) {
+            startRevertTimer();
+            Settings.Secure.putString(getContext().getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
+                    DisplayController.toString(mValues));
+            RevertWarning.show(ColorMatrixFragment.this);
+        }
+
+    }
+
+    public static class RevertWarning extends DialogFragment
+            implements DialogInterface.OnClickListener {
+
+        public static void show(ColorMatrixFragment fragment) {
+            RevertWarning warning = new RevertWarning();
+            warning.setTargetFragment(fragment, 0);
+            warning.show(fragment.getFragmentManager(), "RevertWarning");
+        }
+
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            AlertDialog alertDialog = new AlertDialog.Builder(getContext())
+                    .setTitle(R.string.color_revert_title)
+                    .setMessage(R.string.color_revert_message)
+                    .setPositiveButton(R.string.ok, this)
+                    .create();
+            alertDialog.setCanceledOnTouchOutside(true);
+            return alertDialog;
+        }
+
+        @Override
+        public void onCancel(DialogInterface dialog) {
+            super.onCancel(dialog);
+            ((ColorMatrixFragment) getTargetFragment()).onRevert();
+        }
+
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+            ((ColorMatrixFragment) getTargetFragment()).onApply();
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java
new file mode 100644
index 0000000..1933c15
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java
@@ -0,0 +1,106 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.tuner;
+
+import android.app.ActivityManager;
+import android.provider.Settings;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.DisplayController;
+
+import java.util.Objects;
+
+
+public class ColorMatrixTile extends QSTile<QSTile.State> implements DisplayController.Listener {
+
+    public static final String COLOR_MATRIX_SPEC = "colors";
+
+    private final DisplayController mDisplayController;
+
+    private int mIndex;
+    private String mCurrentValue;
+
+    private boolean mCustomEnabled;
+    private String[] mValues;
+    private CharSequence[] mValueTitles;
+
+    public ColorMatrixTile(Host host) {
+        super(host);
+        mDisplayController = host.getDisplayController();
+    }
+
+    @Override
+    public void setListening(boolean listening) {
+        if (listening) {
+            mValues = DisplayController.getColorTransforms(mContext);
+            mValueTitles = DisplayController.getColorTitles(mContext);
+            mDisplayController.addListener(this);
+        } else {
+            mDisplayController.removeListener(this);
+        }
+    }
+
+    @Override
+    protected State newTileState() {
+        return new State();
+    }
+
+    @Override
+    protected void handleClick() {
+        mIndex++;
+        if (mIndex == DisplayController.AUTO_INDEX) {
+            mDisplayController.setAuto(true);
+        } else {
+            mDisplayController.setAuto(false);
+            if (!mDisplayController.isCustomEnabled()
+                    && (mIndex == DisplayController.CUSTOM_INDEX)) {
+                mIndex++;
+            }
+            if (mIndex == mValues.length - 1) {
+                mIndex = 0;
+            }
+            Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, mValues[mIndex],
+                    ActivityManager.getCurrentUser());
+        }
+        refreshState();
+    }
+
+    @Override
+    protected void handleUpdateState(State state, Object arg) {
+        if (mDisplayController.isAuto()) {
+            mIndex = DisplayController.AUTO_INDEX;
+        } else if (mDisplayController.isCustomSet()) {
+            mIndex = DisplayController.CUSTOM_INDEX;
+        } else {
+            mIndex = Objects.equals(mDisplayController.getCurrentMatrix(), mValues[1]) ? 1 : 0;
+        }
+        state.icon = ResourceIcon.get(R.drawable.ic_colorize);
+        state.label = mValueTitles[mIndex];
+        state.contentDescription = mValueTitles[mIndex];
+    }
+
+    @Override
+    public void onCurrentMatrixChanged() {
+        refreshState();
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsEvent.QS_COLOR_MATRIX;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
index a2b062c..f801963 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
@@ -22,15 +22,16 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
-import android.preference.Preference;
-import android.preference.Preference.OnPreferenceChangeListener;
-import android.preference.PreferenceFragment;
-import android.preference.PreferenceScreen;
-import android.preference.SwitchPreference;
 import android.provider.Settings;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.Preference.OnPreferenceChangeListener;
+import android.support.v7.preference.PreferenceScreen;
 import android.view.MenuItem;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.DemoMode;
 import com.android.systemui.R;
 
@@ -56,9 +57,7 @@
     private SwitchPreference mOnSwitch;
 
     @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
+    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
         Context context = getContext();
         mEnabledSwitch = new SwitchPreference(context);
         mEnabledSwitch.setTitle(R.string.enable_demo_mode);
@@ -96,13 +95,13 @@
     @Override
     public void onResume() {
         super.onResume();
-        MetricsLogger.visibility(getContext(), MetricsLogger.TUNER_DEMO_MODE, true);
+        MetricsLogger.visibility(getContext(), MetricsEvent.TUNER_DEMO_MODE, true);
     }
 
     @Override
     public void onPause() {
         super.onPause();
-        MetricsLogger.visibility(getContext(), MetricsLogger.TUNER_DEMO_MODE, false);
+        MetricsLogger.visibility(getContext(), MetricsEvent.TUNER_DEMO_MODE, false);
     }
 
     @Override
@@ -133,10 +132,10 @@
                 mOnSwitch.setChecked(false);
                 stopDemoMode();
             }
-            MetricsLogger.action(getContext(), MetricsLogger.TUNER_DEMO_MODE_ENABLED, enabled);
+            MetricsLogger.action(getContext(), MetricsEvent.TUNER_DEMO_MODE_ENABLED, enabled);
             setGlobal(DemoMode.DEMO_MODE_ALLOWED, enabled ? 1 : 0);
         } else if (preference == mOnSwitch) {
-            MetricsLogger.action(getContext(), MetricsLogger.TUNER_DEMO_MODE_ON, enabled);
+            MetricsLogger.action(getContext(), MetricsEvent.TUNER_DEMO_MODE_ON, enabled);
             if (enabled) {
                 startDemoMode();
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/KeycodeSelectionHelper.java b/packages/SystemUI/src/com/android/systemui/tuner/KeycodeSelectionHelper.java
new file mode 100644
index 0000000..e6073ae
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/KeycodeSelectionHelper.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.tuner;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.util.Pair;
+import android.view.KeyEvent;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import com.android.systemui.R;
+
+public class KeycodeSelectionHelper {
+
+    private static final ArrayList<String> mKeycodeStrings = new ArrayList<>();
+    private static final ArrayList<Integer> mKeycodes = new ArrayList<>();
+
+    private static final String KEYCODE_STRING = "KEYCODE_";
+
+    static {
+        Class<KeyEvent> cls = KeyEvent.class;
+        for (Field field : cls.getDeclaredFields()) {
+            if (Modifier.isStatic(field.getModifiers())
+                    && field.getName().startsWith(KEYCODE_STRING)
+                    && field.getType().equals(int.class)) {
+                try {
+                    mKeycodeStrings.add(formatString(field.getName()));
+                    mKeycodes.add((Integer) field.get(null));
+                } catch (IllegalAccessException e) {
+                }
+            }
+        }
+    }
+
+    // Force the string into something somewhat readable.
+    private static String formatString(String name) {
+        StringBuilder str = new StringBuilder(name.replace(KEYCODE_STRING, "").replace("_", " ")
+                .toLowerCase());
+        for (int i = 0; i < str.length(); i++) {
+            if (i == 0 || str.charAt(i - 1) == ' ') {
+                str.setCharAt(i, Character.toUpperCase(str.charAt(i)));
+            }
+        }
+        return str.toString();
+    }
+
+    public static void showKeycodeSelect(Context context, final OnSelectionComplete listener) {
+        new AlertDialog.Builder(context)
+                .setTitle(R.string.select_keycode)
+                .setItems(mKeycodeStrings.toArray(new String[0]),
+                        new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        listener.onSelectionComplete(mKeycodes.get(which));
+                    }
+                }).show();
+    }
+
+    public static Intent getSelectImageIntent() {
+        return new Intent(Intent.ACTION_OPEN_DOCUMENT).addCategory(Intent.CATEGORY_OPENABLE)
+                .setType("image/*");
+    }
+
+    public interface OnSelectionComplete {
+        void onSelectionComplete(int code);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
new file mode 100644
index 0000000..6fba9dc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
@@ -0,0 +1,608 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 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.tuner;
+
+import com.android.systemui.R;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.helper.ItemTouchHelper;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.Display;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.CLIPBOARD;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_CODE_END;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_CODE_START;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_IMAGE_DELIM;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.SIZE_MOD_END;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.SIZE_MOD_START;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.extractButton;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.extractSize;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.BACK;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.BUTTON_SEPARATOR;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.GRAVITY_SEPARATOR;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.HOME;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.MENU_IME;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAVSPACE;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAV_BAR_VIEWS;
+import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.RECENT;
+
+public class NavBarTuner extends Fragment implements TunerService.Tunable {
+
+    private static final int SAVE = Menu.FIRST + 1;
+    private static final int RESET = Menu.FIRST + 2;
+    private static final int READ_REQUEST = 42;
+
+    private static final float PREVIEW_SCALE = .95f;
+    private static final float PREVIEW_SCALE_LANDSCAPE = .75f;
+
+    private NavBarAdapter mNavBarAdapter;
+    private PreviewNavInflater mPreview;
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+            Bundle savedInstanceState) {
+        final View view = inflater.inflate(R.layout.nav_bar_tuner, container, false);
+        inflatePreview((ViewGroup) view.findViewById(R.id.nav_preview_frame));
+        return view;
+    }
+
+    private void inflatePreview(ViewGroup view) {
+        Display display = getActivity().getWindowManager().getDefaultDisplay();
+        boolean isRotated = display.getRotation() == Surface.ROTATION_90
+                || display.getRotation() == Surface.ROTATION_270;
+
+        Configuration config = new Configuration(getContext().getResources().getConfiguration());
+        boolean isPhoneLandscape = isRotated && (config.smallestScreenWidthDp < 600);
+        final float scale = isPhoneLandscape ? PREVIEW_SCALE_LANDSCAPE : PREVIEW_SCALE;
+        config.densityDpi = (int) (config.densityDpi * scale);
+
+        mPreview = (PreviewNavInflater) LayoutInflater.from(getContext().createConfigurationContext(
+                config)).inflate(R.layout.nav_bar_tuner_inflater, view, false);
+        final ViewGroup.LayoutParams layoutParams = mPreview.getLayoutParams();
+        layoutParams.width = (int) ((isPhoneLandscape ? display.getHeight() : display.getWidth())
+                * scale);
+        // Not sure why, but the height dimen is not being scaled with the dp, set it manually
+        // for now.
+        layoutParams.height = (int) (layoutParams.height * scale);
+        if (isPhoneLandscape) {
+            int width = layoutParams.width;
+            layoutParams.width = layoutParams.height;
+            layoutParams.height = width;
+        }
+        view.addView(mPreview);
+
+        if (isRotated) {
+            mPreview.findViewById(R.id.rot0).setVisibility(View.GONE);
+            final View rot90 = mPreview.findViewById(R.id.rot90);
+            rot90.findViewById(R.id.ends_group_lightsout).setVisibility(View.GONE);
+            rot90.findViewById(R.id.center_group_lightsout).setVisibility(View.GONE);
+        } else {
+            mPreview.findViewById(R.id.rot90).setVisibility(View.GONE);
+            final View rot0 = mPreview.findViewById(R.id.rot0);
+            rot0.findViewById(R.id.ends_group_lightsout).setVisibility(View.GONE);
+            rot0.findViewById(R.id.center_group_lightsout).setVisibility(View.GONE);
+        }
+    }
+
+    private void notifyChanged() {
+        mPreview.onTuningChanged(NAV_BAR_VIEWS, mNavBarAdapter.getNavString());
+    }
+
+    @Override
+    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        RecyclerView recyclerView = (RecyclerView) view.findViewById(android.R.id.list);
+        final Context context = getContext();
+        recyclerView.setLayoutManager(new LinearLayoutManager(context));
+        mNavBarAdapter = new NavBarAdapter(context);
+        recyclerView.setAdapter(mNavBarAdapter);
+        recyclerView.addItemDecoration(new Dividers(context));
+        final ItemTouchHelper itemTouchHelper = new ItemTouchHelper(mNavBarAdapter.mCallbacks);
+        mNavBarAdapter.setTouchHelper(itemTouchHelper);
+        itemTouchHelper.attachToRecyclerView(recyclerView);
+
+        TunerService.get(getContext()).addTunable(this, NAV_BAR_VIEWS);
+    }
+
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+        TunerService.get(getContext()).removeTunable(this);
+    }
+
+    @Override
+    public void onTuningChanged(String key, String navLayout) {
+        if (!NAV_BAR_VIEWS.equals(key)) return;
+        Context context = getContext();
+        if (navLayout == null) {
+            navLayout = context.getString(R.string.config_navBarLayout);
+        }
+        String[] views = navLayout.split(GRAVITY_SEPARATOR);
+        String[] groups = new String[] { NavBarAdapter.START, NavBarAdapter.CENTER,
+                NavBarAdapter.END};
+        CharSequence[] groupLabels = new String[] { getString(R.string.start),
+                getString(R.string.center), getString(R.string.end) };
+        mNavBarAdapter.clear();
+        for (int i = 0; i < 3; i++) {
+            mNavBarAdapter.addButton(groups[i], groupLabels[i]);
+            for (String button : views[i].split(BUTTON_SEPARATOR)) {
+                mNavBarAdapter.addButton(button, getLabel(button, context));
+            }
+        }
+        mNavBarAdapter.addButton(NavBarAdapter.ADD, getString(R.string.add_button));
+        setHasOptionsMenu(true);
+    }
+
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        super.onCreateOptionsMenu(menu, inflater);
+        // TODO: Show save button conditionally, only when there are changes.
+        menu.add(Menu.NONE, SAVE, Menu.NONE, getString(R.string.save))
+                .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+        menu.add(Menu.NONE, RESET, Menu.NONE, getString(R.string.reset));
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == SAVE) {
+            if (!mNavBarAdapter.hasHomeButton()) {
+                new AlertDialog.Builder(getContext())
+                        .setTitle(R.string.no_home_title)
+                        .setMessage(R.string.no_home_message)
+                        .setPositiveButton(android.R.string.ok, null)
+                        .show();
+            } else {
+                Settings.Secure.putString(getContext().getContentResolver(),
+                        NAV_BAR_VIEWS, mNavBarAdapter.getNavString());
+            }
+            return true;
+        } else if (item.getItemId() == RESET) {
+            Settings.Secure.putString(getContext().getContentResolver(),
+                    NAV_BAR_VIEWS, null);
+            return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    private static CharSequence getLabel(String button, Context context) {
+        if (button.startsWith(HOME)) {
+            return context.getString(R.string.accessibility_home);
+        } else if (button.startsWith(BACK)) {
+            return context.getString(R.string.accessibility_back);
+        } else if (button.startsWith(RECENT)) {
+            return context.getString(R.string.accessibility_recent);
+        } else if (button.startsWith(NAVSPACE)) {
+            return context.getString(R.string.space);
+        } else if (button.startsWith(MENU_IME)) {
+            return context.getString(R.string.menu_ime);
+        } else if (button.startsWith(CLIPBOARD)) {
+            return context.getString(R.string.clipboard);
+        } else if (button.startsWith(KEY)) {
+            return context.getString(R.string.keycode);
+        }
+        return button;
+    }
+
+    private static class Holder extends RecyclerView.ViewHolder {
+        private TextView title;
+
+        public Holder(View itemView) {
+            super(itemView);
+            title = (TextView) itemView.findViewById(android.R.id.title);
+        }
+    }
+
+    private static class Dividers extends RecyclerView.ItemDecoration {
+        private final Drawable mDivider;
+
+        public Dividers(Context context) {
+            TypedValue value = new TypedValue();
+            context.getTheme().resolveAttribute(android.R.attr.listDivider, value, true);
+            mDivider = context.getDrawable(value.resourceId);
+        }
+
+        @Override
+        public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
+            super.onDraw(c, parent, state);
+            final int left = parent.getPaddingLeft();
+            final int right = parent.getWidth() - parent.getPaddingRight();
+
+            final int childCount = parent.getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                final View child = parent.getChildAt(i);
+                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
+                        .getLayoutParams();
+                final int top = child.getBottom() + params.bottomMargin;
+                final int bottom = top + mDivider.getIntrinsicHeight();
+                mDivider.setBounds(left, top, right, bottom);
+                mDivider.draw(c);
+            }
+        }
+    }
+
+    private void selectImage() {
+        startActivityForResult(KeycodeSelectionHelper.getSelectImageIntent(), READ_REQUEST);
+    }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode == READ_REQUEST && resultCode == Activity.RESULT_OK && data != null) {
+            final Uri uri = data.getData();
+            final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION);
+            getContext().getContentResolver().takePersistableUriPermission(uri, takeFlags);
+            mNavBarAdapter.onImageSelected(uri);
+        } else {
+            super.onActivityResult(requestCode, resultCode, data);
+        }
+    }
+
+    private class NavBarAdapter extends RecyclerView.Adapter<Holder>
+            implements View.OnClickListener {
+
+        private static final String START = "start";
+        private static final String CENTER = "center";
+        private static final String END = "end";
+        private static final String ADD = "add";
+
+        private static final int ADD_ID = 0;
+        private static final int BUTTON_ID = 1;
+        private static final int CATEGORY_ID = 2;
+
+        private List<String> mButtons = new ArrayList<>();
+        private List<CharSequence> mLabels = new ArrayList<>();
+        private int mCategoryLayout;
+        private int mButtonLayout;
+        private ItemTouchHelper mTouchHelper;
+
+        // Stored keycode while we wait for image selection on a KEY.
+        private int mKeycode;
+
+        public NavBarAdapter(Context context) {
+            TypedArray attrs = context.getTheme().obtainStyledAttributes(null,
+                    android.R.styleable.Preference, android.R.attr.preferenceStyle, 0);
+            mButtonLayout = attrs.getResourceId(android.R.styleable.Preference_layout, 0);
+            attrs = context.getTheme().obtainStyledAttributes(null,
+                    android.R.styleable.Preference, android.R.attr.preferenceCategoryStyle, 0);
+            mCategoryLayout = attrs.getResourceId(android.R.styleable.Preference_layout, 0);
+        }
+
+        public void setTouchHelper(ItemTouchHelper itemTouchHelper) {
+            mTouchHelper = itemTouchHelper;
+        }
+
+        public void clear() {
+            mButtons.clear();
+            mLabels.clear();
+            notifyDataSetChanged();
+        }
+
+        public void addButton(String button, CharSequence label) {
+            mButtons.add(button);
+            mLabels.add(label);
+            notifyItemInserted(mLabels.size() - 1);
+            notifyChanged();
+        }
+
+        public boolean hasHomeButton() {
+            final int N = mButtons.size();
+            for (int i = 0; i < N; i++) {
+                if (mButtons.get(i).startsWith(HOME)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public String getNavString() {
+            StringBuilder builder = new StringBuilder();
+            for (int i = 1; i < mButtons.size() - 1; i++) {
+                String button = mButtons.get(i);
+                if (button.equals(CENTER) || button.equals(END)) {
+                    if (builder.length() == 0 || builder.toString().endsWith(GRAVITY_SEPARATOR)) {
+                        // No start or center buttons, fill with a space.
+                        builder.append(NAVSPACE);
+                    }
+                    builder.append(GRAVITY_SEPARATOR);
+                    continue;
+                } else if (builder.length() != 0 && !builder.toString().endsWith(
+                        GRAVITY_SEPARATOR)) {
+                    builder.append(BUTTON_SEPARATOR);
+                }
+                builder.append(button);
+            }
+            if (builder.toString().endsWith(GRAVITY_SEPARATOR)) {
+                // No end buttons, fill with space.
+                builder.append(NAVSPACE);
+            }
+            return builder.toString();
+        }
+
+        @Override
+        public int getItemViewType(int position) {
+            String button = mButtons.get(position);
+            if (button.equals(START) || button.equals(CENTER) || button.equals(END)) {
+                return CATEGORY_ID;
+            }
+            if (button.equals(ADD)) {
+                return ADD_ID;
+            }
+            return BUTTON_ID;
+        }
+
+        @Override
+        public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
+            final Context context = parent.getContext();
+            final LayoutInflater inflater = LayoutInflater.from(context);
+            final View view = inflater.inflate(getLayoutId(viewType), parent, false);
+            if (viewType == BUTTON_ID) {
+                inflater.inflate(R.layout.nav_control_widget,
+                        (ViewGroup) view.findViewById(android.R.id.widget_frame));
+            }
+            return new Holder(view);
+        }
+
+        private int getLayoutId(int viewType) {
+            if (viewType == CATEGORY_ID) {
+                return mCategoryLayout;
+            }
+            return mButtonLayout;
+        }
+
+        @Override
+        public void onBindViewHolder(Holder holder, int position) {
+            holder.title.setText(mLabels.get(position));
+            if (holder.getItemViewType() == BUTTON_ID) {
+                bindButton(holder, position);
+            } else if (holder.getItemViewType() == ADD_ID) {
+                bindAdd(holder);
+            }
+        }
+
+        private void bindAdd(Holder holder) {
+            TypedValue value = new TypedValue();
+            final Context context = holder.itemView.getContext();
+            context.getTheme().resolveAttribute(android.R.attr.colorAccent, value, true);
+            final ImageView icon = (ImageView) holder.itemView.findViewById(android.R.id.icon);
+            icon.setImageResource(R.drawable.ic_add);
+            icon.setImageTintList(ColorStateList.valueOf(context.getColor(value.resourceId)));
+            holder.itemView.findViewById(android.R.id.summary).setVisibility(View.GONE);
+            holder.itemView.setClickable(true);
+            holder.itemView.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    showAddDialog(v.getContext());
+                }
+            });
+        }
+
+        private void bindButton(final Holder holder, int position) {
+            holder.itemView.findViewById(android.R.id.icon_frame).setVisibility(View.GONE);
+            holder.itemView.findViewById(android.R.id.summary).setVisibility(View.GONE);
+            bindClick(holder.itemView.findViewById(R.id.close), holder);
+            bindClick(holder.itemView.findViewById(R.id.width), holder);
+            holder.itemView.findViewById(R.id.drag).setOnTouchListener(new View.OnTouchListener() {
+                @Override
+                public boolean onTouch(View v, MotionEvent event) {
+                    mTouchHelper.startDrag(holder);
+                    return true;
+                }
+            });
+        }
+
+        private void showAddDialog(final Context context) {
+            final String[] options = new String[] {
+                    BACK, HOME, RECENT, MENU_IME, NAVSPACE, CLIPBOARD, KEY,
+            };
+            final CharSequence[] labels = new CharSequence[options.length];
+            for (int i = 0; i < options.length; i++) {
+                labels[i] = getLabel(options[i], context);
+            }
+            new AlertDialog.Builder(context)
+                    .setTitle(R.string.select_button)
+                    .setItems(labels, new DialogInterface.OnClickListener() {
+                        @Override
+                        public void onClick(DialogInterface dialog, int which) {
+                            if (KEY.equals(options[which])) {
+                                showKeyDialogs(context);
+                            } else {
+                                int index = mButtons.size() - 1;
+                                showAddedMessage(context, options[which]);
+                                mButtons.add(index, options[which]);
+                                mLabels.add(index, labels[which]);
+
+                                notifyItemInserted(index);
+                                notifyChanged();
+                            }
+                        }
+                    }).setNegativeButton(android.R.string.cancel, null)
+                    .show();
+        }
+
+        private void onImageSelected(Uri uri) {
+            int index = mButtons.size() - 1;
+            mButtons.add(index, KEY + KEY_CODE_START + mKeycode + KEY_IMAGE_DELIM + uri.toString()
+                    + KEY_CODE_END);
+            mLabels.add(index, getLabel(KEY, getContext()));
+
+            notifyItemInserted(index);
+            notifyChanged();
+        }
+
+        private void showKeyDialogs(final Context context) {
+            final KeycodeSelectionHelper.OnSelectionComplete listener =
+                    new KeycodeSelectionHelper.OnSelectionComplete() {
+                        @Override
+                        public void onSelectionComplete(int code) {
+                            mKeycode = code;
+                            selectImage();
+                        }
+                    };
+            new AlertDialog.Builder(context)
+                    .setTitle(R.string.keycode)
+                    .setMessage(R.string.keycode_description)
+                    .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+                        @Override
+                        public void onClick(DialogInterface dialog, int which) {
+                            KeycodeSelectionHelper.showKeycodeSelect(context, listener);
+                        }
+                    }).show();
+        }
+
+        private void showAddedMessage(Context context, String button) {
+            if (CLIPBOARD.equals(button)) {
+                new AlertDialog.Builder(context)
+                        .setTitle(R.string.clipboard)
+                        .setMessage(R.string.clipboard_description)
+                        .setPositiveButton(android.R.string.ok, null)
+                        .show();
+            }
+        }
+
+        private void bindClick(View view, Holder holder) {
+            view.setOnClickListener(this);
+            view.setTag(holder);
+        }
+
+        @Override
+        public void onClick(View v) {
+            Holder holder = (Holder) v.getTag();
+            if (v.getId() == R.id.width) {
+                showWidthDialog(holder, v.getContext());
+            } else if (v.getId() == R.id.close) {
+                int position = holder.getAdapterPosition();
+                mButtons.remove(position);
+                mLabels.remove(position);
+                notifyItemRemoved(position);
+                notifyChanged();
+            }
+        }
+
+        private void showWidthDialog(final Holder holder, Context context) {
+            final String buttonSpec = mButtons.get(holder.getAdapterPosition());
+            float amount = extractSize(buttonSpec);
+            final AlertDialog dialog = new AlertDialog.Builder(context)
+                    .setTitle(R.string.adjust_button_width)
+                    .setView(R.layout.nav_width_view)
+                    .setNegativeButton(android.R.string.cancel, null).create();
+            dialog.setButton(DialogInterface.BUTTON_POSITIVE,
+                    context.getString(android.R.string.ok),
+                    new DialogInterface.OnClickListener() {
+                        @Override
+                        public void onClick(DialogInterface d, int which) {
+                            final String button = extractButton(buttonSpec);
+                            SeekBar seekBar = (SeekBar) dialog.findViewById(R.id.seekbar);
+                            if (seekBar.getProgress() == 75) {
+                                mButtons.set(holder.getAdapterPosition(), button);
+                            } else {
+                                float amount = (seekBar.getProgress() + 25) / 100f;
+                                mButtons.set(holder.getAdapterPosition(), button
+                                        + SIZE_MOD_START + amount + SIZE_MOD_END);
+                            }
+                            notifyChanged();
+                        }
+                    });
+            dialog.show();
+            SeekBar seekBar = (SeekBar) dialog.findViewById(R.id.seekbar);
+            // Range is .25 - 1.75.
+            seekBar.setMax(150);
+            seekBar.setProgress((int) ((amount - .25f) * 100));
+        }
+
+        @Override
+        public int getItemCount() {
+            return mButtons.size();
+        }
+
+        private final ItemTouchHelper.Callback mCallbacks = new ItemTouchHelper.Callback() {
+            @Override
+            public boolean isLongPressDragEnabled() {
+                return false;
+            }
+
+            @Override
+            public boolean isItemViewSwipeEnabled() {
+                return false;
+            }
+
+            @Override
+            public int getMovementFlags(RecyclerView recyclerView,
+                    RecyclerView.ViewHolder viewHolder) {
+                if (viewHolder.getItemViewType() != BUTTON_ID) {
+                    return makeMovementFlags(0, 0);
+                }
+                int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
+                return makeMovementFlags(dragFlags, 0);
+            }
+
+            @Override
+            public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
+                    RecyclerView.ViewHolder target) {
+                int from = viewHolder.getAdapterPosition();
+                int to = target.getAdapterPosition();
+                if (to == 0) {
+                    // Can't go above the top.
+                    return false;
+                }
+                move(from, to, mButtons);
+                move(from, to, mLabels);
+                notifyChanged();
+                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);
+            }
+
+            @Override
+            public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
+                // Don't care.
+            }
+        };
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PreviewNavInflater.java b/packages/SystemUI/src/com/android/systemui/tuner/PreviewNavInflater.java
new file mode 100644
index 0000000..b30ca5c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/PreviewNavInflater.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 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.tuner;
+
+import com.android.systemui.statusbar.phone.NavigationBarInflaterView;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+public class PreviewNavInflater extends NavigationBarInflaterView {
+
+    public PreviewNavInflater(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        // Immediately remove tuner listening, since this is a preview, all values will be injected
+        // manually.
+        TunerService.get(getContext()).removeTunable(this);
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        // Only a preview, not interactable.
+        return true;
+    }
+
+    @Override
+    public void onTuningChanged(String key, String newValue) {
+        if (NAV_BAR_VIEWS.equals(key)) {
+            // Since this is a preview we might get a bunch of random stuff, validate before sending
+            // for inflation.
+            if (isValidLayout(newValue)) {
+                super.onTuningChanged(key, newValue);
+            }
+        } else {
+            super.onTuningChanged(key, newValue);
+        }
+    }
+
+    private boolean isValidLayout(String newValue) {
+        if (newValue == null) {
+            return true;
+        }
+        int separatorCount = 0;
+        int lastGravitySeparator = 0;
+        for (int i = 0; i < newValue.length(); i++) {
+            if (newValue.charAt(i) == GRAVITY_SEPARATOR.charAt(0)) {
+                if (i == 0 || (i - lastGravitySeparator) == 1) {
+                    return false;
+                }
+                lastGravitySeparator = i;
+                separatorCount++;
+            }
+        }
+        return separatorCount == 2 && (newValue.length() - lastGravitySeparator) != 1;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/QSPagingSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/QSPagingSwitch.java
deleted file mode 100644
index d19a825..0000000
--- a/packages/SystemUI/src/com/android/systemui/tuner/QSPagingSwitch.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.android.systemui.tuner;
-
-import android.content.Context;
-import android.provider.Settings;
-import android.util.AttributeSet;
-
-import com.android.systemui.statusbar.phone.QSTileHost;
-
-public class QSPagingSwitch extends TunerSwitch {
-
-    public static final String QS_PAGE_TILES =
-            "dnd,cell,battery,user,rotation,flashlight,location,"
-             + "hotspot,inversion,cast";
-
-    public QSPagingSwitch(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected boolean persistBoolean(boolean value) {
-        Settings.Secure.putString(getContext().getContentResolver(), QSTileHost.TILES_SETTING,
-                value ? QS_PAGE_TILES : "default");
-        return super.persistBoolean(value);
-    }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
index dcb0d8d..f2f0382 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
@@ -18,12 +18,13 @@
 import android.app.ActivityManager;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.preference.SwitchPreference;
 import android.provider.Settings;
+import android.support.v14.preference.SwitchPreference;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.tuner.TunerService.Tunable;
 
@@ -38,15 +39,15 @@
     }
 
     @Override
-    protected void onAttachedToActivity() {
-        super.onAttachedToActivity();
+    public void onAttached() {
+        super.onAttached();
         TunerService.get(getContext()).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
     }
 
     @Override
-    protected void onDetachedFromActivity() {
+    public void onDetached() {
         TunerService.get(getContext()).removeTunable(this);
-        super.onDetachedFromActivity();
+        super.onDetached();
     }
 
     @Override
@@ -63,14 +64,14 @@
         if (!value) {
             // If not enabled add to blacklist.
             if (!mBlacklist.contains(getKey())) {
-                MetricsLogger.action(getContext(), MetricsLogger.TUNER_STATUS_BAR_DISABLE,
+                MetricsLogger.action(getContext(), MetricsEvent.TUNER_STATUS_BAR_DISABLE,
                         getKey());
                 mBlacklist.add(getKey());
                 setList(mBlacklist);
             }
         } else {
             if (mBlacklist.remove(getKey())) {
-                MetricsLogger.action(getContext(), MetricsLogger.TUNER_STATUS_BAR_ENABLE, getKey());
+                MetricsLogger.action(getContext(), MetricsEvent.TUNER_STATUS_BAR_ENABLE, getKey());
                 setList(mBlacklist);
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
index c84f618..4225b48 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
@@ -15,16 +15,69 @@
  */
 package com.android.systemui.tuner;
 
-import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentTransaction;
 import android.os.Bundle;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.util.Log;
 
-public class TunerActivity extends Activity {
+import com.android.settingslib.drawer.SettingsDrawerActivity;
+import com.android.systemui.R;
+
+public class TunerActivity extends SettingsDrawerActivity implements
+        PreferenceFragment.OnPreferenceStartFragmentCallback,
+        PreferenceFragment.OnPreferenceStartScreenCallback {
+
+    private static final String TAG_TUNER = "tuner";
 
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        getFragmentManager().beginTransaction().replace(android.R.id.content, new TunerFragment())
-                .commit();
+        if (getFragmentManager().findFragmentByTag(TAG_TUNER) == null) {
+            getFragmentManager().beginTransaction().replace(R.id.content_frame, new TunerFragment(),
+                    TAG_TUNER).commit();
+        }
+    }
+
+    @Override
+    public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
+        try {
+            Class<?> cls = Class.forName(pref.getFragment());
+            Fragment fragment = (Fragment) cls.newInstance();
+            FragmentTransaction transaction = getFragmentManager().beginTransaction();
+            setTitle(pref.getTitle());
+            transaction.replace(R.id.content_frame, fragment);
+            transaction.addToBackStack("PreferenceFragment");
+            transaction.commit();
+            return true;
+        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
+            Log.d("TunerActivity", "Problem launching fragment", e);
+            return false;
+        }
+    }
+
+    @Override
+    public boolean onPreferenceStartScreen(PreferenceFragment caller, PreferenceScreen pref) {
+        FragmentTransaction transaction = getFragmentManager().beginTransaction();
+        SubSettingsFragment fragment = new SubSettingsFragment();
+        final Bundle b = new Bundle(1);
+        b.putString(PreferenceFragment.ARG_PREFERENCE_ROOT, pref.getKey());
+        fragment.setArguments(b);
+        fragment.setTargetFragment(caller, 0);
+        transaction.replace(R.id.content_frame, fragment);
+        transaction.addToBackStack("PreferenceFragment");
+        transaction.commit();
+        return true;
+    }
+
+    public static class SubSettingsFragment extends PreferenceFragment {
+        @Override
+        public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+            setPreferenceScreen((PreferenceScreen) ((PreferenceFragment) getTargetFragment())
+                    .getPreferenceScreen().findPreference(rootKey));
+        }
     }
 
 }
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index b620b50b..e4d7be7 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -24,20 +24,20 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
-import android.preference.Preference;
-import android.preference.Preference.OnPreferenceChangeListener;
-import android.preference.Preference.OnPreferenceClickListener;
-import android.preference.PreferenceFragment;
-import android.preference.SwitchPreference;
 import android.provider.Settings;
 import android.provider.Settings.System;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.Preference.OnPreferenceChangeListener;
+import android.support.v7.preference.Preference.OnPreferenceClickListener;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
+
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
-import com.android.systemui.qs.QSPanel;
-import com.android.systemui.tuner.TunerService.Tunable;
 
 import static com.android.systemui.BatteryMeterDrawable.SHOW_PERCENT_SETTING;
 
@@ -45,8 +45,6 @@
 
     private static final String TAG = "TunerFragment";
 
-    private static final String KEY_QS_TUNER = "qs_tuner";
-    private static final String KEY_DEMO_MODE = "demo_mode";
     private static final String KEY_BATTERY_PCT = "battery_pct";
 
     public static final String SETTING_SEEN_TUNER_WARNING = "seen_tuner_warning";
@@ -59,23 +57,23 @@
 
     private SwitchPreference mBatteryPct;
 
+    @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        addPreferencesFromResource(R.xml.tuner_prefs);
-        getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
         setHasOptionsMenu(true);
+    }
 
-        findPreference(KEY_DEMO_MODE).setOnPreferenceClickListener(new OnPreferenceClickListener() {
-            @Override
-            public boolean onPreferenceClick(Preference preference) {
-                FragmentTransaction ft = getFragmentManager().beginTransaction();
-                ft.replace(android.R.id.content, new DemoModeFragment(), "DemoMode");
-                ft.addToBackStack(null);
-                ft.commit();
-                return true;
-            }
-        });
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
+    }
+
+    @Override
+    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+        addPreferencesFromResource(R.xml.tuner_prefs);
+
         mBatteryPct = (SwitchPreference) findPreference(KEY_BATTERY_PCT);
         if (Settings.Secure.getInt(getContext().getContentResolver(), SETTING_SEEN_TUNER_WARNING,
                 0) == 0) {
@@ -88,11 +86,12 @@
     @Override
     public void onResume() {
         super.onResume();
+        getActivity().setTitle(R.string.system_ui_tuner);
         updateBatteryPct();
         getContext().getContentResolver().registerContentObserver(
                 System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
 
-        MetricsLogger.visibility(getContext(), MetricsLogger.TUNER, true);
+        MetricsLogger.visibility(getContext(), MetricsEvent.TUNER, true);
     }
 
     @Override
@@ -100,7 +99,7 @@
         super.onPause();
         getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
 
-        MetricsLogger.visibility(getContext(), MetricsLogger.TUNER, false);
+        MetricsLogger.visibility(getContext(), MetricsEvent.TUNER, false);
     }
 
     @Override
@@ -149,7 +148,7 @@
         @Override
         public boolean onPreferenceChange(Preference preference, Object newValue) {
             final boolean v = (Boolean) newValue;
-            MetricsLogger.action(getContext(), MetricsLogger.TUNER_BATTERY_PERCENTAGE, v);
+            MetricsLogger.action(getContext(), MetricsEvent.TUNER_BATTERY_PERCENTAGE, v);
             System.putInt(getContext().getContentResolver(), SHOW_PERCENT_SETTING, v ? 1 : 0);
             return true;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
index 1e3b0f1..abaa628 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
@@ -32,7 +32,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.ArrayMap;
-
+import android.util.ArraySet;
 import com.android.systemui.BatteryMeterDrawable;
 import com.android.systemui.DemoMode;
 import com.android.systemui.R;
@@ -41,9 +41,8 @@
 import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 
-import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
+import java.util.Set;
 
 
 public class TunerService extends SystemUI {
@@ -54,7 +53,7 @@
     // Map of Uris we listen on to their settings keys.
     private final ArrayMap<Uri, String> mListeningUris = new ArrayMap<>();
     // Map of settings keys to the listener.
-    private final HashMap<String, List<Tunable>> mTunableLookup = new HashMap<>();
+    private final HashMap<String, Set<Tunable>> mTunableLookup = new HashMap<>();
 
     private ContentResolver mContentResolver;
     private int mCurrentUser;
@@ -77,6 +76,22 @@
         mUserTracker.startTracking();
     }
 
+    public String getValue(String setting) {
+        return Settings.Secure.getStringForUser(mContentResolver, setting, mCurrentUser);
+    }
+
+    public void setValue(String setting, String value) {
+         Settings.Secure.putStringForUser(mContentResolver, setting, value, mCurrentUser);
+    }
+
+    public int getValue(String setting, int def) {
+        return Settings.Secure.getIntForUser(mContentResolver, setting, def, mCurrentUser);
+    }
+
+    public void setValue(String setting, int value) {
+         Settings.Secure.putIntForUser(mContentResolver, setting, value, mCurrentUser);
+    }
+
     public void addTunable(Tunable tunable, String... keys) {
         for (String key : keys) {
             addTunable(tunable, key);
@@ -85,7 +100,7 @@
 
     private void addTunable(Tunable tunable, String key) {
         if (!mTunableLookup.containsKey(key)) {
-            mTunableLookup.put(key, new ArrayList<Tunable>());
+            mTunableLookup.put(key, new ArraySet<Tunable>());
         }
         mTunableLookup.get(key).add(tunable);
         Uri uri = Settings.Secure.getUriFor(key);
@@ -99,7 +114,7 @@
     }
 
     public void removeTunable(Tunable tunable) {
-        for (List<Tunable> list : mTunableLookup.values()) {
+        for (Set<Tunable> list : mTunableLookup.values()) {
             list.remove(tunable);
         }
     }
@@ -116,7 +131,7 @@
 
     public void reloadSetting(Uri uri) {
         String key = mListeningUris.get(uri);
-        List<Tunable> tunables = mTunableLookup.get(key);
+        Set<Tunable> tunables = mTunableLookup.get(key);
         if (tunables == null) {
             return;
         }
@@ -153,8 +168,11 @@
     private static TunerService sInstance;
 
     public static TunerService get(Context context) {
-        SystemUIApplication sysUi = (SystemUIApplication) context.getApplicationContext();
-        TunerService service = sysUi.getComponent(TunerService.class);
+        TunerService service = null;
+        if (context.getApplicationContext() instanceof SystemUIApplication) {
+            SystemUIApplication sysUi = (SystemUIApplication) context.getApplicationContext();
+            service = sysUi.getComponent(TunerService.class);
+        }
         if (service == null) {
             // Can't get it as a component, must in the tuner, lets just create one for now.
             return getStaticService(context);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
index 54078b0..7ad752e 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
@@ -2,8 +2,8 @@
 
 import android.content.Context;
 import android.content.res.TypedArray;
-import android.preference.SwitchPreference;
 import android.provider.Settings;
+import android.support.v14.preference.SwitchPreference;
 import android.util.AttributeSet;
 
 import com.android.systemui.R;
@@ -21,15 +21,15 @@
     }
 
     @Override
-    protected void onAttachedToActivity() {
-        super.onAttachedToActivity();
+    public void onAttached() {
+        super.onAttached();
         TunerService.get(getContext()).addTunable(this, getKey());
     }
 
     @Override
-    protected void onDetachedFromActivity() {
+    public void onDetached() {
         TunerService.get(getContext()).removeTunable(this);
-        super.onDetachedFromActivity();
+        super.onDetached();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
new file mode 100644
index 0000000..e947ed5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.app.ActivityManager.StackInfo;
+import android.app.ActivityManagerNative;
+import android.app.ActivityOptions;
+import android.app.IActivityManager;
+import android.app.ITaskStackListener;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+
+import android.app.ActivityManager.RunningTaskInfo;
+
+/**
+ * Manages the picture-in-picture (PIP) UI and states.
+ */
+public class PipManager {
+    private static final String TAG = "PipManager";
+    private static final boolean DEBUG = false;
+
+    private static PipManager sPipManager;
+
+    private static final int MAX_RUNNING_TASKS_COUNT = 10;
+
+    private static final int STATE_NO_PIP = 0;
+    private static final int STATE_PIP_OVERLAY = 1;
+    private static final int STATE_PIP_MENU = 2;
+
+    private static final int TASK_ID_NO_PIP = -1;
+    private static final int INVALID_RESOURCE_TYPE = -1;
+
+    private Context mContext;
+    private IActivityManager mActivityManager;
+    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 boolean mInitialized;
+    private int mPipTaskId = TASK_ID_NO_PIP;
+
+    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];
+            showPipOverlay(false);
+        }
+    };
+    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 BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (Intent.ACTION_PICTURE_IN_PICTURE_BUTTON.equals(action)) {
+                if (DEBUG) Log.d(TAG, "PIP button pressed");
+                if (!hasPipTasks()) {
+                    startPip();
+                } else if (mState == STATE_PIP_OVERLAY) {
+                    showPipMenu();
+                }
+            } else if (Intent.ACTION_MEDIA_RESOURCE_GRANTED.equals(action)) {
+                String[] packageNames = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
+                int resourceType = intent.getIntExtra(Intent.EXTRA_MEDIA_RESOURCE_TYPE,
+                        INVALID_RESOURCE_TYPE);
+                if (mState != STATE_NO_PIP && packageNames != null && packageNames.length > 0
+                        && resourceType == Intent.EXTRA_MEDIA_RESOURCE_TYPE_VIDEO_CODEC) {
+                    handleMediaResourceGranted(packageNames);
+                }
+            }
+
+        }
+    };
+
+    private PipManager() { }
+
+    /**
+     * Initializes {@link PipManager}.
+     */
+    public void initialize(Context context) {
+        if (mInitialized) {
+            return;
+        }
+        mInitialized = true;
+        mContext = context;
+        Resources res = context.getResources();
+        mPipBound = Rect.unflattenFromString(res.getString(
+                com.android.internal.R.string.config_defaultPictureInPictureBounds));
+        mMenuModePipBound = Rect.unflattenFromString(res.getString(
+                com.android.internal.R.string.config_centeredPictureInPictureBounds));
+
+        mActivityManager = ActivityManagerNative.getDefault();
+        TaskStackListener taskStackListener = new TaskStackListener();
+        IActivityManager iam = ActivityManagerNative.getDefault();
+        try {
+            iam.registerTaskStackListener(taskStackListener);
+        } catch (RemoteException e) {
+            Log.e(TAG, "registerTaskStackListener failed", e);
+        }
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_PICTURE_IN_PICTURE_BUTTON);
+        intentFilter.addAction(Intent.ACTION_MEDIA_RESOURCE_GRANTED);
+        mContext.registerReceiver(mBroadcastReceiver, intentFilter);
+    }
+
+    private void startPip() {
+        try {
+            mActivityManager.moveTopActivityToPinnedStack(FULLSCREEN_WORKSPACE_STACK_ID, mPipBound);
+        } catch (RemoteException|IllegalArgumentException e) {
+            Log.e(TAG, "moveTopActivityToPinnedStack failed", e);
+        }
+
+    }
+
+    /**
+     * Closes PIP (PIPped activity and PIP system UI).
+     */
+    public void closePip() {
+        mState = STATE_NO_PIP;
+        mPipTaskId = TASK_ID_NO_PIP;
+        StackInfo stackInfo = null;
+        try {
+            stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
+            if (stackInfo == null) {
+                return;
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "getStackInfo failed", e);
+            return;
+        }
+        for (int taskId : stackInfo.taskIds) {
+            try {
+                mActivityManager.removeTask(taskId);
+            } catch (RemoteException e) {
+                Log.e(TAG, "removeTask failed", e);
+            }
+        }
+    }
+
+    /**
+     * Moves the PIPped activity to the fullscreen and closes PIP system UI.
+     */
+    public void movePipToFullscreen() {
+        mState = STATE_NO_PIP;
+        mPipTaskId = TASK_ID_NO_PIP;
+        for (int i = mListeners.size() - 1; i >= 0; --i) {
+            mListeners.get(i).onMoveToFullscreen();
+        }
+        try {
+            mActivityManager.moveTasksToFullscreenStack(PINNED_STACK_ID, true);
+        } catch (RemoteException e) {
+            Log.e(TAG, "moveTasksToFullscreenStack failed", e);
+        }
+    }
+
+    /**
+     * Shows PIP overlay UI by launching {@link PipOverlayActivity}. It also locates the pinned
+     * stack to the default PIP bound {@link com.android.internal.R.string
+     * .config_defaultPictureInPictureBounds}.
+     */
+    public void showPipOverlay(boolean resizeStack) {
+        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);
+        if (resizeStack) {
+            options.setLaunchBounds(mPipBound);
+        }
+        mContext.startActivity(intent, options.toBundle());
+    }
+
+    /**
+     * 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}.
+     */
+    public void showPipMenu() {
+        if (DEBUG) Log.d(TAG, "showPipMenu()");
+        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);
+        options.setLaunchBounds(mMenuModePipBound);
+        mContext.startActivity(intent, options.toBundle());
+    }
+
+    /**
+     * Adds {@link Listener}.
+     */
+    public void addListener(Listener listener) {
+        mListeners.add(listener);
+    }
+
+    /**
+     * Removes {@link Listener}.
+     */
+    public void removeListener(Listener listener) {
+        mListeners.remove(listener);
+    }
+
+    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;
+        }
+    }
+
+    private void handleMediaResourceGranted(String[] packageNames) {
+        StackInfo fullscreenStack = null;
+        try {
+            fullscreenStack = mActivityManager.getStackInfo(FULLSCREEN_WORKSPACE_STACK_ID);
+        } catch (RemoteException e) {
+            Log.e(TAG, "getStackInfo failed", e);
+        }
+        if (fullscreenStack == null) {
+            return;
+        }
+        int fullscreenTopTaskId = fullscreenStack.taskIds[fullscreenStack.taskIds.length - 1];
+        List<RunningTaskInfo> tasks = null;
+        try {
+            tasks = mActivityManager.getTasks(MAX_RUNNING_TASKS_COUNT, 0);
+        } catch (RemoteException e) {
+            Log.e(TAG, "getTasks failed", e);
+        }
+        if (tasks == null) {
+            return;
+        }
+        boolean wasGrantedInFullscreen = false;
+        boolean wasGrantedInPip = false;
+        for (int i = tasks.size() - 1; i >= 0; --i) {
+            RunningTaskInfo task = tasks.get(i);
+            for (int j = packageNames.length - 1; j >= 0; --j) {
+                if (task.topActivity.getPackageName().equals(packageNames[j])) {
+                    if (task.id == fullscreenTopTaskId) {
+                        wasGrantedInFullscreen = true;
+                    } else if (task.id == mPipTaskId) {
+                        wasGrantedInPip= true;
+                    }
+                }
+            }
+        }
+        if (wasGrantedInFullscreen && !wasGrantedInPip) {
+            closePip();
+        }
+    }
+
+    private class TaskStackListener extends ITaskStackListener.Stub {
+        @Override
+        public void onTaskStackChanged() throws RemoteException {
+            // Post the message back to the UI thread.
+            mHandler.post(mOnTaskStackChanged);
+        }
+
+        @Override
+        public void onActivityPinned()  throws RemoteException {
+            // Post the message back to the UI thread.
+            mHandler.post(mOnActivityPinnedRunnable);
+        }
+
+        @Override
+        public void onPinnedActivityRestartAttempt() {
+            // Post the message back to the UI thread.
+            mHandler.post(mOnPinnedActivityRestartAttempt);
+        }
+    }
+
+    /**
+     * A listener interface to receive notification on changes in PIP.
+     */
+    public interface Listener {
+        /**
+         * Invoked when a PIPped activity is closed.
+         */
+        void onPipActivityClosed();
+        /**
+         * Invoked when the PIP menu gets shown.
+         */
+        void onShowPipMenu();
+        /**
+         * Invoked when the PIPped activity is returned back to the fullscreen.
+         */
+        void onMoveToFullscreen();
+    }
+
+    /**
+     * Gets an instance of {@link PipManager}.
+     */
+    public static PipManager getInstance() {
+        if (sPipManager == null) {
+            sPipManager = new PipManager();
+        }
+        return sPipManager;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
new file mode 100644
index 0000000..97c70ed
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.app.Activity;
+import android.media.session.MediaController;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+
+import com.android.systemui.R;
+
+/**
+ * Activity to show the PIP menu to control PIP.
+ */
+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;
+
+    @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.showPipOverlay(true);
+                finish();
+            }
+        });
+    }
+
+    @Override
+    protected void onDestroy() {
+        mPipManager.removeListener(this);
+        super.onDestroy();
+    }
+
+    @Override
+    public void onBackPressed() {
+        mPipManager.showPipOverlay(true);
+        finish();
+    }
+
+    @Override
+    public void onPipActivityClosed() {
+        finish();
+    }
+
+    @Override
+    public void onShowPipMenu() { }
+
+    @Override
+    public void onMoveToFullscreen() {
+        finish();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
new file mode 100644
index 0000000..de997a8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.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.tv.pip;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.view.View;
+
+import com.android.systemui.R;
+
+/**
+ * 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 = 2000;
+
+    private final PipManager mPipManager = PipManager.getInstance();
+    private final Handler mHandler = new Handler();
+
+    @Override
+    protected void onCreate(Bundle bundle) {
+        super.onCreate(bundle);
+        setContentView(R.layout.tv_pip_overlay);
+        mPipManager.addListener(this);
+        final View overlayView = findViewById(R.id.guide_overlay);
+        // TODO: apply animation
+        overlayView.setVisibility(View.VISIBLE);
+        mHandler.postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                overlayView.setVisibility(View.INVISIBLE);
+            }
+        }, SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mHandler.removeCallbacksAndMessages(null);
+        mPipManager.removeListener(this);
+    }
+
+    @Override
+    public void onPipActivityClosed() {
+        finish();
+    }
+
+    @Override
+    public void onShowPipMenu() {
+        finish();
+    }
+
+    @Override
+    public void onMoveToFullscreen() {
+        finish();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipUI.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipUI.java
new file mode 100644
index 0000000..182b9b0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipUI.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.systemui.tv.pip;
+
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+
+import com.android.systemui.SystemUI;
+
+import static android.content.pm.PackageManager.FEATURE_LEANBACK;
+import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
+
+/**
+ * Controls the picture-in-picture window for TV devices.
+ */
+public class PipUI extends SystemUI {
+    private boolean mSupportPip;
+
+    @Override
+    public void start() {
+        PackageManager pm = mContext.getPackageManager();
+        mSupportPip = pm.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)
+                && pm.hasSystemFeature(FEATURE_LEANBACK);
+        if (!mSupportPip) {
+            return;
+        }
+        PipManager pipManager = PipManager.getInstance();
+        pipManager.initialize(mContext);
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        if (!mSupportPip) {
+            return;
+        }
+        // TODO: handle configuration change.
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java
index 893c939..8e0f9b8 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/Events.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java
@@ -23,6 +23,7 @@
 import android.util.Log;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.volume.VolumeDialogController.State;
 
 import java.util.Arrays;
@@ -111,33 +112,33 @@
             sb.append(" ");
             switch (tag) {
                 case EVENT_SHOW_DIALOG:
-                    MetricsLogger.visible(context, MetricsLogger.VOLUME_DIALOG);
+                    MetricsLogger.visible(context, MetricsEvent.VOLUME_DIALOG);
                     MetricsLogger.histogram(context, "volume_from_keyguard",
                             (Boolean) list[1] ? 1 : 0);
                     sb.append(SHOW_REASONS[(Integer) list[0]]).append(" keyguard=").append(list[1]);
                     break;
                 case EVENT_EXPAND:
-                    MetricsLogger.visibility(context, MetricsLogger.VOLUME_DIALOG_DETAILS,
+                    MetricsLogger.visibility(context, MetricsEvent.VOLUME_DIALOG_DETAILS,
                             (Boolean) list[0]);
                     sb.append(list[0]);
                     break;
                 case EVENT_DISMISS_DIALOG:
-                    MetricsLogger.hidden(context, MetricsLogger.VOLUME_DIALOG);
+                    MetricsLogger.hidden(context, MetricsEvent.VOLUME_DIALOG);
                     sb.append(DISMISS_REASONS[(Integer) list[0]]);
                     break;
                 case EVENT_ACTIVE_STREAM_CHANGED:
-                    MetricsLogger.action(context, MetricsLogger.ACTION_VOLUME_STREAM,
+                    MetricsLogger.action(context, MetricsEvent.ACTION_VOLUME_STREAM,
                             (Integer) list[0]);
                     sb.append(AudioSystem.streamToString((Integer) list[0]));
                     break;
                 case EVENT_ICON_CLICK:
-                    MetricsLogger.action(context, MetricsLogger.ACTION_VOLUME_ICON,
+                    MetricsLogger.action(context, MetricsEvent.ACTION_VOLUME_ICON,
                             (Integer) list[1]);
                     sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ')
                             .append(iconStateToString((Integer) list[1]));
                     break;
                 case EVENT_TOUCH_LEVEL_DONE:
-                    MetricsLogger.action(context, MetricsLogger.ACTION_VOLUME_SLIDER,
+                    MetricsLogger.action(context, MetricsEvent.ACTION_VOLUME_SLIDER,
                             (Integer) list[1]);
                     // fall through
                 case EVENT_TOUCH_LEVEL_CHANGED:
@@ -147,13 +148,13 @@
                             .append(list[1]);
                     break;
                 case EVENT_KEY:
-                    MetricsLogger.action(context, MetricsLogger.ACTION_VOLUME_KEY,
+                    MetricsLogger.action(context, MetricsEvent.ACTION_VOLUME_KEY,
                             (Integer) list[1]);
                     sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ')
                             .append(list[1]);
                     break;
                 case EVENT_EXTERNAL_RINGER_MODE_CHANGED:
-                    MetricsLogger.action(context, MetricsLogger.ACTION_RINGER_MODE,
+                    MetricsLogger.action(context, MetricsEvent.ACTION_RINGER_MODE,
                             (Integer) list[0]);
                     // fall through
                 case EVENT_INTERNAL_RINGER_MODE_CHANGED:
diff --git a/packages/SystemUI/src/com/android/systemui/volume/IconPulser.java b/packages/SystemUI/src/com/android/systemui/volume/IconPulser.java
deleted file mode 100644
index 9438af1..0000000
--- a/packages/SystemUI/src/com/android/systemui/volume/IconPulser.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.volume;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.content.Context;
-import android.view.View;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-
-public class IconPulser {
-    private static final float PULSE_SCALE = 1.1f;
-
-    private final Interpolator mFastOutSlowInInterpolator;
-
-    public IconPulser(Context context) {
-        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
-                android.R.interpolator.fast_out_slow_in);
-    }
-
-    public void start(final View target) {
-        if (target == null || target.getScaleX() != 1) return;  // n/a, or already running
-        target.animate().cancel();
-        target.animate().scaleX(PULSE_SCALE).scaleY(PULSE_SCALE)
-                .setInterpolator(mFastOutSlowInInterpolator)
-                .setListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        target.animate().scaleX(1).scaleY(1).setListener(null);
-                    }
-                });
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 9d4ec10..5dc468b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -21,12 +21,12 @@
 
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.animation.LayoutTransition;
-import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.annotation.SuppressLint;
 import android.app.Dialog;
 import android.app.KeyguardManager;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.graphics.Color;
@@ -61,7 +61,6 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
-import android.view.animation.DecelerateInterpolator;
 import android.widget.ImageButton;
 import android.widget.LinearLayout;
 import android.widget.SeekBar;
@@ -70,6 +69,7 @@
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.tuner.TunerService;
 import com.android.systemui.volume.VolumeDialogController.State;
 import com.android.systemui.volume.VolumeDialogController.StreamState;
 
@@ -84,9 +84,11 @@
  *
  * Methods ending in "H" must be called on the (ui) handler.
  */
-public class VolumeDialog {
+public class VolumeDialog implements TunerService.Tunable {
     private static final String TAG = Util.logTag(VolumeDialog.class);
 
+    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;
 
@@ -130,6 +132,9 @@
     private boolean mHovering = false;
     private int mLastActiveStream;
 
+    private boolean mShowFullZen;
+    private final ZenModePanel mZenPanel;
+
     public VolumeDialog(Context context, int windowType, VolumeDialogController controller,
             ZenModeController zenModeController, Callback callback) {
         mContext = context;
@@ -220,11 +225,23 @@
         mExpandButtonAnimationDuration = res.getInteger(R.integer.volume_expand_animation_duration);
         mZenFooter = (ZenFooter) mDialog.findViewById(R.id.volume_zen_footer);
         mZenFooter.init(zenModeController);
+        mZenPanel = (ZenModePanel) mDialog.findViewById(R.id.zen_mode_panel);
+        mZenPanel.addNoneButton();
+        mZenPanel.init(zenModeController);
+        mZenPanel.setCallback(mZenPanelCallback);
 
         mAccessibility.init();
 
         controller.addCallback(mControllerCallbackH, mHandler);
         controller.getState();
+        TunerService.get(mContext).addTunable(this, SHOW_FULL_ZEN);
+    }
+
+    @Override
+    public void onTuningChanged(String key, String newValue) {
+        if (SHOW_FULL_ZEN.equals(key)) {
+            mShowFullZen = newValue != null && Integer.parseInt(newValue) != 0;
+        }
     }
 
     private ColorStateList loadColorStateList(int colorResId) {
@@ -237,11 +254,10 @@
         if (D.BUG) Log.d(TAG, "updateWindowWidth dm.w=" + dm.widthPixels);
         int w = dm.widthPixels;
         final int max = mContext.getResources()
-                .getDimensionPixelSize(R.dimen.standard_notification_panel_width);
+                .getDimensionPixelSize(R.dimen.volume_dialog_panel_width);
         if (w > max) {
             w = max;
         }
-        w -= mContext.getResources().getDimensionPixelSize(R.dimen.notification_side_padding) * 2;
         lp.width = w;
         mDialogView.setLayoutParams(lp);
     }
@@ -277,7 +293,7 @@
                     .getDimensionPixelSize(R.dimen.volume_slider_interspacing);
             final LinearLayout.LayoutParams lp =
                     new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, h);
-            mDialogContentView.addView(v, mDialogContentView.getChildCount() - 1, lp);
+            mDialogContentView.addView(v, mDialogContentView.getChildCount() - 2, lp);
             row.space = v;
         }
         row.settingsButton.addOnLayoutChangeListener(new OnLayoutChangeListener() {
@@ -305,7 +321,7 @@
             }
         });
         // add new row just before the footer
-        mDialogContentView.addView(row.view, mDialogContentView.getChildCount() - 1);
+        mDialogContentView.addView(row.view, mDialogContentView.getChildCount() - 2);
         mRows.add(row);
     }
 
@@ -559,7 +575,13 @@
                 : R.drawable.ic_volume_expand_animation;
         if (res == mExpandButtonRes) return;
         mExpandButtonRes = res;
-        mExpandButton.setImageResource(res);
+        if (hasTouchFeature()) {
+            mExpandButton.setImageResource(res);
+        } else {
+            // if there is no touch feature, show the volume ringer instead
+            mExpandButton.setImageResource(R.drawable.ic_volume_ringer);
+            mExpandButton.setBackgroundResource(0);  // remove gray background emphasis
+        }
         mExpandButton.setContentDescription(mContext.getString(mExpanded ?
                 R.string.accessibility_volume_collapse : R.string.accessibility_volume_expand));
     }
@@ -648,12 +670,21 @@
         if (D.BUG) Log.d(TAG, "updateFooterH");
         final boolean wasVisible = mZenFooter.getVisibility() == View.VISIBLE;
         final boolean visible = mState.zenMode != Global.ZEN_MODE_OFF
-                && mAudioManager.isStreamAffectedByRingerMode(mActiveStream);
+                && (mAudioManager.isStreamAffectedByRingerMode(mActiveStream) || mExpanded)
+                && !mShowFullZen;
         if (wasVisible != visible && !visible) {
             prepareForCollapse();
         }
         Util.setVisOrGone(mZenFooter, visible);
         mZenFooter.update();
+
+        final boolean fullWasVisible = mZenPanel.getVisibility() == View.VISIBLE;
+        final boolean fullVisible = mShowFullZen && (mState.zenMode != Global.ZEN_MODE_OFF
+                || mExpanded);
+        if (fullWasVisible != fullVisible && !fullVisible) {
+            prepareForCollapse();
+        }
+        Util.setVisOrGone(mZenPanel, fullVisible);
     }
 
     private void updateVolumeRowH(VolumeRow row) {
@@ -837,6 +868,11 @@
         rescheduleTimeoutH();
     }
 
+    private boolean hasTouchFeature() {
+        final PackageManager pm = mContext.getPackageManager();
+        return pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);
+    }
+
     private final VolumeDialogController.Callbacks mControllerCallbackH
             = new VolumeDialogController.Callbacks() {
         @Override
@@ -891,6 +927,23 @@
         }
     };
 
+    private final ZenModePanel.Callback mZenPanelCallback = new ZenModePanel.Callback() {
+        @Override
+        public void onPrioritySettings() {
+            mCallback.onZenPrioritySettingsClicked();
+        }
+
+        @Override
+        public void onInteraction() {
+            mHandler.sendEmptyMessage(H.RESCHEDULE_TIMEOUT);
+        }
+
+        @Override
+        public void onExpanded(boolean expanded) {
+            // noop.
+        }
+    };
+
     private final OnClickListener mClickExpand = new OnClickListener() {
         @Override
         public void onClick(View v) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index 1083f40..d7635ad 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -31,6 +31,7 @@
 import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.tuner.TunerService;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -38,16 +39,25 @@
 /**
  * Implementation of VolumeComponent backed by the new volume dialog.
  */
-public class VolumeDialogComponent implements VolumeComponent {
+public class VolumeDialogComponent implements VolumeComponent, TunerService.Tunable {
+
+    public static final String VOLUME_DOWN_SILENT = "sysui_volume_down_silent";
+    public static final String VOLUME_UP_SILENT = "sysui_volume_up_silent";
+    public static final String VOLUME_SILENT_DO_NOT_DISTURB = "sysui_do_not_disturb";
+
+    public static final boolean DEFAULT_VOLUME_DOWN_TO_ENTER_SILENT = true;
+    public static final boolean DEFAULT_VOLUME_UP_TO_EXIT_SILENT = true;
+    public static final boolean DEFAULT_DO_NOT_DISTURB_WHEN_SILENT = true;
+
     private final SystemUI mSysui;
     private final Context mContext;
     private final VolumeDialogController mController;
     private final ZenModeController mZenModeController;
     private final VolumeDialog mDialog;
-    private final VolumePolicy mVolumePolicy = new VolumePolicy(
-            true,  // volumeDownToEnterSilent
-            true,  // volumeUpToExitSilent
-            true,  // doNotDisturbWhenSilent
+    private VolumePolicy mVolumePolicy = new VolumePolicy(
+            DEFAULT_VOLUME_DOWN_TO_ENTER_SILENT,  // volumeDownToEnterSilent
+            DEFAULT_VOLUME_UP_TO_EXIT_SILENT,  // volumeUpToExitSilent
+            DEFAULT_DO_NOT_DISTURB_WHEN_SILENT,  // doNotDisturbWhenSilent
             400    // vibrateToSilentDebounce
     );
 
@@ -65,6 +75,41 @@
         mDialog = new VolumeDialog(context, WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY,
                 mController, zen, mVolumeDialogCallback);
         applyConfiguration();
+        TunerService.get(mContext).addTunable(this, VOLUME_DOWN_SILENT, VOLUME_UP_SILENT,
+                VOLUME_SILENT_DO_NOT_DISTURB);
+    }
+
+    @Override
+    public void onTuningChanged(String key, String newValue) {
+        if (VOLUME_DOWN_SILENT.equals(key)) {
+            final boolean volumeDownToEnterSilent = newValue != null
+                    ? Integer.parseInt(newValue) != 0
+                    : DEFAULT_VOLUME_DOWN_TO_ENTER_SILENT;
+            setVolumePolicy(volumeDownToEnterSilent,
+                    mVolumePolicy.volumeUpToExitSilent, mVolumePolicy.doNotDisturbWhenSilent,
+                    mVolumePolicy.vibrateToSilentDebounce);
+        } else if (VOLUME_UP_SILENT.equals(key)) {
+            final boolean volumeUpToExitSilent = newValue != null
+                    ? Integer.parseInt(newValue) != 0
+                    : DEFAULT_VOLUME_UP_TO_EXIT_SILENT;
+            setVolumePolicy(mVolumePolicy.volumeDownToEnterSilent,
+                    volumeUpToExitSilent, mVolumePolicy.doNotDisturbWhenSilent,
+                    mVolumePolicy.vibrateToSilentDebounce);
+        } else if (VOLUME_SILENT_DO_NOT_DISTURB.equals(key)) {
+            final boolean doNotDisturbWhenSilent = newValue != null
+                    ? Integer.parseInt(newValue) != 0
+                    : DEFAULT_DO_NOT_DISTURB_WHEN_SILENT;
+            setVolumePolicy(mVolumePolicy.volumeDownToEnterSilent,
+                    mVolumePolicy.volumeUpToExitSilent, doNotDisturbWhenSilent,
+                    mVolumePolicy.vibrateToSilentDebounce);
+        }
+    }
+
+    private void setVolumePolicy(boolean volumeDownToEnterSilent, boolean volumeUpToExitSilent,
+            boolean doNotDisturbWhenSilent, int vibrateToSilentDebounce) {
+        mVolumePolicy = new VolumePolicy(volumeDownToEnterSilent, volumeUpToExitSilent,
+                doNotDisturbWhenSilent, vibrateToSilentDebounce);
+        mController.setVolumePolicy(mVolumePolicy);
     }
 
     private void sendUserActivity() {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index cd47ac1..e9594a3 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -51,6 +51,7 @@
 import android.widget.TextView;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.policy.ZenModeController;
@@ -189,6 +190,12 @@
         mZenAlarmWarning = (TextView) findViewById(R.id.zen_alarm_warning);
     }
 
+    public void addNoneButton() {
+        mZenButtons.addButton(R.string.interruption_level_all_twoline,
+                R.string.interruption_level_all,
+                Global.ZEN_MODE_OFF);
+    }
+
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
@@ -494,6 +501,7 @@
         if (mExpanded && isShown()) {
             ensureSelection();
         }
+        mZenConditions.setVisibility(mSessionZen != Global.ZEN_MODE_OFF ? View.VISIBLE : View.GONE);
     }
 
     private Condition forever() {
@@ -510,7 +518,7 @@
         GregorianCalendar weekRange = new GregorianCalendar();
         final long now = weekRange.getTimeInMillis();
         setToMidnight(weekRange);
-        weekRange.roll(Calendar.DATE, 6);
+        weekRange.add(Calendar.DATE, 6);
         final long nextAlarmMs = mController.getNextAlarm();
         if (nextAlarmMs > 0) {
             GregorianCalendar nextAlarm = new GregorianCalendar();
@@ -613,7 +621,7 @@
                         if (childTag == null || childTag == tag) continue;
                         childTag.rb.setChecked(false);
                     }
-                    MetricsLogger.action(mContext, MetricsLogger.QS_DND_CONDITION_SELECT);
+                    MetricsLogger.action(mContext, MetricsEvent.QS_DND_CONDITION_SELECT);
                     select(tag.condition);
                     announceConditionSelection(tag);
                 }
@@ -718,7 +726,7 @@
     }
 
     private void onClickTimeButton(View row, ConditionTag tag, boolean up, int rowId) {
-        MetricsLogger.action(mContext, MetricsLogger.QS_DND_TIME, up);
+        MetricsLogger.action(mContext, MetricsEvent.QS_DND_TIME, up);
         Condition newCondition = null;
         final int N = MINUTE_BUCKETS.length;
         if (mBucketIndex == -1) {
@@ -921,7 +929,7 @@
             if (value != null && mZenButtons.isShown() && isAttachedToWindow()) {
                 final int zen = (Integer) value;
                 if (fromClick) {
-                    MetricsLogger.action(mContext, MetricsLogger.QS_DND_ZEN_SELECT, zen);
+                    MetricsLogger.action(mContext, MetricsEvent.QS_DND_ZEN_SELECT, zen);
                 }
                 if (DEBUG) Log.d(mTag, "mZenButtonsCallback selected=" + zen);
                 final Uri realConditionId = getRealConditionId(mSessionExitCondition);
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 9cf64d3..964688b 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -17,11 +17,15 @@
 
 LOCAL_MODULE_TAGS := tests
 
+LOCAL_JACK_FLAGS := --multi-dex native
+
 LOCAL_PROTOC_OPTIMIZE_TYPE := nano
 LOCAL_PROTOC_FLAGS := -I$(LOCAL_PATH)/..
 LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
 
-LOCAL_AAPT_FLAGS := --auto-add-overlay --extra-packages com.android.systemui:com.android.keyguard
+LOCAL_AAPT_FLAGS := --auto-add-overlay \
+    --extra-packages com.android.systemui:com.android.keyguard:android.support.v14.preference:android.support.v7.preference:android.support.v7.appcompat:android.support.v7.recyclerview \
+    --extra-packages android.support.v17.leanback
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
     $(call all-Iaidl-files-under, src) \
@@ -30,6 +34,11 @@
     src/com/android/systemui/EventLogTags.logtags
 
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \
+    frameworks/support/v7/preference/res \
+    frameworks/support/v14/preference/res \
+    frameworks/support/v7/appcompat/res \
+    frameworks/support/v7/recyclerview/res \
+    frameworks/support/v17/leanback/res \
     frameworks/base/packages/SystemUI/res \
     frameworks/base/packages/Keyguard/res
 
@@ -40,7 +49,11 @@
 LOCAL_STATIC_JAVA_LIBRARIES := \
     mockito-target \
     Keyguard \
-    android-support-v7-recyclerview
+    android-support-v7-recyclerview \
+    android-support-v7-preference \
+    android-support-v7-appcompat \
+    android-support-v14-preference \
+    android-support-v17-leanback
 
 # 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 c21af24..2825601 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -19,10 +19,16 @@
 
     <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.MANAGE_USERS" />
 
     <application>
         <uses-library android:name="android.test.runner" />
         <activity android:name="com.android.systemui.screenshot.ScreenshotStubActivity" />
+
+        <service
+            android:name="com.android.systemui.qs.external.TileLifecycleManagerTests$FakeTileService"
+            android:process=":killable" />
     </application>
 
     <instrumentation android:name="android.test.InstrumentationTestRunner"
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
new file mode 100644
index 0000000..f86c6a4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.qs.external;
+
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.quicksettings.IQSService;
+import android.service.quicksettings.IQSTileService;
+import android.service.quicksettings.Tile;
+import android.test.AndroidTestCase;
+import android.util.ArraySet;
+import android.util.Log;
+
+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";
+
+    private HandlerThread mThread;
+    private Handler mHandler;
+    private TileLifecycleManager mStateManager;
+    private final Object mBroadcastLock = new Object();
+    private final ArraySet<String> mCallbacks = new ArraySet<>();
+    private boolean mBound;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mThread = new HandlerThread("TestThread");
+        mThread.start();
+        mHandler = new Handler(mThread.getLooper());
+        mStateManager = new TileLifecycleManager(mHandler, getContext(),
+                new Intent(mContext, FakeTileService.class), new UserHandle(UserHandle.myUserId()));
+        mCallbacks.clear();
+        getContext().registerReceiver(mReceiver, new IntentFilter(TILE_UPDATE_BROADCAST));
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        if (mBound) {
+            unbindService();
+        }
+        mThread.quit();
+        getContext().unregisterReceiver(mReceiver);
+    }
+
+    public void testSync() {
+        syncWithHandler();
+    }
+
+    public void testBind() {
+        bindService();
+        waitForCallback("onCreate");
+    }
+
+    public void testUnbind() {
+        bindService();
+        waitForCallback("onCreate");
+        unbindService();
+        waitForCallback("onDestroy");
+    }
+
+    public void testTileServiceCallbacks() {
+        bindService();
+        waitForCallback("onCreate");
+
+        mStateManager.onTileAdded();
+        waitForCallback("onTileAdded");
+        mStateManager.onStartListening();
+        waitForCallback("onStartListening");
+        mStateManager.onClick(null);
+        waitForCallback("onClick");
+        mStateManager.onStopListening();
+        waitForCallback("onStopListening");
+        mStateManager.onTileRemoved();
+        waitForCallback("onTileRemoved");
+
+        unbindService();
+    }
+
+    public void testAddedBeforeBind() {
+        mStateManager.onTileAdded();
+
+        bindService();
+        waitForCallback("onCreate");
+        waitForCallback("onTileAdded");
+    }
+
+    public void testListeningBeforeBind() {
+        mStateManager.onTileAdded();
+        mStateManager.onStartListening();
+
+        bindService();
+        waitForCallback("onCreate");
+        waitForCallback("onTileAdded");
+        waitForCallback("onStartListening");
+    }
+
+    public void testClickBeforeBind() {
+        mStateManager.onTileAdded();
+        mStateManager.onStartListening();
+        mStateManager.onClick(null);
+
+        bindService();
+        waitForCallback("onCreate");
+        waitForCallback("onTileAdded");
+        waitForCallback("onStartListening");
+        waitForCallback("onClick");
+    }
+
+    public void testListeningNotListeningBeforeBind() {
+        mStateManager.onTileAdded();
+        mStateManager.onStartListening();
+        mStateManager.onStopListening();
+
+        bindService();
+        waitForCallback("onCreate");
+        unbindService();
+        waitForCallback("onDestroy");
+        assertFalse(mCallbacks.contains("onStartListening"));
+    }
+
+    public void testNoClickOfNotListeningAnymore() {
+        mStateManager.onTileAdded();
+        mStateManager.onStartListening();
+        mStateManager.onClick(null);
+        mStateManager.onStopListening();
+
+        bindService();
+        waitForCallback("onCreate");
+        unbindService();
+        waitForCallback("onDestroy");
+        assertFalse(mCallbacks.contains("onClick"));
+    }
+
+    public void testComponentEnabling() {
+        mStateManager.onTileAdded();
+        mStateManager.onStartListening();
+
+        PackageManager pm = getContext().getPackageManager();
+        pm.setComponentEnabledSetting(new ComponentName(getContext(), FakeTileService.class),
+                PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
+
+        bindService();
+        assertTrue(mStateManager.mReceiverRegistered);
+
+        pm.setComponentEnabledSetting(new ComponentName(getContext(), FakeTileService.class),
+                PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
+        waitForCallback("onCreate");
+    }
+
+    public void testKillProcess() {
+        mStateManager.onStartListening();
+        bindService();
+        waitForCallback("onCreate");
+        waitForCallback("onStartListening");
+
+        getContext().sendBroadcast(new Intent(FakeTileService.ACTION_KILL));
+
+        waitForCallback("onCreate");
+        waitForCallback("onStartListening");
+    }
+
+    private void bindService() {
+        mBound = true;
+        mStateManager.setBindService(true);
+    }
+
+    private void unbindService() {
+        mBound = false;
+        mStateManager.setBindService(false);
+    }
+
+    private void waitForCallback(String callback) {
+        for (int i = 0; i < 25; i++) {
+            if (mCallbacks.contains(callback)) {
+                mCallbacks.remove(callback);
+                return;
+            }
+            synchronized (mBroadcastLock) {
+                try {
+                    mBroadcastLock.wait(500);
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+        if (mCallbacks.contains(callback)) {
+            mCallbacks.remove(callback);
+            return;
+        }
+        fail("Didn't receive callback: " + callback);
+    }
+
+    private void syncWithHandler() {
+        final Object lock = new Object();
+        synchronized (lock) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    synchronized (lock) {
+                        lock.notify();
+                    }
+                }
+            });
+            try {
+                lock.wait(5000);
+            } catch (InterruptedException e) {
+            }
+        }
+    }
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mCallbacks.add(intent.getStringExtra(EXTRA_CALLBACK));
+            synchronized (mBroadcastLock) {
+                mBroadcastLock.notify();
+            }
+        }
+    };
+
+    public static class FakeTileService extends Service {
+        public static final String ACTION_KILL = "com.android.systemui.test.KILL";
+
+        @Override
+        public IBinder onBind(Intent intent) {
+            return new IQSTileService.Stub() {
+
+                @Override
+                public void setQSService(IQSService service) {
+
+                }
+
+                @Override
+                public void setQSTile(Tile tile) throws RemoteException {
+                }
+
+                @Override
+                public void onTileAdded() throws RemoteException {
+                    sendCallback("onTileAdded");
+                }
+
+                @Override
+                public void onTileRemoved() throws RemoteException {
+                    sendCallback("onTileRemoved");
+                }
+
+                @Override
+                public void onStartListening() throws RemoteException {
+                    sendCallback("onStartListening");
+                }
+
+                @Override
+                public void onStopListening() throws RemoteException {
+                    sendCallback("onStopListening");
+                }
+
+                @Override
+                public void onClick(IBinder iBinder) throws RemoteException {
+                    sendCallback("onClick");
+                }
+
+                @Override
+                public void onUnlockComplete() throws RemoteException {
+                    sendCallback("onUnlockComplete");
+                }
+            };
+        }
+
+        @Override
+        public void onCreate() {
+            super.onCreate();
+            registerReceiver(mReceiver, new IntentFilter(ACTION_KILL));
+            sendCallback("onCreate");
+        }
+
+        @Override
+        public void onDestroy() {
+            super.onDestroy();
+            unregisterReceiver(mReceiver);
+            sendCallback("onDestroy");
+        }
+
+        private void sendCallback(String callback) {
+            Log.d("TileLifecycleManager", "Relaying: " + callback);
+            sendBroadcast(new Intent(TILE_UPDATE_BROADCAST)
+                    .putExtra(EXTRA_CALLBACK, callback));
+        }
+
+        private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (ACTION_KILL.equals(intent.getAction())) {
+                    Process.killProcess(Process.myPid());
+                }
+            }
+        };
+    }
+}
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
new file mode 100644
index 0000000..4586c28
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.external;
+
+import android.content.ComponentName;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.service.quicksettings.TileService;
+import com.android.systemui.SysuiTestCase;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+public class TileServiceManagerTests extends SysuiTestCase {
+
+    private TileServices mTileServices;
+    private TileLifecycleManager mTileLifecycle;
+    private HandlerThread mThread;
+    private Handler mHandler;
+    private TileServiceManager mTileServiceManager;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mThread = new HandlerThread("TestThread");
+        mThread.start();
+        mHandler = new Handler(mThread.getLooper());
+        mTileServices = Mockito.mock(TileServices.class);
+        Mockito.when(mTileServices.getContext()).thenReturn(mContext);
+        mTileLifecycle = Mockito.mock(TileLifecycleManager.class);
+        ComponentName componentName = new ComponentName(mContext,
+                TileServiceManagerTests.class);
+        Mockito.when(mTileLifecycle.getComponent()).thenReturn(componentName);
+        mContext.getSharedPreferences(TileServiceManager.PREFS_FILE, 0).edit()
+                .putInt(componentName.flattenToString(), TileService.TILE_MODE_PASSIVE).commit();
+        mTileServiceManager = new TileServiceManager(mTileServices, mHandler, mTileLifecycle);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        mThread.quit();
+    }
+
+    public void testSetBindRequested() {
+        // Request binding.
+        mTileServiceManager.setBindRequested(true);
+        mTileServiceManager.setLastUpdate(0);
+        mTileServiceManager.calculateBindPriority(5);
+        Mockito.verify(mTileServices, Mockito.times(2)).recalculateBindAllowance();
+        assertEquals(5, mTileServiceManager.getBindPriority());
+
+        // Verify same state doesn't trigger recalculating for no reason.
+        mTileServiceManager.setBindRequested(true);
+        Mockito.verify(mTileServices, Mockito.times(2)).recalculateBindAllowance();
+
+        mTileServiceManager.setBindRequested(false);
+        mTileServiceManager.calculateBindPriority(5);
+        Mockito.verify(mTileServices, Mockito.times(3)).recalculateBindAllowance();
+        assertEquals(Integer.MIN_VALUE, mTileServiceManager.getBindPriority());
+    }
+
+    public void testPendingClickPriority() {
+        Mockito.when(mTileLifecycle.hasPendingClick()).thenReturn(true);
+        mTileServiceManager.calculateBindPriority(0);
+        assertEquals(Integer.MAX_VALUE, mTileServiceManager.getBindPriority());
+    }
+
+    public void testBind() {
+        // Trigger binding requested and allowed.
+        mTileServiceManager.setBindRequested(true);
+        mTileServiceManager.setBindAllowed(true);
+
+        ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+        Mockito.verify(mTileLifecycle, Mockito.times(1)).setBindService(captor.capture());
+        assertTrue((boolean) captor.getValue());
+
+        mTileServiceManager.setBindRequested(false);
+        mTileServiceManager.calculateBindPriority(0);
+        // Priority shouldn't disappear after the request goes away if we just bound, instead
+        // it sticks around to avoid thrashing a bunch of processes.
+        assertEquals(Integer.MAX_VALUE - 1, mTileServiceManager.getBindPriority());
+
+        mTileServiceManager.setBindAllowed(false);
+        captor = ArgumentCaptor.forClass(Boolean.class);
+        Mockito.verify(mTileLifecycle, Mockito.times(2)).setBindService(captor.capture());
+        assertFalse((boolean) captor.getValue());
+    }
+}
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
new file mode 100644
index 0000000..c4ca039
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.qs.external;
+
+import android.content.ComponentName;
+import android.os.Looper;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.QSTileHost;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+
+public class TileServicesTests extends SysuiTestCase {
+    private static int NUM_FAKES = TileServices.DEFAULT_MAX_BOUND * 2;
+
+    private TileServices mTileService;
+    private ArrayList<TileServiceManager> mManagers;
+
+    @Override
+    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);
+        mTileService = new TestTileServices(host, Looper.myLooper());
+    }
+
+    public void testRecalculateBindAllowance() {
+        // Add some fake tiles.
+        for (int i = 0; i < NUM_FAKES; i++) {
+            mTileService.getTileWrapper(Mockito.mock(CustomTile.class));
+        }
+        assertEquals(NUM_FAKES, mManagers.size());
+
+        for (int i = 0; i < NUM_FAKES; i++) {
+            Mockito.when(mManagers.get(i).getBindPriority()).thenReturn(i);
+        }
+        mTileService.recalculateBindAllowance();
+        for (int i = 0; i < NUM_FAKES; i++) {
+            Mockito.verify(mManagers.get(i), Mockito.times(1)).calculateBindPriority(
+                    Mockito.anyLong());
+            ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+            Mockito.verify(mManagers.get(i), Mockito.times(1)).setBindAllowed(captor.capture());
+
+            assertEquals("" + i + "th service", i >= (NUM_FAKES - TileServices.DEFAULT_MAX_BOUND),
+                    (boolean) captor.getValue());
+        }
+    }
+
+    public void testSetMemoryPressure() {
+        testRecalculateBindAllowance();
+        mTileService.setMemoryPressure(true);
+
+        for (int i = 0; i < NUM_FAKES; i++) {
+            ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+            Mockito.verify(mManagers.get(i), Mockito.times(2)).setBindAllowed(captor.capture());
+
+            assertEquals("" + i + "th service", i >= (NUM_FAKES - TileServices.REDUCED_MAX_BOUND),
+                    (boolean) captor.getValue());
+        }
+    }
+
+    public void testCalcFew() {
+        for (int i = 0; i < TileServices.DEFAULT_MAX_BOUND - 1; i++) {
+            mTileService.getTileWrapper(Mockito.mock(CustomTile.class));
+        }
+        mTileService.recalculateBindAllowance();
+
+        for (int i = 0; i < TileServices.DEFAULT_MAX_BOUND - 1; i++) {
+            // Shouldn't get bind prioirities calculated when there are less than the max services.
+            Mockito.verify(mManagers.get(i), Mockito.never()).calculateBindPriority(
+                    Mockito.anyLong());
+
+            // All should be bound since there are less than the max services.
+            ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+            Mockito.verify(mManagers.get(i), Mockito.times(1)).setBindAllowed(captor.capture());
+
+            assertTrue(captor.getValue());
+        }
+    }
+
+    private class TestTileServices extends TileServices {
+        public TestTileServices(QSTileHost host, Looper looper) {
+            super(host, looper);
+        }
+
+        @Override
+        protected TileServiceManager onCreateTileService(ComponentName component) {
+            TileServiceManager manager = Mockito.mock(TileServiceManager.class);
+            mManagers.add(manager);
+            return manager;
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java
deleted file mode 100644
index f51e8ff..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java
+++ /dev/null
@@ -1,431 +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.phone;
-
-import org.mockito.InOrder;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.ActivityInfo;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.UserInfo;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.test.AndroidTestCase;
-
-import java.util.Arrays;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.HashMap;
-import java.util.Map;
-
-/** Tests for the data model for the navigation bar app icons. */
-public class NavigationBarAppsModelTest extends AndroidTestCase {
-    private PackageManager mMockPackageManager;
-    private IPackageManager mMockIPackageManager;
-    private SharedPreferences mMockPrefs;
-    private SharedPreferences.Editor mMockEdit;
-    private UserManager mMockUserManager;
-
-    private NavigationBarAppsModel mModel;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        // Mockito setup boilerplate.
-        System.setProperty("dexmaker.dexcache", mContext.getCacheDir().getPath());
-        Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
-
-        final Context context = mock(Context.class);
-        mMockPackageManager = mock(PackageManager.class);
-        mMockIPackageManager = mock(IPackageManager.class);
-        mMockPrefs = mock(SharedPreferences.class);
-        mMockEdit = mock(SharedPreferences.Editor.class);
-        mMockUserManager = mock(UserManager.class);
-
-        when(context.getSharedPreferences(
-                "com.android.systemui.navbarapps", Context.MODE_PRIVATE)).thenReturn(mMockPrefs);
-        when(context.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager);
-        when(context.getPackageManager()).thenReturn(mMockPackageManager);
-
-        setContext(context);
-
-        when(mMockUserManager.getUsers()).thenReturn(new ArrayList<UserInfo>());
-        // Assume the version pref is present and equal to the current version.
-        when(mMockPrefs.getInt("version", -1)).thenReturn(3);
-        when(mMockPrefs.edit()).thenReturn(mMockEdit);
-
-        when(mMockUserManager.getSerialNumberForUser(new UserHandle(2))).thenReturn(222L);
-        when(mMockUserManager.getSerialNumberForUser(new UserHandle(4))).thenReturn(444L);
-        when(mMockUserManager.getSerialNumberForUser(new UserHandle(5))).thenReturn(555L);
-        when(mMockUserManager.getUserForSerialNumber(222L)).thenReturn(new UserHandle(2));
-        when(mMockUserManager.getUserForSerialNumber(444L)).thenReturn(new UserHandle(4));
-        when(mMockUserManager.getUserForSerialNumber(555L)).thenReturn(new UserHandle(5));
-
-        UserInfo ui2 = new UserInfo();
-        ui2.profileGroupId = 999;
-        UserInfo ui4 = new UserInfo();
-        ui4.profileGroupId = 999;
-        UserInfo ui5 = new UserInfo();
-        ui5.profileGroupId = 999;
-        when(mMockUserManager.getUserInfo(2)).thenReturn(ui2);
-        when(mMockUserManager.getUserInfo(4)).thenReturn(ui4);
-        when(mMockUserManager.getUserInfo(5)).thenReturn(ui5);
-
-        mModel = new NavigationBarAppsModel(context) {
-            @Override
-            protected IPackageManager getPackageManager() {
-                return mMockIPackageManager;
-            }
-        };
-    }
-
-    /** Tests resolveApp(). */
-    public void testResolveApp() {
-        ActivityInfo mockNonExportedActivityInfo = new ActivityInfo();
-        mockNonExportedActivityInfo.exported = false;
-        ActivityInfo mockExportedActivityInfo = new ActivityInfo();
-        mockExportedActivityInfo.exported = true;
-        try {
-            when(mMockIPackageManager.getActivityInfo(
-                    new ComponentName("package1", "class1"), 0, 4)).
-                    thenReturn(mockNonExportedActivityInfo);
-            when(mMockIPackageManager.getActivityInfo(
-                    new ComponentName("package2", "class2"), 0, 5)).
-                    thenThrow(new RemoteException());
-            when(mMockIPackageManager.getActivityInfo(
-                    new ComponentName("package3", "class3"), 0, 6)).
-                    thenReturn(mockExportedActivityInfo);
-            when(mMockIPackageManager.getActivityInfo(
-                    new ComponentName("package4", "class4"), 0, 7)).
-                    thenReturn(mockExportedActivityInfo);
-        } catch (RemoteException e) {
-            fail("RemoteException can't happen in the test, but it happened.");
-        }
-
-        // Assume some installed activities.
-        ActivityInfo ai0 = new ActivityInfo();
-        ai0.packageName = "package0";
-        ai0.name = "class0";
-        ActivityInfo ai1 = new ActivityInfo();
-        ai1.packageName = "package4";
-        ai1.name = "class4";
-        ResolveInfo ri0 = new ResolveInfo();
-        ri0.activityInfo = ai0;
-        ResolveInfo ri1 = new ResolveInfo();
-        ri1.activityInfo = ai1;
-        when(mMockPackageManager
-                .queryIntentActivitiesAsUser(any(Intent.class), eq(0), any(int.class)))
-                .thenReturn(Arrays.asList(ri0, ri1));
-
-        mModel.setCurrentUser(3);
-        // Unlauncheable (for various reasons) apps.
-        assertEquals(null, mModel.resolveApp(
-                new AppInfo(new ComponentName("package0", "class0"), new UserHandle(3))));
-        mModel.setCurrentUser(4);
-        assertEquals(null, mModel.resolveApp(
-                new AppInfo(new ComponentName("package1", "class1"), new UserHandle(4))));
-        mModel.setCurrentUser(5);
-        assertEquals(null, mModel.resolveApp(
-                new AppInfo(new ComponentName("package2", "class2"), new UserHandle(5))));
-        mModel.setCurrentUser(6);
-        assertEquals(null, mModel.resolveApp(
-                new AppInfo(new ComponentName("package3", "class3"), new UserHandle(6))));
-
-        // A launcheable app.
-        mModel.setCurrentUser(7);
-        NavigationBarAppsModel.ResolvedApp resolvedApp = mModel.resolveApp(
-                new AppInfo(new ComponentName("package4", "class4"), new UserHandle(7)));
-        assertNotNull(resolvedApp);
-        Intent intent = resolvedApp.launchIntent;
-        assertEquals(new ComponentName("package4", "class4"), intent.getComponent());
-        assertEquals("package4", intent.getPackage());
-        assertEquals(ri1, resolvedApp.ri);
-    }
-
-    /** Initializes the model from SharedPreferences for a few app activites. */
-    private void initializeModelFromPrefs() {
-        // Assume several apps are stored.
-        when(mMockPrefs.getInt("222|app_count", -1)).thenReturn(2);
-        when(mMockPrefs.getString("222|app_0", null)).thenReturn("package1/class1");
-        when(mMockPrefs.getLong("222|app_user_0", -1)).thenReturn(444L);
-        when(mMockPrefs.getString("222|app_1", null)).thenReturn("package2/class2");
-        when(mMockPrefs.getLong("222|app_user_1", -1)).thenReturn(555L);
-
-        ActivityInfo mockActivityInfo = new ActivityInfo();
-        mockActivityInfo.exported = true;
-        try {
-            when(mMockIPackageManager.getActivityInfo(
-                    new ComponentName("package0", "class0"), 0, 5)).thenReturn(mockActivityInfo);
-            when(mMockIPackageManager.getActivityInfo(
-                    new ComponentName("package1", "class1"), 0, 4)).thenReturn(mockActivityInfo);
-            when(mMockIPackageManager.getActivityInfo(
-                    new ComponentName("package2", "class2"), 0, 5)).thenReturn(mockActivityInfo);
-        } catch (RemoteException e) {
-            fail("RemoteException can't happen in the test, but it happened.");
-        }
-
-        // Assume some installed activities.
-        ActivityInfo ai0 = new ActivityInfo();
-        ai0.packageName = "package0";
-        ai0.name = "class0";
-        ActivityInfo ai1 = new ActivityInfo();
-        ai1.packageName = "package1";
-        ai1.name = "class1";
-        ActivityInfo ai2 = new ActivityInfo();
-        ai2.packageName = "package2";
-        ai2.name = "class2";
-        ResolveInfo ri0 = new ResolveInfo();
-        ri0.activityInfo = ai0;
-        ResolveInfo ri1 = new ResolveInfo();
-        ri1.activityInfo = ai1;
-        ResolveInfo ri2 = new ResolveInfo();
-        ri2.activityInfo = ai2;
-        when(mMockPackageManager
-                .queryIntentActivitiesAsUser(any(Intent.class), eq(0), any(int.class)))
-                .thenReturn(Arrays.asList(ri0, ri1, ri2));
-
-        mModel.setCurrentUser(2);
-    }
-
-    /** Tests initializing the model from SharedPreferences. */
-    public void testInitializeFromPrefs() {
-        initializeModelFromPrefs();
-        List<AppInfo> apps = mModel.getApps();
-        assertEquals(2, apps.size());
-        assertEquals("package1/class1", apps.get(0).getComponentName().flattenToString());
-        assertEquals(new UserHandle(4), apps.get(0).getUser());
-        assertEquals("package2/class2", apps.get(1).getComponentName().flattenToString());
-        assertEquals(new UserHandle(5), apps.get(1).getUser());
-    }
-
-    /** Tests initializing the model when the SharedPreferences aren't available. */
-    public void testInitializeDefaultApps() {
-        // Assume the user's app count pref isn't available.
-        when(mMockPrefs.getInt("222|app_count", -1)).thenReturn(-1);
-
-        // Assume some installed activities.
-        ActivityInfo ai1 = new ActivityInfo();
-        ai1.packageName = "package1";
-        ai1.name = "class1";
-        ActivityInfo ai2 = new ActivityInfo();
-        ai2.packageName = "package2";
-        ai2.name = "class2";
-        ResolveInfo ri1 = new ResolveInfo();
-        ri1.activityInfo = ai1;
-        ResolveInfo ri2 = new ResolveInfo();
-        ri2.activityInfo = ai2;
-        when(mMockPackageManager
-                .queryIntentActivitiesAsUser(any(Intent.class), eq(0), eq(2)))
-                .thenReturn(Arrays.asList(ri1, ri2));
-
-        // Setting the user should load the installed activities.
-        mModel.setCurrentUser(2);
-        List<AppInfo> apps = mModel.getApps();
-        assertEquals(2, apps.size());
-        assertEquals("package1/class1", apps.get(0).getComponentName().flattenToString());
-        assertEquals(new UserHandle(2), apps.get(0).getUser());
-        assertEquals("package2/class2", apps.get(1).getComponentName().flattenToString());
-        assertEquals(new UserHandle(2), apps.get(1).getUser());
-        InOrder order = inOrder(mMockEdit);
-        order.verify(mMockEdit).apply();
-        order.verify(mMockEdit).putInt("222|app_count", 2);
-        order.verify(mMockEdit).putString("222|app_0", "package1/class1");
-        order.verify(mMockEdit).putLong("222|app_user_0", 222L);
-        order.verify(mMockEdit).putString("222|app_1", "package2/class2");
-        order.verify(mMockEdit).putLong("222|app_user_1", 222L);
-        order.verify(mMockEdit).apply();
-        verifyNoMoreInteractions(mMockEdit);
-    }
-
-    /** Tests initializing the model if one of the prefs is missing. */
-    public void testInitializeWithMissingPref() {
-        // Assume two apps are nominally stored.
-        when(mMockPrefs.getInt("222|app_count", -1)).thenReturn(2);
-        when(mMockPrefs.getString("222|app_0", null)).thenReturn("package0/class0");
-        when(mMockPrefs.getLong("222|app_user_0", -1)).thenReturn(555L);
-
-        // But assume one pref is missing.
-        when(mMockPrefs.getString("222|app_1", null)).thenReturn(null);
-
-        ActivityInfo mockActivityInfo = new ActivityInfo();
-        mockActivityInfo.exported = true;
-        try {
-            when(mMockIPackageManager.getActivityInfo(
-                    new ComponentName("package0", "class0"), 0, 5)).thenReturn(mockActivityInfo);
-        } catch (RemoteException e) {
-            fail("RemoteException can't happen in the test, but it happened.");
-        }
-
-        ActivityInfo ai0 = new ActivityInfo();
-        ai0.packageName = "package0";
-        ai0.name = "class0";
-        ResolveInfo ri0 = new ResolveInfo();
-        ri0.activityInfo = ai0;
-        when(mMockPackageManager
-                .queryIntentActivitiesAsUser(any(Intent.class), eq(0), any(int.class)))
-                .thenReturn(Arrays.asList(ri0));
-
-        // Initializing the model should load from prefs and skip the missing one.
-        mModel.setCurrentUser(2);
-        List<AppInfo> apps = mModel.getApps();
-        assertEquals(1, apps.size());
-        assertEquals("package0/class0", apps.get(0).getComponentName().flattenToString());
-        assertEquals(new UserHandle(5), apps.get(0).getUser());
-        InOrder order = inOrder(mMockEdit);
-        order.verify(mMockEdit).putInt("222|app_count", 1);
-        order.verify(mMockEdit).putString("222|app_0", "package0/class0");
-        order.verify(mMockEdit).putLong("222|app_user_0", 555L);
-        order.verify(mMockEdit).apply();
-        verifyNoMoreInteractions(mMockEdit);
-    }
-
-    /** Tests initializing the model if one of the apps is unlauncheable. */
-    public void testInitializeWithUnlauncheableApp() {
-        // Assume two apps are nominally stored.
-        when(mMockPrefs.getInt("222|app_count", -1)).thenReturn(2);
-        when(mMockPrefs.getString("222|app_0", null)).thenReturn("package0/class0");
-        when(mMockPrefs.getLong("222|app_user_0", -1)).thenReturn(555L);
-        when(mMockPrefs.getString("222|app_1", null)).thenReturn("package1/class1");
-        when(mMockPrefs.getLong("222|app_user_1", -1)).thenReturn(444L);
-
-        ActivityInfo mockActivityInfo = new ActivityInfo();
-        mockActivityInfo.exported = true;
-        try {
-            when(mMockIPackageManager.getActivityInfo(
-                    new ComponentName("package0", "class0"), 0, 5)).thenReturn(mockActivityInfo);
-        } catch (RemoteException e) {
-            fail("RemoteException can't happen in the test, but it happened.");
-        }
-
-        ActivityInfo ai0 = new ActivityInfo();
-        ai0.packageName = "package0";
-        ai0.name = "class0";
-        ResolveInfo ri0 = new ResolveInfo();
-        ri0.activityInfo = ai0;
-        when(mMockPackageManager
-                .queryIntentActivitiesAsUser(any(Intent.class), eq(0), any(int.class)))
-                .thenReturn(Arrays.asList(ri0));
-
-        // Initializing the model should load from prefs and skip the unlauncheable one.
-        mModel.setCurrentUser(2);
-        List<AppInfo> apps = mModel.getApps();
-        assertEquals(1, apps.size());
-        assertEquals("package0/class0", apps.get(0).getComponentName().flattenToString());
-        assertEquals(new UserHandle(5), apps.get(0).getUser());
-
-        // Once an unlauncheable app is detected, the model should save all apps excluding the
-        // unlauncheable one.
-        verify(mMockEdit).putInt("222|app_count", 1);
-        verify(mMockEdit).putString("222|app_0", "package0/class0");
-        verify(mMockEdit).putLong("222|app_user_0", 555L);
-        verify(mMockEdit).apply();
-        verifyNoMoreInteractions(mMockEdit);
-    }
-
-    /** Tests saving the model to SharedPreferences. */
-    public void testSavePrefs() {
-        initializeModelFromPrefs();
-
-        mModel.setApps(mModel.getApps());
-        verify(mMockEdit).putInt("222|app_count", 2);
-        verify(mMockEdit).putString("222|app_0", "package1/class1");
-        verify(mMockEdit).putLong("222|app_user_0", 444L);
-        verify(mMockEdit).putString("222|app_1", "package2/class2");
-        verify(mMockEdit).putLong("222|app_user_1", 555L);
-        verify(mMockEdit).apply();
-        verifyNoMoreInteractions(mMockEdit);
-    }
-
-    /** Tests cleaning all prefs on a version change. */
-    public void testVersionChange() {
-        // Assume the version pref changed.
-        when(mMockPrefs.getInt("version", -1)).thenReturn(1);
-
-        new NavigationBarAppsModel(getContext());
-        verify(mMockEdit).clear();
-        verify(mMockEdit).putInt("version", 3);
-        verify(mMockEdit).apply();
-        verifyNoMoreInteractions(mMockEdit);
-    }
-
-    /** Tests cleaning prefs for deleted users. */
-    public void testCleaningDeletedUsers() {
-        // Users on the device.
-        final UserInfo user1 = new UserInfo(11, "", 0);
-        user1.serialNumber = 1111;
-        final UserInfo user2 = new UserInfo(13, "", 0);
-        user2.serialNumber = 1313;
-
-        when(mMockUserManager.getUsers()).thenReturn(Arrays.asList(user1, user2));
-
-        when(mMockPrefs.edit()).
-                thenReturn(mMockEdit).
-                thenReturn(mock(SharedPreferences.Editor.class));
-
-        // Assume the user's app count pref isn't available. This will trigger clearing deleted
-        // users' prefs.
-        when(mMockPrefs.getInt("222|app_count", -1)).thenReturn(-1);
-
-        final Map allPrefs = new HashMap<String, Object>();
-        allPrefs.put("version", null);
-        allPrefs.put("some_strange_pref", null);
-        allPrefs.put("", null);
-        allPrefs.put("|", null);
-        allPrefs.put("1313|app_count", null);
-        allPrefs.put("1212|app_count", null);
-        when(mMockPrefs.getAll()).thenReturn(allPrefs);
-
-        // Setting the user should remove prefs for deleted users.
-        mModel.setCurrentUser(2);
-        verify(mMockEdit).remove("some_strange_pref");
-        verify(mMockEdit).remove("");
-        verify(mMockEdit).remove("|");
-        verify(mMockEdit).remove("1212|app_count");
-        verify(mMockEdit).apply();
-        verifyNoMoreInteractions(mMockEdit);
-    }
-
-    /** Tests the apps-changed listener. */
-    public void testAppsChangedListeners() {
-        NavigationBarAppsModel.OnAppsChangedListener listener =
-                mock(NavigationBarAppsModel.OnAppsChangedListener.class);
-
-        mModel.addOnAppsChangedListener(listener);
-        mModel.setApps(new ArrayList<AppInfo>());
-        verify(listener).onPinnedAppsChanged();
-        verifyNoMoreInteractions(listener);
-
-        mModel.removeOnAppsChangedListener(listener);
-        mModel.setApps(new ArrayList<AppInfo>());
-        verifyNoMoreInteractions(listener);
-    }
-}
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 13fc47d..5cf3767 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
@@ -33,7 +33,7 @@
 import android.util.Log;
 
 import com.android.internal.telephony.cdma.EriInfo;
-import com.android.settingslib.net.MobileDataController;
+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.NetworkControllerImpl.Config;
@@ -60,8 +60,8 @@
     protected NetworkControllerImpl mNetworkController;
     protected MobileSignalController mMobileSignalController;
     protected PhoneStateListener mPhoneStateListener;
-    private SignalStrength mSignalStrength;
-    private ServiceState mServiceState;
+    protected SignalStrength mSignalStrength;
+    protected ServiceState mServiceState;
     protected ConnectivityManager mMockCm;
     protected WifiManager mMockWm;
     protected SubscriptionManager mMockSm;
@@ -96,7 +96,7 @@
         mCallbackHandler = mock(CallbackHandler.class);
         mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
                 mConfig, Looper.getMainLooper(), mCallbackHandler,
-                mock(AccessPointControllerImpl.class), mock(MobileDataController.class),
+                mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
                 mMockSubDefaults);
         setupNetworkController();
 
@@ -137,7 +137,7 @@
               = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
                         mConfig, Looper.getMainLooper(), mCallbackHandler,
                         mock(AccessPointControllerImpl.class),
-                        mock(MobileDataController.class), mMockSubDefaults);
+                        mock(DataUsageController.class), mMockSubDefaults);
 
       setupNetworkController();
 
@@ -235,7 +235,7 @@
         mPhoneStateListener.onSignalStrengthsChanged(mSignalStrength);
     }
 
-    private void updateServiceState() {
+    protected void updateServiceState() {
         Log.d(TAG, "Sending Service State: " + mServiceState);
         mPhoneStateListener.onServiceStateChanged(mServiceState);
     }
@@ -246,6 +246,7 @@
     }
 
     public void updateDataConnectionState(int dataState, int dataNetType) {
+        when(mServiceState.getDataNetworkType()).thenReturn(dataNetType);
         mPhoneStateListener.onDataConnectionStateChanged(dataState, dataNetType);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index 587e2b5..d5eca95 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -4,7 +4,7 @@
 import android.telephony.TelephonyManager;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import com.android.settingslib.net.MobileDataController;
+import com.android.settingslib.net.DataUsageController;
 import org.mockito.Mockito;
 
 @SmallTest
@@ -88,7 +88,7 @@
         mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
                 mConfig, Looper.getMainLooper(), mCallbackHandler,
                 Mockito.mock(AccessPointControllerImpl.class),
-                Mockito.mock(MobileDataController.class), mMockSubDefaults);
+                Mockito.mock(DataUsageController.class), mMockSubDefaults);
         setupNetworkController();
 
         setupDefaultSignal();
@@ -115,6 +115,21 @@
                 TelephonyIcons.QS_DATA_4G);
     }
 
+    public void testDataChangeWithoutConnectionState() {
+        setupDefaultSignal();
+        updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
+                TelephonyManager.NETWORK_TYPE_LTE);
+
+        verifyDataIndicators(TelephonyIcons.DATA_LTE[1][0 /* No direction */],
+                TelephonyIcons.QS_DATA_LTE);
+
+        Mockito.when(mServiceState.getDataNetworkType())
+                .thenReturn(TelephonyManager.NETWORK_TYPE_HSPA);
+        updateServiceState();
+        verifyDataIndicators(TelephonyIcons.DATA_H[1][0 /* No direction */],
+                TelephonyIcons.QS_DATA_H);
+    }
+
     public void testDataActivity() {
         setupDefaultSignal();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index 760aa9a..08da382 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -29,7 +29,7 @@
 
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
-import com.android.settingslib.net.MobileDataController;
+import com.android.settingslib.net.DataUsageController;
 import com.android.systemui.R;
 
 import org.mockito.ArgumentCaptor;
@@ -47,7 +47,7 @@
         // Create a new NetworkController as this is currently handled in constructor.
         mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
                 mConfig, Looper.getMainLooper(), mCallbackHandler,
-                mock(AccessPointControllerImpl.class), mock(MobileDataController.class),
+                mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
                 mMockSubDefaults);
         setupNetworkController();
 
@@ -96,7 +96,7 @@
         // Create a new NetworkController as this is currently handled in constructor.
         mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
                 mConfig, Looper.getMainLooper(), mCallbackHandler,
-                mock(AccessPointControllerImpl.class), mock(MobileDataController.class),
+                mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
                 mMockSubDefaults);
         setupNetworkController();
 
diff --git a/packages/VpnDialogs/res/values-de/strings.xml b/packages/VpnDialogs/res/values-de/strings.xml
index 168937b..27b0196 100644
--- a/packages/VpnDialogs/res/values-de/strings.xml
+++ b/packages/VpnDialogs/res/values-de/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">"Verbindungsanfrage"</string>
-    <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> möchte eine VPN-Verbindung herstellen, über die der Netzwerkverkehr überwacht werden kann. Lassen Sie die Verbindung nur zu, wenn die App vertrauenswürdig ist. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; wird oben am Display angezeigt, wenn VPN aktiv ist."</string>
+    <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> möchte eine VPN-Verbindung herstellen, über die der Netzwerkverkehr überwacht werden kann. Lasse die Verbindung nur zu, wenn die App vertrauenswürdig ist. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; wird oben am Display angezeigt, wenn VPN aktiv ist."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN ist verbunden"</string>
     <string name="configure" msgid="4905518375574791375">"Konfigurieren"</string>
     <string name="disconnect" msgid="971412338304200056">"Verbindung trennen"</string>
diff --git a/packages/WallpaperCropper/res/values/styles.xml b/packages/WallpaperCropper/res/values/styles.xml
index e438c84..0f9e247 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.DayNight">
         <item name="android:actionBarStyle">@style/WallpaperCropperActionBar</item>
         <item name="android:windowFullscreen">true</item>
         <item name="android:windowActionBarOverlay">true</item>
diff --git a/proto/Android.mk b/proto/Android.mk
new file mode 100644
index 0000000..a13a780
--- /dev/null
+++ b/proto/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := framework-protos
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+LOCAL_SRC_FILES:= $(call all-proto-files-under, src)
+LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
+
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVA_LIBRARIES := core-oj core-libart
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/jarjar-rules.txt
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/proto/jarjar-rules.txt b/proto/jarjar-rules.txt
new file mode 100644
index 0000000..0c77c2a
--- /dev/null
+++ b/proto/jarjar-rules.txt
@@ -0,0 +1 @@
+rule com.google.** com.android.@1
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
new file mode 100644
index 0000000..697777c
--- /dev/null
+++ b/proto/src/metrics_constants.proto
@@ -0,0 +1,346 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto2";
+
+option java_package = "com.android.internal.logging";
+option java_outer_classname = "MetricsProto";
+
+package com_android_internal_logging;
+
+// Wrapper for System UI log events
+message MetricsEvent {
+
+  // Known visual elements: views or controls.
+  enum View {
+    VIEW_UNKNOWN = 0;
+    MAIN_SETTINGS = 1;
+    ACCESSIBILITY = 2;
+    ACCESSIBILITY_CAPTION_PROPERTIES = 3;
+    ACCESSIBILITY_SERVICE = 4;
+    ACCESSIBILITY_TOGGLE_DALTONIZER = 5;
+    ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE = 6;
+    ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION = 7;
+    ACCOUNT = 8;
+    ACCOUNTS_ACCOUNT_SYNC = 9;
+    ACCOUNTS_CHOOSE_ACCOUNT_ACTIVITY = 10;
+    ACCOUNTS_MANAGE_ACCOUNTS = 11;
+    APN = 12;
+    APN_EDITOR = 13;
+    APP_OPS_DETAILS = 14;
+    APP_OPS_SUMMARY = 15;
+    APPLICATION = 16;
+    APPLICATIONS_APP_LAUNCH = 17;
+    APPLICATIONS_APP_PERMISSION = 18;
+    APPLICATIONS_APP_STORAGE = 19;
+    APPLICATIONS_INSTALLED_APP_DETAILS = 20;
+    APPLICATIONS_PROCESS_STATS_DETAIL = 21;
+    APPLICATIONS_PROCESS_STATS_MEM_DETAIL = 22;
+    APPLICATIONS_PROCESS_STATS_UI = 23;
+    BLUETOOTH = 24;
+    BLUETOOTH_DEVICE_PICKER = 25;
+    BLUETOOTH_DEVICE_PROFILES = 26;
+    CHOOSE_LOCK_GENERIC = 27;
+    CHOOSE_LOCK_PASSWORD = 28;
+    CHOOSE_LOCK_PATTERN = 29;
+    CONFIRM_LOCK_PASSWORD = 30;
+    CONFIRM_LOCK_PATTERN = 31;
+    CRYPT_KEEPER = 32;
+    CRYPT_KEEPER_CONFIRM = 33;
+    DASHBOARD_SEARCH_RESULTS = 34;
+    DASHBOARD_SUMMARY = 35;
+    DATA_USAGE = 36;
+    DATA_USAGE_SUMMARY = 37;
+    DATE_TIME = 38;
+    DEVELOPMENT = 39;
+    DEVICEINFO = 40;
+    DEVICEINFO_IMEI_INFORMATION = 41;
+    DEVICEINFO_STORAGE = 42;
+    DEVICEINFO_SIM_STATUS = 43;
+    DEVICEINFO_STATUS = 44;
+    DEVICEINFO_USB = 45;
+    DISPLAY = 46;
+    DREAM = 47;
+    ENCRYPTION = 48;
+    FINGERPRINT = 49;
+    FINGERPRINT_ENROLL = 50;
+    FUELGAUGE_BATTERY_HISTORY_DETAIL = 51;
+    FUELGAUGE_BATTERY_SAVER = 52;
+    FUELGAUGE_POWER_USAGE_DETAIL = 53;
+    FUELGAUGE_POWER_USAGE_SUMMARY = 54;
+    HOME = 55;
+    ICC_LOCK = 56;
+    INPUTMETHOD_LANGUAGE = 57;
+    INPUTMETHOD_KEYBOARD = 58;
+    INPUTMETHOD_SPELL_CHECKERS = 59;
+    INPUTMETHOD_SUBTYPE_ENABLER = 60;
+    INPUTMETHOD_USER_DICTIONARY = 61;
+    INPUTMETHOD_USER_DICTIONARY_ADD_WORD = 62;
+    LOCATION = 63;
+    LOCATION_MODE = 64;
+    MANAGE_APPLICATIONS = 65;
+    MASTER_CLEAR = 66;
+    MASTER_CLEAR_CONFIRM = 67;
+    NET_DATA_USAGE_METERED = 68;
+    NFC_BEAM = 69;
+    NFC_PAYMENT = 70;
+    NOTIFICATION = 71;
+    NOTIFICATION_APP_NOTIFICATION = 72;
+    NOTIFICATION_OTHER_SOUND = 73;
+    NOTIFICATION_REDACTION = 74;
+    NOTIFICATION_STATION = 75;
+    NOTIFICATION_ZEN_MODE = 76;
+    OWNER_INFO = 77;
+    PRINT_JOB_SETTINGS = 78;
+    PRINT_SERVICE_SETTINGS = 79;
+    PRINT_SETTINGS = 80;
+    PRIVACY = 81;
+    PROXY_SELECTOR = 82;
+    RESET_NETWORK = 83;
+    RESET_NETWORK_CONFIRM = 84;
+    RUNNING_SERVICE_DETAILS = 85;
+    SCREEN_PINNING = 86;
+    SECURITY = 87;
+    SIM = 88;
+    TESTING = 89;
+    TETHER = 90;
+    TRUST_AGENT = 91;
+    TRUSTED_CREDENTIALS = 92;
+    TTS_ENGINE_SETTINGS = 93;
+    TTS_TEXT_TO_SPEECH = 94;
+    USAGE_ACCESS = 95;
+    USER = 96;
+    USERS_APP_RESTRICTIONS = 97;
+    USER_DETAILS = 98;
+    VOICE_INPUT = 99;
+    VPN = 100;
+    WALLPAPER_TYPE = 101;
+    WFD_WIFI_DISPLAY = 102;
+    WIFI = 103;
+    WIFI_ADVANCED = 104;
+    WIFI_CALLING = 105;
+    WIFI_SAVED_ACCESS_POINTS = 106;
+    WIFI_APITEST = 107;
+    WIFI_INFO = 108;
+    WIFI_P2P = 109;
+    WIRELESS = 110;
+    QS_PANEL = 111;
+    QS_AIRPLANEMODE = 112;
+    QS_BLUETOOTH = 113;
+    QS_CAST = 114;
+    QS_CELLULAR = 115;
+    QS_COLORINVERSION = 116;
+    QS_DATAUSAGEDETAIL = 117;
+    QS_DND = 118;
+    QS_FLASHLIGHT = 119;
+    QS_HOTSPOT = 120;
+    QS_INTENT = 121;
+    QS_LOCATION = 122;
+    QS_ROTATIONLOCK = 123;
+    QS_USERDETAILITE = 124;
+    QS_USERDETAIL = 125;
+    QS_WIFI = 126;
+    NOTIFICATION_PANEL = 127;
+    NOTIFICATION_ITEM = 128;
+    NOTIFICATION_ITEM_ACTION = 129;
+    APPLICATIONS_ADVANCED = 130;
+    LOCATION_SCANNING = 131;
+    MANAGE_APPLICATIONS_ALL = 132;
+    MANAGE_APPLICATIONS_NOTIFICATIONS = 133;
+    ACTION_WIFI_ADD_NETWORK = 134;
+    ACTION_WIFI_CONNECT = 135;
+    ACTION_WIFI_FORCE_SCAN = 136;
+    ACTION_WIFI_FORGET = 137;
+    ACTION_WIFI_OFF = 138;
+    ACTION_WIFI_ON = 139;
+    MANAGE_PERMISSIONS = 140;
+    NOTIFICATION_ZEN_MODE_PRIORITY = 141;
+    NOTIFICATION_ZEN_MODE_AUTOMATION = 142;
+    MANAGE_DOMAIN_URLS = 143;
+    NOTIFICATION_ZEN_MODE_SCHEDULE_RULE = 144;
+    NOTIFICATION_ZEN_MODE_EXTERNAL_RULE = 145;
+    NOTIFICATION_ZEN_MODE_EVENT_RULE = 146;
+    ACTION_BAN_APP_NOTES = 147;
+    ACTION_DISMISS_ALL_NOTES = 148;
+    QS_DND_DETAILS = 149;
+    QS_BLUETOOTH_DETAILS = 150;
+    QS_CAST_DETAILS = 151;
+    QS_WIFI_DETAILS = 152;
+    QS_WIFI_TOGGLE = 153;
+    QS_BLUETOOTH_TOGGLE = 154;
+    QS_CELLULAR_TOGGLE = 155;
+    QS_SWITCH_USER = 156;
+    QS_CAST_SELECT = 157;
+    QS_CAST_DISCONNECT = 158;
+    ACTION_BLUETOOTH_TOGGLE = 159;
+    ACTION_BLUETOOTH_SCAN = 160;
+    ACTION_BLUETOOTH_RENAME = 161;
+    ACTION_BLUETOOTH_FILES = 162;
+    QS_DND_TIME = 163;
+    QS_DND_CONDITION_SELECT = 164;
+    QS_DND_ZEN_SELECT = 165;
+    QS_DND_TOGGLE = 166;
+    ACTION_ZEN_ALLOW_REMINDERS = 167;
+    ACTION_ZEN_ALLOW_EVENTS = 168;
+    ACTION_ZEN_ALLOW_MESSAGES = 169;
+    ACTION_ZEN_ALLOW_CALLS = 170;
+    ACTION_ZEN_ALLOW_REPEAT_CALLS = 171;
+    ACTION_ZEN_ADD_RULE = 172;
+    ACTION_ZEN_ADD_RULE_OK = 173;
+    ACTION_ZEN_DELETE_RULE = 174;
+    ACTION_ZEN_DELETE_RULE_OK = 175;
+    ACTION_ZEN_ENABLE_RULE = 176;
+    ACTION_AIRPLANE_TOGGLE = 177;
+    ACTION_CELL_DATA_TOGGLE = 178;
+    NOTIFICATION_ACCESS = 179;
+    NOTIFICATION_ZEN_MODE_ACCESS = 180;
+    APPLICATIONS_DEFAULT_APPS = 181;
+    APPLICATIONS_STORAGE_APPS = 182;
+    APPLICATIONS_USAGE_ACCESS_DETAIL = 183;
+    APPLICATIONS_HIGH_POWER_APPS = 184;
+    FUELGAUGE_HIGH_POWER_DETAILS = 185;
+    ACTION_LS_UNLOCK = 186;
+    ACTION_LS_SHADE = 187;
+    ACTION_LS_HINT = 188;
+    ACTION_LS_CAMERA = 189;
+    ACTION_LS_DIALER = 190;
+    ACTION_LS_LOCK = 191;
+    ACTION_LS_NOTE = 192;
+    ACTION_LS_QS = 193;
+    ACTION_SHADE_QS_PULL = 194;
+    ACTION_SHADE_QS_TAP = 195;
+    LOCKSCREEN = 196;
+    BOUNCER = 197;
+    SCREEN = 198;
+    NOTIFICATION_ALERT = 199;
+    ACTION_EMERGENCY_CALL = 200;
+    APPLICATIONS_MANAGE_ASSIST = 201;
+    PROCESS_STATS_SUMMARY = 202;
+    ACTION_ROTATION_LOCK = 203;
+    ACTION_NOTE_CONTROLS = 204;
+    ACTION_NOTE_INFO = 205;
+    ACTION_APP_NOTE_SETTINGS = 206;
+    VOLUME_DIALOG = 207;
+    VOLUME_DIALOG_DETAILS = 208;
+    ACTION_VOLUME_SLIDER = 209;
+    ACTION_VOLUME_STREAM = 210;
+    ACTION_VOLUME_KEY = 211;
+    ACTION_VOLUME_ICON = 212;
+    ACTION_RINGER_MODE = 213;
+    ACTION_ACTIVITY_CHOOSER_SHOWN = 214;
+    ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET = 215;
+    ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET = 216;
+    ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET = 217;
+    ACTION_BRIGHTNESS = 218;
+    ACTION_BRIGHTNESS_AUTO = 219;
+    BRIGHTNESS_DIALOG = 220;
+    SYSTEM_ALERT_WINDOW_APPS = 221;
+    DREAMING = 222;
+    DOZING = 223;
+    OVERVIEW_ACTIVITY = 224;
+    ABOUT_LEGAL_SETTINGS = 225;
+    ACTION_SEARCH_RESULTS = 226;
+    TUNER = 227;
+    TUNER_QS = 228;
+    TUNER_DEMO_MODE = 229;
+    TUNER_QS_REORDER = 230;
+    TUNER_QS_ADD = 231;
+    TUNER_QS_REMOVE = 232;
+    TUNER_STATUS_BAR_ENABLE = 233;
+    TUNER_STATUS_BAR_DISABLE = 234;
+    TUNER_DEMO_MODE_ENABLED = 235;
+    TUNER_DEMO_MODE_ON = 236;
+    TUNER_BATTERY_PERCENTAGE = 237;
+    FUELGAUGE_INACTIVE_APPS = 238;
+    ACTION_ASSIST_LONG_PRESS = 239;
+    FINGERPRINT_ENROLLING = 240;
+    FINGERPRINT_FIND_SENSOR = 241;
+    FINGERPRINT_ENROLL_FINISH = 242;
+    FINGERPRINT_ENROLL_INTRO = 243;
+    FINGERPRINT_ENROLL_ONBOARD = 244;
+    FINGERPRINT_ENROLL_SIDECAR = 245;
+    FINGERPRINT_ENROLLING_SETUP = 246;
+    FINGERPRINT_FIND_SENSOR_SETUP = 247;
+    FINGERPRINT_ENROLL_FINISH_SETUP = 248;
+    FINGERPRINT_ENROLL_INTRO_SETUP = 249;
+    FINGERPRINT_ENROLL_ONBOARD_SETUP = 250;
+    ACTION_FINGERPRINT_ENROLL = 251;
+    ACTION_FINGERPRINT_AUTH = 252;
+    ACTION_FINGERPRINT_DELETE = 253;
+    ACTION_FINGERPRINT_RENAME = 254;
+    ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE = 255;
+    ACTION_WIGGLE_CAMERA_GESTURE = 256;
+    QS_WORKMODE = 257;
+    BACKGROUND_CHECK_SUMMARY = 258;
+    QS_LOCK_TILE = 259;
+    QS_USER_TILE = 260;
+    QS_BATTERY_TILE = 261;
+    NOTIFICATION_ZEN_MODE_VISUAL_INTERRUPTIONS = 262;
+    ACTION_ZEN_ALLOW_PEEK = 263;
+    ACTION_ZEN_ALLOW_LIGHTS = 264;
+    NOTIFICATION_TOPIC_NOTIFICATION = 265;
+    ACTION_DEFAULT_SMS_APP_CHANGED = 266;
+    QS_COLOR_MATRIX = 267;
+    QS_CUSTOM = 268;
+    ACTION_ZEN_ALLOW_SCREEN_ON = 269;
+
+    // Logged when the user docks a window from recents by
+    // longpressing a task and dragging it to the dock area.
+    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_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_WINDOW_DOCK_SWIPE = 272;
+
+    // Logged when the user launches a profile-specific app and we
+    // intercept it with the confirm credentials UI.
+    PROFILE_CHALLENGE = 273;
+
+    QS_BATTERY_DETAIL = 274;
+
+    // Logged when the user goes into the overview history.
+    OVERVIEW_HISTORY = 275;
+
+    // Logged when the user pages through overview.
+    ACTION_OVERVIEW_PAGE = 276;
+
+    // Logged when the user launches a task from overview.
+    ACTION_OVERVIEW_SELECT = 277;
+
+    // Logged when the user views the emergency info.
+    ACTION_VIEW_EMERGENCY_INFO = 278;
+
+    // Logged when the user views the edit emergency info activity.
+    ACTION_EDIT_EMERGENCY_INFO = 279;
+
+    // Logged when the user edits an emergency info field.
+    ACTION_EDIT_EMERGENCY_INFO_FIELD = 280;
+
+    // Logged when the user adds a new emergency contact.
+    ACTION_ADD_EMERGENCY_CONTACT = 281;
+
+    // Logged when the user deletes an emergency contact.
+    ACTION_DELETE_EMERGENCY_CONTACT = 282;
+
+    // Logged when the user calls an emergency contact.
+    ACTION_CALL_EMERGENCY_CONTACT = 283;
+
+    // QS Tile for Data Saver.
+    QS_DATA_SAVER = 284;
+  }
+}
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index a4876b9..8c78a3a 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -16,14 +16,16 @@
 
 package android.renderscript;
 
+import java.nio.ByteBuffer;
 import java.util.HashMap;
+
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
-import android.view.Surface;
-import android.util.Log;
 import android.graphics.Canvas;
 import android.os.Trace;
+import android.util.Log;
+import android.view.Surface;
 
 /**
  * <p> This class provides the primary method through which data is passed to
@@ -53,12 +55,16 @@
  **/
 
 public class Allocation extends BaseObj {
+    private static final int MAX_NUMBER_IO_INPUT_ALLOC = 16;
+
     Type mType;
     Bitmap mBitmap;
     int mUsage;
     Allocation mAdaptedAllocation;
     int mSize;
+    MipmapControl mMipmapControl;
 
+    long mTimeStamp = -1;
     boolean mReadAllowed = true;
     boolean mWriteAllowed = true;
     boolean mAutoPadding = false;
@@ -78,6 +84,8 @@
     OnBufferAvailableListener mBufferNotifier;
 
     private Surface mGetSurfaceSurface = null;
+    private ByteBuffer mByteBuffer = null;
+    private long mByteBufferStride = -1;
 
     private Element.DataType validateObjectIsPrimitiveArray(Object d, boolean checkType) {
         final Class c = d.getClass();
@@ -274,6 +282,17 @@
     }
 
     /**
+     * @hide
+     * Get the Mipmap control flag of the Allocation.
+     *
+     * @return the Mipmap control flag of the Allocation
+     *
+     */
+    public MipmapControl getMipmap() {
+        return mMipmapControl;
+    }
+
+    /**
      * Enable/Disable AutoPadding for Vec3 elements.
      * By default: Diabled.
      *
@@ -355,6 +374,11 @@
         }
     }
 
+    Allocation(long id, RenderScript rs, Type t, int usage, MipmapControl mips) {
+        this(id, rs, t, usage);
+        mMipmapControl = mips;
+    }
+
     protected void finalize() throws Throwable {
         RenderScript.registerNativeFree.invoke(RenderScript.sRuntime, mSize);
         super.finalize();
@@ -517,7 +541,7 @@
                     "Can only receive if IO_INPUT usage specified.");
             }
             mRS.validate();
-            mRS.nAllocationIoReceive(getID(mRS));
+            mTimeStamp = mRS.nAllocationIoReceive(getID(mRS));
         } finally {
             Trace.traceEnd(RenderScript.TRACE_TAG);
         }
@@ -1886,7 +1910,7 @@
             if (id == 0) {
                 throw new RSRuntimeException("Allocation creation failed.");
             }
-            return new Allocation(id, rs, type, usage);
+            return new Allocation(id, rs, type, usage, mips);
         } finally {
             Trace.traceEnd(RenderScript.TRACE_TAG);
         }
@@ -1944,7 +1968,7 @@
             if (id == 0) {
                 throw new RSRuntimeException("Allocation creation failed.");
             }
-            return new Allocation(id, rs, t, usage);
+            return new Allocation(id, rs, t, usage, MipmapControl.MIPMAP_NONE);
         } finally {
             Trace.traceEnd(RenderScript.TRACE_TAG);
         }
@@ -2033,7 +2057,7 @@
                 }
 
                 // keep a reference to the Bitmap around to prevent GC
-                Allocation alloc = new Allocation(id, rs, t, usage);
+                Allocation alloc = new Allocation(id, rs, t, usage, mips);
                 alloc.setBitmap(b);
                 return alloc;
             }
@@ -2043,13 +2067,185 @@
             if (id == 0) {
                 throw new RSRuntimeException("Load failed.");
             }
-            return new Allocation(id, rs, t, usage);
+            return new Allocation(id, rs, t, usage, mips);
         } finally {
             Trace.traceEnd(RenderScript.TRACE_TAG);
         }
     }
 
     /**
+     * Gets or creates a ByteBuffer that contains the raw data of the current Allocation.
+     * If the Allocation is created with USAGE_IO_INPUT, the returned ByteBuffer
+     * would contain the up-to-date data as READ ONLY.
+     * For a 2D or 3D Allocation, the raw data maybe padded so that each row of
+     * the Allocation has certain alignment. The size of each row including padding,
+     * called stride, can be queried using the {@link #getStride()} method.
+     *
+     * Note: Operating on the ByteBuffer of a destroyed Allocation will triger errors.
+     *
+     * @return ByteBuffer The ByteBuffer associated with raw data pointer of the Allocation.
+     */
+    public ByteBuffer getByteBuffer() {
+        // Create a new ByteBuffer if it is not initialized or using IO_INPUT.
+        if (mType.hasFaces()) {
+            throw new RSInvalidStateException("Cubemap is not supported for getByteBuffer().");
+        }
+        if (mType.getYuv() == android.graphics.ImageFormat.NV21 ||
+            mType.getYuv() == android.graphics.ImageFormat.YV12 ||
+            mType.getYuv() == android.graphics.ImageFormat.YUV_420_888 ) {
+            throw new RSInvalidStateException("YUV format is not supported for getByteBuffer().");
+        }
+        if (mByteBuffer == null || (mUsage & USAGE_IO_INPUT) != 0) {
+            int xBytesSize = mType.getX() * mType.getElement().getBytesSize();
+            long[] stride = new long[1];
+            mByteBuffer = mRS.nAllocationGetByteBuffer(getID(mRS), stride, xBytesSize, mType.getY(), mType.getZ());
+            mByteBufferStride = stride[0];
+        }
+        if ((mUsage & USAGE_IO_INPUT) != 0) {
+            return mByteBuffer.asReadOnlyBuffer();
+        }
+        return mByteBuffer;
+    }
+
+    /**
+     * Creates a new Allocation Array with the given {@link
+     * android.renderscript.Type}, and usage flags.
+     * Note: If the input allocation is of usage: USAGE_IO_INPUT,
+     * the created Allocation will be sharing the same BufferQueue.
+     *
+     * @param rs RenderScript context
+     * @param t RenderScript type describing data layout
+     * @param usage bit field specifying how the Allocation is
+     *              utilized
+     * @param numAlloc Number of Allocations in the array.
+     * @return Allocation[]
+     */
+    public static Allocation[] createAllocations(RenderScript rs, Type t, int usage, int numAlloc) {
+        try {
+            Trace.traceBegin(RenderScript.TRACE_TAG, "createAllocations");
+            rs.validate();
+            if (t.getID(rs) == 0) {
+                throw new RSInvalidStateException("Bad Type");
+            }
+
+            Allocation[] mAllocationArray = new Allocation[numAlloc];
+            mAllocationArray[0] = createTyped(rs, t, usage);
+            if ((usage & USAGE_IO_INPUT) != 0) {
+                if (numAlloc > MAX_NUMBER_IO_INPUT_ALLOC) {
+                    throw new RSIllegalArgumentException("Exceeds the max number of Allocations allowed: " +
+                                                         MAX_NUMBER_IO_INPUT_ALLOC);
+                }
+                mAllocationArray[0].setupBufferQueue(numAlloc);;
+            }
+
+            for (int i=1; i<numAlloc; i++) {
+                mAllocationArray[i] = createFromAllcation(rs, mAllocationArray[0]);
+            }
+            return mAllocationArray;
+        } finally {
+            Trace.traceEnd(RenderScript.TRACE_TAG);
+        }
+    }
+
+    /**
+     * Creates a new Allocation with the given {@link
+     * android.renderscript.Allocation}. The same data layout of
+     * the input Allocation will be applied.
+     * If the input allocation is of usage: USAGE_IO_INPUT, the created
+     * Allocation will be sharing the same BufferQueue.
+     *
+     * @param rs Context to which the allocation will belong.
+     * @param alloc RenderScript Allocation describing data layout.
+     * @return Allocation sharing the same data structure.
+     */
+    static Allocation createFromAllcation(RenderScript rs, Allocation alloc) {
+        try {
+            Trace.traceBegin(RenderScript.TRACE_TAG, "createFromAllcation");
+            rs.validate();
+            if (alloc.getID(rs) == 0) {
+                throw new RSInvalidStateException("Bad input Allocation");
+            }
+
+            Type type = alloc.getType();
+            int usage = alloc.getUsage();
+            MipmapControl mips = alloc.getMipmap();
+            long id = rs.nAllocationCreateTyped(type.getID(rs), mips.mID, usage, 0);
+            if (id == 0) {
+                throw new RSRuntimeException("Allocation creation failed.");
+            }
+            Allocation outAlloc = new Allocation(id, rs, type, usage, mips);
+            if ((usage & USAGE_IO_INPUT) != 0) {
+                outAlloc.shareBufferQueue(alloc);
+            }
+            return outAlloc;
+        } finally {
+            Trace.traceEnd(RenderScript.TRACE_TAG);
+        }
+    }
+
+    /**
+     * Initialize BufferQueue with specified max number of buffers.
+     */
+    void setupBufferQueue(int numAlloc) {
+        mRS.validate();
+        if ((mUsage & USAGE_IO_INPUT) == 0) {
+            throw new RSInvalidStateException("Allocation is not USAGE_IO_INPUT.");
+        }
+        mRS.nAllocationSetupBufferQueue(getID(mRS), numAlloc);
+    }
+
+    /**
+     * Share the BufferQueue with another {@link #USAGE_IO_INPUT} Allocation.
+     *
+     * @param alloc Allocation to associate with allocation
+     */
+    void shareBufferQueue(Allocation alloc) {
+        mRS.validate();
+        if ((mUsage & USAGE_IO_INPUT) == 0) {
+            throw new RSInvalidStateException("Allocation is not USAGE_IO_INPUT.");
+        }
+        mGetSurfaceSurface = alloc.getSurface();
+        mRS.nAllocationShareBufferQueue(getID(mRS), alloc.getID(mRS));
+    }
+
+    /**
+     * Gets the stride of the Allocation.
+     * For a 2D or 3D Allocation, the raw data maybe padded so that each row of
+     * the Allocation has certain alignment. The size of each row including such
+     * padding is called stride.
+     *
+     * @return the stride. For 1D Allocation, the stride will be the number of
+     *         bytes of this Allocation. For 2D and 3D Allocations, the stride
+     *         will be the stride in X dimension measuring in bytes.
+     */
+    public long getStride() {
+        if (mByteBufferStride == -1) {
+            getByteBuffer();
+        }
+        return mByteBufferStride;
+    }
+
+    /**
+     * Get the timestamp for the most recent buffer held by this Allocation.
+     * The timestamp is guaranteed to be unique and monotonically increasing.
+     * Default value: -1. The timestamp will be updated after each {@link
+     * #ioReceive ioReceive()} call.
+     *
+     * It can be used to identify the images by comparing the unique timestamps
+     * when used with {@link android.hardware.camera2} APIs.
+     * Example steps:
+     *   1. Save {@link android.hardware.camera2.TotalCaptureResult} when the
+     *      capture is completed.
+     *   2. Get the timestamp after {@link #ioReceive ioReceive()} call.
+     *   3. Comparing totalCaptureResult.get(CaptureResult.SENSOR_TIMESTAMP) with
+     *      alloc.getTimeStamp().
+     * @return long Timestamp associated with the buffer held by the Allocation.
+     */
+    public long getTimeStamp() {
+        return mTimeStamp;
+    }
+
+    /**
      * Returns the handle to a raw buffer that is being managed by the screen
      * compositor. This operation is only valid for Allocations with {@link
      * #USAGE_IO_INPUT}.
@@ -2153,7 +2349,7 @@
         if(id == 0) {
             throw new RSRuntimeException("Load failed for bitmap " + b + " element " + e);
         }
-        return new Allocation(id, rs, t, usage);
+        return new Allocation(id, rs, t, usage, mips);
     }
 
     /**
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 7eb8005..51fc7dd 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -18,17 +18,18 @@
 
 import java.io.File;
 import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 import android.content.Context;
 import android.content.res.AssetManager;
 import android.graphics.Bitmap;
 import android.graphics.SurfaceTexture;
-import android.util.Log;
-import android.view.Surface;
 import android.os.SystemProperties;
 import android.os.Trace;
-import java.util.ArrayList;
+import android.util.Log;
+import android.view.Surface;
 
 // TODO: Clean up the whitespace that separates methods in this class.
 
@@ -483,12 +484,28 @@
         rsnAllocationCopyToBitmap(mContext, alloc, bmp);
     }
 
-
     native void rsnAllocationSyncAll(long con, long alloc, int src);
     synchronized void nAllocationSyncAll(long alloc, int src) {
         validate();
         rsnAllocationSyncAll(mContext, alloc, src);
     }
+
+    native ByteBuffer rsnAllocationGetByteBuffer(long con, long alloc, long[] stride, int xBytesSize, int dimY, int dimZ);
+    synchronized ByteBuffer nAllocationGetByteBuffer(long alloc, long[] stride, int xBytesSize, int dimY, int dimZ) {
+        validate();
+        return rsnAllocationGetByteBuffer(mContext, alloc, stride, xBytesSize, dimY, dimZ);
+    }
+
+    native void rsnAllocationSetupBufferQueue(long con, long alloc, int numAlloc);
+    synchronized void nAllocationSetupBufferQueue(long alloc, int numAlloc) {
+        validate();
+        rsnAllocationSetupBufferQueue(mContext, alloc, numAlloc);
+    }
+    native void rsnAllocationShareBufferQueue(long con, long alloc1, long alloc2);
+    synchronized void nAllocationShareBufferQueue(long alloc1, long alloc2) {
+        validate();
+        rsnAllocationShareBufferQueue(mContext, alloc1, alloc2);
+    }
     native Surface rsnAllocationGetSurface(long con, long alloc);
     synchronized Surface nAllocationGetSurface(long alloc) {
         validate();
@@ -504,13 +521,12 @@
         validate();
         rsnAllocationIoSend(mContext, alloc);
     }
-    native void rsnAllocationIoReceive(long con, long alloc);
-    synchronized void nAllocationIoReceive(long alloc) {
+    native long rsnAllocationIoReceive(long con, long alloc);
+    synchronized long nAllocationIoReceive(long alloc) {
         validate();
-        rsnAllocationIoReceive(mContext, alloc);
+        return rsnAllocationIoReceive(mContext, alloc);
     }
 
-
     native void rsnAllocationGenerateMipmaps(long con, long alloc);
     synchronized void nAllocationGenerateMipmaps(long alloc) {
         validate();
@@ -751,6 +767,14 @@
         rsnScriptReduce(mContext, id, slot, ain, aout, limits);
     }
 
+    native void rsnScriptReduceNew(long con, long id, int slot, long[] ains,
+                                   long aout, int[] limits);
+    synchronized void nScriptReduceNew(long id, int slot, long ains[], long aout,
+                                       int[] limits) {
+        validate();
+        rsnScriptReduceNew(mContext, id, slot, ains, aout, limits);
+    }
+
     native void rsnScriptInvokeV(long con, long id, int slot, byte[] params);
     synchronized void nScriptInvokeV(long id, int slot, byte[] params) {
         validate();
diff --git a/rs/java/android/renderscript/Script.java b/rs/java/android/renderscript/Script.java
index ed4c6c7..2b06780 100644
--- a/rs/java/android/renderscript/Script.java
+++ b/rs/java/android/renderscript/Script.java
@@ -284,7 +284,7 @@
     }
 
     /**
-     * Only intended for use by generated reflected code.
+     * Only intended for use by generated reflected code.  (Simple reduction)
      *
      * @hide
      */
@@ -312,6 +312,45 @@
         mRS.nScriptReduce(getID(mRS), slot, in_id, out_id, limits);
     }
 
+    /**
+     * Only intended for use by generated reflected code.  (General reduction)
+     *
+     */
+    protected void reduce(int slot, Allocation[] ains, Allocation aout, LaunchOptions sc) {
+        mRS.validate();
+        if (ains == null || ains.length < 1) {
+            throw new RSIllegalArgumentException(
+                "At least one input is required.");
+        }
+        if (aout == null) {
+            throw new RSIllegalArgumentException(
+                "aout is required to be non-null.");
+        }
+        for (Allocation ain : ains) {
+            mRS.validateObject(ain);
+        }
+
+        long[] in_ids = new long[ains.length];
+        for (int index = 0; index < ains.length; ++index) {
+            in_ids[index] = ains[index].getID(mRS);
+        }
+        long out_id = aout.getID(mRS);
+
+        int[] limits = null;
+        if (sc != null) {
+            limits = new int[6];
+
+            limits[0] = sc.xstart;
+            limits[1] = sc.xend;
+            limits[2] = sc.ystart;
+            limits[3] = sc.yend;
+            limits[4] = sc.zstart;
+            limits[5] = sc.zend;
+        }
+
+        mRS.nScriptReduceNew(getID(mRS), slot, in_ids, out_id, limits);
+    }
+
     long[] mInIdsBuffer;
 
     Script(long id, RenderScript rs) {
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 113241d..3dff37b 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -1223,6 +1223,27 @@
     rsAllocationSyncAll((RsContext)con, (RsAllocation)a, (RsAllocationUsageType)bits);
 }
 
+static void
+nAllocationSetupBufferQueue(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jint numAlloc)
+{
+    if (kLogApi) {
+        ALOGD("nAllocationSetupBufferQueue, con(%p), alloc(%p), numAlloc(%d)", (RsContext)con,
+              (RsAllocation)alloc, numAlloc);
+    }
+    rsAllocationSetupBufferQueue((RsContext)con, (RsAllocation)alloc, (uint32_t)numAlloc);
+}
+
+static void
+nAllocationShareBufferQueue(JNIEnv *_env, jobject _this, jlong con, jlong alloc1, jlong alloc2)
+{
+    if (kLogApi) {
+        ALOGD("nAllocationShareBufferQueue, con(%p), alloc1(%p), alloc2(%p)", (RsContext)con,
+              (RsAllocation)alloc1, (RsAllocation)alloc2);
+    }
+
+    rsAllocationShareBufferQueue((RsContext)con, (RsAllocation)alloc1, (RsAllocation)alloc2);
+}
+
 static jobject
 nAllocationGetSurface(JNIEnv *_env, jobject _this, jlong con, jlong a)
 {
@@ -1265,16 +1286,15 @@
     rsAllocationIoSend((RsContext)con, (RsAllocation)alloc);
 }
 
-static void
+static jlong
 nAllocationIoReceive(JNIEnv *_env, jobject _this, jlong con, jlong alloc)
 {
     if (kLogApi) {
         ALOGD("nAllocationIoReceive, con(%p), alloc(%p)", (RsContext)con, (RsAllocation)alloc);
     }
-    rsAllocationIoReceive((RsContext)con, (RsAllocation)alloc);
+    return (jlong) rsAllocationIoReceive((RsContext)con, (RsAllocation)alloc);
 }
 
-
 static void
 nAllocationGenerateMipmaps(JNIEnv *_env, jobject _this, jlong con, jlong alloc)
 {
@@ -1988,7 +2008,6 @@
 
         if (sizeof(RsAllocation) == sizeof(jlong)) {
             in_allocs = (RsAllocation*)in_ptr;
-
         } else {
             // Convert from 64-bit jlong types to the native pointer type.
 
@@ -2127,6 +2146,101 @@
     }
 }
 
+static void
+nScriptReduceNew(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot,
+                 jlongArray ains, jlong aout, jintArray limits)
+{
+    if (kLogApi) {
+        ALOGD("nScriptReduceNew, con(%p), s(%p), slot(%i) ains(%p) aout(%" PRId64 ")", (RsContext)con, (void *)script, slot, ains, aout);
+    }
+
+    if (ains == nullptr) {
+        ALOGE("At least one input required.");
+        // TODO (b/20758983): Report back to Java and throw an exception
+        return;
+    }
+    jint in_len = _env->GetArrayLength(ains);
+    if (in_len > (jint)RS_KERNEL_MAX_ARGUMENTS) {
+        ALOGE("Too many arguments in kernel launch.");
+        // TODO (b/20758983): Report back to Java and throw an exception
+        return;
+    }
+
+    jlong *in_ptr = _env->GetLongArrayElements(ains, nullptr);
+    if (in_ptr == nullptr) {
+        ALOGE("Failed to get Java array elements");
+        // TODO (b/20758983): Report back to Java and throw an exception
+        return;
+    }
+
+    RsAllocation *in_allocs = nullptr;
+    if (sizeof(RsAllocation) == sizeof(jlong)) {
+        in_allocs = (RsAllocation*)in_ptr;
+    } else {
+        // Convert from 64-bit jlong types to the native pointer type.
+
+        in_allocs = (RsAllocation*)alloca(in_len * sizeof(RsAllocation));
+        if (in_allocs == nullptr) {
+            ALOGE("Failed launching kernel for lack of memory.");
+            // TODO (b/20758983): Report back to Java and throw an exception
+            _env->ReleaseLongArrayElements(ains, in_ptr, JNI_ABORT);
+            return;
+        }
+
+        for (int index = in_len; --index >= 0;) {
+            in_allocs[index] = (RsAllocation)in_ptr[index];
+        }
+    }
+
+    RsScriptCall sc, *sca = nullptr;
+    uint32_t sc_size = 0;
+
+    jint  limit_len = 0;
+    jint *limit_ptr = nullptr;
+
+    if (limits != nullptr) {
+        limit_len = _env->GetArrayLength(limits);
+        limit_ptr = _env->GetIntArrayElements(limits, nullptr);
+        if (limit_ptr == nullptr) {
+            ALOGE("Failed to get Java array elements");
+            // TODO (b/20758983): Report back to Java and throw an exception
+            return;
+        }
+
+        assert(limit_len == 6);
+        UNUSED(limit_len);  // As the assert might not be compiled.
+
+        sc.xStart     = limit_ptr[0];
+        sc.xEnd       = limit_ptr[1];
+        sc.yStart     = limit_ptr[2];
+        sc.yEnd       = limit_ptr[3];
+        sc.zStart     = limit_ptr[4];
+        sc.zEnd       = limit_ptr[5];
+        sc.strategy   = RS_FOR_EACH_STRATEGY_DONT_CARE;
+        sc.arrayStart = 0;
+        sc.arrayEnd = 0;
+        sc.array2Start = 0;
+        sc.array2End = 0;
+        sc.array3Start = 0;
+        sc.array3End = 0;
+        sc.array4Start = 0;
+        sc.array4End = 0;
+
+        sca = &sc;
+        sc_size = sizeof(sc);
+    }
+
+    rsScriptReduceNew((RsContext)con, (RsScript)script, slot,
+                      in_allocs, in_len, (RsAllocation)aout,
+                      sca, sc_size);
+
+    _env->ReleaseLongArrayElements(ains, in_ptr, JNI_ABORT);
+
+    if (limits != nullptr) {
+        _env->ReleaseIntArrayElements(limits, limit_ptr, JNI_ABORT);
+    }
+}
+
 // -----------------------------------
 
 static jlong
@@ -2658,7 +2772,43 @@
     return (jint)sizeof(void*);
 }
 
+static jobject
+nAllocationGetByteBuffer(JNIEnv *_env, jobject _this, jlong con, jlong alloc,
+                        jlongArray strideArr, jint xBytesSize,
+                        jint dimY, jint dimZ) {
+    if (kLogApi) {
+        ALOGD("nAllocationGetByteBuffer, con(%p), alloc(%p)", (RsContext)con, (RsAllocation)alloc);
+    }
 
+    jlong *jStridePtr = _env->GetLongArrayElements(strideArr, nullptr);
+    if (jStridePtr == nullptr) {
+        ALOGE("Failed to get Java array elements: strideArr");
+        return 0;
+    }
+
+    size_t strideIn = xBytesSize;
+    void* ptr = nullptr;
+    if (alloc != 0) {
+        ptr = rsAllocationGetPointer((RsContext)con, (RsAllocation)alloc, 0,
+                                     RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, 0, 0,
+                                     &strideIn, sizeof(size_t));
+    }
+
+    jobject byteBuffer = nullptr;
+    if (ptr != nullptr) {
+        size_t bufferSize = strideIn;
+        jStridePtr[0] = strideIn;
+        if (dimY > 0) {
+            bufferSize *= dimY;
+        }
+        if (dimZ > 0) {
+            bufferSize *= dimZ;
+        }
+        byteBuffer = _env->NewDirectByteBuffer(ptr, (jlong) bufferSize);
+    }
+    _env->ReleaseLongArrayElements(strideArr, jStridePtr, 0);
+    return byteBuffer;
+}
 // ---------------------------------------------------------------------------
 
 
@@ -2726,10 +2876,12 @@
 {"rsnAllocationCopyToBitmap",        "(JJLandroid/graphics/Bitmap;)V",        (void*)nAllocationCopyToBitmap },
 
 {"rsnAllocationSyncAll",             "(JJI)V",                                (void*)nAllocationSyncAll },
+{"rsnAllocationSetupBufferQueue",    "(JJI)V",                                (void*)nAllocationSetupBufferQueue },
+{"rsnAllocationShareBufferQueue",    "(JJJ)V",                                (void*)nAllocationShareBufferQueue },
 {"rsnAllocationGetSurface",          "(JJ)Landroid/view/Surface;",            (void*)nAllocationGetSurface },
 {"rsnAllocationSetSurface",          "(JJLandroid/view/Surface;)V",           (void*)nAllocationSetSurface },
 {"rsnAllocationIoSend",              "(JJ)V",                                 (void*)nAllocationIoSend },
-{"rsnAllocationIoReceive",           "(JJ)V",                                 (void*)nAllocationIoReceive },
+{"rsnAllocationIoReceive",           "(JJ)J",                                 (void*)nAllocationIoReceive },
 {"rsnAllocationData1D",              "(JJIIILjava/lang/Object;IIIZ)V",        (void*)nAllocationData1D },
 {"rsnAllocationElementData",         "(JJIIIII[BI)V",                         (void*)nAllocationElementData },
 {"rsnAllocationData2D",              "(JJIIIIIILjava/lang/Object;IIIZ)V",     (void*)nAllocationData2D },
@@ -2755,6 +2907,7 @@
 
 {"rsnScriptForEach",                 "(JJI[JJ[B[I)V",                         (void*)nScriptForEach },
 {"rsnScriptReduce",                  "(JJIJJ[I)V",                            (void*)nScriptReduce },
+{"rsnScriptReduceNew",               "(JJI[JJ[I)V",                           (void*)nScriptReduceNew },
 
 {"rsnScriptSetVarI",                 "(JJII)V",                               (void*)nScriptSetVarI },
 {"rsnScriptGetVarI",                 "(JJI)I",                                (void*)nScriptGetVarI },
@@ -2814,6 +2967,7 @@
 {"rsnMeshGetIndices",                "(JJ[J[II)V",                            (void*)nMeshGetIndices },
 
 {"rsnSystemGetPointerSize",          "()I",                                   (void*)nSystemGetPointerSize },
+{"rsnAllocationGetByteBuffer",       "(JJ[JIII)Ljava/nio/ByteBuffer;",        (void*)nAllocationGetByteBuffer },
 };
 
 static int registerFuncs(JNIEnv *_env)
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
index 28121b4..e310801 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
@@ -64,6 +64,14 @@
     // Indicates that motion events are being collected to match a gesture.
     private boolean mRecognizingGesture;
 
+    // Indicates that motion events from the second pointer are being checked
+    // for a double tap.
+    private boolean mSecondFingerDoubleTap;
+
+    // Tracks the most recent time where ACTION_POINTER_DOWN was sent for the
+    // second pointer.
+    private long mSecondPointerDownTime;
+
     // Policy flags of the previous event.
     private int mPolicyFlags;
 
@@ -102,6 +110,7 @@
         switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
                 mDoubleTapDetected = false;
+                mSecondFingerDoubleTap = false;
                 mRecognizingGesture = true;
                 mPreviousX = x;
                 mPreviousY = y;
@@ -133,6 +142,43 @@
                     }
                 }
                 break;
+
+            case MotionEvent.ACTION_POINTER_DOWN:
+                // Once a second finger is used, we're definitely not
+                // recognizing a gesture.
+                cancelGesture();
+
+                if (event.getPointerCount() == 2) {
+                    // If this was the second finger, attempt to recognize double
+                    // taps on it.
+                    mSecondFingerDoubleTap = true;
+                    mSecondPointerDownTime = event.getEventTime();
+                } else {
+                    // If there are more than two fingers down, stop watching
+                    // for a double tap.
+                    mSecondFingerDoubleTap = false;
+                }
+                break;
+
+            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;
+                }
+                break;
+        }
+
+        // If we're detecting taps on the second finger, map events from the
+        // finger to the first finger.
+        if (mSecondFingerDoubleTap) {
+            MotionEvent newEvent = mapSecondPointerToFirstPointer(event);
+            if (newEvent == null) {
+                return false;
+            }
+            boolean handled = mGestureDetector.onTouchEvent(newEvent);
+            newEvent.recycle();
+            return handled;
         }
 
         if (!mRecognizingGesture) {
@@ -146,6 +192,7 @@
     public void clear() {
         mFirstTapDetected = false;
         mDoubleTapDetected = false;
+        mSecondFingerDoubleTap = false;
         cancelGesture();
         mStrokeBuffer.clear();
     }
@@ -229,4 +276,28 @@
 
         return false;
     }
+
+    private MotionEvent mapSecondPointerToFirstPointer(MotionEvent event) {
+        // Only map basic events when two fingers are down.
+        if (event.getPointerCount() != 2 ||
+                (event.getActionMasked() != MotionEvent.ACTION_POINTER_DOWN &&
+                 event.getActionMasked() != MotionEvent.ACTION_POINTER_UP &&
+                 event.getActionMasked() != MotionEvent.ACTION_MOVE)) {
+            return null;
+        }
+
+        int action = event.getActionMasked();
+
+        if (action == MotionEvent.ACTION_POINTER_DOWN) {
+            action = MotionEvent.ACTION_DOWN;
+        } else if (action == MotionEvent.ACTION_POINTER_UP) {
+            action = MotionEvent.ACTION_UP;
+        }
+
+        // Map the information from the second pointer to the first.
+        return MotionEvent.obtain(mSecondPointerDownTime, event.getEventTime(), action,
+                event.getX(1), event.getY(1), event.getPressure(1), event.getSize(1),
+                event.getMetaState(), event.getXPrecision(), event.getYPrecision(),
+                event.getDeviceId(), event.getEdgeFlags());
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 5f6cbf9..232c080 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -69,6 +69,13 @@
      */
     static final int FLAG_FEATURE_AUTOCLICK = 0x00000008;
 
+    /**
+     * Flag for enabling motion event injectsion
+     *
+     * @see #setUserAndEnabledFeatures(int, int)
+     */
+    static final int FLAG_FEATURE_INJECT_MOTION_EVENTS = 0x00000010;
+
     private final Runnable mProcessBatchedEventsRunnable = new Runnable() {
         @Override
         public void run() {
@@ -104,6 +111,8 @@
 
     private MagnificationGestureHandler mMagnificationGestureHandler;
 
+    private MotionEventInjector mMotionEventInjector;
+
     private AutoclickController mAutoclickController;
 
     private KeyboardInterceptor mKeyboardInterceptor;
@@ -191,6 +200,10 @@
         }
     }
 
+    public MotionEventInjector getMotionEventInjector() {
+        return mMotionEventInjector;
+    }
+
     /**
      * Gets current event stream state associated with an input event.
      * @return The event stream state that should be used for the event. Null if the event should
@@ -351,6 +364,12 @@
     private void enableFeatures() {
         resetStreamState();
 
+        if ((mEnabledFeatures & FLAG_FEATURE_INJECT_MOTION_EVENTS) != 0) {
+            mMotionEventInjector = new MotionEventInjector(mContext.getMainLooper());
+            addFirstEventHandler(mMotionEventInjector);
+            mAms.setMotionEventInjector(mMotionEventInjector);
+        }
+
         if ((mEnabledFeatures & FLAG_FEATURE_AUTOCLICK) != 0) {
             mAutoclickController = new AutoclickController(mContext, mUserId);
             addFirstEventHandler(mAutoclickController);
@@ -388,6 +407,11 @@
     }
 
     private void disableFeatures() {
+        if (mMotionEventInjector != null) {
+            mAms.setMotionEventInjector(null);
+            mMotionEventInjector.onDestroy();
+            mMotionEventInjector = null;
+        }
         if (mAutoclickController != null) {
             mAutoclickController.onDestroy();
             mAutoclickController = null;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 8cf25b3..03809c0 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -37,6 +37,7 @@
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
@@ -72,6 +73,7 @@
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.MagnificationSpec;
+import android.view.MotionEvent;
 import android.view.WindowInfo;
 import android.view.WindowManager;
 import android.view.WindowManagerInternal;
@@ -186,6 +188,8 @@
 
     private KeyEventDispatcher mKeyEventDispatcher;
 
+    private MotionEventInjector mMotionEventInjector;
+
     private final Set<ComponentName> mTempComponentNameSet = new HashSet<>();
 
     private final List<AccessibilityServiceInfo> mTempAccessibilityServiceInfoList =
@@ -711,7 +715,7 @@
     }
 
     @Override
-    public IBinder getWindowToken(int windowId) {
+    public IBinder getWindowToken(int windowId, int userId) {
         mSecurityPolicy.enforceCallingPermission(
                 Manifest.permission.RETRIEVE_WINDOW_TOKEN,
                 GET_WINDOW_TOKEN);
@@ -720,8 +724,7 @@
             // share the accessibility state of the parent. The call below
             // performs the current profile parent resolution.
             final int resolvedUserId = mSecurityPolicy
-                    .resolveCallingUserIdEnforcingPermissionsLocked(
-                            UserHandle.getCallingUserId());
+                    .resolveCallingUserIdEnforcingPermissionsLocked(userId);
             if (resolvedUserId != mCurrentUserId) {
                 return null;
             }
@@ -779,6 +782,18 @@
     }
 
     /**
+     * Called by AccessibilityInputFilter when it creates or destroys the motionEventInjector.
+     * Not using a getter because the AccessibilityInputFilter isn't thread-safe
+     *
+     * @param motionEventInjector The new value of the motionEventInjector. May be null.
+     */
+    void setMotionEventInjector(MotionEventInjector motionEventInjector) {
+        synchronized (mLock) {
+            mMotionEventInjector = motionEventInjector;
+        }
+    }
+
+    /**
      * Gets a point within the accessibility focused node where we can send down
      * and up events to perform a click.
      *
@@ -1189,8 +1204,13 @@
             }
             builder.append(componentName.flattenToShortString());
         }
-        Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                settingName, builder.toString(), userId);
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                    settingName, builder.toString(), userId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 
     private void manageServicesLocked(UserState userState) {
@@ -1235,8 +1255,13 @@
         if (isEnabled && userState.mBoundServices.isEmpty()
                 && userState.mBindingServices.isEmpty()) {
             userState.mIsAccessibilityEnabled = false;
-            Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                    Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId);
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                        Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
         }
     }
 
@@ -1273,6 +1298,9 @@
             if (userState.mIsAutoclickEnabled) {
                 flags |= AccessibilityInputFilter.FLAG_FEATURE_AUTOCLICK;
             }
+            if (userState.mIsPerformGesturesEnabled) {
+                flags |= AccessibilityInputFilter.FLAG_FEATURE_INJECT_MOTION_EVENTS;
+            }
             if (flags != 0) {
                 if (!mHasInputFilter) {
                     mHasInputFilter = true;
@@ -1324,9 +1352,14 @@
                          // Enable touch exploration.
                          UserState userState = getUserStateLocked(service.mUserId);
                          userState.mIsTouchExplorationEnabled = true;
-                         Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                                 Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1,
-                                 service.mUserId);
+                         final long identity = Binder.clearCallingIdentity();
+                         try {
+                             Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                                     Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1,
+                                     service.mUserId);
+                         } finally {
+                             Binder.restoreCallingIdentity(identity);
+                         }
                          onUserStateChangedLocked(userState);
                      }
                  })
@@ -1363,6 +1396,7 @@
         updateAccessibilityFocusBehaviorLocked(userState);
         updateFilterKeyEventsLocked(userState);
         updateTouchExplorationLocked(userState);
+        updatePerformGesturesLocked(userState);
         updateEnhancedWebAccessibilityLocked(userState);
         updateDisplayColorAdjustmentSettingsLocked(userState);
         updateMagnificationLocked(userState);
@@ -1451,6 +1485,19 @@
         }
     }
 
+    private void updatePerformGesturesLocked(UserState userState) {
+        final int serviceCount = userState.mBoundServices.size();
+        for (int i = 0; i < serviceCount; i++) {
+            Service service = userState.mBoundServices.get(i);
+            if ((service.mAccessibilityServiceInfo.getCapabilities()
+                    & AccessibilityServiceInfo.CAPABILITY_CAN_PERFORM_GESTURES) != 0) {
+                userState.mIsPerformGesturesEnabled = true;
+                return;
+            }
+        }
+        userState.mIsPerformGesturesEnabled = false;
+    }
+
     private void updateFilterKeyEventsLocked(UserState userState) {
         final int serviceCount = userState.mBoundServices.size();
         for (int i = 0; i < serviceCount; i++) {
@@ -1581,9 +1628,14 @@
         }
         if (enabled != userState.mIsTouchExplorationEnabled) {
             userState.mIsTouchExplorationEnabled = enabled;
-            Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                    Settings.Secure.TOUCH_EXPLORATION_ENABLED, enabled ? 1 : 0,
-                    userState.mUserId);
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                        Settings.Secure.TOUCH_EXPLORATION_ENABLED, enabled ? 1 : 0,
+                        userState.mUserId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
         }
     }
 
@@ -1634,9 +1686,14 @@
         }
         if (enabled != userState.mIsEnhancedWebAccessibilityEnabled) {
             userState.mIsEnhancedWebAccessibilityEnabled = enabled;
-            Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                    Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, enabled ? 1 : 0,
-                    userState.mUserId);
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                        Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, enabled ? 1 : 0,
+                        userState.mUserId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
         }
     }
 
@@ -2147,6 +2204,24 @@
             return true;
         }
 
+        @Override
+        public void disableSelf() {
+            synchronized(mLock) {
+                UserState userState = getUserStateLocked(mUserId);
+                if (userState.mEnabledServices.remove(mComponentName)) {
+                    final long identity = Binder.clearCallingIdentity();
+                    try {
+                        persistComponentNamesToSettingLocked(
+                                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                                userState.mEnabledServices, mUserId);
+                    } finally {
+                        Binder.restoreCallingIdentity(identity);
+                    }
+                    onUserStateChangedLocked(userState);
+                }
+            }
+        }
+
         public boolean canReceiveEventsLocked() {
             return (mEventTypes != 0 && mFeedbackType != 0 && mService != null);
         }
@@ -2564,6 +2639,23 @@
         }
 
         @Override
+        public void sendMotionEvents(int sequence, ParceledListSlice events) {
+            synchronized (mLock) {
+                if (mSecurityPolicy.canPerformGestures(this) && (mMotionEventInjector != null)) {
+                    mMotionEventInjector.injectEvents((List<MotionEvent>) events.getList(),
+                            mServiceInterface, sequence);
+                    return;
+                }
+            }
+            try {
+                mServiceInterface.onPerformGestureResult(sequence, false);
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG, "Error sending motion event injection failure to "
+                        + mServiceInterface, re);
+            }
+        }
+
+        @Override
         public boolean performAccessibilityAction(int accessibilityWindowId,
                 long accessibilityNodeId, int action, Bundle arguments, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
@@ -3734,6 +3826,11 @@
                     & AccessibilityServiceInfo.CAPABILITY_CAN_CONTROL_MAGNIFICATION) != 0;
         }
 
+        public boolean canPerformGestures(Service service) {
+            return (service.mAccessibilityServiceInfo.getCapabilities()
+                    & AccessibilityServiceInfo.CAPABILITY_CAN_PERFORM_GESTURES) != 0;
+        }
+
         private int resolveProfileParentLocked(int userId) {
             if (userId != mCurrentUserId) {
                 final long identity = Binder.clearCallingIdentity();
@@ -3878,6 +3975,7 @@
         public boolean mIsEnhancedWebAccessibilityEnabled;
         public boolean mIsDisplayMagnificationEnabled;
         public boolean mIsAutoclickEnabled;
+        public boolean mIsPerformGesturesEnabled;
         public boolean mIsFilterKeyEventsEnabled;
         public boolean mHasDisplayColorAdjustment;
         public boolean mAccessibilityFocusOnlyInActiveWindow;
diff --git a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
new file mode 100644
index 0000000..800f0e1
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.accessibility;
+
+import android.accessibilityservice.IAccessibilityServiceClient;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.InputDevice;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.WindowManagerPolicy;
+import android.view.accessibility.AccessibilityEvent;
+import com.android.internal.os.SomeArgs;
+import com.android.server.accessibility.AccessibilityManagerService.Service;
+
+import java.util.List;
+
+/**
+ * Injects MotionEvents to permit {@code AccessibilityService}s to touch the screen on behalf of
+ * users.
+ *
+ * All methods except {@code injectEvents} must be called only from the main thread.
+ */
+public class MotionEventInjector implements EventStreamTransformation {
+    private static final String LOG_TAG = "MotionEventInjector";
+    private static final int MESSAGE_SEND_MOTION_EVENT = 1;
+    private static final int MESSAGE_INJECT_EVENTS = 2;
+    private static final int MAX_POINTERS = 11; // Non-binding maximum
+
+    private final Handler mHandler;
+    private final SparseArray<Boolean> mOpenGesturesInProgress = new SparseArray<>();
+
+    // These two arrays must be the same length
+    private MotionEvent.PointerProperties[] mPointerProperties =
+            new MotionEvent.PointerProperties[MAX_POINTERS];
+    private MotionEvent.PointerCoords[] mPointerCoords =
+            new MotionEvent.PointerCoords[MAX_POINTERS];
+    private EventStreamTransformation mNext;
+    private IAccessibilityServiceClient mServiceInterfaceForCurrentGesture;
+    private int mSequenceForCurrentGesture;
+    private int mSourceOfInjectedGesture = InputDevice.SOURCE_UNKNOWN;
+    private boolean mIsDestroyed = false;
+
+    /**
+     * @param looper A looper on the main thread to use for dispatching new events
+     */
+    public MotionEventInjector(Looper looper) {
+        mHandler = new Handler(looper, new Callback());
+    }
+
+    /**
+     * Schedule a series of events for injection. These events must comprise a complete, valid
+     * sequence. All gestures currently in progress will be cancelled, and all {@code downTime}
+     * and {@code eventTime} fields will be offset by the current time.
+     *
+     * @param events The events to inject. Must all be from the same source.
+     * @param serviceInterface The interface to call back with a result when the gesture is
+     * either complete or cancelled.
+     */
+    public void injectEvents(List<MotionEvent> events,
+            IAccessibilityServiceClient serviceInterface, int sequence) {
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = events;
+        args.arg2 = serviceInterface;
+        args.argi1 = sequence;
+        mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_INJECT_EVENTS, args));
+    }
+
+    @Override
+    public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        cancelAnyPendingInjectedEvents();
+        sendMotionEventToNext(event, rawEvent, policyFlags);
+    }
+
+    @Override
+    public void onKeyEvent(KeyEvent event, int policyFlags) {
+        if (mNext != null) {
+            mNext.onKeyEvent(event, policyFlags);
+        }
+    }
+
+    @Override
+    public void onAccessibilityEvent(AccessibilityEvent event) {
+        if (mNext != null) {
+            mNext.onAccessibilityEvent(event);
+        }
+    }
+
+    @Override
+    public void setNext(EventStreamTransformation next) {
+        mNext = next;
+    }
+
+    @Override
+    public void clearEvents(int inputSource) {
+        /*
+         * Reset state for motion events passing through so we won't send a cancel event for
+         * them.
+         */
+        if (!mHandler.hasMessages(MESSAGE_SEND_MOTION_EVENT)) {
+            mOpenGesturesInProgress.put(inputSource, false);
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        cancelAnyPendingInjectedEvents();
+        mIsDestroyed = true;
+    }
+
+    private void injectEventsMainThread(List<MotionEvent> events,
+            IAccessibilityServiceClient serviceInterface, int sequence) {
+        if (mIsDestroyed) {
+            try {
+                serviceInterface.onPerformGestureResult(sequence, false);
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG, "Error sending status with mIsDestroyed to " + serviceInterface,
+                        re);
+            }
+            return;
+        }
+        cancelAnyPendingInjectedEvents();
+        mSourceOfInjectedGesture = events.get(0).getSource();
+        cancelAnyGestureInProgress(mSourceOfInjectedGesture);
+        mServiceInterfaceForCurrentGesture = serviceInterface;
+        mSequenceForCurrentGesture = sequence;
+        if (mNext == null) {
+            notifyService(false);
+            return;
+        }
+
+        long startTime = SystemClock.uptimeMillis();
+        for (int i = 0; i < events.size(); i++) {
+            MotionEvent event = events.get(i);
+            int numPointers = event.getPointerCount();
+            if (numPointers > mPointerCoords.length) {
+                mPointerCoords = new MotionEvent.PointerCoords[numPointers];
+                mPointerProperties = new MotionEvent.PointerProperties[numPointers];
+            }
+            for (int j = 0; j < numPointers; j++) {
+                if (mPointerCoords[j] == null) {
+                    mPointerCoords[j] = new MotionEvent.PointerCoords();
+                    mPointerProperties[j] = new MotionEvent.PointerProperties();
+                }
+                event.getPointerCoords(j, mPointerCoords[j]);
+                event.getPointerProperties(j, mPointerProperties[j]);
+            }
+
+            /*
+             * MotionEvent doesn't have a setEventTime() method (it carries around history data,
+             * which could become inconsistent), so we need to obtain a new one.
+             */
+            MotionEvent offsetEvent = MotionEvent.obtain(startTime + event.getDownTime(),
+                    startTime + event.getEventTime(), event.getAction(), numPointers,
+                    mPointerProperties, mPointerCoords, event.getMetaState(),
+                    event.getButtonState(), event.getXPrecision(), event.getYPrecision(),
+                    event.getDeviceId(), event.getEdgeFlags(), event.getSource(),
+                    event.getFlags());
+            Message message = mHandler.obtainMessage(MESSAGE_SEND_MOTION_EVENT, offsetEvent);
+            mHandler.sendMessageDelayed(message, event.getEventTime());
+        }
+    }
+
+    private void sendMotionEventToNext(MotionEvent event, MotionEvent rawEvent,
+            int policyFlags) {
+        if (mNext != null) {
+            mNext.onMotionEvent(event, rawEvent, policyFlags);
+            if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+                mOpenGesturesInProgress.put(event.getSource(), true);
+            }
+            if ((event.getActionMasked() == MotionEvent.ACTION_UP)
+                    || (event.getActionMasked() == MotionEvent.ACTION_CANCEL)) {
+                mOpenGesturesInProgress.put(event.getSource(), false);
+            }
+        }
+    }
+
+    private void cancelAnyGestureInProgress(int source) {
+        if ((mNext != null) && mOpenGesturesInProgress.get(source, false)) {
+            long now = SystemClock.uptimeMillis();
+            MotionEvent cancelEvent =
+                    MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
+            sendMotionEventToNext(cancelEvent, cancelEvent,
+                    WindowManagerPolicy.FLAG_PASS_TO_USER);
+        }
+    }
+
+    private void cancelAnyPendingInjectedEvents() {
+        if (mHandler.hasMessages(MESSAGE_SEND_MOTION_EVENT)) {
+            cancelAnyGestureInProgress(mSourceOfInjectedGesture);
+            mHandler.removeMessages(MESSAGE_SEND_MOTION_EVENT);
+            notifyService(false);
+        }
+
+    }
+
+    private void notifyService(boolean success) {
+        try {
+            mServiceInterfaceForCurrentGesture.onPerformGestureResult(
+                    mSequenceForCurrentGesture, success);
+        } catch (RemoteException re) {
+            Slog.e(LOG_TAG, "Error sending motion event injection status to "
+                    + mServiceInterfaceForCurrentGesture, re);
+        }
+    }
+
+    private class Callback implements Handler.Callback {
+        @Override
+        public boolean handleMessage(Message message) {
+            if (message.what == MESSAGE_INJECT_EVENTS) {
+                SomeArgs args = (SomeArgs) message.obj;
+                injectEventsMainThread((List<MotionEvent>) args.arg1,
+                        (IAccessibilityServiceClient) args.arg2, args.argi1);
+                args.recycle();
+                return true;
+            }
+            if (message.what != MESSAGE_SEND_MOTION_EVENT) {
+                throw new IllegalArgumentException("Unknown message: " + message.what);
+            }
+            MotionEvent motionEvent = (MotionEvent) message.obj;
+            sendMotionEventToNext(motionEvent, motionEvent,
+                    WindowManagerPolicy.FLAG_PASS_TO_USER);
+            // If the message queue is now empty, then this gesture is complete
+            if (!mHandler.hasMessages(MESSAGE_SEND_MOTION_EVENT)) {
+                notifyService(true);
+            }
+            return true;
+        }
+    }
+}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index df18d3e..db901aa 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -76,6 +76,7 @@
 import android.view.WindowManager;
 import android.widget.RemoteViews;
 
+import com.android.internal.R;
 import com.android.internal.appwidget.IAppWidgetHost;
 import com.android.internal.appwidget.IAppWidgetService;
 import com.android.internal.os.BackgroundThread;
@@ -83,7 +84,6 @@
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.widget.IRemoteViewsAdapterConnection;
 import com.android.internal.widget.IRemoteViewsFactory;
-import com.android.internal.R;
 import com.android.server.LocalServices;
 import com.android.server.WidgetBackupProvider;
 
@@ -139,8 +139,10 @@
     private static final int CURRENT_VERSION = 1;
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
         public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
+            final String action = intent.getAction();
+            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
 
             if (DEBUG) {
                 Slog.i(TAG, "Received broadcast: " + action);
@@ -148,23 +150,16 @@
 
             if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
                 onConfigurationChanged();
-            } else if (Intent.ACTION_USER_STARTED.equals(action)) {
-                onUserStarted(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
-                        UserHandle.USER_NULL));
+            } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
+                onUserUnlocked(userId);
             } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
-                onUserStopped(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
-                        UserHandle.USER_NULL));
+                onUserStopped(userId);
             } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-                refreshProfileWidgetsMaskedState(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
-                        UserHandle.USER_NULL));
+                refreshProfileWidgetsMaskedState(userId);
             } else if (Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED.equals(action)) {
-                UserHandle profile = (UserHandle)intent.getParcelableExtra(Intent.EXTRA_USER);
-                if (profile != null) {
-                    refreshWidgetMaskedState(profile.getIdentifier());
-                }
+                refreshWidgetMaskedState(userId);
             } else {
-                onPackageBroadcastReceived(intent, intent.getIntExtra(
-                        Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL));
+                onPackageBroadcastReceived(intent, userId);
             }
         }
     };
@@ -263,7 +258,7 @@
                 sdFilter, null, null);
 
         IntentFilter userFilter = new IntentFilter();
-        userFilter.addAction(Intent.ACTION_USER_STARTED);
+        userFilter.addAction(Intent.ACTION_USER_UNLOCKED);
         userFilter.addAction(Intent.ACTION_USER_STOPPED);
         userFilter.addAction(Intent.ACTION_USER_SWITCHED);
         mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
@@ -340,6 +335,8 @@
     }
 
     private void onPackageBroadcastReceived(Intent intent, int userId) {
+        if (!mUserManager.isUserUnlocked(userId)) return;
+
         final String action = intent.getAction();
         boolean added = false;
         boolean changed = false;
@@ -419,9 +416,7 @@
      * Refresh the masked state for all profiles under the given user.
      */
     private void refreshProfileWidgetsMaskedState(int userId) {
-        if (userId == UserHandle.USER_NULL) {
-            return;
-        }
+        if (!mUserManager.isUserUnlocked(userId)) return;
         List<UserInfo> profiles = mUserManager.getEnabledProfiles(userId);
         if (profiles != null) {
             for (int i = 0; i < profiles.size(); i++) {
@@ -435,6 +430,7 @@
      * Mask/unmask widgets in the given profile, depending on the quiet state of the profile.
      */
     private void refreshWidgetMaskedState(int profileId) {
+        if (!mUserManager.isUserUnlocked(profileId)) return;
         final long identity = Binder.clearCallingIdentity();
         try {
             UserInfo user  = mUserManager.getUserInfo(profileId);
@@ -484,6 +480,11 @@
     }
 
     private void ensureGroupStateLoadedLocked(int userId) {
+        if (!mUserManager.isUserUnlocked(userId)) {
+            throw new IllegalStateException(
+                    "User " + userId + " must be unlocked for widgets to be available");
+        }
+
         final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId);
 
         // Careful lad, we may have already loaded the state for some
@@ -2204,9 +2205,11 @@
             final Resources resources;
             final long identity = Binder.clearCallingIdentity();
             try {
-                resources = mContext.getPackageManager()
-                        .getResourcesForApplicationAsUser(activityInfo.packageName,
-                                UserHandle.getUserId(providerId.uid));
+                final PackageManager pm = mContext.getPackageManager();
+                final int userId = UserHandle.getUserId(providerId.uid);
+                final ApplicationInfo app = pm.getApplicationInfoAsUser(activityInfo.packageName,
+                        PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
+                resources = pm.getResourcesForApplication(app);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -2307,6 +2310,10 @@
         try {
             int flags = PackageManager.GET_META_DATA;
 
+            // We really need packages to be around and parsed to know if they
+            // provide widgets, and we only load widgets after user is unlocked.
+            flags |= PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+
             // Widgets referencing shared libraries need to have their
             // dependencies loaded.
             flags |= PackageManager.GET_SHARED_LIBRARY_FILES;
@@ -2321,7 +2328,7 @@
         }
     }
 
-    private void onUserStarted(int userId) {
+    private void onUserUnlocked(int userId) {
         synchronized (mLock) {
             ensureGroupStateLoadedLocked(userId);
 
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 2264c69..0513e53 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -27,9 +27,12 @@
 import android.app.backup.BackupAgent;
 import android.app.backup.BackupDataInput;
 import android.app.backup.BackupDataOutput;
+import android.app.backup.BackupManager;
+import android.app.backup.BackupProgress;
 import android.app.backup.BackupTransport;
 import android.app.backup.FullBackup;
 import android.app.backup.FullBackupDataOutput;
+import android.app.backup.IBackupObserver;
 import android.app.backup.RestoreDescription;
 import android.app.backup.RestoreSet;
 import android.app.backup.IBackupManager;
@@ -217,6 +220,7 @@
     private static final int MSG_RETRY_CLEAR = 12;
     private static final int MSG_WIDGET_BROADCAST = 13;
     private static final int MSG_RUN_FULL_TRANSPORT_BACKUP = 14;
+    private static final int MSG_REQUEST_BACKUP = 15;
 
     // backup task state machine tick
     static final int MSG_BACKUP_RESTORE_STEP = 20;
@@ -239,6 +243,11 @@
     // How long between attempts to perform a full-data backup of any given app
     static final long MIN_FULL_BACKUP_INTERVAL = 1000 * 60 * 60 * 24; // one day
 
+    // If an app is busy when we want to do a full-data backup, how long to defer the retry.
+    // This is fuzzed, so there are two parameters; backoff_min + Rand[0, backoff_fuzz)
+    static final long BUSY_BACKOFF_MIN_MILLIS = 1000 * 60 * 60;  // one hour
+    static final int BUSY_BACKOFF_FUZZ = 1000 * 60 * 60 * 2;  // two hours
+
     Context mContext;
     private PackageManager mPackageManager;
     IPackageManager mPackageManagerBinder;
@@ -527,6 +536,25 @@
         }
     }
 
+    class BackupParams {
+        public IBackupTransport transport;
+        public String dirName;
+        public ArrayList<String> kvPackages;
+        public ArrayList<String> fullPackages;
+        public IBackupObserver observer;
+        public boolean userInitiated;
+
+        BackupParams(IBackupTransport transport, String dirName, ArrayList<String> kvPackages,
+                ArrayList<String> fullPackages, IBackupObserver observer, boolean userInitiated) {
+            this.transport = transport;
+            this.dirName = dirName;
+            this.kvPackages = kvPackages;
+            this.fullPackages = fullPackages;
+            this.observer = observer;
+            this.userInitiated = userInitiated;
+        }
+    }
+
     // Bookkeeping of in-flight operations for timeout etc. purposes.  The operation
     // token is the index of the entry in the pending-operations list.
     static final int OP_PENDING = 0;
@@ -648,8 +676,13 @@
         return true;
     }
 
+    // Checks if the app is in a stopped state, that means it won't receive broadcasts.
+    private static boolean appIsStopped(ApplicationInfo app) {
+        return ((app.flags & ApplicationInfo.FLAG_STOPPED) != 0);
+    }
+
     /* does *not* check overall backup eligibility policy! */
-    public static boolean appGetsFullBackup(PackageInfo pkg) {
+    private static boolean appGetsFullBackup(PackageInfo pkg) {
         if (pkg.applicationInfo.backupAgentName != null) {
             // If it has an agent, it gets full backups only if it says so
             return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0;
@@ -714,7 +747,7 @@
                     try {
                         String dirName = transport.transportDirName();
                         PerformBackupTask pbt = new PerformBackupTask(transport, dirName,
-                                queue, oldJournal);
+                                queue, oldJournal, null, null, false);
                         Message pbtMessage = obtainMessage(MSG_BACKUP_RESTORE_STEP, pbt);
                         sendMessage(pbtMessage);
                     } catch (RemoteException e) {
@@ -937,6 +970,26 @@
                 mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
                 break;
             }
+
+            case MSG_REQUEST_BACKUP:
+            {
+                BackupParams params = (BackupParams)msg.obj;
+                if (MORE_DEBUG) {
+                    Slog.d(TAG, "MSG_REQUEST_BACKUP observer=" + params.observer);
+                }
+                ArrayList<BackupRequest> kvQueue = new ArrayList<>();
+                for (String packageName : params.kvPackages) {
+                    kvQueue.add(new BackupRequest(packageName));
+                }
+                mBackupRunning = true;
+                mWakelock.acquire();
+
+                PerformBackupTask pbt = new PerformBackupTask(params.transport, params.dirName,
+                    kvQueue, null, params.observer, params.fullPackages, true);
+                Message pbtMessage = obtainMessage(MSG_BACKUP_RESTORE_STEP, pbt);
+                sendMessage(pbtMessage);
+                break;
+            }
             }
         }
     }
@@ -1867,7 +1920,9 @@
                 synchronized (mBackupParticipants) {
                     if (replacing) {
                         // This is the package-replaced case; we just remove the entry
-                        // under the old uid and fall through to re-add.
+                        // under the old uid and fall through to re-add.  If an app
+                        // just added key/value backup participation, this picks it up
+                        // as a known participant.
                         removePackageParticipantsLocked(pkgList, uid);
                     }
                     addPackageParticipantsLocked(pkgList);
@@ -1880,6 +1935,14 @@
                         if (appGetsFullBackup(app) && appIsEligibleForBackup(app.applicationInfo)) {
                             enqueueFullBackup(packageName, now);
                             scheduleNextFullBackupJob(0);
+                        } else {
+                            // The app might have just transitioned out of full-data into
+                            // doing key/value backups, or might have just disabled backups
+                            // entirely.  Make sure it is no longer in the full-data queue.
+                            synchronized (mQueueLock) {
+                                dequeueFullBackupLocked(packageName);
+                            }
+                            writeFullBackupScheduleAsync();
                         }
 
                         // Transport maintenance: rebind to known existing transports that have
@@ -1911,6 +1974,9 @@
                 if (replacing) {
                     // The package is being updated.  We'll receive a PACKAGE_ADDED shortly.
                 } else {
+                    // Outright removal.  In the full-data case, the app will be dropped
+                    // from the queue when its (now obsolete) name comes up again for
+                    // backup.
                     synchronized (mBackupParticipants) {
                         removePackageParticipantsLocked(pkgList, uid);
                     }
@@ -2325,6 +2391,63 @@
         return token;
     }
 
+    public int requestBackup(String[] packages, IBackupObserver observer) {
+        mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "requestBackup");
+
+        if (packages == null || packages.length < 1) {
+            Slog.e(TAG, "No packages named for backup request");
+            sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
+            throw new IllegalArgumentException("No packages are provided for backup");
+        }
+
+        IBackupTransport transport = getTransport(mCurrentTransport);
+        if (transport == null) {
+            sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
+            return BackupManager.ERROR_TRANSPORT_ABORTED;
+        }
+
+        ArrayList<String> fullBackupList = new ArrayList<>();
+        ArrayList<String> kvBackupList = new ArrayList<>();
+        for (String packageName : packages) {
+            try {
+                PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName,
+                        PackageManager.GET_SIGNATURES);
+                if (!appIsEligibleForBackup(packageInfo.applicationInfo)) {
+                    sendBackupOnResult(observer, packageName,
+                            BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+                    continue;
+                }
+                if (appGetsFullBackup(packageInfo)) {
+                    fullBackupList.add(packageInfo.packageName);
+                } else {
+                    kvBackupList.add(packageInfo.packageName);
+                }
+            } catch (NameNotFoundException e) {
+                sendBackupOnResult(observer, packageName, BackupManager.ERROR_PACKAGE_NOT_FOUND);
+            }
+        }
+        EventLog.writeEvent(EventLogTags.BACKUP_REQUESTED, packages.length, kvBackupList.size(),
+                fullBackupList.size());
+        if (MORE_DEBUG) {
+            Slog.i(TAG, "Backup requested for " + packages.length + " packages, of them: " +
+                fullBackupList.size() + " full backups, " + kvBackupList.size() + " k/v backups");
+        }
+
+        String dirName;
+        try {
+            dirName = transport.transportDirName();
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Transport became unavailable while attempting backup");
+            sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
+            return BackupManager.ERROR_TRANSPORT_ABORTED;
+        }
+        Message msg = mBackupHandler.obtainMessage(MSG_REQUEST_BACKUP);
+        msg.obj = new BackupParams(transport, dirName, kvBackupList, fullBackupList, observer,
+                true);
+        mBackupHandler.sendMessage(msg);
+        return BackupManager.SUCCESS;
+    }
+
     // -----
     // Interface and methods used by the asynchronous-with-timeout backup/restore operations
 
@@ -2424,6 +2547,8 @@
         File mStateDir;
         File mJournal;
         BackupState mCurrentState;
+        ArrayList<String> mPendingFullBackups;
+        IBackupObserver mObserver;
 
         // carried information about the current in-flight operation
         IBackupAgent mAgentBinder;
@@ -2436,12 +2561,17 @@
         ParcelFileDescriptor mNewState;
         int mStatus;
         boolean mFinished;
+        boolean mUserInitiated;
 
         public PerformBackupTask(IBackupTransport transport, String dirName,
-                ArrayList<BackupRequest> queue, File journal) {
+                ArrayList<BackupRequest> queue, File journal, IBackupObserver observer,
+                ArrayList<String> pendingFullBackups, boolean userInitiated) {
             mTransport = transport;
             mOriginalQueue = queue;
             mJournal = journal;
+            mObserver = observer;
+            mPendingFullBackups = pendingFullBackups;
+            mUserInitiated = userInitiated;
 
             mStateDir = new File(mBaseStateDir, dirName);
 
@@ -2493,9 +2623,10 @@
             mStatus = BackupTransport.TRANSPORT_OK;
 
             // Sanity check: if the queue is empty we have no work to do.
-            if (mOriginalQueue.isEmpty()) {
+            if (mOriginalQueue.isEmpty() && mPendingFullBackups.isEmpty()) {
                 Slog.w(TAG, "Backup begun with an empty queue - nothing to do.");
                 addBackupTrace("queue empty at begin");
+                sendBackupFinished(mObserver, BackupManager.SUCCESS);
                 executeNextState(BackupState.FINAL);
                 return;
             }
@@ -2579,6 +2710,8 @@
                     // if things went wrong at this point, we need to
                     // restage everything and try again later.
                     resetBackupState(mStateDir);  // Just to make sure.
+                    // In case of any other error, it's backup transport error.
+                    sendBackupFinished(mObserver, BackupManager.ERROR_TRANSPORT_ABORTED);
                     executeNextState(BackupState.FINAL);
                 }
             }
@@ -2620,6 +2753,10 @@
                     Slog.i(TAG, "Package " + request.packageName
                             + " no longer supports backup; skipping");
                     addBackupTrace("skipping - not eligible, completion is noop");
+                    // Shouldn't happen in case of requested backup, as pre-check was done in
+                    // #requestBackup(), except to app update done concurrently
+                    sendBackupOnResult(mObserver, mCurrentPackage.packageName,
+                        BackupManager.ERROR_BACKUP_NOT_ALLOWED);
                     executeNextState(BackupState.RUNNING_QUEUE);
                     return;
                 }
@@ -2631,15 +2768,21 @@
                     Slog.i(TAG, "Package " + request.packageName
                             + " requests full-data rather than key/value; skipping");
                     addBackupTrace("skipping - fullBackupOnly, completion is noop");
+                    // Shouldn't happen in case of requested backup, as pre-check was done in
+                    // #requestBackup()
+                    sendBackupOnResult(mObserver, mCurrentPackage.packageName,
+                        BackupManager.ERROR_BACKUP_NOT_ALLOWED);
                     executeNextState(BackupState.RUNNING_QUEUE);
                     return;
                 }
 
-                if ((mCurrentPackage.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0) {
+                if (appIsStopped(mCurrentPackage.applicationInfo)) {
                     // The app has been force-stopped or cleared or just installed,
                     // and not yet launched out of that state, so just as it won't
                     // receive broadcasts, we won't run it for backup.
                     addBackupTrace("skipping - stopped");
+                    sendBackupOnResult(mObserver, mCurrentPackage.packageName,
+                        BackupManager.ERROR_BACKUP_NOT_ALLOWED);
                     executeNextState(BackupState.RUNNING_QUEUE);
                     return;
                 }
@@ -2687,10 +2830,14 @@
                         dataChangedImpl(request.packageName);
                         mStatus = BackupTransport.TRANSPORT_OK;
                         if (mQueue.isEmpty()) nextState = BackupState.FINAL;
+                        sendBackupOnResult(mObserver, mCurrentPackage.packageName,
+                            BackupManager.ERROR_AGENT_FAILURE);
                     } else if (mStatus == BackupTransport.AGENT_UNKNOWN) {
                         // Failed lookup of the app, so we couldn't bring up an agent, but
                         // we're otherwise fine.  Just drop it and go on to the next as usual.
                         mStatus = BackupTransport.TRANSPORT_OK;
+                        sendBackupOnResult(mObserver, mCurrentPackage.packageName,
+                            BackupManager.ERROR_PACKAGE_NOT_FOUND);
                     } else {
                         // Transport-level failure means we reenqueue everything
                         revertAndEndBackup();
@@ -2745,9 +2892,37 @@
                 }
             }
 
-            // Only once we're entirely finished do we release the wakelock
             clearBackupTrace();
-            Slog.i(BackupManagerService.TAG, "Backup pass finished.");
+
+            if (mStatus == BackupTransport.TRANSPORT_OK &&
+                    mPendingFullBackups != null && !mPendingFullBackups.isEmpty()) {
+                Slog.d(TAG, "Starting full backups for: " + mPendingFullBackups);
+                CountDownLatch latch = new CountDownLatch(1);
+                String[] fullBackups =
+                        mPendingFullBackups.toArray(new String[mPendingFullBackups.size()]);
+                PerformFullTransportBackupTask task =
+                        new PerformFullTransportBackupTask(/*fullBackupRestoreObserver*/ null,
+                                fullBackups, /*updateSchedule*/ false, /*runningJob*/ null, latch,
+                                mObserver, mUserInitiated);
+                // Acquiring wakelock for PerformFullTransportBackupTask before its start.
+                mWakelock.acquire();
+                (new Thread(task, "full-transport-requested")).start();
+            } else {
+                switch (mStatus) {
+                    case BackupTransport.TRANSPORT_OK:
+                        sendBackupFinished(mObserver, BackupManager.SUCCESS);
+                        break;
+                    case BackupTransport.TRANSPORT_NOT_INITIALIZED:
+                        sendBackupFinished(mObserver, BackupManager.ERROR_TRANSPORT_ABORTED);
+                        break;
+                    case BackupTransport.TRANSPORT_ERROR:
+                    default:
+                        sendBackupFinished(mObserver, BackupManager.ERROR_TRANSPORT_ABORTED);
+                        break;
+                }
+            }
+            Slog.i(BackupManagerService.TAG, "K/V backup pass finished.");
+            // Only once we're entirely finished do we release the wakelock for k/v backup.
             mWakelock.release();
         }
 
@@ -2954,6 +3129,8 @@
                                 EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, pkgName,
                                         "bad key");
                                 mBackupHandler.removeMessages(MSG_TIMEOUT);
+                                sendBackupOnResult(mObserver, pkgName,
+                                        BackupManager.ERROR_AGENT_FAILURE);
                                 agentErrorCleanup();
                                 // agentErrorCleanup() implicitly executes next state properly
                                 return;
@@ -2991,14 +3168,16 @@
 
             ParcelFileDescriptor backupData = null;
             mStatus = BackupTransport.TRANSPORT_OK;
+            long size = 0;
             try {
-                int size = (int) mBackupDataName.length();
+                size = mBackupDataName.length();
                 if (size > 0) {
                     if (mStatus == BackupTransport.TRANSPORT_OK) {
                         backupData = ParcelFileDescriptor.open(mBackupDataName,
                                 ParcelFileDescriptor.MODE_READ_ONLY);
                         addBackupTrace("sending data to transport");
-                        mStatus = mTransport.performBackup(mCurrentPackage, backupData);
+                        int flags = mUserInitiated ? BackupTransport.FLAG_USER_INITIATED : 0;
+                        mStatus = mTransport.performBackup(mCurrentPackage, backupData, flags);
                     }
 
                     // TODO - We call finishBackup() for each application backed up, because
@@ -3025,6 +3204,7 @@
                     // with the new state file it just created.
                     mBackupDataName.delete();
                     mNewStateName.renameTo(mSavedStateName);
+                    sendBackupOnResult(mObserver, pkgName, BackupManager.SUCCESS);
                     EventLog.writeEvent(EventLogTags.BACKUP_PACKAGE, pkgName, size);
                     logBackupComplete(pkgName);
                 } else if (mStatus == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
@@ -3032,12 +3212,20 @@
                     // back but proceed with running the rest of the queue.
                     mBackupDataName.delete();
                     mNewStateName.delete();
+                    sendBackupOnResult(mObserver, pkgName,
+                            BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
                     EventLogTags.writeBackupAgentFailure(pkgName, "Transport rejected");
+                } else if (mStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
+                    sendBackupOnResult(mObserver, pkgName,
+                            BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED);
+                    EventLog.writeEvent(EventLogTags.BACKUP_QUOTA_EXCEEDED, pkgName);
                 } else {
                     // Actual transport-level failure to communicate the data to the backend
+                    sendBackupOnResult(mObserver, pkgName, BackupManager.ERROR_TRANSPORT_ABORTED);
                     EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, pkgName);
                 }
             } catch (Exception e) {
+                sendBackupOnResult(mObserver, pkgName, BackupManager.ERROR_TRANSPORT_ABORTED);
                 Slog.e(TAG, "Transport error backing up " + pkgName, e);
                 EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_FAILURE, pkgName);
                 mStatus = BackupTransport.TRANSPORT_ERROR;
@@ -3051,6 +3239,20 @@
                 // Success or single-package rejection.  Proceed with the next app if any,
                 // otherwise we're done.
                 nextState = (mQueue.isEmpty()) ? BackupState.FINAL : BackupState.RUNNING_QUEUE;
+            } else if (mStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
+                if (MORE_DEBUG) {
+                    Slog.d(TAG, "Package " + mCurrentPackage.packageName +
+                            " hit quota limit on k/v backup");
+                }
+                if (mAgentBinder != null) {
+                    try {
+                        long quota = mTransport.getBackupQuota(mCurrentPackage.packageName, false);
+                        mAgentBinder.doQuotaExceeded(size, quota);
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "Unable to contact backup agent for quota exceeded");
+                    }
+                }
+                nextState = (mQueue.isEmpty()) ? BackupState.FINAL : BackupState.RUNNING_QUEUE;
             } else {
                 // Any other error here indicates a transport-level failure.  That means
                 // we need to halt everything and reschedule everything for next time.
@@ -3285,12 +3487,15 @@
          *         or one of the other BackupTransport.* error codes as appropriate
          */
         int preflightFullBackup(PackageInfo pkg, IBackupAgent agent);
+
+        long expectedSize();
     };
 
     class FullBackupEngine {
         OutputStream mOutput;
         FullBackupPreflight mPreflightHook;
         IFullBackupRestoreObserver mObserver;
+        IBackupAgent mAgent;
         File mFilesDir;
         File mManifestFile;
         File mMetadataFile;
@@ -3377,14 +3582,14 @@
             int result = BackupTransport.TRANSPORT_OK;
             Slog.d(TAG, "Binding to full backup agent : " + pkg.packageName);
 
-            IBackupAgent agent = bindToAgentSynchronous(pkg.applicationInfo,
+            mAgent = bindToAgentSynchronous(pkg.applicationInfo,
                     IApplicationThread.BACKUP_MODE_FULL);
-            if (agent != null) {
+            if (mAgent != null) {
                 ParcelFileDescriptor[] pipes = null;
                 try {
                     // Call the preflight hook, if any
                     if (mPreflightHook != null) {
-                        result = mPreflightHook.preflightFullBackup(pkg, agent);
+                        result = mPreflightHook.preflightFullBackup(pkg, mAgent);
                         if (MORE_DEBUG) {
                             Slog.v(TAG, "preflight returned " + result);
                         }
@@ -3407,7 +3612,7 @@
                                 UserHandle.USER_SYSTEM);
 
                         final int token = generateToken();
-                        FullBackupRunner runner = new FullBackupRunner(pkg, agent, pipes[1],
+                        FullBackupRunner runner = new FullBackupRunner(pkg, mAgent, pipes[1],
                                 token, sendApk, !isSharedStorage, widgetBlob);
                         pipes[1].close();   // the runner has dup'd it
                         pipes[1] = null;
@@ -3455,6 +3660,16 @@
             return result;
         }
 
+        public void sendQuotaExceeded(final long backupDataBytes, final long quotaBytes) {
+            if (mAgent != null) {
+                try {
+                    mAgent.doQuotaExceeded(backupDataBytes, quotaBytes);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Remote exception while telling agent about quota exceeded");
+                }
+            }
+        }
+
         private void writeApkToBackup(PackageInfo pkg, FullBackupDataOutput output) {
             // Forward-locked apps, system-bundled .apks, etc are filtered out before we get here
             // TODO: handle backing up split APKs
@@ -3992,45 +4207,56 @@
         CountDownLatch mLatch;
         AtomicBoolean mKeepRunning;     // signal from job scheduler
         FullBackupJob mJob;             // if a scheduled job needs to be finished afterwards
+        IBackupObserver mBackupObserver;
+        boolean mUserInitiated;
 
         PerformFullTransportBackupTask(IFullBackupRestoreObserver observer, 
                 String[] whichPackages, boolean updateSchedule,
-                FullBackupJob runningJob, CountDownLatch latch) {
+                FullBackupJob runningJob, CountDownLatch latch, IBackupObserver backupObserver,
+                boolean userInitiated) {
             super(observer);
             mUpdateSchedule = updateSchedule;
             mLatch = latch;
             mKeepRunning = new AtomicBoolean(true);
             mJob = runningJob;
             mPackages = new ArrayList<PackageInfo>(whichPackages.length);
+            mBackupObserver = backupObserver;
+            mUserInitiated = userInitiated;
 
             for (String pkg : whichPackages) {
                 try {
                     PackageInfo info = mPackageManager.getPackageInfo(pkg,
                             PackageManager.GET_SIGNATURES);
-                    if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0
-                            || pkg.equals(SHARED_BACKUP_AGENT_PACKAGE)) {
+                    if (!appIsEligibleForBackup(info.applicationInfo)) {
                         // Cull any packages that have indicated that backups are not permitted,
+                        // that run as system-domain uids but do not define their own backup agents,
                         // as well as any explicit mention of the 'special' shared-storage agent
                         // package (we handle that one at the end).
                         if (MORE_DEBUG) {
-                            Slog.d(TAG, "Ignoring opted-out package " + pkg);
+                            Slog.d(TAG, "Ignoring ineligible package " + pkg);
                         }
+                        sendBackupOnResult(mBackupObserver, pkg,
+                            BackupManager.ERROR_BACKUP_NOT_ALLOWED);
                         continue;
-                    } else if ((info.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
-                            && (info.applicationInfo.backupAgentName == null)) {
-                        // Cull any packages that run as system-domain uids but do not define their
-                        // own backup agents
+                    } else if (!appGetsFullBackup(info)) {
+                        // Cull any packages that are found in the queue but now aren't supposed
+                        // to get full-data backup operations.
                         if (MORE_DEBUG) {
-                            Slog.d(TAG, "Ignoring non-agent system package " + pkg);
+                            Slog.d(TAG, "Ignoring full-data backup of key/value participant "
+                                    + pkg);
                         }
+                        sendBackupOnResult(mBackupObserver, pkg,
+                                BackupManager.ERROR_BACKUP_NOT_ALLOWED);
                         continue;
-                    } else if ((info.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0) {
+                    } else if (appIsStopped(info.applicationInfo)) {
                         // Cull any packages in the 'stopped' state: they've either just been
                         // installed or have explicitly been force-stopped by the user.  In both
                         // cases we do not want to launch them for backup.
                         if (MORE_DEBUG) {
                             Slog.d(TAG, "Ignoring stopped package " + pkg);
                         }
+                        sendBackupOnResult(mBackupObserver, pkg,
+                                BackupManager.ERROR_BACKUP_NOT_ALLOWED);
                         continue;
                     }
                     mPackages.add(info);
@@ -4063,17 +4289,20 @@
                                 + " p=" + mProvisioned + "; ignoring");
                     }
                     mUpdateSchedule = false;
+                    sendBackupFinished(mBackupObserver, BackupManager.ERROR_BACKUP_NOT_ALLOWED);
                     return;
                 }
 
                 IBackupTransport transport = getTransport(mCurrentTransport);
                 if (transport == null) {
                     Slog.w(TAG, "Transport not present; full data backup not performed");
+                    sendBackupFinished(mBackupObserver, BackupManager.ERROR_TRANSPORT_ABORTED);
                     return;
                 }
 
                 // Set up to send data to the transport
                 final int N = mPackages.size();
+                final byte[] buffer = new byte[8192];
                 for (int i = 0; i < N; i++) {
                     currentPackage = mPackages.get(i);
                     if (DEBUG) {
@@ -4086,8 +4315,9 @@
                     transportPipes = ParcelFileDescriptor.createPipe();
 
                     // Tell the transport the data's coming
+                    int flags = mUserInitiated ? BackupTransport.FLAG_USER_INITIATED : 0;
                     int result = transport.performFullBackup(currentPackage,
-                            transportPipes[0]);
+                            transportPipes[0], flags);
                     if (result == BackupTransport.TRANSPORT_OK) {
                         // The transport has its own copy of the read end of the pipe,
                         // so close ours now
@@ -4114,7 +4344,13 @@
                                 enginePipes[0].getFileDescriptor());
                         FileOutputStream out = new FileOutputStream(
                                 transportPipes[1].getFileDescriptor());
-                        byte[] buffer = new byte[8192];
+                        long totalRead = 0;
+                        final long expectedSize = backupRunner.expectedSize();
+                        if (expectedSize < 0) {
+                            result = BackupTransport.AGENT_ERROR;
+                            sendBackupOnResult(mBackupObserver, currentPackage.packageName,
+                                    BackupManager.ERROR_AGENT_FAILURE);
+                        }
                         int nRead = 0;
                         do {
                             if (!mKeepRunning.get()) {
@@ -4130,9 +4366,23 @@
                             if (nRead > 0) {
                                 out.write(buffer, 0, nRead);
                                 result = transport.sendBackupData(nRead);
+                                totalRead += nRead;
+                                if (mBackupObserver != null && expectedSize > 0) {
+                                    sendBackupOnUpdate(mBackupObserver, currentPackage.packageName,
+                                        new BackupProgress(expectedSize, totalRead));
+                                }
                             }
                         } while (nRead > 0 && result == BackupTransport.TRANSPORT_OK);
 
+                        if (result == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
+                            long quota = transport.getBackupQuota(currentPackage.packageName, true);
+                            if (MORE_DEBUG) {
+                                Slog.d(TAG, "Package hit quota limit " + currentPackage.packageName
+                                        + ": " + totalRead + " of " + quota);
+                            }
+                            backupRunner.sendQuotaExceeded(totalRead, quota);
+                        }
+
                         // If we've lost our running criteria, tell the transport to cancel
                         // and roll back this (partial) backup payload; otherwise tell it
                         // that we've reached the clean finish state.
@@ -4176,6 +4426,8 @@
                     }
 
                     if (result == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
+                        sendBackupOnResult(mBackupObserver, currentPackage.packageName,
+                            BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
                         if (DEBUG) {
                             Slog.i(TAG, "Transport rejected backup of "
                                     + currentPackage.packageName
@@ -4184,12 +4436,23 @@
                         EventLog.writeEvent(EventLogTags.FULL_BACKUP_AGENT_FAILURE,
                                 currentPackage.packageName, "transport rejected");
                         // do nothing, clean up, and continue looping
+                    } else if (result == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
+                        sendBackupOnResult(mBackupObserver, currentPackage.packageName,
+                            BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED);
+                        Slog.w(TAG, "Transport quota exceeded; aborting backup: " + result);
+                        EventLog.writeEvent(EventLogTags.FULL_BACKUP_QUOTA_EXCEEDED,
+                                currentPackage.packageName);
+                        return;
                     } else if (result != BackupTransport.TRANSPORT_OK) {
+                        sendBackupOnResult(mBackupObserver, currentPackage.packageName,
+                            BackupManager.ERROR_TRANSPORT_ABORTED);
                         Slog.w(TAG, "Transport failed; aborting backup: " + result);
                         EventLog.writeEvent(EventLogTags.FULL_BACKUP_TRANSPORT_FAILURE);
                         return;
                     } else {
                         // Success!
+                        sendBackupOnResult(mBackupObserver, currentPackage.packageName,
+                            BackupManager.SUCCESS);
                         EventLog.writeEvent(EventLogTags.FULL_BACKUP_SUCCESS,
                                 currentPackage.packageName);
                         logBackupComplete(currentPackage.packageName);
@@ -4199,10 +4462,12 @@
                     currentPackage = null;
                 }
 
+                sendBackupFinished(mBackupObserver, BackupManager.SUCCESS);
                 if (DEBUG) {
                     Slog.i(TAG, "Full backup completed.");
                 }
             } catch (Exception e) {
+                sendBackupFinished(mBackupObserver, BackupManager.ERROR_TRANSPORT_ABORTED);
                 Slog.w(TAG, "Exception trying full transport backup", e);
             } finally {
                 cleanUpPipes(transportPipes);
@@ -4216,6 +4481,7 @@
                     mRunningFullBackupTask = null;
                 }
 
+
                 mLatch.countDown();
 
                 // Now that we're actually done with schedule-driven work, reschedule
@@ -4223,6 +4489,8 @@
                 if (mUpdateSchedule) {
                     scheduleNextFullBackupJob(backoff);
                 }
+                Slog.i(BackupManagerService.TAG, "Full data backup pass finished.");
+                mWakelock.release();
             }
         }
 
@@ -4281,6 +4549,14 @@
                     }
 
                     result = mTransport.checkFullBackupSize(totalSize);
+                    if (result == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
+                        final long quota = mTransport.getBackupQuota(pkg.packageName, true);
+                        if (MORE_DEBUG) {
+                            Slog.d(TAG, "Package hit quota limit on preflight " +
+                                    pkg.packageName + ": " + totalSize + " of " + quota);
+                        }
+                        agent.doQuotaExceeded(totalSize, quota);
+                    }
                 } catch (Exception e) {
                     Slog.w(TAG, "Exception preflighting " + pkg.packageName + ": " + e.getMessage());
                     result = BackupTransport.AGENT_ERROR;
@@ -4311,7 +4587,16 @@
                 mResult.set(BackupTransport.AGENT_ERROR);
                 mLatch.countDown();
             }
-            
+
+            @Override
+            public long expectedSize() {
+                try {
+                    mLatch.await();
+                    return mResult.get();
+                } catch (InterruptedException e) {
+                    return BackupTransport.NO_MORE_DATA;
+                }
+            }
         }
 
         class SinglePackageBackupRunner implements Runnable {
@@ -4319,6 +4604,7 @@
             final PackageInfo mTarget;
             final FullBackupPreflight mPreflight;
             final CountDownLatch mLatch;
+            private FullBackupEngine mEngine;
 
             SinglePackageBackupRunner(ParcelFileDescriptor output, PackageInfo target,
                     IBackupTransport transport, CountDownLatch latch) throws IOException {
@@ -4332,9 +4618,9 @@
             public void run() {
                 try {
                     FileOutputStream out = new FileOutputStream(mOutput.getFileDescriptor());
-                    FullBackupEngine engine = new FullBackupEngine(out, mTarget.packageName,
+                    mEngine = new FullBackupEngine(out, mTarget.packageName,
                             mPreflight, false);
-                    engine.backupOnePackage(mTarget);
+                    mEngine.backupOnePackage(mTarget);
                 } catch (Exception e) {
                     Slog.e(TAG, "Exception during full package backup of " + mTarget);
                 } finally {
@@ -4346,6 +4632,14 @@
                     }
                 }
             }
+
+            public void sendQuotaExceeded(final long backupDataBytes, final long quotaBytes) {
+                mEngine.sendQuotaExceeded(backupDataBytes, quotaBytes);
+            }
+
+            long expectedSize() {
+                return mPreflight.expectedSize();
+            }
         }
     }
 
@@ -4380,21 +4674,28 @@
     }
 
     /**
+     * Remove a package from the full-data queue.
+     */
+    void dequeueFullBackupLocked(String packageName) {
+        final int N = mFullBackupQueue.size();
+        for (int i = N-1; i >= 0; i--) {
+            final FullBackupEntry e = mFullBackupQueue.get(i);
+            if (packageName.equals(e.packageName)) {
+                mFullBackupQueue.remove(i);
+            }
+        }
+    }
+
+    /**
      * Enqueue full backup for the given app, with a note about when it last ran.
      */
     void enqueueFullBackup(String packageName, long lastBackedUp) {
         FullBackupEntry newEntry = new FullBackupEntry(packageName, lastBackedUp);
         synchronized (mQueueLock) {
-            int N = mFullBackupQueue.size();
             // First, sanity check that we aren't adding a duplicate.  Slow but
             // straightforward; we'll have at most on the order of a few hundred
             // items in this list.
-            for (int i = N-1; i >= 0; i--) {
-                final FullBackupEntry e = mFullBackupQueue.get(i);
-                if (packageName.equals(e.packageName)) {
-                    mFullBackupQueue.remove(i);
-                }
-            }
+            dequeueFullBackupLocked(packageName);
 
             // This is also slow but easy for modest numbers of apps: work backwards
             // from the end of the queue until we find an item whose last backup
@@ -4488,43 +4789,95 @@
                 return false;
             }
 
-            if (mFullBackupQueue.size() == 0) {
-                // no work to do so just bow out
-                if (DEBUG) {
-                    Slog.i(TAG, "Backup queue empty; doing nothing");
-                }
-                return false;
-            }
-
-            // At this point we know that we have work to do, just not right now.  Any
-            // exit without actually running backups will also require that we
+            // At this point we think that we have work to do, but possibly not right now.
+            // Any exit without actually running backups will also require that we
             // reschedule the job.
             boolean runBackup = true;
+            boolean headBusy;
 
-            if (!fullBackupAllowable(getTransport(mCurrentTransport))) {
-                if (MORE_DEBUG) {
-                    Slog.i(TAG, "Preconditions not met; not running full backup");
-                }
-                runBackup = false;
-                // Typically this means we haven't run a key/value backup yet.  Back off
-                // full-backup operations by the key/value job's run interval so that
-                // next time we run, we are likely to be able to make progress.
-                latency = KeyValueBackupJob.BATCH_INTERVAL;
-            }
-
-            if (runBackup) {
-                entry = mFullBackupQueue.get(0);
-                long timeSinceRun = now - entry.lastBackup;
-                runBackup = (timeSinceRun >= MIN_FULL_BACKUP_INTERVAL);
-                if (!runBackup) {
-                    // It's too early to back up the next thing in the queue, so bow out
-                    if (MORE_DEBUG) {
-                        Slog.i(TAG, "Device ready but too early to back up next app");
+            do {
+                // Recheck each time, because culling due to ineligibility may
+                // have emptied the queue.
+                if (mFullBackupQueue.size() == 0) {
+                    // no work to do so just bow out
+                    if (DEBUG) {
+                        Slog.i(TAG, "Backup queue empty; doing nothing");
                     }
-                    // Wait until the next app in the queue falls due for a full data backup
-                    latency = MIN_FULL_BACKUP_INTERVAL - timeSinceRun;
+                    runBackup = false;
+                    break;
                 }
-            }
+
+                headBusy = false;
+
+                if (!fullBackupAllowable(getTransport(mCurrentTransport))) {
+                    if (MORE_DEBUG) {
+                        Slog.i(TAG, "Preconditions not met; not running full backup");
+                    }
+                    runBackup = false;
+                    // Typically this means we haven't run a key/value backup yet.  Back off
+                    // full-backup operations by the key/value job's run interval so that
+                    // next time we run, we are likely to be able to make progress.
+                    latency = KeyValueBackupJob.BATCH_INTERVAL;
+                }
+
+                if (runBackup) {
+                    entry = mFullBackupQueue.get(0);
+                    long timeSinceRun = now - entry.lastBackup;
+                    runBackup = (timeSinceRun >= MIN_FULL_BACKUP_INTERVAL);
+                    if (!runBackup) {
+                        // It's too early to back up the next thing in the queue, so bow out
+                        if (MORE_DEBUG) {
+                            Slog.i(TAG, "Device ready but too early to back up next app");
+                        }
+                        // Wait until the next app in the queue falls due for a full data backup
+                        latency = MIN_FULL_BACKUP_INTERVAL - timeSinceRun;
+                        break;  // we know we aren't doing work yet, so bail.
+                    }
+
+                    try {
+                        PackageInfo appInfo = mPackageManager.getPackageInfo(entry.packageName, 0);
+                        if (!appGetsFullBackup(appInfo)) {
+                            // The head app isn't supposed to get full-data backups [any more];
+                            // so we cull it and force a loop around to consider the new head
+                            // app.
+                            if (MORE_DEBUG) {
+                                Slog.i(TAG, "Culling package " + entry.packageName
+                                        + " in full-backup queue but not eligible");
+                            }
+                            mFullBackupQueue.remove(0);
+                            headBusy = true; // force the while() condition
+                            continue;
+                        }
+
+                        headBusy = mActivityManager.isAppForeground(appInfo.applicationInfo.uid);
+
+                        if (headBusy) {
+                            final long nextEligible = System.currentTimeMillis()
+                                    + BUSY_BACKOFF_MIN_MILLIS
+                                    + mTokenGenerator.nextInt(BUSY_BACKOFF_FUZZ);
+                            if (DEBUG_SCHEDULING) {
+                                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                                Slog.i(TAG, "Full backup time but " + entry.packageName
+                                        + " is busy; deferring to "
+                                        + sdf.format(new Date(nextEligible)));
+                            }
+                            // This relocates the app's entry from the head of the queue to
+                            // its order-appropriate position further down, so upon looping
+                            // a new candidate will be considered at the head.
+                            enqueueFullBackup(entry.packageName,
+                                    nextEligible - MIN_FULL_BACKUP_INTERVAL);
+                        }
+                    } catch (NameNotFoundException nnf) {
+                        // So, we think we want to back this up, but it turns out the package
+                        // in question is no longer installed.  We want to drop it from the
+                        // queue entirely and move on, but if there's nothing else in the queue
+                        // we should bail entirely.  headBusy cannot have been set to true yet.
+                        runBackup = (mFullBackupQueue.size() > 1);
+                    } catch (RemoteException e) {
+                        // Cannot happen; the Activity Manager is in the same process
+                    }
+                }
+            } while (headBusy);
 
             if (!runBackup) {
                 if (DEBUG_SCHEDULING) {
@@ -4539,12 +4892,14 @@
                 return false;
             }
 
-            // Okay, the top thing is runnable now.  Pop it off and get going.
+            // Okay, the top thing is ready for backup now.  Do it.
             mFullBackupQueue.remove(0);
             CountDownLatch latch = new CountDownLatch(1);
             String[] pkg = new String[] {entry.packageName};
             mRunningFullBackupTask = new PerformFullTransportBackupTask(null, pkg, true,
-                    scheduledJob, latch);
+                    scheduledJob, latch, null, false /* userInitiated */);
+            // Acquiring wakelock for PerformFullTransportBackupTask before its start.
+            mWakelock.acquire();
             (new Thread(mRunningFullBackupTask)).start();
         }
 
@@ -8702,8 +9057,10 @@
             }
 
             CountDownLatch latch = new CountDownLatch(1);
-            PerformFullTransportBackupTask task =
-                    new PerformFullTransportBackupTask(null, pkgNames, false, null, latch);
+            PerformFullTransportBackupTask task = new PerformFullTransportBackupTask(null, pkgNames,
+                    false, null, latch, null, false /* userInitiated */);
+            // Acquiring wakelock for PerformFullTransportBackupTask before its start.
+            mWakelock.acquire();
             (new Thread(task, "full-transport-master")).start();
             do {
                 try {
@@ -9280,6 +9637,32 @@
         }
     }
 
+    public boolean isAppEligibleForBackup(String packageName) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
+                "isAppEligibleForBackup");
+        try {
+            PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName,
+                    PackageManager.GET_SIGNATURES);
+            if (!appIsEligibleForBackup(packageInfo.applicationInfo) ||
+                    appIsStopped(packageInfo.applicationInfo)) {
+                return false;
+            }
+            IBackupTransport transport = getTransport(mCurrentTransport);
+            if (transport != null) {
+                try {
+                    return transport.isAppEligibleForBackup(packageInfo,
+                        appGetsFullBackup(packageInfo));
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Unable to contact transport");
+                }
+            }
+            // If transport is not present we couldn't tell that the package is not eligible.
+            return true;
+        } catch (NameNotFoundException e) {
+            return false;
+        }
+    }
+
     // ----- Restore session -----
 
     class ActiveRestoreSession extends IRestoreSession.Stub {
@@ -9727,4 +10110,42 @@
             }
         }
     }
+
+    private static void sendBackupOnUpdate(IBackupObserver observer, String packageName,
+            BackupProgress progress) {
+        if (observer != null) {
+            try {
+                observer.onUpdate(packageName, progress);
+            } catch (RemoteException e) {
+                if (DEBUG) {
+                    Slog.w(TAG, "Backup observer went away: onUpdate");
+                }
+            }
+        }
+    }
+
+    private static void sendBackupOnResult(IBackupObserver observer, String packageName,
+            int status) {
+        if (observer != null) {
+            try {
+                observer.onResult(packageName, status);
+            } catch (RemoteException e) {
+                if (DEBUG) {
+                    Slog.w(TAG, "Backup observer went away: onResult");
+                }
+            }
+        }
+    }
+
+    private static void sendBackupFinished(IBackupObserver observer, int status) {
+        if (observer != null) {
+            try {
+                observer.backupFinished(status);
+            } catch (RemoteException e) {
+                if (DEBUG) {
+                    Slog.w(TAG, "Backup observer went away: backupFinished");
+                }
+            }
+        }
+    }
 }
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index a51ab55..bbf881b 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -17,6 +17,7 @@
 package com.android.server.backup;
 
 import android.app.backup.IBackupManager;
+import android.app.backup.IBackupObserver;
 import android.app.backup.IFullBackupRestoreObserver;
 import android.app.backup.IRestoreSession;
 import android.content.Context;
@@ -325,6 +326,18 @@
     }
 
     @Override
+    public boolean isAppEligibleForBackup(String packageName) {
+        BackupManagerService svc = mService;
+        return (svc != null) ? svc.isAppEligibleForBackup(packageName) : false;
+    }
+
+    @Override
+    public int requestBackup(String[] packages, IBackupObserver observer) throws RemoteException {
+        BackupManagerService svc = mService;
+        return (svc != null) ? svc.requestBackup(packages, observer) : null;
+    }
+
+    @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
 
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 353b404..a4455e9 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -265,8 +265,8 @@
                     Ops ops = it.next();
                     int curUid = -1;
                     try {
-                        curUid = AppGlobals.getPackageManager().getPackageUidEtc(ops.packageName,
-                                PackageManager.GET_UNINSTALLED_PACKAGES,
+                        curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
+                                PackageManager.MATCH_UNINSTALLED_PACKAGES,
                                 UserHandle.getUserId(ops.uidState.uid));
                     } catch (RemoteException ignored) {
                     }
@@ -691,7 +691,7 @@
         if (reqPackageName != null) {
             try {
                 reqUid = AppGlobals.getPackageManager().getPackageUid(
-                        reqPackageName, reqUserId);
+                        reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
             } catch (RemoteException e) {
                 /* ignore - local call */
             }
@@ -1167,7 +1167,9 @@
                     int pkgUid = -1;
                     try {
                         ApplicationInfo appInfo = ActivityThread.getPackageManager()
-                                .getApplicationInfo(packageName, 0, UserHandle.getUserId(uid));
+                                .getApplicationInfo(packageName,
+                                        PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
+                                        UserHandle.getUserId(uid));
                         if (appInfo != null) {
                             pkgUid = appInfo.uid;
                             isPrivileged = (appInfo.privateFlags
@@ -1179,6 +1181,9 @@
                             } else if ("audioserver".equals(packageName)) {
                                 pkgUid = Process.AUDIOSERVER_UID;
                                 isPrivileged = false;
+                            } else if ("cameraserver".equals(packageName)) {
+                                pkgUid = Process.CAMERASERVER_UID;
+                                isPrivileged = false;
                             }
                         }
                     } catch (RemoteException e) {
@@ -1647,7 +1652,8 @@
             if ("root".equals(packageName)) {
                 packageUid = 0;
             } else {
-                packageUid = AppGlobals.getPackageManager().getPackageUid(packageName, userId);
+                packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
+                        PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
             }
             if (packageUid < 0) {
                 err.println("Error: No UID for " + packageName + " in user " + userId);
diff --git a/services/core/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java
index 4569dae..b0f6048 100644
--- a/services/core/java/com/android/server/AssetAtlasService.java
+++ b/services/core/java/com/android/server/AssetAtlasService.java
@@ -79,7 +79,7 @@
     private static final boolean DEBUG_ATLAS_TEXTURE = false;
 
     // Minimum size in pixels to consider for the resulting texture
-    private static final int MIN_SIZE = 768;
+    private static final int MIN_SIZE = 512;
     // Maximum size in pixels to consider for the resulting texture
     private static final int MAX_SIZE = 2048;
     // Increment in number of pixels between size variants when looking
@@ -176,7 +176,8 @@
     private static String queryVersionName(Context context) {
         try {
             String packageName = context.getPackageName();
-            PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
+            PackageInfo info = context.getPackageManager().getPackageInfo(packageName,
+                    PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
             return info.versionName;
         } catch (PackageManager.NameNotFoundException e) {
             Log.w(LOG_TAG, "Could not get package info", e);
@@ -664,22 +665,32 @@
             if (DEBUG_ATLAS) Log.d(LOG_TAG, "Running " + Thread.currentThread().getName());
 
             Atlas.Entry entry = new Atlas.Entry();
-            for (Atlas.Type type : Atlas.Type.values()) {
-                for (int width = mEnd; width > mStart; width -= mStep) {
-                    for (int height = MAX_SIZE; height > MIN_SIZE; height -= STEP) {
-                        // If the atlas is not big enough, skip it
-                        if (width * height <= mThreshold) continue;
 
+            for (int width = mEnd; width > mStart; width -= mStep) {
+                for (int height = MAX_SIZE; height > MIN_SIZE; height -= STEP) {
+                    // If the atlas is not big enough, skip it
+                    if (width * height <= mThreshold) continue;
+
+                    boolean packSuccess = false;
+
+                    for (Atlas.Type type : Atlas.Type.values()) {
                         final int count = packBitmaps(type, width, height, entry);
                         if (count > 0) {
                             mResults.add(new WorkerResult(type, width, height, count));
-                            // If we were able to pack everything let's stop here
-                            // Increasing the height further won't make things better
                             if (count == mBitmaps.size()) {
+                                // If we were able to pack everything let's stop here
+                                // Changing the type further won't make things better
+                                packSuccess = true;
                                 break;
                             }
                         }
                     }
+
+                    // If we were not able to pack everything let's stop here
+                    // Decreasing the height further won't make things better
+                    if (!packSuccess) {
+                        break;
+                    }
                 }
             }
 
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index f329cff..499b706 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -114,13 +114,6 @@
     private static final int SERVICE_IBLUETOOTH = 1;
     private static final int SERVICE_IBLUETOOTHGATT = 2;
 
-    private static final String[] DEVICE_TYPE_NAMES = new String[] {
-            "???",
-            "BR/EDR",
-            "LE",
-            "DUAL"
-        };
-
     private final Context mContext;
     private static int mBleAppCount = 0;
 
@@ -131,6 +124,7 @@
     private final ContentResolver mContentResolver;
     private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
     private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
+    private IBinder mBluetoothBinder;
     private IBluetooth mBluetooth;
     private IBluetoothGatt mBluetoothGatt;
     private boolean mBinding;
@@ -242,6 +236,7 @@
 
         mContext = context;
         mBluetooth = null;
+        mBluetoothBinder = null;
         mBluetoothGatt = null;
         mBinding = false;
         mUnbinding = false;
@@ -268,8 +263,8 @@
 
         int sysUiUid = -1;
         try {
-            sysUiUid = mContext.getPackageManager().getPackageUid("com.android.systemui",
-                    UserHandle.USER_SYSTEM);
+            sysUiUid = mContext.getPackageManager().getPackageUidAsUser("com.android.systemui",
+                    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);
@@ -678,6 +673,7 @@
                 }
 
                 if (DBG) Log.d(TAG, "Sending unbind request.");
+                mBluetoothBinder = null;
                 mBluetooth = null;
                 //Unbind
                 mContext.unbindService(mConnection);
@@ -1166,6 +1162,7 @@
                         mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
 
                         mBinding = false;
+                        mBluetoothBinder = service;
                         mBluetooth = IBluetooth.Stub.asInterface(service);
 
                         try {
@@ -1674,44 +1671,15 @@
     }
 
     @Override
-    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
-
-        writer.println("Bluetooth Status");
-        writer.println("  enabled: " + mEnable);
-        writer.println("  state: " + mState);
-        writer.println("  address: " + mAddress);
-        writer.println("  name: " + mName + "\n");
-        writer.flush();
-
-        if (mBluetooth == null) {
-            writer.println("Bluetooth Service not connected");
-        } else {
-            ParcelFileDescriptor pfd = null;
-            try {
-                writer.println("Bonded devices:");
-                for (BluetoothDevice device : mBluetooth.getBondedDevices()) {
-                    writer.println("  " + device.getAddress() +
-                            " [" + DEVICE_TYPE_NAMES[device.getType()] + "] " +
-                            device.getName());
-                }
-                writer.flush();
-
-                pfd = ParcelFileDescriptor.dup(fd);
-                mBluetooth.dump(pfd);
-            } catch (RemoteException re) {
-                writer.println("RemoteException while calling Bluetooth Service");
-            } catch (IOException ioe) {
-                writer.println("IOException attempting to dup() fd");
-            } finally {
-                if (pfd != null) {
-                    try {
-                        pfd.close();
-                    } catch (IOException ioe) {
-                        writer.println("IOException attempting to close() fd");
-                    }
-                }
-            }
+    public void dump(FileDescriptor fd, PrintWriter writer, String args[]) {
+      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");
         }
+      }
     }
 }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 65a27c8..2d1f96b 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -87,6 +87,7 @@
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -171,6 +172,7 @@
     private static final boolean VDBG = false;
 
     private static final boolean LOGD_RULES = false;
+    private static final boolean LOGD_BLOCKED_NETWORKINFO = true;
 
     // TODO: create better separation between radio types and network types
 
@@ -743,7 +745,7 @@
         mTestMode = SystemProperties.get("cm.test.mode").equals("true")
                 && SystemProperties.get("ro.build.type").equals("eng");
 
-        mTethering = new Tethering(mContext, mNetd, statsService, mHandler.getLooper());
+        mTethering = new Tethering(mContext, mNetd, statsService);
 
         mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
 
@@ -753,6 +755,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);
         mContext.registerReceiverAsUser(
                 mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
 
@@ -954,6 +957,21 @@
         }
     }
 
+    private void maybeLogBlockedNetworkInfo(NetworkInfo ni, int uid) {
+        if (ni == null || !LOGD_BLOCKED_NETWORKINFO) return;
+        boolean removed = false;
+        boolean added = false;
+        synchronized (mBlockedAppUids) {
+            if (ni.getDetailedState() == DetailedState.BLOCKED && mBlockedAppUids.add(uid)) {
+                added = true;
+            } else if (ni.isConnected() && mBlockedAppUids.remove(uid)) {
+                removed = true;
+            }
+        }
+        if (added) log("Returning blocked NetworkInfo to uid=" + uid);
+        else if (removed) log("Returning unblocked NetworkInfo to uid=" + uid);
+    }
+
     /**
      * Return a filtered {@link NetworkInfo}, potentially marked
      * {@link DetailedState#BLOCKED} based on
@@ -964,10 +982,6 @@
             // network is blocked; clone and override state
             info = new NetworkInfo(info);
             info.setDetailedState(DetailedState.BLOCKED, null, null);
-            if (VDBG) {
-                log("returning Blocked NetworkInfo for ifname=" +
-                        lp.getInterfaceName() + ", uid=" + uid);
-            }
         }
         if (info != null && mLockdownTracker != null) {
             info = mLockdownTracker.augmentNetworkInfo(info);
@@ -988,7 +1002,9 @@
         enforceAccessPermission();
         final int uid = Binder.getCallingUid();
         NetworkState state = getUnfilteredActiveNetworkState(uid);
-        return getFilteredNetworkInfo(state.networkInfo, state.linkProperties, uid);
+        NetworkInfo ni = getFilteredNetworkInfo(state.networkInfo, state.linkProperties, uid);
+        maybeLogBlockedNetworkInfo(ni, uid);
+        return ni;
     }
 
     @Override
@@ -1568,12 +1584,9 @@
         // load the global proxy at startup
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY));
 
-        // Try bringing up tracker, but if KeyStore isn't ready yet, wait
-        // for user to unlock device.
-        if (!updateLockdownVpn()) {
-            final IntentFilter filter = new IntentFilter(Intent.ACTION_USER_PRESENT);
-            mContext.registerReceiver(mUserPresentReceiver, filter);
-        }
+        // Try bringing up tracker, but KeyStore won't be ready yet for secondary users so wait
+        // for user to unlock device too.
+        updateLockdownVpn();
 
         // Configure whether mobile data is always on.
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON));
@@ -1583,17 +1596,6 @@
         mPermissionMonitor.startMonitoring();
     }
 
-    private BroadcastReceiver mUserPresentReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            // Try creating lockdown tracker, since user present usually means
-            // unlocked keystore.
-            if (updateLockdownVpn()) {
-                mContext.unregisterReceiver(this);
-            }
-        }
-    };
-
     /**
      * Setup data activity tracking for the given network.
      *
@@ -2685,6 +2687,21 @@
                 mTethering.getUpstreamIfaceTypes().length != 0);
     }
 
+    public void startTethering(int type, ResultReceiver receiver,
+            boolean showProvisioningUi) {
+        ConnectivityManager.enforceTetherChangePermission(mContext);
+        if (!isTetheringSupported()) {
+            receiver.send(ConnectivityManager.TETHER_ERROR_UNSUPPORTED, null);
+            return;
+        }
+        mTethering.startTethering(type, receiver, showProvisioningUi);
+    }
+
+    public void stopTethering(int type) {
+        ConnectivityManager.enforceTetherChangePermission(mContext);
+        mTethering.stopTethering(type);
+    }
+
     // Called when we lose the default network and have no replacement yet.
     // This will automatically be cleared after X seconds or a new default network
     // becomes CONNECTED, whichever happens first.  The timer is started by the
@@ -3201,11 +3218,6 @@
         // Tear down existing lockdown if profile was removed
         mLockdownEnabled = LockdownVpnTracker.isEnabled();
         if (mLockdownEnabled) {
-            if (!mKeyStore.isUnlocked()) {
-                Slog.w(TAG, "KeyStore locked; unable to create LockdownTracker");
-                return false;
-            }
-
             final String profileName = new String(mKeyStore.get(Credentials.LOCKDOWN_VPN));
             final VpnProfile profile = VpnProfile.decode(
                     profileName, mKeyStore.get(Credentials.VPN + profileName));
@@ -3258,6 +3270,76 @@
         }
     }
 
+    /**
+     * Sets up or tears down the always-on VPN for user {@param user} as appropriate.
+     *
+     * @return {@code false} in case of errors; {@code true} otherwise.
+     */
+    private boolean updateAlwaysOnVpn(int user) {
+        final String lockdownPackage = getAlwaysOnVpnPackage(user);
+        if (lockdownPackage == null) {
+            return true;
+        }
+
+        // Create an intent to start the VPN service declared in the app's manifest.
+        Intent serviceIntent = new Intent(VpnConfig.SERVICE_INTERFACE);
+        serviceIntent.setPackage(lockdownPackage);
+
+        try {
+            return mContext.startServiceAsUser(serviceIntent, UserHandle.of(user)) != null;
+        } catch (RuntimeException e) {
+            return false;
+        }
+    }
+
+    @Override
+    public boolean setAlwaysOnVpnPackage(int userId, String packageName) {
+        enforceConnectivityInternalPermission();
+        enforceCrossUserPermission(userId);
+
+        // Can't set always-on VPN if legacy VPN is already in lockdown mode.
+        if (LockdownVpnTracker.isEnabled()) {
+            return false;
+        }
+
+        // If the current VPN package is the same as the new one, this is a no-op
+        final String oldPackage = getAlwaysOnVpnPackage(userId);
+        if (TextUtils.equals(oldPackage, packageName)) {
+            return true;
+        }
+
+        synchronized (mVpns) {
+            Vpn vpn = mVpns.get(userId);
+            if (vpn == null) {
+                Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+                return false;
+            }
+            if (!vpn.setAlwaysOnPackage(packageName)) {
+                return false;
+            }
+            if (!updateAlwaysOnVpn(userId)) {
+                vpn.setAlwaysOnPackage(null);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public String getAlwaysOnVpnPackage(int userId) {
+        enforceConnectivityInternalPermission();
+        enforceCrossUserPermission(userId);
+
+        synchronized (mVpns) {
+            Vpn vpn = mVpns.get(userId);
+            if (vpn == null) {
+                Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+                return null;
+            }
+            return vpn.getAlwaysOnPackage();
+        }
+    }
+
     @Override
     public int checkMobileProvisioning(int suggestedTimeOutMs) {
         // TODO: Remove?  Any reason to trigger a provisioning check?
@@ -3514,6 +3596,11 @@
             userVpn = new Vpn(mHandler.getLooper(), mContext, mNetd, userId);
             mVpns.put(userId, userVpn);
         }
+        if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
+            updateLockdownVpn();
+        } else {
+            updateAlwaysOnVpn(userId);
+        }
     }
 
     private void onUserStop(int userId) {
@@ -3547,6 +3634,15 @@
         }
     }
 
+    private void onUserPresent(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();
+        } else {
+            updateAlwaysOnVpn(userId);
+        }
+    }
+
     private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -3562,6 +3658,8 @@
                 onUserAdded(userId);
             } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
                 onUserRemoved(userId);
+            } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
+                onUserPresent(userId);
             }
         }
     };
@@ -3702,6 +3800,12 @@
             throw new IllegalArgumentException("Bad timeout specified");
         }
 
+        if (NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER
+                .equals(networkCapabilities.getNetworkSpecifier())) {
+            throw new IllegalArgumentException("Invalid network specifier - must not be '"
+                    + NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER + "'");
+        }
+
         NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
                 nextNetworkRequestId());
         NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
@@ -3906,6 +4010,9 @@
     private final HashMap<Messenger, NetworkAgentInfo> mNetworkAgentInfos =
             new HashMap<Messenger, NetworkAgentInfo>();
 
+    @GuardedBy("mBlockedAppUids")
+    private final HashSet<Integer> mBlockedAppUids = new HashSet();
+
     // Note: if mDefaultRequest is changed, NetworkMonitor needs to be updated.
     private final NetworkRequest mDefaultRequest;
 
@@ -4848,6 +4955,11 @@
     }
 
     @Override
+    public String getCaptivePortalServerUrl() {
+        return NetworkMonitor.getCaptivePortalServerUrl(mContext);
+    }
+
+    @Override
     public void startNattKeepalive(Network network, int intervalSeconds, Messenger messenger,
             IBinder binder, String srcAddr, int srcPort, String dstAddr) {
         enforceKeepalivePermission();
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index f5ed83e..9bd79c9 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -50,11 +50,13 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IDeviceIdleController;
+import android.os.IMaintenanceActivityListener;
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.PowerManagerInternal;
 import android.os.Process;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
@@ -206,9 +208,13 @@
     private boolean mSyncActive;
     private boolean mJobsActive;
     private boolean mAlarmsActive;
+    private boolean mReportedMaintenanceActivity;
 
     public final AtomicFile mConfigFile;
 
+    private final RemoteCallbackList<IMaintenanceActivityListener> mMaintenanceActivityListeners =
+            new RemoteCallbackList<IMaintenanceActivityListener>();
+
     /**
      * Package names the system has white-listed to opt out of power save restrictions,
      * except for device idle mode.
@@ -813,6 +819,7 @@
     static final int MSG_REPORT_IDLE_OFF = 4;
     static final int MSG_REPORT_ACTIVE = 5;
     static final int MSG_TEMP_APP_WHITELIST_TIMEOUT = 6;
+    static final int MSG_REPORT_MAINTENANCE_ACTIVITY = 7;
 
     final class MyHandler extends Handler {
         MyHandler(Looper looper) {
@@ -902,6 +909,21 @@
                     int uid = msg.arg1;
                     checkTempAppWhitelistTimeout(uid);
                 } break;
+                case MSG_REPORT_MAINTENANCE_ACTIVITY: {
+                    boolean active = (msg.arg1 == 1);
+                    final int size = mMaintenanceActivityListeners.beginBroadcast();
+                    try {
+                        for (int i = 0; i < size; i++) {
+                            try {
+                                mMaintenanceActivityListeners.getBroadcastItem(i)
+                                        .onMaintenanceActivityChanged(active);
+                            } catch (RemoteException ignored) {
+                            }
+                        }
+                    } finally {
+                        mMaintenanceActivityListeners.finishBroadcast();
+                    }
+                } break;
             }
         }
     }
@@ -914,13 +936,23 @@
         @Override public void addPowerSaveWhitelistApp(String name) {
             getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
                     null);
-            addPowerSaveWhitelistAppInternal(name);
+            long ident = Binder.clearCallingIdentity();
+            try {
+                addPowerSaveWhitelistAppInternal(name);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
         }
 
         @Override public void removePowerSaveWhitelistApp(String name) {
             getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
                     null);
-            removePowerSaveWhitelistAppInternal(name);
+            long ident = Binder.clearCallingIdentity();
+            try {
+                removePowerSaveWhitelistAppInternal(name);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
         }
 
         @Override public String[] getSystemPowerWhitelistExceptIdle() {
@@ -981,19 +1013,44 @@
         @Override public void exitIdle(String reason) {
             getContext().enforceCallingOrSelfPermission(Manifest.permission.DEVICE_POWER,
                     null);
-            exitIdleInternal(reason);
+            long ident = Binder.clearCallingIdentity();
+            try {
+                exitIdleInternal(reason);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
         }
 
         @Override public void downloadServiceActive(IBinder token) {
             getContext().enforceCallingOrSelfPermission(
                     "android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS", null);
-            DeviceIdleController.this.downloadServiceActive(token);
+            long ident = Binder.clearCallingIdentity();
+            try {
+                DeviceIdleController.this.downloadServiceActive(token);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
         }
 
         @Override public void downloadServiceInactive() {
             getContext().enforceCallingOrSelfPermission(
                     "android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS", null);
-            DeviceIdleController.this.downloadServiceInactive();
+            long ident = Binder.clearCallingIdentity();
+            try {
+                DeviceIdleController.this.downloadServiceInactive();
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override public boolean registerMaintenanceActivityListener(
+                IMaintenanceActivityListener listener) {
+            return DeviceIdleController.this.registerMaintenanceActivityListener(listener);
+        }
+
+        @Override public void unregisterMaintenanceActivityListener(
+                IMaintenanceActivityListener listener) {
+            DeviceIdleController.this.unregisterMaintenanceActivityListener(listener);
         }
 
         @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -1052,12 +1109,11 @@
             for (int i=0; i<allowPowerExceptIdle.size(); i++) {
                 String pkg = allowPowerExceptIdle.valueAt(i);
                 try {
-                    ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
-                    if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
-                        int appid = UserHandle.getAppId(ai.uid);
-                        mPowerSaveWhitelistAppsExceptIdle.put(ai.packageName, appid);
-                        mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appid, true);
-                    }
+                    ApplicationInfo ai = pm.getApplicationInfo(pkg,
+                            PackageManager.MATCH_SYSTEM_ONLY);
+                    int appid = UserHandle.getAppId(ai.uid);
+                    mPowerSaveWhitelistAppsExceptIdle.put(ai.packageName, appid);
+                    mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appid, true);
                 } catch (PackageManager.NameNotFoundException e) {
                 }
             }
@@ -1065,16 +1121,15 @@
             for (int i=0; i<allowPower.size(); i++) {
                 String pkg = allowPower.valueAt(i);
                 try {
-                    ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
-                    if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
-                        int appid = UserHandle.getAppId(ai.uid);
-                        // These apps are on both the whitelist-except-idle as well
-                        // as the full whitelist, so they apply in all cases.
-                        mPowerSaveWhitelistAppsExceptIdle.put(ai.packageName, appid);
-                        mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appid, true);
-                        mPowerSaveWhitelistApps.put(ai.packageName, appid);
-                        mPowerSaveWhitelistSystemAppIds.put(appid, true);
-                    }
+                    ApplicationInfo ai = pm.getApplicationInfo(pkg,
+                            PackageManager.MATCH_SYSTEM_ONLY);
+                    int appid = UserHandle.getAppId(ai.uid);
+                    // These apps are on both the whitelist-except-idle as well
+                    // as the full whitelist, so they apply in all cases.
+                    mPowerSaveWhitelistAppsExceptIdle.put(ai.packageName, appid);
+                    mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appid, true);
+                    mPowerSaveWhitelistApps.put(ai.packageName, appid);
+                    mPowerSaveWhitelistSystemAppIds.put(appid, true);
                 } catch (PackageManager.NameNotFoundException e) {
                 }
             }
@@ -1182,9 +1237,7 @@
         synchronized (this) {
             try {
                 ApplicationInfo ai = getContext().getPackageManager().getApplicationInfo(name,
-                        PackageManager.GET_UNINSTALLED_PACKAGES
-                                | PackageManager.GET_DISABLED_COMPONENTS
-                                | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
+                        PackageManager.MATCH_UNINSTALLED_PACKAGES);
                 if (mPowerSaveWhitelistUserApps.put(name, UserHandle.getAppId(ai.uid)) == null) {
                     reportPowerSaveWhitelistChangedLocked();
                     updateWhitelistAppIdsLocked();
@@ -1326,7 +1379,7 @@
     void addPowerSaveTempWhitelistAppInternal(int callingUid, String packageName,
             long duration, int userId, boolean sync, String reason) {
         try {
-            int uid = getContext().getPackageManager().getPackageUid(packageName, userId);
+            int uid = getContext().getPackageManager().getPackageUidAsUser(packageName, userId);
             int appId = UserHandle.getAppId(uid);
             addPowerSaveTempWhitelistAppDirectInternal(callingUid, appId, duration, sync, reason);
         } catch (NameNotFoundException e) {
@@ -1708,6 +1761,7 @@
     void downloadServiceActive(IBinder token) {
         synchronized (this) {
             mDownloadServiceActive = token;
+            reportMaintenanceActivityIfNeededLocked();
             try {
                 token.linkToDeath(new IBinder.DeathRecipient() {
                     @Override public void binderDied() {
@@ -1723,6 +1777,7 @@
     void downloadServiceInactive() {
         synchronized (this) {
             mDownloadServiceActive = null;
+            reportMaintenanceActivityIfNeededLocked();
             exitMaintenanceEarlyIfNeededLocked();
         }
     }
@@ -1730,6 +1785,7 @@
     void setSyncActive(boolean active) {
         synchronized (this) {
             mSyncActive = active;
+            reportMaintenanceActivityIfNeededLocked();
             if (!active) {
                 exitMaintenanceEarlyIfNeededLocked();
             }
@@ -1739,6 +1795,7 @@
     void setJobsActive(boolean active) {
         synchronized (this) {
             mJobsActive = active;
+            reportMaintenanceActivityIfNeededLocked();
             if (!active) {
                 exitMaintenanceEarlyIfNeededLocked();
             }
@@ -1754,6 +1811,30 @@
         }
     }
 
+    boolean registerMaintenanceActivityListener(IMaintenanceActivityListener listener) {
+        synchronized (this) {
+            mMaintenanceActivityListeners.register(listener);
+            return mReportedMaintenanceActivity;
+        }
+    }
+
+    void unregisterMaintenanceActivityListener(IMaintenanceActivityListener listener) {
+        synchronized (this) {
+            mMaintenanceActivityListeners.unregister(listener);
+        }
+    }
+
+    void reportMaintenanceActivityIfNeededLocked() {
+        boolean active = mJobsActive | mSyncActive | (mDownloadServiceActive != null);
+        if (active == mReportedMaintenanceActivity) {
+            return;
+        }
+        mReportedMaintenanceActivity = active;
+        Message msg = mHandler.obtainMessage(MSG_REPORT_MAINTENANCE_ACTIVITY,
+                mReportedMaintenanceActivity ? 1 : 0, 0);
+        mHandler.sendMessage(msg);
+    }
+
     void exitMaintenanceEarlyIfNeededLocked() {
         if (mState == STATE_IDLE_MAINTENANCE || mLightState == LIGHT_STATE_IDLE_MAINTENANCE) {
             if (mActiveIdleOpCount <= 0 && mDownloadServiceActive == null
@@ -2010,9 +2091,7 @@
                     if (name != null) {
                         try {
                             ApplicationInfo ai = pm.getApplicationInfo(name,
-                                    PackageManager.GET_UNINSTALLED_PACKAGES
-                                            | PackageManager.GET_DISABLED_COMPONENTS
-                                            | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
+                                    PackageManager.MATCH_UNINSTALLED_PACKAGES);
                             mPowerSaveWhitelistUserApps.put(ai.packageName,
                                     UserHandle.getAppId(ai.uid));
                         } catch (PackageManager.NameNotFoundException e) {
diff --git a/services/core/java/com/android/server/DiskStatsService.java b/services/core/java/com/android/server/DiskStatsService.java
index bc12fc5..9313148 100644
--- a/services/core/java/com/android/server/DiskStatsService.java
+++ b/services/core/java/com/android/server/DiskStatsService.java
@@ -21,6 +21,7 @@
 import android.os.Environment;
 import android.os.StatFs;
 import android.os.SystemClock;
+import android.os.storage.StorageManager;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -79,6 +80,10 @@
         reportFreeSpace(Environment.getDownloadCacheDirectory(), "Cache", pw);
         reportFreeSpace(new File("/system"), "System", pw);
 
+        if (StorageManager.isNativeFileBasedEncryptionEnabled()) {
+            pw.println("File-based Encryption: true");
+        }
+
         // TODO: Read /proc/yaffs and report interesting values;
         // add configurable (through args) performance test parameters.
     }
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 516e2f4..c59ecec 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -107,6 +107,8 @@
 2825 backup_success (Packages|1|1),(Time|1|3)
 2826 backup_reset (Transport|3)
 2827 backup_initialize
+2828 backup_requested (Total|1|1),(Key-Value|1|1),(Full|1|1)
+2829 backup_quota_exceeded (Package|3)
 2830 restore_start (Transport|3),(Source|2|5)
 2831 restore_transport_failure
 2832 restore_agent_failure (Package|3),(Message|3)
@@ -118,6 +120,7 @@
 2842 full_backup_transport_failure
 2843 full_backup_success (Package|3)
 2844 full_restore_package (Package|3)
+2845 full_backup_quota_exceeded (Package|3)
 
 2850 backup_transport_lifecycle (Transport|3),(Bound|1|1)
 
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index 2aa0390..d6575e8 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -38,6 +38,7 @@
 import android.view.KeyEvent;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.server.statusbar.StatusBarManagerInternal;
 
 /**
@@ -270,7 +271,7 @@
             launched = handleCameraLaunchGesture(false /* useWakelock */,
                     StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
             if (launched) {
-                MetricsLogger.action(mContext, MetricsLogger.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE,
+                MetricsLogger.action(mContext, MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE,
                         (int) doubleTapInterval);
             }
         }
@@ -341,7 +342,7 @@
                 }
                 if (handleCameraLaunchGesture(true /* useWakelock */,
                         StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE)) {
-                    MetricsLogger.action(mContext, MetricsLogger.ACTION_WIGGLE_CAMERA_GESTURE);
+                    MetricsLogger.action(mContext, MetricsEvent.ACTION_WIGGLE_CAMERA_GESTURE);
                     trackCameraLaunchEvent(event);
                 }
                 return;
diff --git a/services/core/java/com/android/server/GraphicsStatsService.java b/services/core/java/com/android/server/GraphicsStatsService.java
index 3fdef1d..044bb04 100644
--- a/services/core/java/com/android/server/GraphicsStatsService.java
+++ b/services/core/java/com/android/server/GraphicsStatsService.java
@@ -16,9 +16,8 @@
 
 package com.android.server;
 
+import android.app.AppOpsManager;
 import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.MemoryFile;
@@ -66,6 +65,7 @@
     private static final int HISTORY_SIZE = 20;
 
     private final Context mContext;
+    private final AppOpsManager mAppOps;
     private final Object mLock = new Object();
     private ArrayList<ActiveBuffer> mActive = new ArrayList<>();
     private HistoricalData[] mHistoricalLog = new HistoricalData[HISTORY_SIZE];
@@ -74,15 +74,7 @@
 
     public GraphicsStatsService(Context context) {
         mContext = context;
-    }
-
-    private boolean isValid(int uid, String packageName) {
-        try {
-            PackageInfo info = mContext.getPackageManager().getPackageInfo(packageName, 0);
-            return info.applicationInfo.uid == uid;
-        } catch (NameNotFoundException e) {
-        }
-        return false;
+        mAppOps = context.getSystemService(AppOpsManager.class);
     }
 
     @Override
@@ -93,9 +85,7 @@
         ParcelFileDescriptor pfd = null;
         long callingIdentity = Binder.clearCallingIdentity();
         try {
-            if (!isValid(uid, packageName)) {
-                throw new RemoteException("Invalid package name");
-            }
+            mAppOps.checkPackage(uid, packageName);
             synchronized (mLock) {
                 pfd = requestBufferForProcessLocked(token, uid, pid, packageName);
             }
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 04abcca..4a123df 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -450,6 +450,7 @@
     private boolean mShowImeWithHardKeyboard;
     private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
     private final IPackageManager mIPackageManager;
+    private final String mSlotIme;
 
     class SettingsObserver extends ContentObserver {
         int mUserId;
@@ -741,6 +742,31 @@
         }
     }
 
+    public static final class Lifecycle extends SystemService {
+        private InputMethodManagerService mService;
+
+        public Lifecycle(Context context) {
+            super(context);
+            mService = new InputMethodManagerService(context);
+        }
+
+        @Override
+        public void onStart() {
+            LocalServices.addService(InputMethodManagerInternal.class,
+                    new LocalServiceImpl(mService.mHandler));
+            publishBinderService(Context.INPUT_METHOD_SERVICE, mService);
+        }
+
+        @Override
+        public void onBootPhase(int phase) {
+            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+                StatusBarManagerService statusBarService = (StatusBarManagerService) ServiceManager
+                        .getService(Context.STATUS_BAR_SERVICE);
+                mService.systemRunning(statusBarService);
+            }
+        }
+    }
+
     public InputMethodManagerService(Context context) {
         mIPackageManager = AppGlobals.getPackageManager();
         mContext = context;
@@ -761,6 +787,7 @@
         mHardKeyboardListener = new HardKeyboardListener();
         mHasFeature = context.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_INPUT_METHODS);
+        mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);
 
         Bundle extras = new Bundle();
         extras.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, true);
@@ -892,7 +919,6 @@
                         }
                     }
                 }, filter);
-        LocalServices.addService(InputMethodManagerInternal.class, new LocalServiceImpl(mHandler));
     }
 
     private void resetDefaultImeLocked(Context context) {
@@ -1043,7 +1069,7 @@
                 mNotificationManager = (NotificationManager)
                         mContext.getSystemService(Context.NOTIFICATION_SERVICE);
                 mStatusBar = statusBar;
-                statusBar.setIconVisibility("ime", false);
+                statusBar.setIconVisibility(mSlotIme, false);
                 updateSystemUiLocked(mCurToken, mImeWindowVis, mBackDisposition);
                 mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
                         com.android.internal.R.bool.show_ongoing_ime_switcher);
@@ -1595,7 +1621,7 @@
             mCurMethod = null;
         }
         if (mStatusBar != null) {
-            mStatusBar.setIconVisibility("ime", false);
+            mStatusBar.setIconVisibility(mSlotIme, false);
         }
     }
 
@@ -1635,7 +1661,7 @@
                 if (iconId == 0) {
                     if (DEBUG) Slog.d(TAG, "hide the small icon for the input method");
                     if (mStatusBar != null) {
-                        mStatusBar.setIconVisibility("ime", false);
+                        mStatusBar.setIconVisibility(mSlotIme, false);
                     }
                 } else if (packageName != null) {
                     if (DEBUG) Slog.d(TAG, "show a small icon for the input method");
@@ -1650,10 +1676,10 @@
                         /* ignore */
                     }
                     if (mStatusBar != null) {
-                        mStatusBar.setIcon("ime", packageName, iconId, 0,
+                        mStatusBar.setIcon(mSlotIme, packageName, iconId, 0,
                                 contentDescription  != null
                                         ? contentDescription.toString() : null);
-                        mStatusBar.setIconVisibility("ime", true);
+                        mStatusBar.setIconVisibility(mSlotIme, true);
                     }
                 }
             }
@@ -2383,10 +2409,6 @@
             return;
         }
         synchronized (mMethodMap) {
-            if (mCurClient == null || client == null
-                || mCurClient.client.asBinder() != client.asBinder()) {
-                Slog.w(TAG, "Ignoring showInputMethodAndSubtypeEnablerFromClient of: " + client);
-            }
             executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
                     MSG_SHOW_IM_SUBTYPE_ENABLER, inputMethodId));
         }
@@ -2541,7 +2563,7 @@
         }
         // By this IPC call, only a process which shares the same uid with the IME can add
         // additional input method subtypes to the IME.
-        if (TextUtils.isEmpty(imiId) || subtypes == null || subtypes.length == 0) return;
+        if (TextUtils.isEmpty(imiId) || subtypes == null) return;
         synchronized (mMethodMap) {
             final InputMethodInfo imi = mMethodMap.get(imiId);
             if (imi == null) return;
@@ -2716,9 +2738,7 @@
                 return true;
 
             case MSG_SHOW_IM_SUBTYPE_ENABLER:
-                args = (SomeArgs)msg.obj;
-                showInputMethodAndSubtypeEnabler((String)args.arg1);
-                args.recycle();
+                showInputMethodAndSubtypeEnabler((String)msg.obj);
                 return true;
 
             case MSG_SHOW_IM_CONFIG:
@@ -3005,7 +3025,11 @@
         if (!TextUtils.isEmpty(inputMethodId)) {
             intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, inputMethodId);
         }
-        mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
+        final int userId;
+        synchronized (mMethodMap) {
+            userId = mSettings.getCurrentUserId();
+        }
+        mContext.startActivityAsUser(intent, null, UserHandle.of(userId));
     }
 
     private void showConfigureInputMethods() {
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 9405d8e0..c55c5b6 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -24,10 +24,10 @@
 import com.android.server.location.ActivityRecognitionProxy;
 import com.android.server.location.FlpHardwareProvider;
 import com.android.server.location.FusedProxy;
+import com.android.server.location.GnssLocationProvider;
 import com.android.server.location.GeocoderProxy;
 import com.android.server.location.GeofenceManager;
 import com.android.server.location.GeofenceProxy;
-import com.android.server.location.GpsLocationProvider;
 import com.android.server.location.GpsMeasurementsProvider;
 import com.android.server.location.GpsNavigationMessageProvider;
 import com.android.server.location.LocationBlacklist;
@@ -61,11 +61,11 @@
 import android.location.Criteria;
 import android.location.GeocoderParams;
 import android.location.Geofence;
+import android.location.IGnssStatusListener;
+import android.location.IGnssStatusProvider;
 import android.location.IGpsGeofenceHardware;
 import android.location.IGpsMeasurementsListener;
 import android.location.IGpsNavigationMessageListener;
-import android.location.IGpsStatusListener;
-import android.location.IGpsStatusProvider;
 import android.location.ILocationListener;
 import android.location.ILocationManager;
 import android.location.INetInitiatedListener;
@@ -157,7 +157,7 @@
     private PowerManager mPowerManager;
     private UserManager mUserManager;
     private GeocoderProxy mGeocodeProvider;
-    private IGpsStatusProvider mGpsStatusProvider;
+    private IGnssStatusProvider mGnssStatusProvider;
     private INetInitiatedListener mNetInitiatedListener;
     private LocationWorkerHandler mLocationHandler;
     private PassiveProvider mPassiveProvider;  // track passive provider for special cases
@@ -214,6 +214,8 @@
     private int mCurrentUserId = UserHandle.USER_SYSTEM;
     private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_SYSTEM };
 
+    private GnssLocationProvider.GpsSystemInfoProvider mGpsSystemInfoProvider;
+
     public LocationManagerService(Context context) {
         super();
         mContext = context;
@@ -456,17 +458,18 @@
         mEnabledProviders.add(passiveProvider.getName());
         mPassiveProvider = passiveProvider;
 
-        if (GpsLocationProvider.isSupported()) {
+        if (GnssLocationProvider.isSupported()) {
             // Create a gps location provider
-            GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
+            GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext, this,
                     mLocationHandler.getLooper());
-            mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
-            mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
-            addProviderLocked(gpsProvider);
-            mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
-            mGpsMeasurementsProvider = gpsProvider.getGpsMeasurementsProvider();
-            mGpsNavigationMessageProvider = gpsProvider.getGpsNavigationMessageProvider();
-            mGpsGeofenceProxy = gpsProvider.getGpsGeofenceProxy();
+            mGpsSystemInfoProvider = gnssProvider.getGpsSystemInfoProvider();
+            mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
+            mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
+            addProviderLocked(gnssProvider);
+            mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProvider);
+            mGpsMeasurementsProvider = gnssProvider.getGpsMeasurementsProvider();
+            mGpsNavigationMessageProvider = gnssProvider.getGpsNavigationMessageProvider();
+            mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
         }
 
         /*
@@ -986,6 +989,18 @@
         }
     }
 
+    /**
+     * Returns the system information of the GPS hardware.
+     */
+    @Override
+    public int getGpsYearOfHardware() {
+        if (mGpsNavigationMessageProvider != null) {
+            return mGpsSystemInfoProvider.getGpsYearOfHardware();
+        } else {
+            return 0;
+        }
+    }
+
     private void addProviderLocked(LocationProviderInterface provider) {
         mProviders.add(provider);
         mProvidersByName.put(provider.getName(), provider);
@@ -1867,7 +1882,7 @@
 
 
     @Override
-    public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
+    public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
         int allowedResolutionLevel = getCallerAllowedResolutionLevel();
         checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
                 LocationManager.GPS_PROVIDER);
@@ -1883,26 +1898,26 @@
             Binder.restoreCallingIdentity(ident);
         }
 
-        if (mGpsStatusProvider == null) {
+        if (mGnssStatusProvider == null) {
             return false;
         }
 
         try {
-            mGpsStatusProvider.addGpsStatusListener(listener);
+            mGnssStatusProvider.registerGnssStatusCallback(callback);
         } catch (RemoteException e) {
-            Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
+            Slog.e(TAG, "mGpsStatusProvider.registerGnssStatusCallback failed", e);
             return false;
         }
         return true;
     }
 
     @Override
-    public void removeGpsStatusListener(IGpsStatusListener listener) {
+    public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
         synchronized (mLock) {
             try {
-                mGpsStatusProvider.removeGpsStatusListener(listener);
+                mGnssStatusProvider.unregisterGnssStatusCallback(callback);
             } catch (Exception e) {
-                Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
+                Slog.e(TAG, "mGpsStatusProvider.unregisterGnssStatusCallback failed", e);
             }
         }
     }
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 1a21f5c..d0cd536 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -17,11 +17,12 @@
 package com.android.server;
 
 import android.app.ActivityManagerNative;
-import android.app.AppGlobals;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManager;
 import android.app.backup.BackupManager;
 import android.app.trust.IStrongAuthTracker;
-import android.app.trust.ITrustManager;
 import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
@@ -30,6 +31,8 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
+import android.content.res.Resources;
+
 import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
 import static android.content.Context.USER_SERVICE;
 import static android.Manifest.permission.READ_CONTACTS;
@@ -40,7 +43,6 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.storage.IMountService;
-import android.os.storage.StorageManager;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -70,19 +72,27 @@
  * @hide
  */
 public class LockSettingsService extends ILockSettings.Stub {
-
-    private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
-
     private static final String TAG = "LockSettingsService";
+    private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
+    private static final Intent ACTION_NULL; // hack to ensure notification shows the bouncer
+    private static final int FBE_ENCRYPTED_NOTIFICATION = 0;
+    private static final boolean DEBUG = false;
 
     private final Context mContext;
-
     private final LockSettingsStorage mStorage;
-    private final LockSettingsStrongAuth mStrongAuth = new LockSettingsStrongAuth();
+    private final LockSettingsStrongAuth mStrongAuth;
 
     private LockPatternUtils mLockPatternUtils;
     private boolean mFirstCallToVold;
     private IGateKeeperService mGateKeeperService;
+    private NotificationManager mNotificationManager;
+    private UserManager mUserManager;
+
+    static {
+        // Just launch the home screen, which happens anyway
+        ACTION_NULL = new Intent(Intent.ACTION_MAIN);
+        ACTION_NULL.addCategory(Intent.CATEGORY_HOME);
+    }
 
     private interface CredentialUtil {
         void setCredential(String credential, String savedCredential, int userId)
@@ -91,8 +101,45 @@
         String adjustForKeystore(String credential);
     }
 
+    // This class manages life cycle events for encrypted users on File Based Encryption (FBE)
+    // devices. The most basic of these is to show/hide notifications about missing features until
+    // the user unlocks the account and credential-encrypted storage is available.
+    public static final class Lifecycle extends SystemService {
+        private LockSettingsService mLockSettingsService;
+
+        public Lifecycle(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onStart() {
+            mLockSettingsService = new LockSettingsService(getContext());
+            publishBinderService("lock_settings", mLockSettingsService);
+        }
+
+        @Override
+        public void onBootPhase(int phase) {
+            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+                mLockSettingsService.maybeShowEncryptionNotification(UserHandle.ALL);
+            } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
+                // TODO
+            }
+        }
+
+        @Override
+        public void onUnlockUser(int userHandle) {
+            mLockSettingsService.onUnlockUser(userHandle);
+        }
+
+        @Override
+        public void onCleanupUser(int userHandle) {
+            mLockSettingsService.onCleanupUser(userHandle);
+        }
+    }
+
     public LockSettingsService(Context context) {
         mContext = context;
+        mStrongAuth = new LockSettingsStrongAuth(context);
         // Open the database
 
         mLockPatternUtils = new LockPatternUtils(context);
@@ -116,6 +163,71 @@
                 }
             }
         });
+        mNotificationManager = (NotificationManager)
+                mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+    }
+
+    /**
+     * If the account is credential-encrypted, show notification requesting the user to unlock
+     * the device.
+     */
+    private void maybeShowEncryptionNotification(UserHandle userHandle) {
+        if (UserHandle.ALL.equals(userHandle)) {
+            final List<UserInfo> users = mUserManager.getUsers();
+            for (int i = 0; i < users.size(); i++) {
+                UserHandle user = users.get(i).getUserHandle();
+                if (!mUserManager.isUserUnlocked(user)) {
+                    showEncryptionNotification(user);
+                }
+            }
+        } else if (!mUserManager.isUserUnlocked(userHandle)){
+            showEncryptionNotification(userHandle);
+        }
+    }
+
+    private void showEncryptionNotification(UserHandle user) {
+        if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
+        Resources r = mContext.getResources();
+        CharSequence title = r.getText(
+                com.android.internal.R.string.user_encrypted_title);
+        CharSequence message = r.getText(
+                com.android.internal.R.string.user_encrypted_message);
+        CharSequence detail = r.getText(
+                com.android.internal.R.string.user_encrypted_detail);
+
+        PendingIntent intent = PendingIntent.getBroadcast(mContext, 0, ACTION_NULL,
+                PendingIntent.FLAG_UPDATE_CURRENT);
+
+        Notification notification = new Notification.Builder(mContext)
+                .setSmallIcon(com.android.internal.R.drawable.ic_secure)
+                .setWhen(0)
+                .setOngoing(true)
+                .setTicker(title)
+                .setDefaults(0)  // please be quiet
+                .setPriority(Notification.PRIORITY_MAX)
+                .setColor(mContext.getColor(
+                        com.android.internal.R.color.system_notification_accent_color))
+                .setContentTitle(title)
+                .setContentText(message)
+                .setContentInfo(detail)
+                .setVisibility(Notification.VISIBILITY_PUBLIC)
+                .setContentIntent(intent)
+                .build();
+        mNotificationManager.notifyAsUser(null, FBE_ENCRYPTED_NOTIFICATION, notification, user);
+    }
+
+    public void hideEncryptionNotification(UserHandle userHandle) {
+        if (DEBUG) Slog.v(TAG, "hide encryption notification, user: "+ userHandle.getIdentifier());
+        mNotificationManager.cancelAsUser(null, FBE_ENCRYPTED_NOTIFICATION, userHandle);
+    }
+
+    public void onCleanupUser(int userId) {
+        hideEncryptionNotification(new UserHandle(userId));
+    }
+
+    public void onUnlockUser(int userHandle) {
+        hideEncryptionNotification(new UserHandle(userHandle));
     }
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -143,6 +255,7 @@
         }
     };
 
+    @Override // binder interface
     public void systemReady() {
         migrateOldData();
         try {
@@ -695,7 +808,7 @@
             unlockUser(userId, token);
 
             UserInfo info = UserManager.get(mContext).getUserInfo(userId);
-            if (LockPatternUtils.isSeparateWorkChallengeEnabled() && info.isManagedProfile()) {
+            if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
                 TrustManager trustManager =
                         (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
                 trustManager.setDeviceLockedForUser(userId, false);
diff --git a/services/core/java/com/android/server/LockSettingsStorage.java b/services/core/java/com/android/server/LockSettingsStorage.java
index 137fa27..816c791 100644
--- a/services/core/java/com/android/server/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/LockSettingsStorage.java
@@ -71,6 +71,7 @@
     private final Object mFileWriteLock = new Object();
 
     private int mStoredCredentialType;
+    private LockPatternUtils mLockPatternUtils;
 
     class CredentialHash {
         static final int TYPE_NONE = -1;
@@ -100,6 +101,7 @@
     public LockSettingsStorage(Context context, Callback callback) {
         mContext = context;
         mOpenHelper = new DatabaseHelper(context, callback);
+        mLockPatternUtils = new LockPatternUtils(context);
     }
 
     public void writeKeyValue(String key, String value, int userId) {
@@ -388,7 +390,7 @@
 
     private int getUserParentOrSelfId(int userId) {
         // Device supports per user encryption, so lock is applied to the given user.
-        if (LockPatternUtils.isSeparateWorkChallengeEnabled()) {
+        if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
             return userId;
         }
         // Device uses Block Based Encryption, and the parent user's lock is used for the whole
diff --git a/services/core/java/com/android/server/LockSettingsStrongAuth.java b/services/core/java/com/android/server/LockSettingsStrongAuth.java
index 0e4d5a7..551ceb8 100644
--- a/services/core/java/com/android/server/LockSettingsStrongAuth.java
+++ b/services/core/java/com/android/server/LockSettingsStrongAuth.java
@@ -20,6 +20,7 @@
 import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
 
 import android.app.trust.IStrongAuthTracker;
+import android.content.Context;
 import android.os.DeadObjectException;
 import android.os.Handler;
 import android.os.Message;
@@ -46,6 +47,11 @@
 
     private final ArrayList<IStrongAuthTracker> mStrongAuthTrackers = new ArrayList<>();
     private final SparseIntArray mStrongAuthForUser = new SparseIntArray();
+    private final int mDefaultStrongAuthFlags;
+
+    public LockSettingsStrongAuth(Context context) {
+        mDefaultStrongAuthFlags = StrongAuthTracker.getDefaultFlags(context);
+    }
 
     private void handleAddStrongAuthTracker(IStrongAuthTracker tracker) {
         for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
@@ -87,7 +93,7 @@
     }
 
     private void handleRequireStrongAuthOneUser(int strongAuthReason, int userId) {
-        int oldValue = mStrongAuthForUser.get(userId, LockPatternUtils.StrongAuthTracker.DEFAULT);
+        int oldValue = mStrongAuthForUser.get(userId, mDefaultStrongAuthFlags);
         int newValue = strongAuthReason == STRONG_AUTH_NOT_REQUIRED
                 ? STRONG_AUTH_NOT_REQUIRED
                 : (oldValue | strongAuthReason);
@@ -101,7 +107,7 @@
         int index = mStrongAuthForUser.indexOfKey(userId);
         if (index >= 0) {
             mStrongAuthForUser.removeAt(index);
-            notifyStrongAuthTrackers(StrongAuthTracker.DEFAULT, userId);
+            notifyStrongAuthTrackers(mDefaultStrongAuthFlags, userId);
         }
     }
 
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 184f890..4a186a6 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -24,6 +24,7 @@
 import static com.android.internal.util.XmlUtils.writeIntAttribute;
 import static com.android.internal.util.XmlUtils.writeLongAttribute;
 import static com.android.internal.util.XmlUtils.writeStringAttribute;
+
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
@@ -89,9 +90,6 @@
 import android.util.TimeUtils;
 import android.util.Xml;
 
-import libcore.io.IoUtils;
-import libcore.util.EmptyArray;
-
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IMediaContainerService;
 import com.android.internal.os.SomeArgs;
@@ -106,6 +104,9 @@
 import com.android.server.NativeDaemonConnector.SensitiveArg;
 import com.android.server.pm.PackageManagerService;
 
+import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -807,8 +808,8 @@
                 // System user does not have media provider, so skip.
                 if (user.isSystemOnly()) continue;
 
-                final ProviderInfo provider =
-                        mPms.resolveContentProvider(MediaStore.AUTHORITY, 0, user.id);
+                final ProviderInfo provider = mPms.resolveContentProvider(MediaStore.AUTHORITY,
+                        PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.id);
                 if (provider != null) {
                     final IActivityManager am = ActivityManagerNative.getDefault();
                     try {
@@ -2354,7 +2355,8 @@
             return false;
         }
 
-        final int packageUid = mPms.getPackageUid(packageName, UserHandle.getUserId(callerUid));
+        final int packageUid = mPms.getPackageUid(packageName,
+                PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callerUid));
 
         if (DEBUG_OBB) {
             Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
@@ -2812,9 +2814,33 @@
     }
 
     @Override
-    public ParcelFileDescriptor mountAppFuse(String name) throws RemoteException {
-        // TODO: Invoke vold to mount app fuse.
-        throw new UnsupportedOperationException();
+    public ParcelFileDescriptor mountAppFuse(final String name) throws RemoteException {
+        try {
+            final int uid = Binder.getCallingUid();
+            final NativeDaemonEvent event =
+                    mConnector.execute("appfuse", "mount", uid, name);
+            if (event.getFileDescriptors() == null) {
+                throw new RemoteException("AppFuse FD from vold is null.");
+            }
+            return ParcelFileDescriptor.fromFd(
+                    event.getFileDescriptors()[0],
+                    mHandler,
+                    new ParcelFileDescriptor.OnCloseListener() {
+                        @Override
+                        public void onClose(IOException e) {
+                            try {
+                                final NativeDaemonEvent event = mConnector.execute(
+                                        "appfuse", "unmount", uid, name);
+                            } catch (NativeDaemonConnectorException unmountException) {
+                                Log.e(TAG, "Failed to unmount appfuse.");
+                            }
+                        }
+                    });
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        } catch (IOException e) {
+            throw new RemoteException(e.getMessage());
+        }
     }
 
     @Override
@@ -3592,12 +3618,18 @@
         }
 
         pw.println();
-        pw.println("mConnection:");
+        pw.println("mConnector:");
         pw.increaseIndent();
         mConnector.dump(fd, pw, args);
         pw.decreaseIndent();
 
         pw.println();
+        pw.println("mCryptConnector:");
+        pw.increaseIndent();
+        mCryptConnector.dump(fd, pw, args);
+        pw.decreaseIndent();
+
+        pw.println();
         pw.print("Last maintenance: ");
         pw.println(TimeUtils.formatForLogging(mLastMaintenance));
     }
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index dd19c6a..95f5734 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -186,7 +186,6 @@
 
     private final Handler mFgHandler;
     private final Handler mDaemonHandler;
-    private final PhoneStateListener mPhoneStateListener;
 
     private IBatteryStats mBatteryStats;
 
@@ -283,22 +282,6 @@
 
         mDaemonHandler = new Handler(FgThread.get().getLooper());
 
-        mPhoneStateListener = new PhoneStateListener(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
-                mDaemonHandler.getLooper()) {
-            @Override
-            public void onDataConnectionRealTimeInfoChanged(
-                    DataConnectionRealTimeInfo dcRtInfo) {
-                if (DBG) Slog.d(TAG, "onDataConnectionRealTimeInfoChanged: " + dcRtInfo);
-                notifyInterfaceClassActivity(ConnectivityManager.TYPE_MOBILE,
-                        dcRtInfo.getDcPowerState(), dcRtInfo.getTime(), true);
-            }
-        };
-        TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
-        if (tm != null) {
-            tm.listen(mPhoneStateListener,
-                    PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO);
-        }
-
         // Add ourself to the Watchdog monitors.
         Watchdog.getInstance().addMonitor(this);
     }
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index e8b90d8..a291cc7 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -94,7 +94,8 @@
         PackageManager pm = mContext.getPackageManager();
         int allowedUid = -1;
         try {
-            allowedUid = pm.getPackageUid(allowedPackage, userHandle);
+            allowedUid = pm.getPackageUidAsUser(allowedPackage,
+                    PackageManager.MATCH_SYSTEM_ONLY, userHandle);
         } catch (PackageManager.NameNotFoundException e) {
             // not expected
             Slog.e(TAG, "not able to find package " + allowedPackage, e);
diff --git a/services/core/java/com/android/server/SensorNotificationService.java b/services/core/java/com/android/server/SensorNotificationService.java
new file mode 100644
index 0000000..0610464
--- /dev/null
+++ b/services/core/java/com/android/server/SensorNotificationService.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.server;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Slog;
+
+public class SensorNotificationService extends SystemService implements SensorEventListener {
+    //TODO: set DBG to false or remove Slog before release
+    private static final boolean DBG = true;
+    private static final String TAG = "SensorNotificationService";
+    private Context mContext;
+
+    private SensorManager mSensorManager;
+    private Sensor mMetaSensor;
+
+    public SensorNotificationService(Context context) {
+        super(context);
+        mContext = context;
+    }
+
+    public void onStart() {
+        LocalServices.addService(SensorNotificationService.class, this);
+    }
+
+    public void onBootPhase(int phase) {
+        if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+            // start
+            mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
+            mMetaSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_DYNAMIC_SENSOR_META);
+            if (mMetaSensor == null) {
+                if (DBG) Slog.d(TAG, "Cannot obtain dynamic meta sensor, not supported.");
+            } else {
+                mSensorManager.registerListener(this, mMetaSensor,
+                        SensorManager.SENSOR_DELAY_FASTEST);
+            }
+        }
+    }
+
+    private void broadcastDynamicSensorChanged() {
+        Intent i = new Intent(Intent.ACTION_DYNAMIC_SENSOR_CHANGED);
+        i.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); // avoid waking up manifest receivers
+        mContext.sendBroadcastAsUser(i, UserHandle.ALL);
+        if (DBG) Slog.d(TAG, "DYNS sent dynamic sensor broadcast");
+    }
+
+    @Override
+    public void onSensorChanged(SensorEvent event) {
+        if (event.sensor == mMetaSensor) {
+            broadcastDynamicSensorChanged();
+        }
+    }
+
+    @Override
+    public void onAccuracyChanged(Sensor sensor, int accuracy) {
+
+    }
+}
+
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index 86183af..5aba22d 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -16,20 +16,24 @@
 
 package com.android.server;
 
+import static com.android.internal.util.ArrayUtils.appendInt;
+
 import android.app.ActivityManager;
 import android.content.pm.FeatureInfo;
-import android.os.*;
+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 libcore.io.IoUtils;
-
 import com.android.internal.util.XmlUtils;
 
+import libcore.io.IoUtils;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -38,8 +42,6 @@
 import java.io.FileReader;
 import java.io.IOException;
 
-import static com.android.internal.util.ArrayUtils.appendInt;
-
 /**
  * Loads global system configuration info.
  */
@@ -48,6 +50,13 @@
 
     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;
 
@@ -161,21 +170,27 @@
     SystemConfig() {
         // Read configuration from system
         readPermissions(Environment.buildPath(
-                Environment.getRootDirectory(), "etc", "sysconfig"), false);
+                Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);
         // Read configuration from the old permissions dir
         readPermissions(Environment.buildPath(
-                Environment.getRootDirectory(), "etc", "permissions"), false);
-        // Only read features from OEM config
+                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.getOemDirectory(), "etc", "sysconfig"), true);
+                Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
         readPermissions(Environment.buildPath(
-                Environment.getOemDirectory(), "etc", "permissions"), true);
+                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, boolean onlyFeatures) {
+    void readPermissions(File libraryDir, int permissionFlag) {
         // Read permissions from given directory.
         if (!libraryDir.exists() || !libraryDir.isDirectory()) {
-            if (!onlyFeatures) {
+            if (permissionFlag == ALLOW_ALL) {
                 Slog.w(TAG, "No directory " + libraryDir + ", skipping");
             }
             return;
@@ -203,16 +218,16 @@
                 continue;
             }
 
-            readPermissionsFromXml(f, onlyFeatures);
+            readPermissionsFromXml(f, permissionFlag);
         }
 
         // Read platform permissions last so it will take precedence
         if (platformFile != null) {
-            readPermissionsFromXml(platformFile, onlyFeatures);
+            readPermissionsFromXml(platformFile, permissionFlag);
         }
     }
 
-    private void readPermissionsFromXml(File permFile, boolean onlyFeatures) {
+    private void readPermissionsFromXml(File permFile, int permissionFlag) {
         FileReader permReader = null;
         try {
             permReader = new FileReader(permFile);
@@ -242,6 +257,11 @@
                         + ": 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) {
@@ -249,7 +269,7 @@
                 }
 
                 String name = parser.getName();
-                if ("group".equals(name) && !onlyFeatures) {
+                if ("group".equals(name) && allowAll) {
                     String gidStr = parser.getAttributeValue(null, "gid");
                     if (gidStr != null) {
                         int gid = android.os.Process.getGidForName(gidStr);
@@ -261,7 +281,7 @@
 
                     XmlUtils.skipCurrentTag(parser);
                     continue;
-                } else if ("permission".equals(name) && !onlyFeatures) {
+                } else if ("permission".equals(name) && allowPermissions) {
                     String perm = parser.getAttributeValue(null, "name");
                     if (perm == null) {
                         Slog.w(TAG, "<permission> without name in " + permFile + " at "
@@ -272,7 +292,7 @@
                     perm = perm.intern();
                     readPermission(parser, perm);
 
-                } else if ("assign-permission".equals(name) && !onlyFeatures) {
+                } 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 "
@@ -304,7 +324,7 @@
                     perms.add(perm);
                     XmlUtils.skipCurrentTag(parser);
 
-                } else if ("library".equals(name) && !onlyFeatures) {
+                } else if ("library".equals(name) && allowLibs) {
                     String lname = parser.getAttributeValue(null, "name");
                     String lfile = parser.getAttributeValue(null, "file");
                     if (lname == null) {
@@ -320,7 +340,7 @@
                     XmlUtils.skipCurrentTag(parser);
                     continue;
 
-                } else if ("feature".equals(name)) {
+                } else if ("feature".equals(name) && allowFeatures) {
                     String fname = parser.getAttributeValue(null, "name");
                     boolean allowed;
                     if (!lowRam) {
@@ -333,15 +353,12 @@
                         Slog.w(TAG, "<feature> without name in " + permFile + " at "
                                 + parser.getPositionDescription());
                     } else if (allowed) {
-                        //Log.i(TAG, "Got feature " + fname);
-                        FeatureInfo fi = new FeatureInfo();
-                        fi.name = fname;
-                        mAvailableFeatures.put(fname, fi);
+                        addFeature(fname);
                     }
                     XmlUtils.skipCurrentTag(parser);
                     continue;
 
-                } else if ("unavailable-feature".equals(name)) {
+                } 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 "
@@ -352,7 +369,7 @@
                     XmlUtils.skipCurrentTag(parser);
                     continue;
 
-                } else if ("allow-in-power-save-except-idle".equals(name) && !onlyFeatures) {
+                } 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 "
@@ -363,7 +380,7 @@
                     XmlUtils.skipCurrentTag(parser);
                     continue;
 
-                } else if ("allow-in-power-save".equals(name) && !onlyFeatures) {
+                } 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 "
@@ -374,7 +391,7 @@
                     XmlUtils.skipCurrentTag(parser);
                     continue;
 
-                } else if ("fixed-ime-app".equals(name) && !onlyFeatures) {
+                } 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 "
@@ -385,7 +402,7 @@
                     XmlUtils.skipCurrentTag(parser);
                     continue;
 
-                } else if ("app-link".equals(name)) {
+                } 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 "
@@ -394,7 +411,7 @@
                         mLinkedApps.add(pkgname);
                     }
                     XmlUtils.skipCurrentTag(parser);
-                } else if ("system-user-whitelisted-app".equals(name)) {
+                } 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
@@ -403,7 +420,7 @@
                         mSystemUserWhitelistedApps.add(pkgname);
                     }
                     XmlUtils.skipCurrentTag(parser);
-                } else if ("system-user-blacklisted-app".equals(name)) {
+                } 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
@@ -425,10 +442,29 @@
             IoUtils.closeQuietly(permReader);
         }
 
-        for (String fname : mUnavailableFeatures) {
-            if (mAvailableFeatures.remove(fname) != null) {
-                Slog.d(TAG, "Removed unavailable feature " + fname);
-            }
+        // 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);
+            addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS);
+        }
+
+        for (String featureName : mUnavailableFeatures) {
+            removeFeature(featureName);
+        }
+    }
+
+    private void addFeature(String featureName) {
+        if (!mAvailableFeatures.containsKey(featureName)) {
+            final FeatureInfo fi = new FeatureInfo();
+            fi.name = featureName;
+            mAvailableFeatures.put(featureName, fi);
+        }
+    }
+
+    private void removeFeature(String featureName) {
+        if (mAvailableFeatures.remove(featureName) != null) {
+            Slog.d(TAG, "Removed unavailable feature " + featureName);
         }
     }
 
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 19a4851..820551d 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -34,7 +34,6 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.telephony.CellLocation;
-import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.Rlog;
 import android.telephony.TelephonyManager;
 import android.telephony.SubscriptionManager;
@@ -179,8 +178,6 @@
 
     private int mDefaultPhoneId = SubscriptionManager.INVALID_PHONE_INDEX;
 
-    private DataConnectionRealTimeInfo mDcRtInfo = new DataConnectionRealTimeInfo();
-
     private int mRingingCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
 
     private int mForegroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
@@ -262,7 +259,8 @@
                 mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHED, userHandle, 0));
             } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED)) {
                 Integer newDefaultSubIdObj = new Integer(intent.getIntExtra(
-                        PhoneConstants.SUBSCRIPTION_KEY, SubscriptionManager.getDefaultSubId()));
+                        PhoneConstants.SUBSCRIPTION_KEY,
+                        SubscriptionManager.getDefaultSubscriptionId()));
                 int newDefaultPhoneId = intent.getIntExtra(PhoneConstants.SLOT_KEY,
                     SubscriptionManager.getPhoneId(mDefaultSubId));
                 if (DBG) {
@@ -624,13 +622,6 @@
                             remove(r.binder);
                         }
                     }
-                    if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO) != 0) {
-                        try {
-                            r.callback.onDataConnectionRealTimeInfoChanged(mDcRtInfo);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
-                    }
                     if ((events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
                         try {
                             r.callback.onPreciseCallStateChanged(mPreciseCallState);
@@ -921,31 +912,6 @@
         }
     }
 
-    public void notifyDataConnectionRealTimeInfo(DataConnectionRealTimeInfo dcRtInfo) {
-        if (!checkNotifyPermission("notifyDataConnectionRealTimeInfo()")) {
-            return;
-        }
-
-        synchronized (mRecords) {
-            mDcRtInfo = dcRtInfo;
-            for (Record r : mRecords) {
-                if (validateEventsAndUserLocked(r,
-                        PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO)) {
-                    try {
-                        if (DBG_LOC) {
-                            log("notifyDataConnectionRealTimeInfo: mDcRtInfo="
-                                    + mDcRtInfo + " r=" + r);
-                        }
-                        r.callback.onDataConnectionRealTimeInfoChanged(mDcRtInfo);
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
-                    }
-                }
-            }
-            handleRemoveListLocked();
-        }
-    }
-
     @Override
     public void notifyMessageWaitingChangedForPhoneId(int phoneId, int subId, boolean mwi) {
         if (!checkNotifyPermission("notifyMessageWaitingChanged()")) {
@@ -1370,7 +1336,6 @@
                 pw.println("  mCellLocation=" + mCellLocation[i]);
                 pw.println("  mCellInfo=" + mCellInfo.get(i));
             }
-            pw.println("  mDcRtInfo=" + mDcRtInfo);
             pw.println("registrations: count=" + recordCount);
             for (Record r : mRecords) {
                 pw.println("  " + r);
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index ca5212a..143015f 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -37,7 +37,9 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.app.admin.DeviceAdminInfo;
 import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManagerInternal;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentValues;
@@ -82,6 +84,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.FgThread;
+import com.android.server.LocalServices;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Sets;
 
@@ -173,6 +176,7 @@
     private static final String[] ACCOUNT_TYPE_COUNT_PROJECTION =
             new String[] { ACCOUNTS_TYPE, ACCOUNTS_TYPE_COUNT};
     private static final Intent ACCOUNTS_CHANGED_INTENT;
+
     static {
         ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
         ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
@@ -830,7 +834,8 @@
             throw new SecurityException(msg);
         }
 
-        if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
+        if (!canUserModifyAccounts(userId, callingUid) ||
+                !canUserModifyAccountsForType(userId, account.type, callingUid)) {
             return false;
         }
 
@@ -1259,7 +1264,7 @@
                     account.type);
             throw new SecurityException(msg);
         }
-        if (!canUserModifyAccounts(userId)) {
+        if (!canUserModifyAccounts(userId, callingUid)) {
             try {
                 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
                         "User cannot modify accounts");
@@ -1267,7 +1272,7 @@
             }
             return;
         }
-        if (!canUserModifyAccountsForType(userId, account.type)) {
+        if (!canUserModifyAccountsForType(userId, account.type, callingUid)) {
             try {
                 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
                         "User cannot modify accounts of this type (policy).");
@@ -1321,9 +1326,6 @@
             throw new SecurityException(msg);
         }
         UserAccounts accounts = getUserAccountsForCaller();
-        if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
-            return false;
-        }
         logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE, TABLE_ACCOUNTS);
         long identityToken = clearCallingIdentity();
         try {
@@ -2146,8 +2148,9 @@
         if (accountType == null) throw new IllegalArgumentException("accountType is null");
 
         // Is user disallowed from modifying accounts?
-        int userId = Binder.getCallingUserHandle().getIdentifier();
-        if (!canUserModifyAccounts(userId)) {
+        final int uid = Binder.getCallingUid();
+        final int userId = UserHandle.getUserId(uid);
+        if (!canUserModifyAccounts(userId, uid)) {
             try {
                 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
                         "User is not allowed to add an account!");
@@ -2156,7 +2159,7 @@
             showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
             return;
         }
-        if (!canUserModifyAccountsForType(userId, accountType)) {
+        if (!canUserModifyAccountsForType(userId, accountType, uid)) {
             try {
                 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
                         "User cannot modify accounts of this type (policy).");
@@ -2168,7 +2171,6 @@
         }
 
         final int pid = Binder.getCallingPid();
-        final int uid = Binder.getCallingUid();
         final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
         options.putInt(AccountManager.KEY_CALLER_UID, uid);
         options.putInt(AccountManager.KEY_CALLER_PID, pid);
@@ -2230,7 +2232,7 @@
         }
 
         // Is user disallowed from modifying accounts?
-        if (!canUserModifyAccounts(userId)) {
+        if (!canUserModifyAccounts(userId, callingUid)) {
             try {
                 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
                         "User is not allowed to add an account!");
@@ -2239,7 +2241,7 @@
             showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
             return;
         }
-        if (!canUserModifyAccountsForType(userId, accountType)) {
+        if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
             try {
                 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
                         "User cannot modify accounts of this type (policy).");
@@ -2310,8 +2312,17 @@
             throw new IllegalArgumentException("accountType is null");
         }
 
-        int userId = Binder.getCallingUserHandle().getIdentifier();
-        if (!canUserModifyAccounts(userId)) {
+        final int uid = Binder.getCallingUid();
+        // Only allow system to start session
+        if (!isSystemUid(uid)) {
+            String msg = String.format(
+                    "uid %s cannot stat add account session.",
+                    uid);
+            throw new SecurityException(msg);
+        }
+
+        final int userId = UserHandle.getUserId(uid);
+        if (!canUserModifyAccounts(userId, uid)) {
             try {
                 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
                         "User is not allowed to add an account!");
@@ -2320,7 +2331,7 @@
             showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
             return;
         }
-        if (!canUserModifyAccountsForType(userId, accountType)) {
+        if (!canUserModifyAccountsForType(userId, accountType, uid)) {
             try {
                 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
                         "User cannot modify accounts of this type (policy).");
@@ -2332,7 +2343,6 @@
         }
 
         final int pid = Binder.getCallingPid();
-        final int uid = Binder.getCallingUid();
         final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
         options.putInt(AccountManager.KEY_CALLER_UID, uid);
         options.putInt(AccountManager.KEY_CALLER_PID, pid);
@@ -2476,16 +2486,20 @@
     }
 
     @Override
-    public void finishSession(IAccountManagerResponse response,
+    public void finishSessionAsUser(IAccountManagerResponse response,
             @NonNull Bundle sessionBundle,
             boolean expectActivityLaunch,
-            Bundle appInfo) {
+            Bundle appInfo,
+            int userId) {
+        int callingUid = Binder.getCallingUid();
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG,
                     "finishSession: response "+ response
                             + ", expectActivityLaunch " + expectActivityLaunch
-                            + ", caller's uid " + Binder.getCallingUid()
-                            + ", pid " + Binder.getCallingPid());
+                            + ", caller's uid " + callingUid
+                            + ", caller's user id " + UserHandle.getCallingUserId()
+                            + ", pid " + Binder.getCallingPid()
+                            + ", for user id " + userId);
         }
         if (response == null) {
             throw new IllegalArgumentException("response is null");
@@ -2497,8 +2511,24 @@
             throw new IllegalArgumentException("sessionBundle is empty");
         }
 
-        int userId = Binder.getCallingUserHandle().getIdentifier();
-        if (!canUserModifyAccounts(userId)) {
+        // Only allow the system process to finish session for other users
+        if (isCrossUser(callingUid, userId)) {
+            throw new SecurityException(
+                    String.format(
+                            "User %s trying to finish session for %s without cross user permission",
+                            UserHandle.getCallingUserId(),
+                            userId));
+        }
+
+        // Only allow system to finish session
+        if (!isSystemUid(callingUid)) {
+            String msg = String.format(
+                    "uid %s cannot finish session because it's not system uid.",
+                    callingUid);
+            throw new SecurityException(msg);
+        }
+
+        if (!canUserModifyAccounts(userId, callingUid)) {
             sendErrorResponse(response,
                     AccountManager.ERROR_CODE_USER_RESTRICTED,
                     "User is not allowed to add an account!");
@@ -2507,7 +2537,6 @@
         }
 
         final int pid = Binder.getCallingPid();
-        final int uid = Binder.getCallingUid();
         final Bundle decryptedBundle;
         final String accountType;
         // First decrypt session bundle to get account type for checking permission.
@@ -2541,7 +2570,7 @@
             }
 
             // Add info that may be used by add account or update credentials flow.
-            decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, uid);
+            decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, callingUid);
             decryptedBundle.putInt(AccountManager.KEY_CALLER_PID, pid);
         } catch (GeneralSecurityException e) {
             if (Log.isLoggable(TAG, Log.DEBUG)) {
@@ -2554,7 +2583,7 @@
             return;
         }
 
-        if (!canUserModifyAccountsForType(userId, accountType)) {
+        if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
             sendErrorResponse(
                     response,
                     AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
@@ -2571,7 +2600,7 @@
                     accounts,
                     DebugDbHelper.ACTION_CALLED_ACCOUNT_SESSION_FINISH,
                     TABLE_ACCOUNTS,
-                    uid);
+                    callingUid);
             new Session(
                     accounts,
                     response,
@@ -2716,6 +2745,16 @@
         if (account == null) {
             throw new IllegalArgumentException("account is null");
         }
+
+        final int uid = Binder.getCallingUid();
+        // Only allow system to start session
+        if (!isSystemUid(uid)) {
+            String msg = String.format(
+                    "uid %s cannot start update credentials session.",
+                    uid);
+            throw new SecurityException(msg);
+        }
+
         int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
@@ -2751,6 +2790,99 @@
     }
 
     @Override
+    public void isCredentialsUpdateSuggested(
+            IAccountManagerResponse response,
+            final Account account,
+            final String statusToken) {
+        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+            Log.v(TAG,
+                    "isCredentialsUpdateSuggested: " + account + ", response " + response
+                            + ", caller's uid " + Binder.getCallingUid()
+                            + ", pid " + Binder.getCallingPid());
+        }
+        if (response == null) {
+            throw new IllegalArgumentException("response is null");
+        }
+        if (account == null) {
+            throw new IllegalArgumentException("account is null");
+        }
+        if (TextUtils.isEmpty(statusToken)) {
+            throw new IllegalArgumentException("status token is empty");
+        }
+
+        int uid = Binder.getCallingUid();
+        // Only allow system to start session
+        if (!isSystemUid(uid)) {
+            String msg = String.format(
+                    "uid %s cannot stat add account session.",
+                    uid);
+            throw new SecurityException(msg);
+        }
+
+        int usrId = UserHandle.getCallingUserId();
+        long identityToken = clearCallingIdentity();
+        try {
+            UserAccounts accounts = getUserAccounts(usrId);
+            new Session(accounts, response, account.type, false /* expectActivityLaunch */,
+                    false /* stripAuthTokenFromResult */, account.name,
+                    false /* authDetailsRequired */) {
+                @Override
+                protected String toDebugString(long now) {
+                    return super.toDebugString(now) + ", isCredentialsUpdateSuggested"
+                            + ", " + account;
+                }
+
+                @Override
+                public void run() throws RemoteException {
+                    mAuthenticator.isCredentialsUpdateSuggested(this, account, statusToken);
+                }
+
+                @Override
+                public void onResult(Bundle result) {
+                    IAccountManagerResponse response = getResponseAndClose();
+                    if (response == null) {
+                        return;
+                    }
+
+                    if (result == null) {
+                        sendErrorResponse(
+                                response,
+                                AccountManager.ERROR_CODE_INVALID_RESPONSE,
+                                "null bundle");
+                        return;
+                    }
+
+                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                        Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
+                                + response);
+                    }
+                    // Check to see if an error occurred. We know if an error occurred because all
+                    // error codes are greater than 0.
+                    if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0)) {
+                        sendErrorResponse(response,
+                                result.getInt(AccountManager.KEY_ERROR_CODE),
+                                result.getString(AccountManager.KEY_ERROR_MESSAGE));
+                        return;
+                    }
+                    if (!result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)) {
+                        sendErrorResponse(
+                                response,
+                                AccountManager.ERROR_CODE_INVALID_RESPONSE,
+                                "no result in response");
+                        return;
+                    }
+                    final Bundle newResult = new Bundle();
+                    newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
+                            result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
+                    sendResponse(response, newResult);
+                }
+            }.bind();
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    @Override
     public void editProperties(IAccountManagerResponse response, final String accountType,
             final boolean expectActivityLaunch) {
         final int callingUid = Binder.getCallingUid();
@@ -2792,6 +2924,25 @@
         }
     }
 
+    @Override
+    public boolean someUserHasAccount(@NonNull final Account account) {
+        if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) {
+            throw new SecurityException("Only system can check for accounts across users");
+        }
+        final long token = Binder.clearCallingIdentity();
+        try {
+            AccountAndUser[] allAccounts = getAllAccounts();
+            for (int i = allAccounts.length - 1; i >= 0; i--) {
+                if (allAccounts[i].account.equals(account)) {
+                    return true;
+                }
+            }
+            return false;
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     private class GetAccountsByTypeAndFeatureSession extends Session {
         private final String[] mFeatures;
         private volatile Account[] mAccountsOfType = null;
@@ -3173,7 +3324,8 @@
         int packageUid = -1;
         try {
             packageUid = AppGlobals.getPackageManager().getPackageUid(
-                    packageName, UserHandle.getCallingUserId());
+                    packageName, PackageManager.MATCH_UNINSTALLED_PACKAGES,
+                    UserHandle.getCallingUserId());
         } catch (RemoteException re) {
             Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
             return new Account[0];
@@ -4114,21 +4266,6 @@
         }
     }
 
-    private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
-        for (String perm : permissions) {
-            if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
-                if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    Log.v(TAG, "  caller uid " + callingUid + " has " + perm);
-                }
-                final int opCode = AppOpsManager.permissionToOpCode(perm);
-                if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
-                        opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
 
     private int handleIncomingUser(int userId) {
         try {
@@ -4203,12 +4340,53 @@
 
     private List<String> getTypesVisibleToCaller(int callingUid, int userId,
             String opPackageName) {
-        boolean isPermitted =
-                isPermitted(opPackageName, callingUid, Manifest.permission.GET_ACCOUNTS,
-                        Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
+        List<String> permissionsToCheck = new ArrayList<String>(2);
+        permissionsToCheck.add(Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
+        long id = Binder.clearCallingIdentity();
+        try {
+            ApplicationInfo appInfo = mPackageManager.getApplicationInfo(
+                    opPackageName, 0 /* flags */);
+            /*
+             * At or before SDK 23, clients discover all the accounts in their
+             * user profile (via AccountManager.getAccounts(...)) by declaring
+             * the GET_ACCOUNTS permission.
+             *
+             * After SDK 23 the GET_ACCOUNTS permission is deprecated.  Instead
+             * apps will be able to retrieve those accounts managed by
+             * authenticators sharing a package signature without any special
+             * permissions. The only clients able to discover all the accounts
+             * on the device will be those with the GET_ACCOUNTS_PRVILEGED
+             * system permission.
+             */
+            if (23 >= appInfo.targetSdkVersion) {
+                permissionsToCheck.add(Manifest.permission.GET_ACCOUNTS);
+            }
+        } catch (NameNotFoundException e) {
+            // No application associated with the specified package.
+            Log.w(TAG, "No application associated with package: " + opPackageName);
+        } finally {
+            Binder.restoreCallingIdentity(id);
+        }
+        boolean isPermitted = isPermitted(opPackageName, callingUid, permissionsToCheck);
         return getTypesForCaller(callingUid, userId, isPermitted);
     }
 
+    private boolean isPermitted(String opPackageName, int callingUid, List<String> permissions) {
+        for (String perm : permissions) {
+            if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, "  caller uid " + callingUid + " has " + perm);
+                }
+                final int opCode = AppOpsManager.permissionToOpCode(perm);
+                if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
+                        opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     private List<String> getTypesManagedByCaller(int callingUid, int userId) {
         return getTypesForCaller(callingUid, userId, false);
     }
@@ -4319,7 +4497,11 @@
         }
     }
 
-    private boolean canUserModifyAccounts(int userId) {
+    private boolean canUserModifyAccounts(int userId, int callingUid) {
+        // the managing app can always modify accounts
+        if (isProfileOwner(callingUid)) {
+            return true;
+        }
         if (getUserManager().getUserRestrictions(new UserHandle(userId))
                 .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
             return false;
@@ -4327,7 +4509,11 @@
         return true;
     }
 
-    private boolean canUserModifyAccountsForType(int userId, String accountType) {
+    private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) {
+        // the managing app can always modify accounts
+        if (isProfileOwner(callingUid)) {
+            return true;
+        }
         DevicePolicyManager dpm = (DevicePolicyManager) mContext
                 .getSystemService(Context.DEVICE_POLICY_SERVICE);
         String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
@@ -4342,6 +4528,13 @@
         return true;
     }
 
+    private boolean isProfileOwner(int uid) {
+        final DevicePolicyManagerInternal dpmi =
+                LocalServices.getService(DevicePolicyManagerInternal.class);
+        return (dpmi != null)
+                && dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+    }
+
     @Override
     public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
             throws RemoteException {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 4348913..8c0ec78 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -61,6 +61,7 @@
 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;
@@ -326,7 +327,7 @@
 
         ServiceLookupResult res =
             retrieveServiceLocked(service, resolvedType, callingPackage,
-                    callingPid, callingUid, userId, true, callerFg);
+                    callingPid, callingUid, userId, true, callerFg, false);
         if (res == null) {
             return null;
         }
@@ -549,7 +550,7 @@
 
         // If this service is active, make sure it is stopped.
         ServiceLookupResult r = retrieveServiceLocked(service, resolvedType, null,
-                Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false);
+                Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false, false);
         if (r != null) {
             if (r.record != null) {
                 final long origId = Binder.clearCallingIdentity();
@@ -598,7 +599,7 @@
     IBinder peekServiceLocked(Intent service, String resolvedType, String callingPackage) {
         ServiceLookupResult r = retrieveServiceLocked(service, resolvedType, callingPackage,
                 Binder.getCallingPid(), Binder.getCallingUid(),
-                UserHandle.getCallingUserId(), false, false);
+                UserHandle.getCallingUserId(), false, false, false);
 
         IBinder ret = null;
         if (r != null) {
@@ -831,10 +832,11 @@
         }
 
         final boolean callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
+        final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0;
 
         ServiceLookupResult res =
-            retrieveServiceLocked(service, resolvedType, callingPackage,
-                    Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);
+            retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
+                    Binder.getCallingUid(), userId, true, callerFg, isBindExternal);
         if (res == null) {
             return 0;
         }
@@ -1192,7 +1194,7 @@
 
     private ServiceLookupResult retrieveServiceLocked(Intent service,
             String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
-            boolean createIfNeeded, boolean callingFromFg) {
+            boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal) {
         ServiceRecord r = null;
         if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "retrieveServiceLocked: " + service
                 + " type=" + resolvedType + " callingUid=" + callingUid);
@@ -1205,16 +1207,23 @@
         if (comp != null) {
             r = smap.mServicesByName.get(comp);
         }
-        if (r == null) {
+        if (r == null && !isBindExternal) {
             Intent.FilterComparison filter = new Intent.FilterComparison(service);
             r = smap.mServicesByIntent.get(filter);
         }
+        if (r != null && (r.serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0
+                && !callingPackage.equals(r.packageName)) {
+            // If an external service is running within its own package, other packages
+            // should not bind to that instance.
+            r = null;
+        }
         if (r == null) {
             try {
-                ResolveInfo rInfo =
-                    AppGlobals.getPackageManager().resolveService(
-                                service, resolvedType,
-                                ActivityManagerService.STOCK_PM_FLAGS, userId);
+                // TODO: come back and remove this assumption to triage all services
+                ResolveInfo rInfo = AppGlobals.getPackageManager().resolveService(service,
+                        resolvedType, ActivityManagerService.STOCK_PM_FLAGS
+                                | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
+                        userId);
                 ServiceInfo sInfo =
                     rInfo != null ? rInfo.serviceInfo : null;
                 if (sInfo == null) {
@@ -1224,6 +1233,37 @@
                 }
                 ComponentName name = new ComponentName(
                         sInfo.applicationInfo.packageName, sInfo.name);
+                if ((sInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0) {
+                    if (isBindExternal) {
+                        if (!sInfo.exported) {
+                            throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " + name +
+                                    " is not exported");
+                        }
+                        if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) == 0) {
+                            throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " + name +
+                                    " is not an isolatedProcess");
+                        }
+                        // Run the service under the calling package's application.
+                        ApplicationInfo aInfo = AppGlobals.getPackageManager().getApplicationInfo(
+                                callingPackage, ActivityManagerService.STOCK_PM_FLAGS, userId);
+                        if (aInfo == null) {
+                            throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " +
+                                    "could not resolve client package " + callingPackage);
+                        }
+                        sInfo = new ServiceInfo(sInfo);
+                        sInfo.applicationInfo = new ApplicationInfo(sInfo.applicationInfo);
+                        sInfo.applicationInfo.packageName = aInfo.packageName;
+                        sInfo.applicationInfo.uid = aInfo.uid;
+                        name = new ComponentName(aInfo.packageName, name.getClassName());
+                        service.setComponent(name);
+                    } else {
+                        throw new SecurityException("BIND_EXTERNAL_SERVICE required for " +
+                                name);
+                    }
+                } else if (isBindExternal) {
+                    throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " + name +
+                            " is not an externalService");
+                }
                 if (userId > 0) {
                     if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo,
                             sInfo.name, sInfo.flags)
@@ -1244,7 +1284,7 @@
                                 sInfo.applicationInfo.uid, sInfo.packageName, callingPid);
                         if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
                             Slog.w(TAG, "Background execution not allowed: service "
-                                    + r.intent + " to " + name.flattenToShortString()
+                                    + service + " to " + name.flattenToShortString()
                                     + " from pid=" + callingPid + " uid=" + callingUid
                                     + " pkg=" + callingPackage);
                             return null;
@@ -2735,7 +2775,7 @@
         }
 
         if (anrMessage != null) {
-            mAm.appNotResponding(proc, null, null, false, anrMessage);
+            mAm.mAppErrors.appNotResponding(proc, null, null, false, anrMessage);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d8724b27..b5982c3 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -18,7 +18,6 @@
 
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
-
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.AssistUtils;
@@ -35,6 +34,7 @@
 import com.android.internal.os.ProcessCpuTracker;
 import com.android.internal.os.TransferPipe;
 import com.android.internal.os.Zygote;
+import com.android.internal.os.InstallerConnection.InstallerException;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.FastXmlSerializer;
@@ -53,6 +53,7 @@
 import com.android.server.firewall.IntentFirewall;
 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;
 
@@ -140,6 +141,7 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.database.ContentObserver;
 import android.graphics.Bitmap;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -186,6 +188,7 @@
 import android.os.storage.StorageManager;
 import android.provider.Settings;
 import android.service.voice.IVoiceInteractionSession;
+import android.service.voice.VoiceInteractionManagerInternal;
 import android.service.voice.VoiceInteractionSession;
 import android.text.format.DateUtils;
 import android.text.format.Time;
@@ -238,11 +241,13 @@
 import java.util.concurrent.atomic.AtomicLong;
 
 import dalvik.system.VMRuntime;
+
 import libcore.io.IoUtils;
 import libcore.util.EmptyArray;
 
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
 import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
@@ -253,19 +258,25 @@
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
 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_SYSTEM_ONLY;
+import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
 import static android.provider.Settings.Global.DEBUG_APP;
+import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
 import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
+import static android.provider.Settings.System.FONT_SCALE;
 import static com.android.internal.util.XmlUtils.readBooleanAttribute;
 import static com.android.internal.util.XmlUtils.readIntAttribute;
 import static com.android.internal.util.XmlUtils.readLongAttribute;
 import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
 import static com.android.internal.util.XmlUtils.writeIntAttribute;
 import static com.android.internal.util.XmlUtils.writeLongAttribute;
-import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKUP;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
@@ -323,6 +334,7 @@
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBLE_BEHIND;
 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.ActivityStackSupervisor.ActivityContainer.FORCE_NEW_TASK_FLAGS;
 import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
 import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
@@ -379,7 +391,7 @@
     // The flags that are set for all calls we make to the package manager.
     static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
 
-    private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
+    static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
 
     static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
 
@@ -508,7 +520,9 @@
     private Installer mInstaller;
 
     /** Run all ActivityStacks through this */
-    ActivityStackSupervisor mStackSupervisor;
+    final ActivityStackSupervisor mStackSupervisor;
+
+    final ActivityStarter mActivityStarter;
 
     /** Task stack change listeners. */
     private RemoteCallbackList<ITaskStackListener> mTaskStackListeners =
@@ -520,6 +534,7 @@
     // default actuion automatically.  Important for devices without direct input
     // devices.
     private boolean mShowDialogs = true;
+    private boolean mInVrMode = false;
 
     BroadcastQueue mFgBroadcastQueue;
     BroadcastQueue mBgBroadcastQueue;
@@ -553,7 +568,7 @@
     /**
      * List of intents that were used to start the most recent tasks.
      */
-    private final RecentTasks mRecentTasks;
+    final RecentTasks mRecentTasks;
 
     /**
      * For addAppTask: cached of the last activity component that was added.
@@ -582,6 +597,12 @@
 
     final UserController mUserController;
 
+    final AppErrors mAppErrors;
+
+    public boolean canShowErrorDialogs() {
+        return mShowDialogs && !mSleeping && !mShuttingDown;
+    }
+
     public class PendingAssistExtras extends Binder implements Runnable {
         public final ActivityRecord activity;
         public final Bundle extras;
@@ -652,38 +673,6 @@
     ProcessRecord mHeavyWeightProcess = null;
 
     /**
-     * The last time that various processes have crashed.
-     */
-    final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
-
-    /**
-     * Information about a process that is currently marked as bad.
-     */
-    static final class BadProcessInfo {
-        BadProcessInfo(long time, String shortMsg, String longMsg, String stack) {
-            this.time = time;
-            this.shortMsg = shortMsg;
-            this.longMsg = longMsg;
-            this.stack = stack;
-        }
-
-        final long time;
-        final String shortMsg;
-        final String longMsg;
-        final String stack;
-    }
-
-    /**
-     * Set of applications that we consider to be bad, and will reject
-     * incoming broadcasts from (which the user has no control over).
-     * Processes are added to this set when they have crashed twice within
-     * a minimum amount of time; they are removed from it when they are
-     * later restarted (hopefully due to some user action).  The value is the
-     * time it was added to the list.
-     */
-    final ProcessMap<BadProcessInfo> mBadProcesses = new ProcessMap<BadProcessInfo>();
-
-    /**
      * All of the processes we currently have running organized by pid.
      * The keys are the pid running the application.
      *
@@ -1001,6 +990,25 @@
 
     CoreSettingsObserver mCoreSettingsObserver;
 
+    FontScaleSettingObserver mFontScaleSettingObserver;
+
+    private final class FontScaleSettingObserver extends ContentObserver {
+        private final Uri mFontScaleUri = Settings.System.getUriFor(FONT_SCALE);
+
+        public FontScaleSettingObserver() {
+            super(mHandler);
+            ContentResolver resolver = mContext.getContentResolver();
+            resolver.registerContentObserver(mFontScaleUri, false, this, UserHandle.USER_ALL);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            if (mFontScaleUri.equals(uri)) {
+                updateFontScaleIfNeeded();
+            }
+        }
+    }
+
     /**
      * Thread-local storage used to carry caller permissions over through
      * indirect content-provider access.
@@ -1041,11 +1049,6 @@
     final AppOpsService mAppOpsService;
 
     /**
-     * Save recent tasks information across reboots.
-     */
-    final TaskPersister mTaskPersister;
-
-    /**
      * Current configuration information.  HistoryRecord objects are given
      * a reference to this object to indicate which configuration they are
      * currently running in, so this object must be kept immutable.
@@ -1281,6 +1284,7 @@
     boolean mForceResizableActivities;
     boolean mSupportsFreeformWindowManagement;
     boolean mSupportsPictureInPicture;
+    Rect mDefaultPinnedStackBounds;
     IActivityController mController = null;
     String mProfileApp = null;
     ProcessRecord mProfileProc = null;
@@ -1296,7 +1300,7 @@
     int mMemWatchDumpUid;
     String mTrackAllocationApp = null;
 
-    final long[] mTmpLong = new long[1];
+    final long[] mTmpLong = new long[2];
 
     static final class ProcessChangeItem {
         static final int CHANGE_ACTIVITIES = 1<<0;
@@ -1320,8 +1324,6 @@
     final ArrayList<UidRecord.ChangeItem> mPendingUidChanges = new ArrayList<>();
     final ArrayList<UidRecord.ChangeItem> mAvailUidChanges = new ArrayList<>();
 
-    ArraySet<String> mAppsNotReportingCrashes;
-
     /**
      * Runtime CPU use collection thread.  This object's lock is used to
      * perform synchronization with the thread (notifying it to run).
@@ -1439,6 +1441,9 @@
     static final int IDLE_UIDS_MSG = 60;
     static final int SYSTEM_USER_UNLOCK_MSG = 61;
     static final int LOG_STACK_STATE = 62;
+    static final int VR_MODE_CHANGE_MSG = 63;
+    static final int NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG = 64;
+    static final int NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG = 65;
 
     static final int FIRST_ACTIVITY_STACK_MSG = 100;
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1464,6 +1469,7 @@
     final ServiceThread mHandlerThread;
     final MainHandler mHandler;
     final UiHandler mUiHandler;
+    final ProcessStartLogger mProcessStartLogger;
 
     PackageManagerInternal mPackageManagerInt;
 
@@ -1476,80 +1482,11 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
             case SHOW_ERROR_UI_MSG: {
-                HashMap<String, Object> data = (HashMap<String, Object>) msg.obj;
-                boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
-                        Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
-                synchronized (ActivityManagerService.this) {
-                    ProcessRecord proc = (ProcessRecord)data.get("app");
-                    AppErrorResult res = (AppErrorResult) data.get("result");
-                    if (proc != null && proc.crashDialog != null) {
-                        Slog.e(TAG, "App already has crash dialog: " + proc);
-                        if (res != null) {
-                            res.set(0);
-                        }
-                        return;
-                    }
-                    boolean isBackground = (UserHandle.getAppId(proc.uid)
-                            >= Process.FIRST_APPLICATION_UID
-                            && proc.pid != MY_PID);
-                    for (int userId : mUserController.getCurrentProfileIdsLocked()) {
-                        isBackground &= (proc.userId != userId);
-                    }
-                    if (isBackground && !showBackground) {
-                        Slog.w(TAG, "Skipping crash dialog of " + proc + ": background");
-                        if (res != null) {
-                            res.set(0);
-                        }
-                        return;
-                    }
-                    final boolean crashSilenced = mAppsNotReportingCrashes != null &&
-                            mAppsNotReportingCrashes.contains(proc.info.packageName);
-                    if (mShowDialogs && !mSleeping && !mShuttingDown && !crashSilenced) {
-                        Dialog d = new AppErrorDialog(mContext,
-                                ActivityManagerService.this, res, proc);
-                        d.show();
-                        proc.crashDialog = d;
-                    } 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);
-                        }
-                    }
-                }
-
+                mAppErrors.handleShowAppErrorUi(msg);
                 ensureBootCompleted();
             } break;
             case SHOW_NOT_RESPONDING_UI_MSG: {
-                synchronized (ActivityManagerService.this) {
-                    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);
-                        return;
-                    }
-
-                    Intent intent = new Intent("android.intent.action.ANR");
-                    if (!mProcessesReady) {
-                        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
-                                | Intent.FLAG_RECEIVER_FOREGROUND);
-                    }
-                    broadcastIntentLocked(null, null, intent,
-                            null, null, 0, null, null, null, AppOpsManager.OP_NONE,
-                            null, false, false, MY_PID, Process.SYSTEM_UID, 0 /* TODO: Verify */);
-
-                    if (mShowDialogs) {
-                        Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
-                                mContext, proc, (ActivityRecord)data.get("activity"),
-                                msg.arg1 != 0);
-                        d.show();
-                        proc.anrDialog = d;
-                    } else {
-                        // Just kill the app if there is no dialog to be shown.
-                        killAppAtUsersRequest(proc, null);
-                    }
-                }
-
+                mAppErrors.handleShowAnrUi(msg);
                 ensureBootCompleted();
             } break;
             case SHOW_STRICT_MODE_VIOLATION_UI_MSG: {
@@ -1785,7 +1722,7 @@
             } break;
             case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
                 synchronized (ActivityManagerService.this) {
-                    mStackSupervisor.doPendingActivityLaunchesLocked(true);
+                    mActivityStarter.doPendingActivityLaunchesLocked(true);
                 }
             } break;
             case KILL_APPLICATION_MSG: {
@@ -1942,7 +1879,10 @@
                 break;
             }
             case SYSTEM_USER_UNLOCK_MSG: {
-                mSystemServiceManager.unlockUser(msg.arg1);
+                final int userId = msg.arg1;
+                mSystemServiceManager.unlockUser(userId);
+                mRecentTasks.cleanupLocked(userId);
+                installEncryptionUnawareProviders(userId);
                 break;
             }
             case SYSTEM_USER_CURRENT_MSG: {
@@ -1992,9 +1932,7 @@
             }
             case NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG: {
                 synchronized (ActivityManagerService.this) {
-                    int i = mTaskStackListeners.beginBroadcast();
-                    while (i > 0) {
-                        i--;
+                    for (int i = mTaskStackListeners.beginBroadcast() - 1; i >= 0; i--) {
                         try {
                             // Make a one-way callback to the listener
                             mTaskStackListeners.getBroadcastItem(i).onTaskStackChanged();
@@ -2006,6 +1944,34 @@
                 }
                 break;
             }
+            case NOTIFY_ACTIVITY_PINNED_LISTENERS_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).onActivityPinned();
+                        } catch (RemoteException e){
+                            // Handled by the RemoteCallbackList
+                        }
+                    }
+                    mTaskStackListeners.finishBroadcast();
+                }
+                break;
+            }
+            case NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_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).onPinnedActivityRestartAttempt();
+                        } 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;
@@ -2153,6 +2119,18 @@
                     mStackSupervisor.logStackState();
                 }
             } 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) {
+                        mInVrMode = vrMode;
+                        mShowDialogs = shouldShowDialogs(mConfiguration, mInVrMode);
+                    }
+                }
+            } break;
             }
         }
     };
@@ -2208,7 +2186,7 @@
                 }
 
                 int num = 0;
-                long[] tmp = new long[1];
+                long[] tmp = new long[2];
                 do {
                     ProcessRecord proc;
                     int procState;
@@ -2240,7 +2218,7 @@
                             if (pss != 0 && proc.thread != null && proc.setProcState == procState
                                     && proc.pid == pid && proc.lastPssTime == lastPssTime) {
                                 num++;
-                                recordPssSampleLocked(proc, procState, pss, tmp[0],
+                                recordPssSampleLocked(proc, procState, pss, tmp[0], tmp[1],
                                         SystemClock.uptimeMillis());
                             }
                         }
@@ -2265,7 +2243,7 @@
             ServiceManager.addService("processinfo", new ProcessInfoService(this));
 
             ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
-                    "android", STOCK_PM_FLAGS);
+                    "android", STOCK_PM_FLAGS | MATCH_SYSTEM_ONLY);
             mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());
 
             synchronized (this) {
@@ -2289,6 +2267,7 @@
     public void setWindowManager(WindowManagerService wm) {
         mWindowManager = wm;
         mStackSupervisor.setWindowManager(wm);
+        mActivityStarter.setWindowManager(wm);
     }
 
     public void setUsageStatsManager(UsageStatsManagerInternal usageStatsManager) {
@@ -2421,6 +2400,8 @@
         mHandler = new MainHandler(mHandlerThread.getLooper());
         mUiHandler = new UiHandler();
 
+        mProcessStartLogger = new ProcessStartLogger();
+
         mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
                 "foreground", BROADCAST_FG_TIMEOUT, false);
         mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
@@ -2430,6 +2411,7 @@
 
         mServices = new ActiveServices(this);
         mProviderMap = new ProviderMap(this);
+        mAppErrors = new AppErrors(mContext, this);
 
         // TODO: Move creation of battery stats service outside of activity manager service.
         File dataDir = Environment.getDataDirectory();
@@ -2474,9 +2456,10 @@
 
         mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
         mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
-        mRecentTasks = new RecentTasks(this);
-        mStackSupervisor = new ActivityStackSupervisor(this, mRecentTasks);
-        mTaskPersister = new TaskPersister(systemDir, mStackSupervisor, mRecentTasks);
+        mStackSupervisor = new ActivityStackSupervisor(this);
+        mActivityStarter = new ActivityStarter(this, mStackSupervisor);
+        mRecentTasks = new RecentTasks(this, mStackSupervisor);
+
 
         mProcessCpuThread = new Thread("CpuTracker") {
             @Override
@@ -2530,6 +2513,10 @@
         LocalServices.addService(ActivityManagerInternal.class, new LocalService());
     }
 
+    void onUserStoppedLocked(int userId) {
+        mRecentTasks.unloadUserRecentsLocked(userId);
+    }
+
     public void initPowerManagement() {
         mStackSupervisor.initPowerManagement();
         mBatteryStatsService.initPowerManagement();
@@ -2731,9 +2718,14 @@
         return mAppBindArgs;
     }
 
-    final void setFocusedActivityLocked(ActivityRecord r, String reason) {
+    boolean setFocusedActivityLocked(ActivityRecord r, String reason) {
         if (r == null || mFocusedActivity == r) {
-            return;
+            return false;
+        }
+
+        if (!r.isFocusable()) {
+            if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedActivityLocked: unfocusable r=" + r);
+            return false;
         }
 
         if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedActivityLocked: r=" + r);
@@ -2759,22 +2751,28 @@
         } else {
             r.appTimeTracker = null;
         }
+        // TODO: VI Maybe r.task.voiceInteractor || r.voiceInteractor != null
+        // TODO: Probably not, because we don't want to resume voice on switching
+        // back to this activity
         if (r.task.voiceInteractor != null) {
             startRunningVoiceLocked(r.task.voiceSession, r.info.applicationInfo.uid);
         } else {
             finishRunningVoiceLocked();
-            if (last != null && last.task.voiceSession != null) {
+            IVoiceInteractionSession session;
+            if (last != null && ((session = last.task.voiceSession) != null
+                    || (session = last.voiceSession) != null)) {
                 // We had been in a voice interaction session, but now focused has
                 // move to something different.  Just finish the session, we can't
                 // return to it and retain the proper state and synchronization with
                 // the voice interaction service.
-                finishVoiceTask(last.task.voiceSession);
+                finishVoiceTask(session);
             }
         }
-        if (mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity")) {
+        if (mStackSupervisor.moveActivityStackToFront(r, reason + " setFocusedActivity")) {
             mWindowManager.setFocusedApp(r.appToken, true);
         }
         applyUpdateLockStateLocked(r);
+        applyUpdateVrModeLocked(r);
         if (mFocusedActivity.userId != mLastFocusedUserId) {
             mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG);
             mHandler.obtainMessage(
@@ -2786,23 +2784,35 @@
                 mFocusedActivity == null ? -1 : mFocusedActivity.userId,
                 mFocusedActivity == null ? "NULL" : mFocusedActivity.shortComponentName,
                 reason);
+        return true;
     }
 
-    final void clearFocusedActivity(ActivityRecord r) {
-        if (mFocusedActivity == r) {
-            ActivityStack stack = mStackSupervisor.getFocusedStack();
-            if (stack != null) {
-                ActivityRecord top = stack.topActivity();
-                if (top != null && top.userId != mLastFocusedUserId) {
-                    mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG);
-                    mHandler.sendMessage(mHandler.obtainMessage(FOREGROUND_PROFILE_CHANGED_MSG,
-                                    top.userId, 0));
-                    mLastFocusedUserId = top.userId;
-                }
-            }
-            mFocusedActivity = null;
-            EventLogTags.writeAmFocusedActivity(-1, "NULL", "clearFocusedActivity");
+    final void resetFocusedActivityIfNeededLocked(ActivityRecord goingAway) {
+        if (mFocusedActivity != goingAway) {
+            return;
         }
+
+        final ActivityStack focusedStack = mStackSupervisor.getFocusedStack();
+        if (focusedStack != null) {
+            final ActivityRecord top = focusedStack.topActivity();
+            if (top != null && top.userId != mLastFocusedUserId) {
+                mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG);
+                mHandler.sendMessage(
+                        mHandler.obtainMessage(FOREGROUND_PROFILE_CHANGED_MSG, top.userId, 0));
+                mLastFocusedUserId = top.userId;
+            }
+        }
+
+        // Try to move focus to another activity if possible.
+        if (setFocusedActivityLocked(
+                focusedStack.topRunningActivityLocked(), "resetFocusedActivityIfNeeded")) {
+            return;
+        }
+
+        if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "resetFocusedActivityIfNeeded: Setting focus to NULL "
+                + "prev mFocusedActivity=" + mFocusedActivity + " goingAway=" + goingAway);
+        mFocusedActivity = null;
+        EventLogTags.writeAmFocusedActivity(-1, "NULL", "resetFocusedActivityIfNeeded");
     }
 
     @Override
@@ -2814,7 +2824,7 @@
                 ActivityRecord r = stack.topRunningActivityLocked();
                 if (r != null) {
                     setFocusedActivityLocked(r, "setFocusedStack");
-                    mStackSupervisor.resumeTopActivitiesLocked(stack, null, null);
+                    mStackSupervisor.resumeFocusedStackTopActivityLocked();
                 }
             }
         }
@@ -2828,10 +2838,9 @@
             synchronized (ActivityManagerService.this) {
                 TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
                 if (task != null) {
-                    ActivityRecord r = task.topRunningActivityLocked();
-                    if (r != null) {
-                        setFocusedActivityLocked(r, "setFocusedTask");
-                        mStackSupervisor.resumeTopActivitiesLocked(task.stack, null, null);
+                    final ActivityRecord r = task.topRunningActivityLocked();
+                    if (setFocusedActivityLocked(r, "setFocusedTask")) {
+                        mStackSupervisor.resumeFocusedStackTopActivityLocked();
                     }
                 }
             }
@@ -2843,7 +2852,8 @@
     /** Sets the task stack listener that gets callbacks when a task stack changes. */
     @Override
     public void registerTaskStackListener(ITaskStackListener listener) throws RemoteException {
-        synchronized (ActivityManagerService.this) {
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "registerTaskStackListener()");
+        synchronized (this) {
             if (listener != null) {
                 mTaskStackListeners.register(listener);
             }
@@ -2871,6 +2881,11 @@
                 mHandler.obtainMessage(IMMERSIVE_MODE_LOCK_MSG, (nextState) ? 1 : 0, 0, r));
     }
 
+    final void applyUpdateVrModeLocked(ActivityRecord r) {
+        mHandler.sendMessage(
+                mHandler.obtainMessage(VR_MODE_CHANGE_MSG, (r.isVrActivity) ? 1 : 0, 0));
+    }
+
     final void showAskCompatModeDialogLocked(ActivityRecord r) {
         Message msg = Message.obtain();
         msg.what = SHOW_COMPAT_MODE_DIALOG_UI_MSG;
@@ -2915,7 +2930,7 @@
         return index;
     }
 
-    private static void killProcessGroup(int uid, int pid) {
+    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);
@@ -3237,7 +3252,7 @@
             if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
                 // If we are in the background, then check to see if this process
                 // is bad.  If so, we will just silently fail.
-                if (mBadProcesses.get(info.processName, info.uid) != null) {
+                if (mAppErrors.isBadProcessLocked(info)) {
                     if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
                             + "/" + info.processName);
                     return null;
@@ -3249,12 +3264,12 @@
                 // if it had been bad.
                 if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
                         + "/" + info.processName);
-                mProcessCrashTimes.remove(info.processName, info.uid);
-                if (mBadProcesses.get(info.processName, info.uid) != null) {
+                mAppErrors.resetProcessCrashTimeLocked(info);
+                if (mAppErrors.isBadProcessLocked(info)) {
                     EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,
                             UserHandle.getUserId(info.uid), info.uid,
                             info.processName);
-                    mBadProcesses.remove(info.processName, info.uid);
+                    mAppErrors.clearBadProcessLocked(info);
                     if (app != null) {
                         app.bad = false;
                     }
@@ -3392,7 +3407,8 @@
                 try {
                     checkTime(startTime, "startProcess: getting gids from package manager");
                     final IPackageManager pm = AppGlobals.getPackageManager();
-                    permGids = pm.getPackageGids(app.info.packageName, app.userId);
+                    permGids = pm.getPackageGids(app.info.packageName,
+                            MATCH_DEBUG_TRIAGED_MISSING, app.userId);
                     MountServiceInternal mountServiceInternal = LocalServices.getService(
                             MountServiceInternal.class);
                     mountExternal = mountServiceInternal.getExternalStorageMountMode(uid,
@@ -3492,6 +3508,8 @@
                     app.processName, hostingType,
                     hostingNameStr != null ? hostingNameStr : "");
 
+            mProcessStartLogger.logIfNeededLocked(app, startResult);
+
             if (app.persistent) {
                 Watchdog.getInstance().processStarted(app.processName, startResult.pid);
             }
@@ -3572,6 +3590,7 @@
     Intent getHomeIntent() {
         Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
         intent.setComponent(mTopComponent);
+        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
         if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
             intent.addCategory(Intent.CATEGORY_HOME);
         }
@@ -3587,11 +3606,9 @@
             return false;
         }
         Intent intent = getHomeIntent();
-        ActivityInfo aInfo =
-            resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
+        ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
         if (aInfo != null) {
-            intent.setComponent(new ComponentName(
-                    aInfo.applicationInfo.packageName, aInfo.name));
+            intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
             // Don't do this if the home app is currently being
             // instrumented.
             aInfo = new ActivityInfo(aInfo);
@@ -3600,7 +3617,7 @@
                     aInfo.applicationInfo.uid, true);
             if (app == null || app.instrumentationClass == null) {
                 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
-                mStackSupervisor.startHomeActivity(intent, aInfo, reason);
+                mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);
             }
         }
 
@@ -3650,21 +3667,11 @@
             mCheckedForSetup = true;
 
             // See if we should be showing the platform update setup UI.
-            Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
-            List<ResolveInfo> ris = mContext.getPackageManager()
-                    .queryIntentActivities(intent, PackageManager.GET_META_DATA);
-
-            // We don't allow third party apps to replace this.
-            ResolveInfo ri = null;
-            for (int i=0; ris != null && i<ris.size(); i++) {
-                if ((ris.get(i).activityInfo.applicationInfo.flags
-                        & ApplicationInfo.FLAG_SYSTEM) != 0) {
-                    ri = ris.get(i);
-                    break;
-                }
-            }
-
-            if (ri != null) {
+            final Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
+            final List<ResolveInfo> ris = mContext.getPackageManager().queryIntentActivities(intent,
+                    PackageManager.MATCH_SYSTEM_ONLY | PackageManager.GET_META_DATA);
+            if (!ris.isEmpty()) {
+                final ResolveInfo ri = ris.get(0);
                 String vers = ri.activityInfo.metaData != null
                         ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
                         : null;
@@ -3678,7 +3685,7 @@
                     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                     intent.setComponent(new ComponentName(
                             ri.activityInfo.packageName, ri.activityInfo.name));
-                    mStackSupervisor.startActivityLocked(null, intent, null /*ephemeralIntent*/,
+                    mActivityStarter.startActivityLocked(null, intent, null /*ephemeralIntent*/,
                             null, ri.activityInfo, null /*rInfo*/, null, null, null, null, 0, 0, 0,
                             null, 0, 0, 0, null, false, false, null, null, null);
                 }
@@ -4005,6 +4012,25 @@
                 UserHandle.getCallingUserId());
     }
 
+    final int startActivity(Intent intent, ActivityStackSupervisor.ActivityContainer container) {
+        enforceNotIsolatedCaller("ActivityContainer.startActivity");
+        final int userId = mUserController.handleIncomingUser(Binder.getCallingPid(),
+                Binder.getCallingUid(), mStackSupervisor.mCurrentUser, false,
+                ActivityManagerService.ALLOW_FULL_ONLY, "ActivityContainer", null);
+
+        // TODO: Switch to user app stacks here.
+        String mimeType = intent.getType();
+        final Uri data = intent.getData();
+        if (mimeType == null && data != null && "content".equals(data.getScheme())) {
+            mimeType = getProviderMimeType(data, userId);
+        }
+        container.checkEmbeddedAllowedInner(userId, intent, mimeType);
+
+        intent.addFlags(FORCE_NEW_TASK_FLAGS);
+        return mActivityStarter.startActivityMayWait(null, -1, null, intent, mimeType, null, null, null,
+                null, 0, 0, null, null, null, null, false, userId, container, null);
+    }
+
     @Override
     public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
             Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
@@ -4013,7 +4039,7 @@
         userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                 userId, false, ALLOW_FULL_ONLY, "startActivity", null);
         // TODO: Switch to user app stacks here.
-        return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
+        return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                 resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                 profilerInfo, null, null, bOptions, false, userId, null, null);
     }
@@ -4076,7 +4102,7 @@
 
         // TODO: Switch to user app stacks here.
         try {
-            int ret = mStackSupervisor.startActivityMayWait(null, targetUid, targetPackage, intent,
+            int ret = mActivityStarter.startActivityMayWait(null, targetUid, targetPackage, intent,
                     resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, null,
                     null, null, bOptions, ignoreTargetSecurity, userId, null, null);
             return ret;
@@ -4105,7 +4131,7 @@
                 userId, false, ALLOW_FULL_ONLY, "startActivityAndWait", null);
         WaitResult res = new WaitResult();
         // TODO: Switch to user app stacks here.
-        mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
+        mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
                 null, null, resultTo, resultWho, requestCode, startFlags, profilerInfo, res, null,
                 bOptions, false, userId, null, null);
         return res;
@@ -4119,7 +4145,7 @@
         userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                 userId, false, ALLOW_FULL_ONLY, "startActivityWithConfig", null);
         // TODO: Switch to user app stacks here.
-        int ret = mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
+        int ret = mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                 resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                 null, null, config, bOptions, false, userId, null, null);
         return ret;
@@ -4177,12 +4203,72 @@
         userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
                 ALLOW_FULL_ONLY, "startVoiceActivity", null);
         // TODO: Switch to user app stacks here.
-        return mStackSupervisor.startActivityMayWait(null, callingUid, callingPackage, intent,
+        return mActivityStarter.startActivityMayWait(null, callingUid, callingPackage, intent,
                 resolvedType, session, interactor, null, null, 0, startFlags, profilerInfo, null,
                 null, bOptions, false, userId, null, null);
     }
 
     @Override
+    public void startLocalVoiceInteraction(IBinder callingActivity, Bundle options)
+            throws RemoteException {
+        Slog.i(TAG, "Activity tried to startVoiceInteraction");
+        synchronized (this) {
+            ActivityRecord activity = getFocusedStack().topActivity();
+            if (ActivityRecord.forTokenLocked(callingActivity) != activity) {
+                throw new SecurityException("Only focused activity can call startVoiceInteraction");
+            }
+            if (mRunningVoice != null || activity.task.voiceSession != null
+                    || activity.voiceSession != null) {
+                Slog.w(TAG, "Already in a voice interaction, cannot start new voice interaction");
+                return;
+            }
+            if (activity.pendingVoiceInteractionStart) {
+                Slog.w(TAG, "Pending start of voice interaction already.");
+                return;
+            }
+            activity.pendingVoiceInteractionStart = true;
+        }
+        LocalServices.getService(VoiceInteractionManagerInternal.class)
+                .startLocalVoiceInteraction(callingActivity, options);
+    }
+
+    @Override
+    public void stopLocalVoiceInteraction(IBinder callingActivity) throws RemoteException {
+        LocalServices.getService(VoiceInteractionManagerInternal.class)
+                .stopLocalVoiceInteraction(callingActivity);
+    }
+
+    @Override
+    public boolean supportsLocalVoiceInteraction() throws RemoteException {
+        return LocalServices.getService(VoiceInteractionManagerInternal.class)
+                .supportsLocalVoiceInteraction();
+    }
+
+    void onLocalVoiceInteractionStartedLocked(IBinder activity,
+            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {
+        ActivityRecord activityToCallback = ActivityRecord.forTokenLocked(activity);
+        if (activityToCallback == null) return;
+        activityToCallback.setVoiceSessionLocked(voiceSession);
+
+        // Inform the activity
+        try {
+            activityToCallback.app.thread.scheduleLocalVoiceInteractionStarted(activity,
+                    voiceInteractor);
+            long token = Binder.clearCallingIdentity();
+            try {
+                startRunningVoiceLocked(voiceSession, activityToCallback.appInfo.uid);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+            // TODO: VI Should we cache the activity so that it's easier to find later
+            // rather than scan through all the stacks and activities?
+        } catch (RemoteException re) {
+            activityToCallback.clearVoiceSessionLocked();
+            // TODO: VI Should this terminate the voice session?
+        }
+    }
+
+    @Override
     public void setVoiceKeepAwake(IVoiceInteractionSession session, boolean keepAwake) {
         synchronized (this) {
             if (mRunningVoice != null && mRunningVoice.asBinder() == session.asBinder()) {
@@ -4288,7 +4374,7 @@
             }
 
             final long origId = Binder.clearCallingIdentity();
-            int res = mStackSupervisor.startActivityLocked(r.app.thread, intent,
+            int res = mActivityStarter.startActivityLocked(r.app.thread, intent,
                     null /*ephemeralIntent*/, r.resolvedType, aInfo, null /*rInfo*/, null,
                     null, resultTo != null ? resultTo.appToken : null, resultWho, requestCode, -1,
                     r.launchedFromUid, r.launchedFromPackage, -1, r.launchedFromUid, 0, options,
@@ -4304,7 +4390,7 @@
     }
 
     @Override
-    public final int startActivityFromRecents(int taskId, int launchStackId, Bundle bOptions) {
+    public final int startActivityFromRecents(int taskId, Bundle bOptions) {
         if (checkCallingPermission(START_TASKS_FROM_RECENTS) != PackageManager.PERMISSION_GRANTED) {
             String msg = "Permission Denial: startActivityFromRecents called without " +
                     START_TASKS_FROM_RECENTS;
@@ -4313,24 +4399,28 @@
         }
         final long origId = Binder.clearCallingIdentity();
         try {
-            return startActivityFromRecentsInner(taskId, launchStackId, bOptions);
+            return startActivityFromRecentsInner(taskId, bOptions);
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
     }
 
-    final int startActivityFromRecentsInner(int taskId, int launchStackId, Bundle bOptions) {
+    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(
@@ -4338,10 +4428,9 @@
             }
 
             if (launchStackId != INVALID_STACK_ID) {
-                if (launchStackId == DOCKED_STACK_ID && bOptions != null) {
-                    ActivityOptions activityOptions = new ActivityOptions(bOptions);
-                    mWindowManager.setDockedStackCreateState(activityOptions.getDockCreateMode(),
-                            null /* initialBounds */);
+                if (launchStackId == DOCKED_STACK_ID && activityOptions != null) {
+                    mWindowManager.setDockedStackCreateState(
+                            activityOptions.getDockCreateMode(), null /* initialBounds */);
                 }
                 if (task.stack.mStackId != launchStackId) {
                     mStackSupervisor.moveTaskToStackLocked(
@@ -4350,7 +4439,10 @@
                 }
             }
 
-            if (task.getRootActivity() != null) {
+            // 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;
             }
@@ -4373,7 +4465,7 @@
                 userId, false, ALLOW_FULL_ONLY, "startActivityInPackage", null);
 
         // TODO: Switch to user app stacks here.
-        int ret = mStackSupervisor.startActivityMayWait(null, uid, callingPackage, intent,
+        int ret = mActivityStarter.startActivityMayWait(null, uid, callingPackage, intent,
                 resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                 null, null, null, bOptions, false, userId, container, inTask);
         return ret;
@@ -4387,7 +4479,7 @@
         userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                 userId, false, ALLOW_FULL_ONLY, "startActivity", null);
         // TODO: Switch to user app stacks here.
-        int ret = mStackSupervisor.startActivities(caller, -1, callingPackage, intents,
+        int ret = mActivityStarter.startActivities(caller, -1, callingPackage, intents,
                 resolvedTypes, resultTo, bOptions, userId);
         return ret;
     }
@@ -4399,7 +4491,7 @@
         userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                 userId, false, ALLOW_FULL_ONLY, "startActivityInPackage", null);
         // TODO: Switch to user app stacks here.
-        int ret = mStackSupervisor.startActivities(null, uid, callingPackage, intents, resolvedTypes,
+        int ret = mActivityStarter.startActivities(null, uid, callingPackage, intents, resolvedTypes,
                 resultTo, bOptions, userId);
         return ret;
     }
@@ -4435,7 +4527,7 @@
             if (config != null) {
                 r.frozenBeforeDestroy = true;
                 if (!updateConfigurationLocked(config, r, false)) {
-                    mStackSupervisor.resumeTopActivitiesLocked();
+                    mStackSupervisor.resumeFocusedStackTopActivityLocked();
                 }
             }
             Binder.restoreCallingIdentity(origId);
@@ -4585,46 +4677,7 @@
         }
 
         synchronized(this) {
-            ProcessRecord proc = null;
-
-            // Figure out which process to kill.  We don't trust that initialPid
-            // still has any relation to current pids, so must scan through the
-            // list.
-            synchronized (mPidsSelfLocked) {
-                for (int i=0; i<mPidsSelfLocked.size(); i++) {
-                    ProcessRecord p = mPidsSelfLocked.valueAt(i);
-                    if (p.uid != uid) {
-                        continue;
-                    }
-                    if (p.pid == initialPid) {
-                        proc = p;
-                        break;
-                    }
-                    if (p.pkgList.containsKey(packageName)) {
-                        proc = p;
-                    }
-                }
-            }
-
-            if (proc == null) {
-                Slog.w(TAG, "crashApplication: nothing for uid=" + uid
-                        + " initialPid=" + initialPid
-                        + " packageName=" + packageName);
-                return;
-            }
-
-            if (proc.thread != null) {
-                if (proc.pid == Process.myPid()) {
-                    Log.w(TAG, "crashApplication: trying to crash self!");
-                    return;
-                }
-                long ident = Binder.clearCallingIdentity();
-                try {
-                    proc.thread.scheduleCrash(message);
-                } catch (RemoteException e) {
-                }
-                Binder.restoreCallingIdentity(ident);
-            }
+            mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, message);
         }
     }
 
@@ -4668,9 +4721,11 @@
 
     @Override
     public void finishVoiceTask(IVoiceInteractionSession session) {
-        synchronized(this) {
+        synchronized (this) {
             final long origId = Binder.clearCallingIdentity();
             try {
+                // TODO: VI Consider treating local voice interactions and voice tasks
+                // differently here
                 mStackSupervisor.finishVoiceTask(session);
             } finally {
                 Binder.restoreCallingIdentity(origId);
@@ -4773,12 +4828,11 @@
             finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
         }
 
-        if (!restarting && hasVisibleActivities && !mStackSupervisor.resumeTopActivitiesLocked()) {
-            // If there was nothing to resume, and we are not already
-            // restarting this process, but there is a visible activity that
-            // is hosted by the process...  then make sure all visible
-            // activities are running, taking care of restarting this
-            // process.
+        if (!restarting && hasVisibleActivities
+                && !mStackSupervisor.resumeFocusedStackTopActivityLocked()) {
+            // If there was nothing to resume, and we are not already restarting this process, but
+            // there is a visible activity that is hosted by the process...  then make sure all
+            // visible activities are running, taking care of restarting this process.
             mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
         }
     }
@@ -5104,169 +5158,6 @@
         }
     }
 
-    final void appNotResponding(ProcessRecord app, ActivityRecord activity,
-            ActivityRecord parent, boolean aboveSystem, final String annotation) {
-        ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
-        SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20);
-
-        if (mController != null) {
-            try {
-                // 0 == continue, -1 = kill process immediately
-                int res = mController.appEarlyNotResponding(app.processName, app.pid, annotation);
-                if (res < 0 && app.pid != MY_PID) {
-                    app.kill("anr", true);
-                }
-            } catch (RemoteException e) {
-                mController = null;
-                Watchdog.getInstance().setActivityController(null);
-            }
-        }
-
-        long anrTime = SystemClock.uptimeMillis();
-        if (MONITOR_CPU_USAGE) {
-            updateCpuStatsNow();
-        }
-
-        synchronized (this) {
-            // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
-            if (mShuttingDown) {
-                Slog.i(TAG, "During shutdown skipping ANR: " + app + " " + annotation);
-                return;
-            } else if (app.notResponding) {
-                Slog.i(TAG, "Skipping duplicate ANR: " + app + " " + annotation);
-                return;
-            } else if (app.crashing) {
-                Slog.i(TAG, "Crashing app skipping ANR: " + app + " " + annotation);
-                return;
-            }
-
-            // In case we come through here for the same app before completing
-            // this one, mark as anring now so we will bail out.
-            app.notResponding = true;
-
-            // Log the ANR to the event log.
-            EventLog.writeEvent(EventLogTags.AM_ANR, app.userId, app.pid,
-                    app.processName, app.info.flags, annotation);
-
-            // Dump thread traces as quickly as we can, starting with "interesting" processes.
-            firstPids.add(app.pid);
-
-            int parentPid = app.pid;
-            if (parent != null && parent.app != null && parent.app.pid > 0) parentPid = parent.app.pid;
-            if (parentPid != app.pid) firstPids.add(parentPid);
-
-            if (MY_PID != app.pid && MY_PID != parentPid) firstPids.add(MY_PID);
-
-            for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
-                ProcessRecord r = mLruProcesses.get(i);
-                if (r != null && r.thread != null) {
-                    int pid = r.pid;
-                    if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) {
-                        if (r.persistent) {
-                            firstPids.add(pid);
-                        } else {
-                            lastPids.put(pid, Boolean.TRUE);
-                        }
-                    }
-                }
-            }
-        }
-
-        // Log the ANR to the main log.
-        StringBuilder info = new StringBuilder();
-        info.setLength(0);
-        info.append("ANR in ").append(app.processName);
-        if (activity != null && activity.shortComponentName != null) {
-            info.append(" (").append(activity.shortComponentName).append(")");
-        }
-        info.append("\n");
-        info.append("PID: ").append(app.pid).append("\n");
-        if (annotation != null) {
-            info.append("Reason: ").append(annotation).append("\n");
-        }
-        if (parent != null && parent != activity) {
-            info.append("Parent: ").append(parent.shortComponentName).append("\n");
-        }
-
-        final ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
-
-        File tracesFile = dumpStackTraces(true, firstPids, processCpuTracker, lastPids,
-                NATIVE_STACKS_OF_INTEREST);
-
-        String cpuInfo = null;
-        if (MONITOR_CPU_USAGE) {
-            updateCpuStatsNow();
-            synchronized (mProcessCpuTracker) {
-                cpuInfo = mProcessCpuTracker.printCurrentState(anrTime);
-            }
-            info.append(processCpuTracker.printCurrentLoad());
-            info.append(cpuInfo);
-        }
-
-        info.append(processCpuTracker.printCurrentState(anrTime));
-
-        Slog.e(TAG, info.toString());
-        if (tracesFile == null) {
-            // There is no trace file, so dump (only) the alleged culprit's threads to the log
-            Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
-        }
-
-        addErrorToDropBox("anr", app, app.processName, activity, parent, annotation,
-                cpuInfo, tracesFile, null);
-
-        if (mController != null) {
-            try {
-                // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
-                int res = mController.appNotResponding(app.processName, app.pid, info.toString());
-                if (res != 0) {
-                    if (res < 0 && app.pid != MY_PID) {
-                        app.kill("anr", true);
-                    } else {
-                        synchronized (this) {
-                            mServices.scheduleServiceTimeoutLocked(app);
-                        }
-                    }
-                    return;
-                }
-            } catch (RemoteException e) {
-                mController = null;
-                Watchdog.getInstance().setActivityController(null);
-            }
-        }
-
-        // Unless configured otherwise, swallow ANRs in background processes & kill the process.
-        boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
-                Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
-
-        synchronized (this) {
-            mBatteryStatsService.noteProcessAnr(app.processName, app.uid);
-
-            if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
-                app.kill("bg anr", true);
-                return;
-            }
-
-            // Set the app's notResponding state, and look up the errorReportReceiver
-            makeAppNotRespondingLocked(app,
-                    activity != null ? activity.shortComponentName : null,
-                    annotation != null ? "ANR " + annotation : "ANR",
-                    info.toString());
-
-            // Bring up the infamous App Not Responding dialog
-            Message msg = Message.obtain();
-            HashMap<String, Object> map = new HashMap<String, Object>();
-            msg.what = SHOW_NOT_RESPONDING_UI_MSG;
-            msg.obj = map;
-            msg.arg1 = aboveSystem ? 1 : 0;
-            map.put("app", app);
-            if (activity != null) {
-                map.put("activity", activity);
-            }
-
-            mUiHandler.sendMessage(msg);
-        }
-    }
-
     final void showLaunchWarningLocked(final ActivityRecord cur, final ActivityRecord next) {
         if (!mLaunchWarningShown) {
             mLaunchWarningShown = true;
@@ -5308,7 +5199,7 @@
             int pkgUid = -1;
             synchronized(this) {
                 try {
-                    pkgUid = pm.getPackageUid(packageName, userId);
+                    pkgUid = pm.getPackageUid(packageName, MATCH_UNINSTALLED_PACKAGES, userId);
                 } catch (RemoteException e) {
                 }
                 if (pkgUid == -1) {
@@ -5393,7 +5284,8 @@
             synchronized(this) {
                 int appId = -1;
                 try {
-                    appId = UserHandle.getAppId(pm.getPackageUid(packageName, 0));
+                    appId = UserHandle.getAppId(
+                            pm.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, userId));
                 } catch (RemoteException e) {
                 }
                 if (appId == -1) {
@@ -5401,7 +5293,7 @@
                     return;
                 }
                 killPackageProcessesLocked(packageName, appId, userId,
-                        ProcessList.SERVICE_ADJ, false, true, true, false, true, "kill background");
+                        ProcessList.SERVICE_ADJ, false, true, true, false, "kill background");
             }
         } finally {
             Binder.restoreCallingIdentity(callingId);
@@ -5479,7 +5371,8 @@
                 for (int user : users) {
                     int pkgUid = -1;
                     try {
-                        pkgUid = pm.getPackageUid(packageName, user);
+                        pkgUid = pm.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING,
+                                user);
                     } catch (RemoteException e) {
                     }
                     if (pkgUid == -1) {
@@ -5702,7 +5595,7 @@
 
     private final boolean killPackageProcessesLocked(String packageName, int appId,
             int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart,
-            boolean doit, boolean evenPersistent, boolean killPackageApp, String reason) {
+            boolean doit, boolean evenPersistent, String reason) {
         ArrayList<ProcessRecord> procs = new ArrayList<>();
 
         // Remove all processes this package may have touched: all with the
@@ -5751,7 +5644,7 @@
                     if (userId != UserHandle.USER_ALL && app.userId != userId) {
                         continue;
                     }
-                    if ((!killPackageApp || !app.pkgList.containsKey(packageName)) && !isDep) {
+                    if (!app.pkgList.containsKey(packageName) && !isDep) {
                         continue;
                     }
                 }
@@ -5835,7 +5728,7 @@
         // Clean-up disabled activities.
         if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
                 packageName, disabledClasses, true, false, userId) && mBooted) {
-            mStackSupervisor.resumeTopActivitiesLocked();
+            mStackSupervisor.resumeFocusedStackTopActivityLocked();
             mStackSupervisor.scheduleIdleLocked();
         }
 
@@ -5873,8 +5766,8 @@
 
         if (appId < 0 && packageName != null) {
             try {
-                appId = UserHandle.getAppId(
-                        AppGlobals.getPackageManager().getPackageUid(packageName, 0));
+                appId = UserHandle.getAppId(AppGlobals.getPackageManager()
+                        .getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, userId));
             } catch (RemoteException e) {
             }
         }
@@ -5887,37 +5780,11 @@
                 Slog.i(TAG, "Force stopping u" + userId + ": " + reason);
             }
 
-            final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
-            for (int ip = pmap.size() - 1; ip >= 0; ip--) {
-                SparseArray<Long> ba = pmap.valueAt(ip);
-                for (i = ba.size() - 1; i >= 0; i--) {
-                    boolean remove = false;
-                    final int entUid = ba.keyAt(i);
-                    if (packageName != null) {
-                        if (userId == UserHandle.USER_ALL) {
-                            if (UserHandle.getAppId(entUid) == appId) {
-                                remove = true;
-                            }
-                        } else {
-                            if (entUid == UserHandle.getUid(userId, appId)) {
-                                remove = true;
-                            }
-                        }
-                    } else if (UserHandle.getUserId(entUid) == userId) {
-                        remove = true;
-                    }
-                    if (remove) {
-                        ba.removeAt(i);
-                    }
-                }
-                if (ba.size() == 0) {
-                    pmap.removeAt(ip);
-                }
-            }
+            mAppErrors.resetProcessCrashTimeLocked(packageName == null, appId, userId);
         }
 
         boolean didSomething = killPackageProcessesLocked(packageName, appId, userId,
-                ProcessList.INVALID_ADJ, callerWillRestart, true, doit, evenPersistent, true,
+                ProcessList.INVALID_ADJ, callerWillRestart, true, doit, evenPersistent,
                 packageName == null ? ("stop user " + userId) : ("stop " + packageName));
 
         if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
@@ -6023,7 +5890,7 @@
                 }
             }
             if (mBooted) {
-                mStackSupervisor.resumeTopActivitiesLocked();
+                mStackSupervisor.resumeFocusedStackTopActivityLocked();
                 mStackSupervisor.scheduleIdleLocked();
             }
         }
@@ -6078,7 +5945,7 @@
         }
     }
 
-    private final boolean removeProcessLocked(ProcessRecord app,
+    boolean removeProcessLocked(ProcessRecord app,
             boolean callerWillRestart, boolean allowRestart, String reason) {
         final String name = app.processName;
         final int uid = app.uid;
@@ -6516,8 +6383,10 @@
             Process.establishZygoteConnectionForAbi(abi);
             final String instructionSet = VMRuntime.getInstructionSet(abi);
             if (!completedIsas.contains(instructionSet)) {
-                if (mInstaller.markBootComplete(VMRuntime.getInstructionSet(abi)) != 0) {
-                    Slog.e(TAG, "Unable to mark boot complete for abi: " + abi);
+                try {
+                    mInstaller.markBootComplete(VMRuntime.getInstructionSet(abi));
+                } catch (InstallerException e) {
+                    Slog.e(TAG, "Unable to mark boot complete for abi: " + abi, e);
                 }
                 completedIsas.add(instructionSet);
             }
@@ -6557,6 +6426,8 @@
             }
         }, dumpheapFilter);
 
+        mProcessStartLogger.registerListener(mContext);
+
         // Let system services know.
         mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETED);
 
@@ -6698,6 +6569,15 @@
     }
 
     @Override
+    public final void activityRelaunched(IBinder token) {
+        final long origId = Binder.clearCallingIdentity();
+        synchronized (this) {
+            mStackSupervisor.activityRelaunchedLocked(token);
+        }
+        Binder.restoreCallingIdentity(origId);
+    }
+
+    @Override
     public void reportSizeConfigurations(IBinder token, int[] horizontalSizeConfiguration,
             int[] verticalSizeConfigurations, int[] smallestSizeConfigurations) {
         if (DEBUG_CONFIGURATION) Slog.v(TAG, "Report configuration: " + token + " "
@@ -6845,8 +6725,8 @@
             }
             try {
                 if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
-                    int uid = AppGlobals.getPackageManager()
-                            .getPackageUid(packageName, UserHandle.getUserId(callingUid));
+                    final int uid = AppGlobals.getPackageManager().getPackageUid(packageName,
+                            MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callingUid));
                     if (!UserHandle.isSameApp(callingUid, uid)) {
                         String msg = "Permission Denial: getIntentSender() from pid="
                             + Binder.getCallingPid()
@@ -6941,8 +6821,8 @@
         synchronized(this) {
             PendingIntentRecord rec = (PendingIntentRecord)sender;
             try {
-                int uid = AppGlobals.getPackageManager()
-                        .getPackageUid(rec.key.packageName, UserHandle.getCallingUserId());
+                final int uid = AppGlobals.getPackageManager().getPackageUid(rec.key.packageName,
+                        MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getCallingUserId());
                 if (!UserHandle.isSameApp(uid, Binder.getCallingUid())) {
                     String msg = "Permission Denial: cancelIntentSender() from pid="
                         + Binder.getCallingPid()
@@ -7170,25 +7050,80 @@
     }
 
     @Override
-    public boolean inMultiWindowMode(IBinder token) {
-        synchronized(this) {
-            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
-            if (r == null) {
+    public boolean isAppForeground(int uid) throws RemoteException {
+        synchronized (this) {
+            UidRecord uidRec = mActiveUids.get(uid);
+            if (uidRec == null || uidRec.idle) {
                 return false;
             }
-            // An activity is consider to be in multi-window mode if its task isn't fullscreen.
-            return !r.task.mFullscreen;
+            return uidRec.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+        }
+    }
+
+    @Override
+    public boolean inMultiWindowMode(IBinder token) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized(this) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+                if (r == null) {
+                    return false;
+                }
+                // An activity is consider to be in multi-window mode if its task isn't fullscreen.
+                return !r.task.mFullscreen;
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
     }
 
     @Override
     public boolean inPictureInPictureMode(IBinder token) {
-        synchronized(this) {
-            final ActivityStack stack = ActivityRecord.getStackLocked(token);
-            if (stack == null) {
-                return false;
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized(this) {
+                final ActivityStack stack = ActivityRecord.getStackLocked(token);
+                if (stack == null) {
+                    return false;
+                }
+                return stack.mStackId == PINNED_STACK_ID;
             }
-            return stack.mStackId == PINNED_STACK_ID;
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public void enterPictureInPictureMode(IBinder token) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized(this) {
+                if (!mSupportsPictureInPicture) {
+                    throw new IllegalStateException("enterPictureInPictureMode: "
+                            + "Device doesn't support picture-in-picture mode.");
+                }
+
+                final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+
+                if (r == null) {
+                    throw new IllegalStateException("enterPictureInPictureMode: "
+                            + "Can't find activity for token=" + token);
+                }
+
+                if (!r.supportsPictureInPicture()) {
+                    throw new IllegalArgumentException("enterPictureInPictureMode: "
+                            + "Picture-In-Picture not supported for r=" + r);
+                }
+
+                // Use the default launch bounds for pinned stack if it doesn't exist yet.
+                final Rect bounds = (mStackSupervisor.getStack(PINNED_STACK_ID) == null)
+                        ? mDefaultPinnedStackBounds : null;
+
+                mStackSupervisor.moveActivityToStackLocked(
+                        r, PINNED_STACK_ID, "enterPictureInPictureMode", bounds);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
     }
 
@@ -7645,7 +7580,8 @@
         int targetUid = lastTargetUid;
         if (targetUid < 0 && targetPkg != null) {
             try {
-                targetUid = pm.getPackageUid(targetPkg, UserHandle.getUserId(callingUid));
+                targetUid = pm.getPackageUid(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
+                        UserHandle.getUserId(callingUid));
                 if (targetUid < 0) {
                     if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
                             "Can't grant URI permission no uid for: " + targetPkg);
@@ -7783,7 +7719,7 @@
         int targetUid;
         final IPackageManager pm = AppGlobals.getPackageManager();
         try {
-            targetUid = pm.getPackageUid(targetPkg, targetUserId);
+            targetUid = pm.getPackageUid(targetPkg, MATCH_DEBUG_TRIAGED_MISSING, targetUserId);
         } catch (RemoteException ex) {
             return;
         }
@@ -7844,7 +7780,8 @@
             targetUid = needed.targetUid;
         } else {
             try {
-                targetUid = pm.getPackageUid(targetPkg, targetUserId);
+                targetUid = pm.getPackageUid(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
+                        targetUserId);
             } catch (RemoteException ex) {
                 return null;
             }
@@ -8148,6 +8085,18 @@
         }
     }
 
+    @Override
+    public IBinder getUriPermissionOwnerForActivity(IBinder activityToken) {
+        enforceNotIsolatedCaller("getUriPermissionOwnerForActivity");
+        synchronized(this) {
+            ActivityRecord r = ActivityRecord.isInStackLocked(activityToken);
+            if (r == null) {
+                throw new IllegalArgumentException("Activity does not exist; token="
+                        + activityToken);
+            }
+            return r.getUriPermissionsLocked().getExternalTokenLocked();
+        }
+    }
     /**
      * @param uri This uri must NOT contain an embedded userId.
      * @param sourceUserId The userId in which the uri is to be resolved.
@@ -8299,8 +8248,8 @@
                         if (pi != null && sourcePkg.equals(pi.packageName)) {
                             int targetUid = -1;
                             try {
-                                targetUid = AppGlobals.getPackageManager()
-                                        .getPackageUid(targetPkg, targetUserId);
+                                targetUid = AppGlobals.getPackageManager().getPackageUid(
+                                        targetPkg, MATCH_UNINSTALLED_PACKAGES, targetUserId);
                             } catch (RemoteException e) {
                             }
                             if (targetUid != -1) {
@@ -8456,7 +8405,8 @@
         final int callingUid = Binder.getCallingUid();
         final IPackageManager pm = AppGlobals.getPackageManager();
         try {
-            final int packageUid = pm.getPackageUid(packageName, UserHandle.getUserId(callingUid));
+            final int packageUid = pm.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING,
+                    UserHandle.getUserId(callingUid));
             if (packageUid != callingUid) {
                 throw new SecurityException(
                         "Package " + packageName + " does not belong to calling UID " + callingUid);
@@ -8496,6 +8446,35 @@
     }
 
     @Override
+    public ParceledListSlice<android.content.UriPermission> getGrantedUriPermissions(
+            String packageName, int userId) {
+        enforceCallingPermission(android.Manifest.permission.GET_APP_GRANTED_URI_PERMISSIONS,
+                "getGrantedUriPermissions");
+
+        final ArrayList<android.content.UriPermission> result = Lists.newArrayList();
+        synchronized (this) {
+            final int size = mGrantedUriPermissions.size();
+            for (int i = 0; i < size; i++) {
+                final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
+                for (UriPermission perm : perms.values()) {
+                    if (packageName.equals(perm.targetPkg) && perm.targetUserId == userId
+                            && perm.persistedModeFlags != 0) {
+                        result.add(perm.buildPersistedPublicApiObject());
+                    }
+                }
+            }
+        }
+        return new ParceledListSlice<android.content.UriPermission>(result);
+    }
+
+    @Override
+    public void clearGrantedUriPermissions(String packageName, int userId) {
+        enforceCallingPermission(android.Manifest.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS,
+                "clearGrantedUriPermissions");
+        removeUriPermissionsForPackageLocked(packageName, userId, true);
+    }
+
+    @Override
     public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
         synchronized (this) {
             ProcessRecord app =
@@ -8677,6 +8656,8 @@
                     android.Manifest.permission.GET_DETAILED_TASKS)
                     == PackageManager.PERMISSION_GRANTED;
 
+            mRecentTasks.loadUserRecentsLocked(userId);
+
             final int recentsCount = mRecentTasks.size();
             ArrayList<ActivityManager.RecentTaskInfo> res =
                     new ArrayList<>(maxNum < recentsCount ? maxNum : recentsCount);
@@ -8697,6 +8678,11 @@
                     continue;
                 }
 
+                if (tr.realActivitySuspended) {
+                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, activity suspended: " + tr);
+                    continue;
+                }
+
                 // Return the entry if desired by the caller.  We always return
                 // the first entry, because callers always expect this to be the
                 // foreground app.  We may filter others if the caller has
@@ -8723,6 +8709,20 @@
                             continue;
                         }
                     }
+                    if ((flags & ActivityManager.RECENT_INGORE_DOCKED_STACK_TASKS) != 0) {
+                        if (tr.stack != null && tr.stack.isDockedStack()) {
+                            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+                                    "Skipping, docked stack task: " + tr);
+                            continue;
+                        }
+                    }
+                    if ((flags & ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS) != 0) {
+                        if (tr.stack != null && tr.stack.isPinnedStack()) {
+                            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+                                    "Skipping, pinned stack task: " + tr);
+                            continue;
+                        }
+                    }
                     if (tr.autoRemoveRecents && tr.getTopActivity() == null) {
                         // Don't include auto remove tasks that are finished or finishing.
                         if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
@@ -8825,8 +8825,9 @@
                 thumbnailInfo.taskHeight = displaySize.y;
                 thumbnailInfo.screenOrientation = mConfiguration.orientation;
 
-                TaskRecord task = new TaskRecord(this, mStackSupervisor.getNextTaskId(), ainfo,
-                        intent, description, thumbnailInfo);
+                TaskRecord task = new TaskRecord(this,
+                        mStackSupervisor.getNextTaskIdForUserLocked(r.userId),
+                        ainfo, intent, description, thumbnailInfo);
 
                 int trimIdx = mRecentTasks.trimForTaskLocked(task, false);
                 if (trimIdx >= 0) {
@@ -8886,15 +8887,14 @@
                 task.mResizeable = resizeable;
                 mWindowManager.setTaskResizeable(taskId, resizeable);
                 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
-                mStackSupervisor.resumeTopActivitiesLocked();
+                mStackSupervisor.resumeFocusedStackTopActivityLocked();
             }
         }
     }
 
     @Override
     public void resizeTask(int taskId, Rect bounds, int resizeMode) {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "resizeTask()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeTask()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
@@ -8944,8 +8944,7 @@
 
     @Override
     public Rect getTaskBounds(int taskId) {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "getTaskBounds()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getTaskBounds()");
         long ident = Binder.clearCallingIdentity();
         Rect rect = new Rect();
         try {
@@ -8987,9 +8986,10 @@
                 passedIconFile.getName());
         if (!legitIconFile.getPath().equals(filePath)
                 || !filePath.contains(ActivityRecord.ACTIVITY_ICON_SUFFIX)) {
-            throw new IllegalArgumentException("Bad file path: " + filePath);
+            throw new IllegalArgumentException("Bad file path: " + filePath
+                    + " passed for userId " + userId);
         }
-        return mTaskPersister.getTaskDescriptionIcon(filePath);
+        return mRecentTasks.getTaskDescriptionIcon(filePath);
     }
 
     @Override
@@ -9247,8 +9247,7 @@
     @Override
     public IActivityContainer createVirtualActivityContainer(IBinder parentActivityToken,
             IActivityContainerCallback callback) throws RemoteException {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "createActivityContainer()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "createActivityContainer()");
         synchronized (this) {
             if (parentActivityToken == null) {
                 throw new IllegalArgumentException("parent token must not be null");
@@ -9266,8 +9265,7 @@
 
     @Override
     public void deleteActivityContainer(IActivityContainer container) throws RemoteException {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "deleteActivityContainer()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "deleteActivityContainer()");
         synchronized (this) {
             mStackSupervisor.deleteActivityContainer(container);
         }
@@ -9275,8 +9273,7 @@
 
     @Override
     public IActivityContainer createStackOnDisplay(int displayId) throws RemoteException {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "createStackOnDisplay()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "createStackOnDisplay()");
         synchronized (this) {
             final int stackId = mStackSupervisor.getNextStackId();
             final ActivityStack stack =
@@ -9311,23 +9308,23 @@
     }
 
     @Override
-    public void moveActivityToStack(IBinder token, int stackId) throws RemoteException {
-        if (stackId == HOME_STACK_ID) {
-            throw new IllegalArgumentException(
-                    "moveActivityToStack: Attempt to move token " + token + " to home stack");
-        }
+    public void exitFreeformMode(IBinder token) throws RemoteException {
         synchronized (this) {
             long ident = Binder.clearCallingIdentity();
             try {
                 final ActivityRecord r = ActivityRecord.forTokenLocked(token);
                 if (r == null) {
                     throw new IllegalArgumentException(
-                            "moveActivityToStack: No activity record matching token=" + token);
+                            "exitFreeformMode: No activity record matching token=" + token);
                 }
-                if (DEBUG_STACK) Slog.d(TAG_STACK, "moveActivityToStack: moving r=" + r
-                        + " to stackId=" + stackId);
-                mStackSupervisor.moveTaskToStackLocked(r.task.taskId, stackId, ON_TOP, !FORCE_FOCUS,
-                        "moveActivityToStack", ANIMATE);
+                final ActivityStack stack = r.getStackLocked(token);
+                if (stack == null || stack.mStackId != FREEFORM_WORKSPACE_STACK_ID) {
+                    throw new IllegalStateException(
+                            "exitFreeformMode: You can only go fullscreen from freeform.");
+                }
+                if (DEBUG_STACK) Slog.d(TAG_STACK, "exitFreeformMode: " + r);
+                mStackSupervisor.moveTaskToStackLocked(r.task.taskId, FULLSCREEN_WORKSPACE_STACK_ID,
+                        ON_TOP, !FORCE_FOCUS, "exitFreeformMode", ANIMATE);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -9336,8 +9333,7 @@
 
     @Override
     public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "moveTaskToStack()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToStack()");
         if (stackId == HOME_STACK_ID) {
             throw new IllegalArgumentException(
                     "moveTaskToStack: Attempt to move task " + taskId + " to home stack");
@@ -9372,8 +9368,7 @@
     @Override
     public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
             Rect initialBounds) {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "moveTaskToDockedStack()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToDockedStack()");
         synchronized (this) {
             long ident = Binder.clearCallingIdentity();
             try {
@@ -9399,8 +9394,7 @@
      */
     @Override
     public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "moveTopActivityToPinnedStack()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTopActivityToPinnedStack()");
         synchronized (this) {
             if (!mSupportsPictureInPicture) {
                 throw new IllegalStateException("moveTopActivityToPinnedStack:"
@@ -9417,14 +9411,42 @@
     }
 
     @Override
-    public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode) {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "resizeStack()");
+    public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode,
+            boolean preserveWindows, boolean animate) {
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeStack()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
-                mStackSupervisor.resizeStackLocked(
-                        stackId, bounds, !PRESERVE_WINDOWS, allowResizeInDockedMode);
+                if (animate) {
+                    if (stackId == PINNED_STACK_ID) {
+                        mWindowManager.animateResizePinnedStack(bounds);
+                    } else {
+                        throw new IllegalArgumentException("Stack: " + stackId
+                                + " doesn't support animated resize.");
+                    }
+                } else {
+                    mStackSupervisor.resizeStackLocked(stackId, bounds, null /* tempTaskBounds */,
+                            null /* tempTaskInsetBounds */, preserveWindows,
+                            allowResizeInDockedMode);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
+    public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
+            Rect tempDockedTaskInsetBounds,
+            Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds) {
+        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+                "resizeDockedStack()");
+        long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                mStackSupervisor.resizeDockedStackLocked(dockedBounds, tempDockedTaskBounds,
+                        tempDockedTaskInsetBounds, tempOtherTaskBounds, tempOtherTaskInsetBounds,
+                        PRESERVE_WINDOWS);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -9433,8 +9455,7 @@
 
     @Override
     public void positionTaskInStack(int taskId, int stackId, int position) {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "positionTaskInStack()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "positionTaskInStack()");
         if (stackId == HOME_STACK_ID) {
             throw new IllegalArgumentException(
                     "positionTaskInStack: Attempt to change the position of task "
@@ -9455,8 +9476,7 @@
 
     @Override
     public List<StackInfo> getAllStackInfos() {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "getAllStackInfos()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getAllStackInfos()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
@@ -9469,8 +9489,7 @@
 
     @Override
     public StackInfo getStackInfo(int stackId) {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "getStackInfo()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
@@ -9483,8 +9502,7 @@
 
     @Override
     public boolean isInHomeStack(int taskId) {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "getStackInfo()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
@@ -9598,8 +9616,7 @@
 
     @Override
     public void startLockTaskModeOnCurrent() throws RemoteException {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "startLockTaskModeOnCurrent");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "startLockTaskModeOnCurrent");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
@@ -9651,8 +9668,7 @@
 
     @Override
     public void stopLockTaskModeOnCurrent() throws RemoteException {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "stopLockTaskModeOnCurrent");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "stopLockTaskModeOnCurrent");
         long ident = Binder.clearCallingIdentity();
         try {
             stopLockTaskMode();
@@ -9691,9 +9707,10 @@
     private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
         List<ProviderInfo> providers = null;
         try {
-            ParceledListSlice<ProviderInfo> slice = AppGlobals.getPackageManager().
-                queryContentProviders(app.processName, app.uid,
-                        STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
+            ParceledListSlice<ProviderInfo> slice = 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;
         } catch (RemoteException ex) {
         }
@@ -10606,7 +10623,7 @@
 
         final long token = Binder.clearCallingIdentity();
         try {
-            appNotResponding(host, null, null, false, "ContentProvider not responding");
+            mAppErrors.appNotResponding(host, null, null, false, "ContentProvider not responding");
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -10633,11 +10650,55 @@
         }
 
         mCoreSettingsObserver = new CoreSettingsObserver(this);
+        mFontScaleSettingObserver = new FontScaleSettingObserver();
 
         //mUsageStatsService.monitorPackages();
     }
 
     /**
+     * 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()) {
+            // 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
+            // have already been spun up.
+            return;
+        }
+
+        synchronized (this) {
+            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.userId != userId || app.thread == null) continue;
+
+                    final int NG = app.pkgList.size();
+                    for (int ig = 0; ig < NG; ig++) {
+                        try {
+                            final String pkgName = app.pkgList.keyAt(ig);
+                            final PackageInfo pkgInfo = AppGlobals.getPackageManager()
+                                    .getPackageInfo(pkgName,
+                                            GET_PROVIDERS | MATCH_ENCRYPTION_UNAWARE, userId);
+                            if (pkgInfo != null && !ArrayUtils.isEmpty(pkgInfo.providers)) {
+                                for (ProviderInfo provInfo : pkgInfo.providers) {
+                                    Log.v(TAG, "Installing " + provInfo);
+                                    app.thread.scheduleInstallProvider(provInfo);
+                                }
+                            }
+                        } catch (RemoteException ignored) {
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
      * Allows apps to retrieve the MIME type of a URI.
      * If an app is in the same user as the ContentProvider, or if it is allowed to interact across
      * users, then it does not need permission to access the ContentProvider.
@@ -10849,6 +10910,7 @@
     }
 
     void finishRunningVoiceLocked() {
+        Slog.d(TAG, "finishRunningVoiceLocked()  >>>>");
         if (mRunningVoice != null) {
             mRunningVoice = null;
             mVoiceWakeLock.release();
@@ -10909,11 +10971,7 @@
 
     /** Pokes the task persister. */
     void notifyTaskPersisterLocked(TaskRecord task, boolean flush) {
-        if (task != null && task.stack != null && task.stack.isHomeStack()) {
-            // Never persist the home stack.
-            return;
-        }
-        mTaskPersister.wakeup(task, flush);
+        mRecentTasks.notifyTaskPersisterLocked(task, flush);
     }
 
     /** Notifies all listeners when the task stack has changed. */
@@ -10924,6 +10982,22 @@
         mHandler.sendMessageDelayed(nmsg, NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY);
     }
 
+    /** Notifies all listeners when an Activity is pinned. */
+    void notifyActivityPinnedLocked() {
+        mHandler.removeMessages(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG);
+        mHandler.obtainMessage(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG).sendToTarget();
+    }
+
+    /**
+     * Notifies all listeners when an attempt was made to start an an activity that is already
+     * running in the pinned stack and the activity was not actually started, but the task is
+     * either brought to the front or a new Intent is delivered to it.
+     */
+    void notifyPinnedActivityRestartAttemptLocked() {
+        mHandler.removeMessages(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG);
+        mHandler.obtainMessage(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG).sendToTarget();
+    }
+
     @Override
     public void notifyCleartextNetwork(int uid, byte[] firstPacket) {
         mHandler.obtainMessage(NOTIFY_CLEARTEXT_NETWORK_MSG, uid, 0, firstPacket).sendToTarget();
@@ -10990,6 +11064,7 @@
     }
 
     void startRunningVoiceLocked(IVoiceInteractionSession session, int targetUid) {
+        Slog.d(TAG, "<<<  startRunningVoiceLocked()");
         mVoiceWakeLock.setWorkSource(new WorkSource(targetUid));
         if (mRunningVoice == null || mRunningVoice.asBinder() != session.asBinder()) {
             boolean wasRunningVoice = mRunningVoice != null;
@@ -11012,9 +11087,13 @@
                     + 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();
@@ -11210,8 +11289,23 @@
         }
     }
 
-    public void requestBugReport(boolean progress) {
-        final String service = progress ? "bugreportplus" : "bugreport";
+    public void requestBugReport(int bugreportType) {
+        String service = null;
+        switch (bugreportType) {
+            case ActivityManager.BUGREPORT_OPTION_FULL:
+                service = "bugreport";
+                break;
+            case ActivityManager.BUGREPORT_OPTION_INTERACTIVE:
+                service = "bugreportplus";
+                break;
+            case ActivityManager.BUGREPORT_OPTION_REMOTE:
+                service = "bugreportremote";
+                break;
+        }
+        if (service == null) {
+            throw new IllegalArgumentException("Provided bugreport type is not correct, value: "
+                    + bugreportType);
+        }
         enforceCallingPermission(android.Manifest.permission.DUMP, "requestBugReport");
         SystemProperties.set("ctl.start", service);
     }
@@ -11293,7 +11387,7 @@
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    appNotResponding(proc, activity, parent, aboveSystem, annotation);
+                    mAppErrors.appNotResponding(proc, activity, parent, aboveSystem, annotation);
                 }
             });
         }
@@ -11667,6 +11761,26 @@
         }
     }
 
+    @Override
+    public void setVrMode(IBinder token, boolean enabled) {
+        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) {
+            throw new UnsupportedOperationException("VR mode not supported on this device!");
+        }
+
+        synchronized(this) {
+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            if (r == null) {
+                throw new IllegalArgumentException();
+            }
+            r.isVrActivity = enabled;
+
+            // Update associated state if this activity is currently focused
+            if (r == mFocusedActivity) {
+                applyUpdateVrModeLocked(r);
+            }
+        }
+    }
+
     public boolean isTopActivityImmersive() {
         enforceNotIsolatedCaller("startActivity");
         synchronized (this) {
@@ -11836,7 +11950,7 @@
             final long identity = Binder.clearCallingIdentity();
             try {
                 killPackageProcessesLocked(null, appId, userId,
-                        ProcessList.PERSISTENT_PROC_ADJ, false, true, true, true, true,
+                        ProcessList.PERSISTENT_PROC_ADJ, false, true, true, true,
                         reason != null ? reason : "kill uid");
             } finally {
                 Binder.restoreCallingIdentity(identity);
@@ -11993,6 +12107,8 @@
                             sb.append(proc.processName);
                             sb.append(" in idle maint: pss=");
                             sb.append(proc.lastPss);
+                            sb.append(", swapPss=");
+                            sb.append(proc.lastSwapPss);
                             sb.append(", initialPss=");
                             sb.append(proc.initialIdlePss);
                             sb.append(", period=");
@@ -12020,7 +12136,9 @@
     private void retrieveSettings() {
         final ContentResolver resolver = mContext.getContentResolver();
         final boolean freeformWindowManagement =
-                mContext.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT);
+                mContext.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT)
+                        || Settings.Global.getInt(
+                                resolver, DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
         final boolean supportsPictureInPicture =
                 mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
 
@@ -12029,9 +12147,8 @@
         final boolean alwaysFinishActivities =
                 Settings.Global.getInt(resolver, ALWAYS_FINISH_ACTIVITIES, 0) != 0;
         final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0;
-        final int defaultForceResizable = Build.IS_DEBUGGABLE ? 1 : 0;
         final boolean forceResizable = Settings.Global.getInt(
-                resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, defaultForceResizable) != 0;
+                resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
         // Transfer any global setting for forcing RTL layout, into a System Property
         SystemProperties.set(DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0");
 
@@ -12062,6 +12179,10 @@
                     com.android.internal.R.dimen.thumbnail_width);
             mThumbnailHeight = res.getDimensionPixelSize(
                     com.android.internal.R.dimen.thumbnail_height);
+            mDefaultPinnedStackBounds = Rect.unflattenFromString(res.getString(
+                    com.android.internal.R.string.config_defaultPictureInPictureBounds));
+            mAppErrors.loadAppsNotReportingCrashesFromConfigLocked(res.getString(
+                    com.android.internal.R.string.config_appsNotReportingCrashes));
         }
     }
 
@@ -12212,19 +12333,13 @@
         List<ResolveInfo> ris = null;
         try {
             ris = AppGlobals.getPackageManager().queryIntentReceivers(
-                    intent, null, 0, UserHandle.USER_SYSTEM);
+                    intent, null, MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
         } catch (RemoteException e) {
         }
         if (ris == null) {
             return false;
         }
-        for (int i=ris.size()-1; i>=0; i--) {
-            if ((ris.get(i).activityInfo.applicationInfo.flags
-                    &ApplicationInfo.FLAG_SYSTEM) == 0) {
-                ris.remove(i);
-            }
-        }
-        intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
+        intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE | Intent.FLAG_DEBUG_TRIAGED_MISSING);
 
         ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers();
         for (int i=0; i<ris.size(); i++) {
@@ -12275,11 +12390,7 @@
             // security checks.
             mUserController.updateCurrentProfileIdsLocked();
 
-            mRecentTasks.clear();
-            mRecentTasks.addAll(mTaskPersister.restoreTasksLocked(mUserController.getUserIds()));
-            mRecentTasks.cleanupLocked(UserHandle.USER_ALL);
-            mTaskPersister.startPersisting();
-
+            mRecentTasks.onSystemReady();
             // Check to see if there are any update receivers to run.
             if (!mDidUpdate) {
                 if (mWaitingUpdate) {
@@ -12386,7 +12497,6 @@
 
         if (goingCallback != null) goingCallback.run();
 
-
         mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_RUNNING_START,
                 Integer.toString(currentUserId), currentUserId);
         mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_START,
@@ -12472,179 +12582,17 @@
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
-            mStackSupervisor.resumeTopActivitiesLocked();
+            mStackSupervisor.resumeFocusedStackTopActivityLocked();
             mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId);
         }
     }
 
-    private boolean makeAppCrashingLocked(ProcessRecord app,
-            String shortMsg, String longMsg, String stackTrace) {
-        app.crashing = true;
-        app.crashingReport = generateProcessError(app,
-                ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
-        startAppProblemLocked(app);
-        app.stopFreezingAllLocked();
-        return handleAppCrashLocked(app, "force-crash" /*reason*/, shortMsg, longMsg, stackTrace);
-    }
-
-    private void makeAppNotRespondingLocked(ProcessRecord app,
-            String activity, String shortMsg, String longMsg) {
-        app.notResponding = true;
-        app.notRespondingReport = generateProcessError(app,
-                ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING,
-                activity, shortMsg, longMsg, null);
-        startAppProblemLocked(app);
-        app.stopFreezingAllLocked();
-    }
-
-    /**
-     * Generate a process error record, suitable for attachment to a ProcessRecord.
-     *
-     * @param app The ProcessRecord in which the error occurred.
-     * @param condition Crashing, Application Not Responding, etc.  Values are defined in
-     *                      ActivityManager.AppErrorStateInfo
-     * @param activity The activity associated with the crash, if known.
-     * @param shortMsg Short message describing the crash.
-     * @param longMsg Long message describing the crash.
-     * @param stackTrace Full crash stack trace, may be null.
-     *
-     * @return Returns a fully-formed AppErrorStateInfo record.
-     */
-    private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
-            int condition, String activity, String shortMsg, String longMsg, String stackTrace) {
-        ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
-
-        report.condition = condition;
-        report.processName = app.processName;
-        report.pid = app.pid;
-        report.uid = app.info.uid;
-        report.tag = activity;
-        report.shortMsg = shortMsg;
-        report.longMsg = longMsg;
-        report.stackTrace = stackTrace;
-
-        return report;
-    }
-
     void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog) {
         synchronized (this) {
-            app.crashing = false;
-            app.crashingReport = null;
-            app.notResponding = false;
-            app.notRespondingReport = null;
-            if (app.anrDialog == fromDialog) {
-                app.anrDialog = null;
-            }
-            if (app.waitDialog == fromDialog) {
-                app.waitDialog = null;
-            }
-            if (app.pid > 0 && app.pid != MY_PID) {
-                handleAppCrashLocked(app, "user-terminated" /*reason*/,
-                        null /*shortMsg*/, null /*longMsg*/, null /*stackTrace*/);
-                app.kill("user request after error", true);
-            }
+            mAppErrors.killAppAtUserRequestLocked(app, fromDialog);
         }
     }
 
-    private boolean handleAppCrashLocked(ProcessRecord app, String reason,
-            String shortMsg, String longMsg, String stackTrace) {
-        long now = SystemClock.uptimeMillis();
-
-        Long crashTime;
-        if (!app.isolated) {
-            crashTime = mProcessCrashTimes.get(app.info.processName, app.uid);
-        } else {
-            crashTime = null;
-        }
-        if (crashTime != null && now < crashTime+ProcessList.MIN_CRASH_INTERVAL) {
-            // This process loses!
-            Slog.w(TAG, "Process " + app.info.processName
-                    + " has crashed too many times: killing!");
-            EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
-                    app.userId, app.info.processName, app.uid);
-            mStackSupervisor.handleAppCrashLocked(app);
-            if (!app.persistent) {
-                // We don't want to start this process again until the user
-                // explicitly does so...  but for persistent process, we really
-                // need to keep it running.  If a persistent process is actually
-                // repeatedly crashing, then badness for everyone.
-                EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.userId, app.uid,
-                        app.info.processName);
-                if (!app.isolated) {
-                    // XXX We don't have a way to mark isolated processes
-                    // as bad, since they don't have a peristent identity.
-                    mBadProcesses.put(app.info.processName, app.uid,
-                            new BadProcessInfo(now, shortMsg, longMsg, stackTrace));
-                    mProcessCrashTimes.remove(app.info.processName, app.uid);
-                }
-                app.bad = true;
-                app.removed = true;
-                // Don't let services in this process be restarted and potentially
-                // annoy the user repeatedly.  Unless it is persistent, since those
-                // processes run critical code.
-                removeProcessLocked(app, false, false, "crash");
-                mStackSupervisor.resumeTopActivitiesLocked();
-                return false;
-            }
-            mStackSupervisor.resumeTopActivitiesLocked();
-        } else {
-            mStackSupervisor.finishTopRunningActivityLocked(app, reason);
-        }
-
-        // Bump up the crash count of any services currently running in the proc.
-        for (int i=app.services.size()-1; i>=0; i--) {
-            // Any services running in the application need to be placed
-            // back in the pending list.
-            ServiceRecord sr = app.services.valueAt(i);
-            sr.crashCount++;
-        }
-
-        // If the crashing process is what we consider to be the "home process" and it has been
-        // replaced by a third-party app, clear the package preferred activities from packages
-        // with a home activity running in the process to prevent a repeatedly crashing app
-        // from blocking the user to manually clear the list.
-        final ArrayList<ActivityRecord> activities = app.activities;
-        if (app == mHomeProcess && activities.size() > 0
-                    && (mHomeProcess.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
-            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = activities.get(activityNdx);
-                if (r.isHomeActivity()) {
-                    Log.i(TAG, "Clearing package preferred activities from " + r.packageName);
-                    try {
-                        ActivityThread.getPackageManager()
-                                .clearPackagePreferredActivities(r.packageName);
-                    } catch (RemoteException c) {
-                        // pm is in same process, this will never happen.
-                    }
-                }
-            }
-        }
-
-        if (!app.isolated) {
-            // XXX Can't keep track of crash times for isolated processes,
-            // because they don't have a perisistent identity.
-            mProcessCrashTimes.put(app.info.processName, app.uid, now);
-        }
-
-        if (app.crashHandler != null) mHandler.post(app.crashHandler);
-        return true;
-    }
-
-    void startAppProblemLocked(ProcessRecord app) {
-        // If this app is not running under the current user, then we
-        // can't give it a report button because that would require
-        // launching the report UI under a different user.
-        app.errorReportReceiver = null;
-
-        for (int userId : mUserController.getCurrentProfileIdsLocked()) {
-            if (app.userId == userId) {
-                app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
-                        mContext, app.info.packageName, app.info.flags);
-            }
-        }
-        skipCurrentReceiverLocked(app);
-    }
-
     void skipCurrentReceiverLocked(ProcessRecord app) {
         for (BroadcastQueue queue : mBroadcastQueues) {
             queue.skipCurrentReceiverLocked(app);
@@ -12680,7 +12628,7 @@
 
         addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);
 
-        crashApplication(r, crashInfo);
+        mAppErrors.crashApplication(r, crashInfo);
     }
 
     public void handleApplicationStrictModeViolation(
@@ -12891,7 +12839,7 @@
         if (r != null && r.pid != Process.myPid() &&
                 Settings.Global.getInt(mContext.getContentResolver(),
                         Settings.Global.WTF_IS_FATAL, 0) != 0) {
-            crashApplication(r, crashInfo);
+            mAppErrors.crashApplication(r, crashInfo);
             return true;
         } else {
             return false;
@@ -13022,6 +12970,9 @@
 
         final StringBuilder sb = new StringBuilder(1024);
         appendDropBoxProcessHeaders(process, processName, sb);
+        sb.append("Foreground: ")
+                .append(process.isInterestingToUserLocked() ? "Yes" : "No")
+                .append("\n");
         if (activity != null) {
             sb.append("Activity: ").append(activity.shortComponentName).append("\n");
         }
@@ -13100,164 +13051,6 @@
         }
     }
 
-    /**
-     * Bring up the "unexpected error" dialog box for a crashing app.
-     * Deal with edge cases (intercepts from instrumented applications,
-     * ActivityController, error intent receivers, that sort of thing).
-     * @param r the application crashing
-     * @param crashInfo describing the failure
-     */
-    private void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
-        long timeMillis = System.currentTimeMillis();
-        String shortMsg = crashInfo.exceptionClassName;
-        String longMsg = crashInfo.exceptionMessage;
-        String stackTrace = crashInfo.stackTrace;
-        if (shortMsg != null && longMsg != null) {
-            longMsg = shortMsg + ": " + longMsg;
-        } else if (shortMsg != null) {
-            longMsg = shortMsg;
-        }
-
-        AppErrorResult result = new AppErrorResult();
-        synchronized (this) {
-            if (mController != null) {
-                try {
-                    String name = r != null ? r.processName : null;
-                    int pid = r != null ? r.pid : Binder.getCallingPid();
-                    int uid = r != null ? r.info.uid : Binder.getCallingUid();
-                    if (!mController.appCrashed(name, pid,
-                            shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
-                        if ("1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"))
-                                && "Native crash".equals(crashInfo.exceptionClassName)) {
-                            Slog.w(TAG, "Skip killing native crashed app " + name
-                                    + "(" + pid + ") during testing");
-                        } else {
-                            Slog.w(TAG, "Force-killing crashed app " + name
-                                    + " at watcher's request");
-                            if (r != null) {
-                                r.kill("crash", true);
-                            } else {
-                                // Huh.
-                                Process.killProcess(pid);
-                                killProcessGroup(uid, pid);
-                            }
-                        }
-                        return;
-                    }
-                } catch (RemoteException e) {
-                    mController = null;
-                    Watchdog.getInstance().setActivityController(null);
-                }
-            }
-
-            final long origId = Binder.clearCallingIdentity();
-
-            // If this process is running instrumentation, finish it.
-            if (r != null && r.instrumentationClass != null) {
-                Slog.w(TAG, "Error in app " + r.processName
-                      + " running instrumentation " + r.instrumentationClass + ":");
-                if (shortMsg != null) Slog.w(TAG, "  " + shortMsg);
-                if (longMsg != null) Slog.w(TAG, "  " + longMsg);
-                Bundle info = new Bundle();
-                info.putString("shortMsg", shortMsg);
-                info.putString("longMsg", longMsg);
-                finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
-                Binder.restoreCallingIdentity(origId);
-                return;
-            }
-
-            // Log crash in battery stats.
-            if (r != null) {
-                mBatteryStatsService.noteProcessCrash(r.processName, r.uid);
-            }
-
-            // If we can't identify the process or it's already exceeded its crash quota,
-            // quit right away without showing a crash dialog.
-            if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace)) {
-                Binder.restoreCallingIdentity(origId);
-                return;
-            }
-
-            Message msg = Message.obtain();
-            msg.what = SHOW_ERROR_UI_MSG;
-            HashMap data = new HashMap();
-            data.put("result", result);
-            data.put("app", r);
-            msg.obj = data;
-            mUiHandler.sendMessage(msg);
-
-            Binder.restoreCallingIdentity(origId);
-        }
-
-        int res = result.get();
-
-        Intent appErrorIntent = null;
-        synchronized (this) {
-            if (r != null && !r.isolated) {
-                // XXX Can't keep track of crash time for isolated processes,
-                // since they don't have a persistent identity.
-                mProcessCrashTimes.put(r.info.processName, r.uid,
-                        SystemClock.uptimeMillis());
-            }
-            if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
-                appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
-            }
-        }
-
-        if (appErrorIntent != null) {
-            try {
-                mContext.startActivityAsUser(appErrorIntent, new UserHandle(r.userId));
-            } catch (ActivityNotFoundException e) {
-                Slog.w(TAG, "bug report receiver dissappeared", e);
-            }
-        }
-    }
-
-    Intent createAppErrorIntentLocked(ProcessRecord r,
-            long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
-        ApplicationErrorReport report = createAppErrorReportLocked(r, timeMillis, crashInfo);
-        if (report == null) {
-            return null;
-        }
-        Intent result = new Intent(Intent.ACTION_APP_ERROR);
-        result.setComponent(r.errorReportReceiver);
-        result.putExtra(Intent.EXTRA_BUG_REPORT, report);
-        result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        return result;
-    }
-
-    private ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r,
-            long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
-        if (r.errorReportReceiver == null) {
-            return null;
-        }
-
-        if (!r.crashing && !r.notResponding && !r.forceCrashReport) {
-            return null;
-        }
-
-        ApplicationErrorReport report = new ApplicationErrorReport();
-        report.packageName = r.info.packageName;
-        report.installerPackageName = r.errorReportReceiver.getPackageName();
-        report.processName = r.processName;
-        report.time = timeMillis;
-        report.systemApp = (r.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
-
-        if (r.crashing || r.forceCrashReport) {
-            report.type = ApplicationErrorReport.TYPE_CRASH;
-            report.crashInfo = crashInfo;
-        } else if (r.notResponding) {
-            report.type = ApplicationErrorReport.TYPE_ANR;
-            report.anrInfo = new ApplicationErrorReport.AnrInfo();
-
-            report.anrInfo.activity = r.notRespondingReport.tag;
-            report.anrInfo.cause = r.notRespondingReport.shortMsg;
-            report.anrInfo.info = r.notRespondingReport.longMsg;
-        }
-
-        return report;
-    }
-
     public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
         enforceNotIsolatedCaller("getProcessesInErrorState");
         // assume our apps are happy - lazy create the list
@@ -13744,7 +13537,7 @@
         if (dumpPackage != null) {
             IPackageManager pm = AppGlobals.getPackageManager();
             try {
-                dumpUid = pm.getPackageUid(dumpPackage, 0);
+                dumpUid = pm.getPackageUid(dumpPackage, MATCH_UNINSTALLED_PACKAGES, 0);
             } catch (RemoteException e) {
             }
         }
@@ -13995,88 +13788,9 @@
 
         needSep = dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll, dumpPackage);
 
-        if (mProcessCrashTimes.getMap().size() > 0) {
-            boolean printed = false;
-            long now = SystemClock.uptimeMillis();
-            final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
-            final int NP = pmap.size();
-            for (int ip=0; ip<NP; ip++) {
-                String pname = pmap.keyAt(ip);
-                SparseArray<Long> uids = pmap.valueAt(ip);
-                final int N = uids.size();
-                for (int i=0; i<N; i++) {
-                    int puid = uids.keyAt(i);
-                    ProcessRecord r = mProcessNames.get(pname, puid);
-                    if (dumpPackage != null && (r == null
-                            || !r.pkgList.containsKey(dumpPackage))) {
-                        continue;
-                    }
-                    if (!printed) {
-                        if (needSep) pw.println();
-                        needSep = true;
-                        pw.println("  Time since processes crashed:");
-                        printed = true;
-                        printedAnything = true;
-                    }
-                    pw.print("    Process "); pw.print(pname);
-                            pw.print(" uid "); pw.print(puid);
-                            pw.print(": last crashed ");
-                            TimeUtils.formatDuration(now-uids.valueAt(i), pw);
-                            pw.println(" ago");
-                }
-            }
-        }
-
-        if (mBadProcesses.getMap().size() > 0) {
-            boolean printed = false;
-            final ArrayMap<String, SparseArray<BadProcessInfo>> pmap = mBadProcesses.getMap();
-            final int NP = pmap.size();
-            for (int ip=0; ip<NP; ip++) {
-                String pname = pmap.keyAt(ip);
-                SparseArray<BadProcessInfo> uids = pmap.valueAt(ip);
-                final int N = uids.size();
-                for (int i=0; i<N; i++) {
-                    int puid = uids.keyAt(i);
-                    ProcessRecord r = mProcessNames.get(pname, puid);
-                    if (dumpPackage != null && (r == null
-                            || !r.pkgList.containsKey(dumpPackage))) {
-                        continue;
-                    }
-                    if (!printed) {
-                        if (needSep) pw.println();
-                        needSep = true;
-                        pw.println("  Bad processes:");
-                        printedAnything = true;
-                    }
-                    BadProcessInfo info = uids.valueAt(i);
-                    pw.print("    Bad process "); pw.print(pname);
-                            pw.print(" uid "); pw.print(puid);
-                            pw.print(": crashed at time "); pw.println(info.time);
-                    if (info.shortMsg != null) {
-                        pw.print("      Short msg: "); pw.println(info.shortMsg);
-                    }
-                    if (info.longMsg != null) {
-                        pw.print("      Long msg: "); pw.println(info.longMsg);
-                    }
-                    if (info.stack != null) {
-                        pw.println("      Stack:");
-                        int lastPos = 0;
-                        for (int pos=0; pos<info.stack.length(); pos++) {
-                            if (info.stack.charAt(pos) == '\n') {
-                                pw.print("        ");
-                                pw.write(info.stack, lastPos, pos-lastPos);
-                                pw.println();
-                                lastPos = pos+1;
-                            }
-                        }
-                        if (lastPos < info.stack.length()) {
-                            pw.print("        ");
-                            pw.write(info.stack, lastPos, info.stack.length()-lastPos);
-                            pw.println();
-                        }
-                    }
-                }
-            }
+        needSep = mAppErrors.dumpLocked(fd, pw, needSep, dumpPackage);
+        if (needSep) {
+            printedAnything = true;
         }
 
         if (dumpPackage == null) {
@@ -14680,7 +14394,8 @@
             int dumpUid = -2;
             if (dumpPackage != null) {
                 try {
-                    dumpUid = mContext.getPackageManager().getPackageUid(dumpPackage, 0);
+                    dumpUid = mContext.getPackageManager().getPackageUidAsUser(dumpPackage,
+                            MATCH_UNINSTALLED_PACKAGES, 0);
                 } catch (NameNotFoundException e) {
                     dumpUid = -1;
                 }
@@ -14891,6 +14606,7 @@
                 pw.print("state: cur="); pw.print(ProcessList.makeProcStateString(r.curProcState));
                 pw.print(" set="); pw.print(ProcessList.makeProcStateString(r.setProcState));
                 pw.print(" lastPss="); DebugUtils.printSizeValue(pw, r.lastPss*1024);
+                pw.print(" lastSwapPss="); DebugUtils.printSizeValue(pw, r.lastSwapPss*1024);
                 pw.print(" lastCachedPss="); DebugUtils.printSizeValue(pw, r.lastCachedPss*1024);
                 pw.println();
                 pw.print(prefix);
@@ -15044,32 +14760,35 @@
         final String label;
         final String shortLabel;
         final long pss;
+        final long swapPss;
         final int id;
         final boolean hasActivities;
         ArrayList<MemItem> subitems;
 
-        public MemItem(String _label, String _shortLabel, long _pss, int _id,
+        public MemItem(String _label, String _shortLabel, long _pss, long _swapPss, int _id,
                 boolean _hasActivities) {
             isProc = true;
             label = _label;
             shortLabel = _shortLabel;
             pss = _pss;
+            swapPss = _swapPss;
             id = _id;
             hasActivities = _hasActivities;
         }
 
-        public MemItem(String _label, String _shortLabel, long _pss, int _id) {
+        public MemItem(String _label, String _shortLabel, long _pss, long _swapPss, int _id) {
             isProc = false;
             label = _label;
             shortLabel = _shortLabel;
             pss = _pss;
+            swapPss = _swapPss;
             id = _id;
             hasActivities = false;
         }
     }
 
     static final void dumpMemItems(PrintWriter pw, String prefix, String tag,
-            ArrayList<MemItem> items, boolean sort, boolean isCompact) {
+            ArrayList<MemItem> items, boolean sort, boolean isCompact, boolean dumpSwapPss) {
         if (sort && !isCompact) {
             Collections.sort(items, new Comparator<MemItem>() {
                 @Override
@@ -15087,18 +14806,24 @@
         for (int i=0; i<items.size(); i++) {
             MemItem mi = items.get(i);
             if (!isCompact) {
-                pw.printf("%s%s: %s\n", prefix, stringifyKBSize(mi.pss), mi.label);
+                if (dumpSwapPss) {
+                    pw.printf("%s%s: %-60s (%s in swap)\n", prefix, stringifyKBSize(mi.pss),
+                            mi.label, stringifyKBSize(mi.swapPss));
+                } else {
+                    pw.printf("%s%s: %s\n", prefix, stringifyKBSize(mi.pss), mi.label);
+                }
             } else if (mi.isProc) {
                 pw.print("proc,"); pw.print(tag); pw.print(","); pw.print(mi.shortLabel);
-                pw.print(","); pw.print(mi.id); pw.print(","); pw.print(mi.pss);
+                pw.print(","); pw.print(mi.id); pw.print(","); pw.print(mi.pss); pw.print(",");
+                pw.print(dumpSwapPss ? mi.swapPss : "N/A");
                 pw.println(mi.hasActivities ? ",a" : ",e");
             } else {
                 pw.print(tag); pw.print(","); pw.print(mi.shortLabel); pw.print(",");
-                pw.println(mi.pss);
+                pw.println(mi.pss); pw.print(dumpSwapPss ? mi.swapPss : "N/A");
             }
             if (mi.subitems != null) {
-                dumpMemItems(pw, prefix + "           ", mi.shortLabel, mi.subitems,
-                        true, isCompact);
+                dumpMemItems(pw, prefix + "    ", mi.shortLabel, mi.subitems,
+                        true, isCompact, dumpSwapPss);
             }
         }
     }
@@ -15227,6 +14952,8 @@
         boolean isCompact = false;
         boolean localOnly = false;
         boolean packages = false;
+        boolean isCheckinRequest = false;
+        boolean dumpSwapPss = false;
 
         int opti = 0;
         while (opti < args.length) {
@@ -15239,6 +14966,7 @@
                 dumpDetails = true;
                 dumpFullDetails = true;
                 dumpDalvik = true;
+                dumpSwapPss = true;
             } else if ("-d".equals(opt)) {
                 dumpDalvik = true;
             } else if ("-c".equals(opt)) {
@@ -15246,22 +14974,29 @@
             } else if ("-s".equals(opt)) {
                 dumpDetails = true;
                 dumpSummaryOnly = true;
+            } else if ("-S".equals(opt)) {
+                dumpSwapPss = true;
             } else if ("--oom".equals(opt)) {
                 oomOnly = true;
             } else if ("--local".equals(opt)) {
                 localOnly = true;
             } else if ("--package".equals(opt)) {
                 packages = true;
+            } else if ("--checkin".equals(opt)) {
+                isCheckinRequest = true;
+
             } else if ("-h".equals(opt)) {
                 pw.println("meminfo dump options: [-a] [-d] [-c] [-s] [--oom] [process]");
                 pw.println("  -a: include all available information for each process.");
                 pw.println("  -d: include dalvik details.");
                 pw.println("  -c: dump in a compact machine-parseable representation.");
                 pw.println("  -s: dump only summary of application memory usage.");
+                pw.println("  -S: dump also SwapPss.");
                 pw.println("  --oom: only show processes organized by oom adj.");
                 pw.println("  --local: only collect details locally, don't call process.");
                 pw.println("  --package: interpret process arg as package, dumping all");
                 pw.println("             processes that have loaded that package.");
+                pw.println("  --checkin: dump data for a checkin");
                 pw.println("If [process] is specified it can be the name or ");
                 pw.println("pid of a specific process to dump.");
                 return;
@@ -15270,7 +15005,6 @@
             }
         }
 
-        final boolean isCheckinRequest = scanArgs(args, "--checkin");
         long uptime = SystemClock.uptimeMillis();
         long realtime = SystemClock.elapsedRealtime();
         final long[] tmpLong = new long[1];
@@ -15342,18 +15076,28 @@
         ArrayList<MemItem> procMems = new ArrayList<MemItem>();
         final SparseArray<MemItem> procMemsMap = new SparseArray<MemItem>();
         long nativePss = 0;
+        long nativeSwapPss = 0;
         long dalvikPss = 0;
+        long dalvikSwapPss = 0;
         long[] dalvikSubitemPss = dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] :
                 EmptyArray.LONG;
+        long[] dalvikSubitemSwapPss = dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] :
+                EmptyArray.LONG;
         long otherPss = 0;
+        long otherSwapPss = 0;
         long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
+        long[] miscSwapPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
 
         long oomPss[] = new long[DUMP_MEM_OOM_LABEL.length];
+        long oomSwapPss[] = new long[DUMP_MEM_OOM_LABEL.length];
         ArrayList<MemItem>[] oomProcs = (ArrayList<MemItem>[])
                 new ArrayList[DUMP_MEM_OOM_LABEL.length];
 
         long totalPss = 0;
+        long totalSwapPss = 0;
         long cachedPss = 0;
+        long cachedSwapPss = 0;
+        boolean hasSwapPss = false;
 
         Debug.MemoryInfo mi = null;
         for (int i = procs.size() - 1 ; i >= 0 ; i--) {
@@ -15377,6 +15121,7 @@
                 }
                 if (dumpDetails || (!brief && !oomOnly)) {
                     Debug.getMemoryInfo(pid, mi);
+                    hasSwapPss = mi.hasSwappedOutPss;
                 } else {
                     mi.dalvikPss = (int)Debug.getPss(pid, tmpLong, null);
                     mi.dalvikPrivateDirty = (int)tmpLong[0];
@@ -15404,6 +15149,7 @@
 
                 final long myTotalPss = mi.getTotalPss();
                 final long myTotalUss = mi.getTotalUss();
+                final long myTotalSwapPss = mi.getTotalSwappedOutPss();
 
                 synchronized (this) {
                     if (r.thread != null && oomAdj == r.getSetAdjWithServices()) {
@@ -15414,32 +15160,43 @@
 
                 if (!isCheckinRequest && mi != null) {
                     totalPss += myTotalPss;
+                    totalSwapPss += myTotalSwapPss;
                     MemItem pssItem = new MemItem(r.processName + " (pid " + pid +
-                            (hasActivities ? " / activities)" : ")"),
-                            r.processName, myTotalPss, pid, hasActivities);
+                            (hasActivities ? " / activities)" : ")"), r.processName, myTotalPss,
+                            myTotalSwapPss, pid, hasActivities);
                     procMems.add(pssItem);
                     procMemsMap.put(pid, pssItem);
 
                     nativePss += mi.nativePss;
+                    nativeSwapPss += mi.nativeSwappedOutPss;
                     dalvikPss += mi.dalvikPss;
+                    dalvikSwapPss += mi.dalvikSwappedOutPss;
                     for (int j=0; j<dalvikSubitemPss.length; j++) {
                         dalvikSubitemPss[j] += mi.getOtherPss(Debug.MemoryInfo.NUM_OTHER_STATS + j);
+                        dalvikSubitemSwapPss[j] +=
+                                mi.getOtherSwappedOutPss(Debug.MemoryInfo.NUM_OTHER_STATS + j);
                     }
                     otherPss += mi.otherPss;
+                    otherSwapPss += mi.otherSwappedOutPss;
                     for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
                         long mem = mi.getOtherPss(j);
                         miscPss[j] += mem;
                         otherPss -= mem;
+                        mem = mi.getOtherSwappedOutPss(j);
+                        miscSwapPss[j] += mem;
+                        otherSwapPss -= mem;
                     }
 
                     if (oomAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
                         cachedPss += myTotalPss;
+                        cachedSwapPss += myTotalSwapPss;
                     }
 
                     for (int oomIndex=0; oomIndex<oomPss.length; oomIndex++) {
                         if (oomAdj <= DUMP_MEM_OOM_ADJ[oomIndex]
                                 || oomIndex == (oomPss.length-1)) {
                             oomPss[oomIndex] += myTotalPss;
+                            oomSwapPss[oomIndex] += myTotalSwapPss;
                             if (oomProcs[oomIndex] == null) {
                                 oomProcs[oomIndex] = new ArrayList<MemItem>();
                             }
@@ -15474,26 +15231,35 @@
                         }
 
                         final long myTotalPss = mi.getTotalPss();
+                        final long myTotalSwapPss = mi.getTotalSwappedOutPss();
                         totalPss += myTotalPss;
                         nativeProcTotalPss += myTotalPss;
 
                         MemItem pssItem = new MemItem(st.name + " (pid " + st.pid + ")",
-                                st.name, myTotalPss, st.pid, false);
+                                st.name, myTotalPss, mi.getSummaryTotalSwapPss(), st.pid, false);
                         procMems.add(pssItem);
 
                         nativePss += mi.nativePss;
+                        nativeSwapPss += mi.nativeSwappedOutPss;
                         dalvikPss += mi.dalvikPss;
+                        dalvikSwapPss += mi.dalvikSwappedOutPss;
                         for (int j=0; j<dalvikSubitemPss.length; j++) {
-                            dalvikSubitemPss[j] += mi.getOtherPss(
-                                    Debug.MemoryInfo.NUM_OTHER_STATS + j);
+                            dalvikSubitemPss[j] += mi.getOtherPss(Debug.MemoryInfo.NUM_OTHER_STATS + j);
+                            dalvikSubitemSwapPss[j] +=
+                                    mi.getOtherSwappedOutPss(Debug.MemoryInfo.NUM_OTHER_STATS + j);
                         }
                         otherPss += mi.otherPss;
+                        otherSwapPss += mi.otherSwappedOutPss;
                         for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
                             long mem = mi.getOtherPss(j);
                             miscPss[j] += mem;
                             otherPss -= mem;
+                            mem = mi.getOtherSwappedOutPss(j);
+                            miscSwapPss[j] += mem;
+                            otherSwapPss -= mem;
                         }
                         oomPss[0] += myTotalPss;
+                        oomSwapPss[0] += myTotalSwapPss;
                         if (oomProcs[0] == null) {
                             oomProcs[0] = new ArrayList<MemItem>();
                         }
@@ -15504,21 +15270,23 @@
 
             ArrayList<MemItem> catMems = new ArrayList<MemItem>();
 
-            catMems.add(new MemItem("Native", "Native", nativePss, -1));
-            final MemItem dalvikItem = new MemItem("Dalvik", "Dalvik", dalvikPss, -2);
+            catMems.add(new MemItem("Native", "Native", nativePss, nativeSwapPss, -1));
+            final MemItem dalvikItem =
+                    new MemItem("Dalvik", "Dalvik", dalvikPss, dalvikSwapPss, -2);
             if (dalvikSubitemPss.length > 0) {
                 dalvikItem.subitems = new ArrayList<MemItem>();
                 for (int j=0; j<dalvikSubitemPss.length; j++) {
                     final String name = Debug.MemoryInfo.getOtherLabel(
                             Debug.MemoryInfo.NUM_OTHER_STATS + j);
-                    dalvikItem.subitems.add(new MemItem(name, name, dalvikSubitemPss[j], j));
+                    dalvikItem.subitems.add(new MemItem(name, name, dalvikSubitemPss[j],
+                                    dalvikSubitemSwapPss[j], j));
                 }
             }
             catMems.add(dalvikItem);
-            catMems.add(new MemItem("Unknown", "Unknown", otherPss, -3));
+            catMems.add(new MemItem("Unknown", "Unknown", otherPss, otherSwapPss, -3));
             for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
                 String label = Debug.MemoryInfo.getOtherLabel(j);
-                catMems.add(new MemItem(label, label, miscPss[j], j));
+                catMems.add(new MemItem(label, label, miscPss[j], miscSwapPss[j], j));
             }
 
             ArrayList<MemItem> oomMems = new ArrayList<MemItem>();
@@ -15526,30 +15294,31 @@
                 if (oomPss[j] != 0) {
                     String label = isCompact ? DUMP_MEM_OOM_COMPACT_LABEL[j]
                             : DUMP_MEM_OOM_LABEL[j];
-                    MemItem item = new MemItem(label, label, oomPss[j],
+                    MemItem item = new MemItem(label, label, oomPss[j], oomSwapPss[j],
                             DUMP_MEM_OOM_ADJ[j]);
                     item.subitems = oomProcs[j];
                     oomMems.add(item);
                 }
             }
 
+            dumpSwapPss = dumpSwapPss && hasSwapPss && totalSwapPss != 0;
             if (!brief && !oomOnly && !isCompact) {
                 pw.println();
                 pw.println("Total PSS by process:");
-                dumpMemItems(pw, "  ", "proc", procMems, true, isCompact);
+                dumpMemItems(pw, "  ", "proc", procMems, true, isCompact, dumpSwapPss);
                 pw.println();
             }
             if (!isCompact) {
                 pw.println("Total PSS by OOM adjustment:");
             }
-            dumpMemItems(pw, "  ", "oom", oomMems, false, isCompact);
+            dumpMemItems(pw, "  ", "oom", oomMems, false, isCompact, dumpSwapPss);
             if (!brief && !oomOnly) {
                 PrintWriter out = categoryPw != null ? categoryPw : pw;
                 if (!isCompact) {
                     out.println();
                     out.println("Total PSS by category:");
                 }
-                dumpMemItems(out, "  ", "cat", catMems, true, isCompact);
+                dumpMemItems(out, "  ", "cat", catMems, true, isCompact, dumpSwapPss);
             }
             if (!isCompact) {
                 pw.println();
@@ -15607,18 +15376,17 @@
                     pw.println(totalPss - cachedPss);
                 }
             }
+            long lostRAM = memInfo.getTotalSizeKb()
+                    - totalPss - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
+                    - memInfo.getKernelUsedSizeKb() - memInfo.getZramTotalSizeKb();
             if (!isCompact) {
                 pw.print(" Used RAM: "); pw.print(stringifyKBSize(totalPss - cachedPss
                         + memInfo.getKernelUsedSizeKb())); pw.print(" (");
                 pw.print(stringifyKBSize(totalPss - cachedPss)); pw.print(" used pss + ");
                 pw.print(stringifyKBSize(memInfo.getKernelUsedSizeKb())); pw.print(" kernel)\n");
-                pw.print(" Lost RAM: "); pw.println(stringifyKBSize(memInfo.getTotalSizeKb()
-                        - totalPss - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
-                        - memInfo.getKernelUsedSizeKb()));
+                pw.print(" Lost RAM: "); pw.println(stringifyKBSize(lostRAM));
             } else {
-                pw.print("lostram,"); pw.println(memInfo.getTotalSizeKb()
-                        - totalPss - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
-                        - memInfo.getKernelUsedSizeKb());
+                pw.print("lostram,"); pw.println(lostRAM);
             }
             if (!brief) {
                 if (memInfo.getZramTotalSizeKb() != 0) {
@@ -15916,7 +15684,7 @@
         memInfoBuilder.append("  Lost RAM: ");
         memInfoBuilder.append(stringifyKBSize(memInfo.getTotalSizeKb()
                 - totalPss - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
-                - memInfo.getKernelUsedSizeKb()));
+                - memInfo.getKernelUsedSizeKb() - memInfo.getZramTotalSizeKb()));
         memInfoBuilder.append("\n");
         Slog.i(TAG, "Low on memory:");
         Slog.i(TAG, shortNativeBuilder.toString());
@@ -16878,6 +16646,9 @@
 
     private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType,
             int callingUid, int[] users) {
+        // TODO: come back and remove this assumption to triage all broadcasts
+        int pmFlags = STOCK_PM_FLAGS | MATCH_DEBUG_TRIAGED_MISSING;
+
         List<ResolveInfo> receivers = null;
         try {
             HashSet<ComponentName> singleUserReceivers = null;
@@ -16890,7 +16661,7 @@
                     continue;
                 }
                 List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
-                        .queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS, user);
+                        .queryIntentReceivers(intent, resolvedType, pmFlags, user);
                 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.
@@ -17014,6 +16785,8 @@
             }
         }
 
+        // Verify that protected broadcasts are only being sent by system code,
+        // and that system code is only sending protected broadcasts.
         final String action = intent.getAction();
         final boolean isProtectedBroadcast;
         try {
@@ -17023,35 +16796,47 @@
             return ActivityManager.BROADCAST_SUCCESS;
         }
 
-        /*
-         * Prevent non-system code (defined here to be non-persistent
-         * processes) from sending protected broadcasts.
-         */
-        int callingAppId = UserHandle.getAppId(callingUid);
-        if (callingAppId == Process.SYSTEM_UID || callingAppId == Process.PHONE_UID
-            || callingAppId == Process.SHELL_UID || callingAppId == Process.BLUETOOTH_UID
-            || callingAppId == Process.NFC_UID || callingUid == 0) {
-            // Always okay.
+        final boolean isCallerSystem;
+        switch (UserHandle.getAppId(callingUid)) {
+            case Process.ROOT_UID:
+            case Process.SYSTEM_UID:
+            case Process.PHONE_UID:
+            case Process.SHELL_UID:
+            case Process.BLUETOOTH_UID:
+            case Process.NFC_UID:
+                isCallerSystem = true;
+                break;
+            default:
+                isCallerSystem = (callerApp != null) && callerApp.persistent;
+                break;
+        }
 
-            // Yell if the system is trying to send a non-protected broadcast.
-            // The vast majority of broadcasts sent from system callers should
-            // be protected to avoid security holes, so exceptions here should
-            // be incredibly rare.
-            if (!isProtectedBroadcast
-                    && !Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
-                // TODO: eventually switch over to hard throw
+        if (isCallerSystem) {
+            if (isProtectedBroadcast
+                    || Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
+                    || Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)
+                    || AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
+                    || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
+                // Broadcast is either protected, or it's a public action that
+                // we've relaxed, so it's fine for system internals to send.
+            } else {
+                // The vast majority of broadcasts sent from system internals
+                // should be protected to avoid security holes, so yell loudly
+                // to ensure we examine these cases.
                 Log.wtf(TAG, "Sending non-protected broadcast " + action
                         + " from system", new Throwable());
             }
 
-        } else if (callerApp == null || !callerApp.persistent) {
+        } else {
             if (isProtectedBroadcast) {
                 String msg = "Permission Denial: not allowed to send broadcast "
                         + action + " from pid="
                         + callingPid + ", uid=" + callingUid;
                 Slog.w(TAG, msg);
                 throw new SecurityException(msg);
-            } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)) {
+
+            } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
+                    || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
                 // Special case for compatibility: we don't want apps to send this,
                 // but historically it has not been protected and apps may be using it
                 // to poke their own app widget.  So, instead of making it protected,
@@ -17087,6 +16872,8 @@
                 case Intent.ACTION_PACKAGE_CHANGED:
                 case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
                 case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
+                case Intent.ACTION_PACKAGES_SUSPENDED:
+                case Intent.ACTION_PACKAGES_UNSUSPENDED:
                     // Handle special intents: if this broadcast is from the package
                     // manager about a package being removed, we need to remove all of
                     // its activities from the history stack.
@@ -17167,6 +16954,20 @@
                                 }
                             }
                             break;
+                        case Intent.ACTION_PACKAGES_SUSPENDED:
+                        case Intent.ACTION_PACKAGES_UNSUSPENDED:
+                            final boolean suspended = Intent.ACTION_PACKAGES_SUSPENDED.equals(
+                                    intent.getAction());
+                            final String[] packageNames = intent.getStringArrayExtra(
+                                    Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                            final int userHandle = intent.getIntExtra(
+                                    Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+
+                            synchronized(ActivityManagerService.this) {
+                                mRecentTasks.onPackagesSuspendedChanged(
+                                        packageNames, suspended, userHandle);
+                            }
+                            break;
                     }
                     break;
                 case Intent.ACTION_PACKAGE_ADDED:
@@ -17632,6 +17433,11 @@
                         "Unable to find instrumentation target package: " + ii.targetPackage);
                 return false;
             }
+            if (!ai.hasCode()) {
+                reportStartInstrumentationFailure(watcher, className,
+                        "Instrumentation target has no code: " + ii.targetPackage);
+                return false;
+            }
 
             int match = mContext.getPackageManager().checkSignatures(
                     ii.targetPackage, ii.packageName);
@@ -17785,17 +17591,15 @@
 
     @Override
     public void suppressResizeConfigChanges(boolean suppress) throws RemoteException {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "suppressResizeConfigChanges()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "suppressResizeConfigChanges()");
         synchronized (this) {
             mSuppressResizeConfigChanges = suppress;
         }
     }
 
     @Override
-    public void moveTasksToFullscreenStack(int fromStackId) {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "moveTasksToFullscreenStack()");
+    public void moveTasksToFullscreenStack(int fromStackId, boolean onTop) {
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTasksToFullscreenStack()");
         if (fromStackId == HOME_STACK_ID) {
             throw new IllegalArgumentException("You can't move tasks from the home stack.");
         }
@@ -17804,9 +17608,18 @@
             final ActivityStack stack = mStackSupervisor.getStack(fromStackId);
             if (stack != null) {
                 final ArrayList<TaskRecord> tasks = stack.getAllTasks();
-                for (int i = tasks.size() - 1; i >= 0; i--) {
-                    mStackSupervisor.positionTaskInStackLocked(tasks.get(i).taskId,
-                            FULLSCREEN_WORKSPACE_STACK_ID, 0);
+                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);
+                    }
+                } else {
+                    for (int i = size - 1; i >= 0; i--) {
+                        mStackSupervisor.positionTaskInStackLocked(tasks.get(i).taskId,
+                                FULLSCREEN_WORKSPACE_STACK_ID, 0);
+                    }
                 }
             }
             Binder.restoreCallingIdentity(origId);
@@ -17831,6 +17644,20 @@
         }
     }
 
+    private void updateFontScaleIfNeeded() {
+        final int currentUserId;
+        synchronized(this) {
+            currentUserId = mUserController.getCurrentUserIdLocked();
+        }
+        final float scaleFactor = Settings.System.getFloatForUser(mContext.getContentResolver(),
+                FONT_SCALE, 1.0f, currentUserId);
+        if (mConfiguration.fontScale != scaleFactor) {
+            final Configuration configuration = mWindowManager.computeNewConfiguration();
+            configuration.fontScale = scaleFactor;
+            updatePersistentConfiguration(configuration);
+        }
+    }
+
     private void enforceWriteSettingsPermission(String func) {
         int uid = Binder.getCallingUid();
         if (uid == Process.ROOT_UID) {
@@ -17914,10 +17741,18 @@
                 EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
 
                 if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {
-                    if (mSupportedSystemLocales == null) {
-                        mSupportedSystemLocales = Resources.getSystem().getAssets().getLocales();
+                    final Locale locale;
+                    if (values.getLocales().size() == 1) {
+                        // This is an optimization to avoid the JNI call when the result of
+                        // getFirstMatch() does not depend on the supported locales.
+                        locale = values.getLocales().getPrimary();
+                    } else {
+                        if (mSupportedSystemLocales == null) {
+                            mSupportedSystemLocales =
+                                    Resources.getSystem().getAssets().getLocales();
+                        }
+                        locale = values.getLocales().getFirstMatch(mSupportedSystemLocales);
                     }
-                    final Locale locale = values.getLocales().getFirstMatch(mSupportedSystemLocales);
                     SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
                     mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG,
                             locale));
@@ -17938,7 +17773,7 @@
 
                 // TODO: If our config changes, should we auto dismiss any currently
                 // showing dialogs?
-                mShowDialogs = shouldShowDialogs(newConfig);
+                mShowDialogs = shouldShowDialogs(newConfig, mInVrMode);
 
                 AttributeCache ac = AttributeCache.instance();
                 if (ac != null) {
@@ -18027,10 +17862,13 @@
      * A thought: SystemUI might also want to get told about this, the Power
      * dialog / global actions also might want different behaviors.
      */
-    private static final boolean shouldShowDialogs(Configuration config) {
-        return !(config.keyboard == Configuration.KEYBOARD_NOKEYS
-                && config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH
-                && config.navigation == Configuration.NAVIGATION_NONAV);
+    private static final boolean shouldShowDialogs(Configuration config, boolean inVrMode) {
+        final boolean inputMethodExists = !(config.keyboard == Configuration.KEYBOARD_NOKEYS
+                                   && config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH
+                                   && config.navigation == Configuration.NAVIGATION_NONAV);
+        final boolean uiIsNotCarType = !((config.uiMode & Configuration.UI_MODE_TYPE_MASK)
+                                    == Configuration.UI_MODE_TYPE_CAR);
+        return inputMethodExists && uiIsNotCarType && !inVrMode;
     }
 
     @Override
@@ -18842,8 +18680,10 @@
     /**
      * Record new PSS sample for a process.
      */
-    void recordPssSampleLocked(ProcessRecord proc, int procState, long pss, long uss, long now) {
-        EventLogTags.writeAmPss(proc.pid, proc.uid, proc.processName, pss * 1024, uss * 1024);
+    void recordPssSampleLocked(ProcessRecord proc, int procState, long pss, long uss, long swapPss,
+            long now) {
+        EventLogTags.writeAmPss(proc.pid, proc.uid, proc.processName, pss * 1024, uss * 1024,
+                swapPss * 1024);
         proc.lastPssTime = now;
         proc.baseProcessTracker.addPss(pss, uss, true, proc.pkgList);
         if (DEBUG_PSS) Slog.d(TAG_PSS,
@@ -18853,8 +18693,10 @@
             proc.initialIdlePss = pss;
         }
         proc.lastPss = pss;
+        proc.lastSwapPss = swapPss;
         if (procState >= ActivityManager.PROCESS_STATE_HOME) {
             proc.lastCachedPss = pss;
+            proc.lastCachedSwapPss = swapPss;
         }
 
         final SparseArray<Pair<Long, String>> watchUids
@@ -19290,7 +19132,7 @@
                 // states, which well tend to give noisy data.
                 long start = SystemClock.uptimeMillis();
                 long pss = Debug.getPss(app.pid, mTmpLong, null);
-                recordPssSampleLocked(app, app.curProcState, pss, mTmpLong[0], now);
+                recordPssSampleLocked(app, app.curProcState, pss, mTmpLong[0], mTmpLong[1], now);
                 mPendingPssProcesses.remove(app);
                 Slog.i(TAG, "Recorded pss for " + app + " state " + app.setProcState
                         + " to " + app.curProcState + ": "
@@ -20442,10 +20284,6 @@
         return mUserController.stopUser(userId, force, callback);
     }
 
-    void onUserRemovedLocked(int userId) {
-        mRecentTasks.removeTasksForUserLocked(userId);
-    }
-
     @Override
     public UserInfo getCurrentUser() {
         return mUserController.getCurrentUser();
@@ -20500,6 +20338,12 @@
         return newInfo;
     }
 
+    public boolean isUserStopped(int userId) {
+        synchronized (this) {
+            return mUserController.getStartedUserStateLocked(userId) == null;
+        }
+    }
+
     ActivityInfo getActivityInfoForUser(ActivityInfo aInfo, int userId) {
         if (aInfo == null
                 || (userId < 1 && aInfo.applicationInfo.uid < UserHandle.PER_USER_RANGE)) {
@@ -20609,13 +20453,6 @@
         }
     }
 
-    void stopReportingCrashesLocked(ProcessRecord proc) {
-        if (mAppsNotReportingCrashes == null) {
-            mAppsNotReportingCrashes = new ArraySet<>();
-        }
-        mAppsNotReportingCrashes.add(proc.info.packageName);
-    }
-
     private final class LocalService extends ActivityManagerInternal {
         @Override
         public void onWakefulnessChanged(int wakefulness) {
@@ -20652,7 +20489,16 @@
         @Override
         public void onUserRemoved(int userId) {
             synchronized (ActivityManagerService.this) {
-                ActivityManagerService.this.onUserRemovedLocked(userId);
+                ActivityManagerService.this.onUserStoppedLocked(userId);
+            }
+        }
+
+        @Override
+        public void onLocalVoiceInteractionStarted(IBinder activity,
+                IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {
+            synchronized (ActivityManagerService.this) {
+                ActivityManagerService.this.onLocalVoiceInteractionStartedLocked(activity,
+                        voiceSession, voiceInteractor);
             }
         }
     }
@@ -20741,7 +20587,12 @@
         public void moveToFront() {
             checkCaller();
             // Will bring task to front if it already has a root activity.
-            startActivityFromRecentsInner(mTaskId, INVALID_STACK_ID, null);
+            final long origId = Binder.clearCallingIdentity();
+            try {
+                startActivityFromRecentsInner(mTaskId, null);
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
         }
 
         @Override
@@ -20762,7 +20613,7 @@
                     throw new IllegalArgumentException("Bad app thread " + appThread);
                 }
             }
-            return mStackSupervisor.startActivityMayWait(appThread, -1, callingPackage, intent,
+            return mActivityStarter.startActivityMayWait(appThread, -1, callingPackage, intent,
                     resolvedType, null, null, null, null, 0, 0, null, null,
                     null, bOptions, false, callingUser, null, tr);
         }
@@ -20799,23 +20650,25 @@
     public void killPackageDependents(String packageName, int userId) {
         enforceCallingPermission(android.Manifest.permission.KILL_UID, "killPackageDependents()");
         if (packageName == null) {
-            throw new NullPointerException("Cannot kill the dependents of a package without its name.");
+            throw new NullPointerException(
+                    "Cannot kill the dependents of a package without its name.");
         }
 
         long callingId = Binder.clearCallingIdentity();
         IPackageManager pm = AppGlobals.getPackageManager();
         int pkgUid = -1;
         try {
-            pkgUid = pm.getPackageUid(packageName, userId);
+            pkgUid = pm.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, userId);
         } catch (RemoteException e) {
         }
         if (pkgUid == -1) {
-            throw new IllegalArgumentException("Cannot kill dependents of non-existing package " + packageName);
+            throw new IllegalArgumentException(
+                    "Cannot kill dependents of non-existing package " + packageName);
         }
         try {
             synchronized(this) {
                 killPackageProcessesLocked(packageName, UserHandle.getAppId(pkgUid), userId,
-                        ProcessList.FOREGROUND_APP_ADJ, false, true, true, false, false,
+                        ProcessList.FOREGROUND_APP_ADJ, false, true, true, false,
                         "dep: " + packageName);
             }
         } finally {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 13c1417..8c99739 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -21,6 +21,8 @@
 import android.os.ShellCommand;
 import android.os.UserHandle;
 
+import com.android.internal.util.ArrayUtils;
+
 import java.io.PrintWriter;
 
 class ActivityManagerShellCommand extends ShellCommand {
@@ -58,6 +60,8 @@
                     return runTrackAssociations(pw);
                 case "untrack-associations":
                     return runUntrackAssociations(pw);
+                case "is-user-stopped":
+                    return runIsUserStopped(pw);
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -67,6 +71,13 @@
         return -1;
     }
 
+    int runIsUserStopped(PrintWriter pw) {
+        int userId = UserHandle.parseUserArg(getNextArgRequired());
+        boolean stopped = mInternal.isUserStopped(userId);
+        pw.println(stopped);
+        return 0;
+    }
+
     int runForceStop(PrintWriter pw) throws RemoteException {
         int userId = UserHandle.USER_ALL;
 
@@ -107,7 +118,7 @@
     int runWrite(PrintWriter pw) {
         mInternal.enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
                 "registerUidObserver()");
-        mInternal.mTaskPersister.flush();
+        mInternal.mRecentTasks.flush();
         pw.println("All tasks persisted.");
         return 0;
     }
@@ -190,6 +201,8 @@
             pw.println("    Enable association tracking.");
             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");
         }
     }
 }
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 64f423c..ffb2fc4 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -4,6 +4,8 @@
 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 com.android.server.am.ActivityStack.STACK_INVISIBLE;
 
 import android.app.ActivityManager.StackId;
 import android.content.Context;
@@ -25,7 +27,7 @@
     // 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 = {
-            "tron_varz_window_time_0", "tron_varz_window_time_1", "tron_varz_window_time_2"};
+            "window_time_0", "window_time_1", "window_time_2"};
 
     private int mWindowState = WINDOW_STATE_STANDARD;
     private long mLastLogTimeSecs;
@@ -49,24 +51,26 @@
         }
         mLastLogTimeSecs = now;
 
-        mWindowState = WINDOW_STATE_INVALID;
         ActivityStack stack = mSupervisor.getStack(DOCKED_STACK_ID);
-        if (stack != null && stack.isStackVisibleLocked()) {
+        if (stack != null && stack.getStackVisibilityLocked() != STACK_INVISIBLE) {
             mWindowState = WINDOW_STATE_SIDE_BY_SIDE;
+            return;
         }
-        if (mWindowState == WINDOW_STATE_INVALID) {
-            stack = mSupervisor.getFocusedStack();
-            if (stack.mStackId == HOME_STACK_ID
-                    || stack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
-                mWindowState = WINDOW_STATE_STANDARD;
-            } else if (stack.mStackId == DOCKED_STACK_ID) {
-                throw new IllegalStateException("Docked stack shouldn't be the focused stack, "
-                        + "because it reported not being visible.");
-            } else if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
-                mWindowState = WINDOW_STATE_FREEFORM;
-            } else if (StackId.isStaticStack(stack.mStackId)) {
-                throw new IllegalStateException("Unknown stack=" + stack);
-            }
+        mWindowState = WINDOW_STATE_INVALID;
+        stack = mSupervisor.getFocusedStack();
+        if (stack.mStackId == PINNED_STACK_ID) {
+            stack = mSupervisor.findStackBehind(stack);
+        }
+        if (stack.mStackId == HOME_STACK_ID
+                || stack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
+            mWindowState = WINDOW_STATE_STANDARD;
+        } else if (stack.mStackId == DOCKED_STACK_ID) {
+            throw new IllegalStateException("Docked stack shouldn't be the focused stack, "
+                    + "because it reported not being visible.");
+        } else if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
+            mWindowState = WINDOW_STATE_FREEFORM;
+        } else if (StackId.isStaticStack(stack.mStackId)) {
+            throw new IllegalStateException("Unknown stack=" + stack);
         }
     }
 }
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index d215fc6..d1fcd3b 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -16,22 +16,26 @@
 
 package com.android.server.am;
 
-import static com.android.server.am.ActivityManagerDebugConfig.*;
+import static android.app.ActivityManager.StackId;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+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;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_THUMBNAILS;
+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.TaskRecord.INVALID_TASK_ID;
 
 import android.app.ActivityManager.TaskDescription;
-import android.app.PendingIntent;
-import android.os.PersistableBundle;
-import android.os.Trace;
-
-import com.android.internal.app.ResolverActivity;
-import com.android.internal.content.ReferrerIntent;
-import com.android.internal.util.XmlUtils;
-import com.android.server.AttributeCache;
-import com.android.server.am.ActivityStack.ActivityState;
-import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
-
 import android.app.ActivityOptions;
+import android.app.PendingIntent;
 import android.app.ResultInfo;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -45,10 +49,13 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Message;
+import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.Trace;
 import android.os.UserHandle;
+import android.service.voice.IVoiceInteractionSession;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
@@ -57,9 +64,12 @@
 import android.view.IApplicationToken;
 import android.view.WindowManager;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
+import com.android.internal.app.ResolverActivity;
+import com.android.internal.content.ReferrerIntent;
+import com.android.internal.util.XmlUtils;
+import com.android.server.AttributeCache;
+import com.android.server.am.ActivityStack.ActivityState;
+import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
 
 import java.io.File;
 import java.io.IOException;
@@ -69,6 +79,10 @@
 import java.util.HashSet;
 import java.util.Objects;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
 /**
  * An entry in the history stack, representing an activity.
  */
@@ -159,7 +173,9 @@
     boolean stopped;        // is activity pause finished?
     boolean delayedResume;  // not yet resumed because of stopped app switches?
     boolean finishing;      // activity in pending finish list?
-    boolean configDestroy;  // need to destroy due to config change?
+    boolean deferRelaunchUntilPaused;   // relaunch of activity is being deferred until pause is
+                                        // completed
+    boolean preserveWindowOnDeferredRelaunch; // activity windows are preserved on deferred relaunch
     int configChangeFlags;  // which config values have changed
     boolean keysPaused;     // has key dispatching been paused for it?
     int launchMode;         // the launch mode activity attribute.
@@ -172,8 +188,9 @@
     boolean immersive;      // immersive mode (don't interrupt if possible)
     boolean forceNewConfig; // force re-create with new config next time
     int launchCount;        // count of launches since last state
-    long lastLaunchTime;    // time of last lauch of this activity
-    ArrayList<ActivityContainer> mChildContainers = new ArrayList<ActivityContainer>();
+    long lastLaunchTime;    // time of last launch of this activity
+    boolean isVrActivity;   // is the activity running in VR mode?
+    ArrayList<ActivityContainer> mChildContainers = new ArrayList<>();
 
     String stringName;      // for caching of toString().
 
@@ -194,6 +211,9 @@
     private int[] mHorizontalSizeConfigurations;
     private int[] mSmallestSizeConfigurations;
 
+    boolean pendingVoiceInteractionStart;   // Waiting for activity-invoked voice session
+    IVoiceInteractionSession voiceSession;  // Voice interaction session for this activity
+
     void dump(PrintWriter pw, String prefix) {
         final long now = SystemClock.uptimeMillis();
         pw.print(prefix); pw.print("packageName="); pw.print(packageName);
@@ -309,6 +329,7 @@
                 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 (displayStartTime != 0 || startTime != 0) {
             pw.print(prefix); pw.print("displayStartTime=");
                     if (displayStartTime == 0) pw.print("0");
@@ -327,14 +348,17 @@
                     else TimeUtils.formatDuration(lastVisibleTime, now, pw);
                     pw.println();
         }
-        if (configDestroy || configChangeFlags != 0) {
-            pw.print(prefix); pw.print("configDestroy="); pw.print(configDestroy);
+        if (deferRelaunchUntilPaused || configChangeFlags != 0) {
+            pw.print(prefix); pw.print("deferRelaunchUntilPaused="); pw.print(deferRelaunchUntilPaused);
                     pw.print(" configChangeFlags=");
                     pw.println(Integer.toHexString(configChangeFlags));
         }
         if (connections != null) {
             pw.print(prefix); pw.print("connections="); pw.println(connections);
         }
+        if (info != null) {
+            pw.println(prefix + "resizeMode=" + ActivityInfo.resizeModeToString(info.resizeMode));
+        }
     }
 
     public boolean crossesHorizontalSizeThreshold(int firstDp, int secondDp) {
@@ -398,6 +422,11 @@
         }
     }
 
+    boolean isFreeform() {
+        return task != null && task.stack != null
+                && task.stack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
+    }
+
     static class Token extends IApplicationToken.Stub {
         private final WeakReference<ActivityRecord> weakActivity;
         private final ActivityManagerService mService;
@@ -532,7 +561,7 @@
         stopped = false;
         delayedResume = false;
         finishing = false;
-        configDestroy = false;
+        deferRelaunchUntilPaused = false;
         keysPaused = false;
         inHistory = false;
         visible = false;
@@ -637,6 +666,7 @@
             }
 
             immersive = (aInfo.flags & ActivityInfo.FLAG_IMMERSIVE) != 0;
+            isVrActivity = (aInfo.flags & ActivityInfo.FLAG_ENABLE_VR_MODE) != 0;
         } else {
             realActivity = null;
             taskAffinity = null;
@@ -648,6 +678,7 @@
             noDisplay = false;
             mActivityType = APPLICATION_ACTIVITY_TYPE;
             immersive = false;
+            isVrActivity = false;
         }
     }
 
@@ -722,6 +753,27 @@
                         (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0);
     }
 
+    boolean isFocusable() {
+        return StackId.canReceiveKeys(task.stack.mStackId) || isAlwaysFocusable();
+    }
+
+    boolean isResizeable() {
+        return !isHomeActivity() && (info.resizeMode == RESIZE_MODE_RESIZEABLE
+                || info.resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE);
+    }
+
+    boolean supportsPictureInPicture() {
+        return !isHomeActivity() && info.resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
+    }
+
+    boolean cropAppWindows() {
+        return !isHomeActivity() && info.resizeMode == RESIZE_MODE_CROP_WINDOWS;
+    }
+
+    boolean isAlwaysFocusable() {
+        return (info.flags & FLAG_ALWAYS_FOCUSABLE) != 0;
+    }
+
     void makeFinishingLocked() {
         if (!finishing) {
             if (task != null && task.stack != null
@@ -1229,12 +1281,22 @@
             final String iconFilename = createImageFilename(createTime, task.taskId);
             final File iconFile = new File(TaskPersister.getUserImagesDir(userId), iconFilename);
             final String iconFilePath = iconFile.getAbsolutePath();
-            mStackSupervisor.mService.mTaskPersister.saveImage(icon, iconFilePath);
+            service.mRecentTasks.saveImage(icon, iconFilePath);
             _taskDescription.setIconFilename(iconFilePath);
         }
         taskDescription = _taskDescription;
     }
 
+    void setVoiceSessionLocked(IVoiceInteractionSession session) {
+        voiceSession = session;
+        pendingVoiceInteractionStart = false;
+    }
+
+    void clearVoiceSessionLocked() {
+        voiceSession = null;
+        pendingVoiceInteractionStart = false;
+    }
+
     void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
         out.attribute(null, ATTR_ID, String.valueOf(createTime));
         out.attribute(null, ATTR_LAUNCHEDFROMUID, String.valueOf(launchedFromUid));
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index bfd17b2..3e99558 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -21,13 +21,19 @@
 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.content.pm.ActivityInfo.CONFIG_ORIENTATION;
+import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
+import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
+import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
 
+import static android.content.res.Configuration.SCREENLAYOUT_UNDEFINED;
 import static com.android.server.am.ActivityManagerDebugConfig.*;
 import static com.android.server.am.ActivityManagerService.LOCK_SCREEN_SHOWN;
 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.ActivityStackSupervisor.FindTaskResult;
 import static com.android.server.am.ActivityStackSupervisor.MOVING;
 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
 
@@ -74,7 +80,6 @@
 import android.os.UserHandle;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.EventLog;
-import android.util.Log;
 import android.util.Slog;
 import android.view.Display;
 
@@ -161,6 +166,14 @@
         DESTROYED
     }
 
+    // Stack is not considered visible.
+    static final int STACK_INVISIBLE = 0;
+    // Stack is considered visible
+    static final int STACK_VISIBLE = 1;
+    // Stack is considered visible, but only becuase it has activity that is visible behind other
+    // activities and there is a specific combination of stacks.
+    static final int STACK_VISIBLE_ACTIVITY_BEHIND = 2;
+
     final ActivityManagerService mService;
     final WindowManagerService mWindowManager;
     private final RecentTasks mRecentTasks;
@@ -519,6 +532,14 @@
         return mStackId == HOME_STACK_ID;
     }
 
+    final boolean isDockedStack() {
+        return mStackId == DOCKED_STACK_ID;
+    }
+
+    final boolean isPinnedStack() {
+        return mStackId == PINNED_STACK_ID;
+    }
+
     final boolean isOnHomeDisplay() {
         return isAttached() &&
                 mActivityContainer.mActivityDisplay.mDisplayId == Display.DEFAULT_DISPLAY;
@@ -552,7 +573,7 @@
 
         // TODO(multi-display): Needs to also work if focus is moving to the non-home display.
         if (isOnHomeDisplay()) {
-            mStackSupervisor.setFocusStack(reason, this);
+            mStackSupervisor.setFocusStackUnchecked(reason, this);
         }
         if (task != null) {
             insertTaskAtTop(task, null);
@@ -564,15 +585,25 @@
         }
     }
 
+    boolean isFocusable() {
+        if (StackId.canReceiveKeys(mStackId)) {
+            return true;
+        }
+        // The stack isn't focusable. See if its top activity is focusable to force focus on the
+        // stack.
+        final ActivityRecord r = topRunningActivityLocked();
+        return r != null && r.isFocusable();
+    }
+
     final boolean isAttached() {
         return mStacks != null;
     }
 
     /**
-     * Returns the top activity in any existing task matching the given
-     * Intent.  Returns null if no such task is found.
+     * Returns the top activity in any existing task matching the given Intent in the input result.
+     * Returns null if no such task is found.
      */
-    ActivityRecord findTaskLocked(ActivityRecord target) {
+    void findTaskLocked(ActivityRecord target, FindTaskResult result) {
         Intent intent = target.intent;
         ActivityInfo info = target.info;
         ComponentName cls = intent.getComponent();
@@ -627,10 +658,15 @@
                     + taskIntent.getComponent().flattenToShortString()
                     + "/aff=" + r.task.rootAffinity + " to new cls="
                     + intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
-            if (!isDocument && !taskIsDocument && task.rootAffinity != null) {
+            if (!isDocument && !taskIsDocument
+                    && result.r == null && task.canMatchRootAffinity()) {
                 if (task.rootAffinity.equals(target.taskAffinity)) {
-                    if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity!");
-                    return r;
+                    if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity candidate!");
+                    // It is possible for multiple tasks to have the same root affinity especially
+                    // if they are in separate stacks. We save off this candidate, but keep looking
+                    // to see if there is a better candidate.
+                    result.r = r;
+                    result.matchedByRootAffinity = true;
                 }
             } else if (taskIntent != null && taskIntent.getComponent() != null &&
                     taskIntent.getComponent().compareTo(cls) == 0 &&
@@ -639,7 +675,9 @@
                 //dump();
                 if (DEBUG_TASKS) Slog.d(TAG_TASKS,
                         "For Intent " + intent + " bringing to top: " + r.intent);
-                return r;
+                result.r = r;
+                result.matchedByRootAffinity = false;
+                break;
             } else if (affinityIntent != null && affinityIntent.getComponent() != null &&
                     affinityIntent.getComponent().compareTo(cls) == 0 &&
                     Objects.equals(documentData, taskDocumentData)) {
@@ -647,11 +685,11 @@
                 //dump();
                 if (DEBUG_TASKS) Slog.d(TAG_TASKS,
                         "For Intent " + intent + " bringing to top: " + r.intent);
-                return r;
+                result.r = r;
+                result.matchedByRootAffinity = false;
+                break;
             } else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
         }
-
-        return null;
     }
 
     /**
@@ -813,10 +851,9 @@
 
         if (hasVisibleBehindActivity()) {
             // Stop visible behind activity before going to sleep.
-            final ActivityRecord r = mActivityContainer.mActivityDisplay.mVisibleBehindActivity;
+            final ActivityRecord r = getVisibleBehindActivity();
             mStackSupervisor.mStoppingActivities.add(r);
-            if (DEBUG_STATES) Slog.v(TAG_STATES,
-                    "Sleep still waiting to stop visible behind " + r);
+            if (DEBUG_STATES) Slog.v(TAG_STATES, "Sleep still waiting to stop visible behind " + r);
             return true;
         }
 
@@ -903,7 +940,7 @@
         if (prev == null) {
             if (!resuming) {
                 Slog.wtf(TAG, "Trying to pause when nothing is resumed");
-                mStackSupervisor.resumeTopActivitiesLocked();
+                mStackSupervisor.resumeFocusedStackTopActivityLocked();
             }
             return false;
         }
@@ -994,7 +1031,7 @@
             // pause, so just treat it as being paused now.
             if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Activity not running, resuming next.");
             if (!resuming) {
-                mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null);
+                mStackSupervisor.resumeFocusedStackTopActivityLocked();
             }
             return false;
         }
@@ -1053,15 +1090,15 @@
             mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
             r.stopped = true;
             r.state = ActivityState.STOPPED;
-            if (mActivityContainer.mActivityDisplay.mVisibleBehindActivity == r) {
+            if (getVisibleBehindActivity() == r) {
                 mStackSupervisor.requestVisibleBehindLocked(r, false);
             }
             if (r.finishing) {
                 r.clearOptionsLocked();
             } else {
-                if (r.configDestroy) {
+                if (r.deferRelaunchUntilPaused) {
                     destroyActivityLocked(r, true, "stop-config");
-                    mStackSupervisor.resumeTopActivitiesLocked();
+                    mStackSupervisor.resumeFocusedStackTopActivityLocked();
                 } else {
                     mStackSupervisor.updatePreviousProcessLocked(r);
                 }
@@ -1085,14 +1122,11 @@
                     if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(TAG_PAUSE,
                             "Complete pause, no longer waiting: " + prev);
                 }
-                if (prev.configDestroy) {
-                    // The previous is being paused because the configuration
-                    // is changing, which means it is actually stopping...
-                    // To juggle the fact that we are also starting a new
-                    // instance right now, we need to first completely stop
-                    // the current instance before starting the new one.
-                    if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Destroying after pause: " + prev);
-                    destroyActivityLocked(prev, true, "pause-config");
+                if (prev.deferRelaunchUntilPaused) {
+                    // Complete the deferred relaunch that was waiting for pause to complete.
+                    if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Re-launching after pause: " + prev);
+                    relaunchActivityLocked(prev, prev.configChangeFlags, false,
+                            prev.preserveWindowOnDeferredRelaunch);
                 } else if (wasStopping) {
                     // We are also stopping, the stop request must have gone soon after the pause.
                     // We can't clobber it, because the stop confirmation will not be handled.
@@ -1117,17 +1151,16 @@
         if (resumeNext) {
             final ActivityStack topStack = mStackSupervisor.getFocusedStack();
             if (!mService.isSleepingOrShuttingDown()) {
-                mStackSupervisor.resumeTopActivitiesLocked(topStack, prev, null);
+                mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
             } else {
                 mStackSupervisor.checkReadyForSleepLocked();
                 ActivityRecord top = topStack.topRunningActivityLocked();
                 if (top == null || (prev != null && top != prev)) {
-                    // If there are no more activities available to run,
-                    // do resume anyway to start something.  Also if the top
-                    // activity on the stack is not the just paused activity,
-                    // we need to go ahead and resume it to ensure we complete
-                    // an in-flight app switch.
-                    mStackSupervisor.resumeTopActivitiesLocked(topStack, null, null);
+                    // If there are no more activities available to run, do resume anyway to start
+                    // something. Also if the top activity on the stack is not the just paused
+                    // activity, we need to go ahead and resume it to ensure we complete an
+                    // in-flight app switch.
+                    mStackSupervisor.resumeFocusedStackTopActivityLocked();
                 }
             }
         }
@@ -1154,8 +1187,12 @@
             prev.cpuTimeAtResume = 0; // reset it
         }
 
-        // Notfiy when the task stack has changed
-        mService.notifyTaskStackChangedLocked();
+        // Notify when the task stack has changed, but only if visibilities changed (not just
+        // focus).
+        if (mStackSupervisor.mAppVisibilitiesChangedSinceLastPause) {
+            mService.notifyTaskStackChangedLocked();
+            mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = false;
+        }
     }
 
     private void addToStopping(ActivityRecord r) {
@@ -1214,9 +1251,9 @@
 
         next.returningOptions = null;
 
-        if (mActivityContainer.mActivityDisplay.mVisibleBehindActivity == next) {
+        if (getVisibleBehindActivity() == next) {
             // When resuming an activity, require it to call requestVisibleBehind() again.
-            mActivityContainer.mActivityDisplay.setVisibleBehindActivity(null);
+            setVisibleBehindActivity(null);
         }
     }
 
@@ -1232,6 +1269,7 @@
             ActivityContainer container = containers.get(containerNdx);
             container.setVisible(visible);
         }
+        mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
     }
 
     // Find the first visible activity above the passed activity and if it is translucent return it
@@ -1282,7 +1320,7 @@
         return null;
     }
 
-    private ActivityStack getNextVisibleStackLocked() {
+    ActivityStack getNextFocusableStackLocked() {
         ArrayList<ActivityStack> stacks = mStacks;
         final ActivityRecord parent = mActivityContainer.mParentActivity;
         if (parent != null) {
@@ -1291,7 +1329,8 @@
         if (stacks != null) {
             for (int i = stacks.size() - 1; i >= 0; --i) {
                 ActivityStack stack = stacks.get(i);
-                if (stack != this && stack.isStackVisibleLocked()) {
+                if (stack != this && stack.isFocusable()
+                        && stack.getStackVisibilityLocked() != STACK_INVISIBLE) {
                     return stack;
                 }
             }
@@ -1333,14 +1372,17 @@
         return true;
     }
 
-    /** Returns true if the stack is considered visible. */
-    boolean isStackVisibleLocked() {
+    /**
+     * Returns stack's visibility: {@link #STACK_INVISIBLE}, {@link #STACK_VISIBLE} or
+     * {@link #STACK_VISIBLE_ACTIVITY_BEHIND}.
+     */
+    int getStackVisibilityLocked() {
         if (!isAttached()) {
-            return false;
+            return STACK_INVISIBLE;
         }
 
         if (mStackSupervisor.isFrontStack(this) || mStackSupervisor.isFocusedStack(this)) {
-            return true;
+            return STACK_VISIBLE;
         }
 
         final int stackIndex = mStacks.indexOf(this);
@@ -1348,32 +1390,31 @@
         if (stackIndex == mStacks.size() - 1) {
             Slog.wtf(TAG,
                     "Stack=" + this + " isn't front stack but is at the top of the stack list");
-            return false;
+            return STACK_INVISIBLE;
         }
 
         final boolean isLockscreenShown = mService.mLockScreenShown == LOCK_SCREEN_SHOWN;
         if (isLockscreenShown && !StackId.isAllowedOverLockscreen(mStackId)) {
-            return false;
+            return STACK_INVISIBLE;
         }
 
         final ActivityStack focusedStack = mStackSupervisor.getFocusedStack();
         final int focusedStackId = focusedStack.mStackId;
 
         if (mStackId == FULLSCREEN_WORKSPACE_STACK_ID
-                && hasVisibleBehindActivity() && focusedStackId == HOME_STACK_ID) {
+                && hasVisibleBehindActivity() && focusedStackId == HOME_STACK_ID
+                && !focusedStack.topActivity().fullscreen) {
             // The fullscreen stack should be visible if it has a visible behind activity behind
-            // the home stack that will be translucent.
-            return true;
+            // the home stack that is translucent.
+            return STACK_VISIBLE_ACTIVITY_BEHIND;
         }
 
         if (mStackId == DOCKED_STACK_ID) {
-            // Docked stack is always visible, except in the case where the home activity
-            // is the top running activity in the focused home stack.
-            if (focusedStackId != HOME_STACK_ID) {
-                return true;
-            }
-            ActivityRecord topHomeActivity = focusedStack.topRunningActivityLocked();
-            return topHomeActivity == null || !topHomeActivity.isHomeActivity();
+            // Docked stack is always visible, except in the case where the top running activity in
+            // the focus stack doesn't support any form of resizing.
+            final ActivityRecord r = focusedStack.topRunningActivityLocked();
+            return r == null || r.isResizeable() || r.cropAppWindows()
+                    ? STACK_VISIBLE : STACK_INVISIBLE;
         }
 
         // Find the first stack below focused stack that actually got something visible.
@@ -1385,7 +1426,7 @@
         if ((focusedStackId == DOCKED_STACK_ID || focusedStackId == PINNED_STACK_ID)
                 && stackIndex == belowFocusedIndex) {
             // Stacks directly behind the docked or pinned stack are always visible.
-            return true;
+            return STACK_VISIBLE;
         }
 
         if (focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID
@@ -1394,7 +1435,7 @@
             // visible so they can act as a backdrop to the translucent activity.
             // For example, dialog activities
             if (stackIndex == belowFocusedIndex) {
-                return true;
+                return STACK_VISIBLE;
             }
             if (belowFocusedIndex >= 0) {
                 final ActivityStack stack = mStacks.get(belowFocusedIndex);
@@ -1402,14 +1443,14 @@
                         && stackIndex == (belowFocusedIndex - 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 true;
+                    return STACK_VISIBLE;
                 }
             }
         }
 
         if (StackId.isStaticStack(mStackId)) {
             // Visibility of any static stack should have been determined by the conditions above.
-            return false;
+            return STACK_INVISIBLE;
         }
 
         for (int i = stackIndex + 1; i < mStacks.size(); i++) {
@@ -1421,15 +1462,15 @@
 
             if (!StackId.isDynamicStacksVisibleBehindAllowed(stack.mStackId)) {
                 // These stacks can't have any dynamic stacks visible behind them.
-                return false;
+                return STACK_INVISIBLE;
             }
 
             if (!hasTranslucentActivity(stack)) {
-                return false;
+                return STACK_INVISIBLE;
             }
         }
 
-        return true;
+        return STACK_VISIBLE;
     }
 
     final int rankTaskLayers(int baseLayer) {
@@ -1462,14 +1503,16 @@
         // 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 boolean stackInvisible = !isStackVisibleLocked();
+        final int stackVisibility = getStackVisibilityLocked();
+        final boolean stackInvisible = stackVisibility != STACK_VISIBLE;
+        final boolean stackVisibleBehind = stackVisibility == STACK_VISIBLE_ACTIVITY_BEHIND;
         boolean behindFullscreenActivity = stackInvisible;
-        boolean noStackActivityResumed = (isInStackLocked(starting) == null);
-
+        boolean resumeNextActivity = isFocusable() && (isInStackLocked(starting) == null);
+        boolean behindTranslucentActivity = false;
+        final ActivityRecord visibleBehind = getVisibleBehindActivity();
         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);
                 if (r.finishing) {
@@ -1482,11 +1525,13 @@
                 aboveTop = false;
                 // mLaunchingBehind: Activities launching behind are at the back of the task stack
                 // but must be drawn initially for the animation as though they were visible.
-                if ((!behindFullscreenActivity || r.mLaunchTaskBehind)
-                        && okToShowLocked(r)) {
-                    if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
-                            "Make visible? " + r + " finishing=" + r.finishing
-                            + " state=" + r.state);
+                final boolean activityVisibleBehind =
+                        (behindTranslucentActivity || stackVisibleBehind) && visibleBehind == r;
+                final boolean isVisible = (!behindFullscreenActivity || r.mLaunchTaskBehind
+                        || activityVisibleBehind) && okToShowLocked(r);
+                if (isVisible) {
+                    if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make visible? " + r
+                            + " finishing=" + r.finishing + " state=" + r.state);
                     // First: if this is not the current activity being started, make
                     // sure it matches the current configuration.
                     if (r != starting) {
@@ -1495,18 +1540,18 @@
 
                     if (r.app == null || r.app.thread == null) {
                         if (makeVisibleAndRestartIfNeeded(starting, configChanges, isTop,
-                                noStackActivityResumed, r)) {
+                                resumeNextActivity, r)) {
                             if (activityNdx >= activities.size()) {
                                 // Record may be removed if its process needs to restart.
                                 activityNdx = activities.size() - 1;
                             } else {
-                                noStackActivityResumed = false;
+                                resumeNextActivity = false;
                             }
                         }
                     } else if (r.visible) {
                         // If this activity is already visible, then there is nothing to do here.
                         if (handleAlreadyVisible(r)) {
-                            noStackActivityResumed = false;
+                            resumeNextActivity = false;
                         }
                     } else {
                         makeVisible(starting, r);
@@ -1515,15 +1560,23 @@
                     configChanges |= r.configChangeFlags;
                     behindFullscreenActivity = updateBehindFullscreen(stackInvisible,
                             behindFullscreenActivity, task, r);
+                    if (behindFullscreenActivity && !r.fullscreen) {
+                        behindTranslucentActivity = true;
+                    }
                 } else {
-                    makeInvisible(stackInvisible, behindFullscreenActivity, r);
+                    if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make invisible? " + r
+                            + " finishing=" + r.finishing + " state=" + r.state + " stackInvisible="
+                            + stackInvisible + " behindFullscreenActivity="
+                            + behindFullscreenActivity + " mLaunchTaskBehind="
+                            + r.mLaunchTaskBehind);
+                    makeInvisible(r, visibleBehind);
                 }
             }
             if (mStackId == FREEFORM_WORKSPACE_STACK_ID) {
                 // The visibility of tasks and the activities they contain in freeform stack are
                 // determined individually unlike other stacks where the visibility or fullscreen
                 // status of an activity in a previous task affects other.
-                behindFullscreenActivity = stackInvisible;
+                behindFullscreenActivity = stackVisibility == STACK_INVISIBLE;
             }
         }
 
@@ -1547,7 +1600,7 @@
     }
 
     private boolean makeVisibleAndRestartIfNeeded(ActivityRecord starting, int configChanges,
-            boolean isTop, boolean noStackActivityResumed, ActivityRecord r) {
+            boolean isTop, boolean andResume, ActivityRecord r) {
         // We need to make sure the app is running if it's the top, or it is just made visible from
         // invisible. If the app is already visible, it must have died while it was visible. In this
         // case, we'll show the dead window but will not restart the app. Otherwise we could end up
@@ -1564,25 +1617,21 @@
                 setVisible(r, true);
             }
             if (r != starting) {
-                mStackSupervisor.startSpecificActivityLocked(r, noStackActivityResumed, false);
+                mStackSupervisor.startSpecificActivityLocked(r, andResume, false);
                 return true;
             }
         }
         return false;
     }
 
-    private void makeInvisible(boolean stackInvisible, boolean behindFullscreenActivity,
-            ActivityRecord r) {
-        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make invisible? " + r + " finishing="
-                + r.finishing + " state=" + r.state + " stackInvisible=" + stackInvisible
-                + " behindFullscreenActivity=" + behindFullscreenActivity);
+    private void makeInvisible(ActivityRecord r, ActivityRecord visibleBehind) {
         if (!r.visible) {
             if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + r);
             return;
         }
         // Now for any activities that aren't visible to the user, make sure they no longer are
         // keeping the screen frozen.
-        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making invisible: " + r);
+        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making invisible: " + r + " " + r.state);
         try {
             setVisible(r, false);
             switch (r.state) {
@@ -1601,7 +1650,7 @@
                 case PAUSED:
                     // This case created for transitioning activities from
                     // translucent to opaque {@link Activity#convertToOpaque}.
-                    if (getVisibleBehindActivity() == r) {
+                    if (visibleBehind == r) {
                         releaseBackgroundResources(r);
                     } else {
                         if (!mStackSupervisor.mStoppingActivities.contains(r)) {
@@ -1623,16 +1672,16 @@
     private boolean updateBehindFullscreen(boolean stackInvisible, boolean behindFullscreenActivity,
             TaskRecord task, ActivityRecord r) {
         if (r.fullscreen) {
-            // At this point, nothing else needs to be shown in this task.
-            behindFullscreenActivity = true;
             if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Fullscreen: at " + r
                     + " stackInvisible=" + stackInvisible
                     + " behindFullscreenActivity=" + behindFullscreenActivity);
-        } else if (!isHomeStack() && r.frontOfTask && task.isOverHomeStack()) {
+            // At this point, nothing else needs to be shown in this task.
             behindFullscreenActivity = true;
+        } else if (!isHomeStack() && r.frontOfTask && task.isOverHomeStack()) {
             if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Showing home: at " + r
                     + " stackInvisible=" + stackInvisible
                     + " behindFullscreenActivity=" + behindFullscreenActivity);
+            behindFullscreenActivity = true;
         }
         return behindFullscreenActivity;
     }
@@ -1758,15 +1807,17 @@
      *
      * @param prev The previously resumed activity, for when in the process
      * of pausing; can be null to call from elsewhere.
+     * @param options Activity options.
      *
      * @return Returns true if something is being resumed, or false if
      * nothing happened.
+     *
+     * NOTE: It is not safe to call this method directly as it can cause an activity in a
+     *       non-focused stack to be resumed.
+     *       Use {@link ActivityStackSupervisor#resumeFocusedStackTopActivityLocked} to resume the
+     *       right activity for the current system state.
      */
-    final boolean resumeTopActivityLocked(ActivityRecord prev) {
-        return resumeTopActivityLocked(prev, null);
-    }
-
-    final boolean resumeTopActivityLocked(ActivityRecord prev, ActivityOptions options) {
+    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
         if (mStackSupervisor.inResumeTopActivity) {
             // Don't even start recursing.
             return false;
@@ -1817,14 +1868,13 @@
         if (next == null) {
             // There are no more activities!
             final String reason = "noMoreActivities";
-            if (!mFullscreen) {
+            if (!mFullscreen && adjustFocusToNextFocusableStackLocked(reason)) {
                 // Try to move focus to the next visible stack with a running activity if this
                 // stack is not covering the entire screen.
-                final ActivityStack stack = getNextVisibleStackLocked();
-                if (adjustFocusToNextVisibleStackLocked(stack, reason)) {
-                    return mStackSupervisor.resumeTopActivitiesLocked(stack, prev, null);
-                }
+                return mStackSupervisor.resumeFocusedStackTopActivityLocked(
+                        mStackSupervisor.getFocusedStack(), prev, null);
             }
+
             // Let's just start up the Launcher...
             ActivityOptions.abort(options);
             if (DEBUG_STATES) Slog.d(TAG_STATES,
@@ -2289,11 +2339,12 @@
             ActivityStack lastStack = mStackSupervisor.getLastStack();
             final boolean fromHome = lastStack.isHomeStack();
             if (!isHomeStack() && (fromHome || topTask() != task)) {
-                task.setTaskToReturnTo(fromHome
-                        ? lastStack.topTask() == null
-                                ? HOME_ACTIVITY_TYPE
-                                : lastStack.topTask().taskType
-                        : APPLICATION_ACTIVITY_TYPE);
+                int returnToType = APPLICATION_ACTIVITY_TYPE;
+                if (fromHome && StackId.allowTopTaskToReturnHome(mStackId)) {
+                    returnToType = lastStack.topTask() == null
+                            ? HOME_ACTIVITY_TYPE : lastStack.topTask().taskType;
+                }
+                task.setTaskToReturnTo(returnToType);
             }
         } else {
             task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
@@ -2563,8 +2614,9 @@
                     if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + target
                             + " out to bottom task " + bottom.task);
                 } else {
-                    targetTask = createTaskRecord(mStackSupervisor.getNextTaskId(), target.info,
-                            null, null, null, false);
+                    targetTask = createTaskRecord(
+                            mStackSupervisor.getNextTaskIdForUserLocked(target.userId),
+                            target.info, null, null, null, false);
                     targetTask.affinityIntent = target.intent;
                     if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + target
                             + " out to new task " + target.task);
@@ -2856,7 +2908,7 @@
         final ActivityRecord next = topRunningActivityLocked();
         final String myReason = reason + " adjustFocus";
         if (next != r) {
-            if (next != null && StackId.keepFocusInStackIfPossible(mStackId)) {
+            if (next != null && StackId.keepFocusInStackIfPossible(mStackId) && isFocusable()) {
                 // For freeform, docked, and pinned stacks we always keep the focus within the
                 // stack as long as there is a running activity in the stack that we can adjust
                 // focus to.
@@ -2868,8 +2920,7 @@
                     // For non-fullscreen stack, we want to move the focus to the next visible
                     // stack to prevent the home screen from moving to the top and obscuring
                     // other visible stacks.
-                    if (!mFullscreen
-                            && adjustFocusToNextVisibleStackLocked(null, myReason)) {
+                    if (!mFullscreen && adjustFocusToNextFocusableStackLocked(myReason)) {
                         return;
                     }
                     // Move the home stack to the top if this stack is fullscreen or there is no
@@ -2883,24 +2934,16 @@
             }
         }
 
-        final ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
-        if (top != null) {
-            mService.setFocusedActivityLocked(top, myReason);
-        }
+        mService.setFocusedActivityLocked(mStackSupervisor.topRunningActivityLocked(), myReason);
     }
 
-    private boolean adjustFocusToNextVisibleStackLocked(ActivityStack inStack, String reason) {
-        final ActivityStack stack = (inStack != null) ? inStack : getNextVisibleStackLocked();
-        final String myReason = reason + " adjustFocusToNextVisibleStack";
+    private boolean adjustFocusToNextFocusableStackLocked(String reason) {
+        final ActivityStack stack = getNextFocusableStackLocked();
+        final String myReason = reason + " adjustFocusToNextFocusableStack";
         if (stack == null) {
             return false;
         }
-        final ActivityRecord top = stack.topRunningActivityLocked();
-        if (top == null) {
-            return false;
-        }
-        mService.setFocusedActivityLocked(top, myReason);
-        return true;
+        return mService.setFocusedActivityLocked(stack.topRunningActivityLocked(), myReason);
     }
 
     final void stopActivityLocked(ActivityRecord r) {
@@ -2952,7 +2995,7 @@
                 r.stopped = true;
                 if (DEBUG_STATES) Slog.v(TAG_STATES, "Stop failed; moving to STOPPED: " + r);
                 r.state = ActivityState.STOPPED;
-                if (r.configDestroy) {
+                if (r.deferRelaunchUntilPaused) {
                     destroyActivityLocked(r, true, "stop-except");
                 }
             }
@@ -2995,42 +3038,44 @@
         mService.updateOomAdjLocked();
     }
 
-    final void finishTopRunningActivityLocked(ProcessRecord app, String reason) {
+    final TaskRecord finishTopRunningActivityLocked(ProcessRecord app, String reason) {
         ActivityRecord r = topRunningActivityLocked();
-        if (r != null && r.app == app) {
-            // If the top running activity is from this crashing
-            // process, then terminate it to avoid getting in a loop.
-            Slog.w(TAG, "  Force finishing activity "
-                    + r.intent.getComponent().flattenToShortString());
-            int taskNdx = mTaskHistory.indexOf(r.task);
-            int activityNdx = r.task.mActivities.indexOf(r);
-            finishActivityLocked(r, Activity.RESULT_CANCELED, null, reason, false);
-            // Also terminate any activities below it that aren't yet
-            // stopped, to avoid a situation where one will get
-            // re-start our crashing activity once it gets resumed again.
-            --activityNdx;
-            if (activityNdx < 0) {
-                do {
-                    --taskNdx;
-                    if (taskNdx < 0) {
-                        break;
-                    }
-                    activityNdx = mTaskHistory.get(taskNdx).mActivities.size() - 1;
-                } while (activityNdx < 0);
-            }
-            if (activityNdx >= 0) {
-                r = mTaskHistory.get(taskNdx).mActivities.get(activityNdx);
-                if (r.state == ActivityState.RESUMED
-                        || r.state == ActivityState.PAUSING
-                        || r.state == ActivityState.PAUSED) {
-                    if (!r.isHomeActivity() || mService.mHomeProcess != r.app) {
-                        Slog.w(TAG, "  Force finishing activity "
-                                + r.intent.getComponent().flattenToShortString());
-                        finishActivityLocked(r, Activity.RESULT_CANCELED, null, reason, false);
-                    }
+        TaskRecord finishedTask = null;
+        if (r == null || r.app != app) {
+            return null;
+        }
+        Slog.w(TAG, "  Force finishing activity "
+                + r.intent.getComponent().flattenToShortString());
+        int taskNdx = mTaskHistory.indexOf(r.task);
+        int activityNdx = r.task.mActivities.indexOf(r);
+        finishActivityLocked(r, Activity.RESULT_CANCELED, null, reason, false);
+        finishedTask = r.task;
+        // Also terminate any activities below it that aren't yet
+        // stopped, to avoid a situation where one will get
+        // re-start our crashing activity once it gets resumed again.
+        --activityNdx;
+        if (activityNdx < 0) {
+            do {
+                --taskNdx;
+                if (taskNdx < 0) {
+                    break;
+                }
+                activityNdx = mTaskHistory.get(taskNdx).mActivities.size() - 1;
+            } while (activityNdx < 0);
+        }
+        if (activityNdx >= 0) {
+            r = mTaskHistory.get(taskNdx).mActivities.get(activityNdx);
+            if (r.state == ActivityState.RESUMED
+                    || r.state == ActivityState.PAUSING
+                    || r.state == ActivityState.PAUSED) {
+                if (!r.isHomeActivity() || mService.mHomeProcess != r.app) {
+                    Slog.w(TAG, "  Force finishing activity "
+                            + r.intent.getComponent().flattenToShortString());
+                    finishActivityLocked(r, Activity.RESULT_CANCELED, null, reason, false);
                 }
             }
         }
+        return finishedTask;
     }
 
     final void finishVoiceTask(IVoiceInteractionSession session) {
@@ -3047,8 +3092,29 @@
                         didOne = true;
                     }
                 }
+            } else {
+                // Check if any of the activities are using voice
+                for (int activityNdx = tr.mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
+                    ActivityRecord r = tr.mActivities.get(activityNdx);
+                    if (r.voiceSession != null
+                            && r.voiceSession.asBinder() == sessionBinder) {
+                        // Inform of cancellation
+                        r.clearVoiceSessionLocked();
+                        try {
+                            r.app.thread.scheduleLocalVoiceInteractionStarted((IBinder) r.appToken,
+                                    null);
+                        } catch (RemoteException re) {
+                            // Ok
+                        }
+                        // TODO: VI This is redundant in some cases
+                        mService.finishRunningVoiceLocked();
+                        break;
+                    }
+                }
             }
         }
+        Slog.d(TAG, "ActivityStack.finishVoiceTask()");
+
         if (didOne) {
             mService.updateOomAdjLocked();
         }
@@ -3210,7 +3276,7 @@
             r.makeFinishingLocked();
             boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm");
             if (activityRemoved) {
-                mStackSupervisor.resumeTopActivitiesLocked();
+                mStackSupervisor.resumeFocusedStackTopActivityLocked();
             }
             if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS,
                     "destroyActivityLocked: finishCurrentActivityLocked r=" + r +
@@ -3223,7 +3289,7 @@
         if (DEBUG_ALL) Slog.v(TAG, "Enqueueing pending finish: " + r);
         mStackSupervisor.mFinishingActivities.add(r);
         r.resumeKeyDispatchingLocked();
-        mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null);
+        mStackSupervisor.resumeFocusedStackTopActivityLocked();
         return r;
     }
 
@@ -3348,9 +3414,9 @@
                 try {
                     ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
                             destIntent.getComponent(), 0, srec.userId);
-                    int res = mStackSupervisor.startActivityLocked(srec.app.thread, destIntent,
-                            null /*ephemeralIntent*/, null, aInfo, null /*rInfo*/, null, null,
-                            parent.appToken, null, 0, -1, parent.launchedFromUid,
+                    int res = mService.mActivityStarter.startActivityLocked(srec.app.thread,
+                            destIntent, null /*ephemeralIntent*/, null, aInfo, null /*rInfo*/, null,
+                            null, parent.appToken, null, 0, -1, parent.launchedFromUid,
                             parent.launchedFromPackage, -1, parent.launchedFromUid, 0, null,
                             false, true, null, null, null);
                     foundParentInTask = res == ActivityManager.START_SUCCESS;
@@ -3381,9 +3447,9 @@
         if (mPausingActivity == r) {
             mPausingActivity = null;
         }
-        mService.clearFocusedActivity(r);
+        mService.resetFocusedActivityIfNeededLocked(r);
 
-        r.configDestroy = false;
+        r.deferRelaunchUntilPaused = false;
         r.frozenBeforeDestroy = false;
 
         if (setState) {
@@ -3512,7 +3578,7 @@
             }
         }
         if (activityRemoved) {
-            mStackSupervisor.resumeTopActivitiesLocked();
+            mStackSupervisor.resumeFocusedStackTopActivityLocked();
         }
     }
 
@@ -3686,7 +3752,7 @@
                     removeActivityFromHistoryLocked(r, reason);
                 }
             }
-            mStackSupervisor.resumeTopActivitiesLocked();
+            mStackSupervisor.resumeFocusedStackTopActivityLocked();
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
@@ -3695,9 +3761,9 @@
     void releaseBackgroundResources(ActivityRecord r) {
         if (hasVisibleBehindActivity() &&
                 !mHandler.hasMessages(RELEASE_BACKGROUND_RESOURCES_TIMEOUT_MSG)) {
-            if (r == topRunningActivityLocked()) {
+            if (r == topRunningActivityLocked() && getStackVisibilityLocked() == STACK_VISIBLE) {
                 // Don't release the top activity if it has requested to run behind the next
-                // activity.
+                // activity and the stack is currently visible.
                 return;
             }
             if (DEBUG_STATES) Slog.d(TAG_STATES, "releaseBackgroundResources activtyDisplay=" +
@@ -3724,7 +3790,7 @@
             setVisibleBehindActivity(null);
             mStackSupervisor.scheduleIdleTimeoutLocked(null);
         }
-        mStackSupervisor.resumeTopActivitiesLocked();
+        mStackSupervisor.resumeFocusedStackTopActivityLocked();
     }
 
     boolean hasVisibleBehindActivity() {
@@ -3939,7 +4005,7 @@
             updateTransitLocked(AppTransition.TRANSIT_TASK_TO_FRONT, options);
         }
 
-        mStackSupervisor.resumeTopActivitiesLocked();
+        mStackSupervisor.resumeFocusedStackTopActivityLocked();
         EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, tr.taskId);
 
         if (VALIDATE_TOKENS) {
@@ -4002,7 +4068,7 @@
             if (fullscreenStack != null && fullscreenStack.hasVisibleBehindActivity()) {
                 final ActivityRecord visibleBehind = fullscreenStack.getVisibleBehindActivity();
                 mService.setFocusedActivityLocked(visibleBehind, "moveTaskToBack");
-                mStackSupervisor.resumeTopActivitiesLocked(fullscreenStack, null, null);
+                mStackSupervisor.resumeFocusedStackTopActivityLocked();
                 return true;
             }
         }
@@ -4057,7 +4123,7 @@
             return mStackSupervisor.resumeHomeStackTask(taskToReturnTo, null, "moveTaskToBack");
         }
 
-        mStackSupervisor.resumeTopActivitiesLocked();
+        mStackSupervisor.resumeFocusedStackTopActivityLocked();
         return true;
     }
 
@@ -4155,38 +4221,33 @@
             r.configChangeFlags |= changes;
             r.startFreezingScreenLocked(r.app, globalChanges);
             r.forceNewConfig = false;
+            preserveWindow &= isResizeOnlyChange(changes);
             if (r.app == null || r.app.thread == null) {
                 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                         "Config is destroying non-running " + r);
                 destroyActivityLocked(r, true, "config");
             } else if (r.state == ActivityState.PAUSING) {
-                // A little annoying: we are waiting for this activity to
-                // finish pausing.  Let's not do anything now, but just
-                // flag that it needs to be restarted when done pausing.
+                // A little annoying: we are waiting for this activity to finish pausing. Let's not
+                // do anything now, but just flag that it needs to be restarted when done pausing.
                 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                         "Config is skipping already pausing " + r);
-                r.configDestroy = true;
+                r.deferRelaunchUntilPaused = true;
+                r.preserveWindowOnDeferredRelaunch = preserveWindow;
                 return true;
             } else if (r.state == ActivityState.RESUMED) {
-                // Try to optimize this case: the configuration is changing
-                // and we need to restart the top, resumed activity.
-                // Instead of doing the normal handshaking, just say
+                // Try to optimize this case: the configuration is changing and we need to restart
+                // the top, resumed activity. Instead of doing the normal handshaking, just say
                 // "restart!".
                 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                         "Config is relaunching resumed " + r);
-                relaunchActivityLocked(r, r.configChangeFlags, true,
-                        preserveWindow && isResizeOnlyChange(changes));
-                r.configChangeFlags = 0;
+                relaunchActivityLocked(r, r.configChangeFlags, true, preserveWindow);
             } else {
                 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                         "Config is relaunching non-resumed " + r);
-                relaunchActivityLocked(r, r.configChangeFlags, false,
-                        preserveWindow && isResizeOnlyChange(changes));
-                r.configChangeFlags = 0;
+                relaunchActivityLocked(r, r.configChangeFlags, false, preserveWindow);
             }
 
-            // All done...  tell the caller we weren't able to keep this
-            // activity around.
+            // All done...  tell the caller we weren't able to keep this activity around.
             return false;
         }
 
@@ -4202,6 +4263,14 @@
 
     private int getTaskConfigurationChanges(ActivityRecord record, Configuration taskConfig,
             Configuration oldTaskOverride) {
+
+        // If we went from full-screen to non-full-screen, make sure to use the correct
+        // configuration task diff, so the diff stays as small as possible.
+        if (Configuration.EMPTY.equals(oldTaskOverride)
+                && !Configuration.EMPTY.equals(taskConfig)) {
+            oldTaskOverride = record.task.extractOverrideConfig(record.configuration);
+        }
+
         // Determine what has changed.  May be nothing, if this is a config
         // that has come back from the app after going idle.  In that case
         // we just want to leave the official config object now in the
@@ -4209,20 +4278,20 @@
         int taskChanges = oldTaskOverride.diff(taskConfig);
         // We don't want to use size changes if they don't cross boundaries that are important to
         // the app.
-        if ((taskChanges & ActivityInfo.CONFIG_SCREEN_SIZE) != 0) {
+        if ((taskChanges & CONFIG_SCREEN_SIZE) != 0) {
             final boolean crosses = record.crossesHorizontalSizeThreshold(
                     oldTaskOverride.screenWidthDp, taskConfig.screenWidthDp)
                     || record.crossesVerticalSizeThreshold(
                     oldTaskOverride.screenHeightDp, taskConfig.screenHeightDp);
             if (!crosses) {
-                taskChanges &= ~ActivityInfo.CONFIG_SCREEN_SIZE;
+                taskChanges &= ~CONFIG_SCREEN_SIZE;
             }
         }
-        if ((taskChanges & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0) {
+        if ((taskChanges & CONFIG_SMALLEST_SCREEN_SIZE) != 0) {
             final int oldSmallest = oldTaskOverride.smallestScreenWidthDp;
             final int newSmallest = taskConfig.smallestScreenWidthDp;
             if (!record.crossesSmallestSizeThreshold(oldSmallest, newSmallest)) {
-                taskChanges &= ~ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+                taskChanges &= ~CONFIG_SMALLEST_SCREEN_SIZE;
             }
         }
         return catchConfigChangesFromUnset(taskConfig, oldTaskOverride, taskChanges);
@@ -4234,7 +4303,7 @@
             // {@link Configuration#diff} doesn't catch changes from unset values.
             // Check for changes we care about.
             if (oldTaskOverride.orientation != taskConfig.orientation) {
-                taskChanges |= ActivityInfo.CONFIG_ORIENTATION;
+                taskChanges |= CONFIG_ORIENTATION;
             }
             // We want to explicitly track situations where the size configuration goes from
             // undefined to defined. We don't care about crossing the threshold in that case,
@@ -4244,34 +4313,41 @@
             final int undefinedHeight = Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
             if ((oldHeight == undefinedHeight && newHeight != undefinedHeight)
                     || (oldHeight != undefinedHeight && newHeight == undefinedHeight)) {
-                taskChanges |= ActivityInfo.CONFIG_SCREEN_SIZE;
+                taskChanges |= CONFIG_SCREEN_SIZE;
             }
             final int oldWidth = oldTaskOverride.screenWidthDp;
             final int newWidth = taskConfig.screenWidthDp;
             final int undefinedWidth = Configuration.SCREEN_WIDTH_DP_UNDEFINED;
             if ((oldWidth == undefinedWidth && newWidth != undefinedWidth)
                     || (oldWidth != undefinedWidth && newWidth == undefinedWidth)) {
-                taskChanges |= ActivityInfo.CONFIG_SCREEN_SIZE;
+                taskChanges |= CONFIG_SCREEN_SIZE;
             }
             final int oldSmallest = oldTaskOverride.smallestScreenWidthDp;
             final int newSmallest = taskConfig.smallestScreenWidthDp;
             final int undefinedSmallest = Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
             if ((oldSmallest == undefinedSmallest && newSmallest != undefinedSmallest)
                     || (oldSmallest != undefinedSmallest && newSmallest == undefinedSmallest)) {
-                taskChanges |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+                taskChanges |= CONFIG_SMALLEST_SCREEN_SIZE;
+            }
+            final int oldLayout = oldTaskOverride.screenLayout;
+            final int newLayout = taskConfig.screenLayout;
+            if ((oldLayout == SCREENLAYOUT_UNDEFINED && newLayout != SCREENLAYOUT_UNDEFINED)
+                || (oldLayout != SCREENLAYOUT_UNDEFINED && newLayout == SCREENLAYOUT_UNDEFINED)) {
+                taskChanges |= CONFIG_SCREEN_LAYOUT;
             }
         }
         return taskChanges;
     }
 
     private static boolean isResizeOnlyChange(int change) {
-        return (change & ~(ActivityInfo.CONFIG_SCREEN_SIZE
-                | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) == 0;
+        return (change & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE | CONFIG_ORIENTATION
+                | CONFIG_SCREEN_LAYOUT)) == 0;
     }
 
     private void relaunchActivityLocked(
             ActivityRecord r, int changes, boolean andResume, boolean preserveWindow) {
         if (mService.mSuppressResizeConfigChanges && preserveWindow) {
+            r.configChangeFlags = 0;
             return;
         }
 
@@ -4299,6 +4375,7 @@
             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.
@@ -4314,6 +4391,8 @@
             mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
             r.state = ActivityState.PAUSED;
         }
+
+        r.configChangeFlags = 0;
     }
 
     boolean willActivityBeVisibleLocked(IBinder token) {
@@ -4579,7 +4658,7 @@
                     a.forceNewConfig = true;
                     if (starting != null && a == starting && a.visible) {
                         a.startFreezingScreenLocked(starting.app,
-                                ActivityInfo.CONFIG_SCREEN_LAYOUT);
+                                CONFIG_SCREEN_LAYOUT);
                     }
                 }
             }
@@ -4627,6 +4706,7 @@
         updateTaskMovement(task, true);
 
         if (!moving && task.mActivities.isEmpty()) {
+            // TODO: VI what about activity?
             final boolean isVoiceSession = task.voiceSession != null;
             if (isVoiceSession) {
                 try {
@@ -4647,7 +4727,7 @@
             // We only need to adjust focused stack if this stack is in focus.
             if (isOnHomeDisplay() && mStackSupervisor.isFocusedStack(this)) {
                 String myReason = reason + " leftTaskHistoryEmpty";
-                if (mFullscreen || !adjustFocusToNextVisibleStackLocked(null, myReason)) {
+                if (mFullscreen || !adjustFocusToNextFocusableStackLocked(myReason)) {
                     mStackSupervisor.moveHomeStackToFront(myReason);
                 }
             }
@@ -4720,10 +4800,7 @@
 
     private void postAddTask(TaskRecord task, ActivityStack prevStack) {
         if (prevStack != null) {
-            if (prevStack != this
-                    && (prevStack.mStackId == PINNED_STACK_ID || mStackId == PINNED_STACK_ID)) {
-                task.reportPictureInPictureModeChange();
-            }
+            task.reportPictureInPictureModeChangeIfNeeded(prevStack);
         } else if (task.voiceSession != null) {
             try {
                 task.voiceSession.taskStarted(task.intent, task.taskId);
@@ -4733,36 +4810,32 @@
     }
 
     void addConfigOverride(ActivityRecord r, TaskRecord task) {
-        final Rect bounds = task.getLaunchBounds();
-        task.updateOverrideConfiguration(bounds);
+        final Rect bounds = task.updateOverrideConfigurationFromLaunchBounds();
+        // TODO: VI deal with activity
         mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
                 r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
-                (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
-                r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind,
-                bounds, task.mOverrideConfig, !r.isHomeActivity());
+                (r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId, r.info.configChanges,
+                task.voiceSession != null, r.mLaunchTaskBehind, bounds, task.mOverrideConfig,
+                r.cropAppWindows() | r.isResizeable(), r.isAlwaysFocusable());
         mWindowManager.setTaskResizeable(task.taskId, task.mResizeable);
         r.taskConfigOverride = task.mOverrideConfig;
     }
 
-    void setFocusAndResumeStateIfNeeded(
-            ActivityRecord r, boolean setFocus, boolean setResume, String reason) {
-        // If the activity had focus before move focus to this stack.
-        if (setFocus) {
-            // If the activity owns the last resumed activity, transfer that together,
-            // so that we don't resume the same activity again in the new stack.
-            // Apps may depend on onResume()/onPause() being called in pairs.
-            if (setResume) {
-                mResumedActivity = r;
-                // Move the stack in which we are placing the activity to the front. We don't use
-                // ActivityManagerService.setFocusedActivityLocked, because if the activity is
-                // already focused, the call will short-circuit and do nothing.
-                moveToFront(reason);
-            } else {
-                // We need to not only move the stack to the front, but also have the activity
-                // focused. This will achieve both goals.
-                mService.setFocusedActivityLocked(r, reason);
-            }
+    void moveToFrontAndResumeStateIfNeeded(
+            ActivityRecord r, boolean moveToFront, boolean setResume, String reason) {
+        if (!moveToFront) {
+            return;
         }
+
+        // If the activity owns the last resumed activity, transfer that together,
+        // so that we don't resume the same activity again in the new stack.
+        // Apps may depend on onResume()/onPause() being called in pairs.
+        if (setResume) {
+            mResumedActivity = r;
+        }
+        // Move the stack in which we are placing the activity to the front. The call will also
+        // make sure the activity focus is set.
+        moveToFront(reason);
     }
 
     /**
@@ -4782,19 +4855,22 @@
         final boolean wasResumed = wasFocused && (prevStack.mResumedActivity == r);
 
         final TaskRecord task = createTaskRecord(
-                mStackSupervisor.getNextTaskId(), r.info, r.intent, null, null, true);
+                mStackSupervisor.getNextTaskIdForUserLocked(r.userId),
+                r.info, r.intent, null, null, true);
         r.setTask(task, null);
         task.addActivityToTop(r);
         setAppTask(r, task);
-        task.reportPictureInPictureModeChange();
-        setFocusAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack");
+        task.reportPictureInPictureModeChangeIfNeeded(prevStack);
+        moveToFrontAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack");
+        if (wasResumed) {
+            prevStack.mResumedActivity = null;
+        }
     }
 
     private void setAppTask(ActivityRecord r, TaskRecord task) {
-        final Rect bounds = task.getLaunchBounds();
-        task.updateOverrideConfiguration(bounds);
+        final Rect bounds = task.updateOverrideConfigurationFromLaunchBounds();
         mWindowManager.setAppTask(
-                r.appToken, task.taskId, mStackId, task.getLaunchBounds(), task.mOverrideConfig);
+                r.appToken, task.taskId, mStackId, bounds, task.mOverrideConfig);
         mWindowManager.setTaskResizeable(task.taskId, task.mResizeable);
         r.taskConfigOverride = task.mOverrideConfig;
     }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 9117806..11dd8a3 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -16,84 +16,6 @@
 
 package com.android.server.am;
 
-import static android.Manifest.permission.START_ANY_ACTIVITY;
-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;
-import static android.app.ActivityManager.RESIZE_MODE_FORCED;
-import static android.app.ActivityManager.RESIZE_MODE_SYSTEM;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
-import static android.app.ActivityManager.StackId.FIRST_STATIC_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.INVALID_STACK_ID;
-import static android.app.ActivityManager.StackId.LAST_STATIC_STACK_ID;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
-import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_TO_SIDE;
-import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
-import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
-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;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONTAINERS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IDLE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKSCREEN;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PAUSE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RELEASE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RESULTS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USER_LEAVING;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBLE_BEHIND;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONTAINERS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IDLE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PAUSE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RELEASE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RESULTS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_USER_LEAVING;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBLE_BEHIND;
-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.ANIMATE;
-import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_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;
-import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
-import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
-import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING;
-import static com.android.server.am.ActivityStack.ActivityState.PAUSED;
-import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
-import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
-import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
-import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
-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 android.Manifest;
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -107,9 +29,6 @@
 import android.app.IActivityContainerCallback;
 import android.app.IActivityManager;
 import android.app.IActivityManager.WaitResult;
-import android.app.IApplicationThread;
-import android.app.KeyguardManager;
-import android.app.PendingIntent;
 import android.app.ProfilerInfo;
 import android.app.ResultInfo;
 import android.app.StatusBarManager;
@@ -118,7 +37,6 @@
 import android.content.Context;
 import android.content.IIntentSender;
 import android.content.Intent;
-import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
@@ -133,10 +51,7 @@
 import android.hardware.display.VirtualDisplay;
 import android.hardware.input.InputManager;
 import android.hardware.input.InputManagerInternal;
-import android.net.Uri;
 import android.os.Binder;
-import android.os.Build;
-import android.os.Bundle;
 import android.os.Debug;
 import android.os.Handler;
 import android.os.IBinder;
@@ -168,8 +83,6 @@
 import android.view.InputEvent;
 import android.view.Surface;
 
-import com.android.internal.app.HeavyWeightSwitcherActivity;
-import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.content.ReferrerIntent;
 import com.android.internal.os.TransferPipe;
 import com.android.internal.statusbar.IStatusBarService;
@@ -185,25 +98,86 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 
+import static android.Manifest.permission.START_ANY_ACTIVITY;
+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;
+import static android.app.ActivityManager.RESIZE_MODE_FORCED;
+import static android.app.ActivityManager.RESIZE_MODE_SYSTEM;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
+import static android.app.ActivityManager.StackId.FIRST_STATIC_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.INVALID_STACK_ID;
+import static android.app.ActivityManager.StackId.LAST_STATIC_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+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.PackageManager.PERMISSION_GRANTED;
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONTAINERS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IDLE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKSCREEN;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PAUSE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RELEASE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBLE_BEHIND;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONTAINERS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IDLE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PAUSE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RELEASE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBLE_BEHIND;
+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.FIRST_SUPERVISOR_STACK_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;
+import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
+import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
+import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING;
+import static com.android.server.am.ActivityStack.ActivityState.PAUSED;
+import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
+import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
+import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
+import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
+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;
+
 public final class ActivityStackSupervisor implements DisplayListener {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
-    private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
     private static final String TAG_CONTAINERS = TAG + POSTFIX_CONTAINERS;
-    private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
     private static final String TAG_IDLE = TAG + POSTFIX_IDLE;
     private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
     private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
     private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
     private static final String TAG_RELEASE = TAG + POSTFIX_RELEASE;
-    private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
     private static final String TAG_STACK = TAG + POSTFIX_STACK;
     private static final String TAG_STATES = TAG + POSTFIX_STATES;
     private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
-    private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
+    static final String TAG_TASKS = TAG + POSTFIX_TASKS;
     private static final String TAG_VISIBLE_BEHIND = TAG + POSTFIX_VISIBLE_BEHIND;
-    private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
 
     /** How long we wait until giving up on the last activity telling us it is idle. */
     static final int IDLE_TIMEOUT = 10 * 1000;
@@ -235,7 +209,7 @@
 
     // Used to indicate if an object (e.g. stack) that we are trying to get
     // should be created if it doesn't exist already.
-    private static final boolean CREATE_IF_NEEDED = true;
+    static final boolean CREATE_IF_NEEDED = true;
 
     // Used to indicate that windows of activities should be preserved during the resize.
     static final boolean PRESERVE_WINDOWS = true;
@@ -289,10 +263,12 @@
     // For debugging to make sure the caller when acquiring/releasing our
     // wake lock is the system process.
     static final boolean VALIDATE_WAKE_LOCK_CALLER = false;
+    /** The number of distinct task ids that can be assigned to the tasks of a single user */
+    private static final int MAX_TASK_IDS_PER_USER = UserHandle.PER_USER_RANGE;
 
     final ActivityManagerService mService;
 
-    private final RecentTasks mRecentTasks;
+    private RecentTasks mRecentTasks;
 
     final ActivityStackSupervisorHandler mHandler;
 
@@ -303,19 +279,21 @@
     /** Counter for next free stack ID to use for dynamic activity stacks. */
     private int mNextFreeStackId = FIRST_DYNAMIC_STACK_ID;
 
-    /** Task identifier that activities are currently being started in.  Incremented each time a
-     * new task is created. */
-    private int mCurTaskId = 0;
+    /**
+     * Maps the task identifier that activities are currently being started in to the userId of the
+     * task. Each time a new task is created, the entry for the userId of the task is incremented
+     */
+    private final SparseIntArray mCurTaskIdForUser = new SparseIntArray(20);
 
     /** The current user */
-    private int mCurrentUser;
+    int mCurrentUser;
 
     /** The stack containing the launcher app. Assumed to always be attached to
      * Display.DEFAULT_DISPLAY. */
-    private ActivityStack mHomeStack;
+    ActivityStack mHomeStack;
 
     /** The stack currently receiving input or launching the next activity. */
-    private ActivityStack mFocusedStack;
+    ActivityStack mFocusedStack;
 
     /** If this is the same as mFocusedStack then the activity on the top of the focused stack has
      * been resumed. If stacks are changing position this will hold the old stack until the new
@@ -397,9 +375,7 @@
      */
     private LockTaskNotify mLockTaskNotify;
 
-    final ArrayList<PendingActivityLaunch> mPendingActivityLaunches = new ArrayList<>();
-
-    /** Used to keep resumeTopActivityLocked() from being entered recursively */
+    /** Used to keep resumeTopActivityUncheckedLocked() from being entered recursively */
     boolean inResumeTopActivity;
 
     // temp. rects used during resize calculation so we don't need to create a new object each time.
@@ -408,6 +384,7 @@
 
     private final SparseArray<Configuration> mTmpConfigs = new SparseArray<>();
     private final SparseArray<Rect> mTmpBounds = new SparseArray<>();
+    private final SparseArray<Rect> mTmpInsetBounds = new SparseArray<>();
 
     // The default minimal size that will be used if the activity doesn't specify its minimal size.
     // It will be calculated when the default display gets added.
@@ -418,6 +395,20 @@
 
     private final ActivityMetricsLogger mActivityMetricsLogger;
 
+    private final ResizeDockedStackTimeout mResizeDockedStackTimeout;
+
+    static class FindTaskResult {
+        ActivityRecord r;
+        boolean matchedByRootAffinity;
+    }
+    private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
+
+    /**
+     * Used to keep track whether app visibilities got changed since the last pause. Useful to
+     * determine whether to invoke the task stack change listener after pausing.
+     */
+    boolean mAppVisibilitiesChangedSinceLastPause;
+
     /**
      * Description of a request to start a new activity, which has been held
      * due to app switches being disabled.
@@ -450,11 +441,15 @@
         }
     }
 
-    public ActivityStackSupervisor(ActivityManagerService service, RecentTasks recentTasks) {
+    public ActivityStackSupervisor(ActivityManagerService service) {
         mService = service;
-        mRecentTasks = recentTasks;
         mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper());
         mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext);
+        mResizeDockedStackTimeout = new ResizeDockedStackTimeout(service, this, mHandler);
+    }
+
+    void setRecentTasks(RecentTasks recentTasks) {
+        mRecentTasks = recentTasks;
     }
 
     /**
@@ -515,8 +510,8 @@
                 calculateDefaultMinimalSizeOfResizeableTasks(activityDisplay);
             }
 
-            createStackOnDisplay(HOME_STACK_ID, Display.DEFAULT_DISPLAY, true);
-            mHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID);
+            mHomeStack = mFocusedStack = mLastFocusedStack =
+                    getStack(HOME_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
 
             mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
         }
@@ -560,16 +555,30 @@
         return stack == mHomeStack.mStacks.get((mHomeStack.mStacks.size() - 1));
     }
 
-    void setFocusStack(String reason, ActivityStack focusedStack) {
-        mLastFocusedStack = mFocusedStack;
-        mFocusedStack = focusedStack;
+    /** NOTE: Should only be called from {@link ActivityStack#moveToFront} */
+    void setFocusStackUnchecked(String reason, ActivityStack focusCandidate) {
+        if (!focusCandidate.isFocusable()) {
+            // The focus candidate isn't focusable. Move focus to the top stack that is focusable.
+            focusCandidate = focusCandidate.getNextFocusableStackLocked();
+        }
 
-        EventLogTags.writeAmFocusedStack(
-                mCurrentUser, mFocusedStack == null ? -1 : mFocusedStack.getStackId(),
-                mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(), reason);
+        if (focusCandidate != mFocusedStack) {
+            mLastFocusedStack = mFocusedStack;
+            mFocusedStack = focusCandidate;
+
+            EventLogTags.writeAmFocusedStack(
+                    mCurrentUser, mFocusedStack == null ? -1 : mFocusedStack.getStackId(),
+                    mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(), reason);
+        }
+
+        final ActivityRecord r = topRunningActivityLocked();
+        if (mService.mFocusedActivity != r) {
+            // The focus activity should always be the top activity in the focused stack.
+            // There will be chaos and anarchy if it isn't...
+            mService.setFocusedActivityLocked(r, reason + " setFocusStack");
+        }
 
         if (mService.mBooting || !mService.mBooted) {
-            final ActivityRecord r = topRunningActivityLocked();
             if (r != null && r.idle) {
                 checkFinishBootingLocked();
             }
@@ -614,12 +623,14 @@
 
         mHomeStack.moveHomeStackTaskToTop(homeStackTaskType);
         ActivityRecord r = getHomeActivity();
+        final String myReason = reason + " resumeHomeStackTask";
+
         // Only resume home activity if isn't finishing.
         if (r != null && !r.finishing) {
-            mService.setFocusedActivityLocked(r, reason);
-            return resumeTopActivitiesLocked(mHomeStack, prev, null);
+            mService.setFocusedActivityLocked(r, myReason);
+            return resumeFocusedStackTopActivityLocked(mHomeStack, prev, null);
         }
-        return mService.startHomeActivityLocked(mCurrentUser, reason);
+        return mService.startHomeActivityLocked(mCurrentUser, myReason);
     }
 
     TaskRecord anyTaskForIdLocked(int id) {
@@ -682,20 +693,43 @@
         return null;
     }
 
-    void setNextTaskId(int taskId) {
-        if (taskId > mCurTaskId) {
-            mCurTaskId = taskId;
+    boolean isFocusedUserLockedProfile() {
+        final int userId = mFocusedStack.topRunningActivityLocked().userId;
+        return userId != UserHandle.myUserId()
+                && mService.mUserController.shouldConfirmCredentials(userId);
+    }
+
+    void setNextTaskIdForUserLocked(int taskId, int userId) {
+        final int currentTaskId = mCurTaskIdForUser.get(userId, -1);
+        if (taskId > currentTaskId) {
+            mCurTaskIdForUser.put(userId, taskId);
         }
     }
 
-    int getNextTaskId() {
-        do {
-            mCurTaskId++;
-            if (mCurTaskId <= 0) {
-                mCurTaskId = 1;
+    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) {
+            candidateTaskId++;
+            if (candidateTaskId == (userId + 1) * MAX_TASK_IDS_PER_USER) {
+                // Wrap around as there will be smaller task ids that are available now.
+                candidateTaskId -= MAX_TASK_IDS_PER_USER;
             }
-        } while (anyTaskForIdLocked(mCurTaskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID) != null);
-        return mCurTaskId;
+            if (candidateTaskId == currentTaskId) {
+                // Something wrong!
+                // All MAX_TASK_IDS_PER_USER task ids are taken up by running tasks for this user
+                throw new IllegalStateException("Cannot get an available task id."
+                        + " Reached limit of " + MAX_TASK_IDS_PER_USER
+                        + " running tasks per user.");
+            }
+        }
+        mCurTaskIdForUser.put(userId, candidateTaskId);
+        return candidateTaskId;
     }
 
     ActivityRecord resumedAppLocked() {
@@ -916,7 +950,7 @@
         final ArrayList<ActivityStack> stacks = mHomeStack.mStacks;
         for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
             final ActivityStack stack = stacks.get(stackNdx);
-            if (stack != focusedStack && isFrontStack(stack)) {
+            if (stack != focusedStack && isFrontStack(stack) && stack.isFocusable()) {
                 r = stack.topRunningActivityLocked();
                 if (r != null) {
                     return r;
@@ -1011,270 +1045,6 @@
         return resolveActivity(intent, rInfo, startFlags, profilerInfo);
     }
 
-    void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason) {
-        moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE, reason);
-        startActivityLocked(null /*caller*/, intent, null /*ephemeralIntent*/,
-                null /*resolvedType*/, aInfo, null /*rInfo*/, null /*voiceSession*/,
-                null /*voiceInteractor*/, null /*resultTo*/, null /*resultWho*/,
-                0 /*requestCode*/, 0 /*callingPid*/, 0 /*callingUid*/, null /*callingPackage*/,
-                0 /*realCallingPid*/, 0 /*realCallingUid*/, 0 /*startFlags*/, null /*options*/,
-                false /*ignoreTargetSecurity*/, false /*componentSpecified*/,  null /*outActivity*/,
-                null /*container*/, null /*inTask*/);
-        if (inResumeTopActivity) {
-            // If we are in resume section already, home activity will be initialized, but not
-            // resumed (to avoid recursive resume) and will stay that way until something pokes it
-            // again. We need to schedule another resume.
-            scheduleResumeTopActivities();
-        }
-    }
-
-    final int startActivityMayWait(IApplicationThread caller, int callingUid,
-            String callingPackage, Intent intent, String resolvedType,
-            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
-            IBinder resultTo, String resultWho, int requestCode, int startFlags,
-            ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,
-            Bundle bOptions, boolean ignoreTargetSecurity, int userId,
-            IActivityContainer iContainer, TaskRecord inTask) {
-        // Refuse possible leaked file descriptors
-        if (intent != null && intent.hasFileDescriptors()) {
-            throw new IllegalArgumentException("File descriptors passed in Intent");
-        }
-        boolean componentSpecified = intent.getComponent() != null;
-
-        // Save a copy in case ephemeral needs it
-        final Intent ephemeralIntent = new Intent(intent);
-        // Don't modify the client's object!
-        intent = new Intent(intent);
-
-        ResolveInfo rInfo = resolveIntent(intent, resolvedType, userId);
-        // Collect information about the target of the Intent.
-        ActivityInfo aInfo = resolveActivity(intent, rInfo, startFlags, profilerInfo);
-
-        ActivityOptions options = ActivityOptions.fromBundle(bOptions);
-        ActivityContainer container = (ActivityContainer)iContainer;
-        synchronized (mService) {
-            if (container != null && container.mParentActivity != null &&
-                    container.mParentActivity.state != RESUMED) {
-                // Cannot start a child activity if the parent is not resumed.
-                return ActivityManager.START_CANCELED;
-            }
-            final int realCallingPid = Binder.getCallingPid();
-            final int realCallingUid = Binder.getCallingUid();
-            int callingPid;
-            if (callingUid >= 0) {
-                callingPid = -1;
-            } else if (caller == null) {
-                callingPid = realCallingPid;
-                callingUid = realCallingUid;
-            } else {
-                callingPid = callingUid = -1;
-            }
-
-            final ActivityStack stack;
-            if (container == null || container.mStack.isOnHomeDisplay()) {
-                stack = mFocusedStack;
-            } else {
-                stack = container.mStack;
-            }
-            stack.mConfigWillChange = config != null && mService.mConfiguration.diff(config) != 0;
-            if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                    "Starting activity when config will change = " + stack.mConfigWillChange);
-
-            final long origId = Binder.clearCallingIdentity();
-
-            if (aInfo != null &&
-                    (aInfo.applicationInfo.privateFlags
-                            &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
-                // This may be a heavy-weight process!  Check to see if we already
-                // have another, different heavy-weight process running.
-                if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
-                    if (mService.mHeavyWeightProcess != null &&
-                            (mService.mHeavyWeightProcess.info.uid != aInfo.applicationInfo.uid ||
-                            !mService.mHeavyWeightProcess.processName.equals(aInfo.processName))) {
-                        int appCallingUid = callingUid;
-                        if (caller != null) {
-                            ProcessRecord callerApp = mService.getRecordForAppLocked(caller);
-                            if (callerApp != null) {
-                                appCallingUid = callerApp.info.uid;
-                            } else {
-                                Slog.w(TAG, "Unable to find app for caller " + caller
-                                      + " (pid=" + callingPid + ") when starting: "
-                                      + intent.toString());
-                                ActivityOptions.abort(options);
-                                return ActivityManager.START_PERMISSION_DENIED;
-                            }
-                        }
-
-                        IIntentSender target = mService.getIntentSenderLocked(
-                                ActivityManager.INTENT_SENDER_ACTIVITY, "android",
-                                appCallingUid, userId, null, null, 0, new Intent[] { intent },
-                                new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT
-                                | PendingIntent.FLAG_ONE_SHOT, null);
-
-                        Intent newIntent = new Intent();
-                        if (requestCode >= 0) {
-                            // Caller is requesting a result.
-                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
-                        }
-                        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
-                                new IntentSender(target));
-                        if (mService.mHeavyWeightProcess.activities.size() > 0) {
-                            ActivityRecord hist = mService.mHeavyWeightProcess.activities.get(0);
-                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
-                                    hist.packageName);
-                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
-                                    hist.task.taskId);
-                        }
-                        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
-                                aInfo.packageName);
-                        newIntent.setFlags(intent.getFlags());
-                        newIntent.setClassName("android",
-                                HeavyWeightSwitcherActivity.class.getName());
-                        intent = newIntent;
-                        resolvedType = null;
-                        caller = null;
-                        callingUid = Binder.getCallingUid();
-                        callingPid = Binder.getCallingPid();
-                        componentSpecified = true;
-                        rInfo = resolveIntent(intent, null /*resolvedType*/, userId);
-                        aInfo = rInfo != null ? rInfo.activityInfo : null;
-                        if (aInfo != null) {
-                            aInfo = mService.getActivityInfoForUser(aInfo, userId);
-                        }
-                    }
-                }
-            }
-
-            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);
-
-            Binder.restoreCallingIdentity(origId);
-
-            if (stack.mConfigWillChange) {
-                // If the caller also wants to switch to a new configuration,
-                // do so now.  This allows a clean switch, as we are waiting
-                // for the current activity to pause (so we will not destroy
-                // it), and have not yet started the next activity.
-                mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
-                        "updateConfiguration()");
-                stack.mConfigWillChange = false;
-                if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                        "Updating to new configuration after starting activity.");
-                mService.updateConfigurationLocked(config, null, false);
-            }
-
-            if (outResult != null) {
-                outResult.result = res;
-                if (res == ActivityManager.START_SUCCESS) {
-                    mWaitingActivityLaunched.add(outResult);
-                    do {
-                        try {
-                            mService.wait();
-                        } catch (InterruptedException e) {
-                        }
-                    } while (!outResult.timeout && outResult.who == null);
-                } else if (res == ActivityManager.START_TASK_TO_FRONT) {
-                    ActivityRecord r = stack.topRunningActivityLocked();
-                    if (r.nowVisible && r.state == RESUMED) {
-                        outResult.timeout = false;
-                        outResult.who = new ComponentName(r.info.packageName, r.info.name);
-                        outResult.totalTime = 0;
-                        outResult.thisTime = 0;
-                    } else {
-                        outResult.thisTime = SystemClock.uptimeMillis();
-                        mWaitingActivityVisible.add(outResult);
-                        do {
-                            try {
-                                mService.wait();
-                            } catch (InterruptedException e) {
-                            }
-                        } while (!outResult.timeout && outResult.who == null);
-                    }
-                }
-            }
-
-            return res;
-        }
-    }
-
-    final int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
-            Intent[] intents, String[] resolvedTypes, IBinder resultTo,
-            Bundle bOptions, int userId) {
-        if (intents == null) {
-            throw new NullPointerException("intents is null");
-        }
-        if (resolvedTypes == null) {
-            throw new NullPointerException("resolvedTypes is null");
-        }
-        if (intents.length != resolvedTypes.length) {
-            throw new IllegalArgumentException("intents are length different than resolvedTypes");
-        }
-
-
-        int callingPid;
-        if (callingUid >= 0) {
-            callingPid = -1;
-        } else if (caller == null) {
-            callingPid = Binder.getCallingPid();
-            callingUid = Binder.getCallingUid();
-        } else {
-            callingPid = callingUid = -1;
-        }
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            synchronized (mService) {
-                ActivityRecord[] outActivity = new ActivityRecord[1];
-                for (int i=0; i<intents.length; i++) {
-                    Intent intent = intents[i];
-                    if (intent == null) {
-                        continue;
-                    }
-
-                    // Refuse possible leaked file descriptors
-                    if (intent != null && intent.hasFileDescriptors()) {
-                        throw new IllegalArgumentException("File descriptors passed in Intent");
-                    }
-
-                    boolean componentSpecified = intent.getComponent() != null;
-
-                    // Don't modify the client's object!
-                    intent = new Intent(intent);
-
-                    // Collect information about the target of the Intent.
-                    ActivityInfo aInfo = resolveActivity(intent, resolvedTypes[i], 0, null, userId);
-                    // TODO: New, check if this is correct
-                    aInfo = mService.getActivityInfoForUser(aInfo, userId);
-
-                    if (aInfo != null &&
-                            (aInfo.applicationInfo.privateFlags
-                                    & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)  != 0) {
-                        throw new IllegalArgumentException(
-                                "FLAG_CANT_SAVE_STATE not supported here");
-                    }
-
-                    ActivityOptions options = ActivityOptions.fromBundle(
-                            i == intents.length - 1 ? bOptions : null);
-                    int res = startActivityLocked(caller, intent, null /*ephemeralIntent*/,
-                            resolvedTypes[i], aInfo, null /*rInfo*/, null, null, resultTo, null, -1,
-                            callingPid, callingUid, callingPackage, callingPid, callingUid, 0,
-                            options, false, componentSpecified, outActivity, null, null);
-                    if (res < 0) {
-                        return res;
-                    }
-
-                    resultTo = outActivity[0] != null ? outActivity[0].appToken : null;
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-        }
-
-        return ActivityManager.START_SUCCESS;
-    }
-
     final boolean realStartActivityLocked(ActivityRecord r,
             ProcessRecord app, boolean andResume, boolean checkConfig)
             throws RemoteException {
@@ -1435,14 +1205,12 @@
             // a resume.
             stack.minimalResumeActivityLocked(r);
         } else {
-            // This activity is not starting in the resumed state... which
-            // should look like we asked it to pause+stop (but remain visible),
-            // and it has done so and reported back the current icicle and
-            // other state.
+            // This activity is not starting in the resumed state... which should look like we asked
+            // it to pause+stop (but remain visible), and it has done so and reported back the
+            // current icicle and other state.
             if (DEBUG_STATES) Slog.v(TAG_STATES,
-                    "Moving to STOPPED: " + r + " (starting in stopped state)");
-            r.state = STOPPED;
-            r.stopped = true;
+                    "Moving to PAUSED: " + r + " (starting in paused state)");
+            r.state = PAUSED;
         }
 
         // Launch the new version setup screen if needed.  We do this -after-
@@ -1494,348 +1262,7 @@
                 "activity", r.intent.getComponent(), false, false, true);
     }
 
-    final int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
-            String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
-            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
-            IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
-            String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
-            ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
-            ActivityRecord[] outActivity, ActivityContainer container, TaskRecord inTask) {
-        int err = ActivityManager.START_SUCCESS;
-
-        ProcessRecord callerApp = null;
-        if (caller != null) {
-            callerApp = mService.getRecordForAppLocked(caller);
-            if (callerApp != null) {
-                callingPid = callerApp.pid;
-                callingUid = callerApp.info.uid;
-            } else {
-                Slog.w(TAG, "Unable to find app for caller " + caller
-                      + " (pid=" + callingPid + ") when starting: "
-                      + intent.toString());
-                err = ActivityManager.START_PERMISSION_DENIED;
-            }
-        }
-
-        final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
-
-        if (err == ActivityManager.START_SUCCESS) {
-            Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
-                    + "} from uid " + callingUid
-                    + " on display " + (container == null ? (mFocusedStack == null ?
-                            Display.DEFAULT_DISPLAY : mFocusedStack.mDisplayId) :
-                            (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY :
-                                    container.mActivityDisplay.mDisplayId)));
-        }
-
-        ActivityRecord sourceRecord = null;
-        ActivityRecord resultRecord = null;
-        if (resultTo != null) {
-            sourceRecord = isInAnyStackLocked(resultTo);
-            if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
-                    "Will send result to " + resultTo + " " + sourceRecord);
-            if (sourceRecord != null) {
-                if (requestCode >= 0 && !sourceRecord.finishing) {
-                    resultRecord = sourceRecord;
-                }
-            }
-        }
-
-        final int launchFlags = intent.getFlags();
-
-        if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
-            // Transfer the result target from the source activity to the new
-            // one being started, including any failures.
-            if (requestCode >= 0) {
-                ActivityOptions.abort(options);
-                return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
-            }
-            resultRecord = sourceRecord.resultTo;
-            if (resultRecord != null && !resultRecord.isInStackLocked()) {
-                resultRecord = null;
-            }
-            resultWho = sourceRecord.resultWho;
-            requestCode = sourceRecord.requestCode;
-            sourceRecord.resultTo = null;
-            if (resultRecord != null) {
-                resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
-            }
-            if (sourceRecord.launchedFromUid == callingUid) {
-                // The new activity is being launched from the same uid as the previous
-                // activity in the flow, and asking to forward its result back to the
-                // previous.  In this case the activity is serving as a trampoline between
-                // the two, so we also want to update its launchedFromPackage to be the
-                // same as the previous activity.  Note that this is safe, since we know
-                // these two packages come from the same uid; the caller could just as
-                // well have supplied that same package name itself.  This specifially
-                // deals with the case of an intent picker/chooser being launched in the app
-                // flow to redirect to an activity picked by the user, where we want the final
-                // activity to consider it to have been launched by the previous app activity.
-                callingPackage = sourceRecord.launchedFromPackage;
-            }
-        }
-
-        if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
-            // We couldn't find a class that can handle the given Intent.
-            // That's the end of that!
-            err = ActivityManager.START_INTENT_NOT_RESOLVED;
-        }
-
-        if (err == ActivityManager.START_SUCCESS && aInfo == null) {
-            // We couldn't find the specific class specified in the Intent.
-            // Also the end of the line.
-            err = ActivityManager.START_CLASS_NOT_FOUND;
-        }
-
-        if (err == ActivityManager.START_SUCCESS && sourceRecord != null
-                && sourceRecord.task.voiceSession != null) {
-            // If this activity is being launched as part of a voice session, we need
-            // to ensure that it is safe to do so.  If the upcoming activity will also
-            // be part of the voice session, we can only launch it if it has explicitly
-            // said it supports the VOICE category, or it is a part of the calling app.
-            if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0
-                    && sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
-                try {
-                    intent.addCategory(Intent.CATEGORY_VOICE);
-                    if (!AppGlobals.getPackageManager().activitySupportsIntent(
-                            intent.getComponent(), intent, resolvedType)) {
-                        Slog.w(TAG,
-                                "Activity being started in current voice task does not support voice: "
-                                + intent);
-                        err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
-                    }
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Failure checking voice capabilities", e);
-                    err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
-                }
-            }
-        }
-
-        if (err == ActivityManager.START_SUCCESS && voiceSession != null) {
-            // If the caller is starting a new voice session, just make sure the target
-            // is actually allowing it to run this way.
-            try {
-                if (!AppGlobals.getPackageManager().activitySupportsIntent(intent.getComponent(),
-                        intent, resolvedType)) {
-                    Slog.w(TAG,
-                            "Activity being started in new voice task does not support: "
-                            + intent);
-                    err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
-                }
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Failure checking voice capabilities", e);
-                err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
-            }
-        }
-
-        final ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack;
-
-        if (err != ActivityManager.START_SUCCESS) {
-            if (resultRecord != null) {
-                resultStack.sendActivityResultLocked(-1,
-                    resultRecord, resultWho, requestCode,
-                    Activity.RESULT_CANCELED, null);
-            }
-            ActivityOptions.abort(options);
-            return err;
-        }
-
-        boolean abort = !checkStartAnyActivityPermission(intent, aInfo, resultWho, requestCode,
-                callingPid, callingUid, callingPackage, ignoreTargetSecurity, callerApp,
-                resultRecord, resultStack);
-        abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
-                callingPid, resolvedType, aInfo.applicationInfo);
-
-        if (mService.mController != null) {
-            try {
-                // The Intent we give to the watcher has the extra data
-                // stripped off, since it can contain private information.
-                Intent watchIntent = intent.cloneFilter();
-                abort |= !mService.mController.activityStarting(watchIntent,
-                        aInfo.applicationInfo.packageName);
-            } catch (RemoteException e) {
-                mService.mController = null;
-            }
-        }
-
-        UserInfo user = getUserInfo(userId);
-        KeyguardManager km = (KeyguardManager) mService.mContext
-                .getSystemService(Context.KEYGUARD_SERVICE);
-        if (user.isManagedProfile()
-                && LockPatternUtils.isSeparateWorkChallengeEnabled()
-                && km.isDeviceLocked(userId)) {
-            IIntentSender target = mService.getIntentSenderLocked(
-                    ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
-                    Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
-                    new String[]{ resolvedType },
-                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
-                            | PendingIntent.FLAG_IMMUTABLE, null);
-            final int flags = intent.getFlags();
-            final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, user.id);
-            if (newIntent != null) {
-                intent = newIntent;
-                intent.setFlags(flags
-                        | Intent.FLAG_ACTIVITY_NEW_TASK
-                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-                intent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName);
-                intent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
-
-                resolvedType = null;
-                callingUid = realCallingUid;
-                callingPid = realCallingPid;
-
-                UserInfo parent = UserManager.get(mService.mContext).getProfileParent(userId);
-                rInfo = resolveIntent(intent, resolvedType, parent.id);
-                aInfo = resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
-            }
-        }
-
-        if (abort) {
-            if (resultRecord != null) {
-                resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
-                        Activity.RESULT_CANCELED, null);
-            }
-            // We pretend to the caller that it was really started, but
-            // they will just get a cancel result.
-            ActivityOptions.abort(options);
-            return ActivityManager.START_SUCCESS;
-        }
-
-        // If permissions need a review before any of the app components can run, we
-        // launch the review activity and pass a pending intent to start the activity
-        // we are to launching now after the review is completed.
-        if (Build.PERMISSIONS_REVIEW_REQUIRED && aInfo != null) {
-            if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
-                    aInfo.packageName, userId)) {
-                IIntentSender target = mService.getIntentSenderLocked(
-                        ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
-                        callingUid, userId, null, null, 0, new Intent[]{intent},
-                        new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT
-                                | PendingIntent.FLAG_ONE_SHOT, null);
-
-                final int flags = intent.getFlags();
-                Intent newIntent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
-                newIntent.setFlags(flags
-                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-                newIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName);
-                newIntent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
-                if (resultRecord != null) {
-                    newIntent.putExtra(Intent.EXTRA_RESULT_NEEDED, true);
-                }
-                intent = newIntent;
-
-                resolvedType = null;
-                callingUid = realCallingUid;
-                callingPid = realCallingPid;
-
-                rInfo = resolveIntent(intent, resolvedType, userId);
-                aInfo = resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
-
-                if (DEBUG_PERMISSIONS_REVIEW) {
-                    Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true,
-                            true, false) + "} from uid " + callingUid + " on display "
-                            + (container == null ? (mFocusedStack == null ?
-                            Display.DEFAULT_DISPLAY : mFocusedStack.mDisplayId) :
-                            (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY :
-                                    container.mActivityDisplay.mDisplayId)));
-                }
-            }
-        }
-
-        // If we have an ephemeral app, abort the process of launching the resolved intent.
-        // Instead, launch the ephemeral installer. Once the installer is finished, it
-        // starts either the intent we resolved here [on install error] or the ephemeral
-        // app [on install success].
-        if (rInfo != null && rInfo.ephemeralResolveInfo != null) {
-            // Create a pending intent to start the intent resolved here.
-            final IIntentSender failureTarget = mService.getIntentSenderLocked(
-                    ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
-                    Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
-                    new String[]{ resolvedType },
-                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
-                            | PendingIntent.FLAG_IMMUTABLE, null);
-
-            // Create a pending intent to start the ephemeral application; force it to be
-            // directed to the ephemeral package.
-            ephemeralIntent.setPackage(rInfo.ephemeralResolveInfo.getPackageName());
-            final IIntentSender ephemeralTarget = mService.getIntentSenderLocked(
-                    ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
-                    Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ ephemeralIntent },
-                    new String[]{ resolvedType },
-                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
-                    | PendingIntent.FLAG_IMMUTABLE, null);
-
-            int flags = intent.getFlags();
-            intent = new Intent();
-            intent.setFlags(flags
-                    | Intent.FLAG_ACTIVITY_NEW_TASK
-                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-            intent.putExtra(Intent.EXTRA_PACKAGE_NAME,
-                    rInfo.ephemeralResolveInfo.getPackageName());
-            intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, new IntentSender(failureTarget));
-            intent.putExtra(Intent.EXTRA_EPHEMERAL_SUCCESS, new IntentSender(ephemeralTarget));
-
-            resolvedType = null;
-            callingUid = realCallingUid;
-            callingPid = realCallingPid;
-
-            rInfo = rInfo.ephemeralInstaller;
-            aInfo = resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
-        }
-
-        ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
-                intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
-                requestCode, componentSpecified, voiceSession != null, this, container, options);
-        if (outActivity != null) {
-            outActivity[0] = r;
-        }
-
-        if (r.appTimeTracker == null && sourceRecord != null) {
-            // If the caller didn't specify an explicit time tracker, we want to continue
-            // tracking under any it has.
-            r.appTimeTracker = sourceRecord.appTimeTracker;
-        }
-
-        final ActivityStack stack = mFocusedStack;
-        if (voiceSession == null && (stack.mResumedActivity == null
-                || stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
-            if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
-                    realCallingPid, realCallingUid, "Activity start")) {
-                PendingActivityLaunch pal =  new PendingActivityLaunch(r,
-                        sourceRecord, startFlags, stack, callerApp);
-                mPendingActivityLaunches.add(pal);
-                ActivityOptions.abort(options);
-                return ActivityManager.START_SWITCHES_CANCELED;
-            }
-        }
-
-        if (mService.mDidAppSwitch) {
-            // This is the second allowed switch since we stopped switches,
-            // so now just generally allow switches.  Use case: user presses
-            // home (switches disabled, switch to home, mDidAppSwitch now true);
-            // user taps a home icon (coming from home so allowed, we hit here
-            // and now allow anyone to switch again).
-            mService.mAppSwitchesAllowedTime = 0;
-        } else {
-            mService.mDidAppSwitch = true;
-        }
-
-        doPendingActivityLaunchesLocked(false);
-
-        err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
-                startFlags, true, options, inTask);
-
-        if (err < 0) {
-            // If someone asked to have the keyguard dismissed on the next
-            // activity start, but we are not actually doing an activity
-            // switch...  just dismiss the keyguard now, because we
-            // probably want to see whatever is behind it.
-            notifyActivityDrawnForKeyguard();
-        }
-        return err;
-    }
-
-    private boolean checkStartAnyActivityPermission(Intent intent, ActivityInfo aInfo,
+    boolean checkStartAnyActivityPermission(Intent intent, ActivityInfo aInfo,
             String resultWho, int requestCode, int callingPid, int callingUid,
             String callingPackage, boolean ignoreTargetSecurity, ProcessRecord callerApp,
             ActivityRecord resultRecord, ActivityStack resultStack) {
@@ -1895,7 +1322,7 @@
         return true;
     }
 
-    private UserInfo getUserInfo(int userId) {
+    UserInfo getUserInfo(int userId) {
         final long identity = Binder.clearCallingIdentity();
         try {
             return UserManager.get(mService.mContext).getUserInfo(userId);
@@ -1973,848 +1400,20 @@
         return ACTIVITY_RESTRICTION_NONE;
     }
 
-    private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, Rect bounds,
-            int launchFlags) {
-        final TaskRecord task = r.task;
-        if (!(r.isApplicationActivity() || (task != null && task.isApplicationTask()))) {
-            return mHomeStack;
-        }
-
-        ActivityStack stack = getLaunchToSideStack(r, launchFlags, task);
-        if (stack != null) {
-            return stack;
-        }
-
-        if (task != null && task.stack != null) {
-            stack = task.stack;
-            if (stack.isOnHomeDisplay()) {
-                if (mFocusedStack != stack) {
-                    if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
-                            "computeStackFocus: Setting " + "focused stack to r=" + r
-                                    + " task=" + task);
-                } else {
-                    if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
-                            "computeStackFocus: Focused stack already=" + mFocusedStack);
-                }
-            }
-            return stack;
-        }
-
-        final ActivityContainer container = r.mInitialActivityContainer;
-        if (container != null) {
-            // The first time put it on the desired stack, after this put on task stack.
-            r.mInitialActivityContainer = null;
-            return container.mStack;
-        }
-
-        // The fullscreen stack can contain any task regardless of if the task is resizeable
-        // or not. So, we let the task go in the fullscreen task if it is the focus stack.
-        // If the freeform or docked stack has focus, and the activity to be launched is resizeable,
-        // we can also put it in the focused stack.
-        final int focusedStackId = mFocusedStack.mStackId;
-        final boolean canUseFocusedStack =
-                focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID
-                || focusedStackId == DOCKED_STACK_ID
-                || (focusedStackId == FREEFORM_WORKSPACE_STACK_ID && r.info.resizeable);
-        if (canUseFocusedStack
-                && (!newTask || mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
-            if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
-                    "computeStackFocus: Have a focused stack=" + mFocusedStack);
-            return mFocusedStack;
-        }
-
-        // We first try to put the task in the first dynamic stack.
-        final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;
-        for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            stack = homeDisplayStacks.get(stackNdx);
-            if (!StackId.isStaticStack(stack.mStackId)) {
-                if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
-                        "computeStackFocus: Setting focused stack=" + stack);
-                return stack;
-            }
-        }
-
-        // If there is no suitable dynamic stack then we figure out which static stack to use.
-        final int stackId = task != null ? task.getLaunchStackId() :
-                    bounds != null ? FREEFORM_WORKSPACE_STACK_ID :
-                                     FULLSCREEN_WORKSPACE_STACK_ID;
-        stack = getStack(stackId, CREATE_IF_NEEDED, ON_TOP);
-        if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
-                + r + " stackId=" + stack.mStackId);
-        return stack;
-    }
-
-    private ActivityStack getLaunchToSideStack(ActivityRecord r, int launchFlags, TaskRecord task) {
-        if ((launchFlags & FLAG_ACTIVITY_LAUNCH_TO_SIDE) == 0) {
-            return null;
-        }
-        // 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
-                : 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 getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
-        } 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 = getStack(DOCKED_STACK_ID);
-            if (stack != null && !stack.isStackVisibleLocked()) {
-                // There is a docked stack, but it isn't visible, so we can't launch into that.
-                return null;
-            } else {
-                return stack;
-            }
-        }
-    }
-
-    boolean setFocusedStack(ActivityRecord r, String reason) {
+    boolean moveActivityStackToFront(ActivityRecord r, String reason) {
         if (r == null) {
             // Not sure what you are trying to do, but it is not going to work...
             return false;
         }
         final TaskRecord task = r.task;
         if (task == null || task.stack == null) {
-            Slog.w(TAG, "Can't set focus stack for r=" + r + " task=" + task);
+            Slog.w(TAG, "Can't move stack to front for r=" + r + " task=" + task);
             return false;
         }
         task.stack.moveToFront(reason, task);
         return true;
     }
 
-    final int startActivityUncheckedLocked(final ActivityRecord r, ActivityRecord sourceRecord,
-            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
-            boolean doResume, ActivityOptions options, TaskRecord inTask) {
-        final Intent intent = r.intent;
-        final int callingUid = r.launchedFromUid;
-
-        boolean overrideBounds = false;
-        Rect newBounds = null;
-        if (options != null && (r.info.resizeable || (inTask != null && inTask.mResizeable))) {
-            if (canUseActivityOptionsLaunchBounds(options)) {
-                overrideBounds = true;
-                newBounds = options.getLaunchBounds();
-            }
-        }
-
-        // In some flows in to this function, we retrieve the task record and hold on to it
-        // without a lock before calling back in to here...  so the task at this point may
-        // not actually be in recents.  Check for that, and if it isn't in recents just
-        // consider it invalid.
-        if (inTask != null && !inTask.inRecents) {
-            Slog.w(TAG, "Starting activity in task not in recents: " + inTask);
-            inTask = null;
-        }
-
-        final boolean launchSingleTop = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP;
-        final boolean launchSingleInstance = r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE;
-        final boolean launchSingleTask = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK;
-
-        int launchFlags = intent.getFlags();
-        if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
-                (launchSingleInstance || launchSingleTask)) {
-            // We have a conflict between the Intent and the Activity manifest, manifest wins.
-            Slog.i(TAG, "Ignoring FLAG_ACTIVITY_NEW_DOCUMENT, launchMode is " +
-                    "\"singleInstance\" or \"singleTask\"");
-            launchFlags &=
-                    ~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_MULTIPLE_TASK);
-        } else {
-            switch (r.info.documentLaunchMode) {
-                case ActivityInfo.DOCUMENT_LAUNCH_NONE:
-                    break;
-                case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
-                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
-                    break;
-                case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
-                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
-                    break;
-                case ActivityInfo.DOCUMENT_LAUNCH_NEVER:
-                    launchFlags &= ~FLAG_ACTIVITY_MULTIPLE_TASK;
-                    break;
-            }
-        }
-
-        final boolean launchTaskBehind = r.mLaunchTaskBehind
-                && !launchSingleTask && !launchSingleInstance
-                && (launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
-
-        if (r.resultTo != null && (launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0
-                && r.resultTo.task.stack != null) {
-            // For whatever reason this activity is being launched into a new
-            // task...  yet the caller has requested a result back.  Well, that
-            // is pretty messed up, so instead immediately send back a cancel
-            // and let the new task continue launched as normal without a
-            // dependency on its originator.
-            Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
-            r.resultTo.task.stack.sendActivityResultLocked(-1,
-                    r.resultTo, r.resultWho, r.requestCode,
-                    Activity.RESULT_CANCELED, null);
-            r.resultTo = null;
-        }
-
-        if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
-            launchFlags |= FLAG_ACTIVITY_NEW_TASK;
-        }
-
-        // If we are actually going to launch in to a new task, there are some cases where
-        // we further want to do multiple task.
-        if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
-            if (launchTaskBehind
-                    || r.info.documentLaunchMode == ActivityInfo.DOCUMENT_LAUNCH_ALWAYS) {
-                launchFlags |= FLAG_ACTIVITY_MULTIPLE_TASK;
-            }
-        }
-
-        // We'll invoke onUserLeaving before onPause only if the launching
-        // activity did not explicitly state that this is an automated launch.
-        mUserLeaving = (launchFlags & Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
-        if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
-                "startActivity() => mUserLeaving=" + mUserLeaving);
-
-        // If the caller has asked not to resume at this point, we make note
-        // of this in the record so that we can skip it when trying to find
-        // the top running activity.
-        if (!doResume || !okToShowLocked(r)) {
-            r.delayedResume = true;
-            doResume = false;
-        }
-
-        ActivityRecord notTop =
-                (launchFlags & Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
-
-        // If the onlyIfNeeded flag is set, then we can do this if the activity
-        // being launched is the same as the one making the call...  or, as
-        // a special case, if we do not know the caller then we count the
-        // current top activity as the caller.
-        if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
-            ActivityRecord checkedCaller = sourceRecord;
-            if (checkedCaller == null) {
-                checkedCaller = mFocusedStack.topRunningNonDelayedActivityLocked(notTop);
-            }
-            if (!checkedCaller.realActivity.equals(r.realActivity)) {
-                // Caller is not the same as launcher, so always needed.
-                startFlags &= ~ActivityManager.START_FLAG_ONLY_IF_NEEDED;
-            }
-        }
-
-        boolean addingToTask = false;
-        TaskRecord reuseTask = null;
-
-        // If the caller is not coming from another activity, but has given us an
-        // explicit task into which they would like us to launch the new activity,
-        // then let's see about doing that.
-        if (sourceRecord == null && inTask != null && inTask.stack != null) {
-            final Intent baseIntent = inTask.getBaseIntent();
-            final ActivityRecord root = inTask.getRootActivity();
-            if (baseIntent == null) {
-                ActivityOptions.abort(options);
-                throw new IllegalArgumentException("Launching into task without base intent: "
-                        + inTask);
-            }
-
-            // If this task is empty, then we are adding the first activity -- it
-            // determines the root, and must be launching as a NEW_TASK.
-            if (launchSingleInstance || launchSingleTask) {
-                if (!baseIntent.getComponent().equals(r.intent.getComponent())) {
-                    ActivityOptions.abort(options);
-                    throw new IllegalArgumentException("Trying to launch singleInstance/Task "
-                            + r + " into different task " + inTask);
-                }
-                if (root != null) {
-                    ActivityOptions.abort(options);
-                    throw new IllegalArgumentException("Caller with inTask " + inTask
-                            + " has root " + root + " but target is singleInstance/Task");
-                }
-            }
-
-            // If task is empty, then adopt the interesting intent launch flags in to the
-            // activity being started.
-            if (root == null) {
-                final int flagsOfInterest = FLAG_ACTIVITY_NEW_TASK
-                        | FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT
-                        | Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
-                launchFlags = (launchFlags&~flagsOfInterest)
-                        | (baseIntent.getFlags()&flagsOfInterest);
-                intent.setFlags(launchFlags);
-                inTask.setIntent(r);
-                addingToTask = true;
-
-            // If the task is not empty and the caller is asking to start it as the root
-            // of a new task, then we don't actually want to start this on the task.  We
-            // will bring the task to the front, and possibly give it a new intent.
-            } else if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
-                addingToTask = false;
-
-            } else {
-                addingToTask = true;
-            }
-
-            reuseTask = inTask;
-        } else {
-            inTask = null;
-            // Launch ResolverActivity in the source task, so that it stays in the task
-            // bounds when in freeform workspace.
-            // Also put noDisplay activities in the source task. These by itself can
-            // be placed in any task/stack, however it could launch other activities
-            // like ResolverActivity, and we want those to stay in the original task.
-            if (r.isResolverActivity() || r.noDisplay) {
-                addingToTask = true;
-            }
-        }
-
-        if (inTask == null) {
-            if (sourceRecord == null) {
-                // This activity is not being started from another...  in this
-                // case we -always- start a new task.
-                if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && inTask == null) {
-                    Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
-                            "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
-                    launchFlags |= FLAG_ACTIVITY_NEW_TASK;
-                }
-            } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
-                // The original activity who is starting us is running as a single
-                // instance...  this new activity it is starting must go on its
-                // own task.
-                launchFlags |= FLAG_ACTIVITY_NEW_TASK;
-            } else if (launchSingleInstance || launchSingleTask) {
-                // The activity being started is a single instance...  it always
-                // gets launched into its own task.
-                launchFlags |= FLAG_ACTIVITY_NEW_TASK;
-            }
-        }
-
-        ActivityInfo newTaskInfo = null;
-        Intent newTaskIntent = null;
-        final ActivityStack sourceStack;
-        if (sourceRecord != null) {
-            if (sourceRecord.finishing) {
-                // If the source is finishing, we can't further count it as our source.  This
-                // is because the task it is associated with may now be empty and on its way out,
-                // so we don't want to blindly throw it in to that task.  Instead we will take
-                // the NEW_TASK flow and try to find a task for it. But save the task information
-                // so it can be used when creating the new task.
-                if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0) {
-                    Slog.w(TAG, "startActivity called from finishing " + sourceRecord
-                            + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
-                    launchFlags |= FLAG_ACTIVITY_NEW_TASK;
-                    newTaskInfo = sourceRecord.info;
-                    newTaskIntent = sourceRecord.task.intent;
-                }
-                sourceRecord = null;
-                sourceStack = null;
-            } else {
-                sourceStack = sourceRecord.task.stack;
-            }
-        } else {
-            sourceStack = null;
-        }
-
-        boolean movedHome = false;
-        ActivityStack targetStack;
-
-        intent.setFlags(launchFlags);
-        final boolean noAnimation = (launchFlags & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0;
-
-        ActivityRecord intentActivity = getReusableIntentActivity(r, inTask, intent,
-                launchSingleInstance, launchSingleTask, launchFlags);
-        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 the device would otherwise leave the locked task.
-            if (isLockTaskModeViolation(intentActivity.task,
-                    (launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
-                    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
-                showLockTaskToast();
-                Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
-                return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
-            }
-            if (r.task == null) {
-                r.task = intentActivity.task;
-            }
-            if (intentActivity.task.intent == null) {
-                // This task was started because of movement of the activity based on affinity...
-                // Now that we are actually launching it, we can assign the base intent.
-                intentActivity.task.setIntent(r);
-            }
-
-            targetStack = intentActivity.task.stack;
-            targetStack.mLastPausedActivity = null;
-            // If the target task is not in the front, then we need
-            // to bring it to the front...  except...  well, with
-            // SINGLE_TASK_LAUNCH it's not entirely clear.  We'd like
-            // to have the same behavior as if a new instance was
-            // being started, which means not bringing it to the front
-            // if the caller is not itself in the front.
-            final ActivityStack focusStack = getFocusedStack();
-            ActivityRecord curTop = (focusStack == null)
-                    ? null : focusStack.topRunningNonDelayedActivityLocked(notTop);
-            boolean movedToFront = false;
-            if (curTop != null && (curTop.task != intentActivity.task ||
-                    curTop.task != focusStack.topTask())) {
-                r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
-                if (sourceRecord == null || (sourceStack.topActivity() != null &&
-                        sourceStack.topActivity().task == sourceRecord.task)) {
-                    // We really do want to push this one into the user's face, right now.
-                    if (launchTaskBehind && sourceRecord != null) {
-                        intentActivity.setTaskToAffiliateWith(sourceRecord.task);
-                    }
-                    movedHome = true;
-                    final ActivityStack sideStack = getLaunchToSideStack(r, launchFlags, r.task);
-                    if (sideStack == null || sideStack == targetStack) {
-                        // 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.
-                        targetStack.moveTaskToFrontLocked(intentActivity.task, noAnimation,
-                        options, r.appTimeTracker, "bringingFoundTaskToFront");
-                        movedToFront = true;
-                    }
-                    if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
-                            == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
-                        // Caller wants to appear on home activity.
-                        intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
-                    }
-                    options = null;
-                }
-            }
-            if (!movedToFront && doResume) {
-                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Bring to front target: " + targetStack
-                        + " from " + intentActivity);
-                targetStack.moveToFront("intentActivityFound");
-            }
-
-            // If the caller has requested that the target task be
-            // reset, then do so.
-            if ((launchFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
-                intentActivity = targetStack.resetTaskIfNeededLocked(intentActivity, r);
-            }
-            if ((startFlags & ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
-                // We don't need to start a new activity, and
-                // the client said not to do anything if that
-                // is the case, so this is it!  And for paranoia, make
-                // sure we have correctly resumed the top activity.
-                if (doResume) {
-                    resumeTopActivitiesLocked(targetStack, null, options);
-
-                    // Make sure to notify Keyguard as well if we are not running an app
-                    // transition later.
-                    if (!movedToFront) {
-                        notifyActivityDrawnForKeyguard();
-                    }
-                } else {
-                    ActivityOptions.abort(options);
-                }
-                updateUserStackLocked(r.userId, targetStack);
-                return ActivityManager.START_RETURN_INTENT_TO_CALLER;
-            }
-            if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
-                    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
-                // The caller has requested to completely replace any
-                // existing task with its new activity.  Well that should
-                // not be too hard...
-                reuseTask = intentActivity.task;
-                reuseTask.performClearTaskLocked();
-                reuseTask.setIntent(r);
-            } else if ((launchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
-                    || launchSingleInstance || launchSingleTask) {
-                // In this situation we want to remove all activities
-                // from the task up to the one being started.  In most
-                // cases this means we are resetting the task to its
-                // initial state.
-                ActivityRecord top = intentActivity.task.performClearTaskLocked(r, launchFlags);
-                if (top != null) {
-                    if (top.frontOfTask) {
-                        // Activity aliases may mean we use different
-                        // intents for the top activity, so make sure
-                        // the task now has the identity of the new
-                        // intent.
-                        top.task.setIntent(r);
-                    }
-                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
-                    top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
-                } else {
-                    // A special case: we need to start the activity because it is not
-                    // currently running, and the caller has asked to clear the current
-                    // task to have this activity at the top.
-                    addingToTask = true;
-                    // Now pretend like this activity is being started by the top of its
-                    // task, so it is put in the right place.
-                    sourceRecord = intentActivity;
-                    TaskRecord task = sourceRecord.task;
-                    if (task != null && task.stack == null) {
-                        // Target stack got cleared when we all activities were removed
-                        // above. Go ahead and reset it.
-                        targetStack = computeStackFocus(
-                                sourceRecord, false /* newTask */, null /* bounds */, launchFlags);
-                        targetStack.addTask(task,
-                                !launchTaskBehind /* toTop */, "startActivityUnchecked");
-                    }
-
-                }
-            } else if (r.realActivity.equals(intentActivity.task.realActivity)) {
-                // In this case the top activity on the task is the
-                // same as the one being launched, so we take that
-                // as a request to bring the task to the foreground.
-                // If the top activity in the task is the root
-                // activity, deliver this new intent to it if it
-                // desires.
-                if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 || launchSingleTop)
-                        && intentActivity.realActivity.equals(r.realActivity)) {
-                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r,
-                            intentActivity.task);
-                    if (intentActivity.frontOfTask) {
-                        intentActivity.task.setIntent(r);
-                    }
-                    intentActivity.deliverNewIntentLocked(callingUid, r.intent,
-                            r.launchedFromPackage);
-                } else if (!r.intent.filterEquals(intentActivity.task.intent)) {
-                    // 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.
-                    addingToTask = true;
-                    sourceRecord = intentActivity;
-                }
-            } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
-                // In this case an activity is being launched in to an
-                // existing task, without resetting that task.  This
-                // is typically the situation of launching an activity
-                // from a notification or shortcut.  We want to place
-                // the new activity on top of the current task.
-                addingToTask = true;
-                sourceRecord = intentActivity;
-            } else if (!intentActivity.task.rootWasReset) {
-                // In this case we are launching in to an existing task
-                // that has not yet been started from its front door.
-                // The current task has been brought to the front.
-                // Ideally, we'd probably like to place this new task
-                // at the bottom of its stack, but that's a little hard
-                // to do with the current organization of the code so
-                // for now we'll just drop it.
-                intentActivity.task.setIntent(r);
-            }
-            if (!addingToTask && reuseTask == null) {
-                // We didn't do anything...  but it was needed (a.k.a., client
-                // don't use that intent!)  And for paranoia, make
-                // sure we have correctly resumed the top activity.
-                if (doResume) {
-                    targetStack.resumeTopActivityLocked(null, options);
-                    if (!movedToFront) {
-                        // Make sure to notify Keyguard as well if we are not running an app
-                        // transition later.
-                        notifyActivityDrawnForKeyguard();
-                    }
-                } else {
-                    ActivityOptions.abort(options);
-                }
-                updateUserStackLocked(r.userId, targetStack);
-                return ActivityManager.START_TASK_TO_FRONT;
-            }
-        }
-
-        //String uri = r.intent.toURI();
-        //Intent intent2 = new Intent(uri);
-        //Slog.i(TAG, "Given intent: " + r.intent);
-        //Slog.i(TAG, "URI is: " + uri);
-        //Slog.i(TAG, "To intent: " + intent2);
-
-        if (r.packageName != null) {
-            // If the activity being launched is the same as the one currently
-            // at the top, then we need to check if it should only be launched
-            // once.
-            ActivityStack topStack = mFocusedStack;
-            ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(notTop);
-            final boolean dontStart = top != null && r.resultTo == null
-                    && top.realActivity.equals(r.realActivity) && top.userId == r.userId
-                    && top.app != null && top.app.thread != null
-                    && ((launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
-                            || launchSingleTop || launchSingleTask);
-            if (dontStart) {
-                ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
-                // For paranoia, make sure we have correctly resumed the top activity.
-                topStack.mLastPausedActivity = null;
-                if (doResume) {
-                    resumeTopActivitiesLocked();
-                }
-                ActivityOptions.abort(options);
-                if ((startFlags & ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
-                    // We don't need to start a new activity, and the client said not to do
-                    // anything if that is the case, so this is it!
-                    return ActivityManager.START_RETURN_INTENT_TO_CALLER;
-                }
-                top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
-                return ActivityManager.START_DELIVERED_TO_TOP;
-            }
-        } else {
-            if (r.resultTo != null && r.resultTo.task.stack != null) {
-                r.resultTo.task.stack.sendActivityResultLocked(-1, r.resultTo, r.resultWho,
-                        r.requestCode, Activity.RESULT_CANCELED, null);
-            }
-            ActivityOptions.abort(options);
-            return ActivityManager.START_CLASS_NOT_FOUND;
-        }
-
-        boolean newTask = false;
-        boolean keepCurTransition = false;
-
-        TaskRecord taskToAffiliate = launchTaskBehind && sourceRecord != null ?
-                sourceRecord.task : null;
-
-        // Should this be considered a new task?
-        if (r.resultTo == null && inTask == null && !addingToTask
-                && (launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
-            newTask = true;
-            targetStack = computeStackFocus(r, newTask, newBounds, launchFlags);
-            if (doResume) {
-                targetStack.moveToFront("startingNewTask");
-            }
-
-            if (reuseTask == null) {
-                r.setTask(targetStack.createTaskRecord(getNextTaskId(),
-                        newTaskInfo != null ? newTaskInfo : r.info,
-                        newTaskIntent != null ? newTaskIntent : intent,
-                        voiceSession, voiceInteractor, !launchTaskBehind /* toTop */),
-                        taskToAffiliate);
-                if (overrideBounds) {
-                    r.task.updateOverrideConfiguration(newBounds);
-                }
-                if (DEBUG_TASKS) Slog.v(TAG_TASKS,
-                        "Starting new activity " + r + " in new task " + r.task);
-            } else {
-                r.setTask(reuseTask, taskToAffiliate);
-            }
-            if (isLockTaskModeViolation(r.task)) {
-                Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
-                return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
-            }
-            if (!movedHome) {
-                if ((launchFlags &
-                        (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
-                        == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
-                    // Caller wants to appear on home activity, so before starting
-                    // their own activity we will bring home to the front.
-                    r.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
-                }
-            }
-        } else if (sourceRecord != null) {
-            final TaskRecord sourceTask = sourceRecord.task;
-            if (isLockTaskModeViolation(sourceTask)) {
-                Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
-                return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
-            }
-            targetStack = null;
-            if (sourceTask.stack.topTask() != sourceTask) {
-                // We only want to allow changing stack if the target task is not the top one,
-                // otherwise we would move the launching task to the other side, rather than show
-                // two side by side.
-                targetStack = getLaunchToSideStack(r, launchFlags, r.task);
-            }
-            if (targetStack == null) {
-                targetStack = sourceTask.stack;
-            } else if (targetStack != sourceTask.stack) {
-                moveTaskToStackLocked(sourceTask.taskId, targetStack.mStackId, ON_TOP,
-                        FORCE_FOCUS, "launchToSide", !ANIMATE);
-            }
-            if (doResume) {
-                targetStack.moveToFront("sourceStackToFront");
-            }
-            final TaskRecord topTask = targetStack.topTask();
-            if (topTask != sourceTask) {
-                targetStack.moveTaskToFrontLocked(sourceTask, noAnimation, options,
-                        r.appTimeTracker, "sourceTaskToFront");
-            }
-            if (!addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
-                // In this case, we are adding the activity to an existing
-                // task, but the caller has asked to clear that task if the
-                // activity is already running.
-                ActivityRecord top = sourceTask.performClearTaskLocked(r, launchFlags);
-                keepCurTransition = true;
-                if (top != null) {
-                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
-                    top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
-                    // For paranoia, make sure we have correctly
-                    // resumed the top activity.
-                    targetStack.mLastPausedActivity = null;
-                    if (doResume) {
-                        targetStack.resumeTopActivityLocked(null);
-                    }
-                    ActivityOptions.abort(options);
-                    return ActivityManager.START_DELIVERED_TO_TOP;
-                }
-            } else if (!addingToTask &&
-                    (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
-                // In this case, we are launching an activity in our own task
-                // that may already be running somewhere in the history, and
-                // we want to shuffle it to the front of the stack if so.
-                final ActivityRecord top = sourceTask.findActivityInHistoryLocked(r);
-                if (top != null) {
-                    final TaskRecord task = top.task;
-                    task.moveActivityToFrontLocked(top);
-                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, task);
-                    top.updateOptionsLocked(options);
-                    top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
-                    targetStack.mLastPausedActivity = null;
-                    if (doResume) {
-                        targetStack.resumeTopActivityLocked(null);
-                    }
-                    return ActivityManager.START_DELIVERED_TO_TOP;
-                }
-            }
-            // An existing activity is starting this new activity, so we want
-            // to keep the new one in the same task as the one that is starting
-            // it.
-            r.setTask(sourceTask, null);
-            if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + r
-                    + " in existing task " + r.task + " from source " + sourceRecord);
-
-        } else if (inTask != null) {
-            // The caller is asking that the new activity be started in an explicit
-            // task it has provided to us.
-            if (isLockTaskModeViolation(inTask)) {
-                Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
-                return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
-            }
-            if (overrideBounds) {
-                inTask.updateOverrideConfiguration(newBounds);
-                int stackId = inTask.getLaunchStackId();
-                if (stackId != inTask.stack.mStackId) {
-                    moveTaskToStackUncheckedLocked(
-                            inTask, stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront");
-                }
-            }
-            targetStack = inTask.stack;
-            targetStack.moveTaskToFrontLocked(inTask, noAnimation, options, r.appTimeTracker,
-                    "inTaskToFront");
-
-            // Check whether we should actually launch the new activity in to the task,
-            // or just reuse the current activity on top.
-            ActivityRecord top = inTask.getTopActivity();
-            if (top != null && top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
-                if ((launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
-                        || launchSingleTop || launchSingleTask) {
-                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
-                    if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
-                        // We don't need to start a new activity, and
-                        // the client said not to do anything if that
-                        // is the case, so this is it!
-                        return ActivityManager.START_RETURN_INTENT_TO_CALLER;
-                    }
-                    top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
-                    return ActivityManager.START_DELIVERED_TO_TOP;
-                }
-            }
-
-            if (!addingToTask) {
-                // We don't actually want to have this activity added to the task, so just
-                // stop here but still tell the caller that we consumed the intent.
-                ActivityOptions.abort(options);
-                return ActivityManager.START_TASK_TO_FRONT;
-            }
-
-            r.setTask(inTask, null);
-            if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + r
-                    + " in explicit task " + r.task);
-
-        } else {
-            // This not being started from an existing activity, and not part
-            // of a new task...  just put it in the top task, though these days
-            // this case should never happen.
-            targetStack = computeStackFocus(r, newTask, null /* bounds */, launchFlags);
-            if (doResume) {
-                targetStack.moveToFront("addingToTopTask");
-            }
-            ActivityRecord prev = targetStack.topActivity();
-            r.setTask(prev != null ? prev.task : targetStack.createTaskRecord(getNextTaskId(),
-                            r.info, intent, null, null, true), null);
-            mWindowManager.moveTaskToTop(r.task.taskId);
-            if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + r
-                    + " in new guessed " + r.task);
-        }
-
-        mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
-                intent, r.getUriPermissionsLocked(), r.userId);
-
-        if (sourceRecord != null && sourceRecord.isRecentsActivity()) {
-            r.task.setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);
-        }
-        if (newTask) {
-            EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.userId, r.task.taskId);
-        }
-        ActivityStack.logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
-        targetStack.mLastPausedActivity = null;
-        targetStack.startActivityLocked(r, newTask, keepCurTransition, options);
-        if (doResume) {
-            if (!launchTaskBehind) {
-                mService.setFocusedActivityLocked(r, "startedActivity");
-            }
-            resumeTopActivitiesLocked(targetStack, r, options);
-        } else {
-            targetStack.addRecentActivityLocked(r);
-        }
-        updateUserStackLocked(r.userId, targetStack);
-
-        if (!r.task.mResizeable && isStackDockedInEffect(targetStack.mStackId)) {
-            showNonResizeableDockToast(r.task.taskId);
-        }
-
-        return ActivityManager.START_SUCCESS;
-    }
-
-    /**
-     * Decide whether the new activity should be inserted into an existing task. Returns null if not
-     * or an ActivityRecord with the task into which the new activity should be added.
-     */
-    private ActivityRecord getReusableIntentActivity(ActivityRecord r, TaskRecord inTask, Intent intent,
-            boolean launchSingleInstance, boolean launchSingleTask, int launchFlags) {
-        // We may want to try to place the new activity in to an existing task.  We always
-        // do this if the target activity is singleTask or singleInstance; we will also do
-        // this if NEW_TASK has been requested, and there is not an additional qualifier telling
-        // us to still place it in a new task: multi task, always doc mode, or being asked to
-        // launch this as a new task behind the current one.
-        boolean putIntoExistingTask = ((launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
-                (launchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
-                || launchSingleInstance || launchSingleTask;
-        // If bring to front is requested, and no result is requested and we have not
-        // been given an explicit task to launch in to, and
-        // we can find a task that was started with this same
-        // component, then instead of launching bring that one to the front.
-        putIntoExistingTask &= inTask == null && r.resultTo == null;
-        ActivityRecord intentActivity = null;
-        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.
-            intentActivity = launchSingleInstance ?
-                    findActivityLocked(intent, r.info) : findTaskLocked(r);
-        }
-        return intentActivity;
-    }
-
-    final void doPendingActivityLaunchesLocked(boolean doResume) {
-        while (!mPendingActivityLaunches.isEmpty()) {
-            PendingActivityLaunch pal = mPendingActivityLaunches.remove(0);
-
-            try {
-                startActivityUncheckedLocked(pal.r, pal.sourceRecord, null, null, pal.startFlags,
-                        doResume && mPendingActivityLaunches.isEmpty(), null, null);
-            } catch (Exception e) {
-                Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e);
-                pal.sendErrorResult(e.getMessage());
-            }
-        }
-    }
-
-    void removePendingActivityLaunchesLocked(ActivityStack stack) {
-        for (int palNdx = mPendingActivityLaunches.size() - 1; palNdx >= 0; --palNdx) {
-            PendingActivityLaunch pal = mPendingActivityLaunches.get(palNdx);
-            if (pal.stack == stack) {
-                mPendingActivityLaunches.remove(palNdx);
-            }
-        }
-    }
-
     void setLaunchSource(int uid) {
         mLaunchingActivity.setWorkSource(new WorkSource(uid));
     }
@@ -2964,7 +1563,7 @@
         //mWindowManager.dump();
 
         if (activityRemoved) {
-            resumeTopActivitiesLocked();
+            resumeFocusedStackTopActivityLocked();
         }
 
         return r;
@@ -3057,46 +1656,34 @@
         }
     }
 
-    boolean resumeTopActivitiesLocked() {
-        return resumeTopActivitiesLocked(null, null, null);
+    boolean resumeFocusedStackTopActivityLocked() {
+        return resumeFocusedStackTopActivityLocked(null, null, null);
     }
 
-    boolean resumeTopActivitiesLocked(
+    boolean resumeFocusedStackTopActivityLocked(
             ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
-        if (targetStack == null) {
-            targetStack = mFocusedStack;
+        if (targetStack != null && isFocusedStack(targetStack)) {
+            return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
         }
-        // Do targetStack first.
-        boolean result = false;
-        if (isFocusedStack(targetStack)) {
-            result = targetStack.resumeTopActivityLocked(target, targetOptions);
-        }
-
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
-                if (stack == targetStack) {
-                    // Already started above.
-                    continue;
-                }
-                if (isFocusedStack(stack)) {
-                    stack.resumeTopActivityLocked(null);
-                }
-            }
-        }
-        return result;
+        mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
+        return false;
     }
 
-    void finishTopRunningActivityLocked(ProcessRecord app, String reason) {
+    TaskRecord finishTopRunningActivityLocked(ProcessRecord app, String reason) {
+        TaskRecord finishedTask = null;
+        ActivityStack focusedStack = getFocusedStack();
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
             final int numStacks = stacks.size();
             for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
-                stack.finishTopRunningActivityLocked(app, reason);
+                TaskRecord t = stack.finishTopRunningActivityLocked(app, reason);
+                if (stack == focusedStack || finishedTask == null) {
+                    finishedTask = t;
+                }
             }
         }
+        return finishedTask;
     }
 
     void finishVoiceTask(IVoiceInteractionSession session) {
@@ -3127,20 +1714,29 @@
         }
 
         if (task.mResizeable && options != null) {
-            if (canUseActivityOptionsLaunchBounds(options)) {
-                Rect bounds = options.getLaunchBounds();
+            int stackId = options.getLaunchStackId();
+            if (canUseActivityOptionsLaunchBounds(options, stackId)) {
+                final Rect bounds = TaskRecord.validateBounds(options.getLaunchBounds());
                 task.updateOverrideConfiguration(bounds);
-                final int stackId = task.getLaunchStackId();
+                if (stackId == INVALID_STACK_ID) {
+                    stackId = task.getLaunchStackId();
+                }
                 if (stackId != task.stack.mStackId) {
                     moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, !FORCE_FOCUS, reason);
                     // moveTaskToStackUncheckedLocked() should already placed the task on top,
                     // still need moveTaskToFrontLocked() below for any transition settings.
                 }
-                // 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,
-                        false /*relayout*/, false /*forced*/);
+                if (StackId.resizeStackWithLaunchBounds(stackId)) {
+                    resizeStackLocked(stackId, bounds,
+                            null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
+                            !PRESERVE_WINDOWS, true /* allowResizeInDockedMode */);
+                } else {
+                    // 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,
+                            false /* relayout */, false /* forced */);
+                }
             }
         }
 
@@ -3152,10 +1748,14 @@
                 "findTaskToMoveToFront: moved to front of stack=" + task.stack);
     }
 
-    private boolean canUseActivityOptionsLaunchBounds(ActivityOptions options) {
+    boolean canUseActivityOptionsLaunchBounds(ActivityOptions options, int launchStackId) {
         // We use the launch bounds in the activity options is the device supports freeform
-        // window management.
-        return options.hasLaunchBounds() && mService.mSupportsFreeformWindowManagement;
+        // window management or is launching into the pinned stack.
+        if (!options.hasLaunchBounds()) {
+            return false;
+        }
+        return (mService.mSupportsPictureInPicture && launchStackId == PINNED_STACK_ID)
+                || mService.mSupportsFreeformWindowManagement;
     }
 
     ActivityStack getStack(int stackId) {
@@ -3252,16 +1852,20 @@
         }
     }
 
-    void resizeStackLocked(int stackId, Rect bounds, boolean preserveWindows,
-            boolean allowResizeInDockedMode) {
+    void resizeStackLocked(int stackId, Rect bounds, Rect tempTaskBounds, Rect tempTaskInsetBounds,
+            boolean preserveWindows, boolean allowResizeInDockedMode) {
+        if (stackId == DOCKED_STACK_ID) {
+            resizeDockedStackLocked(bounds, tempTaskBounds, tempTaskInsetBounds, null, null,
+                    preserveWindows);
+            return;
+        }
         final ActivityStack stack = getStack(stackId);
         if (stack == null) {
             Slog.w(TAG, "resizeStack: stackId " + stackId + " not found.");
             return;
         }
 
-        if (!allowResizeInDockedMode
-                && stackId != DOCKED_STACK_ID && getStack(DOCKED_STACK_ID) != null) {
+        if (!allowResizeInDockedMode && getStack(DOCKED_STACK_ID) != null) {
             // If the docked stack exist we don't allow resizes of stacks not caused by the docked
             // stack size changing so things don't get out of sync.
             return;
@@ -3270,100 +1874,145 @@
         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stackId);
         mWindowManager.deferSurfaceLayout();
         try {
-
-            if (bounds != null && mWindowManager.isFullscreenBounds(stackId, bounds)) {
-                // The bounds passed in corresponds to the fullscreen bounds which we normally
-                // represent with null. Go ahead and set it to null so that all tasks configuration
-                // can have the right fullscreen state.
-                bounds = null;
-            }
-
-            ActivityRecord r = stack.topRunningActivityLocked();
-
-            mTmpBounds.clear();
-            mTmpConfigs.clear();
-            ArrayList<TaskRecord> tasks = stack.getAllTasks();
-            for (int i = tasks.size() - 1; i >= 0; i--) {
-                TaskRecord task = tasks.get(i);
-                if (task.mResizeable) {
-                    if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
-                        // For freeform stack we don't adjust the size of the tasks to match that
-                        // of the stack, but we do try to make sure the tasks are still contained
-                        // with the bounds of the stack.
-                        tempRect2.set(task.mBounds);
-                        fitWithinBounds(tempRect2, bounds);
-                        task.updateOverrideConfiguration(tempRect2);
-                    } else {
-                        task.updateOverrideConfiguration(bounds);
-                    }
-                }
-
-                mTmpConfigs.put(task.taskId, task.mOverrideConfig);
-                mTmpBounds.put(task.taskId, task.mBounds);
-            }
-            stack.mFullscreen = mWindowManager.resizeStack(stackId, bounds, mTmpConfigs, mTmpBounds);
-            if (stack.mStackId == DOCKED_STACK_ID) {
-                // Dock stack funness...Yay!
-                if (stack.mFullscreen) {
-                    // The dock stack went fullscreen which is kinda like dismissing it.
-                    // In this case we make all other static stacks fullscreen and move all
-                    // docked stack tasks to the fullscreen stack.
-                    for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
-                        if (StackId.isResizeableByDockedStack(i) && getStack(i) != null) {
-                            resizeStackLocked(i, null, preserveWindows, true);
-                        }
-                    }
-
-                    final int count = tasks.size();
-                    for (int i = 0; i < count; i++) {
-                        moveTaskToStackLocked(tasks.get(i).taskId,
-                                FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, FORCE_FOCUS, "resizeStack",
-                                false /* animate */);
-                    }
-
-                    // stack shouldn't contain anymore activities, so nothing to resume.
-                    r = null;
-                } else {
-                    // Docked stacks occupy a dedicated region on screen so the size of all other
-                    // 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);
-
-                    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, PRESERVE_WINDOWS, true);
-                            }
-                        }
-                    }
-                }
-                // Since we are resizing the stack, all other operations should strive to preserve
-                // windows.
-                preserveWindows = true;
-            }
-            stack.setBounds(bounds);
-
-            if (r != null) {
-                final boolean updated = stack.ensureActivityConfigurationLocked(r, 0, preserveWindows);
-                // And we need to make sure at this point that all other activities
-                // are made visible with the correct configuration.
-                ensureActivitiesVisibleLocked(r, 0, preserveWindows);
-                if (!updated) {
-                    resumeTopActivitiesLocked(stack, null, null);
-                }
-            }
+            resizeStackUncheckedLocked(stack, bounds, tempTaskBounds, tempTaskInsetBounds);
+            ensureConfigurationAndResume(stack, stack.topRunningActivityLocked(), preserveWindows);
         } finally {
             mWindowManager.continueSurfaceLayout();
             Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
         }
     }
 
-    void resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow) {
+    private void resizeStackUncheckedLocked(ActivityStack stack, Rect bounds, Rect tempTaskBounds,
+            Rect tempTaskInsetBounds) {
+        if (bounds != null && mWindowManager.isFullscreenBounds(stack.mStackId, bounds)) {
+            // The bounds passed in corresponds to the fullscreen bounds which we normally
+            // represent with null. Go ahead and set it to null so that all tasks configuration
+            // can have the right fullscreen state.
+            bounds = null;
+        }
+        bounds = TaskRecord.validateBounds(bounds);
+
+        mTmpBounds.clear();
+        mTmpConfigs.clear();
+        mTmpInsetBounds.clear();
+        ArrayList<TaskRecord> tasks = stack.getAllTasks();
+        for (int i = tasks.size() - 1; i >= 0; i--) {
+            TaskRecord task = tasks.get(i);
+            if (task.mResizeable) {
+                if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
+                    // For freeform stack we don't adjust the size of the tasks to match that
+                    // of the stack, but we do try to make sure the tasks are still contained
+                    // with the bounds of the stack.
+                    tempRect2.set(task.mBounds);
+                    fitWithinBounds(tempRect2, bounds);
+                    task.updateOverrideConfiguration(tempRect2);
+                } else {
+                    task.updateOverrideConfiguration(
+                            tempTaskBounds != null ? tempTaskBounds : bounds);
+                }
+            }
+
+            mTmpConfigs.put(task.taskId, task.mOverrideConfig);
+            mTmpBounds.put(task.taskId, task.mBounds);
+            if (tempTaskInsetBounds != null) {
+                mTmpInsetBounds.put(task.taskId, tempTaskInsetBounds);
+            }
+        }
+
+        // We might trigger a configuration change. Save the current task bounds for freezing.
+        mWindowManager.prepareFreezingTaskBounds(stack.mStackId);
+        stack.mFullscreen = mWindowManager.resizeStack(stack.mStackId, bounds, mTmpConfigs,
+                mTmpBounds, mTmpInsetBounds);
+        stack.setBounds(bounds);
+    }
+
+    private void ensureConfigurationAndResume(ActivityStack stack, ActivityRecord r,
+            boolean preserveWindows) {
+        if (r == null) {
+            return;
+        }
+        final boolean updated = stack.ensureActivityConfigurationLocked(r, 0,
+                preserveWindows);
+        // And we need to make sure at this point that all other activities
+        // are made visible with the correct configuration.
+        ensureActivitiesVisibleLocked(r, 0, preserveWindows);
+        if (!updated) {
+            resumeFocusedStackTopActivityLocked();
+        }
+    }
+
+    void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds,
+            Rect tempDockedTaskInsetBounds,
+            Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds, boolean preserveWindows) {
+        final ActivityStack stack = getStack(DOCKED_STACK_ID);
+        if (stack == null) {
+            Slog.w(TAG, "resizeDockedStackLocked: docked stack not found");
+            return;
+        }
+
+        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeDockedStack");
+        mWindowManager.deferSurfaceLayout();
+        try {
+            ActivityRecord r = stack.topRunningActivityLocked();
+            resizeStackUncheckedLocked(stack, dockedBounds, tempDockedTaskBounds,
+                    tempDockedTaskInsetBounds);
+
+            if (stack.mFullscreen) {
+                // The dock stack went fullscreen which is kinda like dismissing it.
+                // In this case we make all other static stacks fullscreen and move all
+                // docked stack tasks to the fullscreen stack.
+                for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
+                    if (StackId.isResizeableByDockedStack(i) && getStack(i) != null) {
+                        resizeStackLocked(i, null, null, null, preserveWindows,
+                                true /* allowResizeInDockedMode */);
+                    }
+                }
+
+                ArrayList<TaskRecord> tasks = stack.getAllTasks();
+                final int count = tasks.size();
+                for (int i = 0; i < count; i++) {
+                    moveTaskToStackLocked(tasks.get(i).taskId,
+                            FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, FORCE_FOCUS, "resizeStack",
+                            false /* animate */);
+                }
+
+                // stack shouldn't contain anymore activities, so nothing to resume.
+                r = null;
+            } else {
+                // Docked stacks occupy a dedicated region on screen so the size of all other
+                // 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 /* ignoreVisibilityOnKeyguardShowing */);
+                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,
+                                    true /* allowResizeInDockedMode */);
+                        }
+                    }
+                }
+            }
+            ensureConfigurationAndResume(stack, r, preserveWindows);
+        } finally {
+            mWindowManager.continueSurfaceLayout();
+            Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+        }
+
+        mResizeDockedStackTimeout.notifyResizing(dockedBounds,
+                tempDockedTaskBounds != null
+                || tempDockedTaskInsetBounds != null
+                || tempOtherTaskBounds != null
+                || tempOtherTaskInsetBounds != null);
+    }
+
+    boolean resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow) {
         if (!task.mResizeable) {
             Slog.w(TAG, "resizeTask: task " + task + " not resizeable.");
-            return;
+            return true;
         }
 
         adjustForMinimalTaskDimensions(task, bounds);
@@ -3371,10 +2020,11 @@
         // If this is a forced resize, let it go through even if the bounds is not changing,
         // as we might need a relayout due to surface size change (to/from fullscreen).
         final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
-        if (task.mBounds != null && task.mBounds.equals(bounds) && !forced) {
+        if (Objects.equals(task.mBounds, bounds) && !forced) {
             // Nothing to do here...
-            return;
+            return true;
         }
+        bounds = TaskRecord.validateBounds(bounds);
 
         if (!mWindowManager.isValidTaskId(task.taskId)) {
             // Task doesn't exist in window manager yet (e.g. was restored from recents).
@@ -3385,7 +2035,7 @@
                 // re-restore the task so it can have the proper stack association.
                 restoreRecentTaskLocked(task, FREEFORM_WORKSPACE_STACK_ID);
             }
-            return;
+            return true;
         }
 
         // Do not move the task to another stack here.
@@ -3407,13 +2057,14 @@
                 // All other activities must be made visible with their correct configuration.
                 ensureActivitiesVisibleLocked(r, 0, !PRESERVE_WINDOWS);
                 if (!kept) {
-                    resumeTopActivitiesLocked(stack, null, null);
+                    resumeFocusedStackTopActivityLocked();
                 }
             }
         }
         mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, kept, forced);
 
         Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+        return kept;
     }
 
     private void adjustForMinimalTaskDimensions(TaskRecord task, Rect bounds) {
@@ -3529,8 +2180,14 @@
     ActivityStack moveTaskToStackUncheckedLocked(
             TaskRecord task, int stackId, boolean toTop, boolean forceFocus, String reason) {
         final ActivityRecord r = task.getTopActivity();
-        final boolean wasFocused = isFocusedStack(task.stack) && (topRunningActivityLocked() == r);
-        final boolean wasResumed = wasFocused && (task.stack.mResumedActivity == r);
+        final ActivityStack prevStack = task.stack;
+        final boolean wasFocused = isFocusedStack(prevStack) && (topRunningActivityLocked() == r);
+        final boolean wasResumed = wasFocused && (prevStack.mResumedActivity == r);
+        // In some cases the focused stack isn't the front stack. E.g. pinned stack.
+        // Whenever we are moving the top activity from the front stack we want to make sure to move
+        // the stack to the front.
+        final boolean wasFront = isFrontStack(prevStack)
+                && (prevStack.topRunningActivityLocked() == r);
 
         final boolean resizeable = task.mResizeable;
         // Temporarily disable resizeablility of task we are moving. We don't want it to be resized
@@ -3543,9 +2200,9 @@
         stack.addTask(task, toTop, reason);
 
         // If the task had focus before (or we're requested to move focus),
-        // move focus to the new stack.
-        stack.setFocusAndResumeStateIfNeeded(
-                r, forceFocus || wasFocused, wasResumed, reason);
+        // move focus to the new stack by moving the stack to the front.
+        stack.moveToFrontAndResumeStateIfNeeded(
+                r, forceFocus || wasFocused || wasFront, wasResumed, reason);
 
         return stack;
     }
@@ -3565,13 +2222,17 @@
         }
 
         final ActivityRecord topActivity = task.getTopActivity();
-        if (StackId.preserveWindowOnTaskMove(stackId) && topActivity != null) {
+        final boolean mightReplaceWindow =
+                StackId.preserveWindowOnTaskMove(stackId) && topActivity != null;
+        if (mightReplaceWindow) {
             // We are about to relaunch the activity because its configuration changed due to
             // being maximized, i.e. size change. The activity will first remove the old window
             // and then add a new one. This call will tell window manager about this, so it can
             // preserve the old window until the new one is drawn. This prevents having a gap
             // between the removal and addition, in which no window is visible. We also want the
             // entrance of the new window to be properly animated.
+            // Note here we always set the replacing window first, as the flags might be needed
+            // during the relaunch. If we end up not doing any relaunch, we clear the flags later.
             mWindowManager.setReplacingWindow(topActivity.appToken, animate);
         }
         final ActivityStack stack = moveTaskToStackUncheckedLocked(
@@ -3581,21 +2242,29 @@
             stack.mNoAnimActivities.add(topActivity);
         }
 
+        boolean kept = true;
         // Make sure the task has the appropriate bounds/size for the stack it is in.
         if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) {
-            resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
+            kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
         } else if (stackId == FREEFORM_WORKSPACE_STACK_ID
                 && task.mBounds == null && task.mLastNonFullscreenBounds != null) {
-            resizeTaskLocked(task, task.mLastNonFullscreenBounds,
+            kept = resizeTaskLocked(task, task.mLastNonFullscreenBounds,
                     RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
         } else if (stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID) {
-            resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
+            kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
+        }
+
+        if (mightReplaceWindow) {
+            // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old
+            // window), we need to clear the replace window settings. Otherwise, we schedule a
+            // timeout to remove the old window if the replacing window is not coming in time.
+            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, !PRESERVE_WINDOWS);
-        resumeTopActivitiesLocked();
+        resumeFocusedStackTopActivityLocked();
 
         if (!task.mResizeable && isStackDockedInEffect(stackId)) {
             showNonResizeableDockToast(taskId);
@@ -3616,31 +2285,43 @@
             return false;
         }
 
-        if (!mService.mForceResizableActivities && !r.info.supportsPip) {
+        if (!mService.mForceResizableActivities && !r.supportsPictureInPicture()) {
             Slog.w(TAG,
                     "moveTopStackActivityToPinnedStackLocked: Picture-In-Picture not supported for "
                             + " r=" + r);
             return false;
         }
 
+        moveActivityToStackLocked(r, PINNED_STACK_ID, "moveTopActivityToPinnedStack", null);
+        mWindowManager.animateResizePinnedStack(bounds);
+        return true;
+    }
+
+    void moveActivityToStackLocked(ActivityRecord r, int stackId, String reason, Rect bounds) {
         final TaskRecord task = r.task;
         if (task.mActivities.size() == 1) {
             // There is only one activity in the task. So, we can just move the task over to the
-            // pinned stack without re-parenting the activity in a different task.
-            moveTaskToStackLocked(task.taskId, PINNED_STACK_ID, ON_TOP, FORCE_FOCUS,
-                    "moveTopActivityToPinnedStack", true /* animate */);
+            // stack without re-parenting the activity in a different task.
+            moveTaskToStackLocked(
+                    task.taskId, stackId, ON_TOP, FORCE_FOCUS, reason, true /* animate */);
         } else {
-            final ActivityStack pinnedStack = getStack(PINNED_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
-            pinnedStack.moveActivityToStack(r);
+            final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, ON_TOP);
+            stack.moveActivityToStack(r);
         }
 
-        resizeStackLocked(PINNED_STACK_ID, bounds, !PRESERVE_WINDOWS, true);
+        if (bounds != null) {
+            resizeStackLocked(stackId, bounds, null /* tempTaskBounds */,
+                    null /* tempTaskInsetBounds */, !PRESERVE_WINDOWS, true);
+        }
 
         // The task might have already been running and its visibility needs to be synchronized with
         // the visibility of the stack / windows.
         ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
-        resumeTopActivitiesLocked();
-        return true;
+        resumeFocusedStackTopActivityLocked();
+
+        if (stackId == PINNED_STACK_ID) {
+            mService.notifyActivityPinnedLocked();
+        }
     }
 
     void positionTaskInStackLocked(int taskId, int stackId, int position) {
@@ -3659,10 +2340,12 @@
         // The task might have already been running and its visibility needs to be synchronized with
         // the visibility of the stack / windows.
         stack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
-        resumeTopActivitiesLocked();
+        resumeFocusedStackTopActivityLocked();
     }
 
     ActivityRecord findTaskLocked(ActivityRecord r) {
+        mTmpFindTaskResult.r = null;
+        mTmpFindTaskResult.matchedByRootAffinity = false;
         if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r);
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
@@ -3677,14 +2360,18 @@
                             "Skipping stack: (new task not allowed) " + stack);
                     continue;
                 }
-                final ActivityRecord ar = stack.findTaskLocked(r);
-                if (ar != null) {
-                    return ar;
+                stack.findTaskLocked(r, mTmpFindTaskResult);
+                // It is possible to have task in multiple stacks with the same root affinity.
+                // If the match we found was based on root affinity we keep on looking to see if
+                // there is a better match in another stack. We eventually return the match based
+                // on root affinity if we don't find a better match.
+                if (mTmpFindTaskResult.r != null && !mTmpFindTaskResult.matchedByRootAffinity) {
+                    return mTmpFindTaskResult.r;
                 }
             }
         }
-        if (DEBUG_TASKS) Slog.d(TAG_TASKS, "No task found");
-        return null;
+        if (DEBUG_TASKS && mTmpFindTaskResult.r == null) Slog.d(TAG_TASKS, "No task found");
+        return mTmpFindTaskResult.r;
     }
 
     ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
@@ -3763,7 +2450,7 @@
                 final ActivityStack stack = stacks.get(stackNdx);
                 stack.awakeFromSleepingLocked();
                 if (isFocusedStack(stack)) {
-                    resumeTopActivitiesLocked();
+                    resumeFocusedStackTopActivityLocked();
                 }
             }
         }
@@ -4088,7 +2775,7 @@
         for (int activityNdx = mStoppingActivities.size() - 1; activityNdx >= 0; --activityNdx) {
             ActivityRecord s = mStoppingActivities.get(activityNdx);
             final boolean waitingVisible = mWaitingVisibleActivities.contains(s);
-            if (DEBUG_ALL) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + nowVisible
+            if (DEBUG_STATES) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + nowVisible
                     + " waitingVisible=" + waitingVisible + " finishing=" + s.finishing);
             if (waitingVisible && nowVisible) {
                 mWaitingVisibleActivities.remove(s);
@@ -4098,12 +2785,12 @@
                     // so get rid of it.  Otherwise, we need to go through the
                     // normal flow and hide it once we determine that it is
                     // hidden by the activities in front of it.
-                    if (DEBUG_ALL) Slog.v(TAG, "Before stopping, can hide: " + s);
+                    if (DEBUG_STATES) Slog.v(TAG, "Before stopping, can hide: " + s);
                     mWindowManager.setAppVisibility(s.appToken, false);
                 }
             }
             if ((!waitingVisible || mService.isSleepingOrShuttingDown()) && remove) {
-                if (DEBUG_ALL) Slog.v(TAG, "Ready to stop: " + s);
+                if (DEBUG_STATES) Slog.v(TAG, "Ready to stop: " + s);
                 if (stops == null) {
                     stops = new ArrayList<>();
                 }
@@ -4162,7 +2849,8 @@
         pw.print(prefix); pw.print("mFocusedStack=" + mFocusedStack);
                 pw.print(" mLastFocusedStack="); pw.println(mLastFocusedStack);
         pw.print(prefix); pw.println("mSleepTimeout=" + mSleepTimeout);
-        pw.print(prefix); pw.println("mCurTaskId=" + mCurTaskId);
+        pw.print(prefix);
+        pw.println("mCurTaskIdForUser=" + mCurTaskIdForUser);
         pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront);
         pw.print(prefix); pw.println("mActivityContainers=" + mActivityContainers);
         pw.print(prefix); pw.print("mLockTaskModeState=" + lockTaskModeToString());
@@ -4532,7 +3220,7 @@
         }
     }
 
-    private void showNonResizeableDockToast(int taskId) {
+    void showNonResizeableDockToast(int taskId) {
         mWindowManager.scheduleShowNonResizeableDockToast(taskId);
     }
 
@@ -4558,7 +3246,7 @@
                     if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK,
                             "setLockTaskModeLocked: Tasks remaining, can't unlock");
                     lockedTask.performClearTaskLocked();
-                    resumeTopActivitiesLocked();
+                    resumeFocusedStackTopActivityLocked();
                     return;
                 }
             }
@@ -4599,7 +3287,7 @@
 
         if (andResume) {
             findTaskToMoveToFrontLocked(task, 0, null, reason);
-            resumeTopActivitiesLocked();
+            resumeFocusedStackTopActivityLocked();
         }
     }
 
@@ -4667,7 +3355,7 @@
             didSomething = true;
         }
         if (didSomething) {
-            resumeTopActivitiesLocked();
+            resumeFocusedStackTopActivityLocked();
         }
     }
 
@@ -4675,6 +3363,14 @@
         return mLockTaskModeState;
     }
 
+    void activityRelaunchedLocked(IBinder token) {
+        mWindowManager.notifyAppRelaunchingFinished(token);
+    }
+
+    void activityRelaunchingLocked(ActivityRecord r) {
+        mWindowManager.notifyAppRelaunching(r.appToken);
+    }
+
     void logStackState() {
         mActivityMetricsLogger.logWindowState();
     }
@@ -4714,7 +3410,7 @@
                 } break;
                 case RESUME_TOP_ACTIVITY_MSG: {
                     synchronized (mService) {
-                        resumeTopActivitiesLocked();
+                        resumeFocusedStackTopActivityLocked();
                     }
                 } break;
                 case SLEEP_TIMEOUT_MSG: {
@@ -4949,7 +3645,7 @@
                 long origId = Binder.clearCallingIdentity();
                 try {
                     mStack.finishAllActivitiesLocked(false);
-                    removePendingActivityLaunchesLocked(mStack);
+                    mService.mActivityStarter.removePendingActivityLaunchesLocked(mStack);
                 } finally {
                     Binder.restoreCallingIdentity(origId);
                 }
@@ -4968,22 +3664,7 @@
 
         @Override
         public final int startActivity(Intent intent) {
-            mService.enforceNotIsolatedCaller("ActivityContainer.startActivity");
-            final int userId = mService.mUserController.handleIncomingUser(Binder.getCallingPid(),
-                    Binder.getCallingUid(), mCurrentUser, false,
-                    ActivityManagerService.ALLOW_FULL_ONLY, "ActivityContainer", null);
-
-            // TODO: Switch to user app stacks here.
-            String mimeType = intent.getType();
-            final Uri data = intent.getData();
-            if (mimeType == null && data != null && "content".equals(data.getScheme())) {
-                mimeType = mService.getProviderMimeType(data, userId);
-            }
-            checkEmbeddedAllowedInner(userId, intent, mimeType);
-
-            intent.addFlags(FORCE_NEW_TASK_FLAGS);
-            return startActivityMayWait(null, -1, null, intent, mimeType, null, null, null, null,
-                    0, 0, null, null, null, null, false, userId, this, null);
+            return mService.startActivity(intent, this);
         }
 
         @Override
@@ -5007,7 +3688,7 @@
                     FORCE_NEW_TASK_FLAGS, FORCE_NEW_TASK_FLAGS, null, this);
         }
 
-        private void checkEmbeddedAllowedInner(int userId, Intent intent, String resolvedType) {
+        void checkEmbeddedAllowedInner(int userId, Intent intent, String resolvedType) {
             ActivityInfo aInfo = resolveActivity(intent, resolvedType, 0, null, userId);
             if (aInfo != null && (aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
                 throw new SecurityException(
@@ -5110,7 +3791,7 @@
 
             mSurface = surface;
             if (surface != null) {
-                mStack.resumeTopActivityLocked(null);
+                resumeFocusedStackTopActivityLocked();
             } else {
                 mContainerState = CONTAINER_STATE_NO_SURFACE;
                 ((VirtualActivityDisplay) mActivityDisplay).setSurface(null);
@@ -5164,7 +3845,7 @@
 
         /** All of the stacks on this display. Order matters, topmost stack is in front of all other
          * stacks, bottommost behind. Accessed directly by ActivityManager package classes */
-        final ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>();
+        final ArrayList<ActivityStack> mStacks = new ArrayList<>();
 
         ActivityRecord mVisibleBehindActivity;
 
@@ -5293,4 +3974,19 @@
         }
     }
 
+    ActivityStack findStackBehind(ActivityStack stack) {
+        // TODO(multi-display): We are only looking for stacks on the default display.
+        final ActivityDisplay display = mActivityDisplays.get(Display.DEFAULT_DISPLAY);
+        if (display == null) {
+            return null;
+        }
+        final ArrayList<ActivityStack> stacks = display.mStacks;
+        for (int i = stacks.size() - 1; i >= 0; i--) {
+            if (stacks.get(i) == stack && i > 0) {
+                return stacks.get(i - 1);
+            }
+        }
+        throw new IllegalStateException("Failed to find a stack behind stack=" + stack
+                + " in=" + stacks);
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
new file mode 100644
index 0000000..1ed749f
--- /dev/null
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -0,0 +1,180 @@
+package com.android.server.am;
+
+import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY;
+import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
+import static android.app.PendingIntent.FLAG_IMMUTABLE;
+import static android.app.PendingIntent.FLAG_ONE_SHOT;
+import static android.content.Context.KEYGUARD_SERVICE;
+import static android.content.Intent.EXTRA_INTENT;
+import static android.content.Intent.EXTRA_PACKAGE_NAME;
+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.pm.ApplicationInfo.FLAG_SUSPENDED;
+
+import android.app.KeyguardManager;
+import android.content.IIntentSender;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
+import android.os.Binder;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import com.android.internal.app.UnlaunchableAppActivity;
+
+/**
+ * A class that contains activity intercepting logic for {@link ActivityStarter#startActivityLocked}
+ * It's initialized
+ */
+class ActivityStartInterceptor {
+
+    private final ActivityManagerService mService;
+    private UserManager mUserManager;
+    private final ActivityStackSupervisor mSupervisor;
+
+    /*
+     * Per-intent states loaded from ActivityStarter than shouldn't be changed by any
+     * interception routines.
+     */
+    private int mRealCallingPid;
+    private int mRealCallingUid;
+    private int mUserId;
+    private int mStartFlags;
+    private String mCallingPackage;
+
+    /*
+     * Per-intent states that were load from ActivityStarter and are subject to modifications
+     * by the interception routines. After calling {@link #intercept} the caller should assign
+     * these values back to {@link ActivityStarter#startActivityLocked}'s local variables.
+     */
+    Intent mIntent;
+    int mCallingPid;
+    int mCallingUid;
+    ResolveInfo mRInfo;
+    ActivityInfo mAInfo;
+    String mResolvedType;
+    TaskRecord mInTask;
+
+    ActivityStartInterceptor(ActivityManagerService service, ActivityStackSupervisor supervisor) {
+        mService = service;
+        mSupervisor = supervisor;
+    }
+
+    void setStates(int userId, int realCallingPid, int realCallingUid, int startFlags,
+            String callingPackage) {
+        mRealCallingPid = realCallingPid;
+        mRealCallingUid = realCallingUid;
+        mUserId = userId;
+        mStartFlags = startFlags;
+        mCallingPackage = callingPackage;
+    }
+
+    void intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType,
+            TaskRecord inTask, int callingPid, int callingUid) {
+        mUserManager = UserManager.get(mService.mContext);
+        mIntent = intent;
+        mCallingPid = callingPid;
+        mCallingUid = callingUid;
+        mRInfo = rInfo;
+        mAInfo = aInfo;
+        mResolvedType = resolvedType;
+        mInTask = inTask;
+        interceptQuietProfileIfNeeded();
+        interceptSuspendPackageIfNeed();
+        interceptWorkProfileChallengeIfNeeded();
+    }
+
+    private void interceptQuietProfileIfNeeded() {
+        // Do not intercept if the user has not turned off the profile
+        if (!mUserManager.isQuietModeEnabled(UserHandle.of(mUserId))) {
+            return;
+        }
+        mIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId);
+        mCallingPid = mRealCallingPid;
+        mCallingUid = mRealCallingUid;
+        mResolvedType = null;
+
+        final UserInfo parent = mUserManager.getProfileParent(mUserId);
+        mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
+        mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags,
+                null /*profilerInfo*/);
+    }
+
+    private void 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;
+        }
+        mIntent = UnlaunchableAppActivity.createPackageSuspendedDialogIntent(mAInfo.packageName,
+                mUserId);
+        mCallingPid = mRealCallingPid;
+        mCallingUid = mRealCallingUid;
+        mResolvedType = null;
+
+        final UserInfo parent = mUserManager.getProfileParent(mUserId);
+        if (parent != null) {
+            mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
+        } else {
+            mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId);
+        }
+        mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags,
+                null /*profilerInfo*/);
+    }
+
+    private void interceptWorkProfileChallengeIfNeeded() {
+        final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(mIntent,
+                mResolvedType, mAInfo, mCallingPackage, mUserId);
+        if (interceptingIntent == null) {
+            return;
+        }
+        mIntent = interceptingIntent;
+        mCallingPid = mRealCallingPid;
+        mCallingUid = mRealCallingUid;
+        mResolvedType = null;
+        // If we are intercepting and there was a task, convert it into an extra for the
+        // ConfirmCredentials intent and unassign it, as otherwise the task will move to
+        // front even if ConfirmCredentials is cancelled.
+        if (mInTask != null) {
+            mIntent.putExtra(EXTRA_TASK_ID, mInTask.taskId);
+            mInTask = null;
+        }
+
+        final UserInfo parent = mUserManager.getProfileParent(mUserId);
+        mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
+        mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags,
+                null /*profilerInfo*/);
+    }
+
+    /**
+     * Creates an intent to intercept the current activity start with Confirm Credentials if needed.
+     *
+     * @return The intercepting intent if needed.
+     */
+    private Intent interceptWithConfirmCredentialsIfNeeded(Intent intent, String resolvedType,
+            ActivityInfo aInfo, String callingPackage, int userId) {
+        if (!mService.mUserController.shouldConfirmCredentials(userId)) {
+            return null;
+        }
+        final IIntentSender target = mService.getIntentSenderLocked(
+                INTENT_SENDER_ACTIVITY, callingPackage,
+                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.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
new file mode 100644
index 0000000..7b7359f
--- /dev/null
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -0,0 +1,1745 @@
+package com.android.server.am;
+
+import static android.app.Activity.RESULT_CANCELED;
+import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
+import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
+import static android.app.ActivityManager.START_FLAG_ONLY_IF_NEEDED;
+import static android.app.ActivityManager.START_RETURN_INTENT_TO_CALLER;
+import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
+import static android.app.ActivityManager.START_SUCCESS;
+import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.app.ActivityManager.StackId;
+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.INVALID_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
+import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_TO_SIDE;
+import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
+import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
+import static android.content.Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP;
+import static android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT;
+import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
+import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
+import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
+import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
+import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RESULTS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USER_LEAVING;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RESULTS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_USER_LEAVING;
+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.ANIMATE;
+import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
+import static com.android.server.am.ActivityStack.STACK_INVISIBLE;
+import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED;
+import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
+import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
+import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.am.ActivityStackSupervisor.TAG_TASKS;
+import static com.android.server.am.EventLogTags.AM_NEW_INTENT;
+
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.AppGlobals;
+import android.app.IActivityContainer;
+import android.app.IActivityManager;
+import android.app.IApplicationThread;
+import android.app.PendingIntent;
+import android.app.ProfilerInfo;
+import android.content.ComponentName;
+import android.content.IIntentSender;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.service.voice.IVoiceInteractionSession;
+import android.util.EventLog;
+import android.util.Slog;
+import android.view.Display;
+
+import com.android.internal.app.HeavyWeightSwitcherActivity;
+import com.android.internal.app.IVoiceInteractor;
+import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch;
+import com.android.server.wm.WindowManagerService;
+
+import java.util.ArrayList;
+
+/**
+ * Controller for interpreting how and then launching activities.
+ *
+ * This class collects all the logic for determining how an intent and flags should be turned into
+ * an activity and associated task and stack.
+ */
+class ActivityStarter {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStarter" : TAG_AM;
+    private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
+    private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
+    private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
+    private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
+
+    private final ActivityManagerService mService;
+    private final ActivityStackSupervisor mSupervisor;
+    private ActivityStartInterceptor mInterceptor;
+    private WindowManagerService mWindowManager;
+
+    final ArrayList<PendingActivityLaunch> mPendingActivityLaunches = new ArrayList<>();
+
+    // Share state variable among methods when starting an activity.
+    private ActivityRecord mStartActivity;
+    private Intent mIntent;
+    private int mCallingUid;
+    private ActivityOptions mOptions;
+
+    private boolean mLaunchSingleTop;
+    private boolean mLaunchSingleInstance;
+    private boolean mLaunchSingleTask;
+    private boolean mLaunchTaskBehind;
+    private int mLaunchFlags;
+
+    private Rect mLaunchBounds;
+
+    private ActivityRecord mNotTop;
+    private boolean mDoResume;
+    private int mStartFlags;
+    private ActivityRecord mSourceRecord;
+
+    private TaskRecord mInTask;
+    private boolean mAddingToTask;
+    private TaskRecord mReuseTask;
+
+    private ActivityInfo mNewTaskInfo;
+    private Intent mNewTaskIntent;
+    private ActivityStack mSourceStack;
+    private ActivityStack mTargetStack;
+    // TODO: Is the mMoveHome flag really needed?
+    private boolean mMovedHome;
+    private boolean mMovedToFront;
+    private boolean mNoAnimation;
+    private boolean mKeepCurTransition;
+
+    private IVoiceInteractionSession mVoiceSession;
+    private IVoiceInteractor mVoiceInteractor;
+
+    private void reset() {
+        mStartActivity = null;
+        mIntent = null;
+        mCallingUid = -1;
+        mOptions = null;
+
+        mLaunchSingleTop = false;
+        mLaunchSingleInstance = false;
+        mLaunchSingleTask = false;
+        mLaunchTaskBehind = false;
+        mLaunchFlags = 0;
+
+        mLaunchBounds = null;
+
+        mNotTop = null;
+        mDoResume = false;
+        mStartFlags = 0;
+        mSourceRecord = null;
+
+        mInTask = null;
+        mAddingToTask = false;
+        mReuseTask = null;
+
+        mNewTaskInfo = null;
+        mNewTaskIntent = null;
+        mSourceStack = null;
+
+        mTargetStack = null;
+        mMovedHome = false;
+        mMovedToFront = false;
+        mNoAnimation = false;
+        mKeepCurTransition = false;
+
+        mVoiceSession = null;
+        mVoiceInteractor = null;
+    }
+
+    ActivityStarter(ActivityManagerService service, ActivityStackSupervisor supervisor) {
+        mService = service;
+        mSupervisor = supervisor;
+        mInterceptor = new ActivityStartInterceptor(mService, mSupervisor);
+    }
+
+    final int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
+            String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
+            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+            IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
+            String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
+            ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
+            ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
+            TaskRecord inTask) {
+        int err = ActivityManager.START_SUCCESS;
+
+        ProcessRecord callerApp = null;
+        if (caller != null) {
+            callerApp = mService.getRecordForAppLocked(caller);
+            if (callerApp != null) {
+                callingPid = callerApp.pid;
+                callingUid = callerApp.info.uid;
+            } else {
+                Slog.w(TAG, "Unable to find app for caller " + caller
+                        + " (pid=" + callingPid + ") when starting: "
+                        + intent.toString());
+                err = ActivityManager.START_PERMISSION_DENIED;
+            }
+        }
+
+        final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
+
+        if (err == ActivityManager.START_SUCCESS) {
+            Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
+                    + "} from uid " + callingUid
+                    + " on display " + (container == null ? (mSupervisor.mFocusedStack == null ?
+                    Display.DEFAULT_DISPLAY : mSupervisor.mFocusedStack.mDisplayId) :
+                    (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY :
+                            container.mActivityDisplay.mDisplayId)));
+        }
+
+        ActivityRecord sourceRecord = null;
+        ActivityRecord resultRecord = null;
+        if (resultTo != null) {
+            sourceRecord = mSupervisor.isInAnyStackLocked(resultTo);
+            if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
+                    "Will send result to " + resultTo + " " + sourceRecord);
+            if (sourceRecord != null) {
+                if (requestCode >= 0 && !sourceRecord.finishing) {
+                    resultRecord = sourceRecord;
+                }
+            }
+        }
+
+        final int launchFlags = intent.getFlags();
+
+        if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
+            // Transfer the result target from the source activity to the new
+            // one being started, including any failures.
+            if (requestCode >= 0) {
+                ActivityOptions.abort(options);
+                return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
+            }
+            resultRecord = sourceRecord.resultTo;
+            if (resultRecord != null && !resultRecord.isInStackLocked()) {
+                resultRecord = null;
+            }
+            resultWho = sourceRecord.resultWho;
+            requestCode = sourceRecord.requestCode;
+            sourceRecord.resultTo = null;
+            if (resultRecord != null) {
+                resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
+            }
+            if (sourceRecord.launchedFromUid == callingUid) {
+                // The new activity is being launched from the same uid as the previous
+                // activity in the flow, and asking to forward its result back to the
+                // previous.  In this case the activity is serving as a trampoline between
+                // the two, so we also want to update its launchedFromPackage to be the
+                // same as the previous activity.  Note that this is safe, since we know
+                // these two packages come from the same uid; the caller could just as
+                // well have supplied that same package name itself.  This specifially
+                // deals with the case of an intent picker/chooser being launched in the app
+                // flow to redirect to an activity picked by the user, where we want the final
+                // activity to consider it to have been launched by the previous app activity.
+                callingPackage = sourceRecord.launchedFromPackage;
+            }
+        }
+
+        if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
+            // We couldn't find a class that can handle the given Intent.
+            // That's the end of that!
+            err = ActivityManager.START_INTENT_NOT_RESOLVED;
+        }
+
+        if (err == ActivityManager.START_SUCCESS && aInfo == null) {
+            // We couldn't find the specific class specified in the Intent.
+            // Also the end of the line.
+            err = ActivityManager.START_CLASS_NOT_FOUND;
+        }
+
+        if (err == ActivityManager.START_SUCCESS && sourceRecord != null
+                && sourceRecord.task.voiceSession != null) {
+            // If this activity is being launched as part of a voice session, we need
+            // to ensure that it is safe to do so.  If the upcoming activity will also
+            // be part of the voice session, we can only launch it if it has explicitly
+            // said it supports the VOICE category, or it is a part of the calling app.
+            if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0
+                    && sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
+                try {
+                    intent.addCategory(Intent.CATEGORY_VOICE);
+                    if (!AppGlobals.getPackageManager().activitySupportsIntent(
+                            intent.getComponent(), intent, resolvedType)) {
+                        Slog.w(TAG,
+                                "Activity being started in current voice task does not support voice: "
+                                        + intent);
+                        err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
+                    }
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failure checking voice capabilities", e);
+                    err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
+                }
+            }
+        }
+
+        if (err == ActivityManager.START_SUCCESS && voiceSession != null) {
+            // If the caller is starting a new voice session, just make sure the target
+            // is actually allowing it to run this way.
+            try {
+                if (!AppGlobals.getPackageManager().activitySupportsIntent(intent.getComponent(),
+                        intent, resolvedType)) {
+                    Slog.w(TAG,
+                            "Activity being started in new voice task does not support: "
+                                    + intent);
+                    err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
+                }
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failure checking voice capabilities", e);
+                err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
+            }
+        }
+
+        final ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack;
+
+        if (err != START_SUCCESS) {
+            if (resultRecord != null) {
+                resultStack.sendActivityResultLocked(
+                        -1, resultRecord, resultWho, requestCode, RESULT_CANCELED, null);
+            }
+            ActivityOptions.abort(options);
+            return err;
+        }
+
+        boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
+                requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity, callerApp,
+                resultRecord, resultStack);
+        abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
+                callingPid, resolvedType, aInfo.applicationInfo);
+
+        if (mService.mController != null) {
+            try {
+                // The Intent we give to the watcher has the extra data
+                // stripped off, since it can contain private information.
+                Intent watchIntent = intent.cloneFilter();
+                abort |= !mService.mController.activityStarting(watchIntent,
+                        aInfo.applicationInfo.packageName);
+            } catch (RemoteException e) {
+                mService.mController = null;
+            }
+        }
+
+        mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage);
+        mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, callingPid, callingUid);
+        intent = mInterceptor.mIntent;
+        rInfo = mInterceptor.mRInfo;
+        aInfo = mInterceptor.mAInfo;
+        resolvedType = mInterceptor.mResolvedType;
+        inTask = mInterceptor.mInTask;
+        callingPid = mInterceptor.mCallingPid;
+        callingUid = mInterceptor.mCallingUid;
+
+        if (abort) {
+            if (resultRecord != null) {
+                resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
+                        RESULT_CANCELED, null);
+            }
+            // We pretend to the caller that it was really started, but
+            // they will just get a cancel result.
+            ActivityOptions.abort(options);
+            return START_SUCCESS;
+        }
+
+        // If permissions need a review before any of the app components can run, we
+        // launch the review activity and pass a pending intent to start the activity
+        // we are to launching now after the review is completed.
+        if (Build.PERMISSIONS_REVIEW_REQUIRED && aInfo != null) {
+            if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
+                    aInfo.packageName, userId)) {
+                IIntentSender target = mService.getIntentSenderLocked(
+                        ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
+                        callingUid, userId, null, null, 0, new Intent[]{intent},
+                        new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT
+                                | PendingIntent.FLAG_ONE_SHOT, null);
+
+                final int flags = intent.getFlags();
+                Intent newIntent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
+                newIntent.setFlags(flags
+                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                newIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName);
+                newIntent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
+                if (resultRecord != null) {
+                    newIntent.putExtra(Intent.EXTRA_RESULT_NEEDED, true);
+                }
+                intent = newIntent;
+
+                resolvedType = null;
+                callingUid = realCallingUid;
+                callingPid = realCallingPid;
+
+                rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
+                aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
+                        null /*profilerInfo*/);
+
+                if (DEBUG_PERMISSIONS_REVIEW) {
+                    Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true,
+                            true, false) + "} from uid " + callingUid + " on display "
+                            + (container == null ? (mSupervisor.mFocusedStack == null ?
+                            Display.DEFAULT_DISPLAY : mSupervisor.mFocusedStack.mDisplayId) :
+                            (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY :
+                                    container.mActivityDisplay.mDisplayId)));
+                }
+            }
+        }
+
+        // If we have an ephemeral app, abort the process of launching the resolved intent.
+        // Instead, launch the ephemeral installer. Once the installer is finished, it
+        // starts either the intent we resolved here [on install error] or the ephemeral
+        // app [on install success].
+        if (rInfo != null && rInfo.ephemeralResolveInfo != null) {
+            // Create a pending intent to start the intent resolved here.
+            final IIntentSender failureTarget = mService.getIntentSenderLocked(
+                    ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
+                    Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
+                    new String[]{ resolvedType },
+                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
+                            | PendingIntent.FLAG_IMMUTABLE, null);
+
+            // Create a pending intent to start the ephemeral application; force it to be
+            // directed to the ephemeral package.
+            ephemeralIntent.setPackage(rInfo.ephemeralResolveInfo.getPackageName());
+            final IIntentSender ephemeralTarget = mService.getIntentSenderLocked(
+                    ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
+                    Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ ephemeralIntent },
+                    new String[]{ resolvedType },
+                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
+                            | PendingIntent.FLAG_IMMUTABLE, null);
+
+            int flags = intent.getFlags();
+            intent = new Intent();
+            intent.setFlags(flags
+                    | Intent.FLAG_ACTIVITY_NEW_TASK
+                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+            intent.putExtra(Intent.EXTRA_PACKAGE_NAME,
+                    rInfo.ephemeralResolveInfo.getPackageName());
+            intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, new IntentSender(failureTarget));
+            intent.putExtra(Intent.EXTRA_EPHEMERAL_SUCCESS, new IntentSender(ephemeralTarget));
+
+            resolvedType = null;
+            callingUid = realCallingUid;
+            callingPid = realCallingPid;
+
+            rInfo = rInfo.ephemeralInstaller;
+            aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
+        }
+
+        ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
+                intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
+                requestCode, componentSpecified, voiceSession != null, mSupervisor, container,
+                options);
+        if (outActivity != null) {
+            outActivity[0] = r;
+        }
+
+        if (r.appTimeTracker == null && sourceRecord != null) {
+            // If the caller didn't specify an explicit time tracker, we want to continue
+            // tracking under any it has.
+            r.appTimeTracker = sourceRecord.appTimeTracker;
+        }
+
+        final ActivityStack stack = mSupervisor.mFocusedStack;
+        if (voiceSession == null && (stack.mResumedActivity == null
+                || stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
+            if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
+                    realCallingPid, realCallingUid, "Activity start")) {
+                PendingActivityLaunch pal =  new PendingActivityLaunch(r,
+                        sourceRecord, startFlags, stack, callerApp);
+                mPendingActivityLaunches.add(pal);
+                ActivityOptions.abort(options);
+                return ActivityManager.START_SWITCHES_CANCELED;
+            }
+        }
+
+        if (mService.mDidAppSwitch) {
+            // This is the second allowed switch since we stopped switches,
+            // so now just generally allow switches.  Use case: user presses
+            // home (switches disabled, switch to home, mDidAppSwitch now true);
+            // user taps a home icon (coming from home so allowed, we hit here
+            // and now allow anyone to switch again).
+            mService.mAppSwitchesAllowedTime = 0;
+        } else {
+            mService.mDidAppSwitch = true;
+        }
+
+        doPendingActivityLaunchesLocked(false);
+
+        err = startActivityUnchecked(
+                r, sourceRecord, voiceSession, voiceInteractor, startFlags, true, options, inTask);
+        postStartActivityUncheckedProcessing(r, err, stack.mStackId);
+        return err;
+    }
+
+    void postStartActivityUncheckedProcessing(
+            ActivityRecord r, int result, int prevFocusedStackId) {
+
+        if (result < START_SUCCESS) {
+            // If someone asked to have the keyguard dismissed on the next activity start,
+            // but we are not actually doing an activity switch...  just dismiss the keyguard now,
+            // because we probably want to see whatever is behind it.
+            mSupervisor.notifyActivityDrawnForKeyguard();
+            return;
+        }
+
+        int startedActivityStackId = INVALID_STACK_ID;
+        if (r.task != null && r.task.stack != null) {
+            startedActivityStackId = r.task.stack.mStackId;
+        } else if (mTargetStack != null) {
+            startedActivityStackId = mTargetStack.mStackId;
+        }
+
+        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;
+        }
+
+        if (startedActivityStackId == PINNED_STACK_ID
+                && (result == START_TASK_TO_FRONT || result == START_DELIVERED_TO_TOP)) {
+            // The activity was already running in the pinned stack so it wasn't started, but either
+            // brought to the front or the new intent was delivered to it since it was already in
+            // front. Notify anyone interested in this piece of information.
+            mService.notifyPinnedActivityRestartAttemptLocked();
+            return;
+        }
+    }
+
+    void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {
+        mSupervisor.moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE, reason);
+        startActivityLocked(null /*caller*/, intent, null /*ephemeralIntent*/,
+                null /*resolvedType*/, aInfo, null /*rInfo*/, null /*voiceSession*/,
+                null /*voiceInteractor*/, null /*resultTo*/, null /*resultWho*/,
+                0 /*requestCode*/, 0 /*callingPid*/, 0 /*callingUid*/, null /*callingPackage*/,
+                0 /*realCallingPid*/, 0 /*realCallingUid*/, 0 /*startFlags*/, null /*options*/,
+                false /*ignoreTargetSecurity*/, false /*componentSpecified*/,  null /*outActivity*/,
+                null /*container*/, null /*inTask*/);
+        if (mSupervisor.inResumeTopActivity) {
+            // If we are in resume section already, home activity will be initialized, but not
+            // resumed (to avoid recursive resume) and will stay that way until something pokes it
+            // again. We need to schedule another resume.
+            mSupervisor.scheduleResumeTopActivities();
+        }
+    }
+
+    final int startActivityMayWait(IApplicationThread caller, int callingUid,
+            String callingPackage, Intent intent, String resolvedType,
+            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+            IBinder resultTo, String resultWho, int requestCode, int startFlags,
+            ProfilerInfo profilerInfo, IActivityManager.WaitResult outResult, Configuration config,
+            Bundle bOptions, boolean ignoreTargetSecurity, int userId,
+            IActivityContainer iContainer, TaskRecord inTask) {
+        // Refuse possible leaked file descriptors
+        if (intent != null && intent.hasFileDescriptors()) {
+            throw new IllegalArgumentException("File descriptors passed in Intent");
+        }
+        boolean componentSpecified = intent.getComponent() != null;
+
+        // Save a copy in case ephemeral needs it
+        final Intent ephemeralIntent = new Intent(intent);
+        // Don't modify the client's object!
+        intent = new Intent(intent);
+
+        ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
+        // Collect information about the target of the Intent.
+        ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
+
+        ActivityOptions options = ActivityOptions.fromBundle(bOptions);
+        ActivityStackSupervisor.ActivityContainer container =
+                (ActivityStackSupervisor.ActivityContainer)iContainer;
+        synchronized (mService) {
+            if (container != null && container.mParentActivity != null &&
+                    container.mParentActivity.state != RESUMED) {
+                // Cannot start a child activity if the parent is not resumed.
+                return ActivityManager.START_CANCELED;
+            }
+            final int realCallingPid = Binder.getCallingPid();
+            final int realCallingUid = Binder.getCallingUid();
+            int callingPid;
+            if (callingUid >= 0) {
+                callingPid = -1;
+            } else if (caller == null) {
+                callingPid = realCallingPid;
+                callingUid = realCallingUid;
+            } else {
+                callingPid = callingUid = -1;
+            }
+
+            final ActivityStack stack;
+            if (container == null || container.mStack.isOnHomeDisplay()) {
+                stack = mSupervisor.mFocusedStack;
+            } else {
+                stack = container.mStack;
+            }
+            stack.mConfigWillChange = config != null && mService.mConfiguration.diff(config) != 0;
+            if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+                    "Starting activity when config will change = " + stack.mConfigWillChange);
+
+            final long origId = Binder.clearCallingIdentity();
+
+            if (aInfo != null &&
+                    (aInfo.applicationInfo.privateFlags
+                            & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
+                // This may be a heavy-weight process!  Check to see if we already
+                // have another, different heavy-weight process running.
+                if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
+                    final ProcessRecord heavy = mService.mHeavyWeightProcess;
+                    if (heavy != null && (heavy.info.uid != aInfo.applicationInfo.uid
+                            || !heavy.processName.equals(aInfo.processName))) {
+                        int appCallingUid = callingUid;
+                        if (caller != null) {
+                            ProcessRecord callerApp = mService.getRecordForAppLocked(caller);
+                            if (callerApp != null) {
+                                appCallingUid = callerApp.info.uid;
+                            } else {
+                                Slog.w(TAG, "Unable to find app for caller " + caller
+                                        + " (pid=" + callingPid + ") when starting: "
+                                        + intent.toString());
+                                ActivityOptions.abort(options);
+                                return ActivityManager.START_PERMISSION_DENIED;
+                            }
+                        }
+
+                        IIntentSender target = mService.getIntentSenderLocked(
+                                ActivityManager.INTENT_SENDER_ACTIVITY, "android",
+                                appCallingUid, userId, null, null, 0, new Intent[] { intent },
+                                new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT
+                                        | PendingIntent.FLAG_ONE_SHOT, null);
+
+                        Intent newIntent = new Intent();
+                        if (requestCode >= 0) {
+                            // Caller is requesting a result.
+                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
+                        }
+                        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
+                                new IntentSender(target));
+                        if (heavy.activities.size() > 0) {
+                            ActivityRecord hist = heavy.activities.get(0);
+                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
+                                    hist.packageName);
+                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
+                                    hist.task.taskId);
+                        }
+                        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
+                                aInfo.packageName);
+                        newIntent.setFlags(intent.getFlags());
+                        newIntent.setClassName("android",
+                                HeavyWeightSwitcherActivity.class.getName());
+                        intent = newIntent;
+                        resolvedType = null;
+                        caller = null;
+                        callingUid = Binder.getCallingUid();
+                        callingPid = Binder.getCallingPid();
+                        componentSpecified = true;
+                        rInfo = mSupervisor.resolveIntent(intent, null /*resolvedType*/, userId);
+                        aInfo = rInfo != null ? rInfo.activityInfo : null;
+                        if (aInfo != null) {
+                            aInfo = mService.getActivityInfoForUser(aInfo, userId);
+                        }
+                    }
+                }
+            }
+
+            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);
+
+            Binder.restoreCallingIdentity(origId);
+
+            if (stack.mConfigWillChange) {
+                // If the caller also wants to switch to a new configuration,
+                // do so now.  This allows a clean switch, as we are waiting
+                // for the current activity to pause (so we will not destroy
+                // it), and have not yet started the next activity.
+                mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
+                        "updateConfiguration()");
+                stack.mConfigWillChange = false;
+                if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+                        "Updating to new configuration after starting activity.");
+                mService.updateConfigurationLocked(config, null, false);
+            }
+
+            if (outResult != null) {
+                outResult.result = res;
+                if (res == ActivityManager.START_SUCCESS) {
+                    mSupervisor.mWaitingActivityLaunched.add(outResult);
+                    do {
+                        try {
+                            mService.wait();
+                        } catch (InterruptedException e) {
+                        }
+                    } while (!outResult.timeout && outResult.who == null);
+                } else if (res == START_TASK_TO_FRONT) {
+                    ActivityRecord r = stack.topRunningActivityLocked();
+                    if (r.nowVisible && r.state == RESUMED) {
+                        outResult.timeout = false;
+                        outResult.who = new ComponentName(r.info.packageName, r.info.name);
+                        outResult.totalTime = 0;
+                        outResult.thisTime = 0;
+                    } else {
+                        outResult.thisTime = SystemClock.uptimeMillis();
+                        mSupervisor.mWaitingActivityVisible.add(outResult);
+                        do {
+                            try {
+                                mService.wait();
+                            } catch (InterruptedException e) {
+                            }
+                        } while (!outResult.timeout && outResult.who == null);
+                    }
+                }
+            }
+
+            return res;
+        }
+    }
+
+    final int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
+            Intent[] intents, String[] resolvedTypes, IBinder resultTo,
+            Bundle bOptions, int userId) {
+        if (intents == null) {
+            throw new NullPointerException("intents is null");
+        }
+        if (resolvedTypes == null) {
+            throw new NullPointerException("resolvedTypes is null");
+        }
+        if (intents.length != resolvedTypes.length) {
+            throw new IllegalArgumentException("intents are length different than resolvedTypes");
+        }
+
+
+        int callingPid;
+        if (callingUid >= 0) {
+            callingPid = -1;
+        } else if (caller == null) {
+            callingPid = Binder.getCallingPid();
+            callingUid = Binder.getCallingUid();
+        } else {
+            callingPid = callingUid = -1;
+        }
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mService) {
+                ActivityRecord[] outActivity = new ActivityRecord[1];
+                for (int i=0; i<intents.length; i++) {
+                    Intent intent = intents[i];
+                    if (intent == null) {
+                        continue;
+                    }
+
+                    // Refuse possible leaked file descriptors
+                    if (intent != null && intent.hasFileDescriptors()) {
+                        throw new IllegalArgumentException("File descriptors passed in Intent");
+                    }
+
+                    boolean componentSpecified = intent.getComponent() != null;
+
+                    // Don't modify the client's object!
+                    intent = new Intent(intent);
+
+                    // Collect information about the target of the Intent.
+                    ActivityInfo aInfo = mSupervisor.resolveActivity(intent, resolvedTypes[i], 0,
+                            null, userId);
+                    // TODO: New, check if this is correct
+                    aInfo = mService.getActivityInfoForUser(aInfo, userId);
+
+                    if (aInfo != null &&
+                            (aInfo.applicationInfo.privateFlags
+                                    & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)  != 0) {
+                        throw new IllegalArgumentException(
+                                "FLAG_CANT_SAVE_STATE not supported here");
+                    }
+
+                    ActivityOptions options = ActivityOptions.fromBundle(
+                            i == intents.length - 1 ? bOptions : null);
+                    int res = startActivityLocked(caller, intent, null /*ephemeralIntent*/,
+                            resolvedTypes[i], aInfo, null /*rInfo*/, null, null, resultTo, null, -1,
+                            callingPid, callingUid, callingPackage, callingPid, callingUid, 0,
+                            options, false, componentSpecified, outActivity, null, null);
+                    if (res < 0) {
+                        return res;
+                    }
+
+                    resultTo = outActivity[0] != null ? outActivity[0].appToken : null;
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+
+        return START_SUCCESS;
+    }
+
+    private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
+            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
+
+        setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
+                voiceInteractor);
+
+        computeLaunchingTaskFlags();
+
+        computeSourceStack();
+
+        mIntent.setFlags(mLaunchFlags);
+
+        ActivityRecord intentActivity = getReusableIntentActivity();
+
+        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
+            // the device would otherwise leave the locked task.
+            if (mSupervisor.isLockTaskModeViolation(intentActivity.task,
+                    (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
+                            == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
+                mSupervisor.showLockTaskToast();
+                Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
+                return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+            }
+
+            if (mStartActivity.task == null) {
+                mStartActivity.task = intentActivity.task;
+            }
+            if (intentActivity.task.intent == null) {
+                // This task was started because of movement of the activity based on affinity...
+                // Now that we are actually launching it, we can assign the base intent.
+                intentActivity.task.setIntent(mStartActivity);
+            }
+
+            // This code path leads to delivering a new intent, we want to make sure we schedule it
+            // as the first operation, in case the activity will be resumed as a result of later
+            // operations.
+            if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
+                    || mLaunchSingleInstance || mLaunchSingleTask) {
+                // In this situation we want to remove all activities from the task up to the one
+                // being started. In most cases this means we are resetting the task to its initial
+                // state.
+                final ActivityRecord top = intentActivity.task.performClearTaskForReuseLocked(
+                        mStartActivity, mLaunchFlags);
+                if (top != null) {
+                    if (top.frontOfTask) {
+                        // Activity aliases may mean we use different intents for the top activity,
+                        // so make sure the task now has the identity of the new intent.
+                        top.task.setIntent(mStartActivity);
+                    }
+                    ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
+                    top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
+                            mStartActivity.launchedFromPackage);
+                }
+            }
+
+            intentActivity = setTargetStackAndMoveToFrontIfNeeded(intentActivity);
+
+            if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
+                // We don't need to start a new activity, and the client said not to do anything
+                // if that is the case, so this is it!  And for paranoia, make sure we have
+                // correctly resumed the top activity.
+                resumeTargetStackIfNeeded();
+                return START_RETURN_INTENT_TO_CALLER;
+            }
+
+            setTaskFromIntentActivity(intentActivity);
+
+            if (!mAddingToTask && mReuseTask == null) {
+                // We didn't do anything...  but it was needed (a.k.a., client don't use that
+                // intent!)  And for paranoia, make sure we have correctly resumed the top activity.
+                resumeTargetStackIfNeeded();
+                return START_TASK_TO_FRONT;
+            }
+        }
+
+        if (mStartActivity.packageName == null) {
+            if (mStartActivity.resultTo != null && mStartActivity.resultTo.task.stack != null) {
+                mStartActivity.resultTo.task.stack.sendActivityResultLocked(
+                        -1, mStartActivity.resultTo, mStartActivity.resultWho,
+                        mStartActivity.requestCode, RESULT_CANCELED, null);
+            }
+            ActivityOptions.abort(mOptions);
+            return START_CLASS_NOT_FOUND;
+        }
+
+        // If the activity being launched is the same as the one currently at the top, then
+        // we need to check if it should only be launched once.
+        final ActivityStack topStack = mSupervisor.mFocusedStack;
+        final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
+        final boolean dontStart = top != null && mStartActivity.resultTo == null
+                && top.realActivity.equals(mStartActivity.realActivity)
+                && top.userId == mStartActivity.userId
+                && top.app != null && top.app.thread != null
+                && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
+                || mLaunchSingleTop || mLaunchSingleTask);
+        if (dontStart) {
+            ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
+            // For paranoia, make sure we have correctly resumed the top activity.
+            topStack.mLastPausedActivity = null;
+            if (mDoResume) {
+                mSupervisor.resumeFocusedStackTopActivityLocked();
+            }
+            ActivityOptions.abort(mOptions);
+            if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
+                // We don't need to start a new activity, and the client said not to do
+                // anything if that is the case, so this is it!
+                return START_RETURN_INTENT_TO_CALLER;
+            }
+            top.deliverNewIntentLocked(
+                    mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+            return START_DELIVERED_TO_TOP;
+        }
+
+        boolean newTask = false;
+        final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
+                ? mSourceRecord.task : null;
+
+        // Should this be considered a new task?
+        if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
+                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
+            newTask = true;
+            setTaskFromReuseOrCreateNewTask(taskToAffiliate);
+
+            if (mSupervisor.isLockTaskModeViolation(mStartActivity.task)) {
+                Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
+                return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+            }
+            if (!mMovedHome
+                    && (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
+                    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
+                // Caller wants to appear on home activity, so before starting
+                // their own activity we will bring home to the front.
+                mStartActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+            }
+        } else if (mSourceRecord != null) {
+            if (mSupervisor.isLockTaskModeViolation(mSourceRecord.task)) {
+                Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
+                return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+            }
+
+            final int result = setTaskFromSourceRecord();
+            if (result != START_SUCCESS) {
+                return result;
+            }
+        } else if (mInTask != null) {
+            // The caller is asking that the new activity be started in an explicit
+            // task it has provided to us.
+            if (mSupervisor.isLockTaskModeViolation(mInTask)) {
+                Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
+                return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+            }
+
+            final int result = setTaskFromInTask();
+            if (result != START_SUCCESS) {
+                return result;
+            }
+        } else {
+            // This not being started from an existing activity, and not part of a new task...
+            // just put it in the top task, though these days this case should never happen.
+            setTaskToCurrentTopOrCreateNewTask();
+        }
+
+        mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,
+                mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);
+
+        if (mSourceRecord != null && mSourceRecord.isRecentsActivity()) {
+            mStartActivity.task.setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);
+        }
+        if (newTask) {
+            EventLog.writeEvent(
+                    EventLogTags.AM_CREATE_TASK, mStartActivity.userId, mStartActivity.task.taskId);
+        }
+        ActivityStack.logStartActivity(
+                EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.task);
+        mTargetStack.mLastPausedActivity = null;
+        mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);
+        if (mDoResume) {
+            if (!mLaunchTaskBehind) {
+                // TODO(b/26381750): Remove this code after verification that all the decision
+                // points above moved targetStack to the front which will also set the focus
+                // activity.
+                mService.setFocusedActivityLocked(mStartActivity, "startedActivity");
+            }
+            mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
+                    mOptions);
+        } else {
+            mTargetStack.addRecentActivityLocked(mStartActivity);
+        }
+        mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
+
+        if (!mStartActivity.task.mResizeable
+                && mSupervisor.isStackDockedInEffect(mTargetStack.mStackId)) {
+            mSupervisor.showNonResizeableDockToast(mStartActivity.task.taskId);
+        }
+
+        return START_SUCCESS;
+    }
+
+    private void setInitialState(ActivityRecord r, ActivityOptions options, TaskRecord inTask,
+            boolean doResume, int startFlags, ActivityRecord sourceRecord,
+            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {
+        reset();
+
+        mStartActivity = r;
+        mIntent = r.intent;
+        mOptions = options;
+        mCallingUid = r.launchedFromUid;
+        mSourceRecord = sourceRecord;
+        mVoiceSession = voiceSession;
+        mVoiceInteractor = voiceInteractor;
+
+        mLaunchBounds = getOverrideBounds(r, options, inTask);
+
+        mLaunchSingleTop = r.launchMode == LAUNCH_SINGLE_TOP;
+        mLaunchSingleInstance = r.launchMode == LAUNCH_SINGLE_INSTANCE;
+        mLaunchSingleTask = r.launchMode == LAUNCH_SINGLE_TASK;
+        mLaunchFlags = adjustLaunchFlagsToDocumentMode(
+                r, mLaunchSingleInstance, mLaunchSingleTask, mIntent.getFlags());
+        mLaunchTaskBehind = r.mLaunchTaskBehind
+                && !mLaunchSingleTask && !mLaunchSingleInstance
+                && (mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
+
+        sendNewTaskResultRequestIfNeeded();
+
+        if ((mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
+            mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
+        }
+
+        // If we are actually going to launch in to a new task, there are some cases where
+        // we further want to do multiple task.
+        if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
+            if (mLaunchTaskBehind
+                    || r.info.documentLaunchMode == DOCUMENT_LAUNCH_ALWAYS) {
+                mLaunchFlags |= FLAG_ACTIVITY_MULTIPLE_TASK;
+            }
+        }
+
+        // We'll invoke onUserLeaving before onPause only if the launching
+        // activity did not explicitly state that this is an automated launch.
+        mSupervisor.mUserLeaving = (mLaunchFlags & FLAG_ACTIVITY_NO_USER_ACTION) == 0;
+        if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
+                "startActivity() => mUserLeaving=" + mSupervisor.mUserLeaving);
+
+        // If the caller has asked not to resume at this point, we make note
+        // of this in the record so that we can skip it when trying to find
+        // the top running activity.
+        mDoResume = doResume;
+        if (!doResume || !mSupervisor.okToShowLocked(r)) {
+            r.delayedResume = true;
+            mDoResume = false;
+        }
+
+        mNotTop = (mLaunchFlags & FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
+
+        mInTask = inTask;
+        // In some flows in to this function, we retrieve the task record and hold on to it
+        // without a lock before calling back in to here...  so the task at this point may
+        // not actually be in recents.  Check for that, and if it isn't in recents just
+        // consider it invalid.
+        if (inTask != null && !inTask.inRecents) {
+            Slog.w(TAG, "Starting activity in task not in recents: " + inTask);
+            mInTask = null;
+        }
+
+        mStartFlags = startFlags;
+        // If the onlyIfNeeded flag is set, then we can do this if the activity being launched
+        // is the same as the one making the call...  or, as a special case, if we do not know
+        // the caller then we count the current top activity as the caller.
+        if ((startFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
+            ActivityRecord checkedCaller = sourceRecord;
+            if (checkedCaller == null) {
+                checkedCaller = mSupervisor.mFocusedStack.topRunningNonDelayedActivityLocked(
+                        mNotTop);
+            }
+            if (!checkedCaller.realActivity.equals(r.realActivity)) {
+                // Caller is not the same as launcher, so always needed.
+                mStartFlags &= ~START_FLAG_ONLY_IF_NEEDED;
+            }
+        }
+
+        mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0;
+    }
+
+    private void sendNewTaskResultRequestIfNeeded() {
+        if (mStartActivity.resultTo != null && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0
+                && mStartActivity.resultTo.task.stack != null) {
+            // For whatever reason this activity is being launched into a new task...
+            // yet the caller has requested a result back.  Well, that is pretty messed up,
+            // so instead immediately send back a cancel and let the new task continue launched
+            // as normal without a dependency on its originator.
+            Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
+            mStartActivity.resultTo.task.stack.sendActivityResultLocked(-1, mStartActivity.resultTo,
+                    mStartActivity.resultWho, mStartActivity.requestCode, RESULT_CANCELED, null);
+            mStartActivity.resultTo = null;
+        }
+    }
+
+    private void computeLaunchingTaskFlags() {
+        // If the caller is not coming from another activity, but has given us an explicit task into
+        // which they would like us to launch the new activity, then let's see about doing that.
+        if (mSourceRecord == null && mInTask != null && mInTask.stack != null) {
+            final Intent baseIntent = mInTask.getBaseIntent();
+            final ActivityRecord root = mInTask.getRootActivity();
+            if (baseIntent == null) {
+                ActivityOptions.abort(mOptions);
+                throw new IllegalArgumentException("Launching into task without base intent: "
+                        + mInTask);
+            }
+
+            // If this task is empty, then we are adding the first activity -- it
+            // determines the root, and must be launching as a NEW_TASK.
+            if (mLaunchSingleInstance || mLaunchSingleTask) {
+                if (!baseIntent.getComponent().equals(mStartActivity.intent.getComponent())) {
+                    ActivityOptions.abort(mOptions);
+                    throw new IllegalArgumentException("Trying to launch singleInstance/Task "
+                            + mStartActivity + " into different task " + mInTask);
+                }
+                if (root != null) {
+                    ActivityOptions.abort(mOptions);
+                    throw new IllegalArgumentException("Caller with mInTask " + mInTask
+                            + " has root " + root + " but target is singleInstance/Task");
+                }
+            }
+
+            // If task is empty, then adopt the interesting intent launch flags in to the
+            // activity being started.
+            if (root == null) {
+                final int flagsOfInterest = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK
+                        | FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS;
+                mLaunchFlags = (mLaunchFlags & ~flagsOfInterest)
+                        | (baseIntent.getFlags() & flagsOfInterest);
+                mIntent.setFlags(mLaunchFlags);
+                mInTask.setIntent(mStartActivity);
+                mAddingToTask = true;
+
+                // If the task is not empty and the caller is asking to start it as the root of
+                // a new task, then we don't actually want to start this on the task. We will
+                // bring the task to the front, and possibly give it a new intent.
+            } else if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
+                mAddingToTask = false;
+
+            } else {
+                mAddingToTask = true;
+            }
+
+            mReuseTask = mInTask;
+        } else {
+            mInTask = null;
+            // Launch ResolverActivity in the source task, so that it stays in the task bounds
+            // when in freeform workspace.
+            // Also put noDisplay activities in the source task. These by itself can be placed
+            // in any task/stack, however it could launch other activities like ResolverActivity,
+            // and we want those to stay in the original task.
+            if ((mStartActivity.isResolverActivity() || mStartActivity.noDisplay) && mSourceRecord != null
+                    && mSourceRecord.isFreeform())  {
+                mAddingToTask = true;
+            }
+        }
+
+        if (mInTask == null) {
+            if (mSourceRecord == null) {
+                // This activity is not being started from another...  in this
+                // case we -always- start a new task.
+                if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {
+                    Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
+                            "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
+                    mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
+                }
+            } else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
+                // The original activity who is starting us is running as a single
+                // instance...  this new activity it is starting must go on its
+                // own task.
+                mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
+            } else if (mLaunchSingleInstance || mLaunchSingleTask) {
+                // The activity being started is a single instance...  it always
+                // gets launched into its own task.
+                mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
+            }
+        }
+    }
+
+    private void computeSourceStack() {
+        if (mSourceRecord == null) {
+            mSourceStack = null;
+            return;
+        }
+        if (!mSourceRecord.finishing) {
+            mSourceStack = mSourceRecord.task.stack;
+            return;
+        }
+
+        // If the source is finishing, we can't further count it as our source. This is because the
+        // task it is associated with may now be empty and on its way out, so we don't want to
+        // blindly throw it in to that task.  Instead we will take the NEW_TASK flow and try to find
+        // a task for it. But save the task information so it can be used when creating the new task.
+        if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0) {
+            Slog.w(TAG, "startActivity called from finishing " + mSourceRecord
+                    + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
+            mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
+            mNewTaskInfo = mSourceRecord.info;
+            mNewTaskIntent = mSourceRecord.task.intent;
+        }
+        mSourceRecord = null;
+        mSourceStack = null;
+    }
+
+    /**
+     * Decide whether the new activity should be inserted into an existing task. Returns null
+     * if not or an ActivityRecord with the task into which the new activity should be added.
+     */
+    private ActivityRecord getReusableIntentActivity() {
+        // We may want to try to place the new activity in to an existing task.  We always
+        // do this if the target activity is singleTask or singleInstance; we will also do
+        // this if NEW_TASK has been requested, and there is not an additional qualifier telling
+        // us to still place it in a new task: multi task, always doc mode, or being asked to
+        // launch this as a new task behind the current one.
+        boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
+                (mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
+                || mLaunchSingleInstance || mLaunchSingleTask;
+        // If bring to front is requested, and no result is requested and we have not been given
+        // an explicit task to launch in to, and we can find a task that was started with this
+        // same component, then instead of launching bring that one to the front.
+        putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
+        ActivityRecord intentActivity = null;
+        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.
+            intentActivity = mLaunchSingleInstance ? mSupervisor.findActivityLocked(mIntent, mStartActivity.info)
+                    : mSupervisor.findTaskLocked(mStartActivity);
+        }
+        return intentActivity;
+    }
+
+    private ActivityRecord setTargetStackAndMoveToFrontIfNeeded(ActivityRecord intentActivity) {
+        mTargetStack = intentActivity.task.stack;
+        mTargetStack.mLastPausedActivity = null;
+        // If the target task is not in the front, then we need to bring it to the front...
+        // except...  well, with SINGLE_TASK_LAUNCH it's not entirely clear. We'd like to have
+        // the same behavior as if a new instance was being started, which means not bringing it
+        // to the front if the caller is not itself in the front.
+        final ActivityStack focusStack = mSupervisor.getFocusedStack();
+        ActivityRecord curTop = (focusStack == null)
+                ? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
+
+        if (curTop != null && (curTop.task != intentActivity.task ||
+                curTop.task != focusStack.topTask())) {
+            mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
+            if (mSourceRecord == null || (mSourceStack.topActivity() != null &&
+                    mSourceStack.topActivity().task == mSourceRecord.task)) {
+                // We really do want to push this one into the user's face, right now.
+                if (mLaunchTaskBehind && mSourceRecord != null) {
+                    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 ((mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
+                        == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
+                    // Caller wants to appear on home activity.
+                    intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+                }
+                mOptions = null;
+            }
+        }
+        if (!mMovedToFront && mDoResume) {
+            if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Bring to front target: " + mTargetStack
+                    + " from " + intentActivity);
+            mTargetStack.moveToFront("intentActivityFound");
+        }
+
+        // If the caller has requested that the target task be reset, then do so.
+        if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
+            return mTargetStack.resetTaskIfNeededLocked(intentActivity, mStartActivity);
+        }
+        return intentActivity;
+    }
+
+    private void setTaskFromIntentActivity(ActivityRecord intentActivity) {
+        if ((mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
+                == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
+            // The caller has requested to completely replace any existing task with its new
+            // activity. Well that should not be too hard...
+            mReuseTask = intentActivity.task;
+            mReuseTask.performClearTaskLocked();
+            mReuseTask.setIntent(mStartActivity);
+        } else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
+                || mLaunchSingleInstance || mLaunchSingleTask) {
+            ActivityRecord top = intentActivity.task.performClearTaskLocked(mStartActivity,
+                    mLaunchFlags);
+            if (top == null) {
+                // A special case: we need to start the activity because it is not currently
+                // running, and the caller has asked to clear the current task to have this
+                // activity at the top.
+                mAddingToTask = true;
+                // Now pretend like this activity is being started by the top of its task, so it
+                // is put in the right place.
+                mSourceRecord = intentActivity;
+                final TaskRecord task = mSourceRecord.task;
+                if (task != null && task.stack == null) {
+                    // Target stack got cleared when we all activities were removed above.
+                    // Go ahead and reset it.
+                    mTargetStack = computeStackFocus(mSourceRecord, false /* newTask */,
+                            null /* bounds */, mLaunchFlags, mOptions);
+                    mTargetStack.addTask(task,
+                            !mLaunchTaskBehind /* toTop */, "startActivityUnchecked");
+                }
+            }
+        } else if (mStartActivity.realActivity.equals(intentActivity.task.realActivity)) {
+            // In this case the top activity on the task is the same as the one being launched,
+            // so we take that as a request to bring the task to the foreground. If the top
+            // activity in the task is the root activity, deliver this new intent to it if it
+            // desires.
+            if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop)
+                    && intentActivity.realActivity.equals(mStartActivity.realActivity)) {
+                ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity,
+                        intentActivity.task);
+                if (intentActivity.frontOfTask) {
+                    intentActivity.task.setIntent(mStartActivity);
+                }
+                intentActivity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
+                        mStartActivity.launchedFromPackage);
+            } else if (!mStartActivity.intent.filterEquals(intentActivity.task.intent)) {
+                // 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;
+                mSourceRecord = intentActivity;
+            }
+        } else if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
+            // In this case an activity is being launched in to an existing task, without
+            // resetting that task. This is typically the situation of launching an activity
+            // from a notification or shortcut. We want to place the new activity on top of the
+            // current task.
+            mAddingToTask = true;
+            mSourceRecord = intentActivity;
+        } else if (!intentActivity.task.rootWasReset) {
+            // In this case we are launching into an existing task that has not yet been started
+            // from its front door. The current task has been brought to the front. Ideally,
+            // we'd probably like to place this new task at the bottom of its stack, but that's
+            // a little hard to do with the current organization of the code so for now we'll
+            // just drop it.
+            intentActivity.task.setIntent(mStartActivity);
+        }
+    }
+
+    private void resumeTargetStackIfNeeded() {
+        if (mDoResume) {
+            mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, null, mOptions);
+            if (!mMovedToFront) {
+                // Make sure to notify Keyguard as well if we are not running an app transition
+                // later.
+                mSupervisor.notifyActivityDrawnForKeyguard();
+            }
+        } else {
+            ActivityOptions.abort(mOptions);
+        }
+        mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
+    }
+
+    private void setTaskFromReuseOrCreateNewTask(TaskRecord taskToAffiliate) {
+        mTargetStack = computeStackFocus(mStartActivity, true, mLaunchBounds, mLaunchFlags,
+                mOptions);
+        if (mDoResume) {
+            mTargetStack.moveToFront("startingNewTask");
+        }
+
+        if (mReuseTask == null) {
+            final TaskRecord task = mTargetStack.createTaskRecord(
+                    mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId),
+                    mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
+                    mNewTaskIntent != null ? mNewTaskIntent : mIntent,
+                    mVoiceSession, mVoiceInteractor, !mLaunchTaskBehind /* toTop */);
+            mStartActivity.setTask(task, taskToAffiliate);
+            if (mLaunchBounds != null) {
+                final int stackId = mTargetStack.mStackId;
+                if (StackId.resizeStackWithLaunchBounds(stackId)) {
+                    mSupervisor.resizeStackLocked(stackId, mLaunchBounds,
+                            null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
+                            !PRESERVE_WINDOWS, true /* allowResizeInDockedMode */);
+                } else {
+                    mStartActivity.task.updateOverrideConfiguration(mLaunchBounds);
+                }
+            }
+            if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+                    "Starting new activity " +
+                            mStartActivity + " in new task " + mStartActivity.task);
+        } else {
+            mStartActivity.setTask(mReuseTask, taskToAffiliate);
+        }
+    }
+
+    private int setTaskFromSourceRecord() {
+        final TaskRecord sourceTask = mSourceRecord.task;
+        // We only want to allow changing stack if the target task is not the top one,
+        // otherwise we would move the launching task to the other side, rather than show
+        // two side by side.
+        final boolean launchToSideAllowed = sourceTask.stack.topTask() != sourceTask;
+        mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task, mOptions, launchToSideAllowed);
+
+        if (mTargetStack == null) {
+            mTargetStack = sourceTask.stack;
+        } else if (mTargetStack != sourceTask.stack) {
+            mSupervisor.moveTaskToStackLocked(sourceTask.taskId, mTargetStack.mStackId,
+                    ON_TOP, FORCE_FOCUS, "launchToSide", !ANIMATE);
+        }
+        if (mDoResume) {
+            mTargetStack.moveToFront("sourceStackToFront");
+        }
+        final TaskRecord topTask = mTargetStack.topTask();
+        if (topTask != sourceTask) {
+            mTargetStack.moveTaskToFrontLocked(sourceTask, mNoAnimation, mOptions,
+                    mStartActivity.appTimeTracker, "sourceTaskToFront");
+        }
+        if (!mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0) {
+            // In this case, we are adding the activity to an existing task, but the caller has
+            // asked to clear that task if the activity is already running.
+            ActivityRecord top = sourceTask.performClearTaskLocked(mStartActivity, mLaunchFlags);
+            mKeepCurTransition = true;
+            if (top != null) {
+                ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
+                top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+                // For paranoia, make sure we have correctly resumed the top activity.
+                mTargetStack.mLastPausedActivity = null;
+                if (mDoResume) {
+                    mSupervisor.resumeFocusedStackTopActivityLocked();
+                }
+                ActivityOptions.abort(mOptions);
+                return START_DELIVERED_TO_TOP;
+            }
+        } else if (!mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
+            // In this case, we are launching an activity in our own task that may already be
+            // running somewhere in the history, and we want to shuffle it to the front of the
+            // stack if so.
+            final ActivityRecord top = sourceTask.findActivityInHistoryLocked(mStartActivity);
+            if (top != null) {
+                final TaskRecord task = top.task;
+                task.moveActivityToFrontLocked(top);
+                top.updateOptionsLocked(mOptions);
+                ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, task);
+                top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+                mTargetStack.mLastPausedActivity = null;
+                if (mDoResume) {
+                    mSupervisor.resumeFocusedStackTopActivityLocked();
+                }
+                return START_DELIVERED_TO_TOP;
+            }
+        }
+
+        // An existing activity is starting this new activity, so we want to keep the new one in
+        // the same task as the one that is starting it.
+        mStartActivity.setTask(sourceTask, null);
+        if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
+                + " in existing task " + mStartActivity.task + " from source " + mSourceRecord);
+        return START_SUCCESS;
+    }
+
+    private int setTaskFromInTask() {
+        if (mLaunchBounds != null) {
+            mInTask.updateOverrideConfiguration(mLaunchBounds);
+            int stackId = mInTask.getLaunchStackId();
+            if (stackId != mInTask.stack.mStackId) {
+                mSupervisor.moveTaskToStackUncheckedLocked(
+                        mInTask, stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront");
+            }
+            if (StackId.resizeStackWithLaunchBounds(stackId)) {
+                mSupervisor.resizeStackLocked(stackId, mLaunchBounds,
+                        null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
+                        !PRESERVE_WINDOWS, true /* allowResizeInDockedMode */);
+            }
+        }
+        mTargetStack = mInTask.stack;
+        mTargetStack.moveTaskToFrontLocked(
+                mInTask, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "inTaskToFront");
+
+        // Check whether we should actually launch the new activity in to the task,
+        // or just reuse the current activity on top.
+        ActivityRecord top = mInTask.getTopActivity();
+        if (top != null && top.realActivity.equals(mStartActivity.realActivity) && top.userId == mStartActivity.userId) {
+            if ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
+                    || mLaunchSingleTop || mLaunchSingleTask) {
+                ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
+                if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
+                    // We don't need to start a new activity, and the client said not to do
+                    // anything if that is the case, so this is it!
+                    return START_RETURN_INTENT_TO_CALLER;
+                }
+                top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+                return START_DELIVERED_TO_TOP;
+            }
+        }
+
+        if (!mAddingToTask) {
+            // We don't actually want to have this activity added to the task, so just
+            // stop here but still tell the caller that we consumed the intent.
+            ActivityOptions.abort(mOptions);
+            return START_TASK_TO_FRONT;
+        }
+
+        mStartActivity.setTask(mInTask, null);
+        if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+                "Starting new activity " + mStartActivity + " in explicit task " + mStartActivity.task);
+
+        return START_SUCCESS;
+    }
+
+    private void setTaskToCurrentTopOrCreateNewTask() {
+        mTargetStack = computeStackFocus(mStartActivity, false, null /* bounds */, mLaunchFlags,
+                mOptions);
+        if (mDoResume) {
+            mTargetStack.moveToFront("addingToTopTask");
+        }
+        final ActivityRecord prev = mTargetStack.topActivity();
+        final TaskRecord task = (prev != null) ? prev.task : mTargetStack.createTaskRecord(
+                        mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId),
+                        mStartActivity.info, mIntent, null, null, true);
+        mStartActivity.setTask(task, null);
+        mWindowManager.moveTaskToTop(mStartActivity.task.taskId);
+        if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+                "Starting new activity " + mStartActivity + " in new guessed " + mStartActivity.task);
+    }
+
+    private int adjustLaunchFlagsToDocumentMode(ActivityRecord r, boolean launchSingleInstance,
+            boolean launchSingleTask, int launchFlags) {
+        if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
+                (launchSingleInstance || launchSingleTask)) {
+            // We have a conflict between the Intent and the Activity manifest, manifest wins.
+            Slog.i(TAG, "Ignoring FLAG_ACTIVITY_NEW_DOCUMENT, launchMode is " +
+                    "\"singleInstance\" or \"singleTask\"");
+            launchFlags &=
+                    ~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_MULTIPLE_TASK);
+        } else {
+            switch (r.info.documentLaunchMode) {
+                case ActivityInfo.DOCUMENT_LAUNCH_NONE:
+                    break;
+                case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
+                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+                    break;
+                case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
+                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+                    break;
+                case ActivityInfo.DOCUMENT_LAUNCH_NEVER:
+                    launchFlags &= ~FLAG_ACTIVITY_MULTIPLE_TASK;
+                    break;
+            }
+        }
+        return launchFlags;
+    }
+
+    final void doPendingActivityLaunchesLocked(boolean doResume) {
+        while (!mPendingActivityLaunches.isEmpty()) {
+            final PendingActivityLaunch pal = mPendingActivityLaunches.remove(0);
+            final boolean resume = doResume && mPendingActivityLaunches.isEmpty();
+            try {
+                final int result = startActivityUnchecked(
+                        pal.r, pal.sourceRecord, null, null, pal.startFlags, resume, null, null);
+                postStartActivityUncheckedProcessing(
+                        pal.r, result, mSupervisor.mFocusedStack.mStackId);
+            } catch (Exception e) {
+                Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e);
+                pal.sendErrorResult(e.getMessage());
+            }
+        }
+    }
+
+    private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, Rect bounds,
+            int launchFlags, ActivityOptions aOptions) {
+        final TaskRecord task = r.task;
+        if (!(r.isApplicationActivity() || (task != null && task.isApplicationTask()))) {
+            return mSupervisor.mHomeStack;
+        }
+
+        ActivityStack stack = getLaunchStack(r, launchFlags, task, aOptions, true);
+        if (stack != null) {
+            return stack;
+        }
+
+        if (task != null && task.stack != null) {
+            stack = task.stack;
+            if (stack.isOnHomeDisplay()) {
+                if (mSupervisor.mFocusedStack != stack) {
+                    if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
+                            "computeStackFocus: Setting " + "focused stack to r=" + r
+                                    + " task=" + task);
+                } else {
+                    if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
+                            "computeStackFocus: Focused stack already="
+                                    + mSupervisor.mFocusedStack);
+                }
+            }
+            return stack;
+        }
+
+        final ActivityStackSupervisor.ActivityContainer container = r.mInitialActivityContainer;
+        if (container != null) {
+            // The first time put it on the desired stack, after this put on task stack.
+            r.mInitialActivityContainer = null;
+            return container.mStack;
+        }
+
+        // The fullscreen stack can contain any task regardless of if the task is resizeable
+        // or not. So, we let the task go in the fullscreen task if it is the focus stack.
+        // If the freeform or docked stack has focus, and the activity to be launched is resizeable,
+        // we can also put it in the focused stack.
+        final int focusedStackId = mSupervisor.mFocusedStack.mStackId;
+        final boolean canUseFocusedStack =
+                focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID
+                        || focusedStackId == DOCKED_STACK_ID
+                        || (focusedStackId == FREEFORM_WORKSPACE_STACK_ID && r.isResizeable());
+        if (canUseFocusedStack && (!newTask
+                || mSupervisor.mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
+            if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
+                    "computeStackFocus: Have a focused stack=" + mSupervisor.mFocusedStack);
+            return mSupervisor.mFocusedStack;
+        }
+
+        // We first try to put the task in the first dynamic stack.
+        final ArrayList<ActivityStack> homeDisplayStacks = mSupervisor.mHomeStack.mStacks;
+        for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            stack = homeDisplayStacks.get(stackNdx);
+            if (!ActivityManager.StackId.isStaticStack(stack.mStackId)) {
+                if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
+                        "computeStackFocus: Setting focused stack=" + stack);
+                return stack;
+            }
+        }
+
+        // If there is no suitable dynamic stack then we figure out which static stack to use.
+        final int stackId = task != null ? task.getLaunchStackId() :
+                bounds != null ? FREEFORM_WORKSPACE_STACK_ID :
+                        FULLSCREEN_WORKSPACE_STACK_ID;
+        stack = mSupervisor.getStack(stackId, CREATE_IF_NEEDED, ON_TOP);
+        if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
+                + r + " stackId=" + stack.mStackId);
+        return stack;
+    }
+
+    private ActivityStack getLaunchStack(ActivityRecord r, int launchFlags, TaskRecord task,
+            ActivityOptions aOptions, boolean launchToSideAllowed) {
+        final int launchStackId =
+                (aOptions != null) ? aOptions.getLaunchStackId() : INVALID_STACK_ID;
+
+        if (isValidLaunchStackId(launchStackId, r)) {
+            return mSupervisor.getStack(launchStackId, CREATE_IF_NEEDED, ON_TOP);
+        }
+
+        if (!launchToSideAllowed || (launchFlags & FLAG_ACTIVITY_LAUNCH_TO_SIDE) == 0) {
+            return null;
+        }
+
+        // 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);
+        } 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;
+            } else {
+                return stack;
+            }
+        }
+    }
+
+    private boolean isValidLaunchStackId(int stackId, ActivityRecord r) {
+        if (stackId == INVALID_STACK_ID || stackId == HOME_STACK_ID
+                || !StackId.isStaticStack(stackId)) {
+            return false;
+        }
+
+        final boolean resizeable = r.isResizeable() || mService.mForceResizableActivities;
+
+        if (stackId != FULLSCREEN_WORKSPACE_STACK_ID && !resizeable) {
+            return false;
+        }
+
+        if (stackId == FREEFORM_WORKSPACE_STACK_ID && !mService.mSupportsFreeformWindowManagement) {
+            return false;
+        }
+
+        final boolean supportsPip = mService.mSupportsPictureInPicture
+                && (r.supportsPictureInPicture() || mService.mForceResizableActivities);
+        if (stackId == PINNED_STACK_ID && !supportsPip) {
+            return false;
+        }
+        return true;
+    }
+
+    Rect getOverrideBounds(ActivityRecord r, ActivityOptions options, TaskRecord inTask) {
+        Rect newBounds = null;
+        if (options != null && (r.isResizeable() || (inTask != null && inTask.mResizeable))) {
+            if (mSupervisor.canUseActivityOptionsLaunchBounds(
+                    options, options.getLaunchStackId())) {
+                newBounds = TaskRecord.validateBounds(options.getLaunchBounds());
+            }
+        }
+        return newBounds;
+    }
+
+    void setWindowManager(WindowManagerService wm) {
+        mWindowManager = wm;
+    }
+
+    void removePendingActivityLaunchesLocked(ActivityStack stack) {
+        for (int palNdx = mPendingActivityLaunches.size() - 1; palNdx >= 0; --palNdx) {
+            PendingActivityLaunch pal = mPendingActivityLaunches.get(palNdx);
+            if (pal.stack == stack) {
+                mPendingActivityLaunches.remove(palNdx);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/AppErrorDialog.java b/services/core/java/com/android/server/am/AppErrorDialog.java
index c87eae0..b746a4b 100644
--- a/services/core/java/com/android/server/am/AppErrorDialog.java
+++ b/services/core/java/com/android/server/am/AppErrorDialog.java
@@ -16,73 +16,74 @@
 
 package com.android.server.am;
 
+import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions;
 import android.content.Context;
-import android.content.DialogInterface;
+import android.content.pm.IPackageDataObserver;
+import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.util.Slog;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.WindowManager;
-import android.widget.CheckBox;
 import android.widget.FrameLayout;
 import android.widget.TextView;
 
-final class AppErrorDialog extends BaseErrorDialog {
+import java.util.List;
+
+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;
+    private final boolean mRepeating;
+
     private CharSequence mName;
 
     // Event 'what' codes
-    static final int FORCE_QUIT = 0;
-    static final int FORCE_QUIT_AND_REPORT = 1;
+    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;
 
     // 5-minute timeout, then we automatically dismiss the crash dialog
     static final long DISMISS_TIMEOUT = 1000 * 60 * 5;
-    
-    public AppErrorDialog(Context context, ActivityManagerService service,
-            AppErrorResult result, ProcessRecord app) {
-        super(context);
 
+    public AppErrorDialog(Context context, ActivityManagerService service, Data data) {
+        super(context);
         Resources res = context.getResources();
 
         mService = service;
-        mProc = app;
-        mResult = result;
-        if ((app.pkgList.size() == 1) &&
-                (mName = context.getPackageManager().getApplicationLabel(app.info)) != null) {
-            setMessage(res.getString(
-                    com.android.internal.R.string.aerr_application,
-                    mName.toString(), app.info.processName));
+        mProc = data.proc;
+        mResult = data.result;
+        mRepeating = data.repeating;
+        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));
         } else {
-            mName = app.processName;
-            setMessage(res.getString(
-                    com.android.internal.R.string.aerr_process,
+            mName = mProc.processName;
+            setTitle(res.getString(
+                    mRepeating ? com.android.internal.R.string.aerr_process_repeated
+                            : com.android.internal.R.string.aerr_process,
                     mName.toString()));
         }
 
         setCancelable(false);
 
-        setButton(DialogInterface.BUTTON_POSITIVE,
-                res.getText(com.android.internal.R.string.force_close),
-                mHandler.obtainMessage(FORCE_QUIT));
-
-        if (app.errorReportReceiver != null) {
-            setButton(DialogInterface.BUTTON_NEGATIVE,
-                    res.getText(com.android.internal.R.string.report),
-                    mHandler.obtainMessage(FORCE_QUIT_AND_REPORT));
-        }
-
-        setTitle(res.getText(com.android.internal.R.string.aerr_title));
         WindowManager.LayoutParams attrs = getWindow().getAttributes();
-        attrs.setTitle("Application Error: " + app.info.processName);
+        attrs.setTitle("Application Error: " + mProc.info.processName);
         attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR
                 | WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
         getWindow().setAttributes(attrs);
-        if (app.persistent) {
+        if (mProc.persistent) {
             getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
         }
 
@@ -95,38 +96,44 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        if (!ActivityManagerService.IS_USER_BUILD) {
-            FrameLayout frame = (FrameLayout) findViewById(android.R.id.custom);
-            Context context = getContext();
-            LayoutInflater.from(context).inflate(
-                    com.android.internal.R.layout.app_error_dialog_dont_show_again, frame, true);
-            ((TextView) frame.findViewById(com.android.internal.R.id.text)).setText(
-                    context.getResources().getString(
-                            com.android.internal.R.string.aerr_process_silence,
-                            mName.toString()));
-            findViewById(com.android.internal.R.id.customPanel).setVisibility(View.VISIBLE);
-        }
+        final FrameLayout frame = (FrameLayout) findViewById(android.R.id.custom);
+        final Context context = getContext();
+        LayoutInflater.from(context).inflate(
+                com.android.internal.R.layout.app_error_dialog, frame, true);
+
+        final TextView restart = (TextView) findViewById(com.android.internal.R.id.aerr_restart);
+        restart.setOnClickListener(this);
+        restart.setVisibility(!mRepeating ? View.VISIBLE : View.GONE);
+        final TextView reset = (TextView) findViewById(com.android.internal.R.id.aerr_reset);
+        reset.setOnClickListener(this);
+        reset.setVisibility(mRepeating ? View.VISIBLE : View.GONE);
+        final TextView report = (TextView) findViewById(com.android.internal.R.id.aerr_report);
+        report.setOnClickListener(this);
+        final boolean hasReceiver = mProc.errorReportReceiver != null;
+        report.setVisibility(hasReceiver ? View.VISIBLE : View.GONE);
+        final TextView close = (TextView) findViewById(com.android.internal.R.id.aerr_close);
+        close.setOnClickListener(this);
+        final TextView mute = (TextView) findViewById(com.android.internal.R.id.aerr_mute);
+        mute.setOnClickListener(this);
+        mute.setVisibility(!IS_USER_BUILD ? View.VISIBLE : View.GONE);
+
+        findViewById(com.android.internal.R.id.customPanel).setVisibility(View.VISIBLE);
     }
 
     private final Handler mHandler = new Handler() {
         public void handleMessage(Message msg) {
-            View view = findViewById(com.android.internal.R.id.checkbox);
-            final boolean stopReporting = view != null && ((CheckBox) view).isChecked();
+            final int result = msg.what;
+
             synchronized (mService) {
                 if (mProc != null && mProc.crashDialog == AppErrorDialog.this) {
                     mProc.crashDialog = null;
                 }
-                if (stopReporting) {
-                    mService.stopReportingCrashesLocked(mProc);
-                }
             }
-            mResult.set(msg.what);
+            mResult.set(result);
 
             // Make sure we don't have time timeout still hanging around.
             removeMessages(FORCE_QUIT);
 
-            // If this is a timeout we won't be automatically closed, so go
-            // ahead and explicitly dismiss ourselves just in case.
             dismiss();
         }
     };
@@ -139,4 +146,34 @@
         }
         super.dismiss();
     }
+
+    @Override
+    public void onClick(View v) {
+        switch (v.getId()) {
+            case com.android.internal.R.id.aerr_restart:
+                mHandler.obtainMessage(RESTART).sendToTarget();
+                break;
+            case com.android.internal.R.id.aerr_reset:
+                mHandler.obtainMessage(RESET).sendToTarget();
+                break;
+            case com.android.internal.R.id.aerr_report:
+                mHandler.obtainMessage(FORCE_QUIT_AND_REPORT).sendToTarget();
+                break;
+            case com.android.internal.R.id.aerr_close:
+                mHandler.obtainMessage(FORCE_QUIT).sendToTarget();
+                break;
+            case com.android.internal.R.id.aerr_mute:
+                mHandler.obtainMessage(MUTE).sendToTarget();
+                break;
+            default:
+                break;
+        }
+    }
+
+    static class Data {
+        AppErrorResult result;
+        TaskRecord task;
+        boolean repeating;
+        ProcessRecord proc;
+    }
 }
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
new file mode 100644
index 0000000..58d9f45
--- /dev/null
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -0,0 +1,964 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 com.android.internal.app.ProcessMap;
+import com.android.internal.os.ProcessCpuTracker;
+import com.android.server.Watchdog;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.ActivityThread;
+import android.app.AppOpsManager;
+import android.app.ApplicationErrorReport;
+import android.app.Dialog;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageDataObserver;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Message;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.EventLog;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.concurrent.Semaphore;
+
+import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
+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;
+import static com.android.server.am.ActivityManagerService.SYSTEM_DEBUGGABLE;
+
+/**
+ * Controls error conditions in applications.
+ */
+class AppErrors {
+
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "AppErrors" : TAG_AM;
+
+    private final ActivityManagerService mService;
+    private final Context mContext;
+
+    private ArraySet<String> mAppsNotReportingCrashes;
+
+    /**
+     * The last time that various processes have crashed since they were last explicitly started.
+     */
+    private final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<>();
+
+    /**
+     * The last time that various processes have crashed (not reset even when explicitly started).
+     */
+    private final ProcessMap<Long> mProcessCrashTimesPersistent = new ProcessMap<>();
+
+    /**
+     * Set of applications that we consider to be bad, and will reject
+     * incoming broadcasts from (which the user has no control over).
+     * Processes are added to this set when they have crashed twice within
+     * a minimum amount of time; they are removed from it when they are
+     * later restarted (hopefully due to some user action).  The value is the
+     * time it was added to the list.
+     */
+    private final ProcessMap<BadProcessInfo> mBadProcesses = new ProcessMap<>();
+
+
+    AppErrors(Context context, ActivityManagerService service) {
+        mService = service;
+        mContext = context;
+    }
+
+    boolean dumpLocked(FileDescriptor fd, PrintWriter pw, boolean needSep,
+            String dumpPackage) {
+        if (!mProcessCrashTimes.getMap().isEmpty()) {
+            boolean printed = false;
+            final long now = SystemClock.uptimeMillis();
+            final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
+            final int processCount = pmap.size();
+            for (int ip = 0; ip < processCount; ip++) {
+                final String pname = pmap.keyAt(ip);
+                final SparseArray<Long> uids = pmap.valueAt(ip);
+                final int uidCount = uids.size();
+                for (int i = 0; i < uidCount; i++) {
+                    final int puid = uids.keyAt(i);
+                    final ProcessRecord r = mService.mProcessNames.get(pname, puid);
+                    if (dumpPackage != null && (r == null
+                            || !r.pkgList.containsKey(dumpPackage))) {
+                        continue;
+                    }
+                    if (!printed) {
+                        if (needSep) pw.println();
+                        needSep = true;
+                        pw.println("  Time since processes crashed:");
+                        printed = true;
+                    }
+                    pw.print("    Process "); pw.print(pname);
+                    pw.print(" uid "); pw.print(puid);
+                    pw.print(": last crashed ");
+                    TimeUtils.formatDuration(now-uids.valueAt(i), pw);
+                    pw.println(" ago");
+                }
+            }
+        }
+
+        if (!mBadProcesses.getMap().isEmpty()) {
+            boolean printed = false;
+            final ArrayMap<String, SparseArray<BadProcessInfo>> pmap = mBadProcesses.getMap();
+            final int processCount = pmap.size();
+            for (int ip = 0; ip < processCount; ip++) {
+                final String pname = pmap.keyAt(ip);
+                final SparseArray<BadProcessInfo> uids = pmap.valueAt(ip);
+                final int uidCount = uids.size();
+                for (int i = 0; i < uidCount; i++) {
+                    final int puid = uids.keyAt(i);
+                    final ProcessRecord r = mService.mProcessNames.get(pname, puid);
+                    if (dumpPackage != null && (r == null
+                            || !r.pkgList.containsKey(dumpPackage))) {
+                        continue;
+                    }
+                    if (!printed) {
+                        if (needSep) pw.println();
+                        needSep = true;
+                        pw.println("  Bad processes:");
+                        printed = true;
+                    }
+                    final BadProcessInfo info = uids.valueAt(i);
+                    pw.print("    Bad process "); pw.print(pname);
+                    pw.print(" uid "); pw.print(puid);
+                    pw.print(": crashed at time "); pw.println(info.time);
+                    if (info.shortMsg != null) {
+                        pw.print("      Short msg: "); pw.println(info.shortMsg);
+                    }
+                    if (info.longMsg != null) {
+                        pw.print("      Long msg: "); pw.println(info.longMsg);
+                    }
+                    if (info.stack != null) {
+                        pw.println("      Stack:");
+                        int lastPos = 0;
+                        for (int pos = 0; pos < info.stack.length(); pos++) {
+                            if (info.stack.charAt(pos) == '\n') {
+                                pw.print("        ");
+                                pw.write(info.stack, lastPos, pos-lastPos);
+                                pw.println();
+                                lastPos = pos+1;
+                            }
+                        }
+                        if (lastPos < info.stack.length()) {
+                            pw.print("        ");
+                            pw.write(info.stack, lastPos, info.stack.length()-lastPos);
+                            pw.println();
+                        }
+                    }
+                }
+            }
+        }
+        return needSep;
+    }
+
+    boolean isBadProcessLocked(ApplicationInfo info) {
+        return mBadProcesses.get(info.processName, info.uid) != null;
+    }
+
+    void clearBadProcessLocked(ApplicationInfo info) {
+        mBadProcesses.remove(info.processName, info.uid);
+    }
+
+    void resetProcessCrashTimeLocked(ApplicationInfo info) {
+        mProcessCrashTimes.remove(info.processName, info.uid);
+    }
+
+    void resetProcessCrashTimeLocked(boolean resetEntireUser, int appId, int userId) {
+        final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
+        for (int ip = pmap.size() - 1; ip >= 0; ip--) {
+            SparseArray<Long> ba = pmap.valueAt(ip);
+            for (int i = ba.size() - 1; i >= 0; i--) {
+                boolean remove = false;
+                final int entUid = ba.keyAt(i);
+                if (!resetEntireUser) {
+                    if (userId == UserHandle.USER_ALL) {
+                        if (UserHandle.getAppId(entUid) == appId) {
+                            remove = true;
+                        }
+                    } else {
+                        if (entUid == UserHandle.getUid(userId, appId)) {
+                            remove = true;
+                        }
+                    }
+                } else if (UserHandle.getUserId(entUid) == userId) {
+                    remove = true;
+                }
+                if (remove) {
+                    ba.removeAt(i);
+                }
+            }
+            if (ba.size() == 0) {
+                pmap.removeAt(ip);
+            }
+        }
+    }
+
+    void loadAppsNotReportingCrashesFromConfigLocked(String appsNotReportingCrashesConfig) {
+        if (appsNotReportingCrashesConfig != null) {
+            final String[] split = appsNotReportingCrashesConfig.split(",");
+            if (split.length > 0) {
+                mAppsNotReportingCrashes = new ArraySet<>();
+                Collections.addAll(mAppsNotReportingCrashes, split);
+            }
+        }
+    }
+
+    void killAppAtUserRequestLocked(ProcessRecord app, Dialog fromDialog) {
+        app.crashing = false;
+        app.crashingReport = null;
+        app.notResponding = false;
+        app.notRespondingReport = null;
+        if (app.anrDialog == fromDialog) {
+            app.anrDialog = null;
+        }
+        if (app.waitDialog == fromDialog) {
+            app.waitDialog = null;
+        }
+        if (app.pid > 0 && app.pid != MY_PID) {
+            handleAppCrashLocked(app, "user-terminated" /*reason*/,
+                    null /*shortMsg*/, null /*longMsg*/, null /*stackTrace*/, null /*data*/);
+            app.kill("user request after error", true);
+        }
+    }
+
+    void scheduleAppCrashLocked(int uid, int initialPid, String packageName,
+            String message) {
+        ProcessRecord proc = null;
+
+        // Figure out which process to kill.  We don't trust that initialPid
+        // still has any relation to current pids, so must scan through the
+        // list.
+
+        synchronized (mService.mPidsSelfLocked) {
+            for (int i=0; i<mService.mPidsSelfLocked.size(); i++) {
+                ProcessRecord p = mService.mPidsSelfLocked.valueAt(i);
+                if (p.uid != uid) {
+                    continue;
+                }
+                if (p.pid == initialPid) {
+                    proc = p;
+                    break;
+                }
+                if (p.pkgList.containsKey(packageName)) {
+                    proc = p;
+                }
+            }
+        }
+
+        if (proc == null) {
+            Slog.w(TAG, "crashApplication: nothing for uid=" + uid
+                    + " initialPid=" + initialPid
+                    + " packageName=" + packageName);
+            return;
+        }
+
+        if (proc.thread != null) {
+            if (proc.pid == Process.myPid()) {
+                Log.w(TAG, "crashApplication: trying to crash self!");
+                return;
+            }
+            long ident = Binder.clearCallingIdentity();
+            try {
+                proc.thread.scheduleCrash(message);
+            } catch (RemoteException e) {
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+
+    /**
+     * Bring up the "unexpected error" dialog box for a crashing app.
+     * Deal with edge cases (intercepts from instrumented applications,
+     * ActivityController, error intent receivers, that sort of thing).
+     * @param r the application crashing
+     * @param crashInfo describing the failure
+     */
+    void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
+        long timeMillis = System.currentTimeMillis();
+        String shortMsg = crashInfo.exceptionClassName;
+        String longMsg = crashInfo.exceptionMessage;
+        String stackTrace = crashInfo.stackTrace;
+        if (shortMsg != null && longMsg != null) {
+            longMsg = shortMsg + ": " + longMsg;
+        } else if (shortMsg != null) {
+            longMsg = shortMsg;
+        }
+
+        AppErrorResult result = new AppErrorResult();
+        TaskRecord task;
+        synchronized (mService) {
+            if (mService.mController != null) {
+                try {
+                    String name = r != null ? r.processName : null;
+                    int pid = r != null ? r.pid : Binder.getCallingPid();
+                    int uid = r != null ? r.info.uid : Binder.getCallingUid();
+                    if (!mService.mController.appCrashed(name, pid,
+                            shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
+                        if ("1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"))
+                                && "Native crash".equals(crashInfo.exceptionClassName)) {
+                            Slog.w(TAG, "Skip killing native crashed app " + name
+                                    + "(" + pid + ") during testing");
+                        } else {
+                            Slog.w(TAG, "Force-killing crashed app " + name
+                                    + " at watcher's request");
+                            if (r != null) {
+                                r.kill("crash", true);
+                            } else {
+                                // Huh.
+                                Process.killProcess(pid);
+                                ActivityManagerService.killProcessGroup(uid, pid);
+                            }
+                        }
+                        return;
+                    }
+                } catch (RemoteException e) {
+                    mService.mController = null;
+                    Watchdog.getInstance().setActivityController(null);
+                }
+            }
+
+            final long origId = Binder.clearCallingIdentity();
+
+            // If this process is running instrumentation, finish it.
+            if (r != null && r.instrumentationClass != null) {
+                Slog.w(TAG, "Error in app " + r.processName
+                        + " running instrumentation " + r.instrumentationClass + ":");
+                if (shortMsg != null) Slog.w(TAG, "  " + shortMsg);
+                if (longMsg != null) Slog.w(TAG, "  " + longMsg);
+                Bundle info = new Bundle();
+                info.putString("shortMsg", shortMsg);
+                info.putString("longMsg", longMsg);
+                mService.finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
+                Binder.restoreCallingIdentity(origId);
+                return;
+            }
+
+            // Log crash in battery stats.
+            if (r != null) {
+                mService.mBatteryStatsService.noteProcessCrash(r.processName, r.uid);
+            }
+
+            AppErrorDialog.Data data = new AppErrorDialog.Data();
+            data.result = result;
+            data.proc = r;
+
+            // If we can't identify the process or it's already exceeded its crash quota,
+            // quit right away without showing a crash dialog.
+            if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, data)) {
+                Binder.restoreCallingIdentity(origId);
+                return;
+            }
+
+            Message msg = Message.obtain();
+            msg.what = ActivityManagerService.SHOW_ERROR_UI_MSG;
+
+            task = data.task;
+            msg.obj = data;
+            mService.mUiHandler.sendMessage(msg);
+
+            Binder.restoreCallingIdentity(origId);
+        }
+
+        int res = result.get();
+
+        Intent appErrorIntent = null;
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            if (res == AppErrorDialog.RESET) {
+                String[] packageList = r.getPackageList();
+                if (packageList != null) {
+                    PackageManager pm = mContext.getPackageManager();
+                    final Semaphore s = new Semaphore(0);
+                    for (int i = 0; i < packageList.length; i++) {
+                        if (i < packageList.length - 1) {
+                            pm.deleteApplicationCacheFiles(packageList[i], null);
+                        } else {
+                            pm.deleteApplicationCacheFiles(packageList[i],
+                                    new IPackageDataObserver.Stub() {
+                                        @Override
+                                        public void onRemoveCompleted(String packageName,
+                                                boolean succeeded) {
+                                            s.release();
+                                        }
+                                    });
+
+                            // Wait until cache has been cleared before we restart.
+                            try {
+                                s.acquire();
+                            } catch (InterruptedException e) {
+                            }
+                        }
+                    }
+                }
+                // If there was nothing to reset, just restart;
+                res = AppErrorDialog.RESTART;
+            }
+            synchronized (mService) {
+                if (res == AppErrorDialog.MUTE) {
+                    stopReportingCrashesLocked(r);
+                }
+                if (res == AppErrorDialog.RESTART) {
+                    mService.removeProcessLocked(r, false, true, "crash");
+                    if (task != null) {
+                        try {
+                            mService.startActivityFromRecents(task.taskId,
+                                    ActivityOptions.makeBasic().toBundle());
+                        } catch (IllegalArgumentException e) {
+                            // Hmm, that didn't work, app might have crashed before creating a
+                            // recents entry. Let's see if we have a safe-to-restart intent.
+                            if (task.intent.getCategories().contains(
+                                    Intent.CATEGORY_LAUNCHER)) {
+                                mService.startActivityInPackage(task.mCallingUid,
+                                        task.mCallingPackage, task.intent,
+                                        null, null, null, 0, 0,
+                                        ActivityOptions.makeBasic().toBundle(),
+                                        task.userId, null, null);
+                            }
+                        }
+                    }
+                }
+                if (res == AppErrorDialog.FORCE_QUIT) {
+                    long orig = Binder.clearCallingIdentity();
+                    try {
+                        // Kill it with fire!
+                        mService.mStackSupervisor.handleAppCrashLocked(r);
+                        if (!r.persistent) {
+                            mService.removeProcessLocked(r, false, false, "crash");
+                            mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
+                        }
+                    } finally {
+                        Binder.restoreCallingIdentity(orig);
+                    }
+                }
+                if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
+                    appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
+                }
+                if (r != null && !r.isolated && res != AppErrorDialog.RESTART) {
+                    // XXX Can't keep track of crash time for isolated processes,
+                    // since they don't have a persistent identity.
+                    mProcessCrashTimes.put(r.info.processName, r.uid,
+                            SystemClock.uptimeMillis());
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+
+        if (appErrorIntent != null) {
+            try {
+                mContext.startActivityAsUser(appErrorIntent, new UserHandle(r.userId));
+            } catch (ActivityNotFoundException e) {
+                Slog.w(TAG, "bug report receiver dissappeared", e);
+            }
+        }
+    }
+
+    private boolean makeAppCrashingLocked(ProcessRecord app,
+            String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
+        app.crashing = true;
+        app.crashingReport = generateProcessError(app,
+                ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
+        startAppProblemLocked(app);
+        app.stopFreezingAllLocked();
+        return handleAppCrashLocked(app, "force-crash" /*reason*/, shortMsg, longMsg, stackTrace,
+                data);
+    }
+
+    void startAppProblemLocked(ProcessRecord app) {
+        // If this app is not running under the current user, then we
+        // can't give it a report button because that would require
+        // launching the report UI under a different user.
+        app.errorReportReceiver = null;
+
+        for (int userId : mService.mUserController.getCurrentProfileIdsLocked()) {
+            if (app.userId == userId) {
+                app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
+                        mContext, app.info.packageName, app.info.flags);
+            }
+        }
+        mService.skipCurrentReceiverLocked(app);
+    }
+
+    /**
+     * Generate a process error record, suitable for attachment to a ProcessRecord.
+     *
+     * @param app The ProcessRecord in which the error occurred.
+     * @param condition Crashing, Application Not Responding, etc.  Values are defined in
+     *                      ActivityManager.AppErrorStateInfo
+     * @param activity The activity associated with the crash, if known.
+     * @param shortMsg Short message describing the crash.
+     * @param longMsg Long message describing the crash.
+     * @param stackTrace Full crash stack trace, may be null.
+     *
+     * @return Returns a fully-formed AppErrorStateInfo record.
+     */
+    private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
+            int condition, String activity, String shortMsg, String longMsg, String stackTrace) {
+        ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
+
+        report.condition = condition;
+        report.processName = app.processName;
+        report.pid = app.pid;
+        report.uid = app.info.uid;
+        report.tag = activity;
+        report.shortMsg = shortMsg;
+        report.longMsg = longMsg;
+        report.stackTrace = stackTrace;
+
+        return report;
+    }
+
+    Intent createAppErrorIntentLocked(ProcessRecord r,
+            long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
+        ApplicationErrorReport report = createAppErrorReportLocked(r, timeMillis, crashInfo);
+        if (report == null) {
+            return null;
+        }
+        Intent result = new Intent(Intent.ACTION_APP_ERROR);
+        result.setComponent(r.errorReportReceiver);
+        result.putExtra(Intent.EXTRA_BUG_REPORT, report);
+        result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        return result;
+    }
+
+    private ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r,
+            long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
+        if (r.errorReportReceiver == null) {
+            return null;
+        }
+
+        if (!r.crashing && !r.notResponding && !r.forceCrashReport) {
+            return null;
+        }
+
+        ApplicationErrorReport report = new ApplicationErrorReport();
+        report.packageName = r.info.packageName;
+        report.installerPackageName = r.errorReportReceiver.getPackageName();
+        report.processName = r.processName;
+        report.time = timeMillis;
+        report.systemApp = (r.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+
+        if (r.crashing || r.forceCrashReport) {
+            report.type = ApplicationErrorReport.TYPE_CRASH;
+            report.crashInfo = crashInfo;
+        } else if (r.notResponding) {
+            report.type = ApplicationErrorReport.TYPE_ANR;
+            report.anrInfo = new ApplicationErrorReport.AnrInfo();
+
+            report.anrInfo.activity = r.notRespondingReport.tag;
+            report.anrInfo.cause = r.notRespondingReport.shortMsg;
+            report.anrInfo.info = r.notRespondingReport.longMsg;
+        }
+
+        return report;
+    }
+
+    boolean handleAppCrashLocked(ProcessRecord app, String reason,
+            String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
+        long now = SystemClock.uptimeMillis();
+
+        Long crashTime;
+        Long crashTimePersistent;
+        if (!app.isolated) {
+            crashTime = mProcessCrashTimes.get(app.info.processName, app.uid);
+            crashTimePersistent = mProcessCrashTimesPersistent.get(app.info.processName, app.uid);
+        } else {
+            crashTime = crashTimePersistent = null;
+        }
+        if (crashTime != null && now < crashTime+ProcessList.MIN_CRASH_INTERVAL) {
+            // This process loses!
+            Slog.w(TAG, "Process " + app.info.processName
+                    + " has crashed too many times: killing!");
+            EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
+                    app.userId, app.info.processName, app.uid);
+            mService.mStackSupervisor.handleAppCrashLocked(app);
+            if (!app.persistent) {
+                // We don't want to start this process again until the user
+                // explicitly does so...  but for persistent process, we really
+                // need to keep it running.  If a persistent process is actually
+                // repeatedly crashing, then badness for everyone.
+                EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.userId, app.uid,
+                        app.info.processName);
+                if (!app.isolated) {
+                    // XXX We don't have a way to mark isolated processes
+                    // as bad, since they don't have a peristent identity.
+                    mBadProcesses.put(app.info.processName, app.uid,
+                            new BadProcessInfo(now, shortMsg, longMsg, stackTrace));
+                    mProcessCrashTimes.remove(app.info.processName, app.uid);
+                }
+                app.bad = true;
+                app.removed = true;
+                // Don't let services in this process be restarted and potentially
+                // annoy the user repeatedly.  Unless it is persistent, since those
+                // processes run critical code.
+                mService.removeProcessLocked(app, false, false, "crash");
+                mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
+                return false;
+            }
+            mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
+        } else {
+            TaskRecord affectedTask =
+                    mService.mStackSupervisor.finishTopRunningActivityLocked(app, reason);
+            if (data != null) {
+                data.task = affectedTask;
+            }
+            if (data != null && crashTimePersistent != null
+                    && now < crashTimePersistent + ProcessList.MIN_CRASH_INTERVAL) {
+                data.repeating = true;
+            }
+        }
+
+        // Bump up the crash count of any services currently running in the proc.
+        for (int i=app.services.size()-1; i>=0; i--) {
+            // Any services running in the application need to be placed
+            // back in the pending list.
+            ServiceRecord sr = app.services.valueAt(i);
+            sr.crashCount++;
+        }
+
+        // If the crashing process is what we consider to be the "home process" and it has been
+        // replaced by a third-party app, clear the package preferred activities from packages
+        // with a home activity running in the process to prevent a repeatedly crashing app
+        // from blocking the user to manually clear the list.
+        final ArrayList<ActivityRecord> activities = app.activities;
+        if (app == mService.mHomeProcess && activities.size() > 0
+                && (mService.mHomeProcess.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                if (r.isHomeActivity()) {
+                    Log.i(TAG, "Clearing package preferred activities from " + r.packageName);
+                    try {
+                        ActivityThread.getPackageManager()
+                                .clearPackagePreferredActivities(r.packageName);
+                    } catch (RemoteException c) {
+                        // pm is in same process, this will never happen.
+                    }
+                }
+            }
+        }
+
+        if (!app.isolated) {
+            // XXX Can't keep track of crash times for isolated processes,
+            // because they don't have a perisistent identity.
+            mProcessCrashTimes.put(app.info.processName, app.uid, now);
+            mProcessCrashTimesPersistent.put(app.info.processName, app.uid, now);
+        }
+
+        if (app.crashHandler != null) mService.mHandler.post(app.crashHandler);
+        return true;
+    }
+
+    void handleShowAppErrorUi(Message msg) {
+        AppErrorDialog.Data data = (AppErrorDialog.Data) msg.obj;
+        boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
+        synchronized (mService) {
+            ProcessRecord proc = data.proc;
+            AppErrorResult res = data.result;
+            if (proc != null && proc.crashDialog != null) {
+                Slog.e(TAG, "App already has crash dialog: " + proc);
+                if (res != null) {
+                    res.set(0);
+                }
+                return;
+            }
+            boolean isBackground = (UserHandle.getAppId(proc.uid)
+                    >= Process.FIRST_APPLICATION_UID
+                    && proc.pid != MY_PID);
+            for (int userId : mService.mUserController.getCurrentProfileIdsLocked()) {
+                isBackground &= (proc.userId != userId);
+            }
+            if (isBackground && !showBackground) {
+                Slog.w(TAG, "Skipping crash dialog of " + proc + ": background");
+                if (res != null) {
+                    res.set(0);
+                }
+                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;
+            } 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);
+                }
+            }
+        }
+    }
+
+    void stopReportingCrashesLocked(ProcessRecord proc) {
+        if (mAppsNotReportingCrashes == null) {
+            mAppsNotReportingCrashes = new ArraySet<>();
+        }
+        mAppsNotReportingCrashes.add(proc.info.packageName);
+    }
+
+    final void appNotResponding(ProcessRecord app, ActivityRecord activity,
+            ActivityRecord parent, boolean aboveSystem, final String annotation) {
+        ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
+        SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20);
+
+        if (mService.mController != null) {
+            try {
+                // 0 == continue, -1 = kill process immediately
+                int res = mService.mController.appEarlyNotResponding(app.processName, app.pid, annotation);
+                if (res < 0 && app.pid != MY_PID) {
+                    app.kill("anr", true);
+                }
+            } catch (RemoteException e) {
+                mService.mController = null;
+                Watchdog.getInstance().setActivityController(null);
+            }
+        }
+
+        long anrTime = SystemClock.uptimeMillis();
+        if (ActivityManagerService.MONITOR_CPU_USAGE) {
+            mService.updateCpuStatsNow();
+        }
+
+        synchronized (mService) {
+            // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
+            if (mService.mShuttingDown) {
+                Slog.i(TAG, "During shutdown skipping ANR: " + app + " " + annotation);
+                return;
+            } else if (app.notResponding) {
+                Slog.i(TAG, "Skipping duplicate ANR: " + app + " " + annotation);
+                return;
+            } else if (app.crashing) {
+                Slog.i(TAG, "Crashing app skipping ANR: " + app + " " + annotation);
+                return;
+            }
+
+            // In case we come through here for the same app before completing
+            // this one, mark as anring now so we will bail out.
+            app.notResponding = true;
+
+            // Log the ANR to the event log.
+            EventLog.writeEvent(EventLogTags.AM_ANR, app.userId, app.pid,
+                    app.processName, app.info.flags, annotation);
+
+            // Dump thread traces as quickly as we can, starting with "interesting" processes.
+            firstPids.add(app.pid);
+
+            int parentPid = app.pid;
+            if (parent != null && parent.app != null && parent.app.pid > 0) {
+                parentPid = parent.app.pid;
+            }
+            if (parentPid != app.pid) firstPids.add(parentPid);
+
+            if (MY_PID != app.pid && MY_PID != parentPid) firstPids.add(MY_PID);
+
+            for (int i = mService.mLruProcesses.size() - 1; i >= 0; i--) {
+                ProcessRecord r = mService.mLruProcesses.get(i);
+                if (r != null && r.thread != null) {
+                    int pid = r.pid;
+                    if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) {
+                        if (r.persistent) {
+                            firstPids.add(pid);
+                        } else {
+                            lastPids.put(pid, Boolean.TRUE);
+                        }
+                    }
+                }
+            }
+        }
+
+        // Log the ANR to the main log.
+        StringBuilder info = new StringBuilder();
+        info.setLength(0);
+        info.append("ANR in ").append(app.processName);
+        if (activity != null && activity.shortComponentName != null) {
+            info.append(" (").append(activity.shortComponentName).append(")");
+        }
+        info.append("\n");
+        info.append("PID: ").append(app.pid).append("\n");
+        if (annotation != null) {
+            info.append("Reason: ").append(annotation).append("\n");
+        }
+        if (parent != null && parent != activity) {
+            info.append("Parent: ").append(parent.shortComponentName).append("\n");
+        }
+
+        final ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
+
+        File tracesFile = mService.dumpStackTraces(true, firstPids, processCpuTracker, lastPids,
+                NATIVE_STACKS_OF_INTEREST);
+
+        String cpuInfo = null;
+        if (ActivityManagerService.MONITOR_CPU_USAGE) {
+            mService.updateCpuStatsNow();
+            synchronized (mService.mProcessCpuTracker) {
+                cpuInfo = mService.mProcessCpuTracker.printCurrentState(anrTime);
+            }
+            info.append(processCpuTracker.printCurrentLoad());
+            info.append(cpuInfo);
+        }
+
+        info.append(processCpuTracker.printCurrentState(anrTime));
+
+        Slog.e(TAG, info.toString());
+        if (tracesFile == null) {
+            // There is no trace file, so dump (only) the alleged culprit's threads to the log
+            Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
+        }
+
+        mService.addErrorToDropBox("anr", app, app.processName, activity, parent, annotation,
+                cpuInfo, tracesFile, null);
+
+        if (mService.mController != null) {
+            try {
+                // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
+                int res = mService.mController.appNotResponding(
+                        app.processName, app.pid, info.toString());
+                if (res != 0) {
+                    if (res < 0 && app.pid != MY_PID) {
+                        app.kill("anr", true);
+                    } else {
+                        synchronized (mService) {
+                            mService.mServices.scheduleServiceTimeoutLocked(app);
+                        }
+                    }
+                    return;
+                }
+            } catch (RemoteException e) {
+                mService.mController = null;
+                Watchdog.getInstance().setActivityController(null);
+            }
+        }
+
+        // Unless configured otherwise, swallow ANRs in background processes & kill the process.
+        boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
+
+        synchronized (mService) {
+            mService.mBatteryStatsService.noteProcessAnr(app.processName, app.uid);
+
+            if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
+                app.kill("bg anr", true);
+                return;
+            }
+
+            // Set the app's notResponding state, and look up the errorReportReceiver
+            makeAppNotRespondingLocked(app,
+                    activity != null ? activity.shortComponentName : null,
+                    annotation != null ? "ANR " + annotation : "ANR",
+                    info.toString());
+
+            // Bring up the infamous App Not Responding dialog
+            Message msg = Message.obtain();
+            HashMap<String, Object> map = new HashMap<String, Object>();
+            msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
+            msg.obj = map;
+            msg.arg1 = aboveSystem ? 1 : 0;
+            map.put("app", app);
+            if (activity != null) {
+                map.put("activity", activity);
+            }
+
+            mService.mUiHandler.sendMessage(msg);
+        }
+    }
+
+    private void makeAppNotRespondingLocked(ProcessRecord app,
+            String activity, String shortMsg, String longMsg) {
+        app.notResponding = true;
+        app.notRespondingReport = generateProcessError(app,
+                ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING,
+                activity, shortMsg, longMsg, null);
+        startAppProblemLocked(app);
+        app.stopFreezingAllLocked();
+    }
+
+    void handleShowAnrUi(Message msg) {
+        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);
+                return;
+            }
+
+            Intent intent = new Intent("android.intent.action.ANR");
+            if (!mService.mProcessesReady) {
+                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+                        | Intent.FLAG_RECEIVER_FOREGROUND);
+            }
+            mService.broadcastIntentLocked(null, null, intent,
+                    null, null, 0, null, null, null, AppOpsManager.OP_NONE,
+                    null, false, false, MY_PID, Process.SYSTEM_UID, 0 /* TODO: Verify */);
+
+            if (mService.canShowErrorDialogs()) {
+                Dialog d = new AppNotRespondingDialog(mService,
+                        mContext, proc, (ActivityRecord)data.get("activity"),
+                        msg.arg1 != 0);
+                d.show();
+                proc.anrDialog = d;
+            } else {
+                // Just kill the app if there is no dialog to be shown.
+                mService.killAppAtUsersRequest(proc, null);
+            }
+        }
+    }
+
+    /**
+     * Information about a process that is currently marked as bad.
+     */
+    static final class BadProcessInfo {
+        BadProcessInfo(long time, String shortMsg, String longMsg, String stack) {
+            this.time = time;
+            this.shortMsg = shortMsg;
+            this.longMsg = longMsg;
+            this.stack = stack;
+        }
+
+        final long time;
+        final String shortMsg;
+        final String longMsg;
+        final String stack;
+    }
+
+}
diff --git a/services/core/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
index f4c1664..4587b72 100644
--- a/services/core/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
@@ -117,7 +117,7 @@
                         ProcessRecord app = mProc;
 
                         if (msg.what == WAIT_AND_REPORT) {
-                            appErrorIntent = mService.createAppErrorIntentLocked(app,
+                            appErrorIntent = mService.mAppErrors.createAppErrorIntentLocked(app,
                                     System.currentTimeMillis(), null);
                         }
 
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index f64b803..97ef10b 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -40,6 +40,7 @@
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.telephony.DataConnectionRealTimeInfo;
+import android.telephony.ModemActivityInfo;
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyManager;
 import android.util.IntArray;
@@ -51,6 +52,7 @@
 import com.android.internal.os.BatteryStatsHelper;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.PowerProfile;
+import com.android.internal.telephony.ITelephony;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
 
@@ -855,6 +857,18 @@
         }
     }
 
+    @Override
+    public void noteBleScanStarted(WorkSource ws) {
+        enforceCallingPermission();
+        Slog.d(TAG, "BLE scan started for " + ws);
+    }
+
+    @Override
+    public void noteBleScanStopped(WorkSource ws) {
+        enforceCallingPermission();
+        Slog.d(TAG, "BLE scan stopped for " + ws);
+    }
+
     public boolean isOnBattery() {
         return mStats.isOnBattery();
     }
@@ -1114,7 +1128,7 @@
                 } else {
                     // Not an option, last argument must be a package name.
                     try {
-                        reqUid = mContext.getPackageManager().getPackageUid(arg,
+                        reqUid = mContext.getPackageManager().getPackageUidAsUser(arg,
                                 UserHandle.getCallingUserId());
                     } catch (PackageManager.NameNotFoundException e) {
                         pw.println("Unknown package: " + arg);
@@ -1317,6 +1331,24 @@
         return null;
     }
 
+    @GuardedBy("mExternalStatsLock")
+    private ModemActivityInfo pullModemActivityInfoLocked() {
+        ITelephony tm = ITelephony.Stub.asInterface(ServiceManager.getService(
+                Context.TELEPHONY_SERVICE));
+        try {
+            if (tm != null) {
+                ModemActivityInfo info = tm.getModemActivityInfo();
+                if (info == null || info.isValid()) {
+                    return info;
+                }
+                Slog.wtf(TAG, "Modem activity info is invalid: " + info);
+            }
+        } catch (RemoteException e) {
+            // Nothing to do.
+        }
+        return null;
+    }
+
     /**
      * Fetches data from external sources (WiFi controller, bluetooth chipset) and updates
      * batterystats with that information.
@@ -1346,6 +1378,11 @@
                 wifiEnergyInfo = pullWifiEnergyInfoLocked();
             }
 
+            ModemActivityInfo modemActivityInfo = null;
+            if ((updateFlags & UPDATE_RADIO) != 0) {
+                modemActivityInfo = pullModemActivityInfoLocked();
+            }
+
             BluetoothActivityEnergyInfo bluetoothEnergyInfo = null;
             if ((updateFlags & UPDATE_BT) != 0) {
                 // We only pull bluetooth stats when we have to, as we are not distributing its
@@ -1367,7 +1404,7 @@
                 }
 
                 if ((updateFlags & UPDATE_RADIO) != 0) {
-                    mStats.updateMobileRadioStateLocked(elapsedRealtime);
+                    mStats.updateMobileRadioStateLocked(elapsedRealtime, modemActivityInfo);
                 }
 
                 if ((updateFlags & UPDATE_WIFI) != 0) {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 622aa16..37b0af1 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -199,7 +199,7 @@
 
         @Override
         public void run() {
-            mService.appNotResponding(mApp, null, null, false, mAnnotation);
+            mService.mAppErrors.appNotResponding(mApp, null, null, false, mAnnotation);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index 0397553..f2e8d09 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -100,6 +100,6 @@
 30045 am_pre_boot (User|1|5),(Package|3)
 
 # Report collection of global memory state
-30046 am_meminfo (CachedKb|2|2),(FreeKb|2|2),(ZramKb|2|2),(KernelKb|2|2),(NativeKb|2|2)
+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),(PssKb|2|2),(UssKb|2|2)
+30047 am_pss (Pid|1|5),(UID|1|5),(Process Name|3),(Pss|2|2),(Uss|2|2),(SwapPss|2|2)
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 4bfe300..b4aa4cf 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -82,7 +82,9 @@
     long lastStateTime;         // Last time setProcState changed
     long initialIdlePss;        // Initial memory pss of process for idle maintenance.
     long lastPss;               // Last computed memory pss.
+    long lastSwapPss;           // Last computed SwapPss.
     long lastCachedPss;         // Last computed pss when in cached state.
+    long lastCachedSwapPss;     // Last computed SwapPss when in cached state.
     int maxAdj;                 // Maximum OOM adjustment for this process
     int curRawAdj;              // Current OOM unlimited adjustment for this process
     int setRawAdj;              // Last set OOM unlimited adjustment for this process
@@ -257,7 +259,9 @@
         pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
                 pw.print(" lruSeq="); pw.print(lruSeq);
                 pw.print(" lastPss="); DebugUtils.printSizeValue(pw, lastPss*1024);
+                pw.print(" lastSwapPss="); DebugUtils.printSizeValue(pw, lastSwapPss*1024);
                 pw.print(" lastCachedPss="); DebugUtils.printSizeValue(pw, lastCachedPss*1024);
+                pw.print(" lastCachedSwapPss="); DebugUtils.printSizeValue(pw, lastCachedSwapPss*1024);
                 pw.println();
         pw.print(prefix); pw.print("cached="); pw.print(cached);
                 pw.print(" empty="); pw.println(empty);
diff --git a/services/core/java/com/android/server/am/ProcessStartLogger.java b/services/core/java/com/android/server/am/ProcessStartLogger.java
new file mode 100644
index 0000000..d2aa966
--- /dev/null
+++ b/services/core/java/com/android/server/am/ProcessStartLogger.java
@@ -0,0 +1,151 @@
+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/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index c63eaac..9c139d5 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -16,9 +16,16 @@
 
 package com.android.server.am;
 
-import static com.android.server.am.ActivityManagerDebugConfig.*;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
+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.TaskRecord.INVALID_TASK_ID;
 
+import com.google.android.collect.Sets;
+
 import android.app.ActivityManager;
 import android.app.AppGlobals;
 import android.content.ComponentName;
@@ -27,14 +34,20 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.os.Environment;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Slog;
+import android.util.SparseBooleanArray;
 
+import java.io.File;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.Set;
 
 /**
  * Class for managing the recent tasks list.
@@ -47,18 +60,106 @@
     // Maximum number recent bitmaps to keep in memory.
     private static final int MAX_RECENT_BITMAPS = 3;
 
-    // Activity manager service.
-    private final ActivityManagerService mService;
+    /**
+     * Save recent tasks information across reboots.
+     */
+    private final TaskPersister mTaskPersister;
+    private final SparseBooleanArray mUsersWithRecentsLoaded = new SparseBooleanArray(5);
 
     // Mainly to avoid object recreation on multiple calls.
     private final ArrayList<TaskRecord> mTmpRecents = new ArrayList<TaskRecord>();
-    private final HashMap<ComponentName, ActivityInfo> tmpAvailActCache = new HashMap<>();
-    private final HashMap<String, ApplicationInfo> tmpAvailAppCache = new HashMap<>();
-    private final ActivityInfo tmpActivityInfo = new ActivityInfo();
-    private final ApplicationInfo tmpAppInfo = new ApplicationInfo();
+    private final HashMap<ComponentName, ActivityInfo> mTmpAvailActCache = new HashMap<>();
+    private final HashMap<String, ApplicationInfo> mTmpAvailAppCache = new HashMap<>();
+    private final ActivityInfo mTmpActivityInfo = new ActivityInfo();
+    private final ApplicationInfo mTmpAppInfo = new ApplicationInfo();
 
-    RecentTasks(ActivityManagerService service) {
-        mService = service;
+    RecentTasks(ActivityManagerService service, ActivityStackSupervisor mStackSupervisor) {
+        File systemDir = Environment.getDataSystemDirectory();
+        mTaskPersister = new TaskPersister(systemDir, mStackSupervisor, service, this);
+        mStackSupervisor.setRecentTasks(this);
+    }
+
+    /**
+     * Loads the persistent recentTasks for {@code userId} into this list from persistent storage.
+     * Does nothing if they are already loaded.
+     *
+     * @param userId the user Id
+     */
+    void loadUserRecentsLocked(int userId) {
+        if (!mUsersWithRecentsLoaded.get(userId)) {
+            Slog.i(TAG, "Loading recents for user " + userId + " into memory.");
+            addAll(mTaskPersister.restoreTasksForUserLocked(userId));
+            cleanupLocked(userId);
+            mUsersWithRecentsLoaded.put(userId, true);
+        }
+    }
+
+    void notifyTaskPersisterLocked(TaskRecord task, boolean flush) {
+        if (task != null && task.stack != null && task.stack.isHomeStack()) {
+            // Never persist the home stack.
+            return;
+        }
+        mTaskPersister.wakeup(task, flush);
+    }
+
+    void onSystemReady() {
+        clear();
+        loadUserRecentsLocked(UserHandle.USER_SYSTEM);
+        startPersisting();
+    }
+
+    void startPersisting() {
+        mTaskPersister.startPersisting();
+    }
+
+    Bitmap getTaskDescriptionIcon(String path) {
+        return mTaskPersister.getTaskDescriptionIcon(path);
+    }
+
+    Bitmap getImageFromWriteQueue(String path) {
+        return mTaskPersister.getImageFromWriteQueue(path);
+    }
+
+    void saveImage(Bitmap image, String path) {
+        mTaskPersister.saveImage(image, path);
+    }
+
+    void flush() {
+        mTaskPersister.flush();
+    }
+
+    /**
+     * Returns all userIds for which recents from storage are loaded
+     *
+     * @return an array of userIds.
+     */
+    int[] usersWithRecentsLoadedLocked() {
+        int[] usersWithRecentsLoaded = new int[mUsersWithRecentsLoaded.size()];
+        int len = 0;
+        for (int i = 0; i < usersWithRecentsLoaded.length; i++) {
+            int userId = mUsersWithRecentsLoaded.keyAt(i);
+            if (mUsersWithRecentsLoaded.valueAt(i)) {
+                usersWithRecentsLoaded[len++] = userId;
+            }
+        }
+        if (len < usersWithRecentsLoaded.length) {
+            // should never happen.
+            return Arrays.copyOf(usersWithRecentsLoaded, len);
+        }
+        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) {
+        if (mUsersWithRecentsLoaded.get(userId)) {
+            Slog.i(TAG, "Unloading recents for user " + userId + " from memory.");
+            mUsersWithRecentsLoaded.delete(userId);
+            removeTasksForUserLocked(userId);
+        }
     }
 
     TaskRecord taskForIdLocked(int id) {
@@ -88,9 +189,21 @@
                 tr.removedFromRecents();
             }
         }
+    }
 
-        // Remove tasks from persistent storage.
-        mService.notifyTaskPersisterLocked(null, true);
+    void onPackagesSuspendedChanged(String[] packages, boolean suspended, int userId) {
+        final Set<String> packageNames = Sets.newHashSet(packages);
+        for (int i = size() - 1; i >= 0; --i) {
+            final TaskRecord tr = get(i);
+            if (tr.realActivity != null
+                    && packageNames.contains(tr.realActivity.getPackageName())
+                    && tr.userId == userId
+                    && tr.realActivitySuspended != suspended) {
+               tr.realActivitySuspended = suspended;
+               notifyTaskPersisterLocked(tr, false);
+            }
+        }
+
     }
 
     /**
@@ -107,86 +220,86 @@
         }
 
         final IPackageManager pm = AppGlobals.getPackageManager();
-        final int[] users = (userId == UserHandle.USER_ALL)
-                ? mService.mUserController.getUsers() : new int[] { userId };
-        for (int userIdx = 0; userIdx < users.length; userIdx++) {
-            final int user = users[userIdx];
-            recentsCount = size() - 1;
-            for (int i = recentsCount; i >= 0; i--) {
-                TaskRecord task = get(i);
-                if (task.userId != user) {
-                    // Only look at tasks for the user ID of interest.
-                    continue;
-                }
-                if (task.autoRemoveRecents && task.getTopActivity() == null) {
-                    // This situation is broken, and we should just get rid of it now.
-                    remove(i);
-                    task.removedFromRecents();
-                    Slog.w(TAG, "Removing auto-remove without activity: " + task);
-                    continue;
-                }
-                // Check whether this activity is currently available.
-                if (task.realActivity != null) {
-                    ActivityInfo ai = tmpAvailActCache.get(task.realActivity);
+        for (int i = recentsCount - 1; i >= 0; i--) {
+            final TaskRecord task = get(i);
+            if (userId != UserHandle.USER_ALL && task.userId != userId) {
+                // Only look at tasks for the user ID of interest.
+                continue;
+            }
+            if (task.autoRemoveRecents && task.getTopActivity() == null) {
+                // This situation is broken, and we should just get rid of it now.
+                remove(i);
+                task.removedFromRecents();
+                Slog.w(TAG, "Removing auto-remove without activity: " + task);
+                continue;
+            }
+            // Check whether this activity is currently available.
+            if (task.realActivity != null) {
+                ActivityInfo ai = mTmpAvailActCache.get(task.realActivity);
+                if (ai == null) {
+                    try {
+                        // At this first cut, we're only interested in
+                        // activities that are fully runnable based on
+                        // current system state.
+                        ai = pm.getActivityInfo(task.realActivity,
+                                PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
+                    } catch (RemoteException e) {
+                        // Will never happen.
+                        continue;
+                    }
                     if (ai == null) {
+                        ai = mTmpActivityInfo;
+                    }
+                    mTmpAvailActCache.put(task.realActivity, ai);
+                }
+                if (ai == mTmpActivityInfo) {
+                    // This could be either because the activity no longer exists, or the
+                    // app is temporarily gone. For the former we want to remove the recents
+                    // entry; for the latter we want to mark it as unavailable.
+                    ApplicationInfo app = mTmpAvailAppCache
+                            .get(task.realActivity.getPackageName());
+                    if (app == null) {
                         try {
-                            ai = pm.getActivityInfo(task.realActivity,
-                                    PackageManager.GET_UNINSTALLED_PACKAGES
-                                            | PackageManager.GET_DISABLED_COMPONENTS, user);
+                            app = pm.getApplicationInfo(task.realActivity.getPackageName(),
+                                    PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
                         } catch (RemoteException e) {
                             // Will never happen.
                             continue;
                         }
-                        if (ai == null) {
-                            ai = tmpActivityInfo;
-                        }
-                        tmpAvailActCache.put(task.realActivity, ai);
-                    }
-                    if (ai == tmpActivityInfo) {
-                        // This could be either because the activity no longer exists, or the
-                        // app is temporarily gone.  For the former we want to remove the recents
-                        // entry; for the latter we want to mark it as unavailable.
-                        ApplicationInfo app = tmpAvailAppCache.get(task.realActivity.getPackageName());
                         if (app == null) {
-                            try {
-                                app = pm.getApplicationInfo(task.realActivity.getPackageName(),
-                                        PackageManager.GET_UNINSTALLED_PACKAGES
-                                                | PackageManager.GET_DISABLED_COMPONENTS, user);
-                            } catch (RemoteException e) {
-                                // Will never happen.
-                                continue;
-                            }
-                            if (app == null) {
-                                app = tmpAppInfo;
-                            }
-                            tmpAvailAppCache.put(task.realActivity.getPackageName(), app);
+                            app = mTmpAppInfo;
                         }
-                        if (app == tmpAppInfo || (app.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
-                            // Doesn't exist any more!  Good-bye.
-                            remove(i);
-                            task.removedFromRecents();
-                            Slog.w(TAG, "Removing no longer valid recent: " + task);
-                            continue;
-                        } else {
-                            // Otherwise just not available for now.
-                            if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG_RECENTS,
-                                    "Making recent unavailable: " + task);
-                            task.isAvailable = false;
-                        }
+                        mTmpAvailAppCache.put(task.realActivity.getPackageName(), app);
+                    }
+                    if (app == mTmpAppInfo
+                            || (app.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
+                        // Doesn't exist any more! Good-bye.
+                        remove(i);
+                        task.removedFromRecents();
+                        Slog.w(TAG, "Removing no longer valid recent: " + task);
+                        continue;
                     } else {
-                        if (!ai.enabled || !ai.applicationInfo.enabled
-                                || (ai.applicationInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
-                            if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG_RECENTS,
-                                    "Making recent unavailable: " + task
-                                    + " (enabled=" + ai.enabled + "/" + ai.applicationInfo.enabled
-                                    + " flags=" + Integer.toHexString(ai.applicationInfo.flags)
-                                    + ")");
-                            task.isAvailable = false;
-                        } else {
-                            if (DEBUG_RECENTS && !task.isAvailable) Slog.d(TAG_RECENTS,
-                                    "Making recent available: " + task);
-                            task.isAvailable = true;
-                        }
+                        // Otherwise just not available for now.
+                        if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG_RECENTS,
+                                "Making recent unavailable: " + task);
+                        task.isAvailable = false;
+                    }
+                } else {
+                    if (!ai.enabled || !ai.applicationInfo.enabled
+                            || (ai.applicationInfo.flags
+                                    & ApplicationInfo.FLAG_INSTALLED) == 0) {
+                        if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG_RECENTS,
+                                "Making recent unavailable: " + task
+                                        + " (enabled=" + ai.enabled + "/"
+                                        + ai.applicationInfo.enabled
+                                        + " flags="
+                                        + Integer.toHexString(ai.applicationInfo.flags)
+                                        + ")");
+                        task.isAvailable = false;
+                    } else {
+                        if (DEBUG_RECENTS && !task.isAvailable) Slog.d(TAG_RECENTS,
+                                "Making recent available: " + task);
+                        task.isAvailable = true;
                     }
                 }
             }
@@ -310,6 +423,8 @@
 
         int recentsCount = size();
         // Quick case: never add voice sessions.
+        // TODO: VI what about if it's just an activity?
+        // Probably nothing to do here
         if (task.voiceSession != null) {
             if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
                     "addRecent: not adding voice interaction " + task);
@@ -340,7 +455,7 @@
                     // Simple case: this is not an affiliated task, so we just move it to the front.
                     remove(taskIndex);
                     add(0, task);
-                    mService.notifyTaskPersisterLocked(task, false);
+                    notifyTaskPersisterLocked(task, false);
                     if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving to top " + task
                             + " from " + taskIndex);
                     return;
@@ -500,7 +615,7 @@
                 // specified, then replace it with the existing recent task.
                 task = tr;
             }
-            mService.notifyTaskPersisterLocked(tr, false);
+            notifyTaskPersisterLocked(tr, false);
         }
 
         return -1;
@@ -550,7 +665,7 @@
         if (first.mNextAffiliate != null) {
             Slog.w(TAG, "Link error 1 first.next=" + first.mNextAffiliate);
             first.setNextAffiliate(null);
-            mService.notifyTaskPersisterLocked(first, false);
+            notifyTaskPersisterLocked(first, false);
         }
         // Everything in the middle is doubly linked from next to prev.
         final int tmpSize = mTmpRecents.size();
@@ -561,13 +676,13 @@
                 Slog.w(TAG, "Link error 2 next=" + next + " prev=" + next.mPrevAffiliate +
                         " setting prev=" + prev);
                 next.setPrevAffiliate(prev);
-                mService.notifyTaskPersisterLocked(next, false);
+                notifyTaskPersisterLocked(next, false);
             }
             if (prev.mNextAffiliate != next) {
                 Slog.w(TAG, "Link error 3 prev=" + prev + " next=" + prev.mNextAffiliate +
                         " setting next=" + next);
                 prev.setNextAffiliate(next);
-                mService.notifyTaskPersisterLocked(prev, false);
+                notifyTaskPersisterLocked(prev, false);
             }
             prev.inRecents = true;
         }
@@ -576,7 +691,7 @@
         if (last.mPrevAffiliate != null) {
             Slog.w(TAG, "Link error 4 last.prev=" + last.mPrevAffiliate);
             last.setPrevAffiliate(null);
-            mService.notifyTaskPersisterLocked(last, false);
+            notifyTaskPersisterLocked(last, false);
         }
 
         // Insert the group back into mRecentTasks at start.
@@ -586,5 +701,4 @@
         // Let the caller know where we left off.
         return start + tmpSize;
     }
-
 }
diff --git a/services/core/java/com/android/server/am/ResizeDockedStackTimeout.java b/services/core/java/com/android/server/am/ResizeDockedStackTimeout.java
new file mode 100644
index 0000000..ff39589
--- /dev/null
+++ b/services/core/java/com/android/server/am/ResizeDockedStackTimeout.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.graphics.Rect;
+import android.os.Handler;
+
+import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
+
+/**
+ * When resizing the docked stack, a caller can temporarily supply task bounds that are different
+ * from the stack bounds. In order to return to a sane state if the caller crashes or has a bug,
+ * this class manages this cycle.
+ */
+class ResizeDockedStackTimeout {
+
+    private static final long TIMEOUT_MS = 10 * 1000;
+    private final ActivityManagerService mService;
+    private final ActivityStackSupervisor mSupervisor;
+    private final Handler mHandler;
+    private final Rect mCurrentDockedBounds = new Rect();
+
+    private final Runnable mTimeoutRunnable = new Runnable() {
+        @Override
+        public void run() {
+            synchronized (mService) {
+                mSupervisor.resizeDockedStackLocked(mCurrentDockedBounds, null, null, null, null,
+                        PRESERVE_WINDOWS);
+            }
+        }
+    };
+
+    ResizeDockedStackTimeout(ActivityManagerService service, ActivityStackSupervisor supervisor,
+            Handler handler) {
+        mService = service;
+        mSupervisor = supervisor;
+        mHandler = handler;
+    }
+
+    void notifyResizing(Rect dockedBounds, boolean hasTempBounds) {
+        mHandler.removeCallbacks(mTimeoutRunnable);
+        if (!hasTempBounds) {
+            return;
+        }
+        mCurrentDockedBounds.set(dockedBounds);
+        mHandler.postDelayed(mTimeoutRunnable, TIMEOUT_MS);
+    }
+
+}
diff --git a/services/core/java/com/android/server/am/StrictModeViolationDialog.java b/services/core/java/com/android/server/am/StrictModeViolationDialog.java
index fda1ec1..6da84bd 100644
--- a/services/core/java/com/android/server/am/StrictModeViolationDialog.java
+++ b/services/core/java/com/android/server/am/StrictModeViolationDialog.java
@@ -73,7 +73,6 @@
                       mHandler.obtainMessage(ACTION_OK_AND_REPORT));
         }
 
-        setTitle(res.getText(com.android.internal.R.string.aerr_title));
         getWindow().addPrivateFlags(PRIVATE_FLAG_SYSTEM_ERROR);
         getWindow().setTitle("Strict Mode Violation: " + app.info.processName);
 
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 9a00075..283939e 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -21,16 +21,18 @@
 import android.os.Debug;
 import android.os.Environment;
 import android.os.FileUtils;
+import android.os.Process;
 import android.os.SystemClock;
 import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.Slog;
 import android.util.Xml;
-import android.os.Process;
 
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
 
+import libcore.io.IoUtils;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -42,12 +44,10 @@
 import java.io.IOException;
 import java.io.StringWriter;
 import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 
-import libcore.io.IoUtils;
-
 public class TaskPersister {
     static final String TAG = "TaskPersister";
     static final boolean DEBUG = false;
@@ -113,7 +113,7 @@
     ArrayList<WriteQueueItem> mWriteQueue = new ArrayList<WriteQueueItem>();
 
     TaskPersister(File systemDir, ActivityStackSupervisor stackSupervisor,
-            RecentTasks recentTasks) {
+            ActivityManagerService service, RecentTasks recentTasks) {
 
         final File legacyImagesDir = new File(systemDir, IMAGES_DIRNAME);
         if (legacyImagesDir.exists()) {
@@ -130,7 +130,7 @@
         }
 
         mStackSupervisor = stackSupervisor;
-        mService = stackSupervisor.mService;
+        mService = service;
         mRecentTasks = recentTasks;
         mLazyTaskWriterThread = new LazyTaskWriterThread("LazyTaskWriterThread");
     }
@@ -145,11 +145,15 @@
         final String taskString = Integer.toString(task.taskId);
         for (int queueNdx = mWriteQueue.size() - 1; queueNdx >= 0; --queueNdx) {
             final WriteQueueItem item = mWriteQueue.get(queueNdx);
-            if (item instanceof ImageWriteQueueItem &&
-                    ((ImageWriteQueueItem) item).mFilePath.startsWith(taskString)) {
-                if (DEBUG) Slog.d(TAG, "Removing " + ((ImageWriteQueueItem) item).mFilePath +
-                        " from write queue");
-                mWriteQueue.remove(queueNdx);
+            if (item instanceof ImageWriteQueueItem) {
+                final File thumbnailFile = new File(((ImageWriteQueueItem) item).mFilePath);
+                if (thumbnailFile.getName().startsWith(taskString)) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "Removing " + ((ImageWriteQueueItem) item).mFilePath +
+                                " from write queue");
+                    }
+                    mWriteQueue.remove(queueNdx);
+                }
             }
         }
     }
@@ -185,7 +189,8 @@
                     mWriteQueue.add(new TaskWriteQueueItem(task));
                 }
             } else {
-                // Dummy.
+                // Dummy. Ensures removeObsoleteFiles is called when LazyTaskThreadWriter is
+                // notified.
                 mWriteQueue.add(new WriteQueueItem());
             }
             if (flush || mWriteQueue.size() > MAX_WRITE_QUEUE_LENGTH) {
@@ -323,8 +328,8 @@
         return null;
     }
 
-    private List<TaskRecord> restoreTasksForUserLocked(final int userId) {
-        final List<TaskRecord> tasks = new ArrayList<TaskRecord>();
+    List<TaskRecord> restoreTasksForUserLocked(final int userId) {
+        final ArrayList<TaskRecord> tasks = new ArrayList<TaskRecord>();
         ArraySet<Integer> recoveredTaskIds = new ArraySet<Integer>();
 
         File userTasksDir = getUserTasksDir(userId);
@@ -351,10 +356,10 @@
                         event != XmlPullParser.END_TAG) {
                     final String name = in.getName();
                     if (event == XmlPullParser.START_TAG) {
-                        if (DEBUG) Slog.d(TAG, "restoreTasksLocked: START_TAG name=" + name);
+                        if (DEBUG) Slog.d(TAG, "restoreTasksForUserLocked: START_TAG name=" + name);
                         if (TAG_TASK.equals(name)) {
                             final TaskRecord task = TaskRecord.restoreFromXml(in, mStackSupervisor);
-                            if (DEBUG) Slog.d(TAG, "restoreTasksLocked: restored task="
+                            if (DEBUG) Slog.d(TAG, "restoreTasksForUserLocked: restored task="
                                     + task);
                             if (task != null) {
                                 // XXX Don't add to write queue... there is no reason to write
@@ -362,7 +367,7 @@
                                 // read the same thing again.
                                 // mWriteQueue.add(new TaskWriteQueueItem(task));
                                 final int taskId = task.taskId;
-                                mStackSupervisor.setNextTaskId(taskId);
+                                mStackSupervisor.setNextTaskIdForUserLocked(taskId, userId);
                                 // Check if it's a valid user id. Don't add tasks for removed users.
                                 if (userId == task.userId) {
                                     task.isPersistable = true;
@@ -396,15 +401,6 @@
         if (!DEBUG) {
             removeObsoleteFiles(recoveredTaskIds, userTasksDir.listFiles());
         }
-        return tasks;
-    }
-
-    ArrayList<TaskRecord> restoreTasksLocked(final int[] validUserIds) {
-        final ArrayList<TaskRecord> tasks = new ArrayList<TaskRecord>();
-
-        for (int userId : validUserIds) {
-            tasks.addAll(restoreTasksForUserLocked(userId));
-        }
 
         // Fix up task affiliation from taskIds
         for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
@@ -413,9 +409,7 @@
             task.setNextAffiliate(taskIdToTask(task.mNextAffiliateTaskId, tasks));
         }
 
-        TaskRecord[] tasksArray = new TaskRecord[tasks.size()];
-        tasks.toArray(tasksArray);
-        Arrays.sort(tasksArray, new Comparator<TaskRecord>() {
+        Collections.sort(tasks, new Comparator<TaskRecord>() {
             @Override
             public int compare(TaskRecord lhs, TaskRecord rhs) {
                 final long diff = rhs.mLastTimeMoved - lhs.mLastTimeMoved;
@@ -428,8 +422,7 @@
                 }
             }
         });
-
-        return new ArrayList<TaskRecord>(Arrays.asList(tasksArray));
+        return tasks;
     }
 
     private static void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds, File[] files) {
@@ -462,7 +455,13 @@
     }
 
     private void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds) {
-        for (int userId : mService.getRunningUserIds()) {
+        int[] candidateUserIds;
+        synchronized (mService) {
+            // Remove only from directories of the users who have recents in memory synchronized
+            // with persistent storage.
+            candidateUserIds = mRecentTasks.usersWithRecentsLoadedLocked();
+        }
+        for (int userId : candidateUserIds) {
             removeObsoleteFiles(persistentTaskIds, getUserImagesDir(userId).listFiles());
             removeObsoleteFiles(persistentTaskIds, getUserTasksDir(userId).listFiles());
         }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 5ee9eea..c9d4595 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+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;
@@ -23,6 +24,8 @@
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
 import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
@@ -93,6 +96,7 @@
     private static final String TAG_INTENT = "intent";
     private static final String TAG_AFFINITYINTENT = "affinity_intent";
     static final String ATTR_REALACTIVITY = "real_activity";
+    static final String ATTR_REALACTIVITY_SUSPENDED = "real_activity_suspended";
     private static final String ATTR_ORIGACTIVITY = "orig_activity";
     private static final String TAG_ACTIVITY = "activity";
     private static final String ATTR_AFFINITY = "affinity";
@@ -134,6 +138,8 @@
     int effectiveUid;       // The current effective uid of the identity of this task.
     ComponentName origActivity; // The non-alias activity component of the intent.
     ComponentName realActivity; // The actual activity component that started the task.
+    boolean realActivitySuspended; // True if the actual activity component that started the
+                                   // task is suspended.
     long firstActiveTime;   // First time this task was active.
     long lastActiveTime;    // Last time this task was active, including sleep.
     boolean inRecents;      // Actually in the recents list?
@@ -204,7 +210,7 @@
 
     // Used in the unique case where we are clearing the task in order to reuse it. In that case we
     // do not want to delete the stack when the task goes empty.
-    boolean mReuseTask = false;
+    private boolean mReuseTask = false;
 
     private Bitmap mLastThumbnail; // Last thumbnail captured for this item.
     private final File mLastThumbnailFile; // File containing last thumbnail.
@@ -303,7 +309,7 @@
             boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription,
             TaskThumbnailInfo lastThumbnailInfo, int taskAffiliation, int prevTaskId,
             int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
-            boolean resizeable, boolean privileged) {
+            boolean resizeable, boolean privileged, boolean realActivitySuspended) {
         mService = service;
         mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
                 TaskPersister.IMAGE_EXTENSION;
@@ -317,6 +323,7 @@
         voiceSession = null;
         voiceInteractor = null;
         realActivity = _realActivity;
+        realActivitySuspended = realActivitySuspended;
         origActivity = _origActivity;
         rootWasReset = _rootWasReset;
         isAvailable = true;
@@ -441,7 +448,9 @@
         } else {
             autoRemoveRecents = false;
         }
-        mResizeable = info.resizeable || mService.mForceResizableActivities;
+        mResizeable = info.resizeMode == RESIZE_MODE_RESIZEABLE
+                || info.resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE
+                || mService.mForceResizableActivities;
         mLockTaskMode = info.lockTaskLaunchMode;
         mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0;
         setLockTaskAuth();
@@ -550,7 +559,7 @@
                     mLastThumbnailFile.delete();
                 }
             } else {
-                mService.mTaskPersister.saveImage(thumbnail, mLastThumbnailFile.getAbsolutePath());
+                mService.mRecentTasks.saveImage(thumbnail, mLastThumbnailFile.getAbsolutePath());
             }
             return true;
         }
@@ -562,7 +571,7 @@
         thumbs.thumbnailInfo = mLastThumbnailInfo;
         thumbs.thumbnailFileDescriptor = null;
         if (mLastThumbnail == null) {
-            thumbs.mainThumbnail = mService.mTaskPersister.getImageFromWriteQueue(
+            thumbs.mainThumbnail = mService.mRecentTasks.getImageFromWriteQueue(
                     mLastThumbnailFile.getAbsolutePath());
         }
         // Only load the thumbnail file if we don't have a thumbnail
@@ -697,7 +706,7 @@
         if (mActivities.isEmpty()) {
             taskType = r.mActivityType;
             if (taskType == HOME_ACTIVITY_TYPE && mService.mForceResizableActivities) {
-                mResizeable = r.info.resizeable;
+                mResizeable = r.isResizeable();
             }
             isPersistable = r.isPersistable();
             mCallingUid = r.launchedFromUid;
@@ -773,6 +782,13 @@
         mReuseTask = false;
     }
 
+    ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) {
+        mReuseTask = true;
+        final ActivityRecord result = performClearTaskLocked(newR, launchFlags);
+        mReuseTask = false;
+        return result;
+    }
+
     /**
      * Perform clear operation as requested by
      * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
@@ -1018,6 +1034,7 @@
         if (realActivity != null) {
             out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
         }
+        out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended));
         if (origActivity != null) {
             out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
         }
@@ -1096,6 +1113,7 @@
         Intent affinityIntent = null;
         ArrayList<ActivityRecord> activities = new ArrayList<>();
         ComponentName realActivity = null;
+        boolean realActivitySuspended = false;
         ComponentName origActivity = null;
         String affinity = null;
         String rootAffinity = null;
@@ -1134,6 +1152,8 @@
                 if (taskId == INVALID_TASK_ID) taskId = Integer.valueOf(attrValue);
             } else if (ATTR_REALACTIVITY.equals(attrName)) {
                 realActivity = ComponentName.unflattenFromString(attrValue);
+            } else if (ATTR_REALACTIVITY_SUSPENDED.equals(attrName)) {
+                realActivitySuspended = Boolean.valueOf(attrValue);
             } else if (ATTR_ORIGACTIVITY.equals(attrName)) {
                 origActivity = ComponentName.unflattenFromString(attrValue);
             } else if (ATTR_AFFINITY.equals(attrName)) {
@@ -1244,7 +1264,8 @@
                 autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription,
                 activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
                 taskDescription, thumbnailInfo, taskAffiliation, prevTaskId, nextTaskId,
-                taskAffiliationColor, callingUid, callingPackage, resizeable, privileged);
+                taskAffiliationColor, callingUid, callingPackage, resizeable, privileged,
+                realActivitySuspended);
         task.updateOverrideConfiguration(bounds);
 
         for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
@@ -1282,21 +1303,7 @@
             if (stack == null || StackId.persistTaskBounds(stack.mStackId)) {
                 mLastNonFullscreenBounds = mBounds;
             }
-
-            final Configuration serviceConfig = mService.mConfiguration;
-            mOverrideConfig = new Configuration(Configuration.EMPTY);
-            // TODO(multidisplay): Update Dp to that of display stack is on.
-            final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
-            mOverrideConfig.screenWidthDp =
-                    Math.min((int)(mBounds.width() / density), serviceConfig.screenWidthDp);
-            mOverrideConfig.screenHeightDp =
-                    Math.min((int)(mBounds.height() / density), serviceConfig.screenHeightDp);
-            mOverrideConfig.smallestScreenWidthDp =
-                    Math.min(mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp);
-            mOverrideConfig.orientation =
-                    (mOverrideConfig.screenWidthDp <= mOverrideConfig.screenHeightDp)
-                            ? Configuration.ORIENTATION_PORTRAIT
-                            : Configuration.ORIENTATION_LANDSCAPE;
+            mOverrideConfig = calculateOverrideConfig(mBounds);
         }
 
         if (mFullscreen != oldFullscreen) {
@@ -1306,6 +1313,55 @@
         return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null;
     }
 
+    Configuration calculateOverrideConfig(Rect bounds) {
+        final Configuration serviceConfig = mService.mConfiguration;
+        final Configuration config = new Configuration(Configuration.EMPTY);
+        // TODO(multidisplay): Update Dp to that of display stack is on.
+        final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+        config.screenWidthDp =
+                Math.min((int)(bounds.width() / density), serviceConfig.screenWidthDp);
+        config.screenHeightDp =
+                Math.min((int)(bounds.height() / density), serviceConfig.screenHeightDp);
+        config.smallestScreenWidthDp =
+                Math.min(config.screenWidthDp, config.screenHeightDp);
+        config.orientation = (config.screenWidthDp <= config.screenHeightDp)
+                ? Configuration.ORIENTATION_PORTRAIT
+                : Configuration.ORIENTATION_LANDSCAPE;
+        final int sl = Configuration.resetScreenLayout(serviceConfig.screenLayout);
+        config.screenLayout = Configuration.reduceScreenLayout(
+                sl, config.screenWidthDp, config.screenHeightDp);
+        return config;
+    }
+
+    /**
+     * Using the existing configuration {@param config}, creates a new task override config such
+     * that all the fields that are usually set in an override config are set to the ones in
+     * {@param config}.
+     */
+    Configuration extractOverrideConfig(Configuration config) {
+        final Configuration extracted = new Configuration(Configuration.EMPTY);
+        extracted.screenWidthDp = config.screenWidthDp;
+        extracted.screenHeightDp = config.screenHeightDp;
+        extracted.smallestScreenWidthDp = config.smallestScreenWidthDp;
+        extracted.orientation = config.orientation;
+        extracted.screenLayout = config.screenLayout;
+        return extracted;
+    }
+
+    Rect updateOverrideConfigurationFromLaunchBounds() {
+        final Rect bounds = validateBounds(getLaunchBounds());
+        updateOverrideConfiguration(bounds);
+        return bounds;
+    }
+
+    static Rect validateBounds(Rect bounds) {
+        if (bounds != null && bounds.isEmpty()) {
+            Slog.wtf(TAG, "Received strange task bounds: " + bounds, new Throwable());
+            return null;
+        }
+        return bounds;
+    }
+
     private void reportMultiWindowModeChange() {
         for (int i = mActivities.size() - 1; i >= 0; i--) {
             final ActivityRecord r = mActivities.get(i);
@@ -1321,7 +1377,12 @@
         }
     }
 
-    void reportPictureInPictureModeChange() {
+    void reportPictureInPictureModeChangeIfNeeded(ActivityStack prevStack) {
+        if (prevStack == null || prevStack == stack
+                || (prevStack.mStackId != PINNED_STACK_ID && stack.mStackId != PINNED_STACK_ID)) {
+            return;
+        }
+
         for (int i = mActivities.size() - 1; i >= 0; i--) {
             final ActivityRecord r = mActivities.get(i);
             if (r.app != null && r.app.thread != null) {
@@ -1377,23 +1438,32 @@
 
     /** Returns the bounds that should be used to launch this task. */
     Rect getLaunchBounds() {
-        final int stackId = stack.mStackId;
-
         // If we're over lockscreen, forget about stack bounds and use fullscreen.
         if (mService.mLockScreenShown == LOCK_SCREEN_SHOWN) {
             return null;
         }
 
-        if (stack == null
-                || stackId == HOME_STACK_ID
-                || stackId == FULLSCREEN_WORKSPACE_STACK_ID) {
-            return (mResizeable && stack != null) ? stack.mBounds : null;
+        if (stack == null) {
+            return null;
+        }
+
+        final int stackId = stack.mStackId;
+        if (stackId == HOME_STACK_ID
+                || stackId == FULLSCREEN_WORKSPACE_STACK_ID
+                || (stackId == DOCKED_STACK_ID && !mResizeable)) {
+            return mResizeable ? stack.mBounds : null;
         } else if (!StackId.persistTaskBounds(stackId)) {
             return stack.mBounds;
         }
         return mLastNonFullscreenBounds;
     }
 
+    boolean canMatchRootAffinity() {
+        // We don't allow root affinity matching on the pinned stack as no other task should
+        // be launching in it based on affinity.
+        return rootAffinity != null && (stack == null || stack.mStackId != PINNED_STACK_ID);
+    }
+
     void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("userId="); pw.print(userId);
                 pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 62e78a4..a21570ce 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -22,6 +22,7 @@
 import static android.app.ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
 import static android.app.ActivityManager.USER_OP_IS_CURRENT;
 import static android.app.ActivityManager.USER_OP_SUCCESS;
+import static android.content.Context.KEYGUARD_SERVICE;
 import static android.os.Process.SYSTEM_UID;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
@@ -43,6 +44,7 @@
 import android.app.Dialog;
 import android.app.IStopUserCallback;
 import android.app.IUserSwitchObserver;
+import android.app.KeyguardManager;
 import android.content.Context;
 import android.content.IIntentReceiver;
 import android.content.Intent;
@@ -73,6 +75,7 @@
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.widget.LockPatternUtils;
 import com.android.server.pm.UserManagerService;
 
 import java.io.PrintWriter;
@@ -140,6 +143,8 @@
 
     private volatile UserManagerService mUserManager;
 
+    private final LockPatternUtils mLockPatternUtils;
+
     UserController(ActivityManagerService service) {
         mService = service;
         mHandler = mService.mHandler;
@@ -147,6 +152,7 @@
         final UserState uss = new UserState(UserHandle.SYSTEM);
         mStartedUsers.put(UserHandle.USER_SYSTEM, uss);
         mUserLru.add(UserHandle.USER_SYSTEM);
+        mLockPatternUtils = new LockPatternUtils(mService.mContext);
         updateStartedUserArrayLocked();
     }
 
@@ -215,7 +221,8 @@
 
                 Intent intent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED, null);
                 intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
-                intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
+                intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
+                        | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
                 mService.broadcastIntentLocked(null, null, intent, null, resultTo, 0, null, null,
                         new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED },
                         AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
@@ -242,9 +249,13 @@
             if (uss.state == UserState.STATE_RUNNING_LOCKED) {
                 uss.setState(UserState.STATE_RUNNING);
 
+                // Give user manager a chance to prepare app storage
+                mUserManager.onBeforeUnlockUser(userId);
+
                 mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0));
 
                 final Intent unlockedIntent = new Intent(Intent.ACTION_USER_UNLOCKED);
+                unlockedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
                 unlockedIntent.addFlags(
                         Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
                 mService.broadcastIntentLocked(null, null, unlockedIntent, null, null, 0, null,
@@ -302,7 +313,10 @@
                         + relatedUserId);
                 // We still need to stop the requested user if it's a force stop.
                 if (force) {
+                    Slog.i(TAG,
+                            "Force stop user " + userId + ". Related users will not be stopped");
                     stopSingleUserLocked(userId, callback);
+                    return USER_OP_SUCCESS;
                 }
                 return USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
             }
@@ -411,6 +425,7 @@
                 mUserLru.remove(Integer.valueOf(userId));
                 updateStartedUserArrayLocked();
 
+                mService.onUserStoppedLocked(userId);
                 // Clean up all state and processes associated with the user.
                 // Kill all the processes for the user.
                 forceStopUserLocked(userId, "finish user");
@@ -430,6 +445,10 @@
             synchronized (mService) {
                 mService.mStackSupervisor.removeUserLocked(userId);
             }
+            // Remove the user if it is ephemeral.
+            if (getUserInfo(userId).isEphemeral()) {
+                mUserManager.removeUser(userId);
+            }
         }
     }
 
@@ -476,9 +495,9 @@
     }
 
     /**
-     * Stops the guest user if it has gone to the background.
+     * Stops the guest or ephemeral user if it has gone to the background.
      */
-    private void stopGuestUserIfBackground() {
+    private void stopGuestOrEphemeralUserIfBackground() {
         synchronized (mService) {
             final int num = mUserLru.size();
             for (int i = 0; i < num; i++) {
@@ -490,7 +509,7 @@
                     continue;
                 }
                 UserInfo userInfo = getUserInfo(oldUserId);
-                if (userInfo.isGuest()) {
+                if (userInfo.isGuest() || userInfo.isEphemeral()) {
                     // This is a user to be stopped.
                     stopUsersLocked(oldUserId, true, null);
                     break;
@@ -506,7 +525,7 @@
         List<UserInfo> profilesToStart = new ArrayList<>(profiles.size());
         for (UserInfo user : profiles) {
             if ((user.flags & UserInfo.FLAG_INITIALIZED) == UserInfo.FLAG_INITIALIZED
-                    && user.id != mCurrentUserId) {
+                    && user.id != mCurrentUserId && !user.isQuietModeEnabled()) {
                 profilesToStart.add(user);
             }
         }
@@ -636,7 +655,8 @@
                 }
 
                 if (uss.state == UserState.STATE_BOOTING) {
-                    // Let user manager propagate user restrictions to other services.
+                    // Give user manager a chance to propagate user restrictions
+                    // to other services and prepare app storage
                     getUserManager().onBeforeStartUser(userId);
 
                     // Booting up a new user, need to tell system services about it.
@@ -916,7 +936,7 @@
             mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG,
                     newUserId, 0));
         }
-        stopGuestUserIfBackground();
+        stopGuestOrEphemeralUserIfBackground();
         stopBackgroundUsersIfEnforced(oldUserId);
     }
 
@@ -925,7 +945,7 @@
         if (homeInFront) {
             mService.startHomeActivityLocked(newUserId, "moveUserToForeground");
         } else {
-            mService.mStackSupervisor.resumeTopActivitiesLocked();
+            mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
         }
         EventLogTags.writeAmSwitchUser(newUserId);
         getUserManager().onUserForeground(newUserId);
@@ -1109,8 +1129,7 @@
             UserState uss = mStartedUsers.valueAt(i);
             if (uss.state != UserState.STATE_STOPPING
                     && uss.state != UserState.STATE_SHUTDOWN) {
-                mStartedUserArray[num] = mStartedUsers.keyAt(i);
-                num++;
+                mStartedUserArray[num++] = mStartedUsers.keyAt(i);
             }
         }
     }
@@ -1220,7 +1239,7 @@
     }
 
     private boolean isCurrentUserLocked(int userId) {
-        return mCurrentUserId == userId || mTargetUserId == userId;
+        return userId == getCurrentOrTargetUserIdLocked();
     }
 
     int setTargetUserIdLocked(int targetUserId) {
@@ -1277,6 +1296,19 @@
         return mCurrentProfileIds;
     }
 
+    /**
+     * Returns whether the given user requires credential entry at this time. This is used to
+     * intercept activity launches for work apps when the Work Challenge is present.
+     */
+    boolean shouldConfirmCredentials(int userId) {
+        if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
+            return false;
+        }
+        final KeyguardManager km = (KeyguardManager) mService.mContext
+                .getSystemService(KEYGUARD_SERVICE);
+        return km.isDeviceLocked(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/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 40d01e7..64c0891 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -58,10 +58,12 @@
 import android.media.AudioManager;
 import android.media.AudioManagerInternal;
 import android.media.AudioPort;
+import android.media.AudioRecordConfiguration;
 import android.media.AudioRoutesInfo;
 import android.media.IAudioFocusDispatcher;
 import android.media.IAudioRoutesObserver;
 import android.media.IAudioService;
+import android.media.IRecordingConfigDispatcher;
 import android.media.IRingtonePlayer;
 import android.media.IVolumeController;
 import android.media.MediaPlayer;
@@ -220,6 +222,7 @@
     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, ...)
@@ -686,6 +689,7 @@
         intentFilter.addAction(Intent.ACTION_USER_BACKGROUND);
         intentFilter.addAction(Intent.ACTION_USER_FOREGROUND);
         intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+        intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
 
         intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
         // TODO merge orientation and rotation
@@ -705,6 +709,8 @@
         LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
 
         mUserManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
+
+        mRecordMonitor.initMonitor();
     }
 
     public void systemReady() {
@@ -820,6 +826,12 @@
             streamState.applyAllVolumes();
         }
 
+        // Restore mono mode
+        final boolean masterMono = System.getIntForUser(
+                mContentResolver, System.MASTER_MONO,
+                0 /* default */, UserHandle.USER_CURRENT) == 1;
+        AudioSystem.setMasterMono(masterMono);
+
         // Restore ringer mode
         setRingerModeInt(getRingerModeInternal(), false);
 
@@ -1079,6 +1091,14 @@
         }
         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);
+
         // Each stream will read its own persisted settings
 
         // Broadcast the sticky intents
@@ -1835,6 +1855,52 @@
                 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);
@@ -3099,57 +3165,18 @@
             }
         }
         public void onServiceDisconnected(int profile) {
-            ArraySet<String> toRemove = null;
+
             switch (profile) {
             case BluetoothProfile.A2DP:
-                synchronized (mConnectedDevices) {
-                    synchronized (mA2dpAvrcpLock) {
-                        // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
-                        for (int i = 0; i < mConnectedDevices.size(); i++) {
-                            DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
-                            if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
-                                toRemove = toRemove != null ? toRemove : new ArraySet<String>();
-                                toRemove.add(deviceSpec.mDeviceAddress);
-                            }
-                        }
-                        if (toRemove != null) {
-                            int delay = checkSendBecomingNoisyIntent(
-                                                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                                                0);
-                            for (int i = 0; i < toRemove.size(); i++) {
-                                makeA2dpDeviceUnavailableLater(toRemove.valueAt(i), delay);
-                            }
-                        }
-                    }
-                }
+                disconnectA2dp();
                 break;
 
             case BluetoothProfile.A2DP_SINK:
-                synchronized (mConnectedDevices) {
-                    // Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices
-                    for(int i = 0; i < mConnectedDevices.size(); i++) {
-                        DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
-                        if (deviceSpec.mDeviceType == AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) {
-                            toRemove = toRemove != null ? toRemove : new ArraySet<String>();
-                            toRemove.add(deviceSpec.mDeviceAddress);
-                        }
-                    }
-                    if (toRemove != null) {
-                        for (int i = 0; i < toRemove.size(); i++) {
-                            makeA2dpSrcUnavailable(toRemove.valueAt(i));
-                        }
-                    }
-                }
+                disconnectA2dpSink();
                 break;
 
             case BluetoothProfile.HEADSET:
-                synchronized (mScoClients) {
-                    if (mBluetoothHeadsetDevice != null) {
-                        setBtScoDeviceConnectionState(mBluetoothHeadsetDevice,
-                                BluetoothProfile.STATE_DISCONNECTED);
-                    }
-                    mBluetoothHeadset = null;
-                }
+                disconnectHeadset();
                 break;
 
             default:
@@ -3158,6 +3185,65 @@
         }
     };
 
+    void disconnectAllBluetoothProfiles() {
+        disconnectA2dp();
+        disconnectA2dpSink();
+        disconnectHeadset();
+    }
+
+    void disconnectA2dp() {
+        synchronized (mConnectedDevices) {
+            synchronized (mA2dpAvrcpLock) {
+                ArraySet<String> toRemove = null;
+                // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
+                for (int i = 0; i < mConnectedDevices.size(); i++) {
+                    DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
+                    if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
+                        toRemove = toRemove != null ? toRemove : new ArraySet<String>();
+                        toRemove.add(deviceSpec.mDeviceAddress);
+                    }
+                }
+                if (toRemove != null) {
+                    int delay = checkSendBecomingNoisyIntent(
+                                        AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+                                        0);
+                    for (int i = 0; i < toRemove.size(); i++) {
+                        makeA2dpDeviceUnavailableLater(toRemove.valueAt(i), delay);
+                    }
+                }
+            }
+        }
+    }
+
+    void disconnectA2dpSink() {
+        synchronized (mConnectedDevices) {
+            ArraySet<String> toRemove = null;
+            // Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices
+            for(int i = 0; i < mConnectedDevices.size(); i++) {
+                DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
+                if (deviceSpec.mDeviceType == AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) {
+                    toRemove = toRemove != null ? toRemove : new ArraySet<String>();
+                    toRemove.add(deviceSpec.mDeviceAddress);
+                }
+            }
+            if (toRemove != null) {
+                for (int i = 0; i < toRemove.size(); i++) {
+                    makeA2dpSrcUnavailable(toRemove.valueAt(i));
+                }
+            }
+        }
+    }
+
+    void disconnectHeadset() {
+        synchronized (mScoClients) {
+            if (mBluetoothHeadsetDevice != null) {
+                setBtScoDeviceConnectionState(mBluetoothHeadsetDevice,
+                        BluetoothProfile.STATE_DISCONNECTED);
+            }
+            mBluetoothHeadset = null;
+        }
+    }
+
     private void onCheckMusicActive(String caller) {
         synchronized (mSafeMediaVolumeState) {
             if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
@@ -4534,6 +4620,13 @@
                 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;
             }
         }
     }
@@ -5156,6 +5249,12 @@
                 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
                 UserManagerService.getInstance().setUserRestriction(
                         UserManager.DISALLOW_RECORD_AUDIO, false, userId);
+            } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
+                state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
+                if (state == BluetoothAdapter.STATE_OFF ||
+                        state == BluetoothAdapter.STATE_TURNING_OFF) {
+                    disconnectAllBluetoothProfiles();
+                }
             }
         }
     } // end class AudioServiceBroadcastReceiver
@@ -6097,7 +6196,7 @@
     }
 
     //======================
-    // Audio policy callback from AudioSystem
+    // Audio policy callbacks from AudioSystem for dynamic policies
     //======================
     private final AudioSystem.DynamicPolicyCallback mDynPolicyCallback =
             new AudioSystem.DynamicPolicyCallback() {
@@ -6126,7 +6225,23 @@
                 }
             }
         }
+    }
 
+    //======================
+    // Audio policy callbacks from AudioSystem for recording configuration updates
+    //======================
+    private final RecordingActivityMonitor mRecordMonitor = new RecordingActivityMonitor();
+
+    public void registerRecordingCallback(IRecordingConfigDispatcher rcdb) {
+        mRecordMonitor.registerRecordingCallback(rcdb);
+    }
+
+    public void unregisterRecordingCallback(IRecordingConfigDispatcher rcdb) {
+        mRecordMonitor.unregisterRecordingCallback(rcdb);
+    }
+
+    public AudioRecordConfiguration[] getActiveRecordConfigurations() {
+        return mRecordMonitor.getActiveRecordConfigurations();
     }
 
     //======================
@@ -6229,4 +6344,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
new file mode 100644
index 0000000..5806f3f
--- /dev/null
+++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.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.server.audio;
+
+import android.media.AudioManager;
+import android.media.AudioRecordConfiguration;
+import android.media.AudioSystem;
+import android.media.IRecordingConfigDispatcher;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * Class to receive and dispatch updates from AudioSystem about recording configurations.
+ */
+public final class RecordingActivityMonitor implements AudioSystem.AudioRecordingCallback {
+
+    public final static String TAG = "AudioService.RecordingActivityMonitor";
+
+    private ArrayList<RecMonitorClient> mClients = new ArrayList<RecMonitorClient>();
+
+    private HashMap<Integer, AudioRecordConfiguration> mRecordConfigs =
+            new HashMap<Integer, AudioRecordConfiguration>();
+
+    RecordingActivityMonitor() {
+        RecMonitorClient.sMonitor = this;
+    }
+
+    /**
+     * Implementation of android.media.AudioSystem.AudioRecordingCallback
+     */
+    public void onRecordingConfigurationChanged(int event, int session, int source) {
+        if (updateSnapshot(event, session, source)) {
+            final Iterator<RecMonitorClient> clientIterator = mClients.iterator();
+            synchronized(mClients) {
+                while (clientIterator.hasNext()) {
+                    try {
+                        clientIterator.next().mDispatcherCb.dispatchRecordingConfigChange();
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Could not call dispatchRecordingConfigChange() on client", e);
+                    }
+                }
+            }
+        }
+    }
+
+    void initMonitor() {
+        AudioSystem.setRecordingCallback(this);
+    }
+
+    void registerRecordingCallback(IRecordingConfigDispatcher rcdb) {
+        if (rcdb == null) {
+            return;
+        }
+        synchronized(mClients) {
+            final RecMonitorClient rmc = new RecMonitorClient(rcdb);
+            if (rmc.init()) {
+                mClients.add(rmc);
+            }
+        }
+    }
+
+    void unregisterRecordingCallback(IRecordingConfigDispatcher rcdb) {
+        if (rcdb == null) {
+            return;
+        }
+        synchronized(mClients) {
+            final Iterator<RecMonitorClient> clientIterator = mClients.iterator();
+            while (clientIterator.hasNext()) {
+                RecMonitorClient rmc = clientIterator.next();
+                if (rcdb.equals(rmc.mDispatcherCb)) {
+                    rmc.release();
+                    clientIterator.remove();
+                    break;
+                }
+            }
+        }
+    }
+
+    AudioRecordConfiguration[] getActiveRecordConfigurations() {
+        synchronized(mRecordConfigs) {
+            return mRecordConfigs.values().toArray(new AudioRecordConfiguration[0]);
+        }
+    }
+
+    /**
+     * Update the internal "view" of the active recording sessions
+     * @param event
+     * @param session
+     * @param source
+     * @return true if the list of active recording sessions has been modified, false otherwise.
+     */
+    private boolean updateSnapshot(int event, int session, int source) {
+        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);
+            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;
+                } else {
+                    mRecordConfigs.put(new Integer(session),
+                            new AudioRecordConfiguration(session, source));
+                    return true;
+                }
+            default:
+                Log.e(TAG, String.format("Unknown event %d for session %d, source %d",
+                        event, session, source));
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Inner class to track clients that want to be notified of recording updates
+     */
+    private final static class RecMonitorClient implements IBinder.DeathRecipient {
+
+        // can afford to be static because only one RecordingActivityMonitor ever instantiated
+        static RecordingActivityMonitor sMonitor;
+
+        final IRecordingConfigDispatcher mDispatcherCb;
+
+        RecMonitorClient(IRecordingConfigDispatcher rcdb) {
+            mDispatcherCb = rcdb;
+        }
+
+        public void binderDied() {
+            Log.w(TAG, "client died");
+            sMonitor.unregisterRecordingCallback(mDispatcherCb);
+        }
+
+        boolean init() {
+            try {
+                mDispatcherCb.asBinder().linkToDeath(this, 0);
+                return true;
+            } catch (RemoteException e) {
+                Log.w(TAG, "Could not link to client death", e);
+                return false;
+            }
+        }
+
+        void release() {
+            mDispatcherCb.asBinder().unlinkToDeath(this, 0);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 0029279..c5d38cb 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -248,10 +248,10 @@
     }
 
     public String toString() {
-        return "NetworkAgentInfo{ ni{" + networkInfo + "}  network{" +
-                network + "}  lp{" +
-                linkProperties + "}  nc{" +
-                networkCapabilities + "}  Score{" + getCurrentScore() + "}  " +
+        return "NetworkAgentInfo{ ni{" + networkInfo + "}  " +
+                "network{" + network + "}  nethandle{" + network.getNetworkHandle() + "}  " +
+                "lp{" + linkProperties + "}  " +
+                "nc{" + networkCapabilities + "}  Score{" + getCurrentScore() + "}  " +
                 "everValidated{" + everValidated + "}  lastValidated{" + lastValidated + "}  " +
                 "created{" + created + "} lingering{" + lingering + "} " +
                 "explicitlySelected{" + networkMisc.explicitlySelected + "} " +
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 3a10dbe..4504bdb 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -223,7 +223,6 @@
     private final AlarmManager mAlarmManager;
     private final NetworkRequest mDefaultRequest;
 
-    private String mServer;
     private boolean mIsCaptivePortalCheckEnabled = false;
 
     // Set if the user explicitly selected "Do not use this network" in captive portal sign-in app.
@@ -265,10 +264,6 @@
         addState(mLingeringState, mDefaultState);
         setInitialState(mDefaultState);
 
-        mServer = Settings.Global.getString(mContext.getContentResolver(),
-                Settings.Global.CAPTIVE_PORTAL_SERVER);
-        if (mServer == null) mServer = DEFAULT_SERVER;
-
         mLingerDelayMs = SystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS);
 
         mIsCaptivePortalCheckEnabled = Settings.Global.getInt(mContext.getContentResolver(),
@@ -622,6 +617,13 @@
         }
     }
 
+    public static String getCaptivePortalServerUrl(Context context) {
+        String server = Settings.Global.getString(context.getContentResolver(),
+                Settings.Global.CAPTIVE_PORTAL_SERVER);
+        if (server == null) server = DEFAULT_SERVER;
+        return "http://" + server + "/generate_204";
+    }
+
     /**
      * Do a URL fetch on a known server to see if we get the data we expect.
      * Returns HTTP response code.
@@ -633,9 +635,9 @@
         HttpURLConnection urlConnection = null;
         int httpResponseCode = 599;
         try {
-            URL url = new URL("http", mServer, "/generate_204");
+            URL url = new URL(getCaptivePortalServerUrl(mContext));
             // On networks with a PAC instead of fetching a URL that should result in a 204
-            // reponse, we instead simply fetch the PAC script.  This is done for a few reasons:
+            // response, we instead simply fetch the PAC script.  This is done for a few reasons:
             // 1. At present our PAC code does not yet handle multiple PACs on multiple networks
             //    until something like https://android-review.googlesource.com/#/c/115180/ lands.
             //    Network.openConnection() will ignore network-specific PACs and instead fetch
@@ -644,7 +646,8 @@
             // 2. To proxy the generate_204 fetch through a PAC would require a number of things
             //    happen before the fetch can commence, namely:
             //        a) the PAC script be fetched
-            //        b) a PAC script resolver service be fired up and resolve mServer
+            //        b) a PAC script resolver service be fired up and resolve the captive portal
+            //           server.
             //    Network validation could be delayed until these prerequisities are satisifed or
             //    could simply be left to race them.  Neither is an optimal solution.
             // 3. PAC scripts are sometimes used to block or restrict Internet access and may in
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 3b43633..a73a67a 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -19,6 +19,10 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothPan;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothProfile.ServiceListener;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -38,20 +42,25 @@
 import android.net.NetworkRequest;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
+import android.net.wifi.WifiManager;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.INetworkManagementService;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Parcel;
+import android.os.ResultReceiver;
+import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.provider.Settings;
+import android.telephony.CarrierConfigManager;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
 import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.IState;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
 import com.android.server.IoThread;
@@ -59,8 +68,8 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.net.InetAddress;
 import java.net.Inet4Address;
+import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -109,6 +118,10 @@
 
     private BroadcastReceiver mStateReceiver;
 
+    // {@link ComponentName} of the Service used to run tether provisioning.
+    private static final ComponentName TETHER_SERVICE = ComponentName.unflattenFromString(Resources
+            .getSystem().getString(com.android.internal.R.string.config_wifi_tether_enable));
+
     private static final String USB_NEAR_IFACE_ADDR      = "192.168.42.129";
     private static final int USB_PREFIX_LENGTH        = 24;
 
@@ -140,11 +153,10 @@
                                          // when RNDIS is enabled
 
     public Tethering(Context context, INetworkManagementService nmService,
-            INetworkStatsService statsService, Looper looper) {
+            INetworkStatsService statsService) {
         mContext = context;
         mNMService = nmService;
         mStatsService = statsService;
-        mLooper = looper;
 
         mPublicSync = new Object();
 
@@ -332,6 +344,218 @@
         }
     }
 
+    public void startTethering(int type, ResultReceiver receiver,
+            boolean showProvisioningUi) {
+        if (!isTetherProvisioningRequired()) {
+            enableTetheringInternal(type, true, receiver);
+            return;
+        }
+
+        if (showProvisioningUi) {
+            runUiTetherProvisioningAndEnable(type, receiver);
+        } else {
+            runSilentTetherProvisioningAndEnable(type, receiver);
+        }
+    }
+
+    public void stopTethering(int type) {
+        enableTetheringInternal(type, false, null);
+        if (isTetherProvisioningRequired()) {
+            cancelTetherProvisioningRechecks(type);
+        }
+    }
+
+    /**
+     * Check if the device requires a provisioning check in order to enable tethering.
+     *
+     * @return a boolean - {@code true} indicating tether provisioning is required by the carrier.
+     */
+    private boolean isTetherProvisioningRequired() {
+        String[] provisionApp = mContext.getResources().getStringArray(
+                com.android.internal.R.array.config_mobile_hotspot_provision_app);
+        if (SystemProperties.getBoolean("net.tethering.noprovisioning", false)
+                || provisionApp == null) {
+            return false;
+        }
+
+        // Check carrier config for entitlement checks
+        final CarrierConfigManager configManager = (CarrierConfigManager) mContext
+             .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        boolean isEntitlementCheckRequired = configManager.getConfig().getBoolean(
+             CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
+
+        if (!isEntitlementCheckRequired) {
+            return false;
+        }
+        return (provisionApp.length == 2);
+    }
+
+    /**
+     * Enables or disables tethering for the given type. This should only be called once
+     * provisioning has succeeded or is not necessary. It will also schedule provisioning rechecks
+     * for the specified interface.
+     */
+    private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) {
+        boolean isProvisioningRequired = isTetherProvisioningRequired();
+        switch (type) {
+            case ConnectivityManager.TETHERING_WIFI:
+                final WifiManager wifiManager =
+                        (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+                if (wifiManager.setWifiApEnabled(null, enable)) {
+                    sendTetherResult(receiver, ConnectivityManager.TETHER_ERROR_NO_ERROR);
+                    if (enable && isProvisioningRequired) {
+                        scheduleProvisioningRechecks(type);
+                    }
+                } else{
+                    sendTetherResult(receiver, ConnectivityManager.TETHER_ERROR_MASTER_ERROR);
+                }
+                break;
+            case ConnectivityManager.TETHERING_USB:
+                int result = setUsbTethering(enable);
+                if (enable && isProvisioningRequired &&
+                        result == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+                    scheduleProvisioningRechecks(type);
+                }
+                sendTetherResult(receiver, result);
+                break;
+            case ConnectivityManager.TETHERING_BLUETOOTH:
+                setBluetoothTethering(enable, receiver);
+                break;
+            default:
+                Log.w(TAG, "Invalid tether type.");
+                sendTetherResult(receiver, ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE);
+        }
+    }
+
+    private void sendTetherResult(ResultReceiver receiver, int result) {
+        if (receiver != null) {
+            receiver.send(result, null);
+        }
+    }
+
+    private void setBluetoothTethering(final boolean enable, final ResultReceiver receiver) {
+        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (adapter == null || !adapter.isEnabled()) {
+            Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: " +
+                    (adapter == null));
+            sendTetherResult(receiver, ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL);
+            return;
+        }
+
+        adapter.getProfileProxy(mContext, new ServiceListener() {
+            @Override
+            public void onServiceDisconnected(int profile) { }
+
+            @Override
+            public void onServiceConnected(int profile, BluetoothProfile proxy) {
+                ((BluetoothPan) proxy).setBluetoothTethering(enable);
+                // TODO: Enabling bluetooth tethering can fail asynchronously here.
+                // We should figure out a way to bubble up that failure instead of sending success.
+                int result = ((BluetoothPan) proxy).isTetheringOn() ?
+                        ConnectivityManager.TETHER_ERROR_NO_ERROR :
+                        ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
+                sendTetherResult(receiver, result);
+                if (enable && isTetherProvisioningRequired()) {
+                    scheduleProvisioningRechecks(ConnectivityManager.TETHERING_BLUETOOTH);
+                }
+                adapter.closeProfileProxy(BluetoothProfile.PAN, proxy);
+            }
+        }, BluetoothProfile.PAN);
+    }
+
+    private void runUiTetherProvisioningAndEnable(int type, ResultReceiver receiver) {
+        ResultReceiver proxyReceiver = getProxyReceiver(type, receiver);
+        sendUiTetherProvisionIntent(type, proxyReceiver);
+    }
+
+    private void sendUiTetherProvisionIntent(int type, ResultReceiver receiver) {
+        Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING);
+        intent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, type);
+        intent.putExtra(ConnectivityManager.EXTRA_PROVISION_CALLBACK, receiver);
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    /**
+     * Creates a proxy {@link ResultReceiver} which enables tethering if the provsioning result is
+     * successful before firing back up to the wrapped receiver.
+     *
+     * @param type The type of tethering being enabled.
+     * @param receiver A ResultReceiver which will be called back with an int resultCode.
+     * @return The proxy receiver.
+     */
+    private ResultReceiver getProxyReceiver(final int type, final ResultReceiver receiver) {
+        ResultReceiver rr = new ResultReceiver(null) {
+            @Override
+            protected void onReceiveResult(int resultCode, Bundle resultData) {
+                // If provisioning is successful, enable tethering, otherwise just send the error.
+                if (resultCode == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+                    enableTetheringInternal(type, true, receiver);
+                } else {
+                    sendTetherResult(receiver, resultCode);
+                }
+            }
+        };
+
+        // The following is necessary to avoid unmarshalling issues when sending the receiver
+        // across proccesses.
+        Parcel parcel = Parcel.obtain();
+        rr.writeToParcel(parcel,0);
+        parcel.setDataPosition(0);
+        ResultReceiver receiverForSending = ResultReceiver.CREATOR.createFromParcel(parcel);
+        parcel.recycle();
+        return receiverForSending;
+    }
+
+    private void scheduleProvisioningRechecks(int type) {
+        Intent intent = new Intent();
+        intent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, type);
+        intent.putExtra(ConnectivityManager.EXTRA_SET_ALARM, true);
+        intent.setComponent(TETHER_SERVICE);
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mContext.startServiceAsUser(intent, UserHandle.CURRENT);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    private void runSilentTetherProvisioningAndEnable(int type, ResultReceiver receiver) {
+        ResultReceiver proxyReceiver = getProxyReceiver(type, receiver);
+        sendSilentTetherProvisionIntent(type, proxyReceiver);
+    }
+
+    private void sendSilentTetherProvisionIntent(int type, ResultReceiver receiver) {
+        Intent intent = new Intent();
+        intent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, type);
+        intent.putExtra(ConnectivityManager.EXTRA_RUN_PROVISION, true);
+        intent.putExtra(ConnectivityManager.EXTRA_PROVISION_CALLBACK, receiver);
+        intent.setComponent(TETHER_SERVICE);
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mContext.startServiceAsUser(intent, UserHandle.CURRENT);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    private void cancelTetherProvisioningRechecks(int type) {
+        if (getConnectivityManager().isTetheringSupported()) {
+            Intent intent = new Intent();
+            intent.putExtra(ConnectivityManager.EXTRA_REM_TETHER_TYPE, type);
+            intent.setComponent(TETHER_SERVICE);
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mContext.startServiceAsUser(intent, UserHandle.CURRENT);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
     public int tether(String iface) {
         if (DBG) Log.d(TAG, "Tethering " + iface);
         TetherInterfaceSM sm = null;
@@ -615,13 +839,23 @@
         synchronized (mPublicSync) {
             if (enable) {
                 if (mRndisEnabled) {
-                    tetherUsb(true);
+                    final long ident = Binder.clearCallingIdentity();
+                    try {
+                        tetherUsb(true);
+                    } finally {
+                        Binder.restoreCallingIdentity(ident);
+                    }
                 } else {
                     mUsbTetherRequested = true;
                     usbManager.setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS);
                 }
             } else {
-                tetherUsb(false);
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    tetherUsb(false);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
                 if (mRndisEnabled) {
                     usbManager.setCurrentFunction(null);
                 }
@@ -1407,15 +1641,6 @@
         private final AtomicInteger mSimBcastGenerationNumber = new AtomicInteger(0);
         private SimChangeBroadcastReceiver mBroadcastReceiver = null;
 
-        // keep consts in sync with packages/apps/Settings TetherSettings.java
-        private static final int WIFI_TETHERING      = 0;
-        private static final int USB_TETHERING       = 1;
-        private static final int BLUETOOTH_TETHERING = 2;
-
-        // keep consts in sync with packages/apps/Settings TetherService.java
-        private static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
-        private static final String EXTRA_RUN_PROVISION = "extraRunProvision";
-
         private void startListeningForSimChanges() {
             if (DBG) Log.d(TAG, "startListeningForSimChanges");
             if (mBroadcastReceiver == null) {
@@ -1472,8 +1697,6 @@
                     try {
                         if (mContext.getResources().getString(com.android.internal.R.string.
                                 config_mobile_hotspot_provision_app_no_ui).isEmpty() == false) {
-                            final String tetherService = mContext.getResources().getString(
-                                    com.android.internal.R.string.config_wifi_tether_enable);
                             ArrayList<Integer> tethered = new ArrayList<Integer>();
                             synchronized (mPublicSync) {
                                 Set ifaces = mIfaces.keySet();
@@ -1481,21 +1704,25 @@
                                     TetherInterfaceSM sm = mIfaces.get(iface);
                                     if (sm != null && sm.isTethered()) {
                                         if (isUsb((String)iface)) {
-                                            tethered.add(new Integer(USB_TETHERING));
+                                            tethered.add(new Integer(
+                                                    ConnectivityManager.TETHERING_USB));
                                         } else if (isWifi((String)iface)) {
-                                            tethered.add(new Integer(WIFI_TETHERING));
+                                            tethered.add(new Integer(
+                                                    ConnectivityManager.TETHERING_WIFI));
                                         } else if (isBluetooth((String)iface)) {
-                                            tethered.add(new Integer(BLUETOOTH_TETHERING));
+                                            tethered.add(new Integer(
+                                                    ConnectivityManager.TETHERING_BLUETOOTH));
                                         }
                                     }
                                 }
                             }
                             for (int tetherType : tethered) {
                                 Intent startProvIntent = new Intent();
-                                startProvIntent.putExtra(EXTRA_ADD_TETHER_TYPE, tetherType);
-                                startProvIntent.putExtra(EXTRA_RUN_PROVISION, true);
-                                startProvIntent.setComponent(
-                                        ComponentName.unflattenFromString(tetherService));
+                                startProvIntent.putExtra(
+                                        ConnectivityManager.EXTRA_ADD_TETHER_TYPE, tetherType);
+                                startProvIntent.putExtra(
+                                        ConnectivityManager.EXTRA_RUN_PROVISION, true);
+                                startProvIntent.setComponent(TETHER_SERVICE);
                                 mContext.startServiceAsUser(startProvIntent, UserHandle.CURRENT);
                             }
                             Log.d(TAG, "re-evaluate provisioning");
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 2bea278..fd9abff 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -63,6 +63,7 @@
 import android.os.SystemService;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.security.Credentials;
 import android.security.KeyStore;
 import android.text.TextUtils;
@@ -169,6 +170,58 @@
     }
 
     /**
+     * Configures an always-on VPN connection through a specific application.
+     * This connection is automatically granted and persisted after a reboot.
+     *
+     * <p>The designated package should exist and declare a {@link VpnService} in its
+     *    manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE},
+     *    otherwise the call will fail.
+     *
+     * @param newPackage the package to designate as always-on VPN supplier.
+     */
+    public synchronized boolean setAlwaysOnPackage(String packageName) {
+        enforceControlPermissionOrInternalCaller();
+
+        // Disconnect current VPN.
+        prepareInternal(VpnConfig.LEGACY_VPN);
+
+        // Pre-authorize new always-on VPN package.
+        if (packageName != null) {
+            if (!setPackageAuthorization(packageName, true)) {
+                return false;
+            }
+        }
+
+        // Save the new package name in Settings.Secure.
+        final long token = Binder.clearCallingIdentity();
+        try {
+            Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                    Settings.Secure.ALWAYS_ON_VPN_APP, packageName, mUserHandle);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+        return true;
+    }
+
+    /**
+     * @return the package name of the VPN controller responsible for always-on VPN,
+     *         or {@code null} if none is set or always-on VPN is controlled through
+     *         lockdown instead.
+     * @hide
+     */
+    public synchronized String getAlwaysOnPackage() {
+        enforceControlPermissionOrInternalCaller();
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            return Settings.Secure.getStringForUser(mContext.getContentResolver(),
+                    Settings.Secure.ALWAYS_ON_VPN_APP, mUserHandle);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    /**
      * Prepare for a VPN application. This method is designed to solve
      * race conditions. It first compares the current prepared package
      * with {@code oldPackage}. If they are the same, the prepared
@@ -270,14 +323,14 @@
     /**
      * Set whether a package has the ability to launch VPNs without user intervention.
      */
-    public void setPackageAuthorization(String packageName, boolean authorized) {
+    public boolean setPackageAuthorization(String packageName, boolean authorized) {
         // Check if the caller is authorized.
-        enforceControlPermission();
+        enforceControlPermissionOrInternalCaller();
 
         int uid = getAppUid(packageName, mUserHandle);
         if (uid == -1 || VpnConfig.LEGACY_VPN.equals(packageName)) {
             // Authorization for nonexistent packages (or fake ones) can't be updated.
-            return;
+            return false;
         }
 
         long token = Binder.clearCallingIdentity();
@@ -286,11 +339,13 @@
                     (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
             appOps.setMode(AppOpsManager.OP_ACTIVATE_VPN, uid, packageName,
                     authorized ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
+            return true;
         } catch (Exception e) {
             Log.wtf(TAG, "Failed to set app ops for package " + packageName + ", uid " + uid, e);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
+        return false;
     }
 
     private boolean isVpnUserPreConsented(String packageName) {
@@ -309,7 +364,7 @@
         PackageManager pm = mContext.getPackageManager();
         int result;
         try {
-            result = pm.getPackageUid(app, userHandle);
+            result = pm.getPackageUidAsUser(app, userHandle);
         } catch (NameNotFoundException e) {
             result = -1;
         }
@@ -743,6 +798,13 @@
         mContext.enforceCallingPermission(Manifest.permission.CONTROL_VPN, "Unauthorized Caller");
     }
 
+    private void enforceControlPermissionOrInternalCaller() {
+        // Require caller to be either an application with CONTROL_VPN permission or a process
+        // in the system server.
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONTROL_VPN,
+                "Unauthorized Caller");
+    }
+
     private class Connection implements ServiceConnection {
         private IBinder mService;
 
@@ -882,9 +944,6 @@
      */
     public void startLegacyVpnPrivileged(VpnProfile profile, KeyStore keyStore,
             LinkProperties egress) {
-        if (!keyStore.isUnlocked()) {
-            throw new IllegalStateException("KeyStore isn't unlocked");
-        }
         UserManager mgr = UserManager.get(mContext);
         UserInfo user = mgr.getUserInfo(mUserHandle);
         if (user.isRestricted() || mgr.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN,
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 75a74c0..f72b1c3 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -815,9 +815,13 @@
         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
                 "no permission to read the sync stats");
 
+        final boolean canAccessAccounts =
+            mContext.checkCallingOrSelfPermission(Manifest.permission.GET_ACCOUNTS)
+                == PackageManager.PERMISSION_GRANTED;
         long identityToken = clearCallingIdentity();
         try {
-            return getSyncManager().getSyncStorageEngine().getCurrentSyncsCopy(userId);
+            return getSyncManager().getSyncStorageEngine()
+                .getCurrentSyncsCopy(userId, canAccessAccounts);
         } finally {
             restoreCallingIdentity(identityToken);
         }
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 78618ce..2eb9095 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -2682,6 +2682,31 @@
                         }
                         continue;
                     }
+                    String packageName = getPackageName(op.target);
+                    ApplicationInfo ai = null;
+                    if (packageName != null) {
+                        try {
+                            ai = mContext.getPackageManager().getApplicationInfo(packageName,
+                                    PackageManager.GET_UNINSTALLED_PACKAGES
+                                            | PackageManager.GET_DISABLED_COMPONENTS);
+                        } catch (NameNotFoundException e) {
+                            operationIterator.remove();
+                            mSyncStorageEngine.deleteFromPending(op.pendingOperation);
+                            continue;
+                        }
+                    }
+                    // If app is considered idle, then skip for now and backoff
+                    if (ai != null
+                            && mAppIdleMonitor.isAppIdle(packageName, ai.uid, op.target.userId)) {
+                        increaseBackoffSetting(op);
+                        op.appIdle = true;
+                        if (isLoggable) {
+                            Log.v(TAG, "Sync backing off idle app " + packageName);
+                        }
+                        continue;
+                    } else {
+                        op.appIdle = false;
+                    }
                     if (!isOperationValidLocked(op)) {
                         operationIterator.remove();
                         mSyncStorageEngine.deleteFromPending(op.pendingOperation);
@@ -2700,28 +2725,6 @@
                         }
                         continue;
                     }
-                    String packageName = getPackageName(op.target);
-                    ApplicationInfo ai = null;
-                    if (packageName != null) {
-                        try {
-                            ai = mContext.getPackageManager().getApplicationInfo(packageName,
-                                    PackageManager.GET_UNINSTALLED_PACKAGES
-                                    | PackageManager.GET_DISABLED_COMPONENTS);
-                        } catch (NameNotFoundException e) {
-                        }
-                    }
-                    // If app is considered idle, then skip for now and backoff
-                    if (ai != null
-                            && mAppIdleMonitor.isAppIdle(packageName, ai.uid, op.target.userId)) {
-                        increaseBackoffSetting(op);
-                        op.appIdle = true;
-                        if (isLoggable) {
-                            Log.v(TAG, "Sync backing off idle app " + packageName);
-                        }
-                        continue;
-                    } else {
-                        op.appIdle = false;
-                    }
                     // Add this sync to be run.
                     operations.add(op);
                 }
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 8266c08..c13518b 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -1469,15 +1469,23 @@
     }
 
     /**
-     * @return a copy of the current syncs data structure. Will not return
-     * null.
+     * @param userId Id of user to return current sync info.
+     * @param canAccessAccounts Determines whether to redact Account information from the result.
+     * @return a copy of the current syncs data structure. Will not return null.
      */
-    public List<SyncInfo> getCurrentSyncsCopy(int userId) {
+    public List<SyncInfo> getCurrentSyncsCopy(int userId, boolean canAccessAccounts) {
         synchronized (mAuthorities) {
             final List<SyncInfo> syncs = getCurrentSyncsLocked(userId);
             final List<SyncInfo> syncsCopy = new ArrayList<SyncInfo>();
             for (SyncInfo sync : syncs) {
-                syncsCopy.add(new SyncInfo(sync));
+                SyncInfo copy;
+                if (!canAccessAccounts) {
+                    copy = SyncInfo.createAccountRedacted(
+                        sync.authorityId, sync.authority, sync.startTime);
+                } else {
+                    copy = new SyncInfo(sync);
+                }
+                syncsCopy.add(copy);
             }
             return syncsCopy;
         }
@@ -1903,8 +1911,10 @@
                             if ("authority".equals(tagName)) {
                                 authority = parseAuthority(parser, version);
                                 periodicSync = null;
-                                if (authority.ident > highestAuthorityId) {
-                                    highestAuthorityId = authority.ident;
+                                if (authority != null) {
+                                    if (authority.ident > highestAuthorityId) {
+                                        highestAuthorityId = authority.ident;
+                                    }
                                 }
                             } else if (XML_TAG_LISTEN_FOR_TICKLES.equals(tagName)) {
                                 parseListenForTickles(parser);
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 835ba17..a16fcd2 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -587,16 +587,16 @@
                     Slog.e(TAG, "Unable to create surface.", ex);
                     return false;
                 }
+
+                mSurfaceControl.setLayerStack(mDisplayLayerStack);
+                mSurfaceControl.setSize(mDisplayWidth, mDisplayHeight);
+                mSurface = new Surface();
+                mSurface.copyFrom(mSurfaceControl);
+
+                mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal,
+                        mDisplayId, mSurfaceControl);
+                mSurfaceLayout.onDisplayTransaction();
             }
-
-            mSurfaceControl.setLayerStack(mDisplayLayerStack);
-            mSurfaceControl.setSize(mDisplayWidth, mDisplayHeight);
-            mSurface = new Surface();
-            mSurface.copyFrom(mSurfaceControl);
-
-            mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal,
-                    mDisplayId, mSurfaceControl);
-            mSurfaceLayout.onDisplayTransaction();
         } finally {
             SurfaceControl.closeTransaction();
         }
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 433d887..b74b0f2 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -673,6 +673,9 @@
                 slowChange = false;
             }
             mAppliedDimming = true;
+        } else if (mAppliedDimming) {
+            slowChange = false;
+            mAppliedDimming = false;
         }
 
         // If low power mode is enabled, cut the brightness level by half
@@ -685,6 +688,9 @@
                 slowChange = false;
             }
             mAppliedLowPower = true;
+        } else if (mAppliedLowPower) {
+            slowChange = false;
+            mAppliedLowPower = false;
         }
 
         // Animate the screen brightness when the screen is on or dozing.
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index 206cc8a..a633996 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -17,6 +17,7 @@
 package com.android.server.dreams;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 
 import android.content.ComponentName;
 import android.content.Context;
@@ -131,7 +132,7 @@
 
             mDreamStartTime = SystemClock.elapsedRealtime();
             MetricsLogger.visible(mContext,
-                    mCurrentDream.mCanDoze ? MetricsLogger.DOZING : MetricsLogger.DREAMING);
+                    mCurrentDream.mCanDoze ? MetricsEvent.DOZING : MetricsEvent.DREAMING);
 
             try {
                 mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_DREAM);
@@ -196,7 +197,7 @@
                     + ", isTest=" + oldDream.mIsTest + ", canDoze=" + oldDream.mCanDoze
                     + ", userId=" + oldDream.mUserId);
             MetricsLogger.hidden(mContext,
-                    oldDream.mCanDoze ? MetricsLogger.DOZING : MetricsLogger.DREAMING);
+                    oldDream.mCanDoze ? MetricsEvent.DOZING : MetricsEvent.DREAMING);
             MetricsLogger.histogram(mContext,
                     oldDream.mCanDoze ? "dozing_minutes" : "dreaming_minutes" ,
                     (int) ((SystemClock.elapsedRealtime() - mDreamStartTime) / (1000L * 60L)));
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 7ac3c4b..13e7648 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -19,6 +19,7 @@
 import android.Manifest;
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningAppProcessInfo;
+import android.app.trust.TrustManager;
 import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
 import android.app.AppOpsManager;
@@ -47,6 +48,7 @@
 import android.util.Slog;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.server.SystemService;
 
 import org.json.JSONArray;
@@ -103,6 +105,7 @@
     private static final int MAX_FAILED_ATTEMPTS = 5;
     private static final int FINGERPRINT_ACQUIRED_GOOD = 0;
     private final String mKeyguardPackage;
+    private int mCurrentUserId = UserHandle.USER_CURRENT;
 
     Handler mHandler = new Handler() {
         @Override
@@ -125,6 +128,7 @@
     private IFingerprintDaemon mDaemon;
     private final PowerManager mPowerManager;
     private final AlarmManager mAlarmManager;
+    private final UserManager mUserManager;
 
     private final BroadcastReceiver mLockoutReceiver = new BroadcastReceiver() {
         @Override
@@ -152,6 +156,7 @@
         mAlarmManager = mContext.getSystemService(AlarmManager.class);
         mContext.registerReceiver(mLockoutReceiver, new IntentFilter(ACTION_LOCKOUT_RESET),
                 RESET_FINGERPRINT_LOCKOUT, null /* handler */);
+        mUserManager = UserManager.get(mContext);
     }
 
     @Override
@@ -170,7 +175,7 @@
                     mDaemon.init(mDaemonCallback);
                     mHalDeviceId = mDaemon.openHal();
                     if (mHalDeviceId != 0) {
-                        updateActiveGroup(ActivityManager.getCurrentUser());
+                        updateActiveGroup(ActivityManager.getCurrentUser(), null);
                     } else {
                         Slog.w(TAG, "Failed to open Fingerprint HAL!");
                         mDaemon = null;
@@ -261,7 +266,7 @@
     }
 
     void handleUserSwitching(int userId) {
-        updateActiveGroup(userId);
+        updateActiveGroup(userId, null);
     }
 
     private void removeClient(ClientMonitor client) {
@@ -414,7 +419,7 @@
         removeClient(mEnrollClient);
     }
 
-    void startAuthentication(IBinder token, long opId, int groupId,
+    void startAuthentication(IBinder token, long opId, int realUserId, int groupId,
             IFingerprintServiceReceiver receiver, int flags, boolean restricted,
             String opPackageName) {
         IFingerprintDaemon daemon = getFingerprintDaemon();
@@ -423,6 +428,7 @@
             return;
         }
         stopPendingOperations(true);
+        updateActiveGroup(groupId, opPackageName);
         mAuthClient = new ClientMonitor(token, receiver, groupId, restricted, opPackageName);
         if (inLockoutMode()) {
             Slog.v(TAG, "In lockout mode; disallowing authentication");
@@ -564,7 +570,7 @@
         checkPermission(USE_FINGERPRINT);
         final int uid = Binder.getCallingUid();
         final int pid = Binder.getCallingPid();
-        if (opPackageName.equals(mKeyguardPackage)) {
+        if (isKeyguard(opPackageName)) {
             return true; // Keyguard is always allowed
         }
         if (!isCurrentUserOrProfile(UserHandle.getCallingUserId())) {
@@ -583,6 +589,14 @@
         return true;
     }
 
+    /**
+     * @param clientPackage
+     * @return true if this is keyguard package
+     */
+    private boolean isKeyguard(String clientPackage) {
+        return mKeyguardPackage.equals(clientPackage);
+    }
+
     private void addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor) {
         if (!mLockoutMonitors.contains(monitor)) {
             mLockoutMonitors.add(monitor);
@@ -673,7 +687,7 @@
         private boolean sendEnrollResult(int fpId, int groupId, int remaining) {
             if (receiver == null) return true; // client not listening
             FingerprintUtils.vibrateFingerprintSuccess(getContext());
-            MetricsLogger.action(mContext, MetricsLogger.ACTION_FINGERPRINT_ENROLL);
+            MetricsLogger.action(mContext, MetricsEvent.ACTION_FINGERPRINT_ENROLL);
             try {
                 receiver.onEnrollResult(mHalDeviceId, fpId, groupId, remaining);
                 return remaining == 0;
@@ -691,7 +705,7 @@
             boolean authenticated = fpId != 0;
             if (receiver != null) {
                 try {
-                    MetricsLogger.action(mContext, MetricsLogger.ACTION_FINGERPRINT_AUTH,
+                    MetricsLogger.action(mContext, MetricsEvent.ACTION_FINGERPRINT_AUTH,
                             authenticated);
                     if (!authenticated) {
                         receiver.onAuthenticationFailed(mHalDeviceId);
@@ -927,14 +941,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);
+            final int realUserId = Binder.getCallingUid();
 
             final boolean restricted = isRestricted();
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
                     MetricsLogger.histogram(mContext, "fingerprint_token", opId != 0L ? 1 : 0);
-                    startAuthentication(token, opId, effectiveGroupId, receiver, flags, restricted,
-                            opPackageName);
+                    startAuthentication(token, opId, realUserId, effectiveGroupId, receiver,
+                            flags, restricted, opPackageName);
                 }
             });
         }
@@ -953,6 +968,17 @@
         }
 
         @Override // Binder call
+        public void setActiveUser(final int userId) {
+            checkPermission(MANAGE_FINGERPRINT);
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    updateActiveGroup(userId, null);
+                }
+            });
+        }
+
+        @Override // Binder call
         public void remove(final IBinder token, final int fingerId, final int groupId,
                 final IFingerprintServiceReceiver receiver) {
             checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
@@ -1102,33 +1128,56 @@
         listenForUserSwitches();
     }
 
-    private void updateActiveGroup(int userId) {
+    private void updateActiveGroup(int userId, String clientPackage) {
         IFingerprintDaemon daemon = getFingerprintDaemon();
         if (daemon != null) {
             try {
-                userId = getEffectiveUserId(userId);
-                final File systemDir = Environment.getUserSystemDirectory(userId);
-                final File fpDir = new File(systemDir, FP_DATA_DIR);
-                if (!fpDir.exists()) {
-                    if (!fpDir.mkdir()) {
-                        Slog.v(TAG, "Cannot make directory: " + fpDir.getAbsolutePath());
-                        return;
+                userId = getUserOrWorkProfileId(clientPackage, userId);
+                if (userId != mCurrentUserId) {
+                    final File systemDir = Environment.getUserSystemDirectory(userId);
+                    final File fpDir = new File(systemDir, FP_DATA_DIR);
+                    if (!fpDir.exists()) {
+                        if (!fpDir.mkdir()) {
+                            Slog.v(TAG, "Cannot make directory: " + fpDir.getAbsolutePath());
+                            return;
+                        }
+                        // Calling mkdir() from this process will create a directory with our
+                        // permissions (inherited from the containing dir). This command fixes
+                        // the label.
+                        if (!SELinux.restorecon(fpDir)) {
+                            Slog.w(TAG, "Restorecons failed. Directory will have wrong label.");
+                            return;
+                        }
                     }
-                    // Calling mkdir() from this process will create a directory with our
-                    // permissions (inherited from the containing dir). This command fixes
-                    // the label.
-                    if (!SELinux.restorecon(fpDir)) {
-                        Slog.w(TAG, "Restorecons failed. Directory will have wrong label.");
-                        return;
-                    }
+                    daemon.setActiveGroup(userId, fpDir.getAbsolutePath().getBytes());
+                    mCurrentUserId = userId;
                 }
-                daemon.setActiveGroup(userId, fpDir.getAbsolutePath().getBytes());
             } catch (RemoteException e) {
                 Slog.e(TAG, "Failed to setActiveGroup():", e);
             }
         }
     }
 
+    /**
+     * @param clientPackage the package of the caller
+     * @return the profile id
+     */
+    private int getUserOrWorkProfileId(String clientPackage, int userId) {
+        if (!isKeyguard(clientPackage) && isWorkProfile(userId)) {
+            return userId;
+        }
+        return getEffectiveUserId(userId);
+    }
+
+    /**
+     * @param userId
+     * @return true if this is a work profile
+     */
+    private boolean isWorkProfile(int userId) {
+        UserInfo info = mUserManager.getUserInfo(userId);
+        return info != null && info.isManagedProfile();
+    }
+
     private void listenForUserSwitches() {
         try {
             ActivityManagerNative.getDefault().registerUserSwitchObserver(
diff --git a/services/core/java/com/android/server/firewall/SenderPackageFilter.java b/services/core/java/com/android/server/firewall/SenderPackageFilter.java
index dc3edd9..91c9671 100644
--- a/services/core/java/com/android/server/firewall/SenderPackageFilter.java
+++ b/services/core/java/com/android/server/firewall/SenderPackageFilter.java
@@ -20,6 +20,7 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
 import android.os.RemoteException;
 import android.os.UserHandle;
 
@@ -46,7 +47,8 @@
         try {
             // USER_SYSTEM here is not important. Only app id is used and getPackageUid() will
             // return a uid whether the app is installed for a user or not.
-            packageUid = pm.getPackageUid(mPackageName, UserHandle.USER_SYSTEM);
+            packageUid = pm.getPackageUid(mPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES,
+                    UserHandle.USER_SYSTEM);
         } catch (RemoteException ex) {
             // handled below
         }
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 5d2ed61..033a243 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -16,8 +16,11 @@
 
 package com.android.server.input;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.util.LocaleList;
 import android.view.Display;
+import com.android.internal.inputmethod.InputMethodSubtypeHandle;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.R;
 import com.android.internal.util.XmlUtils;
@@ -67,10 +70,12 @@
 import android.os.MessageQueue;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCommand;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
-import android.util.Log;
+import android.text.TextUtils;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.Xml;
@@ -97,9 +102,12 @@
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 
 import libcore.io.Streams;
 import libcore.util.Objects;
@@ -155,8 +163,7 @@
     private final ArrayList<InputDevice>
             mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only
     private boolean mKeyboardLayoutNotificationShown;
-    private PendingIntent mKeyboardLayoutIntent;
-    private Toast mSwitchedKeyboardLayoutToast;
+    private InputMethodSubtypeHandle mCurrentImeHandle;
 
     // State for vibrator tokens.
     private Object mVibratorLock = new Object();
@@ -214,6 +221,7 @@
     private static native void nativeSetPointerIconShape(long ptr, int iconId);
     private static native void nativeReloadPointerIcons(long ptr);
     private static native void nativeSetCustomPointerIcon(long ptr, PointerIcon icon);
+    private static native void nativeSetPointerIconDetached(long ptr, boolean detached);
 
     // Input event injection constants defined in InputDispatcher.h.
     private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
@@ -719,40 +727,35 @@
         mTempInputDevicesChangedListenersToNotify.clear();
 
         // Check for missing keyboard layouts.
-        if (mNotificationManager != null) {
-            final int numFullKeyboards = mTempFullKeyboards.size();
-            boolean missingLayoutForExternalKeyboard = false;
-            boolean missingLayoutForExternalKeyboardAdded = false;
-            boolean multipleMissingLayoutsForExternalKeyboardsAdded = false;
-            InputDevice keyboardMissingLayout = null;
-            synchronized (mDataStore) {
-                for (int i = 0; i < numFullKeyboards; i++) {
-                    final InputDevice inputDevice = mTempFullKeyboards.get(i);
-                    final String layout =
-                            getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());
-                    if (layout == null) {
-                        missingLayoutForExternalKeyboard = true;
-                        if (i < numFullKeyboardsAdded) {
-                            missingLayoutForExternalKeyboardAdded = true;
-                            if (keyboardMissingLayout == null) {
-                                keyboardMissingLayout = inputDevice;
-                            } else {
-                                multipleMissingLayoutsForExternalKeyboardsAdded = true;
-                            }
-                        }
+        List<InputDevice> keyboardsMissingLayout = new ArrayList<>();
+        final int numFullKeyboards = mTempFullKeyboards.size();
+        synchronized (mDataStore) {
+            for (int i = 0; i < numFullKeyboards; i++) {
+                final InputDevice inputDevice = mTempFullKeyboards.get(i);
+                String layout =
+                    getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());
+                if (layout == null) {
+                    layout = getDefaultKeyboardLayout(inputDevice);
+                    if (layout != null) {
+                        setCurrentKeyboardLayoutForInputDevice(
+                                inputDevice.getIdentifier(), layout);
                     }
                 }
+                if (layout == null) {
+                    keyboardsMissingLayout.add(inputDevice);
+                }
             }
-            if (missingLayoutForExternalKeyboard) {
-                if (missingLayoutForExternalKeyboardAdded) {
-                    if (multipleMissingLayoutsForExternalKeyboardsAdded) {
-                        // We have more than one keyboard missing a layout, so drop the
-                        // user at the generic input methods page so they can pick which
-                        // one to set.
-                        showMissingKeyboardLayoutNotification(null);
-                    } else {
-                        showMissingKeyboardLayoutNotification(keyboardMissingLayout);
-                    }
+        }
+
+        if (mNotificationManager != null) {
+            if (!keyboardsMissingLayout.isEmpty()) {
+                if (keyboardsMissingLayout.size() > 1) {
+                    // We have more than one keyboard missing a layout, so drop the
+                    // user at the generic input methods page so they can pick which
+                    // one to set.
+                    showMissingKeyboardLayoutNotification(null);
+                } else {
+                    showMissingKeyboardLayoutNotification(keyboardsMissingLayout.get(0));
                 }
             } else if (mKeyboardLayoutNotificationShown) {
                 hideMissingKeyboardLayoutNotification();
@@ -761,6 +764,86 @@
         mTempFullKeyboards.clear();
     }
 
+    private String getDefaultKeyboardLayout(final InputDevice d) {
+        final Locale systemLocale = mContext.getResources().getConfiguration().locale;
+        // If our locale doesn't have a language for some reason, then we don't really have a
+        // reasonable default.
+        if (TextUtils.isEmpty(systemLocale.getLanguage())) {
+            return null;
+        }
+        final List<KeyboardLayout> layouts = new ArrayList<>();
+        visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
+            @Override
+            public void visitKeyboardLayout(Resources resources,
+                    int keyboardLayoutResId, KeyboardLayout layout) {
+                // Only select a default when we know the layout is appropriate. For now, this
+                // means its a custom layout for a specific keyboard.
+                if (layout.getVendorId() != d.getVendorId()
+                        || layout.getProductId() != d.getProductId()) {
+                    return;
+                }
+                final LocaleList locales = layout.getLocales();
+                final int numLocales = locales.size();
+                for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
+                    if (isCompatibleLocale(systemLocale, locales.get(localeIndex))) {
+                        layouts.add(layout);
+                        break;
+                    }
+                }
+            }
+        });
+
+        if (layouts.isEmpty()) {
+            return null;
+        }
+
+        // First sort so that ones with higher priority are listed at the top
+        Collections.sort(layouts);
+        // Next we want to try to find an exact match of language, country and variant.
+        final int N = layouts.size();
+        for (int i = 0; i < N; i++) {
+            KeyboardLayout layout = layouts.get(i);
+            final LocaleList locales = layout.getLocales();
+            final int numLocales = locales.size();
+            for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
+                final Locale locale = locales.get(localeIndex);
+                if (locale.getCountry().equals(systemLocale.getCountry())
+                        && locale.getVariant().equals(systemLocale.getVariant())) {
+                    return layout.getDescriptor();
+                }
+            }
+        }
+        // Then try an exact match of language and country
+        for (int i = 0; i < N; i++) {
+            KeyboardLayout layout = layouts.get(i);
+            final LocaleList locales = layout.getLocales();
+            final int numLocales = locales.size();
+            for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
+                final Locale locale = locales.get(localeIndex);
+                if (locale.getCountry().equals(systemLocale.getCountry())) {
+                    return layout.getDescriptor();
+                }
+            }
+        }
+
+        // Give up and just use the highest priority layout with matching language
+        return layouts.get(0).getDescriptor();
+    }
+
+    private static boolean isCompatibleLocale(Locale systemLocale, Locale keyboardLocale) {
+        // Different languages are never compatible
+        if (!systemLocale.getLanguage().equals(keyboardLocale.getLanguage())) {
+            return false;
+        }
+        // If both the system and the keyboard layout have a country specifier, they must be equal.
+        if (!TextUtils.isEmpty(systemLocale.getCountry())
+                && !TextUtils.isEmpty(keyboardLocale.getCountry())
+                && !systemLocale.getCountry().equals(keyboardLocale.getCountry())) {
+            return false;
+        }
+        return true;
+    }
+
     @Override // Binder call & native callback
     public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor,
             int surfaceRotation) {
@@ -910,9 +993,9 @@
         final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
         visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
             @Override
-            public void visitKeyboardLayout(Resources resources, String descriptor, String label,
-                    String collection, int keyboardLayoutResId, int priority) {
-                availableKeyboardLayouts.add(descriptor);
+            public void visitKeyboardLayout(Resources resources,
+                    int keyboardLayoutResId, KeyboardLayout layout) {
+                availableKeyboardLayouts.add(layout.getDescriptor());
             }
         });
         synchronized (mDataStore) {
@@ -944,15 +1027,64 @@
         final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
         visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
             @Override
-            public void visitKeyboardLayout(Resources resources, String descriptor, String label,
-                    String collection, int keyboardLayoutResId, int priority) {
-                list.add(new KeyboardLayout(descriptor, label, collection, priority));
+            public void visitKeyboardLayout(Resources resources,
+                    int keyboardLayoutResId, KeyboardLayout layout) {
+                list.add(layout);
             }
         });
         return list.toArray(new KeyboardLayout[list.size()]);
     }
 
     @Override // Binder call
+    public KeyboardLayout[] getKeyboardLayoutsForInputDevice(
+            final InputDeviceIdentifier identifier) {
+        final String[] enabledLayoutDescriptors =
+            getEnabledKeyboardLayoutsForInputDevice(identifier);
+        final ArrayList<KeyboardLayout> enabledLayouts =
+            new ArrayList<KeyboardLayout>(enabledLayoutDescriptors.length);
+        final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<KeyboardLayout>();
+        visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
+            boolean mHasSeenDeviceSpecificLayout;
+
+            @Override
+            public void visitKeyboardLayout(Resources resources,
+                    int keyboardLayoutResId, KeyboardLayout layout) {
+                // First check if it's enabled. If the keyboard layout is enabled then we always
+                // want to return it as a possible layout for the device.
+                for (String s : enabledLayoutDescriptors) {
+                    if (s != null && s.equals(layout.getDescriptor())) {
+                        enabledLayouts.add(layout);
+                        return;
+                    }
+                }
+                // Next find any potential layouts that aren't yet enabled for the device. For
+                // devices that have special layouts we assume there's a reason that the generic
+                // layouts don't work for them so we don't want to return them since it's likely
+                // to result in a poor user experience.
+                if (layout.getVendorId() == identifier.getVendorId()
+                        && layout.getProductId() == identifier.getProductId()) {
+                    if (!mHasSeenDeviceSpecificLayout) {
+                        mHasSeenDeviceSpecificLayout = true;
+                        potentialLayouts.clear();
+                    }
+                    potentialLayouts.add(layout);
+                } else if (layout.getVendorId() == -1 && layout.getProductId() == -1
+                        && !mHasSeenDeviceSpecificLayout) {
+                    potentialLayouts.add(layout);
+                }
+            }
+        });
+        final int enabledLayoutSize = enabledLayouts.size();
+        final int potentialLayoutSize = potentialLayouts.size();
+        KeyboardLayout[] layouts = new KeyboardLayout[enabledLayoutSize + potentialLayoutSize];
+        enabledLayouts.toArray(layouts);
+        for (int i = 0; i < potentialLayoutSize; i++) {
+            layouts[enabledLayoutSize + i] = potentialLayouts.get(i);
+        }
+        return layouts;
+    }
+
+    @Override // Binder call
     public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
         if (keyboardLayoutDescriptor == null) {
             throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
@@ -961,13 +1093,13 @@
         final KeyboardLayout[] result = new KeyboardLayout[1];
         visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
             @Override
-            public void visitKeyboardLayout(Resources resources, String descriptor,
-                    String label, String collection, int keyboardLayoutResId, int priority) {
-                result[0] = new KeyboardLayout(descriptor, label, collection, priority);
+            public void visitKeyboardLayout(Resources resources,
+                    int keyboardLayoutResId, KeyboardLayout layout) {
+                result[0] = layout;
             }
         });
         if (result[0] == null) {
-            Log.w(TAG, "Could not get keyboard layout with descriptor '"
+            Slog.w(TAG, "Could not get keyboard layout with descriptor '"
                     + keyboardLayoutDescriptor + "'.");
         }
         return result[0];
@@ -977,7 +1109,7 @@
         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.GET_META_DATA | PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE)) {
             final ActivityInfo activityInfo = resolveInfo.activityInfo;
             final int priority = resolveInfo.priority;
             visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor);
@@ -992,7 +1124,8 @@
             try {
                 ActivityInfo receiver = pm.getReceiverInfo(
                         new ComponentName(d.packageName, d.receiverName),
-                        PackageManager.GET_META_DATA);
+                        PackageManager.GET_META_DATA
+                                | PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
                 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor);
             } catch (NameNotFoundException ex) {
             }
@@ -1008,7 +1141,7 @@
 
         int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
         if (configResId == 0) {
-            Log.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
+            Slog.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
                     + "' on receiver " + receiver.packageName + "/" + receiver.name);
             return;
         }
@@ -1045,8 +1178,16 @@
                             int keyboardLayoutResId = a.getResourceId(
                                     com.android.internal.R.styleable.KeyboardLayout_keyboardLayout,
                                     0);
+                            String languageTags = a.getString(
+                                    com.android.internal.R.styleable.KeyboardLayout_locale);
+                            LocaleList locales = getLocalesFromLanguageTags(languageTags);
+                            int vid = a.getInt(
+                                    com.android.internal.R.styleable.KeyboardLayout_vendorId, -1);
+                            int pid = a.getInt(
+                                    com.android.internal.R.styleable.KeyboardLayout_productId, -1);
+
                             if (name == null || label == null || keyboardLayoutResId == 0) {
-                                Log.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
+                                Slog.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
                                         + "attributes in keyboard layout "
                                         + "resource from receiver "
                                         + receiver.packageName + "/" + receiver.name);
@@ -1054,15 +1195,18 @@
                                 String descriptor = KeyboardLayoutDescriptor.format(
                                         receiver.packageName, receiver.name, name);
                                 if (keyboardName == null || name.equals(keyboardName)) {
-                                    visitor.visitKeyboardLayout(resources, descriptor,
-                                            label, collection, keyboardLayoutResId, priority);
+                                    KeyboardLayout layout = new KeyboardLayout(
+                                            descriptor, label, collection, priority,
+                                            locales, vid, pid);
+                                    visitor.visitKeyboardLayout(
+                                            resources, keyboardLayoutResId, layout);
                                 }
                             }
                         } finally {
                             a.recycle();
                         }
                     } else {
-                        Log.w(TAG, "Skipping unrecognized element '" + element
+                        Slog.w(TAG, "Skipping unrecognized element '" + element
                                 + "' in keyboard layout resource from receiver "
                                 + receiver.packageName + "/" + receiver.name);
                     }
@@ -1071,11 +1215,19 @@
                 parser.close();
             }
         } catch (Exception ex) {
-            Log.w(TAG, "Could not parse keyboard layout resource from receiver "
+            Slog.w(TAG, "Could not parse keyboard layout resource from receiver "
                     + receiver.packageName + "/" + receiver.name, ex);
         }
     }
 
+    @NonNull
+    private static LocaleList getLocalesFromLanguageTags(String languageTags) {
+        if (TextUtils.isEmpty(languageTags)) {
+            return LocaleList.getEmptyLocaleList();
+        }
+        return LocaleList.forLanguageTags(languageTags.replace('|', ','));
+    }
+
     /**
      * Builds a layout descriptor for the vendor/product. This returns the
      * descriptor for ids that aren't useful (such as the default 0, 0).
@@ -1141,7 +1293,7 @@
     }
 
     @Override // Binder call
-    public String[] getKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
+    public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
         String key = getLayoutDescriptor(identifier);
         synchronized (mDataStore) {
             String[] layouts = mDataStore.getKeyboardLayouts(key);
@@ -1154,6 +1306,82 @@
     }
 
     @Override // Binder call
+    @Nullable
+    public KeyboardLayout getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
+            InputMethodInfo imeInfo, InputMethodSubtype imeSubtype) {
+        InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
+        String key = getLayoutDescriptor(identifier);
+        final String keyboardLayoutDescriptor;
+        synchronized (mDataStore) {
+            keyboardLayoutDescriptor = mDataStore.getKeyboardLayout(key, handle);
+        }
+
+        if (keyboardLayoutDescriptor == null) {
+            return null;
+        }
+
+        final KeyboardLayout[] result = new KeyboardLayout[1];
+        visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
+            @Override
+            public void visitKeyboardLayout(Resources resources,
+                    int keyboardLayoutResId, KeyboardLayout layout) {
+                result[0] = layout;
+            }
+        });
+        if (result[0] == null) {
+            Slog.w(TAG, "Could not get keyboard layout with descriptor '"
+                    + keyboardLayoutDescriptor + "'.");
+        }
+        return result[0];
+    }
+
+    @Override
+    public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
+            InputMethodInfo imeInfo, InputMethodSubtype imeSubtype,
+            String keyboardLayoutDescriptor) {
+        if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
+                "setKeyboardLayoutForInputDevice()")) {
+            throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
+        }
+        if (keyboardLayoutDescriptor == null) {
+            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
+        }
+        if (imeInfo == null || imeSubtype == null) {
+            throw new IllegalArgumentException("imeInfo and imeSubtype must not be null");
+        }
+        InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
+        setKeyboardLayoutForInputDeviceInner(identifier, handle, keyboardLayoutDescriptor);
+    }
+
+    private void setKeyboardLayoutForInputDeviceInner(InputDeviceIdentifier identifier,
+            InputMethodSubtypeHandle imeHandle, String keyboardLayoutDescriptor) {
+        String key = getLayoutDescriptor(identifier);
+        synchronized (mDataStore) {
+            try {
+                if (mDataStore.setKeyboardLayout(key, imeHandle, keyboardLayoutDescriptor)) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "Set keyboard layout " + keyboardLayoutDescriptor +
+                                " for subtype " + imeHandle + " and device " + identifier +
+                                " using key " + key);
+                    }
+                    if (imeHandle.equals(mCurrentImeHandle)) {
+                        if (DEBUG) {
+                            Slog.d(TAG, "Layout for current subtype changed, switching layout");
+                        }
+                        SomeArgs args = SomeArgs.obtain();
+                        args.arg1 = identifier;
+                        args.arg2 = imeHandle;
+                        mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, args).sendToTarget();
+                    }
+                    mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
+                }
+            } finally {
+                mDataStore.saveIfNeeded();
+            }
+        }
+    }
+
+    @Override // Binder call
     public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
             String keyboardLayoutDescriptor) {
         if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
@@ -1172,8 +1400,7 @@
                     oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
                 }
                 if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
-                        && !Objects.equal(oldLayout,
-                                mDataStore.getCurrentKeyboardLayout(key))) {
+                        && !Objects.equal(oldLayout, mDataStore.getCurrentKeyboardLayout(key))) {
                     mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
                 }
             } finally {
@@ -1223,45 +1450,44 @@
             Slog.i(TAG, "InputMethodSubtype changed: userId=" + userId
                     + " ime=" + inputMethodInfo + " subtype=" + subtype);
         }
-    }
-
-    public void switchKeyboardLayout(int deviceId, int direction) {
-        mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
+        if (inputMethodInfo == null) {
+            Slog.d(TAG, "No InputMethod is running, ignoring change");
+            return;
+        }
+        if (subtype != null && !"keyboard".equals(subtype.getMode())) {
+            Slog.d(TAG, "InputMethodSubtype changed to non-keyboard subtype, ignoring change");
+            return;
+        }
+        InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(inputMethodInfo, subtype);
+        if (!handle.equals(mCurrentImeHandle)) {
+            mCurrentImeHandle = handle;
+            handleSwitchKeyboardLayout(null, handle);
+        }
     }
 
     // Must be called on handler.
-    private void handleSwitchKeyboardLayout(int deviceId, int direction) {
-        final InputDevice device = getInputDevice(deviceId);
-        if (device != null) {
-            final boolean changed;
-            final String keyboardLayoutDescriptor;
-
-            String key = getLayoutDescriptor(device.getIdentifier());
-            synchronized (mDataStore) {
-                try {
-                    changed = mDataStore.switchKeyboardLayout(key, direction);
-                    keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
-                            key);
-                } finally {
-                    mDataStore.saveIfNeeded();
+    private void handleSwitchKeyboardLayout(@Nullable InputDeviceIdentifier identifier,
+            InputMethodSubtypeHandle handle) {
+        synchronized (mInputDevicesLock) {
+            for (InputDevice device : mInputDevices) {
+                if (identifier != null && !device.getIdentifier().equals(identifier) ||
+                        !device.isFullKeyboard()) {
+                    continue;
                 }
-            }
-
-            if (changed) {
-                if (mSwitchedKeyboardLayoutToast != null) {
-                    mSwitchedKeyboardLayoutToast.cancel();
-                    mSwitchedKeyboardLayoutToast = null;
-                }
-                if (keyboardLayoutDescriptor != null) {
-                    KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor);
-                    if (keyboardLayout != null) {
-                        mSwitchedKeyboardLayoutToast = Toast.makeText(
-                                mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT);
-                        mSwitchedKeyboardLayoutToast.show();
+                String key = getLayoutDescriptor(device.getIdentifier());
+                boolean changed = false;
+                synchronized (mDataStore) {
+                    try {
+                        if (mDataStore.switchKeyboardLayout(key, handle)) {
+                            changed = true;
+                        }
+                    } finally {
+                        mDataStore.saveIfNeeded();
                     }
                 }
-
-                reloadKeyboardLayouts();
+                if (changed) {
+                    reloadKeyboardLayouts();
+                }
             }
         }
     }
@@ -1274,6 +1500,11 @@
         nativeSetFocusedApplication(mPtr, application);
     }
 
+    @Override
+    public void setPointerIconDetached(boolean detached) {
+        nativeSetPointerIconDetached(mPtr, detached);
+    }
+
     public void setInputDispatchMode(boolean enabled, boolean frozen) {
         nativeSetInputDispatchMode(mPtr, enabled, frozen);
     }
@@ -1468,7 +1699,7 @@
     }
 
     @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+    public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
                 != PackageManager.PERMISSION_GRANTED) {
             pw.println("Permission Denial: can't dump InputManager from from pid="
@@ -1482,8 +1713,48 @@
         if (dumpStr != null) {
             pw.println(dumpStr);
         }
+        pw.println("  Keyboard Layouts:");
+        visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
+            @Override
+            public void visitKeyboardLayout(Resources resources,
+                    int keyboardLayoutResId, KeyboardLayout layout) {
+                pw.println("    \"" + layout + "\": " + layout.getDescriptor());
+            }
+        });
+        pw.println();
+        synchronized(mDataStore) {
+            mDataStore.dump(pw, "  ");
+        }
     }
 
+    @Override
+    public void onShellCommand(FileDescriptor in, FileDescriptor out,
+            FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
+        (new Shell()).exec(this, in, out, err, args, resultReceiver);
+    }
+
+    public int onShellCommand(Shell shell, String cmd) {
+        if (TextUtils.isEmpty(cmd)) {
+            shell.onHelp();
+            return 1;
+        }
+        if (cmd.equals("setlayout")) {
+            if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
+                    "onShellCommand()")) {
+                throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
+            }
+            InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(
+                    shell.getNextArgRequired(), Integer.parseInt(shell.getNextArgRequired()));
+            String descriptor = shell.getNextArgRequired();
+            int vid = Integer.decode(shell.getNextArgRequired());
+            int pid = Integer.decode(shell.getNextArgRequired());
+            InputDeviceIdentifier id = new InputDeviceIdentifier(descriptor, vid, pid);
+            setKeyboardLayoutForInputDeviceInner(id, handle, shell.getNextArgRequired());
+        }
+        return 0;
+    }
+
+
     private boolean checkCallingPermission(String permission, String func) {
         // Quick check: if the calling permission is me, it's all okay.
         if (Binder.getCallingPid() == Process.myPid()) {
@@ -1711,10 +1982,10 @@
         final String[] result = new String[2];
         visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
             @Override
-            public void visitKeyboardLayout(Resources resources, String descriptor, String label,
-                    String collection, int keyboardLayoutResId, int priority) {
+            public void visitKeyboardLayout(Resources resources,
+                    int keyboardLayoutResId, KeyboardLayout layout) {
                 try {
-                    result[0] = descriptor;
+                    result[0] = layout.getDescriptor();
                     result[1] = Streams.readFully(new InputStreamReader(
                             resources.openRawResource(keyboardLayoutResId)));
                 } catch (IOException ex) {
@@ -1723,7 +1994,7 @@
             }
         });
         if (result[0] == null) {
-            Log.w(TAG, "Could not get keyboard layout with descriptor '"
+            Slog.w(TAG, "Could not get keyboard layout with descriptor '"
                     + keyboardLayoutDescriptor + "'.");
             return null;
         }
@@ -1789,9 +2060,12 @@
                 case MSG_DELIVER_INPUT_DEVICES_CHANGED:
                     deliverInputDevicesChanged((InputDevice[])msg.obj);
                     break;
-                case MSG_SWITCH_KEYBOARD_LAYOUT:
-                    handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
+                case MSG_SWITCH_KEYBOARD_LAYOUT: {
+                    SomeArgs args = (SomeArgs)msg.obj;
+                    handleSwitchKeyboardLayout((InputDeviceIdentifier)args.arg1,
+                            (InputMethodSubtypeHandle)args.arg2);
                     break;
+                }
                 case MSG_RELOAD_KEYBOARD_LAYOUTS:
                     reloadKeyboardLayouts();
                     break;
@@ -1876,8 +2150,8 @@
     }
 
     private interface KeyboardLayoutVisitor {
-        void visitKeyboardLayout(Resources resources, String descriptor, String label,
-                String collection, int keyboardLayoutResId, int priority);
+        void visitKeyboardLayout(Resources resources,
+                int keyboardLayoutResId, KeyboardLayout layout);
     }
 
     private final class InputDevicesChangedListenerRecord implements DeathRecipient {
@@ -1958,6 +2232,25 @@
         }
     }
 
+    private class Shell extends ShellCommand {
+        @Override
+        public int onCommand(String cmd) {
+            return onShellCommand(this, cmd);
+        }
+
+        @Override
+        public void onHelp() {
+            final PrintWriter pw = getOutPrintWriter();
+            pw.println("Input manager commands:");
+            pw.println("  help");
+            pw.println("    Print this help text.");
+            pw.println("");
+            pw.println("  setlayout IME_ID IME_SUPTYPE_HASH_CODE"
+                    + " DEVICE_DESCRIPTOR VENDOR_ID PRODUCT_ID KEYBOARD_DESCRIPTOR");
+            pw.println("    Sets a keyboard layout for a given IME subtype and input device pair");
+        }
+    }
+
     private final class LocalService extends InputManagerInternal {
         @Override
         public void setDisplayViewports(
diff --git a/services/core/java/com/android/server/input/PersistentDataStore.java b/services/core/java/com/android/server/input/PersistentDataStore.java
index f6d7244..e97aca8 100644
--- a/services/core/java/com/android/server/input/PersistentDataStore.java
+++ b/services/core/java/com/android/server/input/PersistentDataStore.java
@@ -16,6 +16,7 @@
 
 package com.android.server.input;
 
+import com.android.internal.inputmethod.InputMethodSubtypeHandle;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
@@ -26,6 +27,8 @@
 
 import android.view.Surface;
 import android.hardware.input.TouchCalibration;
+import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.AtomicFile;
 import android.util.Slog;
 import android.util.Xml;
@@ -37,10 +40,13 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.PrintWriter;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -131,9 +137,26 @@
         }
         return state.getKeyboardLayouts();
     }
+    public String getKeyboardLayout(String inputDeviceDescriptor,
+            InputMethodSubtypeHandle imeHandle) {
+        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false);
+        if (state == null) {
+            return null;
+        }
+        return state.getKeyboardLayout(imeHandle);
+    }
 
-    public boolean addKeyboardLayout(String inputDeviceDescriptor,
-            String keyboardLayoutDescriptor) {
+    public boolean setKeyboardLayout(String inputDeviceDescriptor,
+            InputMethodSubtypeHandle imeHandle, String keyboardLayoutDescriptor) {
+        InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true);
+        if (state.setKeyboardLayout(imeHandle, keyboardLayoutDescriptor)) {
+            setDirty();
+            return true;
+        }
+        return false;
+    }
+
+    public boolean addKeyboardLayout(String inputDeviceDescriptor, String keyboardLayoutDescriptor) {
         InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true);
         if (state.addKeyboardLayout(keyboardLayoutDescriptor)) {
             setDirty();
@@ -152,9 +175,10 @@
         return false;
     }
 
-    public boolean switchKeyboardLayout(String inputDeviceDescriptor, int direction) {
+    public boolean switchKeyboardLayout(String inputDeviceDescriptor,
+            InputMethodSubtypeHandle imeHandle) {
         InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false);
-        if (state != null && state.switchKeyboardLayout(direction)) {
+        if (state != null && state.switchKeyboardLayout(imeHandle)) {
             setDirty();
             return true;
         }
@@ -301,13 +325,26 @@
         serializer.endDocument();
     }
 
+    public void dump(PrintWriter pw, String prefix) {
+        pw.println(prefix + "PersistentDataStore");
+        pw.println(prefix + "  mLoaded=" + mLoaded);
+        pw.println(prefix + "  mDirty=" + mDirty);
+        pw.println(prefix + "  InputDeviceStates:");
+        int i = 0;
+        for (Map.Entry<String, InputDeviceState> entry : mInputDevices.entrySet()) {
+            pw.println(prefix + "    " + i++ + ": " + entry.getKey());
+            entry.getValue().dump(pw, prefix + "      ");
+        }
+    }
+
     private static final class InputDeviceState {
         private static final String[] CALIBRATION_NAME = { "x_scale",
                 "x_ymix", "x_offset", "y_xmix", "y_scale", "y_offset" };
 
         private TouchCalibration[] mTouchCalibration = new TouchCalibration[4];
         private String mCurrentKeyboardLayout;
-        private ArrayList<String> mKeyboardLayouts = new ArrayList<String>();
+        private List<String> mUnassociatedKeyboardLayouts = new ArrayList<>();
+        private ArrayMap<InputMethodSubtypeHandle, String> mKeyboardLayouts = new ArrayMap<>();
 
         public TouchCalibration getTouchCalibration(int surfaceRotation) {
             try {
@@ -345,18 +382,34 @@
         }
 
         public String[] getKeyboardLayouts() {
-            if (mKeyboardLayouts.isEmpty()) {
+            if (mUnassociatedKeyboardLayouts.isEmpty()) {
                 return (String[])ArrayUtils.emptyArray(String.class);
             }
-            return mKeyboardLayouts.toArray(new String[mKeyboardLayouts.size()]);
+            return mUnassociatedKeyboardLayouts.toArray(
+                    new String[mUnassociatedKeyboardLayouts.size()]);
+        }
+
+        public String getKeyboardLayout(InputMethodSubtypeHandle handle) {
+            return mKeyboardLayouts.get(handle);
+        }
+
+        public boolean setKeyboardLayout(InputMethodSubtypeHandle imeHandle,
+                String keyboardLayout) {
+            String existingLayout = mKeyboardLayouts.get(imeHandle);
+            if (TextUtils.equals(existingLayout, keyboardLayout)) {
+                return false;
+            }
+            mKeyboardLayouts.put(imeHandle, keyboardLayout);
+            return true;
         }
 
         public boolean addKeyboardLayout(String keyboardLayout) {
-            int index = Collections.binarySearch(mKeyboardLayouts, keyboardLayout);
+            int index = Collections.binarySearch(
+                    mUnassociatedKeyboardLayouts, keyboardLayout);
             if (index >= 0) {
                 return false;
             }
-            mKeyboardLayouts.add(-index - 1, keyboardLayout);
+            mUnassociatedKeyboardLayouts.add(-index - 1, keyboardLayout);
             if (mCurrentKeyboardLayout == null) {
                 mCurrentKeyboardLayout = keyboardLayout;
             }
@@ -364,11 +417,11 @@
         }
 
         public boolean removeKeyboardLayout(String keyboardLayout) {
-            int index = Collections.binarySearch(mKeyboardLayouts, keyboardLayout);
+            int index = Collections.binarySearch(mUnassociatedKeyboardLayouts, keyboardLayout);
             if (index < 0) {
                 return false;
             }
-            mKeyboardLayouts.remove(index);
+            mUnassociatedKeyboardLayouts.remove(index);
             updateCurrentKeyboardLayoutIfRemoved(keyboardLayout, index);
             return true;
         }
@@ -376,41 +429,34 @@
         private void updateCurrentKeyboardLayoutIfRemoved(
                 String removedKeyboardLayout, int removedIndex) {
             if (Objects.equal(mCurrentKeyboardLayout, removedKeyboardLayout)) {
-                if (!mKeyboardLayouts.isEmpty()) {
+                if (!mUnassociatedKeyboardLayouts.isEmpty()) {
                     int index = removedIndex;
-                    if (index == mKeyboardLayouts.size()) {
+                    if (index == mUnassociatedKeyboardLayouts.size()) {
                         index = 0;
                     }
-                    mCurrentKeyboardLayout = mKeyboardLayouts.get(index);
+                    mCurrentKeyboardLayout = mUnassociatedKeyboardLayouts.get(index);
                 } else {
                     mCurrentKeyboardLayout = null;
                 }
             }
         }
 
-        public boolean switchKeyboardLayout(int direction) {
-            final int size = mKeyboardLayouts.size();
-            if (size < 2) {
-                return false;
+        public boolean switchKeyboardLayout(InputMethodSubtypeHandle imeHandle) {
+            final String layout = mKeyboardLayouts.get(imeHandle);
+            if (layout != null && !TextUtils.equals(mCurrentKeyboardLayout, layout)) {
+                mCurrentKeyboardLayout = layout;
+                return true;
             }
-            int index = Collections.binarySearch(mKeyboardLayouts, mCurrentKeyboardLayout);
-            assert index >= 0;
-            if (direction > 0) {
-                index = (index + 1) % size;
-            } else {
-                index = (index + size - 1) % size;
-            }
-            mCurrentKeyboardLayout = mKeyboardLayouts.get(index);
-            return true;
+            return false;
         }
 
         public boolean removeUninstalledKeyboardLayouts(Set<String> availableKeyboardLayouts) {
             boolean changed = false;
-            for (int i = mKeyboardLayouts.size(); i-- > 0; ) {
-                String keyboardLayout = mKeyboardLayouts.get(i);
+            for (int i = mUnassociatedKeyboardLayouts.size(); i-- > 0; ) {
+                String keyboardLayout = mUnassociatedKeyboardLayouts.get(i);
                 if (!availableKeyboardLayouts.contains(keyboardLayout)) {
                     Slog.i(TAG, "Removing uninstalled keyboard layout " + keyboardLayout);
-                    mKeyboardLayouts.remove(i);
+                    mUnassociatedKeyboardLayouts.remove(i);
                     updateCurrentKeyboardLayoutIfRemoved(keyboardLayout, i);
                     changed = true;
                 }
@@ -428,13 +474,8 @@
                         throw new XmlPullParserException(
                                 "Missing descriptor attribute on keyboard-layout.");
                     }
-                    String current = parser.getAttributeValue(null, "current");
-                    if (mKeyboardLayouts.contains(descriptor)) {
-                        throw new XmlPullParserException(
-                                "Found duplicate keyboard layout.");
-                    }
 
-                    mKeyboardLayouts.add(descriptor);
+                    String current = parser.getAttributeValue(null, "current");
                     if (current != null && current.equals("true")) {
                         if (mCurrentKeyboardLayout != null) {
                             throw new XmlPullParserException(
@@ -442,6 +483,32 @@
                         }
                         mCurrentKeyboardLayout = descriptor;
                     }
+
+                    String inputMethodId = parser.getAttributeValue(null, "input-method-id");
+                    String inputMethodSubtypeId =
+                        parser.getAttributeValue(null, "input-method-subtype-id");
+                    if (inputMethodId == null && inputMethodSubtypeId != null
+                            || inputMethodId != null && inputMethodSubtypeId == null) {
+                        throw new XmlPullParserException(
+                                "Found an incomplete input method description");
+                    }
+
+                    if (inputMethodSubtypeId != null) {
+                        InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(
+                                inputMethodId, Integer.parseInt(inputMethodSubtypeId));
+                        if (mKeyboardLayouts.containsKey(handle)) {
+                            throw new XmlPullParserException(
+                                    "Found duplicate subtype to keyboard layout mapping: "
+                                    + handle);
+                        }
+                        mKeyboardLayouts.put(handle, descriptor);
+                    } else {
+                        if (mUnassociatedKeyboardLayouts.contains(descriptor)) {
+                            throw new XmlPullParserException(
+                                    "Found duplicate unassociated keyboard layout: " + descriptor);
+                        }
+                        mUnassociatedKeyboardLayouts.add(descriptor);
+                    }
                 } else if (parser.getName().equals("calibration")) {
                     String format = parser.getAttributeValue(null, "format");
                     String rotation = parser.getAttributeValue(null, "rotation");
@@ -492,19 +559,31 @@
             }
 
             // Maintain invariant that layouts are sorted.
-            Collections.sort(mKeyboardLayouts);
+            Collections.sort(mUnassociatedKeyboardLayouts);
 
             // Maintain invariant that there is always a current keyboard layout unless
             // there are none installed.
-            if (mCurrentKeyboardLayout == null && !mKeyboardLayouts.isEmpty()) {
-                mCurrentKeyboardLayout = mKeyboardLayouts.get(0);
+            if (mCurrentKeyboardLayout == null && !mUnassociatedKeyboardLayouts.isEmpty()) {
+                mCurrentKeyboardLayout = mUnassociatedKeyboardLayouts.get(0);
             }
         }
 
         public void saveToXml(XmlSerializer serializer) throws IOException {
-            for (String layout : mKeyboardLayouts) {
+            for (String layout : mUnassociatedKeyboardLayouts) {
                 serializer.startTag(null, "keyboard-layout");
                 serializer.attribute(null, "descriptor", layout);
+                serializer.endTag(null, "keyboard-layout");
+            }
+
+            final int N = mKeyboardLayouts.size();
+            for (int i = 0; i < N; i++) {
+                final InputMethodSubtypeHandle handle = mKeyboardLayouts.keyAt(i);
+                final String layout = mKeyboardLayouts.valueAt(i);
+                serializer.startTag(null, "keyboard-layout");
+                serializer.attribute(null, "descriptor", layout);
+                serializer.attribute(null, "input-method-id", handle.getInputMethodId());
+                serializer.attribute(null, "input-method-subtype-id",
+                        Integer.toString(handle.getSubtypeId()));
                 if (layout.equals(mCurrentKeyboardLayout)) {
                     serializer.attribute(null, "current", "true");
                 }
@@ -529,6 +608,22 @@
             }
         }
 
+        private void dump(final PrintWriter pw, final String prefix) {
+            pw.println(prefix + "CurrentKeyboardLayout=" + mCurrentKeyboardLayout);
+            pw.println(prefix + "UnassociatedKeyboardLayouts=" + mUnassociatedKeyboardLayouts);
+            pw.println(prefix + "TouchCalibration=" + Arrays.toString(mTouchCalibration));
+            pw.println(prefix + "Subtype to Layout Mappings:");
+            final int N = mKeyboardLayouts.size();
+            if (N != 0) {
+                for (int i = 0; i < N; i++) {
+                    pw.println(prefix + "  " + mKeyboardLayouts.keyAt(i) + ": "
+                            + mKeyboardLayouts.valueAt(i));
+                }
+            } else {
+                pw.println(prefix + "  <none>");
+            }
+        }
+
         private static String surfaceRotationToString(int surfaceRotation) {
             switch (surfaceRotation) {
                 case Surface.ROTATION_0:   return "0";
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 309bec8..43cd44f 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -27,6 +27,7 @@
 import android.app.AppGlobals;
 import android.app.IUidObserver;
 import android.app.job.JobInfo;
+import android.app.job.JobParameters;
 import android.app.job.JobScheduler;
 import android.app.job.JobService;
 import android.app.job.IJobScheduler;
@@ -48,6 +49,7 @@
 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;
@@ -58,6 +60,7 @@
 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.IdleController;
 import com.android.server.job.controllers.JobStatus;
 import com.android.server.job.controllers.StateController;
@@ -107,6 +110,11 @@
      */
     static final int MIN_CONNECTIVITY_COUNT = 1;  // Run connectivity jobs as soon as ready.
     /**
+     * Minimum # of content trigger jobs that must be ready in order to force the JMS to schedule
+     * things early.
+     */
+    static final int MIN_CONTENT_COUNT = 1;
+    /**
      * Minimum # of jobs (with no particular constraints) for which the JMS will be happy running
      * some work early.
      * This is correlated with the amount of batching we'll be able to do.
@@ -178,7 +186,7 @@
                     || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction())) {
                 updateIdleMode(mPowerManager != null
                         ? (mPowerManager.isDeviceIdleMode()
-                                || mPowerManager.isLightDeviceIdleMode())
+                        || mPowerManager.isLightDeviceIdleMode())
                         : false);
             }
         }
@@ -219,8 +227,14 @@
      * @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);
+    }
+
+    public int scheduleAsPackage(JobInfo job, int uId, String packageName, int userId) {
         JobStatus jobStatus = new JobStatus(job, uId);
-        cancelJob(uId, job.getId());
+        if (packageName != null) {
+            jobStatus.setSource(packageName, userId);
+        }
         try {
             if (ActivityManagerNative.getDefault().getAppStartMode(uId,
                     job.getService().getPackageName()) == ActivityManager.APP_START_MODE_DISABLED) {
@@ -230,7 +244,15 @@
             }
         } catch (RemoteException e) {
         }
-        startTrackingJob(jobStatus);
+        if (DEBUG) Slog.d(TAG, "SCHEDULE: " + jobStatus.toShortString());
+        JobStatus toCancel;
+        synchronized (mJobs) {
+            toCancel = mJobs.getJobByUidAndJobId(uId, job.getId());
+        }
+        startTrackingJob(jobStatus, toCancel);
+        if (toCancel != null) {
+            cancelJobImpl(toCancel);
+        }
         mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
         return JobScheduler.RESULT_SUCCESS;
     }
@@ -307,15 +329,13 @@
     }
 
     private void cancelJobImpl(JobStatus cancelled) {
-        if (DEBUG) {
-            Slog.d(TAG, "Cancelling: " + cancelled);
-        }
+        if (DEBUG) Slog.d(TAG, "CANCEL: " + cancelled.toShortString());
         stopTrackingJob(cancelled);
         synchronized (mJobs) {
             // Remove from pending queue.
             mPendingJobs.remove(cancelled);
             // Cancel if running.
-            stopJobOnServiceContextLocked(cancelled);
+            stopJobOnServiceContextLocked(cancelled, JobParameters.REASON_CANCELED);
             reportActive();
         }
     }
@@ -343,7 +363,7 @@
                         JobServiceContext jsc = mActiveServices.get(i);
                         final JobStatus executing = jsc.getRunningJob();
                         if (executing != null) {
-                            jsc.cancelExecutingJob();
+                            jsc.cancelExecutingJob(JobParameters.REASON_DEVICE_IDLE);
                         }
                     }
                 } else {
@@ -368,7 +388,7 @@
         if (mPendingJobs.size() <= 0) {
             for (int i=0; i<mActiveServices.size(); i++) {
                 JobServiceContext jsc = mActiveServices.get(i);
-                if (!jsc.isAvailable()) {
+                if (jsc.getRunningJob() != null) {
                     active = true;
                     break;
                 }
@@ -401,6 +421,7 @@
         mControllers.add(IdleController.get(this));
         mControllers.add(BatteryController.get(this));
         mControllers.add(AppIdleController.get(this));
+        mControllers.add(ContentObserverController.get(this));
 
         mHandler = new JobHandler(context.getMainLooper());
         mJobSchedulerStub = new JobSchedulerStub();
@@ -452,7 +473,7 @@
                     JobStatus job = jobs.valueAt(i);
                     for (int controller=0; controller<mControllers.size(); controller++) {
                         mControllers.get(controller).deviceIdleModeChanged(mDeviceIdleMode);
-                        mControllers.get(controller).maybeStartTrackingJob(job);
+                        mControllers.get(controller).maybeStartTrackingJob(job, null);
                     }
                 }
                 // GO GO GO!
@@ -466,7 +487,7 @@
      * {@link com.android.server.job.JobStore}, and make sure all the relevant controllers know
      * about.
      */
-    private void startTrackingJob(JobStatus jobStatus) {
+    private void startTrackingJob(JobStatus jobStatus, JobStatus lastJob) {
         boolean update;
         boolean rocking;
         synchronized (mJobs) {
@@ -477,9 +498,9 @@
             for (int i=0; i<mControllers.size(); i++) {
                 StateController controller = mControllers.get(i);
                 if (update) {
-                    controller.maybeStopTrackingJob(jobStatus);
+                    controller.maybeStopTrackingJob(jobStatus, true);
                 }
-                controller.maybeStartTrackingJob(jobStatus);
+                controller.maybeStartTrackingJob(jobStatus, lastJob);
             }
         }
     }
@@ -499,18 +520,18 @@
         if (removed && rocking) {
             for (int i=0; i<mControllers.size(); i++) {
                 StateController controller = mControllers.get(i);
-                controller.maybeStopTrackingJob(jobStatus);
+                controller.maybeStopTrackingJob(jobStatus, false);
             }
         }
         return removed;
     }
 
-    private boolean stopJobOnServiceContextLocked(JobStatus job) {
+    private boolean stopJobOnServiceContextLocked(JobStatus job, int reason) {
         for (int i=0; i<mActiveServices.size(); i++) {
             JobServiceContext jsc = mActiveServices.get(i);
             final JobStatus executing = jsc.getRunningJob();
             if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
-                jsc.cancelExecutingJob();
+                jsc.cancelExecutingJob(reason);
                 return true;
             }
         }
@@ -568,8 +589,13 @@
         }
         delayMillis =
                 Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS);
-        return new JobStatus(failureToReschedule, elapsedNowMillis + delayMillis,
+        JobStatus newJob = new JobStatus(failureToReschedule, elapsedNowMillis + delayMillis,
                 JobStatus.NO_LATEST_RUNTIME, backoffAttempts);
+        for (int ic=0; ic<mControllers.size(); ic++) {
+            StateController controller = mControllers.get(ic);
+            controller.rescheduleForFailure(newJob, failureToReschedule);
+        }
+        return newJob;
     }
 
     /**
@@ -592,9 +618,10 @@
         if (periodicToReschedule.hasDeadlineConstraint()) {
             runEarly = Math.max(periodicToReschedule.getLatestRunTimeElapsed() - elapsedNow, 0L);
         }
-        long newEarliestRunTimeElapsed = elapsedNow + runEarly;
+        long flex = periodicToReschedule.getJob().getFlexMillis();
         long period = periodicToReschedule.getJob().getIntervalMillis();
-        long newLatestRuntimeElapsed = newEarliestRunTimeElapsed + period;
+        long newLatestRuntimeElapsed = elapsedNow + runEarly + period;
+        long newEarliestRunTimeElapsed = newLatestRuntimeElapsed - flex;
 
         if (DEBUG) {
             Slog.v(TAG, "Rescheduling executed periodic. New execution window [" +
@@ -622,14 +649,21 @@
             if (DEBUG) {
                 Slog.d(TAG, "Could not find job to remove. Was job removed while executing?");
             }
+            // We still want to check for jobs to execute, because this job may have
+            // scheduled a new job under the same job id, and now we can run it.
+            mHandler.obtainMessage(MSG_CHECK_JOB_GREEDY).sendToTarget();
             return;
         }
+        // Note: there is a small window of time in here where, when rescheduling a job,
+        // we will stop monitoring its content providers.  This should be fixed by stopping
+        // the old job after scheduling the new one, but since we have no lock held here
+        // that may cause ordering problems if the app removes jobStatus while in here.
         if (needsReschedule) {
             JobStatus rescheduled = getRescheduleJobForFailure(jobStatus);
-            startTrackingJob(rescheduled);
+            startTrackingJob(rescheduled, jobStatus);
         } else if (jobStatus.getJob().isPeriodic()) {
             JobStatus rescheduledPeriodic = getRescheduleJobForPeriodic(jobStatus);
-            startTrackingJob(rescheduledPeriodic);
+            startTrackingJob(rescheduledPeriodic, jobStatus);
         }
         reportActive();
         mHandler.obtainMessage(MSG_CHECK_JOB_GREEDY).sendToTarget();
@@ -709,6 +743,7 @@
          */
         private void queueReadyJobsForExecutionLockedH() {
             ArraySet<JobStatus> jobs = mJobs.getJobs();
+            mPendingJobs.clear();
             if (DEBUG) {
                 Slog.d(TAG, "queuing all ready jobs for execution:");
             }
@@ -719,8 +754,9 @@
                         Slog.d(TAG, "    queued " + job.toShortString());
                     }
                     mPendingJobs.add(job);
-                } else if (isReadyToBeCancelledLocked(job)) {
-                    stopJobOnServiceContextLocked(job);
+                } else if (areJobConstraintsNotSatisfied(job)) {
+                    stopJobOnServiceContextLocked(job,
+                            JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED);
                 }
             }
             if (DEBUG) {
@@ -743,12 +779,15 @@
          * 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);
                 if (isReadyToBeExecutedLocked(job)) {
@@ -775,18 +814,23 @@
                     if (job.hasChargingConstraint()) {
                         chargingCount++;
                     }
+                    if (job.hasContentTriggerConstraint()) {
+                        contentCount++;
+                    }
                     if (runnableJobs == null) {
                         runnableJobs = new ArrayList<>();
                     }
                     runnableJobs.add(job);
-                } else if (isReadyToBeCancelledLocked(job)) {
-                    stopJobOnServiceContextLocked(job);
+                } else if (areJobConstraintsNotSatisfied(job)) {
+                    stopJobOnServiceContextLocked(job,
+                            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.");
@@ -799,11 +843,6 @@
                     Slog.d(TAG, "maybeQueueReadyJobsForExecutionLockedH: Not running anything.");
                 }
             }
-            if (DEBUG) {
-                Slog.d(TAG, "idle=" + idleCount + " connectivity=" +
-                connectivityCount + " charging=" + chargingCount + " tot=" +
-                        runnableJobs.size());
-            }
         }
 
         /**
@@ -831,7 +870,7 @@
          *      - It's not ready
          *      - It's running on a JSC.
          */
-        private boolean isReadyToBeCancelledLocked(JobStatus job) {
+        private boolean areJobConstraintsNotSatisfied(JobStatus job) {
             return !job.isReady() && isCurrentlyActiveLocked(job);
         }
 
@@ -846,46 +885,130 @@
                     // If device is idle, we will not schedule jobs to run.
                     return;
                 }
-                Iterator<JobStatus> it = mPendingJobs.iterator();
                 if (DEBUG) {
                     Slog.d(TAG, "pending queue: " + mPendingJobs.size() + " jobs.");
                 }
-                while (it.hasNext()) {
-                    JobStatus nextPending = it.next();
-                    JobServiceContext availableContext = null;
-                    for (int i=0; i<mActiveServices.size(); i++) {
-                        JobServiceContext jsc = mActiveServices.get(i);
-                        final JobStatus running = jsc.getRunningJob();
-                        if (running != null && running.matches(nextPending.getUid(),
-                                nextPending.getJobId())) {
-                            // Already running this job for this uId, skip.
-                            availableContext = null;
-                            break;
-                        }
-                        if (jsc.isAvailable()) {
-                            availableContext = jsc;
-                        }
-                    }
-                    if (availableContext != null) {
-                        if (DEBUG) {
-                            Slog.d(TAG, "About to run job "
-                                    + nextPending.getJob().getService().toString());
-                        }
-                        if (!availableContext.executeRunnableJob(nextPending)) {
-                            if (DEBUG) {
-                                Slog.d(TAG, "Error executing " + nextPending);
-                            }
-                            mJobs.remove(nextPending);
-                        }
-                        it.remove();
-                    }
-                }
+                assignJobsToContextsH();
                 reportActive();
             }
         }
     }
 
     /**
+     * Takes jobs from pending queue and runs them on available contexts.
+     * If no contexts are available, preempts lower priority jobs to
+     * run higher priority ones.
+     * Lock on mJobs before calling this function.
+     */
+    private void assignJobsToContextsH() {
+        if (DEBUG) {
+            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();
+        }
+        if (DEBUG) {
+            Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs initial"));
+        }
+        Iterator<JobStatus> it = mPendingJobs.iterator();
+        while (it.hasNext()) {
+            JobStatus nextPending = it.next();
+
+            // If job is already running, go to next job.
+            int jobRunningContext = findJobContextIdFromMap(nextPending, contextIdToJobMap);
+            if (jobRunningContext != -1) {
+                continue;
+            }
+
+            // 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;
+                }
+                if (job == null) {
+                    // No job on this context, but nextPending can't run here because
+                    // the context has a preferred Uid.
+                    continue;
+                }
+                if (job.getUid() != nextPending.getUid()) {
+                    continue;
+                }
+                if (job.getPriority() >= nextPending.getPriority()) {
+                    continue;
+                }
+                if (minPriority > nextPending.getPriority()) {
+                    minPriority = nextPending.getPriority();
+                    minPriorityContextId = i;
+                }
+            }
+            if (minPriorityContextId != -1) {
+                contextIdToJobMap[minPriorityContextId] = nextPending;
+                act[minPriorityContextId] = true;
+            }
+        }
+        if (DEBUG) {
+            Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs final"));
+        }
+        for (int i=0; i<mActiveServices.size(); i++) {
+            boolean preservePreferredUid = false;
+            if (act[i]) {
+                JobStatus js = mActiveServices.get(i).getRunningJob();
+                if (js != null) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "preempting job: " + mActiveServices.get(i).getRunningJob());
+                    }
+                    // preferredUid will be set to uid of currently running job.
+                    mActiveServices.get(i).preemptExecutingJob();
+                    preservePreferredUid = true;
+                } else {
+                    if (DEBUG) {
+                        Slog.d(TAG, "About to run job on context "
+                                + String.valueOf(i) + ", job: " + contextIdToJobMap[i]);
+                    }
+                    for (int ic=0; ic<mControllers.size(); ic++) {
+                        StateController controller = mControllers.get(ic);
+                        controller.prepareForExecution(contextIdToJobMap[i]);
+                    }
+                    if (!mActiveServices.get(i).executeRunnableJob(contextIdToJobMap[i])) {
+                        Slog.d(TAG, "Error executing " + contextIdToJobMap[i]);
+                    }
+                    mPendingJobs.remove(contextIdToJobMap[i]);
+                }
+            }
+            if (!preservePreferredUid) {
+                mActiveServices.get(i).clearPreferredUid();
+            }
+        }
+    }
+
+    int findJobContextIdFromMap(JobStatus jobStatus, JobStatus[] map) {
+        for (int i=0; i<map.length; i++) {
+            if (map[i] != null && map[i].matches(jobStatus.getUid(), jobStatus.getJobId())) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
      * Binder stub trampoline implementation
      */
     final class JobSchedulerStub extends IJobScheduler.Stub {
@@ -965,6 +1088,25 @@
         }
 
         @Override
+        public int scheduleAsPackage(JobInfo job, String packageName, int userId)
+                throws RemoteException {
+            if (DEBUG) {
+                Slog.d(TAG, "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");
+            }
+            long ident = Binder.clearCallingIdentity();
+            try {
+                return JobSchedulerService.this.scheduleAsPackage(job, uid, packageName, userId);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override
         public List<JobInfo> getAllPendingJobs() throws RemoteException {
             final int uid = Binder.getCallingUid();
 
@@ -1016,6 +1158,31 @@
         }
     };
 
+    private String printContextIdToJobMap(JobStatus[] map, String initial) {
+        StringBuilder s = new StringBuilder(initial + ": ");
+        for (int i=0; i<map.length; i++) {
+            s.append("(")
+                    .append(map[i] == null? -1: map[i].getJobId())
+                    .append(map[i] == null? -1: map[i].getUid())
+                    .append(")" );
+        }
+        return s.toString();
+    }
+
+    private String printPendingQueue() {
+        StringBuilder s = new StringBuilder("Pending queue: ");
+        Iterator<JobStatus> it = mPendingJobs.iterator();
+        while (it.hasNext()) {
+            JobStatus js = it.next();
+            s.append("(")
+                    .append(js.getJob().getId())
+                    .append(", ")
+                    .append(js.getUid())
+                    .append(") ");
+        }
+        return s.toString();
+    }
+
     void dumpInternal(PrintWriter pw) {
         final long now = SystemClock.elapsedRealtime();
         synchronized (mJobs) {
@@ -1029,7 +1196,20 @@
                 ArraySet<JobStatus> jobs = mJobs.getJobs();
                 for (int i=0; i<jobs.size(); i++) {
                     JobStatus job = jobs.valueAt(i);
-                    job.dump(pw, "  ");
+                    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(")");
                 }
             } else {
                 pw.println("  None.");
@@ -1039,15 +1219,12 @@
                 mControllers.get(i).dumpControllerState(pw);
             }
             pw.println();
-            pw.println("Pending:");
-            for (int i=0; i<mPendingJobs.size(); i++) {
-                pw.println(mPendingJobs.get(i).hashCode());
-            }
+            pw.println(printPendingQueue());
             pw.println();
             pw.println("Active jobs:");
             for (int i=0; i<mActiveServices.size(); i++) {
                 JobServiceContext jsc = mActiveServices.get(i);
-                if (jsc.isAvailable()) {
+                if (jsc.getRunningJob() == null) {
                     continue;
                 } else {
                     final long timeout = jsc.getTimeoutElapsed();
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 5376043..b249739 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -24,6 +24,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -59,7 +61,6 @@
  * To mitigate this, tearing down the context removes all messages from the handler, including any
  * tardy {@link #MSG_CANCEL}s. Additionally, we avoid sending duplicate onStopJob()
  * calls to the client after they've specified jobFinished().
- *
  */
 public class JobServiceContext extends IJobCallback.Stub implements ServiceConnection {
     private static final boolean DEBUG = JobSchedulerService.DEBUG;
@@ -95,6 +96,8 @@
     /** Shutdown the job. Used when the client crashes and we can't die gracefully.*/
     private static final int MSG_SHUTDOWN_EXECUTION = 4;
 
+    public static final int NO_PREFERRED_UID = -1;
+
     private final Handler mCallbackHandler;
     /** Make callbacks to {@link JobSchedulerService} to inform on job completion status. */
     private final JobCompletedListener mCompletedListener;
@@ -117,7 +120,8 @@
      * Writes can only be done from the handler thread, or {@link #executeRunnableJob(JobStatus)}.
      */
     private JobStatus mRunningJob;
-    /** Binder to the client service. */
+    /** Used to store next job to run when current job is to be preempted. */
+    private int mPreferredUid;
     IJobService service;
 
     private final Object mLock = new Object();
@@ -138,17 +142,19 @@
 
     @VisibleForTesting
     JobServiceContext(Context context, IBatteryStats batteryStats,
-            JobCompletedListener completedListener, Looper looper) {
+                      JobCompletedListener completedListener, Looper looper) {
         mContext = context;
         mBatteryStats = batteryStats;
         mCallbackHandler = new JobServiceHandler(looper);
         mCompletedListener = completedListener;
         mAvailable = true;
+        mVerb = VERB_FINISHED;
+        mPreferredUid = NO_PREFERRED_UID;
     }
 
     /**
-     * Give a job to this context for execution. Callers must first check {@link #isAvailable()}
-     * to make sure this is a valid context.
+     * Give a job to this context for execution. Callers must first check {@link #getRunningJob()}
+     * and ensure it is null to make sure this is a valid context.
      * @param job The status of the job that we are going to run.
      * @return True if the job is valid and is running. False if the job cannot be executed.
      */
@@ -159,11 +165,24 @@
                 return false;
             }
 
+            mPreferredUid = NO_PREFERRED_UID;
+
             mRunningJob = job;
             final boolean isDeadlineExpired =
                     job.hasDeadlineConstraint() &&
                             (job.getLatestRunTimeElapsed() < SystemClock.elapsedRealtime());
-            mParams = new JobParameters(this, job.getJobId(), job.getExtras(), isDeadlineExpired);
+            Uri[] triggeredUris = null;
+            if (job.changedUris != null) {
+                triggeredUris = new Uri[job.changedUris.size()];
+                job.changedUris.toArray(triggeredUris);
+            }
+            String[] triggeredAuthorities = null;
+            if (job.changedAuthorities != null) {
+                triggeredAuthorities = new String[job.changedAuthorities.size()];
+                job.changedAuthorities.toArray(triggeredAuthorities);
+            }
+            mParams = new JobParameters(this, job.getJobId(), job.getExtras(), isDeadlineExpired,
+                    triggeredUris, triggeredAuthorities);
             mExecutionStartTimeElapsed = SystemClock.elapsedRealtime();
 
             mVerb = VERB_BINDING;
@@ -184,7 +203,7 @@
                 return false;
             }
             try {
-                mBatteryStats.noteJobStart(job.getName(), job.getUid());
+                mBatteryStats.noteJobStart(job.getName(), job.getSourceUid());
             } catch (RemoteException e) {
                 // Whatever.
             }
@@ -206,17 +225,22 @@
     }
 
     /** Called externally when a job that was scheduled for execution should be cancelled. */
-    void cancelExecutingJob() {
-        mCallbackHandler.obtainMessage(MSG_CANCEL).sendToTarget();
+    void cancelExecutingJob(int reason) {
+        mCallbackHandler.obtainMessage(MSG_CANCEL, reason, 0 /* unused */).sendToTarget();
     }
 
-    /**
-     * @return Whether this context is available to handle incoming work.
-     */
-    boolean isAvailable() {
-        synchronized (mLock) {
-            return mAvailable;
-        }
+    void preemptExecutingJob() {
+        Message m = mCallbackHandler.obtainMessage(MSG_CANCEL);
+        m.arg1 = JobParameters.REASON_PREEMPT;
+        m.sendToTarget();
+    }
+
+    int getPreferredUid() {
+        return mPreferredUid;
+    }
+
+    void clearPreferredUid() {
+        mPreferredUid = NO_PREFERRED_UID;
     }
 
     long getExecutionStartTimeElapsed() {
@@ -277,7 +301,7 @@
         final PowerManager pm =
                 (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, runningJob.getTag());
-        mWakeLock.setWorkSource(new WorkSource(runningJob.getUid()));
+        mWakeLock.setWorkSource(new WorkSource(runningJob.getSourceUid()));
         mWakeLock.setReferenceCounted(false);
         mWakeLock.acquire();
         mCallbackHandler.obtainMessage(MSG_SERVICE_BOUND).sendToTarget();
@@ -344,6 +368,11 @@
                     }
                     break;
                 case MSG_CANCEL:
+                    mParams.setStopReason(message.arg1);
+                    if (message.arg1 == JobParameters.REASON_PREEMPT) {
+                        mPreferredUid = mRunningJob != null ? mRunningJob.getUid() :
+                                NO_PREFERRED_UID;
+                    }
                     handleCancelH();
                     break;
                 case MSG_TIMEOUT:
@@ -481,6 +510,7 @@
 
         /** 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() +
@@ -549,7 +579,7 @@
                 }
                 completedJob = mRunningJob;
                 try {
-                    mBatteryStats.noteJobFinish(mRunningJob.getName(), mRunningJob.getUid());
+                    mBatteryStats.noteJobFinish(mRunningJob.getName(), 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 d9f94d0..f796164 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -46,6 +46,7 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -186,9 +187,8 @@
      */
     public List<JobStatus> getJobsByUser(int userHandle) {
         List<JobStatus> matchingJobs = new ArrayList<JobStatus>();
-        Iterator<JobStatus> it = mJobSet.iterator();
-        while (it.hasNext()) {
-            JobStatus ts = it.next();
+        for (int i=mJobSet.size()-1; i>=0; i--) {
+            JobStatus ts = mJobSet.valueAt(i);
             if (UserHandle.getUserId(ts.getUid()) == userHandle) {
                 matchingJobs.add(ts);
             }
@@ -202,9 +202,8 @@
      */
     public List<JobStatus> getJobsByUid(int uid) {
         List<JobStatus> matchingJobs = new ArrayList<JobStatus>();
-        Iterator<JobStatus> it = mJobSet.iterator();
-        while (it.hasNext()) {
-            JobStatus ts = it.next();
+        for (int i=mJobSet.size()-1; i>=0; i--) {
+            JobStatus ts = mJobSet.valueAt(i);
             if (ts.getUid() == uid) {
                 matchingJobs.add(ts);
             }
@@ -218,9 +217,8 @@
      * @return the JobStatus that matches the provided uId and jobId, or null if none found.
      */
     public JobStatus getJobByUidAndJobId(int uid, int jobId) {
-        Iterator<JobStatus> it = mJobSet.iterator();
-        while (it.hasNext()) {
-            JobStatus ts = it.next();
+        for (int i=mJobSet.size()-1; i>=0; i--) {
+            JobStatus ts = mJobSet.valueAt(i);
             if (ts.getUid() == uid && ts.getJobId() == jobId) {
                 return ts;
             }
@@ -311,7 +309,7 @@
                         Slog.d(TAG, "Saving job " + jobStatus.getJobId());
                     }
                     out.startTag(null, "job");
-                    addIdentifierAttributesToJobTag(out, jobStatus);
+                    addAttributesToJobTag(out, jobStatus);
                     writeConstraintsToXml(out, jobStatus);
                     writeExecutionCriteriaToXml(out, jobStatus);
                     writeBundleToXml(jobStatus.getExtras(), out);
@@ -336,21 +334,46 @@
             }
         }
 
-        /** Write out a tag with data comprising the required fields of this job and its client. */
-        private void addIdentifierAttributesToJobTag(XmlSerializer out, JobStatus jobStatus)
+        /** Write out a tag with data comprising the required fields and priority of this job and
+         * its client.
+         */
+        private void addAttributesToJobTag(XmlSerializer out, JobStatus jobStatus)
                 throws IOException {
             out.attribute(null, "jobid", Integer.toString(jobStatus.getJobId()));
             out.attribute(null, "package", jobStatus.getServiceComponent().getPackageName());
             out.attribute(null, "class", jobStatus.getServiceComponent().getClassName());
+            if (jobStatus.getSourcePackageName() != null) {
+                out.attribute(null, "sourcePackageName", jobStatus.getSourcePackageName());
+            }
+            out.attribute(null, "sourceUserId", String.valueOf(jobStatus.getSourceUserId()));
             out.attribute(null, "uid", Integer.toString(jobStatus.getUid()));
+            out.attribute(null, "priority", String.valueOf(jobStatus.getPriority()));
         }
 
         private void writeBundleToXml(PersistableBundle extras, XmlSerializer out)
                 throws IOException, XmlPullParserException {
             out.startTag(null, XML_TAG_EXTRAS);
-            extras.saveToXml(out);
+            PersistableBundle extrasCopy = deepCopyBundle(extras, 10);
+            extrasCopy.saveToXml(out);
             out.endTag(null, XML_TAG_EXTRAS);
         }
+
+        private PersistableBundle deepCopyBundle(PersistableBundle bundle, int maxDepth) {
+            if (maxDepth <= 0) {
+                return null;
+            }
+            PersistableBundle copy = (PersistableBundle) bundle.clone();
+            Set<String> keySet = bundle.keySet();
+            for (String key: keySet) {
+                Object o = copy.get(key);
+                if (o instanceof PersistableBundle) {
+                    PersistableBundle bCopy = deepCopyBundle((PersistableBundle) o, maxDepth-1);
+                    copy.putPersistableBundle(key, bCopy);
+                }
+            }
+            return copy;
+        }
+
         /**
          * Write out a tag with data identifying this job's constraints. If the constraint isn't here
          * it doesn't apply.
@@ -378,6 +401,7 @@
             if (jobStatus.getJob().isPeriodic()) {
                 out.startTag(null, XML_TAG_PERIODIC);
                 out.attribute(null, "period", Long.toString(job.getIntervalMillis()));
+                out.attribute(null, "flex", Long.toString(job.getFlexMillis()));
             } else {
                 out.startTag(null, XML_TAG_ONEOFF);
             }
@@ -519,18 +543,27 @@
         private JobStatus restoreJobFromXml(XmlPullParser parser) throws XmlPullParserException,
                 IOException {
             JobInfo.Builder jobBuilder;
-            int uid;
+            int uid, userId;
 
-            // Read out job identifier attributes.
+            // Read out job identifier attributes and priority.
             try {
                 jobBuilder = buildBuilderFromXml(parser);
                 jobBuilder.setPersisted(true);
                 uid = Integer.valueOf(parser.getAttributeValue(null, "uid"));
+
+                String val = parser.getAttributeValue(null, "priority");
+                if (val != null) {
+                    jobBuilder.setPriority(Integer.valueOf(val));
+                }
+                val = parser.getAttributeValue(null, "sourceUserId");
+                userId = val == null ? -1 : Integer.valueOf(val);
             } catch (NumberFormatException e) {
                 Slog.e(TAG, "Error parsing job's required fields, skipping");
                 return null;
             }
 
+            final String sourcePackageName = parser.getAttributeValue(null, "sourcePackageName");
+
             int eventType;
             // Read out constraints tag.
             do {
@@ -575,13 +608,17 @@
                     String val = parser.getAttributeValue(null, "period");
                     final long periodMillis = Long.valueOf(val);
                     jobBuilder.setPeriodic(periodMillis);
-                    // As a sanity check, cap the recreated run time to be no later than 2 periods
+                    val = parser.getAttributeValue(null, "flex");
+                    final long flexMillis = (val != null) ? Long.valueOf(val) : periodMillis;
+                    // As a sanity check, cap the recreated run time to be no later than flex+period
                     // from now. This is the latest the periodic could be pushed out. This could
-                    // happen if the periodic ran early (at the start of its period), and then the
+                    // happen if the periodic ran early (at flex time before period), and then the
                     // device rebooted.
-                    if (elapsedRuntimes.second > elapsedNow + 2 * periodMillis) {
-                        final long clampedEarlyRuntimeElapsed = elapsedNow + periodMillis;
-                        final long clampedLateRuntimeElapsed = elapsedNow + 2 * periodMillis;
+                    if (elapsedRuntimes.second > elapsedNow + periodMillis + flexMillis) {
+                        final long clampedLateRuntimeElapsed = elapsedNow + flexMillis
+                                + periodMillis;
+                        final long clampedEarlyRuntimeElapsed = clampedLateRuntimeElapsed
+                                - flexMillis;
                         Slog.w(TAG,
                                 String.format("Periodic job for uid='%d' persisted run-time is" +
                                                 " too big [%s, %s]. Clamping to [%s,%s]",
@@ -640,8 +677,12 @@
             jobBuilder.setExtras(extras);
             parser.nextTag(); // Consume </extras>
 
-            return new JobStatus(
+            JobStatus js = new JobStatus(
                     jobBuilder.build(), uid, elapsedRuntimes.first, elapsedRuntimes.second);
+            if (userId != -1) {
+                js.setSource(sourcePackageName, userId);
+            }
+            return js;
         }
 
         private JobInfo.Builder buildBuilderFromXml(XmlPullParser parser) throws NumberFormatException {
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 6fc02f6..5f3da75 100644
--- a/services/core/java/com/android/server/job/controllers/AppIdleController.java
+++ b/services/core/java/com/android/server/job/controllers/AppIdleController.java
@@ -62,12 +62,12 @@
     }
 
     @Override
-    public void maybeStartTrackingJob(JobStatus jobStatus) {
+    public void maybeStartTrackingJob(JobStatus jobStatus, JobStatus lastJob) {
         synchronized (mTrackedTasks) {
             mTrackedTasks.add(jobStatus);
-            String packageName = jobStatus.job.getService().getPackageName();
+            String packageName = jobStatus.getSourcePackageName();
             final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
-                    jobStatus.uId, jobStatus.getUserId());
+                    jobStatus.getSourceUid(), jobStatus.getSourceUserId());
             if (DEBUG) {
                 Slog.d(LOG_TAG, "Start tracking, setting idle state of "
                         + packageName + " to " + appIdle);
@@ -77,7 +77,7 @@
     }
 
     @Override
-    public void maybeStopTrackingJob(JobStatus jobStatus) {
+    public void maybeStopTrackingJob(JobStatus jobStatus, boolean forUpdate) {
         synchronized (mTrackedTasks) {
             mTrackedTasks.remove(jobStatus);
         }
@@ -89,7 +89,7 @@
         pw.println("Parole On: " + mAppIdleParoleOn);
         synchronized (mTrackedTasks) {
             for (JobStatus task : mTrackedTasks) {
-                pw.print(task.job.getService().getPackageName());
+                pw.print(task.getSourcePackageName());
                 pw.print(":idle=" + !task.appNotIdleConstraintSatisfied.get());
                 pw.print(", ");
             }
@@ -106,9 +106,9 @@
             }
             mAppIdleParoleOn = isAppIdleParoleOn;
             for (JobStatus task : mTrackedTasks) {
-                String packageName = task.job.getService().getPackageName();
+                String packageName = task.getSourcePackageName();
                 final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
-                        task.uId, task.getUserId());
+                        task.getSourceUid(), task.getSourceUserId());
                 if (DEBUG) {
                     Slog.d(LOG_TAG, "Setting idle state of " + packageName + " to " + appIdle);
                 }
@@ -133,8 +133,8 @@
                     return;
                 }
                 for (JobStatus task : mTrackedTasks) {
-                    if (task.job.getService().getPackageName().equals(packageName)
-                            && task.getUserId() == userId) {
+                    if (task.getSourcePackageName().equals(packageName)
+                            && task.getSourceUserId() == userId) {
                         if (task.appNotIdleConstraintSatisfied.get() != !idle) {
                             if (DEBUG) {
                                 Slog.d(LOG_TAG, "App Idle state changed, setting idle state of "
diff --git a/services/core/java/com/android/server/job/controllers/BatteryController.java b/services/core/java/com/android/server/job/controllers/BatteryController.java
index 7c2aead..b322a3e 100644
--- a/services/core/java/com/android/server/job/controllers/BatteryController.java
+++ b/services/core/java/com/android/server/job/controllers/BatteryController.java
@@ -16,8 +16,6 @@
 
 package com.android.server.job.controllers;
 
-import android.app.AlarmManager;
-import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -79,7 +77,7 @@
     }
 
     @Override
-    public void maybeStartTrackingJob(JobStatus taskStatus) {
+    public void maybeStartTrackingJob(JobStatus taskStatus, JobStatus lastJob) {
         final boolean isOnStablePower = mChargeTracker.isOnStablePower();
         if (taskStatus.hasChargingConstraint()) {
             synchronized (mTrackedTasks) {
@@ -90,7 +88,7 @@
     }
 
     @Override
-    public void maybeStopTrackingJob(JobStatus taskStatus) {
+    public void maybeStopTrackingJob(JobStatus taskStatus, boolean forUpdate) {
         if (taskStatus.hasChargingConstraint()) {
             synchronized (mTrackedTasks) {
                 mTrackedTasks.remove(taskStatus);
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 daba0d9..b84658a 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -82,7 +82,7 @@
     }
 
     @Override
-    public void maybeStartTrackingJob(JobStatus jobStatus) {
+    public void maybeStartTrackingJob(JobStatus jobStatus, JobStatus lastJob) {
         if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
             synchronized (mTrackedJobs) {
                 jobStatus.connectivityConstraintSatisfied.set(mNetworkConnected);
@@ -93,7 +93,7 @@
     }
 
     @Override
-    public void maybeStopTrackingJob(JobStatus jobStatus) {
+    public void maybeStopTrackingJob(JobStatus jobStatus, boolean forUpdate) {
         if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
             synchronized (mTrackedJobs) {
                 mTrackedJobs.remove(jobStatus);
diff --git a/services/core/java/com/android/server/job/controllers/ContentObserverController.java b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
new file mode 100644
index 0000000..212cc94
--- /dev/null
+++ b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.job.controllers;
+
+import android.app.job.JobInfo;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateChangedListener;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Controller for monitoring changes to content URIs through a ContentObserver.
+ */
+public class ContentObserverController extends StateController {
+    private static final String TAG = "JobScheduler.Content";
+
+    /**
+     * Maximum number of changing URIs we will batch together to report.
+     * XXX Should be smarter about this, restricting it by the maximum number
+     * of characters we will retain.
+     */
+    private static final int MAX_URIS_REPORTED = 50;
+
+    private static final Object sCreationLock = new Object();
+    private static volatile ContentObserverController sController;
+
+    final private List<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
+    ArrayMap<Uri, ObserverInstance> mObservers = new ArrayMap<>();
+    final Handler mHandler = new Handler();
+
+    public static ContentObserverController get(JobSchedulerService taskManagerService) {
+        synchronized (sCreationLock) {
+            if (sController == null) {
+                sController = new ContentObserverController(taskManagerService,
+                        taskManagerService.getContext());
+            }
+        }
+        return sController;
+    }
+
+    @VisibleForTesting
+    public static ContentObserverController getForTesting(StateChangedListener stateChangedListener,
+                                           Context context) {
+        return new ContentObserverController(stateChangedListener, context);
+    }
+
+    private ContentObserverController(StateChangedListener stateChangedListener, Context context) {
+        super(stateChangedListener, context);
+    }
+
+    @Override
+    public void maybeStartTrackingJob(JobStatus taskStatus, JobStatus lastJob) {
+        if (taskStatus.hasContentTriggerConstraint()) {
+            synchronized (mTrackedTasks) {
+                if (taskStatus.contentObserverJobInstance == null) {
+                    taskStatus.contentObserverJobInstance = new JobInstance(taskStatus);
+                }
+                mTrackedTasks.add(taskStatus);
+                boolean havePendingUris = false;
+                // If there is a previous job associated with the new job, propagate over
+                // any pending content URI trigger reports.
+                if (lastJob != null && lastJob.contentObserverJobInstance != null
+                        && lastJob.contentObserverJobInstance
+                        != taskStatus.contentObserverJobInstance
+                        && lastJob.contentObserverJobInstance.mChangedAuthorities != null) {
+                    havePendingUris = true;
+                    taskStatus.contentObserverJobInstance.mChangedAuthorities
+                            = lastJob.contentObserverJobInstance.mChangedAuthorities;
+                    taskStatus.contentObserverJobInstance.mChangedUris
+                            = lastJob.contentObserverJobInstance.mChangedUris;
+                    lastJob.contentObserverJobInstance.mChangedAuthorities = null;
+                    lastJob.contentObserverJobInstance.mChangedUris = null;
+                }
+                // If we have previously reported changed authorities/uris, then we failed
+                // to complete the job with them so will re-record them to report again.
+                if (taskStatus.changedAuthorities != null) {
+                    havePendingUris = true;
+                    if (taskStatus.contentObserverJobInstance.mChangedAuthorities == null) {
+                        taskStatus.contentObserverJobInstance.mChangedAuthorities
+                                = new ArraySet<>();
+                    }
+                    for (String auth : taskStatus.changedAuthorities) {
+                        taskStatus.contentObserverJobInstance.mChangedAuthorities.add(auth);
+                    }
+                    if (taskStatus.changedUris != null) {
+                        if (taskStatus.contentObserverJobInstance.mChangedUris == null) {
+                            taskStatus.contentObserverJobInstance.mChangedUris = new ArraySet<>();
+                        }
+                        for (Uri uri : taskStatus.changedUris) {
+                            taskStatus.contentObserverJobInstance.mChangedUris.add(uri);
+                        }
+                    }
+                    taskStatus.changedAuthorities = null;
+                    taskStatus.changedUris = null;
+                }
+                taskStatus.changedAuthorities = null;
+                taskStatus.changedUris = null;
+                taskStatus.contentTriggerConstraintSatisfied.set(havePendingUris);
+            }
+        }
+    }
+
+    @Override
+    public void prepareForExecution(JobStatus taskStatus) {
+        if (taskStatus.hasContentTriggerConstraint()) {
+            synchronized (mTrackedTasks) {
+                if (taskStatus.contentObserverJobInstance != null) {
+                    taskStatus.changedUris = taskStatus.contentObserverJobInstance.mChangedUris;
+                    taskStatus.changedAuthorities
+                            = taskStatus.contentObserverJobInstance.mChangedAuthorities;
+                    taskStatus.contentObserverJobInstance.mChangedUris = null;
+                    taskStatus.contentObserverJobInstance.mChangedAuthorities = null;
+                }
+            }
+        }
+    }
+
+    @Override
+    public void maybeStopTrackingJob(JobStatus taskStatus, boolean forUpdate) {
+        if (taskStatus.hasContentTriggerConstraint()) {
+            synchronized (mTrackedTasks) {
+                if (!forUpdate) {
+                    // We won't do this reset if being called for an update, because
+                    // we know it will be immediately followed by maybeStartTrackingJob...
+                    // and we don't want to lose any content changes in-between.
+                    if (taskStatus.contentObserverJobInstance != null) {
+                        taskStatus.contentObserverJobInstance.detach();
+                        taskStatus.contentObserverJobInstance = null;
+                    }
+                }
+                mTrackedTasks.remove(taskStatus);
+            }
+        }
+    }
+
+    @Override
+    public void rescheduleForFailure(JobStatus newJob, JobStatus failureToReschedule) {
+        if (failureToReschedule.hasContentTriggerConstraint()
+                && newJob.hasContentTriggerConstraint()) {
+            synchronized (mTrackedTasks) {
+                // Our job has failed, and we are scheduling a new job for it.
+                // Copy the last reported content changes in to the new job, so when
+                // we schedule the new one we will pick them up and report them again.
+                newJob.changedAuthorities = failureToReschedule.changedAuthorities;
+                newJob.changedUris = failureToReschedule.changedUris;
+            }
+        }
+    }
+
+    class ObserverInstance extends ContentObserver {
+        final Uri mUri;
+        final ArrayList<JobInstance> mJobs = new ArrayList<>();
+
+        public ObserverInstance(Handler handler, Uri uri) {
+            super(handler);
+            mUri = uri;
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            boolean reportChange = false;
+            synchronized (mTrackedTasks) {
+                final int N = mJobs.size();
+                for (int i=0; i<N; i++) {
+                    JobInstance inst = mJobs.get(i);
+                    if (inst.mChangedUris == null) {
+                        inst.mChangedUris = new ArraySet<>();
+                    }
+                    if (inst.mChangedUris.size() < MAX_URIS_REPORTED) {
+                        inst.mChangedUris.add(uri);
+                    }
+                    if (inst.mChangedAuthorities == null) {
+                        inst.mChangedAuthorities = new ArraySet<>();
+                    }
+                    inst.mChangedAuthorities.add(uri.getAuthority());
+                    boolean previous
+                            = inst.mJobStatus.contentTriggerConstraintSatisfied.getAndSet(true);
+                    if (!previous) {
+                        reportChange = true;
+                    }
+                }
+            }
+            // Let the scheduler know that state has changed. This may or may not result in an
+            // execution.
+            if (reportChange) {
+                mStateChangedListener.onControllerStateChanged();
+            }
+        }
+    }
+
+    class JobInstance extends ArrayList<ObserverInstance> {
+        private final JobStatus mJobStatus;
+        private ArraySet<Uri> mChangedUris;
+        private ArraySet<String> mChangedAuthorities;
+
+        JobInstance(JobStatus jobStatus) {
+            mJobStatus = jobStatus;
+            final JobInfo.TriggerContentUri[] uris = jobStatus.getJob().getTriggerContentUris();
+            if (uris != null) {
+                for (JobInfo.TriggerContentUri uri : uris) {
+                    ObserverInstance obs = mObservers.get(uri.getUri());
+                    if (obs == null) {
+                        obs = new ObserverInstance(mHandler, uri.getUri());
+                        mObservers.put(uri.getUri(), obs);
+                        mContext.getContentResolver().registerContentObserver(
+                                uri.getUri(),
+                                (uri.getFlags() &
+                                        JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS)
+                                    != 0,
+                                obs);
+                    }
+                    obs.mJobs.add(this);
+                    add(obs);
+                }
+            }
+        }
+
+        void detach() {
+            final int N = size();
+            for (int i=0; i<N; i++) {
+                final ObserverInstance obs = get(i);
+                obs.mJobs.remove(this);
+                if (obs.mJobs.size() == 0) {
+                    mContext.getContentResolver().unregisterContentObserver(obs);
+                    mObservers.remove(obs.mUri);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void dumpControllerState(PrintWriter pw) {
+        pw.println("Content.");
+        synchronized (mTrackedTasks) {
+            Iterator<JobStatus> it = mTrackedTasks.iterator();
+            if (it.hasNext()) {
+                pw.print(String.valueOf(it.next().hashCode()));
+            }
+            while (it.hasNext()) {
+                pw.print("," + String.valueOf(it.next().hashCode()));
+            }
+            pw.println();
+            int N = mObservers.size();
+            if (N > 0) {
+                pw.println("URIs:");
+                for (int i = 0; i < N; i++) {
+                    ObserverInstance obs = mObservers.valueAt(i);
+                    pw.print("  ");
+                    pw.print(mObservers.keyAt(i));
+                    pw.println(":");
+                    pw.print("    ");
+                    pw.println(obs);
+                    pw.println("    Jobs:");
+                    int M = obs.mJobs.size();
+                    for (int j=0; j<M; j++) {
+                        JobInstance inst = obs.mJobs.get(j);
+                        pw.print("      ");
+                        pw.print(inst.hashCode());
+                        if (inst.mChangedAuthorities != null) {
+                            pw.println(":");
+                            pw.println("        Changed Authorities:");
+                            for (int k=0; k<inst.mChangedAuthorities.size(); k++) {
+                                pw.print("          ");
+                                pw.println(inst.mChangedAuthorities.valueAt(k));
+                            }
+                            if (inst.mChangedUris != null) {
+                                pw.println("        Changed URIs:");
+                                for (int k = 0; k<inst.mChangedUris.size(); k++) {
+                                    pw.print("          ");
+                                    pw.println(inst.mChangedUris.valueAt(k));
+                                }
+                            }
+                        } else {
+                            pw.println();
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
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 92df851..9f4cdef 100644
--- a/services/core/java/com/android/server/job/controllers/IdleController.java
+++ b/services/core/java/com/android/server/job/controllers/IdleController.java
@@ -34,14 +34,13 @@
 public class IdleController extends StateController {
     private static final String TAG = "IdleController";
 
-    // Policy: we decide that we're "idle" if the device has been unused /
-    // screen off or dreaming for at least this long
-    private static final long INACTIVITY_IDLE_THRESHOLD = 71 * 60 * 1000; // millis; 71 min
-    private static final long IDLE_WINDOW_SLOP = 5 * 60 * 1000; // 5 minute window, to be nice
-
     private static final String ACTION_TRIGGER_IDLE =
             "com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE";
 
+    // Policy: we decide that we're "idle" if the device has been unused /
+    // screen off or dreaming for at least this long
+    private long mInactivityIdleThreshold;
+    private long mIdleWindowSlop;
     final ArrayList<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
     IdlenessTracker mIdleTracker;
 
@@ -67,7 +66,7 @@
      * StateController interface
      */
     @Override
-    public void maybeStartTrackingJob(JobStatus taskStatus) {
+    public void maybeStartTrackingJob(JobStatus taskStatus, JobStatus lastJob) {
         if (taskStatus.hasIdleConstraint()) {
             synchronized (mTrackedTasks) {
                 mTrackedTasks.add(taskStatus);
@@ -77,7 +76,7 @@
     }
 
     @Override
-    public void maybeStopTrackingJob(JobStatus taskStatus) {
+    public void maybeStopTrackingJob(JobStatus taskStatus, boolean forUpdate) {
         synchronized (mTrackedTasks) {
             mTrackedTasks.remove(taskStatus);
         }
@@ -100,6 +99,10 @@
      * significant state changes occur
      */
     private void initIdleStateTracking() {
+        mInactivityIdleThreshold = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_jobSchedulerInactivityIdleThreshold);
+        mIdleWindowSlop = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_jobSchedulerIdleWindowSlop);
         mIdleTracker = new IdlenessTracker();
         mIdleTracker.startTracking();
     }
@@ -168,14 +171,14 @@
                 // alarm that will tell us when we have decided the device is
                 // truly idle.
                 final long nowElapsed = SystemClock.elapsedRealtime();
-                final long when = nowElapsed + INACTIVITY_IDLE_THRESHOLD;
+                final long when = nowElapsed + mInactivityIdleThreshold;
                 if (DEBUG) {
                     Slog.v(TAG, "Scheduling idle : " + action + " now:" + nowElapsed + " when="
                             + when);
                 }
                 mScreenOn = false;
                 mAlarm.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                        when, IDLE_WINDOW_SLOP, mIdleTriggerIntent);
+                        when, mIdleWindowSlop, mIdleTriggerIntent);
             } else if (action.equals(ACTION_TRIGGER_IDLE)) {
                 // idle time starts now. Do not set mIdle if screen is on.
                 if (!mIdle && !mScreenOn) {
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 c02611f..4113180 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -16,12 +16,17 @@
 
 package com.android.server.job.controllers;
 
+import android.app.AppGlobals;
 import android.app.job.JobInfo;
 import android.content.ComponentName;
+import android.net.Uri;
 import android.os.PersistableBundle;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.text.format.DateUtils;
+import android.util.ArraySet;
+import android.util.TimeUtils;
 
 import java.io.PrintWriter;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -47,6 +52,10 @@
     final String name;
     final String tag;
 
+    String sourcePackageName;
+    int sourceUserId = -1;
+    int sourceUid = -1;
+
     // Constraints.
     final AtomicBoolean chargingConstraintSatisfied = new AtomicBoolean();
     final AtomicBoolean timeDelayConstraintSatisfied = new AtomicBoolean();
@@ -55,6 +64,17 @@
     final AtomicBoolean unmeteredConstraintSatisfied = new AtomicBoolean();
     final AtomicBoolean connectivityConstraintSatisfied = new AtomicBoolean();
     final AtomicBoolean appNotIdleConstraintSatisfied = new AtomicBoolean();
+    final AtomicBoolean contentTriggerConstraintSatisfied = new AtomicBoolean();
+
+    // These are filled in by controllers when preparing for execution.
+    public ArraySet<Uri> changedUris;
+    public ArraySet<String> changedAuthorities;
+
+    /**
+     * For use only by ContentObserverController: state it is maintaining about content URIs
+     * being observed.
+     */
+    ContentObserverController.JobInstance contentObserverJobInstance;
 
     /**
      * Earliest point in the future at which this job will be eligible to run. A value of 0
@@ -77,6 +97,7 @@
     private JobStatus(JobInfo job, int uId, int numFailures) {
         this.job = job;
         this.uId = uId;
+        this.sourceUid = uId;
         this.name = job.getService().flattenToShortString();
         this.tag = "*job*/" + this.name;
         this.numFailures = numFailures;
@@ -85,6 +106,8 @@
     /** Copy constructor. */
     public JobStatus(JobStatus jobStatus) {
         this(jobStatus.getJob(), jobStatus.getUid(), jobStatus.getNumFailures());
+        this.sourceUserId = jobStatus.sourceUserId;
+        this.sourcePackageName = jobStatus.sourcePackageName;
         this.earliestRunTimeElapsedMillis = jobStatus.getEarliestRunTime();
         this.latestRunTimeElapsedMillis = jobStatus.getLatestRunTimeElapsed();
     }
@@ -96,8 +119,8 @@
         final long elapsedNow = SystemClock.elapsedRealtime();
 
         if (job.isPeriodic()) {
-            earliestRunTimeElapsedMillis = elapsedNow;
             latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis();
+            earliestRunTimeElapsedMillis = latestRunTimeElapsedMillis - job.getFlexMillis();
         } else {
             earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ?
                     elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
@@ -125,6 +148,8 @@
     public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis,
                       long newLatestRuntimeElapsedMillis, int backoffAttempt) {
         this(rescheduling.job, rescheduling.getUid(), backoffAttempt);
+        this.sourceUserId = rescheduling.sourceUserId;
+        this.sourcePackageName = rescheduling.sourcePackageName;
 
         earliestRunTimeElapsedMillis = newEarliestRuntimeElapsedMillis;
         latestRunTimeElapsedMillis = newLatestRuntimeElapsedMillis;
@@ -146,6 +171,21 @@
         return job.getService();
     }
 
+    public String getSourcePackageName() {
+        return sourcePackageName != null ? sourcePackageName : job.getService().getPackageName();
+    }
+
+    public int getSourceUid() {
+        return sourceUid;
+    }
+
+    public int getSourceUserId() {
+        if (sourceUserId == -1) {
+            sourceUserId = getUserId();
+        }
+        return sourceUserId;
+    }
+
     public int getUserId() {
         return UserHandle.getUserId(uId);
     }
@@ -166,6 +206,10 @@
         return job.getExtras();
     }
 
+    public int getPriority() {
+        return job.getPriority();
+    }
+
     public boolean hasConnectivityConstraint() {
         return job.getNetworkType() == JobInfo.NETWORK_TYPE_ANY;
     }
@@ -190,6 +234,10 @@
         return job.isRequireDeviceIdle();
     }
 
+    public boolean hasContentTriggerConstraint() {
+        return job.getTriggerContentUris() != null;
+    }
+
     public boolean isPersisted() {
         return job.isPersisted();
     }
@@ -222,7 +270,8 @@
                 && (!hasTimingDelayConstraint() || timeDelayConstraintSatisfied.get())
                 && (!hasConnectivityConstraint() || connectivityConstraintSatisfied.get())
                 && (!hasUnmeteredConstraint() || unmeteredConstraintSatisfied.get())
-                && (!hasIdleConstraint() || idleConstraintSatisfied.get());
+                && (!hasIdleConstraint() || idleConstraintSatisfied.get())
+                && (!hasContentTriggerConstraint() || contentTriggerConstraintSatisfied.get());
     }
 
     public boolean matches(int uid, int jobId) {
@@ -238,8 +287,9 @@
                 + ",R=(" + formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME)
                 + "," + formatRunTime(latestRunTimeElapsedMillis, NO_LATEST_RUNTIME) + ")"
                 + ",N=" + job.getNetworkType() + ",C=" + job.isRequireCharging()
-                + ",I=" + job.isRequireDeviceIdle() + ",F=" + numFailures
-                + ",P=" + job.isPersisted()
+                + ",I=" + job.isRequireDeviceIdle()
+                + ",U=" + (job.getTriggerContentUris() != null)
+                + ",F=" + numFailures + ",P=" + job.isPersisted()
                 + ",ANI=" + appNotIdleConstraintSatisfied.get()
                 + (isReady() ? "(READY)" : "")
                 + "]";
@@ -259,18 +309,153 @@
         }
     }
 
+    public void setSource(String sourcePackageName, int sourceUserId) {
+        this.sourcePackageName = sourcePackageName;
+        this.sourceUserId = sourceUserId;
+        try {
+            sourceUid = AppGlobals.getPackageManager().getPackageUid(sourcePackageName, 0,
+                    sourceUserId);
+        } catch (RemoteException ex) {
+            // Can't happen, PackageManager runs in the same process.
+        }
+        if (sourceUid == -1) {
+            sourceUid = uId;
+            this.sourceUserId = getUserId();
+            this.sourcePackageName = null;
+        }
+    }
+
     /**
      * Convenience function to identify a job uniquely without pulling all the data that
      * {@link #toString()} returns.
      */
     public String toShortString() {
-        return job.getService().flattenToShortString() + " jId=" + job.getId() +
-                ", u" + getUserId();
+        StringBuilder sb = new StringBuilder();
+        sb.append(Integer.toHexString(System.identityHashCode(this)));
+        sb.append(" jId=");
+        sb.append(job.getId());
+        sb.append(" uid=");
+        UserHandle.formatUid(sb, uId);
+        sb.append(' ');
+        sb.append(job.getService().flattenToShortString());
+        return sb.toString();
     }
 
     // Dumpsys infrastructure
     public void dump(PrintWriter pw, String prefix) {
+        pw.print(prefix); UserHandle.formatUid(pw, uId);
+        pw.print(" tag="); pw.println(tag);
         pw.print(prefix);
-        pw.println(this.toString());
+        pw.print("Source: uid="); UserHandle.formatUid(pw, sourceUid);
+        pw.print(" user="); pw.print(sourceUserId);
+        pw.print(" pkg="); pw.println(sourcePackageName);
+        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 (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.hasEarlyConstraint()) {
+            pw.print(prefix); pw.println("  Has early constraint");
+        }
+        if (job.hasLateConstraint()) {
+            pw.print(prefix); pw.println("  Has late constraint");
+        }
+        pw.print(prefix); pw.println("Constraints:");
+        if (hasChargingConstraint()) {
+            pw.print(prefix); pw.print("  Charging: ");
+            pw.println(chargingConstraintSatisfied.get());
+        }
+        if (hasTimingDelayConstraint()) {
+            pw.print(prefix); pw.print("  Time delay: ");
+            pw.println(timeDelayConstraintSatisfied.get());
+        }
+        if (hasDeadlineConstraint()) {
+            pw.print(prefix); pw.print("  Deadline: ");
+            pw.println(deadlineConstraintSatisfied.get());
+        }
+        if (hasIdleConstraint()) {
+            pw.print(prefix); pw.print("  System idle: ");
+            pw.println(idleConstraintSatisfied.get());
+        }
+        if (hasUnmeteredConstraint()) {
+            pw.print(prefix); pw.print("  Unmetered: ");
+            pw.println(unmeteredConstraintSatisfied.get());
+        }
+        if (hasConnectivityConstraint()) {
+            pw.print(prefix); pw.print("  Connectivity: ");
+            pw.println(connectivityConstraintSatisfied.get());
+        }
+        if (hasIdleConstraint()) {
+            pw.print(prefix); pw.print("  App not idle: ");
+            pw.println(appNotIdleConstraintSatisfied.get());
+        }
+        if (hasContentTriggerConstraint()) {
+            pw.print(prefix); pw.print("  Content trigger: ");
+            pw.println(contentTriggerConstraintSatisfied.get());
+        }
+        if (changedAuthorities != null) {
+            pw.print(prefix); pw.println("Changed authorities:");
+            for (int i=0; i<changedAuthorities.size(); i++) {
+                pw.print(prefix); pw.print("  "); pw.println(changedAuthorities.valueAt(i));
+            }
+            if (changedUris != null) {
+                pw.print(prefix); pw.println("Changed URIs:");
+                for (int i=0; i<changedUris.size(); i++) {
+                    pw.print(prefix); pw.print("  "); pw.println(changedUris.valueAt(i));
+                }
+            }
+        }
+        pw.print(prefix); pw.print("Earliest run time: ");
+        pw.println(formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME));
+        pw.print(prefix); pw.print("Latest run time: ");
+        pw.println(formatRunTime(latestRunTimeElapsedMillis, NO_LATEST_RUNTIME));
+        if (numFailures != 0) {
+            pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures);
+        }
     }
 }
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 21c30c7..b619ea8 100644
--- a/services/core/java/com/android/server/job/controllers/StateController.java
+++ b/services/core/java/com/android/server/job/controllers/StateController.java
@@ -49,11 +49,21 @@
      * Also called when updating a task, so implementing controllers have to be aware of
      * preexisting tasks.
      */
-    public abstract void maybeStartTrackingJob(JobStatus jobStatus);
+    public abstract void maybeStartTrackingJob(JobStatus jobStatus, JobStatus lastJob);
+    /**
+     * Optionally implement logic here to prepare the job to be executed.
+     */
+    public void prepareForExecution(JobStatus jobStatus) {
+    }
     /**
      * Remove task - this will happen if the task is cancelled, completed, etc.
      */
-    public abstract void maybeStopTrackingJob(JobStatus jobStatus);
+    public abstract void maybeStopTrackingJob(JobStatus jobStatus, boolean forUpdate);
+    /**
+     * Called when a new job is being created to reschedule an old failed job.
+     */
+    public void rescheduleForFailure(JobStatus newJob, JobStatus failureToReschedule) {
+    }
 
     public abstract void dumpControllerState(PrintWriter pw);
 }
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 33b09e3..a68c3ad 100644
--- a/services/core/java/com/android/server/job/controllers/TimeController.java
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -71,9 +71,9 @@
      * list.
      */
     @Override
-    public synchronized void maybeStartTrackingJob(JobStatus job) {
+    public synchronized void maybeStartTrackingJob(JobStatus job, JobStatus lastJob) {
         if (job.hasTimingDelayConstraint() || job.hasDeadlineConstraint()) {
-            maybeStopTrackingJob(job);
+            maybeStopTrackingJob(job, false);
             boolean isInsert = false;
             ListIterator<JobStatus> it = mTrackedJobs.listIterator(mTrackedJobs.size());
             while (it.hasPrevious()) {
@@ -101,7 +101,7 @@
      * Really an == comparison should be enough, but why play with fate? We'll do <=.
      */
     @Override
-    public synchronized void maybeStopTrackingJob(JobStatus job) {
+    public synchronized void maybeStopTrackingJob(JobStatus job, boolean forUpdate) {
         if (mTrackedJobs.remove(job)) {
             checkExpiredDelaysAndResetAlarm();
             checkExpiredDeadlinesAndResetAlarm();
@@ -202,7 +202,7 @@
     /**
      * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a job's
      * delay will expire.
-     * This alarm <b>will not</b> wake up the phone.
+     * This alarm <b>will</b> wake up the phone.
      */
     private void setDelayExpiredAlarm(long alarmTimeElapsedMillis) {
         alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
@@ -238,7 +238,7 @@
             if (DEBUG) {
                 Slog.d(TAG, "Setting " + tag + " for: " + alarmTimeElapsed);
             }
-            mAlarmService.set(AlarmManager.ELAPSED_REALTIME, alarmTimeElapsed,
+            mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTimeElapsed,
                     tag, listener, null);
         }
     }
diff --git a/services/core/java/com/android/server/lights/Light.java b/services/core/java/com/android/server/lights/Light.java
index b496b4c6..b18a181 100644
--- a/services/core/java/com/android/server/lights/Light.java
+++ b/services/core/java/com/android/server/lights/Light.java
@@ -31,6 +31,11 @@
      */
     public static final int BRIGHTNESS_MODE_SENSOR = 1;
 
+    /**
+     * Low-persistence light mode.
+     */
+    public static final int BRIGHTNESS_MODE_LOW_PERSISTENCE = 2;
+
     public abstract void setBrightness(int brightness);
     public abstract void setBrightness(int brightness, int brightnessMode);
     public abstract void setColor(int color);
@@ -38,4 +43,4 @@
     public abstract void pulse();
     public abstract void pulse(int color, int onMS);
     public abstract void turnOff();
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index ed884ef..257c7da 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -17,6 +17,8 @@
 package com.android.server.lights;
 
 import com.android.server.SystemService;
+import com.android.server.vr.VrManagerInternal;
+import com.android.server.vr.VrStateListener;
 
 import android.content.Context;
 import android.os.Handler;
@@ -72,6 +74,9 @@
         @Override
         public void pulse(int color, int onMS) {
             synchronized (this) {
+                if (mBrightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
+                    return;
+                }
                 if (mColor == 0 && !mFlashing) {
                     setLightLocked(color, LIGHT_FLASH_HARDWARE, onMS, 1000, BRIGHTNESS_MODE_USER);
                     mColor = 0;
@@ -87,6 +92,20 @@
             }
         }
 
+        void enableLowPersistence() {
+            synchronized(this) {
+                setLightLocked(0, LIGHT_FLASH_NONE, 0, 0, BRIGHTNESS_MODE_LOW_PERSISTENCE);
+                mLocked = true;
+            }
+        }
+
+        void disableLowPersistence() {
+            synchronized(this) {
+                mLocked = false;
+                setLightLocked(mLastColor, LIGHT_FLASH_NONE, 0, 0, mLastBrightnessMode);
+            }
+        }
+
         private void stopFlashing() {
             synchronized (this) {
                 setLightLocked(mColor, LIGHT_FLASH_NONE, 0, 0, BRIGHTNESS_MODE_USER);
@@ -94,13 +113,17 @@
         }
 
         private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {
-            if (color != mColor || mode != mMode || onMS != mOnMS || offMS != mOffMS) {
+            if (!mLocked && (color != mColor || mode != mMode || onMS != mOnMS || offMS != mOffMS ||
+                    mBrightnessMode != brightnessMode)) {
                 if (DEBUG) Slog.v(TAG, "setLight #" + mId + ": color=#"
-                        + Integer.toHexString(color));
+                        + Integer.toHexString(color) + ": brightnessMode=" + brightnessMode);
+                mLastColor = mColor;
                 mColor = color;
                 mMode = mode;
                 mOnMS = onMS;
                 mOffMS = offMS;
+                mLastBrightnessMode = mBrightnessMode;
+                mBrightnessMode = brightnessMode;
                 Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLight(" + mId + ", 0x"
                         + Integer.toHexString(color) + ")");
                 try {
@@ -117,6 +140,10 @@
         private int mOnMS;
         private int mOffMS;
         private boolean mFlashing;
+        private int mBrightnessMode;
+        private int mLastBrightnessMode;
+        private int mLastColor;
+        private boolean mLocked;
     }
 
     public LightsService(Context context) {
@@ -134,6 +161,28 @@
         publishLocalService(LightsManager.class, mService);
     }
 
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == PHASE_SYSTEM_SERVICES_READY) {
+            getLocalService(VrManagerInternal.class).registerListener(mVrStateListener);
+        }
+    }
+
+    private final VrStateListener mVrStateListener = new VrStateListener() {
+        @Override
+        public void onVrStateChanged(boolean enabled) {
+            LightImpl l = mLights[LightsManager.LIGHT_ID_BACKLIGHT];
+            if (enabled) {
+                if (DEBUG) Slog.v(TAG, "VR mode enabled, setting brightness to low persistence");
+                l.enableLowPersistence();
+
+            } else {
+                if (DEBUG) Slog.v(TAG, "VR mode disabled, resetting brightnes");
+                l.disableLowPersistence();
+            }
+        }
+    };
+
     private final LightsManager mService = new LightsManager() {
         @Override
         public Light getLight(int id) {
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
new file mode 100644
index 0000000..9798e56
--- /dev/null
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -0,0 +1,2480 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import com.android.internal.app.IAppOpsService;
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.location.GpsNetInitiatedHandler;
+import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
+import com.android.internal.location.ProviderProperties;
+import com.android.internal.location.ProviderRequest;
+
+import android.app.AlarmManager;
+import android.app.AppOpsManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.Cursor;
+import android.hardware.location.GeofenceHardware;
+import android.hardware.location.GeofenceHardwareImpl;
+import android.location.Criteria;
+import android.location.FusedBatchOptions;
+import android.location.GnssStatus;
+import android.location.IGnssStatusListener;
+import android.location.IGnssStatusProvider;
+import android.location.GpsMeasurementsEvent;
+import android.location.GpsNavigationMessageEvent;
+import android.location.IGpsGeofenceHardware;
+import android.location.ILocationManager;
+import android.location.INetInitiatedListener;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.location.LocationProvider;
+import android.location.LocationRequest;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.net.NetworkRequest;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.BatteryStats;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.os.WorkSource;
+import android.provider.Settings;
+import android.provider.Telephony.Carriers;
+import android.provider.Telephony.Sms.Intents;
+import android.telephony.SmsMessage;
+import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
+import android.telephony.TelephonyManager;
+import android.telephony.gsm.GsmCellLocation;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.NtpTrustedTime;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import libcore.io.IoUtils;
+
+/**
+ * A GPS implementation of LocationProvider used by LocationManager.
+ *
+ * {@hide}
+ */
+public class GnssLocationProvider implements LocationProviderInterface {
+
+    private static final String TAG = "GnssLocationProvider";
+
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+
+    private static final ProviderProperties PROPERTIES = new ProviderProperties(
+            true, true, false, false, true, true, true,
+            Criteria.POWER_HIGH, Criteria.ACCURACY_FINE);
+
+    // these need to match GpsPositionMode enum in gps.h
+    private static final int GPS_POSITION_MODE_STANDALONE = 0;
+    private static final int GPS_POSITION_MODE_MS_BASED = 1;
+    private static final int GPS_POSITION_MODE_MS_ASSISTED = 2;
+
+    // these need to match GpsPositionRecurrence enum in gps.h
+    private static final int GPS_POSITION_RECURRENCE_PERIODIC = 0;
+    private static final int GPS_POSITION_RECURRENCE_SINGLE = 1;
+
+    // these need to match GpsStatusValue defines in gps.h
+    private static final int GPS_STATUS_NONE = 0;
+    private static final int GPS_STATUS_SESSION_BEGIN = 1;
+    private static final int GPS_STATUS_SESSION_END = 2;
+    private static final int GPS_STATUS_ENGINE_ON = 3;
+    private static final int GPS_STATUS_ENGINE_OFF = 4;
+
+    // these need to match GpsApgsStatusValue defines in gps.h
+    /** AGPS status event values. */
+    private static final int GPS_REQUEST_AGPS_DATA_CONN = 1;
+    private static final int GPS_RELEASE_AGPS_DATA_CONN = 2;
+    private static final int GPS_AGPS_DATA_CONNECTED = 3;
+    private static final int GPS_AGPS_DATA_CONN_DONE = 4;
+    private static final int GPS_AGPS_DATA_CONN_FAILED = 5;
+
+    // these need to match GpsLocationFlags enum in gps.h
+    private static final int LOCATION_INVALID = 0;
+    private static final int LOCATION_HAS_LAT_LONG = 1;
+    private static final int LOCATION_HAS_ALTITUDE = 2;
+    private static final int LOCATION_HAS_SPEED = 4;
+    private static final int LOCATION_HAS_BEARING = 8;
+    private static final int LOCATION_HAS_ACCURACY = 16;
+
+    // IMPORTANT - the GPS_DELETE_* symbols here must match constants in gps.h
+    private static final int GPS_DELETE_EPHEMERIS = 0x0001;
+    private static final int GPS_DELETE_ALMANAC = 0x0002;
+    private static final int GPS_DELETE_POSITION = 0x0004;
+    private static final int GPS_DELETE_TIME = 0x0008;
+    private static final int GPS_DELETE_IONO = 0x0010;
+    private static final int GPS_DELETE_UTC = 0x0020;
+    private static final int GPS_DELETE_HEALTH = 0x0040;
+    private static final int GPS_DELETE_SVDIR = 0x0080;
+    private static final int GPS_DELETE_SVSTEER = 0x0100;
+    private static final int GPS_DELETE_SADATA = 0x0200;
+    private static final int GPS_DELETE_RTI = 0x0400;
+    private static final int GPS_DELETE_CELLDB_INFO = 0x8000;
+    private static final int GPS_DELETE_ALL = 0xFFFF;
+
+    // The GPS_CAPABILITY_* flags must match the values in gps.h
+    private static final int GPS_CAPABILITY_SCHEDULING = 0x0000001;
+    private static final int GPS_CAPABILITY_MSB = 0x0000002;
+    private static final int GPS_CAPABILITY_MSA = 0x0000004;
+    private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
+    private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
+    private static final int GPS_CAPABILITY_GEOFENCING = 0x0000020;
+    private static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040;
+    private static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080;
+
+    // The AGPS SUPL mode
+    private static final int AGPS_SUPL_MODE_MSA = 0x02;
+    private static final int AGPS_SUPL_MODE_MSB = 0x01;
+
+    // these need to match AGpsType enum in gps.h
+    private static final int AGPS_TYPE_SUPL = 1;
+    private static final int AGPS_TYPE_C2K = 2;
+
+    // these must match the definitions in gps.h
+    private static final int APN_INVALID = 0;
+    private static final int APN_IPV4 = 1;
+    private static final int APN_IPV6 = 2;
+    private static final int APN_IPV4V6 = 3;
+
+    // for mAGpsDataConnectionState
+    private static final int AGPS_DATA_CONNECTION_CLOSED = 0;
+    private static final int AGPS_DATA_CONNECTION_OPENING = 1;
+    private static final int AGPS_DATA_CONNECTION_OPEN = 2;
+
+    // Handler messages
+    private static final int CHECK_LOCATION = 1;
+    private static final int ENABLE = 2;
+    private static final int SET_REQUEST = 3;
+    private static final int UPDATE_NETWORK_STATE = 4;
+    private static final int INJECT_NTP_TIME = 5;
+    private static final int DOWNLOAD_XTRA_DATA = 6;
+    private static final int UPDATE_LOCATION = 7;
+    private static final int ADD_LISTENER = 8;
+    private static final int REMOVE_LISTENER = 9;
+    private static final int INJECT_NTP_TIME_FINISHED = 10;
+    private static final int DOWNLOAD_XTRA_DATA_FINISHED = 11;
+    private static final int SUBSCRIPTION_OR_SIM_CHANGED = 12;
+    private static final int INITIALIZE_HANDLER = 13;
+    private static final int REQUEST_SUPL_CONNECTION = 14;
+    private static final int RELEASE_SUPL_CONNECTION = 15;
+
+    // Request setid
+    private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
+    private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2;
+
+    // Request ref location
+    private static final int AGPS_RIL_REQUEST_REFLOC_CELLID = 1;
+    private static final int AGPS_RIL_REQUEST_REFLOC_MAC = 2;
+
+    // ref. location info
+    private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1;
+    private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2;
+    private static final int AGPS_REG_LOCATION_TYPE_MAC        = 3;
+
+    // set id info
+    private static final int AGPS_SETID_TYPE_NONE = 0;
+    private static final int AGPS_SETID_TYPE_IMSI = 1;
+    private static final int AGPS_SETID_TYPE_MSISDN = 2;
+
+    private static final String PROPERTIES_FILE_PREFIX = "/etc/gps";
+    private static final String PROPERTIES_FILE_SUFFIX = ".conf";
+    private static final String DEFAULT_PROPERTIES_FILE = PROPERTIES_FILE_PREFIX + PROPERTIES_FILE_SUFFIX;
+
+    private static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L;
+    private static final int GPS_GEOFENCE_AVAILABLE = 1<<1L;
+
+    // GPS Geofence errors. Should match gps.h constants.
+    private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0;
+    private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100;
+    private static final int GPS_GEOFENCE_ERROR_ID_EXISTS  = -101;
+    private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102;
+    private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103;
+    private static final int GPS_GEOFENCE_ERROR_GENERIC = -149;
+
+    // TCP/IP constants.
+    // Valid TCP/UDP port range is (0, 65535].
+    private static final int TCP_MIN_PORT = 0;
+    private static final int TCP_MAX_PORT = 0xffff;
+
+    // Value of batterySaverGpsMode such that GPS isn't affected by battery saver mode.
+    private static final int BATTERY_SAVER_MODE_NO_CHANGE = 0;
+    // Value of batterySaverGpsMode such that GPS is disabled when battery saver mode
+    // is enabled and the screen is off.
+    private static final int BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF = 1;
+    // Secure setting for GPS behavior when battery saver mode is on.
+    private static final String BATTERY_SAVER_GPS_MODE = "batterySaverGpsMode";
+
+    /** simpler wrapper for ProviderRequest + Worksource */
+    private static class GpsRequest {
+        public ProviderRequest request;
+        public WorkSource source;
+        public GpsRequest(ProviderRequest request, WorkSource source) {
+            this.request = request;
+            this.source = source;
+        }
+    }
+
+    private Object mLock = new Object();
+
+    private int mLocationFlags = LOCATION_INVALID;
+
+    // current status
+    private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE;
+
+    // time for last status update
+    private long mStatusUpdateTime = SystemClock.elapsedRealtime();
+
+    // turn off GPS fix icon if we haven't received a fix in 10 seconds
+    private static final long RECENT_FIX_TIMEOUT = 10 * 1000;
+
+    // stop trying if we do not receive a fix within 60 seconds
+    private static final int NO_FIX_TIMEOUT = 60 * 1000;
+
+    // if the fix interval is below this we leave GPS on,
+    // if above then we cycle the GPS driver.
+    // Typical hot TTTF is ~5 seconds, so 10 seconds seems sane.
+    private static final int GPS_POLLING_THRESHOLD_INTERVAL = 10 * 1000;
+
+    // how often to request NTP time, in milliseconds
+    // current setting 24 hours
+    private static final long NTP_INTERVAL = 24*60*60*1000;
+    // how long to wait if we have a network error in NTP or XTRA downloading
+    // the initial value of the exponential backoff
+    // current setting - 5 minutes
+    private static final long RETRY_INTERVAL = 5*60*1000;
+    // how long to wait if we have a network error in NTP or XTRA downloading
+    // the max value of the exponential backoff
+    // current setting - 4 hours
+    private static final long MAX_RETRY_INTERVAL = 4*60*60*1000;
+
+    private BackOff mNtpBackOff = new BackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL);
+    private BackOff mXtraBackOff = new BackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL);
+
+    // true if we are enabled, protected by this
+    private boolean mEnabled;
+
+    // states for injecting ntp and downloading xtra data
+    private static final int STATE_PENDING_NETWORK = 0;
+    private static final int STATE_DOWNLOADING = 1;
+    private static final int STATE_IDLE = 2;
+
+    // flags to trigger NTP or XTRA data download when network becomes available
+    // initialized to true so we do NTP and XTRA when the network comes up after booting
+    private int mInjectNtpTimePending = STATE_PENDING_NETWORK;
+    private int mDownloadXtraDataPending = STATE_PENDING_NETWORK;
+
+    // set to true if the GPS engine requested on-demand NTP time requests
+    private boolean mOnDemandTimeInjection;
+
+    // true if GPS is navigating
+    private boolean mNavigating;
+
+    // true if GPS engine is on
+    private boolean mEngineOn;
+
+    // requested frequency of fixes, in milliseconds
+    private int mFixInterval = 1000;
+
+    // true if we started navigation
+    private boolean mStarted;
+
+    // true if single shot request is in progress
+    private boolean mSingleShot;
+
+    // capabilities of the GPS engine
+    private int mEngineCapabilities;
+
+    // true if XTRA is supported
+    private boolean mSupportsXtra;
+
+    // for calculating time to first fix
+    private long mFixRequestTime = 0;
+    // time to first fix for most recent session
+    private int mTimeToFirstFix = 0;
+    // time we received our last fix
+    private long mLastFixTime;
+
+    private int mPositionMode;
+
+    // Current request from underlying location clients.
+    private ProviderRequest mProviderRequest = null;
+    // Current list of underlying location clients.
+    private WorkSource mWorkSource = null;
+    // True if gps should be disabled (used to support battery saver mode in settings).
+    private boolean mDisableGps = false;
+
+    /**
+     * Properties loaded from PROPERTIES_FILE.
+     * It must be accessed only inside {@link #mHandler}.
+     */
+    private Properties mProperties;
+
+    private String mSuplServerHost;
+    private int mSuplServerPort = TCP_MIN_PORT;
+    private String mC2KServerHost;
+    private int mC2KServerPort;
+    private boolean mSuplEsEnabled = false;
+
+    private final Context mContext;
+    private final NtpTrustedTime mNtpTime;
+    private final ILocationManager mILocationManager;
+    private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
+    private Bundle mLocationExtras = new Bundle();
+    private final GnssStatusListenerHelper mListenerHelper;
+    private final GpsMeasurementsProvider mGpsMeasurementsProvider;
+    private final GpsNavigationMessageProvider mGpsNavigationMessageProvider;
+
+    // Handler for processing events
+    private Handler mHandler;
+
+    /** It must be accessed only inside {@link #mHandler}. */
+    private int mAGpsDataConnectionState;
+    /** It must be accessed only inside {@link #mHandler}. */
+    private InetAddress mAGpsDataConnectionIpAddr;
+
+    private final ConnectivityManager mConnMgr;
+    private final GpsNetInitiatedHandler mNIHandler;
+
+    // Wakelocks
+    private final static String WAKELOCK_KEY = "GnssLocationProvider";
+    private final PowerManager.WakeLock mWakeLock;
+
+    // Alarms
+    private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
+    private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT";
+
+    // SIM/Carrier info.
+    private final static String SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
+
+    private final PowerManager mPowerManager;
+    private final AlarmManager mAlarmManager;
+    private final PendingIntent mWakeupIntent;
+    private final PendingIntent mTimeoutIntent;
+
+    private final IAppOpsService mAppOpsService;
+    private final IBatteryStats mBatteryStats;
+
+    // only modified on handler thread
+    private WorkSource mClientSource = new WorkSource();
+
+    private GeofenceHardwareImpl mGeofenceHardwareImpl;
+
+    private int mYearOfHardware = 0;
+
+    private final IGnssStatusProvider mGnssStatusProvider = new IGnssStatusProvider.Stub() {
+        @Override
+        public void registerGnssStatusCallback(IGnssStatusListener callback) {
+            mListenerHelper.addListener(callback);
+        }
+
+        @Override
+        public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
+            mListenerHelper.removeListener(callback);
+        }
+    };
+
+    public IGnssStatusProvider getGnssStatusProvider() {
+        return mGnssStatusProvider;
+    }
+
+    public IGpsGeofenceHardware getGpsGeofenceProxy() {
+        return mGpsGeofenceBinder;
+    }
+
+    public GpsMeasurementsProvider getGpsMeasurementsProvider() {
+        return mGpsMeasurementsProvider;
+    }
+
+    public GpsNavigationMessageProvider getGpsNavigationMessageProvider() {
+        return mGpsNavigationMessageProvider;
+    }
+
+    /**
+     * Callback used to listen for data connectivity changes.
+     */
+    private final ConnectivityManager.NetworkCallback mNetworkConnectivityCallback =
+            new ConnectivityManager.NetworkCallback() {
+        @Override
+        public void onAvailable(Network network) {
+            requestUtcTime();
+            xtraDownloadRequest();
+        }
+    };
+
+    /**
+     * Callback used to listen for availability of a requested SUPL connection.
+     * It is kept as a separate instance from {@link #mNetworkConnectivityCallback} to be able to
+     * manage the registration/un-registration lifetimes separate.
+     */
+    private final ConnectivityManager.NetworkCallback mSuplConnectivityCallback =
+            new ConnectivityManager.NetworkCallback() {
+        @Override
+        public void onAvailable(Network network) {
+            sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
+        }
+
+        @Override
+        public void onLost(Network network) {
+            releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
+        }
+
+        @Override
+        public void onUnavailable() {
+            // timeout, it was not possible to establish the required connection
+            releaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
+        }
+    };
+
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action);
+            if (action == null) {
+                return;
+            }
+
+            if (action.equals(ALARM_WAKEUP)) {
+                startNavigating(false);
+            } else if (action.equals(ALARM_TIMEOUT)) {
+                hibernate();
+            } else if (action.equals(Intents.DATA_SMS_RECEIVED_ACTION)) {
+                checkSmsSuplInit(intent);
+            } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) {
+                checkWapSuplInit(intent);
+            } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)
+                    || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)
+                    || Intent.ACTION_SCREEN_OFF.equals(action)
+                    || Intent.ACTION_SCREEN_ON.equals(action)) {
+                updateLowPowerMode();
+            } else if (action.equals(SIM_STATE_CHANGED)) {
+                subscriptionOrSimChanged(context);
+            }
+        }
+    };
+
+    private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
+            new OnSubscriptionsChangedListener() {
+        @Override
+        public void onSubscriptionsChanged() {
+            sendMessage(SUBSCRIPTION_OR_SIM_CHANGED, 0, null);
+        }
+    };
+
+    private void subscriptionOrSimChanged(Context context) {
+        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);
+            synchronized (mLock) {
+                reloadGpsProperties(context, mProperties);
+                mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
+            }
+        } else {
+            Log.d(TAG, "SIM MCC/MNC is still not available");
+        }
+    }
+
+    private void checkSmsSuplInit(Intent intent) {
+        SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
+        if (messages == null) {
+            Log.e(TAG, "Message does not exist in the intent.");
+            return;
+        }
+
+        for (SmsMessage message : messages) {
+            if (message != null && message.mWrappedSmsMessage != null) {
+                byte[] suplInit = message.getUserData();
+                if (suplInit != null) {
+                    native_agps_ni_message(suplInit, suplInit.length);
+                }
+            }
+        }
+    }
+
+    private void checkWapSuplInit(Intent intent) {
+        byte[] suplInit = intent.getByteArrayExtra("data");
+        if (suplInit == null) {
+            return;
+        }
+        native_agps_ni_message(suplInit,suplInit.length);
+    }
+
+    private void updateLowPowerMode() {
+        // Disable GPS if we are in device idle mode.
+        boolean disableGps = mPowerManager.isDeviceIdleMode();
+        switch (Settings.Secure.getInt(mContext.getContentResolver(), BATTERY_SAVER_GPS_MODE,
+                BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF)) {
+            case BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF:
+                // If we are in battery saver mode and the screen is off, disable GPS.
+                disableGps |= mPowerManager.isPowerSaveMode() && !mPowerManager.isInteractive();
+                break;
+        }
+        if (disableGps != mDisableGps) {
+            mDisableGps = disableGps;
+            updateRequirements();
+        }
+    }
+
+    public static boolean isSupported() {
+        return native_is_supported();
+    }
+
+    private void reloadGpsProperties(Context context, Properties properties) {
+        Log.d(TAG, "Reset GPS properties, previous size = " + properties.size());
+        loadPropertiesFromResource(context, properties);
+        boolean isPropertiesLoadedFromFile = false;
+        final String gpsHardware = SystemProperties.get("ro.hardware.gps");
+        if (!TextUtils.isEmpty(gpsHardware)) {
+            final String propFilename =
+                    PROPERTIES_FILE_PREFIX + "." + gpsHardware + PROPERTIES_FILE_SUFFIX;
+            isPropertiesLoadedFromFile =
+                    loadPropertiesFromFile(propFilename, properties);
+        }
+        if (!isPropertiesLoadedFromFile) {
+            loadPropertiesFromFile(DEFAULT_PROPERTIES_FILE, properties);
+        }
+        Log.d(TAG, "GPS properties reloaded, size = " + properties.size());
+
+        // TODO: we should get rid of C2K specific setting.
+        setSuplHostPort(properties.getProperty("SUPL_HOST"),
+                        properties.getProperty("SUPL_PORT"));
+        mC2KServerHost = properties.getProperty("C2K_HOST");
+        String portString = properties.getProperty("C2K_PORT");
+        if (mC2KServerHost != null && portString != null) {
+            try {
+                mC2KServerPort = Integer.parseInt(portString);
+            } catch (NumberFormatException e) {
+                Log.e(TAG, "unable to parse C2K_PORT: " + portString);
+            }
+        }
+
+        if (native_is_gnss_configuration_supported()) {
+            try {
+                // Convert properties to string contents and send it to HAL.
+                ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
+                properties.store(baos, null);
+                native_configuration_update(baos.toString());
+                Log.d(TAG, "final config = " + baos.toString());
+            } catch (IOException ex) {
+                Log.e(TAG, "failed to dump properties contents");
+            }
+        } else if (DEBUG) {
+            Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not"
+                    + " supported");
+        }
+
+        // SUPL_ES configuration.
+        String suplESProperty = mProperties.getProperty("SUPL_ES");
+        if (suplESProperty != null) {
+            try {
+                mSuplEsEnabled = (Integer.parseInt(suplESProperty) == 1);
+            } catch (NumberFormatException e) {
+                Log.e(TAG, "unable to parse SUPL_ES: " + suplESProperty);
+            }
+        }
+    }
+
+    private void loadPropertiesFromResource(Context context,
+                                            Properties properties) {
+        String[] configValues = context.getResources().getStringArray(
+                com.android.internal.R.array.config_gpsParameters);
+        for (String item : configValues) {
+            Log.d(TAG, "GpsParamsResource: " + item);
+            // We need to support "KEY =", but not "=VALUE".
+            String[] split = item.split("=");
+            if (split.length == 2) {
+                properties.setProperty(split[0].trim().toUpperCase(), split[1]);
+            } else {
+                Log.w(TAG, "malformed contents: " + item);
+            }
+        }
+    }
+
+    private boolean loadPropertiesFromFile(String filename,
+                                           Properties properties) {
+        try {
+            File file = new File(filename);
+            FileInputStream stream = null;
+            try {
+                stream = new FileInputStream(file);
+                properties.load(stream);
+            } finally {
+                IoUtils.closeQuietly(stream);
+            }
+
+        } catch (IOException e) {
+            Log.w(TAG, "Could not open GPS configuration file " + filename);
+            return false;
+        }
+        return true;
+    }
+
+    public GnssLocationProvider(Context context, ILocationManager ilocationManager,
+            Looper looper) {
+        mContext = context;
+        mNtpTime = NtpTrustedTime.getInstance(context);
+        mILocationManager = ilocationManager;
+
+        mLocation.setExtras(mLocationExtras);
+
+        // Create a wake lock
+        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
+        mWakeLock.setReferenceCounted(true);
+
+        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+        mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
+        mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
+
+        mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+        // App ops service to keep track of who is accessing the GPS
+        mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(
+                Context.APP_OPS_SERVICE));
+
+        // Battery statistics service to be notified when GPS turns on or off
+        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
+                BatteryStats.SERVICE_NAME));
+
+        // Construct internal handler
+        mHandler = new ProviderHandler(looper);
+
+        // Load GPS configuration and register listeners in the background:
+        // some operations, such as opening files and registering broadcast receivers, can take a
+        // relative long time, so the ctor() is kept to create objects needed by this instance,
+        // while IO initialization and registration is delegated to our internal handler
+        // this approach is just fine because events are posted to our handler anyway
+        mProperties = new Properties();
+        sendMessage(INITIALIZE_HANDLER, 0, null);
+
+        // Create a GPS net-initiated handler.
+        mNIHandler = new GpsNetInitiatedHandler(context,
+                                                mNetInitiatedListener,
+                                                mSuplEsEnabled);
+
+        mListenerHelper = new GnssStatusListenerHelper(mHandler) {
+            @Override
+            protected boolean isAvailableInPlatform() {
+                return isSupported();
+            }
+
+            @Override
+            protected boolean isGpsEnabled() {
+                return isEnabled();
+            }
+        };
+
+        mGpsMeasurementsProvider = new GpsMeasurementsProvider(mHandler) {
+            @Override
+            public boolean isAvailableInPlatform() {
+                return native_is_measurement_supported();
+            }
+
+            @Override
+            protected boolean registerWithService() {
+                return native_start_measurement_collection();
+            }
+
+            @Override
+            protected void unregisterFromService() {
+                native_stop_measurement_collection();
+            }
+
+            @Override
+            protected boolean isGpsEnabled() {
+                return isEnabled();
+            }
+        };
+
+        mGpsNavigationMessageProvider = new GpsNavigationMessageProvider(mHandler) {
+            @Override
+            protected boolean isAvailableInPlatform() {
+                return native_is_navigation_message_supported();
+            }
+
+            @Override
+            protected boolean registerWithService() {
+                return native_start_navigation_message_collection();
+            }
+
+            @Override
+            protected void unregisterFromService() {
+                native_stop_navigation_message_collection();
+            }
+
+            @Override
+            protected boolean isGpsEnabled() {
+                return isEnabled();
+            }
+        };
+    }
+
+    /**
+     * Returns the name of this provider.
+     */
+    @Override
+    public String getName() {
+        return LocationManager.GPS_PROVIDER;
+    }
+
+    @Override
+    public ProviderProperties getProperties() {
+        return PROPERTIES;
+    }
+
+    private void handleUpdateNetworkState(Network network) {
+        // retrieve NetworkInfo for this UID
+        NetworkInfo info = mConnMgr.getNetworkInfo(network);
+        if (info == null) {
+            return;
+        }
+
+        boolean isConnected = info.isConnected();
+        if (DEBUG) {
+            String message = String.format(
+                    "UpdateNetworkState, state=%s, connected=%s, info=%s, capabilities=%S",
+                    agpsDataConnStateAsString(),
+                    isConnected,
+                    info,
+                    mConnMgr.getNetworkCapabilities(network));
+            Log.d(TAG, message);
+        }
+
+        if (native_is_agps_ril_supported()) {
+            boolean dataEnabled = TelephonyManager.getDefault().getDataEnabled();
+            boolean networkAvailable = info.isAvailable() && dataEnabled;
+            String defaultApn = getSelectedApn();
+            if (defaultApn == null) {
+                defaultApn = "dummy-apn";
+            }
+
+            native_update_network_state(
+                    isConnected,
+                    info.getType(),
+                    info.isRoaming(),
+                    networkAvailable,
+                    info.getExtraInfo(),
+                    defaultApn);
+        } else if (DEBUG) {
+            Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not  supported");
+        }
+
+        if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
+            if (isConnected) {
+                String apnName = info.getExtraInfo();
+                if (apnName == null) {
+                    // assign a dummy value in the case of C2K as otherwise we will have a runtime
+                    // exception in the following call to native_agps_data_conn_open
+                    apnName = "dummy-apn";
+                }
+                int apnIpType = getApnIpType(apnName);
+                setRouting();
+                if (DEBUG) {
+                    String message = String.format(
+                            "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s",
+                            apnName,
+                            apnIpType);
+                    Log.d(TAG, message);
+                }
+                native_agps_data_conn_open(apnName, apnIpType);
+                mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
+            } else {
+                handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
+            }
+        }
+    }
+
+    private void handleRequestSuplConnection(InetAddress address) {
+        if (DEBUG) {
+            String message = String.format(
+                    "requestSuplConnection, state=%s, address=%s",
+                    agpsDataConnStateAsString(),
+                    address);
+            Log.d(TAG, message);
+        }
+
+        if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
+            return;
+        }
+        mAGpsDataConnectionIpAddr = address;
+        mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
+
+        NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
+        requestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+        requestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
+        NetworkRequest request = requestBuilder.build();
+        mConnMgr.requestNetwork(
+                request,
+                mSuplConnectivityCallback,
+                ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS);
+    }
+
+    private void handleReleaseSuplConnection(int agpsDataConnStatus) {
+        if (DEBUG) {
+            String message = String.format(
+                    "releaseSuplConnection, state=%s, status=%s",
+                    agpsDataConnStateAsString(),
+                    agpsDataConnStatusAsString(agpsDataConnStatus));
+            Log.d(TAG, message);
+        }
+
+        if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_CLOSED) {
+            return;
+        }
+        mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
+
+        mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback);
+        switch (agpsDataConnStatus) {
+            case GPS_AGPS_DATA_CONN_FAILED:
+                native_agps_data_conn_failed();
+                break;
+            case GPS_RELEASE_AGPS_DATA_CONN:
+                native_agps_data_conn_closed();
+                break;
+            default:
+                Log.e(TAG, "Invalid status to release SUPL connection: " + agpsDataConnStatus);
+        }
+    }
+
+    private void handleInjectNtpTime() {
+        if (mInjectNtpTimePending == STATE_DOWNLOADING) {
+            // already downloading data
+            return;
+        }
+        if (!isDataNetworkConnected()) {
+            // try again when network is up
+            mInjectNtpTimePending = STATE_PENDING_NETWORK;
+            return;
+        }
+        mInjectNtpTimePending = STATE_DOWNLOADING;
+
+        // hold wake lock while task runs
+        mWakeLock.acquire();
+        AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
+            @Override
+            public void run() {
+                long delay;
+
+                // force refresh NTP cache when outdated
+                boolean refreshSuccess = true;
+                if (mNtpTime.getCacheAge() >= NTP_INTERVAL) {
+                    refreshSuccess = mNtpTime.forceRefresh();
+                }
+
+                // only update when NTP time is fresh
+                if (mNtpTime.getCacheAge() < NTP_INTERVAL) {
+                    long time = mNtpTime.getCachedNtpTime();
+                    long timeReference = mNtpTime.getCachedNtpTimeReference();
+                    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));
+
+                    native_inject_time(time, timeReference, (int) certainty);
+                    delay = NTP_INTERVAL;
+                    mNtpBackOff.reset();
+                } else {
+                    Log.e(TAG, "requestTime failed");
+                    delay = mNtpBackOff.nextBackoffMillis();
+                }
+
+                sendMessage(INJECT_NTP_TIME_FINISHED, 0, null);
+
+                if (DEBUG) {
+                    String message = String.format(
+                            "onDemandTimeInjection=%s, refreshSuccess=%s, delay=%s",
+                            mOnDemandTimeInjection,
+                            refreshSuccess,
+                            delay);
+                    Log.d(TAG, message);
+                }
+                if (mOnDemandTimeInjection || !refreshSuccess) {
+                    // send delayed message for next NTP injection
+                    // since this is delayed and not urgent we do not hold a wake lock here
+                    mHandler.sendEmptyMessageDelayed(INJECT_NTP_TIME, delay);
+                }
+
+                // release wake lock held by task
+                mWakeLock.release();
+            }
+        });
+    }
+
+    private void handleDownloadXtraData() {
+        if (mDownloadXtraDataPending == STATE_DOWNLOADING) {
+            // already downloading data
+            return;
+        }
+        if (!isDataNetworkConnected()) {
+            // try again when network is up
+            mDownloadXtraDataPending = STATE_PENDING_NETWORK;
+            return;
+        }
+        mDownloadXtraDataPending = STATE_DOWNLOADING;
+
+        // hold wake lock while task runs
+        mWakeLock.acquire();
+        AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
+            @Override
+            public void run() {
+                GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties);
+                byte[] data = xtraDownloader.downloadXtraData();
+                if (data != null) {
+                    if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data");
+                    native_inject_xtra_data(data, data.length);
+                    mXtraBackOff.reset();
+                }
+
+                sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
+
+                if (data == null) {
+                    // try again later
+                    // since this is delayed and not urgent we do not hold a wake lock here
+                    mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA,
+                            mXtraBackOff.nextBackoffMillis());
+                }
+
+                // release wake lock held by task
+                mWakeLock.release();
+            }
+        });
+    }
+
+    private void handleUpdateLocation(Location location) {
+        if (location.hasAccuracy()) {
+            native_inject_location(location.getLatitude(), location.getLongitude(),
+                    location.getAccuracy());
+        }
+    }
+
+    /**
+     * Enables this provider.  When enabled, calls to getStatus()
+     * must be handled.  Hardware may be started up
+     * when the provider is enabled.
+     */
+    @Override
+    public void enable() {
+        synchronized (mLock) {
+            if (mEnabled) return;
+            mEnabled = true;
+        }
+
+        sendMessage(ENABLE, 1, null);
+    }
+
+    private void setSuplHostPort(String hostString, String portString) {
+        if (hostString != null) {
+            mSuplServerHost = hostString;
+        }
+        if (portString != null) {
+            try {
+                mSuplServerPort = Integer.parseInt(portString);
+            } catch (NumberFormatException e) {
+                Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
+            }
+        }
+        if (mSuplServerHost != null
+                && mSuplServerPort > TCP_MIN_PORT
+                && mSuplServerPort <= TCP_MAX_PORT) {
+            native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
+        }
+    }
+
+    /**
+     * Checks what SUPL mode to use, according to the AGPS mode as well as the
+     * allowed mode from properties.
+     *
+     * @param properties GPS properties
+     * @param agpsEnabled whether AGPS is enabled by settings value
+     * @param singleShot whether "singleshot" is needed
+     * @return SUPL mode (MSA vs MSB vs STANDALONE)
+     */
+    private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) {
+        if (agpsEnabled) {
+            String modeString = properties.getProperty("SUPL_MODE");
+            int suplMode = 0;
+            if (!TextUtils.isEmpty(modeString)) {
+                try {
+                    suplMode = Integer.parseInt(modeString);
+                } catch (NumberFormatException e) {
+                    Log.e(TAG, "unable to parse SUPL_MODE: " + modeString);
+                    return GPS_POSITION_MODE_STANDALONE;
+                }
+            }
+            // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor
+            // such mode when it is available
+            if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) {
+                return GPS_POSITION_MODE_MS_BASED;
+            }
+            // for now, just as the legacy code did, we fallback to MS-Assisted if it is available,
+            // do fallback only for single-shot requests, because it is too expensive to do for
+            // periodic requests as well
+            if (singleShot
+                    && hasCapability(GPS_CAPABILITY_MSA)
+                    && (suplMode & AGPS_SUPL_MODE_MSA) != 0) {
+                return GPS_POSITION_MODE_MS_ASSISTED;
+            }
+        }
+        return GPS_POSITION_MODE_STANDALONE;
+    }
+
+    private void handleEnable() {
+        if (DEBUG) Log.d(TAG, "handleEnable");
+
+        boolean enabled = native_init();
+
+        if (enabled) {
+            mSupportsXtra = native_supports_xtra();
+
+            // TODO: remove the following native calls if we can make sure they are redundant.
+            if (mSuplServerHost != null) {
+                native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
+            }
+            if (mC2KServerHost != null) {
+                native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
+            }
+
+            mGpsMeasurementsProvider.onGpsEnabledChanged();
+            mGpsNavigationMessageProvider.onGpsEnabledChanged();
+        } else {
+            synchronized (mLock) {
+                mEnabled = false;
+            }
+            Log.w(TAG, "Failed to enable location provider");
+        }
+    }
+
+    /**
+     * Disables this provider.  When disabled, calls to getStatus()
+     * need not be handled.  Hardware may be shut
+     * down while the provider is disabled.
+     */
+    @Override
+    public void disable() {
+        synchronized (mLock) {
+            if (!mEnabled) return;
+            mEnabled = false;
+        }
+
+        sendMessage(ENABLE, 0, null);
+    }
+
+    private void handleDisable() {
+        if (DEBUG) Log.d(TAG, "handleDisable");
+
+        updateClientUids(new WorkSource());
+        stopNavigating();
+        mAlarmManager.cancel(mWakeupIntent);
+        mAlarmManager.cancel(mTimeoutIntent);
+
+        // do this before releasing wakelock
+        native_cleanup();
+
+        mGpsMeasurementsProvider.onGpsEnabledChanged();
+        mGpsNavigationMessageProvider.onGpsEnabledChanged();
+    }
+
+    @Override
+    public boolean isEnabled() {
+        synchronized (mLock) {
+            return mEnabled;
+        }
+    }
+
+    @Override
+    public int getStatus(Bundle extras) {
+        if (extras != null) {
+            extras.putInt("satellites", mSvCount);
+        }
+        return mStatus;
+    }
+
+    private void updateStatus(int status, int svCount) {
+        if (status != mStatus || svCount != mSvCount) {
+            mStatus = status;
+            mSvCount = svCount;
+            mLocationExtras.putInt("satellites", svCount);
+            mStatusUpdateTime = SystemClock.elapsedRealtime();
+        }
+    }
+
+    @Override
+    public long getStatusUpdateTime() {
+        return mStatusUpdateTime;
+    }
+
+    @Override
+    public void setRequest(ProviderRequest request, WorkSource source) {
+        sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
+    }
+
+    private void handleSetRequest(ProviderRequest request, WorkSource source) {
+        mProviderRequest = request;
+        mWorkSource = source;
+        updateRequirements();
+    }
+
+    // Called when the requirements for GPS may have changed
+    private void updateRequirements() {
+        if (mProviderRequest == null || mWorkSource == null) {
+            return;
+        }
+
+        boolean singleShot = false;
+
+        // see if the request is for a single update
+        if (mProviderRequest.locationRequests != null
+                && mProviderRequest.locationRequests.size() > 0) {
+            // if any request has zero or more than one updates
+            // requested, then this is not single-shot mode
+            singleShot = true;
+
+            for (LocationRequest lr : mProviderRequest.locationRequests) {
+                if (lr.getNumUpdates() != 1) {
+                    singleShot = false;
+                }
+            }
+        }
+
+        if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest);
+        if (mProviderRequest.reportLocation && !mDisableGps) {
+            // update client uids
+            updateClientUids(mWorkSource);
+
+            mFixInterval = (int) mProviderRequest.interval;
+
+            // check for overflow
+            if (mFixInterval != mProviderRequest.interval) {
+                Log.w(TAG, "interval overflow: " + mProviderRequest.interval);
+                mFixInterval = Integer.MAX_VALUE;
+            }
+
+            // apply request to GPS engine
+            if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
+                // change period
+                if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
+                        mFixInterval, 0, 0)) {
+                    Log.e(TAG, "set_position_mode failed in setMinTime()");
+                }
+            } else if (!mStarted) {
+                // start GPS
+                startNavigating(singleShot);
+            }
+        } else {
+            updateClientUids(new WorkSource());
+
+            stopNavigating();
+            mAlarmManager.cancel(mWakeupIntent);
+            mAlarmManager.cancel(mTimeoutIntent);
+        }
+    }
+
+    private void updateClientUids(WorkSource source) {
+        // Update work source.
+        WorkSource[] changes = mClientSource.setReturningDiffs(source);
+        if (changes == null) {
+            return;
+        }
+        WorkSource newWork = changes[0];
+        WorkSource goneWork = changes[1];
+
+        // Update sources that were not previously tracked.
+        if (newWork != null) {
+            int lastuid = -1;
+            for (int i=0; i<newWork.size(); i++) {
+                try {
+                    int uid = newWork.get(i);
+                    mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
+                            AppOpsManager.OP_GPS, uid, newWork.getName(i));
+                    if (uid != lastuid) {
+                        lastuid = uid;
+                        mBatteryStats.noteStartGps(uid);
+                    }
+                } catch (RemoteException e) {
+                    Log.w(TAG, "RemoteException", e);
+                }
+            }
+        }
+
+        // Update sources that are no longer tracked.
+        if (goneWork != null) {
+            int lastuid = -1;
+            for (int i=0; i<goneWork.size(); i++) {
+                try {
+                    int uid = goneWork.get(i);
+                    mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
+                            AppOpsManager.OP_GPS, uid, goneWork.getName(i));
+                    if (uid != lastuid) {
+                        lastuid = uid;
+                        mBatteryStats.noteStopGps(uid);
+                    }
+                } catch (RemoteException e) {
+                    Log.w(TAG, "RemoteException", e);
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean sendExtraCommand(String command, Bundle extras) {
+
+        long identity = Binder.clearCallingIdentity();
+        boolean result = false;
+
+        if ("delete_aiding_data".equals(command)) {
+            result = deleteAidingData(extras);
+        } else if ("force_time_injection".equals(command)) {
+            requestUtcTime();
+            result = true;
+        } else if ("force_xtra_injection".equals(command)) {
+            if (mSupportsXtra) {
+                xtraDownloadRequest();
+                result = true;
+            }
+        } else {
+            Log.w(TAG, "sendExtraCommand: unknown command " + command);
+        }
+
+        Binder.restoreCallingIdentity(identity);
+        return result;
+    }
+
+    private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() {
+        public boolean isHardwareGeofenceSupported() {
+            return native_is_geofence_supported();
+        }
+
+        public boolean addCircularHardwareGeofence(int geofenceId, double latitude,
+                double longitude, double radius, int lastTransition, int monitorTransitions,
+                int notificationResponsiveness, int unknownTimer) {
+            return native_add_geofence(geofenceId, latitude, longitude, radius,
+                    lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer);
+        }
+
+        public boolean removeHardwareGeofence(int geofenceId) {
+            return native_remove_geofence(geofenceId);
+        }
+
+        public boolean pauseHardwareGeofence(int geofenceId) {
+            return native_pause_geofence(geofenceId);
+        }
+
+        public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) {
+            return native_resume_geofence(geofenceId, monitorTransition);
+        }
+    };
+
+    private boolean deleteAidingData(Bundle extras) {
+        int flags;
+
+        if (extras == null) {
+            flags = GPS_DELETE_ALL;
+        } else {
+            flags = 0;
+            if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
+            if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
+            if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
+            if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
+            if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
+            if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
+            if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
+            if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
+            if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
+            if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
+            if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
+            if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
+            if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
+        }
+
+        if (flags != 0) {
+            native_delete_aiding_data(flags);
+            return true;
+        }
+
+        return false;
+    }
+
+    private void startNavigating(boolean singleShot) {
+        if (!mStarted) {
+            if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot);
+            mTimeToFirstFix = 0;
+            mLastFixTime = 0;
+            mStarted = true;
+            mSingleShot = singleShot;
+            mPositionMode = GPS_POSITION_MODE_STANDALONE;
+
+            boolean agpsEnabled =
+                    (Settings.Global.getInt(mContext.getContentResolver(),
+                                            Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0);
+            mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot);
+
+            if (DEBUG) {
+                String mode;
+
+                switch(mPositionMode) {
+                    case GPS_POSITION_MODE_STANDALONE:
+                        mode = "standalone";
+                        break;
+                    case GPS_POSITION_MODE_MS_ASSISTED:
+                        mode = "MS_ASSISTED";
+                        break;
+                    case GPS_POSITION_MODE_MS_BASED:
+                        mode = "MS_BASED";
+                        break;
+                    default:
+                        mode = "unknown";
+                        break;
+                }
+                Log.d(TAG, "setting position_mode to " + mode);
+            }
+
+            int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
+            if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
+                    interval, 0, 0)) {
+                mStarted = false;
+                Log.e(TAG, "set_position_mode failed in startNavigating()");
+                return;
+            }
+            if (!native_start()) {
+                mStarted = false;
+                Log.e(TAG, "native_start failed in startNavigating()");
+                return;
+            }
+
+            // reset SV count to zero
+            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
+            mFixRequestTime = System.currentTimeMillis();
+            if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
+                // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
+                // and our fix interval is not short
+                if (mFixInterval >= NO_FIX_TIMEOUT) {
+                    mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                            SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
+                }
+            }
+        }
+    }
+
+    private void stopNavigating() {
+        if (DEBUG) Log.d(TAG, "stopNavigating");
+        if (mStarted) {
+            mStarted = false;
+            mSingleShot = false;
+            native_stop();
+            mTimeToFirstFix = 0;
+            mLastFixTime = 0;
+            mLocationFlags = LOCATION_INVALID;
+
+            // reset SV count to zero
+            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
+        }
+    }
+
+    private void hibernate() {
+        // stop GPS until our next fix interval arrives
+        stopNavigating();
+        mAlarmManager.cancel(mTimeoutIntent);
+        mAlarmManager.cancel(mWakeupIntent);
+        long now = SystemClock.elapsedRealtime();
+        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
+    }
+
+    private boolean hasCapability(int capability) {
+        return ((mEngineCapabilities & capability) != 0);
+    }
+
+
+    /**
+     * called from native code to update our position.
+     */
+    private void reportLocation(int flags, double latitude, double longitude, double altitude,
+            float speed, float bearing, float accuracy, long timestamp) {
+        if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude +
+                " timestamp: " + timestamp);
+
+        synchronized (mLocation) {
+            mLocationFlags = flags;
+            if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
+                mLocation.setLatitude(latitude);
+                mLocation.setLongitude(longitude);
+                mLocation.setTime(timestamp);
+                // It would be nice to push the elapsed real-time timestamp
+                // further down the stack, but this is still useful
+                mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
+            }
+            if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
+                mLocation.setAltitude(altitude);
+            } else {
+                mLocation.removeAltitude();
+            }
+            if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
+                mLocation.setSpeed(speed);
+            } else {
+                mLocation.removeSpeed();
+            }
+            if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
+                mLocation.setBearing(bearing);
+            } else {
+                mLocation.removeBearing();
+            }
+            if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
+                mLocation.setAccuracy(accuracy);
+            } else {
+                mLocation.removeAccuracy();
+            }
+            mLocation.setExtras(mLocationExtras);
+
+            try {
+                mILocationManager.reportLocation(mLocation, false);
+            } catch (RemoteException e) {
+                Log.e(TAG, "RemoteException calling reportLocation");
+            }
+        }
+
+        mLastFixTime = System.currentTimeMillis();
+        // report time to first fix
+        if (mTimeToFirstFix == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
+            mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime);
+            if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
+
+            // notify status listeners
+            mListenerHelper.onFirstFix(mTimeToFirstFix);
+        }
+
+        if (mSingleShot) {
+            stopNavigating();
+        }
+
+        if (mStarted && mStatus != LocationProvider.AVAILABLE) {
+            // we want to time out if we do not receive a fix
+            // within the time out and we are requesting infrequent fixes
+            if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
+                mAlarmManager.cancel(mTimeoutIntent);
+            }
+
+            // send an intent to notify that the GPS is receiving fixes.
+            Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
+            intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
+            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+            updateStatus(LocationProvider.AVAILABLE, mSvCount);
+        }
+
+       if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
+               mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
+            if (DEBUG) Log.d(TAG, "got fix, hibernating");
+            hibernate();
+        }
+   }
+
+    /**
+     * called from native code to update our status
+     */
+    private void reportStatus(int status) {
+        if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
+
+        boolean wasNavigating = mNavigating;
+        switch (status) {
+            case GPS_STATUS_SESSION_BEGIN:
+                mNavigating = true;
+                mEngineOn = true;
+                break;
+            case GPS_STATUS_SESSION_END:
+                mNavigating = false;
+                break;
+            case GPS_STATUS_ENGINE_ON:
+                mEngineOn = true;
+                break;
+            case GPS_STATUS_ENGINE_OFF:
+                mEngineOn = false;
+                mNavigating = false;
+                break;
+        }
+
+        if (wasNavigating != mNavigating) {
+            mListenerHelper.onStatusChanged(mNavigating);
+
+            // send an intent to notify that the GPS has been enabled or disabled
+            Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
+            intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
+            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+        }
+    }
+
+    /**
+     * called from native code to update SV info
+     */
+    private void reportSvStatus() {
+        int svCount = native_read_sv_status(mPrnWithFlags, mSnrs, mSvElevations, mSvAzimuths,
+                mConstellationTypes);
+        mListenerHelper.onSvStatusChanged(
+                svCount,
+                mPrnWithFlags,
+                mSnrs,
+                mSvElevations,
+                mSvAzimuths,
+                mConstellationTypes);
+
+        if (VERBOSE) {
+            Log.v(TAG, "SV count: " + svCount);
+        }
+        // Calculate number of sets used in fix.
+        int usedInFixCount = 0;
+        for (int i = 0; i < svCount; i++) {
+            if ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
+                ++usedInFixCount;
+            }
+            if (VERBOSE) {
+                Log.v(TAG, "prn: " + (mPrnWithFlags[i] >> GnssStatus.PRN_SHIFT_WIDTH) +
+                        " snr: " + mSnrs[i]/10 +
+                        " elev: " + mSvElevations[i] +
+                        " azimuth: " + mSvAzimuths[i] +
+                        ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
+                                ? "  " : " E") +
+                        ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0
+                                ? "  " : " A") +
+                        ((mPrnWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
+                                ? "" : "U"));
+            }
+        }
+        // return number of sets used in fix instead of total
+        updateStatus(mStatus, usedInFixCount);
+
+        if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
+            System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) {
+            // send an intent to notify that the GPS is no longer receiving fixes.
+            Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
+            intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
+            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount);
+        }
+    }
+
+    /**
+     * called from native code to update AGPS status
+     */
+    private void reportAGpsStatus(int type, int status, byte[] ipaddr) {
+        switch (status) {
+            case GPS_REQUEST_AGPS_DATA_CONN:
+                if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
+                Log.v(TAG, "Received SUPL IP addr[]: " + Arrays.toString(ipaddr));
+                InetAddress connectionIpAddress = null;
+                if (ipaddr != null) {
+                    try {
+                        connectionIpAddress = InetAddress.getByAddress(ipaddr);
+                        if (DEBUG) Log.d(TAG, "IP address converted to: " + connectionIpAddress);
+                    } catch (UnknownHostException e) {
+                        Log.e(TAG, "Bad IP Address: " + ipaddr, e);
+                    }
+                }
+                sendMessage(REQUEST_SUPL_CONNECTION, 0 /*arg*/, connectionIpAddress);
+                break;
+            case GPS_RELEASE_AGPS_DATA_CONN:
+                if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
+                releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
+                break;
+            case GPS_AGPS_DATA_CONNECTED:
+                if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
+                break;
+            case GPS_AGPS_DATA_CONN_DONE:
+                if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
+                break;
+            case GPS_AGPS_DATA_CONN_FAILED:
+                if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
+                break;
+            default:
+                Log.d(TAG, "Received Unknown AGPS status: " + status);
+        }
+    }
+
+    private void releaseSuplConnection(int connStatus) {
+        sendMessage(RELEASE_SUPL_CONNECTION, connStatus, null /*obj*/);
+    }
+
+    /**
+     * called from native code to report NMEA data received
+     */
+    private void reportNmea(long timestamp) {
+        int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
+        String nmea = new String(mNmeaBuffer, 0 /* offset */, length);
+        mListenerHelper.onNmeaReceived(timestamp, nmea);
+    }
+
+    /**
+     * called from native code - Gps measurements callback
+     */
+    private void reportMeasurementData(GpsMeasurementsEvent event) {
+        mGpsMeasurementsProvider.onMeasurementsAvailable(event);
+    }
+
+    /**
+     * called from native code - GPS navigation message callback
+     */
+    private void reportNavigationMessage(GpsNavigationMessageEvent event) {
+        mGpsNavigationMessageProvider.onNavigationMessageAvailable(event);
+    }
+
+    /**
+     * called from native code to inform us what the GPS engine capabilities are
+     */
+    private void setEngineCapabilities(int capabilities) {
+        mEngineCapabilities = capabilities;
+
+        if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
+            mOnDemandTimeInjection = true;
+            requestUtcTime();
+        }
+
+        mGpsMeasurementsProvider.onCapabilitiesUpdated(
+                (capabilities & GPS_CAPABILITY_MEASUREMENTS) == GPS_CAPABILITY_MEASUREMENTS);
+        mGpsNavigationMessageProvider.onCapabilitiesUpdated(
+                (capabilities & GPS_CAPABILITY_NAV_MESSAGES) == GPS_CAPABILITY_NAV_MESSAGES);
+    }
+
+    /**
+     * Called from native code to inform us the hardware information.
+     */
+    private void setGpsYearOfHardware(int yearOfHardware) {
+        if (DEBUG) Log.d(TAG, "setGpsYearOfHardware called with " + yearOfHardware);
+        mYearOfHardware = yearOfHardware;
+    }
+
+    public interface GpsSystemInfoProvider {
+        /**
+         * Returns the year of GPS hardware.
+         */
+        int getGpsYearOfHardware();
+    }
+
+    /**
+     * @hide
+     */
+    public GpsSystemInfoProvider getGpsSystemInfoProvider() {
+        return new GpsSystemInfoProvider() {
+            @Override
+            public int getGpsYearOfHardware() {
+                return mYearOfHardware;
+            }
+        };
+    }
+
+    /**
+     * called from native code to request XTRA data
+     */
+    private void xtraDownloadRequest() {
+        if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
+        sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
+    }
+
+    /**
+     * Helper method to construct a location object.
+     */
+    private Location buildLocation(
+            int flags,
+            double latitude,
+            double longitude,
+            double altitude,
+            float speed,
+            float bearing,
+            float accuracy,
+            long timestamp) {
+        Location location = new Location(LocationManager.GPS_PROVIDER);
+        if((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
+            location.setLatitude(latitude);
+            location.setLongitude(longitude);
+            location.setTime(timestamp);
+            location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
+        }
+        if((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
+            location.setAltitude(altitude);
+        }
+        if((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
+            location.setSpeed(speed);
+        }
+        if((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
+            location.setBearing(bearing);
+        }
+        if((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
+            location.setAccuracy(accuracy);
+        }
+        return location;
+    }
+
+    /**
+     * Converts the GPS HAL status to the internal Geofence Hardware status.
+     */
+    private int getGeofenceStatus(int status) {
+        switch(status) {
+            case GPS_GEOFENCE_OPERATION_SUCCESS:
+                return GeofenceHardware.GEOFENCE_SUCCESS;
+            case GPS_GEOFENCE_ERROR_GENERIC:
+                return GeofenceHardware.GEOFENCE_FAILURE;
+            case GPS_GEOFENCE_ERROR_ID_EXISTS:
+                return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
+            case GPS_GEOFENCE_ERROR_INVALID_TRANSITION:
+                return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
+            case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES:
+                return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
+            case GPS_GEOFENCE_ERROR_ID_UNKNOWN:
+                return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
+            default:
+                return -1;
+        }
+    }
+
+    /**
+     * Called from native to report GPS Geofence transition
+     * All geofence callbacks are called on the same thread
+     */
+    private void reportGeofenceTransition(int geofenceId, int flags, double latitude,
+            double longitude, double altitude, float speed, float bearing, float accuracy,
+            long timestamp, int transition, long transitionTimestamp) {
+        if (mGeofenceHardwareImpl == null) {
+            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+        }
+        Location location = buildLocation(
+                flags,
+                latitude,
+                longitude,
+                altitude,
+                speed,
+                bearing,
+                accuracy,
+                timestamp);
+        mGeofenceHardwareImpl.reportGeofenceTransition(
+                geofenceId,
+                location,
+                transition,
+                transitionTimestamp,
+                GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
+                FusedBatchOptions.SourceTechnologies.GNSS);
+    }
+
+    /**
+     * called from native code to report GPS status change.
+     */
+    private void reportGeofenceStatus(int status, int flags, double latitude,
+            double longitude, double altitude, float speed, float bearing, float accuracy,
+            long timestamp) {
+        if (mGeofenceHardwareImpl == null) {
+            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+        }
+        Location location = buildLocation(
+                flags,
+                latitude,
+                longitude,
+                altitude,
+                speed,
+                bearing,
+                accuracy,
+                timestamp);
+        int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
+        if(status == GPS_GEOFENCE_AVAILABLE) {
+            monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
+        }
+        mGeofenceHardwareImpl.reportGeofenceMonitorStatus(
+                GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
+                monitorStatus,
+                location,
+                FusedBatchOptions.SourceTechnologies.GNSS);
+    }
+
+    /**
+     * called from native code - Geofence Add callback
+     */
+    private void reportGeofenceAddStatus(int geofenceId, int status) {
+        if (mGeofenceHardwareImpl == null) {
+            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+        }
+        mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status));
+    }
+
+    /**
+     * called from native code - Geofence Remove callback
+     */
+    private void reportGeofenceRemoveStatus(int geofenceId, int status) {
+        if (mGeofenceHardwareImpl == null) {
+            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+        }
+        mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status));
+    }
+
+    /**
+     * called from native code - Geofence Pause callback
+     */
+    private void reportGeofencePauseStatus(int geofenceId, int status) {
+        if (mGeofenceHardwareImpl == null) {
+            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+        }
+        mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status));
+    }
+
+    /**
+     * called from native code - Geofence Resume callback
+     */
+    private void reportGeofenceResumeStatus(int geofenceId, int status) {
+        if (mGeofenceHardwareImpl == null) {
+            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+        }
+        mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status));
+    }
+
+    //=============================================================
+    // NI Client support
+    //=============================================================
+    private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
+        // Sends a response for an NI request to HAL.
+        @Override
+        public boolean sendNiResponse(int notificationId, int userResponse)
+        {
+            // TODO Add Permission check
+
+            if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
+                    ", response: " + userResponse);
+            native_send_ni_response(notificationId, userResponse);
+            return true;
+        }
+    };
+
+    public INetInitiatedListener getNetInitiatedListener() {
+        return mNetInitiatedListener;
+    }
+
+    // Called by JNI function to report an NI request.
+    public void reportNiNotification(
+            int notificationId,
+            int niType,
+            int notifyFlags,
+            int timeout,
+            int defaultResponse,
+            String requestorId,
+            String text,
+            int requestorIdEncoding,
+            int textEncoding,
+            String extras  // Encoded extra data
+        )
+    {
+        Log.i(TAG, "reportNiNotification: entered");
+        Log.i(TAG, "notificationId: " + notificationId +
+                ", niType: " + niType +
+                ", notifyFlags: " + notifyFlags +
+                ", timeout: " + timeout +
+                ", defaultResponse: " + defaultResponse);
+
+        Log.i(TAG, "requestorId: " + requestorId +
+                ", text: " + text +
+                ", requestorIdEncoding: " + requestorIdEncoding +
+                ", textEncoding: " + textEncoding);
+
+        GpsNiNotification notification = new GpsNiNotification();
+
+        notification.notificationId = notificationId;
+        notification.niType = niType;
+        notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
+        notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
+        notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
+        notification.timeout = timeout;
+        notification.defaultResponse = defaultResponse;
+        notification.requestorId = requestorId;
+        notification.text = text;
+        notification.requestorIdEncoding = requestorIdEncoding;
+        notification.textEncoding = textEncoding;
+
+        // Process extras, assuming the format is
+        // one of more lines of "key = value"
+        Bundle bundle = new Bundle();
+
+        if (extras == null) extras = "";
+        Properties extraProp = new Properties();
+
+        try {
+            extraProp.load(new StringReader(extras));
+        }
+        catch (IOException e)
+        {
+            Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras);
+        }
+
+        for (Entry<Object, Object> ent : extraProp.entrySet())
+        {
+            bundle.putString((String) ent.getKey(), (String) ent.getValue());
+        }
+
+        notification.extras = bundle;
+
+        mNIHandler.handleNiNotification(notification);
+    }
+
+    /**
+     * Called from native code to request set id info.
+     * We should be careful about receiving null string from the TelephonyManager,
+     * because sending null String to JNI function would cause a crash.
+     */
+
+    private void requestSetID(int flags) {
+        TelephonyManager phone = (TelephonyManager)
+                mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        int type = AGPS_SETID_TYPE_NONE;
+        String data = "";
+
+        if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
+            String data_temp = phone.getSubscriberId();
+            if (data_temp == null) {
+                // This means the framework does not have the SIM card ready.
+            } else {
+                // This means the framework has the SIM card.
+                data = data_temp;
+                type = AGPS_SETID_TYPE_IMSI;
+            }
+        }
+        else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
+            String data_temp = phone.getLine1Number();
+            if (data_temp == null) {
+                // This means the framework does not have the SIM card ready.
+            } else {
+                // This means the framework has the SIM card.
+                data = data_temp;
+                type = AGPS_SETID_TYPE_MSISDN;
+            }
+        }
+        native_agps_set_id(type, data);
+    }
+
+    /**
+     * Called from native code to request utc time info
+     */
+    private void requestUtcTime() {
+        if (DEBUG) Log.d(TAG, "utcTimeRequest");
+        sendMessage(INJECT_NTP_TIME, 0, null);
+    }
+
+    /**
+     * Called from native code to request reference location info
+     */
+
+    private void requestRefLocation(int flags) {
+        TelephonyManager phone = (TelephonyManager)
+                mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        final int phoneType = phone.getPhoneType();
+        if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
+            GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation();
+            if ((gsm_cell != null) && (phone.getNetworkOperator() != null)
+                    && (phone.getNetworkOperator().length() > 3)) {
+                int type;
+                int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3));
+                int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3));
+                int networkType = phone.getNetworkType();
+                if (networkType == TelephonyManager.NETWORK_TYPE_UMTS
+                    || networkType == TelephonyManager.NETWORK_TYPE_HSDPA
+                    || networkType == TelephonyManager.NETWORK_TYPE_HSUPA
+                    || networkType == TelephonyManager.NETWORK_TYPE_HSPA
+                    || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) {
+                    type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
+                } else {
+                    type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
+                }
+                native_agps_set_ref_location_cellid(type, mcc, mnc,
+                        gsm_cell.getLac(), gsm_cell.getCid());
+            } else {
+                Log.e(TAG,"Error getting cell location info.");
+            }
+        } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
+            Log.e(TAG, "CDMA not supported.");
+        }
+    }
+
+    private void sendMessage(int message, int arg, Object obj) {
+        // hold a wake lock until this message is delivered
+        // note that this assumes the message will not be removed from the queue before
+        // it is handled (otherwise the wake lock would be leaked).
+        mWakeLock.acquire();
+        mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
+    }
+
+    private final class ProviderHandler extends Handler {
+        public ProviderHandler(Looper looper) {
+            super(looper, null, true /*async*/);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            int message = msg.what;
+            switch (message) {
+                case ENABLE:
+                    if (msg.arg1 == 1) {
+                        handleEnable();
+                    } else {
+                        handleDisable();
+                    }
+                    break;
+                case SET_REQUEST:
+                    GpsRequest gpsRequest = (GpsRequest) msg.obj;
+                    handleSetRequest(gpsRequest.request, gpsRequest.source);
+                    break;
+                case UPDATE_NETWORK_STATE:
+                    handleUpdateNetworkState((Network) msg.obj);
+                    break;
+                case REQUEST_SUPL_CONNECTION:
+                    handleRequestSuplConnection((InetAddress) msg.obj);
+                    break;
+                case RELEASE_SUPL_CONNECTION:
+                    handleReleaseSuplConnection(msg.arg1);
+                    break;
+                case INJECT_NTP_TIME:
+                    handleInjectNtpTime();
+                    break;
+                case DOWNLOAD_XTRA_DATA:
+                    if (mSupportsXtra) {
+                        handleDownloadXtraData();
+                    }
+                    break;
+                case INJECT_NTP_TIME_FINISHED:
+                    mInjectNtpTimePending = STATE_IDLE;
+                    break;
+                case DOWNLOAD_XTRA_DATA_FINISHED:
+                    mDownloadXtraDataPending = STATE_IDLE;
+                    break;
+                case UPDATE_LOCATION:
+                    handleUpdateLocation((Location) msg.obj);
+                    break;
+                case SUBSCRIPTION_OR_SIM_CHANGED:
+                    subscriptionOrSimChanged(mContext);
+                    break;
+                case INITIALIZE_HANDLER:
+                    handleInitialize();
+                    break;
+            }
+            if (msg.arg2 == 1) {
+                // wakelock was taken for this message, release it
+                mWakeLock.release();
+            }
+        }
+
+        /**
+         * This method is bound to {@link #GnssLocationProvider(Context, ILocationManager, Looper)}.
+         * It is in charge of loading properties and registering for events that will be posted to
+         * this handler.
+         */
+        private void handleInitialize() {
+            // load default GPS configuration
+            // (this configuration might change in the future based on SIM changes)
+            reloadGpsProperties(mContext, mProperties);
+
+            // TODO: When this object "finishes" we should unregister by invoking
+            // SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener);
+            // This is not strictly necessary because it will be unregistered if the
+            // notification fails but it is good form.
+
+            // Register for SubscriptionInfo list changes which is guaranteed
+            // to invoke onSubscriptionsChanged the first time.
+            SubscriptionManager.from(mContext)
+                    .addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
+
+            // listen for events
+            IntentFilter intentFilter;
+            if (native_is_agps_ril_supported()) {
+                intentFilter = new IntentFilter();
+                intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION);
+                intentFilter.addDataScheme("sms");
+                intentFilter.addDataAuthority("localhost", "7275");
+                mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
+
+                intentFilter = new IntentFilter();
+                intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION);
+                try {
+                    intentFilter.addDataType("application/vnd.omaloc-supl-init");
+                } catch (IntentFilter.MalformedMimeTypeException e) {
+                    Log.w(TAG, "Malformed SUPL init mime type");
+                }
+                mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
+            } else if (DEBUG) {
+                Log.d(TAG, "Skipped registration for SMS/WAP-PUSH messages because AGPS Ril in GPS"
+                        + " HAL is not supported");
+            }
+
+            intentFilter = new IntentFilter();
+            intentFilter.addAction(ALARM_WAKEUP);
+            intentFilter.addAction(ALARM_TIMEOUT);
+            intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+            intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
+            intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
+            intentFilter.addAction(Intent.ACTION_SCREEN_ON);
+            intentFilter.addAction(SIM_STATE_CHANGED);
+            mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
+
+            // register for connectivity change events, this is equivalent to the deprecated way of
+            // registering for CONNECTIVITY_ACTION broadcasts
+            NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
+            networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+            networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+            NetworkRequest networkRequest = networkRequestBuilder.build();
+            mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback);
+
+            // listen for PASSIVE_PROVIDER updates
+            LocationManager locManager =
+                    (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
+            long minTime = 0;
+            float minDistance = 0;
+            boolean oneShot = false;
+            LocationRequest request = LocationRequest.createFromDeprecatedProvider(
+                    LocationManager.PASSIVE_PROVIDER,
+                    minTime,
+                    minDistance,
+                    oneShot);
+            // Don't keep track of this request since it's done on behalf of other clients
+            // (which are kept track of separately).
+            request.setHideFromAppOps(true);
+            locManager.requestLocationUpdates(
+                    request,
+                    new NetworkLocationListener(),
+                    getLooper());
+        }
+    }
+
+    private final class NetworkLocationListener implements LocationListener {
+        @Override
+        public void onLocationChanged(Location location) {
+            // this callback happens on mHandler looper
+            if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
+                handleUpdateLocation(location);
+            }
+        }
+        @Override
+        public void onStatusChanged(String provider, int status, Bundle extras) { }
+        @Override
+        public void onProviderEnabled(String provider) { }
+        @Override
+        public void onProviderDisabled(String provider) { }
+    }
+
+    private String getSelectedApn() {
+        Uri uri = Uri.parse("content://telephony/carriers/preferapn");
+        Cursor cursor = null;
+        try {
+            cursor = mContext.getContentResolver().query(
+                    uri,
+                    new String[] { "apn" },
+                    null /* selection */,
+                    null /* selectionArgs */,
+                    Carriers.DEFAULT_SORT_ORDER);
+            if (cursor != null && cursor.moveToFirst()) {
+                return cursor.getString(0);
+            } else {
+                Log.e(TAG, "No APN found to select.");
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Error encountered on selecting the APN.", e);
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+        }
+
+        return null;
+    }
+
+    private int getApnIpType(String apn) {
+        ensureInHandlerThread();
+        if (apn == null) {
+            return APN_INVALID;
+        }
+
+        String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn);
+        Cursor cursor = null;
+        try {
+            cursor = mContext.getContentResolver().query(
+                    Carriers.CONTENT_URI,
+                    new String[] { Carriers.PROTOCOL },
+                    selection,
+                    null,
+                    Carriers.DEFAULT_SORT_ORDER);
+
+            if (null != cursor && cursor.moveToFirst()) {
+                return translateToApnIpType(cursor.getString(0), apn);
+            } else {
+                Log.e(TAG, "No entry found in query for APN: " + apn);
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Error encountered on APN query for: " + apn, e);
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+        }
+
+        return APN_INVALID;
+    }
+
+    private int translateToApnIpType(String ipProtocol, String apn) {
+        if ("IP".equals(ipProtocol)) {
+            return APN_IPV4;
+        }
+        if ("IPV6".equals(ipProtocol)) {
+            return APN_IPV6;
+        }
+        if ("IPV4V6".equals(ipProtocol)) {
+            return APN_IPV4V6;
+        }
+
+        // we hit the default case so the ipProtocol is not recognized
+        String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn);
+        Log.e(TAG, message);
+        return APN_INVALID;
+    }
+
+    private void setRouting() {
+        if (mAGpsDataConnectionIpAddr == null) {
+            return;
+        }
+
+        // TODO: replace the use of this deprecated API
+        boolean result = mConnMgr.requestRouteToHostAddress(
+                ConnectivityManager.TYPE_MOBILE_SUPL,
+                mAGpsDataConnectionIpAddr);
+
+        if (!result) {
+            Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr);
+        } else if (DEBUG) {
+            Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr);
+        }
+    }
+
+    /**
+     * @return {@code true} if there is a data network available for outgoing connections,
+     *         {@code false} otherwise.
+     */
+    private boolean isDataNetworkConnected() {
+        NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo();
+        return activeNetworkInfo != null && activeNetworkInfo.isConnected();
+    }
+
+    /**
+     * Ensures the calling function is running in the thread associated with {@link #mHandler}.
+     */
+    private void ensureInHandlerThread() {
+        if (mHandler != null && Looper.myLooper() == mHandler.getLooper()) {
+            return;
+        }
+        throw new RuntimeException("This method must run on the Handler thread.");
+    }
+
+    /**
+     * @return A string representing the current state stored in {@link #mAGpsDataConnectionState}.
+     */
+    private String agpsDataConnStateAsString() {
+        switch(mAGpsDataConnectionState) {
+            case AGPS_DATA_CONNECTION_CLOSED:
+                return "CLOSED";
+            case AGPS_DATA_CONNECTION_OPEN:
+                return "OPEN";
+            case AGPS_DATA_CONNECTION_OPENING:
+                return "OPENING";
+            default:
+                return "<Unknown>";
+        }
+    }
+
+    /**
+     * @return A string representing the given GPS_AGPS_DATA status.
+     */
+    private String agpsDataConnStatusAsString(int agpsDataConnStatus) {
+        switch (agpsDataConnStatus) {
+            case GPS_AGPS_DATA_CONNECTED:
+                return "CONNECTED";
+            case GPS_AGPS_DATA_CONN_DONE:
+                return "DONE";
+            case GPS_AGPS_DATA_CONN_FAILED:
+                return "FAILED";
+            case GPS_RELEASE_AGPS_DATA_CONN:
+                return "RELEASE";
+            case GPS_REQUEST_AGPS_DATA_CONN:
+                return "REQUEST";
+            default:
+                return "<Unknown>";
+        }
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        StringBuilder s = new StringBuilder();
+        s.append("  mFixInterval=").append(mFixInterval).append('\n');
+        s.append("  mDisableGps (battery saver mode)=").append(mDisableGps).append('\n');
+        s.append("  mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities));
+        s.append(" ( ");
+        if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHEDULING ");
+        if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
+        if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA ");
+        if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT ");
+        if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME ");
+        if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING ");
+        if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS ");
+        if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
+        s.append(")\n");
+
+        s.append(native_get_internal_state());
+        pw.append(s);
+    }
+
+    /**
+     * A simple implementation of exponential backoff.
+     */
+    private static final class BackOff {
+        private static final int MULTIPLIER = 2;
+        private final long mInitIntervalMillis;
+        private final long mMaxIntervalMillis;
+        private long mCurrentIntervalMillis;
+
+        public BackOff(long initIntervalMillis, long maxIntervalMillis) {
+            mInitIntervalMillis = initIntervalMillis;
+            mMaxIntervalMillis = maxIntervalMillis;
+
+            mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
+        }
+
+        public long nextBackoffMillis() {
+            if (mCurrentIntervalMillis > mMaxIntervalMillis) {
+                return mMaxIntervalMillis;
+            }
+
+            mCurrentIntervalMillis *= MULTIPLIER;
+            return mCurrentIntervalMillis;
+        }
+
+        public void reset() {
+            mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
+        }
+    }
+
+    // for GPS SV statistics
+    private static final int MAX_SVS = 512;
+
+    // preallocated arrays, to avoid memory allocation in reportStatus()
+    private int mPrnWithFlags[] = new int[MAX_SVS];
+    private float mSnrs[] = new float[MAX_SVS];
+    private float mSvElevations[] = new float[MAX_SVS];
+    private float mSvAzimuths[] = new float[MAX_SVS];
+    private int mConstellationTypes[] = new int[MAX_SVS];
+    private int mSvCount;
+    // preallocated to avoid memory allocation in reportNmea()
+    private byte[] mNmeaBuffer = new byte[120];
+
+    static { class_init_native(); }
+    private static native void class_init_native();
+    private static native boolean native_is_supported();
+    private static native boolean native_is_agps_ril_supported();
+    private static native boolean native_is_gnss_configuration_supported();
+
+    private native boolean native_init();
+    private native void native_cleanup();
+    private native boolean native_set_position_mode(int mode, int recurrence, int min_interval,
+            int preferred_accuracy, int preferred_time);
+    private native boolean native_start();
+    private native boolean native_stop();
+    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,
+            float[] azimuths, int[] constellationTypes);
+    private native int native_read_nmea(byte[] buffer, int bufferSize);
+    private native void native_inject_location(double latitude, double longitude, float accuracy);
+
+    // XTRA Support
+    private native void native_inject_time(long time, long timeReference, int uncertainty);
+    private native boolean native_supports_xtra();
+    private native void native_inject_xtra_data(byte[] data, int length);
+
+    // DEBUG Support
+    private native String native_get_internal_state();
+
+    // AGPS Support
+    private native void native_agps_data_conn_open(String apn, int apnIpType);
+    private native void native_agps_data_conn_closed();
+    private native void native_agps_data_conn_failed();
+    private native void native_agps_ni_message(byte [] msg, int length);
+    private native void native_set_agps_server(int type, String hostname, int port);
+
+    // Network-initiated (NI) Support
+    private native void native_send_ni_response(int notificationId, int userResponse);
+
+    // AGPS ril suport
+    private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
+            int lac, int cid);
+    private native void native_agps_set_id(int type, String setid);
+
+    private native void native_update_network_state(boolean connected, int type,
+            boolean roaming, boolean available, String extraInfo, String defaultAPN);
+
+    // Hardware Geofence support.
+    private static native boolean native_is_geofence_supported();
+    private static native boolean native_add_geofence(int geofenceId, double latitude,
+            double longitude, double radius, int lastTransition,int monitorTransitions,
+            int notificationResponsivenes, int unknownTimer);
+    private static native boolean native_remove_geofence(int geofenceId);
+    private static native boolean native_resume_geofence(int geofenceId, int transitions);
+    private static native boolean native_pause_geofence(int geofenceId);
+
+    // Gps Hal measurements support.
+    private static native boolean native_is_measurement_supported();
+    private native boolean native_start_measurement_collection();
+    private native boolean native_stop_measurement_collection();
+
+    // Gps Navigation message support.
+    private static native boolean native_is_navigation_message_supported();
+    private native boolean native_start_navigation_message_collection();
+    private native boolean native_stop_navigation_message_collection();
+
+    // GNSS Configuration
+    private static native void native_configuration_update(String configData);
+}
diff --git a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
new file mode 100644
index 0000000..9840c61
--- /dev/null
+++ b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.location;
+
+import android.location.IGnssStatusListener;
+import android.os.Handler;
+import android.os.RemoteException;
+
+/**
+ * Implementation of a handler for {@link IGnssStatusListener}.
+ */
+abstract class GnssStatusListenerHelper extends RemoteListenerHelper<IGnssStatusListener> {
+    protected GnssStatusListenerHelper(Handler handler) {
+        super(handler, "GnssStatusListenerHelper");
+        setSupported(GnssLocationProvider.isSupported());
+    }
+
+    @Override
+    protected boolean registerWithService() {
+        return true;
+    }
+
+    @Override
+    protected void unregisterFromService() {}
+
+    @Override
+    protected ListenerOperation<IGnssStatusListener> getHandlerOperation(int result) {
+        return null;
+    }
+
+    public void onStatusChanged(boolean isNavigating) {
+        Operation operation;
+        if (isNavigating) {
+            operation = new Operation() {
+                @Override
+                public void execute(IGnssStatusListener listener) throws RemoteException {
+                    listener.onGnssStarted();
+                }
+            };
+        } else {
+            operation = new Operation() {
+                @Override
+                public void execute(IGnssStatusListener listener) throws RemoteException {
+                    listener.onGnssStopped();
+                }
+            };
+        }
+        foreach(operation);
+    }
+
+    public void onFirstFix(final int timeToFirstFix) {
+        Operation operation = new Operation() {
+            @Override
+            public void execute(IGnssStatusListener listener) throws RemoteException {
+                listener.onFirstFix(timeToFirstFix);
+            }
+        };
+        foreach(operation);
+    }
+
+    public void onSvStatusChanged(
+            final int svCount,
+            final int[] prnWithFlags,
+            final float[] snrs,
+            final float[] elevations,
+            final float[] azimuths,
+            final int[] constellationTypes) {
+        Operation operation = new Operation() {
+            @Override
+            public void execute(IGnssStatusListener listener) throws RemoteException {
+                listener.onSvStatusChanged(
+                        svCount,
+                        prnWithFlags,
+                        snrs,
+                        elevations,
+                        azimuths,
+                        constellationTypes);
+            }
+        };
+        foreach(operation);
+    }
+
+    public void onNmeaReceived(final long timestamp, final String nmea) {
+        Operation operation = new Operation() {
+            @Override
+            public void execute(IGnssStatusListener listener) throws RemoteException {
+                listener.onNmeaReceived(timestamp, nmea);
+            }
+        };
+        foreach(operation);
+    }
+
+    private interface Operation extends ListenerOperation<IGnssStatusListener> {}
+}
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
deleted file mode 100644
index 88ab2c6..0000000
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ /dev/null
@@ -1,2447 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.location;
-
-import com.android.internal.app.IAppOpsService;
-import com.android.internal.app.IBatteryStats;
-import com.android.internal.location.GpsNetInitiatedHandler;
-import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
-import com.android.internal.location.ProviderProperties;
-import com.android.internal.location.ProviderRequest;
-
-import android.app.AlarmManager;
-import android.app.AppOpsManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.database.Cursor;
-import android.hardware.location.GeofenceHardware;
-import android.hardware.location.GeofenceHardwareImpl;
-import android.location.Criteria;
-import android.location.FusedBatchOptions;
-import android.location.GpsMeasurementsEvent;
-import android.location.GpsNavigationMessageEvent;
-import android.location.IGpsGeofenceHardware;
-import android.location.IGpsStatusListener;
-import android.location.IGpsStatusProvider;
-import android.location.ILocationManager;
-import android.location.INetInitiatedListener;
-import android.location.Location;
-import android.location.LocationListener;
-import android.location.LocationManager;
-import android.location.LocationProvider;
-import android.location.LocationRequest;
-import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkRequest;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.BatteryStats;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.os.WorkSource;
-import android.provider.Settings;
-import android.provider.Telephony.Carriers;
-import android.provider.Telephony.Sms.Intents;
-import android.telephony.SmsMessage;
-import android.telephony.SubscriptionManager;
-import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
-import android.telephony.TelephonyManager;
-import android.telephony.gsm.GsmCellLocation;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.NtpTrustedTime;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringReader;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.Map.Entry;
-import java.util.Properties;
-
-import libcore.io.IoUtils;
-
-/**
- * A GPS implementation of LocationProvider used by LocationManager.
- *
- * {@hide}
- */
-public class GpsLocationProvider implements LocationProviderInterface {
-
-    private static final String TAG = "GpsLocationProvider";
-
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
-
-    private static final ProviderProperties PROPERTIES = new ProviderProperties(
-            true, true, false, false, true, true, true,
-            Criteria.POWER_HIGH, Criteria.ACCURACY_FINE);
-
-    // these need to match GpsPositionMode enum in gps.h
-    private static final int GPS_POSITION_MODE_STANDALONE = 0;
-    private static final int GPS_POSITION_MODE_MS_BASED = 1;
-    private static final int GPS_POSITION_MODE_MS_ASSISTED = 2;
-
-    // these need to match GpsPositionRecurrence enum in gps.h
-    private static final int GPS_POSITION_RECURRENCE_PERIODIC = 0;
-    private static final int GPS_POSITION_RECURRENCE_SINGLE = 1;
-
-    // these need to match GpsStatusValue defines in gps.h
-    private static final int GPS_STATUS_NONE = 0;
-    private static final int GPS_STATUS_SESSION_BEGIN = 1;
-    private static final int GPS_STATUS_SESSION_END = 2;
-    private static final int GPS_STATUS_ENGINE_ON = 3;
-    private static final int GPS_STATUS_ENGINE_OFF = 4;
-
-    // these need to match GpsApgsStatusValue defines in gps.h
-    /** AGPS status event values. */
-    private static final int GPS_REQUEST_AGPS_DATA_CONN = 1;
-    private static final int GPS_RELEASE_AGPS_DATA_CONN = 2;
-    private static final int GPS_AGPS_DATA_CONNECTED = 3;
-    private static final int GPS_AGPS_DATA_CONN_DONE = 4;
-    private static final int GPS_AGPS_DATA_CONN_FAILED = 5;
-
-    // these need to match GpsLocationFlags enum in gps.h
-    private static final int LOCATION_INVALID = 0;
-    private static final int LOCATION_HAS_LAT_LONG = 1;
-    private static final int LOCATION_HAS_ALTITUDE = 2;
-    private static final int LOCATION_HAS_SPEED = 4;
-    private static final int LOCATION_HAS_BEARING = 8;
-    private static final int LOCATION_HAS_ACCURACY = 16;
-
-    // IMPORTANT - the GPS_DELETE_* symbols here must match constants in gps.h
-    private static final int GPS_DELETE_EPHEMERIS = 0x0001;
-    private static final int GPS_DELETE_ALMANAC = 0x0002;
-    private static final int GPS_DELETE_POSITION = 0x0004;
-    private static final int GPS_DELETE_TIME = 0x0008;
-    private static final int GPS_DELETE_IONO = 0x0010;
-    private static final int GPS_DELETE_UTC = 0x0020;
-    private static final int GPS_DELETE_HEALTH = 0x0040;
-    private static final int GPS_DELETE_SVDIR = 0x0080;
-    private static final int GPS_DELETE_SVSTEER = 0x0100;
-    private static final int GPS_DELETE_SADATA = 0x0200;
-    private static final int GPS_DELETE_RTI = 0x0400;
-    private static final int GPS_DELETE_CELLDB_INFO = 0x8000;
-    private static final int GPS_DELETE_ALL = 0xFFFF;
-
-    // The GPS_CAPABILITY_* flags must match the values in gps.h
-    private static final int GPS_CAPABILITY_SCHEDULING = 0x0000001;
-    private static final int GPS_CAPABILITY_MSB = 0x0000002;
-    private static final int GPS_CAPABILITY_MSA = 0x0000004;
-    private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
-    private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
-    private static final int GPS_CAPABILITY_GEOFENCING = 0x0000020;
-    private static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040;
-    private static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080;
-
-    // The AGPS SUPL mode
-    private static final int AGPS_SUPL_MODE_MSA = 0x02;
-    private static final int AGPS_SUPL_MODE_MSB = 0x01;
-
-    // these need to match AGpsType enum in gps.h
-    private static final int AGPS_TYPE_SUPL = 1;
-    private static final int AGPS_TYPE_C2K = 2;
-
-    // these must match the definitions in gps.h
-    private static final int APN_INVALID = 0;
-    private static final int APN_IPV4 = 1;
-    private static final int APN_IPV6 = 2;
-    private static final int APN_IPV4V6 = 3;
-
-    // for mAGpsDataConnectionState
-    private static final int AGPS_DATA_CONNECTION_CLOSED = 0;
-    private static final int AGPS_DATA_CONNECTION_OPENING = 1;
-    private static final int AGPS_DATA_CONNECTION_OPEN = 2;
-
-    // Handler messages
-    private static final int CHECK_LOCATION = 1;
-    private static final int ENABLE = 2;
-    private static final int SET_REQUEST = 3;
-    private static final int UPDATE_NETWORK_STATE = 4;
-    private static final int INJECT_NTP_TIME = 5;
-    private static final int DOWNLOAD_XTRA_DATA = 6;
-    private static final int UPDATE_LOCATION = 7;
-    private static final int ADD_LISTENER = 8;
-    private static final int REMOVE_LISTENER = 9;
-    private static final int INJECT_NTP_TIME_FINISHED = 10;
-    private static final int DOWNLOAD_XTRA_DATA_FINISHED = 11;
-    private static final int SUBSCRIPTION_OR_SIM_CHANGED = 12;
-    private static final int INITIALIZE_HANDLER = 13;
-    private static final int REQUEST_SUPL_CONNECTION = 14;
-    private static final int RELEASE_SUPL_CONNECTION = 15;
-
-    // Request setid
-    private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
-    private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2;
-
-    // Request ref location
-    private static final int AGPS_RIL_REQUEST_REFLOC_CELLID = 1;
-    private static final int AGPS_RIL_REQUEST_REFLOC_MAC = 2;
-
-    // ref. location info
-    private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1;
-    private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2;
-    private static final int AGPS_REG_LOCATION_TYPE_MAC        = 3;
-
-    // set id info
-    private static final int AGPS_SETID_TYPE_NONE = 0;
-    private static final int AGPS_SETID_TYPE_IMSI = 1;
-    private static final int AGPS_SETID_TYPE_MSISDN = 2;
-
-    private static final String PROPERTIES_FILE_PREFIX = "/etc/gps";
-    private static final String PROPERTIES_FILE_SUFFIX = ".conf";
-    private static final String DEFAULT_PROPERTIES_FILE = PROPERTIES_FILE_PREFIX + PROPERTIES_FILE_SUFFIX;
-
-    private static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L;
-    private static final int GPS_GEOFENCE_AVAILABLE = 1<<1L;
-
-    // GPS Geofence errors. Should match gps.h constants.
-    private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0;
-    private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100;
-    private static final int GPS_GEOFENCE_ERROR_ID_EXISTS  = -101;
-    private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102;
-    private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103;
-    private static final int GPS_GEOFENCE_ERROR_GENERIC = -149;
-
-    // TCP/IP constants.
-    // Valid TCP/UDP port range is (0, 65535].
-    private static final int TCP_MIN_PORT = 0;
-    private static final int TCP_MAX_PORT = 0xffff;
-
-    // Value of batterySaverGpsMode such that GPS isn't affected by battery saver mode.
-    private static final int BATTERY_SAVER_MODE_NO_CHANGE = 0;
-    // Value of batterySaverGpsMode such that GPS is disabled when battery saver mode
-    // is enabled and the screen is off.
-    private static final int BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF = 1;
-    // Secure setting for GPS behavior when battery saver mode is on.
-    private static final String BATTERY_SAVER_GPS_MODE = "batterySaverGpsMode";
-
-    /** simpler wrapper for ProviderRequest + Worksource */
-    private static class GpsRequest {
-        public ProviderRequest request;
-        public WorkSource source;
-        public GpsRequest(ProviderRequest request, WorkSource source) {
-            this.request = request;
-            this.source = source;
-        }
-    }
-
-    private Object mLock = new Object();
-
-    private int mLocationFlags = LOCATION_INVALID;
-
-    // current status
-    private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE;
-
-    // time for last status update
-    private long mStatusUpdateTime = SystemClock.elapsedRealtime();
-
-    // turn off GPS fix icon if we haven't received a fix in 10 seconds
-    private static final long RECENT_FIX_TIMEOUT = 10 * 1000;
-
-    // stop trying if we do not receive a fix within 60 seconds
-    private static final int NO_FIX_TIMEOUT = 60 * 1000;
-
-    // if the fix interval is below this we leave GPS on,
-    // if above then we cycle the GPS driver.
-    // Typical hot TTTF is ~5 seconds, so 10 seconds seems sane.
-    private static final int GPS_POLLING_THRESHOLD_INTERVAL = 10 * 1000;
-
-    // how often to request NTP time, in milliseconds
-    // current setting 24 hours
-    private static final long NTP_INTERVAL = 24*60*60*1000;
-    // how long to wait if we have a network error in NTP or XTRA downloading
-    // the initial value of the exponential backoff
-    // current setting - 5 minutes
-    private static final long RETRY_INTERVAL = 5*60*1000;
-    // how long to wait if we have a network error in NTP or XTRA downloading
-    // the max value of the exponential backoff
-    // current setting - 4 hours
-    private static final long MAX_RETRY_INTERVAL = 4*60*60*1000;
-
-    private BackOff mNtpBackOff = new BackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL);
-    private BackOff mXtraBackOff = new BackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL);
-
-    // true if we are enabled, protected by this
-    private boolean mEnabled;
-
-    // states for injecting ntp and downloading xtra data
-    private static final int STATE_PENDING_NETWORK = 0;
-    private static final int STATE_DOWNLOADING = 1;
-    private static final int STATE_IDLE = 2;
-
-    // flags to trigger NTP or XTRA data download when network becomes available
-    // initialized to true so we do NTP and XTRA when the network comes up after booting
-    private int mInjectNtpTimePending = STATE_PENDING_NETWORK;
-    private int mDownloadXtraDataPending = STATE_PENDING_NETWORK;
-
-    // set to true if the GPS engine requested on-demand NTP time requests
-    private boolean mOnDemandTimeInjection;
-
-    // true if GPS is navigating
-    private boolean mNavigating;
-
-    // true if GPS engine is on
-    private boolean mEngineOn;
-
-    // requested frequency of fixes, in milliseconds
-    private int mFixInterval = 1000;
-
-    // true if we started navigation
-    private boolean mStarted;
-
-    // true if single shot request is in progress
-    private boolean mSingleShot;
-
-    // capabilities of the GPS engine
-    private int mEngineCapabilities;
-
-    // true if XTRA is supported
-    private boolean mSupportsXtra;
-
-    // for calculating time to first fix
-    private long mFixRequestTime = 0;
-    // time to first fix for most recent session
-    private int mTimeToFirstFix = 0;
-    // time we received our last fix
-    private long mLastFixTime;
-
-    private int mPositionMode;
-
-    // Current request from underlying location clients.
-    private ProviderRequest mProviderRequest = null;
-    // Current list of underlying location clients.
-    private WorkSource mWorkSource = null;
-    // True if gps should be disabled (used to support battery saver mode in settings).
-    private boolean mDisableGps = false;
-
-    /**
-     * Properties loaded from PROPERTIES_FILE.
-     * It must be accessed only inside {@link #mHandler}.
-     */
-    private Properties mProperties;
-
-    private String mSuplServerHost;
-    private int mSuplServerPort = TCP_MIN_PORT;
-    private String mC2KServerHost;
-    private int mC2KServerPort;
-    private boolean mSuplEsEnabled = false;
-
-    private final Context mContext;
-    private final NtpTrustedTime mNtpTime;
-    private final ILocationManager mILocationManager;
-    private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
-    private Bundle mLocationExtras = new Bundle();
-    private final GpsStatusListenerHelper mListenerHelper;
-    private final GpsMeasurementsProvider mGpsMeasurementsProvider;
-    private final GpsNavigationMessageProvider mGpsNavigationMessageProvider;
-
-    // Handler for processing events
-    private Handler mHandler;
-
-    /** It must be accessed only inside {@link #mHandler}. */
-    private int mAGpsDataConnectionState;
-    /** It must be accessed only inside {@link #mHandler}. */
-    private InetAddress mAGpsDataConnectionIpAddr;
-
-    private final ConnectivityManager mConnMgr;
-    private final GpsNetInitiatedHandler mNIHandler;
-
-    // Wakelocks
-    private final static String WAKELOCK_KEY = "GpsLocationProvider";
-    private final PowerManager.WakeLock mWakeLock;
-
-    // Alarms
-    private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
-    private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT";
-
-    // SIM/Carrier info.
-    private final static String SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
-
-    private final PowerManager mPowerManager;
-    private final AlarmManager mAlarmManager;
-    private final PendingIntent mWakeupIntent;
-    private final PendingIntent mTimeoutIntent;
-
-    private final IAppOpsService mAppOpsService;
-    private final IBatteryStats mBatteryStats;
-
-    // only modified on handler thread
-    private WorkSource mClientSource = new WorkSource();
-
-    private GeofenceHardwareImpl mGeofenceHardwareImpl;
-
-    private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() {
-        @Override
-        public void addGpsStatusListener(IGpsStatusListener listener) {
-            mListenerHelper.addListener(listener);
-        }
-
-        @Override
-        public void removeGpsStatusListener(IGpsStatusListener listener) {
-            mListenerHelper.removeListener(listener);
-        }
-    };
-
-    public IGpsStatusProvider getGpsStatusProvider() {
-        return mGpsStatusProvider;
-    }
-
-    public IGpsGeofenceHardware getGpsGeofenceProxy() {
-        return mGpsGeofenceBinder;
-    }
-
-    public GpsMeasurementsProvider getGpsMeasurementsProvider() {
-        return mGpsMeasurementsProvider;
-    }
-
-    public GpsNavigationMessageProvider getGpsNavigationMessageProvider() {
-        return mGpsNavigationMessageProvider;
-    }
-
-    /**
-     * Callback used to listen for data connectivity changes.
-     */
-    private final ConnectivityManager.NetworkCallback mNetworkConnectivityCallback =
-            new ConnectivityManager.NetworkCallback() {
-        @Override
-        public void onAvailable(Network network) {
-            requestUtcTime();
-            xtraDownloadRequest();
-        }
-    };
-
-    /**
-     * Callback used to listen for availability of a requested SUPL connection.
-     * It is kept as a separate instance from {@link #mNetworkConnectivityCallback} to be able to
-     * manage the registration/un-registration lifetimes separate.
-     */
-    private final ConnectivityManager.NetworkCallback mSuplConnectivityCallback =
-            new ConnectivityManager.NetworkCallback() {
-        @Override
-        public void onAvailable(Network network) {
-            sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
-        }
-
-        @Override
-        public void onLost(Network network) {
-            releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
-        }
-
-        @Override
-        public void onUnavailable() {
-            // timeout, it was not possible to establish the required connection
-            releaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
-        }
-    };
-
-    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        @Override public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action);
-            if (action == null) {
-                return;
-            }
-
-            if (action.equals(ALARM_WAKEUP)) {
-                startNavigating(false);
-            } else if (action.equals(ALARM_TIMEOUT)) {
-                hibernate();
-            } else if (action.equals(Intents.DATA_SMS_RECEIVED_ACTION)) {
-                checkSmsSuplInit(intent);
-            } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) {
-                checkWapSuplInit(intent);
-            } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)
-                    || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)
-                    || Intent.ACTION_SCREEN_OFF.equals(action)
-                    || Intent.ACTION_SCREEN_ON.equals(action)) {
-                updateLowPowerMode();
-            } else if (action.equals(SIM_STATE_CHANGED)) {
-                subscriptionOrSimChanged(context);
-            }
-        }
-    };
-
-    private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
-            new OnSubscriptionsChangedListener() {
-        @Override
-        public void onSubscriptionsChanged() {
-            sendMessage(SUBSCRIPTION_OR_SIM_CHANGED, 0, null);
-        }
-    };
-
-    private void subscriptionOrSimChanged(Context context) {
-        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);
-            synchronized (mLock) {
-                reloadGpsProperties(context, mProperties);
-                mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
-            }
-        } else {
-            Log.d(TAG, "SIM MCC/MNC is still not available");
-        }
-    }
-
-    private void checkSmsSuplInit(Intent intent) {
-        SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
-        if (messages == null) {
-            Log.e(TAG, "Message does not exist in the intent.");
-            return;
-        }
-
-        for (SmsMessage message : messages) {
-            if (message != null && message.mWrappedSmsMessage != null) {
-                byte[] suplInit = message.getUserData();
-                if (suplInit != null) {
-                    native_agps_ni_message(suplInit, suplInit.length);
-                }
-            }
-        }
-    }
-
-    private void checkWapSuplInit(Intent intent) {
-        byte[] suplInit = intent.getByteArrayExtra("data");
-        if (suplInit == null) {
-            return;
-        }
-        native_agps_ni_message(suplInit,suplInit.length);
-    }
-
-    private void updateLowPowerMode() {
-        // Disable GPS if we are in device idle mode.
-        boolean disableGps = mPowerManager.isDeviceIdleMode();
-        switch (Settings.Secure.getInt(mContext.getContentResolver(), BATTERY_SAVER_GPS_MODE,
-                BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF)) {
-            case BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF:
-                // If we are in battery saver mode and the screen is off, disable GPS.
-                disableGps |= mPowerManager.isPowerSaveMode() && !mPowerManager.isInteractive();
-                break;
-        }
-        if (disableGps != mDisableGps) {
-            mDisableGps = disableGps;
-            updateRequirements();
-        }
-    }
-
-    public static boolean isSupported() {
-        return native_is_supported();
-    }
-
-    private void reloadGpsProperties(Context context, Properties properties) {
-        Log.d(TAG, "Reset GPS properties, previous size = " + properties.size());
-        loadPropertiesFromResource(context, properties);
-        boolean isPropertiesLoadedFromFile = false;
-        final String gpsHardware = SystemProperties.get("ro.hardware.gps");
-        if (!TextUtils.isEmpty(gpsHardware)) {
-            final String propFilename =
-                    PROPERTIES_FILE_PREFIX + "." + gpsHardware + PROPERTIES_FILE_SUFFIX;
-            isPropertiesLoadedFromFile =
-                    loadPropertiesFromFile(propFilename, properties);
-        }
-        if (!isPropertiesLoadedFromFile) {
-            loadPropertiesFromFile(DEFAULT_PROPERTIES_FILE, properties);
-        }
-        Log.d(TAG, "GPS properties reloaded, size = " + properties.size());
-
-        // TODO: we should get rid of C2K specific setting.
-        setSuplHostPort(properties.getProperty("SUPL_HOST"),
-                        properties.getProperty("SUPL_PORT"));
-        mC2KServerHost = properties.getProperty("C2K_HOST");
-        String portString = properties.getProperty("C2K_PORT");
-        if (mC2KServerHost != null && portString != null) {
-            try {
-                mC2KServerPort = Integer.parseInt(portString);
-            } catch (NumberFormatException e) {
-                Log.e(TAG, "unable to parse C2K_PORT: " + portString);
-            }
-        }
-
-        if (native_is_gnss_configuration_supported()) {
-            try {
-                // Convert properties to string contents and send it to HAL.
-                ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
-                properties.store(baos, null);
-                native_configuration_update(baos.toString());
-                Log.d(TAG, "final config = " + baos.toString());
-            } catch (IOException ex) {
-                Log.e(TAG, "failed to dump properties contents");
-            }
-        } else if (DEBUG) {
-            Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not"
-                    + " supported");
-        }
-
-        // SUPL_ES configuration.
-        String suplESProperty = mProperties.getProperty("SUPL_ES");
-        if (suplESProperty != null) {
-            try {
-                mSuplEsEnabled = (Integer.parseInt(suplESProperty) == 1);
-            } catch (NumberFormatException e) {
-                Log.e(TAG, "unable to parse SUPL_ES: " + suplESProperty);
-            }
-        }
-    }
-
-    private void loadPropertiesFromResource(Context context,
-                                            Properties properties) {
-        String[] configValues = context.getResources().getStringArray(
-                com.android.internal.R.array.config_gpsParameters);
-        for (String item : configValues) {
-            Log.d(TAG, "GpsParamsResource: " + item);
-            // We need to support "KEY =", but not "=VALUE".
-            String[] split = item.split("=");
-            if (split.length == 2) {
-                properties.setProperty(split[0].trim().toUpperCase(), split[1]);
-            } else {
-                Log.w(TAG, "malformed contents: " + item);
-            }
-        }
-    }
-
-    private boolean loadPropertiesFromFile(String filename,
-                                           Properties properties) {
-        try {
-            File file = new File(filename);
-            FileInputStream stream = null;
-            try {
-                stream = new FileInputStream(file);
-                properties.load(stream);
-            } finally {
-                IoUtils.closeQuietly(stream);
-            }
-
-        } catch (IOException e) {
-            Log.w(TAG, "Could not open GPS configuration file " + filename);
-            return false;
-        }
-        return true;
-    }
-
-    public GpsLocationProvider(Context context, ILocationManager ilocationManager,
-            Looper looper) {
-        mContext = context;
-        mNtpTime = NtpTrustedTime.getInstance(context);
-        mILocationManager = ilocationManager;
-
-        mLocation.setExtras(mLocationExtras);
-
-        // Create a wake lock
-        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-        mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
-        mWakeLock.setReferenceCounted(true);
-
-        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
-        mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
-        mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
-
-        mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
-
-        // App ops service to keep track of who is accessing the GPS
-        mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(
-                Context.APP_OPS_SERVICE));
-
-        // Battery statistics service to be notified when GPS turns on or off
-        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
-                BatteryStats.SERVICE_NAME));
-
-        // Construct internal handler
-        mHandler = new ProviderHandler(looper);
-
-        // Load GPS configuration and register listeners in the background:
-        // some operations, such as opening files and registering broadcast receivers, can take a
-        // relative long time, so the ctor() is kept to create objects needed by this instance,
-        // while IO initialization and registration is delegated to our internal handler
-        // this approach is just fine because events are posted to our handler anyway
-        mProperties = new Properties();
-        sendMessage(INITIALIZE_HANDLER, 0, null);
-
-        // Create a GPS net-initiated handler.
-        mNIHandler = new GpsNetInitiatedHandler(context,
-                                                mNetInitiatedListener,
-                                                mSuplEsEnabled);
-
-        mListenerHelper = new GpsStatusListenerHelper(mHandler) {
-            @Override
-            protected boolean isAvailableInPlatform() {
-                return isSupported();
-            }
-
-            @Override
-            protected boolean isGpsEnabled() {
-                return isEnabled();
-            }
-        };
-
-        mGpsMeasurementsProvider = new GpsMeasurementsProvider(mHandler) {
-            @Override
-            public boolean isAvailableInPlatform() {
-                return native_is_measurement_supported();
-            }
-
-            @Override
-            protected boolean registerWithService() {
-                return native_start_measurement_collection();
-            }
-
-            @Override
-            protected void unregisterFromService() {
-                native_stop_measurement_collection();
-            }
-
-            @Override
-            protected boolean isGpsEnabled() {
-                return isEnabled();
-            }
-        };
-
-        mGpsNavigationMessageProvider = new GpsNavigationMessageProvider(mHandler) {
-            @Override
-            protected boolean isAvailableInPlatform() {
-                return native_is_navigation_message_supported();
-            }
-
-            @Override
-            protected boolean registerWithService() {
-                return native_start_navigation_message_collection();
-            }
-
-            @Override
-            protected void unregisterFromService() {
-                native_stop_navigation_message_collection();
-            }
-
-            @Override
-            protected boolean isGpsEnabled() {
-                return isEnabled();
-            }
-        };
-    }
-
-    /**
-     * Returns the name of this provider.
-     */
-    @Override
-    public String getName() {
-        return LocationManager.GPS_PROVIDER;
-    }
-
-    @Override
-    public ProviderProperties getProperties() {
-        return PROPERTIES;
-    }
-
-    private void handleUpdateNetworkState(Network network) {
-        // retrieve NetworkInfo for this UID
-        NetworkInfo info = mConnMgr.getNetworkInfo(network);
-        if (info == null) {
-            return;
-        }
-
-        boolean isConnected = info.isConnected();
-        if (DEBUG) {
-            String message = String.format(
-                    "UpdateNetworkState, state=%s, connected=%s, info=%s, capabilities=%S",
-                    agpsDataConnStateAsString(),
-                    isConnected,
-                    info,
-                    mConnMgr.getNetworkCapabilities(network));
-            Log.d(TAG, message);
-        }
-
-        if (native_is_agps_ril_supported()) {
-            boolean dataEnabled = TelephonyManager.getDefault().getDataEnabled();
-            boolean networkAvailable = info.isAvailable() && dataEnabled;
-            String defaultApn = getSelectedApn();
-            if (defaultApn == null) {
-                defaultApn = "dummy-apn";
-            }
-
-            native_update_network_state(
-                    isConnected,
-                    info.getType(),
-                    info.isRoaming(),
-                    networkAvailable,
-                    info.getExtraInfo(),
-                    defaultApn);
-        } else if (DEBUG) {
-            Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not  supported");
-        }
-
-        if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
-            if (isConnected) {
-                String apnName = info.getExtraInfo();
-                if (apnName == null) {
-                    // assign a dummy value in the case of C2K as otherwise we will have a runtime
-                    // exception in the following call to native_agps_data_conn_open
-                    apnName = "dummy-apn";
-                }
-                int apnIpType = getApnIpType(apnName);
-                setRouting();
-                if (DEBUG) {
-                    String message = String.format(
-                            "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s",
-                            apnName,
-                            apnIpType);
-                    Log.d(TAG, message);
-                }
-                native_agps_data_conn_open(apnName, apnIpType);
-                mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
-            } else {
-                handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
-            }
-        }
-    }
-
-    private void handleRequestSuplConnection(InetAddress address) {
-        if (DEBUG) {
-            String message = String.format(
-                    "requestSuplConnection, state=%s, address=%s",
-                    agpsDataConnStateAsString(),
-                    address);
-            Log.d(TAG, message);
-        }
-
-        if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
-            return;
-        }
-        mAGpsDataConnectionIpAddr = address;
-        mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
-
-        NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
-        requestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-        requestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
-        NetworkRequest request = requestBuilder.build();
-        mConnMgr.requestNetwork(
-                request,
-                mSuplConnectivityCallback,
-                ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS);
-    }
-
-    private void handleReleaseSuplConnection(int agpsDataConnStatus) {
-        if (DEBUG) {
-            String message = String.format(
-                    "releaseSuplConnection, state=%s, status=%s",
-                    agpsDataConnStateAsString(),
-                    agpsDataConnStatusAsString(agpsDataConnStatus));
-            Log.d(TAG, message);
-        }
-
-        if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_CLOSED) {
-            return;
-        }
-        mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
-
-        mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback);
-        switch (agpsDataConnStatus) {
-            case GPS_AGPS_DATA_CONN_FAILED:
-                native_agps_data_conn_failed();
-                break;
-            case GPS_RELEASE_AGPS_DATA_CONN:
-                native_agps_data_conn_closed();
-                break;
-            default:
-                Log.e(TAG, "Invalid status to release SUPL connection: " + agpsDataConnStatus);
-        }
-    }
-
-    private void handleInjectNtpTime() {
-        if (mInjectNtpTimePending == STATE_DOWNLOADING) {
-            // already downloading data
-            return;
-        }
-        if (!isDataNetworkConnected()) {
-            // try again when network is up
-            mInjectNtpTimePending = STATE_PENDING_NETWORK;
-            return;
-        }
-        mInjectNtpTimePending = STATE_DOWNLOADING;
-
-        // hold wake lock while task runs
-        mWakeLock.acquire();
-        AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
-            @Override
-            public void run() {
-                long delay;
-
-                // force refresh NTP cache when outdated
-                boolean refreshSuccess = true;
-                if (mNtpTime.getCacheAge() >= NTP_INTERVAL) {
-                    refreshSuccess = mNtpTime.forceRefresh();
-                }
-
-                // only update when NTP time is fresh
-                if (mNtpTime.getCacheAge() < NTP_INTERVAL) {
-                    long time = mNtpTime.getCachedNtpTime();
-                    long timeReference = mNtpTime.getCachedNtpTimeReference();
-                    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));
-
-                    native_inject_time(time, timeReference, (int) certainty);
-                    delay = NTP_INTERVAL;
-                    mNtpBackOff.reset();
-                } else {
-                    Log.e(TAG, "requestTime failed");
-                    delay = mNtpBackOff.nextBackoffMillis();
-                }
-
-                sendMessage(INJECT_NTP_TIME_FINISHED, 0, null);
-
-                if (DEBUG) {
-                    String message = String.format(
-                            "onDemandTimeInjection=%s, refreshSuccess=%s, delay=%s",
-                            mOnDemandTimeInjection,
-                            refreshSuccess,
-                            delay);
-                    Log.d(TAG, message);
-                }
-                if (mOnDemandTimeInjection || !refreshSuccess) {
-                    // send delayed message for next NTP injection
-                    // since this is delayed and not urgent we do not hold a wake lock here
-                    mHandler.sendEmptyMessageDelayed(INJECT_NTP_TIME, delay);
-                }
-
-                // release wake lock held by task
-                mWakeLock.release();
-            }
-        });
-    }
-
-    private void handleDownloadXtraData() {
-        if (mDownloadXtraDataPending == STATE_DOWNLOADING) {
-            // already downloading data
-            return;
-        }
-        if (!isDataNetworkConnected()) {
-            // try again when network is up
-            mDownloadXtraDataPending = STATE_PENDING_NETWORK;
-            return;
-        }
-        mDownloadXtraDataPending = STATE_DOWNLOADING;
-
-        // hold wake lock while task runs
-        mWakeLock.acquire();
-        AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
-            @Override
-            public void run() {
-                GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties);
-                byte[] data = xtraDownloader.downloadXtraData();
-                if (data != null) {
-                    if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data");
-                    native_inject_xtra_data(data, data.length);
-                    mXtraBackOff.reset();
-                }
-
-                sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
-
-                if (data == null) {
-                    // try again later
-                    // since this is delayed and not urgent we do not hold a wake lock here
-                    mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA,
-                            mXtraBackOff.nextBackoffMillis());
-                }
-
-                // release wake lock held by task
-                mWakeLock.release();
-            }
-        });
-    }
-
-    private void handleUpdateLocation(Location location) {
-        if (location.hasAccuracy()) {
-            native_inject_location(location.getLatitude(), location.getLongitude(),
-                    location.getAccuracy());
-        }
-    }
-
-    /**
-     * Enables this provider.  When enabled, calls to getStatus()
-     * must be handled.  Hardware may be started up
-     * when the provider is enabled.
-     */
-    @Override
-    public void enable() {
-        synchronized (mLock) {
-            if (mEnabled) return;
-            mEnabled = true;
-        }
-
-        sendMessage(ENABLE, 1, null);
-    }
-
-    private void setSuplHostPort(String hostString, String portString) {
-        if (hostString != null) {
-            mSuplServerHost = hostString;
-        }
-        if (portString != null) {
-            try {
-                mSuplServerPort = Integer.parseInt(portString);
-            } catch (NumberFormatException e) {
-                Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
-            }
-        }
-        if (mSuplServerHost != null
-                && mSuplServerPort > TCP_MIN_PORT
-                && mSuplServerPort <= TCP_MAX_PORT) {
-            native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
-        }
-    }
-
-    /**
-     * Checks what SUPL mode to use, according to the AGPS mode as well as the
-     * allowed mode from properties.
-     *
-     * @param properties GPS properties
-     * @param agpsEnabled whether AGPS is enabled by settings value
-     * @param singleShot whether "singleshot" is needed
-     * @return SUPL mode (MSA vs MSB vs STANDALONE)
-     */
-    private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) {
-        if (agpsEnabled) {
-            String modeString = properties.getProperty("SUPL_MODE");
-            int suplMode = 0;
-            if (!TextUtils.isEmpty(modeString)) {
-                try {
-                    suplMode = Integer.parseInt(modeString);
-                } catch (NumberFormatException e) {
-                    Log.e(TAG, "unable to parse SUPL_MODE: " + modeString);
-                    return GPS_POSITION_MODE_STANDALONE;
-                }
-            }
-            // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor
-            // such mode when it is available
-            if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) {
-                return GPS_POSITION_MODE_MS_BASED;
-            }
-            // for now, just as the legacy code did, we fallback to MS-Assisted if it is available,
-            // do fallback only for single-shot requests, because it is too expensive to do for
-            // periodic requests as well
-            if (singleShot
-                    && hasCapability(GPS_CAPABILITY_MSA)
-                    && (suplMode & AGPS_SUPL_MODE_MSA) != 0) {
-                return GPS_POSITION_MODE_MS_ASSISTED;
-            }
-        }
-        return GPS_POSITION_MODE_STANDALONE;
-    }
-
-    private void handleEnable() {
-        if (DEBUG) Log.d(TAG, "handleEnable");
-
-        boolean enabled = native_init();
-
-        if (enabled) {
-            mSupportsXtra = native_supports_xtra();
-
-            // TODO: remove the following native calls if we can make sure they are redundant.
-            if (mSuplServerHost != null) {
-                native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
-            }
-            if (mC2KServerHost != null) {
-                native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
-            }
-
-            mGpsMeasurementsProvider.onGpsEnabledChanged();
-            mGpsNavigationMessageProvider.onGpsEnabledChanged();
-        } else {
-            synchronized (mLock) {
-                mEnabled = false;
-            }
-            Log.w(TAG, "Failed to enable location provider");
-        }
-    }
-
-    /**
-     * Disables this provider.  When disabled, calls to getStatus()
-     * need not be handled.  Hardware may be shut
-     * down while the provider is disabled.
-     */
-    @Override
-    public void disable() {
-        synchronized (mLock) {
-            if (!mEnabled) return;
-            mEnabled = false;
-        }
-
-        sendMessage(ENABLE, 0, null);
-    }
-
-    private void handleDisable() {
-        if (DEBUG) Log.d(TAG, "handleDisable");
-
-        updateClientUids(new WorkSource());
-        stopNavigating();
-        mAlarmManager.cancel(mWakeupIntent);
-        mAlarmManager.cancel(mTimeoutIntent);
-
-        // do this before releasing wakelock
-        native_cleanup();
-
-        mGpsMeasurementsProvider.onGpsEnabledChanged();
-        mGpsNavigationMessageProvider.onGpsEnabledChanged();
-    }
-
-    @Override
-    public boolean isEnabled() {
-        synchronized (mLock) {
-            return mEnabled;
-        }
-    }
-
-    @Override
-    public int getStatus(Bundle extras) {
-        if (extras != null) {
-            extras.putInt("satellites", mSvCount);
-        }
-        return mStatus;
-    }
-
-    private void updateStatus(int status, int svCount) {
-        if (status != mStatus || svCount != mSvCount) {
-            mStatus = status;
-            mSvCount = svCount;
-            mLocationExtras.putInt("satellites", svCount);
-            mStatusUpdateTime = SystemClock.elapsedRealtime();
-        }
-    }
-
-    @Override
-    public long getStatusUpdateTime() {
-        return mStatusUpdateTime;
-    }
-
-    @Override
-    public void setRequest(ProviderRequest request, WorkSource source) {
-        sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
-    }
-
-    private void handleSetRequest(ProviderRequest request, WorkSource source) {
-        mProviderRequest = request;
-        mWorkSource = source;
-        updateRequirements();
-    }
-
-    // Called when the requirements for GPS may have changed
-    private void updateRequirements() {
-        if (mProviderRequest == null || mWorkSource == null) {
-            return;
-        }
-
-        boolean singleShot = false;
-
-        // see if the request is for a single update
-        if (mProviderRequest.locationRequests != null
-                && mProviderRequest.locationRequests.size() > 0) {
-            // if any request has zero or more than one updates
-            // requested, then this is not single-shot mode
-            singleShot = true;
-
-            for (LocationRequest lr : mProviderRequest.locationRequests) {
-                if (lr.getNumUpdates() != 1) {
-                    singleShot = false;
-                }
-            }
-        }
-
-        if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest);
-        if (mProviderRequest.reportLocation && !mDisableGps) {
-            // update client uids
-            updateClientUids(mWorkSource);
-
-            mFixInterval = (int) mProviderRequest.interval;
-
-            // check for overflow
-            if (mFixInterval != mProviderRequest.interval) {
-                Log.w(TAG, "interval overflow: " + mProviderRequest.interval);
-                mFixInterval = Integer.MAX_VALUE;
-            }
-
-            // apply request to GPS engine
-            if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
-                // change period
-                if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
-                        mFixInterval, 0, 0)) {
-                    Log.e(TAG, "set_position_mode failed in setMinTime()");
-                }
-            } else if (!mStarted) {
-                // start GPS
-                startNavigating(singleShot);
-            }
-        } else {
-            updateClientUids(new WorkSource());
-
-            stopNavigating();
-            mAlarmManager.cancel(mWakeupIntent);
-            mAlarmManager.cancel(mTimeoutIntent);
-        }
-    }
-
-    private void updateClientUids(WorkSource source) {
-        // Update work source.
-        WorkSource[] changes = mClientSource.setReturningDiffs(source);
-        if (changes == null) {
-            return;
-        }
-        WorkSource newWork = changes[0];
-        WorkSource goneWork = changes[1];
-
-        // Update sources that were not previously tracked.
-        if (newWork != null) {
-            int lastuid = -1;
-            for (int i=0; i<newWork.size(); i++) {
-                try {
-                    int uid = newWork.get(i);
-                    mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
-                            AppOpsManager.OP_GPS, uid, newWork.getName(i));
-                    if (uid != lastuid) {
-                        lastuid = uid;
-                        mBatteryStats.noteStartGps(uid);
-                    }
-                } catch (RemoteException e) {
-                    Log.w(TAG, "RemoteException", e);
-                }
-            }
-        }
-
-        // Update sources that are no longer tracked.
-        if (goneWork != null) {
-            int lastuid = -1;
-            for (int i=0; i<goneWork.size(); i++) {
-                try {
-                    int uid = goneWork.get(i);
-                    mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
-                            AppOpsManager.OP_GPS, uid, goneWork.getName(i));
-                    if (uid != lastuid) {
-                        lastuid = uid;
-                        mBatteryStats.noteStopGps(uid);
-                    }
-                } catch (RemoteException e) {
-                    Log.w(TAG, "RemoteException", e);
-                }
-            }
-        }
-    }
-
-    @Override
-    public boolean sendExtraCommand(String command, Bundle extras) {
-
-        long identity = Binder.clearCallingIdentity();
-        boolean result = false;
-
-        if ("delete_aiding_data".equals(command)) {
-            result = deleteAidingData(extras);
-        } else if ("force_time_injection".equals(command)) {
-            requestUtcTime();
-            result = true;
-        } else if ("force_xtra_injection".equals(command)) {
-            if (mSupportsXtra) {
-                xtraDownloadRequest();
-                result = true;
-            }
-        } else {
-            Log.w(TAG, "sendExtraCommand: unknown command " + command);
-        }
-
-        Binder.restoreCallingIdentity(identity);
-        return result;
-    }
-
-    private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() {
-        public boolean isHardwareGeofenceSupported() {
-            return native_is_geofence_supported();
-        }
-
-        public boolean addCircularHardwareGeofence(int geofenceId, double latitude,
-                double longitude, double radius, int lastTransition, int monitorTransitions,
-                int notificationResponsiveness, int unknownTimer) {
-            return native_add_geofence(geofenceId, latitude, longitude, radius,
-                    lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer);
-        }
-
-        public boolean removeHardwareGeofence(int geofenceId) {
-            return native_remove_geofence(geofenceId);
-        }
-
-        public boolean pauseHardwareGeofence(int geofenceId) {
-            return native_pause_geofence(geofenceId);
-        }
-
-        public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) {
-            return native_resume_geofence(geofenceId, monitorTransition);
-        }
-    };
-
-    private boolean deleteAidingData(Bundle extras) {
-        int flags;
-
-        if (extras == null) {
-            flags = GPS_DELETE_ALL;
-        } else {
-            flags = 0;
-            if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
-            if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
-            if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
-            if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
-            if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
-            if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
-            if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
-            if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
-            if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
-            if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
-            if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
-            if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
-            if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
-        }
-
-        if (flags != 0) {
-            native_delete_aiding_data(flags);
-            return true;
-        }
-
-        return false;
-    }
-
-    private void startNavigating(boolean singleShot) {
-        if (!mStarted) {
-            if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot);
-            mTimeToFirstFix = 0;
-            mLastFixTime = 0;
-            mStarted = true;
-            mSingleShot = singleShot;
-            mPositionMode = GPS_POSITION_MODE_STANDALONE;
-
-            boolean agpsEnabled =
-                    (Settings.Global.getInt(mContext.getContentResolver(),
-                                            Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0);
-            mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot);
-
-            if (DEBUG) {
-                String mode;
-
-                switch(mPositionMode) {
-                    case GPS_POSITION_MODE_STANDALONE:
-                        mode = "standalone";
-                        break;
-                    case GPS_POSITION_MODE_MS_ASSISTED:
-                        mode = "MS_ASSISTED";
-                        break;
-                    case GPS_POSITION_MODE_MS_BASED:
-                        mode = "MS_BASED";
-                        break;
-                    default:
-                        mode = "unknown";
-                        break;
-                }
-                Log.d(TAG, "setting position_mode to " + mode);
-            }
-
-            int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
-            if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
-                    interval, 0, 0)) {
-                mStarted = false;
-                Log.e(TAG, "set_position_mode failed in startNavigating()");
-                return;
-            }
-            if (!native_start()) {
-                mStarted = false;
-                Log.e(TAG, "native_start failed in startNavigating()");
-                return;
-            }
-
-            // reset SV count to zero
-            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
-            mFixRequestTime = System.currentTimeMillis();
-            if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
-                // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
-                // and our fix interval is not short
-                if (mFixInterval >= NO_FIX_TIMEOUT) {
-                    mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                            SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
-                }
-            }
-        }
-    }
-
-    private void stopNavigating() {
-        if (DEBUG) Log.d(TAG, "stopNavigating");
-        if (mStarted) {
-            mStarted = false;
-            mSingleShot = false;
-            native_stop();
-            mTimeToFirstFix = 0;
-            mLastFixTime = 0;
-            mLocationFlags = LOCATION_INVALID;
-
-            // reset SV count to zero
-            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
-        }
-    }
-
-    private void hibernate() {
-        // stop GPS until our next fix interval arrives
-        stopNavigating();
-        mAlarmManager.cancel(mTimeoutIntent);
-        mAlarmManager.cancel(mWakeupIntent);
-        long now = SystemClock.elapsedRealtime();
-        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
-    }
-
-    private boolean hasCapability(int capability) {
-        return ((mEngineCapabilities & capability) != 0);
-    }
-
-
-    /**
-     * called from native code to update our position.
-     */
-    private void reportLocation(int flags, double latitude, double longitude, double altitude,
-            float speed, float bearing, float accuracy, long timestamp) {
-        if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude +
-                " timestamp: " + timestamp);
-
-        synchronized (mLocation) {
-            mLocationFlags = flags;
-            if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
-                mLocation.setLatitude(latitude);
-                mLocation.setLongitude(longitude);
-                mLocation.setTime(timestamp);
-                // It would be nice to push the elapsed real-time timestamp
-                // further down the stack, but this is still useful
-                mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
-            }
-            if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
-                mLocation.setAltitude(altitude);
-            } else {
-                mLocation.removeAltitude();
-            }
-            if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
-                mLocation.setSpeed(speed);
-            } else {
-                mLocation.removeSpeed();
-            }
-            if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
-                mLocation.setBearing(bearing);
-            } else {
-                mLocation.removeBearing();
-            }
-            if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
-                mLocation.setAccuracy(accuracy);
-            } else {
-                mLocation.removeAccuracy();
-            }
-            mLocation.setExtras(mLocationExtras);
-
-            try {
-                mILocationManager.reportLocation(mLocation, false);
-            } catch (RemoteException e) {
-                Log.e(TAG, "RemoteException calling reportLocation");
-            }
-        }
-
-        mLastFixTime = System.currentTimeMillis();
-        // report time to first fix
-        if (mTimeToFirstFix == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
-            mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime);
-            if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
-
-            // notify status listeners
-            mListenerHelper.onFirstFix(mTimeToFirstFix);
-        }
-
-        if (mSingleShot) {
-            stopNavigating();
-        }
-
-        if (mStarted && mStatus != LocationProvider.AVAILABLE) {
-            // we want to time out if we do not receive a fix
-            // within the time out and we are requesting infrequent fixes
-            if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
-                mAlarmManager.cancel(mTimeoutIntent);
-            }
-
-            // send an intent to notify that the GPS is receiving fixes.
-            Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
-            intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
-            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
-            updateStatus(LocationProvider.AVAILABLE, mSvCount);
-        }
-
-       if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
-               mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
-            if (DEBUG) Log.d(TAG, "got fix, hibernating");
-            hibernate();
-        }
-   }
-
-    /**
-     * called from native code to update our status
-     */
-    private void reportStatus(int status) {
-        if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
-
-        boolean wasNavigating = mNavigating;
-        switch (status) {
-            case GPS_STATUS_SESSION_BEGIN:
-                mNavigating = true;
-                mEngineOn = true;
-                break;
-            case GPS_STATUS_SESSION_END:
-                mNavigating = false;
-                break;
-            case GPS_STATUS_ENGINE_ON:
-                mEngineOn = true;
-                break;
-            case GPS_STATUS_ENGINE_OFF:
-                mEngineOn = false;
-                mNavigating = false;
-                break;
-        }
-
-        if (wasNavigating != mNavigating) {
-            mListenerHelper.onStatusChanged(mNavigating);
-
-            // send an intent to notify that the GPS has been enabled or disabled
-            Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
-            intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
-            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
-        }
-    }
-
-    /**
-     * called from native code to update SV info
-     */
-    private void reportSvStatus() {
-        int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks);
-        mListenerHelper.onSvStatusChanged(
-                svCount,
-                mSvs,
-                mSnrs,
-                mSvElevations,
-                mSvAzimuths,
-                mSvMasks[EPHEMERIS_MASK],
-                mSvMasks[ALMANAC_MASK],
-                mSvMasks[USED_FOR_FIX_MASK]);
-
-        if (VERBOSE) {
-            Log.v(TAG, "SV count: " + svCount +
-                    " ephemerisMask: " + Integer.toHexString(mSvMasks[EPHEMERIS_MASK]) +
-                    " almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK]));
-            for (int i = 0; i < svCount; i++) {
-                Log.v(TAG, "sv: " + mSvs[i] +
-                        " snr: " + mSnrs[i]/10 +
-                        " elev: " + mSvElevations[i] +
-                        " azimuth: " + mSvAzimuths[i] +
-                        ((mSvMasks[EPHEMERIS_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "  " : " E") +
-                        ((mSvMasks[ALMANAC_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "  " : " A") +
-                        ((mSvMasks[USED_FOR_FIX_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "" : "U"));
-            }
-        }
-
-        // return number of sets used in fix instead of total
-        updateStatus(mStatus, Integer.bitCount(mSvMasks[USED_FOR_FIX_MASK]));
-
-        if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
-            System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) {
-            // send an intent to notify that the GPS is no longer receiving fixes.
-            Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
-            intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
-            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
-            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount);
-        }
-    }
-
-    /**
-     * called from native code to update AGPS status
-     */
-    private void reportAGpsStatus(int type, int status, byte[] ipaddr) {
-        switch (status) {
-            case GPS_REQUEST_AGPS_DATA_CONN:
-                if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
-                Log.v(TAG, "Received SUPL IP addr[]: " + Arrays.toString(ipaddr));
-                InetAddress connectionIpAddress = null;
-                if (ipaddr != null) {
-                    try {
-                        connectionIpAddress = InetAddress.getByAddress(ipaddr);
-                        if (DEBUG) Log.d(TAG, "IP address converted to: " + connectionIpAddress);
-                    } catch (UnknownHostException e) {
-                        Log.e(TAG, "Bad IP Address: " + ipaddr, e);
-                    }
-                }
-                sendMessage(REQUEST_SUPL_CONNECTION, 0 /*arg*/, connectionIpAddress);
-                break;
-            case GPS_RELEASE_AGPS_DATA_CONN:
-                if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
-                releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
-                break;
-            case GPS_AGPS_DATA_CONNECTED:
-                if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
-                break;
-            case GPS_AGPS_DATA_CONN_DONE:
-                if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
-                break;
-            case GPS_AGPS_DATA_CONN_FAILED:
-                if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
-                break;
-            default:
-                Log.d(TAG, "Received Unknown AGPS status: " + status);
-        }
-    }
-
-    private void releaseSuplConnection(int connStatus) {
-        sendMessage(RELEASE_SUPL_CONNECTION, connStatus, null /*obj*/);
-    }
-
-    /**
-     * called from native code to report NMEA data received
-     */
-    private void reportNmea(long timestamp) {
-        int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
-        String nmea = new String(mNmeaBuffer, 0 /* offset */, length);
-        mListenerHelper.onNmeaReceived(timestamp, nmea);
-    }
-
-    /**
-     * called from native code - Gps measurements callback
-     */
-    private void reportMeasurementData(GpsMeasurementsEvent event) {
-        mGpsMeasurementsProvider.onMeasurementsAvailable(event);
-    }
-
-    /**
-     * called from native code - GPS navigation message callback
-     */
-    private void reportNavigationMessage(GpsNavigationMessageEvent event) {
-        mGpsNavigationMessageProvider.onNavigationMessageAvailable(event);
-    }
-
-    /**
-     * called from native code to inform us what the GPS engine capabilities are
-     */
-    private void setEngineCapabilities(int capabilities) {
-        mEngineCapabilities = capabilities;
-
-        if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
-            mOnDemandTimeInjection = true;
-            requestUtcTime();
-        }
-
-        mGpsMeasurementsProvider.onCapabilitiesUpdated(
-                (capabilities & GPS_CAPABILITY_MEASUREMENTS) == GPS_CAPABILITY_MEASUREMENTS);
-        mGpsNavigationMessageProvider.onCapabilitiesUpdated(
-                (capabilities & GPS_CAPABILITY_NAV_MESSAGES) == GPS_CAPABILITY_NAV_MESSAGES);
-    }
-
-    /**
-     * called from native code to request XTRA data
-     */
-    private void xtraDownloadRequest() {
-        if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
-        sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
-    }
-
-    /**
-     * Helper method to construct a location object.
-     */
-    private Location buildLocation(
-            int flags,
-            double latitude,
-            double longitude,
-            double altitude,
-            float speed,
-            float bearing,
-            float accuracy,
-            long timestamp) {
-        Location location = new Location(LocationManager.GPS_PROVIDER);
-        if((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
-            location.setLatitude(latitude);
-            location.setLongitude(longitude);
-            location.setTime(timestamp);
-            location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
-        }
-        if((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
-            location.setAltitude(altitude);
-        }
-        if((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
-            location.setSpeed(speed);
-        }
-        if((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
-            location.setBearing(bearing);
-        }
-        if((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
-            location.setAccuracy(accuracy);
-        }
-        return location;
-    }
-
-    /**
-     * Converts the GPS HAL status to the internal Geofence Hardware status.
-     */
-    private int getGeofenceStatus(int status) {
-        switch(status) {
-            case GPS_GEOFENCE_OPERATION_SUCCESS:
-                return GeofenceHardware.GEOFENCE_SUCCESS;
-            case GPS_GEOFENCE_ERROR_GENERIC:
-                return GeofenceHardware.GEOFENCE_FAILURE;
-            case GPS_GEOFENCE_ERROR_ID_EXISTS:
-                return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
-            case GPS_GEOFENCE_ERROR_INVALID_TRANSITION:
-                return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
-            case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES:
-                return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
-            case GPS_GEOFENCE_ERROR_ID_UNKNOWN:
-                return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
-            default:
-                return -1;
-        }
-    }
-
-    /**
-     * Called from native to report GPS Geofence transition
-     * All geofence callbacks are called on the same thread
-     */
-    private void reportGeofenceTransition(int geofenceId, int flags, double latitude,
-            double longitude, double altitude, float speed, float bearing, float accuracy,
-            long timestamp, int transition, long transitionTimestamp) {
-        if (mGeofenceHardwareImpl == null) {
-            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
-        }
-        Location location = buildLocation(
-                flags,
-                latitude,
-                longitude,
-                altitude,
-                speed,
-                bearing,
-                accuracy,
-                timestamp);
-        mGeofenceHardwareImpl.reportGeofenceTransition(
-                geofenceId,
-                location,
-                transition,
-                transitionTimestamp,
-                GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
-                FusedBatchOptions.SourceTechnologies.GNSS);
-    }
-
-    /**
-     * called from native code to report GPS status change.
-     */
-    private void reportGeofenceStatus(int status, int flags, double latitude,
-            double longitude, double altitude, float speed, float bearing, float accuracy,
-            long timestamp) {
-        if (mGeofenceHardwareImpl == null) {
-            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
-        }
-        Location location = buildLocation(
-                flags,
-                latitude,
-                longitude,
-                altitude,
-                speed,
-                bearing,
-                accuracy,
-                timestamp);
-        int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
-        if(status == GPS_GEOFENCE_AVAILABLE) {
-            monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
-        }
-        mGeofenceHardwareImpl.reportGeofenceMonitorStatus(
-                GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
-                monitorStatus,
-                location,
-                FusedBatchOptions.SourceTechnologies.GNSS);
-    }
-
-    /**
-     * called from native code - Geofence Add callback
-     */
-    private void reportGeofenceAddStatus(int geofenceId, int status) {
-        if (mGeofenceHardwareImpl == null) {
-            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
-        }
-        mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status));
-    }
-
-    /**
-     * called from native code - Geofence Remove callback
-     */
-    private void reportGeofenceRemoveStatus(int geofenceId, int status) {
-        if (mGeofenceHardwareImpl == null) {
-            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
-        }
-        mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status));
-    }
-
-    /**
-     * called from native code - Geofence Pause callback
-     */
-    private void reportGeofencePauseStatus(int geofenceId, int status) {
-        if (mGeofenceHardwareImpl == null) {
-            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
-        }
-        mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status));
-    }
-
-    /**
-     * called from native code - Geofence Resume callback
-     */
-    private void reportGeofenceResumeStatus(int geofenceId, int status) {
-        if (mGeofenceHardwareImpl == null) {
-            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
-        }
-        mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status));
-    }
-
-    //=============================================================
-    // NI Client support
-    //=============================================================
-    private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
-        // Sends a response for an NI request to HAL.
-        @Override
-        public boolean sendNiResponse(int notificationId, int userResponse)
-        {
-            // TODO Add Permission check
-
-            if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
-                    ", response: " + userResponse);
-            native_send_ni_response(notificationId, userResponse);
-            return true;
-        }
-    };
-
-    public INetInitiatedListener getNetInitiatedListener() {
-        return mNetInitiatedListener;
-    }
-
-    // Called by JNI function to report an NI request.
-    public void reportNiNotification(
-            int notificationId,
-            int niType,
-            int notifyFlags,
-            int timeout,
-            int defaultResponse,
-            String requestorId,
-            String text,
-            int requestorIdEncoding,
-            int textEncoding,
-            String extras  // Encoded extra data
-        )
-    {
-        Log.i(TAG, "reportNiNotification: entered");
-        Log.i(TAG, "notificationId: " + notificationId +
-                ", niType: " + niType +
-                ", notifyFlags: " + notifyFlags +
-                ", timeout: " + timeout +
-                ", defaultResponse: " + defaultResponse);
-
-        Log.i(TAG, "requestorId: " + requestorId +
-                ", text: " + text +
-                ", requestorIdEncoding: " + requestorIdEncoding +
-                ", textEncoding: " + textEncoding);
-
-        GpsNiNotification notification = new GpsNiNotification();
-
-        notification.notificationId = notificationId;
-        notification.niType = niType;
-        notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
-        notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
-        notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
-        notification.timeout = timeout;
-        notification.defaultResponse = defaultResponse;
-        notification.requestorId = requestorId;
-        notification.text = text;
-        notification.requestorIdEncoding = requestorIdEncoding;
-        notification.textEncoding = textEncoding;
-
-        // Process extras, assuming the format is
-        // one of more lines of "key = value"
-        Bundle bundle = new Bundle();
-
-        if (extras == null) extras = "";
-        Properties extraProp = new Properties();
-
-        try {
-            extraProp.load(new StringReader(extras));
-        }
-        catch (IOException e)
-        {
-            Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras);
-        }
-
-        for (Entry<Object, Object> ent : extraProp.entrySet())
-        {
-            bundle.putString((String) ent.getKey(), (String) ent.getValue());
-        }
-
-        notification.extras = bundle;
-
-        mNIHandler.handleNiNotification(notification);
-    }
-
-    /**
-     * Called from native code to request set id info.
-     * We should be careful about receiving null string from the TelephonyManager,
-     * because sending null String to JNI function would cause a crash.
-     */
-
-    private void requestSetID(int flags) {
-        TelephonyManager phone = (TelephonyManager)
-                mContext.getSystemService(Context.TELEPHONY_SERVICE);
-        int type = AGPS_SETID_TYPE_NONE;
-        String data = "";
-
-        if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
-            String data_temp = phone.getSubscriberId();
-            if (data_temp == null) {
-                // This means the framework does not have the SIM card ready.
-            } else {
-                // This means the framework has the SIM card.
-                data = data_temp;
-                type = AGPS_SETID_TYPE_IMSI;
-            }
-        }
-        else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
-            String data_temp = phone.getLine1Number();
-            if (data_temp == null) {
-                // This means the framework does not have the SIM card ready.
-            } else {
-                // This means the framework has the SIM card.
-                data = data_temp;
-                type = AGPS_SETID_TYPE_MSISDN;
-            }
-        }
-        native_agps_set_id(type, data);
-    }
-
-    /**
-     * Called from native code to request utc time info
-     */
-    private void requestUtcTime() {
-        if (DEBUG) Log.d(TAG, "utcTimeRequest");
-        sendMessage(INJECT_NTP_TIME, 0, null);
-    }
-
-    /**
-     * Called from native code to request reference location info
-     */
-
-    private void requestRefLocation(int flags) {
-        TelephonyManager phone = (TelephonyManager)
-                mContext.getSystemService(Context.TELEPHONY_SERVICE);
-        final int phoneType = phone.getPhoneType();
-        if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
-            GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation();
-            if ((gsm_cell != null) && (phone.getNetworkOperator() != null)
-                    && (phone.getNetworkOperator().length() > 3)) {
-                int type;
-                int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3));
-                int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3));
-                int networkType = phone.getNetworkType();
-                if (networkType == TelephonyManager.NETWORK_TYPE_UMTS
-                    || networkType == TelephonyManager.NETWORK_TYPE_HSDPA
-                    || networkType == TelephonyManager.NETWORK_TYPE_HSUPA
-                    || networkType == TelephonyManager.NETWORK_TYPE_HSPA
-                    || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) {
-                    type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
-                } else {
-                    type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
-                }
-                native_agps_set_ref_location_cellid(type, mcc, mnc,
-                        gsm_cell.getLac(), gsm_cell.getCid());
-            } else {
-                Log.e(TAG,"Error getting cell location info.");
-            }
-        } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
-            Log.e(TAG, "CDMA not supported.");
-        }
-    }
-
-    private void sendMessage(int message, int arg, Object obj) {
-        // hold a wake lock until this message is delivered
-        // note that this assumes the message will not be removed from the queue before
-        // it is handled (otherwise the wake lock would be leaked).
-        mWakeLock.acquire();
-        mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
-    }
-
-    private final class ProviderHandler extends Handler {
-        public ProviderHandler(Looper looper) {
-            super(looper, null, true /*async*/);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            int message = msg.what;
-            switch (message) {
-                case ENABLE:
-                    if (msg.arg1 == 1) {
-                        handleEnable();
-                    } else {
-                        handleDisable();
-                    }
-                    break;
-                case SET_REQUEST:
-                    GpsRequest gpsRequest = (GpsRequest) msg.obj;
-                    handleSetRequest(gpsRequest.request, gpsRequest.source);
-                    break;
-                case UPDATE_NETWORK_STATE:
-                    handleUpdateNetworkState((Network) msg.obj);
-                    break;
-                case REQUEST_SUPL_CONNECTION:
-                    handleRequestSuplConnection((InetAddress) msg.obj);
-                    break;
-                case RELEASE_SUPL_CONNECTION:
-                    handleReleaseSuplConnection(msg.arg1);
-                    break;
-                case INJECT_NTP_TIME:
-                    handleInjectNtpTime();
-                    break;
-                case DOWNLOAD_XTRA_DATA:
-                    if (mSupportsXtra) {
-                        handleDownloadXtraData();
-                    }
-                    break;
-                case INJECT_NTP_TIME_FINISHED:
-                    mInjectNtpTimePending = STATE_IDLE;
-                    break;
-                case DOWNLOAD_XTRA_DATA_FINISHED:
-                    mDownloadXtraDataPending = STATE_IDLE;
-                    break;
-                case UPDATE_LOCATION:
-                    handleUpdateLocation((Location) msg.obj);
-                    break;
-                case SUBSCRIPTION_OR_SIM_CHANGED:
-                    subscriptionOrSimChanged(mContext);
-                    break;
-                case INITIALIZE_HANDLER:
-                    handleInitialize();
-                    break;
-            }
-            if (msg.arg2 == 1) {
-                // wakelock was taken for this message, release it
-                mWakeLock.release();
-            }
-        }
-
-        /**
-         * This method is bound to {@link #GpsLocationProvider(Context, ILocationManager, Looper)}.
-         * It is in charge of loading properties and registering for events that will be posted to
-         * this handler.
-         */
-        private void handleInitialize() {
-            // load default GPS configuration
-            // (this configuration might change in the future based on SIM changes)
-            reloadGpsProperties(mContext, mProperties);
-
-            // TODO: When this object "finishes" we should unregister by invoking
-            // SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener);
-            // This is not strictly necessary because it will be unregistered if the
-            // notification fails but it is good form.
-
-            // Register for SubscriptionInfo list changes which is guaranteed
-            // to invoke onSubscriptionsChanged the first time.
-            SubscriptionManager.from(mContext)
-                    .addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
-
-            // listen for events
-            IntentFilter intentFilter;
-            if (native_is_agps_ril_supported()) {
-                intentFilter = new IntentFilter();
-                intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION);
-                intentFilter.addDataScheme("sms");
-                intentFilter.addDataAuthority("localhost", "7275");
-                mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
-
-                intentFilter = new IntentFilter();
-                intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION);
-                try {
-                    intentFilter.addDataType("application/vnd.omaloc-supl-init");
-                } catch (IntentFilter.MalformedMimeTypeException e) {
-                    Log.w(TAG, "Malformed SUPL init mime type");
-                }
-                mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
-            } else if (DEBUG) {
-                Log.d(TAG, "Skipped registration for SMS/WAP-PUSH messages because AGPS Ril in GPS"
-                        + " HAL is not supported");
-            }
-
-            intentFilter = new IntentFilter();
-            intentFilter.addAction(ALARM_WAKEUP);
-            intentFilter.addAction(ALARM_TIMEOUT);
-            intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
-            intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
-            intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
-            intentFilter.addAction(Intent.ACTION_SCREEN_ON);
-            intentFilter.addAction(SIM_STATE_CHANGED);
-            mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
-
-            // register for connectivity change events, this is equivalent to the deprecated way of
-            // registering for CONNECTIVITY_ACTION broadcasts
-            NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
-            networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-            networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
-            NetworkRequest networkRequest = networkRequestBuilder.build();
-            mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback);
-
-            // listen for PASSIVE_PROVIDER updates
-            LocationManager locManager =
-                    (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
-            long minTime = 0;
-            float minDistance = 0;
-            boolean oneShot = false;
-            LocationRequest request = LocationRequest.createFromDeprecatedProvider(
-                    LocationManager.PASSIVE_PROVIDER,
-                    minTime,
-                    minDistance,
-                    oneShot);
-            // Don't keep track of this request since it's done on behalf of other clients
-            // (which are kept track of separately).
-            request.setHideFromAppOps(true);
-            locManager.requestLocationUpdates(
-                    request,
-                    new NetworkLocationListener(),
-                    getLooper());
-        }
-    }
-
-    private final class NetworkLocationListener implements LocationListener {
-        @Override
-        public void onLocationChanged(Location location) {
-            // this callback happens on mHandler looper
-            if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
-                handleUpdateLocation(location);
-            }
-        }
-        @Override
-        public void onStatusChanged(String provider, int status, Bundle extras) { }
-        @Override
-        public void onProviderEnabled(String provider) { }
-        @Override
-        public void onProviderDisabled(String provider) { }
-    }
-
-    private String getSelectedApn() {
-        Uri uri = Uri.parse("content://telephony/carriers/preferapn");
-        Cursor cursor = null;
-        try {
-            cursor = mContext.getContentResolver().query(
-                    uri,
-                    new String[] { "apn" },
-                    null /* selection */,
-                    null /* selectionArgs */,
-                    Carriers.DEFAULT_SORT_ORDER);
-            if (cursor != null && cursor.moveToFirst()) {
-                return cursor.getString(0);
-            } else {
-                Log.e(TAG, "No APN found to select.");
-            }
-        } catch (Exception e) {
-            Log.e(TAG, "Error encountered on selecting the APN.", e);
-        } finally {
-            if (cursor != null) {
-                cursor.close();
-            }
-        }
-
-        return null;
-    }
-
-    private int getApnIpType(String apn) {
-        ensureInHandlerThread();
-        if (apn == null) {
-            return APN_INVALID;
-        }
-
-        String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn);
-        Cursor cursor = null;
-        try {
-            cursor = mContext.getContentResolver().query(
-                    Carriers.CONTENT_URI,
-                    new String[] { Carriers.PROTOCOL },
-                    selection,
-                    null,
-                    Carriers.DEFAULT_SORT_ORDER);
-
-            if (null != cursor && cursor.moveToFirst()) {
-                return translateToApnIpType(cursor.getString(0), apn);
-            } else {
-                Log.e(TAG, "No entry found in query for APN: " + apn);
-            }
-        } catch (Exception e) {
-            Log.e(TAG, "Error encountered on APN query for: " + apn, e);
-        } finally {
-            if (cursor != null) {
-                cursor.close();
-            }
-        }
-
-        return APN_INVALID;
-    }
-
-    private int translateToApnIpType(String ipProtocol, String apn) {
-        if ("IP".equals(ipProtocol)) {
-            return APN_IPV4;
-        }
-        if ("IPV6".equals(ipProtocol)) {
-            return APN_IPV6;
-        }
-        if ("IPV4V6".equals(ipProtocol)) {
-            return APN_IPV4V6;
-        }
-
-        // we hit the default case so the ipProtocol is not recognized
-        String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn);
-        Log.e(TAG, message);
-        return APN_INVALID;
-    }
-
-    private void setRouting() {
-        if (mAGpsDataConnectionIpAddr == null) {
-            return;
-        }
-
-        // TODO: replace the use of this deprecated API
-        boolean result = mConnMgr.requestRouteToHostAddress(
-                ConnectivityManager.TYPE_MOBILE_SUPL,
-                mAGpsDataConnectionIpAddr);
-
-        if (!result) {
-            Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr);
-        } else if (DEBUG) {
-            Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr);
-        }
-    }
-
-    /**
-     * @return {@code true} if there is a data network available for outgoing connections,
-     *         {@code false} otherwise.
-     */
-    private boolean isDataNetworkConnected() {
-        NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo();
-        return activeNetworkInfo != null && activeNetworkInfo.isConnected();
-    }
-
-    /**
-     * Ensures the calling function is running in the thread associated with {@link #mHandler}.
-     */
-    private void ensureInHandlerThread() {
-        if (mHandler != null && Looper.myLooper() == mHandler.getLooper()) {
-            return;
-        }
-        throw new RuntimeException("This method must run on the Handler thread.");
-    }
-
-    /**
-     * @return A string representing the current state stored in {@link #mAGpsDataConnectionState}.
-     */
-    private String agpsDataConnStateAsString() {
-        switch(mAGpsDataConnectionState) {
-            case AGPS_DATA_CONNECTION_CLOSED:
-                return "CLOSED";
-            case AGPS_DATA_CONNECTION_OPEN:
-                return "OPEN";
-            case AGPS_DATA_CONNECTION_OPENING:
-                return "OPENING";
-            default:
-                return "<Unknown>";
-        }
-    }
-
-    /**
-     * @return A string representing the given GPS_AGPS_DATA status.
-     */
-    private String agpsDataConnStatusAsString(int agpsDataConnStatus) {
-        switch (agpsDataConnStatus) {
-            case GPS_AGPS_DATA_CONNECTED:
-                return "CONNECTED";
-            case GPS_AGPS_DATA_CONN_DONE:
-                return "DONE";
-            case GPS_AGPS_DATA_CONN_FAILED:
-                return "FAILED";
-            case GPS_RELEASE_AGPS_DATA_CONN:
-                return "RELEASE";
-            case GPS_REQUEST_AGPS_DATA_CONN:
-                return "REQUEST";
-            default:
-                return "<Unknown>";
-        }
-    }
-
-    @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        StringBuilder s = new StringBuilder();
-        s.append("  mFixInterval=").append(mFixInterval).append('\n');
-        s.append("  mDisableGps (battery saver mode)=").append(mDisableGps).append('\n');
-        s.append("  mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities));
-        s.append(" ( ");
-        if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHEDULING ");
-        if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
-        if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA ");
-        if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT ");
-        if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME ");
-        if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING ");
-        if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS ");
-        if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
-        s.append(")\n");
-
-        s.append(native_get_internal_state());
-        pw.append(s);
-    }
-
-    /**
-     * A simple implementation of exponential backoff.
-     */
-    private static final class BackOff {
-        private static final int MULTIPLIER = 2;
-        private final long mInitIntervalMillis;
-        private final long mMaxIntervalMillis;
-        private long mCurrentIntervalMillis;
-
-        public BackOff(long initIntervalMillis, long maxIntervalMillis) {
-            mInitIntervalMillis = initIntervalMillis;
-            mMaxIntervalMillis = maxIntervalMillis;
-
-            mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
-        }
-
-        public long nextBackoffMillis() {
-            if (mCurrentIntervalMillis > mMaxIntervalMillis) {
-                return mMaxIntervalMillis;
-            }
-
-            mCurrentIntervalMillis *= MULTIPLIER;
-            return mCurrentIntervalMillis;
-        }
-
-        public void reset() {
-            mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
-        }
-    }
-
-    // for GPS SV statistics
-    private static final int MAX_SVS = 32;
-    private static final int EPHEMERIS_MASK = 0;
-    private static final int ALMANAC_MASK = 1;
-    private static final int USED_FOR_FIX_MASK = 2;
-
-    // preallocated arrays, to avoid memory allocation in reportStatus()
-    private int mSvs[] = new int[MAX_SVS];
-    private float mSnrs[] = new float[MAX_SVS];
-    private float mSvElevations[] = new float[MAX_SVS];
-    private float mSvAzimuths[] = new float[MAX_SVS];
-    private int mSvMasks[] = new int[3];
-    private int mSvCount;
-    // preallocated to avoid memory allocation in reportNmea()
-    private byte[] mNmeaBuffer = new byte[120];
-
-    static { class_init_native(); }
-    private static native void class_init_native();
-    private static native boolean native_is_supported();
-    private static native boolean native_is_agps_ril_supported();
-    private static native boolean native_is_gnss_configuration_supported();
-
-    private native boolean native_init();
-    private native void native_cleanup();
-    private native boolean native_set_position_mode(int mode, int recurrence, int min_interval,
-            int preferred_accuracy, int preferred_time);
-    private native boolean native_start();
-    private native boolean native_stop();
-    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[] svs, float[] snrs,
-            float[] elevations, float[] azimuths, int[] masks);
-    private native int native_read_nmea(byte[] buffer, int bufferSize);
-    private native void native_inject_location(double latitude, double longitude, float accuracy);
-
-    // XTRA Support
-    private native void native_inject_time(long time, long timeReference, int uncertainty);
-    private native boolean native_supports_xtra();
-    private native void native_inject_xtra_data(byte[] data, int length);
-
-    // DEBUG Support
-    private native String native_get_internal_state();
-
-    // AGPS Support
-    private native void native_agps_data_conn_open(String apn, int apnIpType);
-    private native void native_agps_data_conn_closed();
-    private native void native_agps_data_conn_failed();
-    private native void native_agps_ni_message(byte [] msg, int length);
-    private native void native_set_agps_server(int type, String hostname, int port);
-
-    // Network-initiated (NI) Support
-    private native void native_send_ni_response(int notificationId, int userResponse);
-
-    // AGPS ril suport
-    private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
-            int lac, int cid);
-    private native void native_agps_set_id(int type, String setid);
-
-    private native void native_update_network_state(boolean connected, int type,
-            boolean roaming, boolean available, String extraInfo, String defaultAPN);
-
-    // Hardware Geofence support.
-    private static native boolean native_is_geofence_supported();
-    private static native boolean native_add_geofence(int geofenceId, double latitude,
-            double longitude, double radius, int lastTransition,int monitorTransitions,
-            int notificationResponsivenes, int unknownTimer);
-    private static native boolean native_remove_geofence(int geofenceId);
-    private static native boolean native_resume_geofence(int geofenceId, int transitions);
-    private static native boolean native_pause_geofence(int geofenceId);
-
-    // Gps Hal measurements support.
-    private static native boolean native_is_measurement_supported();
-    private native boolean native_start_measurement_collection();
-    private native boolean native_stop_measurement_collection();
-
-    // Gps Navigation message support.
-    private static native boolean native_is_navigation_message_supported();
-    private native boolean native_start_navigation_message_collection();
-    private native boolean native_stop_navigation_message_collection();
-
-    // GNSS Configuration
-    private static native void native_configuration_update(String configData);
-}
diff --git a/services/core/java/com/android/server/location/GpsStatusListenerHelper.java b/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
deleted file mode 100644
index 53ff6c2..0000000
--- a/services/core/java/com/android/server/location/GpsStatusListenerHelper.java
+++ /dev/null
@@ -1,112 +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.location;
-
-import android.location.IGpsStatusListener;
-import android.os.Handler;
-import android.os.RemoteException;
-
-/**
- * Implementation of a handler for {@link IGpsStatusListener}.
- */
-abstract class GpsStatusListenerHelper extends RemoteListenerHelper<IGpsStatusListener> {
-    protected GpsStatusListenerHelper(Handler handler) {
-        super(handler, "GpsStatusListenerHelper");
-        setSupported(GpsLocationProvider.isSupported());
-    }
-
-    @Override
-    protected boolean registerWithService() {
-        return true;
-    }
-
-    @Override
-    protected void unregisterFromService() {}
-
-    @Override
-    protected ListenerOperation<IGpsStatusListener> getHandlerOperation(int result) {
-        return null;
-    }
-
-    public void onStatusChanged(boolean isNavigating) {
-        Operation operation;
-        if (isNavigating) {
-            operation = new Operation() {
-                @Override
-                public void execute(IGpsStatusListener listener) throws RemoteException {
-                    listener.onGpsStarted();
-                }
-            };
-        } else {
-            operation = new Operation() {
-                @Override
-                public void execute(IGpsStatusListener listener) throws RemoteException {
-                    listener.onGpsStopped();
-                }
-            };
-        }
-        foreach(operation);
-    }
-
-    public void onFirstFix(final int timeToFirstFix) {
-        Operation operation = new Operation() {
-            @Override
-            public void execute(IGpsStatusListener listener) throws RemoteException {
-                listener.onFirstFix(timeToFirstFix);
-            }
-        };
-        foreach(operation);
-    }
-
-    public void onSvStatusChanged(
-            final int svCount,
-            final int[] prns,
-            final float[] snrs,
-            final float[] elevations,
-            final float[] azimuths,
-            final int ephemerisMask,
-            final int almanacMask,
-            final int usedInFixMask) {
-        Operation operation = new Operation() {
-            @Override
-            public void execute(IGpsStatusListener listener) throws RemoteException {
-                listener.onSvStatusChanged(
-                        svCount,
-                        prns,
-                        snrs,
-                        elevations,
-                        azimuths,
-                        ephemerisMask,
-                        almanacMask,
-                        usedInFixMask);
-            }
-        };
-        foreach(operation);
-    }
-
-    public void onNmeaReceived(final long timestamp, final String nmea) {
-        Operation operation = new Operation() {
-            @Override
-            public void execute(IGpsStatusListener listener) throws RemoteException {
-                listener.onNmeaReceived(timestamp, nmea);
-            }
-        };
-        foreach(operation);
-    }
-
-    private interface Operation extends ListenerOperation<IGpsStatusListener> {}
-}
diff --git a/services/core/java/com/android/server/media/MediaResourceMonitorService.java b/services/core/java/com/android/server/media/MediaResourceMonitorService.java
new file mode 100644
index 0000000..50dd607
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaResourceMonitorService.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 com.android.server.media;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.content.Context;
+import android.content.Intent;
+import android.media.IMediaResourceMonitor;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+import com.android.server.SystemService;
+
+import java.util.List;
+
+/** This class provides a system service that monitors media resource usage. */
+public class MediaResourceMonitorService extends SystemService {
+    private static final String TAG = "MediaResourceMonitor";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    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) {
+        super(context);
+        mMediaResourceMonitorImpl = new MediaResourceMonitorImpl();
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(SERVICE_NAME, mMediaResourceMonitorImpl);
+    }
+
+    class MediaResourceMonitorImpl extends IMediaResourceMonitor.Stub {
+        @Override
+        public void notifyResourceGranted(int pid, String type, String subType, long value)
+                throws RemoteException {
+            if (DEBUG) {
+                Slog.d(TAG, "notifyResourceGranted(pid=" + pid + ", type=" + type + ", subType="
+                        + subType + ", value=" + value + ")");
+            }
+            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) {
+                    Intent intent = new Intent(Intent.ACTION_MEDIA_RESOURCE_GRANTED);
+                    intent.putExtra(Intent.EXTRA_PACKAGES, pkgNames);
+                    intent.putExtra(Intent.EXTRA_MEDIA_RESOURCE_TYPE, resourceType);
+                    getContext().sendBroadcastAsUser(intent,
+                            new UserHandle(ActivityManager.getCurrentUser()),
+                            android.Manifest.permission.RECEIVE_MEDIA_RESOURCE_USAGE);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        private String[] getPackageNamesFromPid(int pid) {
+            try {
+                for (ActivityManager.RunningAppProcessInfo proc :
+                        ActivityManagerNative.getDefault().getRunningAppProcesses()) {
+                    if (proc.pid == pid) {
+                        return proc.pkgList;
+                    }
+                }
+            } catch (RemoteException e) {
+                Slog.w(TAG, "ActivityManager.getRunningAppProcesses() failed");
+            }
+            return null;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index d5c3113..745f476 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -767,7 +767,7 @@
                 synchronized (mLock) {
                     // If we don't have a media button receiver to fall back on
                     // include non-playing sessions for dispatching
-                    UserRecord ur = mUserRecords.get(ActivityManager.getCurrentUser());
+                    UserRecord ur = mUserRecords.get(mCurrentUserId);
                     boolean useNotPlayingSessions = (ur == null) ||
                             (ur.mLastMediaButtonReceiver == null
                                 && ur.mRestoredMediaButtonReceiver == null);
@@ -949,8 +949,7 @@
                         mKeyEventReceiver);
             } else {
                 // Launch the last PendingIntent we had with priority
-                int userId = ActivityManager.getCurrentUser();
-                UserRecord user = mUserRecords.get(userId);
+                UserRecord user = mUserRecords.get(mCurrentUserId);
                 if (user != null && (user.mLastMediaButtonReceiver != null
                         || user.mRestoredMediaButtonReceiver != null)) {
                     if (DEBUG) {
@@ -967,11 +966,11 @@
                         if (user.mLastMediaButtonReceiver != null) {
                             user.mLastMediaButtonReceiver.send(getContext(),
                                     needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
-                                    mediaButtonIntent, mKeyEventReceiver, null);
+                                    mediaButtonIntent, mKeyEventReceiver, mHandler);
                         } else {
                             mediaButtonIntent.setComponent(user.mRestoredMediaButtonReceiver);
                             getContext().sendBroadcastAsUser(mediaButtonIntent,
-                                    new UserHandle(userId));
+                                    new UserHandle(mCurrentUserId));
                         }
                     } catch (CanceledException e) {
                         Log.i(TAG, "Error sending key event to media button receiver "
diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java
index f230bb3..68dc715 100644
--- a/services/core/java/com/android/server/net/NetworkIdentitySet.java
+++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java
@@ -61,7 +61,7 @@
                 roaming = false;
             }
 
-            add(new NetworkIdentity(type, subType, subscriberId, networkId, false));
+            add(new NetworkIdentity(type, subType, subscriberId, networkId, roaming));
         }
     }
 
@@ -77,6 +77,19 @@
         }
     }
 
+    /** @return whether any {@link NetworkIdentity} in this set is considered roaming. */
+    public boolean isAnyMemberRoaming() {
+        if (isEmpty()) {
+            return false;
+        }
+        for (NetworkIdentity ident : this) {
+            if (ident.getRoaming()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private static void writeOptionalString(DataOutputStream out, String value) throws IOException {
         if (value != null) {
             out.writeByte(1);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 2ac0ba6..492632c 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -31,6 +31,9 @@
 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.isNetworkTypeMobile;
 import static android.net.NetworkPolicy.CYCLE_NONE;
 import static android.net.NetworkPolicy.LIMIT_DISABLED;
@@ -75,6 +78,7 @@
 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;
 
 import android.Manifest;
@@ -123,6 +127,7 @@
 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;
@@ -153,6 +158,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.content.PackageMonitor;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
@@ -213,6 +219,8 @@
     private static final String TAG_NETWORK_POLICY = "network-policy";
     private static final String TAG_UID_POLICY = "uid-policy";
     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 ATTR_VERSION = "version";
     private static final String ATTR_RESTRICT_BACKGROUND = "restrictBackground";
@@ -304,6 +312,11 @@
 
     private final SparseBooleanArray mPowerSaveTempWhitelistAppIds = new SparseBooleanArray();
 
+    /**
+     * UIDs that have been white-listed to avoid restricted background.
+     */
+    private final SparseBooleanArray mRestrictBackgroundWhitelistUids = new SparseBooleanArray();
+
     /** Set of ifaces that are metered. */
     private ArraySet<String> mMeteredIfaces = new ArraySet<>();
     /** Set of over-limit templates that have been notified. */
@@ -324,6 +337,8 @@
 
     private final AppOpsManager mAppOps;
 
+    private final MyPackageMonitor mPackageMonitor;
+
     // TODO: keep whitelist of system-critical services that should never have
     // rules enforced, such as system, phone, and radio UIDs.
 
@@ -363,6 +378,8 @@
         mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml"));
 
         mAppOps = context.getSystemService(AppOpsManager.class);
+
+        mPackageMonitor = new MyPackageMonitor();
     }
 
     public void bindConnectivityManager(IConnectivityManager connManager) {
@@ -431,6 +448,8 @@
 
         mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
 
+        mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
+
         synchronized (mRulesLock) {
             updatePowerSaveWhitelistLocked();
             mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
@@ -1127,7 +1146,7 @@
         // 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 precendence
+        // 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;
 
@@ -1136,7 +1155,7 @@
         final ArrayList<Pair<String, NetworkIdentity>> connIdents = new ArrayList<>(states.length);
         final ArraySet<String> connIfaces = new ArraySet<String>(states.length);
         for (NetworkState state : states) {
-            if (state.networkInfo.isConnected()) {
+            if (state.networkInfo != null && state.networkInfo.isConnected()) {
                 final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
 
                 final String baseIface = state.linkProperties.getInterfaceName();
@@ -1339,6 +1358,7 @@
 
             int type;
             int version = VERSION_INIT;
+            boolean insideWhitelist = false;
             while ((type = in.next()) != END_DOCUMENT) {
                 final String tag = in.getName();
                 if (type == START_TAG) {
@@ -1431,7 +1451,17 @@
                         } else {
                             Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
                         }
+                    } else if (TAG_WHITELIST.equals(tag)) {
+                        insideWhitelist = true;
+                    } else if (TAG_RESTRICT_BACKGROUND.equals(tag) && insideWhitelist) {
+                        final int uid = readIntAttribute(in, ATTR_UID);
+                        mRestrictBackgroundWhitelistUids.put(uid, true);
                     }
+                } else if (type == END_TAG) {
+                    if (TAG_WHITELIST.equals(tag)) {
+                        insideWhitelist = false;
+                    }
+
                 }
             }
 
@@ -1519,6 +1549,21 @@
             }
 
             out.endTag(null, TAG_POLICY_LIST);
+
+            // write all whitelists
+            out.startTag(null, TAG_WHITELIST);
+
+            // restrict background whitelist
+            final int size = mRestrictBackgroundWhitelistUids.size();
+            for (int i = 0; i < size; i++) {
+                final int uid = mRestrictBackgroundWhitelistUids.keyAt(i);
+                out.startTag(null, TAG_RESTRICT_BACKGROUND);
+                writeIntAttribute(out, ATTR_UID, uid);
+                out.endTag(null, TAG_RESTRICT_BACKGROUND);
+            }
+
+            out.endTag(null, TAG_WHITELIST);
+
             out.endDocument();
 
             mPolicyFile.finishWrite(fos);
@@ -1789,6 +1834,63 @@
     }
 
     @Override
+    public void addRestrictBackgroundWhitelistedUid(int uid) {
+        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+        Slog.i(TAG, "adding uid " + uid + " to restrict background whitelist");
+        synchronized (mRulesLock) {
+            mRestrictBackgroundWhitelistUids.append(uid, true);
+            writePolicyLocked();
+            // TODO: call other update methods like updateNetworkRulesLocked?
+        }
+    }
+
+    @Override
+    public void removeRestrictBackgroundWhitelistedUid(int uid) {
+        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+        Slog.i(TAG, "removing uid " + uid + " from restrict background whitelist");
+        synchronized (mRulesLock) {
+            removeRestrictBackgroundWhitelistedUidLocked(uid);
+        }
+    }
+
+    private void removeRestrictBackgroundWhitelistedUidLocked(int uid) {
+        mRestrictBackgroundWhitelistUids.delete(uid);
+        writePolicyLocked();
+        // TODO: call other update methods like updateNetworkRulesLocked?
+    }
+
+    @Override
+    public int[] getRestrictBackgroundWhitelistedUids() {
+        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+        synchronized (mRulesLock) {
+            final int size = mRestrictBackgroundWhitelistUids.size();
+            final int[] whitelist = new int[size];
+            for (int i = 0; i < size; i++) {
+                whitelist[i] = mRestrictBackgroundWhitelistUids.keyAt(i);
+            }
+            if (LOGV) {
+                Slog.v(TAG, "getRestrictBackgroundWhitelistedUids(): "
+                        + mRestrictBackgroundWhitelistUids);
+            }
+            return whitelist;
+        }
+    }
+
+    @Override
+    public int getRestrictBackgroundByCaller() {
+        mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
+        final int uid = Binder.getCallingUid();
+        synchronized (mRulesLock) {
+            if (!mRestrictBackground) {
+                return RESTRICT_BACKGROUND_STATUS_DISABLED;
+            }
+            return mRestrictBackgroundWhitelistUids.get(uid)
+                    ? RESTRICT_BACKGROUND_STATUS_WHITELISTED
+                    : RESTRICT_BACKGROUND_STATUS_ENABLED;
+        }
+    }
+
+    @Override
     public boolean getRestrictBackground() {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
 
@@ -1888,6 +1990,10 @@
         if (policy != null) {
             return policy.metered;
         } else {
+            if (state.networkInfo == null) {
+                return false;
+            }
+
             final int type = state.networkInfo.getType();
             if (isNetworkTypeMobile(type) || type == TYPE_WIMAX) {
                 return true;
@@ -1978,6 +2084,18 @@
                 fout.decreaseIndent();
             }
 
+            size = mRestrictBackgroundWhitelistUids.size();
+            if (size > 0) {
+                fout.println("Restrict background whitelist uids:");
+                fout.increaseIndent();
+                for (int i = 0; i < size; i++) {
+                    fout.print("UID=");
+                    fout.print(mRestrictBackgroundWhitelistUids.keyAt(i));
+                    fout.println();
+                }
+                fout.decreaseIndent();
+            }
+
             final SparseBooleanArray knownUids = new SparseBooleanArray();
             collectKeys(mUidState, knownUids);
             collectKeys(mUidRules, knownUids);
@@ -2006,6 +2124,13 @@
     }
 
     @Override
+    public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+            String[] args, ResultReceiver resultReceiver) throws RemoteException {
+        (new NetworkPolicyManagerShellCommand(this)).exec(
+                this, in, out, err, args, resultReceiver);
+    }
+
+    @Override
     public boolean isUidForeground(int uid) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
 
@@ -2187,7 +2312,8 @@
         // 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.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS
+                        | PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
 
         for (UserInfo user : users) {
             for (ApplicationInfo app : apps) {
@@ -2233,9 +2359,11 @@
         final String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
         final int userId = UserHandle.getUserId(uid);
 
-        for (String packageName : packages) {
-            if (!mUsageStats.isAppIdle(packageName, uid, userId)) {
-                return false;
+        if (!ArrayUtils.isEmpty(packages)) {
+            for (String packageName : packages) {
+                if (!mUsageStats.isAppIdle(packageName, uid, userId)) {
+                    return false;
+                }
             }
         }
         return true;
@@ -2276,8 +2404,11 @@
             uidRules = RULE_REJECT_METERED;
         } else if (mRestrictBackground) {
             if (!uidForeground) {
-                // uid in background, and global background disabled
-                uidRules = RULE_REJECT_METERED;
+                // 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;
+                }
             }
         } else if (mRestrictPower) {
             final boolean whitelisted = mPowerSaveWhitelistExceptIdleAppIds.get(appId)
@@ -2332,7 +2463,8 @@
         @Override
         public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
             try {
-                int uid = mContext.getPackageManager().getPackageUid(packageName, userId);
+                final int uid = mContext.getPackageManager().getPackageUidAsUser(packageName,
+                        PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
                 synchronized (mRulesLock) {
                     updateRuleForAppIdleLocked(uid);
                 }
@@ -2638,4 +2770,23 @@
             }
         }
     }
+
+    private class MyPackageMonitor extends PackageMonitor {
+
+        @Override
+        public void onPackageRemoved(String packageName, int uid) {
+            if (LOGV) Slog.v(TAG, "onPackageRemoved: " + packageName + " ->" + uid);
+            synchronized (mRulesLock) {
+                removeRestrictBackgroundWhitelistedUidLocked(uid);
+            }
+        }
+
+        @Override
+        public void onPackageRemovedAllUsers(String packageName, int uid) {
+            if (LOGV) Slog.v(TAG, "onPackageRemovedAllUsers: " + packageName + " ->" + uid);
+            synchronized (mRulesLock) {
+                removeRestrictBackgroundWhitelistedUidLocked(uid);
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
new file mode 100644
index 0000000..7b1acca
--- /dev/null
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 java.io.PrintWriter;
+
+import android.content.Intent;
+import android.net.INetworkPolicyManager;
+import android.os.RemoteException;
+import android.os.ShellCommand;
+
+public class NetworkPolicyManagerShellCommand extends ShellCommand {
+
+    final INetworkPolicyManager mInterface;
+
+    NetworkPolicyManagerShellCommand(NetworkPolicyManagerService service) {
+        mInterface = service;
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        if (cmd == null) {
+            return handleDefaultCommands(cmd);
+        }
+        final PrintWriter pw = getOutPrintWriter();
+        try {
+            switch(cmd) {
+                case "get":
+                    return runGet();
+                case "set":
+                    return runSet();
+                case "list":
+                    return runList();
+                case "add":
+                    return runAdd();
+                case "remove":
+                    return runRemove();
+                default:
+                    return handleDefaultCommands(cmd);
+            }
+        } catch (RemoteException e) {
+            pw.println("Remote exception: " + e);
+        }
+        return -1;
+    }
+
+    @Override
+    public void onHelp() {
+        final PrintWriter pw = getOutPrintWriter();
+        pw.println("Network policy manager (netpolicy) commands:");
+        pw.println("  help");
+        pw.println("    Print this help text.");
+        pw.println("");
+        pw.println("  get restrict-background");
+        pw.println("    Gets the global restrict background usage status.");
+        pw.println("  set restrict-background BOOLEAN");
+        pw.println("    Sets the global restrict background usage status.");
+        pw.println("  list restrict-background-whitelist");
+        pw.println("    Prints UID that are whitelisted for restrict background usage.");
+        pw.println("  add restrict-background-whitelist UID");
+        pw.println("    Adds a UID to the whitelist for restrict background usage.");
+        pw.println("  remove restrict-background-whitelist UID");
+        pw.println("    Removes a UID from the whitelist for restrict background usage.");
+    }
+
+    private int runGet() throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
+        final String type = getNextArg();
+        if (type == null) {
+            pw.println("Error: didn't specify type of data to get");
+            return -1;
+        }
+        switch(type) {
+            case "restrict-background":
+                return getRestrictBackgroundWhitelist();
+        }
+        pw.println("Error: unknown get type '" + type + "'");
+        return -1;
+    }
+
+    private int runSet() throws RemoteException  {
+        final PrintWriter pw = getOutPrintWriter();
+        final String type = getNextArg();
+        if (type == null) {
+            pw.println("Error: didn't specify type of data to set");
+            return -1;
+        }
+        switch(type) {
+            case "restrict-background":
+                return setRestrictBackgroundWhitelist();
+        }
+        pw.println("Error: unknown set type '" + type + "'");
+        return -1;
+    }
+
+    private int runList() throws RemoteException  {
+        final PrintWriter pw = getOutPrintWriter();
+        final String type = getNextArg();
+        if (type == null) {
+            pw.println("Error: didn't specify type of data to list");
+            return -1;
+        }
+        switch(type) {
+            case "restrict-background-whitelist":
+                return runListRestrictBackgroundWhitelist();
+        }
+        pw.println("Error: unknown list type '" + type + "'");
+        return -1;
+    }
+
+    private int runAdd() throws RemoteException  {
+        final PrintWriter pw = getOutPrintWriter();
+        final String type = getNextArg();
+        if (type == null) {
+            pw.println("Error: didn't specify type of data to add");
+            return -1;
+        }
+        switch(type) {
+            case "restrict-background-whitelist":
+                return addRestrictBackgroundWhitelist();
+        }
+        pw.println("Error: unknown add type '" + type + "'");
+        return -1;
+    }
+
+    private int runRemove() throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
+        final String type = getNextArg();
+        if (type == null) {
+            pw.println("Error: didn't specify type of data to remove");
+            return -1;
+        }
+        switch(type) {
+            case "restrict-background-whitelist":
+                return removeRestrictBackgroundWhitelist();
+        }
+        pw.println("Error: unknown remove type '" + type + "'");
+        return -1;
+    }
+
+    private int runListRestrictBackgroundWhitelist() throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
+        final int[] uids = mInterface.getRestrictBackgroundWhitelistedUids();
+        pw.print("Restrict background whitelisted 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 getRestrictBackgroundWhitelist() throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
+        pw.print("Restrict background status: ");
+        pw.println(mInterface.getRestrictBackground() ? "enabled" : "disabled");
+        return 0;
+    }
+
+    private int setRestrictBackgroundWhitelist() throws RemoteException {
+        final int enabled = getNextBooleanArg();
+        if (enabled < 0) {
+            return enabled;
+        }
+        mInterface.setRestrictBackground(enabled > 0);
+        return 0;
+    }
+
+    private int addRestrictBackgroundWhitelist() throws RemoteException {
+      final int uid = getUidFromNextArg();
+      if (uid < 0) {
+          return uid;
+      }
+      mInterface.addRestrictBackgroundWhitelistedUid(uid);
+      return 0;
+    }
+
+    private int removeRestrictBackgroundWhitelist() throws RemoteException {
+        final int uid = getUidFromNextArg();
+        if (uid < 0) {
+            return uid;
+        }
+        mInterface.removeRestrictBackgroundWhitelistedUid(uid);
+        return 0;
+    }
+
+    private int getNextBooleanArg() {
+        final PrintWriter pw = getOutPrintWriter();
+        final String arg = getNextArg();
+        if (arg == null) {
+            pw.println("Error: didn't specify BOOLEAN");
+            return -1;
+        }
+        return Boolean.valueOf(arg) ? 1 : 0;
+    }
+
+    private int getUidFromNextArg() {
+        final PrintWriter pw = getOutPrintWriter();
+        final String arg = getNextArg();
+        if (arg == null) {
+            pw.println("Error: didn't specify UID");
+            return -1;
+        }
+        try {
+            return Integer.parseInt(arg);
+        } catch (NumberFormatException e) {
+            pw.println("Error: UID (" + arg + ") should be a number");
+            return -2;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java
index 53ba718..479b065 100644
--- a/services/core/java/com/android/server/net/NetworkStatsAccess.java
+++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java
@@ -66,15 +66,26 @@
          *
          * <p>Granted to:
          * <ul>
-         * <li>Apps with the PACKAGE_USAGE_STATS permission granted. Note that this is an AppOps bit
-         * so it is not necessarily sufficient to declare this in the manifest.
-         * <li>Apps with the (signature/privileged) READ_NETWORK_USAGE_HISTORY permission.
          * <li>Profile owners.
          * </ul>
          */
         int USER = 1;
 
         /**
+         * Access level for apps which can access usage summary of device. Device summary includes
+         * usage by apps running in any profiles/users, however this access level does not
+         * allow querying usage of individual apps running in other profiles/users.
+         *
+         * <p>Granted to:
+         * <ul>
+         * <li>Apps with the PACKAGE_USAGE_STATS permission granted. Note that this is an AppOps bit
+         * so it is not necessarily sufficient to declare this in the manifest.
+         * <li>Apps with the (signature/privileged) READ_NETWORK_USAGE_HISTORY permission.
+         * </ul>
+         */
+        int DEVICESUMMARY = 2;
+
+        /**
          * Access level for apps which can access usage for any app on the device, including apps
          * running on other users/profiles.
          *
@@ -85,7 +96,7 @@
          * <li>The system UID.
          * </ul>
          */
-        int DEVICE = 2;
+        int DEVICE = 3;
     }
 
     /** Returns the {@link NetworkStatsAccess.Level} for the given caller. */
@@ -107,11 +118,15 @@
             return NetworkStatsAccess.Level.DEVICE;
         }
 
+        boolean hasAppOpsPermission = hasAppOpsPermission(context, callingUid, callingPackage);
+        if (hasAppOpsPermission || context.checkCallingOrSelfPermission(
+                READ_NETWORK_USAGE_HISTORY) == PackageManager.PERMISSION_GRANTED) {
+            return NetworkStatsAccess.Level.DEVICESUMMARY;
+        }
+
         boolean isProfileOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid,
                 DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-        if (hasAppOpsPermission(context, callingUid, callingPackage) || isProfileOwner
-                || context.checkCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY) ==
-                PackageManager.PERMISSION_GRANTED) {
+        if (isProfileOwner) {
             // Apps with the AppOps permission, profile owners, and apps with the privileged
             // permission can access data usage for all apps in this user/profile.
             return NetworkStatsAccess.Level.USER;
@@ -131,6 +146,7 @@
             case NetworkStatsAccess.Level.DEVICE:
                 // Device-level access - can access usage for any uid.
                 return true;
+            case NetworkStatsAccess.Level.DEVICESUMMARY:
             case NetworkStatsAccess.Level.USER:
                 // User-level access - can access usage for any app running in the same user, along
                 // with some special uids (system, removed, or tethering).
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 102695e..eec7d93 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -17,6 +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.SET_ALL;
 import static android.net.NetworkStats.SET_DEFAULT;
 import static android.net.NetworkStats.TAG_NONE;
@@ -218,6 +220,7 @@
                 entry.uid = key.uid;
                 entry.set = key.set;
                 entry.tag = key.tag;
+                entry.roaming = key.ident.isAnyMemberRoaming() ? ROAMING_ROAMING : ROAMING_DEFAULT;
                 entry.rxBytes = historyEntry.rxBytes;
                 entry.rxPackets = historyEntry.rxPackets;
                 entry.txBytes = historyEntry.txBytes;
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index b1d6f89..3aeceef 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -484,15 +484,19 @@
             public NetworkStats getDeviceSummaryForNetwork(NetworkTemplate template, long start,
                     long end) {
                 @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
-                if (accessLevel < NetworkStatsAccess.Level.DEVICE) {
+                if (accessLevel < NetworkStatsAccess.Level.DEVICESUMMARY) {
                     throw new SecurityException("Calling package " + mCallingPackage
-                            + " cannot access device-level network stats");
+                            + " cannot access device summary network stats");
                 }
                 NetworkStats result = new NetworkStats(end - start, 1);
                 final long ident = Binder.clearCallingIdentity();
                 try {
+                    // Using access level higher than the one we checked for above.
+                    // Reason is that we are combining usage data in a way that is not PII
+                    // anymore.
                     result.combineAllValues(
-                            internalGetSummaryForNetwork(template, start, end, accessLevel));
+                            internalGetSummaryForNetwork(template, start, end,
+                                    NetworkStatsAccess.Level.DEVICE));
                 } finally {
                     Binder.restoreCallingIdentity(ident);
                 }
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 1987214..ce18818 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -121,6 +121,11 @@
     }
 
     @Override
+    protected boolean checkType(IInterface service) {
+        return service instanceof IConditionProvider;
+    }
+
+    @Override
     public void onBootPhaseAppsCanStart() {
         super.onBootPhaseAppsCanStart();
         for (int i = 0; i < mSystemConditionProviders.size(); i++) {
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index d577369..f5da52e 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -42,6 +42,7 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
@@ -53,6 +54,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Set;
 
@@ -84,7 +86,7 @@
     protected final ArrayList<ManagedServiceInfo> mServices = new ArrayList<ManagedServiceInfo>();
     // things that will be put into mServices as soon as they're ready
     private final ArrayList<String> mServicesBinding = new ArrayList<String>();
-    // lists the component names of all enabled (and therefore connected)
+    // lists the component names of all enabled (and therefore potentially connected)
     // app services for current profiles.
     private ArraySet<ComponentName> mEnabledServicesForCurrentProfiles
             = new ArraySet<ComponentName>();
@@ -93,6 +95,10 @@
     // List of packages in restored setting across all mUserProfiles, for quick
     // filtering upon package updates.
     private ArraySet<String> mRestoredPackages = new ArraySet<>();
+    // State of current service categories
+    private ArrayMap<String, Boolean> mCategoryEnabled = new ArrayMap<>();
+    // List of enabled packages that have nevertheless asked not to be run
+    private ArraySet<ComponentName> mSnoozingForCurrentProfiles = new ArraySet<>();
 
 
     // Kept to de-dupe user change events (experienced after boot, when we receive a settings and a
@@ -137,6 +143,8 @@
 
     abstract protected IInterface asInterface(IBinder binder);
 
+    abstract protected boolean checkType(IInterface service);
+
     abstract protected void onServiceAdded(ManagedServiceInfo info);
 
     protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
@@ -165,7 +173,14 @@
             if (filter != null && !filter.matches(info.component)) continue;
             pw.println("      " + info.component
                     + " (user " + info.userid + "): " + info.service
-                    + (info.isSystem?" SYSTEM":""));
+                    + (info.isSystem?" SYSTEM":"")
+                    + (info.isGuest(this)?" GUEST":""));
+        }
+
+        pw.println("    Snoozed " + getCaption() + "s (" +
+                mSnoozingForCurrentProfiles.size() + "):");
+        for (ComponentName name : mSnoozingForCurrentProfiles) {
+            pw.println("      " + name.flattenToShortString());
         }
     }
 
@@ -235,14 +250,25 @@
         rebindServices();
     }
 
-    public ManagedServiceInfo checkServiceTokenLocked(IInterface service) {
-        checkNotNull(service);
+    public ManagedServiceInfo getServiceFromTokenLocked(IInterface service) {
+        if (service == null) {
+            return null;
+        }
         final IBinder token = service.asBinder();
         final int N = mServices.size();
         for (int i = 0; i < N; i++) {
             final ManagedServiceInfo info = mServices.get(i);
             if (info.service.asBinder() == token) return info;
         }
+        return null;
+    }
+
+    public ManagedServiceInfo checkServiceTokenLocked(IInterface service) {
+        checkNotNull(service);
+        ManagedServiceInfo info = getServiceFromTokenLocked(service);
+        if (info != null) {
+            return info;
+        }
         throw new SecurityException("Disallowed call from unknown " + getCaption() + ": "
                 + service);
     }
@@ -262,9 +288,90 @@
         }
     }
 
+    /**
+     * Add a service to our callbacks. The lifecycle of this service is managed externally,
+     * but unlike a system service, it should not be considered privledged.
+     * */
+    public void registerGuestService(ManagedServiceInfo guest) {
+        checkNotNull(guest.service);
+        checkType(guest.service);
+        if (registerServiceImpl(guest) != null) {
+            onServiceAdded(guest);
+        }
+    }
+
+    public void setComponentState(ComponentName component, boolean enabled) {
+        boolean previous = !mSnoozingForCurrentProfiles.contains(component);
+        if (previous == enabled) {
+            return;
+        }
+
+        if (enabled) {
+            mSnoozingForCurrentProfiles.remove(component);
+        } else {
+            mSnoozingForCurrentProfiles.add(component);
+        }
+
+        // State changed
+        if (DEBUG) {
+            Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "component " +
+                    component.flattenToShortString());
+        }
+
+        final int[] userIds = mUserProfiles.getCurrentProfileIds();
+        for (int userId : userIds) {
+            if (enabled) {
+                registerServiceLocked(component, userId);
+            } else {
+                unregisterServiceLocked(component, userId);
+            }
+        }
+    }
+
+    public void setCategoryState(String category, boolean enabled) {
+        synchronized (mMutex) {
+            final Boolean previous = mCategoryEnabled.put(category, enabled);
+            if (!(previous == null || previous != enabled)) {
+                return;
+            }
+
+            // State changed
+            if (DEBUG) {
+                Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "category " + category);
+            }
+
+            final int[] userIds = mUserProfiles.getCurrentProfileIds();
+            for (int userId : userIds) {
+                final Set<ComponentName> componentNames = queryPackageForServices(null,
+                        userId, category);
+
+                // Disallow services not enabled in Settings
+                final ArraySet<ComponentName> userComponents =
+                        loadComponentNamesFromSetting(mConfig.secureSettingName, userId);
+                if (userComponents == null) {
+                    componentNames.clear();
+                } else {
+                    componentNames.retainAll(userComponents);
+                }
+
+                if (DEBUG) {
+                    Slog.d(TAG, "Components for category " + category + ": " + componentNames);
+                }
+                for (ComponentName c : componentNames) {
+                    if (enabled) {
+                        registerServiceLocked(c, userId);
+                    } else {
+                        unregisterServiceLocked(c, userId);
+                    }
+                }
+            }
+
+        }
+    }
 
     private void rebuildRestoredPackages() {
         mRestoredPackages.clear();
+        mSnoozingForCurrentProfiles.clear();
         String settingName = restoredSettingName(mConfig);
         int[] userIds = mUserProfiles.getCurrentProfileIds();
         final int N = userIds.length;
@@ -283,9 +390,9 @@
             int userId) {
         final ContentResolver cr = mContext.getContentResolver();
         String settingValue = Settings.Secure.getStringForUser(
-                cr,
-                settingName,
-                userId);
+            cr,
+            settingName,
+            userId);
         if (TextUtils.isEmpty(settingValue))
             return null;
         String[] restored = settingValue.split(ENABLED_SERVICES_SEPARATOR);
@@ -314,10 +421,10 @@
                 TextUtils.join(ENABLED_SERVICES_SEPARATOR, componentNames);
         final ContentResolver cr = mContext.getContentResolver();
         Settings.Secure.putStringForUser(
-                cr,
-                settingName,
-                value,
-                userId);
+            cr,
+            settingName,
+            value,
+            userId);
     }
 
     /**
@@ -333,12 +440,20 @@
     }
 
     protected Set<ComponentName> queryPackageForServices(String packageName, int userId) {
+        return queryPackageForServices(packageName, userId, null);
+    }
+
+    protected Set<ComponentName> queryPackageForServices(String packageName, int userId,
+            String category) {
         Set<ComponentName> installed = new ArraySet<>();
         final PackageManager pm = mContext.getPackageManager();
         Intent queryIntent = new Intent(mConfig.serviceInterface);
         if (!TextUtils.isEmpty(packageName)) {
             queryIntent.setPackage(packageName);
         }
+        if (category != null) {
+            queryIntent.addCategory(category);
+        }
         List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
                 queryIntent,
                 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
@@ -353,9 +468,9 @@
                 ComponentName component = new ComponentName(info.packageName, info.name);
                 if (!mConfig.bindPermission.equals(info.permission)) {
                     Slog.w(TAG, "Skipping " + getCaption() + " service "
-                            + info.packageName + "/" + info.name
-                            + ": it does not require the permission "
-                            + mConfig.bindPermission);
+                        + info.packageName + "/" + info.name
+                        + ": it does not require the permission "
+                        + mConfig.bindPermission);
                     continue;
                 }
                 installed.add(component);
@@ -432,7 +547,7 @@
         synchronized (mMutex) {
             // Unbind automatically bound services, retain system services.
             for (ManagedServiceInfo service : mServices) {
-                if (!service.isSystem) {
+                if (!service.isSystem && !service.isGuest(this)) {
                     toRemove.add(service);
                 }
             }
@@ -449,6 +564,17 @@
                 }
 
                 final ArrayList<ComponentName> add = new ArrayList<>(userComponents);
+
+                // Remove components from disabled categories so that those services aren't run.
+                for (Entry<String, Boolean> e : mCategoryEnabled.entrySet()) {
+                    if (!e.getValue()) {
+                        Set<ComponentName> c = queryPackageForServices(null, userIds[i],
+                            e.getKey());
+                        add.removeAll(c);
+                    }
+                }
+                add.removeAll(mSnoozingForCurrentProfiles);
+
                 toAdd.put(userIds[i], add);
 
                 newEnabled.addAll(userComponents);
@@ -488,93 +614,97 @@
      * Version of registerService that takes the name of a service component to bind to.
      */
     private void registerService(final ComponentName name, final int userid) {
+        synchronized (mMutex) {
+            registerServiceLocked(name, userid);
+        }
+    }
+
+    private void registerServiceLocked(final ComponentName name, final int userid) {
         if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid);
 
-        synchronized (mMutex) {
-            final String servicesBindingTag = name.toString() + "/" + userid;
-            if (mServicesBinding.contains(servicesBindingTag)) {
-                // stop registering this thing already! we're working on it
-                return;
-            }
-            mServicesBinding.add(servicesBindingTag);
+        final String servicesBindingTag = name.toString() + "/" + userid;
+        if (mServicesBinding.contains(servicesBindingTag)) {
+            // stop registering this thing already! we're working on it
+            return;
+        }
+        mServicesBinding.add(servicesBindingTag);
 
-            final int N = mServices.size();
-            for (int i = N - 1; i >= 0; i--) {
-                final ManagedServiceInfo info = mServices.get(i);
-                if (name.equals(info.component)
-                        && info.userid == userid) {
-                    // cut old connections
-                    if (DEBUG) Slog.v(TAG, "    disconnecting old " + getCaption() + ": "
-                            + info.service);
-                    removeServiceLocked(i);
-                    if (info.connection != null) {
-                        mContext.unbindService(info.connection);
-                    }
+        final int N = mServices.size();
+        for (int i = N - 1; i >= 0; i--) {
+            final ManagedServiceInfo info = mServices.get(i);
+            if (name.equals(info.component)
+                && info.userid == userid) {
+                // cut old connections
+                if (DEBUG) Slog.v(TAG, "    disconnecting old " + getCaption() + ": "
+                    + info.service);
+                removeServiceLocked(i);
+                if (info.connection != null) {
+                    mContext.unbindService(info.connection);
                 }
             }
+        }
 
-            Intent intent = new Intent(mConfig.serviceInterface);
-            intent.setComponent(name);
+        Intent intent = new Intent(mConfig.serviceInterface);
+        intent.setComponent(name);
 
-            intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel);
+        intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel);
 
-            final PendingIntent pendingIntent = PendingIntent.getActivity(
-                    mContext, 0, new Intent(mConfig.settingsAction), 0);
-            intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
+        final PendingIntent pendingIntent = PendingIntent.getActivity(
+            mContext, 0, new Intent(mConfig.settingsAction), 0);
+        intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
 
-            ApplicationInfo appInfo = null;
-            try {
-                appInfo = mContext.getPackageManager().getApplicationInfo(
-                        name.getPackageName(), 0);
-            } catch (NameNotFoundException e) {
-                // Ignore if the package doesn't exist we won't be able to bind to the service.
-            }
-            final int targetSdkVersion =
-                    appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
+        ApplicationInfo appInfo = null;
+        try {
+            appInfo = mContext.getPackageManager().getApplicationInfo(
+                name.getPackageName(), 0);
+        } catch (NameNotFoundException e) {
+            // Ignore if the package doesn't exist we won't be able to bind to the service.
+        }
+        final int targetSdkVersion =
+            appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
 
-            try {
-                if (DEBUG) Slog.v(TAG, "binding: " + intent);
-                ServiceConnection serviceConnection = new ServiceConnection() {
-                    IInterface mService;
+        try {
+            if (DEBUG) Slog.v(TAG, "binding: " + intent);
+            ServiceConnection serviceConnection = new ServiceConnection() {
+                IInterface mService;
 
-                    @Override
-                    public void onServiceConnected(ComponentName name, IBinder binder) {
-                        boolean added = false;
-                        ManagedServiceInfo info = null;
-                        synchronized (mMutex) {
-                            mServicesBinding.remove(servicesBindingTag);
-                            try {
-                                mService = asInterface(binder);
-                                info = newServiceInfo(mService, name,
-                                        userid, false /*isSystem*/, this, targetSdkVersion);
-                                binder.linkToDeath(info, 0);
-                                added = mServices.add(info);
-                            } catch (RemoteException e) {
-                                // already dead
-                            }
-                        }
-                        if (added) {
-                            onServiceAdded(info);
+                @Override
+                public void onServiceConnected(ComponentName name, IBinder binder) {
+                    boolean added = false;
+                    ManagedServiceInfo info = null;
+                    synchronized (mMutex) {
+                        mServicesBinding.remove(servicesBindingTag);
+                        try {
+                            mService = asInterface(binder);
+                            info = newServiceInfo(mService, name,
+                                userid, false /*isSystem*/, this, targetSdkVersion);
+                            binder.linkToDeath(info, 0);
+                            added = mServices.add(info);
+                        } catch (RemoteException e) {
+                            // already dead
                         }
                     }
-
-                    @Override
-                    public void onServiceDisconnected(ComponentName name) {
-                        Slog.v(TAG, getCaption() + " connection lost: " + name);
+                    if (added) {
+                        onServiceAdded(info);
                     }
-                };
-                if (!mContext.bindServiceAsUser(intent,
-                        serviceConnection,
-                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
-                        new UserHandle(userid))) {
-                    mServicesBinding.remove(servicesBindingTag);
-                    Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent);
-                    return;
                 }
-            } catch (SecurityException ex) {
-                Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex);
+
+                @Override
+                public void onServiceDisconnected(ComponentName name) {
+                    Slog.v(TAG, getCaption() + " connection lost: " + name);
+                }
+            };
+            if (!mContext.bindServiceAsUser(intent,
+                serviceConnection,
+                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+                new UserHandle(userid))) {
+                mServicesBinding.remove(servicesBindingTag);
+                Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent);
                 return;
             }
+        } catch (SecurityException ex) {
+            Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex);
+            return;
         }
     }
 
@@ -583,20 +713,24 @@
      */
     private void unregisterService(ComponentName name, int userid) {
         synchronized (mMutex) {
-            final int N = mServices.size();
-            for (int i = N - 1; i >= 0; i--) {
-                final ManagedServiceInfo info = mServices.get(i);
-                if (name.equals(info.component)
-                        && info.userid == userid) {
-                    removeServiceLocked(i);
-                    if (info.connection != null) {
-                        try {
-                            mContext.unbindService(info.connection);
-                        } catch (IllegalArgumentException ex) {
-                            // something happened to the service: we think we have a connection
-                            // but it's bogus.
-                            Slog.e(TAG, getCaption() + " " + name + " could not be unbound: " + ex);
-                        }
+            unregisterServiceLocked(name, userid);
+        }
+    }
+
+    private void unregisterServiceLocked(ComponentName name, int userid) {
+        final int N = mServices.size();
+        for (int i = N - 1; i >= 0; i--) {
+            final ManagedServiceInfo info = mServices.get(i);
+            if (name.equals(info.component)
+                && info.userid == userid) {
+                removeServiceLocked(i);
+                if (info.connection != null) {
+                    try {
+                        mContext.unbindService(info.connection);
+                    } catch (IllegalArgumentException ex) {
+                        // something happened to the service: we think we have a connection
+                        // but it's bogus.
+                        Slog.e(TAG, getCaption() + " " + name + " could not be unbound: " + ex);
                     }
                 }
             }
@@ -639,11 +773,15 @@
 
     private ManagedServiceInfo registerServiceImpl(final IInterface service,
             final ComponentName component, final int userid) {
+        ManagedServiceInfo info = newServiceInfo(service, component, userid,
+                true /*isSystem*/, null /*connection*/, Build.VERSION_CODES.LOLLIPOP);
+        return registerServiceImpl(info);
+    }
+
+    private ManagedServiceInfo registerServiceImpl(ManagedServiceInfo info) {
         synchronized (mMutex) {
             try {
-                ManagedServiceInfo info = newServiceInfo(service, component, userid,
-                        true /*isSystem*/, null, Build.VERSION_CODES.LOLLIPOP);
-                service.asBinder().linkToDeath(info, 0);
+                info.service.asBinder().linkToDeath(info, 0);
                 mServices.add(info);
                 return info;
             } catch (RemoteException e) {
@@ -658,7 +796,7 @@
      */
     private void unregisterServiceImpl(IInterface service, int userid) {
         ManagedServiceInfo info = removeServiceImpl(service, userid);
-        if (info != null && info.connection != null) {
+        if (info != null && info.connection != null && !info.isGuest(this)) {
             mContext.unbindService(info.connection);
         }
     }
@@ -710,6 +848,14 @@
             this.targetSdkVersion = targetSdkVersion;
         }
 
+        public boolean isGuest(ManagedServices host) {
+            return ManagedServices.this != host;
+        }
+
+        public ManagedServices getOwner() {
+            return ManagedServices.this;
+        }
+
         @Override
         public String toString() {
             return new StringBuilder("ManagedServiceInfo[")
@@ -753,6 +899,11 @@
         }
     }
 
+    /** convenience method for looking in mEnabledServicesForCurrentProfiles */
+    public boolean isComponentEnabledForCurrentProfiles(ComponentName component) {
+        return mEnabledServicesForCurrentProfiles.contains(component);
+    }
+
     public static class UserProfiles {
         // Profiles of the current user.
         private final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java
index 32db000..5e4703d 100644
--- a/services/core/java/com/android/server/notification/NotificationComparator.java
+++ b/services/core/java/com/android/server/notification/NotificationComparator.java
@@ -18,20 +18,13 @@
 import java.util.Comparator;
 
 /**
- * Sorts notifications individually into attention-relelvant order.
+ * Sorts notifications individually into attention-relevant order.
  */
 public class NotificationComparator
         implements Comparator<NotificationRecord> {
 
     @Override
     public int compare(NotificationRecord left, NotificationRecord right) {
-        final int leftPackagePriority = left.getPackagePriority();
-        final int rightPackagePriority = right.getPackagePriority();
-        if (leftPackagePriority != rightPackagePriority) {
-            // by priority, high to low
-            return -1 * Integer.compare(leftPackagePriority, rightPackagePriority);
-        }
-
         final int leftImportance = left.getImportance();
         final int rightImportance = right.getImportance();
         if (leftImportance != rightImportance) {
@@ -39,6 +32,13 @@
             return -1 * Integer.compare(leftImportance, rightImportance);
         }
 
+        final int leftPackagePriority = left.getPackagePriority();
+        final int rightPackagePriority = right.getPackagePriority();
+        if (leftPackagePriority != rightPackagePriority) {
+            // by priority, high to low
+            return -1 * Integer.compare(leftPackagePriority, rightPackagePriority);
+        }
+
         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 d4fadcf..b57cc75 100644
--- a/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
+++ b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
@@ -18,6 +18,7 @@
 
 import android.app.Notification;
 import android.content.Context;
+import android.service.notification.NotificationListenerService;
 import android.util.Log;
 import android.util.Slog;
 
@@ -44,11 +45,7 @@
         }
 
         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) {
+        if (record.getImportance() > NotificationListenerService.Ranking.IMPORTANCE_DEFAULT) {
             record.setRecentlyIntrusive(true);
         }
 
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index bb07e9d..b54efcc 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.notification;
 
+import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
 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;
@@ -28,17 +29,21 @@
 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_TOPIC_BANNED;
 import static android.service.notification.NotificationAssistantService.REASON_USER_STOPPED;
 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
 import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_LIGHTS;
 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_PEEK;
+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 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.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
@@ -96,6 +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.NotificationListenerService;
 import android.service.notification.NotificationRankingUpdate;
 import android.service.notification.StatusBarNotification;
@@ -124,6 +130,9 @@
 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 libcore.io.IoUtils;
 import org.json.JSONArray;
 import org.json.JSONException;
@@ -151,6 +160,7 @@
 import java.util.List;
 import java.util.Map.Entry;
 import java.util.Objects;
+import java.util.concurrent.TimeUnit;
 
 /** {@hide} */
 public class NotificationManagerService extends SystemService {
@@ -164,11 +174,13 @@
     // message codes
     static final int MESSAGE_TIMEOUT = 2;
     static final int MESSAGE_SAVE_POLICY_FILE = 3;
-    static final int MESSAGE_RECONSIDER_RANKING = 4;
-    static final int MESSAGE_RANKING_CONFIG_CHANGE = 5;
-    static final int MESSAGE_SEND_RANKING_UPDATE = 6;
-    static final int MESSAGE_LISTENER_HINTS_CHANGED = 7;
-    static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 8;
+    static final int MESSAGE_SEND_RANKING_UPDATE = 4;
+    static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
+    static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
+
+    // ranking thread messages
+    private static final int MESSAGE_RECONSIDER_RANKING = 1000;
+    private static final int MESSAGE_RANKING_SORT = 1001;
 
     static final int LONG_DELAY = 3500; // 3.5 seconds
     static final int SHORT_DELAY = 2000; // 2 seconds
@@ -206,11 +218,15 @@
     AudioManagerInternal mAudioManagerInternal;
     StatusBarManagerInternal mStatusBar;
     Vibrator mVibrator;
+    private VrManagerInternal mVrManagerInternal;
+    private final NotificationVrListener mVrListener = new NotificationVrListener();
 
     final IBinder mForegroundToken = new Binder();
     private WorkerHandler 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,11 +292,14 @@
 
     private final UserProfiles mUserProfiles = new UserProfiles();
     private NotificationListeners mListeners;
+    private NotificationAssistant mAssistant;
     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;
@@ -439,7 +458,7 @@
     /** Use this to check if a package can post a notification or toast. */
     private boolean checkNotificationOp(String pkg, int uid) {
         return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
-                == AppOpsManager.MODE_ALLOWED;
+                == AppOpsManager.MODE_ALLOWED && !isApplicationSuspended(pkg, uid);
     }
 
     private static final class ToastRecord
@@ -674,13 +693,15 @@
             boolean queryRemove = false;
             boolean packageChanged = false;
             boolean cancelNotifications = true;
+            int reason = REASON_PACKAGE_CHANGED;
 
             if (action.equals(Intent.ACTION_PACKAGE_ADDED)
                     || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
                     || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
                     || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
                     || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
-                    || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
+                    || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
+                    || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
                 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
                         UserHandle.USER_ALL);
                 String pkgList[] = null;
@@ -689,6 +710,9 @@
                 if (DBG) Slog.i(TAG, "action=" + action + " queryReplace=" + queryReplace);
                 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
+                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                    reason = REASON_PACKAGE_SUSPENDED;
                 } else if (queryRestart) {
                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
                 } else {
@@ -728,11 +752,12 @@
                     for (String pkgName : pkgList) {
                         if (cancelNotifications) {
                             cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
-                                    changeUserId, REASON_PACKAGE_CHANGED, null);
+                                    changeUserId, reason, null, null);
                         }
                     }
                 }
                 mListeners.onPackagesChanged(queryReplace, pkgList);
+                mAssistant.onPackagesChanged(queryReplace, pkgList);
                 mConditionProviders.onPackagesChanged(queryReplace, pkgList);
                 mRankingHelper.onPackagesChanged(queryReplace, pkgList);
             }
@@ -760,7 +785,7 @@
                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
                 if (userHandle >= 0) {
                     cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
-                            REASON_USER_STOPPED, null);
+                            REASON_USER_STOPPED, null, null);
                 }
             } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
                 // turn off LED when user passes through lock screen
@@ -774,6 +799,7 @@
                 // Refresh managed services
                 mConditionProviders.onUserSwitched(user);
                 mListeners.onUserSwitched(user);
+                mAssistant.onUserSwitched(user);
                 mZenModeHelper.onUserSwitched(user);
             } else if (action.equals(Intent.ACTION_USER_ADDED)) {
                 mUserProfiles.updateCache(context);
@@ -816,6 +842,14 @@
         }
     }
 
+    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;
 
@@ -854,6 +888,7 @@
 
         mHandler = new WorkerHandler();
         mRankingThread.start();
+        mAssistantThread.start();
         String[] extractorNames;
         try {
             extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
@@ -861,8 +896,10 @@
             extractorNames = new String[0];
         }
         mUsageStats = new NotificationUsageStats(getContext());
+        mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
+        mAssistantHandler = new Handler(mAssistantThread.getLooper());
         mRankingHelper = new RankingHelper(getContext(),
-                new RankingWorkerHandler(mRankingThread.getLooper()),
+                mRankingHandler,
                 mUsageStats,
                 extractorNames);
         mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
@@ -896,6 +933,7 @@
         importOldBlockDb();
 
         mListeners = new NotificationListeners();
+        mAssistant = new NotificationAssistant();
         mStatusBar = getLocalService(StatusBarManagerInternal.class);
         mStatusBar.setNotificationDelegate(mNotificationDelegate);
 
@@ -958,6 +996,11 @@
         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
                 null);
 
+        IntentFilter suspendedPkgFilter = new IntentFilter();
+        suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
+        getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
+                suspendedPkgFilter, null, null);
+
         IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
                 null);
@@ -1004,12 +1047,15 @@
             // Grab our optional AudioService
             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();
             mConditionProviders.onBootPhaseAppsCanStart();
         }
     }
@@ -1023,7 +1069,7 @@
         // Now, cancel any outstanding notifications that are part of a just-disabled app
         if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid),
-                    REASON_PACKAGE_BANNED, null);
+                    REASON_PACKAGE_BANNED, null, null);
         }
     }
 
@@ -1070,10 +1116,16 @@
             }
 
             final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
+            final boolean isApplicationSuspended =
+                    isApplicationSuspended(pkg, Binder.getCallingUid());
 
-            if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) {
+            if (ENABLE_BLOCKED_TOASTS && (!noteNotificationOp(pkg, Binder.getCallingUid())
+                    || isApplicationSuspended)) {
                 if (!isSystemToast) {
-                    Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request.");
+                    Slog.e(TAG, "Suppressing toast from package " + pkg
+                            + (isApplicationSuspended
+                                    ? " due to package suspended by administrator."
+                                    : " by user request."));
                     return;
                 }
             }
@@ -1181,7 +1233,7 @@
             // running foreground services.
             cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
                     pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
-                    REASON_APP_CANCEL_ALL, null);
+                    REASON_APP_CANCEL_ALL, null, null);
         }
 
         @Override
@@ -1198,7 +1250,7 @@
         public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
             checkCallerIsSystem();
             return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
-                    == AppOpsManager.MODE_ALLOWED);
+                    == AppOpsManager.MODE_ALLOWED) && !isApplicationSuspended(pkg, uid);
         }
 
         @Override
@@ -1208,44 +1260,61 @@
         }
 
         @Override
-        public void setTopicPriority(String pkg, int uid, Notification.Topic topic, int priority) {
+        public void setPriority(String pkg, int uid, Notification.Topic topic, int priority) {
             checkCallerIsSystem();
-            mRankingHelper.setTopicPriority(pkg, uid, topic, priority);
+            mRankingHelper.setPriority(pkg, uid, topic, priority);
             savePolicyFile();
         }
 
         @Override
-        public int getTopicPriority(String pkg, int uid, Notification.Topic topic) {
+        public int getPriority(String pkg, int uid, Notification.Topic topic) {
             checkCallerIsSystem();
-            return mRankingHelper.getTopicPriority(pkg, uid, topic);
+            return mRankingHelper.getPriority(pkg, uid, topic);
         }
 
         @Override
-        public void setTopicVisibilityOverride(String pkg, int uid, Notification.Topic topic,
+        public void setVisibilityOverride(String pkg, int uid, Notification.Topic topic,
                 int visibility) {
             checkCallerIsSystem();
-            mRankingHelper.setTopicVisibilityOverride(pkg, uid, topic, visibility);
+            mRankingHelper.setVisibilityOverride(pkg, uid, topic, visibility);
             savePolicyFile();
         }
 
         @Override
-        public int getTopicVisibilityOverride(String pkg, int uid, Notification.Topic topic) {
+        public int getVisibilityOverride(String pkg, int uid, Notification.Topic topic) {
             checkCallerIsSystem();
-            return mRankingHelper.getTopicVisibilityOverride(pkg, uid, topic);
+            return mRankingHelper.getVisibilityOverride(pkg, uid, topic);
         }
 
         @Override
-        public void setTopicImportance(String pkg, int uid, Notification.Topic topic,
+        public void setImportance(String pkg, int uid, Notification.Topic topic,
                 int importance) {
             enforceSystemOrSystemUI("Caller not system or systemui");
-            mRankingHelper.setTopicImportance(pkg, uid, topic, importance);
+            if (topic == null) {
+                // App wide, potentially store block in app ops.
+                setNotificationsEnabledForPackageImpl(pkg, uid,
+                        importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);
+            } else {
+                if (NotificationListenerService.Ranking.IMPORTANCE_NONE == importance) {
+                    cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true,
+                            UserHandle.getUserId(uid),
+                            REASON_TOPIC_BANNED, topic, null);
+                }
+            }
+            mRankingHelper.setImportance(pkg, uid, topic, importance);
             savePolicyFile();
         }
 
         @Override
-        public int getTopicImportance(String pkg, int uid, Notification.Topic topic) {
+        public int getImportance(String pkg, int uid, Notification.Topic topic) {
             checkCallerIsSystem();
-            return mRankingHelper.getTopicImportance(pkg, uid, topic);
+            return mRankingHelper.getImportance(pkg, uid, topic);
+        }
+
+        @Override
+        public boolean doesAppUseTopics(String pkg, int uid) {
+            enforceSystemOrSystemUI("Caller not system or systemui");
+            return mRankingHelper.doesAppUseTopics(pkg, uid);
         }
 
         /**
@@ -1403,6 +1472,37 @@
             }
         }
 
+        /**
+         * Handle request from an approved listener to re-enable itself.
+         *
+         * @param component The componenet to be re-enabled, caller must match package.
+         */
+        @Override
+        public void requestBindListener(ComponentName component) {
+            checkCallerIsSystemOrSameApp(component.getPackageName());
+            long identity = Binder.clearCallingIdentity();
+            try {
+                ManagedServices manager = mAssistant.isComponentEnabledForCurrentProfiles(component)
+                        ? mAssistant
+                        : mListeners;
+                manager.setComponentState(component, true);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void requestUnbindListener(INotificationListener token) {
+            long identity = Binder.clearCallingIdentity();
+            try {
+                // allow bound services to disable themselves
+                final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
+                info.getOwner().setComponentState(info.component, false);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
         @Override
         public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
             long identity = Binder.clearCallingIdentity();
@@ -1647,6 +1747,14 @@
         }
 
         @Override
+        public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
+            Preconditions.checkNotNull(owner, "Owner is null");
+            enforceSystemOrSystemUI("getRuleInstanceCount");
+
+            return mZenModeHelper.getCurrentInstanceCount(owner);
+        }
+
+        @Override
         public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
             enforcePolicyAccess(pkg, "setInterruptionFilter");
             final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
@@ -1866,6 +1974,22 @@
                 Binder.restoreCallingIdentity(identity);
             }
         }
+
+        @Override
+        public void setImportanceFromAssistant(INotificationListener token, String key,
+                int importance, CharSequence explanation) throws RemoteException {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mNotificationList) {
+                    mAssistant.checkServiceTokenLocked(token);
+                    NotificationRecord n = mNotificationsByKey.get(key);
+                    n.setImportance(importance, explanation);
+                    mRankingHandler.requestSort();
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
     };
 
     private String disableNotificationEffects(NotificationRecord record) {
@@ -2007,6 +2131,8 @@
                     pw.print(listener.component);
                 }
                 pw.println(')');
+                pw.println("\n  Notification assistant:");
+                mAssistant.dump(pw, filter);
             }
             pw.println("\n  Policy access:");
             pw.print("    mPolicyAccess: "); pw.println(mPolicyAccess);
@@ -2045,12 +2171,12 @@
         for (UserInfo user : UserManager.get(getContext()).getUsers()) {
             final int userId = user.getUserHandle().getIdentifier();
             final PackageManager packageManager = getContext().getPackageManager();
-            List<PackageInfo> packages = packageManager.getInstalledPackages(0, userId);
+            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.getPackageUid(packageName, userId);
+                    final int uid = packageManager.getPackageUidAsUser(packageName, userId);
                     if (!checkNotificationOp(packageName, uid)) {
                         packageNames.add(packageName);
                     }
@@ -2143,114 +2269,151 @@
                     + " id=" + id + " notification=" + notification);
         }
 
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
+        // Sanitize inputs
+        notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
+                Notification.PRIORITY_MAX);
 
-                synchronized (mNotificationList) {
-
-                    // Sanitize inputs
-                    notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
-                            Notification.PRIORITY_MAX);
-
-                    // setup local book-keeping
-                    final StatusBarNotification n = new StatusBarNotification(
-                            pkg, opPkg, id, tag, callingUid, callingPid, 0, notification,
-                            user);
-                    NotificationRecord r = new NotificationRecord(getContext(), n);
-                    NotificationRecord old = mNotificationsByKey.get(n.getKey());
-                    if (old != null) {
-                        // Retain ranking information from previous record
-                        r.copyRankingInformation(old);
-                    }
-
-                    // Handle grouped notifications and bail out early if we
-                    // can to avoid extracting signals.
-                    handleGroupedNotificationLocked(r, old, callingUid, callingPid);
-                    boolean ignoreNotification =
-                            removeUnusedGroupedNotificationLocked(r, old, callingUid, callingPid);
-
-                    // This conditional is a dirty hack to limit the logging done on
-                    //     behalf of the download manager without affecting other apps.
-                    if (!pkg.equals("com.android.providers.downloads")
-                            || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
-                        int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
-                        if (ignoreNotification) {
-                            enqueueStatus = EVENTLOG_ENQUEUE_STATUS_IGNORED;
-                        } else if (old != null) {
-                            enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
-                        }
-                        EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
-                                pkg, id, tag, userId, notification.toString(),
-                                enqueueStatus);
-                    }
-
-                    if (ignoreNotification) {
-                        return;
-                    }
-
-                    mRankingHelper.extractSignals(r);
-                    savePolicyFile();
-
-                    // blocked apps
-                    if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) {
-                        if (!isSystemNotification) {
-                            Slog.e(TAG, "Suppressing notification from package " + pkg
-                                    + " by user request.");
-                            mUsageStats.registerBlocked(r);
-                            return;
-                        }
-                    }
-
-                    int index = indexOfNotificationLocked(n.getKey());
-                    if (index < 0) {
-                        mNotificationList.add(r);
-                        mUsageStats.registerPostedByApp(r);
-                    } else {
-                        old = mNotificationList.get(index);
-                        mNotificationList.set(index, r);
-                        mUsageStats.registerUpdatedByApp(r, old);
-                        // Make sure we don't lose the foreground service state.
-                        notification.flags |=
-                                old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
-                        r.isUpdate = true;
-                    }
-
-                    mNotificationsByKey.put(n.getKey(), r);
-
-                    // Ensure if this is a foreground service that the proper additional
-                    // flags are set.
-                    if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
-                        notification.flags |= Notification.FLAG_ONGOING_EVENT
-                                | Notification.FLAG_NO_CLEAR;
-                    }
-
-                    applyZenModeLocked(r);
-                    mRankingHelper.sort(mNotificationList);
-
-                    if (notification.getSmallIcon() != null) {
-                        StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
-                        mListeners.notifyPostedLocked(n, oldSbn);
-                    } else {
-                        Slog.e(TAG, "Not posting notification without small icon: " + notification);
-                        if (old != null && !old.isCanceled) {
-                            mListeners.notifyRemovedLocked(n);
-                        }
-                        // ATTENTION: in a future release we will bail out here
-                        // so that we do not play sounds, show lights, etc. for invalid
-                        // notifications
-                        Slog.e(TAG, "WARNING: In a future release this will crash the app: "
-                                + n.getPackageName());
-                    }
-
-                    buzzBeepBlinkLocked(r);
-                }
-            }
-        });
+        // setup local book-keeping
+        final StatusBarNotification n = new StatusBarNotification(
+                pkg, opPkg, id, tag, callingUid, callingPid, 0, notification,
+                user);
+        final NotificationRecord r = new NotificationRecord(getContext(), n);
+        mHandler.post(new EnqueueNotificationRunnable(userId, r));
 
         idOut[0] = id;
     }
 
+    private class EnqueueNotificationRunnable implements Runnable {
+        private final NotificationRecord r;
+        private final int userId;
+
+        EnqueueNotificationRunnable(int userId, NotificationRecord r) {
+            this.userId = userId;
+            this.r = r;
+        };
+
+        @Override
+        public void run() {
+
+            synchronized (mNotificationList) {
+                final StatusBarNotification n = r.sbn;
+                Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
+                NotificationRecord old = mNotificationsByKey.get(n.getKey());
+                if (old != null) {
+                    // Retain ranking information from previous record
+                    r.copyRankingInformation(old);
+                }
+
+                final int callingUid = n.getUid();
+                final int callingPid = n.getInitialPid();
+                final Notification notification = n.getNotification();
+                final String pkg = n.getPackageName();
+                final int id = n.getId();
+                final String tag = n.getTag();
+                final boolean isSystemNotification = isUidSystem(callingUid) ||
+                        ("android".equals(pkg));
+
+                // Handle grouped notifications and bail out early if we
+                // can to avoid extracting signals.
+                handleGroupedNotificationLocked(r, old, callingUid, callingPid);
+                boolean ignoreNotification =
+                        removeUnusedGroupedNotificationLocked(r, old, callingUid, callingPid);
+                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.
+                if (!pkg.equals("com.android.providers.downloads")
+                        || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
+                    int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
+                    if (ignoreNotification) {
+                        enqueueStatus = EVENTLOG_ENQUEUE_STATUS_IGNORED;
+                    } else if (old != null) {
+                        enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
+                    }
+                    EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
+                            pkg, id, tag, userId, notification.toString(),
+                            enqueueStatus);
+                }
+
+                if (ignoreNotification) {
+                    return;
+                }
+
+                mRankingHelper.extractSignals(r);
+
+                // why is this here?
+                savePolicyFile();
+                final boolean isApplicationSuspended = isApplicationSuspended(pkg, callingUid);
+
+                // blocked apps/topics
+                if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE
+                        || !noteNotificationOp(pkg, callingUid) || isApplicationSuspended) {
+                    if (!isSystemNotification) {
+                        if (isApplicationSuspended) {
+                            Slog.e(TAG, "Suppressing notification from package due to package "
+                                    + "suspended by administrator.");
+                            mUsageStats.registerSuspendedByAdmin(r);
+                        } else {
+                            Slog.e(TAG, "Suppressing notification from package by user request.");
+                            mUsageStats.registerBlocked(r);
+                        }
+                        return;
+                    }
+                }
+
+                // tell the assistant about the notification
+                if (mAssistant.isEnabled()) {
+                    mAssistant.onNotificationEnqueued(r);
+                    // TODO delay the code below here for 100ms or until there is an answer
+                }
+
+
+                int index = indexOfNotificationLocked(n.getKey());
+                if (index < 0) {
+                    mNotificationList.add(r);
+                    mUsageStats.registerPostedByApp(r);
+                } else {
+                    old = mNotificationList.get(index);
+                    mNotificationList.set(index, r);
+                    mUsageStats.registerUpdatedByApp(r, old);
+                    // Make sure we don't lose the foreground service state.
+                    notification.flags |=
+                            old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
+                    r.isUpdate = true;
+                }
+
+                mNotificationsByKey.put(n.getKey(), r);
+
+                // Ensure if this is a foreground service that the proper additional
+                // flags are set.
+                if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
+                    notification.flags |= Notification.FLAG_ONGOING_EVENT
+                            | Notification.FLAG_NO_CLEAR;
+                }
+
+                applyZenModeLocked(r);
+                mRankingHelper.sort(mNotificationList);
+
+                if (notification.getSmallIcon() != null) {
+                    StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
+                    mListeners.notifyPostedLocked(n, oldSbn);
+                } else {
+                    Slog.e(TAG, "Not posting notification without small icon: " + notification);
+                    if (old != null && !old.isCanceled) {
+                        mListeners.notifyRemovedLocked(n);
+                    }
+                    // ATTENTION: in a future release we will bail out here
+                    // so that we do not play sounds, show lights, etc. for invalid
+                    // notifications
+                    Slog.e(TAG, "WARNING: In a future release this will crash the app: "
+                            + n.getPackageName());
+                }
+
+                buzzBeepBlinkLocked(r);
+            }
+        }
+    }
+
     /**
      * Ensures that grouped notification receive their special treatment.
      *
@@ -2503,9 +2666,14 @@
             updateLightsLocked();
         }
         if (buzz || beep || blink) {
-            EventLogTags.writeNotificationAlert(record.getKey(),
-                    buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
-            mHandler.post(mBuzzBeepBlinked);
+            if (((record.getSuppressedVisualEffects()
+                    & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON) != 0)) {
+                if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
+            } else {
+                EventLogTags.writeNotificationAlert(record.getKey(),
+                        buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
+                mHandler.post(mBuzzBeepBlinked);
+            }
         }
     }
 
@@ -2656,7 +2824,7 @@
         }
     }
 
-    private void handleRankingConfigChange() {
+    private void handleRankingSort() {
         synchronized (mNotificationList) {
             final int N = mNotificationList.size();
             ArrayList<String> orderBefore = new ArrayList<String>(N);
@@ -2667,8 +2835,8 @@
                 visibilities[i] = r.getPackageVisibilityOverride();
                 mRankingHelper.extractSignals(r);
             }
+            mRankingHelper.sort(mNotificationList);
             for (int i = 0; i < N; i++) {
-                mRankingHelper.sort(mNotificationList);
                 final NotificationRecord r = mNotificationList.get(i);
                 if (!orderBefore.get(i).equals(r.getKey())
                         || visibilities[i] != r.getPackageVisibilityOverride()) {
@@ -2684,7 +2852,8 @@
         record.setIntercepted(mZenModeHelper.shouldIntercept(record));
         if (record.isIntercepted()) {
             int suppressed = (mZenModeHelper.shouldSuppressLight() ? SUPPRESSED_EFFECT_LIGHTS : 0)
-                    | (mZenModeHelper.shouldSuppressPeek() ? SUPPRESSED_EFFECT_PEEK : 0);
+                    | (mZenModeHelper.shouldSuppressPeek() ? SUPPRESSED_EFFECT_PEEK : 0)
+                    | (mZenModeHelper.shouldSuppressScreenOn() ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
             record.setSuppressedVisualEffects(suppressed);
         }
     }
@@ -2758,9 +2927,9 @@
 
     }
 
-    private final class RankingWorkerHandler extends Handler
+    private final class RankingHandlerWorker extends Handler implements RankingHandler
     {
-        public RankingWorkerHandler(Looper looper) {
+        public RankingHandlerWorker(Looper looper) {
             super(looper);
         }
 
@@ -2770,11 +2939,23 @@
                 case MESSAGE_RECONSIDER_RANKING:
                     handleRankingReconsideration(msg);
                     break;
-                case MESSAGE_RANKING_CONFIG_CHANGE:
-                    handleRankingConfigChange();
+                case MESSAGE_RANKING_SORT:
+                    handleRankingSort();
                     break;
             }
         }
+
+        public void requestSort() {
+            removeMessages(MESSAGE_RANKING_SORT);
+            sendEmptyMessage(MESSAGE_RANKING_SORT);
+        }
+
+        public void requestReconsideration(RankingReconsideration recon) {
+            Message m = Message.obtain(this,
+                    NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
+            long delay = recon.getDelay(TimeUnit.MILLISECONDS);
+            sendMessageDelayed(m, delay);
+        }
     }
 
     // Notifications
@@ -2957,11 +3138,11 @@
     }
 
     /**
-     * Cancels all notifications from a given package that have all of the
+     * Cancels all notifications from a given package or topic that have all of the
      * {@code mustHaveFlags}.
      */
     boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags,
-            int mustNotHaveFlags, boolean doit, int userId, int reason,
+            int mustNotHaveFlags, boolean doit, int userId, int reason, Notification.Topic topic,
             ManagedServiceInfo listener) {
         String listenerName = listener == null ? null : listener.component.toShortString();
         EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
@@ -2989,6 +3170,10 @@
                 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
                     continue;
                 }
+                if (topic != null
+                        && !topic.getId().equals(r.getNotification().getTopic().getId())) {
+                    continue;
+                }
                 if (canceledNotifications == null) {
                     canceledNotifications = new ArrayList<>();
                 }
@@ -3215,7 +3400,6 @@
      * <p>Caller must hold a lock on mNotificationList.</p>
      */
     private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
-        int speedBumpIndex = -1;
         final int N = mNotificationList.size();
         ArrayList<String> keys = new ArrayList<String>(N);
         ArrayList<String> interceptedKeys = new ArrayList<String>(N);
@@ -3243,18 +3427,6 @@
                     != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
                 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
             }
-            // Find first min-prio notification for speedbump placement.
-            if (speedBumpIndex == -1 &&
-                    // Intrusiveness trumps priority, hence ignore intrusives.
-                    !record.isRecentlyIntrusive() &&
-                    // Currently, package priority is either PRIORITY_DEFAULT or PRIORITY_MAX, so
-                    // scanning for PRIORITY_MIN within the package bucket PRIORITY_DEFAULT
-                    // (or lower as a safeguard) is sufficient to find the speedbump index.
-                    // We'll have to revisit this when more package priority buckets are introduced.
-                    record.getPackagePriority() <= Notification.PRIORITY_DEFAULT &&
-                    record.sbn.getNotification().priority == Notification.PRIORITY_MIN) {
-                speedBumpIndex = keys.size() - 1;
-            }
         }
         final int M = keys.size();
         String[] keysAr = keys.toArray(new String[M]);
@@ -3264,7 +3436,7 @@
             importanceAr[i] = importance.get(i);
         }
         return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
-                speedBumpIndex, suppressedVisualEffects, importanceAr, explanation);
+                suppressedVisualEffects, importanceAr, explanation);
     }
 
     private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
@@ -3275,6 +3447,127 @@
         return true;
     }
 
+    private boolean isApplicationSuspended(String pkg, int uid) {
+        int userId = UserHandle.getUserId(uid);
+        ApplicationInfo ai;
+        try {
+            // TODO: it might be faster to return a boolean from package manager rather than the
+            // whole application info. Revisit and make the API change.
+            ai = AppGlobals.getPackageManager().getApplicationInfo(pkg, 0, userId);
+            if (ai == null) {
+                Slog.w(TAG, "No application info for package " + pkg + " and user " + userId);
+                return false;
+            }
+        } catch (RemoteException re) {
+            throw new SecurityException("Could not talk to package manager service");
+        }
+
+        return ((ai.flags & FLAG_SUSPENDED) != 0);
+    }
+
+    private class TrimCache {
+        StatusBarNotification heavy;
+        StatusBarNotification sbnClone;
+        StatusBarNotification sbnCloneLight;
+
+        TrimCache(StatusBarNotification sbn) {
+            heavy = sbn;
+        }
+
+        StatusBarNotification ForListener(ManagedServiceInfo info) {
+            if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
+                if (sbnCloneLight == null) {
+                    sbnCloneLight = heavy.cloneLight();
+                }
+                return sbnCloneLight;
+            } else {
+                if (sbnClone == null) {
+                    sbnClone = heavy.clone();
+                }
+                return sbnClone;
+            }
+        }
+    }
+
+    public class NotificationAssistant extends ManagedServices {
+
+        public NotificationAssistant() {
+            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.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
+            c.clientLabel = R.string.notification_assistant_binding_label;
+            return c;
+        }
+
+        @Override
+        protected IInterface asInterface(IBinder binder) {
+            return INotificationListener.Stub.asInterface(binder);
+        }
+
+        @Override
+        protected boolean checkType(IInterface service) {
+            return service instanceof INotificationListener;
+        }
+
+        @Override
+        protected void onServiceAdded(ManagedServiceInfo info) {
+            mListeners.registerGuestService(info);
+        }
+
+        @Override
+        protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
+            mListeners.unregisterService(removed.service, removed.userid);
+        }
+
+        public void onNotificationEnqueued(final NotificationRecord r) {
+            final StatusBarNotification sbn = r.sbn;
+            TrimCache trimCache = new TrimCache(sbn);
+
+            // mServices is the list inside ManagedServices of all the assistants,
+            // 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) {
+                boolean sbnVisible = isVisibleToListener(sbn, info);
+                if (!sbnVisible) {
+                    continue;
+                }
+
+                final int importance = r.getImportance();
+                final boolean fromUser = r.isImportanceFromUser();
+                final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
+                mAssistantHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        notifyEnqueued(info, sbnToPost, importance, fromUser);
+                    }
+                });
+            }
+        }
+
+        private void notifyEnqueued(final ManagedServiceInfo info,
+                final StatusBarNotification sbn, int importance, boolean fromUser) {
+            final INotificationListener assistant = (INotificationListener) info.service;
+            StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
+            try {
+                assistant.onNotificationEnqueued(sbnHolder, importance, fromUser);
+            } catch (RemoteException ex) {
+                Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
+            }
+        }
+
+        public boolean isEnabled() {
+            return !mServices.isEmpty();
+        }
+    }
+
     public class NotificationListeners extends ManagedServices {
 
         private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
@@ -3302,6 +3595,11 @@
         }
 
         @Override
+        protected boolean checkType(IInterface service) {
+            return service instanceof INotificationListener;
+        }
+
+        @Override
         public void onServiceAdded(ManagedServiceInfo info) {
             final INotificationListener listener = (INotificationListener) info.service;
             final NotificationRankingUpdate update;
@@ -3336,7 +3634,6 @@
 
         public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
             return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
-
         }
 
         /**
@@ -3348,8 +3645,7 @@
          */
         public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
             // Lazily initialized snapshots of the notification.
-            StatusBarNotification sbnClone = null;
-            StatusBarNotification sbnCloneLight = null;
+            TrimCache trimCache = new TrimCache(sbn);
 
             for (final ManagedServiceInfo info : mServices) {
                 boolean sbnVisible = isVisibleToListener(sbn, info);
@@ -3372,16 +3668,7 @@
                     continue;
                 }
 
-                final int trim = mListeners.getOnNotificationPostedTrim(info);
-
-                if (trim == TRIM_LIGHT && sbnCloneLight == null) {
-                    sbnCloneLight = sbn.cloneLight();
-                } else if (trim == TRIM_FULL && sbnClone == null) {
-                    sbnClone = sbn.clone();
-                }
-                final StatusBarNotification sbnToPost =
-                        (trim == TRIM_FULL) ? sbnClone : sbnCloneLight;
-
+                final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
                 mHandler.post(new Runnable() {
                     @Override
                     public void run() {
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index a9f20a6..484b0e9 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_UNSPECIFIED;
 import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_DEFAULT;
 import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
 import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_LOW;
@@ -32,6 +33,7 @@
 import android.service.notification.StatusBarNotification;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
 import com.android.server.EventLogTags;
 
 import java.io.PrintWriter;
@@ -88,8 +90,8 @@
     private int mAuthoritativeRank;
     private String mGlobalSortKey;
     private int mPackageVisibility;
-    private int mTopicImportance = NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
-    private int mImportance = NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
+    private int mTopicImportance = IMPORTANCE_UNSPECIFIED;
+    private int mImportance = IMPORTANCE_UNSPECIFIED;
     private CharSequence mImportanceExplanation = null;
 
     private int mSuppressedVisualEffects = 0;
@@ -105,6 +107,7 @@
         mCreationTimeMs = sbn.getPostTime();
         mUpdateTimeMs = mCreationTimeMs;
         mContext = context;
+        stats = new NotificationUsageStats.SingleNotificationStats();
         mImportance = defaultImportance();
     }
 
@@ -132,27 +135,22 @@
                 importance = IMPORTANCE_MAX;
                 break;
         }
+        stats.requestedImportance = importance;
 
         boolean isNoisy = (n.defaults & Notification.DEFAULT_SOUND) != 0
                 || (n.defaults & Notification.DEFAULT_VIBRATE) != 0
                 || n.sound != null
                 || n.vibrate != null;
+        stats.isNoisy = isNoisy;
         if (!isNoisy && importance > IMPORTANCE_DEFAULT) {
             importance = IMPORTANCE_DEFAULT;
         }
-        // maybe only do this for target API < N?
-        if (isNoisy) {
-            if (importance == IMPORTANCE_HIGH) {
-                importance = IMPORTANCE_MAX;
-            } else {
-                importance = IMPORTANCE_HIGH;
-            }
-        }
 
         if (n.fullScreenIntent != null) {
             importance = IMPORTANCE_MAX;
         }
 
+        stats.naturalImportance = importance;
         return importance;
     }
 
@@ -510,4 +508,8 @@
     public String getGroupKey() {
         return sbn.getGroupKey();
     }
+
+    public boolean isImportanceFromUser() {
+        return mImportance == mTopicImportance;
+    }
 }
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index 1cdc6db..0272850 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -16,6 +16,8 @@
 
 package com.android.server.notification;
 
+import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
+
 import android.app.Notification;
 import android.content.ContentValues;
 import android.content.Context;
@@ -101,7 +103,6 @@
      * Called when a notification has been posted.
      */
     public synchronized void registerPostedByApp(NotificationRecord notification) {
-        notification.stats = new SingleNotificationStats();
         notification.stats.posttimeElapsedMs = SystemClock.elapsedRealtime();
 
         AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
@@ -119,13 +120,16 @@
      * Called when a notification has been updated.
      */
     public void registerUpdatedByApp(NotificationRecord notification, NotificationRecord old) {
-        notification.stats = old.stats;
+        notification.stats.updateFrom(old.stats);
         AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
         for (AggregatedStats stats : aggregatedStatsArray) {
             stats.numUpdatedByApp++;
             stats.countApiUse(notification);
         }
         releaseAggregatedStatsLocked(aggregatedStatsArray);
+        if (ENABLE_SQLITE_LOG) {
+            mSQLiteLog.logPosted(notification);
+        }
     }
 
     /**
@@ -194,6 +198,14 @@
         releaseAggregatedStatsLocked(aggregatedStatsArray);
     }
 
+    public synchronized void registerSuspendedByAdmin(NotificationRecord notification) {
+        AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
+        for (AggregatedStats stats : aggregatedStatsArray) {
+            stats.numSuspendedByAdmin++;
+        }
+        releaseAggregatedStatsLocked(aggregatedStatsArray);
+    }
+
     // Locked by this.
     private AggregatedStats[] getAggregatedStatsLocked(NotificationRecord record) {
         if (!ENABLE_AGGREGATED_IN_MEMORY_STATS) {
@@ -294,13 +306,10 @@
         public int numWithStaredPeople;
         public int numWithValidPeople;
         public int numBlocked;
+        public int numSuspendedByAdmin;
         public int numWithActions;
         public int numPrivate;
         public int numSecret;
-        public int numPriorityMax;
-        public int numPriorityHigh;
-        public int numPriorityLow;
-        public int numPriorityMin;
         public int numWithBigText;
         public int numWithBigPicture;
         public int numForegroundService;
@@ -314,11 +323,17 @@
         public int numWithSubText;
         public int numWithInfoText;
         public int numInterrupt;
+        public ImportanceHistogram noisyImportance;
+        public ImportanceHistogram quietImportance;
+        public ImportanceHistogram finalImportance;
 
         public AggregatedStats(Context context, String key) {
             this.key = key;
             mContext = context;
             mCreated = SystemClock.elapsedRealtime();
+            noisyImportance = new ImportanceHistogram(context, "note_imp_noisy_");
+            quietImportance = new ImportanceHistogram(context, "note_imp_quiet_");
+            finalImportance = new ImportanceHistogram(context, "note_importance_");
         }
 
         public void countApiUse(NotificationRecord record) {
@@ -354,20 +369,12 @@
                     break;
             }
 
-            switch (n.priority) {
-                case Notification.PRIORITY_MAX:
-                    numPriorityMax++;
-                    break;
-                case Notification.PRIORITY_HIGH:
-                    numPriorityHigh++;
-                    break;
-                case Notification.PRIORITY_LOW:
-                    numPriorityLow++;
-                    break;
-                case Notification.PRIORITY_MIN:
-                    numPriorityMin++;
-                    break;
+            if (record.stats.isNoisy) {
+                noisyImportance.increment(record.stats.requestedImportance);
+            } else {
+                quietImportance.increment(record.stats.requestedImportance);
             }
+            finalImportance.increment(record.getImportance());
 
             final Set<String> names = n.extras.keySet();
             if (names.contains(Notification.EXTRA_BIG_TEXT)) {
@@ -416,13 +423,10 @@
             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_prio_max", (numPriorityMax - mPrevious.numPriorityMax));
-            maybeCount("note_prio_high", (numPriorityHigh - mPrevious.numPriorityHigh));
-            maybeCount("note_prio_low", (numPriorityLow - mPrevious.numPriorityLow));
-            maybeCount("note_prio_min", (numPriorityMin - mPrevious.numPriorityMin));
             maybeCount("note_interupt", (numInterrupt - mPrevious.numInterrupt));
             maybeCount("note_big_text", (numWithBigText - mPrevious.numWithBigText));
             maybeCount("note_big_pic", (numWithBigPicture - mPrevious.numWithBigPicture));
@@ -436,6 +440,9 @@
             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;
@@ -445,13 +452,10 @@
             mPrevious.numWithStaredPeople = numWithStaredPeople;
             mPrevious.numWithValidPeople = numWithValidPeople;
             mPrevious.numBlocked = numBlocked;
+            mPrevious.numSuspendedByAdmin = numSuspendedByAdmin;
             mPrevious.numWithActions = numWithActions;
             mPrevious.numPrivate = numPrivate;
             mPrevious.numSecret = numSecret;
-            mPrevious.numPriorityMax = numPriorityMax;
-            mPrevious.numPriorityHigh = numPriorityHigh;
-            mPrevious.numPriorityLow = numPriorityLow;
-            mPrevious.numPriorityMin = numPriorityMin;
             mPrevious.numInterrupt = numInterrupt;
             mPrevious.numWithBigText = numWithBigText;
             mPrevious.numWithBigPicture = numWithBigPicture;
@@ -465,6 +469,9 @@
             mPrevious.numWithText = numWithText;
             mPrevious.numWithSubText = numWithSubText;
             mPrevious.numWithInfoText = numWithInfoText;
+            noisyImportance.update(mPrevious.noisyImportance);
+            quietImportance.update(mPrevious.quietImportance);
+            finalImportance.update(mPrevious.finalImportance);
         }
 
         void maybeCount(String name, int value) {
@@ -483,17 +490,66 @@
         }
 
         private String toStringWithIndent(String indent) {
-            return indent + "AggregatedStats{\n" +
-                    indent + "  key='" + key + "',\n" +
-                    indent + "  numPostedByApp=" + numPostedByApp + ",\n" +
-                    indent + "  numUpdatedByApp=" + numUpdatedByApp + ",\n" +
-                    indent + "  numRemovedByApp=" + numRemovedByApp + ",\n" +
-                    indent + "  numPeopleCacheHit=" + numPeopleCacheHit + ",\n" +
-                    indent + "  numWithStaredPeople=" + numWithStaredPeople + ",\n" +
-                    indent + "  numWithValidPeople=" + numWithValidPeople + ",\n" +
-                    indent + "  numPeopleCacheMiss=" + numPeopleCacheMiss + ",\n" +
-                    indent + "  numBlocked=" + numBlocked + ",\n" +
-                    indent + "}";
+            StringBuilder output = new StringBuilder();
+            output.append(indent).append("AggregatedStats{\n");
+            String indentPlusTwo = indent + "  ";
+            output.append(indentPlusTwo);
+            output.append("key='").append(key).append("',\n");
+            output.append(indentPlusTwo);
+            output.append("numPostedByApp=").append(numPostedByApp).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numUpdatedByApp=").append(numUpdatedByApp).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numRemovedByApp=").append(numRemovedByApp).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numPeopleCacheHit=").append(numPeopleCacheHit).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numWithStaredPeople=").append(numWithStaredPeople).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numWithValidPeople=").append(numWithValidPeople).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numPeopleCacheMiss=").append(numPeopleCacheMiss).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numBlocked=").append(numBlocked).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numSuspendedByAdmin=").append(numSuspendedByAdmin).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numWithActions=").append(numWithActions).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numPrivate=").append(numPrivate).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numSecret=").append(numSecret).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numInterrupt=").append(numInterrupt).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numWithBigText=").append(numWithBigText).append(",\n");
+            output.append(indentPlusTwo);
+            output.append("numWithBigPicture=").append(numWithBigPicture).append("\n");
+            output.append(indentPlusTwo);
+            output.append("numForegroundService=").append(numForegroundService).append("\n");
+            output.append(indentPlusTwo);
+            output.append("numOngoing=").append(numOngoing).append("\n");
+            output.append(indentPlusTwo);
+            output.append("numAutoCancel=").append(numAutoCancel).append("\n");
+            output.append(indentPlusTwo);
+            output.append("numWithLargeIcon=").append(numWithLargeIcon).append("\n");
+            output.append(indentPlusTwo);
+            output.append("numWithInbox=").append(numWithInbox).append("\n");
+            output.append(indentPlusTwo);
+            output.append("numWithMediaSession=").append(numWithMediaSession).append("\n");
+            output.append(indentPlusTwo);
+            output.append("numWithTitle=").append(numWithTitle).append("\n");
+            output.append(indentPlusTwo);
+            output.append("numWithText=").append(numWithText).append("\n");
+            output.append(indentPlusTwo);
+            output.append("numWithSubText=").append(numWithSubText).append("\n");
+            output.append(indentPlusTwo);
+            output.append("numWithInfoText=").append(numWithInfoText).append("\n");
+            output.append(indentPlusTwo).append(noisyImportance.toString()).append("\n");
+            output.append(indentPlusTwo).append(quietImportance.toString()).append("\n");
+            output.append(indentPlusTwo).append(finalImportance.toString()).append("\n");
+            output.append(indent).append("}");
+            return output.toString();
         }
 
         public JSONObject dumpJson() throws JSONException {
@@ -508,13 +564,10 @@
             maybePut(dump, "numWithStaredPeople", numWithStaredPeople);
             maybePut(dump, "numWithValidPeople", numWithValidPeople);
             maybePut(dump, "numBlocked", numBlocked);
+            maybePut(dump, "numSuspendedByAdmin", numSuspendedByAdmin);
             maybePut(dump, "numWithActions", numWithActions);
             maybePut(dump, "numPrivate", numPrivate);
             maybePut(dump, "numSecret", numSecret);
-            maybePut(dump, "numPriorityMax", numPriorityMax);
-            maybePut(dump, "numPriorityHigh", numPriorityHigh);
-            maybePut(dump, "numPriorityLow", numPriorityLow);
-            maybePut(dump, "numPriorityMin", numPriorityMin);
             maybePut(dump, "numInterrupt", numInterrupt);
             maybePut(dump, "numWithBigText", numWithBigText);
             maybePut(dump, "numWithBigPicture", numWithBigPicture);
@@ -528,6 +581,10 @@
             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);
+
             return dump;
         }
 
@@ -538,6 +595,65 @@
         }
     }
 
+    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 final Context mContext;
+        private final String[] mCounterNames;
+        private final String mPrefix;
+        private int[] mCount;
+
+        ImportanceHistogram(Context context, String prefix) {
+            mContext = context;
+            mCount = new int[NUM_IMPORTANCES];
+            mCounterNames = new String[NUM_IMPORTANCES];
+            mPrefix = prefix;
+            for (int i = 0; i < NUM_IMPORTANCES; i++) {
+                mCounterNames[i] = mPrefix + IMPORTANCE_NAMES[i];
+            }
+        }
+
+        void increment(int imp) {
+            imp = imp < 0 ? 0 : imp > NUM_IMPORTANCES ? NUM_IMPORTANCES : imp;
+            mCount[imp] ++;
+        }
+
+        void maybeCount(ImportanceHistogram prev) {
+            for (int i = 0; i < NUM_IMPORTANCES; i++) {
+                final int value = mCount[i] - prev.mCount[i];
+                if (value > 0) {
+                    MetricsLogger.count(mContext, mCounterNames[i], value);
+                }
+            }
+        }
+
+        void update(ImportanceHistogram that) {
+            for (int i = 0; i < NUM_IMPORTANCES; i++) {
+                mCount[i] = that.mCount[i];
+            }
+        }
+
+        public void maybePut(JSONObject dump, ImportanceHistogram prev)
+                throws JSONException {
+            dump.put(mPrefix, new JSONArray(mCount));
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder output = new StringBuilder();
+            output.append(mPrefix).append(": [");
+            for (int i = 0; i < NUM_IMPORTANCES; i++) {
+                output.append(mCount[i]);
+                if (i < (NUM_IMPORTANCES-1)) {
+                    output.append(", ");
+                }
+            }
+            output.append("]");
+            return output.toString();
+        }
+    }
+
     /**
      * Tracks usage of an individual notification that is currently active.
      */
@@ -575,6 +691,12 @@
         public long airtimeExpandedMs = 0;
         /** Number of times the notification has been expanded by the user. */
         public long userExpansionCount = 0;
+        /** Importance directly requested by the app. */
+        public int requestedImportance;
+        /** Did the app include sound or vibration on the notificaiton. */
+        public boolean isNoisy;
+        /** Importance after initial filtering for noise and other features */
+        public int naturalImportance;
 
         public long getCurrentPosttimeMs() {
             if (posttimeElapsedMs < 0) {
@@ -686,17 +808,40 @@
 
         @Override
         public String toString() {
-            return "SingleNotificationStats{" +
-                    "posttimeElapsedMs=" + posttimeElapsedMs +
-                    ", posttimeToFirstClickMs=" + posttimeToFirstClickMs +
-                    ", posttimeToDismissMs=" + posttimeToDismissMs +
-                    ", airtimeCount=" + airtimeCount +
-                    ", airtimeMs=" + airtimeMs +
-                    ", currentAirtimeStartElapsedMs=" + currentAirtimeStartElapsedMs +
-                    ", airtimeExpandedMs=" + airtimeExpandedMs +
-                    ", posttimeToFirstVisibleExpansionMs=" + posttimeToFirstVisibleExpansionMs +
-                    ", currentAirtimeExpandedSEMs=" + currentAirtimeExpandedStartElapsedMs +
-                    '}';
+            StringBuilder output = new StringBuilder();
+            output.append("SingleNotificationStats{");
+
+            output.append("posttimeElapsedMs=").append(posttimeElapsedMs).append(", ");
+            output.append("posttimeToFirstClickMs=").append(posttimeToFirstClickMs).append(", ");
+            output.append("posttimeToDismissMs=").append(posttimeToDismissMs).append(", ");
+            output.append("airtimeCount=").append(airtimeCount).append(", ");
+            output.append("airtimeMs=").append(airtimeMs).append(", ");
+            output.append("currentAirtimeStartElapsedMs=").append(currentAirtimeStartElapsedMs)
+                    .append(", ");
+            output.append("airtimeExpandedMs=").append(airtimeExpandedMs).append(", ");
+            output.append("posttimeToFirstVisibleExpansionMs=")
+                    .append(posttimeToFirstVisibleExpansionMs).append(", ");
+            output.append("currentAirtimeExpandedStartElapsedMs=")
+                    .append(currentAirtimeExpandedStartElapsedMs).append(", ");
+            output.append("requestedImportance=").append(requestedImportance).append(", ");
+            output.append("naturalImportance=").append(naturalImportance).append(", ");
+            output.append("isNoisy=").append(isNoisy);
+            output.append('}');
+            return output.toString();
+        }
+
+        /** Copy useful information out of the stats from the pre-update notifications. */
+        public void updateFrom(SingleNotificationStats old) {
+            posttimeElapsedMs = old.posttimeElapsedMs;
+            posttimeToFirstClickMs = old.posttimeToFirstClickMs;
+            airtimeCount = old.airtimeCount;
+            posttimeToFirstAirtimeMs = old.posttimeToFirstAirtimeMs;
+            currentAirtimeStartElapsedMs = old.currentAirtimeStartElapsedMs;
+            airtimeMs = old.airtimeMs;
+            posttimeToFirstVisibleExpansionMs = old.posttimeToFirstVisibleExpansionMs;
+            currentAirtimeExpandedStartElapsedMs = old.currentAirtimeExpandedStartElapsedMs;
+            airtimeExpandedMs = old.airtimeExpandedMs;
+            userExpansionCount = old.userExpansionCount;
         }
     }
 
@@ -741,7 +886,7 @@
         private static final int MSG_DISMISS = 4;
 
         private static final String DB_NAME = "notification_log.db";
-        private static final int DB_VERSION = 4;
+        private static final int DB_VERSION = 5;
 
         /** Age in ms after which events are pruned from the DB. */
         private static final long HORIZON_MS = 7 * 24 * 60 * 60 * 1000L;  // 1 week
@@ -762,7 +907,11 @@
         private static final String COL_WHEN_MS = "when_ms";
         private static final String COL_DEFAULTS = "defaults";
         private static final String COL_FLAGS = "flags";
-        private static final String COL_PRIORITY = "priority";
+        private static final String COL_IMPORTANCE_REQ = "importance_request";
+        private static final String COL_IMPORTANCE_FINAL = "importance_final";
+        private static final String COL_NOISY = "noisy";
+        private static final String COL_MUTED = "muted";
+        private static final String COL_DEMOTED = "demoted";
         private static final String COL_CATEGORY = "category";
         private static final String COL_ACTION_COUNT = "action_count";
         private static final String COL_POSTTIME_MS = "posttime_ms";
@@ -776,14 +925,28 @@
         private static final int EVENT_TYPE_CLICK = 2;
         private static final int EVENT_TYPE_REMOVE = 3;
         private static final int EVENT_TYPE_DISMISS = 4;
-
         private static long sLastPruneMs;
+
         private static long sNumWrites;
-
         private final SQLiteOpenHelper mHelper;
-        private final Handler mWriteHandler;
 
+        private final Handler mWriteHandler;
         private static final long DAY_MS = 24 * 60 * 60 * 1000;
+        private static final String STATS_QUERY = "SELECT " +
+                COL_EVENT_USER_ID + ", " +
+                COL_PKG + ", " +
+                // Bucket by day by looking at 'floor((midnight - eventTimeMs) / dayMs)'
+                "CAST(((%d - " + COL_EVENT_TIME + ") / " + DAY_MS + ") AS int) " +
+                "AS day, " +
+                "COUNT(*) AS cnt, " +
+                "SUM(" + COL_MUTED + ") as muted, " +
+                "SUM(" + COL_NOISY + ") as noisy, " +
+                "SUM(" + COL_DEMOTED + ") as demoted " +
+                "FROM " + TAB_LOG + " " +
+                "WHERE " +
+                COL_EVENT_TYPE + "=" + EVENT_TYPE_POST +
+                " AND " + COL_EVENT_TIME + " > %d " +
+                " GROUP BY " + COL_EVENT_USER_ID + ", day, " + COL_PKG;
 
         public SQLiteLog(Context context) {
             HandlerThread backgroundThread = new HandlerThread("notification-sqlite-log",
@@ -828,7 +991,11 @@
                             COL_WHEN_MS + " INT," +
                             COL_DEFAULTS + " INT," +
                             COL_FLAGS + " INT," +
-                            COL_PRIORITY + " INT," +
+                            COL_IMPORTANCE_REQ + " INT," +
+                            COL_IMPORTANCE_FINAL + " INT," +
+                            COL_NOISY + " INT," +
+                            COL_MUTED + " INT," +
+                            COL_DEMOTED + " INT," +
                             COL_CATEGORY + " TEXT," +
                             COL_ACTION_COUNT + " INT," +
                             COL_POSTTIME_MS + " INT," +
@@ -841,8 +1008,7 @@
 
                 @Override
                 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-                    if (oldVersion <= 3) {
-                        // Version 3 creation left 'log' in a weird state. Just reset for now.
+                    if (oldVersion != newVersion) {
                         db.execSQL("DROP TABLE IF EXISTS " + TAB_LOG);
                         onCreate(db);
                     }
@@ -866,22 +1032,11 @@
             mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_DISMISS, notification));
         }
 
-        private JSONArray JsonPostFrequencies(DumpFilter filter) throws JSONException {
+        private JSONArray jsonPostFrequencies(DumpFilter filter) throws JSONException {
             JSONArray frequencies = new JSONArray();
             SQLiteDatabase db = mHelper.getReadableDatabase();
             long midnight = getMidnightMs();
-            String q = "SELECT " +
-                    COL_EVENT_USER_ID + ", " +
-                    COL_PKG + ", " +
-                    // Bucket by day by looking at 'floor((midnight - eventTimeMs) / dayMs)'
-                    "CAST(((" + midnight + " - " + COL_EVENT_TIME + ") / " + DAY_MS + ") AS int) " +
-                    "AS day, " +
-                    "COUNT(*) AS cnt " +
-                    "FROM " + TAB_LOG + " " +
-                    "WHERE " +
-                    COL_EVENT_TYPE + "=" + EVENT_TYPE_POST +
-                    " AND " + COL_EVENT_TIME + " > " + filter.since +
-                    " GROUP BY " + COL_EVENT_USER_ID + ", day, " + COL_PKG;
+            String q = String.format(STATS_QUERY, midnight, filter.since);
             Cursor cursor = db.rawQuery(q, null);
             try {
                 for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
@@ -890,11 +1045,17 @@
                     if (filter != null && !filter.matches(pkg)) continue;
                     int day = cursor.getInt(2);
                     int count = cursor.getInt(3);
+                    int muted = cursor.getInt(4);
+                    int noisy = cursor.getInt(5);
+                    int demoted = cursor.getInt(6);
                     JSONObject row = new JSONObject();
                     row.put("user_id", userId);
                     row.put("package", pkg);
                     row.put("day", day);
                     row.put("count", count);
+                    row.put("noisy", noisy);
+                    row.put("muted", muted);
+                    row.put("demoted", demoted);
                     frequencies.put(row);
                 }
             } finally {
@@ -906,17 +1067,7 @@
         public void printPostFrequencies(PrintWriter pw, String indent, DumpFilter filter) {
             SQLiteDatabase db = mHelper.getReadableDatabase();
             long midnight = getMidnightMs();
-            String q = "SELECT " +
-                    COL_EVENT_USER_ID + ", " +
-                    COL_PKG + ", " +
-                    // Bucket by day by looking at 'floor((midnight - eventTimeMs) / dayMs)'
-                    "CAST(((" + midnight + " - " + COL_EVENT_TIME + ") / " + DAY_MS + ") AS int) " +
-                        "AS day, " +
-                    "COUNT(*) AS cnt " +
-                    "FROM " + TAB_LOG + " " +
-                    "WHERE " +
-                    COL_EVENT_TYPE + "=" + EVENT_TYPE_POST + " " +
-                    "GROUP BY " + COL_EVENT_USER_ID + ", day, " + COL_PKG;
+            String q = String.format(STATS_QUERY, midnight, filter.since);
             Cursor cursor = db.rawQuery(q, null);
             try {
                 for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
@@ -925,8 +1076,12 @@
                     if (filter != null && !filter.matches(pkg)) continue;
                     int day = cursor.getInt(2);
                     int count = cursor.getInt(3);
+                    int muted = cursor.getInt(4);
+                    int noisy = cursor.getInt(5);
+                    int demoted = cursor.getInt(6);
                     pw.println(indent + "post_frequency{user_id=" + userId + ",pkg=" + pkg +
-                            ",day=" + day + ",count=" + count + "}");
+                            ",day=" + day + ",count=" + count + ",muted=" + muted + "/" + noisy +
+                            ",demoted=" + demoted + "}");
                 }
             } finally {
                 cursor.close();
@@ -985,7 +1140,18 @@
             }
             outCv.put(COL_WHEN_MS, r.sbn.getPostTime());
             outCv.put(COL_FLAGS, r.getNotification().flags);
-            outCv.put(COL_PRIORITY, r.getNotification().priority);
+            final int before = r.stats.requestedImportance;
+            final int after = r.getImportance();
+            final boolean noisy = r.stats.isNoisy;
+            outCv.put(COL_IMPORTANCE_REQ, before);
+            outCv.put(COL_IMPORTANCE_FINAL, after);
+            outCv.put(COL_DEMOTED, after < before ? 1 : 0);
+            outCv.put(COL_NOISY, noisy);
+            if (noisy && after < IMPORTANCE_HIGH) {
+                outCv.put(COL_MUTED, 1);
+            } else {
+                outCv.put(COL_MUTED, 0);
+            }
             if (r.getNotification().category != null) {
                 outCv.put(COL_CATEGORY, r.getNotification().category);
             }
@@ -1008,7 +1174,9 @@
         public JSONObject dumpJson(DumpFilter filter) {
             JSONObject dump = new JSONObject();
             try {
-                dump.put("post_frequency", JsonPostFrequencies(filter));
+                dump.put("post_frequency", jsonPostFrequencies(filter));
+                dump.put("since", filter.since);
+                dump.put("now", System.currentTimeMillis());
             } catch (JSONException e) {
                 // pass
             }
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index acdd90a..7f85e1f 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -23,16 +23,18 @@
 
     List<Notification.Topic> getTopics(String packageName, int uid);
 
-    int getTopicPriority(String packageName, int uid, Notification.Topic topic);
+    int getPriority(String packageName, int uid, Notification.Topic topic);
 
-    void setTopicPriority(String packageName, int uid, Notification.Topic topic, int priority);
+    void setPriority(String packageName, int uid, Notification.Topic topic, int priority);
 
-    int getTopicVisibilityOverride(String packageName, int uid, Notification.Topic topic);
+    int getVisibilityOverride(String packageName, int uid, Notification.Topic topic);
 
-    void setTopicVisibilityOverride(String packageName, int uid, Notification.Topic topic,
+    void setVisibilityOverride(String packageName, int uid, Notification.Topic topic,
             int visibility);
 
-    void setTopicImportance(String packageName, int uid, Notification.Topic topic, int importance);
+    void setImportance(String packageName, int uid, Notification.Topic topic, int importance);
 
-    int getTopicImportance(String packageName, int uid, Notification.Topic topic);
+    int getImportance(String packageName, int uid, Notification.Topic topic);
+
+    boolean doesAppUseTopics(String packageName, int uid);
 }
diff --git a/services/core/java/com/android/server/notification/RankingHandler.java b/services/core/java/com/android/server/notification/RankingHandler.java
new file mode 100644
index 0000000..80bb4f0
--- /dev/null
+++ b/services/core/java/com/android/server/notification/RankingHandler.java
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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;
+
+public interface RankingHandler {
+    public void requestSort();
+    public void requestReconsideration(RankingReconsideration recon);
+}
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 5a31c6a..827482f 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -19,10 +19,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Handler;
-import android.os.Message;
 import android.os.UserHandle;
-import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.Ranking;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -40,7 +37,6 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.TimeUnit;
 
 public class RankingHelper implements RankingConfig {
     private static final String TAG = "RankingHelper";
@@ -73,10 +69,10 @@
     private final ArrayMap<String, Record> mRestoredWithoutUids = new ArrayMap<>(); // pkg => Record
 
     private final Context mContext;
-    private final Handler mRankingHandler;
+    private final RankingHandler mRankingHandler;
 
-    public RankingHelper(Context context, Handler rankingHandler, NotificationUsageStats usageStats,
-            String[] extractorNames) {
+    public RankingHelper(Context context, RankingHandler rankingHandler,
+            NotificationUsageStats usageStats, String[] extractorNames) {
         mContext = context;
         mRankingHandler = rankingHandler;
 
@@ -119,10 +115,7 @@
             try {
                 RankingReconsideration recon = extractor.process(r);
                 if (recon != null) {
-                    Message m = Message.obtain(mRankingHandler,
-                            NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
-                    long delay = recon.getDelay(TimeUnit.MILLISECONDS);
-                    mRankingHandler.sendMessageDelayed(m, delay);
+                    mRankingHandler.requestReconsideration(recon);
                 }
             } catch (Throwable t) {
                 Slog.w(TAG, "NotificationSignalExtractor failed.", t);
@@ -155,7 +148,7 @@
                         if (forRestore) {
                             try {
                                 //TODO: http://b/22388012
-                                uid = pm.getPackageUid(name, UserHandle.USER_SYSTEM);
+                                uid = pm.getPackageUidAsUser(name, UserHandle.USER_SYSTEM);
                             } catch (NameNotFoundException e) {
                                 // noop
                             }
@@ -170,6 +163,9 @@
                         } else {
                             r = getOrCreateRecord(name, uid);
                         }
+                        r.importance = safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
+                        r.priority = priority;
+                        r.visibility = vis;
 
                         // Migrate package level settings to the default topic.
                         // Might be overwritten by parseTopics.
@@ -251,6 +247,15 @@
             }
             out.startTag(null, TAG_PACKAGE);
             out.attribute(null, ATT_NAME, r.pkg);
+            if (r.importance != DEFAULT_IMPORTANCE) {
+                out.attribute(null, ATT_IMPORTANCE, Integer.toString(r.importance));
+            }
+            if (r.priority != DEFAULT_PRIORITY) {
+                out.attribute(null, ATT_PRIORITY, Integer.toString(r.priority));
+            }
+            if (r.visibility != DEFAULT_VISIBILITY) {
+                out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility));
+            }
 
             if (!forBackup) {
                 out.attribute(null, ATT_UID, Integer.toString(r.uid));
@@ -285,7 +290,7 @@
         for (int i = 0; i < N; i++) {
             mSignalExtractors[i].setConfig(this);
         }
-        mRankingHandler.sendEmptyMessage(NotificationManagerService.MESSAGE_RANKING_CONFIG_CHANGE);
+        mRankingHandler.requestSort();
     }
 
     public void sort(ArrayList<NotificationRecord> notificationList) {
@@ -378,54 +383,125 @@
     public List<Notification.Topic> getTopics(String packageName, int uid) {
         final Record r = getOrCreateRecord(packageName, uid);
         List<Notification.Topic> topics = new ArrayList<>();
-        for (Topic t :  r.topics.values()) {
+        for (Topic t : r.topics.values()) {
             topics.add(t.topic);
         }
         return topics;
     }
 
+    /**
+     * Gets priority. If a topic is given, returns the priority of that topic. Otherwise, the
+     * priority of the app.
+     */
     @Override
-    public int getTopicPriority(String packageName, int uid, Notification.Topic topic) {
+    public int getPriority(String packageName, int uid, Notification.Topic topic) {
         final Record r = getOrCreateRecord(packageName, uid);
+        if (topic == null) {
+            return r.priority;
+        }
         return getOrCreateTopic(r, topic).priority;
     }
 
+    /**
+     * Sets priority. If a topic is given, sets the priority of that topic. If not,
+     * sets the default priority for all new topics that appear in the future, and resets
+     * the priority of all current topics.
+     */
     @Override
-    public void setTopicPriority(String packageName, int uid, Notification.Topic topic,
+    public void setPriority(String packageName, int uid, Notification.Topic topic,
             int priority) {
         final Record r = getOrCreateRecord(packageName, uid);
-        getOrCreateTopic(r, topic).priority = priority;
+        if (topic == null) {
+            r.priority = priority;
+            for (Topic t : r.topics.values()) {
+                t.priority = priority;
+            }
+        } else {
+            getOrCreateTopic(r, topic).priority = priority;
+        }
         updateConfig();
     }
 
+    /**
+     * Gets visual override. If a topic is given, returns the override of that topic. Otherwise, the
+     * override of the app.
+     */
     @Override
-    public int getTopicVisibilityOverride(String packageName, int uid, Notification.Topic topic) {
+    public int getVisibilityOverride(String packageName, int uid, Notification.Topic topic) {
         final Record r = getOrCreateRecord(packageName, uid);
+        if (topic == null) {
+            return r.visibility;
+        }
         return getOrCreateTopic(r, topic).visibility;
     }
 
+    /**
+     * Sets visibility override. If a topic is given, sets the override of that topic. If not,
+     * sets the default override for all new topics that appear in the future, and resets
+     * the override of all current topics.
+     */
     @Override
-    public void setTopicVisibilityOverride(String pkgName, int uid, Notification.Topic topic,
+    public void setVisibilityOverride(String pkgName, int uid, Notification.Topic topic,
         int visibility) {
         final Record r = getOrCreateRecord(pkgName, uid);
-        getOrCreateTopic(r, topic).visibility = visibility;
+        if (topic == null) {
+            r.visibility = visibility;
+            for (Topic t : r.topics.values()) {
+                t.visibility = visibility;
+            }
+        } else {
+            getOrCreateTopic(r, topic).visibility = visibility;
+        }
         updateConfig();
     }
 
+    /**
+     * Gets importance. If a topic is given, returns the importance of that topic. Otherwise, the
+     * importance of the app.
+     */
     @Override
-    public int getTopicImportance(String packageName, int uid, Notification.Topic topic) {
+    public int getImportance(String packageName, int uid, Notification.Topic topic) {
         final Record r = getOrCreateRecord(packageName, uid);
+        if (topic == null) {
+            return r.importance;
+        }
         return getOrCreateTopic(r, topic).importance;
     }
 
+    /**
+     * Sets importance. If a topic is given, sets the importance of that topic. If not, sets the
+     * default importance for all new topics that appear in the future, and resets
+     * the importance of all current topics (unless the app is being blocked).
+     */
     @Override
-    public void setTopicImportance(String pkgName, int uid, Notification.Topic topic,
+    public void setImportance(String pkgName, int uid, Notification.Topic topic,
             int importance) {
         final Record r = getOrCreateRecord(pkgName, uid);
-        getOrCreateTopic(r, topic).importance = importance;
+        if (topic == null) {
+            r.importance = importance;
+            if (Ranking.IMPORTANCE_NONE != importance) {
+                for (Topic t : r.topics.values()) {
+                    t.importance = importance;
+                }
+            }
+        } else {
+            getOrCreateTopic(r, topic).importance = importance;
+        }
         updateConfig();
     }
 
+    @Override
+    public boolean doesAppUseTopics(String pkgName, int uid) {
+        final Record r = getOrCreateRecord(pkgName, uid);
+        int numTopics = r.topics.size();
+        if (numTopics == 0
+                || (numTopics == 1 && r.topics.containsKey(Notification.TOPIC_DEFAULT))) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+
     private Topic getOrCreateTopic(Record r, Notification.Topic topic) {
         if (topic == null) {
             topic = createDefaultTopic();
@@ -435,6 +511,9 @@
             return t;
         } else {
             t = new Topic(topic);
+            t.importance = r.importance;
+            t.priority = r.priority;
+            t.visibility = r.visibility;
             r.topics.put(topic.getId(), t);
             return t;
         }
@@ -461,7 +540,9 @@
             pw.print(prefix);
             pw.println("per-package config:");
         }
+        pw.println("Records:");
         dumpRecords(pw, prefix, filter, mRecords);
+        pw.println("Restored without uid:");
         dumpRecords(pw, prefix, filter, mRestoredWithoutUids);
     }
 
@@ -477,6 +558,18 @@
                 pw.print(" (");
                 pw.print(r.uid == Record.UNKNOWN_UID ? "UNKNOWN_UID" : Integer.toString(r.uid));
                 pw.print(')');
+                if (r.importance != DEFAULT_IMPORTANCE) {
+                    pw.print(" importance=");
+                    pw.print(Ranking.importanceToString(r.importance));
+                }
+                if (r.priority != DEFAULT_PRIORITY) {
+                    pw.print(" priority=");
+                    pw.print(Ranking.importanceToString(r.priority));
+                }
+                if (r.visibility != DEFAULT_VISIBILITY) {
+                    pw.print(" visibility=");
+                    pw.print(Ranking.importanceToString(r.visibility));
+                }
                 pw.println();
                 for (Topic t : r.topics.values()) {
                     pw.print(prefix);
@@ -513,7 +606,7 @@
             if (r != null) {
                 try {
                     //TODO: http://b/22388012
-                    r.uid = pm.getPackageUid(r.pkg, UserHandle.USER_SYSTEM);
+                    r.uid = pm.getPackageUidAsUser(r.pkg, UserHandle.USER_SYSTEM);
                     mRestoredWithoutUids.remove(pkg);
                     mRecords.put(recordKey(r.pkg, r.uid), r);
                     updated = true;
@@ -532,6 +625,9 @@
 
         String pkg;
         int uid = UNKNOWN_UID;
+        int importance = DEFAULT_IMPORTANCE;
+        int priority = DEFAULT_PRIORITY;
+        int visibility = DEFAULT_VISIBILITY;
         Map<String, Topic> topics = new ArrayMap<>();
    }
 
diff --git a/services/core/java/com/android/server/notification/TopicImportanceExtractor.java b/services/core/java/com/android/server/notification/TopicImportanceExtractor.java
index 01770d0..c6b3e0f 100644
--- a/services/core/java/com/android/server/notification/TopicImportanceExtractor.java
+++ b/services/core/java/com/android/server/notification/TopicImportanceExtractor.java
@@ -42,7 +42,7 @@
             return null;
         }
 
-        final int topicImportance = mConfig.getTopicImportance(record.sbn.getPackageName(),
+        final int topicImportance = mConfig.getImportance(record.sbn.getPackageName(),
                 record.sbn.getUid(), record.sbn.getNotification().getTopic());
         record.setTopicImportance(topicImportance);
 
diff --git a/services/core/java/com/android/server/notification/TopicPriorityExtractor.java b/services/core/java/com/android/server/notification/TopicPriorityExtractor.java
index 5bf989ae..1df5c2b 100644
--- a/services/core/java/com/android/server/notification/TopicPriorityExtractor.java
+++ b/services/core/java/com/android/server/notification/TopicPriorityExtractor.java
@@ -42,7 +42,7 @@
             return null;
         }
 
-        final int packagePriority = mConfig.getTopicPriority(record.sbn.getPackageName(),
+        final int packagePriority = mConfig.getPriority(record.sbn.getPackageName(),
                 record.sbn.getUid(), record.sbn.getNotification().getTopic());
         record.setPackagePriority(packagePriority);
 
diff --git a/services/core/java/com/android/server/notification/TopicVisibilityExtractor.java b/services/core/java/com/android/server/notification/TopicVisibilityExtractor.java
index e053382..eaa3ed3 100644
--- a/services/core/java/com/android/server/notification/TopicVisibilityExtractor.java
+++ b/services/core/java/com/android/server/notification/TopicVisibilityExtractor.java
@@ -42,7 +42,7 @@
             return null;
         }
 
-        final int packageVisibility = mConfig.getTopicVisibilityOverride(
+        final int packageVisibility = mConfig.getVisibilityOverride(
                 record.sbn.getPackageName(), record.sbn.getUid(),
                 record.sbn.getNotification().getTopic());
         record.setPackageVisibilityOverride(packageVisibility);
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
index cee9ec8..9cdece5 100644
--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -109,7 +109,6 @@
         if (DEBUG) Log.d(TAG, "onConditionChanged " + id + " " + condition);
         ZenModeConfig config = mHelper.getConfig();
         if (config == null) return;
-        config = config.copy();
         boolean updated = updateCondition(id, condition, config.manualRule);
         for (ZenRule automaticRule : config.automaticRules.values()) {
             updated |= updateCondition(id, condition, automaticRule);
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 6030bab..1d91fb7 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -27,7 +27,10 @@
 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.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.database.ContentObserver;
@@ -45,7 +48,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings.Global;
-import android.service.notification.IConditionListener;
+import android.service.notification.ConditionProviderService;
 import android.service.notification.ZenModeConfig;
 import android.service.notification.ZenModeConfig.EventInfo;
 import android.service.notification.ZenModeConfig.ScheduleInfo;
@@ -77,6 +80,9 @@
     static final String TAG = "ZenModeHelper";
     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
+    // The amount of time rules instances can exist without their owning app being installed.
+    private static final int RULE_INSTANCE_GRACE_PERIOD = 1000 * 60 * 60 * 72;
+
     private final Context mContext;
     private final H mHandler;
     private final SettingsObserver mSettingsObserver;
@@ -88,11 +94,13 @@
     private final ZenModeConditions mConditions;
     private final SparseArray<ZenModeConfig> mConfigs = new SparseArray<>();
     private final Metrics mMetrics = new Metrics();
+    private final ConditionProviders.Config mServiceConfig;
 
     private int mZenMode;
     private int mUser = UserHandle.USER_SYSTEM;
     private ZenModeConfig mConfig;
     private AudioManagerInternal mAudioManager;
+    private PackageManager mPm;
     private boolean mEffectsSuppressed;
 
     public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) {
@@ -109,6 +117,7 @@
         mSettingsObserver.observe();
         mFiltering = new ZenModeFiltering(mContext);
         mConditions = new ZenModeConditions(this, conditionProviders);
+        mServiceConfig = conditionProviders.getConfig();
     }
 
     public Looper getLooper() {
@@ -151,6 +160,12 @@
         }
     }
 
+    public boolean shouldSuppressScreenOn() {
+        synchronized (mConfig) {
+            return !mConfig.allowScreenOn;
+        }
+    }
+
     public void addCallback(Callback callback) {
         mCallbacks.add(callback);
     }
@@ -170,7 +185,9 @@
         if (mAudioManager != null) {
             mAudioManager.setRingerModeDelegate(mRingerModeDelegate);
         }
+        mPm = mContext.getPackageManager();
         mHandler.postMetricsTimer();
+        cleanUpZenRules();
         evaluateZenMode("onSystemReady", true);
     }
 
@@ -184,7 +201,10 @@
             config = mDefaultConfig.copy();
             config.user = user;
         }
-        setConfig(config, "onUserSwitched");
+        synchronized (mConfig) {
+            setConfigLocked(config, "onUserSwitched");
+        }
+        cleanUpZenRules();
     }
 
     public void onUserRemoved(int user) {
@@ -242,25 +262,38 @@
     }
 
     public AutomaticZenRule addAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) {
+        if (!TextUtils.isEmpty(automaticZenRule.getId())) {
+            throw new IllegalArgumentException("Rule already exists");
+        }
+        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);
+            if (ruleInstanceLimit > 0 && ruleInstanceLimit
+                    < (getCurrentInstanceCount(automaticZenRule.getOwner()) + 1)) {
+                throw new IllegalArgumentException("Rule instance limit exceeded");
+            }
+        }
+
         ZenModeConfig newConfig;
         synchronized (mConfig) {
             if (mConfig == null) return null;
             if (DEBUG) {
-                Log.d(TAG,
-                        "addAutomaticZenRule zenRule= " + automaticZenRule + " reason=" + reason);
-            }
-            if (!TextUtils.isEmpty(automaticZenRule.getId())) {
-                throw new IllegalArgumentException("Rule already exists");
+                Log.d(TAG, "addAutomaticZenRule rule= " + automaticZenRule + " reason=" + reason);
             }
             newConfig = mConfig.copy();
-        }
-        ZenRule rule = new ZenRule();
-        populateZenRule(automaticZenRule, rule, true);
-        newConfig.automaticRules.put(rule.id, rule);
-        if (setConfig(newConfig, reason, true)) {
-            return createAutomaticZenRule(rule);
-        } else {
-            return null;
+            ZenRule rule = new ZenRule();
+            populateZenRule(automaticZenRule, rule, true);
+            newConfig.automaticRules.put(rule.id, rule);
+            if (setConfigLocked(newConfig, reason, true)) {
+                return createAutomaticZenRule(rule);
+            } else {
+                return null;
+            }
         }
     }
 
@@ -273,21 +306,21 @@
                         + " reason=" + reason);
             }
             newConfig = mConfig.copy();
-        }
-        final String ruleId = automaticZenRule.getId();
-        ZenModeConfig.ZenRule rule;
-        if (ruleId == null) {
-            throw new IllegalArgumentException("Rule doesn't exist");
-        } else {
-            rule = newConfig.automaticRules.get(ruleId);
-            if (rule == null || !canManageAutomaticZenRule(rule)) {
-                throw new SecurityException(
-                        "Cannot update rules not owned by your condition provider");
+            final String ruleId = automaticZenRule.getId();
+            ZenModeConfig.ZenRule rule;
+            if (ruleId == null) {
+                throw new IllegalArgumentException("Rule doesn't exist");
+            } else {
+                rule = newConfig.automaticRules.get(ruleId);
+                if (rule == null || !canManageAutomaticZenRule(rule)) {
+                    throw new SecurityException(
+                            "Cannot update rules not owned by your condition provider");
+                }
             }
+            populateZenRule(automaticZenRule, rule, false);
+            newConfig.automaticRules.put(ruleId, rule);
+            return setConfigLocked(newConfig, reason, true);
         }
-        populateZenRule(automaticZenRule, rule, false);
-        newConfig.automaticRules.put(ruleId, rule);
-        return setConfig(newConfig, reason, true);
     }
 
     public boolean removeAutomaticZenRule(String id, String reason) {
@@ -295,17 +328,17 @@
         synchronized (mConfig) {
             if (mConfig == null) return false;
             newConfig = mConfig.copy();
+            ZenRule rule = newConfig.automaticRules.get(id);
+            if (rule == null) return false;
+            if (canManageAutomaticZenRule(rule)) {
+                newConfig.automaticRules.remove(id);
+                if (DEBUG) Log.d(TAG, "removeZenRule zenRule=" + id + " reason=" + reason);
+            } else {
+                throw new SecurityException(
+                        "Cannot delete rules not owned by your condition provider");
+            }
+            return setConfigLocked(newConfig, reason, true);
         }
-        ZenRule rule = newConfig.automaticRules.get(id);
-        if (rule == null) return false;
-        if (canManageAutomaticZenRule(rule)) {
-            newConfig.automaticRules.remove(id);
-            if (DEBUG) Log.d(TAG, "removeZenRule zenRule=" + id + " reason=" + reason);
-        } else {
-            throw new SecurityException(
-                     "Cannot delete rules not owned by your condition provider");
-        }
-        return setConfig(newConfig, reason, true);
     }
 
     public boolean removeAutomaticZenRules(String packageName, String reason) {
@@ -313,15 +346,27 @@
         synchronized (mConfig) {
             if (mConfig == null) return false;
             newConfig = mConfig.copy();
+            for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
+                ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
+                if (rule.component.getPackageName().equals(packageName)
+                        && canManageAutomaticZenRule(rule)) {
+                    newConfig.automaticRules.removeAt(i);
+                }
+            }
+            return setConfigLocked(newConfig, reason, true);
         }
-        for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
-            ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
-            if (rule.component.getPackageName().equals(packageName)
-                    && canManageAutomaticZenRule(rule)) {
-                newConfig.automaticRules.removeAt(i);
+    }
+
+    public int getCurrentInstanceCount(ComponentName owner) {
+        int count = 0;
+        synchronized (mConfig) {
+            for (ZenRule rule : mConfig.automaticRules.values()) {
+                if (rule.component != null && rule.component.equals(owner)) {
+                    count++;
+                }
             }
         }
-        return setConfig(newConfig, reason, true);
+        return count;
     }
 
     public boolean canManageAutomaticZenRule(ZenRule rule) {
@@ -332,8 +377,7 @@
                 == PackageManager.PERMISSION_GRANTED) {
             return true;
         } else {
-            String[] packages =
-                    mContext.getPackageManager().getPackagesForUid(Binder.getCallingUid());
+            String[] packages = mPm.getPackagesForUid(Binder.getCallingUid());
             if (packages != null) {
                 final int packageCount = packages.length;
                 for (int i = 0; i < packageCount; i++) {
@@ -346,6 +390,29 @@
         }
     }
 
+    private boolean isSystemRule(AutomaticZenRule rule) {
+        return ZenModeConfig.SYSTEM_AUTHORITY.equals(rule.getOwner().getPackageName());
+    }
+
+    private ServiceInfo getServiceInfo(ComponentName owner) {
+        Intent queryIntent = new Intent();
+        queryIntent.setComponent(owner);
+        List<ResolveInfo> installedServices = mPm.queryIntentServicesAsUser(
+                queryIntent,
+                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
+                UserHandle.getCallingUserId());
+        if (installedServices != null) {
+            for (int i = 0, count = installedServices.size(); i < count; i++) {
+                ResolveInfo resolveInfo = installedServices.get(i);
+                ServiceInfo info = resolveInfo.serviceInfo;
+                if (mServiceConfig.bindPermission.equals(info.permission)) {
+                    return info;
+                }
+            }
+        }
+        return null;
+    }
+
     private void populateZenRule(AutomaticZenRule automaticZenRule, ZenRule rule, boolean isNew) {
         if (isNew) {
             rule.id = ZenModeConfig.newRuleId();
@@ -384,22 +451,22 @@
                     + " conditionId=" + conditionId + " reason=" + reason
                     + " setRingerMode=" + setRingerMode);
             newConfig = mConfig.copy();
-        }
-        if (zenMode == Global.ZEN_MODE_OFF) {
-            newConfig.manualRule = null;
-            for (ZenRule automaticRule : newConfig.automaticRules.values()) {
-                if (automaticRule.isAutomaticActive()) {
-                    automaticRule.snoozing = true;
+            if (zenMode == Global.ZEN_MODE_OFF) {
+                newConfig.manualRule = null;
+                for (ZenRule automaticRule : newConfig.automaticRules.values()) {
+                    if (automaticRule.isAutomaticActive()) {
+                        automaticRule.snoozing = true;
+                    }
                 }
+            } else {
+                final ZenRule newRule = new ZenRule();
+                newRule.enabled = true;
+                newRule.zenMode = zenMode;
+                newRule.conditionId = conditionId;
+                newConfig.manualRule = newRule;
             }
-        } else {
-            final ZenRule newRule = new ZenRule();
-            newRule.enabled = true;
-            newRule.zenMode = zenMode;
-            newRule.conditionId = conditionId;
-            newConfig.manualRule = newRule;
+            setConfigLocked(newConfig, reason, setRingerMode);
         }
-        setConfig(newConfig, reason, setRingerMode);
     }
 
     public void dump(PrintWriter pw, String prefix) {
@@ -426,11 +493,12 @@
             return;
         }
         pw.printf("allow(calls=%s,callsFrom=%s,repeatCallers=%s,messages=%s,messagesFrom=%s,"
-                + "events=%s,reminders=%s,lights=%s,peek=%s)\n",
+                + "events=%s,reminders=%s,lights=%s,peek=%s,screenOn=%s)\n",
                 config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom),
                 config.allowRepeatCallers, config.allowMessages,
                 ZenModeConfig.sourceToString(config.allowMessagesFrom),
-                config.allowEvents, config.allowReminders, config.allowLights, config.allowPeek);
+                config.allowEvents, config.allowReminders, config.allowLights, config.allowPeek,
+                config.allowScreenOn);
         pw.print(prefix); pw.print("  manualRule="); pw.println(config.manualRule);
         if (config.automaticRules.isEmpty()) return;
         final int N = config.automaticRules.size();
@@ -450,16 +518,20 @@
                     return;
                 }
                 config.manualRule = null;  // don't restore the manual rule
+                long time = System.currentTimeMillis();
                 if (config.automaticRules != null) {
                     for (ZenRule automaticRule : config.automaticRules.values()) {
                         // don't restore transient state from restored automatic rules
                         automaticRule.snoozing = false;
                         automaticRule.condition = null;
+                        automaticRule.creationTime = time;
                     }
                 }
             }
             if (DEBUG) Log.d(TAG, "readXml");
-            setConfig(config, "readXml");
+            synchronized (mConfig) {
+                setConfigLocked(config, "readXml");
+            }
         }
     }
 
@@ -484,53 +556,79 @@
 
     public void setNotificationPolicy(Policy policy) {
         if (policy == null || mConfig == null) return;
-        final ZenModeConfig newConfig = mConfig.copy();
-        newConfig.applyNotificationPolicy(policy);
-        setConfig(newConfig, "setNotificationPolicy");
+        synchronized (mConfig) {
+            final ZenModeConfig newConfig = mConfig.copy();
+            newConfig.applyNotificationPolicy(policy);
+            setConfigLocked(newConfig, "setNotificationPolicy");
+        }
     }
 
+    /**
+     * Removes old rule instances whose owner is not installed.
+     */
+    private void cleanUpZenRules() {
+        long currentTime = System.currentTimeMillis();
+        synchronized (mConfig) {
+            final ZenModeConfig newConfig = mConfig.copy();
+            if (newConfig.automaticRules != null) {
+                for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
+                    ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
+                    if (RULE_INSTANCE_GRACE_PERIOD < (currentTime - rule.creationTime)) {
+                        try {
+                            mPm.getPackageInfo(rule.component.getPackageName(), 0);
+                        } catch (PackageManager.NameNotFoundException e) {
+                            newConfig.automaticRules.removeAt(i);
+                        }
+                    }
+                }
+            }
+            setConfigLocked(newConfig, "cleanUpZenRules");
+        }
+    }
+
+    /**
+     * @return a copy of the zen mode configuration
+     */
     public ZenModeConfig getConfig() {
         synchronized (mConfig) {
             return mConfig.copy();
         }
     }
 
-    public boolean setConfig(ZenModeConfig config, String reason) {
-        return setConfig(config, reason, true /*setRingerMode*/);
+    public boolean setConfigLocked(ZenModeConfig config, String reason) {
+        return setConfigLocked(config, reason, true /*setRingerMode*/);
     }
 
     public void setConfigAsync(ZenModeConfig config, String reason) {
         mHandler.postSetConfig(config, reason);
     }
 
-    private boolean setConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
+    private boolean setConfigLocked(ZenModeConfig config, String reason, boolean setRingerMode) {
         final long identity = Binder.clearCallingIdentity();
         try {
             if (config == null || !config.isValid()) {
-                Log.w(TAG, "Invalid config in setConfig; " + config);
+                Log.w(TAG, "Invalid config in setConfigLocked; " + config);
                 return false;
             }
             if (config.user != mUser) {
                 // simply store away for background users
                 mConfigs.put(config.user, config);
-                if (DEBUG) Log.d(TAG, "setConfig: store config for user " + config.user);
+                if (DEBUG) Log.d(TAG, "setConfigLocked: store config for user " + config.user);
                 return true;
             }
             mConditions.evaluateConfig(config, false /*processSubscriptions*/);  // may modify config
-            synchronized (mConfig) {
-                mConfigs.put(config.user, config);
-                if (DEBUG) Log.d(TAG, "setConfig reason=" + reason, new Throwable());
-                ZenLog.traceConfig(reason, mConfig, config);
-                final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
-                        getNotificationPolicy(config));
-                mConfig = config;
-                if (config.equals(mConfig)) {
-                    dispatchOnConfigChanged();
-                }
-                if (policyChanged) {
-                    dispatchOnPolicyChanged();
-                }
+            mConfigs.put(config.user, config);
+            if (DEBUG) Log.d(TAG, "setConfigLocked reason=" + reason, new Throwable());
+            ZenLog.traceConfig(reason, mConfig, config);
+            final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
+                    getNotificationPolicy(config));
+            if (!config.equals(mConfig)) {
+                dispatchOnConfigChanged();
             }
+            if (policyChanged) {
+                dispatchOnPolicyChanged();
+            }
+            mConfig = config;
             final String val = Integer.toString(config.hashCode());
             Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
             if (!evaluateZenMode(reason, setRingerMode)) {
@@ -994,7 +1092,9 @@
                     break;
                 case MSG_SET_CONFIG:
                     ConfigMessageData configData = (ConfigMessageData)msg.obj;
-                    setConfig(configData.config, configData.reason);
+                    synchronized (mConfig) {
+                        setConfigLocked(configData.config, configData.reason);
+                    }
                     break;
             }
         }
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index af20679..89e89b0 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -24,6 +24,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.ServiceManager;
+import android.os.SystemProperties;
 import android.util.ArraySet;
 import android.util.Log;
 
@@ -50,12 +51,13 @@
 
     final AtomicBoolean mIdleTime = new AtomicBoolean(false);
 
-    public static void schedule(Context context, long minLatency) {
+    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)
                 .setRequiresDeviceIdle(true)
                 .setRequiresCharging(true)
-                .setMinimumLatency(minLatency)
                 .setPeriodic(TimeUnit.DAYS.toMillis(1))
                 .build();
         js.schedule(job);
@@ -63,16 +65,17 @@
 
     @Override
     public boolean onStartJob(JobParameters params) {
-        Log.i(TAG, "onIdleStart");
+        Log.i(TAG, "onStartJob");
         final PackageManagerService pm =
                 (PackageManagerService)ServiceManager.getService("package");
 
         if (pm.isStorageLow()) {
-            schedule(BackgroundDexOptService.this, RETRY_LATENCY);
+            Log.i(TAG, "Low storage, skipping this run");
             return false;
         }
-        final ArraySet<String> pkgs = pm.getPackagesThatNeedDexOpt();
-        if (pkgs == null) {
+        final ArraySet<String> pkgs = pm.getOptimizablePackages();
+        if (pkgs == null || pkgs.isEmpty()) {
+            Log.i(TAG, "No packages to optimize");
             return false;
         }
 
@@ -83,15 +86,15 @@
             public void run() {
                 for (String pkg : pkgs) {
                     if (!mIdleTime.get()) {
-                        // stopped while still working, so we need to reschedule
-                        schedule(BackgroundDexOptService.this, 0);
+                        // Out of the idle state. Stop the compilation.
                         return;
                     }
                     if (sFailedPackageNames.contains(pkg)) {
                         // skip previously failing package
                         continue;
                     }
-                    if (!pm.performDexOpt(pkg, null /* instruction set */)) {
+                    if (!pm.performDexOpt(pkg, /* instruction set */ null, useJitProfiles,
+                            /* extractOnly */ 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 073b4f03..6c338c1 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -57,7 +57,7 @@
     private static final String TAG = "DefaultPermGrantPolicy"; // must be <= 23 chars
     private static final boolean DEBUG = false;
 
-    private static final int DEFAULT_FLAGS = PackageManager.GET_ENCRYPTION_UNAWARE_COMPONENTS;
+    private static final int DEFAULT_FLAGS = PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
 
     private static final String AUDIO_MIME_TYPE = "audio/mpeg";
 
@@ -261,6 +261,7 @@
                     && doesPackageSupportRuntimePermissions(setupPackage)) {
                 grantRuntimePermissionsLPw(setupPackage, PHONE_PERMISSIONS, userId);
                 grantRuntimePermissionsLPw(setupPackage, CONTACTS_PERMISSIONS, userId);
+                grantRuntimePermissionsLPw(setupPackage, LOCATION_PERMISSIONS, userId);
             }
 
             // Camera
@@ -594,6 +595,14 @@
                 }
             }
 
+            // Print Spooler
+            PackageParser.Package printSpoolerPackage = getSystemPackageLPr(
+                    "com.android.printspooler");
+            if (printSpoolerPackage != null
+                    && doesPackageSupportRuntimePermissions(printSpoolerPackage)) {
+                grantRuntimePermissionsLPw(printSpoolerPackage, LOCATION_PERMISSIONS, true, userId);
+            }
+
             mService.mSettings.onDefaultRuntimePermissionsGrantedLPr(userId);
         }
     }
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 99a051a..cf876ee 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -16,17 +16,21 @@
 
 package com.android.server.pm;
 
+import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.PackageStats;
 import android.os.Build;
-import android.text.TextUtils;
 import android.util.Slog;
 
+import com.android.internal.os.InstallerConnection;
+import com.android.internal.os.InstallerConnection.InstallerException;
+import com.android.server.SystemService;
+
 import dalvik.system.VMRuntime;
 
-import com.android.internal.os.InstallerConnection;
-import com.android.server.SystemService;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 public final class Installer extends SystemService {
     private static final String TAG = "Installer";
@@ -43,8 +47,22 @@
     public static final int DEXOPT_DEBUGGABLE   = 1 << 3;
     /** The system boot has finished */
     public static final int DEXOPT_BOOTCOMPLETE = 1 << 4;
-    /** Run the application with the JIT compiler */
-    public static final int DEXOPT_USEJIT       = 1 << 5;
+    /** Do not compile, only extract bytecode into an OAT file */
+    public static final int DEXOPT_EXTRACTONLY  = 1 << 5;
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            FLAG_DE_STORAGE,
+            FLAG_CE_STORAGE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface StorageFlags {}
+
+    public static final int FLAG_DE_STORAGE = 1 << 0;
+    public static final int FLAG_CE_STORAGE = 1 << 1;
+
+    public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 2;
+    public static final int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 3;
 
     private final InstallerConnection mInstaller;
 
@@ -67,423 +85,141 @@
         mInstaller.waitForConnection();
     }
 
-    private static String escapeNull(String arg) {
-        if (TextUtils.isEmpty(arg)) {
-            return "!";
-        } else {
-            if (arg.indexOf('\0') != -1 || arg.indexOf(' ') != -1) {
-                throw new IllegalArgumentException(arg);
-            }
-            return arg;
-        }
+    public void createAppData(String uuid, String pkgname, int userid, int flags, int appid,
+            String seinfo, int targetSdkVersion) throws InstallerException {
+        mInstaller.execute("create_app_data", uuid, pkgname, userid, flags, appid, seinfo,
+            targetSdkVersion);
     }
 
-    @Deprecated
-    public int install(String name, int uid, int gid, String seinfo) {
-        return install(null, name, uid, gid, seinfo);
+    public void restoreconAppData(String uuid, String pkgname, int userid, int flags, int appid,
+            String seinfo) throws InstallerException {
+        mInstaller.execute("restorecon_app_data", uuid, pkgname, userid, flags, appid,
+                seinfo);
     }
 
-    public int install(String uuid, String name, int uid, int gid, String seinfo) {
-        StringBuilder builder = new StringBuilder("install");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(name);
-        builder.append(' ');
-        builder.append(uid);
-        builder.append(' ');
-        builder.append(gid);
-        builder.append(' ');
-        builder.append(seinfo != null ? seinfo : "!");
-        return mInstaller.execute(builder.toString());
+    public void clearAppData(String uuid, String pkgname, int userid, int flags)
+            throws InstallerException {
+        mInstaller.execute("clear_app_data", uuid, pkgname, userid, flags);
     }
 
-    public int dexopt(String apkPath, int uid, String instructionSet,
-            int dexoptNeeded, int dexFlags) {
-        if (!isValidInstructionSet(instructionSet)) {
-            Slog.e(TAG, "Invalid instruction set: " + instructionSet);
-            return -1;
-        }
-
-        return mInstaller.dexopt(apkPath, uid, instructionSet, dexoptNeeded, dexFlags);
+    public void destroyAppData(String uuid, String pkgname, int userid, int flags)
+            throws InstallerException {
+        mInstaller.execute("destroy_app_data", uuid, pkgname, userid, flags);
     }
 
-    public int dexopt(String apkPath, int uid, String pkgName, String instructionSet,
-            int dexoptNeeded, @Nullable String outputPath, int dexFlags) {
-        if (!isValidInstructionSet(instructionSet)) {
-            Slog.e(TAG, "Invalid instruction set: " + instructionSet);
-            return -1;
-        }
-        return mInstaller.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded,
-                outputPath, dexFlags);
+    public void moveCompleteApp(String from_uuid, String to_uuid, String package_name,
+            String data_app_name, int appid, String seinfo, int targetSdkVersion)
+            throws InstallerException {
+        mInstaller.execute("move_complete_app", from_uuid, to_uuid, package_name,
+                data_app_name, appid, seinfo, targetSdkVersion);
     }
 
-    public int idmap(String targetApkPath, String overlayApkPath, int uid) {
-        StringBuilder builder = new StringBuilder("idmap");
-        builder.append(' ');
-        builder.append(targetApkPath);
-        builder.append(' ');
-        builder.append(overlayApkPath);
-        builder.append(' ');
-        builder.append(uid);
-        return mInstaller.execute(builder.toString());
-    }
-
-    public int movedex(String srcPath, String dstPath, String instructionSet) {
-        if (!isValidInstructionSet(instructionSet)) {
-            Slog.e(TAG, "Invalid instruction set: " + instructionSet);
-            return -1;
-        }
-
-        StringBuilder builder = new StringBuilder("movedex");
-        builder.append(' ');
-        builder.append(srcPath);
-        builder.append(' ');
-        builder.append(dstPath);
-        builder.append(' ');
-        builder.append(instructionSet);
-        return mInstaller.execute(builder.toString());
-    }
-
-    public int rmdex(String codePath, String instructionSet) {
-        if (!isValidInstructionSet(instructionSet)) {
-            Slog.e(TAG, "Invalid instruction set: " + instructionSet);
-            return -1;
-        }
-
-        StringBuilder builder = new StringBuilder("rmdex");
-        builder.append(' ');
-        builder.append(codePath);
-        builder.append(' ');
-        builder.append(instructionSet);
-        return mInstaller.execute(builder.toString());
-    }
-
-    /**
-     * Removes packageDir or its subdirectory
-     */
-    public int rmPackageDir(String packageDir) {
-        StringBuilder builder = new StringBuilder("rmpackagedir");
-        builder.append(' ');
-        builder.append(packageDir);
-        return mInstaller.execute(builder.toString());
-    }
-
-    @Deprecated
-    public int remove(String name, int userId) {
-        return remove(null, name, userId);
-    }
-
-    public int remove(String uuid, String name, int userId) {
-        StringBuilder builder = new StringBuilder("remove");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(name);
-        builder.append(' ');
-        builder.append(userId);
-        return mInstaller.execute(builder.toString());
-    }
-
-    @Deprecated
-    public int fixUid(String name, int uid, int gid) {
-        return fixUid(null, name, uid, gid);
-    }
-
-    public int fixUid(String uuid, String name, int uid, int gid) {
-        StringBuilder builder = new StringBuilder("fixuid");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(name);
-        builder.append(' ');
-        builder.append(uid);
-        builder.append(' ');
-        builder.append(gid);
-        return mInstaller.execute(builder.toString());
-    }
-
-    @Deprecated
-    public int deleteCacheFiles(String name, int userId) {
-        return deleteCacheFiles(null, name, userId);
-    }
-
-    public int deleteCacheFiles(String uuid, String name, int userId) {
-        StringBuilder builder = new StringBuilder("rmcache");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(name);
-        builder.append(' ');
-        builder.append(userId);
-        return mInstaller.execute(builder.toString());
-    }
-
-    @Deprecated
-    public int deleteCodeCacheFiles(String name, int userId) {
-        return deleteCodeCacheFiles(null, name, userId);
-    }
-
-    public int deleteCodeCacheFiles(String uuid, String name, int userId) {
-        StringBuilder builder = new StringBuilder("rmcodecache");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(name);
-        builder.append(' ');
-        builder.append(userId);
-        return mInstaller.execute(builder.toString());
-    }
-
-    @Deprecated
-    public int createUserData(String name, int uid, int userId, String seinfo) {
-        return createUserData(null, name, uid, userId, seinfo);
-    }
-
-    public int createUserData(String uuid, String name, int uid, int userId, String seinfo) {
-        StringBuilder builder = new StringBuilder("mkuserdata");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(name);
-        builder.append(' ');
-        builder.append(uid);
-        builder.append(' ');
-        builder.append(userId);
-        builder.append(' ');
-        builder.append(seinfo != null ? seinfo : "!");
-        return mInstaller.execute(builder.toString());
-    }
-
-    public int createUserConfig(int userId) {
-        StringBuilder builder = new StringBuilder("mkuserconfig");
-        builder.append(' ');
-        builder.append(userId);
-        return mInstaller.execute(builder.toString());
-    }
-
-    @Deprecated
-    public int removeUserDataDirs(int userId) {
-        return removeUserDataDirs(null, userId);
-    }
-
-    public int removeUserDataDirs(String uuid, int userId) {
-        StringBuilder builder = new StringBuilder("rmuser");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(userId);
-        return mInstaller.execute(builder.toString());
-    }
-
-    public int copyCompleteApp(String fromUuid, String toUuid, String packageName,
-            String dataAppName, int appId, String seinfo) {
-        StringBuilder builder = new StringBuilder("cpcompleteapp");
-        builder.append(' ');
-        builder.append(escapeNull(fromUuid));
-        builder.append(' ');
-        builder.append(escapeNull(toUuid));
-        builder.append(' ');
-        builder.append(packageName);
-        builder.append(' ');
-        builder.append(dataAppName);
-        builder.append(' ');
-        builder.append(appId);
-        builder.append(' ');
-        builder.append(seinfo);
-        return mInstaller.execute(builder.toString());
-    }
-
-    @Deprecated
-    public int clearUserData(String name, int userId) {
-        return clearUserData(null, name, userId);
-    }
-
-    public int clearUserData(String uuid, String name, int userId) {
-        StringBuilder builder = new StringBuilder("rmuserdata");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(name);
-        builder.append(' ');
-        builder.append(userId);
-        return mInstaller.execute(builder.toString());
-    }
-
-    public int markBootComplete(String instructionSet) {
-        if (!isValidInstructionSet(instructionSet)) {
-            Slog.e(TAG, "Invalid instruction set: " + instructionSet);
-            return -1;
-        }
-
-        StringBuilder builder = new StringBuilder("markbootcomplete");
-        builder.append(' ');
-        builder.append(instructionSet);
-        return mInstaller.execute(builder.toString());
-    }
-
-    @Deprecated
-    public int freeCache(long freeStorageSize) {
-        return freeCache(null, freeStorageSize);
-    }
-
-    public int freeCache(String uuid, long freeStorageSize) {
-        StringBuilder builder = new StringBuilder("freecache");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(String.valueOf(freeStorageSize));
-        return mInstaller.execute(builder.toString());
-    }
-
-    @Deprecated
-    public int getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath,
-            String fwdLockApkPath, String asecPath, String[] instructionSets, PackageStats pStats) {
-        return getSizeInfo(null, pkgName, persona, apkPath, libDirPath, fwdLockApkPath, asecPath,
-                instructionSets, pStats);
-    }
-
-    public int getSizeInfo(String uuid, String pkgName, int persona, String apkPath,
+    public void getAppSize(String uuid, String pkgname, int userid, int flags, String apkPath,
             String libDirPath, String fwdLockApkPath, String asecPath, String[] instructionSets,
-            PackageStats pStats) {
+            PackageStats pStats) throws InstallerException {
         for (String instructionSet : instructionSets) {
-            if (!isValidInstructionSet(instructionSet)) {
-                Slog.e(TAG, "Invalid instruction set: " + instructionSet);
-                return -1;
-            }
+            assertValidInstructionSet(instructionSet);
         }
 
-        StringBuilder builder = new StringBuilder("getsize");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(pkgName);
-        builder.append(' ');
-        builder.append(persona);
-        builder.append(' ');
-        builder.append(apkPath);
-        builder.append(' ');
         // TODO: Extend getSizeInfo to look at the full subdirectory tree,
         // not just the first level.
-        builder.append(libDirPath != null ? libDirPath : "!");
-        builder.append(' ');
-        builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!");
-        builder.append(' ');
-        builder.append(asecPath != null ? asecPath : "!");
-        builder.append(' ');
         // TODO: Extend getSizeInfo to look at *all* instrution sets, not
         // just the primary.
-        builder.append(instructionSets[0]);
-
-        String s = mInstaller.transact(builder.toString());
-        String res[] = s.split(" ");
+        final String rawRes = mInstaller.executeForResult("get_app_size", uuid, pkgname, userid,
+                flags, apkPath, libDirPath, fwdLockApkPath, asecPath, instructionSets[0]);
+        final String res[] = rawRes.split(" ");
 
         if ((res == null) || (res.length != 5)) {
-            return -1;
+            throw new InstallerException("Invalid size result: " + rawRes);
         }
         try {
             pStats.codeSize = Long.parseLong(res[1]);
             pStats.dataSize = Long.parseLong(res[2]);
             pStats.cacheSize = Long.parseLong(res[3]);
             pStats.externalCodeSize = Long.parseLong(res[4]);
-            return Integer.parseInt(res[0]);
         } catch (NumberFormatException e) {
-            return -1;
+            throw new InstallerException("Invalid size result: " + rawRes);
         }
     }
 
-    public int moveFiles() {
-        return mInstaller.execute("movefiles");
+    public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded,
+            int dexFlags, String volumeUuid, boolean useProfiles) throws InstallerException {
+        assertValidInstructionSet(instructionSet);
+        mInstaller.dexopt(apkPath, uid, instructionSet, dexoptNeeded, dexFlags,
+                volumeUuid, useProfiles);
     }
 
-    @Deprecated
-    public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath32, int userId) {
-        return linkNativeLibraryDirectory(null, dataPath, nativeLibPath32, userId);
+    public void dexopt(String apkPath, int uid, String pkgName, String instructionSet,
+            int dexoptNeeded, @Nullable String outputPath, int dexFlags,
+            String volumeUuid, boolean useProfiles)
+                    throws InstallerException {
+        assertValidInstructionSet(instructionSet);
+        mInstaller.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded,
+                outputPath, dexFlags, volumeUuid, useProfiles);
+    }
+
+    public void idmap(String targetApkPath, String overlayApkPath, int uid)
+            throws InstallerException {
+        mInstaller.execute("idmap", targetApkPath, overlayApkPath, uid);
+    }
+
+    public void rmdex(String codePath, String instructionSet) throws InstallerException {
+        assertValidInstructionSet(instructionSet);
+        mInstaller.execute("rmdex", codePath, instructionSet);
+    }
+
+    public void rmPackageDir(String packageDir) throws InstallerException {
+        mInstaller.execute("rmpackagedir", packageDir);
+    }
+
+    public void createUserConfig(int userid) throws InstallerException {
+        mInstaller.execute("mkuserconfig", userid);
+    }
+
+    public void removeUserDataDirs(String uuid, int userid) throws InstallerException {
+        mInstaller.execute("rmuser", uuid, userid);
+    }
+
+    public void markBootComplete(String instructionSet) throws InstallerException {
+        assertValidInstructionSet(instructionSet);
+        mInstaller.execute("markbootcomplete", instructionSet);
+    }
+
+    public void freeCache(String uuid, long freeStorageSize) throws InstallerException {
+        mInstaller.execute("freecache", uuid, freeStorageSize);
+    }
+
+    public void moveFiles() throws InstallerException {
+        mInstaller.execute("movefiles");
     }
 
     /**
-     * Links the 32 bit native library directory in an application's data directory to the
-     * real location for backward compatibility. Note that no such symlink is created for
-     * 64 bit shared libraries.
-     *
-     * @return -1 on error
+     * Links the 32 bit native library directory in an application's data
+     * directory to the real location for backward compatibility. Note that no
+     * such symlink is created for 64 bit shared libraries.
      */
-    public int linkNativeLibraryDirectory(String uuid, String dataPath, String nativeLibPath32,
-            int userId) {
-        if (dataPath == null) {
-            Slog.e(TAG, "linkNativeLibraryDirectory dataPath is null");
-            return -1;
-        } else if (nativeLibPath32 == null) {
-            Slog.e(TAG, "linkNativeLibraryDirectory nativeLibPath is null");
-            return -1;
-        }
-
-        StringBuilder builder = new StringBuilder("linklib");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(dataPath);
-        builder.append(' ');
-        builder.append(nativeLibPath32);
-        builder.append(' ');
-        builder.append(userId);
-
-        return mInstaller.execute(builder.toString());
+    public void linkNativeLibraryDirectory(String uuid, String dataPath, String nativeLibPath32,
+            int userId) throws InstallerException {
+        mInstaller.execute("linklib", uuid, dataPath, nativeLibPath32, userId);
     }
 
-    @Deprecated
-    public boolean restoreconData(String pkgName, String seinfo, int uid) {
-        return restoreconData(null, pkgName, seinfo, uid);
+    public void createOatDir(String oatDir, String dexInstructionSet)
+            throws InstallerException {
+        mInstaller.execute("createoatdir", oatDir, dexInstructionSet);
     }
 
-    public boolean restoreconData(String uuid, String pkgName, String seinfo, int uid) {
-        StringBuilder builder = new StringBuilder("restorecondata");
-        builder.append(' ');
-        builder.append(escapeNull(uuid));
-        builder.append(' ');
-        builder.append(pkgName);
-        builder.append(' ');
-        builder.append(seinfo != null ? seinfo : "!");
-        builder.append(' ');
-        builder.append(uid);
-        return (mInstaller.execute(builder.toString()) == 0);
+    public void linkFile(String relativePath, String fromBase, String toBase)
+            throws InstallerException {
+        mInstaller.execute("linkfile", relativePath, fromBase, toBase);
     }
 
-    public int createOatDir(String oatDir, String dexInstructionSet) {
-        StringBuilder builder = new StringBuilder("createoatdir");
-        builder.append(' ');
-        builder.append(oatDir);
-        builder.append(' ');
-        builder.append(dexInstructionSet);
-        return mInstaller.execute(builder.toString());
-    }
-
-
-    public int linkFile(String relativePath, String fromBase, String toBase) {
-        StringBuilder builder = new StringBuilder("linkfile");
-        builder.append(' ');
-        builder.append(relativePath);
-        builder.append(' ');
-        builder.append(fromBase);
-        builder.append(' ');
-        builder.append(toBase);
-        return mInstaller.execute(builder.toString());
-    }
-
-    /**
-     * Returns true iff. {@code instructionSet} is a valid instruction set.
-     */
-    private static boolean isValidInstructionSet(String instructionSet) {
-        if (instructionSet == null) {
-            return false;
-        }
-
+    private static void assertValidInstructionSet(String instructionSet)
+            throws InstallerException {
         for (String abi : Build.SUPPORTED_ABIS) {
-            if (instructionSet.equals(VMRuntime.getInstructionSet(abi))) {
-                return true;
+            if (VMRuntime.getInstructionSet(abi).equals(instructionSet)) {
+                return;
             }
         }
-
-        return false;
+        throw new InstallerException("Invalid instruction set: " + instructionSet);
     }
 }
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 0796811..d82bb3d 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -21,11 +21,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.ILauncherApps;
 import android.content.pm.IOnAppsChangedListener;
 import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
@@ -45,7 +46,6 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.server.SystemService;
 
-import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -200,7 +200,8 @@
             mainIntent.setPackage(packageName);
             long ident = Binder.clearCallingIdentity();
             try {
-                List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(mainIntent, 0 /* flags */,
+                List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(mainIntent,
+                        PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                         user.getIdentifier());
                 return new ParceledListSlice<>(apps);
             } finally {
@@ -218,7 +219,8 @@
 
             long ident = Binder.clearCallingIdentity();
             try {
-                ResolveInfo app = mPm.resolveActivityAsUser(intent, 0, user.getIdentifier());
+                ResolveInfo app = mPm.resolveActivityAsUser(intent,
+                        PackageManager.MATCH_DEBUG_TRIAGED_MISSING, user.getIdentifier());
                 return app;
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -236,7 +238,8 @@
             long ident = Binder.clearCallingIdentity();
             try {
                 IPackageManager pm = AppGlobals.getPackageManager();
-                PackageInfo info = pm.getPackageInfo(packageName, 0, user.getIdentifier());
+                PackageInfo info = pm.getPackageInfo(packageName,
+                        PackageManager.MATCH_DEBUG_TRIAGED_MISSING, user.getIdentifier());
                 return info != null && info.applicationInfo.enabled;
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -244,6 +247,25 @@
         }
 
         @Override
+        public ApplicationInfo getApplicationInfo(String packageName, int flags, UserHandle user)
+                throws RemoteException {
+            ensureInUserProfiles(user, "Cannot check package for unrelated profile " + user);
+            if (!isUserEnabled(user)) {
+                return null;
+            }
+
+            long ident = Binder.clearCallingIdentity();
+            try {
+                IPackageManager pm = AppGlobals.getPackageManager();
+                ApplicationInfo info = pm.getApplicationInfo(packageName, flags,
+                        user.getIdentifier());
+                return info;
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override
         public boolean isActivityEnabled(ComponentName component, UserHandle user)
                 throws RemoteException {
             ensureInUserProfiles(user, "Cannot check component for unrelated profile " + user);
@@ -254,7 +276,8 @@
             long ident = Binder.clearCallingIdentity();
             try {
                 IPackageManager pm = AppGlobals.getPackageManager();
-                ActivityInfo info = pm.getActivityInfo(component, 0, user.getIdentifier());
+                ActivityInfo info = pm.getActivityInfo(component,
+                        PackageManager.MATCH_DEBUG_TRIAGED_MISSING, user.getIdentifier());
                 return info != null;
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -279,7 +302,8 @@
             long ident = Binder.clearCallingIdentity();
             try {
                 IPackageManager pm = AppGlobals.getPackageManager();
-                ActivityInfo info = pm.getActivityInfo(component, 0, user.getIdentifier());
+                ActivityInfo info = pm.getActivityInfo(component,
+                        PackageManager.MATCH_DEBUG_TRIAGED_MISSING, user.getIdentifier());
                 if (!info.exported) {
                     throw new SecurityException("Cannot launch non-exported components "
                             + component);
@@ -289,7 +313,7 @@
                 // as calling startActivityAsUser ignores the category and just
                 // resolves based on the component if present.
                 List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(launchIntent,
-                        0 /* flags */, user.getIdentifier());
+                        PackageManager.MATCH_DEBUG_TRIAGED_MISSING, user.getIdentifier());
                 final int size = apps.size();
                 for (int i = 0; i < size; ++i) {
                     ActivityInfo activityInfo = apps.get(i).activityInfo;
@@ -463,6 +487,44 @@
                 super.onPackagesUnavailable(packages);
             }
 
+            @Override
+            public void onPackagesSuspended(String[] packages) {
+                UserHandle user = new UserHandle(getChangingUserId());
+                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;
+                    try {
+                        listener.onPackagesSuspended(user, packages);
+                    } catch (RemoteException re) {
+                        Slog.d(TAG, "Callback failed ", re);
+                    }
+                }
+                mListeners.finishBroadcast();
+
+                super.onPackagesSuspended(packages);
+            }
+
+            @Override
+            public void onPackagesUnsuspended(String[] packages) {
+                UserHandle user = new UserHandle(getChangingUserId());
+                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;
+                    try {
+                        listener.onPackagesUnsuspended(user, packages);
+                    } catch (RemoteException re) {
+                        Slog.d(TAG, "Callback failed ", re);
+                    }
+                }
+                mListeners.finishBroadcast();
+
+                super.onPackagesUnsuspended(packages);
+            }
+
         }
 
         class PackageCallbackList<T extends IInterface> extends RemoteCallbackList<T> {
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index d29a623..4d66e10 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -23,10 +23,13 @@
 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;
 
+import com.android.internal.os.InstallerConnection.InstallerException;
+
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -38,7 +41,7 @@
 import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE;
 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_USEJIT;
+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;
 
@@ -66,6 +69,10 @@
         mDexoptWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*dexopt*");
     }
 
+    static boolean canOptimizePackage(PackageParser.Package pkg) {
+        return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0;
+    }
+
     /**
      * Performs dexopt on all code paths and libraries of the specified package for specified
      * instruction sets.
@@ -74,7 +81,7 @@
      * {@link PackageManagerService#mInstallLock}.
      */
     int performDexOpt(PackageParser.Package pkg, String[] instructionSets,
-            boolean inclDependencies) {
+            boolean inclDependencies, boolean useProfiles, boolean extractOnly) {
         ArraySet<String> done;
         if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) {
             done = new ArraySet<String>();
@@ -89,7 +96,8 @@
                 mDexoptWakeLock.acquire();
             }
             try {
-                return performDexOptLI(pkg, instructionSets, done);
+                return performDexOptLI(pkg, instructionSets, done, useProfiles,
+                        extractOnly);
             } finally {
                 if (useLock) {
                     mDexoptWakeLock.release();
@@ -99,7 +107,7 @@
     }
 
     private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
-            ArraySet<String> done) {
+            ArraySet<String> done, boolean useProfiles, boolean extractOnly) {
         final String[] instructionSets = targetInstructionSets != null ?
                 targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
 
@@ -113,7 +121,7 @@
             }
         }
 
-        if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) == 0) {
+        if (!canOptimizePackage(pkg)) {
             return DEX_OPT_SKIPPED;
         }
 
@@ -122,18 +130,15 @@
 
         final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
         boolean performedDexOpt = false;
-        // There are three basic cases here:
-        // 1.) we need to dexopt, either because we are forced or it is needed
-        // 2.) we are deferring a needed dexopt
-        // 3.) we are skipping an unneeded dexopt
         final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
         for (String dexCodeInstructionSet : dexCodeInstructionSets) {
-            if (pkg.mDexOptPerformed.contains(dexCodeInstructionSet)) {
+            if (!useProfiles && pkg.mDexOptPerformed.contains(dexCodeInstructionSet)) {
+                // Skip only if we do not use profiles since they might trigger a recompilation.
                 continue;
             }
 
             for (String path : paths) {
-                final int dexoptNeeded;
+                int dexoptNeeded;
                 try {
                     dexoptNeeded = DexFile.getDexOptNeeded(path, pkg.packageName,
                             dexCodeInstructionSet, /* defer */false);
@@ -142,46 +147,58 @@
                     return DEX_OPT_FAILED;
                 }
 
-                if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
-                    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";
+                if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) {
+                    if (useProfiles) {
+                        // If we do a profile guided compilation then we might recompile the same
+                        // package if more profile information is available.
+                        dexoptNeeded = DexFile.DEX2OAT_NEEDED;
                     } else {
-                        throw new IllegalStateException("Invalid dexopt needed: " + dexoptNeeded);
+                        // No dexopt needed and we don't use profiles. Nothing to do.
+                        continue;
                     }
+                }
+                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);
+                }
 
-                    Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg="
-                            + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
-                            + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable
-                            + " oatDir = " + oatDir);
-                    final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
-                    final int dexFlags =
-                            (!pkg.isForwardLocked() ? DEXOPT_PUBLIC : 0)
-                            | (vmSafeMode ? DEXOPT_SAFEMODE : 0)
-                            | (debuggable ? DEXOPT_DEBUGGABLE : 0)
-                            | DEXOPT_BOOTCOMPLETE;
-                    final int ret = mPackageManagerService.mInstaller.dexopt(path, sharedGid,
-                            pkg.packageName, dexCodeInstructionSet, dexoptNeeded, oatDir, dexFlags);
-
-                    // Dex2oat might fail due to compiler / verifier errors.
-                    if (ret == 0) {
-                        performedDexOpt = true;
-                    }
+                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);
+                final int dexFlags =
+                        (!pkg.isForwardLocked() ? DEXOPT_PUBLIC : 0)
+                        | (vmSafeMode ? DEXOPT_SAFEMODE : 0)
+                        | (debuggable ? DEXOPT_DEBUGGABLE : 0)
+                        | (extractOnly ? DEXOPT_EXTRACTONLY : 0)
+                        | DEXOPT_BOOTCOMPLETE;
+                try {
+                    mPackageManagerService.mInstaller.dexopt(path, sharedGid,
+                            pkg.packageName, dexCodeInstructionSet, dexoptNeeded, oatDir,
+                            dexFlags, pkg.volumeUuid, useProfiles);
+                    performedDexOpt = true;
+                } catch (InstallerException e) {
+                    Slog.w(TAG, "Failed to dexopt", e);
                 }
             }
 
-            // 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.
-            pkg.mDexOptPerformed.add(dexCodeInstructionSet);
+            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.
+                pkg.mDexOptPerformed.add(dexCodeInstructionSet);
+            }
         }
 
         // If we've gotten here, we're sure that no error occurred and that we haven't
@@ -210,8 +227,13 @@
         File codePath = new File(pkg.codePath);
         if (codePath.isDirectory()) {
             File oatDir = getOatDir(codePath);
-            mPackageManagerService.mInstaller.createOatDir(oatDir.getAbsolutePath(),
-                    dexInstructionSet);
+            try {
+                mPackageManagerService.mInstaller.createOatDir(oatDir.getAbsolutePath(),
+                        dexInstructionSet);
+            } catch (InstallerException e) {
+                Slog.w(TAG, "Failed to create oat dir", e);
+                return null;
+            }
             return oatDir.getAbsolutePath();
         }
         return null;
@@ -227,7 +249,10 @@
             PackageParser.Package libPkg = mPackageManagerService.findSharedNonSystemLibrary(
                     libName);
             if (libPkg != null && !done.contains(libName)) {
-                performDexOptLI(libPkg, instructionSets, done);
+                // TODO: Analyze and investigate if we (should) profile libraries.
+                // Currently this will do a full compilation of the library.
+                performDexOptLI(libPkg, instructionSets, done, /*useProfiles*/ false,
+                        /* extractOnly */ false);
             }
         }
     }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 7e4e46b..23a58d0 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -258,11 +258,7 @@
         for (File stage : unclaimedStages) {
             Slog.w(TAG, "Deleting orphan stage " + stage);
             synchronized (mPm.mInstallLock) {
-                if (stage.isDirectory()) {
-                    mPm.mInstaller.rmPackageDir(stage.getAbsolutePath());
-                } else {
-                    stage.delete();
-                }
+                mPm.removeCodePathLI(stage);
             }
         }
     }
@@ -386,8 +382,8 @@
         final int sessionId = readIntAttribute(in, ATTR_SESSION_ID);
         final int userId = readIntAttribute(in, ATTR_USER_ID);
         final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME);
-        final int installerUid = readIntAttribute(in, ATTR_INSTALLER_UID,
-                mPm.getPackageUid(installerPackageName, userId));
+        final int installerUid = readIntAttribute(in, ATTR_INSTALLER_UID, mPm.getPackageUid(
+                installerPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId));
         final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
         final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR);
         final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index fa0aa37..b84ffa3 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -69,6 +69,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.NativeLibraryHelper;
 import com.android.internal.content.PackageHelper;
+import com.android.internal.os.InstallerConnection.InstallerException;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
@@ -482,7 +483,6 @@
             throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
                     "Failed to resolve stage location", e);
         }
-        final boolean quickInstall = (params.installFlags & PackageManager.INSTALL_QUICK) != 0;
 
         // Verify that stage looks sane with respect to existing application.
         // This currently only ensures packageName, versionCode, and certificate
@@ -490,10 +490,7 @@
         validateInstallLocked();
 
         Preconditions.checkNotNull(mPackageName);
-        // TODO: fix b/25118622; don't bypass signature check
-        if (!quickInstall) {
-            Preconditions.checkNotNull(mSignatures);
-        }
+        Preconditions.checkNotNull(mSignatures);
         Preconditions.checkNotNull(mResolvedBaseFile);
 
         if (!mPermissionsAccepted) {
@@ -603,7 +600,6 @@
      * {@link PackageManagerService}.
      */
     private void validateInstallLocked() throws PackageManagerException {
-        final boolean quickInstall = (params.installFlags & PackageManager.INSTALL_QUICK) != 0;
         mPackageName = null;
         mVersionCode = -1;
         mSignatures = null;
@@ -627,9 +623,7 @@
 
             final ApkLite apk;
             try {
-                // TODO: fix b/25118622; always use PARSE_COLLECT_CERTIFICATES
-                final int parseFlags = quickInstall ? 0 : PackageParser.PARSE_COLLECT_CERTIFICATES;
-                apk = PackageParser.parseApkLite(file, parseFlags);
+                apk = PackageParser.parseApkLite(file, PackageParser.PARSE_COLLECT_CERTIFICATES);
             } catch (PackageParserException e) {
                 throw PackageManagerException.from(e);
             }
@@ -750,7 +744,6 @@
     }
 
     private void assertApkConsistent(String tag, ApkLite apk) throws PackageManagerException {
-        final boolean quickInstall = (params.installFlags & PackageManager.INSTALL_QUICK) != 0;
         if (!mPackageName.equals(apk.packageName)) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
                     + apk.packageName + " inconsistent with " + mPackageName);
@@ -760,8 +753,7 @@
                     + " version code " + apk.versionCode + " inconsistent with "
                     + mVersionCode);
         }
-        // TODO: fix b/25118622; don't bypass signature check
-        if (!quickInstall && !Signature.areExactMatch(mSignatures, apk.signatures)) {
+        if (!Signature.areExactMatch(mSignatures, apk.signatures)) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                     tag + " signatures are inconsistent");
         }
@@ -841,9 +833,14 @@
         throw new IOException("File: " + pathStr + " outside base: " + baseStr);
     }
 
-    private void createOatDirs(List<String> instructionSets, File fromDir) {
+    private void createOatDirs(List<String> instructionSets, File fromDir)
+            throws PackageManagerException {
         for (String instructionSet : instructionSets) {
-            mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
+            try {
+                mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
+            } catch (InstallerException e) {
+                throw PackageManagerException.from(e);
+            }
         }
     }
 
@@ -851,13 +848,12 @@
             throws IOException {
         for (File fromFile : fromFiles) {
             final String relativePath = getRelativePath(fromFile, fromDir);
-            final int ret = mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
-                    toDir.getAbsolutePath());
-
-            if (ret < 0) {
-                // installd will log failure details.
+            try {
+                mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
+                        toDir.getAbsolutePath());
+            } catch (InstallerException e) {
                 throw new IOException("failed linkOrCreateDir(" + relativePath + ", "
-                        + fromDir + ", " + toDir + ")");
+                        + fromDir + ", " + toDir + ")", e);
             }
         }
 
@@ -956,7 +952,7 @@
         }
 
         final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
-                UserHandle.USER_SYSTEM);
+                PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
         final int gid = UserHandle.getSharedAppGid(uid);
         if (!PackageHelper.fixSdPermissions(cid, gid, null)) {
             throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
@@ -1050,7 +1046,10 @@
             }
         }
         if (stageDir != null) {
-            mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
+            try {
+                mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
+            } catch (InstallerException ignored) {
+            }
         }
         if (stageCid != null) {
             PackageHelper.destroySdDir(stageCid);
diff --git a/services/core/java/com/android/server/pm/PackageManagerException.java b/services/core/java/com/android/server/pm/PackageManagerException.java
index a41636e..f243e63 100644
--- a/services/core/java/com/android/server/pm/PackageManagerException.java
+++ b/services/core/java/com/android/server/pm/PackageManagerException.java
@@ -16,12 +16,20 @@
 
 package com.android.server.pm;
 
+import android.content.pm.PackageManager;
 import android.content.pm.PackageParser.PackageParserException;
 
+import com.android.internal.os.InstallerConnection.InstallerException;
+
 /** {@hide} */
 public class PackageManagerException extends Exception {
     public final int error;
 
+    public PackageManagerException(String detailMessage) {
+        super(detailMessage);
+        this.error = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+    }
+
     public PackageManagerException(int error, String detailMessage) {
         super(detailMessage);
         this.error = error;
@@ -36,4 +44,10 @@
             throws PackageManagerException {
         throw new PackageManagerException(e.error, e.getMessage(), e.getCause());
     }
+
+    public static PackageManagerException from(InstallerException e)
+            throws PackageManagerException {
+        throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
+                e.getMessage(), e.getCause());
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d64b898..c3f20eb 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -34,6 +34,7 @@
 import static android.content.pm.PackageManager.INSTALL_EXTERNAL;
 import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
 import static android.content.pm.PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER;
+import static android.content.pm.PackageManager.INSTALL_FAILED_DEXOPT;
 import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
 import static android.content.pm.PackageManager.INSTALL_FAILED_EPHEMERAL_INVALID;
@@ -46,7 +47,6 @@
 import static android.content.pm.PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_TEST_ONLY;
-import static android.content.pm.PackageManager.INSTALL_FAILED_UID_CHANGED;
 import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_USER_RESTRICTED;
 import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
@@ -54,11 +54,16 @@
 import static android.content.pm.PackageManager.INSTALL_INTERNAL;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
 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_DISABLED_COMPONENTS;
+import static android.content.pm.PackageManager.MATCH_ENCRYPTION_AWARE_AND_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.MOVE_FAILED_DOESNT_EXIST;
 import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR;
 import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING;
@@ -71,6 +76,7 @@
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 import static android.system.OsConstants.O_CREAT;
 import static android.system.OsConstants.O_RDWR;
+
 import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
 import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
 import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
@@ -87,6 +93,8 @@
 import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
 
 import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
@@ -105,8 +113,10 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.AppsQueryHelper;
-import android.content.pm.EphemeralResolveInfo;
+import android.content.pm.ComponentInfo;
 import android.content.pm.EphemeralApplicationInfo;
+import android.content.pm.EphemeralResolveInfo;
+import android.content.pm.EphemeralResolveInfo.EphemeralResolveIntentInfo;
 import android.content.pm.FeatureInfo;
 import android.content.pm.IOnPermissionsChangeListener;
 import android.content.pm.IPackageDataObserver;
@@ -120,7 +130,6 @@
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.KeySet;
-import android.content.pm.ManifestDigest;
 import android.content.pm.PackageCleanItem;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInfoLite;
@@ -145,15 +154,14 @@
 import android.content.pm.VerificationParams;
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.pm.VerifierInfo;
-import android.content.pm.EphemeralResolveInfo.EphemeralResolveIntentInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.hardware.display.DisplayManager;
 import android.net.Uri;
-import android.os.Debug;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.Debug;
 import android.os.Environment;
 import android.os.Environment.UserEnvironment;
 import android.os.FileUtils;
@@ -184,7 +192,6 @@
 import android.security.SystemKeyStore;
 import android.system.ErrnoException;
 import android.system.Os;
-import android.system.StructStat;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
@@ -204,13 +211,6 @@
 import android.util.Xml;
 import android.view.Display;
 
-import com.android.internal.annotations.GuardedBy;
-import dalvik.system.DexFile;
-import dalvik.system.VMRuntime;
-
-import libcore.io.IoUtils;
-import libcore.util.EmptyArray;
-
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IMediaContainerService;
@@ -218,6 +218,7 @@
 import com.android.internal.content.NativeLibraryHelper;
 import com.android.internal.content.PackageHelper;
 import com.android.internal.os.IParcelFileDescriptorFactory;
+import com.android.internal.os.InstallerConnection.InstallerException;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.os.Zygote;
 import com.android.internal.util.ArrayUtils;
@@ -225,6 +226,7 @@
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.XmlUtils;
 import com.android.server.EventLogTags;
 import com.android.server.FgThread;
 import com.android.server.IntentResolver;
@@ -232,11 +234,18 @@
 import com.android.server.ServiceThread;
 import com.android.server.SystemConfig;
 import com.android.server.Watchdog;
+import com.android.server.pm.Installer.StorageFlags;
 import com.android.server.pm.PermissionsState.PermissionState;
 import com.android.server.pm.Settings.DatabaseVersion;
 import com.android.server.pm.Settings.VersionInfo;
 import com.android.server.storage.DeviceStorageMonitorInternal;
 
+import dalvik.system.DexFile;
+import dalvik.system.VMRuntime;
+
+import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -307,9 +316,13 @@
     private static final boolean DEBUG_DEXOPT = false;
     private static final boolean DEBUG_ABI_SELECTION = false;
     private static final boolean DEBUG_EPHEMERAL = false;
+    private static final boolean DEBUG_TRIAGED_MISSING = false;
+    private static final boolean DEBUG_APP_DATA = false;
 
     static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false;
 
+    private static final boolean DISABLE_EPHEMERAL_APPS = true;
+
     private static final int RADIO_UID = Process.PHONE_UID;
     private static final int LOG_UID = Process.LOG_UID;
     private static final int NFC_UID = Process.NFC_UID;
@@ -507,9 +520,6 @@
     // If mac_permissions.xml was found for seinfo labeling.
     boolean mFoundPolicyFile;
 
-    // If a recursive restorecon of /data/data/<pkg> is needed.
-    private boolean mShouldRestoreconData = SELinuxMMAC.shouldRestorecon();
-
     private final EphemeralApplicationRegistry mEphemeralApplicationRegistry;
 
     public static final class SharedLibraryEntry {
@@ -595,7 +605,9 @@
 
     boolean mResolverReplaced = false;
 
-    private final ComponentName mIntentFilterVerifierComponent;
+    private final @Nullable ComponentName mIntentFilterVerifierComponent;
+    private final @Nullable IntentFilterVerifier<ActivityIntentInfo> mIntentFilterVerifier;
+
     private int mIntentFilterVerificationToken = 0;
 
     /** Component that knows whether or not an ephemeral application exists */
@@ -617,6 +629,9 @@
     // 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;
@@ -806,7 +821,7 @@
                         packageName);
             }
             if (DEBUG_DOMAIN_VERIFICATION) {
-                Slog.d(TAG, "Adding verification filter for " + packageName + " : " + filter);
+                Slog.d(TAG, "Adding verification filter for " + packageName + ": " + filter);
             }
             ivs.addFilter(filter);
             return true;
@@ -831,8 +846,6 @@
                         filter.hasDataScheme(IntentFilter.SCHEME_HTTPS));
     }
 
-    private IntentFilterVerifier mIntentFilterVerifier;
-
     // Set of pending broadcasts for aggregating enable/disable of components.
     static class PendingPackageBroadcasts {
         // for each user id, a map of <package name -> components within that package>
@@ -967,8 +980,32 @@
     private static final String TAG_DEFAULT_APPS = "da";
     private static final String TAG_INTENT_FILTER_VERIFICATION = "iv";
 
-    final String mRequiredVerifierPackage;
-    final String mRequiredInstallerPackage;
+    private static final String TAG_PERMISSION_BACKUP = "perm-grant-backup";
+    private static final String TAG_ALL_GRANTS = "rt-grants";
+    private static final String TAG_GRANT = "grant";
+    private static final String ATTR_PACKAGE_NAME = "pkg";
+
+    private static final String TAG_PERMISSION = "perm";
+    private static final String ATTR_PERMISSION_NAME = "name";
+    private static final String ATTR_IS_GRANTED = "g";
+    private static final String ATTR_USER_SET = "set";
+    private static final String ATTR_USER_FIXED = "fixed";
+    private static final String ATTR_REVOKE_ON_UPGRADE = "rou";
+
+    // System/policy permission grants are not backed up
+    private static final int SYSTEM_RUNTIME_GRANT_MASK =
+            FLAG_PERMISSION_POLICY_FIXED
+            | FLAG_PERMISSION_SYSTEM_FIXED
+            | FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+
+    // And we back up these user-adjusted states
+    private static final int USER_RUNTIME_GRANT_MASK =
+            FLAG_PERMISSION_USER_SET
+            | FLAG_PERMISSION_USER_FIXED
+            | FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+
+    final @Nullable String mRequiredVerifierPackage;
+    final @Nullable String mRequiredInstallerPackage;
 
     private final PackageUsage mPackageUsage = new PackageUsage();
 
@@ -1479,16 +1516,25 @@
                                 deleteOld = true;
                             }
 
-                            // If this app is a browser and it's newly-installed for some
-                            // users, clear any default-browser state in those users
+
+                            // Work that needs to happen on first install within each user
                             if (firstUsers.length > 0) {
-                                // the app's nature doesn't depend on the user, so we can just
-                                // check its browser nature in any user and generalize.
-                                if (packageIsBrowser(packageName, firstUsers[0])) {
+                                for (int userId : firstUsers) {
                                     synchronized (mPackages) {
-                                        for (int userId : firstUsers) {
-                                            mSettings.setDefaultBrowserPackageNameLPw(null, userId);
+                                        // If this app is a browser and it's newly-installed for
+                                        // some users, clear any default-browser state in those
+                                        // users.  The app's nature doesn't depend on the user,
+                                        // so we can just check its browser nature in any user
+                                        // and generalize.
+                                        if (packageIsBrowser(packageName, firstUsers[0])) {
+                                            mSettings.setDefaultBrowserPackageNameLPw(
+                                                    null, userId);
                                         }
+
+                                        // We may also need to apply pending (restored) runtime
+                                        // permission grants within these users.
+                                        mSettings.applyPendingPermissionGrantsLPw(
+                                                packageName, userId);
                                     }
                                 }
                             }
@@ -1739,7 +1785,7 @@
         @Override
         public void onVolumeForgotten(String fsUuid) {
             if (TextUtils.isEmpty(fsUuid)) {
-                Slog.w(TAG, "Forgetting internal storage is probably a mistake; ignoring");
+                Slog.e(TAG, "Forgetting internal storage is probably a mistake; ignoring");
                 return;
             }
 
@@ -1845,12 +1891,12 @@
             boolean factoryTest, boolean onlyCore) {
         PackageManagerService m = new PackageManagerService(context, installer,
                 factoryTest, onlyCore);
-        m.enableSystemUserApps();
+        m.enableSystemUserPackages();
         ServiceManager.addService("package", m);
         return m;
     }
 
-    private void enableSystemUserApps() {
+    private void enableSystemUserPackages() {
         if (!UserManager.isSplitSystemUser()) {
             return;
         }
@@ -1867,48 +1913,32 @@
                 | AppsQueryHelper.GET_IMES, /* systemAppsOnly */ true, UserHandle.SYSTEM));
         ArraySet<String> wlApps = SystemConfig.getInstance().getSystemUserWhitelistedApps();
         enableApps.addAll(wlApps);
+        enableApps.addAll(queryHelper.queryApps(AppsQueryHelper.GET_REQUIRED_FOR_SYSTEM_USER,
+                /* systemAppsOnly */ false, UserHandle.SYSTEM));
         ArraySet<String> blApps = SystemConfig.getInstance().getSystemUserBlacklistedApps();
         enableApps.removeAll(blApps);
-
-        List<String> systemApps = queryHelper.queryApps(0, /* systemAppsOnly */ true,
+        Log.i(TAG, "Applications installed for system user: " + enableApps);
+        List<String> allAps = queryHelper.queryApps(0, /* systemAppsOnly */ false,
                 UserHandle.SYSTEM);
-        final int systemAppsSize = systemApps.size();
+        final int allAppsSize = allAps.size();
         synchronized (mPackages) {
-            for (int i = 0; i < systemAppsSize; i++) {
-                String pName = systemApps.get(i);
+            for (int i = 0; i < allAppsSize; i++) {
+                String pName = allAps.get(i);
                 PackageSetting pkgSetting = mSettings.mPackages.get(pName);
                 // Should not happen, but we shouldn't be failing if it does
                 if (pkgSetting == null) {
                     continue;
                 }
-                boolean installed = enableApps.contains(pName);
-                pkgSetting.setInstalled(installed, UserHandle.USER_SYSTEM);
+                boolean install = enableApps.contains(pName);
+                if (pkgSetting.getInstalled(UserHandle.USER_SYSTEM) != install) {
+                    Log.i(TAG, (install ? "Installing " : "Uninstalling ") + pName
+                            + " for system user");
+                    pkgSetting.setInstalled(install, UserHandle.USER_SYSTEM);
+                }
             }
         }
     }
 
-    static String[] splitString(String str, char sep) {
-        int count = 1;
-        int i = 0;
-        while ((i=str.indexOf(sep, i)) >= 0) {
-            count++;
-            i++;
-        }
-
-        String[] res = new String[count];
-        i=0;
-        count = 0;
-        int lastI=0;
-        while ((i=str.indexOf(sep, i)) >= 0) {
-            res[count] = str.substring(lastI, i);
-            count++;
-            i++;
-            lastI = i;
-        }
-        res[count] = str.substring(lastI, str.length());
-        return res;
-    }
-
     private static void getDefaultDisplayMetrics(Context context, DisplayMetrics metrics) {
         DisplayManager displayManager = (DisplayManager) context.getSystemService(
                 Context.DISPLAY_SERVICE);
@@ -2068,12 +2098,16 @@
                         try {
                             int dexoptNeeded = DexFile.getDexOptNeeded(lib, null, dexCodeInstructionSet, false);
                             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*/);
+                                        dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/,
+                                        StorageManager.UUID_PRIVATE_INTERNAL,
+                                        false /*useProfiles*/);
                             }
                         } catch (FileNotFoundException e) {
                             Slog.w(TAG, "Library not found: " + lib);
-                        } catch (IOException e) {
+                        } catch (IOException | InstallerException e) {
                             Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "
                                     + e.getMessage());
                         }
@@ -2142,7 +2176,11 @@
                     | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
 
             if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
-            mInstaller.moveFiles();
+            try {
+                mInstaller.moveFiles();
+            } catch (InstallerException e) {
+                logCriticalInfo(Log.WARN, "Update commands failed: " + e);
+            }
 
             // Prune any system packages that no longer exist.
             final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();
@@ -2343,6 +2381,17 @@
                 }
             }
 
+            // Prepare storage for system user really early during boot,
+            // since core system apps like SettingsProvider and SystemUI
+            // can't wait for user to start
+            final int flags;
+            if (StorageManager.isFileBasedEncryptionEnabled()) {
+                flags = Installer.FLAG_DE_STORAGE;
+            } else {
+                flags = Installer.FLAG_DE_STORAGE | Installer.FLAG_CE_STORAGE;
+            }
+            reconcileAppsData(StorageManager.UUID_PRIVATE_INTERNAL, UserHandle.USER_SYSTEM, flags);
+
             // If this is first boot after an OTA, and a normal boot, then
             // we need to clear code cache directories.
             if (mIsUpgrade && !onlyCore) {
@@ -2371,15 +2420,21 @@
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
                     SystemClock.uptimeMillis());
 
-            mRequiredVerifierPackage = getRequiredVerifierLPr();
-            mRequiredInstallerPackage = getRequiredInstallerLPr();
+            if (!mOnlyCore) {
+                mRequiredVerifierPackage = getRequiredButNotReallyRequiredVerifierLPr();
+                mRequiredInstallerPackage = getRequiredInstallerLPr();
+                mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();
+                mIntentFilterVerifier = new IntentVerifierProxy(mContext,
+                        mIntentFilterVerifierComponent);
+            } else {
+                mRequiredVerifierPackage = null;
+                mRequiredInstallerPackage = null;
+                mIntentFilterVerifierComponent = null;
+                mIntentFilterVerifier = null;
+            }
 
             mInstallerService = new PackageInstallerService(context, this);
 
-            mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();
-            mIntentFilterVerifier = new IntentVerifierProxy(mContext,
-                    mIntentFilterVerifierComponent);
-
             final ComponentName ephemeralResolverComponent = getEphemeralResolverLPr();
             final ComponentName ephemeralInstallerComponent = getEphemeralInstallerLPr();
             // both the installer and resolver must be present to enable ephemeral
@@ -2441,113 +2496,61 @@
         return mIsUpgrade;
     }
 
-    private String getRequiredVerifierLPr() {
-        final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
-        // We only care about verifier that's installed under system user.
-        final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE,
-                PackageManager.GET_DISABLED_COMPONENTS, UserHandle.USER_SYSTEM);
+    private @Nullable String getRequiredButNotReallyRequiredVerifierLPr() {
+        final Intent intent = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
 
-        String requiredVerifier = null;
-
-        final int N = receivers.size();
-        for (int i = 0; i < N; i++) {
-            final ResolveInfo info = receivers.get(i);
-
-            if (info.activityInfo == null) {
-                continue;
-            }
-
-            final String packageName = info.activityInfo.packageName;
-
-            if (checkPermission(android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
-                    packageName, UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) {
-                continue;
-            }
-
-            if (requiredVerifier != null) {
-                throw new RuntimeException("There can be only one required verifier");
-            }
-
-            requiredVerifier = packageName;
+        final List<ResolveInfo> matches = queryIntentReceivers(intent, PACKAGE_MIME_TYPE,
+                MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
+        if (matches.size() == 1) {
+            return matches.get(0).getComponentInfo().packageName;
+        } else {
+            Log.e(TAG, "There should probably be exactly one verifier; found " + matches);
+            return null;
         }
-
-        return requiredVerifier;
     }
 
-    private String getRequiredInstallerLPr() {
-        Intent installerIntent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
-        installerIntent.addCategory(Intent.CATEGORY_DEFAULT);
-        installerIntent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
+    private @NonNull String getRequiredInstallerLPr() {
+        final Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
+        intent.addCategory(Intent.CATEGORY_DEFAULT);
+        intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
 
-        final List<ResolveInfo> installers = queryIntentActivities(installerIntent,
-                PACKAGE_MIME_TYPE, 0, UserHandle.USER_SYSTEM);
-
-        String requiredInstaller = null;
-
-        final int N = installers.size();
-        for (int i = 0; i < N; i++) {
-            final ResolveInfo info = installers.get(i);
-            final String packageName = info.activityInfo.packageName;
-
-            if (!info.activityInfo.applicationInfo.isSystemApp()) {
-                continue;
-            }
-
-            if (requiredInstaller != null) {
-                throw new RuntimeException("There must be one required installer");
-            }
-
-            requiredInstaller = packageName;
+        final List<ResolveInfo> matches = queryIntentActivities(intent, PACKAGE_MIME_TYPE,
+                MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
+        if (matches.size() == 1) {
+            return matches.get(0).getComponentInfo().packageName;
+        } else {
+            throw new RuntimeException("There must be exactly one installer; found " + matches);
         }
-
-        if (requiredInstaller == null) {
-            throw new RuntimeException("There must be one required installer");
-        }
-
-        return requiredInstaller;
     }
 
-    private ComponentName getIntentFilterVerifierComponentNameLPr() {
-        final Intent verification = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION);
-        final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE,
-                PackageManager.GET_DISABLED_COMPONENTS, UserHandle.USER_SYSTEM);
+    private @NonNull ComponentName getIntentFilterVerifierComponentNameLPr() {
+        final Intent intent = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION);
 
-        ComponentName verifierComponentName = null;
-
-        int priority = -1000;
-        final int N = receivers.size();
+        final List<ResolveInfo> matches = queryIntentReceivers(intent, PACKAGE_MIME_TYPE,
+                MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
+        ResolveInfo best = null;
+        final int N = matches.size();
         for (int i = 0; i < N; i++) {
-            final ResolveInfo info = receivers.get(i);
-
-            if (info.activityInfo == null) {
-                continue;
-            }
-
-            final String packageName = info.activityInfo.packageName;
-
-            final PackageSetting ps = mSettings.mPackages.get(packageName);
-            if (ps == null) {
-                continue;
-            }
-
+            final ResolveInfo cur = matches.get(i);
+            final String packageName = cur.getComponentInfo().packageName;
             if (checkPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT,
                     packageName, UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) {
                 continue;
             }
 
-            // Select the IntentFilterVerifier with the highest priority
-            if (priority < info.priority) {
-                priority = info.priority;
-                verifierComponentName = new ComponentName(packageName, info.activityInfo.name);
-                if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Selecting IntentFilterVerifier: "
-                        + verifierComponentName + " with priority: " + info.priority);
+            if (best == null || cur.priority > best.priority) {
+                best = cur;
             }
         }
 
-        return verifierComponentName;
+        if (best != null) {
+            return best.getComponentInfo().getComponentName();
+        } else {
+            throw new RuntimeException("There must be at least one intent filter verifier");
+        }
     }
 
-    private ComponentName getEphemeralResolverLPr() {
+    private @Nullable ComponentName getEphemeralResolverLPr() {
         final String[] packageArray =
                 mContext.getResources().getStringArray(R.array.config_ephemeralResolverPackage);
         if (packageArray.length == 0) {
@@ -2557,9 +2560,9 @@
             return null;
         }
 
-        Intent resolverIntent = new Intent(Intent.ACTION_RESOLVE_EPHEMERAL_PACKAGE);
-        final List<ResolveInfo> resolvers = queryIntentServices(resolverIntent,
-                null /*resolvedType*/, 0 /*flags*/, UserHandle.USER_SYSTEM);
+        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 int N = resolvers.size();
         if (N == 0) {
@@ -2598,36 +2601,21 @@
         return null;
     }
 
-    private ComponentName getEphemeralInstallerLPr() {
-        Intent installerIntent = new Intent(Intent.ACTION_INSTALL_EPHEMERAL_PACKAGE);
-        installerIntent.addCategory(Intent.CATEGORY_DEFAULT);
-        installerIntent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
-        final List<ResolveInfo> installers = queryIntentActivities(installerIntent,
-                PACKAGE_MIME_TYPE, 0 /*flags*/, 0 /*userId*/);
+    private @Nullable ComponentName getEphemeralInstallerLPr() {
+        final Intent intent = new Intent(Intent.ACTION_INSTALL_EPHEMERAL_PACKAGE);
+        intent.addCategory(Intent.CATEGORY_DEFAULT);
+        intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
 
-        ComponentName ephemeralInstaller = null;
-
-        final int N = installers.size();
-        for (int i = 0; i < N; i++) {
-            final ResolveInfo info = installers.get(i);
-            final String packageName = info.activityInfo.packageName;
-
-            if (!info.activityInfo.applicationInfo.isSystemApp()) {
-                if (DEBUG_EPHEMERAL) {
-                    Slog.d(TAG, "Ephemeral installer is not system app;"
-                            + " pkg: " + packageName + ", info:" + info);
-                }
-                continue;
-            }
-
-            if (ephemeralInstaller != null) {
-                throw new RuntimeException("There must only be one ephemeral installer");
-            }
-
-            ephemeralInstaller = new ComponentName(packageName, info.activityInfo.name);
+        final List<ResolveInfo> matches = queryIntentActivities(intent, PACKAGE_MIME_TYPE,
+                MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
+        if (matches.size() == 0) {
+            return null;
+        } else if (matches.size() == 1) {
+            return matches.get(0).getComponentInfo().getComponentName();
+        } else {
+            throw new RuntimeException(
+                    "There must be at most one ephemeral installer; found " + matches);
         }
-
-        return ephemeralInstaller;
     }
 
     private void primeDomainVerificationsLPw(int userId) {
@@ -2674,7 +2662,7 @@
                             + "' does not handle web links");
                 }
             } else {
-                Slog.w(TAG, "Unknown package '" + packageName + "' in sysconfig <app-link>");
+                Slog.w(TAG, "Unknown package " + packageName + " in sysconfig <app-link>");
             }
         }
 
@@ -2777,11 +2765,7 @@
 
         removeDataDirsLI(ps.volumeUuid, ps.name);
         if (ps.codePath != null) {
-            if (ps.codePath.isDirectory()) {
-                mInstaller.rmPackageDir(ps.codePath.getAbsolutePath());
-            } else {
-                ps.codePath.delete();
-            }
+            removeCodePathLI(ps.codePath);
         }
         if (ps.resourcePath != null && !ps.resourcePath.equals(ps.codePath)) {
             if (ps.resourcePath.isDirectory()) {
@@ -2862,6 +2846,7 @@
     @Override
     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");
         // reader
         synchronized (mPackages) {
@@ -2871,7 +2856,7 @@
             if (p != null) {
                 return generatePackageInfo(p, flags, userId);
             }
-            if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
+            if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
                 return generatePackageInfoFromSettingsLPw(packageName, flags, userId);
             }
         }
@@ -2905,24 +2890,20 @@
     }
 
     @Override
-    public int getPackageUid(String packageName, int userId) {
-        return getPackageUidEtc(packageName, 0, userId);
-    }
-
-    @Override
-    public int getPackageUidEtc(String packageName, int flags, int userId) {
+    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");
 
         // reader
         synchronized (mPackages) {
             final PackageParser.Package p = mPackages.get(packageName);
-            if (p != null) {
+            if (p != null && p.isMatch(flags)) {
                 return UserHandle.getUid(userId, p.applicationInfo.uid);
             }
-            if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
+            if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
                 final PackageSetting ps = mSettings.mPackages.get(packageName);
-                if (ps != null) {
+                if (ps != null && ps.isMatch(flags)) {
                     return UserHandle.getUid(userId, ps.appId);
                 }
             }
@@ -2932,29 +2913,22 @@
     }
 
     @Override
-    public int[] getPackageGids(String packageName, int userId) {
-        return getPackageGidsEtc(packageName, 0, userId);
-    }
-
-    @Override
-    public int[] getPackageGidsEtc(String packageName, int flags, int userId) {
-        if (!sUserManager.exists(userId)) {
-            return null;
-        }
-
+    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,
                 "getPackageGids");
 
         // reader
         synchronized (mPackages) {
             final PackageParser.Package p = mPackages.get(packageName);
-            if (p != null) {
+            if (p != null && p.isMatch(flags)) {
                 PackageSetting ps = (PackageSetting) p.mExtras;
                 return ps.getPermissionsState().computeGids(userId);
             }
-            if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
+            if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
                 final PackageSetting ps = mSettings.mPackages.get(packageName);
-                if (ps != null) {
+                if (ps != null && ps.isMatch(flags)) {
                     return ps.getPermissionsState().computeGids(userId);
                 }
             }
@@ -2963,8 +2937,7 @@
         return null;
     }
 
-    static PermissionInfo generatePermissionInfo(
-            BasePermission bp, int flags) {
+    static PermissionInfo generatePermissionInfo(BasePermission bp, int flags) {
         if (bp.perm != null) {
             return PackageParser.generatePermissionInfo(bp.perm, flags);
         }
@@ -3061,7 +3034,7 @@
         if (ps != null) {
             PackageParser.Package pkg = ps.pkg;
             if (pkg == null) {
-                if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) == 0) {
+                if ((flags & MATCH_UNINSTALLED_PACKAGES) == 0) {
                     return null;
                 }
                 // Only data remains, so we aren't worried about code paths
@@ -3082,6 +3055,7 @@
     @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");
         // writer
         synchronized (mPackages) {
@@ -3099,7 +3073,7 @@
             if ("android".equals(packageName)||"system".equals(packageName)) {
                 return mAndroidApplication;
             }
-            if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
+            if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
                 return generateApplicationInfoFromSettingsLPw(packageName, flags, userId);
             }
         }
@@ -3115,16 +3089,18 @@
         mHandler.post(new Runnable() {
             public void run() {
                 mHandler.removeCallbacks(this);
-                int retCode = -1;
+                boolean success = true;
                 synchronized (mInstallLock) {
-                    retCode = mInstaller.freeCache(volumeUuid, freeStorageSize);
-                    if (retCode < 0) {
-                        Slog.w(TAG, "Couldn't clear application caches");
+                    try {
+                        mInstaller.freeCache(volumeUuid, freeStorageSize);
+                    } catch (InstallerException e) {
+                        Slog.w(TAG, "Couldn't clear application caches: " + e);
+                        success = false;
                     }
                 }
                 if (observer != null) {
                     try {
-                        observer.onRemoveCompleted(null, (retCode >= 0));
+                        observer.onRemoveCompleted(null, success);
                     } catch (RemoteException e) {
                         Slog.w(TAG, "RemoveException when invoking call back");
                     }
@@ -3142,17 +3118,19 @@
         mHandler.post(new Runnable() {
             public void run() {
                 mHandler.removeCallbacks(this);
-                int retCode = -1;
+                boolean success = true;
                 synchronized (mInstallLock) {
-                    retCode = mInstaller.freeCache(volumeUuid, freeStorageSize);
-                    if (retCode < 0) {
-                        Slog.w(TAG, "Couldn't clear application caches");
+                    try {
+                        mInstaller.freeCache(volumeUuid, freeStorageSize);
+                    } catch (InstallerException e) {
+                        Slog.w(TAG, "Couldn't clear application caches: " + e);
+                        success = false;
                     }
                 }
                 if(pi != null) {
                     try {
                         // Callback via pending intent
-                        int code = (retCode >= 0) ? 1 : 0;
+                        int code = success ? 1 : 0;
                         pi.sendIntent(null, code, null,
                                 null, null);
                     } catch (SendIntentException e1) {
@@ -3165,8 +3143,10 @@
 
     void freeStorage(String volumeUuid, long freeStorageSize) throws IOException {
         synchronized (mInstallLock) {
-            if (mInstaller.freeCache(volumeUuid, freeStorageSize) < 0) {
-                throw new IOException("Failed to free enough space");
+            try {
+                mInstaller.freeCache(volumeUuid, freeStorageSize);
+            } catch (InstallerException e) {
+                throw new IOException("Failed to free enough space", e);
             }
         }
     }
@@ -3196,26 +3176,107 @@
     }
 
     /**
-     * Augment the given flags depending on current user running state. This is
-     * purposefully done before acquiring {@link #mPackages} lock.
+     * Update given flags based on encryption status of current user.
      */
-    private int augmentFlagsForUser(int flags, int userId) {
-        if (!isUserKeyUnlocked(userId)) {
-            flags |= PackageManager.MATCH_ENCRYPTION_AWARE_ONLY;
+    private int updateFlags(int flags, int userId) {
+        if ((flags & (PackageManager.MATCH_ENCRYPTION_UNAWARE
+                | PackageManager.MATCH_ENCRYPTION_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;
+            } else {
+                flags |= PackageManager.MATCH_ENCRYPTION_AWARE;
+            }
         }
+
+        // Safe mode means we should ignore any third-party apps
+        if (mSafeMode) {
+            flags |= PackageManager.MATCH_SYSTEM_ONLY;
+        }
+
         return flags;
     }
 
+    /**
+     * Update given flags when being used to request {@link PackageInfo}.
+     */
+    private int updateFlagsForPackage(int flags, int userId, Object cookie) {
+        boolean triaged = true;
+        if ((flags & (PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS
+                | 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
+                    | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
+                triaged = false;
+            }
+        }
+        if ((flags & (PackageManager.MATCH_UNINSTALLED_PACKAGES
+                | PackageManager.MATCH_SYSTEM_ONLY
+                | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
+            triaged = false;
+        }
+        if (DEBUG_TRIAGED_MISSING && (Binder.getCallingUid() == Process.SYSTEM_UID) && !triaged) {
+            Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie
+                    + " with flags 0x" + Integer.toHexString(flags), new Throwable());
+        }
+        return updateFlags(flags, userId);
+    }
+
+    /**
+     * Update given flags when being used to request {@link ApplicationInfo}.
+     */
+    private int updateFlagsForApplication(int flags, int userId, Object cookie) {
+        return updateFlagsForPackage(flags, userId, cookie);
+    }
+
+    /**
+     * Update given flags when being used to request {@link ComponentInfo}.
+     */
+    private int updateFlagsForComponent(int flags, int userId, Object cookie) {
+        if (cookie instanceof Intent) {
+            if ((((Intent) cookie).getFlags() & Intent.FLAG_DEBUG_TRIAGED_MISSING) != 0) {
+                flags |= PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+            }
+        }
+
+        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
+                | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
+            triaged = false;
+        }
+        if (DEBUG_TRIAGED_MISSING && (Binder.getCallingUid() == Process.SYSTEM_UID) && !triaged) {
+            Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie
+                    + " with flags 0x" + Integer.toHexString(flags), new Throwable());
+        }
+        return updateFlags(flags, userId);
+    }
+
+    /**
+     * Update given flags when being used to request {@link ResolveInfo}.
+     */
+    int updateFlagsForResolve(int flags, int userId, Object cookie) {
+        return updateFlagsForComponent(flags, userId, cookie);
+    }
+
     @Override
     public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId);
+        flags = updateFlagsForComponent(flags, userId, component);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get activity info");
         synchronized (mPackages) {
             PackageParser.Activity a = mActivities.mActivities.get(component);
 
             if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);
-            if (a != null && mSettings.isEnabledAndVisibleLPr(a.info, flags, userId)) {
+            if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
                 return PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId),
@@ -3254,13 +3315,13 @@
     @Override
     public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId);
+        flags = updateFlagsForComponent(flags, userId, component);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get receiver info");
         synchronized (mPackages) {
             PackageParser.Activity a = mReceivers.mActivities.get(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
                 TAG, "getReceiverInfo " + component + ": " + a);
-            if (a != null && mSettings.isEnabledAndVisibleLPr(a.info, flags, userId)) {
+            if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
                 return PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId),
@@ -3273,13 +3334,13 @@
     @Override
     public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId);
+        flags = updateFlagsForComponent(flags, userId, component);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get service info");
         synchronized (mPackages) {
             PackageParser.Service s = mServices.mServices.get(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
                 TAG, "getServiceInfo " + component + ": " + s);
-            if (s != null && mSettings.isEnabledAndVisibleLPr(s.info, flags, userId)) {
+            if (s != null && mSettings.isEnabledAndMatchLPr(s.info, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
                 return PackageParser.generateServiceInfo(s, flags, ps.readUserState(userId),
@@ -3292,13 +3353,13 @@
     @Override
     public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId);
+        flags = updateFlagsForComponent(flags, userId, component);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get provider info");
         synchronized (mPackages) {
             PackageParser.Provider p = mProviders.mProviders.get(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
                 TAG, "getProviderInfo " + component + ": " + p);
-            if (p != null && mSettings.isEnabledAndVisibleLPr(p.info, flags, userId)) {
+            if (p != null && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
                 return PackageParser.generateProviderInfo(p, flags, ps.readUserState(userId),
@@ -3457,7 +3518,7 @@
     /**
      * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS
      * or INTERACT_ACROSS_USERS_FULL permissions, if the userid is not for the caller.
-     * @param checkShell TODO(yamasani):
+     * @param checkShell whether to prevent shell from access if there's a debugging restriction
      * @param message the message to log on security exception
      */
     void enforceCrossUserPermission(int callingUid, int userId, boolean requireFullPermission,
@@ -3720,8 +3781,8 @@
 
             final int flags = permissionsState.getPermissionFlags(name, userId);
             if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
-                throw new SecurityException("Cannot grant system fixed permission: "
-                        + name + " for package: " + packageName);
+                throw new SecurityException("Cannot grant system fixed permission "
+                        + name + " for package " + packageName);
             }
 
             if (bp.isDevelopment()) {
@@ -3829,8 +3890,8 @@
 
             final int flags = permissionsState.getPermissionFlags(name, userId);
             if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
-                throw new SecurityException("Cannot revoke system fixed permission: "
-                        + name + " for package: " + packageName);
+                throw new SecurityException("Cannot revoke system fixed permission "
+                        + name + " for package " + packageName);
             }
 
             if (bp.isDevelopment()) {
@@ -4034,7 +4095,7 @@
                     "canShowRequestPermissionRationale for user " + userId);
         }
 
-        final int uid = getPackageUid(packageName, userId);
+        final int uid = getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, userId);
         if (UserHandle.getAppId(getCallingUid()) != UserHandle.getAppId(uid)) {
             return false;
         }
@@ -4417,7 +4478,7 @@
     public ResolveInfo resolveIntent(Intent intent, String resolvedType,
             int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId);
+        flags = updateFlagsForResolve(flags, userId, intent);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "resolve intent");
         List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
         final ResolveInfo bestChoice =
@@ -4473,6 +4534,9 @@
     private boolean isEphemeralAllowed(
             Intent intent, List<ResolveInfo> resolvedActivites, int userId) {
         // Short circuit and return early if possible.
+        if (DISABLE_EPHEMERAL_APPS) {
+            return false;
+        }
         final int callingUser = UserHandle.getCallingUserId();
         if (callingUser != UserHandle.USER_SYSTEM) {
             return false;
@@ -4635,7 +4699,7 @@
                     ppa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "  ");
                 }
                 final ActivityInfo ai = getActivityInfo(ppa.mComponent,
-                        flags | PackageManager.GET_DISABLED_COMPONENTS, userId);
+                        flags | MATCH_DISABLED_COMPONENTS, userId);
                 if (DEBUG_PREFERRED || debug) {
                     Slog.v(TAG, "Found persistent preferred activity:");
                     if (ai != null) {
@@ -4675,7 +4739,7 @@
             List<ResolveInfo> query, int priority, boolean always,
             boolean removeMatches, boolean debug, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId);
+        flags = updateFlagsForResolve(flags, userId, intent);
         // writer
         synchronized (mPackages) {
             if (intent.getSelector() != null) {
@@ -4744,7 +4808,7 @@
                             continue;
                         }
                         final ActivityInfo ai = getActivityInfo(pa.mPref.mComponent,
-                                flags | PackageManager.GET_DISABLED_COMPONENTS, userId);
+                                flags | MATCH_DISABLED_COMPONENTS, userId);
                         if (DEBUG_PREFERRED || debug) {
                             Slog.v(TAG, "Found preferred activity:");
                             if (ai != null) {
@@ -4874,7 +4938,7 @@
     public List<ResolveInfo> queryIntentActivities(Intent intent,
             String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = augmentFlagsForUser(flags, userId);
+        flags = updateFlagsForResolve(flags, userId, intent);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "query intent activities");
         ComponentName comp = intent.getComponent();
         if (comp == null) {
@@ -5358,7 +5422,7 @@
             Intent[] specifics, String[] specificTypes, Intent intent,
             String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = augmentFlagsForUser(flags, userId);
+        flags = updateFlagsForResolve(flags, userId, intent);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false,
                 false, "query intent activity options");
         final String resultsAction = intent.getAction();
@@ -5531,7 +5595,7 @@
     public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags,
             int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = augmentFlagsForUser(flags, userId);
+        flags = updateFlagsForResolve(flags, userId, intent);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -5568,7 +5632,7 @@
     @Override
     public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId);
+        flags = updateFlagsForResolve(flags, userId, intent);
         List<ResolveInfo> query = queryIntentServices(intent, resolvedType, flags, userId);
         if (query != null) {
             if (query.size() >= 1) {
@@ -5584,7 +5648,7 @@
     public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags,
             int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = augmentFlagsForUser(flags, userId);
+        flags = updateFlagsForResolve(flags, userId, intent);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -5622,7 +5686,7 @@
     public List<ResolveInfo> queryIntentContentProviders(
             Intent intent, String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = augmentFlagsForUser(flags, userId);
+        flags = updateFlagsForResolve(flags, userId, intent);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -5658,8 +5722,9 @@
 
     @Override
     public ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) {
-        final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
-
+        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");
 
         // writer
@@ -5738,9 +5803,9 @@
     @Override
     public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
             String[] permissions, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId);
-        final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
+        if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+        flags = updateFlagsForPackage(flags, userId, permissions);
+        final boolean listUninstalled = (flags & MATCH_UNINSTALLED_PACKAGES) != 0;
 
         // writer
         synchronized (mPackages) {
@@ -5766,9 +5831,9 @@
 
     @Override
     public ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId);
-        final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
+        if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+        flags = updateFlagsForApplication(flags, userId, null);
+        final boolean listUninstalled = (flags & MATCH_UNINSTALLED_PACKAGES) != 0;
 
         // writer
         synchronized (mPackages) {
@@ -5806,6 +5871,10 @@
 
     @Override
     public ParceledListSlice<EphemeralApplicationInfo> getEphemeralApplications(int userId) {
+        if (DISABLE_EPHEMERAL_APPS) {
+            return null;
+        }
+
         mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_EPHEMERAL_APPS,
                 "getEphemeralApplications");
         enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
@@ -5824,6 +5893,10 @@
     public boolean isEphemeralApplication(String packageName, int userId) {
         enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
                 "isEphemeral");
+        if (DISABLE_EPHEMERAL_APPS) {
+            return false;
+        }
+
         if (!isCallerSameApp(packageName)) {
             return false;
         }
@@ -5838,6 +5911,10 @@
 
     @Override
     public byte[] getEphemeralApplicationCookie(String packageName, int userId) {
+        if (DISABLE_EPHEMERAL_APPS) {
+            return null;
+        }
+
         enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
                 "getCookie");
         if (!isCallerSameApp(packageName)) {
@@ -5851,6 +5928,10 @@
 
     @Override
     public boolean setEphemeralApplicationCookie(String packageName, byte[] cookie, int userId) {
+        if (DISABLE_EPHEMERAL_APPS) {
+            return true;
+        }
+
         enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
                 "setCookie");
         if (!isCallerSameApp(packageName)) {
@@ -5864,6 +5945,10 @@
 
     @Override
     public Bitmap getEphemeralApplicationIcon(String packageName, int userId) {
+        if (DISABLE_EPHEMERAL_APPS) {
+            return null;
+        }
+
         mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_EPHEMERAL_APPS,
                 "getEphemeralApplicationIcon");
         enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
@@ -5910,7 +5995,7 @@
     @Override
     public ProviderInfo resolveContentProvider(String name, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId);
+        flags = updateFlagsForComponent(flags, userId, name);
         // reader
         synchronized (mPackages) {
             final PackageParser.Provider provider = mProvidersByAuthority.get(name);
@@ -5918,9 +6003,7 @@
                     ? mSettings.mPackages.get(provider.owner.packageName)
                     : null;
             return ps != null
-                    && mSettings.isEnabledAndVisibleLPr(provider.info, flags, userId)
-                    && (!mSafeMode || (provider.info.applicationInfo.flags
-                            &ApplicationInfo.FLAG_SYSTEM) != 0)
+                    && mSettings.isEnabledAndMatchLPr(provider.info, flags, userId)
                     ? PackageParser.generateProviderInfo(provider, flags,
                             ps.readUserState(userId), userId)
                     : null;
@@ -5962,7 +6045,7 @@
         final int userId = processName != null ? UserHandle.getUserId(uid)
                 : UserHandle.getCallingUserId();
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId);
+        flags = updateFlagsForComponent(flags, userId, processName);
 
         ArrayList<ProviderInfo> finalList = null;
         // reader
@@ -5975,9 +6058,7 @@
                         && (processName == null
                                 || (p.info.processName.equals(processName)
                                         && UserHandle.isSameApp(p.info.applicationInfo.uid, uid)))
-                        && mSettings.isEnabledAndVisibleLPr(p.info, flags, userId)
-                        && (!mSafeMode
-                                || (p.info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
+                        && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) {
                     if (finalList == null) {
                         finalList = new ArrayList<ProviderInfo>(3);
                     }
@@ -5999,8 +6080,7 @@
     }
 
     @Override
-    public InstrumentationInfo getInstrumentationInfo(ComponentName name,
-            int flags) {
+    public InstrumentationInfo getInstrumentationInfo(ComponentName name, int flags) {
         // reader
         synchronized (mPackages) {
             final PackageParser.Instrumentation i = mInstrumentation.get(name);
@@ -6063,7 +6143,9 @@
         }
         final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
         // TODO: generate idmap for split APKs
-        if (mInstaller.idmap(pkg.baseCodePath, opkg.baseCodePath, sharedGid) != 0) {
+        try {
+            mInstaller.idmap(pkg.baseCodePath, opkg.baseCodePath, sharedGid);
+        } catch (InstallerException e) {
             Slog.e(TAG, "Failed to generate idmap for " + pkg.baseCodePath + " and "
                     + opkg.baseCodePath);
             return false;
@@ -6123,11 +6205,7 @@
                 if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
                         e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
                     logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
-                    if (file.isDirectory()) {
-                        mInstaller.rmPackageDir(file.getAbsolutePath());
-                    } else {
-                        file.delete();
-                    }
+                    removeCodePathLI(file);
                 }
             }
         }
@@ -6195,7 +6273,6 @@
 
         try {
             pp.collectCertificates(pkg, parseFlags);
-            pp.collectManifestDigest(pkg);
         } catch (PackageParserException e) {
             throw PackageManagerException.from(e);
         }
@@ -6283,7 +6360,7 @@
                             + " ignored: updated version " + ps.versionCode
                             + " better than this " + pkg.mVersionCode);
                     if (!updatedPkg.codePath.equals(scanFile)) {
-                        Slog.w(PackageManagerService.TAG, "Code path for hidden system pkg : "
+                        Slog.w(PackageManagerService.TAG, "Code path for hidden system pkg "
                                 + ps.name + " changing from " + updatedPkg.codePathString
                                 + " to " + scanFile);
                         updatedPkg.codePath = scanFile;
@@ -6408,7 +6485,7 @@
                 baseResourcePath = ps.resourcePathString;
             } else {
                 // Should not happen at all. Just log an error.
-                Slog.e(TAG, "Resource path not set for pkg : " + pkg.packageName);
+                Slog.e(TAG, "Resource path not set for package " + pkg.packageName);
             }
         } else {
             resourcePath = pkg.codePath;
@@ -6552,6 +6629,23 @@
         }
     }
 
+    @Override
+    public void extractPackagesIfNeeded() {
+        enforceSystemOrRoot("Only the system can request package extraction");
+
+        // Extract pacakges only if profile-guided compilation is enabled because
+        // otherwise BackgroundDexOptService will not dexopt them later.
+        if (mUseJitProfiles) {
+            ArraySet<String> pkgs = getOptimizablePackages();
+            if (pkgs != null) {
+                for (String pkg : pkgs) {
+                    performDexOpt(pkg, null /* instructionSet */, false /* useProfiles */,
+                            true /* extractOnly */);
+                }
+            }
+        }
+    }
+
     private ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) {
         List<ResolveInfo> ris = null;
         try {
@@ -6579,25 +6673,30 @@
         }
     }
 
+    // TODO: this is not used nor needed. Delete it.
     @Override
     public boolean performDexOptIfNeeded(String packageName, String instructionSet) {
-        return performDexOptTraced(packageName, instructionSet);
+        return performDexOptTraced(packageName, instructionSet, false /* useProfiles */,
+                false /* extractOnly */);
     }
 
-    public boolean performDexOpt(String packageName, String instructionSet) {
-        return performDexOptTraced(packageName, instructionSet);
+    public boolean performDexOpt(String packageName, String instructionSet, boolean useProfiles,
+            boolean extractOnly) {
+        return performDexOptTraced(packageName, instructionSet, useProfiles, extractOnly);
     }
 
-    private boolean performDexOptTraced(String packageName, String instructionSet) {
+    private boolean performDexOptTraced(String packageName, String instructionSet,
+                boolean useProfiles, boolean extractOnly) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
         try {
-            return performDexOptInternal(packageName, instructionSet);
+            return performDexOptInternal(packageName, instructionSet, useProfiles, extractOnly);
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
     }
 
-    private boolean performDexOptInternal(String packageName, String instructionSet) {
+    private boolean performDexOptInternal(String packageName, String instructionSet,
+                boolean useProfiles, boolean extractOnly) {
         PackageParser.Package p;
         final String targetInstructionSet;
         synchronized (mPackages) {
@@ -6609,7 +6708,8 @@
 
             targetInstructionSet = instructionSet != null ? instructionSet :
                     getPrimaryInstructionSet(p.applicationInfo);
-            if (p.mDexOptPerformed.contains(targetInstructionSet)) {
+            if (!useProfiles && p.mDexOptPerformed.contains(targetInstructionSet)) {
+                // Skip only if we do not use profiles since they might trigger a recompilation.
                 return false;
             }
         }
@@ -6618,7 +6718,7 @@
             synchronized (mInstallLock) {
                 final String[] instructionSets = new String[] { targetInstructionSet };
                 int result = mPackageDexOptimizer.performDexOpt(p, instructionSets,
-                        true /* inclDependencies */);
+                        true /* inclDependencies */, useProfiles, extractOnly);
                 return result == PackageDexOptimizer.DEX_OPT_PERFORMED;
             }
         } finally {
@@ -6626,20 +6726,13 @@
         }
     }
 
-    public ArraySet<String> getPackagesThatNeedDexOpt() {
-        ArraySet<String> pkgs = null;
+    public ArraySet<String> getOptimizablePackages() {
+        ArraySet<String> pkgs = new ArraySet<String>();
         synchronized (mPackages) {
             for (PackageParser.Package p : mPackages.values()) {
-                if (DEBUG_DEXOPT) {
-                    Log.i(TAG, p.packageName + " mDexOptPerformed=" + p.mDexOptPerformed.toArray());
+                if (PackageDexOptimizer.canOptimizePackage(p)) {
+                    pkgs.add(p.packageName);
                 }
-                if (!p.mDexOptPerformed.isEmpty()) {
-                    continue;
-                }
-                if (pkgs == null) {
-                    pkgs = new ArraySet<String>();
-                }
-                pkgs.add(p.packageName);
             }
         }
         return pkgs;
@@ -6657,7 +6750,7 @@
         synchronized (mPackages) {
             pkg = mPackages.get(packageName);
             if (pkg == null) {
-                throw new IllegalArgumentException("Missing package: " + packageName);
+                throw new IllegalArgumentException("Unknown package: " + packageName);
             }
         }
 
@@ -6667,8 +6760,11 @@
 
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
 
+            // Whoever is calling forceDexOpt wants a fully compiled package.
+            // Don't use profiles since that may cause compilation to be skipped.
             final int res = mPackageDexOptimizer.performDexOpt(pkg, instructionSets,
-                    true /* inclDependencies */);
+                    true /* inclDependencies */, false /* useProfiles */,
+                    false /* extractOnly */);
 
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
             if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
@@ -6692,52 +6788,67 @@
         return true;
     }
 
-    private void createDataDirsLI(String volumeUuid, String packageName, int uid, String seinfo)
-            throws PackageManagerException {
-        int res = mInstaller.install(volumeUuid, packageName, uid, uid, seinfo);
-        if (res != 0) {
-            throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
-                    "Failed to install " + packageName + ": " + res);
+    private boolean removeDataDirsLI(String volumeUuid, String packageName) {
+        // TODO: triage flags as part of 26466827
+        final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+
+        boolean res = true;
+        final int[] users = sUserManager.getUserIds();
+        for (int user : users) {
+            try {
+                mInstaller.destroyAppData(volumeUuid, packageName, user, flags);
+            } catch (InstallerException e) {
+                Slog.w(TAG, "Failed to delete data directory", e);
+                res = false;
+            }
         }
+        return res;
+    }
+
+    void removeCodePathLI(File codePath) {
+        if (codePath.isDirectory()) {
+            try {
+                mInstaller.rmPackageDir(codePath.getAbsolutePath());
+            } catch (InstallerException e) {
+                Slog.w(TAG, "Failed to remove code path", e);
+            }
+        } else {
+            codePath.delete();
+        }
+    }
+
+    void destroyAppDataLI(String volumeUuid, String packageName, int userId, int flags) {
+        try {
+            mInstaller.destroyAppData(volumeUuid, packageName, userId, flags);
+        } catch (InstallerException e) {
+            Slog.w(TAG, "Failed to destroy app data", e);
+        }
+    }
+
+    void restoreconAppDataLI(String volumeUuid, String packageName, int userId, int flags,
+            int appId, String seinfo) {
+        try {
+            mInstaller.restoreconAppData(volumeUuid, packageName, userId, flags, appId, seinfo);
+        } catch (InstallerException e) {
+            Slog.e(TAG, "Failed to restorecon for " + packageName + ": " + e);
+        }
+    }
+
+    private void deleteCodeCacheDirsLI(String volumeUuid, String packageName) {
+        // TODO: triage flags as part of 26466827
+        final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
 
         final int[] users = sUserManager.getUserIds();
         for (int user : users) {
-            if (user != 0) {
-                res = mInstaller.createUserData(volumeUuid, packageName,
-                        UserHandle.getUid(user, uid), user, seinfo);
-                if (res != 0) {
-                    throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
-                            "Failed to createUserData " + packageName + ": " + res);
-                }
+            try {
+                mInstaller.clearAppData(volumeUuid, packageName, user,
+                        flags | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+            } catch (InstallerException e) {
+                Slog.w(TAG, "Failed to delete code cache directory", e);
             }
         }
     }
 
-    private int removeDataDirsLI(String volumeUuid, String packageName) {
-        int[] users = sUserManager.getUserIds();
-        int res = 0;
-        for (int user : users) {
-            int resInner = mInstaller.remove(volumeUuid, packageName, user);
-            if (resInner < 0) {
-                res = resInner;
-            }
-        }
-
-        return res;
-    }
-
-    private int deleteCodeCacheDirsLI(String volumeUuid, String packageName) {
-        int[] users = sUserManager.getUserIds();
-        int res = 0;
-        for (int user : users) {
-            int resInner = mInstaller.deleteCodeCacheFiles(volumeUuid, packageName, user);
-            if (resInner < 0) {
-                res = resInner;
-            }
-        }
-        return res;
-    }
-
     private void addSharedLibraryLPw(ArraySet<String> usesLibraryFiles, SharedLibraryEntry file,
             PackageParser.Package changingLib) {
         if (file.path != null) {
@@ -7167,7 +7278,7 @@
                                               pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
                             throw new PackageManagerException(
                                     INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
-                                            "Signature mismatch for shared user : "
+                                            "Signature mismatch for shared user: "
                                             + pkgSetting.sharedUser);
                         }
                     }
@@ -7232,108 +7343,8 @@
                 pkg.applicationInfo.uid);
 
         if (pkg != mPlatformPackage) {
-            // This is a normal package, need to make its data directory.
-            final File dataPath = Environment.getDataUserCredentialEncryptedPackageDirectory(
-                    pkg.volumeUuid, UserHandle.USER_SYSTEM, pkg.packageName);
-
-            boolean uidError = false;
-            if (dataPath.exists()) {
-                int currentUid = 0;
-                try {
-                    StructStat stat = Os.stat(dataPath.getPath());
-                    currentUid = stat.st_uid;
-                } catch (ErrnoException e) {
-                    Slog.e(TAG, "Couldn't stat path " + dataPath.getPath(), e);
-                }
-
-                // If we have mismatched owners for the data path, we have a problem.
-                if (currentUid != pkg.applicationInfo.uid) {
-                    boolean recovered = false;
-                    if (currentUid == 0) {
-                        // The directory somehow became owned by root.  Wow.
-                        // This is probably because the system was stopped while
-                        // installd was in the middle of messing with its libs
-                        // directory.  Ask installd to fix that.
-                        int ret = mInstaller.fixUid(pkg.volumeUuid, pkgName,
-                                pkg.applicationInfo.uid, pkg.applicationInfo.uid);
-                        if (ret >= 0) {
-                            recovered = true;
-                            String msg = "Package " + pkg.packageName
-                                    + " unexpectedly changed to uid 0; recovered to " +
-                                    + pkg.applicationInfo.uid;
-                            reportSettingsProblem(Log.WARN, msg);
-                        }
-                    }
-                    if (!recovered && ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0
-                            || (scanFlags&SCAN_BOOTING) != 0)) {
-                        // If this is a system app, we can at least delete its
-                        // current data so the application will still work.
-                        int ret = removeDataDirsLI(pkg.volumeUuid, pkgName);
-                        if (ret >= 0) {
-                            // TODO: Kill the processes first
-                            // Old data gone!
-                            String prefix = (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0
-                                    ? "System package " : "Third party package ";
-                            String msg = prefix + pkg.packageName
-                                    + " has changed from uid: "
-                                    + currentUid + " to "
-                                    + pkg.applicationInfo.uid + "; old data erased";
-                            reportSettingsProblem(Log.WARN, msg);
-                            recovered = true;
-                        }
-                        if (!recovered) {
-                            mHasSystemUidErrors = true;
-                        }
-                    } else if (!recovered) {
-                        // If we allow this install to proceed, we will be broken.
-                        // Abort, abort!
-                        throw new PackageManagerException(INSTALL_FAILED_UID_CHANGED,
-                                "scanPackageLI");
-                    }
-                    if (!recovered) {
-                        pkg.applicationInfo.dataDir = "/mismatched_uid/settings_"
-                            + pkg.applicationInfo.uid + "/fs_"
-                            + currentUid;
-                        pkg.applicationInfo.nativeLibraryDir = pkg.applicationInfo.dataDir;
-                        pkg.applicationInfo.nativeLibraryRootDir = pkg.applicationInfo.dataDir;
-                        String msg = "Package " + pkg.packageName
-                                + " has mismatched uid: "
-                                + currentUid + " on disk, "
-                                + pkg.applicationInfo.uid + " in settings";
-                        // writer
-                        synchronized (mPackages) {
-                            mSettings.mReadMessages.append(msg);
-                            mSettings.mReadMessages.append('\n');
-                            uidError = true;
-                            if (!pkgSetting.uidError) {
-                                reportSettingsProblem(Log.ERROR, msg);
-                            }
-                        }
-                    }
-                }
-
-                // Ensure that directories are prepared
-                createDataDirsLI(pkg.volumeUuid, pkgName, pkg.applicationInfo.uid,
-                        pkg.applicationInfo.seinfo);
-
-                if (mShouldRestoreconData) {
-                    Slog.i(TAG, "SELinux relabeling of " + pkg.packageName + " issued.");
-                    mInstaller.restoreconData(pkg.volumeUuid, pkg.packageName,
-                            pkg.applicationInfo.seinfo, pkg.applicationInfo.uid);
-                }
-            } else {
-                if (DEBUG_PACKAGE_SCANNING) {
-                    if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
-                        Log.v(TAG, "Want this data dir: " + dataPath);
-                }
-                createDataDirsLI(pkg.volumeUuid, pkgName, pkg.applicationInfo.uid,
-                        pkg.applicationInfo.seinfo);
-            }
-
             // Get all of our default paths setup
             pkg.applicationInfo.initForUser(UserHandle.USER_SYSTEM);
-
-            pkgSetting.uidError = uidError;
         }
 
         final String path = scanFile.getPath();
@@ -7367,42 +7378,6 @@
             setNativeLibraryPaths(pkg);
         }
 
-        if (DEBUG_INSTALL) Slog.i(TAG, "Linking native library dir for " + path);
-        final int[] userIds = sUserManager.getUserIds();
-        synchronized (mInstallLock) {
-            // Make sure all user data directories are ready to roll; we're okay
-            // if they already exist
-            if (!TextUtils.isEmpty(pkg.volumeUuid)) {
-                for (int userId : userIds) {
-                    if (userId != UserHandle.USER_SYSTEM) {
-                        mInstaller.createUserData(pkg.volumeUuid, pkg.packageName,
-                                UserHandle.getUid(userId, pkg.applicationInfo.uid), userId,
-                                pkg.applicationInfo.seinfo);
-                    }
-                }
-            }
-
-            // Create a native library symlink only if we have native libraries
-            // and if the native libraries are 32 bit libraries. We do not provide
-            // this symlink for 64 bit libraries.
-            if (pkg.applicationInfo.primaryCpuAbi != null &&
-                    !VMRuntime.is64BitAbi(pkg.applicationInfo.primaryCpuAbi)) {
-                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "linkNativeLib");
-                try {
-                    final String nativeLibPath = pkg.applicationInfo.nativeLibraryDir;
-                    for (int userId : userIds) {
-                        if (mInstaller.linkNativeLibraryDirectory(pkg.volumeUuid, pkg.packageName,
-                                nativeLibPath, userId) < 0) {
-                            throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
-                                    "Failed linking native library dir (user=" + userId + ")");
-                        }
-                    }
-                } finally {
-                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-                }
-            }
-        }
-
         // This is a special case for the "system" package, where the ABI is
         // dictated by the zygote configuration (and init.rc). We should keep track
         // of this ABI so that we can deal with "normal" applications that run under
@@ -7419,7 +7394,7 @@
         if ((scanFlags & SCAN_NO_DEX) == 0 && (scanFlags & SCAN_NEW_INSTALL) != 0) {
             if (cpuAbiOverride == null && pkgSetting.cpuAbiOverrideString != null) {
                 Slog.w(TAG, "Ignoring persisted ABI override " + cpuAbiOverride +
-                        " for package: " + pkg.packageName);
+                        " for package " + pkg.packageName);
             }
         }
 
@@ -8126,9 +8101,12 @@
                     ps.primaryCpuAbiString = adjustedAbi;
                     if (ps.pkg != null && ps.pkg.applicationInfo != null) {
                         ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
-                        Slog.i(TAG, "Adjusting ABI for : " + ps.name + " to " + adjustedAbi);
-                        mInstaller.rmdex(ps.codePathString,
-                                getDexCodeInstructionSet(getPreferredInstructionSet()));
+                        Slog.i(TAG, "Adjusting ABI for " + ps.name + " to " + adjustedAbi);
+                        try {
+                            mInstaller.rmdex(ps.codePathString,
+                                    getDexCodeInstructionSet(getPreferredInstructionSet()));
+                        } catch (InstallerException ignored) {
+                        }
                     }
                 }
             }
@@ -8364,7 +8342,7 @@
             // 64 bit apps will see a 64 bit primary ABI,
 
             if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) {
-                Slog.e(TAG, "Package: " + pkg + " has multiple bundled libs, but is not multiarch.");
+                Slog.e(TAG, "Package " + pkg + " has multiple bundled libs, but is not multiarch.");
             }
 
             if (VMRuntime.is64BitInstructionSet(getPreferredInstructionSet())) {
@@ -9241,14 +9219,10 @@
         protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
                 int match, int userId) {
             if (!sUserManager.exists(userId)) return null;
-            if (!mSettings.isEnabledAndVisibleLPr(info.activity.info, mFlags, userId)) {
+            if (!mSettings.isEnabledAndMatchLPr(info.activity.info, mFlags, userId)) {
                 return null;
             }
             final PackageParser.Activity activity = info.activity;
-            if (mSafeMode && (activity.info.applicationInfo.flags
-                    &ApplicationInfo.FLAG_SYSTEM) == 0) {
-                return null;
-            }
             PackageSetting ps = (PackageSetting) activity.owner.mExtras;
             if (ps == null) {
                 return null;
@@ -9465,14 +9439,10 @@
                 int match, int userId) {
             if (!sUserManager.exists(userId)) return null;
             final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo)filter;
-            if (!mSettings.isEnabledAndVisibleLPr(info.service.info, mFlags, userId)) {
+            if (!mSettings.isEnabledAndMatchLPr(info.service.info, mFlags, userId)) {
                 return null;
             }
             final PackageParser.Service service = info.service;
-            if (mSafeMode && (service.info.applicationInfo.flags
-                    &ApplicationInfo.FLAG_SYSTEM) == 0) {
-                return null;
-            }
             PackageSetting ps = (PackageSetting) service.owner.mExtras;
             if (ps == null) {
                 return null;
@@ -9688,14 +9658,10 @@
             if (!sUserManager.exists(userId))
                 return null;
             final PackageParser.ProviderIntentInfo info = filter;
-            if (!mSettings.isEnabledAndVisibleLPr(info.provider.info, mFlags, userId)) {
+            if (!mSettings.isEnabledAndMatchLPr(info.provider.info, mFlags, userId)) {
                 return null;
             }
             final PackageParser.Provider provider = info.provider;
-            if (mSafeMode && (provider.info.applicationInfo.flags
-                    & ApplicationInfo.FLAG_SYSTEM) == 0) {
-                return null;
-            }
             PackageSetting ps = (PackageSetting) provider.owner.mExtras;
             if (ps == null) {
                 return null;
@@ -10027,7 +9993,7 @@
         }
         final VerificationParams verifParams = new VerificationParams(
                 null, sessionParams.originatingUri, sessionParams.referrerUri,
-                sessionParams.originatingUid, null);
+                sessionParams.originatingUid);
         verifParams.setInstallerUid(installerUid);
 
         final OriginInfo origin;
@@ -10138,6 +10104,19 @@
         info.sendBroadcast(false, false, false);
     }
 
+    private void sendPackagesSuspendedForUser(String[] pkgList, int userId, boolean suspended) {
+        if (pkgList.length > 0) {
+            Bundle extras = new Bundle(1);
+            extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList);
+
+            sendPackageBroadcast(
+                    suspended ? Intent.ACTION_PACKAGES_SUSPENDED
+                            : Intent.ACTION_PACKAGES_UNSUSPENDED,
+                    null, extras, Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null,
+                    new int[] {userId});
+        }
+    }
+
     /**
      * Returns true if application is not found or there was an error. Otherwise it returns
      * the hidden state of the package for the given user.
@@ -10180,7 +10159,7 @@
 
         long callingId = Binder.clearCallingIdentity();
         try {
-            boolean sendAdded = false;
+            boolean installed = false;
 
             // writer
             synchronized (mPackages) {
@@ -10192,11 +10171,14 @@
                     pkgSetting.setInstalled(true, userId);
                     pkgSetting.setHidden(false, userId);
                     mSettings.writePackageRestrictionsLPr(userId);
-                    sendAdded = true;
+                    if (pkgSetting.pkg != null) {
+                        prepareAppDataAfterInstall(pkgSetting.pkg);
+                    }
+                    installed = true;
                 }
             }
 
-            if (sendAdded) {
+            if (installed) {
                 sendPackageAddedForUser(packageName, pkgSetting, userId);
             }
         } finally {
@@ -10221,25 +10203,39 @@
         enforceCrossUserPermission(Binder.getCallingUid(), userId, true, true,
                 "setPackageSuspended for user " + userId);
 
+        // TODO: investigate and add more restrictions for suspending crucial packages.
+        if (isPackageDeviceAdmin(packageName, userId)) {
+            Slog.w(TAG, "Not suspending/un-suspending package \"" + packageName
+                    + "\": has active device admin");
+            return false;
+        }
+
         long callingId = Binder.clearCallingIdentity();
         try {
+            boolean changed = false;
+            boolean success = false;
+            int appId = -1;
             synchronized (mPackages) {
                 final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
                 if (pkgSetting != null) {
                     if (pkgSetting.getSuspended(userId) != suspended) {
                         pkgSetting.setSuspended(suspended, userId);
                         mSettings.writePackageRestrictionsLPr(userId);
+                        appId = pkgSetting.appId;
+                        changed = true;
                     }
-
-                    // TODO:
-                    // * broadcast a PACKAGE_(UN)SUSPENDED intent for launchers to pick up
-                    // * remove app from recents (kill app it if it is running)
-                    // * erase existing notifications for this app
-                    return true;
+                    success = true;
                 }
-
-                return false;
             }
+
+            if (changed) {
+                sendPackagesSuspendedForUser(new String[]{packageName}, userId, suspended);
+                if (suspended) {
+                    killApplication(packageName, UserHandle.getUid(userId, appId),
+                            "suspending package");
+                }
+            }
+            return success;
         } finally {
             Binder.restoreCallingIdentity(callingId);
         }
@@ -10442,10 +10438,6 @@
         if (!DEFAULT_VERIFY_ENABLE) {
             return false;
         }
-        // TODO: fix b/25118622; don't bypass verification
-        if (Build.IS_DEBUGGABLE && (installFlags & PackageManager.INSTALL_QUICK) != 0) {
-            return false;
-        }
         // Ephemeral apps don't get the full verification treatment
         if ((installFlags & PackageManager.INSTALL_EPHEMERAL) != 0) {
             if (DEBUG_EPHEMERAL) {
@@ -10614,7 +10606,7 @@
                     throw new SecurityException("Bad object " + obj + " for uid " + uid);
                 }
             } else {
-                throw new SecurityException("Unknown calling uid " + uid);
+                throw new SecurityException("Unknown calling UID: " + uid);
             }
 
             // Verify: can't set installerPackageName to a package that is
@@ -10965,9 +10957,10 @@
         final String dataAppName;
         final int appId;
         final String seinfo;
+        final int targetSdkVersion;
 
         public MoveInfo(int moveId, String fromUuid, String toUuid, String packageName,
-                String dataAppName, int appId, String seinfo) {
+                String dataAppName, int appId, String seinfo, int targetSdkVersion) {
             this.moveId = moveId;
             this.fromUuid = fromUuid;
             this.toUuid = toUuid;
@@ -10975,6 +10968,7 @@
             this.dataAppName = dataAppName;
             this.appId = appId;
             this.seinfo = seinfo;
+            this.targetSdkVersion = targetSdkVersion;
         }
     }
 
@@ -11013,13 +11007,6 @@
                     + " file=" + origin.file + " cid=" + origin.cid + "}";
         }
 
-        public ManifestDigest getManifestDigest() {
-            if (verificationParams == null) {
-                return null;
-            }
-            return verificationParams.getManifestDigest();
-        }
-
         private int installLocationPolicy(PackageInfoLite pkgLite) {
             String packageName = pkgLite.packageName;
             int installLocation = pkgLite.installLocation;
@@ -11134,9 +11121,12 @@
                     final long sizeBytes = mContainerService.calculateInstalledSize(
                             origin.resolvedPath, isForwardLocked(), packageAbiOverride);
 
-                    if (mInstaller.freeCache(null, sizeBytes + lowThreshold) >= 0) {
+                    try {
+                        mInstaller.freeCache(null, sizeBytes + lowThreshold);
                         pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,
                                 installFlags, packageAbiOverride);
+                    } catch (InstallerException e) {
+                        Slog.w(TAG, "Failed to free cache", e);
                     }
 
                     /*
@@ -11212,7 +11202,8 @@
                  * do, then we'll defer to them to verify the packages.
                  */
                 final int requiredUid = mRequiredVerifierPackage == null ? -1
-                        : getPackageUid(mRequiredVerifierPackage, verifierUser.getIdentifier());
+                        : getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
+                                verifierUser.getIdentifier());
                 if (!origin.existing && requiredUid != -1
                         && isVerificationEnabled(verifierUser.getIdentifier(), installFlags)) {
                     final Intent verification = new Intent(
@@ -11222,9 +11213,9 @@
                             PACKAGE_MIME_TYPE);
                     verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
 
+                    // Query all live verifiers based on current user state
                     final List<ResolveInfo> receivers = queryIntentReceivers(verification,
-                            PACKAGE_MIME_TYPE, PackageManager.GET_DISABLED_COMPONENTS,
-                            verifierUser.getIdentifier());
+                            PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier());
 
                     if (DEBUG_VERIFY) {
                         Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent "
@@ -11438,7 +11429,6 @@
         final int installFlags;
         final String installerPackageName;
         final String volumeUuid;
-        final ManifestDigest manifestDigest;
         final UserHandle user;
         final String abiOverride;
         final String[] installGrantPermissions;
@@ -11453,7 +11443,7 @@
 
         InstallArgs(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
                 int installFlags, String installerPackageName, String volumeUuid,
-                ManifestDigest manifestDigest, UserHandle user, String[] instructionSets,
+                UserHandle user, String[] instructionSets,
                 String abiOverride, String[] installGrantPermissions,
                 String traceMethod, int traceCookie) {
             this.origin = origin;
@@ -11462,7 +11452,6 @@
             this.observer = observer;
             this.installerPackageName = installerPackageName;
             this.volumeUuid = volumeUuid;
-            this.manifestDigest = manifestDigest;
             this.user = user;
             this.instructionSets = instructionSets;
             this.abiOverride = abiOverride;
@@ -11535,11 +11524,9 @@
             String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
             for (String codePath : allCodePaths) {
                 for (String dexCodeInstructionSet : dexCodeInstructionSets) {
-                    int retCode = mInstaller.rmdex(codePath, dexCodeInstructionSet);
-                    if (retCode < 0) {
-                        Slog.w(TAG, "Couldn't remove dex file for package: "
-                                + " at location " + codePath + ", retcode=" + retCode);
-                        // we don't consider this to be a failure of the core package deletion
+                    try {
+                        mInstaller.rmdex(codePath, dexCodeInstructionSet);
+                    } catch (InstallerException ignored) {
                     }
                 }
             }
@@ -11564,7 +11551,7 @@
         /** New install */
         FileInstallArgs(InstallParams params) {
             super(params.origin, params.move, params.observer, params.installFlags,
-                    params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
+                    params.installerPackageName, params.volumeUuid,
                     params.getUser(), null /* instruction sets */, params.packageAbiOverride,
                     params.grantedRuntimePermissions,
                     params.traceMethod, params.traceCookie);
@@ -11575,7 +11562,7 @@
 
         /** Existing install */
         FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) {
-            super(OriginInfo.fromNothing(), null, null, 0, null, null, null, null, instructionSets,
+            super(OriginInfo.fromNothing(), null, null, 0, null, null, null, instructionSets,
                     null, null, null, 0);
             this.codeFile = (codePath != null) ? new File(codePath) : null;
             this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
@@ -11725,11 +11712,7 @@
                 return false;
             }
 
-            if (codeFile.isDirectory()) {
-                mInstaller.rmPackageDir(codeFile.getAbsolutePath());
-            } else {
-                codeFile.delete();
-            }
+            removeCodePathLI(codeFile);
 
             if (resourceFile != null && !FileUtils.contains(codeFile, resourceFile)) {
                 resourceFile.delete();
@@ -11802,7 +11785,7 @@
         /** New install */
         AsecInstallArgs(InstallParams params) {
             super(params.origin, params.move, params.observer, params.installFlags,
-                    params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
+                    params.installerPackageName, params.volumeUuid,
                     params.getUser(), null /* instruction sets */, params.packageAbiOverride,
                     params.grantedRuntimePermissions,
                     params.traceMethod, params.traceCookie);
@@ -11812,7 +11795,7 @@
         AsecInstallArgs(String fullCodePath, String[] instructionSets,
                         boolean isExternal, boolean isForwardLocked) {
             super(OriginInfo.fromNothing(), null, null, (isExternal ? INSTALL_EXTERNAL : 0)
-                    | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null,
+                    | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
                     instructionSets, null, null, null, 0);
             // Hackily pretend we're still looking at a full code path
             if (!fullCodePath.endsWith(RES_FILE_NAME)) {
@@ -11829,7 +11812,7 @@
 
         AsecInstallArgs(String cid, String[] instructionSets, boolean isForwardLocked) {
             super(OriginInfo.fromNothing(), null, null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0)
-                    | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null,
+                    | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
                     instructionSets, null, null, null, 0);
             this.cid = cid;
             setMountPath(PackageHelper.getSdDir(cid));
@@ -12061,8 +12044,8 @@
         @Override
         int doPreCopy() {
             if (isFwdLocked()) {
-                if (!PackageHelper.fixSdPermissions(cid,
-                        getPackageUid(DEFAULT_CONTAINER_PACKAGE, 0), RES_FILE_NAME)) {
+                if (!PackageHelper.fixSdPermissions(cid, getPackageUid(DEFAULT_CONTAINER_PACKAGE,
+                        MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM), RES_FILE_NAME)) {
                     return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
                 }
             }
@@ -12096,7 +12079,7 @@
         /** New install */
         MoveInstallArgs(InstallParams params) {
             super(params.origin, params.move, params.observer, params.installFlags,
-                    params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
+                    params.installerPackageName, params.volumeUuid,
                     params.getUser(), null /* instruction sets */, params.packageAbiOverride,
                     params.grantedRuntimePermissions,
                     params.traceMethod, params.traceCookie);
@@ -12106,8 +12089,11 @@
             if (DEBUG_INSTALL) Slog.d(TAG, "Moving " + move.packageName + " from "
                     + move.fromUuid + " to " + move.toUuid);
             synchronized (mInstaller) {
-                if (mInstaller.copyCompleteApp(move.fromUuid, move.toUuid, move.packageName,
-                        move.dataAppName, move.appId, move.seinfo) != 0) {
+                try {
+                    mInstaller.moveCompleteApp(move.fromUuid, move.toUuid, move.packageName,
+                            move.dataAppName, move.appId, move.seinfo, move.targetSdkVersion);
+                } catch (InstallerException e) {
+                    Slog.w(TAG, "Failed to move app", e);
                     return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
                 }
             }
@@ -12170,11 +12156,7 @@
             synchronized (mInstallLock) {
                 // Clean up both app data and code
                 removeDataDirsLI(volumeUuid, move.packageName);
-                if (codeFile.isDirectory()) {
-                    mInstaller.rmPackageDir(codeFile.getAbsolutePath());
-                } else {
-                    codeFile.delete();
-                }
+                removeCodePathLI(codeFile);
             }
             return true;
         }
@@ -12338,6 +12320,8 @@
                     System.currentTimeMillis(), user);
 
             updateSettingsLI(newPackage, installerPackageName, volumeUuid, null, null, res, user);
+            prepareAppDataAfterInstall(newPackage);
+
             // delete the partially installed application. the data directory will have to be
             // restored if it was already existing
             if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
@@ -12494,6 +12478,7 @@
                         scanFlags | SCAN_UPDATE_TIME, System.currentTimeMillis(), user);
                 updateSettingsLI(newPackage, installerPackageName, volumeUuid, allUsers,
                         perUserInstalled, res, user);
+                prepareAppDataAfterInstall(newPackage);
                 updatedSettings = true;
             } catch (PackageManagerException e) {
                 res.setError("Package couldn't be installed in " + pkg.codePath, e);
@@ -12572,7 +12557,7 @@
             if((oldPkg == null) || (oldPkg.applicationInfo == null) ||
                     (oldPkgSetting == null)) {
                 res.setError(INSTALL_FAILED_REPLACE_COULDNT_DELETE,
-                        "Couldn't find package:" + packageName + " information");
+                        "Couldn't find package " + packageName + " information");
                 return;
             }
         }
@@ -12625,6 +12610,7 @@
             if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                 updateSettingsLI(newPackage, installerPackageName, volumeUuid, allUsers,
                         perUserInstalled, res, user);
+                prepareAppDataAfterInstall(newPackage);
                 updatedSettings = true;
             }
 
@@ -12808,7 +12794,6 @@
         final boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
         final boolean onExternal = (((installFlags & PackageManager.INSTALL_EXTERNAL) != 0)
                 || (args.volumeUuid != null));
-        final boolean quickInstall = ((installFlags & PackageManager.INSTALL_QUICK) != 0);
         final boolean ephemeral = ((installFlags & PackageManager.INSTALL_EPHEMERAL) != 0);
         boolean replace = false;
         int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
@@ -12834,7 +12819,6 @@
                 | PackageParser.PARSE_ENFORCE_CODE
                 | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
                 | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0)
-                | (quickInstall ? PackageParser.PARSE_SKIP_VERIFICATION : 0)
                 | (ephemeral ? PackageParser.PARSE_IS_EPHEMERAL : 0);
         PackageParser pp = new PackageParser();
         pp.setSeparateProcesses(mSeparateProcesses);
@@ -12872,35 +12856,6 @@
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
 
-        /* If the installer passed in a manifest digest, compare it now. */
-        if (args.manifestDigest != null) {
-            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectManifestDigest");
-            try {
-                pp.collectManifestDigest(pkg);
-            } catch (PackageParserException e) {
-                res.setError("Failed collect during installPackageLI", e);
-                return;
-            } finally {
-                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-            }
-
-            if (DEBUG_INSTALL) {
-                final String parsedManifest = pkg.manifestDigest == null ? "null"
-                        : pkg.manifestDigest.toString();
-                Slog.d(TAG, "Comparing manifests: " + args.manifestDigest.toString() + " vs. "
-                        + parsedManifest);
-            }
-
-            if (!args.manifestDigest.equals(pkg.manifestDigest)) {
-                res.setError(INSTALL_FAILED_PACKAGE_CHANGED, "Manifest digest changed");
-                return;
-            }
-        } else if (DEBUG_INSTALL) {
-            final String parsedManifest = pkg.manifestDigest == null
-                    ? "null" : pkg.manifestDigest.toString();
-            Slog.d(TAG, "manifestDigest was not present, but parser got: " + parsedManifest);
-        }
-
         // Get rid of all references to package scan path via parser.
         pp = null;
         String oldCodePath = null;
@@ -13061,6 +13016,24 @@
                 res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");
                 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 /* inclDependencies */, 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;
+                }
+            }
         }
 
         if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
@@ -13095,6 +13068,7 @@
 
         final int verifierUid = getPackageUid(
                 mIntentFilterVerifierComponent.getPackageName(),
+                MATCH_DEBUG_TRIAGED_MISSING,
                 (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
 
         mHandler.removeMessages(START_INTENT_FILTER_VERIFICATIONS);
@@ -13688,10 +13662,12 @@
         try {
             newPkg = scanPackageTracedLI(disabledPs.codePath, parseFlags, SCAN_NO_PATHS, 0, null);
         } catch (PackageManagerException e) {
-            Slog.w(TAG, "Failed to restore system package:" + newPs.name + ": " + e.getMessage());
+            Slog.w(TAG, "Failed to restore system package " + newPs.name + ": " + e.getMessage());
             return false;
         }
 
+        prepareAppDataAfterInstall(newPkg);
+
         // writer
         synchronized (mPackages) {
             PackageSetting ps = mSettings.mPackages.get(newPkg.packageName);
@@ -13782,6 +13758,29 @@
         }
     }
 
+    @Override
+    public boolean setRequiredForSystemUser(String packageName, boolean systemUserApp) {
+        int callingUid = Binder.getCallingUid();
+        if (callingUid != Process.SYSTEM_UID && callingUid != Process.ROOT_UID) {
+            throw new SecurityException(
+                    "setRequiredForSystemUser can only be run by the system or root");
+        }
+        synchronized (mPackages) {
+            PackageSetting ps = mSettings.mPackages.get(packageName);
+            if (ps == null) {
+                Log.w(TAG, "Package doesn't exist: " + packageName);
+                return false;
+            }
+            if (systemUserApp) {
+                ps.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER;
+            } else {
+                ps.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER;
+            }
+            mSettings.writeLPr();
+        }
+        return true;
+    }
+
     /*
      * This method handles package deletion in general
      */
@@ -13862,7 +13861,13 @@
                 outInfo.removedAppId = appId;
                 outInfo.removedUsers = new int[] {removeUser};
             }
-            mInstaller.clearUserData(ps.volumeUuid, packageName, removeUser);
+            // TODO: triage flags as part of 26466827
+            final int installerFlags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+            try {
+                mInstaller.destroyAppData(ps.volumeUuid, packageName, removeUser, installerFlags);
+            } catch (InstallerException e) {
+                Slog.w(TAG, "Failed to delete app data", e);
+            }
             removeKeystoreDataIfNeeded(removeUser, appId);
             schedulePackageCleaning(packageName, removeUser, false);
             synchronized (mPackages) {
@@ -13883,13 +13888,13 @@
 
         boolean ret = false;
         if (isSystemApp(ps)) {
-            if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package:" + ps.name);
+            if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package: " + ps.name);
             // When an updated system application is deleted we delete the existing resources as well and
             // fall back to existing code in system partition
             ret = deleteSystemPackageLI(ps, allUserHandles, perUserInstalled,
                     flags, outInfo, writeSettings);
         } else {
-            if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package:" + ps.name);
+            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, deleteCodeAndResources, flags,
@@ -14036,13 +14041,16 @@
         // Always delete data directories for package, even if we found no other
         // record of app. This helps users recover from UID mismatches without
         // resorting to a full data wipe.
-        int retCode = mInstaller.clearUserData(pkg.volumeUuid, packageName, userId);
-        if (retCode < 0) {
-            Slog.w(TAG, "Couldn't remove cache files for package: " + packageName);
+        // TODO: triage flags as part of 26466827
+        final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+        try {
+            mInstaller.clearAppData(pkg.volumeUuid, packageName, userId, flags);
+        } catch (InstallerException e) {
+            Slog.w(TAG, "Couldn't remove cache files for package " + packageName, e);
             return false;
         }
 
-        final int appId = pkg.applicationInfo.uid;
+        final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
         removeKeystoreDataIfNeeded(userId, appId);
 
         // Create a native library symlink only if we have native libraries
@@ -14051,9 +14059,11 @@
         if (pkg.applicationInfo.primaryCpuAbi != null &&
                 !VMRuntime.is64BitAbi(pkg.applicationInfo.primaryCpuAbi)) {
             final String nativeLibPath = pkg.applicationInfo.nativeLibraryDir;
-            if (mInstaller.linkNativeLibraryDirectory(pkg.volumeUuid, pkg.packageName,
-                    nativeLibPath, userId) < 0) {
-                Slog.w(TAG, "Failed linking native library dir");
+            try {
+                mInstaller.linkNativeLibraryDirectory(pkg.volumeUuid, pkg.packageName,
+                        nativeLibPath, userId);
+            } catch (InstallerException e) {
+                Slog.w(TAG, "Failed linking native library dir", e);
                 return false;
             }
         }
@@ -14266,10 +14276,14 @@
             Slog.w(TAG, "Package " + packageName + " has no applicationInfo.");
             return false;
         }
-        int retCode = mInstaller.deleteCacheFiles(p.volumeUuid, packageName, userId);
-        if (retCode < 0) {
-            Slog.w(TAG, "Couldn't remove cache files for package: "
-                       + packageName + " u" + userId);
+        // TODO: triage flags as part of 26466827
+        final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+        try {
+            mInstaller.clearAppData(p.volumeUuid, packageName, userId,
+                    flags | Installer.FLAG_CLEAR_CACHE_ONLY);
+        } catch (InstallerException e) {
+            Slog.w(TAG, "Couldn't remove cache files for package "
+                    + packageName + " u" + userId, e);
             return false;
         }
         return true;
@@ -14363,9 +14377,12 @@
             apkPath = p.baseCodePath;
         }
 
-        int res = mInstaller.getSizeInfo(p.volumeUuid, packageName, userHandle, apkPath,
-                libDirRoot, publicSrcDir, asecPath, dexCodeInstructionSets, pStats);
-        if (res < 0) {
+        // TODO: triage flags as part of 26466827
+        final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+        try {
+            mInstaller.getAppSize(p.volumeUuid, packageName, userHandle, flags, apkPath,
+                    libDirRoot, publicSrcDir, asecPath, dexCodeInstructionSets, pStats);
+        } catch (InstallerException e) {
             return false;
         }
 
@@ -14713,7 +14730,7 @@
         }
         synchronized (mPackages) {
             Slog.i(TAG, "Adding persistent preferred activity " + activity + " for user " + userId +
-                    " :");
+                    ":");
             filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
             mSettings.editPersistentPreferredActivitiesLPw(userId).addFilter(
                     new PersistentPreferredActivity(filter, activity));
@@ -14782,7 +14799,7 @@
             }
             return;
         }
-
+Slog.v(TAG, ":: restoreFromXml() : got to tag " + parser.getName());
         // this is supposed to be TAG_PREFERRED_BACKUP
         if (!expectedStartTag.equals(parser.getName())) {
             if (DEBUG_BACKUP) {
@@ -14793,6 +14810,7 @@
 
         // skip interfering stuff, then we're aligned with the backing implementation
         while ((type = parser.next()) == XmlPullParser.TEXT) { }
+Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
         functor.apply(parser, userId);
     }
 
@@ -14980,6 +14998,192 @@
     }
 
     @Override
+    public byte[] getPermissionGrantBackup(int userId) {
+        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+            throw new SecurityException("Only the system may call getPermissionGrantBackup()");
+        }
+
+        ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
+        try {
+            final XmlSerializer serializer = new FastXmlSerializer();
+            serializer.setOutput(dataStream, StandardCharsets.UTF_8.name());
+            serializer.startDocument(null, true);
+            serializer.startTag(null, TAG_PERMISSION_BACKUP);
+
+            synchronized (mPackages) {
+                serializeRuntimePermissionGrantsLPr(serializer, userId);
+            }
+
+            serializer.endTag(null, TAG_PERMISSION_BACKUP);
+            serializer.endDocument();
+            serializer.flush();
+        } catch (Exception e) {
+            if (DEBUG_BACKUP) {
+                Slog.e(TAG, "Unable to write default apps for backup", e);
+            }
+            return null;
+        }
+
+        return dataStream.toByteArray();
+    }
+
+    @Override
+    public void restorePermissionGrants(byte[] backup, int userId) {
+        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+            throw new SecurityException("Only the system may call restorePermissionGrants()");
+        }
+
+        try {
+            final XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name());
+            restoreFromXml(parser, userId, TAG_PERMISSION_BACKUP,
+                    new BlobXmlRestorer() {
+                        @Override
+                        public void apply(XmlPullParser parser, int userId)
+                                throws XmlPullParserException, IOException {
+                            synchronized (mPackages) {
+                                processRestoredPermissionGrantsLPr(parser, userId);
+                            }
+                        }
+                    } );
+        } catch (Exception e) {
+            if (DEBUG_BACKUP) {
+                Slog.e(TAG, "Exception restoring preferred activities: " + e.getMessage());
+            }
+        }
+    }
+
+    private void serializeRuntimePermissionGrantsLPr(XmlSerializer serializer, final int userId)
+            throws IOException {
+        serializer.startTag(null, TAG_ALL_GRANTS);
+
+        final int N = mSettings.mPackages.size();
+        for (int i = 0; i < N; i++) {
+            final PackageSetting ps = mSettings.mPackages.valueAt(i);
+            boolean pkgGrantsKnown = false;
+
+            PermissionsState packagePerms = ps.getPermissionsState();
+
+            for (PermissionState state : packagePerms.getRuntimePermissionStates(userId)) {
+                final int grantFlags = state.getFlags();
+                // only look at grants that are not system/policy fixed
+                if ((grantFlags & SYSTEM_RUNTIME_GRANT_MASK) == 0) {
+                    final boolean isGranted = state.isGranted();
+                    // And only back up the user-twiddled state bits
+                    if (isGranted || (grantFlags & USER_RUNTIME_GRANT_MASK) != 0) {
+                        final String packageName = mSettings.mPackages.keyAt(i);
+                        if (!pkgGrantsKnown) {
+                            serializer.startTag(null, TAG_GRANT);
+                            serializer.attribute(null, ATTR_PACKAGE_NAME, packageName);
+                            pkgGrantsKnown = true;
+                        }
+
+                        final boolean userSet =
+                                (grantFlags & FLAG_PERMISSION_USER_SET) != 0;
+                        final boolean userFixed =
+                                (grantFlags & FLAG_PERMISSION_USER_FIXED) != 0;
+                        final boolean revoke =
+                                (grantFlags & FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0;
+
+                        serializer.startTag(null, TAG_PERMISSION);
+                        serializer.attribute(null, ATTR_PERMISSION_NAME, state.getName());
+                        if (isGranted) {
+                            serializer.attribute(null, ATTR_IS_GRANTED, "true");
+                        }
+                        if (userSet) {
+                            serializer.attribute(null, ATTR_USER_SET, "true");
+                        }
+                        if (userFixed) {
+                            serializer.attribute(null, ATTR_USER_FIXED, "true");
+                        }
+                        if (revoke) {
+                            serializer.attribute(null, ATTR_REVOKE_ON_UPGRADE, "true");
+                        }
+                        serializer.endTag(null, TAG_PERMISSION);
+                    }
+                }
+            }
+
+            if (pkgGrantsKnown) {
+                serializer.endTag(null, TAG_GRANT);
+            }
+        }
+
+        serializer.endTag(null, TAG_ALL_GRANTS);
+    }
+
+    private void processRestoredPermissionGrantsLPr(XmlPullParser parser, int userId)
+            throws XmlPullParserException, IOException {
+        String pkgName = null;
+        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;
+            }
+
+            final String tagName = parser.getName();
+            if (tagName.equals(TAG_GRANT)) {
+                pkgName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
+                if (DEBUG_BACKUP) {
+                    Slog.v(TAG, "+++ Restoring grants for package " + pkgName);
+                }
+            } else if (tagName.equals(TAG_PERMISSION)) {
+
+                final boolean isGranted = "true".equals(parser.getAttributeValue(null, ATTR_IS_GRANTED));
+                final String permName = parser.getAttributeValue(null, ATTR_PERMISSION_NAME);
+
+                int newFlagSet = 0;
+                if ("true".equals(parser.getAttributeValue(null, ATTR_USER_SET))) {
+                    newFlagSet |= FLAG_PERMISSION_USER_SET;
+                }
+                if ("true".equals(parser.getAttributeValue(null, ATTR_USER_FIXED))) {
+                    newFlagSet |= FLAG_PERMISSION_USER_FIXED;
+                }
+                if ("true".equals(parser.getAttributeValue(null, ATTR_REVOKE_ON_UPGRADE))) {
+                    newFlagSet |= FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+                }
+                if (DEBUG_BACKUP) {
+                    Slog.v(TAG, "  + Restoring grant: pkg=" + pkgName + " perm=" + permName
+                            + " granted=" + isGranted + " bits=0x" + Integer.toHexString(newFlagSet));
+                }
+                final PackageSetting ps = mSettings.mPackages.get(pkgName);
+                if (ps != null) {
+                    // Already installed so we apply the grant immediately
+                    if (DEBUG_BACKUP) {
+                        Slog.v(TAG, "        + already installed; applying");
+                    }
+                    PermissionsState perms = ps.getPermissionsState();
+                    BasePermission bp = mSettings.mPermissions.get(permName);
+                    if (bp != null) {
+                        if (isGranted) {
+                            perms.grantRuntimePermission(bp, userId);
+                        }
+                        if (newFlagSet != 0) {
+                            perms.updatePermissionFlags(bp, userId, USER_RUNTIME_GRANT_MASK, newFlagSet);
+                        }
+                    }
+                } else {
+                    // Need to wait for post-restore install to apply the grant
+                    if (DEBUG_BACKUP) {
+                        Slog.v(TAG, "        - not yet installed; saving for later");
+                    }
+                    mSettings.processRestoredPermissionGrantLPr(pkgName, permName,
+                            isGranted, newFlagSet, userId);
+                }
+            } else {
+                PackageManagerService.reportSettingsProblem(Log.WARN,
+                        "Unknown element under <" + TAG_PERMISSION_BACKUP + ">: " + tagName);
+                XmlUtils.skipCurrentTag(parser);
+            }
+        }
+
+        scheduleWriteSettingsLocked();
+        mSettings.writeRuntimePermissionsForUserLPr(userId, false);
+    }
+
+    @Override
     public void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage,
             int sourceUserId, int targetUserId, int flags) {
         mContext.enforceCallingOrSelfPermission(
@@ -15118,12 +15322,10 @@
             pkgSetting = mSettings.mPackages.get(packageName);
             if (pkgSetting == null) {
                 if (className == null) {
-                    throw new IllegalArgumentException(
-                            "Unknown package: " + packageName);
+                    throw new IllegalArgumentException("Unknown package: " + packageName);
                 }
                 throw new IllegalArgumentException(
-                        "Unknown component: " + packageName
-                        + "/" + className);
+                        "Unknown component: " + packageName + "/" + className);
             }
             // Allow root and verify that userId is not being specified by a different user
             if (!allowedByPermission && !UserHandle.isSameApp(uid, pkgSetting.appId)) {
@@ -15705,11 +15907,14 @@
                     pw.print("  Required: ");
                     pw.print(mRequiredVerifierPackage);
                     pw.print(" (uid=");
-                    pw.print(getPackageUid(mRequiredVerifierPackage, 0));
+                    pw.print(getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
+                            UserHandle.USER_SYSTEM));
                     pw.println(")");
                 } else if (mRequiredVerifierPackage != null) {
                     pw.print("vrfy,"); pw.print(mRequiredVerifierPackage);
-                    pw.print(","); pw.println(getPackageUid(mRequiredVerifierPackage, 0));
+                    pw.print(",");
+                    pw.println(getPackageUid(mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING,
+                            UserHandle.USER_SYSTEM));
                 }
             }
 
@@ -15724,11 +15929,14 @@
                         pw.print("  Using: ");
                         pw.print(verifierPackageName);
                         pw.print(" (uid=");
-                        pw.print(getPackageUid(verifierPackageName, 0));
+                        pw.print(getPackageUid(verifierPackageName, MATCH_DEBUG_TRIAGED_MISSING,
+                                UserHandle.USER_SYSTEM));
                         pw.println(")");
                     } else if (verifierPackageName != null) {
                         pw.print("ifv,"); pw.print(verifierPackageName);
-                        pw.print(","); pw.println(getPackageUid(verifierPackageName, 0));
+                        pw.print(",");
+                        pw.println(getPackageUid(verifierPackageName, MATCH_DEBUG_TRIAGED_MISSING,
+                                UserHandle.USER_SYSTEM));
                     }
                 } else {
                     pw.println();
@@ -15987,6 +16195,10 @@
                 mSettings.dumpSharedUsersLPr(pw, packageName, permissionNames, dumpState, checkin);
             }
 
+            if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS) && packageName == null) {
+                mSettings.dumpRestoredPermissionGrantsLPr(pw, dumpState);
+            }
+
             if (!checkin && dumpState.isDumping(DumpState.DUMP_INSTALLS) && packageName == null) {
                 // XXX should handle packageName != null by dumping only install data that
                 // the given package is involved with.
@@ -16134,10 +16346,6 @@
      */
     public void scanAvailableAsecs() {
         updateExternalMediaStatusInner(true, false, false);
-        if (mShouldRestoreconData) {
-            SELinuxMMAC.setRestoreconDone();
-            mShouldRestoreconData = false;
-        }
     }
 
     /*
@@ -16458,22 +16666,31 @@
     }
 
     private void loadPrivatePackagesInner(VolumeInfo vol) {
+        final String volumeUuid = vol.fsUuid;
+        if (TextUtils.isEmpty(volumeUuid)) {
+            Slog.e(TAG, "Loading internal storage is probably a mistake; ignoring");
+            return;
+        }
+
         final ArrayList<ApplicationInfo> loaded = new ArrayList<>();
         final int parseFlags = mDefParseFlags | PackageParser.PARSE_EXTERNAL_STORAGE;
 
         final VersionInfo ver;
         final List<PackageSetting> packages;
         synchronized (mPackages) {
-            ver = mSettings.findOrCreateVersion(vol.fsUuid);
-            packages = mSettings.getVolumePackagesLPr(vol.fsUuid);
+            ver = mSettings.findOrCreateVersion(volumeUuid);
+            packages = mSettings.getVolumePackagesLPr(volumeUuid);
         }
 
+        // TODO: introduce a new concept similar to "frozen" to prevent these
+        // apps from being launched until after data has been fully reconciled
         for (PackageSetting ps : packages) {
             synchronized (mInstallLock) {
                 final PackageParser.Package pkg;
                 try {
                     pkg = scanPackageTracedLI(ps.codePath, parseFlags, SCAN_INITIAL, 0, null);
                     loaded.add(pkg.applicationInfo);
+
                 } catch (PackageManagerException e) {
                     Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage());
                 }
@@ -16484,14 +16701,27 @@
             }
         }
 
+        // Reconcile app data for all started/unlocked users
+        final UserManager um = mContext.getSystemService(UserManager.class);
+        for (UserInfo user : um.getUsers()) {
+            if (um.isUserUnlocked(user.id)) {
+                reconcileAppsData(volumeUuid, user.id,
+                        Installer.FLAG_DE_STORAGE | Installer.FLAG_CE_STORAGE);
+            } else if (um.isUserRunning(user.id)) {
+                reconcileAppsData(volumeUuid, user.id, Installer.FLAG_DE_STORAGE);
+            } else {
+                continue;
+            }
+        }
+
         synchronized (mPackages) {
             int updateFlags = UPDATE_PERMISSIONS_ALL;
             if (ver.sdkVersion != mSdkVersion) {
                 logCriticalInfo(Log.INFO, "Platform changed from " + ver.sdkVersion + " to "
-                        + mSdkVersion + "; regranting permissions for " + vol.fsUuid);
+                        + mSdkVersion + "; regranting permissions for " + volumeUuid);
                 updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;
             }
-            updatePermissionsLPw(null, null, vol.fsUuid, updateFlags);
+            updatePermissionsLPw(null, null, volumeUuid, updateFlags);
 
             // Yay, everything is now upgraded
             ver.forceCurrent();
@@ -16513,10 +16743,16 @@
     }
 
     private void unloadPrivatePackagesInner(VolumeInfo vol) {
+        final String volumeUuid = vol.fsUuid;
+        if (TextUtils.isEmpty(volumeUuid)) {
+            Slog.e(TAG, "Unloading internal storage is probably a mistake; ignoring");
+            return;
+        }
+
         final ArrayList<ApplicationInfo> unloaded = new ArrayList<>();
         synchronized (mInstallLock) {
         synchronized (mPackages) {
-            final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(vol.fsUuid);
+            final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(volumeUuid);
             for (PackageSetting ps : packages) {
                 if (ps.pkg == null) continue;
 
@@ -16576,7 +16812,11 @@
 
             if (destroyUser) {
                 synchronized (mInstallLock) {
-                    mInstaller.removeUserDataDirs(volumeUuid, userId);
+                    try {
+                        mInstaller.removeUserDataDirs(volumeUuid, userId);
+                    } catch (InstallerException e) {
+                        Slog.w(TAG, "Failed to clean up user dirs", e);
+                    }
                 }
             }
         }
@@ -16596,6 +16836,37 @@
         }
     }
 
+    private void assertPackageKnown(String volumeUuid, String packageName)
+            throws PackageManagerException {
+        synchronized (mPackages) {
+            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            if (ps == null) {
+                throw new PackageManagerException("Package " + packageName + " is unknown");
+            } else if (!TextUtils.equals(volumeUuid, ps.volumeUuid)) {
+                throw new PackageManagerException(
+                        "Package " + packageName + " found on unknown volume " + volumeUuid
+                                + "; expected volume " + ps.volumeUuid);
+            }
+        }
+    }
+
+    private void assertPackageKnownAndInstalled(String volumeUuid, String packageName, int userId)
+            throws PackageManagerException {
+        synchronized (mPackages) {
+            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            if (ps == null) {
+                throw new PackageManagerException("Package " + packageName + " is unknown");
+            } else if (!TextUtils.equals(volumeUuid, ps.volumeUuid)) {
+                throw new PackageManagerException(
+                        "Package " + packageName + " found on unknown volume " + volumeUuid
+                                + "; expected volume " + ps.volumeUuid);
+            } else if (!ps.getInstalled(userId)) {
+                throw new PackageManagerException(
+                        "Package " + packageName + " not installed for user " + userId);
+            }
+        }
+    }
+
     /**
      * Examine all apps present on given mounted volume, and destroy apps that
      * aren't expected, either due to uninstallation or reinstallation on
@@ -16612,40 +16883,222 @@
                 continue;
             }
 
-            boolean destroyApp = false;
-            String packageName = null;
             try {
                 final PackageLite pkg = PackageParser.parsePackageLite(file,
                         PackageParser.PARSE_MUST_BE_APK);
-                packageName = pkg.packageName;
+                assertPackageKnown(volumeUuid, pkg.packageName);
 
-                synchronized (mPackages) {
-                    final PackageSetting ps = mSettings.mPackages.get(packageName);
-                    if (ps == null) {
-                        logCriticalInfo(Log.WARN, "Destroying " + packageName + " on + "
-                                + volumeUuid + " because we found no install record");
-                        destroyApp = true;
-                    } else if (!TextUtils.equals(volumeUuid, ps.volumeUuid)) {
-                        logCriticalInfo(Log.WARN, "Destroying " + packageName + " on "
-                                + volumeUuid + " because we expected it on " + ps.volumeUuid);
-                        destroyApp = true;
-                    }
+            } catch (PackageParserException | PackageManagerException e) {
+                logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e);
+                synchronized (mInstallLock) {
+                    removeCodePathLI(file);
                 }
+            }
+        }
+    }
 
-            } catch (PackageParserException e) {
-                logCriticalInfo(Log.WARN, "Destroying " + file + " due to parse failure: " + e);
-                destroyApp = true;
+    /**
+     * Reconcile all app data for the given user.
+     * <p>
+     * Verifies that directories exist and that ownership and labeling is
+     * correct for all installed apps on all mounted volumes.
+     */
+    void reconcileAppsData(int userId, @StorageFlags int flags) {
+        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
+            final String volumeUuid = vol.getFsUuid();
+            reconcileAppsData(volumeUuid, userId, flags);
+        }
+    }
+
+    /**
+     * Reconcile all app data on given mounted volume.
+     * <p>
+     * Destroys app data that isn't expected, either due to uninstallation or
+     * reinstallation on another volume.
+     * <p>
+     * Verifies that directories exist and that ownership and labeling is
+     * correct for all installed apps.
+     */
+    private void reconcileAppsData(String volumeUuid, int userId, @StorageFlags int flags) {
+        Slog.v(TAG, "reconcileAppsData for " + volumeUuid + " u" + userId + " 0x"
+                + Integer.toHexString(flags));
+
+        final File ceDir = Environment.getDataUserCredentialEncryptedDirectory(volumeUuid, userId);
+        final File deDir = Environment.getDataUserDeviceEncryptedDirectory(volumeUuid, userId);
+
+        boolean restoreconNeeded = false;
+
+        // First look for stale data that doesn't belong, and check if things
+        // have changed since we did our last restorecon
+        if ((flags & Installer.FLAG_CE_STORAGE) != 0) {
+            if (!isUserKeyUnlocked(userId)) {
+                throw new RuntimeException(
+                        "Yikes, someone asked us to reconcile CE storage while " + userId
+                                + " was still locked; this would have caused massive data loss!");
             }
 
-            if (destroyApp) {
-                synchronized (mInstallLock) {
-                    if (packageName != null) {
-                        removeDataDirsLI(volumeUuid, packageName);
+            restoreconNeeded |= SELinuxMMAC.isRestoreconNeeded(ceDir);
+
+            final File[] files = FileUtils.listFilesOrEmpty(ceDir);
+            for (File file : files) {
+                final String packageName = file.getName();
+                try {
+                    assertPackageKnownAndInstalled(volumeUuid, packageName, userId);
+                } catch (PackageManagerException e) {
+                    logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e);
+                    synchronized (mInstallLock) {
+                        destroyAppDataLI(volumeUuid, packageName, userId,
+                                Installer.FLAG_CE_STORAGE);
                     }
-                    if (file.isDirectory()) {
-                        mInstaller.rmPackageDir(file.getAbsolutePath());
-                    } else {
-                        file.delete();
+                }
+            }
+        }
+        if ((flags & Installer.FLAG_DE_STORAGE) != 0) {
+            restoreconNeeded |= SELinuxMMAC.isRestoreconNeeded(deDir);
+
+            final File[] files = FileUtils.listFilesOrEmpty(deDir);
+            for (File file : files) {
+                final String packageName = file.getName();
+                try {
+                    assertPackageKnownAndInstalled(volumeUuid, packageName, userId);
+                } catch (PackageManagerException e) {
+                    logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e);
+                    synchronized (mInstallLock) {
+                        destroyAppDataLI(volumeUuid, packageName, userId,
+                                Installer.FLAG_DE_STORAGE);
+                    }
+                }
+            }
+        }
+
+        // Ensure that data directories are ready to roll for all packages
+        // installed for this volume and user
+        final List<PackageSetting> packages;
+        synchronized (mPackages) {
+            packages = mSettings.getVolumePackagesLPr(volumeUuid);
+        }
+        int preparedCount = 0;
+        for (PackageSetting ps : packages) {
+            final String packageName = ps.name;
+            if (ps.pkg == null) {
+                Slog.w(TAG, "Odd, missing scanned package " + packageName);
+                // TODO: might be due to legacy ASEC apps; we should circle back
+                // and reconcile again once they're scanned
+                continue;
+            }
+
+            if (ps.getInstalled(userId)) {
+                prepareAppData(volumeUuid, userId, flags, ps.pkg, restoreconNeeded);
+                preparedCount++;
+            }
+        }
+
+        if (restoreconNeeded) {
+            if ((flags & Installer.FLAG_CE_STORAGE) != 0) {
+                SELinuxMMAC.setRestoreconDone(ceDir);
+            }
+            if ((flags & Installer.FLAG_DE_STORAGE) != 0) {
+                SELinuxMMAC.setRestoreconDone(deDir);
+            }
+        }
+
+        Slog.v(TAG, "reconcileAppsData finished " + preparedCount
+                + " packages; restoreconNeeded was " + restoreconNeeded);
+    }
+
+    /**
+     * Prepare app data for the given app just after it was installed or
+     * upgraded. This method carefully only touches users that it's installed
+     * for, and it forces a restorecon to handle any seinfo changes.
+     * <p>
+     * Verifies that directories exist and that ownership and labeling is
+     * 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.
+     */
+    private void prepareAppDataAfterInstall(PackageParser.Package pkg) {
+        final PackageSetting ps;
+        synchronized (mPackages) {
+            ps = mSettings.mPackages.get(pkg.packageName);
+        }
+
+        final UserManager um = mContext.getSystemService(UserManager.class);
+        for (UserInfo user : um.getUsers()) {
+            final int flags;
+            if (um.isUserUnlocked(user.id)) {
+                flags = Installer.FLAG_DE_STORAGE | Installer.FLAG_CE_STORAGE;
+            } else if (um.isUserRunning(user.id)) {
+                flags = Installer.FLAG_DE_STORAGE;
+            } else {
+                continue;
+            }
+
+            if (ps.getInstalled(user.id)) {
+                // Whenever an app changes, force a restorecon of its data
+                // TODO: when user data is locked, mark that we're still dirty
+                prepareAppData(pkg.volumeUuid, user.id, flags, pkg, true);
+            }
+        }
+    }
+
+    /**
+     * Prepare app data for the given app.
+     * <p>
+     * Verifies that directories exist and that ownership and labeling is
+     * correct for all installed apps. If there is an ownership mismatch, this
+     * will try recovering system apps by wiping data; third-party app data is
+     * left intact.
+     */
+    private void prepareAppData(String volumeUuid, int userId, @StorageFlags int flags,
+            PackageParser.Package pkg, boolean restoreconNeeded) {
+        if (DEBUG_APP_DATA) {
+            Slog.v(TAG, "prepareAppData for " + pkg.packageName + " u" + userId + " 0x"
+                    + Integer.toHexString(flags) + (restoreconNeeded ? " restoreconNeeded" : ""));
+        }
+
+        final String packageName = pkg.packageName;
+        final ApplicationInfo app = pkg.applicationInfo;
+        final int appId = UserHandle.getAppId(app.uid);
+
+        Preconditions.checkNotNull(app.seinfo);
+
+        synchronized (mInstallLock) {
+            try {
+                mInstaller.createAppData(volumeUuid, packageName, userId, flags,
+                        appId, app.seinfo, app.targetSdkVersion);
+            } catch (InstallerException e) {
+                if (app.isSystemApp()) {
+                    logCriticalInfo(Log.ERROR, "Failed to create app data for " + packageName
+                            + ", but trying to recover: " + e);
+                    destroyAppDataLI(volumeUuid, packageName, userId, flags);
+                    try {
+                        mInstaller.createAppData(volumeUuid, packageName, userId, flags,
+                                appId, app.seinfo, app.targetSdkVersion);
+                        logCriticalInfo(Log.DEBUG, "Recovery succeeded!");
+                    } catch (InstallerException e2) {
+                        logCriticalInfo(Log.DEBUG, "Recovery failed!");
+                    }
+                } else {
+                    Slog.e(TAG, "Failed to create app data for " + packageName + ": " + e);
+                }
+            }
+
+            if (restoreconNeeded) {
+                restoreconAppDataLI(volumeUuid, packageName, userId, flags, appId, app.seinfo);
+            }
+
+            if ((flags & Installer.FLAG_CE_STORAGE) != 0) {
+                // Create a native library symlink only if we have native libraries
+                // and if the native libraries are 32 bit libraries. We do not provide
+                // this symlink for 64 bit libraries.
+                if (app.primaryCpuAbi != null && !VMRuntime.is64BitAbi(app.primaryCpuAbi)) {
+                    final String nativeLibPath = app.nativeLibraryDir;
+                    try {
+                        mInstaller.linkNativeLibraryDirectory(volumeUuid, packageName,
+                                nativeLibPath, userId);
+                    } catch (InstallerException e) {
+                        Slog.e(TAG, "Failed to link native for " + packageName + ": " + e);
                     }
                 }
             }
@@ -16695,6 +17148,7 @@
         final int appId;
         final String seinfo;
         final String label;
+        final int targetSdkVersion;
 
         // reader
         synchronized (mPackages) {
@@ -16744,6 +17198,7 @@
             appId = UserHandle.getAppId(pkg.applicationInfo.uid);
             seinfo = pkg.applicationInfo.seinfo;
             label = String.valueOf(pm.getApplicationLabel(pkg.applicationInfo));
+            targetSdkVersion = pkg.applicationInfo.targetSdkVersion;
         }
 
         // Now that we're guarded by frozen state, kill app during move
@@ -16876,7 +17331,7 @@
 
             final String dataAppName = codeFile.getName();
             move = new MoveInfo(moveId, currentVolumeUuid, volumeUuid, packageName,
-                    dataAppName, appId, seinfo);
+                    dataAppName, appId, seinfo, targetSdkVersion);
         } else {
             move = null;
         }
@@ -16982,7 +17437,11 @@
             for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
                 final String volumeUuid = vol.getFsUuid();
                 if (DEBUG_INSTALL) Slog.d(TAG, "Removing user data on volume " + volumeUuid);
-                mInstaller.removeUserDataDirs(volumeUuid, userHandle);
+                try {
+                    mInstaller.removeUserDataDirs(volumeUuid, userHandle);
+                } catch (InstallerException e) {
+                    Slog.w(TAG, "Failed to remove user data", e);
+                }
             }
             synchronized (mPackages) {
                 removeUnusedPackagesLILPw(userManager, userHandle);
@@ -17045,7 +17504,11 @@
     /** Called by UserManagerService */
     void createNewUser(int userHandle) {
         synchronized (mInstallLock) {
-            mInstaller.createUserConfig(userHandle);
+            try {
+                mInstaller.createUserConfig(userHandle);
+            } catch (InstallerException e) {
+                Slog.w(TAG, "Failed to create user config", e);
+            }
             mSettings.createNewUserLI(this, mInstaller, userHandle);
         }
         synchronized (mPackages) {
@@ -17165,7 +17628,7 @@
         synchronized(mPackages) {
             final PackageParser.Package pkg = mPackages.get(packageName);
             if (pkg == null) {
-                Slog.w(TAG, "KeySet requested for unknown package:" + packageName);
+                Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
                 throw new IllegalArgumentException("Unknown package: " + packageName);
             }
             KeySetManagerService ksms = mSettings.mKeySetManagerService;
@@ -17181,7 +17644,7 @@
         synchronized(mPackages) {
             final PackageParser.Package pkg = mPackages.get(packageName);
             if (pkg == null) {
-                Slog.w(TAG, "KeySet requested for unknown package:" + packageName);
+                Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
                 throw new IllegalArgumentException("Unknown package: " + packageName);
             }
             if (pkg.applicationInfo.uid != Binder.getCallingUid()
@@ -17201,7 +17664,7 @@
         synchronized(mPackages) {
             final PackageParser.Package pkg = mPackages.get(packageName);
             if (pkg == null) {
-                Slog.w(TAG, "KeySet requested for unknown package:" + packageName);
+                Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
                 throw new IllegalArgumentException("Unknown package: " + packageName);
             }
             IBinder ksh = ks.getToken();
@@ -17221,7 +17684,7 @@
         synchronized(mPackages) {
             final PackageParser.Package pkg = mPackages.get(packageName);
             if (pkg == null) {
-                Slog.w(TAG, "KeySet requested for unknown package:" + packageName);
+                Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
                 throw new IllegalArgumentException("Unknown package: " + packageName);
             }
             IBinder ksh = ks.getToken();
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index eef7d9b..901749e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -46,7 +46,6 @@
 import android.os.ShellCommand;
 import android.os.UserHandle;
 import android.text.TextUtils;
-
 import android.util.PrintWriterPrinter;
 import com.android.internal.util.SizedInputStream;
 
@@ -127,19 +126,31 @@
         final InstallParams params = makeInstallParams();
         final int sessionId = doCreateSession(params.sessionParams,
                 params.installerPackageName, params.userId);
-
-        final String inPath = getNextArg();
-        if (inPath == null && params.sessionParams.sizeBytes == 0) {
-            pw.println("Error: must either specify a package size or an APK file");
-            return 1;
+        boolean abandonSession = true;
+        try {
+            final String inPath = getNextArg();
+            if (inPath == null && params.sessionParams.sizeBytes == 0) {
+                pw.println("Error: must either specify a package size or an APK file");
+                return 1;
+            }
+            if (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
+                    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) {
+                }
+            }
         }
-        if (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk") != 0) {
-            return 1;
-        }
-        if (doCommitSession(sessionId) != 0) {
-            return 1;
-        }
-        return 0;
     }
 
     private int runSuspend(boolean suspendedState) {
@@ -179,12 +190,12 @@
 
     private int runInstallAbandon() throws RemoteException {
         final int sessionId = Integer.parseInt(getNextArg());
-        return doAbandonSession(sessionId);
+        return doAbandonSession(sessionId, true /*logSuccess*/);
     }
 
     private int runInstallCommit() throws RemoteException {
         final int sessionId = Integer.parseInt(getNextArg());
-        return doCommitSession(sessionId);
+        return doCommitSession(sessionId, true /*logSuccess*/);
     }
 
     private int runInstallCreate() throws RemoteException {
@@ -213,7 +224,7 @@
         final int sessionId = Integer.parseInt(getNextArg());
         final String splitName = getNextArg();
         final String path = getNextArg();
-        return doWriteSession(sessionId, path, sizeBytes, splitName);
+        return doWriteSession(sessionId, path, sizeBytes, splitName, true /*logSuccess*/);
     }
 
     private int runList() throws RemoteException {
@@ -559,7 +570,7 @@
         } else {
             final PackageInfo info = mInterface.getPackageInfo(packageName, 0, userId);
             if (info == null) {
-                pw.println("Failure - not installed for " + userId);
+                pw.println("Failure [not installed for " + userId + "]");
                 return 1;
             }
             final boolean isSystem =
@@ -828,8 +839,8 @@
         return sessionId;
     }
 
-    private int doWriteSession(int sessionId, String inPath, long sizeBytes, String splitName)
-            throws RemoteException {
+    private int doWriteSession(int sessionId, String inPath, long sizeBytes, String splitName,
+            boolean logSuccess) throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
         if ("-".equals(inPath)) {
             inPath = null;
@@ -870,7 +881,9 @@
             }
             session.fsync(out);
 
-            pw.println("Success: streamed " + total + " bytes");
+            if (logSuccess) {
+                pw.println("Success: streamed " + total + " bytes");
+            }
             return 0;
         } catch (IOException e) {
             pw.println("Error: failed to write; " + e.getMessage());
@@ -882,7 +895,7 @@
         }
     }
 
-    private int doCommitSession(int sessionId) throws RemoteException {
+    private int doCommitSession(int sessionId, boolean logSuccess) throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
         PackageInstaller.Session session = null;
         try {
@@ -896,11 +909,12 @@
             final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
                     PackageInstaller.STATUS_FAILURE);
             if (status == PackageInstaller.STATUS_SUCCESS) {
-                pw.println("Success");
+                if (logSuccess) {
+                    System.out.println("Success");
+                }
             } else {
                 pw.println("Failure ["
                         + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
-                pw.println("Failure details: " + result.getExtras());
             }
             return status;
         } finally {
@@ -908,14 +922,16 @@
         }
     }
 
-    private int doAbandonSession(int sessionId) throws RemoteException {
+    private int doAbandonSession(int sessionId, boolean logSuccess) throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
         PackageInstaller.Session session = null;
         try {
             session = new PackageInstaller.Session(
                     mInterface.getPackageInstaller().openSession(sessionId));
             session.abandon();
-            pw.println("Success");
+            if (logSuccess) {
+                pw.println("Success");
+            }
             return 0;
         } finally {
             IoUtils.closeQuietly(session);
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index e7c0ef7..f106b62 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -17,6 +17,7 @@
 package com.android.server.pm;
 
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
 
 import java.io.File;
@@ -78,4 +79,11 @@
     public boolean isSharedUser() {
         return sharedUser != null;
     }
+
+    public boolean isMatch(int flags) {
+        if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
+            return isSystem();
+        }
+        return true;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index 903d12b..aa10c08 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -19,20 +19,24 @@
 import android.content.pm.PackageParser;
 import android.content.pm.Signature;
 import android.os.Environment;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
 import android.util.Slog;
 import android.util.Xml;
 
 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.FileOutputStream;
 import java.io.FileReader;
 import java.io.IOException;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
-
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -41,9 +45,6 @@
 import java.util.Map;
 import java.util.Set;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 /**
  * Centralized access to SELinux MMAC (middleware MAC) implementation. This
  * class is responsible for loading the appropriate mac_permissions.xml file
@@ -63,42 +64,21 @@
     // to synchronize access during policy load and access attempts.
     private static List<Policy> sPolicies = new ArrayList<>();
 
-    // Data policy override version file.
-    private static final String DATA_VERSION_FILE =
-            Environment.getDataDirectory() + "/security/current/selinux_version";
+    /** Path to version on rootfs */
+    private static final File VERSION_FILE = new File("/selinux_version");
 
-    // Base policy version file.
-    private static final String BASE_VERSION_FILE = "/selinux_version";
+    /** Path to MAC permissions on system image */
+    private static final File MAC_PERMISSIONS = new File(Environment.getRootDirectory(),
+            "/etc/security/mac_permissions.xml");
 
-    // Whether override security policies should be loaded.
-    private static final boolean USE_OVERRIDE_POLICY = useOverridePolicy();
+    /** Path to app contexts on rootfs */
+    private static final File SEAPP_CONTEXTS = new File("/seapp_contexts");
 
-    // Data override mac_permissions.xml policy file.
-    private static final String DATA_MAC_PERMISSIONS =
-            Environment.getDataDirectory() + "/security/current/mac_permissions.xml";
+    /** Calculated hash of {@link #SEAPP_CONTEXTS} */
+    private static final byte[] SEAPP_CONTEXTS_HASH = returnHash(SEAPP_CONTEXTS);
 
-    // Base mac_permissions.xml policy file.
-    private static final String BASE_MAC_PERMISSIONS =
-            Environment.getRootDirectory() + "/etc/security/mac_permissions.xml";
-
-    // Determine which mac_permissions.xml file to use.
-    private static final String MAC_PERMISSIONS = USE_OVERRIDE_POLICY ?
-            DATA_MAC_PERMISSIONS : BASE_MAC_PERMISSIONS;
-
-    // Data override seapp_contexts policy file.
-    private static final String DATA_SEAPP_CONTEXTS =
-            Environment.getDataDirectory() + "/security/current/seapp_contexts";
-
-    // Base seapp_contexts policy file.
-    private static final String BASE_SEAPP_CONTEXTS = "/seapp_contexts";
-
-    // Determine which seapp_contexts file to use.
-    private static final String SEAPP_CONTEXTS = USE_OVERRIDE_POLICY ?
-            DATA_SEAPP_CONTEXTS : BASE_SEAPP_CONTEXTS;
-
-    // Stores the hash of the last used seapp_contexts file.
-    private static final String SEAPP_HASH_FILE =
-            Environment.getDataDirectory().toString() + "/system/seapp_hash";
+    /** Attribute where {@link #SEAPP_CONTEXTS_HASH} is stored */
+    private static final String XATTR_SEAPP_HASH = "user.seapp_hash";
 
     // Append privapp to existing seinfo label
     private static final String PRIVILEGED_APP_STR = ":privapp";
@@ -332,71 +312,42 @@
     }
 
     /**
-     * Determines if a recursive restorecon on /data/data and /data/user is needed.
-     * It does this by comparing the SHA-1 of the seapp_contexts file against the
-     * stored hash at /data/system/seapp_hash.
+     * Determines if a recursive restorecon on the given package data directory
+     * is needed. It does this by comparing the SHA-1 of the seapp_contexts file
+     * against the stored hash in an xattr.
+     * <p>
+     * Note that the xattr isn't in the 'security' namespace, so this should
+     * only be run on directories owned by the system.
      *
      * @return Returns true if the restorecon should occur or false otherwise.
      */
-    public static boolean shouldRestorecon() {
-        // Any error with the seapp_contexts file should be fatal
-        byte[] currentHash = null;
+    public static boolean isRestoreconNeeded(File file) {
         try {
-            currentHash = returnHash(SEAPP_CONTEXTS);
-        } catch (IOException ioe) {
-            Slog.e(TAG, "Error with hashing seapp_contexts.", ioe);
-            return false;
+            final byte[] buf = new byte[20];
+            final int len = Os.getxattr(file.getAbsolutePath(), XATTR_SEAPP_HASH, buf);
+            if ((len == 20) && Arrays.equals(SEAPP_CONTEXTS_HASH, buf)) {
+                return false;
+            }
+        } catch (ErrnoException e) {
+            if (e.errno != OsConstants.ENODATA) {
+                Slog.e(TAG, "Failed to read seapp hash for " + file, e);
+            }
         }
 
-        // Push past any error with the stored hash file
-        byte[] storedHash = null;
-        try {
-            storedHash = IoUtils.readFileAsByteArray(SEAPP_HASH_FILE);
-        } catch (IOException ioe) {
-            Slog.w(TAG, "Error opening " + SEAPP_HASH_FILE + ". Assuming first boot.");
-        }
-
-        return (storedHash == null || !MessageDigest.isEqual(storedHash, currentHash));
+        return true;
     }
 
     /**
-     * Stores the SHA-1 of the seapp_contexts to /data/system/seapp_hash.
+     * Stores the SHA-1 of the seapp_contexts into an xattr.
+     * <p>
+     * Note that the xattr isn't in the 'security' namespace, so this should
+     * only be run on directories owned by the system.
      */
-    public static void setRestoreconDone() {
+    public static void setRestoreconDone(File file) {
         try {
-            final byte[] currentHash = returnHash(SEAPP_CONTEXTS);
-            dumpHash(new File(SEAPP_HASH_FILE), currentHash);
-        } catch (IOException ioe) {
-            Slog.e(TAG, "Error with saving hash to " + SEAPP_HASH_FILE, ioe);
-        }
-    }
-
-    /**
-     * Dump the contents of a byte array to a specified file.
-     *
-     * @param file The file that receives the byte array content.
-     * @param content A byte array that will be written to the specified file.
-     * @throws IOException if any failed I/O operation occured.
-     *         Included is the failure to atomically rename the tmp
-     *         file used in the process.
-     */
-    private static void dumpHash(File file, byte[] content) throws IOException {
-        FileOutputStream fos = null;
-        File tmp = null;
-        try {
-            tmp = File.createTempFile("seapp_hash", ".journal", file.getParentFile());
-            tmp.setReadable(true);
-            fos = new FileOutputStream(tmp);
-            fos.write(content);
-            fos.getFD().sync();
-            if (!tmp.renameTo(file)) {
-                throw new IOException("Failure renaming " + file.getCanonicalPath());
-            }
-        } finally {
-            if (tmp != null) {
-                tmp.delete();
-            }
-            IoUtils.closeQuietly(fos);
+            Os.setxattr(file.getAbsolutePath(), XATTR_SEAPP_HASH, SEAPP_CONTEXTS_HASH, 0);
+        } catch (ErrnoException e) {
+            Slog.e(TAG, "Failed to persist seapp hash in " + file, e);
         }
     }
 
@@ -405,33 +356,15 @@
      *
      * @param file The path to the file given as a string.
      * @return Returns the SHA-1 of the file as a byte array.
-     * @throws IOException if any failed I/O operations occured.
      */
-    private static byte[] returnHash(String file) throws IOException {
+    private static byte[] returnHash(File file) {
         try {
-            final byte[] contents = IoUtils.readFileAsByteArray(file);
+            final byte[] contents = IoUtils.readFileAsByteArray(file.getAbsolutePath());
             return MessageDigest.getInstance("SHA-1").digest(contents);
-        } catch (NoSuchAlgorithmException nsae) {
-            throw new RuntimeException(nsae);  // impossible
+        } catch (IOException | NoSuchAlgorithmException e) {
+            throw new RuntimeException(e);
         }
     }
-
-    private static boolean useOverridePolicy() {
-        try {
-            final String overrideVersion = IoUtils.readFileAsString(DATA_VERSION_FILE);
-            final String baseVersion = IoUtils.readFileAsString(BASE_VERSION_FILE);
-            if (overrideVersion.equals(baseVersion)) {
-                return true;
-            }
-            Slog.e(TAG, "Override policy version '" + overrideVersion + "' doesn't match " +
-                   "base version '" + baseVersion + "'. Skipping override policy files.");
-        } catch (FileNotFoundException fnfe) {
-            // Override version file doesn't have to exist so silently ignore.
-        } catch (IOException ioe) {
-            Slog.w(TAG, "Skipping override policy files.", ioe);
-        }
-        return false;
-    }
 }
 
 /**
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index 5cf92a9..2921032 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -49,6 +49,7 @@
     void setPrivateFlags(int pkgPrivateFlags) {
         this.pkgPrivateFlags = pkgPrivateFlags
                 & (ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
-                        | ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK);
+                | ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK
+                | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER);
     }
 }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index ef2f29b..bbbe693 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -16,23 +16,44 @@
 
 package com.android.server.pm;
 
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
-import static android.os.Process.SYSTEM_UID;
+import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
+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_SYSTEM_ONLY;
 import static android.os.Process.PACKAGE_INFO_GID;
+import static android.os.Process.SYSTEM_UID;
 import static com.android.server.pm.PackageManagerService.DEBUG_DOMAIN_VERIFICATION;
 
 import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
 import android.content.pm.IntentFilterVerificationInfo;
+import android.content.pm.PackageCleanItem;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageUserState;
+import android.content.pm.PermissionInfo;
 import android.content.pm.ResolveInfo;
+import android.content.pm.Signature;
+import android.content.pm.UserInfo;
+import android.content.pm.VerifierDeviceIdentity;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
@@ -47,14 +68,22 @@
 import android.os.UserManager;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
-import android.util.AtomicFile;
 import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.AtomicFile;
+import android.util.Log;
 import android.util.LogPrinter;
+import android.util.Slog;
+import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
 import android.util.SparseLongArray;
+import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.BackgroundThread;
+import com.android.internal.os.InstallerConnection.InstallerException;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
@@ -65,53 +94,37 @@
 import com.android.server.pm.PackageManagerService.DumpState;
 import com.android.server.pm.PermissionsState.PermissionState;
 
-import java.io.FileNotFoundException;
-import java.util.Collection;
+import libcore.io.IoUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.ComponentInfo;
-import android.content.pm.PackageCleanItem;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
-import android.content.pm.PermissionInfo;
-import android.content.pm.Signature;
-import android.content.pm.UserInfo;
-import android.content.pm.PackageUserState;
-import android.content.pm.VerifierDeviceIdentity;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Log;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
-import android.util.Xml;
-
+import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
+import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
+import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
 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.Map.Entry;
-
-import libcore.io.IoUtils;
 
 /**
  * Holds information about dynamic settings.
@@ -206,6 +219,22 @@
     private static final String ATTR_SDK_VERSION = "sdkVersion";
     private static final String ATTR_DATABASE_VERSION = "databaseVersion";
 
+    // Bookkeeping for restored permission grants
+    private static final String TAG_RESTORED_RUNTIME_PERMISSIONS = "restored-perms";
+    // package name: ATTR_PACKAGE_NAME
+    private static final String TAG_PERMISSION_ENTRY = "perm";
+    // permission name: ATTR_NAME
+    // permission granted (boolean): ATTR_GRANTED
+    private static final String ATTR_USER_SET = "set";
+    private static final String ATTR_USER_FIXED = "fixed";
+    private static final String ATTR_REVOKE_ON_UPGRADE = "rou";
+
+    // Flag mask of restored permission grants that are applied at install time
+    private static final int USER_RUNTIME_GRANT_MASK =
+            FLAG_PERMISSION_USER_SET
+            | FLAG_PERMISSION_USER_FIXED
+            | FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+
     private final Object mLock;
 
     private final RuntimePermissionPersistence mRuntimePermissionsPersistence;
@@ -227,6 +256,26 @@
     private final ArrayMap<String, IntentFilterVerificationInfo> mRestoredIntentFilterVerifications =
             new ArrayMap<String, IntentFilterVerificationInfo>();
 
+    // Bookkeeping for restored user permission grants
+    final class RestoredPermissionGrant {
+        String permissionName;
+        boolean granted;
+        int grantBits;
+
+        RestoredPermissionGrant(String name, boolean isGranted, int theGrantBits) {
+            permissionName = name;
+            granted = isGranted;
+            grantBits = theGrantBits;
+        }
+    }
+
+    // This would be more compact as a flat array of restored grants or something, but we
+    // may have quite a few, especially during early device lifetime, and avoiding all those
+    // linear lookups will be important.
+    private final SparseArray<ArrayMap<String, ArraySet<RestoredPermissionGrant>>>
+            mRestoredUserGrants =
+                new SparseArray<ArrayMap<String, ArraySet<RestoredPermissionGrant>>>();
+
     private static int mFirstAvailableUid = 0;
 
     /** Map from volume UUID to {@link VersionInfo} */
@@ -377,7 +426,7 @@
         return mPackages.get(name);
     }
 
-    void setInstallStatus(String pkgName, int status) {
+    void setInstallStatus(String pkgName, final int status) {
         PackageSetting p = mPackages.get(pkgName);
         if(p != null) {
             if(p.getInstallStatus() != status) {
@@ -386,6 +435,43 @@
         }
     }
 
+    void applyPendingPermissionGrantsLPw(String packageName, int userId) {
+        ArrayMap<String, ArraySet<RestoredPermissionGrant>> grantsByPackage =
+                mRestoredUserGrants.get(userId);
+        if (grantsByPackage == null || grantsByPackage.size() == 0) {
+            return;
+        }
+
+        ArraySet<RestoredPermissionGrant> grants = grantsByPackage.get(packageName);
+        if (grants == null || grants.size() == 0) {
+            return;
+        }
+
+        final PackageSetting ps = mPackages.get(packageName);
+        if (ps == null) {
+            Slog.e(TAG, "Can't find supposedly installed package " + packageName);
+            return;
+        }
+        final PermissionsState perms = ps.getPermissionsState();
+
+        for (RestoredPermissionGrant grant : grants) {
+            BasePermission bp = mPermissions.get(grant.permissionName);
+            if (bp != null) {
+                if (grant.granted) {
+                    perms.grantRuntimePermission(bp, userId);
+                }
+                perms.updatePermissionFlags(bp, userId, USER_RUNTIME_GRANT_MASK, grant.grantBits);
+            }
+        }
+
+        // And remove it from the pending-grant bookkeeping
+        grantsByPackage.remove(packageName);
+        if (grantsByPackage.size() < 1) {
+            mRestoredUserGrants.remove(userId);
+        }
+        writeRuntimePermissionsForUserLPr(userId, false);
+    }
+
     void setInstallerPackageName(String pkgName, String installerPkgName) {
         PackageSetting p = mPackages.get(pkgName);
         if (p != null) {
@@ -421,7 +507,7 @@
     boolean disableSystemPackageLPw(String name) {
         final PackageSetting p = mPackages.get(name);
         if(p == null) {
-            Log.w(PackageManagerService.TAG, "Package:"+name+" is not an installed package");
+            Log.w(PackageManagerService.TAG, "Package " + name + " is not an installed package");
             return false;
         }
         final PackageSetting dp = mDisabledSysPackages.get(name);
@@ -446,7 +532,7 @@
     PackageSetting enableSystemPackageLPw(String name) {
         PackageSetting p = mDisabledSysPackages.get(name);
         if(p == null) {
-            Log.w(PackageManagerService.TAG, "Package:"+name+" is not disabled");
+            Log.w(PackageManagerService.TAG, "Package " + name + " is not disabled");
             return null;
         }
         // Reset flag in ApplicationInfo object
@@ -1333,7 +1419,7 @@
             throws XmlPullParserException, IOException {
         IntentFilterVerificationInfo ivi = new IntentFilterVerificationInfo(parser);
         packageSetting.setIntentFilterVerificationInfo(ivi);
-        Log.d(TAG, "Read domain verification for package:" + ivi.getPackageName());
+        Log.d(TAG, "Read domain verification for package: " + ivi.getPackageName());
     }
 
     private void readRestoredIntentFilterVerifications(XmlPullParser parser)
@@ -1467,7 +1553,7 @@
                     String name = parser.getAttributeValue(null, ATTR_NAME);
                     ps = mPackages.get(name);
                     if (ps == null) {
-                        Slog.w(PackageManagerService.TAG, "No package known for stopped package: "
+                        Slog.w(PackageManagerService.TAG, "No package known for stopped package "
                                 + name);
                         XmlUtils.skipCurrentTag(parser);
                         continue;
@@ -1714,6 +1800,14 @@
         }
     }
 
+    // Specifically for backup/restore
+    public void processRestoredPermissionGrantLPr(String pkgName, String permission,
+            boolean isGranted, int restoredFlagSet, int userId)
+            throws IOException, XmlPullParserException {
+        mRuntimePermissionsPersistence.rememberRestoredUserGrantLPr(
+                pkgName, permission, isGranted, restoredFlagSet, userId);
+    }
+
     void writeDefaultAppsLPr(XmlSerializer serializer, int userId)
             throws IllegalArgumentException, IllegalStateException, IOException {
         serializer.startTag(null, TAG_DEFAULT_APPS);
@@ -2031,7 +2125,7 @@
                         }
                     } else {
                         Slog.w(PackageManagerService.TAG,
-                                "No package known for stopped package: " + name);
+                                "No package known for stopped package " + name);
                     }
                     XmlUtils.skipCurrentTag(parser);
                 } else {
@@ -2249,11 +2343,11 @@
         JournaledFile journal = new JournaledFile(mPackageListFilename, tempFile);
 
         final File writeTarget = journal.chooseForWrite();
-        FileOutputStream fstr = null;
-        BufferedOutputStream str = null;
+        FileOutputStream fstr;
+        BufferedWriter writer = null;
         try {
             fstr = new FileOutputStream(writeTarget);
-            str = new BufferedOutputStream(fstr);
+            writer = new BufferedWriter(new OutputStreamWriter(fstr, Charset.defaultCharset()));
             FileUtils.setPermissions(fstr.getFD(), 0640, SYSTEM_UID, PACKAGE_INFO_GID);
 
             StringBuilder sb = new StringBuilder();
@@ -2270,7 +2364,7 @@
                 final int[] gids = pkg.getPermissionsState().computeGids(userIds);
 
                 // Avoid any application that has a space in its path.
-                if (dataPath.indexOf(" ") >= 0)
+                if (dataPath.indexOf(' ') >= 0)
                     continue;
 
                 // we store on each line the following information for now:
@@ -2292,7 +2386,7 @@
                 sb.setLength(0);
                 sb.append(ai.packageName);
                 sb.append(" ");
-                sb.append((int)ai.uid);
+                sb.append(ai.uid);
                 sb.append(isDebug ? " 1 " : " 0 ");
                 sb.append(dataPath);
                 sb.append(" ");
@@ -2308,15 +2402,15 @@
                     sb.append("none");
                 }
                 sb.append("\n");
-                str.write(sb.toString().getBytes());
+                writer.append(sb);
             }
-            str.flush();
+            writer.flush();
             FileUtils.sync(fstr);
-            str.close();
+            writer.close();
             journal.commit();
         } catch (Exception e) {
             Slog.wtf(TAG, "Failed to write packages.list", e);
-            IoUtils.closeQuietly(str);
+            IoUtils.closeQuietly(writer);
             journal.rollback();
         }
     }
@@ -2799,9 +2893,9 @@
             }
 
             if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Reading default preferred " + f);
-            FileInputStream str = null;
+            InputStream str = null;
             try {
-                str = new FileInputStream(f);
+                str = new BufferedInputStream(new FileInputStream(f));
                 XmlPullParser parser = Xml.newPullParser();
                 parser.setInput(str, null);
 
@@ -2852,7 +2946,7 @@
         for (int i=0; i<tmpPa.countCategories(); i++) {
             String cat = tmpPa.getCategory(i);
             if (cat.equals(Intent.CATEGORY_DEFAULT)) {
-                flags |= PackageManager.MATCH_DEFAULT_ONLY;
+                flags |= MATCH_DEFAULT_ONLY;
             } else {
                 intent.addCategory(cat);
             }
@@ -2951,6 +3045,7 @@
     private void applyDefaultPreferredActivityLPw(PackageManagerService service,
             Intent intent, int flags, ComponentName cn, String scheme, PatternMatcher ssp,
             IntentFilter.AuthorityEntry auth, PatternMatcher path, int userId) {
+        flags = service.updateFlagsForResolve(flags, userId, intent);
         List<ResolveInfo> ri = service.mActivities.queryIntent(intent,
                 intent.getType(), flags, 0);
         if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Queried " + intent
@@ -3002,7 +3097,7 @@
                         filter.addCategory(cat);
                     }
                 }
-                if ((flags&PackageManager.MATCH_DEFAULT_ONLY) != 0) {
+                if ((flags & MATCH_DEFAULT_ONLY) != 0) {
                     filter.addCategory(Intent.CATEGORY_DEFAULT);
                 }
                 if (scheme != null) {
@@ -3658,16 +3753,18 @@
             int userHandle) {
         String[] volumeUuids;
         String[] names;
-        int[] uids;
+        int[] appIds;
         String[] seinfos;
+        int[] targetSdkVersions;
         int packagesCount;
         synchronized (mPackages) {
             Collection<PackageSetting> packages = mPackages.values();
             packagesCount = packages.size();
             volumeUuids = new String[packagesCount];
             names = new String[packagesCount];
-            uids = new int[packagesCount];
+            appIds = new int[packagesCount];
             seinfos = new String[packagesCount];
+            targetSdkVersions = new int[packagesCount];
             Iterator<PackageSetting> packagesIterator = packages.iterator();
             for (int i = 0; i < packagesCount; i++) {
                 PackageSetting ps = packagesIterator.next();
@@ -3680,15 +3777,23 @@
                 // required args and call the installer after mPackages lock has been released
                 volumeUuids[i] = ps.volumeUuid;
                 names[i] = ps.name;
-                uids[i] = UserHandle.getUid(userHandle, ps.appId);
+                appIds[i] = ps.appId;
                 seinfos[i] = ps.pkg.applicationInfo.seinfo;
+                targetSdkVersions[i] = ps.pkg.applicationInfo.targetSdkVersion;
             }
         }
         for (int i = 0; i < packagesCount; i++) {
             if (names[i] == null) {
                 continue;
             }
-            installer.createUserData(volumeUuids[i], names[i], uids[i], userHandle, seinfos[i]);
+            // TODO: triage flags!
+            final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+            try {
+                installer.createAppData(volumeUuids[i], names[i], userHandle, flags, appIds[i],
+                        seinfos[i], targetSdkVersions[i]);
+            } catch (InstallerException e) {
+                Slog.w(TAG, "Failed to prepare app data", e);
+            }
         }
         synchronized (mPackages) {
             applyDefaultPreferredAppsLPw(service, userHandle);
@@ -3788,60 +3893,12 @@
         return cmp != null ? Arrays.toString(cmp.toArray()) : "[]";
     }
 
-    boolean isEnabledAndVisibleLPr(ComponentInfo componentInfo, int flags, int userId) {
-        return isEnabledLPr(componentInfo, flags, userId)
-                && isVisibleLPr(componentInfo, flags);
-    }
+    boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, int flags, int userId) {
+        final PackageSetting ps = mPackages.get(componentInfo.packageName);
+        if (ps == null) return false;
 
-    private boolean isEnabledLPr(ComponentInfo componentInfo, int flags, int userId) {
-        if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
-            return true;
-        }
-        final String pkgName = componentInfo.packageName;
-        final PackageSetting packageSettings = mPackages.get(pkgName);
-        if (PackageManagerService.DEBUG_SETTINGS) {
-            Log.v(PackageManagerService.TAG, "isEnabledLock - packageName = "
-                    + componentInfo.packageName + " componentName = " + componentInfo.name);
-            Log.v(PackageManagerService.TAG, "enabledComponents: "
-                    + compToString(packageSettings.getEnabledComponents(userId)));
-            Log.v(PackageManagerService.TAG, "disabledComponents: "
-                    + compToString(packageSettings.getDisabledComponents(userId)));
-        }
-        if (packageSettings == null) {
-            return false;
-        }
-        PackageUserState ustate = packageSettings.readUserState(userId);
-        if ((flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0) {
-            if (ustate.enabled == COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
-                return true;
-            }
-        }
-        if (ustate.enabled == COMPONENT_ENABLED_STATE_DISABLED
-                || ustate.enabled == COMPONENT_ENABLED_STATE_DISABLED_USER
-                || ustate.enabled == COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
-                || (packageSettings.pkg != null && !packageSettings.pkg.applicationInfo.enabled
-                    && ustate.enabled == COMPONENT_ENABLED_STATE_DEFAULT)) {
-            return false;
-        }
-        if (ustate.enabledComponents != null
-                && ustate.enabledComponents.contains(componentInfo.name)) {
-            return true;
-        }
-        if (ustate.disabledComponents != null
-                && ustate.disabledComponents.contains(componentInfo.name)) {
-            return false;
-        }
-        return componentInfo.enabled;
-    }
-
-    private boolean isVisibleLPr(ComponentInfo componentInfo, int flags) {
-        if ((flags & PackageManager.GET_ENCRYPTION_UNAWARE_COMPONENTS) != 0) {
-            return true;
-        }
-        if ((flags & PackageManager.MATCH_ENCRYPTION_AWARE_ONLY) != 0) {
-            return componentInfo.encryptionAware;
-        }
-        return true;
+        final PackageUserState userState = ps.readUserState(userId);
+        return userState.isMatch(componentInfo, flags);
     }
 
     String getInstallerPackageNameLPr(String packageName) {
@@ -3923,7 +3980,6 @@
      * given {@link VolumeInfo#fsUuid}.
      */
     List<PackageSetting> getVolumePackagesLPr(String volumeUuid) {
-        Preconditions.checkNotNull(volumeUuid);
         ArrayList<PackageSetting> res = new ArrayList<>();
         for (int i = 0; i < mPackages.size(); i++) {
             final PackageSetting setting = mPackages.valueAt(i);
@@ -4440,6 +4496,48 @@
         pw.print(mReadMessages.toString());
     }
 
+    void dumpRestoredPermissionGrantsLPr(PrintWriter pw, DumpState dumpState) {
+        if (mRestoredUserGrants.size() > 0) {
+            pw.println();
+            pw.println("Restored (pending) permission grants:");
+            for (int userIndex = 0; userIndex < mRestoredUserGrants.size(); userIndex++) {
+                ArrayMap<String, ArraySet<RestoredPermissionGrant>> grantsByPackage =
+                        mRestoredUserGrants.valueAt(userIndex);
+                if (grantsByPackage != null && grantsByPackage.size() > 0) {
+                    final int userId = mRestoredUserGrants.keyAt(userIndex);
+                    pw.print("  User "); pw.println(userId);
+
+                    for (int pkgIndex = 0; pkgIndex < grantsByPackage.size(); pkgIndex++) {
+                        ArraySet<RestoredPermissionGrant> grants = grantsByPackage.valueAt(pkgIndex);
+                        if (grants != null && grants.size() > 0) {
+                            final String pkgName = grantsByPackage.keyAt(pkgIndex);
+                            pw.print("    "); pw.print(pkgName); pw.println(" :");
+
+                            for (RestoredPermissionGrant g : grants) {
+                                pw.print("      ");
+                                pw.print(g.permissionName);
+                                if (g.granted) {
+                                    pw.print(" GRANTED");
+                                }
+                                if ((g.grantBits&FLAG_PERMISSION_USER_SET) != 0) {
+                                    pw.print(" user_set");
+                                }
+                                if ((g.grantBits&FLAG_PERMISSION_USER_FIXED) != 0) {
+                                    pw.print(" user_fixed");
+                                }
+                                if ((g.grantBits&FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
+                                    pw.print(" revoke_on_upgrade");
+                                }
+                                pw.println();
+                            }
+                        }
+                    }
+                }
+            }
+            pw.println();
+        }
+    }
+
     private static void dumpSplitNames(PrintWriter pw, PackageParser.Package pkg) {
         if (pkg == null) {
             pw.print("unknown");
@@ -4537,7 +4635,6 @@
 
     private final class RuntimePermissionPersistence {
         private static final long WRITE_PERMISSIONS_DELAY_MILLIS = 200;
-
         private static final long MAX_WRITE_PERMISSIONS_DELAY_MILLIS = 2000;
 
         private final Handler mHandler = new MyHandler();
@@ -4654,6 +4751,7 @@
                 serializer.setFeature(
                         "http://xmlpull.org/v1/doc/features.html#indent-output", true);
                 serializer.startDocument(null, true);
+
                 serializer.startTag(null, TAG_RUNTIME_PERMISSIONS);
 
                 String fingerprint = mFingerprints.get(userId);
@@ -4682,6 +4780,51 @@
                 }
 
                 serializer.endTag(null, TAG_RUNTIME_PERMISSIONS);
+
+                // Now any restored permission grants that are waiting for the apps
+                // in question to be installed.  These are stored as per-package
+                // TAG_RESTORED_RUNTIME_PERMISSIONS blocks, each containing some
+                // number of individual permission grant entities.
+                if (mRestoredUserGrants.get(userId) != null) {
+                    ArrayMap<String, ArraySet<RestoredPermissionGrant>> restoredGrants =
+                            mRestoredUserGrants.get(userId);
+                    if (restoredGrants != null) {
+                        final int pkgCount = restoredGrants.size();
+                        for (int i = 0; i < pkgCount; i++) {
+                            final ArraySet<RestoredPermissionGrant> pkgGrants =
+                                    restoredGrants.valueAt(i);
+                            if (pkgGrants != null && pkgGrants.size() > 0) {
+                                final String pkgName = restoredGrants.keyAt(i);
+                                serializer.startTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS);
+                                serializer.attribute(null, ATTR_PACKAGE_NAME, pkgName);
+
+                                final int N = pkgGrants.size();
+                                for (int z = 0; z < N; z++) {
+                                    RestoredPermissionGrant g = pkgGrants.valueAt(z);
+                                    serializer.startTag(null, TAG_PERMISSION_ENTRY);
+                                    serializer.attribute(null, ATTR_NAME, g.permissionName);
+
+                                    if (g.granted) {
+                                        serializer.attribute(null, ATTR_GRANTED, "true");
+                                    }
+
+                                    if ((g.grantBits&FLAG_PERMISSION_USER_SET) != 0) {
+                                        serializer.attribute(null, ATTR_USER_SET, "true");
+                                    }
+                                    if ((g.grantBits&FLAG_PERMISSION_USER_FIXED) != 0) {
+                                        serializer.attribute(null, ATTR_USER_FIXED, "true");
+                                    }
+                                    if ((g.grantBits&FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
+                                        serializer.attribute(null, ATTR_REVOKE_ON_UPGRADE, "true");
+                                    }
+                                    serializer.endTag(null, TAG_PERMISSION_ENTRY);
+                                }
+                                serializer.endTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS);
+                            }
+                        }
+                    }
+                }
+
                 serializer.endDocument();
                 destination.finishWrite(out);
 
@@ -4755,6 +4898,31 @@
             }
         }
 
+        // Backup/restore support
+
+        public void rememberRestoredUserGrantLPr(String pkgName, String permission,
+                boolean isGranted, int restoredFlagSet, int userId) {
+            // This change will be remembered at write-settings time
+            ArrayMap<String, ArraySet<RestoredPermissionGrant>> grantsByPackage =
+                    mRestoredUserGrants.get(userId);
+            if (grantsByPackage == null) {
+                grantsByPackage = new ArrayMap<String, ArraySet<RestoredPermissionGrant>>();
+                mRestoredUserGrants.put(userId, grantsByPackage);
+            }
+
+            ArraySet<RestoredPermissionGrant> grants = grantsByPackage.get(pkgName);
+            if (grants == null) {
+                grants = new ArraySet<RestoredPermissionGrant>();
+                grantsByPackage.put(pkgName, grants);
+            }
+
+            RestoredPermissionGrant grant = new RestoredPermissionGrant(permission,
+                    isGranted, restoredFlagSet);
+            grants.add(grant);
+        }
+
+        // Private internals
+
         private void parseRuntimePermissionsLPr(XmlPullParser parser, int userId)
                 throws IOException, XmlPullParserException {
             final int outerDepth = parser.getDepth();
@@ -4794,6 +4962,46 @@
                         }
                         parsePermissionsLPr(parser, sus.getPermissionsState(), userId);
                     } break;
+
+                    case TAG_RESTORED_RUNTIME_PERMISSIONS: {
+                        final String pkgName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
+                        parseRestoredRuntimePermissionsLPr(parser, pkgName, userId);
+                    } break;
+                }
+            }
+        }
+
+        private void parseRestoredRuntimePermissionsLPr(XmlPullParser parser,
+                final String pkgName, final int userId) throws IOException, XmlPullParserException {
+            final 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;
+                }
+
+                switch (parser.getName()) {
+                    case TAG_PERMISSION_ENTRY: {
+                        final String permName = parser.getAttributeValue(null, ATTR_NAME);
+                        final boolean isGranted = "true".equals(
+                                parser.getAttributeValue(null, ATTR_GRANTED));
+
+                        int permBits = 0;
+                        if ("true".equals(parser.getAttributeValue(null, ATTR_USER_SET))) {
+                            permBits |= FLAG_PERMISSION_USER_SET;
+                        }
+                        if ("true".equals(parser.getAttributeValue(null, ATTR_USER_FIXED))) {
+                            permBits |= FLAG_PERMISSION_USER_FIXED;
+                        }
+                        if ("true".equals(parser.getAttributeValue(null, ATTR_REVOKE_ON_UPGRADE))) {
+                            permBits |= FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+                        }
+
+                        if (isGranted || permBits != 0) {
+                            rememberRestoredUserGrantLPr(pkgName, permName, isGranted, permBits, userId);
+                        }
+                    } break;
                 }
             }
         }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index f5da103..0f614ca 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -25,13 +25,16 @@
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
 import android.app.IStopUserCallback;
+import android.app.admin.DevicePolicyManager;
 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.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.Bundle;
@@ -43,6 +46,7 @@
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
+import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
@@ -59,7 +63,6 @@
 import android.system.OsConstants;
 import android.util.AtomicFile;
 import android.util.Log;
-import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -69,11 +72,13 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IAppOpsService;
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.LocalServices;
+import com.android.server.pm.Installer.StorageFlags;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -123,6 +128,8 @@
     private static final String ATTR_USER_VERSION = "version";
     private static final String ATTR_PROFILE_GROUP_ID = "profileGroupId";
     private static final String ATTR_RESTRICTED_PROFILE_PARENT_ID = "restrictedProfileParentId";
+    private static final String ATTR_SEED_ACCOUNT_NAME = "seedAccountName";
+    private static final String ATTR_SEED_ACCOUNT_TYPE = "seedAccountType";
     private static final String TAG_GUEST_RESTRICTIONS = "guestRestrictions";
     private static final String TAG_USERS = "users";
     private static final String TAG_USER = "user";
@@ -130,6 +137,7 @@
     private static final String TAG_DEVICE_POLICY_RESTRICTIONS = "device_policy_restrictions";
     private static final String TAG_ENTRY = "entry";
     private static final String TAG_VALUE = "value";
+    private static final String TAG_SEED_ACCOUNT_OPTIONS = "seedAccountOptions";
     private static final String ATTR_KEY = "key";
     private static final String ATTR_VALUE_TYPE = "type";
     private static final String ATTR_MULTIPLE = "m";
@@ -166,6 +174,10 @@
 
     private static final String XATTR_SERIAL = "user.serial";
 
+    // Tron counters
+    private static final String TRON_GUEST_CREATED = "users_guest_created";
+    private static final String TRON_USER_CREATED = "users_user_created";
+
     private final Context mContext;
     private final PackageManagerService mPm;
     private final Object mPackagesLock;
@@ -178,16 +190,35 @@
     private final File mUsersDir;
     private final File mUserListFile;
 
-    @GuardedBy("mUsersLock")
-    private final SparseArray<UserInfo> mUsers = new SparseArray<>();
-
     /**
-     * This collection contains each user's account name if the user chose to set one up
-     * during the initial user creation process.  Keeping this information separate from mUsers
-     * to avoid accidentally leak it.
+     * User-related information that is used for persisting to flash. Only UserInfo is
+     * directly exposed to other system apps.
      */
+    private static class UserData {
+        // Basic user information and properties
+        UserInfo info;
+        // Account name used when there is a strong association between a user and an account
+        String account;
+        // Account information for seeding into a newly created user. This could also be
+        // used for login validation for an existing user, for updating their credentials.
+        // In the latter case, data may not need to be persisted as it is only valid for the
+        // current login session.
+        String seedAccountName;
+        String seedAccountType;
+        PersistableBundle seedAccountOptions;
+        // Whether to perist the seed account information to be available after a boot
+        boolean persistSeedData;
+
+        void clearSeedAccountData() {
+            seedAccountName = null;
+            seedAccountType = null;
+            seedAccountOptions = null;
+            persistSeedData = false;
+        }
+    }
+
     @GuardedBy("mUsersLock")
-    private final SparseArray<String> mUserAccounts = new SparseArray<>();
+    private final SparseArray<UserData> mUsers = new SparseArray<>();
 
     /**
      * User restrictions set via UserManager.  This doesn't include restrictions set by
@@ -271,6 +302,14 @@
     private final ArrayList<UserRestrictionsListener> mUserRestrictionsListeners =
             new ArrayList<>();
 
+    private final LockPatternUtils mLockPatternUtils;
+
+    /**
+     * Whether all users should be created ephemeral.
+     */
+    @GuardedBy("mUsersLock")
+    private boolean mForceEphemeralUsers;
+
     private static UserManagerService sInstance;
 
     public static UserManagerService getInstance() {
@@ -315,6 +354,7 @@
         }
         mLocalService = new LocalService();
         LocalServices.addService(UserManagerInternal.class, mLocalService);
+        mLockPatternUtils = new LockPatternUtils(mContext);
     }
 
     void systemReady() {
@@ -323,7 +363,7 @@
         synchronized (mUsersLock) {
             final int userSize = mUsers.size();
             for (int i = 0; i < userSize; i++) {
-                UserInfo ui = mUsers.valueAt(i);
+                UserInfo ui = mUsers.valueAt(i).info;
                 if ((ui.partial || ui.guestToRemove || ui.isEphemeral()) && i != 0) {
                     partials.add(ui);
                 }
@@ -351,20 +391,25 @@
     public String getUserAccount(int userId) {
         checkManageUserAndAcrossUsersFullPermission("get user account");
         synchronized (mUsersLock) {
-            return mUserAccounts.get(userId);
+            return mUsers.get(userId).account;
         }
     }
 
     @Override
     public void setUserAccount(int userId, String accountName) {
         checkManageUserAndAcrossUsersFullPermission("set user account");
-        UserInfo userToUpdate = null;
+        UserData userToUpdate = null;
         synchronized (mPackagesLock) {
             synchronized (mUsersLock) {
-                String currentAccount = mUserAccounts.get(userId);
+                final UserData userData = mUsers.get(userId);
+                if (userData == null) {
+                    Slog.e(LOG_TAG, "User not found for setting user account: u" + userId);
+                    return;
+                }
+                String currentAccount = userData.account;
                 if (!Objects.equal(currentAccount, accountName)) {
-                    mUserAccounts.put(userId, accountName);
-                    userToUpdate = mUsers.get(userId);
+                    userData.account = accountName;
+                    userToUpdate = userData;
                 }
             }
 
@@ -380,7 +425,7 @@
         synchronized (mUsersLock) {
             final int userSize = mUsers.size();
             for (int i = 0; i < userSize; i++) {
-                UserInfo ui = mUsers.valueAt(i);
+                UserInfo ui = mUsers.valueAt(i).info;
                 if (ui.isPrimary() && !mRemovingUserIds.get(ui.id)) {
                     return ui;
                 }
@@ -396,7 +441,7 @@
             ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
             final int userSize = mUsers.size();
             for (int i = 0; i < userSize; i++) {
-                UserInfo ui = mUsers.valueAt(i);
+                UserInfo ui = mUsers.valueAt(i).info;
                 if (ui.partial) {
                     continue;
                 }
@@ -433,7 +478,7 @@
         }
         final int userSize = mUsers.size();
         for (int i = 0; i < userSize; i++) {
-            UserInfo profile = mUsers.valueAt(i);
+            UserInfo profile = mUsers.valueAt(i).info;
             if (!isProfileOf(user, profile)) {
                 continue;
             }
@@ -451,7 +496,7 @@
     @Override
     public int getCredentialOwnerProfile(int userHandle) {
         checkManageUsersPermission("get the credential owner");
-        if (!LockPatternUtils.isSeparateWorkChallengeEnabled()) {
+        if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(userHandle)) {
             synchronized (mUsersLock) {
                 UserInfo profileParent = getProfileParentLU(userHandle);
                 if (profileParent != null) {
@@ -515,21 +560,13 @@
     }
 
     private void broadcastProfileAvailabilityChanges(UserHandle profileHandle,
-            UserHandle parentHandle, Bundle extras) {
-        // Send intent to profile
-        Intent intent = new Intent(Intent.ACTION_AVAILABILITY_CHANGED);
+            UserHandle parentHandle, boolean inQuietMode) {
+        Intent intent = new Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
+        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);
-        intent.putExtras(extras);
-        mContext.sendBroadcastAsUser(intent, profileHandle);
-
-        // Send intent to parent
-        if (parentHandle != null) {
-            intent = new Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
-            intent.putExtra(Intent.EXTRA_USER, profileHandle);
-            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-            intent.putExtras(extras);
-            mContext.sendBroadcastAsUser(intent, parentHandle);
-        }
+        mContext.sendBroadcastAsUser(intent, parentHandle);
     }
 
     @Override
@@ -548,15 +585,26 @@
             }
             if (profile.isQuietModeEnabled() != enableQuietMode) {
                 profile.flags ^= UserInfo.FLAG_QUIET_MODE;
-                writeUserLP(profile);
+                writeUserLP(getUserDataLU(profile.id));
                 changed = true;
             }
         }
         if (changed) {
-            Bundle extras = new Bundle();
-            extras.putBoolean(Intent.EXTRA_QUIET_MODE, enableQuietMode);
-            broadcastProfileAvailabilityChanges(profile.getUserHandle(),
-                    parent != null ? parent.getUserHandle() : null, extras);
+            long identity = Binder.clearCallingIdentity();
+            try {
+                if (enableQuietMode) {
+                    ActivityManagerNative.getDefault().stopUser(userHandle, /* force */true, null);
+                } else {
+                    ActivityManagerNative.getDefault().startUserInBackground(userHandle);
+                }
+            } catch (RemoteException e) {
+                Slog.e(LOG_TAG, "fail to start/stop user for quiet mode", e);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+
+            broadcastProfileAvailabilityChanges(profile.getUserHandle(), parent.getUserHandle(),
+                    enableQuietMode);
         }
     }
 
@@ -568,7 +616,7 @@
                 info = getUserInfoLU(userHandle);
             }
             if (info == null || !info.isManagedProfile()) {
-                throw new IllegalArgumentException("User " + userHandle + " is not a profile");
+                return false;
             }
             return info.isQuietModeEnabled();
         }
@@ -584,7 +632,7 @@
             }
             if (info != null && !info.isEnabled()) {
                 info.flags ^= UserInfo.FLAG_DISABLED;
-                writeUserLP(info);
+                writeUserLP(getUserDataLU(info.id));
             }
         }
     }
@@ -624,13 +672,22 @@
      * Should be locked on mUsers before calling this.
      */
     private UserInfo getUserInfoLU(int userId) {
-        UserInfo ui = mUsers.get(userId);
+        final UserData userData = mUsers.get(userId);
         // If it is partial and not in the process of being removed, return as unknown user.
-        if (ui != null && ui.partial && !mRemovingUserIds.get(userId)) {
+        if (userData != null && userData.info.partial && !mRemovingUserIds.get(userId)) {
             Slog.w(LOG_TAG, "getUserInfo: unknown user #" + userId);
             return null;
         }
-        return ui;
+        return userData != null ? userData.info : null;
+    }
+
+    private UserData getUserDataLU(int userId) {
+        final UserData userData = mUsers.get(userId);
+        // If it is partial and not in the process of being removed, return as unknown user.
+        if (userData != null && userData.info.partial && !mRemovingUserIds.get(userId)) {
+            return null;
+        }
+        return userData;
     }
 
     /**
@@ -639,6 +696,17 @@
      */
     private UserInfo getUserInfoNoChecks(int userId) {
         synchronized (mUsersLock) {
+            final UserData userData = mUsers.get(userId);
+            return userData != null ? userData.info : null;
+        }
+    }
+
+    /**
+     * Obtains {@link #mUsersLock} and return UserData from mUsers.
+     * <p>No permissions checking or any addition checks are made</p>
+     */
+    private UserData getUserDataNoChecks(int userId) {
+        synchronized (mUsersLock) {
             return mUsers.get(userId);
         }
     }
@@ -653,14 +721,14 @@
         checkManageUsersPermission("rename users");
         boolean changed = false;
         synchronized (mPackagesLock) {
-            UserInfo info = getUserInfoNoChecks(userId);
-            if (info == null || info.partial) {
+            UserData userData = getUserDataNoChecks(userId);
+            if (userData == null || userData.info.partial) {
                 Slog.w(LOG_TAG, "setUserName: unknown user #" + userId);
                 return;
             }
-            if (name != null && !name.equals(info.name)) {
-                info.name = name;
-                writeUserLP(info);
+            if (name != null && !name.equals(userData.info.name)) {
+                userData.info.name = name;
+                writeUserLP(userData);
                 changed = true;
             }
         }
@@ -672,23 +740,15 @@
     @Override
     public void setUserIcon(int userId, Bitmap bitmap) {
         checkManageUsersPermission("update users");
-        long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (mPackagesLock) {
-                UserInfo info = getUserInfoNoChecks(userId);
-                if (info == null || info.partial) {
-                    Slog.w(LOG_TAG, "setUserIcon: unknown user #" + userId);
-                    return;
-                }
-                writeBitmapLP(info, bitmap);
-                writeUserLP(info);
-            }
-            sendUserInfoChangedBroadcast(userId);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
+        if (hasUserRestriction(UserManager.DISALLOW_SET_USER_ICON, userId)) {
+            Log.w(LOG_TAG, "Cannot set user icon. DISALLOW_SET_USER_ICON is enabled.");
+            return;
         }
+        mLocalService.setUserIcon(userId, bitmap);
     }
 
+
+
     private void sendUserInfoChangedBroadcast(int userId) {
         Intent changedIntent = new Intent(Intent.ACTION_USER_INFO_CHANGED);
         changedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
@@ -728,20 +788,20 @@
     public void makeInitialized(int userId) {
         checkManageUsersPermission("makeInitialized");
         boolean scheduleWriteUser = false;
-        UserInfo info;
+        UserData userData;
         synchronized (mUsersLock) {
-            info = mUsers.get(userId);
-            if (info == null || info.partial) {
+            userData = mUsers.get(userId);
+            if (userData == null || userData.info.partial) {
                 Slog.w(LOG_TAG, "makeInitialized: unknown user #" + userId);
                 return;
             }
-            if ((info.flags & UserInfo.FLAG_INITIALIZED) == 0) {
-                info.flags |= UserInfo.FLAG_INITIALIZED;
+            if ((userData.info.flags & UserInfo.FLAG_INITIALIZED) == 0) {
+                userData.info.flags |= UserInfo.FLAG_INITIALIZED;
                 scheduleWriteUser = true;
             }
         }
         if (scheduleWriteUser) {
-            scheduleWriteUser(info);
+            scheduleWriteUser(userData);
         }
     }
 
@@ -817,7 +877,7 @@
                 writeUserListLP();
             }
             if (localChanged) {
-                writeUserLP(getUserInfoNoChecks(userId));
+                writeUserLP(getUserDataNoChecks(userId));
             }
         }
 
@@ -932,7 +992,7 @@
 
             if (!UserRestrictionsUtils.areEqual(prevBaseRestrictions, newRestrictions)) {
                 mBaseUserRestrictions.put(userId, newRestrictions);
-                scheduleWriteUser(getUserInfoNoChecks(userId));
+                scheduleWriteUser(getUserDataNoChecks(userId));
             }
         }
 
@@ -1080,7 +1140,7 @@
         final int totalUserCount = mUsers.size();
         // Skip over users being removed
         for (int i = 0; i < totalUserCount; i++) {
-            UserInfo user = mUsers.valueAt(i);
+            UserInfo user = mUsers.valueAt(i).info;
             if (!mRemovingUserIds.get(user.id)
                     && !user.isGuest() && !user.partial) {
                 aliveUserCount++;
@@ -1198,7 +1258,7 @@
             int type;
             while ((type = parser.next()) != XmlPullParser.START_TAG
                     && type != XmlPullParser.END_DOCUMENT) {
-                ;
+                // Skip
             }
 
             if (type != XmlPullParser.START_TAG) {
@@ -1226,16 +1286,15 @@
                     final String name = parser.getName();
                     if (name.equals(TAG_USER)) {
                         String id = parser.getAttributeValue(null, ATTR_ID);
-                        Pair<UserInfo, String> userPair = readUserLP(Integer.parseInt(id));
 
-                        if (userPair != null) {
-                            UserInfo user = userPair.first;
-                            String account = userPair.second;
+                        UserData userData = readUserLP(Integer.parseInt(id));
+
+                        if (userData != null) {
                             synchronized (mUsersLock) {
-                                mUsers.put(user.id, user);
-                                mUserAccounts.put(user.id, account);
-                                if (mNextSerialNumber < 0 || mNextSerialNumber <= user.id) {
-                                    mNextSerialNumber = user.id + 1;
+                                mUsers.put(userData.info.id, userData);
+                                if (mNextSerialNumber < 0
+                                        || mNextSerialNumber <= userData.info.id) {
+                                    mNextSerialNumber = userData.info.id + 1;
                                 }
                             }
                         }
@@ -1279,20 +1338,21 @@
         int userVersion = mUserVersion;
         if (userVersion < 1) {
             // Assign a proper name for the owner, if not initialized correctly before
-            UserInfo user = getUserInfoNoChecks(UserHandle.USER_SYSTEM);
-            if ("Primary".equals(user.name)) {
-                user.name = mContext.getResources().getString(com.android.internal.R.string.owner_name);
-                scheduleWriteUser(user);
+            UserData userData = getUserDataNoChecks(UserHandle.USER_SYSTEM);
+            if ("Primary".equals(userData.info.name)) {
+                userData.info.name =
+                        mContext.getResources().getString(com.android.internal.R.string.owner_name);
+                scheduleWriteUser(userData);
             }
             userVersion = 1;
         }
 
         if (userVersion < 2) {
             // Owner should be marked as initialized
-            UserInfo user = getUserInfoNoChecks(UserHandle.USER_SYSTEM);
-            if ((user.flags & UserInfo.FLAG_INITIALIZED) == 0) {
-                user.flags |= UserInfo.FLAG_INITIALIZED;
-                scheduleWriteUser(user);
+            UserData userData = getUserDataNoChecks(UserHandle.USER_SYSTEM);
+            if ((userData.info.flags & UserInfo.FLAG_INITIALIZED) == 0) {
+                userData.info.flags |= UserInfo.FLAG_INITIALIZED;
+                scheduleWriteUser(userData);
             }
             userVersion = 2;
         }
@@ -1311,12 +1371,13 @@
             final boolean splitSystemUser = UserManager.isSplitSystemUser();
             synchronized (mUsersLock) {
                 for (int i = 0; i < mUsers.size(); i++) {
-                    UserInfo user = mUsers.valueAt(i);
+                    UserData userData = mUsers.valueAt(i);
                     // In non-split mode, only user 0 can have restricted profiles
-                    if (!splitSystemUser && user.isRestricted()
-                            && (user.restrictedProfileParentId == UserInfo.NO_PROFILE_GROUP_ID)) {
-                        user.restrictedProfileParentId = UserHandle.USER_SYSTEM;
-                        scheduleWriteUser(user);
+                    if (!splitSystemUser && userData.info.isRestricted()
+                            && (userData.info.restrictedProfileParentId
+                                    == UserInfo.NO_PROFILE_GROUP_ID)) {
+                        userData.info.restrictedProfileParentId = UserHandle.USER_SYSTEM;
+                        scheduleWriteUser(userData);
                     }
                 }
             }
@@ -1346,8 +1407,10 @@
         UserInfo system = new UserInfo(UserHandle.USER_SYSTEM,
                 mContext.getResources().getString(com.android.internal.R.string.owner_name), null,
                 flags);
+        UserData userData = new UserData();
+        userData.info = system;
         synchronized (mUsersLock) {
-            mUsers.put(system.id, system);
+            mUsers.put(system.id, userData);
         }
         mNextSerialNumber = MIN_USER_ID;
         mUserVersion = USER_VERSION;
@@ -1361,17 +1424,17 @@
         initDefaultGuestRestrictions();
 
         writeUserListLP();
-        writeUserLP(system);
+        writeUserLP(userData);
     }
 
-    private void scheduleWriteUser(UserInfo userInfo) {
+    private void scheduleWriteUser(UserData UserData) {
         if (DBG) {
             debug("scheduleWriteUser");
         }
         // No need to wrap it within a lock -- worst case, we'll just post the same message
         // twice.
-        if (!mHandler.hasMessages(WRITE_USER_MSG, userInfo)) {
-            Message msg = mHandler.obtainMessage(WRITE_USER_MSG, userInfo);
+        if (!mHandler.hasMessages(WRITE_USER_MSG, UserData)) {
+            Message msg = mHandler.obtainMessage(WRITE_USER_MSG, UserData);
             mHandler.sendMessageDelayed(msg, WRITE_USER_DELAY);
         }
     }
@@ -1383,12 +1446,12 @@
      *   <name>Primary</name>
      * </user>
      */
-    private void writeUserLP(UserInfo userInfo) {
+    private void writeUserLP(UserData userData) {
         if (DBG) {
-            debug("writeUserLP " + userInfo);
+            debug("writeUserLP " + userData);
         }
         FileOutputStream fos = null;
-        AtomicFile userFile = new AtomicFile(new File(mUsersDir, userInfo.id + XML_SUFFIX));
+        AtomicFile userFile = new AtomicFile(new File(mUsersDir, userData.info.id + XML_SUFFIX));
         try {
             fos = userFile.startWrite();
             final BufferedOutputStream bos = new BufferedOutputStream(fos);
@@ -1399,6 +1462,7 @@
             serializer.startDocument(null, true);
             serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
 
+            final UserInfo userInfo = userData.info;
             serializer.startTag(null, TAG_USER);
             serializer.attribute(null, ATTR_ID, Integer.toString(userInfo.id));
             serializer.attribute(null, ATTR_SERIAL_NO, Integer.toString(userInfo.serialNumber));
@@ -1423,6 +1487,15 @@
                 serializer.attribute(null, ATTR_RESTRICTED_PROFILE_PARENT_ID,
                         Integer.toString(userInfo.restrictedProfileParentId));
             }
+            // Write seed data
+            if (userData.persistSeedData) {
+                if (userData.seedAccountName != null) {
+                    serializer.attribute(null, ATTR_SEED_ACCOUNT_NAME, userData.seedAccountName);
+                }
+                if (userData.seedAccountType != null) {
+                    serializer.attribute(null, ATTR_SEED_ACCOUNT_TYPE, userData.seedAccountType);
+                }
+            }
             serializer.startTag(null, TAG_NAME);
             serializer.text(userInfo.name);
             serializer.endTag(null, TAG_NAME);
@@ -1433,23 +1506,24 @@
                         mDevicePolicyLocalUserRestrictions.get(userInfo.id),
                         TAG_DEVICE_POLICY_RESTRICTIONS);
             }
-            // Update the account field if it is set.
-            String account;
-            synchronized (mUsersLock) {
-                account = mUserAccounts.get(userInfo.id);
-            }
-            if (account != null) {
+
+            if (userData.account != null) {
                 serializer.startTag(null, TAG_ACCOUNT);
-                serializer.text(account);
+                serializer.text(userData.account);
                 serializer.endTag(null, TAG_ACCOUNT);
             }
 
+            if (userData.persistSeedData && userData.seedAccountOptions != null) {
+                serializer.startTag(null, TAG_SEED_ACCOUNT_OPTIONS);
+                userData.seedAccountOptions.saveToXml(serializer);
+                serializer.endTag(null, TAG_SEED_ACCOUNT_OPTIONS);
+            }
             serializer.endTag(null, TAG_USER);
 
             serializer.endDocument();
             userFile.finishWrite(fos);
         } catch (Exception ioe) {
-            Slog.e(LOG_TAG, "Error writing user info " + userInfo.id + "\n" + ioe);
+            Slog.e(LOG_TAG, "Error writing user info " + userData.info.id + "\n" + ioe);
             userFile.failWrite(fos);
         }
     }
@@ -1496,7 +1570,7 @@
             synchronized (mUsersLock) {
                 userIdsToWrite = new int[mUsers.size()];
                 for (int i = 0; i < userIdsToWrite.length; i++) {
-                    UserInfo user = mUsers.valueAt(i);
+                    UserInfo user = mUsers.valueAt(i).info;
                     userIdsToWrite[i] = user.id;
                 }
             }
@@ -1516,7 +1590,7 @@
         }
     }
 
-    private Pair<UserInfo, String> readUserLP(int id) {
+    private UserData readUserLP(int id) {
         int flags = 0;
         int serialNumber = id;
         String name = null;
@@ -1528,6 +1602,10 @@
         int restrictedProfileParentId = UserInfo.NO_PROFILE_GROUP_ID;
         boolean partial = false;
         boolean guestToRemove = false;
+        boolean persistSeedData = false;
+        String seedAccountName = null;
+        String seedAccountType = null;
+        PersistableBundle seedAccountOptions = null;
         Bundle baseRestrictions = new Bundle();
         Bundle localRestrictions = new Bundle();
 
@@ -1541,7 +1619,7 @@
             int type;
             while ((type = parser.next()) != XmlPullParser.START_TAG
                     && type != XmlPullParser.END_DOCUMENT) {
-                ;
+                // Skip
             }
 
             if (type != XmlPullParser.START_TAG) {
@@ -1573,6 +1651,12 @@
                     guestToRemove = true;
                 }
 
+                seedAccountName = parser.getAttributeValue(null, ATTR_SEED_ACCOUNT_NAME);
+                seedAccountType = parser.getAttributeValue(null, ATTR_SEED_ACCOUNT_TYPE);
+                if (seedAccountName != null || seedAccountType != null) {
+                    persistSeedData = true;
+                }
+
                 int outerDepth = parser.getDepth();
                 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                        && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
@@ -1594,10 +1678,14 @@
                         if (type == XmlPullParser.TEXT) {
                             account = parser.getText();
                         }
+                    } else if (TAG_SEED_ACCOUNT_OPTIONS.equals(tag)) {
+                        seedAccountOptions = PersistableBundle.restoreFromXml(parser);
+                        persistSeedData = true;
                     }
                 }
             }
 
+            // Create the UserInfo object that gets passed around
             UserInfo userInfo = new UserInfo(id, name, iconPath, flags);
             userInfo.serialNumber = serialNumber;
             userInfo.creationTime = creationTime;
@@ -1606,12 +1694,21 @@
             userInfo.guestToRemove = guestToRemove;
             userInfo.profileGroupId = profileGroupId;
             userInfo.restrictedProfileParentId = restrictedProfileParentId;
+
+            // Create the UserData object that's internal to this class
+            UserData userData = new UserData();
+            userData.info = userInfo;
+            userData.account = account;
+            userData.seedAccountName = seedAccountName;
+            userData.seedAccountType = seedAccountType;
+            userData.persistSeedData = persistSeedData;
+            userData.seedAccountOptions = seedAccountOptions;
+
             synchronized (mRestrictionsLock) {
                 mBaseUserRestrictions.put(id, baseRestrictions);
                 mDevicePolicyLocalUserRestrictions.put(id, localRestrictions);
             }
-            return new Pair<>(userInfo, account);
-
+            return userData;
         } catch (IOException ioe) {
         } catch (XmlPullParserException pe) {
         } finally {
@@ -1656,26 +1753,6 @@
     }
 
     /**
-     * Removes all the restrictions files (res_<packagename>) for a given user.
-     * Does not do any permissions checking.
-     */
-    private void cleanAppRestrictions(int userId) {
-        synchronized (mPackagesLock) {
-            File dir = Environment.getUserSystemDirectory(userId);
-            String[] files = dir.list();
-            if (files == null) return;
-            for (String fileName : files) {
-                if (fileName.startsWith(RESTRICTIONS_FILE_PREFIX)) {
-                    File resFile = new File(dir, fileName);
-                    if (resFile.exists()) {
-                        resFile.delete();
-                    }
-                }
-            }
-        }
-    }
-
-    /**
      * Removes the app restrictions file for a specific package and user id, if it exists.
      */
     private void cleanAppRestrictionsForPackage(String pkg, int userId) {
@@ -1713,13 +1790,14 @@
         final boolean isRestricted = (flags & UserInfo.FLAG_RESTRICTED) != 0;
         final long ident = Binder.clearCallingIdentity();
         UserInfo userInfo;
+        UserData userData;
         final int userId;
         try {
             synchronized (mPackagesLock) {
-                UserInfo parent = null;
+                UserData parent = null;
                 if (parentId != UserHandle.USER_NULL) {
                     synchronized (mUsersLock) {
-                        parent = getUserInfoLU(parentId);
+                        parent = getUserDataLU(parentId);
                     }
                     if (parent == null) return null;
                 }
@@ -1748,7 +1826,7 @@
                                 + "specified");
                         return null;
                     }
-                    if (!parent.canHaveProfile()) {
+                    if (!parent.info.canHaveProfile()) {
                         Log.w(LOG_TAG, "Cannot add restricted profile - profiles cannot be "
                                 + "created for the specified parent user id " + parentId);
                         return null;
@@ -1766,33 +1844,41 @@
                     }
                 }
 
-                if (parent != null && parent.isEphemeral()) {
-                    flags |= UserInfo.FLAG_EPHEMERAL;
-                }
                 userId = getNextAvailableId();
-                userInfo = new UserInfo(userId, name, null, flags);
-                userInfo.serialNumber = mNextSerialNumber++;
-                long now = System.currentTimeMillis();
-                userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;
-                userInfo.partial = true;
-                Environment.getUserSystemDirectory(userInfo.id).mkdirs();
+                Environment.getUserSystemDirectory(userId).mkdirs();
+                boolean ephemeralGuests = Resources.getSystem()
+                        .getBoolean(com.android.internal.R.bool.config_guestUserEphemeral);
+
                 synchronized (mUsersLock) {
-                    mUsers.put(userId, userInfo);
+                    // Add ephemeral flag to guests/users if required. Also inherit it from parent.
+                    if ((isGuest && ephemeralGuests) || mForceEphemeralUsers
+                            || (parent != null && parent.info.isEphemeral())) {
+                        flags |= UserInfo.FLAG_EPHEMERAL;
+                    }
+
+                    userInfo = new UserInfo(userId, name, null, flags);
+                    userInfo.serialNumber = mNextSerialNumber++;
+                    long now = System.currentTimeMillis();
+                    userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;
+                    userInfo.partial = true;
+                    userData = new UserData();
+                    userData.info = userInfo;
+                    mUsers.put(userId, userData);
                 }
                 writeUserListLP();
                 if (parent != null) {
                     if (isManagedProfile) {
-                        if (parent.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
-                            parent.profileGroupId = parent.id;
+                        if (parent.info.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
+                            parent.info.profileGroupId = parent.info.id;
                             writeUserLP(parent);
                         }
-                        userInfo.profileGroupId = parent.profileGroupId;
+                        userInfo.profileGroupId = parent.info.profileGroupId;
                     } else if (isRestricted) {
-                        if (parent.restrictedProfileParentId == UserInfo.NO_PROFILE_GROUP_ID) {
-                            parent.restrictedProfileParentId = parent.id;
+                        if (parent.info.restrictedProfileParentId == UserInfo.NO_PROFILE_GROUP_ID) {
+                            parent.info.restrictedProfileParentId = parent.info.id;
                             writeUserLP(parent);
                         }
-                        userInfo.restrictedProfileParentId = parent.restrictedProfileParentId;
+                        userInfo.restrictedProfileParentId = parent.info.restrictedProfileParentId;
                     }
                 }
             }
@@ -1812,7 +1898,7 @@
             mPm.createNewUser(userId);
             userInfo.partial = false;
             synchronized (mPackagesLock) {
-                writeUserLP(userInfo);
+                writeUserLP(userData);
             }
             updateUserIds();
             Bundle restrictions = new Bundle();
@@ -1829,6 +1915,7 @@
             addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
             mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
                     android.Manifest.permission.MANAGE_USERS);
+            MetricsLogger.count(mContext, isGuest ? TRON_GUEST_CREATED : TRON_USER_CREATED, 1);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -1838,6 +1925,7 @@
     /**
      * @hide
      */
+    @Override
     public UserInfo createRestrictedProfile(String name, int parentUserId) {
         checkManageUsersPermission("setupRestrictedProfile");
         final UserInfo user = createProfileForUser(name, UserInfo.FLAG_RESTRICTED, parentUserId);
@@ -1862,7 +1950,7 @@
         synchronized (mUsersLock) {
             final int size = mUsers.size();
             for (int i = 0; i < size; i++) {
-                final UserInfo user = mUsers.valueAt(i);
+                final UserInfo user = mUsers.valueAt(i).info;
                 if (user.isGuest() && !user.guestToRemove && !mRemovingUserIds.get(user.id)) {
                     return user;
                 }
@@ -1877,6 +1965,7 @@
      * @param userHandle the userid of the current guest
      * @return whether the user could be marked for deletion
      */
+    @Override
     public boolean markGuestForDeletion(int userHandle) {
         checkManageUsersPermission("Only the system can remove users");
         if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(
@@ -1887,15 +1976,15 @@
 
         long ident = Binder.clearCallingIdentity();
         try {
-            final UserInfo user;
+            final UserData userData;
             synchronized (mPackagesLock) {
                 synchronized (mUsersLock) {
-                    user = mUsers.get(userHandle);
-                    if (userHandle == 0 || user == null || mRemovingUserIds.get(userHandle)) {
+                    userData = mUsers.get(userHandle);
+                    if (userHandle == 0 || userData == null || mRemovingUserIds.get(userHandle)) {
                         return false;
                     }
                 }
-                if (!user.isGuest()) {
+                if (!userData.info.isGuest()) {
                     return false;
                 }
                 // We set this to a guest user that is to be removed. This is a temporary state
@@ -1903,11 +1992,11 @@
                 // removed. This user will still show up in getUserInfo() calls.
                 // If we don't get around to removing this Guest user, it will be purged on next
                 // startup.
-                user.guestToRemove = true;
+                userData.info.guestToRemove = true;
                 // Mark it as disabled, so that it isn't returned any more when
                 // profiles are queried.
-                user.flags |= UserInfo.FLAG_DISABLED;
-                writeUserLP(user);
+                userData.info.flags |= UserInfo.FLAG_DISABLED;
+                writeUserLP(userData);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -1920,6 +2009,7 @@
      * after the user's processes have been terminated.
      * @param userHandle the user's id
      */
+    @Override
     public boolean removeUser(int userHandle) {
         checkManageUsersPermission("Only the system can remove users");
         if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(
@@ -1930,7 +2020,7 @@
 
         long ident = Binder.clearCallingIdentity();
         try {
-            final UserInfo user;
+            final UserData userData;
             int currentUser = ActivityManager.getCurrentUser();
             if (currentUser == userHandle) {
                 Log.w(LOG_TAG, "Current user cannot be removed");
@@ -1938,8 +2028,8 @@
             }
             synchronized (mPackagesLock) {
                 synchronized (mUsersLock) {
-                    user = mUsers.get(userHandle);
-                    if (userHandle == 0 || user == null || mRemovingUserIds.get(userHandle)) {
+                    userData = mUsers.get(userHandle);
+                    if (userHandle == 0 || userData == null || mRemovingUserIds.get(userHandle)) {
                         return false;
                     }
 
@@ -1957,18 +2047,18 @@
                 // Set this to a partially created user, so that the user will be purged
                 // on next startup, in case the runtime stops now before stopping and
                 // removing the user completely.
-                user.partial = true;
+                userData.info.partial = true;
                 // Mark it as disabled, so that it isn't returned any more when
                 // profiles are queried.
-                user.flags |= UserInfo.FLAG_DISABLED;
-                writeUserLP(user);
+                userData.info.flags |= UserInfo.FLAG_DISABLED;
+                writeUserLP(userData);
             }
 
-            if (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
-                    && user.isManagedProfile()) {
+            if (userData.info.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
+                    && userData.info.isManagedProfile()) {
                 // Send broadcast to notify system that the user removed was a
                 // managed user.
-                sendProfileRemovedBroadcast(user.profileGroupId, user.id);
+                sendProfileRemovedBroadcast(userData.info.profileGroupId, userData.info.id);
             }
 
             if (DBG) Slog.i(LOG_TAG, "Stopping user " + userHandle);
@@ -2013,6 +2103,7 @@
                                         + userHandle);
                             }
                             new Thread() {
+                                @Override
                                 public void run() {
                                     // Clean up any ActivityManager state
                                     LocalServices.getService(ActivityManagerInternal.class)
@@ -2037,7 +2128,6 @@
         // Remove this user from the list
         synchronized (mUsersLock) {
             mUsers.remove(userHandle);
-            mUserAccounts.delete(userHandle);
             mIsUserManaged.delete(userHandle);
         }
         synchronized (mRestrictionsLock) {
@@ -2054,7 +2144,13 @@
             writeUserListLP();
         }
         updateUserIds();
-        removeDirectoryRecursive(Environment.getUserSystemDirectory(userHandle));
+        File userDir = Environment.getUserSystemDirectory(userHandle);
+        File renamedUserDir = Environment.getUserSystemDirectory(UserHandle.USER_NULL - userHandle);
+        if (userDir.renameTo(renamedUserDir)) {
+            removeDirectoryRecursive(renamedUserDir);
+        } else {
+            removeDirectoryRecursive(userDir);
+        }
     }
 
     private void removeDirectoryRecursive(File parent) {
@@ -2073,6 +2169,7 @@
         managedProfileIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY |
                 Intent.FLAG_RECEIVER_FOREGROUND);
         managedProfileIntent.putExtra(Intent.EXTRA_USER, new UserHandle(removedUserId));
+        managedProfileIntent.putExtra(Intent.EXTRA_USER_HANDLE, removedUserId);
         mContext.sendBroadcastAsUser(managedProfileIntent, new UserHandle(parentUserId), null);
     }
 
@@ -2115,29 +2212,6 @@
         }
     }
 
-    private void unhideAllInstalledAppsForUser(final int userHandle) {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                List<ApplicationInfo> apps =
-                        mPm.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES,
-                                userHandle).getList();
-                final long ident = Binder.clearCallingIdentity();
-                try {
-                    for (ApplicationInfo appInfo : apps) {
-                        if ((appInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0
-                                && (appInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HIDDEN)
-                                        != 0) {
-                            mPm.setApplicationHiddenSettingAsUser(appInfo.packageName, false,
-                                    userHandle);
-                        }
-                    }
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
-                }
-            }
-        });
-    }
     private int getUidForPackage(String packageName) {
         long ident = Binder.clearCallingIdentity();
         try {
@@ -2367,14 +2441,14 @@
         synchronized (mUsersLock) {
             final int userSize = mUsers.size();
             for (int i = 0; i < userSize; i++) {
-                if (!mUsers.valueAt(i).partial) {
+                if (!mUsers.valueAt(i).info.partial) {
                     num++;
                 }
             }
             final int[] newUsers = new int[num];
             int n = 0;
             for (int i = 0; i < userSize; i++) {
-                if (!mUsers.valueAt(i).partial) {
+                if (!mUsers.valueAt(i).info.partial) {
                     newUsers[n++] = mUsers.keyAt(i);
                 }
             }
@@ -2383,28 +2457,41 @@
     }
 
     /**
-     * Called right before a user starts.  This will not be called for the system user.
+     * Called right before a user is started. This gives us a chance to prepare
+     * app storage and apply any user restrictions.
      */
     public void onBeforeStartUser(int userId) {
-        synchronized (mRestrictionsLock) {
-            applyUserRestrictionsLR(userId);
+        mPm.reconcileAppsData(userId, Installer.FLAG_DE_STORAGE);
+
+        if (userId != UserHandle.USER_SYSTEM) {
+            synchronized (mRestrictionsLock) {
+                applyUserRestrictionsLR(userId);
+            }
         }
     }
 
     /**
+     * Called right before a user is unlocked. This gives us a chance to prepare
+     * app storage.
+     */
+    public void onBeforeUnlockUser(int userId) {
+        mPm.reconcileAppsData(userId, Installer.FLAG_CE_STORAGE);
+    }
+
+    /**
      * 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) {
-        UserInfo user = getUserInfoNoChecks(userId);
-        if (user == null || user.partial) {
+        UserData userData = getUserDataNoChecks(userId);
+        if (userData == null || userData.info.partial) {
             Slog.w(LOG_TAG, "userForeground: unknown user #" + userId);
             return;
         }
         long now = System.currentTimeMillis();
         if (now > EPOCH_PLUS_30_YEARS) {
-            user.lastLoggedInTime = now;
-            scheduleWriteUser(user);
+            userData.info.lastLoggedInTime = now;
+            scheduleWriteUser(userData);
         }
     }
 
@@ -2496,6 +2583,91 @@
     }
 
     @Override
+    public void setSeedAccountData(int userId, String accountName, String accountType,
+            PersistableBundle accountOptions, boolean persist) {
+        checkManageUsersPermission("Require MANAGE_USERS permission to set user seed data");
+        synchronized (mPackagesLock) {
+            final UserData userData;
+            synchronized (mUsersLock) {
+                userData = getUserDataLU(userId);
+                if (userData == null) {
+                    Slog.e(LOG_TAG, "No such user for settings seed data u=" + userId);
+                    return;
+                }
+                userData.seedAccountName = accountName;
+                userData.seedAccountType = accountType;
+                userData.seedAccountOptions = accountOptions;
+                userData.persistSeedData = persist;
+            }
+            if (persist) {
+                writeUserLP(userData);
+            }
+        }
+    }
+
+    @Override
+    public String getSeedAccountName() throws RemoteException {
+        checkManageUsersPermission("Cannot get seed account information");
+        synchronized (mUsersLock) {
+            UserData userData = getUserDataLU(UserHandle.getCallingUserId());
+            return userData.seedAccountName;
+        }
+    }
+
+    @Override
+    public String getSeedAccountType() throws RemoteException {
+        checkManageUsersPermission("Cannot get seed account information");
+        synchronized (mUsersLock) {
+            UserData userData = getUserDataLU(UserHandle.getCallingUserId());
+            return userData.seedAccountType;
+        }
+    }
+
+    @Override
+    public PersistableBundle getSeedAccountOptions() throws RemoteException {
+        checkManageUsersPermission("Cannot get seed account information");
+        synchronized (mUsersLock) {
+            UserData userData = getUserDataLU(UserHandle.getCallingUserId());
+            return userData.seedAccountOptions;
+        }
+    }
+
+    @Override
+    public void clearSeedAccountData() throws RemoteException {
+        checkManageUsersPermission("Cannot clear seed account information");
+        synchronized (mPackagesLock) {
+            UserData userData;
+            synchronized (mUsersLock) {
+                userData = getUserDataLU(UserHandle.getCallingUserId());
+                if (userData == null) return;
+                userData.clearSeedAccountData();
+            }
+            writeUserLP(userData);
+        }
+    }
+
+    @Override
+    public boolean someUserHasSeedAccount(String accountName, String accountType)
+            throws RemoteException {
+        checkManageUsersPermission("Cannot check seed account information");
+        synchronized (mUsersLock) {
+            final int userSize = mUsers.size();
+            for (int i = 0; i < userSize; i++) {
+                final UserData data = mUsers.valueAt(i);
+                if (data.info.isInitialized()) continue;
+                if (data.seedAccountName == null || !data.seedAccountName.equals(accountName)) {
+                    continue;
+                }
+                if (data.seedAccountType == null || !data.seedAccountType.equals(accountType)) {
+                    continue;
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out,
             FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
         (new Shell()).exec(this, in, out, err, args, resultReceiver);
@@ -2552,35 +2724,36 @@
             synchronized (mUsersLock) {
                 pw.println("Users:");
                 for (int i = 0; i < mUsers.size(); i++) {
-                    UserInfo user = mUsers.valueAt(i);
-                    if (user == null) {
+                    UserData userData = mUsers.valueAt(i);
+                    if (userData == null) {
                         continue;
                     }
-                    final int userId = user.id;
-                    pw.print("  "); pw.print(user);
-                    pw.print(" serialNo="); pw.print(user.serialNumber);
+                    UserInfo userInfo = userData.info;
+                    final int userId = userInfo.id;
+                    pw.print("  "); pw.print(userInfo);
+                    pw.print(" serialNo="); pw.print(userInfo.serialNumber);
                     if (mRemovingUserIds.get(userId)) {
                         pw.print(" <removing> ");
                     }
-                    if (user.partial) {
+                    if (userInfo.partial) {
                         pw.print(" <partial>");
                     }
                     pw.println();
                     pw.print("    Created: ");
-                    if (user.creationTime == 0) {
+                    if (userInfo.creationTime == 0) {
                         pw.println("<unknown>");
                     } else {
                         sb.setLength(0);
-                        TimeUtils.formatDuration(now - user.creationTime, sb);
+                        TimeUtils.formatDuration(now - userInfo.creationTime, sb);
                         sb.append(" ago");
                         pw.println(sb);
                     }
                     pw.print("    Last logged in: ");
-                    if (user.lastLoggedInTime == 0) {
+                    if (userInfo.lastLoggedInTime == 0) {
                         pw.println("<unknown>");
                     } else {
                         sb.setLength(0);
-                        TimeUtils.formatDuration(now - user.lastLoggedInTime, sb);
+                        TimeUtils.formatDuration(now - userInfo.lastLoggedInTime, sb);
                         sb.append(" ago");
                         pw.println(sb);
                     }
@@ -2589,22 +2762,35 @@
                     pw.println("    Restrictions:");
                     synchronized (mRestrictionsLock) {
                         UserRestrictionsUtils.dumpRestrictions(
-                                pw, "      ", mBaseUserRestrictions.get(user.id));
+                                pw, "      ", mBaseUserRestrictions.get(userInfo.id));
                         pw.println("    Device policy local restrictions:");
                         UserRestrictionsUtils.dumpRestrictions(
-                                pw, "      ", mDevicePolicyLocalUserRestrictions.get(user.id));
+                                pw, "      ", mDevicePolicyLocalUserRestrictions.get(userInfo.id));
                         pw.println("    Effective restrictions:");
                         UserRestrictionsUtils.dumpRestrictions(
-                                pw, "      ", mCachedEffectiveUserRestrictions.get(user.id));
+                                pw, "      ", mCachedEffectiveUserRestrictions.get(userInfo.id));
                     }
-                    pw.println();
-                    String accountName = mUserAccounts.get(userId);
-                    if (accountName != null) {
-                        pw.print("    Account name: " + accountName);
+
+                    if (userData.account != null) {
+                        pw.print("    Account name: " + userData.account);
                         pw.println();
                     }
+
+                    if (userData.seedAccountName != null) {
+                        pw.print("    Seed account name: " + userData.seedAccountName);
+                        pw.println();
+                        if (userData.seedAccountType != null) {
+                            pw.print("         account type: " + userData.seedAccountType);
+                            pw.println();
+                        }
+                        if (userData.seedAccountOptions != null) {
+                            pw.print("         account options exist");
+                            pw.println();
+                        }
+                    }
                 }
             }
+            pw.println();
             pw.println("  Device policy global restrictions:");
             synchronized (mRestrictionsLock) {
                 UserRestrictionsUtils
@@ -2619,6 +2805,12 @@
                 pw.println();
                 pw.println("  Device managed: " + mIsDeviceManaged);
             }
+            // Dump some capabilities
+            pw.println();
+            pw.println("  Max users: " + UserManager.getMaxSupportedUsers());
+            pw.println("  Supports switchable users: " + UserManager.supportsMultipleUsers());
+            pw.println("  All guests ephemeral: " + Resources.getSystem().getBoolean(
+                    com.android.internal.R.bool.config_guestUserEphemeral));
         }
     }
 
@@ -2630,10 +2822,10 @@
                 case WRITE_USER_MSG:
                     removeMessages(WRITE_USER_MSG, msg.obj);
                     synchronized (mPackagesLock) {
-                        int userId = ((UserInfo) msg.obj).id;
-                        UserInfo userInfo = getUserInfoNoChecks(userId);
-                        if (userInfo != null) {
-                            writeUserLP(userInfo);
+                        int userId = ((UserData) msg.obj).info.id;
+                        UserData userData = getUserDataNoChecks(userId);
+                        if (userData != null) {
+                            writeUserLP(userData);
                         }
                     }
             }
@@ -2671,10 +2863,10 @@
                 invalidateEffectiveUserRestrictionsLR(userId);
             }
 
-            final UserInfo userInfo = getUserInfoNoChecks(userId);
+            final UserData userData = getUserDataNoChecks(userId);
             synchronized (mPackagesLock) {
-                if (userInfo != null) {
-                    writeUserLP(userInfo);
+                if (userData != null) {
+                    writeUserLP(userData);
                 } else {
                     Slog.w(LOG_TAG, "UserInfo not found for " + userId);
                 }
@@ -2713,6 +2905,80 @@
                 mIsUserManaged.put(userId, isManaged);
             }
         }
+
+        @Override
+        public void setUserIcon(int userId, Bitmap bitmap) {
+            long ident = Binder.clearCallingIdentity();
+            try {
+                synchronized (mPackagesLock) {
+                    UserData userData = getUserDataNoChecks(userId);
+                    if (userData == null || userData.info.partial) {
+                        Slog.w(LOG_TAG, "setUserIcon: unknown user #" + userId);
+                        return;
+                    }
+                    writeBitmapLP(userData.info, bitmap);
+                    writeUserLP(userData);
+                }
+                sendUserInfoChangedBroadcast(userId);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override
+        public void setForceEphemeralUsers(boolean forceEphemeralUsers) {
+            synchronized (mUsersLock) {
+                mForceEphemeralUsers = forceEphemeralUsers;
+            }
+        }
+
+        @Override
+        public void removeAllUsers() {
+            if (UserHandle.USER_SYSTEM == ActivityManager.getCurrentUser()) {
+                // Remove the non-system users straight away.
+                removeNonSystemUsers();
+            } else {
+                // Switch to the system user first and then remove the other users.
+                BroadcastReceiver userSwitchedReceiver = new BroadcastReceiver() {
+                    @Override
+                    public void onReceive(Context context, Intent intent) {
+                        int userId =
+                                intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+                        if (userId != UserHandle.USER_SYSTEM) {
+                            return;
+                        }
+                        mContext.unregisterReceiver(this);
+                        removeNonSystemUsers();
+                    }
+                };
+                IntentFilter userSwitchedFilter = new IntentFilter();
+                userSwitchedFilter.addAction(Intent.ACTION_USER_SWITCHED);
+                mContext.registerReceiver(
+                        userSwitchedReceiver, userSwitchedFilter, null, mHandler);
+
+                // Switch to the system user.
+                ActivityManager am =
+                        (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+                am.switchUser(UserHandle.USER_SYSTEM);
+            }
+        }
+    }
+
+    /* Remove all the users except of the system one. */
+    private void removeNonSystemUsers() {
+        ArrayList<UserInfo> usersToRemove = new ArrayList<>();
+        synchronized (mUsersLock) {
+            final int userSize = mUsers.size();
+            for (int i = 0; i < userSize; i++) {
+                UserInfo ui = mUsers.valueAt(i).info;
+                if (ui.id != UserHandle.USER_SYSTEM) {
+                    usersToRemove.add(ui);
+                }
+            }
+        }
+        for (UserInfo ui: usersToRemove) {
+            removeUser(ui.id);
+        }
     }
 
     private class Shell extends ShellCommand {
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 9bbc3c1..87f505d 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -33,6 +33,8 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.util.Log;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -40,10 +42,11 @@
 
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.util.List;
 import java.util.Set;
 
 /**
- * Utility methods for uesr restrictions.
+ * Utility methods for user restrictions.
  *
  * <p>See {@link UserManagerService} for the method suffixes.
  */
@@ -88,7 +91,9 @@
             UserManager.ALLOW_PARENT_PROFILE_APP_LINKING,
             UserManager.DISALLOW_RECORD_AUDIO,
             UserManager.DISALLOW_CAMERA,
-            UserManager.DISALLOW_RUN_IN_BACKGROUND
+            UserManager.DISALLOW_RUN_IN_BACKGROUND,
+            UserManager.DISALLOW_DATA_ROAMING,
+            UserManager.DISALLOW_SET_USER_ICON
     );
 
     /**
@@ -113,7 +118,8 @@
             UserManager.DISALLOW_SMS,
             UserManager.DISALLOW_FUN,
             UserManager.DISALLOW_SAFE_BOOT,
-            UserManager.DISALLOW_CREATE_WINDOWS
+            UserManager.DISALLOW_CREATE_WINDOWS,
+            UserManager.DISALLOW_DATA_ROAMING
     );
 
     /**
@@ -315,6 +321,27 @@
                                         .WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0, userId);
                     }
                     break;
+                case UserManager.DISALLOW_DATA_ROAMING:
+                    if (newValue) {
+                        // DISALLOW_DATA_ROAMING user restriction is set.
+
+                        // Multi sim device.
+                        SubscriptionManager subscriptionManager = new SubscriptionManager(context);
+                        final List<SubscriptionInfo> subscriptionInfoList =
+                            subscriptionManager.getActiveSubscriptionInfoList();
+                        if (subscriptionInfoList != null) {
+                            for (SubscriptionInfo subInfo : subscriptionInfoList) {
+                                android.provider.Settings.Global.putStringForUser(cr,
+                                    android.provider.Settings.Global.DATA_ROAMING
+                                    + subInfo.getSubscriptionId(), "0", userId);
+                            }
+                        }
+
+                        // Single sim device.
+                        android.provider.Settings.Global.putStringForUser(cr,
+                            android.provider.Settings.Global.DATA_ROAMING, "0", userId);
+                    }
+                    break;
                 case UserManager.DISALLOW_SHARE_LOCATION:
                     if (newValue) {
                         android.provider.Settings.Secure.putIntForUser(cr,
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index c8523c9..a0f20aa 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -278,7 +278,7 @@
             } else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
                 if (Settings.Global.getInt(mContext.getContentResolver(),
                         Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
-                    mItems.add(getBugReportAction());
+                    mItems.add(new BugReportAction());
                 }
             } else if (GLOBAL_ACTION_KEY_SILENT.equals(actionKey)) {
                 if (mShowSilentToggle) {
@@ -367,60 +367,67 @@
         }
     }
 
-    private Action getBugReportAction() {
-        return new SinglePressAction(com.android.internal.R.drawable.ic_lock_bugreport,
-                R.string.bugreport_title) {
+    private class BugReportAction extends SinglePressAction implements LongPressAction {
 
-            public void onPress() {
-                AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
-                builder.setTitle(com.android.internal.R.string.bugreport_title);
-                builder.setMessage(com.android.internal.R.string.bugreport_message);
-                builder.setNegativeButton(com.android.internal.R.string.cancel, null);
-                builder.setPositiveButton(com.android.internal.R.string.report,
-                        new DialogInterface.OnClickListener() {
-                            @Override
-                            public void onClick(DialogInterface dialog, int which) {
-                                // don't actually trigger the bugreport if we are running stability
-                                // tests via monkey
-                                if (ActivityManager.isUserAMonkey()) {
-                                    return;
-                                }
-                                // Add a little delay before executing, to give the
-                                // dialog a chance to go away before it takes a
-                                // screenshot.
-                                mHandler.postDelayed(new Runnable() {
-                                    @Override public void run() {
-                                        //  TODO: select 'progress' flag according to menu choice
-                                        try {
-                                            ActivityManagerNative.getDefault()
-                                                    .requestBugReport(true);
-                                        } catch (RemoteException e) {
-                                        }
-                                    }
-                                }, 500);
-                            }
-                        });
-                AlertDialog dialog = builder.create();
-                dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-                dialog.show();
+        public BugReportAction() {
+            super(com.android.internal.R.drawable.ic_lock_bugreport, R.string.bugreport_title);
+        }
+
+        @Override
+        public void onPress() {
+            // don't actually trigger the bugreport if we are running stability
+            // tests via monkey
+            if (ActivityManager.isUserAMonkey()) {
+                return;
             }
+            // Add a little delay before executing, to give the
+            // dialog a chance to go away before it takes a
+            // screenshot.
+            mHandler.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        // Take an "interactive" bugreport.
+                        ActivityManagerNative.getDefault().requestBugReport(
+                                ActivityManager.BUGREPORT_OPTION_INTERACTIVE);
+                    } catch (RemoteException e) {
+                    }
+                }
+            }, 500);
+        }
 
-            public boolean showDuringKeyguard() {
-                return true;
-            }
-
-            public boolean showBeforeProvisioning() {
+        @Override
+        public boolean onLongPress() {
+            // don't actually trigger the bugreport if we are running stability
+            // tests via monkey
+            if (ActivityManager.isUserAMonkey()) {
                 return false;
             }
-
-            @Override
-            public String getStatus() {
-                return mContext.getString(
-                        com.android.internal.R.string.bugreport_status,
-                        Build.VERSION.RELEASE,
-                        Build.ID);
+            try {
+                // Take a "full" bugreport.
+                ActivityManagerNative.getDefault().requestBugReport(
+                        ActivityManager.BUGREPORT_OPTION_FULL);
+            } catch (RemoteException e) {
             }
-        };
+            return false;
+        }
+
+        public boolean showDuringKeyguard() {
+            return true;
+        }
+
+        @Override
+        public boolean showBeforeProvisioning() {
+            return false;
+        }
+
+        @Override
+        public String getStatus() {
+            return mContext.getString(
+                    com.android.internal.R.string.bugreport_status,
+                    Build.VERSION.RELEASE,
+                    Build.ID);
+        }
     }
 
     private Action getSettingsAction() {
@@ -742,13 +749,6 @@
             mIcon = icon;
         }
 
-        protected SinglePressAction(int iconResId, CharSequence message) {
-            mIconResId = iconResId;
-            mMessageResId = 0;
-            mMessage = message;
-            mIcon = null;
-        }
-
         public boolean isEnabled() {
             return true;
         }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index dff6e3f..0b1354a 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -18,13 +18,18 @@
 
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_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.LayoutParams.*;
-import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
-import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
-import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
+import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
 import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
 import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
-import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
+import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
+import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
+import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
 
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
@@ -181,10 +186,15 @@
     static final int LONG_PRESS_HOME_NOTHING = 0;
     static final int LONG_PRESS_HOME_RECENT_SYSTEM_UI = 1;
     static final int LONG_PRESS_HOME_ASSIST = 2;
+    static final int LONG_PRESS_HOME_PICTURE_IN_PICTURE = 3;
+    static final int LAST_LONG_PRESS_HOME_BEHAVIOR = LONG_PRESS_HOME_PICTURE_IN_PICTURE;
 
     static final int DOUBLE_TAP_HOME_NOTHING = 0;
     static final int DOUBLE_TAP_HOME_RECENT_SYSTEM_UI = 1;
 
+    static final int SHORT_PRESS_WINDOW_NOTHING = 0;
+    static final int SHORT_PRESS_WINDOW_PICTURE_IN_PICTURE = 1;
+
     static final int SHORT_PRESS_SLEEP_GO_TO_SLEEP = 0;
     static final int SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME = 1;
 
@@ -313,8 +323,10 @@
     boolean mCanHideNavigationBar = false;
     boolean mNavigationBarCanMove = false; // can the navigation bar ever move to the side?
     boolean mNavigationBarOnBottom = true; // is the navigation bar on the bottom *right now*?
-    int[] mNavigationBarHeightForRotation = new int[4];
-    int[] mNavigationBarWidthForRotation = new int[4];
+    int[] mNavigationBarHeightForRotationDefault = new int[4];
+    int[] mNavigationBarWidthForRotationDefault = new int[4];
+    int[] mNavigationBarHeightForRotationInCarMode = new int[4];
+    int[] mNavigationBarWidthForRotationInCarMode = new int[4];
 
     // 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.
@@ -403,6 +415,7 @@
     int mDoublePressOnPowerBehavior;
     int mTriplePressOnPowerBehavior;
     int mShortPressOnSleepBehavior;
+    int mShortPressWindowBehavior;
     boolean mAwake;
     boolean mScreenOnEarly;
     boolean mScreenOnFully;
@@ -1309,16 +1322,26 @@
         }
     }
 
-    private void handleLongPressOnHome(int deviceId) {
-        if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) {
-            mHomeConsumed = true;
-            performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+    private void handleLongPressOnHome(int deviceId, KeyEvent event) {
+        if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_NOTHING) {
+            return;
+        }
+        mHomeConsumed = true;
+        performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
 
-            if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI) {
+        switch (mLongPressOnHomeBehavior) {
+            case LONG_PRESS_HOME_RECENT_SYSTEM_UI:
                 toggleRecentApps();
-            } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_ASSIST) {
+                break;
+            case LONG_PRESS_HOME_ASSIST:
                 launchAssistAction(null, deviceId);
-            }
+                break;
+            case LONG_PRESS_HOME_PICTURE_IN_PICTURE:
+                handlePipKey(event);
+                break;
+            default:
+                Log.w(TAG, "Not defined home long press behavior: " + mLongPressOnHomeBehavior);
+                break;
         }
     }
 
@@ -1329,6 +1352,13 @@
         }
     }
 
+    private void handlePipKey(KeyEvent event) {
+        if (DEBUG_INPUT) Log.d(TAG, "handlePipKey event=" + event);
+        Intent intent = new Intent(Intent.ACTION_PICTURE_IN_PICTURE_BUTTON);
+        intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
+        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+    }
+
     private final Runnable mHomeDoubleTapTimeoutRunnable = new Runnable() {
         @Override
         public void run() {
@@ -1621,7 +1651,7 @@
         mLongPressOnHomeBehavior = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_longPressOnHomeBehavior);
         if (mLongPressOnHomeBehavior < LONG_PRESS_HOME_NOTHING ||
-                mLongPressOnHomeBehavior > LONG_PRESS_HOME_ASSIST) {
+                mLongPressOnHomeBehavior > LAST_LONG_PRESS_HOME_BEHAVIOR) {
             mLongPressOnHomeBehavior = LONG_PRESS_HOME_NOTHING;
         }
 
@@ -1631,6 +1661,11 @@
                 mDoubleTapOnHomeBehavior > DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
             mDoubleTapOnHomeBehavior = LONG_PRESS_HOME_NOTHING;
         }
+
+        mShortPressWindowBehavior = SHORT_PRESS_WINDOW_NOTHING;
+        if (mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
+            mShortPressWindowBehavior = SHORT_PRESS_WINDOW_PICTURE_IN_PICTURE;
+        }
     }
 
     @Override
@@ -1674,20 +1709,37 @@
                 res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
 
         // Height of the navigation bar when presented horizontally at bottom
-        mNavigationBarHeightForRotation[mPortraitRotation] =
-        mNavigationBarHeightForRotation[mUpsideDownRotation] =
+        mNavigationBarHeightForRotationDefault[mPortraitRotation] =
+        mNavigationBarHeightForRotationDefault[mUpsideDownRotation] =
                 res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height);
-        mNavigationBarHeightForRotation[mLandscapeRotation] =
-        mNavigationBarHeightForRotation[mSeascapeRotation] = res.getDimensionPixelSize(
+        mNavigationBarHeightForRotationDefault[mLandscapeRotation] =
+        mNavigationBarHeightForRotationDefault[mSeascapeRotation] = res.getDimensionPixelSize(
                 com.android.internal.R.dimen.navigation_bar_height_landscape);
 
         // Width of the navigation bar when presented vertically along one side
-        mNavigationBarWidthForRotation[mPortraitRotation] =
-        mNavigationBarWidthForRotation[mUpsideDownRotation] =
-        mNavigationBarWidthForRotation[mLandscapeRotation] =
-        mNavigationBarWidthForRotation[mSeascapeRotation] =
+        mNavigationBarWidthForRotationDefault[mPortraitRotation] =
+        mNavigationBarWidthForRotationDefault[mUpsideDownRotation] =
+        mNavigationBarWidthForRotationDefault[mLandscapeRotation] =
+        mNavigationBarWidthForRotationDefault[mSeascapeRotation] =
                 res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
 
+        // Height of the navigation bar when presented horizontally at bottom
+        mNavigationBarHeightForRotationInCarMode[mPortraitRotation] =
+        mNavigationBarHeightForRotationInCarMode[mUpsideDownRotation] =
+                res.getDimensionPixelSize(
+                        com.android.internal.R.dimen.navigation_bar_height_car_mode);
+        mNavigationBarHeightForRotationInCarMode[mLandscapeRotation] =
+        mNavigationBarHeightForRotationInCarMode[mSeascapeRotation] = res.getDimensionPixelSize(
+                com.android.internal.R.dimen.navigation_bar_height_landscape_car_mode);
+
+        // Width of the navigation bar when presented vertically along one side
+        mNavigationBarWidthForRotationInCarMode[mPortraitRotation] =
+        mNavigationBarWidthForRotationInCarMode[mUpsideDownRotation] =
+        mNavigationBarWidthForRotationInCarMode[mLandscapeRotation] =
+        mNavigationBarWidthForRotationInCarMode[mSeascapeRotation] =
+                res.getDimensionPixelSize(
+                        com.android.internal.R.dimen.navigation_bar_width_car_mode);
+
         // SystemUI (status bar) layout policy
         int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT / density;
         int longSizeDp = longSize * DisplayMetrics.DENSITY_DEFAULT / density;
@@ -2063,7 +2115,8 @@
                 attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
             }
             if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
-                    || mForceWindowDrawsStatusBarBackground) {
+                    || (mForceWindowDrawsStatusBarBackground
+                            && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT)) {
                 attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
             }
         }
@@ -2238,42 +2291,61 @@
         return windowTypeToLayerLw(TYPE_STATUS_BAR);
     }
 
+    private int getNavigationBarWidth(int rotation, int uiMode) {
+        if ((uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
+            return mNavigationBarWidthForRotationInCarMode[rotation];
+        } else {
+            return mNavigationBarWidthForRotationDefault[rotation];
+        }
+    }
+
     @Override
-    public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation) {
+    public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation,
+            int uiMode) {
         if (mHasNavigationBar) {
             // For a basic navigation bar, when we are in landscape mode we place
             // the navigation bar to the side.
             if (mNavigationBarCanMove && fullWidth > fullHeight) {
-                return fullWidth - mNavigationBarWidthForRotation[rotation];
+                return fullWidth - getNavigationBarWidth(rotation, uiMode);
             }
         }
         return fullWidth;
     }
 
+    private int getNavigationBarHeight(int rotation, int uiMode) {
+        if ((uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
+            return mNavigationBarHeightForRotationInCarMode[rotation];
+        } else {
+            return mNavigationBarHeightForRotationDefault[rotation];
+        }
+    }
+
     @Override
-    public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation) {
+    public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation,
+            int uiMode) {
         if (mHasNavigationBar) {
             // For a basic navigation bar, when we are in portrait mode we place
             // the navigation bar to the bottom.
             if (!mNavigationBarCanMove || fullWidth < fullHeight) {
-                return fullHeight - mNavigationBarHeightForRotation[rotation];
+                return fullHeight - getNavigationBarHeight(rotation, uiMode);
             }
         }
         return fullHeight;
     }
 
     @Override
-    public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation) {
-        return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation);
+    public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode) {
+        return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation, uiMode);
     }
 
     @Override
-    public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation) {
+    public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode) {
         // There is a separate status bar at the top of the display.  We don't count that as part
         // of the fixed decor, since it can hide; however, for purposes of configurations,
         // we do want to exclude it since applications can't generally use that part
         // of the screen.
-        return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation) - mStatusBarHeight;
+        return getNonDecorDisplayHeight(
+                fullWidth, fullHeight, rotation, uiMode) - mStatusBarHeight;
     }
 
     @Override
@@ -2810,7 +2882,7 @@
                 }
             } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
                 if (!keyguardOn) {
-                    handleLongPressOnHome(event.getDeviceId());
+                    handleLongPressOnHome(event.getDeviceId(), event);
                 }
             }
             return -1;
@@ -2878,7 +2950,7 @@
         } else if (keyCode == KeyEvent.KEYCODE_SLASH && event.isMetaPressed()) {
             if (down) {
                 if (repeatCount == 0) {
-                    showKeyboardShortcutsMenu();
+                    toggleKeyboardShortcutsMenu();
                 }
             }
         } else if (keyCode == KeyEvent.KEYCODE_ASSIST) {
@@ -2962,6 +3034,14 @@
                         UserHandle.CURRENT_OR_SELF);
             }
             return -1;
+        } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP
+                || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
+                || keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) {
+            if (mUseTvRouting) {
+                // On TVs volume keys never go to the foreground app.
+                dispatchDirectAudioEvent(event);
+                return -1;
+            }
         } else if (KeyEvent.isMetaKey(keyCode)) {
             if (down) {
                 mPendingMetaAction = true;
@@ -3056,15 +3136,6 @@
             hideRecentApps(true, false);
         }
 
-        // Handle keyboard layout switching.
-        // TODO: Deprecate this behavior when we fully migrate to IME subtype-based layout rotation.
-        if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_SPACE
-                && ((metaState & KeyEvent.META_CTRL_MASK) != 0)) {
-            int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
-            mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction);
-            return -1;
-        }
-
         // Handle input method switching.
         if (down && repeatCount == 0
                 && (keyCode == KeyEvent.KEYCODE_LANGUAGE_SWITCH
@@ -3310,11 +3381,11 @@
         }
     }
 
-    private void showKeyboardShortcutsMenu() {
+    private void toggleKeyboardShortcutsMenu() {
         try {
             IStatusBarService statusbar = getStatusBarService();
             if (statusbar != null) {
-                statusbar.showKeyboardShortcutsMenu();
+                statusbar.toggleKeyboardShortcutsMenu();
             }
         } catch (RemoteException e) {
             Slog.e(TAG, "RemoteException when showing keyboard shortcuts menu", e);
@@ -3380,7 +3451,6 @@
             if (awakenFromDreams) {
                 awakenDreams();
             }
-            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
             hideRecentApps(false, true);
         } else {
             // Otherwise, just launch Home
@@ -3550,7 +3620,7 @@
     /** {@inheritDoc} */
     @Override
     public void beginLayoutLw(boolean isDefaultDisplay, int displayWidth, int displayHeight,
-                              int displayRotation) {
+                              int displayRotation, int uiMode) {
         mDisplayRotation = displayRotation;
         final int overscanLeft, overscanTop, overscanRight, overscanBottom;
         if (isDefaultDisplay) {
@@ -3661,7 +3731,7 @@
             navVisible |= !canHideNavigationBar();
 
             boolean updateSysUiVisibility = layoutNavigationBar(displayWidth, displayHeight,
-                    displayRotation, overscanRight, overscanBottom, dcf, navVisible, navTranslucent,
+                    displayRotation, uiMode, overscanRight, overscanBottom, dcf, navVisible, navTranslucent,
                     navAllowedHidden);
             if (DEBUG_LAYOUT) Slog.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)",
                     mDockLeft, mDockTop, mDockRight, mDockBottom));
@@ -3740,7 +3810,7 @@
     }
 
     private boolean layoutNavigationBar(int displayWidth, int displayHeight, int displayRotation,
-            int overscanRight, int overscanBottom, Rect dcf, boolean navVisible,
+            int uiMode, int overscanRight, int overscanBottom, Rect dcf, boolean navVisible,
             boolean navTranslucent, boolean navAllowedHidden) {
         if (mNavigationBar != null) {
             boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
@@ -3748,11 +3818,11 @@
             // size.  We need to do this directly, instead of relying on
             // it to bubble up from the nav bar, because this needs to
             // change atomically with screen rotations.
-            mNavigationBarOnBottom = (!mNavigationBarCanMove || displayWidth < displayHeight);
+            mNavigationBarOnBottom = isNavigationBarOnBottom(displayWidth, displayHeight);
             if (mNavigationBarOnBottom) {
                 // It's a system nav bar or a portrait screen; nav bar goes on bottom.
                 int top = displayHeight - overscanBottom
-                        - mNavigationBarHeightForRotation[displayRotation];
+                        - getNavigationBarHeight(displayRotation, uiMode);
                 mTmpNavigationFrame.set(0, top, displayWidth, displayHeight - overscanBottom);
                 mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top;
                 if (transientNavBarShowing) {
@@ -3777,7 +3847,7 @@
             } else {
                 // Landscape screen; nav bar goes to the right.
                 int left = displayWidth - overscanRight
-                        - mNavigationBarWidthForRotation[displayRotation];
+                        - getNavigationBarWidth(displayRotation, uiMode);
                 mTmpNavigationFrame.set(left, 0, displayWidth - overscanRight, displayHeight);
                 mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left;
                 if (transientNavBarShowing) {
@@ -3819,6 +3889,10 @@
         return false;
     }
 
+    private boolean isNavigationBarOnBottom(int displayWidth, int displayHeight) {
+        return !mNavigationBarCanMove || displayWidth < displayHeight;
+    }
+
     /** {@inheritDoc} */
     @Override
     public int getSystemDecorLayerLw() {
@@ -4010,7 +4084,13 @@
             cf.top = vf.top = mStableTop;
             cf.right = vf.right = mStableRight;
             vf.bottom = mStableBottom;
-            cf.bottom = mContentBottom;
+
+            if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
+                cf.bottom = mContentBottom;
+            } else {
+                cf.bottom = mDockBottom;
+                vf.bottom = mContentBottom;
+            }
         } else {
 
             // Default policy decor for the default display
@@ -4242,6 +4322,7 @@
                         && (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
                         && (attrs.type == TYPE_STATUS_BAR
                             || attrs.type == TYPE_TOAST
+                            || attrs.type == TYPE_DOCK_DIVIDER
                             || attrs.type == TYPE_VOICE_INTERACTION_STARTING
                             || (attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
                             && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW))) {
@@ -5039,10 +5120,6 @@
             case KeyEvent.KEYCODE_VOLUME_DOWN:
             case KeyEvent.KEYCODE_VOLUME_UP:
             case KeyEvent.KEYCODE_VOLUME_MUTE: {
-                if (mUseTvRouting) {
-                    // On TVs volume keys never go to the foreground app
-                    result &= ~ACTION_PASS_TO_USER;
-                }
                 if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
                     if (down) {
                         if (interactive && !mScreenshotChordVolumeDownKeyTriggered
@@ -5102,19 +5179,17 @@
                             break;
                         }
                     }
-
-                    if ((result & ACTION_PASS_TO_USER) == 0) {
-                        if (mUseTvRouting) {
-                            dispatchDirectAudioEvent(event);
-                        } else {
-                            // If we aren't passing to the user and no one else
-                            // handled it send it to the session manager to
-                            // figure out.
-                            MediaSessionLegacyHelper.getHelper(mContext)
-                                    .sendVolumeKeyEvent(event, true);
-                        }
-                        break;
-                    }
+                }
+                if (mUseTvRouting) {
+                    // On TVs, defer special key handlings to
+                    // {@link interceptKeyBeforeDispatching()}.
+                    result |= ACTION_PASS_TO_USER;
+                } else if ((result & ACTION_PASS_TO_USER) == 0) {
+                    // If we aren't passing to the user and no one else
+                    // handled it send it to the session manager to
+                    // figure out.
+                    MediaSessionLegacyHelper.getHelper(mContext)
+                            .sendVolumeKeyEvent(event, true);
                 }
                 break;
             }
@@ -5257,6 +5332,16 @@
                     msg.setAsynchronous(true);
                     msg.sendToTarget();
                 }
+                break;
+            }
+            case KeyEvent.KEYCODE_WINDOW: {
+                if (mShortPressWindowBehavior == SHORT_PRESS_WINDOW_PICTURE_IN_PICTURE) {
+                    if (!down) {
+                        handlePipKey(event);
+                    }
+                    result &= ~ACTION_PASS_TO_USER;
+                }
+                break;
             }
         }
 
@@ -5890,6 +5975,22 @@
         }
     }
 
+    @Override
+    public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
+            Rect outInsets) {
+        outInsets.setEmpty();
+        if (mStatusBar != null) {
+            outInsets.top = mStatusBarHeight;
+        }
+        if (mNavigationBar != null) {
+            if (isNavigationBarOnBottom(displayWidth, displayHeight)) {
+                outInsets.bottom = getNavigationBarHeight(displayRotation, mUiMode);
+            } else {
+                outInsets.right = getNavigationBarWidth(displayRotation, mUiMode);
+            }
+        }
+    }
+
     void sendCloseSystemWindows() {
         PhoneWindow.sendCloseSystemWindows(mContext, null);
     }
@@ -6214,11 +6315,9 @@
             @Override public void run() {
                 if (mBootMsgDialog == null) {
                     int theme;
-                    if (mContext.getPackageManager().hasSystemFeature(
-                            PackageManager.FEATURE_WATCH)) {
+                    if (mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH)) {
                         theme = com.android.internal.R.style.Theme_Micro_Dialog_Alert;
-                    } else if (mContext.getPackageManager().hasSystemFeature(
-                            PackageManager.FEATURE_TELEVISION)) {
+                    } else if (mContext.getPackageManager().hasSystemFeature(FEATURE_TELEVISION)) {
                         theme = com.android.internal.R.style.Theme_Leanback_Dialog_Alert;
                     } else {
                         theme = 0;
@@ -6341,6 +6440,7 @@
             if (mLockScreenTimerActive != enable) {
                 if (enable) {
                     if (localLOGV) Log.v(TAG, "setting lockscreen timer");
+                    mHandler.removeCallbacks(mScreenLockTimeout); // remove any pending requests
                     mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout);
                 } else {
                     if (localLOGV) Log.v(TAG, "clearing lockscreen timer");
diff --git a/services/core/java/com/android/server/policy/ShortcutManager.java b/services/core/java/com/android/server/policy/ShortcutManager.java
index 76f56bc..9284442 100644
--- a/services/core/java/com/android/server/policy/ShortcutManager.java
+++ b/services/core/java/com/android/server/policy/ShortcutManager.java
@@ -26,6 +26,7 @@
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
 import com.android.internal.util.XmlUtils;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -47,8 +48,10 @@
     private static final String ATTRIBUTE_CLASS = "class";
     private static final String ATTRIBUTE_SHORTCUT = "shortcut";
     private static final String ATTRIBUTE_CATEGORY = "category";
+    private static final String ATTRIBUTE_SHIFT = "shift";
 
     private final SparseArray<ShortcutInfo> mShortcuts = new SparseArray<>();
+    private final SparseArray<ShortcutInfo> mShiftShortcuts = new SparseArray<>();
 
     private final Context mContext;
     
@@ -75,17 +78,21 @@
     public Intent getIntent(KeyCharacterMap kcm, int keyCode, int metaState) {
         ShortcutInfo shortcut = null;
 
+        // If the Shift key is preesed, then search for the shift shortcuts.
+        boolean isShiftOn = (metaState & KeyEvent.META_SHIFT_ON) == KeyEvent.META_SHIFT_ON;
+        SparseArray<ShortcutInfo> shortcutMap = isShiftOn ? mShiftShortcuts : mShortcuts;
+
         // First try the exact keycode (with modifiers).
         int shortcutChar = kcm.get(keyCode, metaState);
         if (shortcutChar != 0) {
-            shortcut = mShortcuts.get(shortcutChar);
+            shortcut = shortcutMap.get(shortcutChar);
         }
 
         // Next try the primary character on that key.
         if (shortcut == null) {
             shortcutChar = Character.toLowerCase(kcm.getDisplayLabel(keyCode));
             if (shortcutChar != 0) {
-                shortcut = mShortcuts.get(shortcutChar);
+                shortcut = shortcutMap.get(shortcutChar);
             }
         }
 
@@ -114,6 +121,7 @@
                 String className = parser.getAttributeValue(null, ATTRIBUTE_CLASS);
                 String shortcutName = parser.getAttributeValue(null, ATTRIBUTE_SHORTCUT);
                 String categoryName = parser.getAttributeValue(null, ATTRIBUTE_CATEGORY);
+                String shiftName = parser.getAttributeValue(null, ATTRIBUTE_SHIFT);
 
                 if (TextUtils.isEmpty(shortcutName)) {
                     Log.w(TAG, "Unable to get shortcut for: " + packageName + "/" + className);
@@ -121,6 +129,7 @@
                 }
 
                 final int shortcutChar = shortcutName.charAt(0);
+                final boolean isShiftShortcut = (shiftName != null && shiftName.equals("true"));
 
                 final Intent intent;
                 final String title;
@@ -128,13 +137,15 @@
                     ActivityInfo info = null;
                     ComponentName componentName = new ComponentName(packageName, className);
                     try {
-                        info = packageManager.getActivityInfo(componentName, 0);
+                        info = packageManager.getActivityInfo(componentName,
+                                PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
                     } catch (PackageManager.NameNotFoundException e) {
                         String[] packages = packageManager.canonicalToCurrentPackageNames(
                                 new String[] { packageName });
                         componentName = new ComponentName(packages[0], className);
                         try {
-                            info = packageManager.getActivityInfo(componentName, 0);
+                            info = packageManager.getActivityInfo(componentName,
+                                    PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
                         } catch (PackageManager.NameNotFoundException e1) {
                             Log.w(TAG, "Unable to add bookmark: " + packageName
                                     + "/" + className, e);
@@ -156,7 +167,11 @@
                 }
 
                 ShortcutInfo shortcut = new ShortcutInfo(title, intent);
-                mShortcuts.put(shortcutChar, shortcut);
+                if (isShiftShortcut) {
+                    mShiftShortcuts.put(shortcutChar, shortcut);
+                } else {
+                    mShortcuts.put(shortcutChar, shortcut);
+                }
             }
         } catch (XmlPullParserException e) {
             Log.w(TAG, "Got exception parsing bookmarks.", e);
diff --git a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
index b06fe58..80e4341 100644
--- a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
+++ b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
@@ -89,7 +89,7 @@
 
     @Override
     public void onPointerEvent(MotionEvent event) {
-        if (mGestureDetector != null) {
+        if (mGestureDetector != null && event.isTouchEvent()) {
             mGestureDetector.onTouchEvent(event);
         }
         switch (event.getActionMasked()) {
diff --git a/services/core/java/com/android/server/policy/WindowOrientationListener.java b/services/core/java/com/android/server/policy/WindowOrientationListener.java
index 9916223..a32c017 100644
--- a/services/core/java/com/android/server/policy/WindowOrientationListener.java
+++ b/services/core/java/com/android/server/policy/WindowOrientationListener.java
@@ -87,22 +87,10 @@
         mHandler = handler;
         mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
         mRate = rate;
+        mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_DEVICE_ORIENTATION);
 
-        mSensorType = context.getResources().getString(
-                com.android.internal.R.string.config_orientationSensorType);
-        if (!TextUtils.isEmpty(mSensorType)) {
-            List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
-            final int N = sensors.size();
-            for (int i = 0; i < N; i++) {
-                Sensor sensor = sensors.get(i);
-                if (mSensorType.equals(sensor.getStringType())) {
-                    mSensor = sensor;
-                    break;
-                }
-            }
-            if (mSensor != null) {
-                mOrientationJudge = new OrientationSensorJudge();
-            }
+        if (mSensor != null) {
+            mOrientationJudge = new OrientationSensorJudge();
         }
 
         if (mOrientationJudge == null) {
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index c0dfbcb..549d2dc 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -126,6 +126,7 @@
 
         final ComponentName keyguardComponent = ComponentName.unflattenFromString(
                 resources.getString(com.android.internal.R.string.config_keyguardComponent));
+        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
         intent.setComponent(keyguardComponent);
 
         if (!context.bindServiceAsUser(intent, mKeyguardConnection,
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 6498dd9..a1f24f7 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -16,21 +16,8 @@
 
 package com.android.server.power;
 
-import android.app.ActivityManager;
-import android.util.SparseIntArray;
-import com.android.internal.app.IAppOpsService;
-import com.android.internal.app.IBatteryStats;
-import com.android.internal.os.BackgroundThread;
-import com.android.server.EventLogTags;
-import com.android.server.ServiceThread;
-import com.android.server.SystemService;
-import com.android.server.am.BatteryStatsService;
-import com.android.server.lights.Light;
-import com.android.server.lights.LightsManager;
-import com.android.server.Watchdog;
-
 import android.Manifest;
-import android.app.AppOpsManager;
+import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -65,22 +52,32 @@
 import android.service.dreams.DreamManagerInternal;
 import android.util.EventLog;
 import android.util.Slog;
+import android.util.SparseIntArray;
 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.server.EventLogTags;
+import com.android.server.ServiceThread;
+import com.android.server.SystemService;
+import com.android.server.Watchdog;
+import com.android.server.am.BatteryStatsService;
+import com.android.server.lights.Light;
+import com.android.server.lights.LightsManager;
+import libcore.util.Objects;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 
-import libcore.util.Objects;
-
 import static android.os.PowerManagerInternal.POWER_HINT_INTERACTION;
 import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
 import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
-import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING;
 import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING;
+import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING;
 
 /**
  * The power manager service is responsible for coordinating power management
@@ -134,6 +131,7 @@
     private static final int WAKE_LOCK_STAY_AWAKE = 1 << 5; // only set if already awake
     private static final int WAKE_LOCK_DOZE = 1 << 6;
     private static final int WAKE_LOCK_DRAW = 1 << 7;
+    private static final int WAKE_LOCK_SUSTAINED_PERFORMANCE = 1 << 8;
 
     // Summarizes the user activity state.
     private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0;
@@ -152,6 +150,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;
 
     // Power features defined in hardware/libhardware/include/hardware/power.h.
     private static final int POWER_FEATURE_DOUBLE_TAP_TO_WAKE = 1;
@@ -447,6 +446,9 @@
     // True if we are currently in light device idle mode.
     private boolean mLightDeviceIdleMode;
 
+    // True if we are currently in sustained performance mode.
+    private boolean mSustainedPerformanceMode;
+
     // Set of app ids that we will always respect the wake locks for.
     int[] mDeviceIdleWhitelist = new int[0];
 
@@ -455,6 +457,8 @@
 
     private final SparseIntArray mUidState = new SparseIntArray();
 
+    private final SparseIntArray mSustainedPerformanceUid = new SparseIntArray();
+
     // True if theater mode is enabled
     private boolean mTheaterModeEnabled;
 
@@ -771,6 +775,10 @@
                     intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
                     intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                     mContext.sendBroadcast(intent);
+                    // Send internal version that requires signature permission.
+                    mContext.sendBroadcastAsUser(new Intent(
+                            PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL), UserHandle.ALL,
+                            Manifest.permission.DEVICE_POWER);
                 }
             });
         }
@@ -810,6 +818,12 @@
                     throw new IllegalArgumentException("Wake lock is already dead.");
                 }
                 mWakeLocks.add(wakeLock);
+
+                if ((flags & PowerManager.WAKE_LOCK_LEVEL_MASK)
+                        == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK) {
+                    int numberWakelock = mSustainedPerformanceUid.get(uid);
+                    mSustainedPerformanceUid.put(uid, numberWakelock + 1);
+                }
                 setWakeLockDisabledStateLocked(wakeLock);
                 notifyAcquire = true;
             }
@@ -878,6 +892,17 @@
                 mRequestWaitForNegativeProximity = true;
             }
 
+
+            if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
+                    == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK) {
+                int numberWakelock = mSustainedPerformanceUid.get(wakeLock.mOwnerUid);
+                if (numberWakelock == 1) {
+                    mSustainedPerformanceUid.delete(wakeLock.mOwnerUid);
+                } else {
+                    mSustainedPerformanceUid.put(wakeLock.mOwnerUid, numberWakelock - 1);
+                }
+            }
+
             wakeLock.mLock.unlinkToDeath(wakeLock, 0);
             removeWakeLockLocked(wakeLock, index);
         }
@@ -1500,6 +1525,10 @@
                         break;
                     case PowerManager.DRAW_WAKE_LOCK:
                         mWakeLockSummary |= WAKE_LOCK_DRAW;
+                    case PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK:
+                        if (!wakeLock.mDisabled) {
+                            mWakeLockSummary |= WAKE_LOCK_SUSTAINED_PERFORMANCE;
+                        }
                         break;
                 }
             }
@@ -2197,6 +2226,14 @@
         if (autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
             setHalAutoSuspendModeLocked(true);
         }
+
+        if (mSustainedPerformanceMode
+                && (mWakeLockSummary & WAKE_LOCK_SUSTAINED_PERFORMANCE) == 0) {
+            setSustainedPerformanceModeLocked(false);
+        } else if (!mSustainedPerformanceMode
+                && (mWakeLockSummary & WAKE_LOCK_SUSTAINED_PERFORMANCE) != 0) {
+            setSustainedPerformanceModeLocked(true);
+        }
     }
 
     /**
@@ -2295,6 +2332,12 @@
         }
     }
 
+    private void setSustainedPerformanceModeLocked(boolean mode) {
+            mSustainedPerformanceMode = mode;
+            powerHintInternal(POWER_HINT_SUSTAINED_PERFORMANCE,
+                              mSustainedPerformanceMode ? 1 : 0);
+    }
+
     boolean isDeviceIdleModeInternal() {
         synchronized (mLock) {
             return mDeviceIdleMode;
@@ -2424,7 +2467,7 @@
     void updateUidProcStateInternal(int uid, int procState) {
         synchronized (mLock) {
             mUidState.put(uid, procState);
-            if (mDeviceIdleMode) {
+            if (mDeviceIdleMode || mSustainedPerformanceUid.get(uid) != 0) {
                 updateWakeLockDisabledStatesLocked();
             }
         }
@@ -2445,7 +2488,9 @@
         for (int i = 0; i < numWakeLocks; i++) {
             final WakeLock wakeLock = mWakeLocks.get(i);
             if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
-                    == PowerManager.PARTIAL_WAKE_LOCK) {
+                    == PowerManager.PARTIAL_WAKE_LOCK
+                    || (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
+                    == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK) {
                 if (setWakeLockDisabledStateLocked(wakeLock)) {
                     changed = true;
                     if (wakeLock.mDisabled) {
@@ -2464,9 +2509,9 @@
     }
 
     private boolean setWakeLockDisabledStateLocked(WakeLock wakeLock) {
+        boolean disabled = false;
         if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
                 == PowerManager.PARTIAL_WAKE_LOCK) {
-            boolean disabled = false;
             if (mDeviceIdleMode) {
                 final int appid = UserHandle.getAppId(wakeLock.mOwnerUid);
                 // If we are in idle mode, we will ignore all partial wake locks that are
@@ -2480,10 +2525,16 @@
                     disabled = true;
                 }
             }
-            if (wakeLock.mDisabled != disabled) {
-                wakeLock.mDisabled = disabled;
-                return true;
-            }
+        } else if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
+                == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK
+                && mUidState.get(wakeLock.mOwnerUid,
+                                 ActivityManager.PROCESS_STATE_CACHED_EMPTY)
+                > ActivityManager.PROCESS_STATE_TOP) {
+            disabled = true;
+        }
+        if (wakeLock.mDisabled != disabled) {
+            wakeLock.mDisabled = disabled;
+            return true;
         }
         return false;
     }
@@ -2694,6 +2745,7 @@
             pw.println("  mBatteryLevelLow=" + mBatteryLevelLow);
             pw.println("  mLightDeviceIdleMode=" + mLightDeviceIdleMode);
             pw.println("  mDeviceIdleMode=" + mDeviceIdleMode);
+            pw.println("  mSustainedPerformanceMode=" + mSustainedPerformanceMode);
             pw.println("  mDeviceIdleWhitelist=" + Arrays.toString(mDeviceIdleWhitelist));
             pw.println("  mDeviceIdleTempWhitelist=" + Arrays.toString(mDeviceIdleTempWhitelist));
             pw.println("  mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
@@ -2808,6 +2860,14 @@
             pw.println();
             pw.println("Display Power: " + mDisplayPowerCallbacks);
 
+            pw.println();
+            pw.println("Sustained Performance UIDs:");
+            for (int i=0; i<mSustainedPerformanceUid.size(); i++) {
+                pw.print("  UID "); UserHandle.formatUid(pw, mSustainedPerformanceUid.keyAt(i));
+                pw.print(": "); pw.println(mSustainedPerformanceUid.valueAt(i));
+            }
+
+
             wcd = mWirelessChargerDetector;
         }
 
diff --git a/services/core/java/com/android/server/search/SearchManagerService.java b/services/core/java/com/android/server/search/SearchManagerService.java
index 4c7f888..e3e1097 100644
--- a/services/core/java/com/android/server/search/SearchManagerService.java
+++ b/services/core/java/com/android/server/search/SearchManagerService.java
@@ -23,19 +23,16 @@
 import android.app.ISearchManager;
 import android.app.SearchManager;
 import android.app.SearchableInfo;
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.database.ContentObserver;
 import android.os.Binder;
 import android.os.Bundle;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -43,9 +40,11 @@
 import android.util.Log;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.LocalServices;
+import com.android.server.SystemService;
 import com.android.server.statusbar.StatusBarManagerInternal;
 
 import java.io.FileDescriptor;
@@ -53,19 +52,42 @@
 import java.util.List;
 
 /**
- * The search manager service handles the search UI, and maintains a registry of searchable
- * activities.
+ * The search manager service handles the search UI, and maintains a registry of
+ * searchable activities.
  */
 public class SearchManagerService extends ISearchManager.Stub {
-
-    // general debugging support
     private static final String TAG = "SearchManagerService";
 
+    public static class Lifecycle extends SystemService {
+        private SearchManagerService mService;
+
+        public Lifecycle(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onStart() {
+            mService = new SearchManagerService(getContext());
+            publishBinderService(Context.SEARCH_SERVICE, mService);
+        }
+
+        @Override
+        public void onUnlockUser(int userHandle) {
+            mService.onUnlockUser(userHandle);
+        }
+
+        @Override
+        public void onCleanupUser(int userHandle) {
+            mService.onCleanupUser(userHandle);
+        }
+    }
+
     // Context that the service is running in.
     private final Context mContext;
 
     // This field is initialized lazily in getSearchables(), and then never modified.
-    private final SparseArray<Searchables> mSearchables = new SparseArray<Searchables>();
+    @GuardedBy("mSearchables")
+    private final SparseArray<Searchables> mSearchables = new SparseArray<>();
 
     /**
      * Initializes the Search Manager service in the provided system context.
@@ -75,65 +97,47 @@
      */
     public SearchManagerService(Context context)  {
         mContext = context;
-        IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
-        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
-        mContext.registerReceiver(new BootCompletedReceiver(), filter);
-        mContext.registerReceiver(new UserReceiver(),
-                new IntentFilter(Intent.ACTION_USER_REMOVED));
         new MyPackageMonitor().register(context, null, UserHandle.ALL, true);
+        new GlobalSearchProviderObserver(context.getContentResolver());
     }
 
     private Searchables getSearchables(int userId) {
-        long origId = Binder.clearCallingIdentity();
+        return getSearchables(userId, false);
+    }
+
+    private Searchables getSearchables(int userId, boolean forceUpdate) {
+        final long token = Binder.clearCallingIdentity();
         try {
-            boolean userExists = ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
-                    .getUserInfo(userId) != null;
-            if (!userExists) return null;
+            final UserManager um = mContext.getSystemService(UserManager.class);
+            if (um.getUserInfo(userId) == null) {
+                throw new IllegalStateException("User " + userId + " doesn't exist");
+            }
+            if (!um.isUserUnlocked(userId)) {
+                throw new IllegalStateException("User " + userId + " isn't unlocked");
+            }
         } finally {
-            Binder.restoreCallingIdentity(origId);
+            Binder.restoreCallingIdentity(token);
         }
         synchronized (mSearchables) {
             Searchables searchables = mSearchables.get(userId);
-
             if (searchables == null) {
-                //Log.i(TAG, "Building list of searchable activities for userId=" + userId);
                 searchables = new Searchables(mContext, userId);
-                searchables.buildSearchableList();
+                searchables.updateSearchableList();
                 mSearchables.append(userId, searchables);
+            } else if (forceUpdate) {
+                searchables.updateSearchableList();
             }
             return searchables;
         }
     }
 
-    private void onUserRemoved(int userId) {
-        if (userId != UserHandle.USER_NULL) {
-            synchronized (mSearchables) {
-                mSearchables.remove(userId);
-            }
-        }
+    private void onUnlockUser(int userId) {
+        getSearchables(userId, true);
     }
 
-    /**
-     * Creates the initial searchables list after boot.
-     */
-    private final class BootCompletedReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            new Thread() {
-                @Override
-                public void run() {
-                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-                    mContext.unregisterReceiver(BootCompletedReceiver.this);
-                    getSearchables(0);
-                }
-            }.start();
-        }
-    }
-
-    private final class UserReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL));
+    private void onCleanupUser(int userId) {
+        synchronized (mSearchables) {
+            mSearchables.remove(userId);
         }
     }
 
@@ -158,7 +162,7 @@
                 // Update list of searchable activities
                 for (int i = 0; i < mSearchables.size(); i++) {
                     if (changingUserId == mSearchables.keyAt(i)) {
-                        getSearchables(mSearchables.keyAt(i)).buildSearchableList();
+                        mSearchables.valueAt(i).updateSearchableList();
                         break;
                     }
                 }
@@ -187,14 +191,13 @@
         public void onChange(boolean selfChange) {
             synchronized (mSearchables) {
                 for (int i = 0; i < mSearchables.size(); i++) {
-                    getSearchables(mSearchables.keyAt(i)).buildSearchableList();
+                    mSearchables.valueAt(i).updateSearchableList();
                 }
             }
             Intent intent = new Intent(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
         }
-
     }
 
     //
@@ -208,6 +211,7 @@
      * @return Returns a SearchableInfo record describing the parameters of the search,
      * or null if no searchable metadata was available.
      */
+    @Override
     public SearchableInfo getSearchableInfo(final ComponentName launchActivity) {
         if (launchActivity == null) {
             Log.e(TAG, "getSearchableInfo(), activity == null");
@@ -219,10 +223,12 @@
     /**
      * Returns a list of the searchable activities that can be included in global search.
      */
+    @Override
     public List<SearchableInfo> getSearchablesInGlobalSearch() {
         return getSearchables(UserHandle.getCallingUserId()).getSearchablesInGlobalSearchList();
     }
 
+    @Override
     public List<ResolveInfo> getGlobalSearchActivities() {
         return getSearchables(UserHandle.getCallingUserId()).getGlobalSearchActivities();
     }
@@ -230,6 +236,7 @@
     /**
      * Gets the name of the global search activity.
      */
+    @Override
     public ComponentName getGlobalSearchActivity() {
         return getSearchables(UserHandle.getCallingUserId()).getGlobalSearchActivity();
     }
@@ -237,6 +244,7 @@
     /**
      * Gets the name of the web search activity.
      */
+    @Override
     public ComponentName getWebSearchActivity() {
         return getSearchables(UserHandle.getCallingUserId()).getWebSearchActivity();
     }
diff --git a/services/core/java/com/android/server/search/Searchables.java b/services/core/java/com/android/server/search/Searchables.java
index 0ffbb7d..0046fbb 100644
--- a/services/core/java/com/android/server/search/Searchables.java
+++ b/services/core/java/com/android/server/search/Searchables.java
@@ -200,7 +200,7 @@
      *
      * TODO: sort the list somehow?  UI choice.
      */
-    public void buildSearchableList() {
+    public void updateSearchableList() {
         // These will become the new values at the end of the method
         HashMap<ComponentName, SearchableInfo> newSearchablesMap
                                 = new HashMap<ComponentName, SearchableInfo>();
@@ -215,11 +215,13 @@
 
         long ident = Binder.clearCallingIdentity();
         try {
-            searchList = queryIntentActivities(intent, PackageManager.GET_META_DATA);
+            searchList = queryIntentActivities(intent,
+                    PackageManager.GET_META_DATA | PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
 
             List<ResolveInfo> webSearchInfoList;
             final Intent webSearchIntent = new Intent(Intent.ACTION_WEB_SEARCH);
-            webSearchInfoList = queryIntentActivities(webSearchIntent, PackageManager.GET_META_DATA);
+            webSearchInfoList = queryIntentActivities(webSearchIntent,
+                    PackageManager.GET_META_DATA | PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
 
             // analyze each one, generate a Searchables record, and record
             if (searchList != null || webSearchInfoList != null) {
@@ -282,8 +284,8 @@
         // Step 1 : Query the package manager for a list
         // of activities that can handle the GLOBAL_SEARCH intent.
         Intent intent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
-        List<ResolveInfo> activities =
-                    queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
+        List<ResolveInfo> activities = queryIntentActivities(intent,
+                PackageManager.MATCH_DEFAULT_ONLY | PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
         if (activities != null && !activities.isEmpty()) {
             // Step 2: Rank matching activities according to our heuristics.
             Collections.sort(activities, GLOBAL_SEARCH_RANKER);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index fc27170..2a1f46e 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -17,22 +17,20 @@
 package com.android.server.statusbar;
 
 import android.app.StatusBarManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
+import android.util.ArrayMap;
 import android.util.Slog;
-
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.statusbar.StatusBarIconList;
 import com.android.server.LocalServices;
 import com.android.server.notification.NotificationDelegate;
 import com.android.server.wm.WindowManagerService;
@@ -56,7 +54,7 @@
     private Handler mHandler = new Handler();
     private NotificationDelegate mNotificationDelegate;
     private volatile IStatusBar mBar;
-    private StatusBarIconList mIcons = new StatusBarIconList();
+    private ArrayMap<String, StatusBarIcon> mIcons = new ArrayMap<>();
 
     // for disabling the status bar
     private final ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
@@ -96,9 +94,6 @@
         mContext = context;
         mWindowManager = windowManager;
 
-        final Resources res = context.getResources();
-        mIcons.defineSlots(res.getStringArray(com.android.internal.R.array.config_statusBarIcons));
-
         LocalServices.addService(StatusBarManagerInternal.class, mInternalService);
     }
 
@@ -300,19 +295,14 @@
         enforceStatusBar();
 
         synchronized (mIcons) {
-            int index = mIcons.getSlotIndex(slot);
-            if (index < 0) {
-                throw new SecurityException("invalid status bar icon slot: " + slot);
-            }
-
             StatusBarIcon icon = new StatusBarIcon(iconPackage, UserHandle.SYSTEM, iconId,
                     iconLevel, 0, contentDescription);
             //Slog.d(TAG, "setIcon slot=" + slot + " index=" + index + " icon=" + icon);
-            mIcons.setIcon(index, icon);
+            mIcons.put(slot, icon);
 
             if (mBar != null) {
                 try {
-                    mBar.setIcon(index, icon);
+                    mBar.setIcon(slot, icon);
                 } catch (RemoteException ex) {
                 }
             }
@@ -320,26 +310,20 @@
     }
 
     @Override
-    public void setIconVisibility(String slot, boolean visible) {
+    public void setIconVisibility(String slot, boolean visibility) {
         enforceStatusBar();
 
         synchronized (mIcons) {
-            int index = mIcons.getSlotIndex(slot);
-            if (index < 0) {
-                throw new SecurityException("invalid status bar icon slot: " + slot);
-            }
-
-            StatusBarIcon icon = mIcons.getIcon(index);
+            StatusBarIcon icon = mIcons.get(slot);
             if (icon == null) {
                 return;
             }
-
-            if (icon.visible != visible) {
-                icon.visible = visible;
+            if (icon.visible != visibility) {
+                icon.visible = visibility;
 
                 if (mBar != null) {
                     try {
-                        mBar.setIcon(index, icon);
+                        mBar.setIcon(slot, icon);
                     } catch (RemoteException ex) {
                     }
                 }
@@ -352,16 +336,11 @@
         enforceStatusBar();
 
         synchronized (mIcons) {
-            int index = mIcons.getSlotIndex(slot);
-            if (index < 0) {
-                throw new SecurityException("invalid status bar icon slot: " + slot);
-            }
-
-            mIcons.removeIcon(index);
+            mIcons.remove(slot);
 
             if (mBar != null) {
                 try {
-                    mBar.removeIcon(index);
+                    mBar.removeIcon(slot);
                 } catch (RemoteException ex) {
                 }
             }
@@ -503,10 +482,10 @@
     }
 
     @Override
-    public void showKeyboardShortcutsMenu() {
+    public void toggleKeyboardShortcutsMenu() {
         if (mBar != null) {
             try {
-                mBar.showKeyboardShortcutsMenu();
+                mBar.toggleKeyboardShortcutsMenu();
             } catch (RemoteException ex) {}
         }
     }
@@ -583,14 +562,17 @@
     // Callbacks from the status bar service.
     // ================================================================================
     @Override
-    public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList,
-            int switches[], List<IBinder> binders) {
+    public void registerStatusBar(IStatusBar bar, List<String> iconSlots,
+            List<StatusBarIcon> iconList, int switches[], List<IBinder> binders) {
         enforceStatusBarService();
 
         Slog.i(TAG, "registerStatusBar bar=" + bar);
         mBar = bar;
         synchronized (mIcons) {
-            iconList.copyFrom(mIcons);
+            for (String slot : mIcons.keySet()) {
+                iconSlots.add(slot);
+                iconList.add(mIcons.get(slot));
+            }
         }
         synchronized (mLock) {
             switches[0] = gatherDisableActionsLocked(mCurrentUserId, 1);
@@ -812,10 +794,6 @@
             return;
         }
 
-        synchronized (mIcons) {
-            mIcons.dump(pw);
-        }
-
         synchronized (mLock) {
             pw.println("  mDisabled1=0x" + Integer.toHexString(mDisabled1));
             pw.println("  mDisabled2=0x" + Integer.toHexString(mDisabled2));
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index d888c56..b54e866 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -60,7 +60,6 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
 import android.util.Xml;
 import android.view.IWindowManager;
 import android.view.WindowManagerGlobal;
@@ -103,6 +102,9 @@
     private static final int MSG_CLEANUP_USER = 8;
     private static final int MSG_SWITCH_USER = 9;
     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 final ArraySet<AgentInfo> mActiveAgents = new ArraySet<>();
     private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<>();
@@ -120,6 +122,11 @@
     @GuardedBy("mDeviceLockedForUser")
     private final SparseBooleanArray mDeviceLockedForUser = new SparseBooleanArray();
 
+    @GuardedBy("mDeviceLockedForUser")
+    private final SparseBooleanArray mTrustUsuallyManagedForUser = new SparseBooleanArray();
+
+    private final StrongAuthTracker mStrongAuthTracker;
+
     private boolean mTrustAgentsCanRun = false;
     private int mCurrentUser = UserHandle.USER_SYSTEM;
 
@@ -129,6 +136,13 @@
         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);
+            }
+        };
     }
 
     @Override
@@ -187,7 +201,12 @@
     }
 
     public void updateTrust(int userId, int flags) {
-        dispatchOnTrustManagedChanged(aggregateIsTrustManaged(userId), userId);
+        boolean managed = aggregateIsTrustManaged(userId);
+        dispatchOnTrustManagedChanged(managed, userId);
+        if (mStrongAuthTracker.isTrustAllowedForUser(userId)
+                && isTrustUsuallyManagedInternal(userId) != managed) {
+            updateTrustUsuallyManaged(userId, managed);
+        }
         boolean trusted = aggregateIsTrusted(userId);
         boolean changed;
         synchronized (mUserIsTrusted) {
@@ -200,6 +219,18 @@
         }
     }
 
+    private void updateTrustUsuallyManaged(int userId, boolean managed) {
+        synchronized (mTrustUsuallyManagedForUser) {
+            mTrustUsuallyManagedForUser.put(userId, managed);
+        }
+        // Wait a few minutes before committing to flash, in case the trust agent is transiently not
+        // managing trust (crashed, needs to acknowledge DPM restrictions, etc).
+        mHandler.removeMessages(MSG_FLUSH_TRUST_USUALLY_MANAGED);
+        mHandler.sendMessageDelayed(
+                mHandler.obtainMessage(MSG_FLUSH_TRUST_USUALLY_MANAGED),
+                TRUST_USUALLY_MANAGED_FLUSH_DELAY);
+    }
+
     void refreshAgentList(int userId) {
         if (DEBUG) Slog.d(TAG, "refreshAgentList()");
         if (!mTrustAgentsCanRun) {
@@ -290,14 +321,9 @@
     }
 
     public void setDeviceLockedForUser(int userId, boolean locked) {
-        if (LockPatternUtils.isSeparateWorkChallengeEnabled()) {
-            UserInfo info = mUserManager.getUserInfo(userId);
-            if (info.isManagedProfile()) {
-                synchronized (mDeviceLockedForUser) {
-                    mDeviceLockedForUser.put(userId, locked);
-                }
-            } else {
-                Log.wtf(TAG, "Requested to change lock state for non-profile user " + userId);
+        if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
+            synchronized (mDeviceLockedForUser) {
+                mDeviceLockedForUser.put(userId, locked);
             }
         }
     }
@@ -669,24 +695,29 @@
         public boolean isDeviceLocked(int userId) throws RemoteException {
             userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
                     false /* allowAll */, true /* requireFull */, "isDeviceLocked", null);
-            if (!LockPatternUtils.isSeparateWorkChallengeEnabled()) {
-                userId = resolveProfileParent(userId);
-            }
 
-            return isDeviceLockedInner(userId);
+            long token = Binder.clearCallingIdentity();
+            try {
+                if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
+                    userId = resolveProfileParent(userId);
+                }
+                return isDeviceLockedInner(userId);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
         }
 
         @Override
         public boolean isDeviceSecure(int userId) throws RemoteException {
             userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
                     false /* allowAll */, true /* requireFull */, "isDeviceSecure", null);
-            if (!LockPatternUtils.isSeparateWorkChallengeEnabled()) {
-                userId = resolveProfileParent(userId);
-            }
 
             long token = Binder.clearCallingIdentity();
             try {
-                return new LockPatternUtils(mContext).isSecure(userId);
+                if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
+                    userId = resolveProfileParent(userId);
+                }
+                return mLockPatternUtils.isSecure(userId);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -783,11 +814,41 @@
 
         @Override
         public void setDeviceLockedForUser(int userId, boolean value) {
+            enforceReportPermission();
             mHandler.obtainMessage(MSG_SET_DEVICE_LOCKED, value ? 1 : 0, userId)
                     .sendToTarget();
         }
+
+        @Override
+        public boolean isTrustUsuallyManaged(int userId) {
+            mContext.enforceCallingPermission(Manifest.permission.TRUST_LISTENER,
+                    "query trust state");
+            return isTrustUsuallyManagedInternal(userId);
+        }
     };
 
+    private boolean isTrustUsuallyManagedInternal(int userId) {
+        synchronized (mTrustUsuallyManagedForUser) {
+            int i = mTrustUsuallyManagedForUser.indexOfKey(userId);
+            if (i >= 0) {
+                return mTrustUsuallyManagedForUser.valueAt(i);
+            }
+        }
+        // It's not in memory yet, get the value from persisted storage instead
+        boolean persistedValue = mLockPatternUtils.isTrustUsuallyManaged(userId);
+        synchronized (mTrustUsuallyManagedForUser) {
+            int i = mTrustUsuallyManagedForUser.indexOfKey(userId);
+            if (i >= 0) {
+                // Someone set the trust usually managed in the mean time. Better use that.
+                return mTrustUsuallyManagedForUser.valueAt(i);
+            } else {
+                // .. otherwise it's safe to cache the fetched value now.
+                mTrustUsuallyManagedForUser.put(userId, persistedValue);
+                return persistedValue;
+            }
+        }
+    }
+
     private int resolveProfileParent(int userId) {
         long identity = Binder.clearCallingIdentity();
         try {
@@ -833,6 +894,19 @@
                 case MSG_SET_DEVICE_LOCKED:
                     setDeviceLockedForUser(msg.arg2, msg.arg1 != 0);
                     break;
+                case MSG_FLUSH_TRUST_USUALLY_MANAGED:
+                    SparseBooleanArray usuallyManaged;
+                    synchronized (mTrustUsuallyManagedForUser) {
+                        usuallyManaged = mTrustUsuallyManagedForUser.clone();
+                    }
+
+                    for (int i = 0; i < usuallyManaged.size(); i++) {
+                        int userId = usuallyManaged.keyAt(i);
+                        boolean value = usuallyManaged.valueAt(i);
+                        if (value != mLockPatternUtils.isTrustUsuallyManaged(userId)) {
+                            mLockPatternUtils.setTrustUsuallyManaged(value, userId);
+                        }
+                    }
             }
         }
     };
@@ -855,13 +929,6 @@
         }
     };
 
-    private final StrongAuthTracker mStrongAuthTracker = new StrongAuthTracker() {
-        @Override
-        public void onStrongAuthRequiredChanged(int userId) {
-            refreshAgentList(userId);
-        }
-    };
-
     private class Receiver extends BroadcastReceiver {
 
         @Override
diff --git a/services/core/java/com/android/server/tv/TvInputHal.java b/services/core/java/com/android/server/tv/TvInputHal.java
index a035826..ebbb8b3 100644
--- a/services/core/java/com/android/server/tv/TvInputHal.java
+++ b/services/core/java/com/android/server/tv/TvInputHal.java
@@ -116,7 +116,7 @@
 
     public void close() {
         synchronized (mLock) {
-            if (mPtr != 0l) {
+            if (mPtr != 0L) {
                 nativeClose(mPtr);
             }
         }
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 7f4c42b..578428b 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -17,6 +17,7 @@
 package com.android.server.tv;
 
 import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED;
+import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED_STANDBY;
 import static android.media.tv.TvInputManager.INPUT_STATE_DISCONNECTED;
 
 import android.content.BroadcastReceiver;
@@ -38,6 +39,7 @@
 import android.media.AudioPatch;
 import android.media.AudioPort;
 import android.media.AudioPortConfig;
+import android.media.AudioSystem;
 import android.media.tv.ITvInputHardware;
 import android.media.tv.ITvInputHardwareCallback;
 import android.media.tv.TvInputHardwareInfo;
@@ -102,7 +104,6 @@
     private int mCurrentIndex = 0;
     private int mCurrentMaxIndex = 0;
 
-    // TODO: Should handle STANDBY case.
     private final SparseBooleanArray mHdmiStateMap = new SparseBooleanArray();
     private final List<Message> mPendingHdmiDeviceEvents = new LinkedList<>();
 
@@ -206,7 +207,7 @@
             String inputId = mHardwareInputIdMap.get(deviceId);
             if (inputId != null) {
                 mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
-                        convertConnectedToState(configs.length > 0), 0, inputId).sendToTarget();
+                        obtainStateFromConfigs(configs), 0, inputId).sendToTarget();
             }
             ITvInputHardwareCallback callback = connection.getCallbackLocked();
             if (callback != null) {
@@ -256,12 +257,13 @@
                 || connectionCallingUid != callingUid || connectionResolvedUserId != resolvedUserId;
     }
 
-    private int convertConnectedToState(boolean connected) {
-        if (connected) {
-            return INPUT_STATE_CONNECTED;
-        } else {
-            return INPUT_STATE_DISCONNECTED;
+    private int obtainStateFromConfigs(TvStreamConfig[] configs) {
+        for (TvStreamConfig config : configs) {
+            if ((config.getFlags() & TvStreamConfig.FLAG_MASK_SIGNAL_DETECTION) != 0) {
+                return INPUT_STATE_CONNECTED;
+            }
         }
+        return (configs.length > 0) ? INPUT_STATE_CONNECTED_STANDBY : INPUT_STATE_DISCONNECTED;
     }
 
     public void addHardwareTvInput(int deviceId, TvInputInfo info) {
@@ -286,9 +288,14 @@
                 }
                 String inputId = mHardwareInputIdMap.get(hardwareInfo.getDeviceId());
                 if (inputId != null && inputId.equals(info.getId())) {
-                    mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
-                            convertConnectedToState(mHdmiStateMap.valueAt(i)), 0,
-                            inputId).sendToTarget();
+                    // No HDMI hotplug does not necessarily mean disconnected, as old devices may
+                    // not report hotplug state correctly. Using INPUT_STATE_CONNECTED_STANDBY to
+                    // denote unknown state.
+                    int state = mHdmiStateMap.valueAt(i)
+                            ? INPUT_STATE_CONNECTED
+                            : INPUT_STATE_CONNECTED_STANDBY;
+                    mHandler.obtainMessage(
+                            ListenerHandler.STATE_CHANGED, state, 0, inputId).sendToTarget();
                     return;
                 }
             }
@@ -296,7 +303,7 @@
             Connection connection = mConnections.get(deviceId);
             if (connection != null) {
                 mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
-                        convertConnectedToState(connection.getConfigsLocked().length > 0), 0,
+                        obtainStateFromConfigs(connection.getConfigsLocked()), 0,
                         info.getId()).sendToTarget();
             }
         }
@@ -697,7 +704,8 @@
             }
             int sinkDevice = mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC);
             for (AudioDevicePort port : devicePorts) {
-                if ((port.type() & sinkDevice) != 0) {
+                if ((port.type() & sinkDevice) != 0 &&
+                    (port.type() & AudioSystem.DEVICE_BIT_IN) == 0) {
                     sinks.add(port);
                 }
             }
@@ -1110,8 +1118,14 @@
                 if (inputId == null) {
                     return;
                 }
-                mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
-                        convertConnectedToState(event.isConnected()), 0, inputId).sendToTarget();
+                // No HDMI hotplug does not necessarily mean disconnected, as old devices may
+                // not report hotplug state correctly. Using INPUT_STATE_CONNECTED_STANDBY to
+                // denote unknown state.
+                int state = event.isConnected()
+                        ? INPUT_STATE_CONNECTED
+                        : INPUT_STATE_CONNECTED_STANDBY;
+                mHandler.obtainMessage(
+                        ListenerHandler.STATE_CHANGED, state, 0, inputId).sendToTarget();
             }
         }
     }
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index d814ebf..318f966 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -71,6 +71,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.text.TextUtils;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.InputChannel;
@@ -314,7 +315,8 @@
                 }
             } else {
                 try {
-                    inputList.add(TvInputInfo.createTvInputInfo(mContext, ri));
+                    TvInputInfo info = new TvInputInfo.Builder(mContext, ri).build();
+                    inputList.add(info);
                 } catch (XmlPullParserException | IOException e) {
                     Slog.e(TAG, "failed to load TV input " + si.name, e);
                     continue;
@@ -435,7 +437,11 @@
         for (SessionState state : userState.sessionStateMap.values()) {
             if (state.session != null) {
                 try {
-                    state.session.release();
+                    if (state.isRecordingSession) {
+                        state.session.disconnect();
+                    } else {
+                        state.session.release();
+                    }
                 } catch (RemoteException e) {
                     Slog.e(TAG, "error in release", e);
                 }
@@ -465,7 +471,7 @@
         try {
             context = mContext.createPackageContextAsUser("android", 0, user);
         } catch (NameNotFoundException e) {
-            Slog.e(TAG, "failed to create package contenxt as user " + user);
+            Slog.e(TAG, "failed to create package context as user " + user);
             context = mContext;
         }
         return context.getContentResolver();
@@ -604,7 +610,11 @@
 
         // Create a session. When failed, send a null token immediately.
         try {
-            service.createSession(channels[1], callback, sessionState.info.getId());
+            if (sessionState.isRecordingSession) {
+                service.createRecordingSession(callback, sessionState.info.getId());
+            } else {
+                service.createSession(channels[1], callback, sessionState.info.getId());
+            }
         } catch (RemoteException e) {
             Slog.e(TAG, "error in createSession", e);
             removeSessionStateLocked(sessionToken, userId);
@@ -632,7 +642,11 @@
                 if (sessionToken == userState.mainSessionToken) {
                     setMainLocked(sessionToken, false, callingUid, userId);
                 }
-                sessionState.session.release();
+                if (sessionState.isRecordingSession) {
+                    sessionState.session.disconnect();
+                } else {
+                    sessionState.session.release();
+                }
             }
         } catch (RemoteException | SessionNotFoundException e) {
             Slog.e(TAG, "error in releaseSession", e);
@@ -766,6 +780,20 @@
         }
     }
 
+    private void setTvInputInfoLocked(UserState userState, TvInputInfo inputInfo) {
+        if (DEBUG) {
+            Slog.d(TAG, "setTvInputInfoLocked(inputInfo=" + inputInfo + ")");
+        }
+        // TODO: Also update the internal input list.
+        for (ITvInputManagerCallback callback : userState.callbackSet) {
+            try {
+                callback.onTvInputInfoChanged(inputInfo);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "failed to report changed input info to callback", e);
+            }
+        }
+    }
+
     private void setStateLocked(String inputId, int state, int userId) {
         UserState userState = getOrCreateUserStateLocked(userId);
         TvInputState inputState = userState.inputMap.get(inputId);
@@ -818,6 +846,36 @@
             }
         }
 
+        public void setTvInputInfo(TvInputInfo inputInfo, int userId) {
+            String inputInfoPackageName = inputInfo.getServiceInfo().packageName;
+            String callingPackageName = getCallingPackageName();
+            if (!TextUtils.equals(inputInfoPackageName, callingPackageName)) {
+                throw new IllegalArgumentException("calling package " + callingPackageName
+                        + " is not allowed to change TvInputInfo for " + inputInfoPackageName);
+            }
+
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
+                    Binder.getCallingUid(), userId, "setTvInputInfoChanged");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    UserState userState = getOrCreateUserStateLocked(resolvedUserId);
+                    setTvInputInfoLocked(userState, inputInfo);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        private String getCallingPackageName() {
+            final String[] packages = mContext.getPackageManager().getPackagesForUid(
+                    Binder.getCallingUid());
+            if (packages != null && packages.length > 0) {
+                return packages[0];
+            }
+            return "unknown";
+        }
+
         @Override
         public int getTvInputState(String inputId, int userId) {
             final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
@@ -1005,7 +1063,7 @@
 
         @Override
         public void createSession(final ITvInputClient client, final String inputId,
-                int seq, int userId) {
+                boolean isRecordingSession, int seq, int userId) {
             final int callingUid = Binder.getCallingUid();
             final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
                     userId, "createSession");
@@ -1033,8 +1091,8 @@
 
                     // Create a new session token and a session state.
                     IBinder sessionToken = new Binder();
-                    SessionState sessionState = new SessionState(sessionToken, info, client,
-                            seq, callingUid, resolvedUserId);
+                    SessionState sessionState = new SessionState(sessionToken, info,
+                            isRecordingSession, client, seq, callingUid, resolvedUserId);
 
                     // Add them to the global session state map of the current user.
                     userState.sessionStateMap.put(sessionToken, sessionState);
@@ -1375,6 +1433,26 @@
         }
 
         @Override
+        public void timeShiftPlay(IBinder sessionToken, final Uri recordedProgramUri, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "timeShiftPlay");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        getSessionLocked(sessionToken, callingUid, resolvedUserId).timeShiftPlay(
+                                recordedProgramUri);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slog.e(TAG, "error in timeShiftPlay", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public void timeShiftPause(IBinder sessionToken, int userId) {
             final int callingUid = Binder.getCallingUid();
             final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
@@ -1383,8 +1461,7 @@
             try {
                 synchronized (mLock) {
                     try {
-                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
-                                .timeShiftPause();
+                        getSessionLocked(sessionToken, callingUid, resolvedUserId).timeShiftPause();
                     } catch (RemoteException | SessionNotFoundException e) {
                         Slog.e(TAG, "error in timeShiftPause", e);
                     }
@@ -1477,6 +1554,64 @@
         }
 
         @Override
+        public void connect(IBinder sessionToken, final Uri channelUri, Bundle params, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "connect");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        getSessionLocked(sessionToken, callingUid, resolvedUserId).connect(
+                                channelUri, params);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slog.e(TAG, "error in connect", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void startRecording(IBinder sessionToken, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "startRecording");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        getSessionLocked(sessionToken, callingUid, resolvedUserId).startRecording();
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slog.e(TAG, "error in startRecording", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void stopRecording(IBinder sessionToken, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "stopRecording");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        getSessionLocked(sessionToken, callingUid, resolvedUserId).stopRecording();
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slog.e(TAG, "error in stopRecording", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public List<TvInputHardwareInfo> getHardwareList() throws RemoteException {
             if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
                     != PackageManager.PERMISSION_GRANTED) {
@@ -1912,6 +2047,7 @@
 
     private final class SessionState implements IBinder.DeathRecipient {
         private final TvInputInfo info;
+        private final boolean isRecordingSession;
         private final ITvInputClient client;
         private final int seq;
         private final int callingUid;
@@ -1922,10 +2058,11 @@
         // Not null if this session represents an external device connected to a hardware TV input.
         private IBinder hardwareSessionToken;
 
-        private SessionState(IBinder sessionToken, TvInputInfo info, ITvInputClient client,
-                int seq, int callingUid, int userId) {
+        private SessionState(IBinder sessionToken, TvInputInfo info, boolean isRecordingSession,
+                ITvInputClient client, int seq, int callingUid, int userId) {
             this.sessionToken = sessionToken;
             this.info = info;
+            this.isRecordingSession = isRecordingSession;
             this.client = client;
             this.seq = seq;
             this.callingUid = callingUid;
@@ -2393,6 +2530,78 @@
                 }
             }
         }
+
+        // For the recording session only
+        @Override
+        public void onConnected() {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slog.d(TAG, "onConnected()");
+                }
+                if (mSessionState.session == null || mSessionState.client == null) {
+                    return;
+                }
+                try {
+                    mSessionState.client.onConnected(mSessionState.seq);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "error in onConnected", e);
+                }
+            }
+        }
+
+        // For the recording session only
+        @Override
+        public void onRecordingStarted() {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slog.d(TAG, "onRecordingStarted()");
+                }
+                if (mSessionState.session == null || mSessionState.client == null) {
+                    return;
+                }
+                try {
+                    mSessionState.client.onRecordingStarted(mSessionState.seq);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "error in onRecordingStarted", e);
+                }
+            }
+        }
+
+        // For the recording session only
+        @Override
+        public void onRecordingStopped(Uri recordedProgramUri) {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slog.d(TAG, "onRecordingStopped()");
+                }
+                if (mSessionState.session == null || mSessionState.client == null) {
+                    return;
+                }
+                try {
+                    mSessionState.client.onRecordingStopped(recordedProgramUri, mSessionState.seq);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "error in onRecordingStopped", e);
+                }
+            }
+        }
+
+        // For the recording session only
+        @Override
+        public void onError(int error) {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slog.d(TAG, "onError()");
+                }
+                if (mSessionState.session == null || mSessionState.client == null) {
+                    return;
+                }
+                try {
+                    mSessionState.client.onError(error, mSessionState.seq);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "error in onError", e);
+                }
+            }
+        }
     }
 
     private static final class WatchLogHandler extends Handler {
diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java
new file mode 100644
index 0000000..42db364
--- /dev/null
+++ b/services/core/java/com/android/server/vr/VrManagerInternal.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.vr;
+
+/**
+ * VR mode local system service interface.
+ *
+ * @hide Only for use within system server.
+ */
+public abstract class VrManagerInternal {
+
+    /**
+     * Return current VR mode state.
+     *
+     * @return {@code true} if VR mode is enabled.
+     */
+    public abstract boolean isInVrMode();
+
+    /**
+     * Set the current VR mode state.
+     *
+     * @param enabled {@code true} to enable VR mode.
+     */
+    public abstract void setVrMode(boolean enabled);
+
+    /**
+     * Add a listener for VR mode state changes.
+     * <p>
+     * This listener will immediately be called with the current VR mode state.
+     * </p>
+     * @param listener the listener instance to add.
+     */
+    public abstract void registerListener(VrStateListener listener);
+
+    /**
+     * Remove the listener from the current set of listeners.
+     *
+     * @param listener the listener to remove.
+     */
+    public abstract void unregisterListener(VrStateListener listener);
+
+}
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
new file mode 100644
index 0000000..2deb0d5
--- /dev/null
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.server.SystemService;
+
+import java.util.ArrayList;
+
+/**
+ * Service tracking whether VR mode is active, and notifying listening system services of state
+ * changes.
+ *
+ * {@hide}
+ */
+public class VrManagerService extends SystemService {
+
+    public static final String TAG = "VrManagerService";
+
+    private final Object mLock = new Object();
+    private boolean mVrModeEnabled = false;
+    private ArraySet<VrStateListener> mListeners = new ArraySet<>();
+
+    private final class LocalService extends VrManagerInternal {
+        @Override
+        public boolean isInVrMode() {
+            return VrManagerService.this.getVrMode();
+        }
+
+        @Override
+        public void setVrMode(boolean enabled) {
+            VrManagerService.this.setVrMode(enabled);
+        }
+
+        @Override
+        public void registerListener(VrStateListener listener) {
+            VrManagerService.this.addListener(listener);
+        }
+
+        @Override
+        public void unregisterListener(VrStateListener listener) {
+            VrManagerService.this.removeListener(listener);
+        }
+    }
+
+    public VrManagerService(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void onStart() {
+        publishLocalService(VrManagerInternal.class, new LocalService());
+    }
+
+    private void addListener(VrStateListener listener) {
+        synchronized (mLock) {
+            mListeners.add(listener);
+        }
+    }
+
+    private void removeListener(VrStateListener listener) {
+        synchronized (mLock) {
+            mListeners.remove(listener);
+        }
+    }
+
+    private void setVrMode(boolean enabled) {
+        synchronized (mLock) {
+            if (mVrModeEnabled != enabled) {
+                mVrModeEnabled = enabled;
+                // Log mode change event.
+                Slog.i(TAG, "VR mode " + ((mVrModeEnabled) ? "enabled" : "disabled"));
+                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);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/vr/VrStateListener.java b/services/core/java/com/android/server/vr/VrStateListener.java
new file mode 100644
index 0000000..b8af4b2
--- /dev/null
+++ b/services/core/java/com/android/server/vr/VrStateListener.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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;
+
+/**
+ * Listener for state changes in VrManagerService,
+ */
+public abstract class VrStateListener {
+
+  /**
+   * Called when the VR mode state changes.
+   *
+   * @param enabled {@code true} if VR mode is enabled.
+   */
+    public abstract void onVrStateChanged(boolean enabled);
+}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 87d0700..c7d7096 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -42,6 +42,9 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapRegionDecoder;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Binder;
@@ -71,6 +74,7 @@
 import android.view.IWindowManager;
 import android.view.WindowManager;
 
+import java.io.BufferedOutputStream;
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.InputStream;
@@ -92,9 +96,11 @@
 import com.android.internal.R;
 import com.android.server.EventLogTags;
 
+import libcore.io.IoUtils;
+
 public class WallpaperManagerService extends IWallpaperManager.Stub {
     static final String TAG = "WallpaperManagerService";
-    static final boolean DEBUG = false;
+    static final boolean DEBUG = true;
 
     final Object mLock = new Object[0];
 
@@ -104,7 +110,8 @@
      */
     static final long MIN_WALLPAPER_CRASH_TIME = 10000;
     static final int MAX_WALLPAPER_COMPONENT_LOG_LENGTH = 128;
-    static final String WALLPAPER = "wallpaper";
+    static final String WALLPAPER = "wallpaper_orig";
+    static final String WALLPAPER_CROP = "wallpaper";
     static final String WALLPAPER_INFO = "wallpaper_info.xml";
 
     /**
@@ -118,6 +125,7 @@
         final WallpaperData mWallpaper;
         final File mWallpaperDir;
         final File mWallpaperFile;
+        final File mWallpaperCropFile;
         final File mWallpaperInfoFile;
 
         public WallpaperObserver(WallpaperData wallpaper) {
@@ -126,6 +134,7 @@
             mWallpaperDir = getWallpaperDir(wallpaper.userId);
             mWallpaper = wallpaper;
             mWallpaperFile = new File(mWallpaperDir, WALLPAPER);
+            mWallpaperCropFile = new File(mWallpaperDir, WALLPAPER_CROP);
             mWallpaperInfoFile = new File(mWallpaperDir, WALLPAPER_INFO);
         }
 
@@ -134,8 +143,10 @@
             if (path == null) {
                 return;
             }
+            final boolean written = (event == CLOSE_WRITE || event == MOVED_TO);
+            final File changedFile = new File(mWallpaperDir, path);
+
             synchronized (mLock) {
-                File changedFile = new File(mWallpaperDir, path);
                 if (mWallpaperFile.equals(changedFile)
                         || mWallpaperInfoFile.equals(changedFile)) {
                     // changing the wallpaper means we'll need to back up the new one
@@ -146,22 +157,111 @@
                 }
                 if (mWallpaperFile.equals(changedFile)) {
                     notifyCallbacksLocked(mWallpaper);
-                    final boolean written = (event == CLOSE_WRITE || event == MOVED_TO);
                     if (mWallpaper.wallpaperComponent == null
                             || event != CLOSE_WRITE // includes the MOVED_TO case
                             || mWallpaper.imageWallpaperPending) {
                         if (written) {
+                            // The image source has finished writing the source image,
+                            // so we now produce the crop rect (in the background), and
+                            // only publish the new displayable (sub)image as a result
+                            // of that work.
+                            generateCrop(mWallpaper);
                             mWallpaper.imageWallpaperPending = false;
+                            if (mWallpaper.setComplete != null) {
+                                try {
+                                    mWallpaper.setComplete.onWallpaperChanged();
+                                } catch (RemoteException e) {
+                                    // if this fails we don't really care; the setting app may just
+                                    // have crashed and that sort of thing is a fact of life.
+                                }
+                            }
+                            bindWallpaperComponentLocked(mImageWallpaper, true,
+                                    false, mWallpaper, null);
+                            saveSettingsLocked(mWallpaper);
                         }
-                        bindWallpaperComponentLocked(mImageWallpaper, true,
-                                false, mWallpaper, null);
-                        saveSettingsLocked(mWallpaper);
                     }
                 }
             }
         }
     }
 
+    /**
+     * Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped
+     * for display.
+     */
+    private void generateCrop(WallpaperData wallpaper) {
+        boolean success = false;
+        boolean needCrop = false;
+
+        // Analyse the source; needed in multiple cases
+        BitmapFactory.Options options = new BitmapFactory.Options();
+        options.inJustDecodeBounds = true;
+        BitmapFactory.decodeFile(wallpaper.wallpaperFile.getAbsolutePath(), options);
+
+        // Legacy case uses an empty crop rect here, so we just preserve the
+        // source image verbatim
+        if (!wallpaper.cropHint.isEmpty()) {
+            // ...clamp the crop rect to the measured bounds...
+            wallpaper.cropHint.right = Math.min(wallpaper.cropHint.right, options.outWidth);
+            wallpaper.cropHint.bottom = Math.min(wallpaper.cropHint.bottom, options.outHeight);
+            // ...and don't bother cropping if what we're left with is identity
+            needCrop = (options.outHeight >= wallpaper.cropHint.height()
+                    && options.outWidth >= wallpaper.cropHint.width());
+        }
+
+        if (!needCrop) {
+            // Simple case:  the nominal crop is at least as big as the source image,
+            // so we take the whole thing and just copy the image file directly.
+            if (DEBUG) {
+                Slog.v(TAG, "Null crop of new wallpaper; copying");
+            }
+            success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile);
+            if (!success) {
+                wallpaper.cropFile.delete();
+                // TODO: fall back to default wallpaper in this case
+            }
+        } else {
+            // Fancy case: the crop is a subrect of the source
+            FileOutputStream f = null;
+            BufferedOutputStream bos = null;
+            try {
+                BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(
+                        wallpaper.wallpaperFile.getAbsolutePath(), false);
+                Bitmap cropped = decoder.decodeRegion(wallpaper.cropHint, null);
+                decoder.recycle();
+
+                if (cropped == null) {
+                    Slog.e(TAG, "Could not decode new wallpaper");
+                } else {
+                    f = new FileOutputStream(wallpaper.cropFile);
+                    bos = new BufferedOutputStream(f, 32*1024);
+                    cropped.compress(Bitmap.CompressFormat.PNG, 90, bos);
+                    bos.flush();  // don't rely on the implicit flush-at-close when noting success
+                    success = true;
+                }
+            } catch (IOException e) {
+                if (DEBUG) {
+                    Slog.e(TAG, "I/O error decoding crop: " + e.getMessage());
+                }
+            } finally {
+                IoUtils.closeQuietly(bos);
+                IoUtils.closeQuietly(f);
+            }
+        }
+
+        if (!success) {
+            Slog.e(TAG, "Unable to apply new wallpaper");
+            wallpaper.cropFile.delete();
+        }
+
+        if (wallpaper.cropFile.exists()) {
+            boolean didRestorecon = SELinux.restorecon(wallpaper.cropFile.getAbsoluteFile());
+            if (DEBUG) {
+                Slog.v(TAG, "restorecon() of crop file returned " + didRestorecon);
+            }
+        }
+    }
+
     final Context mContext;
     final IWindowManager mIWindowManager;
     final IPackageManager mIPackageManager;
@@ -170,6 +270,12 @@
     WallpaperData mLastWallpaper;
 
     /**
+     * ID of the current wallpaper, changed every time anything sets a wallpaper.
+     * This is used for external detection of wallpaper update activity.
+     */
+    int mWallpaperId;
+
+    /**
      * Name of the component used to display bitmap wallpapers from either the gallery or
      * built-in wallpapers.
      */
@@ -183,7 +289,8 @@
 
         int userId;
 
-        File wallpaperFile;
+        final File wallpaperFile;
+        final File cropFile;
 
         /**
          * Client is currently writing a new image wallpaper.
@@ -191,6 +298,11 @@
         boolean imageWallpaperPending;
 
         /**
+         * Callback once the set + crop is finished
+         */
+        IWallpaperManagerCallback setComplete;
+
+        /**
          * Resource name if using a picture from the wallpaper gallery
          */
         String name = "";
@@ -205,6 +317,11 @@
          */
         ComponentName nextWallpaperComponent;
 
+        /**
+         * The ID of this wallpaper
+         */
+        int wallpaperId;
+
         WallpaperConnection connection;
         long lastDiedTime;
         boolean wallpaperUpdating;
@@ -219,12 +336,34 @@
         int width = -1;
         int height = -1;
 
+        /**
+         * The crop hint supplied for displaying a subset of the source image
+         */
+        final Rect cropHint = new Rect(0, 0, 0, 0);
+
         final Rect padding = new Rect(0, 0, 0, 0);
 
         WallpaperData(int userId) {
             this.userId = userId;
             wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER);
+            cropFile = new File(getWallpaperDir(userId), WALLPAPER_CROP);
         }
+
+        // Only called in single-threaded boot sequence mode
+        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;
+        }
+    }
+
+    int makeWallpaperIdLocked() {
+        do {
+            ++mWallpaperId;
+        } while (mWallpaperId == 0);
+        return mWallpaperId;
     }
 
     class WallpaperConnection extends IWallpaperConnection.Stub
@@ -333,7 +472,7 @@
         public ParcelFileDescriptor setWallpaper(String name) {
             synchronized (mLock) {
                 if (mWallpaper.connection == this) {
-                    return updateWallpaperBitmapLocked(name, mWallpaper);
+                    return updateWallpaperBitmapLocked(name, mWallpaper, null);
                 }
                 return null;
             }
@@ -504,6 +643,9 @@
     public void systemRunning() {
         if (DEBUG) Slog.v(TAG, "systemReady");
         WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
+        if (!wallpaper.ensureCropExists()) {
+            clearWallpaperLocked(false, UserHandle.USER_SYSTEM, null);
+        }
         switchWallpaper(wallpaper, null);
         wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
         wallpaper.wallpaperObserver.startWatching();
@@ -582,6 +724,8 @@
             onStoppingUser(userId);
             File wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER);
             wallpaperFile.delete();
+            File cropFile = new File(getWallpaperDir(userId), WALLPAPER_CROP);
+            cropFile.delete();
             File wallpaperInfoFile = new File(getWallpaperDir(userId), WALLPAPER_INFO);
             wallpaperInfoFile.delete();
         }
@@ -633,9 +777,9 @@
         if (wallpaper == null) {
             return;
         }
-        File f = new File(getWallpaperDir(userId), WALLPAPER);
-        if (f.exists()) {
-            f.delete();
+        if (wallpaper.wallpaperFile.exists()) {
+            wallpaper.wallpaperFile.delete();
+            wallpaper.cropFile.delete();
         }
         final long ident = Binder.clearCallingIdentity();
         try {
@@ -824,11 +968,10 @@
                     outParams.putInt("height", wallpaper.height);
                 }
                 wallpaper.callbacks.register(cb);
-                File f = new File(getWallpaperDir(wallpaperUserId), WALLPAPER);
-                if (!f.exists()) {
+                if (!wallpaper.cropFile.exists()) {
                     return null;
                 }
-                return ParcelFileDescriptor.open(f, MODE_READ_ONLY);
+                return ParcelFileDescriptor.open(wallpaper.cropFile, MODE_READ_ONLY);
             } catch (FileNotFoundException e) {
                 /* Shouldn't happen as we check to see if the file exists */
                 Slog.w(TAG, "Error getting wallpaper", e);
@@ -848,20 +991,41 @@
         }
     }
 
-    public ParcelFileDescriptor setWallpaper(String name, String callingPackage) {
+    @Override
+    public ParcelFileDescriptor setWallpaper(String name, String callingPackage,
+            Rect cropHint, Bundle extras, int which, IWallpaperManagerCallback completion) {
         checkPermission(android.Manifest.permission.SET_WALLPAPER);
+
+        if (which == 0) {
+            return null;
+        }
+
         if (!isWallpaperSupported(callingPackage)) {
             return null;
         }
+
+        // "null" means the no-op crop, preserving the full input image
+        if (cropHint == null) {
+            cropHint = new Rect(0, 0, 0, 0);
+        } else {
+            if (cropHint.isEmpty()
+                    || cropHint.left < 0
+                    || cropHint.top < 0) {
+                return null;
+            }
+        }
+
         synchronized (mLock) {
             if (DEBUG) Slog.v(TAG, "setWallpaper");
             int userId = UserHandle.getCallingUserId();
             WallpaperData wallpaper = getWallpaperSafeLocked(userId);
             final long ident = Binder.clearCallingIdentity();
             try {
-                ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper);
+                ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper, extras);
                 if (pfd != null) {
                     wallpaper.imageWallpaperPending = true;
+                    wallpaper.setComplete = completion;
+                    wallpaper.cropHint.set(cropHint);
                 }
                 return pfd;
             } finally {
@@ -870,7 +1034,8 @@
         }
     }
 
-    ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper) {
+    ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper,
+            Bundle extras) {
         if (name == null) name = "";
         try {
             File dir = getWallpaperDir(wallpaper.userId);
@@ -888,6 +1053,14 @@
                 return null;
             }
             wallpaper.name = name;
+            wallpaper.wallpaperId = makeWallpaperIdLocked();
+            if (extras != null) {
+                extras.putInt(WallpaperManager.EXTRA_NEW_WALLPAPER_ID, wallpaper.wallpaperId);
+            }
+            if (DEBUG) {
+                Slog.v(TAG, "updateWallpaperBitmapLocked() : id=" + wallpaper.wallpaperId
+                        + " name=" + name);
+            }
             return fd;
         } catch (FileNotFoundException e) {
             Slog.w(TAG, "Error setting wallpaper", e);
@@ -1156,8 +1329,15 @@
             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));
+
+            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));
             }
@@ -1170,6 +1350,7 @@
             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)) {
@@ -1184,13 +1365,7 @@
             stream.close();
             journal.commit();
         } catch (IOException e) {
-            try {
-                if (stream != null) {
-                    stream.close();
-                }
-            } catch (IOException ex) {
-                // Ignore
-            }
+            IoUtils.closeQuietly(stream);
             journal.rollback();
         }
     }
@@ -1259,9 +1434,23 @@
                 if (type == XmlPullParser.START_TAG) {
                     String tag = parser.getName();
                     if ("wp".equals(tag)) {
+                        final String idString = parser.getAttributeValue(null, "id");
+                        if (idString != null) {
+                            final int id = wallpaper.wallpaperId = Integer.parseInt(idString);
+                            if (id > mWallpaperId) {
+                                mWallpaperId = id;
+                            }
+                        } else {
+                            wallpaper.wallpaperId = makeWallpaperIdLocked();
+                        }
+
                         wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
                         wallpaper.height = Integer.parseInt(parser
                                 .getAttributeValue(null, "height"));
+                        wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0);
+                        wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0);
+                        wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0);
+                        wallpaper.cropHint.bottom = getAttributeInt(parser, "cropBottom", 0);
                         wallpaper.padding.left = getAttributeInt(parser, "paddingLeft", 0);
                         wallpaper.padding.top = getAttributeInt(parser, "paddingTop", 0);
                         wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0);
@@ -1280,6 +1469,7 @@
                         if (DEBUG) {
                             Slog.v(TAG, "mWidth:" + wallpaper.width);
                             Slog.v(TAG, "mHeight:" + wallpaper.height);
+                            Slog.v(TAG, "cropRect:" + wallpaper.cropHint);
                             Slog.v(TAG, "mName:" + wallpaper.name);
                             Slog.v(TAG, "mNextWallpaperComponent:"
                                     + wallpaper.nextWallpaperComponent);
@@ -1301,19 +1491,22 @@
         } catch (IndexOutOfBoundsException e) {
             Slog.w(TAG, "failed parsing " + file + " " + e);
         }
-        try {
-            if (stream != null) {
-                stream.close();
-            }
-        } catch (IOException e) {
-            // Ignore
-        }
+        IoUtils.closeQuietly(stream);
 
         if (!success) {
             wallpaper.width = -1;
             wallpaper.height = -1;
+            wallpaper.cropHint.set(0, 0, 0, 0);
             wallpaper.padding.set(0, 0, 0, 0);
             wallpaper.name = "";
+        } else {
+            if (wallpaper.wallpaperId <= 0) {
+                wallpaper.wallpaperId = makeWallpaperIdLocked();
+                if (DEBUG) {
+                    Slog.w(TAG, "Didn't set wallpaper id in loadSettingsLocked(" + userId
+                            + "); now " + wallpaper.wallpaperId);
+                }
+            }
         }
 
         // We always want to have some reasonable width hint.
@@ -1324,6 +1517,11 @@
         if (wallpaper.height < baseSize) {
             wallpaper.height = baseSize;
         }
+        // and crop, if not previously specified
+        if (wallpaper.cropHint.width() <= 0
+                || wallpaper.cropHint.height() <= 0) {
+            wallpaper.cropHint.set(0, 0, wallpaper.width, wallpaper.height);
+        }
     }
 
     private int getMaximumSizeDimension() {
@@ -1346,6 +1544,7 @@
         synchronized (mLock) {
             loadSettingsLocked(0);
             wallpaper = mWallpaperMap.get(0);
+            wallpaper.wallpaperId = makeWallpaperIdLocked();    // always bump id at restore
             if (wallpaper.nextWallpaperComponent != null
                     && !wallpaper.nextWallpaperComponent.equals(mImageWallpaper)) {
                 if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
@@ -1366,7 +1565,8 @@
                     if (DEBUG) Slog.v(TAG, "settingsRestored: attempting to restore named resource");
                     success = restoreNamedResourceLocked(wallpaper);
                 }
-                if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success);
+                if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success
+                        + " id=" + wallpaper.wallpaperId);
                 if (success) {
                     bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
                             wallpaper, null);
@@ -1385,6 +1585,7 @@
         }
     }
 
+    // Restore the named resource bitmap to both source + crop files
     boolean restoreNamedResourceLocked(WallpaperData wallpaper) {
         if (wallpaper.name.length() > 4 && "res:".equals(wallpaper.name.substring(0, 4))) {
             String resName = wallpaper.name.substring(4);
@@ -1410,6 +1611,7 @@
                 int resId = -1;
                 InputStream res = null;
                 FileOutputStream fos = null;
+                FileOutputStream cos = null;
                 try {
                     Context c = mContext.createPackageContext(pkg, Context.CONTEXT_RESTRICTED);
                     Resources r = c.getResources();
@@ -1423,13 +1625,16 @@
                     res = r.openRawResource(resId);
                     if (wallpaper.wallpaperFile.exists()) {
                         wallpaper.wallpaperFile.delete();
+                        wallpaper.cropFile.delete();
                     }
                     fos = new FileOutputStream(wallpaper.wallpaperFile);
+                    cos = new FileOutputStream(wallpaper.cropFile);
 
                     byte[] buffer = new byte[32768];
                     int amt;
                     while ((amt=res.read(buffer)) > 0) {
                         fos.write(buffer, 0, amt);
+                        cos.write(buffer, 0, amt);
                     }
                     // mWallpaperObserver will notice the close and send the change broadcast
 
@@ -1442,17 +1647,15 @@
                 } catch (IOException e) {
                     Slog.e(TAG, "IOException while restoring wallpaper ", e);
                 } finally {
-                    if (res != null) {
-                        try {
-                            res.close();
-                        } catch (IOException ex) {}
-                    }
+                    IoUtils.closeQuietly(res);
                     if (fos != null) {
                         FileUtils.sync(fos);
-                        try {
-                            fos.close();
-                        } catch (IOException ex) {}
                     }
+                    if (cos != null) {
+                        FileUtils.sync(cos);
+                    }
+                    IoUtils.closeQuietly(fos);
+                    IoUtils.closeQuietly(cos);
                 }
             }
         }
@@ -1474,11 +1677,13 @@
             pw.println("Current Wallpaper Service state:");
             for (int i = 0; i < mWallpaperMap.size(); i++) {
                 WallpaperData wallpaper = mWallpaperMap.valueAt(i);
-                pw.println(" User " + wallpaper.userId + ":");
+                pw.print(" User "); pw.print(wallpaper.userId);
+                pw.print(": id="); pw.println(wallpaper.wallpaperId);
                 pw.print("  mWidth=");
                     pw.print(wallpaper.width);
                     pw.print(" mHeight=");
                     pw.println(wallpaper.height);
+                pw.print("  mCropHint="); pw.println(wallpaper.cropHint);
                 pw.print("  mPadding="); pw.println(wallpaper.padding);
                 pw.print("  mName=");  pw.println(wallpaper.name);
                 pw.print("  mWallpaperComponent="); pw.println(wallpaper.wallpaperComponent);
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 7be0ead..c3a6f5d 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -291,15 +291,24 @@
 
         // If the user has chosen provider, use that
         for (WebViewProviderInfo provider : providers) {
-            if (provider.packageName.equals(userChosenProvider)) {
+            if (provider.packageName.equals(userChosenProvider) && provider.isEnabled()) {
                 return provider.getPackageInfo();
             }
         }
 
-        // User did not choose, or the choice failed, use the most stable provider available
+        // 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();
+            }
+        }
+
+        // Could not find any enabled package either, use the most stable provider.
         for (WebViewProviderInfo provider : providers) {
             return provider.getPackageInfo();
         }
+
         mAnyWebViewInstalled = false;
         throw new WebViewFactory.MissingWebViewPackageException(
                 "Could not find a loadable WebView package");
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index a7a4ed1..43a17c9 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -39,6 +39,8 @@
 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
 import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation;
 import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
+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.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
@@ -85,9 +87,6 @@
 // made visible or hidden at the next transition.
 public class AppTransition implements Dump {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "AppTransition" : TAG_WM;
-    private static final boolean DEBUG_APP_TRANSITIONS =
-            WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
-    private static final boolean DEBUG_ANIM = WindowManagerDebugConfig.DEBUG_ANIM;
     private static final int CLIP_REVEAL_TRANSLATION_Y_DP = 8;
 
     /** Not set up for a transition. */
@@ -135,7 +134,7 @@
     /** Fraction of animation at which the recents thumbnail becomes completely transparent */
     private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.5f;
 
-    private static final int DEFAULT_APP_TRANSITION_DURATION = 336;
+    static final int DEFAULT_APP_TRANSITION_DURATION = 336;
     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;
@@ -733,7 +732,8 @@
         float scaleW = appWidth / thumbWidth;
         float unscaledHeight = thumbHeight * scaleW;
         getNextAppTransitionStartRect(taskId, mTmpRect);
-        float unscaledStartY = mTmpRect.top - (unscaledHeight - thumbHeight) / 2f;
+        final float unscaledStartY = mTmpRect.top - (unscaledHeight - thumbHeight) / 2f;
+        final float toY = appRect.top + mNextAppTransitionInsets.top + -unscaledStartY;
         if (mNextAppTransitionScaleUp) {
             // Animation up from the thumbnail to the full screen
             Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW,
@@ -745,7 +745,6 @@
             alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
             final float toX = appRect.left + appRect.width() / 2 -
                     (mTmpRect.left + thumbWidth / 2);
-            final float toY = appRect.top + mNextAppTransitionInsets.top + -unscaledStartY;
             Animation translate = new TranslateAnimation(0, toX, 0, toY);
             translate.setInterpolator(mTouchResponseInterpolator);
             translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
@@ -765,8 +764,9 @@
             Animation alpha = new AlphaAnimation(0f, 1f);
             alpha.setInterpolator(mThumbnailFadeInInterpolator);
             alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
-            Animation translate = new TranslateAnimation(0, 0, -unscaledStartY +
-                    mNextAppTransitionInsets.top, 0);
+            final float toX = appRect.left + appRect.width() / 2 -
+                    (mTmpRect.left + thumbWidth / 2);
+            Animation translate = new TranslateAnimation(toX, 0, toY, 0);
             translate.setInterpolator(mTouchResponseInterpolator);
             translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
 
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index ab47f07..e046a77 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -223,7 +223,7 @@
             }
             if (DEBUG_LAYERS) Slog.v(TAG, "Updating layer " + w + ": " + winAnimator.mAnimLayer);
             if (w == mService.mInputMethodTarget && !mService.mInputMethodTargetWaitingAnim) {
-                mService.setInputMethodAnimLayerAdjustment(adj);
+                mService.mLayersController.setInputMethodAnimLayerAdjustment(adj);
             }
             wallpaperController.setAnimLayerAdjustment(w, adj);
         }
@@ -247,7 +247,7 @@
         thumbnailTransformation.getMatrix().getValues(tmpFloats);
         if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail,
                 "thumbnail", "POS " + tmpFloats[Matrix.MTRANS_X]
-                + ", " + tmpFloats[Matrix.MTRANS_Y], null);
+                + ", " + tmpFloats[Matrix.MTRANS_Y]);
         thumbnail.setPosition(tmpFloats[Matrix.MTRANS_X], tmpFloats[Matrix.MTRANS_Y]);
         if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail,
                 "thumbnail", "alpha=" + thumbnailTransformation.getAlpha()
@@ -255,7 +255,7 @@
                 + " matrix=[" + tmpFloats[Matrix.MSCALE_X]
                 + "," + tmpFloats[Matrix.MSKEW_Y]
                 + "][" + tmpFloats[Matrix.MSKEW_X]
-                + "," + tmpFloats[Matrix.MSCALE_Y] + "]", null);
+                + "," + tmpFloats[Matrix.MSCALE_Y] + "]");
         thumbnail.setAlpha(thumbnailTransformation.getAlpha());
         if (thumbnailForceAboveLayer > 0) {
             thumbnail.setLayer(thumbnailForceAboveLayer + 1);
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index b49641f..2732821 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.ActivityManager.StackId;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
@@ -24,12 +25,14 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
 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.WINDOW_REPLACEMENT_TIMEOUT_DURATION;
 
 import com.android.server.input.InputApplicationHandle;
 import com.android.server.wm.WindowManagerService.H;
 
 import android.annotation.NonNull;
 import android.content.pm.ActivityInfo;
+import android.graphics.Rect;
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.Slog;
@@ -38,6 +41,7 @@
 import android.view.WindowManager;
 
 import java.io.PrintWriter;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 
 class AppTokenList extends ArrayList<AppWindowToken> {
@@ -63,6 +67,7 @@
     // Whether we're performing an entering animation with a saved surface.
     boolean mAnimatingWithSavedSurface;
 
+
     Task mTask;
     boolean appFullscreen;
     int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -123,6 +128,10 @@
     // True if the windows associated with this token should be cropped to their stack bounds.
     boolean mCropWindowsToStack;
 
+    boolean mAlwaysFocusable;
+
+    ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
+
     AppWindowToken(WindowManagerService _service, IApplicationToken _token,
             boolean _voiceInteraction) {
         super(_service, _token.asBinder(),
@@ -256,8 +265,8 @@
         return candidate;
     }
 
-    boolean stackCanReceiveKeys() {
-        return (windows.size() > 0) ? windows.get(windows.size() - 1).stackCanReceiveKeys() : false;
+    boolean windowsAreFocusable() {
+        return StackId.canReceiveKeys(mTask.mStack.mStackId) || mAlwaysFocusable;
     }
 
     boolean isVisible() {
@@ -293,6 +302,13 @@
         }
     }
 
+    void markSurfacesExiting() {
+        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
+            WindowState win = allAppWindows.get(i);
+            win.mExiting = true;
+        }
+    }
+
     /**
      * Checks whether we should save surfaces for this app.
      *
@@ -320,15 +336,14 @@
         if (!hasSavedSurface()) {
             return;
         }
-
-        if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG_WM,
-                "Restoring saved surfaces: " + this + ", allDrawn=" + allDrawn);
-
         mAnimatingWithSavedSurface = true;
         for (int i = windows.size() - 1; i >= 0; i--) {
             WindowState ws = windows.get(i);
             ws.restoreSavedSurface();
         }
+        // Mark the app allDrawn since it must be allDrawn at the time
+        // it was first saved.
+        allDrawn = true;
     }
 
     void destroySavedSurfaces() {
@@ -396,12 +411,39 @@
         }
     }
 
+    void setReplacingChildren() {
+        if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + appWindowToken
+                + " with replacing child windows.");
+        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
+            final WindowState w = allAppWindows.get(i);
+            if (w.isChildWindow()) {
+                w.setReplacing(false /* animate */);
+            }
+        }
+    }
+
+    void resetReplacingWindows() {
+        if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Resetting app token " + appWindowToken
+                + " of replacing window marks.");
+
+        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
+            final WindowState w = allAppWindows.get(i);
+            w.resetReplacing();
+        }
+    }
+
     void addWindow(WindowState w) {
         for (int i = allAppWindows.size() - 1; i >= 0; i--) {
             WindowState candidate = allAppWindows.get(i);
             if (candidate.mWillReplaceWindow && candidate.mReplacingWindow == null &&
                     candidate.getWindowTag().equals(w.getWindowTag().toString())) {
                 candidate.mReplacingWindow = w;
+
+                // if we got a replacement window, reset the timeout to give drawing more time
+                service.mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT);
+                service.mH.sendMessageDelayed(
+                        service.mH.obtainMessage(H.WINDOW_REPLACEMENT_TIMEOUT, this),
+                            WINDOW_REPLACEMENT_TIMEOUT_DURATION);
             }
         }
         allAppWindows.add(w);
@@ -417,7 +459,7 @@
         return false;
     }
 
-    void clearTimedoutReplaceesLocked() {
+    void clearTimedoutReplacesLocked() {
         for (int i = allAppWindows.size() - 1; i >= 0;
              // removeWindowLocked at bottom of loop may remove multiple entries from
              // allAppWindows if the window to be removed has child windows. It also may
@@ -430,10 +472,40 @@
                 continue;
             }
             candidate.mWillReplaceWindow = false;
-            service.removeWindowLocked(candidate);
+            // Since the window already timed out, remove it immediately now.
+            // Use removeWindowInnerLocked() instead of removeWindowLocked(), as the latter
+            // delays removal on certain conditions, which will leave the stale window in the
+            // stack and marked mWillReplaceWindow=false, so the window will never be removed.
+            service.removeWindowInnerLocked(candidate);
         }
     }
 
+    /**
+     * 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() {
+        mFrozenBounds.offer(new Rect(mTask.mPreparedFrozenBounds));
+    }
+
+    /**
+     * Unfreezes the previously frozen bounds. See {@link #freezeBounds}.
+     */
+    void unfreezeBounds() {
+        mFrozenBounds.remove();
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            final WindowState win = windows.get(i);
+            win.mLayoutNeeded = true;
+            win.setDisplayLayoutNeeded();
+            if (!service.mResizingWindows.contains(win)) {
+                service.mResizingWindows.add(win);
+            }
+        }
+        service.mWindowPlacerLocked.performSurfacePlacement();
+    }
+
     @Override
     void dump(PrintWriter pw, String prefix) {
         super.dump(pw, prefix);
@@ -480,6 +552,9 @@
                     pw.print(" startingDisplayed="); pw.print(startingDisplayed);
                     pw.print(" startingMoved"); pw.println(startingMoved);
         }
+        if (!mFrozenBounds.isEmpty()) {
+            pw.print(prefix); pw.print("mFrozenBounds="); pw.print(mFrozenBounds);
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
new file mode 100644
index 0000000..5f97478
--- /dev/null
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.graphics.Rect;
+import android.util.ArrayMap;
+import android.util.Slog;
+import android.view.animation.LinearInterpolator;
+
+/**
+ * Enables animating bounds of objects.
+ *
+ * In multi-window world bounds of both stack and tasks can change. When we need these bounds to
+ * change smoothly and not require the app to relaunch (e.g. because it handles resizes and
+ * relaunching it would cause poorer experience), these class provides a way to directly animate
+ * the bounds of the resized object.
+ *
+ * The object that is resized needs to implement {@link AnimateBoundsUser} interface.
+ */
+public class BoundsAnimationController {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "BoundsAnimationController" : TAG_WM;
+
+    // Only acccessed on UI thread.
+    private ArrayMap<AnimateBoundsUser, BoundsAnimator> mRunningAnimations = new ArrayMap<>();
+
+    private final class BoundsAnimator extends ValueAnimator
+            implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener {
+        private final AnimateBoundsUser mTarget;
+        private final Rect mFrom;
+        private final Rect mTo;
+        private final Rect mTmpRect;
+
+        BoundsAnimator(AnimateBoundsUser target, Rect from, Rect to) {
+            super();
+            mTarget = target;
+            mFrom = from;
+            mTo = to;
+            mTmpRect = new Rect();
+            addUpdateListener(this);
+            addListener(this);
+        }
+
+        @Override
+        public void onAnimationUpdate(ValueAnimator animation) {
+            final float value = (Float) animation.getAnimatedValue();
+            final float remains = 1 - value;
+            mTmpRect.left = (int) (mFrom.left * remains + mTo.left * value);
+            mTmpRect.top = (int) (mFrom.top * remains + mTo.top * value);
+            mTmpRect.right = (int) (mFrom.right * remains + mTo.right * value);
+            mTmpRect.bottom = (int) (mFrom.bottom * remains + mTo.bottom * value);
+            if (DEBUG_ANIM) Slog.d(TAG, "animateUpdate: mTarget=" + mTarget + ", mBounds="
+                    + mTmpRect + ", from=" + mFrom + ", mTo=" + mTo + ", value=" + value
+                    + ", remains=" + remains);
+            if (!mTarget.setSize(mTmpRect)) {
+                // Whoops, the target doesn't feel like animating anymore. Let's immediately finish
+                // any further animation.
+                animation.cancel();
+            }
+        }
+
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            finishAnimation();
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            finishAnimation();
+        }
+
+        private void finishAnimation() {
+            mTarget.finishBoundsAnimation();
+            removeListener(this);
+            removeUpdateListener(this);
+            mRunningAnimations.remove(mTarget);
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+
+        }
+    }
+
+    public interface AnimateBoundsUser {
+        /**
+         * Asks the target to directly (without any intermediate steps, like scheduling animation)
+         * resize its bounds.
+         *
+         * @return Whether the target still wants to be animated and successfully finished the
+         * operation. If it returns false, the animation will immediately be cancelled. The target
+         * should return false when something abnormal happened, e.g. it was completely removed
+         * from the hierarchy and is not valid anymore.
+         */
+        boolean setSize(Rect bounds);
+
+        /**
+         * Callback for the target to inform it that the animation is finished, so it can do some
+         * necessary cleanup.
+         */
+        void finishBoundsAnimation();
+    }
+
+    void animateBounds(AnimateBoundsUser target, Rect from, Rect to) {
+        final BoundsAnimator existing = mRunningAnimations.get(target);
+        if (existing != null) {
+            existing.cancel();
+        }
+        BoundsAnimator animator = new BoundsAnimator(target, from, to);
+        mRunningAnimations.put(target, animator);
+        animator.setFloatValues(0f, 1f);
+        animator.setDuration(DEFAULT_APP_TRANSITION_DURATION);
+        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 6657a7b..fc5d8ce 100644
--- a/services/core/java/com/android/server/wm/DimLayer.java
+++ b/services/core/java/com/android/server/wm/DimLayer.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DIM_LAYER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
@@ -33,41 +34,42 @@
 
 public class DimLayer {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "DimLayer" : TAG_WM;
-    private static final boolean DEBUG = false;
-
-    public static final float RESIZING_HINT_ALPHA = 0.5f;
-
-    public static final int RESIZING_HINT_DURATION_MS = 0;
+    private final WindowManagerService mService;
 
     /** Actual surface that dims */
-    SurfaceControl mDimSurface;
+    private SurfaceControl mDimSurface;
 
     /** Last value passed to mDimSurface.setAlpha() */
-    float mAlpha = 0;
+    private float mAlpha = 0;
 
     /** Last value passed to mDimSurface.setLayer() */
-    int mLayer = -1;
+    private int mLayer = -1;
 
     /** Next values to pass to mDimSurface.setPosition() and mDimSurface.setSize() */
-    Rect mBounds = new Rect();
+    private final Rect mBounds = new Rect();
 
     /** Last values passed to mDimSurface.setPosition() and mDimSurface.setSize() */
-    Rect mLastBounds = new Rect();
+    private final Rect mLastBounds = new Rect();
 
     /** True after mDimSurface.show() has been called, false after mDimSurface.hide(). */
     private boolean mShowing = false;
 
     /** Value of mAlpha when beginning transition to mTargetAlpha */
-    float mStartAlpha = 0;
+    private float mStartAlpha = 0;
 
     /** Final value of mAlpha following transition */
-    float mTargetAlpha = 0;
+    private float mTargetAlpha = 0;
 
     /** Time in units of SystemClock.uptimeMillis() at which the current transition started */
-    long mStartTime;
+    private long mStartTime;
 
     /** Time in milliseconds to take to transition from mStartAlpha to mTargetAlpha */
-    long mDuration;
+    private long mDuration;
+
+    private boolean mDestroyed = false;
+
+    private final int mDisplayId;
+
 
     /** Interface implemented by users of the dim layer */
     interface DimLayerUser {
@@ -80,11 +82,16 @@
         String toShortString();
     }
     /** The user of this dim layer. */
-    final DimLayerUser mUser;
+    private final DimLayerUser mUser;
 
     DimLayer(WindowManagerService service, DimLayerUser user, int displayId) {
         mUser = user;
-        if (DEBUG) Slog.v(TAG, "Ctor: displayId=" + displayId);
+        mDisplayId = displayId;
+        mService = service;
+        if (DEBUG_DIM_LAYER) Slog.v(TAG, "Ctor: displayId=" + displayId);
+    }
+
+    private void constructSurface(WindowManagerService service) {
         SurfaceControl.openTransaction();
         try {
             if (DEBUG_SURFACE_TRACE) {
@@ -99,7 +106,10 @@
             }
             if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG,
                     "  DIM " + mDimSurface + ": CREATE");
-            mDimSurface.setLayerStack(displayId);
+            mDimSurface.setLayerStack(mDisplayId);
+            adjustBounds();
+            adjustAlpha(mAlpha);
+            adjustLayer(mLayer);
         } catch (Exception e) {
             Slog.e(TAG_WM, "Exception creating Dim surface", e);
         } finally {
@@ -122,8 +132,15 @@
     }
 
     void setLayer(int layer) {
-        if (mLayer != layer) {
-            mLayer = layer;
+        if (mLayer == layer) {
+            return;
+        }
+        mLayer = layer;
+        adjustLayer(layer);
+    }
+
+    private void adjustLayer(int layer) {
+        if (mDimSurface != null) {
             mDimSurface.setLayer(layer);
         }
     }
@@ -133,23 +150,34 @@
     }
 
     private void setAlpha(float alpha) {
-        if (mAlpha != alpha) {
-            if (DEBUG) Slog.v(TAG, "setAlpha alpha=" + alpha);
-            try {
+        if (mAlpha == alpha) {
+            return;
+        }
+        mAlpha = alpha;
+        adjustAlpha(alpha);
+    }
+
+    private void adjustAlpha(float alpha) {
+        if (DEBUG_DIM_LAYER) Slog.v(TAG, "setAlpha alpha=" + alpha);
+        try {
+            if (mDimSurface != null) {
                 mDimSurface.setAlpha(alpha);
-                if (alpha == 0 && mShowing) {
-                    if (DEBUG) Slog.v(TAG, "setAlpha hiding");
+            }
+            if (alpha == 0 && mShowing) {
+                if (DEBUG_DIM_LAYER) Slog.v(TAG, "setAlpha hiding");
+                if (mDimSurface != null) {
                     mDimSurface.hide();
                     mShowing = false;
-                } else if (alpha > 0 && !mShowing) {
-                    if (DEBUG) Slog.v(TAG, "setAlpha showing");
+                }
+            } else if (alpha > 0 && !mShowing) {
+                if (DEBUG_DIM_LAYER) Slog.v(TAG, "setAlpha showing");
+                if (mDimSurface != null) {
                     mDimSurface.show();
                     mShowing = true;
                 }
-            } catch (RuntimeException e) {
-                Slog.w(TAG, "Failure setting alpha immediately", e);
             }
-            mAlpha = alpha;
+        } catch (RuntimeException e) {
+            Slog.w(TAG, "Failure setting alpha immediately", e);
         }
     }
 
@@ -176,8 +204,10 @@
             yPos = -1 * dh / 6;
         }
 
-        mDimSurface.setPosition(xPos, yPos);
-        mDimSurface.setSize(dw, dh);
+        if (mDimSurface != null) {
+            mDimSurface.setPosition(xPos, yPos);
+            mDimSurface.setSize(dw, dh);
+        }
 
         mLastBounds.set(mBounds);
     }
@@ -209,7 +239,7 @@
      * NOTE: Must be called with Surface transaction open. */
     void show() {
         if (isAnimating()) {
-            if (DEBUG) Slog.v(TAG, "show: immediate");
+            if (DEBUG_DIM_LAYER) Slog.v(TAG, "show: immediate");
             show(mLayer, mTargetAlpha, 0);
         }
     }
@@ -223,15 +253,19 @@
      * @param duration How long to take to get there in milliseconds.
      */
     void show(int layer, float alpha, long duration) {
-        if (DEBUG) Slog.v(TAG, "show: layer=" + layer + " alpha=" + alpha
-                + " duration=" + duration);
-        if (mDimSurface == null) {
+        if (DEBUG_DIM_LAYER) Slog.v(TAG, "show: layer=" + layer + " alpha=" + alpha
+                + " duration=" + duration + ", mDestroyed=" + mDestroyed);
+        if (mDestroyed) {
             Slog.e(TAG, "show: no Surface");
             // Make sure isAnimating() returns false.
             mTargetAlpha = mAlpha = 0;
             return;
         }
 
+        if (mDimSurface == null) {
+            constructSurface(mService);
+        }
+
         if (!mLastBounds.equals(mBounds)) {
             adjustBounds();
         }
@@ -252,15 +286,15 @@
             }
         }
         mTargetAlpha = alpha;
-        if (DEBUG) Slog.v(TAG, "show: mStartAlpha=" + mStartAlpha + " mStartTime=" + mStartTime
-                + " mTargetAlpha=" + mTargetAlpha);
+        if (DEBUG_DIM_LAYER) Slog.v(TAG, "show: mStartAlpha=" + mStartAlpha + " mStartTime="
+                + mStartTime + " mTargetAlpha=" + mTargetAlpha);
     }
 
     /** Immediate hide.
      * NOTE: Must be called with Surface transaction open. */
     void hide() {
         if (mShowing) {
-            if (DEBUG) Slog.v(TAG, "hide: immediate");
+            if (DEBUG_DIM_LAYER) Slog.v(TAG, "hide: immediate");
             hide(0);
         }
     }
@@ -273,7 +307,7 @@
      */
     void hide(long duration) {
         if (mShowing && (mTargetAlpha != 0 || durationEndsEarlier(duration))) {
-            if (DEBUG) Slog.v(TAG, "hide: duration=" + duration);
+            if (DEBUG_DIM_LAYER) Slog.v(TAG, "hide: duration=" + duration);
             show(mLayer, 0, duration);
         }
     }
@@ -285,13 +319,12 @@
      * @return True if animation is still required after this step.
      */
     boolean stepAnimation() {
-        if (mDimSurface == null) {
-            Slog.e(TAG, "stepAnimation: null Surface");
+        if (mDestroyed) {
+            Slog.e(TAG, "stepAnimation: surface destroyed");
             // Ensure that isAnimating() returns false;
             mTargetAlpha = mAlpha = 0;
             return false;
         }
-
         if (isAnimating()) {
             final long curTime = SystemClock.uptimeMillis();
             final float alphaDelta = mTargetAlpha - mStartAlpha;
@@ -301,7 +334,7 @@
                 // Don't exceed limits.
                 alpha = mTargetAlpha;
             }
-            if (DEBUG) Slog.v(TAG, "stepAnimation: curTime=" + curTime + " alpha=" + alpha);
+            if (DEBUG_DIM_LAYER) Slog.v(TAG, "stepAnimation: curTime=" + curTime + " alpha=" + alpha);
             setAlpha(alpha);
         }
 
@@ -310,11 +343,12 @@
 
     /** Cleanup */
     void destroySurface() {
-        if (DEBUG) Slog.v(TAG, "destroySurface.");
+        if (DEBUG_DIM_LAYER) Slog.v(TAG, "destroySurface.");
         if (mDimSurface != null) {
             mDimSurface.destroy();
             mDimSurface = null;
         }
+        mDestroyed = true;
     }
 
     public void printTo(String prefix, PrintWriter pw) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 5942198..0c429e5 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -222,6 +222,10 @@
         out.set(left, top, left + width, top + height);
     }
 
+    void getContentRect(Rect out) {
+        out.set(mContentRect);
+    }
+
     /** Refer to {@link WindowManagerService#attachStack(int, int, boolean)} */
     void attachStack(TaskStack stack, boolean onTop) {
         if (stack.mStackId == HOME_STACK_ID) {
@@ -393,7 +397,7 @@
                     }
                     mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
                 }
-                if (task.isDockedInEffect() && !task.isResizeable()) {
+                if (task.isTwoFingerScrollMode()) {
                     stack.getBounds(mTmpRect);
                     mNonResizeableRegion.op(mTmpRect, Region.Op.UNION);
                     break;
@@ -570,38 +574,19 @@
             pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
             pw.print(subPrefix); pw.print("deferred="); pw.print(mDeferredRemoval);
                 pw.print(" layoutNeeded="); pw.println(layoutNeeded);
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final TaskStack stack = mStacks.get(stackNdx);
-            pw.print(prefix); pw.print("mStacks[" + stackNdx + "]"); pw.println(stack.mStackId);
-            stack.dump(prefix + "  ", pw);
-        }
+
         pw.println();
         pw.println("  Application tokens in top down Z order:");
-        int ndx = 0;
         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
             final TaskStack stack = mStacks.get(stackNdx);
-            pw.print("  mStackId="); pw.println(stack.mStackId);
-            ArrayList<Task> tasks = stack.getTasks();
-            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                final Task task = tasks.get(taskNdx);
-                pw.print("    mTaskId="); pw.println(task.mTaskId);
-                AppTokenList tokens = task.mAppTokens;
-                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx, ++ndx) {
-                    final AppWindowToken wtoken = tokens.get(tokenNdx);
-                    pw.print("    Activity #"); pw.print(tokenNdx);
-                            pw.print(' '); pw.print(wtoken); pw.println(":");
-                    wtoken.dump(pw, "      ");
-                }
-            }
+            stack.dump(prefix + "  ", pw);
         }
-        if (ndx == 0) {
-            pw.println("    None");
-        }
+
         pw.println();
         if (!mExitingTokens.isEmpty()) {
             pw.println();
             pw.println("  Exiting tokens:");
-            for (int i=mExitingTokens.size()-1; i>=0; i--) {
+            for (int i = mExitingTokens.size() - 1; i >= 0; i--) {
                 WindowToken token = mExitingTokens.get(i);
                 pw.print("  Exiting #"); pw.print(i);
                 pw.print(' '); pw.print(token);
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 8f3d3e3..7295318 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -18,11 +18,17 @@
 
 import android.content.Context;
 import android.graphics.Rect;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.util.Slog;
-import android.view.IDockDividerVisibilityListener;
+import android.view.DisplayInfo;
+import android.view.IDockedStackListener;
+import android.view.SurfaceControl;
+
+import com.android.server.wm.DimLayer.DimLayerUser;
 
 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;
@@ -33,7 +39,7 @@
 /**
  * Keeps information about the docked stack divider.
  */
-public class DockedStackDividerController {
+public class DockedStackDividerController implements DimLayerUser {
 
     private static final String TAG = TAG_WITH_CLASS_NAME ? "DockedStackDividerController" : TAG_WM;
 
@@ -44,9 +50,10 @@
     private WindowState mWindow;
     private final Rect mTmpRect = new Rect();
     private final Rect mLastRect = new Rect();
-    private IDockDividerVisibilityListener mListener;
     private boolean mLastVisibility = false;
-    private boolean mForceVisibilityReevaluation;
+    private final RemoteCallbackList<IDockedStackListener> mDockedStackListeners
+            = new RemoteCallbackList<>();
+    private final DimLayer mDimLayer;
 
     DockedStackDividerController(Context context, DisplayContent displayContent) {
         mDisplayContent = displayContent;
@@ -54,6 +61,7 @@
                 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());
     }
 
     boolean isResizing() {
@@ -83,15 +91,16 @@
             return;
         }
         mLastVisibility = visible;
-        if (mListener != null) {
-            try {
-                mListener.onDockDividerVisibilityChanged(visible);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "visibility call failed: " + e);
-            }
+        notifyDockedDividerVisibilityChanged(visible);
+        if (!visible) {
+            setResizeDimLayer(false, INVALID_STACK_ID, 0f);
         }
     }
 
+    boolean wasVisible() {
+        return mLastVisibility;
+    }
+
     void positionDockedStackedDivider(Rect frame) {
         TaskStack stack = mDisplayContent.getDockedStackLocked();
         if (stack == null) {
@@ -127,11 +136,76 @@
         mLastRect.set(frame);
     }
 
-    public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) {
-        if (mListener != null && listener != null) {
-            throw new IllegalStateException("Dock divider visibility listener already set!");
+    void notifyDockedDividerVisibilityChanged(boolean visible) {
+        final int size = mDockedStackListeners.beginBroadcast();
+        for (int i = 0; i < size; ++i) {
+            final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
+            try {
+                listener.onDividerVisibilityChanged(visible);
+            } catch (RemoteException e) {
+                Slog.e(TAG_WM, "Error delivering divider visibility changed event.", e);
+            }
         }
-        mListener = listener;
-        reevaluateVisibility(true);
+        mDockedStackListeners.finishBroadcast();
+    }
+
+    void notifyDockedStackExistsChanged(boolean exists) {
+        final int size = mDockedStackListeners.beginBroadcast();
+        for (int i = 0; i < size; ++i) {
+            final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
+            try {
+                listener.onDockedStackExistsChanged(exists);
+            } catch (RemoteException e) {
+                Slog.e(TAG_WM, "Error delivering docked stack exists changed event.", e);
+            }
+        }
+        mDockedStackListeners.finishBroadcast();
+    }
+
+    void registerDockedStackListener(IDockedStackListener listener) {
+        mDockedStackListeners.register(listener);
+        notifyDockedDividerVisibilityChanged(wasVisible());
+        notifyDockedStackExistsChanged(
+                mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID) != null);
+    }
+
+    void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
+        SurfaceControl.openTransaction();
+        TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(targetStackId);
+        boolean visibleAndValid = visible && stack != null;
+        if (visibleAndValid) {
+            stack.getDimBounds(mTmpRect);
+            if (mTmpRect.height() > 0 && mTmpRect.width() > 0) {
+                mDimLayer.setBounds(mTmpRect);
+                mDimLayer.show(mDisplayContent.mService.mLayersController.getResizeDimLayer(),
+                        alpha, 0 /* duration */);
+            } else {
+                visibleAndValid = false;
+            }
+        }
+        if (!visibleAndValid) {
+            mDimLayer.hide();
+        }
+        SurfaceControl.closeTransaction();
+    }
+
+    @Override
+    public boolean isFullscreen() {
+        return false;
+    }
+
+    @Override
+    public DisplayInfo getDisplayInfo() {
+        return mDisplayContent.getDisplayInfo();
+    }
+
+    @Override
+    public void getDimBounds(Rect outBounds) {
+        // This dim layer user doesn't need this.
+    }
+
+    @Override
+    public String toShortString() {
+        return TAG;
     }
 }
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index da89481..d1c0881 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -28,6 +28,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.hardware.input.InputManager;
 import android.os.IBinder;
 import android.os.Message;
 import android.os.Process;
@@ -35,8 +36,9 @@
 import android.util.Slog;
 import android.view.Display;
 import android.view.DragEvent;
-import android.view.DropPermissionHolder;
 import android.view.InputChannel;
+import android.view.InputDevice;
+import android.view.PointerIcon;
 import android.view.SurfaceControl;
 import android.view.View;
 import android.view.WindowManager;
@@ -54,6 +56,8 @@
 import com.android.server.wm.WindowManagerService.DragInputEventReceiver;
 import com.android.server.wm.WindowManagerService.H;
 
+import com.android.internal.view.IDropPermissions;
+
 import java.util.ArrayList;
 
 /**
@@ -71,6 +75,7 @@
     int mUid;
     ClipData mData;
     ClipDescription mDataDescription;
+    int mTouchSource;
     boolean mDragResult;
     float mOriginalAlpha;
     float mOriginalX, mOriginalY;
@@ -341,6 +346,7 @@
 
     private void cleanUpDragLw() {
         broadcastDragEndedLw();
+        restorePointerIconLw();
 
         // stop intercepting input
         unregister();
@@ -359,8 +365,6 @@
         mCurrentX = x;
         mCurrentY = y;
 
-        final int myPid = Process.myPid();
-
         // Move the surface to the given touch
         if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
                 TAG_WM, ">>> OPEN TRANSACTION notifyMoveLw");
@@ -375,7 +379,10 @@
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
                     TAG_WM, "<<< CLOSE TRANSACTION notifyMoveLw");
         }
+        notifyLocationLw(x, y);
+    }
 
+    void notifyLocationLw(float x, float y) {
         // Tell the affected window
         WindowState touchedWin = getTouchedWinAtPointLw(x, y);
         if (touchedWin == null) {
@@ -391,6 +398,8 @@
             }
         }
         try {
+            final int myPid = Process.myPid();
+
             // have we dragged over a new window?
             if ((touchedWin != mTargetWindow) && (mTargetWindow != null)) {
                 if (DEBUG_DRAG) {
@@ -398,7 +407,7 @@
                 }
                 // force DRAG_EXITED_EVENT if appropriate
                 DragEvent evt = obtainDragEvent(mTargetWindow, DragEvent.ACTION_DRAG_EXITED,
-                        x, y, null, null, null, null, false);
+                        0, 0, null, null, null, null, false);
                 mTargetWindow.mClient.dispatchDragEvent(evt);
                 if (myPid != mTargetWindow.mSession.mPid) {
                     evt.recycle();
@@ -428,7 +437,7 @@
     // Tell the drop target about the data.  Returns 'true' if we can immediately
     // dispatch the global drag-ended message, 'false' if we need to wait for a
     // result from the recipient.
-    boolean notifyDropLw(WindowState touchedWin, DropPermissionHolder dropPermissionHolder,
+    boolean notifyDropLw(WindowState touchedWin, IDropPermissions dropPermissions,
             float x, float y) {
         if (mAnimation != null) {
             return false;
@@ -449,7 +458,7 @@
         final int myPid = Process.myPid();
         final IBinder token = touchedWin.mClient.asBinder();
         DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DROP, x, y,
-                null, null, mData, dropPermissionHolder, false);
+                null, null, mData, dropPermissions, false);
         try {
             touchedWin.mClient.dispatchDragEvent(evt);
 
@@ -516,16 +525,28 @@
     private static DragEvent obtainDragEvent(WindowState win, int action,
             float x, float y, Object localState,
             ClipDescription description, ClipData data,
-            DropPermissionHolder dropPermissionHolder,
+            IDropPermissions dropPermissions,
             boolean result) {
+        final float winX = translateToWindowX(win, x);
+        final float winY = translateToWindowY(win, y);
+        return DragEvent.obtain(action, winX, winY, localState, description, data,
+                dropPermissions, result);
+    }
+
+    private static float translateToWindowX(WindowState win, float x) {
         float winX = x - win.mFrame.left;
-        float winY = y - win.mFrame.top;
         if (win.mEnforceSizeCompat) {
             winX *= win.mGlobalScale;
+        }
+        return winX;
+    }
+
+    private static float translateToWindowY(WindowState win, float y) {
+        float winY = y - win.mFrame.top;
+        if (win.mEnforceSizeCompat) {
             winY *= win.mGlobalScale;
         }
-        return DragEvent.obtain(action, winX, winY, localState, description, data,
-                dropPermissionHolder, result);
+        return winY;
     }
 
     boolean stepAnimationLocked(long currentTimeMs) {
@@ -572,4 +593,32 @@
         set.start();  // Will start on the first call to getTransformation.
         return set;
     }
+
+    private boolean isFromSource(int source) {
+        return (mTouchSource & source) == source;
+    }
+
+    void overridePointerIconLw(int touchSource) {
+        mTouchSource = touchSource;
+        if (isFromSource(InputDevice.SOURCE_MOUSE)) {
+            InputManager.getInstance().setPointerIconShape(PointerIcon.STYLE_GRAB);
+        }
+    }
+
+    private void restorePointerIconLw() {
+        if (isFromSource(InputDevice.SOURCE_MOUSE)) {
+            WindowState touchWin = getTouchedWinAtPointLw(mCurrentX, mCurrentY);
+            if (touchWin != null) {
+                try {
+                    touchWin.mClient.updatePointerIcon(
+                            translateToWindowX(touchWin, mCurrentX),
+                            translateToWindowY(touchWin, mCurrentY));
+                    return;
+                } catch (RemoteException e) {
+                    Slog.w(TAG_WM, "unable to restore pointer icon");
+                }
+            }
+            InputManager.getInstance().setPointerIconShape(PointerIcon.STYLE_DEFAULT);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DropPermissionsHandler.java b/services/core/java/com/android/server/wm/DropPermissionsHandler.java
new file mode 100644
index 0000000..5889fb8
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DropPermissionsHandler.java
@@ -0,0 +1,129 @@
+/*
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package com.android.server.wm;
+
+import android.app.ActivityManagerNative;
+import android.content.ClipData;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.internal.view.IDropPermissions;
+
+import java.util.ArrayList;
+
+class DropPermissionsHandler extends IDropPermissions.Stub implements IBinder.DeathRecipient {
+
+    private final int mSourceUid;
+    private final String mTargetPackage;
+    private final int mMode;
+    private final int mSourceUserId;
+    private final int mTargetUserId;
+
+    private final ArrayList<Uri> mUris = new ArrayList<Uri>();
+
+    private IBinder mActivityToken = null;
+    private IBinder mPermissionOwnerToken = null;
+
+    DropPermissionsHandler(ClipData clipData, int sourceUid, String targetPackage, int mode,
+            int sourceUserId, int targetUserId) {
+        mSourceUid = sourceUid;
+        mTargetPackage = targetPackage;
+        mMode = mode;
+        mSourceUserId = sourceUserId;
+        mTargetUserId = targetUserId;
+
+        clipData.collectUris(mUris);
+    }
+
+    @Override
+    public void take(IBinder activityToken) throws RemoteException {
+        if (mActivityToken != null || mPermissionOwnerToken != null) {
+            return;
+        }
+        mActivityToken = activityToken;
+
+        // Will throw if Activity is not found.
+        IBinder permissionOwner = ActivityManagerNative.getDefault().
+                getUriPermissionOwnerForActivity(mActivityToken);
+
+        doTake(permissionOwner);
+    }
+
+    private void doTake(IBinder permissionOwner) throws RemoteException {
+        long origId = Binder.clearCallingIdentity();
+        try {
+            for (int i = 0; i < mUris.size(); i++) {
+                ActivityManagerNative.getDefault().grantUriPermissionFromOwner(
+                        permissionOwner, mSourceUid, mTargetPackage, mUris.get(i), mMode,
+                        mSourceUserId, mTargetUserId);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public void takeTransient(IBinder permissionOwnerToken) throws RemoteException {
+        if (mActivityToken != null || mPermissionOwnerToken != null) {
+            return;
+        }
+        mPermissionOwnerToken = permissionOwnerToken;
+        mPermissionOwnerToken.linkToDeath(this, 0);
+
+        doTake(mPermissionOwnerToken);
+    }
+
+    @Override
+    public void release() throws RemoteException {
+        if (mActivityToken == null && mPermissionOwnerToken == null) {
+            return;
+        }
+
+        IBinder permissionOwner = null;
+        if (mActivityToken != null) {
+            try {
+                permissionOwner = ActivityManagerNative.getDefault().
+                        getUriPermissionOwnerForActivity(mActivityToken);
+            } catch (Exception e) {
+                // Activity is destroyed, permissions already revoked.
+                return;
+            } finally {
+                mActivityToken = null;
+            }
+        } else {
+            permissionOwner = mPermissionOwnerToken;
+            mPermissionOwnerToken.unlinkToDeath(this, 0);
+            mPermissionOwnerToken = null;
+        }
+
+        for (int i = 0; i < mUris.size(); ++i) {
+            ActivityManagerNative.getDefault().revokeUriPermissionFromOwner(
+                    permissionOwner, mUris.get(i), mMode, mSourceUserId);
+        }
+    }
+
+    @Override
+    public void binderDied() {
+        try {
+            release();
+        } catch (RemoteException e) {
+            // Cannot happen, local call.
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 1b6957d..a8d974f 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -200,18 +200,22 @@
                 deferTransactionUntilFrame, outFrame);
     }
 
+    @Override
+    public void prepareToReplaceChildren(IBinder appToken) {
+        mService.setReplacingChildren(appToken);
+    }
+
     public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
             int requestedWidth, int requestedHeight, int viewFlags,
             int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
-            Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Configuration
-                    outConfig,
-            Surface outSurface) {
+            Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
+            Configuration outConfig, Surface outSurface) {
         if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
                 + Binder.getCallingPid());
         int res = mService.relayoutWindow(this, window, seq, attrs,
                 requestedWidth, requestedHeight, viewFlags, flags,
                 outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
-                outStableInsets, outsets, outConfig, outSurface);
+                outStableInsets, outsets, outBackdropFrame, outConfig, outSurface);
         if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
                 + Binder.getCallingPid());
         return res;
@@ -279,7 +283,7 @@
     }
 
     public boolean performDrag(IWindow window, IBinder dragToken,
-            float touchX, float touchY, float thumbCenterX, float thumbCenterY,
+            int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY,
             ClipData data) {
         if (DEBUG_DRAG) {
             Slog.d(TAG_WM, "perform drag: win=" + window + " data=" + data);
@@ -332,6 +336,7 @@
 
             mService.mDragState.mData = data;
             mService.mDragState.broadcastDragStartedLw(touchX, touchY);
+            mService.mDragState.overridePointerIconLw(touchSource);
 
             // remember the thumb offsets for later
             mService.mDragState.mThumbOffsetX = thumbCenterX;
@@ -353,6 +358,8 @@
                 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
                         TAG_WM, "<<< CLOSE TRANSACTION performDrag");
             }
+
+            mService.mDragState.notifyLocationLw(touchX, touchY);
         }
 
         return true;    // success!
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 72a8343..d9667a1 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -61,6 +61,13 @@
 
     // Content limits relative to the DisplayContent this sits in.
     private Rect mBounds = new Rect();
+    final Rect mPreparedFrozenBounds = new Rect();
+
+    private Rect mPreScrollBounds = new Rect();
+    private boolean mScrollValid;
+
+    // Bounds used to calculate the insets.
+    private final Rect mTempInsetBounds = new Rect();
 
     // Device rotation as of the last time {@link #mBounds} was set.
     int mRotation;
@@ -123,12 +130,25 @@
         int yOffset = 0;
         if (dockSide != DOCKED_INVALID) {
             mStack.getBounds(mTmpRect);
-            displayContent.getLogicalDisplayRect(mTmpRect2);
 
             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;
             }
             mService.mH.obtainMessage(
@@ -153,8 +173,17 @@
         mDeferRemoval = false;
     }
 
+    private boolean hasAppTokensAlive() {
+        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
+            if (!mAppTokens.get(i).appDied) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     void removeLocked() {
-        if (!mAppTokens.isEmpty() && mStack.isAnimating()) {
+        if (hasAppTokensAlive() && mStack.isAnimating()) {
             if (DEBUG_STACK) Slog.i(TAG_WM, "removeTask: deferring removing taskId=" + mTaskId);
             mDeferRemoval = true;
             return;
@@ -197,8 +226,7 @@
     boolean removeAppToken(AppWindowToken wtoken) {
         boolean removed = mAppTokens.remove(wtoken);
         if (mAppTokens.size() == 0) {
-            EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId,
-                    "removeAppToken: last token");
+            EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeAppToken: last token");
             if (mDeferRemoval) {
                 removeLocked();
             }
@@ -246,19 +274,23 @@
             // Can't set to fullscreen if we don't have a display to get bounds from...
             return BOUNDS_CHANGE_NONE;
         }
-        if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
+        if (mPreScrollBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
             return BOUNDS_CHANGE_NONE;
         }
 
         int boundsChange = BOUNDS_CHANGE_NONE;
-        if (mBounds.left != bounds.left || mBounds.top != bounds.top) {
+        if (mPreScrollBounds.left != bounds.left || mPreScrollBounds.top != bounds.top) {
             boundsChange |= BOUNDS_CHANGE_POSITION;
         }
-        if (mBounds.width() != bounds.width() || mBounds.height() != bounds.height()) {
+        if (mPreScrollBounds.width() != bounds.width() || mPreScrollBounds.height() != bounds.height()) {
             boundsChange |= BOUNDS_CHANGE_SIZE;
         }
 
-        mBounds.set(bounds);
+
+        mPreScrollBounds.set(bounds);
+
+        resetScrollLocked();
+
         mRotation = rotation;
         if (displayContent != null) {
             displayContent.mDimLayerController.updateDimLayer(this);
@@ -267,6 +299,26 @@
         return boundsChange;
     }
 
+    /**
+     * Sets the bounds used to calculate the insets. See
+     * {@link android.app.IActivityManager#resizeDockedStack} why this is needed.
+     */
+    void setTempInsetBounds(Rect tempInsetBounds) {
+        if (tempInsetBounds != null) {
+            mTempInsetBounds.set(tempInsetBounds);
+        } else {
+            mTempInsetBounds.setEmpty();
+        }
+    }
+
+    /**
+     * Gets the bounds used to calculate the insets. See
+     * {@link android.app.IActivityManager#resizeDockedStack} why this is needed.
+     */
+    void getTempInsetBounds(Rect out) {
+        out.set(mTempInsetBounds);
+    }
+
     void setResizeable(boolean resizeable) {
         mResizeable = resizeable;
     }
@@ -285,10 +337,46 @@
         }
         if ((boundsChanged & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) {
             resizeWindows();
+        } else {
+            moveWindows();
         }
         return true;
     }
 
+    /**
+     * Prepares the task bounds to be frozen with the current size. See
+     * {@link AppWindowToken#freezeBounds}.
+     */
+    void prepareFreezingBounds() {
+        mPreparedFrozenBounds.set(mBounds);
+    }
+
+    void resetScrollLocked() {
+        if (mScrollValid) {
+            mScrollValid = false;
+            applyScrollToAllWindows(0, 0);
+        }
+        mBounds.set(mPreScrollBounds);
+    }
+
+    void applyScrollToAllWindows(final int xOffset, final int yOffset) {
+        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.mXOffset = xOffset;
+                win.mYOffset = yOffset;
+            }
+        }
+    }
+
+    void applyScrollToWindowIfNeeded(final WindowState win) {
+        if (mScrollValid) {
+            win.mXOffset = mBounds.left;
+            win.mYOffset = mBounds.top;
+        }
+    }
+
     boolean scrollLocked(Rect bounds) {
         // shift the task bound if it doesn't fully cover the stack area
         mStack.getDimBounds(mTmpRect);
@@ -310,21 +398,17 @@
             }
         }
 
-        if (bounds.equals(mBounds)) {
+        // We can stop here if we're already scrolling and the scrolled bounds not changed.
+        if (mScrollValid && bounds.equals(mBounds)) {
             return false;
         }
+
         // Normal setBounds() does not allow non-null bounds for fullscreen apps.
         // We only change bounds for the scrolling case without change it size,
         // on resizing path we should still want the validation.
         mBounds.set(bounds);
-        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.mXOffset = bounds.left;
-                win.mYOffset = bounds.top;
-            }
-        }
+        mScrollValid = true;
+        applyScrollToAllWindows(bounds.left, bounds.top);
         return true;
     }
 
@@ -341,7 +425,7 @@
     }
 
     /** Original bounds of the task if applicable, otherwise fullscreen rect. */
-    public void getBounds(Rect out) {
+    void getBounds(Rect out) {
         if (useCurrentBounds()) {
             // No need to adjust the output bounds if fullscreen or the docked stack is visible
             // since it is already what we want to represent to the rest of the system.
@@ -349,13 +433,11 @@
             return;
         }
 
-        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
-        // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
-        // system.
+        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack is
+        // not currently visible. Go ahead a represent it as fullscreen to the rest of the system.
         mStack.getDisplayContent().getLogicalDisplayRect(out);
     }
 
-
     /**
      * Calculate the maximum visible area of this task. If the task has only one app,
      * the result will be visible frame of that app. If the task has more than one apps,
@@ -440,19 +522,25 @@
             return;
         }
 
-        // Device rotation changed. We don't want the task to move around on the screen when
-        // this happens, so update the task bounds so it stays in the same place.
-        mTmpRect2.set(mBounds);
+        // Device rotation changed.
+        // - Reset the bounds to the pre-scroll bounds as whatever scrolling was done is no longer
+        // valid.
+        // - Rotate the bounds and notify activity manager if the task can be resized independently
+        // from its stack. The stack will take care of task rotation for the other case.
+        mTmpRect2.set(mPreScrollBounds);
+
+        if (!StackId.isTaskResizeAllowed(mStack.mStackId)) {
+            setBounds(mTmpRect2, mOverrideConfig);
+            return;
+        }
+
         displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
         if (setBounds(mTmpRect2, mOverrideConfig) != BOUNDS_CHANGE_NONE) {
-            // 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. Only tasks within the freeform stack
-            // are resizeable independently of their stack resizing.
-            if (mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
-                mService.mH.sendMessage(mService.mH.obtainMessage(
-                        RESIZE_TASK, mTaskId, RESIZE_MODE_SYSTEM_SCREEN_ROTATION, mBounds));
-            }
+            // 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_TASK, mTaskId,
+                    RESIZE_MODE_SYSTEM_SCREEN_ROTATION, mPreScrollBounds).sendToTarget();
         }
     }
 
@@ -463,13 +551,24 @@
             for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
                 final WindowState win = windows.get(winNdx);
                 if (!resizingWindows.contains(win)) {
-                    if (DEBUG_RESIZE) Slog.d(TAG_WM, "setBounds: Resizing " + win);
+                    if (DEBUG_RESIZE) Slog.d(TAG_WM, "resizeWindows: Resizing " + win);
                     resizingWindows.add(win);
                 }
             }
         }
     }
 
+    void moveWindows() {
+        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);
+                if (DEBUG_RESIZE) Slog.d(TAG_WM, "moveWindows: Moving " + win);
+                win.mMovedByResize = true;
+            }
+        }
+    }
+
     /**
      * Cancels any running app transitions associated with the task.
      */
@@ -506,8 +605,9 @@
     }
 
     boolean isResizeableByDockedStack() {
-        return mStack != null && getDisplayContent().getDockedStackLocked() != null &&
-                StackId.isTaskResizeableByDockedStack(mStack.mStackId);
+        final DisplayContent displayContent = getDisplayContent();
+        return displayContent != null && displayContent.getDockedStackLocked() != null
+                && mStack != null && StackId.isTaskResizeableByDockedStack(mStack.mStackId);
     }
 
     /**
@@ -518,6 +618,10 @@
         return inDockedWorkspace() || isResizeableByDockedStack();
     }
 
+    boolean isTwoFingerScrollMode() {
+        return isDockedInEffect() && !isResizeable();
+    }
+
     WindowState getTopVisibleAppMainWindow() {
         final AppWindowToken token = getTopVisibleAppToken();
         return token != null ? token.findMainWindow() : null;
@@ -560,11 +664,23 @@
         return "Task=" + mTaskId;
     }
 
-    public void printTo(String prefix, PrintWriter pw) {
-        pw.print(prefix); pw.print("taskId="); pw.println(mTaskId);
-            pw.print(prefix + prefix); pw.print("mFullscreen="); pw.println(mFullscreen);
-            pw.print(prefix + prefix); pw.print("mBounds="); pw.println(mBounds.toShortString());
-            pw.print(prefix + prefix); pw.print("mdr="); pw.println(mDeferRemoval);
-            pw.print(prefix + prefix); pw.print("appTokens="); pw.println(mAppTokens);
+    public void dump(String prefix, PrintWriter pw) {
+        final String doublePrefix = prefix + "  ";
+
+        pw.println(prefix + "taskId=" + mTaskId);
+        pw.println(doublePrefix + "mFullscreen=" + mFullscreen);
+        pw.println(doublePrefix + "mBounds=" + mBounds.toShortString());
+        pw.println(doublePrefix + "mdr=" + mDeferRemoval);
+        pw.println(doublePrefix + "appTokens=" + mAppTokens);
+        pw.println(doublePrefix + "mTempInsetBounds=" + mTempInsetBounds.toShortString());
+
+        final String triplePrefix = doublePrefix + "  ";
+
+        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
+            final AppWindowToken wtoken = mAppTokens.get(i);
+            pw.println(triplePrefix + "Activity #" + i + " " + wtoken);
+            wtoken.dump(pw, triplePrefix);
+        }
+
     }
 }
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 725bbbc..f7035c5 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -23,8 +23,6 @@
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
-import static com.android.server.wm.DimLayer.RESIZING_HINT_ALPHA;
-import static com.android.server.wm.DimLayer.RESIZING_HINT_DURATION_MS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
@@ -85,6 +83,10 @@
     private static final int CTRL_TOP    = 0x4;
     private static final int CTRL_BOTTOM = 0x8;
 
+    public static final float RESIZING_HINT_ALPHA = 0.5f;
+
+    public static final int RESIZING_HINT_DURATION_MS = 0;
+
     private final WindowManagerService mService;
     private WindowPositionerEventReceiver mInputEventReceiver;
     private Display mDisplay;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index b961879..e6fa837 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -20,12 +20,16 @@
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Debug;
+import android.os.RemoteException;
 import android.util.EventLog;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.DisplayInfo;
 import android.view.Surface;
 
+import com.android.internal.policy.DividerSnapAlgorithm;
+import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
+import com.android.internal.policy.DockedDividerUtils;
 import com.android.server.EventLogTags;
 
 import java.io.PrintWriter;
@@ -34,6 +38,7 @@
 import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.view.WindowManager.DOCKED_BOTTOM;
 import static android.view.WindowManager.DOCKED_INVALID;
 import static android.view.WindowManager.DOCKED_LEFT;
@@ -43,7 +48,8 @@
 import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
-public class TaskStack implements DimLayer.DimLayerUser {
+public class TaskStack implements DimLayer.DimLayerUser,
+        BoundsAnimationController.AnimateBoundsUser {
 
     // If the stack should be resized to fullscreen.
     private static final boolean FULLSCREEN = true;
@@ -68,6 +74,12 @@
     /** Content limits relative to the DisplayContent this sits in. */
     private Rect mBounds = new Rect();
 
+    /** Screen content area excluding IM windows, etc. */
+    private final Rect mContentBounds = new Rect();
+
+    /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */
+    private final Rect mAdjustedBounds = new Rect();
+
     /** Whether mBounds is fullscreen */
     private boolean mFullscreen = true;
 
@@ -85,6 +97,7 @@
 
     /** Detach this stack from its display when animation completes. */
     boolean mDeferDetach;
+    private boolean mUpdateBoundsAfterRotation = false;
 
     TaskStack(WindowManagerService service, int stackId) {
         mService = service;
@@ -100,12 +113,6 @@
         return mTasks;
     }
 
-    void resizeWindows() {
-        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
-            mTasks.get(taskNdx).resizeWindows();
-        }
-    }
-
     /**
      * Set the bounds of the stack and its containing tasks.
      * @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen.
@@ -114,7 +121,8 @@
      * @return True if the stack bounds was changed.
      * */
     boolean setBounds(
-            Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds) {
+            Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds,
+            SparseArray<Rect> taskTempInsetBounds) {
         if (!setBounds(stackBounds)) {
             return false;
         }
@@ -125,17 +133,20 @@
             Configuration config = configs.get(task.mTaskId);
             if (config != null) {
                 Rect bounds = taskBounds.get(task.mTaskId);
-                if (!task.isResizeable() && task.isDockedInEffect()) {
+                if (task.isTwoFingerScrollMode()) {
                     // This is a non-resizeable task that's docked (or side-by-side to the docked
                     // stack). It might have been scrolled previously, and after the stack resizing,
                     // it might no longer fully cover the stack area.
                     // Save the old bounds and re-apply the scroll. This adjusts the bounds to
                     // fit the new stack bounds.
+                    task.resizeLocked(bounds, config, false /* forced */);
                     task.getBounds(mTmpRect);
-                    task.setBounds(bounds, config);
                     task.scrollLocked(mTmpRect);
                 } else {
-                    task.setBounds(bounds, config);
+                    task.resizeLocked(bounds, config, false /* forced */);
+                    task.setTempInsetBounds(
+                            taskTempInsetBounds != null ? taskTempInsetBounds.get(task.mTaskId)
+                                    : null);
                 }
             } else {
                 Slog.wtf(TAG_WM, "No config for task: " + task + ", is there a mismatch with AM?");
@@ -144,6 +155,13 @@
         return true;
     }
 
+    void prepareFreezingTaskBounds() {
+        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+            final Task task = mTasks.get(taskNdx);
+            task.prepareFreezingBounds();
+        }
+    }
+
     boolean isFullscreenBounds(Rect bounds) {
         if (mDisplayContent == null || bounds == null) {
             return true;
@@ -152,6 +170,85 @@
         return mTmpRect.equals(bounds);
     }
 
+    void alignTasksToAdjustedBounds(final Rect adjustedBounds) {
+        if (mFullscreen) {
+            return;
+        }
+        // Update bounds of containing tasks.
+        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+            final Task task = mTasks.get(taskNdx);
+            if (task.isTwoFingerScrollMode()) {
+                // If we're scrolling we don't care about your bounds or configs,
+                // they should be null as if we were in fullscreen.
+                task.resizeLocked(null, null, false /* forced */);
+                task.getBounds(mTmpRect2);
+                task.scrollLocked(mTmpRect2);
+            } else if (task.isResizeable()) {
+                task.getBounds(mTmpRect2);
+                mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top);
+                task.resizeLocked(mTmpRect2, task.mOverrideConfig, false /* forced */);
+            }
+        }
+    }
+
+    void adjustForIME(final WindowState imeWin) {
+        final int dockedSide = getDockSide();
+        final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
+        final Rect adjustedBounds = mAdjustedBounds;
+        if (imeWin == null || !dockedTopOrBottom) {
+            // If mContentBounds is already empty, it means we're not applying
+            // any adjustments, so nothing to do; otherwise clear any adjustments.
+            if (!mContentBounds.isEmpty()) {
+                mContentBounds.setEmpty();
+                adjustedBounds.set(mBounds);
+                alignTasksToAdjustedBounds(adjustedBounds);
+            }
+            return;
+        }
+
+        final Rect displayContentRect = mTmpRect;
+        final Rect contentBounds = mTmpRect2;
+
+        // Calculate the content bounds excluding the area occupied by IME
+        mDisplayContent.getContentRect(displayContentRect);
+        contentBounds.set(displayContentRect);
+        int imeTop = Math.max(imeWin.getDisplayFrameLw().top, contentBounds.top);
+        imeTop += imeWin.getGivenContentInsetsLw().top;
+        if (contentBounds.bottom > imeTop) {
+            contentBounds.bottom = imeTop;
+        }
+
+        // If content bounds not changing, nothing to do.
+        if (mContentBounds.equals(contentBounds)) {
+            return;
+        }
+
+        // Content bounds changed, need to apply adjustments depending on dock sides.
+        mContentBounds.set(contentBounds);
+        adjustedBounds.set(mBounds);
+        final int yOffset = displayContentRect.bottom - contentBounds.bottom;
+
+        if (dockedSide == DOCKED_TOP) {
+            // If this stack is docked on top, we make it smaller so the bottom stack is not
+            // occluded by IME. We shift its bottom up by the height of the IME (capped by
+            // the display content rect). Note that we don't change the task bounds.
+            adjustedBounds.bottom = Math.max(
+                    adjustedBounds.bottom - yOffset, displayContentRect.top);
+        } else {
+            // If this stack is docked on bottom, we shift it up so that it's not occluded by
+            // IME. We try to move it up by the height of the IME window (although the best
+            // we could do is to make the top stack fully collapsed).
+            final int dividerWidth = mDisplayContent.mDividerControllerLocked.getContentWidth();
+            adjustedBounds.top = Math.max(
+                    adjustedBounds.top - yOffset, displayContentRect.top + dividerWidth);
+            adjustedBounds.bottom = adjustedBounds.top + mBounds.height();
+
+            // We also move the member tasks together, taking care not to resize them.
+            // Resizing might cause relaunch, and IME window may not come back after that.
+            alignTasksToAdjustedBounds(adjustedBounds);
+        }
+    }
+
     private boolean setBounds(Rect bounds) {
         boolean oldFullscreen = mFullscreen;
         int rotation = Surface.ROTATION_0;
@@ -181,6 +278,16 @@
 
         mBounds.set(bounds);
         mRotation = rotation;
+
+        // Clear the adjusted content bounds as they're no longer valid.
+        // If IME is still visible, these will be re-applied.
+        // Note that we don't clear mContentBounds here, so that we know the last IME
+        // adjust we applied.
+        // If user starts dragging the dock divider while IME is visible, the new bounds
+        // we received are based on the actual screen location of the divider. It already
+        // accounted for the IME window, so we don't want to adjust again.
+        mAdjustedBounds.set(mBounds);
+
         return true;
     }
 
@@ -205,9 +312,14 @@
 
     public void getBounds(Rect out) {
         if (useCurrentBounds()) {
-            // No need to adjust the output bounds if fullscreen or the docked stack is visible
+            // If we're currently adjusting for IME, we use the adjusted bounds; otherwise,
+            // no need to adjust the output bounds if fullscreen or the docked stack is visible
             // since it is already what we want to represent to the rest of the system.
-            out.set(mBounds);
+            if (!mContentBounds.isEmpty()) {
+                out.set(mAdjustedBounds);
+            } else {
+                out.set(mBounds);
+            }
             return;
         }
 
@@ -224,6 +336,7 @@
     }
 
     void updateDisplayInfo(Rect bounds) {
+        mUpdateBoundsAfterRotation = false;
         if (mDisplayContent != null) {
             for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
                 mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent);
@@ -233,20 +346,71 @@
             } else if (mFullscreen) {
                 setBounds(null);
             } else {
+                mUpdateBoundsAfterRotation = true;
                 mTmpRect2.set(mBounds);
-                mDisplayContent.rotateBounds(
-                        mRotation, mDisplayContent.getDisplayInfo().rotation, mTmpRect2);
-                if (setBounds(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.sendMessage(mService.mH.obtainMessage(
-                            RESIZE_STACK, mStackId, 0 /*allowResizeInDockedMode*/, mBounds));
+                final int newRotation = mDisplayContent.getDisplayInfo().rotation;
+                if (mRotation == newRotation) {
+                    setBounds(mTmpRect2);
                 }
+
+                // If the rotation changes, we'll handle it in updateBoundsAfterRotation
             }
         }
     }
 
+    /**
+     * Updates the bounds after rotating the screen. We can't handle it in
+     * {@link #updateDisplayInfo} because at that point the configuration might not be fully updated
+     * yet.
+     */
+    void updateBoundsAfterRotation() {
+        if (!mUpdateBoundsAfterRotation) {
+            return;
+        }
+        mUpdateBoundsAfterRotation = false;
+        final int newRotation = getDisplayInfo().rotation;
+        mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
+        if (mStackId == DOCKED_STACK_ID) {
+            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.sendMessage(mService.mH.obtainMessage(
+                RESIZE_STACK, mStackId, 0 /*allowResizeInDockedMode*/, mTmpRect2));
+    }
+
+    /**
+     * Snaps the bounds after rotation to the closest snap target for the docked stack.
+     */
+    private void snapDockedStackAfterRotation(Rect outBounds) {
+
+        // Calculate the current position.
+        final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
+        final int dividerSize = mService.getDefaultDisplayContentLocked()
+                .getDockedDividerController().getContentWidth();
+        final int dockSide = getDockSide(outBounds);
+        final int dividerPosition = DockedDividerUtils.calculatePositionForBounds(outBounds,
+                dockSide, dividerSize);
+        final int displayWidth = mDisplayContent.getDisplayInfo().logicalWidth;
+        final int displayHeight = mDisplayContent.getDisplayInfo().logicalHeight;
+
+        // Snap the position to a target.
+        final int rotation = displayInfo.rotation;
+        final int orientation = mService.mCurConfiguration.orientation;
+        mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight, outBounds);
+        final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
+                mService.mContext.getResources(), displayWidth, displayHeight,
+                dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds);
+        final SnapTarget target = algorithm.calculateNonDismissingSnapTarget(dividerPosition);
+
+        // Recalculate the bounds based on the position of the target.
+        DockedDividerUtils.calculateBoundsForPosition(target.position, dockSide,
+                outBounds, displayInfo.logicalWidth, displayInfo.logicalHeight,
+                dividerSize);
+    }
+
     boolean isAnimating() {
         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
             final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
@@ -297,6 +461,10 @@
                 "positionTask: task=" + task + " position=" + position);
         mTasks.add(position, task);
 
+        // If we are moving the task across stacks, the scroll is no longer valid.
+        if (task.mStack != this) {
+            task.resetScrollLocked();
+        }
         task.mStack = this;
         task.updateDisplayInfo(mDisplayContent);
         boolean toTop = position == mTasks.size() - 1;
@@ -418,7 +586,7 @@
         }
     }
 
-    void getStackDockedModeBoundsLocked(Rect outBounds) {
+    void getStackDockedModeBoundsLocked(Rect outBounds, boolean ignoreVisibilityOnKeyguardShowing) {
         if (!StackId.isResizeableByDockedStack(mStackId) || mDisplayContent == null) {
             outBounds.set(mBounds);
             return;
@@ -430,11 +598,11 @@
             throw new IllegalStateException(
                     "Calling getStackDockedModeBoundsLocked() when there is no docked stack.");
         }
-        if (!dockedStack.isVisibleLocked()) {
+        if (!dockedStack.isVisibleLocked(ignoreVisibilityOnKeyguardShowing)) {
             // The docked stack is being dismissed, but we caught before it finished being
             // dismissed. In that case we want to treat it as if it is not occupying any space and
             // let others occupy the whole display.
-            mDisplayContent.getLogicalDisplayRect(mTmpRect);
+            mDisplayContent.getLogicalDisplayRect(outBounds);
             return;
         }
 
@@ -477,20 +645,31 @@
                 outBounds.set(mService.mDockedStackCreateBounds);
                 return;
             }
-            // The initial bounds of the docked stack when it is created half the screen space and
-            // its bounds can be adjusted after that. The bounds of all other stacks are adjusted
-            // to occupy whatever screen space the docked stack isn't occupying.
+
+            // The initial bounds of the docked stack when it is created about half the screen space
+            // and its bounds can be adjusted after that. The bounds of all other stacks are
+            // adjusted to occupy whatever screen space the docked stack isn't occupying.
+            final DisplayInfo di = mDisplayContent.getDisplayInfo();
+            mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
+                    mTmpRect2);
+            final int position = new DividerSnapAlgorithm(mService.mContext.getResources(),
+                    di.logicalWidth,
+                    di.logicalHeight,
+                    dockDividerWidth,
+                    mService.mCurConfiguration.orientation == ORIENTATION_PORTRAIT,
+                    mTmpRect2).getMiddleTarget().position;
+
             if (dockOnTopOrLeft) {
                 if (splitHorizontally) {
-                    outBounds.right = displayRect.centerX() - dockDividerWidth / 2;
+                    outBounds.right = position;
                 } else {
-                    outBounds.bottom = displayRect.centerY() - dockDividerWidth / 2;
+                    outBounds.bottom = position;
                 }
             } else {
                 if (splitHorizontally) {
-                    outBounds.left = displayRect.centerX() + dockDividerWidth / 2;
+                    outBounds.left = position - dockDividerWidth;
                 } else {
-                    outBounds.top = displayRect.centerY() + dockDividerWidth / 2;
+                    outBounds.top = position - dockDividerWidth;
                 }
             }
             return;
@@ -510,6 +689,7 @@
                 outBounds.top = dockedBounds.bottom + dockDividerWidth;
             }
         }
+        DockedDividerUtils.sanitizeStackBounds(outBounds);
     }
 
     /** Resizes all non-docked stacks in the system to either fullscreen or the appropriate size
@@ -608,16 +788,15 @@
     }
 
     public void dump(String prefix, PrintWriter pw) {
-        pw.print(prefix); pw.print("mStackId="); pw.println(mStackId);
-        pw.print(prefix); pw.print("mDeferDetach="); pw.println(mDeferDetach);
-        pw.print(prefix); pw.print("mFullscreen="); pw.println(mFullscreen);
-        pw.print(prefix); pw.print("mBounds="); pw.println(mBounds.toShortString());
-        for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) {
-            pw.print(prefix);
-            mTasks.get(taskNdx).printTo(prefix + " ", pw);
+        pw.println(prefix + "mStackId=" + mStackId);
+        pw.println(prefix + "mDeferDetach=" + mDeferDetach);
+        pw.println(prefix + "mFullscreen=" + mFullscreen);
+        pw.println(prefix + "mBounds=" + mBounds.toShortString());
+        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; taskNdx--) {
+            mTasks.get(taskNdx).dump(prefix + "  ", pw);
         }
         if (mAnimationBackgroundSurface.isDimming()) {
-            pw.print(prefix); pw.println("mWindowAnimationBackgroundSurface:");
+            pw.println(prefix + "mWindowAnimationBackgroundSurface:");
             mAnimationBackgroundSurface.printTo(prefix + "  ", pw);
         }
         if (!mExitingAppTokens.isEmpty()) {
@@ -672,6 +851,10 @@
      * information which side of the screen was the dock anchored.
      */
     int getDockSide() {
+        return getDockSide(mBounds);
+    }
+
+    int getDockSide(Rect bounds) {
         if (mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId)) {
             return DOCKED_INVALID;
         }
@@ -682,14 +865,14 @@
         final int orientation = mService.mCurConfiguration.orientation;
         if (orientation == Configuration.ORIENTATION_PORTRAIT) {
             // Portrait mode, docked either at the top or the bottom.
-            if (mBounds.top - mTmpRect.top < mTmpRect.bottom - mBounds.bottom) {
+            if (bounds.top - mTmpRect.top < mTmpRect.bottom - bounds.bottom) {
                 return DOCKED_TOP;
             } else {
                 return DOCKED_BOTTOM;
             }
         } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
             // Landscape mode, docked either on the left or on the right.
-            if (mBounds.left - mTmpRect.left < mTmpRect.right - mBounds.right) {
+            if (bounds.left - mTmpRect.left < mTmpRect.right - bounds.right) {
                 return DOCKED_LEFT;
             } else {
                 return DOCKED_RIGHT;
@@ -700,10 +883,19 @@
     }
 
     boolean isVisibleLocked() {
+        return isVisibleLocked(false);
+    }
+
+    boolean isVisibleLocked(boolean ignoreVisibilityOnKeyguardShowing) {
         final boolean keyguardOn = mService.mPolicy.isKeyguardShowingOrOccluded();
         if (keyguardOn && !StackId.isAllowedOverLockscreen(mStackId)) {
-            return false;
+            // The keyguard is showing and the stack shouldn't show on top of the keyguard.
+            // We return false for visibility except in cases where the caller wants us to return
+            // true for visibility when the keyguard is showing. One example, is if the docked
+            // is being resized due to orientation while the keyguard is on.
+            return ignoreVisibilityOnKeyguardShowing;
         }
+
         for (int i = mTasks.size() - 1; i >= 0; i--) {
             Task task = mTasks.get(i);
             for (int j = task.mAppTokens.size() - 1; j >= 0; j--) {
@@ -714,4 +906,32 @@
         }
         return false;
     }
+
+    @Override  // AnimatesBounds
+    public boolean setSize(Rect bounds) {
+        synchronized (mService.mWindowMap) {
+            if (mDisplayContent == null) {
+                return false;
+            }
+        }
+        try {
+            mService.mActivityManager.resizeStack(mStackId, bounds, false, true, false);
+        } catch (RemoteException e) {
+        }
+        return true;
+    }
+
+    @Override  // AnimatesBounds
+    public void finishBoundsAnimation() {
+        synchronized (mService.mWindowMap) {
+            if (mTasks.isEmpty()) {
+                return;
+            }
+            final Task task = mTasks.get(mTasks.size() - 1);
+            if (task != null) {
+                task.setDragResizing(false);
+                mService.requestTraversal();
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
index af109d4..3dc512f 100644
--- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
@@ -20,6 +20,7 @@
 import android.graphics.Region;
 import android.view.DisplayInfo;
 import android.view.GestureDetector;
+import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.WindowManagerPolicy.PointerEventListener;
 
@@ -33,13 +34,7 @@
 import static android.view.PointerIcon.STYLE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW;
 
 public class TaskTapPointerEventListener implements PointerEventListener {
-    private static final int TAP_TIMEOUT_MSEC = 300;
-    private static final float TAP_MOTION_SLOP_INCHES = 0.125f;
 
-    private final int mMotionSlop;
-    private float mDownX;
-    private float mDownY;
-    private int mPointerId;
     final private Region mTouchExcludeRegion = new Region();
     private final WindowManagerService mService;
     private final DisplayContent mDisplayContent;
@@ -54,8 +49,6 @@
             DisplayContent displayContent) {
         mService = service;
         mDisplayContent = displayContent;
-        DisplayInfo info = displayContent.getDisplayInfo();
-        mMotionSlop = (int)(info.logicalDensityDpi * TAP_MOTION_SLOP_INCHES);
     }
 
     // initialize the object, note this must be done outside WindowManagerService
@@ -73,31 +66,19 @@
         final int action = motionEvent.getAction();
         switch (action & MotionEvent.ACTION_MASK) {
             case MotionEvent.ACTION_DOWN: {
-                mPointerId = motionEvent.getPointerId(0);
-                mDownX = motionEvent.getX();
-                mDownY = motionEvent.getY();
+                final int x = (int) motionEvent.getX();
+                final int y = (int) motionEvent.getY();
 
-                final int x = (int) mDownX;
-                final int y = (int) mDownY;
                 synchronized (this) {
                     if (!mTouchExcludeRegion.contains(x, y)) {
-                        mService.mH.obtainMessage(H.TAP_DOWN_OUTSIDE_TASK, x, y,
-                                mDisplayContent).sendToTarget();
+                        mService.mH.obtainMessage(H.TAP_OUTSIDE_TASK,
+                                x, y, mDisplayContent).sendToTarget();
                     }
                 }
                 break;
             }
 
             case MotionEvent.ACTION_MOVE: {
-                if (mPointerId >= 0) {
-                    int index = motionEvent.findPointerIndex(mPointerId);
-                    if ((motionEvent.getEventTime() - motionEvent.getDownTime()) > TAP_TIMEOUT_MSEC
-                            || index < 0
-                            || Math.abs(motionEvent.getX(index) - mDownX) > mMotionSlop
-                            || Math.abs(motionEvent.getY(index) - mDownY) > mMotionSlop) {
-                        mPointerId = -1;
-                    }
-                }
                 if (motionEvent.getPointerCount() != 2) {
                     stopTwoFingerScroll();
                 }
@@ -108,7 +89,8 @@
                 final int x = (int) motionEvent.getX();
                 final int y = (int) motionEvent.getY();
                 final Task task = mDisplayContent.findTaskForControlPoint(x, y);
-                if (task == null) {
+                InputDevice inputDevice = motionEvent.getDevice();
+                if (task == null || inputDevice == null) {
                     mPointerIconShape = STYLE_NOT_SPECIFIED;
                     break;
                 }
@@ -130,7 +112,7 @@
                     }
                     if (mPointerIconShape != iconShape) {
                         mPointerIconShape = iconShape;
-                        motionEvent.getDevice().setPointerShape(iconShape);
+                        inputDevice.setPointerShape(iconShape);
                     }
                 } else {
                     mPointerIconShape = STYLE_NOT_SPECIFIED;
@@ -139,29 +121,14 @@
 
             case MotionEvent.ACTION_HOVER_EXIT:
                 mPointerIconShape = STYLE_NOT_SPECIFIED;
-                motionEvent.getDevice().setPointerShape(STYLE_DEFAULT);
+                InputDevice inputDevice = motionEvent.getDevice();
+                if (inputDevice != null) {
+                    inputDevice.setPointerShape(STYLE_DEFAULT);
+                }
                 break;
 
             case MotionEvent.ACTION_UP:
             case MotionEvent.ACTION_POINTER_UP: {
-                int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK)
-                        >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
-                // Extract the index of the pointer that left the touch sensor
-                if (mPointerId == motionEvent.getPointerId(index)) {
-                    final int x = (int)motionEvent.getX(index);
-                    final int y = (int)motionEvent.getY(index);
-                    synchronized(this) {
-                        if ((motionEvent.getEventTime() - motionEvent.getDownTime())
-                                < TAP_TIMEOUT_MSEC
-                                && Math.abs(x - mDownX) < mMotionSlop
-                                && Math.abs(y - mDownY) < mMotionSlop
-                                && !mTouchExcludeRegion.contains(x, y)) {
-                            mService.mH.obtainMessage(H.TAP_OUTSIDE_TASK, x, y,
-                                    mDisplayContent).sendToTarget();
-                        }
-                    }
-                    mPointerId = -1;
-                }
                 stopTwoFingerScroll();
                 break;
             }
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 6a5183f..722c3b4 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -281,8 +281,7 @@
             final int flags = win.mAttrs.flags;
             boolean canBeForceHidden = mPolicy.canBeForceHidden(win, win.mAttrs);
             boolean shouldBeForceHidden = shouldForceHide(win);
-            if (winAnimator.mSurfaceController != null
-                    && winAnimator.mSurfaceController.hasSurface()) {
+            if (winAnimator.hasSurface()) {
                 final boolean wasAnimating = winAnimator.mWasAnimating;
                 final boolean nowAnimating = winAnimator.stepAnimationLocked(mCurrentTime);
                 winAnimator.mWasAnimating = nowAnimating;
@@ -782,7 +781,7 @@
         SurfaceControl.openTransaction();
         try {
             for (int i = mService.mDisplayContents.size() - 1; i >= 0; i--) {
-                DisplayContent display = mService.mDisplayContents.get(i);
+                DisplayContent display = mService.mDisplayContents.valueAt(i);
                 final WindowList windows = mService.getWindowListLocked(display.getDisplayId());
                 for (int j = windows.size() - 1; j >= 0; j--) {
                     windows.get(j).maybeRemoveReplacedWindow();
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
new file mode 100644
index 0000000..2cf2618
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 android.app.ActivityManager.StackId;
+import android.util.Slog;
+import android.view.Display;
+
+import java.io.PrintWriter;
+
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.WINDOW_LAYER_MULTIPLIER;
+
+/**
+ * Controller for assigning layers to windows on the display.
+ *
+ * This class encapsulates general algorithm for assigning layers and special rules that we need to
+ * apply on top. The general algorithm goes through windows from bottom to the top and the higher
+ * the window is, the higher layer is assigned. The final layer is equal to base layer +
+ * adjustment from the order. This means that the window list is assumed to be ordered roughly by
+ * the base layer (there are exceptions, e.g. due to keyguard and wallpaper and they need to be
+ * handled with care, because they break the algorithm).
+ *
+ * On top of the general algorithm we add special rules, that govern such amazing things as:
+ * <li>IME (which has higher base layer, but will be positioned above application windows)</li>
+ * <li>docked/pinned windows (that need to be lifted above other application windows, including
+ * animations)
+ * <li>dock divider (which needs to live above applications, but below IME)</li>
+ * <li>replaced windows, which need to live above their normal level, because they anticipate
+ * an animation</li>.
+ */
+public class WindowLayersController {
+    private final WindowManagerService mService;
+
+    private int mInputMethodAnimLayerAdjustment;
+
+    public WindowLayersController(WindowManagerService service) {
+        mService = service;
+    }
+
+    private int mHighestApplicationLayer = 0;
+    private WindowState mPinnedWindow = null;
+    private WindowState mDockedWindow = null;
+    private WindowState mDockDivider = null;
+    private WindowState mReplacingWindow = null;
+
+    final void assignLayersLocked(WindowList windows) {
+        if (DEBUG_LAYERS) Slog.v(TAG_WM, "Assigning layers based on windows=" + windows,
+                new RuntimeException("here").fillInStackTrace());
+
+        clear();
+        int curBaseLayer = 0;
+        int curLayer = 0;
+        boolean anyLayerChanged = false;
+        for (int i = 0, windowCount = windows.size(); i < windowCount; i++) {
+            final WindowState w = windows.get(i);
+            boolean layerChanged = false;
+
+            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;
+            }
+
+            final WindowStateAnimator winAnimator = w.mWinAnimator;
+            oldLayer = winAnimator.mAnimLayer;
+            winAnimator.mAnimLayer = w.mLayer + w.getAnimLayerAdjustment() +
+                    getSpecialWindowAnimLayerAdjustment(w);
+            if (winAnimator.mAnimLayer != oldLayer) {
+                layerChanged = true;
+                anyLayerChanged = true;
+            }
+
+            if (w.mAppToken != null) {
+                mHighestApplicationLayer = Math.max(mHighestApplicationLayer,
+                        winAnimator.mAnimLayer);
+            }
+            collectSpecialWindows(w);
+
+            if (layerChanged) {
+                w.scheduleAnimationIfDimming();
+            }
+        }
+
+        adjustSpecialWindows();
+
+        //TODO (multidisplay): Magnification is supported only for the default display.
+        if (mService.mAccessibilityController != null && anyLayerChanged
+                && windows.get(windows.size() - 1).getDisplayId() == Display.DEFAULT_DISPLAY) {
+            mService.mAccessibilityController.onWindowLayersChangedLocked();
+        }
+
+        if (DEBUG_LAYERS) logDebugLayers(windows);
+    }
+
+    void setInputMethodAnimLayerAdjustment(int adj) {
+        if (DEBUG_LAYERS) Slog.v(TAG_WM, "Setting im layer adj to " + adj);
+        mInputMethodAnimLayerAdjustment = adj;
+        final WindowState imw = mService.mInputMethodWindow;
+        if (imw != null) {
+            imw.mWinAnimator.mAnimLayer = imw.mLayer + adj;
+            if (DEBUG_LAYERS) Slog.v(TAG_WM, "IM win " + imw
+                    + " anim layer: " + imw.mWinAnimator.mAnimLayer);
+            for (int i = imw.mChildWindows.size() - 1; i >= 0; i--) {
+                final WindowState childWindow = imw.mChildWindows.get(i);
+                childWindow.mWinAnimator.mAnimLayer = childWindow.mLayer + adj;
+                if (DEBUG_LAYERS) Slog.v(TAG_WM, "IM win " + childWindow
+                        + " anim layer: " + childWindow.mWinAnimator.mAnimLayer);
+            }
+        }
+        for (int i = mService.mInputMethodDialogs.size() - 1; i >= 0; i--) {
+            final WindowState dialog = mService.mInputMethodDialogs.get(i);
+            dialog.mWinAnimator.mAnimLayer = dialog.mLayer + adj;
+            if (DEBUG_LAYERS) Slog.v(TAG_WM, "IM win " + imw
+                    + " anim layer: " + dialog.mWinAnimator.mAnimLayer);
+        }
+    }
+
+    int getSpecialWindowAnimLayerAdjustment(WindowState win) {
+        if (win.mIsImWindow) {
+            return mInputMethodAnimLayerAdjustment;
+        } else if (win.mIsWallpaper) {
+            return mService.mWallpaperControllerLocked.getAnimLayerAdjustment();
+        }
+        return 0;
+    }
+
+    /**
+     * @return The layer used for dimming the apps when dismissing docked/fullscreen stack. Just
+     *         above all application surfaces.
+     */
+    int getResizeDimLayer() {
+        return mDockDivider.mLayer - 1;
+    }
+
+    private void logDebugLayers(WindowList windows) {
+        for (int i = 0, n = windows.size(); i < n; i++) {
+            final WindowState w = windows.get(i);
+            final WindowStateAnimator winAnimator = w.mWinAnimator;
+            Slog.v(TAG_WM, "Assign layer " + w + ": " + "mBase=" + w.mBaseLayer
+                    + " mLayer=" + w.mLayer + (w.mAppToken == null
+                    ? "" : " mAppLayer=" + w.mAppToken.mAppAnimator.animLayerAdjustment)
+                    + " =mAnimLayer=" + winAnimator.mAnimLayer);
+        }
+    }
+
+    private void clear() {
+        mHighestApplicationLayer = 0;
+        mPinnedWindow = null;
+        mDockedWindow = null;
+        mDockDivider = null;
+    }
+
+    private void collectSpecialWindows(WindowState w) {
+        if (w.mAttrs.type == TYPE_DOCK_DIVIDER) {
+            mDockDivider = w;
+        } else {
+            final TaskStack stack = w.getStack();
+            if (stack == null) {
+                return;
+            }
+            if (stack.mStackId == StackId.PINNED_STACK_ID) {
+                mPinnedWindow = w;
+            } else if (stack.mStackId == StackId.DOCKED_STACK_ID) {
+                mDockedWindow = w;
+            }
+        }
+    }
+
+    private void adjustSpecialWindows() {
+        int layer = mHighestApplicationLayer + 1;
+        // For pinned and docked stack window, we want to make them above other windows
+        // also when these windows are animating.
+        layer = assignAndIncreaseLayerIfNeeded(mDockedWindow, 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);
+        // 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.
+        layer = assignAndIncreaseLayerIfNeeded(mReplacingWindow, layer);
+        layer = assignAndIncreaseLayerIfNeeded(mPinnedWindow, layer);
+    }
+
+    private int assignAndIncreaseLayerIfNeeded(WindowState win, int layer) {
+        if (win != null) {
+            win.mLayer = layer;
+            win.mWinAnimator.mAnimLayer = layer;
+            layer++;
+        }
+        return layer;
+    }
+
+    void dump(PrintWriter pw, String s) {
+        if (mInputMethodAnimLayerAdjustment != 0 ||
+                mService.mWallpaperControllerLocked.getAnimLayerAdjustment() != 0) {
+            pw.print("  mInputMethodAnimLayerAdjustment=");
+            pw.print(mInputMethodAnimLayerAdjustment);
+            pw.print("  mWallpaperAnimLayerAdjustment=");
+            pw.println(mService.mWallpaperControllerLocked.getAnimLayerAdjustment());
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
index 845100d..66aa863 100644
--- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
@@ -35,10 +35,10 @@
 
     static final boolean DEBUG_RESIZE = false;
     static final boolean DEBUG = false;
-    static final boolean DEBUG_ADD_REMOVE = false;
-    static final boolean DEBUG_FOCUS = true;
+    static final boolean DEBUG_ADD_REMOVE = true;
+    static final boolean DEBUG_FOCUS = false;
     static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || false;
-    static final boolean DEBUG_ANIM = false;
+    static final boolean DEBUG_ANIM = true;
     static final boolean DEBUG_KEYGUARD = false;
     static final boolean DEBUG_LAYOUT = false;
     static final boolean DEBUG_LAYERS = false;
@@ -50,7 +50,7 @@
     static final boolean DEBUG_ORIENTATION = false;
     static final boolean DEBUG_APP_ORIENTATION = false;
     static final boolean DEBUG_CONFIGURATION = false;
-    static final boolean DEBUG_APP_TRANSITIONS = false;
+    static final boolean DEBUG_APP_TRANSITIONS = true;
     static final boolean DEBUG_STARTING_WINDOW = false;
     static final boolean DEBUG_WALLPAPER = false;
     static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
@@ -58,7 +58,7 @@
     static final boolean DEBUG_SCREEN_ON = false;
     static final boolean DEBUG_SCREENSHOT = false;
     static final boolean DEBUG_BOOT = false;
-    static final boolean DEBUG_LAYOUT_REPEATS = true;
+    static final boolean DEBUG_LAYOUT_REPEATS = false;
     static final boolean DEBUG_SURFACE_TRACE = false;
     static final boolean DEBUG_WINDOW_TRACE = false;
     static final boolean DEBUG_TASK_MOVEMENT = false;
@@ -71,6 +71,6 @@
     static final boolean SHOW_TRANSACTIONS = false;
     static final boolean SHOW_VERBOSE_TRANSACTIONS = false && SHOW_TRANSACTIONS;
     static final boolean SHOW_LIGHT_TRANSACTIONS = false || SHOW_TRANSACTIONS;
-    static final boolean HIDE_STACK_CRAWLS = true;
+    static final boolean SHOW_STACK_CRAWLS = false;
     static final boolean DEBUG_WINDOW_CROP = false;
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 456c416..e0e44dc 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -16,83 +16,10 @@
 
 package com.android.server.wm;
 
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.StatusBarManager.DISABLE_MASK;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.view.WindowManager.DOCKED_INVALID;
-import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
-import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
-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_NAVIGATION_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
-import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
-import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
-import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-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.WindowManagerDebugConfig.DEBUG;
-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_ORIENTATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEYGUARD;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
-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_MOVEMENT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
-import static com.android.server.wm.WindowManagerDebugConfig.HIDE_STACK_CRAWLS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_VERBOSE_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-
 import android.Manifest;
 import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.ActivityManager.StackId;
 import android.app.ActivityManagerNative;
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
@@ -153,11 +80,10 @@
 import android.view.Choreographer;
 import android.view.Display;
 import android.view.DisplayInfo;
-import android.view.DropPermissionHolder;
 import android.view.Gravity;
 import android.view.IAppTransitionAnimationSpecsFuture;
 import android.view.IApplicationToken;
-import android.view.IDockDividerVisibilityListener;
+import android.view.IDockedStackListener;
 import android.view.IInputFilter;
 import android.view.IOnKeyguardExitResult;
 import android.view.IRotationWatcher;
@@ -191,6 +117,7 @@
 
 import com.android.internal.R;
 import com.android.internal.app.IAssistScreenshotReceiver;
+import com.android.internal.os.IResultReceiver;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
@@ -227,9 +154,85 @@
 import java.util.Iterator;
 import java.util.List;
 
+import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+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.PINNED_STACK_ID;
+import static android.app.StatusBarManager.DISABLE_MASK;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
+import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
+import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
+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_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
+import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
+import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+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.WindowManagerDebugConfig.DEBUG;
+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_ORIENTATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEYGUARD;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
+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_MOVEMENT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
+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;
+
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
         implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowManagerService" : TAG_WM;
+
     static final int LAYOUT_REPEAT_THRESHOLD = 4;
 
     static final boolean PROFILE_ORIENTATION = false;
@@ -567,7 +570,6 @@
 
     /** If true hold off on modifying the animation layer of mInputMethodTarget */
     boolean mInputMethodTargetWaitingAnim;
-    int mInputMethodAnimLayerAdjustment;
 
     WindowState mInputMethodWindow = null;
     final ArrayList<WindowState> mInputMethodDialogs = new ArrayList<>();
@@ -577,31 +579,23 @@
     final ArrayList<WindowState> mTmpWindows = new ArrayList<>();
 
     boolean mHardKeyboardAvailable;
-    boolean mShowImeWithHardKeyboard;
     WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
     SettingsObserver mSettingsObserver;
 
     private final class SettingsObserver extends ContentObserver {
-        private final Uri mShowImeWithHardKeyboardUri =
-                Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
-
         private final Uri mDisplayInversionEnabledUri =
                 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
 
         public SettingsObserver() {
             super(new Handler());
             ContentResolver resolver = mContext.getContentResolver();
-            resolver.registerContentObserver(mShowImeWithHardKeyboardUri, false, this,
-                    UserHandle.USER_ALL);
             resolver.registerContentObserver(mDisplayInversionEnabledUri, false, this,
                     UserHandle.USER_ALL);
         }
 
         @Override
         public void onChange(boolean selfChange, Uri uri) {
-            if (mShowImeWithHardKeyboardUri.equals(uri)) {
-                updateShowImeWithHardKeyboard();
-            } else if (mDisplayInversionEnabledUri.equals(uri)) {
+            if (mDisplayInversionEnabledUri.equals(uri)) {
                 updateCircularDisplayMaskIfNeeded();
             }
         }
@@ -609,6 +603,8 @@
 
     WallpaperController mWallpaperControllerLocked;
 
+    final WindowLayersController mLayersController;
+
     boolean mAnimateWallpaperWithTarget;
 
     AppWindowToken mFocusedApp = null;
@@ -649,6 +645,9 @@
 
     final WindowAnimator mAnimator;
 
+    private final BoundsAnimationController mBoundsAnimationController =
+            new BoundsAnimationController();
+
     SparseArray<Task> mTaskIdToTask = new SparseArray<>();
 
     /** All of the TaskStacks in the window manager, unordered. For an ordered list call
@@ -758,13 +757,12 @@
     private boolean completeDropLw(float x, float y) {
         WindowState dropTargetWin = mDragState.getDropTargetWinLw(x, y);
 
-        DropPermissionHolder dropPermissionHolder = null;
+        DropPermissionsHandler dropPermissions = null;
         if (dropTargetWin != null &&
                 (mDragState.mFlags & View.DRAG_FLAG_GLOBAL) != 0 &&
                 (mDragState.mFlags & DRAG_FLAGS_URI_ACCESS) != 0) {
-            dropPermissionHolder = new DropPermissionHolder(
+            dropPermissions = new DropPermissionsHandler(
                     mDragState.mData,
-                    mActivityManager,
                     mDragState.mUid,
                     dropTargetWin.getOwningPackage(),
                     mDragState.mFlags & DRAG_FLAGS_URI_PERMISSIONS,
@@ -772,7 +770,7 @@
                     UserHandle.getUserId(dropTargetWin.getOwningUid()));
         }
 
-        return mDragState.notifyDropLw(dropTargetWin, dropPermissionHolder, x, y);
+        return mDragState.notifyDropLw(dropTargetWin, dropPermissions, x, y);
     }
 
     /**
@@ -882,6 +880,7 @@
 
         mWallpaperControllerLocked = new WallpaperController(this);
         mWindowPlacerLocked = new WindowSurfacePlacer(this);
+        mLayersController = new WindowLayersController(this);
 
         LocalServices.addService(WindowManagerPolicy.class, mPolicy);
 
@@ -943,7 +942,6 @@
         mContext.registerReceiver(mBroadcastReceiver, filter);
 
         mSettingsObserver = new SettingsObserver();
-        updateShowImeWithHardKeyboard();
 
         mHoldingScreenWakeLock = mPowerManager.newWakeLock(
                 PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, TAG_WM);
@@ -1507,22 +1505,23 @@
         if (w != null) {
             if (willMove) {
                 if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Moving IM target from " + curTarget + " to "
-                        + w + (HIDE_STACK_CRAWLS ? "" : " Callers=" + Debug.getCallers(4)));
+                        + w + (SHOW_STACK_CRAWLS ? " Callers=" + Debug.getCallers(4) : ""));
                 mInputMethodTarget = w;
                 mInputMethodTargetWaitingAnim = false;
                 if (w.mAppToken != null) {
-                    setInputMethodAnimLayerAdjustment(w.mAppToken.mAppAnimator.animLayerAdjustment);
+                    mLayersController.setInputMethodAnimLayerAdjustment(
+                            w.mAppToken.mAppAnimator.animLayerAdjustment);
                 } else {
-                    setInputMethodAnimLayerAdjustment(0);
+                    mLayersController.setInputMethodAnimLayerAdjustment(0);
                 }
             }
             return i+1;
         }
         if (willMove) {
             if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Moving IM target from " + curTarget + " to null."
-                    + (HIDE_STACK_CRAWLS ? "" : " Callers=" + Debug.getCallers(4)));
+                    + (SHOW_STACK_CRAWLS ? " Callers=" + Debug.getCallers(4) : ""));
             mInputMethodTarget = null;
-            setInputMethodAnimLayerAdjustment(0);
+            mLayersController.setInputMethodAnimLayerAdjustment(0);
         }
         return -1;
     }
@@ -1544,33 +1543,6 @@
         moveInputMethodDialogsLocked(pos);
     }
 
-    void setInputMethodAnimLayerAdjustment(int adj) {
-        if (DEBUG_LAYERS) Slog.v(TAG_WM, "Setting im layer adj to " + adj);
-        mInputMethodAnimLayerAdjustment = adj;
-        WindowState imw = mInputMethodWindow;
-        if (imw != null) {
-            imw.mWinAnimator.mAnimLayer = imw.mLayer + adj;
-            if (DEBUG_LAYERS) Slog.v(TAG_WM, "IM win " + imw
-                    + " anim layer: " + imw.mWinAnimator.mAnimLayer);
-            int wi = imw.mChildWindows.size();
-            while (wi > 0) {
-                wi--;
-                WindowState cw = imw.mChildWindows.get(wi);
-                cw.mWinAnimator.mAnimLayer = cw.mLayer + adj;
-                if (DEBUG_LAYERS) Slog.v(TAG_WM, "IM win " + cw
-                        + " anim layer: " + cw.mWinAnimator.mAnimLayer);
-            }
-        }
-        int di = mInputMethodDialogs.size();
-        while (di > 0) {
-            di --;
-            imw = mInputMethodDialogs.get(di);
-            imw.mWinAnimator.mAnimLayer = imw.mLayer + adj;
-            if (DEBUG_LAYERS) Slog.v(TAG_WM, "IM win " + imw
-                    + " anim layer: " + imw.mWinAnimator.mAnimLayer);
-        }
-    }
-
     private int tmpRemoveWindowLocked(int interestingPos, WindowState win) {
         WindowList windows = win.getWindowList();
         int wpos = windows.indexOf(win);
@@ -1769,7 +1741,7 @@
         }
 
         if (needAssignLayers) {
-            assignLayersLocked(windows);
+            mLayersController.assignLayersLocked(windows);
         }
 
         return true;
@@ -2022,6 +1994,10 @@
                 }
             }
 
+            // If the window is being added to a task that's docked but non-resizeable,
+            // we need to update this new window's scroll position when it's added.
+            win.applyScrollIfNeeded();
+
             if (type == TYPE_DOCK_DIVIDER) {
                 getDefaultDisplayContentLocked().getDockedDividerController().setWindow(win);
             }
@@ -2061,7 +2037,7 @@
                 moveInputMethodWindowsIfNeededLocked(false);
             }
 
-            assignLayersLocked(displayContent.getWindowList());
+            mLayersController.assignLayersLocked(displayContent.getWindowList());
             // Don't do layout here, the window must call
             // relayout to be displayed, so we'll do it there.
 
@@ -2222,7 +2198,7 @@
             // need to see about starting one.
             wasVisible = win.isWinVisibleLw();
 
-            if (wasVisible && appToken != null && appToken.appDied) {
+            if (win.shouldKeepVisibleDeadAppWindow()) {
                 if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
                         "Not removing " + win + " because app died while it's visible");
 
@@ -2261,9 +2237,8 @@
             // trigger its removal.
             final boolean lastWinStartingNotAnimating = startingWindow && appToken!= null
                     && appToken.allAppWindows.size() == 1 && !isAnimating;
-            if (!lastWinStartingNotAnimating && (win.mExiting || isAnimating)) {
+            if (!lastWinStartingNotAnimating && win.mExiting) {
                 // The exit animation is running... wait for it!
-                win.mExiting = true;
                 win.mRemoveOnExit = true;
                 win.setDisplayLayoutNeeded();
                 final boolean focusChanged = updateFocusedWindowLocked(
@@ -2388,7 +2363,7 @@
         if (windows != null) {
             windows.remove(win);
             if (!mWindowPlacerLocked.isInLayout()) {
-                assignLayersLocked(windows);
+                mLayersController.assignLayersLocked(windows);
                 win.setDisplayLayoutNeeded();
                 mWindowPlacerLocked.performSurfacePlacement();
                 if (win.mAppToken != null) {
@@ -2419,22 +2394,27 @@
         }
     }
 
-    static void logSurface(WindowState w, String msg, RuntimeException where) {
+    static void logSurface(WindowState w, String msg, boolean withStackTrace) {
         String str = "  SURFACE " + msg + ": " + w;
-        if (where != null) {
-            Slog.i(TAG_WM, str, where);
+        if (withStackTrace) {
+            logWithStack(TAG, str);
         } else {
             Slog.i(TAG_WM, str);
         }
     }
 
-    static void logSurface(SurfaceControl s, String title, String msg, RuntimeException where) {
+    static void logSurface(SurfaceControl s, String title, String msg) {
         String str = "  SURFACE " + s + ": " + msg + " / " + title;
-        if (where != null) {
-            Slog.i(TAG_WM, str, where);
-        } else {
-            Slog.i(TAG_WM, str);
+        Slog.i(TAG_WM, str);
+    }
+
+    static void logWithStack(String tag, String s) {
+        RuntimeException e = null;
+        if (SHOW_STACK_CRAWLS) {
+            e = new RuntimeException();
+            e.fillInStackTrace();
         }
+        Slog.i(tag, s, e);
     }
 
     void setTransparentRegionWindow(Session session, IWindow client, Region region) {
@@ -2443,7 +2423,7 @@
             synchronized (mWindowMap) {
                 WindowState w = windowForClientLocked(session, client, false);
                 if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
-                        "transparentRegionHint=" + region, null);
+                        "transparentRegionHint=" + region, false);
 
                 if ((w != null) && w.mHasSurface) {
                     w.mWinAnimator.setTransparentRegionHintLocked(region);
@@ -2454,13 +2434,17 @@
         }
     }
 
-    void setInsetsWindow(Session session, IWindow client,
-            int touchableInsets, Rect contentInsets,
+    void setInsetsWindow(Session session, IWindow client, int touchableInsets, Rect contentInsets,
             Rect visibleInsets, Region touchableRegion) {
         long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mWindowMap) {
                 WindowState w = windowForClientLocked(session, client, false);
+                if (DEBUG_LAYOUT) Slog.d(TAG, "setInsetsWindow " + w
+                        + ", contentInsets=" + w.mGivenContentInsets + " -> " + contentInsets
+                        + ", visibleInsets=" + w.mGivenVisibleInsets + " -> " + visibleInsets
+                        + ", touchableRegion=" + w.mGivenTouchableRegion + " -> " + touchableRegion
+                        + ", touchableInsets " + w.mTouchableInsets + " -> " + touchableInsets);
                 if (w != null) {
                     w.mGivenInsetsPending = false;
                     w.mGivenContentInsets.set(contentInsets);
@@ -2585,8 +2569,8 @@
             WindowManager.LayoutParams attrs, int requestedWidth,
             int requestedHeight, int viewVisibility, int flags,
             Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
-            Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Configuration outConfig,
-            Surface outSurface) {
+            Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,
+            Configuration outConfig, Surface outSurface) {
         int result = 0;
         boolean configChanged;
         boolean hasStatusBarPermission =
@@ -2700,25 +2684,23 @@
             } else {
                 winAnimator.mEnterAnimationPending = false;
                 winAnimator.mEnteringAnimation = false;
-                if (winAnimator.mSurfaceController != null &&
-                        winAnimator.mSurfaceController.hasSurface()) {
+                if (winAnimator.hasSurface() && !win.mExiting) {
                     if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Relayout invis " + win
                             + ": mExiting=" + win.mExiting);
-                    // If we are using a saved surface to do enter animation, just let the
-                    // animation run and don't destroy the surface. This could happen when
-                    // the app sets visibility to invisible for the first time after resume,
-                    // or when the user exits immediately after a resume. In both cases, we
-                    // don't want to destroy the saved surface.
                     // If we are not currently running the exit animation, we
                     // need to see about starting one.
-                    final boolean notExitingOrAnimating =
-                            !win.mExiting && !win.isAnimatingWithSavedSurface();
-                    result |= notExitingOrAnimating ? RELAYOUT_RES_SURFACE_CHANGED : 0;
-                    if (notExitingOrAnimating) {
-                        focusMayChange = tryStartingAnimation(win, winAnimator, isDefaultDisplay,
-                                focusMayChange);
-
+                    // We don't want to animate visibility of windows which are pending
+                    // replacement. In the case of activity relaunch child windows
+                    // could request visibility changes as they are detached from the main
+                    // application window during the tear down process. If we satisfied
+                    // these visibility changes though, we would cause a visual glitch
+                    // hiding the window before it's replacement was available.
+                    // So we just do nothing on our side.
+                    if (!win.mWillReplaceWindow) {
+                        focusMayChange = tryStartExitingAnimation(
+                                win, winAnimator, isDefaultDisplay, focusMayChange);
                     }
+                    result |= RELAYOUT_RES_SURFACE_CHANGED;
                 }
 
                 outSurface.release();
@@ -2743,7 +2725,7 @@
                 // its layer recomputed.  However, if the IME was hidden
                 // and isn't actually moved in the list, its layer may be
                 // out of data so we make sure to recompute it.
-                assignLayersLocked(win.getWindowList());
+                mLayersController.assignLayersLocked(win.getWindowList());
             }
 
             if (wallpaperMayMove) {
@@ -2773,6 +2755,7 @@
             outVisibleInsets.set(win.mVisibleInsets);
             outStableInsets.set(win.mStableInsets);
             outOutsets.set(win.mOutsets);
+            outBackdropFrame.set(win.getBackdropFrame(win.mFrame));
             if (localLOGV) Slog.v(
                 TAG_WM, "Relayout given client " + client.asBinder()
                 + ", requestedWidth=" + requestedWidth
@@ -2800,7 +2783,7 @@
         return result;
     }
 
-    private boolean tryStartingAnimation(WindowState win, WindowStateAnimator winAnimator,
+    private boolean tryStartExitingAnimation(WindowState win, WindowStateAnimator winAnimator,
             boolean isDefaultDisplay, boolean focusMayChange) {
         // Try starting an animation; if there isn't one, we
         // can destroy the surface right away.
@@ -2870,11 +2853,12 @@
         if ((result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
             win.prepareWindowToDisplayDuringRelayout(outConfig);
         }
-        if ((attrChanges& LayoutParams.FORMAT_CHANGED) != 0) {
-            // If the format can be changed in place yaay!
-            // If not, fall back to a surface re-build
+        if ((attrChanges & LayoutParams.FORMAT_CHANGED) != 0) {
+            // If the format can't be changed in place, preserve the old surface until the app draws
+            // on the new one. This prevents blinking when we change elevation of freeform and
+            // pinned windows.
             if (!winAnimator.tryChangeFormatInPlaceLocked()) {
-                winAnimator.destroySurfaceLocked();
+                winAnimator.preserveSurfaceLocked();
                 result |= RELAYOUT_RES_SURFACE_CHANGED
                         | WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME;
             }
@@ -2893,7 +2877,12 @@
                 result |= WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME;
             }
         }
-        result |= win.isDragResizing() ? WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING : 0;
+        final boolean freeformResizing = win.isDragResizing()
+                && win.getResizeMode() == WindowState.DRAG_RESIZE_MODE_FREEFORM;
+        final boolean dockedResizing = win.isDragResizing()
+                && win.getResizeMode() == WindowState.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()) {
             // If we're animating with a saved surface now, request client to report draw.
             // We still need to know when the real thing is drawn.
@@ -2908,9 +2897,10 @@
         try {
             synchronized (mWindowMap) {
                 WindowState win = windowForClientLocked(session, client, false);
-                if (win == null) {
+                if (win == null || win.mWillReplaceWindow) {
                     return;
                 }
+
                 win.mWinAnimator.destroyDeferredSurfaceLocked();
             }
         } finally {
@@ -3006,16 +2996,9 @@
                     + " frame=" + frame + " insets=" + insets + " surfaceInsets=" + surfaceInsets);
             Animation a = mAppTransition.loadAnimation(lp, transit, enter,
                     mCurConfiguration.orientation, frame, insets, surfaceInsets, isVoiceInteraction,
-                    freeform, atoken.mTask.mTaskId);
+                    !fullscreen, atoken.mTask.mTaskId);
             if (a != null) {
-                if (DEBUG_ANIM) {
-                    RuntimeException e = null;
-                    if (!HIDE_STACK_CRAWLS) {
-                        e = new RuntimeException();
-                        e.fillInStackTrace();
-                    }
-                    Slog.v(TAG_WM, "Loaded animation " + a + " for " + atoken, e);
-                }
+                if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + atoken);
                 final int containingWidth = frame.width();
                 final int containingHeight = frame.height();
                 atoken.mAppAnimator.setAnimation(a, containingWidth, containingHeight,
@@ -3231,7 +3214,8 @@
     public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
             int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,
             int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
-            Rect taskBounds, Configuration config, boolean cropWindowsToStack) {
+            Rect taskBounds, Configuration config, boolean cropWindowsToStack,
+            boolean alwaysFocusable) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "addAppToken()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3266,6 +3250,7 @@
                     (ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;
             atoken.mLaunchTaskBehind = launchTaskBehind;
             atoken.mCropWindowsToStack = cropWindowsToStack;
+            atoken.mAlwaysFocusable = alwaysFocusable;
             if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
                     + " to stack=" + stackId + " task=" + taskId + " at " + addPos);
 
@@ -3495,6 +3480,7 @@
             // the value of the previous configuration.
             mTempConfiguration.setToDefaults();
             mTempConfiguration.fontScale = currentConfig.fontScale;
+            mTempConfiguration.uiMode = currentConfig.uiMode;
             computeScreenConfigurationLocked(mTempConfiguration);
             if (currentConfig.diff(mTempConfiguration) != 0) {
                 mWaitingForConfig = true;
@@ -3549,6 +3535,7 @@
         }
     }
 
+    @Override
     public void setNewConfiguration(Configuration config) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "setNewConfiguration()")) {
@@ -3562,10 +3549,20 @@
                 mWaitingForConfig = false;
                 mLastFinishedFreezeSource = "new-config";
             }
+            if (orientationChanged) {
+                updateTaskStackBoundsAfterRotation();
+            }
             mWindowPlacerLocked.performSurfacePlacement();
         }
     }
 
+    private void updateTaskStackBoundsAfterRotation() {
+        for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; stackNdx--) {
+            final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
+            stack.updateBoundsAfterRotation();
+        }
+    }
+
     @Override
     public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
@@ -3905,7 +3902,7 @@
             return false;
         }
         WindowState startingWindow = ttoken.startingWindow;
-        if (startingWindow != null) {
+        if (startingWindow != null && ttoken.startingView != null) {
             // In this case, the starting icon has already been displayed, so start
             // letting windows get shown immediately without any more transitions.
             mSkipAppTransitionAnimation = true;
@@ -4240,6 +4237,7 @@
                         }
                     }
                 } else {
+                    wtoken.markSurfacesExiting();
                     mClosingApps.add(wtoken);
                     wtoken.mEnteringAnimation = false;
                 }
@@ -4310,16 +4308,8 @@
     }
 
     private void startAppFreezingScreenLocked(AppWindowToken wtoken) {
-        if (DEBUG_ORIENTATION) {
-            RuntimeException e = null;
-            if (!HIDE_STACK_CRAWLS) {
-                e = new RuntimeException();
-                e.fillInStackTrace();
-            }
-            Slog.i(TAG_WM, "Set freezing of " + wtoken.appToken
-                    + ": hidden=" + wtoken.hidden + " freezing="
-                    + wtoken.mAppAnimator.freezingScreen, e);
-        }
+        if (DEBUG_ORIENTATION) logWithStack(TAG, "Set freezing of " + wtoken.appToken + ": hidden="
+                + wtoken.hidden + " freezing=" + wtoken.mAppAnimator.freezingScreen);
         if (!wtoken.hiddenRequested) {
             if (!wtoken.mAppAnimator.freezingScreen) {
                 wtoken.mAppAnimator.freezingScreen = true;
@@ -4586,7 +4576,7 @@
 
         if (!updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
                 false /*updateInputWindows*/)) {
-            assignLayersLocked(displayContent.getWindowList());
+            mLayersController.assignLayersLocked(displayContent.getWindowList());
         }
 
         mInputMonitor.setUpdateInputWindowsNeededLw();
@@ -4679,6 +4669,10 @@
                         if (DEBUG_STACK) Slog.d(TAG_WM, "attachStack: stackId=" + stackId);
                         stack = new TaskStack(this, stackId);
                         mStackIdToStack.put(stackId, stack);
+                        if (stackId == DOCKED_STACK_ID) {
+                            getDefaultDisplayContentLocked().mDividerControllerLocked
+                                    .notifyDockedStackExistsChanged(true);
+                        }
                     }
                     stack.attachDisplayContent(displayContent);
                     displayContent.attachStack(stack, onTop);
@@ -4704,6 +4698,10 @@
     void detachStackLocked(DisplayContent displayContent, TaskStack stack) {
         displayContent.detachStack(stack);
         stack.detachDisplay();
+        if (stack.mStackId == DOCKED_STACK_ID) {
+            getDefaultDisplayContentLocked().mDividerControllerLocked
+                    .notifyDockedStackExistsChanged(false);
+        }
     }
 
     public void detachStack(int stackId) {
@@ -4797,11 +4795,12 @@
         }
     }
 
-    public void getStackDockedModeBounds(int stackId, Rect bounds) {
+    public void getStackDockedModeBounds(
+            int stackId, Rect bounds, boolean ignoreVisibilityOnKeyguardShowing) {
         synchronized (mWindowMap) {
             final TaskStack stack = mStackIdToStack.get(stackId);
             if (stack != null) {
-                stack.getStackDockedModeBoundsLocked(bounds);
+                stack.getStackDockedModeBoundsLocked(bounds, ignoreVisibilityOnKeyguardShowing);
                 return;
             }
             bounds.setEmpty();
@@ -4850,15 +4849,16 @@
      * @return True if the stack is now fullscreen.
      * */
     public boolean resizeStack(int stackId, Rect bounds,
-            SparseArray<Configuration> configs, SparseArray<Rect> taskBounds) {
+            SparseArray<Configuration> configs, SparseArray<Rect> taskBounds,
+            SparseArray<Rect> taskTempInsetBounds) {
         synchronized (mWindowMap) {
             final TaskStack stack = mStackIdToStack.get(stackId);
             if (stack == null) {
                 throw new IllegalArgumentException("resizeStack: stackId " + stackId
                         + " not found.");
             }
-            if (stack.setBounds(bounds, configs, taskBounds) && stack.isVisibleLocked()) {
-                stack.resizeWindows();
+            if (stack.setBounds(bounds, configs, taskBounds, taskTempInsetBounds)
+                    && stack.isVisibleLocked()) {
                 stack.getDisplayContent().layoutNeeded = true;
                 mWindowPlacerLocked.performSurfacePlacement();
             }
@@ -4866,6 +4866,17 @@
         }
     }
 
+    public void prepareFreezingTaskBounds(int stackId) {
+        synchronized (mWindowMap) {
+            final TaskStack stack = mStackIdToStack.get(stackId);
+            if (stack == null) {
+                throw new IllegalArgumentException("prepareFreezingTaskBounds: stackId " + stackId
+                        + " not found.");
+            }
+            stack.prepareFreezingTaskBounds();
+        }
+    }
+
     public void positionTaskInStack(int taskId, int stackId, int position, Rect bounds,
             Configuration config) {
         synchronized (mWindowMap) {
@@ -5303,12 +5314,6 @@
 
     // Called by window manager policy.  Not exposed externally.
     @Override
-    public void switchKeyboardLayout(int deviceId, int direction) {
-        mInputManager.switchKeyboardLayout(deviceId, direction);
-    }
-
-    // Called by window manager policy.  Not exposed externally.
-    @Override
     public void switchInputMethod(boolean forwardDirection) {
         final InputMethodManagerInternal inputMethodManagerInternal =
                 LocalServices.getService(InputMethodManagerInternal.class);
@@ -5350,9 +5355,31 @@
                 rebuildAppWindowListLocked(displayContent);
             }
             mWindowPlacerLocked.performSurfacePlacement();
+
+            // Notify whether the docked stack exists for the current user
+            getDefaultDisplayContentLocked().mDividerControllerLocked
+                    .notifyDockedStackExistsChanged(hasDockedTasksForUser(newUserId));
         }
     }
 
+    /**
+     * Returns whether there is a docked task for the current user.
+     */
+    boolean hasDockedTasksForUser(int userId) {
+        final TaskStack stack = mStackIdToStack.get(DOCKED_STACK_ID);
+        if (stack == null) {
+            return false;
+        }
+
+        final ArrayList<Task> tasks = stack.getTasks();
+        boolean hasUserTask = false;
+        for (int i = tasks.size() - 1; i >= 0 && !hasUserTask; i--) {
+            final Task task = tasks.get(i);
+            hasUserTask = (task.mUserId == userId);
+        }
+        return hasUserTask;
+    }
+
     /* Called by WindowState */
     boolean isCurrentProfileLocked(int userId) {
         if (userId == mCurrentUserId) return true;
@@ -6291,7 +6318,7 @@
         // the top of the method, the caller is obligated to call computeNewConfigurationLocked().
         // By updating the Display info here it will be available to
         // computeScreenConfigurationLocked later.
-        updateDisplayAndOrientationLocked();
+        updateDisplayAndOrientationLocked(mCurConfiguration.uiMode);
 
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
         if (!inTransaction) {
@@ -6858,16 +6885,17 @@
         return config;
     }
 
-    private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation, int dw, int dh) {
+    private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation, int uiMode,
+            int dw, int dh) {
         // TODO: Multidisplay: for now only use with default display.
-        final int width = mPolicy.getConfigDisplayWidth(dw, dh, rotation);
+        final int width = mPolicy.getConfigDisplayWidth(dw, dh, rotation, uiMode);
         if (width < displayInfo.smallestNominalAppWidth) {
             displayInfo.smallestNominalAppWidth = width;
         }
         if (width > displayInfo.largestNominalAppWidth) {
             displayInfo.largestNominalAppWidth = width;
         }
-        final int height = mPolicy.getConfigDisplayHeight(dw, dh, rotation);
+        final int height = mPolicy.getConfigDisplayHeight(dw, dh, rotation, uiMode);
         if (height < displayInfo.smallestNominalAppHeight) {
             displayInfo.smallestNominalAppHeight = height;
         }
@@ -6877,11 +6905,11 @@
     }
 
     private int reduceConfigLayout(int curLayout, int rotation, float density,
-            int dw, int dh) {
+            int dw, int dh, int uiMode) {
         // TODO: Multidisplay: for now only use with default display.
         // Get the app screen size at this rotation.
-        int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
-        int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
+        int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode);
+        int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode);
 
         // Compute the screen layout size class for this rotation.
         int longSize = w;
@@ -6897,7 +6925,7 @@
     }
 
     private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, boolean rotated,
-                  int dw, int dh, float density, Configuration outConfig) {
+                  int uiMode, int dw, int dh, float density, Configuration outConfig) {
         // TODO: Multidisplay: for now only use with default display.
 
         // We need to determine the smallest width that will occur under normal
@@ -6916,24 +6944,24 @@
         displayInfo.smallestNominalAppHeight = 1<<30;
         displayInfo.largestNominalAppWidth = 0;
         displayInfo.largestNominalAppHeight = 0;
-        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_0, unrotDw, unrotDh);
-        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, unrotDh, unrotDw);
-        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, unrotDw, unrotDh);
-        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, unrotDh, unrotDw);
+        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_0, uiMode, unrotDw, unrotDh);
+        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, uiMode, unrotDh, unrotDw);
+        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, uiMode, unrotDw, unrotDh);
+        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, uiMode, unrotDh, unrotDw);
         int sl = Configuration.resetScreenLayout(outConfig.screenLayout);
-        sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh);
-        sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw);
-        sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh);
-        sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw);
+        sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh, uiMode);
+        sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw, uiMode);
+        sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh, uiMode);
+        sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw, uiMode);
         outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density);
         outConfig.screenLayout = sl;
     }
 
-    private int reduceCompatConfigWidthSize(int curSize, int rotation, DisplayMetrics dm,
-            int dw, int dh) {
+    private int reduceCompatConfigWidthSize(int curSize, int rotation, int uiMode,
+            DisplayMetrics dm, int dw, int dh) {
         // TODO: Multidisplay: for now only use with default display.
-        dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
-        dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
+        dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode);
+        dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode);
         float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
         int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f);
         if (curSize == 0 || size < curSize) {
@@ -6942,7 +6970,7 @@
         return curSize;
     }
 
-    private int computeCompatSmallestWidth(boolean rotated, DisplayMetrics dm, int dw, int dh) {
+    private int computeCompatSmallestWidth(boolean rotated, int uiMode, DisplayMetrics dm, int dw, int dh) {
         // TODO: Multidisplay: for now only use with default display.
         mTmpDisplayMetrics.setTo(dm);
         final DisplayMetrics tmpDm = mTmpDisplayMetrics;
@@ -6954,15 +6982,15 @@
             unrotDw = dw;
             unrotDh = dh;
         }
-        int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, tmpDm, unrotDw, unrotDh);
-        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, tmpDm, unrotDh, unrotDw);
-        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, tmpDm, unrotDw, unrotDh);
-        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, tmpDm, unrotDh, unrotDw);
+        int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, uiMode, tmpDm, unrotDw, unrotDh);
+        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, uiMode, tmpDm, unrotDh, unrotDw);
+        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, uiMode, tmpDm, unrotDw, unrotDh);
+        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, uiMode, tmpDm, unrotDh, unrotDw);
         return sw;
     }
 
     /** Do not call if mDisplayReady == false */
-    DisplayInfo updateDisplayAndOrientationLocked() {
+    DisplayInfo updateDisplayAndOrientationLocked(int uiMode) {
         // TODO(multidisplay): For now, apply Configuration to main screen only.
         final DisplayContent displayContent = getDefaultDisplayContentLocked();
 
@@ -6993,8 +7021,8 @@
         }
 
         // Update application display metrics.
-        final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation);
-        final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation);
+        final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation, uiMode);
+        final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation, uiMode);
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
         displayInfo.rotation = mRotation;
         displayInfo.logicalWidth = dw;
@@ -7026,20 +7054,24 @@
 
     /** Do not call if mDisplayReady == false */
     void computeScreenConfigurationLocked(Configuration config) {
-        final DisplayInfo displayInfo = updateDisplayAndOrientationLocked();
+        final DisplayInfo displayInfo = updateDisplayAndOrientationLocked(
+                config.uiMode);
 
         final int dw = displayInfo.logicalWidth;
         final int dh = displayInfo.logicalHeight;
         config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT :
                 Configuration.ORIENTATION_LANDSCAPE;
         config.screenWidthDp =
-                (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation) / mDisplayMetrics.density);
+                (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation, config.uiMode) /
+                        mDisplayMetrics.density);
         config.screenHeightDp =
-                (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation) / mDisplayMetrics.density);
+                (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation, config.uiMode) /
+                        mDisplayMetrics.density);
         final boolean rotated = (mRotation == Surface.ROTATION_90
                 || mRotation == Surface.ROTATION_270);
-        computeSizeRangesAndScreenLayout(displayInfo, rotated, dw, dh, mDisplayMetrics.density,
-                config);
+
+        computeSizeRangesAndScreenLayout(displayInfo, rotated, config.uiMode, dw, dh,
+                mDisplayMetrics.density, config);
 
         config.screenLayout = (config.screenLayout & ~Configuration.SCREENLAYOUT_ROUND_MASK)
                 | ((displayInfo.flags & Display.FLAG_ROUND) != 0
@@ -7048,7 +7080,7 @@
 
         config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
         config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
-        config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated,
+        config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, config.uiMode,
                 mDisplayMetrics, dw, dh);
         config.densityDpi = displayInfo.logicalDensityDpi;
 
@@ -7107,9 +7139,6 @@
             mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
             mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
         }
-        if (mShowImeWithHardKeyboard) {
-            config.keyboard = Configuration.KEYBOARD_NOKEYS;
-        }
 
         // Let the policy update hidden states.
         config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
@@ -7118,18 +7147,6 @@
         mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
     }
 
-    public void updateShowImeWithHardKeyboard() {
-        synchronized (mWindowMap) {
-            final boolean showImeWithHardKeyboard = Settings.Secure.getIntForUser(
-                    mContext.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0,
-                    mCurrentUserId) == 1;
-            if (mShowImeWithHardKeyboard != showImeWithHardKeyboard) {
-                mShowImeWithHardKeyboard = showImeWithHardKeyboard;
-                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
-            }
-        }
-    }
-
     void notifyHardKeyboardStatusChange() {
         final boolean available;
         final WindowManagerInternal.OnHardKeyboardStatusChangeListener listener;
@@ -7178,18 +7195,25 @@
         } catch(RemoteException e) {}
     }
 
-    private void startResizingTask(DisplayContent displayContent, int startX, int startY) {
-        Task task = null;
+    private void handleTapOutsideTask(DisplayContent displayContent, int x, int y) {
+        int taskId = -1;
         synchronized (mWindowMap) {
-            task = displayContent.findTaskForControlPoint(startX, startY);
-            if (task == null || !startPositioningLocked(
-                    task.getTopVisibleAppMainWindow(), true /*resize*/, startX, startY)) {
-                return;
+            final Task task = displayContent.findTaskForControlPoint(x, y);
+            if (task != null) {
+                if (!startPositioningLocked(
+                        task.getTopVisibleAppMainWindow(), true /*resize*/, x, y)) {
+                    return;
+                }
+                taskId = task.mTaskId;
+            } else {
+                taskId = displayContent.taskIdFromPoint(x, y);
             }
         }
-        try {
-            mActivityManager.setFocusedTask(task.mTaskId);
-        } catch(RemoteException e) {}
+        if (taskId >= 0) {
+            try {
+                mActivityManager.setFocusedTask(taskId);
+            } catch(RemoteException e) {}
+        }
     }
 
     private boolean startPositioningLocked(
@@ -7504,18 +7528,17 @@
         public static final int RESET_ANR_MESSAGE = 38;
         public static final int WALLPAPER_DRAW_PENDING_TIMEOUT = 39;
 
-        public static final int TAP_DOWN_OUTSIDE_TASK = 40;
-        public static final int FINISH_TASK_POSITIONING = 41;
+        public static final int FINISH_TASK_POSITIONING = 40;
 
-        public static final int UPDATE_DOCKED_STACK_DIVIDER = 42;
+        public static final int UPDATE_DOCKED_STACK_DIVIDER = 41;
 
-        public static final int RESIZE_STACK = 43;
-        public static final int RESIZE_TASK = 44;
+        public static final int RESIZE_STACK = 42;
+        public static final int RESIZE_TASK = 43;
 
-        public static final int TWO_FINGER_SCROLL_START = 45;
-        public static final int SHOW_NON_RESIZEABLE_DOCK_TOAST = 46;
+        public static final int TWO_FINGER_SCROLL_START = 44;
+        public static final int SHOW_NON_RESIZEABLE_DOCK_TOAST = 45;
 
-        public static final int WINDOW_REPLACEMENT_TIMEOUT = 47;
+        public static final int WINDOW_REPLACEMENT_TIMEOUT = 46;
 
         /**
          * Used to denote that an integer field in a message will not be used.
@@ -7969,27 +7992,13 @@
                     }
                     break;
 
-                case TAP_OUTSIDE_TASK: {
-                    int taskId;
-                    synchronized (mWindowMap) {
-                        taskId = ((DisplayContent)msg.obj).taskIdFromPoint(msg.arg1, msg.arg2);
-                    }
-                    if (taskId >= 0) {
-                        try {
-                            mActivityManager.setFocusedTask(taskId);
-                        } catch (RemoteException e) {
-                        }
-                    }
-                }
-                break;
-
                 case TWO_FINGER_SCROLL_START: {
                     startScrollingTask((DisplayContent)msg.obj, msg.arg1, msg.arg2);
                 }
                 break;
 
-                case TAP_DOWN_OUTSIDE_TASK: {
-                    startResizingTask((DisplayContent)msg.obj, msg.arg1, msg.arg2);
+                case TAP_OUTSIDE_TASK: {
+                    handleTapOutsideTask((DisplayContent)msg.obj, msg.arg1, msg.arg2);
                 }
                 break;
 
@@ -8067,8 +8076,29 @@
                 }
                 case UPDATE_DOCKED_STACK_DIVIDER: {
                     synchronized (mWindowMap) {
-                        getDefaultDisplayContentLocked().getDockedDividerController()
-                                .reevaluateVisibility(false);
+                        final DisplayContent displayContent = getDefaultDisplayContentLocked();
+
+                        displayContent.getDockedDividerController().reevaluateVisibility(false);
+
+                        final WindowState imeWin = mInputMethodWindow;
+                        final TaskStack focusedStack =
+                                mCurrentFocus != null ? mCurrentFocus.getStack() : null;
+                        if (imeWin != null && focusedStack != null && imeWin.isVisibleNow()
+                                && 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.adjustForIME(imeWin);
+                                }
+                            }
+                        } else {
+                            final ArrayList<TaskStack> stacks = displayContent.getStacks();
+                            for (int i = stacks.size() - 1; i >= 0; --i) {
+                                final TaskStack stack = stacks.get(i);
+                                stack.adjustForIME(null);
+                            }
+                        }
                     }
                 }
                 break;
@@ -8082,7 +8112,8 @@
                 break;
                 case RESIZE_STACK: {
                     try {
-                        mActivityManager.resizeStack(msg.arg1, (Rect) msg.obj, msg.arg2 == 1);
+                        mActivityManager.resizeStack(msg.arg1, (Rect) msg.obj, msg.arg2 == 1, false,
+                                false);
                     } catch (RemoteException e) {
                         // This will not happen since we are in the same process.
                     }
@@ -8102,7 +8133,7 @@
                 case WINDOW_REPLACEMENT_TIMEOUT: {
                     final AppWindowToken token = (AppWindowToken) msg.obj;
                     synchronized (mWindowMap) {
-                        token.clearTimedoutReplaceesLocked();
+                        token.clearTimedoutReplacesLocked();
                     }
                 }
                 break;
@@ -8467,6 +8498,7 @@
         boolean configChanged = updateOrientationFromAppTokensLocked(false);
         mTempConfiguration.setToDefaults();
         mTempConfiguration.fontScale = mCurConfiguration.fontScale;
+        mTempConfiguration.uiMode = mCurConfiguration.uiMode;
         computeScreenConfigurationLocked(mTempConfiguration);
         configChanged |= mCurConfiguration.diff(mTempConfiguration) != 0;
 
@@ -8662,102 +8694,6 @@
         Arrays.fill(mRebuildTmp, null);
     }
 
-    final void assignLayersLocked(WindowList windows) {
-        int N = windows.size();
-        int curBaseLayer = 0;
-        int curLayer = 0;
-        int i;
-
-        if (DEBUG_LAYERS) Slog.v(TAG_WM, "Assigning layers based on windows=" + windows,
-                new RuntimeException("here").fillInStackTrace());
-
-        boolean anyLayerChanged = false;
-
-        for (i=0; i<N; i++) {
-            final WindowState w = windows.get(i);
-            final WindowStateAnimator winAnimator = w.mWinAnimator;
-            boolean layerChanged = false;
-            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;
-            }
-            final AppWindowToken wtoken = w.mAppToken;
-            oldLayer = winAnimator.mAnimLayer;
-            if (w.mTargetAppToken != null) {
-                winAnimator.mAnimLayer =
-                        w.mLayer + w.mTargetAppToken.mAppAnimator.animLayerAdjustment;
-            } else if (wtoken != null) {
-                winAnimator.mAnimLayer =
-                        w.mLayer + wtoken.mAppAnimator.animLayerAdjustment;
-                forceHigherLayerIfNeeded(w, winAnimator, wtoken);
-            } else {
-                winAnimator.mAnimLayer = w.mLayer;
-            }
-            if (w.mIsImWindow) {
-                winAnimator.mAnimLayer += mInputMethodAnimLayerAdjustment;
-            } else if (w.mIsWallpaper) {
-                winAnimator.mAnimLayer += mWallpaperControllerLocked.getAnimLayerAdjustment();
-            }
-            if (winAnimator.mAnimLayer != oldLayer) {
-                layerChanged = true;
-                anyLayerChanged = true;
-            }
-            final DimLayer.DimLayerUser dimLayerUser = w.getDimLayerUser();
-            final DisplayContent displayContent = w.getDisplayContent();
-            if (layerChanged && dimLayerUser != null && displayContent != null &&
-                    displayContent.mDimLayerController.isDimming(dimLayerUser, winAnimator)) {
-                // Force an animation pass just to update the mDimLayer layer.
-                scheduleAnimationLocked();
-            }
-            if (DEBUG_LAYERS) Slog.v(TAG_WM, "Assign layer " + w + ": "
-                    + "mBase=" + w.mBaseLayer
-                    + " mLayer=" + w.mLayer
-                    + (wtoken == null ?
-                            "" : " mAppLayer=" + wtoken.mAppAnimator.animLayerAdjustment)
-                    + " =mAnimLayer=" + winAnimator.mAnimLayer);
-            //System.out.println(
-            //    "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
-        }
-
-        //TODO (multidisplay): Magnification is supported only for the default display.
-        if (mAccessibilityController != null && anyLayerChanged
-                && windows.get(windows.size() - 1).getDisplayId() == Display.DEFAULT_DISPLAY) {
-            mAccessibilityController.onWindowLayersChangedLocked();
-        }
-    }
-
-    private void forceHigherLayerIfNeeded(WindowState w, WindowStateAnimator winAnimator,
-            AppWindowToken wtoken) {
-        boolean force = false;
-
-        if (w.mWillReplaceWindow) {
-            // 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.
-            force = true;
-        }
-        if (!force) {
-            final TaskStack stack = w.getStack();
-            if (stack != null && (StackId.shouldIncreaseApplicationWindowLayer(stack.mStackId))) {
-                // For pinned and docked stack window, we want to make them above other windows
-                // also when these windows are animating.
-                force = true;
-            }
-        }
-        if (force) {
-            w.mLayer += TYPE_LAYER_OFFSET;
-            winAnimator.mAnimLayer += TYPE_LAYER_OFFSET;
-        }
-    }
-
     void makeWindowFreezingScreenIfNeededLocked(WindowState w) {
         // If the screen is currently frozen or off, then keep
         // it frozen/off until this window draws at its new
@@ -9029,7 +8965,7 @@
                                     + ws + " surface=" + wsa.mSurfaceController
                                     + " token=" + ws.mAppToken
                                     + " saved=" + ws.mAppToken.hasSavedSurface());
-                            if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
+                            if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", false);
                             wsa.destroySurface();
                             ws.setHasSurface(false);
                             leakedSurface = true;
@@ -9075,7 +9011,7 @@
                 Slog.w(TAG_WM, "Looks like we have reclaimed some memory, clearing surface for retry.");
                 if (surfaceController != null) {
                     if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
-                            "RECOVER DESTROY", null);
+                            "RECOVER DESTROY", false);
                     surfaceController.destroyInTransaction();
                     winAnimator.mWin.setHasSurface(false);
                     scheduleRemoveStartingWindowLocked(winAnimator.mWin.mAppToken);
@@ -9128,7 +9064,7 @@
                 } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
                     // Client will do the layout, but we need to assign layers
                     // for handleNewWindowLocked() below.
-                    assignLayersLocked(displayContent.getWindowList());
+                    mLayersController.assignLayersLocked(displayContent.getWindowList());
                 }
             }
 
@@ -9202,8 +9138,8 @@
                         if (wtoken == token) {
                             break;
                         }
-                        if (mFocusedApp == token && token.stackCanReceiveKeys()) {
-                            // Whoops, we are below the focused app whose stack can receive keys...
+                        if (mFocusedApp == token && token.windowsAreFocusable()) {
+                            // Whoops, we are below the focused app whose windows are focusable...
                             // No focus for you!!!
                             if (localLOGV || DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM,
                                     "findFocusedWindow: Reached focused app=" + mFocusedApp);
@@ -9588,6 +9524,32 @@
         }
     }
 
+    public void notifyAppRelaunching(IBinder token) {
+        synchronized (mWindowMap) {
+            AppWindowToken appWindow = findAppWindowToken(token);
+            if (canFreezeBounds(appWindow)) {
+                appWindow.freezeBounds();
+            }
+        }
+    }
+
+    public void notifyAppRelaunchingFinished(IBinder token) {
+        synchronized (mWindowMap) {
+            AppWindowToken appWindow = findAppWindowToken(token);
+            if (canFreezeBounds(appWindow)) {
+                appWindow.unfreezeBounds();
+            }
+        }
+    }
+
+    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();
+    }
+
     void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
         pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
         mPolicy.dump("    ", pw, args);
@@ -9816,13 +9778,7 @@
             }
             mWindowPlacerLocked.dump(pw, "  ");
             mWallpaperControllerLocked.dump(pw, "  ");
-            if (mInputMethodAnimLayerAdjustment != 0 ||
-                    mWallpaperControllerLocked.getAnimLayerAdjustment() != 0) {
-                pw.print("  mInputMethodAnimLayerAdjustment=");
-                        pw.print(mInputMethodAnimLayerAdjustment);
-                        pw.print("  mWallpaperAnimLayerAdjustment=");
-                        pw.println(mWallpaperControllerLocked.getAnimLayerAdjustment());
-            }
+            mLayersController.dump(pw, "  ");
             pw.print("  mSystemBooted="); pw.print(mSystemBooted);
                     pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
             if (needsLayout()) {
@@ -9859,17 +9815,22 @@
     boolean dumpWindows(PrintWriter pw, String name, String[] args,
             int opti, boolean dumpAll) {
         WindowList windows = new WindowList();
-        if ("visible".equals(name) || "visible-apps".equals(name)) {
-            final boolean appsOnly = "visible-apps".equals(name);
+        if ("apps".equals(name) || "visible".equals(name) || "visible-apps".equals(name)) {
+            final boolean appsOnly = name.contains("apps");
+            final boolean visibleOnly = name.contains("visible");
             synchronized(mWindowMap) {
+                if (appsOnly) {
+                    dumpDisplayContentsLocked(pw, true);
+                }
+
                 final int numDisplays = mDisplayContents.size();
                 for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
                     final WindowList windowList =
                             mDisplayContents.valueAt(displayNdx).getWindowList();
                     for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
                         final WindowState w = windowList.get(winNdx);
-                        if (w.mWinAnimator.getShown()
-                                && (!appsOnly || (appsOnly && w.mAppToken != null))) {
+                        if ((!visibleOnly || w.mWinAnimator.getShown())
+                                && (!appsOnly || w.mAppToken != null)) {
                             windows.add(w);
                         }
                     }
@@ -10258,16 +10219,61 @@
         synchronized (mWindowMap) {
             appWindowToken = findAppWindowToken(token);
             if (appWindowToken == null || !appWindowToken.isVisible()) {
-                Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token " + token);
+                Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token "
+                        + token);
                 return;
             }
             appWindowToken.setReplacingWindows(animate);
         }
+    }
 
-        if (appWindowToken != null) {
-            mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT);
-            mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_REPLACEMENT_TIMEOUT, appWindowToken),
-                    WINDOW_REPLACEMENT_TIMEOUT_DURATION);
+    /**
+     * Hint to a token that its children will be replaced across activity relaunch.
+     * The children would otherwise be removed  shortly following this as the
+     * activity is torn down.
+     * @param token Application token for which the activity will be relaunched.
+     */
+    public void setReplacingChildren(IBinder token) {
+        AppWindowToken appWindowToken = null;
+        synchronized (mWindowMap) {
+            appWindowToken = findAppWindowToken(token);
+            if (appWindowToken == null || !appWindowToken.isVisible()) {
+                Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token "
+                        + token);
+                return;
+            }
+
+            appWindowToken.setReplacingChildren();
+            scheduleClearReplacingWindowIfNeeded(token, true /* replacing */);
+        }
+    }
+
+    /**
+     * If we're replacing the window, schedule a timer to clear the replaced window
+     * after a timeout, in case the replacing window is not coming.
+     *
+     * If we're not replacing the window, clear the replace window settings of the app.
+     *
+     * @param token Application token for the activity whose window might be replaced.
+     * @param replacing Whether the window is being replaced or not.
+     */
+    public void scheduleClearReplacingWindowIfNeeded(IBinder token, boolean replacing) {
+        AppWindowToken appWindowToken = null;
+        synchronized (mWindowMap) {
+            appWindowToken = findAppWindowToken(token);
+            if (appWindowToken == null) {
+                Slog.w(TAG_WM, "Attempted to reset replacing window on non-existing app token "
+                        + token);
+                return;
+            }
+            if (replacing) {
+                mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT);
+                mH.sendMessageDelayed(
+                        mH.obtainMessage(H.WINDOW_REPLACEMENT_TIMEOUT, appWindowToken),
+                        WINDOW_REPLACEMENT_TIMEOUT_DURATION);
+            } else {
+                appWindowToken.resetReplacingWindows();
+            }
         }
     }
 
@@ -10287,6 +10293,39 @@
         }
     }
 
+    @Override
+    public void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
+        synchronized (mWindowMap) {
+            getDefaultDisplayContentLocked().getDockedDividerController().setResizeDimLayer(
+                    visible, targetStackId, alpha);
+        }
+    }
+
+    public void animateResizePinnedStack(final Rect bounds) {
+        synchronized (mWindowMap) {
+            final TaskStack stack = mStackIdToStack.get(PINNED_STACK_ID);
+            if (stack == null) {
+                Slog.w(TAG, "animateResizePinnedStack: stackId " + PINNED_STACK_ID + " not found.");
+                return;
+            }
+            final ArrayList<Task> tasks = stack.getTasks();
+            if (tasks.isEmpty()) {
+                Slog.w(TAG, "animateResizePinnedStack: pinned stack doesn't have any tasks.");
+                return;
+            }
+            final Task task = tasks.get(tasks.size() - 1);
+            task.setDragResizing(true);
+            final Rect originalBounds = new Rect();
+            stack.getBounds(originalBounds);
+            UiThread.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    mBoundsAnimationController.animateBounds(stack, originalBounds, bounds);
+                }
+            });
+        }
+    }
+
     public void setTaskResizeable(int taskId, boolean resizeable) {
         synchronized (mWindowMap) {
             Task task = mTaskIdToTask.get(taskId);
@@ -10300,30 +10339,22 @@
         return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, displayMetrics);
     }
 
-    void scheduleSurfaceDestroy(WindowState win) {
-        mDestroySurface.add(win);
-    }
-
     @Override
-    public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) {
+    public void registerDockedStackListener(IDockedStackListener listener) {
         if (!checkCallingPermission(android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS,
-                "registerDockDividerVisibilityListener()")) {
+                "registerDockedStackListener()")) {
             return;
         }
         // TODO(multi-display): The listener is registered on the default display only.
-        final DockedStackDividerController controller =
-                getDefaultDisplayContentLocked().getDockedDividerController();
-        controller.registerDockDividerVisibilityListener(listener);
+        getDefaultDisplayContentLocked().mDividerControllerLocked.registerDockedStackListener(
+                listener);
+    }
+
+    @Override
+    public void requestAppKeyboardShortcuts(IResultReceiver receiver) {
         try {
-            listener.asBinder().linkToDeath(new IBinder.DeathRecipient() {
-                @Override
-                public void binderDied() {
-                    getDefaultDisplayContentLocked().getDockedDividerController()
-                            .registerDockDividerVisibilityListener(null);
-                }
-            }, 0);
+            getFocusedWindow().mClient.requestAppKeyboardShortcuts(receiver);
         } catch (RemoteException e) {
-            controller.registerDockDividerVisibilityListener(null);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index e4a6806..381173b 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -57,6 +57,7 @@
 import java.util.ArrayList;
 
 import static android.app.ActivityManager.StackId;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
@@ -74,6 +75,7 @@
 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
@@ -308,6 +310,12 @@
     // possible to draw.
     final Rect mOutsetFrame = new Rect();
 
+    /**
+     * Usually empty. Set to the task's tempInsetFrame. See
+     *{@link android.app.IActivityManager#resizeDockedStack}.
+     */
+    final Rect mInsetFrame = new Rect();
+
     boolean mContentChanged;
 
     // If a window showing a wallpaper: the requested offset for the
@@ -416,6 +424,8 @@
     // 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
@@ -603,10 +613,26 @@
         mHaveFrame = true;
 
         final Task task = getTask();
-        final boolean nonFullscreenTask = task != null && !task.isFullscreen();
+        final boolean fullscreenTask = task == null || task.isFullscreen();
         final boolean freeformWorkspace = task != null && task.inFreeformWorkspace();
-        if (nonFullscreenTask) {
+
+        if (fullscreenTask || (isChildWindow()
+                && (mAttrs.privateFlags & PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME) != 0)) {
+            // We use the parent frame as the containing frame for fullscreen and child windows
+            mContainingFrame.set(pf);
+            mDisplayFrame.set(df);
+            mInsetFrame.setEmpty();
+        } 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
+                // freeze the size.
+                Rect frozen = mAppToken.mFrozenBounds.peek();
+                mContainingFrame.right = mContainingFrame.left + frozen.width();
+                mContainingFrame.bottom = mContainingFrame.top + frozen.height();
+            }
             final WindowState imeWin = mService.mInputMethodWindow;
             if (imeWin != null && imeWin.isVisibleNow() && mService.mInputMethodTarget == this
                     && mContainingFrame.bottom > cf.bottom) {
@@ -623,9 +649,6 @@
                 }
             }
             mDisplayFrame.set(mContainingFrame);
-        } else {
-            mContainingFrame.set(pf);
-            mDisplayFrame.set(df);
         }
 
         final int pw = mContainingFrame.width();
@@ -668,6 +691,12 @@
             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()) {
@@ -701,44 +730,81 @@
                 // will return the correct value to the renderer.
                 mDisplayContent.getDockedDividerController().positionDockedStackedDivider(mFrame);
                 mContentFrame.set(mFrame);
+                if (!mFrame.equals(mLastFrame)) {
+                    mMovedByResize = true;
+                }
             }
         } else {
-            mContentFrame.set(Math.max(mContentFrame.left, mFrame.left),
-                    Math.max(mContentFrame.top, mFrame.top),
-                    Math.min(mContentFrame.right, mFrame.right),
-                    Math.min(mContentFrame.bottom, mFrame.bottom));
+            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));
 
-            mVisibleFrame.set(Math.max(mVisibleFrame.left, mFrame.left),
-                    Math.max(mVisibleFrame.top, mFrame.top),
-                    Math.min(mVisibleFrame.right, mFrame.right),
-                    Math.min(mVisibleFrame.bottom, mFrame.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));
 
-            mStableFrame.set(Math.max(mStableFrame.left, mFrame.left),
-                    Math.max(mStableFrame.top, mFrame.top),
-                    Math.min(mStableFrame.right, mFrame.right),
-                    Math.min(mStableFrame.bottom, mFrame.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));
         }
 
-        mOverscanInsets.set(Math.max(mOverscanFrame.left - mFrame.left, 0),
-                Math.max(mOverscanFrame.top - mFrame.top, 0),
-                Math.max(mFrame.right - mOverscanFrame.right, 0),
-                Math.max(mFrame.bottom - mOverscanFrame.bottom, 0));
+        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));
 
-        mContentInsets.set(mContentFrame.left - mFrame.left,
-                mContentFrame.top - mFrame.top,
-                mFrame.right - mContentFrame.right,
-                mFrame.bottom - mContentFrame.bottom);
 
-        mVisibleInsets.set(mVisibleFrame.left - mFrame.left,
-                mVisibleFrame.top - mFrame.top,
-                mFrame.right - mVisibleFrame.right,
-                mFrame.bottom - mVisibleFrame.bottom);
 
-        mStableInsets.set(Math.max(mStableFrame.left - mFrame.left, 0),
-                Math.max(mStableFrame.top - mFrame.top, 0),
-                Math.max(mFrame.right - mStableFrame.right, 0),
-                Math.max(mFrame.bottom - mStableFrame.bottom, 0));
+        if (mAttrs.type == TYPE_DOCK_DIVIDER) {
 
+            // For the docked divider, we calculate the stable insets like a full-screen window
+            // so it can use it to calculate the snap positions.
+            mStableInsets.set(Math.max(mStableFrame.left - mDisplayFrame.left, 0),
+                    Math.max(mStableFrame.top - mDisplayFrame.top, 0),
+                    Math.max(mDisplayFrame.right - mStableFrame.right, 0),
+                    Math.max(mDisplayFrame.bottom - mStableFrame.bottom, 0));
+
+            // The divider doesn't care about insets in any case, so set it to empty so we don't
+            // trigger a relayout when moving it.
+            mContentInsets.setEmpty();
+            mVisibleInsets.setEmpty();
+        } else {
+            mContentInsets.set(mContentFrame.left - frame.left,
+                    mContentFrame.top - frame.top,
+                    frame.right - mContentFrame.right,
+                    frame.bottom - mContentFrame.bottom);
+
+            mVisibleInsets.set(mVisibleFrame.left - frame.left,
+                    mVisibleFrame.top - frame.top,
+                    frame.right - mVisibleFrame.right,
+                    frame.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));
+        }
+
+        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;
+        }
         mCompatFrame.set(mFrame);
         if (mEnforceSizeCompat) {
             // If there is a size compatibility scale being applied to the
@@ -990,61 +1056,59 @@
     }
 
     /**
-     * Is this window visible?  It is not visible if there is no
-     * surface, or we are in the process of running an exit animation
-     * that will remove the surface, or its app token has been hidden.
+     * Does the minimal check for visibility. Callers generally want to use one of the public
+     * methods as they perform additional checks on the app token.
+     * TODO: See if there are other places we can use this check below instead of duplicating...
      */
-    @Override
-    public boolean isVisibleLw() {
-        final AppWindowToken atoken = mAppToken;
+    private boolean isVisibleUnchecked() {
         return mHasSurface && mPolicyVisibility && !mAttachedHidden
-                && (atoken == null || !atoken.hiddenRequested)
-                && !mExiting && !mDestroying;
+                && !mExiting && !mDestroying && (!mIsWallpaper || mWallpaperVisible);
     }
 
     /**
-     * Like {@link #isVisibleLw}, but also counts a window that is currently
-     * "hidden" behind the keyguard as visible.  This allows us to apply
-     * things like window flags that impact the keyguard.
-     * XXX I am starting to think we need to have ANOTHER visibility flag
-     * for this "hidden behind keyguard" state rather than overloading
-     * mPolicyVisibility.  Ungh.
+     * Is this window visible?  It is not visible if there is no surface, or we are in the process
+     * of running an exit animation that will remove the surface, or its app token has been hidden.
+     */
+    @Override
+    public boolean isVisibleLw() {
+        return (mAppToken == null || !mAppToken.hiddenRequested) && isVisibleUnchecked();
+    }
+
+    /**
+     * Like {@link #isVisibleLw}, but also counts a window that is currently "hidden" behind the
+     * keyguard as visible.  This allows us to apply things like window flags that impact the
+     * keyguard. XXX I am starting to think we need to have ANOTHER visibility flag for this
+     * "hidden behind keyguard" state rather than overloading mPolicyVisibility.  Ungh.
      */
     @Override
     public boolean isVisibleOrBehindKeyguardLw() {
-        if (mRootToken.waitingToShow &&
-                mService.mAppTransition.isTransitionSet()) {
+        if (mRootToken.waitingToShow && mService.mAppTransition.isTransitionSet()) {
             return false;
         }
         final AppWindowToken atoken = mAppToken;
         final boolean animating = atoken != null && atoken.mAppAnimator.animation != null;
         return mHasSurface && !mDestroying && !mExiting
                 && (atoken == null ? mPolicyVisibility : !atoken.hiddenRequested)
-                && ((!mAttachedHidden && mViewVisibility == View.VISIBLE
-                                && !mRootToken.hidden)
+                && ((!mAttachedHidden && mViewVisibility == View.VISIBLE && !mRootToken.hidden)
                         || mWinAnimator.mAnimation != null || animating);
     }
 
     /**
-     * Is this window visible, ignoring its app token?  It is not visible
-     * if there is no surface, or we are in the process of running an exit animation
-     * that will remove the surface.
+     * Is this window visible, ignoring its app token? It is not visible if there is no surface,
+     * or we are in the process of running an exit animation that will remove the surface.
      */
     public boolean isWinVisibleLw() {
-        final AppWindowToken atoken = mAppToken;
-        return mHasSurface && mPolicyVisibility && !mAttachedHidden
-                && (atoken == null || !atoken.hiddenRequested || atoken.mAppAnimator.animating)
-                && !mExiting && !mDestroying;
+        return (mAppToken == null || !mAppToken.hiddenRequested || mAppToken.mAppAnimator.animating)
+                && isVisibleUnchecked();
     }
 
     /**
-     * The same as isVisible(), but follows the current hidden state of
-     * the associated app token, not the pending requested hidden state.
+     * The same as isVisible(), but follows the current hidden state of the associated app token,
+     * not the pending requested hidden state.
      */
     boolean isVisibleNow() {
-        return mHasSurface && mPolicyVisibility && !mAttachedHidden
-                && (!mRootToken.hidden || mAttrs.type == TYPE_APPLICATION_STARTING)
-                && !mExiting && !mDestroying;
+        return (!mRootToken.hidden || mAttrs.type == TYPE_APPLICATION_STARTING)
+                && isVisibleUnchecked();
     }
 
     /**
@@ -1103,8 +1167,7 @@
             return false;
         }
         return mHasSurface && mPolicyVisibility && !mDestroying
-                && ((!mAttachedHidden && mViewVisibility == View.VISIBLE
-                                && !mRootToken.hidden)
+                && ((!mAttachedHidden && mViewVisibility == View.VISIBLE && !mRootToken.hidden)
                         || mWinAnimator.mAnimation != null
                         || ((mAppToken != null) && (mAppToken.mAppAnimator.animation != null)));
     }
@@ -1124,8 +1187,7 @@
             return false;
         }
         return mHasSurface && !mDestroying
-                && ((!mAttachedHidden && mViewVisibility == View.VISIBLE
-                                && !mRootToken.hidden)
+                && ((!mAttachedHidden && mViewVisibility == View.VISIBLE && !mRootToken.hidden)
                         || mWinAnimator.mAnimation != null
                         || ((atoken != null) && (atoken.mAppAnimator.animation != null)
                                 && !mWinAnimator.isDummyAnimation()));
@@ -1204,9 +1266,9 @@
      * sense to call from performLayoutAndPlaceSurfacesLockedInner().)
      */
     boolean hasMoved() {
-        return mHasSurface && mContentChanged && !mExiting && !mWinAnimator.mLastHidden
-                && mService.okToDisplay() && (mFrame.top != mLastFrame.top
-                        || mFrame.left != mLastFrame.left)
+        return mHasSurface && (mContentChanged || mMovedByResize)
+                && !mExiting && !mWinAnimator.mLastHidden && mService.okToDisplay()
+                && (mFrame.top != mLastFrame.top || mFrame.left != mLastFrame.left)
                 && (mAttachedWindow == null || !mAttachedWindow.hasMoved());
     }
 
@@ -1273,6 +1335,29 @@
         mHasSurface = hasSurface;
     }
 
+    int getAnimLayerAdjustment() {
+        if (mTargetAppToken != null) {
+            return mTargetAppToken.mAppAnimator.animLayerAdjustment;
+        } else if (mAppToken != null) {
+            return mAppToken.mAppAnimator.animLayerAdjustment;
+        } else {
+            // Nothing is animating, so there is no animation adjustment.
+            return 0;
+        }
+    }
+
+    void scheduleAnimationIfDimming() {
+        if (mDisplayContent == null) {
+            return;
+        }
+        final DimLayer.DimLayerUser dimLayerUser = getDimLayerUser();
+        if (dimLayerUser != null && mDisplayContent.mDimLayerController.isDimming(
+                dimLayerUser, mWinAnimator)) {
+            // Force an animation pass just to update the mDimLayer layer.
+            mService.scheduleAnimationLocked();
+        }
+    }
+
     private final class DeadWindowEventReceiver extends InputEventReceiver {
         DeadWindowEventReceiver(InputChannel inputChannel) {
             super(inputChannel, mService.mH.getLooper());
@@ -1380,15 +1465,22 @@
     }
 
     boolean inDockedWorkspace() {
-        Task task = getTask();
+        final Task task = getTask();
         return task != null && task.inDockedWorkspace();
     }
 
     boolean isDockedInEffect() {
-        Task task = getTask();
+        final Task task = getTask();
         return task != null && task.isDockedInEffect();
     }
 
+    void applyScrollIfNeeded() {
+        final Task task = getTask();
+        if (task != null) {
+            task.applyScrollToWindowIfNeeded(this);
+        }
+    }
+
     int getTouchableRegion(Region region, int flags) {
         final boolean modal = (flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0;
         if (modal && mAppToken != null) {
@@ -1524,17 +1616,33 @@
         }
     }
 
+    /**
+     * Returns true if this window is visible and belongs to a dead app and shouldn't be removed,
+     * because we want to preserve its location on screen to be re-activated later when the user
+     * interacts with it.
+     */
+    boolean shouldKeepVisibleDeadAppWindow() {
+        if (!isWinVisibleLw() || mAppToken == null || !mAppToken.appDied) {
+            // Not a visible app window or the app isn't dead.
+            return false;
+        }
+
+        if (mAttrs.type == TYPE_APPLICATION_STARTING) {
+            // We don't keep starting windows since they were added by the window manager before
+            // the app even launched.
+            return false;
+        }
+
+        final TaskStack stack = getStack();
+        return stack != null && StackId.keepVisibleDeadAppWindowOnScreen(stack.mStackId);
+    }
+
     /** @return true if this window desires key events. */
     boolean canReceiveKeys() {
         return isVisibleOrAdding()
                 && (mViewVisibility == View.VISIBLE)
                 && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0)
-                && stackCanReceiveKeys();
-    }
-
-    boolean stackCanReceiveKeys() {
-        final TaskStack stack = getStack();
-        return stack != null && StackId.canReceiveKeys(stack.mStackId);
+                && (mAppToken == null || mAppToken.windowsAreFocusable());
     }
 
     @Override
@@ -1682,45 +1790,69 @@
         return mAppToken != null && mAppToken.mAnimatingWithSavedSurface;
     }
 
-    // Returns true if the surface is saved.
-    boolean destroyOrSaveSurface() {
-        Task task = getTask();
+    private boolean shouldSaveSurface() {
         if (ActivityManager.isLowRamDeviceStatic()) {
             // Don't save surfaces on Svelte devices.
-            mSurfaceSaved = false;
-        } else if (task == null || task.inHomeStack()
-                || task.getTopVisibleAppToken() != mAppToken) {
+            return false;
+        }
+
+        if (isChildWindow()) {
+            return false;
+        }
+
+        Task task = getTask();
+        if (task == null || task.inHomeStack()) {
             // Don't save surfaces for home stack apps. These usually resume and draw
             // first frame very fast. Saving surfaces are mostly a waste of memory.
-            // Don't save if the window is not the topmost window.
-            mSurfaceSaved = false;
-        } else if (isChildWindow()) {
-            mSurfaceSaved = false;
-        } else {
-            mSurfaceSaved = mAppToken.shouldSaveSurface();
+            return false;
         }
-        if (mSurfaceSaved == false) {
+
+        final AppWindowToken taskTop = task.getTopVisibleAppToken();
+        if (taskTop != null && taskTop != mAppToken) {
+            // Don't save if the window is not the topmost window.
+            return false;
+        }
+
+        return mAppToken.shouldSaveSurface();
+    }
+
+    void destroyOrSaveSurface() {
+        mSurfaceSaved = shouldSaveSurface();
+        if (mSurfaceSaved) {
+            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
+                Slog.v(TAG, "Saving surface: " + this);
+            }
+
+            mWinAnimator.hide("saved surface");
+            mWinAnimator.mDrawState = WindowStateAnimator.NO_SURFACE;
+            setHasSurface(false);
+        } else {
             mWinAnimator.destroySurfaceLocked();
         }
-        return mSurfaceSaved;
     }
 
     public void destroySavedSurface() {
-        if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, "Destroying saved surface: " + this);
         if (mSurfaceSaved) {
+            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
+                Slog.v(TAG, "Destroying saved surface: " + this);
+            }
             mWinAnimator.destroySurfaceLocked();
         }
     }
 
+    public void restoreSavedSurface() {
+        mSurfaceSaved = false;
+        setHasSurface(true);
+        mWinAnimator.mDrawState = WindowStateAnimator.READY_TO_SHOW;
+        if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
+            Slog.v(TAG, "Restoring saved surface: " + this);
+        }
+    }
+
     public boolean hasSavedSurface() {
         return mSurfaceSaved;
     }
 
-    public void restoreSavedSurface() {
-        mSurfaceSaved = false;
-        mWinAnimator.mDrawState = WindowStateAnimator.READY_TO_SHOW;
-    }
-
     @Override
     public boolean isDefaultDisplay() {
         final DisplayContent displayContent = getDisplayContent();
@@ -1913,11 +2045,7 @@
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
 
-    private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
-            Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
-            Configuration newConfig) throws RemoteException {
-        DisplayInfo displayInfo = getDisplayInfo();
-        mTmpRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
+    Rect getBackdropFrame(Rect frame) {
         // When the task is docked, we send fullscreen sized backDropFrame as soon as resizing
         // start even if we haven't received the relayout window, so that the client requests
         // the relayout sooner. When dragging stops, backDropFrame needs to stay fullscreen
@@ -1925,9 +2053,28 @@
         // one or more frame to wrong offset. So here we send fullscreen backdrop if either
         // isDragResizing() or isDragResizeChanged() is true.
         boolean resizing = isDragResizing() || isDragResizeChanged();
-        final Rect backDropFrame = (inFreeformWorkspace() || !resizing) ? frame : mTmpRect;
-        mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets,
-                outsets, reportDraw, newConfig, backDropFrame);
+        if (StackId.useWindowFrameForBackdrop(getStackId()) || !resizing) {
+            return frame;
+        }
+        DisplayInfo displayInfo = getDisplayInfo();
+        mTmpRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
+        return mTmpRect;
+    }
+
+    private int getStackId() {
+        final TaskStack stack = getStack();
+        if (stack == null) {
+            return INVALID_STACK_ID;
+        }
+        return stack.mStackId;
+    }
+
+    private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
+            Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
+            Configuration newConfig) throws RemoteException {
+        mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets,
+                reportDraw, newConfig, getBackdropFrame(frame),
+                isDragResizeChanged() /* forceRelayout */);
     }
 
     public void registerFocusObserver(IWindowFocusObserver observer) {
@@ -1974,7 +2121,13 @@
         if (task.isDragResizing()) {
             return true;
         }
-        return mDisplayContent.mDividerControllerLocked.isResizing() &&
+
+        // If the bounds are currently frozen, it means that the layout size that the app sees
+        // and the bounds we clip this window to might be different. In order to avoid holes, we
+        // simulate that we are still resizing so the app fills the hole with the resizing
+        // background.
+        return (mDisplayContent.mDividerControllerLocked.isResizing()
+                        || mAppToken != null && !mAppToken.mFrozenBounds.isEmpty()) &&
                 !task.inFreeformWorkspace() && !task.isFullscreen();
     }
 
@@ -2085,7 +2238,8 @@
         }
         pw.print(prefix); pw.print("mHasSurface="); pw.print(mHasSurface);
                 pw.print(" mShownPosition="); mShownPosition.printShortString(pw);
-                pw.print(" isReadyForDisplay()="); pw.println(isReadyForDisplay());
+                pw.print(" isReadyForDisplay()="); pw.print(isReadyForDisplay());
+                pw.print(" hasSavedSurface()="); pw.println(hasSavedSurface());
         if (dumpAll) {
             pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw);
                     pw.print(" last="); mLastFrame.printShortString(pw);
@@ -2196,10 +2350,12 @@
 
     void transformFromScreenToSurfaceSpace(Rect rect) {
          if (mHScale >= 0) {
-            rect.right = rect.left + (int)((rect.right - rect.left) / mHScale);
+            rect.left = (int) (rect.left / mHScale);
+            rect.right = (int) (rect.right / mHScale);
         }
         if (mVScale >= 0) {
-            rect.bottom = rect.top + (int)((rect.bottom - rect.top) / mVScale);
+            rect.top = (int) (rect.top / mVScale);
+            rect.bottom = (int) (rect.bottom / mVScale);
         }
     }
 
@@ -2253,7 +2409,7 @@
         }
 
         if (nonFullscreenTask) {
-            // Make sure window fits in containing frame since it is in a non-fullscreen stack as
+            // 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);
             h = Math.min(h, ph);
@@ -2273,10 +2429,21 @@
     }
 
     void setReplacing(boolean animate) {
-        if ((mAttrs.privateFlags & PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH) == 0) {
-            mWillReplaceWindow = true;
-            mReplacingWindow = null;
-            mAnimateReplacingWindow = animate;
+        if ((mAttrs.privateFlags & PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH) != 0
+                || mAttrs.type == TYPE_APPLICATION_STARTING) {
+            // We don't set replacing on starting windows since they are added by window manager and
+            // not the client so won't be replaced by the client.
+            return;
         }
+
+        mWillReplaceWindow = true;
+        mReplacingWindow = null;
+        mAnimateReplacingWindow = animate;
+    }
+
+    void resetReplacing() {
+        mWillReplaceWindow = false;
+        mReplacingWindow = null;
+        mAnimateReplacingWindow = false;
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index d4001cd..428ab7a 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -29,7 +29,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_CROP;
-import static com.android.server.wm.WindowManagerDebugConfig.HIDE_STACK_CRAWLS;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
@@ -37,6 +37,8 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 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;
@@ -384,12 +386,8 @@
         if (mAnimator.mWindowDetachedWallpaper == mWin) {
             mAnimator.mWindowDetachedWallpaper = null;
         }
-        mAnimLayer = mWin.mLayer;
-        if (mWin.mIsImWindow) {
-            mAnimLayer += mService.mInputMethodAnimLayerAdjustment;
-        } else if (mIsWallpaper) {
-            mAnimLayer += mWallpaperControllerLocked.getAnimLayerAdjustment();
-        }
+        mAnimLayer = mWin.mLayer
+                + mService.mLayersController.getSpecialWindowAnimLayerAdjustment(mWin);
         if (DEBUG_LAYERS) Slog.v(TAG, "Stepping win " + this + " anim layer: " + mAnimLayer);
         mHasTransformation = false;
         mHasLocalTransformation = false;
@@ -470,7 +468,7 @@
         if (WindowManagerService.localLOGV) Slog.v(
                 TAG, "Exit animation finished in " + this
                 + ": remove=" + mWin.mRemoveOnExit);
-        if (mSurfaceController != null && mSurfaceController.hasSurface()) {
+        if (hasSurface()) {
             mService.mDestroySurface.add(mWin);
             mWin.mDestroying = true;
             hide("finishExit");
@@ -550,7 +548,7 @@
         if (mDestroyPreservedSurfaceUponRedraw) {
             return;
         }
-        if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin, "SET FREEZE LAYER", null);
+        if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin, "SET FREEZE LAYER", false);
         if (mSurfaceController != null) {
             mSurfaceController.setLayer(mAnimLayer + 1);
         }
@@ -569,6 +567,10 @@
 
     WindowSurfaceController createSurfaceLocked() {
         final WindowState w = mWin;
+        if (w.hasSavedSurface()) {
+            Slog.i(TAG, "***** createSurface: " + this + ": called when we had a saved surface");
+        }
+
         if (mSurfaceController == null) {
             if (DEBUG_ANIM || DEBUG_ORIENTATION) Slog.i(TAG,
                     "createSurface " + this + ": mDrawState=DRAW_PENDING");
@@ -668,13 +670,13 @@
                 Slog.i(TAG, ">>> OPEN TRANSACTION createSurfaceLocked");
                 WindowManagerService.logSurface(w, "CREATE pos=("
                         + w.mFrame.left + "," + w.mFrame.top + ") ("
-                        + width + "x" + height + "), layer=" + mAnimLayer + " HIDE", null);
+                        + width + "x" + height + "), layer=" + mAnimLayer + " HIDE", false);
             }
 
             // 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, null);
+                    "POS " + mTmpSize.left + ", " + mTmpSize.top, false);
             mSurfaceController.setPositionAndLayer(mTmpSize.left, mTmpSize.top, layerStack,
                     mAnimLayer);
             mLastHidden = true;
@@ -709,14 +711,12 @@
         }
 
         // Something is wrong and SurfaceFlinger will not like this, try to revert to sane values.
+        // This doesn't necessarily mean that there is an error in the system. The sizes might be
+        // incorrect, because it is before the first layout or draw.
         if (mTmpSize.width() < 1) {
-            if (!mWin.mLayoutNeeded) Slog.w(TAG,
-                    "Width of " + w + " is not positive " + mTmpSize.width());
             mTmpSize.right = mTmpSize.left + 1;
         }
         if (mTmpSize.height() < 1) {
-            if (!mWin.mLayoutNeeded) Slog.w(TAG,
-                    "Height of " + w + " is not positive " + mTmpSize.height());
             mTmpSize.bottom = mTmpSize.top + 1;
         }
 
@@ -738,6 +738,11 @@
         mTmpSize.bottom += scale * (attrs.surfaceInsets.top + attrs.surfaceInsets.bottom);
     }
 
+    boolean hasSurface() {
+        return !mWin.mSurfaceSaved
+                && mSurfaceController != null && mSurfaceController.hasSurface();
+    }
+
     void destroySurfaceLocked() {
         final AppWindowToken wtoken = mWin.mAppToken;
         if (wtoken != null) {
@@ -763,25 +768,13 @@
             }
 
             try {
-                if (DEBUG_VISIBILITY) {
-                    RuntimeException e = null;
-                    if (!HIDE_STACK_CRAWLS) {
-                        e = new RuntimeException();
-                        e.fillInStackTrace();
-                    }
-                    Slog.w(TAG, "Window " + this + " destroying surface "
-                            + mSurfaceController + ", session " + mSession, e);
-                }
+                if (DEBUG_VISIBILITY) logWithStack(TAG, "Window " + this + " destroying surface "
+                        + mSurfaceController + ", session " + mSession);
                 if (mSurfaceDestroyDeferred) {
                     if (mSurfaceController != null && mPendingDestroySurface != mSurfaceController) {
                         if (mPendingDestroySurface != null) {
                             if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
-                                RuntimeException e = null;
-                                if (!HIDE_STACK_CRAWLS) {
-                                    e = new RuntimeException();
-                                    e.fillInStackTrace();
-                                }
-                                WindowManagerService.logSurface(mWin, "DESTROY PENDING", e);
+                                WindowManagerService.logSurface(mWin, "DESTROY PENDING", true);
                             }
                             mPendingDestroySurface.destroyInTransaction();
                         }
@@ -789,12 +782,7 @@
                     }
                 } else {
                     if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
-                        RuntimeException e = null;
-                        if (!HIDE_STACK_CRAWLS) {
-                            e = new RuntimeException();
-                            e.fillInStackTrace();
-                        }
-                        WindowManagerService.logSurface(mWin, "DESTROY", null);
+                        WindowManagerService.logSurface(mWin, "DESTROY", true);
                     }
                     destroySurface();
                 }
@@ -825,12 +813,7 @@
         try {
             if (mPendingDestroySurface != null) {
                 if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
-                    RuntimeException e = null;
-                    if (!HIDE_STACK_CRAWLS) {
-                        e = new RuntimeException();
-                        e.fillInStackTrace();
-                    }
-                    WindowManagerService.logSurface(mWin, "DESTROY PENDING", e);
+                    WindowManagerService.logSurface(mWin, "DESTROY PENDING", true);
                 }
                 mPendingDestroySurface.destroyInTransaction();
                 // Don't hide wallpaper if we're destroying a deferred surface
@@ -1069,7 +1052,16 @@
         final int top = w.mYOffset + w.mFrame.top;
 
         // Initialize the decor rect to the entire frame.
-        mSystemDecorRect.set(0, 0, width, height);
+        if (w.isDragResizing() && w.getResizeMode() == DRAG_RESIZE_MODE_DOCKED_DIVIDER) {
+
+            // If we are resizing with the divider, the task bounds might be smaller than the
+            // stack bounds. The system decor is used to clip to the task bounds, which we don't
+            // want in this case in order to avoid holes.
+            final DisplayInfo displayInfo = w.getDisplayContent().getDisplayInfo();
+            mSystemDecorRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
+        } else {
+            mSystemDecorRect.set(0, 0, width, height);
+        }
 
         // If a freeform window is animating from a position where it would be cutoff, it would be
         // cutoff during the animation. We don't want that, so for the duration of the animation
@@ -1188,11 +1180,14 @@
         // 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()
+        if (isAnimating() && (w.mWillReplaceWindow
+                || (w.inDockedWorkspace() && task.isResizeable())
                 || w.inFreeformWorkspace())) {
             return;
         }
@@ -1243,7 +1238,7 @@
 
     void prepareSurfaceLocked(final boolean recoveringMemory) {
         final WindowState w = mWin;
-        if (mSurfaceController == null || !mSurfaceController.hasSurface()) {
+        if (!hasSurface()) {
             if (w.mOrientationChanging) {
                 if (DEBUG_ORIENTATION) {
                     Slog.v(TAG, "Orientation change skips hidden " + w);
@@ -1301,7 +1296,7 @@
                     + " matrix=[" + mDsDx + "*" + w.mHScale
                     + "," + mDtDx + "*" + w.mVScale
                     + "][" + mDsDy + "*" + w.mHScale
-                    + "," + mDtDy + "*" + w.mVScale + "]", null);
+                    + "," + mDtDy + "*" + w.mVScale + "]", false);
 
             boolean prepared =
                 mSurfaceController.prepareToShowInTransaction(mShownAlpha, mAnimLayer,
@@ -1325,7 +1320,7 @@
                     w.mOrientationChanging = false;
                 }
             }
-            if (mSurfaceController != null && mSurfaceController.hasSurface()) {
+            if (hasSurface()) {
                 w.mToken.hasVisible = true;
             }
         } else {
@@ -1348,6 +1343,11 @@
                 }
             }
             w.mToken.hasVisible = true;
+
+            final Task task = w.getTask();
+            if (task != null) {
+                task.scheduleShowNonResizeableDockToastIfNeeded();
+            }
         }
     }
 
@@ -1506,10 +1506,6 @@
                 mWin.mAppToken.updateReportedVisibilityLocked();
             }
 
-            final Task task = mWin.getTask();
-            if (task != null) {
-                task.scheduleShowNonResizeableDockToastIfNeeded();
-            }
             return true;
         }
         return false;
@@ -1612,14 +1608,7 @@
                     + " transit=" + transit
                     + " isEntrance=" + isEntrance + " Callers " + Debug.getCallers(3));
             if (a != null) {
-                if (DEBUG_ANIM) {
-                    RuntimeException e = null;
-                    if (!HIDE_STACK_CRAWLS) {
-                        e = new RuntimeException();
-                        e.fillInStackTrace();
-                    }
-                    Slog.v(TAG, "Loaded animation " + a + " for " + this, e);
-                }
+                if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + this);
                 setAnimation(a);
                 mAnimationIsEntrance = isEntrance;
             }
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 9675d2f..5674ca2 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -18,9 +18,7 @@
 
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
-import static com.android.server.wm.WindowManagerDebugConfig.HIDE_STACK_CRAWLS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 160c97f..761d6e9 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -27,6 +27,7 @@
 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;
@@ -67,6 +68,7 @@
  * surfaces according to these frames. Z layer is still assigned withing WindowManagerService.
  */
 class WindowSurfacePlacer {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowSurfacePlacer" : TAG_WM;
     private final WindowManagerService mService;
     private final WallpaperController mWallpaperControllerLocked;
 
@@ -160,7 +162,7 @@
             if (DEBUG) {
                 throw new RuntimeException("Recursive call!");
             }
-            Slog.w(TAG_WM, "performLayoutAndPlaceSurfacesLocked called while in layout. Callers="
+            Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout. Callers="
                     + Debug.getCallers(3));
             return;
         }
@@ -186,11 +188,10 @@
             // Wait a little bit for things to settle down, and off we go.
             while (!mService.mForceRemoves.isEmpty()) {
                 WindowState ws = mService.mForceRemoves.remove(0);
-                Slog.i(TAG_WM, "Force removing: " + ws);
+                Slog.i(TAG, "Force removing: " + ws);
                 mService.removeWindowInnerLocked(ws);
             }
-            Slog.w(TAG_WM,
-                    "Due to memory failure, waiting a bit for next layout");
+            Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
             Object tmp = new Object();
             synchronized (tmp) {
                 try {
@@ -209,7 +210,7 @@
                 if (++mLayoutRepeatCount < 6) {
                     requestTraversal();
                 } else {
-                    Slog.e(TAG_WM, "Performed 6 layouts in a row. Skipping");
+                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
                     mLayoutRepeatCount = 0;
                 }
             } else {
@@ -222,7 +223,7 @@
             }
         } catch (RuntimeException e) {
             mInLayout = false;
-            Slog.wtf(TAG_WM, "Unhandled exception while laying out windows", e);
+            Slog.wtf(TAG, "Unhandled exception while laying out windows", e);
         }
 
         Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
@@ -230,18 +231,15 @@
 
     void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
         if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
-            Slog.v(TAG_WM, "Layouts looping: " + msg +
+            Slog.v(TAG, "Layouts looping: " + msg +
                     ", mPendingLayoutChanges = 0x" + Integer.toHexString(pendingLayoutChanges));
         }
     }
 
     // "Something has changed!  Let's make it correct now."
     private void performSurfacePlacementInner(boolean recoveringMemory) {
-        if (DEBUG_WINDOW_TRACE) {
-            Slog.v(TAG_WM,
-                    "performSurfacePlacementInner: entry. Called by "
-                    + Debug.getCallers(3));
-        }
+        if (DEBUG_WINDOW_TRACE) Slog.v(TAG, "performSurfacePlacementInner: entry. Called by "
+                + Debug.getCallers(3));
 
         int i;
         boolean updateInputWindowsNeeded = false;
@@ -283,16 +281,16 @@
         final int defaultDw = defaultInfo.logicalWidth;
         final int defaultDh = defaultInfo.logicalHeight;
 
-        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
+        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                 ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
         SurfaceControl.openTransaction();
         try {
             applySurfaceChangesTransaction(recoveringMemory, numDisplays, defaultDw, defaultDh);
         } catch (RuntimeException e) {
-            Slog.wtf(TAG_WM, "Unhandled exception in Window Manager", e);
+            Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
         } finally {
             SurfaceControl.closeTransaction();
-            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
+            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                     "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
         }
 
@@ -339,7 +337,7 @@
 
         if (mWallpaperMayChange) {
             if (DEBUG_WALLPAPER_LIGHT)
-                Slog.v(TAG_WM, "Wallpaper may change!  Adjusting");
+                Slog.v(TAG, "Wallpaper may change!  Adjusting");
             defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
             if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("WallpaperMayChange",
                     defaultDisplay.pendingLayoutChanges);
@@ -374,10 +372,8 @@
             mService.mResizingWindows.remove(i);
         }
 
-        if (DEBUG_ORIENTATION && mService.mDisplayFrozen)
-            Slog.v(TAG_WM,
-                "With display frozen, orientationChangeComplete="
-                + mOrientationChangeComplete);
+        if (DEBUG_ORIENTATION && mService.mDisplayFrozen) Slog.v(TAG,
+                "With display frozen, orientationChangeComplete=" + mOrientationChangeComplete);
         if (mOrientationChangeComplete) {
             if (mService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
                 mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
@@ -435,9 +431,8 @@
                     // soon as their animations are complete
                     token.mAppAnimator.clearAnimation();
                     token.mAppAnimator.animating = false;
-                    if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT)
-                        Slog.v(TAG_WM,
-                                "performLayout: App token exiting now removed" + token);
+                    if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
+                            "performLayout: App token exiting now removed" + token);
                     token.removeAppFromTaskLocked();
                 }
             }
@@ -482,7 +477,7 @@
                     || Settings.Global.getInt(mService.mContext.getContentResolver(),
                         Settings.Global.THEATER_MODE_ON, 0) == 0) {
                 if (DEBUG_VISIBILITY || DEBUG_POWER) {
-                    Slog.v(TAG_WM, "Turning screen on after layout!");
+                    Slog.v(TAG, "Turning screen on after layout!");
                 }
                 mService.mPowerManager.wakeUp(SystemClock.uptimeMillis(),
                         "android.server.wm:TURN_ON");
@@ -491,8 +486,7 @@
         }
 
         if (mUpdateRotation) {
-            if (DEBUG_ORIENTATION) Slog.d(TAG_WM,
-                    "Performing post-rotate rotation");
+            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
             if (mService.updateRotationUncheckedLocked(false)) {
                 mService.mH.sendEmptyMessage(SEND_NEW_CONFIGURATION);
             } else {
@@ -524,7 +518,7 @@
             }
 
             for (DisplayContent displayContent : displayList) {
-                mService.assignLayersLocked(displayContent.getWindowList());
+                mService.mLayersController.assignLayersLocked(displayContent.getWindowList());
                 displayContent.layoutNeeded = true;
             }
         }
@@ -545,7 +539,7 @@
 
         mService.scheduleAnimationLocked();
 
-        if (DEBUG_WINDOW_TRACE) Slog.e(TAG_WM,
+        if (DEBUG_WINDOW_TRACE) Slog.e(TAG,
                 "performSurfacePlacementInner exit: animating=" + mService.mAnimator.isAnimating());
     }
 
@@ -589,7 +583,7 @@
             do {
                 repeats++;
                 if (repeats > 6) {
-                    Slog.w(TAG_WM, "Animation repeat aborted after too many iterations");
+                    Slog.w(TAG, "Animation repeat aborted after too many iterations");
                     displayContent.layoutNeeded = false;
                     break;
                 }
@@ -599,13 +593,13 @@
 
                 if ((displayContent.pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0 &&
                         mWallpaperControllerLocked.adjustWallpaperWindows()) {
-                    mService.assignLayersLocked(windows);
+                    mService.mLayersController.assignLayersLocked(windows);
                     displayContent.layoutNeeded = true;
                 }
 
                 if (isDefaultDisplay
                         && (displayContent.pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) {
-                    if (DEBUG_LAYOUT) Slog.v(TAG_WM, "Computing new config from layout");
+                    if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
                     if (mService.updateOrientationFromAppTokensLocked(true)) {
                         displayContent.layoutNeeded = true;
                         mService.mH.sendEmptyMessage(SEND_NEW_CONFIGURATION);
@@ -621,7 +615,7 @@
                     performLayoutLockedInner(displayContent, repeats == 1,
                             false /* updateInputWindows */);
                 } else {
-                    Slog.w(TAG_WM, "Layout repeat skipped after too many iterations");
+                    Slog.w(TAG, "Layout repeat skipped after too many iterations");
                 }
 
                 // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
@@ -707,8 +701,9 @@
                     }
                 }
 
-                //Slog.i(TAG_WM, "Window " + this + " clearing mContentChanged - done placing");
+                //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
                 w.mContentChanged = false;
+                w.mMovedByResize = false;
 
                 // Moved from updateWindowsAndWallpaperLocked().
                 if (w.mHasSurface) {
@@ -729,7 +724,7 @@
                         }
                         if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
                             if (DEBUG_WALLPAPER_LIGHT)
-                                Slog.v(TAG_WM, "First draw done in potential wallpaper target " + w);
+                                Slog.v(TAG, "First draw done in potential wallpaper target " + w);
                             mWallpaperMayChange = true;
                             displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                             if (DEBUG_LAYOUT_REPEATS) {
@@ -738,19 +733,21 @@
                             }
                         }
                     }
-                    /*
-                     * Updates the shown frame before we set up the surface. This is needed because
-                     * the resizing could change the top-left position (in addition to size) of the
-                     * window. setSurfaceBoundariesLocked uses mShownPosition to position the
-                      * surface.
-                     */
-                    winAnimator.computeShownFrameLocked();
+                    if (!winAnimator.isAnimating()) {
+                        // Updates the shown frame before we set up the surface. This is needed
+                        // because the resizing could change the top-left position (in addition to
+                        // size) of the window. setSurfaceBoundariesLocked uses mShownPosition to
+                        // position the surface. We only apply it to windows that aren't animating,
+                        // because we depend on the animation to calculate the correct shown frame
+                        // on the next animation step.
+                        winAnimator.computeShownFrameLocked();
+                    }
                     winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
                 }
 
                 final AppWindowToken atoken = w.mAppToken;
                 if (DEBUG_STARTING_WINDOW && atoken != null && w == atoken.startingWindow) {
-                    Slog.d(TAG_WM, "updateWindows: starting " + w
+                    Slog.d(TAG, "updateWindows: starting " + w
                             + " isOnScreen=" + w.isOnScreen() + " allDrawn=" + atoken.allDrawn
                             + " freezingScreen=" + atoken.mAppAnimator.freezingScreen);
                 }
@@ -764,11 +761,11 @@
                             || winAnimator.mAttrType == TYPE_BASE_APPLICATION)
                             && !w.mExiting && !w.mDestroying) {
                         if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
-                            Slog.v(TAG_WM, "Eval win " + w + ": isDrawn="
+                            Slog.v(TAG, "Eval win " + w + ": isDrawn="
                                     + w.isDrawnLw()
                                     + ", isAnimating=" + winAnimator.isAnimating());
                             if (!w.isDrawnLw()) {
-                                Slog.v(TAG_WM, "Not displayed: s="
+                                Slog.v(TAG, "Not displayed: s="
                                         + winAnimator.mSurfaceController
                                         + " pv=" + w.mPolicyVisibility
                                         + " mDrawState=" + winAnimator.drawStateToString()
@@ -783,7 +780,7 @@
                                 if (w.isDrawnLw()) {
                                     atoken.numDrawnWindows++;
                                     if (DEBUG_VISIBILITY || DEBUG_ORIENTATION)
-                                        Slog.v(TAG_WM, "tokenMayBeDrawn: " + atoken
+                                        Slog.v(TAG, "tokenMayBeDrawn: " + atoken
                                                 + " freezingScreen="
                                                 + atoken.mAppAnimator.freezingScreen
                                                 + " mAppFreezing=" + w.mAppFreezing);
@@ -851,12 +848,13 @@
         int i;
 
         if (DEBUG_LAYOUT) {
-            Slog.v(TAG_WM, "-------------------------------------");
-            Slog.v(TAG_WM, "performLayout: needed="
+            Slog.v(TAG, "-------------------------------------");
+            Slog.v(TAG, "performLayout: needed="
                     + displayContent.layoutNeeded + " dw=" + dw + " dh=" + dh);
         }
 
-        mService.mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mService.mRotation);
+        mService.mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mService.mRotation,
+                mService.mCurConfiguration.uiMode);
         if (isDefaultDisplay) {
             // Not needed on non-default displays.
             mService.mSystemDecorLayer = mService.mPolicy.getSystemDecorLayerLw();
@@ -885,18 +883,18 @@
                     || win.isGoneForLayoutLw();
 
             if (DEBUG_LAYOUT && !win.mLayoutAttached) {
-                Slog.v(TAG_WM, "1ST PASS " + win
+                Slog.v(TAG, "1ST PASS " + win
                         + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
                         + " mLayoutAttached=" + win.mLayoutAttached
                         + " screen changed=" + win.isConfigChanged());
                 final AppWindowToken atoken = win.mAppToken;
-                if (gone) Slog.v(TAG_WM, "  GONE: mViewVisibility="
+                if (gone) Slog.v(TAG, "  GONE: mViewVisibility="
                         + win.mViewVisibility + " mRelayoutCalled="
                         + win.mRelayoutCalled + " hidden="
                         + win.mRootToken.hidden + " hiddenRequested="
                         + (atoken != null && atoken.hiddenRequested)
                         + " mAttachedHidden=" + win.mAttachedHidden);
-                else Slog.v(TAG_WM, "  VIS: mViewVisibility="
+                else Slog.v(TAG, "  VIS: mViewVisibility="
                         + win.mViewVisibility + " mRelayoutCalled="
                         + win.mRelayoutCalled + " hidden="
                         + win.mRootToken.hidden + " hiddenRequested="
@@ -916,7 +914,7 @@
                             win.mAppToken.layoutConfigChanges)))) {
                 if (!win.mLayoutAttached) {
                     if (initial) {
-                        //Slog.i(TAG_WM, "Window " + this + " clearing mContentChanged - initial");
+                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
                         win.mContentChanged = false;
                     }
                     if (win.mAttrs.type == TYPE_DREAM) {
@@ -936,7 +934,7 @@
                         displayContent.mDimLayerController.updateDimLayer(task);
                     }
 
-                    if (DEBUG_LAYOUT) Slog.v(TAG_WM,
+                    if (DEBUG_LAYOUT) Slog.v(TAG,
                             "  LAYOUT: mFrame="
                             + win.mFrame + " mContainingFrame="
                             + win.mContainingFrame + " mDisplayFrame="
@@ -957,7 +955,7 @@
             final WindowState win = windows.get(i);
 
             if (win.mLayoutAttached) {
-                if (DEBUG_LAYOUT) Slog.v(TAG_WM,
+                if (DEBUG_LAYOUT) Slog.v(TAG,
                         "2ND PASS " + win + " mHaveFrame=" + win.mHaveFrame + " mViewVisibility="
                         + win.mViewVisibility + " mRelayoutCalled=" + win.mRelayoutCalled);
                 // If this view is GONE, then skip it -- keep the current
@@ -971,14 +969,14 @@
                 if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
                         || !win.mHaveFrame || win.mLayoutNeeded) {
                     if (initial) {
-                        //Slog.i(TAG_WM, "Window " + this + " clearing mContentChanged - initial");
+                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
                         win.mContentChanged = false;
                     }
                     win.mLayoutNeeded = false;
                     win.prelayout();
                     mService.mPolicy.layoutWindowLw(win, win.mAttachedWindow);
                     win.mLayoutSeq = seq;
-                    if (DEBUG_LAYOUT) Slog.v(TAG_WM,
+                    if (DEBUG_LAYOUT) Slog.v(TAG,
                             "  LAYOUT: mFrame=" + win.mFrame + " mContainingFrame="
                             + win.mContainingFrame + " mDisplayFrame=" + win.mDisplayFrame);
                 }
@@ -1009,7 +1007,7 @@
         if (!transitionGoodToGo(appsCount)) {
             return 0;
         }
-        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "**** GOOD TO GO");
+        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
         int transit = mService.mAppTransition.getAppTransition();
         if (mService.mSkipAppTransitionAnimation) {
             transit = AppTransition.TRANSIT_UNSET;
@@ -1101,7 +1099,7 @@
         // example, when this transition is being done behind
         // the lock screen.
         if (!mService.mPolicy.allowAppAnimationsLw()) {
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
                     "Animations disallowed by keyguard or dream.");
             animLp = null;
         }
@@ -1134,7 +1132,7 @@
         // TODO(multidisplay): IMEs are only supported on the default display.
         if (windows == mService.getDefaultWindowListLocked()
                 && !mService.moveInputMethodWindowsIfNeededLocked(true)) {
-            mService.assignLayersLocked(windows);
+            mService.mLayersController.assignLayersLocked(windows);
         }
         mService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
                 true /*updateInputWindows*/);
@@ -1150,13 +1148,16 @@
         for (int i = 0; i < appsCount; i++) {
             AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
             final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Now opening app" + wtoken);
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
 
             if (!appAnimator.usingTransferredAnimation) {
                 appAnimator.clearThumbnail();
                 appAnimator.animation = null;
             }
             wtoken.inPendingTransaction = false;
+
+            wtoken.restoreSavedSurfaces();
+
             if (!mService.setTokenVisibilityLocked(
                     wtoken, animLp, true, transit, false, voiceInteraction)){
                 // This token isn't going to be animating. Add it to the list of tokens to
@@ -1172,14 +1173,14 @@
             for (int j = 0; j < windowsCount; j++) {
                 appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
             }
-            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
+            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                     ">>> OPEN TRANSACTION handleAppTransitionReadyLocked()");
             SurfaceControl.openTransaction();
             try {
                 mService.mAnimator.orAnimating(appAnimator.showAllWindowsLocked());
             } finally {
                 SurfaceControl.closeTransaction();
-                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
+                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                         "<<< CLOSE TRANSACTION handleAppTransitionReadyLocked()");
             }
             mService.mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
@@ -1193,7 +1194,12 @@
                     // if app window is removed, or window relayout to invisible. We don't want to
                     // clear it out for windows that get replaced, because the animation depends on
                     // the flag to remove the replaced window.
-                    if (!win.mWillReplaceWindow) {
+                    //
+                    // We also don't clear the mExiting flag for windows which have the
+                    // mRemoveOnExit flag. This indicates an explicit remove request has been issued
+                    // by the client. We should let animation proceed and not clear this flag or
+                    // they won't eventually be removed by WindowStateAnimator#finishExit.
+                    if (!win.mWillReplaceWindow && !win.mRemoveOnExit) {
                         win.mExiting = false;
                     }
                     if (win.mWinAnimator.mAnimLayer > layer) {
@@ -1208,8 +1214,6 @@
             if (mService.mAppTransition.isNextAppTransitionThumbnailUp()) {
                 createThumbnailAppAnimator(transit, wtoken, topOpeningLayer, topClosingLayer);
             }
-
-            wtoken.restoreSavedSurfaces();
         }
         return topOpeningApp;
     }
@@ -1221,7 +1225,7 @@
         for (int i = 0; i < appsCount; i++) {
             AppWindowToken wtoken = mService.mClosingApps.valueAt(i);
             final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Now closing app " + wtoken);
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
             appAnimator.clearThumbnail();
             appAnimator.animation = null;
             wtoken.inPendingTransaction = false;
@@ -1260,14 +1264,14 @@
     }
 
     private boolean transitionGoodToGo(int appsCount) {
-        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
+        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
                 "Checking " + appsCount + " opening apps (frozen="
                         + mService.mDisplayFrozen + " timeout="
                         + mService.mAppTransition.isTimeout() + ")...");
         if (!mService.mAppTransition.isTimeout()) {
             for (int i = 0; i < appsCount; i++) {
                 AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
-                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
+                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
                         "Check opening app=" + wtoken + ": allDrawn="
                         + wtoken.allDrawn + " startingDisplayed="
                         + wtoken.startingDisplayed + " startingMoved="
@@ -1283,7 +1287,7 @@
 
             // We also need to wait for the specs to be fetched, if needed.
             if (mService.mAppTransition.isFetchingAppTransitionsSpecs()) {
-                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "isFetchingAppTransitionSpecs=true");
+                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "isFetchingAppTransitionSpecs=true");
                 return false;
             }
 
@@ -1304,7 +1308,7 @@
                         ? null : wallpaperTarget;
         final ArraySet<AppWindowToken> openingApps = mService.mOpeningApps;
         final ArraySet<AppWindowToken> closingApps = mService.mClosingApps;
-        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
+        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
                 "New wallpaper target=" + wallpaperTarget
                         + ", oldWallpaper=" + oldWallpaper
                         + ", lower target=" + lowerWallpaperTarget
@@ -1314,7 +1318,7 @@
         mService.mAnimateWallpaperWithTarget = false;
         if (closingAppHasWallpaper && openingAppHasWallpaper) {
             if (DEBUG_APP_TRANSITIONS)
-                Slog.v(TAG_WM, "Wallpaper animation!");
+                Slog.v(TAG, "Wallpaper animation!");
             switch (transit) {
                 case AppTransition.TRANSIT_ACTIVITY_OPEN:
                 case AppTransition.TRANSIT_TASK_OPEN:
@@ -1327,14 +1331,14 @@
                     transit = AppTransition.TRANSIT_WALLPAPER_INTRA_CLOSE;
                     break;
             }
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
                     "New transit: " + AppTransition.appTransitionToString(transit));
         } else if (oldWallpaper != null && !mService.mOpeningApps.isEmpty()
                 && !openingApps.contains(oldWallpaper.mAppToken)
                 && closingApps.contains(oldWallpaper.mAppToken)) {
             // We are transitioning from an activity with a wallpaper to one without.
             transit = AppTransition.TRANSIT_WALLPAPER_CLOSE;
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
                     "New transit away from wallpaper: "
                     + AppTransition.appTransitionToString(transit));
         } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw() &&
@@ -1342,7 +1346,7 @@
             // We are transitioning from an activity without
             // a wallpaper to now showing the wallpaper
             transit = AppTransition.TRANSIT_WALLPAPER_OPEN;
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
                     "New transit into wallpaper: "
                     + AppTransition.appTransitionToString(transit));
         } else {
@@ -1437,7 +1441,7 @@
                         int numInteresting = wtoken.numInterestingWindows;
                         if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
                             if (DEBUG_VISIBILITY)
-                                Slog.v(TAG_WM, "allDrawn: " + wtoken
+                                Slog.v(TAG, "allDrawn: " + wtoken
                                     + " interesting=" + numInteresting
                                     + " drawn=" + wtoken.numDrawnWindows);
                             wtoken.allDrawn = true;
@@ -1466,7 +1470,7 @@
                 final AppWindowToken wtoken = win.mAppToken;
                 final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
                 if (DEBUG_APP_TRANSITIONS)
-                    Slog.v(TAG_WM, "Now animating app in place " + wtoken);
+                    Slog.v(TAG, "Now animating app in place " + wtoken);
                 appAnimator.clearThumbnail();
                 appAnimator.animation = null;
                 mService.updateTokenInPlaceLocked(wtoken, transit);
@@ -1492,7 +1496,7 @@
         final int taskId = appToken.mTask.mTaskId;
         Bitmap thumbnailHeader = mService.mAppTransition.getAppTransitionThumbnailHeader(taskId);
         if (thumbnailHeader == null || thumbnailHeader.getConfig() == Bitmap.Config.ALPHA_8) {
-            if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "No thumbnail header bitmap for: " + taskId);
+            if (DEBUG_APP_TRANSITIONS) Slog.d(TAG, "No thumbnail header bitmap for: " + taskId);
             return;
         }
         // This thumbnail animation is very special, we need to have
@@ -1510,7 +1514,7 @@
                     PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
             surfaceControl.setLayerStack(display.getLayerStack());
             if (SHOW_TRANSACTIONS) {
-                Slog.i(TAG_WM, "  THUMBNAIL " + surfaceControl + ": CREATE");
+                Slog.i(TAG, "  THUMBNAIL " + surfaceControl + ": CREATE");
             }
 
             // Draw the thumbnail onto the surface
@@ -1553,7 +1557,7 @@
             openingAppAnimator.thumbnailX = mTmpStartRect.left;
             openingAppAnimator.thumbnailY = mTmpStartRect.top;
         } catch (Surface.OutOfResourcesException e) {
-            Slog.e(TAG_WM, "Can't allocate thumbnail/Canvas surface w="
+            Slog.e(TAG, "Can't allocate thumbnail/Canvas surface w="
                     + dirty.width() + " h=" + dirty.height(), e);
             openingAppAnimator.clearThumbnail();
         }
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 98d8d08..d1b8648 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -22,7 +22,7 @@
     $(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_input_InputWindowHandle.cpp \
     $(LOCAL_REL_DIR)/com_android_server_lights_LightsService.cpp \
-    $(LOCAL_REL_DIR)/com_android_server_location_GpsLocationProvider.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_location_GnssLocationProvider.cpp \
     $(LOCAL_REL_DIR)/com_android_server_location_FlpHardwareProvider.cpp \
     $(LOCAL_REL_DIR)/com_android_server_power_PowerManagerService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_SerialService.cpp \
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 4c8474a..a5237ca 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -207,6 +207,7 @@
     void setPointerIconShape(int32_t iconId);
     void reloadPointerIcons();
     void setCustomPointerIcon(const SpriteIcon& icon);
+    void setPointerIconDetached(bool detached);
 
     /* --- InputReaderPolicyInterface implementation --- */
 
@@ -711,6 +712,14 @@
     mInputManager->getDispatcher()->setFocusedApplication(applicationHandle);
 }
 
+void NativeInputManager::setPointerIconDetached(bool detached) {
+    AutoMutex _l(mLock);
+    sp<PointerController> controller = mLocked.pointerController.promote();
+    if (controller != NULL) {
+        controller->detachPointerIcon(detached);
+    }
+}
+
 void NativeInputManager::setInputDispatchMode(bool enabled, bool frozen) {
     mInputManager->getDispatcher()->setInputDispatchMode(enabled, frozen);
 }
@@ -1317,6 +1326,12 @@
     im->setFocusedApplication(env, applicationHandleObj);
 }
 
+static void nativeSetPointerIconDetached(JNIEnv* env, jclass /* clazz */, jlong ptr,
+        jboolean detached) {
+    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+    im->setPointerIconDetached(detached);
+}
+
 static void nativeSetInputDispatchMode(JNIEnv* /* env */,
         jclass /* clazz */, jlong ptr, jboolean enabled, jboolean frozen) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
@@ -1497,6 +1512,8 @@
             (void*) nativeSetInputWindows },
     { "nativeSetFocusedApplication", "(JLcom/android/server/input/InputApplicationHandle;)V",
             (void*) nativeSetFocusedApplication },
+    { "nativeSetPointerIconDetached", "(JZ)V",
+            (void*) nativeSetPointerIconDetached },
     { "nativeSetInputDispatchMode", "(JZZ)V",
             (void*) nativeSetInputDispatchMode },
     { "nativeSetSystemUiVisibility", "(JI)V",
diff --git a/services/core/jni/com_android_server_lights_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp
index 3f074f5..c8e3946 100644
--- a/services/core/jni/com_android_server_lights_LightsService.cpp
+++ b/services/core/jni/com_android_server_lights_LightsService.cpp
@@ -113,11 +113,27 @@
         return ;
     }
 
+    uint32_t version = devices->lights[light]->common.version;
+
     memset(&state, 0, sizeof(light_state_t));
-    state.color = colorARGB;
-    state.flashMode = flashMode;
-    state.flashOnMS = onMS;
-    state.flashOffMS = offMS;
+
+    if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
+        if (light != LIGHT_INDEX_BACKLIGHT) {
+            ALOGE("Cannot set low-persistence mode for non-backlight device.");
+            return;
+        }
+        if (version < LIGHTS_DEVICE_API_VERSION_2_0) {
+            // HAL impl has not been upgraded to support this.
+            return;
+        }
+    } else {
+        // Only set non-brightness settings when not in low-persistence mode
+        state.color = colorARGB;
+        state.flashMode = flashMode;
+        state.flashOnMS = onMS;
+        state.flashOffMS = offMS;
+    }
+
     state.brightnessMode = brightnessMode;
 
     {
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
new file mode 100644
index 0000000..0c85a15
--- /dev/null
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -0,0 +1,1656 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "GnssLocationProvider"
+
+#define LOG_NDEBUG 0
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include "hardware/hardware.h"
+#include "hardware/gps_internal.h"
+#include "hardware_legacy/power.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
+
+#include <arpa/inet.h>
+#include <string.h>
+#include <pthread.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+
+static jobject mCallbacksObj = NULL;
+
+static jmethodID method_reportLocation;
+static jmethodID method_reportStatus;
+static jmethodID method_reportSvStatus;
+static jmethodID method_reportAGpsStatus;
+static jmethodID method_reportNmea;
+static jmethodID method_setEngineCapabilities;
+static jmethodID method_setGpsYearOfHardware;
+static jmethodID method_xtraDownloadRequest;
+static jmethodID method_reportNiNotification;
+static jmethodID method_requestRefLocation;
+static jmethodID method_requestSetID;
+static jmethodID method_requestUtcTime;
+static jmethodID method_reportGeofenceTransition;
+static jmethodID method_reportGeofenceStatus;
+static jmethodID method_reportGeofenceAddStatus;
+static jmethodID method_reportGeofenceRemoveStatus;
+static jmethodID method_reportGeofencePauseStatus;
+static jmethodID method_reportGeofenceResumeStatus;
+static jmethodID method_reportMeasurementData;
+static jmethodID method_reportNavigationMessages;
+
+static const GpsInterface* sGpsInterface = NULL;
+static const GpsXtraInterface* sGpsXtraInterface = NULL;
+static const AGpsInterface* sAGpsInterface = NULL;
+static const GpsNiInterface* sGpsNiInterface = NULL;
+static const GpsDebugInterface* sGpsDebugInterface = NULL;
+static const AGpsRilInterface* sAGpsRilInterface = NULL;
+static const GpsGeofencingInterface* sGpsGeofencingInterface = NULL;
+static const GpsMeasurementInterface* sGpsMeasurementInterface = NULL;
+static const GpsNavigationMessageInterface* sGpsNavigationMessageInterface = NULL;
+static const GnssConfigurationInterface* sGnssConfigurationInterface = NULL;
+
+#define MAX_SATELLITE_COUNT 512
+#define MAX_GPS_SATELLITE_COUNT 512
+
+#define PRN_SHIFT_WIDTH 3
+
+// temporary storage for GPS callbacks
+static GnssSvInfo sGnssSvList[MAX_SATELLITE_COUNT];
+static size_t sGnssSvListSize;
+static const char* sNmeaString;
+static int sNmeaStringLength;
+
+#define WAKE_LOCK_NAME  "GPS"
+
+namespace android {
+
+static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
+    if (env->ExceptionCheck()) {
+        ALOGE("An exception was thrown by callback '%s'.", methodName);
+        LOGE_EX(env);
+        env->ExceptionClear();
+    }
+}
+
+static void location_callback(GpsLocation* location)
+{
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj, method_reportLocation, location->flags,
+            (jdouble)location->latitude, (jdouble)location->longitude,
+            (jdouble)location->altitude,
+            (jfloat)location->speed, (jfloat)location->bearing,
+            (jfloat)location->accuracy, (jlong)location->timestamp);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+static void status_callback(GpsStatus* status)
+{
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj, method_reportStatus, status->status);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+static void sv_status_callback(GpsSvStatus* sv_status)
+{
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    size_t status_size = sv_status->size;
+    // Some drive doesn't set the size field correctly. Assume GpsSvStatus_v1 if
+    // it doesn't provide a valid size.
+    if (status_size == 0) {
+        status_size = sizeof(GpsSvStatus_v1);
+    }
+    if (status_size == sizeof(GpsSvStatus)) {
+        sGnssSvListSize = sv_status->gnss_sv_list_size;
+        // Cramp the list size
+        if (sGnssSvListSize > MAX_SATELLITE_COUNT) {
+            sGnssSvListSize = MAX_SATELLITE_COUNT;
+        }
+        // Copy GNSS SV info into sGnssSvList, if any.
+        if (sGnssSvListSize > 0 && sv_status->gnss_sv_list) {
+            memcpy(sGnssSvList, sv_status->gnss_sv_list, sizeof(GnssSvInfo) * sGnssSvListSize);
+        }
+    } else if (status_size == sizeof(GpsSvStatus_v1)) {
+        sGnssSvListSize = sv_status->num_svs;
+        // Cramp the list size
+        if (sGnssSvListSize > MAX_GPS_SATELLITE_COUNT) {
+            sGnssSvListSize = MAX_GPS_SATELLITE_COUNT;
+        }
+        uint32_t ephemeris_mask = sv_status->ephemeris_mask;
+        uint32_t almanac_mask = sv_status->almanac_mask;
+        uint32_t used_in_fix_mask = sv_status->used_in_fix_mask;
+        for (size_t i = 0; i < sGnssSvListSize; i++) {
+            GnssSvInfo& info = sGnssSvList[i];
+            info.constellation = GNSS_CONSTELLATION_GPS;
+            info.prn = sv_status->sv_list[i].prn;
+            info.snr = 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;
+            if (info.prn > 0 && info.prn <= 32) {
+              int32_t this_prn_mask = (1 << (info.prn - 1));
+              if ((ephemeris_mask & this_prn_mask) != 0) {
+                info.flags |= GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA;
+              }
+              if ((almanac_mask & this_prn_mask) != 0) {
+                info.flags |= GNSS_SV_FLAGS_HAS_ALMANAC_DATA;
+              }
+              if ((used_in_fix_mask & this_prn_mask) != 0) {
+                info.flags |= GNSS_SV_FLAGS_USED_IN_FIX;
+              }
+            }
+        }
+    } else {
+        sGnssSvListSize = 0;
+        ALOGE("Invalid size of GpsSvStatus found: %zd.", status_size);
+        return;
+    }
+    env->CallVoidMethod(mCallbacksObj, method_reportSvStatus);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+static void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length)
+{
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    // The Java code will call back to read these values
+    // We do this to avoid creating unnecessary String objects
+    sNmeaString = nmea;
+    sNmeaStringLength = length;
+    env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+static void set_system_info_callback(const GpsSystemInfo* info) {
+    ALOGD("set_system_info_callback: year_of_hw=%d\n", info->year_of_hw);
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj, method_setGpsYearOfHardware,
+                        info->year_of_hw);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+static void set_capabilities_callback(uint32_t capabilities)
+{
+    ALOGD("set_capabilities_callback: %du\n", capabilities);
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+static void acquire_wakelock_callback()
+{
+    acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
+}
+
+static void release_wakelock_callback()
+{
+    release_wake_lock(WAKE_LOCK_NAME);
+}
+
+static void request_utc_time_callback()
+{
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg)
+{
+    return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);
+}
+
+GpsCallbacks sGpsCallbacks = {
+    sizeof(GpsCallbacks),
+    location_callback,
+    status_callback,
+    sv_status_callback,
+    nmea_callback,
+    set_capabilities_callback,
+    acquire_wakelock_callback,
+    release_wakelock_callback,
+    create_thread_callback,
+    request_utc_time_callback,
+    set_system_info_callback,
+};
+
+static void xtra_download_request_callback()
+{
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj, method_xtraDownloadRequest);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+GpsXtraCallbacks sGpsXtraCallbacks = {
+    xtra_download_request_callback,
+    create_thread_callback,
+};
+
+static jbyteArray convert_to_ipv4(uint32_t ip, bool net_order)
+{
+    if (INADDR_NONE == ip) {
+        return NULL;
+    }
+
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jbyteArray byteArray = env->NewByteArray(4);
+    if (byteArray == NULL) {
+        ALOGE("Unable to allocate byte array for IPv4 address");
+        return NULL;
+    }
+
+    jbyte ipv4[4];
+    if (net_order) {
+        ALOGV("Converting IPv4 address(net_order) %x", ip);
+        memcpy(ipv4, &ip, sizeof(ipv4));
+    } else {
+        ALOGV("Converting IPv4 address(host_order) %x", ip);
+        //endianess transparent conversion from int to char[]
+        ipv4[0] = (jbyte) (ip & 0xFF);
+        ipv4[1] = (jbyte)((ip>>8) & 0xFF);
+        ipv4[2] = (jbyte)((ip>>16) & 0xFF);
+        ipv4[3] = (jbyte) (ip>>24);
+    }
+
+    env->SetByteArrayRegion(byteArray, 0, 4, (const jbyte*) ipv4);
+    return byteArray;
+}
+
+static void agps_status_callback(AGpsStatus* agps_status)
+{
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jbyteArray byteArray = NULL;
+    bool isSupported = false;
+
+    size_t status_size = agps_status->size;
+    if (status_size == sizeof(AGpsStatus)) {
+      ALOGV("AGpsStatus is V3: %zd", status_size);
+      switch (agps_status->addr.ss_family)
+      {
+      case AF_INET:
+          {
+            struct sockaddr_in *in = (struct sockaddr_in*)&(agps_status->addr);
+            uint32_t ipAddr = *(uint32_t*)&(in->sin_addr);
+            byteArray = convert_to_ipv4(ipAddr, true /* net_order */);
+            if (ipAddr == INADDR_NONE || byteArray != NULL) {
+                isSupported = true;
+            }
+            IF_ALOGD() {
+                // log the IP for reference in case there is a bogus value pushed by HAL
+                char str[INET_ADDRSTRLEN];
+                inet_ntop(AF_INET, &(in->sin_addr), str, INET_ADDRSTRLEN);
+                ALOGD("AGPS IP is v4: %s", str);
+            }
+          }
+          break;
+      case AF_INET6:
+          {
+            struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&(agps_status->addr);
+            byteArray = env->NewByteArray(16);
+            if (byteArray != NULL) {
+                env->SetByteArrayRegion(byteArray, 0, 16, (const jbyte *)&(in6->sin6_addr));
+                isSupported = true;
+            } else {
+                ALOGE("Unable to allocate byte array for IPv6 address.");
+            }
+            IF_ALOGD() {
+                // log the IP for reference in case there is a bogus value pushed by HAL
+                char str[INET6_ADDRSTRLEN];
+                inet_ntop(AF_INET6, &(in6->sin6_addr), str, INET6_ADDRSTRLEN);
+                ALOGD("AGPS IP is v6: %s", str);
+            }
+          }
+          break;
+      default:
+          ALOGE("Invalid ss_family found: %d", agps_status->addr.ss_family);
+          break;
+      }
+    } else if (status_size >= sizeof(AGpsStatus_v2)) {
+      ALOGV("AGpsStatus is V2+: %zd", status_size);
+      // for back-compatibility reasons we check in v2 that the data structure size is greater or
+      // equal to the declared size in gps.h
+      uint32_t ipaddr = agps_status->ipaddr;
+      ALOGV("AGPS IP is v4: %x", ipaddr);
+      byteArray = convert_to_ipv4(ipaddr, false /* net_order */);
+      if (ipaddr == INADDR_NONE || byteArray != NULL) {
+          isSupported = true;
+      }
+    } else if (status_size >= sizeof(AGpsStatus_v1)) {
+        ALOGV("AGpsStatus is V1+: %zd", status_size);
+        // because we have to check for >= with regards to v2, we also need to relax the check here
+        // and only make sure that the size is at least what we expect
+        isSupported = true;
+    } else {
+        ALOGE("Invalid size of AGpsStatus found: %zd.", status_size);
+    }
+
+    if (isSupported) {
+        jsize byteArrayLength = byteArray != NULL ? env->GetArrayLength(byteArray) : 0;
+        ALOGV("Passing AGPS IP addr: size %d", byteArrayLength);
+        env->CallVoidMethod(mCallbacksObj, method_reportAGpsStatus, agps_status->type,
+                            agps_status->status, byteArray);
+
+        checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    } else {
+        ALOGD("Skipping calling method_reportAGpsStatus.");
+    }
+
+    if (byteArray) {
+        env->DeleteLocalRef(byteArray);
+    }
+}
+
+AGpsCallbacks sAGpsCallbacks = {
+    agps_status_callback,
+    create_thread_callback,
+};
+
+static void gps_ni_notify_callback(GpsNiNotification *notification)
+{
+    ALOGD("gps_ni_notify_callback\n");
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jstring requestor_id = env->NewStringUTF(notification->requestor_id);
+    jstring text = env->NewStringUTF(notification->text);
+    jstring extras = env->NewStringUTF(notification->extras);
+
+    if (requestor_id && text && extras) {
+        env->CallVoidMethod(mCallbacksObj, method_reportNiNotification,
+            notification->notification_id, notification->ni_type,
+            notification->notify_flags, notification->timeout,
+            notification->default_response, requestor_id, text,
+            notification->requestor_id_encoding,
+            notification->text_encoding, extras);
+    } else {
+        ALOGE("out of memory in gps_ni_notify_callback\n");
+    }
+
+    if (requestor_id)
+        env->DeleteLocalRef(requestor_id);
+    if (text)
+        env->DeleteLocalRef(text);
+    if (extras)
+        env->DeleteLocalRef(extras);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+GpsNiCallbacks sGpsNiCallbacks = {
+    gps_ni_notify_callback,
+    create_thread_callback,
+};
+
+static void agps_request_set_id(uint32_t flags)
+{
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj, method_requestSetID, flags);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+static void agps_request_ref_location(uint32_t flags)
+{
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj, method_requestRefLocation, flags);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+AGpsRilCallbacks sAGpsRilCallbacks = {
+    agps_request_set_id,
+    agps_request_ref_location,
+    create_thread_callback,
+};
+
+static void gps_geofence_transition_callback(int32_t geofence_id,  GpsLocation* location,
+        int32_t transition, GpsUtcTime timestamp)
+{
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceTransition, geofence_id,
+            location->flags, (jdouble)location->latitude, (jdouble)location->longitude,
+            (jdouble)location->altitude,
+            (jfloat)location->speed, (jfloat)location->bearing,
+            (jfloat)location->accuracy, (jlong)location->timestamp,
+            transition, timestamp);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+};
+
+static void gps_geofence_status_callback(int32_t status, GpsLocation* location)
+{
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jint flags = 0;
+    jdouble latitude = 0;
+    jdouble longitude = 0;
+    jdouble altitude = 0;
+    jfloat speed = 0;
+    jfloat bearing = 0;
+    jfloat accuracy = 0;
+    jlong timestamp = 0;
+    if (location != NULL) {
+        flags = location->flags;
+        latitude = location->latitude;
+        longitude = location->longitude;
+        altitude = location->altitude;
+        speed = location->speed;
+        bearing = location->bearing;
+        accuracy = location->accuracy;
+        timestamp = location->timestamp;
+    }
+
+    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceStatus, status,
+            flags, latitude, longitude, altitude, speed, bearing, accuracy, timestamp);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+};
+
+static void gps_geofence_add_callback(int32_t geofence_id, int32_t status)
+{
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
+        ALOGE("Error in geofence_add_callback: %d\n", status);
+    }
+    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceAddStatus, geofence_id, status);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+};
+
+static void gps_geofence_remove_callback(int32_t geofence_id, int32_t status)
+{
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
+        ALOGE("Error in geofence_remove_callback: %d\n", status);
+    }
+    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceRemoveStatus, geofence_id, status);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+};
+
+static void gps_geofence_resume_callback(int32_t geofence_id, int32_t status)
+{
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
+        ALOGE("Error in geofence_resume_callback: %d\n", status);
+    }
+    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceResumeStatus, geofence_id, status);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+};
+
+static void gps_geofence_pause_callback(int32_t geofence_id, int32_t status)
+{
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
+        ALOGE("Error in geofence_pause_callback: %d\n", status);
+    }
+    env->CallVoidMethod(mCallbacksObj, method_reportGeofencePauseStatus, geofence_id, status);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+};
+
+GpsGeofenceCallbacks sGpsGeofenceCallbacks = {
+    gps_geofence_transition_callback,
+    gps_geofence_status_callback,
+    gps_geofence_add_callback,
+    gps_geofence_remove_callback,
+    gps_geofence_pause_callback,
+    gps_geofence_resume_callback,
+    create_thread_callback,
+};
+
+static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
+    int err;
+    hw_module_t* module;
+
+    method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
+    method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
+    method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
+    method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II[B)V");
+    method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
+    method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
+    method_setGpsYearOfHardware = env->GetMethodID(clazz, "setGpsYearOfHardware", "(I)V");
+    method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
+    method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification",
+            "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
+    method_requestRefLocation = env->GetMethodID(clazz,"requestRefLocation","(I)V");
+    method_requestSetID = env->GetMethodID(clazz,"requestSetID","(I)V");
+    method_requestUtcTime = env->GetMethodID(clazz,"requestUtcTime","()V");
+    method_reportGeofenceTransition = env->GetMethodID(clazz,"reportGeofenceTransition",
+            "(IIDDDFFFJIJ)V");
+    method_reportGeofenceStatus = env->GetMethodID(clazz,"reportGeofenceStatus",
+            "(IIDDDFFFJ)V");
+    method_reportGeofenceAddStatus = env->GetMethodID(clazz,"reportGeofenceAddStatus",
+            "(II)V");
+    method_reportGeofenceRemoveStatus = env->GetMethodID(clazz,"reportGeofenceRemoveStatus",
+            "(II)V");
+    method_reportGeofenceResumeStatus = env->GetMethodID(clazz,"reportGeofenceResumeStatus",
+            "(II)V");
+    method_reportGeofencePauseStatus = env->GetMethodID(clazz,"reportGeofencePauseStatus",
+            "(II)V");
+    method_reportMeasurementData = env->GetMethodID(
+            clazz,
+            "reportMeasurementData",
+            "(Landroid/location/GpsMeasurementsEvent;)V");
+    method_reportNavigationMessages = env->GetMethodID(
+            clazz,
+            "reportNavigationMessage",
+            "(Landroid/location/GpsNavigationMessageEvent;)V");
+
+    err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
+    if (err == 0) {
+        hw_device_t* device;
+        err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
+        if (err == 0) {
+            gps_device_t* gps_device = (gps_device_t *)device;
+            sGpsInterface = gps_device->get_gps_interface(gps_device);
+        }
+    }
+    if (sGpsInterface) {
+        sGpsXtraInterface =
+            (const GpsXtraInterface*)sGpsInterface->get_extension(GPS_XTRA_INTERFACE);
+        sAGpsInterface =
+            (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
+        sGpsNiInterface =
+            (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
+        sGpsDebugInterface =
+            (const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE);
+        sAGpsRilInterface =
+            (const AGpsRilInterface*)sGpsInterface->get_extension(AGPS_RIL_INTERFACE);
+        sGpsGeofencingInterface =
+            (const GpsGeofencingInterface*)sGpsInterface->get_extension(GPS_GEOFENCING_INTERFACE);
+        sGpsMeasurementInterface =
+            (const GpsMeasurementInterface*)sGpsInterface->get_extension(GPS_MEASUREMENT_INTERFACE);
+        sGpsNavigationMessageInterface =
+            (const GpsNavigationMessageInterface*)sGpsInterface->get_extension(
+                    GPS_NAVIGATION_MESSAGE_INTERFACE);
+        sGnssConfigurationInterface =
+            (const GnssConfigurationInterface*)sGpsInterface->get_extension(
+                    GNSS_CONFIGURATION_INTERFACE);
+    }
+}
+
+static jboolean android_location_GnssLocationProvider_is_supported(
+        JNIEnv* /* env */, jclass /* clazz */)
+{
+    return (sGpsInterface != NULL) ?  JNI_TRUE : JNI_FALSE;
+}
+
+static jboolean android_location_GnssLocationProvider_is_agps_ril_supported(
+        JNIEnv* /* env */, jclass /* clazz */)
+{
+    return (sAGpsRilInterface != NULL) ? JNI_TRUE : JNI_FALSE;
+}
+
+static jboolean android_location_gpsLocationProvider_is_gnss_configuration_supported(
+        JNIEnv* /* env */, jclass /* jclazz */)
+{
+    return (sGnssConfigurationInterface != NULL) ? JNI_TRUE : JNI_FALSE;
+}
+
+static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject obj)
+{
+    // this must be set before calling into the HAL library
+    if (!mCallbacksObj)
+        mCallbacksObj = env->NewGlobalRef(obj);
+
+    // fail if the main interface fails to initialize
+    if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
+        return JNI_FALSE;
+
+    // if XTRA initialization fails we will disable it by sGpsXtraInterface to NULL,
+    // but continue to allow the rest of the GPS interface to work.
+    if (sGpsXtraInterface && sGpsXtraInterface->init(&sGpsXtraCallbacks) != 0)
+        sGpsXtraInterface = NULL;
+    if (sAGpsInterface)
+        sAGpsInterface->init(&sAGpsCallbacks);
+    if (sGpsNiInterface)
+        sGpsNiInterface->init(&sGpsNiCallbacks);
+    if (sAGpsRilInterface)
+        sAGpsRilInterface->init(&sAGpsRilCallbacks);
+    if (sGpsGeofencingInterface)
+        sGpsGeofencingInterface->init(&sGpsGeofenceCallbacks);
+
+    return JNI_TRUE;
+}
+
+static void android_location_GnssLocationProvider_cleanup(JNIEnv* /* env */, jobject /* obj */)
+{
+    if (sGpsInterface)
+        sGpsInterface->cleanup();
+}
+
+static jboolean android_location_GnssLocationProvider_set_position_mode(JNIEnv* /* env */,
+        jobject /* obj */, jint mode, jint recurrence, jint min_interval, jint preferred_accuracy,
+        jint preferred_time)
+{
+    if (sGpsInterface) {
+        if (sGpsInterface->set_position_mode(mode, recurrence, min_interval, preferred_accuracy,
+                preferred_time) == 0) {
+            return JNI_TRUE;
+        } else {
+            return JNI_FALSE;
+        }
+    }
+    else
+        return JNI_FALSE;
+}
+
+static jboolean android_location_GnssLocationProvider_start(JNIEnv* /* env */, jobject /* obj */)
+{
+    if (sGpsInterface) {
+        if (sGpsInterface->start() == 0) {
+            return JNI_TRUE;
+        } else {
+            return JNI_FALSE;
+        }
+    }
+    else
+        return JNI_FALSE;
+}
+
+static jboolean android_location_GnssLocationProvider_stop(JNIEnv* /* env */, jobject /* obj */)
+{
+    if (sGpsInterface) {
+        if (sGpsInterface->stop() == 0) {
+            return JNI_TRUE;
+        } else {
+            return JNI_FALSE;
+        }
+    }
+    else
+        return JNI_FALSE;
+}
+
+static void android_location_GnssLocationProvider_delete_aiding_data(JNIEnv* /* env */,
+                                                                    jobject /* obj */,
+                                                                    jint flags)
+{
+    if (sGpsInterface)
+        sGpsInterface->delete_aiding_data(flags);
+}
+
+static jint android_location_GnssLocationProvider_read_sv_status(JNIEnv* env, jobject /* obj */,
+        jintArray prnWithFlagArray, jfloatArray snrArray, jfloatArray elevArray,
+        jfloatArray azumArray, jintArray constellationTypeArray)
+{
+    // this should only be called from within a call to reportSvStatus
+    jint* prnWithFlags = env->GetIntArrayElements(prnWithFlagArray, 0);
+    jfloat* snrs = env->GetFloatArrayElements(snrArray, 0);
+    jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
+    jfloat* azim = env->GetFloatArrayElements(azumArray, 0);
+    jint* constellationTypes = env->GetIntArrayElements(constellationTypeArray, 0);
+
+    // GNSS SV info.
+    for (size_t i = 0; i < sGnssSvListSize; ++i) {
+        const GnssSvInfo& info = sGnssSvList[i];
+        constellationTypes[i] = info.constellation;
+        prnWithFlags[i] = (info.prn << PRN_SHIFT_WIDTH) | info.flags;
+        snrs[i] = info.snr;
+        elev[i] = info.elevation;
+        azim[i] = info.azimuth;
+    }
+
+    env->ReleaseIntArrayElements(prnWithFlagArray, prnWithFlags, 0);
+    env->ReleaseFloatArrayElements(snrArray, snrs, 0);
+    env->ReleaseFloatArrayElements(elevArray, elev, 0);
+    env->ReleaseFloatArrayElements(azumArray, azim, 0);
+    env->ReleaseIntArrayElements(constellationTypeArray, constellationTypes, 0);
+    return (jint) sGnssSvListSize;
+}
+
+static void android_location_GnssLocationProvider_agps_set_reference_location_cellid(
+        JNIEnv* /* env */, jobject /* obj */, jint type, jint mcc, jint mnc, jint lac, jint cid)
+{
+    AGpsRefLocation location;
+
+    if (!sAGpsRilInterface) {
+        ALOGE("no AGPS RIL interface in agps_set_reference_location_cellid");
+        return;
+    }
+
+    switch(type) {
+        case AGPS_REF_LOCATION_TYPE_GSM_CELLID:
+        case AGPS_REF_LOCATION_TYPE_UMTS_CELLID:
+            location.type = type;
+            location.u.cellID.mcc = mcc;
+            location.u.cellID.mnc = mnc;
+            location.u.cellID.lac = lac;
+            location.u.cellID.cid = cid;
+            break;
+        default:
+            ALOGE("Neither a GSM nor a UMTS cellid (%s:%d).",__FUNCTION__,__LINE__);
+            return;
+            break;
+    }
+    sAGpsRilInterface->set_ref_location(&location, sizeof(location));
+}
+
+static void android_location_GnssLocationProvider_agps_send_ni_message(JNIEnv* env,
+        jobject /* obj */, jbyteArray ni_msg, jint size)
+{
+    size_t sz;
+
+    if (!sAGpsRilInterface) {
+        ALOGE("no AGPS RIL interface in send_ni_message");
+        return;
+    }
+    if (size < 0)
+        return;
+    sz = (size_t)size;
+    jbyte* b = env->GetByteArrayElements(ni_msg, 0);
+    sAGpsRilInterface->ni_message((uint8_t *)b,sz);
+    env->ReleaseByteArrayElements(ni_msg,b,0);
+}
+
+static void android_location_GnssLocationProvider_agps_set_id(JNIEnv *env, jobject /* obj */,
+                                                             jint type, jstring  setid_string)
+{
+    if (!sAGpsRilInterface) {
+        ALOGE("no AGPS RIL interface in agps_set_id");
+        return;
+    }
+
+    const char *setid = env->GetStringUTFChars(setid_string, NULL);
+    sAGpsRilInterface->set_set_id(type, setid);
+    env->ReleaseStringUTFChars(setid_string, setid);
+}
+
+static jint android_location_GnssLocationProvider_read_nmea(JNIEnv* env, jobject /* obj */,
+                                            jbyteArray nmeaArray, jint buffer_size)
+{
+    // this should only be called from within a call to reportNmea
+    jbyte* nmea = (jbyte *)env->GetPrimitiveArrayCritical(nmeaArray, 0);
+    int length = sNmeaStringLength;
+    if (length > buffer_size)
+        length = buffer_size;
+    memcpy(nmea, sNmeaString, length);
+    env->ReleasePrimitiveArrayCritical(nmeaArray, nmea, JNI_ABORT);
+    return (jint) length;
+}
+
+static void android_location_GnssLocationProvider_inject_time(JNIEnv* /* env */, jobject /* obj */,
+        jlong time, jlong timeReference, jint uncertainty)
+{
+    if (sGpsInterface)
+        sGpsInterface->inject_time(time, timeReference, uncertainty);
+}
+
+static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env */,
+        jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy)
+{
+    if (sGpsInterface)
+        sGpsInterface->inject_location(latitude, longitude, accuracy);
+}
+
+static jboolean android_location_GnssLocationProvider_supports_xtra(
+        JNIEnv* /* env */, jobject /* obj */)
+{
+    return (sGpsXtraInterface != NULL) ? JNI_TRUE : JNI_FALSE;
+}
+
+static void android_location_GnssLocationProvider_inject_xtra_data(JNIEnv* env, jobject /* obj */,
+        jbyteArray data, jint length)
+{
+    if (!sGpsXtraInterface) {
+        ALOGE("no XTRA interface in inject_xtra_data");
+        return;
+    }
+
+    jbyte* bytes = (jbyte *)env->GetPrimitiveArrayCritical(data, 0);
+    sGpsXtraInterface->inject_xtra_data((char *)bytes, length);
+    env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
+}
+
+static void android_location_GnssLocationProvider_agps_data_conn_open(
+        JNIEnv* env, jobject /* obj */, jstring apn, jint apnIpType)
+{
+    if (!sAGpsInterface) {
+        ALOGE("no AGPS interface in agps_data_conn_open");
+        return;
+    }
+    if (apn == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return;
+    }
+
+    const char *apnStr = env->GetStringUTFChars(apn, NULL);
+
+    size_t interface_size = sAGpsInterface->size;
+    if (interface_size == sizeof(AGpsInterface)) {
+        sAGpsInterface->data_conn_open_with_apn_ip_type(apnStr, apnIpType);
+    } else if (interface_size == sizeof(AGpsInterface_v1)) {
+        sAGpsInterface->data_conn_open(apnStr);
+    } else {
+        ALOGE("Invalid size of AGpsInterface found: %zd.", interface_size);
+    }
+
+    env->ReleaseStringUTFChars(apn, apnStr);
+}
+
+static void android_location_GnssLocationProvider_agps_data_conn_closed(JNIEnv* /* env */,
+                                                                       jobject /* obj */)
+{
+    if (!sAGpsInterface) {
+        ALOGE("no AGPS interface in agps_data_conn_closed");
+        return;
+    }
+    sAGpsInterface->data_conn_closed();
+}
+
+static void android_location_GnssLocationProvider_agps_data_conn_failed(JNIEnv* /* env */,
+                                                                       jobject /* obj */)
+{
+    if (!sAGpsInterface) {
+        ALOGE("no AGPS interface in agps_data_conn_failed");
+        return;
+    }
+    sAGpsInterface->data_conn_failed();
+}
+
+static void android_location_GnssLocationProvider_set_agps_server(JNIEnv* env, jobject /* obj */,
+        jint type, jstring hostname, jint port)
+{
+    if (!sAGpsInterface) {
+        ALOGE("no AGPS interface in set_agps_server");
+        return;
+    }
+    const char *c_hostname = env->GetStringUTFChars(hostname, NULL);
+    sAGpsInterface->set_server(type, c_hostname, port);
+    env->ReleaseStringUTFChars(hostname, c_hostname);
+}
+
+static void android_location_GnssLocationProvider_send_ni_response(JNIEnv* /* env */,
+      jobject /* obj */, jint notifId, jint response)
+{
+    if (!sGpsNiInterface) {
+        ALOGE("no NI interface in send_ni_response");
+        return;
+    }
+
+    sGpsNiInterface->respond(notifId, response);
+}
+
+static jstring android_location_GnssLocationProvider_get_internal_state(JNIEnv* env,
+                                                                       jobject /* obj */) {
+    jstring result = NULL;
+    if (sGpsDebugInterface) {
+        const size_t maxLength = 2047;
+        char buffer[maxLength+1];
+        size_t length = sGpsDebugInterface->get_internal_state(buffer, maxLength);
+        if (length > maxLength) length = maxLength;
+        buffer[length] = 0;
+        result = env->NewStringUTF(buffer);
+    }
+    return result;
+}
+
+static void android_location_GnssLocationProvider_update_network_state(JNIEnv* env, jobject /* obj */,
+        jboolean connected, jint type, jboolean roaming, jboolean available, jstring extraInfo, jstring apn)
+{
+
+    if (sAGpsRilInterface && sAGpsRilInterface->update_network_state) {
+        if (extraInfo) {
+            const char *extraInfoStr = env->GetStringUTFChars(extraInfo, NULL);
+            sAGpsRilInterface->update_network_state(connected, type, roaming, extraInfoStr);
+            env->ReleaseStringUTFChars(extraInfo, extraInfoStr);
+        } else {
+            sAGpsRilInterface->update_network_state(connected, type, roaming, NULL);
+        }
+
+        // update_network_availability callback was not included in original AGpsRilInterface
+        if (sAGpsRilInterface->size >= sizeof(AGpsRilInterface)
+                && sAGpsRilInterface->update_network_availability) {
+            const char *c_apn = env->GetStringUTFChars(apn, NULL);
+            sAGpsRilInterface->update_network_availability(available, c_apn);
+            env->ReleaseStringUTFChars(apn, c_apn);
+        }
+    }
+}
+
+static jboolean android_location_GnssLocationProvider_is_geofence_supported(
+        JNIEnv* /* env */, jobject /* obj */)
+{
+    return (sGpsGeofencingInterface != NULL) ? JNI_TRUE : JNI_FALSE;
+}
+
+static jboolean android_location_GnssLocationProvider_add_geofence(JNIEnv* /* env */,
+        jobject /* obj */, jint geofence_id, jdouble latitude, jdouble longitude, jdouble radius,
+        jint last_transition, jint monitor_transition, jint notification_responsiveness,
+        jint unknown_timer) {
+    if (sGpsGeofencingInterface != NULL) {
+        sGpsGeofencingInterface->add_geofence_area(geofence_id, latitude, longitude,
+                radius, last_transition, monitor_transition, notification_responsiveness,
+                unknown_timer);
+        return JNI_TRUE;
+    } else {
+        ALOGE("Geofence interface not available");
+    }
+    return JNI_FALSE;
+}
+
+static jboolean android_location_GnssLocationProvider_remove_geofence(JNIEnv* /* env */,
+        jobject /* obj */, jint geofence_id) {
+    if (sGpsGeofencingInterface != NULL) {
+        sGpsGeofencingInterface->remove_geofence_area(geofence_id);
+        return JNI_TRUE;
+    } else {
+        ALOGE("Geofence interface not available");
+    }
+    return JNI_FALSE;
+}
+
+static jboolean android_location_GnssLocationProvider_pause_geofence(JNIEnv* /* env */,
+        jobject /* obj */, jint geofence_id) {
+    if (sGpsGeofencingInterface != NULL) {
+        sGpsGeofencingInterface->pause_geofence(geofence_id);
+        return JNI_TRUE;
+    } else {
+        ALOGE("Geofence interface not available");
+    }
+    return JNI_FALSE;
+}
+
+static jboolean android_location_GnssLocationProvider_resume_geofence(JNIEnv* /* env */,
+        jobject /* obj */, jint geofence_id, jint monitor_transition) {
+    if (sGpsGeofencingInterface != NULL) {
+        sGpsGeofencingInterface->resume_geofence(geofence_id, monitor_transition);
+        return JNI_TRUE;
+    } else {
+        ALOGE("Geofence interface not available");
+    }
+    return JNI_FALSE;
+}
+
+static jobject translate_gps_clock(JNIEnv* env, void* data, size_t size) {
+    const char* doubleSignature = "(D)V";
+    const char* longSignature = "(J)V";
+
+    GpsClock* clock = reinterpret_cast<GpsClock*>(data);
+
+    jclass gpsClockClass = env->FindClass("android/location/GpsClock");
+    jmethodID gpsClockCtor = env->GetMethodID(gpsClockClass, "<init>", "()V");
+
+    jobject gpsClockObject = env->NewObject(gpsClockClass, gpsClockCtor);
+    GpsClockFlags flags = clock->flags;
+
+    if (flags & GPS_CLOCK_HAS_LEAP_SECOND) {
+        jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setLeapSecond", "(S)V");
+        env->CallVoidMethod(gpsClockObject, setterMethod, clock->leap_second);
+   }
+
+   jmethodID typeSetterMethod = env->GetMethodID(gpsClockClass, "setType", "(B)V");
+   env->CallVoidMethod(gpsClockObject, typeSetterMethod, clock->type);
+
+    jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setTimeInNs", longSignature);
+    env->CallVoidMethod(gpsClockObject, setterMethod, clock->time_ns);
+
+    if (flags & GPS_CLOCK_HAS_TIME_UNCERTAINTY) {
+        jmethodID setterMethod =
+                env->GetMethodID(gpsClockClass, "setTimeUncertaintyInNs", doubleSignature);
+        env->CallVoidMethod(gpsClockObject, setterMethod, clock->time_uncertainty_ns);
+    }
+
+    if (flags & GPS_CLOCK_HAS_FULL_BIAS) {
+        jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setFullBiasInNs", longSignature);
+        env->CallVoidMethod(gpsClockObject, setterMethod, clock->full_bias_ns);
+    }
+
+    if (flags & GPS_CLOCK_HAS_BIAS) {
+        jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setBiasInNs", doubleSignature);
+        env->CallVoidMethod(gpsClockObject, setterMethod, clock->bias_ns);
+    }
+
+    if (flags & GPS_CLOCK_HAS_BIAS_UNCERTAINTY) {
+        jmethodID setterMethod =
+                env->GetMethodID(gpsClockClass, "setBiasUncertaintyInNs", doubleSignature);
+        env->CallVoidMethod(gpsClockObject, setterMethod, clock->bias_uncertainty_ns);
+    }
+
+    if (flags & GPS_CLOCK_HAS_DRIFT) {
+        jmethodID setterMethod =
+                env->GetMethodID(gpsClockClass, "setDriftInNsPerSec", doubleSignature);
+        env->CallVoidMethod(gpsClockObject, setterMethod, clock->drift_nsps);
+    }
+
+    if (flags & GPS_CLOCK_HAS_DRIFT_UNCERTAINTY) {
+        jmethodID setterMethod =
+                env->GetMethodID(gpsClockClass, "setDriftUncertaintyInNsPerSec", doubleSignature);
+        env->CallVoidMethod(gpsClockObject, setterMethod, clock->drift_uncertainty_nsps);
+    }
+
+    if (flags & GPS_CLOCK_TYPE_LOCAL_HW_TIME) {
+        if (size == sizeof(GpsClock)) {
+            jmethodID setterMethod =
+                    env->GetMethodID(gpsClockClass,
+                                     "setTimeOfLastHwClockDiscontinuityInNs",
+                                     longSignature);
+            env->CallVoidMethod(gpsClockObject,
+                                setterMethod,
+                                clock->time_of_last_hw_clock_discontinuity_ns);
+        }
+    }
+
+    env->DeleteLocalRef(gpsClockClass);
+    return gpsClockObject;
+}
+
+static jobject translate_gps_measurement(JNIEnv* env, void* data, size_t size) {
+    const char* byteSignature = "(B)V";
+    const char* shortSignature = "(S)V";
+    const char* intSignature = "(I)V";
+    const char* longSignature = "(J)V";
+    const char* floatSignature = "(F)V";
+    const char* doubleSignature = "(D)V";
+
+    jclass gpsMeasurementClass = env->FindClass("android/location/GpsMeasurement");
+    jmethodID gpsMeasurementCtor = env->GetMethodID(gpsMeasurementClass, "<init>", "()V");
+    GpsMeasurement* measurement = reinterpret_cast<GpsMeasurement*>(data);
+
+    jobject gpsMeasurementObject = env->NewObject(gpsMeasurementClass, gpsMeasurementCtor);
+    GpsMeasurementFlags flags = measurement->flags;
+
+    jmethodID prnSetterMethod = env->GetMethodID(gpsMeasurementClass, "setPrn", byteSignature);
+    env->CallVoidMethod(gpsMeasurementObject, prnSetterMethod, measurement->prn);
+
+    jmethodID timeOffsetSetterMethod =
+            env->GetMethodID(gpsMeasurementClass, "setTimeOffsetInNs", doubleSignature);
+    env->CallVoidMethod(
+            gpsMeasurementObject,
+            timeOffsetSetterMethod,
+            measurement->time_offset_ns);
+
+    jmethodID stateSetterMethod = env->GetMethodID(gpsMeasurementClass, "setState", shortSignature);
+    env->CallVoidMethod(gpsMeasurementObject, stateSetterMethod, measurement->state);
+
+    jmethodID receivedGpsTowSetterMethod =
+            env->GetMethodID(gpsMeasurementClass, "setReceivedGpsTowInNs", longSignature);
+    env->CallVoidMethod(
+            gpsMeasurementObject,
+            receivedGpsTowSetterMethod,
+            measurement->received_gps_tow_ns);
+
+    jmethodID receivedGpsTowUncertaintySetterMethod = env->GetMethodID(
+            gpsMeasurementClass,
+            "setReceivedGpsTowUncertaintyInNs",
+            longSignature);
+    env->CallVoidMethod(
+            gpsMeasurementObject,
+            receivedGpsTowUncertaintySetterMethod,
+            measurement->received_gps_tow_uncertainty_ns);
+
+    jmethodID cn0SetterMethod =
+            env->GetMethodID(gpsMeasurementClass, "setCn0InDbHz", doubleSignature);
+    env->CallVoidMethod(gpsMeasurementObject, cn0SetterMethod, measurement->c_n0_dbhz);
+
+    jmethodID pseudorangeRateSetterMethod = env->GetMethodID(
+            gpsMeasurementClass,
+            "setPseudorangeRateInMetersPerSec",
+            doubleSignature);
+    env->CallVoidMethod(
+            gpsMeasurementObject,
+            pseudorangeRateSetterMethod,
+            measurement->pseudorange_rate_mps);
+
+    jmethodID pseudorangeRateUncertaintySetterMethod = env->GetMethodID(
+            gpsMeasurementClass,
+            "setPseudorangeRateUncertaintyInMetersPerSec",
+            doubleSignature);
+    env->CallVoidMethod(
+            gpsMeasurementObject,
+            pseudorangeRateUncertaintySetterMethod,
+            measurement->pseudorange_rate_uncertainty_mps);
+
+    jmethodID accumulatedDeltaRangeStateSetterMethod =
+            env->GetMethodID(gpsMeasurementClass, "setAccumulatedDeltaRangeState", shortSignature);
+    env->CallVoidMethod(
+            gpsMeasurementObject,
+            accumulatedDeltaRangeStateSetterMethod,
+            measurement->accumulated_delta_range_state);
+
+    jmethodID accumulatedDeltaRangeSetterMethod = env->GetMethodID(
+            gpsMeasurementClass,
+            "setAccumulatedDeltaRangeInMeters",
+            doubleSignature);
+    env->CallVoidMethod(
+            gpsMeasurementObject,
+            accumulatedDeltaRangeSetterMethod,
+            measurement->accumulated_delta_range_m);
+
+    jmethodID accumulatedDeltaRangeUncertaintySetterMethod = env->GetMethodID(
+            gpsMeasurementClass,
+            "setAccumulatedDeltaRangeUncertaintyInMeters",
+            doubleSignature);
+    env->CallVoidMethod(
+            gpsMeasurementObject,
+            accumulatedDeltaRangeUncertaintySetterMethod,
+            measurement->accumulated_delta_range_uncertainty_m);
+
+    if (flags & GPS_MEASUREMENT_HAS_PSEUDORANGE) {
+        jmethodID setterMethod =
+                env->GetMethodID(gpsMeasurementClass, "setPseudorangeInMeters", doubleSignature);
+        env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->pseudorange_m);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY) {
+        jmethodID setterMethod = env->GetMethodID(
+                gpsMeasurementClass,
+                "setPseudorangeUncertaintyInMeters",
+                doubleSignature);
+        env->CallVoidMethod(
+                gpsMeasurementObject,
+                setterMethod,
+                measurement->pseudorange_uncertainty_m);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_CODE_PHASE) {
+        jmethodID setterMethod =
+                env->GetMethodID(gpsMeasurementClass, "setCodePhaseInChips", doubleSignature);
+        env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->code_phase_chips);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY) {
+        jmethodID setterMethod = env->GetMethodID(
+                gpsMeasurementClass,
+                "setCodePhaseUncertaintyInChips",
+                doubleSignature);
+        env->CallVoidMethod(
+                gpsMeasurementObject,
+                setterMethod,
+                measurement->code_phase_uncertainty_chips);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_CARRIER_FREQUENCY) {
+        jmethodID setterMethod =
+                env->GetMethodID(gpsMeasurementClass, "setCarrierFrequencyInHz", floatSignature);
+        env->CallVoidMethod(
+                gpsMeasurementObject,
+                setterMethod,
+                measurement->carrier_frequency_hz);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_CARRIER_CYCLES) {
+        jmethodID setterMethod =
+                env->GetMethodID(gpsMeasurementClass, "setCarrierCycles", longSignature);
+        env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->carrier_cycles);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_CARRIER_PHASE) {
+        jmethodID setterMethod =
+                env->GetMethodID(gpsMeasurementClass, "setCarrierPhase", doubleSignature);
+        env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->carrier_phase);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY) {
+        jmethodID setterMethod = env->GetMethodID(
+                gpsMeasurementClass,
+                "setCarrierPhaseUncertainty",
+                doubleSignature);
+        env->CallVoidMethod(
+                gpsMeasurementObject,
+                setterMethod,
+                measurement->carrier_phase_uncertainty);
+    }
+
+    jmethodID lossOfLockSetterMethod =
+            env->GetMethodID(gpsMeasurementClass, "setLossOfLock", byteSignature);
+    env->CallVoidMethod(gpsMeasurementObject, lossOfLockSetterMethod, measurement->loss_of_lock);
+
+    if (flags & GPS_MEASUREMENT_HAS_BIT_NUMBER) {
+        jmethodID setterMethod =
+                env->GetMethodID(gpsMeasurementClass, "setBitNumber", intSignature);
+        env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->bit_number);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT) {
+        jmethodID setterMethod =
+                env->GetMethodID(gpsMeasurementClass, "setTimeFromLastBitInMs", shortSignature);
+        env->CallVoidMethod(
+                gpsMeasurementObject,
+                setterMethod,
+                measurement->time_from_last_bit_ms);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_DOPPLER_SHIFT) {
+        jmethodID setterMethod =
+                env->GetMethodID(gpsMeasurementClass, "setDopplerShiftInHz", doubleSignature);
+        env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->doppler_shift_hz);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY) {
+        jmethodID setterMethod = env->GetMethodID(
+                gpsMeasurementClass,
+                "setDopplerShiftUncertaintyInHz",
+                doubleSignature);
+        env->CallVoidMethod(
+                gpsMeasurementObject,
+                setterMethod,
+                measurement->doppler_shift_uncertainty_hz);
+    }
+
+    jmethodID multipathIndicatorSetterMethod =
+            env->GetMethodID(gpsMeasurementClass, "setMultipathIndicator", byteSignature);
+    env->CallVoidMethod(
+            gpsMeasurementObject,
+            multipathIndicatorSetterMethod,
+            measurement->multipath_indicator);
+
+    if (flags & GPS_MEASUREMENT_HAS_SNR) {
+        jmethodID setterMethod =
+                env->GetMethodID(gpsMeasurementClass, "setSnrInDb", doubleSignature);
+        env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->snr_db);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_ELEVATION) {
+        jmethodID setterMethod =
+                env->GetMethodID(gpsMeasurementClass, "setElevationInDeg", doubleSignature);
+        env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->elevation_deg);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY) {
+        jmethodID setterMethod =
+                env->GetMethodID(gpsMeasurementClass, "setElevationUncertaintyInDeg", doubleSignature);
+        env->CallVoidMethod(
+                gpsMeasurementObject,
+                setterMethod,
+                measurement->elevation_uncertainty_deg);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_AZIMUTH) {
+        jmethodID setterMethod =
+                env->GetMethodID(gpsMeasurementClass, "setAzimuthInDeg", doubleSignature);
+        env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->azimuth_deg);
+    }
+
+    if (flags & GPS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY) {
+        jmethodID setterMethod = env->GetMethodID(
+                gpsMeasurementClass,
+                "setAzimuthUncertaintyInDeg",
+                doubleSignature);
+        env->CallVoidMethod(
+                gpsMeasurementObject,
+                setterMethod,
+                measurement->azimuth_uncertainty_deg);
+    }
+
+    jmethodID usedInFixSetterMethod = env->GetMethodID(gpsMeasurementClass, "setUsedInFix", "(Z)V");
+    env->CallVoidMethod(
+            gpsMeasurementObject,
+            usedInFixSetterMethod,
+            (flags & GPS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
+
+    if (size == sizeof(GpsMeasurement)) {
+      jmethodID setterMethod =
+          env->GetMethodID(gpsMeasurementClass,
+                           "setPseudorangeRateCarrierInMetersPerSec",
+                           doubleSignature);
+      env->CallVoidMethod(
+          gpsMeasurementObject,
+          setterMethod,
+          measurement->pseudorange_rate_carrier_mps);
+
+      setterMethod =
+          env->GetMethodID(gpsMeasurementClass,
+                           "setPseudorangeRateCarrierUncertaintyInMetersPerSec",
+                           doubleSignature);
+      env->CallVoidMethod(
+          gpsMeasurementObject,
+          setterMethod,
+          measurement->pseudorange_rate_carrier_uncertainty_mps);
+    }
+
+    env->DeleteLocalRef(gpsMeasurementClass);
+    return gpsMeasurementObject;
+}
+
+/**
+ * <T> can only be GpsData or GpsData_v1. Must rewrite this function if more
+ * types are introduced in the future releases.
+ */
+template<class T>
+static jobjectArray translate_gps_measurements(JNIEnv* env, void* data) {
+    T* gps_data = reinterpret_cast<T*>(data);
+    size_t measurementCount = gps_data->measurement_count;
+    if (measurementCount == 0) {
+        return NULL;
+    }
+
+    jclass gpsMeasurementClass = env->FindClass("android/location/GpsMeasurement");
+    jobjectArray gpsMeasurementArray = env->NewObjectArray(
+            measurementCount,
+            gpsMeasurementClass,
+            NULL /* initialElement */);
+
+    for (uint16_t i = 0; i < measurementCount; ++i) {
+        jobject gpsMeasurement = translate_gps_measurement(
+            env,
+            &(gps_data->measurements[i]),
+            sizeof(gps_data->measurements[0]));
+        env->SetObjectArrayElement(gpsMeasurementArray, i, gpsMeasurement);
+        env->DeleteLocalRef(gpsMeasurement);
+    }
+
+    env->DeleteLocalRef(gpsMeasurementClass);
+    return gpsMeasurementArray;
+}
+
+static void measurement_callback(GpsData* data) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (data == NULL) {
+        ALOGE("Invalid data provided to gps_measurement_callback");
+        return;
+    }
+    if (data->size != sizeof(GpsData) && data->size != sizeof(GpsData_v1)) {
+        ALOGE("Invalid GpsData size found in gps_measurement_callback, size=%zd", data->size);
+        return;
+    }
+
+    jobject gpsClock;
+    jobjectArray measurementArray;
+    if (data->size == sizeof(GpsData)) {
+        gpsClock = translate_gps_clock(env, &data->clock, sizeof(GpsClock));
+        measurementArray = translate_gps_measurements<GpsData>(env, data);
+    } else {
+        gpsClock = translate_gps_clock(env, &data->clock, sizeof(GpsClock_v1));
+        measurementArray = translate_gps_measurements<GpsData_v1>(env, data);
+    }
+    jclass gpsMeasurementsEventClass = env->FindClass("android/location/GpsMeasurementsEvent");
+    jmethodID gpsMeasurementsEventCtor = env->GetMethodID(
+        gpsMeasurementsEventClass,
+        "<init>",
+        "(Landroid/location/GpsClock;[Landroid/location/GpsMeasurement;)V");
+
+    jobject gpsMeasurementsEvent = env->NewObject(
+        gpsMeasurementsEventClass,
+        gpsMeasurementsEventCtor,
+        gpsClock,
+        measurementArray);
+
+    env->CallVoidMethod(mCallbacksObj, method_reportMeasurementData, gpsMeasurementsEvent);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+
+    env->DeleteLocalRef(gpsClock);
+    env->DeleteLocalRef(measurementArray);
+    env->DeleteLocalRef(gpsMeasurementsEventClass);
+    env->DeleteLocalRef(gpsMeasurementsEvent);
+}
+
+GpsMeasurementCallbacks sGpsMeasurementCallbacks = {
+    sizeof(GpsMeasurementCallbacks),
+    measurement_callback,
+};
+
+static jboolean android_location_GnssLocationProvider_is_measurement_supported(
+        JNIEnv* env,
+        jclass clazz) {
+    if (sGpsMeasurementInterface != NULL) {
+        return JNI_TRUE;
+    }
+    return JNI_FALSE;
+}
+
+static jboolean android_location_GnssLocationProvider_start_measurement_collection(
+        JNIEnv* env,
+        jobject obj) {
+    if (sGpsMeasurementInterface == NULL) {
+        ALOGE("Measurement interface is not available.");
+        return JNI_FALSE;
+    }
+
+    int result = sGpsMeasurementInterface->init(&sGpsMeasurementCallbacks);
+    if (result != GPS_GEOFENCE_OPERATION_SUCCESS) {
+        ALOGE("An error has been found on GpsMeasurementInterface::init, status=%d", result);
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+
+static jboolean android_location_GnssLocationProvider_stop_measurement_collection(
+        JNIEnv* env,
+        jobject obj) {
+    if (sGpsMeasurementInterface == NULL) {
+        ALOGE("Measurement interface not available");
+        return JNI_FALSE;
+    }
+
+    sGpsMeasurementInterface->close();
+    return JNI_TRUE;
+}
+
+static jobject translate_gps_navigation_message(JNIEnv* env, GpsNavigationMessage* message) {
+    size_t dataLength = message->data_length;
+    uint8_t* data = message->data;
+    if (dataLength == 0 || data == NULL) {
+        ALOGE("Invalid Navigation Message found: data=%p, length=%zd", data, dataLength);
+        return NULL;
+    }
+
+    jclass navigationMessageClass = env->FindClass("android/location/GpsNavigationMessage");
+    jmethodID navigationMessageCtor = env->GetMethodID(navigationMessageClass, "<init>", "()V");
+    jobject navigationMessageObject = env->NewObject(navigationMessageClass, navigationMessageCtor);
+
+    jmethodID setTypeMethod = env->GetMethodID(navigationMessageClass, "setType", "(B)V");
+    env->CallVoidMethod(navigationMessageObject, setTypeMethod, message->type);
+
+    jmethodID setPrnMethod = env->GetMethodID(navigationMessageClass, "setPrn", "(B)V");
+    env->CallVoidMethod(navigationMessageObject, setPrnMethod, message->prn);
+
+    jmethodID setMessageIdMethod = env->GetMethodID(navigationMessageClass, "setMessageId", "(S)V");
+    env->CallVoidMethod(navigationMessageObject, setMessageIdMethod, message->message_id);
+
+    jmethodID setSubmessageIdMethod =
+            env->GetMethodID(navigationMessageClass, "setSubmessageId", "(S)V");
+    env->CallVoidMethod(navigationMessageObject, setSubmessageIdMethod, message->submessage_id);
+
+    jbyteArray dataArray = env->NewByteArray(dataLength);
+    env->SetByteArrayRegion(dataArray, 0, dataLength, (jbyte*) data);
+    jmethodID setDataMethod = env->GetMethodID(navigationMessageClass, "setData", "([B)V");
+    env->CallVoidMethod(navigationMessageObject, setDataMethod, dataArray);
+
+    env->DeleteLocalRef(navigationMessageClass);
+    env->DeleteLocalRef(dataArray);
+    return navigationMessageObject;
+}
+
+static void navigation_message_callback(GpsNavigationMessage* message) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (message == NULL) {
+        ALOGE("Invalid Navigation Message provided to callback");
+        return;
+    }
+
+    if (message->size == sizeof(GpsNavigationMessage)) {
+        jobject navigationMessage = translate_gps_navigation_message(env, message);
+
+        jclass navigationMessageEventClass =
+                env->FindClass("android/location/GpsNavigationMessageEvent");
+        jmethodID navigationMessageEventCtor = env->GetMethodID(
+                navigationMessageEventClass,
+                "<init>",
+                "(Landroid/location/GpsNavigationMessage;)V");
+        jobject navigationMessageEvent = env->NewObject(
+                navigationMessageEventClass,
+                navigationMessageEventCtor,
+                navigationMessage);
+
+        env->CallVoidMethod(mCallbacksObj, method_reportNavigationMessages, navigationMessageEvent);
+        checkAndClearExceptionFromCallback(env, __FUNCTION__);
+
+        env->DeleteLocalRef(navigationMessage);
+        env->DeleteLocalRef(navigationMessageEventClass);
+        env->DeleteLocalRef(navigationMessageEvent);
+    } else {
+        ALOGE("Invalid GpsNavigationMessage size found: %zd", message->size);
+    }
+}
+
+GpsNavigationMessageCallbacks sGpsNavigationMessageCallbacks = {
+    sizeof(GpsNavigationMessageCallbacks),
+    navigation_message_callback,
+};
+
+static jboolean android_location_GnssLocationProvider_is_navigation_message_supported(
+        JNIEnv* env,
+        jclass clazz) {
+    if(sGpsNavigationMessageInterface != NULL) {
+        return JNI_TRUE;
+    }
+    return JNI_FALSE;
+}
+
+static jboolean android_location_GnssLocationProvider_start_navigation_message_collection(
+        JNIEnv* env,
+        jobject obj) {
+    if (sGpsNavigationMessageInterface == NULL) {
+        ALOGE("Navigation Message interface is not available.");
+        return JNI_FALSE;
+    }
+
+    int result = sGpsNavigationMessageInterface->init(&sGpsNavigationMessageCallbacks);
+    if (result != GPS_NAVIGATION_MESSAGE_OPERATION_SUCCESS) {
+        ALOGE("An error has been found in %s: %d", __FUNCTION__, result);
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+
+static jboolean android_location_GnssLocationProvider_stop_navigation_message_collection(
+        JNIEnv* env,
+        jobject obj) {
+    if (sGpsNavigationMessageInterface == NULL) {
+        ALOGE("Navigation Message interface is not available.");
+        return JNI_FALSE;
+    }
+
+    sGpsNavigationMessageInterface->close();
+    return JNI_TRUE;
+}
+
+static void android_location_GnssLocationProvider_configuration_update(JNIEnv* env, jobject obj,
+        jstring config_content)
+{
+    if (!sGnssConfigurationInterface) {
+        ALOGE("no GPS configuration interface in configuraiton_update");
+        return;
+    }
+    const char *data = env->GetStringUTFChars(config_content, NULL);
+    ALOGD("GPS configuration:\n %s", data);
+    sGnssConfigurationInterface->configuration_update(
+            data, env->GetStringUTFLength(config_content));
+    env->ReleaseStringUTFChars(config_content, data);
+}
+
+static const JNINativeMethod sMethods[] = {
+     /* name, signature, funcPtr */
+    {"class_init_native", "()V", (void *)android_location_GnssLocationProvider_class_init_native},
+    {"native_is_supported", "()Z", (void*)android_location_GnssLocationProvider_is_supported},
+    {"native_is_agps_ril_supported", "()Z",
+            (void*)android_location_GnssLocationProvider_is_agps_ril_supported},
+    {"native_is_gnss_configuration_supported", "()Z",
+            (void*)android_location_gpsLocationProvider_is_gnss_configuration_supported},
+    {"native_init", "()Z", (void*)android_location_GnssLocationProvider_init},
+    {"native_cleanup", "()V", (void*)android_location_GnssLocationProvider_cleanup},
+    {"native_set_position_mode",
+            "(IIIII)Z",
+            (void*)android_location_GnssLocationProvider_set_position_mode},
+    {"native_start", "()Z", (void*)android_location_GnssLocationProvider_start},
+    {"native_stop", "()Z", (void*)android_location_GnssLocationProvider_stop},
+    {"native_delete_aiding_data",
+            "(I)V",
+            (void*)android_location_GnssLocationProvider_delete_aiding_data},
+    {"native_read_sv_status",
+            "([I[F[F[F[I)I",
+            (void*)android_location_GnssLocationProvider_read_sv_status},
+    {"native_read_nmea", "([BI)I", (void*)android_location_GnssLocationProvider_read_nmea},
+    {"native_inject_time", "(JJI)V", (void*)android_location_GnssLocationProvider_inject_time},
+    {"native_inject_location",
+            "(DDF)V",
+            (void*)android_location_GnssLocationProvider_inject_location},
+    {"native_supports_xtra", "()Z", (void*)android_location_GnssLocationProvider_supports_xtra},
+    {"native_inject_xtra_data",
+            "([BI)V",
+            (void*)android_location_GnssLocationProvider_inject_xtra_data},
+    {"native_agps_data_conn_open",
+            "(Ljava/lang/String;I)V",
+            (void*)android_location_GnssLocationProvider_agps_data_conn_open},
+    {"native_agps_data_conn_closed",
+            "()V",
+            (void*)android_location_GnssLocationProvider_agps_data_conn_closed},
+    {"native_agps_data_conn_failed",
+            "()V",
+            (void*)android_location_GnssLocationProvider_agps_data_conn_failed},
+    {"native_agps_set_id",
+            "(ILjava/lang/String;)V",
+            (void*)android_location_GnssLocationProvider_agps_set_id},
+    {"native_agps_set_ref_location_cellid",
+            "(IIIII)V",
+            (void*)android_location_GnssLocationProvider_agps_set_reference_location_cellid},
+    {"native_set_agps_server",
+            "(ILjava/lang/String;I)V",
+            (void*)android_location_GnssLocationProvider_set_agps_server},
+    {"native_send_ni_response",
+            "(II)V",
+            (void*)android_location_GnssLocationProvider_send_ni_response},
+    {"native_agps_ni_message",
+            "([BI)V",
+            (void *)android_location_GnssLocationProvider_agps_send_ni_message},
+    {"native_get_internal_state",
+            "()Ljava/lang/String;",
+            (void*)android_location_GnssLocationProvider_get_internal_state},
+    {"native_update_network_state",
+            "(ZIZZLjava/lang/String;Ljava/lang/String;)V",
+            (void*)android_location_GnssLocationProvider_update_network_state },
+    {"native_is_geofence_supported",
+            "()Z",
+            (void*) android_location_GnssLocationProvider_is_geofence_supported},
+    {"native_add_geofence",
+            "(IDDDIIII)Z",
+            (void *)android_location_GnssLocationProvider_add_geofence},
+    {"native_remove_geofence",
+            "(I)Z",
+            (void *)android_location_GnssLocationProvider_remove_geofence},
+    {"native_pause_geofence", "(I)Z", (void *)android_location_GnssLocationProvider_pause_geofence},
+    {"native_resume_geofence",
+            "(II)Z",
+            (void *)android_location_GnssLocationProvider_resume_geofence},
+    {"native_is_measurement_supported",
+            "()Z",
+            (void*) android_location_GnssLocationProvider_is_measurement_supported},
+    {"native_start_measurement_collection",
+            "()Z",
+            (void*) android_location_GnssLocationProvider_start_measurement_collection},
+    {"native_stop_measurement_collection",
+            "()Z",
+            (void*) android_location_GnssLocationProvider_stop_measurement_collection},
+    {"native_is_navigation_message_supported",
+            "()Z",
+            (void*) android_location_GnssLocationProvider_is_navigation_message_supported},
+    {"native_start_navigation_message_collection",
+            "()Z",
+            (void*) android_location_GnssLocationProvider_start_navigation_message_collection},
+    {"native_stop_navigation_message_collection",
+            "()Z",
+            (void*) android_location_GnssLocationProvider_stop_navigation_message_collection},
+    {"native_configuration_update",
+            "(Ljava/lang/String;)V",
+            (void*)android_location_GnssLocationProvider_configuration_update},
+};
+
+int register_android_server_location_GnssLocationProvider(JNIEnv* env)
+{
+    return jniRegisterNativeMethods(
+            env,
+            "com/android/server/location/GnssLocationProvider",
+            sMethods,
+            NELEM(sMethods));
+}
+
+} /* namespace android */
diff --git a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
deleted file mode 100644
index b8d4196..0000000
--- a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
+++ /dev/null
@@ -1,1542 +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.
- */
-
-#define LOG_TAG "GpsLocationProvider"
-
-#define LOG_NDEBUG 0
-
-#include "JNIHelp.h"
-#include "jni.h"
-#include "hardware/hardware.h"
-#include "hardware/gps.h"
-#include "hardware_legacy/power.h"
-#include "utils/Log.h"
-#include "utils/misc.h"
-#include "android_runtime/AndroidRuntime.h"
-#include "android_runtime/Log.h"
-
-#include <arpa/inet.h>
-#include <string.h>
-#include <pthread.h>
-#include <linux/in.h>
-#include <linux/in6.h>
-
-static jobject mCallbacksObj = NULL;
-
-static jmethodID method_reportLocation;
-static jmethodID method_reportStatus;
-static jmethodID method_reportSvStatus;
-static jmethodID method_reportAGpsStatus;
-static jmethodID method_reportNmea;
-static jmethodID method_setEngineCapabilities;
-static jmethodID method_xtraDownloadRequest;
-static jmethodID method_reportNiNotification;
-static jmethodID method_requestRefLocation;
-static jmethodID method_requestSetID;
-static jmethodID method_requestUtcTime;
-static jmethodID method_reportGeofenceTransition;
-static jmethodID method_reportGeofenceStatus;
-static jmethodID method_reportGeofenceAddStatus;
-static jmethodID method_reportGeofenceRemoveStatus;
-static jmethodID method_reportGeofencePauseStatus;
-static jmethodID method_reportGeofenceResumeStatus;
-static jmethodID method_reportMeasurementData;
-static jmethodID method_reportNavigationMessages;
-
-static const GpsInterface* sGpsInterface = NULL;
-static const GpsXtraInterface* sGpsXtraInterface = NULL;
-static const AGpsInterface* sAGpsInterface = NULL;
-static const GpsNiInterface* sGpsNiInterface = NULL;
-static const GpsDebugInterface* sGpsDebugInterface = NULL;
-static const AGpsRilInterface* sAGpsRilInterface = NULL;
-static const GpsGeofencingInterface* sGpsGeofencingInterface = NULL;
-static const GpsMeasurementInterface* sGpsMeasurementInterface = NULL;
-static const GpsNavigationMessageInterface* sGpsNavigationMessageInterface = NULL;
-static const GnssConfigurationInterface* sGnssConfigurationInterface = NULL;
-
-// temporary storage for GPS callbacks
-static GpsSvStatus  sGpsSvStatus;
-static const char* sNmeaString;
-static int sNmeaStringLength;
-
-#define WAKE_LOCK_NAME  "GPS"
-
-namespace android {
-
-static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
-    if (env->ExceptionCheck()) {
-        ALOGE("An exception was thrown by callback '%s'.", methodName);
-        LOGE_EX(env);
-        env->ExceptionClear();
-    }
-}
-
-static void location_callback(GpsLocation* location)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->CallVoidMethod(mCallbacksObj, method_reportLocation, location->flags,
-            (jdouble)location->latitude, (jdouble)location->longitude,
-            (jdouble)location->altitude,
-            (jfloat)location->speed, (jfloat)location->bearing,
-            (jfloat)location->accuracy, (jlong)location->timestamp);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-static void status_callback(GpsStatus* status)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->CallVoidMethod(mCallbacksObj, method_reportStatus, status->status);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-static void sv_status_callback(GpsSvStatus* sv_status)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    memcpy(&sGpsSvStatus, sv_status, sizeof(sGpsSvStatus));
-    env->CallVoidMethod(mCallbacksObj, method_reportSvStatus);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-static void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    // The Java code will call back to read these values
-    // We do this to avoid creating unnecessary String objects
-    sNmeaString = nmea;
-    sNmeaStringLength = length;
-    env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-static void set_capabilities_callback(uint32_t capabilities)
-{
-    ALOGD("set_capabilities_callback: %du\n", capabilities);
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-static void acquire_wakelock_callback()
-{
-    acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
-}
-
-static void release_wakelock_callback()
-{
-    release_wake_lock(WAKE_LOCK_NAME);
-}
-
-static void request_utc_time_callback()
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg)
-{
-    return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);
-}
-
-GpsCallbacks sGpsCallbacks = {
-    sizeof(GpsCallbacks),
-    location_callback,
-    status_callback,
-    sv_status_callback,
-    nmea_callback,
-    set_capabilities_callback,
-    acquire_wakelock_callback,
-    release_wakelock_callback,
-    create_thread_callback,
-    request_utc_time_callback,
-};
-
-static void xtra_download_request_callback()
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->CallVoidMethod(mCallbacksObj, method_xtraDownloadRequest);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-GpsXtraCallbacks sGpsXtraCallbacks = {
-    xtra_download_request_callback,
-    create_thread_callback,
-};
-
-static jbyteArray convert_to_ipv4(uint32_t ip, bool net_order)
-{
-    if (INADDR_NONE == ip) {
-        return NULL;
-    }
-
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    jbyteArray byteArray = env->NewByteArray(4);
-    if (byteArray == NULL) {
-        ALOGE("Unable to allocate byte array for IPv4 address");
-        return NULL;
-    }
-
-    jbyte ipv4[4];
-    if (net_order) {
-        ALOGV("Converting IPv4 address(net_order) %x", ip);
-        memcpy(ipv4, &ip, sizeof(ipv4));
-    } else {
-        ALOGV("Converting IPv4 address(host_order) %x", ip);
-        //endianess transparent conversion from int to char[]
-        ipv4[0] = (jbyte) (ip & 0xFF);
-        ipv4[1] = (jbyte)((ip>>8) & 0xFF);
-        ipv4[2] = (jbyte)((ip>>16) & 0xFF);
-        ipv4[3] = (jbyte) (ip>>24);
-    }
-
-    env->SetByteArrayRegion(byteArray, 0, 4, (const jbyte*) ipv4);
-    return byteArray;
-}
-
-static void agps_status_callback(AGpsStatus* agps_status)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    jbyteArray byteArray = NULL;
-    bool isSupported = false;
-
-    size_t status_size = agps_status->size;
-    if (status_size == sizeof(AGpsStatus_v3)) {
-      ALOGV("AGpsStatus is V3: %zd", status_size);
-      switch (agps_status->addr.ss_family)
-      {
-      case AF_INET:
-          {
-            struct sockaddr_in *in = (struct sockaddr_in*)&(agps_status->addr);
-            uint32_t ipAddr = *(uint32_t*)&(in->sin_addr);
-            byteArray = convert_to_ipv4(ipAddr, true /* net_order */);
-            if (ipAddr == INADDR_NONE || byteArray != NULL) {
-                isSupported = true;
-            }
-            IF_ALOGD() {
-                // log the IP for reference in case there is a bogus value pushed by HAL
-                char str[INET_ADDRSTRLEN];
-                inet_ntop(AF_INET, &(in->sin_addr), str, INET_ADDRSTRLEN);
-                ALOGD("AGPS IP is v4: %s", str);
-            }
-          }
-          break;
-      case AF_INET6:
-          {
-            struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&(agps_status->addr);
-            byteArray = env->NewByteArray(16);
-            if (byteArray != NULL) {
-                env->SetByteArrayRegion(byteArray, 0, 16, (const jbyte *)&(in6->sin6_addr));
-                isSupported = true;
-            } else {
-                ALOGE("Unable to allocate byte array for IPv6 address.");
-            }
-            IF_ALOGD() {
-                // log the IP for reference in case there is a bogus value pushed by HAL
-                char str[INET6_ADDRSTRLEN];
-                inet_ntop(AF_INET6, &(in6->sin6_addr), str, INET6_ADDRSTRLEN);
-                ALOGD("AGPS IP is v6: %s", str);
-            }
-          }
-          break;
-      default:
-          ALOGE("Invalid ss_family found: %d", agps_status->addr.ss_family);
-          break;
-      }
-    } else if (status_size >= sizeof(AGpsStatus_v2)) {
-      ALOGV("AGpsStatus is V2+: %zd", status_size);
-      // for back-compatibility reasons we check in v2 that the data structure size is greater or
-      // equal to the declared size in gps.h
-      uint32_t ipaddr = agps_status->ipaddr;
-      ALOGV("AGPS IP is v4: %x", ipaddr);
-      byteArray = convert_to_ipv4(ipaddr, false /* net_order */);
-      if (ipaddr == INADDR_NONE || byteArray != NULL) {
-          isSupported = true;
-      }
-    } else if (status_size >= sizeof(AGpsStatus_v1)) {
-        ALOGV("AGpsStatus is V1+: %zd", status_size);
-        // because we have to check for >= with regards to v2, we also need to relax the check here
-        // and only make sure that the size is at least what we expect
-        isSupported = true;
-    } else {
-        ALOGE("Invalid size of AGpsStatus found: %zd.", status_size);
-    }
-
-    if (isSupported) {
-        jsize byteArrayLength = byteArray != NULL ? env->GetArrayLength(byteArray) : 0;
-        ALOGV("Passing AGPS IP addr: size %d", byteArrayLength);
-        env->CallVoidMethod(mCallbacksObj, method_reportAGpsStatus, agps_status->type,
-                            agps_status->status, byteArray);
-
-        checkAndClearExceptionFromCallback(env, __FUNCTION__);
-    } else {
-        ALOGD("Skipping calling method_reportAGpsStatus.");
-    }
-
-    if (byteArray) {
-        env->DeleteLocalRef(byteArray);
-    }
-}
-
-AGpsCallbacks sAGpsCallbacks = {
-    agps_status_callback,
-    create_thread_callback,
-};
-
-static void gps_ni_notify_callback(GpsNiNotification *notification)
-{
-    ALOGD("gps_ni_notify_callback\n");
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    jstring requestor_id = env->NewStringUTF(notification->requestor_id);
-    jstring text = env->NewStringUTF(notification->text);
-    jstring extras = env->NewStringUTF(notification->extras);
-
-    if (requestor_id && text && extras) {
-        env->CallVoidMethod(mCallbacksObj, method_reportNiNotification,
-            notification->notification_id, notification->ni_type,
-            notification->notify_flags, notification->timeout,
-            notification->default_response, requestor_id, text,
-            notification->requestor_id_encoding,
-            notification->text_encoding, extras);
-    } else {
-        ALOGE("out of memory in gps_ni_notify_callback\n");
-    }
-
-    if (requestor_id)
-        env->DeleteLocalRef(requestor_id);
-    if (text)
-        env->DeleteLocalRef(text);
-    if (extras)
-        env->DeleteLocalRef(extras);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-GpsNiCallbacks sGpsNiCallbacks = {
-    gps_ni_notify_callback,
-    create_thread_callback,
-};
-
-static void agps_request_set_id(uint32_t flags)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->CallVoidMethod(mCallbacksObj, method_requestSetID, flags);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-static void agps_request_ref_location(uint32_t flags)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->CallVoidMethod(mCallbacksObj, method_requestRefLocation, flags);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-AGpsRilCallbacks sAGpsRilCallbacks = {
-    agps_request_set_id,
-    agps_request_ref_location,
-    create_thread_callback,
-};
-
-static void gps_geofence_transition_callback(int32_t geofence_id,  GpsLocation* location,
-        int32_t transition, GpsUtcTime timestamp)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-
-    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceTransition, geofence_id,
-            location->flags, (jdouble)location->latitude, (jdouble)location->longitude,
-            (jdouble)location->altitude,
-            (jfloat)location->speed, (jfloat)location->bearing,
-            (jfloat)location->accuracy, (jlong)location->timestamp,
-            transition, timestamp);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-};
-
-static void gps_geofence_status_callback(int32_t status, GpsLocation* location)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    jint flags = 0;
-    jdouble latitude = 0;
-    jdouble longitude = 0;
-    jdouble altitude = 0;
-    jfloat speed = 0;
-    jfloat bearing = 0;
-    jfloat accuracy = 0;
-    jlong timestamp = 0;
-    if (location != NULL) {
-        flags = location->flags;
-        latitude = location->latitude;
-        longitude = location->longitude;
-        altitude = location->altitude;
-        speed = location->speed;
-        bearing = location->bearing;
-        accuracy = location->accuracy;
-        timestamp = location->timestamp;
-    }
-
-    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceStatus, status,
-            flags, latitude, longitude, altitude, speed, bearing, accuracy, timestamp);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-};
-
-static void gps_geofence_add_callback(int32_t geofence_id, int32_t status)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
-        ALOGE("Error in geofence_add_callback: %d\n", status);
-    }
-    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceAddStatus, geofence_id, status);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-};
-
-static void gps_geofence_remove_callback(int32_t geofence_id, int32_t status)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
-        ALOGE("Error in geofence_remove_callback: %d\n", status);
-    }
-    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceRemoveStatus, geofence_id, status);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-};
-
-static void gps_geofence_resume_callback(int32_t geofence_id, int32_t status)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
-        ALOGE("Error in geofence_resume_callback: %d\n", status);
-    }
-    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceResumeStatus, geofence_id, status);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-};
-
-static void gps_geofence_pause_callback(int32_t geofence_id, int32_t status)
-{
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
-        ALOGE("Error in geofence_pause_callback: %d\n", status);
-    }
-    env->CallVoidMethod(mCallbacksObj, method_reportGeofencePauseStatus, geofence_id, status);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-};
-
-GpsGeofenceCallbacks sGpsGeofenceCallbacks = {
-    gps_geofence_transition_callback,
-    gps_geofence_status_callback,
-    gps_geofence_add_callback,
-    gps_geofence_remove_callback,
-    gps_geofence_pause_callback,
-    gps_geofence_resume_callback,
-    create_thread_callback,
-};
-
-static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
-    int err;
-    hw_module_t* module;
-
-    method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
-    method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
-    method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
-    method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II[B)V");
-    method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
-    method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
-    method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
-    method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification",
-            "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
-    method_requestRefLocation = env->GetMethodID(clazz,"requestRefLocation","(I)V");
-    method_requestSetID = env->GetMethodID(clazz,"requestSetID","(I)V");
-    method_requestUtcTime = env->GetMethodID(clazz,"requestUtcTime","()V");
-    method_reportGeofenceTransition = env->GetMethodID(clazz,"reportGeofenceTransition",
-            "(IIDDDFFFJIJ)V");
-    method_reportGeofenceStatus = env->GetMethodID(clazz,"reportGeofenceStatus",
-            "(IIDDDFFFJ)V");
-    method_reportGeofenceAddStatus = env->GetMethodID(clazz,"reportGeofenceAddStatus",
-            "(II)V");
-    method_reportGeofenceRemoveStatus = env->GetMethodID(clazz,"reportGeofenceRemoveStatus",
-            "(II)V");
-    method_reportGeofenceResumeStatus = env->GetMethodID(clazz,"reportGeofenceResumeStatus",
-            "(II)V");
-    method_reportGeofencePauseStatus = env->GetMethodID(clazz,"reportGeofencePauseStatus",
-            "(II)V");
-    method_reportMeasurementData = env->GetMethodID(
-            clazz,
-            "reportMeasurementData",
-            "(Landroid/location/GpsMeasurementsEvent;)V");
-    method_reportNavigationMessages = env->GetMethodID(
-            clazz,
-            "reportNavigationMessage",
-            "(Landroid/location/GpsNavigationMessageEvent;)V");
-
-    err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
-    if (err == 0) {
-        hw_device_t* device;
-        err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
-        if (err == 0) {
-            gps_device_t* gps_device = (gps_device_t *)device;
-            sGpsInterface = gps_device->get_gps_interface(gps_device);
-        }
-    }
-    if (sGpsInterface) {
-        sGpsXtraInterface =
-            (const GpsXtraInterface*)sGpsInterface->get_extension(GPS_XTRA_INTERFACE);
-        sAGpsInterface =
-            (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
-        sGpsNiInterface =
-            (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
-        sGpsDebugInterface =
-            (const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE);
-        sAGpsRilInterface =
-            (const AGpsRilInterface*)sGpsInterface->get_extension(AGPS_RIL_INTERFACE);
-        sGpsGeofencingInterface =
-            (const GpsGeofencingInterface*)sGpsInterface->get_extension(GPS_GEOFENCING_INTERFACE);
-        sGpsMeasurementInterface =
-            (const GpsMeasurementInterface*)sGpsInterface->get_extension(GPS_MEASUREMENT_INTERFACE);
-        sGpsNavigationMessageInterface =
-            (const GpsNavigationMessageInterface*)sGpsInterface->get_extension(
-                    GPS_NAVIGATION_MESSAGE_INTERFACE);
-        sGnssConfigurationInterface =
-            (const GnssConfigurationInterface*)sGpsInterface->get_extension(
-                    GNSS_CONFIGURATION_INTERFACE);
-    }
-}
-
-static jboolean android_location_GpsLocationProvider_is_supported(
-        JNIEnv* /* env */, jclass /* clazz */)
-{
-    return (sGpsInterface != NULL) ?  JNI_TRUE : JNI_FALSE;
-}
-
-static jboolean android_location_GpsLocationProvider_is_agps_ril_supported(
-        JNIEnv* /* env */, jclass /* clazz */)
-{
-    return (sAGpsRilInterface != NULL) ? JNI_TRUE : JNI_FALSE;
-}
-
-static jboolean android_location_gpsLocationProvider_is_gnss_configuration_supported(
-        JNIEnv* /* env */, jclass /* jclazz */)
-{
-    return (sGnssConfigurationInterface != NULL) ? JNI_TRUE : JNI_FALSE;
-}
-
-static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)
-{
-    // this must be set before calling into the HAL library
-    if (!mCallbacksObj)
-        mCallbacksObj = env->NewGlobalRef(obj);
-
-    // fail if the main interface fails to initialize
-    if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
-        return JNI_FALSE;
-
-    // if XTRA initialization fails we will disable it by sGpsXtraInterface to NULL,
-    // but continue to allow the rest of the GPS interface to work.
-    if (sGpsXtraInterface && sGpsXtraInterface->init(&sGpsXtraCallbacks) != 0)
-        sGpsXtraInterface = NULL;
-    if (sAGpsInterface)
-        sAGpsInterface->init(&sAGpsCallbacks);
-    if (sGpsNiInterface)
-        sGpsNiInterface->init(&sGpsNiCallbacks);
-    if (sAGpsRilInterface)
-        sAGpsRilInterface->init(&sAGpsRilCallbacks);
-    if (sGpsGeofencingInterface)
-        sGpsGeofencingInterface->init(&sGpsGeofenceCallbacks);
-
-    return JNI_TRUE;
-}
-
-static void android_location_GpsLocationProvider_cleanup(JNIEnv* /* env */, jobject /* obj */)
-{
-    if (sGpsInterface)
-        sGpsInterface->cleanup();
-}
-
-static jboolean android_location_GpsLocationProvider_set_position_mode(JNIEnv* /* env */,
-        jobject /* obj */, jint mode, jint recurrence, jint min_interval, jint preferred_accuracy,
-        jint preferred_time)
-{
-    if (sGpsInterface) {
-        if (sGpsInterface->set_position_mode(mode, recurrence, min_interval, preferred_accuracy,
-                preferred_time) == 0) {
-            return JNI_TRUE;
-        } else {
-            return JNI_FALSE;
-        }
-    }
-    else
-        return JNI_FALSE;
-}
-
-static jboolean android_location_GpsLocationProvider_start(JNIEnv* /* env */, jobject /* obj */)
-{
-    if (sGpsInterface) {
-        if (sGpsInterface->start() == 0) {
-            return JNI_TRUE;
-        } else {
-            return JNI_FALSE;
-        }
-    }
-    else
-        return JNI_FALSE;
-}
-
-static jboolean android_location_GpsLocationProvider_stop(JNIEnv* /* env */, jobject /* obj */)
-{
-    if (sGpsInterface) {
-        if (sGpsInterface->stop() == 0) {
-            return JNI_TRUE;
-        } else {
-            return JNI_FALSE;
-        }
-    }
-    else
-        return JNI_FALSE;
-}
-
-static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* /* env */,
-                                                                    jobject /* obj */,
-                                                                    jint flags)
-{
-    if (sGpsInterface)
-        sGpsInterface->delete_aiding_data(flags);
-}
-
-static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject /* obj */,
-        jintArray prnArray, jfloatArray snrArray, jfloatArray elevArray, jfloatArray azumArray,
-        jintArray maskArray)
-{
-    // this should only be called from within a call to reportSvStatus
-
-    jint* prns = env->GetIntArrayElements(prnArray, 0);
-    jfloat* snrs = env->GetFloatArrayElements(snrArray, 0);
-    jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
-    jfloat* azim = env->GetFloatArrayElements(azumArray, 0);
-    jint* mask = env->GetIntArrayElements(maskArray, 0);
-
-    int num_svs = sGpsSvStatus.num_svs;
-    for (int i = 0; i < num_svs; i++) {
-        prns[i] = sGpsSvStatus.sv_list[i].prn;
-        snrs[i] = sGpsSvStatus.sv_list[i].snr;
-        elev[i] = sGpsSvStatus.sv_list[i].elevation;
-        azim[i] = sGpsSvStatus.sv_list[i].azimuth;
-    }
-    mask[0] = sGpsSvStatus.ephemeris_mask;
-    mask[1] = sGpsSvStatus.almanac_mask;
-    mask[2] = sGpsSvStatus.used_in_fix_mask;
-
-    env->ReleaseIntArrayElements(prnArray, prns, 0);
-    env->ReleaseFloatArrayElements(snrArray, snrs, 0);
-    env->ReleaseFloatArrayElements(elevArray, elev, 0);
-    env->ReleaseFloatArrayElements(azumArray, azim, 0);
-    env->ReleaseIntArrayElements(maskArray, mask, 0);
-    return (jint) num_svs;
-}
-
-static void android_location_GpsLocationProvider_agps_set_reference_location_cellid(
-        JNIEnv* /* env */, jobject /* obj */, jint type, jint mcc, jint mnc, jint lac, jint cid)
-{
-    AGpsRefLocation location;
-
-    if (!sAGpsRilInterface) {
-        ALOGE("no AGPS RIL interface in agps_set_reference_location_cellid");
-        return;
-    }
-
-    switch(type) {
-        case AGPS_REF_LOCATION_TYPE_GSM_CELLID:
-        case AGPS_REF_LOCATION_TYPE_UMTS_CELLID:
-            location.type = type;
-            location.u.cellID.mcc = mcc;
-            location.u.cellID.mnc = mnc;
-            location.u.cellID.lac = lac;
-            location.u.cellID.cid = cid;
-            break;
-        default:
-            ALOGE("Neither a GSM nor a UMTS cellid (%s:%d).",__FUNCTION__,__LINE__);
-            return;
-            break;
-    }
-    sAGpsRilInterface->set_ref_location(&location, sizeof(location));
-}
-
-static void android_location_GpsLocationProvider_agps_send_ni_message(JNIEnv* env,
-        jobject /* obj */, jbyteArray ni_msg, jint size)
-{
-    size_t sz;
-
-    if (!sAGpsRilInterface) {
-        ALOGE("no AGPS RIL interface in send_ni_message");
-        return;
-    }
-    if (size < 0)
-        return;
-    sz = (size_t)size;
-    jbyte* b = env->GetByteArrayElements(ni_msg, 0);
-    sAGpsRilInterface->ni_message((uint8_t *)b,sz);
-    env->ReleaseByteArrayElements(ni_msg,b,0);
-}
-
-static void android_location_GpsLocationProvider_agps_set_id(JNIEnv *env, jobject /* obj */,
-                                                             jint type, jstring  setid_string)
-{
-    if (!sAGpsRilInterface) {
-        ALOGE("no AGPS RIL interface in agps_set_id");
-        return;
-    }
-
-    const char *setid = env->GetStringUTFChars(setid_string, NULL);
-    sAGpsRilInterface->set_set_id(type, setid);
-    env->ReleaseStringUTFChars(setid_string, setid);
-}
-
-static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject /* obj */,
-                                            jbyteArray nmeaArray, jint buffer_size)
-{
-    // this should only be called from within a call to reportNmea
-    jbyte* nmea = (jbyte *)env->GetPrimitiveArrayCritical(nmeaArray, 0);
-    int length = sNmeaStringLength;
-    if (length > buffer_size)
-        length = buffer_size;
-    memcpy(nmea, sNmeaString, length);
-    env->ReleasePrimitiveArrayCritical(nmeaArray, nmea, JNI_ABORT);
-    return (jint) length;
-}
-
-static void android_location_GpsLocationProvider_inject_time(JNIEnv* /* env */, jobject /* obj */,
-        jlong time, jlong timeReference, jint uncertainty)
-{
-    if (sGpsInterface)
-        sGpsInterface->inject_time(time, timeReference, uncertainty);
-}
-
-static void android_location_GpsLocationProvider_inject_location(JNIEnv* /* env */,
-        jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy)
-{
-    if (sGpsInterface)
-        sGpsInterface->inject_location(latitude, longitude, accuracy);
-}
-
-static jboolean android_location_GpsLocationProvider_supports_xtra(
-        JNIEnv* /* env */, jobject /* obj */)
-{
-    return (sGpsXtraInterface != NULL) ? JNI_TRUE : JNI_FALSE;
-}
-
-static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject /* obj */,
-        jbyteArray data, jint length)
-{
-    if (!sGpsXtraInterface) {
-        ALOGE("no XTRA interface in inject_xtra_data");
-        return;
-    }
-
-    jbyte* bytes = (jbyte *)env->GetPrimitiveArrayCritical(data, 0);
-    sGpsXtraInterface->inject_xtra_data((char *)bytes, length);
-    env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
-}
-
-static void android_location_GpsLocationProvider_agps_data_conn_open(
-        JNIEnv* env, jobject /* obj */, jstring apn, jint apnIpType)
-{
-    if (!sAGpsInterface) {
-        ALOGE("no AGPS interface in agps_data_conn_open");
-        return;
-    }
-    if (apn == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-        return;
-    }
-
-    const char *apnStr = env->GetStringUTFChars(apn, NULL);
-
-    size_t interface_size = sAGpsInterface->size;
-    if (interface_size == sizeof(AGpsInterface_v2)) {
-        sAGpsInterface->data_conn_open_with_apn_ip_type(apnStr, apnIpType);
-    } else if (interface_size == sizeof(AGpsInterface_v1)) {
-        sAGpsInterface->data_conn_open(apnStr);
-    } else {
-        ALOGE("Invalid size of AGpsInterface found: %zd.", interface_size);
-    }
-
-    env->ReleaseStringUTFChars(apn, apnStr);
-}
-
-static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* /* env */,
-                                                                       jobject /* obj */)
-{
-    if (!sAGpsInterface) {
-        ALOGE("no AGPS interface in agps_data_conn_closed");
-        return;
-    }
-    sAGpsInterface->data_conn_closed();
-}
-
-static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* /* env */,
-                                                                       jobject /* obj */)
-{
-    if (!sAGpsInterface) {
-        ALOGE("no AGPS interface in agps_data_conn_failed");
-        return;
-    }
-    sAGpsInterface->data_conn_failed();
-}
-
-static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject /* obj */,
-        jint type, jstring hostname, jint port)
-{
-    if (!sAGpsInterface) {
-        ALOGE("no AGPS interface in set_agps_server");
-        return;
-    }
-    const char *c_hostname = env->GetStringUTFChars(hostname, NULL);
-    sAGpsInterface->set_server(type, c_hostname, port);
-    env->ReleaseStringUTFChars(hostname, c_hostname);
-}
-
-static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* /* env */,
-      jobject /* obj */, jint notifId, jint response)
-{
-    if (!sGpsNiInterface) {
-        ALOGE("no NI interface in send_ni_response");
-        return;
-    }
-
-    sGpsNiInterface->respond(notifId, response);
-}
-
-static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* env,
-                                                                       jobject /* obj */) {
-    jstring result = NULL;
-    if (sGpsDebugInterface) {
-        const size_t maxLength = 2047;
-        char buffer[maxLength+1];
-        size_t length = sGpsDebugInterface->get_internal_state(buffer, maxLength);
-        if (length > maxLength) length = maxLength;
-        buffer[length] = 0;
-        result = env->NewStringUTF(buffer);
-    }
-    return result;
-}
-
-static void android_location_GpsLocationProvider_update_network_state(JNIEnv* env, jobject /* obj */,
-        jboolean connected, jint type, jboolean roaming, jboolean available, jstring extraInfo, jstring apn)
-{
-
-    if (sAGpsRilInterface && sAGpsRilInterface->update_network_state) {
-        if (extraInfo) {
-            const char *extraInfoStr = env->GetStringUTFChars(extraInfo, NULL);
-            sAGpsRilInterface->update_network_state(connected, type, roaming, extraInfoStr);
-            env->ReleaseStringUTFChars(extraInfo, extraInfoStr);
-        } else {
-            sAGpsRilInterface->update_network_state(connected, type, roaming, NULL);
-        }
-
-        // update_network_availability callback was not included in original AGpsRilInterface
-        if (sAGpsRilInterface->size >= sizeof(AGpsRilInterface)
-                && sAGpsRilInterface->update_network_availability) {
-            const char *c_apn = env->GetStringUTFChars(apn, NULL);
-            sAGpsRilInterface->update_network_availability(available, c_apn);
-            env->ReleaseStringUTFChars(apn, c_apn);
-        }
-    }
-}
-
-static jboolean android_location_GpsLocationProvider_is_geofence_supported(
-        JNIEnv* /* env */, jobject /* obj */)
-{
-    return (sGpsGeofencingInterface != NULL) ? JNI_TRUE : JNI_FALSE;
-}
-
-static jboolean android_location_GpsLocationProvider_add_geofence(JNIEnv* /* env */,
-        jobject /* obj */, jint geofence_id, jdouble latitude, jdouble longitude, jdouble radius,
-        jint last_transition, jint monitor_transition, jint notification_responsiveness,
-        jint unknown_timer) {
-    if (sGpsGeofencingInterface != NULL) {
-        sGpsGeofencingInterface->add_geofence_area(geofence_id, latitude, longitude,
-                radius, last_transition, monitor_transition, notification_responsiveness,
-                unknown_timer);
-        return JNI_TRUE;
-    } else {
-        ALOGE("Geofence interface not available");
-    }
-    return JNI_FALSE;
-}
-
-static jboolean android_location_GpsLocationProvider_remove_geofence(JNIEnv* /* env */,
-        jobject /* obj */, jint geofence_id) {
-    if (sGpsGeofencingInterface != NULL) {
-        sGpsGeofencingInterface->remove_geofence_area(geofence_id);
-        return JNI_TRUE;
-    } else {
-        ALOGE("Geofence interface not available");
-    }
-    return JNI_FALSE;
-}
-
-static jboolean android_location_GpsLocationProvider_pause_geofence(JNIEnv* /* env */,
-        jobject /* obj */, jint geofence_id) {
-    if (sGpsGeofencingInterface != NULL) {
-        sGpsGeofencingInterface->pause_geofence(geofence_id);
-        return JNI_TRUE;
-    } else {
-        ALOGE("Geofence interface not available");
-    }
-    return JNI_FALSE;
-}
-
-static jboolean android_location_GpsLocationProvider_resume_geofence(JNIEnv* /* env */,
-        jobject /* obj */, jint geofence_id, jint monitor_transition) {
-    if (sGpsGeofencingInterface != NULL) {
-        sGpsGeofencingInterface->resume_geofence(geofence_id, monitor_transition);
-        return JNI_TRUE;
-    } else {
-        ALOGE("Geofence interface not available");
-    }
-    return JNI_FALSE;
-}
-
-static jobject translate_gps_clock(JNIEnv* env, GpsClock* clock) {
-    const char* doubleSignature = "(D)V";
-    const char* longSignature = "(J)V";
-
-    jclass gpsClockClass = env->FindClass("android/location/GpsClock");
-    jmethodID gpsClockCtor = env->GetMethodID(gpsClockClass, "<init>", "()V");
-
-    jobject gpsClockObject = env->NewObject(gpsClockClass, gpsClockCtor);
-    GpsClockFlags flags = clock->flags;
-
-    if (flags & GPS_CLOCK_HAS_LEAP_SECOND) {
-        jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setLeapSecond", "(S)V");
-        env->CallVoidMethod(gpsClockObject, setterMethod, clock->leap_second);
-   }
-
-   jmethodID typeSetterMethod = env->GetMethodID(gpsClockClass, "setType", "(B)V");
-   env->CallVoidMethod(gpsClockObject, typeSetterMethod, clock->type);
-
-    jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setTimeInNs", longSignature);
-    env->CallVoidMethod(gpsClockObject, setterMethod, clock->time_ns);
-
-    if (flags & GPS_CLOCK_HAS_TIME_UNCERTAINTY) {
-        jmethodID setterMethod =
-                env->GetMethodID(gpsClockClass, "setTimeUncertaintyInNs", doubleSignature);
-        env->CallVoidMethod(gpsClockObject, setterMethod, clock->time_uncertainty_ns);
-    }
-
-    if (flags & GPS_CLOCK_HAS_FULL_BIAS) {
-        jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setFullBiasInNs", longSignature);
-        env->CallVoidMethod(gpsClockObject, setterMethod, clock->full_bias_ns);
-    }
-
-    if (flags & GPS_CLOCK_HAS_BIAS) {
-        jmethodID setterMethod = env->GetMethodID(gpsClockClass, "setBiasInNs", doubleSignature);
-        env->CallVoidMethod(gpsClockObject, setterMethod, clock->bias_ns);
-    }
-
-    if (flags & GPS_CLOCK_HAS_BIAS_UNCERTAINTY) {
-        jmethodID setterMethod =
-                env->GetMethodID(gpsClockClass, "setBiasUncertaintyInNs", doubleSignature);
-        env->CallVoidMethod(gpsClockObject, setterMethod, clock->bias_uncertainty_ns);
-    }
-
-    if (flags & GPS_CLOCK_HAS_DRIFT) {
-        jmethodID setterMethod =
-                env->GetMethodID(gpsClockClass, "setDriftInNsPerSec", doubleSignature);
-        env->CallVoidMethod(gpsClockObject, setterMethod, clock->drift_nsps);
-    }
-
-    if (flags & GPS_CLOCK_HAS_DRIFT_UNCERTAINTY) {
-        jmethodID setterMethod =
-                env->GetMethodID(gpsClockClass, "setDriftUncertaintyInNsPerSec", doubleSignature);
-        env->CallVoidMethod(gpsClockObject, setterMethod, clock->drift_uncertainty_nsps);
-    }
-
-    env->DeleteLocalRef(gpsClockClass);
-    return gpsClockObject;
-}
-
-static jobject translate_gps_measurement(JNIEnv* env, GpsMeasurement* measurement) {
-    const char* byteSignature = "(B)V";
-    const char* shortSignature = "(S)V";
-    const char* intSignature = "(I)V";
-    const char* longSignature = "(J)V";
-    const char* floatSignature = "(F)V";
-    const char* doubleSignature = "(D)V";
-
-    jclass gpsMeasurementClass = env->FindClass("android/location/GpsMeasurement");
-    jmethodID gpsMeasurementCtor = env->GetMethodID(gpsMeasurementClass, "<init>", "()V");
-
-    jobject gpsMeasurementObject = env->NewObject(gpsMeasurementClass, gpsMeasurementCtor);
-    GpsMeasurementFlags flags = measurement->flags;
-
-    jmethodID prnSetterMethod = env->GetMethodID(gpsMeasurementClass, "setPrn", byteSignature);
-    env->CallVoidMethod(gpsMeasurementObject, prnSetterMethod, measurement->prn);
-
-    jmethodID timeOffsetSetterMethod =
-            env->GetMethodID(gpsMeasurementClass, "setTimeOffsetInNs", doubleSignature);
-    env->CallVoidMethod(
-            gpsMeasurementObject,
-            timeOffsetSetterMethod,
-            measurement->time_offset_ns);
-
-    jmethodID stateSetterMethod = env->GetMethodID(gpsMeasurementClass, "setState", shortSignature);
-    env->CallVoidMethod(gpsMeasurementObject, stateSetterMethod, measurement->state);
-
-    jmethodID receivedGpsTowSetterMethod =
-            env->GetMethodID(gpsMeasurementClass, "setReceivedGpsTowInNs", longSignature);
-    env->CallVoidMethod(
-            gpsMeasurementObject,
-            receivedGpsTowSetterMethod,
-            measurement->received_gps_tow_ns);
-
-    jmethodID receivedGpsTowUncertaintySetterMethod = env->GetMethodID(
-            gpsMeasurementClass,
-            "setReceivedGpsTowUncertaintyInNs",
-            longSignature);
-    env->CallVoidMethod(
-            gpsMeasurementObject,
-            receivedGpsTowUncertaintySetterMethod,
-            measurement->received_gps_tow_uncertainty_ns);
-
-    jmethodID cn0SetterMethod =
-            env->GetMethodID(gpsMeasurementClass, "setCn0InDbHz", doubleSignature);
-    env->CallVoidMethod(gpsMeasurementObject, cn0SetterMethod, measurement->c_n0_dbhz);
-
-    jmethodID pseudorangeRateSetterMethod = env->GetMethodID(
-            gpsMeasurementClass,
-            "setPseudorangeRateInMetersPerSec",
-            doubleSignature);
-    env->CallVoidMethod(
-            gpsMeasurementObject,
-            pseudorangeRateSetterMethod,
-            measurement->pseudorange_rate_mps);
-
-    jmethodID pseudorangeRateUncertaintySetterMethod = env->GetMethodID(
-            gpsMeasurementClass,
-            "setPseudorangeRateUncertaintyInMetersPerSec",
-            doubleSignature);
-    env->CallVoidMethod(
-            gpsMeasurementObject,
-            pseudorangeRateUncertaintySetterMethod,
-            measurement->pseudorange_rate_uncertainty_mps);
-
-    jmethodID accumulatedDeltaRangeStateSetterMethod =
-            env->GetMethodID(gpsMeasurementClass, "setAccumulatedDeltaRangeState", shortSignature);
-    env->CallVoidMethod(
-            gpsMeasurementObject,
-            accumulatedDeltaRangeStateSetterMethod,
-            measurement->accumulated_delta_range_state);
-
-    jmethodID accumulatedDeltaRangeSetterMethod = env->GetMethodID(
-            gpsMeasurementClass,
-            "setAccumulatedDeltaRangeInMeters",
-            doubleSignature);
-    env->CallVoidMethod(
-            gpsMeasurementObject,
-            accumulatedDeltaRangeSetterMethod,
-            measurement->accumulated_delta_range_m);
-
-    jmethodID accumulatedDeltaRangeUncertaintySetterMethod = env->GetMethodID(
-            gpsMeasurementClass,
-            "setAccumulatedDeltaRangeUncertaintyInMeters",
-            doubleSignature);
-    env->CallVoidMethod(
-            gpsMeasurementObject,
-            accumulatedDeltaRangeUncertaintySetterMethod,
-            measurement->accumulated_delta_range_uncertainty_m);
-
-    if (flags & GPS_MEASUREMENT_HAS_PSEUDORANGE) {
-        jmethodID setterMethod =
-                env->GetMethodID(gpsMeasurementClass, "setPseudorangeInMeters", doubleSignature);
-        env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->pseudorange_m);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY) {
-        jmethodID setterMethod = env->GetMethodID(
-                gpsMeasurementClass,
-                "setPseudorangeUncertaintyInMeters",
-                doubleSignature);
-        env->CallVoidMethod(
-                gpsMeasurementObject,
-                setterMethod,
-                measurement->pseudorange_uncertainty_m);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_CODE_PHASE) {
-        jmethodID setterMethod =
-                env->GetMethodID(gpsMeasurementClass, "setCodePhaseInChips", doubleSignature);
-        env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->code_phase_chips);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY) {
-        jmethodID setterMethod = env->GetMethodID(
-                gpsMeasurementClass,
-                "setCodePhaseUncertaintyInChips",
-                doubleSignature);
-        env->CallVoidMethod(
-                gpsMeasurementObject,
-                setterMethod,
-                measurement->code_phase_uncertainty_chips);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_CARRIER_FREQUENCY) {
-        jmethodID setterMethod =
-                env->GetMethodID(gpsMeasurementClass, "setCarrierFrequencyInHz", floatSignature);
-        env->CallVoidMethod(
-                gpsMeasurementObject,
-                setterMethod,
-                measurement->carrier_frequency_hz);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_CARRIER_CYCLES) {
-        jmethodID setterMethod =
-                env->GetMethodID(gpsMeasurementClass, "setCarrierCycles", longSignature);
-        env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->carrier_cycles);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_CARRIER_PHASE) {
-        jmethodID setterMethod =
-                env->GetMethodID(gpsMeasurementClass, "setCarrierPhase", doubleSignature);
-        env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->carrier_phase);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY) {
-        jmethodID setterMethod = env->GetMethodID(
-                gpsMeasurementClass,
-                "setCarrierPhaseUncertainty",
-                doubleSignature);
-        env->CallVoidMethod(
-                gpsMeasurementObject,
-                setterMethod,
-                measurement->carrier_phase_uncertainty);
-    }
-
-    jmethodID lossOfLockSetterMethod =
-            env->GetMethodID(gpsMeasurementClass, "setLossOfLock", byteSignature);
-    env->CallVoidMethod(gpsMeasurementObject, lossOfLockSetterMethod, measurement->loss_of_lock);
-
-    if (flags & GPS_MEASUREMENT_HAS_BIT_NUMBER) {
-        jmethodID setterMethod =
-                env->GetMethodID(gpsMeasurementClass, "setBitNumber", intSignature);
-        env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->bit_number);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT) {
-        jmethodID setterMethod =
-                env->GetMethodID(gpsMeasurementClass, "setTimeFromLastBitInMs", shortSignature);
-        env->CallVoidMethod(
-                gpsMeasurementObject,
-                setterMethod,
-                measurement->time_from_last_bit_ms);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_DOPPLER_SHIFT) {
-        jmethodID setterMethod =
-                env->GetMethodID(gpsMeasurementClass, "setDopplerShiftInHz", doubleSignature);
-        env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->doppler_shift_hz);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY) {
-        jmethodID setterMethod = env->GetMethodID(
-                gpsMeasurementClass,
-                "setDopplerShiftUncertaintyInHz",
-                doubleSignature);
-        env->CallVoidMethod(
-                gpsMeasurementObject,
-                setterMethod,
-                measurement->doppler_shift_uncertainty_hz);
-    }
-
-    jmethodID multipathIndicatorSetterMethod =
-            env->GetMethodID(gpsMeasurementClass, "setMultipathIndicator", byteSignature);
-    env->CallVoidMethod(
-            gpsMeasurementObject,
-            multipathIndicatorSetterMethod,
-            measurement->multipath_indicator);
-
-    if (flags & GPS_MEASUREMENT_HAS_SNR) {
-        jmethodID setterMethod =
-                env->GetMethodID(gpsMeasurementClass, "setSnrInDb", doubleSignature);
-        env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->snr_db);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_ELEVATION) {
-        jmethodID setterMethod =
-                env->GetMethodID(gpsMeasurementClass, "setElevationInDeg", doubleSignature);
-        env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->elevation_deg);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY) {
-        jmethodID setterMethod =
-                env->GetMethodID(gpsMeasurementClass, "setElevationUncertaintyInDeg", doubleSignature);
-        env->CallVoidMethod(
-                gpsMeasurementObject,
-                setterMethod,
-                measurement->elevation_uncertainty_deg);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_AZIMUTH) {
-        jmethodID setterMethod =
-                env->GetMethodID(gpsMeasurementClass, "setAzimuthInDeg", doubleSignature);
-        env->CallVoidMethod(gpsMeasurementObject, setterMethod, measurement->azimuth_deg);
-    }
-
-    if (flags & GPS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY) {
-        jmethodID setterMethod = env->GetMethodID(
-                gpsMeasurementClass,
-                "setAzimuthUncertaintyInDeg",
-                doubleSignature);
-        env->CallVoidMethod(
-                gpsMeasurementObject,
-                setterMethod,
-                measurement->azimuth_uncertainty_deg);
-    }
-
-    jmethodID usedInFixSetterMethod = env->GetMethodID(gpsMeasurementClass, "setUsedInFix", "(Z)V");
-    env->CallVoidMethod(
-            gpsMeasurementObject,
-            usedInFixSetterMethod,
-            (flags & GPS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
-
-    env->DeleteLocalRef(gpsMeasurementClass);
-    return gpsMeasurementObject;
-}
-
-static jobjectArray translate_gps_measurements(JNIEnv* env, GpsData* data) {
-    size_t measurementCount = data->measurement_count;
-    if (measurementCount == 0) {
-        return NULL;
-    }
-
-    jclass gpsMeasurementClass = env->FindClass("android/location/GpsMeasurement");
-    jobjectArray gpsMeasurementArray = env->NewObjectArray(
-            measurementCount,
-            gpsMeasurementClass,
-            NULL /* initialElement */);
-
-    GpsMeasurement* gpsMeasurements = data->measurements;
-    for (uint16_t i = 0; i < measurementCount; ++i) {
-        jobject gpsMeasurement = translate_gps_measurement(env, &gpsMeasurements[i]);
-        env->SetObjectArrayElement(gpsMeasurementArray, i, gpsMeasurement);
-        env->DeleteLocalRef(gpsMeasurement);
-    }
-
-    env->DeleteLocalRef(gpsMeasurementClass);
-    return gpsMeasurementArray;
-}
-
-static void measurement_callback(GpsData* data) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    if (data == NULL) {
-        ALOGE("Invalid data provided to gps_measurement_callback");
-        return;
-    }
-
-    if (data->size == sizeof(GpsData)) {
-        jobject gpsClock = translate_gps_clock(env, &data->clock);
-        jobjectArray measurementArray = translate_gps_measurements(env, data);
-
-        jclass gpsMeasurementsEventClass = env->FindClass("android/location/GpsMeasurementsEvent");
-        jmethodID gpsMeasurementsEventCtor = env->GetMethodID(
-                gpsMeasurementsEventClass,
-                "<init>",
-                "(Landroid/location/GpsClock;[Landroid/location/GpsMeasurement;)V");
-
-        jobject gpsMeasurementsEvent = env->NewObject(
-                gpsMeasurementsEventClass,
-                gpsMeasurementsEventCtor,
-                gpsClock,
-                measurementArray);
-
-        env->CallVoidMethod(mCallbacksObj, method_reportMeasurementData, gpsMeasurementsEvent);
-        checkAndClearExceptionFromCallback(env, __FUNCTION__);
-
-        env->DeleteLocalRef(gpsClock);
-        env->DeleteLocalRef(measurementArray);
-        env->DeleteLocalRef(gpsMeasurementsEventClass);
-        env->DeleteLocalRef(gpsMeasurementsEvent);
-    } else {
-        ALOGE("Invalid GpsData size found in gps_measurement_callback, size=%zd", data->size);
-    }
-}
-
-GpsMeasurementCallbacks sGpsMeasurementCallbacks = {
-    sizeof(GpsMeasurementCallbacks),
-    measurement_callback,
-};
-
-static jboolean android_location_GpsLocationProvider_is_measurement_supported(
-        JNIEnv* env,
-        jclass clazz) {
-    if (sGpsMeasurementInterface != NULL) {
-        return JNI_TRUE;
-    }
-    return JNI_FALSE;
-}
-
-static jboolean android_location_GpsLocationProvider_start_measurement_collection(
-        JNIEnv* env,
-        jobject obj) {
-    if (sGpsMeasurementInterface == NULL) {
-        ALOGE("Measurement interface is not available.");
-        return JNI_FALSE;
-    }
-
-    int result = sGpsMeasurementInterface->init(&sGpsMeasurementCallbacks);
-    if (result != GPS_GEOFENCE_OPERATION_SUCCESS) {
-        ALOGE("An error has been found on GpsMeasurementInterface::init, status=%d", result);
-        return JNI_FALSE;
-    }
-
-    return JNI_TRUE;
-}
-
-static jboolean android_location_GpsLocationProvider_stop_measurement_collection(
-        JNIEnv* env,
-        jobject obj) {
-    if (sGpsMeasurementInterface == NULL) {
-        ALOGE("Measurement interface not available");
-        return JNI_FALSE;
-    }
-
-    sGpsMeasurementInterface->close();
-    return JNI_TRUE;
-}
-
-static jobject translate_gps_navigation_message(JNIEnv* env, GpsNavigationMessage* message) {
-    size_t dataLength = message->data_length;
-    uint8_t* data = message->data;
-    if (dataLength == 0 || data == NULL) {
-        ALOGE("Invalid Navigation Message found: data=%p, length=%zd", data, dataLength);
-        return NULL;
-    }
-
-    jclass navigationMessageClass = env->FindClass("android/location/GpsNavigationMessage");
-    jmethodID navigationMessageCtor = env->GetMethodID(navigationMessageClass, "<init>", "()V");
-    jobject navigationMessageObject = env->NewObject(navigationMessageClass, navigationMessageCtor);
-
-    jmethodID setTypeMethod = env->GetMethodID(navigationMessageClass, "setType", "(B)V");
-    env->CallVoidMethod(navigationMessageObject, setTypeMethod, message->type);
-
-    jmethodID setPrnMethod = env->GetMethodID(navigationMessageClass, "setPrn", "(B)V");
-    env->CallVoidMethod(navigationMessageObject, setPrnMethod, message->prn);
-
-    jmethodID setMessageIdMethod = env->GetMethodID(navigationMessageClass, "setMessageId", "(S)V");
-    env->CallVoidMethod(navigationMessageObject, setMessageIdMethod, message->message_id);
-
-    jmethodID setSubmessageIdMethod =
-            env->GetMethodID(navigationMessageClass, "setSubmessageId", "(S)V");
-    env->CallVoidMethod(navigationMessageObject, setSubmessageIdMethod, message->submessage_id);
-
-    jbyteArray dataArray = env->NewByteArray(dataLength);
-    env->SetByteArrayRegion(dataArray, 0, dataLength, (jbyte*) data);
-    jmethodID setDataMethod = env->GetMethodID(navigationMessageClass, "setData", "([B)V");
-    env->CallVoidMethod(navigationMessageObject, setDataMethod, dataArray);
-
-    env->DeleteLocalRef(navigationMessageClass);
-    env->DeleteLocalRef(dataArray);
-    return navigationMessageObject;
-}
-
-static void navigation_message_callback(GpsNavigationMessage* message) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    if (message == NULL) {
-        ALOGE("Invalid Navigation Message provided to callback");
-        return;
-    }
-
-    if (message->size == sizeof(GpsNavigationMessage)) {
-        jobject navigationMessage = translate_gps_navigation_message(env, message);
-
-        jclass navigationMessageEventClass =
-                env->FindClass("android/location/GpsNavigationMessageEvent");
-        jmethodID navigationMessageEventCtor = env->GetMethodID(
-                navigationMessageEventClass,
-                "<init>",
-                "(Landroid/location/GpsNavigationMessage;)V");
-        jobject navigationMessageEvent = env->NewObject(
-                navigationMessageEventClass,
-                navigationMessageEventCtor,
-                navigationMessage);
-
-        env->CallVoidMethod(mCallbacksObj, method_reportNavigationMessages, navigationMessageEvent);
-        checkAndClearExceptionFromCallback(env, __FUNCTION__);
-
-        env->DeleteLocalRef(navigationMessage);
-        env->DeleteLocalRef(navigationMessageEventClass);
-        env->DeleteLocalRef(navigationMessageEvent);
-    } else {
-        ALOGE("Invalid GpsNavigationMessage size found: %zd", message->size);
-    }
-}
-
-GpsNavigationMessageCallbacks sGpsNavigationMessageCallbacks = {
-    sizeof(GpsNavigationMessageCallbacks),
-    navigation_message_callback,
-};
-
-static jboolean android_location_GpsLocationProvider_is_navigation_message_supported(
-        JNIEnv* env,
-        jclass clazz) {
-    if(sGpsNavigationMessageInterface != NULL) {
-        return JNI_TRUE;
-    }
-    return JNI_FALSE;
-}
-
-static jboolean android_location_GpsLocationProvider_start_navigation_message_collection(
-        JNIEnv* env,
-        jobject obj) {
-    if (sGpsNavigationMessageInterface == NULL) {
-        ALOGE("Navigation Message interface is not available.");
-        return JNI_FALSE;
-    }
-
-    int result = sGpsNavigationMessageInterface->init(&sGpsNavigationMessageCallbacks);
-    if (result != GPS_NAVIGATION_MESSAGE_OPERATION_SUCCESS) {
-        ALOGE("An error has been found in %s: %d", __FUNCTION__, result);
-        return JNI_FALSE;
-    }
-
-    return JNI_TRUE;
-}
-
-static jboolean android_location_GpsLocationProvider_stop_navigation_message_collection(
-        JNIEnv* env,
-        jobject obj) {
-    if (sGpsNavigationMessageInterface == NULL) {
-        ALOGE("Navigation Message interface is not available.");
-        return JNI_FALSE;
-    }
-
-    sGpsNavigationMessageInterface->close();
-    return JNI_TRUE;
-}
-
-static void android_location_GpsLocationProvider_configuration_update(JNIEnv* env, jobject obj,
-        jstring config_content)
-{
-    if (!sGnssConfigurationInterface) {
-        ALOGE("no GPS configuration interface in configuraiton_update");
-        return;
-    }
-    const char *data = env->GetStringUTFChars(config_content, NULL);
-    ALOGD("GPS configuration:\n %s", data);
-    sGnssConfigurationInterface->configuration_update(
-            data, env->GetStringUTFLength(config_content));
-    env->ReleaseStringUTFChars(config_content, data);
-}
-
-static const JNINativeMethod sMethods[] = {
-     /* name, signature, funcPtr */
-    {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
-    {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported},
-    {"native_is_agps_ril_supported", "()Z",
-            (void*)android_location_GpsLocationProvider_is_agps_ril_supported},
-    {"native_is_gnss_configuration_supported", "()Z",
-            (void*)android_location_gpsLocationProvider_is_gnss_configuration_supported},
-    {"native_init", "()Z", (void*)android_location_GpsLocationProvider_init},
-    {"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup},
-    {"native_set_position_mode",
-            "(IIIII)Z",
-            (void*)android_location_GpsLocationProvider_set_position_mode},
-    {"native_start", "()Z", (void*)android_location_GpsLocationProvider_start},
-    {"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop},
-    {"native_delete_aiding_data",
-            "(I)V",
-            (void*)android_location_GpsLocationProvider_delete_aiding_data},
-    {"native_read_sv_status",
-            "([I[F[F[F[I)I",
-            (void*)android_location_GpsLocationProvider_read_sv_status},
-    {"native_read_nmea", "([BI)I", (void*)android_location_GpsLocationProvider_read_nmea},
-    {"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
-    {"native_inject_location",
-            "(DDF)V",
-            (void*)android_location_GpsLocationProvider_inject_location},
-    {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
-    {"native_inject_xtra_data",
-            "([BI)V",
-            (void*)android_location_GpsLocationProvider_inject_xtra_data},
-    {"native_agps_data_conn_open",
-            "(Ljava/lang/String;I)V",
-            (void*)android_location_GpsLocationProvider_agps_data_conn_open},
-    {"native_agps_data_conn_closed",
-            "()V",
-            (void*)android_location_GpsLocationProvider_agps_data_conn_closed},
-    {"native_agps_data_conn_failed",
-            "()V",
-            (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
-    {"native_agps_set_id",
-            "(ILjava/lang/String;)V",
-            (void*)android_location_GpsLocationProvider_agps_set_id},
-    {"native_agps_set_ref_location_cellid",
-            "(IIIII)V",
-            (void*)android_location_GpsLocationProvider_agps_set_reference_location_cellid},
-    {"native_set_agps_server",
-            "(ILjava/lang/String;I)V",
-            (void*)android_location_GpsLocationProvider_set_agps_server},
-    {"native_send_ni_response",
-            "(II)V",
-            (void*)android_location_GpsLocationProvider_send_ni_response},
-    {"native_agps_ni_message",
-            "([BI)V",
-            (void *)android_location_GpsLocationProvider_agps_send_ni_message},
-    {"native_get_internal_state",
-            "()Ljava/lang/String;",
-            (void*)android_location_GpsLocationProvider_get_internal_state},
-    {"native_update_network_state",
-            "(ZIZZLjava/lang/String;Ljava/lang/String;)V",
-            (void*)android_location_GpsLocationProvider_update_network_state },
-    {"native_is_geofence_supported",
-            "()Z",
-            (void*) android_location_GpsLocationProvider_is_geofence_supported},
-    {"native_add_geofence",
-            "(IDDDIIII)Z",
-            (void *)android_location_GpsLocationProvider_add_geofence},
-    {"native_remove_geofence",
-            "(I)Z",
-            (void *)android_location_GpsLocationProvider_remove_geofence},
-    {"native_pause_geofence", "(I)Z", (void *)android_location_GpsLocationProvider_pause_geofence},
-    {"native_resume_geofence",
-            "(II)Z",
-            (void *)android_location_GpsLocationProvider_resume_geofence},
-    {"native_is_measurement_supported",
-            "()Z",
-            (void*) android_location_GpsLocationProvider_is_measurement_supported},
-    {"native_start_measurement_collection",
-            "()Z",
-            (void*) android_location_GpsLocationProvider_start_measurement_collection},
-    {"native_stop_measurement_collection",
-            "()Z",
-            (void*) android_location_GpsLocationProvider_stop_measurement_collection},
-    {"native_is_navigation_message_supported",
-            "()Z",
-            (void*) android_location_GpsLocationProvider_is_navigation_message_supported},
-    {"native_start_navigation_message_collection",
-            "()Z",
-            (void*) android_location_GpsLocationProvider_start_navigation_message_collection},
-    {"native_stop_navigation_message_collection",
-            "()Z",
-            (void*) android_location_GpsLocationProvider_stop_navigation_message_collection},
-    {"native_configuration_update",
-            "(Ljava/lang/String;)V",
-            (void*)android_location_GpsLocationProvider_configuration_update},
-};
-
-int register_android_server_location_GpsLocationProvider(JNIEnv* env)
-{
-    return jniRegisterNativeMethods(
-            env,
-            "com/android/server/location/GpsLocationProvider",
-            sMethods,
-            NELEM(sMethods));
-}
-
-} /* namespace android */
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index 01acdef..6c640ba 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -54,6 +54,7 @@
     jmethodID maxWidth;
     jmethodID maxHeight;
     jmethodID generation;
+    jmethodID flags;
     jmethodID build;
 } gTvStreamConfigBuilderClassInfo;
 
@@ -239,7 +240,7 @@
 
     int addOrUpdateStream(int deviceId, int streamId, const sp<Surface>& surface);
     int removeStream(int deviceId, int streamId);
-    const tv_stream_config_t* getStreamConfigs(int deviceId, int* numConfigs);
+    const tv_stream_config_ext_t* getStreamConfigs(int deviceId, int* numConfigs);
 
     void onDeviceAvailable(const tv_input_device_info_t& info);
     void onDeviceUnavailable(int deviceId);
@@ -288,10 +289,15 @@
     sp<Looper> mLooper;
 
     KeyedVector<int, KeyedVector<int, Connection> > mConnections;
+
+    tv_stream_config_ext_t* mConfigBuffer;
+    int mConfigBufferSize;
 };
 
 JTvInputHal::JTvInputHal(JNIEnv* env, jobject thiz, tv_input_device_t* device,
-        const sp<Looper>& looper) {
+        const sp<Looper>& looper)
+    : mConfigBuffer(NULL),
+      mConfigBufferSize(0) {
     mThiz = env->NewWeakGlobalRef(thiz);
     mDevice = device;
     mCallback.notify = &JTvInputHal::notify;
@@ -306,6 +312,10 @@
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     env->DeleteWeakGlobalRef(mThiz);
     mThiz = NULL;
+
+    if (mConfigBuffer != NULL) {
+        delete[] mConfigBuffer;
+    }
 }
 
 JTvInputHal* JTvInputHal::createInstance(JNIEnv* env, jobject thiz, const sp<Looper>& looper) {
@@ -354,15 +364,14 @@
     if (connection.mSourceHandle == NULL && connection.mThread == NULL) {
         // Need to configure stream
         int numConfigs = 0;
-        const tv_stream_config_t* configs = NULL;
-        if (mDevice->get_stream_configurations(
-                mDevice, deviceId, &numConfigs, &configs) != 0) {
+        const tv_stream_config_ext_t* configs = getStreamConfigs(deviceId, &numConfigs);
+        if (configs == NULL) {
             ALOGE("Couldn't get stream configs");
             return UNKNOWN_ERROR;
         }
         int configIndex = -1;
         for (int i = 0; i < numConfigs; ++i) {
-            if (configs[i].stream_id == streamId) {
+            if (configs[i].config.stream_id == streamId) {
                 configIndex = i;
                 break;
             }
@@ -371,13 +380,13 @@
             ALOGE("Cannot find a config with given stream ID: %d", streamId);
             return BAD_VALUE;
         }
-        connection.mStreamType = configs[configIndex].type;
+        connection.mStreamType = configs[configIndex].config.type;
 
         tv_stream_t stream;
-        stream.stream_id = configs[configIndex].stream_id;
+        stream.stream_id = configs[configIndex].config.stream_id;
         if (connection.mStreamType == TV_STREAM_TYPE_BUFFER_PRODUCER) {
-            stream.buffer_producer.width = configs[configIndex].max_video_width;
-            stream.buffer_producer.height = configs[configIndex].max_video_height;
+            stream.buffer_producer.width = configs[configIndex].config.max_video_width;
+            stream.buffer_producer.height = configs[configIndex].config.max_video_height;
         }
         if (mDevice->open_stream(mDevice, deviceId, &stream) != 0) {
             ALOGE("Couldn't add stream");
@@ -431,12 +440,33 @@
     return NO_ERROR;
 }
 
-const tv_stream_config_t* JTvInputHal::getStreamConfigs(int deviceId, int* numConfigs) {
-    const tv_stream_config_t* configs = NULL;
-    if (mDevice->get_stream_configurations(
-            mDevice, deviceId, numConfigs, &configs) != 0) {
-        ALOGE("Couldn't get stream configs");
-        return NULL;
+const tv_stream_config_ext_t* JTvInputHal::getStreamConfigs(int deviceId, int* numConfigs) {
+    const tv_stream_config_ext_t* configs = NULL;
+    if (mDevice->common.version >= TV_INPUT_DEVICE_API_VERSION_0_2) {
+        if (mDevice->get_stream_configurations_ext(
+                mDevice, deviceId, numConfigs, &configs) != 0) {
+            ALOGE("Couldn't get stream configs");
+            return NULL;
+        }
+    } else {
+        const tv_stream_config_t* oldConfigs;
+        if (mDevice->get_stream_configurations(
+                mDevice, deviceId, numConfigs, &oldConfigs) != 0) {
+            ALOGE("Couldn't get stream configs");
+            return NULL;
+        }
+        if (mConfigBufferSize < *numConfigs) {
+            mConfigBufferSize = (*numConfigs / 16 + 1) * 16;
+            if (mConfigBuffer != NULL) {
+                delete[] mConfigBuffer;
+            }
+            mConfigBuffer = new tv_stream_config_ext_t[mConfigBufferSize];
+        }
+        for (int i = 0; i < *numConfigs; ++i) {
+            mConfigBuffer[i].config = oldConfigs[i];
+            mConfigBuffer[i].flags = 0;
+        }
+        configs = mConfigBuffer;
     }
     return configs;
 }
@@ -629,7 +659,7 @@
         jlong ptr, jint deviceId, jint generation) {
     JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
     int numConfigs = 0;
-    const tv_stream_config_t* configs = tvInputHal->getStreamConfigs(deviceId, &numConfigs);
+    const tv_stream_config_ext_t* configs = tvInputHal->getStreamConfigs(deviceId, &numConfigs);
 
     jobjectArray result = env->NewObjectArray(numConfigs, gTvStreamConfigClassInfo.clazz, NULL);
     for (int i = 0; i < numConfigs; ++i) {
@@ -637,15 +667,20 @@
                 gTvStreamConfigBuilderClassInfo.clazz,
                 gTvStreamConfigBuilderClassInfo.constructor);
         env->CallObjectMethod(
-                builder, gTvStreamConfigBuilderClassInfo.streamId, configs[i].stream_id);
+                builder, gTvStreamConfigBuilderClassInfo.streamId, configs[i].config.stream_id);
         env->CallObjectMethod(
-                builder, gTvStreamConfigBuilderClassInfo.type, configs[i].type);
+                builder, gTvStreamConfigBuilderClassInfo.type, configs[i].config.type);
         env->CallObjectMethod(
-                builder, gTvStreamConfigBuilderClassInfo.maxWidth, configs[i].max_video_width);
+                builder, gTvStreamConfigBuilderClassInfo.maxWidth,
+                configs[i].config.max_video_width);
         env->CallObjectMethod(
-                builder, gTvStreamConfigBuilderClassInfo.maxHeight, configs[i].max_video_height);
+                builder, gTvStreamConfigBuilderClassInfo.maxHeight,
+                configs[i].config.max_video_height);
         env->CallObjectMethod(
                 builder, gTvStreamConfigBuilderClassInfo.generation, generation);
+        env->CallObjectMethod(
+                builder, gTvStreamConfigBuilderClassInfo.flags,
+                configs[i].flags);
 
         jobject config = env->CallObjectMethod(builder, gTvStreamConfigBuilderClassInfo.build);
 
@@ -737,6 +772,10 @@
             gTvStreamConfigBuilderClassInfo.clazz,
             "generation", "(I)Landroid/media/tv/TvStreamConfig$Builder;");
     GET_METHOD_ID(
+            gTvStreamConfigBuilderClassInfo.flags,
+            gTvStreamConfigBuilderClassInfo.clazz,
+            "flags", "(I)Landroid/media/tv/TvStreamConfig$Builder;");
+    GET_METHOD_ID(
             gTvStreamConfigBuilderClassInfo.build,
             gTvStreamConfigBuilderClassInfo.clazz,
             "build", "()Landroid/media/tv/TvStreamConfig;");
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 1f3fde6..a7010bc 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -36,7 +36,7 @@
 int register_android_server_UsbMidiDevice(JNIEnv* env);
 int register_android_server_UsbHostManager(JNIEnv* env);
 int register_android_server_VibratorService(JNIEnv* env);
-int register_android_server_location_GpsLocationProvider(JNIEnv* env);
+int register_android_server_location_GnssLocationProvider(JNIEnv* env);
 int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
 int register_android_server_connectivity_Vpn(JNIEnv* env);
 int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
@@ -71,7 +71,7 @@
     register_android_server_UsbHostManager(env);
     register_android_server_VibratorService(env);
     register_android_server_SystemServer(env);
-    register_android_server_location_GpsLocationProvider(env);
+    register_android_server_location_GnssLocationProvider(env);
     register_android_server_location_FlpHardwareProvider(env);
     register_android_server_connectivity_Vpn(env);
     register_android_server_AssetAtlasService(env);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 810ee6b..1b0660d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -16,8 +16,6 @@
 
 package com.android.server.devicepolicy;
 
-import com.google.android.collect.Sets;
-
 import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
 import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
@@ -28,11 +26,14 @@
 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.NonNull;
 import android.app.Activity;
+import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
 import android.app.AppGlobals;
@@ -48,6 +49,7 @@
 import android.app.admin.IDevicePolicyManager;
 import android.app.admin.SystemUpdatePolicy;
 import android.app.backup.IBackupManager;
+import android.auditing.SecurityLog;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -66,6 +68,7 @@
 import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
+import android.graphics.Color;
 import android.media.AudioManager;
 import android.media.IAudioService;
 import android.net.ConnectivityManager;
@@ -82,6 +85,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.ParcelFileDescriptor;
 import android.os.PersistableBundle;
 import android.os.PowerManager;
 import android.os.PowerManagerInternal;
@@ -155,6 +159,7 @@
 import java.util.List;
 import java.util.Map.Entry;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Implementation of the device policy APIs.
@@ -176,13 +181,21 @@
     private static final String DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML =
             "do-not-ask-credentials-on-boot";
 
+    private static final String TAG_AFFILIATION_ID = "affiliation-id";
+
+    private static final String TAG_ADMIN_BROADCAST_PENDING = "admin-broadcast-pending";
+
+    private static final String ATTR_VALUE = "value";
+
+    private static final String TAG_INITIALIZATION_BUNDLE = "initialization-bundle";
+
     private static final int REQUEST_EXPIRE_PASSWORD = 5571;
 
     private static final long MS_PER_DAY = 86400 * 1000;
 
     private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * MS_PER_DAY; // 5 days, in ms
 
-    protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
+    private static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
             = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
 
     private static final int MONITORING_CERT_NOTIFICATION_ID = R.string.ssl_ca_cert_warning;
@@ -190,9 +203,12 @@
 
     private static final String ATTR_PERMISSION_PROVIDER = "permission-provider";
     private static final String ATTR_SETUP_COMPLETE = "setup-complete";
+    private static final String ATTR_PROVISIONING_STATE = "provisioning-state";
     private static final String ATTR_PERMISSION_POLICY = "permission-policy";
 
     private static final String ATTR_DELEGATED_CERT_INSTALLER = "delegated-cert-installer";
+    private static final String ATTR_APPLICATION_RESTRICTIONS_MANAGER
+            = "application-restrictions-manager";
 
     private static final int STATUS_BAR_DISABLE_MASK =
             StatusBarManager.DISABLE_EXPAND |
@@ -235,22 +251,27 @@
         GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.WIFI_ON);
     }
 
-    // Keyguard features that when set of a profile will affect the profiles
-    // parent user.
+    /** Keyguard features that when set on a profile will affect the profiles parent user. */
     private static final int PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER =
+            // STOPSHIP If the work challenge supports fingerprint, move DISABLE_FINGERPRINT
+            // to PROFILE_KEYGUARD_FEATURES_AFFECT_PROFILE?
             DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS
             | DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
 
-    // Keyguard features that are allowed to be set on a managed profile
+    /** Keyguard features that when set on a profile affect the profile content or challenge only */
+    private static final int PROFILE_KEYGUARD_FEATURES_AFFECT_PROFILE =
+            DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
+
+    /** Keyguard features that are allowed to be set on a managed profile */
     private static final int PROFILE_KEYGUARD_FEATURES =
-            PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER
-            | DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
+            PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER | PROFILE_KEYGUARD_FEATURES_AFFECT_PROFILE;
 
     final Context mContext;
     final Injector mInjector;
     final IPackageManager mIPackageManager;
     final UserManager mUserManager;
     final UserManagerInternal mUserManagerInternal;
+    private final LockPatternUtils mLockPatternUtils;
 
     final LocalService mLocalService;
 
@@ -266,6 +287,46 @@
      */
     private boolean mHasFeature;
 
+    private final AtomicBoolean mRemoteBugreportServiceIsActive = new AtomicBoolean();
+    private final AtomicBoolean mRemoteBugreportSharingAccepted = new AtomicBoolean();
+
+    private final Runnable mRemoteBugreportTimeoutRunnable = new Runnable() {
+        @Override
+        public void run() {
+            if(mRemoteBugreportServiceIsActive.get()) {
+                onBugreportFailed();
+            }
+        }
+    };
+
+    private final BroadcastReceiver mRemoteBugreportFinishedReceiver = new BroadcastReceiver() {
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_DISPATCH.equals(intent.getAction())
+                    && mRemoteBugreportServiceIsActive.get()) {
+                onBugreportFinished(intent);
+            }
+        }
+    };
+
+    private final BroadcastReceiver mRemoteBugreportConsentReceiver = new BroadcastReceiver() {
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            mInjector.getNotificationManager().cancel(LOG_TAG,
+                    RemoteBugreportUtils.REMOTE_BUGREPORT_CONSENT_NOTIFICATION_ID);
+            if (RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_ACCEPTED.equals(action)) {
+                onBugreportSharingAccepted();
+            } else if (RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_DECLINED
+                    .equals(action)) {
+                onBugreportSharingDeclined();
+            }
+            mContext.unregisterReceiver(mRemoteBugreportConsentReceiver);
+        }
+    };
+
     public static final class Lifecycle extends SystemService {
         private DevicePolicyManagerService mService;
 
@@ -305,6 +366,7 @@
         int mPasswordOwner = -1;
         long mLastMaximumTimeToLock = -1;
         boolean mUserSetupComplete = false;
+        int mUserProvisioningState;
         int mPermissionPolicy;
 
         final ArrayMap<ComponentName, ActiveAdmin> mAdminMap = new ArrayMap<>();
@@ -322,6 +384,14 @@
 
         boolean doNotAskCredentialsOnBoot = false;
 
+        String mApplicationRestrictionsManagingPackage;
+
+        Set<String> mAffiliationIds = new ArraySet<>();
+
+        // Used for initialization of users created by createAndManageUsers.
+        boolean mAdminBroadcastPending = false;
+        PersistableBundle mInitBundle = null;
+
         public DevicePolicyData(int userHandle) {
             mUserHandle = userHandle;
         }
@@ -337,6 +407,20 @@
             final String action = intent.getAction();
             final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
                     getSendingUserId());
+
+            if (Intent.ACTION_BOOT_COMPLETED.equals(action)
+                    && 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);
+                mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
+                mInjector.getNotificationManager().notify(
+                        LOG_TAG, RemoteBugreportUtils.REMOTE_BUGREPORT_CONSENT_NOTIFICATION_ID,
+                        RemoteBugreportUtils.buildRemoteBugreportConsentNotification(mContext));
+            }
             if (Intent.ACTION_BOOT_COMPLETED.equals(action)
                     || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
                 if (VERBOSE_LOG) {
@@ -356,16 +440,15 @@
             }
             if (Intent.ACTION_USER_REMOVED.equals(action)) {
                 removeUserData(userHandle);
-            } else if (Intent.ACTION_USER_STARTED.equals(action)
-                    || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
-
-                if (Intent.ACTION_USER_STARTED.equals(action)) {
+            } else if (Intent.ACTION_USER_STARTED.equals(action)) {
+                synchronized (DevicePolicyManagerService.this) {
                     // Reset the policy data
-                    synchronized (DevicePolicyManagerService.this) {
-                        mUserData.remove(userHandle);
-                    }
+                    mUserData.remove(userHandle);
+                    sendAdminEnabledBroadcastLocked(userHandle);
                 }
                 handlePackagesChanged(null /* check all admins */, userHandle);
+            } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
+                handlePackagesChanged(null /* check all admins */, userHandle);
             } else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)
                     || (Intent.ACTION_PACKAGE_ADDED.equals(action)
                             && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false))) {
@@ -383,11 +466,13 @@
         private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features";
         private static final String TAG_DISABLE_CAMERA = "disable-camera";
         private static final String TAG_DISABLE_CALLER_ID = "disable-caller-id";
+        private static final String TAG_DISABLE_CONTACTS_SEARCH = "disable-contacts-search";
         private static final String TAG_DISABLE_BLUETOOTH_CONTACT_SHARING
                 = "disable-bt-contacts-sharing";
         private static final String TAG_DISABLE_SCREEN_CAPTURE = "disable-screen-capture";
         private static final String TAG_DISABLE_ACCOUNT_MANAGEMENT = "disable-account-management";
         private static final String TAG_REQUIRE_AUTO_TIME = "require_auto_time";
+        private static final String TAG_FORCE_EPHEMERAL_USERS = "force_ephemeral_users";
         private static final String TAG_ACCOUNT_TYPE = "account-type";
         private static final String TAG_PERMITTED_ACCESSIBILITY_SERVICES
                 = "permitted-accessiblity-services";
@@ -420,6 +505,10 @@
         private static final String TAG_PACKAGE_LIST_ITEM  = "item";
         private static final String TAG_KEEP_UNINSTALLED_PACKAGES  = "keep-uninstalled-packages";
         private static final String TAG_USER_RESTRICTIONS = "user-restrictions";
+        private static final String TAG_SHORT_SUPPORT_MESSAGE = "short-support-message";
+        private static final String TAG_LONG_SUPPORT_MESSAGE = "long-support-message";
+        private static final String TAG_PARENT_ADMIN = "parent-admin";
+        private static final String TAG_ORGANIZATION_COLOR = "organization-color";
 
         final DeviceAdminInfo info;
 
@@ -468,9 +557,14 @@
         boolean encryptionRequested = false;
         boolean disableCamera = false;
         boolean disableCallerId = false;
+        boolean disableContactsSearch = false;
         boolean disableBluetoothContactSharing = true;
         boolean disableScreenCapture = false; // Can only be set by a device/profile owner.
         boolean requireAutoTime = false; // Can only be set by a device owner.
+        boolean forceEphemeralUsers = false; // Can only be set by a device owner.
+
+        ActiveAdmin parentAdmin;
+        final boolean isParent;
 
         static class TrustAgentInfo {
             public PersistableBundle options;
@@ -505,8 +599,30 @@
 
         Bundle userRestrictions;
 
-        ActiveAdmin(DeviceAdminInfo _info) {
+        // Support text provided by the admin to display to the user.
+        String shortSupportMessage = null;
+        String longSupportMessage = null;
+
+        // Background color of confirm credentials screen. Default: gray.
+        static final int DEF_ORGANIZATION_COLOR = Color.GRAY;
+        int organizationColor = DEF_ORGANIZATION_COLOR;
+
+        ActiveAdmin(DeviceAdminInfo _info, boolean parent) {
             info = _info;
+            isParent = parent;
+        }
+
+        ActiveAdmin getParentActiveAdmin() {
+            Preconditions.checkState(!isParent);
+
+            if (parentAdmin == null) {
+                parentAdmin = new ActiveAdmin(info, /* parent */ true);
+            }
+            return parentAdmin;
+        }
+
+        boolean hasParentActiveAdmin() {
+            return parentAdmin != null;
         }
 
         int getUid() { return info.getActivityInfo().applicationInfo.uid; }
@@ -615,6 +731,11 @@
                 out.attribute(null, ATTR_VALUE, Boolean.toString(disableCallerId));
                 out.endTag(null, TAG_DISABLE_CALLER_ID);
             }
+            if (disableContactsSearch) {
+                out.startTag(null, TAG_DISABLE_CONTACTS_SEARCH);
+                out.attribute(null, ATTR_VALUE, Boolean.toString(disableContactsSearch));
+                out.endTag(null, TAG_DISABLE_CONTACTS_SEARCH);
+            }
             if (disableBluetoothContactSharing) {
                 out.startTag(null, TAG_DISABLE_BLUETOOTH_CONTACT_SHARING);
                 out.attribute(null, ATTR_VALUE,
@@ -631,6 +752,11 @@
                 out.attribute(null, ATTR_VALUE, Boolean.toString(requireAutoTime));
                 out.endTag(null, TAG_REQUIRE_AUTO_TIME);
             }
+            if (forceEphemeralUsers) {
+                out.startTag(null, TAG_FORCE_EPHEMERAL_USERS);
+                out.attribute(null, ATTR_VALUE, Boolean.toString(forceEphemeralUsers));
+                out.endTag(null, TAG_FORCE_EPHEMERAL_USERS);
+            }
             if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) {
                 out.startTag(null, TAG_DISABLE_KEYGUARD_FEATURES);
                 out.attribute(null, ATTR_VALUE, Integer.toString(disabledKeyguardFeatures));
@@ -684,6 +810,26 @@
                 UserRestrictionsUtils.writeRestrictions(
                         out, userRestrictions, TAG_USER_RESTRICTIONS);
             }
+            if (!TextUtils.isEmpty(shortSupportMessage)) {
+                out.startTag(null, TAG_SHORT_SUPPORT_MESSAGE);
+                out.text(shortSupportMessage);
+                out.endTag(null, TAG_SHORT_SUPPORT_MESSAGE);
+            }
+            if (!TextUtils.isEmpty(longSupportMessage)) {
+                out.startTag(null, TAG_LONG_SUPPORT_MESSAGE);
+                out.text(longSupportMessage);
+                out.endTag(null, TAG_LONG_SUPPORT_MESSAGE);
+            }
+            if (parentAdmin != null) {
+                out.startTag(null, TAG_PARENT_ADMIN);
+                parentAdmin.writeToXml(out);
+                out.endTag(null, TAG_PARENT_ADMIN);
+            }
+            if (organizationColor != DEF_ORGANIZATION_COLOR) {
+                out.startTag(null, TAG_ORGANIZATION_COLOR);
+                out.attribute(null, ATTR_VALUE, Integer.toString(organizationColor));
+                out.endTag(null, TAG_ORGANIZATION_COLOR);
+            }
         }
 
         void writePackageListToXml(XmlSerializer out, String outerTag,
@@ -771,6 +917,9 @@
                 } else if (TAG_DISABLE_CALLER_ID.equals(tag)) {
                     disableCallerId = Boolean.parseBoolean(
                             parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_DISABLE_CONTACTS_SEARCH.equals(tag)) {
+                    disableContactsSearch = Boolean.parseBoolean(
+                            parser.getAttributeValue(null, ATTR_VALUE));
                 } else if (TAG_DISABLE_BLUETOOTH_CONTACT_SHARING.equals(tag)) {
                     disableBluetoothContactSharing = Boolean.parseBoolean(parser
                             .getAttributeValue(null, ATTR_VALUE));
@@ -778,7 +927,10 @@
                     disableScreenCapture = Boolean.parseBoolean(
                             parser.getAttributeValue(null, ATTR_VALUE));
                 } else if (TAG_REQUIRE_AUTO_TIME.equals(tag)) {
-                    requireAutoTime= Boolean.parseBoolean(
+                    requireAutoTime = Boolean.parseBoolean(
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_FORCE_EPHEMERAL_USERS.equals(tag)) {
+                    forceEphemeralUsers = Boolean.parseBoolean(
                             parser.getAttributeValue(null, ATTR_VALUE));
                 } else if (TAG_DISABLE_KEYGUARD_FEATURES.equals(tag)) {
                     disabledKeyguardFeatures = Integer.parseInt(
@@ -797,6 +949,28 @@
                     keepUninstalledPackages = readPackageList(parser, tag);
                 } else if (TAG_USER_RESTRICTIONS.equals(tag)) {
                     UserRestrictionsUtils.readRestrictions(parser, ensureUserRestrictions());
+                } else if (TAG_SHORT_SUPPORT_MESSAGE.equals(tag)) {
+                    type = parser.next();
+                    if (type == XmlPullParser.TEXT) {
+                        shortSupportMessage = parser.getText();
+                    } else {
+                        Log.w(LOG_TAG, "Missing text when loading short support message");
+                    }
+                } else if (TAG_LONG_SUPPORT_MESSAGE.equals(tag)) {
+                    type = parser.next();
+                    if (type == XmlPullParser.TEXT) {
+                        longSupportMessage = parser.getText();
+                    } else {
+                        Log.w(LOG_TAG, "Missing text when loading long support message");
+                    }
+                } else if (TAG_PARENT_ADMIN.equals(tag)) {
+                    Preconditions.checkState(!isParent);
+
+                    parentAdmin = new ActiveAdmin(info, /* parent */ true);
+                    parentAdmin.readFromXml(parser);
+                } else if (TAG_ORGANIZATION_COLOR.equals(tag)) {
+                    organizationColor = Integer.parseInt(
+                            parser.getAttributeValue(null, ATTR_VALUE));
                 } else {
                     Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
                     XmlUtils.skipCurrentTag(parser);
@@ -979,12 +1153,16 @@
                     pw.println(disableCamera);
             pw.print(prefix); pw.print("disableCallerId=");
                     pw.println(disableCallerId);
+            pw.print(prefix); pw.print("disableContactsSearch=");
+                    pw.println(disableContactsSearch);
             pw.print(prefix); pw.print("disableBluetoothContactSharing=");
                     pw.println(disableBluetoothContactSharing);
             pw.print(prefix); pw.print("disableScreenCapture=");
                     pw.println(disableScreenCapture);
             pw.print(prefix); pw.print("requireAutoTime=");
                     pw.println(requireAutoTime);
+            pw.print(prefix); pw.print("forceEphemeralUsers=");
+                    pw.println(forceEphemeralUsers);
             pw.print(prefix); pw.print("disabledKeyguardFeatures=");
                     pw.println(disabledKeyguardFeatures);
             pw.print(prefix); pw.print("crossProfileWidgetProviders=");
@@ -1003,6 +1181,12 @@
             }
             pw.print(prefix); pw.println("userRestrictions:");
             UserRestrictionsUtils.dumpRestrictions(pw, prefix + "  ", userRestrictions);
+            pw.print(prefix); pw.print("isParent=");
+                    pw.println(isParent);
+            if (parentAdmin != null) {
+                pw.print(prefix);  pw.println("parentAdmin:");
+                parentAdmin.dump(prefix + "  ", pw);
+            }
         }
     }
 
@@ -1035,19 +1219,15 @@
                 saveSettingsLocked(policy.mUserHandle);
             }
 
-            if (policy.mDelegatedCertInstallerPackage != null &&
-                    (packageName == null
-                    || packageName.equals(policy.mDelegatedCertInstallerPackage))) {
-                try {
-                    // Check if delegated cert installer package is removed.
-                    if (mIPackageManager.getPackageInfo(
-                            policy.mDelegatedCertInstallerPackage, 0, userHandle) == null) {
-                        policy.mDelegatedCertInstallerPackage = null;
-                        saveSettingsLocked(policy.mUserHandle);
-                    }
-                } catch (RemoteException e) {
-                    // Shouldn't happen
-                }
+            // Check if delegated cert installer or app restrictions managing packages are removed.
+            if (isRemovedPackage(packageName, policy.mDelegatedCertInstallerPackage, userHandle)) {
+                policy.mDelegatedCertInstallerPackage = null;
+                saveSettingsLocked(policy.mUserHandle);
+            }
+            if (isRemovedPackage(
+                    packageName, policy.mApplicationRestrictionsManagingPackage, userHandle)) {
+                policy.mApplicationRestrictionsManagingPackage = null;
+                saveSettingsLocked(policy.mUserHandle);
             }
         }
         if (removed) {
@@ -1056,6 +1236,18 @@
         }
     }
 
+    private boolean isRemovedPackage(String changedPackage, String targetPackage, int userHandle) {
+        try {
+            return targetPackage != null
+                    && (changedPackage == null || changedPackage.equals(targetPackage))
+                    && mIPackageManager.getPackageInfo(targetPackage, 0, userHandle) == null;
+        } catch (RemoteException e) {
+            // Shouldn't happen
+        }
+
+        return false;
+    }
+
     /**
      * Unit test will subclass it to inject mocks.
      */
@@ -1162,6 +1354,10 @@
             mContext.getSystemService(PowerManager.class).goToSleep(time, reason, flags);
         }
 
+        void powerManagerReboot(String reason) {
+            mContext.getSystemService(PowerManager.class).reboot(reason);
+        }
+
         boolean systemPropertiesGetBoolean(String key, boolean def) {
             return SystemProperties.getBoolean(key, def);
         }
@@ -1250,6 +1446,7 @@
         mIPackageManager = Preconditions.checkNotNull(injector.getIPackageManager());
 
         mLocalService = new LocalService();
+        mLockPatternUtils = injector.newLockPatternUtils();
 
         mHasFeature = mContext.getPackageManager()
                 .hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
@@ -1506,8 +1703,8 @@
      * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
      * reminders.  Clears alarm if no expirations are configured.
      */
-    protected void setExpirationAlarmCheckLocked(Context context, DevicePolicyData policy) {
-        final long expiration = getPasswordExpirationLocked(null, policy.mUserHandle);
+    private void setExpirationAlarmCheckLocked(Context context, int userHandle, boolean parent) {
+        final long expiration = getPasswordExpirationLocked(null, userHandle, parent);
         final long now = System.currentTimeMillis();
         final long timeToExpire = expiration - now;
         final long alarmTime;
@@ -1529,11 +1726,12 @@
 
         long token = mInjector.binderClearCallingIdentity();
         try {
+            int affectedUserHandle = parent ? getProfileParentId(userHandle) : userHandle;
             AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
             PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD,
                     new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
                     PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT,
-                    new UserHandle(policy.mUserHandle));
+                    UserHandle.of(affectedUserHandle));
             am.cancel(pi);
             if (alarmTime != 0) {
                 am.set(AlarmManager.RTC, alarmTime, pi);
@@ -1553,6 +1751,17 @@
         return null;
     }
 
+    ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle, boolean parent) {
+        if (parent) {
+            enforceManagedProfile(userHandle, "call APIs on the parent profile");
+        }
+        ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+        if (admin != null && parent) {
+            admin = admin.getParentActiveAdmin();
+        }
+        return admin;
+    }
+
     ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
             throws SecurityException {
         final int callingUid = mInjector.binderGetCallingUid();
@@ -1583,6 +1792,32 @@
         }
     }
 
+    ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy, boolean parent)
+            throws SecurityException {
+        if (parent) {
+            enforceManagedProfile(mInjector.userHandleGetCallingUserId(),
+                    "call APIs on the parent profile");
+        }
+        ActiveAdmin admin = getActiveAdminForCallerLocked(who, reqPolicy);
+        return parent ? admin.getParentActiveAdmin() : admin;
+    }
+    /**
+     * Find the admin for the component and userId bit of the uid, then check
+     * the admin's uid matches the uid.
+     */
+    private ActiveAdmin getActiveAdminForUidLocked(ComponentName who, int uid) {
+        final int userId = UserHandle.getUserId(uid);
+        final DevicePolicyData policy = getUserData(userId);
+        ActiveAdmin admin = policy.mAdminMap.get(who);
+        if (admin == null) {
+            throw new SecurityException("No active admin " + who);
+        }
+        if (admin.getUid() != uid) {
+            throw new SecurityException("Admin " + who + " is not owned by uid " + uid);
+        }
+        return admin;
+    }
+
     private ActiveAdmin getActiveAdminWithPolicyForUidLocked(ComponentName who, int reqPolicy,
             int uid) {
         // Try to find an admin which can use reqPolicy
@@ -1594,8 +1829,7 @@
                 throw new SecurityException("No active admin " + who);
             }
             if (admin.getUid() != uid) {
-                throw new SecurityException("Admin " + who + " is not owned by uid "
-                        + mInjector.binderGetCallingUid());
+                throw new SecurityException("Admin " + who + " is not owned by uid " + uid);
             }
             if (isActiveAdminWithPolicyForUserLocked(admin, reqPolicy, userId)) {
                 return admin;
@@ -1686,6 +1920,18 @@
         }
     }
 
+    /**
+     * Sends a broadcast to each profile that share the password unlock with the given user id.
+     */
+    private void sendAdminCommandForLockscreenPoliciesLocked(
+            String action, int reqPolicy, int userHandle) {
+        if (isSeparateProfileChallengeEnabled(userHandle)) {
+            sendAdminCommandLocked(action, reqPolicy, userHandle);
+        } else {
+            sendAdminCommandToSelfAndProfilesLocked(action, reqPolicy, userHandle);
+        }
+    }
+
     void removeActiveAdminLocked(final ComponentName adminReceiver, final int userHandle) {
         final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
         if (admin != null) {
@@ -1709,7 +1955,7 @@
                                     resetGlobalProxyLocked(getUserData(userHandle));
                                 }
                                 saveSettingsLocked(userHandle);
-                                updateMaximumTimeToLockLocked(policy);
+                                updateMaximumTimeToLockLocked(userHandle);
                                 policy.mRemovingAdmins.remove(adminReceiver);
                             }
                             // The removed admin might have disabled camera, so update user
@@ -1725,10 +1971,10 @@
         if (!mHasFeature) {
             return null;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         Intent resolveIntent = new Intent();
         resolveIntent.setComponent(adminName);
-        List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
+        List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceiversAsUser(
                 resolveIntent,
                 PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
                 userHandle);
@@ -1739,7 +1985,7 @@
         final ResolveInfo ri = infos.get(0);
 
         if (!permission.BIND_DEVICE_ADMIN.equals(ri.activityInfo.permission)) {
-            final String message = "DeviceAdminReceiver " + adminName + " must be protected with"
+            final String message = "DeviceAdminReceiver " + adminName + " must be protected with "
                     + permission.BIND_DEVICE_ADMIN;
             Slog.w(LOG_TAG, message);
             if (throwForMissiongPermission &&
@@ -1787,6 +2033,10 @@
                 out.attribute(null, ATTR_SETUP_COMPLETE,
                         Boolean.toString(true));
             }
+            if (policy.mUserProvisioningState != DevicePolicyManager.STATE_USER_UNMANAGED) {
+                out.attribute(null, ATTR_PROVISIONING_STATE,
+                        Integer.toString(policy.mUserProvisioningState));
+            }
             if (policy.mPermissionPolicy != DevicePolicyManager.PERMISSION_POLICY_PROMPT) {
                 out.attribute(null, ATTR_PERMISSION_POLICY,
                         Integer.toString(policy.mPermissionPolicy));
@@ -1795,6 +2045,10 @@
                 out.attribute(null, ATTR_DELEGATED_CERT_INSTALLER,
                         policy.mDelegatedCertInstallerPackage);
             }
+            if (policy.mApplicationRestrictionsManagingPackage != null) {
+                out.attribute(null, ATTR_APPLICATION_RESTRICTIONS_MANAGER,
+                        policy.mApplicationRestrictionsManagingPackage);
+            }
 
             final int N = policy.mAdminList.size();
             for (int i=0; i<N; i++) {
@@ -1854,6 +2108,25 @@
                 out.endTag(null, DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML);
             }
 
+            for (String id : policy.mAffiliationIds) {
+                out.startTag(null, TAG_AFFILIATION_ID);
+                out.attribute(null, "id", id);
+                out.endTag(null, TAG_AFFILIATION_ID);
+            }
+
+            if (policy.mAdminBroadcastPending) {
+                out.startTag(null, TAG_ADMIN_BROADCAST_PENDING);
+                out.attribute(null, ATTR_VALUE,
+                        Boolean.toString(policy.mAdminBroadcastPending));
+                out.endTag(null, TAG_ADMIN_BROADCAST_PENDING);
+            }
+
+            if (policy.mInitBundle != null) {
+                out.startTag(null, TAG_INITIALIZATION_BUNDLE);
+                policy.mInitBundle.saveToXml(out);
+                out.endTag(null, TAG_INITIALIZATION_BUNDLE);
+            }
+
             out.endTag(null, "policies");
 
             out.endDocument();
@@ -1862,7 +2135,7 @@
             stream.close();
             journal.commit();
             sendChangedNotification(userHandle);
-        } catch (IOException e) {
+        } catch (XmlPullParserException | IOException e) {
             Slog.w(LOG_TAG, "failed writing file", e);
             try {
                 if (stream != null) {
@@ -1914,18 +2187,25 @@
             if (userSetupComplete != null && Boolean.toString(true).equals(userSetupComplete)) {
                 policy.mUserSetupComplete = true;
             }
+            String provisioningState = parser.getAttributeValue(null, ATTR_PROVISIONING_STATE);
+            if (!TextUtils.isEmpty(provisioningState)) {
+                policy.mUserProvisioningState = Integer.parseInt(provisioningState);
+            }
             String permissionPolicy = parser.getAttributeValue(null, ATTR_PERMISSION_POLICY);
             if (!TextUtils.isEmpty(permissionPolicy)) {
                 policy.mPermissionPolicy = Integer.parseInt(permissionPolicy);
             }
             policy.mDelegatedCertInstallerPackage = parser.getAttributeValue(null,
                     ATTR_DELEGATED_CERT_INSTALLER);
+            policy.mApplicationRestrictionsManagingPackage = parser.getAttributeValue(null,
+                    ATTR_APPLICATION_RESTRICTIONS_MANAGER);
 
             type = parser.next();
             int outerDepth = parser.getDepth();
             policy.mLockTaskPackages.clear();
             policy.mAdminList.clear();
             policy.mAdminMap.clear();
+            policy.mAffiliationIds.clear();
             while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
                 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
@@ -1946,7 +2226,7 @@
                                     + userHandle);
                         }
                         if (dai != null) {
-                            ActiveAdmin ap = new ActiveAdmin(dai);
+                            ActiveAdmin ap = new ActiveAdmin(dai, /* parent */ false);
                             ap.readFromXml(parser);
                             policy.mAdminMap.put(ap.info.getComponent(), ap);
                         }
@@ -1983,6 +2263,13 @@
                             parser.getAttributeValue(null, ATTR_DISABLED));
                 } else if (DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML.equals(tag)) {
                     policy.doNotAskCredentialsOnBoot = true;
+                } else if (TAG_AFFILIATION_ID.equals(tag)) {
+                    policy.mAffiliationIds.add(parser.getAttributeValue(null, "id"));
+                } else if (TAG_ADMIN_BROADCAST_PENDING.equals(tag)) {
+                    String pending = parser.getAttributeValue(null, ATTR_VALUE);
+                    policy.mAdminBroadcastPending = Boolean.toString(true).equals(pending);
+                } else if (TAG_INITIALIZATION_BUNDLE.equals(tag)) {
+                    policy.mInitBundle = PersistableBundle.restoreFromXml(parser);
                 } else {
                     Slog.w(LOG_TAG, "Unknown tag: " + tag);
                     XmlUtils.skipCurrentTag(parser);
@@ -2011,12 +2298,12 @@
         // never normally happen.
         final long identity = mInjector.binderClearCallingIdentity();
         try {
-            LockPatternUtils utils = mInjector.newLockPatternUtils();
-            if (utils.getActivePasswordQuality(userHandle) < policy.mActivePasswordQuality) {
+            int actualPasswordQuality = mLockPatternUtils.getActivePasswordQuality(userHandle);
+            if (actualPasswordQuality < policy.mActivePasswordQuality) {
                 Slog.w(LOG_TAG, "Active password quality 0x"
                         + Integer.toHexString(policy.mActivePasswordQuality)
                         + " does not match actual quality 0x"
-                        + Integer.toHexString(utils.getActivePasswordQuality(userHandle)));
+                        + Integer.toHexString(actualPasswordQuality));
                 policy.mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
                 policy.mActivePasswordLength = 0;
                 policy.mActivePasswordUpperCase = 0;
@@ -2031,7 +2318,7 @@
         }
 
         validatePasswordOwnerLocked(policy);
-        updateMaximumTimeToLockLocked(policy);
+        updateMaximumTimeToLockLocked(userHandle);
         updateLockTaskPackagesLocked(policy.mLockTaskPackages, userHandle);
         if (policy.mStatusBarDisabled) {
             setStatusBarDisabledInternal(policy.mStatusBarDisabled, userHandle);
@@ -2077,6 +2364,7 @@
             case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
             case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
             case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
+            case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
                 return;
         }
         throw new IllegalArgumentException("Invalid quality constant: 0x"
@@ -2134,6 +2422,14 @@
         if (packageList != null) {
             mInjector.getPackageManagerInternal().setKeepUninstalledPackages(packageList);
         }
+
+        synchronized (this) {
+            // push the force-ephemeral-users policy to the user manager.
+            ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
+            if (deviceOwner != null) {
+                mUserManagerInternal.setForceEphemeralUsers(deviceOwner.forceEphemeralUsers);
+            }
+        }
     }
 
     private void ensureDeviceOwnerUserStarted() {
@@ -2194,25 +2490,20 @@
         synchronized (this) {
             final long now = System.currentTimeMillis();
 
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo ui : profiles) {
-                int profileUserHandle = ui.id;
-                final DevicePolicyData policy = getUserData(profileUserHandle);
-                final int count = policy.mAdminList.size();
-                if (count > 0) {
-                    for (int i = 0; i < count; i++) {
-                        final ActiveAdmin admin = policy.mAdminList.get(i);
-                        if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
-                                && admin.passwordExpirationTimeout > 0L
-                                && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS
-                                && admin.passwordExpirationDate > 0L) {
-                            sendAdminCommandLocked(admin,
-                                    DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
-                        }
-                    }
+            List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(
+                    userHandle, /* parent */ false);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
+                        && admin.passwordExpirationTimeout > 0L
+                        && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS
+                        && admin.passwordExpirationDate > 0L) {
+                    sendAdminCommandLocked(admin,
+                            DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
                 }
             }
-            setExpirationAlarmCheckLocked(mContext, getUserData(userHandle));
+            setExpirationAlarmCheckLocked(mContext, userHandle, /* parent */ false);
         }
     }
 
@@ -2322,7 +2613,7 @@
             Bundle onEnableData) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
 
         DevicePolicyData policy = getUserData(userHandle);
         DeviceAdminInfo info = findAdmin(adminReceiver, userHandle,
@@ -2337,7 +2628,7 @@
                         && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
                     throw new IllegalArgumentException("Admin is already added");
                 }
-                ActiveAdmin newAdmin = new ActiveAdmin(info);
+                ActiveAdmin newAdmin = new ActiveAdmin(info, /* parent */ false);
                 policy.mAdminMap.put(adminReceiver, newAdmin);
                 int replaceIndex = -1;
                 final int N = policy.mAdminList.size();
@@ -2368,7 +2659,7 @@
         if (!mHasFeature) {
             return false;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
             return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;
         }
@@ -2379,7 +2670,7 @@
         if (!mHasFeature) {
             return false;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
             DevicePolicyData policyData = getUserData(userHandle);
             return policyData.mRemovingAdmins.contains(adminReceiver);
@@ -2391,7 +2682,7 @@
         if (!mHasFeature) {
             return false;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
             ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
             if (administrator == null) {
@@ -2408,7 +2699,7 @@
             return Collections.EMPTY_LIST;
         }
 
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
             DevicePolicyData policy = getUserData(userHandle);
             final int N = policy.mAdminList.size();
@@ -2428,7 +2719,7 @@
         if (!mHasFeature) {
             return false;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
             DevicePolicyData policy = getUserData(userHandle);
             final int N = policy.mAdminList.size();
@@ -2446,7 +2737,7 @@
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
             ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
             if (admin == null) {
@@ -2472,96 +2763,145 @@
         }
     }
 
+    private boolean isAdminApiLevelMOrBelow(@NonNull ComponentName who, int userHandle) {
+        DeviceAdminInfo adminInfo = findAdmin(who, userHandle, false);
+        return adminInfo.getActivityInfo().applicationInfo.targetSdkVersion
+                <= Build.VERSION_CODES.M;
+    }
+
     @Override
-    public void setPasswordQuality(ComponentName who, int quality) {
+    public boolean isSeparateProfileChallengeAllowed(int userHandle) {
+        ComponentName profileOwner = getProfileOwner(userHandle);
+        return profileOwner != null && !isAdminApiLevelMOrBelow(profileOwner, userHandle);
+    }
+
+    @Override
+    public void setPasswordQuality(ComponentName who, int quality, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
         validateQualityConstant(quality);
 
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             if (ap.passwordQuality != quality) {
                 ap.passwordQuality = quality;
-                saveSettingsLocked(userHandle);
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
             }
         }
     }
 
     @Override
-    public int getPasswordQuality(ComponentName who, int userHandle) {
+    public int getPasswordQuality(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
             int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return admin != null ? admin.passwordQuality : mode;
             }
 
-            // Return strictest policy for this user and profiles that are visible from this user.
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                final int N = policy.mAdminList.size();
-                for (int i=0; i<N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (mode < admin.passwordQuality) {
-                        mode = admin.passwordQuality;
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins =
+                    getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (mode < admin.passwordQuality) {
+                    mode = admin.passwordQuality;
                 }
             }
             return mode;
         }
     }
 
+    private List<ActiveAdmin> getActiveAdminsForLockscreenPoliciesLocked(
+            int userHandle, boolean parent) {
+        if (!parent && isSeparateProfileChallengeEnabled(userHandle)) {
+            // If this user has a separate challenge, only return its restrictions.
+            return getUserDataUnchecked(userHandle).mAdminList;
+        } else {
+            // Return all admins for this user and the profiles that are visible from this
+            // user that do not use a separate work challenge.
+            ArrayList<ActiveAdmin> admins = new ArrayList<ActiveAdmin>();
+            for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) {
+                DevicePolicyData policy = getUserData(userInfo.id);
+                if (!isManagedProfile(userInfo.id)) {
+                    admins.addAll(policy.mAdminList);
+                } else {
+                    // For managed profiles, we always include the policies set on the parent
+                    // profile. Additionally, we include the ones set on the managed profile
+                    // if no separate challenge is in place.
+                    boolean hasSeparateChallenge = isSeparateProfileChallengeEnabled(userInfo.id);
+                    final int N = policy.mAdminList.size();
+                    for (int i = 0; i < N; i++) {
+                        ActiveAdmin admin = policy.mAdminList.get(i);
+                        if (admin.hasParentActiveAdmin()) {
+                            admins.add(admin.getParentActiveAdmin());
+                        }
+                        if (!hasSeparateChallenge) {
+                            admins.add(admin);
+                        }
+                    }
+                }
+            }
+            return admins;
+        }
+    }
+
+    private boolean isSeparateProfileChallengeEnabled(int userHandle) {
+        long ident = mInjector.binderClearCallingIdentity();
+        try {
+            return mLockPatternUtils.isSeparateProfileChallengeEnabled(userHandle);
+        } finally {
+            mInjector.binderRestoreCallingIdentity(ident);
+        }
+    }
+
     @Override
-    public void setPasswordMinimumLength(ComponentName who, int length) {
+    public void setPasswordMinimumLength(ComponentName who, int length, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             if (ap.minimumPasswordLength != length) {
                 ap.minimumPasswordLength = length;
-                saveSettingsLocked(userHandle);
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
             }
         }
     }
 
     @Override
-    public int getPasswordMinimumLength(ComponentName who, int userHandle) {
+    public int getPasswordMinimumLength(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return admin != null ? admin.minimumPasswordLength : length;
             }
 
-            // Return strictest policy for this user and profiles that are visible from this user.
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                final int N = policy.mAdminList.size();
-                for (int i=0; i<N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (length < admin.minimumPasswordLength) {
-                        length = admin.minimumPasswordLength;
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins =
+                    getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (length < admin.minimumPasswordLength) {
+                    length = admin.minimumPasswordLength;
                 }
             }
             return length;
@@ -2569,63 +2909,61 @@
     }
 
     @Override
-    public void setPasswordHistoryLength(ComponentName who, int length) {
+    public void setPasswordHistoryLength(ComponentName who, int length, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             if (ap.passwordHistoryLength != length) {
                 ap.passwordHistoryLength = length;
-                saveSettingsLocked(userHandle);
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
             }
         }
     }
 
     @Override
-    public int getPasswordHistoryLength(ComponentName who, int userHandle) {
+    public int getPasswordHistoryLength(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return admin != null ? admin.passwordHistoryLength : length;
             }
 
-            // Return strictest policy for this user and profiles that are visible from this user.
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                final int N = policy.mAdminList.size();
-                for (int i = 0; i < N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (length < admin.passwordHistoryLength) {
-                        length = admin.passwordHistoryLength;
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins =
+                    getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (length < admin.passwordHistoryLength) {
+                    length = admin.passwordHistoryLength;
                 }
             }
+
             return length;
         }
     }
 
     @Override
-    public void setPasswordExpirationTimeout(ComponentName who, long timeout) {
+    public void setPasswordExpirationTimeout(ComponentName who, long timeout, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
         Preconditions.checkArgumentNonnegative(timeout, "Timeout must be >= 0 ms");
-        final int userHandle = UserHandle.getCallingUserId();
+        final int userHandle = mInjector.userHandleGetCallingUserId();
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD, parent);
             // Calling this API automatically bumps the expiration date
             final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
             ap.passwordExpirationDate = expiration;
@@ -2636,8 +2974,9 @@
                         .format(new Date(expiration)));
             }
             saveSettingsLocked(userHandle);
-            // in case this is the first one
-            setExpirationAlarmCheckLocked(mContext, getUserData(userHandle));
+
+            // in case this is the first one, set the alarm on the appropriate user.
+            setExpirationAlarmCheckLocked(mContext, userHandle, parent);
         }
     }
 
@@ -2646,29 +2985,28 @@
      * Returns 0 if not configured.
      */
     @Override
-    public long getPasswordExpirationTimeout(ComponentName who, int userHandle) {
+    public long getPasswordExpirationTimeout(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0L;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
             long timeout = 0L;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return admin != null ? admin.passwordExpirationTimeout : timeout;
             }
 
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                final int N = policy.mAdminList.size();
-                for (int i = 0; i < N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
-                            && timeout > admin.passwordExpirationTimeout)) {
-                        timeout = admin.passwordExpirationTimeout;
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins =
+                    getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
+                        && timeout > admin.passwordExpirationTimeout)) {
+                    timeout = admin.passwordExpirationTimeout;
                 }
             }
             return timeout;
@@ -2749,81 +3087,76 @@
      * Return a single admin's expiration date/time, or the min (soonest) for all admins.
      * Returns 0 if not configured.
      */
-    private long getPasswordExpirationLocked(ComponentName who, int userHandle) {
+    private long getPasswordExpirationLocked(ComponentName who, int userHandle, boolean parent) {
         long timeout = 0L;
 
         if (who != null) {
-            ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+            ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
             return admin != null ? admin.passwordExpirationDate : timeout;
         }
 
-        List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-        for (UserInfo userInfo : profiles) {
-            DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-            final int N = policy.mAdminList.size();
-            for (int i = 0; i < N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (timeout == 0L || (admin.passwordExpirationDate != 0
-                        && timeout > admin.passwordExpirationDate)) {
-                    timeout = admin.passwordExpirationDate;
-                }
+        // Return the strictest policy across all participating admins.
+        List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+        final int N = admins.size();
+        for (int i = 0; i < N; i++) {
+            ActiveAdmin admin = admins.get(i);
+            if (timeout == 0L || (admin.passwordExpirationDate != 0
+                    && timeout > admin.passwordExpirationDate)) {
+                timeout = admin.passwordExpirationDate;
             }
         }
         return timeout;
     }
 
     @Override
-    public long getPasswordExpiration(ComponentName who, int userHandle) {
+    public long getPasswordExpiration(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0L;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
-            return getPasswordExpirationLocked(who, userHandle);
+            return getPasswordExpirationLocked(who, userHandle, parent);
         }
     }
 
     @Override
-    public void setPasswordMinimumUpperCase(ComponentName who, int length) {
+    public void setPasswordMinimumUpperCase(ComponentName who, int length, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             if (ap.minimumPasswordUpperCase != length) {
                 ap.minimumPasswordUpperCase = length;
-                saveSettingsLocked(userHandle);
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
             }
         }
     }
 
     @Override
-    public int getPasswordMinimumUpperCase(ComponentName who, int userHandle) {
+    public int getPasswordMinimumUpperCase(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return admin != null ? admin.minimumPasswordUpperCase : length;
             }
 
-            // Return strictest policy for this user and profiles that are visible from this user.
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                final int N = policy.mAdminList.size();
-                for (int i=0; i<N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (length < admin.minimumPasswordUpperCase) {
-                        length = admin.minimumPasswordUpperCase;
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins =
+                    getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (length < admin.minimumPasswordUpperCase) {
+                    length = admin.minimumPasswordUpperCase;
                 }
             }
             return length;
@@ -2831,43 +3164,40 @@
     }
 
     @Override
-    public void setPasswordMinimumLowerCase(ComponentName who, int length) {
+    public void setPasswordMinimumLowerCase(ComponentName who, int length, boolean parent) {
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             if (ap.minimumPasswordLowerCase != length) {
                 ap.minimumPasswordLowerCase = length;
-                saveSettingsLocked(userHandle);
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
             }
         }
     }
 
     @Override
-    public int getPasswordMinimumLowerCase(ComponentName who, int userHandle) {
+    public int getPasswordMinimumLowerCase(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return admin != null ? admin.minimumPasswordLowerCase : length;
             }
 
-            // Return strictest policy for this user and profiles that are visible from this user.
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                final int N = policy.mAdminList.size();
-                for (int i=0; i<N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (length < admin.minimumPasswordLowerCase) {
-                        length = admin.minimumPasswordLowerCase;
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins =
+                    getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (length < admin.minimumPasswordLowerCase) {
+                    length = admin.minimumPasswordLowerCase;
                 }
             }
             return length;
@@ -2875,49 +3205,46 @@
     }
 
     @Override
-    public void setPasswordMinimumLetters(ComponentName who, int length) {
+    public void setPasswordMinimumLetters(ComponentName who, int length, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             if (ap.minimumPasswordLetters != length) {
                 ap.minimumPasswordLetters = length;
-                saveSettingsLocked(userHandle);
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
             }
         }
     }
 
     @Override
-    public int getPasswordMinimumLetters(ComponentName who, int userHandle) {
+    public int getPasswordMinimumLetters(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return admin != null ? admin.minimumPasswordLetters : length;
             }
 
-            // Return strictest policy for this user and profiles that are visible from this user.
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                final int N = policy.mAdminList.size();
-                for (int i=0; i<N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
-                        continue;
-                    }
-                    if (length < admin.minimumPasswordLetters) {
-                        length = admin.minimumPasswordLetters;
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins =
+                    getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
+                    continue;
+                }
+                if (length < admin.minimumPasswordLetters) {
+                    length = admin.minimumPasswordLetters;
                 }
             }
             return length;
@@ -2925,49 +3252,46 @@
     }
 
     @Override
-    public void setPasswordMinimumNumeric(ComponentName who, int length) {
+    public void setPasswordMinimumNumeric(ComponentName who, int length, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             if (ap.minimumPasswordNumeric != length) {
                 ap.minimumPasswordNumeric = length;
-                saveSettingsLocked(userHandle);
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
             }
         }
     }
 
     @Override
-    public int getPasswordMinimumNumeric(ComponentName who, int userHandle) {
+    public int getPasswordMinimumNumeric(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return admin != null ? admin.minimumPasswordNumeric : length;
             }
 
-            // Return strictest policy for this user and profiles that are visible from this user.
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                final int N = policy.mAdminList.size();
-                for (int i = 0; i < N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
-                        continue;
-                    }
-                    if (length < admin.minimumPasswordNumeric) {
-                        length = admin.minimumPasswordNumeric;
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins =
+                    getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
+                    continue;
+                }
+                if (length < admin.minimumPasswordNumeric) {
+                    length = admin.minimumPasswordNumeric;
                 }
             }
             return length;
@@ -2975,49 +3299,46 @@
     }
 
     @Override
-    public void setPasswordMinimumSymbols(ComponentName who, int length) {
+    public void setPasswordMinimumSymbols(ComponentName who, int length, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             if (ap.minimumPasswordSymbols != length) {
                 ap.minimumPasswordSymbols = length;
-                saveSettingsLocked(userHandle);
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
             }
         }
     }
 
     @Override
-    public int getPasswordMinimumSymbols(ComponentName who, int userHandle) {
+    public int getPasswordMinimumSymbols(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return admin != null ? admin.minimumPasswordSymbols : length;
             }
 
-            // Return strictest policy for this user and profiles that are visible from this user.
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                final int N = policy.mAdminList.size();
-                for (int i=0; i<N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
-                        continue;
-                    }
-                    if (length < admin.minimumPasswordSymbols) {
-                        length = admin.minimumPasswordSymbols;
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins =
+                    getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
+                    continue;
+                }
+                if (length < admin.minimumPasswordSymbols) {
+                    length = admin.minimumPasswordSymbols;
                 }
             }
             return length;
@@ -3025,49 +3346,46 @@
     }
 
     @Override
-    public void setPasswordMinimumNonLetter(ComponentName who, int length) {
+    public void setPasswordMinimumNonLetter(ComponentName who, int length, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             if (ap.minimumPasswordNonLetter != length) {
                 ap.minimumPasswordNonLetter = length;
-                saveSettingsLocked(userHandle);
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
             }
         }
     }
 
     @Override
-    public int getPasswordMinimumNonLetter(ComponentName who, int userHandle) {
+    public int getPasswordMinimumNonLetter(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return admin != null ? admin.minimumPasswordNonLetter : length;
             }
 
-            // Return strictest policy for this user and profiles that are visible from this user.
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                final int N = policy.mAdminList.size();
-                for (int i=0; i<N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
-                        continue;
-                    }
-                    if (length < admin.minimumPasswordNonLetter) {
-                        length = admin.minimumPasswordNonLetter;
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins =
+                    getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
+                    continue;
+                }
+                if (length < admin.minimumPasswordNonLetter) {
+                    length = admin.minimumPasswordNonLetter;
                 }
             }
             return length;
@@ -3075,120 +3393,154 @@
     }
 
     @Override
-    public boolean isActivePasswordSufficient(int userHandle) {
+    public boolean isActivePasswordSufficient(int userHandle, boolean parent) {
         if (!mHasFeature) {
             return true;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
 
         synchronized (this) {
-            int id = getCredentialOwner(userHandle);
-            DevicePolicyData policy = getUserDataUnchecked(id);
-
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
-            getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
-            if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle)
-                    || policy.mActivePasswordLength < getPasswordMinimumLength(null, userHandle)) {
-                return false;
-            }
-            if (policy.mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
-                return true;
-            }
-            return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null, userHandle)
-                && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle)
-                && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle)
-                && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle)
-                && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle)
-                && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle);
+            getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
+            DevicePolicyData policy = getUserDataUnchecked(getCredentialOwner(userHandle, parent));
+            return isActivePasswordSufficientForUserLocked(policy, userHandle, parent);
         }
     }
 
     @Override
-    public int getCurrentFailedPasswordAttempts(int userHandle) {
+    public boolean isProfileActivePasswordSufficientForParent(int userHandle) {
+        if (!mHasFeature) {
+            return true;
+        }
+        enforceFullCrossUsersPermission(userHandle);
+        enforceManagedProfile(userHandle, "call APIs refering to the parent profile");
+
+        synchronized (this) {
+            int targetUser = getProfileParentId(userHandle);
+            DevicePolicyData policy = getUserDataUnchecked(getCredentialOwner(userHandle, false));
+            return isActivePasswordSufficientForUserLocked(policy, targetUser, false);
+        }
+    }
+
+    private boolean isActivePasswordSufficientForUserLocked(
+            DevicePolicyData policy, int userHandle, boolean parent) {
+        if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle, parent)
+                || policy.mActivePasswordLength < getPasswordMinimumLength(
+                        null, userHandle, parent)) {
+            return false;
+        }
+        if (policy.mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
+            return true;
+        }
+        return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(
+                    null, userHandle, parent)
+                && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(
+                        null, userHandle, parent)
+                && policy.mActivePasswordLetters >= getPasswordMinimumLetters(
+                        null, userHandle, parent)
+                && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(
+                        null, userHandle, parent)
+                && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(
+                        null, userHandle, parent)
+                && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(
+                        null, userHandle, parent);
+    }
+
+    @Override
+    public int getCurrentFailedPasswordAttempts(int userHandle, boolean parent) {
         synchronized (this) {
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
-            getActiveAdminForCallerLocked(null,
-                    DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
+            getActiveAdminForCallerLocked(
+                    null, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, parent);
 
-            int credentialOwnerId = getCredentialOwner(userHandle);
-            DevicePolicyData policy = getUserDataUnchecked(credentialOwnerId);
+            DevicePolicyData policy = getUserDataUnchecked(getCredentialOwner(userHandle, parent));
 
             return policy.mFailedPasswordAttempts;
         }
     }
 
     @Override
-    public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
+    public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
-            getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_WIPE_DATA);
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
+            getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_WIPE_DATA, parent);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, parent);
             if (ap.maximumFailedPasswordsForWipe != num) {
                 ap.maximumFailedPasswordsForWipe = num;
-                saveSettingsLocked(userHandle);
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
             }
         }
     }
 
     @Override
-    public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle) {
+    public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
-            ActiveAdmin admin = (who != null) ? getActiveAdminUncheckedLocked(who, userHandle)
-                    : getAdminWithMinimumFailedPasswordsForWipeLocked(userHandle);
+            ActiveAdmin admin = (who != null)
+                    ? getActiveAdminUncheckedLocked(who, userHandle, parent)
+                    : getAdminWithMinimumFailedPasswordsForWipeLocked(userHandle, parent);
             return admin != null ? admin.maximumFailedPasswordsForWipe : 0;
         }
     }
 
     @Override
-    public int getProfileWithMinimumFailedPasswordsForWipe(int userHandle) {
+    public int getProfileWithMinimumFailedPasswordsForWipe(int userHandle, boolean parent) {
         if (!mHasFeature) {
             return UserHandle.USER_NULL;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
-            ActiveAdmin admin = getAdminWithMinimumFailedPasswordsForWipeLocked(userHandle);
+            ActiveAdmin admin = getAdminWithMinimumFailedPasswordsForWipeLocked(
+                    userHandle, parent);
             return admin != null ? admin.getUserHandle().getIdentifier() : UserHandle.USER_NULL;
         }
     }
 
     /**
-     * Returns the admin with the strictest policy on maximum failed passwords for this user and all
-     * profiles that are visible from this user. If the policy for the primary and any other profile
-     * are equal, it returns the admin for the primary profile.
-     * Returns {@code null} if none of them have that policy set.
+     * Returns the admin with the strictest policy on maximum failed passwords for:
+     * <ul>
+     *   <li>this user if it has a separate profile challenge, or
+     *   <li>this user and all profiles that don't have their own challenge otherwise.
+     * </ul>
+     * <p>If the policy for the primary and any other profile are equal, it returns the admin for
+     * the primary profile.
+     * Returns {@code null} if no participating admin has that policy set.
      */
-    private ActiveAdmin getAdminWithMinimumFailedPasswordsForWipeLocked(int userHandle) {
+    private ActiveAdmin getAdminWithMinimumFailedPasswordsForWipeLocked(
+            int userHandle, boolean parent) {
         int count = 0;
         ActiveAdmin strictestAdmin = null;
-        for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) {
-            DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-            for (ActiveAdmin admin : policy.mAdminList) {
-                if (admin.maximumFailedPasswordsForWipe ==
-                        ActiveAdmin.DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
-                    continue;  // No max number of failed passwords policy set for this profile.
-                }
 
-                // We always favor the primary profile if several profiles have the same value set.
-                if (count == 0 ||
-                        count > admin.maximumFailedPasswordsForWipe ||
-                        (userInfo.isPrimary() && count >= admin.maximumFailedPasswordsForWipe)) {
-                    count = admin.maximumFailedPasswordsForWipe;
-                    strictestAdmin = admin;
-                }
+        // Return the strictest policy across all participating admins.
+        List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+        final int N = admins.size();
+        for (int i = 0; i < N; i++) {
+            ActiveAdmin admin = admins.get(i);
+            if (admin.maximumFailedPasswordsForWipe ==
+                    ActiveAdmin.DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
+                continue;  // No max number of failed passwords policy set for this profile.
+            }
+
+            // We always favor the primary profile if several profiles have the same value set.
+            int userId = admin.getUserHandle().getIdentifier();
+            if (count == 0 ||
+                    count > admin.maximumFailedPasswordsForWipe ||
+                    (count == admin.maximumFailedPasswordsForWipe &&
+                            mUserManager.getUserInfo(userId).isPrimary())) {
+                count = admin.maximumFailedPasswordsForWipe;
+                strictestAdmin = admin;
             }
         }
         return strictestAdmin;
@@ -3202,14 +3554,9 @@
         final int callingUid = mInjector.binderGetCallingUid();
         final int userHandle = mInjector.userHandleGetCallingUserId();
 
-        long ident = mInjector.binderClearCallingIdentity();
-        try {
-            if (getCredentialOwner(userHandle) != userHandle) {
-                throw new SecurityException("You can not change password for this profile because"
+        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");
-            }
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
         }
 
         String password = passwordOrNull != null ? passwordOrNull : "";
@@ -3253,7 +3600,10 @@
                     }
                 }
             }
-            quality = getPasswordQuality(null, userHandle);
+            quality = getPasswordQuality(null, userHandle, /* parent */ false);
+            if (quality == DevicePolicyManager.PASSWORD_QUALITY_MANAGED) {
+                quality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+            }
             if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
                 int realQuality = LockPatternUtils.computePasswordQuality(password);
                 if (realQuality < quality
@@ -3266,7 +3616,7 @@
                 }
                 quality = Math.max(realQuality, quality);
             }
-            int length = getPasswordMinimumLength(null, userHandle);
+            int length = getPasswordMinimumLength(null, userHandle, /* parent */ false);
             if (password.length() < length) {
                 Slog.w(LOG_TAG, "resetPassword: password length " + password.length()
                         + " does not meet required length " + length);
@@ -3295,40 +3645,43 @@
                         nonletter++;
                     }
                 }
-                int neededLetters = getPasswordMinimumLetters(null, userHandle);
+                int neededLetters = getPasswordMinimumLetters(null, userHandle, /* parent */ false);
                 if(letters < neededLetters) {
                     Slog.w(LOG_TAG, "resetPassword: number of letters " + letters
                             + " does not meet required number of letters " + neededLetters);
                     return false;
                 }
-                int neededNumbers = getPasswordMinimumNumeric(null, userHandle);
+                int neededNumbers = getPasswordMinimumNumeric(null, userHandle, /* parent */ false);
                 if (numbers < neededNumbers) {
                     Slog.w(LOG_TAG, "resetPassword: number of numerical digits " + numbers
                             + " does not meet required number of numerical digits "
                             + neededNumbers);
                     return false;
                 }
-                int neededLowerCase = getPasswordMinimumLowerCase(null, userHandle);
+                int neededLowerCase = getPasswordMinimumLowerCase(
+                        null, userHandle, /* parent */ false);
                 if (lowercase < neededLowerCase) {
                     Slog.w(LOG_TAG, "resetPassword: number of lowercase letters " + lowercase
                             + " does not meet required number of lowercase letters "
                             + neededLowerCase);
                     return false;
                 }
-                int neededUpperCase = getPasswordMinimumUpperCase(null, userHandle);
+                int neededUpperCase = getPasswordMinimumUpperCase(
+                        null, userHandle, /* parent */ false);
                 if (uppercase < neededUpperCase) {
                     Slog.w(LOG_TAG, "resetPassword: number of uppercase letters " + uppercase
                             + " does not meet required number of uppercase letters "
                             + neededUpperCase);
                     return false;
                 }
-                int neededSymbols = getPasswordMinimumSymbols(null, userHandle);
+                int neededSymbols = getPasswordMinimumSymbols(null, userHandle, /* parent */ false);
                 if (symbols < neededSymbols) {
                     Slog.w(LOG_TAG, "resetPassword: number of special symbols " + symbols
                             + " does not meet required number of special symbols " + neededSymbols);
                     return false;
                 }
-                int neededNonLetter = getPasswordMinimumNonLetter(null, userHandle);
+                int neededNonLetter = getPasswordMinimumNonLetter(
+                        null, userHandle, /* parent */ false);
                 if (nonletter < neededNonLetter) {
                     Slog.w(LOG_TAG, "resetPassword: number of non-letter characters " + nonletter
                             + " does not meet required number of non-letter characters "
@@ -3353,17 +3706,16 @@
 
         // Don't do this with the lock held, because it is going to call
         // back in to the service.
-        ident = mInjector.binderClearCallingIdentity();
+        final long ident = mInjector.binderClearCallingIdentity();
         try {
-            LockPatternUtils utils = mInjector.newLockPatternUtils();
             if (!TextUtils.isEmpty(password)) {
-                utils.saveLockPassword(password, null, quality, userHandle);
+                mLockPatternUtils.saveLockPassword(password, null, quality, userHandle);
             } else {
-                utils.clearLock(userHandle);
+                mLockPatternUtils.clearLock(userHandle);
             }
             boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0;
             if (requireEntry) {
-                utils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
+                mLockPatternUtils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
                         UserHandle.USER_ALL);
             }
             synchronized (this) {
@@ -3383,7 +3735,7 @@
     private boolean isLockScreenSecureUnchecked(int userId) {
         long ident = mInjector.binderClearCallingIdentity();
         try {
-            return mInjector.newLockPatternUtils().isSecure(userId);
+            return mLockPatternUtils.isSecure(userId);
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
         }
@@ -3410,75 +3762,92 @@
     }
 
     @Override
-    public void setMaximumTimeToLock(ComponentName who, long timeMs) {
+    public void setMaximumTimeToLock(ComponentName who, long timeMs, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
+        final int userHandle = mInjector.userHandleGetCallingUserId();
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_FORCE_LOCK, parent);
             if (ap.maximumTimeToUnlock != timeMs) {
                 ap.maximumTimeToUnlock = timeMs;
                 saveSettingsLocked(userHandle);
-                updateMaximumTimeToLockLocked(getUserData(userHandle));
+                updateMaximumTimeToLockLocked(userHandle);
             }
         }
     }
 
-    void updateMaximumTimeToLockLocked(DevicePolicyData policy) {
-        long timeMs = getMaximumTimeToLock(null, policy.mUserHandle);
+    void updateMaximumTimeToLockLocked(int userHandle) {
+        // Calculate the min timeout for all profiles - including the ones with a separate
+        // challenge. Ideally if the timeout only affected the profile challenge we'd lock that
+        // challenge only and keep the screen on. However there is no easy way of doing that at the
+        // moment so we set the screen off timeout regardless of whether it affects the parent user
+        // or the profile challenge only.
+        long timeMs = Integer.MAX_VALUE;
+        List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+        for (UserInfo userInfo : profiles) {
+            DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
+            final int N = policy.mAdminList.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = policy.mAdminList.get(i);
+                if (admin.maximumTimeToUnlock > 0
+                        && timeMs > admin.maximumTimeToUnlock) {
+                    timeMs = admin.maximumTimeToUnlock;
+                }
+            }
+        }
+
+        // We only store the last maximum time to lock on the parent profile. So if calling from a
+        // managed profile, retrieve the policy for the parent.
+        DevicePolicyData policy = getUserDataUnchecked(getProfileParentId(userHandle));
         if (policy.mLastMaximumTimeToLock == timeMs) {
             return;
         }
+        policy.mLastMaximumTimeToLock = timeMs;
 
-        long ident = mInjector.binderClearCallingIdentity();
+        final long ident = mInjector.binderClearCallingIdentity();
         try {
-            if (timeMs <= 0) {
-                timeMs = Integer.MAX_VALUE;
-            } else {
+            if (policy.mLastMaximumTimeToLock != Integer.MAX_VALUE) {
                 // Make sure KEEP_SCREEN_ON is disabled, since that
                 // would allow bypassing of the maximum time to lock.
                 mInjector.settingsGlobalPutInt(Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
             }
 
-            policy.mLastMaximumTimeToLock = timeMs;
             // TODO It can overflow.  Cap it.
             mInjector.getPowerManagerInternal()
-                    .setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
+                    .setMaximumScreenOffTimeoutFromDeviceAdmin((int)policy.mLastMaximumTimeToLock);
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
         }
     }
 
     @Override
-    public long getMaximumTimeToLock(ComponentName who, int userHandle) {
+    public long getMaximumTimeToLock(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
             long time = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return admin != null ? admin.maximumTimeToUnlock : time;
             }
 
-            // Return strictest policy for this user and profiles that are visible from this user.
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                final int N = policy.mAdminList.size();
-                for (int i=0; i<N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (time == 0) {
-                        time = admin.maximumTimeToUnlock;
-                    } else if (admin.maximumTimeToUnlock != 0
-                            && time > admin.maximumTimeToUnlock) {
-                        time = admin.maximumTimeToUnlock;
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(
+                    userHandle, parent);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (time == 0) {
+                    time = admin.maximumTimeToUnlock;
+                } else if (admin.maximumTimeToUnlock != 0
+                        && time > admin.maximumTimeToUnlock) {
+                    time = admin.maximumTimeToUnlock;
                 }
             }
             return time;
@@ -3486,32 +3855,36 @@
     }
 
     @Override
-    public void lockNow() {
+    public void lockNow(boolean parent) {
         if (!mHasFeature) {
             return;
         }
         synchronized (this) {
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
-            getActiveAdminForCallerLocked(null,
-                    DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
-            lockNowUnchecked();
-        }
-    }
+            getActiveAdminForCallerLocked(
+                    null, DeviceAdminInfo.USES_POLICY_FORCE_LOCK, parent);
 
-    private void lockNowUnchecked() {
-        long ident = mInjector.binderClearCallingIdentity();
-        try {
-            // Power off the display
-            mInjector.powerManagerGoToSleep(SystemClock.uptimeMillis(),
-                    PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN, 0);
-            // Ensure the device is locked
-            new LockPatternUtils(mContext).requireStrongAuth(
-                    STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW, UserHandle.USER_ALL);
-            mInjector.getIWindowManager().lockNow(null);
-        } catch (RemoteException e) {
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
+            int userToLock = mInjector.userHandleGetCallingUserId();
+
+            // Unless this is a managed profile with work challenge enabled, lock all users.
+            if (parent || !isSeparateProfileChallengeEnabled(userToLock)) {
+                userToLock = UserHandle.USER_ALL;
+            }
+            final long ident = mInjector.binderClearCallingIdentity();
+            try {
+                mLockPatternUtils.requireStrongAuth(
+                        STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW, userToLock);
+                if (userToLock == UserHandle.USER_ALL) {
+                    // Power off the display
+                    mInjector.powerManagerGoToSleep(SystemClock.uptimeMillis(),
+                            PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN, 0);
+                    mInjector.getIWindowManager().lockNow(null);
+                }
+            } catch (RemoteException e) {
+            } finally {
+                mInjector.binderRestoreCallingIdentity(ident);
+            }
         }
     }
 
@@ -3550,7 +3923,7 @@
             }
 
             try {
-                int uid = mContext.getPackageManager().getPackageUid(
+                int uid = mContext.getPackageManager().getPackageUidAsUser(
                         policy.mDelegatedCertInstallerPackage, userHandle);
                 return uid == callingUid;
             } catch (NameNotFoundException e) {
@@ -3760,6 +4133,42 @@
         }
     }
 
+    @Override
+    public boolean setAlwaysOnVpnPackage(ComponentName admin, String vpnPackage)
+            throws SecurityException {
+        synchronized (this) {
+            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+        }
+
+        final int userId = mInjector.userHandleGetCallingUserId();
+        final long token = mInjector.binderClearCallingIdentity();
+        try{
+            ConnectivityManager connectivityManager = (ConnectivityManager)
+                    mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+            return connectivityManager.setAlwaysOnVpnPackageForUser(userId, vpnPackage);
+        } finally {
+            mInjector.binderRestoreCallingIdentity(token);
+        }
+    }
+
+    @Override
+    public String getAlwaysOnVpnPackage(ComponentName admin)
+            throws SecurityException {
+        synchronized (this) {
+            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+        }
+
+        final int userId = mInjector.userHandleGetCallingUserId();
+        final long token = mInjector.binderClearCallingIdentity();
+        try{
+            ConnectivityManager connectivityManager = (ConnectivityManager)
+                    mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+            return connectivityManager.getAlwaysOnVpnPackageForUser(userId);
+        } finally {
+            mInjector.binderRestoreCallingIdentity(token);
+        }
+    }
+
     private void wipeDataLocked(boolean wipeExtRequested, String reason) {
         if (wipeExtRequested) {
             StorageManager sm = (StorageManager) mContext.getSystemService(
@@ -3779,7 +4188,7 @@
             return;
         }
         final int userHandle = mInjector.userHandleGetCallingUserId();
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
@@ -3858,7 +4267,7 @@
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
 
@@ -3887,9 +4296,10 @@
         if (!mHasFeature) {
             return;
         }
-        enforceCrossUserPermission(userHandle);
-        // Managed Profile password can only be changed when per user encryption is present.
-        if (!LockPatternUtils.isSeparateWorkChallengeEnabled()) {
+        enforceFullCrossUsersPermission(userHandle);
+
+        // Managed Profile password can only be changed when it has a separate challenge.
+        if (!isSeparateProfileChallengeEnabled(userHandle)) {
             enforceNotManagedProfile(userHandle, "set the active password");
         }
 
@@ -3913,18 +4323,12 @@
                 policy.mFailedPasswordAttempts = 0;
                 saveSettingsLocked(userHandle);
                 updatePasswordExpirationsLocked(userHandle);
-                setExpirationAlarmCheckLocked(mContext, policy);
+                setExpirationAlarmCheckLocked(mContext, userHandle, /* parent */ false);
 
                 // Send a broadcast to each profile using this password as its primary unlock.
-                if (LockPatternUtils.isSeparateWorkChallengeEnabled()) {
-                    sendAdminCommandLocked(
-                            DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
-                            DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
-                } else {
-                    sendAdminCommandToSelfAndProfilesLocked(
-                            DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
-                            DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
-                }
+                sendAdminCommandForLockscreenPoliciesLocked(
+                        DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
+                        DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
             }
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
@@ -3935,33 +4339,35 @@
      * Called any time the device password is updated. Resets all password expiration clocks.
      */
     private void updatePasswordExpirationsLocked(int userHandle) {
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                int profileId = userInfo.id;
-                DevicePolicyData policy = getUserDataUnchecked(profileId);
-                final int N = policy.mAdminList.size();
-                if (N > 0) {
-                    for (int i=0; i<N; i++) {
-                        ActiveAdmin admin = policy.mAdminList.get(i);
-                        if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
-                            long timeout = admin.passwordExpirationTimeout;
-                            long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
-                            admin.passwordExpirationDate = expiration;
-                        }
-                    }
-                }
-                saveSettingsLocked(profileId);
+        ArraySet<Integer> affectedUserIds = new ArraySet<Integer>();
+        List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(
+                userHandle, /* parent */ false);
+        final int N = admins.size();
+        for (int i = 0; i < N; i++) {
+            ActiveAdmin admin = admins.get(i);
+            if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
+                affectedUserIds.add(admin.getUserHandle().getIdentifier());
+                long timeout = admin.passwordExpirationTimeout;
+                long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
+                admin.passwordExpirationDate = expiration;
             }
+        }
+        for (int affectedUserId : affectedUserIds) {
+            saveSettingsLocked(affectedUserId);
+        }
     }
 
     @Override
     public void reportFailedPasswordAttempt(int userHandle) {
-        enforceCrossUserPermission(userHandle);
-        enforceNotManagedProfile(userHandle, "report failed password attempt");
+        enforceFullCrossUsersPermission(userHandle);
+        if (!isSeparateProfileChallengeEnabled(userHandle)) {
+            enforceNotManagedProfile(userHandle,
+                    "report failed password attempt if separate profile challenge is not in place");
+        }
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
 
-        long ident = mInjector.binderClearCallingIdentity();
+        final long ident = mInjector.binderClearCallingIdentity();
         try {
             boolean wipeData = false;
             int identifier = 0;
@@ -3970,8 +4376,8 @@
                 policy.mFailedPasswordAttempts++;
                 saveSettingsLocked(userHandle);
                 if (mHasFeature) {
-                    ActiveAdmin strictestAdmin =
-                            getAdminWithMinimumFailedPasswordsForWipeLocked(userHandle);
+                    ActiveAdmin strictestAdmin = getAdminWithMinimumFailedPasswordsForWipeLocked(
+                            userHandle, /* parent */ false);
                     int max = strictestAdmin != null
                             ? strictestAdmin.maximumFailedPasswordsForWipe : 0;
                     if (max > 0 && policy.mFailedPasswordAttempts >= max) {
@@ -3981,7 +4387,8 @@
                         wipeData = true;
                         identifier = strictestAdmin.getUserHandle().getIdentifier();
                     }
-                    sendAdminCommandToSelfAndProfilesLocked(
+
+                    sendAdminCommandForLockscreenPoliciesLocked(
                             DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
                             DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
                 }
@@ -3994,11 +4401,15 @@
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
         }
+
+        if (SecurityLog.isLoggingEnabled()) {
+            SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 0);
+        }
     }
 
     @Override
     public void reportSuccessfulPasswordAttempt(int userHandle) {
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
 
@@ -4011,7 +4422,7 @@
                     policy.mPasswordOwner = -1;
                     saveSettingsLocked(userHandle);
                     if (mHasFeature) {
-                        sendAdminCommandToSelfAndProfilesLocked(
+                        sendAdminCommandForLockscreenPoliciesLocked(
                                 DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
                                 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
                     }
@@ -4020,6 +4431,28 @@
                 }
             }
         }
+
+        if (SecurityLog.isLoggingEnabled()) {
+            SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT, /*result*/ 1);
+        }
+    }
+
+    @Override
+    public void reportKeyguardDismissed() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+        if (SecurityLog.isLoggingEnabled()) {
+            SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISMISSED);
+        }
+    }
+
+    @Override
+    public void reportKeyguardSecured() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+        if (SecurityLog.isLoggingEnabled()) {
+            SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_SECURED);
+        }
     }
 
     @Override
@@ -4082,7 +4515,7 @@
         if (!mHasFeature) {
             return null;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized(this) {
             DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
             // Scan through active admins and find if anyone has already
@@ -4219,7 +4652,7 @@
         if (!mHasFeature) {
             return false;
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
             // Check for permissions if a particular caller is specified
             if (who != null) {
@@ -4249,7 +4682,7 @@
         if (!mHasFeature) {
             // Ok to return current status.
         }
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         return getEncryptionStatus();
     }
 
@@ -4402,6 +4835,252 @@
         }
     }
 
+    @Override
+    public void setForceEphemeralUsers(ComponentName who, boolean forceEphemeralUsers) {
+        if (!mHasFeature) {
+            return;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        boolean removeAllUsers = false;
+        synchronized (this) {
+            final ActiveAdmin deviceOwner =
+                    getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+            if (deviceOwner.forceEphemeralUsers != forceEphemeralUsers) {
+                deviceOwner.forceEphemeralUsers = forceEphemeralUsers;
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+                mUserManagerInternal.setForceEphemeralUsers(forceEphemeralUsers);
+                removeAllUsers = forceEphemeralUsers;
+            }
+        }
+        if (removeAllUsers) {
+            long identitity = mInjector.binderClearCallingIdentity();
+            try {
+                mUserManagerInternal.removeAllUsers();
+            } finally {
+                mInjector.binderRestoreCallingIdentity(identitity);
+            }
+        }
+    }
+
+    @Override
+    public boolean getForceEphemeralUsers(ComponentName who) {
+        if (!mHasFeature) {
+            return false;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        synchronized (this) {
+            final ActiveAdmin deviceOwner =
+                    getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+            return deviceOwner.forceEphemeralUsers;
+        }
+    }
+
+    private void ensureDeviceOwnerManagingSingleUser(ComponentName who) throws SecurityException {
+        synchronized (this) {
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+        }
+        final long callingIdentity = mInjector.binderClearCallingIdentity();
+        try {
+            if (mInjector.userManagerIsSplitSystemUser()) {
+                // In split system user mode, only allow the case where the device owner is managing
+                // the only non-system user of the device
+                if (mUserManager.getUserCount() > 2
+                        || mOwners.getDeviceOwnerUserId() == UserHandle.USER_SYSTEM) {
+                    throw new SecurityException(
+                            "There should only be one user, managed by Device Owner");
+                }
+            } else if (mUserManager.getUserCount() > 1) {
+                throw new SecurityException(
+                        "There should only be one user, managed by Device Owner");
+            }
+        } finally {
+            mInjector.binderRestoreCallingIdentity(callingIdentity);
+        }
+    }
+
+    @Override
+    public boolean requestBugreport(ComponentName who) {
+        if (!mHasFeature) {
+            return false;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        ensureDeviceOwnerManagingSingleUser(who);
+
+        if (mRemoteBugreportServiceIsActive.get()
+                || (getDeviceOwnerRemoteBugreportUri() != null)) {
+            Slog.d(LOG_TAG, "Remote bugreport wasn't started because there's already one running.");
+            return false;
+        }
+
+        final long callingIdentity = mInjector.binderClearCallingIdentity();
+        try {
+            ActivityManagerNative.getDefault().requestBugReport(
+                    ActivityManager.BUGREPORT_OPTION_REMOTE);
+
+            mRemoteBugreportServiceIsActive.set(true);
+            mRemoteBugreportSharingAccepted.set(false);
+            registerRemoteBugreportReceivers();
+            mInjector.getNotificationManager().notify(
+                    LOG_TAG, RemoteBugreportUtils.REMOTE_BUGREPORT_CONSENT_NOTIFICATION_ID,
+                    RemoteBugreportUtils.buildRemoteBugreportConsentNotification(mContext));
+            mInjector.getNotificationManager().notify(
+                    LOG_TAG, RemoteBugreportUtils.REMOTE_BUGREPORT_IN_PROGRESS_NOTIFICATION_ID,
+                    RemoteBugreportUtils.buildRemoteBugreportInProgressNotification(mContext,
+                            /* canCancelBugReport */ true));
+            mHandler.postDelayed(mRemoteBugreportTimeoutRunnable,
+                    RemoteBugreportUtils.REMOTE_BUGREPORT_TIMEOUT_MILLIS);
+            return true;
+        } catch (RemoteException re) {
+            // should never happen
+            Slog.e(LOG_TAG, "Failed to make remote calls to start bugreportremote service", re);
+            return false;
+        } finally {
+            mInjector.binderRestoreCallingIdentity(callingIdentity);
+        }
+    }
+
+    private synchronized void sendDeviceOwnerCommand(String action, Bundle extras) {
+        Intent intent = new Intent(action);
+        intent.setComponent(mOwners.getDeviceOwnerComponent());
+        if (extras != null) {
+            intent.putExtras(extras);
+        }
+        mContext.sendBroadcastAsUser(intent, UserHandle.of(mOwners.getDeviceOwnerUserId()));
+    }
+
+    private synchronized String getDeviceOwnerRemoteBugreportUri() {
+        return mOwners.getDeviceOwnerRemoteBugreportUri();
+    }
+
+    private synchronized void setDeviceOwnerRemoteBugreportUriAndHash(String bugreportUri,
+            String bugreportHash) {
+        mOwners.setDeviceOwnerRemoteBugreportUriAndHash(bugreportUri, bugreportHash);
+    }
+
+    private void registerRemoteBugreportReceivers() {
+        try {
+            IntentFilter filterFinished = new IntentFilter(
+                    RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_DISPATCH,
+                    RemoteBugreportUtils.BUGREPORT_MIMETYPE);
+            mContext.registerReceiver(mRemoteBugreportFinishedReceiver, filterFinished);
+        } catch (IntentFilter.MalformedMimeTypeException e) {
+            // should never happen, as setting a constant
+            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);
+        mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
+    }
+
+    private void onBugreportFinished(Intent intent) {
+        mHandler.removeCallbacks(mRemoteBugreportTimeoutRunnable);
+        mRemoteBugreportServiceIsActive.set(false);
+        mInjector.getNotificationManager().cancel(LOG_TAG,
+                RemoteBugreportUtils.REMOTE_BUGREPORT_IN_PROGRESS_NOTIFICATION_ID);
+        Uri bugreportUri = intent.getData();
+        String bugreportUriString = null;
+        if (bugreportUri != null) {
+            bugreportUriString = bugreportUri.toString();
+        }
+        String bugreportHash = intent.getStringExtra(
+                RemoteBugreportUtils.EXTRA_REMOTE_BUGREPORT_HASH);
+        if (mRemoteBugreportSharingAccepted.get()) {
+            shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
+        } else {
+            setDeviceOwnerRemoteBugreportUriAndHash(bugreportUriString, bugreportHash);
+        }
+        mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
+    }
+
+    private void onBugreportFailed() {
+        mRemoteBugreportServiceIsActive.set(false);
+        mInjector.systemPropertiesSet(RemoteBugreportUtils.CTL_STOP,
+                RemoteBugreportUtils.REMOTE_BUGREPORT_SERVICE);
+        mRemoteBugreportSharingAccepted.set(false);
+        setDeviceOwnerRemoteBugreportUriAndHash(null, null);
+        mInjector.getNotificationManager().cancel(LOG_TAG,
+                RemoteBugreportUtils.REMOTE_BUGREPORT_CONSENT_NOTIFICATION_ID);
+        mInjector.getNotificationManager().cancel(LOG_TAG,
+                RemoteBugreportUtils.REMOTE_BUGREPORT_IN_PROGRESS_NOTIFICATION_ID);
+        Bundle extras = new Bundle();
+        extras.putInt(DeviceAdminReceiver.EXTRA_BUGREPORT_FAILURE_REASON,
+                DeviceAdminReceiver.BUGREPORT_FAILURE_FAILED_COMPLETING);
+        sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_BUGREPORT_FAILED, extras);
+        mContext.unregisterReceiver(mRemoteBugreportConsentReceiver);
+        mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
+    }
+
+    private void onBugreportSharingAccepted() {
+        mRemoteBugreportSharingAccepted.set(true);
+        String bugreportUriString = null;
+        String bugreportHash = null;
+        synchronized (this) {
+            bugreportUriString = getDeviceOwnerRemoteBugreportUri();
+            bugreportHash = mOwners.getDeviceOwnerRemoteBugreportHash();
+        }
+        if (bugreportUriString != null) {
+            shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
+        } else if (mRemoteBugreportServiceIsActive.get()) {
+            mInjector.getNotificationManager().notify(LOG_TAG,
+                    RemoteBugreportUtils.REMOTE_BUGREPORT_IN_PROGRESS_NOTIFICATION_ID,
+                    RemoteBugreportUtils.buildRemoteBugreportInProgressNotification(mContext,
+                            /* canCancelBugReport */ false));
+        }
+    }
+
+    private void onBugreportSharingDeclined() {
+        if (mRemoteBugreportServiceIsActive.get()) {
+            mInjector.systemPropertiesSet(RemoteBugreportUtils.CTL_STOP,
+                    RemoteBugreportUtils.REMOTE_BUGREPORT_SERVICE);
+            mRemoteBugreportServiceIsActive.set(false);
+            mHandler.removeCallbacks(mRemoteBugreportTimeoutRunnable);
+            mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
+        }
+        mRemoteBugreportSharingAccepted.set(false);
+        setDeviceOwnerRemoteBugreportUriAndHash(null, null);
+        mInjector.getNotificationManager().cancel(LOG_TAG,
+                RemoteBugreportUtils.REMOTE_BUGREPORT_IN_PROGRESS_NOTIFICATION_ID);
+        sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_BUGREPORT_SHARING_DECLINED, null);
+    }
+
+    private void shareBugreportWithDeviceOwnerIfExists(String bugreportUriString,
+            String bugreportHash) {
+        ParcelFileDescriptor pfd = null;
+        try {
+            if (bugreportUriString == null) {
+                throw new FileNotFoundException();
+            }
+            Uri bugreportUri = Uri.parse(bugreportUriString);
+            pfd = mContext.getContentResolver().openFileDescriptor(bugreportUri, "r");
+
+            synchronized (this) {
+                Intent intent = new Intent(DeviceAdminReceiver.ACTION_BUGREPORT_SHARE);
+                intent.setComponent(mOwners.getDeviceOwnerComponent());
+                intent.setDataAndType(bugreportUri, RemoteBugreportUtils.BUGREPORT_MIMETYPE);
+                intent.putExtra(DeviceAdminReceiver.EXTRA_BUGREPORT_HASH, bugreportHash);
+                mContext.grantUriPermission(mOwners.getDeviceOwnerComponent().getPackageName(),
+                        bugreportUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
+                mContext.sendBroadcastAsUser(intent, UserHandle.of(mOwners.getDeviceOwnerUserId()));
+            }
+        } catch (FileNotFoundException e) {
+            Bundle extras = new Bundle();
+            extras.putInt(DeviceAdminReceiver.EXTRA_BUGREPORT_FAILURE_REASON,
+                    DeviceAdminReceiver.BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE);
+            sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_BUGREPORT_FAILED, extras);
+        } finally {
+            try {
+                if (pfd != null) {
+                    pfd.close();
+                }
+            } catch (IOException ex) {
+                // Ignore
+            }
+            mRemoteBugreportSharingAccepted.set(false);
+            setDeviceOwnerRemoteBugreportUriAndHash(null, null);
+        }
+    }
+
     /**
      * Disables all device cameras according to the specified admin.
      */
@@ -4465,22 +5144,25 @@
         }
     }
 
-    /**
-     * Selectively disable keyguard features.
-     */
     @Override
-    public void setKeyguardDisabledFeatures(ComponentName who, int which) {
+    public void setKeyguardDisabledFeatures(ComponentName who, int which, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
+        final int userHandle = mInjector.userHandleGetCallingUserId();
         if (isManagedProfile(userHandle)) {
-            which = which & PROFILE_KEYGUARD_FEATURES;
+            if (parent) {
+                which = which & PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
+            } else if (isSeparateProfileChallengeEnabled(userHandle)){
+                which = which & PROFILE_KEYGUARD_FEATURES_AFFECT_PROFILE;
+            } else {
+                which = which & PROFILE_KEYGUARD_FEATURES;
+            }
         }
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES, parent);
             if (ap.disabledKeyguardFeatures != which) {
                 ap.disabledKeyguardFeatures = which;
                 saveSettingsLocked(userHandle);
@@ -4493,49 +5175,43 @@
      * or the aggregate of all active admins if who is null.
      */
     @Override
-    public int getKeyguardDisabledFeatures(ComponentName who, int userHandle) {
+    public int getKeyguardDisabledFeatures(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0;
         }
-        enforceCrossUserPermission(userHandle);
-        long ident = mInjector.binderClearCallingIdentity();
+        enforceFullCrossUsersPermission(userHandle);
+        final long ident = mInjector.binderClearCallingIdentity();
         try {
             synchronized (this) {
                 if (who != null) {
-                    ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                    ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                     return (admin != null) ? admin.disabledKeyguardFeatures : 0;
                 }
 
-                UserInfo user = mUserManager.getUserInfo(userHandle);
-                final List<UserInfo> profiles;
-                if (user.isManagedProfile() || LockPatternUtils.isSeparateWorkChallengeEnabled()) {
-                    // If we are being asked about a managed profile or the main user profile has a
-                    // separate lock from the work profile, just return keyguard features disabled
-                    // by admins in the profile.
-                    profiles = Collections.singletonList(user);
+                final List<ActiveAdmin> admins;
+                if (!parent && isManagedProfile(userHandle)) {
+                    // If we are being asked about a managed profile, just return keyguard features
+                    // disabled by admins in the profile.
+                    admins = getUserDataUnchecked(userHandle).mAdminList;
                 } else {
-                    // Otherwise return those set by admins in the user
-                    // and its profiles.
-                    profiles = mUserManager.getProfiles(userHandle);
+                    // Otherwise return those set by admins in the user and its profiles.
+                    admins = getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
                 }
 
-                // Determine which keyguard features are disabled by any active admin.
-                int which = 0;
-                for (UserInfo userInfo : profiles) {
-                    DevicePolicyData policy = getUserData(userInfo.id);
-                    final int N = policy.mAdminList.size();
-                    for (int i = 0; i < N; i++) {
-                        ActiveAdmin admin = policy.mAdminList.get(i);
-                        if (userInfo.id == userHandle || !userInfo.isManagedProfile()) {
-                            // If we are being asked explictly about this user
-                            // return all disabled features even if its a managed profile.
-                            which |= admin.disabledKeyguardFeatures;
-                        } else {
-                            // Otherwise a managed profile is only allowed to disable
-                            // some features on the parent user.
-                            which |= (admin.disabledKeyguardFeatures
-                                    & PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER);
-                        }
+                int which = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
+                final int N = admins.size();
+                for (int i = 0; i < N; i++) {
+                    ActiveAdmin admin = admins.get(i);
+                    int userId = admin.getUserHandle().getIdentifier();
+                    if (userId == userHandle || !isManagedProfile(userHandle)) {
+                        // If we are being asked explicitly about this user
+                        // return all disabled features even if its a managed profile.
+                        which |= admin.disabledKeyguardFeatures;
+                    } else {
+                        // Otherwise a managed profile is only allowed to disable
+                        // some features on the parent user.
+                        which |= (admin.disabledKeyguardFeatures
+                                & PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER);
                     }
                 }
                 return which;
@@ -4710,7 +5386,7 @@
         Preconditions.checkNotNull(packageName, "packageName is null");
         final int callingUid = mInjector.binderGetCallingUid();
         try {
-            int uid = mContext.getPackageManager().getPackageUid(packageName, 0);
+            int uid = mContext.getPackageManager().getPackageUidAsUser(packageName, 0);
             if (uid != callingUid) {
                 throw new SecurityException("Invalid packageName");
             }
@@ -4729,6 +5405,8 @@
             if (admin != null) {
                 admin.disableCamera = false;
                 admin.userRestrictions = null;
+                admin.forceEphemeralUsers = false;
+                mUserManagerInternal.setForceEphemeralUsers(admin.forceEphemeralUsers);
             }
 
             clearUserPoliciesLocked(new UserHandle(UserHandle.USER_SYSTEM));
@@ -4771,7 +5449,9 @@
         if (!mHasFeature) {
             return;
         }
-        UserHandle callingUser = mInjector.binderGetCallingUserHandle();
+        final UserHandle callingUser = mInjector.binderGetCallingUserHandle();
+        final int userId = callingUser.getIdentifier();
+        enforceNotManagedProfile(userId, "clear profile owner");
         // Check if this is the profile owner who is calling
         final ActiveAdmin admin =
                 getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -4779,7 +5459,6 @@
             admin.disableCamera = false;
             admin.userRestrictions = null;
             clearUserPoliciesLocked(callingUser);
-            final int userId = callingUser.getIdentifier();
             mOwners.removeProfileOwner(userId);
             mOwners.writeProfileOwner(userId);
         }
@@ -4796,7 +5475,7 @@
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
             long token = mInjector.binderClearCallingIdentity();
             try {
-                new LockPatternUtils(mContext).setDeviceOwnerInfo(info);
+                mLockPatternUtils.setDeviceOwnerInfo(info);
             } finally {
                 mInjector.binderRestoreCallingIdentity(token);
             }
@@ -4806,7 +5485,7 @@
 
     @Override
     public String getDeviceOwnerLockScreenInfo() {
-        return new LockPatternUtils(mContext).getDeviceOwnerInfo();
+        return mLockPatternUtils.getDeviceOwnerInfo();
     }
 
     private void clearUserPoliciesLocked(UserHandle userHandle) {
@@ -4815,7 +5494,9 @@
         DevicePolicyData policy = getUserData(userId);
         policy.mPermissionPolicy = DevicePolicyManager.PERMISSION_POLICY_PROMPT;
         policy.mDelegatedCertInstallerPackage = null;
+        policy.mApplicationRestrictionsManagingPackage = null;
         policy.mStatusBarDisabled = false;
+        policy.mUserProvisioningState = DevicePolicyManager.STATE_USER_UNMANAGED;
         saveSettingsLocked(userId);
 
         final long ident = mInjector.binderClearCallingIdentity();
@@ -4843,6 +5524,98 @@
     }
 
     @Override
+    public int getUserProvisioningState() {
+        if (!mHasFeature) {
+            return DevicePolicyManager.STATE_USER_UNMANAGED;
+        }
+        int userHandle = mInjector.userHandleGetCallingUserId();
+        return getUserProvisioningState(userHandle);
+    }
+
+    private int getUserProvisioningState(int userHandle) {
+        return getUserData(userHandle).mUserProvisioningState;
+    }
+
+    @Override
+    public void setUserProvisioningState(int newState, int userHandle) {
+        if (!mHasFeature) {
+            return;
+        }
+
+        if (userHandle != mOwners.getDeviceOwnerUserId() && !mOwners.hasProfileOwner(userHandle)
+                && getManagedUserId(userHandle) == -1) {
+            // No managed device, user or profile, so setting provisioning state makes no sense.
+            throw new IllegalStateException("Not allowed to change provisioning state unless a "
+                      + "device or profile owner is set.");
+        }
+
+        synchronized (this) {
+            boolean transitionCheckNeeded = true;
+
+            // Calling identity/permission checks.
+            final int callingUid = mInjector.binderGetCallingUid();
+            if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
+                // ADB shell can only move directly from un-managed to finalized as part of directly
+                // setting profile-owner or device-owner.
+                if (getUserProvisioningState(userHandle) !=
+                        DevicePolicyManager.STATE_USER_UNMANAGED
+                        || newState != DevicePolicyManager.STATE_USER_SETUP_FINALIZED) {
+                    throw new IllegalStateException("Not allowed to change provisioning state "
+                            + "unless current provisioning state is unmanaged, and new state is "
+                            + "finalized.");
+                }
+                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);
+            }
+
+            final DevicePolicyData policyData = getUserData(userHandle);
+            if (transitionCheckNeeded) {
+                // Optional state transition check for non-ADB case.
+                checkUserProvisioningStateTransition(policyData.mUserProvisioningState, newState);
+            }
+            policyData.mUserProvisioningState = newState;
+            saveSettingsLocked(userHandle);
+        }
+    }
+
+    private void checkUserProvisioningStateTransition(int currentState, int newState) {
+        // Valid transitions for normal use-cases.
+        switch (currentState) {
+            case DevicePolicyManager.STATE_USER_UNMANAGED:
+                // Can move to any state from unmanaged (except itself as an edge case)..
+                if (newState != DevicePolicyManager.STATE_USER_UNMANAGED) {
+                    return;
+                }
+                break;
+            case DevicePolicyManager.STATE_USER_SETUP_INCOMPLETE:
+            case DevicePolicyManager.STATE_USER_SETUP_COMPLETE:
+                // Can only move to finalized from these states.
+                if (newState == DevicePolicyManager.STATE_USER_SETUP_FINALIZED) {
+                    return;
+                }
+                break;
+            case DevicePolicyManager.STATE_USER_PROFILE_COMPLETE:
+                // Current user has a managed-profile, but current user is not managed, so
+                // rather than moving to finalized state, go back to unmanaged once
+                // profile provisioning is complete.
+                if (newState == DevicePolicyManager.STATE_USER_UNMANAGED) {
+                    return;
+                }
+                break;
+            case DevicePolicyManager.STATE_USER_SETUP_FINALIZED:
+                // Cannot transition out of finalized.
+                break;
+        }
+
+        // Didn't meet any of the accepted state transition checks above, throw appropriate error.
+        throw new IllegalStateException("Cannot move to user provisioning state [" + newState + "] "
+                + "from state [" + currentState + "]");
+    }
+
+    @Override
     public void setProfileEnabled(ComponentName who) {
         if (!mHasFeature) {
             return;
@@ -5057,29 +5830,62 @@
         }
     }
 
-    private void enforceCrossUserPermission(int userHandle) {
+    private void enforceFullCrossUsersPermission(int userHandle) {
+        enforceSystemUserOrPermission(userHandle,
+                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+    }
+
+    private void enforceCrossUsersPermission(int userHandle) {
+        enforceSystemUserOrPermission(userHandle,
+                android.Manifest.permission.INTERACT_ACROSS_USERS);
+    }
+
+    private void enforceSystemUserOrPermission(int userHandle, String permission) {
         if (userHandle < 0) {
             throw new IllegalArgumentException("Invalid userId " + userHandle);
         }
         final int callingUid = mInjector.binderGetCallingUid();
-        if (userHandle == UserHandle.getUserId(callingUid)) return;
+        if (userHandle == UserHandle.getUserId(callingUid)) {
+            return;
+        }
         if (!(UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
                 || callingUid == Process.ROOT_UID)) {
-            mContext.enforceCallingOrSelfPermission(
-                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "Must be system or have"
-                    + " INTERACT_ACROSS_USERS_FULL permission");
+            mContext.enforceCallingOrSelfPermission(permission,
+                    "Must be system or have " + permission + " permission");
+        }
+    }
+
+    private void enforceManagedProfile(int userHandle, String message) {
+        if(!isManagedProfile(userHandle)) {
+            throw new SecurityException("You can not " + message + " outside a managed profile.");
         }
     }
 
     private void enforceNotManagedProfile(int userHandle, String message) {
         if(isManagedProfile(userHandle)) {
-            throw new SecurityException("You can not " + message + " for a managed profile. ");
+            throw new SecurityException("You can not " + message + " for a managed profile.");
         }
     }
 
-    private int getCredentialOwner(int userHandle) {
-        long ident = mInjector.binderClearCallingIdentity();
+    private int getProfileParentId(int userHandle) {
+        final long ident = mInjector.binderClearCallingIdentity();
         try {
+            UserInfo parentUser = mUserManager.getProfileParent(userHandle);
+            return parentUser != null ? parentUser.id : userHandle;
+        } finally {
+            mInjector.binderRestoreCallingIdentity(ident);
+        }
+    }
+
+    private int getCredentialOwner(int userHandle, boolean parent) {
+        final long ident = mInjector.binderClearCallingIdentity();
+        try {
+            if (parent) {
+                UserInfo parentProfile = mUserManager.getProfileParent(userHandle);
+                if (parentProfile != null) {
+                    userHandle = parentProfile.id;
+                }
+            }
             return mUserManager.getCredentialOwnerProfile(userHandle);
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
@@ -5128,7 +5934,8 @@
             for (int u = 0; u < userCount; u++) {
                 DevicePolicyData policy = getUserData(mUserData.keyAt(u));
                 pw.println();
-                pw.println("  Enabled Device Admins (User " + policy.mUserHandle + "):");
+                pw.println("  Enabled Device Admins (User " + policy.mUserHandle
+                        + ", provisioningState: " + policy.mUserProvisioningState + "):");
                 final int N = policy.mAdminList.size();
                 for (int i=0; i<N; i++) {
                     ActiveAdmin ap = policy.mAdminList.get(i);
@@ -5187,18 +5994,68 @@
     }
 
     @Override
-    public void setApplicationRestrictions(ComponentName who, String packageName, Bundle settings) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
-        final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
+    public void setApplicationRestrictionsManagingPackage(ComponentName admin, String packageName) {
+        final int userHandle = mInjector.userHandleGetCallingUserId();
         synchronized (this) {
-            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            DevicePolicyData policy = getUserData(userHandle);
+            policy.mApplicationRestrictionsManagingPackage = packageName;
+            saveSettingsLocked(userHandle);
+        }
+    }
 
-            long id = mInjector.binderClearCallingIdentity();
-            try {
-                mUserManager.setApplicationRestrictions(packageName, settings, userHandle);
-            } finally {
-                mInjector.binderRestoreCallingIdentity(id);
+    @Override
+    public String getApplicationRestrictionsManagingPackage(ComponentName admin) {
+        final int userHandle = mInjector.userHandleGetCallingUserId();
+        synchronized (this) {
+            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            DevicePolicyData policy = getUserData(userHandle);
+            return policy.mApplicationRestrictionsManagingPackage;
+        }
+    }
+
+    @Override
+    public boolean isCallerApplicationRestrictionsManagingPackage() {
+        final int callingUid = mInjector.binderGetCallingUid();
+        final int userHandle = UserHandle.getUserId(callingUid);
+        synchronized (this) {
+            final DevicePolicyData policy = getUserData(userHandle);
+            if (policy.mApplicationRestrictionsManagingPackage == null) {
+                return false;
             }
+
+            try {
+                int uid = mContext.getPackageManager().getPackageUidAsUser(
+                        policy.mApplicationRestrictionsManagingPackage, userHandle);
+                return uid == callingUid;
+            } catch (NameNotFoundException e) {
+                return false;
+            }
+        }
+    }
+
+    private void enforceCanManageApplicationRestrictions(ComponentName who) {
+        if (who != null) {
+            synchronized (this) {
+                getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            }
+        } else if (!isCallerApplicationRestrictionsManagingPackage()) {
+            throw new SecurityException(
+                    "No admin component given, and caller cannot manage application restrictions "
+                    + "for other apps.");
+        }
+    }
+
+    @Override
+    public void setApplicationRestrictions(ComponentName who, String packageName, Bundle settings) {
+        enforceCanManageApplicationRestrictions(who);
+
+        final UserHandle userHandle = mInjector.binderGetCallingUserHandle();
+        final long id = mInjector.binderClearCallingIdentity();
+        try {
+            mUserManager.setApplicationRestrictions(packageName, settings, userHandle);
+        } finally {
+            mInjector.binderRestoreCallingIdentity(id);
         }
     }
 
@@ -5227,7 +6084,7 @@
             return null;
         }
         Preconditions.checkNotNull(agent, "agent null");
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
 
         synchronized (this) {
             final String componentName = agent.flattenToString();
@@ -5725,6 +6582,94 @@
         }
     }
 
+    private void sendAdminEnabledBroadcastLocked(int userHandle) {
+        DevicePolicyData policyData = getUserData(userHandle);
+        if (policyData.mAdminBroadcastPending) {
+            // Send the initialization data to profile owner and delete the data
+            ActiveAdmin admin = getProfileOwnerAdminLocked(userHandle);
+            if (admin != null) {
+                PersistableBundle initBundle = policyData.mInitBundle;
+                sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
+                        initBundle == null ? null : new Bundle(initBundle), null);
+            }
+            policyData.mInitBundle = null;
+            policyData.mAdminBroadcastPending = false;
+            saveSettingsLocked(userHandle);
+        }
+    }
+
+    @Override
+    public UserHandle createAndManageUser(ComponentName admin, String name,
+            ComponentName profileOwner, PersistableBundle adminExtras, int flags) {
+        Preconditions.checkNotNull(admin, "admin is null");
+        Preconditions.checkNotNull(profileOwner, "profileOwner is null");
+        if (!admin.getPackageName().equals(profileOwner.getPackageName())) {
+            throw new IllegalArgumentException("profileOwner " + profileOwner + " and admin "
+                    + admin + " are not in the same package");
+        }
+        // Create user.
+        UserHandle user = null;
+        synchronized (this) {
+            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+
+            final long id = mInjector.binderClearCallingIdentity();
+            try {
+                int userInfoFlags = 0;
+                if ((flags & DevicePolicyManager.MAKE_USER_EPHEMERAL) != 0) {
+                    userInfoFlags |= UserInfo.FLAG_EPHEMERAL;
+                }
+                UserInfo userInfo = mUserManager.createUser(name, userInfoFlags);
+                if (userInfo != null) {
+                    user = userInfo.getUserHandle();
+                }
+            } finally {
+                mInjector.binderRestoreCallingIdentity(id);
+            }
+        }
+        if (user == null) {
+            return null;
+        }
+        // Set admin.
+        final long id = mInjector.binderClearCallingIdentity();
+        try {
+            final String adminPkg = admin.getPackageName();
+
+            final int userHandle = user.getIdentifier();
+            try {
+                // Install the profile owner if not present.
+                if (!mIPackageManager.isPackageAvailable(adminPkg, userHandle)) {
+                    mIPackageManager.installExistingPackageAsUser(adminPkg, userHandle);
+                }
+            } catch (RemoteException e) {
+                Slog.e(LOG_TAG, "Failed to make remote calls for createAndManageUser, "
+                        + "removing created user", e);
+                mUserManager.removeUser(user.getIdentifier());
+                return null;
+            }
+
+            setActiveAdmin(profileOwner, true, userHandle);
+            // User is not started yet, the broadcast by setActiveAdmin will not be received.
+            // So we store adminExtras for broadcasting when the user starts for first time.
+            synchronized(this) {
+                DevicePolicyData policyData = getUserData(userHandle);
+                policyData.mInitBundle = adminExtras;
+                policyData.mAdminBroadcastPending = true;
+                saveSettingsLocked(userHandle);
+            }
+            final String ownerName = getProfileOwnerName(Process.myUserHandle().getIdentifier());
+            setProfileOwner(profileOwner, ownerName, userHandle);
+
+            if ((flags & DevicePolicyManager.SKIP_SETUP_WIZARD) != 0) {
+                Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                        Settings.Secure.USER_SETUP_COMPLETE, 1, userHandle);
+            }
+
+            return user;
+        } finally {
+            mInjector.binderRestoreCallingIdentity(id);
+        }
+    }
+
     @Override
     public boolean removeUser(ComponentName who, UserHandle userHandle) {
         Preconditions.checkNotNull(who, "ComponentName is null");
@@ -5764,21 +6709,17 @@
 
     @Override
     public Bundle getApplicationRestrictions(ComponentName who, String packageName) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
-        final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
+        enforceCanManageApplicationRestrictions(who);
 
-        synchronized (this) {
-            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-
-            long id = mInjector.binderClearCallingIdentity();
-            try {
-                Bundle bundle = mUserManager.getApplicationRestrictions(packageName, userHandle);
-                // if no restrictions were saved, mUserManager.getApplicationRestrictions
-                // returns null, but DPM method should return an empty Bundle as per JavaDoc
-                return bundle != null ? bundle : Bundle.EMPTY;
-            } finally {
-                mInjector.binderRestoreCallingIdentity(id);
-            }
+        final UserHandle userHandle = mInjector.binderGetCallingUserHandle();
+        final long id = mInjector.binderClearCallingIdentity();
+        try {
+           Bundle bundle = mUserManager.getApplicationRestrictions(packageName, userHandle);
+           // if no restrictions were saved, mUserManager.getApplicationRestrictions
+           // returns null, but DPM method should return an empty Bundle as per JavaDoc
+           return bundle != null ? bundle : Bundle.EMPTY;
+        } finally {
+            mInjector.binderRestoreCallingIdentity(id);
         }
     }
 
@@ -5894,7 +6835,7 @@
     @Override
     public Bundle getUserRestrictions(ComponentName who, int userHandle) {
         Preconditions.checkNotNull(who, "ComponentName is null");
-        enforceCrossUserPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
             ActiveAdmin activeAdmin = getActiveAdminUncheckedLocked(who, userHandle);
             if (activeAdmin == null) {
@@ -5902,7 +6843,9 @@
             }
             if (activeAdmin.getUid() != mInjector.binderGetCallingUid()) {
                 mContext.enforceCallingOrSelfPermission(
-                        android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
+                        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 activeAdmin.userRestrictions;
         }
@@ -5968,15 +6911,8 @@
                             + userId);
                 }
 
-                UserManager um = UserManager.get(mContext);
-                UserInfo primaryUser = um.getProfileParent(userId);
-
-                // Call did not come from a managed profile
-                if (primaryUser == null) {
-                    primaryUser = um.getUserInfo(userId);
-                }
-
-                if (!isSystemApp(mIPackageManager, packageName, primaryUser.id)) {
+                int parentUserId = getProfileParentId(userId);
+                if (!isSystemApp(mIPackageManager, packageName, parentUserId)) {
                     throw new IllegalArgumentException("Only system apps can be enabled this way.");
                 }
 
@@ -6004,19 +6940,12 @@
             long id = mInjector.binderClearCallingIdentity();
 
             try {
-                UserManager um = UserManager.get(mContext);
-                UserInfo primaryUser = um.getProfileParent(userId);
-
-                // Call did not come from a managed profile.
-                if (primaryUser == null) {
-                    primaryUser = um.getUserInfo(userId);
-                }
-
+                int parentUserId = getProfileParentId(userId);
                 List<ResolveInfo> activitiesToEnable = mIPackageManager.queryIntentActivities(
                         intent,
                         intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                         0, // no flags
-                        primaryUser.id);
+                        parentUserId);
 
                 if (VERBOSE_LOG) {
                     Slog.d(LOG_TAG, "Enabling system activities: " + activitiesToEnable);
@@ -6026,7 +6955,7 @@
                     for (ResolveInfo info : activitiesToEnable) {
                         if (info.activityInfo != null) {
                             String packageName = info.activityInfo.packageName;
-                            if (isSystemApp(mIPackageManager, packageName, primaryUser.id)) {
+                            if (isSystemApp(mIPackageManager, packageName, parentUserId)) {
                                 numberOfAppsInstalled++;
                                 mIPackageManager.installExistingPackageAsUser(packageName, userId);
                             } else {
@@ -6084,7 +7013,7 @@
 
     @Override
     public String[] getAccountTypesWithManagementDisabledAsUser(int userId) {
-        enforceCrossUserPermission(userId);
+        enforceFullCrossUsersPermission(userId);
         if (!mHasFeature) {
             return null;
         }
@@ -6156,7 +7085,7 @@
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             if (admin.disableCallerId != disabled) {
                 admin.disableCallerId = disabled;
-                saveSettingsLocked(UserHandle.getCallingUserId());
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
             }
         }
     }
@@ -6176,8 +7105,7 @@
 
     @Override
     public boolean getCrossProfileCallerIdDisabledForUser(int userId) {
-        // TODO: Should there be a check to make sure this relationship is within a profile group?
-        //enforceSystemProcess("getCrossProfileCallerIdDisabled can only be called by system");
+        enforceCrossUsersPermission(userId);
         synchronized (this) {
             ActiveAdmin admin = getProfileOwnerAdminLocked(userId);
             return (admin != null) ? admin.disableCallerId : false;
@@ -6185,10 +7113,48 @@
     }
 
     @Override
+    public void setCrossProfileContactsSearchDisabled(ComponentName who, boolean disabled) {
+        if (!mHasFeature) {
+            return;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        synchronized (this) {
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            if (admin.disableContactsSearch != disabled) {
+                admin.disableContactsSearch = disabled;
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+            }
+        }
+    }
+
+    @Override
+    public boolean getCrossProfileContactsSearchDisabled(ComponentName who) {
+        if (!mHasFeature) {
+            return false;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        synchronized (this) {
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            return admin.disableContactsSearch;
+        }
+    }
+
+    @Override
+    public boolean getCrossProfileContactsSearchDisabledForUser(int userId) {
+        enforceCrossUsersPermission(userId);
+        synchronized (this) {
+            ActiveAdmin admin = getProfileOwnerAdminLocked(userId);
+            return (admin != null) ? admin.disableContactsSearch : false;
+        }
+    }
+
+    @Override
     public void startManagedQuickContact(String actualLookupKey, long actualContactId,
-            long actualDirectoryId, Intent originalIntent) {
-        final Intent intent = QuickContact.rebuildManagedQuickContactsIntent(
-                actualLookupKey, actualContactId, actualDirectoryId, originalIntent);
+            boolean isContactIdIgnored, long actualDirectoryId, Intent originalIntent) {
+        final Intent intent = QuickContact.rebuildManagedQuickContactsIntent(actualLookupKey,
+                actualContactId, isContactIdIgnored, actualDirectoryId, originalIntent);
         final int callingUserId = UserHandle.getCallingUserId();
 
         final long ident = mInjector.binderClearCallingIdentity();
@@ -6393,7 +7359,8 @@
 
             if (Settings.Global.STAY_ON_WHILE_PLUGGED_IN.equals(setting)) {
                 // ignore if it contradicts an existing policy
-                long timeMs = getMaximumTimeToLock(who, UserHandle.getCallingUserId());
+                long timeMs = getMaximumTimeToLock(
+                        who, mInjector.userHandleGetCallingUserId(), /* parent */ false);
                 if (timeMs > 0 && timeMs < Integer.MAX_VALUE) {
                     return;
                 }
@@ -6416,7 +7383,7 @@
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
-            if (isDeviceOwner(who, mInjector.userHandleGetCallingUserId())) {
+            if (isDeviceOwner(who, callingUserId)) {
                 if (!SECURE_SETTINGS_DEVICEOWNER_WHITELIST.contains(setting)) {
                     throw new SecurityException(String.format(
                             "Permission denial: Device owners cannot update %1$s", setting));
@@ -6475,7 +7442,7 @@
             int userId = UserHandle.getCallingUserId();
             long id = mInjector.binderClearCallingIdentity();
             try {
-                mUserManager.setUserIcon(userId, icon);
+                mUserManagerInternal.setUserIcon(userId, icon);
             } finally {
                 mInjector.binderRestoreCallingIdentity(id);
             }
@@ -6489,15 +7456,14 @@
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
         }
         final int userId = UserHandle.getCallingUserId();
-        LockPatternUtils utils = new LockPatternUtils(mContext);
 
         long ident = mInjector.binderClearCallingIdentity();
         try {
             // disallow disabling the keyguard if a password is currently set
-            if (disabled && utils.isSecure(userId)) {
+            if (disabled && mLockPatternUtils.isSecure(userId)) {
                 return false;
             }
-            utils.setLockScreenDisabled(disabled, userId);
+            mLockPatternUtils.setLockScreenDisabled(disabled, userId);
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
         }
@@ -6630,7 +7596,6 @@
 
         @Override
         public boolean isActiveAdminWithPolicy(int uid, int reqPolicy) {
-            final int userId = UserHandle.getUserId(uid);
             synchronized(DevicePolicyManagerService.this) {
                 return getActiveAdminWithPolicyForUidLocked(null, reqPolicy, uid) != null;
             }
@@ -7018,4 +7983,201 @@
         return UserManager.isSplitSystemUser() && callingUserId == UserHandle.USER_SYSTEM;
     }
 
+    @Override
+    public void reboot(ComponentName admin) {
+        Preconditions.checkNotNull(admin);
+        // Make sure caller has DO.
+        synchronized (this) {
+            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+        }
+        long ident = mInjector.binderClearCallingIdentity();
+        try {
+            mInjector.powerManagerReboot(PowerManager.REBOOT_REQUESTED_BY_DEVICE_OWNER);
+        } finally {
+            mInjector.binderRestoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
+    public void setShortSupportMessage(@NonNull ComponentName who, String message) {
+        if (!mHasFeature) {
+            return;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        final int userHandle = mInjector.userHandleGetCallingUserId();
+        synchronized (this) {
+            ActiveAdmin admin = getActiveAdminForUidLocked(who,
+                    mInjector.binderGetCallingUid());
+            if (!TextUtils.equals(admin.shortSupportMessage, message)) {
+                admin.shortSupportMessage = message;
+                saveSettingsLocked(userHandle);
+            }
+        }
+    }
+
+    @Override
+    public String getShortSupportMessage(@NonNull ComponentName who) {
+        if (!mHasFeature) {
+            return null;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        synchronized (this) {
+            ActiveAdmin admin = getActiveAdminForUidLocked(who,
+                    mInjector.binderGetCallingUid());
+            return admin.shortSupportMessage;
+        }
+    }
+
+    @Override
+    public void setLongSupportMessage(@NonNull ComponentName who, String message) {
+        if (!mHasFeature) {
+            return;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        final int userHandle = mInjector.userHandleGetCallingUserId();
+        synchronized (this) {
+            ActiveAdmin admin = getActiveAdminForUidLocked(who,
+                    mInjector.binderGetCallingUid());
+            if (!TextUtils.equals(admin.longSupportMessage, message)) {
+                admin.longSupportMessage = message;
+                saveSettingsLocked(userHandle);
+            }
+        }
+    }
+
+    @Override
+    public String getLongSupportMessage(@NonNull ComponentName who) {
+        if (!mHasFeature) {
+            return null;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        synchronized (this) {
+            ActiveAdmin admin = getActiveAdminForUidLocked(who,
+                    mInjector.binderGetCallingUid());
+            return admin.longSupportMessage;
+        }
+    }
+
+    @Override
+    public String getShortSupportMessageForUser(@NonNull ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return null;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) {
+            throw new SecurityException("Only the system can query support message for user");
+        }
+        synchronized (this) {
+            ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+            if (admin != null) {
+                return admin.shortSupportMessage;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public String getLongSupportMessageForUser(@NonNull ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return null;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) {
+            throw new SecurityException("Only the system can query support message for user");
+        }
+        synchronized (this) {
+            ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+            if (admin != null) {
+                return admin.longSupportMessage;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void setOrganizationColor(@NonNull ComponentName who, int color) {
+        final int userHandle = mInjector.userHandleGetCallingUserId();
+        if (!mHasFeature || !isManagedProfile(userHandle)) {
+            return;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        synchronized (this) {
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            admin.organizationColor = color;
+            saveSettingsLocked(userHandle);
+        }
+    }
+
+    @Override
+    public int getOrganizationColor(@NonNull ComponentName who) {
+        final int userHandle = mInjector.userHandleGetCallingUserId();
+        if (!mHasFeature || !isManagedProfile(userHandle)) {
+            return ActiveAdmin.DEF_ORGANIZATION_COLOR;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        synchronized (this) {
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            return admin.organizationColor;
+        }
+    }
+
+    @Override
+    public int getOrganizationColorForUser(int userHandle) {
+        if (!mHasFeature || !isManagedProfile(userHandle)) {
+            return ActiveAdmin.DEF_ORGANIZATION_COLOR;
+        }
+        enforceCrossUsersPermission(userHandle);
+        synchronized (this) {
+            ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userHandle);
+            return (profileOwner != null)
+                    ? profileOwner.organizationColor
+                    : ActiveAdmin.DEF_ORGANIZATION_COLOR;
+        }
+    }
+
+    @Override
+    public void setAffiliationIds(ComponentName admin, List<String> ids) {
+        final Set<String> affiliationIds = new ArraySet<String>(ids);
+        final int callingUserId = mInjector.userHandleGetCallingUserId();
+
+        synchronized (this) {
+            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            getUserData(callingUserId).mAffiliationIds = affiliationIds;
+            saveSettingsLocked(callingUserId);
+            if (callingUserId != UserHandle.USER_SYSTEM && isDeviceOwner(admin, callingUserId)) {
+                // Affiliation ids specified by the device owner are additionally stored in
+                // UserHandle.USER_SYSTEM's DevicePolicyData.
+                getUserData(UserHandle.USER_SYSTEM).mAffiliationIds = affiliationIds;
+                saveSettingsLocked(UserHandle.USER_SYSTEM);
+            }
+        }
+    }
+
+    @Override
+    public boolean isAffiliatedUser() {
+        final int callingUserId = mInjector.userHandleGetCallingUserId();
+
+        synchronized (this) {
+            if (mOwners.getDeviceOwnerUserId() == callingUserId) {
+                // The user that the DO is installed on is always affiliated.
+                return true;
+            }
+            final ComponentName profileOwner = getProfileOwner(callingUserId);
+            if (profileOwner == null
+                    || !profileOwner.getPackageName().equals(mOwners.getDeviceOwnerPackageName())) {
+                return false;
+            }
+            final Set<String> userAffiliationIds = getUserData(callingUserId).mAffiliationIds;
+            final Set<String> deviceAffiliationIds =
+                    getUserData(UserHandle.USER_SYSTEM).mAffiliationIds;
+            for (String id : userAffiliationIds) {
+                if (deviceAffiliationIds.contains(id)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index f7de0b3..880f810 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -77,6 +77,8 @@
     private static final String ATTR_NAME = "name";
     private static final String ATTR_PACKAGE = "package";
     private static final String ATTR_COMPONENT_NAME = "component";
+    private static final String ATTR_REMOTE_BUGREPORT_URI = "remoteBugreportUri";
+    private static final String ATTR_REMOTE_BUGREPORT_HASH = "remoteBugreportHash";
     private static final String ATTR_USERID = "userId";
     private static final String ATTR_USER_RESTRICTIONS_MIGRATED = "userRestrictionsMigrated";
 
@@ -161,6 +163,14 @@
         return mDeviceOwner != null ? mDeviceOwner.admin : null;
     }
 
+    String getDeviceOwnerRemoteBugreportUri() {
+        return mDeviceOwner != null ? mDeviceOwner.remoteBugreportUri : null;
+    }
+
+    String getDeviceOwnerRemoteBugreportHash() {
+        return mDeviceOwner != null ? mDeviceOwner.remoteBugreportHash : null;
+    }
+
     void setDeviceOwner(ComponentName admin, String ownerName, int userId) {
         if (userId < 0) {
             Slog.e(TAG, "Invalid user id for device owner user: " + userId);
@@ -175,7 +185,8 @@
     // userRestrictionsMigrated should always be true.
     void setDeviceOwnerWithRestrictionsMigrated(ComponentName admin, String ownerName, int userId,
             boolean userRestrictionsMigrated) {
-        mDeviceOwner = new OwnerInfo(ownerName, admin, userRestrictionsMigrated);
+        mDeviceOwner = new OwnerInfo(ownerName, admin, userRestrictionsMigrated,
+                /* remoteBugreportUri =*/ null, /* remoteBugreportHash =*/ null);
         mDeviceOwnerUserId = userId;
 
         mUserManagerInternal.setDeviceManaged(true);
@@ -191,7 +202,8 @@
     void setProfileOwner(ComponentName admin, String ownerName, int userId) {
         // For a newly set PO, there's no need for migration.
         mProfileOwners.put(userId, new OwnerInfo(ownerName, admin,
-                /* userRestrictionsMigrated =*/ true));
+                /* userRestrictionsMigrated =*/ true, /* remoteBugreportUri =*/ null,
+                /* remoteBugreportHash =*/ null));
         mUserManagerInternal.setUserManaged(userId, true);
     }
 
@@ -266,6 +278,16 @@
         writeDeviceOwner();
     }
 
+    /** Sets the remote bugreport uri and hash, and also writes to the file. */
+    void setDeviceOwnerRemoteBugreportUriAndHash(String remoteBugreportUri,
+            String remoteBugreportHash) {
+        if (mDeviceOwner != null) {
+            mDeviceOwner.remoteBugreportUri = remoteBugreportUri;
+            mDeviceOwner.remoteBugreportHash = remoteBugreportHash;
+        }
+        writeDeviceOwner();
+    }
+
     /** Sets the user restrictions migrated flag, and also writes to the file.  */
     void setProfileOwnerUserRestrictionsMigrated(int userId) {
         OwnerInfo profileOwner = mProfileOwners.get(userId);
@@ -295,7 +317,8 @@
                     String name = parser.getAttributeValue(null, ATTR_NAME);
                     String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
                     mDeviceOwner = new OwnerInfo(name, packageName,
-                            /* userRestrictionsMigrated =*/ false);
+                            /* userRestrictionsMigrated =*/ false, /* remoteBugreportUri =*/ null,
+                            /* remoteBugreportHash =*/ null);
                     mDeviceOwnerUserId = UserHandle.USER_SYSTEM;
                 } else if (tag.equals(TAG_DEVICE_INITIALIZER)) {
                     // Deprecated tag
@@ -311,7 +334,7 @@
                                 profileOwnerComponentStr);
                         if (admin != null) {
                             profileOwnerInfo = new OwnerInfo(profileOwnerName, admin,
-                                /* userRestrictionsMigrated =*/ false);
+                                /* userRestrictionsMigrated =*/ false, null, null);
                         } else {
                             // This shouldn't happen but switch from package name -> component name
                             // might have written bad device owner files. b/17652534
@@ -321,7 +344,8 @@
                     }
                     if (profileOwnerInfo == null) {
                         profileOwnerInfo = new OwnerInfo(profileOwnerName, profileOwnerPackageName,
-                                /* userRestrictionsMigrated =*/ false);
+                                /* userRestrictionsMigrated =*/ false,
+                                /* remoteBugreportUri =*/ null, /* remoteBugreportHash =*/ null);
                     }
                     mProfileOwners.put(userId, profileOwnerInfo);
                 } else if (TAG_SYSTEM_UPDATE_POLICY.equals(tag)) {
@@ -579,19 +603,27 @@
         public final String packageName;
         public final ComponentName admin;
         public boolean userRestrictionsMigrated;
+        public String remoteBugreportUri;
+        public String remoteBugreportHash;
 
-        public OwnerInfo(String name, String packageName, boolean userRestrictionsMigrated) {
+        public OwnerInfo(String name, String packageName, boolean userRestrictionsMigrated,
+                String remoteBugreportUri, String remoteBugreportHash) {
             this.name = name;
             this.packageName = packageName;
             this.admin = new ComponentName(packageName, "");
             this.userRestrictionsMigrated = userRestrictionsMigrated;
+            this.remoteBugreportUri = remoteBugreportUri;
+            this.remoteBugreportHash = remoteBugreportHash;
         }
 
-        public OwnerInfo(String name, ComponentName admin, boolean userRestrictionsMigrated) {
+        public OwnerInfo(String name, ComponentName admin, boolean userRestrictionsMigrated,
+                String remoteBugreportUri, String remoteBugreportHash) {
             this.name = name;
             this.admin = admin;
             this.packageName = admin.getPackageName();
             this.userRestrictionsMigrated = userRestrictionsMigrated;
+            this.remoteBugreportUri = remoteBugreportUri;
+            this.remoteBugreportHash = remoteBugreportHash;
         }
 
         public void writeToXml(XmlSerializer out, String tag) throws IOException {
@@ -605,6 +637,12 @@
             }
             out.attribute(null, ATTR_USER_RESTRICTIONS_MIGRATED,
                     String.valueOf(userRestrictionsMigrated));
+            if (remoteBugreportUri != null) {
+                out.attribute(null, ATTR_REMOTE_BUGREPORT_URI, remoteBugreportUri);
+            }
+            if (remoteBugreportHash != null) {
+                out.attribute(null, ATTR_REMOTE_BUGREPORT_HASH, remoteBugreportHash);
+            }
             out.endTag(null, tag);
         }
 
@@ -617,12 +655,17 @@
                     parser.getAttributeValue(null, ATTR_USER_RESTRICTIONS_MIGRATED);
             final boolean userRestrictionsMigrated =
                     ("true".equals(userRestrictionsMigratedStr));
+            final String remoteBugreportUri = parser.getAttributeValue(null,
+                    ATTR_REMOTE_BUGREPORT_URI);
+            final String remoteBugreportHash = parser.getAttributeValue(null,
+                    ATTR_REMOTE_BUGREPORT_HASH);
 
             // Has component name?  If so, return [name, component]
             if (componentName != null) {
                 final ComponentName admin = ComponentName.unflattenFromString(componentName);
                 if (admin != null) {
-                    return new OwnerInfo(name, admin, userRestrictionsMigrated);
+                    return new OwnerInfo(name, admin, userRestrictionsMigrated,
+                            remoteBugreportUri, remoteBugreportHash);
                 } else {
                     // This shouldn't happen but switch from package name -> component name
                     // might have written bad device owner files. b/17652534
@@ -632,7 +675,8 @@
             }
 
             // Else, build with [name, package]
-            return new OwnerInfo(name, packageName, userRestrictionsMigrated);
+            return new OwnerInfo(name, packageName, userRestrictionsMigrated, remoteBugreportUri,
+                    remoteBugreportHash);
         }
 
         public void dump(String prefix, PrintWriter pw) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
new file mode 100644
index 0000000..3e1fbc7
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.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.devicepolicy;
+
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.text.format.DateUtils;
+
+import com.android.internal.R;
+
+/**
+ * Utilities class for the remote bugreport operation.
+ */
+class RemoteBugreportUtils {
+
+    static final int REMOTE_BUGREPORT_CONSENT_NOTIFICATION_ID = 678435657;
+    static final int REMOTE_BUGREPORT_IN_PROGRESS_NOTIFICATION_ID = 590907895;
+
+    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 buildRemoteBugreportConsentNotification(Context context) {
+        PendingIntent pendingIntentAccept = PendingIntent.getBroadcast(
+                context, REMOTE_BUGREPORT_CONSENT_NOTIFICATION_ID,
+                new Intent(ACTION_REMOTE_BUGREPORT_SHARING_ACCEPTED),
+                        PendingIntent.FLAG_CANCEL_CURRENT);
+        PendingIntent pendingIntentDecline = PendingIntent.getBroadcast(
+                context, REMOTE_BUGREPORT_CONSENT_NOTIFICATION_ID,
+                new Intent(ACTION_REMOTE_BUGREPORT_SHARING_DECLINED),
+                        PendingIntent.FLAG_CANCEL_CURRENT);
+
+        return new Notification.Builder(context)
+                .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+                .setContentTitle(context.getString(
+                        R.string.share_remote_bugreport_notification_title))
+                .setTicker(context.getString(R.string.share_remote_bugreport_notification_title))
+                .setContentText(context.getString(
+                        R.string.share_remote_bugreport_notification_message))
+                .setStyle(new Notification.BigTextStyle().bigText(context.getString(
+                        R.string.share_remote_bugreport_notification_message)))
+                .addAction(new Notification.Action.Builder(null /* icon */,
+                        context.getString(R.string.share_remote_bugreport_notification_decline),
+                        pendingIntentDecline).build())
+                .addAction(new Notification.Action.Builder(null /* icon */,
+                        context.getString(R.string.share_remote_bugreport_notification_accept),
+                        pendingIntentAccept).build())
+                .setOngoing(true)
+                .setLocalOnly(true)
+                .setColor(context.getColor(
+                        com.android.internal.R.color.system_notification_accent_color))
+                .setPriority(Notification.PRIORITY_MAX)
+                .setVibrate(new long[0])
+                .build();
+    }
+
+    static Notification buildRemoteBugreportInProgressNotification(Context context,
+            boolean canCancelBugreport) {
+        Notification.Builder builder = new Notification.Builder(context)
+                .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+                .setContentTitle(context.getString(
+                        R.string.remote_bugreport_progress_notification_title))
+                .setTicker(context.getString(
+                        R.string.remote_bugreport_progress_notification_title))
+                .setOngoing(true)
+                .setLocalOnly(true)
+                .setColor(context.getColor(
+                        com.android.internal.R.color.system_notification_accent_color))
+                .setPriority(Notification.PRIORITY_HIGH);
+
+        if (canCancelBugreport) {
+            PendingIntent pendingIntentCancel = PendingIntent.getBroadcast(context,
+                    REMOTE_BUGREPORT_IN_PROGRESS_NOTIFICATION_ID,
+                    new Intent(ACTION_REMOTE_BUGREPORT_SHARING_DECLINED),
+                    PendingIntent.FLAG_CANCEL_CURRENT);
+            String message = context.getString(
+                    R.string.remote_bugreport_progress_notification_message_can_cancel);
+            builder.setContentText(message)
+                    .setContentIntent(pendingIntentCancel)
+                    .setStyle(new Notification.BigTextStyle().bigText(message));
+        }
+        return builder.build();
+    }
+}
+
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 189ed33..254a37a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -31,8 +31,11 @@
 import android.os.Build;
 import android.os.Environment;
 import android.os.FactoryTest;
+import android.os.FileUtils;
 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;
@@ -45,7 +48,6 @@
 import android.util.EventLog;
 import android.util.Slog;
 import android.view.WindowManager;
-import android.webkit.WebViewFactory;
 
 import com.android.internal.R;
 import com.android.internal.os.BinderInternal;
@@ -66,8 +68,10 @@
 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.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;
@@ -81,7 +85,7 @@
 import com.android.server.power.PowerManagerService;
 import com.android.server.power.ShutdownThread;
 import com.android.server.restrictions.RestrictionsManagerService;
-import com.android.server.search.SearchManagerService;
+import com.android.server.soundtrigger.SoundTriggerService;
 import com.android.server.statusbar.StatusBarManagerService;
 import com.android.server.storage.DeviceStorageMonitorService;
 import com.android.server.telecom.TelecomLoaderService;
@@ -89,7 +93,7 @@
 import com.android.server.tv.TvInputManagerService;
 import com.android.server.twilight.TwilightService;
 import com.android.server.usage.UsageStatsService;
-import com.android.server.usb.UsbService;
+import com.android.server.vr.VrManagerService;
 import com.android.server.wallpaper.WallpaperManagerService;
 import com.android.server.webkit.WebViewUpdateService;
 import com.android.server.wm.WindowManagerService;
@@ -97,6 +101,7 @@
 import dalvik.system.VMRuntime;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.Locale;
 import java.util.Timer;
 import java.util.TimerTask;
@@ -131,16 +136,34 @@
             "com.android.server.midi.MidiService$Lifecycle";
     private static final String WIFI_SERVICE_CLASS =
             "com.android.server.wifi.WifiService";
+    private static final String WIFI_NAN_SERVICE_CLASS =
+            "com.android.server.wifi.nan.WifiNanService";
     private static final String WIFI_P2P_SERVICE_CLASS =
             "com.android.server.wifi.p2p.WifiP2pService";
     private static final String ETHERNET_SERVICE_CLASS =
             "com.android.server.ethernet.EthernetService";
     private static final String JOB_SCHEDULER_SERVICE_CLASS =
             "com.android.server.job.JobSchedulerService";
+    private static final String LOCK_SETTINGS_SERVICE_CLASS =
+            "com.android.server.LockSettingsService$Lifecycle";
     private static final String MOUNT_SERVICE_CLASS =
             "com.android.server.MountService$Lifecycle";
+    private static final String SEARCH_MANAGER_SERVICE_CLASS =
+            "com.android.server.search.SearchManagerService$Lifecycle";
+
     private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
 
+    private static final String UNCRYPT_PACKAGE_FILE = "/cache/recovery/uncrypt_file";
+    private static final String BLOCK_MAP_FILE = "/cache/recovery/block.map";
+
+    /**
+     * Default theme used by the system context. This is used to style
+     * system-provided dialogs, such as the Power Off dialog, and other
+     * visual content.
+     */
+    private static final int DEFAULT_SYSTEM_THEME =
+            com.android.internal.R.style.Theme_Material_DayNight_DarkActionBar;
+
     private final int mFactoryTestMode;
     private Timer mProfilerSnapshotTimer;
 
@@ -313,6 +336,30 @@
                 reason = null;
             }
 
+            // If it's a pending reboot into recovery to apply an update,
+            // 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)) {
+                File packageFile = new File(UNCRYPT_PACKAGE_FILE);
+                if (packageFile.exists()) {
+                    String filename = null;
+                    try {
+                        filename = FileUtils.readTextFile(packageFile, 0, null);
+                    } catch (IOException e) {
+                        Slog.e(TAG, "Error reading uncrypt package file", e);
+                    }
+
+                    if (filename != null && filename.startsWith("/data")) {
+                        if (!new File(BLOCK_MAP_FILE).exists()) {
+                            Slog.e(TAG, "Can't find block map file, uncrypt failed or " +
+                                       "unexpected runtime restart?");
+                            return;
+                        }
+                    }
+                }
+            }
             ShutdownThread.rebootOrShutdown(null, reboot, reason);
         }
     }
@@ -320,7 +367,7 @@
     private void createSystemContext() {
         ActivityThread activityThread = ActivityThread.systemMain();
         mSystemContext = activityThread.getSystemContext();
-        mSystemContext.setTheme(android.R.style.Theme_Material_DayNight_DarkActionBar);
+        mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);
     }
 
     /**
@@ -439,6 +486,7 @@
         ConsumerIrService consumerIr = null;
         MmsServiceBroker mmsService = null;
         EntropyMixer entropyMixer = null;
+        VrManagerService vrManagerService = null;
 
         boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false);
         boolean disableBluetooth = SystemProperties.getBoolean("config.disable_bluetooth", false);
@@ -524,6 +572,10 @@
             ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
             Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
+            traceBeginAndSlog("StartVrManagerService");
+            mSystemServiceManager.startService(VrManagerService.class);
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+
             mActivityManagerService.setWindowManager(wm);
 
             inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
@@ -554,25 +606,17 @@
 
         StatusBarManagerService statusBar = null;
         INotificationManager notification = null;
-        InputMethodManagerService imm = null;
         WallpaperManagerService wallpaper = null;
         LocationManagerService location = null;
         CountryDetectorService countryDetector = null;
         TextServicesManagerService tsms = null;
-        LockSettingsService lockSettings = null;
+        ILockSettings lockSettings = null;
         AssetAtlasService atlas = null;
         MediaRouterService mediaRouter = null;
 
         // Bring up services needed for UI.
         if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
-            traceBeginAndSlog("StartInputMethodManagerService");
-            try {
-                imm = new InputMethodManagerService(context);
-                ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm);
-            } catch (Throwable e) {
-                reportWtf("starting Input Manager Service", e);
-            }
-            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            mSystemServiceManager.startService(InputMethodManagerService.Lifecycle.class);
 
             traceBeginAndSlog("StartAccessibilityManagerService");
             try {
@@ -619,6 +663,14 @@
         }
         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(
@@ -631,8 +683,9 @@
             if (!disableNonCoreServices) {
                 traceBeginAndSlog("StartLockSettingsService");
                 try {
-                    lockSettings = new LockSettingsService(context);
-                    ServiceManager.addService("lock_settings", lockSettings);
+                    mSystemServiceManager.startService(LOCK_SETTINGS_SERVICE_CLASS);
+                    lockSettings = ILockSettings.Stub.asInterface(
+                            ServiceManager.getService("lock_settings"));
                 } catch (Throwable e) {
                     reportWtf("starting LockSettingsService service", e);
                 }
@@ -724,6 +777,11 @@
                 }
                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
+                if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_NAN)) {
+                    mSystemServiceManager.startService(WIFI_NAN_SERVICE_CLASS);
+                } else {
+                    Slog.i(TAG, "No Wi-Fi NAN Service (NAN support Not Present)");
+                }
                 mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS);
                 mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
                 mSystemServiceManager.startService(
@@ -832,8 +890,7 @@
             if (!disableNonCoreServices) {
                 traceBeginAndSlog("StartSearchManagerService");
                 try {
-                    ServiceManager.addService(Context.SEARCH_SERVICE,
-                            new SearchManagerService(context));
+                    mSystemServiceManager.startService(SEARCH_MANAGER_SERVICE_CLASS);
                 } catch (Throwable e) {
                     reportWtf("starting Search Service", e);
                 }
@@ -907,6 +964,8 @@
 
             mSystemServiceManager.startService(JobSchedulerService.class);
 
+            mSystemServiceManager.startService(SoundTriggerService.class);
+
             if (!disableNonCoreServices) {
                 if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_BACKUP)) {
                     mSystemServiceManager.startService(BACKUP_MANAGER_SERVICE_CLASS);
@@ -924,6 +983,7 @@
                     Slog.i(TAG, "Gesture Launcher Service");
                     mSystemServiceManager.startService(GestureLauncherService.class);
                 }
+                mSystemServiceManager.startService(SensorNotificationService.class);
             }
 
             traceBeginAndSlog("StartDiskStatsService");
@@ -1013,6 +1073,8 @@
                 mSystemServiceManager.startService(TvInputManagerService.class);
             }
 
+            mSystemServiceManager.startService(MediaResourceMonitorService.class);
+
             if (!disableNonCoreServices) {
                 traceBeginAndSlog("StartMediaRouterService");
                 try {
@@ -1029,7 +1091,7 @@
 
                 traceBeginAndSlog("StartBackgroundDexOptService");
                 try {
-                    BackgroundDexOptService.schedule(context, 0);
+                    BackgroundDexOptService.schedule(context);
                 } catch (Throwable e) {
                     reportWtf("starting BackgroundDexOptService", e);
                 }
@@ -1145,7 +1207,6 @@
         final ConnectivityService connectivityF = connectivity;
         final NetworkScoreService networkScoreF = networkScore;
         final WallpaperManagerService wallpaperF = wallpaper;
-        final InputMethodManagerService immF = imm;
         final LocationManagerService locationF = location;
         final CountryDetectorService countryDetectorF = countryDetector;
         final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater;
@@ -1242,11 +1303,6 @@
                     reportWtf("Notifying WallpaperService running", e);
                 }
                 try {
-                    if (immF != null) immF.systemRunning(statusBarF);
-                } catch (Throwable e) {
-                    reportWtf("Notifying InputMethodService running", e);
-                }
-                try {
                     if (locationF != null) locationF.systemRunning();
                 } catch (Throwable e) {
                     reportWtf("Notifying Location Service running", e);
@@ -1310,6 +1366,7 @@
         Intent intent = new Intent();
         intent.setComponent(new ComponentName("com.android.systemui",
                     "com.android.systemui.SystemUIService"));
+        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
         //Slog.d(TAG, "Starting service: " + intent);
         context.startServiceAsUser(intent, UserHandle.SYSTEM);
     }
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index 0a8c014..e6f4177 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -16,7 +16,11 @@
 
 package com.android.server.print;
 
+import static android.content.pm.PackageManager.GET_SERVICES;
+import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+
 import android.Manifest;
+import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.content.ComponentName;
@@ -24,9 +28,9 @@
 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.database.ContentObserver;
+import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -44,25 +48,23 @@
 import android.print.PrinterId;
 import android.printservice.PrintServiceInfo;
 import android.provider.Settings;
-import android.text.TextUtils;
 import android.util.SparseArray;
 
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.Preconditions;
 import com.android.server.SystemService;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Set;
 
 /**
  * SystemService wrapper for the PrintManager implementation. Publishes
  * Context.PRINT_SERVICE.
  * PrintManager implementation is contained within.
  */
-
 public final class PrintManagerService extends SystemService {
     private final PrintManagerImpl mPrintManagerImpl;
 
@@ -77,8 +79,8 @@
     }
 
     @Override
-    public void onStartUser(int userHandle) {
-        mPrintManagerImpl.handleUserStarted(userHandle);
+    public void onUnlockUser(int userHandle) {
+        mPrintManagerImpl.handleUserUnlocked(userHandle);
     }
 
     @Override
@@ -87,11 +89,6 @@
     }
 
     class PrintManagerImpl extends IPrintManager.Stub {
-        private static final char COMPONENT_NAME_SEPARATOR = ':';
-
-        private static final String EXTRA_PRINT_SERVICE_COMPONENT_NAME =
-                "EXTRA_PRINT_SERVICE_COMPONENT_NAME";
-
         private static final int BACKGROUND_USER_ID = -10;
 
         private final Object mLock = new Object();
@@ -112,6 +109,10 @@
         @Override
         public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
                 PrintAttributes attributes, String packageName, int appId, int userId) {
+            printJobName = Preconditions.checkStringNotEmpty(printJobName);
+            adapter = Preconditions.checkNotNull(adapter);
+            packageName = Preconditions.checkStringNotEmpty(packageName);
+
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final int resolvedAppId;
             final UserState userState;
@@ -157,6 +158,10 @@
 
         @Override
         public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId, int userId) {
+            if (printJobId == null) {
+                return null;
+            }
+
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final int resolvedAppId;
             final UserState userState;
@@ -177,7 +182,32 @@
         }
 
         @Override
+        public Icon getCustomPrinterIcon(PrinterId printerId, int userId) {
+            printerId = Preconditions.checkNotNull(printerId);
+
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                // Only the current group members can get the printer icons.
+                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
+                    return null;
+                }
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                return userState.getCustomPrinterIcon(printerId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
+            if (printJobId == null) {
+                return;
+            }
+
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final int resolvedAppId;
             final UserState userState;
@@ -199,6 +229,10 @@
 
         @Override
         public void restartPrintJob(PrintJobId printJobId, int appId, int userId) {
+            if (printJobId == null) {
+                return;
+            }
+
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final int resolvedAppId;
             final UserState userState;
@@ -264,6 +298,8 @@
         @Override
         public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
                 int userId) {
+            observer = Preconditions.checkNotNull(observer);
+
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
             synchronized (mLock) {
@@ -284,6 +320,8 @@
         @Override
         public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
                 int userId) {
+            observer = Preconditions.checkNotNull(observer);
+
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
             synchronized (mLock) {
@@ -304,6 +342,12 @@
         @Override
         public void startPrinterDiscovery(IPrinterDiscoveryObserver observer,
                 List<PrinterId> priorityList, int userId) {
+            observer = Preconditions.checkNotNull(observer);
+            if (priorityList != null) {
+                priorityList = Preconditions.checkCollectionElementsNotNull(priorityList,
+                        "PrinterId");
+            }
+
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
             synchronized (mLock) {
@@ -323,6 +367,8 @@
 
         @Override
         public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer, int userId) {
+            observer = Preconditions.checkNotNull(observer);
+
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
             synchronized (mLock) {
@@ -342,6 +388,8 @@
 
         @Override
         public void validatePrinters(List<PrinterId> printerIds, int userId) {
+            printerIds = Preconditions.checkCollectionElementsNotNull(printerIds, "PrinterId");
+
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
             synchronized (mLock) {
@@ -361,6 +409,8 @@
 
         @Override
         public void startPrinterStateTracking(PrinterId printerId, int userId) {
+            printerId = Preconditions.checkNotNull(printerId);
+
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
             synchronized (mLock) {
@@ -380,6 +430,8 @@
 
         @Override
         public void stopPrinterStateTracking(PrinterId printerId, int userId) {
+            printerId = Preconditions.checkNotNull(printerId);
+
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
             synchronized (mLock) {
@@ -400,6 +452,8 @@
         @Override
         public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
                 int appId, int userId) throws RemoteException {
+            listener = Preconditions.checkNotNull(listener);
+
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final int resolvedAppId;
             final UserState userState;
@@ -422,6 +476,8 @@
         @Override
         public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener,
                 int userId) {
+            listener = Preconditions.checkNotNull(listener);
+
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
             synchronized (mLock) {
@@ -441,6 +497,9 @@
 
         @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            fd = Preconditions.checkNotNull(fd);
+            pw = Preconditions.checkNotNull(pw);
+
             if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
                     != PackageManager.PERMISSION_GRANTED) {
                 pw.println("Permission Denial: can't dump PrintManager from from pid="
@@ -467,20 +526,17 @@
 
         private void registerContentObservers() {
             final Uri enabledPrintServicesUri = Settings.Secure.getUriFor(
-                    Settings.Secure.ENABLED_PRINT_SERVICES);
+                    Settings.Secure.DISABLED_PRINT_SERVICES);
             ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) {
                 @Override
                 public void onChange(boolean selfChange, Uri uri, int userId) {
                     if (enabledPrintServicesUri.equals(uri)) {
                         synchronized (mLock) {
-                            if (userId != UserHandle.USER_ALL) {
-                                UserState userState = getOrCreateUserStateLocked(userId);
-                                userState.updateIfNeededLocked();
-                            } else {
-                                final int userCount = mUserStates.size();
-                                for (int i = 0; i < userCount; i++) {
-                                    UserState userState = mUserStates.valueAt(i);
-                                    userState.updateIfNeededLocked();
+                            final int userCount = mUserStates.size();
+                            for (int i = 0; i < userCount; i++) {
+                                if (userId == UserHandle.USER_ALL
+                                        || userId == mUserStates.keyAt(i)) {
+                                    mUserStates.valueAt(i).updateIfNeededLocked();
                                 }
                             }
                         }
@@ -494,19 +550,23 @@
 
         private void registerBroadcastReceivers() {
             PackageMonitor monitor = new PackageMonitor() {
-                @Override
-                public void onPackageModified(String packageName) {
+                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());
-                        Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
-                        while (iterator.hasNext()) {
-                            ComponentName componentName = iterator.next();
-                            if (packageName.equals(componentName.getPackageName())) {
+
+                        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) {
@@ -516,44 +576,39 @@
                 }
 
                 @Override
+                public void onPackageModified(String packageName) {
+                    if (!mUserManager.isUserUnlocked(getChangingUserId())) return;
+                    updateServices(packageName);
+                    getOrCreateUserStateLocked(getChangingUserId()).prunePrintServices();
+                }
+
+                @Override
                 public void onPackageRemoved(String packageName, int uid) {
-                    synchronized (mLock) {
-                        // A background user/profile's print jobs are running but there is
-                        // no UI shown. Hence, if the packages of such a user change we need
-                        // to handle it as the change may affect ongoing print jobs.
-                        boolean servicesRemoved = false;
-                        UserState userState = getOrCreateUserStateLocked(getChangingUserId());
-                        Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
-                        while (iterator.hasNext()) {
-                            ComponentName componentName = iterator.next();
-                            if (packageName.equals(componentName.getPackageName())) {
-                                userState.removeApprovedPrintService(componentName);
-                                iterator.remove();
-                                servicesRemoved = true;
-                            }
-                        }
-                        if (servicesRemoved) {
-                            persistComponentNamesToSettingLocked(
-                                    Settings.Secure.ENABLED_PRINT_SERVICES,
-                                    userState.getEnabledServices(), getChangingUserId());
-                            userState.updateIfNeededLocked();
-                        }
-                    }
+                    if (!mUserManager.isUserUnlocked(getChangingUserId())) return;
+                    updateServices(packageName);
+                    getOrCreateUserStateLocked(getChangingUserId()).prunePrintServices();
                 }
 
                 @Override
                 public boolean onHandleForceStop(Intent intent, String[] stoppedPackages,
                         int uid, boolean doit) {
+                    if (!mUserManager.isUserUnlocked(getChangingUserId())) return false;
                     synchronized (mLock) {
                         // A background user/profile's print jobs are running but there is
                         // no UI shown. Hence, if the packages of such a user change we need
                         // to handle it as the change may affect ongoing print jobs.
                         UserState userState = getOrCreateUserStateLocked(getChangingUserId());
                         boolean stoppedSomePackages = false;
-                        Iterator<ComponentName> iterator = userState.getEnabledServices()
-                                .iterator();
+
+                        List<PrintServiceInfo> enabledServices = userState
+                                .getEnabledPrintServices();
+                        if (enabledServices == null) {
+                            return false;
+                        }
+
+                        Iterator<PrintServiceInfo> iterator = enabledServices.iterator();
                         while (iterator.hasNext()) {
-                            ComponentName componentName = iterator.next();
+                            ComponentName componentName = iterator.next().getComponentName();
                             String componentPackage = componentName.getPackageName();
                             for (String stoppedPackage : stoppedPackages) {
                                 if (componentPackage.equals(stoppedPackage)) {
@@ -574,6 +629,8 @@
 
                 @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.
@@ -581,51 +638,15 @@
                     intent.setPackage(packageName);
 
                     List<ResolveInfo> installedServices = mContext.getPackageManager()
-                            .queryIntentServicesAsUser(intent, PackageManager.GET_SERVICES,
+                            .queryIntentServicesAsUser(intent,
+                                    GET_SERVICES | MATCH_DEBUG_TRIAGED_MISSING,
                                     getChangingUserId());
 
-                    if (installedServices == null) {
-                        return;
-                    }
-
-                    // Enable all added services by default
-                    synchronized (mLock) {
+                    if (installedServices != null) {
                         UserState userState = getOrCreateUserStateLocked(getChangingUserId());
-
-                        Set<ComponentName> enabledServices = userState.getEnabledServices();
-                        boolean servicesAdded = false;
-
-                        final int installedServiceCount = installedServices.size();
-                        for (int i = 0; i < installedServiceCount; i++) {
-                            ServiceInfo serviceInfo = installedServices.get(i).serviceInfo;
-                            ComponentName component = new ComponentName(serviceInfo.packageName,
-                                    serviceInfo.name);
-
-                            enabledServices.add(component);
-                            servicesAdded = true;
-                        }
-
-                        if (servicesAdded) {
-                            persistComponentNamesToSettingLocked(
-                                    Settings.Secure.ENABLED_PRINT_SERVICES, enabledServices,
-                                    getChangingUserId());
-                            userState.updateIfNeededLocked();
-                        }
+                        userState.updateIfNeededLocked();
                     }
                 }
-
-                private void persistComponentNamesToSettingLocked(String settingName,
-                        Set<ComponentName> componentNames, int userId) {
-                    StringBuilder builder = new StringBuilder();
-                    for (ComponentName componentName : componentNames) {
-                        if (builder.length() > 0) {
-                            builder.append(COMPONENT_NAME_SEPARATOR);
-                        }
-                        builder.append(componentName.flattenToShortString());
-                    }
-                    Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                            settingName, builder.toString(), userId);
-                }
             };
 
             // package changes
@@ -634,6 +655,11 @@
         }
 
         private UserState getOrCreateUserStateLocked(int userId) {
+            if (!mUserManager.isUserUnlocked(userId)) {
+                throw new IllegalStateException(
+                        "User " + userId + " must be unlocked for printing to be available");
+            }
+
             UserState userState = mUserStates.get(userId);
             if (userState == null) {
                 userState = new UserState(mContext, userId, mLock);
@@ -642,7 +668,7 @@
             return userState;
         }
 
-        private void handleUserStarted(final int userId) {
+        private void handleUserUnlocked(final int userId) {
             // This code will touch the remote print spooler which
             // must be called off the main thread, so post the work.
             BackgroundThread.getHandler().post(new Runnable() {
@@ -725,10 +751,8 @@
             return userId;
         }
 
-        private String resolveCallingPackageNameEnforcingSecurity(String packageName) {
-            if (TextUtils.isEmpty(packageName)) {
-                return null;
-            }
+        private @NonNull String resolveCallingPackageNameEnforcingSecurity(
+                @NonNull String packageName) {
             String[] packages = mContext.getPackageManager().getPackagesForUid(
                     Binder.getCallingUid());
             final int packageCount = packages.length;
@@ -737,7 +761,7 @@
                     return packageName;
                 }
             }
-            return null;
+            throw new IllegalArgumentException("packageName has to belong to the caller");
         }
 
         private int getCurrentUserId () {
diff --git a/services/print/java/com/android/server/print/RemotePrintService.java b/services/print/java/com/android/server/print/RemotePrintService.java
index 77a47f8..9b99c67 100644
--- a/services/print/java/com/android/server/print/RemotePrintService.java
+++ b/services/print/java/com/android/server/print/RemotePrintService.java
@@ -24,6 +24,7 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.content.pm.ParceledListSlice;
+import android.graphics.drawable.Icon;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -98,6 +99,15 @@
         public void onPrintersAdded(List<PrinterInfo> printers);
         public void onPrintersRemoved(List<PrinterId> printerIds);
         public void onServiceDied(RemotePrintService service);
+
+        /**
+         * Handle that a custom icon for a printer was loaded.
+         *
+         * @param printerId the id of the printer the icon belongs to
+         * @param icon the icon that was loaded
+         * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+         */
+        public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon);
     }
 
     public RemotePrintService(Context context, ComponentName componentName, int userId,
@@ -399,12 +409,28 @@
         }
     }
 
-    public void startPrinterStateTracking(PrinterId printerId) {
+    public void startPrinterStateTracking(@NonNull PrinterId printerId) {
         mHandler.obtainMessage(MyHandler.MSG_START_PRINTER_STATE_TRACKING,
                 printerId).sendToTarget();
     }
 
-    private void handleStartPrinterStateTracking(final PrinterId printerId) {
+    /**
+     * Request the custom printer icon for a printer.
+     *
+     * @param printerId the id of the printer the icon should be loaded for
+     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+     */
+    public void requestCustomPrinterIcon(@NonNull PrinterId printerId) {
+        try {
+            if (isBound()) {
+                mPrintService.requestCustomPrinterIcon(printerId);
+            }
+        } catch (RemoteException re) {
+            Slog.e(LOG_TAG, "Error requesting icon for " + printerId, re);
+        }
+    }
+
+    private void handleStartPrinterStateTracking(final @NonNull PrinterId printerId) {
         throwIfDestroyed();
         // Take a note we are tracking the printer.
         if (mTrackedPrinterList == null) {
@@ -837,10 +863,23 @@
         }
 
         private void throwIfPrinterIdTampered(ComponentName serviceName, PrinterId printerId) {
-            if (printerId == null || printerId.getServiceName() == null
-                    || !printerId.getServiceName().equals(serviceName)) {
+            if (printerId == null || !printerId.getServiceName().equals(serviceName)) {
                 throw new IllegalArgumentException("Invalid printer id: " + printerId);
             }
         }
+
+        @Override
+        public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon)
+                throws RemoteException {
+            RemotePrintService service = mWeakService.get();
+            if (service != null) {
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    service.mCallbacks.onCustomPrinterIconLoaded(printerId, icon);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+        }
     }
 }
diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java
index c506b6f..d179b95 100644
--- a/services/print/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.graphics.drawable.Icon;
 import android.os.Binder;
 import android.os.Build;
 import android.os.IBinder;
@@ -35,17 +36,19 @@
 import android.print.IPrintSpoolerClient;
 import android.print.PrintJobId;
 import android.print.PrintJobInfo;
+import android.print.PrinterId;
+import android.printservice.PrintService;
 import android.util.Slog;
 import android.util.TimedRemoteCaller;
 
+import libcore.io.IoUtils;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.List;
 import java.util.concurrent.TimeoutException;
 
-import libcore.io.IoUtils;
-
 /**
  * This represents the remote print spooler as a local object to the
  * PrintManagerService. It is responsible to connecting to the remote
@@ -72,6 +75,15 @@
 
     private final SetPrintJobTagCaller mSetPrintJobTagCaller = new SetPrintJobTagCaller();
 
+    private final OnCustomPrinterIconLoadedCaller mCustomPrinterIconLoadedCaller =
+            new OnCustomPrinterIconLoadedCaller();
+
+    private final ClearCustomPrinterIconCacheCaller mClearCustomPrinterIconCache =
+            new ClearCustomPrinterIconCacheCaller();
+
+    private final GetCustomPrinterIconCaller mGetCustomPrinterIconCaller =
+            new GetCustomPrinterIconCaller();
+
     private final ServiceConnection mServiceConnection = new MyServiceConnection();
 
     private final Context mContext;
@@ -287,6 +299,96 @@
         }
     }
 
+    /**
+     * Handle that a custom icon for a printer was loaded.
+     *
+     * @param printerId the id of the printer the icon belongs to
+     * @param icon the icon that was loaded
+     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+     */
+    public final void onCustomPrinterIconLoaded(@NonNull PrinterId printerId,
+            @Nullable Icon icon) {
+        throwIfCalledOnMainThread();
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            mCanUnbind = false;
+        }
+        try {
+            mCustomPrinterIconLoadedCaller.onCustomPrinterIconLoaded(getRemoteInstanceLazy(),
+                    printerId, icon);
+        } catch (RemoteException|TimeoutException re) {
+            Slog.e(LOG_TAG, "Error loading new custom printer icon.", re);
+        } finally {
+            if (DEBUG) {
+                Slog.i(LOG_TAG,
+                        "[user: " + mUserHandle.getIdentifier() + "] onCustomPrinterIconLoaded()");
+            }
+            synchronized (mLock) {
+                mCanUnbind = true;
+                mLock.notifyAll();
+            }
+        }
+    }
+
+    /**
+     * Get the custom icon for a printer. If the icon is not cached, the icon is
+     * requested asynchronously. Once it is available the printer is updated.
+     *
+     * @param printerId the id of the printer the icon should be loaded for
+     * @return the custom icon to be used for the printer or null if the icon is
+     *         not yet available
+     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+     */
+    public final @Nullable Icon getCustomPrinterIcon(@NonNull PrinterId printerId) {
+        throwIfCalledOnMainThread();
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            mCanUnbind = false;
+        }
+        try {
+            return mGetCustomPrinterIconCaller.getCustomPrinterIcon(getRemoteInstanceLazy(),
+                    printerId);
+        } catch (RemoteException|TimeoutException re) {
+            Slog.e(LOG_TAG, "Error getting custom printer icon.", re);
+            return null;
+        } finally {
+            if (DEBUG) {
+                Slog.i(LOG_TAG,
+                        "[user: " + mUserHandle.getIdentifier() + "] getCustomPrinterIcon()");
+            }
+            synchronized (mLock) {
+                mCanUnbind = true;
+                mLock.notifyAll();
+            }
+        }
+    }
+
+    /**
+     * Clear the custom printer icon cache
+     */
+    public void clearCustomPrinterIconCache() {
+        throwIfCalledOnMainThread();
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            mCanUnbind = false;
+        }
+        try {
+            mClearCustomPrinterIconCache.clearCustomPrinterIconCache(getRemoteInstanceLazy());
+        } catch (RemoteException|TimeoutException re) {
+            Slog.e(LOG_TAG, "Error clearing custom printer icon cache.", re);
+        } finally {
+            if (DEBUG) {
+                Slog.i(LOG_TAG,
+                        "[user: " + mUserHandle.getIdentifier()
+                                + "] clearCustomPrinterIconCache()");
+            }
+            synchronized (mLock) {
+                mCanUnbind = true;
+                mLock.notifyAll();
+            }
+        }
+    }
+
     public final boolean setPrintJobTag(PrintJobId printJobId, String tag) {
         throwIfCalledOnMainThread();
         synchronized (mLock) {
@@ -338,26 +440,24 @@
     }
 
     /**
-     * Connect to the print spooler service and remove an approved print service.
+     * Remove all approved {@link PrintService print services} that are not in the given set.
      *
-     * @param serviceToRemove The {@link ComponentName} of the service to be removed.
+     * @param servicesToKeep The {@link ComponentName names } of the services to keep
      */
-    public final void removeApprovedPrintService(ComponentName serviceToRemove) {
+    public final void pruneApprovedPrintServices(List<ComponentName> servicesToKeep) {
         throwIfCalledOnMainThread();
         synchronized (mLock) {
             throwIfDestroyedLocked();
             mCanUnbind = false;
         }
         try {
-            getRemoteInstanceLazy().removeApprovedPrintService(serviceToRemove);
-        } catch (RemoteException re) {
-            Slog.e(LOG_TAG, "Error removing approved print service.", re);
-        } catch (TimeoutException te) {
-            Slog.e(LOG_TAG, "Error removing approved print service.", te);
+            getRemoteInstanceLazy().pruneApprovedPrintServices(servicesToKeep);
+        } catch (RemoteException|TimeoutException re) {
+            Slog.e(LOG_TAG, "Error pruning approved print services.", re);
         } finally {
             if (DEBUG) {
                 Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier()
-                        + "] removing approved print service()");
+                        + "] pruneApprovedPrintServices()");
             }
             synchronized (mLock) {
                 mCanUnbind = true;
@@ -632,6 +732,69 @@
         }
     }
 
+    private static final class OnCustomPrinterIconLoadedCaller extends TimedRemoteCaller<Void> {
+        private final IPrintSpoolerCallbacks mCallback;
+
+        public OnCustomPrinterIconLoadedCaller() {
+            super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+            mCallback = new BasePrintSpoolerServiceCallbacks() {
+                @Override
+                public void onCustomPrinterIconCached(int sequence) {
+                    onRemoteMethodResult(null, sequence);
+                }
+            };
+        }
+
+        public Void onCustomPrinterIconLoaded(IPrintSpooler target, PrinterId printerId,
+                Icon icon) throws RemoteException, TimeoutException {
+            final int sequence = onBeforeRemoteCall();
+            target.onCustomPrinterIconLoaded(printerId, icon, mCallback, sequence);
+            return getResultTimed(sequence);
+        }
+    }
+
+    private static final class ClearCustomPrinterIconCacheCaller extends TimedRemoteCaller<Void> {
+        private final IPrintSpoolerCallbacks mCallback;
+
+        public ClearCustomPrinterIconCacheCaller() {
+            super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+            mCallback = new BasePrintSpoolerServiceCallbacks() {
+                @Override
+                public void customPrinterIconCacheCleared(int sequence) {
+                    onRemoteMethodResult(null, sequence);
+                }
+            };
+        }
+
+        public Void clearCustomPrinterIconCache(IPrintSpooler target)
+                throws RemoteException, TimeoutException {
+            final int sequence = onBeforeRemoteCall();
+            target.clearCustomPrinterIconCache(mCallback, sequence);
+            return getResultTimed(sequence);
+        }
+    }
+
+    private static final class GetCustomPrinterIconCaller extends TimedRemoteCaller<Icon> {
+        private final IPrintSpoolerCallbacks mCallback;
+
+        public GetCustomPrinterIconCaller() {
+            super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+            mCallback = new BasePrintSpoolerServiceCallbacks() {
+                @Override
+                public void onGetCustomPrinterIconResult(Icon icon, int sequence) {
+                    onRemoteMethodResult(icon, sequence);
+                }
+            };
+        }
+
+        public Icon getCustomPrinterIcon(IPrintSpooler target, PrinterId printerId)
+                throws RemoteException, TimeoutException {
+            final int sequence = onBeforeRemoteCall();
+            target.getCustomPrinterIcon(printerId, mCallback, sequence);
+            return getResultTimed(sequence);
+        }
+    }
+
     private static abstract class BasePrintSpoolerServiceCallbacks
             extends IPrintSpoolerCallbacks.Stub {
         @Override
@@ -658,6 +821,21 @@
         public void onSetPrintJobTagResult(boolean success, int sequence) {
             /* do nothing */
         }
+
+        @Override
+        public void onCustomPrinterIconCached(int sequence) {
+            /* do nothing */
+        }
+
+        @Override
+        public void onGetCustomPrinterIconResult(@Nullable Icon icon, int sequence) {
+            /* do nothing */
+        }
+
+        @Override
+        public void customPrinterIconCacheCleared(int sequence) {
+            /* do nothing */
+        }
     }
 
     private static final class PrintSpoolerClient extends IPrintSpoolerClient.Stub {
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index 6a50a6e..fcf2fc8 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -16,16 +16,20 @@
 
 package com.android.server.print;
 
+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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
+import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Binder;
@@ -97,7 +101,7 @@
     private final List<PrintServiceInfo> mInstalledServices =
             new ArrayList<PrintServiceInfo>();
 
-    private final Set<ComponentName> mEnabledServices =
+    private final Set<ComponentName> mDisabledServices =
             new ArraySet<ComponentName>();
 
     private final PrintJobForAppCache mPrintJobForAppCache =
@@ -125,8 +129,15 @@
         mLock = lock;
         mSpooler = new RemotePrintSpooler(context, userId, this);
         mHandler = new UserStateHandler(context.getMainLooper());
+
         synchronized (mLock) {
-            enableSystemPrintServicesLocked();
+            readInstalledPrintServicesLocked();
+            upgradePersistentStateIfNeeded();
+            readDisabledPrintServicesLocked();
+
+            // Some print services might have gotten installed before the User State came up
+            prunePrintServices();
+
             onConfigurationChangedLocked();
         }
     }
@@ -166,8 +177,8 @@
     }
 
     @SuppressWarnings("deprecation")
-    public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
-            PrintAttributes attributes, String packageName, int appId) {
+    public Bundle print(@NonNull String printJobName, @NonNull IPrintDocumentAdapter adapter,
+            @Nullable PrintAttributes attributes, @NonNull String packageName, int appId) {
         // Create print job place holder.
         final PrintJobInfo printJob = new PrintJobInfo();
         printJob.setId(new PrintJobId());
@@ -257,7 +268,7 @@
         return new ArrayList<PrintJobInfo>(result.values());
     }
 
-    public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) {
+    public PrintJobInfo getPrintJobInfo(@NonNull PrintJobId printJobId, int appId) {
         PrintJobInfo printJob = mPrintJobForAppCache.getPrintJob(printJobId, appId);
         if (printJob == null) {
             printJob = mSpooler.getPrintJobInfo(printJobId, appId);
@@ -271,7 +282,29 @@
         return printJob;
     }
 
-    public void cancelPrintJob(PrintJobId printJobId, int appId) {
+    /**
+     * Get the custom icon for a printer. If the icon is not cached, the icon is
+     * requested asynchronously. Once it is available the printer is updated.
+     *
+     * @param printerId the id of the printer the icon should be loaded for
+     * @return the custom icon to be used for the printer or null if the icon is
+     *         not yet available
+     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+     */
+    public @Nullable Icon getCustomPrinterIcon(@NonNull PrinterId printerId) {
+        Icon icon = mSpooler.getCustomPrinterIcon(printerId);
+
+        if (icon == null) {
+            RemotePrintService service = mActiveServices.get(printerId.getServiceName());
+            if (service != null) {
+                service.requestCustomPrinterIcon(printerId);
+            }
+        }
+
+        return icon;
+    }
+
+    public void cancelPrintJob(@NonNull PrintJobId printJobId, int appId) {
         PrintJobInfo printJobInfo = mSpooler.getPrintJobInfo(printJobId, appId);
         if (printJobInfo == null) {
             return;
@@ -281,15 +314,19 @@
         mSpooler.setPrintJobCancelling(printJobId, true);
 
         if (printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
-            ComponentName printServiceName = printJobInfo.getPrinterId().getServiceName();
-            RemotePrintService printService = null;
-            synchronized (mLock) {
-                printService = mActiveServices.get(printServiceName);
+            PrinterId printerId = printJobInfo.getPrinterId();
+
+            if (printerId != null) {
+                ComponentName printServiceName = printerId.getServiceName();
+                RemotePrintService printService = null;
+                synchronized (mLock) {
+                    printService = mActiveServices.get(printServiceName);
+                }
+                if (printService == null) {
+                    return;
+                }
+                printService.onRequestCancelPrintJob(printJobInfo);
             }
-            if (printService == null) {
-                return;
-            }
-            printService.onRequestCancelPrintJob(printJobInfo);
         } else {
             // If the print job is failed we do not need cooperation
             // from the print service.
@@ -297,16 +334,7 @@
         }
     }
 
-    /**
-     * Remove an approved print service.
-     *
-     * @param serviceToRemove The {@link ComponentName} of the service to be removed.
-     */
-    public void removeApprovedPrintService(ComponentName serviceToRemove) {
-        mSpooler.removeApprovedPrintService(serviceToRemove);
-    }
-
-    public void restartPrintJob(PrintJobId printJobId, int appId) {
+    public void restartPrintJob(@NonNull PrintJobId printJobId, int appId) {
         PrintJobInfo printJobInfo = getPrintJobInfo(printJobId, appId);
         if (printJobInfo == null || printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
             return;
@@ -314,7 +342,7 @@
         mSpooler.setPrintJobState(printJobId, PrintJobInfo.STATE_QUEUED, null);
     }
 
-    public List<PrintServiceInfo> getEnabledPrintServices() {
+    public @Nullable List<PrintServiceInfo> getEnabledPrintServices() {
         synchronized (mLock) {
             List<PrintServiceInfo> enabledServices = null;
             final int installedServiceCount = mInstalledServices.size();
@@ -340,11 +368,13 @@
         }
     }
 
-    public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer) {
+    public void createPrinterDiscoverySession(@NonNull IPrinterDiscoveryObserver observer) {
         synchronized (mLock) {
             throwIfDestroyedLocked();
 
             if (mPrinterDiscoverySession == null) {
+                mSpooler.clearCustomPrinterIconCache();
+
                 // If we do not have a session, tell all service to create one.
                 mPrinterDiscoverySession = new PrinterDiscoverySessionMediator(mContext) {
                     @Override
@@ -361,7 +391,7 @@
         }
     }
 
-    public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer) {
+    public void destroyPrinterDiscoverySession(@NonNull IPrinterDiscoveryObserver observer) {
         synchronized (mLock) {
             // Already destroyed - nothing to do.
             if (mPrinterDiscoverySession == null) {
@@ -372,8 +402,8 @@
         }
     }
 
-    public void startPrinterDiscovery(IPrinterDiscoveryObserver observer,
-            List<PrinterId> printerIds) {
+    public void startPrinterDiscovery(@NonNull IPrinterDiscoveryObserver observer,
+            @Nullable List<PrinterId> printerIds) {
         synchronized (mLock) {
             throwIfDestroyedLocked();
             // No services - nothing to do.
@@ -390,7 +420,7 @@
         }
     }
 
-    public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer) {
+    public void stopPrinterDiscovery(@NonNull IPrinterDiscoveryObserver observer) {
         synchronized (mLock) {
             throwIfDestroyedLocked();
             // No services - nothing to do.
@@ -406,7 +436,7 @@
         }
     }
 
-    public void validatePrinters(List<PrinterId> printerIds) {
+    public void validatePrinters(@NonNull List<PrinterId> printerIds) {
         synchronized (mLock) {
             throwIfDestroyedLocked();
             // No services - nothing to do.
@@ -422,7 +452,7 @@
         }
     }
 
-    public void startPrinterStateTracking(PrinterId printerId) {
+    public void startPrinterStateTracking(@NonNull PrinterId printerId) {
         synchronized (mLock) {
             throwIfDestroyedLocked();
             // No services - nothing to do.
@@ -454,7 +484,7 @@
         }
     }
 
-    public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
+    public void addPrintJobStateChangeListener(@NonNull IPrintJobStateChangeListener listener,
             int appId) throws RemoteException {
         synchronized (mLock) {
             throwIfDestroyedLocked();
@@ -472,7 +502,7 @@
         }
     }
 
-    public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener) {
+    public void removePrintJobStateChangeListener(@NonNull IPrintJobStateChangeListener listener) {
         synchronized (mLock) {
             throwIfDestroyedLocked();
             if (mPrintJobStateChangeListenerRecords == null) {
@@ -533,6 +563,20 @@
     }
 
     @Override
+    public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon) {
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+
+            // No session - nothing to do.
+            if (mPrinterDiscoverySession == null) {
+                return;
+            }
+            mSpooler.onCustomPrinterIconLoaded(printerId, icon);
+            mPrinterDiscoverySession.onCustomPrinterIconLoadedLocked(printerId);
+        }
+    }
+
+    @Override
     public void onServiceDied(RemotePrintService service) {
         synchronized (mLock) {
             throwIfDestroyedLocked();
@@ -558,13 +602,6 @@
         }
     }
 
-    public Set<ComponentName> getEnabledServices() {
-        synchronized(mLock) {
-            throwIfDestroyedLocked();
-            return mEnabledServices;
-        }
-    }
-
     public void destroyLocked() {
         throwIfDestroyedLocked();
         mSpooler.destroy();
@@ -573,7 +610,7 @@
         }
         mActiveServices.clear();
         mInstalledServices.clear();
-        mEnabledServices.clear();
+        mDisabledServices.clear();
         if (mPrinterDiscoverySession != null) {
             mPrinterDiscoverySession.destroyLocked();
             mPrinterDiscoverySession = null;
@@ -581,7 +618,7 @@
         mDestroyed = true;
     }
 
-    public void dump(FileDescriptor fd, PrintWriter pw, String prefix) {
+    public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String prefix) {
         pw.append(prefix).append("user state ").append(String.valueOf(mUserId)).append(":");
         pw.println();
 
@@ -607,12 +644,12 @@
                    .append(installedService.getAdvancedOptionsActivityName()).println();
         }
 
-        pw.append(prefix).append(tab).append("enabled services:").println();
-        for (ComponentName enabledService : mEnabledServices) {
-            String enabledServicePrefix = prefix + tab + tab;
-            pw.append(enabledServicePrefix).append("service:").println();
-            pw.append(enabledServicePrefix).append(tab).append("componentName=")
-                    .append(enabledService.flattenToString());
+        pw.append(prefix).append(tab).append("disabled services:").println();
+        for (ComponentName disabledService : mDisabledServices) {
+            String disabledServicePrefix = prefix + tab + tab;
+            pw.append(disabledServicePrefix).append("service:").println();
+            pw.append(disabledServicePrefix).append(tab).append("componentName=")
+                    .append(disabledService.flattenToString());
             pw.println();
         }
 
@@ -640,7 +677,7 @@
     private boolean readConfigurationLocked() {
         boolean somethingChanged = false;
         somethingChanged |= readInstalledPrintServicesLocked();
-        somethingChanged |= readEnabledPrintServicesLocked();
+        somethingChanged |= readDisabledPrintServicesLocked();
         return somethingChanged;
     }
 
@@ -648,8 +685,8 @@
         Set<PrintServiceInfo> tempPrintServices = new HashSet<PrintServiceInfo>();
 
         List<ResolveInfo> installedServices = mContext.getPackageManager()
-                .queryIntentServicesAsUser(mQueryIntent, PackageManager.GET_SERVICES
-                        | PackageManager.GET_META_DATA, mUserId);
+                .queryIntentServicesAsUser(mQueryIntent,
+                        GET_SERVICES | GET_META_DATA | MATCH_DEBUG_TRIAGED_MISSING, mUserId);
 
         final int installedCount = installedServices.size();
         for (int i = 0, count = installedCount; i < count; i++) {
@@ -703,13 +740,50 @@
         return false;
     }
 
-    private boolean readEnabledPrintServicesLocked() {
-        Set<ComponentName> tempEnabledServiceNameSet = new HashSet<ComponentName>();
-        readPrintServicesFromSettingLocked(Settings.Secure.ENABLED_PRINT_SERVICES,
-                tempEnabledServiceNameSet);
-        if (!tempEnabledServiceNameSet.equals(mEnabledServices)) {
-            mEnabledServices.clear();
-            mEnabledServices.addAll(tempEnabledServiceNameSet);
+    /**
+     * Update persistent state from a previous version of Android.
+     */
+    private void upgradePersistentStateIfNeeded() {
+        String enabledSettingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+                Settings.Secure.ENABLED_PRINT_SERVICES, mUserId);
+
+        // Pre N we store the enabled services, in N and later we store the disabled services.
+        // Hence if enabledSettingValue is still set, we need to upgrade.
+        if (enabledSettingValue != null) {
+            Set<ComponentName> enabledServiceNameSet = new HashSet<ComponentName>();
+            readPrintServicesFromSettingLocked(Settings.Secure.ENABLED_PRINT_SERVICES,
+                    enabledServiceNameSet);
+
+            ArraySet<ComponentName> disabledServices = new ArraySet<>();
+            final int numInstalledServices = mInstalledServices.size();
+            for (int i = 0; i < numInstalledServices; i++) {
+                ComponentName serviceName = mInstalledServices.get(i).getComponentName();
+                if (!enabledServiceNameSet.contains(serviceName)) {
+                    disabledServices.add(serviceName);
+                }
+            }
+
+            writeDisabledPrintServicesLocked(disabledServices);
+
+            // We won't needed ENABLED_PRINT_SERVICES anymore, set to null to prevent upgrade to run
+            // again.
+            Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                    Settings.Secure.ENABLED_PRINT_SERVICES, null, mUserId);
+        }
+    }
+
+    /**
+     * Read the set of disabled print services from the secure settings.
+     *
+     * @return true if the state changed.
+     */
+    private boolean readDisabledPrintServicesLocked() {
+        Set<ComponentName> tempDisabledServiceNameSet = new HashSet<ComponentName>();
+        readPrintServicesFromSettingLocked(Settings.Secure.DISABLED_PRINT_SERVICES,
+                tempDisabledServiceNameSet);
+        if (!tempDisabledServiceNameSet.equals(mDisabledServices)) {
+            mDisabledServices.clear();
+            mDisabledServices.addAll(tempDisabledServiceNameSet);
             return true;
         }
         return false;
@@ -735,70 +809,28 @@
         }
     }
 
-    private void enableSystemPrintServicesLocked() {
-        // Load enabled and installed services.
-        readEnabledPrintServicesLocked();
-        readInstalledPrintServicesLocked();
-
-        // Load the system services once enabled on first boot.
-        Set<ComponentName> enabledOnFirstBoot = new HashSet<ComponentName>();
-        readPrintServicesFromSettingLocked(
-                Settings.Secure.ENABLED_ON_FIRST_BOOT_SYSTEM_PRINT_SERVICES,
-                enabledOnFirstBoot);
-
+    /**
+     * Persist the disabled print services to the secure settings.
+     */
+    private void writeDisabledPrintServicesLocked(Set<ComponentName> disabledServices) {
         StringBuilder builder = new StringBuilder();
-
-        final int serviceCount = mInstalledServices.size();
-        for (int i = 0; i < serviceCount; i++) {
-            ServiceInfo serviceInfo = mInstalledServices.get(i).getResolveInfo().serviceInfo;
-            // Enable system print services if we never did that and are not enabled.
-            if ((serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
-                ComponentName serviceName = new ComponentName(
-                        serviceInfo.packageName, serviceInfo.name);
-                if (!mEnabledServices.contains(serviceName)
-                        && !enabledOnFirstBoot.contains(serviceName)) {
-                    if (builder.length() > 0) {
-                        builder.append(":");
-                    }
-                    builder.append(serviceName.flattenToString());
-                }
+        for (ComponentName componentName : disabledServices) {
+            if (builder.length() > 0) {
+                builder.append(COMPONENT_NAME_SEPARATOR);
             }
-        }
-
-        // Nothing to be enabled - done.
-        if (builder.length() <= 0) {
-            return;
-        }
-
-        String servicesToEnable = builder.toString();
-
-        // Update the enabled services setting.
-        String enabledServices = Settings.Secure.getStringForUser(
-                mContext.getContentResolver(), Settings.Secure.ENABLED_PRINT_SERVICES, mUserId);
-        if (TextUtils.isEmpty(enabledServices)) {
-            enabledServices = servicesToEnable;
-        } else {
-            enabledServices = enabledServices + ":" + servicesToEnable;
+            builder.append(componentName.flattenToShortString());
         }
         Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                Settings.Secure.ENABLED_PRINT_SERVICES, enabledServices, mUserId);
-
-        // Update the enabled on first boot services setting.
-        String enabledOnFirstBootServices = Settings.Secure.getStringForUser(
-                mContext.getContentResolver(),
-                Settings.Secure.ENABLED_ON_FIRST_BOOT_SYSTEM_PRINT_SERVICES, mUserId);
-        if (TextUtils.isEmpty(enabledOnFirstBootServices)) {
-            enabledOnFirstBootServices = servicesToEnable;
-        } else {
-            enabledOnFirstBootServices = enabledOnFirstBootServices + ":" + enabledServices;
-        }
-        Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                Settings.Secure.ENABLED_ON_FIRST_BOOT_SYSTEM_PRINT_SERVICES,
-                enabledOnFirstBootServices, mUserId);
+                Settings.Secure.DISABLED_PRINT_SERVICES, builder.toString(), mUserId);
     }
 
-    private void onConfigurationChangedLocked() {
-        Set<ComponentName> installedComponents = new ArraySet<ComponentName>();
+    /**
+     * Get the {@link ComponentName names} of the installed print services
+     *
+     * @return The names of the installed print services
+     */
+    private ArrayList<ComponentName> getInstalledComponents() {
+        ArrayList<ComponentName> installedComponents = new ArrayList<ComponentName>();
 
         final int installedCount = mInstalledServices.size();
         for (int i = 0; i < installedCount; i++) {
@@ -807,8 +839,37 @@
                     resolveInfo.serviceInfo.name);
 
             installedComponents.add(serviceName);
+        }
 
-            if (mEnabledServices.contains(serviceName)) {
+        return installedComponents;
+    }
+
+    /**
+     * Prune persistent state if a print service was uninstalled
+     */
+    public void prunePrintServices() {
+        synchronized (mLock) {
+            ArrayList<ComponentName> installedComponents = getInstalledComponents();
+
+            // Remove unnecessary entries from persistent state "disabled services"
+            boolean disabledServicesUninstalled = mDisabledServices.retainAll(installedComponents);
+            if (disabledServicesUninstalled) {
+                writeDisabledPrintServicesLocked(mDisabledServices);
+            }
+
+            // Remove unnecessary entries from persistent state "approved services"
+            mSpooler.pruneApprovedPrintServices(installedComponents);
+        }
+    }
+
+    private void onConfigurationChangedLocked() {
+        ArrayList<ComponentName> installedComponents = getInstalledComponents();
+
+        final int installedCount = installedComponents.size();
+        for (int i = 0; i < installedCount; i++) {
+            ComponentName serviceName = installedComponents.get(i);
+
+            if (!mDisabledServices.contains(serviceName)) {
                 if (!mActiveServices.containsKey(serviceName)) {
                     RemotePrintService service = new RemotePrintService(
                             mContext, serviceName, mUserId, mSpooler, this);
@@ -935,10 +996,10 @@
     }
 
     private abstract class PrintJobStateChangeListenerRecord implements DeathRecipient {
-        final IPrintJobStateChangeListener listener;
+        @NonNull final IPrintJobStateChangeListener listener;
         final int appId;
 
-        public PrintJobStateChangeListenerRecord(IPrintJobStateChangeListener listener,
+        public PrintJobStateChangeListenerRecord(@NonNull IPrintJobStateChangeListener listener,
                 int appId) throws RemoteException {
             this.listener = listener;
             this.appId = appId;
@@ -973,21 +1034,21 @@
 
         private final List<PrinterId> mStateTrackedPrinters = new ArrayList<PrinterId>();
 
-        private final Handler mHandler;
+        private final Handler mSessionHandler;
 
         private boolean mIsDestroyed;
 
         public PrinterDiscoverySessionMediator(Context context) {
-            mHandler = new SessionHandler(context.getMainLooper());
+            mSessionHandler = new SessionHandler(context.getMainLooper());
             // Kick off the session creation.
             List<RemotePrintService> services = new ArrayList<RemotePrintService>(
                     mActiveServices.values());
-            mHandler.obtainMessage(SessionHandler
+            mSessionHandler.obtainMessage(SessionHandler
                     .MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION, services)
                     .sendToTarget();
         }
 
-        public void addObserverLocked(IPrinterDiscoveryObserver observer) {
+        public void addObserverLocked(@NonNull IPrinterDiscoveryObserver observer) {
             // Add the observer.
             mDiscoveryObservers.register(observer);
 
@@ -997,12 +1058,12 @@
                 SomeArgs args = SomeArgs.obtain();
                 args.arg1 = observer;
                 args.arg2 = printers;
-                mHandler.obtainMessage(SessionHandler.MSG_PRINTERS_ADDED,
+                mSessionHandler.obtainMessage(SessionHandler.MSG_PRINTERS_ADDED,
                         args).sendToTarget();
             }
         }
 
-        public void removeObserverLocked(IPrinterDiscoveryObserver observer) {
+        public void removeObserverLocked(@NonNull IPrinterDiscoveryObserver observer) {
             // Remove the observer.
             mDiscoveryObservers.unregister(observer);
             // No one else observing - then kill it.
@@ -1011,8 +1072,8 @@
             }
         }
 
-        public final void startPrinterDiscoveryLocked(IPrinterDiscoveryObserver observer,
-                List<PrinterId> priorityList) {
+        public final void startPrinterDiscoveryLocked(@NonNull IPrinterDiscoveryObserver observer,
+                @Nullable List<PrinterId> priorityList) {
             if (mIsDestroyed) {
                 Log.w(LOG_TAG, "Not starting dicovery - session destroyed");
                 return;
@@ -1040,12 +1101,12 @@
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = services;
             args.arg2 = priorityList;
-            mHandler.obtainMessage(SessionHandler
+            mSessionHandler.obtainMessage(SessionHandler
                     .MSG_DISPATCH_START_PRINTER_DISCOVERY, args)
                     .sendToTarget();
         }
 
-        public final void stopPrinterDiscoveryLocked(IPrinterDiscoveryObserver observer) {
+        public final void stopPrinterDiscoveryLocked(@NonNull IPrinterDiscoveryObserver observer) {
             if (mIsDestroyed) {
                 Log.w(LOG_TAG, "Not stopping dicovery - session destroyed");
                 return;
@@ -1060,12 +1121,12 @@
             }
             List<RemotePrintService> services = new ArrayList<RemotePrintService>(
                     mActiveServices.values());
-            mHandler.obtainMessage(SessionHandler
+            mSessionHandler.obtainMessage(SessionHandler
                     .MSG_DISPATCH_STOP_PRINTER_DISCOVERY, services)
                     .sendToTarget();
         }
 
-        public void validatePrintersLocked(List<PrinterId> printerIds) {
+        public void validatePrintersLocked(@NonNull List<PrinterId> printerIds) {
             if (mIsDestroyed) {
                 Log.w(LOG_TAG, "Not validating pritners - session destroyed");
                 return;
@@ -1079,13 +1140,15 @@
                 ComponentName serviceName = null;
                 while (iterator.hasNext()) {
                     PrinterId printerId = iterator.next();
-                    if (updateList.isEmpty()) {
-                        updateList.add(printerId);
-                        serviceName = printerId.getServiceName();
-                        iterator.remove();
-                    } else if (printerId.getServiceName().equals(serviceName)) {
-                        updateList.add(printerId);
-                        iterator.remove();
+                    if (printerId != null) {
+                        if (updateList.isEmpty()) {
+                            updateList.add(printerId);
+                            serviceName = printerId.getServiceName();
+                            iterator.remove();
+                        } else if (printerId.getServiceName().equals(serviceName)) {
+                            updateList.add(printerId);
+                            iterator.remove();
+                        }
                     }
                 }
                 // Schedule a notification of the service.
@@ -1094,14 +1157,14 @@
                     SomeArgs args = SomeArgs.obtain();
                     args.arg1 = service;
                     args.arg2 = updateList;
-                    mHandler.obtainMessage(SessionHandler
+                    mSessionHandler.obtainMessage(SessionHandler
                             .MSG_VALIDATE_PRINTERS, args)
                             .sendToTarget();
                 }
             }
         }
 
-        public final void startPrinterStateTrackingLocked(PrinterId printerId) {
+        public final void startPrinterStateTrackingLocked(@NonNull PrinterId printerId) {
             if (mIsDestroyed) {
                 Log.w(LOG_TAG, "Not starting printer state tracking - session destroyed");
                 return;
@@ -1126,7 +1189,7 @@
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = service;
             args.arg2 = printerId;
-            mHandler.obtainMessage(SessionHandler
+            mSessionHandler.obtainMessage(SessionHandler
                     .MSG_START_PRINTER_STATE_TRACKING, args)
                     .sendToTarget();
         }
@@ -1153,7 +1216,7 @@
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = service;
             args.arg2 = printerId;
-            mHandler.obtainMessage(SessionHandler
+            mSessionHandler.obtainMessage(SessionHandler
                     .MSG_STOP_PRINTER_STATE_TRACKING, args)
                     .sendToTarget();
         }
@@ -1183,7 +1246,7 @@
             // Tell the services we are done.
             List<RemotePrintService> services = new ArrayList<RemotePrintService>(
                     mActiveServices.values());
-            mHandler.obtainMessage(SessionHandler
+            mSessionHandler.obtainMessage(SessionHandler
                     .MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION, services)
                     .sendToTarget();
         }
@@ -1209,7 +1272,7 @@
                 }
             }
             if (addedPrinters != null) {
-                mHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_ADDED,
+                mSessionHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_ADDED,
                         addedPrinters).sendToTarget();
             }
         }
@@ -1234,7 +1297,7 @@
                 }
             }
             if (removedPrinterIds != null) {
-                mHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
+                mSessionHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
                         removedPrinterIds).sendToTarget();
             }
         }
@@ -1250,6 +1313,37 @@
             service.destroy();
         }
 
+        /**
+         * Handle that a custom icon for a printer was loaded.
+         *
+         * This increments the icon generation and adds the printer again which triggers an update
+         * in all users of the currently known printers.
+         *
+         * @param printerId the id of the printer the icon belongs to
+         * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+         */
+        public void onCustomPrinterIconLoadedLocked(PrinterId printerId) {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "onCustomPrinterIconLoadedLocked()");
+            }
+            if (mIsDestroyed) {
+                Log.w(LOG_TAG, "Not updating printer - session destroyed");
+                return;
+            }
+
+            PrinterInfo printer = mPrinters.get(printerId);
+            if (printer != null) {
+                PrinterInfo newPrinter = (new PrinterInfo.Builder(printer))
+                        .incCustomPrinterIconGen().build();
+                mPrinters.put(printerId, newPrinter);
+
+                ArrayList<PrinterInfo> addedPrinters = new ArrayList<>(1);
+                addedPrinters.add(newPrinter);
+                mSessionHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_ADDED,
+                        addedPrinters).sendToTarget();
+            }
+        }
+
         public void onServiceDiedLocked(RemotePrintService service) {
             // Remove the reported by that service.
             removePrintersForServiceLocked(service.getComponentName());
@@ -1261,12 +1355,12 @@
                 return;
             }
             // Tell the service to create a session.
-            mHandler.obtainMessage(
+            mSessionHandler.obtainMessage(
                     SessionHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION,
                     service).sendToTarget();
             // Start printer discovery if necessary.
             if (!mStartedPrinterDiscoveryTokens.isEmpty()) {
-                mHandler.obtainMessage(
+                mSessionHandler.obtainMessage(
                         SessionHandler.MSG_START_PRINTER_DISCOVERY,
                         service).sendToTarget();
             }
@@ -1278,7 +1372,7 @@
                     SomeArgs args = SomeArgs.obtain();
                     args.arg1 = service;
                     args.arg2 = printerId;
-                    mHandler.obtainMessage(SessionHandler
+                    mSessionHandler.obtainMessage(SessionHandler
                             .MSG_START_PRINTER_STATE_TRACKING, args)
                             .sendToTarget();
                 }
@@ -1348,7 +1442,7 @@
                 for (int i = 0; i < removedPrinterCount; i++) {
                     mPrinters.remove(removedPrinterIds.get(i));
                 }
-                mHandler.obtainMessage(
+                mSessionHandler.obtainMessage(
                         SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
                         removedPrinterIds).sendToTarget();
             }
@@ -1413,8 +1507,8 @@
             service.validatePrinters(printerIds);
         }
 
-        private void handleStartPrinterStateTracking(RemotePrintService service,
-                PrinterId printerId) {
+        private void handleStartPrinterStateTracking(@NonNull RemotePrintService service,
+                @NonNull PrinterId printerId) {
             service.startPrinterStateTracking(printerId);
         }
 
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index eed326e..3ae1072 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -27,7 +27,9 @@
     <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
     <uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
-
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+    <uses-permission android:name="android.permission.REAL_GET_TASKS" />
+    <uses-permission android:name="android.permission.GET_DETAILED_TASKS" />
     <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
     <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
     <uses-permission android:name="android.permission.MODIFY_NETWORK_ACCOUNTING" />
@@ -102,6 +104,8 @@
             </intent-filter>
         </receiver>
 
+        <service android:name="com.android.server.job.MockPriorityJobService"
+                 android:permission="android.permission.BIND_JOB_SERVICE" />
     </application>
 
     <instrumentation
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 27deb72..5874429 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -52,13 +52,16 @@
 import android.os.ConditionVariable;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.IBinder;
 import android.os.INetworkManagementService;
 import android.os.Looper;
 import android.os.Message;
 import android.os.MessageQueue;
+import android.os.Messenger;
 import android.os.MessageQueue.IdleHandler;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 import android.util.LogPrinter;
 
@@ -1297,6 +1300,36 @@
         validatedCallback.expectCallback(CallbackState.LOST);
     }
 
+    @SmallTest
+    public void testInvalidNetworkSpecifier() {
+        boolean execptionCalled = true;
+
+        try {
+            NetworkRequest.Builder builder = new NetworkRequest.Builder();
+            builder.setNetworkSpecifier(MATCH_ALL_REQUESTS_NETWORK_SPECIFIER);
+            execptionCalled = false;
+        } catch (IllegalArgumentException e) {
+            // do nothing - should get here
+        }
+
+        assertTrue("NetworkReqeuest builder with MATCH_ALL_REQUESTS_NETWORK_SPECIFIER",
+                execptionCalled);
+
+        try {
+            NetworkCapabilities networkCapabilities = new NetworkCapabilities();
+            networkCapabilities.addTransportType(TRANSPORT_WIFI)
+                    .setNetworkSpecifier(NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER);
+            mService.requestNetwork(networkCapabilities, null, 0, null,
+                    ConnectivityManager.TYPE_WIFI);
+            execptionCalled = false;
+        } catch (IllegalArgumentException e) {
+            // do nothing - should get here
+        }
+
+        assertTrue("ConnectivityService requestNetwork with MATCH_ALL_REQUESTS_NETWORK_SPECIFIER",
+                execptionCalled);
+    }
+
     private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
 
         public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
@@ -1504,4 +1537,10 @@
         ka3.stop();
         callback3.expectStopped();
     }
+
+    @SmallTest
+    public void testGetCaptivePortalServerUrl() throws Exception {
+        String url = mCm.getCaptivePortalServerUrl();
+        assertEquals("http://connectivitycheck.gstatic.com/generate_204", url);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index 204bc2e..8cbd32d 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -22,6 +22,9 @@
 import static android.net.ConnectivityManager.TYPE_WIFI;
 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.SET_ALL;
 import static android.net.NetworkStats.SET_DEFAULT;
 import static android.net.NetworkStats.SET_FOREGROUND;
@@ -81,6 +84,8 @@
 import org.easymock.EasyMock;
 
 import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Tests for {@link NetworkStatsService}.
@@ -282,8 +287,9 @@
         // 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, 512L, 4L, 256L, 2L, 4);
-        assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, 512L, 4L, 256L, 2L, 6);
+        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,
+                6);
         assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0);
         verifyAndReset();
 
@@ -317,8 +323,9 @@
         // 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, 512L, 4L, 256L, 2L, 4);
-        assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, 512L, 4L, 256L, 2L, 6);
+        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,
+                6);
         assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0);
         verifyAndReset();
 
@@ -670,16 +677,20 @@
         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, 50L, 5L, 50L, 5L, 1);
-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 1);
-        assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, 2048L, 16L, 1024L, 8L, 0);
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 50L, 5L,
+                50L, 5L, 1);
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT, 10L, 1L, 10L,
+                1L, 1);
+        assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 2048L, 16L,
+                1024L, 8L, 0);
 
         // now verify that recent history only contains one uid
         final long currentTime = currentTimeMillis();
         stats = mSession.getSummaryForAllUid(
                 sTemplateWifi, currentTime - HOUR_IN_MILLIS, currentTime, true);
         assertEquals(1, stats.size());
-        assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0);
+        assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 1024L, 8L,
+                512L, 4L, 0);
 
         verifyAndReset();
     }
@@ -742,10 +753,61 @@
         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, 128L, 2L, 128L, 2L, 1);
-        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 1);
-        assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, TAG_NONE, 32L, 2L, 32L, 2L, 1);
-        assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, 0xFAAD, 1L, 1L, 1L, 1L, 1);
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 128L, 2L,
+                128L, 2L, 1);
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT, 64L, 1L, 64L,
+                1L, 1);
+        assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, TAG_NONE, ROAMING_DEFAULT, 32L, 2L,
+                32L, 2L, 1);
+        assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, 0xFAAD, ROAMING_DEFAULT, 1L, 1L, 1L,
+                1L, 1);
+
+        verifyAndReset();
+    }
+
+    public void testRoaming() throws Exception {
+        // pretend that network comes online
+        expectCurrentTime();
+        expectDefaultSettings();
+        expectNetworkState(buildMobile3gState(IMSI_1, true /* isRoaming */));
+        expectNetworkStatsSummary(buildEmptyStats());
+        expectNetworkStatsUidDetail(buildEmptyStats());
+        expectNetworkStatsPoll();
+        expectBandwidthControlCheck();
+
+        replay();
+        mService.forceUpdateIfaces();
+        verifyAndReset();
+
+        // Create some traffic
+        incrementCurrentTime(HOUR_IN_MILLIS);
+        expectCurrentTime();
+        expectDefaultSettings();
+        expectNetworkStatsSummary(buildEmptyStats());
+        // Note that all traffic from NetworkManagementService is tagged as ROAMING_DEFAULT, 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,
+                        128L, 2L, 0L)
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT, 64L, 1L, 64L,
+                        1L, 0L));
+        expectNetworkStatsPoll();
+
+        replay();
+        mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+
+        // verify service recorded history
+        assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 0);
+
+        // verify entire history present
+        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,
+                128L, 2L, 0);
+        assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_ROAMING, 64L, 1L, 64L,
+                1L, 0);
 
         verifyAndReset();
     }
@@ -805,17 +867,19 @@
 
         // verify summary API
         final NetworkStats stats = mSession.getSummaryForNetwork(template, start, end);
-        assertValues(stats, IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes,
-                txPackets, operations);
+        assertValues(stats, IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, rxBytes,
+                rxPackets, txBytes, txPackets, operations);
     }
 
     private void assertUidTotal(NetworkTemplate template, int uid, long rxBytes, long rxPackets,
             long txBytes, long txPackets, int operations) throws Exception {
-        assertUidTotal(template, uid, SET_ALL, rxBytes, rxPackets, txBytes, txPackets, operations);
+        assertUidTotal(template, uid, SET_ALL, ROAMING_ALL, rxBytes, rxPackets, txBytes, txPackets,
+                operations);
     }
 
-    private void assertUidTotal(NetworkTemplate template, int uid, int set, long rxBytes,
-            long rxPackets, long txBytes, long txPackets, int operations) throws Exception {
+    private void assertUidTotal(NetworkTemplate template, int uid, int set, int roaming,
+            long rxBytes, long rxPackets, long txBytes, long txPackets, int operations)
+            throws Exception {
         // verify history API
         final NetworkStatsHistory history = mSession.getHistoryForUid(
                 template, uid, set, TAG_NONE, FIELD_ALL);
@@ -825,8 +889,8 @@
         // verify summary API
         final NetworkStats stats = mSession.getSummaryForAllUid(
                 template, Long.MIN_VALUE, Long.MAX_VALUE, false);
-        assertValues(stats, IFACE_ALL, uid, set, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets,
-                operations);
+        assertValues(stats, IFACE_ALL, uid, set, TAG_NONE, roaming, rxBytes, rxPackets, txBytes,
+                txPackets, operations);
     }
 
     private void expectSystemReady() throws Exception {
@@ -933,18 +997,31 @@
     }
 
     private static void assertValues(NetworkStats stats, String iface, int uid, int set,
-            int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, int operations) {
+            int tag, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets,
+            int operations) {
         final NetworkStats.Entry entry = new NetworkStats.Entry();
+        List<Integer> sets = new ArrayList<>();
         if (set == SET_DEFAULT || set == SET_ALL) {
-            final int i = stats.findIndex(iface, uid, SET_DEFAULT, tag);
-            if (i != -1) {
-                entry.add(stats.getValues(i, null));
-            }
+            sets.add(SET_DEFAULT);
         }
         if (set == SET_FOREGROUND || set == SET_ALL) {
-            final int i = stats.findIndex(iface, uid, SET_FOREGROUND, tag);
-            if (i != -1) {
-                entry.add(stats.getValues(i, null));
+            sets.add(SET_FOREGROUND);
+        }
+
+        List<Integer> roamings = new ArrayList<>();
+        if (roaming == ROAMING_DEFAULT || roaming == ROAMING_ALL) {
+            roamings.add(ROAMING_DEFAULT);
+        }
+        if (roaming == ROAMING_ROAMING || roaming == ROAMING_ALL) {
+            roamings.add(ROAMING_ROAMING);
+        }
+
+        for (int s : sets) {
+            for (int r : roamings) {
+                final int i = stats.findIndex(iface, uid, s, tag, r);
+                if (i != -1) {
+                    entry.add(stats.getValues(i, null));
+                }
             }
         }
 
@@ -974,9 +1051,14 @@
     }
 
     private static NetworkState buildMobile3gState(String subscriberId) {
+        return buildMobile3gState(subscriberId, false /* isRoaming */);
+    }
+
+    private static NetworkState buildMobile3gState(String subscriberId, boolean isRoaming) {
         final NetworkInfo info = new NetworkInfo(
                 TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UMTS, null, null);
         info.setDetailedState(DetailedState.CONNECTED, null, null);
+        info.setRoaming(isRoaming);
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(TEST_IFACE);
         return new NetworkState(info, prop, null, null, subscriberId, null);
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
new file mode 100644
index 0000000..625fe77
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.RemoteException;
+import android.test.AndroidTestCase;
+
+import java.util.List;
+
+public class ActivityManagerTest extends AndroidTestCase {
+
+    IActivityManager service;
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        service = ActivityManagerNative.getDefault();
+    }
+
+    public void testTaskIdsForRunningUsers() throws RemoteException {
+        for(int userId : service.getRunningUserIds()) {
+            testTaskIdsForUser(userId);
+        }
+    }
+
+    private void testTaskIdsForUser(int userId) throws RemoteException {
+        List<ActivityManager.RecentTaskInfo> recentTasks = service.getRecentTasks(
+                100, 0, userId);
+        if(recentTasks != null) {
+            for(ActivityManager.RecentTaskInfo recentTask : recentTasks) {
+                int taskId = recentTask.persistentId;
+                assertEquals("The task id " + taskId + " should not belong to user " + userId,
+                        taskId / UserHandle.PER_USER_RANGE, userId);
+            }
+        }
+    }
+}
\ 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 435b602..90e4acf 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -208,6 +208,11 @@
         }
 
         @Override
+        void powerManagerReboot(String reason) {
+            context.powerManager.reboot(reason);
+        }
+
+        @Override
         boolean systemPropertiesGetBoolean(String key, boolean def) {
             return context.systemProperties.getBoolean(key, def);
         }
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 565ef4b..87569b7 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -15,9 +15,6 @@
  */
 package com.android.server.devicepolicy;
 
-import com.android.server.LocalServices;
-import com.android.server.SystemService;
-
 import android.Manifest.permission;
 import android.app.Activity;
 import android.app.admin.DeviceAdminReceiver;
@@ -27,23 +24,30 @@
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
 import android.net.wifi.WifiInfo;
-import android.os.Build;
 import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.test.MoreAsserts;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.ArraySet;
 import android.util.Pair;
 
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+
 import org.mockito.ArgumentCaptor;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
@@ -62,13 +66,18 @@
  *
  m FrameworksServicesTests &&
  adb install \
-   -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
+   -r ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
  adb shell am instrument -e class com.android.server.devicepolicy.DevicePolicyManagerTest \
    -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
 
  (mmma frameworks/base/services/tests/servicestests/ for non-ninja build)
  */
+@SmallTest
 public class DevicePolicyManagerTest extends DpmTestBase {
+    private static final List<String> OWNER_SETUP_PERMISSIONS = Arrays.asList(
+            permission.MANAGE_DEVICE_ADMINS, permission.MANAGE_PROFILE_AND_DEVICE_OWNERS,
+            permission.MANAGE_USERS, permission.INTERACT_ACROSS_USERS_FULL);
+
     private DpmMockContext mContext;
     public DevicePolicyManager dpm;
     public DevicePolicyManagerServiceTestable dpms;
@@ -758,7 +767,7 @@
         when(mContext.userManager.getUserRestrictions()).thenReturn(new Bundle());
 
         // Now call clear.
-        doReturn(DpmMockContext.CALLER_SYSTEM_USER_UID).when(mContext.packageManager).getPackageUid(
+        doReturn(DpmMockContext.CALLER_SYSTEM_USER_UID).when(mContext.packageManager).getPackageUidAsUser(
                 eq(admin1.getPackageName()),
                 anyInt());
         dpm.clearDeviceOwnerApp(admin1.getPackageName());
@@ -797,7 +806,7 @@
         mContext.binder.callingUid = DpmMockContext.CALLER_UID;
 
         // Now call clear.
-        doReturn(DpmMockContext.CALLER_UID).when(mContext.packageManager).getPackageUid(
+        doReturn(DpmMockContext.CALLER_UID).when(mContext.packageManager).getPackageUidAsUser(
                 eq(admin1.getPackageName()),
                 anyInt());
         try {
@@ -944,6 +953,88 @@
         assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg2").size());
     }
 
+    public void testApplicationRestrictionsManagingApp() throws Exception {
+        setAsProfileOwner(admin1);
+
+        final String appRestrictionsManagerPackage = "com.google.app.restrictions.manager";
+        final int appRestrictionsManagerAppId = 20987;
+        final int appRestrictionsManagerUid = UserHandle.getUid(
+                DpmMockContext.CALLER_USER_HANDLE, appRestrictionsManagerAppId);
+        doReturn(appRestrictionsManagerUid).when(mContext.packageManager).getPackageUidAsUser(
+                eq(appRestrictionsManagerPackage),
+                eq(DpmMockContext.CALLER_USER_HANDLE));
+        mContext.binder.callingUid = appRestrictionsManagerUid;
+
+        // appRestrictionsManager package shouldn't be able to manage restrictions as the PO hasn't
+        // delegated that permission yet.
+        assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage());
+        Bundle rest = new Bundle();
+        rest.putString("KEY_STRING", "Foo1");
+        try {
+            dpm.setApplicationRestrictions(null, "pkg1", rest);
+            fail("Didn't throw expected SecurityException");
+        } catch (SecurityException expected) {
+            MoreAsserts.assertContainsRegex(
+                    "caller cannot manage application restrictions", expected.getMessage());
+        }
+        try {
+            dpm.getApplicationRestrictions(null, "pkg1");
+            fail("Didn't throw expected SecurityException");
+        } catch (SecurityException expected) {
+            MoreAsserts.assertContainsRegex(
+                    "caller cannot manage application restrictions", expected.getMessage());
+        }
+
+        // Check via the profile owner that no restrictions were set.
+        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+        assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg1").size());
+
+        // Let appRestrictionsManagerPackage manage app restrictions
+        dpm.setApplicationRestrictionsManagingPackage(admin1, appRestrictionsManagerPackage);
+        assertEquals(appRestrictionsManagerPackage,
+                dpm.getApplicationRestrictionsManagingPackage(admin1));
+
+        // Now that package should be able to set and retrieve app restrictions.
+        mContext.binder.callingUid = appRestrictionsManagerUid;
+        assertTrue(dpm.isCallerApplicationRestrictionsManagingPackage());
+        dpm.setApplicationRestrictions(null, "pkg1", rest);
+        Bundle returned = dpm.getApplicationRestrictions(null, "pkg1");
+        assertEquals(1, returned.size(), 1);
+        assertEquals("Foo1", returned.get("KEY_STRING"));
+
+        // The same app running on a separate user shouldn't be able to manage app restrictions.
+        mContext.binder.callingUid = UserHandle.getUid(
+                UserHandle.USER_SYSTEM, appRestrictionsManagerAppId);
+        assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage());
+        try {
+            dpm.setApplicationRestrictions(null, "pkg1", rest);
+            fail("Didn't throw expected SecurityException");
+        } catch (SecurityException expected) {
+            MoreAsserts.assertContainsRegex(
+                    "caller cannot manage application restrictions", expected.getMessage());
+        }
+
+        // The DPM is still able to manage app restrictions, even if it allowed another app to do it
+        // too.
+        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+        assertEquals(returned, dpm.getApplicationRestrictions(admin1, "pkg1"));
+        dpm.setApplicationRestrictions(admin1, "pkg1", null);
+        assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg1").size());
+
+        // Removing the ability for the package to manage app restrictions.
+        dpm.setApplicationRestrictionsManagingPackage(admin1, null);
+        assertNull(dpm.getApplicationRestrictionsManagingPackage(admin1));
+        mContext.binder.callingUid = appRestrictionsManagerUid;
+        assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage());
+        try {
+            dpm.setApplicationRestrictions(null, "pkg1", null);
+            fail("Didn't throw expected SecurityException");
+        } catch (SecurityException expected) {
+            MoreAsserts.assertContainsRegex(
+                    "caller cannot manage application restrictions", expected.getMessage());
+        }
+    }
+
     public void testSetUserRestriction_asDo() throws Exception {
         mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
         mContext.callerPermissions.add(permission.MANAGE_USERS);
@@ -1267,4 +1358,348 @@
         when(mContext.wifiManager.getConnectionInfo()).thenReturn(wi);
         assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress());
     }
+
+    public void testRebootCanOnlyBeCalledByDeviceOwner() throws Exception {
+        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+
+        // In this test, change the caller user to "system".
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        // Make sure admin1 is installed on system user.
+        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
+
+        // Set admin1 as DA.
+        dpm.setActiveAdmin(admin1, false);
+        assertTrue(dpm.isAdminActive(admin1));
+        try {
+            dpm.reboot(admin1);
+            fail("DA calls DPM.reboot(), did not throw expected SecurityException");
+        } catch (SecurityException expected) {
+            MoreAsserts.assertContainsRegex("does not own the device", expected.getMessage());
+        }
+
+        // Set admin1 as PO.
+        assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM));
+        try {
+            dpm.reboot(admin1);
+            fail("PO calls DPM.reboot(), did not throw expected SecurityException");
+        } catch (SecurityException expected) {
+            MoreAsserts.assertContainsRegex("does not own the device", expected.getMessage());
+        }
+
+        // Remove PO and add DO.
+        dpm.clearProfileOwner(admin1);
+        assertTrue(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM));
+
+        dpm.reboot(admin1);
+    }
+
+    public void testSetGetSupportText() {
+        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+        dpm.setActiveAdmin(admin1, true);
+        dpm.setActiveAdmin(admin2, true);
+        mContext.callerPermissions.remove(permission.MANAGE_DEVICE_ADMINS);
+
+        // Null default support messages.
+        {
+            assertNull(dpm.getLongSupportMessage(admin1));
+            assertNull(dpm.getShortSupportMessage(admin1));
+            mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+            assertNull(dpm.getShortSupportMessageForUser(admin1,
+                    DpmMockContext.CALLER_USER_HANDLE));
+            assertNull(dpm.getLongSupportMessageForUser(admin1,
+                    DpmMockContext.CALLER_USER_HANDLE));
+            mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
+        }
+
+        // Only system can call the per user versions.
+        {
+            try {
+                dpm.getShortSupportMessageForUser(admin1,
+                        DpmMockContext.CALLER_USER_HANDLE);
+                fail("Only system should be able to call getXXXForUser versions");
+            } catch (SecurityException expected) {
+                MoreAsserts.assertContainsRegex("message for user", expected.getMessage());
+            }
+            try {
+                dpm.getLongSupportMessageForUser(admin1,
+                        DpmMockContext.CALLER_USER_HANDLE);
+                fail("Only system should be able to call getXXXForUser versions");
+            } catch (SecurityException expected) {
+                MoreAsserts.assertContainsRegex("message for user", expected.getMessage());
+            }
+        }
+
+        // Can't set message for admin in another uid.
+        {
+            mContext.binder.callingUid = DpmMockContext.CALLER_UID + 1;
+            try {
+                dpm.setShortSupportMessage(admin1, "Some text");
+                fail("Admins should only be able to change their own support text.");
+            } catch (SecurityException expected) {
+                MoreAsserts.assertContainsRegex("is not owned by uid", expected.getMessage());
+            }
+            mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+        }
+
+        // Set/Get short returns what it sets and other admins text isn't changed.
+        {
+            final String supportText = "Some text to test with.";
+            dpm.setShortSupportMessage(admin1, supportText);
+            assertEquals(supportText, dpm.getShortSupportMessage(admin1));
+            assertNull(dpm.getLongSupportMessage(admin1));
+            assertNull(dpm.getShortSupportMessage(admin2));
+
+            mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+            assertEquals(supportText, dpm.getShortSupportMessageForUser(admin1,
+                    DpmMockContext.CALLER_USER_HANDLE));
+            assertNull(dpm.getShortSupportMessageForUser(admin2,
+                    DpmMockContext.CALLER_USER_HANDLE));
+            assertNull(dpm.getLongSupportMessageForUser(admin1,
+                    DpmMockContext.CALLER_USER_HANDLE));
+            mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+            dpm.setShortSupportMessage(admin1, null);
+            assertNull(dpm.getShortSupportMessage(admin1));
+        }
+
+        // Set/Get long returns what it sets and other admins text isn't changed.
+        {
+            final String supportText = "Some text to test with.\nWith more text.";
+            dpm.setLongSupportMessage(admin1, supportText);
+            assertEquals(supportText, dpm.getLongSupportMessage(admin1));
+            assertNull(dpm.getShortSupportMessage(admin1));
+            assertNull(dpm.getLongSupportMessage(admin2));
+
+            mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+            assertEquals(supportText, dpm.getLongSupportMessageForUser(admin1,
+                    DpmMockContext.CALLER_USER_HANDLE));
+            assertNull(dpm.getLongSupportMessageForUser(admin2,
+                    DpmMockContext.CALLER_USER_HANDLE));
+            assertNull(dpm.getShortSupportMessageForUser(admin1,
+                    DpmMockContext.CALLER_USER_HANDLE));
+            mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+            dpm.setLongSupportMessage(admin1, null);
+            assertNull(dpm.getLongSupportMessage(admin1));
+        }
+    }
+
+    /**
+     * Test for:
+     * {@link DevicePolicyManager#setAffiliationIds}
+     * {@link DevicePolicyManager#isAffiliatedUser}
+     */
+    public void testUserAffiliation() throws Exception {
+        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
+
+        // Check that the system user is unaffiliated.
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        assertFalse(dpm.isAffiliatedUser());
+
+        // Set a device owner on the system user. Check that the system user becomes affiliated.
+        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
+        dpm.setActiveAdmin(admin1, /* replace =*/ false);
+        assertTrue(dpm.setDeviceOwner(admin1, "owner-name"));
+        assertTrue(dpm.isAffiliatedUser());
+
+        // Install a profile owner whose package name matches the device owner on a test user. Check
+        // that the test user is unaffiliated.
+        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+        setAsProfileOwner(admin2);
+        assertFalse(dpm.isAffiliatedUser());
+
+        // Have the profile owner specify a set of affiliation ids. Check that the test user remains
+        // unaffiliated.
+        final Set<String> userAffiliationIds = new ArraySet<>();
+        userAffiliationIds.add("red");
+        userAffiliationIds.add("green");
+        userAffiliationIds.add("blue");
+        dpm.setAffiliationIds(admin2, userAffiliationIds);
+        assertFalse(dpm.isAffiliatedUser());
+
+        // Have the device owner specify a set of affiliation ids that do not intersect with those
+        // specified by the profile owner. Check that the test user remains unaffiliated.
+        final Set<String> deviceAffiliationIds = new ArraySet<>();
+        deviceAffiliationIds.add("cyan");
+        deviceAffiliationIds.add("yellow");
+        deviceAffiliationIds.add("magenta");
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        dpm.setAffiliationIds(admin1, deviceAffiliationIds);
+        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+        assertFalse(dpm.isAffiliatedUser());
+
+        // Have the profile owner specify a set of affiliation ids that intersect with those
+        // specified by the device owner. Check that the test user becomes affiliated.
+        userAffiliationIds.add("yellow");
+        dpm.setAffiliationIds(admin2, userAffiliationIds);
+        assertTrue(dpm.isAffiliatedUser());
+
+        // Change the profile owner to one whose package name does not match the device owner. Check
+        // that the test user is not affiliated anymore.
+        dpm.clearProfileOwner(admin2);
+        final ComponentName admin = new ComponentName("test", "test");
+        markPackageAsInstalled(admin.getPackageName(), null, DpmMockContext.CALLER_USER_HANDLE);
+        assertTrue(dpm.setProfileOwner(admin, "owner-name", DpmMockContext.CALLER_USER_HANDLE));
+        assertFalse(dpm.isAffiliatedUser());
+
+        // Check that the system user remains affiliated.
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        assertTrue(dpm.isAffiliatedUser());
+    }
+
+    public void testGetUserProvisioningState_defaultResult() {
+        assertEquals(DevicePolicyManager.STATE_USER_UNMANAGED, dpm.getUserProvisioningState());
+    }
+
+    public void testSetUserProvisioningState_permission() throws Exception {
+        setupProfileOwner();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+
+        exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
+                DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
+    }
+
+    public void testSetUserProvisioningState_unprivileged() throws Exception {
+        setupProfileOwner();
+        try {
+            dpm.setUserProvisioningState(DevicePolicyManager.STATE_USER_SETUP_FINALIZED,
+                    DpmMockContext.CALLER_USER_HANDLE);
+            fail("Expected SecurityException");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    public void testSetUserProvisioningState_noManagement() {
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        try {
+            dpm.setUserProvisioningState(DevicePolicyManager.STATE_USER_SETUP_FINALIZED,
+                    DpmMockContext.CALLER_USER_HANDLE);
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            MoreAsserts.assertContainsRegex("change provisioning state unless a .* owner is set",
+                    e.getMessage());
+        }
+        assertEquals(DevicePolicyManager.STATE_USER_UNMANAGED, dpm.getUserProvisioningState());
+    }
+
+    public void testSetUserProvisioningState_deviceOwnerFromSetupWizard() throws Exception {
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        setupDeviceOwner();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+
+        exerciseUserProvisioningTransitions(UserHandle.USER_SYSTEM,
+                DevicePolicyManager.STATE_USER_SETUP_COMPLETE,
+                DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
+    }
+
+    public void testSetUserProvisioningState_deviceOwnerFromSetupWizardAlternative()
+            throws Exception {
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        setupDeviceOwner();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+
+        exerciseUserProvisioningTransitions(UserHandle.USER_SYSTEM,
+                DevicePolicyManager.STATE_USER_SETUP_INCOMPLETE,
+                DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
+    }
+
+    public void testSetUserProvisioningState_deviceOwnerWithoutSetupWizard() throws Exception {
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        setupDeviceOwner();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+
+        exerciseUserProvisioningTransitions(UserHandle.USER_SYSTEM,
+                DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
+    }
+
+    public void testSetUserProvisioningState_managedProfileFromSetupWizard_primaryUser()
+            throws Exception {
+        setupProfileOwner();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+
+        exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
+                DevicePolicyManager.STATE_USER_PROFILE_COMPLETE,
+                DevicePolicyManager.STATE_USER_UNMANAGED);
+    }
+
+    public void testSetUserProvisioningState_managedProfileFromSetupWizard_managedProfile()
+            throws Exception {
+        setupProfileOwner();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+
+        exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
+                DevicePolicyManager.STATE_USER_SETUP_COMPLETE,
+                DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
+    }
+
+    public void testSetUserProvisioningState_managedProfileWithoutSetupWizard() throws Exception {
+        setupProfileOwner();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+
+        exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
+                DevicePolicyManager.STATE_USER_SETUP_FINALIZED);
+    }
+
+    public void testSetUserProvisioningState_illegalTransitionOutOfFinalized1() throws Exception {
+        setupProfileOwner();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+
+        try {
+            exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
+                    DevicePolicyManager.STATE_USER_SETUP_FINALIZED,
+                    DevicePolicyManager.STATE_USER_UNMANAGED);
+            fail("Expected IllegalStateException");
+        } catch (IllegalStateException e) {
+            MoreAsserts.assertContainsRegex("Cannot move to user provisioning state",
+                    e.getMessage());
+        }
+    }
+
+    public void testSetUserProvisioningState_illegalTransitionToAnotherInProgressState()
+            throws Exception {
+        setupProfileOwner();
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+
+        try {
+            exerciseUserProvisioningTransitions(DpmMockContext.CALLER_USER_HANDLE,
+                    DevicePolicyManager.STATE_USER_SETUP_INCOMPLETE,
+                    DevicePolicyManager.STATE_USER_SETUP_COMPLETE);
+            fail("Expected IllegalStateException");
+        } catch (IllegalStateException e) {
+            MoreAsserts.assertContainsRegex("Cannot move to user provisioning state",
+                    e.getMessage());
+        }
+    }
+
+    private void exerciseUserProvisioningTransitions(int userId, int... states) {
+        assertEquals(DevicePolicyManager.STATE_USER_UNMANAGED, dpm.getUserProvisioningState());
+        for (int state : states) {
+            dpm.setUserProvisioningState(state, userId);
+            assertEquals(state, dpm.getUserProvisioningState());
+        }
+    }
+
+    private void setupProfileOwner() throws Exception {
+        mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS);
+
+        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
+        dpm.setActiveAdmin(admin1, false);
+        assertTrue(dpm.setProfileOwner(admin1, null, DpmMockContext.CALLER_USER_HANDLE));
+
+        mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
+    }
+
+    private void setupDeviceOwner() throws Exception {
+        mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS);
+
+        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
+        dpm.setActiveAdmin(admin1, false);
+        assertTrue(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM));
+
+        mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java
index b80f3bf..3da61d6 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java
@@ -26,7 +26,7 @@
 
     public DevicePolicyManagerTestable(DpmMockContext context,
             DevicePolicyManagerServiceTestable dpms) {
-        super(context, dpms);
+        super(context, dpms, /* parentInstance = */ false);
         this.dpms = dpms;
     }
 
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 66d701d..56667e5 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -134,6 +134,9 @@
 
         public void goToSleep(long time, int reason, int flags) {
         }
+
+        public void reboot(String reason) {
+        }
     }
 
     public static class SystemPropertiesForMock {
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 5b33e4d..3dc1a9a 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -65,6 +65,22 @@
         return mMockContext;
     }
 
+    protected void markPackageAsInstalled(String packageName, ApplicationInfo ai, int userId)
+            throws Exception {
+        final PackageInfo pi = DpmTestUtils.cloneParcelable(
+                mRealTestContext.getPackageManager().getPackageInfo(
+                        mRealTestContext.getPackageName(), 0));
+        assertTrue(pi.applicationInfo.flags != 0);
+
+        if (ai != null) {
+            pi.applicationInfo = ai;
+        }
+
+        doReturn(pi).when(mMockContext.ipackageManager).getPackageInfo(
+                eq(packageName),
+                eq(0),
+                eq(userId));
+    }
 
     protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid)
             throws Exception {
@@ -117,24 +133,13 @@
         // We need to rewrite the UID in the activity info.
         realResolveInfo.get(0).activityInfo.applicationInfo = ai;
 
-        doReturn(realResolveInfo).when(mMockContext.packageManager).queryBroadcastReceivers(
+        doReturn(realResolveInfo).when(mMockContext.packageManager).queryBroadcastReceiversAsUser(
                 MockUtils.checkIntentComponent(admin),
                 eq(PackageManager.GET_META_DATA
                         | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
                 eq(UserHandle.getUserId(packageUid)));
 
         // Set up getPackageInfo().
-
-        final PackageInfo pi = DpmTestUtils.cloneParcelable(
-                mRealTestContext.getPackageManager().getPackageInfo(
-                        admin.getPackageName(), 0));
-        assertTrue(pi.applicationInfo.flags != 0);
-
-        pi.applicationInfo = ai;
-
-        doReturn(pi).when(mMockContext.ipackageManager).getPackageInfo(
-                eq(admin.getPackageName()),
-                eq(0),
-                eq(UserHandle.getUserId(packageUid)));
+        markPackageAsInstalled(admin.getPackageName(), ai, 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 312b1b0..ae0a25e 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
@@ -179,7 +179,21 @@
                 loaded.getEarliestRunTime() <= newNowElapsed + TEN_SECONDS);
         // Assert late runtime was clamped to be now + period*2.
         assertTrue("Early runtime wasn't correctly clamped.",
-                loaded.getEarliestRunTime() <= newNowElapsed + TEN_SECONDS*2);
+                loaded.getEarliestRunTime() <= newNowElapsed + TEN_SECONDS * 2);
+    }
+
+    public void testPriorityPersisted() throws Exception {
+        JobInfo.Builder b = new Builder(92, mComponent)
+                .setOverrideDeadline(5000)
+                .setPriority(42)
+                .setPersisted(true);
+        final JobStatus js = new JobStatus(b.build(), SOME_UID);
+        mTaskStoreUnderTest.add(js);
+        Thread.sleep(IO_WAIT);
+        final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
+        mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet);
+        JobStatus loaded = jobStatusSet.iterator().next();
+        assertEquals("Priority not correctly persisted.", 42, loaded.getPriority());
     }
 
     /**
diff --git a/services/tests/servicestests/src/com/android/server/job/MockPriorityJobService.java b/services/tests/servicestests/src/com/android/server/job/MockPriorityJobService.java
new file mode 100644
index 0000000..3ea86f2
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/job/MockPriorityJobService.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.job;
+
+import android.annotation.TargetApi;
+import android.app.job.JobParameters;
+import android.app.job.JobService;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+@TargetApi(24)
+public class MockPriorityJobService extends JobService {
+    private static final String TAG = "MockPriorityJobService";
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        Log.e(TAG, "Created test service.");
+    }
+
+    @Override
+    public boolean onStartJob(JobParameters params) {
+        Log.i(TAG, "Test job executing: " + params.getJobId());
+        TestEnvironment.getTestEnvironment().executedEvents.add(
+                new TestEnvironment.Event(TestEnvironment.EVENT_START_JOB, params.getJobId()));
+        return true;  // Job not finished
+    }
+
+    @Override
+    public boolean onStopJob(JobParameters params) {
+        Log.i(TAG, "Test job stop executing: " + params.getJobId());
+        int reason = params.getStopReason();
+        int event = TestEnvironment.EVENT_STOP_JOB;
+        Log.d(TAG, "stop reason: " + String.valueOf(reason));
+        if (reason == JobParameters.REASON_PREEMPT) {
+            event = TestEnvironment.EVENT_PREEMPT_JOB;
+            Log.d(TAG, "preempted " + String.valueOf(params.getJobId()));
+        }
+        TestEnvironment.getTestEnvironment().executedEvents
+                .add(new TestEnvironment.Event(event, params.getJobId()));
+        return false;  // Do not reschedule
+    }
+
+    public static class TestEnvironment {
+
+        public static final int EVENT_START_JOB = 0;
+        public static final int EVENT_PREEMPT_JOB = 1;
+        public static final int EVENT_STOP_JOB = 2;
+
+        private static TestEnvironment kTestEnvironment;
+
+        private ArrayList<Event> executedEvents = new ArrayList<Event>();
+
+        public static TestEnvironment getTestEnvironment() {
+            if (kTestEnvironment == null) {
+                kTestEnvironment = new TestEnvironment();
+            }
+            return kTestEnvironment;
+        }
+
+        public static class Event {
+            public int event;
+            public int jobId;
+
+            public Event() {
+            }
+
+            public Event(int event, int jobId) {
+                this.event = event;
+                this.jobId = jobId;
+            }
+
+            @Override
+            public boolean equals(Object other) {
+                if (other instanceof Event) {
+                    Event otherEvent = (Event) other;
+                    return otherEvent.event == event && otherEvent.jobId == jobId;
+                }
+                return false;
+            }
+        }
+
+        public void setUp() {
+            executedEvents.clear();
+        }
+
+        public ArrayList<Event> getExecutedEvents() {
+            return executedEvents;
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/job/PrioritySchedulingTest.java b/services/tests/servicestests/src/com/android/server/job/PrioritySchedulingTest.java
new file mode 100644
index 0000000..63bccfa
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/job/PrioritySchedulingTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.annotation.TargetApi;
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.content.ComponentName;
+import android.content.Context;
+import android.test.AndroidTestCase;
+import com.android.server.job.MockPriorityJobService.TestEnvironment;
+import com.android.server.job.MockPriorityJobService.TestEnvironment.Event;
+
+import java.util.ArrayList;
+
+@TargetApi(24)
+public class PrioritySchedulingTest extends AndroidTestCase {
+    /** Environment that notifies of JobScheduler callbacks. */
+    static TestEnvironment kTestEnvironment = TestEnvironment.getTestEnvironment();
+    /** Handle for the service which receives the execution callbacks from the JobScheduler. */
+    static ComponentName kJobServiceComponent;
+    JobScheduler mJobScheduler;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        kTestEnvironment.setUp();
+        kJobServiceComponent = new ComponentName(getContext(), MockPriorityJobService.class);
+        mJobScheduler = (JobScheduler) getContext().getSystemService(Context.JOB_SCHEDULER_SERVICE);
+        mJobScheduler.cancelAll();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        mJobScheduler.cancelAll();
+        super.tearDown();
+    }
+
+    public void testLowerPriorityJobPreempted() throws Exception {
+        JobInfo job1 = new JobInfo.Builder(111, kJobServiceComponent)
+                .setPriority(1)
+                .setOverrideDeadline(7000L)
+                .build();
+        JobInfo job2 = new JobInfo.Builder(222, kJobServiceComponent)
+                .setPriority(1)
+                .setOverrideDeadline(7000L)
+                .build();
+        JobInfo job3 = new JobInfo.Builder(333, kJobServiceComponent)
+                .setPriority(1)
+                .setOverrideDeadline(7000L)
+                .build();
+        JobInfo job4 = new JobInfo.Builder(444, kJobServiceComponent)
+                .setPriority(2)
+                .setMinimumLatency(2000L)
+                .setOverrideDeadline(7000L)
+                .build();
+        mJobScheduler.schedule(job1);
+        mJobScheduler.schedule(job2);
+        mJobScheduler.schedule(job3);
+        mJobScheduler.schedule(job4);
+        Thread.sleep(10000);  // Wait for job 4 to preempt one of the lower priority jobs
+
+        Event job4Execution = new Event(TestEnvironment.EVENT_START_JOB, 444);
+        ArrayList<Event> executedEvents = kTestEnvironment.getExecutedEvents();
+        boolean wasJob4Executed = executedEvents.contains(job4Execution);
+        boolean wasSomeJobPreempted = false;
+        for (Event event: executedEvents) {
+            if (event.event == TestEnvironment.EVENT_PREEMPT_JOB) {
+                wasSomeJobPreempted = true;
+                break;
+            }
+        }
+        assertTrue("No job was preempted.", wasSomeJobPreempted);
+        assertTrue("Lower priority jobs were not preempted.",  wasJob4Executed);
+    }
+
+    public void testHigherPriorityJobNotPreempted() throws Exception {
+        JobInfo job1 = new JobInfo.Builder(111, kJobServiceComponent)
+                .setPriority(2)
+                .setOverrideDeadline(7000L)
+                .build();
+        JobInfo job2 = new JobInfo.Builder(222, kJobServiceComponent)
+                .setPriority(2)
+                .setOverrideDeadline(7000L)
+                .build();
+        JobInfo job3 = new JobInfo.Builder(333, kJobServiceComponent)
+                .setPriority(2)
+                .setOverrideDeadline(7000L)
+                .build();
+        JobInfo job4 = new JobInfo.Builder(444, kJobServiceComponent)
+                .setPriority(1)
+                .setMinimumLatency(2000L)
+                .setOverrideDeadline(7000L)
+                .build();
+        mJobScheduler.schedule(job1);
+        mJobScheduler.schedule(job2);
+        mJobScheduler.schedule(job3);
+        mJobScheduler.schedule(job4);
+        Thread.sleep(10000);  // Wait for job 4 to preempt one of the higher priority jobs
+
+        Event job4Execution = new Event(TestEnvironment.EVENT_START_JOB, 444);
+        boolean wasJob4Executed = kTestEnvironment.getExecutedEvents().contains(job4Execution);
+        assertFalse("Higher priority job was preempted.", wasJob4Executed);
+    }
+}
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 df7b412..31182fc 100644
--- a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -35,7 +35,7 @@
 
 public class RankingHelperTest extends AndroidTestCase {
     @Mock NotificationUsageStats mUsageStats;
-    @Mock Handler handler;
+    @Mock RankingHandler handler;
 
     private Notification mNotiGroupGSortA;
     private Notification mNotiGroupGSortB;
@@ -155,16 +155,12 @@
 
     @SmallTest
     public void testTopicImportanceExtractor() throws Exception {
-        mHelper.setTopicImportance("package", 0, new Notification.Topic("A", "a"),
-                IMPORTANCE_MAX);
+        mHelper.setImportance("package", 0, new Notification.Topic("A", "a"), IMPORTANCE_MAX);
         // There is no B. There never was a b. Moving on...
-        mHelper.setTopicImportance("package", 0, new Notification.Topic("C", "c"),
-                IMPORTANCE_HIGH);
-        mHelper.setTopicImportance("package", 0, new Notification.Topic("D", "d"),
-                IMPORTANCE_LOW);
+        mHelper.setImportance("package", 0, new Notification.Topic("C", "c"), IMPORTANCE_HIGH);
+        mHelper.setImportance("package", 0, new Notification.Topic("D", "d"), IMPORTANCE_LOW);
         // watch out: different package.
-        mHelper.setTopicImportance("package2", 0, new Notification.Topic("E", "e"),
-                IMPORTANCE_NONE);
+        mHelper.setImportance("package2", 0, new Notification.Topic("E", "e"), IMPORTANCE_NONE);
 
         TopicImportanceExtractor validator = mHelper.findExtractor(TopicImportanceExtractor.class);
         validator.process(mRecordGroupGSortA);
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index b4bca3e..6c2fcd5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -26,7 +26,10 @@
 import android.os.UserManager;
 import android.test.AndroidTestCase;
 
+import com.android.internal.util.ArrayUtils;
+
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 /** Test {@link UserManager} functionality. */
@@ -196,6 +199,17 @@
         assertEquals(user2.id, mUserManager.getUserHandle(serialNumber2));
     }
 
+    public void testGetSerialNumbersOfUsers() {
+        UserInfo user1 = createUser("User 1", 0);
+        UserInfo user2 = createUser("User 2", 0);
+        long[] serialNumbersOfUsers = mUserManager.getSerialNumbersOfUsers(false);
+        String errMsg = "Array " + Arrays.toString(serialNumbersOfUsers) + " should contain ";
+        assertTrue(errMsg + user1.serialNumber,
+                ArrayUtils.contains(serialNumbersOfUsers, user1.serialNumber));
+        assertTrue(errMsg + user2.serialNumber,
+                ArrayUtils.contains(serialNumbersOfUsers, user2.serialNumber));
+    }
+
     public void testMaxUsers() {
         int N = UserManager.getMaxSupportedUsers();
         int count = mUserManager.getUsers().size();
diff --git a/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java b/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java
index 79b9135..0f9bf2f 100644
--- a/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java
+++ b/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java
@@ -72,7 +72,7 @@
     public void testNonSearchable() {
         // test basic array & hashmap
         Searchables searchables = new Searchables(mContext, 0);
-        searchables.buildSearchableList();
+        searchables.updateSearchableList();
 
         // confirm that we return null for non-searchy activities
         ComponentName nonActivity = new ComponentName(
@@ -104,7 +104,7 @@
         // build item list with real-world source data
         mockPM.setSearchablesMode(MyMockPackageManager.SEARCHABLES_PASSTHROUGH);
         Searchables searchables = new Searchables(mockContext, 0);
-        searchables.buildSearchableList();
+        searchables.updateSearchableList();
         // tests with "real" searchables (deprecate, this should be a unit test)
         ArrayList<SearchableInfo> searchablesList = searchables.getSearchablesList();
         int count = searchablesList.size();
@@ -123,7 +123,7 @@
 
         mockPM.setSearchablesMode(MyMockPackageManager.SEARCHABLES_MOCK_ZERO);
         Searchables searchables = new Searchables(mockContext, 0);
-        searchables.buildSearchableList();
+        searchables.updateSearchableList();
         ArrayList<SearchableInfo> searchablesList = searchables.getSearchablesList();
         assertNotNull(searchablesList);
         MoreAsserts.assertEmpty(searchablesList);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index 0ca4bd8..87c5ba0 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -17,6 +17,7 @@
 package com.android.server.usage;
 
 import android.app.usage.TimeSparseArray;
+import android.app.usage.UsageStats;
 import android.app.usage.UsageStatsManager;
 import android.os.Build;
 import android.util.AtomicFile;
@@ -25,6 +26,10 @@
 
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
 import java.io.File;
 import java.io.FileReader;
 import java.io.FileWriter;
@@ -39,6 +44,14 @@
 class UsageStatsDatabase {
     private static final int CURRENT_VERSION = 3;
 
+    // Current version of the backup schema
+    static final int BACKUP_STATE_VERSION = 1;
+
+    // Key under which the payload blob is stored
+    // same as UsageStatsBackupHelper.KEY_USAGE_STATS
+    static final String KEY_USAGE_STATS = "usage_stats";
+
+
     private static final String TAG = "UsageStatsDatabase";
     private static final boolean DEBUG = UsageStatsService.DEBUG;
     private static final String BAK_SUFFIX = ".bak";
@@ -539,4 +552,186 @@
             stats.lastTimeSaved = f.getLastModifiedTime();
         }
     }
+
+
+    /* Backup/Restore Code */
+    protected byte[] getBackupPayload(String key){
+        synchronized (mLock) {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            if (KEY_USAGE_STATS.equals(key)) {
+                prune(System.currentTimeMillis());
+                DataOutputStream out = new DataOutputStream(baos);
+                try {
+                    out.writeInt(BACKUP_STATE_VERSION);
+
+                    out.writeInt(mSortedStatFiles[UsageStatsManager.INTERVAL_DAILY].size());
+                    for(int i = 0; i<mSortedStatFiles[UsageStatsManager.INTERVAL_DAILY].size(); i++){
+                        writeIntervalStatsToStream(out, mSortedStatFiles[UsageStatsManager.INTERVAL_DAILY].valueAt(i));
+                    }
+
+                    out.writeInt(mSortedStatFiles[UsageStatsManager.INTERVAL_WEEKLY].size());
+                    for(int i = 0; i<mSortedStatFiles[UsageStatsManager.INTERVAL_WEEKLY].size(); i++){
+                        writeIntervalStatsToStream(out, mSortedStatFiles[UsageStatsManager.INTERVAL_WEEKLY].valueAt(i));
+                    }
+
+                    out.writeInt(mSortedStatFiles[UsageStatsManager.INTERVAL_MONTHLY].size());
+                    for(int i = 0; i<mSortedStatFiles[UsageStatsManager.INTERVAL_MONTHLY].size(); i++){
+                        writeIntervalStatsToStream(out, mSortedStatFiles[UsageStatsManager.INTERVAL_MONTHLY].valueAt(i));
+                    }
+
+                    out.writeInt(mSortedStatFiles[UsageStatsManager.INTERVAL_YEARLY].size());
+                    for(int i = 0; i<mSortedStatFiles[UsageStatsManager.INTERVAL_YEARLY].size(); i++){
+                        writeIntervalStatsToStream(out, mSortedStatFiles[UsageStatsManager.INTERVAL_YEARLY].valueAt(i));
+                    }
+                    if (DEBUG) Slog.i(TAG, "Written " + baos.size() + " bytes of data");
+                } catch (IOException ioe){
+                    Slog.d(TAG, "Failed to write data to output stream", ioe);
+                    baos.reset();
+                }
+            }
+            return baos.toByteArray();
+        }
+
+    }
+
+    protected void applyRestoredPayload(String key, byte[] payload){
+        synchronized (mLock) {
+            if (KEY_USAGE_STATS.equals(key)) {
+                // Read stats files for the current device configs
+                IntervalStats dailyConfigSource = getLatestUsageStats(UsageStatsManager.INTERVAL_DAILY);
+                IntervalStats weeklyConfigSource = getLatestUsageStats(UsageStatsManager.INTERVAL_WEEKLY);
+                IntervalStats monthlyConfigSource = getLatestUsageStats(UsageStatsManager.INTERVAL_MONTHLY);
+                IntervalStats yearlyConfigSource = getLatestUsageStats(UsageStatsManager.INTERVAL_YEARLY);
+
+                // Delete all stats files
+                for(int i = 0; i<mIntervalDirs.length; i++){
+                    deleteDirectoryContents(mIntervalDirs[i]);
+                }
+                try {
+                    DataInputStream in = new DataInputStream(new ByteArrayInputStream(payload));
+                    int stateVersion = in.readInt();
+
+                    int fileCount = in.readInt();
+                    for(int i = 0; i<fileCount; i++){
+                        IntervalStats stats = deserializeIntervalStats(getIntervalStatsBytes(in));
+                        stats = mergeStats(stats, dailyConfigSource);
+                        putUsageStats(UsageStatsManager.INTERVAL_DAILY, stats);
+                    }
+
+                    fileCount = in.readInt();
+                    for(int i = 0; i<fileCount; i++){
+                        IntervalStats stats = deserializeIntervalStats(getIntervalStatsBytes(in));
+                        stats = mergeStats(stats, weeklyConfigSource);
+                        putUsageStats(UsageStatsManager.INTERVAL_WEEKLY, stats);
+                    }
+
+                    fileCount = in.readInt();
+                    for(int i = 0; i<fileCount; i++){
+                        IntervalStats stats = deserializeIntervalStats(getIntervalStatsBytes(in));
+                        stats = mergeStats(stats, monthlyConfigSource);
+                        putUsageStats(UsageStatsManager.INTERVAL_MONTHLY, stats);
+                    }
+
+                    fileCount = in.readInt();
+                    for(int i = 0; i<fileCount; i++){
+                        IntervalStats stats = deserializeIntervalStats(getIntervalStatsBytes(in));
+                        stats = mergeStats(stats, yearlyConfigSource);
+                        putUsageStats(UsageStatsManager.INTERVAL_YEARLY, stats);
+                    }
+                    if (DEBUG) Slog.i(TAG, "Completed Restoring UsageStats");
+                } catch (IOException ioe){
+                    Slog.d(TAG, "Failed to read data from input stream", ioe);
+                }
+                finally {
+                    indexFilesLocked();
+                }
+            }
+        }
+    }
+
+    /**
+     * Get the Configuration Statistics from the current device statistics and merge them
+     * with the backed up usage statistics.
+     */
+    private IntervalStats mergeStats(IntervalStats beingRestored, IntervalStats onDevice) {
+        beingRestored.activeConfiguration = onDevice.activeConfiguration;
+        beingRestored.configurations.putAll(onDevice.configurations);
+        beingRestored.events = onDevice.events;
+        return beingRestored;
+    }
+
+    private void writeIntervalStatsToStream(DataOutputStream out, AtomicFile statsFile) throws IOException{
+        IntervalStats stats = new IntervalStats();
+        try {
+            UsageStatsXml.read(statsFile, stats);
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to read usage stats file", e);
+            out.writeInt(0);
+            return;
+        }
+        sanitizeIntervalStatsForBackup(stats);
+        byte[] data = serializeIntervalStats(stats);
+        out.writeInt(data.length);
+        out.write(data);
+    }
+
+    private static byte[] getIntervalStatsBytes(DataInputStream in) throws IOException {
+        int length = in.readInt();
+        byte[] buffer = new byte[length];
+        in.read(buffer, 0, length);
+        return buffer;
+    }
+
+    private static void sanitizeIntervalStatsForBackup(IntervalStats stats) {
+        if (stats == null) return;
+        stats.activeConfiguration = null;
+        stats.configurations.clear();
+        if (stats.events != null) stats.events.clear();
+    }
+
+    private static byte[] serializeIntervalStats(IntervalStats stats) {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        DataOutputStream out = new DataOutputStream(baos);
+        try {
+            out.writeLong(stats.beginTime);
+            UsageStatsXml.write(out, stats);
+        } catch (IOException ioe) {
+            Slog.d(TAG, "Serializing IntervalStats Failed", ioe);
+            baos.reset();
+        }
+        return baos.toByteArray();
+    }
+
+    private static IntervalStats deserializeIntervalStats(byte[] data) {
+        ByteArrayInputStream bais = new ByteArrayInputStream(data);
+        DataInputStream in = new DataInputStream(bais);
+        IntervalStats stats = new IntervalStats();
+        try {
+            stats.beginTime = in.readLong();
+            UsageStatsXml.read(in, stats);
+        } catch (IOException ioe) {
+            Slog.d(TAG, "DeSerializing IntervalStats Failed", ioe);
+            stats = null;
+        }
+        return stats;
+    }
+
+    private static void deleteDirectoryContents(File directory){
+        File[] files = directory.listFiles();
+        for (File file : files) {
+            deleteDirectory(file);
+        }
+    }
+
+    private static void deleteDirectory(File directory) {
+        File[] files = directory.listFiles();
+        for (File file : files) {
+            if (!file.isDirectory()) {
+                file.delete();
+            } else {
+                deleteDirectory(file);
+            }
+        }
+        directory.delete();
+    }
 }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 2b0919b..bfdac7e 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -123,6 +123,7 @@
     static final int MSG_PAROLE_END_TIMEOUT = 7;
     static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
     static final int MSG_PAROLE_STATE_CHANGED = 9;
+    static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10;
 
     private final Object mLock = new Object();
     Handler mHandler;
@@ -145,7 +146,7 @@
     private long mLastAppIdleParoledTime;
 
     long mScreenOnTime;
-    long mScreenOnSystemTimeSnapshot;
+    long mLastScreenOnEventRealtime;
 
     @GuardedBy("mLock")
     private AppIdleHistory mAppIdleHistory = new AppIdleHistory();
@@ -188,6 +189,8 @@
 
         synchronized (mLock) {
             cleanUpRemovedUsersLocked();
+            mLastScreenOnEventRealtime = SystemClock.elapsedRealtime();
+            mScreenOnTime = readScreenOnTimeLocked();
         }
 
         mRealTimeSnapshot = SystemClock.elapsedRealtime();
@@ -214,10 +217,6 @@
                     Context.DISPLAY_SERVICE);
             mPowerManager = getContext().getSystemService(PowerManager.class);
 
-            mScreenOnSystemTimeSnapshot = System.currentTimeMillis();
-            synchronized (mLock) {
-                mScreenOnTime = readScreenOnTimeLocked();
-            }
             mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
             synchronized (mLock) {
                 updateDisplayLocked();
@@ -280,6 +279,16 @@
         mHandler.sendEmptyMessageDelayed(MSG_FLUSH_TO_DISK, FLUSH_INTERVAL);
     }
 
+    @Override
+    public void onStatsReloaded() {
+        postOneTimeCheckIdleStates();
+    }
+
+    @Override
+    public long getAppIdleRollingWindowDurationMillis() {
+        return mAppIdleWallclockThresholdMillis * 2;
+    }
+
     private void cleanUpRemovedUsersLocked() {
         final List<UserInfo> users = mUserManager.getUsers(true);
         if (users == null || users.size() == 0) {
@@ -354,6 +363,14 @@
         mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
     }
 
+    /**
+     * We send a different message to check idle states once, otherwise we would end up
+     * scheduling a series of repeating checkIdleStates each time we fired off one.
+     */
+    void postOneTimeCheckIdleStates() {
+        mHandler.sendEmptyMessage(MSG_ONE_TIME_CHECK_IDLE_STATES);
+    }
+
     /** Check all running users' or specified user's apps to see if they enter an idle state. */
     void checkIdleStates(int checkUserId) {
         if (!mAppIdleEnabled) {
@@ -374,13 +391,13 @@
         for (int i = 0; i < userIds.length; i++) {
             final int userId = userIds[i];
             List<PackageInfo> packages =
-                    getContext().getPackageManager().getInstalledPackages(
+                    getContext().getPackageManager().getInstalledPackagesAsUser(
                             PackageManager.GET_DISABLED_COMPONENTS
                                 | PackageManager.GET_UNINSTALLED_PACKAGES,
                             userId);
             synchronized (mLock) {
                 final long timeNow = checkAndGetTimeLocked();
-                final long screenOnTime = getScreenOnTimeLocked(timeNow);
+                final long screenOnTime = getScreenOnTimeLocked();
                 UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId,
                         timeNow);
                 final int packageCount = packages.size();
@@ -396,8 +413,6 @@
                 }
             }
         }
-        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, checkUserId, 0),
-                mCheckIdleIntervalMillis);
     }
 
     /** Check if it's been a while since last parole and let idle apps do some work */
@@ -418,7 +433,8 @@
 
     private void notifyBatteryStats(String packageName, int userId, boolean idle) {
         try {
-            int uid = AppGlobals.getPackageManager().getPackageUid(packageName, userId);
+            final int uid = AppGlobals.getPackageManager().getPackageUid(packageName,
+                    PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
             if (idle) {
                 mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_INACTIVE,
                         packageName, uid);
@@ -437,21 +453,21 @@
         if (screenOn == mScreenOn) return;
 
         mScreenOn = screenOn;
-        long now = System.currentTimeMillis();
+        long now = SystemClock.elapsedRealtime();
         if (mScreenOn) {
-            mScreenOnSystemTimeSnapshot = now;
+            mLastScreenOnEventRealtime = now;
         } else {
-            mScreenOnTime += now - mScreenOnSystemTimeSnapshot;
+            mScreenOnTime += now - mLastScreenOnEventRealtime;
             writeScreenOnTimeLocked(mScreenOnTime);
         }
     }
 
-    private long getScreenOnTimeLocked(long now) {
+    long getScreenOnTimeLocked() {
+        long screenOnTime = mScreenOnTime;
         if (mScreenOn) {
-            return now - mScreenOnSystemTimeSnapshot + mScreenOnTime;
-        } else {
-            return mScreenOnTime;
+            screenOnTime += SystemClock.elapsedRealtime() - mLastScreenOnEventRealtime;
         }
+        return screenOnTime;
     }
 
     private File getScreenOnTimeFile() {
@@ -521,7 +537,7 @@
         if (service == null) {
             service = new UserUsageStatsService(getContext(), userId,
                     new File(mUsageStatsDir, Integer.toString(userId)), this);
-            service.init(currentTimeMillis, getScreenOnTimeLocked(currentTimeMillis));
+            service.init(currentTimeMillis, getScreenOnTimeLocked());
             mUserState.put(userId, service);
         }
         return service;
@@ -534,20 +550,15 @@
         final long actualSystemTime = System.currentTimeMillis();
         final long actualRealtime = SystemClock.elapsedRealtime();
         final long expectedSystemTime = (actualRealtime - mRealTimeSnapshot) + mSystemTimeSnapshot;
-        boolean resetBeginIdleTime = false;
-        if (Math.abs(actualSystemTime - expectedSystemTime) > TIME_CHANGE_THRESHOLD_MILLIS) {
+        final long diffSystemTime = actualSystemTime - expectedSystemTime;
+        if (Math.abs(diffSystemTime) > TIME_CHANGE_THRESHOLD_MILLIS) {
             // The time has changed.
-
-            // Check if it's severe enough a change to reset screenOnTime
-            if (Math.abs(actualSystemTime - expectedSystemTime) > mAppIdleDurationMillis) {
-                mScreenOnSystemTimeSnapshot = actualSystemTime;
-                mScreenOnTime = 0;
-                resetBeginIdleTime = true;
-            }
+            Slog.i(TAG, "Time changed in UsageStats by " + (diffSystemTime / 1000) + " seconds");
             final int userCount = mUserState.size();
             for (int i = 0; i < userCount; i++) {
                 final UserUsageStatsService service = mUserState.valueAt(i);
-                service.onTimeChanged(expectedSystemTime, actualSystemTime, resetBeginIdleTime);
+                service.onTimeChanged(expectedSystemTime, actualSystemTime, getScreenOnTimeLocked(),
+                        false);
             }
             mRealTimeSnapshot = actualRealtime;
             mSystemTimeSnapshot = actualSystemTime;
@@ -579,7 +590,7 @@
     void reportEvent(UsageEvents.Event event, int userId) {
         synchronized (mLock) {
             final long timeNow = checkAndGetTimeLocked();
-            final long screenOnTime = getScreenOnTimeLocked(timeNow);
+            final long screenOnTime = getScreenOnTimeLocked();
             convertToSystemTimeLocked(event);
 
             final UserUsageStatsService service =
@@ -595,7 +606,6 @@
                     || event.mEventType == Event.SYSTEM_INTERACTION
                     || event.mEventType == Event.USER_INTERACTION)) {
                 if (previouslyIdle) {
-                    // Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
                     mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
                             /* idle = */ 0, event.mPackage));
                     notifyBatteryStats(event.mPackage, userId, false);
@@ -614,9 +624,8 @@
             // the sync adapter is a system package.
             try {
                 PackageInfo pi = AppGlobals.getPackageManager().getPackageInfo(
-                        packageName, 0, userId);
-                if (pi == null || pi.applicationInfo == null
-                        || !pi.applicationInfo.isSystemApp()) {
+                        packageName, PackageManager.MATCH_SYSTEM_ONLY, userId);
+                if (pi == null || pi.applicationInfo == null) {
                     continue;
                 }
                 if (!packageName.equals(providerPkgName)) {
@@ -636,7 +645,7 @@
     void forceIdleState(String packageName, int userId, boolean idle) {
         synchronized (mLock) {
             final long timeNow = checkAndGetTimeLocked();
-            final long screenOnTime = getScreenOnTimeLocked(timeNow);
+            final long screenOnTime = getScreenOnTimeLocked();
             final long deviceUsageTime = screenOnTime - (idle ? mAppIdleDurationMillis : 0) - 5000;
 
             final UserUsageStatsService service =
@@ -650,7 +659,6 @@
                     timeNow - (idle ? mAppIdleWallclockThresholdMillis : 0) - 5000);
             // Inform listeners if necessary
             if (previouslyIdle != idle) {
-                // Slog.d(TAG, "Informing listeners of out-of-idle " + packageName);
                 mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
                         /* idle = */ idle ? 1 : 0, packageName));
                 if (!idle) {
@@ -789,7 +797,7 @@
                 timeNow = checkAndGetTimeLocked();
             }
             userService = getUserDataAndInitializeIfNeededLocked(userId, timeNow);
-            screenOnTime = getScreenOnTimeLocked(timeNow);
+            screenOnTime = getScreenOnTimeLocked();
         }
         return isAppIdleFiltered(packageName, UserHandle.getAppId(uidForAppId), userId,
                 userService, timeNow, screenOnTime);
@@ -858,13 +866,13 @@
         synchronized (mLock) {
             timeNow = checkAndGetTimeLocked();
             userService = getUserDataAndInitializeIfNeededLocked(userId, timeNow);
-            screenOnTime = getScreenOnTimeLocked(timeNow);
+            screenOnTime = getScreenOnTimeLocked();
         }
 
         List<ApplicationInfo> apps;
         try {
-            ParceledListSlice<ApplicationInfo> slice
-                    = AppGlobals.getPackageManager().getInstalledApplications(0, userId);
+            ParceledListSlice<ApplicationInfo> slice = AppGlobals.getPackageManager()
+                    .getInstalledApplications(PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
             if (slice == null) {
                 return new int[0];
             }
@@ -980,7 +988,7 @@
      */
     void dump(String[] args, PrintWriter pw) {
         synchronized (mLock) {
-            final long screenOnTime = getScreenOnTimeLocked(checkAndGetTimeLocked());
+            final long screenOnTime = getScreenOnTimeLocked();
             IndentingPrintWriter idpw = new IndentingPrintWriter(pw, "  ");
             ArraySet<String> argSet = new ArraySet<>();
             argSet.addAll(Arrays.asList(args));
@@ -1001,7 +1009,11 @@
                 }
                 idpw.decreaseIndent();
             }
-            pw.println("Screen On Timebase:" + mScreenOnTime);
+            pw.print("Screen On Timebase: ");
+            pw.print(screenOnTime);
+            pw.print(" (");
+            TimeUtils.formatDuration(screenOnTime, pw);
+            pw.println(")");
 
             pw.println();
             pw.println("Settings:");
@@ -1035,8 +1047,8 @@
             pw.println();
             pw.print("mScreenOnTime="); TimeUtils.formatDuration(mScreenOnTime, pw);
             pw.println();
-            pw.print("mScreenOnSystemTimeSnapshot=");
-            TimeUtils.formatDuration(mScreenOnSystemTimeSnapshot, pw);
+            pw.print("mLastScreenOnEventRealtime=");
+            TimeUtils.formatDuration(mLastScreenOnEventRealtime, pw);
             pw.println();
         }
     }
@@ -1071,6 +1083,14 @@
 
                 case MSG_CHECK_IDLE_STATES:
                     checkIdleStates(msg.arg1);
+                    mHandler.sendMessageDelayed(mHandler.obtainMessage(
+                            MSG_CHECK_IDLE_STATES, msg.arg1, 0),
+                            mCheckIdleIntervalMillis);
+                    break;
+
+                case MSG_ONE_TIME_CHECK_IDLE_STATES:
+                    mHandler.removeMessages(MSG_ONE_TIME_CHECK_IDLE_STATES);
+                    checkIdleStates(UserHandle.USER_ALL);
                     break;
 
                 case MSG_CHECK_PAROLE_TIMEOUT:
@@ -1106,7 +1126,13 @@
      * Observe settings changes for {@link Settings.Global#APP_IDLE_CONSTANTS}.
      */
     private class SettingsObserver extends ContentObserver {
-        private static final String KEY_IDLE_DURATION = "idle_duration";
+        /**
+         * This flag has been used to disable app idle on older builds with bug b/26355386.
+         */
+        @Deprecated
+        private static final String KEY_IDLE_DURATION_OLD = "idle_duration";
+
+        private static final String KEY_IDLE_DURATION = "idle_duration2";
         private static final String KEY_WALLCLOCK_THRESHOLD = "wallclock_threshold";
         private static final String KEY_PAROLE_INTERVAL = "parole_interval";
         private static final String KEY_PAROLE_DURATION = "parole_duration";
@@ -1125,7 +1151,7 @@
         @Override
         public void onChange(boolean selfChange) {
             updateSettings();
-            postCheckIdleStates(UserHandle.USER_ALL);
+            postOneTimeCheckIdleStates();
         }
 
         void updateSettings() {
@@ -1266,8 +1292,8 @@
                     "No permission to change app idle state");
             final long token = Binder.clearCallingIdentity();
             try {
-                PackageInfo pi = AppGlobals.getPackageManager()
-                        .getPackageInfo(packageName, 0, userId);
+                PackageInfo pi = AppGlobals.getPackageManager().getPackageInfo(packageName,
+                        PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
                 if (pi == null) return;
                 UsageStatsService.this.setAppIdle(packageName, idle, userId);
             } catch (RemoteException re) {
@@ -1297,6 +1323,8 @@
             }
             UsageStatsService.this.dump(args, pw);
         }
+
+
     }
 
     /**
@@ -1403,5 +1431,26 @@
                 AppIdleStateChangeListener listener) {
             UsageStatsService.this.removeListener(listener);
         }
+
+        @Override
+        public byte[] getBackupPayload(int user, String key) {
+            // Check to ensure that only user 0's data is b/r for now
+            if (user == UserHandle.USER_SYSTEM) {
+                final UserUsageStatsService userStats =
+                        getUserDataAndInitializeIfNeededLocked(user, checkAndGetTimeLocked());
+                return userStats.getBackupPayload(key);
+            } else {
+                return null;
+            }
+        }
+
+        @Override
+        public void applyRestoredPayload(int user, String key, byte[] payload) {
+            if (user == UserHandle.USER_SYSTEM) {
+                final UserUsageStatsService userStats =
+                        getUserDataAndInitializeIfNeededLocked(user, checkAndGetTimeLocked());
+                userStats.applyRestoredPayload(key, payload);
+            }
+        }
     }
 }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsXml.java b/services/usage/java/com/android/server/usage/UsageStatsXml.java
index 543f361..e7db741 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsXml.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsXml.java
@@ -87,7 +87,7 @@
         }
     }
 
-    private static void read(InputStream in, IntervalStats statsOut) throws IOException {
+    static void read(InputStream in, IntervalStats statsOut) throws IOException {
         XmlPullParser parser = Xml.newPullParser();
         try {
             parser.setInput(in, "utf-8");
@@ -113,7 +113,7 @@
         }
     }
 
-    private static void write(OutputStream out, IntervalStats stats) throws IOException {
+    static void write(OutputStream out, IntervalStats stats) throws IOException {
         FastXmlSerializer xml = new FastXmlSerializer();
         xml.setOutput(out, "utf-8");
         xml.startDocument("utf-8", true);
@@ -126,4 +126,4 @@
         xml.endTag(null, USAGESTATS_TAG);
         xml.endDocument();
     }
-}
+}
\ No newline at end of file
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 5188e5f..f2045d3 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -59,6 +59,7 @@
     private final Context mContext;
     private final UsageStatsDatabase mDatabase;
     private final IntervalStats[] mCurrentStats;
+    private IntervalStats mAppIdleRollingWindow;
     private boolean mStatsChanged = false;
     private final UnixCalendar mDailyExpiryDate;
     private final StatsUpdatedListener mListener;
@@ -72,6 +73,8 @@
 
     interface StatsUpdatedListener {
         void onStatsUpdated();
+        void onStatsReloaded();
+        long getAppIdleRollingWindowDurationMillis();
     }
 
     UserUsageStatsService(Context context, int userId, File usageStatsDir,
@@ -133,6 +136,8 @@
             stat.updateConfigurationStats(null, stat.lastTimeSaved);
         }
 
+        refreshAppIdleRollingWindow(currentTimeMillis, deviceUsageTime);
+
         if (mDatabase.isNewUpdate()) {
             initializeDefaultsForApps(currentTimeMillis, deviceUsageTime,
                     mDatabase.isFirstUpdate());
@@ -148,7 +153,7 @@
     private void initializeDefaultsForApps(long currentTimeMillis, long deviceUsageTime,
             boolean firstUpdate) {
         PackageManager pm = mContext.getPackageManager();
-        List<PackageInfo> packages = pm.getInstalledPackages(0, mUserId);
+        List<PackageInfo> packages = pm.getInstalledPackagesAsUser(0, mUserId);
         final int packageCount = packages.size();
         for (int i = 0; i < packageCount; i++) {
             final PackageInfo pi = packages.get(i);
@@ -158,18 +163,24 @@
                 for (IntervalStats stats : mCurrentStats) {
                     stats.update(packageName, currentTimeMillis, Event.SYSTEM_INTERACTION);
                     stats.updateBeginIdleTime(packageName, deviceUsageTime);
-                    mStatsChanged = true;
                 }
+
+                mAppIdleRollingWindow.update(packageName, currentTimeMillis,
+                        Event.SYSTEM_INTERACTION);
+                mAppIdleRollingWindow.updateBeginIdleTime(packageName, deviceUsageTime);
+                mStatsChanged = true;
             }
         }
         // Persist the new OTA-related access stats.
         persistActiveStats();
     }
 
-    void onTimeChanged(long oldTime, long newTime, boolean resetBeginIdleTime) {
+    void onTimeChanged(long oldTime, long newTime, long deviceUsageTime,
+                       boolean resetBeginIdleTime) {
         persistActiveStats();
         mDatabase.onTimeChanged(newTime - oldTime);
         loadActiveStats(newTime, resetBeginIdleTime);
+        refreshAppIdleRollingWindow(newTime, deviceUsageTime);
     }
 
     void reportEvent(UsageEvents.Event event, long deviceUsageTime) {
@@ -181,7 +192,7 @@
 
         if (event.mTimeStamp >= mDailyExpiryDate.getTimeInMillis()) {
             // Need to rollover
-            rolloverStats(event.mTimeStamp);
+            rolloverStats(event.mTimeStamp, deviceUsageTime);
         }
 
         final IntervalStats currentDailyStats = mCurrentStats[UsageStatsManager.INTERVAL_DAILY];
@@ -211,6 +222,11 @@
             }
         }
 
+        if (event.mEventType != Event.CONFIGURATION_CHANGE) {
+            mAppIdleRollingWindow.update(event.mPackage, event.mTimeStamp, event.mEventType);
+            mAppIdleRollingWindow.updateBeginIdleTime(event.mPackage, deviceUsageTime);
+        }
+
         notifyStatsChanged();
     }
 
@@ -222,6 +238,7 @@
         for (IntervalStats stats : mCurrentStats) {
             stats.updateBeginIdleTime(packageName, beginIdleTime);
         }
+        mAppIdleRollingWindow.updateBeginIdleTime(packageName, beginIdleTime);
         notifyStatsChanged();
     }
 
@@ -229,6 +246,7 @@
         for (IntervalStats stats : mCurrentStats) {
             stats.updateSystemLastUsedTime(packageName, lastUsedTime);
         }
+        mAppIdleRollingWindow.updateSystemLastUsedTime(packageName, lastUsedTime);
         notifyStatsChanged();
     }
 
@@ -387,9 +405,8 @@
     }
 
     long getBeginIdleTime(String packageName) {
-        final IntervalStats yearly = mCurrentStats[UsageStatsManager.INTERVAL_YEARLY];
         UsageStats packageUsage;
-        if ((packageUsage = yearly.packageStats.get(packageName)) == null) {
+        if ((packageUsage = mAppIdleRollingWindow.packageStats.get(packageName)) == null) {
             return -1;
         } else {
             return packageUsage.getBeginIdleTime();
@@ -397,9 +414,8 @@
     }
 
     long getSystemLastUsedTime(String packageName) {
-        final IntervalStats yearly = mCurrentStats[UsageStatsManager.INTERVAL_YEARLY];
         UsageStats packageUsage;
-        if ((packageUsage = yearly.packageStats.get(packageName)) == null) {
+        if ((packageUsage = mAppIdleRollingWindow.packageStats.get(packageName)) == null) {
             return -1;
         } else {
             return packageUsage.getLastTimeSystemUsed();
@@ -420,7 +436,7 @@
         }
     }
 
-    private void rolloverStats(final long currentTimeMillis) {
+    private void rolloverStats(final long currentTimeMillis, final long deviceUsageTime) {
         final long startTime = SystemClock.elapsedRealtime();
         Slog.i(TAG, mLogPrefix + "Rolling over usage stats");
 
@@ -461,6 +477,8 @@
         }
         persistActiveStats();
 
+        refreshAppIdleRollingWindow(currentTimeMillis, deviceUsageTime);
+
         final long totalTime = SystemClock.elapsedRealtime() - startTime;
         Slog.i(TAG, mLogPrefix + "Rolling over usage stats complete. Took " + totalTime
                 + " milliseconds");
@@ -503,8 +521,12 @@
                 }
             }
         }
+
         mStatsChanged = false;
         updateRolloverDeadline();
+
+        // Tell the listener that the stats reloaded, which may have changed idle states.
+        mListener.onStatsReloaded();
     }
 
     private void updateRolloverDeadline() {
@@ -516,6 +538,71 @@
                 mDailyExpiryDate.getTimeInMillis() + ")");
     }
 
+    private static void mergePackageStats(IntervalStats dst, IntervalStats src,
+                                          final long deviceUsageTime) {
+        dst.endTime = Math.max(dst.endTime, src.endTime);
+
+        final int srcPackageCount = src.packageStats.size();
+        for (int i = 0; i < srcPackageCount; i++) {
+            final String packageName = src.packageStats.keyAt(i);
+            final UsageStats srcStats = src.packageStats.valueAt(i);
+            UsageStats dstStats = dst.packageStats.get(packageName);
+            if (dstStats == null) {
+                dstStats = new UsageStats(srcStats);
+                dst.packageStats.put(packageName, dstStats);
+            } else {
+                dstStats.add(src.packageStats.valueAt(i));
+            }
+
+            // App idle times can not begin in the future. This happens if we had a time change.
+            if (dstStats.mBeginIdleTime > deviceUsageTime) {
+                dstStats.mBeginIdleTime = deviceUsageTime;
+            }
+        }
+    }
+
+    /**
+     * App idle operates on a rolling window of time. When we roll over time, we end up with a
+     * period of time where in-memory stats are empty and we don't hit the disk for older stats
+     * for performance reasons. Suddenly all apps will become idle.
+     *
+     * Instead, at times we do a deep query to find all the apps that have run in the past few
+     * days and keep the cached data up to date.
+     *
+     * @param currentTimeMillis
+     */
+    void refreshAppIdleRollingWindow(final long currentTimeMillis, final long deviceUsageTime) {
+        // Start the rolling window for AppIdle requests.
+        final long startRangeMillis = currentTimeMillis -
+                mListener.getAppIdleRollingWindowDurationMillis();
+
+        List<IntervalStats> stats = mDatabase.queryUsageStats(UsageStatsManager.INTERVAL_DAILY,
+                startRangeMillis, currentTimeMillis, new StatCombiner<IntervalStats>() {
+                    @Override
+                    public void combine(IntervalStats stats, boolean mutable,
+                                        List<IntervalStats> accumulatedResult) {
+                        IntervalStats accum;
+                        if (accumulatedResult.isEmpty()) {
+                            accum = new IntervalStats();
+                            accum.beginTime = stats.beginTime;
+                            accumulatedResult.add(accum);
+                        } else {
+                            accum = accumulatedResult.get(0);
+                        }
+
+                        mergePackageStats(accum, stats, deviceUsageTime);
+                    }
+                });
+
+        if (stats == null || stats.isEmpty()) {
+            mAppIdleRollingWindow = new IntervalStats();
+            mergePackageStats(mAppIdleRollingWindow,
+                    mCurrentStats[UsageStatsManager.INTERVAL_YEARLY], deviceUsageTime);
+        } else {
+            mAppIdleRollingWindow = stats.get(0);
+        }
+    }
+
     //
     // -- DUMP related methods --
     //
@@ -538,6 +625,9 @@
             pw.println(" stats");
             printIntervalStats(pw, mCurrentStats[interval], screenOnTime, true);
         }
+
+        pw.println("AppIdleRollingWindow cache");
+        printIntervalStats(pw, mAppIdleRollingWindow, screenOnTime, true);
     }
 
     private String formatDateTime(long dateTime, boolean pretty) {
@@ -655,4 +745,12 @@
                 return "UNKNOWN";
         }
     }
+
+    byte[] getBackupPayload(String key){
+        return mDatabase.getBackupPayload(key);
+    }
+
+    void applyRestoredPayload(String key, byte[] payload){
+        mDatabase.applyRestoredPayload(key, payload);
+    }
 }
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index c734fab..35a0464 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -858,7 +858,7 @@
                             .setOngoing(true)
                             .setTicker(title)
                             .setDefaults(0)  // please be quiet
-                            .setPriority(Notification.PRIORITY_LOW)
+                            .setPriority(Notification.PRIORITY_DEFAULT)
                             .setColor(mContext.getColor(
                                     com.android.internal.R.color.system_notification_accent_color))
                             .setContentTitle(title)
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerDbHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerDbHelper.java
new file mode 100644
index 0000000..18a5d59
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerDbHelper.java
@@ -0,0 +1,144 @@
+/**
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.soundtrigger;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.hardware.soundtrigger.SoundTrigger;
+import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import java.util.Locale;
+import java.util.UUID;
+
+/**
+ * Helper to manage the database of the sound models that have been registered on the device.
+ *
+ * @hide
+ */
+public class SoundTriggerDbHelper extends SQLiteOpenHelper {
+    static final String TAG = "SoundTriggerDbHelper";
+    static final boolean DBG = false;
+
+    private static final String NAME = "st_sound_model.db";
+    private static final int VERSION = 1;
+
+    // Sound trigger-based sound models.
+    public static interface GenericSoundModelContract {
+        public static final String TABLE = "st_sound_model";
+        public static final String KEY_MODEL_UUID = "model_uuid";
+        public static final String KEY_VENDOR_UUID = "vendor_uuid";
+        public static final String KEY_DATA = "data";
+    }
+
+
+    // Table Create Statement for the sound trigger table
+    private static final String CREATE_TABLE_ST_SOUND_MODEL = "CREATE TABLE "
+            + GenericSoundModelContract.TABLE + "("
+            + GenericSoundModelContract.KEY_MODEL_UUID + " TEXT PRIMARY KEY,"
+            + GenericSoundModelContract.KEY_DATA + " BLOB" + " )";
+
+
+    public SoundTriggerDbHelper(Context context) {
+        super(context, NAME, null, VERSION);
+    }
+
+    @Override
+    public void onCreate(SQLiteDatabase db) {
+        // creating required tables
+        db.execSQL(CREATE_TABLE_ST_SOUND_MODEL);
+    }
+
+    @Override
+    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+        // TODO: For now, drop older tables and recreate new ones.
+        db.execSQL("DROP TABLE IF EXISTS " + GenericSoundModelContract.TABLE);
+        onCreate(db);
+    }
+
+    /**
+     * Updates the given sound trigger model, adds it, if it doesn't already exist.
+     *
+     */
+    public boolean updateGenericSoundModel(GenericSoundModel soundModel) {
+        synchronized(this) {
+            SQLiteDatabase db = getWritableDatabase();
+            ContentValues values = new ContentValues();
+            values.put(GenericSoundModelContract.KEY_MODEL_UUID, soundModel.uuid.toString());
+            values.put(GenericSoundModelContract.KEY_VENDOR_UUID, soundModel.vendorUuid.toString());
+            values.put(GenericSoundModelContract.KEY_DATA, soundModel.data);
+
+            try {
+                return db.insertWithOnConflict(GenericSoundModelContract.TABLE, null, values,
+                        SQLiteDatabase.CONFLICT_REPLACE) != -1;
+            } finally {
+                db.close();
+            }
+
+        }
+    }
+
+    public GenericSoundModel getGenericSoundModel(UUID model_uuid) {
+        synchronized(this) {
+
+            // Find the corresponding sound model ID for the keyphrase.
+            String selectQuery = "SELECT  * FROM " + GenericSoundModelContract.TABLE
+                    + " WHERE " + GenericSoundModelContract.KEY_MODEL_UUID + "= '" +
+                    model_uuid + "'";
+            SQLiteDatabase db = getReadableDatabase();
+            Cursor c = db.rawQuery(selectQuery, null);
+            try {
+                if (c.moveToFirst()) {
+                    do {
+                        byte[] data = c.getBlob(c.getColumnIndex(
+                                GenericSoundModelContract.KEY_DATA));
+                        String vendor_uuid = c.getString(
+                                c.getColumnIndex(GenericSoundModelContract.KEY_VENDOR_UUID));
+                        return new GenericSoundModel(model_uuid, UUID.fromString(vendor_uuid),
+                                data);
+                    } while (c.moveToNext());
+                }
+            } finally {
+                c.close();
+                db.close();
+            }
+        }
+        return null;
+    }
+
+    public boolean deleteGenericSoundModel(UUID model_uuid) {
+        synchronized(this) {
+            GenericSoundModel soundModel = getGenericSoundModel(model_uuid);
+            if (soundModel == null) {
+                return false;
+            }
+            // Delete all sound models for the given keyphrase and specified user.
+            SQLiteDatabase db = getWritableDatabase();
+            String soundModelClause = GenericSoundModelContract.KEY_MODEL_UUID
+                    + "='" + soundModel.uuid.toString() + "'";
+            try {
+                return db.delete(GenericSoundModelContract.TABLE, soundModelClause, null) != 0;
+            } finally {
+                db.close();
+            }
+        }
+    }
+}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
new file mode 100644
index 0000000..597f915ec
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -0,0 +1,591 @@
+/**
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.soundtrigger;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.SoundTrigger;
+import android.hardware.soundtrigger.SoundTrigger.Keyphrase;
+import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionEvent;
+import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra;
+import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
+import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
+import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
+import android.hardware.soundtrigger.SoundTrigger.SoundModelEvent;
+import android.hardware.soundtrigger.SoundTriggerModule;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
+import android.util.Slog;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * Helper for {@link SoundTrigger} APIs.
+ * Currently this just acts as an abstraction over all SoundTrigger API calls.
+ *
+ * @hide
+ */
+public class SoundTriggerHelper implements SoundTrigger.StatusListener {
+    static final String TAG = "SoundTriggerHelper";
+    static final boolean DBG = false;
+
+    /**
+     * Return codes for {@link #startRecognition(int, KeyphraseSoundModel,
+     *      IRecognitionStatusCallback, RecognitionConfig)},
+     * {@link #stopRecognition(int, IRecognitionStatusCallback)}
+     */
+    public static final int STATUS_ERROR = SoundTrigger.STATUS_ERROR;
+    public static final int STATUS_OK = SoundTrigger.STATUS_OK;
+
+    private static final int INVALID_VALUE = Integer.MIN_VALUE;
+
+    /** The {@link ModuleProperties} for the system, or null if none exists. */
+    final ModuleProperties moduleProperties;
+
+    /** The properties for the DSP module */
+    private SoundTriggerModule mModule;
+    private final Object mLock = new Object();
+    private final Context mContext;
+    private final TelephonyManager mTelephonyManager;
+    private final PhoneStateListener mPhoneStateListener;
+    private final PowerManager mPowerManager;
+
+    // TODO: Since many layers currently only deal with one recognition
+    // we simplify things by assuming one listener here too.
+    private IRecognitionStatusCallback mActiveListener;
+    private int mKeyphraseId = INVALID_VALUE;
+    private int mCurrentSoundModelHandle = INVALID_VALUE;
+    private KeyphraseSoundModel mCurrentSoundModel = null;
+    // FIXME: Ideally this should not be stored if allowMultipleTriggers happens at a lower layer.
+    private RecognitionConfig mRecognitionConfig = null;
+    private boolean mRequested = false;
+    private boolean mCallActive = false;
+    private boolean mIsPowerSaveMode = false;
+    // Indicates if the native sound trigger service is disabled or not.
+    // This is an indirect indication of the microphone being open in some other application.
+    private boolean mServiceDisabled = false;
+    private boolean mStarted = false;
+    private boolean mRecognitionAborted = false;
+    private PowerSaveModeListener mPowerSaveModeListener;
+
+    SoundTriggerHelper(Context context) {
+        ArrayList <ModuleProperties> modules = new ArrayList<>();
+        int status = SoundTrigger.listModules(modules);
+        mContext = context;
+        mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+        mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+        mPhoneStateListener = new MyCallStateListener();
+        if (status != SoundTrigger.STATUS_OK || modules.size() == 0) {
+            Slog.w(TAG, "listModules status=" + status + ", # of modules=" + modules.size());
+            moduleProperties = null;
+            mModule = null;
+        } else {
+            // TODO: Figure out how to determine which module corresponds to the DSP hardware.
+            moduleProperties = modules.get(0);
+        }
+    }
+
+    /**
+     * Starts recognition for the given keyphraseId.
+     *
+     * @param keyphraseId The identifier of the keyphrase for which
+     *        the recognition is to be started.
+     * @param soundModel The sound model to use for recognition.
+     * @param listener The listener for the recognition events related to the given keyphrase.
+     * @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
+     */
+    int startRecognition(int keyphraseId,
+            KeyphraseSoundModel soundModel,
+            IRecognitionStatusCallback listener,
+            RecognitionConfig recognitionConfig) {
+        if (soundModel == null || listener == null || recognitionConfig == null) {
+            return STATUS_ERROR;
+        }
+
+        synchronized (mLock) {
+            if (DBG) {
+                Slog.d(TAG, "startRecognition for keyphraseId=" + keyphraseId
+                        + " soundModel=" + soundModel + ", listener=" + listener.asBinder()
+                        + ", recognitionConfig=" + recognitionConfig);
+                Slog.d(TAG, "moduleProperties=" + moduleProperties);
+                Slog.d(TAG, "current listener="
+                        + (mActiveListener == null ? "null" : mActiveListener.asBinder()));
+                Slog.d(TAG, "current SoundModel handle=" + mCurrentSoundModelHandle);
+                Slog.d(TAG, "current SoundModel UUID="
+                        + (mCurrentSoundModel == null ? null : mCurrentSoundModel.uuid));
+            }
+
+            if (!mStarted) {
+                // Get the current call state synchronously for the first recognition.
+                mCallActive = mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE;
+                // Register for call state changes when the first call to start recognition occurs.
+                mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
+
+                // Register for power saver mode changes when the first call to start recognition
+                // occurs.
+                if (mPowerSaveModeListener == null) {
+                    mPowerSaveModeListener = new PowerSaveModeListener();
+                    mContext.registerReceiver(mPowerSaveModeListener,
+                            new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
+                }
+                mIsPowerSaveMode = mPowerManager.isPowerSaveMode();
+            }
+
+            if (moduleProperties == null) {
+                Slog.w(TAG, "Attempting startRecognition without the capability");
+                return STATUS_ERROR;
+            }
+            if (mModule == null) {
+                mModule = SoundTrigger.attachModule(moduleProperties.id, this, null);
+                if (mModule == null) {
+                    Slog.w(TAG, "startRecognition cannot attach to sound trigger module");
+                    return STATUS_ERROR;
+                }
+            }
+
+            // Unload the previous model if the current one isn't invalid
+            // and, it's not the same as the new one.
+            // This helps use cache and reuse the model and just start/stop it when necessary.
+            if (mCurrentSoundModelHandle != INVALID_VALUE
+                    && !soundModel.equals(mCurrentSoundModel)) {
+                Slog.w(TAG, "Unloading previous sound model");
+                int status = mModule.unloadSoundModel(mCurrentSoundModelHandle);
+                if (status != SoundTrigger.STATUS_OK) {
+                    Slog.w(TAG, "unloadSoundModel call failed with " + status);
+                }
+                internalClearSoundModelLocked();
+                mStarted = false;
+            }
+
+            // If the previous recognition was by a different listener,
+            // Notify them that it was stopped.
+            if (mActiveListener != null && mActiveListener.asBinder() != listener.asBinder()) {
+                Slog.w(TAG, "Canceling previous recognition");
+                try {
+                    mActiveListener.onError(STATUS_ERROR);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "RemoteException in onDetectionStopped", e);
+                }
+                mActiveListener = null;
+            }
+
+            // Load the sound model if the current one is null.
+            int soundModelHandle = mCurrentSoundModelHandle;
+            if (mCurrentSoundModelHandle == INVALID_VALUE
+                    || mCurrentSoundModel == null) {
+                int[] handle = new int[] { INVALID_VALUE };
+                int status = mModule.loadSoundModel(soundModel, handle);
+                if (status != SoundTrigger.STATUS_OK) {
+                    Slog.w(TAG, "loadSoundModel call failed with " + status);
+                    return status;
+                }
+                if (handle[0] == INVALID_VALUE) {
+                    Slog.w(TAG, "loadSoundModel call returned invalid sound model handle");
+                    return STATUS_ERROR;
+                }
+                soundModelHandle = handle[0];
+            } else {
+                if (DBG) Slog.d(TAG, "Reusing previously loaded sound model");
+            }
+
+            // Start the recognition.
+            mRequested = true;
+            mKeyphraseId = keyphraseId;
+            mCurrentSoundModelHandle = soundModelHandle;
+            mCurrentSoundModel = soundModel;
+            mRecognitionConfig = recognitionConfig;
+            // Register the new listener. This replaces the old one.
+            // There can only be a maximum of one active listener at any given time.
+            mActiveListener = listener;
+
+            return updateRecognitionLocked(false /* don't notify for synchronous calls */);
+        }
+    }
+
+    /**
+     * Stops recognition for the given {@link Keyphrase} if a recognition is
+     * currently active.
+     *
+     * @param keyphraseId The identifier of the keyphrase for which
+     *        the recognition is to be stopped.
+     * @param listener The listener for the recognition events related to the given keyphrase.
+     *
+     * @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
+     */
+    int stopRecognition(int keyphraseId, IRecognitionStatusCallback listener) {
+        if (listener == null) {
+            return STATUS_ERROR;
+        }
+
+        synchronized (mLock) {
+            if (DBG) {
+                Slog.d(TAG, "stopRecognition for keyphraseId=" + keyphraseId
+                        + ", listener=" + listener.asBinder());
+                Slog.d(TAG, "current listener="
+                        + (mActiveListener == null ? "null" : mActiveListener.asBinder()));
+            }
+
+            if (moduleProperties == null || mModule == null) {
+                Slog.w(TAG, "Attempting stopRecognition without the capability");
+                return STATUS_ERROR;
+            }
+
+            if (mActiveListener == null) {
+                // startRecognition hasn't been called or it failed.
+                Slog.w(TAG, "Attempting stopRecognition without a successful startRecognition");
+                return STATUS_ERROR;
+            }
+            if (mActiveListener.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");
+                return STATUS_ERROR;
+            }
+
+            // Stop recognition if it's the current one, ignore otherwise.
+            mRequested = false;
+            int status = updateRecognitionLocked(false /* don't notify for synchronous calls */);
+            if (status != SoundTrigger.STATUS_OK) {
+                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.
+            internalClearStateLocked();
+            return status;
+        }
+    }
+
+    /**
+     * Stops all recognitions active currently and clears the internal state.
+     */
+    void stopAllRecognitions() {
+        synchronized (mLock) {
+            if (moduleProperties == null || mModule == null) {
+                return;
+            }
+
+            if (mCurrentSoundModelHandle == INVALID_VALUE) {
+                return;
+            }
+
+            mRequested = false;
+            int status = updateRecognitionLocked(false /* don't notify for synchronous calls */);
+            internalClearStateLocked();
+        }
+    }
+
+    //---- SoundTrigger.StatusListener methods
+    @Override
+    public void onRecognition(RecognitionEvent event) {
+        if (event == null || !(event instanceof KeyphraseRecognitionEvent)) {
+            Slog.w(TAG, "Invalid recognition event!");
+            return;
+        }
+
+        if (DBG) Slog.d(TAG, "onRecognition: " + event);
+        synchronized (mLock) {
+            if (mActiveListener == null) {
+                Slog.w(TAG, "received onRecognition event without any listener for it");
+                return;
+            }
+            switch (event.status) {
+                // Fire aborts/failures to all listeners since it's not tied to a keyphrase.
+                case SoundTrigger.RECOGNITION_STATUS_ABORT:
+                    onRecognitionAbortLocked();
+                    break;
+                case SoundTrigger.RECOGNITION_STATUS_FAILURE:
+                    onRecognitionFailureLocked();
+                    break;
+                case SoundTrigger.RECOGNITION_STATUS_SUCCESS:
+                    onRecognitionSuccessLocked((KeyphraseRecognitionEvent) event);
+                    break;
+            }
+        }
+    }
+
+    @Override
+    public void onSoundModelUpdate(SoundModelEvent event) {
+        if (event == null) {
+            Slog.w(TAG, "Invalid sound model event!");
+            return;
+        }
+        if (DBG) Slog.d(TAG, "onSoundModelUpdate: " + event);
+        synchronized (mLock) {
+            onSoundModelUpdatedLocked(event);
+        }
+    }
+
+    @Override
+    public void onServiceStateChange(int state) {
+        if (DBG) Slog.d(TAG, "onServiceStateChange, state: " + state);
+        synchronized (mLock) {
+            onServiceStateChangedLocked(SoundTrigger.SERVICE_STATE_DISABLED == state);
+        }
+    }
+
+    @Override
+    public void onServiceDied() {
+        Slog.e(TAG, "onServiceDied!!");
+        synchronized (mLock) {
+            onServiceDiedLocked();
+        }
+    }
+
+    private void onCallStateChangedLocked(boolean callActive) {
+        if (mCallActive == callActive) {
+            // We consider multiple call states as being active
+            // so we check if something really changed or not here.
+            return;
+        }
+        mCallActive = callActive;
+        updateRecognitionLocked(true /* notify */);
+    }
+
+    private void onPowerSaveModeChangedLocked(boolean isPowerSaveMode) {
+        if (mIsPowerSaveMode == isPowerSaveMode) {
+            return;
+        }
+        mIsPowerSaveMode = isPowerSaveMode;
+        updateRecognitionLocked(true /* notify */);
+    }
+
+    private void onSoundModelUpdatedLocked(SoundModelEvent event) {
+        // TODO: Handle sound model update here.
+    }
+
+    private void onServiceStateChangedLocked(boolean disabled) {
+        if (disabled == mServiceDisabled) {
+            return;
+        }
+        mServiceDisabled = disabled;
+        updateRecognitionLocked(true /* notify */);
+    }
+
+    private void onRecognitionAbortLocked() {
+        Slog.w(TAG, "Recognition aborted");
+        // If abort has been called, the hardware has already stopped recognition, so we shouldn't
+        // call it again when we process the state change.
+        mRecognitionAborted = true;
+    }
+
+    private void onRecognitionFailureLocked() {
+        Slog.w(TAG, "Recognition failure");
+        try {
+            if (mActiveListener != null) {
+                mActiveListener.onError(STATUS_ERROR);
+            }
+        } catch (RemoteException e) {
+            Slog.w(TAG, "RemoteException in onError", e);
+        } finally {
+            internalClearStateLocked();
+        }
+    }
+
+    private void onRecognitionSuccessLocked(KeyphraseRecognitionEvent event) {
+        Slog.i(TAG, "Recognition success");
+        KeyphraseRecognitionExtra[] keyphraseExtras =
+                ((KeyphraseRecognitionEvent) event).keyphraseExtras;
+        if (keyphraseExtras == null || keyphraseExtras.length == 0) {
+            Slog.w(TAG, "Invalid keyphrase recognition event!");
+            return;
+        }
+        // TODO: Handle more than one keyphrase extras.
+        if (mKeyphraseId != keyphraseExtras[0].id) {
+            Slog.w(TAG, "received onRecognition event for a different keyphrase");
+            return;
+        }
+
+        try {
+            if (mActiveListener != null) {
+                mActiveListener.onDetected((KeyphraseRecognitionEvent) event);
+            }
+        } catch (RemoteException e) {
+            Slog.w(TAG, "RemoteException in onDetected", e);
+        }
+
+        mStarted = false;
+        mRequested = mRecognitionConfig.allowMultipleTriggers;
+        // TODO: Remove this block if the lower layer supports multiple triggers.
+        if (mRequested) {
+            updateRecognitionLocked(true /* notify */);
+        }
+    }
+
+    private void onServiceDiedLocked() {
+        try {
+            if (mActiveListener != null) {
+                mActiveListener.onError(SoundTrigger.STATUS_DEAD_OBJECT);
+            }
+        } catch (RemoteException e) {
+            Slog.w(TAG, "RemoteException in onError", e);
+        } finally {
+            internalClearSoundModelLocked();
+            internalClearStateLocked();
+            if (mModule != null) {
+                mModule.detach();
+                mModule = null;
+            }
+        }
+    }
+
+    private int updateRecognitionLocked(boolean notify) {
+        if (mModule == null || moduleProperties == null
+                || mCurrentSoundModelHandle == INVALID_VALUE || mActiveListener == null) {
+            // Nothing to do here.
+            return STATUS_OK;
+        }
+
+        boolean start = mRequested && !mCallActive && !mServiceDisabled && !mIsPowerSaveMode;
+        if (start == mStarted) {
+            // No-op.
+            return STATUS_OK;
+        }
+
+        // See if the recognition needs to be started.
+        if (start) {
+            // Start recognition.
+            int status = mModule.startRecognition(mCurrentSoundModelHandle, mRecognitionConfig);
+            if (status != SoundTrigger.STATUS_OK) {
+                Slog.w(TAG, "startRecognition failed with " + status);
+                // Notify of error if needed.
+                if (notify) {
+                    try {
+                        mActiveListener.onError(status);
+                    } catch (RemoteException e) {
+                        Slog.w(TAG, "RemoteException in onError", e);
+                    }
+                }
+            } else {
+                mStarted = true;
+                // Notify of resume if needed.
+                if (notify) {
+                    try {
+                        mActiveListener.onRecognitionResumed();
+                    } catch (RemoteException e) {
+                        Slog.w(TAG, "RemoteException in onRecognitionResumed", e);
+                    }
+                }
+            }
+            return status;
+        } else {
+            // Stop recognition (only if we haven't been aborted).
+            int status = STATUS_OK;
+            if (!mRecognitionAborted) {
+                status = mModule.stopRecognition(mCurrentSoundModelHandle);
+            } else {
+                mRecognitionAborted = false;
+            }
+            if (status != SoundTrigger.STATUS_OK) {
+                Slog.w(TAG, "stopRecognition call failed with " + status);
+                if (notify) {
+                    try {
+                        mActiveListener.onError(status);
+                    } catch (RemoteException e) {
+                        Slog.w(TAG, "RemoteException in onError", e);
+                    }
+                }
+            } else {
+                mStarted = false;
+                // Notify of pause if needed.
+                if (notify) {
+                    try {
+                        mActiveListener.onRecognitionPaused();
+                    } catch (RemoteException e) {
+                        Slog.w(TAG, "RemoteException in onRecognitionPaused", e);
+                    }
+                }
+            }
+            return status;
+        }
+    }
+
+    private void internalClearStateLocked() {
+        mStarted = false;
+        mRequested = false;
+
+        mKeyphraseId = INVALID_VALUE;
+        mRecognitionConfig = null;
+        mActiveListener = null;
+
+        // Unregister from call state changes.
+        mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+
+        // Unregister from power save mode changes.
+        if (mPowerSaveModeListener != null) {
+            mContext.unregisterReceiver(mPowerSaveModeListener);
+            mPowerSaveModeListener = null;
+        }
+    }
+
+    private void internalClearSoundModelLocked() {
+        mCurrentSoundModelHandle = INVALID_VALUE;
+        mCurrentSoundModel = null;
+    }
+
+    class MyCallStateListener extends PhoneStateListener {
+        @Override
+        public void onCallStateChanged(int state, String arg1) {
+            if (DBG) Slog.d(TAG, "onCallStateChanged: " + state);
+            synchronized (mLock) {
+                onCallStateChangedLocked(TelephonyManager.CALL_STATE_IDLE != state);
+            }
+        }
+    }
+
+    class PowerSaveModeListener extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (!PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())) {
+                return;
+            }
+            boolean active = mPowerManager.isPowerSaveMode();
+            if (DBG) Slog.d(TAG, "onPowerSaveModeChanged: " + active);
+            synchronized (mLock) {
+                onPowerSaveModeChangedLocked(active);
+            }
+        }
+    }
+
+    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        synchronized (mLock) {
+            pw.print("  module properties=");
+            pw.println(moduleProperties == null ? "null" : moduleProperties);
+            pw.print("  keyphrase ID="); pw.println(mKeyphraseId);
+            pw.print("  sound model handle="); pw.println(mCurrentSoundModelHandle);
+            pw.print("  sound model UUID=");
+            pw.println(mCurrentSoundModel == null ? "null" : mCurrentSoundModel.uuid);
+            pw.print("  current listener=");
+            pw.println(mActiveListener == null ? "null" : mActiveListener.asBinder());
+
+            pw.print("  requested="); pw.println(mRequested);
+            pw.print("  started="); pw.println(mStarted);
+            pw.print("  call active="); pw.println(mCallActive);
+            pw.print("  power save mode active="); pw.println(mIsPowerSaveMode);
+            pw.print("  service disabled="); pw.println(mServiceDisabled);
+        }
+    }
+}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
new file mode 100644
index 0000000..0a06bfa
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
@@ -0,0 +1,84 @@
+/**
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.soundtrigger;
+
+import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.SoundTrigger;
+import android.hardware.soundtrigger.SoundTrigger.Keyphrase;
+import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionEvent;
+import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra;
+import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
+import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
+import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
+import android.hardware.soundtrigger.SoundTrigger.SoundModelEvent;
+import android.hardware.soundtrigger.SoundTriggerModule;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Provides a local service for managing voice-related recoginition models. This is primarily used
+ * by the {@link VoiceInteractionManagerService}.
+ */
+public abstract class SoundTriggerInternal {
+    /**
+     * Return codes for {@link #startRecognition(int, KeyphraseSoundModel,
+     *      IRecognitionStatusCallback, RecognitionConfig)},
+     * {@link #stopRecognition(int, IRecognitionStatusCallback)}
+     */
+    public static final int STATUS_ERROR = SoundTrigger.STATUS_ERROR;
+    public static final int STATUS_OK = SoundTrigger.STATUS_OK;
+
+    /** The {@link ModuleProperties} for the system, or null if none exists. */
+    private ModuleProperties moduleProperties;
+
+    /**
+     * Starts recognition for the given keyphraseId.
+     *
+     * @param keyphraseId The identifier of the keyphrase for which
+     *        the recognition is to be started.
+     * @param soundModel The sound model to use for recognition.
+     * @param listener The listener for the recognition events related to the given keyphrase.
+     * @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
+     */
+    public abstract int startRecognition(int keyphraseId, KeyphraseSoundModel soundModel,
+            IRecognitionStatusCallback listener, RecognitionConfig recognitionConfig);
+
+    /**
+     * Stops recognition for the given {@link Keyphrase} if a recognition is
+     * currently active.
+     *
+     * @param keyphraseId The identifier of the keyphrase for which
+     *        the recognition is to be stopped.
+     * @param listener The listener for the recognition events related to the given keyphrase.
+     *
+     * @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
+     */
+    public abstract int stopRecognition(int keyphraseId, IRecognitionStatusCallback listener);
+
+    /**
+     * Stops all recognitions active currently and clears the internal state.
+     */
+    public abstract void stopAllRecognitions();
+
+    public ModuleProperties getModuleProperties() {
+        return moduleProperties;
+    }
+
+    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
new file mode 100644
index 0000000..5e8fe9e
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.soundtrigger;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.Manifest;
+import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.SoundTrigger;
+import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
+import android.os.Parcel;
+import android.os.ParcelUuid;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.SystemService;
+import com.android.internal.app.ISoundTriggerService;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.UUID;
+
+/**
+ * A single SystemService to manage all sound/voice-based sound models on the DSP.
+ * This services provides apis to manage sound trigger-based sound models via
+ * the ISoundTriggerService interface. This class also publishes a local interface encapsulating
+ * the functionality provided by {@link SoundTriggerHelper} for use by
+ * {@link VoiceInteractionManagerService}.
+ *
+ * @hide
+ */
+public class SoundTriggerService extends SystemService {
+    static final String TAG = "SoundTriggerService";
+    static final boolean DEBUG = false;
+
+    final Context mContext;
+    private final SoundTriggerServiceStub mServiceStub;
+    private final LocalSoundTriggerService mLocalSoundTriggerService;
+    private SoundTriggerDbHelper mDbHelper;
+
+    public SoundTriggerService(Context context) {
+        super(context);
+        mContext = context;
+        mServiceStub = new SoundTriggerServiceStub();
+        mLocalSoundTriggerService = new LocalSoundTriggerService(context);
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(Context.SOUND_TRIGGER_SERVICE, mServiceStub);
+        publishLocalService(SoundTriggerInternal.class, mLocalSoundTriggerService);
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (PHASE_SYSTEM_SERVICES_READY == phase) {
+            mLocalSoundTriggerService.initSoundTriggerHelper();
+        } else if (PHASE_THIRD_PARTY_APPS_CAN_START == phase) {
+            mDbHelper = new SoundTriggerDbHelper(mContext);
+        }
+    }
+
+    @Override
+    public void onStartUser(int userHandle) {
+    }
+
+    @Override
+    public void onSwitchUser(int userHandle) {
+    }
+
+    class SoundTriggerServiceStub extends ISoundTriggerService.Stub {
+        @Override
+        public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+                throws RemoteException {
+            try {
+                return super.onTransact(code, data, reply, flags);
+            } catch (RuntimeException e) {
+                // The activity manager only throws security exceptions, so let's
+                // log all others.
+                if (!(e instanceof SecurityException)) {
+                    Slog.wtf(TAG, "SoundTriggerService Crash", e);
+                }
+                throw e;
+            }
+        }
+
+        @Override
+        public void startRecognition(ParcelUuid parcelUuid, IRecognitionStatusCallback callback) {
+            enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+            if (DEBUG) {
+                Slog.i(TAG, "startRecognition(): Uuid : " + parcelUuid);
+            }
+        }
+
+        @Override
+        public void stopRecognition(ParcelUuid parcelUuid, IRecognitionStatusCallback callback) {
+            enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+            if (DEBUG) {
+                Slog.i(TAG, "stopRecognition(): Uuid : " + parcelUuid);
+            }
+        }
+
+        @Override
+        public SoundTrigger.GenericSoundModel getSoundModel(ParcelUuid soundModelId) {
+            enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+            if (DEBUG) {
+                Slog.i(TAG, "getSoundModel(): id = " + soundModelId);
+            }
+            SoundTrigger.GenericSoundModel model = mDbHelper.getGenericSoundModel(soundModelId.getUuid());
+            if (model == null) {
+                Slog.e(TAG, "Null model in database.");
+            }
+            return model;
+        }
+
+        @Override
+        public void updateSoundModel(SoundTrigger.GenericSoundModel soundModel) {
+            enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+            if (DEBUG) {
+                Slog.i(TAG, "updateSoundModel(): model = " + soundModel);
+            }
+            mDbHelper.updateGenericSoundModel(soundModel);
+        }
+
+        @Override
+        public void deleteSoundModel(ParcelUuid soundModelId) {
+            enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+            if (DEBUG) {
+                Slog.i(TAG, "deleteSoundModel(): id = " + soundModelId);
+            }
+            mDbHelper.deleteGenericSoundModel(soundModelId.getUuid());
+        }
+    }
+
+    public final class LocalSoundTriggerService extends SoundTriggerInternal {
+        private final Context mContext;
+        private SoundTriggerHelper mSoundTriggerHelper;
+
+        LocalSoundTriggerService(Context context) {
+            mContext = context;
+        }
+
+        void initSoundTriggerHelper() {
+            if (mSoundTriggerHelper == null) {
+                mSoundTriggerHelper = new SoundTriggerHelper(mContext);
+            }
+        }
+
+        @Override
+        public int startRecognition(int keyphraseId, KeyphraseSoundModel soundModel,
+                IRecognitionStatusCallback listener, RecognitionConfig recognitionConfig) {
+            return mSoundTriggerHelper.startRecognition(keyphraseId, soundModel, listener,
+                    recognitionConfig);
+        }
+
+        @Override
+        public int stopRecognition(int keyphraseId, IRecognitionStatusCallback listener) {
+            return mSoundTriggerHelper.stopRecognition(keyphraseId, listener);
+        }
+
+        @Override
+        public void stopAllRecognitions() {
+            mSoundTriggerHelper.stopAllRecognitions();
+        }
+
+        @Override
+        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            mSoundTriggerHelper.dump(fd, pw, args);
+        }
+    }
+
+    private void enforceCallingPermission(String permission) {
+        if (mContext.checkCallingOrSelfPermission(permission)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Caller does not hold the permission " + permission);
+        }
+    }
+}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
deleted file mode 100644
index 31d859f..0000000
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
+++ /dev/null
@@ -1,591 +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.voiceinteraction;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.hardware.soundtrigger.IRecognitionStatusCallback;
-import android.hardware.soundtrigger.SoundTrigger;
-import android.hardware.soundtrigger.SoundTrigger.Keyphrase;
-import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionEvent;
-import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra;
-import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
-import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
-import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
-import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
-import android.hardware.soundtrigger.SoundTrigger.SoundModelEvent;
-import android.hardware.soundtrigger.SoundTriggerModule;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.telephony.PhoneStateListener;
-import android.telephony.TelephonyManager;
-import android.util.Slog;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
-/**
- * Helper for {@link SoundTrigger} APIs.
- * Currently this just acts as an abstraction over all SoundTrigger API calls.
- *
- * @hide
- */
-public class SoundTriggerHelper implements SoundTrigger.StatusListener {
-    static final String TAG = "SoundTriggerHelper";
-    static final boolean DBG = false;
-
-    /**
-     * Return codes for {@link #startRecognition(int, KeyphraseSoundModel,
-     *      IRecognitionStatusCallback, RecognitionConfig)},
-     * {@link #stopRecognition(int, IRecognitionStatusCallback)}
-     */
-    public static final int STATUS_ERROR = SoundTrigger.STATUS_ERROR;
-    public static final int STATUS_OK = SoundTrigger.STATUS_OK;
-
-    private static final int INVALID_VALUE = Integer.MIN_VALUE;
-
-    /** The {@link ModuleProperties} for the system, or null if none exists. */
-    final ModuleProperties moduleProperties;
-
-    /** The properties for the DSP module */
-    private SoundTriggerModule mModule;
-    private final Object mLock = new Object();
-    private final Context mContext;
-    private final TelephonyManager mTelephonyManager;
-    private final PhoneStateListener mPhoneStateListener;
-    private final PowerManager mPowerManager;
-
-    // TODO: Since many layers currently only deal with one recognition
-    // we simplify things by assuming one listener here too.
-    private IRecognitionStatusCallback mActiveListener;
-    private int mKeyphraseId = INVALID_VALUE;
-    private int mCurrentSoundModelHandle = INVALID_VALUE;
-    private KeyphraseSoundModel mCurrentSoundModel = null;
-    // FIXME: Ideally this should not be stored if allowMultipleTriggers happens at a lower layer.
-    private RecognitionConfig mRecognitionConfig = null;
-    private boolean mRequested = false;
-    private boolean mCallActive = false;
-    private boolean mIsPowerSaveMode = false;
-    // Indicates if the native sound trigger service is disabled or not.
-    // This is an indirect indication of the microphone being open in some other application.
-    private boolean mServiceDisabled = false;
-    private boolean mStarted = false;
-    private boolean mRecognitionAborted = false;
-    private PowerSaveModeListener mPowerSaveModeListener;
-
-    SoundTriggerHelper(Context context) {
-        ArrayList <ModuleProperties> modules = new ArrayList<>();
-        int status = SoundTrigger.listModules(modules);
-        mContext = context;
-        mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
-        mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-        mPhoneStateListener = new MyCallStateListener();
-        if (status != SoundTrigger.STATUS_OK || modules.size() == 0) {
-            Slog.w(TAG, "listModules status=" + status + ", # of modules=" + modules.size());
-            moduleProperties = null;
-            mModule = null;
-        } else {
-            // TODO: Figure out how to determine which module corresponds to the DSP hardware.
-            moduleProperties = modules.get(0);
-        }
-    }
-
-    /**
-     * Starts recognition for the given keyphraseId.
-     *
-     * @param keyphraseId The identifier of the keyphrase for which
-     *        the recognition is to be started.
-     * @param soundModel The sound model to use for recognition.
-     * @param listener The listener for the recognition events related to the given keyphrase.
-     * @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
-     */
-    int startRecognition(int keyphraseId,
-            KeyphraseSoundModel soundModel,
-            IRecognitionStatusCallback listener,
-            RecognitionConfig recognitionConfig) {
-        if (soundModel == null || listener == null || recognitionConfig == null) {
-            return STATUS_ERROR;
-        }
-
-        synchronized (mLock) {
-            if (DBG) {
-                Slog.d(TAG, "startRecognition for keyphraseId=" + keyphraseId
-                        + " soundModel=" + soundModel + ", listener=" + listener.asBinder()
-                        + ", recognitionConfig=" + recognitionConfig);
-                Slog.d(TAG, "moduleProperties=" + moduleProperties);
-                Slog.d(TAG, "current listener="
-                        + (mActiveListener == null ? "null" : mActiveListener.asBinder()));
-                Slog.d(TAG, "current SoundModel handle=" + mCurrentSoundModelHandle);
-                Slog.d(TAG, "current SoundModel UUID="
-                        + (mCurrentSoundModel == null ? null : mCurrentSoundModel.uuid));
-            }
-
-            if (!mStarted) {
-                // Get the current call state synchronously for the first recognition.
-                mCallActive = mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE;
-                // Register for call state changes when the first call to start recognition occurs.
-                mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
-
-                // Register for power saver mode changes when the first call to start recognition
-                // occurs.
-                if (mPowerSaveModeListener == null) {
-                    mPowerSaveModeListener = new PowerSaveModeListener();
-                    mContext.registerReceiver(mPowerSaveModeListener,
-                            new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
-                }
-                mIsPowerSaveMode = mPowerManager.isPowerSaveMode();
-            }
-
-            if (moduleProperties == null) {
-                Slog.w(TAG, "Attempting startRecognition without the capability");
-                return STATUS_ERROR;
-            }
-            if (mModule == null) {
-                mModule = SoundTrigger.attachModule(moduleProperties.id, this, null);
-                if (mModule == null) {
-                    Slog.w(TAG, "startRecognition cannot attach to sound trigger module");
-                    return STATUS_ERROR;
-                }
-            }
-
-            // Unload the previous model if the current one isn't invalid
-            // and, it's not the same as the new one.
-            // This helps use cache and reuse the model and just start/stop it when necessary.
-            if (mCurrentSoundModelHandle != INVALID_VALUE
-                    && !soundModel.equals(mCurrentSoundModel)) {
-                Slog.w(TAG, "Unloading previous sound model");
-                int status = mModule.unloadSoundModel(mCurrentSoundModelHandle);
-                if (status != SoundTrigger.STATUS_OK) {
-                    Slog.w(TAG, "unloadSoundModel call failed with " + status);
-                }
-                internalClearSoundModelLocked();
-                mStarted = false;
-            }
-
-            // If the previous recognition was by a different listener,
-            // Notify them that it was stopped.
-            if (mActiveListener != null && mActiveListener.asBinder() != listener.asBinder()) {
-                Slog.w(TAG, "Canceling previous recognition");
-                try {
-                    mActiveListener.onError(STATUS_ERROR);
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "RemoteException in onDetectionStopped", e);
-                }
-                mActiveListener = null;
-            }
-
-            // Load the sound model if the current one is null.
-            int soundModelHandle = mCurrentSoundModelHandle;
-            if (mCurrentSoundModelHandle == INVALID_VALUE
-                    || mCurrentSoundModel == null) {
-                int[] handle = new int[] { INVALID_VALUE };
-                int status = mModule.loadSoundModel(soundModel, handle);
-                if (status != SoundTrigger.STATUS_OK) {
-                    Slog.w(TAG, "loadSoundModel call failed with " + status);
-                    return status;
-                }
-                if (handle[0] == INVALID_VALUE) {
-                    Slog.w(TAG, "loadSoundModel call returned invalid sound model handle");
-                    return STATUS_ERROR;
-                }
-                soundModelHandle = handle[0];
-            } else {
-                if (DBG) Slog.d(TAG, "Reusing previously loaded sound model");
-            }
-
-            // Start the recognition.
-            mRequested = true;
-            mKeyphraseId = keyphraseId;
-            mCurrentSoundModelHandle = soundModelHandle;
-            mCurrentSoundModel = soundModel;
-            mRecognitionConfig = recognitionConfig;
-            // Register the new listener. This replaces the old one.
-            // There can only be a maximum of one active listener at any given time.
-            mActiveListener = listener;
-
-            return updateRecognitionLocked(false /* don't notify for synchronous calls */);
-        }
-    }
-
-    /**
-     * Stops recognition for the given {@link Keyphrase} if a recognition is
-     * currently active.
-     *
-     * @param keyphraseId The identifier of the keyphrase for which
-     *        the recognition is to be stopped.
-     * @param listener The listener for the recognition events related to the given keyphrase.
-     *
-     * @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
-     */
-    int stopRecognition(int keyphraseId, IRecognitionStatusCallback listener) {
-        if (listener == null) {
-            return STATUS_ERROR;
-        }
-
-        synchronized (mLock) {
-            if (DBG) {
-                Slog.d(TAG, "stopRecognition for keyphraseId=" + keyphraseId
-                        + ", listener=" + listener.asBinder());
-                Slog.d(TAG, "current listener="
-                        + (mActiveListener == null ? "null" : mActiveListener.asBinder()));
-            }
-
-            if (moduleProperties == null || mModule == null) {
-                Slog.w(TAG, "Attempting stopRecognition without the capability");
-                return STATUS_ERROR;
-            }
-
-            if (mActiveListener == null) {
-                // startRecognition hasn't been called or it failed.
-                Slog.w(TAG, "Attempting stopRecognition without a successful startRecognition");
-                return STATUS_ERROR;
-            }
-            if (mActiveListener.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");
-                return STATUS_ERROR;
-            }
-
-            // Stop recognition if it's the current one, ignore otherwise.
-            mRequested = false;
-            int status = updateRecognitionLocked(false /* don't notify for synchronous calls */);
-            if (status != SoundTrigger.STATUS_OK) {
-                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.
-            internalClearStateLocked();
-            return status;
-        }
-    }
-
-    /**
-     * Stops all recognitions active currently and clears the internal state.
-     */
-    void stopAllRecognitions() {
-        synchronized (mLock) {
-            if (moduleProperties == null || mModule == null) {
-                return;
-            }
-
-            if (mCurrentSoundModelHandle == INVALID_VALUE) {
-                return;
-            }
-
-            mRequested = false;
-            int status = updateRecognitionLocked(false /* don't notify for synchronous calls */);
-            internalClearStateLocked();
-        }
-    }
-
-    //---- SoundTrigger.StatusListener methods
-    @Override
-    public void onRecognition(RecognitionEvent event) {
-        if (event == null || !(event instanceof KeyphraseRecognitionEvent)) {
-            Slog.w(TAG, "Invalid recognition event!");
-            return;
-        }
-
-        if (DBG) Slog.d(TAG, "onRecognition: " + event);
-        synchronized (mLock) {
-            if (mActiveListener == null) {
-                Slog.w(TAG, "received onRecognition event without any listener for it");
-                return;
-            }
-            switch (event.status) {
-                // Fire aborts/failures to all listeners since it's not tied to a keyphrase.
-                case SoundTrigger.RECOGNITION_STATUS_ABORT:
-                    onRecognitionAbortLocked();
-                    break;
-                case SoundTrigger.RECOGNITION_STATUS_FAILURE:
-                    onRecognitionFailureLocked();
-                    break;
-                case SoundTrigger.RECOGNITION_STATUS_SUCCESS:
-                    onRecognitionSuccessLocked((KeyphraseRecognitionEvent) event);
-                    break;
-            }
-        }
-    }
-
-    @Override
-    public void onSoundModelUpdate(SoundModelEvent event) {
-        if (event == null) {
-            Slog.w(TAG, "Invalid sound model event!");
-            return;
-        }
-        if (DBG) Slog.d(TAG, "onSoundModelUpdate: " + event);
-        synchronized (mLock) {
-            onSoundModelUpdatedLocked(event);
-        }
-    }
-
-    @Override
-    public void onServiceStateChange(int state) {
-        if (DBG) Slog.d(TAG, "onServiceStateChange, state: " + state);
-        synchronized (mLock) {
-            onServiceStateChangedLocked(SoundTrigger.SERVICE_STATE_DISABLED == state);
-        }
-    }
-
-    @Override
-    public void onServiceDied() {
-        Slog.e(TAG, "onServiceDied!!");
-        synchronized (mLock) {
-            onServiceDiedLocked();
-        }
-    }
-
-    private void onCallStateChangedLocked(boolean callActive) {
-        if (mCallActive == callActive) {
-            // We consider multiple call states as being active
-            // so we check if something really changed or not here.
-            return;
-        }
-        mCallActive = callActive;
-        updateRecognitionLocked(true /* notify */);
-    }
-
-    private void onPowerSaveModeChangedLocked(boolean isPowerSaveMode) {
-        if (mIsPowerSaveMode == isPowerSaveMode) {
-            return;
-        }
-        mIsPowerSaveMode = isPowerSaveMode;
-        updateRecognitionLocked(true /* notify */);
-    }
-
-    private void onSoundModelUpdatedLocked(SoundModelEvent event) {
-        // TODO: Handle sound model update here.
-    }
-
-    private void onServiceStateChangedLocked(boolean disabled) {
-        if (disabled == mServiceDisabled) {
-            return;
-        }
-        mServiceDisabled = disabled;
-        updateRecognitionLocked(true /* notify */);
-    }
-
-    private void onRecognitionAbortLocked() {
-        Slog.w(TAG, "Recognition aborted");
-        // If abort has been called, the hardware has already stopped recognition, so we shouldn't
-        // call it again when we process the state change.
-        mRecognitionAborted = true;
-    }
-
-    private void onRecognitionFailureLocked() {
-        Slog.w(TAG, "Recognition failure");
-        try {
-            if (mActiveListener != null) {
-                mActiveListener.onError(STATUS_ERROR);
-            }
-        } catch (RemoteException e) {
-            Slog.w(TAG, "RemoteException in onError", e);
-        } finally {
-            internalClearStateLocked();
-        }
-    }
-
-    private void onRecognitionSuccessLocked(KeyphraseRecognitionEvent event) {
-        Slog.i(TAG, "Recognition success");
-        KeyphraseRecognitionExtra[] keyphraseExtras =
-                ((KeyphraseRecognitionEvent) event).keyphraseExtras;
-        if (keyphraseExtras == null || keyphraseExtras.length == 0) {
-            Slog.w(TAG, "Invalid keyphrase recognition event!");
-            return;
-        }
-        // TODO: Handle more than one keyphrase extras.
-        if (mKeyphraseId != keyphraseExtras[0].id) {
-            Slog.w(TAG, "received onRecognition event for a different keyphrase");
-            return;
-        }
-
-        try {
-            if (mActiveListener != null) {
-                mActiveListener.onDetected((KeyphraseRecognitionEvent) event);
-            }
-        } catch (RemoteException e) {
-            Slog.w(TAG, "RemoteException in onDetected", e);
-        }
-
-        mStarted = false;
-        mRequested = mRecognitionConfig.allowMultipleTriggers;
-        // TODO: Remove this block if the lower layer supports multiple triggers.
-        if (mRequested) {
-            updateRecognitionLocked(true /* notify */);
-        }
-    }
-
-    private void onServiceDiedLocked() {
-        try {
-            if (mActiveListener != null) {
-                mActiveListener.onError(SoundTrigger.STATUS_DEAD_OBJECT);
-            }
-        } catch (RemoteException e) {
-            Slog.w(TAG, "RemoteException in onError", e);
-        } finally {
-            internalClearSoundModelLocked();
-            internalClearStateLocked();
-            if (mModule != null) {
-                mModule.detach();
-                mModule = null;
-            }
-        }
-    }
-
-    private int updateRecognitionLocked(boolean notify) {
-        if (mModule == null || moduleProperties == null
-                || mCurrentSoundModelHandle == INVALID_VALUE || mActiveListener == null) {
-            // Nothing to do here.
-            return STATUS_OK;
-        }
-
-        boolean start = mRequested && !mCallActive && !mServiceDisabled && !mIsPowerSaveMode;
-        if (start == mStarted) {
-            // No-op.
-            return STATUS_OK;
-        }
-
-        // See if the recognition needs to be started.
-        if (start) {
-            // Start recognition.
-            int status = mModule.startRecognition(mCurrentSoundModelHandle, mRecognitionConfig);
-            if (status != SoundTrigger.STATUS_OK) {
-                Slog.w(TAG, "startRecognition failed with " + status);
-                // Notify of error if needed.
-                if (notify) {
-                    try {
-                        mActiveListener.onError(status);
-                    } catch (RemoteException e) {
-                        Slog.w(TAG, "RemoteException in onError", e);
-                    }
-                }
-            } else {
-                mStarted = true;
-                // Notify of resume if needed.
-                if (notify) {
-                    try {
-                        mActiveListener.onRecognitionResumed();
-                    } catch (RemoteException e) {
-                        Slog.w(TAG, "RemoteException in onRecognitionResumed", e);
-                    }
-                }
-            }
-            return status;
-        } else {
-            // Stop recognition (only if we haven't been aborted).
-            int status = STATUS_OK;
-            if (!mRecognitionAborted) {
-                status = mModule.stopRecognition(mCurrentSoundModelHandle);
-            } else {
-                mRecognitionAborted = false;
-            }
-            if (status != SoundTrigger.STATUS_OK) {
-                Slog.w(TAG, "stopRecognition call failed with " + status);
-                if (notify) {
-                    try {
-                        mActiveListener.onError(status);
-                    } catch (RemoteException e) {
-                        Slog.w(TAG, "RemoteException in onError", e);
-                    }
-                }
-            } else {
-                mStarted = false;
-                // Notify of pause if needed.
-                if (notify) {
-                    try {
-                        mActiveListener.onRecognitionPaused();
-                    } catch (RemoteException e) {
-                        Slog.w(TAG, "RemoteException in onRecognitionPaused", e);
-                    }
-                }
-            }
-            return status;
-        }
-    }
-
-    private void internalClearStateLocked() {
-        mStarted = false;
-        mRequested = false;
-
-        mKeyphraseId = INVALID_VALUE;
-        mRecognitionConfig = null;
-        mActiveListener = null;
-
-        // Unregister from call state changes.
-        mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
-
-        // Unregister from power save mode changes.
-        if (mPowerSaveModeListener != null) {
-            mContext.unregisterReceiver(mPowerSaveModeListener);
-            mPowerSaveModeListener = null;
-        }
-    }
-
-    private void internalClearSoundModelLocked() {
-        mCurrentSoundModelHandle = INVALID_VALUE;
-        mCurrentSoundModel = null;
-    }
-
-    class MyCallStateListener extends PhoneStateListener {
-        @Override
-        public void onCallStateChanged(int state, String arg1) {
-            if (DBG) Slog.d(TAG, "onCallStateChanged: " + state);
-            synchronized (mLock) {
-                onCallStateChangedLocked(TelephonyManager.CALL_STATE_IDLE != state);
-            }
-        }
-    }
-
-    class PowerSaveModeListener extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (!PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())) {
-                return;
-            }
-            boolean active = mPowerManager.isPowerSaveMode();
-            if (DBG) Slog.d(TAG, "onPowerSaveModeChanged: " + active);
-            synchronized (mLock) {
-                onPowerSaveModeChangedLocked(active);
-            }
-        }
-    }
-
-    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        synchronized (mLock) {
-            pw.print("  module properties=");
-            pw.println(moduleProperties == null ? "null" : moduleProperties);
-            pw.print("  keyphrase ID="); pw.println(mKeyphraseId);
-            pw.print("  sound model handle="); pw.println(mCurrentSoundModelHandle);
-            pw.print("  sound model UUID=");
-            pw.println(mCurrentSoundModel == null ? "null" : mCurrentSoundModel.uuid);
-            pw.print("  current listener=");
-            pw.println(mActiveListener == null ? "null" : mActiveListener.asBinder());
-
-            pw.print("  requested="); pw.println(mRequested);
-            pw.print("  started="); pw.println(mStarted);
-            pw.print("  call active="); pw.println(mCallActive);
-            pw.print("  power save mode active="); pw.println(mIsPowerSaveMode);
-            pw.print("  service disabled="); pw.println(mServiceDisabled);
-        }
-    }
-}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 8fee91f..4a54643 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -18,6 +18,8 @@
 
 import android.Manifest;
 import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -45,6 +47,7 @@
 import android.provider.Settings;
 import android.service.voice.IVoiceInteractionService;
 import android.service.voice.IVoiceInteractionSession;
+import android.service.voice.VoiceInteractionManagerInternal;
 import android.service.voice.VoiceInteractionService;
 import android.service.voice.VoiceInteractionServiceInfo;
 import android.service.voice.VoiceInteractionSession;
@@ -59,6 +62,7 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
 import com.android.server.LocalServices;
+import com.android.server.soundtrigger.SoundTriggerInternal;
 import com.android.server.SystemService;
 import com.android.server.UiThread;
 
@@ -71,20 +75,21 @@
  */
 public class VoiceInteractionManagerService extends SystemService {
     static final String TAG = "VoiceInteractionManagerService";
-    static final boolean DEBUG = false;
+    static final boolean DEBUG = true;
 
     final Context mContext;
     final ContentResolver mResolver;
     final DatabaseHelper mDbHelper;
-    final SoundTriggerHelper mSoundTriggerHelper;
+    final ActivityManagerInternal mAmInternal;
+    SoundTriggerInternal mSoundTriggerInternal;
 
     public VoiceInteractionManagerService(Context context) {
         super(context);
         mContext = context;
         mResolver = context.getContentResolver();
         mDbHelper = new DatabaseHelper(context);
-        mSoundTriggerHelper = new SoundTriggerHelper(context);
         mServiceStub = new VoiceInteractionManagerServiceStub();
+        mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
 
         PackageManagerInternal packageManagerInternal = LocalServices.getService(
                 PackageManagerInternal.class);
@@ -105,11 +110,14 @@
     @Override
     public void onStart() {
         publishBinderService(Context.VOICE_INTERACTION_MANAGER_SERVICE, mServiceStub);
+        publishLocalService(VoiceInteractionManagerInternal.class, new LocalService());
     }
 
     @Override
     public void onBootPhase(int phase) {
-        if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+        if (PHASE_SYSTEM_SERVICES_READY == phase) {
+            mSoundTriggerInternal = LocalServices.getService(SoundTriggerInternal.class);
+        } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
             mServiceStub.systemRunning(isSafeMode());
         }
     }
@@ -124,6 +132,31 @@
         mServiceStub.switchUser(userHandle);
     }
 
+    class LocalService extends VoiceInteractionManagerInternal {
+        @Override
+        public void startLocalVoiceInteraction(IBinder callingActivity, Bundle options) {
+            if (DEBUG) {
+                Slog.i(TAG, "startLocalVoiceInteraction " + callingActivity);
+            }
+            VoiceInteractionManagerService.this.mServiceStub.startLocalVoiceInteraction(
+                    callingActivity, options);
+        }
+
+        @Override
+        public boolean supportsLocalVoiceInteraction() {
+            return VoiceInteractionManagerService.this.mServiceStub.supportsLocalVoiceInteraction();
+        }
+
+        @Override
+        public void stopLocalVoiceInteraction(IBinder callingActivity) {
+            if (DEBUG) {
+                Slog.i(TAG, "stopLocalVoiceInteraction " + callingActivity);
+            }
+            VoiceInteractionManagerService.this.mServiceStub.stopLocalVoiceInteraction(
+                    callingActivity);
+        }
+    }
+
     // implementation entry point and binder service
     private final VoiceInteractionManagerServiceStub mServiceStub;
 
@@ -139,6 +172,49 @@
             mEnableService = shouldEnableService(mContext.getResources());
         }
 
+        // TODO: VI Make sure the caller is the current user or profile
+        void startLocalVoiceInteraction(final IBinder token, Bundle options) {
+            if (mImpl == null) return;
+
+            final long caller = Binder.clearCallingIdentity();
+            try {
+                mImpl.showSessionLocked(options,
+                        VoiceInteractionSession.SHOW_SOURCE_ACTIVITY,
+                        new IVoiceInteractionSessionShowCallback.Stub() {
+                            @Override
+                            public void onFailed() {
+                            }
+
+                            @Override
+                            public void onShown() {
+                                mAmInternal.onLocalVoiceInteractionStarted(token,
+                                        mImpl.mActiveSession.mSession,
+                                        mImpl.mActiveSession.mInteractor);
+                            }
+                        },
+                        token);
+            } finally {
+                Binder.restoreCallingIdentity(caller);
+            }
+        }
+
+        public void stopLocalVoiceInteraction(IBinder callingActivity) {
+            if (mImpl == null) return;
+
+            final long caller = Binder.clearCallingIdentity();
+            try {
+                mImpl.finishLocked(callingActivity, true);
+            } finally {
+                Binder.restoreCallingIdentity(caller);
+            }
+        }
+
+        public boolean supportsLocalVoiceInteraction() {
+            if (mImpl == null) return false;
+
+            return mImpl.supportsLocalVoiceInteraction();
+        }
+
         @Override
         public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
                 throws RemoteException {
@@ -306,7 +382,7 @@
 
                 if (force || mImpl == null || mImpl.mUser != mCurUser
                         || !mImpl.mComponent.equals(serviceComponent)) {
-                    mSoundTriggerHelper.stopAllRecognitions();
+                    mSoundTriggerInternal.stopAllRecognitions();
                     if (mImpl != null) {
                         mImpl.shutdownLocked();
                     }
@@ -568,7 +644,7 @@
                 }
                 final long caller = Binder.clearCallingIdentity();
                 try {
-                    mImpl.finishLocked(token);
+                    mImpl.finishLocked(token, false);
                 } finally {
                     Binder.restoreCallingIdentity(caller);
                 }
@@ -662,9 +738,9 @@
                             mImpl.notifySoundModelsChangedLocked();
                         }
                     }
-                    return SoundTriggerHelper.STATUS_OK;
+                    return SoundTriggerInternal.STATUS_OK;
                 } else {
-                    return SoundTriggerHelper.STATUS_ERROR;
+                    return SoundTriggerInternal.STATUS_ERROR;
                 }
             } finally {
                 Binder.restoreCallingIdentity(caller);
@@ -685,7 +761,7 @@
             boolean deleted = false;
             try {
                 deleted = mDbHelper.deleteKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
-                return deleted ? SoundTriggerHelper.STATUS_OK : SoundTriggerHelper.STATUS_ERROR;
+                return deleted ? SoundTriggerInternal.STATUS_OK : SoundTriggerInternal.STATUS_ERROR;
             } finally {
                 if (deleted) {
                     synchronized (this) {
@@ -738,7 +814,7 @@
 
                 final long caller = Binder.clearCallingIdentity();
                 try {
-                    return mSoundTriggerHelper.moduleProperties;
+                    return mSoundTriggerInternal.getModuleProperties();
                 } finally {
                     Binder.restoreCallingIdentity(caller);
                 }
@@ -771,9 +847,9 @@
                         || soundModel.uuid == null
                         || soundModel.keyphrases == null) {
                     Slog.w(TAG, "No matching sound model found in startRecognition");
-                    return SoundTriggerHelper.STATUS_ERROR;
+                    return SoundTriggerInternal.STATUS_ERROR;
                 } else {
-                    return mSoundTriggerHelper.startRecognition(
+                    return mSoundTriggerInternal.startRecognition(
                             keyphraseId, soundModel, callback, recognitionConfig);
                 }
             } finally {
@@ -795,7 +871,7 @@
 
             final long caller = Binder.clearCallingIdentity();
             try {
-                return mSoundTriggerHelper.stopRecognition(keyphraseId, callback);
+                return mSoundTriggerInternal.stopRecognition(keyphraseId, callback);
             } finally {
                 Binder.restoreCallingIdentity(caller);
             }
@@ -937,7 +1013,7 @@
                 }
                 mImpl.dumpLocked(fd, pw, args);
             }
-            mSoundTriggerHelper.dump(fd, pw, args);
+            mSoundTriggerInternal.dump(fd, pw, args);
         }
 
         private void enforceCallingPermission(String permission) {
@@ -986,7 +1062,7 @@
                     // The user is force stopping our current interactor/recognizer.
                     // Clear the current settings and restore default state.
                     synchronized (VoiceInteractionManagerService.this) {
-                        mSoundTriggerHelper.stopAllRecognitions();
+                        mSoundTriggerInternal.stopAllRecognitions();
                         if (mImpl != null) {
                             mImpl.shutdownLocked();
                             mImpl = null;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 3efd0fb..1544723 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -215,12 +215,12 @@
         }
     }
 
-    public void finishLocked(IBinder token) {
-        if (mActiveSession == null || token != mActiveSession.mToken) {
+    public void finishLocked(IBinder token, boolean finishTask) {
+        if (mActiveSession == null || (!finishTask && token != mActiveSession.mToken)) {
             Slog.w(TAG, "finish does not match active session");
             return;
         }
-        mActiveSession.cancelLocked();
+        mActiveSession.cancelLocked(finishTask);
         mActiveSession = null;
     }
 
@@ -251,6 +251,10 @@
         return mActiveSession != null ? mActiveSession.getUserDisabledShowContextLocked() : 0;
     }
 
+    public boolean supportsLocalVoiceInteraction() {
+        return mInfo.getSupportsLocalInteraction();
+    }
+
     public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!mValid) {
             pw.print("  NOT VALID: ");
@@ -308,7 +312,7 @@
         // If there is an active session, cancel it to allow it to clean up its window and other
         // state.
         if (mActiveSession != null) {
-            mActiveSession.cancelLocked();
+            mActiveSession.cancelLocked(false);
             mActiveSession = null;
         }
         try {
@@ -343,7 +347,7 @@
     @Override
     public void sessionConnectionGone(VoiceInteractionSessionConnection connection) {
         synchronized (mLock) {
-            finishLocked(connection.mToken);
+            finishLocked(connection.mToken, false);
         }
     }
 }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 1788e88..e04f312 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -418,7 +418,7 @@
         return false;
     }
 
-    public void cancelLocked() {
+    public void cancelLocked(boolean finishTask) {
         hideLocked();
         mCanceled = true;
         if (mBound) {
@@ -429,7 +429,7 @@
                     Slog.w(TAG, "Voice interation session already dead");
                 }
             }
-            if (mSession != null) {
+            if (finishTask && mSession != null) {
                 try {
                     mAm.finishVoiceTask(mSession);
                 } catch (RemoteException e) {
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 8a1a553..de90202 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -24,7 +24,6 @@
 import java.lang.String;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -210,7 +209,22 @@
          * Call sends responses through connection.
          * @hide
          */
-        public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00400000;
+        public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00200000;
+
+        /**
+         * When set, prevents a video {@code Call} from being downgraded to an audio-only call.
+         * <p>
+         * Should be set when the VideoState has the {@link VideoProfile#STATE_TX_ENABLED} or
+         * {@link VideoProfile#STATE_RX_ENABLED} bits set to indicate that the connection cannot be
+         * downgraded from a video call back to a VideoState of
+         * {@link VideoProfile#STATE_AUDIO_ONLY}.
+         * <p>
+         * Intuitively, a call which can be downgraded to audio should also have local and remote
+         * video
+         * capabilities (see {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and
+         * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL}).
+         */
+        public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00400000;
 
         //******************************************************************************************
         // Next CAPABILITY value: 0x00800000
@@ -242,10 +256,16 @@
          */
         public static final int PROPERTY_HIGH_DEF_AUDIO = 0x00000010;
 
+        /**
+         * Whether the call is associated with the work profile.
+         */
+        public static final int PROPERTY_WORK_CALL = 0x00000020;
+
         //******************************************************************************************
-        // Next PROPERTY value: 0x00000020
+        // Next PROPERTY value: 0x00000040
         //******************************************************************************************
 
+        private final String mTelecomCallId;
         private final Uri mHandle;
         private final int mHandlePresentation;
         private final String mCallerDisplayName;
@@ -269,7 +289,7 @@
          * @return Whether the specified capability is supported.
          */
         public static boolean can(int capabilities, int capability) {
-            return (capabilities & capability) != 0;
+            return (capabilities & capability) == capability;
         }
 
         /**
@@ -327,6 +347,9 @@
             if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
                 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX");
             }
+            if (can(capabilities, CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)) {
+                builder.append(" CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO");
+            }
             if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
                 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
             }
@@ -351,7 +374,7 @@
          * @return Whether the specified property is supported.
          */
         public static boolean hasProperty(int properties, int property) {
-            return (properties & property) != 0;
+            return (properties & property) == property;
         }
 
         /**
@@ -392,6 +415,11 @@
             return builder.toString();
         }
 
+        /** {@hide} */
+        public String getTelecomCallId() {
+            return mTelecomCallId;
+        }
+
         /**
          * @return The handle (e.g., phone number) to which the {@code Call} is currently
          * connected.
@@ -545,6 +573,7 @@
 
         /** {@hide} */
         public Details(
+                String telecomCallId,
                 Uri handle,
                 int handlePresentation,
                 String callerDisplayName,
@@ -559,6 +588,7 @@
                 StatusHints statusHints,
                 Bundle extras,
                 Bundle intentExtras) {
+            mTelecomCallId = telecomCallId;
             mHandle = handle;
             mHandlePresentation = handlePresentation;
             mCallerDisplayName = callerDisplayName;
@@ -574,6 +604,26 @@
             mExtras = extras;
             mIntentExtras = intentExtras;
         }
+
+        /** {@hide} */
+        public static Details createFromParcelableCall(ParcelableCall parcelableCall) {
+            return new Details(
+                    parcelableCall.getId(),
+                    parcelableCall.getHandle(),
+                    parcelableCall.getHandlePresentation(),
+                    parcelableCall.getCallerDisplayName(),
+                    parcelableCall.getCallerDisplayNamePresentation(),
+                    parcelableCall.getAccountHandle(),
+                    parcelableCall.getCapabilities(),
+                    parcelableCall.getProperties(),
+                    parcelableCall.getDisconnectCause(),
+                    parcelableCall.getConnectTimeMillis(),
+                    parcelableCall.getGatewayInfo(),
+                    parcelableCall.getVideoState(),
+                    parcelableCall.getStatusHints(),
+                    parcelableCall.getExtras(),
+                    parcelableCall.getIntentExtras());
+        }
     }
 
     public static abstract class Callback {
@@ -684,7 +734,7 @@
     private int mState;
     private List<String> mCannedTextResponses = null;
     private String mRemainingPostDialSequence;
-    private InCallService.VideoCall mVideoCall;
+    private VideoCallImpl mVideoCallImpl;
     private Details mDetails;
 
     /**
@@ -897,7 +947,7 @@
      * @return An {@code Call.VideoCall}.
      */
     public InCallService.VideoCall getVideoCall() {
-        return mVideoCall;
+        return mVideoCallImpl;
     }
 
     /**
@@ -1000,21 +1050,7 @@
     /** {@hide} */
     final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) {
         // First, we update the internal state as far as possible before firing any updates.
-        Details details = new Details(
-                parcelableCall.getHandle(),
-                parcelableCall.getHandlePresentation(),
-                parcelableCall.getCallerDisplayName(),
-                parcelableCall.getCallerDisplayNamePresentation(),
-                parcelableCall.getAccountHandle(),
-                parcelableCall.getCapabilities(),
-                parcelableCall.getProperties(),
-                parcelableCall.getDisconnectCause(),
-                parcelableCall.getConnectTimeMillis(),
-                parcelableCall.getGatewayInfo(),
-                parcelableCall.getVideoState(),
-                parcelableCall.getStatusHints(),
-                parcelableCall.getExtras(),
-                parcelableCall.getIntentExtras());
+        Details details = Details.createFromParcelableCall(parcelableCall);
         boolean detailsChanged = !Objects.equals(mDetails, details);
         if (detailsChanged) {
             mDetails = details;
@@ -1028,10 +1064,14 @@
             cannedTextResponsesChanged = true;
         }
 
+        VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl();
         boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() &&
-                !Objects.equals(mVideoCall, parcelableCall.getVideoCall(this));
+                !Objects.equals(mVideoCallImpl, newVideoCallImpl);
         if (videoCallChanged) {
-            mVideoCall = parcelableCall.getVideoCall(this);
+            mVideoCallImpl = newVideoCallImpl;
+        }
+        if (mVideoCallImpl != null) {
+            mVideoCallImpl.setVideoState(getDetails().getVideoState());
         }
 
         int state = parcelableCall.getState();
@@ -1081,7 +1121,7 @@
             fireCannedTextResponsesLoaded(mCannedTextResponses);
         }
         if (videoCallChanged) {
-            fireVideoCallChanged(mVideoCall);
+            fireVideoCallChanged(mVideoCallImpl);
         }
         if (parentChanged) {
             fireParentChanged(getParent());
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
new file mode 100644
index 0000000..f62b170
--- /dev/null
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telecom;
+
+import android.annotation.SdkConstant;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+
+import com.android.internal.os.SomeArgs;
+import com.android.internal.telecom.ICallScreeningService;
+import com.android.internal.telecom.ICallScreeningAdapter;
+
+/**
+ * This service can be implemented by the default dialer (see
+ * {@link TelecomManager#getDefaultDialerPackage()}) to allow or disallow incoming calls before
+ * they are shown to a user.
+ * <p>
+ * Below is an example manifest registration for a {@code CallScreeningService}.
+ * <pre>
+ * {@code
+ * <service android:name="your.package.YourCallScreeningServiceImplementation"
+ *          android:permission="android.permission.BIND_SCREENING_SERVICE">
+ *      <intent-filter>
+ *          <action android:name="android.telecom.CallScreeningService"/>
+ *      </intent-filter>
+ * </service>
+ * }
+ * </pre>
+ */
+public abstract class CallScreeningService 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.telecom.CallScreeningService";
+
+    private static final int MSG_SCREEN_CALL = 1;
+
+    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_SCREEN_CALL:
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        mCallScreeningAdapter = (ICallScreeningAdapter) args.arg1;
+                        onScreenCall(
+                                Call.Details.createFromParcelableCall((ParcelableCall) args.arg2));
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+            }
+        }
+    };
+
+    private final class CallScreeningBinder extends ICallScreeningService.Stub {
+        @Override
+        public void screenCall(ICallScreeningAdapter adapter, ParcelableCall call) {
+            Log.v(this, "screenCall");
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = adapter;
+            args.arg2 = call;
+            mHandler.obtainMessage(MSG_SCREEN_CALL, args).sendToTarget();
+        }
+    }
+
+    private ICallScreeningAdapter mCallScreeningAdapter;
+
+    /*
+     * Information about how to respond to an incoming call.
+     */
+    public static class CallResponse {
+        private final boolean mShouldDisallowCall;
+        private final boolean mShouldRejectCall;
+        private final boolean mShouldSkipCallLog;
+        private final boolean mShouldSkipNotification;
+
+        private CallResponse(
+                boolean shouldDisallowCall,
+                boolean shouldRejectCall,
+                boolean shouldSkipCallLog,
+                boolean shouldSkipNotification) {
+            if (!shouldDisallowCall
+                    && (shouldRejectCall || shouldSkipCallLog || shouldSkipNotification)) {
+                throw new IllegalStateException("Invalid response state for allowed call.");
+            }
+
+            mShouldDisallowCall = shouldDisallowCall;
+            mShouldRejectCall = shouldRejectCall;
+            mShouldSkipCallLog = shouldSkipCallLog;
+            mShouldSkipNotification = shouldSkipNotification;
+        }
+
+        /*
+         * @return Whether the incoming call should be blocked.
+         */
+        public boolean getDisallowCall() {
+            return mShouldDisallowCall;
+        }
+
+        /*
+         * @return Whether the incoming call should be disconnected as if the user had manually
+         * rejected it.
+         */
+        public boolean getRejectCall() {
+            return mShouldRejectCall;
+        }
+
+        /*
+         * @return Whether the incoming call should not be displayed in the call log.
+         */
+        public boolean getSkipCallLog() {
+            return mShouldSkipCallLog;
+        }
+
+        /*
+         * @return Whether a missed call notification should not be shown for the incoming call.
+         */
+        public boolean getSkipNotification() {
+            return mShouldSkipNotification;
+        }
+
+        public static class Builder {
+            private boolean mShouldDisallowCall;
+            private boolean mShouldRejectCall;
+            private boolean mShouldSkipCallLog;
+            private boolean mShouldSkipNotification;
+
+            /*
+             * Sets whether the incoming call should be blocked.
+             */
+            public Builder setDisallowCall(boolean shouldDisallowCall) {
+                mShouldDisallowCall = shouldDisallowCall;
+                return this;
+            }
+
+            /*
+             * Sets whether the incoming call should be disconnected as if the user had manually
+             * rejected it. This property should only be set to true if the call is disallowed.
+             */
+            public Builder setRejectCall(boolean shouldRejectCall) {
+                mShouldRejectCall = shouldRejectCall;
+                return this;
+            }
+
+            /*
+             * Sets whether the incoming call should not be displayed in the call log. This property
+             * should only be set to true if the call is disallowed.
+             */
+            public Builder setSkipCallLog(boolean shouldSkipCallLog) {
+                mShouldSkipCallLog = shouldSkipCallLog;
+                return this;
+            }
+
+            /*
+             * Sets whether a missed call notification should not be shown for the incoming call.
+             * This property should only be set to true if the call is disallowed.
+             */
+            public Builder setSkipNotification(boolean shouldSkipNotification) {
+                mShouldSkipNotification = shouldSkipNotification;
+                return this;
+            }
+
+            public CallResponse build() {
+                return new CallResponse(
+                        mShouldDisallowCall,
+                        mShouldRejectCall,
+                        mShouldSkipCallLog,
+                        mShouldSkipNotification);
+            }
+       }
+    }
+
+    public CallScreeningService() {
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        Log.v(this, "onBind");
+        return new CallScreeningBinder();
+    }
+
+    @Override
+    public boolean onUnbind(Intent intent) {
+        Log.v(this, "onUnbind");
+        return false;
+    }
+
+    /**
+     * Called when a new incoming call is added.
+     * {@link CallScreeningService#respondToCall(Call.Details, CallScreeningService.CallResponse)}
+     * should be called to allow or disallow the call.
+     *
+     * @param callDetails Information about a new incoming call, see {@link Call.Details}.
+     */
+    public abstract void onScreenCall(Call.Details callDetails);
+
+    /**
+     * Responds to the given call, either allowing it or disallowing it.
+     *
+     * @param callDetails The call to allow.
+     * @param response The {@link CallScreeningService.CallResponse} which contains information
+     * about how to respond to a call.
+     */
+    public final void respondToCall(Call.Details callDetails, CallResponse response) {
+        try {
+            if (response.getDisallowCall()) {
+                mCallScreeningAdapter.disallowCall(
+                        callDetails.getTelecomCallId(),
+                        response.getRejectCall(),
+                        !response.getSkipCallLog(),
+                        !response.getSkipNotification());
+            } else {
+                mCallScreeningAdapter.allowCall(callDetails.getTelecomCallId());
+            }
+        } catch (RemoteException e) {
+        }
+    }
+}
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 17bd08c..fa7a59d 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -255,8 +255,23 @@
      */
     public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00400000;
 
+    /**
+     * When set, prevents a video call from being downgraded to an audio-only call.
+     * <p>
+     * Should be set when the VideoState has the {@link VideoProfile#STATE_TX_ENABLED} or
+     * {@link VideoProfile#STATE_RX_ENABLED} bits set to indicate that the connection cannot be
+     * downgraded from a video call back to a VideoState of
+     * {@link VideoProfile#STATE_AUDIO_ONLY}.
+     * <p>
+     * Intuitively, a call which can be downgraded to audio should also have local and remote
+     * video
+     * capabilities (see {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and
+     * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL}).
+     */
+    public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00800000;
+
     //**********************************************************************************************
-    // Next CAPABILITY value: 0x00800000
+    // Next CAPABILITY value: 0x01000000
     //**********************************************************************************************
 
     /**
@@ -294,7 +309,7 @@
      * @hide
      */
     public static boolean can(int capabilities, int capability) {
-        return (capabilities & capability) != 0;
+        return (capabilities & capability) == capability;
     }
 
     /**
@@ -371,6 +386,9 @@
         if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
             builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
         }
+        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");
         }
diff --git a/telecomm/java/android/telecom/DefaultDialerManager.java b/telecomm/java/android/telecom/DefaultDialerManager.java
index 5852b8e..a5e8fe1 100644
--- a/telecomm/java/android/telecom/DefaultDialerManager.java
+++ b/telecomm/java/android/telecom/DefaultDialerManager.java
@@ -21,6 +21,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.net.Uri;
+import android.os.Process;
 import android.provider.Settings;
 import android.text.TextUtils;
 
@@ -150,12 +151,13 @@
      *
      * @hide
      **/
-    public static List<String> getInstalledDialerApplications(Context context) {
+    public static List<String> getInstalledDialerApplications(Context context, int userId) {
         PackageManager packageManager = context.getPackageManager();
 
         // Get the list of apps registered for the DIAL intent with empty scheme
         Intent intent = new Intent(Intent.ACTION_DIAL);
-        List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent, 0);
+        List<ResolveInfo> resolveInfoList =
+                packageManager.queryIntentActivitiesAsUser(intent, 0, userId);
 
         List<String> packageNames = new ArrayList<>();
 
@@ -171,6 +173,10 @@
         return filterByIntent(context, packageNames, dialIntentWithTelScheme);
     }
 
+    public static List<String> getInstalledDialerApplications(Context context) {
+        return getInstalledDialerApplications(context, Process.myUserHandle().getIdentifier());
+    }
+
     /**
      * Determines if the package name belongs to the user-selected default dialer or the preloaded
      * system dialer, and thus should be allowed to perform certain privileged operations.
@@ -207,8 +213,8 @@
         }
 
         final List<String> result = new ArrayList<>();
-        final List<ResolveInfo> resolveInfoList =
-                context.getPackageManager().queryIntentActivities(intent, 0);
+        final List<ResolveInfo> resolveInfoList = context.getPackageManager()
+                .queryIntentActivities(intent, 0);
         final int length = resolveInfoList.size();
         for (int i = 0; i < length; i++) {
             final ActivityInfo info = resolveInfoList.get(i).activityInfo;
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 5087080..671399b 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -49,7 +49,7 @@
  * <pre>
  * {@code
  * <service android:name="your.package.YourInCallServiceImplementation"
- *          android:permission="android.permission.BIND_IN_CALL_SERVICE">
+ *          android:permission="android.permission.BIND_INCALL_SERVICE">
  *      <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true" />
  *      <intent-filter>
  *          <action android:name="android.telecom.InCallService"/>
@@ -73,6 +73,7 @@
     private static final int MSG_ON_CALL_AUDIO_STATE_CHANGED = 5;
     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;
 
     /** Default Handler used to consolidate binder method calls onto a single thread. */
     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@@ -114,6 +115,9 @@
                 case MSG_ON_CAN_ADD_CALL_CHANGED:
                     mPhone.internalSetCanAddCall(msg.arg1 == 1);
                     break;
+                case MSG_SILENCE_RINGER:
+                    mPhone.internalSilenceRinger();
+                    break;
                 default:
                     break;
             }
@@ -165,6 +169,11 @@
             mHandler.obtainMessage(MSG_ON_CAN_ADD_CALL_CHANGED, canAddCall ? 1 : 0, 0)
                     .sendToTarget();
         }
+
+        @Override
+        public void silenceRinger() {
+            mHandler.obtainMessage(MSG_SILENCE_RINGER).sendToTarget();
+        }
     }
 
     private Phone.Listener mPhoneListener = new Phone.Listener() {
@@ -202,6 +211,12 @@
             InCallService.this.onCanAddCallChanged(canAddCall);
         }
 
+        /** ${inheritDoc} */
+        @Override
+        public void onSilenceRinger(Phone phone) {
+            InCallService.this.onSilenceRinger();
+        }
+
     };
 
     private Phone mPhone;
@@ -405,6 +420,12 @@
     }
 
     /**
+     * Called to silence the ringer if a ringing call exists.
+     */
+    public void onSilenceRinger() {
+    }
+
+    /**
      * Used to issue commands to the {@link Connection.VideoProvider} associated with a
      * {@link Call}.
      */
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index 8cf4aeb..4a6fd7c 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -48,7 +48,7 @@
     private final PhoneAccountHandle mAccountHandle;
     private final boolean mIsVideoCallProviderChanged;
     private final IVideoProvider mVideoCallProvider;
-    private InCallService.VideoCall mVideoCall;
+    private VideoCallImpl mVideoCall;
     private final String mParentCallId;
     private final List<String> mChildCallIds;
     private final StatusHints mStatusHints;
@@ -179,12 +179,13 @@
 
     /**
      * Returns an object for remotely communicating through the video call provider's binder.
+
      * @return The video call.
      */
-    public InCallService.VideoCall getVideoCall(Call call) {
+    public VideoCallImpl getVideoCallImpl() {
         if (mVideoCall == null && mVideoCallProvider != null) {
             try {
-                mVideoCall = new VideoCallImpl(mVideoCallProvider, call);
+                mVideoCall = new VideoCallImpl(mVideoCallProvider);
             } catch (RemoteException ignored) {
                 // Ignore RemoteException.
             }
diff --git a/telecomm/java/android/telecom/ParcelableCallAnalytics.aidl b/telecomm/java/android/telecom/ParcelableCallAnalytics.aidl
new file mode 100644
index 0000000..b7e78d1
--- /dev/null
+++ b/telecomm/java/android/telecom/ParcelableCallAnalytics.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.telecom;
+
+/**
+ * {@hide}
+ */
+parcelable ParcelableCallAnalytics;
diff --git a/telecomm/java/android/telecom/ParcelableCallAnalytics.java b/telecomm/java/android/telecom/ParcelableCallAnalytics.java
new file mode 100644
index 0000000..e7c9672
--- /dev/null
+++ b/telecomm/java/android/telecom/ParcelableCallAnalytics.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 android.telecom;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public class ParcelableCallAnalytics implements Parcelable {
+    public static final int CALLTYPE_UNKNOWN = 0;
+    public static final int CALLTYPE_INCOMING = 1;
+    public static final int CALLTYPE_OUTGOING = 2;
+
+    // Constants for call technology
+    public static final int CDMA_PHONE = 0x1;
+    public static final int GSM_PHONE = 0x2;
+    public static final int IMS_PHONE = 0x4;
+    public static final int SIP_PHONE = 0x8;
+    public static final int THIRD_PARTY_PHONE = 0x10;
+
+    public static final long MILLIS_IN_5_MINUTES = 1000 * 60 * 5;
+    public static final long MILLIS_IN_1_SECOND = 1000;
+
+    public static final int STILL_CONNECTED = -1;
+
+    public static final Parcelable.Creator<ParcelableCallAnalytics> CREATOR =
+            new Parcelable.Creator<ParcelableCallAnalytics> () {
+
+                @Override
+                public ParcelableCallAnalytics createFromParcel(Parcel in) {
+                    return new ParcelableCallAnalytics(in);
+                }
+
+                @Override
+                public ParcelableCallAnalytics[] newArray(int size) {
+                    return new ParcelableCallAnalytics[size];
+                }
+            };
+
+    // The start time of the call in milliseconds since Jan. 1, 1970, rounded to the nearest
+    // 5 minute increment.
+    private final long startTimeMillis;
+
+    // The duration of the call, in milliseconds.
+    private final long callDurationMillis;
+
+    // ONE OF calltype_unknown, calltype_incoming, or calltype_outgoing
+    private final int callType;
+
+    // true if the call came in while another call was in progress or if the user dialed this call
+    // while in the middle of another call.
+    private final boolean isAdditionalCall;
+
+    // true if the call was interrupted by an incoming or outgoing call.
+    private final boolean isInterrupted;
+
+    // bitmask denoting which technologies a call used.
+    private final int callTechnologies;
+
+    // Any of the DisconnectCause codes, or STILL_CONNECTED.
+    private final int callTerminationCode;
+
+    // Whether the call is an emergency call
+    private final boolean isEmergencyCall;
+
+    // The package name of the connection service that this call used.
+    private final String connectionService;
+
+    // Whether the call object was created from an existing connection.
+    private final boolean isCreatedFromExistingConnection;
+
+    public ParcelableCallAnalytics(long startTimeMillis, long callDurationMillis, int callType,
+            boolean isAdditionalCall, boolean isInterrupted, int callTechnologies,
+            int callTerminationCode, boolean isEmergencyCall, String connectionService,
+            boolean isCreatedFromExistingConnection) {
+        this.startTimeMillis = startTimeMillis;
+        this.callDurationMillis = callDurationMillis;
+        this.callType = callType;
+        this.isAdditionalCall = isAdditionalCall;
+        this.isInterrupted = isInterrupted;
+        this.callTechnologies = callTechnologies;
+        this.callTerminationCode = callTerminationCode;
+        this.isEmergencyCall = isEmergencyCall;
+        this.connectionService = connectionService;
+        this.isCreatedFromExistingConnection = isCreatedFromExistingConnection;
+    }
+
+    public ParcelableCallAnalytics(Parcel in) {
+        startTimeMillis = in.readLong();
+        callDurationMillis = in.readLong();
+        callType = in.readInt();
+        isAdditionalCall = readByteAsBoolean(in);
+        isInterrupted = readByteAsBoolean(in);
+        callTechnologies = in.readInt();
+        callTerminationCode = in.readInt();
+        isEmergencyCall = readByteAsBoolean(in);
+        connectionService = in.readString();
+        isCreatedFromExistingConnection = readByteAsBoolean(in);
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeLong(startTimeMillis);
+        out.writeLong(callDurationMillis);
+        out.writeInt(callType);
+        writeBooleanAsByte(out, isAdditionalCall);
+        writeBooleanAsByte(out, isInterrupted);
+        out.writeInt(callTechnologies);
+        out.writeInt(callTerminationCode);
+        writeBooleanAsByte(out, isEmergencyCall);
+        out.writeString(connectionService);
+        writeBooleanAsByte(out, isCreatedFromExistingConnection);
+    }
+
+    public long getStartTimeMillis() {
+        return startTimeMillis;
+    }
+
+    public long getCallDurationMillis() {
+        return callDurationMillis;
+    }
+
+    public int getCallType() {
+        return callType;
+    }
+
+    public boolean isAdditionalCall() {
+        return isAdditionalCall;
+    }
+
+    public boolean isInterrupted() {
+        return isInterrupted;
+    }
+
+    public int getCallTechnologies() {
+        return callTechnologies;
+    }
+
+    public int getCallTerminationCode() {
+        return callTerminationCode;
+    }
+
+    public boolean isEmergencyCall() {
+        return isEmergencyCall;
+    }
+
+    public String getConnectionService() {
+        return connectionService;
+    }
+
+    public boolean isCreatedFromExistingConnection() {
+        return isCreatedFromExistingConnection;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    private static void writeBooleanAsByte(Parcel out, boolean b) {
+        out.writeByte((byte) (b ? 1 : 0));
+    }
+
+    private static boolean readByteAsBoolean(Parcel in) {
+        return (in.readByte() == 1);
+    }
+}
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index 47154da..56eb7ec 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -97,6 +97,13 @@
          * @param canAddCall Indicates whether an additional call can be added.
          */
         public void onCanAddCallChanged(Phone phone, boolean canAddCall) { }
+
+        /**
+         * Called to silence the ringer if a ringing call exists.
+         *
+         * @param phone The {@code Phone} calling this method.
+         */
+        public void onSilenceRinger(Phone phone) { }
     }
 
     // A Map allows us to track each Call by its Telecom-specified call ID
@@ -179,6 +186,10 @@
         }
     }
 
+    final void internalSilenceRinger() {
+        fireSilenceRinger();
+    }
+
     /**
      * Called to destroy the phone and cleanup any lingering calls.
      */
@@ -330,6 +341,12 @@
         }
     }
 
+    private void fireSilenceRinger() {
+        for (Listener listener : mListeners) {
+            listener.onSilenceRinger(this);
+        }
+    }
+
     private void checkCallTree(ParcelableCall parcelableCall) {
         if (parcelableCall.getParentCallId() != null &&
                 !mCallByTelecomCallId.containsKey(parcelableCall.getParentCallId())) {
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index b18af33..b56ce73 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -687,7 +687,7 @@
                 .append("] PhoneAccount: ")
                 .append(mAccountHandle)
                 .append(" Capabilities: ")
-                .append(mCapabilities)
+                .append(capabilitiesToString(mCapabilities))
                 .append(" Schemes: ");
         for (String scheme : mSupportedUriSchemes) {
             sb.append(scheme)
@@ -698,4 +698,42 @@
         sb.append("]");
         return sb.toString();
     }
+
+    /**
+     * Generates a string representation of a capabilities bitmask.
+     *
+     * @param capabilities The capabilities bitmask.
+     * @return String representation of the capabilities bitmask.
+     */
+    private String capabilitiesToString(int capabilities) {
+        StringBuilder sb = new StringBuilder();
+        if (hasCapabilities(CAPABILITY_VIDEO_CALLING)) {
+            sb.append("Video ");
+        }
+        if (hasCapabilities(CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE)) {
+            sb.append("Presence ");
+        }
+        if (hasCapabilities(CAPABILITY_CALL_PROVIDER)) {
+            sb.append("CallProvider ");
+        }
+        if (hasCapabilities(CAPABILITY_CALL_SUBJECT)) {
+            sb.append("CallSubject ");
+        }
+        if (hasCapabilities(CAPABILITY_CONNECTION_MANAGER)) {
+            sb.append("ConnectionMgr ");
+        }
+        if (hasCapabilities(CAPABILITY_EMERGENCY_CALLS_ONLY)) {
+            sb.append("EmergOnly ");
+        }
+        if (hasCapabilities(CAPABILITY_MULTI_USER)) {
+            sb.append("MultiUser ");
+        }
+        if (hasCapabilities(CAPABILITY_PLACE_EMERGENCY_CALLS)) {
+            sb.append("PlaceEmerg ");
+        }
+        if (hasCapabilities(CAPABILITY_SIM_SUBSCRIPTION)) {
+            sb.append("SimSub ");
+        }
+        return sb.toString();
+    }
 }
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 9eb1665..72ff272 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -14,6 +14,7 @@
 
 package android.telecom;
 
+import android.Manifest;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.content.ComponentName;
@@ -297,6 +298,25 @@
     public static final String METADATA_IN_CALL_SERVICE_UI = "android.telecom.IN_CALL_SERVICE_UI";
 
     /**
+     * A boolean meta-data value indicating whether an {@link InCallService} implements an
+     * in-call user interface to be used while the device is in car-mode (see
+     * {@link android.content.res.Configuration.UI_MODE_TYPE_CAR}).
+     *
+     * @hide
+     */
+    public static final String METADATA_IN_CALL_SERVICE_CAR_MODE_UI =
+            "android.telecom.IN_CALL_SERVICE_CAR_MODE_UI";
+
+    /**
+     * A boolean meta-data value indicating whether an {@link InCallService} implements ringing.
+     * Dialer implementations (see {@link #getDefaultDialerPackage()}) which would also like to
+     * override the system provided ringing should set this meta-data to {@code true} in the
+     * manifest registration of their {@link InCallService}.
+     */
+    public static final String METADATA_IN_CALL_SERVICE_RINGING =
+            "android.telecom.IN_CALL_SERVICE_RINGING";
+
+    /**
      * The dual tone multi-frequency signaling character sent to indicate the dialing system should
      * pause for a predefined period.
      */
@@ -386,27 +406,23 @@
 
     /**
      * Broadcast intent action for letting custom component know to show the missed call
-     * notification.
-     * @hide
+     * notification. If no custom component exists then this is sent to the default dialer which
+     * should post a missed-call notification.
      */
-    @SystemApi
     public static final String ACTION_SHOW_MISSED_CALLS_NOTIFICATION =
             "android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION";
 
     /**
-     * The number of calls associated with the notification.
-     * @hide
+     * The number of calls associated with the notification. If the number is zero then the missed
+     * call notification should be dismissed.
      */
-    @SystemApi
     public static final String EXTRA_NOTIFICATION_COUNT =
             "android.telecom.extra.NOTIFICATION_COUNT";
 
     /**
      * The number associated with the missed calls. This number is only relevant
      * when EXTRA_NOTIFICATION_COUNT is 1.
-     * @hide
      */
-    @SystemApi
     public static final String EXTRA_NOTIFICATION_PHONE_NUMBER =
             "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
 
@@ -1377,6 +1393,27 @@
         }
     }
 
+    /**
+     * Dumps telecom analytics for uploading.
+     *
+     * @return
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.DUMP)
+    public List<ParcelableCallAnalytics> dumpAnalytics() {
+        ITelecomService service = getTelecomService();
+        List<ParcelableCallAnalytics> result = null;
+        if (service != null) {
+            try {
+                result = service.dumpCallAnalytics();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error dumping call analytics", e);
+            }
+        }
+        return result;
+    }
+
     private ITelecomService getTelecomService() {
         if (mTelecomServiceOverride != null) {
             return mTelecomServiceOverride;
diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java
index 93484cd..e54abee 100644
--- a/telecomm/java/android/telecom/VideoCallImpl.java
+++ b/telecomm/java/android/telecom/VideoCallImpl.java
@@ -42,7 +42,7 @@
     private final VideoCallListenerBinder mBinder;
     private VideoCall.Callback mCallback;
     private int mVideoQuality = VideoProfile.QUALITY_UNKNOWN;
-    private Call mCall;
+    private int mVideoState = VideoProfile.STATE_AUDIO_ONLY;
 
     private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
         @Override
@@ -197,13 +197,12 @@
 
     private Handler mHandler;
 
-    VideoCallImpl(IVideoProvider videoProvider, Call call) throws RemoteException {
+    VideoCallImpl(IVideoProvider videoProvider) throws RemoteException {
         mVideoProvider = videoProvider;
         mVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0);
 
         mBinder = new VideoCallListenerBinder();
         mVideoProvider.addVideoCallback(mBinder);
-        mCall = call;
     }
 
     public void destroy() {
@@ -292,8 +291,7 @@
      */
     public void sendSessionModifyRequest(VideoProfile requestProfile) {
         try {
-            VideoProfile originalProfile = new VideoProfile(mCall.getDetails().getVideoState(),
-                    mVideoQuality);
+            VideoProfile originalProfile = new VideoProfile(mVideoState, mVideoQuality);
 
             mVideoProvider.sendSessionModifyRequest(originalProfile, requestProfile);
         } catch (RemoteException e) {
@@ -331,4 +329,12 @@
         } catch (RemoteException e) {
         }
     }
+
+    /**
+     * Sets the video state for the current video call.
+     * @param videoState the new video state.
+     */
+    public void setVideoState(int videoState) {
+        mVideoState = videoState;
+    }
 }
diff --git a/telecomm/java/android/telecom/VideoProfile.java b/telecomm/java/android/telecom/VideoProfile.java
index dabf706..216603c 100644
--- a/telecomm/java/android/telecom/VideoProfile.java
+++ b/telecomm/java/android/telecom/VideoProfile.java
@@ -16,13 +16,23 @@
 
 package android.telecom;
 
+import android.annotation.IntDef;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Represents attributes of video calls.
  */
 public class VideoProfile implements Parcelable {
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({QUALITY_UNKNOWN, QUALITY_HIGH, QUALITY_MEDIUM, QUALITY_LOW, QUALITY_DEFAULT})
+    public @interface VideoQuality {}
+
     /**
      * "Unknown" video quality.
      * @hide
@@ -48,6 +58,14 @@
      */
     public static final int QUALITY_DEFAULT = 4;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(
+            flag = true,
+            value = {STATE_AUDIO_ONLY, STATE_TX_ENABLED, STATE_RX_ENABLED, STATE_BIDIRECTIONAL,
+                    STATE_PAUSED})
+    public @interface VideoState {}
+
     /**
      * Used when answering or dialing a call to indicate that the call does not have a video
      * component.
@@ -107,7 +125,7 @@
      *
      * @param videoState The video state.
      */
-    public VideoProfile(int videoState) {
+    public VideoProfile(@VideoState int videoState) {
         this(videoState, QUALITY_DEFAULT);
     }
 
@@ -117,7 +135,7 @@
      * @param videoState The video state.
      * @param quality The video quality.
      */
-    public VideoProfile(int videoState, int quality) {
+    public VideoProfile(@VideoState int videoState, @VideoQuality int quality) {
         mVideoState = videoState;
         mQuality = quality;
     }
@@ -130,6 +148,7 @@
      * {@link VideoProfile#STATE_RX_ENABLED},
      * {@link VideoProfile#STATE_PAUSED}.
      */
+    @VideoState
     public int getVideoState() {
         return mVideoState;
     }
@@ -139,6 +158,7 @@
      * Valid values: {@link VideoProfile#QUALITY_HIGH}, {@link VideoProfile#QUALITY_MEDIUM},
      * {@link VideoProfile#QUALITY_LOW}, {@link VideoProfile#QUALITY_DEFAULT}.
      */
+    @VideoQuality
     public int getQuality() {
         return mQuality;
     }
@@ -211,7 +231,7 @@
      * @param videoState The video state.
      * @return String representation of the video state.
      */
-    public static String videoStateToString(int videoState) {
+    public static String videoStateToString(@VideoState int videoState) {
         StringBuilder sb = new StringBuilder();
         sb.append("Audio");
 
@@ -240,7 +260,7 @@
      * @param videoState The video state.
      * @return {@code True} if the video state is audio only, {@code false} otherwise.
      */
-    public static boolean isAudioOnly(int videoState) {
+    public static boolean isAudioOnly(@VideoState int videoState) {
         return !hasState(videoState, VideoProfile.STATE_TX_ENABLED)
                 && !hasState(videoState, VideoProfile.STATE_RX_ENABLED);
     }
@@ -251,7 +271,7 @@
      * @param videoState The video state.
      * @return {@code True} if video transmission or reception is enabled, {@code false} otherwise.
      */
-    public static boolean isVideo(int videoState) {
+    public static boolean isVideo(@VideoState int videoState) {
         return hasState(videoState, VideoProfile.STATE_TX_ENABLED)
                 || hasState(videoState, VideoProfile.STATE_RX_ENABLED)
                 || hasState(videoState, VideoProfile.STATE_BIDIRECTIONAL);
@@ -263,7 +283,7 @@
      * @param videoState The video state.
      * @return {@code True} if video transmission is enabled, {@code false} otherwise.
      */
-    public static boolean isTransmissionEnabled(int videoState) {
+    public static boolean isTransmissionEnabled(@VideoState int videoState) {
         return hasState(videoState, VideoProfile.STATE_TX_ENABLED);
     }
 
@@ -273,7 +293,7 @@
      * @param videoState The video state.
      * @return {@code True} if video reception is enabled, {@code false} otherwise.
      */
-    public static boolean isReceptionEnabled(int videoState) {
+    public static boolean isReceptionEnabled(@VideoState int videoState) {
         return hasState(videoState, VideoProfile.STATE_RX_ENABLED);
     }
 
@@ -283,7 +303,7 @@
      * @param videoState The video state.
      * @return {@code True} if the video is bi-directional, {@code false} otherwise.
      */
-    public static boolean isBidirectional(int videoState) {
+    public static boolean isBidirectional(@VideoState int videoState) {
         return hasState(videoState, VideoProfile.STATE_BIDIRECTIONAL);
     }
 
@@ -293,7 +313,7 @@
      * @param videoState The video state.
      * @return {@code True} if the video is paused, {@code false} otherwise.
      */
-    public static boolean isPaused(int videoState) {
+    public static boolean isPaused(@VideoState int videoState) {
         return hasState(videoState, VideoProfile.STATE_PAUSED);
     }
 
@@ -304,7 +324,7 @@
      * @param state The state to check.
      * @return {@code True} if the state is set.
      */
-    private static boolean hasState(int videoState, int state) {
+    private static boolean hasState(@VideoState int videoState, @VideoState int state) {
         return (videoState & state) == state;
     }
 
diff --git a/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
new file mode 100644
index 0000000..2e0af27
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.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 com.android.internal.telecom;
+
+/**
+ * Internal remote callback interface for call screening services.
+ *
+ * @see android.telecom.CallScreeningService
+ *
+ * {@hide}
+ */
+oneway interface ICallScreeningAdapter {
+    void allowCall(String callId);
+
+    void disallowCall(
+            String callId,
+            boolean shouldReject,
+            boolean shouldAddToCallLog,
+            boolean shouldShowNotification);
+}
diff --git a/telecomm/java/com/android/internal/telecom/ICallScreeningService.aidl b/telecomm/java/com/android/internal/telecom/ICallScreeningService.aidl
new file mode 100644
index 0000000..c3fe1af
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecom/ICallScreeningService.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 com.android.internal.telecom;
+
+import android.telecom.ParcelableCall;
+
+import com.android.internal.telecom.ICallScreeningAdapter;
+
+/**
+ * Internal remote interface for a call screening service.
+ * @see android.telecom.CallScreeningService
+ * @hide
+ */
+oneway interface ICallScreeningService {
+    void screenCall(in ICallScreeningAdapter adapter, in ParcelableCall call);
+}
diff --git a/telecomm/java/com/android/internal/telecom/IInCallService.aidl b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
index ded47d5..0088e0c 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
@@ -45,4 +45,6 @@
     void bringToForeground(boolean showDialpad);
 
     void onCanAddCallChanged(boolean canAddCall);
+
+    void silenceRinger();
 }
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 856e210..af36b3e 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.telecom.ParcelableCallAnalytics;
 import android.telecom.PhoneAccountHandle;
 import android.net.Uri;
 import android.os.Bundle;
@@ -143,6 +144,11 @@
      */
     String getSystemDialerPackage();
 
+    /**
+    * @see TelecomServiceImpl#dumpCallAnalytics
+    */
+    List<ParcelableCallAnalytics> dumpCallAnalytics();
+
     //
     // Internal system apis relating to call management.
     //
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 6ffc026..4368b81 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -81,7 +81,6 @@
      * Flag to require or skip entitlement checks.
      * If true, entitlement checks will be executed if device has been configured for it,
      * If false, entitlement checks will be skipped.
-     * @hide
      */
     public static final String
             KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
@@ -269,7 +268,6 @@
 
     /**
      * Flag specifying whether Generic Bootstrapping Architecture capable SIM is required for IMS.
-     * @hide
      */
     public static final String KEY_CARRIER_IMS_GBA_REQUIRED_BOOL
             = "carrier_ims_gba_required_bool";
@@ -277,7 +275,6 @@
     /**
      * Flag specifying whether IMS instant lettering is available for the carrier.  {@code True} if
      * instant lettering is available for the carrier, {@code false} otherwise.
-     * @hide
      */
     public static final String KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL =
             "carrier_instant_lettering_available_bool";
@@ -294,7 +291,6 @@
      * {@link #KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL}), determines the list of characters
      * which may not be contained in messages.  Should be specified as a regular expression suitable
      * for use with {@link String#matches(String)}.
-     * @hide
      */
     public static final String KEY_CARRIER_INSTANT_LETTERING_INVALID_CHARS_STRING =
             "carrier_instant_lettering_invalid_chars_string";
@@ -305,7 +301,6 @@
      * must be escaped with a backslash '\' character.  Should be specified as a string containing
      * the characters to be escaped.  For example to escape quote and backslash the string would be
      * a quote and a backslash.
-     * @hide
      */
     public static final String KEY_CARRIER_INSTANT_LETTERING_ESCAPED_CHARS_STRING =
             "carrier_instant_lettering_escaped_chars_string";
@@ -319,7 +314,6 @@
      * towards the messages size limit as a single bye.  If a character encoding is specified, the
      * message size limit will be based on the number of bytes in the message per the specified
      * encoding.
-     * @hide
      */
     public static final String KEY_CARRIER_INSTANT_LETTERING_ENCODING_STRING =
             "carrier_instant_lettering_encoding_string";
@@ -330,7 +324,6 @@
      * in the InCall UI to ensure the user cannot enter more characters than allowed by the carrier.
      * See also {@link #KEY_CARRIER_INSTANT_LETTERING_ENCODING_STRING} for more information on how
      * the length of the message is calculated.
-     * @hide
      */
     public static final String KEY_CARRIER_INSTANT_LETTERING_LENGTH_LIMIT_INT =
             "carrier_instant_lettering_length_limit_int";
@@ -353,7 +346,6 @@
     /**
      * The default flag specifying whether ETWS/CMAS test setting is forcibly disabled in
      * Settings->More->Emergency broadcasts menu even though developer options is turned on.
-     * @hide
      */
     public static final String KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL =
             "carrier_force_disable_etws_cmas_test_bool";
@@ -361,11 +353,38 @@
     /**
      * The default flag specifying whether "Turn on Notifications" option will be always shown in
      * Settings->More->Emergency broadcasts menu regardless developer options is turned on or not.
-     * @hide
      */
     public static final String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL =
             "always_show_emergency_alert_onoff_bool";
 
+    /**
+     * The data call APN retry configuration for default type APN.
+     * @hide
+     */
+    public static final String KEY_CARRIER_DATA_CALL_RETRY_CONFIG_DEFAULT_STRING =
+            "carrier_data_call_retry_config_default_string";
+
+    /**
+     * The data call APN retry configuration for other type APNs.
+     * @hide
+     */
+    public static final String KEY_CARRIER_DATA_CALL_RETRY_CONFIG_OTHERS_STRING =
+            "carrier_data_call_retry_config_others_string";
+
+    /**
+     * Delay between trying APN from the pool
+     * @hide
+     */
+    public static final String KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG =
+            "carrier_data_call_apn_delay_default_long";
+
+    /**
+     * Faster delay between trying APN from the pool
+     * @hide
+     */
+    public static final String KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG =
+            "carrier_data_call_apn_delay_faster_long";
+
     /* The following 3 fields are related to carrier visual voicemail. */
 
     /**
@@ -390,6 +409,11 @@
     public static final String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN = "vvm_cellular_data_required";
 
     /**
+     * Whether to prefetch audio data on new voicemail arrival, defaulted to true.
+     */
+    public static final String KEY_VVM_PREFETCH_BOOLEAN = "vvm_prefetch";
+
+    /**
      * The package name of the carrier's visual voicemail app to ensure that dialer visual voicemail
      * and carrier visual voicemail are not active at the same time.
      */
@@ -398,27 +422,23 @@
     /**
      * Flag specifying whether an additional (client initiated) intent needs to be sent on System
      * update
-     * @hide
      */
     public static final String KEY_CI_ACTION_ON_SYS_UPDATE_BOOL = "ci_action_on_sys_update_bool";
 
     /**
      * Intent to be sent for the additional action on System update
-     * @hide
      */
     public static final String KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING =
             "ci_action_on_sys_update_intent_string";
 
     /**
      * Extra to be included in the intent sent for additional action on System update
-     * @hide
      */
     public static final String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING =
             "ci_action_on_sys_update_extra_string";
 
     /**
      * Value of extra included in intent sent for additional action on System update
-     * @hide
      */
     public static final String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING =
             "ci_action_on_sys_update_extra_val_string";
@@ -427,7 +447,6 @@
      * Specifies the amount of gap to be added in millis between postdial DTMF tones. When a
      * non-zero value is specified, the UE shall wait for the specified amount of time before it
      * sends out successive DTMF tones on the network.
-     * @hide
      */
     public static final String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
 
@@ -435,7 +454,6 @@
      * Specifies the amount of gap to be added in millis between DTMF tones. When a non-zero value
      * is specified, the UE shall wait for the specified amount of time before it sends out
      * successive DTMF tones on the network.
-     * @hide
      */
     public static final String KEY_IMS_DTMF_TONE_DELAY_INT = "ims_dtmf_tone_delay_int";
 
@@ -443,36 +461,40 @@
      * Specifies the amount of gap to be added in millis between postdial DTMF tones. When a
      * non-zero value is specified, the UE shall wait for the specified amount of time before it
      * sends out successive DTMF tones on the network.
-     * @hide
      */
     public static final String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
 
     /**
      * Determines whether conference calls are supported by a carrier.  When {@code true},
      * conference calling is supported, {@code false otherwise}.
-     * @hide
      */
     public static final String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
 
     /**
      * Determine whether user can toggle Enhanced 4G LTE Mode in Settings.
-     * @hide
      */
     public static final String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
 
     /**
      * Determine whether IMS apn can be shown.
-     * @hide
      */
     public static final String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool";
 
     /**
      * Determine whether preferred network type can be shown.
-     * @hide
      */
     public static final String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool";
 
     /**
+     * Determine whether user can switch Wi-Fi preferred or Cellular preferred in calling preference.
+     * Some operators support Wi-Fi Calling only, not VoLTE.
+     * They don't need "Cellular preferred" option.
+     * In this case, set uneditalbe attribute for preferred preference.
+     * @hide
+     */
+    public static final String KEY_EDITABLE_WFC_MODE_BOOL = "editable_wfc_mode_bool";
+
+    /**
      * If this is true, the SIM card (through Customer Service Profile EF file) will be able to
      * prevent manual operator selection. If false, this SIM setting will be ignored and manual
      * operator selection will always be available. See CPHS4_2.WW6, CPHS B.4.7.1 for more
@@ -482,10 +504,16 @@
 
     /**
      * Allow user to add APNs
-     * @hide
      */
     public static final String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
 
+    /**
+     * Boolean indicating if intent for emergency call state changes should be broadcast
+     * @hide
+     */
+    public static final String KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL =
+            "broadcast_emergency_call_state_changes_bool";
+
     // These variables are used by the MMS service and exposed through another API, {@link
     // SmsManager}. The variable names and string values are copied from there.
     public static final String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled";
@@ -524,7 +552,6 @@
      * Determines whether the carrier supports making non-emergency phone calls while the phone is
      * in emergency callback mode.  Default value is {@code true}, meaning that non-emergency calls
      * are allowed in emergency callback mode.
-     * @hide
      */
     public static final String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL =
             "allow_non_emergency_calls_in_ecm_bool";
@@ -533,8 +560,6 @@
      * Flag indicating whether to allow carrier video calls to emergency numbers.
      * 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.
-     *
-     * @hide
      */
     @SystemApi
     public static final String BOOL_ALLOW_EMERGENCY_VIDEO_CALLS =
@@ -546,13 +571,26 @@
      * 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.
-     *
-     * @hide
      */
     @SystemApi
     public static final String BOOL_ALLOW_VIDEO_PAUSE =
             "bool_allow_video_pause";
 
+
+    /**
+     * Flag indicating whether the carrier supports RCS presence indication for video calls.  When
+     * {@code true}, the carrier supports RCS presence indication for video calls.  When presence
+     * is supported, the device should use the
+     * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE} bit mask and set the
+     * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE_VT_CAPABLE} bit to indicate
+     * whether each contact supports video calling.  The UI is made aware that presence is enabled
+     * via {@link android.telecom.PhoneAccount#CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE}
+     * 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";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -605,6 +643,7 @@
         sDefaults.putInt(KEY_VVM_PORT_NUMBER_INT, 0);
         sDefaults.putString(KEY_VVM_TYPE_STRING, "");
         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_CI_ACTION_ON_SYS_UPDATE_BOOL, false);
         sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING, "");
@@ -612,7 +651,15 @@
         sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING, "");
         sDefaults.putBoolean(KEY_CSP_ENABLED_BOOL, false);
         sDefaults.putBoolean(KEY_ALLOW_ADDING_APNS_BOOL, true);
+        sDefaults.putBoolean(KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL, false);
         sDefaults.putBoolean(KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL, false);
+        sDefaults.putString(KEY_CARRIER_DATA_CALL_RETRY_CONFIG_DEFAULT_STRING,
+                "default_randomization=2000,5000,10000,20000,40000,80000:5000,160000:5000,"
+                        + "320000:5000,640000:5000,1280000:5000,1800000:5000");
+        sDefaults.putString(KEY_CARRIER_DATA_CALL_RETRY_CONFIG_OTHERS_STRING,
+                "max_retries=3, 5000, 5000, 5000");
+        sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG, 20000);
+        sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG, 3000);
 
         sDefaults.putStringArray(KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY, null);
         sDefaults.putStringArray(KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY, null);
@@ -628,6 +675,7 @@
         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_EDITABLE_WFC_MODE_BOOL, true);
 
         // MMS defaults
         sDefaults.putBoolean(KEY_MMS_ALIAS_ENABLED_BOOL, false);
@@ -662,6 +710,7 @@
         sDefaults.putString(KEY_MMS_UA_PROF_URL_STRING, "");
         sDefaults.putString(KEY_MMS_USER_AGENT_STRING, "");
         sDefaults.putBoolean(KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL, true);
+        sDefaults.putBoolean(KEY_USE_RCS_PRESENCE_BOOL, false);
     }
 
     /**
@@ -703,7 +752,7 @@
      */
     @Nullable
     public PersistableBundle getConfig() {
-        return getConfigForSubId(SubscriptionManager.getDefaultSubId());
+        return getConfigForSubId(SubscriptionManager.getDefaultSubscriptionId());
     }
 
     /**
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 90d2aa0..74f1171 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -38,6 +38,10 @@
     private final int mLac;
     // 16-bit GSM Cell Identity described in TS 27.007, 0..65535
     private final int mCid;
+    // 16-bit GSM Absolute RF Channel Number
+    private final int mArfcn;
+    // 6-bit Base Station Identity Code
+    private final int mBsic;
 
     /**
      * @hide
@@ -47,6 +51,8 @@
         mMnc = Integer.MAX_VALUE;
         mLac = Integer.MAX_VALUE;
         mCid = Integer.MAX_VALUE;
+        mArfcn = Integer.MAX_VALUE;
+        mBsic = Integer.MAX_VALUE;
     }
     /**
      * public constructor
@@ -58,10 +64,27 @@
      * @hide
      */
     public CellIdentityGsm (int mcc, int mnc, int lac, int cid) {
+        this(mcc, mnc, lac, cid, Integer.MAX_VALUE, Integer.MAX_VALUE);
+    }
+
+    /**
+     * public constructor
+     * @param mcc 3-digit Mobile Country Code, 0..999
+     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
+     * @param lac 16-bit Location Area Code, 0..65535
+     * @param cid 16-bit GSM Cell Identity or 28-bit UMTS Cell Identity
+     * @param arfcn 16-bit GSM Absolute RF Channel Number
+     * @param bsic 6-bit Base Station Identity Code
+     *
+     * @hide
+     */
+    public CellIdentityGsm (int mcc, int mnc, int lac, int cid, int arfcn, int bsic) {
         mMcc = mcc;
         mMnc = mnc;
         mLac = lac;
         mCid = cid;
+        mArfcn = arfcn;
+        mBsic = bsic;
     }
 
     private CellIdentityGsm(CellIdentityGsm cid) {
@@ -69,6 +92,8 @@
         mMnc = cid.mMnc;
         mLac = cid.mLac;
         mCid = cid.mCid;
+        mArfcn = cid.mArfcn;
+        mBsic = cid.mBsic;
     }
 
     CellIdentityGsm copy() {
@@ -106,6 +131,21 @@
     }
 
     /**
+     * @return 16-bit GSM Absolute RF Channel Number, Integer.MAX_VALUE if unknown
+     */
+    public int getArfcn() {
+        return mArfcn;
+    }
+
+    /**
+     * @return 6-bit Base Station Identity Code, Integer.MAX_VALUE if unknown
+     */
+    public int getBsic() {
+        return mBsic;
+    }
+
+
+    /**
      * @return Integer.MAX_VALUE, undefined for GSM
      */
     @Deprecated
@@ -132,7 +172,9 @@
         return mMcc == o.mMcc &&
                 mMnc == o.mMnc &&
                 mLac == o.mLac &&
-                mCid == o.mCid;
+                mCid == o.mCid &&
+                mArfcn == o.mArfcn &&
+                mBsic == o.mBsic;
     }
 
     @Override
@@ -142,6 +184,8 @@
         sb.append(" mMnc=").append(mMnc);
         sb.append(" mLac=").append(mLac);
         sb.append(" mCid=").append(mCid);
+        sb.append(" mArfcn=").append(mArfcn);
+        sb.append(" mBsic=").append("0x").append(Integer.toHexString(mBsic));
         sb.append("}");
 
         return sb.toString();
@@ -161,6 +205,8 @@
         dest.writeInt(mMnc);
         dest.writeInt(mLac);
         dest.writeInt(mCid);
+        dest.writeInt(mArfcn);
+        dest.writeInt(mBsic);
     }
 
     /** Construct from Parcel, type has already been processed */
@@ -169,6 +215,8 @@
         mMnc = in.readInt();
         mLac = in.readInt();
         mCid = in.readInt();
+        mArfcn = in.readInt();
+        mBsic = in.readInt();
         if (DBG) log("CellIdentityGsm(Parcel): " + toString());
     }
 
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 1e7ac08..ce74383 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -40,6 +40,8 @@
     private final int mPci;
     // 16-bit tracking area code
     private final int mTac;
+    // 18-bit Absolute RF Channel Number
+    private final int mEarfcn;
 
     /**
      * @hide
@@ -50,6 +52,7 @@
         mCi = Integer.MAX_VALUE;
         mPci = Integer.MAX_VALUE;
         mTac = Integer.MAX_VALUE;
+        mEarfcn = Integer.MAX_VALUE;
     }
 
     /**
@@ -63,11 +66,27 @@
      * @hide
      */
     public CellIdentityLte (int mcc, int mnc, int ci, int pci, int tac) {
+        this(mcc, mnc, ci, pci, tac, Integer.MAX_VALUE);
+    }
+
+    /**
+     *
+     * @param mcc 3-digit Mobile Country Code, 0..999
+     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
+     * @param ci 28-bit Cell Identity
+     * @param pci Physical Cell Id 0..503
+     * @param tac 16-bit Tracking Area Code
+     * @param earfcn 18-bit LTE Absolute RF Channel Number
+     *
+     * @hide
+     */
+    public CellIdentityLte (int mcc, int mnc, int ci, int pci, int tac, int earfcn) {
         mMcc = mcc;
         mMnc = mnc;
         mCi = ci;
         mPci = pci;
         mTac = tac;
+        mEarfcn = earfcn;
     }
 
     private CellIdentityLte(CellIdentityLte cid) {
@@ -76,6 +95,7 @@
         mCi = cid.mCi;
         mPci = cid.mPci;
         mTac = cid.mTac;
+        mEarfcn = cid.mEarfcn;
     }
 
     CellIdentityLte copy() {
@@ -117,6 +137,13 @@
         return mTac;
     }
 
+    /**
+     * @return 18-bit Absolute RF Channel Number, Integer.MAX_VALUE if unknown
+     */
+    public int getEarfcn() {
+        return mEarfcn;
+    }
+
     @Override
     public int hashCode() {
         return Objects.hash(mMcc, mMnc, mCi, mPci, mTac);
@@ -137,7 +164,8 @@
                 mMnc == o.mMnc &&
                 mCi == o.mCi &&
                 mPci == o.mPci &&
-                mTac == o.mTac;
+                mTac == o.mTac &&
+                mEarfcn == o.mEarfcn;
     }
 
     @Override
@@ -148,6 +176,7 @@
         sb.append(" mCi="); sb.append(mCi);
         sb.append(" mPci="); sb.append(mPci);
         sb.append(" mTac="); sb.append(mTac);
+        sb.append(" mEarfcn="); sb.append(mEarfcn);
         sb.append("}");
 
         return sb.toString();
@@ -168,6 +197,7 @@
         dest.writeInt(mCi);
         dest.writeInt(mPci);
         dest.writeInt(mTac);
+        dest.writeInt(mEarfcn);
     }
 
     /** Construct from Parcel, type has already been processed */
@@ -177,6 +207,7 @@
         mCi = in.readInt();
         mPci = in.readInt();
         mTac = in.readInt();
+        mEarfcn = in.readInt();
         if (DBG) log("CellIdentityLte(Parcel): " + toString());
     }
 
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index 56ee8c9..0d13efd 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -40,6 +40,8 @@
     private final int mCid;
     // 9-bit UMTS Primary Scrambling Code described in TS 25.331, 0..511
     private final int mPsc;
+    // 16-bit UMTS Absolute RF Channel Number
+    private final int mUarfcn;
 
     /**
      * @hide
@@ -50,6 +52,7 @@
         mLac = Integer.MAX_VALUE;
         mCid = Integer.MAX_VALUE;
         mPsc = Integer.MAX_VALUE;
+        mUarfcn = Integer.MAX_VALUE;
     }
     /**
      * public constructor
@@ -62,11 +65,27 @@
      * @hide
      */
     public CellIdentityWcdma (int mcc, int mnc, int lac, int cid, int psc) {
+        this(mcc, mnc, lac, cid, psc, Integer.MAX_VALUE);
+    }
+
+    /**
+     * public constructor
+     * @param mcc 3-digit Mobile Country Code, 0..999
+     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
+     * @param lac 16-bit Location Area Code, 0..65535
+     * @param cid 28-bit UMTS Cell Identity
+     * @param psc 9-bit UMTS Primary Scrambling Code
+     * @param uarfcn 16-bit UMTS Absolute RF Channel Number
+     *
+     * @hide
+     */
+    public CellIdentityWcdma (int mcc, int mnc, int lac, int cid, int psc, int uarfcn) {
         mMcc = mcc;
         mMnc = mnc;
         mLac = lac;
         mCid = cid;
         mPsc = psc;
+        mUarfcn = uarfcn;
     }
 
     private CellIdentityWcdma(CellIdentityWcdma cid) {
@@ -75,6 +94,7 @@
         mLac = cid.mLac;
         mCid = cid.mCid;
         mPsc = cid.mPsc;
+        mUarfcn = cid.mUarfcn;
     }
 
     CellIdentityWcdma copy() {
@@ -123,6 +143,13 @@
         return Objects.hash(mMcc, mMnc, mLac, mCid, mPsc);
     }
 
+    /**
+     * @return 16-bit UMTS Absolute RF Channel Number, Integer.MAX_VALUE if unknown
+     */
+    public int getUarfcn() {
+        return mUarfcn;
+    }
+
     @Override
     public boolean equals(Object other) {
         if (this == other) {
@@ -138,7 +165,8 @@
                 mMnc == o.mMnc &&
                 mLac == o.mLac &&
                 mCid == o.mCid &&
-                mPsc == o.mPsc;
+                mPsc == o.mPsc &&
+                mUarfcn == o.mUarfcn;
     }
 
     @Override
@@ -149,6 +177,7 @@
         sb.append(" mLac=").append(mLac);
         sb.append(" mCid=").append(mCid);
         sb.append(" mPsc=").append(mPsc);
+        sb.append(" mUarfcn=").append(mUarfcn);
         sb.append("}");
 
         return sb.toString();
@@ -169,6 +198,7 @@
         dest.writeInt(mLac);
         dest.writeInt(mCid);
         dest.writeInt(mPsc);
+        dest.writeInt(mUarfcn);
     }
 
     /** Construct from Parcel, type has already been processed */
@@ -178,6 +208,7 @@
         mLac = in.readInt();
         mCid = in.readInt();
         mPsc = in.readInt();
+        mUarfcn = in.readInt();
         if (DBG) log("CellIdentityWcdma(Parcel): " + toString());
     }
 
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index d27fcec..addf7ef 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -34,6 +34,7 @@
 
     private int mSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
     private int mBitErrorRate;   // bit error rate (0-7, 99) as defined in TS 27.007 8.5
+    private int mTimingAdvance;
 
     /**
      * Empty constructor
@@ -75,6 +76,22 @@
     public void initialize(int ss, int ber) {
         mSignalStrength = ss;
         mBitErrorRate = ber;
+        mTimingAdvance = Integer.MAX_VALUE;
+    }
+
+    /**
+     * Initialize all the values
+     *
+     * @param ss SignalStrength as ASU value
+     * @param ber is Bit Error Rate
+     * @param ta timing advance
+     *
+     * @hide
+     */
+    public void initialize(int ss, int ber, int ta) {
+        mSignalStrength = ss;
+        mBitErrorRate = ber;
+        mTimingAdvance = ta;
     }
 
     /**
@@ -83,6 +100,7 @@
     protected void copyFrom(CellSignalStrengthGsm s) {
         mSignalStrength = s.mSignalStrength;
         mBitErrorRate = s.mBitErrorRate;
+        mTimingAdvance = s.mTimingAdvance;
     }
 
     /**
@@ -98,6 +116,7 @@
     public void setDefaultValues() {
         mSignalStrength = Integer.MAX_VALUE;
         mBitErrorRate = Integer.MAX_VALUE;
+        mTimingAdvance = Integer.MAX_VALUE;
     }
 
     /**
@@ -174,7 +193,8 @@
             return false;
         }
 
-        return mSignalStrength == s.mSignalStrength && mBitErrorRate == s.mBitErrorRate;
+        return mSignalStrength == s.mSignalStrength && mBitErrorRate == s.mBitErrorRate &&
+                        s.mTimingAdvance == mTimingAdvance;
     }
 
     /**
@@ -184,7 +204,8 @@
     public String toString() {
         return "CellSignalStrengthGsm:"
                 + " ss=" + mSignalStrength
-                + " ber=" + mBitErrorRate;
+                + " ber=" + mBitErrorRate
+                + " mTa=" + mTimingAdvance;
     }
 
     /** Implement the Parcelable interface */
@@ -193,6 +214,7 @@
         if (DBG) log("writeToParcel(Parcel, int): " + toString());
         dest.writeInt(mSignalStrength);
         dest.writeInt(mBitErrorRate);
+        dest.writeInt(mTimingAdvance);
     }
 
     /**
@@ -202,6 +224,7 @@
     private CellSignalStrengthGsm(Parcel in) {
         mSignalStrength = in.readInt();
         mBitErrorRate = in.readInt();
+        mTimingAdvance = in.readInt();
         if (DBG) log("CellSignalStrengthGsm(Parcel): " + toString());
     }
 
diff --git a/telephony/java/android/telephony/DataConnectionRealTimeInfo.java b/telephony/java/android/telephony/DataConnectionRealTimeInfo.java
index 96069213..f71f58d 100644
--- a/telephony/java/android/telephony/DataConnectionRealTimeInfo.java
+++ b/telephony/java/android/telephony/DataConnectionRealTimeInfo.java
@@ -28,10 +28,10 @@
 public class DataConnectionRealTimeInfo implements Parcelable {
     private long mTime;             // Time the info was collected since boot in nanos;
 
-    public static int DC_POWER_STATE_LOW       = 1;
-    public static int DC_POWER_STATE_MEDIUM    = 2;
-    public static int DC_POWER_STATE_HIGH      = 3;
-    public static int DC_POWER_STATE_UNKNOWN   = Integer.MAX_VALUE;
+    public static final int DC_POWER_STATE_LOW       = 1;
+    public static final int DC_POWER_STATE_MEDIUM    = 2;
+    public static final int DC_POWER_STATE_HIGH      = 3;
+    public static final int DC_POWER_STATE_UNKNOWN   = Integer.MAX_VALUE;
 
     private int mDcPowerState;      // DC_POWER_STATE_[LOW | MEDIUM | HIGH | UNKNOWN]
 
diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java
index ea96e7c..84883d8 100644
--- a/telephony/java/android/telephony/ModemActivityInfo.java
+++ b/telephony/java/android/telephony/ModemActivityInfo.java
@@ -48,7 +48,9 @@
         mTimestamp = timestamp;
         mSleepTimeMs = sleepTimeMs;
         mIdleTimeMs = idleTimeMs;
-        System.arraycopy(txTimeMs, 0, mTxTimeMs, 0, Math.min(txTimeMs.length, TX_POWER_LEVELS));
+        if (txTimeMs != null) {
+            System.arraycopy(txTimeMs, 0, mTxTimeMs, 0, Math.min(txTimeMs.length, TX_POWER_LEVELS));
+        }
         mRxTimeMs = rxTimeMs;
         mEnergyUsed = energyUsed;
     }
@@ -58,6 +60,7 @@
         return "ModemActivityInfo{"
             + " mTimestamp=" + mTimestamp
             + " mSleepTimeMs=" + mSleepTimeMs
+            + " mIdleTimeMs=" + mIdleTimeMs
             + " mTxTimeMs[]=" + Arrays.toString(mTxTimeMs)
             + " mRxTimeMs=" + mRxTimeMs
             + " mEnergyUsed=" + mEnergyUsed
@@ -153,7 +156,7 @@
         for (int i = 0; i < TX_POWER_LEVELS; i++) {
             totalTxTimeMs += txTime[i];
         }
-        return ((getIdleTimeMillis() != 0) || (totalTxTimeMs != 0)
-                || (getSleepTimeMillis() != 0) || (getIdleTimeMillis() != 0));
+        return ((getIdleTimeMillis() >= 0) && (totalTxTimeMs >= 0)
+                && (getSleepTimeMillis() >= 0) && (getIdleTimeMillis() >= 0));
     }
 }
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 553221d..962a600 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1857,9 +1857,6 @@
         // to the list.
         number = extractNetworkPortionAlt(number);
 
-        Rlog.d(LOG_TAG, "subId:" + subId + ", defaultCountryIso:" +
-                ((defaultCountryIso == null) ? "NULL" : defaultCountryIso));
-
         String emergencyNumbers = "";
         int slotId = SubscriptionManager.getSlotId(subId);
 
@@ -1869,7 +1866,8 @@
 
         emergencyNumbers = SystemProperties.get(ecclist, "");
 
-        Rlog.d(LOG_TAG, "slotId:" + slotId + ", emergencyNumbers: " +  emergencyNumbers);
+        Rlog.d(LOG_TAG, "slotId:" + slotId + " subId:" + subId + " country:"
+                + defaultCountryIso + " emergencyNumbers: " +  emergencyNumbers);
 
         if (TextUtils.isEmpty(emergencyNumbers)) {
             // then read-only ecclist property since old RIL only uses this
@@ -2082,7 +2080,7 @@
      * to read the VM number.
      */
     public static boolean isVoiceMailNumber(String number) {
-        return isVoiceMailNumber(SubscriptionManager.getDefaultSubId(), number);
+        return isVoiceMailNumber(SubscriptionManager.getDefaultSubscriptionId(), number);
     }
 
     /**
@@ -2977,7 +2975,7 @@
      * Returns Default voice subscription Id.
      */
     private static int getDefaultVoiceSubId() {
-        return SubscriptionManager.getDefaultVoiceSubId();
+        return SubscriptionManager.getDefaultVoiceSubscriptionId();
     }
     //==== End of utility methods used only in compareStrictly() =====
 }
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 16472c8..ae130d4 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -194,10 +194,12 @@
      * {@more}
      * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
      * READ_PRECISE_PHONE_STATE}
-     *
      * @see #onDataConnectionRealTimeInfoChanged(DataConnectionRealTimeInfo)
+     *
+     * @deprecated Use {@link TelephonyManager#getModemActivityInfo()}
      * @hide
      */
+    @Deprecated
     public static final int LISTEN_DATA_CONNECTION_REAL_TIME_INFO           = 0x00002000;
 
     /**
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 8537f9c..ad007c6 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -37,6 +37,7 @@
 
     static final String LOG_TAG = "PHONE";
     static final boolean DBG = true;
+    static final boolean VDBG = false;  // STOPSHIP if true
 
     /**
      * Normal operation condition, the phone is registered
@@ -153,6 +154,17 @@
      * @hide
      */
     public static final int RIL_RADIO_TECHNOLOGY_IWLAN = 18;
+
+    /** @hide */
+    public static final int RIL_RADIO_CDMA_TECHNOLOGY_BITMASK =
+            (1 << (RIL_RADIO_TECHNOLOGY_IS95A - 1))
+                    | (1 << (RIL_RADIO_TECHNOLOGY_IS95B - 1))
+                    | (1 << (RIL_RADIO_TECHNOLOGY_1xRTT - 1))
+                    | (1 << (RIL_RADIO_TECHNOLOGY_EVDO_0 - 1))
+                    | (1 << (RIL_RADIO_TECHNOLOGY_EVDO_A - 1))
+                    | (1 << (RIL_RADIO_TECHNOLOGY_EVDO_B - 1))
+                    | (1 << (RIL_RADIO_TECHNOLOGY_EHRPD - 1));
+
     /**
      * Available registration states for GSM, UMTS and CDMA.
      */
@@ -818,7 +830,7 @@
     /** @hide */
     public void setDataRegState(int state) {
         mDataRegState = state;
-        if (DBG) Rlog.d(LOG_TAG, "[ServiceState] setDataRegState=" + mDataRegState);
+        if (VDBG) Rlog.d(LOG_TAG, "[ServiceState] setDataRegState=" + mDataRegState);
     }
 
     public void setRoaming(boolean roaming) {
@@ -1006,7 +1018,8 @@
     /** @hide */
     public void setRilDataRadioTechnology(int rt) {
         this.mRilDataRadioTechnology = rt;
-        if (DBG) Rlog.d(LOG_TAG, "[ServiceState] setDataRadioTechnology=" + mRilDataRadioTechnology);
+        if (VDBG) Rlog.d(LOG_TAG, "[ServiceState] setRilDataRadioTechnology=" +
+                mRilDataRadioTechnology);
     }
 
     /** @hide */
@@ -1141,16 +1154,8 @@
     }
 
     /** @hide */
-    public static boolean hasCdma(int radioTechnologyBitmask) {
-        int cdmaBitmask = (RIL_RADIO_TECHNOLOGY_IS95A
-                | RIL_RADIO_TECHNOLOGY_IS95B
-                | RIL_RADIO_TECHNOLOGY_1xRTT
-                | RIL_RADIO_TECHNOLOGY_EVDO_0
-                | RIL_RADIO_TECHNOLOGY_EVDO_A
-                | RIL_RADIO_TECHNOLOGY_EVDO_B
-                | RIL_RADIO_TECHNOLOGY_EHRPD);
-
-        return ((radioTechnologyBitmask & cdmaBitmask) != 0);
+    public static boolean bearerBitmapHasCdma(int radioTechnologyBitmap) {
+        return (RIL_RADIO_CDMA_TECHNOLOGY_BITMASK & radioTechnologyBitmap) != 0;
     }
 
     /** @hide */
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 36407e1..ff8c71c 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -53,7 +53,6 @@
     private static final boolean VDBG = false;
 
     /** An invalid subscription identifier */
-    /** @hide */
     public static final int INVALID_SUBSCRIPTION_ID = -1;
 
     /** Base value for Dummy SUBSCRIPTION_ID's. */
@@ -455,8 +454,9 @@
     }
 
     /**
-     * Get the active SubscriptionInfo with the subId key
-     * @param subId The unique SubscriptionInfo key in database
+     * Get the active SubscriptionInfo with the input subId.
+     *
+     * @param subId The unique SubscriptionInfo key in database.
      * @return SubscriptionInfo, maybe null if its not active.
      */
     public SubscriptionInfo getActiveSubscriptionInfo(int subId) {
@@ -898,12 +898,15 @@
     }
 
     /**
-     * @return the "system" defaultSubId on a voice capable device this
-     * will be getDefaultVoiceSubId() and on a data only device it will be
-     * getDefaultDataSubId().
-     * @hide
+     * Returns the system's default subscription id.
+     *
+     * For a voice capable device, it will return getDefaultVoiceSubscriptionId.
+     * For a data only device, it will return the getDefaultDataSubscriptionId.
+     * May return an INVALID_SUBSCRIPTION_ID on error.
+     *
+     * @return the "system" default subscription id.
      */
-    public static int getDefaultSubId() {
+    public static int getDefaultSubscriptionId() {
         int subId = INVALID_SUBSCRIPTION_ID;
 
         try {
@@ -919,8 +922,14 @@
         return subId;
     }
 
-    /** @hide */
-    public static int getDefaultVoiceSubId() {
+    /**
+     * Returns the system's default voice subscription id.
+     *
+     * On a data only device or on error, will return INVALID_SUBSCRIPTION_ID.
+     *
+     * @return the default voice subscription Id.
+     */
+    public static int getDefaultVoiceSubscriptionId() {
         int subId = INVALID_SUBSCRIPTION_ID;
 
         try {
@@ -932,7 +941,7 @@
             // ignore it
         }
 
-        if (VDBG) logd("getDefaultVoiceSubId, sub id = " + subId);
+        if (VDBG) logd("getDefaultVoiceSubscriptionId, sub id = " + subId);
         return subId;
     }
 
@@ -949,23 +958,31 @@
         }
     }
 
-    /** @hide */
+    /**
+     * Return the SubscriptionInfo for default voice subscription.
+     *
+     * Will return null on data only devices, or on error.
+     *
+     * @return the SubscriptionInfo for the default voice subscription.
+     * @hide
+     */
     public SubscriptionInfo getDefaultVoiceSubscriptionInfo() {
-        return getActiveSubscriptionInfo(getDefaultVoiceSubId());
+        return getActiveSubscriptionInfo(getDefaultVoiceSubscriptionId());
     }
 
     /** @hide */
     public static int getDefaultVoicePhoneId() {
-        return getPhoneId(getDefaultVoiceSubId());
+        return getPhoneId(getDefaultVoiceSubscriptionId());
     }
 
     /**
-     * @return subId of the DefaultSms subscription or
-     * a value < 0 if an error.
+     * Returns the system's default SMS subscription id.
      *
-     * @hide
+     * On a data only device or on error, will return INVALID_SUBSCRIPTION_ID.
+     *
+     * @return the default SMS subscription Id.
      */
-    public static int getDefaultSmsSubId() {
+    public static int getDefaultSmsSubscriptionId() {
         int subId = INVALID_SUBSCRIPTION_ID;
 
         try {
@@ -977,7 +994,7 @@
             // ignore it
         }
 
-        if (VDBG) logd("getDefaultSmsSubId, sub id = " + subId);
+        if (VDBG) logd("getDefaultSmsSubscriptionId, sub id = " + subId);
         return subId;
     }
 
@@ -994,18 +1011,31 @@
         }
     }
 
-    /** @hide */
+    /**
+     * Return the SubscriptionInfo for default voice subscription.
+     *
+     * Will return null on data only devices, or on error.
+     *
+     * @return the SubscriptionInfo for the default SMS subscription.
+     * @hide
+     */
     public SubscriptionInfo getDefaultSmsSubscriptionInfo() {
-        return getActiveSubscriptionInfo(getDefaultSmsSubId());
+        return getActiveSubscriptionInfo(getDefaultSmsSubscriptionId());
     }
 
     /** @hide */
     public int getDefaultSmsPhoneId() {
-        return getPhoneId(getDefaultSmsSubId());
+        return getPhoneId(getDefaultSmsSubscriptionId());
     }
 
-    /** @hide */
-    public static int getDefaultDataSubId() {
+    /**
+     * Returns the system's default data subscription id.
+     *
+     * On a voice only device or on error, will return INVALID_SUBSCRIPTION_ID.
+     *
+     * @return the default data subscription Id.
+     */
+    public static int getDefaultDataSubscriptionId() {
         int subId = INVALID_SUBSCRIPTION_ID;
 
         try {
@@ -1017,7 +1047,7 @@
             // ignore it
         }
 
-        if (VDBG) logd("getDefaultDataSubId, sub id = " + subId);
+        if (VDBG) logd("getDefaultDataSubscriptionId, sub id = " + subId);
         return subId;
     }
 
@@ -1034,14 +1064,21 @@
         }
     }
 
-    /** @hide */
+    /**
+     * Return the SubscriptionInfo for default data subscription.
+     *
+     * Will return null on voice only devices, or on error.
+     *
+     * @return the SubscriptionInfo for the default data subscription.
+     * @hide
+     */
     public SubscriptionInfo getDefaultDataSubscriptionInfo() {
-        return getActiveSubscriptionInfo(getDefaultDataSubId());
+        return getActiveSubscriptionInfo(getDefaultDataSubscriptionId());
     }
 
     /** @hide */
     public int getDefaultDataPhoneId() {
-        return getPhoneId(getDefaultDataSubId());
+        return getPhoneId(getDefaultDataSubscriptionId());
     }
 
     /** @hide */
@@ -1061,13 +1098,13 @@
     //FIXME this is vulnerable to race conditions
     /** @hide */
     public boolean allDefaultsSelected() {
-        if (!isValidSubscriptionId(getDefaultDataSubId())) {
+        if (!isValidSubscriptionId(getDefaultDataSubscriptionId())) {
             return false;
         }
-        if (!isValidSubscriptionId(getDefaultSmsSubId())) {
+        if (!isValidSubscriptionId(getDefaultSmsSubscriptionId())) {
             return false;
         }
-        if (!isValidSubscriptionId(getDefaultVoiceSubId())) {
+        if (!isValidSubscriptionId(getDefaultVoiceSubscriptionId())) {
             return false;
         }
         return true;
@@ -1207,7 +1244,7 @@
             }
         } catch (RemoteException ex) {
         }
-        logd("getSimStateForSubscriber: simState=" + simState + " slotIdx=" + slotIdx);
+
         return simState;
     }
 
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 3b281e2..fcb42a4 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -24,6 +24,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.net.Uri;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.os.Bundle;
@@ -31,6 +32,7 @@
 import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
 import android.util.Log;
 
 import com.android.internal.telecom.ITelecomService;
@@ -294,7 +296,7 @@
     /**
      * @hide
      */
-    public static final boolean EMERGENCY_ASSISTANCE_ENABLED = false;
+    public static final boolean EMERGENCY_ASSISTANCE_ENABLED = true;
 
     /**
      * The lookup key used with the {@link #ACTION_PHONE_STATE_CHANGED} broadcast
@@ -766,7 +768,7 @@
             IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
-            return info.getDeviceIdForPhone(slotId);
+            return info.getDeviceIdForPhone(slotId, mContext.getOpPackageName());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -1230,7 +1232,6 @@
      * on a CDMA network).
      * @param subId
      */
-    /** {@hide} */
     public String getNetworkOperatorName(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_ALPHA, "");
@@ -1257,8 +1258,7 @@
      *
      * @param subId
      */
-    /** {@hide} */
-   public String getNetworkOperatorForSubscription(int subId) {
+    public String getNetworkOperator(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return getNetworkOperatorForPhone(phoneId);
      }
@@ -1274,7 +1274,7 @@
      * @param phoneId
      * @hide
      **/
-   public String getNetworkOperatorForPhone(int phoneId) {
+    public String getNetworkOperatorForPhone(int phoneId) {
         return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, "");
      }
 
@@ -1296,7 +1296,6 @@
      *
      * @param subId
      */
-    /** {@hide} */
     public boolean isNetworkRoaming(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return Boolean.parseBoolean(getTelephonyProperty(phoneId,
@@ -1325,8 +1324,7 @@
      *
      * @param subId for which Network CountryIso is returned
      */
-    /** {@hide} */
-    public String getNetworkCountryIsoForSubscription(int subId) {
+    public String getNetworkCountryIso(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return getNetworkCountryIsoForPhone(phoneId);
     }
@@ -1434,7 +1432,6 @@
      * Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
-    /** {@hide} */
    public int getNetworkType(int subId) {
        try {
            ITelephony telephony = getITelephony();
@@ -1495,7 +1492,6 @@
      * Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
-    /** {@hide} */
     public int getDataNetworkType(int subId) {
         try{
             ITelephony telephony = getITelephony();
@@ -1533,7 +1529,6 @@
      * Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
-    /** {@hide} */
     public int getVoiceNetworkType(int subId) {
         try{
             ITelephony telephony = getITelephony();
@@ -1802,10 +1797,9 @@
      * @see #getSimState
      *
      * @param subId for which SimOperator is returned
-     * @hide
      */
     public String getSimOperator(int subId) {
-        return getSimOperatorNumericForSubscription(subId);
+        return getSimOperatorNumeric(subId);
     }
 
     /**
@@ -1818,17 +1812,17 @@
      * @hide
      */
     public String getSimOperatorNumeric() {
-        int subId = SubscriptionManager.getDefaultDataSubId();
+        int subId = SubscriptionManager.getDefaultDataSubscriptionId();
         if (!SubscriptionManager.isUsableSubIdValue(subId)) {
-            subId = SubscriptionManager.getDefaultSmsSubId();
+            subId = SubscriptionManager.getDefaultSmsSubscriptionId();
             if (!SubscriptionManager.isUsableSubIdValue(subId)) {
-                subId = SubscriptionManager.getDefaultVoiceSubId();
+                subId = SubscriptionManager.getDefaultVoiceSubscriptionId();
                 if (!SubscriptionManager.isUsableSubIdValue(subId)) {
-                    subId = SubscriptionManager.getDefaultSubId();
+                    subId = SubscriptionManager.getDefaultSubscriptionId();
                 }
             }
         }
-        return getSimOperatorNumericForSubscription(subId);
+        return getSimOperatorNumeric(subId);
     }
 
     /**
@@ -1842,7 +1836,7 @@
      * @param subId for which SimOperator is returned
      * @hide
      */
-    public String getSimOperatorNumericForSubscription(int subId) {
+    public String getSimOperatorNumeric(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return getSimOperatorNumericForPhone(phoneId);
     }
@@ -1879,9 +1873,8 @@
      * @see #getSimState
      *
      * @param subId for which SimOperatorName is returned
-     * @hide
      */
-    public String getSimOperatorNameForSubscription(int subId) {
+    public String getSimOperatorName(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return getSimOperatorNameForPhone(phoneId);
     }
@@ -1907,21 +1900,8 @@
      * Returns the ISO country code equivalent for the SIM provider's country code.
      *
      * @param subId for which SimCountryIso is returned
-     *
-     * @hide
      */
     public String getSimCountryIso(int subId) {
-        return getSimCountryIsoForSubscription(subId);
-    }
-
-    /**
-     * Returns the ISO country code equivalent for the SIM provider's country code.
-     *
-     * @param subId for which SimCountryIso is returned
-     *
-     * @hide
-     */
-    public String getSimCountryIsoForSubscription(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return getSimCountryIsoForPhone(phoneId);
     }
@@ -1955,7 +1935,6 @@
      * Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
-    /** {@hide} */
     public String getSimSerialNumber(int subId) {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
@@ -2044,7 +2023,6 @@
      *
      * @param subId whose subscriber id is returned
      */
-    /** {@hide} */
     public String getSubscriberId(int subId) {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
@@ -2087,9 +2065,8 @@
      * Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      *
-     * @param subscription whose subscriber id is returned
+     * @param subId whose subscriber id is returned
      */
-    /** {@hide} */
     public String getGroupIdLevel1(int subId) {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
@@ -2116,7 +2093,7 @@
      * The default SMS app can also use this.
      */
     public String getLine1Number() {
-        return getLine1NumberForSubscriber(getDefaultSubscription());
+        return getLine1Number(getDefaultSubscription());
     }
 
     /**
@@ -2132,8 +2109,7 @@
      *
      * @param subId whose phone number for line 1 is returned
      */
-    /** {@hide} */
-    public String getLine1NumberForSubscriber(int subId) {
+    public String getLine1Number(int subId) {
         String number = null;
         try {
             ITelephony telephony = getITelephony();
@@ -2172,7 +2148,7 @@
      * @return true if the operation was executed correctly.
      */
     public boolean setLine1NumberForDisplay(String alphaTag, String number) {
-        return setLine1NumberForDisplayForSubscriber(getDefaultSubscription(), alphaTag, number);
+        return setLine1NumberForDisplay(getDefaultSubscription(), alphaTag, number);
     }
 
     /**
@@ -2188,9 +2164,8 @@
      * @param alphaTag alpha-tagging of the dailing nubmer
      * @param number The dialing number
      * @return true if the operation was executed correctly.
-     * @hide
      */
-    public boolean setLine1NumberForDisplayForSubscriber(int subId, String alphaTag, String number) {
+    public boolean setLine1NumberForDisplay(int subId, String alphaTag, String number) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
@@ -2211,7 +2186,7 @@
      * nobody seems to call this.
      */
     public String getLine1AlphaTag() {
-        return getLine1AlphaTagForSubscriber(getDefaultSubscription());
+        return getLine1AlphaTag(getDefaultSubscription());
     }
 
     /**
@@ -2224,8 +2199,7 @@
      * @param subId whose alphabetic identifier associated with line 1 is returned
      * nobody seems to call this.
      */
-    /** {@hide} */
-    public String getLine1AlphaTagForSubscriber(int subId) {
+    public String getLine1AlphaTag(int subId) {
         String alphaTag = null;
         try {
             ITelephony telephony = getITelephony();
@@ -2325,7 +2299,6 @@
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      * @param subId whose voice mail number is returned
      */
-    /** {@hide} */
     public String getVoiceMailNumber(int subId) {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
@@ -2398,7 +2371,6 @@
      * @param alphaTag The alpha tag to display.
      * @param number The voicemail number.
      */
-    /** {@hide} */
     public boolean setVoiceMailNumber(int subId, String alphaTag, String number) {
         try {
             ITelephony telephony = getITelephony();
@@ -2464,7 +2436,6 @@
      * @param subId whose alphabetic identifier associated with the
      * voice mail number is returned
      */
-    /** {@hide} */
     public String getVoiceMailAlphaTag(int subId) {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
@@ -2582,7 +2553,6 @@
      *
      * @param subId whose call state is returned
      */
-    /** {@hide} */
     public int getCallState(int subId) {
         try {
             ITelephony telephony = getITelephony();
@@ -3223,19 +3193,19 @@
      * Returns Default subscription.
      */
     private static int getDefaultSubscription() {
-        return SubscriptionManager.getDefaultSubId();
+        return SubscriptionManager.getDefaultSubscriptionId();
     }
 
     /**
      * Returns Default phone.
      */
     private static int getDefaultPhone() {
-        return SubscriptionManager.getPhoneId(SubscriptionManager.getDefaultSubId());
+        return SubscriptionManager.getPhoneId(SubscriptionManager.getDefaultSubscriptionId());
     }
 
     /** {@hide} */
     public int getDefaultSim() {
-        return SubscriptionManager.getSlotId(SubscriptionManager.getDefaultSubId());
+        return SubscriptionManager.getSlotId(SubscriptionManager.getDefaultSubscriptionId());
     }
 
     /**
@@ -3492,10 +3462,13 @@
     /**
      * Returns the response of SIM Authentication through RIL for the default subscription.
      * Returns null if the Authentication hasn't been successful
+     *
+     * <p>Requires that the calling app has carrier privileges.
+     * @see #hasCarrierPrivileges
+     *
      * @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);
@@ -3996,19 +3969,6 @@
 
     /** @hide */
     @SystemApi
-    public boolean isSimPinEnabled() {
-        try {
-            ITelephony telephony = getITelephony();
-            if (telephony != null)
-                return telephony.isSimPinEnabled(getOpPackageName());
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#isSimPinEnabled", e);
-        }
-        return false;
-    }
-
-    /** @hide */
-    @SystemApi
     public boolean supplyPin(String pin) {
         try {
             ITelephony telephony = getITelephony();
@@ -4190,7 +4150,7 @@
     /** @hide */
     @SystemApi
     public void setDataEnabled(boolean enable) {
-        setDataEnabled(SubscriptionManager.getDefaultDataSubId(), enable);
+        setDataEnabled(SubscriptionManager.getDefaultDataSubscriptionId(), enable);
     }
 
     /** @hide */
@@ -4209,7 +4169,7 @@
     /** @hide */
     @SystemApi
     public boolean getDataEnabled() {
-        return getDataEnabled(SubscriptionManager.getDefaultDataSubId());
+        return getDataEnabled(SubscriptionManager.getDefaultDataSubscriptionId());
     }
 
     /** @hide */
@@ -4865,4 +4825,43 @@
         }
         return null;
     }
-}
\ No newline at end of file
+
+    /**
+     * Returns the URI for the per-account voicemail ringtone set in Phone settings.
+     *
+     * @param accountHandle The handle for the {@link PhoneAccount} for which to retrieve the
+     * voicemail ringtone.
+     * @return The URI for the ringtone to play when receiving a voicemail from a specific
+     * PhoneAccount.
+     */
+    public Uri getVoicemailRingtoneUri(PhoneAccountHandle accountHandle) {
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                return service.getVoicemailRingtoneUri(accountHandle);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#getVoicemailRingtoneUri", e);
+        }
+        return null;
+    }
+
+    /**
+     * Returns whether vibration is set for voicemail notification in Phone settings.
+     *
+     * @param accountHandle The handle for the {@link PhoneAccount} for which to retrieve the
+     * voicemail vibration setting.
+     * @return {@code true} if the vibration is set for this PhoneAccount, {@code false} otherwise.
+     */
+    public boolean isVoicemailVibrationEnabled(PhoneAccountHandle accountHandle) {
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                return service.isVoicemailVibrationEnabled(accountHandle);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#isVoicemailVibrationEnabled", e);
+        }
+        return false;
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index 59a8a67..5f3f773 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -53,6 +53,9 @@
     private static final String TAG = "CallerInfo";
     private static final boolean VDBG = Rlog.isLoggable(TAG, Log.VERBOSE);
 
+    public static final long USER_TYPE_CURRENT = 0;
+    public static final long USER_TYPE_WORK = 1;
+
     /**
      * Please note that, any one of these member variables can be null,
      * and any accesses to them should be prepared to handle such a case.
@@ -103,6 +106,8 @@
     public Uri contactRefUri;
     public String lookupKey;
 
+    public long userType;
+
     /**
      * Contact display photo URI.  If a contact has no display photo but a thumbnail, it'll be
      * the thumbnail URI instead.
@@ -154,6 +159,7 @@
         // TODO: Move all the basic initialization here?
         mIsEmergency = false;
         mIsVoiceMail = false;
+        userType = USER_TYPE_CURRENT;
     }
 
     /**
@@ -173,6 +179,7 @@
         info.cachedPhoto = null;
         info.isCachedPhotoCurrent = false;
         info.contactExists = false;
+        info.userType = USER_TYPE_CURRENT;
 
         if (VDBG) Rlog.v(TAG, "getCallerInfo() based on cursor...");
 
@@ -225,6 +232,9 @@
                             Rlog.v(TAG, "==> got info.contactIdOrZero: " + info.contactIdOrZero);
                         }
                     }
+                    if (Contacts.isEnterpriseContactId(contactId)) {
+                        info.userType = USER_TYPE_WORK;
+                    }
                 } else {
                     // No valid columnIndex, so we can't look up person_id.
                     Rlog.w(TAG, "Couldn't find contact_id column for " + contactRef);
@@ -317,7 +327,7 @@
     public static CallerInfo getCallerInfo(Context context, String number) {
         if (VDBG) Rlog.v(TAG, "getCallerInfo() based on number...");
 
-        int subId = SubscriptionManager.getDefaultSubId();
+        int subId = SubscriptionManager.getDefaultSubscriptionId();
         return getCallerInfo(context, number, subId);
     }
 
@@ -434,7 +444,7 @@
     // string in the phone number field.
     /* package */ CallerInfo markAsVoiceMail() {
 
-        int subId = SubscriptionManager.getDefaultSubId();
+        int subId = SubscriptionManager.getDefaultSubscriptionId();
         return markAsVoiceMail(subId);
 
     }
@@ -628,6 +638,7 @@
     /**
      * @return a string debug representation of this instance.
      */
+    @Override
     public String toString() {
         // Warning: never check in this file with VERBOSE_DEBUG = true
         // because that will result in PII in the system log.
@@ -658,6 +669,7 @@
                     .append("\nemergency: " + mIsEmergency)
                     .append("\nvoicemail " + mIsVoiceMail)
                     .append("\ncontactExists " + contactExists)
+                    .append("\nuserType " + userType)
                     .append(" }")
                     .toString();
         } else {
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index c754068..05cb31e 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -387,7 +387,7 @@
     public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
             OnQueryCompleteListener listener, Object cookie) {
 
-        int subId = SubscriptionManager.getDefaultSubId();
+        int subId = SubscriptionManager.getDefaultSubscriptionId();
         return startQuery(token, context, number, listener, cookie, subId);
     }
 
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index a4e9486..fcb967f 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -44,7 +44,9 @@
         CONNECTED,
         DISCONNECTING,
         FAILED,
-        RETRYING
+        RETRYING        // After moving retry manager to ApnContext, we'll never enter this state!
+                        // Todo: Remove this state and other places that use this state and then
+                        // rename SCANNING to RETRYING.
     }
 
     public enum Activity {
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index ed85392..dc2b297 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -36,7 +36,7 @@
      * Retrieves the unique device ID of a phone for the device, e.g., IMEI
      * for GSM phones.
      */
-    String getDeviceIdForPhone(int phoneId);
+    String getDeviceIdForPhone(int phoneId, String callingPackage);
 
     /**
      * Retrieves the IMEI.
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 8172e94..62f294c 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -18,7 +18,9 @@
 
 import android.content.Intent;
 import android.os.Bundle;
+import android.net.Uri;
 import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
 import android.telephony.CellInfo;
 import android.telephony.IccOpenLogicalChannelResponse;
 import android.telephony.ModemActivityInfo;
@@ -180,13 +182,6 @@
     boolean isRadioOnForSubscriber(int subId, String callingPackage);
 
     /**
-     * Check if the SIM pin lock is enabled.
-     * @return true if the SIM pin lock is enabled.
-     * @param callingPackage The package making the call.
-     */
-    boolean isSimPinEnabled(String callingPackage);
-
-    /**
      * Supply a pin to unlock the SIM.  Blocks until a result is determined.
      * @param pin The pin to check.
      * @return whether the operation was a success.
@@ -966,7 +961,7 @@
      * Returns the Status of Wi-Fi Calling
      */
     boolean isWifiCallingAvailable();
-    
+
     /**
      * Returns the Status of Volte
      */
@@ -1014,4 +1009,23 @@
      * @return Service state on specified subscription.
      */
     ServiceState getServiceStateForSubscriber(int subId, String callingPackage);
+
+    /**
+     * Returns the URI for the per-account voicemail ringtone set in Phone settings.
+     *
+     * @param accountHandle The handle for the {@link PhoneAccount} for which to retrieve the
+     * voicemail ringtone.
+     * @return The URI for the ringtone to play when receiving a voicemail from a specific
+     * PhoneAccount.
+     */
+    Uri getVoicemailRingtoneUri(in PhoneAccountHandle accountHandle);
+
+    /**
+     * Returns whether vibration is set for voicemail notification in Phone settings.
+     *
+     * @param accountHandle The handle for the {@link PhoneAccount} for which to retrieve the
+     * voicemail vibration setting.
+     * @return {@code true} if the vibration is set for this PhoneAccount, {@code false} otherwise.
+     */
+    boolean isVoicemailVibrationEnabled(in PhoneAccountHandle accountHandle);
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl b/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
new file mode 100644
index 0000000..069fcbf
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import com.android.internal.telephony.ITelephonyDebugSubscriber;
+
+import android.os.Bundle;
+
+/**
+ * Interface used to interact with the Telephony debug service.
+ *
+ * {@hide}
+ */
+interface ITelephonyDebug {
+
+    /**
+     * Write telephony event
+     * @param timestamp returned by System.currentTimeMillis()
+     * @param phoneId for which event is written
+     * @param tag constant defined in TelephonyEventLog
+     * @param param1 optional
+     * @param param2 optional
+     * @param data optional
+     */
+    void writeEvent(long timestamp, int phoneId, int tag, int param1, int param2, in Bundle data);
+
+    void subscribe(in ITelephonyDebugSubscriber subscriber);
+    void unsubscribe(in ITelephonyDebugSubscriber subscriber);
+}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl b/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl
new file mode 100644
index 0000000..64eb0f1
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.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 com.android.internal.telephony;
+
+import com.android.internal.telephony.TelephonyEvent;
+
+import android.os.Bundle;
+
+/**
+ * Interface used to subscribe for events from Telephony debug service.
+ *
+ * {@hide}
+ */
+oneway interface ITelephonyDebugSubscriber {
+
+    /**
+     * Called when Telephony debug service has events.
+     */
+    void onEvents(in TelephonyEvent[] events);
+}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 76b69ce..907d76e 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -21,7 +21,6 @@
 import android.net.NetworkCapabilities;
 import android.os.Bundle;
 import android.telephony.CellInfo;
-import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.CellInfo;
@@ -65,7 +64,6 @@
     void notifyPreciseDataConnectionFailed(String reason, String apnType, String apn,
             String failCause);
     void notifyCellInfoForSubscriber(in int subId, in List<CellInfo> cellInfo);
-    void notifyDataConnectionRealTimeInfo(in DataConnectionRealTimeInfo dcRtInfo);
     void notifyVoLteServiceStateChanged(in VoLteServiceState lteState);
     void notifyOemHookRawEventForSubscriber(in int subId, in byte[] rawData);
     void notifySubscriptionInfoChanged();
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index a183de5..ecd89ed 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -35,17 +35,17 @@
         IDLE, RINGING, OFFHOOK;
     };
 
-   /**
-     * The state of a data connection.
-     * <ul>
-     * <li>CONNECTED = IP traffic should be available</li>
-     * <li>CONNECTING = Currently setting up data connection</li>
-     * <li>DISCONNECTED = IP not available</li>
-     * <li>SUSPENDED = connection is created but IP traffic is
-     *                 temperately not available. i.e. voice call is in place
-     *                 in 2G network</li>
-     * </ul>
-     */
+    /**
+      * The state of a data connection.
+      * <ul>
+      * <li>CONNECTED = IP traffic should be available</li>
+      * <li>CONNECTING = Currently setting up data connection</li>
+      * <li>DISCONNECTED = IP not available</li>
+      * <li>SUSPENDED = connection is created but IP traffic is
+      *                 temperately not available. i.e. voice call is in place
+      *                 in 2G network</li>
+      * </ul>
+      */
     public enum DataState {
         CONNECTED, CONNECTING, DISCONNECTED, SUSPENDED;
     };
@@ -89,6 +89,7 @@
     public static final String NETWORK_UNAVAILABLE_KEY = "networkUnvailable";
     public static final String DATA_NETWORK_ROAMING_KEY = "networkRoaming";
     public static final String PHONE_IN_ECM_STATE = "phoneinECMState";
+    public static final String PHONE_IN_EMERGENCY_CALL = "phoneInEmergencyCall";
 
     public static final String REASON_LINK_PROPERTIES_CHANGED = "linkPropertiesChanged";
 
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 3c4c04b..7d5645e 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -336,6 +336,8 @@
     int RIL_REQUEST_PULL_LCEDATA = 134;
     int RIL_REQUEST_GET_ACTIVITY_INFO = 135;
 
+    int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
+
     int RIL_UNSOL_RESPONSE_BASE = 1000;
     int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
     int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl b/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl
new file mode 100644
index 0000000..1e74b31
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/TelephonyEvent.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.internal.telephony;
+
+parcelable TelephonyEvent;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyEvent.java b/telephony/java/com/android/internal/telephony/TelephonyEvent.java
new file mode 100644
index 0000000..26d466d
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/TelephonyEvent.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.internal.telephony;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ *  A parcelable used in ITelephonyDebugSubscriber.aidl
+ */
+public class TelephonyEvent implements Parcelable {
+
+    final public long timestamp;
+    final public int phoneId;
+    final public int tag;
+    final public int param1;
+    final public int param2;
+    final public Bundle data;
+
+    public TelephonyEvent(long timestamp, int phoneId, int tag,
+            int param1, int param2, Bundle data) {
+        this.timestamp = timestamp;
+        this.phoneId = phoneId;
+        this.tag = tag;
+        this.param1 = param1;
+        this.param2 = param2;
+        this.data = data;
+    }
+
+    /** Implement the Parcelable interface */
+    public static final Parcelable.Creator<TelephonyEvent> CREATOR
+            = new Parcelable.Creator<TelephonyEvent> (){
+        public TelephonyEvent createFromParcel(Parcel source) {
+            final long timestamp = source.readLong();
+            final int phoneId = source.readInt();
+            final int tag = source.readInt();
+            final int param1 = source.readInt();
+            final int param2 = source.readInt();
+            final Bundle data = source.readBundle();
+            return new TelephonyEvent(timestamp, phoneId, tag, param1, param2, data);
+        }
+
+        public TelephonyEvent[] newArray(int size) {
+            return new TelephonyEvent[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(phoneId);
+        dest.writeInt(tag);
+        dest.writeInt(param1);
+        dest.writeInt(param2);
+        dest.writeBundle(data);
+    }
+
+    public String toString() {
+        return String.format("%d,%d,%d,%d,%d,%s",
+                timestamp, phoneId, tag, param1, param2, data);
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index d2e4de3..c70f8cf 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -75,6 +75,7 @@
      */
     public static final String ACTION_RADIO_TECHNOLOGY_CHANGED
             = "android.intent.action.RADIO_TECHNOLOGY";
+
     /**
      * <p>Broadcast Action: The emergency callback mode is changed.
      * <ul>
@@ -94,6 +95,28 @@
      */
     public static final String ACTION_EMERGENCY_CALLBACK_MODE_CHANGED
             = "android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED";
+
+    /**
+     * <p>Broadcast Action: The emergency call state is changed.
+     * <ul>
+     *   <li><em>phoneInEmergencyCall</em> - A boolean value, true if phone in emergency call,
+     *   false otherwise</li>
+     * </ul>
+     * <p class="note">
+     * You can <em>not</em> receive this through components declared
+     * in manifests, only by explicitly registering for it with
+     * {@link android.content.Context#registerReceiver(android.content.BroadcastReceiver,
+     * android.content.IntentFilter) Context.registerReceiver()}.
+     *
+     * <p class="note">
+     * Requires no permission.
+     *
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
+     */
+    public static final String ACTION_EMERGENCY_CALL_STATE_CHANGED
+            = "android.intent.action.EMERGENCY_CALL_STATE_CHANGED";
+
     /**
      * Broadcast Action: The phone's signal strength has changed. The intent will have the
      * following extra values:</p>
diff --git a/test-runner/src/android/test/ActivityInstrumentationTestCase.java b/test-runner/src/android/test/ActivityInstrumentationTestCase.java
index a59ee35..aca1c16 100644
--- a/test-runner/src/android/test/ActivityInstrumentationTestCase.java
+++ b/test-runner/src/android/test/ActivityInstrumentationTestCase.java
@@ -23,15 +23,15 @@
  * be created using the system infrastructure (by calling InstrumentationTestCase.launchActivity())
  * and you will then be able to manipulate your Activity directly.  Most of the work is handled
  * automatically here by {@link #setUp} and {@link #tearDown}.
- * 
+ *
  * <p>If you prefer an isolated unit test, see {@link android.test.ActivityUnitTestCase}.
- * 
- * @deprecated new tests should be written using 
+ *
+ * @deprecated new tests should be written using
  * {@link android.test.ActivityInstrumentationTestCase2}, which provides more options for
  * configuring the Activity under test
  */
 @Deprecated
-public abstract class ActivityInstrumentationTestCase<T extends Activity> 
+public abstract class ActivityInstrumentationTestCase<T extends Activity>
         extends ActivityTestCase {
     String mPackage;
     Class<T> mActivityClass;
@@ -39,7 +39,7 @@
 
     /**
      * Creates an {@link ActivityInstrumentationTestCase} in non-touch mode.
-     * 
+     *
      * @param pkg ignored - no longer in use.
      * @param activityClass The activity to test. This must be a class in the instrumentation
      * targetPackage specified in the AndroidManifest.xml
@@ -56,7 +56,7 @@
      * targetPackage specified in the AndroidManifest.xml
      * @param initialTouchMode true = in touch mode
      */
-    public ActivityInstrumentationTestCase(String pkg, Class<T> activityClass, 
+    public ActivityInstrumentationTestCase(String pkg, Class<T> activityClass,
             boolean initialTouchMode) {
         mActivityClass = activityClass;
         mInitialTouchMode = initialTouchMode;
@@ -80,8 +80,8 @@
     protected void tearDown() throws Exception {
         getActivity().finish();
         setActivity(null);
-        
-        // Scrub out members - protects against memory leaks in the case where someone 
+
+        // Scrub out members - protects against memory leaks in the case where someone
         // creates a non-static inner class (thus referencing the test case) and gives it to
         // someone else to hold onto
         scrubClass(ActivityInstrumentationTestCase.class);
diff --git a/test-runner/src/android/test/ActivityInstrumentationTestCase2.java b/test-runner/src/android/test/ActivityInstrumentationTestCase2.java
index c4bcf31..0e61ce7 100644
--- a/test-runner/src/android/test/ActivityInstrumentationTestCase2.java
+++ b/test-runner/src/android/test/ActivityInstrumentationTestCase2.java
@@ -25,26 +25,26 @@
  * This class provides functional testing of a single activity.  The activity under test will
  * be created using the system infrastructure (by calling InstrumentationTestCase.launchActivity())
  * and you will then be able to manipulate your Activity directly.
- * 
+ *
  * <p>Other options supported by this test case include:
  * <ul>
  * <li>You can run any test method on the UI thread (see {@link android.test.UiThreadTest}).</li>
- * <li>You can inject custom Intents into your Activity (see 
+ * <li>You can inject custom Intents into your Activity (see
  * {@link #setActivityIntent(Intent)}).</li>
  * </ul>
- * 
+ *
  * <p>This class replaces {@link android.test.ActivityInstrumentationTestCase}, which is deprecated.
  * New tests should be written using this base class.
- * 
+ *
  * <p>If you prefer an isolated unit test, see {@link android.test.ActivityUnitTestCase}.
  *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about application testing, read the
- * <a href="{@docRoot}guide/topics/testing/index.html">Testing</a> developer guide.</p>
- * </div>
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">
+ * ActivityTestRule</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
-public abstract class ActivityInstrumentationTestCase2<T extends Activity> 
+@Deprecated
+public abstract class ActivityInstrumentationTestCase2<T extends Activity>
         extends ActivityTestCase {
     Class<T> mActivityClass;
     boolean mInitialTouchMode = false;
@@ -78,18 +78,18 @@
      * Get the Activity under test, starting it if necessary.
      *
      * For each test method invocation, the Activity will not actually be created until the first
-     * time this method is called. 
-     * 
-     * <p>If you wish to provide custom setup values to your Activity, you may call 
-     * {@link #setActivityIntent(Intent)} and/or {@link #setActivityInitialTouchMode(boolean)} 
-     * before your first call to getActivity().  Calling them after your Activity has 
+     * time this method is called.
+     *
+     * <p>If you wish to provide custom setup values to your Activity, you may call
+     * {@link #setActivityIntent(Intent)} and/or {@link #setActivityInitialTouchMode(boolean)}
+     * before your first call to getActivity().  Calling them after your Activity has
      * started will have no effect.
      *
      * <p><b>NOTE:</b> Activities under test may not be started from within the UI thread.
      * If your test method is annotated with {@link android.test.UiThreadTest}, then your Activity
      * will be started automatically just before your test method is run.  You still call this
      * method in order to get the Activity under test.
-     * 
+     *
      * @return the Activity under test
      */
     @Override
@@ -113,10 +113,10 @@
     /**
      * Call this method before the first call to {@link #getActivity} to inject a customized Intent
      * into the Activity under test.
-     * 
+     *
      * <p>If you do not call this, the default intent will be provided.  If you call this after
      * your Activity has been started, it will have no effect.
-     * 
+     *
      * <p><b>NOTE:</b> Activities under test may not be started from within the UI thread.
      * If your test method is annotated with {@link android.test.UiThreadTest}, then you must call
      * {@link #setActivityIntent(Intent)} from {@link #setUp()}.
@@ -131,28 +131,28 @@
     public void setActivityIntent(Intent i) {
         mActivityIntent = i;
     }
-    
+
     /**
      * Call this method before the first call to {@link #getActivity} to set the initial touch
      * mode for the Activity under test.
-     * 
+     *
      * <p>If you do not call this, the touch mode will be false.  If you call this after
      * your Activity has been started, it will have no effect.
-     * 
+     *
      * <p><b>NOTE:</b> Activities under test may not be started from within the UI thread.
      * If your test method is annotated with {@link android.test.UiThreadTest}, then you must call
      * {@link #setActivityInitialTouchMode(boolean)} from {@link #setUp()}.
-     * 
+     *
      * @param initialTouchMode true if the Activity should be placed into "touch mode" when started
      */
     public void setActivityInitialTouchMode(boolean initialTouchMode) {
         mInitialTouchMode = initialTouchMode;
     }
-    
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        
+
         mInitialTouchMode = false;
         mActivityIntent = null;
     }
@@ -165,8 +165,8 @@
             a.finish();
             setActivity(null);
         }
-        
-        // Scrub out members - protects against memory leaks in the case where someone 
+
+        // Scrub out members - protects against memory leaks in the case where someone
         // creates a non-static inner class (thus referencing the test case) and gives it to
         // someone else to hold onto
         scrubClass(ActivityInstrumentationTestCase2.class);
diff --git a/test-runner/src/android/test/ActivityTestCase.java b/test-runner/src/android/test/ActivityTestCase.java
index c7b1d70..51dd3ef 100644
--- a/test-runner/src/android/test/ActivityTestCase.java
+++ b/test-runner/src/android/test/ActivityTestCase.java
@@ -25,7 +25,11 @@
  * This is common code used to support Activity test cases.  For more useful classes, please see
  * {@link android.test.ActivityUnitTestCase} and
  * {@link android.test.ActivityInstrumentationTestCase}.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public abstract class ActivityTestCase extends InstrumentationTestCase {
 
     /**
diff --git a/test-runner/src/android/test/ActivityUnitTestCase.java b/test-runner/src/android/test/ActivityUnitTestCase.java
index 40cca90..a191445 100644
--- a/test-runner/src/android/test/ActivityUnitTestCase.java
+++ b/test-runner/src/android/test/ActivityUnitTestCase.java
@@ -32,14 +32,14 @@
 
 /**
  * This class provides isolated testing of a single activity.  The activity under test will
- * be created with minimal connection to the system infrastructure, and you can inject mocked or 
+ * be created with minimal connection to the system infrastructure, and you can inject mocked or
  * wrappered versions of many of Activity's dependencies.  Most of the work is handled
  * automatically here by {@link #setUp} and {@link #tearDown}.
- * 
+ *
  * <p>If you prefer a functional test, see {@link android.test.ActivityInstrumentationTestCase}.
- * 
+ *
  * <p>It must be noted that, as a true unit test, your Activity will not be running in the
- * normal system and will not participate in the normal interactions with other Activities.  
+ * normal system and will not participate in the normal interactions with other Activities.
  * The following methods should not be called in this configuration - most of them will throw
  * exceptions:
  * <ul>
@@ -54,17 +54,17 @@
  * <li>{@link android.app.Activity#isTaskRoot()}</li>
  * <li>{@link android.app.Activity#moveTaskToBack(boolean)}</li>
  * </ul>
- * 
- * <p>The following methods may be called but will not do anything.  For test purposes, you can use 
- * the methods {@link #getStartedActivityIntent()} and {@link #getStartedActivityRequest()} to 
+ *
+ * <p>The following methods may be called but will not do anything.  For test purposes, you can use
+ * the methods {@link #getStartedActivityIntent()} and {@link #getStartedActivityRequest()} to
  * inspect the parameters that they were called with.
  * <ul>
  * <li>{@link android.app.Activity#startActivity(Intent)}</li>
  * <li>{@link android.app.Activity#startActivityForResult(Intent, int)}</li>
  * </ul>
  *
- * <p>The following methods may be called but will not do anything.  For test purposes, you can use 
- * the methods {@link #isFinishCalled()} and {@link #getFinishedActivityRequest()} to inspect the 
+ * <p>The following methods may be called but will not do anything.  For test purposes, you can use
+ * the methods {@link #isFinishCalled()} and {@link #getFinishedActivityRequest()} to inspect the
  * parameters that they were called with.
  * <ul>
  * <li>{@link android.app.Activity#finish()}</li>
@@ -72,8 +72,12 @@
  * <li>{@link android.app.Activity#finishActivity(int requestCode)}</li>
  * </ul>
  *
+ * @deprecated Write
+ * <a href="{@docRoot}training/testing/unit-testing/local-unit-tests.html">Local Unit Tests</a>
+ * instead.
  */
-public abstract class ActivityUnitTestCase<T extends Activity> 
+@Deprecated
+public abstract class ActivityUnitTestCase<T extends Activity>
         extends ActivityTestCase {
 
     private static final String TAG = "ActivityUnitTestCase";
@@ -102,31 +106,31 @@
         // default value for target context, as a default
       mActivityContext = getInstrumentation().getTargetContext();
     }
-    
+
     /**
      * Start the activity under test, in the same way as if it was started by
-     * {@link android.content.Context#startActivity Context.startActivity()}, providing the 
+     * {@link android.content.Context#startActivity Context.startActivity()}, providing the
      * arguments it supplied.  When you use this method to start the activity, it will automatically
      * be stopped by {@link #tearDown}.
-     * 
-     * <p>This method will call onCreate(), but if you wish to further exercise Activity life 
+     *
+     * <p>This method will call onCreate(), but if you wish to further exercise Activity life
      * cycle methods, you must call them yourself from your test case.
-     * 
+     *
      * <p><i>Do not call from your setUp() method.  You must call this method from each of your
      * test methods.</i>
-     *  
+     *
      * @param intent The Intent as if supplied to {@link android.content.Context#startActivity}.
      * @param savedInstanceState The instance state, if you are simulating this part of the life
      * cycle.  Typically null.
-     * @param lastNonConfigurationInstance This Object will be available to the 
-     * Activity if it calls {@link android.app.Activity#getLastNonConfigurationInstance()}.  
+     * @param lastNonConfigurationInstance This Object will be available to the
+     * Activity if it calls {@link android.app.Activity#getLastNonConfigurationInstance()}.
      * Typically null.
      * @return Returns the Activity that was created
      */
     protected T startActivity(Intent intent, Bundle savedInstanceState,
             Object lastNonConfigurationInstance) {
         assertFalse("Activity already created", mCreated);
-        
+
         if (!mAttached) {
             assertNotNull(mActivityClass);
             setActivity(null);
@@ -154,7 +158,7 @@
 
             assertNotNull(newActivity);
             setActivity(newActivity);
-            
+
             mAttached = true;
         }
 
@@ -165,22 +169,22 @@
         }
         return result;
     }
-    
+
     @Override
     protected void tearDown() throws Exception {
-        
+
         setActivity(null);
-        
-        // Scrub out members - protects against memory leaks in the case where someone 
+
+        // Scrub out members - protects against memory leaks in the case where someone
         // creates a non-static inner class (thus referencing the test case) and gives it to
         // someone else to hold onto
         scrubClass(ActivityInstrumentationTestCase.class);
 
         super.tearDown();
     }
-    
+
     /**
-     * Set the application for use during the test.  You must call this function before calling 
+     * Set the application for use during the test.  You must call this function before calling
      * {@link #startActivity}.  If your test does not call this method,
      * @param application The Application object that will be injected into the Activity under test.
      */
@@ -198,7 +202,7 @@
     }
 
     /**
-     * This method will return the value if your Activity under test calls 
+     * This method will return the value if your Activity under test calls
      * {@link android.app.Activity#setRequestedOrientation}.
      */
     public int getRequestedOrientation() {
@@ -207,10 +211,10 @@
         }
         return 0;
     }
-    
+
     /**
-     * This method will return the launch intent if your Activity under test calls 
-     * {@link android.app.Activity#startActivity(Intent)} or 
+     * This method will return the launch intent if your Activity under test calls
+     * {@link android.app.Activity#startActivity(Intent)} or
      * {@link android.app.Activity#startActivityForResult(Intent, int)}.
      * @return The Intent provided in the start call, or null if no start call was made.
      */
@@ -220,9 +224,9 @@
         }
         return null;
     }
-    
+
     /**
-     * This method will return the launch request code if your Activity under test calls 
+     * This method will return the launch request code if your Activity under test calls
      * {@link android.app.Activity#startActivityForResult(Intent, int)}.
      * @return The request code provided in the start call, or -1 if no start call was made.
      */
@@ -234,9 +238,9 @@
     }
 
     /**
-     * This method will notify you if the Activity under test called 
-     * {@link android.app.Activity#finish()}, 
-     * {@link android.app.Activity#finishFromChild(Activity)}, or 
+     * This method will notify you if the Activity under test called
+     * {@link android.app.Activity#finish()},
+     * {@link android.app.Activity#finishFromChild(Activity)}, or
      * {@link android.app.Activity#finishActivity(int)}.
      * @return Returns true if one of the listed finish methods was called.
      */
@@ -246,9 +250,9 @@
         }
         return false;
     }
-    
+
     /**
-     * This method will return the request code if the Activity under test called 
+     * This method will return the request code if the Activity under test called
      * {@link android.app.Activity#finishActivity(int)}.
      * @return The request code provided in the start call, or -1 if no finish call was made.
      */
@@ -258,7 +262,7 @@
         }
         return 0;
     }
-    
+
     /**
      * This mock Activity represents the "parent" activity.  By injecting this, we allow the user
      * to call a few more Activity methods, including:
@@ -269,7 +273,7 @@
      * <li>{@link android.app.Activity#finishActivity(int requestCode)}</li>
      * <li>{@link android.app.Activity#finishFromChild(Activity child)}</li>
      * </ul>
-     * 
+     *
      * TODO: Make this overrideable, and the unit test can look for calls to other methods
      */
     private static class MockParent extends Activity {
@@ -303,7 +307,7 @@
         public Window getWindow() {
             return null;
         }
-        
+
         /**
          * By defining this in the parent, we allow the tested activity to call
          * <ul>
@@ -316,7 +320,7 @@
             mStartedActivityIntent = intent;
             mStartedActivityRequest = requestCode;
         }
-        
+
         /**
          * By defining this in the parent, we allow the tested activity to call
          * <ul>
diff --git a/test-runner/src/android/test/AndroidTestRunner.java b/test-runner/src/android/test/AndroidTestRunner.java
index aa7c677..50eaafb 100644
--- a/test-runner/src/android/test/AndroidTestRunner.java
+++ b/test-runner/src/android/test/AndroidTestRunner.java
@@ -33,6 +33,13 @@
 import java.lang.reflect.InvocationTargetException;
 import java.util.List;
 
+/**
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
+ * AndroidJUnitRunner</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ */
+@Deprecated
 public class AndroidTestRunner extends BaseTestRunner {
 
     private TestResult mTestResult;
diff --git a/test-runner/src/android/test/ApplicationTestCase.java b/test-runner/src/android/test/ApplicationTestCase.java
index f093181..4d73f53 100644
--- a/test-runner/src/android/test/ApplicationTestCase.java
+++ b/test-runner/src/android/test/ApplicationTestCase.java
@@ -32,7 +32,7 @@
  * In order to support the lifecycle of a Application, this test case will make the
  * following calls at the following times.
  *
- * <ul><li>The test case will not call onCreate() until your test calls 
+ * <ul><li>The test case will not call onCreate() until your test calls
  * {@link #createApplication()}.  This gives you a chance
  * to set up or adjust any additional framework or test logic before
  * onCreate().</li>
@@ -40,22 +40,28 @@
  * automatically called, and it will stop & destroy your application by calling its
  * onDestroy() method.</li>
  * </ul>
- * 
+ *
  * <p><b>Dependency Injection.</b>
  * Every Application has one inherent dependency, the {@link android.content.Context Context} in
  * which it runs.
- * This framework allows you to inject a modified, mock, or isolated replacement for this 
+ * This framework allows you to inject a modified, mock, or isolated replacement for this
  * dependencies, and thus perform a true unit test.
- * 
+ *
  * <p>If simply run your tests as-is, your Application will be injected with a fully-functional
  * Context.
- * You can create and inject alternative types of Contexts by calling 
+ * You can create and inject alternative types of Contexts by calling
  * {@link AndroidTestCase#setContext(Context) setContext()}.  You must do this <i>before</i> calling
  * {@link #createApplication()}.  The test framework provides a
- * number of alternatives for Context, including {@link android.test.mock.MockContext MockContext}, 
- * {@link android.test.RenamingDelegatingContext RenamingDelegatingContext}, and 
+ * number of alternatives for Context, including {@link android.test.mock.MockContext MockContext},
+ * {@link android.test.RenamingDelegatingContext RenamingDelegatingContext}, and
  * {@link android.content.ContextWrapper ContextWrapper}.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html">
+ * InstrumentationRegistry</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public abstract class ApplicationTestCase<T extends Application> extends AndroidTestCase {
 
     Class<T> mApplicationClass;
@@ -78,17 +84,17 @@
     }
 
     /**
-     * This will do the work to instantiate the Application under test.  After this, your test 
+     * This will do the work to instantiate the Application under test.  After this, your test
      * code must also start and stop the Application.
      */
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        
+
         // get the real context, before the individual tests have a chance to muck with it
         mSystemContext = getContext();
     }
-    
+
     /**
      * Load and attach the application under test.
      */
@@ -101,26 +107,26 @@
         }
         mAttached = true;
     }
-    
+
     /**
-     * Start the Application under test, in the same way as if it was started by the system.  
+     * Start the Application under test, in the same way as if it was started by the system.
      * If you use this method to start the Application, it will automatically
      * be stopped by {@link #tearDown}.  If you wish to inject a specialized Context for your
-     * test, by calling {@link AndroidTestCase#setContext(Context) setContext()}, 
+     * test, by calling {@link AndroidTestCase#setContext(Context) setContext()},
      * you must do so  before calling this method.
      */
     final protected void createApplication() {
         assertFalse(mCreated);
-        
+
         if (!mAttached) {
             setupApplication();
         }
         assertNotNull(mApplication);
-        
+
         mApplication.onCreate();
         mCreated = true;
     }
-    
+
     /**
      * This will make the necessary calls to terminate the Application under test (it will
      * call onTerminate().  Ordinarily this will be called automatically (by {@link #tearDown}, but
@@ -131,13 +137,13 @@
             mApplication.onTerminate();
         }
     }
-    
+
     /**
-     * Shuts down the Application under test.  Also makes sure all resources are cleaned up and 
+     * Shuts down the Application under test.  Also makes sure all resources are cleaned up and
      * garbage collected before moving on to the next
      * test.  Subclasses that override this method should make sure they call super.tearDown()
      * at the end of the overriding method.
-     * 
+     *
      * @throws Exception
      */
     @Override
@@ -145,7 +151,7 @@
         terminateApplication();
         mApplication = null;
 
-        // Scrub out members - protects against memory leaks in the case where someone 
+        // Scrub out members - protects against memory leaks in the case where someone
         // creates a non-static inner class (thus referencing the test case) and gives it to
         // someone else to hold onto
         scrubClass(ApplicationTestCase.class);
@@ -156,7 +162,7 @@
     /**
      * Return a real (not mocked or instrumented) system Context that can be used when generating
      * Mock or other Context objects for your Application under test.
-     * 
+     *
      * @return Returns a reference to a normal Context.
      */
     public Context getSystemContext() {
@@ -165,7 +171,7 @@
 
     /**
      * This test simply confirms that the Application class can be instantiated properly.
-     * 
+     *
      * @throws Exception
      */
     final public void testApplicationTestCaseSetUpProperly() throws Exception {
diff --git a/test-runner/src/android/test/AssertionFailedError.java b/test-runner/src/android/test/AssertionFailedError.java
index b3ac6d1..fc3e98e 100644
--- a/test-runner/src/android/test/AssertionFailedError.java
+++ b/test-runner/src/android/test/AssertionFailedError.java
@@ -18,17 +18,18 @@
 
 /**
  * Thrown when an assertion failed.
- * 
+ *
  * @deprecated use junit.framework.AssertionFailedError
  */
+@Deprecated
 public class AssertionFailedError extends Error {
-    
+
     /**
      * It is more typical to call {@link #AssertionFailedError(String)}.
      */
     public AssertionFailedError() {
     }
-    
+
     public AssertionFailedError(String errorMessage) {
         super(errorMessage);
     }
diff --git a/test-runner/src/android/test/ClassPathPackageInfo.java b/test-runner/src/android/test/ClassPathPackageInfo.java
index 1f6e647..1ab7c7f 100644
--- a/test-runner/src/android/test/ClassPathPackageInfo.java
+++ b/test-runner/src/android/test/ClassPathPackageInfo.java
@@ -24,9 +24,10 @@
 /**
  * The Package object doesn't allow you to iterate over the contained
  * classes and subpackages of that package.  This is a version that does.
- * 
+ *
  * {@hide} Not needed for 1.0 SDK.
  */
+@Deprecated
 public class ClassPathPackageInfo {
 
     private final ClassPathPackageInfoSource source;
diff --git a/test-runner/src/android/test/ClassPathPackageInfoSource.java b/test-runner/src/android/test/ClassPathPackageInfoSource.java
index 0ffecdb..89bb494 100644
--- a/test-runner/src/android/test/ClassPathPackageInfoSource.java
+++ b/test-runner/src/android/test/ClassPathPackageInfoSource.java
@@ -33,9 +33,10 @@
 
 /**
  * Generate {@link ClassPathPackageInfo}s by scanning apk paths.
- * 
+ *
  * {@hide} Not needed for 1.0 SDK.
  */
+@Deprecated
 public class ClassPathPackageInfoSource {
 
     private static final String CLASS_EXTENSION = ".class";
@@ -82,7 +83,7 @@
                 // Don't try to load classes that are generated. They usually aren't in test apks.
                 continue;
             }
-            
+
             try {
                 // We get errors in the emulator if we don't use the caller's class loader.
                 topLevelClasses.add(Class.forName(className, false,
diff --git a/test-runner/src/android/test/DatabaseTestUtils.java b/test-runner/src/android/test/DatabaseTestUtils.java
index 23e0aba..42ef48b 100644
--- a/test-runner/src/android/test/DatabaseTestUtils.java
+++ b/test-runner/src/android/test/DatabaseTestUtils.java
@@ -27,6 +27,7 @@
  * A collection of utilities for writing unit tests for database code.
  * @hide pending API council approval
  */
+@Deprecated
 public class DatabaseTestUtils {
 
     /**
diff --git a/test-runner/src/android/test/InstrumentationCoreTestRunner.java b/test-runner/src/android/test/InstrumentationCoreTestRunner.java
index 655a65c..2b05e4a 100644
--- a/test-runner/src/android/test/InstrumentationCoreTestRunner.java
+++ b/test-runner/src/android/test/InstrumentationCoreTestRunner.java
@@ -41,6 +41,7 @@
  *
  * @hide
  */
+@Deprecated
 public class InstrumentationCoreTestRunner extends InstrumentationTestRunner {
 
     /**
diff --git a/test-runner/src/android/test/InstrumentationTestRunner.java b/test-runner/src/android/test/InstrumentationTestRunner.java
index db80ef951..9bd4c96 100644
--- a/test-runner/src/android/test/InstrumentationTestRunner.java
+++ b/test-runner/src/android/test/InstrumentationTestRunner.java
@@ -155,6 +155,10 @@
  * -e coverageFile /sdcard/myFile.ec
  * <br/>
  * in addition to the other arguments.
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
+ * AndroidJUnitRunner</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
 
 /* (not JavaDoc)
@@ -170,6 +174,7 @@
  *
  * This model is used by many existing app tests, but can probably be deprecated.
  */
+@Deprecated
 public class InstrumentationTestRunner extends Instrumentation implements TestSuiteProvider {
 
     /** @hide */
diff --git a/test-runner/src/android/test/InstrumentationUtils.java b/test-runner/src/android/test/InstrumentationUtils.java
index 1a7002a..cc50813 100644
--- a/test-runner/src/android/test/InstrumentationUtils.java
+++ b/test-runner/src/android/test/InstrumentationUtils.java
@@ -17,17 +17,17 @@
 package android.test;
 
 /**
- * 
  * The InstrumentationUtils class has all the utility functions needed for
  * instrumentation tests.
  *
  * {@hide} - Not currently used.
  */
+@Deprecated
 public class InstrumentationUtils {
     /**
      * An utility function that returns the menu identifier for a particular
      * menu item.
-     * 
+     *
      * @param cls Class object of the class that handles the menu ite,.
      * @param identifier Menu identifier.
      * @return The integer corresponding to the menu item.
@@ -35,7 +35,7 @@
     public static int getMenuIdentifier(Class cls, String identifier) {
         int id = -1;
         try {
-            Integer field = (Integer)cls.getDeclaredField(identifier).get(cls);   
+            Integer field = (Integer)cls.getDeclaredField(identifier).get(cls);
             id = field.intValue();
         } catch (NoSuchFieldException e) {
             e.printStackTrace();
diff --git a/test-runner/src/android/test/IsolatedContext.java b/test-runner/src/android/test/IsolatedContext.java
index f971b5d..3abf38f 100644
--- a/test-runner/src/android/test/IsolatedContext.java
+++ b/test-runner/src/android/test/IsolatedContext.java
@@ -43,9 +43,13 @@
 
 
 /**
-     * A mock context which prevents its users from talking to the rest of the device while
+ * A mock context which prevents its users from talking to the rest of the device while
  * stubbing enough methods to satify code that tries to talk to other packages.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class IsolatedContext extends ContextWrapper {
 
     private ContentResolver mResolver;
diff --git a/test-runner/src/android/test/LaunchPerformanceBase.java b/test-runner/src/android/test/LaunchPerformanceBase.java
index d423e62..62c90d6 100644
--- a/test-runner/src/android/test/LaunchPerformanceBase.java
+++ b/test-runner/src/android/test/LaunchPerformanceBase.java
@@ -26,6 +26,7 @@
  *
  * @hide
  */
+@Deprecated
 public class LaunchPerformanceBase extends Instrumentation {
 
     public static final String LOG_TAG = "Launch Performance";
@@ -39,7 +40,7 @@
         mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         setAutomaticPerformanceSnapshots();
     }
-   
+
     /**
      * Launches intent, and waits for idle before returning.
      *
diff --git a/test-runner/src/android/test/MoreAsserts.java b/test-runner/src/android/test/MoreAsserts.java
index 3364895..d33911a 100644
--- a/test-runner/src/android/test/MoreAsserts.java
+++ b/test-runner/src/android/test/MoreAsserts.java
@@ -30,7 +30,10 @@
 
 /**
  * Contains additional assertion methods not found in JUnit.
+ * @deprecated Use
+ * <a href="https://github.com/hamcrest">Hamcrest matchers</a> instead.
  */
+@Deprecated
 public final class MoreAsserts {
 
     private MoreAsserts() { }
@@ -375,7 +378,7 @@
                 failWithMessage(message, "Extra object in actual: (" + actualObj.toString() + ")");
             }
         }
-        
+
         if (expectedMap.size() > 0) {
             failWithMessage(message, "Extra objects in expected.");
         }
diff --git a/test-runner/src/android/test/NoExecTestResult.java b/test-runner/src/android/test/NoExecTestResult.java
index 1ee62c1..a01b6aa 100644
--- a/test-runner/src/android/test/NoExecTestResult.java
+++ b/test-runner/src/android/test/NoExecTestResult.java
@@ -19,11 +19,12 @@
 import junit.framework.TestResult;
 
 /**
- * A benign test result that does no actually test execution, just runs 
+ * A benign test result that does no actually test execution, just runs
  * through the motions
- * 
+ *
  * {@hide} Not needed for SDK.
  */
+@Deprecated
 class NoExecTestResult extends TestResult {
 
     /**
diff --git a/test-runner/src/android/test/PackageInfoSources.java b/test-runner/src/android/test/PackageInfoSources.java
index ef37449..205f86b 100644
--- a/test-runner/src/android/test/PackageInfoSources.java
+++ b/test-runner/src/android/test/PackageInfoSources.java
@@ -19,6 +19,7 @@
 /**
  * {@hide} Not needed for SDK.
  */
+@Deprecated
 public class PackageInfoSources {
 
     private static ClassPathPackageInfoSource classPathSource;
diff --git a/test-runner/src/android/test/PerformanceCollectorTestCase.java b/test-runner/src/android/test/PerformanceCollectorTestCase.java
index 4309ff7..3a5dafc 100644
--- a/test-runner/src/android/test/PerformanceCollectorTestCase.java
+++ b/test-runner/src/android/test/PerformanceCollectorTestCase.java
@@ -30,6 +30,7 @@
  *
  * {@hide} Not needed for SDK.
  */
+@Deprecated
 public interface PerformanceCollectorTestCase {
     public PerformanceCollector mPerfCollector = new PerformanceCollector();
 
diff --git a/test-runner/src/android/test/RenamingDelegatingContext.java b/test-runner/src/android/test/RenamingDelegatingContext.java
index 3c4da9e..36786b0 100644
--- a/test-runner/src/android/test/RenamingDelegatingContext.java
+++ b/test-runner/src/android/test/RenamingDelegatingContext.java
@@ -36,7 +36,11 @@
  * This is a class which delegates to the given context, but performs database
  * and file operations with a renamed database/file name (prefixes default
  * names with a given prefix).
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class RenamingDelegatingContext extends ContextWrapper {
 
     private Context mFileContext;
@@ -168,7 +172,7 @@
             return false;
         }
     }
-    
+
     @Override
     public File getDatabasePath(String name) {
         return mFileContext.getDatabasePath(renamedFileName(name));
@@ -216,7 +220,7 @@
     public String[] fileList() {
         return mFileNames.toArray(new String[]{});
     }
-    
+
     /**
      * In order to support calls to getCacheDir(), we create a temp cache dir (inside the real
      * one) and return it instead.  This code is basically getCacheDir(), except it uses the real
@@ -241,21 +245,4 @@
         }
         return mCacheDir;
     }
-
-
-//    /**
-//     * Given an array of files returns only those whose names indicate that they belong to this
-//     * context.
-//     * @param allFiles the original list of files
-//     * @return the pruned list of files
-//     */
-//    private String[] prunedFileList(String[] allFiles) {
-//        List<String> files = Lists.newArrayList();
-//        for (String file : allFiles) {
-//            if (file.startsWith(mFilePrefix)) {
-//                files.add(file);
-//            }
-//        }
-//        return files.toArray(new String[]{});
-//    }
 }
diff --git a/test-runner/src/android/test/ServiceTestCase.java b/test-runner/src/android/test/ServiceTestCase.java
index ba20c09..c8ff0f9 100644
--- a/test-runner/src/android/test/ServiceTestCase.java
+++ b/test-runner/src/android/test/ServiceTestCase.java
@@ -92,7 +92,13 @@
  *      {@link android.test.RenamingDelegatingContext RenamingDelegatingContext},
  *      {@link android.content.ContextWrapper ContextWrapper}, and
  *      {@link android.test.IsolatedContext}.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/rule/ServiceTestRule.html">
+ * ServiceTestRule</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public abstract class ServiceTestCase<T extends Service> extends AndroidTestCase {
 
     Class<T> mServiceClass;
diff --git a/test-runner/src/android/test/SimpleCache.java b/test-runner/src/android/test/SimpleCache.java
index 44424ec..46143e4 100644
--- a/test-runner/src/android/test/SimpleCache.java
+++ b/test-runner/src/android/test/SimpleCache.java
@@ -19,6 +19,7 @@
 import java.util.HashMap;
 import java.util.Map;
 
+@Deprecated
 abstract class SimpleCache<K, V> {
     private Map<K, V> map = new HashMap<K, V>();
 
diff --git a/test-runner/src/android/test/SingleLaunchActivityTestCase.java b/test-runner/src/android/test/SingleLaunchActivityTestCase.java
index 72c93ce..af1448e 100644
--- a/test-runner/src/android/test/SingleLaunchActivityTestCase.java
+++ b/test-runner/src/android/test/SingleLaunchActivityTestCase.java
@@ -22,13 +22,19 @@
  * If you would like to test a single activity with an
  * {@link android.test.InstrumentationTestCase}, this provides some of the boiler plate to
  * launch and finish the activity in {@link #setUp} and {@link #tearDown}.
- * 
- * This launches the activity only once for the entire class instead of doing it 
+ *
+ * This launches the activity only once for the entire class instead of doing it
  * in every setup / teardown call.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">
+ * ActivityTestRule</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public abstract class SingleLaunchActivityTestCase<T extends Activity>
         extends InstrumentationTestCase {
-    
+
     String mPackage;
     Class<T> mActivityClass;
     private static int sTestCaseCounter = 0;
@@ -44,10 +50,10 @@
      */
     public SingleLaunchActivityTestCase(String pkg, Class<T> activityClass) {
         mPackage = pkg;
-        mActivityClass = activityClass;        
-        sTestCaseCounter ++;                
+        mActivityClass = activityClass;
+        sTestCaseCounter ++;
     }
-    
+
     /**
      * The activity that will be set up for use in each test method.
      */
@@ -66,7 +72,7 @@
             getInstrumentation().setInTouchMode(false);
             sActivity = launchActivity(mPackage, mActivityClass, null);
             sActivityLaunchedFlag = true;
-        }                        
+        }
     }
 
     @Override
@@ -75,7 +81,7 @@
         sTestCaseCounter --;
         if (sTestCaseCounter == 0) {
             sActivity.finish();
-        }        
+        }
         super.tearDown();
     }
 
diff --git a/test-runner/src/android/test/SyncBaseInstrumentation.java b/test-runner/src/android/test/SyncBaseInstrumentation.java
index 7d418f0..de36b4f 100644
--- a/test-runner/src/android/test/SyncBaseInstrumentation.java
+++ b/test-runner/src/android/test/SyncBaseInstrumentation.java
@@ -27,7 +27,13 @@
  * If you would like to test sync a single provider with an
  * {@link InstrumentationTestCase}, this provides some of the boiler plate in {@link #setUp} and
  * {@link #tearDown}.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html">
+ * InstrumentationRegistry</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class SyncBaseInstrumentation extends InstrumentationTestCase {
     private Context mTargetContext;
     ContentResolver mContentResolver;
diff --git a/test-runner/src/android/test/TestCase.java b/test-runner/src/android/test/TestCase.java
index 5432ce8..b234f44 100644
--- a/test-runner/src/android/test/TestCase.java
+++ b/test-runner/src/android/test/TestCase.java
@@ -23,14 +23,13 @@
  * More complex interface for test cases.
  *
  * <p>Just implementing Runnable is enough for many test cases.  If you
- * have additional setup or teardown, this interface might be for you, 
+ * have additional setup or teardown, this interface might be for you,
  * especially if you need to share it between different test cases, or your
  * teardown code must execute regardless of whether your test passed.
  *
  * <p>See the android.test package documentation (click the more... link)
  * for a full description
  */
-
 @Deprecated
 public interface TestCase extends Runnable
 {
diff --git a/test-runner/src/android/test/TestCaseUtil.java b/test-runner/src/android/test/TestCaseUtil.java
index 3ba9711..c46d403 100644
--- a/test-runner/src/android/test/TestCaseUtil.java
+++ b/test-runner/src/android/test/TestCaseUtil.java
@@ -35,6 +35,7 @@
  * @hide - This is part of a framework that is under development and should not be used for
  * active development.
  */
+@Deprecated
 public class TestCaseUtil {
 
     private TestCaseUtil() {
@@ -67,7 +68,7 @@
              */
             if (test instanceof TestCase &&
                     ((TestCase)test).getName() == null) {
-                workingTest = invokeSuiteMethodIfPossible(test.getClass(), 
+                workingTest = invokeSuiteMethodIfPossible(test.getClass(),
                         seen);
             }
             if (workingTest == null) {
@@ -155,7 +156,7 @@
     public static TestSuite createTestSuite(Class<? extends Test> testClass)
             throws InstantiationException, IllegalAccessException {
 
-        Test test = invokeSuiteMethodIfPossible(testClass, 
+        Test test = invokeSuiteMethodIfPossible(testClass,
                 new HashSet<Class<?>>());
         if (test == null) {
             return new TestSuite(testClass);
diff --git a/test-runner/src/android/test/TestPrinter.java b/test-runner/src/android/test/TestPrinter.java
index 37bd721..a23f06d 100644
--- a/test-runner/src/android/test/TestPrinter.java
+++ b/test-runner/src/android/test/TestPrinter.java
@@ -30,9 +30,10 @@
  * probably will not need to create or extend this class or call its methods manually.
  * See the full {@link android.test} package description for information about
  * getting test results.
- * 
+ *
  * {@hide} Not needed for 1.0 SDK.
  */
+@Deprecated
 public class TestPrinter implements TestRunner.Listener, TestListener {
 
     private String mTag;
@@ -89,7 +90,7 @@
         mFailedTests.add(test.toString());
         failed(test.toString(), t);
     }
-    
+
     public void addError(Test test, Throwable t) {
         failed(test, t);
     }
diff --git a/test-runner/src/android/test/TestRunner.java b/test-runner/src/android/test/TestRunner.java
index 012df35..beecc6f 100644
--- a/test-runner/src/android/test/TestRunner.java
+++ b/test-runner/src/android/test/TestRunner.java
@@ -42,6 +42,7 @@
  *
  * {@hide} Not needed for 1.0 SDK.
  */
+@Deprecated
 public class TestRunner implements PerformanceTestCase.Intermediates {
     public static final int REGRESSION = 0;
     public static final int PERFORMANCE = 1;
diff --git a/test-runner/src/android/test/TestSuiteProvider.java b/test-runner/src/android/test/TestSuiteProvider.java
index dc9ce6e..c74651c 100644
--- a/test-runner/src/android/test/TestSuiteProvider.java
+++ b/test-runner/src/android/test/TestSuiteProvider.java
@@ -21,6 +21,7 @@
 /**
  * Implementors will know how to get a test suite.
  */
+@Deprecated
 public interface TestSuiteProvider {
 
     TestSuite getTestSuite();
diff --git a/test-runner/src/android/test/TimedTest.java b/test-runner/src/android/test/TimedTest.java
index 95cc9bf..cb15ef9 100644
--- a/test-runner/src/android/test/TimedTest.java
+++ b/test-runner/src/android/test/TimedTest.java
@@ -30,6 +30,7 @@
  *
  * {@hide} Pending approval for public API.
  */
+@Deprecated
 @Retention(RetentionPolicy.RUNTIME)
 public @interface TimedTest {
     boolean includeDetailedStats() default false;
diff --git a/test-runner/src/android/test/TouchUtils.java b/test-runner/src/android/test/TouchUtils.java
index 1b854b0..28dc7b2 100644
--- a/test-runner/src/android/test/TouchUtils.java
+++ b/test-runner/src/android/test/TouchUtils.java
@@ -31,9 +31,15 @@
  * Reusable methods for generating touch events. These methods can be used with
  * InstrumentationTestCase or ActivityInstrumentationTestCase2 to simulate user interaction with
  * the application through a touch screen.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}training/testing/ui-testing/espresso-testing.html">Espresso UI testing
+ * framework</a> instead. New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class TouchUtils {
-    
+
     /**
      * Simulate touching in the center of the screen and dragging one quarter of the way down
      * @param test The test case that is being run
@@ -46,7 +52,7 @@
     public static void dragQuarterScreenDown(ActivityInstrumentationTestCase test) {
         dragQuarterScreenDown(test, test.getActivity());
     }
-    
+
     /**
      * Simulate touching in the center of the screen and dragging one quarter of the way down
      * @param test The test case that is being run
@@ -56,14 +62,14 @@
         Display display = activity.getWindowManager().getDefaultDisplay();
         final Point size = new Point();
         display.getSize(size);
-        
+
         final float x = size.x / 2.0f;
         final float fromY = size.y * 0.5f;
         final float toY = size.y * 0.75f;
-      
+
         drag(test, x, x, fromY, toY, 4);
     }
-    
+
     /**
      * Simulate touching in the center of the screen and dragging one quarter of the way up
      * @param test The test case that is being run
@@ -76,7 +82,7 @@
     public static void dragQuarterScreenUp(ActivityInstrumentationTestCase test) {
         dragQuarterScreenUp(test, test.getActivity());
     }
-    
+
     /**
      * Simulate touching in the center of the screen and dragging one quarter of the way up
      * @param test The test case that is being run
@@ -86,18 +92,18 @@
         Display display = activity.getWindowManager().getDefaultDisplay();
         final Point size = new Point();
         display.getSize(size);
-        
+
         final float x = size.x / 2.0f;
         final float fromY = size.y * 0.5f;
         final float toY = size.y * 0.25f;
-      
+
         drag(test, x, x, fromY, toY, 4);
     }
-    
+
     /**
      * Scroll a ViewGroup to the bottom by repeatedly calling
      * {@link #dragQuarterScreenUp(InstrumentationTestCase, Activity)}
-     * 
+     *
      * @param test The test case that is being run
      * @param v The ViewGroup that should be dragged
      *
@@ -109,11 +115,11 @@
     public static void scrollToBottom(ActivityInstrumentationTestCase test, ViewGroup v) {
         scrollToBottom(test, test.getActivity(), v);
     }
-    
+
     /**
      * Scroll a ViewGroup to the bottom by repeatedly calling
      * {@link #dragQuarterScreenUp(InstrumentationTestCase, Activity)}
-     * 
+     *
      * @param test The test case that is being run
      * @param activity The activity that is in the foreground of the test case
      * @param v The ViewGroup that should be dragged
@@ -132,7 +138,7 @@
     /**
      * Scroll a ViewGroup to the top by repeatedly calling
      * {@link #dragQuarterScreenDown(InstrumentationTestCase, Activity)}
-     * 
+     *
      * @param test The test case that is being run
      * @param v The ViewGroup that should be dragged
      *
@@ -144,11 +150,11 @@
     public static void scrollToTop(ActivityInstrumentationTestCase test, ViewGroup v) {
         scrollToTop(test, test.getActivity(), v);
     }
-    
+
     /**
      * Scroll a ViewGroup to the top by repeatedly calling
      * {@link #dragQuarterScreenDown(InstrumentationTestCase, Activity)}
-     * 
+     *
      * @param test The test case that is being run
      * @param activity The activity that is in the foreground of the test case
      * @param v The ViewGroup that should be dragged
@@ -162,10 +168,10 @@
             next = new ViewStateSnapshot(v);
         } while (!prev.equals(next));
     }
-    
+
     /**
      * Simulate touching the center of a view and dragging to the bottom of the screen.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      *
@@ -177,10 +183,10 @@
     public static void dragViewToBottom(ActivityInstrumentationTestCase test, View v) {
         dragViewToBottom(test, test.getActivity(), v, 4);
     }
-    
+
     /**
      * Simulate touching the center of a view and dragging to the bottom of the screen.
-     * 
+     *
      * @param test The test case that is being run
      * @param activity The activity that is in the foreground of the test case
      * @param v The view that should be dragged
@@ -188,10 +194,10 @@
     public static void dragViewToBottom(InstrumentationTestCase test, Activity activity, View v) {
         dragViewToBottom(test, activity, v, 4);
     }
-    
+
     /**
      * Simulate touching the center of a view and dragging to the bottom of the screen.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      * @param stepCount How many move steps to include in the drag
@@ -205,10 +211,10 @@
             int stepCount) {
         dragViewToBottom(test, test.getActivity(), v, stepCount);
     }
-    
+
     /**
      * Simulate touching the center of a view and dragging to the bottom of the screen.
-     * 
+     *
      * @param test The test case that is being run
      * @param activity The activity that is in the foreground of the test case
      * @param v The view that should be dragged
@@ -220,38 +226,38 @@
 
         int[] xy = new int[2];
         v.getLocationOnScreen(xy);
-        
+
         final int viewWidth = v.getWidth();
         final int viewHeight = v.getHeight();
-        
+
         final float x = xy[0] + (viewWidth / 2.0f);
         float fromY = xy[1] + (viewHeight / 2.0f);
         float toY = screenHeight - 1;
-        
+
         drag(test, x, x, fromY, toY, stepCount);
     }
 
     /**
      * Simulate touching the center of a view and releasing quickly (before the tap timeout).
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be clicked
      */
     public static void tapView(InstrumentationTestCase test, View v) {
         int[] xy = new int[2];
         v.getLocationOnScreen(xy);
-        
+
         final int viewWidth = v.getWidth();
         final int viewHeight = v.getHeight();
-        
+
         final float x = xy[0] + (viewWidth / 2.0f);
         float y = xy[1] + (viewHeight / 2.0f);
-        
+
         Instrumentation inst = test.getInstrumentation();
 
         long downTime = SystemClock.uptimeMillis();
         long eventTime = SystemClock.uptimeMillis();
-        
+
         MotionEvent event = MotionEvent.obtain(downTime, eventTime,
                 MotionEvent.ACTION_DOWN, x, y, 0);
         inst.sendPointerSync(event);
@@ -308,30 +314,30 @@
 
     /**
      * Simulate touching the center of a view and releasing.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be clicked
      */
     public static void clickView(InstrumentationTestCase test, View v) {
         int[] xy = new int[2];
         v.getLocationOnScreen(xy);
-        
+
         final int viewWidth = v.getWidth();
         final int viewHeight = v.getHeight();
-        
+
         final float x = xy[0] + (viewWidth / 2.0f);
         float y = xy[1] + (viewHeight / 2.0f);
-        
+
         Instrumentation inst = test.getInstrumentation();
 
         long downTime = SystemClock.uptimeMillis();
         long eventTime = SystemClock.uptimeMillis();
-        
+
         MotionEvent event = MotionEvent.obtain(downTime, eventTime,
                 MotionEvent.ACTION_DOWN, x, y, 0);
         inst.sendPointerSync(event);
         inst.waitForIdleSync();
-        
+
 
         eventTime = SystemClock.uptimeMillis();
         final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop();
@@ -344,7 +350,7 @@
         event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
         inst.sendPointerSync(event);
         inst.waitForIdleSync();
-        
+
         try {
             Thread.sleep(1000);
         } catch (InterruptedException e) {
@@ -354,7 +360,7 @@
 
     /**
      * Simulate touching the center of a view, holding until it is a long press, and then releasing.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be clicked
      *
@@ -369,20 +375,20 @@
 
     /**
      * Simulate touching the center of a view, holding until it is a long press, and then releasing.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be clicked
      */
     public static void longClickView(InstrumentationTestCase test, View v) {
         int[] xy = new int[2];
         v.getLocationOnScreen(xy);
-        
+
         final int viewWidth = v.getWidth();
         final int viewHeight = v.getHeight();
-        
+
         final float x = xy[0] + (viewWidth / 2.0f);
         float y = xy[1] + (viewHeight / 2.0f);
-        
+
         Instrumentation inst = test.getInstrumentation();
 
         long downTime = SystemClock.uptimeMillis();
@@ -399,7 +405,7 @@
                 x + touchSlop / 2, y + touchSlop / 2, 0);
         inst.sendPointerSync(event);
         inst.waitForIdleSync();
-        
+
         try {
             Thread.sleep((long)(ViewConfiguration.getLongPressTimeout() * 1.5f));
         } catch (InterruptedException e) {
@@ -414,7 +420,7 @@
 
     /**
      * Simulate touching the center of a view and dragging to the top of the screen.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      *
@@ -426,10 +432,10 @@
     public static void dragViewToTop(ActivityInstrumentationTestCase test, View v) {
         dragViewToTop((InstrumentationTestCase) test, v, 4);
     }
-    
+
     /**
      * Simulate touching the center of a view and dragging to the top of the screen.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      * @param stepCount How many move steps to include in the drag
@@ -442,20 +448,20 @@
     public static void dragViewToTop(ActivityInstrumentationTestCase test, View v, int stepCount) {
         dragViewToTop((InstrumentationTestCase) test, v, stepCount);
     }
-    
+
     /**
      * Simulate touching the center of a view and dragging to the top of the screen.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      */
     public static void dragViewToTop(InstrumentationTestCase test, View v) {
         dragViewToTop(test, v, 4);
     }
-    
+
     /**
      * Simulate touching the center of a view and dragging to the top of the screen.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      * @param stepCount How many move steps to include in the drag
@@ -463,21 +469,21 @@
     public static void dragViewToTop(InstrumentationTestCase test, View v, int stepCount) {
         int[] xy = new int[2];
         v.getLocationOnScreen(xy);
-        
+
         final int viewWidth = v.getWidth();
         final int viewHeight = v.getHeight();
-        
+
         final float x = xy[0] + (viewWidth / 2.0f);
         float fromY = xy[1] + (viewHeight / 2.0f);
         float toY = 0;
-        
+
         drag(test, x, x, fromY, toY, stepCount);
     }
-    
+
     /**
      * Get the location of a view. Use the gravity param to specify which part of the view to
      * return.
-     * 
+     *
      * @param v View to find
      * @param gravity A combination of (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL,
      *        RIGHT)
@@ -488,7 +494,7 @@
 
         final int viewWidth = v.getWidth();
         final int viewHeight = v.getHeight();
-        
+
         switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {
         case Gravity.TOP:
             break;
@@ -501,7 +507,7 @@
         default:
             // Same as top -- do nothing
         }
-        
+
         switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
         case Gravity.LEFT:
             break;
@@ -518,14 +524,14 @@
 
     /**
      * Simulate touching a view and dragging it by the specified amount.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      * @param gravity Which part of the view to use for the initial down event. A combination of
      *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
      * @param deltaX Amount to drag horizontally in pixels
      * @param deltaY Amount to drag vertically in pixels
-     * 
+     *
      * @return distance in pixels covered by the drag
      *
      * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
@@ -537,17 +543,17 @@
             int deltaX, int deltaY) {
         return dragViewBy((InstrumentationTestCase) test, v, gravity, deltaX, deltaY);
     }
-    
+
     /**
      * Simulate touching a view and dragging it by the specified amount.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      * @param gravity Which part of the view to use for the initial down event. A combination of
      *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
      * @param deltaX Amount to drag horizontally in pixels
      * @param deltaY Amount to drag vertically in pixels
-     * 
+     *
      * @return distance in pixels covered by the drag
      *
      * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
@@ -558,29 +564,29 @@
     public static int dragViewBy(InstrumentationTestCase test, View v, int gravity, int deltaX,
             int deltaY) {
         int[] xy = new int[2];
-        
+
         getStartLocation(v, gravity, xy);
 
         final int fromX = xy[0];
         final int fromY = xy[1];
-        
+
         int distance = (int) Math.hypot(deltaX, deltaY);
 
         drag(test, fromX, fromX + deltaX, fromY, fromY + deltaY, distance);
 
         return distance;
     }
-    
+
     /**
      * Simulate touching a view and dragging it to a specified location.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      * @param gravity Which part of the view to use for the initial down event. A combination of
      *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
      * @param toX Final location of the view after dragging
      * @param toY Final location of the view after dragging
-     * 
+     *
      * @return distance in pixels covered by the drag
      *
      * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
@@ -595,14 +601,14 @@
 
     /**
      * Simulate touching a view and dragging it to a specified location.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      * @param gravity Which part of the view to use for the initial down event. A combination of
      *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
      * @param toX Final location of the view after dragging
      * @param toY Final location of the view after dragging
-     * 
+     *
      * @return distance in pixels covered by the drag
      */
     public static int dragViewTo(InstrumentationTestCase test, View v, int gravity, int toX,
@@ -610,28 +616,28 @@
         int[] xy = new int[2];
 
         getStartLocation(v, gravity, xy);
-        
+
         final int fromX = xy[0];
         final int fromY = xy[1];
-        
+
         int deltaX = fromX - toX;
         int deltaY = fromY - toY;
-        
+
         int distance = (int)Math.hypot(deltaX, deltaY);
         drag(test, fromX, toX, fromY, toY, distance);
-        
+
         return distance;
     }
 
     /**
      * Simulate touching a view and dragging it to a specified location. Only moves horizontally.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      * @param gravity Which part of the view to use for the initial down event. A combination of
      *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
      * @param toX Final location of the view after dragging
-     * 
+     *
      * @return distance in pixels covered by the drag
      *
      * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
@@ -646,39 +652,39 @@
 
     /**
      * Simulate touching a view and dragging it to a specified location. Only moves horizontally.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      * @param gravity Which part of the view to use for the initial down event. A combination of
      *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
      * @param toX Final location of the view after dragging
-     * 
+     *
      * @return distance in pixels covered by the drag
      */
     public static int dragViewToX(InstrumentationTestCase test, View v, int gravity, int toX) {
         int[] xy = new int[2];
 
         getStartLocation(v, gravity, xy);
-        
+
         final int fromX = xy[0];
         final int fromY = xy[1];
-        
+
         int deltaX = fromX - toX;
 
         drag(test, fromX, toX, fromY, fromY, deltaX);
-        
+
         return deltaX;
     }
-    
+
     /**
      * Simulate touching a view and dragging it to a specified location. Only moves vertically.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      * @param gravity Which part of the view to use for the initial down event. A combination of
      *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
      * @param toY Final location of the view after dragging
-     * 
+     *
      * @return distance in pixels covered by the drag
      *
      * @deprecated {@link android.test.ActivityInstrumentationTestCase} is deprecated in favor of
@@ -690,37 +696,37 @@
             int toY) {
         return dragViewToY((InstrumentationTestCase) test, v, gravity, toY);
     }
-    
+
     /**
      * Simulate touching a view and dragging it to a specified location. Only moves vertically.
-     * 
+     *
      * @param test The test case that is being run
      * @param v The view that should be dragged
      * @param gravity Which part of the view to use for the initial down event. A combination of
      *        (TOP, CENTER_VERTICAL, BOTTOM) and (LEFT, CENTER_HORIZONTAL, RIGHT)
      * @param toY Final location of the view after dragging
-     * 
+     *
      * @return distance in pixels covered by the drag
      */
     public static int dragViewToY(InstrumentationTestCase test, View v, int gravity, int toY) {
         int[] xy = new int[2];
 
         getStartLocation(v, gravity, xy);
-       
+
         final int fromX = xy[0];
         final int fromY = xy[1];
-        
+
         int deltaY = fromY - toY;
 
         drag(test, fromX, fromX, fromY, toY, deltaY);
-        
+
         return deltaY;
     }
-    
+
 
     /**
      * Simulate touching a specific location and dragging to a new location.
-     * 
+     *
      * @param test The test case that is being run
      * @param fromX X coordinate of the initial touch, in screen coordinates
      * @param toX Xcoordinate of the drag destination, in screen coordinates
@@ -737,10 +743,10 @@
             float fromY, float toY, int stepCount) {
         drag((InstrumentationTestCase) test, fromX, toX, fromY, toY, stepCount);
     }
-    
+
     /**
      * Simulate touching a specific location and dragging to a new location.
-     * 
+     *
      * @param test The test case that is being run
      * @param fromX X coordinate of the initial touch, in screen coordinates
      * @param toX Xcoordinate of the drag destination, in screen coordinates
@@ -757,7 +763,7 @@
 
         float y = fromY;
         float x = fromX;
-        
+
         float yStep = (toY - fromY) / stepCount;
         float xStep = (toX - fromX) / stepCount;
 
diff --git a/test-runner/src/android/test/ViewAsserts.java b/test-runner/src/android/test/ViewAsserts.java
index c575fc5..00ab443 100644
--- a/test-runner/src/android/test/ViewAsserts.java
+++ b/test-runner/src/android/test/ViewAsserts.java
@@ -23,7 +23,15 @@
 
 /**
  * Some useful assertions about views.
+ *
+ * @deprecated Use
+ * <a href="{@docRoot}reference/android/support/test/espresso/matcher/ViewMatchers.html">Espresso
+ * View Matchers</a> instead. New test should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ * For more information about UI testing, take the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Espresso UI testing</a> training.
  */
+@Deprecated
 public class ViewAsserts {
 
     private ViewAsserts() {}
diff --git a/test-runner/src/android/test/mock/MockApplication.java b/test-runner/src/android/test/mock/MockApplication.java
index 572dfbf..3257ecf 100644
--- a/test-runner/src/android/test/mock/MockApplication.java
+++ b/test-runner/src/android/test/mock/MockApplication.java
@@ -20,12 +20,17 @@
 import android.content.res.Configuration;
 
 /**
- * A mock {@link android.app.Application} class.  All methods are non-functional and throw 
- * {@link java.lang.UnsupportedOperationException}.  Override it as necessary to provide the 
+ * A mock {@link android.app.Application} class.  All methods are non-functional and throw
+ * {@link java.lang.UnsupportedOperationException}.  Override it as necessary to provide the
  * operations that you need.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class MockApplication extends Application {
-    
+
     public MockApplication() {
     }
 
@@ -38,7 +43,7 @@
     public void onTerminate() {
         throw new UnsupportedOperationException();
     }
-    
+
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         throw new UnsupportedOperationException();
diff --git a/test-runner/src/android/test/mock/MockContentProvider.java b/test-runner/src/android/test/mock/MockContentProvider.java
index 5ef71df..3743fb0 100644
--- a/test-runner/src/android/test/mock/MockContentProvider.java
+++ b/test-runner/src/android/test/mock/MockContentProvider.java
@@ -41,7 +41,12 @@
  * Mock implementation of ContentProvider.  All methods are non-functional and throw
  * {@link java.lang.UnsupportedOperationException}.  Tests can extend this class to
  * implement behavior needed for tests.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class MockContentProvider extends ContentProvider {
     /*
      * Note: if you add methods to ContentProvider, you must add similar methods to
diff --git a/test-runner/src/android/test/mock/MockContentResolver.java b/test-runner/src/android/test/mock/MockContentResolver.java
index aec6c77..75c8335 100644
--- a/test-runner/src/android/test/mock/MockContentResolver.java
+++ b/test-runner/src/android/test/mock/MockContentResolver.java
@@ -49,8 +49,12 @@
  * <p>For more information about application testing, read the
  * <a href="{@docRoot}guide/topics/testing/index.html">Testing</a> developer guide.</p>
  * </div>
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
-
+@Deprecated
 public class MockContentResolver extends ContentResolver {
     Map<String, ContentProvider> mProviders;
 
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 64d2978..9b93bda 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -52,10 +52,15 @@
 import java.io.InputStream;
 
 /**
- * A mock {@link android.content.Context} class.  All methods are non-functional and throw 
+ * A mock {@link android.content.Context} class.  All methods are non-functional and throw
  * {@link java.lang.UnsupportedOperationException}.  You can use this to inject other dependencies,
  * mocks, or monitors into the classes you are testing.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class MockContext extends Context {
 
     @Override
@@ -82,12 +87,12 @@
     public Looper getMainLooper() {
         throw new UnsupportedOperationException();
     }
-    
+
     @Override
     public Context getApplicationContext() {
         throw new UnsupportedOperationException();
     }
-    
+
     @Override
     public void setTheme(int resid) {
         throw new UnsupportedOperationException();
@@ -124,7 +129,7 @@
     public ApplicationInfo getApplicationInfo() {
         throw new UnsupportedOperationException();
     }
-    
+
     @Override
     public String getPackageResourcePath() {
         throw new UnsupportedOperationException();
@@ -194,7 +199,7 @@
     public File getObbDir() {
         throw new UnsupportedOperationException();
     }
-    
+
     @Override
     public File getCacheDir() {
         throw new UnsupportedOperationException();
@@ -216,7 +221,7 @@
     }
 
     @Override
-    public SQLiteDatabase openOrCreateDatabase(String file, int mode, 
+    public SQLiteDatabase openOrCreateDatabase(String file, int mode,
             SQLiteDatabase.CursorFactory factory) {
         throw new UnsupportedOperationException();
     }
@@ -310,7 +315,7 @@
             Bundle options) throws IntentSender.SendIntentException {
         startIntentSender(intent, fillInIntent, flagsMask, flagsValues, extraFlags);
     }
-    
+
     @Override
     public void sendBroadcast(Intent intent) {
         throw new UnsupportedOperationException();
diff --git a/test-runner/src/android/test/mock/MockCursor.java b/test-runner/src/android/test/mock/MockCursor.java
index 28fa0f8..576f24a 100644
--- a/test-runner/src/android/test/mock/MockCursor.java
+++ b/test-runner/src/android/test/mock/MockCursor.java
@@ -25,15 +25,18 @@
 import android.os.Bundle;
 
 /**
- * <P>
  * A mock {@link android.database.Cursor} class that isolates the test code from real
  * Cursor implementation.
- * </P>
- * <P>
+ *
+ * <p>
  * All methods including ones related to querying the state of the cursor are
  * are non-functional and throw {@link java.lang.UnsupportedOperationException}.
- * </P>
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class MockCursor implements Cursor {
     @Override
     public int getColumnCount() {
diff --git a/test-runner/src/android/test/mock/MockDialogInterface.java b/test-runner/src/android/test/mock/MockDialogInterface.java
index e4dd0ba..d0a5a09 100644
--- a/test-runner/src/android/test/mock/MockDialogInterface.java
+++ b/test-runner/src/android/test/mock/MockDialogInterface.java
@@ -1,14 +1,33 @@
-// Copyright 2008 The Android Open Source Project
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 package android.test.mock;
 
 import android.content.DialogInterface;
 
 /**
- * A mock {@link android.content.DialogInterface} class.  All methods are non-functional and throw 
- * {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you 
+ * A mock {@link android.content.DialogInterface} class.  All methods are non-functional and throw
+ * {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you
  * need.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class MockDialogInterface implements DialogInterface {
     public void cancel() {
         throw new UnsupportedOperationException("not implemented yet");
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 2813df5..ffb73f6 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -34,7 +34,6 @@
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.KeySet;
-import android.content.pm.ManifestDigest;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageItemInfo;
@@ -61,7 +60,12 @@
  * A mock {@link android.content.pm.PackageManager} class.  All methods are non-functional and throw
  * {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you
  * need.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class MockPackageManager extends PackageManager {
 
     @Override
@@ -97,14 +101,30 @@
     }
 
     @Override
-
     public int[] getPackageGids(String packageName) throws NameNotFoundException {
         throw new UnsupportedOperationException();
     }
 
+    @Override
+    public int[] getPackageGids(String packageName, int flags) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getPackageUid(String packageName, int flags) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
     /** @hide */
     @Override
-    public int getPackageUid(String packageName, int userHandle)
+    public int getPackageUidAsUser(String packageName, int flags, int userHandle)
+            throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public int getPackageUidAsUser(String packageName, int userHandle)
             throws NameNotFoundException {
         throw new UnsupportedOperationException();
     }
@@ -134,7 +154,14 @@
 
     @Override
     public ApplicationInfo getApplicationInfo(String packageName, int flags)
-    throws NameNotFoundException {
+            throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public ApplicationInfo getApplicationInfoAsUser(String packageName, int flags, int userId)
+            throws NameNotFoundException {
         throw new UnsupportedOperationException();
     }
 
@@ -175,7 +202,7 @@
 
     /** @hide */
     @Override
-    public List<PackageInfo> getInstalledPackages(int flags, int userId) {
+    public List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {
         throw new UnsupportedOperationException();
     }
 
@@ -300,21 +327,25 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
     @Override
     public byte[] getEphemeralCookie() {
         return new byte[0];
     }
 
+    /** @hide */
     @Override
     public boolean isEphemeralApplication() {
         return false;
     }
 
+    /** @hide */
     @Override
     public int getEphemeralCookieMaxSizeBytes() {
         return 0;
     }
 
+    /** @hide */
     @Override
     public boolean setEphemeralCookie(@NonNull byte[] cookie) {
         return false;
@@ -356,7 +387,7 @@
 
     /** @hide */
     @Override
-    public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags, int userId) {
+    public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent, int flags, int userId) {
         throw new UnsupportedOperationException();
     }
 
@@ -506,6 +537,12 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
+    @Override
+    public Drawable getUserBadgeForDensityNoBackground(UserHandle user, int density) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public CharSequence getUserBadgedLabel(CharSequence label, UserHandle user) {
         throw new UnsupportedOperationException();
@@ -747,7 +784,7 @@
      * @hide - to match hiding in superclass
      */
     @Override
-    public void getPackageSizeInfo(String packageName, int userHandle,
+    public void getPackageSizeInfoAsUser(String packageName, int userHandle,
             IPackageStatsObserver observer) {
         throw new UnsupportedOperationException();
     }
@@ -820,7 +857,7 @@
     @Override
     public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
             int flags, String installerPackageName, Uri verificationURI,
-            ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
+            ContainerEncryptionParams encryptionParams) {
         throw new UnsupportedOperationException();
     }
 
@@ -891,7 +928,7 @@
      * @hide
      */
     @Override
-    public int getIntentVerificationStatus(String packageName, int userId) {
+    public int getIntentVerificationStatusAsUser(String packageName, int userId) {
         throw new UnsupportedOperationException();
     }
 
@@ -899,7 +936,7 @@
      * @hide
      */
     @Override
-    public boolean updateIntentVerificationStatus(String packageName, int status, int userId) {
+    public boolean updateIntentVerificationStatusAsUser(String packageName, int status, int userId) {
         throw new UnsupportedOperationException();
     }
 
@@ -916,16 +953,30 @@
         throw new UnsupportedOperationException();
     }
 
-    @Override
+    /** {@removed} */
+    @Deprecated
     public String getDefaultBrowserPackageName(int userId) {
         throw new UnsupportedOperationException();
     }
 
+    /** {@hide} */
     @Override
+    public String getDefaultBrowserPackageNameAsUser(int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** {@removed} */
+    @Deprecated
     public boolean setDefaultBrowserPackageName(String packageName, int userId) {
         throw new UnsupportedOperationException();
     }
 
+    /** {@hide} */
+    @Override
+    public boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
     /**
      * @hide
      */
@@ -957,7 +1008,7 @@
     @Override
     public void installPackageWithVerification(Uri packageURI,
             PackageInstallObserver observer, int flags, String installerPackageName,
-            Uri verificationURI, ManifestDigest manifestDigest,
+            Uri verificationURI,
             ContainerEncryptionParams encryptionParams) {
         throw new UnsupportedOperationException();
     }
diff --git a/test-runner/src/android/test/mock/MockResources.java b/test-runner/src/android/test/mock/MockResources.java
index 18752ce..880343e 100644
--- a/test-runner/src/android/test/mock/MockResources.java
+++ b/test-runner/src/android/test/mock/MockResources.java
@@ -32,10 +32,15 @@
 import java.io.InputStream;
 
 /**
- * A mock {@link android.content.res.Resources} class.  All methods are non-functional and throw 
- * {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you 
+ * A mock {@link android.content.res.Resources} class. All methods are non-functional and throw
+ * {@link java.lang.UnsupportedOperationException}. Override it to provide the operations that you
  * need.
+ *
+ * @deprecated Use a mocking framework like <a href="https://github.com/mockito/mockito">Mockito</a>.
+ * New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 public class MockResources extends Resources {
 
     public MockResources() {
diff --git a/tests/FeatureSplit/base/AndroidManifest.xml b/tests/FeatureSplit/base/AndroidManifest.xml
index 989e802..e82b3b9 100644
--- a/tests/FeatureSplit/base/AndroidManifest.xml
+++ b/tests/FeatureSplit/base/AndroidManifest.xml
@@ -16,7 +16,15 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.test.split.feature">
-    <application android:label="@string/app_title"
-        android:hasCode="false">
+
+    <uses-sdk android:minSdkVersion="21" />
+
+    <application android:label="@string/app_title">
+        <activity android:name=".ActivityMain" android:label="Feature Base">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/tests/FeatureSplit/base/res/layout/main.xml b/tests/FeatureSplit/base/res/layout/main.xml
new file mode 100644
index 0000000..f01b920
--- /dev/null
+++ b/tests/FeatureSplit/base/res/layout/main.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:padding="16dp">
+    <TextView android:id="@+id/text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerInParent="true"
+        android:textAppearance="?android:textAppearanceLarge" />
+</RelativeLayout>
diff --git a/tests/FeatureSplit/base/res/values/values.xml b/tests/FeatureSplit/base/res/values/values.xml
index 564d301..854a8bb 100644
--- a/tests/FeatureSplit/base/res/values/values.xml
+++ b/tests/FeatureSplit/base/res/values/values.xml
@@ -16,6 +16,7 @@
 
 <resources>
     <string name="app_title">FeatureSplit APK</string>
+    <string name="base">Base</string>
 
     <item type="id" name="test_id"/>
     <integer name="test_integer">100</integer>
diff --git a/tests/FeatureSplit/base/src/com/android/test/split/feature/ActivityMain.java b/tests/FeatureSplit/base/src/com/android/test/split/feature/ActivityMain.java
new file mode 100644
index 0000000..6cca7c3
--- /dev/null
+++ b/tests/FeatureSplit/base/src/com/android/test/split/feature/ActivityMain.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.split.feature;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+public class ActivityMain extends Activity {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+        ((TextView) findViewById(R.id.text)).setText(R.string.base);
+    }
+}
+
diff --git a/tests/FeatureSplit/feature1/Android.mk b/tests/FeatureSplit/feature1/Android.mk
index adfb575..aa222dd 100644
--- a/tests/FeatureSplit/feature1/Android.mk
+++ b/tests/FeatureSplit/feature1/Android.mk
@@ -22,10 +22,12 @@
 LOCAL_MODULE_TAGS := tests
 
 featureOf := FeatureSplitBase
+
+LOCAL_APK_LIBRARIES := $(featureOf)
 featureOfApk := $(call intermediates-dir-for,APPS,$(featureOf))/package.apk
 localRStamp := $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),,COMMON)/src/R.stamp
 $(localRStamp): $(featureOfApk)
 
-LOCAL_AAPT_FLAGS := --feature-of $(featureOfApk)
+LOCAL_AAPT_FLAGS := --feature-of $(featureOfApk) --custom-package com.android.test.split.feature.one
 
 include $(BUILD_PACKAGE)
diff --git a/tests/FeatureSplit/feature1/AndroidManifest.xml b/tests/FeatureSplit/feature1/AndroidManifest.xml
index 2aadc6d..42619b6 100644
--- a/tests/FeatureSplit/feature1/AndroidManifest.xml
+++ b/tests/FeatureSplit/feature1/AndroidManifest.xml
@@ -17,5 +17,15 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.test.split.feature"
     featureName="feature1">
-    <application android:hasCode="false" />
+
+    <uses-sdk android:minSdkVersion="21" />
+
+    <application>
+        <activity android:name=".one.One" android:label="Feature One">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
 </manifest>
diff --git a/tests/FeatureSplit/feature1/res/values/values.xml b/tests/FeatureSplit/feature1/res/values/values.xml
index 70eb56a..10dbd97 100644
--- a/tests/FeatureSplit/feature1/res/values/values.xml
+++ b/tests/FeatureSplit/feature1/res/values/values.xml
@@ -15,6 +15,7 @@
 -->
 
 <resources>
+    <string name="feature_string">Feature1</string>
     <item type="id" name="test_id2"/>
     <integer name="test_integer2">200</integer>
     <color name="test_color2">#00ff00</color>
diff --git a/tests/FeatureSplit/feature1/src/com/android/test/split/feature/one/One.java b/tests/FeatureSplit/feature1/src/com/android/test/split/feature/one/One.java
new file mode 100644
index 0000000..def1339
--- /dev/null
+++ b/tests/FeatureSplit/feature1/src/com/android/test/split/feature/one/One.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.split.feature.one;
+
+import com.android.test.split.feature.ActivityMain;
+
+import android.widget.TextView;
+import android.os.Bundle;
+
+public class One extends ActivityMain {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        ((TextView) findViewById(com.android.test.split.feature.R.id.text))
+                .setText(R.string.feature_string);
+    }
+}
diff --git a/tests/FeatureSplit/feature2/Android.mk b/tests/FeatureSplit/feature2/Android.mk
index e69cbe8..1a0322b 100644
--- a/tests/FeatureSplit/feature2/Android.mk
+++ b/tests/FeatureSplit/feature2/Android.mk
@@ -24,6 +24,8 @@
 featureOf := FeatureSplitBase
 featureAfter := FeatureSplit1
 
+LOCAL_APK_LIBRARIES := $(featureOf)
+
 featureOfApk := $(call intermediates-dir-for,APPS,$(featureOf))/package.apk
 featureAfterApk := $(call intermediates-dir-for,APPS,$(featureAfter))/package.apk
 localRStamp := $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),,COMMON)/src/R.stamp
@@ -31,5 +33,6 @@
 
 LOCAL_AAPT_FLAGS := --feature-of $(featureOfApk)
 LOCAL_AAPT_FLAGS += --feature-after $(featureAfterApk)
+LOCAL_AAPT_FLAGS += --custom-package com.android.test.split.feature.two
 
 include $(BUILD_PACKAGE)
diff --git a/tests/FeatureSplit/feature2/AndroidManifest.xml b/tests/FeatureSplit/feature2/AndroidManifest.xml
index d139900..b50044a 100644
--- a/tests/FeatureSplit/feature2/AndroidManifest.xml
+++ b/tests/FeatureSplit/feature2/AndroidManifest.xml
@@ -17,5 +17,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.test.split.feature"
     featureName="feature2">
+
+    <uses-sdk android:minSdkVersion="21" />
+
     <application android:hasCode="false"/>
 </manifest>
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestCertificateSource.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestCertificateSource.java
index 0c36063..4c12c2d 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestCertificateSource.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestCertificateSource.java
@@ -16,8 +16,9 @@
 
 package android.security.net.config;
 
-import java.util.Set;
+import android.util.ArraySet;
 import java.security.cert.X509Certificate;
+import java.util.Set;
 
 import com.android.org.conscrypt.TrustedCertificateIndex;
 
@@ -33,10 +34,12 @@
         }
     }
 
+    @Override
     public Set<X509Certificate> getCertificates() {
             return mCertificates;
     }
 
+    @Override
     public X509Certificate findBySubjectAndPublicKey(X509Certificate cert) {
         java.security.cert.TrustAnchor anchor = mIndex.findBySubjectAndPublicKey(cert);
         if (anchor == null) {
@@ -45,6 +48,7 @@
         return anchor.getTrustedCert();
     }
 
+    @Override
     public X509Certificate findByIssuerAndSignature(X509Certificate cert) {
         java.security.cert.TrustAnchor anchor = mIndex.findByIssuerAndSignature(cert);
         if (anchor == null) {
@@ -52,4 +56,13 @@
         }
         return anchor.getTrustedCert();
     }
+
+    @Override
+    public Set<X509Certificate> findAllByIssuerAndSignature(X509Certificate cert) {
+        Set<X509Certificate> certs = new ArraySet<X509Certificate>();
+        for (java.security.cert.TrustAnchor anchor : mIndex.findAllByIssuerAndSignature(cert)) {
+            certs.add(anchor.getTrustedCert());
+        }
+        return certs;
+    }
 }
diff --git a/tests/RenderScriptTests/Android.mk b/tests/RenderScriptTests/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/tests/RenderScriptTests/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/tests/RenderScriptTests/FBOTest/Android.mk b/tests/RenderScriptTests/FBOTest/Android.mk
deleted file mode 100644
index 7a578d9..0000000
--- a/tests/RenderScriptTests/FBOTest/Android.mk
+++ /dev/null
@@ -1,28 +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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-
-LOCAL_PACKAGE_NAME := FBOTest
-
-LOCAL_SDK_VERSION := 17
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/FBOTest/AndroidManifest.xml b/tests/RenderScriptTests/FBOTest/AndroidManifest.xml
deleted file mode 100644
index 788e856..0000000
--- a/tests/RenderScriptTests/FBOTest/AndroidManifest.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.fbotest">
-    <application android:label="_FBOTest">
-        <activity android:name="FBOTest"
-                  android:label="FBO Base Test"
-                  android:theme="@android:style/Theme.Black.NoTitleBar">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-        <activity android:name="FBOSync"
-                  android:label="FBO Sync Test"
-                  android:theme="@android:style/Theme.Black.NoTitleBar">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/FBOTest/res/drawable-nodpi/robot.png b/tests/RenderScriptTests/FBOTest/res/drawable-nodpi/robot.png
deleted file mode 100644
index f7353fd..0000000
--- a/tests/RenderScriptTests/FBOTest/res/drawable-nodpi/robot.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/FBOTest/res/raw/robot.a3d b/tests/RenderScriptTests/FBOTest/res/raw/robot.a3d
deleted file mode 100644
index f48895c..0000000
--- a/tests/RenderScriptTests/FBOTest/res/raw/robot.a3d
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSync.java b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSync.java
deleted file mode 100644
index d30ad7e..0000000
--- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSync.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.fbotest;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-
-import android.app.Activity;
-import android.content.res.Configuration;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Settings.System;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.MenuInflater;
-import android.view.Window;
-import android.widget.Button;
-import android.widget.ListView;
-import android.net.Uri;
-
-import java.lang.Runtime;
-
-public class FBOSync extends Activity {
-
-    private FBOSyncView mView;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        // Create our Preview view and set it as the content of our
-        // Activity
-        mView = new FBOSyncView(this);
-        setContentView(mView);
-    }
-
-    @Override
-    protected void onResume() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity looses focus
-        super.onResume();
-        mView.resume();
-    }
-
-    @Override
-    protected void onPause() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity looses focus
-        super.onPause();
-        mView.pause();
-    }
-}
-
diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSyncRS.java b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSyncRS.java
deleted file mode 100644
index 57a117c..0000000
--- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSyncRS.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.fbotest;
-
-import java.io.Writer;
-
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.renderscript.Element.DataType;
-import android.renderscript.Element.DataKind;
-import android.renderscript.ProgramStore.DepthFunc;
-import android.renderscript.Type.Builder;
-import android.util.Log;
-
-
-public class FBOSyncRS {
-
-    public FBOSyncRS() {
-    }
-
-    public void init(RenderScriptGL rs, Resources res) {
-        mRS = rs;
-        mRes = res;
-        initRS();
-    }
-
-    public void surfaceChanged() {
-        mRS.getWidth();
-        mRS.getHeight();
-    }
-
-    private Resources mRes;
-    private RenderScriptGL mRS;
-    private Sampler mSampler;
-    private ProgramStore mPSBackground;
-    private ProgramFragment mPFBackground;
-    private ProgramVertex mPVBackground;
-    private ProgramVertexFixedFunction.Constants mPVA;
-
-    private Allocation mGridImage;
-    private Allocation mOffscreen;
-    private Allocation mOffscreenDepth;
-    private Allocation mAllocPV;
-    private Allocation mReadBackTest;
-
-    private Font mItalic;
-    private Allocation mTextAlloc;
-
-    private ScriptField_MeshInfo mMeshes;
-    private ScriptC_fbosync mScript;
-
-
-    public void onActionDown(float x, float y) {
-        mScript.invoke_onActionDown(x, y);
-    }
-
-    public void onActionScale(float scale) {
-        mScript.invoke_onActionScale(scale);
-    }
-
-    public void onActionMove(float x, float y) {
-        mScript.invoke_onActionMove(x, y);
-    }
-
-    private void initPFS() {
-        ProgramStore.Builder b = new ProgramStore.Builder(mRS);
-
-        b.setDepthFunc(ProgramStore.DepthFunc.LESS);
-        b.setDitherEnabled(false);
-        b.setDepthMaskEnabled(true);
-        mPSBackground = b.create();
-
-        mScript.set_gPFSBackground(mPSBackground);
-    }
-
-    private void initPF() {
-        Sampler.Builder bs = new Sampler.Builder(mRS);
-        bs.setMinification(Sampler.Value.LINEAR);
-        bs.setMagnification(Sampler.Value.LINEAR);
-        bs.setWrapS(Sampler.Value.CLAMP);
-        bs.setWrapT(Sampler.Value.CLAMP);
-        mSampler = bs.create();
-
-        ProgramFragmentFixedFunction.Builder b = new ProgramFragmentFixedFunction.Builder(mRS);
-        b.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
-                     ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
-        mPFBackground = b.create();
-        mPFBackground.bindSampler(mSampler, 0);
-
-        mScript.set_gPFBackground(mPFBackground);
-    }
-
-    private void initPV() {
-        ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
-        mPVBackground = pvb.create();
-
-        mPVA = new ProgramVertexFixedFunction.Constants(mRS);
-        ((ProgramVertexFixedFunction)mPVBackground).bindConstants(mPVA);
-
-        mScript.set_gPVBackground(mPVBackground);
-    }
-
-    private void loadImage() {
-        mGridImage = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot,
-                                                         Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
-                                                         Allocation.USAGE_GRAPHICS_TEXTURE);
-        mScript.set_gTGrid(mGridImage);
-    }
-
-    private void initTextAllocation(String fileName) {
-        String allocString = "Displaying file: " + fileName;
-        mTextAlloc = Allocation.createFromString(mRS, allocString, Allocation.USAGE_SCRIPT);
-        mScript.set_gTextAlloc(mTextAlloc);
-    }
-
-    private void initMeshes(FileA3D model) {
-        int numEntries = model.getIndexEntryCount();
-        int numMeshes = 0;
-        for (int i = 0; i < numEntries; i ++) {
-            FileA3D.IndexEntry entry = model.getIndexEntry(i);
-            if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) {
-                numMeshes ++;
-            }
-        }
-
-        if (numMeshes > 0) {
-            mMeshes = new ScriptField_MeshInfo(mRS, numMeshes);
-
-            for (int i = 0; i < numEntries; i ++) {
-                FileA3D.IndexEntry entry = model.getIndexEntry(i);
-                if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) {
-                    Mesh mesh = entry.getMesh();
-                    mMeshes.set_mMesh(i, mesh, false);
-                    mMeshes.set_mNumIndexSets(i, mesh.getPrimitiveCount(), false);
-                }
-            }
-            mMeshes.copyAll();
-        } else {
-            throw new RSRuntimeException("No valid meshes in file");
-        }
-
-        mScript.bind_gMeshes(mMeshes);
-        mScript.invoke_updateMeshInfo();
-    }
-
-    public void loadA3DFile(String path) {
-        FileA3D model = FileA3D.createFromFile(mRS, path);
-        initMeshes(model);
-        initTextAllocation(path);
-    }
-
-    private void initRS() {
-
-        mScript = new ScriptC_fbosync(mRS, mRes, R.raw.fbosync);
-
-        initPFS();
-        initPF();
-        initPV();
-
-        loadImage();
-
-        Type.Builder b = new Type.Builder(mRS, Element.RGBA_8888(mRS));
-        b.setX(512).setY(512);
-        mOffscreen = Allocation.createTyped(mRS,
-                                            b.create(),
-                                            Allocation.USAGE_SCRIPT |
-                                            Allocation.USAGE_GRAPHICS_TEXTURE |
-                                            Allocation.USAGE_GRAPHICS_RENDER_TARGET);
-        mScript.set_gOffscreen(mOffscreen);
-
-        mReadBackTest = Allocation.createTyped(mRS,
-                                               b.create(),
-                                               Allocation.USAGE_SCRIPT |
-                                               Allocation.USAGE_GRAPHICS_TEXTURE);
-        mScript.set_gReadBackTest(mReadBackTest);
-
-        b = new Type.Builder(mRS,
-                             Element.createPixel(mRS, DataType.UNSIGNED_16,
-                             DataKind.PIXEL_DEPTH));
-        b.setX(512).setY(512);
-        mOffscreenDepth = Allocation.createTyped(mRS,
-                                                 b.create(),
-                                                 Allocation.USAGE_GRAPHICS_RENDER_TARGET);
-        mScript.set_gOffscreenDepth(mOffscreenDepth);
-
-        FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot);
-        initMeshes(model);
-
-        mItalic = Font.create(mRS, mRes, "serif", Font.Style.ITALIC, 8);
-        mScript.set_gItalic(mItalic);
-
-        initTextAllocation("R.raw.robot");
-
-        mRS.bindRootScript(mScript);
-    }
-}
-
-
-
diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSyncView.java b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSyncView.java
deleted file mode 100644
index 6a85628..0000000
--- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSyncView.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.fbotest;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScriptGL;
-
-import android.content.Context;
-import android.view.MotionEvent;
-import android.view.SurfaceHolder;
-import android.view.ScaleGestureDetector;
-import android.util.Log;
-
-public class FBOSyncView extends RSSurfaceView {
-
-    private RenderScriptGL mRS;
-    private FBOSyncRS mRender;
-
-    private ScaleGestureDetector mScaleDetector;
-
-    private static final int INVALID_POINTER_ID = -1;
-    private int mActivePointerId = INVALID_POINTER_ID;
-
-    public FBOSyncView(Context context) {
-        super(context);
-        ensureRenderScript();
-        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
-    }
-
-    private void ensureRenderScript() {
-        if (mRS == null) {
-            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
-            sc.setDepth(16, 24);
-            mRS = createRenderScriptGL(sc);
-            mRender = new FBOSyncRS();
-            mRender.init(mRS, getResources());
-        }
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        ensureRenderScript();
-    }
-
-    @Override
-    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
-        super.surfaceChanged(holder, format, w, h);
-        mRender.surfaceChanged();
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        mRender = null;
-        if (mRS != null) {
-            mRS = null;
-            destroyRenderScriptGL();
-        }
-    }
-
-    public void loadA3DFile(String path) {
-        mRender.loadA3DFile(path);
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        mScaleDetector.onTouchEvent(ev);
-
-        boolean ret = false;
-        float x = ev.getX();
-        float y = ev.getY();
-
-        final int action = ev.getAction();
-
-        switch (action & MotionEvent.ACTION_MASK) {
-        case MotionEvent.ACTION_DOWN: {
-            mRender.onActionDown(x, y);
-            mActivePointerId = ev.getPointerId(0);
-            ret = true;
-            break;
-        }
-        case MotionEvent.ACTION_MOVE: {
-            if (!mScaleDetector.isInProgress()) {
-                mRender.onActionMove(x, y);
-            }
-            mRender.onActionDown(x, y);
-            ret = true;
-            break;
-        }
-
-        case MotionEvent.ACTION_UP: {
-            mActivePointerId = INVALID_POINTER_ID;
-            break;
-        }
-
-        case MotionEvent.ACTION_CANCEL: {
-            mActivePointerId = INVALID_POINTER_ID;
-            break;
-        }
-
-        case MotionEvent.ACTION_POINTER_UP: {
-            final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
-                    >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
-            final int pointerId = ev.getPointerId(pointerIndex);
-            if (pointerId == mActivePointerId) {
-                // This was our active pointer going up. Choose a new
-                // active pointer and adjust accordingly.
-                final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
-                x = ev.getX(newPointerIndex);
-                y = ev.getY(newPointerIndex);
-                mRender.onActionDown(x, y);
-                mActivePointerId = ev.getPointerId(newPointerIndex);
-            }
-            break;
-        }
-        }
-
-        return ret;
-    }
-
-    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
-        @Override
-        public boolean onScale(ScaleGestureDetector detector) {
-            mRender.onActionScale(detector.getScaleFactor());
-            return true;
-        }
-    }
-}
-
-
diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTest.java b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTest.java
deleted file mode 100644
index 72aa3ea..0000000
--- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.fbotest;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-
-import android.app.Activity;
-import android.content.res.Configuration;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Settings.System;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.MenuInflater;
-import android.view.Window;
-import android.widget.Button;
-import android.widget.ListView;
-import android.net.Uri;
-
-import java.lang.Runtime;
-
-public class FBOTest extends Activity {
-
-    private FBOTestView mView;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        // Create our Preview view and set it as the content of our
-        // Activity
-        mView = new FBOTestView(this);
-        setContentView(mView);
-    }
-
-    @Override
-    protected void onResume() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity looses focus
-        super.onResume();
-        mView.resume();
-    }
-
-    @Override
-    protected void onPause() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity looses focus
-        super.onPause();
-        mView.pause();
-    }
-}
-
diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTestRS.java b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTestRS.java
deleted file mode 100644
index 9e30c4b5..0000000
--- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTestRS.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.fbotest;
-
-import java.io.Writer;
-
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.renderscript.Element.DataType;
-import android.renderscript.Element.DataKind;
-import android.renderscript.ProgramStore.DepthFunc;
-import android.renderscript.Type.Builder;
-import android.util.Log;
-
-
-public class FBOTestRS {
-
-    public FBOTestRS() {
-    }
-
-    public void init(RenderScriptGL rs, Resources res) {
-        mRS = rs;
-        mRes = res;
-        initRS();
-    }
-
-    public void surfaceChanged() {
-        mRS.getWidth();
-        mRS.getHeight();
-    }
-
-    private Resources mRes;
-    private RenderScriptGL mRS;
-    private Sampler mSampler;
-    private ProgramStore mPSBackground;
-    private ProgramFragment mPFBackground;
-    private ProgramVertex mPVBackground;
-    private ProgramVertexFixedFunction.Constants mPVA;
-
-    private Allocation mGridImage;
-    private Allocation mOffscreen;
-    private Allocation mOffscreenDepth;
-    private Allocation mAllocPV;
-
-    private Font mItalic;
-    private Allocation mTextAlloc;
-
-    private ScriptField_MeshInfo mMeshes;
-    private ScriptC_fbotest mScript;
-
-
-    public void onActionDown(float x, float y) {
-        mScript.invoke_onActionDown(x, y);
-    }
-
-    public void onActionScale(float scale) {
-        mScript.invoke_onActionScale(scale);
-    }
-
-    public void onActionMove(float x, float y) {
-        mScript.invoke_onActionMove(x, y);
-    }
-
-    private void initPFS() {
-        ProgramStore.Builder b = new ProgramStore.Builder(mRS);
-
-        b.setDepthFunc(ProgramStore.DepthFunc.LESS);
-        b.setDitherEnabled(false);
-        b.setDepthMaskEnabled(true);
-        mPSBackground = b.create();
-
-        mScript.set_gPFSBackground(mPSBackground);
-    }
-
-    private void initPF() {
-        Sampler.Builder bs = new Sampler.Builder(mRS);
-        bs.setMinification(Sampler.Value.LINEAR);
-        bs.setMagnification(Sampler.Value.LINEAR);
-        bs.setWrapS(Sampler.Value.CLAMP);
-        bs.setWrapT(Sampler.Value.CLAMP);
-        mSampler = bs.create();
-
-        ProgramFragmentFixedFunction.Builder b = new ProgramFragmentFixedFunction.Builder(mRS);
-        b.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
-                     ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
-        mPFBackground = b.create();
-        mPFBackground.bindSampler(mSampler, 0);
-
-        mScript.set_gPFBackground(mPFBackground);
-    }
-
-    private void initPV() {
-        ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
-        mPVBackground = pvb.create();
-
-        mPVA = new ProgramVertexFixedFunction.Constants(mRS);
-        ((ProgramVertexFixedFunction)mPVBackground).bindConstants(mPVA);
-
-        mScript.set_gPVBackground(mPVBackground);
-    }
-
-    private void loadImage() {
-        mGridImage = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot,
-                                                         Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
-                                                         Allocation.USAGE_GRAPHICS_TEXTURE);
-        mScript.set_gTGrid(mGridImage);
-    }
-
-    private void initTextAllocation(String fileName) {
-        String allocString = "Displaying file: " + fileName;
-        mTextAlloc = Allocation.createFromString(mRS, allocString, Allocation.USAGE_SCRIPT);
-        mScript.set_gTextAlloc(mTextAlloc);
-    }
-
-    private void initMeshes(FileA3D model) {
-        int numEntries = model.getIndexEntryCount();
-        int numMeshes = 0;
-        for (int i = 0; i < numEntries; i ++) {
-            FileA3D.IndexEntry entry = model.getIndexEntry(i);
-            if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) {
-                numMeshes ++;
-            }
-        }
-
-        if (numMeshes > 0) {
-            mMeshes = new ScriptField_MeshInfo(mRS, numMeshes);
-
-            for (int i = 0; i < numEntries; i ++) {
-                FileA3D.IndexEntry entry = model.getIndexEntry(i);
-                if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) {
-                    Mesh mesh = entry.getMesh();
-                    mMeshes.set_mMesh(i, mesh, false);
-                    mMeshes.set_mNumIndexSets(i, mesh.getPrimitiveCount(), false);
-                }
-            }
-            mMeshes.copyAll();
-        } else {
-            throw new RSRuntimeException("No valid meshes in file");
-        }
-
-        mScript.bind_gMeshes(mMeshes);
-        mScript.invoke_updateMeshInfo();
-    }
-
-    public void loadA3DFile(String path) {
-        FileA3D model = FileA3D.createFromFile(mRS, path);
-        initMeshes(model);
-        initTextAllocation(path);
-    }
-
-    private void initRS() {
-
-        mScript = new ScriptC_fbotest(mRS, mRes, R.raw.fbotest);
-
-        initPFS();
-        initPF();
-        initPV();
-
-        loadImage();
-
-        Type.Builder b = new Type.Builder(mRS, Element.RGBA_8888(mRS));
-        b.setX(512).setY(512);
-        mOffscreen = Allocation.createTyped(mRS,
-                                            b.create(),
-                                            Allocation.USAGE_GRAPHICS_TEXTURE |
-                                            Allocation.USAGE_GRAPHICS_RENDER_TARGET);
-        mScript.set_gOffscreen(mOffscreen);
-
-        b = new Type.Builder(mRS,
-                             Element.createPixel(mRS, DataType.UNSIGNED_16,
-                             DataKind.PIXEL_DEPTH));
-        b.setX(512).setY(512);
-        mOffscreenDepth = Allocation.createTyped(mRS,
-                                                 b.create(),
-                                                 Allocation.USAGE_GRAPHICS_RENDER_TARGET);
-        mScript.set_gOffscreenDepth(mOffscreenDepth);
-
-        FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot);
-        initMeshes(model);
-
-        mItalic = Font.create(mRS, mRes, "serif", Font.Style.ITALIC, 8);
-        mScript.set_gItalic(mItalic);
-
-        initTextAllocation("R.raw.robot");
-
-        mRS.bindRootScript(mScript);
-    }
-}
-
-
-
diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTestView.java b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTestView.java
deleted file mode 100644
index c9598ee..0000000
--- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTestView.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.fbotest;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScriptGL;
-
-import android.content.Context;
-import android.view.MotionEvent;
-import android.view.SurfaceHolder;
-import android.view.ScaleGestureDetector;
-import android.util.Log;
-
-public class FBOTestView extends RSSurfaceView {
-
-    private RenderScriptGL mRS;
-    private FBOTestRS mRender;
-
-    private ScaleGestureDetector mScaleDetector;
-
-    private static final int INVALID_POINTER_ID = -1;
-    private int mActivePointerId = INVALID_POINTER_ID;
-
-    public FBOTestView(Context context) {
-        super(context);
-        ensureRenderScript();
-        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
-    }
-
-    private void ensureRenderScript() {
-        if (mRS == null) {
-            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
-            sc.setDepth(16, 24);
-            mRS = createRenderScriptGL(sc);
-            mRender = new FBOTestRS();
-            mRender.init(mRS, getResources());
-        }
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        ensureRenderScript();
-    }
-
-    @Override
-    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
-        super.surfaceChanged(holder, format, w, h);
-        mRender.surfaceChanged();
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        mRender = null;
-        if (mRS != null) {
-            mRS = null;
-            destroyRenderScriptGL();
-        }
-    }
-
-    public void loadA3DFile(String path) {
-        mRender.loadA3DFile(path);
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        mScaleDetector.onTouchEvent(ev);
-
-        boolean ret = false;
-        float x = ev.getX();
-        float y = ev.getY();
-
-        final int action = ev.getAction();
-
-        switch (action & MotionEvent.ACTION_MASK) {
-        case MotionEvent.ACTION_DOWN: {
-            mRender.onActionDown(x, y);
-            mActivePointerId = ev.getPointerId(0);
-            ret = true;
-            break;
-        }
-        case MotionEvent.ACTION_MOVE: {
-            if (!mScaleDetector.isInProgress()) {
-                mRender.onActionMove(x, y);
-            }
-            mRender.onActionDown(x, y);
-            ret = true;
-            break;
-        }
-
-        case MotionEvent.ACTION_UP: {
-            mActivePointerId = INVALID_POINTER_ID;
-            break;
-        }
-
-        case MotionEvent.ACTION_CANCEL: {
-            mActivePointerId = INVALID_POINTER_ID;
-            break;
-        }
-
-        case MotionEvent.ACTION_POINTER_UP: {
-            final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
-                    >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
-            final int pointerId = ev.getPointerId(pointerIndex);
-            if (pointerId == mActivePointerId) {
-                // This was our active pointer going up. Choose a new
-                // active pointer and adjust accordingly.
-                final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
-                x = ev.getX(newPointerIndex);
-                y = ev.getY(newPointerIndex);
-                mRender.onActionDown(x, y);
-                mActivePointerId = ev.getPointerId(newPointerIndex);
-            }
-            break;
-        }
-        }
-
-        return ret;
-    }
-
-    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
-        @Override
-        public boolean onScale(ScaleGestureDetector detector) {
-            mRender.onActionScale(detector.getScaleFactor());
-            return true;
-        }
-    }
-}
-
-
diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs
deleted file mode 100644
index 0c177ef..0000000
--- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs
+++ /dev/null
@@ -1,230 +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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.fbotest)
-
-#include "rs_graphics.rsh"
-
-rs_program_vertex gPVBackground;
-rs_program_fragment gPFBackground;
-
-rs_allocation gTGrid;
-
-rs_program_store gPFSBackground;
-
-rs_font gItalic;
-rs_allocation gTextAlloc;
-
-rs_allocation gOffscreen;
-rs_allocation gOffscreenDepth;
-rs_allocation gReadBackTest;
-
-typedef struct MeshInfo {
-    rs_mesh mMesh;
-    int mNumIndexSets;
-    float3 bBoxMin;
-    float3 bBoxMax;
-} MeshInfo_t;
-
-MeshInfo_t *gMeshes;
-
-static float3 gLookAt;
-
-static float gRotateX;
-static float gRotateY;
-static float gZoom;
-
-static float gLastX;
-static float gLastY;
-
-void onActionDown(float x, float y) {
-    gLastX = x;
-    gLastY = y;
-}
-
-void onActionScale(float scale) {
-
-    gZoom *= 1.0f / scale;
-    gZoom = max(0.1f, min(gZoom, 500.0f));
-}
-
-void onActionMove(float x, float y) {
-    float dx = gLastX - x;
-    float dy = gLastY - y;
-
-    if (fabs(dy) <= 2.0f) {
-        dy = 0.0f;
-    }
-    if (fabs(dx) <= 2.0f) {
-        dx = 0.0f;
-    }
-
-    gRotateY -= dx;
-    if (gRotateY > 360) {
-        gRotateY -= 360;
-    }
-    if (gRotateY < 0) {
-        gRotateY += 360;
-    }
-
-    gRotateX -= dy;
-    gRotateX = min(gRotateX, 80.0f);
-    gRotateX = max(gRotateX, -80.0f);
-
-    gLastX = x;
-    gLastY = y;
-}
-
-void init() {
-    gRotateX = 0.0f;
-    gRotateY = 0.0f;
-    gZoom = 50.0f;
-    gLookAt = 0.0f;
-}
-
-void updateMeshInfo() {
-    rs_allocation allMeshes = rsGetAllocation(gMeshes);
-    int size = rsAllocationGetDimX(allMeshes);
-    gLookAt = 0.0f;
-    float minX, minY, minZ, maxX, maxY, maxZ;
-    for (int i = 0; i < size; i++) {
-        MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i);
-        rsgMeshComputeBoundingBox(info->mMesh,
-                                  &minX, &minY, &minZ,
-                                  &maxX, &maxY, &maxZ);
-        info->bBoxMin = (float3){minX, minY, minZ};
-        info->bBoxMax = (float3){maxX, maxY, maxZ};
-        gLookAt += (info->bBoxMin + info->bBoxMax)*0.5f;
-    }
-    gLookAt = gLookAt / (float)size;
-}
-
-static void renderAllMeshes() {
-    rs_allocation allMeshes = rsGetAllocation(gMeshes);
-    int size = rsAllocationGetDimX(allMeshes);
-    gLookAt = 0.0f;
-    for (int i = 0; i < size; i++) {
-        MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i);
-        rsgDrawMesh(info->mMesh);
-    }
-}
-
-static void drawDescription() {
-    uint height = rsgGetHeight();
-    int left = 0, right = 0, top = 0, bottom = 0;
-
-    rsgBindFont(gItalic);
-
-    rsgMeasureText(gTextAlloc, &left, &right, &top, &bottom);
-    rsgDrawText(gTextAlloc, 2 -left, height - 2 + bottom);
-}
-
-static void renderOffscreen(bool useDepth) {
-
-    rsgBindColorTarget(gOffscreen, 0);
-    if (useDepth) {
-        rsgBindDepthTarget(gOffscreenDepth);
-        rsgClearDepth(1.0f);
-    } else {
-        rsgClearDepthTarget();
-    }
-    rsgClearColor(0.8f, 0.0f, 0.0f, 1.0f);
-
-    rsgBindProgramVertex(gPVBackground);
-    rs_matrix4x4 proj;
-    float aspect = (float)rsAllocationGetDimX(gOffscreen) / (float)rsAllocationGetDimY(gOffscreen);
-    rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 100.0f);
-    rsgProgramVertexLoadProjectionMatrix(&proj);
-
-    rsgBindProgramFragment(gPFBackground);
-    rsgBindProgramStore(gPFSBackground);
-    rsgBindTexture(gPFBackground, 0, gTGrid);
-
-    rs_matrix4x4 matrix;
-    rsMatrixLoadIdentity(&matrix);
-    // Position our models on the screen
-    rsMatrixTranslate(&matrix, gLookAt.x, gLookAt.y, gLookAt.z - gZoom);
-    rsMatrixRotate(&matrix, gRotateX, 1.0f, 0.0f, 0.0f);
-    rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f);
-    rsgProgramVertexLoadModelMatrix(&matrix);
-
-    renderAllMeshes();
-
-    // Render into the frambuffer
-    rsgClearAllRenderTargets();
-}
-
-static void drawOffscreenResult(int posX, int posY, rs_allocation texture) {
-    // display the result
-    rs_matrix4x4 proj, matrix;
-    rsMatrixLoadOrtho(&proj, 0, rsgGetWidth(), rsgGetHeight(), 0, -500, 500);
-    rsgProgramVertexLoadProjectionMatrix(&proj);
-    rsMatrixLoadIdentity(&matrix);
-    rsgProgramVertexLoadModelMatrix(&matrix);
-    rsgBindTexture(gPFBackground, 0, texture);
-    float startX = posX, startY = posY;
-    float width = 256, height = 256;
-    rsgDrawQuadTexCoords(startX, startY, 0, 0, 1,
-                         startX, startY + height, 0, 0, 0,
-                         startX + width, startY + height, 0, 1, 0,
-                         startX + width, startY, 0, 1, 1);
-}
-
-int root(void) {
-
-    rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f);
-    rsgClearDepth(1.0f);
-
-    renderOffscreen(true);
-    drawOffscreenResult(0, 0, gOffscreen);
-
-
-    uint32_t w = rsAllocationGetDimX(gOffscreen);
-    uint32_t h = rsAllocationGetDimY(gOffscreen);
-
-    rsgAllocationSyncAll(gOffscreen, RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET);
-
-    rsAllocationCopy2DRange(gReadBackTest, 0, 0, 0,
-                            RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, w, h,
-                            gOffscreen, 0, 0, 0, RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X);
-
-    rsgAllocationSyncAll(gReadBackTest);
-    drawOffscreenResult(0, 300, gReadBackTest);
-
-    rsgBindProgramVertex(gPVBackground);
-    rs_matrix4x4 proj;
-    float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
-    rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 100.0f);
-    rsgProgramVertexLoadProjectionMatrix(&proj);
-
-    rsgBindProgramFragment(gPFBackground);
-    rsgBindProgramStore(gPFSBackground);
-    rsgBindTexture(gPFBackground, 0, gTGrid);
-
-    rs_matrix4x4 matrix;
-    rsMatrixLoadIdentity(&matrix);
-    // Position our models on the screen
-    rsMatrixTranslate(&matrix, gLookAt.x, gLookAt.y, gLookAt.z - gZoom);
-    rsMatrixRotate(&matrix, gRotateX, 1.0f, 0.0f, 0.0f);
-    rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f);
-    rsgProgramVertexLoadModelMatrix(&matrix);
-
-    renderAllMeshes();
-
-    drawDescription();
-
-    return 0;
-}
diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs
deleted file mode 100644
index 13a3c85..0000000
--- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs
+++ /dev/null
@@ -1,219 +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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.fbotest)
-
-#include "rs_graphics.rsh"
-
-rs_program_vertex gPVBackground;
-rs_program_fragment gPFBackground;
-
-rs_allocation gTGrid;
-
-rs_program_store gPFSBackground;
-
-rs_font gItalic;
-rs_allocation gTextAlloc;
-
-rs_allocation gOffscreen;
-rs_allocation gOffscreenDepth;
-
-typedef struct MeshInfo {
-    rs_mesh mMesh;
-    int mNumIndexSets;
-    float3 bBoxMin;
-    float3 bBoxMax;
-} MeshInfo_t;
-
-MeshInfo_t *gMeshes;
-
-static float3 gLookAt;
-
-static float gRotateX;
-static float gRotateY;
-static float gZoom;
-
-static float gLastX;
-static float gLastY;
-
-void onActionDown(float x, float y) {
-    gLastX = x;
-    gLastY = y;
-}
-
-void onActionScale(float scale) {
-
-    gZoom *= 1.0f / scale;
-    gZoom = max(0.1f, min(gZoom, 500.0f));
-}
-
-void onActionMove(float x, float y) {
-    float dx = gLastX - x;
-    float dy = gLastY - y;
-
-    if (fabs(dy) <= 2.0f) {
-        dy = 0.0f;
-    }
-    if (fabs(dx) <= 2.0f) {
-        dx = 0.0f;
-    }
-
-    gRotateY -= dx;
-    if (gRotateY > 360) {
-        gRotateY -= 360;
-    }
-    if (gRotateY < 0) {
-        gRotateY += 360;
-    }
-
-    gRotateX -= dy;
-    gRotateX = min(gRotateX, 80.0f);
-    gRotateX = max(gRotateX, -80.0f);
-
-    gLastX = x;
-    gLastY = y;
-}
-
-void init() {
-    gRotateX = 0.0f;
-    gRotateY = 0.0f;
-    gZoom = 50.0f;
-    gLookAt = 0.0f;
-}
-
-void updateMeshInfo() {
-    rs_allocation allMeshes = rsGetAllocation(gMeshes);
-    int size = rsAllocationGetDimX(allMeshes);
-    gLookAt = 0.0f;
-    float minX, minY, minZ, maxX, maxY, maxZ;
-    for (int i = 0; i < size; i++) {
-        MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i);
-        rsgMeshComputeBoundingBox(info->mMesh,
-                                  &minX, &minY, &minZ,
-                                  &maxX, &maxY, &maxZ);
-        info->bBoxMin = (float3){minX, minY, minZ};
-        info->bBoxMax = (float3){maxX, maxY, maxZ};
-        gLookAt += (info->bBoxMin + info->bBoxMax)*0.5f;
-    }
-    gLookAt = gLookAt / (float)size;
-}
-
-static void renderAllMeshes() {
-    rs_allocation allMeshes = rsGetAllocation(gMeshes);
-    int size = rsAllocationGetDimX(allMeshes);
-    gLookAt = 0.0f;
-    for (int i = 0; i < size; i++) {
-        MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i);
-        rsgDrawMesh(info->mMesh);
-    }
-}
-
-static void drawDescription() {
-    uint height = rsgGetHeight();
-    int left = 0, right = 0, top = 0, bottom = 0;
-
-    rsgBindFont(gItalic);
-
-    rsgMeasureText(gTextAlloc, &left, &right, &top, &bottom);
-    rsgDrawText(gTextAlloc, 2 -left, height - 2 + bottom);
-}
-
-static void renderOffscreen(bool useDepth) {
-
-    rsgBindColorTarget(gOffscreen, 0);
-    if (useDepth) {
-        rsgBindDepthTarget(gOffscreenDepth);
-        rsgClearDepth(1.0f);
-    } else {
-        rsgClearDepthTarget();
-    }
-    rsgClearColor(0.8f, 0.8f, 0.8f, 1.0f);
-
-    rsgBindProgramVertex(gPVBackground);
-    rs_matrix4x4 proj;
-    float aspect = (float)rsAllocationGetDimX(gOffscreen) / (float)rsAllocationGetDimY(gOffscreen);
-    rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 100.0f);
-    rsgProgramVertexLoadProjectionMatrix(&proj);
-
-    rsgBindProgramFragment(gPFBackground);
-    rsgBindProgramStore(gPFSBackground);
-    rsgBindTexture(gPFBackground, 0, gTGrid);
-
-    rs_matrix4x4 matrix;
-    rsMatrixLoadIdentity(&matrix);
-    // Position our models on the screen
-    rsMatrixTranslate(&matrix, gLookAt.x, gLookAt.y, gLookAt.z - gZoom);
-    rsMatrixRotate(&matrix, gRotateX, 1.0f, 0.0f, 0.0f);
-    rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f);
-    rsgProgramVertexLoadModelMatrix(&matrix);
-
-    renderAllMeshes();
-
-    // Render into the frambuffer
-    rsgClearAllRenderTargets();
-}
-
-static void drawOffscreenResult(int posX, int posY) {
-    // display the result
-    rs_matrix4x4 proj, matrix;
-    rsMatrixLoadOrtho(&proj, 0, rsgGetWidth(), rsgGetHeight(), 0, -500, 500);
-    rsgProgramVertexLoadProjectionMatrix(&proj);
-    rsMatrixLoadIdentity(&matrix);
-    rsgProgramVertexLoadModelMatrix(&matrix);
-    rsgBindTexture(gPFBackground, 0, gOffscreen);
-    float startX = posX, startY = posY;
-    float width = 256, height = 256;
-    rsgDrawQuadTexCoords(startX, startY, 0, 0, 1,
-                         startX, startY + height, 0, 0, 0,
-                         startX + width, startY + height, 0, 1, 0,
-                         startX + width, startY, 0, 1, 1);
-}
-
-int root(void) {
-
-    rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f);
-    rsgClearDepth(1.0f);
-
-    renderOffscreen(true);
-    drawOffscreenResult(0, 0);
-
-    renderOffscreen(false);
-    drawOffscreenResult(0, 256);
-
-    rsgBindProgramVertex(gPVBackground);
-    rs_matrix4x4 proj;
-    float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
-    rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 100.0f);
-    rsgProgramVertexLoadProjectionMatrix(&proj);
-
-    rsgBindProgramFragment(gPFBackground);
-    rsgBindProgramStore(gPFSBackground);
-    rsgBindTexture(gPFBackground, 0, gTGrid);
-
-    rs_matrix4x4 matrix;
-    rsMatrixLoadIdentity(&matrix);
-    // Position our models on the screen
-    rsMatrixTranslate(&matrix, gLookAt.x, gLookAt.y, gLookAt.z - gZoom);
-    rsMatrixRotate(&matrix, gRotateX, 1.0f, 0.0f, 0.0f);
-    rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f);
-    rsgProgramVertexLoadModelMatrix(&matrix);
-
-    renderAllMeshes();
-
-    drawDescription();
-
-    return 0;
-}
diff --git a/tests/RenderScriptTests/HelloWorld/Android.mk b/tests/RenderScriptTests/HelloWorld/Android.mk
deleted file mode 100644
index c1c08ec..0000000
--- a/tests/RenderScriptTests/HelloWorld/Android.mk
+++ /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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-
-LOCAL_PACKAGE_NAME := RsHelloWorld
-
-LOCAL_SDK_VERSION := 17
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/HelloWorld/AndroidManifest.xml b/tests/RenderScriptTests/HelloWorld/AndroidManifest.xml
deleted file mode 100644
index 1d37dc9..0000000
--- a/tests/RenderScriptTests/HelloWorld/AndroidManifest.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
- 
-          http://www.apache.org/licenses/LICENSE-2.0
- 
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.example.android.rs.helloworld">
-    <uses-sdk android:minSdkVersion="11" />
-    <application android:label="RsHelloWorld"
-    android:icon="@drawable/test_pattern">
-        <activity android:name="HelloWorld"
-                  android:label="RsHelloWorld"
-                  android:theme="@android:style/Theme.Black.NoTitleBar">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/HelloWorld/_index.html b/tests/RenderScriptTests/HelloWorld/_index.html
deleted file mode 100644
index 4cab738..0000000
--- a/tests/RenderScriptTests/HelloWorld/_index.html
+++ /dev/null
@@ -1 +0,0 @@
-<p>A Renderscript graphics application that draws the text "Hello, World!" where the user touches.</p>
\ No newline at end of file
diff --git a/tests/RenderScriptTests/HelloWorld/res/drawable/test_pattern.png b/tests/RenderScriptTests/HelloWorld/res/drawable/test_pattern.png
deleted file mode 100644
index e7d1455..0000000
--- a/tests/RenderScriptTests/HelloWorld/res/drawable/test_pattern.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorld.java b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorld.java
deleted file mode 100644
index 9b1697b..0000000
--- a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorld.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.rs.helloworld;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-// Renderscript activity
-public class HelloWorld extends Activity {
-
-    // Custom view to use with RenderScript
-    private HelloWorldView mView;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        // Create our view and set it as the content of our Activity
-        mView = new HelloWorldView(this);
-        setContentView(mView);
-    }
-
-    @Override
-    protected void onResume() {
-        // Ideally an app should implement onResume() and onPause()
-        // to take appropriate action when the activity loses focus
-        super.onResume();
-        mView.resume();
-    }
-
-    @Override
-    protected void onPause() {
-        // Ideally an app should implement onResume() and onPause()
-        // to take appropriate action when the activity loses focus
-        super.onPause();
-        mView.pause();
-    }
-
-}
-
diff --git a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldRS.java b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldRS.java
deleted file mode 100644
index 4316411..0000000
--- a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldRS.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.rs.helloworld;
-
-import android.content.res.Resources;
-import android.renderscript.*;
-
-// This is the renderer for the HelloWorldView
-public class HelloWorldRS {
-    private Resources mRes;
-    private RenderScriptGL mRS;
-
-    private ScriptC_helloworld mScript;
-
-    public HelloWorldRS() {
-    }
-
-    // This provides us with the renderscript context and resources that
-    // allow us to create the script that does rendering
-    public void init(RenderScriptGL rs, Resources res) {
-        mRS = rs;
-        mRes = res;
-        initRS();
-    }
-
-    public void onActionDown(int x, int y) {
-        mScript.set_gTouchX(x);
-        mScript.set_gTouchY(y);
-    }
-
-    private void initRS() {
-        mScript = new ScriptC_helloworld(mRS, mRes, R.raw.helloworld);
-        mRS.bindRootScript(mScript);
-    }
-}
-
-
-
diff --git a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldView.java b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldView.java
deleted file mode 100644
index 557ebc5..0000000
--- a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldView.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.rs.helloworld;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScriptGL;
-
-import android.content.Context;
-import android.view.MotionEvent;
-
-public class HelloWorldView extends RSSurfaceView {
-    // Renderscipt context
-    private RenderScriptGL mRS;
-    // Script that does the rendering
-    private HelloWorldRS mRender;
-
-    public HelloWorldView(Context context) {
-        super(context);
-        ensureRenderScript();
-    }
-
-    private void ensureRenderScript() {
-        if (mRS == null) {
-            // Initialize renderscript with desired surface characteristics.
-            // In this case, just use the defaults
-            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
-            mRS = createRenderScriptGL(sc);
-            // Create an instance of the script that does the rendering
-            mRender = new HelloWorldRS();
-            mRender.init(mRS, getResources());
-        }
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        ensureRenderScript();
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        // Handle the system event and clean up
-        mRender = null;
-        if (mRS != null) {
-            mRS = null;
-            destroyRenderScriptGL();
-        }
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        // Pass touch events from the system to the rendering script
-        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            mRender.onActionDown((int)ev.getX(), (int)ev.getY());
-            return true;
-        }
-
-        return false;
-    }
-}
-
-
diff --git a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/helloworld.rs b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/helloworld.rs
deleted file mode 100644
index bcf624e..0000000
--- a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/helloworld.rs
+++ /dev/null
@@ -1,47 +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.
-
-#pragma version(1)
-
-// Tell which java package name the reflected files should belong to
-#pragma rs java_package_name(com.example.android.rs.helloworld)
-
-// Built-in header with graphics API's
-#include "rs_graphics.rsh"
-
-// gTouchX and gTouchY are variables that will be reflected for use
-// by the java API. We can use them to notify the script of touch events.
-int gTouchX;
-int gTouchY;
-
-// This is invoked automatically when the script is created
-void init() {
-    gTouchX = 50.0f;
-    gTouchY = 50.0f;
-}
-
-int root(void) {
-
-    // Clear the background color
-    rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-    // Tell the runtime what the font color should be
-    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
-    // Introuduce ourselves to the world by drawing a greeting
-    // at the position user touched on the screen
-    rsgDrawText("Hello World!", gTouchX, gTouchY);
-
-    // Return value tells RS roughly how often to redraw
-    // in this case 20 ms
-    return 20;
-}
diff --git a/tests/RenderScriptTests/MiscSamples/Android.mk b/tests/RenderScriptTests/MiscSamples/Android.mk
deleted file mode 100644
index ee3567b..0000000
--- a/tests/RenderScriptTests/MiscSamples/Android.mk
+++ /dev/null
@@ -1,28 +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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-
-LOCAL_PACKAGE_NAME := RsMiscSamples
-
-LOCAL_SDK_VERSION := 17
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/MiscSamples/AndroidManifest.xml b/tests/RenderScriptTests/MiscSamples/AndroidManifest.xml
deleted file mode 100644
index 08a3976..0000000
--- a/tests/RenderScriptTests/MiscSamples/AndroidManifest.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.example.android.rs.miscsamples">
-    <uses-sdk android:minSdkVersion="11" />
-    <application android:label="RsMiscSamples"
-    android:icon="@drawable/test_pattern">
-        <activity android:name="RsList"
-                  android:label="RsList"
-                  android:theme="@android:style/Theme.Black.NoTitleBar">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-        
-        <activity android:name="RsRenderStates"
-                  android:label="RsStates"
-                  android:theme="@android:style/Theme.Black.NoTitleBar">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/MiscSamples/_index.html b/tests/RenderScriptTests/MiscSamples/_index.html
deleted file mode 100644
index 5872431..0000000
--- a/tests/RenderScriptTests/MiscSamples/_index.html
+++ /dev/null
@@ -1 +0,0 @@
-<p>A set of samples that demonstrate how to use various features of the Renderscript APIs.</p>
\ No newline at end of file
diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/checker.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/checker.png
deleted file mode 100644
index b631e1e..0000000
--- a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/checker.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/cubemap_test.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/cubemap_test.png
deleted file mode 100644
index baf35d0..0000000
--- a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/cubemap_test.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/data.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/data.png
deleted file mode 100644
index 8e34714..0000000
--- a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/data.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/leaf.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/leaf.png
deleted file mode 100644
index 3cd3775..0000000
--- a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/leaf.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/test_pattern.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/test_pattern.png
deleted file mode 100644
index e7d1455..0000000
--- a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/test_pattern.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/torusmap.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/torusmap.png
deleted file mode 100644
index 1e08f3b..0000000
--- a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/torusmap.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/multitexf.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/multitexf.glsl
deleted file mode 100644
index e492a47..0000000
--- a/tests/RenderScriptTests/MiscSamples/res/raw/multitexf.glsl
+++ /dev/null
@@ -1,13 +0,0 @@
-varying vec2 varTex0;
-
-void main() {
-   vec2 t0 = varTex0.xy;
-   lowp vec4 col0 = texture2D(UNI_Tex0, t0).rgba;
-   lowp vec4 col1 = texture2D(UNI_Tex1, t0*4.0).rgba;
-   lowp vec4 col2 = texture2D(UNI_Tex2, t0).rgba;
-   col0.xyz = col0.xyz*col1.xyz*1.5;
-   col0.xyz = mix(col0.xyz, col2.xyz, col2.w);
-   col0.w = 0.5;
-   gl_FragColor = col0;
-}
-
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shader2f.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shader2f.glsl
deleted file mode 100644
index 5fc05f1..0000000
--- a/tests/RenderScriptTests/MiscSamples/res/raw/shader2f.glsl
+++ /dev/null
@@ -1,29 +0,0 @@
-varying vec3 varWorldPos;
-varying vec3 varWorldNormal;
-varying vec2 varTex0;
-
-void main() {
-
-   vec3 V = normalize(-varWorldPos.xyz);
-   vec3 worldNorm = normalize(varWorldNormal);
-
-   vec3 light0Vec = normalize(UNI_light0_Posision.xyz - varWorldPos);
-   vec3 light0R = -reflect(light0Vec, worldNorm);
-   float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0) * UNI_light0_Diffuse;
-   float light0Spec = clamp(dot(light0R, V), 0.001, 1.0);
-   float light0_Specular = pow(light0Spec, UNI_light0_CosinePower) * UNI_light0_Specular;
-
-   vec3 light1Vec = normalize(UNI_light1_Posision.xyz - varWorldPos);
-   vec3 light1R = reflect(light1Vec, worldNorm);
-   float light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0) * UNI_light1_Diffuse;
-   float light1Spec = clamp(dot(light1R, V), 0.001, 1.0);
-   float light1_Specular = pow(light1Spec, UNI_light1_CosinePower) * UNI_light1_Specular;
-
-   vec2 t0 = varTex0.xy;
-   lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
-   col.xyz = col.xyz * (light0_Diffuse * UNI_light0_DiffuseColor.xyz + light1_Diffuse * UNI_light1_DiffuseColor.xyz);
-   col.xyz += light0_Specular * UNI_light0_SpecularColor.xyz;
-   col.xyz += light1_Specular * UNI_light1_SpecularColor.xyz;
-   gl_FragColor = col;
-}
-
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shader2movev.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shader2movev.glsl
deleted file mode 100644
index a2c807e..0000000
--- a/tests/RenderScriptTests/MiscSamples/res/raw/shader2movev.glsl
+++ /dev/null
@@ -1,21 +0,0 @@
-varying vec3 varWorldPos;
-varying vec3 varWorldNormal;
-varying vec2 varTex0;
-
-// This is where actual shader code begins
-void main() {
-   vec4 objPos = ATTRIB_position;
-   vec3 oldPos = objPos.xyz;
-   objPos.xyz += 0.1*sin(objPos.xyz*2.0 + UNI_time);
-   objPos.xyz += 0.05*sin(objPos.xyz*4.0 + UNI_time*0.5);
-   objPos.xyz += 0.02*sin(objPos.xyz*7.0 + UNI_time*0.75);
-   vec4 worldPos = UNI_model * objPos;
-   gl_Position = UNI_proj * worldPos;
-
-   mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
-   vec3 worldNorm = model3 * (ATTRIB_normal + oldPos - objPos.xyz);
-
-   varWorldPos = worldPos.xyz;
-   varWorldNormal = worldNorm;
-   varTex0 = ATTRIB_texture0;
-}
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shader2v.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shader2v.glsl
deleted file mode 100644
index e6885a3..0000000
--- a/tests/RenderScriptTests/MiscSamples/res/raw/shader2v.glsl
+++ /dev/null
@@ -1,17 +0,0 @@
-varying vec3 varWorldPos;
-varying vec3 varWorldNormal;
-varying vec2 varTex0;
-
-// This is where actual shader code begins
-void main() {
-   vec4 objPos = ATTRIB_position;
-   vec4 worldPos = UNI_model * objPos;
-   gl_Position = UNI_proj * worldPos;
-
-   mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
-   vec3 worldNorm = model3 * ATTRIB_normal;
-
-   varWorldPos = worldPos.xyz;
-   varWorldNormal = worldNorm;
-   varTex0 = ATTRIB_texture0;
-}
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayf.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayf.glsl
deleted file mode 100644
index 238ecad..0000000
--- a/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayf.glsl
+++ /dev/null
@@ -1,16 +0,0 @@
-
-varying lowp float light0_Diffuse;
-varying lowp float light0_Specular;
-varying lowp float light1_Diffuse;
-varying lowp float light1_Specular;
-varying vec2 varTex0;
-
-void main() {
-   vec2 t0 = varTex0.xy;
-   lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
-   col.xyz = col.xyz * (light0_Diffuse * UNI_light_DiffuseColor[0].xyz + light1_Diffuse * UNI_light_DiffuseColor[1].xyz);
-   col.xyz += light0_Specular * UNI_light_SpecularColor[0].xyz;
-   col.xyz += light1_Specular * UNI_light_SpecularColor[1].xyz;
-   gl_FragColor = col;
-}
-
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayv.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayv.glsl
deleted file mode 100644
index 7a1310a..0000000
--- a/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayv.glsl
+++ /dev/null
@@ -1,32 +0,0 @@
-varying float light0_Diffuse;
-varying float light0_Specular;
-varying float light1_Diffuse;
-varying float light1_Specular;
-varying vec2 varTex0;
-
-// This is where actual shader code begins
-void main() {
-   vec4 worldPos = UNI_model[0] * ATTRIB_position;
-   worldPos = UNI_model[1] * worldPos;
-   gl_Position = UNI_proj * worldPos;
-
-   mat4 model0 = UNI_model[0];
-   mat3 model3 = mat3(model0[0].xyz, model0[1].xyz, model0[2].xyz);
-   vec3 worldNorm = model3 * ATTRIB_normal;
-   vec3 V = normalize(-worldPos.xyz);
-
-   vec3 light0Vec = normalize(UNI_light_Posision[0].xyz - worldPos.xyz);
-   vec3 light0R = -reflect(light0Vec, worldNorm);
-   light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0) * UNI_light_Diffuse[0];
-   float light0Spec = clamp(dot(light0R, V), 0.001, 1.0);
-   light0_Specular = pow(light0Spec, UNI_light_CosinePower[0]) * UNI_light_Specular[0];
-
-   vec3 light1Vec = normalize(UNI_light_Posision[1].xyz - worldPos.xyz);
-   vec3 light1R = reflect(light1Vec, worldNorm);
-   light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0) * UNI_light_Diffuse[1];
-   float light1Spec = clamp(dot(light1R, V), 0.001, 1.0);
-   light1_Specular = pow(light1Spec, UNI_light_CosinePower[1]) * UNI_light_Specular[1];
-
-   gl_PointSize = 1.0;
-   varTex0 = ATTRIB_texture0;
-}
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shadercubef.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shadercubef.glsl
deleted file mode 100644
index 15696a4..0000000
--- a/tests/RenderScriptTests/MiscSamples/res/raw/shadercubef.glsl
+++ /dev/null
@@ -1,8 +0,0 @@
-
-varying vec3 worldNormal;
-
-void main() {
-   lowp vec4 col = textureCube(UNI_Tex0, worldNormal);
-   gl_FragColor = col;
-}
-
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shadercubev.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shadercubev.glsl
deleted file mode 100644
index 70f5cd6..0000000
--- a/tests/RenderScriptTests/MiscSamples/res/raw/shadercubev.glsl
+++ /dev/null
@@ -1,10 +0,0 @@
-varying vec3 worldNormal;
-
-// This is where actual shader code begins
-void main() {
-   vec4 worldPos = UNI_model * ATTRIB_position;
-   gl_Position = UNI_proj * worldPos;
-
-   mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
-   worldNormal = model3 * ATTRIB_normal;
-}
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shaderf.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shaderf.glsl
deleted file mode 100644
index d56e203..0000000
--- a/tests/RenderScriptTests/MiscSamples/res/raw/shaderf.glsl
+++ /dev/null
@@ -1,16 +0,0 @@
-
-varying lowp float light0_Diffuse;
-varying lowp float light0_Specular;
-varying lowp float light1_Diffuse;
-varying lowp float light1_Specular;
-varying vec2 varTex0;
-
-void main() {
-   vec2 t0 = varTex0.xy;
-   lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
-   col.xyz = col.xyz * (light0_Diffuse * UNI_light0_DiffuseColor.xyz + light1_Diffuse * UNI_light1_DiffuseColor.xyz);
-   col.xyz += light0_Specular * UNI_light0_SpecularColor.xyz;
-   col.xyz += light1_Specular * UNI_light1_SpecularColor.xyz;
-   gl_FragColor = col;
-}
-
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shaderv.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shaderv.glsl
deleted file mode 100644
index f7d01de..0000000
--- a/tests/RenderScriptTests/MiscSamples/res/raw/shaderv.glsl
+++ /dev/null
@@ -1,30 +0,0 @@
-varying float light0_Diffuse;
-varying float light0_Specular;
-varying float light1_Diffuse;
-varying float light1_Specular;
-varying vec2 varTex0;
-
-// This is where actual shader code begins
-void main() {
-   vec4 worldPos = UNI_model * ATTRIB_position;
-   gl_Position = UNI_proj * worldPos;
-
-   mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
-   vec3 worldNorm = model3 * ATTRIB_normal;
-   vec3 V = normalize(-worldPos.xyz);
-
-   vec3 light0Vec = normalize(UNI_light0_Posision.xyz - worldPos.xyz);
-   vec3 light0R = -reflect(light0Vec, worldNorm);
-   light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0) * UNI_light0_Diffuse;
-   float light0Spec = clamp(dot(light0R, V), 0.001, 1.0);
-   light0_Specular = pow(light0Spec, UNI_light0_CosinePower) * UNI_light0_Specular;
-
-   vec3 light1Vec = normalize(UNI_light1_Posision.xyz - worldPos.xyz);
-   vec3 light1R = reflect(light1Vec, worldNorm);
-   light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0) * UNI_light1_Diffuse;
-   float light1Spec = clamp(dot(light1R, V), 0.001, 1.0);
-   light1_Specular = pow(light1Spec, UNI_light1_CosinePower) * UNI_light1_Specular;
-
-   gl_PointSize = 1.0;
-   varTex0 = ATTRIB_texture0;
-}
diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/torus.a3d b/tests/RenderScriptTests/MiscSamples/res/raw/torus.a3d
deleted file mode 100644
index 0322b01..0000000
--- a/tests/RenderScriptTests/MiscSamples/res/raw/torus.a3d
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsList.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsList.java
deleted file mode 100644
index dade3b3..0000000
--- a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsList.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.rs.miscsamples;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class RsList extends Activity {
-
-    private RsListView mView;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        // Create our Preview view and set it as the content of our
-        // Activity
-        mView = new RsListView(this);
-        setContentView(mView);
-    }
-
-    @Override
-    protected void onResume() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity loses focus
-        super.onResume();
-        mView.resume();
-    }
-
-    @Override
-    protected void onPause() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity loses focus
-        super.onPause();
-        mView.pause();
-    }
-
-}
-
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListRS.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListRS.java
deleted file mode 100644
index eeb2480..0000000
--- a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListRS.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.rs.miscsamples;
-
-import java.io.Writer;
-import java.util.Vector;
-
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.renderscript.ProgramStore.DepthFunc;
-import android.util.Log;
-
-
-public class RsListRS {
-
-    private final int STATE_LAST_FOCUS = 1;
-
-    private static final String[] DATA_LIST = {
-    "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
-    "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
-    "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
-    "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
-    "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
-    "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil",
-    "British Indian Ocean Territory", "British Virgin Islands", "Brunei", "Bulgaria",
-    "Burkina Faso", "Burundi", "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
-    "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
-    "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
-    "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic",
-    "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
-    "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
-    "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
-    "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
-    "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
-    "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
-    "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
-    "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
-    "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
-    "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
-    "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
-    "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
-    "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
-    "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
-    "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
-    "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
-    "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
-    "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
-    "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
-    "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
-    "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
-    "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
-    "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
-    "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
-    "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
-    "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
-    "Ukraine", "United Arab Emirates", "United Kingdom",
-    "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
-    "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
-    "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
-    };
-
-    public RsListRS() {
-    }
-
-    public void init(RenderScriptGL rs, Resources res) {
-        mRS = rs;
-        mRes = res;
-        initRS();
-    }
-
-    private Resources mRes;
-    private RenderScriptGL mRS;
-    private Font mItalic;
-
-    ScriptField_ListAllocs_s mListAllocs;
-
-    private ScriptC_rslist mScript;
-
-    int mLastX;
-    int mLastY;
-
-    public void onActionDown(int x, int y) {
-        mScript.set_gDY(0.0f);
-
-        mLastX = x;
-        mLastY = y;
-    }
-
-    public void onActionMove(int x, int y) {
-        int dx = mLastX - x;
-        int dy = mLastY - y;
-
-        if (Math.abs(dy) <= 2) {
-            dy = 0;
-        }
-
-        mScript.set_gDY(dy);
-
-        mLastX = x;
-        mLastY = y;
-    }
-
-    private void initRS() {
-
-        mScript = new ScriptC_rslist(mRS, mRes, R.raw.rslist);
-
-        mListAllocs = new ScriptField_ListAllocs_s(mRS, DATA_LIST.length);
-        for (int i = 0; i < DATA_LIST.length; i ++) {
-            ScriptField_ListAllocs_s.Item listElem = new ScriptField_ListAllocs_s.Item();
-            listElem.text = Allocation.createFromString(mRS, DATA_LIST[i], Allocation.USAGE_SCRIPT);
-            mListAllocs.set(listElem, i, false);
-        }
-
-        mListAllocs.copyAll();
-
-        mScript.bind_gList(mListAllocs);
-
-        mItalic = Font.create(mRS, mRes, "serif", Font.Style.BOLD_ITALIC, 8);
-        mScript.set_gItalic(mItalic);
-
-        mRS.bindRootScript(mScript);
-    }
-}
-
-
-
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListView.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListView.java
deleted file mode 100644
index db6e6c5..0000000
--- a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListView.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.rs.miscsamples;
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScriptGL;
-
-import android.content.Context;
-import android.view.MotionEvent;
-
-public class RsListView extends RSSurfaceView {
-
-    public RsListView(Context context) {
-        super(context);
-        ensureRenderScript();
-    }
-
-    private RenderScriptGL mRS;
-    private RsListRS mRender;
-
-    private void ensureRenderScript() {
-        if (mRS == null) {
-            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
-            mRS = createRenderScriptGL(sc);
-            mRender = new RsListRS();
-            mRender.init(mRS, getResources());
-        }
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        ensureRenderScript();
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        mRender = null;
-        if (mRS != null) {
-            mRS = null;
-            destroyRenderScriptGL();
-        }
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev)
-    {
-        boolean ret = false;
-        int act = ev.getAction();
-        if (act == MotionEvent.ACTION_DOWN) {
-            mRender.onActionDown((int)ev.getX(), (int)ev.getY());
-            ret = true;
-        } else if (act == MotionEvent.ACTION_MOVE) {
-            mRender.onActionMove((int)ev.getX(), (int)ev.getY());
-            ret = true;
-        }
-
-        return ret;
-    }
-}
-
-
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStates.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStates.java
deleted file mode 100644
index f4ea76e..0000000
--- a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStates.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.rs.miscsamples;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class RsRenderStates extends Activity {
-
-    private RsRenderStatesView mView;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        // Create our Preview view and set it as the content of our
-        // Activity
-        mView = new RsRenderStatesView(this);
-        setContentView(mView);
-    }
-
-    @Override
-    protected void onResume() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity looses focus
-        super.onResume();
-        mView.resume();
-    }
-
-    @Override
-    protected void onPause() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity looses focus
-        super.onPause();
-        mView.pause();
-    }
-
-}
-
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesRS.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesRS.java
deleted file mode 100644
index 0e319fe..0000000
--- a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesRS.java
+++ /dev/null
@@ -1,422 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.rs.miscsamples;
-
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.renderscript.*;
-import android.renderscript.Font.Style;
-import android.renderscript.Program.TextureType;
-import android.renderscript.ProgramStore.DepthFunc;
-import android.renderscript.ProgramStore.BlendSrcFunc;
-import android.renderscript.ProgramStore.BlendDstFunc;
-import android.renderscript.Sampler.Value;
-import android.util.Log;
-
-
-public class RsRenderStatesRS {
-
-    int mWidth;
-    int mHeight;
-
-    public RsRenderStatesRS() {
-    }
-
-    public void init(RenderScriptGL rs, Resources res) {
-        mRS = rs;
-        mWidth = mRS.getWidth();
-        mHeight = mRS.getHeight();
-        mRes = res;
-        mOptionsARGB.inScaled = false;
-        mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888;
-        mMode = 0;
-        mMaxModes = 0;
-        initRS();
-    }
-
-    public void surfaceChanged() {
-        mWidth = mRS.getWidth();
-        mHeight = mRS.getHeight();
-
-        Matrix4f proj = new Matrix4f();
-        proj.loadOrthoWindow(mWidth, mHeight);
-        mPVA.setProjection(proj);
-    }
-
-    private Resources mRes;
-    private RenderScriptGL mRS;
-
-    private Sampler mLinearClamp;
-    private Sampler mLinearWrap;
-    private Sampler mMipLinearWrap;
-    private Sampler mNearestClamp;
-    private Sampler mMipLinearAniso8;
-    private Sampler mMipLinearAniso15;
-
-    private ProgramStore mProgStoreBlendNoneDepth;
-    private ProgramStore mProgStoreBlendNone;
-    private ProgramStore mProgStoreBlendAlpha;
-    private ProgramStore mProgStoreBlendAdd;
-
-    private ProgramFragment mProgFragmentTexture;
-    private ProgramFragment mProgFragmentColor;
-
-    private ProgramVertex mProgVertex;
-    private ProgramVertexFixedFunction.Constants mPVA;
-
-    // Custom shaders
-    private ProgramVertex mProgVertexCustom;
-    private ProgramFragment mProgFragmentCustom;
-    private ProgramFragment mProgFragmentMultitex;
-    private ScriptField_VertexShaderConstants_s mVSConst;
-    private ScriptField_VertexShaderConstants2_s mVSConst2;
-    private ScriptField_FragentShaderConstants_s mFSConst;
-    private ScriptField_FragentShaderConstants2_s mFSConst2;
-
-    private ProgramVertex mProgVertexCustom2;
-    private ProgramFragment mProgFragmentCustom2;
-
-    private ProgramVertex mProgVertexCube;
-    private ProgramFragment mProgFragmentCube;
-
-    private ProgramRaster mCullBack;
-    private ProgramRaster mCullFront;
-    private ProgramRaster mCullNone;
-
-    private Allocation mTexTorus;
-    private Allocation mTexOpaque;
-    private Allocation mTexTransparent;
-    private Allocation mTexChecker;
-    private Allocation mTexCube;
-
-    private Mesh mMbyNMesh;
-    private Mesh mTorus;
-
-    Font mFontSans;
-    Font mFontSerif;
-    Font mFontSerifBold;
-    Font mFontSerifItalic;
-    Font mFontSerifBoldItalic;
-    Font mFontMono;
-    private Allocation mTextAlloc;
-
-    private ScriptC_rsrenderstates mScript;
-
-    private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
-
-    int mMode;
-    int mMaxModes;
-
-    public void onActionDown(int x, int y) {
-        mMode ++;
-        mMode = mMode % mMaxModes;
-        mScript.set_gDisplayMode(mMode);
-    }
-
-    ProgramStore BLEND_ADD_DEPTH_NONE(RenderScript rs) {
-        ProgramStore.Builder builder = new ProgramStore.Builder(rs);
-        builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
-        builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE);
-        builder.setDitherEnabled(false);
-        builder.setDepthMaskEnabled(false);
-        return builder.create();
-    }
-
-    private Mesh getMbyNMesh(float width, float height, int wResolution, int hResolution) {
-
-        Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS,
-                                           2, Mesh.TriangleMeshBuilder.TEXTURE_0);
-
-        for (int y = 0; y <= hResolution; y++) {
-            final float normalizedY = (float)y / hResolution;
-            final float yOffset = (normalizedY - 0.5f) * height;
-            for (int x = 0; x <= wResolution; x++) {
-                float normalizedX = (float)x / wResolution;
-                float xOffset = (normalizedX - 0.5f) * width;
-                tmb.setTexture(normalizedX, normalizedY);
-                tmb.addVertex(xOffset, yOffset);
-             }
-        }
-
-        for (int y = 0; y < hResolution; y++) {
-            final int curY = y * (wResolution + 1);
-            final int belowY = (y + 1) * (wResolution + 1);
-            for (int x = 0; x < wResolution; x++) {
-                int curV = curY + x;
-                int belowV = belowY + x;
-                tmb.addTriangle(curV, belowV, curV + 1);
-                tmb.addTriangle(belowV, belowV + 1, curV + 1);
-            }
-        }
-
-        return tmb.create(true);
-    }
-
-    private void initProgramStore() {
-        // Use stock the stock program store object
-        mProgStoreBlendNoneDepth = ProgramStore.BLEND_NONE_DEPTH_TEST(mRS);
-        mProgStoreBlendNone = ProgramStore.BLEND_NONE_DEPTH_NONE(mRS);
-
-        // Create a custom program store
-        ProgramStore.Builder builder = new ProgramStore.Builder(mRS);
-        builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
-        builder.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA,
-                             ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA);
-        builder.setDitherEnabled(false);
-        builder.setDepthMaskEnabled(false);
-        mProgStoreBlendAlpha = builder.create();
-
-        mProgStoreBlendAdd = BLEND_ADD_DEPTH_NONE(mRS);
-
-        mScript.set_gProgStoreBlendNoneDepth(mProgStoreBlendNoneDepth);
-        mScript.set_gProgStoreBlendNone(mProgStoreBlendNone);
-        mScript.set_gProgStoreBlendAlpha(mProgStoreBlendAlpha);
-        mScript.set_gProgStoreBlendAdd(mProgStoreBlendAdd);
-    }
-
-    private void initProgramFragment() {
-
-        ProgramFragmentFixedFunction.Builder texBuilder = new ProgramFragmentFixedFunction.Builder(mRS);
-        texBuilder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
-                              ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
-        mProgFragmentTexture = texBuilder.create();
-        mProgFragmentTexture.bindSampler(mLinearClamp, 0);
-
-        ProgramFragmentFixedFunction.Builder colBuilder = new ProgramFragmentFixedFunction.Builder(mRS);
-        colBuilder.setVaryingColor(false);
-        mProgFragmentColor = colBuilder.create();
-
-        mScript.set_gProgFragmentColor(mProgFragmentColor);
-        mScript.set_gProgFragmentTexture(mProgFragmentTexture);
-    }
-
-    private void initProgramVertex() {
-        ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
-        mProgVertex = pvb.create();
-
-        mPVA = new ProgramVertexFixedFunction.Constants(mRS);
-        ((ProgramVertexFixedFunction)mProgVertex).bindConstants(mPVA);
-        Matrix4f proj = new Matrix4f();
-        proj.loadOrthoWindow(mWidth, mHeight);
-        mPVA.setProjection(proj);
-
-        mScript.set_gProgVertex(mProgVertex);
-    }
-
-    private void initCustomShaders() {
-        mVSConst = new ScriptField_VertexShaderConstants_s(mRS, 1);
-        mVSConst2 = new ScriptField_VertexShaderConstants2_s(mRS, 1);
-        mFSConst = new ScriptField_FragentShaderConstants_s(mRS, 1);
-        mFSConst2 = new ScriptField_FragentShaderConstants2_s(mRS, 1);
-
-        mScript.bind_gVSConstants(mVSConst);
-        mScript.bind_gVSConstants2(mVSConst2);
-        mScript.bind_gFSConstants(mFSConst);
-        mScript.bind_gFSConstants2(mFSConst2);
-
-        // Initialize the shader builder
-        ProgramVertex.Builder pvbCustom = new ProgramVertex.Builder(mRS);
-        // Specify the resource that contains the shader string
-        pvbCustom.setShader(mRes, R.raw.shaderv);
-        // Use a script field to spcify the input layout
-        pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS));
-        // Define the constant input layout
-        pvbCustom.addConstant(mVSConst.getAllocation().getType());
-        mProgVertexCustom = pvbCustom.create();
-        // Bind the source of constant data
-        mProgVertexCustom.bindConstants(mVSConst.getAllocation(), 0);
-
-        ProgramFragment.Builder pfbCustom = new ProgramFragment.Builder(mRS);
-        // Specify the resource that contains the shader string
-        pfbCustom.setShader(mRes, R.raw.shaderf);
-        //Tell the builder how many textures we have
-        pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
-        // Define the constant input layout
-        pfbCustom.addConstant(mFSConst.getAllocation().getType());
-        mProgFragmentCustom = pfbCustom.create();
-        // Bind the source of constant data
-        mProgFragmentCustom.bindConstants(mFSConst.getAllocation(), 0);
-
-        pvbCustom = new ProgramVertex.Builder(mRS);
-        pvbCustom.setShader(mRes, R.raw.shaderarrayv);
-        pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS));
-        pvbCustom.addConstant(mVSConst2.getAllocation().getType());
-        mProgVertexCustom2 = pvbCustom.create();
-        mProgVertexCustom2.bindConstants(mVSConst2.getAllocation(), 0);
-
-        pfbCustom = new ProgramFragment.Builder(mRS);
-        pfbCustom.setShader(mRes, R.raw.shaderarrayf);
-        pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
-        pfbCustom.addConstant(mFSConst2.getAllocation().getType());
-        mProgFragmentCustom2 = pfbCustom.create();
-        mProgFragmentCustom2.bindConstants(mFSConst2.getAllocation(), 0);
-
-        // Cubemap test shaders
-        pvbCustom = new ProgramVertex.Builder(mRS);
-        pvbCustom.setShader(mRes, R.raw.shadercubev);
-        pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS));
-        pvbCustom.addConstant(mVSConst.getAllocation().getType());
-        mProgVertexCube = pvbCustom.create();
-        mProgVertexCube.bindConstants(mVSConst.getAllocation(), 0);
-
-        pfbCustom = new ProgramFragment.Builder(mRS);
-        pfbCustom.setShader(mRes, R.raw.shadercubef);
-        pfbCustom.addTexture(Program.TextureType.TEXTURE_CUBE);
-        mProgFragmentCube = pfbCustom.create();
-
-        pfbCustom = new ProgramFragment.Builder(mRS);
-        pfbCustom.setShader(mRes, R.raw.multitexf);
-        for (int texCount = 0; texCount < 3; texCount ++) {
-            pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
-        }
-        mProgFragmentMultitex = pfbCustom.create();
-
-        mScript.set_gProgVertexCustom(mProgVertexCustom);
-        mScript.set_gProgFragmentCustom(mProgFragmentCustom);
-        mScript.set_gProgVertexCustom2(mProgVertexCustom2);
-        mScript.set_gProgFragmentCustom2(mProgFragmentCustom2);
-        mScript.set_gProgVertexCube(mProgVertexCube);
-        mScript.set_gProgFragmentCube(mProgFragmentCube);
-        mScript.set_gProgFragmentMultitex(mProgFragmentMultitex);
-    }
-
-    private Allocation loadTextureRGB(int id) {
-        return Allocation.createFromBitmapResource(mRS, mRes, id,
-                                                   Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
-                                                   Allocation.USAGE_GRAPHICS_TEXTURE);
-    }
-
-    private Allocation loadTextureARGB(int id) {
-        Bitmap b = BitmapFactory.decodeResource(mRes, id, mOptionsARGB);
-        return Allocation.createFromBitmap(mRS, b,
-                                           Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
-                                           Allocation.USAGE_GRAPHICS_TEXTURE);
-    }
-
-    private void loadImages() {
-        mTexTorus = loadTextureRGB(R.drawable.torusmap);
-        mTexOpaque = loadTextureRGB(R.drawable.data);
-        mTexTransparent = loadTextureARGB(R.drawable.leaf);
-        mTexChecker = loadTextureRGB(R.drawable.checker);
-        Bitmap b = BitmapFactory.decodeResource(mRes, R.drawable.cubemap_test);
-        mTexCube = Allocation.createCubemapFromBitmap(mRS, b);
-
-        mScript.set_gTexTorus(mTexTorus);
-        mScript.set_gTexOpaque(mTexOpaque);
-        mScript.set_gTexTransparent(mTexTransparent);
-        mScript.set_gTexChecker(mTexChecker);
-        mScript.set_gTexCube(mTexCube);
-    }
-
-    private void initFonts() {
-        // Sans font by family name
-        mFontSans = Font.create(mRS, mRes, "sans-serif", Font.Style.NORMAL, 8);
-        mFontSerif = Font.create(mRS, mRes, "serif", Font.Style.NORMAL, 8);
-        // Create fonts by family and style
-        mFontSerifBold = Font.create(mRS, mRes, "serif", Font.Style.BOLD, 8);
-        mFontSerifItalic = Font.create(mRS, mRes, "serif", Font.Style.ITALIC, 8);
-        mFontSerifBoldItalic = Font.create(mRS, mRes, "serif", Font.Style.BOLD_ITALIC, 8);
-        mFontMono = Font.create(mRS, mRes, "mono", Font.Style.NORMAL, 8);
-
-        mTextAlloc = Allocation.createFromString(mRS, "String from allocation", Allocation.USAGE_SCRIPT);
-
-        mScript.set_gFontSans(mFontSans);
-        mScript.set_gFontSerif(mFontSerif);
-        mScript.set_gFontSerifBold(mFontSerifBold);
-        mScript.set_gFontSerifItalic(mFontSerifItalic);
-        mScript.set_gFontSerifBoldItalic(mFontSerifBoldItalic);
-        mScript.set_gFontMono(mFontMono);
-        mScript.set_gTextAlloc(mTextAlloc);
-    }
-
-    private void initMesh() {
-        mMbyNMesh = getMbyNMesh(256, 256, 10, 10);
-        mScript.set_gMbyNMesh(mMbyNMesh);
-
-        FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.torus);
-        FileA3D.IndexEntry entry = model.getIndexEntry(0);
-        if (entry == null || entry.getEntryType() != FileA3D.EntryType.MESH) {
-            Log.e("rs", "could not load model");
-        } else {
-            mTorus = (Mesh)entry.getObject();
-            mScript.set_gTorusMesh(mTorus);
-        }
-    }
-
-    private void initSamplers() {
-        Sampler.Builder bs = new Sampler.Builder(mRS);
-        bs.setMinification(Sampler.Value.LINEAR);
-        bs.setMagnification(Sampler.Value.LINEAR);
-        bs.setWrapS(Sampler.Value.WRAP);
-        bs.setWrapT(Sampler.Value.WRAP);
-        mLinearWrap = bs.create();
-
-        mLinearClamp = Sampler.CLAMP_LINEAR(mRS);
-        mNearestClamp = Sampler.CLAMP_NEAREST(mRS);
-        mMipLinearWrap = Sampler.WRAP_LINEAR_MIP_LINEAR(mRS);
-
-        bs = new Sampler.Builder(mRS);
-        bs.setMinification(Sampler.Value.LINEAR_MIP_LINEAR);
-        bs.setMagnification(Sampler.Value.LINEAR);
-        bs.setWrapS(Sampler.Value.WRAP);
-        bs.setWrapT(Sampler.Value.WRAP);
-        bs.setAnisotropy(8.0f);
-        mMipLinearAniso8 = bs.create();
-        bs.setAnisotropy(15.0f);
-        mMipLinearAniso15 = bs.create();
-
-        mScript.set_gLinearClamp(mLinearClamp);
-        mScript.set_gLinearWrap(mLinearWrap);
-        mScript.set_gMipLinearWrap(mMipLinearWrap);
-        mScript.set_gMipLinearAniso8(mMipLinearAniso8);
-        mScript.set_gMipLinearAniso15(mMipLinearAniso15);
-        mScript.set_gNearestClamp(mNearestClamp);
-    }
-
-    private void initProgramRaster() {
-        mCullBack = ProgramRaster.CULL_BACK(mRS);
-        mCullFront = ProgramRaster.CULL_FRONT(mRS);
-        mCullNone = ProgramRaster.CULL_NONE(mRS);
-
-        mScript.set_gCullBack(mCullBack);
-        mScript.set_gCullFront(mCullFront);
-        mScript.set_gCullNone(mCullNone);
-    }
-
-    private void initRS() {
-
-        mScript = new ScriptC_rsrenderstates(mRS, mRes, R.raw.rsrenderstates);
-
-        mMaxModes = mScript.get_gMaxModes();
-
-        initSamplers();
-        initProgramStore();
-        initProgramFragment();
-        initProgramVertex();
-        initFonts();
-        loadImages();
-        initMesh();
-        initProgramRaster();
-        initCustomShaders();
-
-        mRS.bindRootScript(mScript);
-    }
-}
-
-
-
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesView.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesView.java
deleted file mode 100644
index a15e38f..0000000
--- a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesView.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.rs.miscsamples;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScriptGL;
-
-import android.content.Context;
-import android.view.MotionEvent;
-import android.view.SurfaceHolder;
-
-public class RsRenderStatesView extends RSSurfaceView {
-
-    public RsRenderStatesView(Context context) {
-        super(context);
-        ensureRenderScript();
-    }
-
-    private RenderScriptGL mRS;
-    private RsRenderStatesRS mRender;
-
-    private void ensureRenderScript() {
-        if (mRS == null) {
-            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
-            sc.setDepth(16, 24);
-            mRS = createRenderScriptGL(sc);
-            mRender = new RsRenderStatesRS();
-            mRender.init(mRS, getResources());
-        }
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        ensureRenderScript();
-    }
-
-    @Override
-    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
-        super.surfaceChanged(holder, format, w, h);
-        mRender.surfaceChanged();
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        mRender = null;
-        if (mRS != null) {
-            mRS = null;
-            destroyRenderScriptGL();
-        }
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            mRender.onActionDown((int)ev.getX(), (int)ev.getY());
-            return true;
-        }
-
-        return false;
-    }
-}
-
-
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rslist.rs b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rslist.rs
deleted file mode 100644
index d9d450d..0000000
--- a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rslist.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (C) 2009 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.example.android.rs.miscsamples)
-
-#include "rs_graphics.rsh"
-
-float gDY;
-
-rs_font gItalic;
-
-typedef struct ListAllocs_s {
-    rs_allocation text;
-} ListAllocs;
-
-ListAllocs *gList;
-
-void init() {
-    gDY = 0.0f;
-}
-
-int textPos = 0;
-
-int root(void) {
-
-    rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-
-    textPos -= (int)gDY*2;
-    gDY *= 0.95;
-
-    rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f);
-    rsgBindFont(gItalic);
-
-    rs_allocation listAlloc;
-    listAlloc = rsGetAllocation(gList);
-    int allocSize = rsAllocationGetDimX(listAlloc);
-
-    int width = rsgGetWidth();
-    int height = rsgGetHeight();
-
-    int itemHeight = 80;
-    int currentYPos = itemHeight + textPos;
-
-    for (int i = 0; i < allocSize; i ++) {
-        if (currentYPos - itemHeight > height) {
-            break;
-        }
-
-        if (currentYPos > 0) {
-            rsgDrawRect(0, currentYPos - 1, width, currentYPos, 0);
-            rsgDrawText(gList[i].text, 30, currentYPos - 32);
-        }
-        currentYPos += itemHeight;
-    }
-
-    return 10;
-}
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rsrenderstates.rs b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rsrenderstates.rs
deleted file mode 100644
index 5dabd00..0000000
--- a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rsrenderstates.rs
+++ /dev/null
@@ -1,680 +0,0 @@
-// Copyright (C) 2009 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.example.android.rs.miscsamples)
-
-#include "rs_graphics.rsh"
-#include "shader_def.rsh"
-
-const int gMaxModes = 11;
-
-rs_program_vertex gProgVertex;
-rs_program_fragment gProgFragmentColor;
-rs_program_fragment gProgFragmentTexture;
-
-rs_program_store gProgStoreBlendNoneDepth;
-rs_program_store gProgStoreBlendNone;
-rs_program_store gProgStoreBlendAlpha;
-rs_program_store gProgStoreBlendAdd;
-
-rs_allocation gTexOpaque;
-rs_allocation gTexTorus;
-rs_allocation gTexTransparent;
-rs_allocation gTexChecker;
-rs_allocation gTexCube;
-
-rs_mesh gMbyNMesh;
-rs_mesh gTorusMesh;
-
-rs_font gFontSans;
-rs_font gFontSerif;
-rs_font gFontSerifBold;
-rs_font gFontSerifItalic;
-rs_font gFontSerifBoldItalic;
-rs_font gFontMono;
-rs_allocation gTextAlloc;
-
-int gDisplayMode;
-
-rs_sampler gLinearClamp;
-rs_sampler gLinearWrap;
-rs_sampler gMipLinearWrap;
-rs_sampler gMipLinearAniso8;
-rs_sampler gMipLinearAniso15;
-rs_sampler gNearestClamp;
-
-rs_program_raster gCullBack;
-rs_program_raster gCullFront;
-rs_program_raster gCullNone;
-
-// Custom vertex shader compunents
-VertexShaderConstants *gVSConstants;
-VertexShaderConstants2 *gVSConstants2;
-FragentShaderConstants *gFSConstants;
-FragentShaderConstants2 *gFSConstants2;
-// Export these out to easily set the inputs to shader
-VertexShaderInputs *gVSInputs;
-// Custom shaders we use for lighting
-rs_program_vertex gProgVertexCustom;
-rs_program_fragment gProgFragmentCustom;
-rs_program_vertex gProgVertexCustom2;
-rs_program_fragment gProgFragmentCustom2;
-rs_program_vertex gProgVertexCube;
-rs_program_fragment gProgFragmentCube;
-rs_program_fragment gProgFragmentMultitex;
-
-float gDt = 0;
-
-void init() {
-}
-
-static void displayFontSamples() {
-    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
-    int yPos = 100;
-    rsgBindFont(gFontSans);
-    rsgDrawText("Sans font sample", 30, yPos);
-    yPos += 30;
-    rsgFontColor(0.5f, 0.9f, 0.5f, 1.0f);
-    rsgBindFont(gFontSerif);
-    rsgDrawText("Serif font sample", 30, yPos);
-    yPos += 30;
-    rsgFontColor(0.7f, 0.7f, 0.7f, 1.0f);
-    rsgBindFont(gFontSerifBold);
-    rsgDrawText("Serif Bold font sample", 30, yPos);
-    yPos += 30;
-    rsgFontColor(0.5f, 0.5f, 0.9f, 1.0f);
-    rsgBindFont(gFontSerifItalic);
-    rsgDrawText("Serif Italic font sample", 30, yPos);
-    yPos += 30;
-    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
-    rsgBindFont(gFontSerifBoldItalic);
-    rsgDrawText("Serif Bold Italic font sample", 30, yPos);
-    yPos += 30;
-    rsgBindFont(gFontMono);
-    rsgDrawText("Monospace font sample", 30, yPos);
-    yPos += 50;
-
-    // Now use text metrics to center the text
-    uint width = rsgGetWidth();
-    uint height = rsgGetHeight();
-    int left = 0, right = 0, top = 0, bottom = 0;
-
-    rsgFontColor(0.9f, 0.9f, 0.95f, 1.0f);
-    rsgBindFont(gFontSerifBoldItalic);
-
-    rsgMeasureText(gTextAlloc, &left, &right, &top, &bottom);
-    int centeredPos = width / 2 - (right - left) / 2;
-    rsgDrawText(gTextAlloc, centeredPos, yPos);
-    yPos += 30;
-
-    const char* text = "Centered Text Sample";
-    rsgMeasureText(text, &left, &right, &top, &bottom);
-    centeredPos = width / 2 - (right - left) / 2;
-    rsgDrawText(text, centeredPos, yPos);
-    yPos += 30;
-
-    rsgBindFont(gFontSans);
-    text = "More Centered Text Samples";
-    rsgMeasureText(text, &left, &right, &top, &bottom);
-    centeredPos = width / 2 - (right - left) / 2;
-    rsgDrawText(text, centeredPos, yPos);
-    yPos += 30;
-
-    // Now draw bottom and top right aligned text
-    text = "Top-right aligned text";
-    rsgMeasureText(text, &left, &right, &top, &bottom);
-    rsgDrawText(text, width - right, top);
-
-    text = "Top-left";
-    rsgMeasureText(text, &left, &right, &top, &bottom);
-    rsgDrawText(text, -left, top);
-
-    text = "Bottom-right aligned text";
-    rsgMeasureText(text, &left, &right, &top, &bottom);
-    rsgDrawText(text, width - right, height + bottom);
-
-}
-
-static void bindProgramVertexOrtho() {
-    // Default vertex sahder
-    rsgBindProgramVertex(gProgVertex);
-    // Setup the projectioni matrix
-    rs_matrix4x4 proj;
-    rsMatrixLoadOrtho(&proj, 0, rsgGetWidth(), rsgGetHeight(), 0, -500, 500);
-    rsgProgramVertexLoadProjectionMatrix(&proj);
-}
-
-static void displayShaderSamples() {
-    bindProgramVertexOrtho();
-    rs_matrix4x4 matrix;
-    rsMatrixLoadIdentity(&matrix);
-    rsgProgramVertexLoadModelMatrix(&matrix);
-
-    // Fragment shader with texture
-    rsgBindProgramStore(gProgStoreBlendNone);
-    rsgBindProgramFragment(gProgFragmentTexture);
-    rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
-    rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
-
-    float startX = 0, startY = 0;
-    float width = 256, height = 256;
-    rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
-                         startX, startY + height, 0, 0, 1,
-                         startX + width, startY + height, 0, 1, 1,
-                         startX + width, startY, 0, 1, 0);
-
-    startX = 200; startY = 0;
-    width = 128; height = 128;
-    rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
-                         startX, startY + height, 0, 0, 1,
-                         startX + width, startY + height, 0, 1, 1,
-                         startX + width, startY, 0, 1, 0);
-
-    rsgBindProgramStore(gProgStoreBlendAlpha);
-    rsgBindTexture(gProgFragmentTexture, 0, gTexTransparent);
-    startX = 0; startY = 200;
-    width = 128; height = 128;
-    rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
-                         startX, startY + height, 0, 0, 1,
-                         startX + width, startY + height, 0, 1, 1,
-                         startX + width, startY, 0, 1, 0);
-
-    // Fragment program with simple color
-    rsgBindProgramFragment(gProgFragmentColor);
-    rsgProgramFragmentConstantColor(gProgFragmentColor, 0.9, 0.3, 0.3, 1);
-    rsgDrawRect(200, 300, 350, 450, 0);
-    rsgProgramFragmentConstantColor(gProgFragmentColor, 0.3, 0.9, 0.3, 1);
-    rsgDrawRect(50, 400, 400, 600, 0);
-
-    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
-    rsgBindFont(gFontMono);
-    rsgDrawText("Texture shader", 10, 50);
-    rsgDrawText("Alpha-blended texture shader", 10, 280);
-    rsgDrawText("Flat color shader", 100, 450);
-}
-
-static void displayBlendingSamples() {
-    int i;
-
-    bindProgramVertexOrtho();
-    rs_matrix4x4 matrix;
-    rsMatrixLoadIdentity(&matrix);
-    rsgProgramVertexLoadModelMatrix(&matrix);
-
-    rsgBindProgramFragment(gProgFragmentColor);
-
-    rsgBindProgramStore(gProgStoreBlendNone);
-    for (i = 0; i < 3; i ++) {
-        float iPlusOne = (float)(i + 1);
-        rsgProgramFragmentConstantColor(gProgFragmentColor,
-                                        0.1f*iPlusOne, 0.2f*iPlusOne, 0.3f*iPlusOne, 1);
-        float yPos = 150 * (float)i;
-        rsgDrawRect(0, yPos, 200, yPos + 200, 0);
-    }
-
-    rsgBindProgramStore(gProgStoreBlendAlpha);
-    for (i = 0; i < 3; i ++) {
-        float iPlusOne = (float)(i + 1);
-        rsgProgramFragmentConstantColor(gProgFragmentColor,
-                                        0.2f*iPlusOne, 0.3f*iPlusOne, 0.1f*iPlusOne, 0.5);
-        float yPos = 150 * (float)i;
-        rsgDrawRect(150, yPos, 350, yPos + 200, 0);
-    }
-
-    rsgBindProgramStore(gProgStoreBlendAdd);
-    for (i = 0; i < 3; i ++) {
-        float iPlusOne = (float)(i + 1);
-        rsgProgramFragmentConstantColor(gProgFragmentColor,
-                                        0.3f*iPlusOne, 0.1f*iPlusOne, 0.2f*iPlusOne, 0.5);
-        float yPos = 150 * (float)i;
-        rsgDrawRect(300, yPos, 500, yPos + 200, 0);
-    }
-
-
-    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
-    rsgBindFont(gFontMono);
-    rsgDrawText("No Blending", 10, 50);
-    rsgDrawText("Alpha Blending", 160, 150);
-    rsgDrawText("Additive Blending", 320, 250);
-
-}
-
-static void displayMeshSamples() {
-
-    bindProgramVertexOrtho();
-    rs_matrix4x4 matrix;
-    rsMatrixLoadTranslate(&matrix, 128, 128, 0);
-    rsgProgramVertexLoadModelMatrix(&matrix);
-
-    // Fragment shader with texture
-    rsgBindProgramStore(gProgStoreBlendNone);
-    rsgBindProgramFragment(gProgFragmentTexture);
-    rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
-    rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
-
-    rsgDrawMesh(gMbyNMesh);
-
-    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
-    rsgBindFont(gFontMono);
-    rsgDrawText("User gen 10 by 10 grid mesh", 10, 250);
-}
-
-static void displayTextureSamplers() {
-
-    bindProgramVertexOrtho();
-    rs_matrix4x4 matrix;
-    rsMatrixLoadIdentity(&matrix);
-    rsgProgramVertexLoadModelMatrix(&matrix);
-
-    // Fragment shader with texture
-    rsgBindProgramStore(gProgStoreBlendNone);
-    rsgBindProgramFragment(gProgFragmentTexture);
-    rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
-
-    // Linear clamp
-    rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
-    float startX = 0, startY = 0;
-    float width = 300, height = 300;
-    rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
-                         startX, startY + height, 0, 0, 1.1,
-                         startX + width, startY + height, 0, 1.1, 1.1,
-                         startX + width, startY, 0, 1.1, 0);
-
-    // Linear Wrap
-    rsgBindSampler(gProgFragmentTexture, 0, gLinearWrap);
-    startX = 0; startY = 300;
-    width = 300; height = 300;
-    rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
-                         startX, startY + height, 0, 0, 1.1,
-                         startX + width, startY + height, 0, 1.1, 1.1,
-                         startX + width, startY, 0, 1.1, 0);
-
-    // Nearest
-    rsgBindSampler(gProgFragmentTexture, 0, gNearestClamp);
-    startX = 300; startY = 0;
-    width = 300; height = 300;
-    rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
-                         startX, startY + height, 0, 0, 1.1,
-                         startX + width, startY + height, 0, 1.1, 1.1,
-                         startX + width, startY, 0, 1.1, 0);
-
-    rsgBindSampler(gProgFragmentTexture, 0, gMipLinearWrap);
-    startX = 300; startY = 300;
-    width = 300; height = 300;
-    rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
-                         startX, startY + height, 0, 0, 1.5,
-                         startX + width, startY + height, 0, 1.5, 1.5,
-                         startX + width, startY, 0, 1.5, 0);
-
-    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
-    rsgBindFont(gFontMono);
-    rsgDrawText("Filtering: linear clamp", 10, 290);
-    rsgDrawText("Filtering: linear wrap", 10, 590);
-    rsgDrawText("Filtering: nearest clamp", 310, 290);
-    rsgDrawText("Filtering: miplinear wrap", 310, 590);
-}
-
-static float gTorusRotation = 0;
-
-static void displayCullingSamples() {
-    rsgBindProgramVertex(gProgVertex);
-    // Setup the projectioni matrix with 60 degree field of view
-    rs_matrix4x4 proj;
-    float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
-    rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f);
-    rsgProgramVertexLoadProjectionMatrix(&proj);
-
-    // Fragment shader with texture
-    rsgBindProgramStore(gProgStoreBlendNoneDepth);
-    rsgBindProgramFragment(gProgFragmentTexture);
-    rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
-    rsgBindTexture(gProgFragmentTexture, 0, gTexTorus);
-
-    // Aplly a rotation to our mesh
-    gTorusRotation += 50.0f * gDt;
-    if (gTorusRotation > 360.0f) {
-        gTorusRotation -= 360.0f;
-    }
-
-    rs_matrix4x4 matrix;
-    // Position our model on the screen
-    rsMatrixLoadTranslate(&matrix, -2.0f, 0.0f, -10.0f);
-    rsMatrixRotate(&matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
-    rsgProgramVertexLoadModelMatrix(&matrix);
-    // Use front face culling
-    rsgBindProgramRaster(gCullFront);
-    rsgDrawMesh(gTorusMesh);
-
-    rsMatrixLoadTranslate(&matrix, 2.0f, 0.0f, -10.0f);
-    rsMatrixRotate(&matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
-    rsgProgramVertexLoadModelMatrix(&matrix);
-    // Use back face culling
-    rsgBindProgramRaster(gCullBack);
-    rsgDrawMesh(gTorusMesh);
-
-    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
-    rsgBindFont(gFontMono);
-    rsgDrawText("Displaying mesh front/back face culling", 10, rsgGetHeight() - 10);
-}
-
-static float gLight0Rotation = 0;
-static float gLight1Rotation = 0;
-
-static void setupCustomShaderLights() {
-    float4 light0Pos = {-5.0f, 5.0f, -10.0f, 1.0f};
-    float4 light1Pos = {2.0f, 5.0f, 15.0f, 1.0f};
-    float4 light0DiffCol = {0.9f, 0.7f, 0.7f, 1.0f};
-    float4 light0SpecCol = {0.9f, 0.6f, 0.6f, 1.0f};
-    float4 light1DiffCol = {0.5f, 0.5f, 0.9f, 1.0f};
-    float4 light1SpecCol = {0.5f, 0.5f, 0.9f, 1.0f};
-
-    gLight0Rotation += 50.0f * gDt;
-    if (gLight0Rotation > 360.0f) {
-        gLight0Rotation -= 360.0f;
-    }
-    gLight1Rotation -= 50.0f * gDt;
-    if (gLight1Rotation > 360.0f) {
-        gLight1Rotation -= 360.0f;
-    }
-
-    rs_matrix4x4 l0Mat;
-    rsMatrixLoadRotate(&l0Mat, gLight0Rotation, 1.0f, 0.0f, 0.0f);
-    light0Pos = rsMatrixMultiply(&l0Mat, light0Pos);
-    rs_matrix4x4 l1Mat;
-    rsMatrixLoadRotate(&l1Mat, gLight1Rotation, 0.0f, 0.0f, 1.0f);
-    light1Pos = rsMatrixMultiply(&l1Mat, light1Pos);
-
-    // Set light 0 properties
-    gVSConstants->light0_Posision = light0Pos;
-    gVSConstants->light0_Diffuse = 1.0f;
-    gVSConstants->light0_Specular = 0.5f;
-    gVSConstants->light0_CosinePower = 10.0f;
-    // Set light 1 properties
-    gVSConstants->light1_Posision = light1Pos;
-    gVSConstants->light1_Diffuse = 1.0f;
-    gVSConstants->light1_Specular = 0.7f;
-    gVSConstants->light1_CosinePower = 25.0f;
-    rsgAllocationSyncAll(rsGetAllocation(gVSConstants));
-
-    gVSConstants2->light_Posision[0] = light0Pos;
-    gVSConstants2->light_Diffuse[0] = 1.0f;
-    gVSConstants2->light_Specular[0] = 0.5f;
-    gVSConstants2->light_CosinePower[0] = 10.0f;
-    gVSConstants2->light_Posision[1] = light1Pos;
-    gVSConstants2->light_Diffuse[1] = 1.0f;
-    gVSConstants2->light_Specular[1] = 0.7f;
-    gVSConstants2->light_CosinePower[1] = 25.0f;
-    rsgAllocationSyncAll(rsGetAllocation(gVSConstants2));
-
-    // Update fragmetn shader constants
-    // Set light 0 colors
-    gFSConstants->light0_DiffuseColor = light0DiffCol;
-    gFSConstants->light0_SpecularColor = light0SpecCol;
-    // Set light 1 colors
-    gFSConstants->light1_DiffuseColor = light1DiffCol;
-    gFSConstants->light1_SpecularColor = light1SpecCol;
-    rsgAllocationSyncAll(rsGetAllocation(gFSConstants));
-
-    gFSConstants2->light_DiffuseColor[0] = light0DiffCol;
-    gFSConstants2->light_SpecularColor[0] = light0SpecCol;
-    // Set light 1 colors
-    gFSConstants2->light_DiffuseColor[1] = light1DiffCol;
-    gFSConstants2->light_SpecularColor[1] = light1SpecCol;
-    rsgAllocationSyncAll(rsGetAllocation(gFSConstants2));
-}
-
-static void displayCustomShaderSamples() {
-
-    // Update vertex shader constants
-    // Load model matrix
-    // Aplly a rotation to our mesh
-    gTorusRotation += 50.0f * gDt;
-    if (gTorusRotation > 360.0f) {
-        gTorusRotation -= 360.0f;
-    }
-
-    // Position our model on the screen
-    rsMatrixLoadTranslate(&gVSConstants->model, 0.0f, 0.0f, -10.0f);
-    rsMatrixRotate(&gVSConstants->model, gTorusRotation, 1.0f, 0.0f, 0.0f);
-    rsMatrixRotate(&gVSConstants->model, gTorusRotation, 0.0f, 0.0f, 1.0f);
-    // Setup the projectioni matrix
-    float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
-    rsMatrixLoadPerspective(&gVSConstants->proj, 30.0f, aspect, 0.1f, 100.0f);
-    setupCustomShaderLights();
-
-    rsgBindProgramVertex(gProgVertexCustom);
-
-    // Fragment shader with texture
-    rsgBindProgramStore(gProgStoreBlendNoneDepth);
-    rsgBindProgramFragment(gProgFragmentCustom);
-    rsgBindSampler(gProgFragmentCustom, 0, gLinearClamp);
-    rsgBindTexture(gProgFragmentCustom, 0, gTexTorus);
-
-    // Use back face culling
-    rsgBindProgramRaster(gCullBack);
-    rsgDrawMesh(gTorusMesh);
-
-    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
-    rsgBindFont(gFontMono);
-    rsgDrawText("Custom shader sample", 10, rsgGetHeight() - 10);
-}
-
-static void displayCustomShaderSamples2() {
-
-    // Update vertex shader constants
-    // Load model matrix
-    // Aplly a rotation to our mesh
-    gTorusRotation += 50.0f * gDt;
-    if (gTorusRotation > 360.0f) {
-        gTorusRotation -= 360.0f;
-    }
-
-    // Position our model on the screen
-    rsMatrixLoadTranslate(&gVSConstants2->model[1], 0.0f, 0.0f, -10.0f);
-    rsMatrixLoadIdentity(&gVSConstants2->model[0]);
-    rsMatrixRotate(&gVSConstants2->model[0], gTorusRotation, 1.0f, 0.0f, 0.0f);
-    rsMatrixRotate(&gVSConstants2->model[0], gTorusRotation, 0.0f, 0.0f, 1.0f);
-    // Setup the projectioni matrix
-    float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
-    rsMatrixLoadPerspective(&gVSConstants2->proj, 30.0f, aspect, 0.1f, 100.0f);
-    setupCustomShaderLights();
-
-    rsgBindProgramVertex(gProgVertexCustom2);
-
-    // Fragment shader with texture
-    rsgBindProgramStore(gProgStoreBlendNoneDepth);
-    rsgBindProgramFragment(gProgFragmentCustom2);
-    rsgBindSampler(gProgFragmentCustom2, 0, gLinearClamp);
-    rsgBindTexture(gProgFragmentCustom2, 0, gTexTorus);
-
-    // Use back face culling
-    rsgBindProgramRaster(gCullBack);
-    rsgDrawMesh(gTorusMesh);
-
-    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
-    rsgBindFont(gFontMono);
-    rsgDrawText("Custom shader sample with array uniforms", 10, rsgGetHeight() - 10);
-}
-
-static void displayCubemapShaderSample() {
-    // Update vertex shader constants
-    // Load model matrix
-    // Aplly a rotation to our mesh
-    gTorusRotation += 50.0f * gDt;
-    if (gTorusRotation > 360.0f) {
-        gTorusRotation -= 360.0f;
-    }
-
-    // Position our model on the screen
-    // Position our model on the screen
-    rsMatrixLoadTranslate(&gVSConstants->model, 0.0f, 0.0f, -10.0f);
-    rsMatrixRotate(&gVSConstants->model, gTorusRotation, 1.0f, 0.0f, 0.0f);
-    rsMatrixRotate(&gVSConstants->model, gTorusRotation, 0.0f, 0.0f, 1.0f);
-    // Setup the projectioni matrix
-    float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
-    rsMatrixLoadPerspective(&gVSConstants->proj, 30.0f, aspect, 0.1f, 100.0f);
-    rsgAllocationSyncAll(rsGetAllocation(gFSConstants));
-
-    rsgBindProgramVertex(gProgVertexCube);
-
-    // Fragment shader with texture
-    rsgBindProgramStore(gProgStoreBlendNoneDepth);
-    rsgBindProgramFragment(gProgFragmentCube);
-    rsgBindSampler(gProgFragmentCube, 0, gLinearClamp);
-    rsgBindTexture(gProgFragmentCube, 0, gTexCube);
-
-    // Use back face culling
-    rsgBindProgramRaster(gCullBack);
-    rsgDrawMesh(gTorusMesh);
-
-    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
-    rsgBindFont(gFontMono);
-    rsgDrawText("Cubemap shader sample", 10, rsgGetHeight() - 10);
-}
-
-static void displayMultitextureSample() {
-    bindProgramVertexOrtho();
-    rs_matrix4x4 matrix;
-    rsMatrixLoadIdentity(&matrix);
-    rsgProgramVertexLoadModelMatrix(&matrix);
-
-    // Fragment shader with texture
-    rsgBindProgramStore(gProgStoreBlendNone);
-    rsgBindProgramFragment(gProgFragmentMultitex);
-    rsgBindSampler(gProgFragmentMultitex, 0, gLinearClamp);
-    rsgBindSampler(gProgFragmentMultitex, 1, gLinearWrap);
-    rsgBindSampler(gProgFragmentMultitex, 2, gLinearClamp);
-    rsgBindTexture(gProgFragmentMultitex, 0, gTexChecker);
-    rsgBindTexture(gProgFragmentMultitex, 1, gTexTorus);
-    rsgBindTexture(gProgFragmentMultitex, 2, gTexTransparent);
-
-    float startX = 0, startY = 0;
-    float width = 256, height = 256;
-    rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
-                         startX, startY + height, 0, 0, 1,
-                         startX + width, startY + height, 0, 1, 1,
-                         startX + width, startY, 0, 1, 0);
-
-    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
-    rsgBindFont(gFontMono);
-    rsgDrawText("Custom shader with multitexturing", 10, 280);
-}
-
-static float gAnisoTime = 0.0f;
-static uint anisoMode = 0;
-static void displayAnisoSample() {
-
-    gAnisoTime += gDt;
-
-    rsgBindProgramVertex(gProgVertex);
-    float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
-    rs_matrix4x4 proj;
-    rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f);
-    rsgProgramVertexLoadProjectionMatrix(&proj);
-
-    rs_matrix4x4 matrix;
-    // Fragment shader with texture
-    rsgBindProgramStore(gProgStoreBlendNone);
-    rsgBindProgramFragment(gProgFragmentTexture);
-    rsMatrixLoadTranslate(&matrix, 0.0f, 0.0f, -10.0f);
-    rsMatrixRotate(&matrix, -80, 1.0f, 0.0f, 0.0f);
-    rsgProgramVertexLoadModelMatrix(&matrix);
-
-    rsgBindProgramRaster(gCullNone);
-
-    rsgBindTexture(gProgFragmentTexture, 0, gTexChecker);
-
-    if (gAnisoTime >= 5.0f) {
-        gAnisoTime = 0.0f;
-        anisoMode ++;
-        anisoMode = anisoMode % 3;
-    }
-
-    if (anisoMode == 0) {
-        rsgBindSampler(gProgFragmentTexture, 0, gMipLinearAniso8);
-    } else if (anisoMode == 1) {
-        rsgBindSampler(gProgFragmentTexture, 0, gMipLinearAniso15);
-    } else {
-        rsgBindSampler(gProgFragmentTexture, 0, gMipLinearWrap);
-    }
-
-    float startX = -15;
-    float startY = -15;
-    float width = 30;
-    float height = 30;
-    rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
-                         startX, startY + height, 0, 0, 10,
-                         startX + width, startY + height, 0, 10, 10,
-                         startX + width, startY, 0, 10, 0);
-
-    rsgBindProgramRaster(gCullBack);
-
-    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
-    rsgBindFont(gFontMono);
-    if (anisoMode == 0) {
-        rsgDrawText("Anisotropic filtering 8", 10, 40);
-    } else if (anisoMode == 1) {
-        rsgDrawText("Anisotropic filtering 15", 10, 40);
-    } else {
-        rsgDrawText("Miplinear filtering", 10, 40);
-    }
-}
-
-int root(void) {
-
-    gDt = rsGetDt();
-
-    rsgClearColor(0.2f, 0.2f, 0.2f, 0.0f);
-    rsgClearDepth(1.0f);
-
-    switch (gDisplayMode) {
-    case 0:
-        displayFontSamples();
-        break;
-    case 1:
-        displayShaderSamples();
-        break;
-    case 2:
-        displayBlendingSamples();
-        break;
-    case 3:
-        displayMeshSamples();
-        break;
-    case 4:
-        displayTextureSamplers();
-        break;
-    case 5:
-        displayCullingSamples();
-        break;
-    case 6:
-        displayCustomShaderSamples();
-        break;
-    case 7:
-        displayMultitextureSample();
-        break;
-    case 8:
-        displayAnisoSample();
-        break;
-    case 9:
-        displayCustomShaderSamples2();
-        break;
-    case 10:
-        displayCubemapShaderSample();
-        break;
-    }
-
-    return 10;
-}
diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/shader_def.rsh b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/shader_def.rsh
deleted file mode 100644
index 08cf361..0000000
--- a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/shader_def.rsh
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright (C) 2009 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.example.android.rs.miscsamples)
-
-typedef struct VertexShaderConstants_s {
-    rs_matrix4x4 model;
-    rs_matrix4x4 proj;
-    float4 light0_Posision;
-    float light0_Diffuse;
-    float light0_Specular;
-    float light0_CosinePower;
-
-    float4 light1_Posision;
-    float light1_Diffuse;
-    float light1_Specular;
-    float light1_CosinePower;
-} VertexShaderConstants;
-
-typedef struct VertexShaderConstants2_s {
-    rs_matrix4x4 model[2];
-    rs_matrix4x4 proj;
-    float4 light_Posision[2];
-    float light_Diffuse[2];
-    float light_Specular[2];
-    float light_CosinePower[2];
-} VertexShaderConstants2;
-
-typedef struct VertexShaderConstants3_s {
-    rs_matrix4x4 model;
-    rs_matrix4x4 proj;
-    float time;
-} VertexShaderConstants3;
-
-
-typedef struct FragentShaderConstants_s {
-    float4 light0_DiffuseColor;
-    float4 light0_SpecularColor;
-
-    float4 light1_DiffuseColor;
-    float4 light1_SpecularColor;
-} FragentShaderConstants;
-
-typedef struct FragentShaderConstants2_s {
-    float4 light_DiffuseColor[2];
-    float4 light_SpecularColor[2];
-} FragentShaderConstants2;
-
-typedef struct FragentShaderConstants3_s {
-    float4 light0_DiffuseColor;
-    float4 light0_SpecularColor;
-    float4 light0_Posision;
-    float light0_Diffuse;
-    float light0_Specular;
-    float light0_CosinePower;
-
-    float4 light1_DiffuseColor;
-    float4 light1_SpecularColor;
-    float4 light1_Posision;
-    float light1_Diffuse;
-    float light1_Specular;
-    float light1_CosinePower;
-} FragentShaderConstants3;
-
-typedef struct VertexShaderInputs_s {
-    float4 position;
-    float3 normal;
-    float2 texture0;
-} VertexShaderInputs;
-
diff --git a/tests/RenderScriptTests/ModelViewer/Android.mk b/tests/RenderScriptTests/ModelViewer/Android.mk
deleted file mode 100644
index 86724cf..0000000
--- a/tests/RenderScriptTests/ModelViewer/Android.mk
+++ /dev/null
@@ -1,29 +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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
-
-LOCAL_SDK_VERSION := 17
-
-LOCAL_PACKAGE_NAME := ModelViewer
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/ModelViewer/AndroidManifest.xml b/tests/RenderScriptTests/ModelViewer/AndroidManifest.xml
deleted file mode 100644
index 57ec4fe..0000000
--- a/tests/RenderScriptTests/ModelViewer/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.modelviewer">
-    <application android:label="ModelViewer">
-        <activity android:name="SimpleModel"
-                  android:label="SimpleModel"
-                  android:screenOrientation="nosensor">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-        <activity android:name="A3DSelector"
-                  android:label="A3DSelector"
-                  android:hardwareAccelerated="true">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-        <activity android:name="SceneGraph"
-                  android:label="SceneGraph"
-                  android:theme="@android:style/Theme.Black.NoTitleBar">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/ModelViewer/res/drawable-nodpi/robot.png b/tests/RenderScriptTests/ModelViewer/res/drawable-nodpi/robot.png
deleted file mode 100644
index f7353fd..0000000
--- a/tests/RenderScriptTests/ModelViewer/res/drawable-nodpi/robot.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/ModelViewer/res/menu/loader_menu.xml b/tests/RenderScriptTests/ModelViewer/res/menu/loader_menu.xml
deleted file mode 100644
index 2a8759c..0000000
--- a/tests/RenderScriptTests/ModelViewer/res/menu/loader_menu.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-* Copyright (C) 2011 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*      http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
--->
-
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:id="@+id/load_model"
-          android:title="@string/load_model" />
-    <item android:id="@+id/display_options"
-          android:title="@string/display_options" />
-    <item android:id="@+id/sensor"
-          android:title="@string/sensor" />
-</menu>
diff --git a/tests/RenderScriptTests/ModelViewer/res/raw/robot.a3d b/tests/RenderScriptTests/ModelViewer/res/raw/robot.a3d
deleted file mode 100644
index f48895c..0000000
--- a/tests/RenderScriptTests/ModelViewer/res/raw/robot.a3d
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/ModelViewer/res/values/strings.xml b/tests/RenderScriptTests/ModelViewer/res/values/strings.xml
deleted file mode 100644
index a5c8f22..0000000
--- a/tests/RenderScriptTests/ModelViewer/res/values/strings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-* Copyright (C) 2011 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*      http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <skip />
-    <string name="load_model">Load Model</string>
-    <string name="display_options">Display Options</string>
-    <string name="sensor">Toggle Sensor</string>
-</resources>
diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/A3DSelector.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/A3DSelector.java
deleted file mode 100644
index 0e2004f..0000000
--- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/A3DSelector.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.modelviewer;
-
-import java.io.File;
-import java.io.FileFilter;
-import java.util.ArrayList;
-import java.util.List;
-
-import android.app.ListActivity;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-
-/**
- * A list view where the last item the user clicked is placed in
- * the "activated" state, causing its background to highlight.
- */
-public class A3DSelector extends ListActivity {
-
-    File[] mCurrentSubList;
-    File mCurrentFile;
-
-    class A3DFilter implements FileFilter {
-        public boolean accept(File file) {
-            if (file.isDirectory()) {
-                return true;
-            }
-            return file.getName().endsWith(".a3d");
-        }
-    }
-
-    private void populateList(File file) {
-
-        mCurrentFile = file;
-        setTitle(mCurrentFile.getAbsolutePath() + "/*.a3d");
-        List<String> names = new ArrayList<String>();
-        names.add("..");
-
-        mCurrentSubList = mCurrentFile.listFiles(new A3DFilter());
-
-        if (mCurrentSubList != null) {
-            for (int i = 0; i < mCurrentSubList.length; i ++) {
-                String fileName = mCurrentSubList[i].getName();
-                if (mCurrentSubList[i].isDirectory()) {
-                    fileName = "/" + fileName;
-                }
-                names.add(fileName);
-            }
-        }
-
-        // Use the built-in layout for showing a list item with a single
-        // line of text whose background is changes when activated.
-        setListAdapter(new ArrayAdapter<String>(this,
-                android.R.layout.simple_list_item_activated_1, names));
-        getListView().setTextFilterEnabled(true);
-
-        // Tell the list view to show one checked/activated item at a time.
-        getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        populateList(new File("/sdcard/"));
-    }
-
-    @Override
-    protected void onListItemClick(ListView l, View v, int position, long id) {
-        if (position == 0) {
-            File parent = mCurrentFile.getParentFile();
-            if (parent == null) {
-                return;
-            }
-            populateList(parent);
-            return;
-        }
-
-        // the first thing in list is parent directory
-        File selectedFile = mCurrentSubList[position - 1];
-        if (selectedFile.isDirectory()) {
-            populateList(selectedFile);
-            return;
-        }
-
-        Intent resultIntent = new Intent();
-        resultIntent.setData(Uri.fromFile(selectedFile));
-        setResult(RESULT_OK, resultIntent);
-        finish();
-    }
-
-}
diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraph.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraph.java
deleted file mode 100644
index c9c4dc1..0000000
--- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraph.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.modelviewer;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-
-import android.app.Activity;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Settings.System;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.Window;
-import android.widget.Button;
-import android.widget.ListView;
-
-import java.lang.Runtime;
-
-public class SceneGraph extends Activity {
-
-    private SceneGraphView mView;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        // Create our Preview view and set it as the content of our
-        // Activity
-        mView = new SceneGraphView(this);
-        setContentView(mView);
-    }
-
-    @Override
-    protected void onResume() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity looses focus
-        super.onResume();
-        mView.resume();
-    }
-
-    @Override
-    protected void onPause() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity looses focus
-        super.onPause();
-        mView.pause();
-    }
-
-}
-
diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java
deleted file mode 100644
index f91f31e..0000000
--- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.modelviewer;
-
-import java.io.Writer;
-import java.util.Map;
-import java.util.Vector;
-
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.renderscript.Element.Builder;
-import android.renderscript.Font.Style;
-import android.renderscript.ProgramStore.DepthFunc;
-import android.util.Log;
-
-
-public class SceneGraphRS {
-
-    private final int STATE_LAST_FOCUS = 1;
-
-    int mWidth;
-    int mHeight;
-    int mRotation;
-
-    public SceneGraphRS() {
-    }
-
-    public void init(RenderScriptGL rs, Resources res, int width, int height) {
-        mRS = rs;
-        mRes = res;
-        mWidth = width;
-        mHeight = height;
-        mRotation = 0;
-        initRS();
-    }
-
-    private Resources mRes;
-    private RenderScriptGL mRS;
-    private Sampler mSampler;
-    private ProgramStore mPSBackground;
-    private ProgramFragment mPFBackground;
-    private ProgramVertex mPVBackground;
-    private ProgramVertexFixedFunction.Constants mPVA;
-
-    private Allocation mGridImage;
-    private Allocation mAllocPV;
-
-    private Mesh mMesh;
-
-    private Font mItalic;
-    private Allocation mTextAlloc;
-
-    private ScriptC_scenegraph mScript;
-    private ScriptC_transform mTransformScript;
-
-    int mLastX;
-    int mLastY;
-
-    public void touchEvent(int x, int y) {
-        int dx = mLastX - x;
-        if (Math.abs(dx) > 50 || Math.abs(dx) < 3) {
-            dx = 0;
-        }
-
-        mRotation -= dx;
-        if (mRotation > 360) {
-            mRotation -= 360;
-        }
-        if (mRotation < 0) {
-            mRotation += 360;
-        }
-
-        mScript.set_gRotate(-(float)mRotation);
-
-        mLastX = x;
-        mLastY = y;
-    }
-
-    private void initPFS() {
-        ProgramStore.Builder b = new ProgramStore.Builder(mRS);
-
-        b.setDepthFunc(ProgramStore.DepthFunc.LESS);
-        b.setDitherEnabled(false);
-        b.setDepthMaskEnabled(true);
-        mPSBackground = b.create();
-
-        mScript.set_gPFSBackground(mPSBackground);
-    }
-
-    private void initPF() {
-        Sampler.Builder bs = new Sampler.Builder(mRS);
-        bs.setMinification(Sampler.Value.LINEAR);
-        bs.setMagnification(Sampler.Value.LINEAR);
-        bs.setWrapS(Sampler.Value.CLAMP);
-        bs.setWrapT(Sampler.Value.CLAMP);
-        mSampler = bs.create();
-
-        ProgramFragmentFixedFunction.Builder b = new ProgramFragmentFixedFunction.Builder(mRS);
-        b.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
-                     ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
-        mPFBackground = b.create();
-        mPFBackground.bindSampler(mSampler, 0);
-
-        mScript.set_gPFBackground(mPFBackground);
-    }
-
-    private void initPV() {
-        ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
-        mPVBackground = pvb.create();
-
-        mPVA = new ProgramVertexFixedFunction.Constants(mRS);
-        ((ProgramVertexFixedFunction)mPVBackground).bindConstants(mPVA);
-
-        mScript.set_gPVBackground(mPVBackground);
-    }
-
-    private void loadImage() {
-        mGridImage = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot,
-                                                         Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
-                                                         Allocation.USAGE_GRAPHICS_TEXTURE);
-        mScript.set_gTGrid(mGridImage);
-    }
-
-    private void initTextAllocation() {
-        String allocString = "Displaying file: R.raw.robot";
-        mTextAlloc = Allocation.createFromString(mRS, allocString, Allocation.USAGE_SCRIPT);
-        mScript.set_gTextAlloc(mTextAlloc);
-    }
-
-    SgTransform mRootTransform;
-    SgTransform mGroup1;
-
-    SgTransform mRobot1;
-    SgTransform mRobot2;
-
-    void initTransformHierarchy() {
-        mRootTransform = new SgTransform(mRS);
-
-        mGroup1 = new SgTransform(mRS);
-        mRootTransform.addChild(mGroup1);
-
-        mRobot1 = new SgTransform(mRS);
-        mRobot2 = new SgTransform(mRS);
-
-        mGroup1.addChild(mRobot1);
-        mGroup1.addChild(mRobot2);
-
-        mGroup1.setTransform(0, new Float4(0.0f, 0.0f, -15.0f, 0.0f), TransformType.TRANSLATE);
-        mGroup1.setTransform(1, new Float4(0.0f, 1.0f, 0.0f, 15.0f), TransformType.ROTATE);
-
-        mRobot1.setTransform(0, new Float4(-3.0f, -0.5f, 0.0f, 0.0f), TransformType.TRANSLATE);
-        mRobot1.setTransform(1, new Float4(0.0f, 1.0f, 0.0f, 20.0f), TransformType.ROTATE);
-        mRobot1.setTransform(2, new Float4(0.2f, 0.2f, 0.2f, 0.0f), TransformType.SCALE);
-
-        mRobot2.setTransform(0, new Float4(3.0f, 0.0f, 0.0f, 0.0f), TransformType.TRANSLATE);
-        mRobot2.setTransform(1, new Float4(0.0f, 1.0f, 0.0f, -20.0f), TransformType.ROTATE);
-        mRobot2.setTransform(2, new Float4(0.3f, 0.3f, 0.3f, 0.0f), TransformType.SCALE);
-    }
-
-    private void initRS() {
-
-        mScript = new ScriptC_scenegraph(mRS, mRes, R.raw.scenegraph);
-        mTransformScript = new ScriptC_transform(mRS, mRes, R.raw.transform);
-        mTransformScript.set_transformScript(mTransformScript);
-
-        mScript.set_gTransformRS(mTransformScript);
-
-        initPFS();
-        initPF();
-        initPV();
-
-        loadImage();
-
-        FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot);
-        FileA3D.IndexEntry entry = model.getIndexEntry(0);
-        if (entry == null || entry.getEntryType() != FileA3D.EntryType.MESH) {
-            Log.e("rs", "could not load model");
-        } else {
-            mMesh = (Mesh)entry.getObject();
-            mScript.set_gTestMesh(mMesh);
-        }
-
-        mItalic = Font.create(mRS, mRes, "serif", Font.Style.ITALIC, 8);
-        mScript.set_gItalic(mItalic);
-
-        initTextAllocation();
-
-        initTransformHierarchy();
-
-        mScript.bind_gRootNode(mRootTransform.getField());
-
-        mScript.bind_gGroup(mGroup1.mParent.mChildField);
-        mScript.bind_gRobot1(mRobot1.mParent.mChildField);
-        mScript.set_gRobot1Index(mRobot1.mIndexInParentGroup);
-        mScript.bind_gRobot2(mRobot2.mParent.mChildField);
-        mScript.set_gRobot2Index(mRobot2.mIndexInParentGroup);
-
-        mRS.bindRootScript(mScript);
-    }
-}
-
-
-
diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraphView.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraphView.java
deleted file mode 100644
index 0b6a3b8..0000000
--- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraphView.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.modelviewer;
-
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.concurrent.Semaphore;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-import android.renderscript.RenderScriptGL;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.Message;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-
-public class SceneGraphView extends RSSurfaceView {
-
-    public SceneGraphView(Context context) {
-        super(context);
-        //setFocusable(true);
-    }
-
-    private RenderScriptGL mRS;
-    private SceneGraphRS mRender;
-
-
-    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
-        super.surfaceChanged(holder, format, w, h);
-        if (mRS == null) {
-            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
-            sc.setDepth(16, 24);
-            mRS = createRenderScriptGL(sc);
-            mRS.setSurface(holder, w, h);
-            mRender = new SceneGraphRS();
-            mRender.init(mRS, getResources(), w, h);
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        if (mRS != null) {
-            mRS = null;
-            destroyRenderScriptGL();
-        }
-    }
-
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event)
-    {
-        // break point at here
-        // this method doesn't work when 'extends View' include 'extends ScrollView'.
-        return super.onKeyDown(keyCode, event);
-    }
-
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev)
-    {
-        boolean ret = true;
-        int act = ev.getAction();
-        if (act == ev.ACTION_UP) {
-            ret = false;
-        }
-
-        mRender.touchEvent((int)ev.getX(), (int)ev.getY());
-        return ret;
-    }
-}
-
-
diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SgTransform.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SgTransform.java
deleted file mode 100644
index f5484e2..0000000
--- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SgTransform.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.modelviewer;
-
-import java.io.Writer;
-import java.util.Map;
-import java.util.Vector;
-
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.renderscript.Element.Builder;
-import android.renderscript.ProgramStore.DepthFunc;
-import android.util.Log;
-
-enum TransformType {
-
-    NONE(0),
-    TRANSLATE(1),
-    ROTATE(2),
-    SCALE(3);
-
-    int mID;
-    TransformType(int id) {
-        mID = id;
-    }
-}
-
-public class SgTransform {
-
-
-    ScriptField_SgTransform mTransformField;
-    ScriptField_SgTransform mChildField;
-    public ScriptField_SgTransform.Item mTransformData;
-
-    RenderScript mRS;
-
-    Vector mChildren;
-    SgTransform mParent;
-    int mIndexInParentGroup;
-
-    public void setParent(SgTransform parent, int parentIndex) {
-        mParent = parent;
-        mIndexInParentGroup = parentIndex;
-    }
-
-    public void addChild(SgTransform child) {
-        mChildren.add(child);
-        child.setParent(this, mChildren.size() - 1);
-    }
-
-    public void setTransform(int index, Float4 value, TransformType type) {
-        mTransformData.transforms[index] = value;
-        mTransformData.transformTypes[index] = type.mID;
-    }
-
-    void initData() {
-        int numElements = mTransformData.transforms.length;
-        mTransformData.transformTypes = new int[numElements];
-        for (int i = 0; i < numElements; i ++) {
-            mTransformData.transforms[i] = new Float4(0, 0, 0, 0);
-            mTransformData.transformTypes[i] = TransformType.NONE.mID;
-        }
-
-        mTransformData.isDirty = 1;
-        mTransformData.children = null;
-    }
-
-    public SgTransform(RenderScript rs) {
-        mRS = rs;
-        mTransformData = new ScriptField_SgTransform.Item();
-        mChildren = new Vector();
-        initData();
-    }
-
-    public ScriptField_SgTransform.Item getData() {
-        if (mChildren.size() != 0) {
-            mChildField = new ScriptField_SgTransform(mRS, mChildren.size());
-            mTransformData.children = mChildField.getAllocation();
-
-            for (int i = 0; i < mChildren.size(); i ++) {
-                SgTransform child = (SgTransform)mChildren.get(i);
-                mChildField.set(child.getData(), i, false);
-            }
-            mChildField.copyAll();
-        }
-
-        return mTransformData;
-    }
-
-    public ScriptField_SgTransform getField() {
-        mTransformField = new ScriptField_SgTransform(mRS, 1);
-        mTransformField.set(getData(), 0, true);
-        return mTransformField;
-    }
-}
-
-
-
diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModel.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModel.java
deleted file mode 100644
index 2b29ff4..0000000
--- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModel.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.modelviewer;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-
-import android.app.Activity;
-import android.content.res.Configuration;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Settings.System;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.MenuInflater;
-import android.view.Window;
-import android.widget.Button;
-import android.widget.ListView;
-import android.net.Uri;
-
-import java.lang.Runtime;
-
-public class SimpleModel extends Activity {
-
-    private SimpleModelView mView;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        // Create our Preview view and set it as the content of our
-        // Activity
-        mView = new SimpleModelView(this);
-        setContentView(mView);
-    }
-
-    @Override
-    protected void onResume() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity looses focus
-        super.onResume();
-        mView.resume();
-    }
-
-    @Override
-    protected void onPause() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity looses focus
-        super.onPause();
-        mView.pause();
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        MenuInflater inflater = getMenuInflater();
-        inflater.inflate(R.menu.loader_menu, menu);
-        return true;
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        // Handle item selection
-        switch (item.getItemId()) {
-        case R.id.load_model:
-            loadModel();
-            return true;
-        case R.id.display_options:
-            return true;
-        case R.id.sensor:
-            mView.toggleSensor();
-            return true;
-        default:
-            return super.onOptionsItemSelected(item);
-        }
-    }
-
-    private static final int FIND_A3D_MODEL = 10;
-    public void onActivityResult(int requestCode, int resultCode, Intent data) {
-        if (resultCode == RESULT_OK) {
-            if (requestCode == FIND_A3D_MODEL) {
-                Uri selectedImageUri = data.getData();
-                Log.e("Selected Path: ", selectedImageUri.getPath());
-                mView.loadA3DFile(selectedImageUri.getPath());
-            }
-        }
-    }
-
-    public void loadModel() {
-        Intent intent = new Intent();
-        intent.setAction(Intent.ACTION_PICK);
-        intent.setClassName("com.android.modelviewer",
-                            "com.android.modelviewer.A3DSelector");
-        startActivityForResult(intent, FIND_A3D_MODEL);
-    }
-
-}
-
diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java
deleted file mode 100644
index 5fa3a9e..0000000
--- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.modelviewer;
-
-import java.io.Writer;
-
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.renderscript.ProgramStore.DepthFunc;
-import android.util.Log;
-
-
-public class SimpleModelRS {
-
-    public SimpleModelRS() {
-    }
-
-    public void init(RenderScriptGL rs, Resources res) {
-        mRS = rs;
-        mRes = res;
-        initRS();
-    }
-
-    public void surfaceChanged() {
-        mRS.getWidth();
-        mRS.getHeight();
-    }
-
-    private Resources mRes;
-    private RenderScriptGL mRS;
-    private Sampler mSampler;
-    private ProgramStore mPSBackground;
-    private ProgramFragment mPFBackground;
-    private ProgramVertex mPVBackground;
-    private ProgramVertexFixedFunction.Constants mPVA;
-
-    private Allocation mGridImage;
-    private Allocation mAllocPV;
-
-    private Font mItalic;
-    private Allocation mTextAlloc;
-
-    private ScriptField_MeshInfo mMeshes;
-    private ScriptC_simplemodel mScript;
-
-
-    public void onActionDown(float x, float y) {
-        mScript.invoke_onActionDown(x, y);
-    }
-
-    public void onActionScale(float scale) {
-        mScript.invoke_onActionScale(scale);
-    }
-
-    public void onActionMove(float x, float y) {
-        mScript.invoke_onActionMove(x, y);
-    }
-
-    public void onPostureChanged(Matrix4f posture) {
-        mScript.set_gPostureMatrix(posture);
-    }
-
-    private void initPFS() {
-        ProgramStore.Builder b = new ProgramStore.Builder(mRS);
-
-        b.setDepthFunc(ProgramStore.DepthFunc.LESS);
-        b.setDitherEnabled(false);
-        b.setDepthMaskEnabled(true);
-        mPSBackground = b.create();
-
-        mScript.set_gPFSBackground(mPSBackground);
-    }
-
-    private void initPF() {
-        Sampler.Builder bs = new Sampler.Builder(mRS);
-        bs.setMinification(Sampler.Value.LINEAR);
-        bs.setMagnification(Sampler.Value.LINEAR);
-        bs.setWrapS(Sampler.Value.CLAMP);
-        bs.setWrapT(Sampler.Value.CLAMP);
-        mSampler = bs.create();
-
-        ProgramFragmentFixedFunction.Builder b = new ProgramFragmentFixedFunction.Builder(mRS);
-        b.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
-                     ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
-        mPFBackground = b.create();
-        mPFBackground.bindSampler(mSampler, 0);
-
-        mScript.set_gPFBackground(mPFBackground);
-    }
-
-    private void initPV() {
-        ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
-        mPVBackground = pvb.create();
-
-        mPVA = new ProgramVertexFixedFunction.Constants(mRS);
-        ((ProgramVertexFixedFunction)mPVBackground).bindConstants(mPVA);
-
-        mScript.set_gPVBackground(mPVBackground);
-    }
-
-    private void loadImage() {
-        mGridImage = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot,
-                                                         Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
-                                                         Allocation.USAGE_GRAPHICS_TEXTURE);
-        mScript.set_gTGrid(mGridImage);
-    }
-
-    private void initTextAllocation(String fileName) {
-        String allocString = "Displaying file: " + fileName;
-        mTextAlloc = Allocation.createFromString(mRS, allocString, Allocation.USAGE_SCRIPT);
-        mScript.set_gTextAlloc(mTextAlloc);
-    }
-
-    private void initMeshes(FileA3D model) {
-        int numEntries = model.getIndexEntryCount();
-        int numMeshes = 0;
-        for (int i = 0; i < numEntries; i ++) {
-            FileA3D.IndexEntry entry = model.getIndexEntry(i);
-            if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) {
-                numMeshes ++;
-            }
-        }
-
-        if (numMeshes > 0) {
-            mMeshes = new ScriptField_MeshInfo(mRS, numMeshes);
-
-            for (int i = 0; i < numEntries; i ++) {
-                FileA3D.IndexEntry entry = model.getIndexEntry(i);
-                if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) {
-                    Mesh mesh = entry.getMesh();
-                    mMeshes.set_mMesh(i, mesh, false);
-                    mMeshes.set_mNumIndexSets(i, mesh.getPrimitiveCount(), false);
-                }
-            }
-            mMeshes.copyAll();
-        } else {
-            throw new RSRuntimeException("No valid meshes in file");
-        }
-
-        mScript.bind_gMeshes(mMeshes);
-        mScript.invoke_updateMeshInfo();
-    }
-
-    public void loadA3DFile(String path) {
-        FileA3D model = FileA3D.createFromFile(mRS, path);
-        initMeshes(model);
-        initTextAllocation(path);
-    }
-
-    private void initRS() {
-
-        mScript = new ScriptC_simplemodel(mRS, mRes, R.raw.simplemodel);
-
-        initPFS();
-        initPF();
-        initPV();
-
-        loadImage();
-
-        FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot);
-        initMeshes(model);
-
-        mItalic = Font.create(mRS, mRes, "serif", Font.Style.ITALIC, 8);
-        mScript.set_gItalic(mItalic);
-
-        initTextAllocation("R.raw.robot");
-
-        mRS.bindRootScript(mScript);
-    }
-}
-
-
-
diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModelView.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModelView.java
deleted file mode 100644
index 4b7836b..0000000
--- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModelView.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.modelviewer;
-
-import android.renderscript.Matrix4f;
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScriptGL;
-
-import android.content.Context;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-import android.view.MotionEvent;
-import android.view.SurfaceHolder;
-import android.view.ScaleGestureDetector;
-import android.util.Log;
-
-public class SimpleModelView extends RSSurfaceView implements SensorEventListener {
-
-    private RenderScriptGL mRS;
-    private SimpleModelRS mRender;
-
-    private ScaleGestureDetector mScaleDetector;
-
-    private SensorManager mSensorManager;
-    private Sensor mRotationVectorSensor;
-    private final float[] mRotationMatrix = new float[16];
-
-    private static final int INVALID_POINTER_ID = -1;
-    private int mActivePointerId = INVALID_POINTER_ID;
-    private boolean mUseSensor = false;
-    private Matrix4f mIdentityMatrix = new Matrix4f();
-
-    public SimpleModelView(Context context) {
-        super(context);
-        ensureRenderScript();
-        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
-        // Get an instance of the SensorManager
-        mSensorManager = (SensorManager)getContext().getSystemService(Context.SENSOR_SERVICE);
-        // find the rotation-vector sensor
-        mRotationVectorSensor = mSensorManager.getDefaultSensor(
-                Sensor.TYPE_ROTATION_VECTOR);
-        mIdentityMatrix.loadIdentity();
-    }
-
-    private void ensureRenderScript() {
-        if (mRS == null) {
-            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
-            sc.setDepth(16, 24);
-            mRS = createRenderScriptGL(sc);
-            mRender = new SimpleModelRS();
-            mRender.init(mRS, getResources());
-        }
-    }
-
-    @Override
-    public void resume() {
-        mSensorManager.registerListener(this, mRotationVectorSensor, 10000);
-    }
-
-    @Override
-    public void pause() {
-        mSensorManager.unregisterListener(this);
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        ensureRenderScript();
-    }
-
-    @Override
-    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
-        super.surfaceChanged(holder, format, w, h);
-        mRender.surfaceChanged();
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        mRender = null;
-        if (mRS != null) {
-            mRS = null;
-            destroyRenderScriptGL();
-        }
-    }
-
-    public void loadA3DFile(String path) {
-        mRender.loadA3DFile(path);
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        mScaleDetector.onTouchEvent(ev);
-
-        boolean ret = false;
-        float x = ev.getX();
-        float y = ev.getY();
-
-        final int action = ev.getAction();
-
-        switch (action & MotionEvent.ACTION_MASK) {
-        case MotionEvent.ACTION_DOWN: {
-            mRender.onActionDown(x, y);
-            mActivePointerId = ev.getPointerId(0);
-            ret = true;
-            break;
-        }
-        case MotionEvent.ACTION_MOVE: {
-            if (!mScaleDetector.isInProgress()) {
-                mRender.onActionMove(x, y);
-            }
-            mRender.onActionDown(x, y);
-            ret = true;
-            break;
-        }
-
-        case MotionEvent.ACTION_UP: {
-            mActivePointerId = INVALID_POINTER_ID;
-            break;
-        }
-
-        case MotionEvent.ACTION_CANCEL: {
-            mActivePointerId = INVALID_POINTER_ID;
-            break;
-        }
-
-        case MotionEvent.ACTION_POINTER_UP: {
-            final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
-                    >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
-            final int pointerId = ev.getPointerId(pointerIndex);
-            if (pointerId == mActivePointerId) {
-                // This was our active pointer going up. Choose a new
-                // active pointer and adjust accordingly.
-                final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
-                x = ev.getX(newPointerIndex);
-                y = ev.getY(newPointerIndex);
-                mRender.onActionDown(x, y);
-                mActivePointerId = ev.getPointerId(newPointerIndex);
-            }
-            break;
-        }
-        }
-
-        return ret;
-    }
-
-    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
-        @Override
-        public boolean onScale(ScaleGestureDetector detector) {
-            mRender.onActionScale(detector.getScaleFactor());
-            return true;
-        }
-    }
-
-    public void onSensorChanged(SensorEvent event) {
-        // we received a sensor event. it is a good practice to check
-        // that we received the proper event
-        if (mUseSensor) {
-            if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
-                // convert the rotation-vector to a 4x4 matrix. the matrix
-                // is interpreted by Open GL as the inverse of the
-                // rotation-vector, which is what we want.
-                SensorManager.getRotationMatrixFromVector(
-                        mRotationMatrix , event.values);
-
-                if (mRender != null) {
-                    mRender.onPostureChanged(new Matrix4f(mRotationMatrix));
-                }
-            }
-        }
-    }
-
-    public void onAccuracyChanged(Sensor sensor, int accuracy) {
-    }
-
-    public void toggleSensor() {
-        mUseSensor = !mUseSensor;
-        if (mUseSensor == false) {
-            mRender.onPostureChanged(mIdentityMatrix);
-        }
-    }
-}
diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/scenegraph.rs b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/scenegraph.rs
deleted file mode 100644
index 5c5b1c9..0000000
--- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/scenegraph.rs
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright (C) 2009 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.modelviewer)
-
-#include "rs_graphics.rsh"
-#include "transform_def.rsh"
-
-rs_program_vertex gPVBackground;
-rs_program_fragment gPFBackground;
-
-rs_allocation gTGrid;
-rs_mesh gTestMesh;
-
-rs_program_store gPFSBackground;
-
-float gRotate;
-
-rs_font gItalic;
-rs_allocation gTextAlloc;
-
-rs_script gTransformRS;
-
-SgTransform *gGroup;
-SgTransform *gRobot1;
-int gRobot1Index;
-SgTransform *gRobot2;
-int gRobot2Index;
-
-SgTransform *gRootNode;
-
-void init() {
-    gRotate = 0.0f;
-}
-
-int root(void) {
-
-    gGroup->transforms[1].w += 0.5f;
-    gGroup->isDirty = 1;
-
-    SgTransform *robot1Ptr = gRobot1 + gRobot1Index;
-
-    robot1Ptr->transforms[1].w -= 1.5f;
-    robot1Ptr->isDirty = 1;
-
-    SgTransform *robot2Ptr = gRobot2 + gRobot2Index;
-    robot2Ptr->transforms[1].w += 2.5f;
-    robot2Ptr->isDirty = 1;
-
-    rsForEach(gTransformRS, gRootNode->children, gRootNode->children);
-
-    rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f);
-    rsgClearDepth(1.0f);
-
-    rsgBindProgramVertex(gPVBackground);
-    rs_matrix4x4 proj;
-    float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
-    rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f);
-    rsgProgramVertexLoadProjectionMatrix(&proj);
-
-    rsgBindProgramFragment(gPFBackground);
-    rsgBindProgramStore(gPFSBackground);
-    rsgBindTexture(gPFBackground, 0, gTGrid);
-
-    rsgProgramVertexLoadModelMatrix(&robot1Ptr->globalMat);
-    rsgDrawMesh(gTestMesh);
-
-    rsgProgramVertexLoadModelMatrix(&robot2Ptr->globalMat);
-    rsgDrawMesh(gTestMesh);
-
-    //color(0.3f, 0.3f, 0.3f, 1.0f);
-    rsgDrawText("Renderscript transform test", 30, 695);
-
-    rsgBindFont(gItalic);
-    rsgDrawText(gTextAlloc, 30, 730);
-
-    return 10;
-}
diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs
deleted file mode 100644
index d3dd5b9..0000000
--- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs
+++ /dev/null
@@ -1,172 +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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.modelviewer)
-
-#include "rs_graphics.rsh"
-
-rs_program_vertex gPVBackground;
-rs_program_fragment gPFBackground;
-
-rs_allocation gTGrid;
-
-rs_program_store gPFSBackground;
-
-rs_font gItalic;
-rs_allocation gTextAlloc;
-
-rs_matrix4x4 gPostureMatrix;
-
-typedef struct MeshInfo {
-    rs_mesh mMesh;
-    int mNumIndexSets;
-    float3 bBoxMin;
-    float3 bBoxMax;
-} MeshInfo_t;
-
-MeshInfo_t *gMeshes;
-
-static float3 gLookAt;
-
-static float gRotateX;
-static float gRotateY;
-static float gZoom;
-
-static float gLastX;
-static float gLastY;
-
-static float3 toFloat3(float x, float y, float z) {
-    float3 f;
-    f.x = x;
-    f.y = y;
-    f.z = z;
-    return f;
-}
-
-void onActionDown(float x, float y) {
-    gLastX = x;
-    gLastY = y;
-}
-
-void onActionScale(float scale) {
-
-    gZoom *= 1.0f / scale;
-    gZoom = max(0.1f, min(gZoom, 500.0f));
-}
-
-void onActionMove(float x, float y) {
-    float dx = gLastX - x;
-    float dy = gLastY - y;
-
-    if (fabs(dy) <= 2.0f) {
-        dy = 0.0f;
-    }
-    if (fabs(dx) <= 2.0f) {
-        dx = 0.0f;
-    }
-
-    gRotateY -= dx;
-    if (gRotateY > 360) {
-        gRotateY -= 360;
-    }
-    if (gRotateY < 0) {
-        gRotateY += 360;
-    }
-
-    gRotateX -= dy;
-    gRotateX = min(gRotateX, 80.0f);
-    gRotateX = max(gRotateX, -80.0f);
-
-    gLastX = x;
-    gLastY = y;
-}
-
-void init() {
-    gRotateX = 0.0f;
-    gRotateY = 0.0f;
-    gZoom = 50.0f;
-    gLookAt = 0.0f;
-    rsMatrixLoadIdentity(&gPostureMatrix);
-}
-
-void updateMeshInfo() {
-    rs_allocation allMeshes = rsGetAllocation(gMeshes);
-    int size = rsAllocationGetDimX(allMeshes);
-    gLookAt = 0.0f;
-    float minX, minY, minZ, maxX, maxY, maxZ;
-    for (int i = 0; i < size; i++) {
-        MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i);
-        rsgMeshComputeBoundingBox(info->mMesh,
-                                  &minX, &minY, &minZ,
-                                  &maxX, &maxY, &maxZ);
-        info->bBoxMin = toFloat3(minX, minY, minZ);
-        info->bBoxMax = toFloat3(maxX, maxY, maxZ);
-        gLookAt += (info->bBoxMin + info->bBoxMax)*0.5f;
-    }
-    gLookAt = gLookAt / (float)size;
-}
-
-static void renderAllMeshes() {
-    rs_allocation allMeshes = rsGetAllocation(gMeshes);
-    int size = rsAllocationGetDimX(allMeshes);
-    gLookAt = 0.0f;
-    for (int i = 0; i < size; i++) {
-        MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i);
-        rsgDrawMesh(info->mMesh);
-    }
-}
-
-void drawDescription() {
-    uint height = rsgGetHeight();
-    int left = 0, right = 0, top = 0, bottom = 0;
-
-    rsgBindFont(gItalic);
-
-    rsgMeasureText(gTextAlloc, &left, &right, &top, &bottom);
-    rsgDrawText(gTextAlloc, 2 -left, height - 2 + bottom);
-}
-
-int root(void) {
-
-    rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f);
-    rsgClearDepth(1.0f);
-
-    rsgBindProgramVertex(gPVBackground);
-    rs_matrix4x4 proj;
-    float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
-    rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 100.0f);
-    rsgProgramVertexLoadProjectionMatrix(&proj);
-
-    rsgBindProgramFragment(gPFBackground);
-    rsgBindProgramStore(gPFSBackground);
-    rsgBindTexture(gPFBackground, 0, gTGrid);
-
-    rs_matrix4x4 matrix;
-    rsMatrixLoadIdentity(&matrix);
-    // Position our models on the screen
-    rsMatrixTranslate(&matrix, gLookAt.x, gLookAt.y, gLookAt.z - gZoom);
-    rsMatrixMultiply(&matrix, &gPostureMatrix);
-    rsMatrixRotate(&matrix, gRotateX, 1.0f, 0.0f, 0.0f);
-    rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f);
-
-    rsgProgramVertexLoadModelMatrix(&matrix);
-
-    renderAllMeshes();
-
-    drawDescription();
-
-    return 0;
-}
diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/transform.rs b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/transform.rs
deleted file mode 100644
index 85c0630..0000000
--- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/transform.rs
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright (C) 2009 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.modelviewer)
-
-#include "transform_def.rsh"
-
-rs_script transformScript;
-
-typedef struct {
-    int changed;
-    rs_matrix4x4 *mat;
-} ParentData;
-
-static void appendTransformation(int type, float4 data, rs_matrix4x4 *mat) {
-    rs_matrix4x4 temp;
-
-    switch (type) {
-    case TRANSFORM_TRANSLATE:
-        rsMatrixLoadTranslate(&temp, data.x, data.y, data.z);
-        break;
-    case TRANSFORM_ROTATE:
-        rsMatrixLoadRotate(&temp, data.w, data.x, data.y, data.z);
-        break;
-    case TRANSFORM_SCALE:
-        rsMatrixLoadScale(&temp, data.x, data.y, data.z);
-        break;
-    }
-    rsMatrixMultiply(mat, &temp);
-}
-
-void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
-
-    SgTransform *data = (SgTransform *)v_out;
-    const ParentData *parent = (const ParentData *)usrData;
-
-    //rsDebug("Transform data", (int)data);
-    //rsDebug("Entering parent", (int)parent);
-
-    rs_matrix4x4 *localMat = &data->localMat;
-    rs_matrix4x4 *globalMat = &data->globalMat;
-
-    ParentData toChild;
-    toChild.changed = 0;
-    toChild.mat = globalMat;
-
-    //rsDebug("Transform is dirty", data->isDirty);
-
-    // Refresh matrices if dirty
-    if (data->isDirty) {
-        data->isDirty = 0;
-        toChild.changed = 1;
-
-        // Reset our local matrix
-        rsMatrixLoadIdentity(localMat);
-
-        for (int i = 0; i < 16; i ++) {
-            if (data->transformTypes[i] == TRANSFORM_NONE) {
-                break;
-            }
-            //rsDebug("Transform adding transformation", transformTypes[i]);
-            appendTransformation(data->transformTypes[i], data->transforms[i], localMat);
-        }
-    }
-
-    //rsDebug("Transform checking parent", (int)0);
-
-    if (parent) {
-        if (parent->changed) {
-            toChild.changed = 1;
-
-            rsMatrixLoad(globalMat, parent->mat);
-            rsMatrixMultiply(globalMat, localMat);
-        }
-    } else {
-        rsMatrixLoad(globalMat, localMat);
-    }
-
-    //rsDebug("Transform calling self with child ", (int)data->children.p);
-    if (data->children.p) {
-        rsForEach(transformScript, data->children, data->children, (void*)&toChild, sizeof(toChild));
-    }
-}
diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/transform_def.rsh b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/transform_def.rsh
deleted file mode 100644
index 24a36c1..0000000
--- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/transform_def.rsh
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (C) 2009 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.modelviewer)
-
-#define TRANSFORM_NONE 0
-#define TRANSFORM_TRANSLATE 1
-#define TRANSFORM_ROTATE 2
-#define TRANSFORM_SCALE 3
-
-typedef struct __attribute__((packed, aligned(4))) SgTransform {
-    rs_matrix4x4 globalMat;
-    rs_matrix4x4 localMat;
-
-    float4 transforms[16];
-    int transformTypes[16];
-
-    int isDirty;
-
-    rs_allocation children;
-
-} SgTransform;
diff --git a/tests/RenderScriptTests/PerfTest/Android.mk b/tests/RenderScriptTests/PerfTest/Android.mk
deleted file mode 100644
index e9ee771..0000000
--- a/tests/RenderScriptTests/PerfTest/Android.mk
+++ /dev/null
@@ -1,31 +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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
-
-LOCAL_SDK_VERSION := 17
-
-LOCAL_PACKAGE_NAME := PerfTest
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/PerfTest/AndroidManifest.xml b/tests/RenderScriptTests/PerfTest/AndroidManifest.xml
deleted file mode 100644
index cc60396..0000000
--- a/tests/RenderScriptTests/PerfTest/AndroidManifest.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.perftest">
-    
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-    
-    <uses-sdk android:minSdkVersion="11" />
-    <application android:label="PerfTest"
-      android:icon="@drawable/test_pattern">
-        <uses-library android:name="android.test.runner" />
-        <activity android:name="RsBench"
-                  android:label="RsBenchmark">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-      </application>
-
-      <instrumentation android:name=".RsPerfTestRunner"
-        android:targetPackage="com.android.perftest"
-        android:label="Test runner for RsBench tests"
-      />
-</manifest>
diff --git a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/checker.png b/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/checker.png
deleted file mode 100644
index b631e1e..0000000
--- a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/checker.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/data.png b/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/data.png
deleted file mode 100644
index 8e34714..0000000
--- a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/data.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/flares.png b/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/flares.png
deleted file mode 100644
index 3a5c970..0000000
--- a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/flares.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/globe.png b/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/globe.png
deleted file mode 100644
index f9d6172..0000000
--- a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/globe.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/leaf.png b/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/leaf.png
deleted file mode 100644
index 3cd3775..0000000
--- a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/leaf.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/light1.jpg b/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/light1.jpg
deleted file mode 100644
index 2f2f10e..0000000
--- a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/light1.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/space.jpg b/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/space.jpg
deleted file mode 100644
index b61f6a3..0000000
--- a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/space.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/test_pattern.png b/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/test_pattern.png
deleted file mode 100644
index e7d1455..0000000
--- a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/test_pattern.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/torusmap.png b/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/torusmap.png
deleted file mode 100644
index 1e08f3b..0000000
--- a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/torusmap.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/PerfTest/res/menu/loader_menu.xml b/tests/RenderScriptTests/PerfTest/res/menu/loader_menu.xml
deleted file mode 100644
index 59a251d..0000000
--- a/tests/RenderScriptTests/PerfTest/res/menu/loader_menu.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-* Copyright (C) 2011 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*      http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
--->
-
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:id="@+id/benchmark_all"
-          android:title="@string/benchmark_all" />
-    <item android:id="@+id/benchmark_one"
-          android:title="@string/benchmark_one" />
-    <item android:id="@+id/debug_mode"
-          android:title="@string/debug_mode" />
-</menu>
-
diff --git a/tests/RenderScriptTests/PerfTest/res/raw/multitexf.glsl b/tests/RenderScriptTests/PerfTest/res/raw/multitexf.glsl
deleted file mode 100644
index e492a47..0000000
--- a/tests/RenderScriptTests/PerfTest/res/raw/multitexf.glsl
+++ /dev/null
@@ -1,13 +0,0 @@
-varying vec2 varTex0;
-
-void main() {
-   vec2 t0 = varTex0.xy;
-   lowp vec4 col0 = texture2D(UNI_Tex0, t0).rgba;
-   lowp vec4 col1 = texture2D(UNI_Tex1, t0*4.0).rgba;
-   lowp vec4 col2 = texture2D(UNI_Tex2, t0).rgba;
-   col0.xyz = col0.xyz*col1.xyz*1.5;
-   col0.xyz = mix(col0.xyz, col2.xyz, col2.w);
-   col0.w = 0.5;
-   gl_FragColor = col0;
-}
-
diff --git a/tests/RenderScriptTests/PerfTest/res/raw/shader2f.glsl b/tests/RenderScriptTests/PerfTest/res/raw/shader2f.glsl
deleted file mode 100644
index 5fc05f1..0000000
--- a/tests/RenderScriptTests/PerfTest/res/raw/shader2f.glsl
+++ /dev/null
@@ -1,29 +0,0 @@
-varying vec3 varWorldPos;
-varying vec3 varWorldNormal;
-varying vec2 varTex0;
-
-void main() {
-
-   vec3 V = normalize(-varWorldPos.xyz);
-   vec3 worldNorm = normalize(varWorldNormal);
-
-   vec3 light0Vec = normalize(UNI_light0_Posision.xyz - varWorldPos);
-   vec3 light0R = -reflect(light0Vec, worldNorm);
-   float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0) * UNI_light0_Diffuse;
-   float light0Spec = clamp(dot(light0R, V), 0.001, 1.0);
-   float light0_Specular = pow(light0Spec, UNI_light0_CosinePower) * UNI_light0_Specular;
-
-   vec3 light1Vec = normalize(UNI_light1_Posision.xyz - varWorldPos);
-   vec3 light1R = reflect(light1Vec, worldNorm);
-   float light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0) * UNI_light1_Diffuse;
-   float light1Spec = clamp(dot(light1R, V), 0.001, 1.0);
-   float light1_Specular = pow(light1Spec, UNI_light1_CosinePower) * UNI_light1_Specular;
-
-   vec2 t0 = varTex0.xy;
-   lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
-   col.xyz = col.xyz * (light0_Diffuse * UNI_light0_DiffuseColor.xyz + light1_Diffuse * UNI_light1_DiffuseColor.xyz);
-   col.xyz += light0_Specular * UNI_light0_SpecularColor.xyz;
-   col.xyz += light1_Specular * UNI_light1_SpecularColor.xyz;
-   gl_FragColor = col;
-}
-
diff --git a/tests/RenderScriptTests/PerfTest/res/raw/shader2movev.glsl b/tests/RenderScriptTests/PerfTest/res/raw/shader2movev.glsl
deleted file mode 100644
index a2c807e..0000000
--- a/tests/RenderScriptTests/PerfTest/res/raw/shader2movev.glsl
+++ /dev/null
@@ -1,21 +0,0 @@
-varying vec3 varWorldPos;
-varying vec3 varWorldNormal;
-varying vec2 varTex0;
-
-// This is where actual shader code begins
-void main() {
-   vec4 objPos = ATTRIB_position;
-   vec3 oldPos = objPos.xyz;
-   objPos.xyz += 0.1*sin(objPos.xyz*2.0 + UNI_time);
-   objPos.xyz += 0.05*sin(objPos.xyz*4.0 + UNI_time*0.5);
-   objPos.xyz += 0.02*sin(objPos.xyz*7.0 + UNI_time*0.75);
-   vec4 worldPos = UNI_model * objPos;
-   gl_Position = UNI_proj * worldPos;
-
-   mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
-   vec3 worldNorm = model3 * (ATTRIB_normal + oldPos - objPos.xyz);
-
-   varWorldPos = worldPos.xyz;
-   varWorldNormal = worldNorm;
-   varTex0 = ATTRIB_texture0;
-}
diff --git a/tests/RenderScriptTests/PerfTest/res/raw/shader2v.glsl b/tests/RenderScriptTests/PerfTest/res/raw/shader2v.glsl
deleted file mode 100644
index e6885a3..0000000
--- a/tests/RenderScriptTests/PerfTest/res/raw/shader2v.glsl
+++ /dev/null
@@ -1,17 +0,0 @@
-varying vec3 varWorldPos;
-varying vec3 varWorldNormal;
-varying vec2 varTex0;
-
-// This is where actual shader code begins
-void main() {
-   vec4 objPos = ATTRIB_position;
-   vec4 worldPos = UNI_model * objPos;
-   gl_Position = UNI_proj * worldPos;
-
-   mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
-   vec3 worldNorm = model3 * ATTRIB_normal;
-
-   varWorldPos = worldPos.xyz;
-   varWorldNormal = worldNorm;
-   varTex0 = ATTRIB_texture0;
-}
diff --git a/tests/RenderScriptTests/PerfTest/res/raw/shaderf.glsl b/tests/RenderScriptTests/PerfTest/res/raw/shaderf.glsl
deleted file mode 100644
index d56e203..0000000
--- a/tests/RenderScriptTests/PerfTest/res/raw/shaderf.glsl
+++ /dev/null
@@ -1,16 +0,0 @@
-
-varying lowp float light0_Diffuse;
-varying lowp float light0_Specular;
-varying lowp float light1_Diffuse;
-varying lowp float light1_Specular;
-varying vec2 varTex0;
-
-void main() {
-   vec2 t0 = varTex0.xy;
-   lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
-   col.xyz = col.xyz * (light0_Diffuse * UNI_light0_DiffuseColor.xyz + light1_Diffuse * UNI_light1_DiffuseColor.xyz);
-   col.xyz += light0_Specular * UNI_light0_SpecularColor.xyz;
-   col.xyz += light1_Specular * UNI_light1_SpecularColor.xyz;
-   gl_FragColor = col;
-}
-
diff --git a/tests/RenderScriptTests/PerfTest/res/raw/shaderv.glsl b/tests/RenderScriptTests/PerfTest/res/raw/shaderv.glsl
deleted file mode 100644
index f7d01de..0000000
--- a/tests/RenderScriptTests/PerfTest/res/raw/shaderv.glsl
+++ /dev/null
@@ -1,30 +0,0 @@
-varying float light0_Diffuse;
-varying float light0_Specular;
-varying float light1_Diffuse;
-varying float light1_Specular;
-varying vec2 varTex0;
-
-// This is where actual shader code begins
-void main() {
-   vec4 worldPos = UNI_model * ATTRIB_position;
-   gl_Position = UNI_proj * worldPos;
-
-   mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
-   vec3 worldNorm = model3 * ATTRIB_normal;
-   vec3 V = normalize(-worldPos.xyz);
-
-   vec3 light0Vec = normalize(UNI_light0_Posision.xyz - worldPos.xyz);
-   vec3 light0R = -reflect(light0Vec, worldNorm);
-   light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0) * UNI_light0_Diffuse;
-   float light0Spec = clamp(dot(light0R, V), 0.001, 1.0);
-   light0_Specular = pow(light0Spec, UNI_light0_CosinePower) * UNI_light0_Specular;
-
-   vec3 light1Vec = normalize(UNI_light1_Posision.xyz - worldPos.xyz);
-   vec3 light1R = reflect(light1Vec, worldNorm);
-   light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0) * UNI_light1_Diffuse;
-   float light1Spec = clamp(dot(light1R, V), 0.001, 1.0);
-   light1_Specular = pow(light1Spec, UNI_light1_CosinePower) * UNI_light1_Specular;
-
-   gl_PointSize = 1.0;
-   varTex0 = ATTRIB_texture0;
-}
diff --git a/tests/RenderScriptTests/PerfTest/res/raw/singletexf.glsl b/tests/RenderScriptTests/PerfTest/res/raw/singletexf.glsl
deleted file mode 100644
index 83dfc7f..0000000
--- a/tests/RenderScriptTests/PerfTest/res/raw/singletexf.glsl
+++ /dev/null
@@ -1,8 +0,0 @@
-varying vec2 varTex0;
-
-void main() {
-   lowp vec3 col0 = texture2D(UNI_Tex0, varTex0).rgb;
-   gl_FragColor.xyz = col0;
-   gl_FragColor.w = 0.5;
-}
-
diff --git a/tests/RenderScriptTests/PerfTest/res/raw/singletexfm.glsl b/tests/RenderScriptTests/PerfTest/res/raw/singletexfm.glsl
deleted file mode 100644
index 656961c..0000000
--- a/tests/RenderScriptTests/PerfTest/res/raw/singletexfm.glsl
+++ /dev/null
@@ -1,8 +0,0 @@
-varying vec2 varTex0;
-
-void main() {
-   lowp vec3 col0 = texture2D(UNI_Tex0, varTex0).rgb;
-   gl_FragColor.xyz = col0 * UNI_modulate.rgb;
-   gl_FragColor.w = UNI_modulate.a;
-}
-
diff --git a/tests/RenderScriptTests/PerfTest/res/raw/torus.a3d b/tests/RenderScriptTests/PerfTest/res/raw/torus.a3d
deleted file mode 100644
index 0322b01..0000000
--- a/tests/RenderScriptTests/PerfTest/res/raw/torus.a3d
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/PerfTest/res/values/strings.xml b/tests/RenderScriptTests/PerfTest/res/values/strings.xml
deleted file mode 100644
index ce9819e..0000000
--- a/tests/RenderScriptTests/PerfTest/res/values/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-* Copyright (C) 2011 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*      http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <skip />
-    <string name="benchmark_all">Benchmark All</string>
-    <string name="benchmark_one">Benchmark One</string>
-    <string name="debug_mode">Debug Mode</string>
-</resources>
-
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
deleted file mode 100644
index 41f664a..0000000
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.perftest;
-
-import android.os.Environment;
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-
-
-import android.util.Log;
-
-
-public class FillTest implements RsBenchBaseTest{
-
-    private static final String TAG = "FillTest";
-    private RenderScriptGL mRS;
-    private Resources mRes;
-
-    // Custom shaders
-    private ProgramFragment mProgFragmentMultitex;
-    private ProgramFragment mProgFragmentSingletex;
-    private ProgramFragment mProgFragmentSingletexModulate;
-    private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
-    int mBenchmarkDimX;
-    int mBenchmarkDimY;
-
-    private ScriptC_fill_test mFillScript;
-    ScriptField_TestScripts_s.Item[] mTests;
-    ScriptField_FillTestFragData_s mFragData;
-
-    private final String[] mNames = {
-        "Fill screen 10x singletexture",
-        "Fill screen 10x 3tex multitexture",
-        "Fill screen 10x blended singletexture",
-        "Fill screen 10x blended 3tex multitexture",
-        "Fill screen 3x modulate blended singletexture",
-        "Fill screen 1x modulate blended singletexture",
-    };
-
-    public FillTest() {
-        mOptionsARGB.inScaled = false;
-        mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888;
-        mBenchmarkDimX = 1280;
-        mBenchmarkDimY = 720;
-    }
-
-    void addTest(int index, int testId, int blend, int quadCount) {
-        mTests[index] = new ScriptField_TestScripts_s.Item();
-        mTests[index].testScript = mFillScript;
-        mTests[index].testName = Allocation.createFromString(mRS,
-                                                             mNames[index],
-                                                             Allocation.USAGE_SCRIPT);
-        mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS,
-                                                                      mNames[index],
-                                                                      Allocation.USAGE_SCRIPT);
-
-        ScriptField_FillTestData_s.Item dataItem = new ScriptField_FillTestData_s.Item();
-        dataItem.testId = testId;
-        dataItem.blend = blend;
-        dataItem.quadCount = quadCount;
-        ScriptField_FillTestData_s testData = new ScriptField_FillTestData_s(mRS, 1);
-        testData.set(dataItem, 0, true);
-        mTests[index].testData = testData.getAllocation();
-    }
-
-    public boolean init(RenderScriptGL rs, Resources res) {
-        mRS = rs;
-        mRes = res;
-        initCustomShaders();
-        initFillScript();
-        mTests = new ScriptField_TestScripts_s.Item[mNames.length];
-
-        int index = 0;
-
-        addTest(index++, 1 /*testId*/, 0 /*blend*/, 10 /*quadCount*/);
-        addTest(index++, 0 /*testId*/, 0 /*blend*/, 10 /*quadCount*/);
-        addTest(index++, 1 /*testId*/, 1 /*blend*/, 10 /*quadCount*/);
-        addTest(index++, 0 /*testId*/, 1 /*blend*/, 10 /*quadCount*/);
-        addTest(index++, 2 /*testId*/, 1 /*blend*/, 3 /*quadCount*/);
-        addTest(index++, 2 /*testId*/, 1 /*blend*/, 1 /*quadCount*/);
-
-        return true;
-    }
-
-    public ScriptField_TestScripts_s.Item[] getTests() {
-        return mTests;
-    }
-
-    public String[] getTestNames() {
-        return mNames;
-    }
-
-    private void initCustomShaders() {
-        ProgramFragment.Builder pfbCustom = new ProgramFragment.Builder(mRS);
-        pfbCustom.setShader(mRes, R.raw.multitexf);
-        for (int texCount = 0; texCount < 3; texCount ++) {
-            pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
-        }
-        mProgFragmentMultitex = pfbCustom.create();
-
-        pfbCustom = new ProgramFragment.Builder(mRS);
-        pfbCustom.setShader(mRes, R.raw.singletexf);
-        pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
-        mProgFragmentSingletex = pfbCustom.create();
-
-        pfbCustom = new ProgramFragment.Builder(mRS);
-        pfbCustom.setShader(mRes, R.raw.singletexfm);
-        pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
-        mFragData = new ScriptField_FillTestFragData_s(mRS, 1);
-        pfbCustom.addConstant(mFragData.getType());
-        mProgFragmentSingletexModulate = pfbCustom.create();
-        mProgFragmentSingletexModulate.bindConstants(mFragData.getAllocation(), 0);
-    }
-
-    private Allocation loadTextureARGB(int id) {
-        Bitmap b = BitmapFactory.decodeResource(mRes, id, mOptionsARGB);
-        return Allocation.createFromBitmap(mRS, b,
-                Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
-                Allocation.USAGE_GRAPHICS_TEXTURE);
-    }
-
-    private Allocation loadTextureRGB(int id) {
-        return Allocation.createFromBitmapResource(mRS, mRes, id,
-                Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
-                Allocation.USAGE_GRAPHICS_TEXTURE);
-    }
-
-    void initFillScript() {
-        mFillScript = new ScriptC_fill_test(mRS, mRes, R.raw.fill_test);
-
-        ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
-        ProgramVertexFixedFunction progVertex = pvb.create();
-        ProgramVertexFixedFunction.Constants PVA = new ProgramVertexFixedFunction.Constants(mRS);
-        ((ProgramVertexFixedFunction)progVertex).bindConstants(PVA);
-        Matrix4f proj = new Matrix4f();
-        proj.loadOrthoWindow(mBenchmarkDimX, mBenchmarkDimY);
-        PVA.setProjection(proj);
-        mFillScript.set_gProgVertex(progVertex);
-
-        mFillScript.set_gProgFragmentTexture(mProgFragmentSingletex);
-        mFillScript.set_gProgFragmentTextureModulate(mProgFragmentSingletexModulate);
-        mFillScript.set_gProgFragmentMultitex(mProgFragmentMultitex);
-        mFillScript.set_gProgStoreBlendNone(ProgramStore.BLEND_NONE_DEPTH_NONE(mRS));
-        mFillScript.set_gProgStoreBlendAlpha(ProgramStore.BLEND_ALPHA_DEPTH_NONE(mRS));
-
-        mFillScript.set_gLinearClamp(Sampler.CLAMP_LINEAR(mRS));
-        mFillScript.set_gLinearWrap(Sampler.WRAP_LINEAR(mRS));
-        mFillScript.set_gTexTorus(loadTextureRGB(R.drawable.torusmap));
-        mFillScript.set_gTexOpaque(loadTextureRGB(R.drawable.data));
-        mFillScript.set_gTexTransparent(loadTextureARGB(R.drawable.leaf));
-        mFillScript.set_gTexChecker(loadTextureRGB(R.drawable.checker));
-
-        mFillScript.bind_gFragData(mFragData);
-    }
-}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/MeshTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/MeshTest.java
deleted file mode 100644
index cdb4435..0000000
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/MeshTest.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.perftest;
-
-import android.os.Environment;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.renderscript.*;
-import android.renderscript.Element.DataKind;
-import android.renderscript.Element.DataType;
-import android.renderscript.Allocation.MipmapControl;
-import android.renderscript.Program.TextureType;
-import android.renderscript.RenderScript.RSMessageHandler;
-import android.renderscript.Mesh.Primitive;
-import android.renderscript.Matrix4f;
-import android.renderscript.ProgramVertexFixedFunction;
-
-import android.util.Log;
-
-
-public class MeshTest implements RsBenchBaseTest{
-
-    private static final String TAG = "MeshTest";
-    private RenderScriptGL mRS;
-    private Resources mRes;
-
-    int mBenchmarkDimX;
-    int mBenchmarkDimY;
-
-    private Mesh m10by10Mesh;
-    private Mesh m100by100Mesh;
-    private Mesh mWbyHMesh;
-
-    private ScriptC_mesh_test mGeoScript;
-
-    private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
-
-    ScriptField_TestScripts_s.Item[] mTests;
-
-    private final String[] mNames = {
-        "Full screen mesh 10 by 10",
-        "Full screen mesh 100 by 100",
-        "Full screen mesh W / 4 by H / 4"
-    };
-
-    public MeshTest() {
-        mBenchmarkDimX = 1280;
-        mBenchmarkDimY = 720;
-    }
-
-    void addTest(int index, int meshNum) {
-        mTests[index] = new ScriptField_TestScripts_s.Item();
-        mTests[index].testScript = mGeoScript;
-        mTests[index].testName = Allocation.createFromString(mRS,
-                                                             mNames[index],
-                                                             Allocation.USAGE_SCRIPT);
-        mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS,
-                                                                      mNames[index],
-                                                                      Allocation.USAGE_SCRIPT);
-
-        ScriptField_MeshTestData_s.Item dataItem = new ScriptField_MeshTestData_s.Item();
-        dataItem.meshNum = meshNum;
-        ScriptField_MeshTestData_s testData = new ScriptField_MeshTestData_s(mRS, 1);
-        testData.set(dataItem, 0, true);
-        mTests[index].testData = testData.getAllocation();
-    }
-
-    public boolean init(RenderScriptGL rs, Resources res) {
-        mRS = rs;
-        mRes = res;
-        initGeoScript();
-        mTests = new ScriptField_TestScripts_s.Item[mNames.length];
-
-        int index = 0;
-        addTest(index++, 0 /*meshNum*/);
-        addTest(index++, 1 /*meshNum*/);
-        addTest(index++, 2 /*meshNum*/);
-
-        return true;
-    }
-
-    public ScriptField_TestScripts_s.Item[] getTests() {
-        return mTests;
-    }
-
-    public String[] getTestNames() {
-        return mNames;
-    }
-
-    private Mesh getMbyNMesh(float width, float height, int wResolution, int hResolution) {
-
-        Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS,
-                                           2, Mesh.TriangleMeshBuilder.TEXTURE_0);
-
-        for (int y = 0; y <= hResolution; y++) {
-            final float normalizedY = (float)y / hResolution;
-            final float yOffset = (normalizedY - 0.5f) * height;
-            for (int x = 0; x <= wResolution; x++) {
-                float normalizedX = (float)x / wResolution;
-                float xOffset = (normalizedX - 0.5f) * width;
-                tmb.setTexture((float)x % 2, (float)y % 2);
-                tmb.addVertex(xOffset, yOffset);
-             }
-        }
-
-        for (int y = 0; y < hResolution; y++) {
-            final int curY = y * (wResolution + 1);
-            final int belowY = (y + 1) * (wResolution + 1);
-            for (int x = 0; x < wResolution; x++) {
-                int curV = curY + x;
-                int belowV = belowY + x;
-                tmb.addTriangle(curV, belowV, curV + 1);
-                tmb.addTriangle(belowV, belowV + 1, curV + 1);
-            }
-        }
-
-        return tmb.create(true);
-    }
-
-    private Allocation loadTextureRGB(int id) {
-        return Allocation.createFromBitmapResource(mRS, mRes, id,
-                Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
-                Allocation.USAGE_GRAPHICS_TEXTURE);
-    }
-
-    void initGeoScript() {
-        mGeoScript = new ScriptC_mesh_test(mRS, mRes, R.raw.mesh_test);
-
-        ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
-        ProgramVertexFixedFunction progVertex = pvb.create();
-        ProgramVertexFixedFunction.Constants PVA = new ProgramVertexFixedFunction.Constants(mRS);
-        ((ProgramVertexFixedFunction)progVertex).bindConstants(PVA);
-        Matrix4f proj = new Matrix4f();
-        proj.loadOrthoWindow(mBenchmarkDimX, mBenchmarkDimY);
-        PVA.setProjection(proj);
-
-        mGeoScript.set_gProgVertex(progVertex);
-        ProgramFragmentFixedFunction.Builder texBuilder = new ProgramFragmentFixedFunction.Builder(mRS);
-        texBuilder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
-                              ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
-        mGeoScript.set_gProgFragmentTexture(texBuilder.create());
-        mGeoScript.set_gProgStoreBlendNone(ProgramStore.BLEND_NONE_DEPTH_NONE(mRS));
-
-        mGeoScript.set_gLinearClamp(Sampler.CLAMP_LINEAR(mRS));
-        mGeoScript.set_gTexOpaque(loadTextureRGB(R.drawable.data));
-
-        m10by10Mesh = getMbyNMesh(mBenchmarkDimX, mBenchmarkDimY, 10, 10);
-        m100by100Mesh = getMbyNMesh(mBenchmarkDimX, mBenchmarkDimY, 100, 100);
-        mWbyHMesh= getMbyNMesh(mBenchmarkDimX, mBenchmarkDimY, mBenchmarkDimX/4, mBenchmarkDimY/4);
-
-        mGeoScript.set_g10by10Mesh(m10by10Mesh);
-        mGeoScript.set_g100by100Mesh(m100by100Mesh);
-        mGeoScript.set_gWbyHMesh(mWbyHMesh);
-    }
-}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java
deleted file mode 100644
index 0dceafe..0000000
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.perftest;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-
-import android.app.Activity;
-import android.content.res.Configuration;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Settings.System;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MenuInflater;
-import android.view.View;
-import android.view.Window;
-import android.widget.Button;
-import android.widget.ListView;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.widget.Toast;
-
-import java.lang.Runtime;
-
-public class RsBench extends Activity {
-    private final String TAG = "RsBench";
-    public RsBenchView mView;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        int iterations = 0;
-        Intent intent = getIntent();
-        Uri uri = intent.getData();
-        if (uri != null) {
-            // when lauched from instrumentation
-            String scheme = uri.getScheme();
-            if ("iterations".equals(scheme)) {
-                iterations = Integer.parseInt(uri.getSchemeSpecificPart());
-            }
-        }
-        // Create our Preview view and set it as the content of our
-        // Activity
-        mView = new RsBenchView(this);
-        setContentView(mView);
-        mView.setLoops(iterations);
-    }
-
-    @Override
-    protected void onResume() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity loses focus
-        super.onResume();
-        mView.resume();
-    }
-
-    @Override
-    protected void onPause() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity loses focus
-        super.onPause();
-        mView.pause();
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        MenuInflater inflater = getMenuInflater();
-        inflater.inflate(R.menu.loader_menu, menu);
-        return true;
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        // Handle item selection
-        switch (item.getItemId()) {
-            case R.id.benchmark_all:
-                mView.setBenchmarkMode(-1);
-                mView.suspendRendering(false);
-                return true;
-            case R.id.benchmark_one:
-                mView.suspendRendering(true);
-                AlertDialog.Builder builder = new AlertDialog.Builder(this);
-                builder.setTitle("Pick a Test");
-                builder.setItems(mView.getTestNames(),
-                                 new DialogInterface.OnClickListener() {
-                    public void onClick(DialogInterface dialog, int item) {
-                        Toast.makeText(getApplicationContext(),
-                                       "Starting to benchmark: " + mView.getTestNames()[item],
-                                       Toast.LENGTH_SHORT).show();
-                        mView.setBenchmarkMode(item);
-                        mView.suspendRendering(false);
-                    }
-                });
-                builder.show();
-                return true;
-            case R.id.debug_mode:
-                mView.suspendRendering(true);
-                AlertDialog.Builder debugBuilder = new AlertDialog.Builder(this);
-                debugBuilder.setTitle("Pick a Test");
-                debugBuilder.setItems(mView.getTestNames(),
-                                 new DialogInterface.OnClickListener() {
-                    public void onClick(DialogInterface dialog, int item) {
-                        Toast.makeText(getApplicationContext(),
-                                       "Switching to: " + mView.getTestNames()[item],
-                                       Toast.LENGTH_SHORT).show();
-                        mView.setDebugMode(item);
-                        mView.suspendRendering(false);
-                    }
-                });
-                debugBuilder.show();
-                return true;
-            default:
-                return super.onOptionsItemSelected(item);
-        }
-    }
-}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchBaseTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchBaseTest.java
deleted file mode 100644
index a9e1777..0000000
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchBaseTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.perftest;
-import android.renderscript.*;
-import android.content.res.Resources;
-
-interface RsBenchBaseTest {
-    boolean init(RenderScriptGL rs, Resources res);
-
-    ScriptField_TestScripts_s.Item[] getTests();
-    String[] getTestNames();
-}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
deleted file mode 100644
index 4ac7dd5..0000000
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.perftest;
-
-import java.io.Writer;
-import java.io.BufferedWriter;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.OutputStream;
-
-import android.os.Environment;
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.renderscript.Element.DataKind;
-import android.renderscript.Element.DataType;
-import android.renderscript.Allocation.MipmapControl;
-import android.renderscript.Program.TextureType;
-import android.renderscript.RenderScript.RSMessageHandler;
-import android.renderscript.Sampler.Value;
-import android.renderscript.Mesh.Primitive;
-import android.renderscript.Matrix4f;
-import android.renderscript.ProgramVertexFixedFunction;
-
-import android.util.Log;
-
-
-public class RsBenchRS {
-
-    private static final String TAG = "RsBenchRS";
-    int mWidth;
-    int mHeight;
-    int mLoops;
-    int mCurrentLoop;
-
-    int mBenchmarkDimX;
-    int mBenchmarkDimY;
-
-    public RsBenchRS() {
-    }
-
-    public void init(RenderScriptGL rs, Resources res, int width, int height, int loops) {
-        mRS = rs;
-        mRes = res;
-        mWidth = width;
-        mHeight = height;
-        mMode = 0;
-        mLoops = loops;
-        mCurrentLoop = 0;
-        mBenchmarkDimX = 1280;
-        mBenchmarkDimY = 720;
-        initRS();
-    }
-
-    private boolean stopTest = false;
-
-    private Resources mRes;
-    private RenderScriptGL mRS;
-
-    private ProgramStore mProgStoreBlendNone;
-    private ProgramStore mProgStoreBlendAlpha;
-
-    private ProgramFragment mProgFragmentTexture;
-    private ProgramFragment mProgFragmentColor;
-
-    private ProgramVertex mProgVertex;
-    private ProgramVertexFixedFunction.Constants mPVA;
-    private ProgramVertexFixedFunction.Constants mPvProjectionAlloc;
-
-    private ScriptC_rsbench mScript;
-
-    ScriptField_TestScripts_s.Item[] mIndividualTests;
-
-    int mMode;
-
-    String[] mTestNames;
-    float[] mLocalTestResults;
-
-    static Allocation createZeroTerminatedAlloc(RenderScript rs,
-                                                String str,
-                                                int usage) {
-        byte[] allocArray = null;
-        try {
-            allocArray = str.getBytes("UTF-8");
-            byte[] allocArrayZero = new byte[allocArray.length + 1];
-            System.arraycopy(allocArray, 0, allocArrayZero, 0, allocArray.length);
-            allocArrayZero[allocArrayZero.length - 1] = '\0';
-            Allocation alloc = Allocation.createSized(rs, Element.U8(rs),
-                                                      allocArrayZero.length, usage);
-            alloc.copyFrom(allocArrayZero);
-            return alloc;
-        }
-        catch (Exception e) {
-            throw new RSRuntimeException("Could not convert string to utf-8.");
-        }
-
-    }
-
-    void appendTests(RsBenchBaseTest testSet) {
-        ScriptField_TestScripts_s.Item[] newTests = testSet.getTests();
-        if (mIndividualTests != null) {
-            ScriptField_TestScripts_s.Item[] combined;
-            combined = new ScriptField_TestScripts_s.Item[newTests.length + mIndividualTests.length];
-            System.arraycopy(mIndividualTests, 0, combined, 0, mIndividualTests.length);
-            System.arraycopy(newTests, 0, combined, mIndividualTests.length, newTests.length);
-            mIndividualTests = combined;
-        } else {
-            mIndividualTests = newTests;
-        }
-
-        String[] newNames = testSet.getTestNames();
-        if (mTestNames != null) {
-            String[] combinedNames;
-            combinedNames = new String[newNames.length + mTestNames.length];
-            System.arraycopy(mTestNames, 0, combinedNames, 0, mTestNames.length);
-            System.arraycopy(newNames, 0, combinedNames, mTestNames.length, newNames.length);
-            mTestNames = combinedNames;
-        } else {
-            mTestNames = newNames;
-        }
-    }
-
-    void createTestAllocation() {
-        int numTests = mIndividualTests.length;
-        mLocalTestResults = new float[numTests];
-        ScriptField_TestScripts_s allTests;
-        allTests = new ScriptField_TestScripts_s(mRS, numTests);
-        for (int i = 0; i < numTests; i ++) {
-            allTests.set(mIndividualTests[i], i, false);
-        }
-        allTests.copyAll();
-        mScript.bind_gTestScripts(allTests);
-    }
-
-    private void saveTestResults() {
-        String state = Environment.getExternalStorageState();
-        if (!Environment.MEDIA_MOUNTED.equals(state)) {
-            Log.v(TAG, "sdcard is read only");
-            return;
-        }
-        File sdCard = Environment.getExternalStorageDirectory();
-        if (!sdCard.canWrite()) {
-            Log.v(TAG, "ssdcard is read only");
-            return;
-        }
-
-        File resultFile = new File(sdCard, "rsbench_result" + mCurrentLoop + ".csv");
-        resultFile.setWritable(true, false);
-
-        try {
-            BufferedWriter results = new BufferedWriter(new FileWriter(resultFile));
-            for (int i = 0; i < mLocalTestResults.length; i ++) {
-                results.write(mTestNames[i] + ", " + mLocalTestResults[i] + ",\n");
-            }
-            results.close();
-            Log.v(TAG, "Saved results in: " + resultFile.getAbsolutePath());
-        } catch (IOException e) {
-            Log.v(TAG, "Unable to write result file " + e.getMessage());
-        }
-    }
-
-    /**
-     * Create a message handler to handle message sent from the script
-     */
-    protected RSMessageHandler mRsMessage = new RSMessageHandler() {
-        public void run() {
-            if (mID == mScript.get_RS_MSG_RESULTS_READY()) {
-                for (int i = 0; i < mLocalTestResults.length; i ++) {
-                    mLocalTestResults[i] = Float.intBitsToFloat(mData[i]);
-                }
-                saveTestResults();
-                if (mLoops > 0) {
-                    mCurrentLoop ++;
-                    mCurrentLoop = mCurrentLoop % mLoops;
-                }
-                return;
-
-            } else if (mID == mScript.get_RS_MSG_TEST_DONE()) {
-                synchronized(this) {
-                    stopTest = true;
-                    this.notifyAll();
-                }
-                return;
-            } else {
-                Log.v(TAG, "Perf test got unexpected message");
-                return;
-            }
-        }
-    };
-
-    /**
-     * Wait for message from the script
-     */
-    public boolean testIsFinished() {
-        synchronized(this) {
-            while (true) {
-                if (stopTest) {
-                    return true;
-                } else {
-                    try {
-                        this.wait(60*1000);
-                    } catch (InterruptedException e) {
-                        e.printStackTrace();
-                    }
-                }
-            }
-        }
-    }
-
-    private void initProgramFragment() {
-
-        ProgramFragmentFixedFunction.Builder texBuilder = new ProgramFragmentFixedFunction.Builder(mRS);
-        texBuilder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
-                              ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
-        mProgFragmentTexture = texBuilder.create();
-        mProgFragmentTexture.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0);
-
-        ProgramFragmentFixedFunction.Builder colBuilder = new ProgramFragmentFixedFunction.Builder(mRS);
-        colBuilder.setVaryingColor(false);
-        mProgFragmentColor = colBuilder.create();
-
-        mScript.set_gProgFragmentTexture(mProgFragmentTexture);
-    }
-
-    private void initProgramVertex() {
-        ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
-        mProgVertex = pvb.create();
-
-        mPVA = new ProgramVertexFixedFunction.Constants(mRS);
-        ((ProgramVertexFixedFunction)mProgVertex).bindConstants(mPVA);
-        Matrix4f proj = new Matrix4f();
-        proj.loadOrthoWindow(mBenchmarkDimX, mBenchmarkDimY);
-        mPVA.setProjection(proj);
-
-        mScript.set_gProgVertex(mProgVertex);
-    }
-
-    private int strlen(byte[] array) {
-        int count = 0;
-        while(count < array.length && array[count] != 0) {
-            count ++;
-        }
-        return count;
-    }
-
-    public void setDebugMode(int num) {
-        mScript.invoke_setDebugMode(num);
-    }
-
-    public void setBenchmarkMode(int benchNum) {
-        mScript.invoke_setBenchmarkMode(benchNum);
-    }
-
-    public void pause(boolean pause) {
-        mScript.set_gPauseRendering(pause);
-    }
-
-    private void initRS() {
-
-        mScript = new ScriptC_rsbench(mRS, mRes, R.raw.rsbench);
-        mRS.bindRootScript(mScript);
-
-        mRS.setMessageHandler(mRsMessage);
-
-        mScript.set_gMaxLoops(mLoops);
-
-        initProgramVertex();
-        initProgramFragment();
-        mScript.set_gFontSerif(Font.create(mRS, mRes, "serif", Font.Style.NORMAL, 8));
-
-        Type.Builder b = new Type.Builder(mRS, Element.RGBA_8888(mRS));
-        b.setX(mBenchmarkDimX).setY(mBenchmarkDimY);
-        Allocation offscreen = Allocation.createTyped(mRS,
-                                                      b.create(),
-                                                      Allocation.USAGE_GRAPHICS_TEXTURE |
-                                                      Allocation.USAGE_GRAPHICS_RENDER_TARGET);
-        mScript.set_gRenderBufferColor(offscreen);
-
-        b = new Type.Builder(mRS,
-                             Element.createPixel(mRS, DataType.UNSIGNED_16,
-                             DataKind.PIXEL_DEPTH));
-        b.setX(mBenchmarkDimX).setY(mBenchmarkDimY);
-        offscreen = Allocation.createTyped(mRS,
-                                           b.create(),
-                                           Allocation.USAGE_GRAPHICS_RENDER_TARGET);
-        mScript.set_gRenderBufferDepth(offscreen);
-        mScript.set_gLinearClamp(Sampler.CLAMP_LINEAR(mRS));
-
-        RsBenchBaseTest test = new TextTest();
-        if (test.init(mRS, mRes)) {
-            appendTests(test);
-        }
-        test = new FillTest();
-        if (test.init(mRS, mRes)) {
-            appendTests(test);
-        }
-        test = new MeshTest();
-        if (test.init(mRS, mRes)) {
-            appendTests(test);
-        }
-        test = new TorusTest();
-        if (test.init(mRS, mRes)) {
-            appendTests(test);
-        }
-        test = new UiTest();
-        if (test.init(mRS, mRes)) {
-            appendTests(test);
-        }
-        createTestAllocation();
-
-        mScript.set_gLoadComplete(true);
-    }
-}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchTest.java
deleted file mode 100644
index 199200b..0000000
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchTest.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.perftest;
-
-import android.app.Instrumentation;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.util.Log;
-
-/**
- * To run the test, please use command
- *
- * adb shell am instrument -w com.android.perftest/.RsPerfTestRunner
- *
- */
-public class RsBenchTest extends ActivityInstrumentationTestCase2<RsBench> {
-    private String TAG = "RsBenchTest";
-    private int iterations = 0;
-    private RsBench mAct;
-
-    public RsBenchTest() {
-        super(RsBench.class);
-    }
-
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        Instrumentation mInst = getInstrumentation();
-        RsPerfTestRunner mRunner = (RsPerfTestRunner) getInstrumentation();
-        iterations = mRunner.iterations;
-        Log.v(TAG, "Run benchmark for " + iterations + " iterations.");
-
-        Uri data = Uri.fromParts("iterations", Integer.toString(iterations), null);
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        intent.setClassName("com.android.perftest", "com.android.perftest.RsBench");
-        intent.setData(data);
-        mAct = (RsBench) mInst.startActivitySync(intent);
-        mInst.waitForIdleSync();
-
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        mAct.finish();
-        super.tearDown();
-    }
-
-    /**
-     * Run tests and wait until the test has been run for iterations.
-     */
-    @LargeTest
-    public void testRsBench() {
-        if (mAct.mView.testIsFinished()) {
-            return;
-        } else {
-            fail("test didn't stop correctly");
-        }
-    }
-}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java
deleted file mode 100644
index 124071e..0000000
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.perftest;
-
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.concurrent.Semaphore;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-import android.renderscript.RenderScriptGL;
-import android.renderscript.RenderScript.RSMessageHandler;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.Message;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-
-public class RsBenchView extends RSSurfaceView {
-
-    public RsBenchView(Context context) {
-        super(context);
-    }
-
-    private RenderScriptGL mRS;
-    private RsBenchRS mRender;
-    private int mLoops = 0;
-
-    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
-        super.surfaceChanged(holder, format, w, h);
-        if (mRS == null) {
-            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
-            sc.setDepth(16, 24);
-            mRS = createRenderScriptGL(sc);
-            mRS.setSurface(holder, w, h);
-            mRender = new RsBenchRS();
-            Log.v("RsBenchView", "mLoops = " + mLoops);
-            mRender.init(mRS, getResources(), w, h, mLoops);
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        if (mRS != null) {
-            mRS = null;
-            destroyRenderScriptGL();
-        }
-    }
-
-    /**
-     * Set the total number of loops the benchmark tests will run
-     * before the test results are collected.
-     */
-    public void setLoops(int iterations) {
-        if (iterations > 0) {
-            mLoops = iterations;
-        }
-    }
-
-    /**
-     * Wait for message from the script
-     */
-    public boolean testIsFinished() {
-        return mRender.testIsFinished();
-    }
-
-    void setBenchmarkMode(int benchNum) {
-        mRender.setBenchmarkMode(benchNum);
-    }
-
-    void suspendRendering(boolean pause) {
-        mRender.pause(pause);
-    }
-
-    void setDebugMode(int num) {
-        mRender.setDebugMode(num);
-    }
-
-    String[] getTestNames() {
-        return mRender.mTestNames;
-    }
-}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsPerfTestRunner.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsPerfTestRunner.java
deleted file mode 100644
index 031af6a..0000000
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsPerfTestRunner.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.perftest;
-
-//import com.android.perftest.RsBenchTest;
-
-import android.os.Bundle;
-import android.test.InstrumentationTestRunner;
-import android.test.InstrumentationTestSuite;
-
-import junit.framework.TestSuite;
-
-/**
- * Run the RenderScript Performance Test
- * adb shell am instrument -w com.android.perftest/.RsPerfTestRunner
- *
- * with specified iterations:
- * adb shell am instrument -e iterations <n> -w com.android.perftest/.RsPerfTestRunner
- *
- */
-public class RsPerfTestRunner extends InstrumentationTestRunner {
-    public int iterations = 10;
-
-    @Override
-    public TestSuite getAllTests() {
-        TestSuite suite = new InstrumentationTestSuite(this);
-        suite.addTestSuite(RsBenchTest.class);
-        return suite;
-    }
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        String strValue = (String)icicle.get("iterations");
-        if (strValue != null) {
-            int intValue = Integer.parseInt(strValue);
-            if (iterations > 0) {
-                iterations = intValue;
-            }
-        }
-    }
-}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TextTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TextTest.java
deleted file mode 100644
index 3ca2792..0000000
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TextTest.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.perftest;
-
-import android.os.Environment;
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.util.DisplayMetrics;
-
-import android.util.Log;
-
-
-public class TextTest implements RsBenchBaseTest{
-
-    private static final String TAG = "TextTest";
-    private RenderScriptGL mRS;
-    private Resources mRes;
-
-    private ScriptC_text_test mTextScript;
-    ScriptField_TestScripts_s.Item[] mTests;
-
-    private final String[] mNames = {
-        "Fill screen with text 1 time",
-        "Fill screen with text 3 times",
-        "Fill screen with text 5 times"
-    };
-
-    public TextTest() {
-    }
-
-    void addTest(int index, int fillNum) {
-        mTests[index] = new ScriptField_TestScripts_s.Item();
-        mTests[index].testScript = mTextScript;
-        mTests[index].testName = Allocation.createFromString(mRS,
-                                                             mNames[index],
-                                                             Allocation.USAGE_SCRIPT);
-        mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS,
-                                                                     mNames[index],
-                                                                     Allocation.USAGE_SCRIPT);
-
-        ScriptField_TextTestData_s.Item dataItem = new ScriptField_TextTestData_s.Item();
-        dataItem.fillNum = fillNum;
-        ScriptField_TextTestData_s testData = new ScriptField_TextTestData_s(mRS, 1);
-        testData.set(dataItem, 0, true);
-        mTests[index].testData = testData.getAllocation();
-    }
-
-    public boolean init(RenderScriptGL rs, Resources res) {
-        mRS = rs;
-        mRes = res;
-        initTextScript();
-        mTests = new ScriptField_TestScripts_s.Item[mNames.length];
-
-        int index = 0;
-        addTest(index++, 1 /*fillNum*/);
-        addTest(index++, 3 /*fillNum*/);
-        addTest(index++, 5 /*fillNum*/);
-
-        return true;
-    }
-
-    public ScriptField_TestScripts_s.Item[] getTests() {
-        return mTests;
-    }
-
-    public String[] getTestNames() {
-        return mNames;
-    }
-
-    void initTextScript() {
-        DisplayMetrics metrics = mRes.getDisplayMetrics();
-
-        mTextScript = new ScriptC_text_test(mRS, mRes, R.raw.text_test);
-        mTextScript.set_gFontSans(Font.create(mRS, mRes, "sans-serif",
-                                              Font.Style.NORMAL, 8.0f / metrics.density));
-        mTextScript.set_gFontSerif(Font.create(mRS, mRes, "serif",
-                                               Font.Style.NORMAL, 8.0f / metrics.density));
-    }
-}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TorusTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TorusTest.java
deleted file mode 100644
index 5c9ecd5..0000000
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TorusTest.java
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.perftest;
-
-import android.os.Environment;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.renderscript.*;
-import android.renderscript.Element.DataKind;
-import android.renderscript.Element.DataType;
-import android.renderscript.Allocation.MipmapControl;
-import android.renderscript.Program.TextureType;
-import android.renderscript.RenderScript.RSMessageHandler;
-import android.renderscript.Mesh.Primitive;
-import android.renderscript.Matrix4f;
-import android.renderscript.ProgramVertexFixedFunction;
-
-import android.util.Log;
-
-
-public class TorusTest implements RsBenchBaseTest{
-
-    private static final String TAG = "TorusTest";
-    private RenderScriptGL mRS;
-    private Resources mRes;
-
-    private ProgramStore mProgStoreBlendNoneDepth;
-    private ProgramStore mProgStoreBlendNone;
-    private ProgramStore mProgStoreBlendAlpha;
-
-    private ProgramFragment mProgFragmentTexture;
-    private ProgramFragment mProgFragmentColor;
-
-    private ProgramVertex mProgVertex;
-    private ProgramVertexFixedFunction.Constants mPVA;
-    private ProgramVertexFixedFunction.Constants mPvProjectionAlloc;
-
-    // Custom shaders
-    private ProgramVertex mProgVertexCustom;
-    private ProgramFragment mProgFragmentCustom;
-    private ProgramFragment mProgFragmentMultitex;
-    private ProgramVertex mProgVertexPixelLight;
-    private ProgramVertex mProgVertexPixelLightMove;
-    private ProgramFragment mProgFragmentPixelLight;
-    private ScriptField_VertexShaderConstants_s mVSConst;
-    private ScriptField_FragentShaderConstants_s mFSConst;
-    private ScriptField_VertexShaderConstants3_s mVSConstPixel;
-    private ScriptField_FragentShaderConstants3_s mFSConstPixel;
-
-    private Allocation mTexTorus;
-    private Mesh mTorus;
-
-    private ScriptC_torus_test mTorusScript;
-
-    private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
-
-    ScriptField_TestScripts_s.Item[] mTests;
-
-    private final String[] mNames = {
-        "Geo test 25.6k flat color",
-        "Geo test 51.2k flat color",
-        "Geo test 204.8k small tries flat color",
-        "Geo test 25.6k single texture",
-        "Geo test 51.2k single texture",
-        "Geo test 204.8k small tries single texture",
-        "Geo test 25.6k geo heavy vertex",
-        "Geo test 51.2k geo heavy vertex",
-        "Geo test 204.8k geo raster load heavy vertex",
-        "Geo test 25.6k heavy fragment",
-        "Geo test 51.2k heavy fragment",
-        "Geo test 204.8k small tries heavy fragment",
-        "Geo test 25.6k heavy fragment heavy vertex",
-        "Geo test 51.2k heavy fragment heavy vertex",
-        "Geo test 204.8k small tries heavy fragment heavy vertex"
-    };
-
-    public TorusTest() {
-    }
-
-    void addTest(int index, int testId, int user1, int user2) {
-        mTests[index] = new ScriptField_TestScripts_s.Item();
-        mTests[index].testScript = mTorusScript;
-        mTests[index].testName = Allocation.createFromString(mRS,
-                                                             mNames[index],
-                                                             Allocation.USAGE_SCRIPT);
-        mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS,
-                                                                      mNames[index],
-                                                                      Allocation.USAGE_SCRIPT);
-
-        ScriptField_TorusTestData_s.Item dataItem = new ScriptField_TorusTestData_s.Item();
-        dataItem.testId = testId;
-        dataItem.user1 = user1;
-        dataItem.user2 = user2;
-        ScriptField_TorusTestData_s testData = new ScriptField_TorusTestData_s(mRS, 1);
-        testData.set(dataItem, 0, true);
-        mTests[index].testData = testData.getAllocation();
-    }
-
-    public boolean init(RenderScriptGL rs, Resources res) {
-        mRS = rs;
-        mRes = res;
-        initCustomShaders();
-        loadImages();
-        initMesh();
-        initTorusScript();
-        mTests = new ScriptField_TestScripts_s.Item[mNames.length];
-
-        int index = 0;
-        addTest(index++, 0, 0 /*useTexture*/, 1 /*numMeshes*/);
-        addTest(index++, 0, 0 /*useTexture*/, 2 /*numMeshes*/);
-        addTest(index++, 0, 0 /*useTexture*/, 8 /*numMeshes*/);
-        addTest(index++, 0, 1 /*useTexture*/, 1 /*numMeshes*/);
-        addTest(index++, 0, 1 /*useTexture*/, 2 /*numMeshes*/);
-        addTest(index++, 0, 1 /*useTexture*/, 8 /*numMeshes*/);
-
-        // Secont test
-        addTest(index++, 1, 1 /*numMeshes*/, 0 /*unused*/);
-        addTest(index++, 1, 2 /*numMeshes*/, 0 /*unused*/);
-        addTest(index++, 1, 8 /*numMeshes*/, 0 /*unused*/);
-
-        // Third test
-        addTest(index++, 2, 1 /*numMeshes*/, 0 /*heavyVertex*/);
-        addTest(index++, 2, 2 /*numMeshes*/, 0 /*heavyVertex*/);
-        addTest(index++, 2, 8 /*numMeshes*/, 0 /*heavyVertex*/);
-        addTest(index++, 2, 1 /*numMeshes*/, 1 /*heavyVertex*/);
-        addTest(index++, 2, 2 /*numMeshes*/, 1 /*heavyVertex*/);
-        addTest(index++, 2, 8 /*numMeshes*/, 1 /*heavyVertex*/);
-
-        return true;
-    }
-
-    public ScriptField_TestScripts_s.Item[] getTests() {
-        return mTests;
-    }
-
-    public String[] getTestNames() {
-        return mNames;
-    }
-
-    private void initCustomShaders() {
-        mVSConst = new ScriptField_VertexShaderConstants_s(mRS, 1);
-        mFSConst = new ScriptField_FragentShaderConstants_s(mRS, 1);
-
-        mVSConstPixel = new ScriptField_VertexShaderConstants3_s(mRS, 1);
-        mFSConstPixel = new ScriptField_FragentShaderConstants3_s(mRS, 1);
-
-        // Initialize the shader builder
-        ProgramVertex.Builder pvbCustom = new ProgramVertex.Builder(mRS);
-        // Specify the resource that contains the shader string
-        pvbCustom.setShader(mRes, R.raw.shaderv);
-        // Use a script field to specify the input layout
-        pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS));
-        // Define the constant input layout
-        pvbCustom.addConstant(mVSConst.getAllocation().getType());
-        mProgVertexCustom = pvbCustom.create();
-        // Bind the source of constant data
-        mProgVertexCustom.bindConstants(mVSConst.getAllocation(), 0);
-
-        ProgramFragment.Builder pfbCustom = new ProgramFragment.Builder(mRS);
-        // Specify the resource that contains the shader string
-        pfbCustom.setShader(mRes, R.raw.shaderf);
-        // Tell the builder how many textures we have
-        pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
-        // Define the constant input layout
-        pfbCustom.addConstant(mFSConst.getAllocation().getType());
-        mProgFragmentCustom = pfbCustom.create();
-        // Bind the source of constant data
-        mProgFragmentCustom.bindConstants(mFSConst.getAllocation(), 0);
-
-        pvbCustom = new ProgramVertex.Builder(mRS);
-        pvbCustom.setShader(mRes, R.raw.shader2v);
-        pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS));
-        pvbCustom.addConstant(mVSConstPixel.getAllocation().getType());
-        mProgVertexPixelLight = pvbCustom.create();
-        mProgVertexPixelLight.bindConstants(mVSConstPixel.getAllocation(), 0);
-
-        pvbCustom = new ProgramVertex.Builder(mRS);
-        pvbCustom.setShader(mRes, R.raw.shader2movev);
-        pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS));
-        pvbCustom.addConstant(mVSConstPixel.getAllocation().getType());
-        mProgVertexPixelLightMove = pvbCustom.create();
-        mProgVertexPixelLightMove.bindConstants(mVSConstPixel.getAllocation(), 0);
-
-        pfbCustom = new ProgramFragment.Builder(mRS);
-        pfbCustom.setShader(mRes, R.raw.shader2f);
-        pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
-        pfbCustom.addConstant(mFSConstPixel.getAllocation().getType());
-        mProgFragmentPixelLight = pfbCustom.create();
-        mProgFragmentPixelLight.bindConstants(mFSConstPixel.getAllocation(), 0);
-
-        pfbCustom = new ProgramFragment.Builder(mRS);
-        pfbCustom.setShader(mRes, R.raw.multitexf);
-        for (int texCount = 0; texCount < 3; texCount ++) {
-            pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
-        }
-        mProgFragmentMultitex = pfbCustom.create();
-
-        ProgramFragmentFixedFunction.Builder colBuilder = new ProgramFragmentFixedFunction.Builder(mRS);
-        colBuilder.setVaryingColor(false);
-        mProgFragmentColor = colBuilder.create();
-
-        ProgramFragmentFixedFunction.Builder texBuilder = new ProgramFragmentFixedFunction.Builder(mRS);
-        texBuilder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
-                              ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
-        mProgFragmentTexture = texBuilder.create();
-
-        ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
-        mProgVertex = pvb.create();
-        ProgramVertexFixedFunction.Constants PVA = new ProgramVertexFixedFunction.Constants(mRS);
-        ((ProgramVertexFixedFunction)mProgVertex).bindConstants(PVA);
-        Matrix4f proj = new Matrix4f();
-        proj.loadOrthoWindow(1280, 720);
-        PVA.setProjection(proj);
-    }
-
-    private Allocation loadTextureRGB(int id) {
-        return Allocation.createFromBitmapResource(mRS, mRes, id,
-                Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
-                Allocation.USAGE_GRAPHICS_TEXTURE);
-    }
-
-    private void loadImages() {
-        mTexTorus = loadTextureRGB(R.drawable.torusmap);
-    }
-
-    private void initMesh() {
-        FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.torus);
-        FileA3D.IndexEntry entry = model.getIndexEntry(0);
-        if (entry == null || entry.getEntryType() != FileA3D.EntryType.MESH) {
-            Log.e("rs", "could not load model");
-        } else {
-            mTorus = (Mesh)entry.getObject();
-        }
-    }
-
-    void initTorusScript() {
-        mTorusScript = new ScriptC_torus_test(mRS, mRes, R.raw.torus_test);
-        mTorusScript.set_gCullFront(ProgramRaster.CULL_FRONT(mRS));
-        mTorusScript.set_gCullBack(ProgramRaster.CULL_BACK(mRS));
-        mTorusScript.set_gLinearClamp(Sampler.CLAMP_LINEAR(mRS));
-        mTorusScript.set_gTorusMesh(mTorus);
-        mTorusScript.set_gTexTorus(mTexTorus);
-        mTorusScript.set_gProgVertexCustom(mProgVertexCustom);
-        mTorusScript.set_gProgFragmentCustom(mProgFragmentCustom);
-        mTorusScript.set_gProgVertexPixelLight(mProgVertexPixelLight);
-        mTorusScript.set_gProgVertexPixelLightMove(mProgVertexPixelLightMove);
-        mTorusScript.set_gProgFragmentPixelLight(mProgFragmentPixelLight);
-        mTorusScript.bind_gVSConstPixel(mVSConstPixel);
-        mTorusScript.bind_gFSConstPixel(mFSConstPixel);
-        mTorusScript.bind_gVSConstants(mVSConst);
-        mTorusScript.bind_gFSConstants(mFSConst);
-        mTorusScript.set_gProgVertex(mProgVertex);
-        mTorusScript.set_gProgFragmentTexture(mProgFragmentTexture);
-        mTorusScript.set_gProgFragmentColor(mProgFragmentColor);
-        mTorusScript.set_gProgStoreBlendNoneDepth(mProgStoreBlendNoneDepth);
-    }
-}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/UiTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/UiTest.java
deleted file mode 100644
index c8b58b2..0000000
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/UiTest.java
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.perftest;
-
-import android.os.Environment;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.renderscript.*;
-import android.renderscript.Element.DataKind;
-import android.renderscript.Element.DataType;
-import android.renderscript.Allocation.MipmapControl;
-import android.renderscript.Program.TextureType;
-import android.renderscript.ProgramStore.DepthFunc;
-import android.renderscript.ProgramStore.BlendSrcFunc;
-import android.renderscript.ProgramStore.BlendDstFunc;
-import android.renderscript.RenderScript.RSMessageHandler;
-import android.renderscript.Mesh.Primitive;
-import android.renderscript.Matrix4f;
-import android.renderscript.ProgramVertexFixedFunction;
-
-import android.util.Log;
-
-
-public class UiTest implements RsBenchBaseTest{
-
-    private static final String TAG = "UiTest";
-    private static final String SAMPLE_TEXT = "Bench Test";
-    private static final String LIST_TEXT =
-      "This is a sample list of text to show in the list view";
-    private static int PARTICLES_COUNT = 12000;
-
-    private RenderScriptGL mRS;
-    private Resources mRes;
-
-    Font mFontSans;
-
-    private ScriptField_ListAllocs_s mTextureAllocs;
-    private ScriptField_ListAllocs_s mSampleTextAllocs;
-    private ScriptField_ListAllocs_s mSampleListViewAllocs;
-    private ScriptField_VpConsts mPvStarAlloc;
-    private ProgramVertexFixedFunction.Constants mPvProjectionAlloc;
-
-    private Mesh mSingleMesh;
-    private Mesh mParticlesMesh;
-
-    private ScriptC_ui_test mUiScript;
-
-    private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
-
-    ScriptField_TestScripts_s.Item[] mTests;
-
-    private final String[] mNames = {
-        "UI test with icon display 10 by 10",
-        "UI test with icon display 100 by 100",
-        "UI test with image and text display 3 pages",
-        "UI test with image and text display 5 pages",
-        "UI test with list view",
-        "UI test with live wallpaper"
-    };
-
-    public UiTest() {
-    }
-
-    void addTest(int index, int testId, int user1, int user2, int user3) {
-        mTests[index] = new ScriptField_TestScripts_s.Item();
-        mTests[index].testScript = mUiScript;
-        mTests[index].testName = Allocation.createFromString(mRS,
-                                                             mNames[index],
-                                                             Allocation.USAGE_SCRIPT);
-        mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS,
-                                                                      mNames[index],
-                                                                      Allocation.USAGE_SCRIPT);
-
-        ScriptField_UiTestData_s.Item dataItem = new ScriptField_UiTestData_s.Item();
-        dataItem.testId = testId;
-        dataItem.user1 = user1;
-        dataItem.user2 = user2;
-        dataItem.user3 = user3;
-        ScriptField_UiTestData_s testData = new ScriptField_UiTestData_s(mRS, 1);
-        testData.set(dataItem, 0, true);
-        mTests[index].testData = testData.getAllocation();
-    }
-
-    public boolean init(RenderScriptGL rs, Resources res) {
-        mRS = rs;
-        mRes = res;
-        mFontSans = Font.create(mRS, mRes, "sans-serif", Font.Style.NORMAL, 8);
-        mSingleMesh = getSingleMesh(1, 1);  // a unit size mesh
-
-        initUiScript();
-        mTests = new ScriptField_TestScripts_s.Item[mNames.length];
-
-        int index = 0;
-
-        addTest(index++, 0, 0 /*meshMode*/, 0 /*unused*/, 0 /*unused*/);
-        addTest(index++, 0, 1 /*meshMode*/, 0 /*unused*/, 0 /*unused*/);
-        addTest(index++, 1, 7 /*wResolution*/, 5 /*hResolution*/, 0 /*meshMode*/);
-        addTest(index++, 1, 7 /*wResolution*/, 5 /*hResolution*/, 1 /*meshMode*/);
-        addTest(index++, 2, 0 /*unused*/, 0 /*unused*/, 0 /*unused*/);
-        addTest(index++, 3, 7 /*wResolution*/, 5 /*hResolution*/, 0 /*unused*/);
-
-        return true;
-    }
-
-    public ScriptField_TestScripts_s.Item[] getTests() {
-        return mTests;
-    }
-
-    public String[] getTestNames() {
-        return mNames;
-    }
-
-    private Allocation loadTextureRGB(int id) {
-        return Allocation.createFromBitmapResource(mRS, mRes, id,
-                Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
-                Allocation.USAGE_GRAPHICS_TEXTURE);
-    }
-
-    private Allocation loadTextureARGB(int id) {
-        Bitmap b = BitmapFactory.decodeResource(mRes, id, mOptionsARGB);
-        return Allocation.createFromBitmap(mRS, b,
-                Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
-                Allocation.USAGE_GRAPHICS_TEXTURE);
-    }
-
-    private void createParticlesMesh() {
-        ScriptField_Particle p = new ScriptField_Particle(mRS, PARTICLES_COUNT);
-
-        final Mesh.AllocationBuilder meshBuilder = new Mesh.AllocationBuilder(mRS);
-        meshBuilder.addVertexAllocation(p.getAllocation());
-        final int vertexSlot = meshBuilder.getCurrentVertexTypeIndex();
-        meshBuilder.addIndexSetType(Primitive.POINT);
-        mParticlesMesh = meshBuilder.create();
-
-        mUiScript.set_gParticlesMesh(mParticlesMesh);
-        mUiScript.bind_Particles(p);
-    }
-
-    /**
-     * Create a mesh with a single quad for the given width and height.
-     */
-    private Mesh getSingleMesh(float width, float height) {
-        Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS,
-                                           2, Mesh.TriangleMeshBuilder.TEXTURE_0);
-        float xOffset = width/2;
-        float yOffset = height/2;
-        tmb.setTexture(0, 0);
-        tmb.addVertex(-1.0f * xOffset, -1.0f * yOffset);
-        tmb.setTexture(1, 0);
-        tmb.addVertex(xOffset, -1.0f * yOffset);
-        tmb.setTexture(1, 1);
-        tmb.addVertex(xOffset, yOffset);
-        tmb.setTexture(0, 1);
-        tmb.addVertex(-1.0f * xOffset, yOffset);
-        tmb.addTriangle(0, 3, 1);
-        tmb.addTriangle(1, 3, 2);
-        return tmb.create(true);
-    }
-
-    private Matrix4f getProjectionNormalized(int w, int h) {
-        // range -1,1 in the narrow axis at z = 0.
-        Matrix4f m1 = new Matrix4f();
-        Matrix4f m2 = new Matrix4f();
-
-        if(w > h) {
-            float aspect = ((float)w) / h;
-            m1.loadFrustum(-aspect,aspect,  -1,1,  1,100);
-        } else {
-            float aspect = ((float)h) / w;
-            m1.loadFrustum(-1,1, -aspect,aspect, 1,100);
-        }
-
-        m2.loadRotate(180, 0, 1, 0);
-        m1.loadMultiply(m1, m2);
-
-        m2.loadScale(-2, 2, 1);
-        m1.loadMultiply(m1, m2);
-
-        m2.loadTranslate(0, 0, 2);
-        m1.loadMultiply(m1, m2);
-        return m1;
-    }
-
-    private void updateProjectionMatrices() {
-        Matrix4f projNorm = getProjectionNormalized(1280, 720);
-        ScriptField_VpConsts.Item i = new ScriptField_VpConsts.Item();
-        i.Proj = projNorm;
-        i.MVP = projNorm;
-        mPvStarAlloc.set(i, 0, true);
-        mPvProjectionAlloc.setProjection(projNorm);
-    }
-
-    void initUiScript() {
-        mUiScript = new ScriptC_ui_test(mRS, mRes, R.raw.ui_test);
-
-        ProgramFragmentFixedFunction.Builder colBuilder = new ProgramFragmentFixedFunction.Builder(mRS);
-        colBuilder.setVaryingColor(false);
-        ProgramFragmentFixedFunction.Builder texBuilder = new ProgramFragmentFixedFunction.Builder(mRS);
-        texBuilder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
-                              ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
-
-        ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
-        ProgramVertexFixedFunction progVertex = pvb.create();
-        ProgramVertexFixedFunction.Constants PVA = new ProgramVertexFixedFunction.Constants(mRS);
-        ((ProgramVertexFixedFunction)progVertex).bindConstants(PVA);
-        Matrix4f proj = new Matrix4f();
-        proj.loadOrthoWindow(1280, 720);
-        PVA.setProjection(proj);
-
-        mUiScript.set_gProgVertex(progVertex);
-        mUiScript.set_gProgFragmentColor(colBuilder.create());
-        mUiScript.set_gProgFragmentTexture(texBuilder.create());
-        mUiScript.set_gProgStoreBlendAlpha(ProgramStore.BLEND_ALPHA_DEPTH_NONE(mRS));
-
-        mUiScript.set_gLinearClamp(Sampler.CLAMP_LINEAR(mRS));
-
-        mUiScript.set_gTexTorus(loadTextureRGB(R.drawable.torusmap));
-        mUiScript.set_gTexOpaque(loadTextureRGB(R.drawable.data));
-        mUiScript.set_gTexGlobe(loadTextureRGB(R.drawable.globe));
-        mUiScript.set_gSingleMesh(mSingleMesh);
-
-        // For GALAXY
-        ProgramStore.Builder psb = new ProgramStore.Builder(mRS);
-        psb.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ZERO);
-        mRS.bindProgramStore(psb.create());
-
-        psb.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE);
-        mUiScript.set_gPSLights(psb.create());
-
-        // For Galaxy live wallpaper drawing
-        ProgramFragmentFixedFunction.Builder builder = new ProgramFragmentFixedFunction.Builder(mRS);
-        builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
-                           ProgramFragmentFixedFunction.Builder.Format.RGB, 0);
-        ProgramFragment pfb = builder.create();
-        pfb.bindSampler(Sampler.WRAP_NEAREST(mRS), 0);
-        mUiScript.set_gPFBackground(pfb);
-
-        builder = new ProgramFragmentFixedFunction.Builder(mRS);
-        builder.setPointSpriteTexCoordinateReplacement(true);
-        builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.MODULATE,
-                           ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
-        builder.setVaryingColor(true);
-        ProgramFragment pfs = builder.create();
-        pfs.bindSampler(Sampler.WRAP_LINEAR_MIP_LINEAR(mRS), 0);
-        mUiScript.set_gPFStars(pfs);
-
-        mTextureAllocs = new ScriptField_ListAllocs_s(mRS, 100);
-        for (int i = 0; i < 100; i++) {
-            ScriptField_ListAllocs_s.Item texElem = new ScriptField_ListAllocs_s.Item();
-            texElem.item = loadTextureRGB(R.drawable.globe);
-            mTextureAllocs.set(texElem, i, false);
-        }
-        mTextureAllocs.copyAll();
-        mUiScript.bind_gTexList100(mTextureAllocs);
-
-        mSampleTextAllocs = new ScriptField_ListAllocs_s(mRS, 100);
-        for (int i = 0; i < 100; i++) {
-            ScriptField_ListAllocs_s.Item textElem = new ScriptField_ListAllocs_s.Item();
-            textElem.item = Allocation.createFromString(mRS, SAMPLE_TEXT, Allocation.USAGE_SCRIPT);
-            mSampleTextAllocs.set(textElem, i, false);
-        }
-        mSampleTextAllocs.copyAll();
-        mUiScript.bind_gSampleTextList100(mSampleTextAllocs);
-
-        mSampleListViewAllocs = new ScriptField_ListAllocs_s(mRS, 1000);
-        for (int i = 0; i < 1000; i++) {
-            ScriptField_ListAllocs_s.Item textElem = new ScriptField_ListAllocs_s.Item();
-            textElem.item = Allocation.createFromString(mRS, LIST_TEXT, Allocation.USAGE_SCRIPT);
-            mSampleListViewAllocs.set(textElem, i, false);
-        }
-        mSampleListViewAllocs.copyAll();
-        mUiScript.bind_gListViewText(mSampleListViewAllocs);
-
-        // For galaxy live wallpaper
-        mPvStarAlloc = new ScriptField_VpConsts(mRS, 1);
-        mUiScript.bind_vpConstants(mPvStarAlloc);
-        mPvProjectionAlloc = new ProgramVertexFixedFunction.Constants(mRS);
-        updateProjectionMatrices();
-
-        pvb = new ProgramVertexFixedFunction.Builder(mRS);
-        ProgramVertex pvbp = pvb.create();
-        ((ProgramVertexFixedFunction)pvbp).bindConstants(mPvProjectionAlloc);
-        mUiScript.set_gPVBkProj(pvbp);
-
-        createParticlesMesh();
-
-        ProgramVertex.Builder sb = new ProgramVertex.Builder(mRS);
-        String t =  "varying vec4 varColor;\n" +
-                    "varying vec2 varTex0;\n" +
-                    "void main() {\n" +
-                    "  float dist = ATTRIB_position.y;\n" +
-                    "  float angle = ATTRIB_position.x;\n" +
-                    "  float x = dist * sin(angle);\n" +
-                    "  float y = dist * cos(angle) * 0.892;\n" +
-                    "  float p = dist * 5.5;\n" +
-                    "  float s = cos(p);\n" +
-                    "  float t = sin(p);\n" +
-                    "  vec4 pos;\n" +
-                    "  pos.x = t * x + s * y;\n" +
-                    "  pos.y = s * x - t * y;\n" +
-                    "  pos.z = ATTRIB_position.z;\n" +
-                    "  pos.w = 1.0;\n" +
-                    "  gl_Position = UNI_MVP * pos;\n" +
-                    "  gl_PointSize = ATTRIB_color.a * 10.0;\n" +
-                    "  varColor.rgb = ATTRIB_color.rgb;\n" +
-                    "  varColor.a = 1.0;\n" +
-                    "}\n";
-        sb.setShader(t);
-        sb.addInput(mParticlesMesh.getVertexAllocation(0).getType().getElement());
-        sb.addConstant(mPvStarAlloc.getType());
-        ProgramVertex pvs = sb.create();
-        pvs.bindConstants(mPvStarAlloc.getAllocation(), 0);
-        mUiScript.set_gPVStars(pvs);
-
-        // For Galaxy live wallpaper
-        mUiScript.set_gTSpace(loadTextureRGB(R.drawable.space));
-        mUiScript.set_gTLight1(loadTextureRGB(R.drawable.light1));
-        mUiScript.set_gTFlares(loadTextureARGB(R.drawable.flares));
-
-        mUiScript.set_gFontSans(mFontSans);
-    }
-}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs
deleted file mode 100644
index 281f830..0000000
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs
+++ /dev/null
@@ -1,158 +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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.perftest)
-
-#include "rs_graphics.rsh"
-#include "subtest_def.rsh"
-
-rs_program_vertex gProgVertex;
-rs_program_fragment gProgFragmentTexture;
-rs_program_fragment gProgFragmentTextureModulate;
-rs_program_fragment gProgFragmentMultitex;
-
-rs_program_store gProgStoreBlendNone;
-rs_program_store gProgStoreBlendAlpha;
-
-rs_allocation gTexOpaque;
-rs_allocation gTexTorus;
-rs_allocation gTexTransparent;
-rs_allocation gTexChecker;
-
-rs_sampler gLinearClamp;
-rs_sampler gLinearWrap;
-
-typedef struct FillTestData_s {
-    int testId;
-    int blend;
-    int quadCount;
-} FillTestData;
-FillTestData *gData;
-
-typedef struct FillTestFragData_s {
-    float4 modulate;
-} FillTestFragData;
-FillTestFragData *gFragData;
-
-static float gDt = 0.0f;
-
-void init() {
-}
-
-static int gRenderSurfaceW = 1280;
-static int gRenderSurfaceH = 720;
-
-static void bindProgramVertexOrtho() {
-    // Default vertex shader
-    rsgBindProgramVertex(gProgVertex);
-    // Setup the projection matrix
-    rs_matrix4x4 proj;
-    rsMatrixLoadOrtho(&proj, 0, gRenderSurfaceW, gRenderSurfaceH, 0, -500, 500);
-    rsgProgramVertexLoadProjectionMatrix(&proj);
-}
-
-static void displaySingletexFill(bool blend, int quadCount, bool modulate) {
-    bindProgramVertexOrtho();
-    rs_matrix4x4 matrix;
-    rsMatrixLoadIdentity(&matrix);
-    rsgProgramVertexLoadModelMatrix(&matrix);
-
-    // Fragment shader with texture
-    if (!blend) {
-        rsgBindProgramStore(gProgStoreBlendNone);
-    } else {
-        rsgBindProgramStore(gProgStoreBlendAlpha);
-    }
-    if (modulate) {
-        rsgBindProgramFragment(gProgFragmentTextureModulate);
-        rsgBindSampler(gProgFragmentTextureModulate, 0, gLinearClamp);
-        rsgBindTexture(gProgFragmentTextureModulate, 0, gTexOpaque);
-
-        gFragData->modulate.r = 0.8f;
-        gFragData->modulate.g = 0.7f;
-        gFragData->modulate.b = 0.8f;
-        gFragData->modulate.a = 0.5f;
-        rsgAllocationSyncAll(rsGetAllocation(gFragData));
-    } else {
-        rsgBindProgramFragment(gProgFragmentTexture);
-        rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
-        rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
-    }
-
-    for (int i = 0; i < quadCount; i ++) {
-        float startX = 5 * i, startY = 5 * i;
-        float width = gRenderSurfaceW - startX, height = gRenderSurfaceH - startY;
-        rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
-                             startX, startY + height, 0, 0, 1,
-                             startX + width, startY + height, 0, 1, 1,
-                             startX + width, startY, 0, 1, 0);
-    }
-}
-
-static void displayMultitextureSample(bool blend, int quadCount) {
-    bindProgramVertexOrtho();
-    rs_matrix4x4 matrix;
-    rsMatrixLoadIdentity(&matrix);
-    rsgProgramVertexLoadModelMatrix(&matrix);
-
-    // Fragment shader with texture
-    if (!blend) {
-        rsgBindProgramStore(gProgStoreBlendNone);
-    } else {
-        rsgBindProgramStore(gProgStoreBlendAlpha);
-    }
-    rsgBindProgramFragment(gProgFragmentMultitex);
-    rsgBindSampler(gProgFragmentMultitex, 0, gLinearClamp);
-    rsgBindSampler(gProgFragmentMultitex, 1, gLinearWrap);
-    rsgBindSampler(gProgFragmentMultitex, 2, gLinearClamp);
-    rsgBindTexture(gProgFragmentMultitex, 0, gTexChecker);
-    rsgBindTexture(gProgFragmentMultitex, 1, gTexTorus);
-    rsgBindTexture(gProgFragmentMultitex, 2, gTexTransparent);
-
-    for (int i = 0; i < quadCount; i ++) {
-        float startX = 10 * i, startY = 10 * i;
-        float width = gRenderSurfaceW - startX, height = gRenderSurfaceH - startY;
-        rsgDrawQuadTexCoords(startX, startY, 0, 0, 0,
-                             startX, startY + height, 0, 0, 1,
-                             startX + width, startY + height, 0, 1, 1,
-                             startX + width, startY, 0, 1, 0);
-    }
-}
-
-
-void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
-    TestData *testData = (TestData*)usrData;
-    gRenderSurfaceW = testData->renderSurfaceW;
-    gRenderSurfaceH = testData->renderSurfaceH;
-    gDt = testData->dt;
-
-    gData = (FillTestData*)v_in;
-
-    switch(gData->testId) {
-        case 0:
-            displayMultitextureSample(gData->blend == 1 ? true : false, gData->quadCount);
-            break;
-        case 1:
-            displaySingletexFill(gData->blend == 1 ? true : false, gData->quadCount, false);
-            break;
-        case 2:
-            displaySingletexFill(gData->blend == 1 ? true : false, gData->quadCount, true);
-            break;
-        default:
-            rsDebug("Wrong test number", 0);
-            break;
-    }
-}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/mesh_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/mesh_test.rs
deleted file mode 100644
index d7e4857..0000000
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/mesh_test.rs
+++ /dev/null
@@ -1,89 +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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.perftest)
-
-#include "rs_graphics.rsh"
-#include "shader_def.rsh"
-#include "subtest_def.rsh"
-
-rs_program_vertex gProgVertex;
-rs_program_fragment gProgFragmentTexture;
-
-rs_program_store gProgStoreBlendNone;
-
-rs_allocation gTexOpaque;
-
-rs_mesh g10by10Mesh;
-rs_mesh g100by100Mesh;
-rs_mesh gWbyHMesh;
-
-rs_sampler gLinearClamp;
-static int gRenderSurfaceW;
-static int gRenderSurfaceH;
-
-static float gDt = 0;
-
-typedef struct MeshTestData_s {
-    int meshNum;
-} MeshTestData;
-MeshTestData *gData;
-
-void init() {
-}
-
-static void bindProgramVertexOrtho() {
-    // Default vertex shader
-    rsgBindProgramVertex(gProgVertex);
-    // Setup the projection matrix
-    rs_matrix4x4 proj;
-    rsMatrixLoadOrtho(&proj, 0, gRenderSurfaceW, gRenderSurfaceH, 0, -500, 500);
-    rsgProgramVertexLoadProjectionMatrix(&proj);
-}
-
-static void displayMeshSamples(int meshNum) {
-
-    bindProgramVertexOrtho();
-    rs_matrix4x4 matrix;
-    rsMatrixLoadTranslate(&matrix, gRenderSurfaceW/2, gRenderSurfaceH/2, 0);
-    rsgProgramVertexLoadModelMatrix(&matrix);
-
-    // Fragment shader with texture
-    rsgBindProgramStore(gProgStoreBlendNone);
-    rsgBindProgramFragment(gProgFragmentTexture);
-    rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
-
-    rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
-
-    if (meshNum == 0) {
-        rsgDrawMesh(g10by10Mesh);
-    } else if (meshNum == 1) {
-        rsgDrawMesh(g100by100Mesh);
-    } else if (meshNum == 2) {
-        rsgDrawMesh(gWbyHMesh);
-    }
-}
-
-void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
-    TestData *testData = (TestData*)usrData;
-    gRenderSurfaceW = testData->renderSurfaceW;
-    gRenderSurfaceH = testData->renderSurfaceH;
-    gDt = testData->dt;
-
-    gData = (MeshTestData*)v_in;
-
-    displayMeshSamples(gData->meshNum);
-}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
deleted file mode 100644
index 43cf4e0..0000000
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
+++ /dev/null
@@ -1,270 +0,0 @@
-// Copyright (C) 2010-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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.perftest)
-
-#include "rs_graphics.rsh"
-#include "shader_def.rsh"
-#include "subtest_def.rsh"
-
-/* Message sent from script to renderscript */
-const int RS_MSG_TEST_DONE = 100;
-const int RS_MSG_RESULTS_READY = 101;
-
-static const int gMaxModes = 64;
-int gMaxLoops = 1;
-int gDisplayMode = 1;
-
-// Allocation to write the results into
-static float gResultBuffer[gMaxModes];
-
-rs_font gFontSerif;
-rs_sampler gLinearClamp;
-
-rs_program_vertex gProgVertex;
-rs_program_fragment gProgFragmentTexture;
-
-rs_allocation gRenderBufferColor;
-rs_allocation gRenderBufferDepth;
-
-VertexShaderInputs *gVSInputs;
-
-typedef struct TestScripts_s {
-    rs_allocation testData;
-    rs_allocation testName;
-    rs_allocation debugName;
-    rs_script testScript;
-} TestScripts;
-TestScripts *gTestScripts;
-
-bool gLoadComplete = false;
-bool gPauseRendering = false;
-
-static float gDt = 0;
-
-void init() {
-}
-
-static int gRenderSurfaceW;
-static int gRenderSurfaceH;
-
-static void fillSurfaceParams(TestData *testData) {
-    testData->renderSurfaceW = gRenderSurfaceW;
-    testData->renderSurfaceH = gRenderSurfaceH;
-    testData->dt = gDt;
-}
-
-static void setupOffscreenTarget() {
-    rsgBindColorTarget(gRenderBufferColor, 0);
-    rsgBindDepthTarget(gRenderBufferDepth);
-}
-
-static void bindProgramVertexOrtho() {
-    // Default vertex shader
-    rsgBindProgramVertex(gProgVertex);
-    // Setup the projection matrix
-    rs_matrix4x4 proj;
-    rsMatrixLoadOrtho(&proj, 0, gRenderSurfaceW, gRenderSurfaceH, 0, -500, 500);
-    rsgProgramVertexLoadProjectionMatrix(&proj);
-}
-
-static void runSubTest(int index) {
-    TestData testData;
-    fillSurfaceParams(&testData);
-
-    rs_allocation null_alloc = {0};
-    rsForEach(gTestScripts[index].testScript,
-              gTestScripts[index].testData,
-              null_alloc,
-              &testData,
-              sizeof(testData));
-}
-
-
-static bool checkInit() {
-
-    static int countdown = 3;
-
-    // Perform all the uploads so we only measure rendered time
-    if(countdown > 1) {
-        int testCount = rsAllocationGetDimX(rsGetAllocation(gTestScripts));
-        for(int i = 0; i < testCount; i ++) {
-            rsgClearColor(0.2f, 0.2f, 0.2f, 0.0f);
-            runSubTest(i);
-            rsgFinish();
-        }
-        countdown --;
-        rsgClearColor(0.2f, 0.2f, 0.2f, 0.0f);
-
-        rsgFontColor(0.9f, 0.9f, 0.95f, 1.0f);
-        rsgBindFont(gFontSerif);
-        if (countdown == 1) {
-            rsgDrawText("Rendering", 50, 50);
-        } else {
-            rsgDrawText("Initializing", 50, 50);
-        }
-
-        return false;
-    }
-
-    return true;
-}
-
-static int benchMode = 0;
-static bool benchmarkSingleTest = false;
-static int runningLoops = 0;
-static bool sendMsgFlag = false;
-
-static bool gIsDebugMode = false;
-void setDebugMode(int testNumber) {
-    gIsDebugMode = true;
-    benchMode = testNumber;
-    rsgClearAllRenderTargets();
-}
-
-void setBenchmarkMode(int testNumber) {
-    gIsDebugMode = false;
-    if (testNumber == -1) {
-        benchmarkSingleTest = false;
-        benchMode = 0;
-    } else {
-        benchmarkSingleTest = true;
-        benchMode = testNumber;
-    }
-
-    runningLoops = 0;
-}
-
-static void drawOffscreenResult(int posX, int posY, int width, int height) {
-    bindProgramVertexOrtho();
-
-    rs_matrix4x4 matrix;
-    rsMatrixLoadIdentity(&matrix);
-    rsgProgramVertexLoadModelMatrix(&matrix);
-
-    rsgBindProgramFragment(gProgFragmentTexture);
-
-    rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
-    rsgBindTexture(gProgFragmentTexture, 0, gRenderBufferColor);
-
-    float startX = posX, startY = posY;
-    rsgDrawQuadTexCoords(startX, startY, 0, 0, 1,
-                         startX, startY + height, 0, 0, 0,
-                         startX + width, startY + height, 0, 1, 0,
-                         startX + width, startY, 0, 1, 1);
-}
-
-static void benchmark() {
-
-    gDt = 1.0f / 60.0f;
-
-    rsgFinish();
-    int64_t start = rsUptimeMillis();
-
-    int drawPos = 0;
-    int frameCount = 100;
-    for(int i = 0; i < frameCount; i ++) {
-        setupOffscreenTarget();
-        gRenderSurfaceW = rsAllocationGetDimX(gRenderBufferColor);
-        gRenderSurfaceH = rsAllocationGetDimY(gRenderBufferColor);
-        rsgClearColor(0.1f, 0.1f, 0.1f, 1.0f);
-        rsgClearDepth(1.0f);
-
-        runSubTest(benchMode);
-        rsgClearAllRenderTargets();
-        gRenderSurfaceW = rsgGetWidth();
-        gRenderSurfaceH = rsgGetHeight();
-        int size = 8;
-        // draw each frame at (8, 3/4 gRenderSurfaceH) with size
-        drawOffscreenResult((drawPos+=size)%gRenderSurfaceW, (gRenderSurfaceH * 3) / 4, size, size);
-    }
-
-    rsgFinish();
-
-    int64_t end = rsUptimeMillis();
-    float fps = (float)(frameCount) / ((float)(end - start)*0.001f);
-    const char *testName = rsGetElementAt(gTestScripts[benchMode].debugName, 0);
-    rsDebug(testName, fps);
-
-    gResultBuffer[benchMode] = fps;
-    int bufferW = rsAllocationGetDimX(gRenderBufferColor);
-    int bufferH = rsAllocationGetDimY(gRenderBufferColor);
-
-    int quadW = gRenderSurfaceW / 2;
-    int quadH = (quadW * bufferH) / bufferW;
-    drawOffscreenResult(0, 0, quadW, quadH);
-
-    int left = 0, right = 0, top = 0, bottom = 0;
-    uint height = rsgGetHeight();
-    rsgFontColor(0.9f, 0.9f, 0.95f, 1.0f);
-    rsgBindFont(gFontSerif);
-    rsgMeasureText(gTestScripts[benchMode].testName, &left, &right, &top, &bottom);
-    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
-    rsgDrawText(gTestScripts[benchMode].testName, 2 -left, height - 2 + bottom);
-
-    if (benchmarkSingleTest) {
-        return;
-    }
-
-    benchMode ++;
-    int testCount = rsAllocationGetDimX(rsGetAllocation(gTestScripts));
-    if (benchMode == testCount) {
-        rsSendToClientBlocking(RS_MSG_RESULTS_READY, gResultBuffer, testCount*sizeof(float));
-        benchMode = 0;
-        runningLoops++;
-        if ((gMaxLoops > 0) && (runningLoops > gMaxLoops) && !sendMsgFlag) {
-            //Notifiy the test to stop and get results
-            rsDebug("gMaxLoops and runningLoops: ", gMaxLoops, runningLoops);
-            rsSendToClientBlocking(RS_MSG_TEST_DONE);
-            sendMsgFlag = true;
-        }
-    }
-}
-
-static void debug() {
-    gDt = rsGetDt();
-    runSubTest(benchMode);
-}
-
-int root(void) {
-    gRenderSurfaceW = rsgGetWidth();
-    gRenderSurfaceH = rsgGetHeight();
-    rsgClearColor(0.2f, 0.2f, 0.2f, 1.0f);
-    rsgClearDepth(1.0f);
-
-    if (!gLoadComplete) {
-        rsgFontColor(0.9f, 0.9f, 0.95f, 1.0f);
-        rsgBindFont(gFontSerif);
-        rsgDrawText("Loading", 50, 50);
-        return 0;
-    }
-
-    if(!checkInit()) {
-        return 1;
-    }
-
-    if (gPauseRendering) {
-        rsgDrawText("Paused", 50, 50);
-        return 30;
-    }
-    if (gIsDebugMode) {
-        debug();
-    } else {
-        benchmark();
-    }
-
-    return 1;
-}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/shader_def.rsh b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/shader_def.rsh
deleted file mode 100644
index 648359c..0000000
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/shader_def.rsh
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (C) 2009 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.perftest)
-
-typedef struct VertexShaderConstants_s {
-    rs_matrix4x4 model;
-    rs_matrix4x4 proj;
-    float4 light0_Posision;
-    float light0_Diffuse;
-    float light0_Specular;
-    float light0_CosinePower;
-
-    float4 light1_Posision;
-    float light1_Diffuse;
-    float light1_Specular;
-    float light1_CosinePower;
-} VertexShaderConstants;
-
-typedef struct VertexShaderConstants3_s {
-    rs_matrix4x4 model;
-    rs_matrix4x4 proj;
-    float time;
-} VertexShaderConstants3;
-
-
-typedef struct FragentShaderConstants_s {
-    float4 light0_DiffuseColor;
-    float4 light0_SpecularColor;
-
-    float4 light1_DiffuseColor;
-    float4 light1_SpecularColor;
-} FragentShaderConstants;
-
-typedef struct FragentShaderConstants2_s {
-    float4 light_DiffuseColor[2];
-    float4 light_SpecularColor[2];
-} FragentShaderConstants2;
-
-typedef struct FragentShaderConstants3_s {
-    float4 light0_DiffuseColor;
-    float4 light0_SpecularColor;
-    float4 light0_Posision;
-    float light0_Diffuse;
-    float light0_Specular;
-    float light0_CosinePower;
-
-    float4 light1_DiffuseColor;
-    float4 light1_SpecularColor;
-    float4 light1_Posision;
-    float light1_Diffuse;
-    float light1_Specular;
-    float light1_CosinePower;
-} FragentShaderConstants3;
-
-typedef struct VertexShaderInputs_s {
-    float4 position;
-    float3 normal;
-    float2 texture0;
-} VertexShaderInputs;
-
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/subtest_def.rsh b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/subtest_def.rsh
deleted file mode 100644
index 43658b1..0000000
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/subtest_def.rsh
+++ /dev/null
@@ -1,24 +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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.perftest)
-
-typedef struct TestData_s {
-    int renderSurfaceW;
-    int renderSurfaceH;
-    float dt;
-} TestData;
-
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs
deleted file mode 100644
index 0f50828..0000000
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs
+++ /dev/null
@@ -1,89 +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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.perftest)
-
-#include "rs_graphics.rsh"
-#include "subtest_def.rsh"
-
-rs_font gFontSans;
-rs_font gFontSerif;
-
-typedef struct TextTestData_s {
-    int fillNum;
-} TextTestData;
-TextTestData *gData;
-
-void init() {
-}
-
-static int gRenderSurfaceW = 1280;
-static int gRenderSurfaceH = 720;
-
-static const char *sampleText = "This is a sample of small text for performace";
-// Offsets for multiple layer of text
-static int textOffsets[] = { 0,  0, -5, -5, 5,  5, -8, -8, 8,  8};
-static float textColors[] = {1.0f, 1.0f, 1.0f, 1.0f,
-                             0.5f, 0.7f, 0.5f, 1.0f,
-                             0.7f, 0.5f, 0.5f, 1.0f,
-                             0.5f, 0.5f, 0.7f, 1.0f,
-                             0.5f, 0.6f, 0.7f, 1.0f,
-};
-
-static void displayFontSamples(int fillNum) {
-
-    rs_font fonts[5];
-    fonts[0] = gFontSans;
-    fonts[1] = gFontSerif;
-    fonts[2] = gFontSans;
-    fonts[3] = gFontSerif;
-    fonts[4] = gFontSans;
-
-    uint height = gRenderSurfaceH;
-    int left = 0, right = 0, top = 0, bottom = 0;
-    rsgMeasureText(sampleText, &left, &right, &top, &bottom);
-
-    int textHeight = top - bottom;
-    int textWidth = right - left;
-    int numVerticalLines = height / textHeight;
-    int yPos = top;
-
-    int xOffset = 0, yOffset = 0;
-    for(int fillI = 0; fillI < fillNum; fillI ++) {
-        rsgBindFont(fonts[fillI]);
-        xOffset = textOffsets[fillI * 2];
-        yOffset = textOffsets[fillI * 2 + 1];
-        float *colPtr = textColors + fillI * 4;
-        rsgFontColor(colPtr[0], colPtr[1], colPtr[2], colPtr[3]);
-        for (int h = 0; h < 4; h ++) {
-            yPos = top + yOffset;
-            for (int v = 0; v < numVerticalLines; v ++) {
-                rsgDrawText(sampleText, xOffset + textWidth * h, yPos);
-                yPos += textHeight;
-            }
-        }
-    }
-}
-
-void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
-    TestData *testData = (TestData*)usrData;
-    gRenderSurfaceW = testData->renderSurfaceW;
-    gRenderSurfaceH = testData->renderSurfaceH;
-
-    gData = (TextTestData*)v_in;
-
-    displayFontSamples(gData->fillNum);
-}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/torus_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/torus_test.rs
deleted file mode 100644
index 853a05d..0000000
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/torus_test.rs
+++ /dev/null
@@ -1,295 +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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.perftest)
-
-#include "rs_graphics.rsh"
-#include "subtest_def.rsh"
-#include "shader_def.rsh"
-
-rs_program_vertex gProgVertex;
-rs_program_fragment gProgFragmentColor;
-rs_program_fragment gProgFragmentTexture;
-
-rs_program_store gProgStoreBlendNoneDepth;
-rs_mesh gTorusMesh;
-
-rs_program_raster gCullBack;
-rs_program_raster gCullFront;
-
-// Custom vertex shader compunents
-VertexShaderConstants *gVSConstants;
-FragentShaderConstants *gFSConstants;
-VertexShaderConstants3 *gVSConstPixel;
-FragentShaderConstants3 *gFSConstPixel;
-
-// Custom shaders we use for lighting
-rs_program_vertex gProgVertexCustom;
-rs_program_fragment gProgFragmentCustom;
-
-rs_sampler gLinearClamp;
-rs_allocation gTexTorus;
-
-rs_program_vertex gProgVertexPixelLight;
-rs_program_vertex gProgVertexPixelLightMove;
-rs_program_fragment gProgFragmentPixelLight;
-
-typedef struct TorusTestData_s {
-    int testId;
-    int user1;
-    int user2;
-} TorusTestData;
-TorusTestData *gData;
-
-static float gDt = 0.0f;
-
-static int gRenderSurfaceW;
-static int gRenderSurfaceH;
-
-
-static float gTorusRotation = 0;
-static void updateModelMatrix(rs_matrix4x4 *matrix, void *buffer) {
-    if (buffer == 0) {
-        rsgProgramVertexLoadModelMatrix(matrix);
-    } else {
-        rsgAllocationSyncAll(rsGetAllocation(buffer));
-    }
-}
-
-static void drawToruses(int numMeshes, rs_matrix4x4 *matrix, void *buffer) {
-
-    if (numMeshes == 1) {
-        rsMatrixLoadTranslate(matrix, 0.0f, 0.0f, -7.5f);
-        rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
-        updateModelMatrix(matrix, buffer);
-        rsgDrawMesh(gTorusMesh);
-        return;
-    }
-
-    if (numMeshes == 2) {
-        rsMatrixLoadTranslate(matrix, -1.6f, 0.0f, -7.5f);
-        rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
-        updateModelMatrix(matrix, buffer);
-        rsgDrawMesh(gTorusMesh);
-
-        rsMatrixLoadTranslate(matrix, 1.6f, 0.0f, -7.5f);
-        rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
-        updateModelMatrix(matrix, buffer);
-        rsgDrawMesh(gTorusMesh);
-        return;
-    }
-
-    float startX = -5.0f;
-    float startY = -1.5f;
-    float startZ = -15.0f;
-    float dist = 3.2f;
-
-    for (int h = 0; h < 4; h ++) {
-        for (int v = 0; v < 2; v ++) {
-            // Position our model on the screen
-            rsMatrixLoadTranslate(matrix, startX + dist * h, startY + dist * v, startZ);
-            rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
-            updateModelMatrix(matrix, buffer);
-            rsgDrawMesh(gTorusMesh);
-        }
-    }
-}
-
-
-// Quick hack to get some geometry numbers
-static void displaySimpleGeoSamples(bool useTexture, int numMeshes) {
-    rsgBindProgramVertex(gProgVertex);
-    rsgBindProgramRaster(gCullBack);
-    // Setup the projection matrix with 30 degree field of view
-    rs_matrix4x4 proj;
-    float aspect = (float)gRenderSurfaceW / (float)gRenderSurfaceH;
-    rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f);
-    rsgProgramVertexLoadProjectionMatrix(&proj);
-
-    // Fragment shader with texture
-    rsgBindProgramStore(gProgStoreBlendNoneDepth);
-    if (useTexture) {
-        rsgBindProgramFragment(gProgFragmentTexture);
-    } else {
-        rsgBindProgramFragment(gProgFragmentColor);
-        rsgProgramFragmentConstantColor(gProgFragmentColor, 0.1, 0.7, 0.1, 1);
-    }
-    rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
-    rsgBindTexture(gProgFragmentTexture, 0, gTexTorus);
-
-    // Apply a rotation to our mesh
-    gTorusRotation += 50.0f * gDt;
-    if (gTorusRotation > 360.0f) {
-        gTorusRotation -= 360.0f;
-    }
-
-    rs_matrix4x4 matrix;
-    drawToruses(numMeshes, &matrix, 0);
-}
-
-float gLight0Rotation = 0;
-float gLight1Rotation = 0;
-
-static void setupCustomShaderLights() {
-    float4 light0Pos = {-5.0f, 5.0f, -10.0f, 1.0f};
-    float4 light1Pos = {2.0f, 5.0f, 15.0f, 1.0f};
-    float4 light0DiffCol = {0.9f, 0.7f, 0.7f, 1.0f};
-    float4 light0SpecCol = {0.9f, 0.6f, 0.6f, 1.0f};
-    float4 light1DiffCol = {0.5f, 0.5f, 0.9f, 1.0f};
-    float4 light1SpecCol = {0.5f, 0.5f, 0.9f, 1.0f};
-
-    gLight0Rotation += 50.0f * gDt;
-    if (gLight0Rotation > 360.0f) {
-        gLight0Rotation -= 360.0f;
-    }
-    gLight1Rotation -= 50.0f * gDt;
-    if (gLight1Rotation > 360.0f) {
-        gLight1Rotation -= 360.0f;
-    }
-
-    rs_matrix4x4 l0Mat;
-    rsMatrixLoadRotate(&l0Mat, gLight0Rotation, 1.0f, 0.0f, 0.0f);
-    light0Pos = rsMatrixMultiply(&l0Mat, light0Pos);
-    rs_matrix4x4 l1Mat;
-    rsMatrixLoadRotate(&l1Mat, gLight1Rotation, 0.0f, 0.0f, 1.0f);
-    light1Pos = rsMatrixMultiply(&l1Mat, light1Pos);
-
-    // Set light 0 properties
-    gVSConstants->light0_Posision = light0Pos;
-    gVSConstants->light0_Diffuse = 1.0f;
-    gVSConstants->light0_Specular = 0.5f;
-    gVSConstants->light0_CosinePower = 10.0f;
-    // Set light 1 properties
-    gVSConstants->light1_Posision = light1Pos;
-    gVSConstants->light1_Diffuse = 1.0f;
-    gVSConstants->light1_Specular = 0.7f;
-    gVSConstants->light1_CosinePower = 25.0f;
-    rsgAllocationSyncAll(rsGetAllocation(gVSConstants));
-
-    // Update fragment shader constants
-    // Set light 0 colors
-    gFSConstants->light0_DiffuseColor = light0DiffCol;
-    gFSConstants->light0_SpecularColor = light0SpecCol;
-    // Set light 1 colors
-    gFSConstants->light1_DiffuseColor = light1DiffCol;
-    gFSConstants->light1_SpecularColor = light1SpecCol;
-    rsgAllocationSyncAll(rsGetAllocation(gFSConstants));
-
-    // Set light 0 properties for per pixel lighting
-    gFSConstPixel->light0_Posision = light0Pos;
-    gFSConstPixel->light0_Diffuse = 1.0f;
-    gFSConstPixel->light0_Specular = 0.5f;
-    gFSConstPixel->light0_CosinePower = 10.0f;
-    gFSConstPixel->light0_DiffuseColor = light0DiffCol;
-    gFSConstPixel->light0_SpecularColor = light0SpecCol;
-    // Set light 1 properties
-    gFSConstPixel->light1_Posision = light1Pos;
-    gFSConstPixel->light1_Diffuse = 1.0f;
-    gFSConstPixel->light1_Specular = 0.7f;
-    gFSConstPixel->light1_CosinePower = 25.0f;
-    gFSConstPixel->light1_DiffuseColor = light1DiffCol;
-    gFSConstPixel->light1_SpecularColor = light1SpecCol;
-    rsgAllocationSyncAll(rsGetAllocation(gFSConstPixel));
-}
-
-static void displayCustomShaderSamples(int numMeshes) {
-
-    // Update vertex shader constants
-    // Load model matrix
-    // Apply a rotation to our mesh
-    gTorusRotation += 50.0f * gDt;
-    if (gTorusRotation > 360.0f) {
-        gTorusRotation -= 360.0f;
-    }
-
-    // Setup the projection matrix
-    float aspect = (float)gRenderSurfaceW / (float)gRenderSurfaceH;
-    rsMatrixLoadPerspective(&gVSConstants->proj, 30.0f, aspect, 0.1f, 100.0f);
-    setupCustomShaderLights();
-
-    rsgBindProgramVertex(gProgVertexCustom);
-
-    // Fragment shader with texture
-    rsgBindProgramStore(gProgStoreBlendNoneDepth);
-    rsgBindProgramFragment(gProgFragmentCustom);
-    rsgBindSampler(gProgFragmentCustom, 0, gLinearClamp);
-    rsgBindTexture(gProgFragmentCustom, 0, gTexTorus);
-
-    // Use back face culling
-    rsgBindProgramRaster(gCullBack);
-
-    drawToruses(numMeshes, &gVSConstants->model, gVSConstants);
-}
-
-static void displayPixelLightSamples(int numMeshes, bool heavyVertex) {
-
-    // Update vertex shader constants
-    // Load model matrix
-    // Apply a rotation to our mesh
-    gTorusRotation += 30.0f * gDt;
-    if (gTorusRotation > 360.0f) {
-        gTorusRotation -= 360.0f;
-    }
-
-    gVSConstPixel->time = rsUptimeMillis()*0.005;
-
-    // Setup the projection matrix
-    float aspect = (float)gRenderSurfaceW / (float)gRenderSurfaceH;
-    rsMatrixLoadPerspective(&gVSConstPixel->proj, 30.0f, aspect, 0.1f, 100.0f);
-    setupCustomShaderLights();
-
-    if (heavyVertex) {
-        rsgBindProgramVertex(gProgVertexPixelLightMove);
-    } else {
-        rsgBindProgramVertex(gProgVertexPixelLight);
-    }
-
-    // Fragment shader with texture
-    rsgBindProgramStore(gProgStoreBlendNoneDepth);
-    rsgBindProgramFragment(gProgFragmentPixelLight);
-    rsgBindSampler(gProgFragmentPixelLight, 0, gLinearClamp);
-    rsgBindTexture(gProgFragmentPixelLight, 0, gTexTorus);
-
-    // Use back face culling
-    rsgBindProgramRaster(gCullBack);
-
-    drawToruses(numMeshes, &gVSConstPixel->model, gVSConstPixel);
-}
-
-
-void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
-    TestData *testData = (TestData*)usrData;
-    gRenderSurfaceW = testData->renderSurfaceW;
-    gRenderSurfaceH = testData->renderSurfaceH;
-    gDt = testData->dt;
-
-    gData = (TorusTestData*)v_in;
-
-    switch(gData->testId) {
-        case 0:
-            displaySimpleGeoSamples(gData->user1 == 1 ? true : false, gData->user2);
-            break;
-        case 1:
-            displayCustomShaderSamples(gData->user1);
-            break;
-        case 2:
-            displayPixelLightSamples(gData->user1, gData->user2 == 1 ? true : false);
-            break;
-        default:
-            rsDebug("Wrong test number", gData->testId);
-            break;
-    }
-}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/ui_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/ui_test.rs
deleted file mode 100644
index e87db39..0000000
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/ui_test.rs
+++ /dev/null
@@ -1,442 +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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.perftest)
-
-#include "rs_graphics.rsh"
-#include "shader_def.rsh"
-#include "subtest_def.rsh"
-
-// Parameters for galaxy live wallpaper
-rs_allocation gTSpace;
-rs_allocation gTLight1;
-rs_allocation gTFlares;
-rs_mesh gParticlesMesh;
-
-rs_program_fragment gPFBackground;
-rs_program_fragment gPFStars;
-rs_program_vertex gPVStars;
-rs_program_vertex gPVBkProj;
-rs_program_store gPSLights;
-
-float gXOffset = 0.5f;
-
-#define ELLIPSE_RATIO 0.892f
-#define PI 3.1415f
-#define TWO_PI 6.283f
-#define ELLIPSE_TWIST 0.023333333f
-
-static float angle = 50.f;
-static int gOldWidth;
-static int gOldHeight;
-static int gWidth;
-static int gHeight;
-static float gSpeed[12000];
-static int gGalaxyRadius = 300;
-static rs_allocation gParticlesBuffer;
-
-typedef struct __attribute__((packed, aligned(4))) Particle {
-    uchar4 color;
-    float3 position;
-} Particle_t;
-Particle_t *Particles;
-
-typedef struct VpConsts {
-    rs_matrix4x4 Proj;
-    rs_matrix4x4 MVP;
-} VpConsts_t;
-VpConsts_t *vpConstants;
-// End of parameters for galaxy live wallpaper
-
-rs_program_vertex gProgVertex;
-rs_program_fragment gProgFragmentColor;
-rs_program_fragment gProgFragmentTexture;
-
-rs_program_store gProgStoreBlendAlpha;
-
-rs_allocation gTexOpaque;
-rs_allocation gTexTorus;
-rs_allocation gTexGlobe;
-
-typedef struct ListAllocs_s {
-    rs_allocation item;
-} ListAllocs;
-
-ListAllocs *gTexList100;
-ListAllocs *gSampleTextList100;
-ListAllocs *gListViewText;
-
-rs_mesh gSingleMesh;
-
-rs_font gFontSans;
-
-rs_sampler gLinearClamp;
-
-typedef struct UiTestData_s {
-    int testId;
-    int user1;
-    int user2;
-    int user3;
-} UiTestData;
-UiTestData *gData;
-
-static float gDt = 0;
-
-
-void init() {
-}
-
-static int gRenderSurfaceW;
-static int gRenderSurfaceH;
-
-static void bindProgramVertexOrtho() {
-    // Default vertex shader
-    rsgBindProgramVertex(gProgVertex);
-    // Setup the projection matrix
-    rs_matrix4x4 proj;
-    rsMatrixLoadOrtho(&proj, 0, gRenderSurfaceW, gRenderSurfaceH, 0, -500, 500);
-    rsgProgramVertexLoadProjectionMatrix(&proj);
-}
-
-/**
-  * Methods to draw the galaxy live wall paper
-  */
-static float mapf(float minStart, float minStop, float maxStart, float maxStop, float value) {
-    return maxStart + (maxStart - maxStop) * ((value - minStart) / (minStop - minStart));
-}
-
-/**
- * Helper function to generate the stars.
- */
-static float randomGauss() {
-    float x1;
-    float x2;
-    float w = 2.f;
-
-    while (w >= 1.0f) {
-        x1 = rsRand(2.0f) - 1.0f;
-        x2 = rsRand(2.0f) - 1.0f;
-        w = x1 * x1 + x2 * x2;
-    }
-
-    w = sqrt(-2.0f * log(w) / w);
-    return x1 * w;
-}
-
-/**
- * Generates the properties for a given star.
- */
-static void createParticle(Particle_t *part, int idx, float scale) {
-    float d = fabs(randomGauss()) * gGalaxyRadius * 0.5f + rsRand(64.0f);
-    float id = d / gGalaxyRadius;
-    float z = randomGauss() * 0.4f * (1.0f - id);
-
-    if (d < gGalaxyRadius * 0.33f) {
-        part->color.x = (uchar) (220 + id * 35);
-        part->color.y = 220;
-        part->color.z = 220;
-    } else {
-        part->color.x = 180;
-        part->color.y = 180;
-        part->color.z = (uchar) clamp(140.f + id * 115.f, 140.f, 255.f);
-    }
-    // Stash point size * 10 in Alpha
-    part->color.w = (uchar) (rsRand(1.2f, 2.1f) * 60);
-
-    if (d > gGalaxyRadius * 0.15f) {
-        z *= 0.6f * (1.0f - id);
-    } else {
-        z *= 0.72f;
-    }
-
-    // Map to the projection coordinates (viewport.x = -1.0 -> 1.0)
-    d = mapf(-4.0f, gGalaxyRadius + 4.0f, 0.0f, scale, d);
-
-    part->position.x = rsRand(TWO_PI);
-    part->position.y = d;
-    gSpeed[idx] = rsRand(0.0015f, 0.0025f) * (0.5f + (scale / d)) * 0.8f;
-
-    part->position.z = z / 5.0f;
-}
-
-/**
- * Initialize all the starts, called from Java
- */
-void initParticles() {
-    Particle_t *part = Particles;
-    float scale = gGalaxyRadius / (gWidth * 0.5f);
-    int count = rsAllocationGetDimX(gParticlesBuffer);
-    for (int i = 0; i < count; i ++) {
-        createParticle(part, i, scale);
-        part++;
-    }
-}
-
-static void drawSpace() {
-    rsgBindProgramFragment(gPFBackground);
-    rsgBindTexture(gPFBackground, 0, gTSpace);
-    rsgDrawQuadTexCoords(
-            0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-            gWidth, 0.0f, 0.0f, 2.0f, 1.0f,
-            gWidth, gHeight, 0.0f, 2.0f, 0.0f,
-            0.0f, gHeight, 0.0f, 0.0f, 0.0f);
-}
-
-static void drawLights() {
-    rsgBindProgramVertex(gPVBkProj);
-    rsgBindProgramFragment(gPFBackground);
-    rsgBindTexture(gPFBackground, 0, gTLight1);
-
-    float scale = 512.0f / gWidth;
-    float x = -scale - scale * 0.05f;
-    float y = -scale;
-
-    scale *= 2.0f;
-
-    rsgDrawQuad(x, y, 0.0f,
-             x + scale * 1.1f, y, 0.0f,
-             x + scale * 1.1f, y + scale, 0.0f,
-             x, y + scale, 0.0f);
-}
-
-static void drawParticles(float offset) {
-    float a = offset * angle;
-    float absoluteAngle = fabs(a);
-
-    rs_matrix4x4 matrix;
-    rsMatrixLoadTranslate(&matrix, 0.0f, 0.0f, 10.0f - 6.0f * absoluteAngle / 50.0f);
-    if (gHeight > gWidth) {
-        rsMatrixScale(&matrix, 6.6f, 6.0f, 1.0f);
-    } else {
-        rsMatrixScale(&matrix, 12.6f, 12.0f, 1.0f);
-    }
-    rsMatrixRotate(&matrix, absoluteAngle, 1.0f, 0.0f, 0.0f);
-    rsMatrixRotate(&matrix, a, 0.0f, 0.4f, 0.1f);
-    rsMatrixLoad(&vpConstants->MVP, &vpConstants->Proj);
-    rsMatrixMultiply(&vpConstants->MVP, &matrix);
-    rsgAllocationSyncAll(rsGetAllocation(vpConstants));
-
-    rsgBindProgramVertex(gPVStars);
-    rsgBindProgramFragment(gPFStars);
-    rsgBindProgramStore(gPSLights);
-    rsgBindTexture(gPFStars, 0, gTFlares);
-
-    Particle_t *vtx = Particles;
-    int count = rsAllocationGetDimX(gParticlesBuffer);
-    for (int i = 0; i < count; i++) {
-        vtx->position.x = vtx->position.x + gSpeed[i];
-        vtx++;
-    }
-
-    rsgDrawMesh(gParticlesMesh);
-}
-/* end of methods for drawing galaxy */
-
-// Display sample images in a mesh with different texture
-static void displayIcons(int meshMode) {
-    bindProgramVertexOrtho();
-
-    // Fragment shader with texture
-    rsgBindProgramStore(gProgStoreBlendAlpha);
-    rsgBindProgramFragment(gProgFragmentTexture);
-    rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
-    rsgBindTexture(gProgFragmentTexture, 0, gTexTorus);
-    rsgDrawQuadTexCoords(
-            0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-            0.0f, gRenderSurfaceH, 0.0f, 0.0f, 1.0f,
-            gRenderSurfaceW, gRenderSurfaceH, 0.0f, 1.0f, 1.0f,
-            gRenderSurfaceW, 0.0f, 0.0f, 1.0f, 0.0f);
-
-    int meshCount = (int)pow(10.0f, (float)(meshMode + 1));
-
-    float wSize = gRenderSurfaceW/(float)meshCount;
-    float hSize = gRenderSurfaceH/(float)meshCount;
-    rs_matrix4x4 matrix;
-    rsMatrixLoadScale(&matrix, wSize, hSize, 1.0);
-
-    float yPos = 0;
-    float yPad = hSize / 2;
-    float xPad = wSize / 2;
-    for (int y = 0; y < meshCount; y++) {
-        yPos = y * hSize + yPad;
-        float xPos = 0;
-        for (int x = 0; x < meshCount; x++) {
-            xPos = x * wSize + xPad;
-            rs_matrix4x4 transMatrix;
-            rsMatrixLoadTranslate(&transMatrix, xPos, yPos, 0);
-            rsMatrixMultiply(&transMatrix, &matrix);
-            rsgProgramVertexLoadModelMatrix(&transMatrix);
-            int i = (x + y * meshCount) % 100;
-            rsgBindTexture(gProgFragmentTexture, 0, gTexList100[i].item);
-            rsgDrawMesh(gSingleMesh);
-        }
-    }
-}
-
-// Draw meshes in a single page with top left corner coordinates (xStart, yStart)
-static void drawMeshInPage(float xStart, float yStart, int wResolution, int hResolution) {
-    // Draw wResolution * hResolution meshes in one page
-    float wMargin = 100.0f;
-    float hMargin = 100.0f;
-    float xPad = 50.0f;
-    float yPad = 20.0f;
-    float size = 100.0f;  // size of images
-
-    // font info
-    rs_font font = gFontSans;
-    rsgBindFont(font);
-    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
-
-    // Measure text size
-    int left = 0, right = 0, top = 0, bottom = 0;
-    rsgMeasureText(gSampleTextList100[0].item, &left, &right, &top, &bottom);
-    float textHeight = (float)(top - bottom);
-
-    rs_matrix4x4 matrix;
-    rsMatrixLoadScale(&matrix, size, size, 1.0);
-
-    for (int y = 0; y < hResolution; y++) {
-        float yPos = yStart + hMargin + y * size + y * yPad;
-        for (int x = 0; x < wResolution; x++) {
-            float xPos = xStart + wMargin + x * size + x * xPad;
-
-            rs_matrix4x4 transMatrix;
-            rsMatrixLoadTranslate(&transMatrix, xPos + size/2, yPos + size/2, 0);
-            rsMatrixMultiply(&transMatrix, &matrix);  // scale the mesh
-            rsgProgramVertexLoadModelMatrix(&transMatrix);
-
-            int i = (y * wResolution + x) % 100;
-            rsgBindTexture(gProgFragmentTexture, 0, gTexList100[i].item);
-            rsgDrawMesh(gSingleMesh);
-            rsgDrawText(gSampleTextList100[i].item, xPos, yPos + size + yPad/2 + textHeight);
-        }
-    }
-}
-
-// Display both images and text as shown in launcher and homepage
-// meshMode will decide how many pages we draw
-// meshMode = 0: draw 3 pages of meshes
-// meshMode = 1: draw 5 pages of meshes
-static void displayImageWithText(int wResolution, int hResolution, int meshMode) {
-    bindProgramVertexOrtho();
-
-    // Fragment shader with texture
-    rsgBindProgramStore(gProgStoreBlendAlpha);
-    rsgBindProgramFragment(gProgFragmentTexture);
-    rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
-
-    drawMeshInPage(0, 0, wResolution, hResolution);
-    drawMeshInPage(-1.0f*gRenderSurfaceW, 0, wResolution, hResolution);
-    drawMeshInPage(1.0f*gRenderSurfaceW, 0, wResolution, hResolution);
-    if (meshMode == 1) {
-        // draw another two pages of meshes
-        drawMeshInPage(-2.0f*gRenderSurfaceW, 0, wResolution, hResolution);
-        drawMeshInPage(2.0f*gRenderSurfaceW, 0, wResolution, hResolution);
-    }
-}
-
-// Display a list of text as the list view
-static void displayListView() {
-    // set text color
-    rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f);
-    rsgBindFont(gFontSans);
-
-    // get the size of the list
-    rs_allocation textAlloc;
-    textAlloc = rsGetAllocation(gListViewText);
-    int allocSize = rsAllocationGetDimX(textAlloc);
-
-    int listItemHeight = 80;
-    int yOffset = listItemHeight;
-
-    // set the color for the list divider
-    rsgBindProgramFragment(gProgFragmentColor);
-    rsgProgramFragmentConstantColor(gProgFragmentColor, 1.0, 1.0, 1.0, 1);
-
-    // draw the list with divider
-    for (int i = 0; i < allocSize; i++) {
-        if (yOffset - listItemHeight > gRenderSurfaceH) {
-            break;
-        }
-        rsgDrawRect(0, yOffset - 1, gRenderSurfaceW, yOffset, 0);
-        rsgDrawText(gListViewText[i].item, 20, yOffset - 10);
-        yOffset += listItemHeight;
-    }
-}
-
-static void drawGalaxy() {
-    rsgClearColor(0.f, 0.f, 0.f, 1.f);
-    gParticlesBuffer = rsGetAllocation(Particles);
-    rsgBindProgramFragment(gPFBackground);
-
-    gWidth = rsgGetWidth();
-    gHeight = rsgGetHeight();
-    if ((gWidth != gOldWidth) || (gHeight != gOldHeight)) {
-        initParticles();
-        gOldWidth = gWidth;
-        gOldHeight = gHeight;
-    }
-
-    float offset = mix(-1.0f, 1.0f, gXOffset);
-    drawSpace();
-    drawParticles(offset);
-    drawLights();
-}
-
-// Display images and text with live wallpaper in the background
-static void displayLiveWallPaper(int wResolution, int hResolution) {
-    bindProgramVertexOrtho();
-
-    drawGalaxy();
-
-    rsgBindProgramVertex(gProgVertex);
-    rsgBindProgramStore(gProgStoreBlendAlpha);
-    rsgBindProgramFragment(gProgFragmentTexture);
-    rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
-
-    drawMeshInPage(0, 0, wResolution, hResolution);
-    drawMeshInPage(-1.0f*gRenderSurfaceW, 0, wResolution, hResolution);
-    drawMeshInPage(1.0f*gRenderSurfaceW, 0, wResolution, hResolution);
-    drawMeshInPage(-2.0f*gRenderSurfaceW, 0, wResolution, hResolution);
-    drawMeshInPage(2.0f*gRenderSurfaceW, 0, wResolution, hResolution);
-}
-
-void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
-    TestData *testData = (TestData*)usrData;
-    gRenderSurfaceW = testData->renderSurfaceW;
-    gRenderSurfaceH = testData->renderSurfaceH;
-    gDt = testData->dt;
-
-    gData = (UiTestData*)v_in;
-
-    switch(gData->testId) {
-        case 0:
-            displayIcons(gData->user1);
-            break;
-        case 1:
-            displayImageWithText(gData->user1, gData->user2, gData->user3);
-            break;
-        case 2:
-            displayListView();
-            break;
-        case 3:
-            displayLiveWallPaper(gData->user1, gData->user2);
-            break;
-        default:
-            rsDebug("Wrong test number", 0);
-            break;
-    }
-}
diff --git a/tests/RenderScriptTests/SceneGraph/Android.mk b/tests/RenderScriptTests/SceneGraph/Android.mk
deleted file mode 100644
index 6047305..0000000
--- a/tests/RenderScriptTests/SceneGraph/Android.mk
+++ /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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-
-LOCAL_SDK_VERSION := 17
-
-LOCAL_PACKAGE_NAME := SceneGraphTest
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/SceneGraph/AndroidManifest.xml b/tests/RenderScriptTests/SceneGraph/AndroidManifest.xml
deleted file mode 100644
index 67af0fa..0000000
--- a/tests/RenderScriptTests/SceneGraph/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.testapp">
-    <uses-permission
-        android:name="android.permission.INTERNET" />
-    <application android:label="SceneGraphTest">
-        <activity android:name="TestApp"
-                  android:label="SceneGraphTest">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-        <activity android:name="SimpleApp"
-                  android:label="SimpleSceneGraph">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-        <activity android:name="FileSelector"
-                  android:label="FileSelector"
-                  android:hardwareAccelerated="true">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/SceneGraph/assets/blue.jpg b/tests/RenderScriptTests/SceneGraph/assets/blue.jpg
deleted file mode 100644
index 494e77a..0000000
--- a/tests/RenderScriptTests/SceneGraph/assets/blue.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/carbonfiber.jpg b/tests/RenderScriptTests/SceneGraph/assets/carbonfiber.jpg
deleted file mode 100644
index 2fcecb0..0000000
--- a/tests/RenderScriptTests/SceneGraph/assets/carbonfiber.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/green.jpg b/tests/RenderScriptTests/SceneGraph/assets/green.jpg
deleted file mode 100644
index a86a754..0000000
--- a/tests/RenderScriptTests/SceneGraph/assets/green.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/grey.jpg b/tests/RenderScriptTests/SceneGraph/assets/grey.jpg
deleted file mode 100644
index 5870b1a..0000000
--- a/tests/RenderScriptTests/SceneGraph/assets/grey.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/orange.jpg b/tests/RenderScriptTests/SceneGraph/assets/orange.jpg
deleted file mode 100644
index 7dbe942..0000000
--- a/tests/RenderScriptTests/SceneGraph/assets/orange.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/orientation_test.a3d b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.a3d
deleted file mode 100644
index 07318ae..0000000
--- a/tests/RenderScriptTests/SceneGraph/assets/orientation_test.a3d
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/orientation_test.dae b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.dae
deleted file mode 100644
index 7eef443..0000000
--- a/tests/RenderScriptTests/SceneGraph/assets/orientation_test.dae
+++ /dev/null
@@ -1,1102 +0,0 @@
-<?xml version="1.0" ?>
-<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
-    <asset>
-        <contributor>
-            <author>alexst</author>
-            <authoring_tool>OpenCOLLADA2010</authoring_tool>
-            <comments>ColladaMaya export options: bakeTransforms=0;relativePaths=0;copyTextures=0;exportTriangles=1;exportCgfxFileReferences=0; isSampling=0;curveConstrainSampling=0;removeStaticCurves=1;exportPolygonMeshes=1;exportLights=1; exportCameras=1;exportJointsAndSkin=1;exportAnimations=0;exportInvisibleNodes=0;exportDefaultCameras=0; exportTexCoords=1;exportNormals=1;exportNormalsPerVertex=1;exportVertexColors=0;exportVertexColorsPerVertex=0; exportTexTangents=0;exportTangents=0;exportReferencedMaterials=1;exportMaterialsOnly=0; exportXRefs=1;dereferenceXRefs=1;exportCameraAsLookat=0;cameraXFov=0;cameraYFov=1;doublePrecision=0</comments>
-            <source_data>file:///Volumes/Android/art/orientation_test.mb</source_data>
-        </contributor>
-        <created>2011-09-30T15:31:38</created>
-        <modified>2011-09-30T15:31:38</modified>
-        <unit meter="0.01" name="centimeter" />
-        <up_axis>Y_UP</up_axis>
-    </asset>
-    <library_cameras>
-        <camera id="cameraShape1" name="cameraShape1">
-            <optics>
-                <technique_common>
-                    <perspective>
-                        <yfov>37.8493</yfov>
-                        <aspect_ratio>1.5</aspect_ratio>
-                        <znear>1</znear>
-                        <zfar>400</zfar>
-                    </perspective>
-                </technique_common>
-            </optics>
-            <extra>
-                <technique profile="OpenCOLLADAMaya">
-                    <film_fit>0</film_fit>
-                    <film_fit_offset>0</film_fit_offset>
-                    <film_offsetX>0</film_offsetX>
-                    <film_offsetY>0</film_offsetY>
-                    <horizontal_aperture>3.599993</horizontal_aperture>
-                    <lens_squeeze>1</lens_squeeze>
-                    <originalMayaNodeId>cameraShape1</originalMayaNodeId>
-                    <vertical_aperture>2.399995</vertical_aperture>
-                </technique>
-            </extra>
-        </camera>
-        <camera id="CameraDistShape" name="CameraDistShape">
-            <optics>
-                <technique_common>
-                    <perspective>
-                        <yfov>37.8493</yfov>
-                        <aspect_ratio>1.5</aspect_ratio>
-                        <znear>1</znear>
-                        <zfar>1000</zfar>
-                    </perspective>
-                </technique_common>
-            </optics>
-            <extra>
-                <technique profile="OpenCOLLADAMaya">
-                    <film_fit>0</film_fit>
-                    <film_fit_offset>0</film_fit_offset>
-                    <film_offsetX>0</film_offsetX>
-                    <film_offsetY>0</film_offsetY>
-                    <horizontal_aperture>3.599993</horizontal_aperture>
-                    <lens_squeeze>1</lens_squeeze>
-                    <originalMayaNodeId>CameraDistShape</originalMayaNodeId>
-                    <vertical_aperture>2.399995</vertical_aperture>
-                </technique>
-            </extra>
-        </camera>
-    </library_cameras>
-    <library_materials>
-        <material id="Paint1" name="Paint1">
-            <instance_effect url="#Paint1-fx" />
-        </material>
-        <material id="lambert2" name="lambert2">
-            <instance_effect url="#lambert2-fx" />
-        </material>
-        <material id="Plastic" name="Plastic">
-            <instance_effect url="#Plastic-fx" />
-        </material>
-        <material id="Metal" name="Metal">
-            <instance_effect url="#Metal-fx" />
-        </material>
-        <material id="PlasticCenter" name="PlasticCenter">
-            <instance_effect url="#PlasticCenter-fx" />
-        </material>
-        <material id="PlasticRed" name="PlasticRed">
-            <instance_effect url="#PlasticRed-fx" />
-        </material>
-        <material id="lambert10" name="lambert10">
-            <instance_effect url="#lambert10-fx" />
-        </material>
-        <material id="lambert11" name="lambert11">
-            <instance_effect url="#lambert11-fx" />
-        </material>
-    </library_materials>
-    <library_effects>
-        <effect id="Metal-fx">
-            <profile_COMMON>
-                <newparam sid="file23-surface">
-                    <surface type="2D">
-                        <init_from>file23</init_from>
-                    </surface>
-                </newparam>
-                <newparam sid="file23-sampler">
-                    <sampler2D>
-                        <source>file23-surface</source>
-                    </sampler2D>
-                </newparam>
-                <technique sid="common">
-                    <lambert>
-                        <emission>
-                            <color>0 0 0 1</color>
-                        </emission>
-                        <ambient>
-                            <color>0 0 0 1</color>
-                        </ambient>
-                        <diffuse>
-                            <texture texture="file23-sampler" texcoord="TEX0">
-                                <extra>
-                                    <technique profile="OpenCOLLADAMaya">
-                                        <blend_mode>NONE</blend_mode>
-                                        <coverageU>1</coverageU>
-                                        <coverageV>1</coverageV>
-                                        <fast>0</fast>
-                                        <mirrorU>0</mirrorU>
-                                        <mirrorV>0</mirrorV>
-                                        <noiseU>0</noiseU>
-                                        <noiseV>0</noiseV>
-                                        <offsetU>0</offsetU>
-                                        <offsetV>0</offsetV>
-                                        <repeatU>1</repeatU>
-                                        <repeatV>1</repeatV>
-                                        <rotateFrame>0</rotateFrame>
-                                        <rotateUV>0</rotateUV>
-                                        <stagger>0</stagger>
-                                        <translateFrameU>0</translateFrameU>
-                                        <translateFrameV>0</translateFrameV>
-                                        <wrapU>1</wrapU>
-                                        <wrapV>1</wrapV>
-                                    </technique>
-                                </extra>
-                            </texture>
-                        </diffuse>
-                        <transparent opaque="RGB_ZERO">
-                            <color>0 0 0 1</color>
-                        </transparent>
-                        <transparency>
-                            <float>1</float>
-                        </transparency>
-                    </lambert>
-                </technique>
-            </profile_COMMON>
-        </effect>
-        <effect id="Paint1-fx">
-            <profile_COMMON>
-                <newparam sid="file25-surface">
-                    <surface type="2D">
-                        <init_from>file25</init_from>
-                    </surface>
-                </newparam>
-                <newparam sid="file25-sampler">
-                    <sampler2D>
-                        <source>file25-surface</source>
-                    </sampler2D>
-                </newparam>
-                <technique sid="common">
-                    <lambert>
-                        <emission>
-                            <color>0 0 0 1</color>
-                        </emission>
-                        <ambient>
-                            <color>0 0 0 1</color>
-                        </ambient>
-                        <diffuse>
-                            <texture texture="file25-sampler" texcoord="TEX0">
-                                <extra>
-                                    <technique profile="OpenCOLLADAMaya">
-                                        <blend_mode>NONE</blend_mode>
-                                        <coverageU>1</coverageU>
-                                        <coverageV>1</coverageV>
-                                        <fast>0</fast>
-                                        <mirrorU>0</mirrorU>
-                                        <mirrorV>0</mirrorV>
-                                        <noiseU>0</noiseU>
-                                        <noiseV>0</noiseV>
-                                        <offsetU>0</offsetU>
-                                        <offsetV>0</offsetV>
-                                        <repeatU>1</repeatU>
-                                        <repeatV>1</repeatV>
-                                        <rotateFrame>0</rotateFrame>
-                                        <rotateUV>0</rotateUV>
-                                        <stagger>0</stagger>
-                                        <translateFrameU>0</translateFrameU>
-                                        <translateFrameV>0</translateFrameV>
-                                        <wrapU>1</wrapU>
-                                        <wrapV>1</wrapV>
-                                    </technique>
-                                </extra>
-                            </texture>
-                        </diffuse>
-                        <transparent opaque="RGB_ZERO">
-                            <color>0 0 0 1</color>
-                        </transparent>
-                        <transparency>
-                            <float>1</float>
-                        </transparency>
-                    </lambert>
-                </technique>
-            </profile_COMMON>
-        </effect>
-        <effect id="Plastic-fx">
-            <profile_COMMON>
-                <newparam sid="file24-surface">
-                    <surface type="2D">
-                        <init_from>file24</init_from>
-                    </surface>
-                </newparam>
-                <newparam sid="file24-sampler">
-                    <sampler2D>
-                        <source>file24-surface</source>
-                    </sampler2D>
-                </newparam>
-                <technique sid="common">
-                    <lambert>
-                        <emission>
-                            <color>0 0 0 1</color>
-                        </emission>
-                        <ambient>
-                            <color>0 0 0 1</color>
-                        </ambient>
-                        <diffuse>
-                            <texture texture="file24-sampler" texcoord="TEX0">
-                                <extra>
-                                    <technique profile="OpenCOLLADAMaya">
-                                        <blend_mode>NONE</blend_mode>
-                                        <coverageU>1</coverageU>
-                                        <coverageV>1</coverageV>
-                                        <fast>0</fast>
-                                        <mirrorU>0</mirrorU>
-                                        <mirrorV>0</mirrorV>
-                                        <noiseU>0</noiseU>
-                                        <noiseV>0</noiseV>
-                                        <offsetU>0</offsetU>
-                                        <offsetV>0</offsetV>
-                                        <repeatU>1</repeatU>
-                                        <repeatV>1</repeatV>
-                                        <rotateFrame>0</rotateFrame>
-                                        <rotateUV>0</rotateUV>
-                                        <stagger>0</stagger>
-                                        <translateFrameU>0</translateFrameU>
-                                        <translateFrameV>0</translateFrameV>
-                                        <wrapU>1</wrapU>
-                                        <wrapV>1</wrapV>
-                                    </technique>
-                                </extra>
-                            </texture>
-                        </diffuse>
-                        <transparent opaque="RGB_ZERO">
-                            <color>0 0 0 1</color>
-                        </transparent>
-                        <transparency>
-                            <float>1</float>
-                        </transparency>
-                    </lambert>
-                </technique>
-            </profile_COMMON>
-        </effect>
-        <effect id="PlasticCenter-fx">
-            <profile_COMMON>
-                <newparam sid="file24-surface">
-                    <surface type="2D">
-                        <init_from>file24</init_from>
-                    </surface>
-                </newparam>
-                <newparam sid="file24-sampler">
-                    <sampler2D>
-                        <source>file24-surface</source>
-                    </sampler2D>
-                </newparam>
-                <technique sid="common">
-                    <lambert>
-                        <emission>
-                            <color>0 0 0 1</color>
-                        </emission>
-                        <ambient>
-                            <color>0 0 0 1</color>
-                        </ambient>
-                        <diffuse>
-                            <texture texture="file24-sampler" texcoord="TEX0">
-                                <extra>
-                                    <technique profile="OpenCOLLADAMaya">
-                                        <blend_mode>NONE</blend_mode>
-                                        <coverageU>1</coverageU>
-                                        <coverageV>1</coverageV>
-                                        <fast>0</fast>
-                                        <mirrorU>0</mirrorU>
-                                        <mirrorV>0</mirrorV>
-                                        <noiseU>0</noiseU>
-                                        <noiseV>0</noiseV>
-                                        <offsetU>0</offsetU>
-                                        <offsetV>0</offsetV>
-                                        <repeatU>1</repeatU>
-                                        <repeatV>1</repeatV>
-                                        <rotateFrame>0</rotateFrame>
-                                        <rotateUV>0</rotateUV>
-                                        <stagger>0</stagger>
-                                        <translateFrameU>0</translateFrameU>
-                                        <translateFrameV>0</translateFrameV>
-                                        <wrapU>1</wrapU>
-                                        <wrapV>1</wrapV>
-                                    </technique>
-                                </extra>
-                            </texture>
-                        </diffuse>
-                        <transparent opaque="RGB_ZERO">
-                            <color>0 0 0 1</color>
-                        </transparent>
-                        <transparency>
-                            <float>1</float>
-                        </transparency>
-                    </lambert>
-                </technique>
-            </profile_COMMON>
-        </effect>
-        <effect id="PlasticRed-fx">
-            <profile_COMMON>
-                <newparam sid="file23-surface">
-                    <surface type="2D">
-                        <init_from>file23</init_from>
-                    </surface>
-                </newparam>
-                <newparam sid="file23-sampler">
-                    <sampler2D>
-                        <source>file23-surface</source>
-                    </sampler2D>
-                </newparam>
-                <technique sid="common">
-                    <lambert>
-                        <emission>
-                            <color>0 0 0 1</color>
-                        </emission>
-                        <ambient>
-                            <color>0 0 0 1</color>
-                        </ambient>
-                        <diffuse>
-                            <texture texture="file23-sampler" texcoord="TEX0">
-                                <extra>
-                                    <technique profile="OpenCOLLADAMaya">
-                                        <blend_mode>NONE</blend_mode>
-                                        <coverageU>1</coverageU>
-                                        <coverageV>1</coverageV>
-                                        <fast>0</fast>
-                                        <mirrorU>0</mirrorU>
-                                        <mirrorV>0</mirrorV>
-                                        <noiseU>0</noiseU>
-                                        <noiseV>0</noiseV>
-                                        <offsetU>0</offsetU>
-                                        <offsetV>0</offsetV>
-                                        <repeatU>1</repeatU>
-                                        <repeatV>1</repeatV>
-                                        <rotateFrame>0</rotateFrame>
-                                        <rotateUV>0</rotateUV>
-                                        <stagger>0</stagger>
-                                        <translateFrameU>0</translateFrameU>
-                                        <translateFrameV>0</translateFrameV>
-                                        <wrapU>1</wrapU>
-                                        <wrapV>1</wrapV>
-                                    </technique>
-                                </extra>
-                            </texture>
-                        </diffuse>
-                        <transparent opaque="RGB_ZERO">
-                            <color>0 0 0 1</color>
-                        </transparent>
-                        <transparency>
-                            <float>1</float>
-                        </transparency>
-                    </lambert>
-                </technique>
-            </profile_COMMON>
-        </effect>
-        <effect id="lambert10-fx">
-            <profile_COMMON>
-                <newparam sid="file28-surface">
-                    <surface type="2D">
-                        <init_from>file28</init_from>
-                    </surface>
-                </newparam>
-                <newparam sid="file28-sampler">
-                    <sampler2D>
-                        <source>file28-surface</source>
-                    </sampler2D>
-                </newparam>
-                <technique sid="common">
-                    <lambert>
-                        <emission>
-                            <color>0 0 0 1</color>
-                        </emission>
-                        <ambient>
-                            <color>0 0 0 1</color>
-                        </ambient>
-                        <diffuse>
-                            <texture texture="file28-sampler" texcoord="TEX0">
-                                <extra>
-                                    <technique profile="OpenCOLLADAMaya">
-                                        <blend_mode>NONE</blend_mode>
-                                        <coverageU>1</coverageU>
-                                        <coverageV>1</coverageV>
-                                        <fast>0</fast>
-                                        <mirrorU>0</mirrorU>
-                                        <mirrorV>0</mirrorV>
-                                        <noiseU>0</noiseU>
-                                        <noiseV>0</noiseV>
-                                        <offsetU>0</offsetU>
-                                        <offsetV>0</offsetV>
-                                        <repeatU>1</repeatU>
-                                        <repeatV>1</repeatV>
-                                        <rotateFrame>0</rotateFrame>
-                                        <rotateUV>0</rotateUV>
-                                        <stagger>0</stagger>
-                                        <translateFrameU>0</translateFrameU>
-                                        <translateFrameV>0</translateFrameV>
-                                        <wrapU>1</wrapU>
-                                        <wrapV>1</wrapV>
-                                    </technique>
-                                </extra>
-                            </texture>
-                        </diffuse>
-                        <transparent opaque="RGB_ZERO">
-                            <color>0 0 0 1</color>
-                        </transparent>
-                        <transparency>
-                            <float>1</float>
-                        </transparency>
-                    </lambert>
-                </technique>
-            </profile_COMMON>
-        </effect>
-        <effect id="lambert11-fx">
-            <profile_COMMON>
-                <newparam sid="file29-surface">
-                    <surface type="2D">
-                        <init_from>file29</init_from>
-                    </surface>
-                </newparam>
-                <newparam sid="file29-sampler">
-                    <sampler2D>
-                        <source>file29-surface</source>
-                    </sampler2D>
-                </newparam>
-                <technique sid="common">
-                    <lambert>
-                        <emission>
-                            <color>0 0 0 1</color>
-                        </emission>
-                        <ambient>
-                            <color>0 0 0 1</color>
-                        </ambient>
-                        <diffuse>
-                            <texture texture="file29-sampler" texcoord="TEX0">
-                                <extra>
-                                    <technique profile="OpenCOLLADAMaya">
-                                        <blend_mode>NONE</blend_mode>
-                                        <coverageU>1</coverageU>
-                                        <coverageV>1</coverageV>
-                                        <fast>0</fast>
-                                        <mirrorU>0</mirrorU>
-                                        <mirrorV>0</mirrorV>
-                                        <noiseU>0</noiseU>
-                                        <noiseV>0</noiseV>
-                                        <offsetU>0</offsetU>
-                                        <offsetV>0</offsetV>
-                                        <repeatU>1</repeatU>
-                                        <repeatV>1</repeatV>
-                                        <rotateFrame>0</rotateFrame>
-                                        <rotateUV>0</rotateUV>
-                                        <stagger>0</stagger>
-                                        <translateFrameU>0</translateFrameU>
-                                        <translateFrameV>0</translateFrameV>
-                                        <wrapU>1</wrapU>
-                                        <wrapV>1</wrapV>
-                                    </technique>
-                                </extra>
-                            </texture>
-                        </diffuse>
-                        <transparent opaque="RGB_ZERO">
-                            <color>0 0 0 1</color>
-                        </transparent>
-                        <transparency>
-                            <float>1</float>
-                        </transparency>
-                    </lambert>
-                </technique>
-            </profile_COMMON>
-        </effect>
-        <effect id="lambert2-fx">
-            <profile_COMMON>
-                <newparam sid="file22-surface">
-                    <surface type="2D">
-                        <init_from>file22</init_from>
-                    </surface>
-                </newparam>
-                <newparam sid="file22-sampler">
-                    <sampler2D>
-                        <source>file22-surface</source>
-                    </sampler2D>
-                </newparam>
-                <technique sid="common">
-                    <lambert>
-                        <emission>
-                            <color>0 0 0 1</color>
-                        </emission>
-                        <ambient>
-                            <color>0 0 0 1</color>
-                        </ambient>
-                        <diffuse>
-                            <texture texture="file22-sampler" texcoord="TEX0">
-                                <extra>
-                                    <technique profile="OpenCOLLADAMaya">
-                                        <blend_mode>NONE</blend_mode>
-                                        <coverageU>1</coverageU>
-                                        <coverageV>1</coverageV>
-                                        <fast>0</fast>
-                                        <mirrorU>0</mirrorU>
-                                        <mirrorV>0</mirrorV>
-                                        <noiseU>0</noiseU>
-                                        <noiseV>0</noiseV>
-                                        <offsetU>0</offsetU>
-                                        <offsetV>0</offsetV>
-                                        <repeatU>1</repeatU>
-                                        <repeatV>1</repeatV>
-                                        <rotateFrame>0</rotateFrame>
-                                        <rotateUV>0</rotateUV>
-                                        <stagger>0</stagger>
-                                        <translateFrameU>0</translateFrameU>
-                                        <translateFrameV>0</translateFrameV>
-                                        <wrapU>1</wrapU>
-                                        <wrapV>1</wrapV>
-                                    </technique>
-                                </extra>
-                            </texture>
-                        </diffuse>
-                        <transparent opaque="RGB_ZERO">
-                            <color>0 0 0 1</color>
-                        </transparent>
-                        <transparency>
-                            <float>1</float>
-                        </transparency>
-                    </lambert>
-                </technique>
-            </profile_COMMON>
-        </effect>
-    </library_effects>
-    <library_images>
-        <image id="file29" name="file29" height="0" width="0">
-            <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/blue.jpg</init_from>
-            <extra>
-                <technique profile="OpenCOLLADAMaya">
-                    <dgnode_type>kFile</dgnode_type>
-                    <image_sequence>0</image_sequence>
-                    <originalMayaNodeId>file29</originalMayaNodeId>
-                </technique>
-            </extra>
-        </image>
-        <image id="file25" name="file25" height="0" width="0">
-            <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/carbonfiber.jpg</init_from>
-            <extra>
-                <technique profile="OpenCOLLADAMaya">
-                    <dgnode_type>kFile</dgnode_type>
-                    <image_sequence>0</image_sequence>
-                    <originalMayaNodeId>file25</originalMayaNodeId>
-                </technique>
-            </extra>
-        </image>
-        <image id="file28" name="file28" height="0" width="0">
-            <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/green.jpg</init_from>
-            <extra>
-                <technique profile="OpenCOLLADAMaya">
-                    <dgnode_type>kFile</dgnode_type>
-                    <image_sequence>0</image_sequence>
-                    <originalMayaNodeId>file28</originalMayaNodeId>
-                </technique>
-            </extra>
-        </image>
-        <image id="file22" name="file22" height="0" width="0">
-            <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/grey.jpg</init_from>
-            <extra>
-                <technique profile="OpenCOLLADAMaya">
-                    <dgnode_type>kFile</dgnode_type>
-                    <image_sequence>0</image_sequence>
-                    <originalMayaNodeId>file22</originalMayaNodeId>
-                </technique>
-            </extra>
-        </image>
-        <image id="file24" name="file24" height="0" width="0">
-            <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/orange.jpg</init_from>
-            <extra>
-                <technique profile="OpenCOLLADAMaya">
-                    <dgnode_type>kFile</dgnode_type>
-                    <image_sequence>0</image_sequence>
-                    <originalMayaNodeId>file24</originalMayaNodeId>
-                </technique>
-            </extra>
-        </image>
-        <image id="file23" name="file23" height="0" width="0">
-            <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/red.jpg</init_from>
-            <extra>
-                <technique profile="OpenCOLLADAMaya">
-                    <dgnode_type>kFile</dgnode_type>
-                    <image_sequence>0</image_sequence>
-                    <originalMayaNodeId>file23</originalMayaNodeId>
-                </technique>
-            </extra>
-        </image>
-    </library_images>
-    <library_visual_scenes>
-        <visual_scene id="VisualSceneNode" name="orientation_test">
-            <node id="camera1" name="camera1">
-                <translate sid="translate">24.5791 14.1321 31.4654</translate>
-                <rotate sid="rotateZ">0 0 1 0</rotate>
-                <rotate sid="rotateY">0 1 0 42</rotate>
-                <rotate sid="rotateX">1 0 0 -16.2</rotate>
-                <scale sid="scale">1 1 1</scale>
-                <instance_camera url="#cameraShape1" />
-                <extra>
-                    <technique profile="OpenCOLLADAMaya">
-                        <originalMayaNodeId>camera1</originalMayaNodeId>
-                    </technique>
-                </extra>
-            </node>
-            <node id="CameraAim" name="CameraAim">
-                <translate sid="translate">0.0209301 3.68542 2.06912</translate>
-                <rotate sid="rotateY">0 1 0 43.2561</rotate>
-                <rotate sid="rotateX">1 0 0 -20</rotate>
-                <scale sid="scale">1 1 1</scale>
-                <node id="CameraDist" name="CameraDist">
-                    <translate sid="translate">0 0 45</translate>
-                    <scale sid="scale">1 1 1</scale>
-                    <instance_camera url="#CameraDistShape" />
-                    <extra>
-                        <technique profile="OpenCOLLADAMaya">
-                            <originalMayaNodeId>CameraDist</originalMayaNodeId>
-                        </technique>
-                    </extra>
-                </node>
-                <extra>
-                    <technique profile="OpenCOLLADAMaya">
-                        <originalMayaNodeId>CameraAim</originalMayaNodeId>
-                    </technique>
-                </extra>
-            </node>
-            <node id="pSphere4" name="pSphere4">
-                <translate sid="translate">-9.69237 0 7.70498</translate>
-                <scale sid="scale">1 1 1</scale>
-                <instance_geometry url="#pSphereShape4">
-                    <bind_material>
-                        <technique_common>
-                            <instance_material symbol="lambert7SG" target="#Paint1">
-                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                            </instance_material>
-                        </technique_common>
-                    </bind_material>
-                </instance_geometry>
-                <extra>
-                    <technique profile="OpenCOLLADAMaya">
-                        <originalMayaNodeId>pSphere4</originalMayaNodeId>
-                    </technique>
-                </extra>
-            </node>
-            <node id="pSphere1" name="pSphere1">
-                <translate sid="translate">13.0966 0 5.76254</translate>
-                <scale sid="scale">1 1 1</scale>
-                <instance_geometry url="#pSphereShape1">
-                    <bind_material>
-                        <technique_common>
-                            <instance_material symbol="lambert7SG" target="#Paint1">
-                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                            </instance_material>
-                        </technique_common>
-                    </bind_material>
-                </instance_geometry>
-                <extra>
-                    <technique profile="OpenCOLLADAMaya">
-                        <originalMayaNodeId>pSphere1</originalMayaNodeId>
-                    </technique>
-                </extra>
-            </node>
-            <node id="pSphere2" name="pSphere2">
-                <translate sid="translate">21.7661 0 -13.6375</translate>
-                <scale sid="scale">1 1 1</scale>
-                <instance_geometry url="#pSphereShape2">
-                    <bind_material>
-                        <technique_common>
-                            <instance_material symbol="lambert7SG" target="#Paint1">
-                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                            </instance_material>
-                        </technique_common>
-                    </bind_material>
-                </instance_geometry>
-                <extra>
-                    <technique profile="OpenCOLLADAMaya">
-                        <originalMayaNodeId>pSphere2</originalMayaNodeId>
-                    </technique>
-                </extra>
-            </node>
-            <node id="pSphere3" name="pSphere3">
-                <translate sid="translate">-13.862 0 -13.6154</translate>
-                <scale sid="scale">1 1 1</scale>
-                <instance_geometry url="#pSphereShape3">
-                    <bind_material>
-                        <technique_common>
-                            <instance_material symbol="lambert7SG" target="#Paint1">
-                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                            </instance_material>
-                        </technique_common>
-                    </bind_material>
-                </instance_geometry>
-                <extra>
-                    <technique profile="OpenCOLLADAMaya">
-                        <originalMayaNodeId>pSphere3</originalMayaNodeId>
-                    </technique>
-                </extra>
-            </node>
-            <node id="pSphere5" name="pSphere5">
-                <translate sid="translate">31.0862 0 18.5992</translate>
-                <scale sid="scale">1 1 1</scale>
-                <instance_geometry url="#pSphereShape5">
-                    <bind_material>
-                        <technique_common>
-                            <instance_material symbol="lambert7SG" target="#Paint1">
-                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                            </instance_material>
-                        </technique_common>
-                    </bind_material>
-                </instance_geometry>
-                <extra>
-                    <technique profile="OpenCOLLADAMaya">
-                        <originalMayaNodeId>pSphere5</originalMayaNodeId>
-                    </technique>
-                </extra>
-            </node>
-            <node id="pCube1" name="pCube1">
-                <translate sid="translate">0 0 0</translate>
-                <scale sid="scale">1 1 1</scale>
-                <instance_geometry url="#pCubeShape1">
-                    <bind_material>
-                        <technique_common>
-                            <instance_material symbol="lambert4SG" target="#lambert2">
-                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                            </instance_material>
-                        </technique_common>
-                    </bind_material>
-                </instance_geometry>
-                <extra>
-                    <technique profile="OpenCOLLADAMaya">
-                        <originalMayaNodeId>pCube1</originalMayaNodeId>
-                    </technique>
-                </extra>
-            </node>
-            <node id="group1" name="group1">
-                <translate sid="translate">0 0 0</translate>
-                <rotate sid="rotateZ">0 0 1 -162.693</rotate>
-                <rotate sid="rotateY">0 1 0 21.3345</rotate>
-                <rotate sid="rotateX">1 0 0 -100.567</rotate>
-                <scale sid="scale">1 1 1</scale>
-                <node id="pSphere6" name="pSphere6">
-                    <translate sid="translate">-13.862 0 -13.6154</translate>
-                    <scale sid="scale">1 1 1</scale>
-                    <instance_geometry url="#pSphereShape6">
-                        <bind_material>
-                            <technique_common>
-                                <instance_material symbol="lambert6SG" target="#Plastic">
-                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                                </instance_material>
-                            </technique_common>
-                        </bind_material>
-                    </instance_geometry>
-                    <extra>
-                        <technique profile="OpenCOLLADAMaya">
-                            <originalMayaNodeId>pSphere6</originalMayaNodeId>
-                        </technique>
-                    </extra>
-                </node>
-                <node id="pSphere7" name="pSphere7">
-                    <translate sid="translate">-9.69237 0 7.70498</translate>
-                    <scale sid="scale">1 1 1</scale>
-                    <instance_geometry url="#pSphereShape7">
-                        <bind_material>
-                            <technique_common>
-                                <instance_material symbol="lambert6SG" target="#Plastic">
-                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                                </instance_material>
-                            </technique_common>
-                        </bind_material>
-                    </instance_geometry>
-                    <extra>
-                        <technique profile="OpenCOLLADAMaya">
-                            <originalMayaNodeId>pSphere7</originalMayaNodeId>
-                        </technique>
-                    </extra>
-                </node>
-                <node id="pSphere8" name="pSphere8">
-                    <translate sid="translate">21.7661 0 -13.6375</translate>
-                    <scale sid="scale">1 1 1</scale>
-                    <instance_geometry url="#pSphereShape8">
-                        <bind_material>
-                            <technique_common>
-                                <instance_material symbol="lambert6SG" target="#Plastic">
-                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                                </instance_material>
-                            </technique_common>
-                        </bind_material>
-                    </instance_geometry>
-                    <extra>
-                        <technique profile="OpenCOLLADAMaya">
-                            <originalMayaNodeId>pSphere8</originalMayaNodeId>
-                        </technique>
-                    </extra>
-                </node>
-                <node id="pSphere9" name="pSphere9">
-                    <translate sid="translate">13.0966 0 5.76254</translate>
-                    <scale sid="scale">1 1 1</scale>
-                    <instance_geometry url="#pSphereShape9">
-                        <bind_material>
-                            <technique_common>
-                                <instance_material symbol="lambert6SG" target="#Plastic">
-                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                                </instance_material>
-                            </technique_common>
-                        </bind_material>
-                    </instance_geometry>
-                    <extra>
-                        <technique profile="OpenCOLLADAMaya">
-                            <originalMayaNodeId>pSphere9</originalMayaNodeId>
-                        </technique>
-                    </extra>
-                </node>
-                <extra>
-                    <technique profile="OpenCOLLADAMaya">
-                        <originalMayaNodeId>group1</originalMayaNodeId>
-                    </technique>
-                </extra>
-            </node>
-            <node id="group2" name="group2">
-                <translate sid="translate">0 0 0</translate>
-                <rotate sid="rotateZ">0 0 1 45.4017</rotate>
-                <rotate sid="rotateY">0 1 0 79.393</rotate>
-                <rotate sid="rotateX">1 0 0 5.10889</rotate>
-                <scale sid="scale">1 1 1</scale>
-                <node id="pSphere10" name="pSphere10">
-                    <translate sid="translate">31.0862 0 18.5992</translate>
-                    <scale sid="scale">1 1 1</scale>
-                    <instance_geometry url="#pSphereShape10">
-                        <bind_material>
-                            <technique_common>
-                                <instance_material symbol="lambert5SG" target="#Metal">
-                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                                </instance_material>
-                            </technique_common>
-                        </bind_material>
-                    </instance_geometry>
-                    <extra>
-                        <technique profile="OpenCOLLADAMaya">
-                            <originalMayaNodeId>pSphere10</originalMayaNodeId>
-                        </technique>
-                    </extra>
-                </node>
-                <node id="pSphere11" name="pSphere11">
-                    <translate sid="translate">13.0966 0 5.76254</translate>
-                    <scale sid="scale">1 1 1</scale>
-                    <instance_geometry url="#pSphereShape11">
-                        <bind_material>
-                            <technique_common>
-                                <instance_material symbol="lambert5SG" target="#Metal">
-                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                                </instance_material>
-                            </technique_common>
-                        </bind_material>
-                    </instance_geometry>
-                    <extra>
-                        <technique profile="OpenCOLLADAMaya">
-                            <originalMayaNodeId>pSphere11</originalMayaNodeId>
-                        </technique>
-                    </extra>
-                </node>
-                <node id="pSphere12" name="pSphere12">
-                    <translate sid="translate">7.4784 16.3496 7.36882</translate>
-                    <rotate sid="rotateZ">0 0 1 17.3073</rotate>
-                    <rotate sid="rotateY">0 1 0 158.666</rotate>
-                    <rotate sid="rotateX">1 0 0 79.4335</rotate>
-                    <scale sid="scale">1 1 1</scale>
-                    <instance_geometry url="#pSphereShape12">
-                        <bind_material>
-                            <technique_common>
-                                <instance_material symbol="lambert5SG" target="#Metal">
-                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                                </instance_material>
-                            </technique_common>
-                        </bind_material>
-                    </instance_geometry>
-                    <extra>
-                        <technique profile="OpenCOLLADAMaya">
-                            <originalMayaNodeId>pSphere12</originalMayaNodeId>
-                        </technique>
-                    </extra>
-                </node>
-                <node id="pSphere13" name="pSphere13">
-                    <translate sid="translate">-9.69237 0 7.70498</translate>
-                    <scale sid="scale">1 1 1</scale>
-                    <instance_geometry url="#pSphereShape13">
-                        <bind_material>
-                            <technique_common>
-                                <instance_material symbol="lambert5SG" target="#Metal">
-                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                                </instance_material>
-                            </technique_common>
-                        </bind_material>
-                    </instance_geometry>
-                    <extra>
-                        <technique profile="OpenCOLLADAMaya">
-                            <originalMayaNodeId>pSphere13</originalMayaNodeId>
-                        </technique>
-                    </extra>
-                </node>
-                <node id="pSphere14" name="pSphere14">
-                    <translate sid="translate">11.3635 -4.3926 2.21012</translate>
-                    <rotate sid="rotateZ">0 0 1 17.3073</rotate>
-                    <rotate sid="rotateY">0 1 0 158.666</rotate>
-                    <rotate sid="rotateX">1 0 0 79.4335</rotate>
-                    <scale sid="scale">1 1 1</scale>
-                    <instance_geometry url="#pSphereShape14">
-                        <bind_material>
-                            <technique_common>
-                                <instance_material symbol="lambert5SG" target="#Metal">
-                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                                </instance_material>
-                            </technique_common>
-                        </bind_material>
-                    </instance_geometry>
-                    <extra>
-                        <technique profile="OpenCOLLADAMaya">
-                            <originalMayaNodeId>pSphere14</originalMayaNodeId>
-                        </technique>
-                    </extra>
-                </node>
-                <node id="pSphere15" name="pSphere15">
-                    <translate sid="translate">21.7661 0 -13.6375</translate>
-                    <scale sid="scale">1 1 1</scale>
-                    <instance_geometry url="#pSphereShape15">
-                        <bind_material>
-                            <technique_common>
-                                <instance_material symbol="lambert5SG" target="#Metal">
-                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                                </instance_material>
-                            </technique_common>
-                        </bind_material>
-                    </instance_geometry>
-                    <extra>
-                        <technique profile="OpenCOLLADAMaya">
-                            <originalMayaNodeId>pSphere15</originalMayaNodeId>
-                        </technique>
-                    </extra>
-                </node>
-                <node id="pSphere16" name="pSphere16">
-                    <translate sid="translate">-9.5945 -8.92317 -5.74901</translate>
-                    <rotate sid="rotateZ">0 0 1 17.3073</rotate>
-                    <rotate sid="rotateY">0 1 0 158.666</rotate>
-                    <rotate sid="rotateX">1 0 0 79.4335</rotate>
-                    <scale sid="scale">1 1 1</scale>
-                    <instance_geometry url="#pSphereShape16">
-                        <bind_material>
-                            <technique_common>
-                                <instance_material symbol="lambert5SG" target="#Metal">
-                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                                </instance_material>
-                            </technique_common>
-                        </bind_material>
-                    </instance_geometry>
-                    <extra>
-                        <technique profile="OpenCOLLADAMaya">
-                            <originalMayaNodeId>pSphere16</originalMayaNodeId>
-                        </technique>
-                    </extra>
-                </node>
-                <node id="pSphere17" name="pSphere17">
-                    <translate sid="translate">-13.862 0 -13.6154</translate>
-                    <scale sid="scale">1 1 1</scale>
-                    <instance_geometry url="#pSphereShape17">
-                        <bind_material>
-                            <technique_common>
-                                <instance_material symbol="lambert5SG" target="#Metal">
-                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                                </instance_material>
-                            </technique_common>
-                        </bind_material>
-                    </instance_geometry>
-                    <extra>
-                        <technique profile="OpenCOLLADAMaya">
-                            <originalMayaNodeId>pSphere17</originalMayaNodeId>
-                        </technique>
-                    </extra>
-                </node>
-                <node id="pSphere18" name="pSphere18">
-                    <translate sid="translate">-24.2135 6.497 -5.58935</translate>
-                    <rotate sid="rotateZ">0 0 1 17.3073</rotate>
-                    <rotate sid="rotateY">0 1 0 158.666</rotate>
-                    <rotate sid="rotateX">1 0 0 79.4335</rotate>
-                    <scale sid="scale">1 1 1</scale>
-                    <instance_geometry url="#pSphereShape18">
-                        <bind_material>
-                            <technique_common>
-                                <instance_material symbol="lambert5SG" target="#Metal">
-                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                                </instance_material>
-                            </technique_common>
-                        </bind_material>
-                    </instance_geometry>
-                    <extra>
-                        <technique profile="OpenCOLLADAMaya">
-                            <originalMayaNodeId>pSphere18</originalMayaNodeId>
-                        </technique>
-                    </extra>
-                </node>
-                <extra>
-                    <technique profile="OpenCOLLADAMaya">
-                        <originalMayaNodeId>group2</originalMayaNodeId>
-                    </technique>
-                </extra>
-            </node>
-            <node id="pCube2" name="pCube2">
-                <translate sid="translate">0 0 0</translate>
-                <scale sid="scale">1 1 1</scale>
-                <instance_geometry url="#pCubeShape2">
-                    <bind_material>
-                        <technique_common>
-                            <instance_material symbol="lambert8SG" target="#PlasticCenter">
-                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                            </instance_material>
-                        </technique_common>
-                    </bind_material>
-                </instance_geometry>
-                <extra>
-                    <technique profile="OpenCOLLADAMaya">
-                        <originalMayaNodeId>pCube2</originalMayaNodeId>
-                    </technique>
-                </extra>
-            </node>
-            <node id="pCube3" name="pCube3">
-                <translate sid="translate">15 0 0</translate>
-                <scale sid="scale">1 1 1</scale>
-                <instance_geometry url="#pCubeShape3">
-                    <bind_material>
-                        <technique_common>
-                            <instance_material symbol="lambert9SG" target="#PlasticRed">
-                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                            </instance_material>
-                        </technique_common>
-                    </bind_material>
-                </instance_geometry>
-                <extra>
-                    <technique profile="OpenCOLLADAMaya">
-                        <originalMayaNodeId>pCube3</originalMayaNodeId>
-                    </technique>
-                </extra>
-            </node>
-            <node id="pCube4" name="pCube4">
-                <translate sid="translate">0 15 0</translate>
-                <scale sid="scale">1 1 1</scale>
-                <instance_geometry url="#pCubeShape4">
-                    <bind_material>
-                        <technique_common>
-                            <instance_material symbol="lambert10SG" target="#lambert10">
-                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                            </instance_material>
-                        </technique_common>
-                    </bind_material>
-                </instance_geometry>
-                <extra>
-                    <technique profile="OpenCOLLADAMaya">
-                        <originalMayaNodeId>pCube4</originalMayaNodeId>
-                    </technique>
-                </extra>
-            </node>
-            <node id="pCube5" name="pCube5">
-                <translate sid="translate">0 0 15</translate>
-                <scale sid="scale">1 1 1</scale>
-                <instance_geometry url="#pCubeShape5">
-                    <bind_material>
-                        <technique_common>
-                            <instance_material symbol="lambert11SG" target="#lambert11">
-                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
-                            </instance_material>
-                        </technique_common>
-                    </bind_material>
-                </instance_geometry>
-                <extra>
-                    <technique profile="OpenCOLLADAMaya">
-                        <originalMayaNodeId>pCube5</originalMayaNodeId>
-                    </technique>
-                </extra>
-            </node>
-        </visual_scene>
-    </library_visual_scenes>
-    <scene>
-        <instance_visual_scene url="#VisualSceneNode" />
-    </scene>
-</COLLADA>
diff --git a/tests/RenderScriptTests/SceneGraph/assets/paint.jpg b/tests/RenderScriptTests/SceneGraph/assets/paint.jpg
deleted file mode 100644
index 0791045..0000000
--- a/tests/RenderScriptTests/SceneGraph/assets/paint.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/red.jpg b/tests/RenderScriptTests/SceneGraph/assets/red.jpg
deleted file mode 100644
index 320a2a6..0000000
--- a/tests/RenderScriptTests/SceneGraph/assets/red.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/icon.png b/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/icon.png
deleted file mode 100644
index ff34a7f..0000000
--- a/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/icon.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/robot.png b/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/robot.png
deleted file mode 100644
index f7353fd..0000000
--- a/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/robot.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/res/menu/loader_menu.xml b/tests/RenderScriptTests/SceneGraph/res/menu/loader_menu.xml
deleted file mode 100644
index 9ea30107..0000000
--- a/tests/RenderScriptTests/SceneGraph/res/menu/loader_menu.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-* Copyright (C) 2011 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*      http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
--->
-
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:id="@+id/load_model"
-          android:title="@string/load_model" />
-    <item android:id="@+id/use_blur"
-          android:title="@string/use_blur" />
-</menu>
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/blur_h.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/blur_h.glsl
deleted file mode 100644
index c34adc9..0000000
--- a/tests/RenderScriptTests/SceneGraph/res/raw/blur_h.glsl
+++ /dev/null
@@ -1,15 +0,0 @@
-varying vec2 varTex0;
-
-void main() {
-   vec2 blurCoord = varTex0;
-   blurCoord.x = varTex0.x + UNI_blurOffset0;
-   vec3 col = texture2D(UNI_color, blurCoord).rgb;
-   blurCoord.x = varTex0.x + UNI_blurOffset1;
-   col += texture2D(UNI_color, blurCoord).rgb;
-   blurCoord.x = varTex0.x + UNI_blurOffset2;
-   col += texture2D(UNI_color, blurCoord).rgb;
-   blurCoord.x = varTex0.x + UNI_blurOffset3;
-   col += texture2D(UNI_color, blurCoord).rgb;
-
-   gl_FragColor = vec4(col * 0.25, 0.0);
-}
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/blur_v.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/blur_v.glsl
deleted file mode 100644
index ade05a2..0000000
--- a/tests/RenderScriptTests/SceneGraph/res/raw/blur_v.glsl
+++ /dev/null
@@ -1,17 +0,0 @@
-varying vec2 varTex0;
-
-void main() {
-   vec2 blurCoord = varTex0;
-   blurCoord.y = varTex0.y + UNI_blurOffset0;
-   vec3 col = texture2D(UNI_color, blurCoord).rgb;
-   blurCoord.y = varTex0.y + UNI_blurOffset1;
-   col += texture2D(UNI_color, blurCoord).rgb;
-   blurCoord.y = varTex0.y + UNI_blurOffset2;
-   col += texture2D(UNI_color, blurCoord).rgb;
-   blurCoord.y = varTex0.y + UNI_blurOffset3;
-   col += texture2D(UNI_color, blurCoord).rgb;
-
-   col = col * 0.25;
-
-   gl_FragColor = vec4(col, 0.0);
-}
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/blur_vertex.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/blur_vertex.glsl
deleted file mode 100644
index bc824b6..0000000
--- a/tests/RenderScriptTests/SceneGraph/res/raw/blur_vertex.glsl
+++ /dev/null
@@ -1,7 +0,0 @@
-varying vec2 varTex0;
-
-void main() {
-   gl_Position = ATTRIB_position;
-   varTex0 = ATTRIB_texture0;
-}
-
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/diffuse.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/diffuse.glsl
deleted file mode 100644
index 2eb1028..0000000
--- a/tests/RenderScriptTests/SceneGraph/res/raw/diffuse.glsl
+++ /dev/null
@@ -1,19 +0,0 @@
-varying vec3 varWorldPos;
-varying vec3 varWorldNormal;
-varying vec2 varTex0;
-
-void main() {
-
-   vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
-   vec3 worldNorm = (varWorldNormal);
-
-   vec3 light0Vec = V;
-   vec3 light0R = reflect(light0Vec, worldNorm);
-   float light0_Diffuse = dot(worldNorm, light0Vec);
-
-   vec2 t0 = varTex0.xy;
-   lowp vec4 col = texture2D(UNI_diffuse, t0).rgba;
-   col.xyz = col.xyz * light0_Diffuse * 1.2;
-   gl_FragColor = col;
-}
-
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/diffuse_lights.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/diffuse_lights.glsl
deleted file mode 100644
index ef93e1c..0000000
--- a/tests/RenderScriptTests/SceneGraph/res/raw/diffuse_lights.glsl
+++ /dev/null
@@ -1,22 +0,0 @@
-varying vec3 varWorldPos;
-varying vec3 varWorldNormal;
-varying vec2 varTex0;
-
-void main() {
-
-   vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
-   vec3 worldNorm = normalize(varWorldNormal);
-
-   vec3 light0Vec = normalize(UNI_lightPos_0.xyz - varWorldPos.xyz);
-   float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0);
-
-   vec3 light1Vec = normalize(UNI_lightPos_1.xyz - varWorldPos.xyz);
-   float light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0);
-
-   vec2 t0 = varTex0.xy;
-   lowp vec4 col = UNI_diffuse;
-   col.xyz = col.xyz * (light0_Diffuse * UNI_lightColor_0.xyz +
-                        light1_Diffuse * UNI_lightColor_1.xyz);
-   gl_FragColor = col;
-}
-
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/metal.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/metal.glsl
deleted file mode 100644
index b90a7b2..0000000
--- a/tests/RenderScriptTests/SceneGraph/res/raw/metal.glsl
+++ /dev/null
@@ -1,23 +0,0 @@
-varying vec3 varWorldPos;
-varying vec3 varWorldNormal;
-varying vec2 varTex0;
-
-void main() {
-
-   vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
-   vec3 worldNorm = normalize(varWorldNormal);
-
-   vec3 light0Vec = V;
-   vec3 light0R = reflect(light0Vec, worldNorm);
-   float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0);
-   float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0);
-   float light0_Specular = pow(light0Spec, 15.0) * 0.5;
-
-   vec2 t0 = varTex0.xy;
-   lowp vec4 col = texture2D(UNI_diffuse, t0).rgba;
-   col.xyz = col.xyz * (textureCube(UNI_reflection, worldNorm).rgb * 0.5 + vec3(light0_Diffuse));
-   col.xyz += light0_Specular * vec3(0.8, 0.8, 1.0);
-
-   gl_FragColor = col;
-}
-
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/paintf.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/paintf.glsl
deleted file mode 100644
index f3b89ed..0000000
--- a/tests/RenderScriptTests/SceneGraph/res/raw/paintf.glsl
+++ /dev/null
@@ -1,26 +0,0 @@
-varying vec3 varWorldPos;
-varying vec3 varWorldNormal;
-varying vec2 varTex0;
-
-void main() {
-
-   vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
-   vec3 worldNorm = normalize(varWorldNormal);
-
-   vec3 light0Vec = V;
-   vec3 light0R = reflect(light0Vec, worldNorm);
-   float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.01, 0.99);
-   float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0);
-   float light0_Specular = pow(light0Spec, 150.0) * 0.5;
-
-   vec2 t0 = varTex0.xy;
-   lowp vec4 col = texture2D(UNI_diffuse, t0).rgba;
-   col.xyz = col.xyz * light0_Diffuse * 1.1;
-   col.xyz += light0_Specular * vec3(0.8, 0.8, 1.0);
-
-   float fresnel = mix(pow(1.0 - light0_Diffuse, 15.0), 1.0, 0.1);
-   col.xyz = mix(col.xyz, textureCube(UNI_reflection, -light0R).rgb * 2.4, fresnel);
-   col.w = 0.8;
-   gl_FragColor = col;
-}
-
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/plastic.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/plastic.glsl
deleted file mode 100644
index 56f7151f..0000000
--- a/tests/RenderScriptTests/SceneGraph/res/raw/plastic.glsl
+++ /dev/null
@@ -1,22 +0,0 @@
-varying vec3 varWorldPos;
-varying vec3 varWorldNormal;
-varying vec2 varTex0;
-
-void main() {
-
-   vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
-   vec3 worldNorm = normalize(varWorldNormal);
-
-   vec3 light0Vec = V;
-   vec3 light0R = reflect(light0Vec, worldNorm);
-   float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0);
-   float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0);
-   float light0_Specular = pow(light0Spec, 10.0) * 0.5;
-
-   vec2 t0 = varTex0.xy;
-   lowp vec4 col = texture2D(UNI_diffuse, t0).rgba;
-   col.xyz = col.xyz * light0_Diffuse * 1.2;
-   col.xyz += light0_Specular * vec3(0.8, 0.8, 1.0);
-   gl_FragColor = col;
-}
-
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/plastic_lights.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/plastic_lights.glsl
deleted file mode 100644
index b253622..0000000
--- a/tests/RenderScriptTests/SceneGraph/res/raw/plastic_lights.glsl
+++ /dev/null
@@ -1,29 +0,0 @@
-varying vec3 varWorldPos;
-varying vec3 varWorldNormal;
-varying vec2 varTex0;
-
-void main() {
-
-   vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
-   vec3 worldNorm = normalize(varWorldNormal);
-
-   vec3 light0Vec = normalize(UNI_lightPos_0.xyz - varWorldPos.xyz);
-   vec3 light0R = reflect(light0Vec, worldNorm);
-   float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0);
-   float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0);
-   float light0_Specular = pow(light0Spec, 10.0) * 0.7;
-
-   vec3 light1Vec = normalize(UNI_lightPos_1.xyz - varWorldPos.xyz);
-   vec3 light1R = reflect(light1Vec, worldNorm);
-   float light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0);
-   float light1Spec = clamp(dot(-light1R, V), 0.001, 1.0);
-   float light1_Specular = pow(light1Spec, 10.0) * 0.7;
-
-   vec2 t0 = varTex0.xy;
-   lowp vec4 col = UNI_diffuse;
-   col.xyz = col.xyz * (light0_Diffuse * UNI_lightColor_0.xyz +
-                        light1_Diffuse * UNI_lightColor_1.xyz);
-   col.xyz += (light0_Specular + light1_Specular);
-   gl_FragColor = col;
-}
-
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/robot.a3d b/tests/RenderScriptTests/SceneGraph/res/raw/robot.a3d
deleted file mode 100644
index f48895c..0000000
--- a/tests/RenderScriptTests/SceneGraph/res/raw/robot.a3d
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/select_color.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/select_color.glsl
deleted file mode 100644
index 1a927ca..0000000
--- a/tests/RenderScriptTests/SceneGraph/res/raw/select_color.glsl
+++ /dev/null
@@ -1,13 +0,0 @@
-varying vec2 varTex0;
-
-void main() {
-   vec3 col = texture2D(UNI_color, varTex0).rgb;
-
-   vec3 desat = vec3(0.299, 0.587, 0.114);
-   float lum = dot(desat, col);
-   float stepVal = step(lum, 0.8);
-   col = mix(col, vec3(0.0), stepVal)*0.5;
-
-   gl_FragColor = vec4(col, 0.0);
-}
-
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/shader2v.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/shader2v.glsl
deleted file mode 100644
index 7910a54..0000000
--- a/tests/RenderScriptTests/SceneGraph/res/raw/shader2v.glsl
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
-    rs_matrix4x4 model;
-    rs_matrix4x4 viewProj;
-*/
-
-varying vec3 varWorldPos;
-varying vec3 varWorldNormal;
-varying vec2 varTex0;
-
-// This is where actual shader code begins
-void main() {
-   vec4 objPos = ATTRIB_position;
-   vec4 worldPos = UNI_model * objPos;
-   gl_Position = UNI_viewProj * worldPos;
-
-   mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
-   vec3 worldNorm = model3 * ATTRIB_normal;
-
-   varWorldPos = worldPos.xyz;
-   varWorldNormal = worldNorm;
-   varTex0 = ATTRIB_texture0;
-}
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/texture.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/texture.glsl
deleted file mode 100644
index 662ecd8..0000000
--- a/tests/RenderScriptTests/SceneGraph/res/raw/texture.glsl
+++ /dev/null
@@ -1,7 +0,0 @@
-varying vec2 varTex0;
-
-void main() {
-   lowp vec4 col = texture2D(UNI_color, varTex0).rgba;
-   gl_FragColor = col;
-}
-
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/unit_obj.a3d b/tests/RenderScriptTests/SceneGraph/res/raw/unit_obj.a3d
deleted file mode 100644
index 56eff04..0000000
--- a/tests/RenderScriptTests/SceneGraph/res/raw/unit_obj.a3d
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/res/values/strings.xml b/tests/RenderScriptTests/SceneGraph/res/values/strings.xml
deleted file mode 100644
index c916d79..0000000
--- a/tests/RenderScriptTests/SceneGraph/res/values/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-* Copyright (C) 2011 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*      http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <skip />
-    <string name="load_model">Load Model</string>
-    <string name="use_blur">Use Blur</string>
-</resources>
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java
deleted file mode 100644
index 42f2be5..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-import java.util.ArrayList;
-
-import com.android.scenegraph.SceneManager;
-
-import android.renderscript.*;
-import android.renderscript.Matrix4f;
-import android.renderscript.RenderScriptGL;
-import android.util.Log;
-
-/**
- * @hide
- */
-public class Camera extends SceneGraphBase {
-
-    Transform mTransform;
-
-    ScriptField_Camera_s.Item mData;
-    ScriptField_Camera_s mField;
-
-    public Camera() {
-        mData = new ScriptField_Camera_s.Item();
-        mData.near = 0.1f;
-        mData.far = 1000.0f;
-        mData.horizontalFOV = 60.0f;
-        mData.aspect = 0;
-    }
-
-    public void setTransform(Transform t) {
-        mTransform = t;
-        if (mField != null) {
-            mField.set_transformMatrix(0, mTransform.getRSData().getAllocation(), true);
-            mField.set_isDirty(0, 1, true);
-        }
-    }
-    public void setFOV(float fov) {
-        mData.horizontalFOV = fov;
-        if (mField != null) {
-            mField.set_horizontalFOV(0, fov, true);
-            mField.set_isDirty(0, 1, true);
-        }
-    }
-
-    public void setNear(float n) {
-        mData.near = n;
-        if (mField != null) {
-            mField.set_near(0, n, true);
-            mField.set_isDirty(0, 1, true);
-        }
-    }
-
-    public void setFar(float f) {
-        mData.far = f;
-        if (mField != null) {
-            mField.set_far(0, f, true);
-            mField.set_isDirty(0, 1, true);
-        }
-    }
-
-    public void setName(String n) {
-        super.setName(n);
-        if (mField != null) {
-            RenderScriptGL rs = SceneManager.getRS();
-            mData.name = getNameAlloc(rs);
-            mField.set_name(0, mData.name, true);
-            mField.set_isDirty(0, 1, true);
-        }
-    }
-
-    ScriptField_Camera_s getRSData() {
-        if (mField != null) {
-            return mField;
-        }
-
-        RenderScriptGL rs = SceneManager.getRS();
-        if (rs == null) {
-            return null;
-        }
-
-        if (mTransform == null) {
-            throw new RuntimeException("Cameras without transforms are invalid");
-        }
-
-        mField = new ScriptField_Camera_s(rs, 1);
-
-        mData.transformMatrix = mTransform.getRSData().getAllocation();
-        mData.transformTimestamp = 1;
-        mData.timestamp = 1;
-        mData.isDirty = 1;
-        mData.name = getNameAlloc(rs);
-        mField.set(mData, 0, true);
-
-        return mField;
-    }
-}
-
-
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java
deleted file mode 100644
index b4b6fb9..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java
+++ /dev/null
@@ -1,563 +0,0 @@
-/*

- * Copyright (C) 2011 The Android Open Source Project

- *

- * Licensed under the Apache License, Version 2.0 (the "License");

- * you may not use this file except in compliance with the License.

- * You may obtain a copy of the License at

- *

- *      http://www.apache.org/licenses/LICENSE-2.0

- *

- * Unless required by applicable law or agreed to in writing, software

- * distributed under the License is distributed on an "AS IS" BASIS,

- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

- * See the License for the specific language governing permissions and

- * limitations under the License.

- */

-

-package com.android.scenegraph;

-import com.android.scenegraph.CompoundTransform.TranslateComponent;

-import com.android.scenegraph.CompoundTransform.RotateComponent;

-import com.android.scenegraph.CompoundTransform.ScaleComponent;

-import java.io.IOException;

-import java.io.InputStream;

-import java.util.ArrayList;

-import java.util.Iterator;

-import java.util.List;

-import java.util.StringTokenizer;

-import java.util.HashMap;

-

-import javax.xml.parsers.DocumentBuilder;

-import javax.xml.parsers.DocumentBuilderFactory;

-import javax.xml.parsers.ParserConfigurationException;

-

-import org.w3c.dom.Document;

-import org.w3c.dom.Element;

-import org.w3c.dom.Node;

-import org.w3c.dom.NodeList;

-import org.xml.sax.SAXException;

-

-import android.renderscript.*;

-import android.util.Log;

-

-public class ColladaParser {

-    static final String TAG = "ColladaParser";

-    Document mDom;

-

-    HashMap<String, LightBase> mLights;

-    HashMap<String, Camera> mCameras;

-    HashMap<String, ArrayList<ShaderParam> > mEffectsParams;

-    HashMap<String, Texture2D> mImages;

-    HashMap<String, Texture2D> mSamplerImageMap;

-    HashMap<String, String> mMeshIdNameMap;

-    Scene mScene;

-

-    String mRootDir;

-

-    String toString(Float3 v) {

-        String valueStr = v.x + " " + v.y + " " + v.z;

-        return valueStr;

-    }

-

-    String toString(Float4 v) {

-        String valueStr = v.x + " " + v.y + " " + v.z + " " + v.w;

-        return valueStr;

-    }

-

-    public ColladaParser(){

-        mLights = new HashMap<String, LightBase>();

-        mCameras = new HashMap<String, Camera>();

-        mEffectsParams = new HashMap<String, ArrayList<ShaderParam> >();

-        mImages = new HashMap<String, Texture2D>();

-        mMeshIdNameMap = new HashMap<String, String>();

-    }

-

-    public void init(InputStream is, String rootDir) {

-        mLights.clear();

-        mCameras.clear();

-        mEffectsParams.clear();

-

-        mRootDir = rootDir;

-

-        long start = System.currentTimeMillis();

-        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

-        try {

-            DocumentBuilder db = dbf.newDocumentBuilder();

-            mDom = db.parse(is);

-        } catch(ParserConfigurationException e) {

-            e.printStackTrace();

-        } catch(SAXException e) {

-            e.printStackTrace();

-        } catch(IOException e) {

-            e.printStackTrace();

-        }

-        long end = System.currentTimeMillis();

-        Log.v("TIMER", "    Parse time: " + (end - start));

-        exportSceneData();

-    }

-

-    Scene getScene() {

-        return mScene;

-    }

-

-    private void exportSceneData(){

-        mScene = new Scene();

-

-        Element docEle = mDom.getDocumentElement();

-        NodeList nl = docEle.getElementsByTagName("light");

-        if (nl != null) {

-            for(int i = 0; i < nl.getLength(); i++) {

-                Element l = (Element)nl.item(i);

-                convertLight(l);

-            }

-        }

-

-        nl = docEle.getElementsByTagName("camera");

-        if (nl != null) {

-            for(int i = 0; i < nl.getLength(); i++) {

-                Element c = (Element)nl.item(i);

-                convertCamera(c);

-            }

-        }

-

-        nl = docEle.getElementsByTagName("image");

-        if (nl != null) {

-            for(int i = 0; i < nl.getLength(); i++) {

-                Element img = (Element)nl.item(i);

-                convertImage(img);

-            }

-        }

-

-        nl = docEle.getElementsByTagName("effect");

-        if (nl != null) {

-            for(int i = 0; i < nl.getLength(); i++) {

-                Element e = (Element)nl.item(i);

-                convertEffects(e);

-            }

-        }

-

-        // Material is just a link to the effect

-        nl = docEle.getElementsByTagName("material");

-        if (nl != null) {

-            for(int i = 0; i < nl.getLength(); i++) {

-                Element m = (Element)nl.item(i);

-                convertMaterials(m);

-            }

-        }

-

-        // Look through the geometry list and build up a correlation between id's and names

-        nl = docEle.getElementsByTagName("geometry");

-        if (nl != null) {

-            for(int i = 0; i < nl.getLength(); i++) {

-                Element m = (Element)nl.item(i);

-                convertGeometries(m);

-            }

-        }

-

-

-        nl = docEle.getElementsByTagName("visual_scene");

-        if (nl != null) {

-            for(int i = 0; i < nl.getLength(); i++) {

-                Element s = (Element)nl.item(i);

-                getScene(s);

-            }

-        }

-    }

-

-    private void getRenderable(Element shape, Transform t) {

-        String geoURL = shape.getAttribute("url").substring(1);

-        String geoName = mMeshIdNameMap.get(geoURL);

-        if (geoName != null) {

-            geoURL = geoName;

-        }

-        //RenderableGroup group = new RenderableGroup();

-        //group.setName(geoURL.substring(1));

-        //mScene.appendRenderable(group);

-        NodeList nl = shape.getElementsByTagName("instance_material");

-        if (nl != null) {

-            for(int i = 0; i < nl.getLength(); i++) {

-                Element materialRef = (Element)nl.item(i);

-                String meshIndexName = materialRef.getAttribute("symbol");

-                String materialName = materialRef.getAttribute("target");

-

-                Renderable d = new Renderable();

-                d.setMesh(geoURL, meshIndexName);

-                d.setMaterialName(materialName.substring(1));

-                d.setName(geoURL);

-

-                //Log.v(TAG, "Created drawable geo " + geoURL + " index " + meshIndexName + " material " + materialName);

-

-                d.setTransform(t);

-                //Log.v(TAG, "Set source param " + t.getName());

-

-                // Now find all the parameters that exist on the material

-                ArrayList<ShaderParam> materialParams;

-                materialParams = mEffectsParams.get(materialName.substring(1));

-                for (int pI = 0; pI < materialParams.size(); pI ++) {

-                    d.appendSourceParams(materialParams.get(pI));

-                    //Log.v(TAG, "Set source param i: " + pI + " name " + materialParams.get(pI).getParamName());

-                }

-                mScene.appendRenderable(d);

-                //group.appendChildren(d);

-            }

-        }

-    }

-

-    private void updateLight(Element shape, Transform t) {

-        String lightURL = shape.getAttribute("url");

-        // collada uses a uri structure to link things,

-        // but we ignore it for now and do a simple search

-        LightBase light = mLights.get(lightURL.substring(1));

-        if (light != null) {

-            light.setTransform(t);

-            //Log.v(TAG, "Set Light " + light.getName() + " " + t.getName());

-        }

-    }

-

-    private void updateCamera(Element shape, Transform t) {

-        String camURL = shape.getAttribute("url");

-        // collada uses a uri structure to link things,

-        // but we ignore it for now and do a simple search

-        Camera cam = mCameras.get(camURL.substring(1));

-        if (cam != null) {

-            cam.setTransform(t);

-            //Log.v(TAG, "Set Camera " + cam.getName() + " " + t.getName());

-        }

-    }

-

-    private void getNode(Element node, Transform parent, String indent) {

-        String name = node.getAttribute("name");

-        String id = node.getAttribute("id");

-        CompoundTransform current = new CompoundTransform();

-        current.setName(name);

-        if (parent != null) {

-            parent.appendChild(current);

-        } else {

-            mScene.appendTransform(current);

-        }

-

-        mScene.addToTransformMap(current);

-

-        //Log.v(TAG, indent + "|");

-        //Log.v(TAG, indent + "[" + name + "]");

-

-        Node childNode = node.getFirstChild();

-        while (childNode != null) {

-            if (childNode.getNodeType() == Node.ELEMENT_NODE) {

-                Element field = (Element)childNode;

-                String fieldName = field.getTagName();

-                String description = field.getAttribute("sid");

-                if (fieldName.equals("translate")) {

-                    Float3 value = getFloat3(field);

-                    current.addTranslate(description, value);

-                    //Log.v(TAG, indent + " translate " + description + toString(value));

-                } else if (fieldName.equals("rotate")) {

-                    Float4 value = getFloat4(field);

-                    //Log.v(TAG, indent + " rotate " + description + toString(value));

-                    Float3 axis = new Float3(value.x, value.y, value.z);

-                    current.addRotate(description, axis, value.w);

-                } else if (fieldName.equals("scale")) {

-                    Float3 value = getFloat3(field);

-                    //Log.v(TAG, indent + " scale " + description + toString(value));

-                    current.addScale(description, value);

-                } else if (fieldName.equals("instance_geometry")) {

-                    getRenderable(field, current);

-                } else if (fieldName.equals("instance_light")) {

-                    updateLight(field, current);

-                } else if (fieldName.equals("instance_camera")) {

-                    updateCamera(field, current);

-                } else if (fieldName.equals("node")) {

-                    getNode(field, current, indent + "   ");

-                }

-            }

-            childNode = childNode.getNextSibling();

-        }

-    }

-

-    // This will find the actual texture node, which is sometimes hidden behind a sampler

-    // and sometimes referenced directly

-    Texture2D getTexture(String samplerName) {

-        String texName = samplerName;

-

-        // Check to see if the image file is hidden by a sampler surface link combo

-        Element sampler = mDom.getElementById(samplerName);

-        if (sampler != null) {

-            NodeList nl = sampler.getElementsByTagName("source");

-            if (nl != null && nl.getLength() == 1) {

-                Element ref = (Element)nl.item(0);

-                String surfaceName = getString(ref);

-                if (surfaceName == null) {

-                    return null;

-                }

-

-                Element surface = mDom.getElementById(surfaceName);

-                if (surface == null) {

-                    return null;

-                }

-                nl = surface.getElementsByTagName("init_from");

-                if (nl != null && nl.getLength() == 1) {

-                    ref = (Element)nl.item(0);

-                    texName = getString(ref);

-                }

-            }

-        }

-

-        //Log.v(TAG, "Extracted texture name " + texName);

-        return mImages.get(texName);

-    }

-

-    void extractParams(Element fx, ArrayList<ShaderParam> params) {

-        Node paramNode = fx.getFirstChild();

-        while (paramNode != null) {

-            if (paramNode.getNodeType() == Node.ELEMENT_NODE) {

-                String name = paramNode.getNodeName();

-                // Now find what type it is

-                Node typeNode = paramNode.getFirstChild();

-                while (typeNode != null && typeNode.getNodeType() != Node.ELEMENT_NODE) {

-                    typeNode = typeNode.getNextSibling();

-                }

-                String paramType = typeNode.getNodeName();

-                Element typeElem = (Element)typeNode;

-                ShaderParam sceneParam = null;

-                if (paramType.equals("color")) {

-                    Float4Param f4p = new Float4Param(name);

-                    Float4 value = getFloat4(typeElem);

-                    f4p.setValue(value);

-                    sceneParam = f4p;

-                    //Log.v(TAG, "Extracted " + sceneParam.getParamName() + " value " + toString(value));

-                } else if (paramType.equals("float")) {

-                    Float4Param f4p = new Float4Param(name);

-                    float value = getFloat(typeElem);

-                    f4p.setValue(new Float4(value, value, value, value));

-                    sceneParam = f4p;

-                    //Log.v(TAG, "Extracted " + sceneParam.getParamName() + " value " + value);

-                }  else if (paramType.equals("texture")) {

-                    String samplerName = typeElem.getAttribute("texture");

-                    Texture2D tex = getTexture(samplerName);

-                    TextureParam texP = new TextureParam(name);

-                    texP.setTexture(tex);

-                    sceneParam = texP;

-                    //Log.v(TAG, "Extracted texture " + tex);

-                }

-                if (sceneParam != null) {

-                    params.add(sceneParam);

-                }

-            }

-            paramNode = paramNode.getNextSibling();

-        }

-    }

-

-    private void convertMaterials(Element mat) {

-        String id = mat.getAttribute("id");

-        NodeList nl = mat.getElementsByTagName("instance_effect");

-        if (nl != null && nl.getLength() == 1) {

-            Element ref = (Element)nl.item(0);

-            String url = ref.getAttribute("url");

-            ArrayList<ShaderParam> params = mEffectsParams.get(url.substring(1));

-            mEffectsParams.put(id, params);

-        }

-    }

-

-    private void convertGeometries(Element geo) {

-        String id = geo.getAttribute("id");

-        String name = geo.getAttribute("name");

-        if (!id.equals(name)) {

-            mMeshIdNameMap.put(id, name);

-        }

-    }

-

-    private void convertEffects(Element fx) {

-        String id = fx.getAttribute("id");

-        ArrayList<ShaderParam> params = new ArrayList<ShaderParam>();

-

-        NodeList nl = fx.getElementsByTagName("newparam");

-        if (nl != null) {

-            for(int i = 0; i < nl.getLength(); i++) {

-                Element field = (Element)nl.item(i);

-                field.setIdAttribute("sid", true);

-            }

-        }

-

-        nl = fx.getElementsByTagName("blinn");

-        if (nl != null) {

-            for(int i = 0; i < nl.getLength(); i++) {

-                Element field = (Element)nl.item(i);

-                //Log.v(TAG, "blinn");

-                extractParams(field, params);

-            }

-        }

-        nl = fx.getElementsByTagName("lambert");

-        if (nl != null) {

-            for(int i = 0; i < nl.getLength(); i++) {

-                Element field = (Element)nl.item(i);

-                //Log.v(TAG, "lambert");

-                extractParams(field, params);

-            }

-        }

-        nl = fx.getElementsByTagName("phong");

-        if (nl != null) {

-            for(int i = 0; i < nl.getLength(); i++) {

-                Element field = (Element)nl.item(i);

-                //Log.v(TAG, "phong");

-                extractParams(field, params);

-            }

-        }

-        mEffectsParams.put(id, params);

-    }

-

-    private void convertLight(Element light) {

-        String name = light.getAttribute("name");

-        String id = light.getAttribute("id");

-

-        // Determine type

-        String[] knownTypes = { "point", "spot", "directional" };

-        final int POINT_LIGHT = 0;

-        final int SPOT_LIGHT = 1;

-        final int DIR_LIGHT = 2;

-        int type = -1;

-        for (int i = 0; i < knownTypes.length; i ++) {

-            NodeList nl = light.getElementsByTagName(knownTypes[i]);

-            if (nl != null && nl.getLength() != 0) {

-                type = i;

-                break;

-            }

-        }

-

-        //Log.v(TAG, "Found Light Type " + type);

-

-        LightBase sceneLight = null;

-        switch (type) {

-        case POINT_LIGHT:

-            sceneLight = new PointLight();

-            break;

-        case SPOT_LIGHT: // TODO: finish light types

-            break;

-        case DIR_LIGHT: // TODO: finish light types

-            break;

-        }

-

-        if (sceneLight == null) {

-            return;

-        }

-

-        Float3 color = getFloat3(light, "color");

-        sceneLight.setColor(color.x, color.y, color.z);

-        sceneLight.setName(name);

-        mScene.appendLight(sceneLight);

-        mLights.put(id, sceneLight);

-

-        //Log.v(TAG, "Light " + name + " color " + toString(color));

-    }

-

-    private void convertCamera(Element camera) {

-        String name = camera.getAttribute("name");

-        String id = camera.getAttribute("id");

-        float fov = 30.0f;

-        if (getString(camera, "yfov") != null) {

-            fov = getFloat(camera, "yfov");

-        } else if(getString(camera, "xfov") != null) {

-            float aspect = getFloat(camera, "aspect_ratio");

-            fov = getFloat(camera, "xfov") / aspect;

-        }

-

-        float near = getFloat(camera, "znear");

-        float far = getFloat(camera, "zfar");

-

-        Camera sceneCamera = new Camera();

-        sceneCamera.setFOV(fov);

-        sceneCamera.setNear(near);

-        sceneCamera.setFar(far);

-        sceneCamera.setName(name);

-        mScene.appendCamera(sceneCamera);

-        mCameras.put(id, sceneCamera);

-    }

-

-    private void convertImage(Element img) {

-        String name = img.getAttribute("name");

-        String id = img.getAttribute("id");

-        String file = getString(img, "init_from");

-

-        Texture2D tex = new Texture2D();

-        tex.setFileName(file);

-        tex.setFileDir(mRootDir);

-        mScene.appendTextures(tex);

-        mImages.put(id, tex);

-    }

-

-    private void getScene(Element scene) {

-        String name = scene.getAttribute("name");

-        String id = scene.getAttribute("id");

-

-        Node childNode = scene.getFirstChild();

-        while (childNode != null) {

-            if (childNode.getNodeType() == Node.ELEMENT_NODE) {

-                String indent = "";

-                getNode((Element)childNode, null, indent);

-            }

-            childNode = childNode.getNextSibling();

-        }

-    }

-

-    private String getString(Element elem, String name) {

-        String text = null;

-        NodeList nl = elem.getElementsByTagName(name);

-        if (nl != null && nl.getLength() != 0) {

-            text = ((Element)nl.item(0)).getFirstChild().getNodeValue();

-        }

-        return text;

-    }

-

-    private String getString(Element elem) {

-        String text = null;

-        text = elem.getFirstChild().getNodeValue();

-        return text;

-    }

-

-    private int getInt(Element elem, String name) {

-        return Integer.parseInt(getString(elem, name));

-    }

-

-    private float getFloat(Element elem, String name) {

-        return Float.parseFloat(getString(elem, name));

-    }

-

-    private float getFloat(Element elem) {

-        return Float.parseFloat(getString(elem));

-    }

-

-    private Float3 parseFloat3(String valueString) {

-        StringTokenizer st = new StringTokenizer(valueString);

-        float x = Float.parseFloat(st.nextToken());

-        float y = Float.parseFloat(st.nextToken());

-        float z = Float.parseFloat(st.nextToken());

-        return new Float3(x, y, z);

-    }

-

-    private Float4 parseFloat4(String valueString) {

-        StringTokenizer st = new StringTokenizer(valueString);

-        float x = Float.parseFloat(st.nextToken());

-        float y = Float.parseFloat(st.nextToken());

-        float z = Float.parseFloat(st.nextToken());

-        float w = Float.parseFloat(st.nextToken());

-        return new Float4(x, y, z, w);

-    }

-

-    private Float3 getFloat3(Element elem, String name) {

-        String valueString = getString(elem, name);

-        return parseFloat3(valueString);

-    }

-

-    private Float4 getFloat4(Element elem, String name) {

-        String valueString = getString(elem, name);

-        return parseFloat4(valueString);

-    }

-

-    private Float3 getFloat3(Element elem) {

-        String valueString = getString(elem);

-        return parseFloat3(valueString);

-    }

-

-    private Float4 getFloat4(Element elem) {

-        String valueString = getString(elem);

-        return parseFloat4(valueString);

-    }

-}

diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaScene.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaScene.java
deleted file mode 100644
index 301075e..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaScene.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.FileInputStream;
-import java.io.BufferedInputStream;
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Vector;
-
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.AsyncTask;
-import android.renderscript.*;
-import android.renderscript.Allocation.MipmapControl;
-import android.renderscript.Element.Builder;
-import android.renderscript.Font.Style;
-import android.renderscript.Program.TextureType;
-import android.renderscript.ProgramStore.DepthFunc;
-import android.util.Log;
-import com.android.scenegraph.SceneManager.SceneLoadedCallback;
-
-
-public class ColladaScene {
-
-    private String modelName;
-    private static String TAG = "ColladaScene";
-    private final int STATE_LAST_FOCUS = 1;
-    boolean mLoadFromSD = false;
-
-    SceneLoadedCallback mCallback;
-
-    public ColladaScene(String name, SceneLoadedCallback cb) {
-        modelName = name;
-        mCallback = cb;
-    }
-
-    public void init(RenderScriptGL rs, Resources res) {
-        mRS = rs;
-        mRes = res;
-
-        mLoadFromSD = SceneManager.isSDCardPath(modelName);
-
-        new ColladaLoaderTask().execute(modelName);
-    }
-
-    private Resources mRes;
-    private RenderScriptGL mRS;
-    Scene mActiveScene;
-
-    private class ColladaLoaderTask extends AsyncTask<String, Void, Boolean> {
-        ColladaParser sceneSource;
-        protected Boolean doInBackground(String... names) {
-            String rootDir = names[0].substring(0, names[0].lastIndexOf('/') + 1);
-            long start = System.currentTimeMillis();
-            sceneSource = new ColladaParser();
-            InputStream is = null;
-            try {
-                if (!mLoadFromSD) {
-                    is = mRes.getAssets().open(names[0]);
-                } else {
-                    File f = new File(names[0]);
-                    is = new BufferedInputStream(new FileInputStream(f));
-                }
-            } catch (IOException e) {
-                Log.e(TAG, "Could not open collada file");
-                return new Boolean(false);
-            }
-            long end = System.currentTimeMillis();
-            Log.v("TIMER", "Stream load time: " + (end - start));
-
-            start = System.currentTimeMillis();
-            sceneSource.init(is, rootDir);
-            end = System.currentTimeMillis();
-            Log.v("TIMER", "Collada parse time: " + (end - start));
-            return new Boolean(true);
-        }
-
-        protected void onPostExecute(Boolean result) {
-            mActiveScene = sceneSource.getScene();
-            if (mCallback != null) {
-                mCallback.mLoadedScene = mActiveScene;
-                mCallback.run();
-            }
-
-            String shortName = modelName.substring(0, modelName.lastIndexOf('.'));
-            new A3DLoaderTask().execute(shortName + ".a3d");
-        }
-    }
-
-    private class A3DLoaderTask extends AsyncTask<String, Void, Boolean> {
-        protected Boolean doInBackground(String... names) {
-            long start = System.currentTimeMillis();
-            FileA3D model;
-            if (!mLoadFromSD) {
-                model = FileA3D.createFromAsset(mRS, mRes.getAssets(), names[0]);
-            } else {
-                model = FileA3D.createFromFile(mRS, names[0]);
-            }
-            int numModels = model.getIndexEntryCount();
-            for (int i = 0; i < numModels; i ++) {
-                FileA3D.IndexEntry entry = model.getIndexEntry(i);
-                if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) {
-                    mActiveScene.meshLoaded(entry.getMesh());
-                }
-            }
-            long end = System.currentTimeMillis();
-            Log.v("TIMER", "A3D load time: " + (end - start));
-            return new Boolean(true);
-        }
-
-        protected void onPostExecute(Boolean result) {
-        }
-    }
-
-}
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java
deleted file mode 100644
index 9274b17..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-import java.util.ArrayList;
-
-import com.android.scenegraph.SceneManager;
-
-import android.renderscript.*;
-import android.renderscript.Float3;
-import android.renderscript.Matrix4f;
-import android.util.Log;
-
-/**
- * @hide
- */
-public class CompoundTransform extends Transform {
-
-    public static abstract class Component {
-        String mName;
-        CompoundTransform mParent;
-        int mParentIndex;
-        protected ScriptField_TransformComponent_s.Item mData;
-
-        Component(int type, String name) {
-            mData = new ScriptField_TransformComponent_s.Item();
-            mData.type = type;
-            mName = name;
-        }
-
-        void setNameAlloc() {
-            RenderScriptGL rs = SceneManager.getRS();
-            if (mData.name != null)  {
-                return;
-            }
-            mData.name = SceneManager.getCachedAlloc(getName());
-            if (mData.name == null) {
-                mData.name = SceneManager.getStringAsAllocation(rs, getName());
-                SceneManager.cacheAlloc(getName(), mData.name);
-            }
-        }
-
-        ScriptField_TransformComponent_s.Item getRSData() {
-            setNameAlloc();
-            return mData;
-        }
-
-        protected void update() {
-            if (mParent != null) {
-                mParent.updateRSComponent(this);
-            }
-        }
-
-        public String getName() {
-            return mName;
-        }
-    }
-
-    public static class TranslateComponent extends Component {
-        public TranslateComponent(String name, Float3 translate) {
-            super(ScriptC_export.const_Transform_TRANSLATE, name);
-            setValue(translate);
-        }
-        public Float3 getValue() {
-            return new Float3(mData.value.x, mData.value.y, mData.value.z);
-        }
-        public void setValue(Float3 val) {
-            mData.value.x = val.x;
-            mData.value.y = val.y;
-            mData.value.z = val.z;
-            update();
-        }
-    }
-
-    public static class RotateComponent extends Component {
-        public RotateComponent(String name, Float3 axis, float angle) {
-            super(ScriptC_export.const_Transform_ROTATE, name);
-            setAxis(axis);
-            setAngle(angle);
-        }
-        public Float3 getAxis() {
-            return new Float3(mData.value.x, mData.value.y, mData.value.z);
-        }
-        public float getAngle() {
-            return mData.value.w;
-        }
-        public void setAxis(Float3 val) {
-            mData.value.x = val.x;
-            mData.value.y = val.y;
-            mData.value.z = val.z;
-            update();
-        }
-        public void setAngle(float val) {
-            mData.value.w = val;
-            update();
-        }
-    }
-
-    public static class ScaleComponent extends Component {
-        public ScaleComponent(String name, Float3 scale) {
-            super(ScriptC_export.const_Transform_SCALE, name);
-            setValue(scale);
-        }
-        public Float3 getValue() {
-            return new Float3(mData.value.x, mData.value.y, mData.value.z);
-        }
-        public void setValue(Float3 val) {
-            mData.value.x = val.x;
-            mData.value.y = val.y;
-            mData.value.z = val.z;
-            update();
-        }
-    }
-
-    ScriptField_TransformComponent_s mComponentField;
-    public ArrayList<Component> mTransformComponents;
-
-    public CompoundTransform() {
-        mTransformComponents = new ArrayList<Component>();
-    }
-
-    public TranslateComponent addTranslate(String name, Float3 translate) {
-        TranslateComponent c = new TranslateComponent(name, translate);
-        addComponent(c);
-        return c;
-    }
-
-    public RotateComponent addRotate(String name, Float3 axis, float angle) {
-        RotateComponent c = new RotateComponent(name, axis, angle);
-        addComponent(c);
-        return c;
-    }
-
-    public ScaleComponent addScale(String name, Float3 scale) {
-        ScaleComponent c = new ScaleComponent(name, scale);
-        addComponent(c);
-        return c;
-    }
-
-    public void addComponent(Component c) {
-        if (c.mParent != null) {
-            throw new IllegalArgumentException("Transform components may not be shared");
-        }
-        c.mParent = this;
-        c.mParentIndex = mTransformComponents.size();
-        mTransformComponents.add(c);
-        updateRSComponentAllocation();
-    }
-
-    public void setComponent(int index, Component c) {
-        if (c.mParent != null) {
-            throw new IllegalArgumentException("Transform components may not be shared");
-        }
-        if (index >= mTransformComponents.size()) {
-            throw new IllegalArgumentException("Invalid component index");
-        }
-        c.mParent = this;
-        c.mParentIndex = index;
-        mTransformComponents.set(index, c);
-        updateRSComponent(c);
-    }
-
-    void updateRSComponent(Component c) {
-        if (mField == null || mComponentField == null) {
-            return;
-        }
-        mComponentField.set(c.getRSData(), c.mParentIndex, true);
-        mField.set_isDirty(0, 1, true);
-    }
-
-    void updateRSComponentAllocation() {
-        if (mField == null) {
-            return;
-        }
-        initLocalData();
-
-        mField.set_components(0, mTransformData.components, false);
-        mField.set_isDirty(0, 1, true);
-    }
-
-    void initLocalData() {
-        RenderScriptGL rs = SceneManager.getRS();
-        int numComponenets = mTransformComponents.size();
-        if (numComponenets > 0) {
-            mComponentField = new ScriptField_TransformComponent_s(rs, numComponenets);
-            for (int i = 0; i < numComponenets; i ++) {
-                Component ith = mTransformComponents.get(i);
-                mComponentField.set(ith.getRSData(), i, false);
-            }
-            mComponentField.copyAll();
-
-            mTransformData.components = mComponentField.getAllocation();
-        }
-    }
-}
-
-
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java
deleted file mode 100644
index 1502458..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-import java.util.ArrayList;
-
-import com.android.scenegraph.Scene;
-import com.android.scenegraph.SceneManager;
-
-import android.renderscript.Element;
-import android.renderscript.Float4;
-import android.renderscript.Matrix4f;
-import android.renderscript.ProgramFragment;
-import android.renderscript.ProgramStore;
-import android.renderscript.ProgramVertex;
-import android.renderscript.RenderScriptGL;
-import android.util.Log;
-
-/**
- * @hide
- */
-public class Float4Param extends ShaderParam {
-    private static String TAG = "Float4Param";
-
-    LightBase mLight;
-
-    public Float4Param(String name) {
-        super(name);
-    }
-
-    public Float4Param(String name, float x) {
-        super(name);
-        set(x, 0, 0, 0);
-    }
-
-    public Float4Param(String name, float x, float y) {
-        super(name);
-        set(x, y, 0, 0);
-    }
-
-    public Float4Param(String name, float x, float y, float z) {
-        super(name);
-        set(x, y, z, 0);
-    }
-
-    public Float4Param(String name, float x, float y, float z, float w) {
-        super(name);
-        set(x, y, z, w);
-    }
-
-    void set(float x, float y, float z, float w) {
-        mData.float_value.x = x;
-        mData.float_value.y = y;
-        mData.float_value.z = z;
-        mData.float_value.w = w;
-        if (mField != null) {
-            mField.set_float_value(0, mData.float_value, true);
-        }
-        incTimestamp();
-    }
-
-    public void setValue(Float4 v) {
-        set(v.x, v.y, v.z, v.w);
-    }
-
-    public Float4 getValue() {
-        return mData.float_value;
-    }
-
-    public void setLight(LightBase l) {
-        mLight = l;
-        if (mField != null) {
-            mData.light = mLight.getRSData().getAllocation();
-            mField.set_light(0, mData.light, true);
-        }
-        incTimestamp();
-    }
-
-    boolean findLight(String property) {
-        String indexStr = mParamName.substring(property.length() + 1);
-        if (indexStr == null) {
-            Log.e(TAG, "Invalid light index.");
-            return false;
-        }
-        int index = Integer.parseInt(indexStr);
-        if (index == -1) {
-            return false;
-        }
-        Scene parentScene = SceneManager.getInstance().getActiveScene();
-        ArrayList<LightBase> allLights = parentScene.getLights();
-        if (index >= allLights.size()) {
-            return false;
-        }
-        mLight = allLights.get(index);
-        if (mLight == null) {
-            return false;
-        }
-        return true;
-    }
-
-    int getTypeFromName() {
-        int paramType = ScriptC_export.const_ShaderParam_FLOAT4_DATA;
-        if (mParamName.equalsIgnoreCase(cameraPos)) {
-            paramType = ScriptC_export.const_ShaderParam_FLOAT4_CAMERA_POS;
-        } else if(mParamName.equalsIgnoreCase(cameraDir)) {
-            paramType = ScriptC_export.const_ShaderParam_FLOAT4_CAMERA_DIR;
-        } else if(mParamName.startsWith(lightColor) && findLight(lightColor)) {
-            paramType = ScriptC_export.const_ShaderParam_FLOAT4_LIGHT_COLOR;
-        } else if(mParamName.startsWith(lightPos) && findLight(lightPos)) {
-            paramType = ScriptC_export.const_ShaderParam_FLOAT4_LIGHT_POS;
-        } else if(mParamName.startsWith(lightDir) && findLight(lightDir)) {
-            paramType = ScriptC_export.const_ShaderParam_FLOAT4_LIGHT_DIR;
-        }
-        return paramType;
-    }
-
-    void initLocalData() {
-        mData.type = getTypeFromName();
-        if (mCamera != null) {
-            mData.camera = mCamera.getRSData().getAllocation();
-        }
-        if (mLight != null) {
-            mData.light = mLight.getRSData().getAllocation();
-        }
-    }
-}
-
-
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java
deleted file mode 100644
index 8a468db..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-import java.util.ArrayList;
-
-import com.android.scenegraph.TextureBase;
-
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.renderscript.ProgramFragment.Builder;
-import android.util.Log;
-
-/**
- * @hide
- */
-public class FragmentShader extends Shader {
-    ProgramFragment mProgram;
-    ScriptField_FragmentShader_s mField;
-
-    public static class Builder {
-
-        FragmentShader mShader;
-        ProgramFragment.Builder mBuilder;
-
-        public Builder(RenderScriptGL rs) {
-            mShader = new FragmentShader();
-            mBuilder = new ProgramFragment.Builder(rs);
-        }
-
-        public Builder setShader(Resources resources, int resourceID) {
-            mBuilder.setShader(resources, resourceID);
-            return this;
-        }
-
-        public Builder setShader(String code) {
-            mBuilder.setShader(code);
-            return this;
-        }
-
-        public Builder setObjectConst(Type type) {
-            mShader.mPerObjConstants = type;
-            return this;
-        }
-
-        public Builder setShaderConst(Type type) {
-            mShader.mPerShaderConstants = type;
-            return this;
-        }
-
-        public Builder addShaderTexture(Program.TextureType texType, String name) {
-            mShader.mShaderTextureNames.add(name);
-            mShader.mShaderTextureTypes.add(texType);
-            return this;
-        }
-
-        public Builder addTexture(Program.TextureType texType, String name) {
-            mShader.mTextureNames.add(name);
-            mShader.mTextureTypes.add(texType);
-            return this;
-        }
-
-        public FragmentShader create() {
-            if (mShader.mPerShaderConstants != null) {
-                mBuilder.addConstant(mShader.mPerShaderConstants);
-            }
-            if (mShader.mPerObjConstants != null) {
-                mBuilder.addConstant(mShader.mPerObjConstants);
-            }
-            for (int i = 0; i < mShader.mTextureTypes.size(); i ++) {
-                mBuilder.addTexture(mShader.mTextureTypes.get(i),
-                                    mShader.mTextureNames.get(i));
-            }
-            for (int i = 0; i < mShader.mShaderTextureTypes.size(); i ++) {
-                mBuilder.addTexture(mShader.mShaderTextureTypes.get(i),
-                                    mShader.mShaderTextureNames.get(i));
-            }
-
-            mShader.mProgram = mBuilder.create();
-            return mShader;
-        }
-    }
-
-    public ProgramFragment getProgram() {
-        return mProgram;
-    }
-
-    ScriptField_ShaderParam_s getTextureParams() {
-        RenderScriptGL rs = SceneManager.getRS();
-        Resources res = SceneManager.getRes();
-        if (rs == null || res == null) {
-            return null;
-        }
-
-        ArrayList<ScriptField_ShaderParam_s.Item> paramList;
-        paramList = new ArrayList<ScriptField_ShaderParam_s.Item>();
-
-        int shaderTextureStart = mTextureTypes.size();
-        for (int i = 0; i < mShaderTextureNames.size(); i ++) {
-            ShaderParam sp = mSourceParams.get(mShaderTextureNames.get(i));
-            if (sp != null && sp instanceof TextureParam) {
-                TextureParam p = (TextureParam)sp;
-                ScriptField_ShaderParam_s.Item paramRS = new ScriptField_ShaderParam_s.Item();
-                paramRS.bufferOffset = shaderTextureStart + i;
-                paramRS.transformTimestamp = 0;
-                paramRS.dataTimestamp = 0;
-                paramRS.data = p.getRSData().getAllocation();
-                paramList.add(paramRS);
-            }
-        }
-
-        ScriptField_ShaderParam_s rsParams = null;
-        int paramCount = paramList.size();
-        if (paramCount != 0) {
-            rsParams = new ScriptField_ShaderParam_s(rs, paramCount);
-            for (int i = 0; i < paramCount; i++) {
-                rsParams.set(paramList.get(i), i, false);
-            }
-            rsParams.copyAll();
-        }
-        return rsParams;
-    }
-
-    ScriptField_FragmentShader_s getRSData() {
-        if (mField != null) {
-            return mField;
-        }
-
-        RenderScriptGL rs = SceneManager.getRS();
-        Resources res = SceneManager.getRes();
-        if (rs == null || res == null) {
-            return null;
-        }
-
-        ScriptField_FragmentShader_s.Item item = new ScriptField_FragmentShader_s.Item();
-        item.program = mProgram;
-
-        ScriptField_ShaderParam_s texParams = getTextureParams();
-        if (texParams != null) {
-            item.shaderTextureParams = texParams.getAllocation();
-        }
-
-        linkConstants(rs);
-        if (mPerShaderConstants != null) {
-            item.shaderConst = mConstantBuffer;
-            item.shaderConstParams = mConstantBufferParams.getAllocation();
-            mProgram.bindConstants(item.shaderConst, 0);
-        }
-
-        item.objectConstIndex = -1;
-        if (mPerObjConstants != null) {
-            item.objectConstIndex = mPerShaderConstants != null ? 1 : 0;
-        }
-
-        mField = new ScriptField_FragmentShader_s(rs, 1);
-        mField.set(item, 0, true);
-        return mField;
-    }
-}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/LightBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/LightBase.java
deleted file mode 100644
index 8f5e2e7..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/LightBase.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-import java.util.ArrayList;
-
-import android.renderscript.Float3;
-import android.renderscript.Float4;
-import android.renderscript.Matrix4f;
-import android.renderscript.RenderScriptGL;
-import android.util.Log;
-
-/**
- * @hide
- */
-public abstract class LightBase extends SceneGraphBase {
-    static final int RS_LIGHT_POINT = 0;
-    static final int RS_LIGHT_DIRECTIONAL = 1;
-
-    ScriptField_Light_s mField;
-    ScriptField_Light_s.Item mFieldData;
-    Transform mTransform;
-    Float4 mColor;
-    float mIntensity;
-    public LightBase() {
-        mColor = new Float4(0.0f, 0.0f, 0.0f, 0.0f);
-        mIntensity = 1.0f;
-    }
-
-    public void setTransform(Transform t) {
-        mTransform = t;
-        updateRSData();
-    }
-
-    public void setColor(float r, float g, float b) {
-        mColor.x = r;
-        mColor.y = g;
-        mColor.z = b;
-        updateRSData();
-    }
-
-    public void setColor(Float3 c) {
-        setColor(c.x, c.y, c.z);
-    }
-
-    public void setIntensity(float i) {
-        mIntensity = i;
-        updateRSData();
-    }
-
-    public void setName(String n) {
-        super.setName(n);
-        updateRSData();
-    }
-
-    protected void updateRSData() {
-        if (mField == null) {
-            return;
-        }
-        RenderScriptGL rs = SceneManager.getRS();
-        mFieldData.transformMatrix = mTransform.getRSData().getAllocation();
-        mFieldData.name = getNameAlloc(rs);
-        mFieldData.color = mColor;
-        mFieldData.intensity = mIntensity;
-
-        initLocalData();
-
-        mField.set(mFieldData, 0, true);
-    }
-
-    abstract void initLocalData();
-
-    ScriptField_Light_s getRSData() {
-        if (mField != null) {
-            return mField;
-        }
-
-        RenderScriptGL rs = SceneManager.getRS();
-        if (rs == null) {
-            return null;
-        }
-        if (mField == null) {
-            mField = new ScriptField_Light_s(rs, 1);
-            mFieldData = new ScriptField_Light_s.Item();
-        }
-
-        updateRSData();
-
-        return mField;
-    }
-}
-
-
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java
deleted file mode 100644
index 6d70bc9..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-import java.util.ArrayList;
-
-import android.renderscript.Matrix4f;
-import android.util.Log;
-
-/**
- * @hide
- */
-public class MatrixTransform extends Transform {
-
-    Matrix4f mLocalMatrix;
-    public MatrixTransform() {
-        mLocalMatrix = new Matrix4f();
-    }
-
-    public void setMatrix(Matrix4f matrix) {
-        mLocalMatrix = matrix;
-        updateRSData();
-    }
-
-    public Matrix4f getMatrix() {
-        return new Matrix4f(mLocalMatrix.getArray());
-    }
-
-    void initLocalData() {
-        mTransformData.localMat = mLocalMatrix;
-    }
-
-    void updateRSData() {
-        if (mField == null) {
-            return;
-        }
-        mField.set_localMat(0, mLocalMatrix, false);
-        mField.set_isDirty(0, 1, true);
-    }
-}
-
-
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/PointLight.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/PointLight.java
deleted file mode 100644
index 574bafc..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/PointLight.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-import java.util.ArrayList;
-
-import android.renderscript.Matrix4f;
-import android.renderscript.ProgramFragment;
-import android.renderscript.ProgramStore;
-import android.renderscript.ProgramVertex;
-import android.util.Log;
-
-/**
- * @hide
- */
-public class PointLight extends LightBase {
-    public PointLight() {
-    }
-
-     void initLocalData() {
-        mFieldData.type = RS_LIGHT_POINT;
-    }
-}
-
-
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderPass.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderPass.java
deleted file mode 100644
index 02fd69d..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderPass.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-import java.util.ArrayList;
-
-import android.util.Log;
-
-import android.renderscript.*;
-import android.content.res.Resources;
-
-/**
- * @hide
- */
-public class RenderPass extends SceneGraphBase {
-
-    TextureRenderTarget mColorTarget;
-    Float4 mClearColor;
-    boolean mShouldClearColor;
-
-    TextureRenderTarget mDepthTarget;
-    float mClearDepth;
-    boolean mShouldClearDepth;
-
-    ArrayList<RenderableBase> mObjectsToDraw;
-
-    Camera mCamera;
-
-    ScriptField_RenderPass_s.Item mRsField;
-
-    public RenderPass() {
-        mObjectsToDraw = new ArrayList<RenderableBase>();
-        mClearColor = new Float4(0.0f, 0.0f, 0.0f, 0.0f);
-        mShouldClearColor = true;
-        mClearDepth = 1.0f;
-        mShouldClearDepth = true;
-    }
-
-    public void appendRenderable(Renderable d) {
-        mObjectsToDraw.add(d);
-    }
-
-    public void setCamera(Camera c) {
-        mCamera = c;
-    }
-
-    public void setColorTarget(TextureRenderTarget colorTarget) {
-        mColorTarget = colorTarget;
-    }
-    public void setClearColor(Float4 clearColor) {
-        mClearColor = clearColor;
-    }
-    public void setShouldClearColor(boolean shouldClearColor) {
-        mShouldClearColor = shouldClearColor;
-    }
-
-    public void setDepthTarget(TextureRenderTarget depthTarget) {
-        mDepthTarget = depthTarget;
-    }
-    public void setClearDepth(float clearDepth) {
-        mClearDepth = clearDepth;
-    }
-    public void setShouldClearDepth(boolean shouldClearDepth) {
-        mShouldClearDepth = shouldClearDepth;
-    }
-
-    public ArrayList<RenderableBase> getRenderables() {
-        return mObjectsToDraw;
-    }
-
-    ScriptField_RenderPass_s.Item getRsField(RenderScriptGL rs, Resources res) {
-        if (mRsField != null) {
-            return mRsField;
-        }
-
-        mRsField = new ScriptField_RenderPass_s.Item();
-        if (mColorTarget != null) {
-            mRsField.color_target = mColorTarget.getRsData(true).get_texture(0);
-        }
-        if (mColorTarget != null) {
-            mRsField.depth_target = mDepthTarget.getRsData(true).get_texture(0);
-        }
-        mRsField.camera = mCamera != null ? mCamera.getRSData().getAllocation() : null;
-
-        if (mObjectsToDraw.size() != 0) {
-            Allocation drawableData = Allocation.createSized(rs,
-                                                              Element.ALLOCATION(rs),
-                                                              mObjectsToDraw.size());
-            Allocation[] drawableAllocs = new Allocation[mObjectsToDraw.size()];
-            for (int i = 0; i < mObjectsToDraw.size(); i ++) {
-                Renderable dI = (Renderable)mObjectsToDraw.get(i);
-                drawableAllocs[i] = dI.getRsField(rs, res).getAllocation();
-            }
-            drawableData.copyFrom(drawableAllocs);
-            mRsField.objects = drawableData;
-        }
-
-        mRsField.clear_color = mClearColor;
-        mRsField.clear_depth = mClearDepth;
-        mRsField.should_clear_color = mShouldClearColor;
-        mRsField.should_clear_depth = mShouldClearDepth;
-        return mRsField;
-    }
-}
-
-
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderState.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderState.java
deleted file mode 100644
index c08a722..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderState.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-import java.util.ArrayList;
-import android.content.res.Resources;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.Matrix4f;
-import android.renderscript.ProgramFragment;
-import android.renderscript.ProgramRaster;
-import android.renderscript.ProgramStore;
-import android.renderscript.ProgramVertex;
-import android.renderscript.RSRuntimeException;
-import android.renderscript.RenderScript;
-import android.renderscript.RenderScriptGL;
-import android.util.Log;
-
-/**
- * @hide
- */
-public class RenderState extends SceneGraphBase {
-    VertexShader mVertex;
-    FragmentShader mFragment;
-    ProgramStore mStore;
-    ProgramRaster mRaster;
-
-    ScriptField_RenderState_s mField;
-
-    public RenderState(VertexShader pv,
-                       FragmentShader pf,
-                       ProgramStore ps,
-                       ProgramRaster pr) {
-        mVertex = pv;
-        mFragment = pf;
-        mStore = ps;
-        mRaster = pr;
-    }
-
-    public RenderState(RenderState r) {
-        mVertex = r.mVertex;
-        mFragment = r.mFragment;
-        mStore = r.mStore;
-        mRaster = r.mRaster;
-    }
-
-    public void setProgramVertex(VertexShader pv) {
-        mVertex = pv;
-        updateRSData();
-    }
-
-    public void setProgramFragment(FragmentShader pf) {
-        mFragment = pf;
-        updateRSData();
-    }
-
-    public void setProgramStore(ProgramStore ps) {
-        mStore = ps;
-        updateRSData();
-    }
-
-    public void setProgramRaster(ProgramRaster pr) {
-        mRaster = pr;
-        updateRSData();
-    }
-
-    void updateRSData() {
-        if (mField == null) {
-            return;
-        }
-        ScriptField_RenderState_s.Item item = new ScriptField_RenderState_s.Item();
-        item.pv = mVertex.getRSData().getAllocation();
-        item.pf = mFragment.getRSData().getAllocation();
-        item.ps = mStore;
-        item.pr = mRaster;
-
-        mField.set(item, 0, true);
-    }
-
-    public ScriptField_RenderState_s getRSData() {
-        if (mField != null) {
-            return mField;
-        }
-
-        RenderScriptGL rs = SceneManager.getRS();
-        if (rs == null) {
-            return null;
-        }
-
-        mField = new ScriptField_RenderState_s(rs, 1);
-        updateRSData();
-
-        return mField;
-    }
-}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java
deleted file mode 100644
index 9266f30..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-
-import com.android.scenegraph.Float4Param;
-import com.android.scenegraph.MatrixTransform;
-import com.android.scenegraph.SceneManager;
-import com.android.scenegraph.ShaderParam;
-import com.android.scenegraph.TransformParam;
-
-import android.content.res.Resources;
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.Element.DataType;
-import android.renderscript.Matrix4f;
-import android.renderscript.Mesh;
-import android.renderscript.ProgramFragment;
-import android.renderscript.ProgramStore;
-import android.renderscript.ProgramVertex;
-import android.renderscript.RenderScriptGL;
-import android.util.Log;
-
-/**
- * @hide
- */
-public class Renderable extends RenderableBase {
-    HashMap<String, ShaderParam> mSourceParams;
-
-    RenderState mRenderState;
-    Transform mTransform;
-
-    String mMeshName;
-    String mMeshIndexName;
-
-    public String mMaterialName;
-
-    ScriptField_Renderable_s mField;
-    ScriptField_Renderable_s.Item mData;
-
-    public Renderable() {
-        mSourceParams = new HashMap<String, ShaderParam>();
-        mData = new ScriptField_Renderable_s.Item();
-    }
-
-    public void setCullType(int cull) {
-        mData.cullType = cull;
-    }
-
-    public void setRenderState(RenderState renderState) {
-        mRenderState = renderState;
-        if (mField != null) {
-            RenderScriptGL rs = SceneManager.getRS();
-            updateFieldItem(rs);
-            mField.set(mData, 0, true);
-        }
-    }
-
-    public void setMesh(Mesh mesh) {
-        mData.mesh = mesh;
-        if (mField != null) {
-            mField.set_mesh(0, mData.mesh, true);
-        }
-    }
-
-    public void setMesh(String mesh, String indexName) {
-        mMeshName = mesh;
-        mMeshIndexName = indexName;
-    }
-
-    public void setMaterialName(String name) {
-        mMaterialName = name;
-    }
-
-    public Transform getTransform() {
-        return mTransform;
-    }
-
-    public void setTransform(Transform t) {
-        mTransform = t;
-        if (mField != null) {
-            RenderScriptGL rs = SceneManager.getRS();
-            updateFieldItem(rs);
-            mField.set(mData, 0, true);
-        }
-    }
-
-    public void appendSourceParams(ShaderParam p) {
-        mSourceParams.put(p.getParamName(), p);
-        // Possibly lift this restriction later
-        if (mField != null) {
-            throw new RuntimeException("Can't add source params to objects that are rendering");
-        }
-    }
-
-    public void resolveMeshData(Mesh mesh) {
-        mData.mesh = mesh;
-        if (mData.mesh == null) {
-            Log.v("DRAWABLE: ", "*** NO MESH *** " + mMeshName);
-            return;
-        }
-        int subIndexCount = mData.mesh.getPrimitiveCount();
-        if (subIndexCount == 1 || mMeshIndexName == null) {
-            mData.meshIndex = 0;
-        } else {
-            for (int i = 0; i < subIndexCount; i ++) {
-                if (mData.mesh.getIndexSetAllocation(i).getName().equals(mMeshIndexName)) {
-                    mData.meshIndex = i;
-                    break;
-                }
-            }
-        }
-        if (mField != null) {
-            mField.set(mData, 0, true);
-        }
-    }
-
-    void updateTextures(RenderScriptGL rs) {
-        Iterator<ShaderParam> allParamsIter = mSourceParams.values().iterator();
-        int paramIndex = 0;
-        while (allParamsIter.hasNext()) {
-            ShaderParam sp = allParamsIter.next();
-            if (sp instanceof TextureParam) {
-                TextureParam p = (TextureParam)sp;
-                TextureBase tex = p.getTexture();
-                if (tex != null) {
-                    mData.pf_textures[paramIndex++] = tex.getRsData(false).getAllocation();
-                }
-            }
-        }
-        ProgramFragment pf = mRenderState.mFragment.mProgram;
-        mData.pf_num_textures = pf != null ? Math.min(pf.getTextureCount(), paramIndex) : 0;
-        if (mField != null) {
-            mField.set_pf_textures(0, mData.pf_textures, true);
-            mField.set_pf_num_textures(0, mData.pf_num_textures, true);
-        }
-    }
-
-    public void setVisible(boolean vis) {
-        mData.cullType = vis ? 0 : 2;
-        if (mField != null) {
-            mField.set_cullType(0, mData.cullType, true);
-        }
-    }
-
-    ScriptField_Renderable_s getRsField(RenderScriptGL rs, Resources res) {
-        if (mField != null) {
-            return mField;
-        }
-        updateFieldItem(rs);
-        updateTextures(rs);
-
-        mField = new ScriptField_Renderable_s(rs, 1);
-        mField.set(mData, 0, true);
-
-        return mField;
-    }
-
-    void updateVertexConstants(RenderScriptGL rs) {
-        Allocation pvParams = null, vertexConstants = null;
-        VertexShader pv = mRenderState.mVertex;
-        if (pv != null && pv.getObjectConstants() != null) {
-            vertexConstants = Allocation.createTyped(rs, pv.getObjectConstants());
-            Element vertexConst = vertexConstants.getType().getElement();
-            pvParams = ShaderParam.fillInParams(vertexConst, mSourceParams,
-                                                mTransform).getAllocation();
-        }
-        mData.pv_const = vertexConstants;
-        mData.pv_constParams = pvParams;
-    }
-
-    void updateFragmentConstants(RenderScriptGL rs) {
-        Allocation pfParams = null, fragmentConstants = null;
-        FragmentShader pf = mRenderState.mFragment;
-        if (pf != null && pf.getObjectConstants() != null) {
-            fragmentConstants = Allocation.createTyped(rs, pf.getObjectConstants());
-            Element fragmentConst = fragmentConstants.getType().getElement();
-            pfParams = ShaderParam.fillInParams(fragmentConst, mSourceParams,
-                                                mTransform).getAllocation();
-        }
-        mData.pf_const = fragmentConstants;
-        mData.pf_constParams = pfParams;
-    }
-
-    void updateFieldItem(RenderScriptGL rs) {
-        if (mRenderState == null) {
-            mRenderState = SceneManager.getDefaultState();
-        }
-        if (mTransform == null) {
-            mTransform = SceneManager.getDefaultTransform();
-        }
-        updateVertexConstants(rs);
-        updateFragmentConstants(rs);
-
-        mData.transformMatrix = mTransform.getRSData().getAllocation();
-
-        mData.name = getNameAlloc(rs);
-        mData.render_state = mRenderState.getRSData().getAllocation();
-        mData.bVolInitialized = 0;
-    }
-}
-
-
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableBase.java
deleted file mode 100644
index 74535dd..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableBase.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-import java.util.ArrayList;
-
-import android.renderscript.Matrix4f;
-import android.renderscript.ProgramFragment;
-import android.renderscript.ProgramStore;
-import android.renderscript.ProgramVertex;
-import android.util.Log;
-
-/**
- * @hide
- */
-public class RenderableBase extends SceneGraphBase {
-    public RenderableBase() {
-    }
-}
-
-
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableGroup.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableGroup.java
deleted file mode 100644
index 590bbab..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableGroup.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-import java.util.ArrayList;
-
-import android.renderscript.Matrix4f;
-import android.renderscript.ProgramFragment;
-import android.renderscript.ProgramStore;
-import android.renderscript.ProgramVertex;
-import android.util.Log;
-
-/**
- * @hide
- */
-public class RenderableGroup extends RenderableBase {
-
-    ArrayList<RenderableBase> mChildren;
-
-    public RenderableGroup() {
-        mChildren = new ArrayList<RenderableBase>();
-    }
-
-    public void appendChildren(RenderableBase d) {
-        mChildren.add(d);
-    }
-}
-
-
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java
deleted file mode 100644
index 27336ab..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import com.android.scenegraph.Camera;
-import com.android.scenegraph.CompoundTransform;
-import com.android.scenegraph.RenderPass;
-import com.android.scenegraph.Renderable;
-import com.android.scenegraph.SceneManager;
-import com.android.scenegraph.TextureBase;
-
-import android.content.res.Resources;
-import android.os.AsyncTask;
-import android.renderscript.*;
-import android.renderscript.Mesh;
-import android.renderscript.RenderScriptGL;
-import android.util.Log;
-
-/**
- * @hide
- */
-public class Scene extends SceneGraphBase {
-    private static String TIMER_TAG = "TIMER";
-
-    CompoundTransform mRootTransforms;
-    HashMap<String, Transform> mTransformMap;
-    ArrayList<RenderPass> mRenderPasses;
-    ArrayList<LightBase> mLights;
-    ArrayList<Camera> mCameras;
-    ArrayList<FragmentShader> mFragmentShaders;
-    ArrayList<VertexShader> mVertexShaders;
-    ArrayList<RenderableBase> mRenderables;
-    HashMap<String, RenderableBase> mRenderableMap;
-    ArrayList<Texture2D> mTextures;
-
-    HashMap<String, ArrayList<Renderable> > mRenderableMeshMap;
-
-    // RS Specific stuff
-    ScriptField_SgTransform mTransformRSData;
-
-    RenderScriptGL mRS;
-    Resources mRes;
-
-    ScriptField_RenderPass_s mRenderPassAlloc;
-
-    public Scene() {
-        mRenderPasses = new ArrayList<RenderPass>();
-        mLights = new ArrayList<LightBase>();
-        mCameras = new ArrayList<Camera>();
-        mFragmentShaders = new ArrayList<FragmentShader>();
-        mVertexShaders = new ArrayList<VertexShader>();
-        mRenderables = new ArrayList<RenderableBase>();
-        mRenderableMap = new HashMap<String, RenderableBase>();
-        mRenderableMeshMap = new HashMap<String, ArrayList<Renderable> >();
-        mTextures = new ArrayList<Texture2D>();
-        mRootTransforms = new CompoundTransform();
-        mRootTransforms.setName("_scene_root_");
-        mTransformMap = new HashMap<String, Transform>();
-    }
-
-    public void appendTransform(Transform t) {
-        if (t == null) {
-            throw new RuntimeException("Adding null object");
-        }
-        mRootTransforms.appendChild(t);
-    }
-
-    public CompoundTransform appendNewCompoundTransform() {
-        CompoundTransform t = new CompoundTransform();
-        appendTransform(t);
-        return t;
-    }
-
-    public MatrixTransform appendNewMatrixTransform() {
-        MatrixTransform t = new MatrixTransform();
-        appendTransform(t);
-        return t;
-    }
-
-    // temporary
-    public void addToTransformMap(Transform t) {
-        mTransformMap.put(t.getName(), t);
-    }
-
-    public Transform getTransformByName(String name) {
-        return mTransformMap.get(name);
-    }
-
-    public void appendRenderPass(RenderPass p) {
-        if (p == null) {
-            throw new RuntimeException("Adding null object");
-        }
-        mRenderPasses.add(p);
-    }
-
-    public RenderPass appendNewRenderPass() {
-        RenderPass p = new RenderPass();
-        appendRenderPass(p);
-        return p;
-    }
-
-    public void clearRenderPasses() {
-        mRenderPasses.clear();
-    }
-
-    public void appendLight(LightBase l) {
-        if (l == null) {
-            throw new RuntimeException("Adding null object");
-        }
-        mLights.add(l);
-    }
-
-    public void appendCamera(Camera c) {
-        if (c == null) {
-            throw new RuntimeException("Adding null object");
-        }
-        mCameras.add(c);
-    }
-
-    public Camera appendNewCamera() {
-        Camera c = new Camera();
-        appendCamera(c);
-        return c;
-    }
-
-    public void appendShader(FragmentShader f) {
-        if (f == null) {
-            throw new RuntimeException("Adding null object");
-        }
-        mFragmentShaders.add(f);
-    }
-
-    public void appendShader(VertexShader v) {
-        if (v == null) {
-            throw new RuntimeException("Adding null object");
-        }
-        mVertexShaders.add(v);
-    }
-
-    public ArrayList<Camera> getCameras() {
-        return mCameras;
-    }
-
-    public ArrayList<LightBase> getLights() {
-        return mLights;
-    }
-
-    public void appendRenderable(RenderableBase d) {
-        if (d == null) {
-            throw new RuntimeException("Adding null object");
-        }
-        mRenderables.add(d);
-        if (d.getName() != null) {
-            mRenderableMap.put(d.getName(), d);
-        }
-    }
-
-    public Renderable appendNewRenderable() {
-        Renderable r = new Renderable();
-        appendRenderable(r);
-        return r;
-    }
-
-    public ArrayList<RenderableBase> getRenderables() {
-        return mRenderables;
-    }
-
-    public RenderableBase getRenderableByName(String name) {
-        return mRenderableMap.get(name);
-    }
-
-    public void appendTextures(Texture2D tex) {
-        if (tex == null) {
-            throw new RuntimeException("Adding null object");
-        }
-        mTextures.add(tex);
-    }
-
-    public void assignRenderStateToMaterial(RenderState renderState, String regex) {
-        Pattern pattern = Pattern.compile(regex);
-        int numRenderables = mRenderables.size();
-        for (int i = 0; i < numRenderables; i ++) {
-            Renderable shape = (Renderable)mRenderables.get(i);
-            Matcher m = pattern.matcher(shape.mMaterialName);
-            if (m.find()) {
-                shape.setRenderState(renderState);
-            }
-        }
-    }
-
-    public void assignRenderState(RenderState renderState) {
-        int numRenderables = mRenderables.size();
-        for (int i = 0; i < numRenderables; i ++) {
-            Renderable shape = (Renderable)mRenderables.get(i);
-            shape.setRenderState(renderState);
-        }
-    }
-
-    public void meshLoaded(Mesh m) {
-        ArrayList<Renderable> entries = mRenderableMeshMap.get(m.getName());
-        int numEntries = entries.size();
-        for (int i = 0; i < numEntries; i++) {
-            Renderable d = entries.get(i);
-            d.resolveMeshData(m);
-        }
-    }
-
-    void addToMeshMap(Renderable d) {
-        ArrayList<Renderable> entries = mRenderableMeshMap.get(d.mMeshName);
-        if (entries == null) {
-            entries = new ArrayList<Renderable>();
-            mRenderableMeshMap.put(d.mMeshName, entries);
-        }
-        entries.add(d);
-    }
-
-    public void destroyRS() {
-        SceneManager sceneManager = SceneManager.getInstance();
-        mTransformRSData = null;
-        sceneManager.mRenderLoop.bind_gRootNode(mTransformRSData);
-        sceneManager.mRenderLoop.set_gRenderableObjects(null);
-        mRenderPassAlloc = null;
-        sceneManager.mRenderLoop.set_gRenderPasses(null);
-        sceneManager.mRenderLoop.bind_gFrontToBack(null);
-        sceneManager.mRenderLoop.bind_gBackToFront(null);
-        sceneManager.mRenderLoop.set_gCameras(null);
-
-        mTransformMap = null;
-        mRenderPasses = null;
-        mLights = null;
-        mCameras = null;
-        mRenderables = null;
-        mRenderableMap = null;
-        mTextures = null;
-        mRenderableMeshMap = null;
-        mRootTransforms = null;
-    }
-
-    public void initRenderPassRS(RenderScriptGL rs, SceneManager sceneManager) {
-        if (mRenderPasses.size() != 0) {
-            mRenderPassAlloc = new ScriptField_RenderPass_s(mRS, mRenderPasses.size());
-            for (int i = 0; i < mRenderPasses.size(); i ++) {
-                mRenderPassAlloc.set(mRenderPasses.get(i).getRsField(mRS, mRes), i, false);
-            }
-            mRenderPassAlloc.copyAll();
-            sceneManager.mRenderLoop.set_gRenderPasses(mRenderPassAlloc.getAllocation());
-        }
-    }
-
-    private void addDrawables(RenderScriptGL rs, Resources res, SceneManager sceneManager) {
-        Allocation drawableData = Allocation.createSized(rs,
-                                                         Element.ALLOCATION(rs),
-                                                         mRenderables.size());
-        Allocation[] drawableAllocs = new Allocation[mRenderables.size()];
-        for (int i = 0; i < mRenderables.size(); i ++) {
-            Renderable dI = (Renderable)mRenderables.get(i);
-            addToMeshMap(dI);
-            drawableAllocs[i] = dI.getRsField(rs, res).getAllocation();
-        }
-        drawableData.copyFrom(drawableAllocs);
-        sceneManager.mRenderLoop.set_gRenderableObjects(drawableData);
-
-        initRenderPassRS(rs, sceneManager);
-    }
-
-    private void addShaders(RenderScriptGL rs, Resources res, SceneManager sceneManager) {
-        if (mVertexShaders.size() > 0) {
-            Allocation shaderData = Allocation.createSized(rs, Element.ALLOCATION(rs),
-                                                           mVertexShaders.size());
-            Allocation[] shaderAllocs = new Allocation[mVertexShaders.size()];
-            for (int i = 0; i < mVertexShaders.size(); i ++) {
-                VertexShader sI = mVertexShaders.get(i);
-                shaderAllocs[i] = sI.getRSData().getAllocation();
-            }
-            shaderData.copyFrom(shaderAllocs);
-            sceneManager.mRenderLoop.set_gVertexShaders(shaderData);
-        }
-
-        if (mFragmentShaders.size() > 0) {
-            Allocation shaderData = Allocation.createSized(rs, Element.ALLOCATION(rs),
-                                                           mFragmentShaders.size());
-            Allocation[] shaderAllocs = new Allocation[mFragmentShaders.size()];
-            for (int i = 0; i < mFragmentShaders.size(); i ++) {
-                FragmentShader sI = mFragmentShaders.get(i);
-                shaderAllocs[i] = sI.getRSData().getAllocation();
-            }
-            shaderData.copyFrom(shaderAllocs);
-            sceneManager.mRenderLoop.set_gFragmentShaders(shaderData);
-        }
-    }
-
-    public void initRS() {
-        SceneManager sceneManager = SceneManager.getInstance();
-        mRS = SceneManager.getRS();
-        mRes = SceneManager.getRes();
-        long start = System.currentTimeMillis();
-        mTransformRSData = mRootTransforms.getRSData();
-        long end = System.currentTimeMillis();
-        Log.v(TIMER_TAG, "Transform init time: " + (end - start));
-
-        start = System.currentTimeMillis();
-
-        sceneManager.mRenderLoop.bind_gRootNode(mTransformRSData);
-        end = System.currentTimeMillis();
-        Log.v(TIMER_TAG, "Script init time: " + (end - start));
-
-        start = System.currentTimeMillis();
-        addDrawables(mRS, mRes, sceneManager);
-        end = System.currentTimeMillis();
-        Log.v(TIMER_TAG, "Renderable init time: " + (end - start));
-
-        addShaders(mRS, mRes, sceneManager);
-
-        Allocation opaqueBuffer = null;
-        if (mRenderables.size() > 0) {
-            opaqueBuffer = Allocation.createSized(mRS, Element.U32(mRS), mRenderables.size());
-        }
-        Allocation transparentBuffer = null;
-        if (mRenderables.size() > 0) {
-            transparentBuffer = Allocation.createSized(mRS, Element.U32(mRS), mRenderables.size());
-        }
-
-        sceneManager.mRenderLoop.bind_gFrontToBack(opaqueBuffer);
-        sceneManager.mRenderLoop.bind_gBackToFront(transparentBuffer);
-
-        if (mCameras.size() > 0) {
-            Allocation cameraData;
-            cameraData = Allocation.createSized(mRS, Element.ALLOCATION(mRS), mCameras.size());
-            Allocation[] cameraAllocs = new Allocation[mCameras.size()];
-            for (int i = 0; i < mCameras.size(); i ++) {
-                cameraAllocs[i] = mCameras.get(i).getRSData().getAllocation();
-            }
-            cameraData.copyFrom(cameraAllocs);
-            sceneManager.mRenderLoop.set_gCameras(cameraData);
-        }
-
-        if (mLights.size() > 0) {
-            Allocation lightData = Allocation.createSized(mRS,
-                                                          Element.ALLOCATION(mRS),
-                                                          mLights.size());
-            Allocation[] lightAllocs = new Allocation[mLights.size()];
-            for (int i = 0; i < mLights.size(); i ++) {
-                lightAllocs[i] = mLights.get(i).getRSData().getAllocation();
-            }
-            lightData.copyFrom(lightAllocs);
-            sceneManager.mRenderLoop.set_gLights(lightData);
-        }
-    }
-}
-
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneGraphBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneGraphBase.java
deleted file mode 100644
index 412ffbf..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneGraphBase.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-import java.util.ArrayList;
-
-import com.android.scenegraph.SceneManager;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.Matrix4f;
-import android.renderscript.ProgramFragment;
-import android.renderscript.ProgramStore;
-import android.renderscript.ProgramVertex;
-import android.renderscript.RSRuntimeException;
-import android.renderscript.RenderScript;
-import android.renderscript.RenderScriptGL;
-import android.util.Log;
-
-/**
- * @hide
- */
-public abstract class SceneGraphBase {
-    String mName;
-    Allocation mNameAlloc;
-    public void setName(String n) {
-        mName = n;
-        mNameAlloc = null;
-    }
-
-    public String getName() {
-        return mName;
-    }
-
-    Allocation getNameAlloc(RenderScriptGL rs) {
-        if (mNameAlloc == null)  {
-            mNameAlloc = SceneManager.getStringAsAllocation(rs, getName());
-        }
-        return mNameAlloc;
-    }
-}
-
-
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java
deleted file mode 100644
index 4ff2c8b..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java
+++ /dev/null
@@ -1,503 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Writer;
-import java.lang.Math;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import com.android.scenegraph.Camera;
-import com.android.scenegraph.FragmentShader;
-import com.android.scenegraph.MatrixTransform;
-import com.android.scenegraph.Scene;
-import com.android.scenegraph.VertexShader;
-import com.android.testapp.R;
-
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.AsyncTask;
-import android.renderscript.*;
-import android.renderscript.Allocation.MipmapControl;
-import android.renderscript.Mesh;
-import android.renderscript.RenderScriptGL;
-import android.util.Log;
-import android.view.SurfaceHolder;
-
-/**
- * @hide
- */
-public class SceneManager extends SceneGraphBase {
-
-    HashMap<String, Allocation> mAllocationMap;
-
-    ScriptC_render mRenderLoop;
-    ScriptC mCameraScript;
-    ScriptC mLightScript;
-    ScriptC mObjectParamsScript;
-    ScriptC mFragmentParamsScript;
-    ScriptC mVertexParamsScript;
-    ScriptC mCullScript;
-    ScriptC_transform mTransformScript;
-    ScriptC_export mExportScript;
-
-    RenderScriptGL mRS;
-    Resources mRes;
-    Mesh mQuad;
-    int mWidth;
-    int mHeight;
-
-    Scene mActiveScene;
-    private static SceneManager sSceneManager;
-
-    private Allocation mDefault2D;
-    private Allocation mDefaultCube;
-
-    private FragmentShader mColor;
-    private FragmentShader mTexture;
-    private VertexShader mDefaultVertex;
-
-    private RenderState mDefaultState;
-    private Transform mDefaultTransform;
-
-    private static Allocation getDefault(boolean isCube) {
-        final int dimension = 4;
-        final int bytesPerPixel = 4;
-        int arraySize = dimension * dimension * bytesPerPixel;
-
-        RenderScriptGL rs = sSceneManager.mRS;
-        Type.Builder b = new Type.Builder(rs, Element.RGBA_8888(rs));
-        b.setX(dimension).setY(dimension);
-        if (isCube) {
-            b.setFaces(true);
-            arraySize *= 6;
-        }
-        Type bitmapType = b.create();
-
-        Allocation.MipmapControl mip = Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE;
-        int usage =  Allocation.USAGE_GRAPHICS_TEXTURE;
-        Allocation defaultImage = Allocation.createTyped(rs, bitmapType, mip, usage);
-
-        byte imageData[] = new byte[arraySize];
-        defaultImage.copyFrom(imageData);
-        return defaultImage;
-    }
-
-    static Allocation getDefaultTex2D() {
-        if (sSceneManager == null) {
-            return null;
-        }
-        if (sSceneManager.mDefault2D == null) {
-            sSceneManager.mDefault2D = getDefault(false);
-        }
-        return sSceneManager.mDefault2D;
-    }
-
-    static Allocation getDefaultTexCube() {
-        if (sSceneManager == null) {
-            return null;
-        }
-        if (sSceneManager.mDefaultCube == null) {
-            sSceneManager.mDefaultCube = getDefault(true);
-        }
-        return sSceneManager.mDefaultCube;
-    }
-
-    public static boolean isSDCardPath(String path) {
-        int sdCardIndex = path.indexOf("sdcard/");
-        // We are looking for /sdcard/ or sdcard/
-        if (sdCardIndex == 0 || sdCardIndex == 1) {
-            return true;
-        }
-        sdCardIndex = path.indexOf("mnt/sdcard/");
-        if (sdCardIndex == 0 || sdCardIndex == 1) {
-            return true;
-        }
-        return false;
-    }
-
-    static Bitmap loadBitmap(String name, Resources res) {
-        InputStream is = null;
-        boolean loadFromSD = isSDCardPath(name);
-        try {
-            if (!loadFromSD) {
-                is = res.getAssets().open(name);
-            } else {
-                File f = new File(name);
-                is = new BufferedInputStream(new FileInputStream(f));
-            }
-        } catch (IOException e) {
-            Log.e("ImageLoaderTask", " Message: " + e.getMessage());
-            return null;
-        }
-
-        Bitmap b = BitmapFactory.decodeStream(is);
-        try {
-            is.close();
-        } catch (IOException e) {
-            Log.e("ImageLoaderTask", " Message: " + e.getMessage());
-        }
-        return b;
-    }
-
-    static Allocation createFromBitmap(Bitmap b, RenderScriptGL rs, boolean isCube) {
-        if (b == null) {
-            return null;
-        }
-        MipmapControl mip = MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE;
-        int usage = Allocation.USAGE_GRAPHICS_TEXTURE;
-        if (isCube) {
-            return Allocation.createCubemapFromBitmap(rs, b, mip, usage);
-        }
-        return Allocation.createFromBitmap(rs, b, mip, usage);
-    }
-
-    public static Allocation loadCubemap(String name, RenderScriptGL rs, Resources res) {
-        return createFromBitmap(loadBitmap(name, res), rs, true);
-    }
-
-    public static Allocation loadCubemap(int id, RenderScriptGL rs, Resources res) {
-        return createFromBitmap(BitmapFactory.decodeResource(res, id), rs, true);
-    }
-
-    public static Allocation loadTexture2D(String name, RenderScriptGL rs, Resources res) {
-        return createFromBitmap(loadBitmap(name, res), rs, false);
-    }
-
-    public static Allocation loadTexture2D(int id, RenderScriptGL rs, Resources res) {
-        return createFromBitmap(BitmapFactory.decodeResource(res, id), rs, false);
-    }
-
-    public static ProgramStore BLEND_ADD_DEPTH_NONE(RenderScript rs) {
-        ProgramStore.Builder builder = new ProgramStore.Builder(rs);
-        builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
-        builder.setBlendFunc(ProgramStore.BlendSrcFunc.ONE, ProgramStore.BlendDstFunc.ONE);
-        builder.setDitherEnabled(false);
-        builder.setDepthMaskEnabled(false);
-        return builder.create();
-    }
-
-    static Allocation getStringAsAllocation(RenderScript rs, String str) {
-        if (str == null) {
-            return null;
-        }
-        if (str.length() == 0) {
-            return null;
-        }
-        byte[] allocArray = null;
-        byte[] nullChar = new byte[1];
-        nullChar[0] = 0;
-        try {
-            allocArray = str.getBytes("UTF-8");
-            Allocation alloc = Allocation.createSized(rs, Element.U8(rs),
-                                                      allocArray.length + 1,
-                                                      Allocation.USAGE_SCRIPT);
-            alloc.copy1DRangeFrom(0, allocArray.length, allocArray);
-            alloc.copy1DRangeFrom(allocArray.length, 1, nullChar);
-            return alloc;
-        }
-        catch (Exception e) {
-            throw new RSRuntimeException("Could not convert string to utf-8.");
-        }
-    }
-
-    static Allocation getCachedAlloc(String str) {
-        if (sSceneManager == null) {
-            throw new RuntimeException("Scene manager not initialized");
-        }
-        return sSceneManager.mAllocationMap.get(str);
-    }
-
-    static void cacheAlloc(String str, Allocation alloc) {
-        if (sSceneManager == null) {
-            throw new RuntimeException("Scene manager not initialized");
-        }
-        sSceneManager.mAllocationMap.put(str, alloc);
-    }
-
-    public static class SceneLoadedCallback implements Runnable {
-        public Scene mLoadedScene;
-        public String mName;
-        public void run() {
-        }
-    }
-
-    public Scene getActiveScene() {
-        return mActiveScene;
-    }
-
-    public void setActiveScene(Scene s) {
-        mActiveScene = s;
-
-        if (mActiveScene == null) {
-            return;
-        }
-
-        // Do some sanity checking
-        if (mActiveScene.getCameras().size() == 0) {
-            Matrix4f camPos = new Matrix4f();
-            camPos.translate(0, 0, 10);
-            MatrixTransform cameraTransform = new MatrixTransform();
-            cameraTransform.setName("_DefaultCameraTransform");
-            cameraTransform.setMatrix(camPos);
-            mActiveScene.appendTransform(cameraTransform);
-            Camera cam = new Camera();
-            cam.setName("_DefaultCamera");
-            cam.setTransform(cameraTransform);
-            mActiveScene.appendCamera(cam);
-        }
-
-        mActiveScene.appendShader(getDefaultVS());
-        mActiveScene.appendTransform(getDefaultTransform());
-    }
-
-    static RenderScriptGL getRS() {
-        if (sSceneManager == null) {
-            return null;
-        }
-        return sSceneManager.mRS;
-    }
-
-    static Resources getRes() {
-        if (sSceneManager == null) {
-            return null;
-        }
-        return sSceneManager.mRes;
-    }
-
-    // Provides the folowing inputs to fragment shader
-    // Assigned by default if nothing is present
-    // vec3 varWorldPos;
-    // vec3 varWorldNormal;
-    // vec2 varTex0;
-    public static VertexShader getDefaultVS() {
-        if (sSceneManager == null) {
-            return null;
-        }
-
-        if (sSceneManager.mDefaultVertex == null) {
-            RenderScriptGL rs = getRS();
-            Element.Builder b = new Element.Builder(rs);
-            b.add(Element.MATRIX_4X4(rs), "model");
-            Type.Builder objConstBuilder = new Type.Builder(rs, b.create());
-
-            b = new Element.Builder(rs);
-            b.add(Element.MATRIX_4X4(rs), "viewProj");
-            Type.Builder shaderConstBuilder = new Type.Builder(rs, b.create());
-
-            b = new Element.Builder(rs);
-            b.add(Element.F32_4(rs), "position");
-            b.add(Element.F32_2(rs), "texture0");
-            b.add(Element.F32_3(rs), "normal");
-            Element defaultIn = b.create();
-
-            final String code = "\n" +
-                "varying vec3 varWorldPos;\n" +
-                "varying vec3 varWorldNormal;\n" +
-                "varying vec2 varTex0;\n" +
-                "void main() {" +
-                "   vec4 objPos = ATTRIB_position;\n" +
-                "   vec4 worldPos = UNI_model * objPos;\n" +
-                "   gl_Position = UNI_viewProj * worldPos;\n" +
-                "   mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);\n" +
-                "   vec3 worldNorm = model3 * ATTRIB_normal;\n" +
-                "   varWorldPos = worldPos.xyz;\n" +
-                "   varWorldNormal = worldNorm;\n" +
-                "   varTex0 = ATTRIB_texture0;\n" +
-                "}\n";
-
-            VertexShader.Builder sb = new VertexShader.Builder(rs);
-            sb.addInput(defaultIn);
-            sb.setObjectConst(objConstBuilder.setX(1).create());
-            sb.setShaderConst(shaderConstBuilder.setX(1).create());
-            sb.setShader(code);
-            sSceneManager.mDefaultVertex = sb.create();
-        }
-
-        return sSceneManager.mDefaultVertex;
-    }
-
-    public static FragmentShader getColorFS() {
-        if (sSceneManager == null) {
-            return null;
-        }
-        if (sSceneManager.mColor == null) {
-            RenderScriptGL rs = getRS();
-            Element.Builder b = new Element.Builder(rs);
-            b.add(Element.F32_4(rs), "color");
-            Type.Builder objConstBuilder = new Type.Builder(rs, b.create());
-
-            final String code = "\n" +
-                "varying vec2 varTex0;\n" +
-                "void main() {\n" +
-                "   lowp vec4 col = UNI_color;\n" +
-                "   gl_FragColor = col;\n" +
-                "}\n";
-            FragmentShader.Builder fb = new FragmentShader.Builder(rs);
-            fb.setShader(code);
-            fb.setObjectConst(objConstBuilder.create());
-            sSceneManager.mColor = fb.create();
-        }
-
-        return sSceneManager.mColor;
-    }
-
-    public static FragmentShader getTextureFS() {
-        if (sSceneManager == null) {
-            return null;
-        }
-        if (sSceneManager.mTexture == null) {
-            RenderScriptGL rs = getRS();
-
-            final String code = "\n" +
-                "varying vec2 varTex0;\n" +
-                "void main() {\n" +
-                "   lowp vec4 col = texture2D(UNI_color, varTex0).rgba;\n" +
-                "   gl_FragColor = col;\n" +
-                "}\n";
-
-            FragmentShader.Builder fb = new FragmentShader.Builder(rs);
-            fb.setShader(code);
-            fb.addTexture(Program.TextureType.TEXTURE_2D, "color");
-            sSceneManager.mTexture = fb.create();
-            sSceneManager.mTexture.mProgram.bindSampler(Sampler.CLAMP_LINEAR_MIP_LINEAR(rs), 0);
-        }
-
-        return sSceneManager.mTexture;
-    }
-
-    static RenderState getDefaultState() {
-        if (sSceneManager == null) {
-            return null;
-        }
-        if (sSceneManager.mDefaultState == null) {
-            sSceneManager.mDefaultState = new RenderState(getDefaultVS(), getColorFS(), null, null);
-            sSceneManager.mDefaultState.setName("__DefaultState");
-        }
-        return sSceneManager.mDefaultState;
-    }
-
-    static Transform getDefaultTransform() {
-        if (sSceneManager == null) {
-            return null;
-        }
-        if (sSceneManager.mDefaultTransform == null) {
-            sSceneManager.mDefaultTransform = new MatrixTransform();
-            sSceneManager.mDefaultTransform.setName("__DefaultTransform");
-        }
-        return sSceneManager.mDefaultTransform;
-    }
-
-    public static SceneManager getInstance() {
-        if (sSceneManager == null) {
-            sSceneManager = new SceneManager();
-        }
-        return sSceneManager;
-    }
-
-    protected SceneManager() {
-    }
-
-    public void loadModel(String name, SceneLoadedCallback cb) {
-        ColladaScene scene = new ColladaScene(name, cb);
-        scene.init(mRS, mRes);
-    }
-
-    public Mesh getScreenAlignedQuad() {
-        if (mQuad != null) {
-            return mQuad;
-        }
-
-        Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS,
-                                           3, Mesh.TriangleMeshBuilder.TEXTURE_0);
-
-        tmb.setTexture(0.0f, 1.0f).addVertex(-1.0f, 1.0f, 1.0f);
-        tmb.setTexture(0.0f, 0.0f).addVertex(-1.0f, -1.0f, 1.0f);
-        tmb.setTexture(1.0f, 0.0f).addVertex(1.0f, -1.0f, 1.0f);
-        tmb.setTexture(1.0f, 1.0f).addVertex(1.0f, 1.0f, 1.0f);
-
-        tmb.addTriangle(0, 1, 2);
-        tmb.addTriangle(2, 3, 0);
-
-        mQuad = tmb.create(true);
-        return mQuad;
-    }
-
-    public Renderable getRenderableQuad(String name, RenderState state) {
-        Renderable quad = new Renderable();
-        quad.setTransform(new MatrixTransform());
-        quad.setMesh(getScreenAlignedQuad());
-        quad.setName(name);
-        quad.setRenderState(state);
-        quad.setCullType(1);
-        return quad;
-    }
-
-    public void initRS(RenderScriptGL rs, Resources res, int w, int h) {
-        mRS = rs;
-        mRes = res;
-        mAllocationMap = new HashMap<String, Allocation>();
-
-        mQuad = null;
-        mDefault2D = null;
-        mDefaultCube = null;
-        mDefaultVertex = null;
-        mColor = null;
-        mTexture = null;
-        mDefaultState = null;
-        mDefaultTransform = null;
-
-        mExportScript = new ScriptC_export(rs, res, R.raw.export);
-
-        mTransformScript = new ScriptC_transform(rs, res, R.raw.transform);
-        mTransformScript.set_gTransformScript(mTransformScript);
-
-        mCameraScript = new ScriptC_camera(rs, res, R.raw.camera);
-        mLightScript = new ScriptC_light(rs, res, R.raw.light);
-        mObjectParamsScript = new ScriptC_object_params(rs, res, R.raw.object_params);
-        mFragmentParamsScript = new ScriptC_object_params(rs, res, R.raw.fragment_params);
-        mVertexParamsScript = new ScriptC_object_params(rs, res, R.raw.vertex_params);
-        mCullScript = new ScriptC_cull(rs, res, R.raw.cull);
-
-        mRenderLoop = new ScriptC_render(rs, res, R.raw.render);
-        mRenderLoop.set_gTransformScript(mTransformScript);
-        mRenderLoop.set_gCameraScript(mCameraScript);
-        mRenderLoop.set_gLightScript(mLightScript);
-        mRenderLoop.set_gObjectParamsScript(mObjectParamsScript);
-        mRenderLoop.set_gFragmentParamsScript(mFragmentParamsScript);
-        mRenderLoop.set_gVertexParamsScript(mVertexParamsScript);
-        mRenderLoop.set_gCullScript(mCullScript);
-
-        mRenderLoop.set_gPFSBackground(ProgramStore.BLEND_NONE_DEPTH_TEST(mRS));
-    }
-
-    public ScriptC getRenderLoop() {
-        return mRenderLoop;
-    }
-}
-
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Shader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Shader.java
deleted file mode 100644
index 4975114..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Shader.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-import java.util.ArrayList;
-import java.util.HashMap;
-
-import com.android.scenegraph.SceneGraphBase;
-import com.android.scenegraph.ShaderParam;
-
-import android.renderscript.*;
-import android.renderscript.ProgramFragment.Builder;
-import android.util.Log;
-
-/**
- * @hide
- */
-public abstract class Shader extends SceneGraphBase {
-    protected Type mPerObjConstants;
-    protected Type mPerShaderConstants;
-
-    protected HashMap<String, ShaderParam> mSourceParams;
-    protected ArrayList<String> mShaderTextureNames;
-    protected ArrayList<Program.TextureType > mShaderTextureTypes;
-    protected ArrayList<String> mTextureNames;
-    protected ArrayList<Program.TextureType > mTextureTypes;
-
-    protected Allocation mConstantBuffer;
-    protected ScriptField_ShaderParam_s mConstantBufferParams;
-
-    public Shader() {
-        mSourceParams = new HashMap<String, ShaderParam>();
-        mShaderTextureNames = new ArrayList<String>();
-        mShaderTextureTypes = new ArrayList<Program.TextureType>();
-        mTextureNames = new ArrayList<String>();
-        mTextureTypes = new ArrayList<Program.TextureType>();
-    }
-
-    public void appendSourceParams(ShaderParam p) {
-        mSourceParams.put(p.getParamName(), p);
-    }
-
-    public Type getObjectConstants() {
-        return mPerObjConstants;
-    }
-
-    public Type getShaderConstants() {
-        return mPerObjConstants;
-    }
-
-    void linkConstants(RenderScriptGL rs) {
-        if (mPerShaderConstants == null) {
-            return;
-        }
-
-        Element constElem = mPerShaderConstants.getElement();
-        mConstantBufferParams  = ShaderParam.fillInParams(constElem, mSourceParams, null);
-
-        mConstantBuffer = Allocation.createTyped(rs, mPerShaderConstants);
-    }
-}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java
deleted file mode 100644
index 3dd41ca..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-import java.util.ArrayList;
-import java.util.HashMap;
-
-import com.android.scenegraph.SceneManager;
-import com.android.scenegraph.Transform;
-
-import android.renderscript.Element;
-import android.renderscript.Matrix4f;
-import android.renderscript.ProgramFragment;
-import android.renderscript.ProgramStore;
-import android.renderscript.ProgramVertex;
-import android.renderscript.RenderScriptGL;
-import android.util.Log;
-
-/**
- * @hide
- */
-public abstract class ShaderParam extends SceneGraphBase {
-
-    static final String cameraPos        = "cameraPos";
-    static final String cameraDir        = "cameraDir";
-
-    static final String lightColor       = "lightColor";
-    static final String lightPos         = "lightPos";
-    static final String lightDir         = "lightDir";
-
-    static final String view             = "view";
-    static final String proj             = "proj";
-    static final String viewProj         = "viewProj";
-    static final String model            = "model";
-    static final String modelView        = "modelView";
-    static final String modelViewProj    = "modelViewProj";
-
-    static final long sMaxTimeStamp = 0xffffffffL;
-
-    ScriptField_ShaderParamData_s.Item mData;
-    ScriptField_ShaderParamData_s mField;
-
-    String mParamName;
-    Camera mCamera;
-
-    static ScriptField_ShaderParam_s fillInParams(Element constantElem,
-                                                  HashMap<String, ShaderParam> sourceParams,
-                                                  Transform transform) {
-        RenderScriptGL rs = SceneManager.getRS();
-        ArrayList<ScriptField_ShaderParam_s.Item> paramList;
-        paramList = new ArrayList<ScriptField_ShaderParam_s.Item>();
-
-        int subElemCount = constantElem.getSubElementCount();
-        for (int i = 0; i < subElemCount; i ++) {
-            String inputName = constantElem.getSubElementName(i);
-            int offset = constantElem.getSubElementOffsetBytes(i);
-
-            ShaderParam matchingParam = sourceParams.get(inputName);
-            Element subElem = constantElem.getSubElement(i);
-            // Make one if it's not there
-            if (matchingParam == null) {
-                if (subElem.getDataType() == Element.DataType.FLOAT_32) {
-                    matchingParam = new Float4Param(inputName, 0.5f, 0.5f, 0.5f, 0.5f);
-                } else if (subElem.getDataType() == Element.DataType.MATRIX_4X4) {
-                    TransformParam trParam = new TransformParam(inputName);
-                    trParam.setTransform(transform);
-                    matchingParam = trParam;
-                }
-            }
-            ScriptField_ShaderParam_s.Item paramRS = new ScriptField_ShaderParam_s.Item();
-            paramRS.bufferOffset = offset;
-            paramRS.transformTimestamp = 0;
-            paramRS.dataTimestamp = 0;
-            paramRS.data = matchingParam.getRSData().getAllocation();
-            if (subElem.getDataType() == Element.DataType.FLOAT_32) {
-                paramRS.float_vecSize = subElem.getVectorSize();
-            }
-
-            paramList.add(paramRS);
-        }
-
-        ScriptField_ShaderParam_s rsParams = null;
-        int paramCount = paramList.size();
-        if (paramCount != 0) {
-            rsParams = new ScriptField_ShaderParam_s(rs, paramCount);
-            for (int i = 0; i < paramCount; i++) {
-                rsParams.set(paramList.get(i), i, false);
-            }
-            rsParams.copyAll();
-        }
-        return rsParams;
-    }
-
-    public ShaderParam(String name) {
-        mParamName = name;
-        mData = new ScriptField_ShaderParamData_s.Item();
-    }
-
-    public String getParamName() {
-        return mParamName;
-    }
-
-    public void setCamera(Camera c) {
-        mCamera = c;
-        if (mField != null) {
-            mData.camera = mCamera.getRSData().getAllocation();
-            mField.set_camera(0, mData.camera, true);
-        }
-    }
-
-    protected void incTimestamp() {
-        if (mField != null) {
-            mData.timestamp ++;
-            mData.timestamp %= sMaxTimeStamp;
-            mField.set_timestamp(0, mData.timestamp, true);
-        }
-    }
-
-    abstract void initLocalData();
-
-    public ScriptField_ShaderParamData_s getRSData() {
-        if (mField != null) {
-            return mField;
-        }
-
-        RenderScriptGL rs = SceneManager.getRS();
-        mField = new ScriptField_ShaderParamData_s(rs, 1);
-
-        if (mParamName != null) {
-            mData.paramName = SceneManager.getCachedAlloc(mParamName);
-            if (mData.paramName == null) {
-                mData.paramName = SceneManager.getStringAsAllocation(rs, mParamName);
-                SceneManager.cacheAlloc(mParamName, mData.paramName);
-            }
-        }
-        initLocalData();
-        mData.timestamp = 1;
-
-        mField.set(mData, 0, true);
-        return mField;
-    }
-}
-
-
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Texture2D.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Texture2D.java
deleted file mode 100644
index b53ab88..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Texture2D.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-
-import com.android.scenegraph.SceneManager;
-
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.util.Log;
-
-/**
- * @hide
- */
-public class Texture2D extends TextureBase {
-    String mFileName;
-    String mFileDir;
-    int mResourceID;
-
-    public Texture2D() {
-        super(ScriptC_export.const_TextureType_TEXTURE_2D);
-    }
-
-    public Texture2D(Allocation tex) {
-        super(ScriptC_export.const_TextureType_TEXTURE_2D);
-        setTexture(tex);
-    }
-
-    public Texture2D(String dir, String file) {
-        super(ScriptC_export.const_TextureType_TEXTURE_CUBE);
-        setFileDir(dir);
-        setFileName(file);
-    }
-
-    public Texture2D(int resourceID) {
-        super(ScriptC_export.const_TextureType_TEXTURE_2D);
-        mResourceID = resourceID;
-    }
-
-    public void setFileDir(String dir) {
-        mFileDir = dir;
-    }
-
-    public void setFileName(String file) {
-        mFileName = file;
-    }
-
-    public String getFileName() {
-        return mFileName;
-    }
-
-    public void setTexture(Allocation tex) {
-        mData.texture = tex != null ? tex : SceneManager.getDefaultTex2D();
-        if (mField != null) {
-            mField.set_texture(0, mData.texture, true);
-        }
-    }
-
-    void load() {
-        RenderScriptGL rs = SceneManager.getRS();
-        Resources res = SceneManager.getRes();
-        if (mFileName != null && mFileName.length() > 0) {
-            String shortName = mFileName.substring(mFileName.lastIndexOf('/') + 1);
-            setTexture(SceneManager.loadTexture2D(mFileDir + shortName, rs, res));
-        } else if (mResourceID != 0) {
-            setTexture(SceneManager.loadTexture2D(mResourceID, rs, res));
-        }
-    }
-
-    ScriptField_Texture_s getRsData(boolean loadNow) {
-        if (mField != null) {
-            return mField;
-        }
-
-        RenderScriptGL rs = SceneManager.getRS();
-        Resources res = SceneManager.getRes();
-        if (rs == null || res == null) {
-            return null;
-        }
-
-        mField = new ScriptField_Texture_s(rs, 1);
-
-        if (loadNow) {
-            load();
-        } else {
-            mData.texture = SceneManager.getDefaultTex2D();
-            new SingleImageLoaderTask().execute(this);
-        }
-
-        mField.set(mData, 0, true);
-        return mField;
-    }
-}
-
-
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureBase.java
deleted file mode 100644
index ba49d4e..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureBase.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-
-import com.android.scenegraph.SceneManager;
-import android.os.AsyncTask;
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.util.Log;
-
-/**
- * @hide
- */
-public abstract class TextureBase extends SceneGraphBase {
-
-    class SingleImageLoaderTask extends AsyncTask<TextureBase, Void, Boolean> {
-        protected Boolean doInBackground(TextureBase... objects) {
-            TextureBase tex = objects[0];
-            tex.load();
-            return new Boolean(true);
-        }
-        protected void onPostExecute(Boolean result) {
-        }
-    }
-
-    ScriptField_Texture_s.Item mData;
-    ScriptField_Texture_s mField;
-    TextureBase(int type) {
-        mData = new ScriptField_Texture_s.Item();
-        mData.type = type;
-    }
-
-    protected Allocation mRsTexture;
-    abstract ScriptField_Texture_s getRsData(boolean loadNow);
-    abstract void load();
-}
-
-
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureCube.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureCube.java
deleted file mode 100644
index 1269e3c..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureCube.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-
-import com.android.scenegraph.SceneManager;
-import com.android.scenegraph.TextureBase;
-
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.util.Log;
-
-/**
- * @hide
- */
-public class TextureCube extends TextureBase {
-    String mFileName;
-    String mFileDir;
-    int mResourceID;
-
-    public TextureCube() {
-        super(ScriptC_export.const_TextureType_TEXTURE_CUBE);
-    }
-
-    public TextureCube(Allocation tex) {
-        super(ScriptC_export.const_TextureType_TEXTURE_CUBE);
-        setTexture(tex);
-    }
-
-    public TextureCube(String dir, String file) {
-        super(ScriptC_export.const_TextureType_TEXTURE_CUBE);
-        setFileDir(dir);
-        setFileName(file);
-    }
-
-    public TextureCube(int resourceID) {
-        super(ScriptC_export.const_TextureType_TEXTURE_2D);
-        mResourceID = resourceID;
-    }
-
-    public void setFileDir(String dir) {
-        mFileDir = dir;
-    }
-
-    public void setFileName(String file) {
-        mFileName = file;
-    }
-
-    public String getFileName() {
-        return mFileName;
-    }
-
-    public void setTexture(Allocation tex) {
-        mData.texture = tex != null ? tex : SceneManager.getDefaultTexCube();
-        if (mField != null) {
-            mField.set_texture(0, mData.texture, true);
-        }
-    }
-
-    void load() {
-        RenderScriptGL rs = SceneManager.getRS();
-        Resources res = SceneManager.getRes();
-        if (mFileName != null && mFileName.length() > 0) {
-            String shortName = mFileName.substring(mFileName.lastIndexOf('/') + 1);
-            setTexture(SceneManager.loadCubemap(mFileDir + shortName, rs, res));
-        } else if (mResourceID != 0) {
-            setTexture(SceneManager.loadCubemap(mResourceID , rs, res));
-        }
-    }
-
-    ScriptField_Texture_s getRsData(boolean loadNow) {
-        if (mField != null) {
-            return mField;
-        }
-
-        RenderScriptGL rs = SceneManager.getRS();
-        Resources res = SceneManager.getRes();
-        if (rs == null || res == null) {
-            return null;
-        }
-
-        mField = new ScriptField_Texture_s(rs, 1);
-
-        if (loadNow) {
-            load();
-        } else {
-            mData.texture = SceneManager.getDefaultTexCube();
-            new SingleImageLoaderTask().execute(this);
-        }
-
-        mField.set(mData, 0, true);
-        return mField;
-    }
-}
-
-
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java
deleted file mode 100644
index e656ed2..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-import java.util.ArrayList;
-
-import android.graphics.Camera;
-import android.renderscript.RenderScriptGL;
-import android.renderscript.Float4;
-import android.renderscript.Matrix4f;
-import android.renderscript.ProgramFragment;
-import android.renderscript.ProgramStore;
-import android.renderscript.ProgramVertex;
-import android.renderscript.Element;
-import android.util.Log;
-
-/**
- * @hide
- */
-public class TextureParam extends ShaderParam {
-
-    TextureBase mTexture;
-
-    public TextureParam(String name) {
-        super(name);
-    }
-
-    public TextureParam(String name, TextureBase t) {
-        super(name);
-        setTexture(t);
-    }
-
-    public void setTexture(TextureBase t) {
-        mTexture = t;
-    }
-
-    public TextureBase getTexture() {
-        return mTexture;
-    }
-
-    void initLocalData() {
-        mData.type = ScriptC_export.const_ShaderParam_TEXTURE;
-        if (mTexture != null) {
-            mData.texture = mTexture.getRsData(false).getAllocation();
-        }
-    }
-}
-
-
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureRenderTarget.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureRenderTarget.java
deleted file mode 100644
index 6aa29a5..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureRenderTarget.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-
-import com.android.scenegraph.SceneManager;
-
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.util.Log;
-
-/**
- * @hide
- */
-public class TextureRenderTarget extends TextureBase {
-    public TextureRenderTarget() {
-        super(ScriptC_export.const_TextureType_TEXTURE_RENDER_TARGET);
-    }
-
-    public TextureRenderTarget(Allocation tex) {
-        super(ScriptC_export.const_TextureType_TEXTURE_RENDER_TARGET);
-        setTexture(tex);
-    }
-
-    public void setTexture(Allocation tex) {
-        mData.texture = tex;
-        if (mField != null) {
-            mField.set_texture(0, mData.texture, true);
-        }
-    }
-
-    void load() {
-    }
-
-    ScriptField_Texture_s getRsData(boolean loadNow) {
-        if (mField != null) {
-            return mField;
-        }
-
-        RenderScriptGL rs = SceneManager.getRS();
-        if (rs == null) {
-            return null;
-        }
-
-        mField = new ScriptField_Texture_s(rs, 1);
-        mField.set(mData, 0, true);
-        return mField;
-    }
-}
-
-
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java
deleted file mode 100644
index 8180bd0..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-import java.util.ArrayList;
-
-import android.renderscript.*;
-import android.renderscript.Matrix4f;
-import android.util.Log;
-
-/**
- * @hide
- */
-public abstract class Transform extends SceneGraphBase {
-    Transform mParent;
-    ArrayList<Transform> mChildren;
-
-    ScriptField_SgTransform mField;
-    ScriptField_SgTransform.Item mTransformData;
-
-    public Transform() {
-        mChildren = new ArrayList<Transform>();
-        mParent = null;
-    }
-
-    public void appendChild(Transform t) {
-        mChildren.add(t);
-        t.mParent = this;
-        updateRSChildData(true);
-    }
-
-    abstract void initLocalData();
-
-    void updateRSChildData(boolean copyData) {
-        if (mField == null) {
-            return;
-        }
-        RenderScriptGL rs = SceneManager.getRS();
-        if (mChildren.size() != 0) {
-            Allocation childRSData = Allocation.createSized(rs, Element.ALLOCATION(rs),
-                                                            mChildren.size());
-            mTransformData.children = childRSData;
-
-            Allocation[] childrenAllocs = new Allocation[mChildren.size()];
-            for (int i = 0; i < mChildren.size(); i ++) {
-                Transform child = mChildren.get(i);
-                childrenAllocs[i] = child.getRSData().getAllocation();
-            }
-            childRSData.copyFrom(childrenAllocs);
-        }
-        if (copyData) {
-            mField.set(mTransformData, 0, true);
-        }
-    }
-
-    ScriptField_SgTransform getRSData() {
-        if (mField != null) {
-            return mField;
-        }
-
-        RenderScriptGL rs = SceneManager.getRS();
-        if (rs == null) {
-            return null;
-        }
-        mField = new ScriptField_SgTransform(rs, 1);
-
-        mTransformData = new ScriptField_SgTransform.Item();
-        mTransformData.name = getNameAlloc(rs);
-        mTransformData.isDirty = 1;
-        mTransformData.timestamp = 1;
-
-        initLocalData();
-        updateRSChildData(false);
-
-        mField.set(mTransformData, 0, true);
-        return mField;
-    }
-}
-
-
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java
deleted file mode 100644
index d120d5d..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-import java.util.ArrayList;
-
-import android.renderscript.RenderScriptGL;
-import android.renderscript.Matrix4f;
-import android.renderscript.ProgramFragment;
-import android.renderscript.ProgramStore;
-import android.renderscript.ProgramVertex;
-import android.renderscript.Element;
-import android.util.Log;
-
-/**
- * @hide
- */
-public class TransformParam extends ShaderParam {
-
-    Transform mTransform;
-    LightBase mLight;
-
-    public TransformParam(String name) {
-        super(name);
-    }
-
-    public void setTransform(Transform t) {
-        mTransform = t;
-        if (mField != null && mTransform != null) {
-            mData.transform = mTransform.getRSData().getAllocation();
-        }
-        incTimestamp();
-    }
-
-    int getTypeFromName() {
-        int paramType = ScriptC_export.const_ShaderParam_TRANSFORM_DATA;
-        if (mParamName.equalsIgnoreCase(view)) {
-            paramType = ScriptC_export.const_ShaderParam_TRANSFORM_VIEW;
-        } else if(mParamName.equalsIgnoreCase(proj)) {
-            paramType = ScriptC_export.const_ShaderParam_TRANSFORM_PROJ;
-        } else if(mParamName.equalsIgnoreCase(viewProj)) {
-            paramType = ScriptC_export.const_ShaderParam_TRANSFORM_VIEW_PROJ;
-        } else if(mParamName.equalsIgnoreCase(model)) {
-            paramType = ScriptC_export.const_ShaderParam_TRANSFORM_MODEL;
-        } else if(mParamName.equalsIgnoreCase(modelView)) {
-            paramType = ScriptC_export.const_ShaderParam_TRANSFORM_MODEL_VIEW;
-        } else if(mParamName.equalsIgnoreCase(modelViewProj)) {
-            paramType = ScriptC_export.const_ShaderParam_TRANSFORM_MODEL_VIEW_PROJ;
-        }
-        return paramType;
-    }
-
-    void initLocalData() {
-        mData.type = getTypeFromName();
-        if (mTransform != null) {
-            mData.transform = mTransform.getRSData().getAllocation();
-        }
-        if (mCamera != null) {
-            mData.camera = mCamera.getRSData().getAllocation();
-        }
-        if (mLight != null) {
-            mData.light = mLight.getRSData().getAllocation();
-        }
-    }
-}
-
-
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java
deleted file mode 100644
index 4efaff7..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.scenegraph;
-
-import java.lang.Math;
-import java.util.ArrayList;
-
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.util.Log;
-
-/**
- * @hide
- */
-public class VertexShader extends Shader {
-    ProgramVertex mProgram;
-    ScriptField_VertexShader_s mField;
-
-    public static class Builder {
-        VertexShader mShader;
-        ProgramVertex.Builder mBuilder;
-
-        public Builder(RenderScriptGL rs) {
-            mShader = new VertexShader();
-            mBuilder = new ProgramVertex.Builder(rs);
-        }
-
-        public Builder setShader(Resources resources, int resourceID) {
-            mBuilder.setShader(resources, resourceID);
-            return this;
-        }
-
-        public Builder setShader(String code) {
-            mBuilder.setShader(code);
-            return this;
-        }
-
-        public Builder setObjectConst(Type type) {
-            mShader.mPerObjConstants = type;
-            return this;
-        }
-
-        public Builder setShaderConst(Type type) {
-            mShader.mPerShaderConstants = type;
-            return this;
-        }
-
-        public Builder addInput(Element e) {
-            mBuilder.addInput(e);
-            return this;
-        }
-
-        public VertexShader create() {
-            if (mShader.mPerShaderConstants != null) {
-                mBuilder.addConstant(mShader.mPerShaderConstants);
-            }
-            if (mShader.mPerObjConstants != null) {
-                mBuilder.addConstant(mShader.mPerObjConstants);
-            }
-            mShader.mProgram = mBuilder.create();
-            return mShader;
-        }
-    }
-
-    public ProgramVertex getProgram() {
-        return mProgram;
-    }
-
-    ScriptField_VertexShader_s getRSData() {
-        if (mField != null) {
-            return mField;
-        }
-
-        RenderScriptGL rs = SceneManager.getRS();
-        Resources res = SceneManager.getRes();
-        if (rs == null || res == null) {
-            return null;
-        }
-
-        ScriptField_VertexShader_s.Item item = new ScriptField_VertexShader_s.Item();
-        item.program = mProgram;
-
-        linkConstants(rs);
-        if (mPerShaderConstants != null) {
-            item.shaderConst = mConstantBuffer;
-            item.shaderConstParams = mConstantBufferParams.getAllocation();
-            mProgram.bindConstants(item.shaderConst, 0);
-        }
-
-        item.objectConstIndex = -1;
-        if (mPerObjConstants != null) {
-            item.objectConstIndex = mPerShaderConstants != null ? 1 : 0;
-        }
-
-        mField = new ScriptField_VertexShader_s(rs, 1);
-        mField.set(item, 0, true);
-        return mField;
-    }
-}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs
deleted file mode 100644
index dc0a885..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs
+++ /dev/null
@@ -1,66 +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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.scenegraph)
-
-//#define DEBUG_CAMERA
-#include "scenegraph_objects.rsh"
-
-void root(const rs_allocation *v_in, rs_allocation *v_out, const float *usrData) {
-
-    SgCamera *cam = (SgCamera *)rsGetElementAt(*v_in, 0);
-    float aspect = *usrData;
-    if (cam->aspect != aspect) {
-        cam->isDirty = 1;
-        cam->aspect = aspect;
-    }
-    if (cam->isDirty) {
-        rsMatrixLoadPerspective(&cam->proj, cam->horizontalFOV, cam->aspect, cam->near, cam->far);
-    }
-
-    const SgTransform *camTransform = (const SgTransform *)rsGetElementAt(cam->transformMatrix, 0);
-    //rsDebug("Camera stamp", cam->transformTimestamp);
-    //rsDebug("Transform stamp", camTransform->timestamp);
-    if (camTransform->timestamp != cam->transformTimestamp || cam->isDirty) {
-        cam->isDirty = 1;
-        rs_matrix4x4 camPosMatrix;
-        rsMatrixLoad(&camPosMatrix, &camTransform->globalMat);
-        float4 zero = {0.0f, 0.0f, 0.0f, 1.0f};
-        cam->position = rsMatrixMultiply(&camPosMatrix, zero);
-
-        rsMatrixInverse(&camPosMatrix);
-        rsMatrixLoad(&cam->view, &camPosMatrix);
-
-        rsMatrixLoad(&cam->viewProj, &cam->proj);
-        rsMatrixMultiply(&cam->viewProj, &cam->view);
-
-        rsExtractFrustumPlanes(&cam->viewProj,
-                               &cam->frustumPlanes[0], &cam->frustumPlanes[1],
-                               &cam->frustumPlanes[2], &cam->frustumPlanes[3],
-                               &cam->frustumPlanes[3], &cam->frustumPlanes[4]);
-    }
-
-    if (cam->isDirty) {
-        cam->timestamp ++;
-    }
-
-    cam->isDirty = 0;
-    cam->transformTimestamp = camTransform->timestamp;
-
-#ifdef DEBUG_CAMERA
-    printCameraInfo(cam);
-#endif //DEBUG_CAMERA
-}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/cull.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/cull.rs
deleted file mode 100644
index 024e026..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/cull.rs
+++ /dev/null
@@ -1,86 +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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.scenegraph)
-
-#include "scenegraph_objects.rsh"
-
-static void getTransformedSphere(SgRenderable *obj) {
-    obj->worldBoundingSphere = obj->boundingSphere;
-    obj->worldBoundingSphere.w = 1.0f;
-    const SgTransform *objTransform = (const SgTransform *)rsGetElementAt(obj->transformMatrix, 0);
-    obj->worldBoundingSphere = rsMatrixMultiply(&objTransform->globalMat, obj->worldBoundingSphere);
-
-    const float4 unitVec = {0.57735f, 0.57735f, 0.57735f, 0.0f};
-    float4 scaledVec = rsMatrixMultiply(&objTransform->globalMat, unitVec);
-    scaledVec.w = 0.0f;
-    obj->worldBoundingSphere.w = obj->boundingSphere.w * length(scaledVec);
-}
-
-static bool frustumCulled(SgRenderable *obj, SgCamera *cam) {
-    if (!obj->bVolInitialized) {
-        float minX, minY, minZ, maxX, maxY, maxZ;
-        rsgMeshComputeBoundingBox(obj->mesh,
-                                  &minX, &minY, &minZ,
-                                  &maxX, &maxY, &maxZ);
-        //rsDebug("min", minX, minY, minZ);
-        //rsDebug("max", maxX, maxY, maxZ);
-        float4 sphere;
-        sphere.x = (maxX + minX) * 0.5f;
-        sphere.y = (maxY + minY) * 0.5f;
-        sphere.z = (maxZ + minZ) * 0.5f;
-        float3 radius;
-        radius.x = (maxX - sphere.x);
-        radius.y = (maxY - sphere.y);
-        radius.z = (maxZ - sphere.z);
-
-        sphere.w = length(radius);
-        obj->boundingSphere = sphere;
-        obj->bVolInitialized = 1;
-        //rsDebug("Sphere", sphere);
-    }
-
-    getTransformedSphere(obj);
-
-    return !rsIsSphereInFrustum(&obj->worldBoundingSphere,
-                                &cam->frustumPlanes[0], &cam->frustumPlanes[1],
-                                &cam->frustumPlanes[2], &cam->frustumPlanes[3],
-                                &cam->frustumPlanes[4], &cam->frustumPlanes[5]);
-}
-
-
-void root(rs_allocation *v_out, const void *usrData) {
-
-    SgRenderable *drawable = (SgRenderable *)rsGetElementAt(*v_out, 0);
-    const SgCamera *camera = (const SgCamera*)usrData;
-
-    drawable->isVisible = 0;
-    // Not loaded yet
-    if (!rsIsObject(drawable->mesh) || drawable->cullType == CULL_ALWAYS) {
-        return;
-    }
-
-    // check to see if we are culling this object and if it's
-    // outside the frustum
-    if (drawable->cullType == CULL_FRUSTUM && frustumCulled(drawable, (SgCamera*)camera)) {
-#ifdef DEBUG_RENDERABLES
-        rsDebug("Culled", drawable);
-        printName(drawable->name);
-#endif // DEBUG_RENDERABLES
-        return;
-    }
-    drawable->isVisible = 1;
-}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs
deleted file mode 100644
index b438a43..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs
+++ /dev/null
@@ -1,61 +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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.scenegraph)
-
-// The sole purpose of this script is to have various structs exposed
-// so that java reflected classes are generated
-#include "scenegraph_objects.rsh"
-
-// Export our native constants to java so that we don't have parallel definitions
-const int ShaderParam_FLOAT4_DATA = SHADER_PARAM_FLOAT4_DATA;
-const int ShaderParam_TRANSFORM_DATA = SHADER_PARAM_TRANSFORM_DATA;
-const int ShaderParam_TRANSFORM_MODEL = SHADER_PARAM_TRANSFORM_MODEL;
-
-const int ShaderParam_FLOAT4_CAMERA_POS = SHADER_PARAM_FLOAT4_CAMERA_POS;
-const int ShaderParam_FLOAT4_CAMERA_DIR = SHADER_PARAM_FLOAT4_CAMERA_DIR;
-const int ShaderParam_TRANSFORM_VIEW = SHADER_PARAM_TRANSFORM_VIEW;
-const int ShaderParam_TRANSFORM_PROJ = SHADER_PARAM_TRANSFORM_PROJ;
-const int ShaderParam_TRANSFORM_VIEW_PROJ = SHADER_PARAM_TRANSFORM_VIEW_PROJ;
-const int ShaderParam_TRANSFORM_MODEL_VIEW = SHADER_PARAM_TRANSFORM_MODEL_VIEW;
-const int ShaderParam_TRANSFORM_MODEL_VIEW_PROJ = SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ;
-
-const int ShaderParam_FLOAT4_LIGHT_COLOR = SHADER_PARAM_FLOAT4_LIGHT_COLOR;
-const int ShaderParam_FLOAT4_LIGHT_POS = SHADER_PARAM_FLOAT4_LIGHT_POS;
-const int ShaderParam_FLOAT4_LIGHT_DIR = SHADER_PARAM_FLOAT4_LIGHT_DIR;
-
-const int ShaderParam_TEXTURE = SHADER_PARAM_TEXTURE;
-
-const int Transform_TRANSLATE = TRANSFORM_TRANSLATE;
-const int Transform_ROTATE = TRANSFORM_ROTATE;
-const int Transform_SCALE = TRANSFORM_SCALE;
-
-const int TextureType_TEXTURE_2D = TEXTURE_2D;
-const int TextureType_TEXTURE_CUBE = TEXTURE_CUBE;
-const int TextureType_TEXTURE_RENDER_TARGET = TEXTURE_RENDER_TARGET;
-
-SgTransform *exportPtr;
-SgTransformComponent *componentPtr;
-SgRenderState *sExport;
-SgRenderable *drExport;
-SgRenderPass *pExport;
-SgCamera *exportPtrCam;
-SgLight *exportPtrLight;
-SgShaderParam *spExport;
-SgShaderParamData *spDataExport;
-SgVertexShader *pvExport;
-SgFragmentShader *pfExport;
-SgTexture *texExport;
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/fragment_params.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/fragment_params.rs
deleted file mode 100644
index 7202285..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/fragment_params.rs
+++ /dev/null
@@ -1,30 +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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.scenegraph)
-
-#include "scenegraph_objects.rsh"
-
-//#define DEBUG_PARAMS
-
-#include "params.rsh"
-
-void root(rs_allocation *v_out, const void *usrData) {
-    SgFragmentShader *shader = (SgFragmentShader *)rsGetElementAt(*v_out, 0);
-    const SgCamera *camera = (const SgCamera*)usrData;
-    processAllParams(shader->shaderConst, shader->shaderConstParams, camera);
-    processTextureParams(shader);
-}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/light.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/light.rs
deleted file mode 100644
index e11979f..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/light.rs
+++ /dev/null
@@ -1,33 +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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.scenegraph)
-
-//#define DEBUG_LIGHT
-#include "scenegraph_objects.rsh"
-
-void root(const rs_allocation *v_in, rs_allocation *v_out) {
-
-    SgLight *light = (SgLight *)rsGetElementAt(*v_in, 0);
-    const SgTransform *lTransform = (const SgTransform *)rsGetElementAt(light->transformMatrix, 0);
-
-    float4 zero = {0.0f, 0.0f, 0.0f, 1.0f};
-    light->position = rsMatrixMultiply(&lTransform->globalMat, zero);
-
-#ifdef DEBUG_LIGHT
-    printLightInfo(light);
-#endif //DEBUG_LIGHT
-}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/object_params.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/object_params.rs
deleted file mode 100644
index 0d524a6..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/object_params.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (C) 2012 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.scenegraph)
-
-#include "scenegraph_objects.rsh"
-
-//#define DEBUG_PARAMS
-
-#include "params.rsh"
-
-void root(rs_allocation *v_out, const void *usrData) {
-
-    SgRenderable *drawable = (SgRenderable *)rsGetElementAt(*v_out, 0);
-    // Visibility flag was set earlier in the cull stage
-    if (!drawable->isVisible) {
-        return;
-    }
-
-    const SgCamera *camera = (const SgCamera*)usrData;
-    processAllParams(drawable->pf_const, drawable->pf_constParams, camera);
-    processAllParams(drawable->pv_const, drawable->pv_constParams, camera);
-}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh
deleted file mode 100644
index 00793c0..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh
+++ /dev/null
@@ -1,192 +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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.scenegraph)
-
-#include "scenegraph_objects.rsh"
-
-//#define DEBUG_PARAMS
-static inline void debugParam(SgShaderParam *p, SgShaderParamData *pData) {
-    rsDebug("____________ Param ____________", p);
-    printName(pData->paramName);
-    rsDebug("bufferOffset", p->bufferOffset);
-    rsDebug("type ", pData->type);
-    rsDebug("data timestamp ", pData->timestamp);
-    rsDebug("param timestamp", p->dataTimestamp);
-
-    const SgTransform *pTransform = NULL;
-    if (rsIsObject(pData->transform)) {
-        pTransform = (const SgTransform *)rsGetElementAt(pData->transform, 0);
-
-        rsDebug("transform", pTransform);
-        printName(pTransform->name);
-        rsDebug("timestamp", pTransform->timestamp);
-        rsDebug("param timestamp", p->transformTimestamp);
-    }
-
-    const SgLight *pLight = NULL;
-    if (rsIsObject(pData->light)) {
-        pLight = (const SgLight *)rsGetElementAt(pData->light, 0);
-        printLightInfo(pLight);
-    }
-}
-
-static inline void writeFloatData(float *ptr, const float4 *input, uint32_t vecSize) {
-#ifdef DEBUG_PARAMS
-    rsDebug("Writing value ", *input);
-    rsDebug("Writing vec size ", vecSize);
-#endif // DEBUG_PARAMS
-
-    switch (vecSize) {
-    case 1:
-        *ptr = input->x;
-        break;
-    case 2:
-        *((float2*)ptr) = (*input).xy;
-        break;
-    case 3:
-        *((float3*)ptr) = (*input).xyz;
-        break;
-    case 4:
-        *((float4*)ptr) = *input;
-        break;
-    }
-}
-
-static inline bool processParam(SgShaderParam *p, SgShaderParamData *pData,
-                         uint8_t *constantBuffer,
-                         const SgCamera *currentCam,
-                         SgFragmentShader *shader) {
-    bool isDataOnly = (pData->type > SHADER_PARAM_DATA_ONLY);
-    const SgTransform *pTransform = NULL;
-    if (rsIsObject(pData->transform)) {
-        pTransform = (const SgTransform *)rsGetElementAt(pData->transform, 0);
-    }
-
-    if (isDataOnly) {
-        // If we are a transform param and our transform is unchanged, nothing to do
-        if (pTransform) {
-            if (p->transformTimestamp == pTransform->timestamp) {
-                return false;
-            }
-            p->transformTimestamp = pTransform->timestamp;
-        } else {
-            if (p->dataTimestamp == pData->timestamp) {
-                return false;
-            }
-            p->dataTimestamp = pData->timestamp;
-        }
-    }
-
-    const SgLight *pLight = NULL;
-    if (rsIsObject(pData->light)) {
-        pLight = (const SgLight *)rsGetElementAt(pData->light, 0);
-    }
-
-    uint8_t *dataPtr = NULL;
-    const SgTexture *tex = NULL;
-    if (pData->type == SHADER_PARAM_TEXTURE) {
-        tex = rsGetElementAt(pData->texture, 0);
-    } else {
-        dataPtr = constantBuffer + p->bufferOffset;
-    }
-
-    switch (pData->type) {
-    case SHADER_PARAM_TEXTURE:
-        rsgBindTexture(shader->program, p->bufferOffset, tex->texture);
-        break;
-    case SHADER_PARAM_FLOAT4_DATA:
-        writeFloatData((float*)dataPtr, &pData->float_value, p->float_vecSize);
-        break;
-    case SHADER_PARAM_FLOAT4_CAMERA_POS:
-        writeFloatData((float*)dataPtr, &currentCam->position, p->float_vecSize);
-        break;
-    case SHADER_PARAM_FLOAT4_CAMERA_DIR: break;
-    case SHADER_PARAM_FLOAT4_LIGHT_COLOR:
-        writeFloatData((float*)dataPtr, &pLight->color, p->float_vecSize);
-        break;
-    case SHADER_PARAM_FLOAT4_LIGHT_POS:
-        writeFloatData((float*)dataPtr, &pLight->position, p->float_vecSize);
-        break;
-    case SHADER_PARAM_FLOAT4_LIGHT_DIR: break;
-
-    case SHADER_PARAM_TRANSFORM_DATA:
-        rsMatrixLoad((rs_matrix4x4*)dataPtr, &pTransform->globalMat);
-        break;
-    case SHADER_PARAM_TRANSFORM_VIEW:
-        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->view);
-        break;
-    case SHADER_PARAM_TRANSFORM_PROJ:
-        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->proj);
-        break;
-    case SHADER_PARAM_TRANSFORM_VIEW_PROJ:
-        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->viewProj);
-        break;
-    case SHADER_PARAM_TRANSFORM_MODEL:
-        rsMatrixLoad((rs_matrix4x4*)dataPtr, &pTransform->globalMat);
-        break;
-    case SHADER_PARAM_TRANSFORM_MODEL_VIEW:
-        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->view);
-        rsMatrixLoadMultiply((rs_matrix4x4*)dataPtr,
-                             (rs_matrix4x4*)dataPtr,
-                             &pTransform->globalMat);
-        break;
-    case SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ:
-        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->viewProj);
-        rsMatrixLoadMultiply((rs_matrix4x4*)dataPtr,
-                             (rs_matrix4x4*)dataPtr,
-                             &pTransform->globalMat);
-        break;
-    }
-    return true;
-}
-
-static inline void processAllParams(rs_allocation shaderConst,
-                             rs_allocation allParams,
-                             const SgCamera *camera) {
-    if (rsIsObject(shaderConst)) {
-        uint8_t *constantBuffer = (uint8_t*)rsGetElementAt(shaderConst, 0);
-
-        int numParams = 0;
-        if (rsIsObject(allParams)) {
-            numParams = rsAllocationGetDimX(allParams);
-        }
-        bool updated = false;
-        for (int i = 0; i < numParams; i ++) {
-            SgShaderParam *current = (SgShaderParam*)rsGetElementAt(allParams, i);
-            SgShaderParamData *currentData = (SgShaderParamData*)rsGetElementAt(current->data, 0);
-#ifdef DEBUG_PARAMS
-            debugParam(current, currentData);
-#endif // DEBUG_PARAMS
-            updated = processParam(current, currentData, constantBuffer, camera, NULL) || updated;
-        }
-    }
-}
-
-static inline void processTextureParams(SgFragmentShader *shader) {
-    int numParams = 0;
-    if (rsIsObject(shader->shaderTextureParams)) {
-        numParams = rsAllocationGetDimX(shader->shaderTextureParams);
-    }
-    for (int i = 0; i < numParams; i ++) {
-        SgShaderParam *current = (SgShaderParam*)rsGetElementAt(shader->shaderTextureParams, i);
-        SgShaderParamData *currentData = (SgShaderParamData*)rsGetElementAt(current->data, 0);
-#ifdef DEBUG_PARAMS
-        debugParam(current, currentData);
-#endif // DEBUG_PARAMS
-        processParam(current, currentData, NULL, NULL, shader);
-    }
-}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs
deleted file mode 100644
index 205b2cb..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs
+++ /dev/null
@@ -1,244 +0,0 @@
-// Copyright (C) 2011-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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.scenegraph)
-
-#include "rs_graphics.rsh"
-#include "scenegraph_objects.rsh"
-
-rs_script gTransformScript;
-rs_script gCameraScript;
-rs_script gLightScript;
-rs_script gObjectParamsScript;
-rs_script gFragmentParamsScript;
-rs_script gVertexParamsScript;
-rs_script gCullScript;
-
-SgTransform *gRootNode;
-rs_allocation gCameras;
-rs_allocation gLights;
-rs_allocation gFragmentShaders;
-rs_allocation gVertexShaders;
-rs_allocation gRenderableObjects;
-
-rs_allocation gRenderPasses;
-
-// Temporary shaders
-rs_program_store gPFSBackground;
-
-uint32_t *gFrontToBack;
-static uint32_t gFrontToBackCount = 0;
-uint32_t *gBackToFront;
-static uint32_t gBackToFrontCount = 0;
-
-static SgCamera *gActiveCamera = NULL;
-
-static rs_allocation nullAlloc;
-
-// #define DEBUG_RENDERABLES
-static void draw(SgRenderable *obj) {
-#ifdef DEBUG_RENDERABLES
-    const SgTransform *objTransform = (const SgTransform *)rsGetElementAt(obj->transformMatrix, 0);
-    rsDebug("**** Drawing object with transform", obj);
-    printName(objTransform->name);
-    rsDebug("Model matrix: ", &objTransform->globalMat);
-    printName(obj->name);
-#endif //DEBUG_RENDERABLES
-
-    const SgRenderState *renderState = (const SgRenderState *)rsGetElementAt(obj->render_state, 0);
-    const SgVertexShader *pv = (const SgVertexShader *)rsGetElementAt(renderState->pv, 0);
-    const SgFragmentShader *pf = (const SgFragmentShader *)rsGetElementAt(renderState->pf, 0);
-
-    if (pv->objectConstIndex != -1) {
-        rsgBindConstant(pv->program, pv->objectConstIndex, obj->pv_const);
-    }
-    if (pf->objectConstIndex != -1) {
-        rsgBindConstant(pf->program, pf->objectConstIndex, obj->pf_const);
-    }
-
-    if (rsIsObject(renderState->ps)) {
-        rsgBindProgramStore(renderState->ps);
-    } else {
-        rsgBindProgramStore(gPFSBackground);
-    }
-
-    if (rsIsObject(renderState->pr)) {
-        rsgBindProgramRaster(renderState->pr);
-    } else {
-        rs_program_raster pr = {0};
-        rsgBindProgramRaster(pr);
-    }
-
-    rsgBindProgramVertex(pv->program);
-    rsgBindProgramFragment(pf->program);
-
-    for (uint32_t i = 0; i < obj->pf_num_textures; i ++) {
-        const SgTexture *tex = rsGetElementAt(obj->pf_textures[i], 0);
-        rsgBindTexture(pf->program, i, tex->texture);
-    }
-
-    rsgDrawMesh(obj->mesh, obj->meshIndex);
-}
-
-static void sortToBucket(SgRenderable *obj) {
-    const SgRenderState *renderState = (const SgRenderState *)rsGetElementAt(obj->render_state, 0);
-    if (rsIsObject(renderState->ps)) {
-        bool isOpaque = false;
-        if (isOpaque) {
-            gFrontToBack[gFrontToBackCount++] = (uint32_t)obj;
-        } else {
-            gBackToFront[gBackToFrontCount++] = (uint32_t)obj;
-        }
-    } else {
-        gFrontToBack[gFrontToBackCount++] = (uint32_t)obj;
-    }
-}
-
-static void updateActiveCamera(rs_allocation cam) {
-    gActiveCamera = (SgCamera *)rsGetElementAt(cam, 0);
-}
-
-static void prepareCameras() {
-    // now compute all the camera matrices
-    if (rsIsObject(gCameras)) {
-        float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
-        rsForEach(gCameraScript, gCameras, nullAlloc, &aspect, sizeof(aspect));
-    }
-}
-
-static void prepareLights() {
-    if (rsIsObject(gLights)) {
-        rsForEach(gLightScript, gLights, nullAlloc);
-    }
-}
-
-static void drawSorted() {
-    for (int i = 0; i < gFrontToBackCount; i ++) {
-        SgRenderable *current = (SgRenderable*)gFrontToBack[i];
-        draw(current);
-    }
-
-    for (int i = 0; i < gBackToFrontCount; i ++) {
-        SgRenderable *current = (SgRenderable*)gBackToFront[i];
-        draw(current);
-    }
-}
-
-static void drawAllObjects(rs_allocation allObj) {
-    if (!rsIsObject(allObj)) {
-        return;
-    }
-
-    if (rsIsObject(gVertexShaders)) {
-        rsForEach(gVertexParamsScript, nullAlloc, gVertexShaders,
-                  gActiveCamera, sizeof(gActiveCamera));
-    }
-    if (rsIsObject(gFragmentShaders)) {
-        rsForEach(gFragmentParamsScript, nullAlloc, gFragmentShaders,
-                  gActiveCamera, sizeof(gActiveCamera));
-    }
-
-    // Run the params and cull script
-    rsForEach(gCullScript, nullAlloc, allObj, gActiveCamera, sizeof(gActiveCamera));
-    rsForEach(gObjectParamsScript, nullAlloc, allObj, gActiveCamera, sizeof(gActiveCamera));
-
-    int numRenderables = rsAllocationGetDimX(allObj);
-    for (int i = 0; i < numRenderables; i ++) {
-        rs_allocation *drawAlloc = (rs_allocation*)rsGetElementAt(allObj, i);
-        SgRenderable *current = (SgRenderable*)rsGetElementAt(*drawAlloc, 0);
-        if (current->isVisible) {
-            sortToBucket(current);
-        }
-    }
-    drawSorted();
-}
-
-int root(void) {
-#ifdef DEBUG_RENDERABLES
-    rsDebug("=============================================================================", 0);
-#endif // DEBUG_RENDERABLES
-
-    // first step is to update the transform hierachy
-    if (gRootNode && rsIsObject(gRootNode->children)) {
-        rsForEach(gTransformScript, gRootNode->children, nullAlloc, 0, 0);
-    }
-
-    prepareCameras();
-    prepareLights();
-
-    if (rsIsObject(gRenderPasses)) {
-        rsgClearDepth(1.0f);
-        int numPasses = rsAllocationGetDimX(gRenderPasses);
-        for (uint i = 0; i < numPasses; i ++) {
-            gFrontToBackCount = 0;
-            gBackToFrontCount = 0;
-            SgRenderPass *pass = (SgRenderPass*)rsGetElementAt(gRenderPasses, i);
-            if (rsIsObject(pass->color_target)) {
-                rsgBindColorTarget(pass->color_target, 0);
-            }
-            if (rsIsObject(pass->depth_target)) {
-                rsgBindDepthTarget(pass->depth_target);
-            }
-            if (!rsIsObject(pass->color_target) &&
-                !rsIsObject(pass->depth_target)) {
-                rsgClearAllRenderTargets();
-            }
-            updateActiveCamera(pass->camera);
-            if (pass->should_clear_color) {
-                rsgClearColor(pass->clear_color.x, pass->clear_color.y,
-                              pass->clear_color.z, pass->clear_color.w);
-            }
-            if (pass->should_clear_depth) {
-                rsgClearDepth(pass->clear_depth);
-            }
-            drawAllObjects(pass->objects);
-        }
-    } else {
-        gFrontToBackCount = 0;
-        gBackToFrontCount = 0;
-        rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f);
-        rsgClearDepth(1.0f);
-
-        if (rsIsObject(gCameras)) {
-            rs_allocation *camAlloc = (rs_allocation*)rsGetElementAt(gCameras, 0);
-            updateActiveCamera(*camAlloc);
-        }
-        drawAllObjects(gRenderableObjects);
-    }
-    return 10;
-}
-
-// Search through sorted and culled objects
-void pick(int screenX, int screenY) {
-    float3 pnt, vec;
-    getCameraRay(gActiveCamera, screenX, screenY, &pnt, &vec);
-
-    for (int i = 0; i < gFrontToBackCount; i ++) {
-        SgRenderable *current = (SgRenderable*)gFrontToBack[i];
-        bool isPicked = intersect(current, pnt, vec);
-        if (isPicked) {
-            current->cullType = CULL_ALWAYS;
-        }
-    }
-
-    for (int i = 0; i < gBackToFrontCount; i ++) {
-        SgRenderable *current = (SgRenderable*)gBackToFront[i];
-        bool isPicked = intersect(current, pnt, vec);
-        if (isPicked) {
-            current->cullType = CULL_ALWAYS;
-        }
-    }
-}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh
deleted file mode 100644
index 90ae212..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh
+++ /dev/null
@@ -1,323 +0,0 @@
-// Copyright (C) 2011-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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.scenegraph)
-
-#ifndef _TRANSFORM_DEF_
-#define _TRANSFORM_DEF_
-
-#include "rs_graphics.rsh"
-
-#define TRANSFORM_NONE      0
-#define TRANSFORM_TRANSLATE 1
-#define TRANSFORM_ROTATE    2
-#define TRANSFORM_SCALE     3
-
-#define CULL_FRUSTUM 0
-#define CULL_ALWAYS  2
-
-#define LIGHT_POINT       0
-#define LIGHT_DIRECTIONAL 1
-
-// Shader params that involve only data
-#define SHADER_PARAM_DATA_ONLY                 10000
-#define SHADER_PARAM_FLOAT4_DATA               10001
-#define SHADER_PARAM_TRANSFORM_DATA            10002
-#define SHADER_PARAM_TRANSFORM_MODEL           10003
-
-// Shader params that involve camera
-#define SHADER_PARAM_CAMERA                    1000
-#define SHADER_PARAM_FLOAT4_CAMERA_POS         1001
-#define SHADER_PARAM_FLOAT4_CAMERA_DIR         1002
-#define SHADER_PARAM_TRANSFORM_VIEW            1003
-#define SHADER_PARAM_TRANSFORM_PROJ            1004
-#define SHADER_PARAM_TRANSFORM_VIEW_PROJ       1005
-#define SHADER_PARAM_TRANSFORM_MODEL_VIEW      1006
-#define SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ 1007
-
-// Shader Params that only involve lights
-#define SHADER_PARAM_LIGHT                     100
-#define SHADER_PARAM_FLOAT4_LIGHT_COLOR        103
-#define SHADER_PARAM_FLOAT4_LIGHT_POS          104
-#define SHADER_PARAM_FLOAT4_LIGHT_DIR          105
-
-#define SHADER_PARAM_TEXTURE                   10
-
-#define TEXTURE_NONE          0
-#define TEXTURE_2D            1
-#define TEXTURE_CUBE          2
-#define TEXTURE_RENDER_TARGET 3
-
-typedef struct TransformComponent_s {
-    float4 value;
-    int type;
-    rs_allocation name;
-} SgTransformComponent;
-
-typedef struct __attribute__((packed, aligned(4))) SgTransform {
-    rs_matrix4x4 globalMat;
-    rs_matrix4x4 localMat;
-
-    rs_allocation components;
-    int isDirty;
-
-    rs_allocation children;
-    rs_allocation name;
-
-    // Used to check whether transform params need to be updated
-    uint32_t timestamp;
-} SgTransform;
-
-typedef struct VertexShader_s {
-    rs_program_vertex program;
-    // Buffer with vertex constant data
-    rs_allocation shaderConst;
-    // ShaderParam's that populate data
-    rs_allocation shaderConstParams;
-    // location of the per object constants on the buffer
-    int objectConstIndex;
-} SgVertexShader;
-
-typedef struct FragmentShader_s {
-    rs_program_fragment program;
-    // Buffer with vertex constant data
-    rs_allocation shaderConst;
-    // ShaderParam's that populate data
-    rs_allocation shaderConstParams;
-    // ShaderParam's that set textures
-    rs_allocation shaderTextureParams;
-    // location of the per object constants on the buffer
-    int objectConstIndex;
-} SgFragmentShader;
-
-typedef struct RenderState_s {
-    rs_allocation pv; // VertexShader struct
-    rs_allocation pf; // FragmentShader struct
-    rs_program_store ps;
-    rs_program_raster pr;
-} SgRenderState;
-
-typedef struct Renderable_s {
-    rs_allocation render_state;
-    // Buffer with vertex constant data
-    rs_allocation pv_const;
-    // ShaderParam's that populate data
-    rs_allocation pv_constParams;
-    // Buffer with fragment constant data
-    rs_allocation pf_const;
-    // ShaderParam's that populate data
-    rs_allocation pf_constParams;
-    rs_allocation pf_textures[8];
-    int pf_num_textures;
-    rs_mesh mesh;
-    int meshIndex;
-    rs_allocation transformMatrix;
-    rs_allocation name;
-    float4 boundingSphere;
-    float4 worldBoundingSphere;
-    int bVolInitialized;
-    int cullType; // specifies whether to frustum cull
-    int isVisible;
-} SgRenderable;
-
-typedef struct RenderPass_s {
-    rs_allocation color_target;
-    rs_allocation depth_target;
-    rs_allocation camera;
-    rs_allocation objects;
-
-    float4 clear_color;
-    float clear_depth;
-    bool should_clear_color;
-    bool should_clear_depth;
-} SgRenderPass;
-
-typedef struct Camera_s {
-    rs_matrix4x4 proj;
-    rs_matrix4x4 view;
-    rs_matrix4x4 viewProj;
-    float4 position;
-    float near;
-    float far;
-    float horizontalFOV;
-    float aspect;
-    rs_allocation name;
-    rs_allocation transformMatrix;
-    float4 frustumPlanes[6];
-
-    int isDirty;
-    // Timestamp of the camera itself to signal params if anything changes
-    uint32_t timestamp;
-    // Timestamp of our transform
-    uint32_t transformTimestamp;
-} SgCamera;
-
-typedef struct Light_s {
-    float4 position;
-    float4 color;
-    float intensity;
-    int type;
-    rs_allocation name;
-    rs_allocation transformMatrix;
-} SgLight;
-
-// This represents the shader parameter data needed to set a float or transform data
-typedef struct ShaderParamData_s {
-    int type;
-    float4 float_value;
-    uint32_t timestamp;
-    rs_allocation paramName;
-    rs_allocation camera;
-    rs_allocation light;
-    rs_allocation transform;
-    rs_allocation texture;
-} SgShaderParamData;
-
-// This represents a shader parameter that knows how to update itself for a given
-// renderable or shader and contains a timestamp for the last time this buffer was updated
-typedef struct ShaderParam_s {
-    // Used to check whether transform params need to be updated
-    uint32_t transformTimestamp;
-    // Used to check whether data params need to be updated
-    // These are used when somebody set the matrix of float value directly in java
-    uint32_t dataTimestamp;
-    // Specifies where in the constant buffer data gets written to
-    int bufferOffset;
-    // An instance of SgShaderParamData that could be shared by multiple objects
-    rs_allocation data;
-    // How many components of the vector we need to write
-    int float_vecSize;
-} SgShaderParam;
-
-// This represents a texture object
-typedef struct Texture_s {
-    uint32_t type;
-    rs_allocation texture;
-} SgTexture;
-
-static inline void printName(rs_allocation name) {
-    if (!rsIsObject(name)) {
-        rsDebug("no name", 0);
-        return;
-    }
-
-    rsDebug((const char*)rsGetElementAt(name, 0), 0);
-}
-
-static inline void printCameraInfo(const SgCamera *cam) {
-    rsDebug("***** Camera information. ptr:", cam);
-    printName(cam->name);
-    const SgTransform *camTransform = (const SgTransform *)rsGetElementAt(cam->transformMatrix, 0);
-    rsDebug("Transform name:", camTransform);
-    printName(camTransform->name);
-
-    rsDebug("Aspect: ", cam->aspect);
-    rsDebug("Near: ", cam->near);
-    rsDebug("Far: ", cam->far);
-    rsDebug("Fov: ", cam->horizontalFOV);
-    rsDebug("Position: ", cam->position);
-    rsDebug("Proj: ", &cam->proj);
-    rsDebug("View: ", &cam->view);
-}
-
-static inline void printLightInfo(const SgLight *light) {
-    rsDebug("***** Light information. ptr:", light);
-    printName(light->name);
-    const SgTransform *lTransform = (const SgTransform *)rsGetElementAt(light->transformMatrix, 0);
-    rsDebug("Transform name:", lTransform);
-    printName(lTransform->name);
-
-    rsDebug("Position: ", light->position);
-    rsDebug("Color : ", light->color);
-    rsDebug("Intensity: ", light->intensity);
-    rsDebug("Type: ", light->type);
-}
-
-static inline void getCameraRay(const SgCamera *cam, int screenX, int screenY, float3 *pnt, float3 *vec) {
-    rsDebug("=================================", screenX);
-    rsDebug("Point X", screenX);
-    rsDebug("Point Y", screenY);
-
-    rs_matrix4x4 mvpInv;
-    rsMatrixLoad(&mvpInv, &cam->viewProj);
-    rsMatrixInverse(&mvpInv);
-
-    float width = (float)rsgGetWidth();
-    float height = (float)rsgGetHeight();
-
-    float4 pos = {(float)screenX, height - (float)screenY, 0.0f, 1.0f};
-
-    pos.x /= width;
-    pos.y /= height;
-
-    rsDebug("Pre Norm X", pos.x);
-    rsDebug("Pre Norm Y", pos.y);
-
-    pos.xy = pos.xy * 2.0f - 1.0f;
-
-    rsDebug("Norm X", pos.x);
-    rsDebug("Norm Y", pos.y);
-
-    pos = rsMatrixMultiply(&mvpInv, pos);
-    float oneOverW = 1.0f / pos.w;
-    pos.xyz *= oneOverW;
-
-    rsDebug("World X", pos.x);
-    rsDebug("World Y", pos.y);
-    rsDebug("World Z", pos.z);
-
-    rsDebug("Cam X", cam->position.x);
-    rsDebug("Cam Y", cam->position.y);
-    rsDebug("Cam Z", cam->position.z);
-
-    *vec = normalize(pos.xyz - cam->position.xyz);
-    rsDebug("Vec X", vec->x);
-    rsDebug("Vec Y", vec->y);
-    rsDebug("Vec Z", vec->z);
-    *pnt = cam->position.xyz;
-}
-
-static inline bool intersect(const SgRenderable *obj, float3 pnt, float3 vec) {
-    // Solving for t^2 + Bt + C = 0
-    float3 originMinusCenter = pnt - obj->worldBoundingSphere.xyz;
-    float B = dot(originMinusCenter, vec) * 2.0f;
-    float C = dot(originMinusCenter, originMinusCenter) -
-              obj->worldBoundingSphere.w * obj->worldBoundingSphere.w;
-
-    float discriminant = B * B - 4.0f * C;
-    if (discriminant < 0.0f) {
-        return false;
-    }
-    discriminant = sqrt(discriminant);
-
-    float t0 = (-B - discriminant) * 0.5f;
-    float t1 = (-B + discriminant) * 0.5f;
-
-    if (t0 > t1) {
-        float temp = t0;
-        t0 = t1;
-        t1 = temp;
-    }
-
-    // The sphere is behind us
-    if (t1 < 0.0f) {
-        return false;
-    }
-    return true;
-}
-
-
-#endif // _TRANSFORM_DEF_
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs
deleted file mode 100644
index 1d0b5be..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs
+++ /dev/null
@@ -1,129 +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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.modelviewer)
-
-#include "scenegraph_objects.rsh"
-
-rs_script gTransformScript;
-
-typedef struct {
-    int changed;
-    rs_matrix4x4 *mat;
-} ParentData;
-
-//#define DEBUG_TRANSFORMS
-/* Unused function:
-static void debugTransform(SgTransform *data, const ParentData *parent) {
-    rsDebug("****** <Transform> ******", (int)data);
-    printName(data->name);
-    rsDebug("isDirty", data->isDirty);
-    rsDebug("parent", (int)parent);
-    rsDebug("child ", rsIsObject(data->children));
-
-    // Refresh matrices if dirty
-    if (data->isDirty && rsIsObject(data->components)) {
-        uint32_t numComponenets = rsAllocationGetDimX(data->components);
-        for (int i = 0; i < numComponenets; i ++) {
-            const SgTransformComponent *comp = NULL;
-            comp = (const SgTransformComponent *)rsGetElementAt(data->components, i);
-
-            if (rsIsObject(comp->name)) {
-                rsDebug((const char*)rsGetElementAt(comp->name, 0), comp->value);
-                rsDebug("Type", comp->type);
-            } else {
-                rsDebug("no name", comp->value);
-                rsDebug("Type", comp->type);
-            }
-        }
-    }
-
-    rsDebug("timestamp", data->timestamp);
-    rsDebug("****** </Transform> ******", (int)data);
-}
-*/
-
-static void appendTransformation(int type, float4 data, rs_matrix4x4 *mat) {
-    rs_matrix4x4 temp;
-
-    switch (type) {
-    case TRANSFORM_TRANSLATE:
-        rsMatrixLoadTranslate(&temp, data.x, data.y, data.z);
-        break;
-    case TRANSFORM_ROTATE:
-        rsMatrixLoadRotate(&temp, data.w, data.x, data.y, data.z);
-        break;
-    case TRANSFORM_SCALE:
-        rsMatrixLoadScale(&temp, data.x, data.y, data.z);
-        break;
-    }
-    rsMatrixMultiply(mat, &temp);
-}
-
-void root(const rs_allocation *v_in, rs_allocation *v_out, const void *usrData) {
-
-    SgTransform *data = (SgTransform *)rsGetElementAt(*v_in, 0);
-    const ParentData *parent = (const ParentData *)usrData;
-
-#ifdef DEBUG_TRANSFORMS
-    debugTransform(data, parent);
-#endif //DEBUG_TRANSFORMS
-
-    rs_matrix4x4 *localMat = &data->localMat;
-    rs_matrix4x4 *globalMat = &data->globalMat;
-
-    // Refresh matrices if dirty
-    if (data->isDirty && rsIsObject(data->components)) {
-        bool resetLocal = false;
-        uint32_t numComponenets = rsAllocationGetDimX(data->components);
-        for (int i = 0; i < numComponenets; i ++) {
-            if (!resetLocal) {
-                // Reset our local matrix only for component transforms
-                rsMatrixLoadIdentity(localMat);
-                resetLocal = true;
-            }
-            const SgTransformComponent *comp = NULL;
-            comp = (const SgTransformComponent *)rsGetElementAt(data->components, i);
-            appendTransformation(comp->type, comp->value, localMat);
-        }
-    }
-
-    if (parent) {
-        data->isDirty = (parent->changed || data->isDirty) ? 1 : 0;
-        if (data->isDirty) {
-            rsMatrixLoad(globalMat, parent->mat);
-            rsMatrixMultiply(globalMat, localMat);
-        }
-    } else if (data->isDirty) {
-        rsMatrixLoad(globalMat, localMat);
-    }
-
-    ParentData toChild;
-    toChild.changed = 0;
-    toChild.mat = globalMat;
-
-    if (data->isDirty) {
-        toChild.changed = 1;
-        data->timestamp ++;
-    }
-
-    if (rsIsObject(data->children)) {
-        rs_allocation nullAlloc = {0};
-        rsForEach(gTransformScript, data->children, nullAlloc, &toChild, sizeof(toChild));
-    }
-
-    data->isDirty = 0;
-}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/vertex_params.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/vertex_params.rs
deleted file mode 100644
index 88955a8..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/vertex_params.rs
+++ /dev/null
@@ -1,29 +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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.scenegraph)
-
-#include "scenegraph_objects.rsh"
-
-//#define DEBUG_PARAMS
-
-#include "params.rsh"
-
-void root(rs_allocation *v_out, const void *usrData) {
-    SgVertexShader *shader = (SgVertexShader *)rsGetElementAt(*v_out, 0);
-    const SgCamera *camera = (const SgCamera*)usrData;
-    processAllParams(shader->shaderConst, shader->shaderConstParams, camera);
-}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FileSelector.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FileSelector.java
deleted file mode 100644
index 420e133..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FileSelector.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.testapp;
-
-import java.io.File;
-import java.io.FileFilter;
-import java.util.ArrayList;
-import java.util.List;
-
-import android.app.ListActivity;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-
-/**
- * A list view where the last item the user clicked is placed in
- * the "activated" state, causing its background to highlight.
- */
-public class FileSelector extends ListActivity {
-
-    File[] mCurrentSubList;
-    File mCurrentFile;
-
-    class DAEFilter implements FileFilter {
-        public boolean accept(File file) {
-            if (file.isDirectory()) {
-                return true;
-            }
-            return file.getName().endsWith(".dae");
-        }
-    }
-
-    private void populateList(File file) {
-
-        mCurrentFile = file;
-        setTitle(mCurrentFile.getAbsolutePath() + "/*.dae");
-        List<String> names = new ArrayList<String>();
-        names.add("..");
-
-        mCurrentSubList = mCurrentFile.listFiles(new DAEFilter());
-
-        if (mCurrentSubList != null) {
-            for (int i = 0; i < mCurrentSubList.length; i ++) {
-                String fileName = mCurrentSubList[i].getName();
-                if (mCurrentSubList[i].isDirectory()) {
-                    fileName = "/" + fileName;
-                }
-                names.add(fileName);
-            }
-        }
-
-        // Use the built-in layout for showing a list item with a single
-        // line of text whose background is changes when activated.
-        setListAdapter(new ArrayAdapter<String>(this,
-                android.R.layout.simple_list_item_activated_1, names));
-        getListView().setTextFilterEnabled(true);
-
-        // Tell the list view to show one checked/activated item at a time.
-        getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        populateList(new File("/sdcard/"));
-    }
-
-    @Override
-    protected void onListItemClick(ListView l, View v, int position, long id) {
-        if (position == 0) {
-            File parent = mCurrentFile.getParentFile();
-            if (parent == null) {
-                return;
-            }
-            populateList(parent);
-            return;
-        }
-
-        // the first thing in list is parent directory
-        File selectedFile = mCurrentSubList[position - 1];
-        if (selectedFile.isDirectory()) {
-            populateList(selectedFile);
-            return;
-        }
-
-        Intent resultIntent = new Intent();
-        resultIntent.setData(Uri.fromFile(selectedFile));
-        setResult(RESULT_OK, resultIntent);
-        finish();
-    }
-
-}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FullscreenBlur.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FullscreenBlur.java
deleted file mode 100644
index 28f916c..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FullscreenBlur.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*

- * Copyright (C) 2011 The Android Open Source Project

- *

- * Licensed under the Apache License, Version 2.0 (the "License");

- * you may not use this file except in compliance with the License.

- * You may obtain a copy of the License at

- *

- *      http://www.apache.org/licenses/LICENSE-2.0

- *

- * Unless required by applicable law or agreed to in writing, software

- * distributed under the License is distributed on an "AS IS" BASIS,

- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

- * See the License for the specific language governing permissions and

- * limitations under the License.

- */

-

-

-package com.android.testapp;

-

-import java.util.ArrayList;

-

-import com.android.scenegraph.*;

-

-import android.content.res.Resources;

-import android.graphics.Bitmap;

-import android.graphics.BitmapFactory;

-import android.os.AsyncTask;

-import android.renderscript.*;

-import android.renderscript.Allocation.MipmapControl;

-import android.renderscript.Element.Builder;

-import android.renderscript.Font.Style;

-import android.renderscript.Program.TextureType;

-import android.renderscript.ProgramStore.DepthFunc;

-import android.util.Log;

-

-class FullscreenBlur {

-

-    static TextureRenderTarget sRenderTargetBlur0Color;

-    static TextureRenderTarget sRenderTargetBlur0Depth;

-    static TextureRenderTarget sRenderTargetBlur1Color;

-    static TextureRenderTarget sRenderTargetBlur1Depth;

-    static TextureRenderTarget sRenderTargetBlur2Color;

-    static TextureRenderTarget sRenderTargetBlur2Depth;

-

-    static FragmentShader mPF_BlurH;

-    static FragmentShader mPF_BlurV;

-    static FragmentShader mPF_SelectColor;

-    static FragmentShader mPF_Texture;

-    static VertexShader mPV_Paint;

-    static VertexShader mPV_Blur;

-

-    static int targetWidth;

-    static int targetHeight;

-

-    // This is only used when full screen blur is enabled

-    // Basically, it's the offscreen render targets

-    static void createRenderTargets(RenderScriptGL rs, int w, int h) {

-        targetWidth = w/8;

-        targetHeight = h/8;

-        Type.Builder b = new Type.Builder(rs, Element.RGBA_8888(rs));

-        Type renderType = b.setX(targetWidth).setY(targetHeight).create();

-        int usage = Allocation.USAGE_GRAPHICS_TEXTURE | Allocation.USAGE_GRAPHICS_RENDER_TARGET;

-        sRenderTargetBlur0Color = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));

-        sRenderTargetBlur1Color = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));

-        sRenderTargetBlur2Color = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));

-

-        b = new Type.Builder(rs, Element.createPixel(rs, Element.DataType.UNSIGNED_16,

-                                                     Element.DataKind.PIXEL_DEPTH));

-        renderType = b.setX(targetWidth).setY(targetHeight).create();

-        usage = Allocation.USAGE_GRAPHICS_RENDER_TARGET;

-        sRenderTargetBlur0Depth = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));

-        sRenderTargetBlur1Depth = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));

-        sRenderTargetBlur2Depth = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));

-    }

-

-    static void addOffsets(Renderable quad, float advance) {

-        quad.appendSourceParams(new Float4Param("blurOffset0", - advance * 2.5f));

-        quad.appendSourceParams(new Float4Param("blurOffset1", - advance * 0.5f));

-        quad.appendSourceParams(new Float4Param("blurOffset2", advance * 1.5f));

-        quad.appendSourceParams(new Float4Param("blurOffset3", advance * 3.5f));

-    }

-

-    static RenderPass addPass(Scene scene, Camera cam, TextureRenderTarget color, TextureRenderTarget depth) {

-        RenderPass pass = new RenderPass();

-        pass.setColorTarget(color);

-        pass.setDepthTarget(depth);

-        pass.setShouldClearColor(false);

-        pass.setShouldClearDepth(false);

-        pass.setCamera(cam);

-        scene.appendRenderPass(pass);

-        return pass;

-    }

-

-    static void addBlurPasses(Scene scene, RenderScriptGL rs, Camera cam) {

-        SceneManager sceneManager = SceneManager.getInstance();

-        ArrayList<RenderableBase> allDraw = scene.getRenderables();

-        int numDraw = allDraw.size();

-

-        ProgramRaster cullNone = ProgramRaster.CULL_NONE(rs);

-        ProgramStore blendAdd = SceneManager.BLEND_ADD_DEPTH_NONE(rs);

-        ProgramStore blendNone = ProgramStore.BLEND_NONE_DEPTH_NONE(rs);

-

-        RenderState drawTex = new RenderState(mPV_Blur, mPF_Texture, blendAdd, cullNone);

-        RenderState selectCol = new RenderState(mPV_Blur, mPF_SelectColor, blendNone, cullNone);

-        RenderState hBlur = new RenderState(mPV_Blur, mPF_BlurH, blendNone, cullNone);

-        RenderState vBlur = new RenderState(mPV_Blur, mPF_BlurV, blendNone, cullNone);

-

-        // Renders the scene off screen

-        RenderPass blurSourcePass = addPass(scene, cam,

-                                            sRenderTargetBlur0Color,

-                                            sRenderTargetBlur0Depth);

-        blurSourcePass.setClearColor(new Float4(1.0f, 1.0f, 1.0f, 1.0f));

-        blurSourcePass.setShouldClearColor(true);

-        blurSourcePass.setClearDepth(1.0f);

-        blurSourcePass.setShouldClearDepth(true);

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

-            blurSourcePass.appendRenderable((Renderable)allDraw.get(i));

-        }

-

-        // Pass for selecting bright colors

-        RenderPass selectColorPass = addPass(scene, cam,

-                                             sRenderTargetBlur2Color,

-                                             sRenderTargetBlur2Depth);

-        Renderable quad = sceneManager.getRenderableQuad("ScreenAlignedQuadS", selectCol);

-        quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur0Color));

-        selectColorPass.appendRenderable(quad);

-

-        // Horizontal blur

-        RenderPass horizontalBlurPass = addPass(scene, cam,

-                                                sRenderTargetBlur1Color,

-                                                sRenderTargetBlur1Depth);

-        quad = sceneManager.getRenderableQuad("ScreenAlignedQuadH", hBlur);

-        quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur2Color));

-        addOffsets(quad, 1.0f / (float)targetWidth);

-        horizontalBlurPass.appendRenderable(quad);

-

-        // Vertical Blur

-        RenderPass verticalBlurPass = addPass(scene, cam,

-                                              sRenderTargetBlur2Color,

-                                              sRenderTargetBlur2Depth);

-        quad = sceneManager.getRenderableQuad("ScreenAlignedQuadV", vBlur);

-        quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur1Color));

-        addOffsets(quad, 1.0f / (float)targetHeight);

-        verticalBlurPass.appendRenderable(quad);

-    }

-

-    // Additively renders the blurred colors on top of the scene

-    static void addCompositePass(Scene scene, RenderScriptGL rs, Camera cam) {

-        SceneManager sceneManager = SceneManager.getInstance();

-        RenderState drawTex = new RenderState(mPV_Blur, mPF_Texture,

-                                              SceneManager.BLEND_ADD_DEPTH_NONE(rs),

-                                              ProgramRaster.CULL_NONE(rs));

-

-        RenderPass compositePass = addPass(scene, cam, null, null);

-        Renderable quad = sceneManager.getRenderableQuad("ScreenAlignedQuadComposite", drawTex);

-        quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur2Color));

-        compositePass.appendRenderable(quad);

-    }

-

-    static private FragmentShader getShader(Resources res, RenderScriptGL rs,

-                                            int resID, Type constants) {

-        FragmentShader.Builder fb = new FragmentShader.Builder(rs);

-        fb.setShader(res, resID);

-        fb.addTexture(TextureType.TEXTURE_2D, "color");

-        if (constants != null) {

-            fb.setObjectConst(constants);

-        }

-        FragmentShader prog = fb.create();

-        prog.getProgram().bindSampler(Sampler.CLAMP_LINEAR(rs), 0);

-        return prog;

-    }

-

-    static void initShaders(Resources res, RenderScriptGL rs) {

-        ScriptField_BlurOffsets blurConst = new ScriptField_BlurOffsets(rs, 1);

-        VertexShader.Builder vb = new VertexShader.Builder(rs);

-        vb.addInput(ScriptField_VertexShaderInputs.createElement(rs));

-        vb.setShader(res, R.raw.blur_vertex);

-        mPV_Blur = vb.create();

-

-        mPF_Texture = getShader(res, rs, R.raw.texture, null);

-        mPF_Texture.getProgram().bindSampler(Sampler.WRAP_LINEAR_MIP_LINEAR(rs), 0);

-        mPF_BlurH = getShader(res, rs, R.raw.blur_h, blurConst.getAllocation().getType());

-        mPF_BlurV = getShader(res, rs, R.raw.blur_v, blurConst.getAllocation().getType());

-        mPF_SelectColor = getShader(res, rs, R.raw.select_color, null);

-    }

-

-}

-

-

-

-

-

diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/SimpleApp.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/SimpleApp.java
deleted file mode 100644
index 314db80..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/SimpleApp.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.testapp;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.View;
-import android.view.Window;
-import android.view.Window;
-import android.net.Uri;
-
-import java.lang.Runtime;
-
-public class SimpleApp extends Activity {
-
-    private SimpleAppView mView;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        // Create our Preview view and set it as the content of our
-        // Activity
-        mView = new SimpleAppView(this);
-        setContentView(mView);
-    }
-}
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/SimpleAppRS.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/SimpleAppRS.java
deleted file mode 100644
index fff6f34..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/SimpleAppRS.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.testapp;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Vector;
-
-import com.android.scenegraph.*;
-import com.android.scenegraph.SceneManager.SceneLoadedCallback;
-
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.AsyncTask;
-import android.renderscript.*;
-import android.renderscript.Program.TextureType;
-import android.util.Log;
-
-// This is where the scenegraph and the rendered objects are initialized and used
-public class SimpleAppRS {
-    SceneManager mSceneManager;
-
-    RenderScriptGL mRS;
-    Resources mRes;
-
-    Scene mScene;
-    Mesh mSimpleMesh;
-    Mesh mSphereMesh;
-    Mesh mCubeMesh;
-
-    public void init(RenderScriptGL rs, Resources res, int width, int height) {
-        mRS = rs;
-        mRes = res;
-        mSceneManager = SceneManager.getInstance();
-        mSceneManager.initRS(mRS, mRes, width, height);
-
-        mScene = new Scene();
-
-        setupGeometry();
-        setupColoredQuad();
-        setupTexturedQuad();
-        setupShadedGeometry();
-        setupCamera();
-        setupRenderPass();
-
-        mSceneManager.setActiveScene(mScene);
-
-        mScene.initRS();
-        mRS.bindRootScript(mSceneManager.getRenderLoop());
-    }
-
-    private void setupGeometry() {
-        Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS, 3,
-                                                         Mesh.TriangleMeshBuilder.TEXTURE_0);
-
-        // Create four vertices with texture coordinates
-        tmb.setTexture(0.0f, 1.0f).addVertex(-1.0f, 1.0f, 0.0f);
-        tmb.setTexture(0.0f, 0.0f).addVertex(-1.0f, -1.0f, 0.0f);
-        tmb.setTexture(1.0f, 0.0f).addVertex(1.0f, -1.0f, 0.0f);
-        tmb.setTexture(1.0f, 1.0f).addVertex(1.0f, 1.0f, 0.0f);
-
-        tmb.addTriangle(0, 1, 2);
-        tmb.addTriangle(2, 3, 0);
-        mSimpleMesh = tmb.create(true);
-
-        // Load a file that constains two pieces of geometry, a sphere and a cube
-        FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.unit_obj);
-        for (int i = 0; i < model.getIndexEntryCount(); i ++) {
-            FileA3D.IndexEntry entry = model.getIndexEntry(i);
-            if (entry != null && entry.getName().equals("CubeMesh")) {
-                mCubeMesh = entry.getMesh();
-            } else if (entry != null && entry.getName().equals("SphereMesh")) {
-                mSphereMesh = entry.getMesh();
-            }
-        }
-    }
-
-    private void setupColoredQuad() {
-        // Built-in shader that provides position, texcoord and normal
-        VertexShader genericV = SceneManager.getDefaultVS();
-        // Built-in shader that displays a color
-        FragmentShader colorF = SceneManager.getColorFS();
-        RenderState colorRS = new RenderState(genericV, colorF, null, null);
-
-        // Draw a simple colored quad
-        Renderable quad = mScene.appendNewRenderable();
-        quad.setMesh(mSimpleMesh);
-        // Our shader has a constant input called "color"
-        // This tells the scenegraph to assign the following float3 to that input
-        quad.appendSourceParams(new Float4Param("color", 0.2f, 0.3f, 0.4f));
-        quad.setRenderState(colorRS);
-    }
-
-    private void setupTexturedQuad() {
-        // Built-in shader that provides position, texcoord and normal
-        VertexShader genericV = SceneManager.getDefaultVS();
-        // Built-in shader that displays a texture
-        FragmentShader textureF = SceneManager.getTextureFS();
-        // We want to use transparency based on the alpha channel of the texture
-        ProgramStore alphaBlend = ProgramStore.BLEND_ALPHA_DEPTH_TEST(mRS);
-        RenderState texRS = new RenderState(genericV, textureF, alphaBlend, null);
-
-        // Draw a textured quad
-        Renderable quad = mScene.appendNewRenderable();
-        quad.setMesh(mSimpleMesh);
-        // Make a transform to position the quad
-        CompoundTransform t = mScene.appendNewCompoundTransform();
-        t.addTranslate("position", new Float3(2, 2, 0));
-        quad.setTransform(t);
-        // Our fragment shader has a constant texture input called "color"
-        // This will assign an icon from drawables to that input
-        quad.appendSourceParams(new TextureParam("color", new Texture2D(R.drawable.icon)));
-        quad.setRenderState(texRS);
-    }
-
-    private FragmentShader createLambertShader() {
-        // Describe what constant inputs our shader wants
-        Element.Builder b = new Element.Builder(mRS);
-        b.add(Element.F32_4(mRS), "cameraPos");
-
-        // Create a shader from a text file in resources
-        FragmentShader.Builder fb = new FragmentShader.Builder(mRS);
-        // Tell the shader what constants we want
-        fb.setShaderConst(new Type.Builder(mRS, b.create()).setX(1).create());
-        // Shader code location
-        fb.setShader(mRes, R.raw.diffuse);
-        // We want a texture called diffuse on our shader
-        fb.addTexture(TextureType.TEXTURE_2D, "diffuse");
-        FragmentShader shader = fb.create();
-        mScene.appendShader(shader);
-        return shader;
-    }
-
-    private void setupShadedGeometry() {
-        // Built-in shader that provides position, texcoord and normal
-        VertexShader genericV = SceneManager.getDefaultVS();
-        // Custom shader
-        FragmentShader diffuseF = createLambertShader();
-        RenderState diffuseRS = new RenderState(genericV, diffuseF, null, null);
-
-        // Draw a sphere
-        Renderable sphere = mScene.appendNewRenderable();
-        // Use the sphere geometry loaded earlier
-        sphere.setMesh(mSphereMesh);
-        // Make a transform to position the sphere
-        CompoundTransform t = mScene.appendNewCompoundTransform();
-        t.addTranslate("position", new Float3(-1, 2, 3));
-        t.addScale("scale", new Float3(1.4f, 1.4f, 1.4f));
-        sphere.setTransform(t);
-        // Tell the renderable which texture to use when we draw
-        // This will mean a texture param in the shader called "diffuse"
-        // will be assigned a texture called red.jpg
-        sphere.appendSourceParams(new TextureParam("diffuse", new Texture2D("", "red.jpg")));
-        sphere.setRenderState(diffuseRS);
-
-        // Draw a cube
-        Renderable cube = mScene.appendNewRenderable();
-        cube.setMesh(mCubeMesh);
-        t = mScene.appendNewCompoundTransform();
-        t.addTranslate("position", new Float3(-2, -2.1f, 0));
-        t.addRotate("rotateX", new Float3(1, 0, 0), 30);
-        t.addRotate("rotateY", new Float3(0, 1, 0), 30);
-        t.addScale("scale", new Float3(2, 2, 2));
-        cube.setTransform(t);
-        cube.appendSourceParams(new TextureParam("diffuse", new Texture2D("", "orange.jpg")));
-        cube.setRenderState(diffuseRS);
-    }
-
-    private void setupCamera() {
-        Camera camera = mScene.appendNewCamera();
-        camera.setFar(200);
-        camera.setNear(0.1f);
-        camera.setFOV(60);
-        CompoundTransform cameraTransform = mScene.appendNewCompoundTransform();
-        cameraTransform.addTranslate("camera", new Float3(0, 0, 10));
-        camera.setTransform(cameraTransform);
-    }
-
-    private void setupRenderPass() {
-        RenderPass mainPass = mScene.appendNewRenderPass();
-        mainPass.setClearColor(new Float4(1.0f, 1.0f, 1.0f, 1.0f));
-        mainPass.setShouldClearColor(true);
-        mainPass.setClearDepth(1.0f);
-        mainPass.setShouldClearDepth(true);
-        mainPass.setCamera(mScene.getCameras().get(0));
-        ArrayList<RenderableBase> allRender = mScene.getRenderables();
-        for (RenderableBase renderable : allRender) {
-            mainPass.appendRenderable((Renderable)renderable);
-        }
-    }
-}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/SimpleAppView.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/SimpleAppView.java
deleted file mode 100644
index 2112181..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/SimpleAppView.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.testapp;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-import android.renderscript.RenderScriptGL;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.Log;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-
-public class SimpleAppView extends RSSurfaceView {
-
-    public SimpleAppView(Context context) {
-        super(context);
-    }
-
-    private RenderScriptGL mRS;
-    SimpleAppRS mRender;
-
-    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
-        super.surfaceChanged(holder, format, w, h);
-        if (mRS == null) {
-            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
-            sc.setDepth(16, 24);
-            sc.setSamples(1, 2, 1);
-            mRS = createRenderScriptGL(sc);
-            mRS.setSurface(holder, w, h);
-            mRender = new SimpleAppRS();
-            mRender.init(mRS, getResources(), w, h);
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        if (mRS != null) {
-            mRender = null;
-            mRS = null;
-            destroyRenderScriptGL();
-        }
-    }
-}
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestApp.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestApp.java
deleted file mode 100644
index 385a7ab..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestApp.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.testapp;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-
-import android.app.Activity;
-import android.content.res.Configuration;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Settings.System;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.Window;
-import android.widget.Button;
-import android.widget.ListView;
-import android.view.MenuInflater;
-import android.view.Window;
-import android.net.Uri;
-
-import java.lang.Runtime;
-
-public class TestApp extends Activity {
-
-    private TestAppView mView;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        // Create our Preview view and set it as the content of our
-        // Activity
-        mView = new TestAppView(this);
-        setContentView(mView);
-    }
-
-    @Override
-    protected void onResume() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity looses focus
-        super.onResume();
-        mView.resume();
-    }
-
-    @Override
-    protected void onPause() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity looses focus
-        super.onPause();
-        mView.pause();
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        MenuInflater inflater = getMenuInflater();
-        inflater.inflate(R.menu.loader_menu, menu);
-        return true;
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        // Handle item selection
-        switch (item.getItemId()) {
-        case R.id.load_model:
-            loadModel();
-            return true;
-        case R.id.use_blur:
-            mView.mRender.toggleBlur();
-            return true;
-        default:
-            return super.onOptionsItemSelected(item);
-        }
-    }
-
-    private static final int FIND_DAE_MODEL = 10;
-    public void onActivityResult(int requestCode, int resultCode, Intent data) {
-        if (resultCode == RESULT_OK) {
-            if (requestCode == FIND_DAE_MODEL) {
-                Uri selectedImageUri = data.getData();
-                Log.e("Selected Path: ", selectedImageUri.getPath());
-                mView.mRender.loadModel(selectedImageUri.getPath());
-            }
-        }
-    }
-
-    public void loadModel() {
-        Intent intent = new Intent();
-        intent.setAction(Intent.ACTION_PICK);
-        intent.setClassName("com.android.testapp",
-                            "com.android.testapp.FileSelector");
-        startActivityForResult(intent, FIND_DAE_MODEL);
-    }
-
-}
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppLoadingScreen.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppLoadingScreen.java
deleted file mode 100644
index 5bd8f0b..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppLoadingScreen.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.testapp;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Vector;
-
-import com.android.scenegraph.SceneManager;
-
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.AsyncTask;
-import android.renderscript.*;
-import android.renderscript.Allocation.MipmapControl;
-import android.renderscript.Element.Builder;
-import android.renderscript.Font.Style;
-import android.renderscript.Program.TextureType;
-import android.renderscript.ProgramStore.DepthFunc;
-import android.util.Log;
-
-// This is where the scenegraph and the rendered objects are initialized and used
-public class TestAppLoadingScreen {
-
-    private static String TAG = "TestAppLoadingScreen";
-
-    private Resources mRes;
-    private RenderScriptGL mRS;
-    private ScriptC_test_app mScript;
-
-    public TestAppLoadingScreen(RenderScriptGL rs, Resources res) {
-        mRS = rs;
-        mRes = res;
-        // Shows the loading screen with some text
-        renderLoading();
-        // Adds a little 3D bugdroid model to the laoding screen asynchronously.
-        new LoadingScreenLoaderTask().execute();
-    }
-
-    public void showLoadingScreen(boolean show) {
-        if (show) {
-            mRS.bindRootScript(mScript);
-        } else {
-            mRS.bindRootScript(SceneManager.getInstance().getRenderLoop());
-        }
-    }
-
-    // The loading screen has some elements that shouldn't be loaded on the UI thread
-    private class LoadingScreenLoaderTask extends AsyncTask<String, Void, Boolean> {
-        Allocation robotTex;
-        Mesh robotMesh;
-        protected Boolean doInBackground(String... names) {
-            long start = System.currentTimeMillis();
-            robotTex = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot,
-                                                           MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
-                                                           Allocation.USAGE_GRAPHICS_TEXTURE);
-
-            FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot);
-            FileA3D.IndexEntry entry = model.getIndexEntry(0);
-            if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) {
-                robotMesh = entry.getMesh();
-            }
-
-            mScript.set_gPFSBackground(ProgramStore.BLEND_NONE_DEPTH_TEST(mRS));
-
-            ProgramFragmentFixedFunction.Builder b = new ProgramFragmentFixedFunction.Builder(mRS);
-            b.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
-                         ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
-            ProgramFragment pfDefault = b.create();
-            pfDefault.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0);
-            mScript.set_gPFBackground(pfDefault);
-
-            ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
-            ProgramVertexFixedFunction pvDefault = pvb.create();
-            ProgramVertexFixedFunction.Constants va = new ProgramVertexFixedFunction.Constants(mRS);
-            ((ProgramVertexFixedFunction)pvDefault).bindConstants(va);
-            mScript.set_gPVBackground(pvDefault);
-
-            long end = System.currentTimeMillis();
-            Log.v("TIMER", "Loading load time: " + (end - start));
-            return new Boolean(true);
-        }
-
-        protected void onPostExecute(Boolean result) {
-            mScript.set_gRobotTex(robotTex);
-            mScript.set_gRobotMesh(robotMesh);
-        }
-    }
-
-    // Creates a simple script to show a loding screen until everything is initialized
-    // Could also be used to do some custom renderscript work before handing things over
-    // to the scenegraph
-    void renderLoading() {
-        mScript = new ScriptC_test_app(mRS, mRes, R.raw.test_app);
-        mRS.bindRootScript(mScript);
-    }
-}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java
deleted file mode 100644
index 3aa80f4..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (C) 2011-2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.testapp;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Vector;
-
-import com.android.scenegraph.*;
-import com.android.scenegraph.SceneManager.SceneLoadedCallback;
-
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.AsyncTask;
-import android.renderscript.*;
-import android.renderscript.Program.TextureType;
-import android.util.Log;
-
-// This is where the scenegraph and the rendered objects are initialized and used
-public class TestAppRS {
-
-    private static String modelName = "orientation_test.dae";
-    private static String TAG = "TestAppRS";
-    private static String mFilePath = "";
-
-    int mWidth;
-    int mHeight;
-
-    boolean mUseBlur;
-
-    TestAppLoadingScreen mLoadingScreen;
-
-    // Used to asynchronously load scene elements like meshes and transform hierarchies
-    SceneLoadedCallback mLoadedCallback = new SceneLoadedCallback() {
-        public void run() {
-            prepareToRender(mLoadedScene);
-        }
-    };
-
-    // Top level class that initializes all the elements needed to use the scene graph
-    SceneManager mSceneManager;
-
-    // Used to move the camera around in the 3D world
-    TouchHandler mTouchHandler;
-
-    private Resources mRes;
-    private RenderScriptGL mRS;
-
-    // Shaders
-    private FragmentShader mPaintF;
-    private FragmentShader mLightsF;
-    private FragmentShader mLightsDiffF;
-    private FragmentShader mAluminumF;
-    private FragmentShader mPlasticF;
-    private FragmentShader mDiffuseF;
-    private FragmentShader mTextureF;
-    private VertexShader mGenericV;
-
-    Scene mActiveScene;
-
-    // This is a part of the test app, it's used to tests multiple render passes and is toggled
-    // on and off in the menu, off by default
-    void toggleBlur() {
-        mUseBlur = !mUseBlur;
-
-        mActiveScene.clearRenderPasses();
-        initRenderPasses();
-        mActiveScene.initRenderPassRS(mRS, mSceneManager);
-
-        // This is just a hardcoded object in the scene that gets turned on and off for the demo
-        // to make things look a bit better. This could be deleted in the cleanup
-        Renderable plane = (Renderable)mActiveScene.getRenderableByName("pPlaneShape1");
-        if (plane != null) {
-            plane.setVisible(!mUseBlur);
-        }
-    }
-
-    public void init(RenderScriptGL rs, Resources res, int width, int height) {
-        mUseBlur = false;
-        mRS = rs;
-        mRes = res;
-        mWidth = width;
-        mHeight = height;
-
-        mTouchHandler = new TouchHandler();
-
-        mSceneManager = SceneManager.getInstance();
-        // Initializes all the RS specific scenegraph elements
-        mSceneManager.initRS(mRS, mRes, mWidth, mHeight);
-
-        mLoadingScreen = new TestAppLoadingScreen(mRS, mRes);
-
-        // Initi renderscript stuff specific to the app. This will need to be abstracted out later.
-        FullscreenBlur.createRenderTargets(mRS, mWidth, mHeight);
-        initPaintShaders();
-
-        // Load a scene to render
-        mSceneManager.loadModel(mFilePath + modelName, mLoadedCallback);
-    }
-
-    // When a new model file is selected from the UI, this function gets called to init everything
-    void loadModel(String path) {
-        mLoadingScreen.showLoadingScreen(true);
-        mActiveScene.destroyRS();
-        mSceneManager.loadModel(path, mLoadedCallback);
-    }
-
-    public void onActionDown(float x, float y) {
-        mTouchHandler.onActionDown(x, y);
-    }
-
-    public void onActionScale(float scale) {
-        mTouchHandler.onActionScale(scale);
-    }
-
-    public void onActionMove(float x, float y) {
-        mTouchHandler.onActionMove(x, y);
-    }
-
-    FragmentShader createFromResource(int id, boolean addCubemap, Type constType) {
-        FragmentShader.Builder fb = new FragmentShader.Builder(mRS);
-        fb.setShaderConst(constType);
-        fb.setShader(mRes, id);
-        fb.addTexture(TextureType.TEXTURE_2D, "diffuse");
-        if (addCubemap) {
-            fb.addShaderTexture(TextureType.TEXTURE_CUBE, "reflection");
-        }
-        FragmentShader pf = fb.create();
-        pf.getProgram().bindSampler(Sampler.WRAP_LINEAR_MIP_LINEAR(mRS), 0);
-        if (addCubemap) {
-            pf.getProgram().bindSampler(Sampler.CLAMP_LINEAR_MIP_LINEAR(mRS), 1);
-        }
-        return pf;
-    }
-
-    private void initPaintShaders() {
-        mGenericV = SceneManager.getDefaultVS();
-
-        ScriptField_CameraParams camParams = new ScriptField_CameraParams(mRS, 1);
-        Type camParamType = camParams.getAllocation().getType();
-        ScriptField_LightParams lightParams = new ScriptField_LightParams(mRS, 1);
-
-        mPaintF = createFromResource(R.raw.paintf, true, camParamType);
-        // Assign a reflection map
-        TextureCube envCube = new TextureCube("sdcard/scenegraph/", "cube_env.png");
-        mPaintF.appendSourceParams(new TextureParam("reflection", envCube));
-
-        mAluminumF = createFromResource(R.raw.metal, true, camParamType);
-        TextureCube diffCube = new TextureCube("sdcard/scenegraph/", "cube_spec.png");
-        mAluminumF.appendSourceParams(new TextureParam("reflection", diffCube));
-
-        mPlasticF = createFromResource(R.raw.plastic, false, camParamType);
-        mDiffuseF = createFromResource(R.raw.diffuse, false, camParamType);
-        mTextureF = SceneManager.getTextureFS();
-
-        FragmentShader.Builder fb = new FragmentShader.Builder(mRS);
-        fb.setObjectConst(lightParams.getAllocation().getType());
-        fb.setShader(mRes, R.raw.plastic_lights);
-        mLightsF = fb.create();
-
-        fb = new FragmentShader.Builder(mRS);
-        fb.setObjectConst(lightParams.getAllocation().getType());
-        fb.setShader(mRes, R.raw.diffuse_lights);
-        mLightsDiffF = fb.create();
-
-        FullscreenBlur.initShaders(mRes, mRS);
-    }
-
-    void initRenderPasses() {
-        ArrayList<RenderableBase> allDraw = mActiveScene.getRenderables();
-        int numDraw = allDraw.size();
-
-        if (mUseBlur) {
-            FullscreenBlur.addBlurPasses(mActiveScene, mRS, mTouchHandler.getCamera());
-        }
-
-        RenderPass mainPass = new RenderPass();
-        mainPass.setClearColor(new Float4(1.0f, 1.0f, 1.0f, 1.0f));
-        mainPass.setShouldClearColor(true);
-        mainPass.setClearDepth(1.0f);
-        mainPass.setShouldClearDepth(true);
-        mainPass.setCamera(mTouchHandler.getCamera());
-        for (int i = 0; i < numDraw; i ++) {
-            mainPass.appendRenderable((Renderable)allDraw.get(i));
-        }
-        mActiveScene.appendRenderPass(mainPass);
-
-        if (mUseBlur) {
-            FullscreenBlur.addCompositePass(mActiveScene, mRS, mTouchHandler.getCamera());
-        }
-    }
-
-    private void addShadersToScene() {
-        mActiveScene.appendShader(mPaintF);
-        mActiveScene.appendShader(mLightsF);
-        mActiveScene.appendShader(mLightsDiffF);
-        mActiveScene.appendShader(mAluminumF);
-        mActiveScene.appendShader(mPlasticF);
-        mActiveScene.appendShader(mDiffuseF);
-        mActiveScene.appendShader(mTextureF);
-    }
-
-    public void prepareToRender(Scene s) {
-        mSceneManager.setActiveScene(s);
-        mActiveScene = s;
-        mTouchHandler.init(mActiveScene);
-        addShadersToScene();
-        RenderState plastic = new RenderState(mGenericV, mPlasticF, null, null);
-        RenderState diffuse = new RenderState(mGenericV, mDiffuseF, null, null);
-        RenderState paint = new RenderState(mGenericV, mPaintF, null, null);
-        RenderState aluminum = new RenderState(mGenericV, mAluminumF, null, null);
-        RenderState lights = new RenderState(mGenericV, mLightsF, null, null);
-        RenderState diff_lights = new RenderState(mGenericV, mLightsDiffF, null, null);
-        RenderState diff_lights_no_cull = new RenderState(mGenericV, mLightsDiffF, null,
-                                                          ProgramRaster.CULL_NONE(mRS));
-        RenderState glassTransp = new RenderState(mGenericV, mPaintF,
-                                                  ProgramStore.BLEND_ALPHA_DEPTH_TEST(mRS), null);
-        RenderState texState = new RenderState(mGenericV, mTextureF, null, null);
-
-        initRenderPasses();
-
-        mActiveScene.assignRenderState(plastic);
-
-        mActiveScene.assignRenderStateToMaterial(diffuse, "lambert2$");
-
-        mActiveScene.assignRenderStateToMaterial(paint, "^Paint");
-        mActiveScene.assignRenderStateToMaterial(paint, "^Carbon");
-        mActiveScene.assignRenderStateToMaterial(paint, "^Glass");
-        mActiveScene.assignRenderStateToMaterial(paint, "^MainGlass");
-
-        mActiveScene.assignRenderStateToMaterial(aluminum, "^Metal");
-        mActiveScene.assignRenderStateToMaterial(aluminum, "^Brake");
-
-        mActiveScene.assignRenderStateToMaterial(glassTransp, "^GlassLight");
-
-        mActiveScene.assignRenderStateToMaterial(lights, "^LightBlinn");
-        mActiveScene.assignRenderStateToMaterial(diff_lights, "^LightLambert");
-        mActiveScene.assignRenderStateToMaterial(diff_lights_no_cull, "^LightLambertNoCull");
-        mActiveScene.assignRenderStateToMaterial(texState, "^TextureOnly");
-
-        Renderable plane = (Renderable)mActiveScene.getRenderableByName("pPlaneShape1");
-        if (plane != null) {
-            plane.setRenderState(texState);
-            plane.setVisible(!mUseBlur);
-        }
-
-        long start = System.currentTimeMillis();
-        mActiveScene.initRS();
-        long end = System.currentTimeMillis();
-        Log.v("TIMER", "Scene init time: " + (end - start));
-
-        mLoadingScreen.showLoadingScreen(false);
-    }
-}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppView.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppView.java
deleted file mode 100644
index 33ca1b8..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppView.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.testapp;
-
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.concurrent.Semaphore;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-import android.renderscript.RenderScriptGL;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.Message;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
-
-public class TestAppView extends RSSurfaceView {
-
-    public TestAppView(Context context) {
-        super(context);
-        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
-    }
-
-    private RenderScriptGL mRS;
-    TestAppRS mRender;
-
-    private ScaleGestureDetector mScaleDetector;
-    private static final int INVALID_POINTER_ID = -1;
-    private int mActivePointerId = INVALID_POINTER_ID;
-
-    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
-        super.surfaceChanged(holder, format, w, h);
-        if (mRS == null) {
-            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
-            sc.setDepth(16, 24);
-            sc.setSamples(1, 2, 1);
-            mRS = createRenderScriptGL(sc);
-            mRS.setSurface(holder, w, h);
-            mRender = new TestAppRS();
-            mRender.init(mRS, getResources(), w, h);
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        if (mRS != null) {
-            mRender = null;
-            mRS = null;
-            destroyRenderScriptGL();
-        }
-    }
-
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event)
-    {
-        // break point at here
-        // this method doesn't work when 'extends View' include 'extends ScrollView'.
-        return super.onKeyDown(keyCode, event);
-    }
-
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        mScaleDetector.onTouchEvent(ev);
-
-        boolean ret = false;
-        float x = ev.getX();
-        float y = ev.getY();
-
-        final int action = ev.getAction();
-
-        switch (action & MotionEvent.ACTION_MASK) {
-        case MotionEvent.ACTION_DOWN: {
-            mRender.onActionDown(x, y);
-            mActivePointerId = ev.getPointerId(0);
-            ret = true;
-            break;
-        }
-        case MotionEvent.ACTION_MOVE: {
-            if (!mScaleDetector.isInProgress()) {
-                mRender.onActionMove(x, y);
-            }
-            mRender.onActionDown(x, y);
-            ret = true;
-            break;
-        }
-
-        case MotionEvent.ACTION_UP: {
-            mActivePointerId = INVALID_POINTER_ID;
-            break;
-        }
-
-        case MotionEvent.ACTION_CANCEL: {
-            mActivePointerId = INVALID_POINTER_ID;
-            break;
-        }
-
-        case MotionEvent.ACTION_POINTER_UP: {
-            final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
-                    >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
-            final int pointerId = ev.getPointerId(pointerIndex);
-            if (pointerId == mActivePointerId) {
-                // This was our active pointer going up. Choose a new
-                // active pointer and adjust accordingly.
-                final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
-                x = ev.getX(newPointerIndex);
-                y = ev.getY(newPointerIndex);
-                mRender.onActionDown(x, y);
-                mActivePointerId = ev.getPointerId(newPointerIndex);
-            }
-            break;
-        }
-        }
-
-        return ret;
-    }
-
-    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
-        @Override
-        public boolean onScale(ScaleGestureDetector detector) {
-            mRender.onActionScale(detector.getScaleFactor());
-            return true;
-        }
-    }
-}
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TouchHandler.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TouchHandler.java
deleted file mode 100644
index d0f9797..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TouchHandler.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.testapp;
-
-import android.util.Log;
-import android.renderscript.Float3;
-import com.android.scenegraph.*;
-import com.android.scenegraph.CompoundTransform.RotateComponent;
-import com.android.scenegraph.CompoundTransform.TranslateComponent;
-
-public class TouchHandler {
-    private static String TAG = "TouchHandler";
-
-    float mLastX;
-    float mLastY;
-
-    float mRotateXValue;
-    float mRotateYValue;
-    Float3 mDistValue;
-    Float3 mPosValue;
-
-    CompoundTransform mCameraRig;
-    RotateComponent mRotateX;
-    RotateComponent mRotateY;
-    TranslateComponent mDist;
-    TranslateComponent mPosition;
-    Camera mCamera;
-
-    public void init(Scene scene) {
-        // Some initial values for camera position
-        mRotateXValue = -20;
-        mRotateYValue = 0;
-        mDistValue = new Float3(0, 0, 45);
-        mPosValue = new Float3(0, 4, 0);
-
-        // Make a camera transform we can manipulate
-        mCameraRig = scene.appendNewCompoundTransform();
-        mCameraRig.setName("CameraRig");
-
-        mPosition = mCameraRig.addTranslate("Position", mPosValue);
-        mRotateY  = mCameraRig.addRotate("RotateY", new Float3(0, 1, 0), mRotateYValue);
-        mRotateX  = mCameraRig.addRotate("RotateX", new Float3(1, 0, 0), mRotateXValue);
-        mDist     = mCameraRig.addTranslate("Distance", mDistValue);
-
-        mCamera = scene.appendNewCamera();
-        mCamera.setTransform(mCameraRig);
-    }
-
-    public Camera getCamera() {
-        return mCamera;
-    }
-
-    public void onActionDown(float x, float y) {
-        mLastX = x;
-        mLastY = y;
-    }
-
-    public void onActionScale(float scale) {
-        if (mDist == null) {
-            return;
-        }
-        mDistValue.z *= 1.0f / scale;
-        mDistValue.z = Math.max(10.0f, Math.min(mDistValue.z, 150.0f));
-        mDist.setValue(mDistValue);
-    }
-
-    public void onActionMove(float x, float y) {
-        if (mRotateX == null) {
-            return;
-        }
-
-        float dx = mLastX - x;
-        float dy = mLastY - y;
-
-        if (Math.abs(dy) <= 2.0f) {
-            dy = 0.0f;
-        }
-        if (Math.abs(dx) <= 2.0f) {
-            dx = 0.0f;
-        }
-
-        mRotateYValue += dx * 0.25f;
-        mRotateYValue %= 360.0f;
-
-        mRotateXValue  += dy * 0.25f;
-        mRotateXValue  = Math.max(mRotateXValue , -80.0f);
-        mRotateXValue  = Math.min(mRotateXValue , 0.0f);
-
-        mRotateX.setAngle(mRotateXValue);
-        mRotateY.setAngle(mRotateYValue);
-
-        mLastX = x;
-        mLastY = y;
-    }
-}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs
deleted file mode 100644
index d94da52..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs
+++ /dev/null
@@ -1,84 +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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.testapp)
-
-#include "rs_graphics.rsh"
-#include "test_app.rsh"
-
-// Making sure these get reflected
-FBlurOffsets *blurExport;
-VShaderInputs *iExport;
-FShaderParams *fConst;
-FShaderLightParams *fConts2;
-VSParams *vConst2;
-VObjectParams *vConst3;
-
-rs_program_vertex gPVBackground;
-rs_program_fragment gPFBackground;
-
-rs_allocation gRobotTex;
-rs_mesh gRobotMesh;
-
-rs_program_store gPFSBackground;
-
-float gRotate;
-
-void init() {
-    gRotate = 0.0f;
-}
-
-static float gRotateY = 120.0f;
-static float gZoom = 50.0f;
-static void displayLoading() {
-    if (rsIsObject(gRobotTex) && rsIsObject(gRobotMesh)) {
-        rsgBindProgramVertex(gPVBackground);
-        rs_matrix4x4 proj;
-        float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
-        rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 100.0f);
-        rsgProgramVertexLoadProjectionMatrix(&proj);
-
-        rsgBindProgramFragment(gPFBackground);
-        rsgBindProgramStore(gPFSBackground);
-        rsgBindTexture(gPFBackground, 0, gRobotTex);
-
-        rs_matrix4x4 matrix;
-        rsMatrixLoadIdentity(&matrix);
-        // Position our models on the screen
-        gRotateY += rsGetDt()*100;
-        rsMatrixTranslate(&matrix, 0, 0, -gZoom);
-        rsMatrixRotate(&matrix, 20.0f, 1.0f, 0.0f, 0.0f);
-        rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f);
-        rsMatrixScale(&matrix, 0.2f, 0.2f, 0.2f);
-        rsgProgramVertexLoadModelMatrix(&matrix);
-        rsgDrawMesh(gRobotMesh);
-    }
-
-    uint width = rsgGetWidth();
-    uint height = rsgGetHeight();
-    int left = 0, right = 0, top = 0, bottom = 0;
-    const char* text = "Initializing...";
-    rsgMeasureText(text, &left, &right, &top, &bottom);
-    int centeredPos = width / 2 - (right - left) / 2;
-    rsgDrawText(text, centeredPos, height / 2 + height / 10);
-}
-
-int root(void) {
-    rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f);
-    rsgClearDepth(1.0f);
-    displayLoading();
-    return 30;
-}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rsh
deleted file mode 100644
index 5fbcbb2..0000000
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rsh
+++ /dev/null
@@ -1,52 +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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.testapp)
-
-// Helpers
-typedef struct ViewProjParams {
-    rs_matrix4x4 viewProj;
-} VSParams;
-
-typedef struct ModelParams {
-    rs_matrix4x4 model;
-} VObjectParams;
-
-typedef struct CameraParams {
-    float4 cameraPos;
-} FShaderParams;
-
-typedef struct LightParams {
-    float4 lightPos_0;
-    float4 lightColor_0;
-    float4 lightPos_1;
-    float4 lightColor_1;
-    float4 cameraPos;
-    float4 diffuse;
-} FShaderLightParams;
-
-typedef struct BlurOffsets {
-    float blurOffset0;
-    float blurOffset1;
-    float blurOffset2;
-    float blurOffset3;
-} FBlurOffsets;
-
-typedef struct VertexShaderInputs {
-    float4 position;
-    float3 normal;
-    float2 texture0;
-} VShaderInputs;
diff --git a/tests/RenderScriptTests/ShadersTest/Android.mk b/tests/RenderScriptTests/ShadersTest/Android.mk
deleted file mode 100644
index fb6356e..0000000
--- a/tests/RenderScriptTests/ShadersTest/Android.mk
+++ /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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-
-LOCAL_SDK_VERSION := 17
-
-LOCAL_PACKAGE_NAME := ShadersTest
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/ShadersTest/AndroidManifest.xml b/tests/RenderScriptTests/ShadersTest/AndroidManifest.xml
deleted file mode 100644
index 871200d..0000000
--- a/tests/RenderScriptTests/ShadersTest/AndroidManifest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.shaderstest">
-
-    <uses-permission android:name="android.permission.INTERNET" />
-    
-    <application android:label="_ShadersTest">
-        <activity android:name="ShadersTest"
-                  android:label="_ShadersTest"
-                  android:theme="@android:style/Theme.Black.NoTitleBar">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/ShadersTest/res/drawable-nodpi/robot.png b/tests/RenderScriptTests/ShadersTest/res/drawable-nodpi/robot.png
deleted file mode 100644
index f7353fd..0000000
--- a/tests/RenderScriptTests/ShadersTest/res/drawable-nodpi/robot.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/ShadersTest/res/raw/depth_fs.glsl b/tests/RenderScriptTests/ShadersTest/res/raw/depth_fs.glsl
deleted file mode 100644
index 096843b..0000000
--- a/tests/RenderScriptTests/ShadersTest/res/raw/depth_fs.glsl
+++ /dev/null
@@ -1,13 +0,0 @@
-void main() {
-    // Non-linear depth value
-    float z = gl_FragCoord.z;
-    // Near and far planes from the projection
-    // In practice, these values can be used to tweak
-    // the focus range
-    float n = UNI_near;
-    float f = UNI_far;
-    // Linear depth value
-    z = (2.0 * n) / (f + n - z * (f - n));
-
-    gl_FragColor = vec4(z, z, z, 1.0);
-}
diff --git a/tests/RenderScriptTests/ShadersTest/res/raw/robot.a3d b/tests/RenderScriptTests/ShadersTest/res/raw/robot.a3d
deleted file mode 100644
index f48895c..0000000
--- a/tests/RenderScriptTests/ShadersTest/res/raw/robot.a3d
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/ShadersTest/res/raw/vignette_fs.glsl b/tests/RenderScriptTests/ShadersTest/res/raw/vignette_fs.glsl
deleted file mode 100644
index 2dc1ea3..0000000
--- a/tests/RenderScriptTests/ShadersTest/res/raw/vignette_fs.glsl
+++ /dev/null
@@ -1,31 +0,0 @@
-#define CRT_MASK
-
-varying vec2 varTex0;
-
-void main() {
-    lowp vec4 color = texture2D(UNI_Tex0, varTex0);
-    
-    vec2 powers = pow(abs((gl_FragCoord.xy / vec2(UNI_width, UNI_height)) - 0.5), vec2(2.0));
-    float gradient = smoothstep(UNI_size - UNI_feather, UNI_size + UNI_feather,
-            powers.x + powers.y);
-
-    color = vec4(mix(color.rgb, vec3(0.0), gradient), 1.0);
-
-#ifdef CRT_MASK
-    float vShift = gl_FragCoord.y;
-    if (mod(gl_FragCoord.x, 6.0) >= 3.0) {
-        vShift += 2.0;
-    }
-
-    lowp vec3 r = vec3(0.95, 0.0, 0.2);
-    lowp vec3 g = vec3(0.2, 0.95, 0.0);
-    lowp vec3 b = vec3(0.0, 0.2, 0.95);
-    int channel = int(floor(mod(gl_FragCoord.x, 3.0)));
-    lowp vec4 crt = vec4(r[channel], g[channel], b[channel], 1.0);
-    crt *= clamp(floor(mod(vShift, 4.0)), 0.0, 1.0);
-    
-    color = (crt * color * 1.25) + 0.05;
-#endif
-
-    gl_FragColor = color;
-}
diff --git a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/ShadersTest.java b/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/ShadersTest.java
deleted file mode 100644
index 6803fbb..0000000
--- a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/ShadersTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.shaderstest;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-@SuppressWarnings({"UnusedDeclaration"})
-public class ShadersTest extends Activity {
-
-    private ShadersTestView mView;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        mView = new ShadersTestView(this);
-        setContentView(mView);
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        mView.resume();
-    }
-
-    @Override
-    protected void onPause() {
-        super.onPause();
-        mView.pause();
-    }
-}
diff --git a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/ShadersTestRS.java b/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/ShadersTestRS.java
deleted file mode 100644
index dad97e2..0000000
--- a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/ShadersTestRS.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.shaderstest;
-
-import android.content.res.Resources;
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.Element.DataKind;
-import android.renderscript.Element.DataType;
-import android.renderscript.FileA3D;
-import android.renderscript.Mesh;
-import android.renderscript.Program;
-import android.renderscript.ProgramFragment;
-import android.renderscript.ProgramFragmentFixedFunction;
-import android.renderscript.ProgramStore;
-import android.renderscript.ProgramStore.DepthFunc;
-import android.renderscript.ProgramVertex;
-import android.renderscript.ProgramVertexFixedFunction;
-import android.renderscript.RSRuntimeException;
-import android.renderscript.RenderScriptGL;
-import android.renderscript.Sampler;
-import android.renderscript.Type.Builder;
-
-@SuppressWarnings({"FieldCanBeLocal"})
-public class ShadersTestRS {
-    public ShadersTestRS() {
-    }
-
-    public void init(RenderScriptGL rs, Resources res) {
-        mRS = rs;
-        mRes = res;
-        initRS();
-    }
-
-    public void surfaceChanged() {
-        initBuffers(mRS.getWidth(), mRS.getHeight());
-    }
-
-    private Resources mRes;
-    private RenderScriptGL mRS;
-    private Sampler mLinearClamp;
-    private Sampler mNearestClamp;
-    private ProgramStore mPSBackground;
-    private ProgramFragment mPFBackground;
-    private ProgramVertex mPVBackground;
-    private ProgramVertexFixedFunction.Constants mPVA;
-
-    private ProgramFragment mPFVignette;
-    private ScriptField_VignetteConstants_s mFSVignetteConst;
-
-    private Allocation mMeshTexture;
-    private Allocation mScreen;
-    private Allocation mScreenDepth;
-
-    private ScriptField_MeshInfo mMeshes;
-    private ScriptC_shaderstest mScript;
-
-
-    public void onActionDown(float x, float y) {
-        mScript.invoke_onActionDown(x, y);
-    }
-
-    public void onActionScale(float scale) {
-        mScript.invoke_onActionScale(scale);
-    }
-
-    public void onActionMove(float x, float y) {
-        mScript.invoke_onActionMove(x, y);
-    }
-
-    private void initPFS() {
-        ProgramStore.Builder b = new ProgramStore.Builder(mRS);
-
-        b.setDepthFunc(DepthFunc.LESS);
-        b.setDitherEnabled(false);
-        b.setDepthMaskEnabled(true);
-        mPSBackground = b.create();
-
-        mScript.set_gPFSBackground(mPSBackground);
-    }
-
-    private void initPF() {
-        mLinearClamp = Sampler.CLAMP_LINEAR(mRS);
-        mScript.set_gLinear(mLinearClamp);
-
-        mNearestClamp = Sampler.CLAMP_NEAREST(mRS);
-        mScript.set_gNearest(mNearestClamp);
-
-        ProgramFragmentFixedFunction.Builder b = new ProgramFragmentFixedFunction.Builder(mRS);
-        b.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
-                     ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
-        mPFBackground = b.create();
-        mPFBackground.bindSampler(mLinearClamp, 0);
-        mScript.set_gPFBackground(mPFBackground);
-
-        mFSVignetteConst = new ScriptField_VignetteConstants_s(mRS, 1);
-        mScript.bind_gFSVignetteConstants(mFSVignetteConst);
-
-        ProgramFragment.Builder fs;
-
-        fs = new ProgramFragment.Builder(mRS);
-        fs.setShader(mRes, R.raw.vignette_fs);
-        fs.addConstant(mFSVignetteConst.getAllocation().getType());
-        fs.addTexture(Program.TextureType.TEXTURE_2D);
-        mPFVignette = fs.create();
-        mPFVignette.bindConstants(mFSVignetteConst.getAllocation(), 0);
-        mScript.set_gPFVignette(mPFVignette);
-    }
-
-    private void initPV() {
-        ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
-        mPVBackground = pvb.create();
-
-        mPVA = new ProgramVertexFixedFunction.Constants(mRS);
-        ((ProgramVertexFixedFunction) mPVBackground).bindConstants(mPVA);
-
-        mScript.set_gPVBackground(mPVBackground);
-    }
-
-    private void loadImage() {
-        mMeshTexture = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot,
-                Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
-                Allocation.USAGE_GRAPHICS_TEXTURE);
-        mScript.set_gTMesh(mMeshTexture);
-    }
-
-    private void initMeshes(FileA3D model) {
-        int numEntries = model.getIndexEntryCount();
-        int numMeshes = 0;
-        for (int i = 0; i < numEntries; i ++) {
-            FileA3D.IndexEntry entry = model.getIndexEntry(i);
-            if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) {
-                numMeshes ++;
-            }
-        }
-
-        if (numMeshes > 0) {
-            mMeshes = new ScriptField_MeshInfo(mRS, numMeshes);
-
-            for (int i = 0; i < numEntries; i ++) {
-                FileA3D.IndexEntry entry = model.getIndexEntry(i);
-                if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) {
-                    Mesh mesh = entry.getMesh();
-                    mMeshes.set_mMesh(i, mesh, false);
-                    mMeshes.set_mNumIndexSets(i, mesh.getPrimitiveCount(), false);
-                }
-            }
-            mMeshes.copyAll();
-        } else {
-            throw new RSRuntimeException("No valid meshes in file");
-        }
-
-        mScript.bind_gMeshes(mMeshes);
-        mScript.invoke_updateMeshInfo();
-    }
-
-    private void initRS() {
-        mScript = new ScriptC_shaderstest(mRS, mRes, R.raw.shaderstest);
-
-        initPFS();
-        initPF();
-        initPV();
-
-        loadImage();
-
-        initBuffers(1, 1);
-
-        FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot);
-        initMeshes(model);
-
-        mRS.bindRootScript(mScript);
-    }
-
-    private void initBuffers(int width, int height) {
-        Builder b;
-        b = new Builder(mRS, Element.RGBA_8888(mRS));
-        b.setX(width).setY(height);
-        mScreen = Allocation.createTyped(mRS, b.create(),
-                Allocation.USAGE_GRAPHICS_TEXTURE | Allocation.USAGE_GRAPHICS_RENDER_TARGET);
-        mScript.set_gScreen(mScreen);
-
-        b = new Builder(mRS, Element.createPixel(mRS, DataType.UNSIGNED_16, DataKind.PIXEL_DEPTH));
-        b.setX(width).setY(height);
-        mScreenDepth = Allocation.createTyped(mRS, b.create(),
-                Allocation.USAGE_GRAPHICS_RENDER_TARGET);
-        mScript.set_gScreenDepth(mScreenDepth);
-    }
-}
diff --git a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/ShadersTestView.java b/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/ShadersTestView.java
deleted file mode 100644
index e0a540f..0000000
--- a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/ShadersTestView.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.shaderstest;
-
-import android.content.Context;
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScriptGL;
-import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
-import android.view.SurfaceHolder;
-
-public class ShadersTestView extends RSSurfaceView {
-
-    private RenderScriptGL mRS;
-    private ShadersTestRS mRender;
-
-    private ScaleGestureDetector mScaleDetector;
-
-    private static final int INVALID_POINTER_ID = -1;
-    private int mActivePointerId = INVALID_POINTER_ID;
-
-    public ShadersTestView(Context context) {
-        super(context);
-        ensureRenderScript();
-        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
-    }
-
-    private void ensureRenderScript() {
-        if (mRS == null) {
-            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
-            sc.setDepth(16, 24);
-            mRS = createRenderScriptGL(sc);
-            mRender = new ShadersTestRS();
-            mRender.init(mRS, getResources());
-        }
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        ensureRenderScript();
-    }
-
-    @Override
-    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
-        super.surfaceChanged(holder, format, w, h);
-        mRender.surfaceChanged();
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        mRender = null;
-        if (mRS != null) {
-            mRS = null;
-            destroyRenderScriptGL();
-        }
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        mScaleDetector.onTouchEvent(ev);
-
-        boolean ret = false;
-        float x = ev.getX();
-        float y = ev.getY();
-
-        final int action = ev.getAction();
-
-        switch (action & MotionEvent.ACTION_MASK) {
-        case MotionEvent.ACTION_DOWN: {
-            mRender.onActionDown(x, y);
-            mActivePointerId = ev.getPointerId(0);
-            ret = true;
-            break;
-        }
-        case MotionEvent.ACTION_MOVE: {
-            if (!mScaleDetector.isInProgress()) {
-                mRender.onActionMove(x, y);
-            }
-            mRender.onActionDown(x, y);
-            ret = true;
-            break;
-        }
-
-        case MotionEvent.ACTION_UP: {
-            mActivePointerId = INVALID_POINTER_ID;
-            break;
-        }
-
-        case MotionEvent.ACTION_CANCEL: {
-            mActivePointerId = INVALID_POINTER_ID;
-            break;
-        }
-
-        case MotionEvent.ACTION_POINTER_UP: {
-            final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
-                    >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
-            final int pointerId = ev.getPointerId(pointerIndex);
-            if (pointerId == mActivePointerId) {
-                // This was our active pointer going up. Choose a new
-                // active pointer and adjust accordingly.
-                final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
-                x = ev.getX(newPointerIndex);
-                y = ev.getY(newPointerIndex);
-                mRender.onActionDown(x, y);
-                mActivePointerId = ev.getPointerId(newPointerIndex);
-            }
-            break;
-        }
-        }
-
-        return ret;
-    }
-
-    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
-        @Override
-        public boolean onScale(ScaleGestureDetector detector) {
-            mRender.onActionScale(detector.getScaleFactor());
-            return true;
-        }
-    }
-}
-
-
diff --git a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs b/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs
deleted file mode 100644
index 735f6b9..0000000
--- a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs
+++ /dev/null
@@ -1,200 +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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.shaderstest)
-
-#include "rs_graphics.rsh"
-
-rs_program_vertex gPVBackground;
-rs_program_fragment gPFBackground;
-
-typedef struct VignetteConstants_s {
-    float size;
-    float feather;
-    float width;
-    float height;
-} VignetteConstants;
-VignetteConstants *gFSVignetteConstants;
-rs_program_fragment gPFVignette;
-
-rs_allocation gTMesh;
-
-rs_sampler gLinear;
-rs_sampler gNearest;
-
-rs_program_store gPFSBackground;
-
-rs_allocation gScreenDepth;
-rs_allocation gScreen;
-
-typedef struct MeshInfo {
-    rs_mesh mMesh;
-    int mNumIndexSets;
-    float3 bBoxMin;
-    float3 bBoxMax;
-} MeshInfo_t;
-MeshInfo_t *gMeshes;
-
-static float3 gLookAt;
-
-static float gRotateX;
-static float gRotateY;
-static float gZoom;
-
-static float gLastX;
-static float gLastY;
-
-static float3 toFloat3(float x, float y, float z) {
-    float3 f;
-    f.x = x;
-    f.y = y;
-    f.z = z;
-    return f;
-}
-
-void onActionDown(float x, float y) {
-    gLastX = x;
-    gLastY = y;
-}
-
-void onActionScale(float scale) {
-
-    gZoom *= 1.0f / scale;
-    gZoom = max(0.1f, min(gZoom, 500.0f));
-}
-
-void onActionMove(float x, float y) {
-    float dx = gLastX - x;
-    float dy = gLastY - y;
-
-    if (fabs(dy) <= 2.0f) {
-        dy = 0.0f;
-    }
-    if (fabs(dx) <= 2.0f) {
-        dx = 0.0f;
-    }
-
-    gRotateY -= dx;
-    if (gRotateY > 360) {
-        gRotateY -= 360;
-    }
-    if (gRotateY < 0) {
-        gRotateY += 360;
-    }
-
-    gRotateX -= dy;
-    gRotateX = min(gRotateX, 80.0f);
-    gRotateX = max(gRotateX, -80.0f);
-
-    gLastX = x;
-    gLastY = y;
-}
-
-void init() {
-    gRotateX = 0.0f;
-    gRotateY = 0.0f;
-    gZoom = 50.0f;
-    gLookAt = 0.0f;
-}
-
-void updateMeshInfo() {
-    rs_allocation allMeshes = rsGetAllocation(gMeshes);
-    int size = rsAllocationGetDimX(allMeshes);
-    gLookAt = 0.0f;
-    float minX, minY, minZ, maxX, maxY, maxZ;
-    for (int i = 0; i < size; i++) {
-        MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i);
-        rsgMeshComputeBoundingBox(info->mMesh,
-                                  &minX, &minY, &minZ,
-                                  &maxX, &maxY, &maxZ);
-        info->bBoxMin = toFloat3(minX, minY, minZ);
-        info->bBoxMax = toFloat3(maxX, maxY, maxZ);
-        gLookAt += (info->bBoxMin + info->bBoxMax)*0.5f;
-    }
-    gLookAt = gLookAt / (float)size;
-}
-
-static void renderAllMeshes() {
-    rs_allocation allMeshes = rsGetAllocation(gMeshes);
-    int size = rsAllocationGetDimX(allMeshes);
-    gLookAt = 0.0f;
-    for (int i = 0; i < size; i++) {
-        MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i);
-        rsgDrawMesh(info->mMesh);
-    }
-}
-
-static void renderOffscreen() {
-    rsgBindProgramVertex(gPVBackground);
-    rs_matrix4x4 proj;
-    float aspect = (float) rsAllocationGetDimX(gScreen) / (float) rsAllocationGetDimY(gScreen);
-    rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 1000.0f);
-    rsgProgramVertexLoadProjectionMatrix(&proj);
-
-    rsgBindProgramFragment(gPFBackground);
-    rsgBindTexture(gPFBackground, 0, gTMesh);
-
-    rs_matrix4x4 matrix;
-
-    rsMatrixLoadIdentity(&matrix);
-    rsMatrixTranslate(&matrix, gLookAt.x, gLookAt.y, gLookAt.z - gZoom);
-    rsMatrixRotate(&matrix, gRotateX, 1.0f, 0.0f, 0.0f);
-    rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f);
-    rsgProgramVertexLoadModelMatrix(&matrix);
-
-    renderAllMeshes();
-}
-
-static void drawOffscreenResult(int posX, int posY, float width, float height) {
-    // display the result d
-    rs_matrix4x4 proj, matrix;
-    rsMatrixLoadOrtho(&proj, 0, width, height, 0, -500, 500);
-    rsgProgramVertexLoadProjectionMatrix(&proj);
-    rsMatrixLoadIdentity(&matrix);
-    rsgProgramVertexLoadModelMatrix(&matrix);
-    float startX = posX, startY = posY;
-    rsgDrawQuadTexCoords(startX, startY, 0, 0, 1,
-                         startX, startY + height, 0, 0, 0,
-                         startX + width, startY + height, 0, 1, 0,
-                         startX + width, startY, 0, 1, 1);
-}
-
-int root(void) {
-    gFSVignetteConstants->size = 0.58f * 0.58f;
-    gFSVignetteConstants->feather = 0.2f;
-    gFSVignetteConstants->width = (float) rsAllocationGetDimX(gScreen);
-    gFSVignetteConstants->height = (float) rsAllocationGetDimY(gScreen);
-
-    rsgBindProgramStore(gPFSBackground);
-
-    // Render scene to fullscreenbuffer
-    rsgBindColorTarget(gScreen, 0);
-    rsgBindDepthTarget(gScreenDepth);
-    rsgClearDepth(1.0f);
-    rsgClearColor(1.0f, 1.0f, 1.0f, 0.0f);
-    renderOffscreen();
-
-    // Render on screen
-    rsgClearAllRenderTargets();
-    rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f);
-    rsgClearDepth(1.0f);
-
-    rsgBindProgramFragment(gPFVignette);
-    rsgBindTexture(gPFVignette, 0, gScreen);
-    drawOffscreenResult(0, 0, rsgGetWidth(), rsgGetHeight());
-
-    return 0;
-}
diff --git a/tests/SoundTriggerTestApp/Android.mk b/tests/SoundTriggerTestApp/Android.mk
new file mode 100644
index 0000000..7bcab5e
--- /dev/null
+++ b/tests/SoundTriggerTestApp/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := SoundTriggerTestApp
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_PRIVILEGED_MODULE := true
+
+include $(BUILD_PACKAGE)
diff --git a/tests/SoundTriggerTestApp/AndroidManifest.xml b/tests/SoundTriggerTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..40619da
--- /dev/null
+++ b/tests/SoundTriggerTestApp/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.test.soundtrigger">
+
+    <uses-permission android:name="android.permission.MANAGE_SOUND_TRIGGER" />
+    <application
+         android:permission="android.permission.MANAGE_SOUND_TRIGGER">
+        <activity
+            android:name="TestSoundTriggerActivity"
+            android:label="SoundTrigger Test Application"
+            android:theme="@android:style/Theme.Material.Light.Voice">
+            <intent-filter>
+                <action android:name="com.android.intent.action.MANAGE_SOUND_TRIGGER" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/SoundTriggerTestApp/res/layout/main.xml b/tests/SoundTriggerTestApp/res/layout/main.xml
new file mode 100644
index 0000000..9d2b9d9
--- /dev/null
+++ b/tests/SoundTriggerTestApp/res/layout/main.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 Google Inc.
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    >
+
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/enroll"
+        android:onClick="onEnrollButtonClicked"
+        android:padding="20dp" />
+
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/reenroll"
+        android:onClick="onReEnrollButtonClicked"
+        android:padding="20dp" />
+
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/unenroll"
+        android:onClick="onUnEnrollButtonClicked"
+        android:padding="20dp" />
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/SoundTriggerTestApp/res/values/strings.xml b/tests/SoundTriggerTestApp/res/values/strings.xml
new file mode 100644
index 0000000..07bac2a
--- /dev/null
+++ b/tests/SoundTriggerTestApp/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 Google Inc.
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <string name="enroll">Enroll</string>
+    <string name="reenroll">Re-enroll</string>
+    <string name="unenroll">Un-enroll</string>
+</resources>
\ No newline at end of file
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java
new file mode 100644
index 0000000..4702835
--- /dev/null
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.soundtrigger;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.hardware.soundtrigger.SoundTrigger;
+import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
+import android.media.soundtrigger.SoundTriggerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.internal.app.ISoundTriggerService;
+
+import java.util.UUID;
+
+/**
+ * Utility class for the managing sound trigger sound models.
+ */
+public class SoundTriggerUtil {
+    private static final String TAG = "TestSoundTriggerUtil:Hotsound";
+
+    private final ISoundTriggerService mSoundTriggerService;
+    private final SoundTriggerManager mSoundTriggerManager;
+    private final Context mContext;
+
+    public SoundTriggerUtil(Context context) {
+        mSoundTriggerService = ISoundTriggerService.Stub.asInterface(
+                ServiceManager.getService(Context.SOUND_TRIGGER_SERVICE));
+        mSoundTriggerManager = (SoundTriggerManager) context.getSystemService(
+                Context.SOUND_TRIGGER_SERVICE);
+        mContext = context;
+    }
+
+    /**
+     * Adds/Updates a sound model.
+     * The sound model must contain a valid UUID.
+     *
+     * @param soundModel The sound model to add/update.
+     */
+    public boolean addOrUpdateSoundModel(GenericSoundModel soundModel) {
+        try {
+            mSoundTriggerService.updateSoundModel(soundModel);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in updateSoundModel", e);
+        }
+        return true;
+    }
+
+    public void addOrUpdateSoundModel(SoundTriggerManager.Model soundModel) {
+        mSoundTriggerManager.updateModel(soundModel);
+    }
+
+    /**
+     * Gets the sound model for the given keyphrase, null if none exists.
+     * If a sound model for a given keyphrase exists, and it needs to be updated,
+     * it should be obtained using this method, updated and then passed in to
+     * {@link #addOrUpdateSoundModel(GenericSoundModel)} without changing the IDs.
+     *
+     * @param modelId The model ID to look-up the sound model for.
+     * @return The sound model if one was found, null otherwise.
+     */
+    @Nullable
+    public GenericSoundModel getSoundModel(UUID modelId) {
+        GenericSoundModel model = null;
+        try {
+            model = mSoundTriggerService.getSoundModel(new ParcelUuid(modelId));
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in updateKeyphraseSoundModel");
+        }
+
+        if (model == null) {
+            Log.w(TAG, "No models present for the gien keyphrase ID");
+            return null;
+        } else {
+            return model;
+        }
+    }
+
+    /**
+     * Deletes the sound model for the given keyphrase id.
+     *
+     * @param modelId The model ID to look-up the sound model for.
+     * @return {@code true} if the call succeeds, {@code false} otherwise.
+     */
+    @Nullable
+    public boolean deleteSoundModel(UUID modelId) {
+        try {
+            mSoundTriggerService.deleteSoundModel(new ParcelUuid(modelId));
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in updateSoundModel");
+        }
+        return true;
+    }
+
+    public void deleteSoundModelUsingManager(UUID modelId) {
+            mSoundTriggerManager.deleteModel(modelId);
+    }
+}
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java
new file mode 100644
index 0000000..966179b
--- /dev/null
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.soundtrigger;
+
+import java.util.Random;
+import java.util.UUID;
+
+import android.app.Activity;
+import android.hardware.soundtrigger.SoundTrigger;
+import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
+import android.media.soundtrigger.SoundTriggerManager;
+import android.os.Bundle;
+import android.os.UserManager;
+import android.util.Log;
+import android.view.View;
+import android.widget.Toast;
+
+public class TestSoundTriggerActivity extends Activity {
+    private static final String TAG = "TestSoundTriggerActivity";
+    private static final boolean DBG = true;
+
+    private SoundTriggerUtil mSoundTriggerUtil;
+    private Random mRandom;
+    private UUID mModelUuid = UUID.randomUUID();
+    private UUID mModelUuid2 = UUID.randomUUID();
+    private UUID mVendorUuid = UUID.randomUUID();
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        if (DBG) Log.d(TAG, "onCreate");
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+        mSoundTriggerUtil = new SoundTriggerUtil(this);
+        mRandom = new Random();
+    }
+
+    /**
+     * Called when the user clicks the enroll button.
+     * Performs a fresh enrollment.
+     */
+    public void onEnrollButtonClicked(View v) {
+        // Generate a fake model to push.
+        byte[] data = new byte[1024];
+        mRandom.nextBytes(data);
+        GenericSoundModel model = new GenericSoundModel(mModelUuid, mVendorUuid, data);
+
+        boolean status = mSoundTriggerUtil.addOrUpdateSoundModel(model);
+        if (status) {
+            Toast.makeText(
+                    this, "Successfully created sound trigger model UUID=" + mModelUuid, Toast.LENGTH_SHORT)
+                    .show();
+        } else {
+            Toast.makeText(this, "Failed to enroll!!!" + mModelUuid, Toast.LENGTH_SHORT).show();
+        }
+
+        // Test the SoundManager API.
+        SoundTriggerManager.Model tmpModel = SoundTriggerManager.Model.create(mModelUuid2,
+                mVendorUuid, data);
+        mSoundTriggerUtil.addOrUpdateSoundModel(tmpModel);
+    }
+
+    /**
+     * Called when the user clicks the un-enroll button.
+     * Clears the enrollment information for the user.
+     */
+    public void onUnEnrollButtonClicked(View v) {
+        GenericSoundModel soundModel = mSoundTriggerUtil.getSoundModel(mModelUuid);
+        if (soundModel == null) {
+            Toast.makeText(this, "Sound model not found!!!", Toast.LENGTH_SHORT).show();
+            return;
+        }
+        boolean status = mSoundTriggerUtil.deleteSoundModel(mModelUuid);
+        if (status) {
+            Toast.makeText(this, "Successfully deleted model UUID=" + soundModel.uuid,
+                    Toast.LENGTH_SHORT)
+                    .show();
+        } else {
+            Toast.makeText(this, "Failed to delete sound model!!!", Toast.LENGTH_SHORT).show();
+        }
+        mSoundTriggerUtil.deleteSoundModelUsingManager(mModelUuid2);
+    }
+
+    /**
+     * Called when the user clicks the re-enroll button.
+     * Uses the previously enrolled sound model and makes changes to it before pushing it back.
+     */
+    public void onReEnrollButtonClicked(View v) {
+        GenericSoundModel soundModel = mSoundTriggerUtil.getSoundModel(mModelUuid);
+        if (soundModel == null) {
+            Toast.makeText(this, "Sound model not found!!!", Toast.LENGTH_SHORT).show();
+            return;
+        }
+        // Generate a fake model to push.
+        byte[] data = new byte[2048];
+        mRandom.nextBytes(data);
+        GenericSoundModel updated = new GenericSoundModel(soundModel.uuid,
+                soundModel.vendorUuid, data);
+        boolean status = mSoundTriggerUtil.addOrUpdateSoundModel(updated);
+        if (status) {
+            Toast.makeText(this, "Successfully re-enrolled, model UUID=" + updated.uuid,
+                    Toast.LENGTH_SHORT)
+                    .show();
+        } else {
+            Toast.makeText(this, "Failed to re-enroll!!!", Toast.LENGTH_SHORT).show();
+        }
+    }
+}
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index cf1a4aa..3a30230 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -23,6 +23,7 @@
 import android.content.ContentResolver;
 import android.content.Intent;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.graphics.drawable.BitmapDrawable;
 import android.os.Bundle;
 import android.os.Vibrator;
@@ -174,12 +175,15 @@
                         .setTopic(new Notification.Topic("hello", "Hello"))
                         .build();
 
-                mNM.notify(999, n);
+                mNM.notify(70, n);
             }
         },
 
         new Test("with topic GoodBye") {
             public void run() {
+                Notification.BigPictureStyle picture = new Notification.BigPictureStyle();
+                picture.bigPicture(BitmapFactory.decodeResource(getResources(),
+                        R.id.large_icon_pineapple2));
                 Notification n = new Notification.Builder(NotificationTestList.this)
                         .setSmallIcon(R.drawable.icon1)
                         .setWhen(mActivityCreateTime)
@@ -187,11 +191,47 @@
                         .setContentText("This is a notification!!!")
                         .setContentIntent(makeIntent2())
                         .setTopic(new Notification.Topic("bye", "Goodbye"))
+                        .setStyle(picture)
                         .build();
 
-                mNM.notify(9999, n);
+                mNM.notify(71, n);
             }
         },
+        new Test("with topic Bananas") {
+            public void run() {
+                Notification.BigTextStyle bigText = new Notification.BigTextStyle();
+                bigText.bigText("bananas are great\nso tasty\nyum\nyum\nyum\n");
+                Notification n = new Notification.Builder(NotificationTestList.this)
+                        .setSmallIcon(R.drawable.icon1)
+                        .setStyle(bigText)
+                        .setWhen(mActivityCreateTime)
+                        .setContentTitle("bananananana")
+                        .setContentText("This is a banana!!!")
+                        .setContentIntent(makeIntent2())
+                        .setTopic(new Notification.Topic("bananas", "Bananas"))
+                        .build();
+
+                mNM.notify(72, n);
+            }
+        },
+
+            new Test("with delete intent") {
+                public void run() {
+                    Notification.BigTextStyle bigText = new Notification.BigTextStyle();
+                    bigText.bigText("bananas are great\nso tasty\nyum\nyum\nyum\n");
+                    Notification n = new Notification.Builder(NotificationTestList.this)
+                            .setSmallIcon(R.drawable.icon1)
+                            .setStyle(bigText)
+                            .setWhen(mActivityCreateTime)
+                            .setContentTitle("bananananana")
+                            .setContentText("This is a banana!!!")
+                            .setTopic(new Notification.Topic("bananas", "Bananas"))
+                            .setDeleteIntent(makeIntent2())
+                            .build();
+
+                    mNM.notify(73, n);
+                }
+            },
 
         new Test("Whens") {
             public void run()
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_linear.xml b/tests/VectorDrawableTest/res/color/fill_gradient_linear.xml
new file mode 100644
index 0000000..e0e3f03
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_linear.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:angle="90"
+          android:startColor="?android:attr/colorPrimary"
+          android:endColor="?android:attr/colorControlActivated"
+          android:centerColor="#00ff0000"
+          android:startX="0"
+          android:startY="0"
+          android:endX="100"
+          android:endY="100"
+          android:type="linear">
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_linear_item.xml b/tests/VectorDrawableTest/res/color/fill_gradient_linear_item.xml
new file mode 100644
index 0000000..cfb1236
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_linear_item.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.
+ */
+-->
+<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="100"
+          android:endY="100"
+          android:type="linear">
+    <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_linear_item_overlap.xml b/tests/VectorDrawableTest/res/color/fill_gradient_linear_item_overlap.xml
new file mode 100644
index 0000000..18274b9
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_linear_item_overlap.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="100"
+          android:endY="100"
+          android:type="linear">
+    <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_radial.xml b/tests/VectorDrawableTest/res/color/fill_gradient_radial.xml
new file mode 100644
index 0000000..ef6fd70
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_radial.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:centerColor="#ff0000"
+          android:endColor="?android:attr/colorControlActivated"
+          android:centerX="300"
+          android:centerY="300"
+          android:gradientRadius="100"
+          android:startColor="?android:attr/colorPrimary"
+          android:type="radial">
+</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
new file mode 100644
index 0000000..51b0e17
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_radial_item.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:centerColor="#ff0000"
+          android:endColor="#ff0000ff"
+          android:centerX="300"
+          android:centerY="300"
+          android:gradientRadius="100"
+          android:startColor="#ffffffff"
+          android:type="radial">
+    <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
new file mode 100644
index 0000000..8caa1b4
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_radial_item_short.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.
+ */
+-->
+<gradient xmlns:android="http://schemas.android.com/apk/res/android"
+          android:centerX="300"
+          android:centerY="300"
+          android:gradientRadius="100"
+          android:type="radial">
+    <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.xml b/tests/VectorDrawableTest/res/color/fill_gradient_sweep.xml
new file mode 100644
index 0000000..e1fbd10
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_sweep.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:centerColor="#ff0000"
+          android:endColor="#ff0000ff"
+          android:centerX="500"
+          android:centerY="500"
+          android:gradientRadius="10"
+          android:startColor="#ffffffff"
+          android:type="sweep">
+</gradient>
diff --git a/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item.xml b/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item.xml
new file mode 100644
index 0000000..332b938
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item.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:centerColor="#ff0000"
+          android:endColor="#ff0000ff"
+          android:centerX="500"
+          android:centerY="500"
+          android:gradientRadius="10"
+          android:startColor="#ffffffff"
+          android:type="sweep">
+    <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/fill_gradient_sweep_item_long.xml b/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_long.xml
new file mode 100644
index 0000000..3931288
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/fill_gradient_sweep_item_long.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:centerX="500"
+          android:centerY="500"
+          android:gradientRadius="10"
+          android:type="sweep">
+    <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/stroke_gradient.xml b/tests/VectorDrawableTest/res/color/stroke_gradient.xml
new file mode 100644
index 0000000..cb324c9
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/stroke_gradient.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:angle="90"
+          android:centerColor="#7f7f7f"
+          android:endColor="#ffffff"
+          android:startColor="#000000"
+          android:startX="0"
+          android:endX="100"
+          android:startY="0"
+          android:endY="0"
+          android:type="linear">
+</gradient>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/stroke_gradient_item.xml b/tests/VectorDrawableTest/res/color/stroke_gradient_item.xml
new file mode 100644
index 0000000..15d948c
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/stroke_gradient_item.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.
+ */
+-->
+<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="100"
+          android:startY="0"
+          android:endY="0"
+          android:type="linear">
+    <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/color/stroke_gradient_item_alpha.xml b/tests/VectorDrawableTest/res/color/stroke_gradient_item_alpha.xml
new file mode 100644
index 0000000..fda2b88
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/stroke_gradient_item_alpha.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:startX="0"
+          android:endX="100"
+          android:startY="0"
+          android:endY="0"
+          android:type="linear">
+    <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/vector_icon_fill_state_list.xml b/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list.xml
new file mode 100644
index 0000000..45d88b5
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list.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:color="?android:attr/colorPrimary" android:state_pressed="true" />
+    <item android:color="?android:attr/colorControlActivated" />
+</selector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list_simple.xml b/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list_simple.xml
new file mode 100644
index 0000000..0e2467f
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list_simple.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:color="#f00" android:state_pressed="true" />
+    <item android:color="#00f" />
+</selector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list.xml b/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list.xml
new file mode 100644
index 0000000..16251c8
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list.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:color="?android:attr/colorControlActivated" android:state_pressed="true" />
+    <item android:color="?android:attr/colorPrimary" />
+</selector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list_simple.xml b/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list_simple.xml
new file mode 100644
index 0000000..7e6c8ce
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list_simple.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:color="#00f" android:state_pressed="true" />
+    <item android:color="#f00" />
+</selector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
index 2be99be..89afde2 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
@@ -27,8 +27,8 @@
         <path
             android:name="box1"
             android:pathData="m20,200l100,90l180-180l-35-35l-145,145l-60-60l-40,40z"
-            android:fillColor="?android:attr/colorControlNormal"
-            android:strokeColor="?android:attr/colorControlNormal"
+            android:fillColor="?android:attr/colorPrimary"
+            android:strokeColor="?android:attr/colorPrimary"
             android:strokeLineCap="round"
             android:strokeLineJoin="round" />
     </group>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_1.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_1.xml
new file mode 100644
index 0000000..d67aca7
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_1.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"
+            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"
+            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"
+            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"
+            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"
+                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"
+                        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"
+                        android:strokeColor="@color/stroke_gradient"
+                        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.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_2.xml
new file mode 100644
index 0000000..abf3c7a
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_2.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"
+            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"
+            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"
+            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"
+            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"
+                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"
+                        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"
+                        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.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_3.xml
new file mode 100644
index 0000000..5f9726f
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_gradient_3.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"
+            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"
+            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"
+            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"
+            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"
+                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"
+                        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/drawable/vector_icon_state_list_simple.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_state_list_simple.xml
new file mode 100644
index 0000000..9f08fe8
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_state_list_simple.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.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="24"
+        android:viewportWidth="24" >
+
+    <path
+        android:fillColor="@color/vector_icon_fill_state_list_simple"
+        android:strokeColor="@color/vector_icon_stroke_state_list_simple"
+        android:strokeWidth="3"
+        android:pathData="M16.0,5.0c-1.955.0 -3.83,1.268 -4.5,3.0c-0.67-1.732 -2.547-3.0 -4.5-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207-5.242 9.0-7.971 9.0-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z"/>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_state_list_theme.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_state_list_theme.xml
new file mode 100644
index 0000000..b1ed850
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_state_list_theme.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.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="24"
+        android:viewportWidth="24" >
+
+    <path
+        android:fillColor="@color/vector_icon_fill_state_list"
+        android:strokeColor="@color/vector_icon_stroke_state_list"
+        android:strokeWidth="3"
+        android:pathData="M16.0,5.0c-1.955.0 -3.83,1.268 -4.5,3.0c-0.67-1.732 -2.547-3.0 -4.5-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207-5.242 9.0-7.971 9.0-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z"/>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
index b4a93f6..7172147 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
@@ -35,6 +35,11 @@
 public class VectorDrawablePerformance extends Activity {
     private static final String LOGCAT = "VectorDrawable1";
     protected int[] icon = {
+            R.drawable.vector_icon_gradient_1,
+            R.drawable.vector_icon_gradient_2,
+            R.drawable.vector_icon_gradient_3,
+            R.drawable.vector_icon_state_list_simple,
+            R.drawable.vector_icon_state_list_theme,
             R.drawable.vector_drawable01,
             R.drawable.vector_drawable02,
             R.drawable.vector_drawable03,
@@ -102,7 +107,7 @@
         ScrollView scrollView = new ScrollView(this);
         GridLayout container = new GridLayout(this);
         scrollView.addView(container);
-        container.setColumnCount(5);
+        container.setColumnCount(4);
         Resources res = this.getResources();
         container.setBackgroundColor(0xFF888888);
         VectorDrawable []d = new VectorDrawable[icon.length];
diff --git a/tests/VoiceInteraction/AndroidManifest.xml b/tests/VoiceInteraction/AndroidManifest.xml
index fe17c6e..cbc6c76 100644
--- a/tests/VoiceInteraction/AndroidManifest.xml
+++ b/tests/VoiceInteraction/AndroidManifest.xml
@@ -61,5 +61,13 @@
                 <category android:name="android.intent.category.VOICE" />
             </intent-filter>
         </activity>
+        <activity android:name="StartVoiceInteractionActivity" android:label="In-Activity Voice"
+                  android:theme="@android:style/Theme.Material.Light">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/tests/VoiceInteraction/res/layout/local_interaction_app.xml b/tests/VoiceInteraction/res/layout/local_interaction_app.xml
new file mode 100644
index 0000000..9694133
--- /dev/null
+++ b/tests/VoiceInteraction/res/layout/local_interaction_app.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:padding="8dp"
+    >
+
+    <TextView android:id="@+id/log"
+        android:layout_width="match_parent"
+        android:layout_height="0px"
+        android:layout_weight="1"
+        android:layout_marginTop="16dp"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        />
+
+    <LinearLayout android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"
+        android:orientation="horizontal">
+
+        <Button android:id="@+id/start"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/startFromActivity"
+            />
+
+    </LinearLayout>
+
+    <LinearLayout android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"
+        android:orientation="horizontal">
+
+        <Button android:id="@+id/stop"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/stopFromActivity"
+            android:enabled="false"
+            />
+
+    </LinearLayout>
+
+    <LinearLayout android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"
+        android:orientation="horizontal">
+
+        <Button android:id="@+id/command"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/commandVoice"
+            />
+
+        <Button android:id="@+id/pick"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/pickVoice"
+            />
+
+    </LinearLayout>
+
+    <LinearLayout android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"
+        android:layout_marginBottom="16dp"
+        android:orientation="horizontal">
+
+        <Button android:id="@+id/cancel"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/cancelVoice"
+        />
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/tests/VoiceInteraction/res/values/strings.xml b/tests/VoiceInteraction/res/values/strings.xml
index c665c23..64f8bc5 100644
--- a/tests/VoiceInteraction/res/values/strings.xml
+++ b/tests/VoiceInteraction/res/values/strings.xml
@@ -31,6 +31,8 @@
     <string name="pickVoice">Pick Voice</string>
     <string name="cancelVoice">Cancel</string>
     <string name="jumpOut">Jump out</string>
+    <string name="startFromActivity">Start voice interaction</string>
+    <string name="stopFromActivity">Stop voice interaction</string>
 
     <string name="largetext">This is a bunch of text that we will use to show how we handle it
 when reporting it for assist data.  We need many many lines of text, like\n
diff --git a/tests/VoiceInteraction/res/xml/interaction_service.xml b/tests/VoiceInteraction/res/xml/interaction_service.xml
index c015ad2..f0c88a2 100644
--- a/tests/VoiceInteraction/res/xml/interaction_service.xml
+++ b/tests/VoiceInteraction/res/xml/interaction_service.xml
@@ -21,4 +21,5 @@
     android:sessionService="com.android.test.voiceinteraction.MainInteractionSessionService"
     android:recognitionService="com.android.test.voiceinteraction.MainRecognitionService"
     android:settingsActivity="com.android.test.voiceinteraction.SettingsActivity"
-    android:supportsAssist="true" />
+    android:supportsAssist="true" 
+    android:supportsLocalInteraction="true" />
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
index 6e3694b..450334c 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -73,6 +73,7 @@
     CharSequence mPendingPrompt;
     Request mPendingRequest;
     int mCurrentTask = -1;
+    int mShowFlags;
 
     MainInteractionSession(Context context) {
         super(context);
@@ -88,6 +89,7 @@
     @Override
     public void onShow(Bundle args, int showFlags) {
         super.onShow(args, showFlags);
+        mShowFlags = showFlags;
         Log.i(TAG, "onShow: flags=0x" + Integer.toHexString(showFlags) + " args=" + args);
         mState = STATE_IDLE;
         mStartIntent = args != null ? (Intent)args.getParcelable("intent") : null;
@@ -311,6 +313,8 @@
         if (mState != STATE_IDLE) {
             outInsets.contentInsets.top = mBottomContent.getTop();
             outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_CONTENT;
+        } else if ((mShowFlags & SHOW_SOURCE_ACTIVITY) != 0) {
+            outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_CONTENT;
         }
     }
 
@@ -355,7 +359,7 @@
             mPendingPrompt = prompt.getVisualPrompt();
         }
     }
-      
+
     @Override
     public void onRequestConfirmation(ConfirmationRequest request) {
         Log.i(TAG, "onConfirm: prompt=" + request.getVoicePrompt() + " extras="
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/StartVoiceInteractionActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/StartVoiceInteractionActivity.java
new file mode 100644
index 0000000..41058c9
--- /dev/null
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/StartVoiceInteractionActivity.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.voiceinteraction;
+
+import android.app.Activity;
+import android.app.VoiceInteractor;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+public class StartVoiceInteractionActivity extends Activity implements View.OnClickListener {
+    static final String TAG = "LocalVoiceInteractionActivity";
+
+    static final String REQUEST_ABORT = "abort";
+    static final String REQUEST_COMPLETE = "complete";
+    static final String REQUEST_COMMAND = "command";
+    static final String REQUEST_PICK = "pick";
+    static final String REQUEST_CONFIRM = "confirm";
+
+    VoiceInteractor mInteractor;
+    VoiceInteractor.Request mCurrentRequest = null;
+    TextView mLog;
+    Button mCommandButton;
+    Button mPickButton;
+    Button mCancelButton;
+    Button mStartButton;
+    Button mStopButton;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.local_interaction_app);
+
+        mLog = (TextView)findViewById(R.id.log);
+        mCommandButton = (Button)findViewById(R.id.command);
+        mCommandButton.setOnClickListener(this);
+        mPickButton = (Button)findViewById(R.id.pick);
+        mPickButton.setOnClickListener(this);
+        mCancelButton = (Button)findViewById(R.id.cancel);
+        mCancelButton.setOnClickListener(this);
+        mStartButton = (Button) findViewById(R.id.start);
+        mStartButton.setOnClickListener(this);
+        mStopButton = (Button) findViewById(R.id.stop);
+        mStopButton.setOnClickListener(this);
+
+        mLog.append("Local Voice Interaction Supported = " + isLocalVoiceInteractionSupported());
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (v == mCommandButton) {
+            VoiceInteractor.CommandRequest req = new TestCommand("Some arg");
+            mInteractor.submitRequest(req, REQUEST_COMMAND);
+        } else if (v == mPickButton) {
+            VoiceInteractor.PickOptionRequest.Option[] options =
+                    new VoiceInteractor.PickOptionRequest.Option[5];
+            options[0] = new VoiceInteractor.PickOptionRequest.Option("One");
+            options[1] = new VoiceInteractor.PickOptionRequest.Option("Two");
+            options[2] = new VoiceInteractor.PickOptionRequest.Option("Three");
+            options[3] = new VoiceInteractor.PickOptionRequest.Option("Four");
+            options[4] = new VoiceInteractor.PickOptionRequest.Option("Five");
+            VoiceInteractor.PickOptionRequest req = new TestPickOption(options);
+            mInteractor.submitRequest(req, REQUEST_PICK);
+        } else if (v == mCancelButton && mCurrentRequest != null) {
+            Log.i(TAG, "Cancel request");
+            mCurrentRequest.cancel();
+        } else if (v == mStartButton) {
+            Bundle args = new Bundle();
+            args.putString("Foo", "Bar");
+            startLocalVoiceInteraction(args);
+        } else if (v == mStopButton) {
+            stopLocalVoiceInteraction();
+        }
+    }
+
+    @Override
+    public void onLocalVoiceInteractionStarted() {
+        mInteractor = getVoiceInteractor();
+        mLog.append("\nLocalVoiceInteraction started!");
+        mStopButton.setEnabled(true);
+    }
+
+    @Override
+    public void onLocalVoiceInteractionStopped() {
+        mInteractor = getVoiceInteractor();
+        mLog.append("\nLocalVoiceInteraction stopped!");
+        mStopButton.setEnabled(false);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+    }
+
+    static class TestAbortVoice extends VoiceInteractor.AbortVoiceRequest {
+        public TestAbortVoice() {
+            super(new VoiceInteractor.Prompt("Dammit, we suck :("), null);
+        }
+        @Override public void onCancel() {
+            Log.i(TAG, "Canceled!");
+            ((StartVoiceInteractionActivity)getActivity()).mLog.append("Canceled abort\n");
+        }
+        @Override public void onAbortResult(Bundle result) {
+            Log.i(TAG, "Abort result: result=" + result);
+            ((StartVoiceInteractionActivity)getActivity()).mLog.append(
+                    "Abort: result=" + result + "\n");
+            getActivity().finish();
+        }
+    }
+
+    static class TestCompleteVoice extends VoiceInteractor.CompleteVoiceRequest {
+        public TestCompleteVoice() {
+            super(new VoiceInteractor.Prompt("Woohoo, completed!"), null);
+        }
+        @Override public void onCancel() {
+            Log.i(TAG, "Canceled!");
+            ((StartVoiceInteractionActivity)getActivity()).mLog.append("Canceled complete\n");
+        }
+        @Override public void onCompleteResult(Bundle result) {
+            Log.i(TAG, "Complete result: result=" + result);
+            ((StartVoiceInteractionActivity)getActivity()).mLog.append("Complete: result="
+                    + result + "\n");
+            getActivity().finish();
+        }
+    }
+
+    static class TestCommand extends VoiceInteractor.CommandRequest {
+        public TestCommand(String arg) {
+            super("com.android.test.voiceinteraction.COMMAND", makeBundle(arg));
+        }
+        @Override public void onCancel() {
+            Log.i(TAG, "Canceled!");
+            ((StartVoiceInteractionActivity)getActivity()).mLog.append("Canceled command\n");
+        }
+        @Override
+        public void onCommandResult(boolean finished, Bundle result) {
+            Log.i(TAG, "Command result: finished=" + finished + " result=" + result);
+            StringBuilder sb = new StringBuilder();
+            if (finished) {
+                sb.append("Command final result: ");
+            } else {
+                sb.append("Command intermediate result: ");
+            }
+            if (result != null) {
+                result.getString("key");
+            }
+            sb.append(result);
+            sb.append("\n");
+            ((StartVoiceInteractionActivity)getActivity()).mLog.append(sb.toString());
+        }
+        static Bundle makeBundle(String arg) {
+            Bundle b = new Bundle();
+            b.putString("key", arg);
+            return b;
+        }
+    }
+
+    static class TestPickOption extends VoiceInteractor.PickOptionRequest {
+        public TestPickOption(Option[] options) {
+            super(new VoiceInteractor.Prompt("Need to pick something"), options, null);
+        }
+        @Override public void onCancel() {
+            Log.i(TAG, "Canceled!");
+            ((StartVoiceInteractionActivity)getActivity()).mLog.append("Canceled pick\n");
+        }
+        @Override
+        public void onPickOptionResult(boolean finished, Option[] selections, Bundle result) {
+            Log.i(TAG, "Pick result: finished=" + finished + " selections=" + selections
+                    + " result=" + result);
+            StringBuilder sb = new StringBuilder();
+            if (finished) {
+                sb.append("Pick final result: ");
+            } else {
+                sb.append("Pick intermediate result: ");
+            }
+            for (int i=0; i<selections.length; i++) {
+                if (i >= 1) {
+                    sb.append(", ");
+                }
+                sb.append(selections[i].getLabel());
+            }
+            sb.append("\n");
+            ((StartVoiceInteractionActivity)getActivity()).mLog.append(sb.toString());
+        }
+    }
+}
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 3c2659f..b78fd49 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -93,7 +93,7 @@
 
         try {
             mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false, null,
-                    Configuration.EMPTY, false);
+                    Configuration.EMPTY, false, false);
             fail("IWindowManager.addAppToken did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index d346731..3b01827 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -235,7 +235,7 @@
          setRegion(part2.string());
      } else if (part2.length() == 4 && isAlpha(part2)) {
          setScript(part2.string());
-     } else if (part2.length() >= 5 && part2.length() <= 8) {
+     } else if (part2.length() >= 4 && part2.length() <= 8) {
          setVariant(part2.string());
      } else {
          valid = false;
@@ -250,7 +250,7 @@
      if (((part3.length() == 2 && isAlpha(part3)) ||
          (part3.length() == 3 && isNumber(part3))) && script[0]) {
          setRegion(part3.string());
-     } else if (part3.length() >= 5 && part3.length() <= 8) {
+     } else if (part3.length() >= 4 && part3.length() <= 8) {
          setVariant(part3.string());
      } else {
          valid = false;
@@ -261,7 +261,7 @@
      }
 
      const String8& part4 = parts[3];
-     if (part4.length() >= 5 && part4.length() <= 8) {
+     if (part4.length() >= 4 && part4.length() <= 8) {
          setVariant(part4.string());
      } else {
          valid = false;
@@ -280,7 +280,7 @@
 
     String8 part = parts[currentIndex];
     if (part[0] == 'b' && part[1] == '+') {
-        // This is a "modified" BCP-47 language tag. Same semantics as BCP-47 tags,
+        // This is a "modified" BCP 47 language tag. Same semantics as BCP 47 tags,
         // except that the separator is "+" and not "-".
         Vector<String8> subtags = AaptUtil::splitAndLowerCase(part, '+');
         subtags.removeItemsAt(0);
@@ -296,8 +296,11 @@
                     setRegion(subtags[1]);
                     break;
                 case 4:
-                    setScript(subtags[1]);
-                    break;
+                    if (isAlpha(subtags[1])) {
+                        setScript(subtags[1]);
+                        break;
+                    }
+                    // This is not alphabetical, so we fall through to variant
                 case 5:
                 case 6:
                 case 7:
@@ -305,7 +308,7 @@
                     setVariant(subtags[1]);
                     break;
                 default:
-                    fprintf(stderr, "ERROR: Invalid BCP-47 tag in directory name %s\n",
+                    fprintf(stderr, "ERROR: Invalid BCP 47 tag in directory name %s\n",
                             part.string());
                     return -1;
             }
@@ -322,13 +325,13 @@
                 setRegion(subtags[1]);
                 hasRegion = true;
             } else {
-                fprintf(stderr, "ERROR: Invalid BCP-47 tag in directory name %s\n", part.string());
+                fprintf(stderr, "ERROR: Invalid BCP 47 tag in directory name %s\n", part.string());
                 return -1;
             }
 
             // The third tag can either be a region code (if the second tag was
             // a script), else a variant code.
-            if (subtags[2].size() > 4) {
+            if (subtags[2].size() >= 4) {
                 setVariant(subtags[2]);
             } else {
                 setRegion(subtags[2]);
@@ -339,7 +342,7 @@
             setRegion(subtags[2]);
             setVariant(subtags[3]);
         } else {
-            fprintf(stderr, "ERROR: Invalid BCP-47 tag in directory name: %s\n", part.string());
+            fprintf(stderr, "ERROR: Invalid BCP 47 tag in directory name: %s\n", part.string());
             return -1;
         }
 
@@ -370,7 +373,7 @@
 void AaptLocaleValue::initFromResTable(const ResTable_config& config) {
     config.unpackLanguage(language);
     config.unpackRegion(region);
-    if (config.localeScript[0]) {
+    if (config.localeScriptWasProvided) {
         memcpy(script, config.localeScript, sizeof(config.localeScript));
     }
 
@@ -385,6 +388,10 @@
 
     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/Images.cpp b/tools/aapt/Images.cpp
index e4738f5..5ad3379 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -1095,13 +1095,6 @@
     analyze_image(imageName, imageInfo, grayscaleTolerance, rgbPalette, alphaPalette,
                   &paletteEntries, &hasTransparency, &color_type, outRows);
 
-    // If the image is a 9-patch, we need to preserve it as a ARGB file to make
-    // sure the pixels will not be pre-dithered/clamped until we decide they are
-    if (imageInfo.is9Patch && (color_type == PNG_COLOR_TYPE_RGB ||
-            color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_PALETTE)) {
-        color_type = PNG_COLOR_TYPE_RGB_ALPHA;
-    }
-
     if (kIsDebug) {
         switch (color_type) {
         case PNG_COLOR_TYPE_PALETTE:
@@ -1180,18 +1173,11 @@
         }
 
         for (int i = 0; i < chunk_count; i++) {
-            unknowns[i].location = PNG_HAVE_PLTE;
+            unknowns[i].location = PNG_HAVE_IHDR;
         }
         png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_ALWAYS,
                                     chunk_names, chunk_count);
         png_set_unknown_chunks(write_ptr, write_info, unknowns, chunk_count);
-#if PNG_LIBPNG_VER < 10600
-        /* Deal with unknown chunk location bug in 1.5.x and earlier */
-        png_set_unknown_chunk_location(write_ptr, write_info, 0, PNG_HAVE_PLTE);
-        if (imageInfo.haveLayoutBounds) {
-            png_set_unknown_chunk_location(write_ptr, write_info, 1, PNG_HAVE_PLTE);
-        }
-#endif
     }
 
 
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 576f076..4d9ba6c 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -2119,7 +2119,7 @@
                 indentStr);
     }
 
-    return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
+    return hasErrors ? STATUST(UNKNOWN_ERROR) : NO_ERROR;
 }
 
 static status_t writeResourceLoadedCallback(
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index 0f83980..a4f4ba9 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -27,6 +27,8 @@
 sources := \
 	compile/IdAssigner.cpp \
 	compile/Png.cpp \
+	compile/PseudolocaleGenerator.cpp \
+	compile/Pseudolocalizer.cpp \
 	compile/XmlIdCollector.cpp \
 	flatten/Archive.cpp \
 	flatten/TableFlattener.cpp \
@@ -66,6 +68,8 @@
 
 testSources := \
 	compile/IdAssigner_test.cpp \
+	compile/PseudolocaleGenerator_test.cpp \
+	compile/Pseudolocalizer_test.cpp \
 	compile/XmlIdCollector_test.cpp \
 	flatten/FileExportWriter_test.cpp \
 	flatten/TableFlattener_test.cpp \
diff --git a/tools/aapt2/ConfigDescription.cpp b/tools/aapt2/ConfigDescription.cpp
index 64353de..13f8b3b 100644
--- a/tools/aapt2/ConfigDescription.cpp
+++ b/tools/aapt2/ConfigDescription.cpp
@@ -30,6 +30,11 @@
 
 static const char* kWildcardName = "any";
 
+const ConfigDescription& ConfigDescription::defaultConfig() {
+    static ConfigDescription config = {};
+    return config;
+}
+
 static bool parseMcc(const char* name, ResTable_config* out) {
     if (strcmp(name, kWildcardName) == 0) {
         if (out) out->mcc = 0;
diff --git a/tools/aapt2/ConfigDescription.h b/tools/aapt2/ConfigDescription.h
index 4af089d..5749816 100644
--- a/tools/aapt2/ConfigDescription.h
+++ b/tools/aapt2/ConfigDescription.h
@@ -29,6 +29,11 @@
  * initialization and comparison methods.
  */
 struct ConfigDescription : public android::ResTable_config {
+    /**
+     * Returns an immutable default config.
+     */
+    static const ConfigDescription& defaultConfig();
+
     /*
      * Parse a string of the form 'fr-sw600dp-land' and fill in the
      * given ResTable_config with resulting configuration parameters.
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index d864f66..b4e75f9 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -52,13 +52,17 @@
     void visit(Style* style) override {
         std::cout << "(style)";
         if (style->parent) {
+            const Reference& parentRef = style->parent.value();
             std::cout << " parent=";
-            if (style->parent.value().name) {
-                std::cout << style->parent.value().name.value() << " ";
+            if (parentRef.name) {
+                if (parentRef.privateReference) {
+                    std::cout << "*";
+                }
+                std::cout << parentRef.name.value() << " ";
             }
 
-            if (style->parent.value().id) {
-                std::cout << style->parent.value().id.value();
+            if (parentRef.id) {
+                std::cout << parentRef.id.value();
             }
         }
 
@@ -206,4 +210,19 @@
     std::cout << "}" << std::endl;
 }
 
+void Debug::dumpHex(const void* data, size_t len) {
+    const uint8_t* d = (const uint8_t*) data;
+    for (size_t i = 0; i < len; i++) {
+        std::cerr << std::hex << std::setfill('0') << std::setw(2) << (uint32_t) d[i] << " ";
+        if (i % 8 == 7) {
+            std::cerr << "\n";
+        }
+    }
+
+    if (len - 1 % 8 != 7) {
+        std::cerr << std::endl;
+    }
+}
+
+
 } // namespace aapt
diff --git a/tools/aapt2/Debug.h b/tools/aapt2/Debug.h
index 5b0d7d6..ba05be9 100644
--- a/tools/aapt2/Debug.h
+++ b/tools/aapt2/Debug.h
@@ -20,12 +20,16 @@
 #include "Resource.h"
 #include "ResourceTable.h"
 
+// Include for printf-like debugging.
+#include <iostream>
+
 namespace aapt {
 
 struct Debug {
     static void printTable(ResourceTable* table);
     static void printStyleGraph(ResourceTable* table,
                                 const ResourceName& targetStyle);
+    static void dumpHex(const void* data, size_t len);
 };
 
 } // namespace aapt
diff --git a/tools/aapt2/Flags.cpp b/tools/aapt2/Flags.cpp
index 9435396..666e8a8e 100644
--- a/tools/aapt2/Flags.cpp
+++ b/tools/aapt2/Flags.cpp
@@ -81,6 +81,8 @@
 }
 
 void Flags::usage(const StringPiece& command, std::ostream* out) {
+    constexpr size_t kWidth = 50;
+
     *out << command << " [options]";
     for (const Flag& flag : mFlags) {
         if (flag.required) {
@@ -100,11 +102,11 @@
         // the first line) followed by the description line. This will make sure that multiline
         // descriptions are still right justified and aligned.
         for (StringPiece line : util::tokenize<char>(flag.description, '\n')) {
-            *out << " " << std::setw(30) << std::left << argLine << line << "\n";
+            *out << " " << std::setw(kWidth) << std::left << argLine << line << "\n";
             argLine = " ";
         }
     }
-    *out << " " << std::setw(30) << std::left << "-h" << "Displays this help menu\n";
+    *out << " " << std::setw(kWidth) << std::left << "-h" << "Displays this help menu\n";
     out->flush();
 }
 
diff --git a/tools/aapt2/Locale.cpp b/tools/aapt2/Locale.cpp
index 20a2d0c..0369156 100644
--- a/tools/aapt2/Locale.cpp
+++ b/tools/aapt2/Locale.cpp
@@ -96,7 +96,7 @@
          setRegion(part2.c_str());
      } else if (part2.length() == 4 && isAlpha(part2)) {
          setScript(part2.c_str());
-     } else if (part2.length() >= 5 && part2.length() <= 8) {
+     } else if (part2.length() >= 4 && part2.length() <= 8) {
          setVariant(part2.c_str());
      } else {
          valid = false;
@@ -111,7 +111,7 @@
      if (((part3.length() == 2 && isAlpha(part3)) ||
          (part3.length() == 3 && isNumber(part3))) && script[0]) {
          setRegion(part3.c_str());
-     } else if (part3.length() >= 5 && part3.length() <= 8) {
+     } else if (part3.length() >= 4 && part3.length() <= 8) {
          setVariant(part3.c_str());
      } else {
          valid = false;
@@ -122,7 +122,7 @@
      }
 
      const std::string& part4 = parts[3];
-     if (part4.length() >= 5 && part4.length() <= 8) {
+     if (part4.length() >= 4 && part4.length() <= 8) {
          setVariant(part4.c_str());
      } else {
          valid = false;
@@ -141,7 +141,7 @@
 
     std::string& part = *iter;
     if (part[0] == 'b' && part[1] == '+') {
-        // This is a "modified" BCP-47 language tag. Same semantics as BCP-47 tags,
+        // This is a "modified" BCP 47 language tag. Same semantics as BCP 47 tags,
         // except that the separator is "+" and not "-".
         std::vector<std::string> subtags = util::splitAndLowercase(part, '+');
         subtags.erase(subtags.begin());
@@ -157,8 +157,12 @@
                     setRegion(subtags[1].c_str());
                     break;
                 case 4:
-                    setScript(subtags[1].c_str());
-                    break;
+                    if ('0' <= subtags[1][0] && subtags[1][0] <= '9') {
+                        // This is a variant: fall through
+                    } else {
+                        setScript(subtags[1].c_str());
+                        break;
+                    }
                 case 5:
                 case 6:
                 case 7:
@@ -184,7 +188,7 @@
 
             // The third tag can either be a region code (if the second tag was
             // a script), else a variant code.
-            if (subtags[2].size() > 4) {
+            if (subtags[2].size() >= 4) {
                 setVariant(subtags[2].c_str());
             } else {
                 setRegion(subtags[2].c_str());
@@ -249,7 +253,7 @@
 void LocaleValue::initFromResTable(const ResTable_config& config) {
     config.unpackLanguage(language);
     config.unpackRegion(region);
-    if (config.localeScript[0]) {
+    if (config.localeScriptWasProvided) {
         memcpy(script, config.localeScript, sizeof(config.localeScript));
     }
 
@@ -264,6 +268,10 @@
 
     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/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index d4c536f..b37d366 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -19,9 +19,12 @@
 #include "ResourceUtils.h"
 #include "ResourceValues.h"
 #include "ValueVisitor.h"
+#include "util/Comparators.h"
+#include "util/ImmutableMap.h"
 #include "util/Util.h"
 #include "xml/XmlPullParser.h"
 
+#include <functional>
 #include <sstream>
 
 namespace aapt {
@@ -35,6 +38,111 @@
     return ns.empty() && (name == u"skip" || name == u"eat-comment");
 }
 
+static uint32_t parseFormatType(const StringPiece16& piece) {
+    if (piece == u"reference")      return android::ResTable_map::TYPE_REFERENCE;
+    else if (piece == u"string")    return android::ResTable_map::TYPE_STRING;
+    else if (piece == u"integer")   return android::ResTable_map::TYPE_INTEGER;
+    else if (piece == u"boolean")   return android::ResTable_map::TYPE_BOOLEAN;
+    else if (piece == u"color")     return android::ResTable_map::TYPE_COLOR;
+    else if (piece == u"float")     return android::ResTable_map::TYPE_FLOAT;
+    else if (piece == u"dimension") return android::ResTable_map::TYPE_DIMENSION;
+    else if (piece == u"fraction")  return android::ResTable_map::TYPE_FRACTION;
+    else if (piece == u"enum")      return android::ResTable_map::TYPE_ENUM;
+    else if (piece == u"flags")     return android::ResTable_map::TYPE_FLAGS;
+    return 0;
+}
+
+static uint32_t parseFormatAttribute(const StringPiece16& str) {
+    uint32_t mask = 0;
+    for (StringPiece16 part : util::tokenize(str, u'|')) {
+        StringPiece16 trimmedPart = util::trimWhitespace(part);
+        uint32_t type = parseFormatType(trimmedPart);
+        if (type == 0) {
+            return 0;
+        }
+        mask |= type;
+    }
+    return mask;
+}
+
+/**
+ * A parsed resource ready to be added to the ResourceTable.
+ */
+struct ParsedResource {
+    ResourceName name;
+    ConfigDescription config;
+    Source source;
+    ResourceId id;
+    Maybe<SymbolState> symbolState;
+    std::u16string comment;
+    std::unique_ptr<Value> value;
+    std::list<ParsedResource> childResources;
+};
+
+bool ResourceParser::shouldStripResource(const ResourceNameRef& name,
+                                         const Maybe<std::u16string>& product) const {
+    if (product) {
+        for (const std::u16string& productToMatch : mOptions.products) {
+            if (product.value() == productToMatch) {
+                // We specified a product, and it is in the list, so don't strip.
+                return false;
+            }
+        }
+    }
+
+    // Nothing matched, try 'default'. Default only matches if we didn't already use another
+    // product variant.
+    if (!product || product.value() == u"default") {
+        if (Maybe<ResourceTable::SearchResult> result = mTable->findResource(name)) {
+            const ResourceEntry* entry = result.value().entry;
+            auto iter = std::lower_bound(entry->values.begin(), entry->values.end(), mConfig,
+                                         cmp::lessThanConfig);
+            if (iter != entry->values.end() && iter->config == mConfig && !iter->value->isWeak()) {
+                // We have a value for this config already, and it is not weak,
+                // so filter out this default.
+                return true;
+            }
+        }
+        return false;
+    }
+    return true;
+}
+
+// Recursively adds resources to the ResourceTable.
+static bool addResourcesToTable(ResourceTable* table, IDiagnostics* diag, ParsedResource* res) {
+    if (res->symbolState) {
+        Symbol symbol;
+        symbol.state = res->symbolState.value();
+        symbol.source = res->source;
+        symbol.comment = res->comment;
+        if (!table->setSymbolState(res->name, res->id, symbol, diag)) {
+            return false;
+        }
+    }
+
+    if (res->value) {
+        // Attach the comment, source and config to the value.
+        res->value->setComment(std::move(res->comment));
+        res->value->setSource(std::move(res->source));
+
+        if (!table->addResource(res->name, res->id, res->config, std::move(res->value), diag)) {
+            return false;
+        }
+    }
+
+    bool error = false;
+    for (ParsedResource& child : res->childResources) {
+        error |= !addResourcesToTable(table, diag, &child);
+    }
+    return !error;
+}
+
+// Convenient aliases for more readable function calls.
+enum {
+    kAllowRawString = true,
+    kNoRawString = false
+};
+
 ResourceParser::ResourceParser(IDiagnostics* diag, ResourceTable* table, const Source& source,
                                const ConfigDescription& config,
                                const ResourceParserOptions& options) :
@@ -146,69 +254,6 @@
     return !error;
 }
 
-static bool shouldStripResource(const xml::XmlPullParser* parser,
-                                const Maybe<std::u16string> productToMatch) {
-    assert(parser->getEvent() == xml::XmlPullParser::Event::kStartElement);
-
-    if (Maybe<StringPiece16> maybeProduct = xml::findNonEmptyAttribute(parser, u"product")) {
-        if (!productToMatch) {
-            if (maybeProduct.value() != u"default" && maybeProduct.value() != u"phone") {
-                // We didn't specify a product and this is not a default product, so skip.
-                return true;
-            }
-        } else {
-            if (productToMatch && maybeProduct.value() != productToMatch.value()) {
-                // We specified a product, but they don't match.
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
-/**
- * A parsed resource ready to be added to the ResourceTable.
- */
-struct ParsedResource {
-    ResourceName name;
-    Source source;
-    ResourceId id;
-    Maybe<SymbolState> symbolState;
-    std::u16string comment;
-    std::unique_ptr<Value> value;
-    std::list<ParsedResource> childResources;
-};
-
-// Recursively adds resources to the ResourceTable.
-static bool addResourcesToTable(ResourceTable* table, const ConfigDescription& config,
-                                IDiagnostics* diag, ParsedResource* res) {
-    if (res->symbolState) {
-        Symbol symbol;
-        symbol.state = res->symbolState.value();
-        symbol.source = res->source;
-        symbol.comment = res->comment;
-        if (!table->setSymbolState(res->name, res->id, symbol, diag)) {
-            return false;
-        }
-    }
-
-    if (res->value) {
-        // Attach the comment, source and config to the value.
-        res->value->setComment(std::move(res->comment));
-        res->value->setSource(std::move(res->source));
-
-        if (!table->addResource(res->name, res->id, config, std::move(res->value), diag)) {
-            return false;
-        }
-    }
-
-    bool error = false;
-    for (ParsedResource& child : res->childResources) {
-        error |= !addResourcesToTable(table, config, diag, &child);
-    }
-    return !error;
-}
-
 bool ResourceParser::parseResources(xml::XmlPullParser* parser) {
     std::set<ResourceName> strippedResources;
 
@@ -244,118 +289,29 @@
             continue;
         }
 
-        if (elementName == u"item") {
-            // Items simply have their type encoded in the type attribute.
-            if (Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type")) {
-                elementName = maybeType.value().toString();
-            } else {
-                mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber()))
-                             << "<item> must have a 'type' attribute");
-                error = true;
-                continue;
-            }
-        }
-
         ParsedResource parsedResource;
+        parsedResource.config = mConfig;
         parsedResource.source = mSource.withLine(parser->getLineNumber());
         parsedResource.comment = std::move(comment);
 
-        if (Maybe<StringPiece16> maybeName = xml::findNonEmptyAttribute(parser, u"name")) {
-            parsedResource.name.entry = maybeName.value().toString();
+        // Extract the product name if it exists.
+        Maybe<std::u16string> product;
+        if (Maybe<StringPiece16> maybeProduct = xml::findNonEmptyAttribute(parser, u"product")) {
+            product = maybeProduct.value().toString();
+        }
 
-        } else if (elementName != u"public-group") {
-            mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber()))
-                         << "<" << elementName << "> tag must have a 'name' attribute");
+        // Parse the resource regardless of product.
+        if (!parseResource(parser, &parsedResource)) {
             error = true;
             continue;
         }
 
-        // Check if we should skip this product.
-        const bool stripResource = shouldStripResource(parser, mOptions.product);
-
-        bool result = true;
-        if (elementName == u"id") {
-            parsedResource.name.type = ResourceType::kId;
-            parsedResource.value = util::make_unique<Id>();
-        } else if (elementName == u"string") {
-            parsedResource.name.type = ResourceType::kString;
-            result = parseString(parser, &parsedResource);
-        } else if (elementName == u"color") {
-            parsedResource.name.type = ResourceType::kColor;
-            result = parseColor(parser, &parsedResource);
-        } else if (elementName == u"drawable") {
-            parsedResource.name.type = ResourceType::kDrawable;
-            result = parseColor(parser, &parsedResource);
-        } else if (elementName == u"bool") {
-            parsedResource.name.type = ResourceType::kBool;
-            result = parsePrimitive(parser, &parsedResource);
-        } else if (elementName == u"integer") {
-            parsedResource.name.type = ResourceType::kInteger;
-            result = parsePrimitive(parser, &parsedResource);
-        } else if (elementName == u"dimen") {
-            parsedResource.name.type = ResourceType::kDimen;
-            result = parsePrimitive(parser, &parsedResource);
-        } else if (elementName == u"fraction") {
-            parsedResource.name.type = ResourceType::kFraction;
-            result = parsePrimitive(parser, &parsedResource);
-        } else if (elementName == u"style") {
-            parsedResource.name.type = ResourceType::kStyle;
-            result = parseStyle(parser, &parsedResource);
-        } else if (elementName == u"plurals") {
-            parsedResource.name.type = ResourceType::kPlurals;
-            result = parsePlural(parser, &parsedResource);
-        } else if (elementName == u"array") {
-            parsedResource.name.type = ResourceType::kArray;
-            result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_ANY);
-        } else if (elementName == u"string-array") {
-            parsedResource.name.type = ResourceType::kArray;
-            result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_STRING);
-        } else if (elementName == u"integer-array") {
-            parsedResource.name.type = ResourceType::kArray;
-            result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_INTEGER);
-        } else if (elementName == u"declare-styleable") {
-            parsedResource.name.type = ResourceType::kStyleable;
-            result = parseDeclareStyleable(parser, &parsedResource);
-        } else if (elementName == u"attr") {
-            parsedResource.name.type = ResourceType::kAttr;
-            result = parseAttr(parser, &parsedResource);
-        } else if (elementName == u"public") {
-            result = parsePublic(parser, &parsedResource);
-        } else if (elementName == u"java-symbol" || elementName == u"symbol") {
-            result = parseSymbol(parser, &parsedResource);
-        } else if (elementName == u"public-group") {
-            result = parsePublicGroup(parser, &parsedResource);
-        } else if (elementName == u"add-resource") {
-            result = parseAddResource(parser, &parsedResource);
-        } else {
-            // Try parsing the elementName (or type) as a resource. These shall only be
-            // resources like 'layout' or 'xml' and they can only be references.
-            if (const ResourceType* type = parseResourceType(elementName)) {
-                parsedResource.name.type = *type;
-                parsedResource.value = parseXml(parser, android::ResTable_map::TYPE_REFERENCE,
-                                                false);
-                if (!parsedResource.value) {
-                    mDiag->error(DiagMessage(parsedResource.source) << "invalid value for type '"
-                                 << *type << "'. Expected a reference");
-                    result = false;
-                }
-            } else {
-                mDiag->warn(DiagMessage(mSource.withLine(parser->getLineNumber()))
-                            << "unknown resource type '" << elementName << "'");
-            }
-        }
-
-        if (result) {
-            // We successfully parsed the resource.
-
-            if (stripResource) {
-                // Record that we stripped out this resource name.
-                // We will check that at least one variant of this resource was included.
-                strippedResources.insert(parsedResource.name);
-            } else {
-                error |= !addResourcesToTable(mTable, mConfig, mDiag, &parsedResource);
-            }
-        } else {
+        // We successfully parsed the resource. Check if we should include it or strip it.
+        if (shouldStripResource(parsedResource.name, product)) {
+            // Record that we stripped out this resource name.
+            // We will check that at least one variant of this resource was included.
+            strippedResources.insert(parsedResource.name);
+        } else if (!addResourcesToTable(mTable, mDiag, &parsedResource)) {
             error = true;
         }
     }
@@ -373,10 +329,173 @@
     return !error;
 }
 
-enum {
-    kAllowRawString = true,
-    kNoRawString = false
-};
+
+bool ResourceParser::parseResource(xml::XmlPullParser* parser, ParsedResource* outResource) {
+    struct ItemTypeFormat {
+        ResourceType type;
+        uint32_t format;
+    };
+
+    using BagParseFunc = std::function<bool(ResourceParser*, xml::XmlPullParser*, ParsedResource*)>;
+
+    static const auto elToItemMap = ImmutableMap<std::u16string, ItemTypeFormat>::createPreSorted({
+            { u"bool",      { ResourceType::kBool, android::ResTable_map::TYPE_BOOLEAN } },
+            { u"color",     { ResourceType::kColor, android::ResTable_map::TYPE_COLOR } },
+            { u"dimen",     { ResourceType::kDimen, android::ResTable_map::TYPE_FLOAT
+                                                    | android::ResTable_map::TYPE_FRACTION
+                                                    | android::ResTable_map::TYPE_DIMENSION } },
+            { u"drawable",  { ResourceType::kDrawable, android::ResTable_map::TYPE_COLOR } },
+            { u"fraction",  { ResourceType::kFraction, android::ResTable_map::TYPE_FLOAT
+                                                       | android::ResTable_map::TYPE_FRACTION
+                                                       | android::ResTable_map::TYPE_DIMENSION } },
+            { u"integer",   { ResourceType::kInteger, android::ResTable_map::TYPE_INTEGER } },
+            { u"string",    { ResourceType::kString, android::ResTable_map::TYPE_STRING } },
+    });
+
+    static const auto elToBagMap = ImmutableMap<std::u16string, BagParseFunc>::createPreSorted({
+            { u"add-resource",      std::mem_fn(&ResourceParser::parseAddResource) },
+            { u"array",             std::mem_fn(&ResourceParser::parseArray) },
+            { u"attr",              std::mem_fn(&ResourceParser::parseAttr) },
+            { u"declare-styleable", std::mem_fn(&ResourceParser::parseDeclareStyleable) },
+            { u"integer-array",     std::mem_fn(&ResourceParser::parseIntegerArray) },
+            { u"java-symbol",       std::mem_fn(&ResourceParser::parseSymbol) },
+            { u"plurals",           std::mem_fn(&ResourceParser::parsePlural) },
+            { u"public",            std::mem_fn(&ResourceParser::parsePublic) },
+            { u"public-group",      std::mem_fn(&ResourceParser::parsePublicGroup) },
+            { u"string-array",      std::mem_fn(&ResourceParser::parseStringArray) },
+            { u"style",             std::mem_fn(&ResourceParser::parseStyle) },
+            { u"symbol",            std::mem_fn(&ResourceParser::parseSymbol) },
+    });
+
+    std::u16string resourceType = parser->getElementName();
+
+    // The value format accepted for this resource.
+    uint32_t resourceFormat = 0u;
+
+    if (resourceType == u"item") {
+        // Items have their type encoded in the type attribute.
+        if (Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type")) {
+            resourceType = maybeType.value().toString();
+        } else {
+            mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber()))
+                         << "<item> must have a 'type' attribute");
+            return false;
+        }
+
+        if (Maybe<StringPiece16> maybeFormat = xml::findNonEmptyAttribute(parser, u"format")) {
+            // An explicit format for this resource was specified. The resource will retain
+            // its type in its name, but the accepted value for this type is overridden.
+            resourceFormat = parseFormatType(maybeFormat.value());
+            if (!resourceFormat) {
+                mDiag->error(DiagMessage(outResource->source)
+                             << "'" << maybeFormat.value() << "' is an invalid format");
+                return false;
+            }
+        }
+    }
+
+    // Get the name of the resource. This will be checked later, because not all
+    // XML elements require a name.
+    Maybe<StringPiece16> maybeName = xml::findNonEmptyAttribute(parser, u"name");
+
+    if (resourceType == u"id") {
+        if (!maybeName) {
+            mDiag->error(DiagMessage(outResource->source)
+                         << "<" << parser->getElementName() << "> missing 'name' attribute");
+            return false;
+        }
+
+        outResource->name.type = ResourceType::kId;
+        outResource->name.entry = maybeName.value().toString();
+        outResource->value = util::make_unique<Id>();
+        return true;
+    }
+
+    const auto itemIter = elToItemMap.find(resourceType);
+    if (itemIter != elToItemMap.end()) {
+        // This is an item, record its type and format and start parsing.
+
+        if (!maybeName) {
+            mDiag->error(DiagMessage(outResource->source)
+                         << "<" << parser->getElementName() << "> missing 'name' attribute");
+            return false;
+        }
+
+        outResource->name.type = itemIter->second.type;
+        outResource->name.entry = maybeName.value().toString();
+
+        // Only use the implicit format for this type if it wasn't overridden.
+        if (!resourceFormat) {
+            resourceFormat = itemIter->second.format;
+        }
+
+        if (!parseItem(parser, outResource, resourceFormat)) {
+            return false;
+        }
+        return true;
+    }
+
+    // This might be a bag or something.
+    const auto bagIter = elToBagMap.find(resourceType);
+    if (bagIter != elToBagMap.end()) {
+        // Ensure we have a name (unless this is a <public-group>).
+        if (resourceType != u"public-group") {
+            if (!maybeName) {
+                mDiag->error(DiagMessage(outResource->source)
+                             << "<" << parser->getElementName() << "> missing 'name' attribute");
+                return false;
+            }
+
+            outResource->name.entry = maybeName.value().toString();
+        }
+
+        // Call the associated parse method. The type will be filled in by the
+        // parse func.
+        if (!bagIter->second(this, parser, outResource)) {
+            return false;
+        }
+        return true;
+    }
+
+    // Try parsing the elementName (or type) as a resource. These shall only be
+    // resources like 'layout' or 'xml' and they can only be references.
+    const ResourceType* parsedType = parseResourceType(resourceType);
+    if (parsedType) {
+        if (!maybeName) {
+            mDiag->error(DiagMessage(outResource->source)
+                         << "<" << parser->getElementName() << "> missing 'name' attribute");
+            return false;
+        }
+
+        outResource->name.type = *parsedType;
+        outResource->name.entry = maybeName.value().toString();
+        outResource->value = parseXml(parser, android::ResTable_map::TYPE_REFERENCE, kNoRawString);
+        if (!outResource->value) {
+            mDiag->error(DiagMessage(outResource->source)
+                         << "invalid value for type '" << *parsedType << "'. Expected a reference");
+            return false;
+        }
+        return true;
+    }
+
+    mDiag->warn(DiagMessage(outResource->source)
+                << "unknown resource type '" << parser->getElementName() << "'");
+    return false;
+}
+
+bool ResourceParser::parseItem(xml::XmlPullParser* parser, ParsedResource* outResource,
+                               const uint32_t format) {
+    if (format == android::ResTable_map::TYPE_STRING) {
+        return parseString(parser, outResource);
+    }
+
+    outResource->value = parseXml(parser, format, kNoRawString);
+    if (!outResource->value) {
+        mDiag->error(DiagMessage(outResource->source) << "invalid " << outResource->name.type);
+        return false;
+    }
+    return true;
+}
 
 /**
  * Reads the entire XML subtree and attempts to parse it as some Item,
@@ -431,17 +550,15 @@
         return util::make_unique<RawString>(
                 mTable->stringPool.makeRef(rawValue, StringPool::Context{ 1, mConfig }));
     }
-
     return {};
 }
 
 bool ResourceParser::parseString(xml::XmlPullParser* parser, ParsedResource* outResource) {
-    const Source source = mSource.withLine(parser->getLineNumber());
-
     bool formatted = true;
     if (Maybe<StringPiece16> formattedAttr = xml::findAttribute(parser, u"formatted")) {
         if (!ResourceUtils::tryParseBool(formattedAttr.value(), &formatted)) {
-            mDiag->error(DiagMessage(source) << "invalid value for 'formatted'. Must be a boolean");
+            mDiag->error(DiagMessage(outResource->source)
+                         << "invalid value for 'formatted'. Must be a boolean");
             return false;
         }
     }
@@ -449,7 +566,7 @@
     bool translateable = mOptions.translatable;
     if (Maybe<StringPiece16> translateableAttr = xml::findAttribute(parser, u"translatable")) {
         if (!ResourceUtils::tryParseBool(translateableAttr.value(), &translateable)) {
-            mDiag->error(DiagMessage(source)
+            mDiag->error(DiagMessage(outResource->source)
                          << "invalid value for 'translatable'. Must be a boolean");
             return false;
         }
@@ -457,81 +574,44 @@
 
     outResource->value = parseXml(parser, android::ResTable_map::TYPE_STRING, kNoRawString);
     if (!outResource->value) {
-        mDiag->error(DiagMessage(source) << "not a valid string");
+        mDiag->error(DiagMessage(outResource->source) << "not a valid string");
         return false;
     }
 
-    if (formatted && translateable) {
-        if (String* stringValue = valueCast<String>(outResource->value.get())) {
+    if (String* stringValue = valueCast<String>(outResource->value.get())) {
+        stringValue->setTranslateable(translateable);
+
+        if (formatted && translateable) {
             if (!util::verifyJavaStringFormat(*stringValue->value)) {
-                mDiag->error(DiagMessage(source)
-                             << "multiple substitutions specified in non-positional format; "
-                                "did you mean to add the formatted=\"false\" attribute?");
-                return false;
+                DiagMessage msg(outResource->source);
+                msg << "multiple substitutions specified in non-positional format; "
+                       "did you mean to add the formatted=\"false\" attribute?";
+                if (mOptions.errorOnPositionalArguments) {
+                    mDiag->error(msg);
+                    return false;
+                }
+
+                mDiag->warn(msg);
             }
         }
-    }
-    return true;
-}
 
-bool ResourceParser::parseColor(xml::XmlPullParser* parser, ParsedResource* outResource) {
-    const Source source = mSource.withLine(parser->getLineNumber());
-
-    outResource->value = parseXml(parser, android::ResTable_map::TYPE_COLOR, kNoRawString);
-    if (!outResource->value) {
-        mDiag->error(DiagMessage(source) << "invalid color");
-        return false;
-    }
-    return true;
-}
-
-bool ResourceParser::parsePrimitive(xml::XmlPullParser* parser, ParsedResource* outResource) {
-    const Source source = mSource.withLine(parser->getLineNumber());
-
-    uint32_t typeMask = 0;
-    switch (outResource->name.type) {
-    case ResourceType::kInteger:
-        typeMask |= android::ResTable_map::TYPE_INTEGER;
-        break;
-
-    case ResourceType::kFraction:
-        // fallthrough
-    case ResourceType::kDimen:
-        typeMask |= android::ResTable_map::TYPE_DIMENSION
-                  | android::ResTable_map::TYPE_FLOAT
-                  | android::ResTable_map::TYPE_FRACTION;
-        break;
-
-    case ResourceType::kBool:
-        typeMask |= android::ResTable_map::TYPE_BOOLEAN;
-        break;
-
-    default:
-        assert(false);
-        break;
-    }
-
-    outResource->value = parseXml(parser, typeMask, kNoRawString);
-    if (!outResource->value) {
-        mDiag->error(DiagMessage(source) << "invalid " << outResource->name.type);
-        return false;
+    } else if (StyledString* stringValue = valueCast<StyledString>(outResource->value.get())) {
+        stringValue->setTranslateable(translateable);
     }
     return true;
 }
 
 bool ResourceParser::parsePublic(xml::XmlPullParser* parser, ParsedResource* outResource) {
-    const Source source = mSource.withLine(parser->getLineNumber());
-
     Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type");
     if (!maybeType) {
-        mDiag->error(DiagMessage(source) << "<public> must have a 'type' attribute");
+        mDiag->error(DiagMessage(outResource->source) << "<public> must have a 'type' attribute");
         return false;
     }
 
     const ResourceType* parsedType = parseResourceType(maybeType.value());
     if (!parsedType) {
-        mDiag->error(DiagMessage(source) << "invalid resource type '" << maybeType.value()
-                     << "' in <public>");
+        mDiag->error(DiagMessage(outResource->source)
+                     << "invalid resource type '" << maybeType.value() << "' in <public>");
         return false;
     }
 
@@ -543,8 +623,8 @@
                                                      maybeId.value().size(), &val);
         ResourceId resourceId(val.data);
         if (!result || !resourceId.isValid()) {
-            mDiag->error(DiagMessage(source) << "invalid resource ID '" << maybeId.value()
-                         << "' in <public>");
+            mDiag->error(DiagMessage(outResource->source)
+                         << "invalid resource ID '" << maybeId.value() << "' in <public>");
             return false;
         }
         outResource->id = resourceId;
@@ -560,24 +640,24 @@
 }
 
 bool ResourceParser::parsePublicGroup(xml::XmlPullParser* parser, ParsedResource* outResource) {
-    const Source source = mSource.withLine(parser->getLineNumber());
-
     Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type");
     if (!maybeType) {
-        mDiag->error(DiagMessage(source) << "<public-group> must have a 'type' attribute");
+        mDiag->error(DiagMessage(outResource->source)
+                     << "<public-group> must have a 'type' attribute");
         return false;
     }
 
     const ResourceType* parsedType = parseResourceType(maybeType.value());
     if (!parsedType) {
-        mDiag->error(DiagMessage(source) << "invalid resource type '" << maybeType.value()
-                     << "' in <public-group>");
+        mDiag->error(DiagMessage(outResource->source)
+                     << "invalid resource type '" << maybeType.value() << "' in <public-group>");
         return false;
     }
 
     Maybe<StringPiece16> maybeId = xml::findNonEmptyAttribute(parser, u"first-id");
     if (!maybeId) {
-        mDiag->error(DiagMessage(source) << "<public-group> must have a 'first-id' attribute");
+        mDiag->error(DiagMessage(outResource->source)
+                     << "<public-group> must have a 'first-id' attribute");
         return false;
     }
 
@@ -586,8 +666,8 @@
                                                  maybeId.value().size(), &val);
     ResourceId nextId(val.data);
     if (!result || !nextId.isValid()) {
-        mDiag->error(DiagMessage(source) << "invalid resource ID '" << maybeId.value()
-                     << "' in <public-group>");
+        mDiag->error(DiagMessage(outResource->source)
+                     << "invalid resource ID '" << maybeId.value() << "' in <public-group>");
         return false;
     }
 
@@ -646,18 +726,17 @@
 }
 
 bool ResourceParser::parseSymbolImpl(xml::XmlPullParser* parser, ParsedResource* outResource) {
-    const Source source = mSource.withLine(parser->getLineNumber());
-
     Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type");
     if (!maybeType) {
-        mDiag->error(DiagMessage(source) << "<" << parser->getElementName() << "> must have a "
-                     "'type' attribute");
+        mDiag->error(DiagMessage(outResource->source)
+                     << "<" << parser->getElementName() << "> must have a 'type' attribute");
         return false;
     }
 
     const ResourceType* parsedType = parseResourceType(maybeType.value());
     if (!parsedType) {
-        mDiag->error(DiagMessage(source) << "invalid resource type '" << maybeType.value()
+        mDiag->error(DiagMessage(outResource->source)
+                     << "invalid resource type '" << maybeType.value()
                      << "' in <" << parser->getElementName() << ">");
         return false;
     }
@@ -682,40 +761,22 @@
     return false;
 }
 
-static uint32_t parseFormatType(const StringPiece16& piece) {
-    if (piece == u"reference")      return android::ResTable_map::TYPE_REFERENCE;
-    else if (piece == u"string")    return android::ResTable_map::TYPE_STRING;
-    else if (piece == u"integer")   return android::ResTable_map::TYPE_INTEGER;
-    else if (piece == u"boolean")   return android::ResTable_map::TYPE_BOOLEAN;
-    else if (piece == u"color")     return android::ResTable_map::TYPE_COLOR;
-    else if (piece == u"float")     return android::ResTable_map::TYPE_FLOAT;
-    else if (piece == u"dimension") return android::ResTable_map::TYPE_DIMENSION;
-    else if (piece == u"fraction")  return android::ResTable_map::TYPE_FRACTION;
-    else if (piece == u"enum")      return android::ResTable_map::TYPE_ENUM;
-    else if (piece == u"flags")     return android::ResTable_map::TYPE_FLAGS;
-    return 0;
-}
-
-static uint32_t parseFormatAttribute(const StringPiece16& str) {
-    uint32_t mask = 0;
-    for (StringPiece16 part : util::tokenize(str, u'|')) {
-        StringPiece16 trimmedPart = util::trimWhitespace(part);
-        uint32_t type = parseFormatType(trimmedPart);
-        if (type == 0) {
-            return 0;
-        }
-        mask |= type;
-    }
-    return mask;
-}
 
 bool ResourceParser::parseAttr(xml::XmlPullParser* parser, ParsedResource* outResource) {
-    outResource->source = mSource.withLine(parser->getLineNumber());
     return parseAttrImpl(parser, outResource, false);
 }
 
 bool ResourceParser::parseAttrImpl(xml::XmlPullParser* parser, ParsedResource* outResource,
                                    bool weak) {
+    outResource->name.type = ResourceType::kAttr;
+
+    // Attributes only end up in default configuration.
+    if (outResource->config != ConfigDescription::defaultConfig()) {
+        mDiag->warn(DiagMessage(outResource->source) << "ignoring configuration '"
+                    << outResource->config << "' for attribute " << outResource->name);
+        outResource->config = ConfigDescription::defaultConfig();
+    }
+
     uint32_t typeMask = 0;
 
     Maybe<StringPiece16> maybeFormat = xml::findAttribute(parser, u"format");
@@ -887,8 +948,7 @@
     }
 
     return Attribute::Symbol{
-            Reference(ResourceNameRef({}, ResourceType::kId, maybeName.value())),
-            val.data };
+            Reference(ResourceNameRef({}, ResourceType::kId, maybeName.value())), val.data };
 }
 
 static Maybe<Reference> parseXmlAttributeName(StringPiece16 str) {
@@ -949,7 +1009,8 @@
 }
 
 bool ResourceParser::parseStyle(xml::XmlPullParser* parser, ParsedResource* outResource) {
-    const Source source = mSource.withLine(parser->getLineNumber());
+    outResource->name.type = ResourceType::kStyle;
+
     std::unique_ptr<Style> style = util::make_unique<Style>();
 
     Maybe<StringPiece16> maybeParent = xml::findAttribute(parser, u"parent");
@@ -959,7 +1020,7 @@
             std::string errStr;
             style->parent = ResourceUtils::parseStyleParentReference(maybeParent.value(), &errStr);
             if (!style->parent) {
-                mDiag->error(DiagMessage(source) << errStr);
+                mDiag->error(DiagMessage(outResource->source) << errStr);
                 return false;
             }
 
@@ -1007,9 +1068,22 @@
     return true;
 }
 
-bool ResourceParser::parseArray(xml::XmlPullParser* parser, ParsedResource* outResource,
-                                uint32_t typeMask) {
-    const Source source = mSource.withLine(parser->getLineNumber());
+bool ResourceParser::parseArray(xml::XmlPullParser* parser, ParsedResource* outResource) {
+    return parseArrayImpl(parser, outResource, android::ResTable_map::TYPE_ANY);
+}
+
+bool ResourceParser::parseIntegerArray(xml::XmlPullParser* parser, ParsedResource* outResource) {
+    return parseArrayImpl(parser, outResource, android::ResTable_map::TYPE_INTEGER);
+}
+
+bool ResourceParser::parseStringArray(xml::XmlPullParser* parser, ParsedResource* outResource) {
+    return parseArrayImpl(parser, outResource, android::ResTable_map::TYPE_STRING);
+}
+
+bool ResourceParser::parseArrayImpl(xml::XmlPullParser* parser, ParsedResource* outResource,
+                                    const uint32_t typeMask) {
+    outResource->name.type = ResourceType::kArray;
+
     std::unique_ptr<Array> array = util::make_unique<Array>();
 
     bool error = false;
@@ -1049,7 +1123,8 @@
 }
 
 bool ResourceParser::parsePlural(xml::XmlPullParser* parser, ParsedResource* outResource) {
-    const Source source = mSource.withLine(parser->getLineNumber());
+    outResource->name.type = ResourceType::kPlurals;
+
     std::unique_ptr<Plural> plural = util::make_unique<Plural>();
 
     bool error = false;
@@ -1122,13 +1197,23 @@
     return true;
 }
 
-bool ResourceParser::parseDeclareStyleable(xml::XmlPullParser* parser, ParsedResource* outResource) {
-    const Source source = mSource.withLine(parser->getLineNumber());
-    std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
+bool ResourceParser::parseDeclareStyleable(xml::XmlPullParser* parser,
+                                           ParsedResource* outResource) {
+    outResource->name.type = ResourceType::kStyleable;
 
     // Declare-styleable is kPrivate by default, because it technically only exists in R.java.
     outResource->symbolState = SymbolState::kPublic;
 
+    // Declare-styleable only ends up in default config;
+    if (outResource->config != ConfigDescription::defaultConfig()) {
+        mDiag->warn(DiagMessage(outResource->source) << "ignoring configuration '"
+                            << outResource->config << "' for styleable "
+                            << outResource->name.entry);
+        outResource->config = ConfigDescription::defaultConfig();
+    }
+
+    std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
+
     std::u16string comment;
     bool error = false;
     const size_t depth = parser->getDepth();
diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h
index 04db577..51cbbe1 100644
--- a/tools/aapt2/ResourceParser.h
+++ b/tools/aapt2/ResourceParser.h
@@ -34,16 +34,21 @@
 
 struct ResourceParserOptions {
     /**
-     * Optional product name by which to filter resources.
+     * Optional product names by which to filter resources.
      * This is like a preprocessor definition in that we strip out resources
      * that don't match before we compile them.
      */
-    Maybe<std::u16string> product;
+    std::vector<std::u16string> products;
 
     /**
      * Whether the default setting for this parser is to allow translation.
      */
     bool translatable = true;
+
+    /**
+     * Whether positional arguments in formatted strings are treated as errors or warnings.
+     */
+    bool errorOnPositionalArguments = true;
 };
 
 /*
@@ -78,9 +83,11 @@
                                    const bool allowRawValue);
 
     bool parseResources(xml::XmlPullParser* parser);
+    bool parseResource(xml::XmlPullParser* parser, ParsedResource* outResource);
+
+    bool parseItem(xml::XmlPullParser* parser, ParsedResource* outResource, uint32_t format);
     bool parseString(xml::XmlPullParser* parser, ParsedResource* outResource);
-    bool parseColor(xml::XmlPullParser* parser, ParsedResource* outResource);
-    bool parsePrimitive(xml::XmlPullParser* parser, ParsedResource* outResource);
+
     bool parsePublic(xml::XmlPullParser* parser, ParsedResource* outResource);
     bool parsePublicGroup(xml::XmlPullParser* parser, ParsedResource* outResource);
     bool parseSymbolImpl(xml::XmlPullParser* parser, ParsedResource* outResource);
@@ -93,9 +100,15 @@
     bool parseStyle(xml::XmlPullParser* parser, ParsedResource* outResource);
     bool parseStyleItem(xml::XmlPullParser* parser, Style* style);
     bool parseDeclareStyleable(xml::XmlPullParser* parser, ParsedResource* outResource);
-    bool parseArray(xml::XmlPullParser* parser, ParsedResource* outResource, uint32_t typeMask);
+    bool parseArray(xml::XmlPullParser* parser, ParsedResource* outResource);
+    bool parseIntegerArray(xml::XmlPullParser* parser, ParsedResource* outResource);
+    bool parseStringArray(xml::XmlPullParser* parser, ParsedResource* outResource);
+    bool parseArrayImpl(xml::XmlPullParser* parser, ParsedResource* outResource, uint32_t typeMask);
     bool parsePlural(xml::XmlPullParser* parser, ParsedResource* outResource);
 
+    bool shouldStripResource(const ResourceNameRef& name,
+                             const Maybe<std::u16string>& product) const;
+
     IDiagnostics* mDiag;
     ResourceTable* mTable;
     Source mSource;
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 84f67c6..cf0fcd1 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -47,13 +47,26 @@
         mContext = test::ContextBuilder().build();
     }
 
+    ::testing::AssertionResult testParse(const StringPiece& str) {
+        return testParse(str, ConfigDescription{}, {});
+    }
+
+    ::testing::AssertionResult testParse(const StringPiece& str, const ConfigDescription& config) {
+        return testParse(str, config, {});
+    }
+
     ::testing::AssertionResult testParse(const StringPiece& str,
-                                         Maybe<std::u16string> product = {}) {
+                                         std::initializer_list<std::u16string> products) {
+        return testParse(str, {}, std::move(products));
+    }
+
+    ::testing::AssertionResult testParse(const StringPiece& str, const ConfigDescription& config,
+                                         std::initializer_list<std::u16string> products) {
         std::stringstream input(kXmlPreamble);
         input << "<resources>\n" << str << "\n</resources>" << std::endl;
         ResourceParserOptions parserOptions;
-        parserOptions.product = product;
-        ResourceParser parser(mContext->getDiagnostics(), &mTable, Source{ "test" }, {},
+        parserOptions.products = products;
+        ResourceParser parser(mContext->getDiagnostics(), &mTable, Source{ "test" }, config,
                               parserOptions);
         xml::XmlPullParser xmlParser(input);
         if (parser.parse(&xmlParser)) {
@@ -138,6 +151,26 @@
     EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_ANY), attr->typeMask);
 }
 
+// Old AAPT allowed attributes to be defined under different configurations, but ultimately
+// stored them with the default configuration. Check that we have the same behavior.
+TEST_F(ResourceParserTest, ParseAttrAndDeclareStyleableUnderConfigButRecordAsNoConfig) {
+    const ConfigDescription watchConfig = test::parseConfigOrDie("watch");
+    std::string input = R"EOF(
+        <attr name="foo" />
+        <declare-styleable name="bar">
+          <attr name="baz" />
+        </declare-styleable>)EOF";
+    ASSERT_TRUE(testParse(input, watchConfig));
+
+    EXPECT_EQ(nullptr, test::getValueForConfig<Attribute>(&mTable, u"@attr/foo", watchConfig));
+    EXPECT_EQ(nullptr, test::getValueForConfig<Attribute>(&mTable, u"@attr/baz", watchConfig));
+    EXPECT_EQ(nullptr, test::getValueForConfig<Styleable>(&mTable, u"@styleable/bar", watchConfig));
+
+    EXPECT_NE(nullptr, test::getValue<Attribute>(&mTable, u"@attr/foo"));
+    EXPECT_NE(nullptr, test::getValue<Attribute>(&mTable, u"@attr/baz"));
+    EXPECT_NE(nullptr, test::getValue<Styleable>(&mTable, u"@styleable/bar"));
+}
+
 TEST_F(ResourceParserTest, ParseAttrWithMinMax) {
     std::string input = "<attr name=\"foo\" min=\"10\" max=\"23\" format=\"integer\"/>";
     ASSERT_TRUE(testParse(input));
@@ -215,7 +248,7 @@
     ASSERT_TRUE(testParse(input));
 
     Attribute* flagAttr = test::getValue<Attribute>(&mTable, u"@attr/foo");
-    ASSERT_NE(flagAttr, nullptr);
+    ASSERT_NE(nullptr, flagAttr);
     EXPECT_EQ(flagAttr->typeMask, android::ResTable_map::TYPE_FLAGS);
     ASSERT_EQ(flagAttr->symbols.size(), 3u);
 
@@ -233,7 +266,7 @@
 
     std::unique_ptr<BinaryPrimitive> flagValue = ResourceUtils::tryParseFlagSymbol(flagAttr,
                                                                                    u"baz|bat");
-    ASSERT_NE(flagValue, nullptr);
+    ASSERT_NE(nullptr, flagValue);
     EXPECT_EQ(flagValue->value.data, 1u | 2u);
 }
 
@@ -255,7 +288,7 @@
     ASSERT_TRUE(testParse(input));
 
     Style* style = test::getValue<Style>(&mTable, u"@style/foo");
-    ASSERT_NE(style, nullptr);
+    ASSERT_NE(nullptr, style);
     AAPT_ASSERT_TRUE(style->parent);
     AAPT_ASSERT_TRUE(style->parent.value().name);
     EXPECT_EQ(test::parseNameOrDie(u"@style/fu"), style->parent.value().name.value());
@@ -276,7 +309,7 @@
     ASSERT_TRUE(testParse(input));
 
     Style* style = test::getValue<Style>(&mTable, u"@style/foo");
-    ASSERT_NE(style, nullptr);
+    ASSERT_NE(nullptr, style);
     AAPT_ASSERT_TRUE(style->parent);
     AAPT_ASSERT_TRUE(style->parent.value().name);
     EXPECT_EQ(test::parseNameOrDie(u"@com.app:style/Theme"), style->parent.value().name.value());
@@ -288,7 +321,7 @@
     ASSERT_TRUE(testParse(input));
 
     Style* style = test::getValue<Style>(&mTable, u"@style/foo");
-    ASSERT_NE(style, nullptr);
+    ASSERT_NE(nullptr, style);
     AAPT_ASSERT_TRUE(style->parent);
     AAPT_ASSERT_TRUE(style->parent.value().name);
     EXPECT_EQ(test::parseNameOrDie(u"@android:style/Theme"), style->parent.value().name.value());
@@ -302,7 +335,7 @@
     ASSERT_TRUE(testParse(input));
 
     Style* style = test::getValue<Style>(&mTable, u"@style/foo");
-    ASSERT_NE(style, nullptr);
+    ASSERT_NE(nullptr, style);
     ASSERT_EQ(1u, style->entries.size());
     EXPECT_EQ(test::parseNameOrDie(u"@android:attr/bar"), style->entries[0].key.name.value());
 }
@@ -312,7 +345,7 @@
     ASSERT_TRUE(testParse(input));
 
     Style* style = test::getValue<Style>(&mTable, u"@style/foo.bar");
-    ASSERT_NE(style, nullptr);
+    ASSERT_NE(nullptr, style);
     AAPT_ASSERT_TRUE(style->parent);
     AAPT_ASSERT_TRUE(style->parent.value().name);
     EXPECT_EQ(style->parent.value().name.value(), test::parseNameOrDie(u"@style/foo"));
@@ -324,11 +357,21 @@
     ASSERT_TRUE(testParse(input));
 
     Style* style = test::getValue<Style>(&mTable, u"@style/foo.bar");
-    ASSERT_NE(style, nullptr);
+    ASSERT_NE(nullptr, style);
     AAPT_EXPECT_FALSE(style->parent);
     EXPECT_FALSE(style->parentInferred);
 }
 
+TEST_F(ResourceParserTest, ParseStyleWithPrivateParentReference) {
+    std::string input = R"EOF(<style name="foo" parent="*android:style/bar" />)EOF";
+    ASSERT_TRUE(testParse(input));
+
+    Style* style = test::getValue<Style>(&mTable, u"@style/foo");
+    ASSERT_NE(nullptr, style);
+    AAPT_ASSERT_TRUE(style->parent);
+    EXPECT_TRUE(style->parent.value().privateReference);
+}
+
 TEST_F(ResourceParserTest, ParseAutoGeneratedIdReference) {
     std::string input = "<string name=\"foo\">@+id/bar</string>";
     ASSERT_TRUE(testParse(input));
@@ -504,11 +547,15 @@
 }
 
 TEST_F(ResourceParserTest, FilterProductsThatDontMatch) {
-    std::string input = "<string name=\"foo\" product=\"phone\">hi</string>\n"
-                        "<string name=\"foo\" product=\"no-sdcard\">ho</string>\n"
-                        "<string name=\"bar\" product=\"\">wee</string>\n"
-                        "<string name=\"baz\">woo</string>\n";
-    ASSERT_TRUE(testParse(input, std::u16string(u"no-sdcard")));
+    std::string input = R"EOF(
+        <string name="foo" product="phone">hi</string>
+        <string name="foo" product="no-sdcard">ho</string>
+        <string name="bar" product="">wee</string>
+        <string name="baz">woo</string>
+        <string name="bit" product="phablet">hoot</string>
+        <string name="bot" product="default">yes</string>
+    )EOF";
+    ASSERT_TRUE(testParse(input, { std::u16string(u"no-sdcard"), std::u16string(u"phablet") }));
 
     String* fooStr = test::getValue<String>(&mTable, u"@string/foo");
     ASSERT_NE(nullptr, fooStr);
@@ -516,11 +563,25 @@
 
     EXPECT_NE(nullptr, test::getValue<String>(&mTable, u"@string/bar"));
     EXPECT_NE(nullptr, test::getValue<String>(&mTable, u"@string/baz"));
+    EXPECT_NE(nullptr, test::getValue<String>(&mTable, u"@string/bit"));
+    EXPECT_NE(nullptr, test::getValue<String>(&mTable, u"@string/bot"));
+}
+
+TEST_F(ResourceParserTest, FilterProductsThatBothMatchInOrder) {
+    std::string input = R"EOF(
+        <string name="foo" product="phone">phone</string>
+        <string name="foo" product="default">default</string>
+    )EOF";
+    ASSERT_TRUE(testParse(input, { std::u16string(u"phone") }));
+
+    String* foo = test::getValue<String>(&mTable, u"@string/foo");
+    ASSERT_NE(nullptr, foo);
+    EXPECT_EQ(std::u16string(u"phone"), *foo->value);
 }
 
 TEST_F(ResourceParserTest, FailWhenProductFilterStripsOutAllVersionsOfResource) {
     std::string input = "<string name=\"foo\" product=\"tablet\">hello</string>\n";
-    ASSERT_FALSE(testParse(input, std::u16string(u"phone")));
+    ASSERT_FALSE(testParse(input, { std::u16string(u"phone") }));
 }
 
 TEST_F(ResourceParserTest, AutoIncrementIdsInPublicGroup) {
@@ -575,4 +636,14 @@
     EXPECT_EQ(SymbolState::kUndefined, entry->symbolStatus.state);
 }
 
+TEST_F(ResourceParserTest, ParseItemElementWithFormat) {
+    std::string input = R"EOF(<item name="foo" type="integer" format="float">0.3</item>)EOF";
+    ASSERT_TRUE(testParse(input));
+
+    BinaryPrimitive* val = test::getValue<BinaryPrimitive>(&mTable, u"@integer/foo");
+    ASSERT_NE(nullptr, val);
+
+    EXPECT_EQ(uint32_t(android::Res_value::TYPE_FLOAT), val->value.dataType);
+}
+
 } // namespace aapt
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 36c3e70..07f62af 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -176,10 +176,10 @@
 /*
  * Style parent's are a bit different. We accept the following formats:
  *
- * @[package:]style/<entry>
- * ?[package:]style/<entry>
- * <package>:[style/]<entry>
- * [package:style/]<entry>
+ * @[[*]package:][style/]<entry>
+ * ?[[*]package:]style/<entry>
+ * <[*]package>:[style/]<entry>
+ * [[*]package:style/]<entry>
  */
 Maybe<Reference> parseStyleParentReference(const StringPiece16& str, std::string* outError) {
     if (str.empty()) {
@@ -195,10 +195,11 @@
     if (name.data()[0] == u'@' || name.data()[0] == u'?') {
         hasLeadingIdentifiers = true;
         name = name.substr(1, name.size() - 1);
-        if (name.data()[0] == u'*') {
-            privateRef = true;
-            name = name.substr(1, name.size() - 1);
-        }
+    }
+
+    if (name.data()[0] == u'*') {
+        privateRef = true;
+        name = name.substr(1, name.size() - 1);
     }
 
     ResourceNameRef ref;
@@ -215,14 +216,6 @@
             *outError = err.str();
             return {};
         }
-    } else {
-        // No type was defined, this should not have a leading identifier.
-        if (hasLeadingIdentifiers) {
-            std::stringstream err;
-            err << "invalid parent reference '" << str << "'";
-            *outError = err.str();
-            return {};
-        }
     }
 
     if (!hasLeadingIdentifiers && ref.package.empty() && !typeStr.empty()) {
@@ -293,6 +286,12 @@
                                                     const StringPiece16& str) {
     android::Res_value flags = { };
     flags.dataType = android::Res_value::TYPE_INT_DEC;
+    flags.data = 0u;
+
+    if (util::trimWhitespace(str).empty()) {
+        // Empty string is a valid flag (0).
+        return util::make_unique<BinaryPrimitive>(flags);
+    }
 
     for (StringPiece16 part : util::tokenize(str, u'|')) {
         StringPiece16 trimmedPart = util::trimWhitespace(part);
@@ -385,12 +384,12 @@
 
 bool tryParseBool(const StringPiece16& str, bool* outValue) {
     StringPiece16 trimmedStr(util::trimWhitespace(str));
-    if (trimmedStr == u"true" || trimmedStr == u"TRUE") {
+    if (trimmedStr == u"true" || trimmedStr == u"TRUE" || trimmedStr == u"True") {
         if (outValue) {
             *outValue = true;
         }
         return true;
-    } else if (trimmedStr == u"false" || trimmedStr == u"FALSE") {
+    } else if (trimmedStr == u"false" || trimmedStr == u"FALSE" || trimmedStr == u"False") {
         if (outValue) {
             *outValue = false;
         }
diff --git a/tools/aapt2/ResourceUtils_test.cpp b/tools/aapt2/ResourceUtils_test.cpp
index 4bbfc32..c9f93e1 100644
--- a/tools/aapt2/ResourceUtils_test.cpp
+++ b/tools/aapt2/ResourceUtils_test.cpp
@@ -16,12 +16,34 @@
 
 #include "Resource.h"
 #include "ResourceUtils.h"
+#include "test/Builders.h"
 #include "test/Common.h"
 
 #include <gtest/gtest.h>
 
 namespace aapt {
 
+TEST(ResourceUtilsTest, ParseBool) {
+    bool val = false;
+    EXPECT_TRUE(ResourceUtils::tryParseBool(u"true", &val));
+    EXPECT_TRUE(val);
+
+    EXPECT_TRUE(ResourceUtils::tryParseBool(u"TRUE", &val));
+    EXPECT_TRUE(val);
+
+    EXPECT_TRUE(ResourceUtils::tryParseBool(u"True", &val));
+    EXPECT_TRUE(val);
+
+    EXPECT_TRUE(ResourceUtils::tryParseBool(u"false", &val));
+    EXPECT_FALSE(val);
+
+    EXPECT_TRUE(ResourceUtils::tryParseBool(u"FALSE", &val));
+    EXPECT_FALSE(val);
+
+    EXPECT_TRUE(ResourceUtils::tryParseBool(u"False", &val));
+    EXPECT_FALSE(val);
+}
+
 TEST(ResourceUtilsTest, ParseResourceName) {
     ResourceNameRef actual;
     bool actualPriv = false;
@@ -154,9 +176,30 @@
     AAPT_ASSERT_TRUE(ref);
     EXPECT_EQ(ref.value().name.value(), kAndroidStyleFooName);
 
+    ref = ResourceUtils::parseStyleParentReference(u"@android:foo", &errStr);
+    AAPT_ASSERT_TRUE(ref);
+    EXPECT_EQ(ref.value().name.value(), kAndroidStyleFooName);
+
     ref = ResourceUtils::parseStyleParentReference(u"foo", &errStr);
     AAPT_ASSERT_TRUE(ref);
     EXPECT_EQ(ref.value().name.value(), kStyleFooName);
+
+    ref = ResourceUtils::parseStyleParentReference(u"*android:style/foo", &errStr);
+    AAPT_ASSERT_TRUE(ref);
+    EXPECT_EQ(ref.value().name.value(), kAndroidStyleFooName);
+    EXPECT_TRUE(ref.value().privateReference);
+}
+
+TEST(ResourceUtilsTest, ParseEmptyFlag) {
+    std::unique_ptr<Attribute> attr = test::AttributeBuilder(false)
+            .setTypeMask(android::ResTable_map::TYPE_FLAGS)
+            .addItem(u"one", 0x01)
+            .addItem(u"two", 0x02)
+            .build();
+
+    std::unique_ptr<BinaryPrimitive> result = ResourceUtils::tryParseFlagSymbol(attr.get(), u"");
+    ASSERT_NE(nullptr, result);
+    EXPECT_EQ(0u, result->value.data);
 }
 
 } // namespace aapt
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index 04c375f..b93e6d8 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -36,10 +36,6 @@
     visitor->visit(static_cast<Derived*>(this));
 }
 
-bool Value::isWeak() const {
-    return false;
-}
-
 RawString::RawString(const StringPool::Ref& ref) : value(ref) {
 }
 
@@ -101,10 +97,6 @@
     }
 }
 
-bool Id::isWeak() const {
-    return true;
-}
-
 bool Id::flatten(android::Res_value* out) const {
     out->dataType = android::Res_value::TYPE_INT_BOOLEAN;
     out->data = util::hostToDevice32(0);
@@ -119,7 +111,15 @@
     *out << "(id)";
 }
 
-String::String(const StringPool::Ref& ref) : value(ref) {
+String::String(const StringPool::Ref& ref) : value(ref), mTranslateable(true) {
+}
+
+void String::setTranslateable(bool val) {
+    mTranslateable = val;
+}
+
+bool String::isTranslateable() const {
+    return mTranslateable;
 }
 
 bool String::flatten(android::Res_value* outValue) const {
@@ -144,7 +144,15 @@
     *out << "(string) \"" << *value << "\"";
 }
 
-StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) {
+StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref), mTranslateable(true) {
+}
+
+void StyledString::setTranslateable(bool val) {
+    mTranslateable = val;
+}
+
+bool StyledString::isTranslateable() const {
+    return mTranslateable;
 }
 
 bool StyledString::flatten(android::Res_value* outValue) const {
@@ -238,13 +246,10 @@
 }
 
 Attribute::Attribute(bool w, uint32_t t) :
-        weak(w), typeMask(t),
+        typeMask(t),
         minInt(std::numeric_limits<int32_t>::min()),
         maxInt(std::numeric_limits<int32_t>::max()) {
-}
-
-bool Attribute::isWeak() const {
-    return weak;
+    mWeak = w;
 }
 
 Attribute* Attribute::clone(StringPool* /*newPool*/) const {
@@ -359,7 +364,7 @@
             << "]";
     }
 
-    if (weak) {
+    if (isWeak()) {
         *out << " [weak]";
     }
 }
@@ -457,6 +462,9 @@
 void Style::print(std::ostream* out) const {
     *out << "(style) ";
     if (parent && parent.value().name) {
+        if (parent.value().privateReference) {
+            *out << "*";
+        }
         *out << parent.value().name.value();
     }
     *out << " ["
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index a038282..8e317db 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -43,9 +43,15 @@
 
     /**
      * Whether this value is weak and can be overridden without
-     * warning or error. Default for base class is false.
+     * warning or error. Default is false.
      */
-    virtual bool isWeak() const;
+    bool isWeak() const {
+        return mWeak;
+    }
+
+    void setWeak(bool val) {
+        mWeak = val;
+    }
 
     /**
      * Returns the source where this value was defined.
@@ -95,6 +101,7 @@
 protected:
     Source mSource;
     std::u16string mComment;
+    bool mWeak = false;
 };
 
 /**
@@ -159,7 +166,7 @@
  * An ID resource. Has no real value, just a place holder.
  */
 struct Id : public BaseItem<Id> {
-    bool isWeak() const override;
+    Id() { mWeak = true; }
     bool flatten(android::Res_value* out) const override;
     Id* clone(StringPool* newPool) const override;
     void print(std::ostream* out) const override;
@@ -185,9 +192,17 @@
 
     String(const StringPool::Ref& ref);
 
+    // Whether the string is marked as translateable. This does not persist when flattened.
+    // It is only used during compilation phase.
+    void setTranslateable(bool val);
+    bool isTranslateable() const;
+
     bool flatten(android::Res_value* outValue) const override;
     String* clone(StringPool* newPool) const override;
     void print(std::ostream* out) const override;
+
+private:
+    bool mTranslateable;
 };
 
 struct StyledString : public BaseItem<StyledString> {
@@ -195,9 +210,17 @@
 
     StyledString(const StringPool::StyleRef& ref);
 
+    // Whether the string is marked as translateable. This does not persist when flattened.
+    // It is only used during compilation phase.
+    void setTranslateable(bool val);
+    bool isTranslateable() const;
+
     bool flatten(android::Res_value* outValue) const override;
     StyledString* clone(StringPool* newPool) const override;
     void print(std::ostream* out) const override;
+
+private:
+    bool mTranslateable;
 };
 
 struct FileReference : public BaseItem<FileReference> {
@@ -232,7 +255,6 @@
         uint32_t value;
     };
 
-	bool weak;
     uint32_t typeMask;
     int32_t minInt;
     int32_t maxInt;
@@ -240,7 +262,6 @@
 
     Attribute(bool w, uint32_t t = 0u);
 
-    bool isWeak() const override;
     Attribute* clone(StringPool* newPool) const override;
     void printMask(std::ostream* out) const;
     void print(std::ostream* out) const override;
diff --git a/tools/aapt2/StringPool.cpp b/tools/aapt2/StringPool.cpp
index 8552f47..aadb00b 100644
--- a/tools/aapt2/StringPool.cpp
+++ b/tools/aapt2/StringPool.cpp
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
+#include "StringPool.h"
 #include "util/BigBuffer.h"
 #include "util/StringPiece.h"
-#include "StringPool.h"
 #include "util/Util.h"
 
 #include <algorithm>
@@ -342,7 +342,14 @@
 
             // Encode the actual UTF16 string length.
             data = encodeLength(data, entry->value.size());
-            strncpy16(data, entry->value.data(), entry->value.size());
+            const size_t byteLength = entry->value.size() * sizeof(char16_t);
+
+            // NOTE: For some reason, strncpy16(data, entry->value.data(), entry->value.size())
+            // truncates the string.
+            memcpy(data, entry->value.data(), byteLength);
+
+            // The null-terminating character is already here due to the block of data being set
+            // to 0s on allocation.
         }
     }
 
diff --git a/tools/aapt2/StringPool_test.cpp b/tools/aapt2/StringPool_test.cpp
index c722fbe..e93c2fba 100644
--- a/tools/aapt2/StringPool_test.cpp
+++ b/tools/aapt2/StringPool_test.cpp
@@ -180,6 +180,22 @@
     ASSERT_EQ(test.setTo(data.get(), buffer.size()), android::NO_ERROR);
 }
 
+TEST(StringPoolTest, FlattenOddCharactersUtf16) {
+    StringPool pool;
+    pool.makeRef(u"\u093f");
+    BigBuffer buffer(1024);
+    StringPool::flattenUtf16(&buffer, pool);
+
+    std::unique_ptr<uint8_t[]> data = util::copy(buffer);
+    android::ResStringPool test;
+    ASSERT_EQ(test.setTo(data.get(), buffer.size()), android::NO_ERROR);
+    size_t len = 0;
+    const char16_t* str = test.stringAt(0, &len);
+    EXPECT_EQ(1u, len);
+    EXPECT_EQ(u'\u093f', *str);
+    EXPECT_EQ(0u, str[1]);
+}
+
 constexpr const char16_t* sLongString = u"バッテリーを長持ちさせるため、バッテリーセーバーは端末のパフォーマンスを抑え、バイブレーション、位置情報サービス、大半のバックグラウンドデータを制限します。メール、SMSや、同期を使 用するその他のアプリは、起動しても更新されないことがあります。バッテリーセーバーは端末の充電中は自動的にOFFになります。";
 
 TEST(StringPoolTest, FlattenUtf8) {
diff --git a/tools/aapt2/compile/Compile.cpp b/tools/aapt2/compile/Compile.cpp
index 90e35d5..689ace6 100644
--- a/tools/aapt2/compile/Compile.cpp
+++ b/tools/aapt2/compile/Compile.cpp
@@ -21,6 +21,7 @@
 #include "ResourceTable.h"
 #include "compile/IdAssigner.h"
 #include "compile/Png.h"
+#include "compile/PseudolocaleGenerator.h"
 #include "compile/XmlIdCollector.h"
 #include "flatten/Archive.h"
 #include "flatten/FileExportWriter.h"
@@ -104,7 +105,9 @@
 struct CompileOptions {
     std::string outputPath;
     Maybe<std::string> resDir;
-    Maybe<std::u16string> product;
+    std::vector<std::u16string> products;
+    bool pseudolocalize = false;
+    bool legacyMode = false;
     bool verbose = false;
 };
 
@@ -114,7 +117,11 @@
     if (!data.configStr.empty()) {
         name << "-" << data.configStr;
     }
-    name << "_" << data.name << "." << data.extension << ".flat";
+    name << "_" << data.name;
+    if (!data.extension.empty()) {
+        name << "." << data.extension;
+    }
+    name << ".flat";
     return name.str();
 }
 
@@ -189,7 +196,8 @@
         xml::XmlPullParser xmlParser(fin);
 
         ResourceParserOptions parserOptions;
-        parserOptions.product = options.product;
+        parserOptions.products = options.products;
+        parserOptions.errorOnPositionalArguments = !options.legacyMode;
 
         // If the filename includes donottranslate, then the default translatable is false.
         parserOptions.translatable = pathData.name.find(u"donottranslate") == std::string::npos;
@@ -203,6 +211,16 @@
         fin.close();
     }
 
+    if (options.pseudolocalize) {
+        // Generate pseudo-localized strings (en-XA and ar-XB).
+        // These are created as weak symbols, and are only generated from default configuration
+        // strings and plurals.
+        PseudolocaleGenerator pseudolocaleGenerator;
+        if (!pseudolocaleGenerator.consume(context, &table)) {
+            return false;
+        }
+    }
+
     // Ensure we have the compilation package at least.
     table.createPackage(context->getCompilationPackage());
 
@@ -372,16 +390,26 @@
     fileExportWriter.getChunkHeader()->size =
             util::hostToDevice32(buffer.size() + f.value().getDataLength());
 
-    if (writer->writeEntry(buffer)) {
-        if (writer->writeEntry(f.value().getDataPtr(), f.value().getDataLength())) {
-            if (writer->finishEntry()) {
-                return true;
-            }
+    if (!writer->writeEntry(buffer)) {
+        context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write");
+        return false;
+    }
+
+    // Only write if we have something to write. This is because mmap fails with length of 0,
+    // but we still want to compile the file to get the resource ID.
+    if (f.value().getDataPtr() && f.value().getDataLength() > 0) {
+        if (!writer->writeEntry(f.value().getDataPtr(), f.value().getDataLength())) {
+            context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write");
+            return false;
         }
     }
 
-    context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write");
-    return false;
+    if (!writer->finishEntry()) {
+        context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write");
+        return false;
+    }
+
+    return true;
 }
 
 class CompileContext : public IAaptContext {
@@ -418,18 +446,25 @@
 int compile(const std::vector<StringPiece>& args) {
     CompileOptions options;
 
-    Maybe<std::string> product;
+    Maybe<std::string> productList;
     Flags flags = Flags()
             .requiredFlag("-o", "Output path", &options.outputPath)
-            .optionalFlag("--product", "Product type to compile", &product)
+            .optionalFlag("--product", "Comma separated list of product types to compile",
+                          &productList)
             .optionalFlag("--dir", "Directory to scan for resources", &options.resDir)
+            .optionalSwitch("--pseudo-localize", "Generate resources for pseudo-locales "
+                            "(en-XA and ar-XB)", &options.pseudolocalize)
+            .optionalSwitch("--legacy", "Treat errors that used to be valid in AAPT as warnings",
+                            &options.legacyMode)
             .optionalSwitch("-v", "Enables verbose logging", &options.verbose);
     if (!flags.parse("aapt2 compile", args, &std::cerr)) {
         return 1;
     }
 
-    if (product) {
-        options.product = util::utf8ToUtf16(product.value());
+    if (productList) {
+        for (StringPiece part : util::tokenize<char>(productList.value(), ',')) {
+            options.products.push_back(util::utf8ToUtf16(part));
+        }
     }
 
     CompileContext context;
diff --git a/tools/aapt2/compile/PseudolocaleGenerator.cpp b/tools/aapt2/compile/PseudolocaleGenerator.cpp
new file mode 100644
index 0000000..2963d13
--- /dev/null
+++ b/tools/aapt2/compile/PseudolocaleGenerator.cpp
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ResourceTable.h"
+#include "ResourceValues.h"
+#include "ValueVisitor.h"
+#include "compile/PseudolocaleGenerator.h"
+#include "compile/Pseudolocalizer.h"
+#include "util/Comparators.h"
+
+namespace aapt {
+
+std::unique_ptr<StyledString> pseudolocalizeStyledString(StyledString* string,
+                                                         Pseudolocalizer::Method method,
+                                                         StringPool* pool) {
+    Pseudolocalizer localizer(method);
+
+    const StringPiece16 originalText = *string->value->str;
+
+    StyleString localized;
+
+    // Copy the spans. We will update their offsets when we localize.
+    localized.spans.reserve(string->value->spans.size());
+    for (const StringPool::Span& span : string->value->spans) {
+        localized.spans.push_back(Span{ *span.name, span.firstChar, span.lastChar });
+    }
+
+    // The ranges are all represented with a single value. This is the start of one range and
+    // end of another.
+    struct Range {
+        size_t start;
+
+        // Once the new string is localized, these are the pointers to the spans to adjust.
+        // Since this struct represents the start of one range and end of another, we have
+        // the two pointers respectively.
+        uint32_t* updateStart;
+        uint32_t* updateEnd;
+    };
+
+    auto cmp = [](const Range& r, size_t index) -> bool {
+        return r.start < index;
+    };
+
+    // Construct the ranges. The ranges are represented like so: [0, 2, 5, 7]
+    // The ranges are the spaces in between. In this example, with a total string length of 9,
+    // the vector represents: (0,1], (2,4], (5,6], (7,9]
+    //
+    std::vector<Range> ranges;
+    ranges.push_back(Range{ 0 });
+    ranges.push_back(Range{ originalText.size() - 1 });
+    for (size_t i = 0; i < string->value->spans.size(); i++) {
+        const StringPool::Span& span = string->value->spans[i];
+
+        // Insert or update the Range marker for the start of this span.
+        auto iter = std::lower_bound(ranges.begin(), ranges.end(), span.firstChar, cmp);
+        if (iter != ranges.end() && iter->start == span.firstChar) {
+            iter->updateStart = &localized.spans[i].firstChar;
+        } else {
+            ranges.insert(iter,
+                          Range{ span.firstChar, &localized.spans[i].firstChar, nullptr });
+        }
+
+        // Insert or update the Range marker for the end of this span.
+        iter = std::lower_bound(ranges.begin(), ranges.end(), span.lastChar, cmp);
+        if (iter != ranges.end() && iter->start == span.lastChar) {
+            iter->updateEnd = &localized.spans[i].lastChar;
+        } else {
+            ranges.insert(iter,
+                          Range{ span.lastChar, nullptr, &localized.spans[i].lastChar });
+        }
+    }
+
+    localized.str += localizer.start();
+
+    // Iterate over the ranges and localize each section.
+    for (size_t i = 0; i < ranges.size(); i++) {
+        const size_t start = ranges[i].start;
+        size_t len = originalText.size() - start;
+        if (i + 1 < ranges.size()) {
+            len = ranges[i + 1].start - start;
+        }
+
+        if (ranges[i].updateStart) {
+            *ranges[i].updateStart = localized.str.size();
+        }
+
+        if (ranges[i].updateEnd) {
+            *ranges[i].updateEnd = localized.str.size();
+        }
+
+        localized.str += localizer.text(originalText.substr(start, len));
+    }
+
+    localized.str += localizer.end();
+
+    std::unique_ptr<StyledString> localizedString = util::make_unique<StyledString>(
+            pool->makeRef(localized));
+    localizedString->setSource(string->getSource());
+    return localizedString;
+}
+
+namespace {
+
+struct Visitor : public RawValueVisitor {
+    StringPool* mPool;
+    Pseudolocalizer::Method mMethod;
+    Pseudolocalizer mLocalizer;
+
+    // Either value or item will be populated upon visiting the value.
+    std::unique_ptr<Value> mValue;
+    std::unique_ptr<Item> mItem;
+
+    Visitor(StringPool* pool, Pseudolocalizer::Method method) :
+            mPool(pool), mMethod(method), mLocalizer(method) {
+    }
+
+    void visit(Array* array) override {
+        std::unique_ptr<Array> localized = util::make_unique<Array>();
+        localized->items.resize(array->items.size());
+        for (size_t i = 0; i < array->items.size(); i++) {
+            Visitor subVisitor(mPool, mMethod);
+            array->items[i]->accept(&subVisitor);
+            if (subVisitor.mItem) {
+                localized->items[i] = std::move(subVisitor.mItem);
+            } else {
+                localized->items[i] = std::unique_ptr<Item>(array->items[i]->clone(mPool));
+            }
+        }
+        localized->setSource(array->getSource());
+        localized->setWeak(true);
+        mValue = std::move(localized);
+    }
+
+    void visit(Plural* plural) override {
+        std::unique_ptr<Plural> localized = util::make_unique<Plural>();
+        for (size_t i = 0; i < plural->values.size(); i++) {
+            Visitor subVisitor(mPool, mMethod);
+            if (plural->values[i]) {
+                plural->values[i]->accept(&subVisitor);
+                if (subVisitor.mValue) {
+                    localized->values[i] = std::move(subVisitor.mItem);
+                } else {
+                    localized->values[i] = std::unique_ptr<Item>(plural->values[i]->clone(mPool));
+                }
+            }
+        }
+        localized->setSource(plural->getSource());
+        localized->setWeak(true);
+        mValue = std::move(localized);
+    }
+
+    void visit(String* string) override {
+        if (!string->isTranslateable()) {
+            return;
+        }
+
+        std::u16string result = mLocalizer.start() + mLocalizer.text(*string->value) +
+                mLocalizer.end();
+        std::unique_ptr<String> localized = util::make_unique<String>(mPool->makeRef(result));
+        localized->setSource(string->getSource());
+        localized->setWeak(true);
+        mItem = std::move(localized);
+    }
+
+    void visit(StyledString* string) override {
+        if (!string->isTranslateable()) {
+            return;
+        }
+
+        mItem = pseudolocalizeStyledString(string, mMethod, mPool);
+        mItem->setWeak(true);
+    }
+};
+
+ConfigDescription modifyConfigForPseudoLocale(const ConfigDescription& base,
+                                              Pseudolocalizer::Method m) {
+    ConfigDescription modified = base;
+    switch (m) {
+    case Pseudolocalizer::Method::kAccent:
+        modified.language[0] = 'e';
+        modified.language[1] = 'n';
+        modified.country[0] = 'X';
+        modified.country[1] = 'A';
+        break;
+
+    case Pseudolocalizer::Method::kBidi:
+        modified.language[0] = 'a';
+        modified.language[1] = 'r';
+        modified.country[0] = 'X';
+        modified.country[1] = 'B';
+        break;
+    default:
+        break;
+    }
+    return modified;
+}
+
+void pseudolocalizeIfNeeded(std::vector<ResourceConfigValue>* configValues,
+                            Pseudolocalizer::Method method, StringPool* pool, Value* value) {
+    Visitor visitor(pool, method);
+    value->accept(&visitor);
+
+    std::unique_ptr<Value> localizedValue;
+    if (visitor.mValue) {
+        localizedValue = std::move(visitor.mValue);
+    } else if (visitor.mItem) {
+        localizedValue = std::move(visitor.mItem);
+    }
+
+    if (localizedValue) {
+        ConfigDescription pseudolocalizedConfig = modifyConfigForPseudoLocale(ConfigDescription{},
+                                                                              method);
+        auto iter = std::lower_bound(configValues->begin(), configValues->end(),
+                                     pseudolocalizedConfig, cmp::lessThanConfig);
+        if (iter == configValues->end() || iter->config != pseudolocalizedConfig) {
+            // The pseudolocalized config doesn't exist, add it.
+            configValues->insert(iter, ResourceConfigValue{ pseudolocalizedConfig,
+                                                            std::move(localizedValue) });
+        }
+    }
+}
+
+} // namespace
+
+bool PseudolocaleGenerator::consume(IAaptContext* context, ResourceTable* table) {
+    for (auto& package : table->packages) {
+        for (auto& type : package->types) {
+            for (auto& entry : type->entries) {
+                auto iter = std::lower_bound(entry->values.begin(), entry->values.end(),
+                                             ConfigDescription{}, cmp::lessThanConfig);
+                if (iter != entry->values.end() && iter->config == ConfigDescription{}) {
+                    // Only pseudolocalize the default configuration.
+
+                    // The iterator will be invalidated, so grab a pointer to the value.
+                    Value* originalValue = iter->value.get();
+
+                    pseudolocalizeIfNeeded(&entry->values, Pseudolocalizer::Method::kAccent,
+                                           &table->stringPool, originalValue);
+                    pseudolocalizeIfNeeded(&entry->values, Pseudolocalizer::Method::kBidi,
+                                           &table->stringPool, originalValue);
+                }
+            }
+        }
+    }
+    return true;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/compile/PseudolocaleGenerator.h b/tools/aapt2/compile/PseudolocaleGenerator.h
new file mode 100644
index 0000000..4fbc516
--- /dev/null
+++ b/tools/aapt2/compile/PseudolocaleGenerator.h
@@ -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.
+ */
+
+#ifndef AAPT_COMPILE_PSEUDOLOCALEGENERATOR_H
+#define AAPT_COMPILE_PSEUDOLOCALEGENERATOR_H
+
+#include "StringPool.h"
+#include "compile/Pseudolocalizer.h"
+#include "process/IResourceTableConsumer.h"
+
+namespace aapt {
+
+std::unique_ptr<StyledString> pseudolocalizeStyledString(StyledString* string,
+                                                         Pseudolocalizer::Method method,
+                                                         StringPool* pool);
+
+struct PseudolocaleGenerator : public IResourceTableConsumer {
+    bool consume(IAaptContext* context, ResourceTable* table) override;
+};
+
+} // namespace aapt
+
+#endif /* AAPT_COMPILE_PSEUDOLOCALEGENERATOR_H */
diff --git a/tools/aapt2/compile/PseudolocaleGenerator_test.cpp b/tools/aapt2/compile/PseudolocaleGenerator_test.cpp
new file mode 100644
index 0000000..4cb6ea2
--- /dev/null
+++ b/tools/aapt2/compile/PseudolocaleGenerator_test.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "compile/PseudolocaleGenerator.h"
+#include "test/Builders.h"
+#include "test/Common.h"
+#include "test/Context.h"
+#include "util/Util.h"
+
+#include <androidfw/ResourceTypes.h>
+#include <gtest/gtest.h>
+
+namespace aapt {
+
+TEST(PseudolocaleGeneratorTest, PseudolocalizeStyledString) {
+    StringPool pool;
+    StyleString originalStyle;
+    originalStyle.str = u"Hello world!";
+    originalStyle.spans = { Span{ u"b", 2, 3 }, Span{ u"b", 6, 7 }, Span{ u"i", 1, 10 } };
+
+    std::unique_ptr<StyledString> newString = pseudolocalizeStyledString(
+            util::make_unique<StyledString>(pool.makeRef(originalStyle)).get(),
+            Pseudolocalizer::Method::kNone, &pool);
+
+    EXPECT_EQ(originalStyle.str, *newString->value->str);
+    ASSERT_EQ(originalStyle.spans.size(), newString->value->spans.size());
+
+    EXPECT_EQ(2u, newString->value->spans[0].firstChar);
+    EXPECT_EQ(3u, newString->value->spans[0].lastChar);
+    EXPECT_EQ(std::u16string(u"b"), *newString->value->spans[0].name);
+
+    EXPECT_EQ(6u, newString->value->spans[1].firstChar);
+    EXPECT_EQ(7u, newString->value->spans[1].lastChar);
+    EXPECT_EQ(std::u16string(u"b"), *newString->value->spans[1].name);
+
+    EXPECT_EQ(1u, newString->value->spans[2].firstChar);
+    EXPECT_EQ(10u, newString->value->spans[2].lastChar);
+    EXPECT_EQ(std::u16string(u"i"), *newString->value->spans[2].name);
+
+    originalStyle.spans.push_back(Span{ u"em", 0, 11u });
+
+    newString = pseudolocalizeStyledString(
+            util::make_unique<StyledString>(pool.makeRef(originalStyle)).get(),
+            Pseudolocalizer::Method::kAccent, &pool);
+
+    EXPECT_EQ(std::u16string(u"[Ĥéļļö ŵöŕļð¡ one two]"), *newString->value->str);
+    ASSERT_EQ(originalStyle.spans.size(), newString->value->spans.size());
+
+    EXPECT_EQ(3u, newString->value->spans[0].firstChar);
+    EXPECT_EQ(4u, newString->value->spans[0].lastChar);
+
+    EXPECT_EQ(7u, newString->value->spans[1].firstChar);
+    EXPECT_EQ(8u, newString->value->spans[1].lastChar);
+
+    EXPECT_EQ(2u, newString->value->spans[2].firstChar);
+    EXPECT_EQ(11u, newString->value->spans[2].lastChar);
+
+    EXPECT_EQ(1u, newString->value->spans[3].firstChar);
+    EXPECT_EQ(12u, newString->value->spans[3].lastChar);
+}
+
+TEST(PseudolocaleGeneratorTest, PseudolocalizeOnlyDefaultConfigs) {
+    std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
+            .addString(u"@android:string/one", u"one")
+            .addString(u"@android:string/two", ResourceId{}, test::parseConfigOrDie("en"), u"two")
+            .addString(u"@android:string/three", u"three")
+            .addString(u"@android:string/three", ResourceId{}, test::parseConfigOrDie("en-rXA"),
+                       u"three")
+            .addString(u"@android:string/four", u"four")
+            .build();
+
+    String* val = test::getValue<String>(table.get(), u"@android:string/four");
+    val->setTranslateable(false);
+
+    std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
+    PseudolocaleGenerator generator;
+    ASSERT_TRUE(generator.consume(context.get(), table.get()));
+
+    // Normal pseudolocalization should take place.
+    ASSERT_NE(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/one",
+                                                       test::parseConfigOrDie("en-rXA")));
+    ASSERT_NE(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/one",
+                                                       test::parseConfigOrDie("ar-rXB")));
+
+    // No default config for android:string/two, so no pseudlocales should exist.
+    ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/two",
+                                                       test::parseConfigOrDie("en-rXA")));
+    ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/two",
+                                                       test::parseConfigOrDie("ar-rXB")));
+
+
+    // Check that we didn't override manual pseudolocalization.
+    val = test::getValueForConfig<String>(table.get(), u"@android:string/three",
+                                          test::parseConfigOrDie("en-rXA"));
+    ASSERT_NE(nullptr, val);
+    EXPECT_EQ(std::u16string(u"three"), *val->value);
+
+    ASSERT_NE(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/three",
+                                                       test::parseConfigOrDie("ar-rXB")));
+
+    // Check that four's translateable marker was honored.
+    ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/four",
+                                                       test::parseConfigOrDie("en-rXA")));
+    ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/four",
+                                                       test::parseConfigOrDie("ar-rXB")));
+
+}
+
+} // namespace aapt
+
diff --git a/tools/aapt2/compile/Pseudolocalizer.cpp b/tools/aapt2/compile/Pseudolocalizer.cpp
new file mode 100644
index 0000000..eae52d7
--- /dev/null
+++ b/tools/aapt2/compile/Pseudolocalizer.cpp
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "compile/Pseudolocalizer.h"
+#include "util/Util.h"
+
+namespace aapt {
+
+// String basis to generate expansion
+static const std::u16string k_expansion_string = u"one two three "
+        "four five six seven eight nine ten eleven twelve thirteen "
+        "fourteen fiveteen sixteen seventeen nineteen twenty";
+
+// Special unicode characters to override directionality of the words
+static const std::u16string k_rlm = u"\u200f";
+static const std::u16string k_rlo = u"\u202e";
+static const std::u16string k_pdf = u"\u202c";
+
+// Placeholder marks
+static const std::u16string k_placeholder_open = u"\u00bb";
+static const std::u16string k_placeholder_close = u"\u00ab";
+
+static const char16_t k_arg_start = u'{';
+static const char16_t k_arg_end = u'}';
+
+class PseudoMethodNone : public PseudoMethodImpl {
+public:
+    std::u16string text(const StringPiece16& text) override { return text.toString(); }
+    std::u16string placeholder(const StringPiece16& text) override { return text.toString(); }
+};
+
+class PseudoMethodBidi : public PseudoMethodImpl {
+public:
+    std::u16string text(const StringPiece16& text) override;
+    std::u16string placeholder(const StringPiece16& text) override;
+};
+
+class PseudoMethodAccent : public PseudoMethodImpl {
+public:
+    PseudoMethodAccent() : mDepth(0), mWordCount(0), mLength(0) {}
+    std::u16string start() override;
+    std::u16string end() override;
+    std::u16string text(const StringPiece16& text) override;
+    std::u16string placeholder(const StringPiece16& text) override;
+private:
+    size_t mDepth;
+    size_t mWordCount;
+    size_t mLength;
+};
+
+Pseudolocalizer::Pseudolocalizer(Method method) : mLastDepth(0) {
+    setMethod(method);
+}
+
+void Pseudolocalizer::setMethod(Method method) {
+    switch (method) {
+    case Method::kNone:
+        mImpl = util::make_unique<PseudoMethodNone>();
+        break;
+    case Method::kAccent:
+        mImpl = util::make_unique<PseudoMethodAccent>();
+        break;
+    case Method::kBidi:
+        mImpl = util::make_unique<PseudoMethodBidi>();
+        break;
+    }
+}
+
+std::u16string Pseudolocalizer::text(const StringPiece16& text) {
+    std::u16string out;
+    size_t depth = mLastDepth;
+    size_t lastpos, pos;
+    const size_t length = text.size();
+    const char16_t* str = text.data();
+    bool escaped = false;
+    for (lastpos = pos = 0; pos < length; pos++) {
+        char16_t c = str[pos];
+        if (escaped) {
+            escaped = false;
+            continue;
+        }
+        if (c == '\'') {
+            escaped = true;
+            continue;
+        }
+
+        if (c == k_arg_start) {
+            depth++;
+        } else if (c == k_arg_end && depth) {
+            depth--;
+        }
+
+        if (mLastDepth != depth || pos == length - 1) {
+            bool pseudo = ((mLastDepth % 2) == 0);
+            size_t nextpos = pos;
+            if (!pseudo || depth == mLastDepth) {
+                nextpos++;
+            }
+            size_t size = nextpos - lastpos;
+            if (size) {
+                std::u16string chunk = text.substr(lastpos, size).toString();
+                if (pseudo) {
+                    chunk = mImpl->text(chunk);
+                } else if (str[lastpos] == k_arg_start && str[nextpos - 1] == k_arg_end) {
+                    chunk = mImpl->placeholder(chunk);
+                }
+                out.append(chunk);
+            }
+            if (pseudo && depth < mLastDepth) { // End of message
+                out.append(mImpl->end());
+            } else if (!pseudo && depth > mLastDepth) { // Start of message
+                out.append(mImpl->start());
+            }
+            lastpos = nextpos;
+            mLastDepth = depth;
+        }
+    }
+    return out;
+}
+
+static const char16_t* pseudolocalizeChar(const char16_t c) {
+    switch (c) {
+        case 'a':   return u"\u00e5";
+        case 'b':   return u"\u0253";
+        case 'c':   return u"\u00e7";
+        case 'd':   return u"\u00f0";
+        case 'e':   return u"\u00e9";
+        case 'f':   return u"\u0192";
+        case 'g':   return u"\u011d";
+        case 'h':   return u"\u0125";
+        case 'i':   return u"\u00ee";
+        case 'j':   return u"\u0135";
+        case 'k':   return u"\u0137";
+        case 'l':   return u"\u013c";
+        case 'm':   return u"\u1e3f";
+        case 'n':   return u"\u00f1";
+        case 'o':   return u"\u00f6";
+        case 'p':   return u"\u00fe";
+        case 'q':   return u"\u0051";
+        case 'r':   return u"\u0155";
+        case 's':   return u"\u0161";
+        case 't':   return u"\u0163";
+        case 'u':   return u"\u00fb";
+        case 'v':   return u"\u0056";
+        case 'w':   return u"\u0175";
+        case 'x':   return u"\u0445";
+        case 'y':   return u"\u00fd";
+        case 'z':   return u"\u017e";
+        case 'A':   return u"\u00c5";
+        case 'B':   return u"\u03b2";
+        case 'C':   return u"\u00c7";
+        case 'D':   return u"\u00d0";
+        case 'E':   return u"\u00c9";
+        case 'G':   return u"\u011c";
+        case 'H':   return u"\u0124";
+        case 'I':   return u"\u00ce";
+        case 'J':   return u"\u0134";
+        case 'K':   return u"\u0136";
+        case 'L':   return u"\u013b";
+        case 'M':   return u"\u1e3e";
+        case 'N':   return u"\u00d1";
+        case 'O':   return u"\u00d6";
+        case 'P':   return u"\u00de";
+        case 'Q':   return u"\u0071";
+        case 'R':   return u"\u0154";
+        case 'S':   return u"\u0160";
+        case 'T':   return u"\u0162";
+        case 'U':   return u"\u00db";
+        case 'V':   return u"\u03bd";
+        case 'W':   return u"\u0174";
+        case 'X':   return u"\u00d7";
+        case 'Y':   return u"\u00dd";
+        case 'Z':   return u"\u017d";
+        case '!':   return u"\u00a1";
+        case '?':   return u"\u00bf";
+        case '$':   return u"\u20ac";
+        default:    return NULL;
+    }
+}
+
+static bool isPossibleNormalPlaceholderEnd(const char16_t c) {
+    switch (c) {
+        case 's': return true;
+        case 'S': return true;
+        case 'c': return true;
+        case 'C': return true;
+        case 'd': return true;
+        case 'o': return true;
+        case 'x': return true;
+        case 'X': return true;
+        case 'f': return true;
+        case 'e': return true;
+        case 'E': return true;
+        case 'g': return true;
+        case 'G': return true;
+        case 'a': return true;
+        case 'A': return true;
+        case 'b': return true;
+        case 'B': return true;
+        case 'h': return true;
+        case 'H': return true;
+        case '%': return true;
+        case 'n': return true;
+        default:  return false;
+    }
+}
+
+static std::u16string pseudoGenerateExpansion(const unsigned int length) {
+    std::u16string result = k_expansion_string;
+    const char16_t* s = result.data();
+    if (result.size() < length) {
+        result += u" ";
+        result += pseudoGenerateExpansion(length - result.size());
+    } else {
+        int ext = 0;
+        // Should contain only whole words, so looking for a space
+        for (unsigned int i = length + 1; i < result.size(); ++i) {
+            ++ext;
+            if (s[i] == ' ') {
+                break;
+            }
+        }
+        result = result.substr(0, length + ext);
+    }
+    return result;
+}
+
+std::u16string PseudoMethodAccent::start() {
+    std::u16string result;
+    if (mDepth == 0) {
+        result = u"[";
+    }
+    mWordCount = mLength = 0;
+    mDepth++;
+    return result;
+}
+
+std::u16string PseudoMethodAccent::end() {
+    std::u16string result;
+    if (mLength) {
+        result += u" ";
+        result += pseudoGenerateExpansion(mWordCount > 3 ? mLength : mLength / 2);
+    }
+    mWordCount = mLength = 0;
+    mDepth--;
+    if (mDepth == 0) {
+        result += u"]";
+    }
+    return result;
+}
+
+/**
+ * Converts characters so they look like they've been localized.
+ *
+ * Note: This leaves placeholder syntax untouched.
+ */
+std::u16string PseudoMethodAccent::text(const StringPiece16& source)
+{
+    const char16_t* s = source.data();
+    std::u16string result;
+    const size_t I = source.size();
+    bool lastspace = true;
+    for (size_t i = 0; i < I; i++) {
+        char16_t c = s[i];
+        if (c == '%') {
+            // Placeholder syntax, no need to pseudolocalize
+            std::u16string chunk;
+            bool end = false;
+            chunk.append(&c, 1);
+            while (!end && i < I) {
+                ++i;
+                c = s[i];
+                chunk.append(&c, 1);
+                if (isPossibleNormalPlaceholderEnd(c)) {
+                    end = true;
+                } else if (c == 't') {
+                    ++i;
+                    c = s[i];
+                    chunk.append(&c, 1);
+                    end = true;
+                }
+            }
+            // Treat chunk as a placeholder unless it ends with %.
+            result += ((c == '%') ? chunk : placeholder(chunk));
+        } else if (c == '<' || c == '&') {
+            // html syntax, no need to pseudolocalize
+            bool tag_closed = false;
+            while (!tag_closed && i < I) {
+                if (c == '&') {
+                    std::u16string escapeText;
+                    escapeText.append(&c, 1);
+                    bool end = false;
+                    size_t htmlCodePos = i;
+                    while (!end && htmlCodePos < I) {
+                        ++htmlCodePos;
+                        c = s[htmlCodePos];
+                        escapeText.append(&c, 1);
+                        // Valid html code
+                        if (c == ';') {
+                            end = true;
+                            i = htmlCodePos;
+                        }
+                        // Wrong html code
+                        else if (!((c == '#' ||
+                                 (c >= 'a' && c <= 'z') ||
+                                 (c >= 'A' && c <= 'Z') ||
+                                 (c >= '0' && c <= '9')))) {
+                            end = true;
+                        }
+                    }
+                    result += escapeText;
+                    if (escapeText != u"&lt;") {
+                        tag_closed = true;
+                    }
+                    continue;
+                }
+                if (c == '>') {
+                    tag_closed = true;
+                    result.append(&c, 1);
+                    continue;
+                }
+                result.append(&c, 1);
+                i++;
+                c = s[i];
+            }
+        } else {
+            // This is a pure text that should be pseudolocalized
+            const char16_t* p = pseudolocalizeChar(c);
+            if (p != nullptr) {
+                result += p;
+            } else {
+                bool space = util::isspace16(c);
+                if (lastspace && !space) {
+                    mWordCount++;
+                }
+                lastspace = space;
+                result.append(&c, 1);
+            }
+            // Count only pseudolocalizable chars and delimiters
+            mLength++;
+        }
+    }
+    return result;
+}
+
+std::u16string PseudoMethodAccent::placeholder(const StringPiece16& source) {
+    // Surround a placeholder with brackets
+    return k_placeholder_open + source.toString() + k_placeholder_close;
+}
+
+std::u16string PseudoMethodBidi::text(const StringPiece16& source) {
+    const char16_t* s = source.data();
+    std::u16string result;
+    bool lastspace = true;
+    bool space = true;
+    for (size_t i = 0; i < source.size(); i++) {
+        char16_t c = s[i];
+        space = util::isspace16(c);
+        if (lastspace && !space) {
+            // Word start
+            result += k_rlm + k_rlo;
+        } else if (!lastspace && space) {
+            // Word end
+            result += k_pdf + k_rlm;
+        }
+        lastspace = space;
+        result.append(&c, 1);
+    }
+    if (!lastspace) {
+        // End of last word
+        result += k_pdf + k_rlm;
+    }
+    return result;
+}
+
+std::u16string PseudoMethodBidi::placeholder(const StringPiece16& source) {
+    // Surround a placeholder with directionality change sequence
+    return k_rlm + k_rlo + source.toString() + k_pdf + k_rlm;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/compile/Pseudolocalizer.h b/tools/aapt2/compile/Pseudolocalizer.h
new file mode 100644
index 0000000..8818c17
--- /dev/null
+++ b/tools/aapt2/compile/Pseudolocalizer.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_COMPILE_PSEUDOLOCALIZE_H
+#define AAPT_COMPILE_PSEUDOLOCALIZE_H
+
+#include "ResourceValues.h"
+#include "StringPool.h"
+#include "util/StringPiece.h"
+
+#include <android-base/macros.h>
+#include <memory>
+
+namespace aapt {
+
+class PseudoMethodImpl {
+public:
+    virtual ~PseudoMethodImpl() {}
+    virtual std::u16string start() { return {}; }
+    virtual std::u16string end() { return {}; }
+    virtual std::u16string text(const StringPiece16& text) = 0;
+    virtual std::u16string placeholder(const StringPiece16& text) = 0;
+};
+
+class Pseudolocalizer {
+public:
+    enum class Method {
+        kNone,
+        kAccent,
+        kBidi,
+    };
+
+    Pseudolocalizer(Method method);
+    void setMethod(Method method);
+    std::u16string start() { return mImpl->start(); }
+    std::u16string end() { return mImpl->end(); }
+    std::u16string text(const StringPiece16& text);
+private:
+    std::unique_ptr<PseudoMethodImpl> mImpl;
+    size_t mLastDepth;
+};
+
+} // namespace aapt
+
+#endif /* AAPT_COMPILE_PSEUDOLOCALIZE_H */
diff --git a/tools/aapt2/compile/Pseudolocalizer_test.cpp b/tools/aapt2/compile/Pseudolocalizer_test.cpp
new file mode 100644
index 0000000..b0bc2c1
--- /dev/null
+++ b/tools/aapt2/compile/Pseudolocalizer_test.cpp
@@ -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.
+ */
+
+#include "compile/Pseudolocalizer.h"
+#include "util/Util.h"
+
+#include <androidfw/ResourceTypes.h>
+#include <gtest/gtest.h>
+
+namespace aapt {
+
+// In this context, 'Axis' represents a particular field in the configuration,
+// such as language or density.
+
+static ::testing::AssertionResult simpleHelper(const char* input, const char* expected,
+                                               Pseudolocalizer::Method method) {
+    Pseudolocalizer pseudo(method);
+    std::string result = util::utf16ToUtf8(
+            pseudo.start() + pseudo.text(util::utf8ToUtf16(input)) + pseudo.end());
+    if (StringPiece(expected) != result) {
+        return ::testing::AssertionFailure() << expected << " != " << result;
+    }
+    return ::testing::AssertionSuccess();
+}
+
+static ::testing::AssertionResult compoundHelper(const char* in1, const char* in2, const char *in3,
+                                                 const char* expected,
+                                                 Pseudolocalizer::Method method) {
+    Pseudolocalizer pseudo(method);
+    std::string result = util::utf16ToUtf8(pseudo.start() +
+                                           pseudo.text(util::utf8ToUtf16(in1)) +
+                                           pseudo.text(util::utf8ToUtf16(in2)) +
+                                           pseudo.text(util::utf8ToUtf16(in3)) +
+                                           pseudo.end());
+    if (StringPiece(expected) != result) {
+        return ::testing::AssertionFailure() << expected << " != " << result;
+    }
+    return ::testing::AssertionSuccess();
+}
+
+TEST(PseudolocalizerTest, NoPseudolocalization) {
+    EXPECT_TRUE(simpleHelper("", "", Pseudolocalizer::Method::kNone));
+    EXPECT_TRUE(simpleHelper("Hello, world", "Hello, world", Pseudolocalizer::Method::kNone));
+
+    EXPECT_TRUE(compoundHelper("Hello,", " world", "",
+                               "Hello, world", Pseudolocalizer::Method::kNone));
+}
+
+TEST(PseudolocalizerTest, PlaintextAccent) {
+    EXPECT_TRUE(simpleHelper("", "[]", Pseudolocalizer::Method::kAccent));
+    EXPECT_TRUE(simpleHelper("Hello, world",
+                             "[Ĥéļļö, ŵöŕļð one two]", Pseudolocalizer::Method::kAccent));
+
+    EXPECT_TRUE(simpleHelper("Hello, %1d",
+                             "[Ĥéļļö, »%1d« one two]", Pseudolocalizer::Method::kAccent));
+
+    EXPECT_TRUE(simpleHelper("Battery %1d%%",
+                             "[βåţţéŕý »%1d«%% one two]", Pseudolocalizer::Method::kAccent));
+
+    EXPECT_TRUE(compoundHelper("", "", "", "[]", Pseudolocalizer::Method::kAccent));
+    EXPECT_TRUE(compoundHelper("Hello,", " world", "",
+                               "[Ĥéļļö, ŵöŕļð one two]", Pseudolocalizer::Method::kAccent));
+}
+
+TEST(PseudolocalizerTest, PlaintextBidi) {
+    EXPECT_TRUE(simpleHelper("", "", Pseudolocalizer::Method::kBidi));
+    EXPECT_TRUE(simpleHelper("word",
+                             "\xe2\x80\x8f\xE2\x80\xaeword\xE2\x80\xac\xe2\x80\x8f",
+                             Pseudolocalizer::Method::kBidi));
+    EXPECT_TRUE(simpleHelper("  word  ",
+                             "  \xe2\x80\x8f\xE2\x80\xaeword\xE2\x80\xac\xe2\x80\x8f  ",
+                             Pseudolocalizer::Method::kBidi));
+    EXPECT_TRUE(simpleHelper("  word  ",
+                             "  \xe2\x80\x8f\xE2\x80\xaeword\xE2\x80\xac\xe2\x80\x8f  ",
+                             Pseudolocalizer::Method::kBidi));
+    EXPECT_TRUE(simpleHelper("hello\n  world\n",
+                             "\xe2\x80\x8f\xE2\x80\xaehello\xE2\x80\xac\xe2\x80\x8f\n" \
+                                     "  \xe2\x80\x8f\xE2\x80\xaeworld\xE2\x80\xac\xe2\x80\x8f\n",
+                             Pseudolocalizer::Method::kBidi));
+    EXPECT_TRUE(compoundHelper("hello", "\n ", " world\n",
+                               "\xe2\x80\x8f\xE2\x80\xaehello\xE2\x80\xac\xe2\x80\x8f\n" \
+                                       "  \xe2\x80\x8f\xE2\x80\xaeworld\xE2\x80\xac\xe2\x80\x8f\n",
+                               Pseudolocalizer::Method::kBidi));
+}
+
+TEST(PseudolocalizerTest, SimpleICU) {
+    // Single-fragment messages
+    EXPECT_TRUE(simpleHelper("{placeholder}", "[»{placeholder}«]",
+                             Pseudolocalizer::Method::kAccent));
+    EXPECT_TRUE(simpleHelper("{USER} is offline",
+                             "[»{USER}« îš öƒƒļîñé one two]", Pseudolocalizer::Method::kAccent));
+    EXPECT_TRUE(simpleHelper("Copy from {path1} to {path2}",
+                             "[Çöþý ƒŕöḿ »{path1}« ţö »{path2}« one two three]",
+                             Pseudolocalizer::Method::kAccent));
+    EXPECT_TRUE(simpleHelper("Today is {1,date} {1,time}",
+                             "[Ţöðåý îš »{1,date}« »{1,time}« one two]",
+                             Pseudolocalizer::Method::kAccent));
+
+    // Multi-fragment messages
+    EXPECT_TRUE(compoundHelper("{USER}", " ", "is offline",
+                               "[»{USER}« îš öƒƒļîñé one two]",
+                               Pseudolocalizer::Method::kAccent));
+    EXPECT_TRUE(compoundHelper("Copy from ", "{path1}", " to {path2}",
+                               "[Çöþý ƒŕöḿ »{path1}« ţö »{path2}« one two three]",
+                               Pseudolocalizer::Method::kAccent));
+}
+
+TEST(PseudolocalizerTest, ICUBidi) {
+    // Single-fragment messages
+    EXPECT_TRUE(simpleHelper("{placeholder}",
+                             "\xe2\x80\x8f\xE2\x80\xae{placeholder}\xE2\x80\xac\xe2\x80\x8f",
+                             Pseudolocalizer::Method::kBidi));
+    EXPECT_TRUE(simpleHelper(
+            "{COUNT, plural, one {one} other {other}}",
+            "{COUNT, plural, " \
+                    "one {\xe2\x80\x8f\xE2\x80\xaeone\xE2\x80\xac\xe2\x80\x8f} " \
+                    "other {\xe2\x80\x8f\xE2\x80\xaeother\xE2\x80\xac\xe2\x80\x8f}}",
+            Pseudolocalizer::Method::kBidi));
+}
+
+TEST(PseudolocalizerTest, Escaping) {
+    // Single-fragment messages
+    EXPECT_TRUE(simpleHelper("'{USER'} is offline",
+                             "['{ÛŠÉŔ'} îš öƒƒļîñé one two three]",
+                             Pseudolocalizer::Method::kAccent));
+
+    // Multi-fragment messages
+    EXPECT_TRUE(compoundHelper("'{USER}", " ", "''is offline",
+                               "['{ÛŠÉŔ} ''îš öƒƒļîñé one two three]",
+                               Pseudolocalizer::Method::kAccent));
+}
+
+TEST(PseudolocalizerTest, PluralsAndSelects) {
+    EXPECT_TRUE(simpleHelper(
+            "{COUNT, plural, one {Delete a file} other {Delete {COUNT} files}}",
+            "[{COUNT, plural, one {Ðéļéţé å ƒîļé one two} " \
+                     "other {Ðéļéţé »{COUNT}« ƒîļéš one two}}]",
+            Pseudolocalizer::Method::kAccent));
+
+    EXPECT_TRUE(simpleHelper(
+            "Distance is {COUNT, plural, one {# mile} other {# miles}}",
+            "[Ðîšţåñçé îš {COUNT, plural, one {# ḿîļé one two} " \
+                                 "other {# ḿîļéš one two}}]",
+            Pseudolocalizer::Method::kAccent));
+
+    EXPECT_TRUE(simpleHelper(
+            "{1, select, female {{1} added you} " \
+                    "male {{1} added you} other {{1} added you}}",
+            "[{1, select, female {»{1}« åððéð ýöû one two} " \
+                    "male {»{1}« åððéð ýöû one two} other {»{1}« åððéð ýöû one two}}]",
+            Pseudolocalizer::Method::kAccent));
+
+    EXPECT_TRUE(compoundHelper(
+            "{COUNT, plural, one {Delete a file} " \
+                    "other {Delete ", "{COUNT}", " files}}",
+            "[{COUNT, plural, one {Ðéļéţé å ƒîļé one two} " \
+                    "other {Ðéļéţé »{COUNT}« ƒîļéš one two}}]",
+            Pseudolocalizer::Method::kAccent));
+}
+
+TEST(PseudolocalizerTest, NestedICU) {
+    EXPECT_TRUE(simpleHelper(
+            "{person, select, " \
+                "female {" \
+                    "{num_circles, plural," \
+                        "=0{{person} didn't add you to any of her circles.}" \
+                        "=1{{person} added you to one of her circles.}" \
+                        "other{{person} added you to her # circles.}}}" \
+                "male {" \
+                    "{num_circles, plural," \
+                        "=0{{person} didn't add you to any of his circles.}" \
+                        "=1{{person} added you to one of his circles.}" \
+                        "other{{person} added you to his # circles.}}}" \
+                "other {" \
+                    "{num_circles, plural," \
+                        "=0{{person} didn't add you to any of their circles.}" \
+                        "=1{{person} added you to one of their circles.}" \
+                        "other{{person} added you to their # circles.}}}}",
+            "[{person, select, " \
+                "female {" \
+                    "{num_circles, plural," \
+                        "=0{»{person}« ðîðñ'ţ åðð ýöû ţö åñý öƒ ĥéŕ çîŕçļéš." \
+                            " one two three four five}" \
+                        "=1{»{person}« åððéð ýöû ţö öñé öƒ ĥéŕ çîŕçļéš." \
+                            " one two three four}" \
+                        "other{»{person}« åððéð ýöû ţö ĥéŕ # çîŕçļéš." \
+                            " one two three four}}}" \
+                "male {" \
+                    "{num_circles, plural," \
+                        "=0{»{person}« ðîðñ'ţ åðð ýöû ţö åñý öƒ ĥîš çîŕçļéš." \
+                            " one two three four five}" \
+                        "=1{»{person}« åððéð ýöû ţö öñé öƒ ĥîš çîŕçļéš." \
+                            " one two three four}" \
+                        "other{»{person}« åððéð ýöû ţö ĥîš # çîŕçļéš." \
+                            " one two three four}}}" \
+                "other {{num_circles, plural," \
+                    "=0{»{person}« ðîðñ'ţ åðð ýöû ţö åñý öƒ ţĥéîŕ çîŕçļéš." \
+                        " one two three four five}" \
+                    "=1{»{person}« åððéð ýöû ţö öñé öƒ ţĥéîŕ çîŕçļéš." \
+                        " one two three four}" \
+                    "other{»{person}« åððéð ýöû ţö ţĥéîŕ # çîŕçļéš." \
+                        " one two three four}}}}]",
+            Pseudolocalizer::Method::kAccent));
+}
+
+TEST(PseudolocalizerTest, RedefineMethod) {
+    Pseudolocalizer pseudo(Pseudolocalizer::Method::kAccent);
+    std::u16string result = pseudo.text(u"Hello, ");
+    pseudo.setMethod(Pseudolocalizer::Method::kNone);
+    result += pseudo.text(u"world!");
+    ASSERT_EQ(StringPiece("Ĥéļļö, world!"), util::utf16ToUtf8(result));
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/compile/XmlIdCollector_test.cpp b/tools/aapt2/compile/XmlIdCollector_test.cpp
index 45b7af2..a37ea86 100644
--- a/tools/aapt2/compile/XmlIdCollector_test.cpp
+++ b/tools/aapt2/compile/XmlIdCollector_test.cpp
@@ -37,13 +37,13 @@
     XmlIdCollector collector;
     ASSERT_TRUE(collector.consume(context.get(), doc.get()));
 
-    EXPECT_EQ(1u, std::count(doc->file.exportedSymbols.begin(), doc->file.exportedSymbols.end(),
+    EXPECT_EQ(1, std::count(doc->file.exportedSymbols.begin(), doc->file.exportedSymbols.end(),
                              SourcedResourceName{ test::parseNameOrDie(u"@id/foo"), 3u }));
 
-    EXPECT_EQ(1u, std::count(doc->file.exportedSymbols.begin(), doc->file.exportedSymbols.end(),
+    EXPECT_EQ(1, std::count(doc->file.exportedSymbols.begin(), doc->file.exportedSymbols.end(),
                              SourcedResourceName{ test::parseNameOrDie(u"@id/bar"), 3u }));
 
-    EXPECT_EQ(1u, std::count(doc->file.exportedSymbols.begin(), doc->file.exportedSymbols.end(),
+    EXPECT_EQ(1, std::count(doc->file.exportedSymbols.begin(), doc->file.exportedSymbols.end(),
                              SourcedResourceName{ test::parseNameOrDie(u"@id/car"), 6u }));
 }
 
diff --git a/tools/aapt2/flatten/TableFlattener.cpp b/tools/aapt2/flatten/TableFlattener.cpp
index a2f53e1..26d7c2c 100644
--- a/tools/aapt2/flatten/TableFlattener.cpp
+++ b/tools/aapt2/flatten/TableFlattener.cpp
@@ -113,8 +113,7 @@
     bool mUseExtendedChunks;
 
     size_t mEntryCount = 0;
-    Maybe<uint32_t> mParentIdent;
-    Maybe<ResourceNameRef> mParentName;
+    const Reference* mParent = nullptr;
 
     MapFlattenVisitor(SymbolWriter* symbols, FlatEntry* entry, BigBuffer* buffer,
                       StringPool* sourcePool, StringPool* commentPool,
@@ -227,13 +226,8 @@
 
     void visit(Style* style) override {
         if (style->parent) {
-            bool privateRef = style->parent.value().privateReference && mUseExtendedChunks;
-            if (!style->parent.value().id || privateRef) {
-                assert(style->parent.value().name && "reference must have a name");
-                mParentName = style->parent.value().name;
-            } else {
-                mParentIdent = style->parent.value().id.value().id;
-            }
+            // Parents are treated a bit differently, so record the existence and move on.
+            mParent = &style->parent.value();
         }
 
         // Sort the style.
@@ -427,11 +421,16 @@
                                       mOptions.useExtendedChunks);
             entry->value->accept(&visitor);
             outEntry->count = util::hostToDevice32(visitor.mEntryCount);
-            if (visitor.mParentName) {
-                mSymbols->addSymbol(visitor.mParentName.value(),
-                                    beforeEntry + offsetof(ResTable_entry_ext, parent));
-            } else if (visitor.mParentIdent) {
-                outEntry->parent.ident = util::hostToDevice32(visitor.mParentIdent.value());
+            if (visitor.mParent) {
+                const bool forceSymbol = visitor.mParent->privateReference &&
+                        mOptions.useExtendedChunks;
+                if (!visitor.mParent->id || forceSymbol) {
+                    assert(visitor.mParent->name && "reference must have a name");
+                    mSymbols->addSymbol(*visitor.mParent,
+                                        beforeEntry + offsetof(ResTable_entry_ext, parent));
+                } else {
+                    outEntry->parent.ident = util::hostToDevice32(visitor.mParent->id.value().id);
+                }
             }
         }
         return true;
diff --git a/tools/aapt2/io/Data.h b/tools/aapt2/io/Data.h
index 9081c55..467e604 100644
--- a/tools/aapt2/io/Data.h
+++ b/tools/aapt2/io/Data.h
@@ -79,6 +79,21 @@
     size_t mSize;
 };
 
+/**
+ * When mmap fails because the file has length 0, we use the EmptyData to simulate data of length 0.
+ */
+class EmptyData : public IData {
+public:
+    const void* data() const override {
+        static const uint8_t d = 0;
+        return &d;
+    }
+
+    size_t size() const override {
+        return 0u;
+    }
+};
+
 } // namespace io
 } // namespace aapt
 
diff --git a/tools/aapt2/io/FileSystem.cpp b/tools/aapt2/io/FileSystem.cpp
index 76f87ae..e758d8a4 100644
--- a/tools/aapt2/io/FileSystem.cpp
+++ b/tools/aapt2/io/FileSystem.cpp
@@ -32,7 +32,10 @@
 std::unique_ptr<IData> RegularFile::openAsData() {
     android::FileMap map;
     if (Maybe<android::FileMap> map = file::mmapPath(mSource.path, nullptr)) {
-        return util::make_unique<MmappedData>(std::move(map.value()));
+        if (map.value().getDataPtr() && map.value().getDataLength() > 0) {
+            return util::make_unique<MmappedData>(std::move(map.value()));
+        }
+        return util::make_unique<EmptyData>();
     }
     return {};
 }
diff --git a/tools/aapt2/io/ZipArchive.cpp b/tools/aapt2/io/ZipArchive.cpp
index bf0f4aa..329dac9 100644
--- a/tools/aapt2/io/ZipArchive.cpp
+++ b/tools/aapt2/io/ZipArchive.cpp
@@ -75,11 +75,19 @@
 
 std::unique_ptr<ZipFileCollection> ZipFileCollection::create(const StringPiece& path,
                                                              std::string* outError) {
+    constexpr static const int32_t kEmptyArchive = -6;
+
     std::unique_ptr<ZipFileCollection> collection = std::unique_ptr<ZipFileCollection>(
             new ZipFileCollection());
 
     int32_t result = OpenArchive(path.data(), &collection->mHandle);
     if (result != 0) {
+        // If a zip is empty, result will be an error code. This is fine and we should
+        // return an empty ZipFileCollection.
+        if (result == kEmptyArchive) {
+            return collection;
+        }
+
         if (outError) *outError = ErrorCodeString(result);
         return {};
     }
diff --git a/tools/aapt2/java/ProguardRules.cpp b/tools/aapt2/java/ProguardRules.cpp
index c096854..c610bb0 100644
--- a/tools/aapt2/java/ProguardRules.cpp
+++ b/tools/aapt2/java/ProguardRules.cpp
@@ -227,14 +227,14 @@
 bool writeKeepSet(std::ostream* out, const KeepSet& keepSet) {
     for (const auto& entry : keepSet.mKeepSet) {
         for (const Source& source : entry.second) {
-            *out << "// Referenced at " << source << "\n";
+            *out << "# Referenced at " << source << "\n";
         }
         *out << "-keep class " << entry.first << " { <init>(...); }\n" << std::endl;
     }
 
     for (const auto& entry : keepSet.mKeepMethodSet) {
         for (const Source& source : entry.second) {
-            *out << "// Referenced at " << source << "\n";
+            *out << "# Referenced at " << source << "\n";
         }
         *out << "-keepclassmembers class * { *** " << entry.first << "(...); }\n" << std::endl;
     }
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index 652e52f..3ecb2c4 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -51,16 +51,20 @@
     std::vector<std::string> includePaths;
     std::vector<std::string> overlayFiles;
     Maybe<std::string> generateJavaClassPath;
-    std::set<std::string> extraJavaPackages;
+    Maybe<std::u16string> customJavaPackage;
+    std::set<std::u16string> extraJavaPackages;
     Maybe<std::string> generateProguardRulesPath;
     bool noAutoVersion = false;
     bool staticLib = false;
+    bool generateNonFinalIds = false;
     bool verbose = false;
     bool outputToDirectory = false;
     bool autoAddOverlay = false;
+    bool doNotCompressAnything = false;
+    std::vector<std::string> extensionsToNotCompress;
     Maybe<std::u16string> privateSymbols;
-    Maybe<std::u16string> minSdkVersionDefault;
-    Maybe<std::u16string> targetSdkVersionDefault;
+    ManifestFixerOptions manifestFixerOptions;
+
 };
 
 struct LinkContext : public IAaptContext {
@@ -186,7 +190,20 @@
         return resFile;
     }
 
-    bool copyFileToArchive(io::IFile* file, const std::string& outPath, uint32_t flags,
+    uint32_t getCompressionFlags(const StringPiece& str) {
+        if (mOptions.doNotCompressAnything) {
+            return 0;
+        }
+
+        for (const std::string& extension : mOptions.extensionsToNotCompress) {
+            if (util::stringEndsWith<char>(str, extension)) {
+                return 0;
+            }
+        }
+        return ArchiveEntry::kCompress;
+    }
+
+    bool copyFileToArchive(io::IFile* file, const std::string& outPath,
                            IArchiveWriter* writer) {
         std::unique_ptr<io::IData> data = file->openAsData();
         if (!data) {
@@ -202,7 +219,7 @@
             return false;
         }
 
-        if (writer->startEntry(outPath, flags)) {
+        if (writer->startEntry(outPath, getCompressionFlags(outPath))) {
             if (writer->writeEntry(reinterpret_cast<const uint8_t*>(data->data()) + offset,
                                    data->size() - static_cast<size_t>(offset))) {
                 if (writer->finishEntry()) {
@@ -228,29 +245,53 @@
         return {};
     }
 
+    /**
+     * Precondition: ResourceTable doesn't have any IDs assigned yet, nor is it linked.
+     * Postcondition: ResourceTable has only one package left. All others are stripped, or there
+     *                is an error and false is returned.
+     */
     bool verifyNoExternalPackages() {
+        auto isExtPackageFunc = [&](const std::unique_ptr<ResourceTablePackage>& pkg) -> bool {
+            return mContext.getCompilationPackage() != pkg->name ||
+                    !pkg->id ||
+                    pkg->id.value() != mContext.getPackageId();
+        };
+
         bool error = false;
         for (const auto& package : mFinalTable.packages) {
-            if (mContext.getCompilationPackage() != package->name ||
-                    !package->id || package->id.value() != mContext.getPackageId()) {
+            if (isExtPackageFunc(package)) {
                 // We have a package that is not related to the one we're building!
                 for (const auto& type : package->types) {
                     for (const auto& entry : type->entries) {
+                        ResourceNameRef resName(package->name, type->type, entry->name);
+
                         for (const auto& configValue : entry->values) {
-                            mContext.getDiagnostics()->error(
-                                    DiagMessage(configValue.value->getSource())
-                                                << "defined resource '"
-                                                << ResourceNameRef(package->name,
-                                                                   type->type,
-                                                                   entry->name)
-                                                << "' for external package '"
-                                                << package->name << "'");
-                            error = true;
+                            // Special case the occurrence of an ID that is being generated for the
+                            // 'android' package. This is due to legacy reasons.
+                            if (valueCast<Id>(configValue.value.get()) &&
+                                    package->name == u"android") {
+                                mContext.getDiagnostics()->warn(
+                                        DiagMessage(configValue.value->getSource())
+                                        << "generated id '" << resName
+                                        << "' for external package '" << package->name
+                                        << "'");
+                            } else {
+                                mContext.getDiagnostics()->error(
+                                        DiagMessage(configValue.value->getSource())
+                                        << "defined resource '" << resName
+                                        << "' for external package '" << package->name
+                                        << "'");
+                                error = true;
+                            }
                         }
                     }
                 }
             }
         }
+
+        auto newEndIter = std::remove_if(mFinalTable.packages.begin(), mFinalTable.packages.end(),
+                                         isExtPackageFunc);
+        mFinalTable.packages.erase(newEndIter, mFinalTable.packages.end());
         return !error;
     }
 
@@ -295,7 +336,6 @@
             return false;
         }
 
-
         if (writer->startEntry(path, ArchiveEntry::kCompress)) {
             if (writer->writeEntry(buffer)) {
                 if (writer->finishEntry()) {
@@ -484,7 +524,10 @@
     }
 
     bool processFile(const std::string& path, bool override) {
-        if (util::stringEndsWith<char>(path, ".flata")) {
+        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);
         }
 
@@ -496,7 +539,7 @@
         const Source& src = file->getSource();
         if (util::stringEndsWith<char>(src.path, ".arsc.flat")) {
             return mergeResourceTable(file, override);
-        } else {
+        } 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();
             if (!data) {
@@ -509,8 +552,13 @@
             if (resourceFile) {
                 return mergeCompiledFile(file, std::move(resourceFile), override);
             }
+
+            return false;
         }
-        return false;
+
+        // Ignore non .flat files. This could be classes.dex or something else that happens
+        // to be in an archive.
+        return true;
     }
 
     int run(const std::vector<std::string>& inputFiles) {
@@ -622,10 +670,7 @@
 
         bool error = false;
         {
-            ManifestFixerOptions manifestFixerOptions;
-            manifestFixerOptions.minSdkVersionDefault = mOptions.minSdkVersionDefault;
-            manifestFixerOptions.targetSdkVersionDefault = mOptions.targetSdkVersionDefault;
-            ManifestFixer manifestFixer(manifestFixerOptions);
+            ManifestFixer manifestFixer(mOptions.manifestFixerOptions);
             if (!manifestFixer.consume(&mContext, manifestXml.get())) {
                 error = true;
             }
@@ -762,7 +807,7 @@
                     mContext.getDiagnostics()->note(DiagMessage() << "copying " << path);
                 }
 
-                if (!copyFileToArchive(fileToMerge.file, fileToMerge.dstPath, 0,
+                if (!copyFileToArchive(fileToMerge.file, fileToMerge.dstPath,
                                        archiveWriter.get())) {
                     error = true;
                 }
@@ -789,12 +834,18 @@
 
         if (mOptions.generateJavaClassPath) {
             JavaClassGeneratorOptions options;
-            if (mOptions.staticLib) {
+            options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
+
+            if (mOptions.staticLib || mOptions.generateNonFinalIds) {
                 options.useFinal = false;
             }
 
-            StringPiece16 actualPackage = mContext.getCompilationPackage();
+            const StringPiece16 actualPackage = mContext.getCompilationPackage();
             StringPiece16 outputPackage = mContext.getCompilationPackage();
+            if (mOptions.customJavaPackage) {
+                // Override the output java package to the custom one.
+                outputPackage = mOptions.customJavaPackage.value();
+            }
 
             if (mOptions.privateSymbols) {
                 // If we defined a private symbols package, we only emit Public symbols
@@ -802,7 +853,7 @@
 
                 options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
                 if (!writeJavaFile(&mFinalTable, mContext.getCompilationPackage(),
-                                   mContext.getCompilationPackage(), options)) {
+                                   outputPackage, options)) {
                     return 1;
                 }
 
@@ -814,9 +865,8 @@
                 return 1;
             }
 
-            for (const std::string& extraPackage : mOptions.extraJavaPackages) {
-                if (!writeJavaFile(&mFinalTable, actualPackage, util::utf8ToUtf16(extraPackage),
-                                   options)) {
+            for (const std::u16string& extraPackage : mOptions.extraJavaPackages) {
+                if (!writeJavaFile(&mFinalTable, actualPackage, extraPackage, options)) {
                     return 1;
                 }
             }
@@ -853,13 +903,18 @@
     LinkOptions options;
     Maybe<std::string> privateSymbolsPackage;
     Maybe<std::string> minSdkVersion, targetSdkVersion;
+    Maybe<std::string> renameManifestPackage, renameInstrumentationTargetPackage;
+    Maybe<std::string> versionCode, versionName;
+    Maybe<std::string> customJavaPackage;
     std::vector<std::string> extraJavaPackages;
+    bool legacyXFlag = false;
+    bool requireLocalization = false;
     Flags flags = Flags()
             .requiredFlag("-o", "Output path", &options.outputPath)
             .requiredFlag("--manifest", "Path to the Android manifest to build",
                           &options.manifestPath)
             .optionalFlagList("-I", "Adds an Android APK to link against", &options.includePaths)
-            .optionalFlagList("-R", "Compilation unit to link, using `overlay` semantics. "
+            .optionalFlagList("-R", "Compilation unit to link, using `overlay` semantics.\n"
                               "The last conflicting resource given takes precedence.",
                               &options.overlayFiles)
             .optionalFlag("--java", "Directory in which to generate R.java",
@@ -869,6 +924,10 @@
             .optionalSwitch("--no-auto-version",
                             "Disables automatic style and layout SDK versioning",
                             &options.noAutoVersion)
+            .optionalSwitch("-x", "Legacy flag that specifies to use the package identifier 0x01",
+                            &legacyXFlag)
+            .optionalSwitch("-z", "Require localization of strings marked 'suggested'",
+                            &requireLocalization)
             .optionalSwitch("--output-to-dir", "Outputs the APK contents to a directory specified "
                             "by -o",
                             &options.outputToDirectory)
@@ -876,15 +935,32 @@
                           "AndroidManifest.xml", &minSdkVersion)
             .optionalFlag("--target-sdk-version", "Default target SDK version to use for "
                           "AndroidManifest.xml", &targetSdkVersion)
+            .optionalFlag("--version-code", "Version code (integer) to inject into the "
+                          "AndroidManifest.xml if none is present", &versionCode)
+            .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("--non-final-ids", "Generates R.java without the final modifier.\n"
+                            "This is implied when --static-lib is specified.",
+                            &options.generateNonFinalIds)
             .optionalFlag("--private-symbols", "Package name to use when generating R.java for "
                           "private symbols.\n"
                           "If not specified, public and private symbols will use the application's "
                           "package name", &privateSymbolsPackage)
+            .optionalFlag("--custom-package", "Custom Java package under which to generate R.java",
+                          &customJavaPackage)
             .optionalFlagList("--extra-packages", "Generate the same R.java but with different "
                               "package names", &extraJavaPackages)
             .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",
+                          &renameManifestPackage)
+            .optionalFlag("--rename-instrumentation-target-package",
+                          "Changes the name of the target package for instrumentation. Most useful "
+                          "when used\nin conjunction with --rename-manifest-package",
+                          &renameInstrumentationTargetPackage)
+            .optionalFlagList("-0", "File extensions not to compress",
+                              &options.extensionsToNotCompress)
             .optionalSwitch("-v", "Enables verbose logging", &options.verbose);
 
     if (!flags.parse("aapt2 link", args, &std::cerr)) {
@@ -896,18 +972,42 @@
     }
 
     if (minSdkVersion) {
-        options.minSdkVersionDefault = util::utf8ToUtf16(minSdkVersion.value());
+        options.manifestFixerOptions.minSdkVersionDefault =
+                util::utf8ToUtf16(minSdkVersion.value());
     }
 
     if (targetSdkVersion) {
-        options.targetSdkVersionDefault = util::utf8ToUtf16(targetSdkVersion.value());
+        options.manifestFixerOptions.targetSdkVersionDefault =
+                util::utf8ToUtf16(targetSdkVersion.value());
+    }
+
+    if (renameManifestPackage) {
+        options.manifestFixerOptions.renameManifestPackage =
+                util::utf8ToUtf16(renameManifestPackage.value());
+    }
+
+    if (renameInstrumentationTargetPackage) {
+        options.manifestFixerOptions.renameInstrumentationTargetPackage =
+                util::utf8ToUtf16(renameInstrumentationTargetPackage.value());
+    }
+
+    if (versionCode) {
+        options.manifestFixerOptions.versionCodeDefault = util::utf8ToUtf16(versionCode.value());
+    }
+
+    if (versionName) {
+        options.manifestFixerOptions.versionNameDefault = util::utf8ToUtf16(versionName.value());
+    }
+
+    if (customJavaPackage) {
+        options.customJavaPackage = util::utf8ToUtf16(customJavaPackage.value());
     }
 
     // Populate the set of extra packages for which to generate R.java.
     for (std::string& extraPackage : extraJavaPackages) {
         // A given package can actually be a colon separated list of packages.
         for (StringPiece package : util::split(extraPackage, ':')) {
-            options.extraJavaPackages.insert(package.toString());
+            options.extraJavaPackages.insert(util::utf8ToUtf16(package));
         }
     }
 
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 2034c57..9baf1d8 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -22,25 +22,43 @@
 namespace aapt {
 
 static bool verifyManifest(IAaptContext* context, const Source& source, xml::Element* manifestEl) {
-    bool error = false;
-
     xml::Attribute* attr = manifestEl->findAttribute({}, u"package");
     if (!attr) {
         context->getDiagnostics()->error(DiagMessage(source.withLine(manifestEl->lineNumber))
                                          << "missing 'package' attribute");
-        error = true;
     } else if (ResourceUtils::isReference(attr->value)) {
         context->getDiagnostics()->error(DiagMessage(source.withLine(manifestEl->lineNumber))
                                          << "value for attribute 'package' must not be a "
                                             "reference");
-        error = true;
     } else if (!util::isJavaPackageName(attr->value)) {
         context->getDiagnostics()->error(DiagMessage(source.withLine(manifestEl->lineNumber))
                                          << "invalid package name '" << attr->value << "'");
-        error = true;
+    } else {
+        return true;
+    }
+    return false;
+}
+
+static bool includeVersionName(IAaptContext* context, const Source& source,
+                               const StringPiece16& versionName, xml::Element* manifestEl) {
+    if (manifestEl->findAttribute(xml::kSchemaAndroid, u"versionName")) {
+        return true;
     }
 
-    return !error;
+    manifestEl->attributes.push_back(xml::Attribute{
+            xml::kSchemaAndroid, u"versionName", versionName.toString() });
+    return true;
+}
+
+static bool includeVersionCode(IAaptContext* context, const Source& source,
+                               const StringPiece16& versionCode, xml::Element* manifestEl) {
+    if (manifestEl->findAttribute(xml::kSchemaAndroid, u"versionCode")) {
+        return true;
+    }
+
+    manifestEl->attributes.push_back(xml::Attribute{
+            xml::kSchemaAndroid, u"versionCode", versionCode.toString() });
+    return true;
 }
 
 static bool fixUsesSdk(IAaptContext* context, const Source& source, xml::Element* el,
@@ -62,6 +80,76 @@
     return true;
 }
 
+class FullyQualifiedClassNameVisitor : public xml::Visitor {
+public:
+    using xml::Visitor::visit;
+
+    FullyQualifiedClassNameVisitor(const StringPiece16& package) : mPackage(package) {
+    }
+
+    void visit(xml::Element* el) override {
+        for (xml::Attribute& attr : el->attributes) {
+            if (Maybe<std::u16string> newValue =
+                    util::getFullyQualifiedClassName(mPackage, attr.value)) {
+                attr.value = std::move(newValue.value());
+            }
+        }
+
+        // Super implementation to iterate over the children.
+        xml::Visitor::visit(el);
+    }
+
+private:
+    StringPiece16 mPackage;
+};
+
+static bool renameManifestPackage(IAaptContext* context, const Source& source,
+                                  const StringPiece16& packageOverride, xml::Element* manifestEl) {
+    if (!util::isJavaPackageName(packageOverride)) {
+        context->getDiagnostics()->error(DiagMessage() << "invalid manifest package override '"
+                                         << packageOverride << "'");
+        return false;
+    }
+
+    xml::Attribute* attr = manifestEl->findAttribute({}, u"package");
+
+    // We've already verified that the manifest element is present, with a package name specified.
+    assert(attr);
+
+    std::u16string originalPackage = std::move(attr->value);
+    attr->value = packageOverride.toString();
+
+    FullyQualifiedClassNameVisitor visitor(originalPackage);
+    manifestEl->accept(&visitor);
+    return true;
+}
+
+static bool renameInstrumentationTargetPackage(IAaptContext* context, const Source& source,
+                                               const StringPiece16& packageOverride,
+                                               xml::Element* manifestEl) {
+    if (!util::isJavaPackageName(packageOverride)) {
+        context->getDiagnostics()->error(DiagMessage()
+                                         << "invalid instrumentation target package override '"
+                                         << packageOverride << "'");
+        return false;
+    }
+
+    xml::Element* instrumentationEl = manifestEl->findChild({}, u"instrumentation");
+    if (!instrumentationEl) {
+        // No error if there is no work to be done.
+        return true;
+    }
+
+    xml::Attribute* attr = instrumentationEl->findAttribute(xml::kSchemaAndroid, u"targetPackage");
+    if (!attr) {
+        // No error if there is no work to be done.
+        return true;
+    }
+
+    attr->value = packageOverride.toString();
+    return true;
+}
+
 bool ManifestFixer::consume(IAaptContext* context, xml::XmlResource* doc) {
     xml::Element* root = xml::findRootElement(doc->root.get());
     if (!root || !root->namespaceUri.empty() || root->name != u"manifest") {
@@ -74,6 +162,36 @@
         return false;
     }
 
+    if (mOptions.versionCodeDefault) {
+        if (!includeVersionCode(context, doc->file.source, mOptions.versionCodeDefault.value(),
+                                root)) {
+            return false;
+        }
+    }
+
+    if (mOptions.versionNameDefault) {
+        if (!includeVersionName(context, doc->file.source, mOptions.versionNameDefault.value(),
+                                root)) {
+            return false;
+        }
+    }
+
+    if (mOptions.renameManifestPackage) {
+        // Rename manifest package.
+        if (!renameManifestPackage(context, doc->file.source,
+                                   mOptions.renameManifestPackage.value(), root)) {
+            return false;
+        }
+    }
+
+    if (mOptions.renameInstrumentationTargetPackage) {
+        if (!renameInstrumentationTargetPackage(context, doc->file.source,
+                                                mOptions.renameInstrumentationTargetPackage.value(),
+                                                root)) {
+            return false;
+        }
+    }
+
     bool foundUsesSdk = false;
     for (xml::Element* el : root->getChildElements()) {
         if (!el->namespaceUri.empty()) {
diff --git a/tools/aapt2/link/ManifestFixer.h b/tools/aapt2/link/ManifestFixer.h
index a77e6d5..b8d9c83 100644
--- a/tools/aapt2/link/ManifestFixer.h
+++ b/tools/aapt2/link/ManifestFixer.h
@@ -28,6 +28,10 @@
 struct ManifestFixerOptions {
     Maybe<std::u16string> minSdkVersionDefault;
     Maybe<std::u16string> targetSdkVersionDefault;
+    Maybe<std::u16string> renameManifestPackage;
+    Maybe<std::u16string> renameInstrumentationTargetPackage;
+    Maybe<std::u16string> versionNameDefault;
+    Maybe<std::u16string> versionCodeDefault;
 };
 
 /**
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index f6bf895..f40fbfb 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -82,8 +82,6 @@
     EXPECT_EQ(nullptr, verify("<manifest package=\"@string/str\" />"));
 }
 
-
-
 TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) {
     ManifestFixerOptions options = { std::u16string(u"8"), std::u16string(u"22") };
 
@@ -97,7 +95,7 @@
     xml::Element* el;
     xml::Attribute* attr;
 
-    el = xml::findRootElement(doc->root.get());
+    el = xml::findRootElement(doc.get());
     ASSERT_NE(nullptr, el);
     el = el->findChild({}, u"uses-sdk");
     ASSERT_NE(nullptr, el);
@@ -115,7 +113,7 @@
       </manifest>)EOF", options);
     ASSERT_NE(nullptr, doc);
 
-    el = xml::findRootElement(doc->root.get());
+    el = xml::findRootElement(doc.get());
     ASSERT_NE(nullptr, el);
     el = el->findChild({}, u"uses-sdk");
     ASSERT_NE(nullptr, el);
@@ -133,7 +131,7 @@
       </manifest>)EOF", options);
     ASSERT_NE(nullptr, doc);
 
-    el = xml::findRootElement(doc->root.get());
+    el = xml::findRootElement(doc.get());
     ASSERT_NE(nullptr, el);
     el = el->findChild({}, u"uses-sdk");
     ASSERT_NE(nullptr, el);
@@ -149,7 +147,7 @@
                 package="android" />)EOF", options);
     ASSERT_NE(nullptr, doc);
 
-    el = xml::findRootElement(doc->root.get());
+    el = xml::findRootElement(doc.get());
     ASSERT_NE(nullptr, el);
     el = el->findChild({}, u"uses-sdk");
     ASSERT_NE(nullptr, el);
@@ -161,4 +159,98 @@
     EXPECT_EQ(u"22", attr->value);
 }
 
+TEST_F(ManifestFixerTest, RenameManifestPackageAndFullyQualifyClasses) {
+    ManifestFixerOptions options;
+    options.renameManifestPackage = std::u16string(u"com.android");
+
+    std::unique_ptr<xml::XmlResource> doc = verifyWithOptions(R"EOF(
+      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+                package="android">
+        <application name=".MainApplication" text="hello">
+          <activity name=".activity.Start" />
+          <receiver name="com.google.android.Receiver" />
+        </application>
+      </manifest>)EOF", options);
+    ASSERT_NE(nullptr, doc);
+
+    xml::Element* manifestEl = xml::findRootElement(doc.get());
+    ASSERT_NE(nullptr, manifestEl);
+
+    xml::Attribute* attr = nullptr;
+
+    attr = manifestEl->findAttribute({}, u"package");
+    ASSERT_NE(nullptr, attr);
+    EXPECT_EQ(std::u16string(u"com.android"), attr->value);
+
+    xml::Element* applicationEl = manifestEl->findChild({}, u"application");
+    ASSERT_NE(nullptr, applicationEl);
+
+    attr = applicationEl->findAttribute({}, u"name");
+    ASSERT_NE(nullptr, attr);
+    EXPECT_EQ(std::u16string(u"android.MainApplication"), attr->value);
+
+    attr = applicationEl->findAttribute({}, u"text");
+    ASSERT_NE(nullptr, attr);
+    EXPECT_EQ(std::u16string(u"hello"), attr->value);
+
+    xml::Element* el;
+    el = applicationEl->findChild({}, u"activity");
+    ASSERT_NE(nullptr, el);
+
+    attr = el->findAttribute({}, u"name");
+    ASSERT_NE(nullptr, el);
+    EXPECT_EQ(std::u16string(u"android.activity.Start"), attr->value);
+
+    el = applicationEl->findChild({}, u"receiver");
+    ASSERT_NE(nullptr, el);
+
+    attr = el->findAttribute({}, u"name");
+    ASSERT_NE(nullptr, el);
+    EXPECT_EQ(std::u16string(u"com.google.android.Receiver"), attr->value);
+}
+
+TEST_F(ManifestFixerTest, RenameManifestInstrumentationPackageAndFullyQualifyTarget) {
+    ManifestFixerOptions options;
+    options.renameInstrumentationTargetPackage = std::u16string(u"com.android");
+
+    std::unique_ptr<xml::XmlResource> doc = verifyWithOptions(R"EOF(
+      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+                package="android">
+        <instrumentation android:targetPackage="android" />
+      </manifest>)EOF", options);
+    ASSERT_NE(nullptr, doc);
+
+    xml::Element* manifestEl = xml::findRootElement(doc.get());
+    ASSERT_NE(nullptr, manifestEl);
+
+    xml::Element* instrumentationEl = manifestEl->findChild({}, u"instrumentation");
+    ASSERT_NE(nullptr, instrumentationEl);
+
+    xml::Attribute* attr = instrumentationEl->findAttribute(xml::kSchemaAndroid, u"targetPackage");
+    ASSERT_NE(nullptr, attr);
+    EXPECT_EQ(std::u16string(u"com.android"), attr->value);
+}
+
+TEST_F(ManifestFixerTest, UseDefaultVersionNameAndCode) {
+    ManifestFixerOptions options;
+    options.versionNameDefault = std::u16string(u"Beta");
+    options.versionCodeDefault = std::u16string(u"0x10000000");
+
+    std::unique_ptr<xml::XmlResource> doc = verifyWithOptions(R"EOF(
+      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+                package="android" />)EOF", options);
+    ASSERT_NE(nullptr, doc);
+
+    xml::Element* manifestEl = xml::findRootElement(doc.get());
+    ASSERT_NE(nullptr, manifestEl);
+
+    xml::Attribute* attr = manifestEl->findAttribute(xml::kSchemaAndroid, u"versionName");
+    ASSERT_NE(nullptr, attr);
+    EXPECT_EQ(std::u16string(u"Beta"), attr->value);
+
+    attr = manifestEl->findAttribute(xml::kSchemaAndroid, u"versionCode");
+    ASSERT_NE(nullptr, attr);
+    EXPECT_EQ(std::u16string(u"0x10000000"), attr->value);
+}
+
 } // namespace aapt
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index f8e3d03..93a11b9 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -68,6 +68,12 @@
         return addValue(name, id, util::make_unique<String>(mTable->stringPool.makeRef(str)));
     }
 
+    ResourceTableBuilder& addString(const StringPiece16& name, const ResourceId id,
+                                    const ConfigDescription& config, const StringPiece16& str) {
+        return addValue(name, id, config,
+                        util::make_unique<String>(mTable->stringPool.makeRef(str)));
+    }
+
     ResourceTableBuilder& addFileReference(const StringPiece16& name, const StringPiece16& path) {
         return addFileReference(name, {}, path);
     }
diff --git a/tools/aapt2/unflatten/BinaryResourceParser.cpp b/tools/aapt2/unflatten/BinaryResourceParser.cpp
index 21e476f..6b7a63cf 100644
--- a/tools/aapt2/unflatten/BinaryResourceParser.cpp
+++ b/tools/aapt2/unflatten/BinaryResourceParser.cpp
@@ -585,6 +585,13 @@
                 source.path = path.toString();
             }
             source.line = util::deviceToHost32(sourceBlock->line);
+
+            if (Style* style = valueCast<Style>(resourceValue.get())) {
+                // The parent's source is the same as the resource itself, set it here.
+                if (style->parent) {
+                    style->parent.value().setSource(source);
+                }
+            }
         }
 
         StringPiece16 comment = util::getString(mSourcePool,
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index a81dc7b..04e8199 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -163,6 +163,11 @@
     }
 
     android::FileMap fileMap;
+    if (fileStats.st_size == 0) {
+        // mmap doesn't like a length of 0. Instead we return an empty FileMap.
+        return std::move(fileMap);
+    }
+
     if (!fileMap.create(path.data(), fd, 0, fileStats.st_size, true)) {
         if (outError) *outError = strerror(errno);
         return {};
diff --git a/tools/aapt2/util/ImmutableMap.h b/tools/aapt2/util/ImmutableMap.h
new file mode 100644
index 0000000..b1f9e9d
--- /dev/null
+++ b/tools/aapt2/util/ImmutableMap.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_UTIL_IMMUTABLEMAP_H
+#define AAPT_UTIL_IMMUTABLEMAP_H
+
+#include "util/TypeTraits.h"
+
+#include <utility>
+#include <vector>
+
+namespace aapt {
+
+template <typename TKey, typename TValue>
+class ImmutableMap {
+    static_assert(is_comparable<TKey, TKey>::value, "key is not comparable");
+
+private:
+    std::vector<std::pair<TKey, TValue>> mData;
+
+    explicit ImmutableMap(std::vector<std::pair<TKey, TValue>> data) : mData(std::move(data)) {
+    }
+
+public:
+    using const_iterator = typename decltype(mData)::const_iterator;
+
+    ImmutableMap(ImmutableMap&&) = default;
+    ImmutableMap& operator=(ImmutableMap&&) = default;
+
+    ImmutableMap(const ImmutableMap&) = delete;
+    ImmutableMap& operator=(const ImmutableMap&) = delete;
+
+    static ImmutableMap<TKey, TValue> createPreSorted(
+            std::initializer_list<std::pair<TKey, TValue>> list) {
+        return ImmutableMap(std::vector<std::pair<TKey, TValue>>(list.begin(), list.end()));
+    }
+
+    static ImmutableMap<TKey, TValue> createAndSort(
+            std::initializer_list<std::pair<TKey, TValue>> list) {
+        std::vector<std::pair<TKey, TValue>> data(list.begin(), list.end());
+        std::sort(data.begin(), data.end());
+        return ImmutableMap(std::move(data));
+    }
+
+    template <typename TKey2,
+              typename = typename std::enable_if<is_comparable<TKey, TKey2>::value>::type>
+    const_iterator find(const TKey2& key) const {
+        auto cmp = [](const std::pair<TKey, TValue>& candidate, const TKey2& target) -> bool {
+            return candidate.first < target;
+        };
+
+        const_iterator endIter = end();
+        auto iter = std::lower_bound(mData.begin(), endIter, key, cmp);
+        if (iter == endIter || iter->first == key) {
+            return iter;
+        }
+        return endIter;
+    }
+
+    const_iterator begin() const {
+        return mData.begin();
+    }
+
+    const_iterator end() const {
+        return mData.end();
+    }
+};
+
+} // namespace aapt
+
+#endif /* AAPT_UTIL_IMMUTABLEMAP_H */
diff --git a/tools/aapt2/util/TypeTraits.h b/tools/aapt2/util/TypeTraits.h
new file mode 100644
index 0000000..76c13d6
--- /dev/null
+++ b/tools/aapt2/util/TypeTraits.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_UTIL_TYPETRAITS_H
+#define AAPT_UTIL_TYPETRAITS_H
+
+#include <type_traits>
+
+namespace aapt {
+
+#define DEFINE_HAS_BINARY_OP_TRAIT(name, op) \
+    template <typename T, typename U> \
+    struct name { \
+        template <typename V, typename W> \
+        static constexpr decltype(std::declval<V>() op std::declval<W>(), bool()) test(int) { \
+        return true; \
+    } \
+    template <typename V, typename W> \
+    static constexpr bool test(...) { \
+        return false; \
+    } \
+    static constexpr bool value = test<T, U>(int()); \
+}
+
+DEFINE_HAS_BINARY_OP_TRAIT(has_eq_op, ==);
+DEFINE_HAS_BINARY_OP_TRAIT(has_lt_op, <);
+
+/**
+ * Type trait that checks if two types can be equated (==) and compared (<).
+ */
+template <typename T, typename U>
+struct is_comparable {
+    static constexpr bool value = has_eq_op<T, U>::value && has_lt_op<T, U>::value;
+};
+
+} // namespace aapt
+
+#endif /* AAPT_UTIL_TYPETRAITS_H */
diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp
index 9ecc974..7b0c71d 100644
--- a/tools/aapt2/util/Util.cpp
+++ b/tools/aapt2/util/Util.cpp
@@ -175,10 +175,11 @@
         return {};
     }
 
-    std::u16string result(package.data(), package.size());
     if (className.data()[0] != u'.') {
-        result += u'.';
+        return {};
     }
+
+    std::u16string result(package.data(), package.size());
     result.append(className.data(), className.size());
     if (!isJavaClassName(result)) {
         return {};
diff --git a/tools/aapt2/util/Util_test.cpp b/tools/aapt2/util/Util_test.cpp
index 9208e07..1e0c7fa 100644
--- a/tools/aapt2/util/Util_test.cpp
+++ b/tools/aapt2/util/Util_test.cpp
@@ -144,8 +144,7 @@
 
 TEST(UtilTest, FullyQualifiedClassName) {
     Maybe<std::u16string> res = util::getFullyQualifiedClassName(u"android", u"asdf");
-    AAPT_ASSERT_TRUE(res);
-    EXPECT_EQ(res.value(), u"android.asdf");
+    AAPT_ASSERT_FALSE(res);
 
     res = util::getFullyQualifiedClassName(u"android", u".asdf");
     AAPT_ASSERT_TRUE(res);
diff --git a/tools/layoutlib/.idea/compiler.xml b/tools/layoutlib/.idea/compiler.xml
index 5aaaf18..35961a2 100644
--- a/tools/layoutlib/.idea/compiler.xml
+++ b/tools/layoutlib/.idea/compiler.xml
@@ -21,7 +21,5 @@
         <processorPath useClasspath="true" />
       </profile>
     </annotationProcessing>
-    <bytecodeTargetLevel target="1.6" />
   </component>
-</project>
-
+</project>
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java b/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
index 54021c9..28a489a 100644
--- a/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
@@ -64,7 +64,8 @@
     private static long registerMethod(Class<?> targetClass, String methodName, Class[] types,
             int nArgs) {
         // Encode the number of arguments in the method name
-        String methodIndexName = String.format("%1$s#%2$d", methodName, nArgs);
+        String methodIndexName = String.format("%1$s.%2$s#%3$d", targetClass.getSimpleName(),
+                methodName, nArgs);
         synchronized (sMethodIndexLock) {
             Long methodId = METHOD_NAME_TO_ID.get(methodIndexName);
 
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index 31dd3d9..db4c6dc6 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -327,12 +327,19 @@
             return null;
         }
 
-        // let the framework inflate the ColorStateList from the XML file.
-        File f = new File(value);
-        if (f.isFile()) {
-            try {
-                XmlPullParser parser = ParserFactory.create(f);
 
+        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 {
@@ -341,18 +348,18 @@
                 } 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;
             }
+        } 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 {
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
index 60514b6..8d5863b 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
@@ -122,4 +122,35 @@
     /*package*/ static boolean nativeIsSeekable(FileDescriptor fd) {
         return true;
     }
+
+    /**
+     * Set the newly decoded bitmap's density based on the Options.
+     *
+     * Copied from {@link BitmapFactory#setDensityFromOptions(Bitmap, Options)}.
+     */
+    @LayoutlibDelegate
+    /*package*/ static void setDensityFromOptions(Bitmap outputBitmap, Options opts) {
+        if (outputBitmap == null || opts == null) return;
+
+        final int density = opts.inDensity;
+        if (density != 0) {
+            outputBitmap.setDensity(density);
+            final int targetDensity = opts.inTargetDensity;
+            if (targetDensity == 0 || density == targetDensity || density == opts.inScreenDensity) {
+                return;
+            }
+
+            // --- Change from original implementation begins ---
+            // LayoutLib doesn't scale the nine patch when decoding it. Hence, don't change the
+            // density of the source bitmap in case of ninepatch.
+
+            if (opts.inScaled) {
+            // --- Change from original implementation ends. ---
+                outputBitmap.setDensity(targetDensity);
+            }
+        } else if (opts.inBitmap != null) {
+            // bitmap was reused, ensure density is reset
+            outputBitmap.setDensity(Bitmap.getDefaultDensity());
+        }
+    }
 }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 64cd503..ba0d399 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -35,7 +35,6 @@
 import java.awt.Shape;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Arc2D;
-import java.awt.geom.Path2D;
 import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
 
@@ -713,8 +712,27 @@
                         if (bounds.isEmpty()) {
                             // Apple JRE 1.6 doesn't like drawing empty shapes.
                             // http://b.android.com/178278
-                            return;
+
+                            if (pathDelegate.isEmpty()) {
+                                // This means that the path doesn't have any lines or curves so
+                                // nothing to draw.
+                                return;
+                            }
+
+                            // The stroke width is not consider for the size of the bounds so,
+                            // for example, a horizontal line, would be considered as an empty
+                            // rectangle.
+                            // If the strokeWidth is not 0, we use it to consider the size of the
+                            // path as well.
+                            float strokeWidth = paintDelegate.getStrokeWidth();
+                            if (strokeWidth <= 0.0f) {
+                                return;
+                            }
+                            bounds.setRect(bounds.getX(), bounds.getY(),
+                                    Math.max(strokeWidth, bounds.getWidth()),
+                                    Math.max(strokeWidth, bounds.getHeight()));
                         }
+
                         int style = paintDelegate.getStyle();
 
                         if (style == Paint.Style.FILL.nativeInt ||
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index a545283..dbd45c4 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -152,11 +152,7 @@
      * returns the value of stroke miter needed by the java api.
      */
     public float getJavaStrokeMiter() {
-        float miter = mStrokeMiter * mStrokeWidth;
-        if (miter < 1.f) {
-            miter = 1.f;
-        }
-        return miter;
+        return mStrokeMiter;
     }
 
     public int getJavaCap() {
diff --git a/tools/layoutlib/bridge/src/android/graphics/PathMeasure_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PathMeasure_Delegate.java
index 3c71233..fc9b4f7 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PathMeasure_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PathMeasure_Delegate.java
@@ -19,10 +19,12 @@
 import com.android.ide.common.rendering.api.LayoutLog;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.layoutlib.bridge.util.CachedPathIteratorFactory;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
+import com.android.layoutlib.bridge.util.CachedPathIteratorFactory.CachedPathIterator;
+
 import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
 
 /**
  * Delegate implementing the native methods of {@link android.graphics.PathMeasure}
@@ -38,35 +40,30 @@
  * @see DelegateManager
  */
 public final class PathMeasure_Delegate {
+
     // ---- delegate manager ----
     private static final DelegateManager<PathMeasure_Delegate> sManager =
             new DelegateManager<PathMeasure_Delegate>(PathMeasure_Delegate.class);
 
     // ---- delegate data ----
-    // This governs how accurate the approximation of the Path is.
-    private static final float PRECISION = 0.0002f;
+    private CachedPathIteratorFactory mOriginalPathIterator;
 
-    /**
-     * Array containing the path points components. There are three components for each point:
-     * <ul>
-     *     <li>Fraction along the length of the path that the point resides</li>
-     *     <li>The x coordinate of the point</li>
-     *     <li>The y coordinate of the point</li>
-     * </ul>
-     */
-    private float mPathPoints[];
     private long mNativePath;
 
+
     private PathMeasure_Delegate(long native_path, boolean forceClosed) {
         mNativePath = native_path;
-        if (forceClosed && mNativePath != 0) {
-            // Copy the path and call close
-            mNativePath = Path_Delegate.init2(native_path);
-            Path_Delegate.native_close(mNativePath);
-        }
+        if (native_path != 0) {
+            if (forceClosed) {
+                // Copy the path and call close
+                native_path = Path_Delegate.init2(native_path);
+                Path_Delegate.native_close(native_path);
+            }
 
-        mPathPoints =
-                mNativePath != 0 ? Path_Delegate.native_approximate(mNativePath, PRECISION) : null;
+            Path_Delegate pathDelegate = Path_Delegate.getDelegate(native_path);
+            mOriginalPathIterator = new CachedPathIteratorFactory(pathDelegate.getJavaShape()
+                    .getPathIterator(null));
+        }
     }
 
     @LayoutlibDelegate
@@ -108,13 +105,19 @@
         PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance);
         assert pathMeasure != null;
 
-        if (forceClosed && native_path != 0) {
-            // Copy the path and call close
-            native_path = Path_Delegate.init2(native_path);
-            Path_Delegate.native_close(native_path);
+        if (native_path != 0) {
+            if (forceClosed) {
+                // Copy the path and call close
+                native_path = Path_Delegate.init2(native_path);
+                Path_Delegate.native_close(native_path);
+            }
+
+            Path_Delegate pathDelegate = Path_Delegate.getDelegate(native_path);
+            pathMeasure.mOriginalPathIterator = new CachedPathIteratorFactory(pathDelegate.getJavaShape()
+                    .getPathIterator(null));
         }
+
         pathMeasure.mNativePath = native_path;
-        pathMeasure.mPathPoints = Path_Delegate.native_approximate(native_path, PRECISION);
     }
 
     @LayoutlibDelegate
@@ -122,21 +125,11 @@
         PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance);
         assert pathMeasure != null;
 
-        if (pathMeasure.mPathPoints == null) {
+        if (pathMeasure.mOriginalPathIterator == null) {
             return 0;
         }
 
-        float length = 0;
-        int nPoints = pathMeasure.mPathPoints.length / 3;
-        for (int i = 1; i < nPoints; i++) {
-            length += Point2D.distance(
-                    pathMeasure.mPathPoints[(i - 1) * 3 + 1],
-                    pathMeasure.mPathPoints[(i - 1) * 3 + 2],
-                    pathMeasure.mPathPoints[i*3 + 1],
-                    pathMeasure.mPathPoints[i*3 + 2]);
-        }
-
-        return length;
+        return pathMeasure.mOriginalPathIterator.iterator().getTotalLength();
     }
 
     @LayoutlibDelegate
@@ -149,13 +142,10 @@
             return false;
         }
 
-        PathIterator pathIterator = path.getJavaShape().getPathIterator(null);
-
         int type = 0;
         float segment[] = new float[6];
-        while (!pathIterator.isDone()) {
-            type = pathIterator.currentSegment(segment);
-            pathIterator.next();
+        for (PathIterator pi = path.getJavaShape().getPathIterator(null); !pi.isDone(); pi.next()) {
+            type = pi.currentSegment(segment);
         }
 
         // A path is a closed path if the last element is SEG_CLOSE
@@ -176,33 +166,56 @@
         PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance);
         assert pathMeasure != null;
 
-        if (pathMeasure.mPathPoints == null) {
-            return false;
-        }
-
-        float accLength = 0;
+        CachedPathIterator iterator = pathMeasure.mOriginalPathIterator.iterator();
+        float accLength = startD;
         boolean isZeroLength = true; // Whether the output has zero length or not
-        int nPoints = pathMeasure.mPathPoints.length / 3;
-        for (int i = 0; i < nPoints; i++) {
-            float x = pathMeasure.mPathPoints[i * 3 + 1];
-            float y = pathMeasure.mPathPoints[i * 3 + 2];
-            if (accLength >= startD && accLength <= stopD) {
+        float[] points = new float[6];
+
+        iterator.jumpToSegment(accLength);
+        while (!iterator.isDone() && (stopD - accLength > 0.1f)) {
+            int type = iterator.currentSegment(points, stopD - accLength);
+
+            if (accLength - iterator.getCurrentSegmentLength() <= stopD) {
                 if (startWithMoveTo) {
                     startWithMoveTo = false;
-                    Path_Delegate.native_moveTo(native_dst_path, x, y);
-                } else {
-                    isZeroLength = false;
-                    Path_Delegate.native_lineTo(native_dst_path, x, y);
+
+                    // If this segment is a MOVETO, then we just use that one. If not, then we issue
+                    // a first moveto
+                    if (type != PathIterator.SEG_MOVETO) {
+                        float[] lastPoint = new float[2];
+                        iterator.getCurrentSegmentEnd(lastPoint);
+                        Path_Delegate.native_moveTo(native_dst_path, lastPoint[0], lastPoint[1]);
+                    }
+                }
+
+                isZeroLength = isZeroLength && iterator.getCurrentSegmentLength() > 0;
+                switch (type) {
+                    case PathIterator.SEG_MOVETO:
+                        Path_Delegate.native_moveTo(native_dst_path, points[0], points[1]);
+                        break;
+                    case PathIterator.SEG_LINETO:
+                        Path_Delegate.native_lineTo(native_dst_path, points[0], points[1]);
+                        break;
+                    case PathIterator.SEG_CLOSE:
+                        Path_Delegate.native_close(native_dst_path);
+                        break;
+                    case PathIterator.SEG_CUBICTO:
+                        Path_Delegate.native_cubicTo(native_dst_path, points[0], points[1],
+                                points[2], points[3],
+                                points[4], points[5]);
+                        break;
+                    case PathIterator.SEG_QUADTO:
+                        Path_Delegate.native_quadTo(native_dst_path, points[0], points[1],
+                                points[2],
+                                points[3]);
+                        break;
+                    default:
+                        assert false;
                 }
             }
 
-            if (i > 0) {
-                accLength += Point2D.distance(
-                        pathMeasure.mPathPoints[(i - 1) * 3 + 1],
-                        pathMeasure.mPathPoints[(i - 1) * 3 + 2],
-                        pathMeasure.mPathPoints[i * 3 + 1],
-                        pathMeasure.mPathPoints[i * 3 + 2]);
-            }
+            accLength += iterator.getCurrentSegmentLength();
+            iterator.next();
         }
 
         return !isZeroLength;
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index a2a53fe..d0dd22f 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -57,6 +57,8 @@
     private static final DelegateManager<Path_Delegate> sManager =
             new DelegateManager<Path_Delegate>(Path_Delegate.class);
 
+    private static final float EPSILON = 1e-4f;
+
     // ---- delegate data ----
     private FillType mFillType = FillType.WINDING;
     private Path2D mPath = new Path2D.Double();
@@ -64,6 +66,9 @@
     private float mLastX = 0;
     private float mLastY = 0;
 
+    // true if the path contains does not contain a curve or line.
+    private boolean mCachedIsEmpty = true;
+
     // ---- Public Helper methods ----
 
     public static Path_Delegate getDelegate(long nPath) {
@@ -75,7 +80,7 @@
     }
 
     public void setJavaShape(Shape shape) {
-        mPath.reset();
+        reset();
         mPath.append(shape, false /*connect*/);
     }
 
@@ -84,7 +89,7 @@
     }
 
     public void setPathIterator(PathIterator iterator) {
-        mPath.reset();
+        reset();
         mPath.append(iterator, false /*connect*/);
     }
 
@@ -591,11 +596,37 @@
 
 
     /**
-     * Returns whether the path is empty.
-     * @return true if the path is empty.
+     * Returns whether the path already contains any points.
+     * Note that this is different to
+     * {@link #isEmpty} because if all elements are {@link PathIterator#SEG_MOVETO},
+     * {@link #isEmpty} will return true while hasPoints will return false.
      */
-    private boolean isEmpty() {
-        return mPath.getCurrentPoint() == null;
+    public boolean hasPoints() {
+        return !mPath.getPathIterator(null).isDone();
+    }
+
+    /**
+     * Returns whether the path is empty (contains no lines or curves).
+     * @see Path#isEmpty
+     */
+    public boolean isEmpty() {
+        if (!mCachedIsEmpty) {
+            return false;
+        }
+
+        float[] coords = new float[6];
+        mCachedIsEmpty = Boolean.TRUE;
+        for (PathIterator it = mPath.getPathIterator(null); !it.isDone(); it.next()) {
+            int type = it.currentSegment(coords);
+            if (type != PathIterator.SEG_MOVETO) {
+                // Once we know that the path is not empty, we do not need to check again unless
+                // Path#reset is called.
+                mCachedIsEmpty = false;
+                return false;
+            }
+        }
+
+        return true;
     }
 
     /**
@@ -645,7 +676,7 @@
      * @param y The y-coordinate of the end of a line
      */
     private void lineTo(float x, float y) {
-        if (isEmpty()) {
+        if (!hasPoints()) {
             mPath.moveTo(mLastX = 0, mLastY = 0);
         }
         mPath.lineTo(mLastX = x, mLastY = y);
@@ -662,9 +693,15 @@
      *           this contour, to specify a line
      */
     private void rLineTo(float dx, float dy) {
-        if (isEmpty()) {
+        if (!hasPoints()) {
             mPath.moveTo(mLastX = 0, mLastY = 0);
         }
+
+        if (Math.abs(dx) < EPSILON && Math.abs(dy) < EPSILON) {
+            // The delta is so small that this shouldn't generate a line
+            return;
+        }
+
         dx += mLastX;
         dy += mLastY;
         mPath.lineTo(mLastX = dx, mLastY = dy);
@@ -699,7 +736,7 @@
      *            this contour, for the end point of a quadratic curve
      */
     private void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
-        if (isEmpty()) {
+        if (!hasPoints()) {
             mPath.moveTo(mLastX = 0, mLastY = 0);
         }
         dx1 += mLastX;
@@ -723,7 +760,7 @@
      */
     private void cubicTo(float x1, float y1, float x2, float y2,
                         float x3, float y3) {
-        if (isEmpty()) {
+        if (!hasPoints()) {
             mPath.moveTo(0, 0);
         }
         mPath.curveTo(x1, y1, x2, y2, mLastX = x3, mLastY = y3);
@@ -736,7 +773,7 @@
      */
     private void rCubicTo(float dx1, float dy1, float dx2, float dy2,
                          float dx3, float dy3) {
-        if (isEmpty()) {
+        if (!hasPoints()) {
             mPath.moveTo(mLastX = 0, mLastY = 0);
         }
         dx1 += mLastX;
diff --git a/tools/layoutlib/bridge/src/android/os/ServiceManager.java b/tools/layoutlib/bridge/src/android/os/ServiceManager.java
index 6a68ee2..549074d 100644
--- a/tools/layoutlib/bridge/src/android/os/ServiceManager.java
+++ b/tools/layoutlib/bridge/src/android/os/ServiceManager.java
@@ -51,8 +51,10 @@
 
     /**
      * Return a list of all currently running services.
+     * @return an array of all currently running services, or <code>null</code> in
+     * case of an exception
      */
-    public static String[] listServices() throws RemoteException {
+    public static String[] listServices() {
         // actual implementation returns null sometimes, so it's ok
         // to return null instead of an empty list.
         return null;
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 40437fa..9f0153a 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -19,6 +19,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import com.android.internal.app.IAssistScreenshotReceiver;
+import com.android.internal.os.IResultReceiver;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
 
@@ -76,7 +77,7 @@
     @Override
     public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
             boolean arg5, boolean arg6, int arg7, int arg8, boolean arg9, boolean arg10,
-            Rect arg11, Configuration arg12, boolean arg13) throws RemoteException {
+            Rect arg11, Configuration arg12, boolean arg13, boolean arg14) throws RemoteException {
         // TODO Auto-generated method stub
     }
 
@@ -543,6 +544,15 @@
     }
 
     @Override
-    public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) {
+    public void registerDockedStackListener(IDockedStackListener listener) throws RemoteException {
+    }
+
+    @Override
+    public void setResizeDimLayer(boolean visible, int targetStackId, float alpha)
+            throws RemoteException {
+    }
+
+    @Override
+    public void requestAppKeyboardShortcuts(IResultReceiver receiver) 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 6c949d9..1465f50 100644
--- a/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java
@@ -19,6 +19,8 @@
 import com.android.layoutlib.bridge.impl.DelegateManager;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
+import android.graphics.Matrix;
+
 /**
  * Delegate implementing the native methods of {@link RenderNode}
  * <p/>
@@ -36,6 +38,19 @@
 
 
     private float mLift;
+    private float mTranslationX;
+    private float mTranslationY;
+    private float mTranslationZ;
+    private float mRotation;
+    private float mScaleX = 1;
+    private float mScaleY = 1;
+    private float mPivotX;
+    private float mPivotY;
+    private boolean mPivotExplicitlySet;
+    private int mLeft;
+    private int mRight;
+    private int mTop;
+    private int mBottom;
     @SuppressWarnings("UnusedDeclaration")
     private String mName;
 
@@ -69,4 +84,245 @@
         }
         return 0f;
     }
+
+    @LayoutlibDelegate
+    /*package*/ static boolean nSetTranslationX(long renderNode, float translationX) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null && delegate.mTranslationX != translationX) {
+            delegate.mTranslationX = translationX;
+            return true;
+        }
+        return false;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static float nGetTranslationX(long renderNode) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null) {
+            return delegate.mTranslationX;
+        }
+        return 0f;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static boolean nSetTranslationY(long renderNode, float translationY) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null && delegate.mTranslationY != translationY) {
+            delegate.mTranslationY = translationY;
+            return true;
+        }
+        return false;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static float nGetTranslationY(long renderNode) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null) {
+            return delegate.mTranslationY;
+        }
+        return 0f;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static boolean nSetTranslationZ(long renderNode, float translationZ) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null && delegate.mTranslationZ != translationZ) {
+            delegate.mTranslationZ = translationZ;
+            return true;
+        }
+        return false;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static float nGetTranslationZ(long renderNode) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null) {
+            return delegate.mTranslationZ;
+        }
+        return 0f;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static boolean nSetRotation(long renderNode, float rotation) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null && delegate.mRotation != rotation) {
+            delegate.mRotation = rotation;
+            return true;
+        }
+        return false;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static float nGetRotation(long renderNode) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null) {
+            return delegate.mRotation;
+        }
+        return 0f;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void getMatrix(RenderNode renderNode, Matrix outMatrix) {
+        outMatrix.reset();
+        if (renderNode != null) {
+            float rotation = renderNode.getRotation();
+            float translationX = renderNode.getTranslationX();
+            float translationY = renderNode.getTranslationY();
+            float pivotX = renderNode.getPivotX();
+            float pivotY = renderNode.getPivotY();
+            float scaleX = renderNode.getScaleX();
+            float scaleY = renderNode.getScaleY();
+
+            outMatrix.setTranslate(translationX, translationY);
+            outMatrix.preRotate(rotation, pivotX, pivotY);
+            outMatrix.preScale(scaleX, scaleY, pivotX, pivotY);
+        }
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static boolean nSetLeft(long renderNode, int left) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null && delegate.mLeft != left) {
+            delegate.mLeft = left;
+            return true;
+        }
+        return false;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static boolean nSetTop(long renderNode, int top) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null && delegate.mTop != top) {
+            delegate.mTop = top;
+            return true;
+        }
+        return false;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static boolean nSetRight(long renderNode, int right) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null && delegate.mRight != right) {
+            delegate.mRight = right;
+            return true;
+        }
+        return false;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static boolean nSetBottom(long renderNode, int bottom) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null && delegate.mBottom != bottom) {
+            delegate.mBottom = bottom;
+            return true;
+        }
+        return false;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static boolean nSetLeftTopRightBottom(long renderNode, int left, int top, int right,
+            int bottom) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null && (delegate.mLeft != left || delegate.mTop != top || delegate
+                .mRight != right || delegate.mBottom != bottom)) {
+            delegate.mLeft = left;
+            delegate.mTop = top;
+            delegate.mRight = right;
+            delegate.mBottom = bottom;
+            return true;
+        }
+        return false;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static boolean nIsPivotExplicitlySet(long renderNode) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        return delegate != null && delegate.mPivotExplicitlySet;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static boolean nSetPivotX(long renderNode, float pivotX) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null) {
+            delegate.mPivotX = pivotX;
+            delegate.mPivotExplicitlySet = true;
+            return true;
+        }
+        return false;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static float nGetPivotX(long renderNode) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null) {
+            if (delegate.mPivotExplicitlySet) {
+                return delegate.mPivotX;
+            } else {
+                return (delegate.mRight - delegate.mLeft) / 2.0f;
+            }
+        }
+        return 0f;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static boolean nSetPivotY(long renderNode, float pivotY) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null) {
+            delegate.mPivotY = pivotY;
+            delegate.mPivotExplicitlySet = true;
+            return true;
+        }
+        return false;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static float nGetPivotY(long renderNode) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null) {
+            if (delegate.mPivotExplicitlySet) {
+                return delegate.mPivotY;
+            } else {
+                return (delegate.mBottom - delegate.mTop) / 2.0f;
+            }
+        }
+        return 0f;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static boolean nSetScaleX(long renderNode, float scaleX) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null && delegate.mScaleX != scaleX) {
+            delegate.mScaleX = scaleX;
+            return true;
+        }
+        return false;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static float nGetScaleX(long renderNode) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null) {
+            return delegate.mScaleX;
+        }
+        return 0f;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static boolean nSetScaleY(long renderNode, float scaleY) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null && delegate.mScaleY != scaleY) {
+            delegate.mScaleY = scaleY;
+            return true;
+        }
+        return false;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static float nGetScaleY(long renderNode) {
+        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
+        if (delegate != null) {
+            return delegate.mScaleY;
+        }
+        return 0f;
+    }
 }
diff --git a/tools/layoutlib/bridge/src/android/view/WindowCallback.java b/tools/layoutlib/bridge/src/android/view/WindowCallback.java
index d691c8e..411417c 100644
--- a/tools/layoutlib/bridge/src/android/view/WindowCallback.java
+++ b/tools/layoutlib/bridge/src/android/view/WindowCallback.java
@@ -16,10 +16,13 @@
 
 package android.view;
 
+import android.annotation.Nullable;
 import android.view.ActionMode.Callback;
 import android.view.WindowManager.LayoutParams;
 import android.view.accessibility.AccessibilityEvent;
 
+import java.util.List;
+
 /**
  * An empty implementation of {@link Window.Callback} that always returns null/false.
  */
@@ -138,4 +141,9 @@
     public void onActionModeFinished(ActionMode mode) {
 
     }
+
+    @Override
+    public void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, @Nullable Menu menu) {
+
+    }
 }
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 683c4aa..c8e3d03 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -183,7 +183,7 @@
      */
     private static LayoutLog sCurrentLog = sDefaultLog;
 
-    private static final int LAST_SUPPORTED_FEATURE = Features.CHOREOGRAPHER;
+    private static final int LAST_SUPPORTED_FEATURE = Features.THEME_PREVIEW_NAVIGATION_BAR;
 
     @Override
     public int getApiLevel() {
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 63411b0..e6fb620 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
@@ -197,7 +197,12 @@
 
         mRenderResources = renderResources;
         mConfig = config;
-        mAssets = new BridgeAssetManager();
+        AssetManager systemAssetManager = AssetManager.getSystem();
+        if (systemAssetManager instanceof BridgeAssetManager) {
+            mAssets = (BridgeAssetManager) systemAssetManager;
+        } else {
+            throw new AssertionError("Creating BridgeContext without initializing Bridge");
+        }
         mAssets.setAssetRepository(assets);
 
         mApplicationInfo = new ApplicationInfo();
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 a2fad13..037ce57 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
@@ -34,7 +34,6 @@
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.KeySet;
-import android.content.pm.ManifestDigest;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageItemInfo;
@@ -98,7 +97,22 @@
     }
 
     @Override
-    public int getPackageUid(String packageName, int userHandle) throws NameNotFoundException {
+    public int[] getPackageGids(String packageName, int flags) throws NameNotFoundException {
+        return new int[0];
+    }
+
+    @Override
+    public int getPackageUid(String packageName, int flags) throws NameNotFoundException {
+        return 0;
+    }
+
+    @Override
+    public int getPackageUidAsUser(String packageName, int userHandle) throws NameNotFoundException {
+        return 0;
+    }
+
+    @Override
+    public int getPackageUidAsUser(String packageName, int flags, int userHandle) throws NameNotFoundException {
         return 0;
     }
 
@@ -131,6 +145,12 @@
     }
 
     @Override
+    public ApplicationInfo getApplicationInfoAsUser(String packageName, int flags, int userId)
+            throws NameNotFoundException {
+        return null;
+    }
+
+    @Override
     public ActivityInfo getActivityInfo(ComponentName component, int flags)
             throws NameNotFoundException {
         return null;
@@ -165,7 +185,7 @@
     }
 
     @Override
-    public List<PackageInfo> getInstalledPackages(int flags, int userId) {
+    public List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {
         return null;
     }
 
@@ -329,7 +349,7 @@
     }
 
     @Override
-    public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags, int userId) {
+    public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent, int flags, int userId) {
         return null;
     }
 
@@ -472,6 +492,11 @@
     }
 
     @Override
+    public Drawable getUserBadgeForDensityNoBackground(UserHandle user, int density) {
+        return null;
+    }
+
+    @Override
     public CharSequence getUserBadgedLabel(CharSequence label, UserHandle user) {
         return null;
     }
@@ -522,7 +547,7 @@
     @Override
     public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
             int flags, String installerPackageName, Uri verificationURI,
-            ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
+            ContainerEncryptionParams encryptionParams) {
     }
 
     @Override
@@ -544,7 +569,7 @@
     @Override
     public void installPackageWithVerification(Uri packageURI, PackageInstallObserver observer,
             int flags, String installerPackageName, Uri verificationURI,
-            ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
+            ContainerEncryptionParams encryptionParams) {
     }
 
     @Override
@@ -579,12 +604,12 @@
     }
 
     @Override
-    public int getIntentVerificationStatus(String packageName, int userId) {
+    public int getIntentVerificationStatusAsUser(String packageName, int userId) {
         return 0;
     }
 
     @Override
-    public boolean updateIntentVerificationStatus(String packageName, int status, int userId) {
+    public boolean updateIntentVerificationStatusAsUser(String packageName, int status, int userId) {
         return false;
     }
 
@@ -599,12 +624,12 @@
     }
 
     @Override
-    public String getDefaultBrowserPackageName(int userId) {
+    public String getDefaultBrowserPackageNameAsUser(int userId) {
         return null;
     }
 
     @Override
-    public boolean setDefaultBrowserPackageName(String packageName, int userId) {
+    public boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId) {
         return false;
     }
 
@@ -644,7 +669,7 @@
     }
 
     @Override
-    public void getPackageSizeInfo(String packageName, int userHandle,
+    public void getPackageSizeInfoAsUser(String packageName, int userHandle,
             IPackageStatsObserver observer) {
     }
 
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 3662573..2000fbc 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
@@ -16,6 +16,8 @@
 
 package com.android.layoutlib.bridge.android;
 
+import com.android.internal.os.IResultReceiver;
+
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Bundle;
@@ -48,7 +50,7 @@
 
     @Override
     public void resized(Rect rect, Rect rect2, Rect rect3, Rect rect4, Rect rect5, Rect rect6,
-            boolean b, Configuration configuration, Rect rect7) throws RemoteException {
+            boolean b, Configuration configuration, Rect rect7, boolean b2) throws RemoteException {
         // pass for now.
     }
 
@@ -85,6 +87,11 @@
     }
 
     @Override
+    public void updatePointerIcon(float x, float y) {
+        // pass for now
+    }
+
+    @Override
     public void dispatchSystemUiVisibilityChanged(int seq, int globalUi,
             int localValue, int localChanges) {
         // pass for now.
@@ -95,8 +102,13 @@
     }
 
     @Override
+    public void requestAppKeyboardShortcuts(IResultReceiver receiver) throws RemoteException {
+    }
+
+    @Override
     public IBinder asBinder() {
         // pass for now.
         return null;
     }
+
 }
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 5c73fb6a..7b8e29a 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
@@ -89,7 +89,8 @@
     @Override
     public int relayout(IWindow iWindow, int i, LayoutParams layoutParams, int i2,
             int i3, int i4, int i5, Rect rect, Rect rect2, Rect rect3, Rect rect4, Rect rect5,
-            Rect rect6, Configuration configuration, Surface surface) throws RemoteException {
+            Rect rect6, Rect rect7, Configuration configuration, Surface surface)
+            throws RemoteException {
         // pass for now.
         return 0;
     }
@@ -147,7 +148,7 @@
 
     @Override
     public boolean performDrag(IWindow window, IBinder dragToken,
-            float touchX, float touchY, float thumbCenterX, float thumbCenterY,
+            int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY,
             ClipData data)
             throws RemoteException {
         // pass for now
@@ -230,4 +231,9 @@
     public void pokeDrawLock(IBinder window) {
         // pass for now.
     }
+
+    @Override
+    public void prepareToReplaceChildren(IBinder appToken) {
+        // pass for now.
+    }
 }
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 7e5ae8d..d417eb7 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
@@ -63,4 +63,9 @@
     public void removeViewImmediate(View arg0) {
         // pass
     }
+
+    @Override
+    public void requestAppKeyboardShortcuts(
+            KeyboardShortcutsReceiver receiver) {
+    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
index 9c89bfe..dfbc69b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
@@ -19,9 +19,6 @@
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.resources.Density;
 
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.view.View;
 import android.widget.LinearLayout;
@@ -41,29 +38,18 @@
     private static final int WIDTH_DEFAULT = 36;
     private static final int WIDTH_SW360 = 40;
     private static final int WIDTH_SW600 = 48;
-    private static final String LAYOUT_XML = "/bars/navigation_bar.xml";
+    protected static final String LAYOUT_XML = "/bars/navigation_bar.xml";
     private static final String LAYOUT_600DP_XML = "/bars/navigation_bar600dp.xml";
 
-
-    /**
-     * Constructor to be used when creating the {@link NavigationBar} as a regular control.
-     * This is currently used by the theme editor.
-     */
-    @SuppressWarnings("unused")
-    public NavigationBar(Context context, AttributeSet attrs) {
-        this((BridgeContext) context,
-                Density.getEnum(((BridgeContext) context).getMetrics().densityDpi),
-                LinearLayout.HORIZONTAL, // In this mode, it doesn't need to be render vertically
-                ((BridgeContext) context).getConfiguration().getLayoutDirection() ==
-                        View.LAYOUT_DIRECTION_RTL,
-                (context.getApplicationInfo().flags & ApplicationInfo.FLAG_SUPPORTS_RTL) != 0,
-                0);
+    public NavigationBar(BridgeContext context, Density density, int orientation, boolean isRtl,
+      boolean rtlEnabled, int simulatedPlatformVersion) {
+        this(context, density, orientation, isRtl, rtlEnabled, simulatedPlatformVersion,
+          getShortestWidth(context)>= 600 ? LAYOUT_600DP_XML : LAYOUT_XML);
     }
 
-    public NavigationBar(BridgeContext context, Density density, int orientation, boolean isRtl,
-            boolean rtlEnabled, int simulatedPlatformVersion) {
-        super(context, orientation, getShortestWidth(context)>= 600 ? LAYOUT_600DP_XML : LAYOUT_XML,
-                "navigation_bar.xml", simulatedPlatformVersion);
+    protected NavigationBar(BridgeContext context, Density density, int orientation, boolean isRtl,
+      boolean rtlEnabled, int simulatedPlatformVersion, String layoutPath) {
+        super(context, orientation, layoutPath, "navigation_bar.xml", simulatedPlatformVersion);
 
         int color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT);
         setBackgroundColor(color == 0 ? 0xFF000000 : color);
@@ -117,7 +103,7 @@
         view.setLayoutParams(layoutParams);
     }
 
-    private static int getSidePadding(float sw) {
+    protected int getSidePadding(float sw) {
         if (sw >= 400) {
             return PADDING_WIDTH_SW400;
         }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ThemePreviewNavigationBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ThemePreviewNavigationBar.java
new file mode 100644
index 0000000..0435280
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ThemePreviewNavigationBar.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.bars;
+
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.resources.Density;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+
+/**
+ * Navigation Bar for the Theme Editor preview.
+ *
+ * For small bars, it is identical to {@link NavigationBar}.
+ * But wide bars from {@link NavigationBar} are too wide for the Theme Editor preview.
+ * To solve that problem, {@link ThemePreviewNavigationBar} use the layout for small bars,
+ * and have no padding on the sides. That way, they have a similar look as the true ones,
+ * and they fit in the Theme Editor preview.
+ */
+public class ThemePreviewNavigationBar extends NavigationBar {
+    private static final int PADDING_WIDTH_SW600 = 0;
+
+    @SuppressWarnings("unused")
+    public ThemePreviewNavigationBar(Context context, AttributeSet attrs) {
+        super((BridgeContext) context,
+                Density.getEnum(((BridgeContext) context).getMetrics().densityDpi),
+                LinearLayout.HORIZONTAL, // In this mode, it doesn't need to be render vertically
+                ((BridgeContext) context).getConfiguration().getLayoutDirection() ==
+                        View.LAYOUT_DIRECTION_RTL,
+                (context.getApplicationInfo().flags & ApplicationInfo.FLAG_SUPPORTS_RTL) != 0,
+                0, LAYOUT_XML);
+    }
+
+    @Override
+    protected int getSidePadding(float sw) {
+        if (sw >= 600) {
+            return PADDING_WIDTH_SW600;
+        }
+        return super.getSidePadding(sw);
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java
index 9aab340..8c60bae 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java
@@ -114,7 +114,7 @@
                         if (value != null) {
                             if (value.getClass() != ViewAttribute.IS_CHECKED.getAttributeClass()) {
                                 Bridge.getLog().error(LayoutLog.TAG_BROKEN, String.format(
-                                        "Wrong Adapter Item value class for TEXT. Expected Boolean, got %s",
+                                        "Wrong Adapter Item value class for IS_CHECKED. Expected Boolean, got %s",
                                         value.getClass().getName()), null);
                             } else {
                                 cb.setChecked((Boolean) value);
@@ -134,7 +134,7 @@
                         if (value != null) {
                             if (value.getClass() != ViewAttribute.SRC.getAttributeClass()) {
                                 Bridge.getLog().error(LayoutLog.TAG_BROKEN, String.format(
-                                        "Wrong Adapter Item value class for TEXT. Expected Boolean, got %s",
+                                        "Wrong Adapter Item value class for SRC. Expected Boolean, got %s",
                                         value.getClass().getName()), null);
                             } else {
                                 // FIXME
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/CachedPathIteratorFactory.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/CachedPathIteratorFactory.java
new file mode 100644
index 0000000..0a9b9ec
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/CachedPathIteratorFactory.java
@@ -0,0 +1,485 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 android.annotation.NonNull;
+
+import java.awt.geom.CubicCurve2D;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.QuadCurve2D;
+import java.util.ArrayList;
+
+import com.google.android.collect.Lists;
+
+/**
+ * Class that returns iterators for a given path. These iterators are lightweight and can be reused
+ * multiple times to iterate over the path.
+ */
+public class CachedPathIteratorFactory {
+    /*
+     * A few conventions used in the code:
+     * Coordinates or coords arrays store segment coordinates. They use the same format as
+     * PathIterator#currentSegment coordinates array.
+     * float arrays store always points where the first element is X and the second is Y.
+     */
+
+    // This governs how accurate the approximation of the Path is.
+    private static final float PRECISION = 0.002f;
+
+    private final int mWindingRule;
+    private final int[] mTypes;
+    private final float[][] mCoordinates;
+    private final float[] mSegmentsLength;
+    private final float mTotalLength;
+
+    public CachedPathIteratorFactory(@NonNull PathIterator iterator) {
+        mWindingRule = iterator.getWindingRule();
+
+        ArrayList<Integer> typesArray = Lists.newArrayList();
+        ArrayList<float[]> pointsArray = Lists.newArrayList();
+        float[] points = new float[6];
+        while (!iterator.isDone()) {
+            int type = iterator.currentSegment(points);
+            int nPoints = getNumberOfPoints(type) * 2; // 2 coordinates per point
+
+            typesArray.add(type);
+            float[] itemPoints = new float[nPoints];
+            System.arraycopy(points, 0, itemPoints, 0, nPoints);
+            pointsArray.add(itemPoints);
+            iterator.next();
+        }
+
+        mTypes = new int[typesArray.size()];
+        mCoordinates = new float[mTypes.length][];
+        for (int i = 0; i < typesArray.size(); i++) {
+            mTypes[i] = typesArray.get(i);
+            mCoordinates[i] = pointsArray.get(i);
+        }
+
+        // Do measurement
+        mSegmentsLength = new float[mTypes.length];
+
+        // Curves that we can reuse to estimate segments length
+        CubicCurve2D.Float cubicCurve = new CubicCurve2D.Float();
+        QuadCurve2D.Float quadCurve = new QuadCurve2D.Float();
+        float lastX = 0;
+        float lastY = 0;
+        float totalLength = 0;
+        for (int i = 0; i < mTypes.length; i++) {
+            switch (mTypes[i]) {
+                case PathIterator.SEG_CUBICTO:
+                    cubicCurve.setCurve(lastX, lastY,
+                            mCoordinates[i][0], mCoordinates[i][1], mCoordinates[i][2],
+                            mCoordinates[i][3], lastX = mCoordinates[i][4],
+                            lastY = mCoordinates[i][5]);
+                    mSegmentsLength[i] =
+                            getFlatPathLength(cubicCurve.getPathIterator(null, PRECISION));
+                    break;
+                case PathIterator.SEG_QUADTO:
+                    quadCurve.setCurve(lastX, lastY, mCoordinates[i][0], mCoordinates[i][1],
+                            lastX = mCoordinates[i][2], lastY = mCoordinates[i][3]);
+                    mSegmentsLength[i] =
+                            getFlatPathLength(quadCurve.getPathIterator(null, PRECISION));
+                    break;
+                case PathIterator.SEG_CLOSE:
+                    mSegmentsLength[i] = (float) Point2D.distance(lastX, lastY,
+                            lastX = mCoordinates[0][0],
+                            lastY = mCoordinates[0][1]);
+                    mCoordinates[i] = new float[2];
+                    // We convert a SEG_CLOSE segment to a SEG_LINETO so we do not have to worry
+                    // about this special case in the rest of the code.
+                    mTypes[i] = PathIterator.SEG_LINETO;
+                    mCoordinates[i][0] = mCoordinates[0][0];
+                    mCoordinates[i][1] = mCoordinates[0][1];
+                    break;
+                case PathIterator.SEG_MOVETO:
+                    mSegmentsLength[i] = 0;
+                    lastX = mCoordinates[i][0];
+                    lastY = mCoordinates[i][1];
+                    break;
+                case PathIterator.SEG_LINETO:
+                    mSegmentsLength[i] = (float) Point2D.distance(lastX, lastY, mCoordinates[i][0],
+                            mCoordinates[i][1]);
+                    lastX = mCoordinates[i][0];
+                    lastY = mCoordinates[i][1];
+                default:
+            }
+            totalLength += mSegmentsLength[i];
+        }
+
+        mTotalLength = totalLength;
+    }
+
+    private static void quadCurveSegment(float[] coords, float t0, float t1) {
+        // Calculate X and Y at 0.5 (We'll use this to reconstruct the control point later)
+        float mt = t0 + (t1 - t0) / 2;
+        float mu = 1 - mt;
+        float mx = mu * mu * coords[0] + 2 * mu * mt * coords[2] + mt * mt * coords[4];
+        float my = mu * mu * coords[1] + 2 * mu * mt * coords[3] + mt * mt * coords[5];
+
+        float u0 = 1 - t0;
+        float u1 = 1 - t1;
+
+        // coords at t0
+        coords[0] = coords[0] * u0 * u0 + coords[2] * 2 * t0 * u0 + coords[4] * t0 * t0;
+        coords[1] = coords[1] * u0 * u0 + coords[3] * 2 * t0 * u0 + coords[5] * t0 * t0;
+
+        // coords at t1
+        coords[4] = coords[0] * u1 * u1 + coords[2] * 2 * t1 * u1 + coords[4] * t1 * t1;
+        coords[5] = coords[1] * u1 * u1 + coords[3] * 2 * t1 * u1 + coords[5] * t1 * t1;
+
+        // estimated control point at t'=0.5
+        coords[2] = 2 * mx - coords[0] / 2 - coords[4] / 2;
+        coords[3] = 2 * my - coords[1] / 2 - coords[5] / 2;
+    }
+
+    private static void cubicCurveSegment(float[] coords, float t0, float t1) {
+        // http://stackoverflow.com/questions/11703283/cubic-bezier-curve-segment
+        float u0 = 1 - t0;
+        float u1 = 1 - t1;
+
+        // Calculate the points at t0 and t1 for the quadratic curves formed by (P0, P1, P2) and
+        // (P1, P2, P3)
+        float qxa = coords[0] * u0 * u0 + coords[2] * 2 * t0 * u0 + coords[4] * t0 * t0;
+        float qxb = coords[0] * u1 * u1 + coords[2] * 2 * t1 * u1 + coords[4] * t1 * t1;
+        float qxc = coords[2] * u0 * u0 + coords[4] * 2 * t0 * u0 + coords[6] * t0 * t0;
+        float qxd = coords[2] * u1 * u1 + coords[4] * 2 * t1 * u1 + coords[6] * t1 * t1;
+
+        float qya = coords[1] * u0 * u0 + coords[3] * 2 * t0 * u0 + coords[5] * t0 * t0;
+        float qyb = coords[1] * u1 * u1 + coords[3] * 2 * t1 * u1 + coords[5] * t1 * t1;
+        float qyc = coords[3] * u0 * u0 + coords[5] * 2 * t0 * u0 + coords[7] * t0 * t0;
+        float qyd = coords[3] * u1 * u1 + coords[5] * 2 * t1 * u1 + coords[7] * t1 * t1;
+
+        // Linear interpolation
+        coords[0] = qxa * u0 + qxc * t0;
+        coords[1] = qya * u0 + qyc * t0;
+
+        coords[2] = qxa * u1 + qxc * t1;
+        coords[3] = qya * u1 + qyc * t1;
+
+        coords[4] = qxb * u0 + qxd * t0;
+        coords[5] = qyb * u0 + qyd * t0;
+
+        coords[6] = qxb * u1 + qxd * t1;
+        coords[7] = qyb * u1 + qyd * t1;
+    }
+
+    /**
+     * Returns the end point of a given segment
+     *
+     * @param type the segment type
+     * @param coords the segment coordinates array
+     * @param point the return array where the point will be stored
+     */
+    private static void getShapeEndPoint(int type, @NonNull float[] coords, @NonNull float[]
+            point) {
+        // start index of the end point for the segment type
+        int pointIndex = (getNumberOfPoints(type) - 1) * 2;
+        point[0] = coords[pointIndex];
+        point[1] = coords[pointIndex + 1];
+    }
+
+    /**
+     * Returns the number of points stored in a coordinates array for the given segment type.
+     */
+    private static int getNumberOfPoints(int segmentType) {
+        switch (segmentType) {
+            case PathIterator.SEG_QUADTO:
+                return 2;
+            case PathIterator.SEG_CUBICTO:
+                return 3;
+            case PathIterator.SEG_CLOSE:
+                return 0;
+            default:
+                return 1;
+        }
+    }
+
+    /**
+     * Returns the estimated length of a flat path. If the passed path is not flat (i.e. contains a
+     * segment that is not {@link PathIterator#SEG_CLOSE}, {@link PathIterator#SEG_MOVETO} or {@link
+     * PathIterator#SEG_LINETO} this method will fail.
+     */
+    private static float getFlatPathLength(@NonNull PathIterator iterator) {
+        float segment[] = new float[6];
+        float totalLength = 0;
+        float[] previousPoint = new float[2];
+        boolean isFirstPoint = true;
+
+        while (!iterator.isDone()) {
+            int type = iterator.currentSegment(segment);
+            assert type == PathIterator.SEG_LINETO || type == PathIterator.SEG_CLOSE || type ==
+                    PathIterator.SEG_MOVETO;
+
+            // MoveTo shouldn't affect the length
+            if (!isFirstPoint && type != PathIterator.SEG_MOVETO) {
+                totalLength += Point2D.distance(previousPoint[0], previousPoint[1], segment[0],
+                        segment[1]);
+            } else {
+                isFirstPoint = false;
+            }
+            previousPoint[0] = segment[0];
+            previousPoint[1] = segment[1];
+            iterator.next();
+        }
+
+        return totalLength;
+    }
+
+    /**
+     * Returns the estimated position along a path of the given length.
+     */
+    private void getPointAtLength(int type, @NonNull float[] coords, float lastX, float
+            lastY, float t, @NonNull float[] point) {
+        if (type == PathIterator.SEG_LINETO) {
+            point[0] = lastX + (coords[0] - lastX) * t;
+            point[1] = lastY + (coords[1] - lastY) * t;
+            // Return here, since we do not need a shape to estimate
+            return;
+        }
+
+        float[] curve = new float[8];
+        int lastPointIndex = (getNumberOfPoints(type) - 1) * 2;
+
+        System.arraycopy(coords, 0, curve, 2, coords.length);
+        curve[0] = lastX;
+        curve[1] = lastY;
+        if (type == PathIterator.SEG_CUBICTO) {
+            cubicCurveSegment(curve, 0f, t);
+        } else {
+            quadCurveSegment(curve, 0f, t);
+        }
+
+        point[0] = curve[2 + lastPointIndex];
+        point[1] = curve[2 + lastPointIndex + 1];
+    }
+
+    public CachedPathIterator iterator() {
+        return new CachedPathIterator();
+    }
+
+    /**
+     * Class that allows us to iterate over a path multiple times
+     */
+    public class CachedPathIterator implements PathIterator {
+        private int mNextIndex;
+
+        /**
+         * Current segment type.
+         *
+         * @see PathIterator
+         */
+        private int mCurrentType;
+
+        /**
+         * Stores the coordinates array of the current segment. The number of points stored depends
+         * on the segment type.
+         *
+         * @see PathIterator
+         */
+        private float[] mCurrentCoords = new float[6];
+        private float mCurrentSegmentLength;
+
+        /**
+         * Current segment length offset. When asking for the length of the current segment, the
+         * length will be reduced by this amount. This is useful when we are only using portions of
+         * the segment.
+         *
+         * @see #jumpToSegment(float)
+         */
+        private float mOffsetLength;
+
+        /** Point where the current segment started */
+        private float[] mLastPoint = new float[2];
+        private boolean isIteratorDone;
+
+        private CachedPathIterator() {
+            next();
+        }
+
+        public float getCurrentSegmentLength() {
+            return mCurrentSegmentLength;
+        }
+
+        @Override
+        public int getWindingRule() {
+            return mWindingRule;
+        }
+
+        @Override
+        public boolean isDone() {
+            return isIteratorDone;
+        }
+
+        @Override
+        public void next() {
+            if (mNextIndex >= mTypes.length) {
+                isIteratorDone = true;
+                return;
+            }
+
+            if (mNextIndex >= 1) {
+                // We've already called next() once so there is a previous segment in this path.
+                // We want to get the coordinates where the path ends.
+                getShapeEndPoint(mCurrentType, mCurrentCoords, mLastPoint);
+            } else {
+                // This is the first segment, no previous point so initialize to 0, 0
+                mLastPoint[0] = mLastPoint[1] = 0f;
+            }
+            mCurrentType = mTypes[mNextIndex];
+            mCurrentSegmentLength = mSegmentsLength[mNextIndex] - mOffsetLength;
+
+            if (mOffsetLength > 0f && (mCurrentType == SEG_CUBICTO || mCurrentType == SEG_QUADTO)) {
+                // We need to skip part of the start of the current segment (because
+                // mOffsetLength > 0)
+                float[] points = new float[8];
+
+                if (mNextIndex < 1) {
+                    points[0] = points[1] = 0f;
+                } else {
+                    getShapeEndPoint(mTypes[mNextIndex - 1], mCoordinates[mNextIndex - 1], points);
+                }
+
+                System.arraycopy(mCoordinates[mNextIndex], 0, points, 2,
+                        mCoordinates[mNextIndex].length);
+                float t0 = (mSegmentsLength[mNextIndex] - mCurrentSegmentLength) /
+                        mSegmentsLength[mNextIndex];
+                if (mCurrentType == SEG_CUBICTO) {
+                    cubicCurveSegment(points, t0, 1f);
+                } else {
+                    quadCurveSegment(points, t0, 1f);
+                }
+                System.arraycopy(points, 2, mCurrentCoords, 0, mCoordinates[mNextIndex].length);
+            } else {
+                System.arraycopy(mCoordinates[mNextIndex], 0, mCurrentCoords, 0,
+                        mCoordinates[mNextIndex].length);
+            }
+
+            mOffsetLength = 0f;
+            mNextIndex++;
+        }
+
+        @Override
+        public int currentSegment(float[] coords) {
+            System.arraycopy(mCurrentCoords, 0, coords, 0, getNumberOfPoints(mCurrentType) * 2);
+            return mCurrentType;
+        }
+
+        @Override
+        public int currentSegment(double[] coords) {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * Returns the point where the current segment ends
+         */
+        public void getCurrentSegmentEnd(float[] point) {
+            point[0] = mLastPoint[0];
+            point[1] = mLastPoint[1];
+        }
+
+        /**
+         * Restarts the iterator and jumps all the segments of this path up to the length value.
+         */
+        public void jumpToSegment(float length) {
+            isIteratorDone = false;
+            if (length <= 0f) {
+                mNextIndex = 0;
+                return;
+            }
+
+            float accLength = 0;
+            float lastPoint[] = new float[2];
+            for (mNextIndex = 0; mNextIndex < mTypes.length; mNextIndex++) {
+                float segmentLength = mSegmentsLength[mNextIndex];
+                if (accLength + segmentLength >= length && mTypes[mNextIndex] != SEG_MOVETO) {
+                    float[] estimatedPoint = new float[2];
+                    getPointAtLength(mTypes[mNextIndex],
+                            mCoordinates[mNextIndex], lastPoint[0], lastPoint[1],
+                            (length - accLength) / segmentLength,
+                            estimatedPoint);
+
+                    // This segment makes us go further than length so we go back one step,
+                    // set a moveto and offset the length of the next segment by the length
+                    // of this segment that we've already used.
+                    mCurrentType = PathIterator.SEG_MOVETO;
+                    mCurrentCoords[0] = estimatedPoint[0];
+                    mCurrentCoords[1] = estimatedPoint[1];
+                    mCurrentSegmentLength = 0;
+
+                    // We need to offset next path length to account for the segment we've just
+                    // skipped.
+                    mOffsetLength = length - accLength;
+                    return;
+                }
+                accLength += segmentLength;
+                getShapeEndPoint(mTypes[mNextIndex], mCoordinates[mNextIndex], lastPoint);
+            }
+        }
+
+        /**
+         * Returns the current segment up to certain length. If the current segment is shorter than
+         * length, then the whole segment is returned. The segment coordinates are copied into the
+         * coords array.
+         *
+         * @return the segment type
+         */
+        public int currentSegment(@NonNull float[] coords, float length) {
+            int type = currentSegment(coords);
+            // If the length is greater than the current segment length, no need to find
+            // the cut point. Same if this is a SEG_MOVETO.
+            if (mCurrentSegmentLength <= length || type == SEG_MOVETO) {
+                return type;
+            }
+
+            float t = length / getCurrentSegmentLength();
+
+            // We find at which offset the end point is located within the coords array and set
+            // a new end point to cut the segment short
+            switch (type) {
+                case SEG_CUBICTO:
+                case SEG_QUADTO:
+                    float[] curve = new float[8];
+                    curve[0] = mLastPoint[0];
+                    curve[1] = mLastPoint[1];
+                    System.arraycopy(coords, 0, curve, 2, coords.length);
+                    if (type == SEG_CUBICTO) {
+                        cubicCurveSegment(curve, 0f, t);
+                    } else {
+                        quadCurveSegment(curve, 0f, t);
+                    }
+                    System.arraycopy(curve, 2, coords, 0, coords.length);
+                    break;
+                default:
+                    float[] point = new float[2];
+                    getPointAtLength(type, coords, mLastPoint[0], mLastPoint[1], t, point);
+                    coords[0] = point[0];
+                    coords[1] = point[1];
+            }
+
+            return type;
+        }
+
+        /**
+         * Returns the total length of the path
+         */
+        public float getTotalLength() {
+            return mTotalLength;
+        }
+    }
+}
diff --git a/tools/layoutlib/bridge/src/libcore/util/ZoneInfo_WallTime_Delegate.java b/tools/layoutlib/bridge/src/libcore/util/ZoneInfo_WallTime_Delegate.java
deleted file mode 100644
index f29c5c0..0000000
--- a/tools/layoutlib/bridge/src/libcore/util/ZoneInfo_WallTime_Delegate.java
+++ /dev/null
@@ -1,32 +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 libcore.util;
-
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import java.util.GregorianCalendar;
-
-/**
- * Delegate used to provide alternate implementation of select methods in {@link ZoneInfo.WallTime}
- */
-public class ZoneInfo_WallTime_Delegate {
-
-    @LayoutlibDelegate
-    static GregorianCalendar createGregorianCalendar() {
-        return new GregorianCalendar();
-    }
-}
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png
index 2b86bfb..d8ead23 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png
new file mode 100644
index 0000000..65d1dc5
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.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
new file mode 100644
index 0000000..72b87ab
--- /dev/null
+++ 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/drawable/multi_path.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/multi_path.xml
new file mode 100644
index 0000000..ffc70dc
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/multi_path.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="76dp"
+        android:width="76dp"
+        android:viewportHeight="48"
+        android:viewportWidth="48">
+
+    <group
+        android:name="root"
+        android:translateX="24.0"
+        android:translateY="24.0">
+        <!--
+            This is the same as the material indeterminate progressbar which involves drawing
+            several cubic segments
+        -->
+        <path
+            android:pathData="M0, 0 m 0, -19 a 19,19 0 1,1 0,38 a 19,19 0 1,1 0,-38"
+            android:strokeColor="#00FF00"
+            android:strokeLineCap="square"
+            android:strokeLineJoin="miter"
+            android:strokeWidth="1"
+            android:trimPathEnd="0.8"
+            android:trimPathStart="0.3" />
+        <!-- Same figure with reversed end and start -->
+        <path
+            android:pathData="M0, 0 m 0, -12 a 19,19 0 1,1 0,38 a 19,19 0 1,1 0,-38"
+            android:strokeColor="#FFFF00"
+            android:strokeLineCap="square"
+            android:strokeLineJoin="miter"
+            android:strokeWidth="1"
+            android:trimPathEnd="0.3"
+            android:trimPathStart="0.8" />
+
+        <!--
+            Draw a few partial quadratic segments
+        -->
+        <path
+            android:strokeWidth="2"
+            android:strokeColor="#FFFF00"
+            android:pathData="M2,2 Q 5 30 15 0"
+            android:trimPathStart="0.1"
+            android:trimPathEnd="0.9"
+        />
+
+        <!--
+            Draw a line
+        -->
+        <path
+            android:strokeWidth="3"
+            android:strokeColor="#00FFFF"
+            android:pathData="M-10,-10 L 10, 10"
+            android:trimPathStart="0.2"
+            android:trimPathEnd="0.8"
+        />
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/vector_drawable.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/vector_drawable.xml
new file mode 100644
index 0000000..2ce4f4c
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/vector_drawable.xml
@@ -0,0 +1,30 @@
+<?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:padding="16dp"
+              android:orientation="horizontal"
+              android:layout_width="fill_parent"
+              android:layout_height="fill_parent">
+    <ImageView
+             android:layout_height="fill_parent"
+             android:layout_width="fill_parent"
+             android:src="@drawable/multi_path" />
+
+</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 2dca07c..fe16a3e 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
@@ -305,6 +305,11 @@
         renderAndVerify("array_check.xml", "array_check.png");
     }
 
+    @Test
+    public void testAllWidgetsTablet() throws ClassNotFoundException {
+        renderAndVerify("allwidgets.xml", "allwidgets_tab.png", ConfigGenerator.NEXUS_7_2012);
+    }
+
     @AfterClass
     public static void tearDown() {
         sLayoutLibLog = null;
@@ -350,7 +355,7 @@
         renderAndVerify(params, "expand_horz_layout.png");
     }
 
-    /** Test expand_layout.xml */
+    /** Test indeterminate_progressbar.xml */
     @Test
     public void testVectorAnimation() throws ClassNotFoundException {
         // Create the layout pull parser.
@@ -375,10 +380,31 @@
     }
 
     /**
-     * Create a new rendering session and test that rendering given layout on nexus 5
-     * doesn't throw any exceptions and matches the provided image.
-     * <p/>If frameTimeNanos is >= 0 a frame will be executed during the rendering. The time
-     * indicates how far in the future is.
+     * Test a vector drawable that uses trimStart and trimEnd. It also tests all the primitives
+     * for vector drawables (lines, moves and cubic and quadratic curves).
+     */
+    @Test
+    public void testVectorDrawable() throws ClassNotFoundException {
+        // Create the layout pull parser.
+        LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/" +
+                "vector_drawable.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);
+
+        renderAndVerify(params, "vector_drawable.png", TimeUnit.SECONDS.toNanos(2));
+    }
+
+    /**
+     * Create a new rendering session and test that rendering the given layout doesn't throw any
+     * exceptions and matches the provided image.
+     * <p>
+     * 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)
             throws ClassNotFoundException {
@@ -409,8 +435,8 @@
     }
 
     /**
-     * Create a new rendering session and test that rendering given layout on nexus 5
-     * doesn't throw any exceptions and matches the provided image.
+     * 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)
             throws ClassNotFoundException {
@@ -418,11 +444,21 @@
     }
 
     /**
-     * Create a new rendering session and test that rendering given layout on nexus 5
+     * 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)
             throws ClassNotFoundException {
+        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,
+            ConfigGenerator deviceConfig)
+            throws ClassNotFoundException {
         // Create the layout pull parser.
         LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/" + layoutFileName);
         // Create LayoutLibCallback.
@@ -430,7 +466,7 @@
         layoutLibCallback.initResources();
         // TODO: Set up action bar handler properly to test menu rendering.
         // Create session params.
-        SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5,
+        SessionParams params = getSessionParams(parser, deviceConfig,
                 layoutLibCallback, "AppTheme", true, RenderingMode.NORMAL, 22);
         renderAndVerify(params, goldenFileName);
     }
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ConfigGenerator.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ConfigGenerator.java
index 8e0cec6..34fc726 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ConfigGenerator.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/ConfigGenerator.java
@@ -126,6 +126,21 @@
                                                         .setSoftButtons(true)
                                                         .setNavigation(Navigation.NONAV);
 
+    public static final ConfigGenerator NEXUS_7_2012 = new ConfigGenerator()
+                                                        .setScreenHeight(1280)
+                                                        .setScreenWidth(800)
+                                                        .setXdpi(195)
+                                                        .setYdpi(200)
+                                                        .setOrientation(ScreenOrientation.PORTRAIT)
+                                                        .setDensity(Density.TV)
+                                                        .setRatio(ScreenRatio.NOTLONG)
+                                                        .setSize(ScreenSize.LARGE)
+                                                        .setKeyboard(Keyboard.NOKEY)
+                                                        .setTouchScreen(TouchScreen.FINGER)
+                                                        .setKeyboardState(KeyboardState.SOFT)
+                                                        .setSoftButtons(true)
+                                                        .setNavigation(Navigation.NONAV);
+
     private static final String TAG_ATTR = "attr";
     private static final String TAG_ENUM = "enum";
     private static final String TAG_FLAG = "flag";
diff --git a/tools/layoutlib/create/Android.mk b/tools/layoutlib/create/Android.mk
index e6f0bc3..c7f2c41 100644
--- a/tools/layoutlib/create/Android.mk
+++ b/tools/layoutlib/create/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_JAR_MANIFEST := manifest.txt
 LOCAL_STATIC_JAVA_LIBRARIES := \
-	asm-4.0
+	asm-5.0
 
 LOCAL_MODULE := layoutlib_create
 
diff --git a/tools/layoutlib/create/create.iml b/tools/layoutlib/create/create.iml
index 9b18e73..b2b14b4 100644
--- a/tools/layoutlib/create/create.iml
+++ b/tools/layoutlib/create/create.iml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <module type="JAVA_MODULE" version="4">
-  <component name="NewModuleRootManager" inherit-compiler-output="true">
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="true">
     <exclude-output />
     <content url="file://$MODULE_DIR$">
       <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
@@ -9,12 +9,12 @@
       <sourceFolder url="file://$MODULE_DIR$/tests/mock_data" type="java-test-resource" />
       <excludeFolder url="file://$MODULE_DIR$/.settings" />
     </content>
-    <orderEntry type="inheritedJdk" />
+    <orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
     <orderEntry type="sourceFolder" forTests="false" />
     <orderEntry type="module-library">
-      <library name="asm-4.0">
+      <library name="asm-5.0">
         <CLASSES>
-          <root url="jar://$MODULE_DIR$/../../../../../prebuilts/misc/common/asm/asm-4.0.jar!/" />
+          <root url="jar://$MODULE_DIR$/../../../../../prebuilts/misc/common/asm/asm-5.0.jar!/" />
         </CLASSES>
         <JAVADOC />
         <SOURCES>
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AbstractClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AbstractClassAdapter.java
index a6902a4..758bd48 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AbstractClassAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AbstractClassAdapter.java
@@ -21,7 +21,6 @@
 import org.objectweb.asm.FieldVisitor;
 import org.objectweb.asm.Label;
 import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;
 import org.objectweb.asm.signature.SignatureReader;
 import org.objectweb.asm.signature.SignatureVisitor;
@@ -44,7 +43,7 @@
     abstract String renameInternalType(String name);
 
     public AbstractClassAdapter(ClassVisitor cv) {
-        super(Opcodes.ASM4, cv);
+        super(Main.ASM_VERSION, cv);
     }
 
     /**
@@ -239,7 +238,7 @@
          * The names must be full qualified internal ASM names (e.g. com/blah/MyClass$InnerClass).
          */
         public RenameMethodAdapter(MethodVisitor mv) {
-            super(Opcodes.ASM4, mv);
+            super(Main.ASM_VERSION, mv);
         }
 
         @Override
@@ -276,7 +275,8 @@
         }
 
         @Override
-        public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+        public void visitMethodInsn(int opcode, String owner, String name, String desc,
+                boolean itf) {
             // The owner sometimes turns out to be a type descriptor. We try to detect it and fix.
             if (owner.indexOf(';') > 0) {
                 owner = renameTypeDesc(owner);
@@ -285,7 +285,7 @@
             }
             desc = renameMethodDesc(desc);
 
-            super.visitMethodInsn(opcode, owner, name, desc);
+            super.visitMethodInsn(opcode, owner, name, desc, itf);
         }
 
         @Override
@@ -330,7 +330,7 @@
         private final SignatureVisitor mSv;
 
         public RenameSignatureAdapter(SignatureVisitor sv) {
-            super(Opcodes.ASM4);
+            super(Main.ASM_VERSION);
             mSv = sv;
         }
 
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 c8b2b84..48544ca 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
@@ -23,7 +23,6 @@
 import org.objectweb.asm.FieldVisitor;
 import org.objectweb.asm.Label;
 import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;
 import org.objectweb.asm.signature.SignatureReader;
 import org.objectweb.asm.signature.SignatureVisitor;
@@ -65,7 +64,7 @@
     /** Glob patterns of files to keep as is. */
     private final String[] mIncludeFileGlobs;
     /** Internal names of classes that contain method calls that need to be rewritten. */
-    private final Set<String> mReplaceMethodCallClasses = new HashSet<String>();
+    private final Set<String> mReplaceMethodCallClasses = new HashSet<>();
 
     /**
      * Creates a new analyzer.
@@ -97,8 +96,8 @@
      */
     public void analyze() throws IOException, LogAbortException {
 
-        TreeMap<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
-        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+        TreeMap<String, ClassReader> zipClasses = new TreeMap<>();
+        Map<String, InputStream> filesFound = new TreeMap<>();
 
         parseZip(mOsSourceJar, zipClasses, filesFound);
         mLog.info("Found %d classes in input JAR%s.", zipClasses.size(),
@@ -189,7 +188,7 @@
      */
     Map<String, ClassReader> findIncludes(Map<String, ClassReader> zipClasses)
             throws LogAbortException {
-        TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
+        TreeMap<String, ClassReader> found = new TreeMap<>();
 
         mLog.debug("Find classes to include.");
 
@@ -318,10 +317,10 @@
     Map<String, ClassReader> findDeps(Map<String, ClassReader> zipClasses,
             Map<String, ClassReader> inOutKeepClasses) {
 
-        TreeMap<String, ClassReader> deps = new TreeMap<String, ClassReader>();
-        TreeMap<String, ClassReader> new_deps = new TreeMap<String, ClassReader>();
-        TreeMap<String, ClassReader> new_keep = new TreeMap<String, ClassReader>();
-        TreeMap<String, ClassReader> temp = new TreeMap<String, ClassReader>();
+        TreeMap<String, ClassReader> deps = new TreeMap<>();
+        TreeMap<String, ClassReader> new_deps = new TreeMap<>();
+        TreeMap<String, ClassReader> new_keep = new TreeMap<>();
+        TreeMap<String, ClassReader> temp = new TreeMap<>();
 
         DependencyVisitor visitor = getVisitor(zipClasses,
                 inOutKeepClasses, new_keep,
@@ -399,7 +398,7 @@
                 Map<String, ClassReader> outKeep,
                 Map<String,ClassReader> inDeps,
                 Map<String,ClassReader> outDeps) {
-            super(Opcodes.ASM4);
+            super(Main.ASM_VERSION);
             mZipClasses = zipClasses;
             mInKeep = inKeep;
             mOutKeep = outKeep;
@@ -557,7 +556,7 @@
         private class MyFieldVisitor extends FieldVisitor {
 
             public MyFieldVisitor() {
-                super(Opcodes.ASM4);
+                super(Main.ASM_VERSION);
             }
 
             @Override
@@ -630,7 +629,7 @@
             private String mOwnerClass;
 
             public MyMethodVisitor(String ownerClass) {
-                super(Opcodes.ASM4);
+                super(Main.ASM_VERSION);
                 mOwnerClass = ownerClass;
             }
 
@@ -719,7 +718,8 @@
 
             // instruction that invokes a method
             @Override
-            public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+            public void visitMethodInsn(int opcode, String owner, String name, String desc,
+                    boolean itf) {
 
                 // owner is the internal name of the method's owner class
                 considerName(owner);
@@ -779,7 +779,7 @@
         private class MySignatureVisitor extends SignatureVisitor {
 
             public MySignatureVisitor() {
-                super(Opcodes.ASM4);
+                super(Main.ASM_VERSION);
             }
 
             // ---------------------------------------------------
@@ -878,7 +878,7 @@
         private class MyAnnotationVisitor extends AnnotationVisitor {
 
             public MyAnnotationVisitor() {
-                super(Opcodes.ASM4);
+                super(Main.ASM_VERSION);
             }
 
             // Visits a primitive value of an annotation
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 8f0ad01..5b99a6b 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
@@ -91,7 +91,7 @@
         mLog = log;
         mOsDestJar = osDestJar;
         ArrayList<Class<?>> injectedClasses =
-                new ArrayList<Class<?>>(Arrays.asList(createInfo.getInjectedClasses()));
+                new ArrayList<>(Arrays.asList(createInfo.getInjectedClasses()));
         // Search for and add anonymous inner classes also.
         ListIterator<Class<?>> iter = injectedClasses.listIterator();
         while (iter.hasNext()) {
@@ -107,25 +107,25 @@
             }
         }
         mInjectClasses = injectedClasses.toArray(new Class<?>[0]);
-        mStubMethods = new HashSet<String>(Arrays.asList(createInfo.getOverriddenMethods()));
+        mStubMethods = new HashSet<>(Arrays.asList(createInfo.getOverriddenMethods()));
 
         // Create the map/set of methods to change to delegates
-        mDelegateMethods = new HashMap<String, Set<String>>();
+        mDelegateMethods = new HashMap<>();
         addToMap(createInfo.getDelegateMethods(), mDelegateMethods);
 
         for (String className : createInfo.getDelegateClassNatives()) {
             className = binaryToInternalClassName(className);
             Set<String> methods = mDelegateMethods.get(className);
             if (methods == null) {
-                methods = new HashSet<String>();
+                methods = new HashSet<>();
                 mDelegateMethods.put(className, methods);
             }
             methods.add(DelegateClassAdapter.ALL_NATIVES);
         }
 
         // Create the map of classes to rename.
-        mRenameClasses = new HashMap<String, String>();
-        mClassesNotRenamed = new HashSet<String>();
+        mRenameClasses = new HashMap<>();
+        mClassesNotRenamed = new HashSet<>();
         String[] renameClasses = createInfo.getRenamedClasses();
         int n = renameClasses.length;
         for (int i = 0; i < n; i += 2) {
@@ -138,7 +138,7 @@
         }
 
         // Create a map of classes to be refactored.
-        mRefactorClasses = new HashMap<String, String>();
+        mRefactorClasses = new HashMap<>();
         String[] refactorClasses = createInfo.getJavaPkgClasses();
         n = refactorClasses.length;
         for (int i = 0; i < n; i += 2) {
@@ -149,7 +149,7 @@
         }
 
         // create the map of renamed class -> return type of method to delete.
-        mDeleteReturns = new HashMap<String, Set<String>>();
+        mDeleteReturns = new HashMap<>();
         String[] deleteReturns = createInfo.getDeleteReturns();
         Set<String> returnTypes = null;
         String renamedClass = null;
@@ -172,12 +172,12 @@
 
             // just a standard return type, we add it to the list.
             if (returnTypes == null) {
-                returnTypes = new HashSet<String>();
+                returnTypes = new HashSet<>();
             }
             returnTypes.add(binaryToInternalClassName(className));
         }
 
-        mPromotedFields = new HashMap<String, Set<String>>();
+        mPromotedFields = new HashMap<>();
         addToMap(createInfo.getPromotedFields(), mPromotedFields);
 
         mInjectedMethodsMap = createInfo.getInjectedMethodsMap();
@@ -197,7 +197,7 @@
             String methodOrFieldName = entry.substring(pos + 1);
             Set<String> set = map.get(className);
             if (set == null) {
-                set = new HashSet<String>();
+                set = new HashSet<>();
                 map.put(className, set);
             }
             set.add(methodOrFieldName);
@@ -247,7 +247,7 @@
 
     /** Generates the final JAR */
     public void generate() throws IOException {
-        TreeMap<String, byte[]> all = new TreeMap<String, byte[]>();
+        TreeMap<String, byte[]> all = new TreeMap<>();
 
         for (Class<?> clazz : mInjectClasses) {
             String name = classToEntryPath(clazz);
@@ -314,7 +314,7 @@
      * e.g. for the input "android.view.View" it returns "android/view/View.class"
      */
     String classNameToEntryPath(String className) {
-        return className.replaceAll("\\.", "/").concat(".class");
+        return className.replace('.', '/').concat(".class");
     }
 
     /**
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ClassHasNativeVisitor.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ClassHasNativeVisitor.java
index 2c955fd..4748a7c 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ClassHasNativeVisitor.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ClassHasNativeVisitor.java
@@ -31,7 +31,7 @@
  */
 public class ClassHasNativeVisitor extends ClassVisitor {
     public ClassHasNativeVisitor() {
-        super(Opcodes.ASM4);
+        super(Main.ASM_VERSION);
     }
 
     private boolean mHasNativeMethods = false;
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 b571c5a..d106592 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
@@ -111,7 +111,7 @@
     public Set<String> getExcludedClasses() {
         String[] refactoredClasses = getJavaPkgClasses();
         int count = refactoredClasses.length / 2 + EXCLUDED_CLASSES.length;
-        Set<String> excludedClasses = new HashSet<String>(count);
+        Set<String> excludedClasses = new HashSet<>(count);
         for (int i = 0; i < refactoredClasses.length; i+=2) {
             excludedClasses.add(refactoredClasses[i]);
         }
@@ -166,6 +166,7 @@
         "android.content.res.TypedArray#getValueAt",
         "android.content.res.TypedArray#obtain",
         "android.graphics.BitmapFactory#finishDecode",
+        "android.graphics.BitmapFactory#setDensityFromOptions",
         "android.graphics.drawable.GradientDrawable#buildRing",
         "android.graphics.Typeface#getSystemFontConfigLocation",
         "android.os.Handler#sendMessageAtTime",
@@ -191,6 +192,29 @@
         "android.view.RenderNode#nDestroyRenderNode",
         "android.view.RenderNode#nSetElevation",
         "android.view.RenderNode#nGetElevation",
+        "android.view.RenderNode#nSetTranslationX",
+        "android.view.RenderNode#nGetTranslationX",
+        "android.view.RenderNode#nSetTranslationY",
+        "android.view.RenderNode#nGetTranslationY",
+        "android.view.RenderNode#nSetTranslationZ",
+        "android.view.RenderNode#nGetTranslationZ",
+        "android.view.RenderNode#nSetRotation",
+        "android.view.RenderNode#nGetRotation",
+        "android.view.RenderNode#getMatrix",
+        "android.view.RenderNode#nSetLeft",
+        "android.view.RenderNode#nSetTop",
+        "android.view.RenderNode#nSetRight",
+        "android.view.RenderNode#nSetBottom",
+        "android.view.RenderNode#nSetLeftTopRightBottom",
+        "android.view.RenderNode#nSetPivotX",
+        "android.view.RenderNode#nGetPivotX",
+        "android.view.RenderNode#nSetPivotY",
+        "android.view.RenderNode#nGetPivotY",
+        "android.view.RenderNode#nSetScaleX",
+        "android.view.RenderNode#nGetScaleX",
+        "android.view.RenderNode#nSetScaleY",
+        "android.view.RenderNode#nGetScaleY",
+        "android.view.RenderNode#nIsPivotExplicitlySet",
         "android.view.ViewGroup#drawChild",
         "android.widget.TimePickerClockDelegate#getAmOrPmKeyCode",
         "com.android.internal.view.menu.MenuBuilder#createNewMenuItem",
@@ -200,7 +224,6 @@
         "libcore.io.MemoryMappedFile#mmapRO",
         "libcore.io.MemoryMappedFile#close",
         "libcore.io.MemoryMappedFile#bigEndianIterator",
-        "libcore.util.ZoneInfo$WallTime#createGregorianCalendar",
     };
 
     /**
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java
index 7ef7566..cbb3a8a 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java
@@ -60,7 +60,7 @@
             ClassVisitor cv,
             String className,
             Set<String> delegateMethods) {
-        super(Opcodes.ASM4, cv);
+        super(Main.ASM_VERSION, cv);
         mLog = log;
         mClassName = className;
         mDelegateMethods = delegateMethods;
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java
index cca9e57..da8babc 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java
@@ -124,7 +124,7 @@
             String desc,
             boolean isStatic,
             boolean isStaticClass) {
-        super(Opcodes.ASM4);
+        super(Main.ASM_VERSION);
         mLog = log;
         mOrgWriter = mvOriginal;
         mDelWriter = mvDelegate;
@@ -188,7 +188,7 @@
             mDelWriter.visitLineNumber((Integer) p[0], (Label) p[1]);
         }
 
-        ArrayList<Type> paramTypes = new ArrayList<Type>();
+        ArrayList<Type> paramTypes = new ArrayList<>();
         String delegateClassName = mClassName + DELEGATE_SUFFIX;
         boolean pushedArg0 = false;
         int maxStack = 0;
@@ -253,7 +253,8 @@
         mDelWriter.visitMethodInsn(Opcodes.INVOKESTATIC,
                 delegateClassName,
                 mMethodName,
-                desc);
+                desc,
+                false);
 
         Type returnType = Type.getReturnType(mDesc);
         mDelWriter.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
@@ -371,9 +372,9 @@
     }
 
     @Override
-    public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+    public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
         if (mOrgWriter != null) {
-            mOrgWriter.visitMethodInsn(opcode, owner, name, desc);
+            mOrgWriter.visitMethodInsn(opcode, owner, name, desc, itf);
         }
     }
 
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java
index 61b64a2..aa68ea0 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java
@@ -26,7 +26,6 @@
 import org.objectweb.asm.FieldVisitor;
 import org.objectweb.asm.Label;
 import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;
 import org.objectweb.asm.signature.SignatureReader;
 import org.objectweb.asm.signature.SignatureVisitor;
@@ -82,7 +81,7 @@
 
         Map<String, Set<String>> missing = findMissingClasses(deps, zipClasses.keySet());
 
-        List<Map<String, Set<String>>> result = new ArrayList<Map<String,Set<String>>>(2);
+        List<Map<String, Set<String>>> result = new ArrayList<>(2);
         result.add(deps);
         result.add(missing);
         return result;
@@ -151,7 +150,7 @@
      * class name => ASM ClassReader. Class names are in the form "android.view.View".
      */
     Map<String,ClassReader> parseZip(List<String> jarPathList) throws IOException {
-        TreeMap<String, ClassReader> classes = new TreeMap<String, ClassReader>();
+        TreeMap<String, ClassReader> classes = new TreeMap<>();
 
         for (String jarPath : jarPathList) {
             ZipFile zip = new ZipFile(jarPath);
@@ -202,7 +201,7 @@
 
         // The dependencies that we'll collect.
         // It's a map Class name => uses class names.
-        Map<String, Set<String>> dependencyMap = new TreeMap<String, Set<String>>();
+        Map<String, Set<String>> dependencyMap = new TreeMap<>();
 
         DependencyVisitor visitor = getVisitor();
 
@@ -211,7 +210,7 @@
             for (Entry<String, ClassReader> entry : zipClasses.entrySet()) {
                 String name = entry.getKey();
 
-                TreeSet<String> set = new TreeSet<String>();
+                TreeSet<String> set = new TreeSet<>();
                 dependencyMap.put(name, set);
                 visitor.setDependencySet(set);
 
@@ -240,7 +239,7 @@
     private Map<String, Set<String>> findMissingClasses(
             Map<String, Set<String>> deps,
             Set<String> zipClasses) {
-        Map<String, Set<String>> missing = new TreeMap<String, Set<String>>();
+        Map<String, Set<String>> missing = new TreeMap<>();
 
         for (Entry<String, Set<String>> entry : deps.entrySet()) {
             String name = entry.getKey();
@@ -250,7 +249,7 @@
                     // This dependency doesn't exist in the zip classes.
                     Set<String> set = missing.get(dep);
                     if (set == null) {
-                        set = new TreeSet<String>();
+                        set = new TreeSet<>();
                         missing.put(dep, set);
                     }
                     set.add(name);
@@ -284,7 +283,7 @@
          * Creates a new visitor that will find all the dependencies for the visited class.
          */
         public DependencyVisitor() {
-            super(Opcodes.ASM4);
+            super(Main.ASM_VERSION);
         }
 
         /**
@@ -435,7 +434,7 @@
         private class MyFieldVisitor extends FieldVisitor {
 
             public MyFieldVisitor() {
-                super(Opcodes.ASM4);
+                super(Main.ASM_VERSION);
             }
 
             @Override
@@ -510,7 +509,7 @@
         private class MyMethodVisitor extends MethodVisitor {
 
             public MyMethodVisitor() {
-                super(Opcodes.ASM4);
+                super(Main.ASM_VERSION);
             }
 
 
@@ -598,7 +597,8 @@
 
             // instruction that invokes a method
             @Override
-            public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+            public void visitMethodInsn(int opcode, String owner, String name, String desc,
+                    boolean itf) {
 
                 // owner is the internal name of the method's owner class
                 if (!considerDesc(owner) && owner.indexOf('/') != -1) {
@@ -654,7 +654,7 @@
         private class MySignatureVisitor extends SignatureVisitor {
 
             public MySignatureVisitor() {
-                super(Opcodes.ASM4);
+                super(Main.ASM_VERSION);
             }
 
             // ---------------------------------------------------
@@ -753,7 +753,7 @@
         private class MyAnnotationVisitor extends AnnotationVisitor {
 
             public MyAnnotationVisitor() {
-                super(Opcodes.ASM4);
+                super(Main.ASM_VERSION);
             }
 
             // Visits a primitive value of an annotation
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodRunnables.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodRunnables.java
index 37fc096..1941ab4 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodRunnables.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodRunnables.java
@@ -42,9 +42,9 @@
             mv.visitCode();
             mv.visitVarInsn(ALOAD, 0);
             mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass",
-                    "()Ljava/lang/Class;");
+                    "()Ljava/lang/Class;", false);
             mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader",
-                    "()Ljava/lang/ClassLoader;");
+                    "()Ljava/lang/ClassLoader;", false);
             mv.visitInsn(ARETURN);
             mv.visitMaxs(1, 1);
             mv.visitEnd();
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodsAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodsAdapter.java
index ea2b9c9..c834808 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodsAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodsAdapter.java
@@ -19,7 +19,6 @@
 import com.android.tools.layoutlib.create.ICreateInfo.InjectMethodRunnable;
 
 import org.objectweb.asm.ClassVisitor;
-import org.objectweb.asm.Opcodes;
 
 /**
  * Injects methods into some classes.
@@ -29,7 +28,7 @@
     private final ICreateInfo.InjectMethodRunnable mRunnable;
 
     public InjectMethodsAdapter(ClassVisitor cv, InjectMethodRunnable runnable) {
-        super(Opcodes.ASM4, cv);
+        super(Main.ASM_VERSION, cv);
         mRunnable = runnable;
     }
 
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
index 383168f..9bb91e5 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
@@ -16,6 +16,8 @@
 
 package com.android.tools.layoutlib.create;
 
+import org.objectweb.asm.Opcodes;
+
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
@@ -52,13 +54,15 @@
         public boolean listOnlyMissingDeps = false;
     }
 
+    public static final int ASM_VERSION = Opcodes.ASM5;
+
     public static final Options sOptions = new Options();
 
     public static void main(String[] args) {
 
         Log log = new Log();
 
-        ArrayList<String> osJarPath = new ArrayList<String>();
+        ArrayList<String> osJarPath = new ArrayList<>();
         String[] osDestJar = { null };
 
         if (!processArgs(log, args, osJarPath, osDestJar)) {
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodListener.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodListener.java
index 6fc2b24..faba4d7 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodListener.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodListener.java
@@ -36,41 +36,40 @@
      * @param isNative True if the method was a native method.
      * @param caller The calling object. Null for static methods, "this" for instance methods.
      */
-    public void onInvokeV(String signature, boolean isNative, Object caller);
+    void onInvokeV(String signature, boolean isNative, Object caller);
 
     /**
      * Same as {@link #onInvokeV(String, boolean, Object)} but returns an integer or similar.
      * @see #onInvokeV(String, boolean, Object)
      * @return an integer, or a boolean, or a short or a byte.
      */
-    public int onInvokeI(String signature, boolean isNative, Object caller);
+    int onInvokeI(String signature, boolean isNative, Object caller);
 
     /**
      * Same as {@link #onInvokeV(String, boolean, Object)} but returns a long.
      * @see #onInvokeV(String, boolean, Object)
      * @return a long.
      */
-    public long onInvokeL(String signature, boolean isNative, Object caller);
+    long onInvokeL(String signature, boolean isNative, Object caller);
 
     /**
      * Same as {@link #onInvokeV(String, boolean, Object)} but returns a float.
      * @see #onInvokeV(String, boolean, Object)
      * @return a float.
      */
-    public float onInvokeF(String signature, boolean isNative, Object caller);
+    float onInvokeF(String signature, boolean isNative, Object caller);
 
     /**
      * Same as {@link #onInvokeV(String, boolean, Object)} but returns a double.
      * @see #onInvokeV(String, boolean, Object)
      * @return a double.
      */
-    public double onInvokeD(String signature, boolean isNative, Object caller);
+    double onInvokeD(String signature, boolean isNative, Object caller);
 
     /**
      * Same as {@link #onInvokeV(String, boolean, Object)} but returns an object.
      * @see #onInvokeV(String, boolean, Object)
      * @return an object.
      */
-    public Object onInvokeA(String signature, boolean isNative, Object caller);
+    Object onInvokeA(String signature, boolean isNative, Object caller);
 }
-    
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/OverrideMethod.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/OverrideMethod.java
index 4c87b3c..7ccafc3 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/OverrideMethod.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/OverrideMethod.java
@@ -28,7 +28,7 @@
 public final class OverrideMethod {
 
     /** Map of method overridden. */
-    private static HashMap<String, MethodListener> sMethods = new HashMap<String, MethodListener>();
+    private static HashMap<String, MethodListener> sMethods = new HashMap<>();
     /** Default listener for all method not listed in sMethods. Nothing if null. */
     private static MethodListener sDefaultListener = null;
     
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java
index e4b70da..05af033 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java
@@ -24,7 +24,6 @@
 import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
 import static org.objectweb.asm.Opcodes.ACC_PROTECTED;
 import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
-import static org.objectweb.asm.Opcodes.ASM4;
 
 /**
  * Promotes given fields to public visibility.
@@ -35,7 +34,7 @@
     private static final int ACC_NOT_PUBLIC = ~(ACC_PRIVATE | ACC_PROTECTED);
 
     public PromoteFieldClassAdapter(ClassVisitor cv, Set<String> fieldNames) {
-        super(ASM4, cv);
+        super(Main.ASM_VERSION, cv);
         mFieldNames = fieldNames;
     }
 
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java
index 5e47261..bf94415 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java
@@ -43,11 +43,11 @@
      * Descriptors for specialized versions {@link System#arraycopy} that are not present on the
      * Desktop VM.
      */
-    private static Set<String> ARRAYCOPY_DESCRIPTORS = new HashSet<String>(Arrays.asList(
+    private static Set<String> ARRAYCOPY_DESCRIPTORS = new HashSet<>(Arrays.asList(
             "([CI[CII)V", "([BI[BII)V", "([SI[SII)V", "([II[III)V",
             "([JI[JII)V", "([FI[FII)V", "([DI[DII)V", "([ZI[ZII)V"));
 
-    private static final List<MethodReplacer> METHOD_REPLACERS = new ArrayList<MethodReplacer>(5);
+    private static final List<MethodReplacer> METHOD_REPLACERS = new ArrayList<>(5);
 
     private static final String ANDROID_LOCALE_CLASS =
             "com/android/layoutlib/bridge/android/AndroidLocale";
@@ -232,7 +232,7 @@
     private final String mOriginalClassName;
 
     public ReplaceMethodCallsAdapter(ClassVisitor cv, String originalClassName) {
-        super(Opcodes.ASM4, cv);
+        super(Main.ASM_VERSION, cv);
         mOriginalClassName = originalClassName;
     }
 
@@ -245,11 +245,12 @@
     private class MyMethodVisitor extends MethodVisitor {
 
         public MyMethodVisitor(MethodVisitor mv) {
-            super(Opcodes.ASM4, mv);
+            super(Main.ASM_VERSION, mv);
         }
 
         @Override
-        public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+        public void visitMethodInsn(int opcode, String owner, String name, String desc,
+                boolean itf) {
             for (MethodReplacer replacer : METHOD_REPLACERS) {
                 if (replacer.isNeeded(owner, name, desc, mOriginalClassName)) {
                     MethodInformation mi = new MethodInformation(opcode, owner, name, desc);
@@ -261,7 +262,7 @@
                     break;
                 }
             }
-            super.visitMethodInsn(opcode, owner, name, desc);
+            super.visitMethodInsn(opcode, owner, name, desc, itf);
         }
     }
 
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/StubMethodAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/StubMethodAdapter.java
index 416b73a..b5ab738 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/StubMethodAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/StubMethodAdapter.java
@@ -50,7 +50,7 @@
 
     public StubMethodAdapter(MethodVisitor mv, String methodName, Type returnType,
             String invokeSignature, boolean isStatic, boolean isNative) {
-        super(Opcodes.ASM4);
+        super(Main.ASM_VERSION);
         mParentVisitor = mv;
         mReturnType = returnType;
         mInvokeSignature = invokeSignature;
@@ -82,7 +82,8 @@
             mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC,
                     "com/android/tools/layoutlib/create/OverrideMethod",
                     "invokeV",
-                    "(Ljava/lang/String;ZLjava/lang/Object;)V");
+                    "(Ljava/lang/String;ZLjava/lang/Object;)V",
+                    false);
             mParentVisitor.visitInsn(Opcodes.RETURN);
             break;
         case Type.BOOLEAN:
@@ -93,7 +94,8 @@
             mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC,
                     "com/android/tools/layoutlib/create/OverrideMethod",
                     "invokeI",
-                    "(Ljava/lang/String;ZLjava/lang/Object;)I");
+                    "(Ljava/lang/String;ZLjava/lang/Object;)I",
+                    false);
             switch(sort) {
             case Type.BOOLEAN:
                 Label l1 = new Label();
@@ -119,21 +121,24 @@
             mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC,
                     "com/android/tools/layoutlib/create/OverrideMethod",
                     "invokeL",
-                    "(Ljava/lang/String;ZLjava/lang/Object;)J");
+                    "(Ljava/lang/String;ZLjava/lang/Object;)J",
+                    false);
             mParentVisitor.visitInsn(Opcodes.LRETURN);
             break;
         case Type.FLOAT:
             mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC,
                     "com/android/tools/layoutlib/create/OverrideMethod",
                     "invokeF",
-                    "(Ljava/lang/String;ZLjava/lang/Object;)F");
+                    "(Ljava/lang/String;ZLjava/lang/Object;)F",
+                    false);
             mParentVisitor.visitInsn(Opcodes.FRETURN);
             break;
         case Type.DOUBLE:
             mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC,
                     "com/android/tools/layoutlib/create/OverrideMethod",
                     "invokeD",
-                    "(Ljava/lang/String;ZLjava/lang/Object;)D");
+                    "(Ljava/lang/String;ZLjava/lang/Object;)D",
+                    false);
             mParentVisitor.visitInsn(Opcodes.DRETURN);
             break;
         case Type.ARRAY:
@@ -141,7 +146,8 @@
             mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC,
                     "com/android/tools/layoutlib/create/OverrideMethod",
                     "invokeA",
-                    "(Ljava/lang/String;ZLjava/lang/Object;)Ljava/lang/Object;");
+                    "(Ljava/lang/String;ZLjava/lang/Object;)Ljava/lang/Object;",
+                    false);
             mParentVisitor.visitTypeInsn(Opcodes.CHECKCAST, mReturnType.getInternalName());
             mParentVisitor.visitInsn(Opcodes.ARETURN);
             break;
@@ -282,9 +288,9 @@
     }
 
     @Override
-    public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+    public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
         if (mIsInitMethod) {
-            mParentVisitor.visitMethodInsn(opcode, owner, name, desc);
+            mParentVisitor.visitMethodInsn(opcode, owner, name, desc, itf);
         }
     }
 
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/TransformClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/TransformClassAdapter.java
index d9ecf98..a28ae69 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/TransformClassAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/TransformClassAdapter.java
@@ -49,7 +49,7 @@
     public TransformClassAdapter(Log logger, Set<String> stubMethods,
             Set<String> deleteReturns, String className, ClassVisitor cv,
             boolean stubNativesOnly) {
-        super(Opcodes.ASM4, cv);
+        super(Main.ASM_VERSION, cv);
         mLog = logger;
         mStubMethods = stubMethods;
         mClassName = className;
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/java/AutoCloseable.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/java/AutoCloseable.java
index ed2c128..7d6c4ec 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/java/AutoCloseable.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/java/AutoCloseable.java
@@ -28,4 +28,5 @@
     /**
      * Closes the object and release any system resources it holds.
      */
-    void close() throws Exception; }
+    void close() throws Exception;
+}
diff --git a/tools/layoutlib/create/tests/Android.mk b/tools/layoutlib/create/tests/Android.mk
index c197d57..dafb9c6 100644
--- a/tools/layoutlib/create/tests/Android.mk
+++ b/tools/layoutlib/create/tests/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_JAVA_LIBRARIES := layoutlib_create junit
-LOCAL_STATIC_JAVA_LIBRARIES := asm-4.0
+LOCAL_STATIC_JAVA_LIBRARIES := asm-5.0
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
index 78e2c48..f86917a 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
@@ -17,13 +17,8 @@
 
 package com.android.tools.layoutlib.create;
 
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
 import com.android.tools.layoutlib.create.AsmAnalyzer.DependencyVisitor;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.objectweb.asm.ClassReader;
@@ -32,11 +27,15 @@
 import java.io.InputStream;
 import java.net.URL;
 import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.Collections;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
 
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
 /**
  * Unit tests for some methods of {@link AsmAnalyzer}.
  */
@@ -51,26 +50,22 @@
         mLog = new MockLog();
         URL url = this.getClass().getClassLoader().getResource("data/mock_android.jar");
 
-        mOsJarPath = new ArrayList<String>();
+        mOsJarPath = new ArrayList<>();
+        //noinspection ConstantConditions
         mOsJarPath.add(url.getFile());
 
-        Set<String> excludeClasses = new HashSet<String>(1);
-        excludeClasses.add("java.lang.JavaClass");
+        Set<String> excludeClasses = Collections.singleton("java.lang.JavaClass");
 
         String[] includeFiles = new String[]{"mock_android/data/data*"};
         mAa = new AsmAnalyzer(mLog, mOsJarPath, null /* gen */, null /* deriveFrom */,
                 null /* includeGlobs */, excludeClasses, includeFiles);
     }
 
-    @After
-    public void tearDown() throws Exception {
-    }
-
     @Test
     public void testParseZip() throws IOException {
 
-        Map<String, ClassReader> map = new TreeMap<String, ClassReader>();
-        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+        Map<String, ClassReader> map = new TreeMap<>();
+        Map<String, InputStream> filesFound = new TreeMap<>();
 
         mAa.parseZip(mOsJarPath, map, filesFound);
 
@@ -101,11 +96,11 @@
     @Test
     public void testFindClass() throws IOException, LogAbortException {
 
-        Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
-        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+        Map<String, ClassReader> zipClasses = new TreeMap<>();
+        Map<String, InputStream> filesFound = new TreeMap<>();
 
         mAa.parseZip(mOsJarPath, zipClasses, filesFound);
-        TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
+        TreeMap<String, ClassReader> found = new TreeMap<>();
 
         ClassReader cr = mAa.findClass("mock_android.view.ViewGroup$LayoutParams",
                 zipClasses, found);
@@ -120,11 +115,11 @@
     @Test
     public void testFindGlobs() throws IOException, LogAbortException {
 
-        Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
-        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+        Map<String, ClassReader> zipClasses = new TreeMap<>();
+        Map<String, InputStream> filesFound = new TreeMap<>();
 
         mAa.parseZip(mOsJarPath, zipClasses, filesFound);
-        TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
+        TreeMap<String, ClassReader> found = new TreeMap<>();
 
         // this matches classes, a package match returns nothing
         found.clear();
@@ -183,11 +178,11 @@
     @Test
     public void testFindClassesDerivingFrom() throws LogAbortException, IOException {
 
-        Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
-        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+        Map<String, ClassReader> zipClasses = new TreeMap<>();
+        Map<String, InputStream> filesFound = new TreeMap<>();
 
         mAa.parseZip(mOsJarPath, zipClasses, filesFound);
-        TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
+        TreeMap<String, ClassReader> found = new TreeMap<>();
 
         mAa.findClassesDerivingFrom("mock_android.view.View", zipClasses, found);
 
@@ -209,14 +204,14 @@
     @Test
     public void testDependencyVisitor() throws IOException, LogAbortException {
 
-        Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
-        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+        Map<String, ClassReader> zipClasses = new TreeMap<>();
+        Map<String, InputStream> filesFound = new TreeMap<>();
 
         mAa.parseZip(mOsJarPath, zipClasses, filesFound);
-        TreeMap<String, ClassReader> keep = new TreeMap<String, ClassReader>();
-        TreeMap<String, ClassReader> new_keep = new TreeMap<String, ClassReader>();
-        TreeMap<String, ClassReader> in_deps = new TreeMap<String, ClassReader>();
-        TreeMap<String, ClassReader> out_deps = new TreeMap<String, ClassReader>();
+        TreeMap<String, ClassReader> keep = new TreeMap<>();
+        TreeMap<String, ClassReader> new_keep = new TreeMap<>();
+        TreeMap<String, ClassReader> in_deps = new TreeMap<>();
+        TreeMap<String, ClassReader> out_deps = new TreeMap<>();
 
         ClassReader cr = mAa.findClass("mock_android.widget.LinearLayout", zipClasses, keep);
         DependencyVisitor visitor = mAa.getVisitor(zipClasses, keep, new_keep, in_deps, out_deps);
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
index 8a2235b..c4dd7ee 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
@@ -18,12 +18,6 @@
 package com.android.tools.layoutlib.create;
 
 
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -31,7 +25,6 @@
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.FieldVisitor;
 import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;
 
 import java.io.ByteArrayOutputStream;
@@ -44,7 +37,6 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Enumeration;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
@@ -52,11 +44,18 @@
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
 /**
  * Unit tests for some methods of {@link AsmGenerator}.
  */
 public class AsmGeneratorTest {
 
+    private static final String[] EMPTY_STRING_ARRAY = new String[0];
     private MockLog mLog;
     private ArrayList<String> mOsJarPath;
     private String mOsDestJar;
@@ -70,7 +69,8 @@
         mLog = new MockLog();
         URL url = this.getClass().getClassLoader().getResource("data/mock_android.jar");
 
-        mOsJarPath = new ArrayList<String>();
+        mOsJarPath = new ArrayList<>();
+        //noinspection ConstantConditions
         mOsJarPath.add(url.getFile());
 
         mTempFile = File.createTempFile("mock", ".jar");
@@ -98,18 +98,18 @@
 
             @Override
             public String[] getDelegateMethods() {
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public String[] getDelegateClassNatives() {
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public String[] getOverriddenMethods() {
                 // methods to force override
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
@@ -123,7 +123,7 @@
 
             @Override
             public String[] getJavaPkgClasses() {
-              return new String[0];
+              return EMPTY_STRING_ARRAY;
             }
 
             @Override
@@ -134,17 +134,17 @@
             @Override
             public String[] getDeleteReturns() {
                  // methods deleted from their return type.
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public String[] getPromotedFields() {
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
-                return new HashMap<String, InjectMethodRunnable>(0);
+                return Collections.emptyMap();
             }
         };
 
@@ -155,7 +155,7 @@
                 new String[] {        // include classes
                     "**"
                 },
-                new HashSet<String>(0) /* excluded classes */,
+                Collections.<String>emptySet() /* excluded classes */,
                 new String[]{} /* include files */);
         aa.analyze();
         agen.generate();
@@ -178,24 +178,24 @@
 
             @Override
             public String[] getDelegateMethods() {
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public String[] getDelegateClassNatives() {
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public String[] getOverriddenMethods() {
                 // methods to force override
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public String[] getRenamedClasses() {
                 // classes to rename (so that we can replace them)
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
@@ -214,17 +214,17 @@
             @Override
             public String[] getDeleteReturns() {
                  // methods deleted from their return type.
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public String[] getPromotedFields() {
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
-                return new HashMap<String, InjectMethodRunnable>(0);
+                return Collections.emptyMap();
             }
         };
 
@@ -235,14 +235,14 @@
                 new String[] {        // include classes
                     "**"
                 },
-                new HashSet<String>(1),
+                Collections.<String>emptySet(),
                 new String[] {        /* include files */
                     "mock_android/data/data*"
                 });
         aa.analyze();
         agen.generate();
-        Map<String, ClassReader> output = new TreeMap<String, ClassReader>();
-        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+        Map<String, ClassReader> output = new TreeMap<>();
+        Map<String, InputStream> filesFound = new TreeMap<>();
         parseZip(mOsDestJar, output, filesFound);
         boolean injectedClassFound = false;
         for (ClassReader cr: output.values()) {
@@ -265,35 +265,35 @@
 
             @Override
             public String[] getDelegateMethods() {
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public String[] getDelegateClassNatives() {
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public String[] getOverriddenMethods() {
                 // methods to force override
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public String[] getRenamedClasses() {
                 // classes to rename (so that we can replace them)
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public String[] getJavaPkgClasses() {
                 // classes to refactor (so that we can replace them)
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public Set<String> getExcludedClasses() {
-                Set<String> set = new HashSet<String>(2);
+                Set<String> set = new HashSet<>(2);
                 set.add("mock_android.dummy.InnerTest");
                 set.add("java.lang.JavaClass");
                 return set;
@@ -302,17 +302,17 @@
             @Override
             public String[] getDeleteReturns() {
                 // methods deleted from their return type.
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public String[] getPromotedFields() {
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
-                return new HashMap<String, InjectMethodRunnable>(0);
+                return Collections.emptyMap();
             }
         };
 
@@ -329,8 +329,8 @@
                 });
         aa.analyze();
         agen.generate();
-        Map<String, ClassReader> output = new TreeMap<String, ClassReader>();
-        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+        Map<String, ClassReader> output = new TreeMap<>();
+        Map<String, InputStream> filesFound = new TreeMap<>();
         parseZip(mOsDestJar, output, filesFound);
         for (String s : output.keySet()) {
             assertFalse(excludedClasses.contains(s));
@@ -351,55 +351,52 @@
 
             @Override
             public String[] getDelegateMethods() {
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public String[] getDelegateClassNatives() {
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public String[] getOverriddenMethods() {
                 // methods to force override
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public String[] getRenamedClasses() {
                 // classes to rename (so that we can replace them)
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public String[] getJavaPkgClasses() {
                 // classes to refactor (so that we can replace them)
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public Set<String> getExcludedClasses() {
-                return new HashSet<String>(0);
+                return Collections.emptySet();
             }
 
             @Override
             public String[] getDeleteReturns() {
                 // methods deleted from their return type.
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public String[] getPromotedFields() {
-                return new String[0];
+                return EMPTY_STRING_ARRAY;
             }
 
             @Override
             public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
-                HashMap<String, InjectMethodRunnable> map =
-                        new HashMap<String, InjectMethodRunnable>(1);
-                map.put("mock_android.util.EmptyArray",
+                return Collections.singletonMap("mock_android.util.EmptyArray",
                         InjectMethodRunnables.CONTEXT_GET_FRAMEWORK_CLASS_LOADER);
-                return map;
             }
         };
 
@@ -415,8 +412,8 @@
                 });
         aa.analyze();
         agen.generate();
-        Map<String, ClassReader> output = new TreeMap<String, ClassReader>();
-        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+        Map<String, ClassReader> output = new TreeMap<>();
+        Map<String, InputStream> filesFound = new TreeMap<>();
         parseZip(mOsDestJar, output, filesFound);
         final String modifiedClass = "mock_android.util.EmptyArray";
         final String modifiedClassPath = modifiedClass.replace('.', '/').concat(".class");
@@ -424,11 +421,8 @@
         ZipEntry entry = zipFile.getEntry(modifiedClassPath);
         assertNotNull(entry);
         final byte[] bytes;
-        final InputStream inputStream = zipFile.getInputStream(entry);
-        try {
+        try (InputStream inputStream = zipFile.getInputStream(entry)) {
             bytes = getByteArray(inputStream);
-        } finally {
-            inputStream.close();
         }
         ClassLoader classLoader = new ClassLoader(getClass().getClassLoader()) {
             @Override
@@ -489,7 +483,7 @@
         boolean mInjectedClassFound = false;
 
         TestClassVisitor() {
-            super(Opcodes.ASM4);
+            super(Main.ASM_VERSION);
         }
 
         @Override
@@ -514,7 +508,7 @@
         public MethodVisitor visitMethod(int access, String name, String desc,
                 String signature, String[] exceptions) {
             MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
-            return new MethodVisitor(Opcodes.ASM4, mv) {
+            return new MethodVisitor(Main.ASM_VERSION, mv) {
 
                 @Override
                 public void visitFieldInsn(int opcode, String owner, String name,
@@ -540,10 +534,10 @@
 
                 @Override
                 public void visitMethodInsn(int opcode, String owner, String name,
-                        String desc) {
+                        String desc, boolean itf) {
                     assertTrue(!getBase(owner).equals(JAVA_CLASS_NAME));
                     assertTrue(testType(Type.getType(desc)));
-                    super.visitMethodInsn(opcode, owner, name, desc);
+                    super.visitMethodInsn(opcode, owner, name, desc, itf);
                 }
 
             };
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/ClassHasNativeVisitorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/ClassHasNativeVisitorTest.java
index 0135c40..0cdcdc0 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/ClassHasNativeVisitorTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/ClassHasNativeVisitorTest.java
@@ -60,7 +60,7 @@
      * Overrides {@link ClassHasNativeVisitor} to collec the name of the native methods found.
      */
     private static class MockClassHasNativeVisitor extends ClassHasNativeVisitor {
-        private ArrayList<String> mMethodsFound = new ArrayList<String>();
+        private ArrayList<String> mMethodsFound = new ArrayList<>();
 
         public String[] getMethodsFound() {
             return mMethodsFound.toArray(new String[mMethodsFound.size()]);
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 e37a09b..0912fb1 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
@@ -88,7 +88,7 @@
         // Now process it but tell the delegate to not modify any method
         ClassWriter cw = new ClassWriter(0 /*flags*/);
 
-        HashSet<String> delegateMethods = new HashSet<String>();
+        HashSet<String> delegateMethods = new HashSet<>();
         String internalClassName = NATIVE_CLASS_NAME.replace('.', '/');
         DelegateClassAdapter cv = new DelegateClassAdapter(
                 mLog, cw, internalClassName, delegateMethods);
@@ -152,7 +152,7 @@
 
         String internalClassName = NATIVE_CLASS_NAME.replace('.', '/');
 
-        HashSet<String> delegateMethods = new HashSet<String>();
+        HashSet<String> delegateMethods = new HashSet<>();
         delegateMethods.add("<init>");
         DelegateClassAdapter cv = new DelegateClassAdapter(
                 mLog, cw, internalClassName, delegateMethods);
@@ -166,7 +166,7 @@
         ClassWriter cw = new ClassWriter(0 /*flags*/);
         String internalClassName = NATIVE_CLASS_NAME.replace('.', '/');
 
-        HashSet<String> delegateMethods = new HashSet<String>();
+        HashSet<String> delegateMethods = new HashSet<>();
         delegateMethods.add(DelegateClassAdapter.ALL_NATIVES);
         DelegateClassAdapter cv = new DelegateClassAdapter(
                 mLog, cw, internalClassName, delegateMethods);
@@ -217,7 +217,7 @@
     @Test
     public void testDelegateInner() throws Throwable {
         // We'll delegate the "get" method of both the inner and outer class.
-        HashSet<String> delegateMethods = new HashSet<String>();
+        HashSet<String> delegateMethods = new HashSet<>();
         delegateMethods.add("get");
         delegateMethods.add("privateMethod");
 
@@ -300,7 +300,7 @@
     @Test
     public void testDelegateStaticInner() throws Throwable {
         // We'll delegate the "get" method of both the inner and outer class.
-        HashSet<String> delegateMethods = new HashSet<String>();
+        HashSet<String> delegateMethods = new HashSet<>();
         delegateMethods.add("get");
 
         // Generate the delegate for the outer class.
@@ -367,7 +367,7 @@
      */
     private abstract class ClassLoader2 extends ClassLoader {
 
-        private final Map<String, byte[]> mClassDefs = new HashMap<String, byte[]>();
+        private final Map<String, byte[]> mClassDefs = new HashMap<>();
 
         public ClassLoader2() {
             super(null);
diff --git a/tools/localedata/extract_icu_data.py b/tools/localedata/extract_icu_data.py
new file mode 100755
index 0000000..b071093
--- /dev/null
+++ b/tools/localedata/extract_icu_data.py
@@ -0,0 +1,286 @@
+#!/usr/bin/env python
+#
+# Copyright 2016 The Android Open Source Project. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+
+"""Generate a C++ data table containing locale data."""
+
+import collections
+import glob
+import os.path
+import sys
+
+
+def get_locale_parts(locale):
+    """Split a locale into three parts, for langauge, script, and region."""
+    parts = locale.split('_')
+    if len(parts) == 1:
+        return (parts[0], None, None)
+    elif len(parts) == 2:
+        if len(parts[1]) == 4:  # parts[1] is a script
+            return (parts[0], parts[1], None)
+        else:
+            return (parts[0], None, parts[1])
+    else:
+        assert len(parts) == 3
+        return tuple(parts)
+
+
+def read_likely_subtags(input_file_name):
+    """Read and parse ICU's likelySubtags.txt."""
+    with open(input_file_name) as input_file:
+        likely_script_dict = {
+            # Android's additions for pseudo-locales. These internal codes make
+            # sure that the pseudo-locales would not match other English or
+            # Arabic locales. (We can't use private-use ISO 15924 codes, since
+            # they may be used by apps for other purposes.)
+            "en_XA": "~~~A",
+            "ar_XB": "~~~B",
+        }
+        representative_locales = {
+            # Android's additions
+            "en_Latn_GB", # representative for en_Latn_001
+            "es_Latn_MX", # representative for es_Latn_419
+            "es_Latn_US", # representative for es_Latn_419 (not the best idea,
+                          # but Android has been shipping with it for quite a
+                          # while. Fortunately, MX < US, so if both exist, MX
+                          # would be chosen.)
+        }
+        for line in input_file:
+            line = unicode(line, 'UTF-8').strip(u' \n\uFEFF').encode('UTF-8')
+            if line.startswith('//'):
+                continue
+            if '{' in line and '}' in line:
+                from_locale = line[:line.index('{')]
+                to_locale = line[line.index('"')+1:line.rindex('"')]
+                from_lang, from_scr, from_region = get_locale_parts(from_locale)
+                _, to_scr, to_region = get_locale_parts(to_locale)
+                if from_lang == 'und':
+                    continue  # not very useful for our purposes
+                if from_region is None and to_region != '001':
+                    representative_locales.add(to_locale)
+                if from_scr is None:
+                    likely_script_dict[from_locale] = to_scr
+        return likely_script_dict, frozenset(representative_locales)
+
+
+# From packLanguageOrRegion() in ResourceTypes.cpp
+def pack_language_or_region(inp, base):
+    """Pack langauge or region in a two-byte tuple."""
+    if inp is None:
+        return (0, 0)
+    elif len(inp) == 2:
+        return ord(inp[0]), ord(inp[1])
+    else:
+        assert len(inp) == 3
+        base = ord(base)
+        first = ord(inp[0]) - base
+        second = ord(inp[1]) - base
+        third = ord(inp[2]) - base
+
+        return (0x80 | (third << 2) | (second >>3),
+                ((second << 5) | first) & 0xFF)
+
+
+# From packLanguage() in ResourceTypes.cpp
+def pack_language(language):
+    """Pack language in a two-byte tuple."""
+    return pack_language_or_region(language, 'a')
+
+
+# From packRegion() in ResourceTypes.cpp
+def pack_region(region):
+    """Pack region in a two-byte tuple."""
+    return pack_language_or_region(region, '0')
+
+
+def pack_to_uint32(locale):
+    """Pack language+region of locale into a 32-bit unsigned integer."""
+    lang, _, region = get_locale_parts(locale)
+    plang = pack_language(lang)
+    pregion = pack_region(region)
+    return (plang[0] << 24) | (plang[1] << 16) | (pregion[0] << 8) | pregion[1]
+
+
+def dump_script_codes(all_scripts):
+    """Dump the SCRIPT_CODES table."""
+    print 'const char SCRIPT_CODES[][4] = {'
+    for index, script in enumerate(all_scripts):
+        print "    /* %-2d */ {'%c', '%c', '%c', '%c'}," % (
+            index, script[0], script[1], script[2], script[3])
+    print '};'
+    print
+
+
+def dump_script_data(likely_script_dict, all_scripts):
+    """Dump the script data."""
+    print
+    print 'const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({'
+    for locale in sorted(likely_script_dict.keys()):
+        script = likely_script_dict[locale]
+        print '    {0x%08Xu, %2du}, // %s -> %s' % (
+            pack_to_uint32(locale),
+            all_scripts.index(script),
+            locale.replace('_', '-'),
+            script)
+    print '});'
+
+
+def pack_to_uint64(locale):
+    """Pack a full locale into a 64-bit unsigned integer."""
+    _, script, _ = get_locale_parts(locale)
+    return ((pack_to_uint32(locale) << 32) |
+            (ord(script[0]) << 24) |
+            (ord(script[1]) << 16) |
+            (ord(script[2]) << 8) |
+            ord(script[3]))
+
+
+def dump_representative_locales(representative_locales):
+    """Dump the set of representative locales."""
+    print
+    print 'std::unordered_set<uint64_t> REPRESENTATIVE_LOCALES({'
+    for locale in sorted(representative_locales):
+        print '    0x%08Xllu, // %s' % (
+            pack_to_uint64(locale),
+            locale)
+    print '});'
+
+
+def read_and_dump_likely_data(icu_data_dir):
+    """Read and dump the likely-script data."""
+    likely_subtags_txt = os.path.join(icu_data_dir, 'misc', 'likelySubtags.txt')
+    likely_script_dict, representative_locales = read_likely_subtags(
+        likely_subtags_txt)
+
+    all_scripts = list(set(likely_script_dict.values()))
+    assert len(all_scripts) <= 256
+    all_scripts.sort()
+
+    dump_script_codes(all_scripts)
+    dump_script_data(likely_script_dict, all_scripts)
+    dump_representative_locales(representative_locales)
+    return likely_script_dict
+
+
+def read_parent_data(icu_data_dir):
+    """Read locale parent data from ICU data files."""
+    all_icu_data_files = glob.glob(os.path.join(icu_data_dir, '*', '*.txt'))
+    parent_dict = {}
+    for data_file in all_icu_data_files:
+        locale = os.path.splitext(os.path.basename(data_file))[0]
+        with open(data_file) as input_file:
+            for line in input_file:
+                if '%%Parent' in line:
+                    parent = line[line.index('"')+1:line.rindex('"')]
+                    if locale in parent_dict:
+                        # Different files shouldn't have different parent info
+                        assert parent_dict[locale] == parent
+                    else:
+                        parent_dict[locale] = parent
+                elif locale.startswith('ar_') and 'default{"latn"}' in line:
+                    # Arabic parent overrides for ASCII digits. Since
+                    # Unicode extensions are not supported in ResourceTypes,
+                    # we will use ar-015 (Arabic, Northern Africa) instead
+                    # of the more correct ar-u-nu-latn.
+                    parent_dict[locale] = 'ar_015'
+    return parent_dict
+
+
+def get_likely_script(locale, likely_script_dict):
+    """Find the likely script for a locale, given the likely-script dictionary.
+    """
+    if locale.count('_') == 2:
+        # it already has a script
+        return locale.split('_')[1]
+    elif locale in likely_script_dict:
+        return likely_script_dict[locale]
+    else:
+        language = locale.split('_')[0]
+        return likely_script_dict[language]
+
+
+def dump_parent_data(script_organized_dict):
+    """Dump information for parents of locales."""
+    sorted_scripts = sorted(script_organized_dict.keys())
+    print
+    for script in sorted_scripts:
+        parent_dict = script_organized_dict[script]
+        print ('const std::unordered_map<uint32_t, uint32_t> %s_PARENTS({'
+            % script.upper())
+        for locale in sorted(parent_dict.keys()):
+            parent = parent_dict[locale]
+            print '    {0x%08Xu, 0x%08Xu}, // %s -> %s' % (
+                pack_to_uint32(locale),
+                pack_to_uint32(parent),
+                locale.replace('_', '-'),
+                parent.replace('_', '-'))
+        print '});'
+        print
+
+    print 'const struct {'
+    print '    const char script[4];'
+    print '    const std::unordered_map<uint32_t, uint32_t>* map;'
+    print '} SCRIPT_PARENTS[] = {'
+    for script in sorted_scripts:
+        print "    {{'%c', '%c', '%c', '%c'}, &%s_PARENTS}," % (
+            script[0], script[1], script[2], script[3],
+            script.upper())
+    print '};'
+
+
+def dump_parent_tree_depth(parent_dict):
+    """Find and dump the depth of the parent tree."""
+    max_depth = 1
+    for locale, _ in parent_dict.items():
+        depth = 1
+        while locale in parent_dict:
+            locale = parent_dict[locale]
+            depth += 1
+        max_depth = max(max_depth, depth)
+    assert max_depth < 5 # Our algorithms assume small max_depth
+    print
+    print 'const size_t MAX_PARENT_DEPTH = %d;' % max_depth
+
+
+def read_and_dump_parent_data(icu_data_dir, likely_script_dict):
+    """Read parent data from ICU and dump it."""
+    parent_dict = read_parent_data(icu_data_dir)
+    script_organized_dict = collections.defaultdict(dict)
+    for locale in parent_dict:
+        parent = parent_dict[locale]
+        if parent == 'root':
+            continue
+        script = get_likely_script(locale, likely_script_dict)
+        script_organized_dict[script][locale] = parent_dict[locale]
+    dump_parent_data(script_organized_dict)
+    dump_parent_tree_depth(parent_dict)
+
+
+def main():
+    """Read the data files from ICU and dump the output to a C++ file."""
+    source_root = sys.argv[1]
+    icu_data_dir = os.path.join(
+        source_root,
+        'external', 'icu', 'icu4c', 'source', 'data')
+
+    print '// Auto-generated by %s' % sys.argv[0]
+    print
+    likely_script_dict = read_and_dump_likely_data(icu_data_dir)
+    read_and_dump_parent_data(icu_data_dir, likely_script_dict)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/tools/preload2/Android.mk b/tools/preload2/Android.mk
new file mode 100644
index 0000000..35d28fb
--- /dev/null
+++ b/tools/preload2/Android.mk
@@ -0,0 +1,32 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+# To connect to devices (and take hprof dumps).
+LOCAL_STATIC_JAVA_LIBRARIES := ddmlib-prebuilt
+
+# To process hprof dumps.
+LOCAL_STATIC_JAVA_LIBRARIES += perflib-prebuilt trove-prebuilt guavalib
+
+# For JDWP access we use the framework in the JDWP tests from Apache Harmony, for
+# convenience (and to not depend on internal JDK APIs).
+LOCAL_STATIC_JAVA_LIBRARIES += apache-harmony-jdwp-tests-host junit
+
+LOCAL_MODULE:= preload2
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+# Copy the preload-tool shell script to the host's bin directory.
+include $(CLEAR_VARS)
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE := preload-tool
+include $(BUILD_SYSTEM)/base_rules.mk
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/preload-tool $(ACP)
+	@echo "Copy: $(PRIVATE_MODULE) ($@)"
+	$(copy-file-to-new-target)
+	$(hide) chmod 755 $@
diff --git a/tools/preload2/preload-tool b/tools/preload2/preload-tool
new file mode 100644
index 0000000..36dbc1c
--- /dev/null
+++ b/tools/preload2/preload-tool
@@ -0,0 +1,37 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This script is used on the host only. It uses a common subset
+# shell dialect that should work well. It is partially derived
+# from art/tools/art.
+
+function follow_links() {
+  if [ z"$BASH_SOURCE" != z ]; then
+    file="$BASH_SOURCE"
+  else
+    file="$0"
+  fi
+  while [ -h "$file" ]; do
+    # On Mac OS, readlink -f doesn't work.
+    file="$(readlink "$file")"
+  done
+  echo "$file"
+}
+
+
+PROG_NAME="$(follow_links)"
+PROG_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+ANDROID_ROOT=$PROG_DIR/..
+
+java -cp $ANDROID_ROOT/framework/preload2.jar com.android.preload.Main
diff --git a/tools/preload2/src/com/android/preload/ClientUtils.java b/tools/preload2/src/com/android/preload/ClientUtils.java
new file mode 100644
index 0000000..71ef025
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/ClientUtils.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload;
+
+import com.android.ddmlib.AndroidDebugBridge;
+import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener;
+import com.android.ddmlib.Client;
+import com.android.ddmlib.IDevice;
+
+/**
+ * Helper class for common communication with a Client (the ddms name for a running application).
+ *
+ * Instances take a default timeout parameter that's applied to all functions without explicit
+ * timeout. Timeouts are in milliseconds.
+ */
+public class ClientUtils {
+
+    private int defaultTimeout;
+
+    public ClientUtils() {
+        this(10000);
+    }
+
+    public ClientUtils(int defaultTimeout) {
+        this.defaultTimeout = defaultTimeout;
+    }
+
+    /**
+     * Shortcut for findClient with default timeout.
+     */
+    public Client findClient(IDevice device, String processName, int processPid) {
+        return findClient(device, processName, processPid, defaultTimeout);
+    }
+
+    /**
+     * Find the client with the given process name or process id. The name takes precedence over
+     * the process id (if valid). Stop looking after the given timeout.
+     *
+     * @param device The device to communicate with.
+     * @param processName The name of the process. May be null.
+     * @param processPid The pid of the process. Values less than or equal to zero are ignored.
+     * @param timeout The amount of milliseconds to wait, at most.
+     * @return The client, if found. Otherwise null.
+     */
+    public Client findClient(IDevice device, String processName, int processPid, int timeout) {
+        WaitForClient wfc = new WaitForClient(device, processName, processPid, timeout);
+        return wfc.get();
+    }
+
+    /**
+     * Shortcut for findAllClients with default timeout.
+     */
+    public Client[] findAllClients(IDevice device) {
+        return findAllClients(device, defaultTimeout);
+    }
+
+    /**
+     * Retrieve all clients known to the given device. Wait at most the given timeout.
+     *
+     * @param device The device to investigate.
+     * @param timeout The amount of milliseconds to wait, at most.
+     * @return An array of clients running on the given device. May be null depending on the
+     *         device implementation.
+     */
+    public Client[] findAllClients(IDevice device, int timeout) {
+        if (device.hasClients()) {
+            return device.getClients();
+        }
+        WaitForClients wfc = new WaitForClients(device, timeout);
+        return wfc.get();
+    }
+
+    private static class WaitForClient implements IClientChangeListener {
+
+        private IDevice device;
+        private String processName;
+        private int processPid;
+        private long timeout;
+        private Client result;
+
+        public WaitForClient(IDevice device, String processName, int processPid, long timeout) {
+            this.device = device;
+            this.processName = processName;
+            this.processPid = processPid;
+            this.timeout = timeout;
+            this.result = null;
+        }
+
+        public Client get() {
+            synchronized (this) {
+                AndroidDebugBridge.addClientChangeListener(this);
+
+                // Maybe it's already there.
+                if (result == null) {
+                    result = searchForClient(device);
+                }
+
+                if (result == null) {
+                    try {
+                        wait(timeout);
+                    } catch (InterruptedException e) {
+                        // Note: doesn't guard for spurious wakeup.
+                    }
+                }
+            }
+
+            AndroidDebugBridge.removeClientChangeListener(this);
+            return result;
+        }
+
+        private Client searchForClient(IDevice device) {
+            if (processName != null) {
+                Client tmp = device.getClient(processName);
+                if (tmp != null) {
+                    return tmp;
+                }
+            }
+            if (processPid > 0) {
+                String name = device.getClientName(processPid);
+                if (name != null && !name.isEmpty()) {
+                    Client tmp = device.getClient(name);
+                    if (tmp != null) {
+                        return tmp;
+                    }
+                }
+            }
+            if (processPid > 0) {
+                // Try manual search.
+                for (Client cl : device.getClients()) {
+                    if (cl.getClientData().getPid() == processPid
+                            && cl.getClientData().getClientDescription() != null) {
+                        return cl;
+                    }
+                }
+            }
+            return null;
+        }
+
+        private boolean isTargetClient(Client c) {
+            if (processPid > 0 && c.getClientData().getPid() == processPid) {
+                return true;
+            }
+            if (processName != null
+                    && processName.equals(c.getClientData().getClientDescription())) {
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public void clientChanged(Client arg0, int arg1) {
+            synchronized (this) {
+                if ((arg1 & Client.CHANGE_INFO) != 0 && (arg0.getDevice() == device)) {
+                    if (isTargetClient(arg0)) {
+                        result = arg0;
+                        notifyAll();
+                    }
+                }
+            }
+        }
+    }
+
+    private static class WaitForClients implements IClientChangeListener {
+
+        private IDevice device;
+        private long timeout;
+
+        public WaitForClients(IDevice device, long timeout) {
+            this.device = device;
+            this.timeout = timeout;
+        }
+
+        public Client[] get() {
+            synchronized (this) {
+                AndroidDebugBridge.addClientChangeListener(this);
+
+                if (device.hasClients()) {
+                    return device.getClients();
+                }
+
+                try {
+                    wait(timeout); // Note: doesn't guard for spurious wakeup.
+                } catch (InterruptedException exc) {
+                }
+
+                // We will be woken up when the first client data arrives. Sleep a little longer
+                // to give (hopefully all of) the rest of the clients a chance to become available.
+                // Note: a loop with timeout is brittle as well and complicated, just accept this
+                //       for now.
+                try {
+                    Thread.sleep(500);
+                } catch (InterruptedException exc) {
+                }
+            }
+
+            AndroidDebugBridge.removeClientChangeListener(this);
+
+            return device.getClients();
+        }
+
+        @Override
+        public void clientChanged(Client arg0, int arg1) {
+            synchronized (this) {
+                if ((arg1 & Client.CHANGE_INFO) != 0 && (arg0.getDevice() == device)) {
+                    notifyAll();
+                }
+            }
+        }
+    }
+}
diff --git a/tools/preload2/src/com/android/preload/DeviceUtils.java b/tools/preload2/src/com/android/preload/DeviceUtils.java
new file mode 100644
index 0000000..72de7b5
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/DeviceUtils.java
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload;
+
+import com.android.ddmlib.AndroidDebugBridge;
+import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
+import com.android.preload.classdataretrieval.hprof.Hprof;
+import com.android.ddmlib.DdmPreferences;
+import com.android.ddmlib.IDevice;
+import com.android.ddmlib.IShellOutputReceiver;
+
+import java.util.Date;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Helper class for some device routines.
+ */
+public class DeviceUtils {
+
+  public static void init(int debugPort) {
+    DdmPreferences.setSelectedDebugPort(debugPort);
+
+    Hprof.init();
+
+    AndroidDebugBridge.init(true);
+
+    AndroidDebugBridge.createBridge();
+  }
+
+  /**
+   * Run a command in the shell on the device.
+   */
+  public static void doShell(IDevice device, String cmdline, long timeout, TimeUnit unit) {
+    doShell(device, cmdline, new NullShellOutputReceiver(), timeout, unit);
+  }
+
+  /**
+   * Run a command in the shell on the device. Collects and returns the console output.
+   */
+  public static String doShellReturnString(IDevice device, String cmdline, long timeout,
+      TimeUnit unit) {
+    CollectStringShellOutputReceiver rec = new CollectStringShellOutputReceiver();
+    doShell(device, cmdline, rec, timeout, unit);
+    return rec.toString();
+  }
+
+  /**
+   * Run a command in the shell on the device, directing all output to the given receiver.
+   */
+  public static void doShell(IDevice device, String cmdline, IShellOutputReceiver receiver,
+      long timeout, TimeUnit unit) {
+    try {
+      device.executeShellCommand(cmdline, receiver, timeout, unit);
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+  /**
+   * Run am start on the device.
+   */
+  public static void doAMStart(IDevice device, String name, String activity) {
+    doShell(device, "am start -n " + name + " /." + activity, 30, TimeUnit.SECONDS);
+  }
+
+  /**
+   * Find the device with the given serial. Give up after the given timeout (in milliseconds).
+   */
+  public static IDevice findDevice(String serial, int timeout) {
+    WaitForDevice wfd = new WaitForDevice(serial, timeout);
+    return wfd.get();
+  }
+
+  /**
+   * Get all devices ddms knows about. Wait at most for the given timeout.
+   */
+  public static IDevice[] findDevices(int timeout) {
+    WaitForDevice wfd = new WaitForDevice(null, timeout);
+    wfd.get();
+    return AndroidDebugBridge.getBridge().getDevices();
+  }
+
+  /**
+   * Return the build type of the given device. This is the value of the "ro.build.type"
+   * system property.
+   */
+  public static String getBuildType(IDevice device) {
+    try {
+      Future<String> buildType = device.getSystemProperty("ro.build.type");
+      return buildType.get(500, TimeUnit.MILLISECONDS);
+    } catch (Exception e) {
+    }
+    return null;
+  }
+
+  /**
+   * Check whether the given device has a pre-optimized boot image. More precisely, checks
+   * whether /system/framework/ * /boot.art exists.
+   */
+  public static boolean hasPrebuiltBootImage(IDevice device) {
+    String ret =
+        doShellReturnString(device, "ls /system/framework/*/boot.art", 500, TimeUnit.MILLISECONDS);
+
+    return !ret.contains("No such file or directory");
+  }
+
+  /**
+   * Remove files involved in a standard build that interfere with collecting data. This will
+   * remove /etc/preloaded-classes, which determines which classes are allocated already in the
+   * boot image. It also deletes any compiled boot image on the device. Then it restarts the
+   * device.
+   *
+   * This is a potentially long-running operation, as the boot after the deletion may take a while.
+   * The method will abort after the given timeout.
+   */
+  public static boolean removePreloaded(IDevice device, long preloadedWaitTimeInSeconds) {
+    String oldContent =
+        DeviceUtils.doShellReturnString(device, "cat /etc/preloaded-classes", 1, TimeUnit.SECONDS);
+    if (oldContent.trim().equals("")) {
+      System.out.println("Preloaded-classes already empty.");
+      return true;
+    }
+
+    // Stop the system server etc.
+    doShell(device, "stop", 100, TimeUnit.MILLISECONDS);
+
+    // Remount /system, delete /etc/preloaded-classes. It would be nice to use "adb remount,"
+    // but AndroidDebugBridge doesn't expose it.
+    doShell(device, "mount -o remount,rw /system", 500, TimeUnit.MILLISECONDS);
+    doShell(device, "rm /etc/preloaded-classes", 100, TimeUnit.MILLISECONDS);
+    // We do need an empty file.
+    doShell(device, "touch /etc/preloaded-classes", 100, TimeUnit.MILLISECONDS);
+
+    // Delete the files in the dalvik cache.
+    doShell(device, "rm /data/dalvik-cache/*/*boot.art", 500, TimeUnit.MILLISECONDS);
+
+    // We'll try to use dev.bootcomplete to know when the system server is back up. But stop
+    // doesn't reset it, so do it manually.
+    doShell(device, "setprop dev.bootcomplete \"0\"", 500, TimeUnit.MILLISECONDS);
+
+    // Start the system server.
+    doShell(device, "start", 100, TimeUnit.MILLISECONDS);
+
+    // Do a loop checking each second whether bootcomplete. Wait for at most the given
+    // threshold.
+    Date startDate = new Date();
+    for (;;) {
+      try {
+        Thread.sleep(1000);
+      } catch (InterruptedException e) {
+        // Ignore spurious wakeup.
+      }
+      // Check whether bootcomplete.
+      String ret =
+          doShellReturnString(device, "getprop dev.bootcomplete", 500, TimeUnit.MILLISECONDS);
+      if (ret.trim().equals("1")) {
+        break;
+      }
+      System.out.println("Still not booted: " + ret);
+
+      // Check whether we timed out. This is a simplistic check that doesn't take into account
+      // things like switches in time.
+      Date endDate = new Date();
+      long seconds =
+          TimeUnit.SECONDS.convert(endDate.getTime() - startDate.getTime(), TimeUnit.MILLISECONDS);
+      if (seconds > preloadedWaitTimeInSeconds) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  /**
+   * Enable method-tracing on device. The system should be restarted after this.
+   */
+  public static void enableTracing(IDevice device) {
+    // Disable selinux.
+    doShell(device, "setenforce 0", 100, TimeUnit.MILLISECONDS);
+
+    // Make the profile directory world-writable.
+    doShell(device, "chmod 777 /data/dalvik-cache/profiles", 100, TimeUnit.MILLISECONDS);
+
+    // Enable streaming method tracing with a small 1K buffer.
+    doShell(device, "setprop dalvik.vm.method-trace true", 100, TimeUnit.MILLISECONDS);
+    doShell(device, "setprop dalvik.vm.method-trace-file "
+                    + "/data/dalvik-cache/profiles/zygote.trace.bin", 100, TimeUnit.MILLISECONDS);
+    doShell(device, "setprop dalvik.vm.method-trace-file-siz 1024", 100, TimeUnit.MILLISECONDS);
+    doShell(device, "setprop dalvik.vm.method-trace-stream true", 100, TimeUnit.MILLISECONDS);
+  }
+
+  private static class NullShellOutputReceiver implements IShellOutputReceiver {
+    @Override
+    public boolean isCancelled() {
+      return false;
+    }
+
+    @Override
+    public void flush() {}
+
+    @Override
+    public void addOutput(byte[] arg0, int arg1, int arg2) {}
+  }
+
+  private static class CollectStringShellOutputReceiver implements IShellOutputReceiver {
+
+    private StringBuilder builder = new StringBuilder();
+
+    @Override
+    public String toString() {
+      String ret = builder.toString();
+      // Strip trailing newlines. They are especially ugly because adb uses DOS line endings.
+      while (ret.endsWith("\r") || ret.endsWith("\n")) {
+        ret = ret.substring(0, ret.length() - 1);
+      }
+      return ret;
+    }
+
+    @Override
+    public void addOutput(byte[] arg0, int arg1, int arg2) {
+      builder.append(new String(arg0, arg1, arg2));
+    }
+
+    @Override
+    public void flush() {}
+
+    @Override
+    public boolean isCancelled() {
+      return false;
+    }
+  }
+
+  private static class WaitForDevice {
+
+    private String serial;
+    private long timeout;
+    private IDevice device;
+
+    public WaitForDevice(String serial, long timeout) {
+      this.serial = serial;
+      this.timeout = timeout;
+      device = null;
+    }
+
+    public IDevice get() {
+      if (device == null) {
+          WaitForDeviceListener wfdl = new WaitForDeviceListener(serial);
+          synchronized (wfdl) {
+              AndroidDebugBridge.addDeviceChangeListener(wfdl);
+
+              // Check whether we already know about this device.
+              IDevice[] devices = AndroidDebugBridge.getBridge().getDevices();
+              if (serial != null) {
+                  for (IDevice d : devices) {
+                      if (serial.equals(d.getSerialNumber())) {
+                          // Only accept if there are clients already. Else wait for the callback informing
+                          // us that we now have clients.
+                          if (d.hasClients()) {
+                              device = d;
+                          }
+
+                          break;
+                      }
+                  }
+              } else {
+                  if (devices.length > 0) {
+                      device = devices[0];
+                  }
+              }
+
+              if (device == null) {
+                  try {
+                      wait(timeout);
+                  } catch (InterruptedException e) {
+                      // Ignore spurious wakeups.
+                  }
+                  device = wfdl.getDevice();
+              }
+
+              AndroidDebugBridge.removeDeviceChangeListener(wfdl);
+          }
+      }
+
+      if (device != null) {
+          // Wait for clients.
+          WaitForClientsListener wfcl = new WaitForClientsListener(device);
+          synchronized (wfcl) {
+              AndroidDebugBridge.addDeviceChangeListener(wfcl);
+
+              if (!device.hasClients()) {
+                  try {
+                      wait(timeout);
+                  } catch (InterruptedException e) {
+                      // Ignore spurious wakeups.
+                  }
+              }
+
+              AndroidDebugBridge.removeDeviceChangeListener(wfcl);
+          }
+      }
+
+      return device;
+    }
+
+    private static class WaitForDeviceListener implements IDeviceChangeListener {
+
+        private String serial;
+        private IDevice device;
+
+        public WaitForDeviceListener(String serial) {
+            this.serial = serial;
+        }
+
+        public IDevice getDevice() {
+            return device;
+        }
+
+        @Override
+        public void deviceChanged(IDevice arg0, int arg1) {
+            // We may get a device changed instead of connected. Handle like a connection.
+            deviceConnected(arg0);
+        }
+
+        @Override
+        public void deviceConnected(IDevice arg0) {
+            if (device != null) {
+                // Ignore updates.
+                return;
+            }
+
+            if (serial == null || serial.equals(arg0.getSerialNumber())) {
+                device = arg0;
+                synchronized (this) {
+                    notifyAll();
+                }
+            }
+        }
+
+        @Override
+        public void deviceDisconnected(IDevice arg0) {
+            // Ignore disconnects.
+        }
+
+    }
+
+    private static class WaitForClientsListener implements IDeviceChangeListener {
+
+        private IDevice myDevice;
+
+        public WaitForClientsListener(IDevice myDevice) {
+            this.myDevice = myDevice;
+        }
+
+        @Override
+        public void deviceChanged(IDevice arg0, int arg1) {
+            if (arg0 == myDevice && (arg1 & IDevice.CHANGE_CLIENT_LIST) != 0) {
+                // Got a client list, done here.
+                synchronized (this) {
+                    notifyAll();
+                }
+            }
+        }
+
+        @Override
+        public void deviceConnected(IDevice arg0) {
+        }
+
+        @Override
+        public void deviceDisconnected(IDevice arg0) {
+        }
+
+    }
+  }
+
+}
diff --git a/tools/preload2/src/com/android/preload/DumpData.java b/tools/preload2/src/com/android/preload/DumpData.java
new file mode 100644
index 0000000..d997224
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/DumpData.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Holds the collected data for a process.
+ */
+public class DumpData {
+    /**
+     * Name of the package (=application).
+     */
+    String packageName;
+
+    /**
+     * A map of class name to a string for the classloader. This may be a toString equivalent,
+     * or just a unique ID.
+     */
+    Map<String, String> dumpData;
+
+    /**
+     * The Date when this data was captured. Mostly for display purposes.
+     */
+    Date date;
+
+    /**
+     * A cached value for the number of boot classpath classes (classloader value in dumpData is
+     * null).
+     */
+    int bcpClasses;
+
+    public DumpData(String packageName, Map<String, String> dumpData, Date date) {
+        this.packageName = packageName;
+        this.dumpData = dumpData;
+        this.date = date;
+
+        countBootClassPath();
+    }
+
+    public String getPackageName() {
+        return packageName;
+    }
+
+    public Date getDate() {
+        return date;
+    }
+
+    public Map<String, String> getDumpData() {
+        return dumpData;
+    }
+
+    public void countBootClassPath() {
+        bcpClasses = 0;
+        for (Map.Entry<String, String> e : dumpData.entrySet()) {
+            if (e.getValue() == null) {
+                bcpClasses++;
+            }
+        }
+    }
+
+    // Return an inverted mapping.
+    public Map<String, Set<String>> invertData() {
+        Map<String, Set<String>> ret = new HashMap<>();
+        for (Map.Entry<String, String> e : dumpData.entrySet()) {
+            if (!ret.containsKey(e.getValue())) {
+                ret.put(e.getValue(), new HashSet<String>());
+            }
+            ret.get(e.getValue()).add(e.getKey());
+        }
+        return ret;
+    }
+}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/DumpDataIO.java b/tools/preload2/src/com/android/preload/DumpDataIO.java
new file mode 100644
index 0000000..28625c5
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/DumpDataIO.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+import java.io.File;
+import java.io.FileReader;
+import java.text.DateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+/**
+ * Helper class for serialization and deserialization of a collection of DumpData objects to XML.
+ */
+public class DumpDataIO {
+
+  /**
+   * Serialize the given collection to an XML document. Returns the produced string.
+   */
+  public static String serialize(Collection<DumpData> data) {
+      // We'll do this by hand, constructing a DOM or similar is too complicated for our simple
+      // use case.
+
+      StringBuilder sb = new StringBuilder();
+      sb.append("<preloaded-classes-data>\n");
+
+      for (DumpData d : data) {
+          serialize(d, sb);
+      }
+
+      sb.append("</preloaded-classes-data>\n");
+      return sb.toString();
+  }
+
+  private static void serialize(DumpData d, StringBuilder sb) {
+      sb.append("<data package=\"" + d.packageName + "\" date=\"" +
+              DateFormat.getDateTimeInstance().format(d.date) +"\">\n");
+
+      for (Map.Entry<String, String> e : d.dumpData.entrySet()) {
+          sb.append("<class name=\"" + e.getKey() + "\" classloader=\"" + e.getValue() + "\"/>\n");
+      }
+
+      sb.append("</data>\n");
+  }
+
+  /**
+   * Load a collection of DumpData objects from the given file.
+   */
+  public static Collection<DumpData> deserialize(File f) throws Exception {
+      // Use SAX parsing. Our format is very simple. Don't do any schema validation or such.
+
+      SAXParserFactory spf = SAXParserFactory.newInstance();
+      spf.setNamespaceAware(false);
+      SAXParser saxParser = spf.newSAXParser();
+
+      XMLReader xmlReader = saxParser.getXMLReader();
+      DumpDataContentHandler ddch = new DumpDataContentHandler();
+      xmlReader.setContentHandler(ddch);
+      xmlReader.parse(new InputSource(new FileReader(f)));
+
+      return ddch.data;
+  }
+
+  private static class DumpDataContentHandler extends DefaultHandler {
+      Collection<DumpData> data = new LinkedList<DumpData>();
+      DumpData openData = null;
+
+      @Override
+      public void startElement(String uri, String localName, String qName, Attributes attributes)
+              throws SAXException {
+          if (qName.equals("data")) {
+              if (openData != null) {
+                  throw new IllegalStateException();
+              }
+              String pkg = attributes.getValue("package");
+              String dateString = attributes.getValue("date");
+
+              if (pkg == null || dateString == null) {
+                  throw new IllegalArgumentException();
+              }
+
+              try {
+                  Date date = DateFormat.getDateTimeInstance().parse(dateString);
+                  openData = new DumpData(pkg, new HashMap<String, String>(), date);
+              } catch (Exception e) {
+                  throw new RuntimeException(e);
+              }
+          } else if (qName.equals("class")) {
+              if (openData == null) {
+                  throw new IllegalStateException();
+              }
+              String className = attributes.getValue("name");
+              String classLoader = attributes.getValue("classloader");
+
+              if (className == null || classLoader == null) {
+                  throw new IllegalArgumentException();
+              }
+
+              openData.dumpData.put(className, classLoader.equals("null") ? null : classLoader);
+          }
+      }
+
+      @Override
+      public void endElement(String uri, String localName, String qName) throws SAXException {
+          if (qName.equals("data")) {
+              if (openData == null) {
+                  throw new IllegalStateException();
+              }
+              openData.countBootClassPath();
+
+              data.add(openData);
+              openData = null;
+          }
+      }
+  }
+}
diff --git a/tools/preload2/src/com/android/preload/DumpTableModel.java b/tools/preload2/src/com/android/preload/DumpTableModel.java
new file mode 100644
index 0000000..d97cbf0
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/DumpTableModel.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.table.AbstractTableModel;
+
+/**
+ * A table model for collected DumpData. This is both the internal storage as well as the model
+ * for display.
+ */
+public class DumpTableModel extends AbstractTableModel {
+
+    private List<DumpData> data = new ArrayList<DumpData>();
+
+    public void addData(DumpData d) {
+        data.add(d);
+        fireTableRowsInserted(data.size() - 1, data.size() - 1);
+    }
+
+    public void clear() {
+        int size = data.size();
+        if (size > 0) {
+            data.clear();
+            fireTableRowsDeleted(0, size - 1);
+        }
+    }
+
+    public List<DumpData> getData() {
+        return data;
+    }
+
+    @Override
+    public int getRowCount() {
+        return data.size();
+    }
+
+    @Override
+    public int getColumnCount() {
+        return 4;
+    }
+
+    @Override
+    public String getColumnName(int column) {
+        switch (column) {
+            case 0:
+                return "Package";
+            case 1:
+                return "Date";
+            case 2:
+                return "# All Classes";
+            case 3:
+                return "# Boot Classpath Classes";
+
+            default:
+                throw new IndexOutOfBoundsException(String.valueOf(column));
+        }
+    }
+
+    @Override
+    public Object getValueAt(int rowIndex, int columnIndex) {
+        DumpData d = data.get(rowIndex);
+        switch (columnIndex) {
+            case 0:
+                return d.packageName;
+            case 1:
+                return d.date;
+            case 2:
+                return d.dumpData.size();
+            case 3:
+                return d.bcpClasses;
+
+            default:
+                throw new IndexOutOfBoundsException(String.valueOf(columnIndex));
+        }
+    }
+}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/Main.java b/tools/preload2/src/com/android/preload/Main.java
new file mode 100644
index 0000000..ca5b0e0
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/Main.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload;
+
+import com.android.ddmlib.Client;
+import com.android.ddmlib.IDevice;
+import com.android.preload.actions.ClearTableAction;
+import com.android.preload.actions.ComputeThresholdAction;
+import com.android.preload.actions.ComputeThresholdXAction;
+import com.android.preload.actions.DeviceSpecific;
+import com.android.preload.actions.ExportAction;
+import com.android.preload.actions.ImportAction;
+import com.android.preload.actions.ReloadListAction;
+import com.android.preload.actions.RunMonkeyAction;
+import com.android.preload.actions.ScanAllPackagesAction;
+import com.android.preload.actions.ScanPackageAction;
+import com.android.preload.actions.ShowDataAction;
+import com.android.preload.classdataretrieval.ClassDataRetriever;
+import com.android.preload.classdataretrieval.hprof.Hprof;
+import com.android.preload.classdataretrieval.jdwp.JDWPClassDataRetriever;
+import com.android.preload.ui.UI;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.Action;
+import javax.swing.DefaultListModel;
+
+public class Main {
+
+    /**
+     * Enable tracing mode. This is a work-in-progress to derive compiled-methods data, so it is
+     * off for now.
+     */
+    public final static boolean ENABLE_TRACING = false;
+
+    /**
+     * Ten-second timeout.
+     */
+    public final static int DEFAULT_TIMEOUT_MILLIS = 10 * 1000;
+
+    /**
+     * Hprof timeout. Two minutes.
+     */
+    public final static int HPROF_TIMEOUT_MILLIS = 120 * 1000;
+
+    private IDevice device;
+    private static ClientUtils clientUtils;
+
+    private DumpTableModel dataTableModel;
+    private DefaultListModel<Client> clientListModel;
+
+    private UI ui;
+
+    // Actions that need to be updated once a device is selected.
+    private Collection<DeviceSpecific> deviceSpecificActions;
+
+    // Current main instance.
+    private static Main top;
+    private static boolean useJdwpClassDataRetriever = false;
+
+    public final static String CLASS_PRELOAD_BLACKLIST = "android.app.AlarmManager$" + "|"
+            + "android.app.SearchManager$" + "|" + "android.os.FileObserver$" + "|"
+            + "com.android.server.PackageManagerService\\$AppDirObserver$" + "|" +
+
+
+            // Threads
+            "android.os.AsyncTask$" + "|" + "android.pim.ContactsAsyncHelper$" + "|"
+            + "android.webkit.WebViewClassic\\$1$" + "|" + "java.lang.ProcessManager$" + "|"
+            + "(.*\\$NoPreloadHolder$)";
+
+    /**
+     * @param args
+     */
+    public static void main(String[] args) {
+        Main m = new Main();
+        top = m;
+
+        m.startUp();
+    }
+
+    public Main() {
+        clientListModel = new DefaultListModel<Client>();
+        dataTableModel = new DumpTableModel();
+
+        clientUtils = new ClientUtils(DEFAULT_TIMEOUT_MILLIS);  // Client utils with 10s timeout.
+
+        List<Action> actions = new ArrayList<Action>();
+        actions.add(new ReloadListAction(clientUtils, null, clientListModel));
+        actions.add(new ClearTableAction(dataTableModel));
+        actions.add(new RunMonkeyAction(null, dataTableModel));
+        actions.add(new ScanPackageAction(clientUtils, null, dataTableModel));
+        actions.add(new ScanAllPackagesAction(clientUtils, null, dataTableModel));
+        actions.add(new ComputeThresholdAction("Compute preloaded-classes", dataTableModel, 2,
+                CLASS_PRELOAD_BLACKLIST));
+        actions.add(new ComputeThresholdAction("Compute compiled-classes", dataTableModel, 1,
+                null));
+        actions.add(new ComputeThresholdXAction("Compute(X)", dataTableModel,
+                CLASS_PRELOAD_BLACKLIST));
+        actions.add(new ShowDataAction(dataTableModel));
+        actions.add(new ImportAction(dataTableModel));
+        actions.add(new ExportAction(dataTableModel));
+
+        deviceSpecificActions = new ArrayList<DeviceSpecific>();
+        for (Action a : actions) {
+            if (a instanceof DeviceSpecific) {
+                deviceSpecificActions.add((DeviceSpecific)a);
+            }
+        }
+
+        ui = new UI(clientListModel, dataTableModel, actions);
+        ui.setVisible(true);
+    }
+
+    public static UI getUI() {
+        return top.ui;
+    }
+
+    public static ClassDataRetriever getClassDataRetriever() {
+        if (useJdwpClassDataRetriever) {
+            return new JDWPClassDataRetriever();
+        } else {
+            return new Hprof(HPROF_TIMEOUT_MILLIS);
+        }
+    }
+
+    public IDevice getDevice() {
+        return device;
+    }
+
+    public void setDevice(IDevice device) {
+        this.device = device;
+        for (DeviceSpecific ds : deviceSpecificActions) {
+            ds.setDevice(device);
+        }
+    }
+
+    public DefaultListModel<Client> getClientListModel() {
+        return clientListModel;
+    }
+
+    static class DeviceWrapper {
+        IDevice device;
+
+        public DeviceWrapper(IDevice d) {
+            device = d;
+        }
+
+        @Override
+        public String toString() {
+            return device.getName() + " (#" + device.getSerialNumber() + ")";
+        }
+    }
+
+    private void startUp() {
+        getUI().showWaitDialog();
+        initDevice();
+
+        // Load clients.
+        new ReloadListAction(clientUtils, getDevice(), clientListModel).run();
+
+        getUI().hideWaitDialog();
+    }
+
+    private void initDevice() {
+        DeviceUtils.init(DEFAULT_TIMEOUT_MILLIS);
+
+        IDevice devices[] = DeviceUtils.findDevices(DEFAULT_TIMEOUT_MILLIS);
+        if (devices == null || devices.length == 0) {
+            throw new RuntimeException("Could not find any devices...");
+        }
+
+        getUI().hideWaitDialog();
+
+        DeviceWrapper deviceWrappers[] = new DeviceWrapper[devices.length];
+        for (int i = 0; i < devices.length; i++) {
+            deviceWrappers[i] = new DeviceWrapper(devices[i]);
+        }
+
+        DeviceWrapper ret = Main.getUI().showChoiceDialog("Choose a device", "Choose device",
+                deviceWrappers);
+        if (ret != null) {
+            setDevice(ret.device);
+        } else {
+            System.exit(0);
+        }
+
+        boolean prepare = Main.getUI().showConfirmDialog("Prepare device?",
+                "Do you want to prepare the device? This is highly recommended.");
+        if (prepare) {
+            String buildType = DeviceUtils.getBuildType(device);
+            if (buildType == null || (!buildType.equals("userdebug") && !buildType.equals("eng"))) {
+                Main.getUI().showMessageDialog("Need a userdebug or eng build! (Found " + buildType
+                        + ")");
+                return;
+            }
+            if (DeviceUtils.hasPrebuiltBootImage(device)) {
+                Main.getUI().showMessageDialog("Cannot prepare a device with pre-optimized boot "
+                        + "image!");
+                return;
+            }
+
+            if (ENABLE_TRACING) {
+                DeviceUtils.enableTracing(device);
+            }
+
+            Main.getUI().showMessageDialog("The device will reboot. This will potentially take a "
+                    + "long time. Please be patient.");
+            if (!DeviceUtils.removePreloaded(device, 15 * 60) /* 15m timeout */) {
+                Main.getUI().showMessageDialog("Removing preloaded-classes failed unexpectedly!");
+            }
+        }
+    }
+
+    public static Map<String, String> findAndGetClassData(IDevice device, String packageName)
+            throws Exception {
+        Client client = clientUtils.findClient(device, packageName, -1);
+        if (client == null) {
+            throw new RuntimeException("Could not find client...");
+        }
+        System.out.println("Found client: " + client);
+
+        return getClassDataRetriever().getClassData(client);
+    }
+
+}
diff --git a/tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java b/tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java
new file mode 100644
index 0000000..fbf83d2
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload.actions;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+public abstract class AbstractThreadedAction extends AbstractAction implements Runnable {
+
+    protected AbstractThreadedAction(String title) {
+        super(title);
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        new Thread(this).start();
+    }
+
+}
diff --git a/tools/preload2/src/com/android/preload/actions/AbstractThreadedDeviceSpecificAction.java b/tools/preload2/src/com/android/preload/actions/AbstractThreadedDeviceSpecificAction.java
new file mode 100644
index 0000000..7906417
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/actions/AbstractThreadedDeviceSpecificAction.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload.actions;
+
+import com.android.ddmlib.IDevice;
+
+import java.awt.event.ActionEvent;
+
+public abstract class AbstractThreadedDeviceSpecificAction extends AbstractThreadedAction
+        implements DeviceSpecific {
+
+    protected IDevice device;
+
+    protected AbstractThreadedDeviceSpecificAction(String title, IDevice device) {
+        super(title);
+        this.device = device;
+    }
+
+    @Override
+    public void setDevice(IDevice device) {
+        this.device = device;
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        if (device == null) {
+            return;
+        }
+        super.actionPerformed(e);
+    }
+}
diff --git a/tools/preload2/src/com/android/preload/actions/ClearTableAction.java b/tools/preload2/src/com/android/preload/actions/ClearTableAction.java
new file mode 100644
index 0000000..c0e4795
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/actions/ClearTableAction.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload.actions;
+
+import com.android.preload.DumpTableModel;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+public class ClearTableAction extends AbstractAction {
+    private final DumpTableModel dataTableModel;
+
+    public ClearTableAction(DumpTableModel dataTableModel) {
+        super("Clear");
+        this.dataTableModel = dataTableModel;
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        dataTableModel.clear();
+    }
+}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java b/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java
new file mode 100644
index 0000000..b524716
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload.actions;
+
+import com.android.preload.DumpData;
+import com.android.preload.DumpTableModel;
+import com.android.preload.Main;
+
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.regex.Pattern;
+
+import javax.swing.AbstractAction;
+import javax.swing.JFileChooser;
+
+/**
+ * Compute an intersection of classes from the given data. A class is in the intersection if it
+ * appears in at least the number of threshold given packages. An optional blacklist can be
+ * used to filter classes from the intersection.
+ */
+public class ComputeThresholdAction extends AbstractAction implements Runnable {
+    protected int threshold;
+    private Pattern blacklist;
+    private DumpTableModel dataTableModel;
+
+    /**
+     * Create an action with the given parameters. The blacklist is a regular expression
+     * that filters classes.
+     */
+    public ComputeThresholdAction(String name, DumpTableModel dataTableModel, int threshold,
+            String blacklist) {
+        super(name);
+        this.dataTableModel = dataTableModel;
+        this.threshold = threshold;
+        if (blacklist != null) {
+            this.blacklist = Pattern.compile(blacklist);
+        }
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        List<DumpData> data = dataTableModel.getData();
+        if (data.size() == 0) {
+            Main.getUI().showMessageDialog("No data available, please scan packages or run "
+                    + "monkeys.");
+            return;
+        }
+        if (data.size() == 1) {
+            Main.getUI().showMessageDialog("Cannot compute list from only one data set, please "
+                    + "scan packages or run monkeys.");
+            return;
+        }
+
+        new Thread(this).start();
+    }
+
+    @Override
+    public void run() {
+        Main.getUI().showWaitDialog();
+
+        Map<String, Set<String>> uses = new HashMap<String, Set<String>>();
+        for (DumpData d : dataTableModel.getData()) {
+            Main.getUI().updateWaitDialog("Merging " + d.getPackageName());
+            updateClassUse(d.getPackageName(), uses, getBootClassPathClasses(d.getDumpData()));
+        }
+
+        Main.getUI().updateWaitDialog("Computing thresholded set");
+        Set<String> result = fromThreshold(uses, blacklist, threshold);
+        Main.getUI().hideWaitDialog();
+
+        boolean ret = Main.getUI().showConfirmDialog("Computed a set with " + result.size()
+                + " classes, would you like to save to disk?", "Save?");
+        if (ret) {
+            JFileChooser jfc = new JFileChooser();
+            int ret2 = jfc.showSaveDialog(Main.getUI());
+            if (ret2 == JFileChooser.APPROVE_OPTION) {
+                File f = jfc.getSelectedFile();
+                saveSet(result, f);
+            }
+        }
+    }
+
+    private Set<String> fromThreshold(Map<String, Set<String>> classUses, Pattern blacklist,
+            int threshold) {
+        TreeSet<String> ret = new TreeSet<>(); // TreeSet so it's nicely ordered by name.
+
+        for (Map.Entry<String, Set<String>> e : classUses.entrySet()) {
+            if (e.getValue().size() >= threshold) {
+                if (blacklist == null || !blacklist.matcher(e.getKey()).matches()) {
+                    ret.add(e.getKey());
+                }
+            }
+        }
+
+        return ret;
+    }
+
+    private static void updateClassUse(String pkg, Map<String, Set<String>> classUses,
+            Set<String> classes) {
+        for (String className : classes) {
+            Set<String> old = classUses.get(className);
+            if (old == null) {
+                classUses.put(className, new HashSet<String>());
+            }
+            classUses.get(className).add(pkg);
+        }
+    }
+
+    private static Set<String> getBootClassPathClasses(Map<String, String> source) {
+        Set<String> ret = new HashSet<>();
+        for (Map.Entry<String, String> e : source.entrySet()) {
+            if (e.getValue() == null) {
+                ret.add(e.getKey());
+            }
+        }
+        return ret;
+    }
+
+    private static void saveSet(Set<String> result, File f) {
+        try {
+            PrintWriter out = new PrintWriter(f);
+            for (String s : result) {
+                out.println(s);
+            }
+            out.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ComputeThresholdXAction.java b/tools/preload2/src/com/android/preload/actions/ComputeThresholdXAction.java
new file mode 100644
index 0000000..3ec0a4c
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/actions/ComputeThresholdXAction.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload.actions;
+
+import com.android.preload.DumpTableModel;
+import com.android.preload.Main;
+
+public class ComputeThresholdXAction extends ComputeThresholdAction {
+
+    public ComputeThresholdXAction(String name, DumpTableModel dataTableModel,
+            String blacklist) {
+        super(name, dataTableModel, 1, blacklist);
+    }
+
+    @Override
+    public void run() {
+        String value = Main.getUI().showInputDialog("Threshold?");
+
+        if (value != null) {
+            try {
+                threshold = Integer.parseInt(value);
+                super.run();
+            } catch (Exception exc) {
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/DeviceSpecific.java b/tools/preload2/src/com/android/preload/actions/DeviceSpecific.java
new file mode 100644
index 0000000..35a8f26
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/actions/DeviceSpecific.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload.actions;
+
+import com.android.ddmlib.IDevice;
+
+/**
+ * Marks an action as being device-specific. The user must set the device through the specified
+ * method if the device selection changes.
+ *
+ * Implementors must tolerate a null device (for example, with a no-op). This includes calling
+ * any methods before setDevice has been called.
+ */
+public interface DeviceSpecific {
+
+    /**
+     * Set the device that should be used. Note that there is no restriction on calling other
+     * methods of the implementor before a setDevice call. Neither is device guaranteed to be
+     * non-null.
+     *
+     * @param device The device to use going forward.
+     */
+    public void setDevice(IDevice device);
+}
diff --git a/tools/preload2/src/com/android/preload/actions/ExportAction.java b/tools/preload2/src/com/android/preload/actions/ExportAction.java
new file mode 100644
index 0000000..cb8b3df
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/actions/ExportAction.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload.actions;
+
+import com.android.preload.DumpDataIO;
+import com.android.preload.DumpTableModel;
+import com.android.preload.Main;
+
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.io.PrintWriter;
+
+import javax.swing.AbstractAction;
+
+public class ExportAction extends AbstractAction implements Runnable {
+    private File lastSaveFile;
+    private DumpTableModel dataTableModel;
+
+    public ExportAction(DumpTableModel dataTableModel) {
+        super("Export data");
+        this.dataTableModel = dataTableModel;
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        lastSaveFile = Main.getUI().showSaveDialog();
+        if (lastSaveFile != null) {
+            new Thread(this).start();
+        }
+    }
+
+    @Override
+    public void run() {
+        Main.getUI().showWaitDialog();
+
+        String serialized = DumpDataIO.serialize(dataTableModel.getData());
+
+        if (serialized != null) {
+            try {
+                PrintWriter out = new PrintWriter(lastSaveFile);
+                out.println(serialized);
+                out.close();
+
+                Main.getUI().hideWaitDialog();
+            } catch (Exception e) {
+                Main.getUI().hideWaitDialog();
+                Main.getUI().showMessageDialog("Failed writing: " + e.getMessage());
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ImportAction.java b/tools/preload2/src/com/android/preload/actions/ImportAction.java
new file mode 100644
index 0000000..5c19765
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/actions/ImportAction.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload.actions;
+
+import com.android.preload.DumpData;
+import com.android.preload.DumpDataIO;
+import com.android.preload.DumpTableModel;
+import com.android.preload.Main;
+
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.util.Collection;
+
+import javax.swing.AbstractAction;
+
+public class ImportAction extends AbstractAction implements Runnable {
+    private File[] lastOpenFiles;
+    private DumpTableModel dataTableModel;
+
+    public ImportAction(DumpTableModel dataTableModel) {
+        super("Import data");
+        this.dataTableModel = dataTableModel;
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        lastOpenFiles = Main.getUI().showOpenDialog(true);
+        if (lastOpenFiles != null) {
+            new Thread(this).start();
+        }
+    }
+
+    @Override
+    public void run() {
+        Main.getUI().showWaitDialog();
+
+        try {
+            for (File f : lastOpenFiles) {
+                try {
+                    Collection<DumpData> data = DumpDataIO.deserialize(f);
+
+                    for (DumpData d : data) {
+                        dataTableModel.addData(d);
+                    }
+                } catch (Exception e) {
+                    Main.getUI().showMessageDialog("Failed reading: " + e.getMessage());
+                }
+            }
+        } finally {
+            Main.getUI().hideWaitDialog();
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ReloadListAction.java b/tools/preload2/src/com/android/preload/actions/ReloadListAction.java
new file mode 100644
index 0000000..29f0557
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/actions/ReloadListAction.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload.actions;
+
+import com.android.ddmlib.Client;
+import com.android.ddmlib.IDevice;
+import com.android.preload.ClientUtils;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+import javax.swing.DefaultListModel;
+
+public class ReloadListAction extends AbstractThreadedDeviceSpecificAction {
+
+    private ClientUtils clientUtils;
+    private final DefaultListModel<Client> clientListModel;
+
+    public ReloadListAction(ClientUtils utils, IDevice device,
+            DefaultListModel<Client> clientListModel) {
+        super("Reload", device);
+        this.clientUtils = utils;
+        this.clientListModel = clientListModel;
+    }
+
+    @Override
+    public void run() {
+        Client[] clients = clientUtils.findAllClients(device);
+        if (clients != null) {
+            Arrays.sort(clients, new ClientComparator());
+        }
+        clientListModel.removeAllElements();
+        for (Client c : clients) {
+            clientListModel.addElement(c);
+        }
+    }
+
+    private static class ClientComparator implements Comparator<Client> {
+
+        @Override
+        public int compare(Client o1, Client o2) {
+            String s1 = o1.getClientData().getClientDescription();
+            String s2 = o2.getClientData().getClientDescription();
+
+            if (s1 == null || s2 == null) {
+                // Not good, didn't get all data?
+                return (s1 == null) ? -1 : 1;
+            }
+
+            return s1.compareTo(s2);
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java b/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java
new file mode 100644
index 0000000..385e857
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload.actions;
+
+import com.android.ddmlib.IDevice;
+import com.android.preload.DeviceUtils;
+import com.android.preload.DumpData;
+import com.android.preload.DumpTableModel;
+import com.android.preload.Main;
+
+import java.awt.event.ActionEvent;
+import java.util.Date;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import javax.swing.AbstractAction;
+
+public class RunMonkeyAction extends AbstractAction implements DeviceSpecific {
+
+    private final static String DEFAULT_MONKEY_PACKAGES =
+            "com.android.calendar,com.android.gallery3d";
+
+    private IDevice device;
+    private DumpTableModel dataTableModel;
+
+    public RunMonkeyAction(IDevice device, DumpTableModel dataTableModel) {
+        super("Run monkey");
+        this.device = device;
+        this.dataTableModel = dataTableModel;
+    }
+
+    @Override
+    public void setDevice(IDevice device) {
+        this.device = device;
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        String packages = Main.getUI().showInputDialog("Please enter packages name to run with"
+                + " the monkey, or leave empty for default.");
+        if (packages == null) {
+            return;
+        }
+        if (packages.isEmpty()) {
+            packages = DEFAULT_MONKEY_PACKAGES;
+        }
+        new Thread(new RunMonkeyRunnable(packages)).start();
+    }
+
+    private class RunMonkeyRunnable implements Runnable {
+
+        private String packages;
+        private final static int ITERATIONS = 1000;
+
+        public RunMonkeyRunnable(String packages) {
+            this.packages = packages;
+        }
+
+        @Override
+        public void run() {
+            Main.getUI().showWaitDialog();
+
+            try {
+                String pkgs[] = packages.split(",");
+
+                for (String pkg : pkgs) {
+                    Main.getUI().updateWaitDialog("Running monkey on " + pkg);
+
+                    try {
+                        // Stop running app.
+                        forceStop(pkg);
+
+                        // Little bit of breather here.
+                        try {
+                            Thread.sleep(1000);
+                        } catch (Exception e) {
+                        }
+
+                        DeviceUtils.doShell(device, "monkey -p " + pkg + " " + ITERATIONS, 1,
+                                TimeUnit.MINUTES);
+
+                        Main.getUI().updateWaitDialog("Retrieving heap data for " + pkg);
+                        Map<String, String> data = Main.findAndGetClassData(device, pkg);
+                        DumpData dumpData = new DumpData(pkg, data, new Date());
+                        dataTableModel.addData(dumpData);
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    } finally {
+                        // Stop running app.
+                        forceStop(pkg);
+                    }
+                }
+            } finally {
+                Main.getUI().hideWaitDialog();
+            }
+        }
+
+        private void forceStop(String packageName) {
+            // Stop running app.
+            DeviceUtils.doShell(device, "force-stop " + packageName, 5, TimeUnit.SECONDS);
+            DeviceUtils.doShell(device, "kill " + packageName, 5, TimeUnit.SECONDS);
+            DeviceUtils.doShell(device, "kill `pid " + packageName + "`", 5, TimeUnit.SECONDS);
+        }
+    }
+}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ScanAllPackagesAction.java b/tools/preload2/src/com/android/preload/actions/ScanAllPackagesAction.java
new file mode 100644
index 0000000..d74b8a3
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/actions/ScanAllPackagesAction.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload.actions;
+
+import com.android.ddmlib.Client;
+import com.android.ddmlib.IDevice;
+import com.android.preload.ClientUtils;
+import com.android.preload.DumpData;
+import com.android.preload.DumpTableModel;
+import com.android.preload.Main;
+
+import java.util.Date;
+import java.util.Map;
+
+public class ScanAllPackagesAction extends AbstractThreadedDeviceSpecificAction {
+
+    private ClientUtils clientUtils;
+    private DumpTableModel dataTableModel;
+
+    public ScanAllPackagesAction(ClientUtils utils, IDevice device, DumpTableModel dataTableModel) {
+        super("Scan all packages", device);
+        this.clientUtils = utils;
+        this.dataTableModel = dataTableModel;
+    }
+
+    @Override
+    public void run() {
+        Main.getUI().showWaitDialog();
+
+        try {
+            Client[] clients = clientUtils.findAllClients(device);
+            for (Client c : clients) {
+                String pkg = c.getClientData().getClientDescription();
+                Main.getUI().showWaitDialog();
+                Main.getUI().updateWaitDialog("Retrieving heap data for " + pkg);
+
+                try {
+                    Map<String, String> data = Main.getClassDataRetriever().getClassData(c);
+                    DumpData dumpData = new DumpData(pkg, data, new Date());
+                    dataTableModel.addData(dumpData);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        } finally {
+            Main.getUI().hideWaitDialog();
+        }
+    }
+}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ScanPackageAction.java b/tools/preload2/src/com/android/preload/actions/ScanPackageAction.java
new file mode 100644
index 0000000..98492bd
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/actions/ScanPackageAction.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload.actions;
+
+import com.android.ddmlib.Client;
+import com.android.ddmlib.IDevice;
+import com.android.preload.ClientUtils;
+import com.android.preload.DumpData;
+import com.android.preload.DumpTableModel;
+import com.android.preload.Main;
+
+import java.util.Date;
+import java.util.Map;
+
+public class ScanPackageAction extends AbstractThreadedDeviceSpecificAction {
+
+    private ClientUtils clientUtils;
+    private DumpTableModel dataTableModel;
+
+    public ScanPackageAction(ClientUtils utils, IDevice device, DumpTableModel dataTableModel) {
+        super("Scan package", device);
+        this.clientUtils = utils;
+        this.dataTableModel = dataTableModel;
+    }
+
+    @Override
+    public void run() {
+        Main.getUI().showWaitDialog();
+
+        try {
+            Client client = Main.getUI().getSelectedClient();
+            if (client != null) {
+                work(client);
+            } else {
+                Client[] clients = clientUtils.findAllClients(device);
+                if (clients.length > 0) {
+                    ClientWrapper[] clientWrappers = new ClientWrapper[clients.length];
+                    for (int i = 0; i < clientWrappers.length; i++) {
+                        clientWrappers[i] = new ClientWrapper(clients[i]);
+                    }
+                    Main.getUI().hideWaitDialog();
+
+                    ClientWrapper ret = Main.getUI().showChoiceDialog("Choose a package to scan",
+                            "Choose package",
+                            clientWrappers);
+                    if (ret != null) {
+                        work(ret.client);
+                    }
+                }
+            }
+        } finally {
+            Main.getUI().hideWaitDialog();
+        }
+    }
+
+    private void work(Client c) {
+        String pkg = c.getClientData().getClientDescription();
+        Main.getUI().showWaitDialog();
+        Main.getUI().updateWaitDialog("Retrieving heap data for " + pkg);
+
+        try {
+            Map<String, String> data = Main.findAndGetClassData(device, pkg);
+            DumpData dumpData = new DumpData(pkg, data, new Date());
+            dataTableModel.addData(dumpData);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    private static class ClientWrapper {
+        private Client client;
+
+        public ClientWrapper(Client c) {
+            client = c;
+        }
+
+        @Override
+        public String toString() {
+            return client.getClientData().getClientDescription() + " (pid "
+                    + client.getClientData().getPid() + ")";
+        }
+    }
+}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/actions/ShowDataAction.java b/tools/preload2/src/com/android/preload/actions/ShowDataAction.java
new file mode 100644
index 0000000..2bb175f
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/actions/ShowDataAction.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload.actions;
+
+import com.android.preload.DumpData;
+import com.android.preload.DumpTableModel;
+import com.android.preload.Main;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionEvent;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.swing.AbstractAction;
+import javax.swing.JFrame;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+
+public class ShowDataAction extends AbstractAction {
+    private DumpTableModel dataTableModel;
+
+    public ShowDataAction(DumpTableModel dataTableModel) {
+        super("Show data");
+        this.dataTableModel = dataTableModel;
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        // TODO(agampe): Auto-generated method stub
+        int selRow = Main.getUI().getSelectedDataTableRow();
+        if (selRow != -1) {
+            DumpData data = dataTableModel.getData().get(selRow);
+            Map<String, Set<String>> inv = data.invertData();
+
+            StringBuilder builder = new StringBuilder();
+
+            // First bootclasspath.
+            add(builder, "Boot classpath:", inv.get(null));
+
+            // Now everything else.
+            for (String k : inv.keySet()) {
+                if (k != null) {
+                    builder.append("==================\n\n");
+                    add(builder, k, inv.get(k));
+                }
+            }
+
+            JFrame newFrame = new JFrame(data.getPackageName() + " " + data.getDate());
+            newFrame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
+            newFrame.getContentPane().add(new JScrollPane(new JTextArea(builder.toString())),
+                    BorderLayout.CENTER);
+            newFrame.setSize(800, 600);
+            newFrame.setLocationRelativeTo(null);
+            newFrame.setVisible(true);
+        }
+    }
+
+    private void add(StringBuilder builder, String head, Set<String> set) {
+        builder.append(head);
+        builder.append('\n');
+        addSet(builder, set);
+        builder.append('\n');
+    }
+
+    private void addSet(StringBuilder builder, Set<String> set) {
+        if (set == null) {
+            builder.append("  NONE\n");
+            return;
+        }
+        List<String> sorted = new ArrayList<>(set);
+        Collections.sort(sorted);
+        for (String s : sorted) {
+            builder.append(s);
+            builder.append('\n');
+        }
+    }
+}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/ClassDataRetriever.java b/tools/preload2/src/com/android/preload/classdataretrieval/ClassDataRetriever.java
new file mode 100644
index 0000000..f04360f
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/classdataretrieval/ClassDataRetriever.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload.classdataretrieval;
+
+import com.android.ddmlib.Client;
+
+import java.util.Map;
+
+/**
+ * Retrieve a class-to-classloader map for loaded classes from the client.
+ */
+public interface ClassDataRetriever {
+
+    public Map<String, String> getClassData(Client client);
+}
diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/hprof/GeneralHprofDumpHandler.java b/tools/preload2/src/com/android/preload/classdataretrieval/hprof/GeneralHprofDumpHandler.java
new file mode 100644
index 0000000..8d797ee
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/classdataretrieval/hprof/GeneralHprofDumpHandler.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload.classdataretrieval.hprof;
+
+import com.android.ddmlib.Client;
+import com.android.ddmlib.ClientData.IHprofDumpHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class GeneralHprofDumpHandler implements IHprofDumpHandler {
+
+    private List<IHprofDumpHandler> handlers = new ArrayList<>();
+
+    public void addHandler(IHprofDumpHandler h) {
+      synchronized (handlers) {
+        handlers.add(h);
+      }
+    }
+
+    public void removeHandler(IHprofDumpHandler h) {
+      synchronized (handlers) {
+        handlers.remove(h);
+      }
+    }
+
+    private List<IHprofDumpHandler> getIterationList() {
+      synchronized (handlers) {
+        return new ArrayList<>(handlers);
+      }
+    }
+
+    @Override
+    public void onEndFailure(Client arg0, String arg1) {
+      List<IHprofDumpHandler> iterList = getIterationList();
+      for (IHprofDumpHandler h : iterList) {
+        h.onEndFailure(arg0, arg1);
+      }
+    }
+
+    @Override
+    public void onSuccess(String arg0, Client arg1) {
+      List<IHprofDumpHandler> iterList = getIterationList();
+      for (IHprofDumpHandler h : iterList) {
+        h.onSuccess(arg0, arg1);
+      }
+    }
+
+    @Override
+    public void onSuccess(byte[] arg0, Client arg1) {
+      List<IHprofDumpHandler> iterList = getIterationList();
+      for (IHprofDumpHandler h : iterList) {
+        h.onSuccess(arg0, arg1);
+      }
+    }
+  }
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/hprof/Hprof.java b/tools/preload2/src/com/android/preload/classdataretrieval/hprof/Hprof.java
new file mode 100644
index 0000000..21b7a04
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/classdataretrieval/hprof/Hprof.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload.classdataretrieval.hprof;
+
+import com.android.ddmlib.Client;
+import com.android.ddmlib.ClientData;
+import com.android.ddmlib.ClientData.IHprofDumpHandler;
+import com.android.preload.classdataretrieval.ClassDataRetriever;
+import com.android.preload.ui.NullProgressMonitor;
+import com.android.tools.perflib.captures.MemoryMappedFileBuffer;
+import com.android.tools.perflib.heap.ClassObj;
+import com.android.tools.perflib.heap.Queries;
+import com.android.tools.perflib.heap.Snapshot;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class Hprof implements ClassDataRetriever {
+
+    private static GeneralHprofDumpHandler hprofHandler;
+
+    public static void init() {
+        synchronized(Hprof.class) {
+            if (hprofHandler == null) {
+                ClientData.setHprofDumpHandler(hprofHandler = new GeneralHprofDumpHandler());
+            }
+        }
+    }
+
+    public static File doHprof(Client client, int timeout) {
+        GetHprof gh = new GetHprof(client, timeout);
+        return gh.get();
+    }
+
+    /**
+     * Return a map of class names to class-loader names derived from the hprof dump.
+     *
+     * @param hprofLocalFile
+     */
+    public static Map<String, String> analyzeHprof(File hprofLocalFile) throws Exception {
+        Snapshot snapshot = Snapshot.createSnapshot(new MemoryMappedFileBuffer(hprofLocalFile));
+
+        Map<String, Set<ClassObj>> classes = Queries.classes(snapshot, null);
+        Map<String, String> retValue = new HashMap<String, String>();
+        for (Map.Entry<String, Set<ClassObj>> e : classes.entrySet()) {
+            for (ClassObj c : e.getValue()) {
+                String cl = c.getClassLoader() == null ? null : c.getClassLoader().toString();
+                String cName = c.getClassName();
+                int aDepth = 0;
+                while (cName.endsWith("[]")) {
+                    cName = cName.substring(0, cName.length()-2);
+                    aDepth++;
+                }
+                String newName = transformPrimitiveClass(cName);
+                if (aDepth > 0) {
+                    // Need to use kind-a descriptor syntax. If it was transformed, it is primitive.
+                    if (newName.equals(cName)) {
+                        newName = "L" + newName + ";";
+                    }
+                    for (int i = 0; i < aDepth; i++) {
+                        newName = "[" + newName;
+                    }
+                }
+                retValue.put(newName, cl);
+            }
+        }
+
+        // Free up memory.
+        snapshot.dispose();
+
+        return retValue;
+    }
+
+    private static Map<String, String> primitiveMapping;
+
+    static {
+        primitiveMapping = new HashMap<>();
+        primitiveMapping.put("boolean", "Z");
+        primitiveMapping.put("byte", "B");
+        primitiveMapping.put("char", "C");
+        primitiveMapping.put("double", "D");
+        primitiveMapping.put("float", "F");
+        primitiveMapping.put("int", "I");
+        primitiveMapping.put("long", "J");
+        primitiveMapping.put("short", "S");
+        primitiveMapping.put("void", "V");
+    }
+
+    private static String transformPrimitiveClass(String name) {
+        String rep = primitiveMapping.get(name);
+        if (rep != null) {
+            return rep;
+        }
+        return name;
+    }
+
+    private static class GetHprof implements IHprofDumpHandler {
+
+        private File target;
+        private long timeout;
+        private Client client;
+
+        public GetHprof(Client client, long timeout) {
+            this.client = client;
+            this.timeout = timeout;
+        }
+
+        public File get() {
+            synchronized (this) {
+                hprofHandler.addHandler(this);
+                client.dumpHprof();
+                if (target == null) {
+                    try {
+                        wait(timeout);
+                    } catch (Exception e) {
+                        System.out.println(e);
+                    }
+                }
+            }
+
+            hprofHandler.removeHandler(this);
+            return target;
+        }
+
+        private void wakeUp() {
+            synchronized (this) {
+                notifyAll();
+            }
+        }
+
+        @Override
+        public void onEndFailure(Client arg0, String arg1) {
+            System.out.println("GetHprof.onEndFailure");
+            if (client == arg0) {
+                wakeUp();
+            }
+        }
+
+        private static File createTargetFile() {
+            try {
+                return File.createTempFile("ddms", ".hprof");
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        @Override
+        public void onSuccess(String arg0, Client arg1) {
+            System.out.println("GetHprof.onSuccess");
+            if (client == arg1) {
+                try {
+                    target = createTargetFile();
+                    arg1.getDevice().getSyncService().pullFile(arg0,
+                            target.getAbsoluteFile().toString(), new NullProgressMonitor());
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    target = null;
+                }
+                wakeUp();
+            }
+        }
+
+        @Override
+        public void onSuccess(byte[] arg0, Client arg1) {
+            System.out.println("GetHprof.onSuccess");
+            if (client == arg1) {
+                try {
+                    target = createTargetFile();
+                    BufferedOutputStream out =
+                            new BufferedOutputStream(new FileOutputStream(target));
+                    out.write(arg0);
+                    out.close();
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    target = null;
+                }
+                wakeUp();
+            }
+        }
+    }
+
+    private int timeout;
+
+    public Hprof(int timeout) {
+        this.timeout = timeout;
+    }
+
+    @Override
+    public Map<String, String> getClassData(Client client) {
+        File hprofLocalFile = Hprof.doHprof(client, timeout);
+        if (hprofLocalFile == null) {
+            throw new RuntimeException("Failed getting dump...");
+        }
+        System.out.println("Dump file is " + hprofLocalFile);
+
+        try {
+            return analyzeHprof(hprofLocalFile);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/JDWPClassDataRetriever.java b/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/JDWPClassDataRetriever.java
new file mode 100644
index 0000000..dbd4c89
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/JDWPClassDataRetriever.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload.classdataretrieval.jdwp;
+
+import com.android.ddmlib.Client;
+import com.android.preload.classdataretrieval.ClassDataRetriever;
+
+import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket;
+import org.apache.harmony.jpda.tests.framework.jdwp.JDWPCommands;
+import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
+import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
+import org.apache.harmony.jpda.tests.jdwp.share.JDWPTestCase;
+import org.apache.harmony.jpda.tests.jdwp.share.JDWPUnitDebuggeeWrapper;
+import org.apache.harmony.jpda.tests.share.JPDALogWriter;
+import org.apache.harmony.jpda.tests.share.JPDATestOptions;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class JDWPClassDataRetriever extends JDWPTestCase implements ClassDataRetriever {
+
+    private final Client client;
+
+    public JDWPClassDataRetriever() {
+        this(null);
+    }
+
+    public JDWPClassDataRetriever(Client client) {
+        this.client = client;
+    }
+
+
+    @Override
+    protected String getDebuggeeClassName() {
+        return "<unset>";
+    }
+
+    @Override
+    public Map<String, String> getClassData(Client client) {
+        return new JDWPClassDataRetriever(client).retrieve();
+    }
+
+    private Map<String, String> retrieve() {
+        if (client == null) {
+            throw new IllegalStateException();
+        }
+
+        settings = createTestOptions("localhost:" + String.valueOf(client.getDebuggerListenPort()));
+        settings.setDebuggeeSuspend("n");
+
+        logWriter = new JPDALogWriter(System.out, "", false);
+
+        try {
+            internalSetUp();
+
+            return retrieveImpl();
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        } finally {
+            internalTearDown();
+        }
+    }
+
+    private Map<String, String> retrieveImpl() {
+        try {
+            // Suspend the app.
+            {
+                CommandPacket packet = new CommandPacket(
+                        JDWPCommands.VirtualMachineCommandSet.CommandSetID,
+                        JDWPCommands.VirtualMachineCommandSet.SuspendCommand);
+                ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
+                if (reply.getErrorCode() != JDWPConstants.Error.NONE) {
+                    return null;
+                }
+            }
+
+            // List all classes.
+            CommandPacket packet = new CommandPacket(
+                    JDWPCommands.VirtualMachineCommandSet.CommandSetID,
+                    JDWPCommands.VirtualMachineCommandSet.AllClassesCommand);
+            ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
+
+            if (reply.getErrorCode() != JDWPConstants.Error.NONE) {
+                return null;
+            }
+
+            int classCount = reply.getNextValueAsInt();
+            System.out.println("Runtime reported " + classCount + " classes.");
+
+            Map<Long, String> classes = new HashMap<Long, String>();
+            Map<Long, String> arrayClasses = new HashMap<Long, String>();
+
+            for (int i = 0; i < classCount; i++) {
+                byte refTypeTag = reply.getNextValueAsByte();
+                long typeID = reply.getNextValueAsReferenceTypeID();
+                String signature = reply.getNextValueAsString();
+                /* int status = */ reply.getNextValueAsInt();
+
+                switch (refTypeTag) {
+                    case JDWPConstants.TypeTag.CLASS:
+                    case JDWPConstants.TypeTag.INTERFACE:
+                        classes.put(typeID, signature);
+                        break;
+
+                    case JDWPConstants.TypeTag.ARRAY:
+                        arrayClasses.put(typeID, signature);
+                        break;
+                }
+            }
+
+            Map<String, String> result = new HashMap<String, String>();
+
+            // Parse all classes.
+            for (Map.Entry<Long, String> entry : classes.entrySet()) {
+                long typeID = entry.getKey();
+                String signature = entry.getValue();
+
+                if (!checkClass(typeID, signature, result)) {
+                    System.err.println("Issue investigating " + signature);
+                }
+            }
+
+            // For arrays, look at the leaf component type.
+            for (Map.Entry<Long, String> entry : arrayClasses.entrySet()) {
+                long typeID = entry.getKey();
+                String signature = entry.getValue();
+
+                if (!checkArrayClass(typeID, signature, result)) {
+                    System.err.println("Issue investigating " + signature);
+                }
+            }
+
+            return result;
+        } finally {
+            // Resume the app.
+            {
+                CommandPacket packet = new CommandPacket(
+                        JDWPCommands.VirtualMachineCommandSet.CommandSetID,
+                        JDWPCommands.VirtualMachineCommandSet.ResumeCommand);
+                /* ReplyPacket reply = */ debuggeeWrapper.vmMirror.performCommand(packet);
+            }
+        }
+    }
+
+    private boolean checkClass(long typeID, String signature, Map<String, String> result) {
+        CommandPacket packet = new CommandPacket(
+                JDWPCommands.ReferenceTypeCommandSet.CommandSetID,
+                JDWPCommands.ReferenceTypeCommandSet.ClassLoaderCommand);
+        packet.setNextValueAsReferenceTypeID(typeID);
+        ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
+        if (reply.getErrorCode() != JDWPConstants.Error.NONE) {
+            return false;
+        }
+
+        long classLoaderID = reply.getNextValueAsObjectID();
+
+        // TODO: Investigate the classloader to have a better string?
+        String classLoaderString = (classLoaderID == 0) ? null : String.valueOf(classLoaderID);
+
+        result.put(getClassName(signature), classLoaderString);
+
+        return true;
+    }
+
+    private boolean checkArrayClass(long typeID, String signature, Map<String, String> result) {
+        // Classloaders of array classes are the same as the component class'.
+        CommandPacket packet = new CommandPacket(
+                JDWPCommands.ReferenceTypeCommandSet.CommandSetID,
+                JDWPCommands.ReferenceTypeCommandSet.ClassLoaderCommand);
+        packet.setNextValueAsReferenceTypeID(typeID);
+        ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet);
+        if (reply.getErrorCode() != JDWPConstants.Error.NONE) {
+            return false;
+        }
+
+        long classLoaderID = reply.getNextValueAsObjectID();
+
+        // TODO: Investigate the classloader to have a better string?
+        String classLoaderString = (classLoaderID == 0) ? null : String.valueOf(classLoaderID);
+
+        // For array classes, we *need* the signature directly.
+        result.put(signature, classLoaderString);
+
+        return true;
+    }
+
+    private static String getClassName(String signature) {
+        String withoutLAndSemicolon = signature.substring(1, signature.length() - 1);
+        return withoutLAndSemicolon.replace('/', '.');
+    }
+
+
+    private static JPDATestOptions createTestOptions(String address) {
+        JPDATestOptions options = new JPDATestOptions();
+        options.setAttachConnectorKind();
+        options.setTimeout(1000);
+        options.setWaitingTime(1000);
+        options.setTransportAddress(address);
+        return options;
+    }
+
+    @Override
+    protected JDWPUnitDebuggeeWrapper createDebuggeeWrapper() {
+        return new PreloadDebugeeWrapper(settings, logWriter);
+    }
+}
diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/PreloadDebugeeWrapper.java b/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/PreloadDebugeeWrapper.java
new file mode 100644
index 0000000..b9df6d0
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/PreloadDebugeeWrapper.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload.classdataretrieval.jdwp;
+
+import org.apache.harmony.jpda.tests.framework.LogWriter;
+import org.apache.harmony.jpda.tests.jdwp.share.JDWPManualDebuggeeWrapper;
+import org.apache.harmony.jpda.tests.share.JPDATestOptions;
+
+import java.io.IOException;
+
+public class PreloadDebugeeWrapper extends JDWPManualDebuggeeWrapper {
+
+    public PreloadDebugeeWrapper(JPDATestOptions options, LogWriter writer) {
+        super(options, writer);
+    }
+
+    @Override
+    protected Process launchProcess(String cmdLine) throws IOException {
+        return null;
+    }
+
+    @Override
+    protected void WaitForProcessExit(Process process) {
+    }
+
+}
diff --git a/tools/preload2/src/com/android/preload/ui/NullProgressMonitor.java b/tools/preload2/src/com/android/preload/ui/NullProgressMonitor.java
new file mode 100644
index 0000000..f45aad0
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/ui/NullProgressMonitor.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload.ui;
+
+import com.android.ddmlib.SyncService.ISyncProgressMonitor;
+
+public class NullProgressMonitor implements ISyncProgressMonitor {
+
+    @Override
+    public void advance(int arg0) {}
+
+    @Override
+    public boolean isCanceled() {
+        return false;
+    }
+
+    @Override
+    public void start(int arg0) {}
+
+    @Override
+    public void startSubTask(String arg0) {}
+
+    @Override
+    public void stop() {}
+}
\ No newline at end of file
diff --git a/tools/preload2/src/com/android/preload/ui/UI.java b/tools/preload2/src/com/android/preload/ui/UI.java
new file mode 100644
index 0000000..47174dd
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/ui/UI.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload.ui;
+
+import com.android.ddmlib.Client;
+import com.android.ddmlib.ClientData;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.io.File;
+import java.util.List;
+
+import javax.swing.Action;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JProgressBar;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.JToolBar;
+import javax.swing.ListModel;
+import javax.swing.SwingUtilities;
+import javax.swing.table.TableModel;
+
+public class UI extends JFrame {
+
+    private JList<Client> clientList;
+    private JTable dataTable;
+
+    // Shared file chooser, means the directory is retained.
+    private JFileChooser jfc;
+
+    public UI(ListModel<Client> clientListModel,
+              TableModel dataTableModel,
+              List<Action> actions) {
+        super("Preloaded-classes computation");
+
+        getContentPane().add(new JScrollPane(clientList = new JList<Client>(clientListModel)),
+                BorderLayout.WEST);
+        clientList.setCellRenderer(new ClientListCellRenderer());
+        // clientList.addListSelectionListener(listener);
+
+        dataTable = new JTable(dataTableModel);
+        getContentPane().add(new JScrollPane(dataTable), BorderLayout.CENTER);
+
+        JToolBar toolbar = new JToolBar(JToolBar.HORIZONTAL);
+        for (Action a : actions) {
+            if (a == null) {
+                toolbar.addSeparator();
+            } else {
+                toolbar.add(a);
+            }
+        }
+        getContentPane().add(toolbar, BorderLayout.PAGE_START);
+
+        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        setBounds(100, 100, 800, 600);
+    }
+
+    public Client getSelectedClient() {
+        return clientList.getSelectedValue();
+    }
+
+    public int getSelectedDataTableRow() {
+        return dataTable.getSelectedRow();
+    }
+
+    private JDialog currentWaitDialog = null;
+
+    public void showWaitDialog() {
+        if (currentWaitDialog == null) {
+            currentWaitDialog = new JDialog(this, "Please wait...", true);
+            currentWaitDialog.getContentPane().add(new JLabel("Please be patient."),
+                    BorderLayout.CENTER);
+            JProgressBar progress = new JProgressBar(JProgressBar.HORIZONTAL);
+            progress.setIndeterminate(true);
+            currentWaitDialog.getContentPane().add(progress, BorderLayout.SOUTH);
+            currentWaitDialog.setSize(200, 100);
+            currentWaitDialog.setLocationRelativeTo(null);
+            showWaitDialogLater();
+        }
+    }
+
+    private void showWaitDialogLater() {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                if (currentWaitDialog != null) {
+                    currentWaitDialog.setVisible(true); // This is blocking.
+                }
+            }
+        });
+    }
+
+    public void updateWaitDialog(String s) {
+        if (currentWaitDialog != null) {
+            ((JLabel) currentWaitDialog.getContentPane().getComponent(0)).setText(s);
+            Dimension prefSize = currentWaitDialog.getPreferredSize();
+            Dimension curSize = currentWaitDialog.getSize();
+            if (prefSize.width > curSize.width || prefSize.height > curSize.height) {
+                currentWaitDialog.setSize(Math.max(prefSize.width, curSize.width),
+                        Math.max(prefSize.height, curSize.height));
+                currentWaitDialog.invalidate();
+            }
+        }
+    }
+
+    public void hideWaitDialog() {
+        if (currentWaitDialog != null) {
+            currentWaitDialog.setVisible(false);
+            currentWaitDialog = null;
+        }
+    }
+
+    public void showMessageDialog(String s) {
+        // Hide the wait dialog...
+        if (currentWaitDialog != null) {
+            currentWaitDialog.setVisible(false);
+        }
+
+        try {
+            JOptionPane.showMessageDialog(this, s);
+        } finally {
+            // And reshow it afterwards...
+            if (currentWaitDialog != null) {
+                showWaitDialogLater();
+            }
+        }
+    }
+
+    public boolean showConfirmDialog(String title, String message) {
+        // Hide the wait dialog...
+        if (currentWaitDialog != null) {
+            currentWaitDialog.setVisible(false);
+        }
+
+        try {
+            return JOptionPane.showConfirmDialog(this, title, message, JOptionPane.YES_NO_OPTION)
+                    == JOptionPane.YES_OPTION;
+        } finally {
+            // And reshow it afterwards...
+            if (currentWaitDialog != null) {
+                showWaitDialogLater();
+            }
+        }
+    }
+
+    public String showInputDialog(String message) {
+        // Hide the wait dialog...
+        if (currentWaitDialog != null) {
+            currentWaitDialog.setVisible(false);
+        }
+
+        try {
+            return JOptionPane.showInputDialog(message);
+        } finally {
+            // And reshow it afterwards...
+            if (currentWaitDialog != null) {
+                showWaitDialogLater();
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T showChoiceDialog(String title, String message, T[] choices) {
+        // Hide the wait dialog...
+        if (currentWaitDialog != null) {
+            currentWaitDialog.setVisible(false);
+        }
+
+        try{
+            return (T)JOptionPane.showInputDialog(this,
+                    title,
+                    message,
+                    JOptionPane.QUESTION_MESSAGE,
+                    null,
+                    choices,
+                    choices[0]);
+        } finally {
+            // And reshow it afterwards...
+            if (currentWaitDialog != null) {
+                showWaitDialogLater();
+            }
+        }
+    }
+
+    public File showSaveDialog() {
+        // Hide the wait dialog...
+        if (currentWaitDialog != null) {
+            currentWaitDialog.setVisible(false);
+        }
+
+        try{
+            if (jfc == null) {
+                jfc = new JFileChooser();
+            }
+
+            int ret = jfc.showSaveDialog(this);
+            if (ret == JFileChooser.APPROVE_OPTION) {
+                return jfc.getSelectedFile();
+            } else {
+                return null;
+            }
+        } finally {
+            // And reshow it afterwards...
+            if (currentWaitDialog != null) {
+                showWaitDialogLater();
+            }
+        }
+    }
+
+    public File[] showOpenDialog(boolean multi) {
+        // Hide the wait dialog...
+        if (currentWaitDialog != null) {
+            currentWaitDialog.setVisible(false);
+        }
+
+        try{
+            if (jfc == null) {
+                jfc = new JFileChooser();
+            }
+
+            jfc.setMultiSelectionEnabled(multi);
+            int ret = jfc.showOpenDialog(this);
+            if (ret == JFileChooser.APPROVE_OPTION) {
+                return jfc.getSelectedFiles();
+            } else {
+                return null;
+            }
+        } finally {
+            // And reshow it afterwards...
+            if (currentWaitDialog != null) {
+                showWaitDialogLater();
+            }
+        }
+    }
+
+    private class ClientListCellRenderer extends DefaultListCellRenderer {
+
+        @Override
+        public Component getListCellRendererComponent(JList<?> list, Object value, int index,
+                boolean isSelected, boolean cellHasFocus) {
+            ClientData cd = ((Client) value).getClientData();
+            String s = cd.getClientDescription() + " (pid " + cd.getPid() + ")";
+            return super.getListCellRendererComponent(list, s, index, isSelected, cellHasFocus);
+        }
+    }
+}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index dc329e2..4c22460 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -24,15 +24,12 @@
 import android.net.StaticIpConfiguration;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 import android.text.TextUtils;
-import android.util.Log;
 
-import java.util.HashMap;
+import java.util.Arrays;
 import java.util.BitSet;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
+import java.util.HashMap;
 
 /**
  * A class representing a configured Wi-Fi network, including the
@@ -81,6 +78,7 @@
           * (requires {@code preSharedKey} to be specified).
           * @hide
           */
+        @SystemApi
         public static final int WPA2_PSK = 4;
 
         public static final String varName = "key_mgmt";
@@ -182,19 +180,6 @@
     }
 
     /** @hide */
-    public static final int DISABLED_UNKNOWN_REASON                         = 0;
-    /** @hide */
-    public static final int DISABLED_DNS_FAILURE                            = 1;
-    /** @hide */
-    public static final int DISABLED_DHCP_FAILURE                           = 2;
-    /** @hide */
-    public static final int DISABLED_AUTH_FAILURE                           = 3;
-    /** @hide */
-    public static final int DISABLED_ASSOCIATION_REJECT                     = 4;
-    /** @hide */
-    public static final int DISABLED_BY_WIFI_MANAGER                        = 5;
-
-    /** @hide */
     public static final int UNKNOWN_UID = -1;
 
     /**
@@ -206,24 +191,12 @@
 
     /**
      * The current status of this network configuration entry.
+     * Fixme We need remove this field to use only Quality network selection status only
      * @see Status
      */
     public int status;
 
     /**
-     * The configuration needs to be written to networkHistory.txt
-     * @hide
-     */
-    public boolean dirty;
-
-    /**
-     * The code referring to a reason for disabling the network
-     * Valid when {@link #status} == Status.DISABLED
-     * @hide
-     */
-    public int disableReason;
-
-    /**
      * The network's SSID. Can either be an ASCII string,
      * which must be enclosed in double quotation marks
      * (e.g., {@code "MyNetwork"}, or a string of
@@ -356,6 +329,13 @@
 
     /**
      * @hide
+     * This network configuration is visible to and usable by other users on the
+     * same device.
+     */
+    public boolean shared;
+
+    /**
+     * @hide
      */
     private IpConfiguration mIpConfiguration;
 
@@ -421,12 +401,6 @@
 
     /**
      * @hide
-     * Uid used by autoJoin
-     */
-    public String autoJoinBSSID;
-
-    /**
-     * @hide
      * Status of user approval for connection
      */
     public int userApproved = USER_UNSPECIFIED;
@@ -444,77 +418,6 @@
     /** @hide **/
     public static int INVALID_RSSI = -127;
 
-    /** @hide **/
-    public static int UNWANTED_BLACKLIST_SOFT_RSSI_24 = -80;
-
-    /** @hide **/
-    public static int UNWANTED_BLACKLIST_SOFT_RSSI_5 = -70;
-
-    /** @hide **/
-    public static int GOOD_RSSI_24 = -65;
-
-    /** @hide **/
-    public static int LOW_RSSI_24 = -77;
-
-    /** @hide **/
-    public static int BAD_RSSI_24 = -87;
-
-    /** @hide **/
-    public static int GOOD_RSSI_5 = -60;
-
-    /** @hide **/
-    public static int LOW_RSSI_5 = -72;
-
-    /** @hide **/
-    public static int BAD_RSSI_5 = -82;
-
-    /** @hide **/
-    public static int UNWANTED_BLACKLIST_SOFT_BUMP = 4;
-
-    /** @hide **/
-    public static int UNWANTED_BLACKLIST_HARD_BUMP = 8;
-
-    /** @hide **/
-    public static int UNBLACKLIST_THRESHOLD_24_SOFT = -77;
-
-    /** @hide **/
-    public static int UNBLACKLIST_THRESHOLD_24_HARD = -68;
-
-    /** @hide **/
-    public static int UNBLACKLIST_THRESHOLD_5_SOFT = -63;
-
-    /** @hide **/
-    public static int UNBLACKLIST_THRESHOLD_5_HARD = -56;
-
-    /** @hide **/
-    public static int INITIAL_AUTO_JOIN_ATTEMPT_MIN_24 = -80;
-
-    /** @hide **/
-    public static int INITIAL_AUTO_JOIN_ATTEMPT_MIN_5 = -70;
-
-    /** @hide
-     * 5GHz band is prefered low over 2.4 if the 5GHz RSSI is higher than this threshold */
-    public static int A_BAND_PREFERENCE_RSSI_THRESHOLD = -65;
-
-    /** @hide
-     * 5GHz band is penalized if the 5GHz RSSI is lower than this threshold **/
-    public static int G_BAND_PREFERENCE_RSSI_THRESHOLD = -75;
-
-    /** @hide
-     * Boost given to RSSI on a home network for the purpose of calculating the score
-     * This adds stickiness to home networks, as defined by:
-     * - less than 4 known BSSIDs
-     * - PSK only
-     * - TODO: add a test to verify that all BSSIDs are behind same gateway
-     ***/
-    public static int HOME_NETWORK_RSSI_BOOST = 5;
-
-    /** @hide
-     * RSSI boost for configuration which use autoJoinUseAggressiveJoinAttemptThreshold
-     * To be more aggressive when initially attempting to auto join
-     */
-    public static int MAX_INITIAL_AUTO_JOIN_RSSI_BOOST = 8;
-
     /**
      * @hide
      * A summary of the RSSI and Band status for that configuration
@@ -600,38 +503,6 @@
         visibility = status;
     }
 
-    /** @hide */
-    public static final int AUTO_JOIN_ENABLED                   = 0;
-    /**
-     * if this is set, the WifiConfiguration cannot use linkages so as to bump
-     * it's relative priority.
-     * - status between and 128 indicate various level of blacklisting depending
-     * on the severity or frequency of the connection error
-     * - deleted status indicates that the user is deleting the configuration, and so
-     * although it may have been self added we will not re-self-add it, ignore it,
-     * not return it to applications, and not connect to it
-     * */
-
-    /** @hide
-     * network was temporary disabled due to bad connection, most likely due
-     * to weak RSSI */
-    public static final int AUTO_JOIN_TEMPORARY_DISABLED  = 1;
-    /** @hide
-     * network was temporary disabled due to bad connection, which cant be attributed
-     * to weak RSSI */
-    public static final int AUTO_JOIN_TEMPORARY_DISABLED_LINK_ERRORS  = 32;
-    /** @hide */
-    public static final int AUTO_JOIN_TEMPORARY_DISABLED_AT_SUPPLICANT  = 64;
-    /** @hide */
-    public static final int AUTO_JOIN_DISABLED_ON_AUTH_FAILURE  = 128;
-    /** @hide */
-    public static final int AUTO_JOIN_DISABLED_NO_CREDENTIALS = 160;
-    /** @hide */
-    public static final int AUTO_JOIN_DISABLED_USER_ACTION = 161;
-
-    /** @hide */
-    public static final int AUTO_JOIN_DELETED  = 200;
-
     // States for the userApproved field
     /**
      * @hide
@@ -656,29 +527,6 @@
 
     /**
      * @hide
-     */
-    public int autoJoinStatus;
-
-    /**
-     * @hide
-     * Number of connection failures
-     */
-    public int numConnectionFailures;
-
-    /**
-     * @hide
-     * Number of IP config failures
-     */
-    public int numIpConfigFailures;
-
-    /**
-     * @hide
-     * Number of Auth failures
-     */
-    public int numAuthFailures;
-
-    /**
-     * @hide
      * Number of reports indicating no Internet Access
      */
     public int numNoInternetAccessReports;
@@ -715,12 +563,6 @@
 
     /**
      * @hide
-     * Last time we blacklisted the configuration
-     */
-    public long blackListTimestamp;
-
-    /**
-     * @hide
      * Last time the system was connected to this configuration.
      */
     public long lastConnected;
@@ -795,18 +637,6 @@
 
     /**
      * @hide
-     * Indicate that we didn't auto-join because rssi was too low
-     */
-    public boolean autoJoinBailedDueToLowRssi;
-
-    /**
-     * @hide
-     * AutoJoin even though RSSI is 10dB below threshold
-     */
-    public int autoJoinUseAggressiveJoinAttemptThreshold;
-
-    /**
-     * @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
@@ -874,24 +704,526 @@
      */
     public int numUserTriggeredJoinAttempts;
 
+    /** @hide
+     * Boost given to RSSI on a home network for the purpose of calculating the score
+     * This adds stickiness to home networks, as defined by:
+     * - less than 4 known BSSIDs
+     * - PSK only
+     * - TODO: add a test to verify that all BSSIDs are behind same gateway
+     ***/
+    public static final int HOME_NETWORK_RSSI_BOOST = 5;
+
     /**
      * @hide
-     * Connect choices
-     *
-     * remember the keys identifying the known WifiConfiguration over which this configuration
-     * was preferred by user or a "WiFi Network Management app", that is,
-     * a WifiManager.CONNECT_NETWORK or SELECT_NETWORK was received while this configuration
-     * was visible to the user:
-     * configKey is : "SSID"-WEP-WPA_PSK-WPA_EAP
-     *
-     * The integer represents the configuration's RSSI at that time (useful?)
-     *
-     * The overall auto-join algorithm make use of past connect choice so as to sort configuration,
-     * the exact algorithm still fluctuating as of 5/7/2014
-     *
+     * This class is used to contain all the information and API used for quality network selection
      */
-    public HashMap<String, Integer> connectChoices;
+    public static class NetworkSelectionStatus {
+        /**
+         * Quality Network Selection Status enable, temporary disabled, permanently disabled
+         */
+        /**
+         * This network is allowed to join Quality Network Selection
+         */
+        public static final int NETWORK_SELECTION_ENABLED = 0;
+        /**
+         * network was temporary disabled. Can be re-enabled after a time period expire
+         */
+        public static final int NETWORK_SELECTION_TEMPORARY_DISABLED  = 1;
+        /**
+         * network was permanently disabled.
+         */
+        public static final int NETWORK_SELECTION_PERMANENTLY_DISABLED  = 2;
+        /**
+         * Maximum Network selection status
+         */
+        public static final int NETWORK_SELECTION_STATUS_MAX = 3;
 
+        /**
+         * Quality network selection status String (for debug purpose). Use Quality network
+         * selection status value as index to extec the corresponding debug string
+         */
+        private static final String[] QUALITY_NETWORK_SELECTION_STATUS = {
+                "NETWORK_SELECTION_ENABLED",
+                "NETWORK_SELECTION_TEMPORARY_DISABLED",
+                "NETWORK_SELECTION_PERMANENTLY_DISABLED"};
+
+        //Quality Network disabled reasons
+        /**
+         * Default value. Means not disabled
+         */
+        public static final int NETWORK_SELECTION_ENABLE = 0;
+        /**
+         * This network is disabled because higher layer (>2) network is bad
+         */
+        public static final int DISABLED_BAD_LINK = 1;
+        /**
+         * This network is disabled because multiple association rejects
+         */
+        public static final int DISABLED_ASSOCIATION_REJECTION = 2;
+        /**
+         * This network is disabled because multiple authentication failure
+         */
+        public static final int DISABLED_AUTHENTICATION_FAILURE = 3;
+        /**
+         * This network is disabled because multiple DHCP failure
+         */
+        public static final int DISABLED_DHCP_FAILURE = 4;
+        /**
+         * This network is disabled because of security network but no credentials
+         */
+        public static final int DISABLED_DNS_FAILURE = 5;
+        /**
+         * This network is disabled because EAP-TLS failure
+         */
+        public static final int DISABLED_TLS_VERSION_MISMATCH = 6;
+        /**
+         * This network is disabled due to WifiManager disable it explicitly
+         */
+        public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 7;
+        /**
+         * This network is disabled because no Internet connected and user do not want
+         */
+        public static final int DISABLED_NO_INTERNET = 8;
+        /**
+         * This network is disabled due to WifiManager disable it explicitly
+         */
+        public static final int DISABLED_BY_WIFI_MANAGER = 9;
+        /**
+         * This Maximum disable reason value
+         */
+        public static final int NETWORK_SELECTION_DISABLED_MAX = 10;
+
+        /**
+         * Quality network selection disable reason String (for debug purpose)
+         */
+        private static final String[] QUALITY_NETWORK_SELECTION_DISABLE_REASON = {
+                "NETWORK_SELECTION_ENABLE",
+                "NETWORK_SELECTION_DISABLED_BAD_LINK",
+                "NETWORK_SELECTION_DISABLED_ASSOCIATION_REJECTION ",
+                "NETWORK_SELECTION_DISABLED_AUTHENTICATION_FAILURE",
+                "NETWORK_SELECTION_DISABLED_DHCP_FAILURE",
+                "NETWORK_SELECTION_DISABLED_DNS_FAILURE",
+                "NETWORK_SELECTION_DISABLED_TLS_VERSION",
+                "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_CREDENTIALS",
+                "NETWORK_SELECTION_DISABLED_NO_INTERNET",
+                "NETWORK_SELECTION_DISABLED_BY_WIFI_MANAGER"};
+
+        /**
+         * Invalid time stamp for network selection disable
+         */
+        public static final long INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP = -1L;
+
+        /**
+         *  This constant indicates the current configuration has connect choice set
+         */
+        private static final int CONNECT_CHOICE_EXISTS = 1;
+
+        /**
+         *  This constant indicates the current configuration does not have connect choice set
+         */
+        private static final int CONNECT_CHOICE_NOT_EXISTS = -1;
+
+        // fields for QualityNetwork Selection
+        /**
+         * Network selection status, should be in one of three status: enable, temporaily disabled
+         * or permanently disabled
+         */
+        private int mStatus;
+
+        /**
+         * Reason for disable this network
+         */
+        private int mNetworkSelectionDisableReason;
+
+        /**
+         * Last time we temporarily disabled the configuration
+         */
+        private long mTemporarilyDisabledTimestamp = INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP;
+
+        /**
+         * counter for each Network selection disable reason
+         */
+        private int[] mNetworkSeclectionDisableCounter = new int[NETWORK_SELECTION_DISABLED_MAX];
+
+        /**
+         * Connect Choice over this configuration
+         *
+         * When current wifi configuration is visible to the user but user explicitly choose to
+         * connect to another network X, the another networks X's configure key will be stored here.
+         * We will consider user has a preference of X over this network. And in the future,
+         * network selection will always give X a higher preference over this configuration.
+         * configKey is : "SSID"-WEP-WPA_PSK-WPA_EAP
+         */
+        private String mConnectChoice;
+
+        /**
+         * The system timestamp when we records the connectChoice. This value is obtained from
+         * System.currentTimeMillis
+         */
+        private long mConnectChoiceTimestamp = INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP;
+
+        /**
+         * Used to cache the temporary candidate during the network selection procedure. It will be
+         * kept updating once a new scan result has a higher score than current one
+         */
+        private ScanResult mCandidate;
+
+        /**
+         * Used to cache the score of the current temporary candidate during the network
+         * selection procedure.
+         */
+        private int mCandidateScore;
+
+        /**
+         * Indicate whether this network is visible in latest Qualified Network Selection. This
+         * means there is scan result found related to this Configuration and meet the minimum
+         * requirement. The saved network need not join latest Qualified Network Selection. For
+         * example, it is disabled. True means network is visible in latest Qualified Network
+         * Selection and false means network is invisible
+         */
+        private boolean mSeenInLastQualifiedNetworkSelection;
+
+        /**
+         * set whether this network is visible in latest Qualified Network Selection
+         * @param seen value set to candidate
+         */
+        public void setSeenInLastQualifiedNetworkSelection(boolean seen) {
+            mSeenInLastQualifiedNetworkSelection =  seen;
+        }
+
+        /**
+         * get whether this network is visible in latest Qualified Network Selection
+         * @return returns true -- network is visible in latest Qualified Network Selection
+         *         false -- network is invisible in latest Qualified Network Selection
+         */
+        public boolean getSeenInLastQualifiedNetworkSelection() {
+            return mSeenInLastQualifiedNetworkSelection;
+        }
+        /**
+         * set the temporary candidate of current network selection procedure
+         * @param scanCandidate {@link ScanResult} the candidate set to mCandidate
+         */
+        public void setCandidate(ScanResult scanCandidate) {
+            mCandidate = scanCandidate;
+        }
+
+        /**
+         * get the temporary candidate of current network selection procedure
+         * @return  returns {@link ScanResult} temporary candidate of current network selection
+         * procedure
+         */
+        public ScanResult getCandidate() {
+            return mCandidate;
+        }
+
+        /**
+         * set the score of the temporary candidate of current network selection procedure
+         * @param score value set to mCandidateScore
+         */
+        public void setCandidateScore(int score) {
+            mCandidateScore = score;
+        }
+
+        /**
+         * get the score of the temporary candidate of current network selection procedure
+         * @return returns score of the temporary candidate of current network selection procedure
+         */
+        public int getCandidateScore() {
+            return mCandidateScore;
+        }
+
+        /**
+         * get user preferred choice over this configuration
+         *@return returns configKey of user preferred choice over this configuration
+         */
+        public String getConnectChoice() {
+            return mConnectChoice;
+        }
+
+        /**
+         * set user preferred choice over this configuration
+         * @param newConnectChoice, the configKey of user preferred choice over this configuration
+         */
+        public void setConnectChoice(String newConnectChoice) {
+            mConnectChoice = newConnectChoice;
+        }
+
+        /**
+         * get the timeStamp when user select a choice over this configuration
+         * @return returns when current connectChoice is set (time from System.currentTimeMillis)
+         */
+        public long getConnectChoiceTimestamp() {
+            return mConnectChoiceTimestamp;
+        }
+
+        /**
+         * set the timeStamp when user select a choice over this configuration
+         * @param timeStamp, the timestamp set to connectChoiceTimestamp, expected timestamp should
+         *        be obtained from System.currentTimeMillis
+         */
+        public void setConnectChoiceTimestamp(long timeStamp) {
+            mConnectChoiceTimestamp = timeStamp;
+        }
+
+        /**
+         * get current Quality network selection status
+         * @return returns current Quality network selection status in String (for debug purpose)
+         */
+        public String getNetworkStatusString() {
+            return QUALITY_NETWORK_SELECTION_STATUS[mStatus];
+        }
+
+        private NetworkSelectionStatus() {};
+
+        /**
+         * @param reason specific error reason
+         * @return  corresponding network disable reason String (for debug purpose)
+         */
+        public static String getNetworkDisableReasonString(int reason) {
+            if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
+                return QUALITY_NETWORK_SELECTION_DISABLE_REASON[reason];
+            } else {
+                return null;
+            }
+        }
+        /**
+         * get current network disable reason
+         * @return current network disable reason in String (for debug purpose)
+         */
+        public String getNetworkDisableReasonString() {
+            return QUALITY_NETWORK_SELECTION_DISABLE_REASON[mNetworkSelectionDisableReason];
+        }
+
+        /**
+         * get current network network selection status
+         * @return return current network network selection status
+         */
+        public int getNetworkSelectionStatus() {
+            return mStatus;
+        }
+        /**
+         * @return whether current network is enabled to join network selection
+         */
+        public boolean isNetworkEnabled() {
+            return mStatus == NETWORK_SELECTION_ENABLED;
+        }
+
+        /**
+         * @return whether current network is temporary disabled
+         */
+        public boolean isNetworkTemporaryDisabled() {
+            return mStatus == NETWORK_SELECTION_TEMPORARY_DISABLED;
+        }
+
+        /**
+         * @return returns whether current network is permanently disabled
+         */
+        public boolean isNetworkPermanentlyDisabled() {
+            return mStatus == NETWORK_SELECTION_PERMANENTLY_DISABLED;
+        }
+
+        /**
+         * set current networ work selection status
+         * @param status network selection status to set
+         */
+        public void setNetworkSelectionStatus(int status) {
+            if (status >= 0 && status < NETWORK_SELECTION_STATUS_MAX) {
+                mStatus = status;
+            }
+        }
+
+        /**
+         * @return returns current network's disable reason
+         */
+        public int getNetworkSelectionDisableReason() {
+            return mNetworkSelectionDisableReason;
+        }
+
+        /**
+         * set Network disable reason
+         * @param  reason Network disable reason
+         */
+        public void setNetworkSelectionDisableReason(int reason) {
+            if (reason >= 0 && reason < NETWORK_SELECTION_DISABLED_MAX) {
+                mNetworkSelectionDisableReason = reason;
+            } else {
+                throw new IllegalArgumentException("Illegal reason value: " + reason);
+            }
+        }
+
+        /**
+         * check whether network is disabled by this reason
+         * @param reason a specific disable reason
+         * @return true -- network is disabled for this reason
+         *         false -- network is not disabled for this reason
+         */
+        public boolean isDisabledByReason(int reason) {
+            return mNetworkSelectionDisableReason == reason;
+        }
+
+        /**
+         * @param timeStamp Set when current network is disabled in millisecond since January 1,
+         * 1970 00:00:00.0 UTC
+         */
+        public void setDisableTime(long timeStamp) {
+            mTemporarilyDisabledTimestamp = timeStamp;
+        }
+
+        /**
+         * @return returns when current network is disabled in millisecond since January 1,
+         * 1970 00:00:00.0 UTC
+         */
+        public long getDisableTime() {
+            return mTemporarilyDisabledTimestamp;
+        }
+
+        /**
+         * get the disable counter of a specific reason
+         * @param  reason specific failure reason
+         * @exception throw IllegalArgumentException for illegal input
+         * @return counter number for specific error reason.
+         */
+        public int getDisableReasonCounter(int reason) {
+            if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
+                return mNetworkSeclectionDisableCounter[reason];
+            } else {
+                throw new IllegalArgumentException("Illegal reason value: " + reason);
+            }
+        }
+
+        /**
+         * set the counter of a specific failure reason
+         * @param reason reason for disable error
+         * @param value the counter value for this specific reason
+         * @exception throw IllegalArgumentException for illegal input
+         */
+        public void setDisableReasonCounter(int reason, int value) {
+            if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
+                mNetworkSeclectionDisableCounter[reason] = value;
+            } else {
+                throw new IllegalArgumentException("Illegal reason value: " + reason);
+            }
+        }
+
+        /**
+         * increment the counter of a specific failure reason
+         * @param reason a specific failure reason
+         * @exception throw IllegalArgumentException for illegal input
+         */
+        public void incrementDisableReasonCounter(int reason) {
+            if (reason >= NETWORK_SELECTION_ENABLE  && reason < NETWORK_SELECTION_DISABLED_MAX) {
+                mNetworkSeclectionDisableCounter[reason]++;
+            } else {
+                throw new IllegalArgumentException("Illegal reason value: " + reason);
+            }
+        }
+
+        /**
+         * clear the counter of a specific failure reason
+         * @hide
+         * @param reason a specific failure reason
+         * @exception throw IllegalArgumentException for illegal input
+         */
+        public void clearDisableReasonCounter(int reason) {
+            if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
+                mNetworkSeclectionDisableCounter[reason] = NETWORK_SELECTION_ENABLE;
+            } else {
+                throw new IllegalArgumentException("Illegal reason value: " + reason);
+            }
+        }
+
+        /**
+         * clear all the failure reason counters
+         */
+        public void clearDisableReasonCounter() {
+            Arrays.fill(mNetworkSeclectionDisableCounter, NETWORK_SELECTION_ENABLE);
+        }
+
+        /**
+         * BSSID for connection to this network (through network selection procedure)
+         */
+        private String mNetworkSelectionBSSID;
+
+        /**
+         * get current network Selection BSSID
+         * @return current network Selection BSSID
+         */
+        public String getNetworkSelectionBSSID() {
+            return mNetworkSelectionBSSID;
+        }
+
+        /**
+         * set network Selection BSSID
+         * @param bssid The target BSSID for assocaition
+         */
+        public void setNetworkSelectionBSSID(String bssid) {
+            mNetworkSelectionBSSID = bssid;
+        }
+
+        public void copy(NetworkSelectionStatus source) {
+            mStatus = source.mStatus;
+            mNetworkSelectionDisableReason = source.mNetworkSelectionDisableReason;
+            for (int index = NETWORK_SELECTION_ENABLE; index < NETWORK_SELECTION_DISABLED_MAX;
+                    index++) {
+                mNetworkSeclectionDisableCounter[index] =
+                        source.mNetworkSeclectionDisableCounter[index];
+            }
+            mTemporarilyDisabledTimestamp = source.mTemporarilyDisabledTimestamp;
+            mNetworkSelectionBSSID = source.mNetworkSelectionBSSID;
+            setConnectChoice(source.getConnectChoice());
+            setConnectChoiceTimestamp(source.getConnectChoiceTimestamp());
+        }
+
+        public void writeToParcel(Parcel dest) {
+            dest.writeInt(getNetworkSelectionStatus());
+            dest.writeInt(getNetworkSelectionDisableReason());
+            for (int index = NETWORK_SELECTION_ENABLE; index < NETWORK_SELECTION_DISABLED_MAX;
+                    index++) {
+                dest.writeInt(getDisableReasonCounter(index));
+            }
+            dest.writeLong(getDisableTime());
+            dest.writeString(getNetworkSelectionBSSID());
+            if (getConnectChoice() != null) {
+                dest.writeInt(CONNECT_CHOICE_EXISTS);
+                dest.writeString(getConnectChoice());
+                dest.writeLong(getConnectChoiceTimestamp());
+            } else {
+                dest.writeInt(CONNECT_CHOICE_NOT_EXISTS);
+            }
+        }
+
+        public void readFromParcel(Parcel in) {
+            setNetworkSelectionStatus(in.readInt());
+            setNetworkSelectionDisableReason(in.readInt());
+            for (int index = NETWORK_SELECTION_ENABLE; index < NETWORK_SELECTION_DISABLED_MAX;
+                    index++) {
+                setDisableReasonCounter(index, in.readInt());
+            }
+            setDisableTime(in.readLong());
+            setNetworkSelectionBSSID(in.readString());
+            if (in.readInt() == CONNECT_CHOICE_EXISTS) {
+                setConnectChoice(in.readString());
+                setConnectChoiceTimestamp(in.readLong());
+            } else {
+                setConnectChoice(null);
+                setConnectChoiceTimestamp(INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP);
+            }
+        }
+    }
+
+    /**
+     * @hide
+     * network selection related member
+     */
+    private final NetworkSelectionStatus mNetworkSelectionStatus = new NetworkSelectionStatus();
+
+    /**
+     * @hide
+     * @return network selection status
+     */
+    public NetworkSelectionStatus getNetworkSelectionStatus() {
+        return mNetworkSelectionStatus;
+    }
     /**
      * @hide
      * Linked Configurations: represent the set of Wificonfigurations that are equivalent
@@ -910,7 +1242,6 @@
         roamingConsortiumIds = new long[0];
         priority = 0;
         hiddenSSID = false;
-        disableReason = DISABLED_UNKNOWN_REASON;
         allowedKeyManagement = new BitSet();
         allowedProtocols = new BitSet();
         allowedAuthAlgorithms = new BitSet();
@@ -921,7 +1252,6 @@
             wepKeys[i] = null;
         }
         enterpriseConfig = new WifiEnterpriseConfig();
-        autoJoinStatus = AUTO_JOIN_ENABLED;
         selfAdded = false;
         didSelfAdd = false;
         ephemeral = false;
@@ -929,6 +1259,7 @@
         mIpConfiguration = new IpConfiguration();
         lastUpdateUid = -1;
         creatorUid = -1;
+        shared = true;
     }
 
     /**
@@ -946,10 +1277,12 @@
      * @hide
      */
     public boolean isLinked(WifiConfiguration config) {
-        if (config.linkedConfigurations != null && linkedConfigurations != null) {
-            if (config.linkedConfigurations.get(configKey()) != null
-                    && linkedConfigurations.get(config.configKey()) != null) {
-                return true;
+        if (config != null) {
+            if (config.linkedConfigurations != null && linkedConfigurations != null) {
+                if (config.linkedConfigurations.get(configKey()) != null
+                        && linkedConfigurations.get(config.configKey()) != null) {
+                    return true;
+                }
             }
         }
         return  false;
@@ -964,20 +1297,6 @@
             allowedKeyManagement.get(KeyMgmt.IEEE8021X);
     }
 
-    /** @hide **/
-    public void setAutoJoinStatus(int status) {
-        if (status < 0) status = 0;
-        if (status == 0) {
-            blackListTimestamp = 0;
-        }  else if (status > autoJoinStatus) {
-            blackListTimestamp = System.currentTimeMillis();
-        }
-        if (status != autoJoinStatus) {
-            autoJoinStatus = status;
-            dirty = true;
-        }
-    }
-
     @Override
     public String toString() {
         StringBuilder sbuf = new StringBuilder();
@@ -988,24 +1307,32 @@
         }
         sbuf.append("ID: ").append(this.networkId).append(" SSID: ").append(this.SSID).
                 append(" PROVIDER-NAME: ").append(this.providerFriendlyName).
-                append(" BSSID: ").append(this.BSSID).append(" FQDN: ").append(this.FQDN).
-                append(" PRIO: ").append(this.priority).
-                append('\n');
-        if (this.numConnectionFailures > 0) {
-            sbuf.append(" numConnectFailures ").append(this.numConnectionFailures).append("\n");
+                append(" BSSID: ").append(this.BSSID).append(" FQDN: ").append(this.FQDN)
+                .append(" PRIO: ").append(this.priority)
+                .append('\n');
+
+
+        sbuf.append(" NetworkSelectionStatus ")
+                .append(mNetworkSelectionStatus.getNetworkStatusString() + "\n");
+        if (mNetworkSelectionStatus.getNetworkSelectionDisableReason() > 0) {
+            sbuf.append(" mNetworkSelectionDisableReason ")
+                    .append(mNetworkSelectionStatus.getNetworkDisableReasonString() + "\n");
+
+            for (int index = mNetworkSelectionStatus.NETWORK_SELECTION_ENABLE;
+                    index < mNetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX; index++) {
+                if (mNetworkSelectionStatus.getDisableReasonCounter(index) != 0) {
+                    sbuf.append(NetworkSelectionStatus.getNetworkDisableReasonString(index)
+                            + " counter:" + mNetworkSelectionStatus.getDisableReasonCounter(index)
+                            + "\n");
+                }
+            }
         }
-        if (this.numIpConfigFailures > 0) {
-            sbuf.append(" numIpConfigFailures ").append(this.numIpConfigFailures).append("\n");
+        if (mNetworkSelectionStatus.getConnectChoice() != null) {
+            sbuf.append(" connect choice: ").append(mNetworkSelectionStatus.getConnectChoice());
+            sbuf.append(" connect choice set time: ").append(mNetworkSelectionStatus
+                    .getConnectChoiceTimestamp());
         }
-        if (this.numAuthFailures > 0) {
-            sbuf.append(" numAuthFailures ").append(this.numAuthFailures).append("\n");
-        }
-        if (this.autoJoinStatus > 0) {
-            sbuf.append(" autoJoinStatus ").append(this.autoJoinStatus).append("\n");
-        }
-        if (this.disableReason > 0) {
-            sbuf.append(" disableReason ").append(this.disableReason).append("\n");
-        }
+
         if (this.numAssociation > 0) {
             sbuf.append(" numAssociation ").append(this.numAssociation).append("\n");
         }
@@ -1094,11 +1421,15 @@
         sbuf.append("IP config:\n");
         sbuf.append(mIpConfiguration.toString());
 
-        if (this.autoJoinBSSID != null) sbuf.append(" autoJoinBSSID=" + autoJoinBSSID);
+        if (mNetworkSelectionStatus.getNetworkSelectionBSSID() != null) {
+            sbuf.append(" networkSelectionBSSID="
+                    + mNetworkSelectionStatus.getNetworkSelectionBSSID());
+        }
         long now_ms = System.currentTimeMillis();
-        if (this.blackListTimestamp != 0) {
+        if (mNetworkSelectionStatus.getDisableTime() != NetworkSelectionStatus
+                .INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP) {
             sbuf.append('\n');
-            long diff = now_ms - this.blackListTimestamp;
+            long diff = now_ms - mNetworkSelectionStatus.getDisableTime();
             if (diff <= 0) {
                 sbuf.append(" blackListed since <incorrect>");
             } else {
@@ -1152,16 +1483,7 @@
                 sbuf.append('\n');
             }
         }
-        if (this.connectChoices != null) {
-            for(String key : this.connectChoices.keySet()) {
-                Integer choice = this.connectChoices.get(key);
-                if (choice != null) {
-                    sbuf.append(" choice: ").append(key);
-                    sbuf.append(" = ").append(choice);
-                    sbuf.append('\n');
-                }
-            }
-        }
+
         sbuf.append("triggeredLow: ").append(this.numUserTriggeredWifiDisableLowRSSI);
         sbuf.append(" triggeredBad: ").append(this.numUserTriggeredWifiDisableBadRSSI);
         sbuf.append(" triggeredNotHigh: ").append(this.numUserTriggeredWifiDisableNotHighRSSI);
@@ -1172,11 +1494,6 @@
         sbuf.append('\n');
         sbuf.append("triggeredJoin: ").append(this.numUserTriggeredJoinAttempts);
         sbuf.append('\n');
-        sbuf.append("autoJoinBailedDueToLowRssi: ").append(this.autoJoinBailedDueToLowRssi);
-        sbuf.append('\n');
-        sbuf.append("autoJoinUseAggressiveJoinAttemptThreshold: ");
-        sbuf.append(this.autoJoinUseAggressiveJoinAttemptThreshold);
-        sbuf.append('\n');
 
         return sbuf.toString();
     }
@@ -1323,6 +1640,9 @@
             key = mCachedConfigKey;
         } else if (providerFriendlyName != null) {
             key = FQDN + KeyMgmt.strings[KeyMgmt.WPA_EAP];
+            if (!shared) {
+                key += "-" + Integer.toString(UserHandle.getUserId(creatorUid));
+            }
         } else {
             if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
                 key = SSID + KeyMgmt.strings[KeyMgmt.WPA_PSK];
@@ -1334,6 +1654,9 @@
             } else {
                 key = SSID + KeyMgmt.strings[KeyMgmt.NONE];
             }
+            if (!shared) {
+                key += "-" + Integer.toString(UserHandle.getUserId(creatorUid));
+            }
             mCachedConfigKey = key;
         }
         return key;
@@ -1346,27 +1669,6 @@
         return configKey(false);
     }
 
-    /** @hide
-     * return the config key string based on a scan result
-     */
-    static public String configKey(ScanResult result) {
-        String key = "\"" + result.SSID + "\"";
-
-        if (result.capabilities.contains("WEP")) {
-            key = key + "-WEP";
-        }
-
-        if (result.capabilities.contains("PSK")) {
-            key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_PSK];
-        }
-
-        if (result.capabilities.contains("EAP")) {
-            key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_EAP];
-        }
-
-        return key;
-    }
-
     /** @hide */
     public IpConfiguration getIpConfiguration() {
         return mIpConfiguration;
@@ -1428,13 +1730,16 @@
         return 0;
     }
 
+    /** @hide */
+    public boolean isVisibleToUser(int userId) {
+        return shared || (UserHandle.getUserId(creatorUid) == userId);
+    }
+
     /** copy constructor {@hide} */
     public WifiConfiguration(WifiConfiguration source) {
         if (source != null) {
             networkId = source.networkId;
             status = source.status;
-            disableReason = source.disableReason;
-            disableReason = source.disableReason;
             SSID = source.SSID;
             BSSID = source.BSSID;
             FQDN = source.FQDN;
@@ -1442,6 +1747,7 @@
             providerFriendlyName = source.providerFriendlyName;
             preSharedKey = source.preSharedKey;
 
+            mNetworkSelectionStatus.copy(source.getNetworkSelectionStatus());
             apBand = source.apBand;
             apChannel = source.apChannel;
 
@@ -1458,25 +1764,18 @@
             allowedAuthAlgorithms  = (BitSet) source.allowedAuthAlgorithms.clone();
             allowedPairwiseCiphers = (BitSet) source.allowedPairwiseCiphers.clone();
             allowedGroupCiphers    = (BitSet) source.allowedGroupCiphers.clone();
-
             enterpriseConfig = new WifiEnterpriseConfig(source.enterpriseConfig);
 
             defaultGwMacAddress = source.defaultGwMacAddress;
 
             mIpConfiguration = new IpConfiguration(source.mIpConfiguration);
 
-            if ((source.connectChoices != null) && (source.connectChoices.size() > 0)) {
-                connectChoices = new HashMap<String, Integer>();
-                connectChoices.putAll(source.connectChoices);
-            }
-
             if ((source.linkedConfigurations != null)
                     && (source.linkedConfigurations.size() > 0)) {
                 linkedConfigurations = new HashMap<String, Integer>();
                 linkedConfigurations.putAll(source.linkedConfigurations);
             }
             mCachedConfigKey = null; //force null configKey
-            autoJoinStatus = source.autoJoinStatus;
             selfAdded = source.selfAdded;
             validatedInternetAccess = source.validatedInternetAccess;
             ephemeral = source.ephemeral;
@@ -1492,16 +1791,13 @@
             creatorName = source.creatorName;
             lastUpdateName = source.lastUpdateName;
             peerWifiConfiguration = source.peerWifiConfiguration;
-            blackListTimestamp = source.blackListTimestamp;
+
             lastConnected = source.lastConnected;
             lastDisconnected = source.lastDisconnected;
             lastConnectionFailure = source.lastConnectionFailure;
             lastRoamingFailure = source.lastRoamingFailure;
             lastRoamingFailureReason = source.lastRoamingFailureReason;
             roamingFailureBlackListTimeMilli = source.roamingFailureBlackListTimeMilli;
-            numConnectionFailures = source.numConnectionFailures;
-            numIpConfigFailures = source.numIpConfigFailures;
-            numAuthFailures = source.numAuthFailures;
             numScorerOverride = source.numScorerOverride;
             numScorerOverrideAndSwitchedNetwork = source.numScorerOverrideAndSwitchedNetwork;
             numAssociation = source.numAssociation;
@@ -1512,16 +1808,12 @@
             numTicksAtBadRSSI = source.numTicksAtBadRSSI;
             numTicksAtNotHighRSSI = source.numTicksAtNotHighRSSI;
             numUserTriggeredJoinAttempts = source.numUserTriggeredJoinAttempts;
-            autoJoinBSSID = source.autoJoinBSSID;
-            autoJoinUseAggressiveJoinAttemptThreshold
-                    = source.autoJoinUseAggressiveJoinAttemptThreshold;
-            autoJoinBailedDueToLowRssi = source.autoJoinBailedDueToLowRssi;
-            dirty = source.dirty;
             userApproved = source.userApproved;
             numNoInternetAccessReports = source.numNoInternetAccessReports;
             noInternetAccessExpected = source.noInternetAccessExpected;
             creationTime = source.creationTime;
             updateTime = source.updateTime;
+            shared = source.shared;
         }
     }
 
@@ -1535,12 +1827,11 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(networkId);
         dest.writeInt(status);
-        dest.writeInt(disableReason);
+        mNetworkSelectionStatus.writeToParcel(dest);
         dest.writeString(SSID);
         dest.writeString(BSSID);
         dest.writeInt(apBand);
         dest.writeInt(apChannel);
-        dest.writeString(autoJoinBSSID);
         dest.writeString(FQDN);
         dest.writeString(providerFriendlyName);
         dest.writeInt(roamingConsortiumIds.length);
@@ -1568,7 +1859,6 @@
         dest.writeParcelable(mIpConfiguration, flags);
         dest.writeString(dhcpServer);
         dest.writeString(defaultGwMacAddress);
-        dest.writeInt(autoJoinStatus);
         dest.writeInt(selfAdded ? 1 : 0);
         dest.writeInt(didSelfAdd ? 1 : 0);
         dest.writeInt(validatedInternetAccess ? 1 : 0);
@@ -1578,14 +1868,10 @@
         dest.writeInt(lastUpdateUid);
         dest.writeString(creatorName);
         dest.writeString(lastUpdateName);
-        dest.writeLong(blackListTimestamp);
         dest.writeLong(lastConnectionFailure);
         dest.writeLong(lastRoamingFailure);
         dest.writeInt(lastRoamingFailureReason);
         dest.writeLong(roamingFailureBlackListTimeMilli);
-        dest.writeInt(numConnectionFailures);
-        dest.writeInt(numIpConfigFailures);
-        dest.writeInt(numAuthFailures);
         dest.writeInt(numScorerOverride);
         dest.writeInt(numScorerOverrideAndSwitchedNetwork);
         dest.writeInt(numAssociation);
@@ -1596,11 +1882,10 @@
         dest.writeInt(numTicksAtBadRSSI);
         dest.writeInt(numTicksAtNotHighRSSI);
         dest.writeInt(numUserTriggeredJoinAttempts);
-        dest.writeInt(autoJoinUseAggressiveJoinAttemptThreshold);
-        dest.writeInt(autoJoinBailedDueToLowRssi ? 1 : 0);
         dest.writeInt(userApproved);
         dest.writeInt(numNoInternetAccessReports);
         dest.writeInt(noInternetAccessExpected ? 1 : 0);
+        dest.writeInt(shared ? 1 : 0);
     }
 
     /** Implement the Parcelable interface {@hide} */
@@ -1610,12 +1895,11 @@
                 WifiConfiguration config = new WifiConfiguration();
                 config.networkId = in.readInt();
                 config.status = in.readInt();
-                config.disableReason = in.readInt();
+                config.mNetworkSelectionStatus.readFromParcel(in);
                 config.SSID = in.readString();
                 config.BSSID = in.readString();
                 config.apBand = in.readInt();
                 config.apChannel = in.readInt();
-                config.autoJoinBSSID = in.readString();
                 config.FQDN = in.readString();
                 config.providerFriendlyName = in.readString();
                 int numRoamingConsortiumIds = in.readInt();
@@ -1640,11 +1924,9 @@
                 config.allowedGroupCiphers    = readBitSet(in);
 
                 config.enterpriseConfig = in.readParcelable(null);
-
                 config.mIpConfiguration = in.readParcelable(null);
                 config.dhcpServer = in.readString();
                 config.defaultGwMacAddress = in.readString();
-                config.autoJoinStatus = in.readInt();
                 config.selfAdded = in.readInt() != 0;
                 config.didSelfAdd = in.readInt() != 0;
                 config.validatedInternetAccess = in.readInt() != 0;
@@ -1654,14 +1936,10 @@
                 config.lastUpdateUid = in.readInt();
                 config.creatorName = in.readString();
                 config.lastUpdateName = in.readString();
-                config.blackListTimestamp = in.readLong();
                 config.lastConnectionFailure = in.readLong();
                 config.lastRoamingFailure = in.readLong();
                 config.lastRoamingFailureReason = in.readInt();
                 config.roamingFailureBlackListTimeMilli = in.readLong();
-                config.numConnectionFailures = in.readInt();
-                config.numIpConfigFailures = in.readInt();
-                config.numAuthFailures = in.readInt();
                 config.numScorerOverride = in.readInt();
                 config.numScorerOverrideAndSwitchedNetwork = in.readInt();
                 config.numAssociation = in.readInt();
@@ -1672,11 +1950,10 @@
                 config.numTicksAtBadRSSI = in.readInt();
                 config.numTicksAtNotHighRSSI = in.readInt();
                 config.numUserTriggeredJoinAttempts = in.readInt();
-                config.autoJoinUseAggressiveJoinAttemptThreshold = in.readInt();
-                config.autoJoinBailedDueToLowRssi = in.readInt() != 0;
                 config.userApproved = in.readInt();
                 config.numNoInternetAccessReports = in.readInt();
                 config.noInternetAccessExpected = in.readInt() != 0;
+                config.shared = in.readInt() != 0;
                 return config;
             }
 
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 6e42391..605e8c0 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -15,12 +15,14 @@
  */
 package android.net.wifi;
 
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.security.Credentials;
 import android.text.TextUtils;
 
 import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
 import java.security.KeyFactory;
 import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
@@ -72,6 +74,13 @@
     public static final String KEYSTORE_URI = "keystore://";
 
     /**
+     * String representing the keystore URI used for wpa_supplicant,
+     * Unlike #KEYSTORE_URI, this supports a list of space-delimited aliases
+     * @hide
+     */
+    public static final String KEYSTORES_URI = "keystores://";
+
+    /**
      * String to set the engine value to when it should be enabled.
      * @hide
      */
@@ -101,10 +110,12 @@
     public static final String REALM_KEY           = "realm";
     /** @hide */
     public static final String PLMN_KEY            = "plmn";
+    /** @hide */
+    public static final String CA_CERT_ALIAS_DELIMITER = " ";
 
 
     private HashMap<String, String> mFields = new HashMap<String, String>();
-    private X509Certificate mCaCert;
+    private X509Certificate[] mCaCerts;
     private PrivateKey mClientPrivateKey;
     private X509Certificate mClientCertificate;
 
@@ -136,7 +147,7 @@
             dest.writeString(entry.getValue());
         }
 
-        writeCertificate(dest, mCaCert);
+        writeCertificates(dest, mCaCerts);
 
         if (mClientPrivateKey != null) {
             String algorithm = mClientPrivateKey.getAlgorithm();
@@ -151,6 +162,17 @@
         writeCertificate(dest, mClientCertificate);
     }
 
+    private void writeCertificates(Parcel dest, X509Certificate[] cert) {
+        if (cert != null && cert.length != 0) {
+            dest.writeInt(cert.length);
+            for (int i = 0; i < cert.length; i++) {
+                writeCertificate(dest, cert[i]);
+            }
+        } else {
+            dest.writeInt(0);
+        }
+    }
+
     private void writeCertificate(Parcel dest, X509Certificate cert) {
         if (cert != null) {
             try {
@@ -176,7 +198,7 @@
                         enterpriseConfig.mFields.put(key, value);
                     }
 
-                    enterpriseConfig.mCaCert = readCertificate(in);
+                    enterpriseConfig.mCaCerts = readCertificates(in);
 
                     PrivateKey userKey = null;
                     int len = in.readInt();
@@ -199,6 +221,18 @@
                     return enterpriseConfig;
                 }
 
+                private X509Certificate[] readCertificates(Parcel in) {
+                    X509Certificate[] certs = null;
+                    int len = in.readInt();
+                    if (len > 0) {
+                        certs = new X509Certificate[len];
+                        for (int i = 0; i < len; i++) {
+                            certs[i] = readCertificate(in);
+                        }
+                    }
+                    return certs;
+                }
+
                 private X509Certificate readCertificate(Parcel in) {
                     X509Certificate cert = null;
                     int len = in.readInt();
@@ -399,6 +433,36 @@
     }
 
     /**
+     * Encode a CA certificate alias so it does not contain illegal character.
+     * @hide
+     */
+    public static String encodeCaCertificateAlias(String alias) {
+        byte[] bytes = alias.getBytes(StandardCharsets.UTF_8);
+        StringBuilder sb = new StringBuilder(bytes.length * 2);
+        for (byte o : bytes) {
+            sb.append(String.format("%02x", o & 0xFF));
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Decode a previously-encoded CA certificate alias.
+     * @hide
+     */
+    public static String decodeCaCertificateAlias(String alias) {
+        byte[] data = new byte[alias.length() >> 1];
+        for (int n = 0, position = 0; n < alias.length(); n += 2, position++) {
+            data[position] = (byte) Integer.parseInt(alias.substring(n,  n + 2), 16);
+        }
+        try {
+            return new String(data, StandardCharsets.UTF_8);
+        } catch (NumberFormatException e) {
+            e.printStackTrace();
+            return alias;
+        }
+    }
+
+    /**
      * Set CA certificate alias.
      *
      * <p> See the {@link android.security.KeyChain} for details on installing or choosing
@@ -412,6 +476,35 @@
     }
 
     /**
+     * Set CA certificate aliases. When creating installing the corresponding certificate to
+     * the keystore, please use alias encoded by {@link #encodeCaCertificateAlias(String)}.
+     *
+     * <p> See the {@link android.security.KeyChain} for details on installing or choosing
+     * a certificate.
+     * </p>
+     * @param aliases identifies the certificate
+     * @hide
+     */
+    public void setCaCertificateAliases(@Nullable String[] aliases) {
+        if (aliases == null) {
+            setFieldValue(CA_CERT_KEY, null, CA_CERT_PREFIX);
+        } else if (aliases.length == 1) {
+            // Backwards compatibility: use the original cert prefix if setting only one alias.
+            setCaCertificateAlias(aliases[0]);
+        } else {
+            // Use KEYSTORES_URI which supports multiple aliases.
+            StringBuilder sb = new StringBuilder();
+            for (int i = 0; i < aliases.length; i++) {
+                if (i > 0) {
+                    sb.append(CA_CERT_ALIAS_DELIMITER);
+                }
+                sb.append(encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + aliases[i]));
+            }
+            setFieldValue(CA_CERT_KEY, sb.toString(), KEYSTORES_URI);
+        }
+    }
+
+    /**
      * Get CA certificate alias
      * @return alias to the CA certificate
      * @hide
@@ -421,6 +514,32 @@
     }
 
     /**
+     * Get CA certificate aliases
+     * @return alias to the CA certificate
+     * @hide
+     */
+    @Nullable public String[] getCaCertificateAliases() {
+        String value = getFieldValue(CA_CERT_KEY, "");
+        if (value.startsWith(CA_CERT_PREFIX)) {
+            // Backwards compatibility: parse the original alias prefix.
+            return new String[] {getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX)};
+        } else if (value.startsWith(KEYSTORES_URI)) {
+            String values = value.substring(KEYSTORES_URI.length());
+
+            String[] aliases = TextUtils.split(values, CA_CERT_ALIAS_DELIMITER);
+            for (int i = 0; i < aliases.length; i++) {
+                aliases[i] = decodeCaCertificateAlias(aliases[i]);
+                if (aliases[i].startsWith(Credentials.CA_CERTIFICATE)) {
+                    aliases[i] = aliases[i].substring(Credentials.CA_CERTIFICATE.length());
+                }
+            }
+            return aliases.length != 0 ? aliases : null;
+        } else {
+            return TextUtils.isEmpty(value) ? null : new String[] {value};
+        }
+    }
+
+    /**
      * Specify a X.509 certificate that identifies the server.
      *
      * <p>A default name is automatically assigned to the certificate and used
@@ -431,31 +550,76 @@
      * @param cert X.509 CA certificate
      * @throws IllegalArgumentException if not a CA certificate
      */
-    public void setCaCertificate(X509Certificate cert) {
+    public void setCaCertificate(@Nullable X509Certificate cert) {
         if (cert != null) {
             if (cert.getBasicConstraints() >= 0) {
-                mCaCert = cert;
+                mCaCerts = new X509Certificate[] {cert};
             } else {
                 throw new IllegalArgumentException("Not a CA certificate");
             }
         } else {
-            mCaCert = null;
+            mCaCerts = null;
         }
     }
 
     /**
-     * Get CA certificate
+     * Get CA certificate. If multiple CA certificates are configured previously,
+     * return the first one.
      * @return X.509 CA certificate
      */
-    public X509Certificate getCaCertificate() {
-        return mCaCert;
+    @Nullable public X509Certificate getCaCertificate() {
+        if (mCaCerts != null && mCaCerts.length > 0) {
+            return mCaCerts[0];
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Specify a list of X.509 certificates that identifies the server. The validation
+     * passes if the CA of server certificate matches one of the given certificates.
+
+     * <p>Default names are automatically assigned to the certificates and used
+     * with this configuration. The framework takes care of installing the
+     * certificates when the config is saved and removing the certificates when
+     * the config is removed.
+     *
+     * @param certs X.509 CA certificates
+     * @throws IllegalArgumentException if any of the provided certificates is
+     *     not a CA certificate
+     */
+    public void setCaCertificates(@Nullable X509Certificate[] certs) {
+        if (certs != null) {
+            X509Certificate[] newCerts = new X509Certificate[certs.length];
+            for (int i = 0; i < certs.length; i++) {
+                if (certs[i].getBasicConstraints() >= 0) {
+                    newCerts[i] = certs[i];
+                } else {
+                    throw new IllegalArgumentException("Not a CA certificate");
+                }
+            }
+            mCaCerts = newCerts;
+        } else {
+            mCaCerts = null;
+        }
+    }
+
+    /**
+     * Get CA certificates.
+     */
+    @Nullable public X509Certificate[] getCaCertificates() {
+        if (mCaCerts != null || mCaCerts.length > 0) {
+            return mCaCerts;
+        } else {
+            return null;
+        }
     }
 
     /**
      * @hide
      */
     public void resetCaCertificate() {
-        mCaCert = null;
+        mCaCerts = null;
     }
 
     /** Set Client certificate alias.
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 7a5a74f..db40cd8 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1007,7 +1007,7 @@
 
     /**
      * @return true if this adapter supports Neighbour Awareness Network APIs
-     * @hide
+     * @hide PROPOSED_NAN_API
      */
     public boolean isNanSupported() {
         return isFeatureSupported(WIFI_FEATURE_NAN);
@@ -1435,8 +1435,9 @@
      *        part of WifiConfiguration
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      *
-     * @hide Dont open up yet
+     * @hide
      */
+    @SystemApi
     public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
         try {
             mService.setWifiApEnabled(wifiConfig, enabled);
@@ -1453,8 +1454,9 @@
      *         {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
      * @see #isWifiApEnabled()
      *
-     * @hide Dont open yet
+     * @hide
      */
+    @SystemApi
     public int getWifiApState() {
         try {
             return mService.getWifiApEnabledState();
@@ -1468,8 +1470,9 @@
      * @return {@code true} if Wi-Fi AP is enabled
      * @see #getWifiApState()
      *
-     * @hide Dont open yet
+     * @hide
      */
+    @SystemApi
     public boolean isWifiApEnabled() {
         return getWifiApState() == WIFI_AP_STATE_ENABLED;
     }
@@ -1478,8 +1481,9 @@
      * Gets the Wi-Fi AP Configuration.
      * @return AP details in WifiConfiguration
      *
-     * @hide Dont open yet
+     * @hide
      */
+    @SystemApi
     public WifiConfiguration getWifiApConfiguration() {
         try {
             return mService.getWifiApConfiguration();
@@ -1507,8 +1511,9 @@
      * Sets the Wi-Fi AP Configuration.
      * @return {@code true} if the operation succeeded, {@code false} otherwise
      *
-     * @hide Dont open yet
+     * @hide
      */
+    @SystemApi
     public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
         try {
             mService.setWifiApConfiguration(wifiConfig);
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 5534cad..44be671 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -136,17 +136,29 @@
         }
     }
 
-    /** reports {@link ScanListener#onResults} when underlying buffers are full
+    /**
+     * reports {@link ScanListener#onResults} when underlying buffers are full
+     * this is simply the lack of the {@link #REPORT_EVENT_AFTER_EACH_SCAN} flag
      * @deprecated
      */
     @Deprecated
     public static final int REPORT_EVENT_AFTER_BUFFER_FULL = 0;
-    /** reports {@link ScanListener#onResults} after each scan */
-    public static final int REPORT_EVENT_AFTER_EACH_SCAN = 1;
-    /** reports {@link ScanListener#onFullResult} whenever each beacon is discovered */
-    public static final int REPORT_EVENT_FULL_SCAN_RESULT = 2;
-    /** do not batch */
-    public static final int REPORT_EVENT_NO_BATCH = 4;
+    /**
+     * reports {@link ScanListener#onResults} after each scan
+     */
+    public static final int REPORT_EVENT_AFTER_EACH_SCAN = (1 << 0);
+    /**
+     * reports {@link ScanListener#onFullResult} whenever each beacon is discovered
+     */
+    public static final int REPORT_EVENT_FULL_SCAN_RESULT = (1 << 1);
+    /**
+     * Do not place scans in the chip's scan history buffer
+     */
+    public static final int REPORT_EVENT_NO_BATCH = (1 << 2);
+    /**
+     * report full scan results and completion event to the context hub
+     */
+    public static final int REPORT_EVENT_CONTEXT_HUB = (1 << 3);
 
     /**
      * scan configuration parameters to be sent to {@link #startBackgroundScan}
@@ -170,18 +182,14 @@
         public int maxScansToCache;
         /**
          * if maxPeriodInMs is non zero or different than period, then this bucket is
-         * an exponential backoff bucket and the scan period will grow exponentially
-         * as per formula: actual_period(N) = period ^ (N/(step_count+1))
-         * to a maximum period of max_period.
+         * a truncated binary exponential backoff bucket and the scan period will grow
+         * exponentially as per formula: actual_period(N) = period * (2 ^ (N/stepCount))
+         * to maxPeriodInMs
          */
         public int maxPeriodInMs;
         /**
-         * for exponential back off bucket: multiplier: new_period=old_period*exponent
-         */
-        public int exponent;
-        /**
-         * for exponential back off bucket, number of scans performed at a given
-         * period and until the exponent is applied
+         * for truncated binary exponential back off bucket, number of scans to perform
+         * for a given period
          */
         public int stepCount;
 
@@ -198,7 +206,6 @@
             dest.writeInt(numBssidsPerScan);
             dest.writeInt(maxScansToCache);
             dest.writeInt(maxPeriodInMs);
-            dest.writeInt(exponent);
             dest.writeInt(stepCount);
 
             if (channels != null) {
@@ -226,7 +233,6 @@
                         settings.numBssidsPerScan = in.readInt();
                         settings.maxScansToCache = in.readInt();
                         settings.maxPeriodInMs = in.readInt();
-                        settings.exponent = in.readInt();
                         settings.stepCount = in.readInt();
                         int num_channels = in.readInt();
                         settings.channels = new ChannelSpec[num_channels];
diff --git a/wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java b/wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java
new file mode 100644
index 0000000..17cc29f
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+/**
+ * A class representing wifi wake reason accounting.
+ */
+
+/** @hide */
+public class WifiWakeReasonAndCounts implements Parcelable {
+    private static final String TAG = "WifiWakeReasonAndCounts";
+    /**
+     * Wlan can wake host, only when it is cmd/event, local driver-fw
+     * functions(non-data, non cmd/event) and rx data.The first packet
+     * from wlan that woke up a sleep host is what is accounted here.
+     * Total wlan wake to application processor would be:
+     * [cmdEventWake + driverFwLocalWake + totalRxDataWake]
+     * A further classification is provided for identifying the reasons
+     * for wakeup.
+     */
+    public int totalCmdEventWake;
+    public int totalDriverFwLocalWake;
+    public int totalRxDataWake;
+
+    public int rxUnicast;
+    public int rxMulticast;
+    public int rxBroadcast;
+
+    public int icmp;
+    public int icmp6;
+    public int icmp6Ra;
+    public int icmp6Na;
+    public int icmp6Ns;
+
+    public int ipv4RxMulticast;
+    public int ipv6Multicast;
+    public int otherRxMulticast;
+
+    /* {@hide} */
+    public WifiWakeReasonAndCounts () {
+    }
+
+    @Override
+    /* {@hide} */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append(" totalCmdEventWake ").append(totalCmdEventWake);
+        sb.append(" totalDriverFwLocalWake ").append(totalDriverFwLocalWake);
+        sb.append(" totalRxDataWake ").append(totalRxDataWake);
+
+        sb.append(" rxUnicast ").append(rxUnicast);
+        sb.append(" rxMulticast ").append(rxMulticast);
+        sb.append(" rxBroadcast ").append(rxBroadcast);
+
+        sb.append(" icmp ").append(icmp);
+        sb.append(" icmp6 ").append(icmp6);
+        sb.append(" icmp6Ra ").append(icmp6Ra);
+        sb.append(" icmp6Na ").append(icmp6Na);
+        sb.append(" icmp6Ns ").append(icmp6Ns);
+
+        sb.append(" ipv4RxMulticast ").append(ipv4RxMulticast);
+        sb.append(" ipv6Multicast ").append(ipv6Multicast);
+        sb.append(" otherRxMulticast ").append(otherRxMulticast);
+        return sb.toString();
+    }
+
+    /* Implement the Parcelable interface
+     * {@hide}
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /* Implement the Parcelable interface
+     * {@hide}
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(totalCmdEventWake);
+        dest.writeInt(totalDriverFwLocalWake);
+        dest.writeInt(totalRxDataWake);
+
+        dest.writeInt(rxUnicast);
+        dest.writeInt(rxMulticast);
+        dest.writeInt(rxBroadcast);
+
+        dest.writeInt(icmp);
+        dest.writeInt(icmp6);
+        dest.writeInt(icmp6Ra);
+        dest.writeInt(icmp6Na);
+        dest.writeInt(icmp6Ns);
+
+        dest.writeInt(ipv4RxMulticast);
+        dest.writeInt(ipv6Multicast);
+        dest.writeInt(otherRxMulticast);
+    }
+
+    /* Implement the Parcelable interface
+     * {@hide}
+     */
+    public static final Creator<WifiWakeReasonAndCounts> CREATOR =
+        new Creator<WifiWakeReasonAndCounts>() {
+            public WifiWakeReasonAndCounts createFromParcel(Parcel in) {
+                WifiWakeReasonAndCounts counts = new WifiWakeReasonAndCounts();
+                counts.totalCmdEventWake = in.readInt();
+                counts.totalDriverFwLocalWake = in.readInt();
+                counts.totalRxDataWake = in.readInt();
+
+                counts.rxUnicast = in.readInt();
+                counts.rxMulticast = in.readInt();
+                counts.rxBroadcast = in.readInt();
+
+                counts.icmp = in.readInt();
+                counts.icmp6 = in.readInt();
+                counts.icmp6Ra = in.readInt();
+                counts.icmp6Na = in.readInt();
+                counts.icmp6Ns = in.readInt();
+
+                counts.ipv4RxMulticast = in.readInt();
+                counts.ipv6Multicast = in.readInt();
+                counts.otherRxMulticast = in.readInt();
+                return counts;
+            }
+            /* Implement the Parcelable interface
+             * {@hide}
+             */
+            @Override
+            public WifiWakeReasonAndCounts[] newArray(int size) {
+                return new WifiWakeReasonAndCounts[size];
+            }
+        };
+}
diff --git a/wifi/java/android/net/wifi/nan/ConfigRequest.aidl b/wifi/java/android/net/wifi/nan/ConfigRequest.aidl
new file mode 100644
index 0000000..38dddc2
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/ConfigRequest.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.net.wifi.nan;
+
+parcelable ConfigRequest;
diff --git a/wifi/java/android/net/wifi/nan/ConfigRequest.java b/wifi/java/android/net/wifi/nan/ConfigRequest.java
new file mode 100644
index 0000000..23e3754
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/ConfigRequest.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nan;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Defines a request object to configure a Wi-Fi NAN network. Built using
+ * {@link ConfigRequest.Builder}. Configuration is requested using
+ * {@link WifiNanManager#requestConfig(ConfigRequest)}. Note that the actual
+ * achieved configuration may be different from the requested configuration -
+ * since multiple applications may request different configurations.
+ *
+ * @hide PROPOSED_NAN_API
+ */
+public class ConfigRequest implements Parcelable {
+    /**
+     * Lower range of possible cluster ID.
+     *
+     * @hide
+     */
+    public static final int CLUSTER_ID_MIN = 0;
+
+    /**
+     * Upper range of possible cluster ID.
+     *
+     * @hide
+     */
+    public static final int CLUSTER_ID_MAX = 0xFFFF;
+
+    /**
+     * Indicates whether 5G band support is requested.
+     *
+     * @hide
+     */
+    public final boolean mSupport5gBand;
+
+    /**
+     * Specifies the desired master preference.
+     *
+     * @hide
+     */
+    public final int mMasterPreference;
+
+    /**
+     * Specifies the desired lower range of the cluster ID. Must be lower then
+     * {@link ConfigRequest#mClusterHigh}.
+     *
+     * @hide
+     */
+    public final int mClusterLow;
+
+    /**
+     * Specifies the desired higher range of the cluster ID. Must be higher then
+     * {@link ConfigRequest#mClusterLow}.
+     *
+     * @hide
+     */
+    public final int mClusterHigh;
+
+    private ConfigRequest(boolean support5gBand, int masterPreference, int clusterLow,
+            int clusterHigh) {
+        mSupport5gBand = support5gBand;
+        mMasterPreference = masterPreference;
+        mClusterLow = clusterLow;
+        mClusterHigh = clusterHigh;
+    }
+
+    @Override
+    public String toString() {
+        return "ConfigRequest [mSupport5gBand=" + mSupport5gBand + ", mMasterPreference="
+                + mMasterPreference + ", mClusterLow=" + mClusterLow + ", mClusterHigh="
+                + mClusterHigh + "]";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mSupport5gBand ? 1 : 0);
+        dest.writeInt(mMasterPreference);
+        dest.writeInt(mClusterLow);
+        dest.writeInt(mClusterHigh);
+    }
+
+    public static final Creator<ConfigRequest> CREATOR = new Creator<ConfigRequest>() {
+        @Override
+        public ConfigRequest[] newArray(int size) {
+            return new ConfigRequest[size];
+        }
+
+        @Override
+        public ConfigRequest createFromParcel(Parcel in) {
+            boolean support5gBand = in.readInt() != 0;
+            int masterPreference = in.readInt();
+            int clusterLow = in.readInt();
+            int clusterHigh = in.readInt();
+            return new ConfigRequest(support5gBand, masterPreference, clusterLow, clusterHigh);
+        }
+    };
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (!(o instanceof ConfigRequest)) {
+            return false;
+        }
+
+        ConfigRequest lhs = (ConfigRequest) o;
+
+        return mSupport5gBand == lhs.mSupport5gBand && mMasterPreference == lhs.mMasterPreference
+                && mClusterLow == lhs.mClusterLow && mClusterHigh == lhs.mClusterHigh;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 17;
+
+        result = 31 * result + (mSupport5gBand ? 1 : 0);
+        result = 31 * result + mMasterPreference;
+        result = 31 * result + mClusterLow;
+        result = 31 * result + mClusterHigh;
+
+        return result;
+    }
+
+    /**
+     * Builder used to build {@link ConfigRequest} objects.
+     */
+    public static final class Builder {
+        private boolean mSupport5gBand;
+        private int mMasterPreference;
+        private int mClusterLow;
+        private int mClusterHigh;
+
+        /**
+         * Default constructor for the Builder.
+         */
+        public Builder() {
+            mSupport5gBand = false;
+            mMasterPreference = 0;
+            mClusterLow = 0;
+            mClusterHigh = CLUSTER_ID_MAX;
+        }
+
+        /**
+         * Specify whether 5G band support is required in this request.
+         *
+         * @param support5gBand Support for 5G band is required.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setSupport5gBand(boolean support5gBand) {
+            mSupport5gBand = support5gBand;
+            return this;
+        }
+
+        /**
+         * Specify the Master Preference requested. The permitted range is 0 to
+         * 255 with 1 and 255 excluded (reserved).
+         *
+         * @param masterPreference The requested master preference
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setMasterPreference(int masterPreference) {
+            if (masterPreference < 0) {
+                throw new IllegalArgumentException(
+                        "Master Preference specification must be non-negative");
+            }
+            if (masterPreference == 1 || masterPreference == 255 || masterPreference > 255) {
+                throw new IllegalArgumentException("Master Preference specification must not "
+                        + "exceed 255 or use 1 or 255 (reserved values)");
+            }
+
+            mMasterPreference = masterPreference;
+            return this;
+        }
+
+        /**
+         * The Cluster ID is generated randomly for new NAN networks. Specify
+         * the lower range of the cluster ID. The upper range is specified using
+         * the {@link ConfigRequest.Builder#setClusterHigh(int)}. The permitted
+         * range is 0 to the value specified by
+         * {@link ConfigRequest.Builder#setClusterHigh(int)}. Equality is
+         * permitted which restricts the Cluster ID to the specified value.
+         *
+         * @param clusterLow The lower range of the generated cluster ID.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setClusterLow(..).setClusterHigh(..)}.
+         */
+        public Builder setClusterLow(int clusterLow) {
+            if (clusterLow < CLUSTER_ID_MIN) {
+                throw new IllegalArgumentException("Cluster specification must be non-negative");
+            }
+            if (clusterLow > CLUSTER_ID_MAX) {
+                throw new IllegalArgumentException("Cluster specification must not exceed 0xFFFF");
+            }
+
+            mClusterLow = clusterLow;
+            return this;
+        }
+
+        /**
+         * The Cluster ID is generated randomly for new NAN networks. Specify
+         * the lower upper of the cluster ID. The lower range is specified using
+         * the {@link ConfigRequest.Builder#setClusterLow(int)}. The permitted
+         * range is the value specified by
+         * {@link ConfigRequest.Builder#setClusterLow(int)} to 0xFFFF. Equality
+         * is permitted which restricts the Cluster ID to the specified value.
+         *
+         * @param clusterHigh The upper range of the generated cluster ID.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setClusterLow(..).setClusterHigh(..)}.
+         */
+        public Builder setClusterHigh(int clusterHigh) {
+            if (clusterHigh < CLUSTER_ID_MIN) {
+                throw new IllegalArgumentException("Cluster specification must be non-negative");
+            }
+            if (clusterHigh > CLUSTER_ID_MAX) {
+                throw new IllegalArgumentException("Cluster specification must not exceed 0xFFFF");
+            }
+
+            mClusterHigh = clusterHigh;
+            return this;
+        }
+
+        /**
+         * Build {@link ConfigRequest} given the current requests made on the
+         * builder.
+         */
+        public ConfigRequest build() {
+            if (mClusterLow > mClusterHigh) {
+                throw new IllegalArgumentException(
+                        "Invalid argument combination - must have Cluster Low <= Cluster High");
+            }
+
+            return new ConfigRequest(mSupport5gBand, mMasterPreference, mClusterLow, mClusterHigh);
+        }
+    }
+}
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanEventListener.aidl b/wifi/java/android/net/wifi/nan/IWifiNanEventListener.aidl
new file mode 100644
index 0000000..13efc36
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/IWifiNanEventListener.aidl
@@ -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.net.wifi.nan;
+
+import android.net.wifi.nan.ConfigRequest;
+
+/**
+ * Callback interface that WifiNanManager implements
+ *
+ * {@hide}
+ */
+oneway interface IWifiNanEventListener
+{
+    void onConfigCompleted(in ConfigRequest completedConfig);
+    void onConfigFailed(int reason);
+    void onNanDown(int reason);
+    void onIdentityChanged();
+}
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
new file mode 100644
index 0000000..ec9e462
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
@@ -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.net.wifi.nan;
+
+import android.app.PendingIntent;
+
+import android.net.wifi.nan.ConfigRequest;
+import android.net.wifi.nan.IWifiNanEventListener;
+import android.net.wifi.nan.IWifiNanSessionListener;
+import android.net.wifi.nan.PublishData;
+import android.net.wifi.nan.PublishSettings;
+import android.net.wifi.nan.SubscribeData;
+import android.net.wifi.nan.SubscribeSettings;
+
+/**
+ * Interface that WifiNanService implements
+ *
+ * {@hide}
+ */
+interface IWifiNanManager
+{
+    // client API
+    void connect(in IBinder binder, in IWifiNanEventListener listener, int events);
+    void disconnect(in IBinder binder);
+    void requestConfig(in ConfigRequest configRequest);
+
+    // session API
+    int createSession(in IWifiNanSessionListener listener, int events);
+    void publish(int sessionId, in PublishData publishData, in PublishSettings publishSettings);
+    void subscribe(int sessionId, in SubscribeData subscribeData,
+            in SubscribeSettings subscribeSettings);
+    void sendMessage(int sessionId, int peerId, in byte[] message, int messageLength,
+            int messageId);
+    void stopSession(int sessionId);
+    void destroySession(int sessionId);
+}
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl b/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl
new file mode 100644
index 0000000..50c34d9
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.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 android.net.wifi.nan;
+
+/**
+ * Callback interface that WifiNanManager implements
+ *
+ * {@hide}
+ */
+oneway interface IWifiNanSessionListener
+{
+    void onPublishFail(int reason);
+    void onPublishTerminated(int reason);
+
+    void onSubscribeFail(int reason);
+    void onSubscribeTerminated(int reason);
+
+    void onMatch(int peerId, in byte[] serviceSpecificInfo,
+            int serviceSpecificInfoLength, in byte[] matchFilter, int matchFilterLength);
+
+    void onMessageSendSuccess(int messageId);
+    void onMessageSendFail(int messageId, int reason);
+    void onMessageReceived(int peerId, in byte[] message, int messageLength);
+}
diff --git a/wifi/java/android/net/wifi/nan/PublishData.aidl b/wifi/java/android/net/wifi/nan/PublishData.aidl
new file mode 100644
index 0000000..15e4ddf
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/PublishData.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.net.wifi.nan;
+
+parcelable PublishData;
diff --git a/wifi/java/android/net/wifi/nan/PublishData.java b/wifi/java/android/net/wifi/nan/PublishData.java
new file mode 100644
index 0000000..80119eb
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/PublishData.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nan;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * Defines the data for a NAN publish session. Built using
+ * {@link PublishData.Builder}. Publish is done using
+ * {@link WifiNanManager#publish(PublishData, PublishSettings, WifiNanSessionListener, int)}
+ * or {@link WifiNanPublishSession#publish(PublishData, PublishSettings)}.
+ * @hide PROPOSED_NAN_API
+ */
+public class PublishData implements Parcelable {
+    /**
+     * @hide
+     */
+    public final String mServiceName;
+
+    /**
+     * @hide
+     */
+    public final int mServiceSpecificInfoLength;
+
+    /**
+     * @hide
+     */
+    public final byte[] mServiceSpecificInfo;
+
+    /**
+     * @hide
+     */
+    public final int mTxFilterLength;
+
+    /**
+     * @hide
+     */
+    public final byte[] mTxFilter;
+
+    /**
+     * @hide
+     */
+    public final int mRxFilterLength;
+
+    /**
+     * @hide
+     */
+    public final byte[] mRxFilter;
+
+    private PublishData(String serviceName, byte[] serviceSpecificInfo,
+            int serviceSpecificInfoLength, byte[] txFilter, int txFilterLength, byte[] rxFilter,
+            int rxFilterLength) {
+        mServiceName = serviceName;
+        mServiceSpecificInfoLength = serviceSpecificInfoLength;
+        mServiceSpecificInfo = serviceSpecificInfo;
+        mTxFilterLength = txFilterLength;
+        mTxFilter = txFilter;
+        mRxFilterLength = rxFilterLength;
+        mRxFilter = rxFilter;
+    }
+
+    @Override
+    public String toString() {
+        return "PublishData [mServiceName='" + mServiceName + "', mServiceSpecificInfo='"
+                + (new String(mServiceSpecificInfo, 0, mServiceSpecificInfoLength))
+                + "', mTxFilter="
+                + (new TlvBufferUtils.TlvIterable(0, 1, mTxFilter, mTxFilterLength)).toString()
+                + ", mRxFilter="
+                + (new TlvBufferUtils.TlvIterable(0, 1, mRxFilter, mRxFilterLength)).toString()
+                + "']";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mServiceName);
+        dest.writeInt(mServiceSpecificInfoLength);
+        if (mServiceSpecificInfoLength != 0) {
+            dest.writeByteArray(mServiceSpecificInfo, 0, mServiceSpecificInfoLength);
+        }
+        dest.writeInt(mTxFilterLength);
+        if (mTxFilterLength != 0) {
+            dest.writeByteArray(mTxFilter, 0, mTxFilterLength);
+        }
+        dest.writeInt(mRxFilterLength);
+        if (mRxFilterLength != 0) {
+            dest.writeByteArray(mRxFilter, 0, mRxFilterLength);
+        }
+    }
+
+    public static final Creator<PublishData> CREATOR = new Creator<PublishData>() {
+        @Override
+        public PublishData[] newArray(int size) {
+            return new PublishData[size];
+        }
+
+        @Override
+        public PublishData createFromParcel(Parcel in) {
+            String serviceName = in.readString();
+            int ssiLength = in.readInt();
+            byte[] ssi = new byte[ssiLength];
+            if (ssiLength != 0) {
+                in.readByteArray(ssi);
+            }
+            int txFilterLength = in.readInt();
+            byte[] txFilter = new byte[txFilterLength];
+            if (txFilterLength != 0) {
+                in.readByteArray(txFilter);
+            }
+            int rxFilterLength = in.readInt();
+            byte[] rxFilter = new byte[rxFilterLength];
+            if (rxFilterLength != 0) {
+                in.readByteArray(rxFilter);
+            }
+
+            return new PublishData(serviceName, ssi, ssiLength, txFilter, txFilterLength, rxFilter,
+                    rxFilterLength);
+        }
+    };
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (!(o instanceof PublishData)) {
+            return false;
+        }
+
+        PublishData lhs = (PublishData) o;
+
+        if (!mServiceName.equals(lhs.mServiceName)
+                || mServiceSpecificInfoLength != lhs.mServiceSpecificInfoLength
+                || mTxFilterLength != lhs.mTxFilterLength
+                || mRxFilterLength != lhs.mRxFilterLength) {
+            return false;
+        }
+
+        if (mServiceSpecificInfo != null && lhs.mServiceSpecificInfo != null) {
+            for (int i = 0; i < mServiceSpecificInfoLength; ++i) {
+                if (mServiceSpecificInfo[i] != lhs.mServiceSpecificInfo[i]) {
+                    return false;
+                }
+            }
+        } else if (mServiceSpecificInfoLength != 0) {
+            return false; // invalid != invalid
+        }
+
+        if (mTxFilter != null && lhs.mTxFilter != null) {
+            for (int i = 0; i < mTxFilterLength; ++i) {
+                if (mTxFilter[i] != lhs.mTxFilter[i]) {
+                    return false;
+                }
+            }
+        } else if (mTxFilterLength != 0) {
+            return false; // invalid != invalid
+        }
+
+        if (mRxFilter != null && lhs.mRxFilter != null) {
+            for (int i = 0; i < mRxFilterLength; ++i) {
+                if (mRxFilter[i] != lhs.mRxFilter[i]) {
+                    return false;
+                }
+            }
+        } else if (mRxFilterLength != 0) {
+            return false; // invalid != invalid
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 17;
+
+        result = 31 * result + mServiceName.hashCode();
+        result = 31 * result + mServiceSpecificInfoLength;
+        result = 31 * result + Arrays.hashCode(mServiceSpecificInfo);
+        result = 31 * result + mTxFilterLength;
+        result = 31 * result + Arrays.hashCode(mTxFilter);
+        result = 31 * result + mRxFilterLength;
+        result = 31 * result + Arrays.hashCode(mRxFilter);
+
+        return result;
+    }
+
+    /**
+     * Builder used to build {@link PublishData} objects.
+     */
+    public static final class Builder {
+        private String mServiceName;
+        private int mServiceSpecificInfoLength;
+        private byte[] mServiceSpecificInfo = new byte[0];
+        private int mTxFilterLength;
+        private byte[] mTxFilter = new byte[0];
+        private int mRxFilterLength;
+        private byte[] mRxFilter = new byte[0];
+
+        /**
+         * Specify the service name of the publish session. The actual on-air
+         * value is a 6 byte hashed representation of this string.
+         *
+         * @param serviceName The service name for the publish session.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setServiceName(String serviceName) {
+            mServiceName = serviceName;
+            return this;
+        }
+
+        /**
+         * Specify service specific information for the publish session. This is
+         * a free-form byte array available to the application to send
+         * additional information as part of the discovery operation - i.e. it
+         * will not be used to determine whether a publish/subscribe match
+         * occurs.
+         *
+         * @param serviceSpecificInfo A byte-array for the service-specific
+         *            information field.
+         * @param serviceSpecificInfoLength The length of the byte-array to be
+         *            used.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setServiceSpecificInfo(byte[] serviceSpecificInfo,
+                int serviceSpecificInfoLength) {
+            if (serviceSpecificInfoLength != 0 && (serviceSpecificInfo == null
+                    || serviceSpecificInfo.length < serviceSpecificInfoLength)) {
+                throw new IllegalArgumentException("Non-matching combination of "
+                        + "serviceSpecificInfo and serviceSpecificInfoLength");
+            }
+            mServiceSpecificInfoLength = serviceSpecificInfoLength;
+            mServiceSpecificInfo = serviceSpecificInfo;
+            return this;
+        }
+
+        /**
+         * Specify service specific information for the publish session - same
+         * as {@link PublishData.Builder#setServiceSpecificInfo(byte[], int)}
+         * but obtaining the data from a String.
+         *
+         * @param serviceSpecificInfoStr The service specific information string
+         *            to be included (as a byte array) in the publish
+         *            information.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setServiceSpecificInfo(String serviceSpecificInfoStr) {
+            mServiceSpecificInfoLength = serviceSpecificInfoStr.length();
+            mServiceSpecificInfo = serviceSpecificInfoStr.getBytes();
+            return this;
+        }
+
+        /**
+         * The transmit filter for an active publish session
+         * {@link PublishSettings.Builder#setPublishType(int)} and
+         * {@link PublishSettings#PUBLISH_TYPE_UNSOLICITED}. Included in
+         * transmitted publish packets and used by receivers (subscribers) to
+         * determine whether they match - in addition to just relying on the
+         * service name.
+         * <p>
+         * Format is an LV byte array - the {@link TlvBufferUtils} utility class
+         * is available to form and parse.
+         *
+         * @param txFilter The byte-array containing the LV formatted transmit
+         *            filter.
+         * @param txFilterLength The number of bytes in the transmit filter
+         *            argument.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setTxFilter(byte[] txFilter, int txFilterLength) {
+            if (txFilterLength != 0 && (txFilter == null || txFilter.length < txFilterLength)) {
+                throw new IllegalArgumentException(
+                        "Non-matching combination of txFilter and txFilterLength");
+            }
+            mTxFilter = txFilter;
+            mTxFilterLength = txFilterLength;
+            return this;
+        }
+
+        /**
+         * The transmit filter for a passive publish session
+         * {@link PublishSettings.Builder#setPublishType(int)} and
+         * {@link PublishSettings#PUBLISH_TYPE_SOLICITED}. Used by the publisher
+         * to determine whether they match transmitted subscriber packets
+         * (active subscribers) - in addition to just relying on the service
+         * name.
+         * <p>
+         * Format is an LV byte array - the {@link TlvBufferUtils} utility class
+         * is available to form and parse.
+         *
+         * @param rxFilter The byte-array containing the LV formatted receive
+         *            filter.
+         * @param rxFilterLength The number of bytes in the receive filter
+         *            argument.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setRxFilter(byte[] rxFilter, int rxFilterLength) {
+            if (rxFilterLength != 0 && (rxFilter == null || rxFilter.length < rxFilterLength)) {
+                throw new IllegalArgumentException(
+                        "Non-matching combination of rxFilter and rxFilterLength");
+            }
+            mRxFilter = rxFilter;
+            mRxFilterLength = rxFilterLength;
+            return this;
+        }
+
+        /**
+         * Build {@link PublishData} given the current requests made on the
+         * builder.
+         */
+        public PublishData build() {
+            return new PublishData(mServiceName, mServiceSpecificInfo, mServiceSpecificInfoLength,
+                    mTxFilter, mTxFilterLength, mRxFilter, mRxFilterLength);
+        }
+    }
+}
diff --git a/wifi/java/android/net/wifi/nan/PublishSettings.aidl b/wifi/java/android/net/wifi/nan/PublishSettings.aidl
new file mode 100644
index 0000000..ff69293
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/PublishSettings.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.net.wifi.nan;
+
+parcelable PublishSettings;
diff --git a/wifi/java/android/net/wifi/nan/PublishSettings.java b/wifi/java/android/net/wifi/nan/PublishSettings.java
new file mode 100644
index 0000000..bbc5340
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/PublishSettings.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nan;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Defines the settings (configuration) for a NAN publish session. Built using
+ * {@link PublishSettings.Builder}. Publish is done using
+ * {@link WifiNanManager#publish(PublishData, PublishSettings, WifiNanSessionListener, int)}
+ * or {@link WifiNanPublishSession#publish(PublishData, PublishSettings)}.
+ *
+ * @hide PROPOSED_NAN_API
+ */
+public class PublishSettings implements Parcelable {
+
+    /**
+     * Defines an unsolicited publish session - i.e. a publish session where
+     * publish packets are transmitted over-the-air. Configuration is done using
+     * {@link PublishSettings.Builder#setPublishType(int)}.
+     */
+    public static final int PUBLISH_TYPE_UNSOLICITED = 0;
+
+    /**
+     * Defines a solicited publish session - i.e. a publish session where
+     * publish packets are not transmitted over-the-air and the device listens
+     * and matches to transmitted subscribe packets. Configuration is done using
+     * {@link PublishSettings.Builder#setPublishType(int)}.
+     */
+    public static final int PUBLISH_TYPE_SOLICITED = 1;
+
+    /**
+     * @hide
+     */
+    public final int mPublishType;
+
+    /**
+     * @hide
+     */
+    public final int mPublishCount;
+
+    /**
+     * @hide
+     */
+    public final int mTtlSec;
+
+    private PublishSettings(int publishType, int publichCount, int ttlSec) {
+        mPublishType = publishType;
+        mPublishCount = publichCount;
+        mTtlSec = ttlSec;
+    }
+
+    @Override
+    public String toString() {
+        return "PublishSettings [mPublishType=" + mPublishType + ", mPublishCount=" + mPublishCount
+                + ", mTtlSec=" + mTtlSec + "]";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mPublishType);
+        dest.writeInt(mPublishCount);
+        dest.writeInt(mTtlSec);
+    }
+
+    public static final Creator<PublishSettings> CREATOR = new Creator<PublishSettings>() {
+        @Override
+        public PublishSettings[] newArray(int size) {
+            return new PublishSettings[size];
+        }
+
+        @Override
+        public PublishSettings createFromParcel(Parcel in) {
+            int publishType = in.readInt();
+            int publishCount = in.readInt();
+            int ttlSec = in.readInt();
+            return new PublishSettings(publishType, publishCount, ttlSec);
+        }
+    };
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (!(o instanceof PublishSettings)) {
+            return false;
+        }
+
+        PublishSettings lhs = (PublishSettings) o;
+
+        return mPublishType == lhs.mPublishType && mPublishCount == lhs.mPublishCount
+                && mTtlSec == lhs.mTtlSec;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 17;
+
+        result = 31 * result + mPublishType;
+        result = 31 * result + mPublishCount;
+        result = 31 * result + mTtlSec;
+
+        return result;
+    }
+
+    /**
+     * Builder used to build {@link PublishSettings} objects.
+     */
+    public static final class Builder {
+        int mPublishType;
+        int mPublishCount;
+        int mTtlSec;
+
+        /**
+         * Sets the type of the publish session: solicited (aka active - publish
+         * packets are transmitted over-the-air), or unsolicited (aka passive -
+         * no publish packets are transmitted, a match is made against an active
+         * subscribe session whose packets are transmitted over-the-air).
+         *
+         * @param publishType Publish session type: solicited (
+         *            {@link PublishSettings#PUBLISH_TYPE_SOLICITED}) or
+         *            unsolicited (
+         *            {@link PublishSettings#PUBLISH_TYPE_UNSOLICITED}).
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setPublishType(int publishType) {
+            if (publishType < PUBLISH_TYPE_UNSOLICITED || publishType > PUBLISH_TYPE_SOLICITED) {
+                throw new IllegalArgumentException("Invalid publishType - " + publishType);
+            }
+            mPublishType = publishType;
+            return this;
+        }
+
+        /**
+         * Sets the number of times a solicited (
+         * {@link PublishSettings.Builder#setPublishType(int)}) publish session
+         * will transmit a packet. When the count is reached an event will be
+         * generated for {@link WifiNanSessionListener#onPublishTerminated(int)}
+         * with reason={@link WifiNanSessionListener#TERMINATE_REASON_DONE}.
+         *
+         * @param publishCount Number of publish packets to transmit.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setPublishCount(int publishCount) {
+            if (publishCount < 0) {
+                throw new IllegalArgumentException("Invalid publishCount - must be non-negative");
+            }
+            mPublishCount = publishCount;
+            return this;
+        }
+
+        /**
+         * Sets the time interval (in seconds) a solicited (
+         * {@link PublishSettings.Builder#setPublishCount(int)}) publish session
+         * will be alive - i.e. transmitting a packet. When the TTL is reached
+         * an event will be generated for
+         * {@link WifiNanSessionListener#onPublishTerminated(int)} with reason=
+         * {@link WifiNanSessionListener#TERMINATE_REASON_DONE}.
+         *
+         * @param ttlSec Lifetime of a publish session in seconds.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setTtlSec(int ttlSec) {
+            if (ttlSec < 0) {
+                throw new IllegalArgumentException("Invalid ttlSec - must be non-negative");
+            }
+            mTtlSec = ttlSec;
+            return this;
+        }
+
+        /**
+         * Build {@link PublishSettings} given the current requests made on the
+         * builder.
+         */
+        public PublishSettings build() {
+            return new PublishSettings(mPublishType, mPublishCount, mTtlSec);
+        }
+    }
+}
diff --git a/wifi/java/android/net/wifi/nan/SubscribeData.aidl b/wifi/java/android/net/wifi/nan/SubscribeData.aidl
new file mode 100644
index 0000000..662fdb8
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/SubscribeData.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.net.wifi.nan;
+
+parcelable SubscribeData;
diff --git a/wifi/java/android/net/wifi/nan/SubscribeData.java b/wifi/java/android/net/wifi/nan/SubscribeData.java
new file mode 100644
index 0000000..cd6e918
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/SubscribeData.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nan;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * Defines the data for a NAN subscribe session. Built using
+ * {@link SubscribeData.Builder}. Subscribe is done using
+ * {@link WifiNanManager#subscribe(SubscribeData, SubscribeSettings, WifiNanSessionListener, int)}
+ * or
+ * {@link WifiNanSubscribeSession#subscribe(SubscribeData, SubscribeSettings)}.
+ * @hide PROPOSED_NAN_API
+ */
+public class SubscribeData implements Parcelable {
+    /**
+     * @hide
+     */
+    public final String mServiceName;
+
+    /**
+     * @hide
+     */
+    public final int mServiceSpecificInfoLength;
+
+    /**
+     * @hide
+     */
+    public final byte[] mServiceSpecificInfo;
+
+    /**
+     * @hide
+     */
+    public final int mTxFilterLength;
+
+    /**
+     * @hide
+     */
+    public final byte[] mTxFilter;
+
+    /**
+     * @hide
+     */
+    public final int mRxFilterLength;
+
+    /**
+     * @hide
+     */
+    public final byte[] mRxFilter;
+
+    private SubscribeData(String serviceName, byte[] serviceSpecificInfo,
+            int serviceSpecificInfoLength, byte[] txFilter, int txFilterLength, byte[] rxFilter,
+            int rxFilterLength) {
+        mServiceName = serviceName;
+        mServiceSpecificInfoLength = serviceSpecificInfoLength;
+        mServiceSpecificInfo = serviceSpecificInfo;
+        mTxFilterLength = txFilterLength;
+        mTxFilter = txFilter;
+        mRxFilterLength = rxFilterLength;
+        mRxFilter = rxFilter;
+    }
+
+    @Override
+    public String toString() {
+        return "SubscribeData [mServiceName='" + mServiceName + "', mServiceSpecificInfo='"
+                + (new String(mServiceSpecificInfo, 0, mServiceSpecificInfoLength))
+                + "', mTxFilter="
+                + (new TlvBufferUtils.TlvIterable(0, 1, mTxFilter, mTxFilterLength)).toString()
+                + ", mRxFilter="
+                + (new TlvBufferUtils.TlvIterable(0, 1, mRxFilter, mRxFilterLength)).toString()
+                + "']";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mServiceName);
+        dest.writeInt(mServiceSpecificInfoLength);
+        if (mServiceSpecificInfoLength != 0) {
+            dest.writeByteArray(mServiceSpecificInfo, 0, mServiceSpecificInfoLength);
+        }
+        dest.writeInt(mTxFilterLength);
+        if (mTxFilterLength != 0) {
+            dest.writeByteArray(mTxFilter, 0, mTxFilterLength);
+        }
+        dest.writeInt(mRxFilterLength);
+        if (mRxFilterLength != 0) {
+            dest.writeByteArray(mRxFilter, 0, mRxFilterLength);
+        }
+    }
+
+    public static final Creator<SubscribeData> CREATOR = new Creator<SubscribeData>() {
+        @Override
+        public SubscribeData[] newArray(int size) {
+            return new SubscribeData[size];
+        }
+
+        @Override
+        public SubscribeData createFromParcel(Parcel in) {
+            String serviceName = in.readString();
+            int ssiLength = in.readInt();
+            byte[] ssi = new byte[ssiLength];
+            if (ssiLength != 0) {
+                in.readByteArray(ssi);
+            }
+            int txFilterLength = in.readInt();
+            byte[] txFilter = new byte[txFilterLength];
+            if (txFilterLength != 0) {
+                in.readByteArray(txFilter);
+            }
+            int rxFilterLength = in.readInt();
+            byte[] rxFilter = new byte[rxFilterLength];
+            if (rxFilterLength != 0) {
+                in.readByteArray(rxFilter);
+            }
+
+            return new SubscribeData(serviceName, ssi, ssiLength, txFilter, txFilterLength,
+                    rxFilter, rxFilterLength);
+        }
+    };
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (!(o instanceof SubscribeData)) {
+            return false;
+        }
+
+        SubscribeData lhs = (SubscribeData) o;
+
+        if (!mServiceName.equals(lhs.mServiceName)
+                || mServiceSpecificInfoLength != lhs.mServiceSpecificInfoLength
+                || mTxFilterLength != lhs.mTxFilterLength
+                || mRxFilterLength != lhs.mRxFilterLength) {
+            return false;
+        }
+
+        if (mServiceSpecificInfo != null && lhs.mServiceSpecificInfo != null) {
+            for (int i = 0; i < mServiceSpecificInfoLength; ++i) {
+                if (mServiceSpecificInfo[i] != lhs.mServiceSpecificInfo[i]) {
+                    return false;
+                }
+            }
+        } else if (mServiceSpecificInfoLength != 0) {
+            return false; // invalid != invalid
+        }
+
+        if (mTxFilter != null && lhs.mTxFilter != null) {
+            for (int i = 0; i < mTxFilterLength; ++i) {
+                if (mTxFilter[i] != lhs.mTxFilter[i]) {
+                    return false;
+                }
+            }
+        } else if (mTxFilterLength != 0) {
+            return false; // invalid != invalid
+        }
+
+        if (mRxFilter != null && lhs.mRxFilter != null) {
+            for (int i = 0; i < mRxFilterLength; ++i) {
+                if (mRxFilter[i] != lhs.mRxFilter[i]) {
+                    return false;
+                }
+            }
+        } else if (mRxFilterLength != 0) {
+            return false; // invalid != invalid
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 17;
+
+        result = 31 * result + mServiceName.hashCode();
+        result = 31 * result + mServiceSpecificInfoLength;
+        result = 31 * result + Arrays.hashCode(mServiceSpecificInfo);
+        result = 31 * result + mTxFilterLength;
+        result = 31 * result + Arrays.hashCode(mTxFilter);
+        result = 31 * result + mRxFilterLength;
+        result = 31 * result + Arrays.hashCode(mRxFilter);
+
+        return result;
+    }
+
+    /**
+     * Builder used to build {@link SubscribeData} objects.
+     */
+    public static final class Builder {
+        private String mServiceName;
+        private int mServiceSpecificInfoLength;
+        private byte[] mServiceSpecificInfo = new byte[0];
+        private int mTxFilterLength;
+        private byte[] mTxFilter = new byte[0];
+        private int mRxFilterLength;
+        private byte[] mRxFilter = new byte[0];
+
+        /**
+         * Specify the service name of the subscribe session. The actual on-air
+         * value is a 6 byte hashed representation of this string.
+         *
+         * @param serviceName The service name for the subscribe session.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setServiceName(String serviceName) {
+            mServiceName = serviceName;
+            return this;
+        }
+
+        /**
+         * Specify service specific information for the subscribe session. This
+         * is a free-form byte array available to the application to send
+         * additional information as part of the discovery operation - i.e. it
+         * will not be used to determine whether a publish/subscribe match
+         * occurs.
+         *
+         * @param serviceSpecificInfo A byte-array for the service-specific
+         *            information field.
+         * @param serviceSpecificInfoLength The length of the byte-array to be
+         *            used.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setServiceSpecificInfo(byte[] serviceSpecificInfo,
+                int serviceSpecificInfoLength) {
+            mServiceSpecificInfoLength = serviceSpecificInfoLength;
+            mServiceSpecificInfo = serviceSpecificInfo;
+            return this;
+        }
+
+        /**
+         * Specify service specific information for the subscribe session - same
+         * as {@link SubscribeData.Builder#setServiceSpecificInfo(byte[], int)}
+         * but obtaining the data from a String.
+         *
+         * @param serviceSpecificInfoStr The service specific information string
+         *            to be included (as a byte array) in the subscribe
+         *            information.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setServiceSpecificInfo(String serviceSpecificInfoStr) {
+            mServiceSpecificInfoLength = serviceSpecificInfoStr.length();
+            mServiceSpecificInfo = serviceSpecificInfoStr.getBytes();
+            return this;
+        }
+
+        /**
+         * The transmit filter for an active subscribe session
+         * {@link SubscribeSettings.Builder#setSubscribeType(int)} and
+         * {@link SubscribeSettings#SUBSCRIBE_TYPE_ACTIVE}. Included in
+         * transmitted subscribe packets and used by receivers (passive
+         * publishers) to determine whether they match - in addition to just
+         * relying on the service name.
+         * <p>
+         * Format is an LV byte array - the {@link TlvBufferUtils} utility class
+         * is available to form and parse.
+         *
+         * @param txFilter The byte-array containing the LV formatted transmit
+         *            filter.
+         * @param txFilterLength The number of bytes in the transmit filter
+         *            argument.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setTxFilter(byte[] txFilter, int txFilterLength) {
+            mTxFilter = txFilter;
+            mTxFilterLength = txFilterLength;
+            return this;
+        }
+
+        /**
+         * The transmit filter for a passive subsribe session
+         * {@link SubscribeSettings.Builder#setSubscribeType(int)} and
+         * {@link SubscribeSettings#SUBSCRIBE_TYPE_PASSIVE}. Used by the
+         * subscriber to determine whether they match transmitted publish
+         * packets - in addition to just relying on the service name.
+         * <p>
+         * Format is an LV byte array - the {@link TlvBufferUtils} utility class
+         * is available to form and parse.
+         *
+         * @param rxFilter The byte-array containing the LV formatted receive
+         *            filter.
+         * @param rxFilterLength The number of bytes in the receive filter
+         *            argument.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setRxFilter(byte[] rxFilter, int rxFilterLength) {
+            mRxFilter = rxFilter;
+            mRxFilterLength = rxFilterLength;
+            return this;
+        }
+
+        /**
+         * Build {@link SubscribeData} given the current requests made on the
+         * builder.
+         */
+        public SubscribeData build() {
+            return new SubscribeData(mServiceName, mServiceSpecificInfo, mServiceSpecificInfoLength,
+                    mTxFilter, mTxFilterLength, mRxFilter, mRxFilterLength);
+        }
+    }
+}
diff --git a/wifi/java/android/net/wifi/nan/SubscribeSettings.aidl b/wifi/java/android/net/wifi/nan/SubscribeSettings.aidl
new file mode 100644
index 0000000..44849bc
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/SubscribeSettings.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.net.wifi.nan;
+
+parcelable SubscribeSettings;
diff --git a/wifi/java/android/net/wifi/nan/SubscribeSettings.java b/wifi/java/android/net/wifi/nan/SubscribeSettings.java
new file mode 100644
index 0000000..5c4f8fb
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/SubscribeSettings.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nan;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Defines the settings (configuration) for a NAN subscribe session. Built using
+ * {@link SubscribeSettings.Builder}. Subscribe is done using
+ * {@link WifiNanManager#subscribe(SubscribeData, SubscribeSettings, WifiNanSessionListener, int)}
+ * or {@link WifiNanSubscribeSession#subscribe(SubscribeData, SubscribeSettings)}.
+ *
+ * @hide PROPOSED_NAN_API
+ */
+public class SubscribeSettings implements Parcelable {
+
+    /**
+     * Defines a passive subscribe session - i.e. a subscribe session where
+     * subscribe packets are not transmitted over-the-air and the device listens
+     * and matches to transmitted publish packets. Configuration is done using
+     * {@link SubscribeSettings.Builder#setSubscribeType(int)}.
+     */
+    public static final int SUBSCRIBE_TYPE_PASSIVE = 0;
+
+    /**
+     * Defines an active subscribe session - i.e. a subscribe session where
+     * subscribe packets are transmitted over-the-air. Configuration is done
+     * using {@link SubscribeSettings.Builder#setSubscribeType(int)}.
+     */
+    public static final int SUBSCRIBE_TYPE_ACTIVE = 1;
+
+    /**
+     * @hide
+     */
+    public final int mSubscribeType;
+
+    /**
+     * @hide
+     */
+    public final int mSubscribeCount;
+
+    /**
+     * @hide
+     */
+    public final int mTtlSec;
+
+    private SubscribeSettings(int subscribeType, int publichCount, int ttlSec) {
+        mSubscribeType = subscribeType;
+        mSubscribeCount = publichCount;
+        mTtlSec = ttlSec;
+    }
+
+    @Override
+    public String toString() {
+        return "SubscribeSettings [mSubscribeType=" + mSubscribeType + ", mSubscribeCount="
+                + mSubscribeCount + ", mTtlSec=" + mTtlSec + "]";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mSubscribeType);
+        dest.writeInt(mSubscribeCount);
+        dest.writeInt(mTtlSec);
+    }
+
+    public static final Creator<SubscribeSettings> CREATOR = new Creator<SubscribeSettings>() {
+        @Override
+        public SubscribeSettings[] newArray(int size) {
+            return new SubscribeSettings[size];
+        }
+
+        @Override
+        public SubscribeSettings createFromParcel(Parcel in) {
+            int subscribeType = in.readInt();
+            int subscribeCount = in.readInt();
+            int ttlSec = in.readInt();
+            return new SubscribeSettings(subscribeType, subscribeCount, ttlSec);
+        }
+    };
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (!(o instanceof SubscribeSettings)) {
+            return false;
+        }
+
+        SubscribeSettings lhs = (SubscribeSettings) o;
+
+        return mSubscribeType == lhs.mSubscribeType && mSubscribeCount == lhs.mSubscribeCount
+                && mTtlSec == lhs.mTtlSec;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 17;
+
+        result = 31 * result + mSubscribeType;
+        result = 31 * result + mSubscribeCount;
+        result = 31 * result + mTtlSec;
+
+        return result;
+    }
+
+    /**
+     * Builder used to build {@link SubscribeSettings} objects.
+     */
+    public static final class Builder {
+        int mSubscribeType;
+        int mSubscribeCount;
+        int mTtlSec;
+
+        /**
+         * Sets the type of the subscribe session: active (subscribe packets are
+         * transmitted over-the-air), or passive (no subscribe packets are
+         * transmitted, a match is made against a solicited/active publish
+         * session whose packets are transmitted over-the-air).
+         *
+         * @param subscribeType Subscribe session type: active (
+         *            {@link SubscribeSettings#SUBSCRIBE_TYPE_ACTIVE}) or
+         *            passive ( {@link SubscribeSettings#SUBSCRIBE_TYPE_PASSIVE}
+         *            ).
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setSubscribeType(int subscribeType) {
+            if (subscribeType < SUBSCRIBE_TYPE_PASSIVE || subscribeType > SUBSCRIBE_TYPE_ACTIVE) {
+                throw new IllegalArgumentException("Invalid subscribeType - " + subscribeType);
+            }
+            mSubscribeType = subscribeType;
+            return this;
+        }
+
+        /**
+         * Sets the number of times an active (
+         * {@link SubscribeSettings.Builder#setSubscribeType(int)}) subscribe
+         * session will transmit a packet. When the count is reached an event
+         * will be generated for
+         * {@link WifiNanSessionListener#onSubscribeTerminated(int)} with reason=
+         * {@link WifiNanSessionListener#TERMINATE_REASON_DONE}.
+         *
+         * @param subscribeCount Number of subscribe packets to transmit.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setSubscribeCount(int subscribeCount) {
+            if (subscribeCount < 0) {
+                throw new IllegalArgumentException("Invalid subscribeCount - must be non-negative");
+            }
+            mSubscribeCount = subscribeCount;
+            return this;
+        }
+
+        /**
+         * Sets the time interval (in seconds) an active (
+         * {@link SubscribeSettings.Builder#setSubscribeType(int)}) subscribe
+         * session will be alive - i.e. transmitting a packet. When the TTL is
+         * reached an event will be generated for
+         * {@link WifiNanSessionListener#onSubscribeTerminated(int)} with reason=
+         * {@link WifiNanSessionListener#TERMINATE_REASON_DONE}.
+         *
+         * @param ttlSec Lifetime of a subscribe session in seconds.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setTtlSec(int ttlSec) {
+            if (ttlSec < 0) {
+                throw new IllegalArgumentException("Invalid ttlSec - must be non-negative");
+            }
+            mTtlSec = ttlSec;
+            return this;
+        }
+
+        /**
+         * Build {@link SubscribeSettings} given the current requests made on
+         * the builder.
+         */
+        public SubscribeSettings build() {
+            return new SubscribeSettings(mSubscribeType, mSubscribeCount, mTtlSec);
+        }
+    }
+}
diff --git a/wifi/java/android/net/wifi/nan/TlvBufferUtils.java b/wifi/java/android/net/wifi/nan/TlvBufferUtils.java
new file mode 100644
index 0000000..ea8785a
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/TlvBufferUtils.java
@@ -0,0 +1,490 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nan;
+
+import libcore.io.Memory;
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteOrder;
+import java.util.Iterator;
+
+/**
+ * Utility class to construct and parse byte arrays using the TLV format -
+ * Type/Length/Value format. The utilities accept a configuration of the size of
+ * the Type field and the Length field. A Type field size of 0 is allowed -
+ * allowing usage for LV (no T) array formats.
+ *
+ * @hide PROPOSED_NAN_API
+ */
+public class TlvBufferUtils {
+    private TlvBufferUtils() {
+        // no reason to ever create this class
+    }
+
+    /**
+     * Utility class to construct byte arrays using the TLV format -
+     * Type/Length/Value.
+     * <p>
+     * A constructor is created specifying the size of the Type (T) and Length
+     * (L) fields. A specification of zero size T field is allowed - resulting
+     * in LV type format.
+     * <p>
+     * The byte array is either provided (using
+     * {@link TlvConstructor#wrap(byte[])}) or allocated (using
+     * {@link TlvConstructor#allocate(int)}).
+     * <p>
+     * Values are added to the structure using the {@code TlvConstructor.put*()}
+     * methods.
+     * <p>
+     * The final byte array is obtained using {@link TlvConstructor#getArray()}
+     * and {@link TlvConstructor#getActualLength()} methods.
+     */
+    public static class TlvConstructor {
+        private int mTypeSize;
+        private int mLengthSize;
+
+        private byte[] mArray;
+        private int mArrayLength;
+        private int mPosition;
+
+        /**
+         * Define a TLV constructor with the specified size of the Type (T) and
+         * Length (L) fields.
+         *
+         * @param typeSize Number of bytes used for the Type (T) field. Values
+         *            of 0, 1, or 2 bytes are allowed. A specification of 0
+         *            bytes implies that the field being constructed has the LV
+         *            format rather than the TLV format.
+         * @param lengthSize Number of bytes used for the Length (L) field.
+         *            Values of 1 or 2 bytes are allowed.
+         */
+        public TlvConstructor(int typeSize, int lengthSize) {
+            if (typeSize < 0 || typeSize > 2 || lengthSize <= 0 || lengthSize > 2) {
+                throw new IllegalArgumentException(
+                        "Invalid sizes - typeSize=" + typeSize + ", lengthSize=" + lengthSize);
+            }
+            mTypeSize = typeSize;
+            mLengthSize = lengthSize;
+        }
+
+        /**
+         * Set the byte array to be used to construct the TLV.
+         *
+         * @param array Byte array to be formatted.
+         * @return The constructor to facilitate chaining
+         *         {@code ctr.putXXX(..).putXXX(..)}.
+         */
+        public TlvConstructor wrap(byte[] array) {
+            mArray = array;
+            mArrayLength = array.length;
+            return this;
+        }
+
+        /**
+         * Allocates a new byte array to be used ot construct a TLV.
+         *
+         * @param capacity The size of the byte array to be allocated.
+         * @return The constructor to facilitate chaining
+         *         {@code ctr.putXXX(..).putXXX(..)}.
+         */
+        public TlvConstructor allocate(int capacity) {
+            mArray = new byte[capacity];
+            mArrayLength = capacity;
+            return this;
+        }
+
+        /**
+         * Copies a byte into the TLV with the indicated type. For an LV
+         * formatted structure (i.e. typeLength=0 in {@link TlvConstructor
+         * TlvConstructor(int, int)} ) the type field is ignored.
+         *
+         * @param type The value to be placed into the Type field.
+         * @param b The byte to be inserted into the structure.
+         * @return The constructor to facilitate chaining
+         *         {@code ctr.putXXX(..).putXXX(..)}.
+         */
+        public TlvConstructor putByte(int type, byte b) {
+            checkLength(1);
+            addHeader(type, 1);
+            mArray[mPosition++] = b;
+            return this;
+        }
+
+        /**
+         * Copies a byte array into the TLV with the indicated type. For an LV
+         * formatted structure (i.e. typeLength=0 in {@link TlvConstructor
+         * TlvConstructor(int, int)} ) the type field is ignored.
+         *
+         * @param type The value to be placed into the Type field.
+         * @param array The array to be copied into the TLV structure.
+         * @param offset Start copying from the array at the specified offset.
+         * @param length Copy the specified number (length) of bytes from the
+         *            array.
+         * @return The constructor to facilitate chaining
+         *         {@code ctr.putXXX(..).putXXX(..)}.
+         */
+        public TlvConstructor putByteArray(int type, byte[] array, int offset, int length) {
+            checkLength(length);
+            addHeader(type, length);
+            System.arraycopy(array, offset, mArray, mPosition, length);
+            mPosition += length;
+            return this;
+        }
+
+        /**
+         * Copies a byte array into the TLV with the indicated type. For an LV
+         * formatted structure (i.e. typeLength=0 in {@link TlvConstructor
+         * TlvConstructor(int, int)} ) the type field is ignored.
+         *
+         * @param type The value to be placed into the Type field.
+         * @param array The array to be copied (in full) into the TLV structure.
+         * @return The constructor to facilitate chaining
+         *         {@code ctr.putXXX(..).putXXX(..)}.
+         */
+        public TlvConstructor putByteArray(int type, byte[] array) {
+            return putByteArray(type, array, 0, array.length);
+        }
+
+        /**
+         * Places a zero length element (i.e. Length field = 0) into the TLV.
+         * For an LV formatted structure (i.e. typeLength=0 in
+         * {@link TlvConstructor TlvConstructor(int, int)} ) the type field is
+         * ignored.
+         *
+         * @param type The value to be placed into the Type field.
+         * @return The constructor to facilitate chaining
+         *         {@code ctr.putXXX(..).putXXX(..)}.
+         */
+        public TlvConstructor putZeroLengthElement(int type) {
+            checkLength(0);
+            addHeader(type, 0);
+            return this;
+        }
+
+        /**
+         * Copies short into the TLV with the indicated type. For an LV
+         * formatted structure (i.e. typeLength=0 in {@link TlvConstructor
+         * TlvConstructor(int, int)} ) the type field is ignored.
+         *
+         * @param type The value to be placed into the Type field.
+         * @param data The short to be inserted into the structure.
+         * @return The constructor to facilitate chaining
+         *         {@code ctr.putXXX(..).putXXX(..)}.
+         */
+        public TlvConstructor putShort(int type, short data) {
+            checkLength(2);
+            addHeader(type, 2);
+            Memory.pokeShort(mArray, mPosition, data, ByteOrder.BIG_ENDIAN);
+            mPosition += 2;
+            return this;
+        }
+
+        /**
+         * Copies integer into the TLV with the indicated type. For an LV
+         * formatted structure (i.e. typeLength=0 in {@link TlvConstructor
+         * TlvConstructor(int, int)} ) the type field is ignored.
+         *
+         * @param type The value to be placed into the Type field.
+         * @param data The integer to be inserted into the structure.
+         * @return The constructor to facilitate chaining
+         *         {@code ctr.putXXX(..).putXXX(..)}.
+         */
+        public TlvConstructor putInt(int type, int data) {
+            checkLength(4);
+            addHeader(type, 4);
+            Memory.pokeInt(mArray, mPosition, data, ByteOrder.BIG_ENDIAN);
+            mPosition += 4;
+            return this;
+        }
+
+        /**
+         * Copies a String's byte representation into the TLV with the indicated
+         * type. For an LV formatted structure (i.e. typeLength=0 in
+         * {@link TlvConstructor TlvConstructor(int, int)} ) the type field is
+         * ignored.
+         *
+         * @param type The value to be placed into the Type field.
+         * @param data The string whose bytes are to be inserted into the
+         *            structure.
+         * @return The constructor to facilitate chaining
+         *         {@code ctr.putXXX(..).putXXX(..)}.
+         */
+        public TlvConstructor putString(int type, String data) {
+            return putByteArray(type, data.getBytes(), 0, data.length());
+        }
+
+        /**
+         * Returns the constructed TLV formatted byte-array. Note that the
+         * returned array is the fully wrapped (
+         * {@link TlvConstructor#wrap(byte[])}) or allocated (
+         * {@link TlvConstructor#allocate(int)}) array - which isn't necessarily
+         * the actual size of the formatted data. Use
+         * {@link TlvConstructor#getActualLength()} to obtain the size of the
+         * formatted data.
+         *
+         * @return The byte array containing the TLV formatted structure.
+         */
+        public byte[] getArray() {
+            return mArray;
+        }
+
+        /**
+         * Returns the size of the TLV formatted portion of the wrapped or
+         * allocated byte array. The array itself is returned with
+         * {@link TlvConstructor#getArray()}.
+         *
+         * @return The size of the TLV formatted portion of the byte array.
+         */
+        public int getActualLength() {
+            return mPosition;
+        }
+
+        private void checkLength(int dataLength) {
+            if (mPosition + mTypeSize + mLengthSize + dataLength > mArrayLength) {
+                throw new BufferOverflowException();
+            }
+        }
+
+        private void addHeader(int type, int length) {
+            if (mTypeSize == 1) {
+                mArray[mPosition] = (byte) type;
+            } else if (mTypeSize == 2) {
+                Memory.pokeShort(mArray, mPosition, (short) type, ByteOrder.BIG_ENDIAN);
+            }
+            mPosition += mTypeSize;
+
+            if (mLengthSize == 1) {
+                mArray[mPosition] = (byte) length;
+            } else if (mLengthSize == 2) {
+                Memory.pokeShort(mArray, mPosition, (short) length, ByteOrder.BIG_ENDIAN);
+            }
+            mPosition += mLengthSize;
+        }
+    }
+
+    /**
+     * Utility class used when iterating over a TLV formatted byte-array. Use
+     * {@link TlvIterable} to iterate over array. A {@link TlvElement}
+     * represents each entry in a TLV formatted byte-array.
+     */
+    public static class TlvElement {
+        /**
+         * The Type (T) field of the current TLV element. Note that for LV
+         * formatted byte-arrays (i.e. TLV whose Type/T size is 0) the value of
+         * this field is undefined.
+         */
+        public int mType;
+
+        /**
+         * The Length (L) field of the current TLV element.
+         */
+        public int mLength;
+
+        /**
+         * The Value (V) field - a raw byte array representing the current TLV
+         * element where the entry starts at {@link TlvElement#mOffset}.
+         */
+        public byte[] mRefArray;
+
+        /**
+         * The offset to be used into {@link TlvElement#mRefArray} to access the
+         * raw data representing the current TLV element.
+         */
+        public int mOffset;
+
+        private TlvElement(int type, int length, byte[] refArray, int offset) {
+            mType = type;
+            mLength = length;
+            mRefArray = refArray;
+            mOffset = offset;
+        }
+
+        /**
+         * Utility function to return a byte representation of a TLV element of
+         * length 1. Note: an attempt to call this function on a TLV item whose
+         * {@link TlvElement#mLength} is != 1 will result in an exception.
+         *
+         * @return byte representation of current TLV element.
+         */
+        public byte getByte() {
+            if (mLength != 1) {
+                throw new IllegalArgumentException(
+                        "Accesing a byte from a TLV element of length " + mLength);
+            }
+            return mRefArray[mOffset];
+        }
+
+        /**
+         * Utility function to return a short representation of a TLV element of
+         * length 2. Note: an attempt to call this function on a TLV item whose
+         * {@link TlvElement#mLength} is != 2 will result in an exception.
+         *
+         * @return short representation of current TLV element.
+         */
+        public short getShort() {
+            if (mLength != 2) {
+                throw new IllegalArgumentException(
+                        "Accesing a short from a TLV element of length " + mLength);
+            }
+            return Memory.peekShort(mRefArray, mOffset, ByteOrder.BIG_ENDIAN);
+        }
+
+        /**
+         * Utility function to return an integer representation of a TLV element
+         * of length 4. Note: an attempt to call this function on a TLV item
+         * whose {@link TlvElement#mLength} is != 4 will result in an exception.
+         *
+         * @return integer representation of current TLV element.
+         */
+        public int getInt() {
+            if (mLength != 4) {
+                throw new IllegalArgumentException(
+                        "Accesing an int from a TLV element of length " + mLength);
+            }
+            return Memory.peekInt(mRefArray, mOffset, ByteOrder.BIG_ENDIAN);
+        }
+
+        /**
+         * Utility function to return a String representation of a TLV element.
+         *
+         * @return String repersentation of the current TLV element.
+         */
+        public String getString() {
+            return new String(mRefArray, mOffset, mLength);
+        }
+    }
+
+    /**
+     * Utility class to iterate over a TLV formatted byte-array.
+     */
+    public static class TlvIterable implements Iterable<TlvElement> {
+        private int mTypeSize;
+        private int mLengthSize;
+        private byte[] mArray;
+        private int mArrayLength;
+
+        /**
+         * Constructs a TlvIterable object - specifying the format of the TLV
+         * (the sizes of the Type and Length fields), and the byte array whose
+         * data is to be parsed.
+         *
+         * @param typeSize Number of bytes used for the Type (T) field. Valid
+         *            values are 0 (i.e. indicating the format is LV rather than
+         *            TLV), 1, and 2 bytes.
+         * @param lengthSize Number of bytes sued for the Length (L) field.
+         *            Values values are 1 or 2 bytes.
+         * @param array The TLV formatted byte-array to parse.
+         * @param length The number of bytes of the array to be used in the
+         *            parsing.
+         */
+        public TlvIterable(int typeSize, int lengthSize, byte[] array, int length) {
+            if (typeSize < 0 || typeSize > 2 || lengthSize <= 0 || lengthSize > 2) {
+                throw new IllegalArgumentException(
+                        "Invalid sizes - typeSize=" + typeSize + ", lengthSize=" + lengthSize);
+            }
+            mTypeSize = typeSize;
+            mLengthSize = lengthSize;
+            mArray = array;
+            mArrayLength = length;
+        }
+
+        /**
+         * Prints out a parsed representation of the TLV-formatted byte array.
+         * Whenever possible bytes, shorts, and integer are printed out (for
+         * fields whose length is 1, 2, or 4 respectively).
+         */
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+
+            builder.append("[");
+            boolean first = true;
+            for (TlvElement tlv : this) {
+                if (!first) {
+                    builder.append(",");
+                }
+                first = false;
+                builder.append(" (");
+                if (mTypeSize != 0) {
+                    builder.append("T=" + tlv.mType + ",");
+                }
+                builder.append("L=" + tlv.mLength + ") ");
+                if (tlv.mLength == 0) {
+                    builder.append("<null>");
+                } else if (tlv.mLength == 1) {
+                    builder.append(tlv.getByte());
+                } else if (tlv.mLength == 2) {
+                    builder.append(tlv.getShort());
+                } else if (tlv.mLength == 4) {
+                    builder.append(tlv.getInt());
+                } else {
+                    builder.append("<bytes>");
+                }
+                if (tlv.mLength != 0) {
+                    builder.append(" (S='" + tlv.getString() + "')");
+                }
+            }
+            builder.append("]");
+
+            return builder.toString();
+        }
+
+        /**
+         * Returns an iterator to step through a TLV formatted byte-array. The
+         * individual elements returned by the iterator are {@link TlvElement}.
+         */
+        @Override
+        public Iterator<TlvElement> iterator() {
+            return new Iterator<TlvElement>() {
+                private int mOffset = 0;
+
+                @Override
+                public boolean hasNext() {
+                    return mOffset < mArrayLength;
+                }
+
+                @Override
+                public TlvElement next() {
+                    int type = 0;
+                    if (mTypeSize == 1) {
+                        type = mArray[mOffset];
+                    } else if (mTypeSize == 2) {
+                        type = Memory.peekShort(mArray, mOffset, ByteOrder.BIG_ENDIAN);
+                    }
+                    mOffset += mTypeSize;
+
+                    int length = 0;
+                    if (mLengthSize == 1) {
+                        length = mArray[mOffset];
+                    } else if (mLengthSize == 2) {
+                        length = Memory.peekShort(mArray, mOffset, ByteOrder.BIG_ENDIAN);
+                    }
+                    mOffset += mLengthSize;
+
+                    TlvElement tlv = new TlvElement(type, length, mArray, mOffset);
+                    mOffset += length;
+                    return tlv;
+                }
+
+                @Override
+                public void remove() {
+                    throw new UnsupportedOperationException();
+                }
+            };
+        }
+    }
+}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanEventListener.java b/wifi/java/android/net/wifi/nan/WifiNanEventListener.java
new file mode 100644
index 0000000..eae0a55
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/WifiNanEventListener.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nan;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+
+/**
+ * Base class for NAN events callbacks. Should be extended by applications
+ * wanting notifications. These are callbacks applying to the NAN connection as
+ * a whole - not to specific publish or subscribe sessions - for that see
+ * {@link WifiNanSessionListener}.
+ * <p>
+ * During registration specify which specific events are desired using a set of
+ * {@code NanEventListener.LISTEN_*} flags OR'd together. Only those events will
+ * be delivered to the registered listener. Override those callbacks
+ * {@code NanEventListener.on*} for the registered events.
+ *
+ * @hide PROPOSED_NAN_API
+ */
+public class WifiNanEventListener {
+    private static final String TAG = "WifiNanEventListener";
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false; // STOPSHIP if true
+
+    /**
+     * Configuration completion callback event registration flag. Corresponding
+     * callback is {@link WifiNanEventListener#onConfigCompleted(ConfigRequest)}.
+     */
+    public static final int LISTEN_CONFIG_COMPLETED = 0x1 << 0;
+
+    /**
+     * Configuration failed callback event registration flag. Corresponding
+     * callback is {@link WifiNanEventListener#onConfigFailed(int)}.
+     */
+    public static final int LISTEN_CONFIG_FAILED = 0x1 << 1;
+
+    /**
+     * NAN cluster is down callback event registration flag. Corresponding
+     * callback is {@link WifiNanEventListener#onNanDown(int)}.
+     */
+    public static final int LISTEN_NAN_DOWN = 0x1 << 2;
+
+    /**
+     * NAN identity has changed event registration flag. This may be due to
+     * joining a cluster, starting a cluster, or discovery interface change. The
+     * implication is that peers you've been communicating with may no longer
+     * recognize you and you need to re-establish your identity. Corresponding
+     * callback is {@link WifiNanEventListener#onIdentityChanged()}.
+     */
+    public static final int LISTEN_IDENTITY_CHANGED = 0x1 << 3;
+
+    private final Handler mHandler;
+
+    /**
+     * Constructs a {@link WifiNanEventListener} using the looper of the current
+     * thread. I.e. all callbacks will be delivered on the current thread.
+     */
+    public WifiNanEventListener() {
+        this(Looper.myLooper());
+    }
+
+    /**
+     * Constructs a {@link WifiNanEventListener} using the specified looper. I.e.
+     * all callbacks will delivered on the thread of the specified looper.
+     *
+     * @param looper The looper on which to execute the callbacks.
+     */
+    public WifiNanEventListener(Looper looper) {
+        if (VDBG) Log.v(TAG, "ctor: looper=" + looper);
+        mHandler = new Handler(looper) {
+            @Override
+            public void handleMessage(Message msg) {
+                if (DBG) Log.d(TAG, "What=" + msg.what + ", msg=" + msg);
+                switch (msg.what) {
+                    case LISTEN_CONFIG_COMPLETED:
+                        WifiNanEventListener.this.onConfigCompleted((ConfigRequest) msg.obj);
+                        break;
+                    case LISTEN_CONFIG_FAILED:
+                        WifiNanEventListener.this.onConfigFailed(msg.arg1);
+                        break;
+                    case LISTEN_NAN_DOWN:
+                        WifiNanEventListener.this.onNanDown(msg.arg1);
+                        break;
+                    case LISTEN_IDENTITY_CHANGED:
+                        WifiNanEventListener.this.onIdentityChanged();
+                        break;
+                }
+            }
+        };
+    }
+
+    /**
+     * Called when NAN configuration is completed. Event will only be delivered
+     * if registered using {@link WifiNanEventListener#LISTEN_CONFIG_COMPLETED}. A
+     * dummy (empty implementation printing out a warning). Make sure to
+     * override if registered.
+     *
+     * @param completedConfig The actual configuration request which was
+     *            completed. Note that it may be different from that requested
+     *            by the application. The service combines configuration
+     *            requests from all applications.
+     */
+    public void onConfigCompleted(ConfigRequest completedConfig) {
+        Log.w(TAG, "onConfigCompleted: called in stub - override if interested or disable");
+    }
+
+    /**
+     * Called when NAN configuration failed. Event will only be delivered if
+     * registered using {@link WifiNanEventListener#LISTEN_CONFIG_FAILED}. A dummy
+     * (empty implementation printing out a warning). Make sure to override if
+     * registered.
+     *
+     * @param reason Failure reason code, see {@code NanSessionListener.FAIL_*}.
+     */
+    public void onConfigFailed(int reason) {
+        Log.w(TAG, "onConfigFailed: called in stub - override if interested or disable");
+    }
+
+    /**
+     * Called when NAN cluster is down. Event will only be delivered if
+     * registered using {@link WifiNanEventListener#LISTEN_NAN_DOWN}. A dummy (empty
+     * implementation printing out a warning). Make sure to override if
+     * registered.
+     *
+     * @param reason Reason code for event, see {@code NanSessionListener.FAIL_*}.
+     */
+    public void onNanDown(int reason) {
+        Log.w(TAG, "onNanDown: called in stub - override if interested or disable");
+    }
+
+    /**
+     * Called when NAN identity has changed. This may be due to joining a
+     * cluster, starting a cluster, or discovery interface change. The
+     * implication is that peers you've been communicating with may no longer
+     * recognize you and you need to re-establish your identity. Event will only
+     * be delivered if registered using
+     * {@link WifiNanEventListener#LISTEN_IDENTITY_CHANGED}. A dummy (empty
+     * implementation printing out a warning). Make sure to override if
+     * registered.
+     */
+    public void onIdentityChanged() {
+        if (VDBG) Log.v(TAG, "onIdentityChanged: called in stub - override if interested");
+    }
+
+    /**
+     * {@hide}
+     */
+    public IWifiNanEventListener callback = new IWifiNanEventListener.Stub() {
+        @Override
+        public void onConfigCompleted(ConfigRequest completedConfig) {
+            if (VDBG) Log.v(TAG, "onConfigCompleted: configRequest=" + completedConfig);
+
+            Message msg = mHandler.obtainMessage(LISTEN_CONFIG_COMPLETED);
+            msg.obj = completedConfig;
+            mHandler.sendMessage(msg);
+        }
+
+        @Override
+        public void onConfigFailed(int reason) {
+            if (VDBG) Log.v(TAG, "onConfigFailed: reason=" + reason);
+
+            Message msg = mHandler.obtainMessage(LISTEN_CONFIG_FAILED);
+            msg.arg1 = reason;
+            mHandler.sendMessage(msg);
+        }
+
+        @Override
+        public void onNanDown(int reason) {
+            if (VDBG) Log.v(TAG, "onNanDown: reason=" + reason);
+
+            Message msg = mHandler.obtainMessage(LISTEN_NAN_DOWN);
+            msg.arg1 = reason;
+            mHandler.sendMessage(msg);
+        }
+
+        @Override
+        public void onIdentityChanged() {
+            if (VDBG) Log.v(TAG, "onIdentityChanged");
+
+            Message msg = mHandler.obtainMessage(LISTEN_IDENTITY_CHANGED);
+            mHandler.sendMessage(msg);
+        }
+    };
+}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanManager.java b/wifi/java/android/net/wifi/nan/WifiNanManager.java
new file mode 100644
index 0000000..cb82268
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nan;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * This class provides the primary API for managing Wi-Fi NAN operation:
+ * including discovery and data-links. Get an instance of this class by calling
+ * {@link android.content.Context#getSystemService(String)
+ * Context.getSystemService(Context.WIFI_NAN_SERVICE)}.
+ * <p>
+ * The class provides access to:
+ * <ul>
+ * <li>Configure a NAN connection and register for events.
+ * <li>Create publish and subscribe sessions.
+ * <li>Create NAN network specifier to be used to create a NAN network.
+ * </ul>
+ *
+ * @hide PROPOSED_NAN_API
+ */
+public class WifiNanManager {
+    private static final String TAG = "WifiNanManager";
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false; // STOPSHIP if true
+
+    private IBinder mBinder;
+
+    private IWifiNanManager mService;
+
+    /**
+     * {@hide}
+     */
+    public WifiNanManager(IWifiNanManager service) {
+        mService = service;
+    }
+
+    /**
+     * Re-connect to the Wi-Fi NAN service - enabling the application to execute
+     * {@link WifiNanManager} APIs. Application don't normally need to call this
+     * API since it is executed in the constructor. However, applications which
+     * have explicitly {@link WifiNanManager#disconnect()} need to call this
+     * function to re-connect.
+     *
+     * @param listener A listener extended from {@link WifiNanEventListener}.
+     * @param events The set of events to be delivered to the {@code listener}.
+     *            OR'd event flags from {@link WifiNanEventListener
+     *            NanEventListener.LISTEN*}.
+     */
+    public void connect(WifiNanEventListener listener, int events) {
+        try {
+            if (VDBG) Log.v(TAG, "connect()");
+            if (listener == null) {
+                throw new IllegalArgumentException("Invalid listener - must not be null");
+            }
+            if (mBinder == null) {
+                mBinder = new Binder();
+            }
+            mService.connect(mBinder, listener.callback, events);
+        } catch (RemoteException e) {
+            Log.w(TAG, "connect RemoteException (FYI - ignoring): " + e);
+        }
+    }
+
+    /**
+     * Disconnect from the Wi-Fi NAN service and destroy all outstanding
+     * operations - i.e. all publish and subscribes are terminated, any
+     * outstanding data-link is shut-down, and all requested NAN configurations
+     * are cancelled.
+     * <p>
+     * An application may then re-connect using
+     * {@link WifiNanManager#connect(WifiNanEventListener, int)} .
+     */
+    public void disconnect() {
+        try {
+            if (VDBG) Log.v(TAG, "disconnect()");
+            mService.disconnect(mBinder);
+            mBinder = null;
+        } catch (RemoteException e) {
+            Log.w(TAG, "disconnect RemoteException (FYI - ignoring): " + e);
+        }
+    }
+
+    /**
+     * Requests a NAN configuration, specified by {@link ConfigRequest}. Note
+     * that NAN is a shared resource and the device can only be a member of a
+     * single cluster. Thus the service may merge configuration requests from
+     * multiple applications and configure NAN differently from individual
+     * requests.
+     * <p>
+     * The {@link WifiNanEventListener#onConfigCompleted(ConfigRequest)} will be
+     * called when configuration is completed (if a listener is registered for
+     * this specific event).
+     *
+     * @param configRequest The requested NAN configuration.
+     */
+    public void requestConfig(ConfigRequest configRequest) {
+        if (VDBG) Log.v(TAG, "requestConfig(): configRequest=" + configRequest);
+        try {
+            mService.requestConfig(configRequest);
+        } catch (RemoteException e) {
+            Log.w(TAG, "requestConfig RemoteException (FYI - ignoring): " + e);
+        }
+    }
+
+    /**
+     * Request a NAN publish session. The results of the publish session
+     * operation will result in callbacks to the indicated listener:
+     * {@link WifiNanSessionListener NanSessionListener.on*}.
+     *
+     * @param publishData The {@link PublishData} specifying the contents of the
+     *            publish session.
+     * @param publishSettings The {@link PublishSettings} specifying the
+     *            settings for the publish session.
+     * @param listener The {@link WifiNanSessionListener} derived objects to be used
+     *            for the event callbacks specified by {@code events}.
+     * @param events The list of events to be delivered to the {@code listener}
+     *            object. An OR'd value of {@link WifiNanSessionListener
+     *            NanSessionListener.LISTEN_*}.
+     * @return The {@link WifiNanPublishSession} which can be used to further
+     *         control the publish session.
+     */
+    public WifiNanPublishSession publish(PublishData publishData, PublishSettings publishSettings,
+            WifiNanSessionListener listener, int events) {
+        return publishRaw(publishData, publishSettings, listener,
+                events | WifiNanSessionListener.LISTEN_HIDDEN_FLAGS);
+    }
+
+    /**
+     * Same as publish(*) but does not modify the event flag
+     *
+     * @hide
+     */
+    public WifiNanPublishSession publishRaw(PublishData publishData,
+            PublishSettings publishSettings, WifiNanSessionListener listener, int events) {
+        if (VDBG) Log.v(TAG, "publish(): data='" + publishData + "', settings=" + publishSettings);
+
+        if (publishSettings.mPublishType == PublishSettings.PUBLISH_TYPE_UNSOLICITED
+                && publishData.mRxFilterLength != 0) {
+            throw new IllegalArgumentException("Invalid publish data & settings: UNSOLICITED "
+                    + "publishes (active) can't have an Rx filter");
+        }
+        if (publishSettings.mPublishType == PublishSettings.PUBLISH_TYPE_SOLICITED
+                && publishData.mTxFilterLength != 0) {
+            throw new IllegalArgumentException("Invalid publish data & settings: SOLICITED "
+                    + "publishes (passive) can't have a Tx filter");
+        }
+        if (listener == null) {
+            throw new IllegalArgumentException("Invalid listener - must not be null");
+        }
+
+        int sessionId;
+
+        try {
+            sessionId = mService.createSession(listener.callback, events);
+            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;
+        }
+
+        return new WifiNanPublishSession(this, sessionId);
+    }
+
+    /**
+     * {@hide}
+     */
+    public void publish(int sessionId, PublishData publishData, PublishSettings publishSettings) {
+        if (VDBG) Log.v(TAG, "publish(): data='" + publishData + "', settings=" + publishSettings);
+
+        if (publishSettings.mPublishType == PublishSettings.PUBLISH_TYPE_UNSOLICITED
+                && publishData.mRxFilterLength != 0) {
+            throw new IllegalArgumentException("Invalid publish data & settings: UNSOLICITED "
+                    + "publishes (active) can't have an Rx filter");
+        }
+        if (publishSettings.mPublishType == PublishSettings.PUBLISH_TYPE_SOLICITED
+                && publishData.mTxFilterLength != 0) {
+            throw new IllegalArgumentException("Invalid publish data & settings: SOLICITED "
+                    + "publishes (passive) can't have a Tx filter");
+        }
+
+        try {
+            mService.publish(sessionId, publishData, publishSettings);
+        } catch (RemoteException e) {
+            Log.w(TAG, "publish RemoteException: " + e);
+        }
+    }
+    /**
+     * Request a NAN subscribe session. The results of the subscribe session
+     * operation will result in callbacks to the indicated listener:
+     * {@link WifiNanSessionListener NanSessionListener.on*}.
+     *
+     * @param subscribeData The {@link SubscribeData} specifying the contents of
+     *            the subscribe session.
+     * @param subscribeSettings The {@link SubscribeSettings} specifying the
+     *            settings for the subscribe session.
+     * @param listener The {@link WifiNanSessionListener} derived objects to be used
+     *            for the event callbacks specified by {@code events}.
+     * @param events The list of events to be delivered to the {@code listener}
+     *            object. An OR'd value of {@link WifiNanSessionListener
+     *            NanSessionListener.LISTEN_*}.
+     * @return The {@link WifiNanSubscribeSession} which can be used to further
+     *         control the subscribe session.
+     */
+    public WifiNanSubscribeSession subscribe(SubscribeData subscribeData,
+            SubscribeSettings subscribeSettings,
+            WifiNanSessionListener listener, int events) {
+        return subscribeRaw(subscribeData, subscribeSettings, listener,
+                events | WifiNanSessionListener.LISTEN_HIDDEN_FLAGS);
+    }
+
+    /**
+     * Same as subscribe(*) but does not modify the event flag
+     *
+     * @hide
+     */
+    public WifiNanSubscribeSession subscribeRaw(SubscribeData subscribeData,
+            SubscribeSettings subscribeSettings, WifiNanSessionListener listener, int events) {
+        if (VDBG) {
+            Log.v(TAG, "subscribe(): data='" + subscribeData + "', settings=" + subscribeSettings);
+        }
+
+        if (subscribeSettings.mSubscribeType == SubscribeSettings.SUBSCRIBE_TYPE_ACTIVE
+                && subscribeData.mRxFilterLength != 0) {
+            throw new IllegalArgumentException(
+                    "Invalid subscribe data & settings: ACTIVE subscribes can't have an Rx filter");
+        }
+        if (subscribeSettings.mSubscribeType == SubscribeSettings.SUBSCRIBE_TYPE_PASSIVE
+                && subscribeData.mTxFilterLength != 0) {
+            throw new IllegalArgumentException(
+                    "Invalid subscribe data & settings: PASSIVE subscribes can't have a Tx filter");
+        }
+
+        int sessionId;
+
+        try {
+            sessionId = mService.createSession(listener.callback, events);
+            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;
+        }
+
+        return new WifiNanSubscribeSession(this, sessionId);
+    }
+
+    /**
+     * {@hide}
+     */
+    public void subscribe(int sessionId, SubscribeData subscribeData,
+            SubscribeSettings subscribeSettings) {
+        if (VDBG) {
+            Log.v(TAG, "subscribe(): data='" + subscribeData + "', settings=" + subscribeSettings);
+        }
+
+        if (subscribeSettings.mSubscribeType == SubscribeSettings.SUBSCRIBE_TYPE_ACTIVE
+                && subscribeData.mRxFilterLength != 0) {
+            throw new IllegalArgumentException(
+                    "Invalid subscribe data & settings: ACTIVE subscribes can't have an Rx filter");
+        }
+        if (subscribeSettings.mSubscribeType == SubscribeSettings.SUBSCRIBE_TYPE_PASSIVE
+                && subscribeData.mTxFilterLength != 0) {
+            throw new IllegalArgumentException(
+                    "Invalid subscribe data & settings: PASSIVE subscribes can't have a Tx filter");
+        }
+
+        try {
+            mService.subscribe(sessionId, subscribeData, subscribeSettings);
+        } catch (RemoteException e) {
+            Log.w(TAG, "subscribe RemoteException: " + e);
+        }
+    }
+
+    /**
+     * {@hide}
+     */
+    public void stopSession(int sessionId) {
+        if (DBG) Log.d(TAG, "Stop NAN session #" + sessionId);
+
+        try {
+            mService.stopSession(sessionId);
+        } catch (RemoteException e) {
+            Log.w(TAG, "stopSession RemoteException (FYI - ignoring): " + e);
+        }
+    }
+
+    /**
+     * {@hide}
+     */
+    public void destroySession(int sessionId) {
+        if (DBG) Log.d(TAG, "Destroy NAN session #" + sessionId);
+
+        try {
+            mService.destroySession(sessionId);
+        } catch (RemoteException e) {
+            Log.w(TAG, "destroySession RemoteException (FYI - ignoring): " + e);
+        }
+    }
+
+    /**
+     * {@hide}
+     */
+    public void sendMessage(int sessionId, int peerId, byte[] message, int messageLength,
+            int messageId) {
+        try {
+            if (VDBG) {
+                Log.v(TAG, "sendMessage(): sessionId=" + sessionId + ", peerId=" + peerId
+                        + ", messageLength=" + messageLength + ", messageId=" + messageId);
+            }
+            mService.sendMessage(sessionId, peerId, message, messageLength, messageId);
+        } catch (RemoteException e) {
+            Log.w(TAG, "subscribe RemoteException (FYI - ignoring): " + e);
+        }
+    }
+}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java b/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java
new file mode 100644
index 0000000..81b38f4
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nan;
+
+/**
+ * A representation of a NAN publish session. Created when
+ * {@link WifiNanManager#publish(PublishData, PublishSettings, WifiNanSessionListener, int)}
+ * is executed. The object can be used to stop and re-start (re-configure) the
+ * publish session.
+ *
+ * @hide PROPOSED_NAN_API
+ */
+public class WifiNanPublishSession extends WifiNanSession {
+    /**
+     * {@hide}
+     */
+    public WifiNanPublishSession(WifiNanManager manager, int sessionId) {
+        super(manager, sessionId);
+    }
+
+    /**
+     * Restart/re-configure the publish session. Note that the
+     * {@link WifiNanSessionListener} is not replaced - the same listener used at
+     * creation is still used.
+     *
+     * @param publishData The data ({@link PublishData}) to publish.
+     * @param publishSettings The settings ({@link PublishSettings}) of the
+     *            publish session.
+     */
+    public void publish(PublishData publishData, PublishSettings publishSettings) {
+        mManager.publish(mSessionId, publishData, publishSettings);
+    }
+}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSession.java b/wifi/java/android/net/wifi/nan/WifiNanSession.java
new file mode 100644
index 0000000..d0a9410
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/WifiNanSession.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 android.net.wifi.nan;
+
+import android.util.Log;
+
+/**
+ * A representation of a single publish or subscribe NAN session. This object
+ * will not be created directly - only its child classes are available:
+ * {@link WifiNanPublishSession} and {@link WifiNanSubscribeSession}.
+ *
+ * @hide PROPOSED_NAN_API
+ */
+public class WifiNanSession {
+    private static final String TAG = "WifiNanSession";
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false; // STOPSHIP if true
+
+    /**
+     * {@hide}
+     */
+    protected WifiNanManager mManager;
+
+    /**
+     * {@hide}
+     */
+    protected int mSessionId;
+
+    /**
+     * {@hide}
+     */
+    private boolean mDestroyed;
+
+    /**
+     * {@hide}
+     */
+    public WifiNanSession(WifiNanManager manager, int sessionId) {
+        if (VDBG) Log.v(TAG, "New client created: manager=" + manager + ", sessionId=" + sessionId);
+
+        mManager = manager;
+        mSessionId = sessionId;
+        mDestroyed = false;
+    }
+
+    /**
+     * Terminate the current publish or subscribe session - i.e. stop
+     * transmitting packet on-air (for an active session) or listening for
+     * matches (for a passive session). Note that the session may still receive
+     * incoming messages and may be re-configured/re-started at a later time.
+     */
+    public void stop() {
+        mManager.stopSession(mSessionId);
+    }
+
+    /**
+     * Destroy the current publish or subscribe session. Performs a
+     * {@link WifiNanSession#stop()} function but in addition destroys the session -
+     * it will not be able to receive any messages or to be restarted at a later
+     * time.
+     */
+    public void destroy() {
+        mManager.destroySession(mSessionId);
+        mDestroyed = true;
+    }
+
+    /**
+     * {@hide}
+     */
+    @Override
+    protected void finalize() throws Throwable {
+        if (!mDestroyed) {
+            Log.w(TAG, "WifiNanSession mSessionId=" + mSessionId
+                            + " was not explicitly destroyed. The session may use resources until "
+                            + "destroyed so step should be done explicitly");
+        }
+        destroy();
+    }
+
+    /**
+     * Sends a message to the specified destination. Message transmission is
+     * part of the current discovery session - i.e. executed subsequent to a
+     * publish/subscribe
+     * {@link WifiNanSessionListener#onMatch(int, byte[], int, byte[], int)}
+     * event.
+     *
+     * @param peerId The peer's ID for the message. Must be a result of an
+     *            {@link WifiNanSessionListener#onMatch(int, byte[], int, byte[], int)}
+     *            event.
+     * @param message The message to be transmitted.
+     * @param messageLength The number of bytes from the {@code message} to be
+     *            transmitted.
+     * @param messageId An arbitrary integer used by the caller to identify the
+     *            message. The same integer ID will be returned in the callbacks
+     *            indicated message send success or failure.
+     */
+    public void sendMessage(int peerId, byte[] message, int messageLength, int messageId) {
+        mManager.sendMessage(mSessionId, peerId, message, messageLength, messageId);
+    }
+}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java b/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
new file mode 100644
index 0000000..d5e59f0
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nan;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+
+/**
+ * Base class for NAN session events callbacks. Should be extended by
+ * applications wanting notifications. The callbacks are registered when a
+ * publish or subscribe session is created using
+ * {@link WifiNanManager#publish(PublishData, PublishSettings, WifiNanSessionListener, int)}
+ * or
+ * {@link WifiNanManager#subscribe(SubscribeData, SubscribeSettings, WifiNanSessionListener, int)}
+ * . These are callbacks applying to a specific NAN session. Events
+ * corresponding to the NAN link are delivered using {@link WifiNanEventListener}.
+ * <p>
+ * A single listener is registered at session creation - it cannot be replaced.
+ * <p>
+ * During registration specify which specific events are desired using a set of
+ * {@code NanSessionListener.LISTEN_*} flags OR'd together. Only those events
+ * will be delivered to the registered listener. Override those callbacks
+ * {@code NanSessionListener.on*} for the registered events.
+ *
+ * @hide PROPOSED_NAN_API
+ */
+public class WifiNanSessionListener {
+    private static final String TAG = "WifiNanSessionListener";
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false; // STOPSHIP if true
+
+    /**
+     * Publish fail callback event registration flag. Corresponding callback is
+     * {@link WifiNanSessionListener#onPublishFail(int)}.
+     *
+     * @hide
+     */
+    public static final int LISTEN_PUBLISH_FAIL = 0x1 << 0;
+
+    /**
+     * Publish terminated callback event registration flag. Corresponding
+     * callback is {@link WifiNanSessionListener#onPublishTerminated(int)}.
+     */
+    public static final int LISTEN_PUBLISH_TERMINATED = 0x1 << 1;
+
+    /**
+     * Subscribe fail callback event registration flag. Corresponding callback
+     * is {@link WifiNanSessionListener#onSubscribeFail(int)}.
+     *
+     * @hide
+     */
+    public static final int LISTEN_SUBSCRIBE_FAIL = 0x1 << 2;
+
+    /**
+     * Subscribe terminated callback event registration flag. Corresponding
+     * callback is {@link WifiNanSessionListener#onSubscribeTerminated(int)}.
+     */
+    public static final int LISTEN_SUBSCRIBE_TERMINATED = 0x1 << 3;
+
+    /**
+     * Match (discovery: publish or subscribe) callback event registration flag.
+     * Corresponding callback is
+     * {@link WifiNanSessionListener#onMatch(int, byte[], int, byte[], int)}.
+     *
+     * @hide
+     */
+    public static final int LISTEN_MATCH = 0x1 << 4;
+
+    /**
+     * Message sent successfully callback event registration flag. Corresponding
+     * callback is {@link WifiNanSessionListener#onMessageSendSuccess()}.
+     *
+     * @hide
+     */
+    public static final int LISTEN_MESSAGE_SEND_SUCCESS = 0x1 << 5;
+
+    /**
+     * Message sending failure callback event registration flag. Corresponding
+     * callback is {@link WifiNanSessionListener#onMessageSendFail(int)}.
+     *
+     * @hide
+     */
+    public static final int LISTEN_MESSAGE_SEND_FAIL = 0x1 << 6;
+
+    /**
+     * Message received callback event registration flag. Corresponding callback
+     * is {@link WifiNanSessionListener#onMessageReceived(int, byte[], int)}.
+     *
+     * @hide
+     */
+    public static final int LISTEN_MESSAGE_RECEIVED = 0x1 << 7;
+
+    /**
+     * List of hidden events: which are mandatory - i.e. they will be added to
+     * every request.
+     *
+     * @hide
+     */
+    public static final int LISTEN_HIDDEN_FLAGS = LISTEN_PUBLISH_FAIL | LISTEN_SUBSCRIBE_FAIL
+            | LISTEN_MATCH | LISTEN_MESSAGE_SEND_SUCCESS | LISTEN_MESSAGE_SEND_FAIL
+            | LISTEN_MESSAGE_RECEIVED;
+
+    /**
+     * Failure reason flag for {@link WifiNanEventListener} and
+     * {@link WifiNanSessionListener} callbacks. Indicates no resources to execute
+     * the requested operation.
+     */
+    public static final int FAIL_REASON_NO_RESOURCES = 0;
+
+    /**
+     * Failure reason flag for {@link WifiNanEventListener} and
+     * {@link WifiNanSessionListener} callbacks. Indicates invalid argument in the
+     * requested operation.
+     */
+    public static final int FAIL_REASON_INVALID_ARGS = 1;
+
+    /**
+     * Failure reason flag for {@link WifiNanEventListener} and
+     * {@link WifiNanSessionListener} callbacks. Indicates a message is transmitted
+     * without a match (i.e. a discovery) occurring first.
+     */
+    public static final int FAIL_REASON_NO_MATCH_SESSION = 2;
+
+    /**
+     * Failure reason flag for {@link WifiNanEventListener} and
+     * {@link WifiNanSessionListener} callbacks. Indicates an unspecified error
+     * occurred during the operation.
+     */
+    public static final int FAIL_REASON_OTHER = 3;
+
+    /**
+     * Failure reason flag for
+     * {@link WifiNanSessionListener#onPublishTerminated(int)} and
+     * {@link WifiNanSessionListener#onSubscribeTerminated(int)} callbacks.
+     * Indicates that publish or subscribe session is done - i.e. all the
+     * requested operations (per {@link PublishSettings} or
+     * {@link SubscribeSettings}) have been executed.
+     */
+    public static final int TERMINATE_REASON_DONE = 0;
+
+    /**
+     * Failure reason flag for
+     * {@link WifiNanSessionListener#onPublishTerminated(int)} and
+     * {@link WifiNanSessionListener#onSubscribeTerminated(int)} callbacks.
+     * Indicates that publish or subscribe session is terminated due to a
+     * failure.
+     */
+    public static final int TERMINATE_REASON_FAIL = 1;
+
+    private static final String MESSAGE_BUNDLE_KEY_PEER_ID = "peer_id";
+    private static final String MESSAGE_BUNDLE_KEY_MESSAGE = "message";
+    private static final String MESSAGE_BUNDLE_KEY_MESSAGE2 = "message2";
+
+    private final Handler mHandler;
+
+    /**
+     * Constructs a {@link WifiNanSessionListener} using the looper of the current
+     * thread. I.e. all callbacks will be delivered on the current thread.
+     */
+    public WifiNanSessionListener() {
+        this(Looper.myLooper());
+    }
+
+    /**
+     * Constructs a {@link WifiNanSessionListener} using the specified looper. I.e.
+     * all callbacks will delivered on the thread of the specified looper.
+     *
+     * @param looper The looper on which to execute the callbacks.
+     */
+    public WifiNanSessionListener(Looper looper) {
+        if (VDBG) Log.v(TAG, "ctor: looper=" + looper);
+        mHandler = new Handler(looper) {
+            @Override
+            public void handleMessage(Message msg) {
+                if (DBG) Log.d(TAG, "What=" + msg.what + ", msg=" + msg);
+                switch (msg.what) {
+                    case LISTEN_PUBLISH_FAIL:
+                        WifiNanSessionListener.this.onPublishFail(msg.arg1);
+                        break;
+                    case LISTEN_PUBLISH_TERMINATED:
+                        WifiNanSessionListener.this.onPublishTerminated(msg.arg1);
+                        break;
+                    case LISTEN_SUBSCRIBE_FAIL:
+                        WifiNanSessionListener.this.onSubscribeFail(msg.arg1);
+                        break;
+                    case LISTEN_SUBSCRIBE_TERMINATED:
+                        WifiNanSessionListener.this.onSubscribeTerminated(msg.arg1);
+                        break;
+                    case LISTEN_MATCH:
+                        WifiNanSessionListener.this.onMatch(
+                                msg.getData().getInt(MESSAGE_BUNDLE_KEY_PEER_ID),
+                                msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE), msg.arg1,
+                                msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2), msg.arg2);
+                        break;
+                    case LISTEN_MESSAGE_SEND_SUCCESS:
+                        WifiNanSessionListener.this.onMessageSendSuccess(msg.arg1);
+                        break;
+                    case LISTEN_MESSAGE_SEND_FAIL:
+                        WifiNanSessionListener.this.onMessageSendFail(msg.arg1, msg.arg2);
+                        break;
+                    case LISTEN_MESSAGE_RECEIVED:
+                        WifiNanSessionListener.this.onMessageReceived(msg.arg2,
+                                msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE), msg.arg1);
+                        break;
+                }
+            }
+        };
+    }
+
+    /**
+     * Called when a publish operation fails. It is dummy method (empty
+     * implementation printing out a log message). Override to implement your
+     * custom response.
+     *
+     * @param reason The failure reason using {@code NanSessionListener.FAIL_*}
+     *            codes.
+     */
+    public void onPublishFail(int reason) {
+        if (VDBG) Log.v(TAG, "onPublishFail: called in stub - override if interested");
+    }
+
+    /**
+     * Called when a publish operation terminates. Event will only be delivered
+     * if registered using {@link WifiNanSessionListener#LISTEN_PUBLISH_TERMINATED}.
+     * A dummy (empty implementation printing out a warning). Make sure to
+     * override if registered.
+     *
+     * @param reason The termination reason using
+     *            {@code NanSessionListener.TERMINATE_*} codes.
+     */
+    public void onPublishTerminated(int reason) {
+        Log.w(TAG, "onPublishTerminated: called in stub - override if interested or disable");
+    }
+
+    /**
+     * Called when a subscribe operation fails. It is dummy method (empty
+     * implementation printing out a log message). Override to implement your
+     * custom response.
+     *
+     * @param reason The failure reason using {@code NanSessionListener.FAIL_*}
+     *            codes.
+     */
+    public void onSubscribeFail(int reason) {
+        if (VDBG) Log.v(TAG, "onSubscribeFail: called in stub - override if interested");
+    }
+
+    /**
+     * Called when a subscribe operation terminates. Event will only be
+     * delivered if registered using
+     * {@link WifiNanSessionListener#LISTEN_SUBSCRIBE_TERMINATED}. A dummy (empty
+     * implementation printing out a warning). Make sure to override if
+     * registered.
+     *
+     * @param reason The termination reason using
+     *            {@code NanSessionListener.TERMINATE_*} codes.
+     */
+    public void onSubscribeTerminated(int reason) {
+        Log.w(TAG, "onSubscribeTerminated: called in stub - override if interested or disable");
+    }
+
+    /**
+     * Called when a discovery (publish or subscribe) operation results in a
+     * match - i.e. when a peer is discovered. It is dummy method (empty
+     * implementation printing out a log message). Override to implement your
+     * custom response.
+     *
+     * @param peerId The ID of the peer matching our discovery operation.
+     * @param serviceSpecificInfo The service specific information (arbitrary
+     *            byte array) provided by the peer as part of its discovery
+     *            packet.
+     * @param serviceSpecificInfoLength The length of the service specific
+     *            information array.
+     * @param matchFilter The filter (Tx on advertiser and Rx on listener) which
+     *            resulted in this match.
+     * @param matchFilterLength The length of the match filter array.
+     */
+    public void onMatch(int peerId, byte[] serviceSpecificInfo,
+            int serviceSpecificInfoLength, byte[] matchFilter, int matchFilterLength) {
+        if (VDBG) Log.v(TAG, "onMatch: called in stub - override if interested");
+    }
+
+    /**
+     * Called when a message is transmitted successfully - i.e. when we know
+     * that it was received successfully (corresponding to an ACK being
+     * received). It is dummy method (empty implementation printing out a log
+     * message). Override to implement your custom response.
+     * <p>
+     * Note that either this callback or
+     * {@link WifiNanSessionListener#onMessageSendFail(int)} will be received -
+     * never both.
+     */
+    public void onMessageSendSuccess(int messageId) {
+        if (VDBG) Log.v(TAG, "onMessageSendSuccess: called in stub - override if interested");
+    }
+
+    /**
+     * Called when a message transmission fails - i.e. when no ACK is received.
+     * The hardware will usually attempt to re-transmit several times - this
+     * event is received after all retries are exhausted. There is a possibility
+     * that message was received by the destination successfully but the ACK was
+     * lost. It is dummy method (empty implementation printing out a log
+     * message). Override to implement your custom response.
+     * <p>
+     * Note that either this callback or
+     * {@link WifiNanSessionListener#onMessageSendSuccess()} will be received -
+     * never both
+     *
+     * @param reason The failure reason using {@code NanSessionListener.FAIL_*}
+     *            codes.
+     */
+    public void onMessageSendFail(int messageId, int reason) {
+        if (VDBG) Log.v(TAG, "onMessageSendFail: called in stub - override if interested");
+    }
+
+    /**
+     * Called when a message is received from a discovery session peer. It is
+     * dummy method (empty implementation printing out a log message). Override
+     * to implement your custom response.
+     *
+     * @param peerId The ID of the peer sending the message.
+     * @param message A byte array containing the message.
+     * @param messageLength The length of the byte array containing the relevant
+     *            message bytes.
+     */
+    public void onMessageReceived(int peerId, byte[] message, int messageLength) {
+        if (VDBG) Log.v(TAG, "onMessageReceived: called in stub - override if interested");
+    }
+
+    /**
+     * {@hide}
+     */
+    public IWifiNanSessionListener callback = new IWifiNanSessionListener.Stub() {
+        @Override
+        public void onPublishFail(int reason) {
+            if (VDBG) Log.v(TAG, "onPublishFail: reason=" + reason);
+
+            Message msg = mHandler.obtainMessage(LISTEN_PUBLISH_FAIL);
+            msg.arg1 = reason;
+            mHandler.sendMessage(msg);
+        }
+
+        @Override
+        public void onPublishTerminated(int reason) {
+            if (VDBG) Log.v(TAG, "onPublishResponse: reason=" + reason);
+
+            Message msg = mHandler.obtainMessage(LISTEN_PUBLISH_TERMINATED);
+            msg.arg1 = reason;
+            mHandler.sendMessage(msg);
+        }
+
+        @Override
+        public void onSubscribeFail(int reason) {
+            if (VDBG) Log.v(TAG, "onSubscribeFail: reason=" + reason);
+
+            Message msg = mHandler.obtainMessage(LISTEN_SUBSCRIBE_FAIL);
+            msg.arg1 = reason;
+            mHandler.sendMessage(msg);
+        }
+
+        @Override
+        public void onSubscribeTerminated(int reason) {
+            if (VDBG) Log.v(TAG, "onSubscribeTerminated: reason=" + reason);
+
+            Message msg = mHandler.obtainMessage(LISTEN_SUBSCRIBE_TERMINATED);
+            msg.arg1 = reason;
+            mHandler.sendMessage(msg);
+        }
+
+        @Override
+        public void onMatch(int peerId, byte[] serviceSpecificInfo,
+                int serviceSpecificInfoLength, byte[] matchFilter, int matchFilterLength) {
+            if (VDBG) Log.v(TAG, "onMatch: peerId=" + peerId);
+
+            Bundle data = new Bundle();
+            data.putInt(MESSAGE_BUNDLE_KEY_PEER_ID, peerId);
+            data.putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE, serviceSpecificInfo);
+            data.putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2, matchFilter);
+
+            Message msg = mHandler.obtainMessage(LISTEN_MATCH);
+            msg.arg1 = serviceSpecificInfoLength;
+            msg.arg2 = matchFilterLength;
+            msg.setData(data);
+            mHandler.sendMessage(msg);
+        }
+
+        @Override
+        public void onMessageSendSuccess(int messageId) {
+            if (VDBG) Log.v(TAG, "onMessageSendSuccess");
+
+            Message msg = mHandler.obtainMessage(LISTEN_MESSAGE_SEND_SUCCESS);
+            msg.arg1 = messageId;
+            mHandler.sendMessage(msg);
+        }
+
+        @Override
+        public void onMessageSendFail(int messageId, int reason) {
+            if (VDBG) Log.v(TAG, "onMessageSendFail: reason=" + reason);
+
+            Message msg = mHandler.obtainMessage(LISTEN_MESSAGE_SEND_FAIL);
+            msg.arg1 = messageId;
+            msg.arg2 = reason;
+            mHandler.sendMessage(msg);
+        }
+
+        @Override
+        public void onMessageReceived(int peerId, byte[] message, int messageLength) {
+            if (VDBG) {
+                Log.v(TAG, "onMessageReceived: peerId='" + peerId + "', messageLength="
+                        + messageLength);
+            }
+
+            Bundle data = new Bundle();
+            data.putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE, message);
+
+            Message msg = mHandler.obtainMessage(LISTEN_MESSAGE_RECEIVED);
+            msg.arg1 = messageLength;
+            msg.arg2 = peerId;
+            msg.setData(data);
+            mHandler.sendMessage(msg);
+        }
+    };
+}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java b/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java
new file mode 100644
index 0000000..7dfdd32
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nan;
+
+/**
+ * A representation of a NAN subscribe session. Created when
+ * {@link WifiNanManager#subscribe(SubscribeData, SubscribeSettings, WifiNanSessionListener, int)}
+ * is executed. The object can be used to stop and re-start (re-configure) the
+ * subscribe session.
+ *
+ * @hide PROPOSED_NAN_API
+ */
+public class WifiNanSubscribeSession extends WifiNanSession {
+    /**
+     * {@hide}
+     */
+    public WifiNanSubscribeSession(WifiNanManager manager, int sessionId) {
+        super(manager, sessionId);
+    }
+
+    /**
+     * Restart/re-configure the subscribe session. Note that the
+     * {@link WifiNanSessionListener} is not replaced - the same listener used at
+     * creation is still used.
+     *
+     * @param subscribeData The data ({@link SubscribeData}) to subscribe.
+     * @param subscribeSettings The settings ({@link SubscribeSettings}) of the
+     *            subscribe session.
+     */
+    public void subscribe(SubscribeData subscribeData, SubscribeSettings subscribeSettings) {
+        mManager.subscribe(mSessionId, subscribeData, subscribeSettings);
+    }
+}
diff --git a/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl b/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
deleted file mode 100644
index 50bec33..0000000
--- a/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-import android.net.wifi.ScanResult;
-import android.net.wifi.passpoint.WifiPasspointPolicy;
-import android.net.wifi.passpoint.WifiPasspointCredential;
-import android.os.Messenger;
-
-/**
- * Interface that allows controlling and querying Wifi Passpoint connectivity.
- *
- * {@hide}
- */
-interface IWifiPasspointManager
-{
-    Messenger getMessenger();
-
-    int getPasspointState();
-
-    List<WifiPasspointPolicy> requestCredentialMatch(in List<ScanResult> requested);
-
-    List<WifiPasspointCredential> getCredentials();
-
-    boolean addCredential(in WifiPasspointCredential cred);
-
-    boolean updateCredential(in WifiPasspointCredential cred);
-
-    boolean removeCredential(in WifiPasspointCredential cred);
-}
-
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.aidl
deleted file mode 100644
index cfd3605..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-parcelable WifiPasspointCredential;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
deleted file mode 100644
index a100aed..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
+++ /dev/null
@@ -1,665 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-import android.net.wifi.WifiEnterpriseConfig;
-import android.os.Parcelable;
-import android.os.Parcel;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-
-/**
- * A class representing a Wi-Fi Passpoint credential.
- * @hide
- */
-public class WifiPasspointCredential implements Parcelable {
-
-    private final static String TAG = "PasspointCredential";
-    private final static boolean DBG = true;
-
-    /** Wi-Fi nodes**/
-    private String mWifiSpFqdn;
-
-    /** PerProviderSubscription nodes **/
-    private String mCredentialName;
-
-    /** SubscriptionUpdate nodes **/
-    private String mSubscriptionUpdateInterval;
-    private String mSubscriptionUpdateMethod;
-    private String mSubscriptionUpdateRestriction;
-    private String mSubscriptionUpdateURI;
-    private String mSubscriptionUpdateUsername;
-    private String mSubscriptionUpdatePassword;
-
-    /** HomeSP nodes **/
-    private String mHomeSpFqdn;
-    private String mFriendlyName;
-    private Collection<WifiPasspointDmTree.HomeOIList> mHomeOIList;
-    private Collection<WifiPasspointDmTree.OtherHomePartners> mOtherHomePartnerList;
-
-    /** SubscriptionParameters nodes**/
-    private String mCreationDate;
-    private String mExpirationDate;
-
-    /** Credential nodes **/
-    private String mType;
-    private String mInnerMethod;
-    private String mCertType;
-    private String mCertSha256Fingerprint;
-    private String mUpdateIdentifier;
-    private String mUsername;
-    private String mPasswd;
-    private String mRealm;
-    private String mImsi;
-    private String mMcc;
-    private String mMnc;
-    private String mCaRootCert;
-    private String mClientCert;
-    private boolean mCheckAaaServerCertStatus;
-
-    /** Policy nodes **/
-    private String mPolicyUpdateUri;
-    private String mPolicyUpdateInterval;
-    private String mPolicyUpdateUsername;
-    private String mPolicyUpdatePassword;
-    private String mPolicyUpdateRestriction;
-    private String mPolicyUpdateMethod;
-    private Collection<WifiPasspointDmTree.PreferredRoamingPartnerList> mPreferredRoamingPartnerList;
-    private Collection<WifiPasspointDmTree.MinBackhaulThresholdNetwork> mMinBackhaulThresholdNetwork;
-    private Collection<WifiPasspointDmTree.SPExclusionList> mSpExclusionList;
-    private Collection<WifiPasspointDmTree.RequiredProtoPortTuple> mRequiredProtoPortTuple;
-    private String mMaxBssLoad;
-
-    /** CrednetialPriority node **/
-    private int mCrednetialPriority;
-
-    /** AAAServerTrustRoot nodes **/
-    private String mAaaCertUrl;
-    private String mAaaSha256Fingerprint;
-
-    /** Others **/
-    private boolean mIsMachineRemediation;
-    private boolean mUserPreferred = false;
-    private String mWifiTreePath;
-    private WifiEnterpriseConfig mEnterpriseConfig;
-
-    /** @hide */
-    public WifiPasspointCredential() {}
-
-    /**
-     * Constructor
-     * @param realm Realm of the passpoint credential
-     * @param fqdn Fully qualified domain name (FQDN) of the credential
-     * @param config Enterprise config, must be either EAP-TLS or EAP-TTLS
-     * @see WifiEnterpriseConfig
-     */
-    public WifiPasspointCredential(String realm, String fqdn, WifiEnterpriseConfig config) {
-        mRealm = realm;
-        switch (config.getEapMethod()) {
-            case WifiEnterpriseConfig.Eap.TLS:
-            case WifiEnterpriseConfig.Eap.TTLS:
-                mEnterpriseConfig = new WifiEnterpriseConfig(config);
-                break;
-            default:
-                // ignore
-        }
-    }
-
-    /** @hide */
-    public WifiPasspointCredential(String type,
-            String caroot,
-            String clientcert,
-            String mcc,
-            String mnc,
-            WifiPasspointDmTree.SpFqdn sp,
-            WifiPasspointDmTree.CredentialInfo credinfo) {
-
-        if (credinfo == null) {
-            return;
-        }
-
-        mType = type;
-        mCaRootCert = caroot;
-        mClientCert = clientcert;
-
-        mWifiSpFqdn = sp.nodeName;
-        mUpdateIdentifier = sp.perProviderSubscription.UpdateIdentifier;
-
-        mCredentialName = credinfo.nodeName;
-        mOtherHomePartnerList = credinfo.homeSP.otherHomePartners.values();
-
-        Set set = credinfo.aAAServerTrustRoot.entrySet();
-        Iterator i = set.iterator();
-        if (i.hasNext()) {
-            Map.Entry entry3 = (Map.Entry) i.next();
-            WifiPasspointDmTree.AAAServerTrustRoot aaa = (WifiPasspointDmTree.AAAServerTrustRoot) entry3.getValue();
-            mAaaCertUrl = aaa.CertURL;
-            mAaaSha256Fingerprint = aaa.CertSHA256Fingerprint;
-        }
-
-        mCertType = credinfo.credential.digitalCertificate.CertificateType;
-        mCertSha256Fingerprint = credinfo.credential.digitalCertificate.CertSHA256Fingerprint;
-        mUsername = credinfo.credential.usernamePassword.Username;
-        mPasswd = credinfo.credential.usernamePassword.Password;
-        mIsMachineRemediation = credinfo.credential.usernamePassword.MachineManaged;
-        mInnerMethod = credinfo.credential.usernamePassword.eAPMethod.InnerMethod;
-        mImsi = credinfo.credential.sim.IMSI;
-        mMcc = mcc;
-        mMnc = mnc;
-        mCreationDate = credinfo.credential.CreationDate;
-        mExpirationDate = credinfo.credential.ExpirationDate;
-        mRealm = credinfo.credential.Realm;
-
-        if (credinfo.credentialPriority == null) {
-            mCrednetialPriority = 128;
-        } else {
-            mCrednetialPriority = Integer.parseInt(credinfo.credentialPriority);
-        }
-
-        mHomeSpFqdn = credinfo.homeSP.FQDN;
-
-        mSubscriptionUpdateInterval = credinfo.subscriptionUpdate.UpdateInterval;
-        mSubscriptionUpdateMethod = credinfo.subscriptionUpdate.UpdateMethod;
-        mSubscriptionUpdateRestriction = credinfo.subscriptionUpdate.Restriction;
-        mSubscriptionUpdateURI = credinfo.subscriptionUpdate.URI;
-        mSubscriptionUpdateUsername = credinfo.subscriptionUpdate.usernamePassword.Username;
-        mSubscriptionUpdatePassword = credinfo.subscriptionUpdate.usernamePassword.Password;
-
-        mPolicyUpdateUri = credinfo.policy.policyUpdate.URI;
-        mPolicyUpdateInterval = credinfo.policy.policyUpdate.UpdateInterval;
-        mPolicyUpdateUsername = credinfo.policy.policyUpdate.usernamePassword.Username;
-        mPolicyUpdatePassword = credinfo.policy.policyUpdate.usernamePassword.Password;
-        mPolicyUpdateRestriction = credinfo.policy.policyUpdate.Restriction;
-        mPolicyUpdateMethod = credinfo.policy.policyUpdate.UpdateMethod;
-        mPreferredRoamingPartnerList = credinfo.policy.preferredRoamingPartnerList.values();
-        mMinBackhaulThresholdNetwork = credinfo.policy.minBackhaulThreshold.values();
-        mRequiredProtoPortTuple = credinfo.policy.requiredProtoPortTuple.values();
-        mMaxBssLoad = credinfo.policy.maximumBSSLoadValue;
-        mSpExclusionList = credinfo.policy.sPExclusionList.values();
-
-        mHomeOIList = credinfo.homeSP.homeOIList.values();
-        mFriendlyName = credinfo.homeSP.FriendlyName;
-        mCheckAaaServerCertStatus = credinfo.credential.CheckAAAServerCertStatus;
-    }
-
-    /** @hide */
-    public String getUpdateIdentifier() {
-        return mUpdateIdentifier;
-    }
-
-    /** @hide */
-    public String getUpdateMethod() {
-        return mSubscriptionUpdateMethod;
-    }
-
-    /** @hide */
-    public void setUpdateMethod(String method) {
-        mSubscriptionUpdateMethod = method;
-    }
-
-    /** @hide */
-    public String getWifiSpFqdn() {
-        return mWifiSpFqdn;
-    }
-
-    /** @hide */
-    public String getCredName() {
-        return mCredentialName;
-    }
-
-    /** @hide */
-    public String getType() {
-        return mType;
-    }
-
-    /**
-     * Get enterprise config of this Passpoint credential.
-     * @return Enterprise config
-     * @see WifiEnterpriseConfig
-     */
-    public WifiEnterpriseConfig getEnterpriseConfig() {
-        return new WifiEnterpriseConfig(mEnterpriseConfig);
-    }
-
-    /**
-     * Set enterprise config of this Passpoint credential.
-     * @param config Enterprise config, must be either EAP-TLS or EAP-TTLS
-     * @see WifiEnterpriseConfig
-     */
-    public void setEnterpriseConfig(WifiEnterpriseConfig config) {
-        // TODO
-    }
-
-    /** @hide */
-    public String getCertType() {
-        return mCertType;
-    }
-
-    /** @hide */
-    public String getCertSha256Fingerprint() {
-        return mCertSha256Fingerprint;
-    }
-
-    /** @hide */
-    public String getUserName() {
-        return mUsername;
-    }
-
-    /** @hide */
-    public String getPassword() {
-        // TODO: guarded by connectivity internal
-        return mPasswd;
-    }
-
-    /** @hide */
-    public String getImsi() {
-        return mImsi;
-    }
-
-    /** @hide */
-    public String getMcc() {
-        return mMcc;
-    }
-
-    /** @hide */
-    public String getMnc() {
-        return mMnc;
-    }
-
-    /** @hide */
-    public String getCaRootCertPath() {
-        return mCaRootCert;
-    }
-
-    /** @hide */
-    public String getClientCertPath() {
-        return mClientCert;
-    }
-
-    /**
-     * Get the realm of this Passpoint credential.
-     * @return Realm
-     */
-    public String getRealm() {
-        return mRealm;
-    }
-
-    /**
-     * Set the ream of this Passpoint credential.
-     * @param realm Realm
-     */
-    public void setRealm(String realm) {
-        mRealm = realm;
-    }
-
-    /** @hide */
-    public int getPriority() {
-        if (mUserPreferred) {
-            return 0;
-        }
-
-        return mCrednetialPriority;
-    }
-
-    /**
-     * Get the fully qualified domain name (FQDN) of this Passpoint credential.
-     * @return FQDN
-     */
-    public String getHomeSpFqdn() {
-        return mHomeSpFqdn;
-    }
-
-    /**
-     * Set the fully qualified domain name (FQDN) of this Passpoint credential.
-     * @param fqdn FQDN
-     */
-    public void setHomeFqdn(String fqdn) {
-        mHomeSpFqdn = fqdn;
-    }
-
-
-    /** @hide */
-    public Collection<WifiPasspointDmTree.OtherHomePartners> getOtherHomePartnerList() {
-        return mOtherHomePartnerList;
-    }
-
-    /** @hide */
-    public String getSubscriptionUpdateUsername() {
-        return mSubscriptionUpdateUsername;
-    }
-
-    /** @hide */
-    public String getSubscriptionUpdatePassword() {
-        return mSubscriptionUpdatePassword;
-    }
-
-    /** @hide */
-    public String getPolicyUpdateUri() {
-        return mPolicyUpdateUri;
-    }
-
-    /** @hide */
-    public String getPolicyUpdateInterval() {
-        return mPolicyUpdateInterval;
-    }
-
-    /** @hide */
-    public String getPolicyUpdateUsername() {
-        return mPolicyUpdateUsername;
-    }
-
-    /** @hide */
-    public String getPolicyUpdatePassword() {
-        return mPolicyUpdatePassword;
-    }
-
-    /** @hide */
-    public String getPolicyUpdateRestriction() {
-        return mPolicyUpdateRestriction;
-    }
-
-    /** @hide */
-    public String getPolicyUpdateMethod() {
-        return mPolicyUpdateMethod;
-    }
-
-    /** @hide */
-    public String getCreationDate() {
-        return mCreationDate;
-    }
-
-    /** @hide */
-    public String getExpirationDate() {
-        return mExpirationDate;
-    }
-
-    /** @hide */
-    public void setExpirationDate(String expirationdate) {
-        mExpirationDate = expirationdate;
-    }
-
-    /** @hide */
-    public Collection<WifiPasspointDmTree.PreferredRoamingPartnerList> getPreferredRoamingPartnerList() {
-        return mPreferredRoamingPartnerList;
-    }
-
-    /** @hide */
-    public Collection<WifiPasspointDmTree.HomeOIList> getHomeOiList() {
-        return mHomeOIList;
-    }
-
-    /** @hide */
-    public Collection<WifiPasspointDmTree.MinBackhaulThresholdNetwork> getBackhaulThresholdList() {
-        return mMinBackhaulThresholdNetwork;
-    }
-
-    /** @hide */
-    public Collection<WifiPasspointDmTree.RequiredProtoPortTuple> getRequiredProtoPortList() {
-        return mRequiredProtoPortTuple;
-    }
-
-    /** @hide */
-    public Collection<WifiPasspointDmTree.SPExclusionList> getSPExclusionList() {
-        return mSpExclusionList;
-    }
-
-    /** @hide */
-    public boolean getIsMachineRemediation() {
-        return mIsMachineRemediation;
-    }
-
-    /** @hide */
-    public String getAaaCertUrl() {
-        return mAaaCertUrl;
-    }
-
-    /** @hide */
-    public String getAaaSha256Fingerprint() {
-        return mAaaSha256Fingerprint;
-    }
-
-    /** @hide */
-    public String getSubscriptionUpdateRestriction() {
-        return mSubscriptionUpdateRestriction;
-    }
-
-    /** @hide */
-    public String getSubscriptionUpdateURI() {
-        return mSubscriptionUpdateURI;
-    }
-
-    /** @hide */
-    public String getSubscriptionUpdateInterval() {
-        return mSubscriptionUpdateInterval;
-    }
-
-    /** @hide */
-    public String getFriendlyName() {
-        return mFriendlyName;
-    }
-
-    /** @hide */
-    public String getMaxBssLoad() {
-        return mMaxBssLoad;
-    }
-
-    /** @hide */
-    public boolean getUserPreference() {
-        return mUserPreferred;
-    }
-
-    /** @hide */
-    public boolean getCheckAaaServerCertStatus() {
-        return mCheckAaaServerCertStatus;
-    }
-
-    /** @hide */
-    public void setUserPreference(boolean value) {
-        mUserPreferred = value;
-    }
-
-    @Override
-    /** @hide */
-    public boolean equals(Object obj) {
-        boolean result = false;
-        if (obj instanceof WifiPasspointCredential) {
-            final WifiPasspointCredential other = (WifiPasspointCredential) obj;
-            if (this.mType.equals(other.mType)) {
-                if (this.mType.equals("TTLS")) {
-                    result = this.mUsername.equals(other.mUsername) &&
-                            this.mPasswd.equals(other.mPasswd) &&
-                            this.mRealm.equals(other.mRealm) &&
-                            this.mHomeSpFqdn.equals(other.mHomeSpFqdn);
-                }
-                if (this.mType.equals("TLS")) {
-                    result = this.mRealm.equals(other.mRealm) &&
-                            this.mHomeSpFqdn.equals(other.mHomeSpFqdn) &&
-                            this.mClientCert.equals(other.mClientCert);
-                }
-                if (this.mType.equals("SIM")) {
-                    result = this.mMcc.equals(other.mMcc) &&
-                            this.mMnc.equals(other.mMnc) &&
-                            this.mImsi.equals(other.mImsi) &&
-                            this.mHomeSpFqdn.equals(other.mHomeSpFqdn);
-                }
-            }
-        }
-        return result;
-    }
-
-    @Override
-    /** @hide */
-    public String toString() {
-        StringBuffer sb = new StringBuffer();
-        String none = "<none>";
-
-        if (!DBG) {
-            sb.append(none);
-        } else {
-            sb.append(", UpdateIdentifier: ")
-            .append(mUpdateIdentifier == null ? none : mUpdateIdentifier)
-            .append(", SubscriptionUpdateMethod: ")
-            .append(mSubscriptionUpdateMethod == null ? none : mSubscriptionUpdateMethod)
-            .append(", Type: ").append(mType == null ? none : mType)
-            .append(", Username: ").append(mUsername == null ? none : mUsername)
-            .append(", Passwd: ").append(mPasswd == null ? none : mPasswd)
-            .append(", SubDMAccUsername: ")
-            .append(mSubscriptionUpdateUsername == null ? none : mSubscriptionUpdateUsername)
-            .append(", SubDMAccPassword: ")
-            .append(mSubscriptionUpdatePassword == null ? none : mSubscriptionUpdatePassword)
-            .append(", PolDMAccUsername: ")
-            .append(mPolicyUpdateUsername == null ? none : mPolicyUpdateUsername)
-            .append(", PolDMAccPassword: ")
-            .append(mPolicyUpdatePassword == null ? none : mPolicyUpdatePassword)
-            .append(", Imsi: ").append(mImsi == null ? none : mImsi)
-            .append(", Mcc: ").append(mMcc == null ? none : mMcc)
-            .append(", Mnc: ").append(mMnc == null ? none : mMnc)
-            .append(", CaRootCert: ").append(mCaRootCert == null ? none : mCaRootCert)
-            .append(", Realm: ").append(mRealm == null ? none : mRealm)
-            .append(", Priority: ").append(mCrednetialPriority)
-            .append(", Fqdn: ").append(mHomeSpFqdn == null ? none : mHomeSpFqdn)
-            .append(", Otherhomepartners: ")
-            .append(mOtherHomePartnerList == null ? none : mOtherHomePartnerList)
-            .append(", ExpirationDate: ")
-            .append(mExpirationDate == null ? none : mExpirationDate)
-            .append(", MaxBssLoad: ").append(mMaxBssLoad == null ? none : mMaxBssLoad)
-            .append(", SPExclusionList: ").append(mSpExclusionList);
-
-            if (mPreferredRoamingPartnerList != null) {
-                sb.append("PreferredRoamingPartnerList:");
-                for (WifiPasspointDmTree.PreferredRoamingPartnerList prpListItem : mPreferredRoamingPartnerList) {
-                    sb.append("[fqdnmatch:").append(prpListItem.FQDN_Match).
-                            append(", priority:").append(prpListItem.Priority).
-                            append(", country:").append(prpListItem.Country).append("]");
-                }
-            }
-
-            if (mHomeOIList != null) {
-                sb.append("HomeOIList:");
-                for (WifiPasspointDmTree.HomeOIList HomeOIListItem : mHomeOIList) {
-                    sb.append("[HomeOI:").append(HomeOIListItem.HomeOI).
-                            append(", HomeOIRequired:").append(HomeOIListItem.HomeOIRequired).
-                            append("]");
-                }
-            }
-
-            if (mMinBackhaulThresholdNetwork != null) {
-                sb.append("BackHaulThreshold:");
-                for (WifiPasspointDmTree.MinBackhaulThresholdNetwork BhtListItem : mMinBackhaulThresholdNetwork) {
-                    sb.append("[networkType:").append(BhtListItem.NetworkType).
-                            append(", dlBandwidth:").append(BhtListItem.DLBandwidth).
-                            append(", ulBandwidth:").append(BhtListItem.ULBandwidth).
-                            append("]");
-                }
-            }
-
-            if (mRequiredProtoPortTuple != null) {
-                sb.append("WifiMORequiredProtoPortTupleList:");
-                for (WifiPasspointDmTree.RequiredProtoPortTuple RpptListItem : mRequiredProtoPortTuple) {
-                    sb.append("[IPProtocol:").append(RpptListItem.IPProtocol).
-                            append(", PortNumber:").append(RpptListItem.PortNumber).
-                            append("]");
-                }
-            }
-        }
-        return sb.toString();
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    public int describeContents() {
-        return 0;
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(mWifiSpFqdn);
-        dest.writeString(mCredentialName);
-        dest.writeString(mType);
-        dest.writeInt(mCrednetialPriority);
-        dest.writeString(mHomeSpFqdn);
-        dest.writeString(mRealm);
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    public void readFromParcel(Parcel in) {
-        mWifiSpFqdn = in.readString();
-        mCredentialName = in.readString();
-        mType = in.readString();
-        mCrednetialPriority = in.readInt();
-        mHomeSpFqdn = in.readString();
-        mRealm = in.readString();
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    public static final Creator<WifiPasspointCredential> CREATOR =
-            new Creator<WifiPasspointCredential>() {
-                public WifiPasspointCredential createFromParcel(Parcel in) {
-                    WifiPasspointCredential pc = new WifiPasspointCredential();
-                    pc.mWifiSpFqdn = in.readString();
-                    pc.mCredentialName = in.readString();
-                    pc.mType = in.readString();
-                    pc.mCrednetialPriority = in.readInt();
-                    pc.mHomeSpFqdn = in.readString();
-                    pc.mRealm = in.readString();
-                    return pc;
-                }
-
-                public WifiPasspointCredential[] newArray(int size) {
-                    return new WifiPasspointCredential[size];
-                }
-            };
-
-    /** @hide */
-    public int compareTo(WifiPasspointCredential another) {
-
-        //The smaller the higher
-        if (mCrednetialPriority < another.mCrednetialPriority) {
-            return -1;
-        } else if (mCrednetialPriority == another.mCrednetialPriority) {
-            return this.mType.compareTo(another.mType);
-        } else {
-            return 1;
-        }
-    }
-
-    @Override
-    /** @hide */
-    public int hashCode() {
-        int hash = 208;
-        if (mType != null) {
-            hash += mType.hashCode();
-        }
-        if (mRealm != null) {
-            hash += mRealm.hashCode();
-        }
-        if (mHomeSpFqdn != null) {
-            hash += mHomeSpFqdn.hashCode();
-        }
-        if (mUsername != null) {
-            hash += mUsername.hashCode();
-        }
-        if (mPasswd != null) {
-            hash += mPasswd.hashCode();
-        }
-
-        return hash;
-    }
-}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.aidl
deleted file mode 100644
index 6a88b2e..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-parcelable WifiPasspointDmTree;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.java
deleted file mode 100644
index 427c84c..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.java
+++ /dev/null
@@ -1,1375 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-import android.os.Parcelable;
-import android.os.Parcel;
-import java.util.HashMap;
-
-/**
- * Required Mobile Device Management Tree Structure
- *
- *                   +----------+
- *                   | ./(Root) |
- *                   +----+-----+
- *                        |
- *  +---------+           |         +---------+  +---------+
- *  | DevInfo |-----------+---------|  Wi-Fi  |--|SP FQDN* |
- *  +---------+           |         +---------+  +---------+
- *  +---------+           |                           |
- *  |DevDetail|-----------+                      +-----------------------+
- *  +---------+                                  |PerproviderSubscription|--<X>+
- *                                               +-----------------------+
- *
- * This class contains all nodes start from Wi-Fi
- * @hide
- **/
-public class WifiPasspointDmTree implements Parcelable {
-    private final static String TAG = "WifiTree";
-    public int PpsMoId;//plugfest used only
-    public HashMap<String, SpFqdn> spFqdn = new HashMap<String, SpFqdn>();//Maps.newHashMap();
-
-    public SpFqdn createSpFqdn(String name) {
-        SpFqdn obj = new SpFqdn(name);
-        spFqdn.put(name, obj);
-        return obj;
-    }
-
-    public static class SpFqdn implements Parcelable {
-        public String nodeName;
-        public PerProviderSubscription perProviderSubscription = new PerProviderSubscription();
-
-        public SpFqdn(String name) {
-            nodeName = name;
-        }
-
-        public SpFqdn() {
-        }
-
-        public SpFqdn(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(nodeName);
-            out.writeParcelable(perProviderSubscription, flags);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                nodeName = in.readString();
-                perProviderSubscription = in.readParcelable(PerProviderSubscription.class
-                        .getClassLoader());
-            }
-        }
-
-        public static final Parcelable.Creator<SpFqdn> CREATOR = new Parcelable.Creator<SpFqdn>() {
-            public SpFqdn createFromParcel(Parcel in) {
-                return new SpFqdn(in);
-            }
-
-            public SpFqdn[] newArray(int size) {
-                return new SpFqdn[size];
-            }
-        };
-    }
-
-    /**
-     * PerProviderSubscription
-     **/
-    public static class PerProviderSubscription implements Parcelable {
-        /**
-         * PerProviderSubscription/UpdateIdentifier
-         **/
-        public String UpdateIdentifier;
-        public HashMap<String, CredentialInfo> credentialInfo = new HashMap<String, CredentialInfo>();
-
-        public CredentialInfo createCredentialInfo(String name) {
-            CredentialInfo obj = new CredentialInfo(name);
-            credentialInfo.put(name, obj);
-            return obj;
-        }
-
-        public PerProviderSubscription() {
-        }
-
-        public PerProviderSubscription(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(UpdateIdentifier);
-            out.writeMap(credentialInfo);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                UpdateIdentifier = in.readString();
-                in.readMap(credentialInfo, CredentialInfo.class.getClassLoader());
-            }
-        }
-
-        public static final Parcelable.Creator<PerProviderSubscription> CREATOR = new Parcelable.Creator<PerProviderSubscription>() {
-            public PerProviderSubscription createFromParcel(Parcel in) {
-                return new PerProviderSubscription(in);
-            }
-
-            public PerProviderSubscription[] newArray(int size) {
-                return new PerProviderSubscription[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>
-     * This interior node contains the Home SP information, subscription policy, management and credential information.
-     **/
-    public static class CredentialInfo implements Parcelable {
-        public String nodeName;
-        public Policy policy = new Policy();
-        public String credentialPriority;
-        public HashMap<String, AAAServerTrustRoot> aAAServerTrustRoot = new HashMap<String, AAAServerTrustRoot>();
-        public SubscriptionUpdate subscriptionUpdate = new SubscriptionUpdate();
-        public HomeSP homeSP = new HomeSP();
-        public SubscriptionParameters subscriptionParameters = new SubscriptionParameters();
-        public Credential credential = new Credential();
-        public Extension extension = new Extension();
-
-        public CredentialInfo(String nn) {
-            nodeName = nn;
-        }
-
-        public AAAServerTrustRoot createAAAServerTrustRoot(String name, String url, String fp) {
-            AAAServerTrustRoot obj = new AAAServerTrustRoot(name, url, fp);
-            aAAServerTrustRoot.put(name, obj);
-            return obj;
-        }
-
-        public CredentialInfo() {
-        }
-
-        public CredentialInfo(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(nodeName);
-            out.writeParcelable(policy, flags);
-            out.writeString(credentialPriority);
-            out.writeMap(aAAServerTrustRoot);
-            out.writeParcelable(subscriptionUpdate, flags);
-            out.writeParcelable(homeSP, flags);
-            out.writeParcelable(subscriptionParameters, flags);
-            out.writeParcelable(credential, flags);
-            //out.writeParcelable(extension, flags);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                nodeName = in.readString();
-                policy = in.readParcelable(Policy.class.getClassLoader());
-                credentialPriority = in.readString();
-                in.readMap(aAAServerTrustRoot, AAAServerTrustRoot.class.getClassLoader());
-                subscriptionUpdate = in.readParcelable(SubscriptionUpdate.class.getClassLoader());
-                homeSP = in.readParcelable(HomeSP.class.getClassLoader());
-                subscriptionParameters = in.readParcelable(SubscriptionParameters.class
-                        .getClassLoader());
-                credential = in.readParcelable(Credential.class.getClassLoader());
-                //extension = in.readParcelable(Extension.class.getClassLoader());
-            }
-        }
-
-        public static final Parcelable.Creator<CredentialInfo> CREATOR = new Parcelable.Creator<CredentialInfo>() {
-            public CredentialInfo createFromParcel(Parcel in) {
-                return new CredentialInfo(in);
-            }
-
-            public CredentialInfo[] newArray(int size) {
-                return new CredentialInfo[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Policy
-     **/
-    public static class Policy implements Parcelable {
-        public HashMap<String, PreferredRoamingPartnerList> preferredRoamingPartnerList = new HashMap<String, PreferredRoamingPartnerList>();
-        public HashMap<String, MinBackhaulThresholdNetwork> minBackhaulThreshold = new HashMap<String, MinBackhaulThresholdNetwork>();
-        public PolicyUpdate policyUpdate = new PolicyUpdate();
-        public HashMap<String, SPExclusionList> sPExclusionList = new HashMap<String, SPExclusionList>();
-        public HashMap<String, RequiredProtoPortTuple> requiredProtoPortTuple = new HashMap<String, RequiredProtoPortTuple>();
-        public String maximumBSSLoadValue;
-
-        public PreferredRoamingPartnerList createPreferredRoamingPartnerList(String name,
-                String fqdn, String priority, String country) {
-            PreferredRoamingPartnerList obj = new PreferredRoamingPartnerList(name, fqdn, priority,
-                    country);
-            preferredRoamingPartnerList.put(name, obj);
-            return obj;
-        }
-
-        public MinBackhaulThresholdNetwork createMinBackhaulThreshold(String name, String type,
-                String dl, String ul) {
-            MinBackhaulThresholdNetwork obj = new MinBackhaulThresholdNetwork(name, type, dl, ul);
-            minBackhaulThreshold.put(name, obj);
-            return obj;
-        }
-
-        public SPExclusionList createSPExclusionList(String name, String ssid) {
-            SPExclusionList obj = new SPExclusionList(name, ssid);
-            sPExclusionList.put(name, obj);
-            return obj;
-        }
-
-        public RequiredProtoPortTuple createRequiredProtoPortTuple(String name, String proto,
-                String port) {
-            RequiredProtoPortTuple obj = new RequiredProtoPortTuple(name, proto, port);
-            requiredProtoPortTuple.put(name, obj);
-            return obj;
-        }
-
-        public Policy() {
-        }
-
-        public Policy(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeMap(preferredRoamingPartnerList);
-            out.writeMap(minBackhaulThreshold);
-            out.writeParcelable(policyUpdate, flags);
-            out.writeMap(sPExclusionList);
-            out.writeMap(requiredProtoPortTuple);
-            out.writeString(maximumBSSLoadValue);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                in.readMap(preferredRoamingPartnerList,
-                        PreferredRoamingPartnerList.class.getClassLoader());
-                in.readMap(minBackhaulThreshold, MinBackhaulThresholdNetwork.class.getClassLoader());
-                policyUpdate = in.readParcelable(PolicyUpdate.class.getClassLoader());
-                in.readMap(sPExclusionList, SPExclusionList.class.getClassLoader());
-                in.readMap(requiredProtoPortTuple, RequiredProtoPortTuple.class.getClassLoader());
-                maximumBSSLoadValue = in.readString();
-
-            }
-        }
-
-        public static final Parcelable.Creator<Policy> CREATOR = new Parcelable.Creator<Policy>() {
-            public Policy createFromParcel(Parcel in) {
-                return new Policy(in);
-            }
-
-            public Policy[] newArray(int size) {
-                return new Policy[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Policy/PreferredRoamingPartnerList/<X+>
-     **/
-    public static class PreferredRoamingPartnerList implements Parcelable {
-        public String nodeName;
-        public String FQDN_Match; //maximum 255 + ",includeSubdomains", equals 273
-        public String Priority;
-        public String Country; // maximum 600 octets
-
-        public PreferredRoamingPartnerList(String nn, String f, String p, String c) {
-            nodeName = nn;
-            FQDN_Match = f;
-            Priority = p;
-            Country = c;
-        }
-
-        public PreferredRoamingPartnerList() {
-        }
-
-        public PreferredRoamingPartnerList(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(nodeName);
-            out.writeString(FQDN_Match);
-            out.writeString(Priority);
-            out.writeString(Country);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                nodeName = in.readString();
-                FQDN_Match = in.readString();
-                Priority = in.readString();
-                Country = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<PreferredRoamingPartnerList> CREATOR = new Parcelable.Creator<PreferredRoamingPartnerList>() {
-            public PreferredRoamingPartnerList createFromParcel(Parcel in) {
-                return new PreferredRoamingPartnerList(in);
-            }
-
-            public PreferredRoamingPartnerList[] newArray(int size) {
-                return new PreferredRoamingPartnerList[size];
-            }
-        };
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Policy/MinBackhaulThreshold
-     **/
-    public static class MinBackhaulThresholdNetwork implements Parcelable {
-        public String nodeName;
-        public String NetworkType;
-        public String DLBandwidth;
-        public String ULBandwidth;
-
-        public MinBackhaulThresholdNetwork(String nn, String nt, String d, String u) {
-            nodeName = nn;
-            NetworkType = nt;
-            DLBandwidth = d;
-            ULBandwidth = u;
-        }
-
-        public MinBackhaulThresholdNetwork() {
-        }
-
-        public MinBackhaulThresholdNetwork(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(nodeName);
-            out.writeString(NetworkType);
-            out.writeString(DLBandwidth);
-            out.writeString(ULBandwidth);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                nodeName = in.readString();
-                NetworkType = in.readString();
-                DLBandwidth = in.readString();
-                ULBandwidth = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<MinBackhaulThresholdNetwork> CREATOR = new Parcelable.Creator<MinBackhaulThresholdNetwork>() {
-            public MinBackhaulThresholdNetwork createFromParcel(Parcel in) {
-                return new MinBackhaulThresholdNetwork(in);
-            }
-
-            public MinBackhaulThresholdNetwork[] newArray(int size) {
-                return new MinBackhaulThresholdNetwork[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Policy/PolicyUpdate
-     **/
-    public static class PolicyUpdate implements Parcelable {
-        public String UpdateInterval;
-        public String UpdateMethod;
-        public String Restriction;
-        public String URI;
-        public UsernamePassword usernamePassword = new UsernamePassword();
-        public String Other;
-        public TrustRoot trustRoot = new TrustRoot();
-
-        public PolicyUpdate() {
-        }
-
-        public PolicyUpdate(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(UpdateInterval);
-            out.writeString(UpdateMethod);
-            out.writeString(Restriction);
-            out.writeString(URI);
-            out.writeParcelable(usernamePassword, flags);
-            out.writeString(Other);
-            out.writeParcelable(trustRoot, flags);
-
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                UpdateInterval = in.readString();
-                UpdateMethod = in.readString();
-                Restriction = in.readString();
-                URI = in.readString();
-                usernamePassword = in.readParcelable(UsernamePassword.class.getClassLoader());
-                Other = in.readString();
-                trustRoot = in.readParcelable(TrustRoot.class.getClassLoader());
-            }
-        }
-
-        public static final Parcelable.Creator<PolicyUpdate> CREATOR = new Parcelable.Creator<PolicyUpdate>() {
-            public PolicyUpdate createFromParcel(Parcel in) {
-                return new PolicyUpdate(in);
-            }
-
-            public PolicyUpdate[] newArray(int size) {
-                return new PolicyUpdate[size];
-            }
-        };
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Policy/SPExclusionList
-     **/
-    public static class SPExclusionList implements Parcelable {
-        public String nodeName;
-        public String SSID;
-
-        public SPExclusionList(String nn, String s) {
-            nodeName = nn;
-            SSID = s;
-        }
-
-        public SPExclusionList() {
-        }
-
-        public SPExclusionList(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(nodeName);
-            out.writeString(SSID);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                nodeName = in.readString();
-                SSID = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<SPExclusionList> CREATOR = new Parcelable.Creator<SPExclusionList>() {
-            public SPExclusionList createFromParcel(Parcel in) {
-                return new SPExclusionList(in);
-            }
-
-            public SPExclusionList[] newArray(int size) {
-                return new SPExclusionList[size];
-            }
-        };
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Policy/RequiredProtoPortTuple
-     **/
-    public static class RequiredProtoPortTuple implements Parcelable {
-        public String nodeName;
-        public String IPProtocol;
-        public String PortNumber;
-
-        public RequiredProtoPortTuple() {
-        }
-
-        public RequiredProtoPortTuple(String nn, String protocol, String port) {
-            nodeName = nn;
-            IPProtocol = protocol;
-            PortNumber = port;
-        }
-
-        public RequiredProtoPortTuple(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(nodeName);
-            out.writeString(IPProtocol);
-            out.writeString(PortNumber);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                nodeName = in.readString();
-                IPProtocol = in.readString();
-                PortNumber = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<RequiredProtoPortTuple> CREATOR = new Parcelable.Creator<RequiredProtoPortTuple>() {
-            public RequiredProtoPortTuple createFromParcel(Parcel in) {
-                return new RequiredProtoPortTuple(in);
-            }
-
-            public RequiredProtoPortTuple[] newArray(int size) {
-                return new RequiredProtoPortTuple[size];
-            }
-        };
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/AAAServerTrustRoot
-     **/
-    public static class AAAServerTrustRoot implements Parcelable {
-        public String nodeName;
-        public String CertURL;
-        public String CertSHA256Fingerprint;
-
-        public AAAServerTrustRoot(String nn, String url, String fp) {
-            nodeName = nn;
-            CertURL = url;
-            CertSHA256Fingerprint = fp;
-        }
-
-        public AAAServerTrustRoot() {
-        }
-
-        public AAAServerTrustRoot(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(nodeName);
-            out.writeString(CertURL);
-            out.writeString(CertSHA256Fingerprint);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                nodeName = in.readString();
-                CertURL = in.readString();
-                CertSHA256Fingerprint = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<AAAServerTrustRoot> CREATOR = new Parcelable.Creator<AAAServerTrustRoot>() {
-            public AAAServerTrustRoot createFromParcel(Parcel in) {
-                return new AAAServerTrustRoot(in);
-            }
-
-            public AAAServerTrustRoot[] newArray(int size) {
-                return new AAAServerTrustRoot[size];
-            }
-        };
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/SubscriptionUpdate
-     **/
-    public static class SubscriptionUpdate implements Parcelable {
-        public String UpdateInterval;
-        public String UpdateMethod;
-        public String Restriction;
-        public String URI;
-        public UsernamePassword usernamePassword = new UsernamePassword();
-        public String Other;
-        public TrustRoot trustRoot = new TrustRoot();
-
-        public SubscriptionUpdate() {
-        }
-
-        public SubscriptionUpdate(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(UpdateInterval);
-            out.writeString(UpdateMethod);
-            out.writeString(Restriction);
-            out.writeString(URI);
-            out.writeParcelable(usernamePassword, flags);
-            out.writeString(Other);
-            out.writeParcelable(trustRoot, flags);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                UpdateInterval = in.readString();
-                UpdateMethod = in.readString();
-                Restriction = in.readString();
-                URI = in.readString();
-                usernamePassword = in.readParcelable(UsernamePassword.class.getClassLoader());
-                Other = in.readString();
-                trustRoot = in.readParcelable(TrustRoot.class.getClassLoader());
-            }
-        }
-
-        public static final Parcelable.Creator<SubscriptionUpdate> CREATOR = new Parcelable.Creator<SubscriptionUpdate>() {
-            public SubscriptionUpdate createFromParcel(Parcel in) {
-                return new SubscriptionUpdate(in);
-            }
-
-            public SubscriptionUpdate[] newArray(int size) {
-                return new SubscriptionUpdate[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Policy/PolicyUpdate/TrustRoot
-     * PerProviderSubscription/<X+>/SubscriptionUpdate/TrustRoot
-     * PerProviderSubscription/<X+>/AAAServerTrustRoot/<X+>
-     **/
-    public static class TrustRoot implements Parcelable {
-        public String CertURL;
-        public String CertSHA256Fingerprint;
-
-        public TrustRoot() {
-        }
-
-        public TrustRoot(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(CertURL);
-            out.writeString(CertSHA256Fingerprint);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                CertURL = in.readString();
-                CertSHA256Fingerprint = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<TrustRoot> CREATOR = new Parcelable.Creator<TrustRoot>() {
-            public TrustRoot createFromParcel(Parcel in) {
-                return new TrustRoot(in);
-            }
-
-            public TrustRoot[] newArray(int size) {
-                return new TrustRoot[size];
-            }
-        };
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Policy/PolicyUpdate/UsernamePassword
-     * PerProviderSubscription/<X+>/SubscriptionUpdate/UsernamePassword
-     * PerProviderSubscription/<X+>/Credential/UsernamePassword
-     **/
-    public static class UsernamePassword implements Parcelable {
-        public String Username;
-        public String Password;
-        //following are Credential node used only
-        public boolean MachineManaged;
-        public String SoftTokenApp;
-        public String AbleToShare;
-        public EAPMethod eAPMethod = new EAPMethod();
-
-        public UsernamePassword() {
-        }
-
-        public UsernamePassword(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(Username);
-            out.writeString(Password);
-            out.writeInt(MachineManaged ? 1 : 0);
-            out.writeString(SoftTokenApp);
-            out.writeString(AbleToShare);
-            out.writeParcelable(eAPMethod, flags);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                Username = in.readString();
-                Password = in.readString();
-                MachineManaged = (in.readInt() == 1) ? true : false;
-                SoftTokenApp = in.readString();
-                AbleToShare = in.readString();
-                eAPMethod = in.readParcelable(EAPMethod.class.getClassLoader());
-            }
-        }
-
-        public static final Parcelable.Creator<UsernamePassword> CREATOR = new Parcelable.Creator<UsernamePassword>() {
-            public UsernamePassword createFromParcel(Parcel in) {
-                return new UsernamePassword(in);
-            }
-
-            public UsernamePassword[] newArray(int size) {
-                return new UsernamePassword[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Credential/UsernamePassword/EAPMethod
-     **/
-    public static class EAPMethod implements Parcelable {
-        public String EAPType;
-        public String VendorId;
-        public String VendorType;
-        public String InnerEAPType;
-        public String InnerVendorId;
-        public String InnerVendorType;
-        public String InnerMethod;
-
-        public EAPMethod() {
-        }
-
-        public EAPMethod(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(EAPType);
-            out.writeString(VendorId);
-            out.writeString(VendorType);
-            out.writeString(InnerEAPType);
-            out.writeString(InnerVendorId);
-            out.writeString(InnerVendorType);
-            out.writeString(InnerMethod);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                EAPType = in.readString();
-                VendorId = in.readString();
-                VendorType = in.readString();
-                InnerEAPType = in.readString();
-                InnerVendorId = in.readString();
-                InnerVendorType = in.readString();
-                InnerMethod = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<EAPMethod> CREATOR = new Parcelable.Creator<EAPMethod>() {
-            public EAPMethod createFromParcel(Parcel in) {
-                return new EAPMethod(in);
-            }
-
-            public EAPMethod[] newArray(int size) {
-                return new EAPMethod[size];
-            }
-        };
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/HomeSP
-     **/
-    public static class HomeSP implements Parcelable {
-        public HashMap<String, NetworkID> networkID = new HashMap<String, NetworkID>();
-        public String FriendlyName;
-        public String IconURL;
-        public String FQDN;
-        public HashMap<String, HomeOIList> homeOIList = new HashMap<String, HomeOIList>();
-        public HashMap<String, OtherHomePartners> otherHomePartners = new HashMap<String, OtherHomePartners>();
-        public String RoamingConsortiumOI;
-
-        public NetworkID createNetworkID(String name, String ssid, String hessid) {
-            NetworkID obj = new NetworkID(name, ssid, hessid);
-            networkID.put(name, obj);
-            return obj;
-        }
-
-        public HomeOIList createHomeOIList(String name, String homeoi, boolean required) {
-            HomeOIList obj = new HomeOIList(name, homeoi, required);
-            homeOIList.put(name, obj);
-            return obj;
-        }
-
-        public OtherHomePartners createOtherHomePartners(String name, String fqdn) {
-            OtherHomePartners obj = new OtherHomePartners(name, fqdn);
-            otherHomePartners.put(name, obj);
-            return obj;
-        }
-
-        public HomeSP() {
-        }
-
-        public HomeSP(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeMap(networkID);
-            out.writeString(FriendlyName);
-            out.writeString(IconURL);
-            out.writeString(FQDN);
-            out.writeMap(homeOIList);
-            out.writeMap(otherHomePartners);
-            out.writeString(RoamingConsortiumOI);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                in.readMap(networkID, NetworkID.class.getClassLoader());
-                FriendlyName = in.readString();
-                IconURL = in.readString();
-                FQDN = in.readString();
-                in.readMap(homeOIList, HomeOIList.class.getClassLoader());
-                in.readMap(otherHomePartners, OtherHomePartners.class.getClassLoader());
-                RoamingConsortiumOI = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<HomeSP> CREATOR = new Parcelable.Creator<HomeSP>() {
-            public HomeSP createFromParcel(Parcel in) {
-                return new HomeSP(in);
-            }
-
-            public HomeSP[] newArray(int size) {
-                return new HomeSP[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/HomeSP/NetworkID
-     **/
-    public static class NetworkID implements Parcelable {
-        public String nodeName;
-        public String SSID;
-        public String HESSID;
-
-        public NetworkID(String nn, String s, String h) {
-            nodeName = nn;
-            SSID = s;
-            HESSID = h;
-        }
-
-        public NetworkID() {
-        }
-
-        public NetworkID(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(nodeName);
-            out.writeString(SSID);
-            out.writeString(HESSID);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                nodeName = in.readString();
-                SSID = in.readString();
-                HESSID = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<NetworkID> CREATOR = new Parcelable.Creator<NetworkID>() {
-            public NetworkID createFromParcel(Parcel in) {
-                return new NetworkID(in);
-            }
-
-            public NetworkID[] newArray(int size) {
-                return new NetworkID[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/HomeSP/HomeOIList
-     **/
-    public static class HomeOIList implements Parcelable {
-        public String nodeName;
-        public String HomeOI;
-        public boolean HomeOIRequired;
-
-        public HomeOIList(String nn, String h, boolean r) {
-            nodeName = nn;
-            HomeOI = h;
-            HomeOIRequired = r;
-        }
-
-        public HomeOIList() {
-        }
-
-        public HomeOIList(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(nodeName);
-            out.writeString(HomeOI);
-            out.writeInt(HomeOIRequired ? 1 : 0);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                nodeName = in.readString();
-                HomeOI = in.readString();
-                HomeOIRequired = (in.readInt() == 1) ? true : false;
-            }
-        }
-
-        public static final Parcelable.Creator<HomeOIList> CREATOR = new Parcelable.Creator<HomeOIList>() {
-            public HomeOIList createFromParcel(Parcel in) {
-                return new HomeOIList(in);
-            }
-
-            public HomeOIList[] newArray(int size) {
-                return new HomeOIList[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/HomeSP/OtherHomePartners
-     **/
-    public static class OtherHomePartners implements Parcelable {
-        public String nodeName;
-        public String FQDN;
-
-        public OtherHomePartners(String nn, String f) {
-            nodeName = nn;
-            FQDN = f;
-        }
-
-        public OtherHomePartners() {
-        }
-
-        public OtherHomePartners(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(nodeName);
-            out.writeString(FQDN);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                nodeName = in.readString();
-                FQDN = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<OtherHomePartners> CREATOR = new Parcelable.Creator<OtherHomePartners>() {
-            public OtherHomePartners createFromParcel(Parcel in) {
-                return new OtherHomePartners(in);
-            }
-
-            public OtherHomePartners[] newArray(int size) {
-                return new OtherHomePartners[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/SubscriptionParameters
-     **/
-    public static class SubscriptionParameters implements Parcelable {
-        public String CreationDate;
-        public String ExpirationDate;
-        public String TypeOfSubscription;
-        public UsageLimits usageLimits = new UsageLimits();
-
-        public SubscriptionParameters() {
-        }
-
-        public SubscriptionParameters(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(CreationDate);
-            out.writeString(ExpirationDate);
-            out.writeString(TypeOfSubscription);
-            out.writeParcelable(usageLimits, flags);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                CreationDate = in.readString();
-                ExpirationDate = in.readString();
-                TypeOfSubscription = in.readString();
-                usageLimits = in.readParcelable(UsageLimits.class.getClassLoader());
-            }
-        }
-
-        public static final Parcelable.Creator<SubscriptionParameters> CREATOR = new Parcelable.Creator<SubscriptionParameters>() {
-            public SubscriptionParameters createFromParcel(Parcel in) {
-                return new SubscriptionParameters(in);
-            }
-
-            public SubscriptionParameters[] newArray(int size) {
-                return new SubscriptionParameters[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/SubscriptionParameters/UsageLimits
-     **/
-    public static class UsageLimits implements Parcelable {
-        public String DataLimit;
-        public String StartDate;
-        public String TimeLimit;
-        public String UsageTimePeriod;
-
-        public UsageLimits() {
-        }
-
-        public UsageLimits(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(DataLimit);
-            out.writeString(StartDate);
-            out.writeString(TimeLimit);
-            out.writeString(UsageTimePeriod);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                DataLimit = in.readString();
-                StartDate = in.readString();
-                TimeLimit = in.readString();
-                UsageTimePeriod = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<UsageLimits> CREATOR = new Parcelable.Creator<UsageLimits>() {
-            public UsageLimits createFromParcel(Parcel in) {
-                return new UsageLimits(in);
-            }
-
-            public UsageLimits[] newArray(int size) {
-                return new UsageLimits[size];
-            }
-        };
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Credential
-     **/
-    public static class Credential implements Parcelable {
-        public String CreationDate;
-        public String ExpirationDate;
-        public UsernamePassword usernamePassword = new UsernamePassword();
-        public DigitalCertificate digitalCertificate = new DigitalCertificate();
-        public String Realm;
-        public boolean CheckAAAServerCertStatus;
-        public SIM sim = new SIM();
-
-        public Credential() {
-        }
-
-        public Credential(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(CreationDate);
-            out.writeString(ExpirationDate);
-            out.writeParcelable(usernamePassword, flags);
-            out.writeParcelable(digitalCertificate, flags);
-            out.writeString(Realm);
-            out.writeInt(CheckAAAServerCertStatus ? 1 : 0);
-            out.writeParcelable(sim, flags);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                CreationDate = in.readString();
-                ExpirationDate = in.readString();
-                usernamePassword = in.readParcelable(UsernamePassword.class.getClassLoader());
-                digitalCertificate = in.readParcelable(DigitalCertificate.class.getClassLoader());
-                Realm = in.readString();
-                CheckAAAServerCertStatus = (in.readInt() == 1) ? true : false;
-                sim = in.readParcelable(SIM.class.getClassLoader());
-            }
-        }
-
-        public static final Parcelable.Creator<Credential> CREATOR = new Parcelable.Creator<Credential>() {
-            public Credential createFromParcel(Parcel in) {
-                return new Credential(in);
-            }
-
-            public Credential[] newArray(int size) {
-                return new Credential[size];
-            }
-        };
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Credential/DigitalCertificate
-     **/
-    public static class DigitalCertificate implements Parcelable {
-        public String CertificateType;
-        public String CertSHA256Fingerprint;
-
-        public DigitalCertificate() {
-        }
-
-        public DigitalCertificate(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(CertificateType);
-            out.writeString(CertSHA256Fingerprint);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                CertificateType = in.readString();
-                CertSHA256Fingerprint = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<DigitalCertificate> CREATOR = new Parcelable.Creator<DigitalCertificate>() {
-            public DigitalCertificate createFromParcel(Parcel in) {
-                return new DigitalCertificate(in);
-            }
-
-            public DigitalCertificate[] newArray(int size) {
-                return new DigitalCertificate[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Credential/SIM
-     **/
-    public static class SIM implements Parcelable {
-        public String IMSI;
-        public String EAPType;
-
-        public SIM() {
-        }
-
-        public SIM(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(IMSI);
-            out.writeString(EAPType);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                IMSI = in.readString();
-                EAPType = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<SIM> CREATOR = new Parcelable.Creator<SIM>() {
-            public SIM createFromParcel(Parcel in) {
-                return new SIM(in);
-            }
-
-            public SIM[] newArray(int size) {
-                return new SIM[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Extension
-     **/
-    public static class Extension {
-        public String empty;
-    }
-
-    public WifiPasspointDmTree() {
-    }
-
-    public WifiPasspointDmTree(Parcel in) {
-        readFromParcel(in);
-    }
-
-    public int describeContents() {
-        return 0;
-    }
-
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeMap(spFqdn);
-    }
-
-    public void readFromParcel(Parcel in) {
-        if (in == null) {
-            //log here
-        } else {
-            in.readMap(spFqdn, SpFqdn.class.getClassLoader());
-        }
-    }
-
-    public static final Parcelable.Creator<WifiPasspointDmTree> CREATOR = new Parcelable.Creator<WifiPasspointDmTree>() {
-        public WifiPasspointDmTree createFromParcel(Parcel in) {
-            return new WifiPasspointDmTree(in);
-        }
-
-        public WifiPasspointDmTree[] newArray(int size) {
-            return new WifiPasspointDmTree[size];
-        }
-    };
-
-}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.aidl
deleted file mode 100644
index 27f23bc..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-parcelable WifiPasspointInfo;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java
deleted file mode 100644
index 33db3f5..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java
+++ /dev/null
@@ -1,559 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/** @hide */
-public class WifiPasspointInfo implements Parcelable {
-
-    /** TODO doc */
-    public static final int ANQP_CAPABILITY = 1 << 0;
-
-    /** TODO doc */
-    public static final int VENUE_NAME = 1 << 1;
-
-    /** TODO doc */
-    public static final int NETWORK_AUTH_TYPE = 1 << 2;
-
-    /** TODO doc */
-    public static final int ROAMING_CONSORTIUM = 1 << 3;
-
-    /** TODO doc */
-    public static final int IP_ADDR_TYPE_AVAILABILITY = 1 << 4;
-
-    /** TODO doc */
-    public static final int NAI_REALM = 1 << 5;
-
-    /** TODO doc */
-    public static final int CELLULAR_NETWORK = 1 << 6;
-
-    /** TODO doc */
-    public static final int DOMAIN_NAME = 1 << 7;
-
-    /** TODO doc */
-    public static final int HOTSPOT_CAPABILITY = 1 << 8;
-
-    /** TODO doc */
-    public static final int OPERATOR_FRIENDLY_NAME = 1 << 9;
-
-    /** TODO doc */
-    public static final int WAN_METRICS = 1 << 10;
-
-    /** TODO doc */
-    public static final int CONNECTION_CAPABILITY = 1 << 11;
-
-    /** TODO doc */
-    public static final int OSU_PROVIDER = 1 << 12;
-
-    /** TODO doc */
-    public static final int PRESET_CRED_MATCH =
-            ANQP_CAPABILITY |
-                    HOTSPOT_CAPABILITY |
-                    NAI_REALM |
-                    CELLULAR_NETWORK |
-                    DOMAIN_NAME;
-
-    /** TODO doc */
-    public static final int PRESET_ALL =
-            ANQP_CAPABILITY |
-                    VENUE_NAME |
-                    NETWORK_AUTH_TYPE |
-                    ROAMING_CONSORTIUM |
-                    IP_ADDR_TYPE_AVAILABILITY |
-                    NAI_REALM |
-                    CELLULAR_NETWORK |
-                    DOMAIN_NAME |
-                    HOTSPOT_CAPABILITY |
-                    OPERATOR_FRIENDLY_NAME |
-                    WAN_METRICS |
-                    CONNECTION_CAPABILITY |
-                    OSU_PROVIDER;
-
-
-    public static class WanMetrics {
-        public static final int STATUS_RESERVED = 0;
-        public static final int STATUS_UP = 1;
-        public static final int STATUS_DOWN = 2;
-        public static final int STATUS_TEST = 3;
-
-        public int wanInfo;
-        public long downlinkSpeed;
-        public long uplinkSpeed;
-        public int downlinkLoad;
-        public int uplinkLoad;
-        public int lmd;
-
-        public int getLinkStatus() {
-            return wanInfo & 0x3;
-        }
-
-        public boolean getSymmetricLink() {
-            return (wanInfo & (1 << 2)) != 0;
-        }
-
-        public boolean getAtCapacity() {
-            return (wanInfo & (1 << 3)) != 0;
-        }
-
-        @Override
-        public String toString() {
-            return wanInfo + "," + downlinkSpeed + "," + uplinkSpeed + "," +
-                    downlinkLoad + "," + uplinkLoad + "," + lmd;
-        }
-    }
-
-    public static class IpProtoPort {
-        public static final int STATUS_CLOSED = 0;
-        public static final int STATUS_OPEN = 1;
-        public static final int STATUS_UNKNOWN = 2;
-
-        public int proto;
-        public int port;
-        public int status;
-
-        @Override
-        public String toString() {
-            return proto + "," + port + "," + status;
-        }
-    }
-
-    public static class NetworkAuthType {
-        public static final int TYPE_TERMS_AND_CONDITION = 0;
-        public static final int TYPE_ONLINE_ENROLLMENT = 1;
-        public static final int TYPE_HTTP_REDIRECTION = 2;
-        public static final int TYPE_DNS_REDIRECTION = 3;
-
-        public int type;
-        public String redirectUrl;
-
-        @Override
-        public String toString() {
-            return type + "," + redirectUrl;
-        }
-    }
-
-    public static class IpAddressType {
-        public static final int IPV6_NOT_AVAILABLE = 0;
-        public static final int IPV6_AVAILABLE = 1;
-        public static final int IPV6_UNKNOWN = 2;
-
-        public static final int IPV4_NOT_AVAILABLE = 0;
-        public static final int IPV4_PUBLIC = 1;
-        public static final int IPV4_PORT_RESTRICTED = 2;
-        public static final int IPV4_SINGLE_NAT = 3;
-        public static final int IPV4_DOUBLE_NAT = 4;
-        public static final int IPV4_PORT_RESTRICTED_SINGLE_NAT = 5;
-        public static final int IPV4_PORT_RESTRICTED_DOUBLE_NAT = 6;
-        public static final int IPV4_PORT_UNKNOWN = 7;
-
-        private static final int NULL_VALUE = -1;
-
-        public int availability;
-
-        public int getIpv6Availability() {
-            return availability & 0x3;
-        }
-
-        public int getIpv4Availability() {
-            return (availability & 0xFF) >> 2;
-        }
-
-        @Override
-        public String toString() {
-            return getIpv6Availability() + "," + getIpv4Availability();
-        }
-    }
-
-    public static class NaiRealm {
-        public static final int ENCODING_RFC4282 = 0;
-        public static final int ENCODING_UTF8 = 1;
-
-        public int encoding;
-        public String realm;
-
-        @Override
-        public String toString() {
-            return encoding + "," + realm;
-        }
-    }
-
-    public static class CellularNetwork {
-        public String mcc;
-        public String mnc;
-
-        @Override
-        public String toString() {
-            return mcc + "," + mnc;
-        }
-    }
-
-    /** BSSID */
-    public String bssid;
-
-    /** venue name */
-    public String venueName;
-
-    /** list of network authentication types */
-    public List<NetworkAuthType> networkAuthTypeList;
-
-    /** list of roaming consortium OIs */
-    public List<String> roamingConsortiumList;
-
-    /** IP address availability */
-    public IpAddressType ipAddrTypeAvailability;
-
-    /** list of NAI realm */
-    public List<NaiRealm> naiRealmList;
-
-    /** list of 3GPP cellular network */
-    public List<CellularNetwork> cellularNetworkList;
-
-    /** list of fully qualified domain name (FQDN) */
-    public List<String> domainNameList;
-
-    /** HS 2.0 operator friendly name */
-    public String operatorFriendlyName;
-
-    /** HS 2.0 wan metrics */
-    public WanMetrics wanMetrics;
-
-    /** list of HS 2.0 IP proto port */
-    public List<IpProtoPort> connectionCapabilityList;
-
-    /** list of HS 2.0 OSU providers */
-    public List<WifiPasspointOsuProvider> osuProviderList;
-
-    /**
-     * Convert mask to ANQP subtypes, for supplicant command use.
-     *
-     * @param mask The ANQP subtypes mask.
-     * @return String of ANQP subtypes, good for supplicant command use
-     * @hide
-     */
-    public static String toAnqpSubtypes(int mask) {
-        StringBuilder sb = new StringBuilder();
-        if ((mask & ANQP_CAPABILITY) != 0)
-            sb.append("257,");
-        if ((mask & VENUE_NAME) != 0)
-            sb.append("258,");
-        if ((mask & NETWORK_AUTH_TYPE) != 0)
-            sb.append("260,");
-        if ((mask & ROAMING_CONSORTIUM) != 0)
-            sb.append("261,");
-        if ((mask & IP_ADDR_TYPE_AVAILABILITY) != 0)
-            sb.append("262,");
-        if ((mask & NAI_REALM) != 0)
-            sb.append("263,");
-        if ((mask & CELLULAR_NETWORK) != 0)
-            sb.append("264,");
-        if ((mask & DOMAIN_NAME) != 0)
-            sb.append("268,");
-        if ((mask & HOTSPOT_CAPABILITY) != 0)
-            sb.append("hs20:2,");
-        if ((mask & OPERATOR_FRIENDLY_NAME) != 0)
-            sb.append("hs20:3,");
-        if ((mask & WAN_METRICS) != 0)
-            sb.append("hs20:4,");
-        if ((mask & CONNECTION_CAPABILITY) != 0)
-            sb.append("hs20:5,");
-        if ((mask & OSU_PROVIDER) != 0)
-            sb.append("hs20:8,");
-        if (sb.length() > 0)
-            sb.deleteCharAt(sb.length() - 1);
-        return sb.toString();
-    }
-
-    @Override
-    public String toString() {
-        StringBuffer sb = new StringBuffer();
-
-        sb.append("BSSID: ").append("(").append(bssid).append(")");
-
-        if (venueName != null)
-            sb.append(" venueName: ").append("(")
-              .append(venueName.replace("\n", "\\n")).append(")");
-
-        if (networkAuthTypeList != null) {
-            sb.append(" networkAuthType: ");
-            for (NetworkAuthType auth : networkAuthTypeList)
-                sb.append("(").append(auth.toString()).append(")");
-        }
-
-        if (roamingConsortiumList != null) {
-            sb.append(" roamingConsortium: ");
-            for (String oi : roamingConsortiumList)
-                sb.append("(").append(oi).append(")");
-        }
-
-        if (ipAddrTypeAvailability != null) {
-            sb.append(" ipAddrTypeAvaibility: ").append("(")
-              .append(ipAddrTypeAvailability.toString()).append(")");
-        }
-
-        if (naiRealmList != null) {
-            sb.append(" naiRealm: ");
-            for (NaiRealm realm : naiRealmList)
-                sb.append("(").append(realm.toString()).append(")");
-        }
-
-        if (cellularNetworkList != null) {
-            sb.append(" cellularNetwork: ");
-            for (CellularNetwork plmn : cellularNetworkList)
-                sb.append("(").append(plmn.toString()).append(")");
-        }
-
-        if (domainNameList != null) {
-            sb.append(" domainName: ");
-            for (String fqdn : domainNameList)
-                sb.append("(").append(fqdn).append(")");
-        }
-
-        if (operatorFriendlyName != null)
-            sb.append(" operatorFriendlyName: ").append("(")
-              .append(operatorFriendlyName).append(")");
-
-        if (wanMetrics != null)
-            sb.append(" wanMetrics: ").append("(")
-              .append(wanMetrics.toString()).append(")");
-
-        if (connectionCapabilityList != null) {
-            sb.append(" connectionCapability: ");
-            for (IpProtoPort ip : connectionCapabilityList)
-                sb.append("(").append(ip.toString()).append(")");
-        }
-
-        if (osuProviderList != null) {
-            sb.append(" osuProviderList: ");
-            for (WifiPasspointOsuProvider osu : osuProviderList)
-                sb.append("(").append(osu.toString()).append(")");
-        }
-
-        return sb.toString();
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeString(bssid);
-        out.writeString(venueName);
-
-        if (networkAuthTypeList == null) {
-            out.writeInt(0);
-        } else {
-            out.writeInt(networkAuthTypeList.size());
-            for (NetworkAuthType auth : networkAuthTypeList) {
-                out.writeInt(auth.type);
-                out.writeString(auth.redirectUrl);
-            }
-        }
-
-        if (roamingConsortiumList == null) {
-            out.writeInt(0);
-        } else {
-            out.writeInt(roamingConsortiumList.size());
-            for (String oi : roamingConsortiumList)
-                out.writeString(oi);
-        }
-
-        if (ipAddrTypeAvailability == null) {
-            out.writeInt(IpAddressType.NULL_VALUE);
-        } else {
-            out.writeInt(ipAddrTypeAvailability.availability);
-        }
-
-        if (naiRealmList == null) {
-            out.writeInt(0);
-        } else {
-            out.writeInt(naiRealmList.size());
-            for (NaiRealm realm : naiRealmList) {
-                out.writeInt(realm.encoding);
-                out.writeString(realm.realm);
-            }
-        }
-
-        if (cellularNetworkList == null) {
-            out.writeInt(0);
-        } else {
-            out.writeInt(cellularNetworkList.size());
-            for (CellularNetwork plmn : cellularNetworkList) {
-                out.writeString(plmn.mcc);
-                out.writeString(plmn.mnc);
-            }
-        }
-
-
-        if (domainNameList == null) {
-            out.writeInt(0);
-        } else {
-            out.writeInt(domainNameList.size());
-            for (String fqdn : domainNameList)
-                out.writeString(fqdn);
-        }
-
-        out.writeString(operatorFriendlyName);
-
-        if (wanMetrics == null) {
-            out.writeInt(0);
-        } else {
-            out.writeInt(1);
-            out.writeInt(wanMetrics.wanInfo);
-            out.writeLong(wanMetrics.downlinkSpeed);
-            out.writeLong(wanMetrics.uplinkSpeed);
-            out.writeInt(wanMetrics.downlinkLoad);
-            out.writeInt(wanMetrics.uplinkLoad);
-            out.writeInt(wanMetrics.lmd);
-        }
-
-        if (connectionCapabilityList == null) {
-            out.writeInt(0);
-        } else {
-            out.writeInt(connectionCapabilityList.size());
-            for (IpProtoPort ip : connectionCapabilityList) {
-                out.writeInt(ip.proto);
-                out.writeInt(ip.port);
-                out.writeInt(ip.status);
-            }
-        }
-
-        if (osuProviderList == null) {
-            out.writeInt(0);
-        } else {
-            out.writeInt(osuProviderList.size());
-            for (WifiPasspointOsuProvider osu : osuProviderList)
-                osu.writeToParcel(out, flags);
-        }
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    public static final Parcelable.Creator<WifiPasspointInfo> CREATOR =
-            new Parcelable.Creator<WifiPasspointInfo>() {
-                @Override
-                public WifiPasspointInfo createFromParcel(Parcel in) {
-                    WifiPasspointInfo p = new WifiPasspointInfo();
-                    int n;
-
-                    p.bssid = in.readString();
-                    p.venueName = in.readString();
-
-                    n = in.readInt();
-                    if (n > 0) {
-                        p.networkAuthTypeList = new ArrayList<NetworkAuthType>();
-                        for (int i = 0; i < n; i++) {
-                            NetworkAuthType auth = new NetworkAuthType();
-                            auth.type = in.readInt();
-                            auth.redirectUrl = in.readString();
-                            p.networkAuthTypeList.add(auth);
-                        }
-                    }
-
-                    n = in.readInt();
-                    if (n > 0) {
-                        p.roamingConsortiumList = new ArrayList<String>();
-                        for (int i = 0; i < n; i++)
-                            p.roamingConsortiumList.add(in.readString());
-                    }
-
-                    n = in.readInt();
-                    if (n != IpAddressType.NULL_VALUE) {
-                        p.ipAddrTypeAvailability = new IpAddressType();
-                        p.ipAddrTypeAvailability.availability = n;
-                    }
-
-                    n = in.readInt();
-                    if (n > 0) {
-                        p.naiRealmList = new ArrayList<NaiRealm>();
-                        for (int i = 0; i < n; i++) {
-                            NaiRealm realm = new NaiRealm();
-                            realm.encoding = in.readInt();
-                            realm.realm = in.readString();
-                            p.naiRealmList.add(realm);
-                        }
-                    }
-
-                    n = in.readInt();
-                    if (n > 0) {
-                        p.cellularNetworkList = new ArrayList<CellularNetwork>();
-                        for (int i = 0; i < n; i++) {
-                            CellularNetwork plmn = new CellularNetwork();
-                            plmn.mcc = in.readString();
-                            plmn.mnc = in.readString();
-                            p.cellularNetworkList.add(plmn);
-                        }
-                    }
-
-                    n = in.readInt();
-                    if (n > 0) {
-                        p.domainNameList = new ArrayList<String>();
-                        for (int i = 0; i < n; i++)
-                            p.domainNameList.add(in.readString());
-                    }
-
-                    p.operatorFriendlyName = in.readString();
-
-                    n = in.readInt();
-                    if (n > 0) {
-                        p.wanMetrics = new WanMetrics();
-                        p.wanMetrics.wanInfo = in.readInt();
-                        p.wanMetrics.downlinkSpeed = in.readLong();
-                        p.wanMetrics.uplinkSpeed = in.readLong();
-                        p.wanMetrics.downlinkLoad = in.readInt();
-                        p.wanMetrics.uplinkLoad = in.readInt();
-                        p.wanMetrics.lmd = in.readInt();
-                    }
-
-                    n = in.readInt();
-                    if (n > 0) {
-                        p.connectionCapabilityList = new ArrayList<IpProtoPort>();
-                        for (int i = 0; i < n; i++) {
-                            IpProtoPort ip = new IpProtoPort();
-                            ip.proto = in.readInt();
-                            ip.port = in.readInt();
-                            ip.status = in.readInt();
-                            p.connectionCapabilityList.add(ip);
-                        }
-                    }
-
-                    n = in.readInt();
-                    if (n > 0) {
-                        p.osuProviderList = new ArrayList<WifiPasspointOsuProvider>();
-                        for (int i = 0; i < n; i++) {
-                            WifiPasspointOsuProvider osu = WifiPasspointOsuProvider.CREATOR
-                                    .createFromParcel(in);
-                            p.osuProviderList.add(osu);
-                        }
-                    }
-
-                    return p;
-                }
-
-                @Override
-                public WifiPasspointInfo[] newArray(int size) {
-                    return new WifiPasspointInfo[size];
-                }
-            };
-}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
deleted file mode 100644
index 0245a3d..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
+++ /dev/null
@@ -1,567 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-import android.content.Context;
-import android.net.wifi.ScanResult;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.internal.util.AsyncChannel;
-import com.android.internal.util.Protocol;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * Provides APIs for managing Wifi Passpoint credentials.
- * @hide
- */
-public class WifiPasspointManager {
-
-    private static final String TAG = "PasspointManager";
-
-    private static final boolean DBG = true;
-
-    /* Passpoint states values */
-
-    /** Passpoint is in an unknown state. This should only occur in boot time */
-    public static final int PASSPOINT_STATE_UNKNOWN = 0;
-
-    /** Passpoint is disabled. This occurs when wifi is disabled */
-    public static final int PASSPOINT_STATE_DISABLED = 1;
-
-    /** Passpoint is enabled and in discovery state */
-    public static final int PASSPOINT_STATE_DISCOVERY = 2;
-
-    /** Passpoint is enabled and in access state */
-    public static final int PASSPOINT_STATE_ACCESS = 3;
-
-    /** Passpoint is enabled and in provisioning state */
-    public static final int PASSPOINT_STATE_PROVISION = 4;
-
-    /* Passpoint callback error codes */
-
-    /** Indicates that the operation failed due to an internal error */
-    public static final int REASON_ERROR = 0;
-
-    /** Indicates that the operation failed because wifi is disabled */
-    public static final int REASON_WIFI_DISABLED = 1;
-
-    /** Indicates that the operation failed because the framework is busy */
-    public static final int REASON_BUSY = 2;
-
-    /** Indicates that the operation failed because parameter is invalid */
-    public static final int REASON_INVALID_PARAMETER = 3;
-
-    /** Indicates that the operation failed because the server is not trusted */
-    public static final int REASON_NOT_TRUSTED = 4;
-
-    /**
-     * protocol supported for Passpoint
-     */
-    public static final String PROTOCOL_DM = "OMA-DM-ClientInitiated";
-
-    /**
-     * protocol supported for Passpoint
-     */
-    public static final String PROTOCOL_SOAP = "SPP-ClientInitiated";
-
-    /* Passpoint broadcasts */
-
-    /**
-     * Broadcast intent action indicating that the state of Passpoint
-     * connectivity has changed
-     */
-    public static final String PASSPOINT_STATE_CHANGED_ACTION =
-            "android.net.wifi.passpoint.STATE_CHANGE";
-
-    /**
-     * Broadcast intent action indicating that the saved Passpoint credential
-     * list has changed
-     */
-    public static final String PASSPOINT_CRED_CHANGED_ACTION =
-            "android.net.wifi.passpoint.CRED_CHANGE";
-
-    /**
-     * Broadcast intent action indicating that Passpoint online sign up is
-     * avaiable.
-     */
-    public static final String PASSPOINT_OSU_AVAILABLE_ACTION =
-            "android.net.wifi.passpoint.OSU_AVAILABLE";
-
-    /**
-     * Broadcast intent action indicating that user remediation is required
-     */
-    public static final String PASSPOINT_USER_REM_REQ_ACTION =
-            "android.net.wifi.passpoint.USER_REM_REQ";
-
-    /**
-     * Interface for callback invocation when framework channel is lost
-     */
-    public interface ChannelListener {
-        /**
-         * The channel to the framework has been disconnected. Application could
-         * try re-initializing using {@link #initialize}
-         */
-        public void onChannelDisconnected();
-    }
-
-    /**
-     * Interface for callback invocation on an application action
-     */
-    public interface ActionListener {
-        /** The operation succeeded */
-        public void onSuccess();
-
-        /**
-         * The operation failed
-         *
-         * @param reason The reason for failure could be one of
-         *            {@link #WIFI_DISABLED}, {@link #ERROR} or {@link #BUSY}
-         */
-        public void onFailure(int reason);
-    }
-
-    /**
-     * Interface for callback invocation when doing OSU or user remediation
-     */
-    public interface OsuRemListener {
-        /** The operation succeeded */
-        public void onSuccess();
-
-        /**
-         * The operation failed
-         *
-         * @param reason The reason for failure could be one of
-         *            {@link #WIFI_DISABLED}, {@link #ERROR} or {@link #BUSY}
-         */
-        public void onFailure(int reason);
-
-        /**
-         * Browser launch is requried for user interaction. When this callback
-         * is called, app should launch browser / webview to the given URI.
-         *
-         * @param uri URI for browser launch
-         */
-        public void onBrowserLaunch(String uri);
-
-        /**
-         * When this is called, app should dismiss the previously lanched browser.
-         */
-        public void onBrowserDismiss();
-    }
-
-    /**
-     * A channel that connects the application to the wifi passpoint framework.
-     * Most passpoint operations require a Channel as an argument.
-     * An instance of Channel is obtained by doing a call on {@link #initialize}
-     */
-    public static class Channel {
-        private final static int INVALID_LISTENER_KEY = 0;
-
-        private ChannelListener mChannelListener;
-
-        private HashMap<Integer, Object> mListenerMap = new HashMap<Integer, Object>();
-        private HashMap<Integer, Integer> mListenerMapCount = new HashMap<Integer, Integer>();
-        private Object mListenerMapLock = new Object();
-        private int mListenerKey = 0;
-
-        private List<ScanResult> mAnqpRequest = new LinkedList<ScanResult>();
-        private Object mAnqpRequestLock = new Object();
-
-        private AsyncChannel mAsyncChannel;
-        private PasspointHandler mHandler;
-        Context mContext;
-
-        Channel(Context context, Looper looper, ChannelListener l) {
-            mAsyncChannel = new AsyncChannel();
-            mHandler = new PasspointHandler(looper);
-            mChannelListener = l;
-            mContext = context;
-        }
-
-        private int putListener(Object listener) {
-            return putListener(listener, 1);
-        }
-
-        private int putListener(Object listener, int count) {
-            if (listener == null || count <= 0)
-                return INVALID_LISTENER_KEY;
-            int key;
-            synchronized (mListenerMapLock) {
-                do {
-                    key = mListenerKey++;
-                } while (key == INVALID_LISTENER_KEY);
-                mListenerMap.put(key, listener);
-                mListenerMapCount.put(key, count);
-            }
-            return key;
-        }
-
-        private Object peekListener(int key) {
-            Log.d(TAG, "peekListener() key=" + key);
-            if (key == INVALID_LISTENER_KEY)
-                return null;
-            synchronized (mListenerMapLock) {
-                return mListenerMap.get(key);
-            }
-        }
-
-
-        private Object getListener(int key, boolean forceRemove) {
-            Log.d(TAG, "getListener() key=" + key + " force=" + forceRemove);
-            if (key == INVALID_LISTENER_KEY)
-                return null;
-            synchronized (mListenerMapLock) {
-                if (!forceRemove) {
-                    int count = mListenerMapCount.get(key);
-                    Log.d(TAG, "count=" + count);
-                    mListenerMapCount.put(key, --count);
-                    if (count > 0)
-                        return null;
-                }
-                Log.d(TAG, "remove key");
-                mListenerMapCount.remove(key);
-                return mListenerMap.remove(key);
-            }
-        }
-
-        private void anqpRequestStart(ScanResult sr) {
-            Log.d(TAG, "anqpRequestStart sr.bssid=" + sr.BSSID);
-            synchronized (mAnqpRequestLock) {
-                mAnqpRequest.add(sr);
-            }
-        }
-
-        private void anqpRequestFinish(WifiPasspointInfo result) {
-            Log.d(TAG, "anqpRequestFinish pi.bssid=" + result.bssid);
-            synchronized (mAnqpRequestLock) {
-                for (ScanResult sr : mAnqpRequest)
-                    if (sr.BSSID.equals(result.bssid)) {
-                        Log.d(TAG, "find hit " + result.bssid);
-                        /* sr.passpoint = result; */
-                        mAnqpRequest.remove(sr);
-                        Log.d(TAG, "mAnqpRequest.len=" + mAnqpRequest.size());
-                        break;
-                    }
-            }
-        }
-
-        private void anqpRequestFinish(ScanResult sr) {
-            Log.d(TAG, "anqpRequestFinish sr.bssid=" + sr.BSSID);
-            synchronized (mAnqpRequestLock) {
-                for (ScanResult sr1 : mAnqpRequest)
-                    if (sr1.BSSID.equals(sr.BSSID)) {
-                        mAnqpRequest.remove(sr1);
-                        break;
-                    }
-            }
-        }
-
-        class PasspointHandler extends Handler {
-            PasspointHandler(Looper looper) {
-                super(looper);
-            }
-
-            @Override
-            public void handleMessage(Message message) {
-                Object listener = null;
-
-                switch (message.what) {
-                    case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
-                        if (mChannelListener != null) {
-                            mChannelListener.onChannelDisconnected();
-                            mChannelListener = null;
-                        }
-                        break;
-
-                    case REQUEST_ANQP_INFO_SUCCEEDED:
-                        WifiPasspointInfo result = (WifiPasspointInfo) message.obj;
-                        anqpRequestFinish(result);
-                        listener = getListener(message.arg2, false);
-                        if (listener != null) {
-                            ((ActionListener) listener).onSuccess();
-                        }
-                        break;
-
-                    case REQUEST_ANQP_INFO_FAILED:
-                        anqpRequestFinish((ScanResult) message.obj);
-                        listener = getListener(message.arg2, false);
-                        if (listener == null)
-                            getListener(message.arg2, true);
-                        if (listener != null) {
-                            ((ActionListener) listener).onFailure(message.arg1);
-                        }
-                        break;
-
-                    case START_OSU_SUCCEEDED:
-                        listener = getListener(message.arg2, true);
-                        if (listener != null) {
-                            ((OsuRemListener) listener).onSuccess();
-                        }
-                        break;
-
-                    case START_OSU_FAILED:
-                        listener = getListener(message.arg2, true);
-                        if (listener != null) {
-                            ((OsuRemListener) listener).onFailure(message.arg1);
-                        }
-                        break;
-
-                    case START_OSU_BROWSER:
-                        listener = peekListener(message.arg2);
-                        if (listener != null) {
-                            ParcelableString str = (ParcelableString) message.obj;
-                            if (str == null || str.string == null)
-                                ((OsuRemListener) listener).onBrowserDismiss();
-                            else
-                                ((OsuRemListener) listener).onBrowserLaunch(str.string);
-                        }
-                        break;
-
-                    default:
-                        Log.d(TAG, "Ignored " + message);
-                        break;
-                }
-            }
-        }
-
-    }
-
-    public static class ParcelableString implements Parcelable {
-        public String string;
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(string);
-        }
-
-        public static final Parcelable.Creator<ParcelableString> CREATOR =
-                new Parcelable.Creator<ParcelableString>() {
-                    @Override
-                    public ParcelableString createFromParcel(Parcel in) {
-                        ParcelableString ret = new ParcelableString();
-                        ret.string = in.readString();
-                        return ret;
-                    }
-                    @Override
-                    public ParcelableString[] newArray(int size) {
-                        return new ParcelableString[size];
-                    }
-        };
-    }
-
-    private static final int BASE = Protocol.BASE_WIFI_PASSPOINT_MANAGER;
-
-    public static final int REQUEST_ANQP_INFO                   = BASE + 1;
-    public static final int REQUEST_ANQP_INFO_FAILED            = BASE + 2;
-    public static final int REQUEST_ANQP_INFO_SUCCEEDED         = BASE + 3;
-    public static final int REQUEST_OSU_ICON                    = BASE + 4;
-    public static final int REQUEST_OSU_ICON_FAILED             = BASE + 5;
-    public static final int REQUEST_OSU_ICON_SUCCEEDED          = BASE + 6;
-    public static final int START_OSU                           = BASE + 7;
-    public static final int START_OSU_BROWSER                   = BASE + 8;
-    public static final int START_OSU_FAILED                    = BASE + 9;
-    public static final int START_OSU_SUCCEEDED                 = BASE + 10;
-
-    private Context mContext;
-    IWifiPasspointManager mService;
-
-    /**
-     * TODO: doc
-     * @param context
-     * @param service
-     */
-    public WifiPasspointManager(Context context, IWifiPasspointManager service) {
-        mContext = context;
-        mService = service;
-    }
-
-    /**
-     * Registers the application with the framework. This function must be the
-     * first to be called before any async passpoint operations are performed.
-     *
-     * @param srcContext is the context of the source
-     * @param srcLooper is the Looper on which the callbacks are receivied
-     * @param listener for callback at loss of framework communication. Can be
-     *            null.
-     * @return Channel instance that is necessary for performing any further
-     *         passpoint operations
-     *
-     */
-    public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
-        Messenger messenger = getMessenger();
-        if (messenger == null)
-            return null;
-
-        Channel c = new Channel(srcContext, srcLooper, listener);
-        if (c.mAsyncChannel.connectSync(srcContext, c.mHandler, messenger)
-                == AsyncChannel.STATUS_SUCCESSFUL) {
-            return c;
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * STOPSHIP: temp solution, should use supplicant manager instead, check
-     * with b/13931972
-     */
-    public Messenger getMessenger() {
-        try {
-            return mService.getMessenger();
-        } catch (RemoteException e) {
-            return null;
-        }
-    }
-
-    public int getPasspointState() {
-        try {
-            return mService.getPasspointState();
-        } catch (RemoteException e) {
-            return PASSPOINT_STATE_UNKNOWN;
-        }
-    }
-
-    public void requestAnqpInfo(Channel c, List<ScanResult> requested, int mask,
-            ActionListener listener) {
-        Log.d(TAG, "requestAnqpInfo start");
-        Log.d(TAG, "requested.size=" + requested.size());
-        checkChannel(c);
-        List<ScanResult> list = new ArrayList<ScanResult>();
-        for (ScanResult sr : requested)
-            if (sr.capabilities.contains("[HS20]")) {
-                list.add(sr);
-                c.anqpRequestStart(sr);
-                Log.d(TAG, "adding " + sr.BSSID);
-            }
-        int count = list.size();
-        Log.d(TAG, "after filter, count=" + count);
-        if (count == 0) {
-            if (DBG)
-                Log.d(TAG, "ANQP info request contains no HS20 APs, skipped");
-            listener.onSuccess();
-            return;
-        }
-        int key = c.putListener(listener, count);
-        for (ScanResult sr : list)
-            c.mAsyncChannel.sendMessage(REQUEST_ANQP_INFO, mask, key, sr);
-        Log.d(TAG, "requestAnqpInfo end");
-    }
-
-    public void requestOsuIcons(Channel c, List<WifiPasspointOsuProvider> requested,
-            int resolution, ActionListener listener) {
-    }
-
-    public List<WifiPasspointPolicy> requestCredentialMatch(List<ScanResult> requested) {
-        try {
-            return mService.requestCredentialMatch(requested);
-        } catch (RemoteException e) {
-            return null;
-        }
-    }
-
-    /**
-     * Get a list of saved Passpoint credentials. Only those credentials owned
-     * by the caller will be returned.
-     *
-     * @return The list of credentials
-     */
-    public List<WifiPasspointCredential> getCredentials() {
-        try {
-            return mService.getCredentials();
-        } catch (RemoteException e) {
-            return null;
-        }
-    }
-
-    /**
-     * Add a new Passpoint credential.
-     *
-     * @param cred The credential to be added
-     * @return {@code true} if the operation succeeds, {@code false} otherwise
-     */
-    public boolean addCredential(WifiPasspointCredential cred) {
-        try {
-            return mService.addCredential(cred);
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
-    /**
-     * Update an existing Passpoint credential. Only system or the owner of this
-     * credential has the permission to do this.
-     *
-     * @param cred The credential to be updated
-     * @return {@code true} if the operation succeeds, {@code false} otherwise
-     */
-    public boolean updateCredential(WifiPasspointCredential cred) {
-        try {
-            return mService.updateCredential(cred);
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
-    /**
-     * Remove an existing Passpoint credential. Only system or the owner of this
-     * credential has the permission to do this.
-     *
-     * @param cred The credential to be removed
-     * @return {@code true} if the operation succeeds, {@code false} otherwise
-     */
-    public boolean removeCredential(WifiPasspointCredential cred) {
-        try {
-            return mService.removeCredential(cred);
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
-    public void startOsu(Channel c, WifiPasspointOsuProvider osu, OsuRemListener listener) {
-        Log.d(TAG, "startOsu start");
-        checkChannel(c);
-        int key = c.putListener(listener);
-        c.mAsyncChannel.sendMessage(START_OSU, 0, key, osu);
-        Log.d(TAG, "startOsu end");
-    }
-
-    public void startRemediation(Channel c, OsuRemListener listener) {
-    }
-
-    public void connect(WifiPasspointPolicy policy) {
-    }
-
-    private static void checkChannel(Channel c) {
-        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
-    }
-}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.aidl
deleted file mode 100644
index 088136f..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-parcelable WifiPasspointOsuProvider;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java
deleted file mode 100644
index b54b70c..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/** @hide */
-public class WifiPasspointOsuProvider implements Parcelable {
-
-    /** TODO: doc
-     * @hide
-     */
-    public static final int OSU_METHOD_UNKNOWN = -1;
-
-    /** TODO: doc
-     * @hide
-     */
-    public static final int OSU_METHOD_OMADM = 0;
-
-    /** TODO: doc
-     * @hide
-     */
-    public static final int OSU_METHOD_SOAP = 1;
-
-    /** TODO: doc */
-    public String ssid;
-
-    /** TODO: doc */
-    public String friendlyName;
-
-    /** TODO: doc
-     * @hide
-     */
-    public String serverUri;
-
-    /** TODO: doc
-     * @hide
-     */
-    public int osuMethod = OSU_METHOD_UNKNOWN;
-
-    /** TODO: doc */
-    public int iconWidth;
-
-    /** TODO: doc */
-    public int iconHeight;
-
-    /** TODO: doc */
-    public String iconType;
-
-    /** TODO: doc */
-    public String iconFileName;
-
-    /** TODO: doc */
-    public Object icon; // TODO: should change to image format
-
-    /** TODO: doc */
-    public String osuNai;
-
-    /** TODO: doc */
-    public String osuService;
-
-    /** default constructor @hide */
-    public WifiPasspointOsuProvider() {
-        // TODO
-    }
-
-    /** copy constructor @hide */
-    public WifiPasspointOsuProvider(WifiPasspointOsuProvider source) {
-        // TODO
-    }
-
-    @Override
-    public String toString() {
-        StringBuffer sb = new StringBuffer();
-        sb.append("SSID: ").append("<").append(ssid).append(">");
-        if (friendlyName != null)
-            sb.append(" friendlyName: ").append("<").append(friendlyName).append(">");
-        if (serverUri != null)
-            sb.append(" serverUri: ").append("<").append(serverUri).append(">");
-        sb.append(" osuMethod: ").append("<").append(osuMethod).append(">");
-        if (iconFileName != null) {
-            sb.append(" icon: <").append(iconWidth).append("x")
-                    .append(iconHeight).append(" ")
-                    .append(iconType).append(" ")
-                    .append(iconFileName).append(">");
-        }
-        if (osuNai != null)
-            sb.append(" osuNai: ").append("<").append(osuNai).append(">");
-        if (osuService != null)
-            sb.append(" osuService: ").append("<").append(osuService).append(">");
-        return sb.toString();
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeString(ssid);
-        out.writeString(friendlyName);
-        out.writeString(serverUri);
-        out.writeInt(osuMethod);
-        out.writeInt(iconWidth);
-        out.writeInt(iconHeight);
-        out.writeString(iconType);
-        out.writeString(iconFileName);
-        out.writeString(osuNai);
-        out.writeString(osuService);
-        // TODO: icon image?
-    }
-
-    public static final Parcelable.Creator<WifiPasspointOsuProvider> CREATOR =
-            new Parcelable.Creator<WifiPasspointOsuProvider>() {
-                @Override
-                public WifiPasspointOsuProvider createFromParcel(Parcel in) {
-                    WifiPasspointOsuProvider osu = new WifiPasspointOsuProvider();
-                    osu.ssid = in.readString();
-                    osu.friendlyName = in.readString();
-                    osu.serverUri = in.readString();
-                    osu.osuMethod = in.readInt();
-                    osu.iconWidth = in.readInt();
-                    osu.iconHeight = in.readInt();
-                    osu.iconType = in.readString();
-                    osu.iconFileName = in.readString();
-                    osu.osuNai = in.readString();
-                    osu.osuService = in.readString();
-                    return osu;
-                }
-
-                @Override
-                public WifiPasspointOsuProvider[] newArray(int size) {
-                    return new WifiPasspointOsuProvider[size];
-                }
-            };
-}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.aidl
deleted file mode 100644
index 1d61da0..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-parcelable WifiPasspointPolicy;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java
deleted file mode 100644
index c08877e..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-import android.net.wifi.WifiConfiguration;
-import android.os.Parcelable;
-import android.os.Parcel;
-import android.security.Credentials;
-import android.util.Log;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-
-
-/** @hide */
-public class WifiPasspointPolicy implements Parcelable {
-
-    private final static String TAG = "PasspointPolicy";
-
-    /** @hide */
-    public static final int HOME_SP = 0;
-
-    /** @hide */
-    public static final int ROAMING_PARTNER = 1;
-
-    /** @hide */
-    public static final int UNRESTRICTED = 2;
-
-    private String mName;
-    private int mCredentialPriority;
-    private int mRoamingPriority;
-    private String mBssid;
-    private String mSsid;
-    private WifiPasspointCredential mCredential;
-    private int mRestriction;// Permitted values are "HomeSP", "RoamingPartner", or "Unrestricted"
-    private boolean mIsHomeSp;
-
-    private final String INT_PRIVATE_KEY = "private_key";
-    private final String INT_PHASE2 = "phase2";
-    private final String INT_PASSWORD = "password";
-    private final String INT_IDENTITY = "identity";
-    private final String INT_EAP = "eap";
-    private final String INT_CLIENT_CERT = "client_cert";
-    private final String INT_CA_CERT = "ca_cert";
-    private final String INT_ANONYMOUS_IDENTITY = "anonymous_identity";
-    private final String INT_SIM_SLOT = "sim_slot";
-    private final String INT_ENTERPRISEFIELD_NAME ="android.net.wifi.WifiConfiguration$EnterpriseField";
-    private final String ISO8601DATEFORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
-    private final String ENTERPRISE_PHASE2_MSCHAPV2 = "auth=MSCHAPV2";
-    private final String ENTERPRISE_PHASE2_MSCHAP = "auth=MSCHAP";
-
-    /** @hide */
-    public WifiPasspointPolicy(String name, String ssid,
-            String bssid, WifiPasspointCredential pc,
-            int restriction, boolean ishomesp) {
-        mName = name;
-        if (pc != null) {
-            mCredentialPriority = pc.getPriority();
-        }
-        //PerProviderSubscription/<X+>/Policy/PreferredRoamingPartnerList/<X+>/Priority
-        mRoamingPriority = 128; //default priority value of 128
-        mSsid = ssid;
-        mCredential = pc;
-        mBssid = bssid;
-        mRestriction = restriction;
-        mIsHomeSp = ishomesp;
-    }
-
-    public String getSsid() {
-        return mSsid;
-    }
-
-    /** @hide */
-    public void setBssid(String bssid) {
-        mBssid = bssid;
-    }
-
-    public String getBssid() {
-        return mBssid;
-    }
-
-    /** @hide */
-    public void setRestriction(int r) {
-        mRestriction = r;
-    }
-
-    /** @hide */
-    public int getRestriction() {
-        return mRestriction;
-    }
-
-    /** @hide */
-    public void setHomeSp(boolean b) {
-        mIsHomeSp = b;
-    }
-
-    /** @hide */
-    public boolean isHomeSp() {
-        return mIsHomeSp;
-    }
-
-    /** @hide */
-    public void setCredential(WifiPasspointCredential newCredential) {
-        mCredential = newCredential;
-    }
-
-    public WifiPasspointCredential getCredential() {
-        // TODO: return a copy
-        return mCredential;
-    }
-
-    /** @hide */
-    public void setCredentialPriority(int priority) {
-        mCredentialPriority = priority;
-    }
-
-    /** @hide */
-    public void setRoamingPriority(int priority) {
-        mRoamingPriority = priority;
-    }
-
-    public int getCredentialPriority() {
-        return mCredentialPriority;
-    }
-
-    public int getRoamingPriority() {
-        return mRoamingPriority;
-    }
-
-    public WifiConfiguration createWifiConfiguration() {
-        WifiConfiguration wfg = new WifiConfiguration();
-        if (mBssid != null) {
-            Log.d(TAG, "create bssid:" + mBssid);
-            wfg.BSSID = mBssid;
-        }
-
-        if (mSsid != null) {
-            Log.d(TAG, "create ssid:" + mSsid);
-            wfg.SSID = mSsid;
-        }
-        //TODO: 1. add pmf configuration
-        //      2. add ocsp configuration
-        //      3. add eap-sim configuration
-        /*Key management*/
-        wfg.status = WifiConfiguration.Status.ENABLED;
-        wfg.allowedKeyManagement.clear();
-        wfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
-        wfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
-
-        /*Group Ciphers*/
-        wfg.allowedGroupCiphers.clear();
-        wfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
-        wfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
-
-        /*Protocols*/
-        wfg.allowedProtocols.clear();
-        wfg.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
-        wfg.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
-
-        Class[] enterpriseFieldArray  = WifiConfiguration.class.getClasses();
-        Class<?> enterpriseFieldClass = null;
-
-
-        for(Class<?> myClass : enterpriseFieldArray) {
-            if(myClass.getName().equals(INT_ENTERPRISEFIELD_NAME)) {
-                enterpriseFieldClass = myClass;
-                break;
-            }
-        }
-        Log.d(TAG, "class chosen " + enterpriseFieldClass.getName() );
-
-
-        Field anonymousId = null, caCert = null, clientCert = null,
-              eap = null, identity = null, password = null,
-              phase2 = null, privateKey =  null;
-
-        Field[] fields = WifiConfiguration.class.getFields();
-
-
-        for (Field tempField : fields) {
-            if (tempField.getName().trim().equals(INT_ANONYMOUS_IDENTITY)) {
-                anonymousId = tempField;
-                Log.d(TAG, "field " + anonymousId.getName() );
-            } else if (tempField.getName().trim().equals(INT_CA_CERT)) {
-                caCert = tempField;
-            } else if (tempField.getName().trim().equals(INT_CLIENT_CERT)) {
-                clientCert = tempField;
-                Log.d(TAG, "field " + clientCert.getName() );
-            } else if (tempField.getName().trim().equals(INT_EAP)) {
-                eap = tempField;
-                Log.d(TAG, "field " + eap.getName() );
-            } else if (tempField.getName().trim().equals(INT_IDENTITY)) {
-                identity = tempField;
-                Log.d(TAG, "field " + identity.getName() );
-            } else if (tempField.getName().trim().equals(INT_PASSWORD)) {
-                password = tempField;
-                Log.d(TAG, "field " + password.getName() );
-            } else if (tempField.getName().trim().equals(INT_PHASE2)) {
-                phase2 = tempField;
-                Log.d(TAG, "field " + phase2.getName() );
-
-            } else if (tempField.getName().trim().equals(INT_PRIVATE_KEY)) {
-                privateKey = tempField;
-            }
-        }
-
-
-        Method setValue = null;
-
-        for(Method m: enterpriseFieldClass.getMethods()) {
-            if(m.getName().trim().equals("setValue")) {
-                Log.d(TAG, "method " + m.getName() );
-                setValue = m;
-                break;
-            }
-        }
-
-        try {
-            // EAP
-            String eapmethod = mCredential.getType();
-            Log.d(TAG, "eapmethod:" + eapmethod);
-            setValue.invoke(eap.get(wfg), eapmethod);
-
-            // Username, password, EAP Phase 2
-            if ("TTLS".equals(eapmethod)) {
-                setValue.invoke(phase2.get(wfg), ENTERPRISE_PHASE2_MSCHAPV2);
-                setValue.invoke(identity.get(wfg), mCredential.getUserName());
-                setValue.invoke(password.get(wfg), mCredential.getPassword());
-                setValue.invoke(anonymousId.get(wfg), "anonymous@" + mCredential.getRealm());
-            }
-
-            // EAP CA Certificate
-            String cacertificate = null;
-            String rootCA = mCredential.getCaRootCertPath();
-            if (rootCA == null){
-                cacertificate = null;
-            } else {
-                cacertificate = "keystore://" + Credentials.WIFI + "HS20" + Credentials.CA_CERTIFICATE + rootCA;
-            }
-            Log.d(TAG, "cacertificate:" + cacertificate);
-            setValue.invoke(caCert.get(wfg), cacertificate);
-
-            //User certificate
-            if ("TLS".equals(eapmethod)) {
-                String usercertificate = null;
-                String privatekey = null;
-                String clientCertPath = mCredential.getClientCertPath();
-                if (clientCertPath != null){
-                    privatekey = "keystore://" + Credentials.WIFI + "HS20" + Credentials.USER_PRIVATE_KEY + clientCertPath;
-                    usercertificate = "keystore://" + Credentials.WIFI + "HS20" + Credentials.USER_CERTIFICATE + clientCertPath;
-                }
-                Log.d(TAG, "privatekey:" + privatekey);
-                Log.d(TAG, "usercertificate:" + usercertificate);
-                if (privatekey != null && usercertificate != null) {
-                    setValue.invoke(privateKey.get(wfg), privatekey);
-                    setValue.invoke(clientCert.get(wfg), usercertificate);
-                }
-            }
-        } catch (Exception e) {
-            Log.d(TAG, "createWifiConfiguration err:" + e);
-        }
-
-        return wfg;
-    }
-
-    /** {@inheritDoc} @hide */
-    public int compareTo(WifiPasspointPolicy another) {
-        Log.d(TAG, "this:" + this);
-        Log.d(TAG, "another:" + another);
-
-        if (another == null) {
-            return -1;
-        } else if (this.mIsHomeSp == true && another.isHomeSp() == false) {
-            //home sp priority is higher then roaming
-            Log.d(TAG, "compare HomeSP  first, this is HomeSP, another isn't");
-            return -1;
-        } else if ((this.mIsHomeSp == true && another.isHomeSp() == true)) {
-            Log.d(TAG, "both HomeSP");
-            //if both home sp, compare credential priority
-            if (this.mCredentialPriority < another.getCredentialPriority()) {
-                Log.d(TAG, "this priority is higher");
-                return -1;
-            } else if (this.mCredentialPriority == another.getCredentialPriority()) {
-                Log.d(TAG, "both priorities equal");
-                //if priority still the same, compare name(ssid)
-                if (this.mName.compareTo(another.mName) != 0) {
-                    Log.d(TAG, "compare mName return:" + this.mName.compareTo(another.mName));
-                    return this.mName.compareTo(another.mName);
-                }
-                /**
-                 *if name still the same, compare credential
-                 *the device may has two more credentials(TLS,SIM..etc)
-                 *it can associate to one AP(same ssid). so we should compare by credential
-                 */
-                if (this.mCredential != null && another.mCredential != null) {
-                    if (this.mCredential.compareTo(another.mCredential) != 0) {
-                        Log.d(TAG,
-                                "compare mCredential return:" + this.mName.compareTo(another.mName));
-                        return this.mCredential.compareTo(another.mCredential);
-                    }
-                }
-            } else {
-                return 1;
-            }
-        } else if ((this.mIsHomeSp == false && another.isHomeSp() == false)) {
-            Log.d(TAG, "both RoamingSp");
-            //if both roaming sp, compare roaming priority(preferredRoamingPartnerList/<X+>/priority)
-            if (this.mRoamingPriority < another.getRoamingPriority()) {
-                Log.d(TAG, "this priority is higher");
-                return -1;
-            } else if (this.mRoamingPriority == another.getRoamingPriority()) {//priority equals, compare name
-                Log.d(TAG, "both priorities equal");
-                //if priority still the same, compare name(ssid)
-                if (this.mName.compareTo(another.mName) != 0) {
-                    Log.d(TAG, "compare mName return:" + this.mName.compareTo(another.mName));
-                    return this.mName.compareTo(another.mName);
-                }
-                //if name still the same, compare credential
-                if (this.mCredential != null && another.mCredential != null) {
-                    if (this.mCredential.compareTo(another.mCredential) != 0) {
-                        Log.d(TAG,
-                                "compare mCredential return:"
-                                        + this.mCredential.compareTo(another.mCredential));
-                        return this.mCredential.compareTo(another.mCredential);
-                    }
-                }
-            } else {
-                return 1;
-            }
-        }
-
-        Log.d(TAG, "both policies equal");
-        return 0;
-    }
-
-    @Override
-    /** @hide */
-    public String toString() {
-        return "PasspointPolicy: name=" + mName + " CredentialPriority=" + mCredentialPriority +
-                " mRoamingPriority" + mRoamingPriority +
-                " ssid=" + mSsid + " restriction=" + mRestriction +
-                " ishomesp=" + mIsHomeSp + " Credential=" + mCredential;
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        // TODO
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    public static final Creator<WifiPasspointPolicy> CREATOR =
-            new Creator<WifiPasspointPolicy>() {
-                @Override
-                public WifiPasspointPolicy createFromParcel(Parcel in) {
-                    return null;
-                }
-
-                @Override
-                public WifiPasspointPolicy[] newArray(int size) {
-                    return new WifiPasspointPolicy[size];
-                }
-            };
-}